blob: 8bdc511fd53c35bd157cc8087b56e41185386729 [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 *
Eric Biedermanfcd5ace2004-10-14 19:29:29 +000019 *
20 * Reference: Intel Architecture Software Developer's Manual, Volume 3: System Programming
21 */
Yinghai Lu13f1c2a2005-07-08 02:49:49 +000022
Eric Biedermanf8a2ddd2004-10-30 08:05:41 +000023#include <stddef.h>
Aaron Durbinbb4e79a2013-03-26 14:09:47 -050024#include <stdlib.h>
25#include <string.h>
Aaron Durbinbebf6692013-04-24 20:59:43 -050026#include <bootstate.h>
Eric Biedermanfcd5ace2004-10-14 19:29:29 +000027#include <console/console.h>
28#include <device/device.h>
Aaron Durbinca4f4b82014-02-08 15:41:52 -060029#include <device/pci_ids.h>
Aaron Durbinebf142a2013-03-29 16:23:23 -050030#include <cpu/cpu.h>
Eric Biedermanfcd5ace2004-10-14 19:29:29 +000031#include <cpu/x86/msr.h>
32#include <cpu/x86/mtrr.h>
33#include <cpu/x86/cache.h>
Stefan Reinauer00093a82011-11-02 16:12:34 -070034#include <cpu/x86/lapic.h>
Sven Schnelleadfbcb792012-01-10 12:01:43 +010035#include <arch/cpu.h>
Stefan Reinauer00093a82011-11-02 16:12:34 -070036#include <arch/acpi.h>
Aaron Durbinbb4e79a2013-03-26 14:09:47 -050037#include <memrange.h>
Aaron Durbin57686f82013-03-20 15:50:59 -050038#if CONFIG_X86_AMD_FIXED_MTRRS
39#include <cpu/amd/mtrr.h>
40#define MTRR_FIXED_WRBACK_BITS (MTRR_READ_MEM | MTRR_WRITE_MEM)
41#else
42#define MTRR_FIXED_WRBACK_BITS 0
43#endif
Eric Biedermanfcd5ace2004-10-14 19:29:29 +000044
Stefan Reinauerc00dfbc2012-04-03 16:24:37 -070045/* 2 MTRRS are reserved for the operating system */
46#define BIOS_MTRRS 6
47#define OS_MTRRS 2
48#define MTRRS (BIOS_MTRRS + OS_MTRRS)
Gabe Black7756fe72014-02-25 01:40:34 -080049/*
Isaac Christensen81f90c52014-09-24 14:59:32 -060050 * Static storage size for variable MTRRs. It's sized sufficiently large to
51 * handle different types of CPUs. Empirically, 16 variable MTRRs has not
Gabe Black7756fe72014-02-25 01:40:34 -080052 * yet been observed.
53 */
54#define NUM_MTRR_STATIC_STORAGE 16
Stefan Reinauerc00dfbc2012-04-03 16:24:37 -070055
56static int total_mtrrs = MTRRS;
57static int bios_mtrrs = BIOS_MTRRS;
58
59static void detect_var_mtrrs(void)
60{
61 msr_t msr;
62
Alexandru Gagniuc86091f92015-09-30 20:23:09 -070063 msr = rdmsr(MTRR_CAP_MSR);
Stefan Reinauerc00dfbc2012-04-03 16:24:37 -070064
65 total_mtrrs = msr.lo & 0xff;
Gabe Black7756fe72014-02-25 01:40:34 -080066
67 if (total_mtrrs > NUM_MTRR_STATIC_STORAGE) {
68 printk(BIOS_WARNING,
69 "MTRRs detected (%d) > NUM_MTRR_STATIC_STORAGE (%d)\n",
70 total_mtrrs, NUM_MTRR_STATIC_STORAGE);
71 total_mtrrs = NUM_MTRR_STATIC_STORAGE;
72 }
Stefan Reinauerc00dfbc2012-04-03 16:24:37 -070073 bios_mtrrs = total_mtrrs - OS_MTRRS;
74}
75
Yinghai Lu13f1c2a2005-07-08 02:49:49 +000076void enable_fixed_mtrr(void)
Eric Biedermanfcd5ace2004-10-14 19:29:29 +000077{
78 msr_t msr;
79
Alexandru Gagniuc86091f92015-09-30 20:23:09 -070080 msr = rdmsr(MTRR_DEF_TYPE_MSR);
81 msr.lo |= MTRR_DEF_TYPE_EN | MTRR_DEF_TYPE_FIX_EN;
82 wrmsr(MTRR_DEF_TYPE_MSR, msr);
Eric Biedermanfcd5ace2004-10-14 19:29:29 +000083}
84
Aaron Durbinbb4e79a2013-03-26 14:09:47 -050085static void enable_var_mtrr(unsigned char deftype)
Eric Biedermanfcd5ace2004-10-14 19:29:29 +000086{
87 msr_t msr;
88
Alexandru Gagniuc86091f92015-09-30 20:23:09 -070089 msr = rdmsr(MTRR_DEF_TYPE_MSR);
Aaron Durbinbb4e79a2013-03-26 14:09:47 -050090 msr.lo &= ~0xff;
Alexandru Gagniuc86091f92015-09-30 20:23:09 -070091 msr.lo |= MTRR_DEF_TYPE_EN | deftype;
92 wrmsr(MTRR_DEF_TYPE_MSR, msr);
Eric Biedermanfcd5ace2004-10-14 19:29:29 +000093}
94
Martin Roth2f914032016-01-15 10:20:11 -070095/* fms: find most significant bit set, stolen from Linux Kernel Source. */
Eric Biedermanfcd5ace2004-10-14 19:29:29 +000096static inline unsigned int fms(unsigned int x)
97{
98 int r;
99
100 __asm__("bsrl %1,%0\n\t"
101 "jnz 1f\n\t"
102 "movl $0,%0\n"
103 "1:" : "=r" (r) : "g" (x));
104 return r;
105}
106
Martin Roth4c3ab732013-07-08 16:23:54 -0600107/* fls: find least significant bit set */
Eric Biedermanfcd5ace2004-10-14 19:29:29 +0000108static inline unsigned int fls(unsigned int x)
109{
110 int r;
111
112 __asm__("bsfl %1,%0\n\t"
113 "jnz 1f\n\t"
114 "movl $32,%0\n"
115 "1:" : "=r" (r) : "g" (x));
116 return r;
117}
118
Aaron Durbinbb4e79a2013-03-26 14:09:47 -0500119#define MTRR_VERBOSE_LEVEL BIOS_NEVER
Eric Biedermanfcd5ace2004-10-14 19:29:29 +0000120
Aaron Durbinbb4e79a2013-03-26 14:09:47 -0500121/* MTRRs are at a 4KiB granularity. Therefore all address calculations can
122 * be done with 32-bit numbers. This allows for the MTRR code to handle
123 * up to 2^44 bytes (16 TiB) of address space. */
124#define RANGE_SHIFT 12
125#define ADDR_SHIFT_TO_RANGE_SHIFT(x) \
126 (((x) > RANGE_SHIFT) ? ((x) - RANGE_SHIFT) : RANGE_SHIFT)
127#define PHYS_TO_RANGE_ADDR(x) ((x) >> RANGE_SHIFT)
128#define RANGE_TO_PHYS_ADDR(x) (((resource_t)(x)) << RANGE_SHIFT)
129#define NUM_FIXED_MTRRS (NUM_FIXED_RANGES / RANGES_PER_FIXED_MTRR)
130
131/* The minimum alignment while handling variable MTRR ranges is 64MiB. */
132#define MTRR_MIN_ALIGN PHYS_TO_RANGE_ADDR(64 << 20)
133/* Helpful constants. */
134#define RANGE_1MB PHYS_TO_RANGE_ADDR(1 << 20)
135#define RANGE_4GB (1 << (ADDR_SHIFT_TO_RANGE_SHIFT(32)))
136
Aaron Durbine3834422013-03-28 20:48:51 -0500137/*
138 * The default MTRR type selection uses 3 approaches for selecting the
139 * optimal number of variable MTRRs. For each range do 3 calculations:
140 * 1. UC as default type with no holes at top of range.
141 * 2. UC as default using holes at top of range.
142 * 3. WB as default.
143 * If using holes is optimal for a range when UC is the default type the
144 * tag is updated to direct the commit routine to use a hole at the top
145 * of a range.
146 */
147#define MTRR_ALGO_SHIFT (8)
148#define MTRR_TAG_MASK ((1 << MTRR_ALGO_SHIFT) - 1)
149/* If the default type is UC use the hole carving algorithm for a range. */
150#define MTRR_RANGE_UC_USE_HOLE (1 << MTRR_ALGO_SHIFT)
151
Aaron Durbinbb4e79a2013-03-26 14:09:47 -0500152static inline uint32_t range_entry_base_mtrr_addr(struct range_entry *r)
Eric Biedermanfcd5ace2004-10-14 19:29:29 +0000153{
Aaron Durbinbb4e79a2013-03-26 14:09:47 -0500154 return PHYS_TO_RANGE_ADDR(range_entry_base(r));
Eric Biedermanfcd5ace2004-10-14 19:29:29 +0000155}
156
Aaron Durbinbb4e79a2013-03-26 14:09:47 -0500157static inline uint32_t range_entry_end_mtrr_addr(struct range_entry *r)
Eric Biedermanfcd5ace2004-10-14 19:29:29 +0000158{
Aaron Durbinbb4e79a2013-03-26 14:09:47 -0500159 return PHYS_TO_RANGE_ADDR(range_entry_end(r));
Eric Biedermanfcd5ace2004-10-14 19:29:29 +0000160}
161
Aaron Durbine3834422013-03-28 20:48:51 -0500162static inline int range_entry_mtrr_type(struct range_entry *r)
163{
164 return range_entry_tag(r) & MTRR_TAG_MASK;
165}
166
Aaron Durbinca4f4b82014-02-08 15:41:52 -0600167static int filter_vga_wrcomb(struct device *dev, struct resource *res)
168{
169 /* Only handle PCI devices. */
170 if (dev->path.type != DEVICE_PATH_PCI)
171 return 0;
172
173 /* Only handle VGA class devices. */
174 if (((dev->class >> 8) != PCI_CLASS_DISPLAY_VGA))
175 return 0;
176
177 /* Add resource as write-combining in the address space. */
178 return 1;
179}
180
Aaron Durbinbb4e79a2013-03-26 14:09:47 -0500181static struct memranges *get_physical_address_space(void)
Eric Biedermanfcd5ace2004-10-14 19:29:29 +0000182{
Aaron Durbinbb4e79a2013-03-26 14:09:47 -0500183 static struct memranges *addr_space;
184 static struct memranges addr_space_storage;
Duncan Laurie7389fa92011-12-22 10:59:40 -0800185
Aaron Durbinbb4e79a2013-03-26 14:09:47 -0500186 /* In order to handle some chipsets not being able to pre-determine
Martin Roth4c3ab732013-07-08 16:23:54 -0600187 * uncacheable ranges, such as graphics memory, at resource insertion
188 * time remove uncacheable regions from the cacheable ones. */
Aaron Durbinbb4e79a2013-03-26 14:09:47 -0500189 if (addr_space == NULL) {
190 struct range_entry *r;
Aaron Durbin9b027fe2013-03-26 14:10:34 -0500191 unsigned long mask;
192 unsigned long match;
Aaron Durbinbb4e79a2013-03-26 14:09:47 -0500193
194 addr_space = &addr_space_storage;
195
Aaron Durbin9b027fe2013-03-26 14:10:34 -0500196 mask = IORESOURCE_CACHEABLE;
Aaron Durbinbb4e79a2013-03-26 14:09:47 -0500197 /* Collect cacheable and uncacheable address ranges. The
198 * uncacheable regions take precedence over the cacheable
199 * regions. */
200 memranges_init(addr_space, mask, mask, MTRR_TYPE_WRBACK);
201 memranges_add_resources(addr_space, mask, 0,
202 MTRR_TYPE_UNCACHEABLE);
203
Aaron Durbin9b027fe2013-03-26 14:10:34 -0500204 /* Handle any write combining resources. Only prefetchable
Vladimir Serbinenko30fe6122014-02-05 23:25:28 +0100205 * resources are appropriate for this MTRR type. */
206 match = IORESOURCE_PREFETCH;
Aaron Durbin9b027fe2013-03-26 14:10:34 -0500207 mask |= match;
Aaron Durbinca4f4b82014-02-08 15:41:52 -0600208 memranges_add_resources_filter(addr_space, mask, match, MTRR_TYPE_WRCOMB,
209 filter_vga_wrcomb);
Aaron Durbin9b027fe2013-03-26 14:10:34 -0500210
Aaron Durbinbb4e79a2013-03-26 14:09:47 -0500211 /* The address space below 4GiB is special. It needs to be
Martin Roth2f914032016-01-15 10:20:11 -0700212 * covered entirely by range entries so that MTRR calculations
Aaron Durbinbb4e79a2013-03-26 14:09:47 -0500213 * can be properly done for the full 32-bit address space.
214 * Therefore, ensure holes are filled up to 4GiB as
215 * uncacheable */
216 memranges_fill_holes_up_to(addr_space,
217 RANGE_TO_PHYS_ADDR(RANGE_4GB),
218 MTRR_TYPE_UNCACHEABLE);
219
220 printk(BIOS_DEBUG, "MTRR: Physical address space:\n");
221 memranges_each_entry(r, addr_space)
222 printk(BIOS_DEBUG,
223 "0x%016llx - 0x%016llx size 0x%08llx type %ld\n",
224 range_entry_base(r), range_entry_end(r),
225 range_entry_size(r), range_entry_tag(r));
Carl-Daniel Hailfinger7dde1da2009-02-11 16:57:32 +0000226 }
Stefan Reinauer7f86ed12009-02-12 16:02:16 +0000227
Aaron Durbinbb4e79a2013-03-26 14:09:47 -0500228 return addr_space;
Eric Biedermanfcd5ace2004-10-14 19:29:29 +0000229}
230
Aaron Durbinbb4e79a2013-03-26 14:09:47 -0500231/* Fixed MTRR descriptor. This structure defines the step size and begin
Martin Roth4c3ab732013-07-08 16:23:54 -0600232 * and end (exclusive) address covered by a set of fixed MTRR MSRs.
Aaron Durbinbb4e79a2013-03-26 14:09:47 -0500233 * It also describes the offset in byte intervals to store the calculated MTRR
234 * type in an array. */
235struct fixed_mtrr_desc {
236 uint32_t begin;
237 uint32_t end;
238 uint32_t step;
239 int range_index;
240 int msr_index_base;
Eric Biedermanf8a2ddd2004-10-30 08:05:41 +0000241};
242
Aaron Durbinbb4e79a2013-03-26 14:09:47 -0500243/* Shared MTRR calculations. Can be reused by APs. */
244static uint8_t fixed_mtrr_types[NUM_FIXED_RANGES];
245
246/* Fixed MTRR descriptors. */
247static const struct fixed_mtrr_desc fixed_mtrr_desc[] = {
248 { PHYS_TO_RANGE_ADDR(0x000000), PHYS_TO_RANGE_ADDR(0x080000),
Alexandru Gagniuc86091f92015-09-30 20:23:09 -0700249 PHYS_TO_RANGE_ADDR(64 * 1024), 0, MTRR_FIX_64K_00000 },
Aaron Durbinbb4e79a2013-03-26 14:09:47 -0500250 { PHYS_TO_RANGE_ADDR(0x080000), PHYS_TO_RANGE_ADDR(0x0C0000),
Alexandru Gagniuc86091f92015-09-30 20:23:09 -0700251 PHYS_TO_RANGE_ADDR(16 * 1024), 8, MTRR_FIX_16K_80000 },
Aaron Durbinbb4e79a2013-03-26 14:09:47 -0500252 { PHYS_TO_RANGE_ADDR(0x0C0000), PHYS_TO_RANGE_ADDR(0x100000),
Alexandru Gagniuc86091f92015-09-30 20:23:09 -0700253 PHYS_TO_RANGE_ADDR(4 * 1024), 24, MTRR_FIX_4K_C0000 },
Aaron Durbinbb4e79a2013-03-26 14:09:47 -0500254};
255
256static void calc_fixed_mtrrs(void)
Eric Biedermanf8a2ddd2004-10-30 08:05:41 +0000257{
Aaron Durbinbb4e79a2013-03-26 14:09:47 -0500258 static int fixed_mtrr_types_initialized;
259 struct memranges *phys_addr_space;
260 struct range_entry *r;
261 const struct fixed_mtrr_desc *desc;
262 const struct fixed_mtrr_desc *last_desc;
263 uint32_t begin;
264 uint32_t end;
265 int type_index;
266
267 if (fixed_mtrr_types_initialized)
Eric Biedermanf8a2ddd2004-10-30 08:05:41 +0000268 return;
Kyösti Mälkki2d42b342012-07-12 00:18:22 +0300269
Aaron Durbinbb4e79a2013-03-26 14:09:47 -0500270 phys_addr_space = get_physical_address_space();
Kyösti Mälkki2d42b342012-07-12 00:18:22 +0300271
Aaron Durbinbb4e79a2013-03-26 14:09:47 -0500272 /* Set all fixed ranges to uncacheable first. */
273 memset(&fixed_mtrr_types[0], MTRR_TYPE_UNCACHEABLE, NUM_FIXED_RANGES);
Kyösti Mälkki2d42b342012-07-12 00:18:22 +0300274
Aaron Durbinbb4e79a2013-03-26 14:09:47 -0500275 desc = &fixed_mtrr_desc[0];
276 last_desc = &fixed_mtrr_desc[ARRAY_SIZE(fixed_mtrr_desc) - 1];
Kyösti Mälkki1ec5e742012-07-26 23:51:20 +0300277
Aaron Durbinbb4e79a2013-03-26 14:09:47 -0500278 memranges_each_entry(r, phys_addr_space) {
279 begin = range_entry_base_mtrr_addr(r);
280 end = range_entry_end_mtrr_addr(r);
Kyösti Mälkki2d42b342012-07-12 00:18:22 +0300281
Aaron Durbinbb4e79a2013-03-26 14:09:47 -0500282 if (begin >= last_desc->end)
283 break;
284
285 if (end > last_desc->end)
286 end = last_desc->end;
287
288 /* Get to the correct fixed mtrr descriptor. */
289 while (begin >= desc->end)
290 desc++;
291
292 type_index = desc->range_index;
293 type_index += (begin - desc->begin) / desc->step;
294
295 while (begin != end) {
296 unsigned char type;
297
298 type = range_entry_tag(r);
299 printk(MTRR_VERBOSE_LEVEL,
300 "MTRR addr 0x%x-0x%x set to %d type @ %d\n",
301 begin, begin + desc->step, type, type_index);
302 if (type == MTRR_TYPE_WRBACK)
303 type |= MTRR_FIXED_WRBACK_BITS;
304 fixed_mtrr_types[type_index] = type;
305 type_index++;
306 begin += desc->step;
307 if (begin == desc->end)
308 desc++;
Yinghai Lu63601872005-01-27 22:48:12 +0000309 }
Eric Biedermanf8a2ddd2004-10-30 08:05:41 +0000310 }
Aaron Durbinbb4e79a2013-03-26 14:09:47 -0500311 fixed_mtrr_types_initialized = 1;
312}
313
314static void commit_fixed_mtrrs(void)
315{
316 int i;
317 int j;
318 int msr_num;
319 int type_index;
320 /* 8 ranges per msr. */
321 msr_t fixed_msrs[NUM_FIXED_MTRRS];
322 unsigned long msr_index[NUM_FIXED_MTRRS];
323
324 memset(&fixed_msrs, 0, sizeof(fixed_msrs));
325
Aaron Durbinbb4e79a2013-03-26 14:09:47 -0500326 msr_num = 0;
327 type_index = 0;
328 for (i = 0; i < ARRAY_SIZE(fixed_mtrr_desc); i++) {
329 const struct fixed_mtrr_desc *desc;
330 int num_ranges;
331
332 desc = &fixed_mtrr_desc[i];
333 num_ranges = (desc->end - desc->begin) / desc->step;
334 for (j = 0; j < num_ranges; j += RANGES_PER_FIXED_MTRR) {
335 msr_index[msr_num] = desc->msr_index_base +
336 (j / RANGES_PER_FIXED_MTRR);
337 fixed_msrs[msr_num].lo |=
338 fixed_mtrr_types[type_index++] << 0;
339 fixed_msrs[msr_num].lo |=
340 fixed_mtrr_types[type_index++] << 8;
341 fixed_msrs[msr_num].lo |=
342 fixed_mtrr_types[type_index++] << 16;
343 fixed_msrs[msr_num].lo |=
344 fixed_mtrr_types[type_index++] << 24;
345 fixed_msrs[msr_num].hi |=
346 fixed_mtrr_types[type_index++] << 0;
347 fixed_msrs[msr_num].hi |=
348 fixed_mtrr_types[type_index++] << 8;
349 fixed_msrs[msr_num].hi |=
350 fixed_mtrr_types[type_index++] << 16;
351 fixed_msrs[msr_num].hi |=
352 fixed_mtrr_types[type_index++] << 24;
353 msr_num++;
354 }
355 }
356
Gabe Black7756fe72014-02-25 01:40:34 -0800357 for (i = 0; i < ARRAY_SIZE(fixed_msrs); i++)
Aaron Durbinbb4e79a2013-03-26 14:09:47 -0500358 printk(BIOS_DEBUG, "MTRR: Fixed MSR 0x%lx 0x%08x%08x\n",
359 msr_index[i], fixed_msrs[i].hi, fixed_msrs[i].lo);
Aaron Durbinbb4e79a2013-03-26 14:09:47 -0500360
Gabe Black7756fe72014-02-25 01:40:34 -0800361 disable_cache();
362 for (i = 0; i < ARRAY_SIZE(fixed_msrs); i++)
363 wrmsr(msr_index[i], fixed_msrs[i]);
Aaron Durbinbb4e79a2013-03-26 14:09:47 -0500364 enable_cache();
Eric Biedermanf8a2ddd2004-10-30 08:05:41 +0000365}
366
Aaron Durbin57686f82013-03-20 15:50:59 -0500367void x86_setup_fixed_mtrrs_no_enable(void)
Yinghai Lu13f1c2a2005-07-08 02:49:49 +0000368{
Aaron Durbinbb4e79a2013-03-26 14:09:47 -0500369 calc_fixed_mtrrs();
370 commit_fixed_mtrrs();
Yinghai Lu13f1c2a2005-07-08 02:49:49 +0000371}
Stefan Reinauer7f86ed12009-02-12 16:02:16 +0000372
Aaron Durbin57686f82013-03-20 15:50:59 -0500373void x86_setup_fixed_mtrrs(void)
374{
375 x86_setup_fixed_mtrrs_no_enable();
376
377 printk(BIOS_SPEW, "call enable_fixed_mtrr()\n");
378 enable_fixed_mtrr();
379}
380
Gabe Black7756fe72014-02-25 01:40:34 -0800381struct var_mtrr_regs {
382 msr_t base;
383 msr_t mask;
384};
385
386struct var_mtrr_solution {
387 int mtrr_default_type;
388 int num_used;
389 struct var_mtrr_regs regs[NUM_MTRR_STATIC_STORAGE];
390};
391
392/* Global storage for variable MTRR solution. */
393static struct var_mtrr_solution mtrr_global_solution;
394
Aaron Durbinbb4e79a2013-03-26 14:09:47 -0500395struct var_mtrr_state {
396 struct memranges *addr_space;
397 int above4gb;
398 int address_bits;
Gabe Black7756fe72014-02-25 01:40:34 -0800399 int prepare_msrs;
Aaron Durbinbb4e79a2013-03-26 14:09:47 -0500400 int mtrr_index;
401 int def_mtrr_type;
Gabe Black7756fe72014-02-25 01:40:34 -0800402 struct var_mtrr_regs *regs;
Aaron Durbinbb4e79a2013-03-26 14:09:47 -0500403};
Aaron Durbin57686f82013-03-20 15:50:59 -0500404
Aaron Durbinbb4e79a2013-03-26 14:09:47 -0500405static void clear_var_mtrr(int index)
Eric Biedermanfcd5ace2004-10-14 19:29:29 +0000406{
Aaron Durbinbb4e79a2013-03-26 14:09:47 -0500407 msr_t msr_val;
408
Alexandru Gagniuc86091f92015-09-30 20:23:09 -0700409 msr_val = rdmsr(MTRR_PHYS_MASK(index));
410 msr_val.lo &= ~MTRR_PHYS_MASK_VALID;
411 wrmsr(MTRR_PHYS_MASK(index), msr_val);
Aaron Durbinbb4e79a2013-03-26 14:09:47 -0500412}
413
Gabe Black7756fe72014-02-25 01:40:34 -0800414static void prep_var_mtrr(struct var_mtrr_state *var_state,
415 uint32_t base, uint32_t size, int mtrr_type)
Aaron Durbinbb4e79a2013-03-26 14:09:47 -0500416{
Gabe Black7756fe72014-02-25 01:40:34 -0800417 struct var_mtrr_regs *regs;
Aaron Durbinbb4e79a2013-03-26 14:09:47 -0500418 resource_t rbase;
419 resource_t rsize;
420 resource_t mask;
421
422 /* Some variable MTRRs are attempted to be saved for the OS use.
423 * However, it's more important to try to map the full address space
424 * properly. */
425 if (var_state->mtrr_index >= bios_mtrrs)
426 printk(BIOS_WARNING, "Taking a reserved OS MTRR.\n");
427 if (var_state->mtrr_index >= total_mtrrs) {
Paul Menzel6a70dbc2015-10-15 12:41:53 +0200428 printk(BIOS_ERR, "ERROR: Not enough MTRRs available! MTRR index"
429 "is %d with %d MTTRs in total.\n",
430 var_state->mtrr_index, total_mtrrs);
Aaron Durbinbb4e79a2013-03-26 14:09:47 -0500431 return;
432 }
433
434 rbase = base;
435 rsize = size;
436
437 rbase = RANGE_TO_PHYS_ADDR(rbase);
438 rsize = RANGE_TO_PHYS_ADDR(rsize);
439 rsize = -rsize;
440
441 mask = (1ULL << var_state->address_bits) - 1;
442 rsize = rsize & mask;
443
444 printk(BIOS_DEBUG, "MTRR: %d base 0x%016llx mask 0x%016llx type %d\n",
445 var_state->mtrr_index, rbase, rsize, mtrr_type);
446
Gabe Black7756fe72014-02-25 01:40:34 -0800447 regs = &var_state->regs[var_state->mtrr_index];
Aaron Durbinbb4e79a2013-03-26 14:09:47 -0500448
Gabe Black7756fe72014-02-25 01:40:34 -0800449 regs->base.lo = rbase;
450 regs->base.lo |= mtrr_type;
451 regs->base.hi = rbase >> 32;
Aaron Durbinbb4e79a2013-03-26 14:09:47 -0500452
Gabe Black7756fe72014-02-25 01:40:34 -0800453 regs->mask.lo = rsize;
Alexandru Gagniuc86091f92015-09-30 20:23:09 -0700454 regs->mask.lo |= MTRR_PHYS_MASK_VALID;
Gabe Black7756fe72014-02-25 01:40:34 -0800455 regs->mask.hi = rsize >> 32;
Aaron Durbinbb4e79a2013-03-26 14:09:47 -0500456}
457
458static void calc_var_mtrr_range(struct var_mtrr_state *var_state,
459 uint32_t base, uint32_t size, int mtrr_type)
460{
461 while (size != 0) {
462 uint32_t addr_lsb;
463 uint32_t size_msb;
464 uint32_t mtrr_size;
465
466 addr_lsb = fls(base);
467 size_msb = fms(size);
468
469 /* All MTRR entries need to have their base aligned to the mask
470 * size. The maximum size is calculated by a function of the
471 * min base bit set and maximum size bit set. */
472 if (addr_lsb > size_msb)
473 mtrr_size = 1 << size_msb;
474 else
475 mtrr_size = 1 << addr_lsb;
476
Gabe Black7756fe72014-02-25 01:40:34 -0800477 if (var_state->prepare_msrs)
478 prep_var_mtrr(var_state, base, mtrr_size, mtrr_type);
Aaron Durbinbb4e79a2013-03-26 14:09:47 -0500479
480 size -= mtrr_size;
481 base += mtrr_size;
482 var_state->mtrr_index++;
483 }
484}
485
Aaron Durbine3834422013-03-28 20:48:51 -0500486static void calc_var_mtrrs_with_hole(struct var_mtrr_state *var_state,
487 struct range_entry *r)
Aaron Durbinbb4e79a2013-03-26 14:09:47 -0500488{
Aaron Durbine3834422013-03-28 20:48:51 -0500489 uint32_t a1, a2, b1, b2;
490 int mtrr_type;
491 struct range_entry *next;
492
493 /*
Martin Roth4c3ab732013-07-08 16:23:54 -0600494 * Determine MTRRs based on the following algorithm for the given entry:
Aaron Durbine3834422013-03-28 20:48:51 -0500495 * +------------------+ b2 = ALIGN_UP(end)
496 * | 0 or more bytes | <-- hole is carved out between b1 and b2
497 * +------------------+ a2 = b1 = end
498 * | |
499 * +------------------+ a1 = begin
500 *
501 * Thus, there are 3 sub-ranges to configure variable MTRRs for.
502 */
503 mtrr_type = range_entry_mtrr_type(r);
504
505 a1 = range_entry_base_mtrr_addr(r);
506 a2 = range_entry_end_mtrr_addr(r);
507
Aaron Durbina38677b2016-07-21 14:26:34 -0500508 /* The end address is within the first 1MiB. The fixed MTRRs take
Aaron Durbine3834422013-03-28 20:48:51 -0500509 * precedence over the variable ones. Therefore this range
510 * can be ignored. */
Aaron Durbina38677b2016-07-21 14:26:34 -0500511 if (a2 <= RANGE_1MB)
Aaron Durbine3834422013-03-28 20:48:51 -0500512 return;
513
514 /* Again, the fixed MTRRs take precedence so the beginning
Aaron Durbina38677b2016-07-21 14:26:34 -0500515 * of the range can be set to 0 if it starts at or below 1MiB. */
516 if (a1 <= RANGE_1MB)
Aaron Durbine3834422013-03-28 20:48:51 -0500517 a1 = 0;
518
519 /* If the range starts above 4GiB the processing is done. */
520 if (!var_state->above4gb && a1 >= RANGE_4GB)
521 return;
522
523 /* Clip the upper address to 4GiB if addresses above 4GiB
524 * are not being processed. */
525 if (!var_state->above4gb && a2 > RANGE_4GB)
526 a2 = RANGE_4GB;
527
Aaron Durbin53924242013-03-29 11:48:27 -0500528 next = memranges_next_entry(var_state->addr_space, r);
529
Aaron Durbine3834422013-03-28 20:48:51 -0500530 b1 = a2;
Aaron Durbin53924242013-03-29 11:48:27 -0500531
Martin Roth4c3ab732013-07-08 16:23:54 -0600532 /* First check if a1 is >= 4GiB and the current entry is the last
Aaron Durbin53924242013-03-29 11:48:27 -0500533 * entry. If so perform an optimization of covering a larger range
534 * defined by the base address' alignment. */
535 if (a1 >= RANGE_4GB && next == NULL) {
536 uint32_t addr_lsb;
537
538 addr_lsb = fls(a1);
539 b2 = (1 << addr_lsb) + a1;
540 if (b2 >= a2) {
541 calc_var_mtrr_range(var_state, a1, b2 - a1, mtrr_type);
542 return;
543 }
544 }
545
546 /* Handle the min alignment roundup case. */
Aaron Durbine3834422013-03-28 20:48:51 -0500547 b2 = ALIGN_UP(a2, MTRR_MIN_ALIGN);
548
549 /* Check against the next range. If the current range_entry is the
550 * last entry then carving a hole is no problem. If the current entry
551 * isn't the last entry then check that the last entry covers the
552 * entire hole range with the default mtrr type. */
Aaron Durbine3834422013-03-28 20:48:51 -0500553 if (next != NULL &&
554 (range_entry_mtrr_type(next) != var_state->def_mtrr_type ||
555 range_entry_end_mtrr_addr(next) < b2)) {
556 calc_var_mtrr_range(var_state, a1, a2 - a1, mtrr_type);
557 return;
558 }
559
560 calc_var_mtrr_range(var_state, a1, b2 - a1, mtrr_type);
561 calc_var_mtrr_range(var_state, b1, b2 - b1, var_state->def_mtrr_type);
562}
563
564static void calc_var_mtrrs_without_hole(struct var_mtrr_state *var_state,
565 struct range_entry *r)
566{
567 uint32_t a1, a2, b1, b2, c1, c2;
568 int mtrr_type;
Aaron Durbinbb4e79a2013-03-26 14:09:47 -0500569
570 /*
571 * For each range that meets the non-default type process it in the
572 * following manner:
573 * +------------------+ c2 = end
574 * | 0 or more bytes |
575 * +------------------+ b2 = c1 = ALIGN_DOWN(end)
576 * | |
577 * +------------------+ b1 = a2 = ALIGN_UP(begin)
578 * | 0 or more bytes |
579 * +------------------+ a1 = begin
580 *
581 * Thus, there are 3 sub-ranges to configure variable MTRRs for.
Eric Biedermanfcd5ace2004-10-14 19:29:29 +0000582 */
Aaron Durbine3834422013-03-28 20:48:51 -0500583 mtrr_type = range_entry_mtrr_type(r);
Aaron Durbinbb4e79a2013-03-26 14:09:47 -0500584
Aaron Durbine3834422013-03-28 20:48:51 -0500585 a1 = range_entry_base_mtrr_addr(r);
586 c2 = range_entry_end_mtrr_addr(r);
Aaron Durbinbb4e79a2013-03-26 14:09:47 -0500587
Aaron Durbina38677b2016-07-21 14:26:34 -0500588 /* The end address is within the first 1MiB. The fixed MTRRs take
Aaron Durbine3834422013-03-28 20:48:51 -0500589 * precedence over the variable ones. Therefore this range
590 * can be ignored. */
Aaron Durbina38677b2016-07-21 14:26:34 -0500591 if (c2 <= RANGE_1MB)
Aaron Durbine3834422013-03-28 20:48:51 -0500592 return;
Aaron Durbinbb4e79a2013-03-26 14:09:47 -0500593
Aaron Durbine3834422013-03-28 20:48:51 -0500594 /* Again, the fixed MTRRs take precedence so the beginning
Aaron Durbina38677b2016-07-21 14:26:34 -0500595 * of the range can be set to 0 if it starts at or below 1MiB. */
596 if (a1 <= RANGE_1MB)
Aaron Durbine3834422013-03-28 20:48:51 -0500597 a1 = 0;
Aaron Durbinbb4e79a2013-03-26 14:09:47 -0500598
Aaron Durbine3834422013-03-28 20:48:51 -0500599 /* If the range starts above 4GiB the processing is done. */
600 if (!var_state->above4gb && a1 >= RANGE_4GB)
601 return;
Aaron Durbinbb4e79a2013-03-26 14:09:47 -0500602
Aaron Durbine3834422013-03-28 20:48:51 -0500603 /* Clip the upper address to 4GiB if addresses above 4GiB
604 * are not being processed. */
605 if (!var_state->above4gb && c2 > RANGE_4GB)
606 c2 = RANGE_4GB;
Aaron Durbinbb4e79a2013-03-26 14:09:47 -0500607
Aaron Durbine3834422013-03-28 20:48:51 -0500608 /* Don't align up or down on the range if it is smaller
609 * than the minimum granularity. */
610 if ((c2 - a1) < MTRR_MIN_ALIGN) {
611 calc_var_mtrr_range(var_state, a1, c2 - a1, mtrr_type);
612 return;
Aaron Durbinbb4e79a2013-03-26 14:09:47 -0500613 }
Aaron Durbine3834422013-03-28 20:48:51 -0500614
615 b1 = a2 = ALIGN_UP(a1, MTRR_MIN_ALIGN);
616 b2 = c1 = ALIGN_DOWN(c2, MTRR_MIN_ALIGN);
617
618 calc_var_mtrr_range(var_state, a1, a2 - a1, mtrr_type);
619 calc_var_mtrr_range(var_state, b1, b2 - b1, mtrr_type);
620 calc_var_mtrr_range(var_state, c1, c2 - c1, mtrr_type);
Aaron Durbinbb4e79a2013-03-26 14:09:47 -0500621}
622
Aaron Durbin5b9e3b62014-02-05 16:00:43 -0600623static void __calc_var_mtrrs(struct memranges *addr_space,
624 int above4gb, int address_bits,
625 int *num_def_wb_mtrrs, int *num_def_uc_mtrrs)
Aaron Durbinbb4e79a2013-03-26 14:09:47 -0500626{
627 int wb_deftype_count;
628 int uc_deftype_count;
Aaron Durbine3834422013-03-28 20:48:51 -0500629 struct range_entry *r;
Eric Biedermanf8a2ddd2004-10-30 08:05:41 +0000630 struct var_mtrr_state var_state;
Eric Biedermanf8a2ddd2004-10-30 08:05:41 +0000631
Aaron Durbinbb4e79a2013-03-26 14:09:47 -0500632 /* The default MTRR cacheability type is determined by calculating
Paul Menzel4fe98132014-01-25 15:55:28 +0100633 * the number of MTRRs required for each MTRR type as if it was the
Aaron Durbinbb4e79a2013-03-26 14:09:47 -0500634 * default. */
635 var_state.addr_space = addr_space;
Scott Duplichanf3cce2f2010-11-13 19:07:59 +0000636 var_state.above4gb = above4gb;
Aaron Durbinbb4e79a2013-03-26 14:09:47 -0500637 var_state.address_bits = address_bits;
Gabe Black7756fe72014-02-25 01:40:34 -0800638 var_state.prepare_msrs = 0;
Stefan Reinauer7f86ed12009-02-12 16:02:16 +0000639
Aaron Durbine3834422013-03-28 20:48:51 -0500640 wb_deftype_count = 0;
641 uc_deftype_count = 0;
Duncan Laurie7389fa92011-12-22 10:59:40 -0800642
Aaron Durbine3834422013-03-28 20:48:51 -0500643 /*
644 * For each range do 3 calculations:
645 * 1. UC as default type with no holes at top of range.
646 * 2. UC as default using holes at top of range.
647 * 3. WB as default.
Martin Roth4c3ab732013-07-08 16:23:54 -0600648 * The lowest count is then used as default after totaling all
649 * MTRRs. Note that the optimal algorithm for UC default is marked in
Aaron Durbine3834422013-03-28 20:48:51 -0500650 * the tag of each range regardless of final decision. UC takes
Martin Roth4c3ab732013-07-08 16:23:54 -0600651 * precedence in the MTRR architecture. Therefore, only holes can be
Aaron Durbine3834422013-03-28 20:48:51 -0500652 * used when the type of the region is MTRR_TYPE_WRBACK with
653 * MTRR_TYPE_UNCACHEABLE as the default type.
654 */
655 memranges_each_entry(r, var_state.addr_space) {
656 int mtrr_type;
657
658 mtrr_type = range_entry_mtrr_type(r);
659
660 if (mtrr_type != MTRR_TYPE_UNCACHEABLE) {
661 int uc_hole_count;
662 int uc_no_hole_count;
663
664 var_state.def_mtrr_type = MTRR_TYPE_UNCACHEABLE;
665 var_state.mtrr_index = 0;
666
667 /* No hole calculation. */
668 calc_var_mtrrs_without_hole(&var_state, r);
669 uc_no_hole_count = var_state.mtrr_index;
670
671 /* Hole calculation only if type is WB. The 64 number
672 * is a count that is unachievable, thus making it
673 * a default large number in the case of not doing
674 * the hole calculation. */
675 uc_hole_count = 64;
676 if (mtrr_type == MTRR_TYPE_WRBACK) {
677 var_state.mtrr_index = 0;
678 calc_var_mtrrs_with_hole(&var_state, r);
679 uc_hole_count = var_state.mtrr_index;
680 }
681
682 /* Mark the entry with the optimal algorithm. */
683 if (uc_no_hole_count < uc_hole_count) {
684 uc_deftype_count += uc_no_hole_count;
685 } else {
686 unsigned long new_tag;
687
688 new_tag = mtrr_type | MTRR_RANGE_UC_USE_HOLE;
689 range_entry_update_tag(r, new_tag);
690 uc_deftype_count += uc_hole_count;
691 }
692 }
693
694 if (mtrr_type != MTRR_TYPE_WRBACK) {
695 var_state.mtrr_index = 0;
696 var_state.def_mtrr_type = MTRR_TYPE_WRBACK;
697 calc_var_mtrrs_without_hole(&var_state, r);
698 wb_deftype_count += var_state.mtrr_index;
699 }
700 }
Aaron Durbin5b9e3b62014-02-05 16:00:43 -0600701 *num_def_wb_mtrrs = wb_deftype_count;
702 *num_def_uc_mtrrs = uc_deftype_count;
703}
704
705static int calc_var_mtrrs(struct memranges *addr_space,
706 int above4gb, int address_bits)
707{
708 int wb_deftype_count = 0;
709 int uc_deftype_count = 0;
710
711 __calc_var_mtrrs(addr_space, above4gb, address_bits, &wb_deftype_count,
712 &uc_deftype_count);
713
714 if (wb_deftype_count > bios_mtrrs && uc_deftype_count > bios_mtrrs) {
715 printk(BIOS_DEBUG, "MTRR: Removing WRCOMB type. "
716 "WB/UC MTRR counts: %d/%d > %d.\n",
717 wb_deftype_count, uc_deftype_count, bios_mtrrs);
718 memranges_update_tag(addr_space, MTRR_TYPE_WRCOMB,
719 MTRR_TYPE_UNCACHEABLE);
720 __calc_var_mtrrs(addr_space, above4gb, address_bits,
721 &wb_deftype_count, &uc_deftype_count);
722 }
Scott Duplichanf3cce2f2010-11-13 19:07:59 +0000723
Aaron Durbinbb4e79a2013-03-26 14:09:47 -0500724 printk(BIOS_DEBUG, "MTRR: default type WB/UC MTRR counts: %d/%d.\n",
725 wb_deftype_count, uc_deftype_count);
Kyösti Mälkkiffc1fb32012-07-11 14:40:19 +0300726
Aaron Durbinbb4e79a2013-03-26 14:09:47 -0500727 if (wb_deftype_count < uc_deftype_count) {
728 printk(BIOS_DEBUG, "MTRR: WB selected as default type.\n");
729 return MTRR_TYPE_WRBACK;
730 }
731 printk(BIOS_DEBUG, "MTRR: UC selected as default type.\n");
732 return MTRR_TYPE_UNCACHEABLE;
733}
Kyösti Mälkkiffc1fb32012-07-11 14:40:19 +0300734
Gabe Black7756fe72014-02-25 01:40:34 -0800735static void prepare_var_mtrrs(struct memranges *addr_space, int def_type,
736 int above4gb, int address_bits,
737 struct var_mtrr_solution *sol)
Aaron Durbinbb4e79a2013-03-26 14:09:47 -0500738{
Aaron Durbine3834422013-03-28 20:48:51 -0500739 struct range_entry *r;
Aaron Durbinbb4e79a2013-03-26 14:09:47 -0500740 struct var_mtrr_state var_state;
Aaron Durbinbb4e79a2013-03-26 14:09:47 -0500741
742 var_state.addr_space = addr_space;
743 var_state.above4gb = above4gb;
744 var_state.address_bits = address_bits;
Gabe Black7756fe72014-02-25 01:40:34 -0800745 /* Prepare the MSRs. */
746 var_state.prepare_msrs = 1;
Aaron Durbinbb4e79a2013-03-26 14:09:47 -0500747 var_state.mtrr_index = 0;
748 var_state.def_mtrr_type = def_type;
Gabe Black7756fe72014-02-25 01:40:34 -0800749 var_state.regs = &sol->regs[0];
Aaron Durbine3834422013-03-28 20:48:51 -0500750
751 memranges_each_entry(r, var_state.addr_space) {
752 if (range_entry_mtrr_type(r) == def_type)
753 continue;
754
755 if (def_type == MTRR_TYPE_UNCACHEABLE &&
756 (range_entry_tag(r) & MTRR_RANGE_UC_USE_HOLE))
757 calc_var_mtrrs_with_hole(&var_state, r);
758 else
759 calc_var_mtrrs_without_hole(&var_state, r);
760 }
Aaron Durbinbb4e79a2013-03-26 14:09:47 -0500761
Gabe Black7756fe72014-02-25 01:40:34 -0800762 /* Update the solution. */
763 sol->num_used = var_state.mtrr_index;
764}
765
766static void commit_var_mtrrs(const struct var_mtrr_solution *sol)
767{
768 int i;
769
Isaac Christensen81f90c52014-09-24 14:59:32 -0600770 /* Write out the variable MTRRs. */
Gabe Black7756fe72014-02-25 01:40:34 -0800771 disable_cache();
772 for (i = 0; i < sol->num_used; i++) {
Alexandru Gagniuc86091f92015-09-30 20:23:09 -0700773 wrmsr(MTRR_PHYS_BASE(i), sol->regs[i].base);
774 wrmsr(MTRR_PHYS_MASK(i), sol->regs[i].mask);
Gabe Black7756fe72014-02-25 01:40:34 -0800775 }
776 /* Clear the ones that are unused. */
777 for (; i < total_mtrrs; i++)
Aaron Durbinbb4e79a2013-03-26 14:09:47 -0500778 clear_var_mtrr(i);
Isaac Christensen81f90c52014-09-24 14:59:32 -0600779 enable_var_mtrr(sol->mtrr_default_type);
Gabe Black7756fe72014-02-25 01:40:34 -0800780 enable_cache();
781
Aaron Durbinbb4e79a2013-03-26 14:09:47 -0500782}
783
784void x86_setup_var_mtrrs(unsigned int address_bits, unsigned int above4gb)
785{
Gabe Black7756fe72014-02-25 01:40:34 -0800786 static struct var_mtrr_solution *sol = NULL;
Aaron Durbinbb4e79a2013-03-26 14:09:47 -0500787 struct memranges *addr_space;
788
789 addr_space = get_physical_address_space();
790
Gabe Black7756fe72014-02-25 01:40:34 -0800791 if (sol == NULL) {
Gabe Black7756fe72014-02-25 01:40:34 -0800792 sol = &mtrr_global_solution;
793 sol->mtrr_default_type =
Aaron Durbinbb4e79a2013-03-26 14:09:47 -0500794 calc_var_mtrrs(addr_space, !!above4gb, address_bits);
Gabe Black7756fe72014-02-25 01:40:34 -0800795 prepare_var_mtrrs(addr_space, sol->mtrr_default_type,
796 !!above4gb, address_bits, sol);
Eric Biedermanfcd5ace2004-10-14 19:29:29 +0000797 }
Stefan Reinauer00093a82011-11-02 16:12:34 -0700798
Gabe Black7756fe72014-02-25 01:40:34 -0800799 commit_var_mtrrs(sol);
Eric Biedermanfcd5ace2004-10-14 19:29:29 +0000800}
801
Sven Schnelleadfbcb792012-01-10 12:01:43 +0100802void x86_setup_mtrrs(void)
Yinghai Lu13f1c2a2005-07-08 02:49:49 +0000803{
Sven Schnelleadfbcb792012-01-10 12:01:43 +0100804 int address_size;
Aaron Durbine63be892016-03-07 16:05:36 -0600805
Yinghai Lu13f1c2a2005-07-08 02:49:49 +0000806 x86_setup_fixed_mtrrs();
Sven Schnelleadfbcb792012-01-10 12:01:43 +0100807 address_size = cpu_phys_address_size();
Aaron Durbine63be892016-03-07 16:05:36 -0600808 printk(BIOS_DEBUG, "CPU physical address size: %d bits\n",
809 address_size);
810 /* Always handle addresses above 4GiB. */
Sven Schnelleadfbcb792012-01-10 12:01:43 +0100811 x86_setup_var_mtrrs(address_size, 1);
Yinghai Lu13f1c2a2005-07-08 02:49:49 +0000812}
813
Aaron Durbine63be892016-03-07 16:05:36 -0600814void x86_setup_mtrrs_with_detect(void)
815{
816 detect_var_mtrrs();
817 x86_setup_mtrrs();
818}
819
Kyösti Mälkki38a8fb02014-06-30 13:48:18 +0300820void x86_mtrr_check(void)
Eric Biedermanfcd5ace2004-10-14 19:29:29 +0000821{
822 /* Only Pentium Pro and later have MTRR */
823 msr_t msr;
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000824 printk(BIOS_DEBUG, "\nMTRR check\n");
Eric Biedermanfcd5ace2004-10-14 19:29:29 +0000825
Alexandru Gagniuc86091f92015-09-30 20:23:09 -0700826 msr = rdmsr(MTRR_DEF_TYPE_MSR);
Eric Biedermanfcd5ace2004-10-14 19:29:29 +0000827
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000828 printk(BIOS_DEBUG, "Fixed MTRRs : ");
Alexandru Gagniuc86091f92015-09-30 20:23:09 -0700829 if (msr.lo & MTRR_DEF_TYPE_FIX_EN)
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000830 printk(BIOS_DEBUG, "Enabled\n");
Eric Biedermanfcd5ace2004-10-14 19:29:29 +0000831 else
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000832 printk(BIOS_DEBUG, "Disabled\n");
Eric Biedermanfcd5ace2004-10-14 19:29:29 +0000833
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000834 printk(BIOS_DEBUG, "Variable MTRRs: ");
Alexandru Gagniuc86091f92015-09-30 20:23:09 -0700835 if (msr.lo & MTRR_DEF_TYPE_EN)
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000836 printk(BIOS_DEBUG, "Enabled\n");
Eric Biedermanfcd5ace2004-10-14 19:29:29 +0000837 else
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000838 printk(BIOS_DEBUG, "Disabled\n");
Eric Biedermanfcd5ace2004-10-14 19:29:29 +0000839
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000840 printk(BIOS_DEBUG, "\n");
Eric Biedermanfcd5ace2004-10-14 19:29:29 +0000841
842 post_code(0x93);
Eric Biedermanfcd5ace2004-10-14 19:29:29 +0000843}