Blame view
drivers/xen/pci.c
4.68 KB
e28c31a96 xen: register xen... |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
/* * Copyright (c) 2009, Intel Corporation. * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License along with * this program; if not, write to the Free Software Foundation, Inc., 59 Temple * Place - Suite 330, Boston, MA 02111-1307 USA. * * Author: Weidong Han <weidong.han@intel.com> */ #include <linux/pci.h> |
55e901fc1 xen/pci: support ... |
21 |
#include <linux/acpi.h> |
e28c31a96 xen: register xen... |
22 23 24 25 26 27 28 |
#include <xen/xen.h> #include <xen/interface/physdev.h> #include <xen/interface/xen.h> #include <asm/xen/hypervisor.h> #include <asm/xen/hypercall.h> #include "../pci/pci.h" |
55e901fc1 xen/pci: support ... |
29 |
static bool __read_mostly pci_seg_supported = true; |
e28c31a96 xen: register xen... |
30 31 32 33 |
static int xen_add_device(struct device *dev) { int r; struct pci_dev *pci_dev = to_pci_dev(dev); |
55e901fc1 xen/pci: support ... |
34 35 36 37 38 39 40 41 42 43 44 45 46 |
#ifdef CONFIG_PCI_IOV struct pci_dev *physfn = pci_dev->physfn; #endif if (pci_seg_supported) { struct physdev_pci_device_add add = { .seg = pci_domain_nr(pci_dev->bus), .bus = pci_dev->bus->number, .devfn = pci_dev->devfn }; #ifdef CONFIG_ACPI acpi_handle handle; #endif |
e28c31a96 xen: register xen... |
47 48 |
#ifdef CONFIG_PCI_IOV |
55e901fc1 xen/pci: support ... |
49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 |
if (pci_dev->is_virtfn) { add.flags = XEN_PCI_DEV_VIRTFN; add.physfn.bus = physfn->bus->number; add.physfn.devfn = physfn->devfn; } else #endif if (pci_ari_enabled(pci_dev->bus) && PCI_SLOT(pci_dev->devfn)) add.flags = XEN_PCI_DEV_EXTFN; #ifdef CONFIG_ACPI handle = DEVICE_ACPI_HANDLE(&pci_dev->dev); if (!handle) handle = DEVICE_ACPI_HANDLE(pci_dev->bus->bridge); #ifdef CONFIG_PCI_IOV if (!handle && pci_dev->is_virtfn) handle = DEVICE_ACPI_HANDLE(physfn->bus->bridge); #endif if (handle) { acpi_status status; do { unsigned long long pxm; status = acpi_evaluate_integer(handle, "_PXM", NULL, &pxm); if (ACPI_SUCCESS(status)) { add.optarr[0] = pxm; add.flags |= XEN_PCI_DEV_PXM; break; } status = acpi_get_parent(handle, &handle); } while (ACPI_SUCCESS(status)); } #endif /* CONFIG_ACPI */ r = HYPERVISOR_physdev_op(PHYSDEVOP_pci_device_add, &add); if (r != -ENOSYS) return r; pci_seg_supported = false; } if (pci_domain_nr(pci_dev->bus)) r = -ENOSYS; #ifdef CONFIG_PCI_IOV else if (pci_dev->is_virtfn) { |
e28c31a96 xen: register xen... |
94 95 96 97 |
struct physdev_manage_pci_ext manage_pci_ext = { .bus = pci_dev->bus->number, .devfn = pci_dev->devfn, .is_virtfn = 1, |
55e901fc1 xen/pci: support ... |
98 99 |
.physfn.bus = physfn->bus->number, .physfn.devfn = physfn->devfn, |
e28c31a96 xen: register xen... |
100 101 102 103 |
}; r = HYPERVISOR_physdev_op(PHYSDEVOP_manage_pci_add_ext, &manage_pci_ext); |
55e901fc1 xen/pci: support ... |
104 |
} |
e28c31a96 xen: register xen... |
105 |
#endif |
55e901fc1 xen/pci: support ... |
106 |
else if (pci_ari_enabled(pci_dev->bus) && PCI_SLOT(pci_dev->devfn)) { |
e28c31a96 xen: register xen... |
107 108 109 110 111 112 113 114 115 116 |
struct physdev_manage_pci_ext manage_pci_ext = { .bus = pci_dev->bus->number, .devfn = pci_dev->devfn, .is_extfn = 1, }; r = HYPERVISOR_physdev_op(PHYSDEVOP_manage_pci_add_ext, &manage_pci_ext); } else { struct physdev_manage_pci manage_pci = { |
4b0109830 Xen: fix whitespa... |
117 |
.bus = pci_dev->bus->number, |
e28c31a96 xen: register xen... |
118 119 120 121 122 123 124 125 126 127 128 129 130 131 |
.devfn = pci_dev->devfn, }; r = HYPERVISOR_physdev_op(PHYSDEVOP_manage_pci_add, &manage_pci); } return r; } static int xen_remove_device(struct device *dev) { int r; struct pci_dev *pci_dev = to_pci_dev(dev); |
e28c31a96 xen: register xen... |
132 |
|
55e901fc1 xen/pci: support ... |
133 134 135 136 137 138 |
if (pci_seg_supported) { struct physdev_pci_device device = { .seg = pci_domain_nr(pci_dev->bus), .bus = pci_dev->bus->number, .devfn = pci_dev->devfn }; |
e28c31a96 xen: register xen... |
139 |
|
55e901fc1 xen/pci: support ... |
140 141 142 143 144 145 146 147 148 149 150 151 152 |
r = HYPERVISOR_physdev_op(PHYSDEVOP_pci_device_remove, &device); } else if (pci_domain_nr(pci_dev->bus)) r = -ENOSYS; else { struct physdev_manage_pci manage_pci = { .bus = pci_dev->bus->number, .devfn = pci_dev->devfn }; r = HYPERVISOR_physdev_op(PHYSDEVOP_manage_pci_remove, &manage_pci); } |
e28c31a96 xen: register xen... |
153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 |
return r; } static int xen_pci_notifier(struct notifier_block *nb, unsigned long action, void *data) { struct device *dev = data; int r = 0; switch (action) { case BUS_NOTIFY_ADD_DEVICE: r = xen_add_device(dev); break; case BUS_NOTIFY_DEL_DEVICE: r = xen_remove_device(dev); break; default: |
12e13ac84 xen/pci: make bus... |
171 |
return NOTIFY_DONE; |
e28c31a96 xen: register xen... |
172 |
} |
12e13ac84 xen/pci: make bus... |
173 174 175 176 177 178 |
if (r) dev_err(dev, "Failed to %s - passthrough or MSI/MSI-X might fail! ", action == BUS_NOTIFY_ADD_DEVICE ? "add" : (action == BUS_NOTIFY_DEL_DEVICE ? "delete" : "?")); return NOTIFY_OK; |
e28c31a96 xen: register xen... |
179 |
} |
12e13ac84 xen/pci: make bus... |
180 |
static struct notifier_block device_nb = { |
e28c31a96 xen: register xen... |
181 182 183 184 185 186 187 188 189 190 191 192 |
.notifier_call = xen_pci_notifier, }; static int __init register_xen_pci_notifier(void) { if (!xen_initial_domain()) return 0; return bus_register_notifier(&pci_bus_type, &device_nb); } arch_initcall(register_xen_pci_notifier); |