diff options
Diffstat (limited to 'arch/x86/kernel/setup.c')
| -rw-r--r-- | arch/x86/kernel/setup.c | 80 | 
1 files changed, 80 insertions, 0 deletions
diff --git a/arch/x86/kernel/setup.c b/arch/x86/kernel/setup.c index 23ddd558fbd..00f6c1472b8 100644 --- a/arch/x86/kernel/setup.c +++ b/arch/x86/kernel/setup.c @@ -610,6 +610,83 @@ static __init void reserve_ibft_region(void)  static unsigned reserve_low = CONFIG_X86_RESERVE_LOW << 10; +static bool __init snb_gfx_workaround_needed(void) +{ +#ifdef CONFIG_PCI +	int i; +	u16 vendor, devid; +	static const __initconst u16 snb_ids[] = { +		0x0102, +		0x0112, +		0x0122, +		0x0106, +		0x0116, +		0x0126, +		0x010a, +	}; + +	/* Assume no if something weird is going on with PCI */ +	if (!early_pci_allowed()) +		return false; + +	vendor = read_pci_config_16(0, 2, 0, PCI_VENDOR_ID); +	if (vendor != 0x8086) +		return false; + +	devid = read_pci_config_16(0, 2, 0, PCI_DEVICE_ID); +	for (i = 0; i < ARRAY_SIZE(snb_ids); i++) +		if (devid == snb_ids[i]) +			return true; +#endif + +	return false; +} + +/* + * Sandy Bridge graphics has trouble with certain ranges, exclude + * them from allocation. + */ +static void __init trim_snb_memory(void) +{ +	static const __initconst unsigned long bad_pages[] = { +		0x20050000, +		0x20110000, +		0x20130000, +		0x20138000, +		0x40004000, +	}; +	int i; + +	if (!snb_gfx_workaround_needed()) +		return; + +	printk(KERN_DEBUG "reserving inaccessible SNB gfx pages\n"); + +	/* +	 * Reserve all memory below the 1 MB mark that has not +	 * already been reserved. +	 */ +	memblock_reserve(0, 1<<20); +	 +	for (i = 0; i < ARRAY_SIZE(bad_pages); i++) { +		if (memblock_reserve(bad_pages[i], PAGE_SIZE)) +			printk(KERN_WARNING "failed to reserve 0x%08lx\n", +			       bad_pages[i]); +	} +} + +/* + * Here we put platform-specific memory range workarounds, i.e. + * memory known to be corrupt or otherwise in need to be reserved on + * specific platforms. + * + * If this gets used more widely it could use a real dispatch mechanism. + */ +static void __init trim_platform_memory_ranges(void) +{ +	trim_snb_memory(); +} +  static void __init trim_bios_range(void)  {  	/* @@ -630,6 +707,7 @@ static void __init trim_bios_range(void)  	 * take them out.  	 */  	e820_remove_range(BIOS_BEGIN, BIOS_END - BIOS_BEGIN, E820_RAM, 1); +  	sanitize_e820_map(e820.map, ARRAY_SIZE(e820.map), &e820.nr_map);  } @@ -908,6 +986,8 @@ void __init setup_arch(char **cmdline_p)  	setup_real_mode(); +	trim_platform_memory_ranges(); +  	init_gbpages();  	/* max_pfn_mapped is updated here */  |