diff --git a/arch/i386/kernel/cpu/mtrr/main.c b/arch/i386/kernel/cpu/mtrr/main.c index 1cf466d..45113d5 100644 --- a/arch/i386/kernel/cpu/mtrr/main.c +++ b/arch/i386/kernel/cpu/mtrr/main.c @@ -631,6 +631,70 @@ static struct sysdev_driver mtrr_sysdev_driver = { .resume = mtrr_restore, }; +/** + * mtrr_page_wb - check if a given page is marked WB in an MTRR range + * @page: page to check + * + * See if @page is marked as WB in an MTRR, assuming the default non-MTRR + * covered memory is marked uncached. + * + * RETURNS + * + * True if page is marked WB, false otherwise. + */ +static bool __init mtrr_page_wb(struct page *page) +{ + struct mtrr_value mtrr; + int i, wb = 0; + + /* FIXME: check fixed ranges too? */ + for (i = 0; i < num_var_ranges; i++) { + mtrr_if->get(i, &mtrr.lbase, &mtrr.lsize, &mtrr.ltype); + + /* Is the page in the current MTRR range? */ + if (page_to_phys(page) + PAGE_SIZE <= mtrr.lbase + mtrr.lsize && + page_to_phys(page) >= mtrr.lbase) { + /* Ok, now check the memory type... */ + if (mtrr.ltype == MTRR_TYPE_WRBACK) + wb = 1; + else + return false; + } + } + + /* Assume if we didn't find a matching MTRR, it must be uncached */ + return wb; +} + +/** + * verify_mtrr_ranges - check MTRRs against memory map + * + * Make sure MTRR WB ranges match our memory map. If they don't, disable + * any memory marked uncached that should be WB and warn the user. + */ +static void __init verify_mtrr_ranges(void) +{ + pg_data_t *pgdat; + int i, pages_disabled = 0; + + printk(KERN_ERR "Verifying MTRR ranges against memory map\n"); + + for_each_online_pgdat(pgdat) + for (i = 0; i < pgdat->node_present_pages; i++) { + struct page *page = pgdat_page_nr(pgdat, i); + if (!mtrr_page_wb(page)) { + pages_disabled++; + SetPageReserved(page); + } + } + + if (pages_disabled) { + printk(KERN_WARNING "MTRRs don't cover all of RAM, removing " + "%dk from available memory\n", + pages_disabled << PAGE_SHIFT); + msleep(100000); + } +} /** * mtrr_bp_init - initialize mtrrs on the boot CPU @@ -705,6 +769,7 @@ void mtrr_bp_init(void) init_table(); if (use_intel()) get_mtrr_state(); + verify_mtrr_ranges(); } }