diff options
author | Olivier Galibert <galibert@pobox.com> | 2007-02-13 07:26:20 -0500 |
---|---|---|
committer | Andi Kleen <andi@basil.nowhere.org> | 2007-02-13 07:26:20 -0500 |
commit | b78673944b22b662b270c8bba5c198f19e4ee4e1 (patch) | |
tree | 3cbbe3808335fc297fb3daf01dcbf26d4243a2db | |
parent | 2e188938ab2358034801938c2329b016ca135823 (diff) |
[PATCH] mmconfig: Share parts of mmconfig code between i386 and x86-64
i386 and x86-64 pci mmconfig code have a lot in common. So share what's
shareable between the two.
Signed-off-by: Olivier Galibert <galibert@pobox.com>
Signed-off-by: Andi Kleen <ak@suse.de>
Cc: Andi Kleen <ak@suse.de>
Signed-off-by: Andrew Morton <akpm@osdl.org>
-rw-r--r-- | arch/i386/pci/Makefile | 2 | ||||
-rw-r--r-- | arch/i386/pci/mmconfig-shared.c | 86 | ||||
-rw-r--r-- | arch/i386/pci/mmconfig.c | 74 | ||||
-rw-r--r-- | arch/i386/pci/pci.h | 6 | ||||
-rw-r--r-- | arch/x86_64/pci/Makefile | 3 | ||||
-rw-r--r-- | arch/x86_64/pci/mmconfig.c | 76 |
6 files changed, 111 insertions, 136 deletions
diff --git a/arch/i386/pci/Makefile b/arch/i386/pci/Makefile index 1594d2f55c8f..44650e03308b 100644 --- a/arch/i386/pci/Makefile +++ b/arch/i386/pci/Makefile | |||
@@ -1,7 +1,7 @@ | |||
1 | obj-y := i386.o init.o | 1 | obj-y := i386.o init.o |
2 | 2 | ||
3 | obj-$(CONFIG_PCI_BIOS) += pcbios.o | 3 | obj-$(CONFIG_PCI_BIOS) += pcbios.o |
4 | obj-$(CONFIG_PCI_MMCONFIG) += mmconfig.o direct.o | 4 | obj-$(CONFIG_PCI_MMCONFIG) += mmconfig.o direct.o mmconfig-shared.o |
5 | obj-$(CONFIG_PCI_DIRECT) += direct.o | 5 | obj-$(CONFIG_PCI_DIRECT) += direct.o |
6 | 6 | ||
7 | pci-y := fixup.o | 7 | pci-y := fixup.o |
diff --git a/arch/i386/pci/mmconfig-shared.c b/arch/i386/pci/mmconfig-shared.c new file mode 100644 index 000000000000..998e04f6d68f --- /dev/null +++ b/arch/i386/pci/mmconfig-shared.c | |||
@@ -0,0 +1,86 @@ | |||
1 | /* | ||
2 | * mmconfig-shared.c - Low-level direct PCI config space access via | ||
3 | * MMCONFIG - common code between i386 and x86-64. | ||
4 | * | ||
5 | * This code does: | ||
6 | * - ACPI decoding and validation | ||
7 | * | ||
8 | * Per-architecture code takes care of the mappings and accesses | ||
9 | * themselves. | ||
10 | */ | ||
11 | |||
12 | #include <linux/pci.h> | ||
13 | #include <linux/init.h> | ||
14 | #include <linux/acpi.h> | ||
15 | #include <linux/bitmap.h> | ||
16 | #include <asm/e820.h> | ||
17 | |||
18 | #include "pci.h" | ||
19 | |||
20 | /* aperture is up to 256MB but BIOS may reserve less */ | ||
21 | #define MMCONFIG_APER_MIN (2 * 1024*1024) | ||
22 | #define MMCONFIG_APER_MAX (256 * 1024*1024) | ||
23 | |||
24 | /* Verify the first 16 busses. We assume that systems with more busses | ||
25 | get MCFG right. */ | ||
26 | #define PCI_MMCFG_MAX_CHECK_BUS 16 | ||
27 | |||
28 | DECLARE_BITMAP(pci_mmcfg_fallback_slots, 32*PCI_MMCFG_MAX_CHECK_BUS); | ||
29 | |||
30 | /* K8 systems have some devices (typically in the builtin northbridge) | ||
31 | that are only accessible using type1 | ||
32 | Normally this can be expressed in the MCFG by not listing them | ||
33 | and assigning suitable _SEGs, but this isn't implemented in some BIOS. | ||
34 | Instead try to discover all devices on bus 0 that are unreachable using MM | ||
35 | and fallback for them. */ | ||
36 | static __init void unreachable_devices(void) | ||
37 | { | ||
38 | int i, k; | ||
39 | /* Use the max bus number from ACPI here? */ | ||
40 | for (k = 0; k < PCI_MMCFG_MAX_CHECK_BUS; k++) { | ||
41 | for (i = 0; i < 32; i++) { | ||
42 | u32 val1, val2; | ||
43 | |||
44 | pci_conf1_read(0, k, PCI_DEVFN(i,0), 0, 4, &val1); | ||
45 | if (val1 == 0xffffffff) | ||
46 | continue; | ||
47 | |||
48 | raw_pci_ops->read(0, k, PCI_DEVFN(i, 0), 0, 4, &val2); | ||
49 | if (val1 != val2) { | ||
50 | set_bit(i + 32*k, pci_mmcfg_fallback_slots); | ||
51 | printk(KERN_NOTICE "PCI: No mmconfig possible" | ||
52 | " on device %02x:%02x\n", k, i); | ||
53 | } | ||
54 | } | ||
55 | } | ||
56 | } | ||
57 | |||
58 | void __init pci_mmcfg_init(int type) | ||
59 | { | ||
60 | if ((pci_probe & PCI_PROBE_MMCONF) == 0) | ||
61 | return; | ||
62 | |||
63 | acpi_table_parse(ACPI_SIG_MCFG, acpi_parse_mcfg); | ||
64 | |||
65 | if ((pci_mmcfg_config_num == 0) || | ||
66 | (pci_mmcfg_config == NULL) || | ||
67 | (pci_mmcfg_config[0].address == 0)) | ||
68 | return; | ||
69 | |||
70 | /* Only do this check when type 1 works. If it doesn't work | ||
71 | assume we run on a Mac and always use MCFG */ | ||
72 | if (type == 1 && | ||
73 | !e820_all_mapped(pci_mmcfg_config[0].address, | ||
74 | pci_mmcfg_config[0].address + MMCONFIG_APER_MIN, | ||
75 | E820_RESERVED)) { | ||
76 | printk(KERN_ERR "PCI: BIOS Bug: MCFG area at %Lx is not E820-reserved\n", | ||
77 | pci_mmcfg_config[0].address); | ||
78 | printk(KERN_ERR "PCI: Not using MMCONFIG.\n"); | ||
79 | return; | ||
80 | } | ||
81 | |||
82 | if (pci_mmcfg_arch_init()) { | ||
83 | unreachable_devices(); | ||
84 | pci_probe = (pci_probe & ~PCI_PROBE_MASK) | PCI_PROBE_MMCONF; | ||
85 | } | ||
86 | } | ||
diff --git a/arch/i386/pci/mmconfig.c b/arch/i386/pci/mmconfig.c index 5700220dcf5f..97dcaaa0de0f 100644 --- a/arch/i386/pci/mmconfig.c +++ b/arch/i386/pci/mmconfig.c | |||
@@ -15,21 +15,13 @@ | |||
15 | #include <asm/e820.h> | 15 | #include <asm/e820.h> |
16 | #include "pci.h" | 16 | #include "pci.h" |
17 | 17 | ||
18 | /* aperture is up to 256MB but BIOS may reserve less */ | ||
19 | #define MMCONFIG_APER_MIN (2 * 1024*1024) | ||
20 | #define MMCONFIG_APER_MAX (256 * 1024*1024) | ||
21 | |||
22 | /* Assume systems with more busses have correct MCFG */ | 18 | /* Assume systems with more busses have correct MCFG */ |
23 | #define MAX_CHECK_BUS 16 | ||
24 | |||
25 | #define mmcfg_virt_addr ((void __iomem *) fix_to_virt(FIX_PCIE_MCFG)) | 19 | #define mmcfg_virt_addr ((void __iomem *) fix_to_virt(FIX_PCIE_MCFG)) |
26 | 20 | ||
27 | /* The base address of the last MMCONFIG device accessed */ | 21 | /* The base address of the last MMCONFIG device accessed */ |
28 | static u32 mmcfg_last_accessed_device; | 22 | static u32 mmcfg_last_accessed_device; |
29 | static int mmcfg_last_accessed_cpu; | 23 | static int mmcfg_last_accessed_cpu; |
30 | 24 | ||
31 | static DECLARE_BITMAP(fallback_slots, MAX_CHECK_BUS*32); | ||
32 | |||
33 | /* | 25 | /* |
34 | * Functions for accessing PCI configuration space with MMCONFIG accesses | 26 | * Functions for accessing PCI configuration space with MMCONFIG accesses |
35 | */ | 27 | */ |
@@ -38,8 +30,8 @@ static u32 get_base_addr(unsigned int seg, int bus, unsigned devfn) | |||
38 | int cfg_num = -1; | 30 | int cfg_num = -1; |
39 | struct acpi_mcfg_allocation *cfg; | 31 | struct acpi_mcfg_allocation *cfg; |
40 | 32 | ||
41 | if (seg == 0 && bus < MAX_CHECK_BUS && | 33 | if (seg == 0 && bus < PCI_MMCFG_MAX_CHECK_BUS && |
42 | test_bit(PCI_SLOT(devfn) + 32*bus, fallback_slots)) | 34 | test_bit(PCI_SLOT(devfn) + 32*bus, pci_mmcfg_fallback_slots)) |
43 | return 0; | 35 | return 0; |
44 | 36 | ||
45 | while (1) { | 37 | while (1) { |
@@ -158,67 +150,9 @@ static struct pci_raw_ops pci_mmcfg = { | |||
158 | .write = pci_mmcfg_write, | 150 | .write = pci_mmcfg_write, |
159 | }; | 151 | }; |
160 | 152 | ||
161 | /* K8 systems have some devices (typically in the builtin northbridge) | 153 | int __init pci_mmcfg_arch_init(void) |
162 | that are only accessible using type1 | ||
163 | Normally this can be expressed in the MCFG by not listing them | ||
164 | and assigning suitable _SEGs, but this isn't implemented in some BIOS. | ||
165 | Instead try to discover all devices on bus 0 that are unreachable using MM | ||
166 | and fallback for them. */ | ||
167 | static __init void unreachable_devices(void) | ||
168 | { | 154 | { |
169 | int i, k; | ||
170 | unsigned long flags; | ||
171 | |||
172 | for (k = 0; k < MAX_CHECK_BUS; k++) { | ||
173 | for (i = 0; i < 32; i++) { | ||
174 | u32 val1; | ||
175 | u32 addr; | ||
176 | |||
177 | pci_conf1_read(0, k, PCI_DEVFN(i, 0), 0, 4, &val1); | ||
178 | if (val1 == 0xffffffff) | ||
179 | continue; | ||
180 | |||
181 | /* Locking probably not needed, but safer */ | ||
182 | spin_lock_irqsave(&pci_config_lock, flags); | ||
183 | addr = get_base_addr(0, k, PCI_DEVFN(i, 0)); | ||
184 | if (addr != 0) | ||
185 | pci_exp_set_dev_base(addr, k, PCI_DEVFN(i, 0)); | ||
186 | if (addr == 0 || | ||
187 | readl((u32 __iomem *)mmcfg_virt_addr) != val1) { | ||
188 | set_bit(i + 32*k, fallback_slots); | ||
189 | printk(KERN_NOTICE | ||
190 | "PCI: No mmconfig possible on %x:%x\n", k, i); | ||
191 | } | ||
192 | spin_unlock_irqrestore(&pci_config_lock, flags); | ||
193 | } | ||
194 | } | ||
195 | } | ||
196 | |||
197 | void __init pci_mmcfg_init(int type) | ||
198 | { | ||
199 | if ((pci_probe & PCI_PROBE_MMCONF) == 0) | ||
200 | return; | ||
201 | |||
202 | acpi_table_parse(ACPI_SIG_MCFG, acpi_parse_mcfg); | ||
203 | if ((pci_mmcfg_config_num == 0) || | ||
204 | (pci_mmcfg_config == NULL) || | ||
205 | (pci_mmcfg_config[0].address == 0)) | ||
206 | return; | ||
207 | |||
208 | /* Only do this check when type 1 works. If it doesn't work | ||
209 | assume we run on a Mac and always use MCFG */ | ||
210 | if (type == 1 && !e820_all_mapped(pci_mmcfg_config[0].address, | ||
211 | pci_mmcfg_config[0].address + MMCONFIG_APER_MIN, | ||
212 | E820_RESERVED)) { | ||
213 | printk(KERN_ERR "PCI: BIOS Bug: MCFG area at %lx is not E820-reserved\n", | ||
214 | (unsigned long)pci_mmcfg_config[0].address); | ||
215 | printk(KERN_ERR "PCI: Not using MMCONFIG.\n"); | ||
216 | return; | ||
217 | } | ||
218 | |||
219 | printk(KERN_INFO "PCI: Using MMCONFIG\n"); | 155 | printk(KERN_INFO "PCI: Using MMCONFIG\n"); |
220 | raw_pci_ops = &pci_mmcfg; | 156 | raw_pci_ops = &pci_mmcfg; |
221 | pci_probe = (pci_probe & ~PCI_PROBE_MASK) | PCI_PROBE_MMCONF; | 157 | return 1; |
222 | |||
223 | unreachable_devices(); | ||
224 | } | 158 | } |
diff --git a/arch/i386/pci/pci.h b/arch/i386/pci/pci.h index a0a25180b61a..0270c80d99cc 100644 --- a/arch/i386/pci/pci.h +++ b/arch/i386/pci/pci.h | |||
@@ -94,3 +94,9 @@ extern void pci_pcbios_init(void); | |||
94 | extern void pci_mmcfg_init(int type); | 94 | extern void pci_mmcfg_init(int type); |
95 | extern void pcibios_sort(void); | 95 | extern void pcibios_sort(void); |
96 | 96 | ||
97 | /* pci-mmconfig.c */ | ||
98 | |||
99 | #define PCI_MMCFG_MAX_CHECK_BUS 16 | ||
100 | extern DECLARE_BITMAP(pci_mmcfg_fallback_slots, 32*PCI_MMCFG_MAX_CHECK_BUS); | ||
101 | |||
102 | extern int pci_mmcfg_arch_init(void); | ||
diff --git a/arch/x86_64/pci/Makefile b/arch/x86_64/pci/Makefile index 149aba05a5b8..c9eddc8859c0 100644 --- a/arch/x86_64/pci/Makefile +++ b/arch/x86_64/pci/Makefile | |||
@@ -11,7 +11,7 @@ obj-y += fixup.o init.o | |||
11 | obj-$(CONFIG_ACPI) += acpi.o | 11 | obj-$(CONFIG_ACPI) += acpi.o |
12 | obj-y += legacy.o irq.o common.o early.o | 12 | obj-y += legacy.o irq.o common.o early.o |
13 | # mmconfig has a 64bit special | 13 | # mmconfig has a 64bit special |
14 | obj-$(CONFIG_PCI_MMCONFIG) += mmconfig.o direct.o | 14 | obj-$(CONFIG_PCI_MMCONFIG) += mmconfig.o direct.o mmconfig-shared.o |
15 | 15 | ||
16 | obj-$(CONFIG_NUMA) += k8-bus.o | 16 | obj-$(CONFIG_NUMA) += k8-bus.o |
17 | 17 | ||
@@ -24,3 +24,4 @@ fixup-y += ../../i386/pci/fixup.o | |||
24 | i386-y += ../../i386/pci/i386.o | 24 | i386-y += ../../i386/pci/i386.o |
25 | init-y += ../../i386/pci/init.o | 25 | init-y += ../../i386/pci/init.o |
26 | early-y += ../../i386/pci/early.o | 26 | early-y += ../../i386/pci/early.o |
27 | mmconfig-shared-y += ../../i386/pci/mmconfig-shared.o | ||
diff --git a/arch/x86_64/pci/mmconfig.c b/arch/x86_64/pci/mmconfig.c index faabb6e87f12..0847735bb31e 100644 --- a/arch/x86_64/pci/mmconfig.c +++ b/arch/x86_64/pci/mmconfig.c | |||
@@ -19,9 +19,7 @@ | |||
19 | 19 | ||
20 | /* Verify the first 16 busses. We assume that systems with more busses | 20 | /* Verify the first 16 busses. We assume that systems with more busses |
21 | get MCFG right. */ | 21 | get MCFG right. */ |
22 | #define MAX_CHECK_BUS 16 | 22 | #define PCI_MMCFG_MAX_CHECK_BUS 16 |
23 | |||
24 | static DECLARE_BITMAP(fallback_slots, 32*MAX_CHECK_BUS); | ||
25 | 23 | ||
26 | /* Static virtual mapping of the MMCONFIG aperture */ | 24 | /* Static virtual mapping of the MMCONFIG aperture */ |
27 | struct mmcfg_virt { | 25 | struct mmcfg_virt { |
@@ -63,8 +61,8 @@ static char __iomem *get_virt(unsigned int seg, unsigned bus) | |||
63 | static char __iomem *pci_dev_base(unsigned int seg, unsigned int bus, unsigned int devfn) | 61 | static char __iomem *pci_dev_base(unsigned int seg, unsigned int bus, unsigned int devfn) |
64 | { | 62 | { |
65 | char __iomem *addr; | 63 | char __iomem *addr; |
66 | if (seg == 0 && bus < MAX_CHECK_BUS && | 64 | if (seg == 0 && bus < PCI_MMCFG_MAX_CHECK_BUS && |
67 | test_bit(32*bus + PCI_SLOT(devfn), fallback_slots)) | 65 | test_bit(32*bus + PCI_SLOT(devfn), pci_mmcfg_fallback_slots)) |
68 | return NULL; | 66 | return NULL; |
69 | addr = get_virt(seg, bus); | 67 | addr = get_virt(seg, bus); |
70 | if (!addr) | 68 | if (!addr) |
@@ -135,63 +133,16 @@ static struct pci_raw_ops pci_mmcfg = { | |||
135 | .write = pci_mmcfg_write, | 133 | .write = pci_mmcfg_write, |
136 | }; | 134 | }; |
137 | 135 | ||
138 | /* K8 systems have some devices (typically in the builtin northbridge) | 136 | int __init pci_mmcfg_arch_init(void) |
139 | that are only accessible using type1 | ||
140 | Normally this can be expressed in the MCFG by not listing them | ||
141 | and assigning suitable _SEGs, but this isn't implemented in some BIOS. | ||
142 | Instead try to discover all devices on bus 0 that are unreachable using MM | ||
143 | and fallback for them. */ | ||
144 | static __init void unreachable_devices(void) | ||
145 | { | ||
146 | int i, k; | ||
147 | /* Use the max bus number from ACPI here? */ | ||
148 | for (k = 0; k < MAX_CHECK_BUS; k++) { | ||
149 | for (i = 0; i < 32; i++) { | ||
150 | u32 val1; | ||
151 | char __iomem *addr; | ||
152 | |||
153 | pci_conf1_read(0, k, PCI_DEVFN(i,0), 0, 4, &val1); | ||
154 | if (val1 == 0xffffffff) | ||
155 | continue; | ||
156 | addr = pci_dev_base(0, k, PCI_DEVFN(i, 0)); | ||
157 | if (addr == NULL|| readl(addr) != val1) { | ||
158 | set_bit(i + 32*k, fallback_slots); | ||
159 | printk(KERN_NOTICE "PCI: No mmconfig possible" | ||
160 | " on device %02x:%02x\n", k, i); | ||
161 | } | ||
162 | } | ||
163 | } | ||
164 | } | ||
165 | |||
166 | void __init pci_mmcfg_init(int type) | ||
167 | { | 137 | { |
168 | int i; | 138 | int i; |
169 | 139 | pci_mmcfg_virt = kmalloc(sizeof(*pci_mmcfg_virt) * | |
170 | if ((pci_probe & PCI_PROBE_MMCONF) == 0) | 140 | pci_mmcfg_config_num, GFP_KERNEL); |
171 | return; | ||
172 | |||
173 | acpi_table_parse(ACPI_SIG_MCFG, acpi_parse_mcfg); | ||
174 | if ((pci_mmcfg_config_num == 0) || | ||
175 | (pci_mmcfg_config == NULL) || | ||
176 | (pci_mmcfg_config[0].address == 0)) | ||
177 | return; | ||
178 | |||
179 | /* Only do this check when type 1 works. If it doesn't work | ||
180 | assume we run on a Mac and always use MCFG */ | ||
181 | if (type == 1 && !e820_all_mapped(pci_mmcfg_config[0].address, | ||
182 | pci_mmcfg_config[0].address + MMCONFIG_APER_MIN, | ||
183 | E820_RESERVED)) { | ||
184 | printk(KERN_ERR "PCI: BIOS Bug: MCFG area at %lx is not E820-reserved\n", | ||
185 | (unsigned long)pci_mmcfg_config[0].address); | ||
186 | printk(KERN_ERR "PCI: Not using MMCONFIG.\n"); | ||
187 | return; | ||
188 | } | ||
189 | |||
190 | pci_mmcfg_virt = kmalloc(sizeof(*pci_mmcfg_virt) * pci_mmcfg_config_num, GFP_KERNEL); | ||
191 | if (pci_mmcfg_virt == NULL) { | 141 | if (pci_mmcfg_virt == NULL) { |
192 | printk(KERN_ERR "PCI: Can not allocate memory for mmconfig structures\n"); | 142 | printk(KERN_ERR "PCI: Can not allocate memory for mmconfig structures\n"); |
193 | return; | 143 | return 0; |
194 | } | 144 | } |
145 | |||
195 | for (i = 0; i < pci_mmcfg_config_num; ++i) { | 146 | for (i = 0; i < pci_mmcfg_config_num; ++i) { |
196 | pci_mmcfg_virt[i].cfg = &pci_mmcfg_config[i]; | 147 | pci_mmcfg_virt[i].cfg = &pci_mmcfg_config[i]; |
197 | pci_mmcfg_virt[i].virt = ioremap_nocache(pci_mmcfg_config[i].address, | 148 | pci_mmcfg_virt[i].virt = ioremap_nocache(pci_mmcfg_config[i].address, |
@@ -200,14 +151,11 @@ void __init pci_mmcfg_init(int type) | |||
200 | printk(KERN_ERR "PCI: Cannot map mmconfig aperture for " | 151 | printk(KERN_ERR "PCI: Cannot map mmconfig aperture for " |
201 | "segment %d\n", | 152 | "segment %d\n", |
202 | pci_mmcfg_config[i].pci_segment); | 153 | pci_mmcfg_config[i].pci_segment); |
203 | return; | 154 | return 0; |
204 | } | 155 | } |
205 | printk(KERN_INFO "PCI: Using MMCONFIG at %lx\n", | 156 | printk(KERN_INFO "PCI: Using MMCONFIG at %Lx\n", |
206 | (unsigned long)pci_mmcfg_config[i].address); | 157 | pci_mmcfg_config[i].address); |
207 | } | 158 | } |
208 | |||
209 | unreachable_devices(); | ||
210 | |||
211 | raw_pci_ops = &pci_mmcfg; | 159 | raw_pci_ops = &pci_mmcfg; |
212 | pci_probe = (pci_probe & ~PCI_PROBE_MASK) | PCI_PROBE_MMCONF; | 160 | return 1; |
213 | } | 161 | } |