aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/pci
diff options
context:
space:
mode:
Diffstat (limited to 'arch/x86/pci')
-rw-r--r--arch/x86/pci/Makefile1
-rw-r--r--arch/x86/pci/acpi.c46
-rw-r--r--arch/x86/pci/common.c32
-rw-r--r--arch/x86/pci/numachip.c129
4 files changed, 202 insertions, 6 deletions
diff --git a/arch/x86/pci/Makefile b/arch/x86/pci/Makefile
index 3af5a1e79c9c..ee0af58ca5bd 100644
--- a/arch/x86/pci/Makefile
+++ b/arch/x86/pci/Makefile
@@ -16,6 +16,7 @@ obj-$(CONFIG_STA2X11) += sta2x11-fixup.o
16obj-$(CONFIG_X86_VISWS) += visws.o 16obj-$(CONFIG_X86_VISWS) += visws.o
17 17
18obj-$(CONFIG_X86_NUMAQ) += numaq_32.o 18obj-$(CONFIG_X86_NUMAQ) += numaq_32.o
19obj-$(CONFIG_X86_NUMACHIP) += numachip.o
19 20
20obj-$(CONFIG_X86_INTEL_MID) += mrst.o 21obj-$(CONFIG_X86_INTEL_MID) += mrst.o
21 22
diff --git a/arch/x86/pci/acpi.c b/arch/x86/pci/acpi.c
index 192397c98606..0c01261fe5a8 100644
--- a/arch/x86/pci/acpi.c
+++ b/arch/x86/pci/acpi.c
@@ -12,6 +12,7 @@ struct pci_root_info {
12 char name[16]; 12 char name[16];
13 unsigned int res_num; 13 unsigned int res_num;
14 struct resource *res; 14 struct resource *res;
15 resource_size_t *res_offset;
15 struct pci_sysdata sd; 16 struct pci_sysdata sd;
16#ifdef CONFIG_PCI_MMCONFIG 17#ifdef CONFIG_PCI_MMCONFIG
17 bool mcfg_added; 18 bool mcfg_added;
@@ -22,6 +23,7 @@ struct pci_root_info {
22}; 23};
23 24
24static bool pci_use_crs = true; 25static bool pci_use_crs = true;
26static bool pci_ignore_seg = false;
25 27
26static int __init set_use_crs(const struct dmi_system_id *id) 28static int __init set_use_crs(const struct dmi_system_id *id)
27{ 29{
@@ -35,7 +37,14 @@ static int __init set_nouse_crs(const struct dmi_system_id *id)
35 return 0; 37 return 0;
36} 38}
37 39
38static const struct dmi_system_id pci_use_crs_table[] __initconst = { 40static int __init set_ignore_seg(const struct dmi_system_id *id)
41{
42 printk(KERN_INFO "PCI: %s detected: ignoring ACPI _SEG\n", id->ident);
43 pci_ignore_seg = true;
44 return 0;
45}
46
47static const struct dmi_system_id pci_crs_quirks[] __initconst = {
39 /* http://bugzilla.kernel.org/show_bug.cgi?id=14183 */ 48 /* http://bugzilla.kernel.org/show_bug.cgi?id=14183 */
40 { 49 {
41 .callback = set_use_crs, 50 .callback = set_use_crs,
@@ -98,6 +107,16 @@ static const struct dmi_system_id pci_use_crs_table[] __initconst = {
98 DMI_MATCH(DMI_BIOS_VERSION, "6JET85WW (1.43 )"), 107 DMI_MATCH(DMI_BIOS_VERSION, "6JET85WW (1.43 )"),
99 }, 108 },
100 }, 109 },
110
111 /* https://bugzilla.kernel.org/show_bug.cgi?id=15362 */
112 {
113 .callback = set_ignore_seg,
114 .ident = "HP xw9300",
115 .matches = {
116 DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
117 DMI_MATCH(DMI_PRODUCT_NAME, "HP xw9300 Workstation"),
118 },
119 },
101 {} 120 {}
102}; 121};
103 122
@@ -108,7 +127,7 @@ void __init pci_acpi_crs_quirks(void)
108 if (dmi_get_date(DMI_BIOS_DATE, &year, NULL, NULL) && year < 2008) 127 if (dmi_get_date(DMI_BIOS_DATE, &year, NULL, NULL) && year < 2008)
109 pci_use_crs = false; 128 pci_use_crs = false;
110 129
111 dmi_check_system(pci_use_crs_table); 130 dmi_check_system(pci_crs_quirks);
112 131
113 /* 132 /*
114 * If the user specifies "pci=use_crs" or "pci=nocrs" explicitly, that 133 * If the user specifies "pci=use_crs" or "pci=nocrs" explicitly, that
@@ -305,6 +324,7 @@ setup_resource(struct acpi_resource *acpi_res, void *data)
305 res->flags = flags; 324 res->flags = flags;
306 res->start = start; 325 res->start = start;
307 res->end = end; 326 res->end = end;
327 info->res_offset[info->res_num] = addr.translation_offset;
308 328
309 if (!pci_use_crs) { 329 if (!pci_use_crs) {
310 dev_printk(KERN_DEBUG, &info->bridge->dev, 330 dev_printk(KERN_DEBUG, &info->bridge->dev,
@@ -374,7 +394,8 @@ static void add_resources(struct pci_root_info *info,
374 "ignoring host bridge window %pR (conflicts with %s %pR)\n", 394 "ignoring host bridge window %pR (conflicts with %s %pR)\n",
375 res, conflict->name, conflict); 395 res, conflict->name, conflict);
376 else 396 else
377 pci_add_resource(resources, res); 397 pci_add_resource_offset(resources, res,
398 info->res_offset[i]);
378 } 399 }
379} 400}
380 401
@@ -382,6 +403,8 @@ static void free_pci_root_info_res(struct pci_root_info *info)
382{ 403{
383 kfree(info->res); 404 kfree(info->res);
384 info->res = NULL; 405 info->res = NULL;
406 kfree(info->res_offset);
407 info->res_offset = NULL;
385 info->res_num = 0; 408 info->res_num = 0;
386} 409}
387 410
@@ -432,10 +455,20 @@ probe_pci_root_info(struct pci_root_info *info, struct acpi_device *device,
432 return; 455 return;
433 456
434 size = sizeof(*info->res) * info->res_num; 457 size = sizeof(*info->res) * info->res_num;
435 info->res_num = 0;
436 info->res = kzalloc(size, GFP_KERNEL); 458 info->res = kzalloc(size, GFP_KERNEL);
437 if (!info->res) 459 if (!info->res) {
460 info->res_num = 0;
461 return;
462 }
463
464 size = sizeof(*info->res_offset) * info->res_num;
465 info->res_num = 0;
466 info->res_offset = kzalloc(size, GFP_KERNEL);
467 if (!info->res_offset) {
468 kfree(info->res);
469 info->res = NULL;
438 return; 470 return;
471 }
439 472
440 acpi_walk_resources(device->handle, METHOD_NAME__CRS, setup_resource, 473 acpi_walk_resources(device->handle, METHOD_NAME__CRS, setup_resource,
441 info); 474 info);
@@ -455,6 +488,9 @@ struct pci_bus * __devinit pci_acpi_scan_root(struct acpi_pci_root *root)
455 int pxm; 488 int pxm;
456#endif 489#endif
457 490
491 if (pci_ignore_seg)
492 domain = 0;
493
458 if (domain && !pci_domains_supported) { 494 if (domain && !pci_domains_supported) {
459 printk(KERN_WARNING "pci_bus %04x:%02x: " 495 printk(KERN_WARNING "pci_bus %04x:%02x: "
460 "ignored (multiple domains not supported)\n", 496 "ignored (multiple domains not supported)\n",
diff --git a/arch/x86/pci/common.c b/arch/x86/pci/common.c
index 720e973fc34a..1b1dda90a945 100644
--- a/arch/x86/pci/common.c
+++ b/arch/x86/pci/common.c
@@ -17,6 +17,7 @@
17#include <asm/io.h> 17#include <asm/io.h>
18#include <asm/smp.h> 18#include <asm/smp.h>
19#include <asm/pci_x86.h> 19#include <asm/pci_x86.h>
20#include <asm/setup.h>
20 21
21unsigned int pci_probe = PCI_PROBE_BIOS | PCI_PROBE_CONF1 | PCI_PROBE_CONF2 | 22unsigned int pci_probe = PCI_PROBE_BIOS | PCI_PROBE_CONF1 | PCI_PROBE_CONF2 |
22 PCI_PROBE_MMCONF; 23 PCI_PROBE_MMCONF;
@@ -608,6 +609,35 @@ unsigned int pcibios_assign_all_busses(void)
608 return (pci_probe & PCI_ASSIGN_ALL_BUSSES) ? 1 : 0; 609 return (pci_probe & PCI_ASSIGN_ALL_BUSSES) ? 1 : 0;
609} 610}
610 611
612int pcibios_add_device(struct pci_dev *dev)
613{
614 struct setup_data *data;
615 struct pci_setup_rom *rom;
616 u64 pa_data;
617
618 pa_data = boot_params.hdr.setup_data;
619 while (pa_data) {
620 data = phys_to_virt(pa_data);
621
622 if (data->type == SETUP_PCI) {
623 rom = (struct pci_setup_rom *)data;
624
625 if ((pci_domain_nr(dev->bus) == rom->segment) &&
626 (dev->bus->number == rom->bus) &&
627 (PCI_SLOT(dev->devfn) == rom->device) &&
628 (PCI_FUNC(dev->devfn) == rom->function) &&
629 (dev->vendor == rom->vendor) &&
630 (dev->device == rom->devid)) {
631 dev->rom = pa_data +
632 offsetof(struct pci_setup_rom, romdata);
633 dev->romlen = rom->pcilen;
634 }
635 }
636 pa_data = data->next;
637 }
638 return 0;
639}
640
611int pcibios_enable_device(struct pci_dev *dev, int mask) 641int pcibios_enable_device(struct pci_dev *dev, int mask)
612{ 642{
613 int err; 643 int err;
@@ -626,7 +656,7 @@ void pcibios_disable_device (struct pci_dev *dev)
626 pcibios_disable_irq(dev); 656 pcibios_disable_irq(dev);
627} 657}
628 658
629int pci_ext_cfg_avail(struct pci_dev *dev) 659int pci_ext_cfg_avail(void)
630{ 660{
631 if (raw_pci_ext_ops) 661 if (raw_pci_ext_ops)
632 return 1; 662 return 1;
diff --git a/arch/x86/pci/numachip.c b/arch/x86/pci/numachip.c
new file mode 100644
index 000000000000..7307d9d12d15
--- /dev/null
+++ b/arch/x86/pci/numachip.c
@@ -0,0 +1,129 @@
1/*
2 * This file is subject to the terms and conditions of the GNU General Public
3 * License. See the file "COPYING" in the main directory of this archive
4 * for more details.
5 *
6 * Numascale NumaConnect-specific PCI code
7 *
8 * Copyright (C) 2012 Numascale AS. All rights reserved.
9 *
10 * Send feedback to <support@numascale.com>
11 *
12 * PCI accessor functions derived from mmconfig_64.c
13 *
14 */
15
16#include <linux/pci.h>
17#include <asm/pci_x86.h>
18
19static u8 limit __read_mostly;
20
21static inline char __iomem *pci_dev_base(unsigned int seg, unsigned int bus, unsigned int devfn)
22{
23 struct pci_mmcfg_region *cfg = pci_mmconfig_lookup(seg, bus);
24
25 if (cfg && cfg->virt)
26 return cfg->virt + (PCI_MMCFG_BUS_OFFSET(bus) | (devfn << 12));
27 return NULL;
28}
29
30static int pci_mmcfg_read_numachip(unsigned int seg, unsigned int bus,
31 unsigned int devfn, int reg, int len, u32 *value)
32{
33 char __iomem *addr;
34
35 /* Why do we have this when nobody checks it. How about a BUG()!? -AK */
36 if (unlikely((bus > 255) || (devfn > 255) || (reg > 4095))) {
37err: *value = -1;
38 return -EINVAL;
39 }
40
41 /* Ensure AMD Northbridges don't decode reads to other devices */
42 if (unlikely(bus == 0 && devfn >= limit)) {
43 *value = -1;
44 return 0;
45 }
46
47 rcu_read_lock();
48 addr = pci_dev_base(seg, bus, devfn);
49 if (!addr) {
50 rcu_read_unlock();
51 goto err;
52 }
53
54 switch (len) {
55 case 1:
56 *value = mmio_config_readb(addr + reg);
57 break;
58 case 2:
59 *value = mmio_config_readw(addr + reg);
60 break;
61 case 4:
62 *value = mmio_config_readl(addr + reg);
63 break;
64 }
65 rcu_read_unlock();
66
67 return 0;
68}
69
70static int pci_mmcfg_write_numachip(unsigned int seg, unsigned int bus,
71 unsigned int devfn, int reg, int len, u32 value)
72{
73 char __iomem *addr;
74
75 /* Why do we have this when nobody checks it. How about a BUG()!? -AK */
76 if (unlikely((bus > 255) || (devfn > 255) || (reg > 4095)))
77 return -EINVAL;
78
79 /* Ensure AMD Northbridges don't decode writes to other devices */
80 if (unlikely(bus == 0 && devfn >= limit))
81 return 0;
82
83 rcu_read_lock();
84 addr = pci_dev_base(seg, bus, devfn);
85 if (!addr) {
86 rcu_read_unlock();
87 return -EINVAL;
88 }
89
90 switch (len) {
91 case 1:
92 mmio_config_writeb(addr + reg, value);
93 break;
94 case 2:
95 mmio_config_writew(addr + reg, value);
96 break;
97 case 4:
98 mmio_config_writel(addr + reg, value);
99 break;
100 }
101 rcu_read_unlock();
102
103 return 0;
104}
105
106const struct pci_raw_ops pci_mmcfg_numachip = {
107 .read = pci_mmcfg_read_numachip,
108 .write = pci_mmcfg_write_numachip,
109};
110
111int __init pci_numachip_init(void)
112{
113 int ret = 0;
114 u32 val;
115
116 /* For remote I/O, restrict bus 0 access to the actual number of AMD
117 Northbridges, which starts at device number 0x18 */
118 ret = raw_pci_read(0, 0, PCI_DEVFN(0x18, 0), 0x60, sizeof(val), &val);
119 if (ret)
120 goto out;
121
122 /* HyperTransport fabric size in bits 6:4 */
123 limit = PCI_DEVFN(0x18 + ((val >> 4) & 7) + 1, 0);
124
125 /* Use NumaChip PCI accessors for non-extended and extended access */
126 raw_pci_ops = raw_pci_ext_ops = &pci_mmcfg_numachip;
127out:
128 return ret;
129}