diff options
Diffstat (limited to 'arch/x86/pci')
-rw-r--r-- | arch/x86/pci/acpi.c | 32 | ||||
-rw-r--r-- | arch/x86/pci/ce4100.c | 2 | ||||
-rw-r--r-- | arch/x86/pci/common.c | 14 | ||||
-rw-r--r-- | arch/x86/pci/direct.c | 6 | ||||
-rw-r--r-- | arch/x86/pci/mmconfig-shared.c | 3 | ||||
-rw-r--r-- | arch/x86/pci/numaq_32.c | 2 | ||||
-rw-r--r-- | arch/x86/pci/olpc.c | 4 | ||||
-rw-r--r-- | arch/x86/pci/pcbios.c | 2 | ||||
-rw-r--r-- | arch/x86/pci/visws.c | 2 | ||||
-rw-r--r-- | arch/x86/pci/xen.c | 401 |
10 files changed, 238 insertions, 230 deletions
diff --git a/arch/x86/pci/acpi.c b/arch/x86/pci/acpi.c index 68c3c1395202..404f21a3ff9e 100644 --- a/arch/x86/pci/acpi.c +++ b/arch/x86/pci/acpi.c | |||
@@ -43,6 +43,17 @@ static const struct dmi_system_id pci_use_crs_table[] __initconst = { | |||
43 | DMI_MATCH(DMI_PRODUCT_NAME, "ALiveSATA2-GLAN"), | 43 | DMI_MATCH(DMI_PRODUCT_NAME, "ALiveSATA2-GLAN"), |
44 | }, | 44 | }, |
45 | }, | 45 | }, |
46 | /* https://bugzilla.kernel.org/show_bug.cgi?id=30552 */ | ||
47 | /* 2006 AMD HT/VIA system with two host bridges */ | ||
48 | { | ||
49 | .callback = set_use_crs, | ||
50 | .ident = "ASUS M2V-MX SE", | ||
51 | .matches = { | ||
52 | DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer INC."), | ||
53 | DMI_MATCH(DMI_BOARD_NAME, "M2V-MX SE"), | ||
54 | DMI_MATCH(DMI_BIOS_VENDOR, "American Megatrends Inc."), | ||
55 | }, | ||
56 | }, | ||
46 | {} | 57 | {} |
47 | }; | 58 | }; |
48 | 59 | ||
@@ -246,10 +257,9 @@ static void add_resources(struct pci_root_info *info) | |||
246 | 257 | ||
247 | conflict = insert_resource_conflict(root, res); | 258 | conflict = insert_resource_conflict(root, res); |
248 | if (conflict) | 259 | if (conflict) |
249 | dev_err(&info->bridge->dev, | 260 | dev_info(&info->bridge->dev, |
250 | "address space collision: host bridge window %pR " | 261 | "ignoring host bridge window %pR (conflicts with %s %pR)\n", |
251 | "conflicts with %s %pR\n", | 262 | res, conflict->name, conflict); |
252 | res, conflict->name, conflict); | ||
253 | else | 263 | else |
254 | pci_bus_add_resource(info->bus, res, 0); | 264 | pci_bus_add_resource(info->bus, res, 0); |
255 | } | 265 | } |
@@ -361,6 +371,20 @@ struct pci_bus * __devinit pci_acpi_scan_root(struct acpi_pci_root *root) | |||
361 | } | 371 | } |
362 | } | 372 | } |
363 | 373 | ||
374 | /* After the PCI-E bus has been walked and all devices discovered, | ||
375 | * configure any settings of the fabric that might be necessary. | ||
376 | */ | ||
377 | if (bus) { | ||
378 | struct pci_bus *child; | ||
379 | list_for_each_entry(child, &bus->children, node) { | ||
380 | struct pci_dev *self = child->self; | ||
381 | if (!self) | ||
382 | continue; | ||
383 | |||
384 | pcie_bus_configure_settings(child, self->pcie_mpss); | ||
385 | } | ||
386 | } | ||
387 | |||
364 | if (!bus) | 388 | if (!bus) |
365 | kfree(sd); | 389 | kfree(sd); |
366 | 390 | ||
diff --git a/arch/x86/pci/ce4100.c b/arch/x86/pci/ce4100.c index 67858be4b52b..99176094500b 100644 --- a/arch/x86/pci/ce4100.c +++ b/arch/x86/pci/ce4100.c | |||
@@ -257,6 +257,7 @@ static int ce4100_conf_read(unsigned int seg, unsigned int bus, | |||
257 | { | 257 | { |
258 | int i; | 258 | int i; |
259 | 259 | ||
260 | WARN_ON(seg); | ||
260 | if (bus == 1) { | 261 | if (bus == 1) { |
261 | for (i = 0; i < ARRAY_SIZE(bus1_fixups); i++) { | 262 | for (i = 0; i < ARRAY_SIZE(bus1_fixups); i++) { |
262 | if (bus1_fixups[i].dev_func == devfn && | 263 | if (bus1_fixups[i].dev_func == devfn && |
@@ -282,6 +283,7 @@ static int ce4100_conf_write(unsigned int seg, unsigned int bus, | |||
282 | { | 283 | { |
283 | int i; | 284 | int i; |
284 | 285 | ||
286 | WARN_ON(seg); | ||
285 | if (bus == 1) { | 287 | if (bus == 1) { |
286 | for (i = 0; i < ARRAY_SIZE(bus1_fixups); i++) { | 288 | for (i = 0; i < ARRAY_SIZE(bus1_fixups); i++) { |
287 | if (bus1_fixups[i].dev_func == devfn && | 289 | if (bus1_fixups[i].dev_func == devfn && |
diff --git a/arch/x86/pci/common.c b/arch/x86/pci/common.c index 5fe75026ecc2..92df322e0b57 100644 --- a/arch/x86/pci/common.c +++ b/arch/x86/pci/common.c | |||
@@ -247,13 +247,6 @@ static const struct dmi_system_id __devinitconst pciprobe_dmi_table[] = { | |||
247 | }, | 247 | }, |
248 | #endif /* __i386__ */ | 248 | #endif /* __i386__ */ |
249 | { | 249 | { |
250 | .callback = find_sort_method, | ||
251 | .ident = "Dell System", | ||
252 | .matches = { | ||
253 | DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"), | ||
254 | }, | ||
255 | }, | ||
256 | { | ||
257 | .callback = set_bf_sort, | 250 | .callback = set_bf_sort, |
258 | .ident = "Dell PowerEdge 1950", | 251 | .ident = "Dell PowerEdge 1950", |
259 | .matches = { | 252 | .matches = { |
@@ -294,6 +287,13 @@ static const struct dmi_system_id __devinitconst pciprobe_dmi_table[] = { | |||
294 | }, | 287 | }, |
295 | }, | 288 | }, |
296 | { | 289 | { |
290 | .callback = find_sort_method, | ||
291 | .ident = "Dell System", | ||
292 | .matches = { | ||
293 | DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"), | ||
294 | }, | ||
295 | }, | ||
296 | { | ||
297 | .callback = set_bf_sort, | 297 | .callback = set_bf_sort, |
298 | .ident = "HP ProLiant BL20p G3", | 298 | .ident = "HP ProLiant BL20p G3", |
299 | .matches = { | 299 | .matches = { |
diff --git a/arch/x86/pci/direct.c b/arch/x86/pci/direct.c index e6fd8473fb7b..4f2c70439d7f 100644 --- a/arch/x86/pci/direct.c +++ b/arch/x86/pci/direct.c | |||
@@ -22,7 +22,7 @@ static int pci_conf1_read(unsigned int seg, unsigned int bus, | |||
22 | { | 22 | { |
23 | unsigned long flags; | 23 | unsigned long flags; |
24 | 24 | ||
25 | if ((bus > 255) || (devfn > 255) || (reg > 4095)) { | 25 | if (seg || (bus > 255) || (devfn > 255) || (reg > 4095)) { |
26 | *value = -1; | 26 | *value = -1; |
27 | return -EINVAL; | 27 | return -EINVAL; |
28 | } | 28 | } |
@@ -53,7 +53,7 @@ static int pci_conf1_write(unsigned int seg, unsigned int bus, | |||
53 | { | 53 | { |
54 | unsigned long flags; | 54 | unsigned long flags; |
55 | 55 | ||
56 | if ((bus > 255) || (devfn > 255) || (reg > 4095)) | 56 | if (seg || (bus > 255) || (devfn > 255) || (reg > 4095)) |
57 | return -EINVAL; | 57 | return -EINVAL; |
58 | 58 | ||
59 | raw_spin_lock_irqsave(&pci_config_lock, flags); | 59 | raw_spin_lock_irqsave(&pci_config_lock, flags); |
@@ -97,6 +97,7 @@ static int pci_conf2_read(unsigned int seg, unsigned int bus, | |||
97 | unsigned long flags; | 97 | unsigned long flags; |
98 | int dev, fn; | 98 | int dev, fn; |
99 | 99 | ||
100 | WARN_ON(seg); | ||
100 | if ((bus > 255) || (devfn > 255) || (reg > 255)) { | 101 | if ((bus > 255) || (devfn > 255) || (reg > 255)) { |
101 | *value = -1; | 102 | *value = -1; |
102 | return -EINVAL; | 103 | return -EINVAL; |
@@ -138,6 +139,7 @@ static int pci_conf2_write(unsigned int seg, unsigned int bus, | |||
138 | unsigned long flags; | 139 | unsigned long flags; |
139 | int dev, fn; | 140 | int dev, fn; |
140 | 141 | ||
142 | WARN_ON(seg); | ||
141 | if ((bus > 255) || (devfn > 255) || (reg > 255)) | 143 | if ((bus > 255) || (devfn > 255) || (reg > 255)) |
142 | return -EINVAL; | 144 | return -EINVAL; |
143 | 145 | ||
diff --git a/arch/x86/pci/mmconfig-shared.c b/arch/x86/pci/mmconfig-shared.c index 750c346ef50a..301e325992f6 100644 --- a/arch/x86/pci/mmconfig-shared.c +++ b/arch/x86/pci/mmconfig-shared.c | |||
@@ -519,7 +519,8 @@ static int __init acpi_mcfg_check_entry(struct acpi_table_mcfg *mcfg, | |||
519 | if (cfg->address < 0xFFFFFFFF) | 519 | if (cfg->address < 0xFFFFFFFF) |
520 | return 0; | 520 | return 0; |
521 | 521 | ||
522 | if (!strcmp(mcfg->header.oem_id, "SGI")) | 522 | if (!strcmp(mcfg->header.oem_id, "SGI") || |
523 | !strcmp(mcfg->header.oem_id, "SGI2")) | ||
523 | return 0; | 524 | return 0; |
524 | 525 | ||
525 | if (mcfg->header.revision >= 1) { | 526 | if (mcfg->header.revision >= 1) { |
diff --git a/arch/x86/pci/numaq_32.c b/arch/x86/pci/numaq_32.c index 5c9e2458df4e..512a88c41501 100644 --- a/arch/x86/pci/numaq_32.c +++ b/arch/x86/pci/numaq_32.c | |||
@@ -34,6 +34,7 @@ static int pci_conf1_mq_read(unsigned int seg, unsigned int bus, | |||
34 | unsigned long flags; | 34 | unsigned long flags; |
35 | void *adr __iomem = XQUAD_PORT_ADDR(0xcfc, BUS2QUAD(bus)); | 35 | void *adr __iomem = XQUAD_PORT_ADDR(0xcfc, BUS2QUAD(bus)); |
36 | 36 | ||
37 | WARN_ON(seg); | ||
37 | if (!value || (bus >= MAX_MP_BUSSES) || (devfn > 255) || (reg > 255)) | 38 | if (!value || (bus >= MAX_MP_BUSSES) || (devfn > 255) || (reg > 255)) |
38 | return -EINVAL; | 39 | return -EINVAL; |
39 | 40 | ||
@@ -73,6 +74,7 @@ static int pci_conf1_mq_write(unsigned int seg, unsigned int bus, | |||
73 | unsigned long flags; | 74 | unsigned long flags; |
74 | void *adr __iomem = XQUAD_PORT_ADDR(0xcfc, BUS2QUAD(bus)); | 75 | void *adr __iomem = XQUAD_PORT_ADDR(0xcfc, BUS2QUAD(bus)); |
75 | 76 | ||
77 | WARN_ON(seg); | ||
76 | if ((bus >= MAX_MP_BUSSES) || (devfn > 255) || (reg > 255)) | 78 | if ((bus >= MAX_MP_BUSSES) || (devfn > 255) || (reg > 255)) |
77 | return -EINVAL; | 79 | return -EINVAL; |
78 | 80 | ||
diff --git a/arch/x86/pci/olpc.c b/arch/x86/pci/olpc.c index 13700ec8e2e4..5262603b04d9 100644 --- a/arch/x86/pci/olpc.c +++ b/arch/x86/pci/olpc.c | |||
@@ -206,6 +206,8 @@ static int pci_olpc_read(unsigned int seg, unsigned int bus, | |||
206 | { | 206 | { |
207 | uint32_t *addr; | 207 | uint32_t *addr; |
208 | 208 | ||
209 | WARN_ON(seg); | ||
210 | |||
209 | /* Use the hardware mechanism for non-simulated devices */ | 211 | /* Use the hardware mechanism for non-simulated devices */ |
210 | if (!is_simulated(bus, devfn)) | 212 | if (!is_simulated(bus, devfn)) |
211 | return pci_direct_conf1.read(seg, bus, devfn, reg, len, value); | 213 | return pci_direct_conf1.read(seg, bus, devfn, reg, len, value); |
@@ -264,6 +266,8 @@ static int pci_olpc_read(unsigned int seg, unsigned int bus, | |||
264 | static int pci_olpc_write(unsigned int seg, unsigned int bus, | 266 | static int pci_olpc_write(unsigned int seg, unsigned int bus, |
265 | unsigned int devfn, int reg, int len, uint32_t value) | 267 | unsigned int devfn, int reg, int len, uint32_t value) |
266 | { | 268 | { |
269 | WARN_ON(seg); | ||
270 | |||
267 | /* Use the hardware mechanism for non-simulated devices */ | 271 | /* Use the hardware mechanism for non-simulated devices */ |
268 | if (!is_simulated(bus, devfn)) | 272 | if (!is_simulated(bus, devfn)) |
269 | return pci_direct_conf1.write(seg, bus, devfn, reg, len, value); | 273 | return pci_direct_conf1.write(seg, bus, devfn, reg, len, value); |
diff --git a/arch/x86/pci/pcbios.c b/arch/x86/pci/pcbios.c index a5f7d0d63de0..f68553551467 100644 --- a/arch/x86/pci/pcbios.c +++ b/arch/x86/pci/pcbios.c | |||
@@ -181,6 +181,7 @@ static int pci_bios_read(unsigned int seg, unsigned int bus, | |||
181 | unsigned long flags; | 181 | unsigned long flags; |
182 | unsigned long bx = (bus << 8) | devfn; | 182 | unsigned long bx = (bus << 8) | devfn; |
183 | 183 | ||
184 | WARN_ON(seg); | ||
184 | if (!value || (bus > 255) || (devfn > 255) || (reg > 255)) | 185 | if (!value || (bus > 255) || (devfn > 255) || (reg > 255)) |
185 | return -EINVAL; | 186 | return -EINVAL; |
186 | 187 | ||
@@ -247,6 +248,7 @@ static int pci_bios_write(unsigned int seg, unsigned int bus, | |||
247 | unsigned long flags; | 248 | unsigned long flags; |
248 | unsigned long bx = (bus << 8) | devfn; | 249 | unsigned long bx = (bus << 8) | devfn; |
249 | 250 | ||
251 | WARN_ON(seg); | ||
250 | if ((bus > 255) || (devfn > 255) || (reg > 255)) | 252 | if ((bus > 255) || (devfn > 255) || (reg > 255)) |
251 | return -EINVAL; | 253 | return -EINVAL; |
252 | 254 | ||
diff --git a/arch/x86/pci/visws.c b/arch/x86/pci/visws.c index 03008f72eb04..6f2f8eeed171 100644 --- a/arch/x86/pci/visws.c +++ b/arch/x86/pci/visws.c | |||
@@ -24,7 +24,7 @@ static void pci_visws_disable_irq(struct pci_dev *dev) { } | |||
24 | 24 | ||
25 | unsigned int pci_bus0, pci_bus1; | 25 | unsigned int pci_bus0, pci_bus1; |
26 | 26 | ||
27 | static int __init visws_map_irq(struct pci_dev *dev, u8 slot, u8 pin) | 27 | static int __init visws_map_irq(const struct pci_dev *dev, u8 slot, u8 pin) |
28 | { | 28 | { |
29 | int irq, bus = dev->bus->number; | 29 | int irq, bus = dev->bus->number; |
30 | 30 | ||
diff --git a/arch/x86/pci/xen.c b/arch/x86/pci/xen.c index f567965c0620..492ade8c978e 100644 --- a/arch/x86/pci/xen.c +++ b/arch/x86/pci/xen.c | |||
@@ -1,8 +1,13 @@ | |||
1 | /* | 1 | /* |
2 | * Xen PCI Frontend Stub - puts some "dummy" functions in to the Linux | 2 | * Xen PCI - handle PCI (INTx) and MSI infrastructure calls for PV, HVM and |
3 | * x86 PCI core to support the Xen PCI Frontend | 3 | * initial domain support. We also handle the DSDT _PRT callbacks for GSI's |
4 | * used in HVM and initial domain mode (PV does not parse ACPI, so it has no | ||
5 | * concept of GSIs). Under PV we hook under the pnbbios API for IRQs and | ||
6 | * 0xcf8 PCI configuration read/write. | ||
4 | * | 7 | * |
5 | * Author: Ryan Wilson <hap9@epoch.ncsc.mil> | 8 | * Author: Ryan Wilson <hap9@epoch.ncsc.mil> |
9 | * Konrad Rzeszutek Wilk <konrad.wilk@oracle.com> | ||
10 | * Stefano Stabellini <stefano.stabellini@eu.citrix.com> | ||
6 | */ | 11 | */ |
7 | #include <linux/module.h> | 12 | #include <linux/module.h> |
8 | #include <linux/init.h> | 13 | #include <linux/init.h> |
@@ -19,22 +24,53 @@ | |||
19 | #include <xen/events.h> | 24 | #include <xen/events.h> |
20 | #include <asm/xen/pci.h> | 25 | #include <asm/xen/pci.h> |
21 | 26 | ||
27 | static int xen_pcifront_enable_irq(struct pci_dev *dev) | ||
28 | { | ||
29 | int rc; | ||
30 | int share = 1; | ||
31 | int pirq; | ||
32 | u8 gsi; | ||
33 | |||
34 | rc = pci_read_config_byte(dev, PCI_INTERRUPT_LINE, &gsi); | ||
35 | if (rc < 0) { | ||
36 | dev_warn(&dev->dev, "Xen PCI: failed to read interrupt line: %d\n", | ||
37 | rc); | ||
38 | return rc; | ||
39 | } | ||
40 | /* In PV DomU the Xen PCI backend puts the PIRQ in the interrupt line.*/ | ||
41 | pirq = gsi; | ||
42 | |||
43 | if (gsi < NR_IRQS_LEGACY) | ||
44 | share = 0; | ||
45 | |||
46 | rc = xen_bind_pirq_gsi_to_irq(gsi, pirq, share, "pcifront"); | ||
47 | if (rc < 0) { | ||
48 | dev_warn(&dev->dev, "Xen PCI: failed to bind GSI%d (PIRQ%d) to IRQ: %d\n", | ||
49 | gsi, pirq, rc); | ||
50 | return rc; | ||
51 | } | ||
52 | |||
53 | dev->irq = rc; | ||
54 | dev_info(&dev->dev, "Xen PCI mapped GSI%d to IRQ%d\n", gsi, dev->irq); | ||
55 | return 0; | ||
56 | } | ||
57 | |||
22 | #ifdef CONFIG_ACPI | 58 | #ifdef CONFIG_ACPI |
23 | static int acpi_register_gsi_xen_hvm(struct device *dev, u32 gsi, | 59 | static int xen_register_pirq(u32 gsi, int gsi_override, int triggering, |
24 | int trigger, int polarity) | 60 | bool set_pirq) |
25 | { | 61 | { |
26 | int rc, irq; | 62 | int rc, pirq = -1, irq = -1; |
27 | struct physdev_map_pirq map_irq; | 63 | struct physdev_map_pirq map_irq; |
28 | int shareable = 0; | 64 | int shareable = 0; |
29 | char *name; | 65 | char *name; |
30 | 66 | ||
31 | if (!xen_hvm_domain()) | 67 | if (set_pirq) |
32 | return -1; | 68 | pirq = gsi; |
33 | 69 | ||
34 | map_irq.domid = DOMID_SELF; | 70 | map_irq.domid = DOMID_SELF; |
35 | map_irq.type = MAP_PIRQ_TYPE_GSI; | 71 | map_irq.type = MAP_PIRQ_TYPE_GSI; |
36 | map_irq.index = gsi; | 72 | map_irq.index = gsi; |
37 | map_irq.pirq = -1; | 73 | map_irq.pirq = pirq; |
38 | 74 | ||
39 | rc = HYPERVISOR_physdev_op(PHYSDEVOP_map_pirq, &map_irq); | 75 | rc = HYPERVISOR_physdev_op(PHYSDEVOP_map_pirq, &map_irq); |
40 | if (rc) { | 76 | if (rc) { |
@@ -42,7 +78,7 @@ static int acpi_register_gsi_xen_hvm(struct device *dev, u32 gsi, | |||
42 | return -1; | 78 | return -1; |
43 | } | 79 | } |
44 | 80 | ||
45 | if (trigger == ACPI_EDGE_SENSITIVE) { | 81 | if (triggering == ACPI_EDGE_SENSITIVE) { |
46 | shareable = 0; | 82 | shareable = 0; |
47 | name = "ioapic-edge"; | 83 | name = "ioapic-edge"; |
48 | } else { | 84 | } else { |
@@ -50,12 +86,63 @@ static int acpi_register_gsi_xen_hvm(struct device *dev, u32 gsi, | |||
50 | name = "ioapic-level"; | 86 | name = "ioapic-level"; |
51 | } | 87 | } |
52 | 88 | ||
89 | if (gsi_override >= 0) | ||
90 | gsi = gsi_override; | ||
91 | |||
53 | irq = xen_bind_pirq_gsi_to_irq(gsi, map_irq.pirq, shareable, name); | 92 | irq = xen_bind_pirq_gsi_to_irq(gsi, map_irq.pirq, shareable, name); |
93 | if (irq < 0) | ||
94 | goto out; | ||
95 | |||
96 | printk(KERN_DEBUG "xen: --> pirq=%d -> irq=%d (gsi=%d)\n", map_irq.pirq, irq, gsi); | ||
97 | out: | ||
98 | return irq; | ||
99 | } | ||
100 | |||
101 | static int acpi_register_gsi_xen_hvm(struct device *dev, u32 gsi, | ||
102 | int trigger, int polarity) | ||
103 | { | ||
104 | if (!xen_hvm_domain()) | ||
105 | return -1; | ||
54 | 106 | ||
55 | printk(KERN_DEBUG "xen: --> irq=%d, pirq=%d\n", irq, map_irq.pirq); | 107 | return xen_register_pirq(gsi, -1 /* no GSI override */, trigger, |
108 | false /* no mapping of GSI to PIRQ */); | ||
109 | } | ||
110 | |||
111 | #ifdef CONFIG_XEN_DOM0 | ||
112 | static int xen_register_gsi(u32 gsi, int gsi_override, int triggering, int polarity) | ||
113 | { | ||
114 | int rc, irq; | ||
115 | struct physdev_setup_gsi setup_gsi; | ||
116 | |||
117 | if (!xen_pv_domain()) | ||
118 | return -1; | ||
119 | |||
120 | printk(KERN_DEBUG "xen: registering gsi %u triggering %d polarity %d\n", | ||
121 | gsi, triggering, polarity); | ||
122 | |||
123 | irq = xen_register_pirq(gsi, gsi_override, triggering, true); | ||
124 | |||
125 | setup_gsi.gsi = gsi; | ||
126 | setup_gsi.triggering = (triggering == ACPI_EDGE_SENSITIVE ? 0 : 1); | ||
127 | setup_gsi.polarity = (polarity == ACPI_ACTIVE_HIGH ? 0 : 1); | ||
128 | |||
129 | rc = HYPERVISOR_physdev_op(PHYSDEVOP_setup_gsi, &setup_gsi); | ||
130 | if (rc == -EEXIST) | ||
131 | printk(KERN_INFO "Already setup the GSI :%d\n", gsi); | ||
132 | else if (rc) { | ||
133 | printk(KERN_ERR "Failed to setup GSI :%d, err_code:%d\n", | ||
134 | gsi, rc); | ||
135 | } | ||
56 | 136 | ||
57 | return irq; | 137 | return irq; |
58 | } | 138 | } |
139 | |||
140 | static int acpi_register_gsi_xen(struct device *dev, u32 gsi, | ||
141 | int trigger, int polarity) | ||
142 | { | ||
143 | return xen_register_gsi(gsi, -1 /* no GSI override */, trigger, polarity); | ||
144 | } | ||
145 | #endif | ||
59 | #endif | 146 | #endif |
60 | 147 | ||
61 | #if defined(CONFIG_PCI_MSI) | 148 | #if defined(CONFIG_PCI_MSI) |
@@ -65,6 +152,45 @@ static int acpi_register_gsi_xen_hvm(struct device *dev, u32 gsi, | |||
65 | struct xen_pci_frontend_ops *xen_pci_frontend; | 152 | struct xen_pci_frontend_ops *xen_pci_frontend; |
66 | EXPORT_SYMBOL_GPL(xen_pci_frontend); | 153 | EXPORT_SYMBOL_GPL(xen_pci_frontend); |
67 | 154 | ||
155 | static int xen_setup_msi_irqs(struct pci_dev *dev, int nvec, int type) | ||
156 | { | ||
157 | int irq, ret, i; | ||
158 | struct msi_desc *msidesc; | ||
159 | int *v; | ||
160 | |||
161 | v = kzalloc(sizeof(int) * max(1, nvec), GFP_KERNEL); | ||
162 | if (!v) | ||
163 | return -ENOMEM; | ||
164 | |||
165 | if (type == PCI_CAP_ID_MSIX) | ||
166 | ret = xen_pci_frontend_enable_msix(dev, v, nvec); | ||
167 | else | ||
168 | ret = xen_pci_frontend_enable_msi(dev, v); | ||
169 | if (ret) | ||
170 | goto error; | ||
171 | i = 0; | ||
172 | list_for_each_entry(msidesc, &dev->msi_list, list) { | ||
173 | irq = xen_bind_pirq_msi_to_irq(dev, msidesc, v[i], 0, | ||
174 | (type == PCI_CAP_ID_MSIX) ? | ||
175 | "pcifront-msi-x" : | ||
176 | "pcifront-msi", | ||
177 | DOMID_SELF); | ||
178 | if (irq < 0) { | ||
179 | ret = irq; | ||
180 | goto free; | ||
181 | } | ||
182 | i++; | ||
183 | } | ||
184 | kfree(v); | ||
185 | return 0; | ||
186 | |||
187 | error: | ||
188 | dev_err(&dev->dev, "Xen PCI frontend has not registered MSI/MSI-X support!\n"); | ||
189 | free: | ||
190 | kfree(v); | ||
191 | return ret; | ||
192 | } | ||
193 | |||
68 | #define XEN_PIRQ_MSI_DATA (MSI_DATA_TRIGGER_EDGE | \ | 194 | #define XEN_PIRQ_MSI_DATA (MSI_DATA_TRIGGER_EDGE | \ |
69 | MSI_DATA_LEVEL_ASSERT | (3 << 8) | MSI_DATA_VECTOR(0)) | 195 | MSI_DATA_LEVEL_ASSERT | (3 << 8) | MSI_DATA_VECTOR(0)) |
70 | 196 | ||
@@ -97,8 +223,10 @@ static int xen_hvm_setup_msi_irqs(struct pci_dev *dev, int nvec, int type) | |||
97 | if (msg.data != XEN_PIRQ_MSI_DATA || | 223 | if (msg.data != XEN_PIRQ_MSI_DATA || |
98 | xen_irq_from_pirq(pirq) < 0) { | 224 | xen_irq_from_pirq(pirq) < 0) { |
99 | pirq = xen_allocate_pirq_msi(dev, msidesc); | 225 | pirq = xen_allocate_pirq_msi(dev, msidesc); |
100 | if (pirq < 0) | 226 | if (pirq < 0) { |
227 | irq = -ENODEV; | ||
101 | goto error; | 228 | goto error; |
229 | } | ||
102 | xen_msi_compose_msg(dev, pirq, &msg); | 230 | xen_msi_compose_msg(dev, pirq, &msg); |
103 | __write_msi_msg(msidesc, &msg); | 231 | __write_msi_msg(msidesc, &msg); |
104 | dev_dbg(&dev->dev, "xen: msi bound to pirq=%d\n", pirq); | 232 | dev_dbg(&dev->dev, "xen: msi bound to pirq=%d\n", pirq); |
@@ -120,71 +248,12 @@ static int xen_hvm_setup_msi_irqs(struct pci_dev *dev, int nvec, int type) | |||
120 | error: | 248 | error: |
121 | dev_err(&dev->dev, | 249 | dev_err(&dev->dev, |
122 | "Xen PCI frontend has not registered MSI/MSI-X support!\n"); | 250 | "Xen PCI frontend has not registered MSI/MSI-X support!\n"); |
123 | return -ENODEV; | 251 | return irq; |
124 | } | ||
125 | |||
126 | /* | ||
127 | * For MSI interrupts we have to use drivers/xen/event.s functions to | ||
128 | * allocate an irq_desc and setup the right */ | ||
129 | |||
130 | |||
131 | static int xen_setup_msi_irqs(struct pci_dev *dev, int nvec, int type) | ||
132 | { | ||
133 | int irq, ret, i; | ||
134 | struct msi_desc *msidesc; | ||
135 | int *v; | ||
136 | |||
137 | v = kzalloc(sizeof(int) * max(1, nvec), GFP_KERNEL); | ||
138 | if (!v) | ||
139 | return -ENOMEM; | ||
140 | |||
141 | if (type == PCI_CAP_ID_MSIX) | ||
142 | ret = xen_pci_frontend_enable_msix(dev, v, nvec); | ||
143 | else | ||
144 | ret = xen_pci_frontend_enable_msi(dev, v); | ||
145 | if (ret) | ||
146 | goto error; | ||
147 | i = 0; | ||
148 | list_for_each_entry(msidesc, &dev->msi_list, list) { | ||
149 | irq = xen_bind_pirq_msi_to_irq(dev, msidesc, v[i], 0, | ||
150 | (type == PCI_CAP_ID_MSIX) ? | ||
151 | "pcifront-msi-x" : | ||
152 | "pcifront-msi", | ||
153 | DOMID_SELF); | ||
154 | if (irq < 0) | ||
155 | goto free; | ||
156 | i++; | ||
157 | } | ||
158 | kfree(v); | ||
159 | return 0; | ||
160 | |||
161 | error: | ||
162 | dev_err(&dev->dev, "Xen PCI frontend has not registered MSI/MSI-X support!\n"); | ||
163 | free: | ||
164 | kfree(v); | ||
165 | return ret; | ||
166 | } | ||
167 | |||
168 | static void xen_teardown_msi_irqs(struct pci_dev *dev) | ||
169 | { | ||
170 | struct msi_desc *msidesc; | ||
171 | |||
172 | msidesc = list_entry(dev->msi_list.next, struct msi_desc, list); | ||
173 | if (msidesc->msi_attrib.is_msix) | ||
174 | xen_pci_frontend_disable_msix(dev); | ||
175 | else | ||
176 | xen_pci_frontend_disable_msi(dev); | ||
177 | |||
178 | /* Free the IRQ's and the msidesc using the generic code. */ | ||
179 | default_teardown_msi_irqs(dev); | ||
180 | } | ||
181 | |||
182 | static void xen_teardown_msi_irq(unsigned int irq) | ||
183 | { | ||
184 | xen_destroy_irq(irq); | ||
185 | } | 252 | } |
186 | 253 | ||
187 | #ifdef CONFIG_XEN_DOM0 | 254 | #ifdef CONFIG_XEN_DOM0 |
255 | static bool __read_mostly pci_seg_supported = true; | ||
256 | |||
188 | static int xen_initdom_setup_msi_irqs(struct pci_dev *dev, int nvec, int type) | 257 | static int xen_initdom_setup_msi_irqs(struct pci_dev *dev, int nvec, int type) |
189 | { | 258 | { |
190 | int ret = 0; | 259 | int ret = 0; |
@@ -202,10 +271,11 @@ static int xen_initdom_setup_msi_irqs(struct pci_dev *dev, int nvec, int type) | |||
202 | 271 | ||
203 | memset(&map_irq, 0, sizeof(map_irq)); | 272 | memset(&map_irq, 0, sizeof(map_irq)); |
204 | map_irq.domid = domid; | 273 | map_irq.domid = domid; |
205 | map_irq.type = MAP_PIRQ_TYPE_MSI; | 274 | map_irq.type = MAP_PIRQ_TYPE_MSI_SEG; |
206 | map_irq.index = -1; | 275 | map_irq.index = -1; |
207 | map_irq.pirq = -1; | 276 | map_irq.pirq = -1; |
208 | map_irq.bus = dev->bus->number; | 277 | map_irq.bus = dev->bus->number | |
278 | (pci_domain_nr(dev->bus) << 16); | ||
209 | map_irq.devfn = dev->devfn; | 279 | map_irq.devfn = dev->devfn; |
210 | 280 | ||
211 | if (type == PCI_CAP_ID_MSIX) { | 281 | if (type == PCI_CAP_ID_MSIX) { |
@@ -222,7 +292,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; | 292 | map_irq.entry_nr = msidesc->msi_attrib.entry_nr; |
223 | } | 293 | } |
224 | 294 | ||
225 | ret = HYPERVISOR_physdev_op(PHYSDEVOP_map_pirq, &map_irq); | 295 | ret = -EINVAL; |
296 | if (pci_seg_supported) | ||
297 | ret = HYPERVISOR_physdev_op(PHYSDEVOP_map_pirq, | ||
298 | &map_irq); | ||
299 | if (ret == -EINVAL && !pci_domain_nr(dev->bus)) { | ||
300 | map_irq.type = MAP_PIRQ_TYPE_MSI; | ||
301 | map_irq.index = -1; | ||
302 | map_irq.pirq = -1; | ||
303 | map_irq.bus = dev->bus->number; | ||
304 | ret = HYPERVISOR_physdev_op(PHYSDEVOP_map_pirq, | ||
305 | &map_irq); | ||
306 | if (ret != -EINVAL) | ||
307 | pci_seg_supported = false; | ||
308 | } | ||
226 | if (ret) { | 309 | if (ret) { |
227 | dev_warn(&dev->dev, "xen map irq failed %d for %d domain\n", | 310 | dev_warn(&dev->dev, "xen map irq failed %d for %d domain\n", |
228 | ret, domid); | 311 | ret, domid); |
@@ -242,45 +325,28 @@ out: | |||
242 | return ret; | 325 | return ret; |
243 | } | 326 | } |
244 | #endif | 327 | #endif |
245 | #endif | ||
246 | 328 | ||
247 | static int xen_pcifront_enable_irq(struct pci_dev *dev) | 329 | static void xen_teardown_msi_irqs(struct pci_dev *dev) |
248 | { | 330 | { |
249 | int rc; | 331 | struct msi_desc *msidesc; |
250 | int share = 1; | ||
251 | int pirq; | ||
252 | u8 gsi; | ||
253 | |||
254 | rc = pci_read_config_byte(dev, PCI_INTERRUPT_LINE, &gsi); | ||
255 | if (rc < 0) { | ||
256 | dev_warn(&dev->dev, "Xen PCI: failed to read interrupt line: %d\n", | ||
257 | rc); | ||
258 | return rc; | ||
259 | } | ||
260 | |||
261 | rc = xen_allocate_pirq_gsi(gsi); | ||
262 | if (rc < 0) { | ||
263 | dev_warn(&dev->dev, "Xen PCI: failed to allocate a PIRQ for GSI%d: %d\n", | ||
264 | gsi, rc); | ||
265 | return rc; | ||
266 | } | ||
267 | pirq = rc; | ||
268 | 332 | ||
269 | if (gsi < NR_IRQS_LEGACY) | 333 | msidesc = list_entry(dev->msi_list.next, struct msi_desc, list); |
270 | share = 0; | 334 | if (msidesc->msi_attrib.is_msix) |
335 | xen_pci_frontend_disable_msix(dev); | ||
336 | else | ||
337 | xen_pci_frontend_disable_msi(dev); | ||
271 | 338 | ||
272 | rc = xen_bind_pirq_gsi_to_irq(gsi, pirq, share, "pcifront"); | 339 | /* Free the IRQ's and the msidesc using the generic code. */ |
273 | if (rc < 0) { | 340 | default_teardown_msi_irqs(dev); |
274 | dev_warn(&dev->dev, "Xen PCI: failed to bind GSI%d (PIRQ%d) to IRQ: %d\n", | 341 | } |
275 | gsi, pirq, rc); | ||
276 | return rc; | ||
277 | } | ||
278 | 342 | ||
279 | dev->irq = rc; | 343 | static void xen_teardown_msi_irq(unsigned int irq) |
280 | dev_info(&dev->dev, "Xen PCI mapped GSI%d to IRQ%d\n", gsi, dev->irq); | 344 | { |
281 | return 0; | 345 | xen_destroy_irq(irq); |
282 | } | 346 | } |
283 | 347 | ||
348 | #endif | ||
349 | |||
284 | int __init pci_xen_init(void) | 350 | int __init pci_xen_init(void) |
285 | { | 351 | { |
286 | if (!xen_pv_domain() || xen_initial_domain()) | 352 | if (!xen_pv_domain() || xen_initial_domain()) |
@@ -327,79 +393,6 @@ int __init pci_xen_hvm_init(void) | |||
327 | } | 393 | } |
328 | 394 | ||
329 | #ifdef CONFIG_XEN_DOM0 | 395 | #ifdef CONFIG_XEN_DOM0 |
330 | static int xen_register_pirq(u32 gsi, int gsi_override, int triggering) | ||
331 | { | ||
332 | int rc, pirq, irq = -1; | ||
333 | struct physdev_map_pirq map_irq; | ||
334 | int shareable = 0; | ||
335 | char *name; | ||
336 | |||
337 | if (!xen_pv_domain()) | ||
338 | return -1; | ||
339 | |||
340 | if (triggering == ACPI_EDGE_SENSITIVE) { | ||
341 | shareable = 0; | ||
342 | name = "ioapic-edge"; | ||
343 | } else { | ||
344 | shareable = 1; | ||
345 | name = "ioapic-level"; | ||
346 | } | ||
347 | pirq = xen_allocate_pirq_gsi(gsi); | ||
348 | if (pirq < 0) | ||
349 | goto out; | ||
350 | |||
351 | if (gsi_override >= 0) | ||
352 | irq = xen_bind_pirq_gsi_to_irq(gsi_override, pirq, shareable, name); | ||
353 | else | ||
354 | irq = xen_bind_pirq_gsi_to_irq(gsi, pirq, shareable, name); | ||
355 | if (irq < 0) | ||
356 | goto out; | ||
357 | |||
358 | printk(KERN_DEBUG "xen: --> pirq=%d -> irq=%d (gsi=%d)\n", pirq, irq, gsi); | ||
359 | |||
360 | map_irq.domid = DOMID_SELF; | ||
361 | map_irq.type = MAP_PIRQ_TYPE_GSI; | ||
362 | map_irq.index = gsi; | ||
363 | map_irq.pirq = pirq; | ||
364 | |||
365 | rc = HYPERVISOR_physdev_op(PHYSDEVOP_map_pirq, &map_irq); | ||
366 | if (rc) { | ||
367 | printk(KERN_WARNING "xen map irq failed %d\n", rc); | ||
368 | return -1; | ||
369 | } | ||
370 | |||
371 | out: | ||
372 | return irq; | ||
373 | } | ||
374 | |||
375 | static int xen_register_gsi(u32 gsi, int gsi_override, int triggering, int polarity) | ||
376 | { | ||
377 | int rc, irq; | ||
378 | struct physdev_setup_gsi setup_gsi; | ||
379 | |||
380 | if (!xen_pv_domain()) | ||
381 | return -1; | ||
382 | |||
383 | printk(KERN_DEBUG "xen: registering gsi %u triggering %d polarity %d\n", | ||
384 | gsi, triggering, polarity); | ||
385 | |||
386 | irq = xen_register_pirq(gsi, gsi_override, triggering); | ||
387 | |||
388 | setup_gsi.gsi = gsi; | ||
389 | setup_gsi.triggering = (triggering == ACPI_EDGE_SENSITIVE ? 0 : 1); | ||
390 | setup_gsi.polarity = (polarity == ACPI_ACTIVE_HIGH ? 0 : 1); | ||
391 | |||
392 | rc = HYPERVISOR_physdev_op(PHYSDEVOP_setup_gsi, &setup_gsi); | ||
393 | if (rc == -EEXIST) | ||
394 | printk(KERN_INFO "Already setup the GSI :%d\n", gsi); | ||
395 | else if (rc) { | ||
396 | printk(KERN_ERR "Failed to setup GSI :%d, err_code:%d\n", | ||
397 | gsi, rc); | ||
398 | } | ||
399 | |||
400 | return irq; | ||
401 | } | ||
402 | |||
403 | static __init void xen_setup_acpi_sci(void) | 396 | static __init void xen_setup_acpi_sci(void) |
404 | { | 397 | { |
405 | int rc; | 398 | int rc; |
@@ -419,7 +412,7 @@ static __init void xen_setup_acpi_sci(void) | |||
419 | } | 412 | } |
420 | trigger = trigger ? ACPI_LEVEL_SENSITIVE : ACPI_EDGE_SENSITIVE; | 413 | trigger = trigger ? ACPI_LEVEL_SENSITIVE : ACPI_EDGE_SENSITIVE; |
421 | polarity = polarity ? ACPI_ACTIVE_LOW : ACPI_ACTIVE_HIGH; | 414 | polarity = polarity ? ACPI_ACTIVE_LOW : ACPI_ACTIVE_HIGH; |
422 | 415 | ||
423 | printk(KERN_INFO "xen: sci override: global_irq=%d trigger=%d " | 416 | printk(KERN_INFO "xen: sci override: global_irq=%d trigger=%d " |
424 | "polarity=%d\n", gsi, trigger, polarity); | 417 | "polarity=%d\n", gsi, trigger, polarity); |
425 | 418 | ||
@@ -434,10 +427,9 @@ static __init void xen_setup_acpi_sci(void) | |||
434 | * the ACPI interpreter and keels over since IRQ 9 has not been | 427 | * the ACPI interpreter and keels over since IRQ 9 has not been |
435 | * setup as we had setup IRQ 20 for it). | 428 | * setup as we had setup IRQ 20 for it). |
436 | */ | 429 | */ |
437 | /* Check whether the GSI != IRQ */ | ||
438 | if (acpi_gsi_to_irq(gsi, &irq) == 0) { | 430 | if (acpi_gsi_to_irq(gsi, &irq) == 0) { |
439 | if (irq >= 0 && irq != gsi) | 431 | /* Use the provided value if it's valid. */ |
440 | /* Bugger, we MUST have that IRQ. */ | 432 | if (irq >= 0) |
441 | gsi_override = irq; | 433 | gsi_override = irq; |
442 | } | 434 | } |
443 | 435 | ||
@@ -447,41 +439,16 @@ static __init void xen_setup_acpi_sci(void) | |||
447 | return; | 439 | return; |
448 | } | 440 | } |
449 | 441 | ||
450 | static int acpi_register_gsi_xen(struct device *dev, u32 gsi, | 442 | int __init pci_xen_initial_domain(void) |
451 | int trigger, int polarity) | ||
452 | { | 443 | { |
453 | return xen_register_gsi(gsi, -1 /* no GSI override */, trigger, polarity); | 444 | int irq; |
454 | } | ||
455 | 445 | ||
456 | static int __init pci_xen_initial_domain(void) | ||
457 | { | ||
458 | #ifdef CONFIG_PCI_MSI | 446 | #ifdef CONFIG_PCI_MSI |
459 | x86_msi.setup_msi_irqs = xen_initdom_setup_msi_irqs; | 447 | x86_msi.setup_msi_irqs = xen_initdom_setup_msi_irqs; |
460 | x86_msi.teardown_msi_irq = xen_teardown_msi_irq; | 448 | x86_msi.teardown_msi_irq = xen_teardown_msi_irq; |
461 | #endif | 449 | #endif |
462 | xen_setup_acpi_sci(); | 450 | xen_setup_acpi_sci(); |
463 | __acpi_register_gsi = acpi_register_gsi_xen; | 451 | __acpi_register_gsi = acpi_register_gsi_xen; |
464 | |||
465 | return 0; | ||
466 | } | ||
467 | |||
468 | void __init xen_setup_pirqs(void) | ||
469 | { | ||
470 | int pirq, irq; | ||
471 | |||
472 | pci_xen_initial_domain(); | ||
473 | |||
474 | if (0 == nr_ioapics) { | ||
475 | for (irq = 0; irq < NR_IRQS_LEGACY; irq++) { | ||
476 | pirq = xen_allocate_pirq_gsi(irq); | ||
477 | if (WARN(pirq < 0, | ||
478 | "Could not allocate PIRQ for legacy interrupt\n")) | ||
479 | break; | ||
480 | irq = xen_bind_pirq_gsi_to_irq(irq, pirq, 0, "xt-pic"); | ||
481 | } | ||
482 | return; | ||
483 | } | ||
484 | |||
485 | /* Pre-allocate legacy irqs */ | 452 | /* Pre-allocate legacy irqs */ |
486 | for (irq = 0; irq < NR_IRQS_LEGACY; irq++) { | 453 | for (irq = 0; irq < NR_IRQS_LEGACY; irq++) { |
487 | int trigger, polarity; | 454 | int trigger, polarity; |
@@ -490,12 +457,16 @@ void __init xen_setup_pirqs(void) | |||
490 | continue; | 457 | continue; |
491 | 458 | ||
492 | xen_register_pirq(irq, -1 /* no GSI override */, | 459 | xen_register_pirq(irq, -1 /* no GSI override */, |
493 | trigger ? ACPI_LEVEL_SENSITIVE : ACPI_EDGE_SENSITIVE); | 460 | trigger ? ACPI_LEVEL_SENSITIVE : ACPI_EDGE_SENSITIVE, |
461 | true /* Map GSI to PIRQ */); | ||
494 | } | 462 | } |
463 | if (0 == nr_ioapics) { | ||
464 | for (irq = 0; irq < NR_IRQS_LEGACY; irq++) | ||
465 | xen_bind_pirq_gsi_to_irq(irq, irq, 0, "xt-pic"); | ||
466 | } | ||
467 | return 0; | ||
495 | } | 468 | } |
496 | #endif | ||
497 | 469 | ||
498 | #ifdef CONFIG_XEN_DOM0 | ||
499 | struct xen_device_domain_owner { | 470 | struct xen_device_domain_owner { |
500 | domid_t domain; | 471 | domid_t domain; |
501 | struct pci_dev *dev; | 472 | struct pci_dev *dev; |