aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/pci
diff options
context:
space:
mode:
Diffstat (limited to 'arch/x86/pci')
-rw-r--r--arch/x86/pci/Makefile3
-rw-r--r--arch/x86/pci/acpi.c50
-rw-r--r--arch/x86/pci/amd_bus.c42
-rw-r--r--arch/x86/pci/ce4100.c2
-rw-r--r--arch/x86/pci/common.c14
-rw-r--r--arch/x86/pci/direct.c6
-rw-r--r--arch/x86/pci/mmconfig-shared.c3
-rw-r--r--arch/x86/pci/numaq_32.c2
-rw-r--r--arch/x86/pci/olpc.c4
-rw-r--r--arch/x86/pci/pcbios.c2
-rw-r--r--arch/x86/pci/visws.c2
-rw-r--r--arch/x86/pci/xen.c371
12 files changed, 242 insertions, 259 deletions
diff --git a/arch/x86/pci/Makefile b/arch/x86/pci/Makefile
index 6b8759f7634..d24d3da7292 100644
--- a/arch/x86/pci/Makefile
+++ b/arch/x86/pci/Makefile
@@ -18,8 +18,9 @@ obj-$(CONFIG_X86_NUMAQ) += numaq_32.o
18obj-$(CONFIG_X86_MRST) += mrst.o 18obj-$(CONFIG_X86_MRST) += mrst.o
19 19
20obj-y += common.o early.o 20obj-y += common.o early.o
21obj-y += amd_bus.o bus_numa.o 21obj-y += bus_numa.o
22 22
23obj-$(CONFIG_AMD_NB) += amd_bus.o
23obj-$(CONFIG_PCI_CNB20LE_QUIRK) += broadcom_bus.o 24obj-$(CONFIG_PCI_CNB20LE_QUIRK) += broadcom_bus.o
24 25
25ifeq ($(CONFIG_PCI_DEBUG),y) 26ifeq ($(CONFIG_PCI_DEBUG),y)
diff --git a/arch/x86/pci/acpi.c b/arch/x86/pci/acpi.c
index 68c3c139520..f8348ab1032 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
@@ -138,7 +149,7 @@ setup_resource(struct acpi_resource *acpi_res, void *data)
138 struct acpi_resource_address64 addr; 149 struct acpi_resource_address64 addr;
139 acpi_status status; 150 acpi_status status;
140 unsigned long flags; 151 unsigned long flags;
141 u64 start, end; 152 u64 start, orig_end, end;
142 153
143 status = resource_to_addr(acpi_res, &addr); 154 status = resource_to_addr(acpi_res, &addr);
144 if (!ACPI_SUCCESS(status)) 155 if (!ACPI_SUCCESS(status))
@@ -154,7 +165,21 @@ setup_resource(struct acpi_resource *acpi_res, void *data)
154 return AE_OK; 165 return AE_OK;
155 166
156 start = addr.minimum + addr.translation_offset; 167 start = addr.minimum + addr.translation_offset;
157 end = addr.maximum + addr.translation_offset; 168 orig_end = end = addr.maximum + addr.translation_offset;
169
170 /* Exclude non-addressable range or non-addressable portion of range */
171 end = min(end, (u64)iomem_resource.end);
172 if (end <= start) {
173 dev_info(&info->bridge->dev,
174 "host bridge window [%#llx-%#llx] "
175 "(ignored, not CPU addressable)\n", start, orig_end);
176 return AE_OK;
177 } else if (orig_end != end) {
178 dev_info(&info->bridge->dev,
179 "host bridge window [%#llx-%#llx] "
180 "([%#llx-%#llx] ignored, not CPU addressable)\n",
181 start, orig_end, end + 1, orig_end);
182 }
158 183
159 res = &info->res[info->res_num]; 184 res = &info->res[info->res_num];
160 res->name = info->name; 185 res->name = info->name;
@@ -246,10 +271,9 @@ static void add_resources(struct pci_root_info *info)
246 271
247 conflict = insert_resource_conflict(root, res); 272 conflict = insert_resource_conflict(root, res);
248 if (conflict) 273 if (conflict)
249 dev_err(&info->bridge->dev, 274 dev_info(&info->bridge->dev,
250 "address space collision: host bridge window %pR " 275 "ignoring host bridge window %pR (conflicts with %s %pR)\n",
251 "conflicts with %s %pR\n", 276 res, conflict->name, conflict);
252 res, conflict->name, conflict);
253 else 277 else
254 pci_bus_add_resource(info->bus, res, 0); 278 pci_bus_add_resource(info->bus, res, 0);
255 } 279 }
@@ -361,6 +385,20 @@ struct pci_bus * __devinit pci_acpi_scan_root(struct acpi_pci_root *root)
361 } 385 }
362 } 386 }
363 387
388 /* After the PCI-E bus has been walked and all devices discovered,
389 * configure any settings of the fabric that might be necessary.
390 */
391 if (bus) {
392 struct pci_bus *child;
393 list_for_each_entry(child, &bus->children, node) {
394 struct pci_dev *self = child->self;
395 if (!self)
396 continue;
397
398 pcie_bus_configure_settings(child, self->pcie_mpss);
399 }
400 }
401
364 if (!bus) 402 if (!bus)
365 kfree(sd); 403 kfree(sd);
366 404
diff --git a/arch/x86/pci/amd_bus.c b/arch/x86/pci/amd_bus.c
index 026e4931d16..385a940b542 100644
--- a/arch/x86/pci/amd_bus.c
+++ b/arch/x86/pci/amd_bus.c
@@ -30,34 +30,6 @@ static struct pci_hostbridge_probe pci_probes[] __initdata = {
30 { 0, 0x18, PCI_VENDOR_ID_AMD, 0x1300 }, 30 { 0, 0x18, PCI_VENDOR_ID_AMD, 0x1300 },
31}; 31};
32 32
33static u64 __initdata fam10h_mmconf_start;
34static u64 __initdata fam10h_mmconf_end;
35static void __init get_pci_mmcfg_amd_fam10h_range(void)
36{
37 u32 address;
38 u64 base, msr;
39 unsigned segn_busn_bits;
40
41 /* assume all cpus from fam10h have mmconf */
42 if (boot_cpu_data.x86 < 0x10)
43 return;
44
45 address = MSR_FAM10H_MMIO_CONF_BASE;
46 rdmsrl(address, msr);
47
48 /* mmconfig is not enable */
49 if (!(msr & FAM10H_MMIO_CONF_ENABLE))
50 return;
51
52 base = msr & (FAM10H_MMIO_CONF_BASE_MASK<<FAM10H_MMIO_CONF_BASE_SHIFT);
53
54 segn_busn_bits = (msr >> FAM10H_MMIO_CONF_BUSRANGE_SHIFT) &
55 FAM10H_MMIO_CONF_BUSRANGE_MASK;
56
57 fam10h_mmconf_start = base;
58 fam10h_mmconf_end = base + (1ULL<<(segn_busn_bits + 20)) - 1;
59}
60
61#define RANGE_NUM 16 33#define RANGE_NUM 16
62 34
63/** 35/**
@@ -85,6 +57,9 @@ static int __init early_fill_mp_bus_info(void)
85 u64 val; 57 u64 val;
86 u32 address; 58 u32 address;
87 bool found; 59 bool found;
60 struct resource fam10h_mmconf_res, *fam10h_mmconf;
61 u64 fam10h_mmconf_start;
62 u64 fam10h_mmconf_end;
88 63
89 if (!early_pci_allowed()) 64 if (!early_pci_allowed())
90 return -1; 65 return -1;
@@ -211,12 +186,17 @@ static int __init early_fill_mp_bus_info(void)
211 subtract_range(range, RANGE_NUM, 0, end); 186 subtract_range(range, RANGE_NUM, 0, end);
212 187
213 /* get mmconfig */ 188 /* get mmconfig */
214 get_pci_mmcfg_amd_fam10h_range(); 189 fam10h_mmconf = amd_get_mmconfig_range(&fam10h_mmconf_res);
215 /* need to take out mmconf range */ 190 /* need to take out mmconf range */
216 if (fam10h_mmconf_end) { 191 if (fam10h_mmconf) {
217 printk(KERN_DEBUG "Fam 10h mmconf [%llx, %llx]\n", fam10h_mmconf_start, fam10h_mmconf_end); 192 printk(KERN_DEBUG "Fam 10h mmconf %pR\n", fam10h_mmconf);
193 fam10h_mmconf_start = fam10h_mmconf->start;
194 fam10h_mmconf_end = fam10h_mmconf->end;
218 subtract_range(range, RANGE_NUM, fam10h_mmconf_start, 195 subtract_range(range, RANGE_NUM, fam10h_mmconf_start,
219 fam10h_mmconf_end + 1); 196 fam10h_mmconf_end + 1);
197 } else {
198 fam10h_mmconf_start = 0;
199 fam10h_mmconf_end = 0;
220 } 200 }
221 201
222 /* mmio resource */ 202 /* mmio resource */
diff --git a/arch/x86/pci/ce4100.c b/arch/x86/pci/ce4100.c
index 67858be4b52..99176094500 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 5fe75026ecc..92df322e0b5 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 e6fd8473fb7..4f2c70439d7 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 750c346ef50..301e325992f 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 5c9e2458df4..512a88c4150 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 13700ec8e2e..5262603b04d 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,
264static int pci_olpc_write(unsigned int seg, unsigned int bus, 266static 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 a5f7d0d63de..f6855355146 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 03008f72eb0..6f2f8eeed17 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
25unsigned int pci_bus0, pci_bus1; 25unsigned int pci_bus0, pci_bus1;
26 26
27static int __init visws_map_irq(struct pci_dev *dev, u8 slot, u8 pin) 27static 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 f567965c062..1017c7bee38 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
27static 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
23static int acpi_register_gsi_xen_hvm(struct device *dev, u32 gsi, 59static 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);
97out:
98 return irq;
99}
100
101static 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
112static 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
140static 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,43 @@ static int acpi_register_gsi_xen_hvm(struct device *dev, u32 gsi,
65struct xen_pci_frontend_ops *xen_pci_frontend; 152struct xen_pci_frontend_ops *xen_pci_frontend;
66EXPORT_SYMBOL_GPL(xen_pci_frontend); 153EXPORT_SYMBOL_GPL(xen_pci_frontend);
67 154
155static 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 goto free;
180 i++;
181 }
182 kfree(v);
183 return 0;
184
185error:
186 dev_err(&dev->dev, "Xen PCI frontend has not registered MSI/MSI-X support!\n");
187free:
188 kfree(v);
189 return ret;
190}
191
68#define XEN_PIRQ_MSI_DATA (MSI_DATA_TRIGGER_EDGE | \ 192#define XEN_PIRQ_MSI_DATA (MSI_DATA_TRIGGER_EDGE | \
69 MSI_DATA_LEVEL_ASSERT | (3 << 8) | MSI_DATA_VECTOR(0)) 193 MSI_DATA_LEVEL_ASSERT | (3 << 8) | MSI_DATA_VECTOR(0))
70 194
@@ -123,67 +247,6 @@ error:
123 return -ENODEV; 247 return -ENODEV;
124} 248}
125 249
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
131static 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
161error:
162 dev_err(&dev->dev, "Xen PCI frontend has not registered MSI/MSI-X support!\n");
163free:
164 kfree(v);
165 return ret;
166}
167
168static 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
182static void xen_teardown_msi_irq(unsigned int irq)
183{
184 xen_destroy_irq(irq);
185}
186
187#ifdef CONFIG_XEN_DOM0 250#ifdef CONFIG_XEN_DOM0
188static int xen_initdom_setup_msi_irqs(struct pci_dev *dev, int nvec, int type) 251static int xen_initdom_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)
189{ 252{
@@ -242,45 +305,28 @@ out:
242 return ret; 305 return ret;
243} 306}
244#endif 307#endif
245#endif
246 308
247static int xen_pcifront_enable_irq(struct pci_dev *dev) 309static void xen_teardown_msi_irqs(struct pci_dev *dev)
248{ 310{
249 int rc; 311 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 312
269 if (gsi < NR_IRQS_LEGACY) 313 msidesc = list_entry(dev->msi_list.next, struct msi_desc, list);
270 share = 0; 314 if (msidesc->msi_attrib.is_msix)
315 xen_pci_frontend_disable_msix(dev);
316 else
317 xen_pci_frontend_disable_msi(dev);
271 318
272 rc = xen_bind_pirq_gsi_to_irq(gsi, pirq, share, "pcifront"); 319 /* Free the IRQ's and the msidesc using the generic code. */
273 if (rc < 0) { 320 default_teardown_msi_irqs(dev);
274 dev_warn(&dev->dev, "Xen PCI: failed to bind GSI%d (PIRQ%d) to IRQ: %d\n", 321}
275 gsi, pirq, rc);
276 return rc;
277 }
278 322
279 dev->irq = rc; 323static 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); 324{
281 return 0; 325 xen_destroy_irq(irq);
282} 326}
283 327
328#endif
329
284int __init pci_xen_init(void) 330int __init pci_xen_init(void)
285{ 331{
286 if (!xen_pv_domain() || xen_initial_domain()) 332 if (!xen_pv_domain() || xen_initial_domain())
@@ -327,79 +373,6 @@ int __init pci_xen_hvm_init(void)
327} 373}
328 374
329#ifdef CONFIG_XEN_DOM0 375#ifdef CONFIG_XEN_DOM0
330static 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
371out:
372 return irq;
373}
374
375static 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
403static __init void xen_setup_acpi_sci(void) 376static __init void xen_setup_acpi_sci(void)
404{ 377{
405 int rc; 378 int rc;
@@ -419,7 +392,7 @@ static __init void xen_setup_acpi_sci(void)
419 } 392 }
420 trigger = trigger ? ACPI_LEVEL_SENSITIVE : ACPI_EDGE_SENSITIVE; 393 trigger = trigger ? ACPI_LEVEL_SENSITIVE : ACPI_EDGE_SENSITIVE;
421 polarity = polarity ? ACPI_ACTIVE_LOW : ACPI_ACTIVE_HIGH; 394 polarity = polarity ? ACPI_ACTIVE_LOW : ACPI_ACTIVE_HIGH;
422 395
423 printk(KERN_INFO "xen: sci override: global_irq=%d trigger=%d " 396 printk(KERN_INFO "xen: sci override: global_irq=%d trigger=%d "
424 "polarity=%d\n", gsi, trigger, polarity); 397 "polarity=%d\n", gsi, trigger, polarity);
425 398
@@ -434,10 +407,9 @@ static __init void xen_setup_acpi_sci(void)
434 * the ACPI interpreter and keels over since IRQ 9 has not been 407 * the ACPI interpreter and keels over since IRQ 9 has not been
435 * setup as we had setup IRQ 20 for it). 408 * setup as we had setup IRQ 20 for it).
436 */ 409 */
437 /* Check whether the GSI != IRQ */
438 if (acpi_gsi_to_irq(gsi, &irq) == 0) { 410 if (acpi_gsi_to_irq(gsi, &irq) == 0) {
439 if (irq >= 0 && irq != gsi) 411 /* Use the provided value if it's valid. */
440 /* Bugger, we MUST have that IRQ. */ 412 if (irq >= 0)
441 gsi_override = irq; 413 gsi_override = irq;
442 } 414 }
443 415
@@ -447,41 +419,16 @@ static __init void xen_setup_acpi_sci(void)
447 return; 419 return;
448} 420}
449 421
450static int acpi_register_gsi_xen(struct device *dev, u32 gsi, 422int __init pci_xen_initial_domain(void)
451 int trigger, int polarity)
452{ 423{
453 return xen_register_gsi(gsi, -1 /* no GSI override */, trigger, polarity); 424 int irq;
454}
455 425
456static int __init pci_xen_initial_domain(void)
457{
458#ifdef CONFIG_PCI_MSI 426#ifdef CONFIG_PCI_MSI
459 x86_msi.setup_msi_irqs = xen_initdom_setup_msi_irqs; 427 x86_msi.setup_msi_irqs = xen_initdom_setup_msi_irqs;
460 x86_msi.teardown_msi_irq = xen_teardown_msi_irq; 428 x86_msi.teardown_msi_irq = xen_teardown_msi_irq;
461#endif 429#endif
462 xen_setup_acpi_sci(); 430 xen_setup_acpi_sci();
463 __acpi_register_gsi = acpi_register_gsi_xen; 431 __acpi_register_gsi = acpi_register_gsi_xen;
464
465 return 0;
466}
467
468void __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 */ 432 /* Pre-allocate legacy irqs */
486 for (irq = 0; irq < NR_IRQS_LEGACY; irq++) { 433 for (irq = 0; irq < NR_IRQS_LEGACY; irq++) {
487 int trigger, polarity; 434 int trigger, polarity;
@@ -490,12 +437,16 @@ void __init xen_setup_pirqs(void)
490 continue; 437 continue;
491 438
492 xen_register_pirq(irq, -1 /* no GSI override */, 439 xen_register_pirq(irq, -1 /* no GSI override */,
493 trigger ? ACPI_LEVEL_SENSITIVE : ACPI_EDGE_SENSITIVE); 440 trigger ? ACPI_LEVEL_SENSITIVE : ACPI_EDGE_SENSITIVE,
441 true /* Map GSI to PIRQ */);
494 } 442 }
443 if (0 == nr_ioapics) {
444 for (irq = 0; irq < NR_IRQS_LEGACY; irq++)
445 xen_bind_pirq_gsi_to_irq(irq, irq, 0, "xt-pic");
446 }
447 return 0;
495} 448}
496#endif
497 449
498#ifdef CONFIG_XEN_DOM0
499struct xen_device_domain_owner { 450struct xen_device_domain_owner {
500 domid_t domain; 451 domid_t domain;
501 struct pci_dev *dev; 452 struct pci_dev *dev;