aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorOlivier Galibert <galibert@pobox.com>2007-02-13 07:26:20 -0500
committerAndi Kleen <andi@basil.nowhere.org>2007-02-13 07:26:20 -0500
commitb78673944b22b662b270c8bba5c198f19e4ee4e1 (patch)
tree3cbbe3808335fc297fb3daf01dcbf26d4243a2db
parent2e188938ab2358034801938c2329b016ca135823 (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/Makefile2
-rw-r--r--arch/i386/pci/mmconfig-shared.c86
-rw-r--r--arch/i386/pci/mmconfig.c74
-rw-r--r--arch/i386/pci/pci.h6
-rw-r--r--arch/x86_64/pci/Makefile3
-rw-r--r--arch/x86_64/pci/mmconfig.c76
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 @@
1obj-y := i386.o init.o 1obj-y := i386.o init.o
2 2
3obj-$(CONFIG_PCI_BIOS) += pcbios.o 3obj-$(CONFIG_PCI_BIOS) += pcbios.o
4obj-$(CONFIG_PCI_MMCONFIG) += mmconfig.o direct.o 4obj-$(CONFIG_PCI_MMCONFIG) += mmconfig.o direct.o mmconfig-shared.o
5obj-$(CONFIG_PCI_DIRECT) += direct.o 5obj-$(CONFIG_PCI_DIRECT) += direct.o
6 6
7pci-y := fixup.o 7pci-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
28DECLARE_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. */
36static __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
58void __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 */
28static u32 mmcfg_last_accessed_device; 22static u32 mmcfg_last_accessed_device;
29static int mmcfg_last_accessed_cpu; 23static int mmcfg_last_accessed_cpu;
30 24
31static 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) 153int __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. */
167static __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
197void __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);
94extern void pci_mmcfg_init(int type); 94extern void pci_mmcfg_init(int type);
95extern void pcibios_sort(void); 95extern void pcibios_sort(void);
96 96
97/* pci-mmconfig.c */
98
99#define PCI_MMCFG_MAX_CHECK_BUS 16
100extern DECLARE_BITMAP(pci_mmcfg_fallback_slots, 32*PCI_MMCFG_MAX_CHECK_BUS);
101
102extern 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
11obj-$(CONFIG_ACPI) += acpi.o 11obj-$(CONFIG_ACPI) += acpi.o
12obj-y += legacy.o irq.o common.o early.o 12obj-y += legacy.o irq.o common.o early.o
13# mmconfig has a 64bit special 13# mmconfig has a 64bit special
14obj-$(CONFIG_PCI_MMCONFIG) += mmconfig.o direct.o 14obj-$(CONFIG_PCI_MMCONFIG) += mmconfig.o direct.o mmconfig-shared.o
15 15
16obj-$(CONFIG_NUMA) += k8-bus.o 16obj-$(CONFIG_NUMA) += k8-bus.o
17 17
@@ -24,3 +24,4 @@ fixup-y += ../../i386/pci/fixup.o
24i386-y += ../../i386/pci/i386.o 24i386-y += ../../i386/pci/i386.o
25init-y += ../../i386/pci/init.o 25init-y += ../../i386/pci/init.o
26early-y += ../../i386/pci/early.o 26early-y += ../../i386/pci/early.o
27mmconfig-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
24static 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 */
27struct mmcfg_virt { 25struct mmcfg_virt {
@@ -63,8 +61,8 @@ static char __iomem *get_virt(unsigned int seg, unsigned bus)
63static char __iomem *pci_dev_base(unsigned int seg, unsigned int bus, unsigned int devfn) 61static 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) 136int __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. */
144static __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
166void __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}