diff options
-rw-r--r-- | arch/x86/pci/xen.c | 22 | ||||
-rw-r--r-- | drivers/xen/pci.c | 94 | ||||
-rw-r--r-- | include/xen/interface/physdev.h | 34 |
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 |
188 | static bool __read_mostly pci_seg_supported = true; | ||
189 | |||
188 | static int xen_initdom_setup_msi_irqs(struct pci_dev *dev, int nvec, int type) | 190 | static 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 | ||
30 | static bool __read_mostly pci_seg_supported = true; | ||
31 | |||
29 | static int xen_add_device(struct device *dev) | 32 | static 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 |
114 | struct physdev_map_pirq { | 115 | struct 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 | ||
207 | struct 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 | ||
226 | struct 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 ** |