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: Venkatesh Pallipadi <venkatesh.pallipadi@intel.com>
Signed-off-by: Suresh Siddha <suresh.b.siddha@intel.com>
Tested-by: Rufus & Azrael <rufus-azrael@numericable.fr>
Signed-off-by: Ingo Molnar <mingo@elte.hu>

authored by Venki Pallipadi and committed by Thomas Gleixner 282c454c 51163101

+24 -25
+24 -25
arch/x86/mm/pat.c
··· 151 unsigned long pat_type; 152 u8 mtrr_type; 153 154 - mtrr_type = mtrr_type_lookup(start, end); 155 - if (mtrr_type == 0xFF) { /* MTRR not enabled */ 156 - *ret_prot = prot; 157 - return 0; 158 - } 159 - if (mtrr_type == 0xFE) { /* MTRR match error */ 160 - *ret_prot = _PAGE_CACHE_UC; 161 - return -1; 162 - } 163 - if (mtrr_type != MTRR_TYPE_UNCACHABLE && 164 - mtrr_type != MTRR_TYPE_WRBACK && 165 - mtrr_type != MTRR_TYPE_WRCOMB) { /* MTRR type unhandled */ 166 - *ret_prot = _PAGE_CACHE_UC; 167 - return -1; 168 - } 169 - 170 pat_type = prot & _PAGE_CACHE_MASK; 171 prot &= (~_PAGE_CACHE_MASK); 172 173 - /* Currently doing intersection by hand. Optimize it later. */ 174 if (pat_type == _PAGE_CACHE_WC) { 175 *ret_prot = prot | _PAGE_CACHE_WC; 176 } else if (pat_type == _PAGE_CACHE_UC_MINUS) { 177 *ret_prot = prot | _PAGE_CACHE_UC_MINUS; 178 - } else if (pat_type == _PAGE_CACHE_UC || 179 - mtrr_type == MTRR_TYPE_UNCACHABLE) { 180 *ret_prot = prot | _PAGE_CACHE_UC; 181 } else if (mtrr_type == MTRR_TYPE_WRCOMB) { 182 *ret_prot = prot | _PAGE_CACHE_WC; ··· 234 235 if (req_type == -1) { 236 /* 237 - * Special case where caller wants to inherit from mtrr or 238 - * existing pat mapping, defaulting to UC_MINUS in case of 239 - * no match. 240 */ 241 u8 mtrr_type = mtrr_type_lookup(start, end); 242 - if (mtrr_type == 0xFE) { /* MTRR match error */ 243 - err = -1; 244 - } 245 246 if (mtrr_type == MTRR_TYPE_WRBACK) { 247 req_type = _PAGE_CACHE_WB;
··· 151 unsigned long pat_type; 152 u8 mtrr_type; 153 154 pat_type = prot & _PAGE_CACHE_MASK; 155 prot &= (~_PAGE_CACHE_MASK); 156 157 + /* 158 + * We return the PAT request directly for types where PAT takes 159 + * precedence with respect to MTRR and for UC_MINUS. 160 + * Consistency checks with other PAT requests is done later 161 + * while going through memtype list. 162 + */ 163 if (pat_type == _PAGE_CACHE_WC) { 164 *ret_prot = prot | _PAGE_CACHE_WC; 165 + return 0; 166 } else if (pat_type == _PAGE_CACHE_UC_MINUS) { 167 *ret_prot = prot | _PAGE_CACHE_UC_MINUS; 168 + return 0; 169 + } else if (pat_type == _PAGE_CACHE_UC) { 170 + *ret_prot = prot | _PAGE_CACHE_UC; 171 + return 0; 172 + } 173 + 174 + /* 175 + * Look for MTRR hint to get the effective type in case where PAT 176 + * request is for WB. 177 + */ 178 + mtrr_type = mtrr_type_lookup(start, end); 179 + 180 + if (mtrr_type == MTRR_TYPE_UNCACHABLE) { 181 *ret_prot = prot | _PAGE_CACHE_UC; 182 } else if (mtrr_type == MTRR_TYPE_WRCOMB) { 183 *ret_prot = prot | _PAGE_CACHE_WC; ··· 233 234 if (req_type == -1) { 235 /* 236 + * Call mtrr_lookup to get the type hint. This is an 237 + * optimization for /dev/mem mmap'ers into WB memory (BIOS 238 + * tools and ACPI tools). Use WB request for WB memory and use 239 + * UC_MINUS otherwise. 240 */ 241 u8 mtrr_type = mtrr_type_lookup(start, end); 242 243 if (mtrr_type == MTRR_TYPE_WRBACK) { 244 req_type = _PAGE_CACHE_WB;