aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/xen/pci.c
diff options
context:
space:
mode:
authorJan Beulich <JBeulich@suse.com>2011-09-22 04:17:57 -0400
committerKonrad Rzeszutek Wilk <konrad.wilk@oracle.com>2011-09-22 16:23:46 -0400
commit55e901fc1f03dd8437f877813c68b6014cdbeefd (patch)
tree0f3d81f7bb534a89fcc59e3109246ca5cd75935b /drivers/xen/pci.c
parent6810df88dcfc22de267caf23eb072ffb97b3c411 (diff)
xen/pci: support multi-segment systems
Now that the hypercall interface changes are in -unstable, make the kernel side code not ignore the segment (aka domain) number anymore (which results in pretty odd behavior on such systems). Rather, if only the old interfaces are available, don't call them for devices on non-zero segments at all. Signed-off-by: Jan Beulich <jbeulich@suse.com> [v1: Edited git description] Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>
Diffstat (limited to 'drivers/xen/pci.c')
-rw-r--r--drivers/xen/pci.c94
1 files changed, 84 insertions, 10 deletions
diff --git a/drivers/xen/pci.c b/drivers/xen/pci.c
index 02c402b1ed80..66057075d6e2 100644
--- a/drivers/xen/pci.c
+++ b/drivers/xen/pci.c
@@ -18,6 +18,7 @@
18 */ 18 */
19 19
20#include <linux/pci.h> 20#include <linux/pci.h>
21#include <linux/acpi.h>
21#include <xen/xen.h> 22#include <xen/xen.h>
22#include <xen/interface/physdev.h> 23#include <xen/interface/physdev.h>
23#include <xen/interface/xen.h> 24#include <xen/interface/xen.h>
@@ -26,26 +27,85 @@
26#include <asm/xen/hypercall.h> 27#include <asm/xen/hypercall.h>
27#include "../pci/pci.h" 28#include "../pci/pci.h"
28 29
30static bool __read_mostly pci_seg_supported = true;
31
29static int xen_add_device(struct device *dev) 32static int xen_add_device(struct device *dev)
30{ 33{
31 int r; 34 int r;
32 struct pci_dev *pci_dev = to_pci_dev(dev); 35 struct pci_dev *pci_dev = to_pci_dev(dev);
36#ifdef CONFIG_PCI_IOV
37 struct pci_dev *physfn = pci_dev->physfn;
38#endif
39
40 if (pci_seg_supported) {
41 struct physdev_pci_device_add add = {
42 .seg = pci_domain_nr(pci_dev->bus),
43 .bus = pci_dev->bus->number,
44 .devfn = pci_dev->devfn
45 };
46#ifdef CONFIG_ACPI
47 acpi_handle handle;
48#endif
33 49
34#ifdef CONFIG_PCI_IOV 50#ifdef CONFIG_PCI_IOV
35 if (pci_dev->is_virtfn) { 51 if (pci_dev->is_virtfn) {
52 add.flags = XEN_PCI_DEV_VIRTFN;
53 add.physfn.bus = physfn->bus->number;
54 add.physfn.devfn = physfn->devfn;
55 } else
56#endif
57 if (pci_ari_enabled(pci_dev->bus) && PCI_SLOT(pci_dev->devfn))
58 add.flags = XEN_PCI_DEV_EXTFN;
59
60#ifdef CONFIG_ACPI
61 handle = DEVICE_ACPI_HANDLE(&pci_dev->dev);
62 if (!handle)
63 handle = DEVICE_ACPI_HANDLE(pci_dev->bus->bridge);
64#ifdef CONFIG_PCI_IOV
65 if (!handle && pci_dev->is_virtfn)
66 handle = DEVICE_ACPI_HANDLE(physfn->bus->bridge);
67#endif
68 if (handle) {
69 acpi_status status;
70
71 do {
72 unsigned long long pxm;
73
74 status = acpi_evaluate_integer(handle, "_PXM",
75 NULL, &pxm);
76 if (ACPI_SUCCESS(status)) {
77 add.optarr[0] = pxm;
78 add.flags |= XEN_PCI_DEV_PXM;
79 break;
80 }
81 status = acpi_get_parent(handle, &handle);
82 } while (ACPI_SUCCESS(status));
83 }
84#endif /* CONFIG_ACPI */
85
86 r = HYPERVISOR_physdev_op(PHYSDEVOP_pci_device_add, &add);
87 if (r != -ENOSYS)
88 return r;
89 pci_seg_supported = false;
90 }
91
92 if (pci_domain_nr(pci_dev->bus))
93 r = -ENOSYS;
94#ifdef CONFIG_PCI_IOV
95 else if (pci_dev->is_virtfn) {
36 struct physdev_manage_pci_ext manage_pci_ext = { 96 struct physdev_manage_pci_ext manage_pci_ext = {
37 .bus = pci_dev->bus->number, 97 .bus = pci_dev->bus->number,
38 .devfn = pci_dev->devfn, 98 .devfn = pci_dev->devfn,
39 .is_virtfn = 1, 99 .is_virtfn = 1,
40 .physfn.bus = pci_dev->physfn->bus->number, 100 .physfn.bus = physfn->bus->number,
41 .physfn.devfn = pci_dev->physfn->devfn, 101 .physfn.devfn = physfn->devfn,
42 }; 102 };
43 103
44 r = HYPERVISOR_physdev_op(PHYSDEVOP_manage_pci_add_ext, 104 r = HYPERVISOR_physdev_op(PHYSDEVOP_manage_pci_add_ext,
45 &manage_pci_ext); 105 &manage_pci_ext);
46 } else 106 }
47#endif 107#endif
48 if (pci_ari_enabled(pci_dev->bus) && PCI_SLOT(pci_dev->devfn)) { 108 else if (pci_ari_enabled(pci_dev->bus) && PCI_SLOT(pci_dev->devfn)) {
49 struct physdev_manage_pci_ext manage_pci_ext = { 109 struct physdev_manage_pci_ext manage_pci_ext = {
50 .bus = pci_dev->bus->number, 110 .bus = pci_dev->bus->number,
51 .devfn = pci_dev->devfn, 111 .devfn = pci_dev->devfn,
@@ -71,13 +131,27 @@ static int xen_remove_device(struct device *dev)
71{ 131{
72 int r; 132 int r;
73 struct pci_dev *pci_dev = to_pci_dev(dev); 133 struct pci_dev *pci_dev = to_pci_dev(dev);
74 struct physdev_manage_pci manage_pci;
75 134
76 manage_pci.bus = pci_dev->bus->number; 135 if (pci_seg_supported) {
77 manage_pci.devfn = pci_dev->devfn; 136 struct physdev_pci_device device = {
137 .seg = pci_domain_nr(pci_dev->bus),
138 .bus = pci_dev->bus->number,
139 .devfn = pci_dev->devfn
140 };
78 141
79 r = HYPERVISOR_physdev_op(PHYSDEVOP_manage_pci_remove, 142 r = HYPERVISOR_physdev_op(PHYSDEVOP_pci_device_remove,
80 &manage_pci); 143 &device);
144 } else if (pci_domain_nr(pci_dev->bus))
145 r = -ENOSYS;
146 else {
147 struct physdev_manage_pci manage_pci = {
148 .bus = pci_dev->bus->number,
149 .devfn = pci_dev->devfn
150 };
151
152 r = HYPERVISOR_physdev_op(PHYSDEVOP_manage_pci_remove,
153 &manage_pci);
154 }
81 155
82 return r; 156 return r;
83} 157}