diff options
Diffstat (limited to 'arch')
-rw-r--r-- | arch/x86/kernel/early-quirks.c | 154 |
1 files changed, 154 insertions, 0 deletions
diff --git a/arch/x86/kernel/early-quirks.c b/arch/x86/kernel/early-quirks.c index 63bdb29b2549..b3cd3ebae077 100644 --- a/arch/x86/kernel/early-quirks.c +++ b/arch/x86/kernel/early-quirks.c | |||
@@ -12,6 +12,7 @@ | |||
12 | #include <linux/pci.h> | 12 | #include <linux/pci.h> |
13 | #include <linux/acpi.h> | 13 | #include <linux/acpi.h> |
14 | #include <linux/pci_ids.h> | 14 | #include <linux/pci_ids.h> |
15 | #include <drm/i915_drm.h> | ||
15 | #include <asm/pci-direct.h> | 16 | #include <asm/pci-direct.h> |
16 | #include <asm/dma.h> | 17 | #include <asm/dma.h> |
17 | #include <asm/io_apic.h> | 18 | #include <asm/io_apic.h> |
@@ -216,6 +217,157 @@ static void __init intel_remapping_check(int num, int slot, int func) | |||
216 | 217 | ||
217 | } | 218 | } |
218 | 219 | ||
220 | /* | ||
221 | * Systems with Intel graphics controllers set aside memory exclusively | ||
222 | * for gfx driver use. This memory is not marked in the E820 as reserved | ||
223 | * or as RAM, and so is subject to overlap from E820 manipulation later | ||
224 | * in the boot process. On some systems, MMIO space is allocated on top, | ||
225 | * despite the efforts of the "RAM buffer" approach, which simply rounds | ||
226 | * memory boundaries up to 64M to try to catch space that may decode | ||
227 | * as RAM and so is not suitable for MMIO. | ||
228 | * | ||
229 | * And yes, so far on current devices the base addr is always under 4G. | ||
230 | */ | ||
231 | static u32 __init intel_stolen_base(int num, int slot, int func) | ||
232 | { | ||
233 | u32 base; | ||
234 | |||
235 | /* | ||
236 | * For the PCI IDs in this quirk, the stolen base is always | ||
237 | * in 0x5c, aka the BDSM register (yes that's really what | ||
238 | * it's called). | ||
239 | */ | ||
240 | base = read_pci_config(num, slot, func, 0x5c); | ||
241 | base &= ~((1<<20) - 1); | ||
242 | |||
243 | return base; | ||
244 | } | ||
245 | |||
246 | #define KB(x) ((x) * 1024) | ||
247 | #define MB(x) (KB (KB (x))) | ||
248 | #define GB(x) (MB (KB (x))) | ||
249 | |||
250 | static size_t __init gen3_stolen_size(int num, int slot, int func) | ||
251 | { | ||
252 | size_t stolen_size; | ||
253 | u16 gmch_ctrl; | ||
254 | |||
255 | gmch_ctrl = read_pci_config_16(0, 0, 0, I830_GMCH_CTRL); | ||
256 | |||
257 | switch (gmch_ctrl & I855_GMCH_GMS_MASK) { | ||
258 | case I855_GMCH_GMS_STOLEN_1M: | ||
259 | stolen_size = MB(1); | ||
260 | break; | ||
261 | case I855_GMCH_GMS_STOLEN_4M: | ||
262 | stolen_size = MB(4); | ||
263 | break; | ||
264 | case I855_GMCH_GMS_STOLEN_8M: | ||
265 | stolen_size = MB(8); | ||
266 | break; | ||
267 | case I855_GMCH_GMS_STOLEN_16M: | ||
268 | stolen_size = MB(16); | ||
269 | break; | ||
270 | case I855_GMCH_GMS_STOLEN_32M: | ||
271 | stolen_size = MB(32); | ||
272 | break; | ||
273 | case I915_GMCH_GMS_STOLEN_48M: | ||
274 | stolen_size = MB(48); | ||
275 | break; | ||
276 | case I915_GMCH_GMS_STOLEN_64M: | ||
277 | stolen_size = MB(64); | ||
278 | break; | ||
279 | case G33_GMCH_GMS_STOLEN_128M: | ||
280 | stolen_size = MB(128); | ||
281 | break; | ||
282 | case G33_GMCH_GMS_STOLEN_256M: | ||
283 | stolen_size = MB(256); | ||
284 | break; | ||
285 | case INTEL_GMCH_GMS_STOLEN_96M: | ||
286 | stolen_size = MB(96); | ||
287 | break; | ||
288 | case INTEL_GMCH_GMS_STOLEN_160M: | ||
289 | stolen_size = MB(160); | ||
290 | break; | ||
291 | case INTEL_GMCH_GMS_STOLEN_224M: | ||
292 | stolen_size = MB(224); | ||
293 | break; | ||
294 | case INTEL_GMCH_GMS_STOLEN_352M: | ||
295 | stolen_size = MB(352); | ||
296 | break; | ||
297 | default: | ||
298 | stolen_size = 0; | ||
299 | break; | ||
300 | } | ||
301 | |||
302 | return stolen_size; | ||
303 | } | ||
304 | |||
305 | static size_t __init gen6_stolen_size(int num, int slot, int func) | ||
306 | { | ||
307 | u16 gmch_ctrl; | ||
308 | |||
309 | gmch_ctrl = read_pci_config_16(num, slot, func, SNB_GMCH_CTRL); | ||
310 | gmch_ctrl >>= SNB_GMCH_GMS_SHIFT; | ||
311 | gmch_ctrl &= SNB_GMCH_GMS_MASK; | ||
312 | |||
313 | return gmch_ctrl << 25; /* 32 MB units */ | ||
314 | } | ||
315 | |||
316 | typedef size_t (*stolen_size_fn)(int num, int slot, int func); | ||
317 | |||
318 | static struct pci_device_id intel_stolen_ids[] __initdata = { | ||
319 | INTEL_I915G_IDS(gen3_stolen_size), | ||
320 | INTEL_I915GM_IDS(gen3_stolen_size), | ||
321 | INTEL_I945G_IDS(gen3_stolen_size), | ||
322 | INTEL_I945GM_IDS(gen3_stolen_size), | ||
323 | INTEL_VLV_M_IDS(gen3_stolen_size), | ||
324 | INTEL_VLV_D_IDS(gen3_stolen_size), | ||
325 | INTEL_PINEVIEW_IDS(gen3_stolen_size), | ||
326 | INTEL_I965G_IDS(gen3_stolen_size), | ||
327 | INTEL_G33_IDS(gen3_stolen_size), | ||
328 | INTEL_I965GM_IDS(gen3_stolen_size), | ||
329 | INTEL_GM45_IDS(gen3_stolen_size), | ||
330 | INTEL_G45_IDS(gen3_stolen_size), | ||
331 | INTEL_IRONLAKE_D_IDS(gen3_stolen_size), | ||
332 | INTEL_IRONLAKE_M_IDS(gen3_stolen_size), | ||
333 | INTEL_SNB_D_IDS(gen6_stolen_size), | ||
334 | INTEL_SNB_M_IDS(gen6_stolen_size), | ||
335 | INTEL_IVB_M_IDS(gen6_stolen_size), | ||
336 | INTEL_IVB_D_IDS(gen6_stolen_size), | ||
337 | INTEL_HSW_D_IDS(gen6_stolen_size), | ||
338 | INTEL_HSW_M_IDS(gen6_stolen_size), | ||
339 | }; | ||
340 | |||
341 | static void __init intel_graphics_stolen(int num, int slot, int func) | ||
342 | { | ||
343 | size_t size; | ||
344 | int i; | ||
345 | u32 start; | ||
346 | u16 device, subvendor, subdevice; | ||
347 | |||
348 | device = read_pci_config_16(num, slot, func, PCI_DEVICE_ID); | ||
349 | subvendor = read_pci_config_16(num, slot, func, | ||
350 | PCI_SUBSYSTEM_VENDOR_ID); | ||
351 | subdevice = read_pci_config_16(num, slot, func, PCI_SUBSYSTEM_ID); | ||
352 | |||
353 | for (i = 0; i < ARRAY_SIZE(intel_stolen_ids); i++) { | ||
354 | if (intel_stolen_ids[i].device == device) { | ||
355 | stolen_size_fn stolen_size = | ||
356 | (stolen_size_fn)intel_stolen_ids[i].driver_data; | ||
357 | size = stolen_size(num, slot, func); | ||
358 | start = intel_stolen_base(num, slot, func); | ||
359 | if (size && start) { | ||
360 | /* Mark this space as reserved */ | ||
361 | e820_add_region(start, size, E820_RESERVED); | ||
362 | sanitize_e820_map(e820.map, | ||
363 | ARRAY_SIZE(e820.map), | ||
364 | &e820.nr_map); | ||
365 | } | ||
366 | return; | ||
367 | } | ||
368 | } | ||
369 | } | ||
370 | |||
219 | #define QFLAG_APPLY_ONCE 0x1 | 371 | #define QFLAG_APPLY_ONCE 0x1 |
220 | #define QFLAG_APPLIED 0x2 | 372 | #define QFLAG_APPLIED 0x2 |
221 | #define QFLAG_DONE (QFLAG_APPLY_ONCE|QFLAG_APPLIED) | 373 | #define QFLAG_DONE (QFLAG_APPLY_ONCE|QFLAG_APPLIED) |
@@ -251,6 +403,8 @@ static struct chipset early_qrk[] __initdata = { | |||
251 | PCI_BASE_CLASS_BRIDGE, 0, intel_remapping_check }, | 403 | PCI_BASE_CLASS_BRIDGE, 0, intel_remapping_check }, |
252 | { PCI_VENDOR_ID_INTEL, 0x3406, PCI_CLASS_BRIDGE_HOST, | 404 | { PCI_VENDOR_ID_INTEL, 0x3406, PCI_CLASS_BRIDGE_HOST, |
253 | PCI_BASE_CLASS_BRIDGE, 0, intel_remapping_check }, | 405 | PCI_BASE_CLASS_BRIDGE, 0, intel_remapping_check }, |
406 | { PCI_VENDOR_ID_INTEL, PCI_ANY_ID, PCI_CLASS_DISPLAY_VGA, PCI_ANY_ID, | ||
407 | QFLAG_APPLY_ONCE, intel_graphics_stolen }, | ||
254 | {} | 408 | {} |
255 | }; | 409 | }; |
256 | 410 | ||