aboutsummaryrefslogtreecommitdiffstats
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
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>
-rw-r--r--arch/x86/pci/xen.c22
-rw-r--r--drivers/xen/pci.c94
-rw-r--r--include/xen/interface/physdev.h34
3 files changed, 136 insertions, 14 deletions
diff --git a/arch/x86/pci/xen.c b/arch/x86/pci/xen.c
index f567965c0620..265fa8814ccd 100644
--- a/arch/x86/pci/xen.c
+++ b/arch/x86/pci/xen.c
@@ -185,6 +185,8 @@ static void xen_teardown_msi_irq(unsigned int irq)
185} 185}
186 186
187#ifdef CONFIG_XEN_DOM0 187#ifdef CONFIG_XEN_DOM0
188static bool __read_mostly pci_seg_supported = true;
189
188static int xen_initdom_setup_msi_irqs(struct pci_dev *dev, int nvec, int type) 190static int xen_initdom_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)
189{ 191{
190 int ret = 0; 192 int ret = 0;
@@ -202,10 +204,11 @@ static int xen_initdom_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)
202 204
203 memset(&map_irq, 0, sizeof(map_irq)); 205 memset(&map_irq, 0, sizeof(map_irq));
204 map_irq.domid = domid; 206 map_irq.domid = domid;
205 map_irq.type = MAP_PIRQ_TYPE_MSI; 207 map_irq.type = MAP_PIRQ_TYPE_MSI_SEG;
206 map_irq.index = -1; 208 map_irq.index = -1;
207 map_irq.pirq = -1; 209 map_irq.pirq = -1;
208 map_irq.bus = dev->bus->number; 210 map_irq.bus = dev->bus->number |
211 (pci_domain_nr(dev->bus) << 16);
209 map_irq.devfn = dev->devfn; 212 map_irq.devfn = dev->devfn;
210 213
211 if (type == PCI_CAP_ID_MSIX) { 214 if (type == PCI_CAP_ID_MSIX) {
@@ -222,7 +225,20 @@ static int xen_initdom_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)
222 map_irq.entry_nr = msidesc->msi_attrib.entry_nr; 225 map_irq.entry_nr = msidesc->msi_attrib.entry_nr;
223 } 226 }
224 227
225 ret = HYPERVISOR_physdev_op(PHYSDEVOP_map_pirq, &map_irq); 228 ret = -EINVAL;
229 if (pci_seg_supported)
230 ret = HYPERVISOR_physdev_op(PHYSDEVOP_map_pirq,
231 &map_irq);
232 if (ret == -EINVAL && !pci_domain_nr(dev->bus)) {
233 map_irq.type = MAP_PIRQ_TYPE_MSI;
234 map_irq.index = -1;
235 map_irq.pirq = -1;
236 map_irq.bus = dev->bus->number;
237 ret = HYPERVISOR_physdev_op(PHYSDEVOP_map_pirq,
238 &map_irq);
239 if (ret != -EINVAL)
240 pci_seg_supported = false;
241 }
226 if (ret) { 242 if (ret) {
227 dev_warn(&dev->dev, "xen map irq failed %d for %d domain\n", 243 dev_warn(&dev->dev, "xen map irq failed %d for %d domain\n",
228 ret, domid); 244 ret, domid);
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}
diff --git a/include/xen/interface/physdev.h b/include/xen/interface/physdev.h
index 534cac89a77d..c1080d9c705d 100644
--- a/include/xen/interface/physdev.h
+++ b/include/xen/interface/physdev.h
@@ -109,6 +109,7 @@ struct physdev_irq {
109#define MAP_PIRQ_TYPE_MSI 0x0 109#define MAP_PIRQ_TYPE_MSI 0x0
110#define MAP_PIRQ_TYPE_GSI 0x1 110#define MAP_PIRQ_TYPE_GSI 0x1
111#define MAP_PIRQ_TYPE_UNKNOWN 0x2 111#define MAP_PIRQ_TYPE_UNKNOWN 0x2
112#define MAP_PIRQ_TYPE_MSI_SEG 0x3
112 113
113#define PHYSDEVOP_map_pirq 13 114#define PHYSDEVOP_map_pirq 13
114struct physdev_map_pirq { 115struct physdev_map_pirq {
@@ -119,7 +120,7 @@ struct physdev_map_pirq {
119 int index; 120 int index;
120 /* IN or OUT */ 121 /* IN or OUT */
121 int pirq; 122 int pirq;
122 /* IN */ 123 /* IN - high 16 bits hold segment for MAP_PIRQ_TYPE_MSI_SEG */
123 int bus; 124 int bus;
124 /* IN */ 125 /* IN */
125 int devfn; 126 int devfn;
@@ -198,6 +199,37 @@ struct physdev_get_free_pirq {
198 uint32_t pirq; 199 uint32_t pirq;
199}; 200};
200 201
202#define XEN_PCI_DEV_EXTFN 0x1
203#define XEN_PCI_DEV_VIRTFN 0x2
204#define XEN_PCI_DEV_PXM 0x4
205
206#define PHYSDEVOP_pci_device_add 25
207struct physdev_pci_device_add {
208 /* IN */
209 uint16_t seg;
210 uint8_t bus;
211 uint8_t devfn;
212 uint32_t flags;
213 struct {
214 uint8_t bus;
215 uint8_t devfn;
216 } physfn;
217#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
218 uint32_t optarr[];
219#elif defined(__GNUC__)
220 uint32_t optarr[0];
221#endif
222};
223
224#define PHYSDEVOP_pci_device_remove 26
225#define PHYSDEVOP_restore_msi_ext 27
226struct physdev_pci_device {
227 /* IN */
228 uint16_t seg;
229 uint8_t bus;
230 uint8_t devfn;
231};
232
201/* 233/*
202 * Notify that some PIRQ-bound event channels have been unmasked. 234 * Notify that some PIRQ-bound event channels have been unmasked.
203 * ** This command is obsolete since interface version 0x00030202 and is ** 235 * ** This command is obsolete since interface version 0x00030202 and is **