Merge tag 'for-linus-20190706' of git://git.kernel.dk/linux-block
[linux/fpc-iii.git] / drivers / xen / pci.c
blob3eeb9bea7630023e1c7ef96020a5a066916ad50b
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3 * Copyright (c) 2009, Intel Corporation.
5 * Author: Weidong Han <weidong.han@intel.com>
6 */
8 #include <linux/pci.h>
9 #include <linux/acpi.h>
10 #include <linux/pci-acpi.h>
11 #include <xen/xen.h>
12 #include <xen/interface/physdev.h>
13 #include <xen/interface/xen.h>
15 #include <asm/xen/hypervisor.h>
16 #include <asm/xen/hypercall.h>
17 #include "../pci/pci.h"
18 #ifdef CONFIG_PCI_MMCONFIG
19 #include <asm/pci_x86.h>
20 #endif
22 static bool __read_mostly pci_seg_supported = true;
24 static int xen_add_device(struct device *dev)
26 int r;
27 struct pci_dev *pci_dev = to_pci_dev(dev);
28 #ifdef CONFIG_PCI_IOV
29 struct pci_dev *physfn = pci_dev->physfn;
30 #endif
32 if (pci_seg_supported) {
33 struct {
34 struct physdev_pci_device_add add;
35 uint32_t pxm;
36 } add_ext = {
37 .add.seg = pci_domain_nr(pci_dev->bus),
38 .add.bus = pci_dev->bus->number,
39 .add.devfn = pci_dev->devfn
41 struct physdev_pci_device_add *add = &add_ext.add;
43 #ifdef CONFIG_ACPI
44 acpi_handle handle;
45 #endif
47 #ifdef CONFIG_PCI_IOV
48 if (pci_dev->is_virtfn) {
49 add->flags = XEN_PCI_DEV_VIRTFN;
50 add->physfn.bus = physfn->bus->number;
51 add->physfn.devfn = physfn->devfn;
52 } else
53 #endif
54 if (pci_ari_enabled(pci_dev->bus) && PCI_SLOT(pci_dev->devfn))
55 add->flags = XEN_PCI_DEV_EXTFN;
57 #ifdef CONFIG_ACPI
58 handle = ACPI_HANDLE(&pci_dev->dev);
59 #ifdef CONFIG_PCI_IOV
60 if (!handle && pci_dev->is_virtfn)
61 handle = ACPI_HANDLE(physfn->bus->bridge);
62 #endif
63 if (!handle) {
65 * This device was not listed in the ACPI name space at
66 * all. Try to get acpi handle of parent pci bus.
68 struct pci_bus *pbus;
69 for (pbus = pci_dev->bus; pbus; pbus = pbus->parent) {
70 handle = acpi_pci_get_bridge_handle(pbus);
71 if (handle)
72 break;
75 if (handle) {
76 acpi_status status;
78 do {
79 unsigned long long pxm;
81 status = acpi_evaluate_integer(handle, "_PXM",
82 NULL, &pxm);
83 if (ACPI_SUCCESS(status)) {
84 add->optarr[0] = pxm;
85 add->flags |= XEN_PCI_DEV_PXM;
86 break;
88 status = acpi_get_parent(handle, &handle);
89 } while (ACPI_SUCCESS(status));
91 #endif /* CONFIG_ACPI */
93 r = HYPERVISOR_physdev_op(PHYSDEVOP_pci_device_add, add);
94 if (r != -ENOSYS)
95 return r;
96 pci_seg_supported = false;
99 if (pci_domain_nr(pci_dev->bus))
100 r = -ENOSYS;
101 #ifdef CONFIG_PCI_IOV
102 else if (pci_dev->is_virtfn) {
103 struct physdev_manage_pci_ext manage_pci_ext = {
104 .bus = pci_dev->bus->number,
105 .devfn = pci_dev->devfn,
106 .is_virtfn = 1,
107 .physfn.bus = physfn->bus->number,
108 .physfn.devfn = physfn->devfn,
111 r = HYPERVISOR_physdev_op(PHYSDEVOP_manage_pci_add_ext,
112 &manage_pci_ext);
114 #endif
115 else if (pci_ari_enabled(pci_dev->bus) && PCI_SLOT(pci_dev->devfn)) {
116 struct physdev_manage_pci_ext manage_pci_ext = {
117 .bus = pci_dev->bus->number,
118 .devfn = pci_dev->devfn,
119 .is_extfn = 1,
122 r = HYPERVISOR_physdev_op(PHYSDEVOP_manage_pci_add_ext,
123 &manage_pci_ext);
124 } else {
125 struct physdev_manage_pci manage_pci = {
126 .bus = pci_dev->bus->number,
127 .devfn = pci_dev->devfn,
130 r = HYPERVISOR_physdev_op(PHYSDEVOP_manage_pci_add,
131 &manage_pci);
134 return r;
137 static int xen_remove_device(struct device *dev)
139 int r;
140 struct pci_dev *pci_dev = to_pci_dev(dev);
142 if (pci_seg_supported) {
143 struct physdev_pci_device device = {
144 .seg = pci_domain_nr(pci_dev->bus),
145 .bus = pci_dev->bus->number,
146 .devfn = pci_dev->devfn
149 r = HYPERVISOR_physdev_op(PHYSDEVOP_pci_device_remove,
150 &device);
151 } else if (pci_domain_nr(pci_dev->bus))
152 r = -ENOSYS;
153 else {
154 struct physdev_manage_pci manage_pci = {
155 .bus = pci_dev->bus->number,
156 .devfn = pci_dev->devfn
159 r = HYPERVISOR_physdev_op(PHYSDEVOP_manage_pci_remove,
160 &manage_pci);
163 return r;
166 static int xen_pci_notifier(struct notifier_block *nb,
167 unsigned long action, void *data)
169 struct device *dev = data;
170 int r = 0;
172 switch (action) {
173 case BUS_NOTIFY_ADD_DEVICE:
174 r = xen_add_device(dev);
175 break;
176 case BUS_NOTIFY_DEL_DEVICE:
177 r = xen_remove_device(dev);
178 break;
179 default:
180 return NOTIFY_DONE;
182 if (r)
183 dev_err(dev, "Failed to %s - passthrough or MSI/MSI-X might fail!\n",
184 action == BUS_NOTIFY_ADD_DEVICE ? "add" :
185 (action == BUS_NOTIFY_DEL_DEVICE ? "delete" : "?"));
186 return NOTIFY_OK;
189 static struct notifier_block device_nb = {
190 .notifier_call = xen_pci_notifier,
193 static int __init register_xen_pci_notifier(void)
195 if (!xen_initial_domain())
196 return 0;
198 return bus_register_notifier(&pci_bus_type, &device_nb);
201 arch_initcall(register_xen_pci_notifier);
203 #ifdef CONFIG_PCI_MMCONFIG
204 static int __init xen_mcfg_late(void)
206 struct pci_mmcfg_region *cfg;
207 int rc;
209 if (!xen_initial_domain())
210 return 0;
212 if ((pci_probe & PCI_PROBE_MMCONF) == 0)
213 return 0;
215 if (list_empty(&pci_mmcfg_list))
216 return 0;
218 /* Check whether they are in the right area. */
219 list_for_each_entry(cfg, &pci_mmcfg_list, list) {
220 struct physdev_pci_mmcfg_reserved r;
222 r.address = cfg->address;
223 r.segment = cfg->segment;
224 r.start_bus = cfg->start_bus;
225 r.end_bus = cfg->end_bus;
226 r.flags = XEN_PCI_MMCFG_RESERVED;
228 rc = HYPERVISOR_physdev_op(PHYSDEVOP_pci_mmcfg_reserved, &r);
229 switch (rc) {
230 case 0:
231 case -ENOSYS:
232 continue;
234 default:
235 pr_warn("Failed to report MMCONFIG reservation"
236 " state for %s to hypervisor"
237 " (%d)\n",
238 cfg->name, rc);
241 return 0;
244 * Needs to be done after acpi_init which are subsys_initcall.
246 subsys_initcall_sync(xen_mcfg_late);
247 #endif