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 <xen/xen.h> 23 #include <xen/interface/physdev.h> 24 #include <xen/interface/xen.h> 25 26 #include <asm/xen/hypervisor.h> 27 #include <asm/xen/hypercall.h> 28 #include "../pci/pci.h" 29 #ifdef CONFIG_PCI_MMCONFIG 30 #include <asm/pci_x86.h> 31 #endif 32 33 static bool __read_mostly pci_seg_supported = true; 34 35 static int xen_add_device(struct device *dev) 36 { 37 int r; 38 struct pci_dev *pci_dev = to_pci_dev(dev); 39 #ifdef CONFIG_PCI_IOV 40 struct pci_dev *physfn = pci_dev->physfn; 41 #endif 42 43 if (pci_seg_supported) { 44 struct physdev_pci_device_add add = { 45 .seg = pci_domain_nr(pci_dev->bus), 46 .bus = pci_dev->bus->number, 47 .devfn = pci_dev->devfn 48 }; 49 #ifdef CONFIG_ACPI 50 acpi_handle handle; 51 #endif 52 53 #ifdef CONFIG_PCI_IOV 54 if (pci_dev->is_virtfn) { 55 add.flags = XEN_PCI_DEV_VIRTFN; 56 add.physfn.bus = physfn->bus->number; 57 add.physfn.devfn = physfn->devfn; 58 } else 59 #endif 60 if (pci_ari_enabled(pci_dev->bus) && PCI_SLOT(pci_dev->devfn)) 61 add.flags = XEN_PCI_DEV_EXTFN; 62 63 #ifdef CONFIG_ACPI 64 handle = ACPI_HANDLE(&pci_dev->dev); 65 if (!handle && pci_dev->bus->bridge) 66 handle = ACPI_HANDLE(pci_dev->bus->bridge); 67 #ifdef CONFIG_PCI_IOV 68 if (!handle && pci_dev->is_virtfn) 69 handle = ACPI_HANDLE(physfn->bus->bridge); 70 #endif 71 if (handle) { 72 acpi_status status; 73 74 do { 75 unsigned long long pxm; 76 77 status = acpi_evaluate_integer(handle, "_PXM", 78 NULL, &pxm); 79 if (ACPI_SUCCESS(status)) { 80 add.optarr[0] = pxm; 81 add.flags |= XEN_PCI_DEV_PXM; 82 break; 83 } 84 status = acpi_get_parent(handle, &handle); 85 } while (ACPI_SUCCESS(status)); 86 } 87 #endif /* CONFIG_ACPI */ 88 89 r = HYPERVISOR_physdev_op(PHYSDEVOP_pci_device_add, &add); 90 if (r != -ENOSYS) 91 return r; 92 pci_seg_supported = false; 93 } 94 95 if (pci_domain_nr(pci_dev->bus)) 96 r = -ENOSYS; 97 #ifdef CONFIG_PCI_IOV 98 else if (pci_dev->is_virtfn) { 99 struct physdev_manage_pci_ext manage_pci_ext = { 100 .bus = pci_dev->bus->number, 101 .devfn = pci_dev->devfn, 102 .is_virtfn = 1, 103 .physfn.bus = physfn->bus->number, 104 .physfn.devfn = physfn->devfn, 105 }; 106 107 r = HYPERVISOR_physdev_op(PHYSDEVOP_manage_pci_add_ext, 108 &manage_pci_ext); 109 } 110 #endif 111 else if (pci_ari_enabled(pci_dev->bus) && PCI_SLOT(pci_dev->devfn)) { 112 struct physdev_manage_pci_ext manage_pci_ext = { 113 .bus = pci_dev->bus->number, 114 .devfn = pci_dev->devfn, 115 .is_extfn = 1, 116 }; 117 118 r = HYPERVISOR_physdev_op(PHYSDEVOP_manage_pci_add_ext, 119 &manage_pci_ext); 120 } else { 121 struct physdev_manage_pci manage_pci = { 122 .bus = pci_dev->bus->number, 123 .devfn = pci_dev->devfn, 124 }; 125 126 r = HYPERVISOR_physdev_op(PHYSDEVOP_manage_pci_add, 127 &manage_pci); 128 } 129 130 return r; 131 } 132 133 static int xen_remove_device(struct device *dev) 134 { 135 int r; 136 struct pci_dev *pci_dev = to_pci_dev(dev); 137 138 if (pci_seg_supported) { 139 struct physdev_pci_device device = { 140 .seg = pci_domain_nr(pci_dev->bus), 141 .bus = pci_dev->bus->number, 142 .devfn = pci_dev->devfn 143 }; 144 145 r = HYPERVISOR_physdev_op(PHYSDEVOP_pci_device_remove, 146 &device); 147 } else if (pci_domain_nr(pci_dev->bus)) 148 r = -ENOSYS; 149 else { 150 struct physdev_manage_pci manage_pci = { 151 .bus = pci_dev->bus->number, 152 .devfn = pci_dev->devfn 153 }; 154 155 r = HYPERVISOR_physdev_op(PHYSDEVOP_manage_pci_remove, 156 &manage_pci); 157 } 158 159 return r; 160 } 161 162 static int xen_pci_notifier(struct notifier_block *nb, 163 unsigned long action, void *data) 164 { 165 struct device *dev = data; 166 int r = 0; 167 168 switch (action) { 169 case BUS_NOTIFY_ADD_DEVICE: 170 r = xen_add_device(dev); 171 break; 172 case BUS_NOTIFY_DEL_DEVICE: 173 r = xen_remove_device(dev); 174 break; 175 default: 176 return NOTIFY_DONE; 177 } 178 if (r) 179 dev_err(dev, "Failed to %s - passthrough or MSI/MSI-X might fail!\n", 180 action == BUS_NOTIFY_ADD_DEVICE ? "add" : 181 (action == BUS_NOTIFY_DEL_DEVICE ? "delete" : "?")); 182 return NOTIFY_OK; 183 } 184 185 static struct notifier_block device_nb = { 186 .notifier_call = xen_pci_notifier, 187 }; 188 189 static int __init register_xen_pci_notifier(void) 190 { 191 if (!xen_initial_domain()) 192 return 0; 193 194 return bus_register_notifier(&pci_bus_type, &device_nb); 195 } 196 197 arch_initcall(register_xen_pci_notifier); 198 199 #ifdef CONFIG_PCI_MMCONFIG 200 static int __init xen_mcfg_late(void) 201 { 202 struct pci_mmcfg_region *cfg; 203 int rc; 204 205 if (!xen_initial_domain()) 206 return 0; 207 208 if ((pci_probe & PCI_PROBE_MMCONF) == 0) 209 return 0; 210 211 if (list_empty(&pci_mmcfg_list)) 212 return 0; 213 214 /* Check whether they are in the right area. */ 215 list_for_each_entry(cfg, &pci_mmcfg_list, list) { 216 struct physdev_pci_mmcfg_reserved r; 217 218 r.address = cfg->address; 219 r.segment = cfg->segment; 220 r.start_bus = cfg->start_bus; 221 r.end_bus = cfg->end_bus; 222 r.flags = XEN_PCI_MMCFG_RESERVED; 223 224 rc = HYPERVISOR_physdev_op(PHYSDEVOP_pci_mmcfg_reserved, &r); 225 switch (rc) { 226 case 0: 227 case -ENOSYS: 228 continue; 229 230 default: 231 pr_warn("Failed to report MMCONFIG reservation" 232 " state for %s to hypervisor" 233 " (%d)\n", 234 cfg->name, rc); 235 } 236 } 237 return 0; 238 } 239 /* 240 * Needs to be done after acpi_init which are subsys_initcall. 241 */ 242 subsys_initcall_sync(xen_mcfg_late); 243 #endif 244