@@ -68,8 +68,6 @@ static int __init pat_debug_setup(char *str)
6868}
6969__setup ("debugpat" , pat_debug_setup );
7070
71- static u64 __read_mostly boot_pat_state ;
72-
7371#ifdef CONFIG_X86_PAT
7472/*
7573 * X86 PAT uses page flags WC and Uncached together to keep track of
@@ -177,14 +175,12 @@ static enum page_cache_mode pat_get_cache_mode(unsigned pat_val, char *msg)
177175 * configuration.
178176 * Using lower indices is preferred, so we start with highest index.
179177 */
180- void pat_init_cache_modes (void )
178+ void pat_init_cache_modes (u64 pat )
181179{
182- int i ;
183180 enum page_cache_mode cache ;
184181 char pat_msg [33 ];
185- u64 pat ;
182+ int i ;
186183
187- rdmsrl (MSR_IA32_CR_PAT , pat );
188184 pat_msg [32 ] = 0 ;
189185 for (i = 7 ; i >= 0 ; i -- ) {
190186 cache = pat_get_cache_mode ((pat >> (i * 8 )) & 7 ,
@@ -198,24 +194,33 @@ void pat_init_cache_modes(void)
198194
199195static void pat_bsp_init (u64 pat )
200196{
197+ u64 tmp_pat ;
198+
201199 if (!cpu_has_pat ) {
202200 pat_disable ("PAT not supported by CPU." );
203201 return ;
204202 }
205203
206- rdmsrl (MSR_IA32_CR_PAT , boot_pat_state );
207- if (!boot_pat_state ) {
204+ if (!pat_enabled ())
205+ goto done ;
206+
207+ rdmsrl (MSR_IA32_CR_PAT , tmp_pat );
208+ if (!tmp_pat ) {
208209 pat_disable ("PAT MSR is 0, disabled." );
209210 return ;
210211 }
211212
212213 wrmsrl (MSR_IA32_CR_PAT , pat );
213214
214- pat_init_cache_modes ();
215+ done :
216+ pat_init_cache_modes (pat );
215217}
216218
217219static void pat_ap_init (u64 pat )
218220{
221+ if (!pat_enabled ())
222+ return ;
223+
219224 if (!cpu_has_pat ) {
220225 /*
221226 * If this happens we are on a secondary CPU, but switched to
@@ -231,25 +236,45 @@ void pat_init(void)
231236{
232237 u64 pat ;
233238
234- if (!pat_enabled ())
235- return ;
236-
237- /*
238- * Set PWT to Write-Combining. All other bits stay the same:
239- *
240- * PTE encoding used in Linux:
241- * PAT
242- * |PCD
243- * ||PWT
244- * |||
245- * 000 WB _PAGE_CACHE_WB
246- * 001 WC _PAGE_CACHE_WC
247- * 010 UC- _PAGE_CACHE_UC_MINUS
248- * 011 UC _PAGE_CACHE_UC
249- * PAT bit unused
250- */
251- pat = PAT (0 , WB ) | PAT (1 , WC ) | PAT (2 , UC_MINUS ) | PAT (3 , UC ) |
252- PAT (4 , WB ) | PAT (5 , WC ) | PAT (6 , UC_MINUS ) | PAT (7 , UC );
239+ if (!pat_enabled ()) {
240+ /*
241+ * No PAT. Emulate the PAT table that corresponds to the two
242+ * cache bits, PWT (Write Through) and PCD (Cache Disable). This
243+ * setup is the same as the BIOS default setup when the system
244+ * has PAT but the "nopat" boot option has been specified. This
245+ * emulated PAT table is used when MSR_IA32_CR_PAT returns 0.
246+ *
247+ * PTE encoding used:
248+ *
249+ * PCD
250+ * |PWT PAT
251+ * || slot
252+ * 00 0 WB : _PAGE_CACHE_MODE_WB
253+ * 01 1 WT : _PAGE_CACHE_MODE_WT
254+ * 10 2 UC-: _PAGE_CACHE_MODE_UC_MINUS
255+ * 11 3 UC : _PAGE_CACHE_MODE_UC
256+ *
257+ * NOTE: When WC or WP is used, it is redirected to UC- per
258+ * the default setup in __cachemode2pte_tbl[].
259+ */
260+ pat = PAT (0 , WB ) | PAT (1 , WT ) | PAT (2 , UC_MINUS ) | PAT (3 , UC ) |
261+ PAT (4 , WB ) | PAT (5 , WT ) | PAT (6 , UC_MINUS ) | PAT (7 , UC );
262+ } else {
263+ /*
264+ * PTE encoding used in Linux:
265+ * PAT
266+ * |PCD
267+ * ||PWT
268+ * |||
269+ * 000 WB _PAGE_CACHE_WB
270+ * 001 WC _PAGE_CACHE_WC
271+ * 010 UC- _PAGE_CACHE_UC_MINUS
272+ * 011 UC _PAGE_CACHE_UC
273+ * PAT bit unused
274+ */
275+ pat = PAT (0 , WB ) | PAT (1 , WC ) | PAT (2 , UC_MINUS ) | PAT (3 , UC ) |
276+ PAT (4 , WB ) | PAT (5 , WC ) | PAT (6 , UC_MINUS ) | PAT (7 , UC );
277+ }
253278
254279 if (!boot_cpu_done ) {
255280 pat_bsp_init (pat );
0 commit comments