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 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)
|
static void __init trim_bios_range(void)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
@ -630,6 +705,7 @@ static void __init trim_bios_range(void)
|
|||||||
* take them out.
|
* take them out.
|
||||||
*/
|
*/
|
||||||
e820_remove_range(BIOS_BEGIN, BIOS_END - BIOS_BEGIN, E820_RAM, 1);
|
e820_remove_range(BIOS_BEGIN, BIOS_END - BIOS_BEGIN, E820_RAM, 1);
|
||||||
|
|
||||||
sanitize_e820_map(e820.map, ARRAY_SIZE(e820.map), &e820.nr_map);
|
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();
|
setup_real_mode();
|
||||||
|
|
||||||
|
trim_platform_memory_ranges();
|
||||||
|
|
||||||
init_gbpages();
|
init_gbpages();
|
||||||
|
|
||||||
/* max_pfn_mapped is updated here */
|
/* max_pfn_mapped is updated here */
|
||||||
|
Loading…
Reference in New Issue
Block a user