1 /* 2 * Copyright (c) 2009, Intel Corporation. 3 * 4 * This program is free software; you can redistribute it and/or modify it 5 * under the terms and conditions of the GNU General Public License, 6 * version 2, as published by the Free Software Foundation. 7 * 8 * This program is distributed in the hope it will be useful, but WITHOUT 9 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 10 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 11 * more details. 12 * 13 * You should have received a copy of the GNU General Public License along with 14 * this program; if not, write to the Free Software Foundation, Inc., 59 Temple 15 * Place - Suite 330, Boston, MA 02111-1307 USA. 16 * 17 * Author: Weidong Han <weidong.han@intel.com> 18 */ 19 20 #include <linux/pci.h> 21 #include <linux/acpi.h> 22 #include <linux/pci-acpi.h> 23 #include <xen/xen.h> 24 #include <xen/interface/physdev.h> 25 #include <xen/interface/xen.h> 26 27 #include <asm/xen/hypervisor.h> 28 #include <asm/xen/hypercall.h> 29 #include "../pci/pci.h" 30 #ifdef CONFIG_PCI_MMCONFIG 31 #include <asm/pci_x86.h> 32 #endif 33 34 static bool __read_mostly pci_seg_supported = true; 35 36 static int xen_add_device(struct device *dev) 37 { 38 int r; 39 struct pci_dev *pci_dev = to_pci_dev(dev); 40 #ifdef CONFIG_PCI_IOV 41 struct pci_dev *physfn = pci_dev->physfn; 42 #endif 43 44 if (pci_seg_supported) { 45 struct { 46 struct physdev_pci_device_add add; 47 uint32_t pxm; 48 } add_ext = { 49 .add.seg = pci_domain_nr(pci_dev->bus), 50 .add.bus = pci_dev->bus->number, 51 .add.devfn = pci_dev->devfn 52 }; 53 struct physdev_pci_device_add *add = &add_ext.add; 54 55 #ifdef CONFIG_ACPI 56 acpi_handle handle; 57 #endif 58 59 #ifdef CONFIG_PCI_IOV 60 if (pci_dev->is_virtfn) { 61 add->flags = XEN_PCI_DEV_VIRTFN; 62 add->physfn.bus = physfn->bus->number; 63 add->physfn.devfn = physfn->devfn; 64 } else 65 #endif 66 if (pci_ari_enabled(pci_dev->bus) && PCI_SLOT(pci_dev->devfn)) 67 add->flags = XEN_PCI_DEV_EXTFN; 68 69 #ifdef CONFIG_ACPI 70 handle = ACPI_HANDLE(&pci_dev->dev); 71 #ifdef CONFIG_PCI_IOV 72 if (!handle && pci_dev->is_virtfn) 73 handle = ACPI_HANDLE(physfn->bus->bridge); 74 #endif 75 if (!handle) { 76 /* 77 * This device was not listed in the ACPI name space at 78 * all. Try to get acpi handle of parent pci bus. 79 */ 80 struct pci_bus *pbus; 81 for (pbus = pci_dev->bus; pbus; pbus = pbus->parent) { 82 handle = acpi_pci_get_bridge_handle(pbus); 83 if (handle) 84 break; 85 } 86 } 87 if (handle) { 88 acpi_status status; 89 90 do { 91 unsigned long long pxm; 92 93 status = acpi_evaluate_integer(handle, "_PXM", 94 NULL, &pxm); 95 if (ACPI_SUCCESS(status)) { 96 add->optarr[0] = pxm; 97 add->flags |= XEN_PCI_DEV_PXM; 98 break; 99 } 100 status = acpi_get_parent(handle, &handle); 101 } while (ACPI_SUCCESS(status)); 102 } 103 #endif /* CONFIG_ACPI */ 104 105 r = HYPERVISOR_physdev_op(PHYSDEVOP_pci_device_add, add); 106 if (r != -ENOSYS) 107 return r; 108 pci_seg_supported = false; 109 } 110 111 if (pci_domain_nr(pci_dev->bus)) 112 r = -ENOSYS; 113 #ifdef CONFIG_PCI_IOV 114 else if (pci_dev->is_virtfn) { 115 struct physdev_manage_pci_ext manage_pci_ext = { 116 .bus = pci_dev->bus->number, 117 .devfn = pci_dev->devfn, 118 .is_virtfn = 1, 119 .physfn.bus = physfn->bus->number, 120 .physfn.devfn = physfn->devfn, 121 }; 122 123 r = HYPERVISOR_physdev_op(PHYSDEVOP_manage_pci_add_ext, 124 &manage_pci_ext); 125 } 126 #endif 127 else if (pci_ari_enabled(pci_dev->bus) && PCI_SLOT(pci_dev->devfn)) { 128 struct physdev_manage_pci_ext manage_pci_ext = { 129 .bus = pci_dev->bus->number, 130 .devfn = pci_dev->devfn, 131 .is_extfn = 1, 132 }; 133 134 r = HYPERVISOR_physdev_op(PHYSDEVOP_manage_pci_add_ext, 135 &manage_pci_ext); 136 } else { 137 struct physdev_manage_pci manage_pci = { 138 .bus = pci_dev->bus->number, 139 .devfn = pci_dev->devfn, 140 }; 141 142 r = HYPERVISOR_physdev_op(PHYSDEVOP_manage_pci_add, 143 &manage_pci); 144 } 145 146 return r; 147 } 148 149 static int xen_remove_device(struct device *dev) 150 { 151 int r; 152 struct pci_dev *pci_dev = to_pci_dev(dev); 153 154 if (pci_seg_supported) { 155 struct physdev_pci_device device = { 156 .seg = pci_domain_nr(pci_dev->bus), 157 .bus = pci_dev->bus->number, 158 .devfn = pci_dev->devfn 159 }; 160 161 r = HYPERVISOR_physdev_op(PHYSDEVOP_pci_device_remove, 162 &device); 163 } else if (pci_domain_nr(pci_dev->bus)) 164 r = -ENOSYS; 165 else { 166 struct physdev_manage_pci manage_pci = { 167 .bus = pci_dev->bus->number, 168 .devfn = pci_dev->devfn 169 }; 170 171 r = HYPERVISOR_physdev_op(PHYSDEVOP_manage_pci_remove, 172 &manage_pci); 173 } 174 175 return r; 176 } 177 178 static int xen_pci_notifier(struct notifier_block *nb, 179 unsigned long action, void *data) 180 { 181 struct device *dev = data; 182 int r = 0; 183 184 switch (action) { 185 case BUS_NOTIFY_ADD_DEVICE: 186 r = xen_add_device(dev); 187 break; 188 case BUS_NOTIFY_DEL_DEVICE: 189 r = xen_remove_device(dev); 190 break; 191 default: 192 return NOTIFY_DONE; 193 } 194 if (r) 195 dev_err(dev, "Failed to %s - passthrough or MSI/MSI-X might fail!\n", 196 action == BUS_NOTIFY_ADD_DEVICE ? "add" : 197 (action == BUS_NOTIFY_DEL_DEVICE ? "delete" : "?")); 198 return NOTIFY_OK; 199 } 200 201 static struct notifier_block device_nb = { 202 .notifier_call = xen_pci_notifier, 203 }; 204 205 static int __init register_xen_pci_notifier(void) 206 { 207 if (!xen_initial_domain()) 208 return 0; 209 210 return bus_register_notifier(&pci_bus_type, &device_nb); 211 } 212 213 arch_initcall(register_xen_pci_notifier); 214 215 #ifdef CONFIG_PCI_MMCONFIG 216 static int __init xen_mcfg_late(void) 217 { 218 struct pci_mmcfg_region *cfg; 219 int rc; 220 221 if (!xen_initial_domain()) 222 return 0; 223 224 if ((pci_probe & PCI_PROBE_MMCONF) == 0) 225 return 0; 226 227 if (list_empty(&pci_mmcfg_list)) 228 return 0; 229 230 /* Check whether they are in the right area. */ 231 list_for_each_entry(cfg, &pci_mmcfg_list, list) { 232 struct physdev_pci_mmcfg_reserved r; 233 234 r.address = cfg->address; 235 r.segment = cfg->segment; 236 r.start_bus = cfg->start_bus; 237 r.end_bus = cfg->end_bus; 238 r.flags = XEN_PCI_MMCFG_RESERVED; 239 240 rc = HYPERVISOR_physdev_op(PHYSDEVOP_pci_mmcfg_reserved, &r); 241 switch (rc) { 242 case 0: 243 case -ENOSYS: 244 continue; 245 246 default: 247 pr_warn("Failed to report MMCONFIG reservation" 248 " state for %s to hypervisor" 249 " (%d)\n", 250 cfg->name, rc); 251 } 252 } 253 return 0; 254 } 255 /* 256 * Needs to be done after acpi_init which are subsys_initcall. 257 */ 258 subsys_initcall_sync(xen_mcfg_late); 259 #endif 260