]>
Commit | Line | Data |
---|---|---|
b7867394 OG |
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: | |
9358c693 | 6 | * - known chipset handling |
b7867394 OG |
7 | * - ACPI decoding and validation |
8 | * | |
9 | * Per-architecture code takes care of the mappings and accesses | |
10 | * themselves. | |
11 | */ | |
12 | ||
13 | #include <linux/pci.h> | |
14 | #include <linux/init.h> | |
15 | #include <linux/acpi.h> | |
16 | #include <linux/bitmap.h> | |
17 | #include <asm/e820.h> | |
18 | ||
19 | #include "pci.h" | |
20 | ||
21 | /* aperture is up to 256MB but BIOS may reserve less */ | |
22 | #define MMCONFIG_APER_MIN (2 * 1024*1024) | |
23 | #define MMCONFIG_APER_MAX (256 * 1024*1024) | |
24 | ||
b7867394 OG |
25 | DECLARE_BITMAP(pci_mmcfg_fallback_slots, 32*PCI_MMCFG_MAX_CHECK_BUS); |
26 | ||
27 | /* K8 systems have some devices (typically in the builtin northbridge) | |
28 | that are only accessible using type1 | |
29 | Normally this can be expressed in the MCFG by not listing them | |
30 | and assigning suitable _SEGs, but this isn't implemented in some BIOS. | |
31 | Instead try to discover all devices on bus 0 that are unreachable using MM | |
32 | and fallback for them. */ | |
429d512e | 33 | static void __init unreachable_devices(void) |
b7867394 | 34 | { |
429d512e | 35 | int i, bus; |
b7867394 | 36 | /* Use the max bus number from ACPI here? */ |
429d512e | 37 | for (bus = 0; bus < PCI_MMCFG_MAX_CHECK_BUS; bus++) { |
b7867394 | 38 | for (i = 0; i < 32; i++) { |
429d512e | 39 | unsigned int devfn = PCI_DEVFN(i, 0); |
b7867394 OG |
40 | u32 val1, val2; |
41 | ||
429d512e | 42 | pci_conf1_read(0, bus, devfn, 0, 4, &val1); |
b7867394 OG |
43 | if (val1 == 0xffffffff) |
44 | continue; | |
45 | ||
56829d19 OH |
46 | if (pci_mmcfg_arch_reachable(0, bus, devfn)) { |
47 | raw_pci_ops->read(0, bus, devfn, 0, 4, &val2); | |
48 | if (val1 == val2) | |
49 | continue; | |
b7867394 | 50 | } |
56829d19 OH |
51 | set_bit(i + 32 * bus, pci_mmcfg_fallback_slots); |
52 | printk(KERN_NOTICE "PCI: No mmconfig possible on device" | |
53 | " %02x:%02x\n", bus, i); | |
b7867394 OG |
54 | } |
55 | } | |
56 | } | |
57 | ||
429d512e | 58 | static const char __init *pci_mmcfg_e7520(void) |
9358c693 OG |
59 | { |
60 | u32 win; | |
61 | pci_conf1_read(0, 0, PCI_DEVFN(0,0), 0xce, 2, &win); | |
62 | ||
63 | pci_mmcfg_config_num = 1; | |
64 | pci_mmcfg_config = kzalloc(sizeof(pci_mmcfg_config[0]), GFP_KERNEL); | |
65 | if (!pci_mmcfg_config) | |
66 | return NULL; | |
67 | pci_mmcfg_config[0].address = (win & 0xf000) << 16; | |
68 | pci_mmcfg_config[0].pci_segment = 0; | |
69 | pci_mmcfg_config[0].start_bus_number = 0; | |
70 | pci_mmcfg_config[0].end_bus_number = 255; | |
71 | ||
72 | return "Intel Corporation E7520 Memory Controller Hub"; | |
73 | } | |
74 | ||
429d512e | 75 | static const char __init *pci_mmcfg_intel_945(void) |
9358c693 OG |
76 | { |
77 | u32 pciexbar, mask = 0, len = 0; | |
78 | ||
79 | pci_mmcfg_config_num = 1; | |
80 | ||
81 | pci_conf1_read(0, 0, PCI_DEVFN(0,0), 0x48, 4, &pciexbar); | |
82 | ||
83 | /* Enable bit */ | |
84 | if (!(pciexbar & 1)) | |
85 | pci_mmcfg_config_num = 0; | |
86 | ||
87 | /* Size bits */ | |
88 | switch ((pciexbar >> 1) & 3) { | |
89 | case 0: | |
90 | mask = 0xf0000000U; | |
91 | len = 0x10000000U; | |
92 | break; | |
93 | case 1: | |
94 | mask = 0xf8000000U; | |
95 | len = 0x08000000U; | |
96 | break; | |
97 | case 2: | |
98 | mask = 0xfc000000U; | |
99 | len = 0x04000000U; | |
100 | break; | |
101 | default: | |
102 | pci_mmcfg_config_num = 0; | |
103 | } | |
104 | ||
105 | /* Errata #2, things break when not aligned on a 256Mb boundary */ | |
106 | /* Can only happen in 64M/128M mode */ | |
107 | ||
108 | if ((pciexbar & mask) & 0x0fffffffU) | |
109 | pci_mmcfg_config_num = 0; | |
110 | ||
111 | if (pci_mmcfg_config_num) { | |
112 | pci_mmcfg_config = kzalloc(sizeof(pci_mmcfg_config[0]), GFP_KERNEL); | |
113 | if (!pci_mmcfg_config) | |
114 | return NULL; | |
115 | pci_mmcfg_config[0].address = pciexbar & mask; | |
116 | pci_mmcfg_config[0].pci_segment = 0; | |
117 | pci_mmcfg_config[0].start_bus_number = 0; | |
118 | pci_mmcfg_config[0].end_bus_number = (len >> 20) - 1; | |
119 | } | |
120 | ||
121 | return "Intel Corporation 945G/GZ/P/PL Express Memory Controller Hub"; | |
122 | } | |
123 | ||
124 | struct pci_mmcfg_hostbridge_probe { | |
125 | u32 vendor; | |
126 | u32 device; | |
127 | const char *(*probe)(void); | |
128 | }; | |
129 | ||
429d512e | 130 | static struct pci_mmcfg_hostbridge_probe pci_mmcfg_probes[] __initdata = { |
9358c693 OG |
131 | { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_E7520_MCH, pci_mmcfg_e7520 }, |
132 | { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82945G_HB, pci_mmcfg_intel_945 }, | |
133 | }; | |
134 | ||
135 | static int __init pci_mmcfg_check_hostbridge(void) | |
136 | { | |
137 | u32 l; | |
138 | u16 vendor, device; | |
139 | int i; | |
140 | const char *name; | |
141 | ||
142 | pci_conf1_read(0, 0, PCI_DEVFN(0,0), 0, 4, &l); | |
143 | vendor = l & 0xffff; | |
144 | device = (l >> 16) & 0xffff; | |
145 | ||
146 | pci_mmcfg_config_num = 0; | |
147 | pci_mmcfg_config = NULL; | |
148 | name = NULL; | |
149 | ||
429d512e OH |
150 | for (i = 0; !name && i < ARRAY_SIZE(pci_mmcfg_probes); i++) { |
151 | if (pci_mmcfg_probes[i].vendor == vendor && | |
152 | pci_mmcfg_probes[i].device == device) | |
9358c693 | 153 | name = pci_mmcfg_probes[i].probe(); |
429d512e | 154 | } |
9358c693 OG |
155 | |
156 | if (name) { | |
429d512e OH |
157 | printk(KERN_INFO "PCI: Found %s %s MMCONFIG support.\n", |
158 | name, pci_mmcfg_config_num ? "with" : "without"); | |
9358c693 OG |
159 | } |
160 | ||
161 | return name != NULL; | |
162 | } | |
163 | ||
429d512e | 164 | static void __init pci_mmcfg_insert_resources(void) |
6a0668fc OG |
165 | { |
166 | #define PCI_MMCFG_RESOURCE_NAME_LEN 19 | |
167 | int i; | |
168 | struct resource *res; | |
169 | char *names; | |
170 | unsigned num_buses; | |
171 | ||
172 | res = kcalloc(PCI_MMCFG_RESOURCE_NAME_LEN + sizeof(*res), | |
173 | pci_mmcfg_config_num, GFP_KERNEL); | |
6a0668fc OG |
174 | if (!res) { |
175 | printk(KERN_ERR "PCI: Unable to allocate MMCONFIG resources\n"); | |
176 | return; | |
177 | } | |
178 | ||
179 | names = (void *)&res[pci_mmcfg_config_num]; | |
180 | for (i = 0; i < pci_mmcfg_config_num; i++, res++) { | |
429d512e OH |
181 | struct acpi_mcfg_allocation *cfg = &pci_mmcfg_config[i]; |
182 | num_buses = cfg->end_bus_number - cfg->start_bus_number + 1; | |
6a0668fc OG |
183 | res->name = names; |
184 | snprintf(names, PCI_MMCFG_RESOURCE_NAME_LEN, "PCI MMCONFIG %u", | |
429d512e OH |
185 | cfg->pci_segment); |
186 | res->start = cfg->address; | |
6a0668fc OG |
187 | res->end = res->start + (num_buses << 20) - 1; |
188 | res->flags = IORESOURCE_MEM | IORESOURCE_BUSY; | |
189 | insert_resource(&iomem_resource, res); | |
190 | names += PCI_MMCFG_RESOURCE_NAME_LEN; | |
191 | } | |
192 | } | |
193 | ||
44de0203 OH |
194 | static void __init pci_mmcfg_reject_broken(void) |
195 | { | |
196 | typeof(pci_mmcfg_config[0]) *cfg = &pci_mmcfg_config[0]; | |
197 | ||
198 | /* | |
199 | * Handle more broken MCFG tables on Asus etc. | |
200 | * They only contain a single entry for bus 0-0. | |
201 | */ | |
202 | if (pci_mmcfg_config_num == 1 && | |
203 | cfg->pci_segment == 0 && | |
204 | (cfg->start_bus_number | cfg->end_bus_number) == 0) { | |
205 | kfree(pci_mmcfg_config); | |
206 | pci_mmcfg_config = NULL; | |
207 | pci_mmcfg_config_num = 0; | |
208 | ||
209 | printk(KERN_ERR "PCI: start and end of bus number is 0. " | |
210 | "Rejected as broken MCFG."); | |
211 | } | |
212 | } | |
213 | ||
b7867394 OG |
214 | void __init pci_mmcfg_init(int type) |
215 | { | |
9358c693 OG |
216 | int known_bridge = 0; |
217 | ||
b7867394 OG |
218 | if ((pci_probe & PCI_PROBE_MMCONF) == 0) |
219 | return; | |
220 | ||
9358c693 OG |
221 | if (type == 1 && pci_mmcfg_check_hostbridge()) |
222 | known_bridge = 1; | |
223 | ||
44de0203 | 224 | if (!known_bridge) { |
9358c693 | 225 | acpi_table_parse(ACPI_SIG_MCFG, acpi_parse_mcfg); |
44de0203 OH |
226 | pci_mmcfg_reject_broken(); |
227 | } | |
b7867394 OG |
228 | |
229 | if ((pci_mmcfg_config_num == 0) || | |
230 | (pci_mmcfg_config == NULL) || | |
231 | (pci_mmcfg_config[0].address == 0)) | |
232 | return; | |
233 | ||
234 | /* Only do this check when type 1 works. If it doesn't work | |
235 | assume we run on a Mac and always use MCFG */ | |
9358c693 | 236 | if (type == 1 && !known_bridge && |
b7867394 OG |
237 | !e820_all_mapped(pci_mmcfg_config[0].address, |
238 | pci_mmcfg_config[0].address + MMCONFIG_APER_MIN, | |
239 | E820_RESERVED)) { | |
240 | printk(KERN_ERR "PCI: BIOS Bug: MCFG area at %Lx is not E820-reserved\n", | |
241 | pci_mmcfg_config[0].address); | |
242 | printk(KERN_ERR "PCI: Not using MMCONFIG.\n"); | |
243 | return; | |
244 | } | |
245 | ||
246 | if (pci_mmcfg_arch_init()) { | |
5f027387 OG |
247 | if (type == 1) |
248 | unreachable_devices(); | |
6a0668fc OG |
249 | if (known_bridge) |
250 | pci_mmcfg_insert_resources(); | |
b7867394 OG |
251 | pci_probe = (pci_probe & ~PCI_PROBE_MASK) | PCI_PROBE_MMCONF; |
252 | } | |
253 | } |