@@ -68,8 +68,6 @@ static int __init pat_debug_setup(char *str)
68
68
}
69
69
__setup ("debugpat" , pat_debug_setup );
70
70
71
- static u64 __read_mostly boot_pat_state ;
72
-
73
71
#ifdef CONFIG_X86_PAT
74
72
/*
75
73
* 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)
177
175
* configuration.
178
176
* Using lower indices is preferred, so we start with highest index.
179
177
*/
180
- void pat_init_cache_modes (void )
178
+ void pat_init_cache_modes (u64 pat )
181
179
{
182
- int i ;
183
180
enum page_cache_mode cache ;
184
181
char pat_msg [33 ];
185
- u64 pat ;
182
+ int i ;
186
183
187
- rdmsrl (MSR_IA32_CR_PAT , pat );
188
184
pat_msg [32 ] = 0 ;
189
185
for (i = 7 ; i >= 0 ; i -- ) {
190
186
cache = pat_get_cache_mode ((pat >> (i * 8 )) & 7 ,
@@ -198,24 +194,33 @@ void pat_init_cache_modes(void)
198
194
199
195
static void pat_bsp_init (u64 pat )
200
196
{
197
+ u64 tmp_pat ;
198
+
201
199
if (!cpu_has_pat ) {
202
200
pat_disable ("PAT not supported by CPU." );
203
201
return ;
204
202
}
205
203
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 ) {
208
209
pat_disable ("PAT MSR is 0, disabled." );
209
210
return ;
210
211
}
211
212
212
213
wrmsrl (MSR_IA32_CR_PAT , pat );
213
214
214
- pat_init_cache_modes ();
215
+ done :
216
+ pat_init_cache_modes (pat );
215
217
}
216
218
217
219
static void pat_ap_init (u64 pat )
218
220
{
221
+ if (!pat_enabled ())
222
+ return ;
223
+
219
224
if (!cpu_has_pat ) {
220
225
/*
221
226
* If this happens we are on a secondary CPU, but switched to
@@ -231,25 +236,45 @@ void pat_init(void)
231
236
{
232
237
u64 pat ;
233
238
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
+ }
253
278
254
279
if (!boot_cpu_done ) {
255
280
pat_bsp_init (pat );
0 commit comments