blob: 74aae64a8963fe1852509968edaf66e713ce83c6 [file] [log] [blame]
Eric Biedermanfcd5ace2004-10-14 19:29:29 +00001/*
Stefan Reinauercdc5cc62007-04-24 18:40:02 +00002 * mtrr.c: setting MTRR to decent values for cache initialization on P6
Eric Biedermanfcd5ace2004-10-14 19:29:29 +00003 *
4 * Derived from intel_set_mtrr in intel_subr.c and mtrr.c in linux kernel
5 *
6 * Copyright 2000 Silicon Integrated System Corporation
Aaron Durbinbb4e79a2013-03-26 14:09:47 -05007 * Copyright 2013 Google Inc.
Eric Biedermanfcd5ace2004-10-14 19:29:29 +00008 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 *
23 *
24 * Reference: Intel Architecture Software Developer's Manual, Volume 3: System Programming
25 */
Yinghai Lu13f1c2a2005-07-08 02:49:49 +000026
Eric Biedermanf8a2ddd2004-10-30 08:05:41 +000027#include <stddef.h>
Aaron Durbinbb4e79a2013-03-26 14:09:47 -050028#include <stdlib.h>
29#include <string.h>
Eric Biedermanfcd5ace2004-10-14 19:29:29 +000030#include <console/console.h>
31#include <device/device.h>
32#include <cpu/x86/msr.h>
33#include <cpu/x86/mtrr.h>
34#include <cpu/x86/cache.h>
Stefan Reinauer00093a82011-11-02 16:12:34 -070035#include <cpu/x86/lapic.h>
Sven Schnelleadfbcb792012-01-10 12:01:43 +010036#include <arch/cpu.h>
Stefan Reinauer00093a82011-11-02 16:12:34 -070037#include <arch/acpi.h>
Aaron Durbinbb4e79a2013-03-26 14:09:47 -050038#include <memrange.h>
Aaron Durbin57686f82013-03-20 15:50:59 -050039#if CONFIG_X86_AMD_FIXED_MTRRS
40#include <cpu/amd/mtrr.h>
41#define MTRR_FIXED_WRBACK_BITS (MTRR_READ_MEM | MTRR_WRITE_MEM)
42#else
43#define MTRR_FIXED_WRBACK_BITS 0
44#endif
Eric Biedermanfcd5ace2004-10-14 19:29:29 +000045
Stefan Reinauerc00dfbc2012-04-03 16:24:37 -070046/* 2 MTRRS are reserved for the operating system */
47#define BIOS_MTRRS 6
48#define OS_MTRRS 2
49#define MTRRS (BIOS_MTRRS + OS_MTRRS)
50
51static int total_mtrrs = MTRRS;
52static int bios_mtrrs = BIOS_MTRRS;
53
54static void detect_var_mtrrs(void)
55{
56 msr_t msr;
57
58 msr = rdmsr(MTRRcap_MSR);
59
60 total_mtrrs = msr.lo & 0xff;
61 bios_mtrrs = total_mtrrs - OS_MTRRS;
62}
63
Yinghai Lu13f1c2a2005-07-08 02:49:49 +000064void enable_fixed_mtrr(void)
Eric Biedermanfcd5ace2004-10-14 19:29:29 +000065{
66 msr_t msr;
67
68 msr = rdmsr(MTRRdefType_MSR);
Aaron Durbinbb4e79a2013-03-26 14:09:47 -050069 msr.lo |= MTRRdefTypeEn | MTRRdefTypeFixEn;
Eric Biedermanfcd5ace2004-10-14 19:29:29 +000070 wrmsr(MTRRdefType_MSR, msr);
71}
72
Aaron Durbinbb4e79a2013-03-26 14:09:47 -050073static void enable_var_mtrr(unsigned char deftype)
Eric Biedermanfcd5ace2004-10-14 19:29:29 +000074{
75 msr_t msr;
76
77 msr = rdmsr(MTRRdefType_MSR);
Aaron Durbinbb4e79a2013-03-26 14:09:47 -050078 msr.lo &= ~0xff;
79 msr.lo |= MTRRdefTypeEn | deftype;
Eric Biedermanfcd5ace2004-10-14 19:29:29 +000080 wrmsr(MTRRdefType_MSR, msr);
81}
82
Eric Biedermanfcd5ace2004-10-14 19:29:29 +000083/* fms: find most sigificant bit set, stolen from Linux Kernel Source. */
84static inline unsigned int fms(unsigned int x)
85{
86 int r;
87
88 __asm__("bsrl %1,%0\n\t"
89 "jnz 1f\n\t"
90 "movl $0,%0\n"
91 "1:" : "=r" (r) : "g" (x));
92 return r;
93}
94
Marc Jones5cbdc1e2009-04-01 22:07:53 +000095/* fls: find least sigificant bit set */
Eric Biedermanfcd5ace2004-10-14 19:29:29 +000096static inline unsigned int fls(unsigned int x)
97{
98 int r;
99
100 __asm__("bsfl %1,%0\n\t"
101 "jnz 1f\n\t"
102 "movl $32,%0\n"
103 "1:" : "=r" (r) : "g" (x));
104 return r;
105}
106
Aaron Durbinbb4e79a2013-03-26 14:09:47 -0500107#define MTRR_VERBOSE_LEVEL BIOS_NEVER
Eric Biedermanfcd5ace2004-10-14 19:29:29 +0000108
Aaron Durbinbb4e79a2013-03-26 14:09:47 -0500109/* MTRRs are at a 4KiB granularity. Therefore all address calculations can
110 * be done with 32-bit numbers. This allows for the MTRR code to handle
111 * up to 2^44 bytes (16 TiB) of address space. */
112#define RANGE_SHIFT 12
113#define ADDR_SHIFT_TO_RANGE_SHIFT(x) \
114 (((x) > RANGE_SHIFT) ? ((x) - RANGE_SHIFT) : RANGE_SHIFT)
115#define PHYS_TO_RANGE_ADDR(x) ((x) >> RANGE_SHIFT)
116#define RANGE_TO_PHYS_ADDR(x) (((resource_t)(x)) << RANGE_SHIFT)
117#define NUM_FIXED_MTRRS (NUM_FIXED_RANGES / RANGES_PER_FIXED_MTRR)
118
119/* The minimum alignment while handling variable MTRR ranges is 64MiB. */
120#define MTRR_MIN_ALIGN PHYS_TO_RANGE_ADDR(64 << 20)
121/* Helpful constants. */
122#define RANGE_1MB PHYS_TO_RANGE_ADDR(1 << 20)
123#define RANGE_4GB (1 << (ADDR_SHIFT_TO_RANGE_SHIFT(32)))
124
125static inline uint32_t range_entry_base_mtrr_addr(struct range_entry *r)
Eric Biedermanfcd5ace2004-10-14 19:29:29 +0000126{
Aaron Durbinbb4e79a2013-03-26 14:09:47 -0500127 return PHYS_TO_RANGE_ADDR(range_entry_base(r));
Eric Biedermanfcd5ace2004-10-14 19:29:29 +0000128}
129
Aaron Durbinbb4e79a2013-03-26 14:09:47 -0500130static inline uint32_t range_entry_end_mtrr_addr(struct range_entry *r)
Eric Biedermanfcd5ace2004-10-14 19:29:29 +0000131{
Aaron Durbinbb4e79a2013-03-26 14:09:47 -0500132 return PHYS_TO_RANGE_ADDR(range_entry_end(r));
Eric Biedermanfcd5ace2004-10-14 19:29:29 +0000133}
134
Aaron Durbinbb4e79a2013-03-26 14:09:47 -0500135static struct memranges *get_physical_address_space(void)
Eric Biedermanfcd5ace2004-10-14 19:29:29 +0000136{
Aaron Durbinbb4e79a2013-03-26 14:09:47 -0500137 static struct memranges *addr_space;
138 static struct memranges addr_space_storage;
Duncan Laurie7389fa92011-12-22 10:59:40 -0800139
Aaron Durbinbb4e79a2013-03-26 14:09:47 -0500140 /* In order to handle some chipsets not being able to pre-determine
141 * uncacheable ranges, such as graphics memory, at resource inseration
142 * time remove unacheable regions from the cacheable ones. */
143 if (addr_space == NULL) {
144 struct range_entry *r;
Aaron Durbin9b027fe2013-03-26 14:10:34 -0500145 unsigned long mask;
146 unsigned long match;
Aaron Durbinbb4e79a2013-03-26 14:09:47 -0500147
148 addr_space = &addr_space_storage;
149
Aaron Durbin9b027fe2013-03-26 14:10:34 -0500150 mask = IORESOURCE_CACHEABLE;
Aaron Durbinbb4e79a2013-03-26 14:09:47 -0500151 /* Collect cacheable and uncacheable address ranges. The
152 * uncacheable regions take precedence over the cacheable
153 * regions. */
154 memranges_init(addr_space, mask, mask, MTRR_TYPE_WRBACK);
155 memranges_add_resources(addr_space, mask, 0,
156 MTRR_TYPE_UNCACHEABLE);
157
Aaron Durbin9b027fe2013-03-26 14:10:34 -0500158 /* Handle any write combining resources. Only prefetchable
159 * resources with the IORESOURCE_WRCOMB flag are appropriate
160 * for this MTRR type. */
161 match = IORESOURCE_PREFETCH | IORESOURCE_WRCOMB;
162 mask |= match;
163 memranges_add_resources(addr_space, mask, match,
164 MTRR_TYPE_WRCOMB);
165
Aaron Durbinbb4e79a2013-03-26 14:09:47 -0500166 /* The address space below 4GiB is special. It needs to be
167 * covered entirly by range entries so that MTRR calculations
168 * can be properly done for the full 32-bit address space.
169 * Therefore, ensure holes are filled up to 4GiB as
170 * uncacheable */
171 memranges_fill_holes_up_to(addr_space,
172 RANGE_TO_PHYS_ADDR(RANGE_4GB),
173 MTRR_TYPE_UNCACHEABLE);
174
175 printk(BIOS_DEBUG, "MTRR: Physical address space:\n");
176 memranges_each_entry(r, addr_space)
177 printk(BIOS_DEBUG,
178 "0x%016llx - 0x%016llx size 0x%08llx type %ld\n",
179 range_entry_base(r), range_entry_end(r),
180 range_entry_size(r), range_entry_tag(r));
Carl-Daniel Hailfinger7dde1da2009-02-11 16:57:32 +0000181 }
Stefan Reinauer7f86ed12009-02-12 16:02:16 +0000182
Aaron Durbinbb4e79a2013-03-26 14:09:47 -0500183 return addr_space;
Eric Biedermanfcd5ace2004-10-14 19:29:29 +0000184}
185
Aaron Durbinbb4e79a2013-03-26 14:09:47 -0500186/* Fixed MTRR descriptor. This structure defines the step size and begin
187 * and end (exclusive) address covered by a set of fixe MTRR MSRs.
188 * It also describes the offset in byte intervals to store the calculated MTRR
189 * type in an array. */
190struct fixed_mtrr_desc {
191 uint32_t begin;
192 uint32_t end;
193 uint32_t step;
194 int range_index;
195 int msr_index_base;
Eric Biedermanf8a2ddd2004-10-30 08:05:41 +0000196};
197
Aaron Durbinbb4e79a2013-03-26 14:09:47 -0500198/* Shared MTRR calculations. Can be reused by APs. */
199static uint8_t fixed_mtrr_types[NUM_FIXED_RANGES];
200
201/* Fixed MTRR descriptors. */
202static const struct fixed_mtrr_desc fixed_mtrr_desc[] = {
203 { PHYS_TO_RANGE_ADDR(0x000000), PHYS_TO_RANGE_ADDR(0x080000),
204 PHYS_TO_RANGE_ADDR(64 * 1024), 0, MTRRfix64K_00000_MSR },
205 { PHYS_TO_RANGE_ADDR(0x080000), PHYS_TO_RANGE_ADDR(0x0C0000),
206 PHYS_TO_RANGE_ADDR(16 * 1024), 8, MTRRfix16K_80000_MSR },
207 { PHYS_TO_RANGE_ADDR(0x0C0000), PHYS_TO_RANGE_ADDR(0x100000),
208 PHYS_TO_RANGE_ADDR(4 * 1024), 24, MTRRfix4K_C0000_MSR },
209};
210
211static void calc_fixed_mtrrs(void)
Eric Biedermanf8a2ddd2004-10-30 08:05:41 +0000212{
Aaron Durbinbb4e79a2013-03-26 14:09:47 -0500213 static int fixed_mtrr_types_initialized;
214 struct memranges *phys_addr_space;
215 struct range_entry *r;
216 const struct fixed_mtrr_desc *desc;
217 const struct fixed_mtrr_desc *last_desc;
218 uint32_t begin;
219 uint32_t end;
220 int type_index;
221
222 if (fixed_mtrr_types_initialized)
Eric Biedermanf8a2ddd2004-10-30 08:05:41 +0000223 return;
Kyösti Mälkki2d42b342012-07-12 00:18:22 +0300224
Aaron Durbinbb4e79a2013-03-26 14:09:47 -0500225 phys_addr_space = get_physical_address_space();
Kyösti Mälkki2d42b342012-07-12 00:18:22 +0300226
Aaron Durbinbb4e79a2013-03-26 14:09:47 -0500227 /* Set all fixed ranges to uncacheable first. */
228 memset(&fixed_mtrr_types[0], MTRR_TYPE_UNCACHEABLE, NUM_FIXED_RANGES);
Kyösti Mälkki2d42b342012-07-12 00:18:22 +0300229
Aaron Durbinbb4e79a2013-03-26 14:09:47 -0500230 desc = &fixed_mtrr_desc[0];
231 last_desc = &fixed_mtrr_desc[ARRAY_SIZE(fixed_mtrr_desc) - 1];
232 type_index = desc->range_index;
Kyösti Mälkki1ec5e742012-07-26 23:51:20 +0300233
Aaron Durbinbb4e79a2013-03-26 14:09:47 -0500234 memranges_each_entry(r, phys_addr_space) {
235 begin = range_entry_base_mtrr_addr(r);
236 end = range_entry_end_mtrr_addr(r);
Kyösti Mälkki2d42b342012-07-12 00:18:22 +0300237
Aaron Durbinbb4e79a2013-03-26 14:09:47 -0500238 if (begin >= last_desc->end)
239 break;
240
241 if (end > last_desc->end)
242 end = last_desc->end;
243
244 /* Get to the correct fixed mtrr descriptor. */
245 while (begin >= desc->end)
246 desc++;
247
248 type_index = desc->range_index;
249 type_index += (begin - desc->begin) / desc->step;
250
251 while (begin != end) {
252 unsigned char type;
253
254 type = range_entry_tag(r);
255 printk(MTRR_VERBOSE_LEVEL,
256 "MTRR addr 0x%x-0x%x set to %d type @ %d\n",
257 begin, begin + desc->step, type, type_index);
258 if (type == MTRR_TYPE_WRBACK)
259 type |= MTRR_FIXED_WRBACK_BITS;
260 fixed_mtrr_types[type_index] = type;
261 type_index++;
262 begin += desc->step;
263 if (begin == desc->end)
264 desc++;
Yinghai Lu63601872005-01-27 22:48:12 +0000265 }
Eric Biedermanf8a2ddd2004-10-30 08:05:41 +0000266 }
Aaron Durbinbb4e79a2013-03-26 14:09:47 -0500267 fixed_mtrr_types_initialized = 1;
268}
269
270static void commit_fixed_mtrrs(void)
271{
272 int i;
273 int j;
274 int msr_num;
275 int type_index;
276 /* 8 ranges per msr. */
277 msr_t fixed_msrs[NUM_FIXED_MTRRS];
278 unsigned long msr_index[NUM_FIXED_MTRRS];
279
280 memset(&fixed_msrs, 0, sizeof(fixed_msrs));
281
282 disable_cache();
283
284 msr_num = 0;
285 type_index = 0;
286 for (i = 0; i < ARRAY_SIZE(fixed_mtrr_desc); i++) {
287 const struct fixed_mtrr_desc *desc;
288 int num_ranges;
289
290 desc = &fixed_mtrr_desc[i];
291 num_ranges = (desc->end - desc->begin) / desc->step;
292 for (j = 0; j < num_ranges; j += RANGES_PER_FIXED_MTRR) {
293 msr_index[msr_num] = desc->msr_index_base +
294 (j / RANGES_PER_FIXED_MTRR);
295 fixed_msrs[msr_num].lo |=
296 fixed_mtrr_types[type_index++] << 0;
297 fixed_msrs[msr_num].lo |=
298 fixed_mtrr_types[type_index++] << 8;
299 fixed_msrs[msr_num].lo |=
300 fixed_mtrr_types[type_index++] << 16;
301 fixed_msrs[msr_num].lo |=
302 fixed_mtrr_types[type_index++] << 24;
303 fixed_msrs[msr_num].hi |=
304 fixed_mtrr_types[type_index++] << 0;
305 fixed_msrs[msr_num].hi |=
306 fixed_mtrr_types[type_index++] << 8;
307 fixed_msrs[msr_num].hi |=
308 fixed_mtrr_types[type_index++] << 16;
309 fixed_msrs[msr_num].hi |=
310 fixed_mtrr_types[type_index++] << 24;
311 msr_num++;
312 }
313 }
314
315 for (i = 0; i < ARRAY_SIZE(fixed_msrs); i++) {
316 printk(BIOS_DEBUG, "MTRR: Fixed MSR 0x%lx 0x%08x%08x\n",
317 msr_index[i], fixed_msrs[i].hi, fixed_msrs[i].lo);
318 wrmsr(msr_index[i], fixed_msrs[i]);
319 }
320
321 enable_cache();
Eric Biedermanf8a2ddd2004-10-30 08:05:41 +0000322}
323
Aaron Durbin57686f82013-03-20 15:50:59 -0500324void x86_setup_fixed_mtrrs_no_enable(void)
Yinghai Lu13f1c2a2005-07-08 02:49:49 +0000325{
Aaron Durbinbb4e79a2013-03-26 14:09:47 -0500326 calc_fixed_mtrrs();
327 commit_fixed_mtrrs();
Yinghai Lu13f1c2a2005-07-08 02:49:49 +0000328}
Stefan Reinauer7f86ed12009-02-12 16:02:16 +0000329
Aaron Durbin57686f82013-03-20 15:50:59 -0500330void x86_setup_fixed_mtrrs(void)
331{
332 x86_setup_fixed_mtrrs_no_enable();
333
334 printk(BIOS_SPEW, "call enable_fixed_mtrr()\n");
335 enable_fixed_mtrr();
336}
337
Aaron Durbinbb4e79a2013-03-26 14:09:47 -0500338struct var_mtrr_state {
339 struct memranges *addr_space;
340 int above4gb;
341 int address_bits;
342 int commit_mtrrs;
343 int mtrr_index;
344 int def_mtrr_type;
345};
Aaron Durbin57686f82013-03-20 15:50:59 -0500346
Aaron Durbinbb4e79a2013-03-26 14:09:47 -0500347static void clear_var_mtrr(int index)
Eric Biedermanfcd5ace2004-10-14 19:29:29 +0000348{
Aaron Durbinbb4e79a2013-03-26 14:09:47 -0500349 msr_t msr_val;
350
351 msr_val = rdmsr(MTRRphysMask_MSR(index));
352 msr_val.lo &= ~MTRRphysMaskValid;
353 wrmsr(MTRRphysMask_MSR(index), msr_val);
354}
355
356static void write_var_mtrr(struct var_mtrr_state *var_state,
357 uint32_t base, uint32_t size, int mtrr_type)
358{
359 msr_t msr_val;
360 unsigned long msr_index;
361 resource_t rbase;
362 resource_t rsize;
363 resource_t mask;
364
365 /* Some variable MTRRs are attempted to be saved for the OS use.
366 * However, it's more important to try to map the full address space
367 * properly. */
368 if (var_state->mtrr_index >= bios_mtrrs)
369 printk(BIOS_WARNING, "Taking a reserved OS MTRR.\n");
370 if (var_state->mtrr_index >= total_mtrrs) {
371 printk(BIOS_ERR, "ERROR: Not enough MTTRs available!\n");
372 return;
373 }
374
375 rbase = base;
376 rsize = size;
377
378 rbase = RANGE_TO_PHYS_ADDR(rbase);
379 rsize = RANGE_TO_PHYS_ADDR(rsize);
380 rsize = -rsize;
381
382 mask = (1ULL << var_state->address_bits) - 1;
383 rsize = rsize & mask;
384
385 printk(BIOS_DEBUG, "MTRR: %d base 0x%016llx mask 0x%016llx type %d\n",
386 var_state->mtrr_index, rbase, rsize, mtrr_type);
387
388 msr_val.lo = rbase;
389 msr_val.lo |= mtrr_type;
390
391 msr_val.hi = rbase >> 32;
392 msr_index = MTRRphysBase_MSR(var_state->mtrr_index);
393 wrmsr(msr_index, msr_val);
394
395 msr_val.lo = rsize;
396 msr_val.lo |= MTRRphysMaskValid;
397 msr_val.hi = rsize >> 32;
398 msr_index = MTRRphysMask_MSR(var_state->mtrr_index);
399 wrmsr(msr_index, msr_val);
400}
401
402static void calc_var_mtrr_range(struct var_mtrr_state *var_state,
403 uint32_t base, uint32_t size, int mtrr_type)
404{
405 while (size != 0) {
406 uint32_t addr_lsb;
407 uint32_t size_msb;
408 uint32_t mtrr_size;
409
410 addr_lsb = fls(base);
411 size_msb = fms(size);
412
413 /* All MTRR entries need to have their base aligned to the mask
414 * size. The maximum size is calculated by a function of the
415 * min base bit set and maximum size bit set. */
416 if (addr_lsb > size_msb)
417 mtrr_size = 1 << size_msb;
418 else
419 mtrr_size = 1 << addr_lsb;
420
421 if (var_state->commit_mtrrs)
422 write_var_mtrr(var_state, base, mtrr_size, mtrr_type);
423
424 size -= mtrr_size;
425 base += mtrr_size;
426 var_state->mtrr_index++;
427 }
428}
429
430static void setup_var_mtrrs_by_state(struct var_mtrr_state *var_state)
431{
432 struct range_entry *r;
433
434 /*
435 * For each range that meets the non-default type process it in the
436 * following manner:
437 * +------------------+ c2 = end
438 * | 0 or more bytes |
439 * +------------------+ b2 = c1 = ALIGN_DOWN(end)
440 * | |
441 * +------------------+ b1 = a2 = ALIGN_UP(begin)
442 * | 0 or more bytes |
443 * +------------------+ a1 = begin
444 *
445 * Thus, there are 3 sub-ranges to configure variable MTRRs for.
Eric Biedermanfcd5ace2004-10-14 19:29:29 +0000446 */
Aaron Durbinbb4e79a2013-03-26 14:09:47 -0500447 memranges_each_entry(r, var_state->addr_space) {
448 uint32_t a1, a2, b1, b2, c1, c2;
449 int mtrr_type = range_entry_tag(r);
450
451 /* Skip default type. */
452 if (var_state->def_mtrr_type == mtrr_type)
453 continue;
454
455 a1 = range_entry_base_mtrr_addr(r);
456 c2 = range_entry_end_mtrr_addr(r);
457
458 /* The end address is under 1MiB. The fixed MTRRs take
459 * precedence over the variable ones. Therefore this range
460 * can be ignored. */
461 if (c2 < RANGE_1MB)
462 continue;
463
464 /* Again, the fixed MTRRs take precedence so the beginning
465 * of the range can be set to 0 if it starts below 1MiB. */
466 if (a1 < RANGE_1MB)
467 a1 = 0;
468
469 /* If the range starts above 4GiB the processing is done. */
470 if (!var_state->above4gb && a1 >= RANGE_4GB)
471 break;
472
473 /* Clip the upper address to 4GiB if addresses above 4GiB
474 * are not being processed. */
475 if (!var_state->above4gb && c2 > RANGE_4GB)
476 c2 = RANGE_4GB;
477
478 /* Don't align up or down on the range if it is smaller
479 * than the minimum granularity. */
480 if ((c2 - a1) < MTRR_MIN_ALIGN) {
481 calc_var_mtrr_range(var_state, a1, c2 - a1, mtrr_type);
482 continue;
483 }
484
485 b1 = a2 = ALIGN_UP(a1, MTRR_MIN_ALIGN);
486 b2 = c1 = ALIGN_DOWN(c2, MTRR_MIN_ALIGN);
487
488 calc_var_mtrr_range(var_state, a1, a2 - a1, mtrr_type);
489 calc_var_mtrr_range(var_state, b1, b2 - b1, mtrr_type);
490 calc_var_mtrr_range(var_state, c1, c2 - c1, mtrr_type);
491 }
492}
493
494static int calc_var_mtrrs(struct memranges *addr_space,
495 int above4gb, int address_bits)
496{
497 int wb_deftype_count;
498 int uc_deftype_count;
Eric Biedermanf8a2ddd2004-10-30 08:05:41 +0000499 struct var_mtrr_state var_state;
Eric Biedermanf8a2ddd2004-10-30 08:05:41 +0000500
Aaron Durbinbb4e79a2013-03-26 14:09:47 -0500501 /* The default MTRR cacheability type is determined by calculating
502 * the number of MTTRs required for each MTTR type as if it was the
503 * default. */
504 var_state.addr_space = addr_space;
Scott Duplichanf3cce2f2010-11-13 19:07:59 +0000505 var_state.above4gb = above4gb;
Aaron Durbinbb4e79a2013-03-26 14:09:47 -0500506 var_state.address_bits = address_bits;
507 var_state.commit_mtrrs = 0;
Stefan Reinauer7f86ed12009-02-12 16:02:16 +0000508
Aaron Durbinbb4e79a2013-03-26 14:09:47 -0500509 var_state.mtrr_index = 0;
510 var_state.def_mtrr_type = MTRR_TYPE_WRBACK;
511 setup_var_mtrrs_by_state(&var_state);
512 wb_deftype_count = var_state.mtrr_index;
Duncan Laurie7389fa92011-12-22 10:59:40 -0800513
Aaron Durbinbb4e79a2013-03-26 14:09:47 -0500514 var_state.mtrr_index = 0;
515 var_state.def_mtrr_type = MTRR_TYPE_UNCACHEABLE;
516 setup_var_mtrrs_by_state(&var_state);
517 uc_deftype_count = var_state.mtrr_index;
Scott Duplichanf3cce2f2010-11-13 19:07:59 +0000518
Aaron Durbinbb4e79a2013-03-26 14:09:47 -0500519 printk(BIOS_DEBUG, "MTRR: default type WB/UC MTRR counts: %d/%d.\n",
520 wb_deftype_count, uc_deftype_count);
Kyösti Mälkkiffc1fb32012-07-11 14:40:19 +0300521
Aaron Durbinbb4e79a2013-03-26 14:09:47 -0500522 if (wb_deftype_count < uc_deftype_count) {
523 printk(BIOS_DEBUG, "MTRR: WB selected as default type.\n");
524 return MTRR_TYPE_WRBACK;
525 }
526 printk(BIOS_DEBUG, "MTRR: UC selected as default type.\n");
527 return MTRR_TYPE_UNCACHEABLE;
528}
Kyösti Mälkkiffc1fb32012-07-11 14:40:19 +0300529
Aaron Durbinbb4e79a2013-03-26 14:09:47 -0500530static void commit_var_mtrrs(struct memranges *addr_space, int def_type,
531 int above4gb, int address_bits)
532{
533 struct var_mtrr_state var_state;
534 int i;
535
536 var_state.addr_space = addr_space;
537 var_state.above4gb = above4gb;
538 var_state.address_bits = address_bits;
539 /* Write the MSRs. */
540 var_state.commit_mtrrs = 1;
541 var_state.mtrr_index = 0;
542 var_state.def_mtrr_type = def_type;
543 setup_var_mtrrs_by_state(&var_state);
544
545 /* Clear all remaining variable MTTRs. */
546 for (i = var_state.mtrr_index; i < total_mtrrs; i++)
547 clear_var_mtrr(i);
548}
549
550void x86_setup_var_mtrrs(unsigned int address_bits, unsigned int above4gb)
551{
552 static int mtrr_default_type = -1;
553 struct memranges *addr_space;
554
555 addr_space = get_physical_address_space();
556
557 if (mtrr_default_type == -1) {
558 if (above4gb == 2)
559 detect_var_mtrrs();
560 mtrr_default_type =
561 calc_var_mtrrs(addr_space, !!above4gb, address_bits);
Eric Biedermanfcd5ace2004-10-14 19:29:29 +0000562 }
Stefan Reinauer00093a82011-11-02 16:12:34 -0700563
Aaron Durbinbb4e79a2013-03-26 14:09:47 -0500564 disable_cache();
565 commit_var_mtrrs(addr_space, mtrr_default_type, !!above4gb,
566 address_bits);
567 enable_var_mtrr(mtrr_default_type);
568 enable_cache();
Eric Biedermanfcd5ace2004-10-14 19:29:29 +0000569}
570
Sven Schnelleadfbcb792012-01-10 12:01:43 +0100571void x86_setup_mtrrs(void)
Yinghai Lu13f1c2a2005-07-08 02:49:49 +0000572{
Sven Schnelleadfbcb792012-01-10 12:01:43 +0100573 int address_size;
Yinghai Lu13f1c2a2005-07-08 02:49:49 +0000574 x86_setup_fixed_mtrrs();
Sven Schnelleadfbcb792012-01-10 12:01:43 +0100575 address_size = cpu_phys_address_size();
576 printk(BIOS_DEBUG, "CPU physical address size: %d bits\n", address_size);
577 x86_setup_var_mtrrs(address_size, 1);
Yinghai Lu13f1c2a2005-07-08 02:49:49 +0000578}
579
Eric Biedermanfcd5ace2004-10-14 19:29:29 +0000580int x86_mtrr_check(void)
581{
582 /* Only Pentium Pro and later have MTRR */
583 msr_t msr;
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000584 printk(BIOS_DEBUG, "\nMTRR check\n");
Eric Biedermanfcd5ace2004-10-14 19:29:29 +0000585
586 msr = rdmsr(0x2ff);
587 msr.lo >>= 10;
588
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000589 printk(BIOS_DEBUG, "Fixed MTRRs : ");
Eric Biedermanfcd5ace2004-10-14 19:29:29 +0000590 if (msr.lo & 0x01)
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000591 printk(BIOS_DEBUG, "Enabled\n");
Eric Biedermanfcd5ace2004-10-14 19:29:29 +0000592 else
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000593 printk(BIOS_DEBUG, "Disabled\n");
Eric Biedermanfcd5ace2004-10-14 19:29:29 +0000594
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000595 printk(BIOS_DEBUG, "Variable MTRRs: ");
Eric Biedermanfcd5ace2004-10-14 19:29:29 +0000596 if (msr.lo & 0x02)
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000597 printk(BIOS_DEBUG, "Enabled\n");
Eric Biedermanfcd5ace2004-10-14 19:29:29 +0000598 else
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000599 printk(BIOS_DEBUG, "Disabled\n");
Eric Biedermanfcd5ace2004-10-14 19:29:29 +0000600
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000601 printk(BIOS_DEBUG, "\n");
Eric Biedermanfcd5ace2004-10-14 19:29:29 +0000602
603 post_code(0x93);
604 return ((int) msr.lo);
605}