1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Copyright (c) 2009, Intel Corporation. 4 * 5 * Author: Weidong Han <weidong.han@intel.com> 6 */ 7 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> 14 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 21 22 static bool __read_mostly pci_seg_supported = true; 23 24 static int xen_add_device(struct device *dev) 25 { 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 31 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 40 }; 41 struct physdev_pci_device_add *add = &add_ext.add; 42 43 #ifdef CONFIG_ACPI 44 acpi_handle handle; 45 #endif 46 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; 56 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) { 64 /* 65 * This device was not listed in the ACPI name space at 66 * all. Try to get acpi handle of parent pci bus. 67 */ 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; 73 } 74 } 75 if (handle) { 76 acpi_status status; 77 78 do { 79 unsigned long long pxm; 80 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; 87 } 88 status = acpi_get_parent(handle, &handle); 89 } while (ACPI_SUCCESS(status)); 90 } 91 #endif /* CONFIG_ACPI */ 92 93 r = HYPERVISOR_physdev_op(PHYSDEVOP_pci_device_add, add); 94 if (r != -ENOSYS) 95 return r; 96 pci_seg_supported = false; 97 } 98 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, 109 }; 110 111 r = HYPERVISOR_physdev_op(PHYSDEVOP_manage_pci_add_ext, 112 &manage_pci_ext); 113 } 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, 120 }; 121 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, 128 }; 129 130 r = HYPERVISOR_physdev_op(PHYSDEVOP_manage_pci_add, 131 &manage_pci); 132 } 133 134 return r; 135 } 136 137 static int xen_remove_device(struct device *dev) 138 { 139 int r; 140 struct pci_dev *pci_dev = to_pci_dev(dev); 141 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 147 }; 148 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 157 }; 158 159 r = HYPERVISOR_physdev_op(PHYSDEVOP_manage_pci_remove, 160 &manage_pci); 161 } 162 163 return r; 164 } 165 166 static int xen_pci_notifier(struct notifier_block *nb, 167 unsigned long action, void *data) 168 { 169 struct device *dev = data; 170 int r = 0; 171 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; 181 } 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; 187 } 188 189 static struct notifier_block device_nb = { 190 .notifier_call = xen_pci_notifier, 191 }; 192 193 static int __init register_xen_pci_notifier(void) 194 { 195 if (!xen_initial_domain()) 196 return 0; 197 198 return bus_register_notifier(&pci_bus_type, &device_nb); 199 } 200 201 arch_initcall(register_xen_pci_notifier); 202 203 #ifdef CONFIG_PCI_MMCONFIG 204 static int __init xen_mcfg_late(void) 205 { 206 struct pci_mmcfg_region *cfg; 207 int rc; 208 209 if (!xen_initial_domain()) 210 return 0; 211 212 if ((pci_probe & PCI_PROBE_MMCONF) == 0) 213 return 0; 214 215 if (list_empty(&pci_mmcfg_list)) 216 return 0; 217 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; 221 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; 227 228 rc = HYPERVISOR_physdev_op(PHYSDEVOP_pci_mmcfg_reserved, &r); 229 switch (rc) { 230 case 0: 231 case -ENOSYS: 232 continue; 233 234 default: 235 pr_warn("Failed to report MMCONFIG reservation" 236 " state for %s to hypervisor" 237 " (%d)\n", 238 cfg->name, rc); 239 } 240 } 241 return 0; 242 } 243 /* 244 * Needs to be done after acpi_init which are subsys_initcall. 245 */ 246 subsys_initcall_sync(xen_mcfg_late); 247 #endif 248