diff options
author | Yinghai Lu <yinghai@kernel.org> | 2009-10-05 00:54:24 -0400 |
---|---|---|
committer | Jesse Barnes <jbarnes@virtuousgeek.org> | 2009-11-04 11:47:09 -0500 |
commit | 99935a7a59eaca0292c1a5880e10bae03f4a5e3d (patch) | |
tree | 44d7265182ad7e1ee795a420088bc99d0096b62c /arch/x86 | |
parent | 91d3f9bacdb4950d2f79fe2ba296aa249f60d06c (diff) |
x86/PCI: read root resources from IOH on Intel
For intel systems with multi IOH, we should read peer root resources
directly from PCI config space, and don't trust _CRS.
Signed-off-by: Yinghai Lu <yinghai.lu@sun.com>
Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Diffstat (limited to 'arch/x86')
-rw-r--r-- | arch/x86/pci/Makefile | 1 | ||||
-rw-r--r-- | arch/x86/pci/amd_bus.c | 45 | ||||
-rw-r--r-- | arch/x86/pci/bus_numa.h | 26 | ||||
-rw-r--r-- | arch/x86/pci/intel_bus.c | 90 |
4 files changed, 135 insertions, 27 deletions
diff --git a/arch/x86/pci/Makefile b/arch/x86/pci/Makefile index d49202e740ea..56d917b556c6 100644 --- a/arch/x86/pci/Makefile +++ b/arch/x86/pci/Makefile | |||
@@ -15,3 +15,4 @@ obj-$(CONFIG_X86_NUMAQ) += numaq_32.o | |||
15 | 15 | ||
16 | obj-y += common.o early.o | 16 | obj-y += common.o early.o |
17 | obj-y += amd_bus.o | 17 | obj-y += amd_bus.o |
18 | obj-$(CONFIG_X86_64) += intel_bus.o | ||
diff --git a/arch/x86/pci/amd_bus.c b/arch/x86/pci/amd_bus.c index 572ee9782f2a..995f36096a42 100644 --- a/arch/x86/pci/amd_bus.c +++ b/arch/x86/pci/amd_bus.c | |||
@@ -10,6 +10,8 @@ | |||
10 | #include <linux/cpumask.h> | 10 | #include <linux/cpumask.h> |
11 | #endif | 11 | #endif |
12 | 12 | ||
13 | #include "bus_numa.h" | ||
14 | |||
13 | /* | 15 | /* |
14 | * This discovers the pcibus <-> node mapping on AMD K8. | 16 | * This discovers the pcibus <-> node mapping on AMD K8. |
15 | * also get peer root bus resource for io,mmio | 17 | * also get peer root bus resource for io,mmio |
@@ -17,25 +19,9 @@ | |||
17 | 19 | ||
18 | #ifdef CONFIG_X86_64 | 20 | #ifdef CONFIG_X86_64 |
19 | 21 | ||
20 | /* | 22 | int pci_root_num; |
21 | * sub bus (transparent) will use entres from 3 to store extra from root, | 23 | struct pci_root_info pci_root_info[PCI_ROOT_NR]; |
22 | * so need to make sure have enought slot there, increase PCI_BUS_NUM_RESOURCES? | 24 | static int found_all_numa_early; |
23 | */ | ||
24 | #define RES_NUM 16 | ||
25 | struct pci_root_info { | ||
26 | char name[12]; | ||
27 | unsigned int res_num; | ||
28 | struct resource res[RES_NUM]; | ||
29 | int bus_min; | ||
30 | int bus_max; | ||
31 | int node; | ||
32 | int link; | ||
33 | }; | ||
34 | |||
35 | /* 4 at this time, it may become to 32 */ | ||
36 | #define PCI_ROOT_NR 4 | ||
37 | static int pci_root_num; | ||
38 | static struct pci_root_info pci_root_info[PCI_ROOT_NR]; | ||
39 | 25 | ||
40 | void x86_pci_root_bus_res_quirks(struct pci_bus *b) | 26 | void x86_pci_root_bus_res_quirks(struct pci_bus *b) |
41 | { | 27 | { |
@@ -48,8 +34,11 @@ void x86_pci_root_bus_res_quirks(struct pci_bus *b) | |||
48 | b->resource[1] != &iomem_resource) | 34 | b->resource[1] != &iomem_resource) |
49 | return; | 35 | return; |
50 | 36 | ||
51 | /* if only one root bus, don't need to anything */ | 37 | if (!pci_root_num) |
52 | if (pci_root_num < 2) | 38 | return; |
39 | |||
40 | /* for amd, if only one root bus, don't need to do anything */ | ||
41 | if (pci_root_num < 2 && found_all_numa_early) | ||
53 | return; | 42 | return; |
54 | 43 | ||
55 | for (i = 0; i < pci_root_num; i++) { | 44 | for (i = 0; i < pci_root_num; i++) { |
@@ -130,12 +119,15 @@ static void __init update_range(struct res_range *range, size_t start, | |||
130 | } | 119 | } |
131 | } | 120 | } |
132 | 121 | ||
133 | static void __init update_res(struct pci_root_info *info, size_t start, | 122 | void __init update_res(struct pci_root_info *info, size_t start, |
134 | size_t end, unsigned long flags, int merge) | 123 | size_t end, unsigned long flags, int merge) |
135 | { | 124 | { |
136 | int i; | 125 | int i; |
137 | struct resource *res; | 126 | struct resource *res; |
138 | 127 | ||
128 | if (start > end) | ||
129 | return; | ||
130 | |||
139 | if (!merge) | 131 | if (!merge) |
140 | goto addit; | 132 | goto addit; |
141 | 133 | ||
@@ -230,7 +222,6 @@ static int __init early_fill_mp_bus_info(void) | |||
230 | int j; | 222 | int j; |
231 | unsigned bus; | 223 | unsigned bus; |
232 | unsigned slot; | 224 | unsigned slot; |
233 | int found; | ||
234 | int node; | 225 | int node; |
235 | int link; | 226 | int link; |
236 | int def_node; | 227 | int def_node; |
@@ -247,7 +238,7 @@ static int __init early_fill_mp_bus_info(void) | |||
247 | if (!early_pci_allowed()) | 238 | if (!early_pci_allowed()) |
248 | return -1; | 239 | return -1; |
249 | 240 | ||
250 | found = 0; | 241 | found_all_numa_early = 0; |
251 | for (i = 0; i < ARRAY_SIZE(pci_probes); i++) { | 242 | for (i = 0; i < ARRAY_SIZE(pci_probes); i++) { |
252 | u32 id; | 243 | u32 id; |
253 | u16 device; | 244 | u16 device; |
@@ -261,12 +252,12 @@ static int __init early_fill_mp_bus_info(void) | |||
261 | device = (id>>16) & 0xffff; | 252 | device = (id>>16) & 0xffff; |
262 | if (pci_probes[i].vendor == vendor && | 253 | if (pci_probes[i].vendor == vendor && |
263 | pci_probes[i].device == device) { | 254 | pci_probes[i].device == device) { |
264 | found = 1; | 255 | found_all_numa_early = 1; |
265 | break; | 256 | break; |
266 | } | 257 | } |
267 | } | 258 | } |
268 | 259 | ||
269 | if (!found) | 260 | if (!found_all_numa_early) |
270 | return 0; | 261 | return 0; |
271 | 262 | ||
272 | pci_root_num = 0; | 263 | pci_root_num = 0; |
@@ -488,7 +479,7 @@ static int __init early_fill_mp_bus_info(void) | |||
488 | info = &pci_root_info[i]; | 479 | info = &pci_root_info[i]; |
489 | res_num = info->res_num; | 480 | res_num = info->res_num; |
490 | busnum = info->bus_min; | 481 | busnum = info->bus_min; |
491 | printk(KERN_DEBUG "bus: [%02x,%02x] on node %x link %x\n", | 482 | printk(KERN_DEBUG "bus: [%02x, %02x] on node %x link %x\n", |
492 | info->bus_min, info->bus_max, info->node, info->link); | 483 | info->bus_min, info->bus_max, info->node, info->link); |
493 | for (j = 0; j < res_num; j++) { | 484 | for (j = 0; j < res_num; j++) { |
494 | res = &info->res[j]; | 485 | res = &info->res[j]; |
diff --git a/arch/x86/pci/bus_numa.h b/arch/x86/pci/bus_numa.h new file mode 100644 index 000000000000..4ff126a3e887 --- /dev/null +++ b/arch/x86/pci/bus_numa.h | |||
@@ -0,0 +1,26 @@ | |||
1 | #ifdef CONFIG_X86_64 | ||
2 | |||
3 | /* | ||
4 | * sub bus (transparent) will use entres from 3 to store extra from | ||
5 | * root, so need to make sure we have enought slot there, Should we | ||
6 | * increase PCI_BUS_NUM_RESOURCES? | ||
7 | */ | ||
8 | #define RES_NUM 16 | ||
9 | struct pci_root_info { | ||
10 | char name[12]; | ||
11 | unsigned int res_num; | ||
12 | struct resource res[RES_NUM]; | ||
13 | int bus_min; | ||
14 | int bus_max; | ||
15 | int node; | ||
16 | int link; | ||
17 | }; | ||
18 | |||
19 | /* 4 at this time, it may become to 32 */ | ||
20 | #define PCI_ROOT_NR 4 | ||
21 | extern int pci_root_num; | ||
22 | extern struct pci_root_info pci_root_info[PCI_ROOT_NR]; | ||
23 | |||
24 | extern void update_res(struct pci_root_info *info, size_t start, | ||
25 | size_t end, unsigned long flags, int merge); | ||
26 | #endif | ||
diff --git a/arch/x86/pci/intel_bus.c b/arch/x86/pci/intel_bus.c new file mode 100644 index 000000000000..b7a55dc55d13 --- /dev/null +++ b/arch/x86/pci/intel_bus.c | |||
@@ -0,0 +1,90 @@ | |||
1 | /* | ||
2 | * to read io range from IOH pci conf, need to do it after mmconfig is there | ||
3 | */ | ||
4 | |||
5 | #include <linux/delay.h> | ||
6 | #include <linux/dmi.h> | ||
7 | #include <linux/pci.h> | ||
8 | #include <linux/init.h> | ||
9 | #include <asm/pci_x86.h> | ||
10 | |||
11 | #include "bus_numa.h" | ||
12 | |||
13 | static inline void print_ioh_resources(struct pci_root_info *info) | ||
14 | { | ||
15 | int res_num; | ||
16 | int busnum; | ||
17 | int i; | ||
18 | |||
19 | printk(KERN_DEBUG "IOH bus: [%02x, %02x]\n", | ||
20 | info->bus_min, info->bus_max); | ||
21 | res_num = info->res_num; | ||
22 | busnum = info->bus_min; | ||
23 | for (i = 0; i < res_num; i++) { | ||
24 | struct resource *res; | ||
25 | |||
26 | res = &info->res[i]; | ||
27 | printk(KERN_DEBUG "IOH bus: %02x index %x %s: [%llx, %llx]\n", | ||
28 | busnum, i, | ||
29 | (res->flags & IORESOURCE_IO) ? "io port" : | ||
30 | "mmio", | ||
31 | res->start, res->end); | ||
32 | } | ||
33 | } | ||
34 | |||
35 | #define IOH_LIO 0x108 | ||
36 | #define IOH_LMMIOL 0x10c | ||
37 | #define IOH_LMMIOH 0x110 | ||
38 | #define IOH_LMMIOH_BASEU 0x114 | ||
39 | #define IOH_LMMIOH_LIMITU 0x118 | ||
40 | #define IOH_LCFGBUS 0x11c | ||
41 | |||
42 | static void __devinit pci_root_bus_res(struct pci_dev *dev) | ||
43 | { | ||
44 | u16 word; | ||
45 | u32 dword; | ||
46 | struct pci_root_info *info; | ||
47 | u16 io_base, io_end; | ||
48 | u32 mmiol_base, mmiol_end; | ||
49 | u64 mmioh_base, mmioh_end; | ||
50 | int bus_base, bus_end; | ||
51 | |||
52 | if (pci_root_num >= PCI_ROOT_NR) { | ||
53 | printk(KERN_DEBUG "intel_bus.c: PCI_ROOT_NR is too small\n"); | ||
54 | return; | ||
55 | } | ||
56 | |||
57 | info = &pci_root_info[pci_root_num]; | ||
58 | pci_root_num++; | ||
59 | |||
60 | pci_read_config_word(dev, IOH_LCFGBUS, &word); | ||
61 | bus_base = (word & 0xff); | ||
62 | bus_end = (word & 0xff00) >> 8; | ||
63 | sprintf(info->name, "PCI Bus #%02x", bus_base); | ||
64 | info->bus_min = bus_base; | ||
65 | info->bus_max = bus_end; | ||
66 | |||
67 | pci_read_config_word(dev, IOH_LIO, &word); | ||
68 | io_base = (word & 0xf0) << (12 - 4); | ||
69 | io_end = (word & 0xf000) | 0xfff; | ||
70 | update_res(info, io_base, io_end, IORESOURCE_IO, 0); | ||
71 | |||
72 | pci_read_config_dword(dev, IOH_LMMIOL, &dword); | ||
73 | mmiol_base = (dword & 0xff00) << (24 - 8); | ||
74 | mmiol_end = (dword & 0xff000000) | 0xffffff; | ||
75 | update_res(info, mmiol_base, mmiol_end, IORESOURCE_MEM, 0); | ||
76 | |||
77 | pci_read_config_dword(dev, IOH_LMMIOH, &dword); | ||
78 | mmioh_base = ((u64)(dword & 0xfc00)) << (26 - 10); | ||
79 | mmioh_end = ((u64)(dword & 0xfc000000) | 0x3ffffff); | ||
80 | pci_read_config_dword(dev, IOH_LMMIOH_BASEU, &dword); | ||
81 | mmioh_base |= ((u64)(dword & 0x7ffff)) << 32; | ||
82 | pci_read_config_dword(dev, IOH_LMMIOH_LIMITU, &dword); | ||
83 | mmioh_end |= ((u64)(dword & 0x7ffff)) << 32; | ||
84 | update_res(info, mmioh_base, mmioh_end, IORESOURCE_MEM, 0); | ||
85 | |||
86 | print_ioh_resources(info); | ||
87 | } | ||
88 | |||
89 | /* intel IOH */ | ||
90 | DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, 0x342e, pci_root_bus_res); | ||