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 | ||
b5229dbb OG |
63 | win = win & 0xf000; |
64 | if(win == 0x0000 || win == 0xf000) | |
65 | pci_mmcfg_config_num = 0; | |
66 | else { | |
67 | pci_mmcfg_config_num = 1; | |
68 | pci_mmcfg_config = kzalloc(sizeof(pci_mmcfg_config[0]), GFP_KERNEL); | |
69 | if (!pci_mmcfg_config) | |
70 | return NULL; | |
71 | pci_mmcfg_config[0].address = win << 16; | |
72 | pci_mmcfg_config[0].pci_segment = 0; | |
73 | pci_mmcfg_config[0].start_bus_number = 0; | |
74 | pci_mmcfg_config[0].end_bus_number = 255; | |
75 | } | |
9358c693 OG |
76 | |
77 | return "Intel Corporation E7520 Memory Controller Hub"; | |
78 | } | |
79 | ||
429d512e | 80 | static const char __init *pci_mmcfg_intel_945(void) |
9358c693 OG |
81 | { |
82 | u32 pciexbar, mask = 0, len = 0; | |
83 | ||
84 | pci_mmcfg_config_num = 1; | |
85 | ||
86 | pci_conf1_read(0, 0, PCI_DEVFN(0,0), 0x48, 4, &pciexbar); | |
87 | ||
88 | /* Enable bit */ | |
89 | if (!(pciexbar & 1)) | |
90 | pci_mmcfg_config_num = 0; | |
91 | ||
92 | /* Size bits */ | |
93 | switch ((pciexbar >> 1) & 3) { | |
94 | case 0: | |
95 | mask = 0xf0000000U; | |
96 | len = 0x10000000U; | |
97 | break; | |
98 | case 1: | |
99 | mask = 0xf8000000U; | |
100 | len = 0x08000000U; | |
101 | break; | |
102 | case 2: | |
103 | mask = 0xfc000000U; | |
104 | len = 0x04000000U; | |
105 | break; | |
106 | default: | |
107 | pci_mmcfg_config_num = 0; | |
108 | } | |
109 | ||
110 | /* Errata #2, things break when not aligned on a 256Mb boundary */ | |
111 | /* Can only happen in 64M/128M mode */ | |
112 | ||
113 | if ((pciexbar & mask) & 0x0fffffffU) | |
114 | pci_mmcfg_config_num = 0; | |
115 | ||
b5229dbb OG |
116 | /* Don't hit the APIC registers and their friends */ |
117 | if ((pciexbar & mask) >= 0xf0000000U) | |
118 | pci_mmcfg_config_num = 0; | |
119 | ||
9358c693 OG |
120 | if (pci_mmcfg_config_num) { |
121 | pci_mmcfg_config = kzalloc(sizeof(pci_mmcfg_config[0]), GFP_KERNEL); | |
122 | if (!pci_mmcfg_config) | |
123 | return NULL; | |
124 | pci_mmcfg_config[0].address = pciexbar & mask; | |
125 | pci_mmcfg_config[0].pci_segment = 0; | |
126 | pci_mmcfg_config[0].start_bus_number = 0; | |
127 | pci_mmcfg_config[0].end_bus_number = (len >> 20) - 1; | |
128 | } | |
129 | ||
130 | return "Intel Corporation 945G/GZ/P/PL Express Memory Controller Hub"; | |
131 | } | |
132 | ||
133 | struct pci_mmcfg_hostbridge_probe { | |
134 | u32 vendor; | |
135 | u32 device; | |
136 | const char *(*probe)(void); | |
137 | }; | |
138 | ||
429d512e | 139 | static struct pci_mmcfg_hostbridge_probe pci_mmcfg_probes[] __initdata = { |
9358c693 OG |
140 | { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_E7520_MCH, pci_mmcfg_e7520 }, |
141 | { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82945G_HB, pci_mmcfg_intel_945 }, | |
142 | }; | |
143 | ||
144 | static int __init pci_mmcfg_check_hostbridge(void) | |
145 | { | |
146 | u32 l; | |
147 | u16 vendor, device; | |
148 | int i; | |
149 | const char *name; | |
150 | ||
151 | pci_conf1_read(0, 0, PCI_DEVFN(0,0), 0, 4, &l); | |
152 | vendor = l & 0xffff; | |
153 | device = (l >> 16) & 0xffff; | |
154 | ||
155 | pci_mmcfg_config_num = 0; | |
156 | pci_mmcfg_config = NULL; | |
157 | name = NULL; | |
158 | ||
429d512e OH |
159 | for (i = 0; !name && i < ARRAY_SIZE(pci_mmcfg_probes); i++) { |
160 | if (pci_mmcfg_probes[i].vendor == vendor && | |
161 | pci_mmcfg_probes[i].device == device) | |
9358c693 | 162 | name = pci_mmcfg_probes[i].probe(); |
429d512e | 163 | } |
9358c693 OG |
164 | |
165 | if (name) { | |
429d512e OH |
166 | printk(KERN_INFO "PCI: Found %s %s MMCONFIG support.\n", |
167 | name, pci_mmcfg_config_num ? "with" : "without"); | |
9358c693 OG |
168 | } |
169 | ||
170 | return name != NULL; | |
171 | } | |
172 | ||
429d512e | 173 | static void __init pci_mmcfg_insert_resources(void) |
6a0668fc OG |
174 | { |
175 | #define PCI_MMCFG_RESOURCE_NAME_LEN 19 | |
176 | int i; | |
177 | struct resource *res; | |
178 | char *names; | |
179 | unsigned num_buses; | |
180 | ||
181 | res = kcalloc(PCI_MMCFG_RESOURCE_NAME_LEN + sizeof(*res), | |
182 | pci_mmcfg_config_num, GFP_KERNEL); | |
6a0668fc OG |
183 | if (!res) { |
184 | printk(KERN_ERR "PCI: Unable to allocate MMCONFIG resources\n"); | |
185 | return; | |
186 | } | |
187 | ||
188 | names = (void *)&res[pci_mmcfg_config_num]; | |
189 | for (i = 0; i < pci_mmcfg_config_num; i++, res++) { | |
429d512e OH |
190 | struct acpi_mcfg_allocation *cfg = &pci_mmcfg_config[i]; |
191 | num_buses = cfg->end_bus_number - cfg->start_bus_number + 1; | |
6a0668fc OG |
192 | res->name = names; |
193 | snprintf(names, PCI_MMCFG_RESOURCE_NAME_LEN, "PCI MMCONFIG %u", | |
429d512e OH |
194 | cfg->pci_segment); |
195 | res->start = cfg->address; | |
6a0668fc OG |
196 | res->end = res->start + (num_buses << 20) - 1; |
197 | res->flags = IORESOURCE_MEM | IORESOURCE_BUSY; | |
198 | insert_resource(&iomem_resource, res); | |
199 | names += PCI_MMCFG_RESOURCE_NAME_LEN; | |
200 | } | |
201 | } | |
202 | ||
26054ed0 | 203 | static void __init pci_mmcfg_reject_broken(int type) |
44de0203 | 204 | { |
26054ed0 OH |
205 | typeof(pci_mmcfg_config[0]) *cfg; |
206 | ||
207 | if ((pci_mmcfg_config_num == 0) || | |
208 | (pci_mmcfg_config == NULL) || | |
209 | (pci_mmcfg_config[0].address == 0)) | |
210 | return; | |
211 | ||
212 | cfg = &pci_mmcfg_config[0]; | |
44de0203 OH |
213 | |
214 | /* | |
215 | * Handle more broken MCFG tables on Asus etc. | |
216 | * They only contain a single entry for bus 0-0. | |
217 | */ | |
218 | if (pci_mmcfg_config_num == 1 && | |
219 | cfg->pci_segment == 0 && | |
220 | (cfg->start_bus_number | cfg->end_bus_number) == 0) { | |
44de0203 | 221 | printk(KERN_ERR "PCI: start and end of bus number is 0. " |
26054ed0 OH |
222 | "Rejected as broken MCFG.\n"); |
223 | goto reject; | |
224 | } | |
225 | ||
226 | /* | |
227 | * Only do this check when type 1 works. If it doesn't work | |
228 | * assume we run on a Mac and always use MCFG | |
229 | */ | |
230 | if (type == 1 && !e820_all_mapped(cfg->address, | |
231 | cfg->address + MMCONFIG_APER_MIN, | |
232 | E820_RESERVED)) { | |
233 | printk(KERN_ERR "PCI: BIOS Bug: MCFG area at %Lx is not" | |
234 | " E820-reserved\n", cfg->address); | |
235 | goto reject; | |
44de0203 | 236 | } |
26054ed0 OH |
237 | return; |
238 | ||
239 | reject: | |
240 | printk(KERN_ERR "PCI: Not using MMCONFIG.\n"); | |
241 | kfree(pci_mmcfg_config); | |
242 | pci_mmcfg_config = NULL; | |
243 | pci_mmcfg_config_num = 0; | |
44de0203 OH |
244 | } |
245 | ||
b7867394 OG |
246 | void __init pci_mmcfg_init(int type) |
247 | { | |
9358c693 OG |
248 | int known_bridge = 0; |
249 | ||
b7867394 OG |
250 | if ((pci_probe & PCI_PROBE_MMCONF) == 0) |
251 | return; | |
252 | ||
9358c693 OG |
253 | if (type == 1 && pci_mmcfg_check_hostbridge()) |
254 | known_bridge = 1; | |
255 | ||
44de0203 | 256 | if (!known_bridge) { |
9358c693 | 257 | acpi_table_parse(ACPI_SIG_MCFG, acpi_parse_mcfg); |
26054ed0 | 258 | pci_mmcfg_reject_broken(type); |
44de0203 | 259 | } |
b7867394 OG |
260 | |
261 | if ((pci_mmcfg_config_num == 0) || | |
262 | (pci_mmcfg_config == NULL) || | |
263 | (pci_mmcfg_config[0].address == 0)) | |
264 | return; | |
265 | ||
b7867394 | 266 | if (pci_mmcfg_arch_init()) { |
5f027387 OG |
267 | if (type == 1) |
268 | unreachable_devices(); | |
6a0668fc OG |
269 | if (known_bridge) |
270 | pci_mmcfg_insert_resources(); | |
b7867394 OG |
271 | pci_probe = (pci_probe & ~PCI_PROBE_MASK) | PCI_PROBE_MMCONF; |
272 | } | |
273 | } |