Commit 282c454c authored by Venki Pallipadi's avatar Venki Pallipadi Committed by Thomas Gleixner

x86: fix Xorg crash with xf86MapVidMem error

Clarify the usage of mtrr_lookup() in PAT code, and to make PAT code
resilient to mtrr lookup problems.

Specifically, pat_x_mtrr_type() is restructured to highlight, under what
conditions we look for mtrr hint. pat_x_mtrr_type() uses a default type
when there are any errors in mtrr lookup (still maintaining the pat
consistency). And, reserve_memtype() highlights its usage ot mtrr_lookup
for request type of '-1' and also defaults in a sane way on any mtrr
lookup failure.

pat.c looks at mtrr type of a range to get a hint on what mapping type
to request when user/API: (1) hasn't specified any type (/dev/mem
mapping) and we do not want to take performance hit by always mapping
UC_MINUS. This will be the case for /dev/mem mappings used to map BIOS
area or ACPI region which are WB'able. In this case, as long as MTRR is
not WB, PAT will request UC_MINUS for such mappings.

(2) user/API requests WB mapping while in reality MTRR may have UC or
WC. In this case, PAT can map as WB (without checking MTRR) and still
effective type will be UC or WC. But, a subsequent request to map same
region as UC or WC may fail, as the region will get trackked as WB in
PAT list. Looking at MTRR hint helps us to track based on effective type
rather than what user requested. Again, here mtrr_lookup is only used as
hint and we fallback to WB mapping (as requested by user) as default.

In both cases, after using the mtrr hint, we still go through the
memtype list to make sure there are no inconsistencies among multiple
users.
Signed-off-by: default avatarVenkatesh Pallipadi <venkatesh.pallipadi@intel.com>
Signed-off-by: default avatarSuresh Siddha <suresh.b.siddha@intel.com>
Tested-by: default avatarRufus &amp; Azrael <rufus-azrael@numericable.fr>
Signed-off-by: default avatarIngo Molnar <mingo@elte.hu>
parent 51163101
...@@ -151,32 +151,33 @@ static int pat_x_mtrr_type(u64 start, u64 end, unsigned long prot, ...@@ -151,32 +151,33 @@ static int pat_x_mtrr_type(u64 start, u64 end, unsigned long prot,
unsigned long pat_type; unsigned long pat_type;
u8 mtrr_type; u8 mtrr_type;
mtrr_type = mtrr_type_lookup(start, end);
if (mtrr_type == 0xFF) { /* MTRR not enabled */
*ret_prot = prot;
return 0;
}
if (mtrr_type == 0xFE) { /* MTRR match error */
*ret_prot = _PAGE_CACHE_UC;
return -1;
}
if (mtrr_type != MTRR_TYPE_UNCACHABLE &&
mtrr_type != MTRR_TYPE_WRBACK &&
mtrr_type != MTRR_TYPE_WRCOMB) { /* MTRR type unhandled */
*ret_prot = _PAGE_CACHE_UC;
return -1;
}
pat_type = prot & _PAGE_CACHE_MASK; pat_type = prot & _PAGE_CACHE_MASK;
prot &= (~_PAGE_CACHE_MASK); prot &= (~_PAGE_CACHE_MASK);
/* Currently doing intersection by hand. Optimize it later. */ /*
* We return the PAT request directly for types where PAT takes
* precedence with respect to MTRR and for UC_MINUS.
* Consistency checks with other PAT requests is done later
* while going through memtype list.
*/
if (pat_type == _PAGE_CACHE_WC) { if (pat_type == _PAGE_CACHE_WC) {
*ret_prot = prot | _PAGE_CACHE_WC; *ret_prot = prot | _PAGE_CACHE_WC;
return 0;
} else if (pat_type == _PAGE_CACHE_UC_MINUS) { } else if (pat_type == _PAGE_CACHE_UC_MINUS) {
*ret_prot = prot | _PAGE_CACHE_UC_MINUS; *ret_prot = prot | _PAGE_CACHE_UC_MINUS;
} else if (pat_type == _PAGE_CACHE_UC || return 0;
mtrr_type == MTRR_TYPE_UNCACHABLE) { } else if (pat_type == _PAGE_CACHE_UC) {
*ret_prot = prot | _PAGE_CACHE_UC;
return 0;
}
/*
* Look for MTRR hint to get the effective type in case where PAT
* request is for WB.
*/
mtrr_type = mtrr_type_lookup(start, end);
if (mtrr_type == MTRR_TYPE_UNCACHABLE) {
*ret_prot = prot | _PAGE_CACHE_UC; *ret_prot = prot | _PAGE_CACHE_UC;
} else if (mtrr_type == MTRR_TYPE_WRCOMB) { } else if (mtrr_type == MTRR_TYPE_WRCOMB) {
*ret_prot = prot | _PAGE_CACHE_WC; *ret_prot = prot | _PAGE_CACHE_WC;
...@@ -233,14 +234,12 @@ int reserve_memtype(u64 start, u64 end, unsigned long req_type, ...@@ -233,14 +234,12 @@ int reserve_memtype(u64 start, u64 end, unsigned long req_type,
if (req_type == -1) { if (req_type == -1) {
/* /*
* Special case where caller wants to inherit from mtrr or * Call mtrr_lookup to get the type hint. This is an
* existing pat mapping, defaulting to UC_MINUS in case of * optimization for /dev/mem mmap'ers into WB memory (BIOS
* no match. * tools and ACPI tools). Use WB request for WB memory and use
* UC_MINUS otherwise.
*/ */
u8 mtrr_type = mtrr_type_lookup(start, end); u8 mtrr_type = mtrr_type_lookup(start, end);
if (mtrr_type == 0xFE) { /* MTRR match error */
err = -1;
}
if (mtrr_type == MTRR_TYPE_WRBACK) { if (mtrr_type == MTRR_TYPE_WRBACK) {
req_type = _PAGE_CACHE_WB; req_type = _PAGE_CACHE_WB;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment