1 // SPDX-License-Identifier: GPL-2.0-only
3 * Copyright (c) 2009, Intel Corporation.
9 #include <linux/acpi.h>
10 #include <linux/pci-acpi.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>
22 static bool __read_mostly pci_seg_supported = true;
24 static int xen_add_device(struct device *dev)
27 struct pci_dev *pci_dev = to_pci_dev(dev);
29 struct pci_dev *physfn = pci_dev->physfn;
32 if (pci_seg_supported) {
34 struct physdev_pci_device_add add;
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;
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;
54 if (pci_ari_enabled(pci_dev->bus) && PCI_SLOT(pci_dev->devfn))
55 add->flags = XEN_PCI_DEV_EXTFN;
58 handle = ACPI_HANDLE(&pci_dev->dev);
60 if (!handle && pci_dev->is_virtfn)
61 handle = ACPI_HANDLE(physfn->bus->bridge);
65 * This device was not listed in the ACPI name space at
66 * all. Try to get acpi handle of parent pci bus.
69 for (pbus = pci_dev->bus; pbus; pbus = pbus->parent) {
70 handle = acpi_pci_get_bridge_handle(pbus);
79 unsigned long long pxm;
81 status = acpi_evaluate_integer(handle, "_PXM",
83 if (ACPI_SUCCESS(status)) {
85 add->flags |= XEN_PCI_DEV_PXM;
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);
96 pci_seg_supported = false;
99 if (pci_domain_nr(pci_dev->bus))
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,
107 .physfn.bus = physfn->bus->number,
108 .physfn.devfn = physfn->devfn,
111 r = HYPERVISOR_physdev_op(PHYSDEVOP_manage_pci_add_ext,
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,
122 r = HYPERVISOR_physdev_op(PHYSDEVOP_manage_pci_add_ext,
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,
137 static int xen_remove_device(struct device *dev)
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,
151 } else if (pci_domain_nr(pci_dev->bus))
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,
166 static int xen_pci_notifier(struct notifier_block *nb,
167 unsigned long action, void *data)
169 struct device *dev = data;
173 case BUS_NOTIFY_ADD_DEVICE:
174 r = xen_add_device(dev);
176 case BUS_NOTIFY_DEL_DEVICE:
177 r = xen_remove_device(dev);
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" : "?"));
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())
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;
209 if (!xen_initial_domain())
212 if ((pci_probe & PCI_PROBE_MMCONF) == 0)
215 if (list_empty(&pci_mmcfg_list))
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);
235 pr_warn("Failed to report MMCONFIG reservation"
236 " state for %s to hypervisor"
244 * Needs to be done after acpi_init which are subsys_initcall.
246 subsys_initcall_sync(xen_mcfg_late);