Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit f0348c43 authored by Yinghai Lu's avatar Yinghai Lu Committed by Ingo Molnar
Browse files

x86: MTRR workaround for system with stange var MTRRs



Impact: don't trim e820 according to wrong mtrr

Ozan reports that his server emits strange warning.
it turns out the BIOS sets the MTRRs incorrectly.

Ignore those strange ranges, and don't trim e820,
just emit one warning about BIOS

Reported-by: default avatarOzan Çağlayan <ozan@pardus.org.tr>
Signed-off-by: default avatarYinghai Lu <yinghai@kernel.org>
LKML-Reference: <49BEE1E7.7020706@kernel.org>
Signed-off-by: default avatarIngo Molnar <mingo@elte.hu>
parent d4c90e37
Loading
Loading
Loading
Loading
+11 −0
Original line number Diff line number Diff line
@@ -189,6 +189,17 @@ x86_get_mtrr_mem_range(struct res_range *range, int nr_range,
		if (!size)
			continue;
		base = range_state[i].base_pfn;
		if (base < (1<<(20-PAGE_SHIFT)) && mtrr_state.have_fixed &&
		    (mtrr_state.enabled & 1)) {
			/* Var MTRR contains UC entry below 1M? Skip it: */
			printk(KERN_WARNING "WARNING: BIOS bug: VAR MTRR %d "
				"contains strange UC entry under 1M, check "
				"with your system vendor!\n", i);
			if (base + size <= (1<<(20-PAGE_SHIFT)))
				continue;
			size -= (1<<(20-PAGE_SHIFT)) - base;
			base = 1<<(20-PAGE_SHIFT);
		}
		subtract_range(range, base, base + size - 1);
	}
	if (extra_remove_size)
+8 −8
Original line number Diff line number Diff line
@@ -574,7 +574,7 @@ struct mtrr_value {
	unsigned long	lsize;
};

static struct mtrr_value mtrr_state[MTRR_MAX_VAR_RANGES];
static struct mtrr_value mtrr_value[MTRR_MAX_VAR_RANGES];

static int mtrr_save(struct sys_device * sysdev, pm_message_t state)
{
@@ -582,9 +582,9 @@ static int mtrr_save(struct sys_device * sysdev, pm_message_t state)

	for (i = 0; i < num_var_ranges; i++) {
		mtrr_if->get(i,
			     &mtrr_state[i].lbase,
			     &mtrr_state[i].lsize,
			     &mtrr_state[i].ltype);
			     &mtrr_value[i].lbase,
			     &mtrr_value[i].lsize,
			     &mtrr_value[i].ltype);
	}
	return 0;
}
@@ -594,11 +594,11 @@ static int mtrr_restore(struct sys_device * sysdev)
	int i;

	for (i = 0; i < num_var_ranges; i++) {
		if (mtrr_state[i].lsize) 
		if (mtrr_value[i].lsize)
			set_mtrr(i,
				 mtrr_state[i].lbase,
				 mtrr_state[i].lsize,
				 mtrr_state[i].ltype);
				 mtrr_value[i].lbase,
				 mtrr_value[i].lsize,
				 mtrr_value[i].ltype);
	}
	return 0;
}
+1 −0
Original line number Diff line number Diff line
@@ -79,6 +79,7 @@ extern struct mtrr_ops * mtrr_if;

extern unsigned int num_var_ranges;
extern u64 mtrr_tom2;
extern struct mtrr_state_type mtrr_state;

void mtrr_state_warn(void);
const char *mtrr_attrib_to_str(int x);