x86/Sandy Bridge: reserve pages when integrated graphics is present
SNB graphics devices have a bug that prevent them from accessing certain memory ranges, namely anything below 1M and in the pages listed in the table. So reserve those at boot if set detect a SNB gfx device on the CPU to avoid GPU hangs. Stephane Marchesin had a similar patch to the page allocator awhile back, but rather than reserving pages up front, it leaked them at allocation time. [ hpa: made a number of stylistic changes, marked arrays as static const, and made less verbose; use "memblock=debug" for full verbosity. ] Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org> Signed-off-by: H. Peter Anvin <hpa@linux.intel.com>
This commit is contained in:
parent
886d751a2e
commit
a9acc5365d
|
@ -610,6 +610,81 @@ static __init void reserve_ibft_region(void)
|
|||
|
||||
static unsigned reserve_low = CONFIG_X86_RESERVE_LOW << 10;
|
||||
|
||||
static bool __init snb_gfx_workaround_needed(void)
|
||||
{
|
||||
int i;
|
||||
u16 vendor, devid;
|
||||
static const 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;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* Sandy Bridge graphics has trouble with certain ranges, exclude
|
||||
* them from allocation.
|
||||
*/
|
||||
static void __init trim_snb_memory(void)
|
||||
{
|
||||
static const 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 +705,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 +984,8 @@ void __init setup_arch(char **cmdline_p)
|
|||
|
||||
setup_real_mode();
|
||||
|
||||
trim_platform_memory_ranges();
|
||||
|
||||
init_gbpages();
|
||||
|
||||
/* max_pfn_mapped is updated here */
|
||||
|
|
Loading…
Reference in New Issue