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 151 unsigned long pat_type; 152 152 u8 mtrr_type; 153 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 154 pat_type = prot & _PAGE_CACHE_MASK; 171 155 prot &= (~_PAGE_CACHE_MASK); 172 156 173 - /* Currently doing intersection by hand. Optimize it later. */ 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 + */ 174 163 if (pat_type == _PAGE_CACHE_WC) { 175 164 *ret_prot = prot | _PAGE_CACHE_WC; 165 + return 0; 176 166 } else if (pat_type == _PAGE_CACHE_UC_MINUS) { 177 167 *ret_prot = prot | _PAGE_CACHE_UC_MINUS; 178 - } else if (pat_type == _PAGE_CACHE_UC || 179 - mtrr_type == MTRR_TYPE_UNCACHABLE) { 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) { 180 181 *ret_prot = prot | _PAGE_CACHE_UC; 181 182 } else if (mtrr_type == MTRR_TYPE_WRCOMB) { 182 183 *ret_prot = prot | _PAGE_CACHE_WC; ··· 234 233 235 234 if (req_type == -1) { 236 235 /* 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. 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 240 */ 241 241 u8 mtrr_type = mtrr_type_lookup(start, end); 242 - if (mtrr_type == 0xFE) { /* MTRR match error */ 243 - err = -1; 244 - } 245 242 246 243 if (mtrr_type == MTRR_TYPE_WRBACK) { 247 244 req_type = _PAGE_CACHE_WB;