generic.c 20.9 KB
Newer Older
1 2
/*
 * This only handles 32bit MTRR on 32bit hosts. This is strictly wrong
L
Lucas De Marchi 已提交
3
 * because MTRRs can span up to 40 bits (36bits on most modern x86)
4 5 6 7
 */
#define DEBUG

#include <linux/module.h>
L
Linus Torvalds 已提交
8
#include <linux/init.h>
9
#include <linux/io.h>
L
Linus Torvalds 已提交
10
#include <linux/mm.h>
11

D
Dave Jones 已提交
12
#include <asm/processor-flags.h>
13
#include <asm/cpufeature.h>
L
Linus Torvalds 已提交
14
#include <asm/tlbflush.h>
15 16
#include <asm/mtrr.h>
#include <asm/msr.h>
17
#include <asm/pat.h>
18

L
Linus Torvalds 已提交
19 20
#include "mtrr.h"

21
struct fixed_range_block {
22 23
	int base_msr;		/* start address of an MTRR block */
	int ranges;		/* number of MTRRs in this block  */
24 25 26
};

static struct fixed_range_block fixed_range_blocks[] = {
27 28 29
	{ MSR_MTRRfix64K_00000, 1 }, /* one   64k MTRR  */
	{ MSR_MTRRfix16K_80000, 2 }, /* two   16k MTRRs */
	{ MSR_MTRRfix4K_C0000,  8 }, /* eight  4k MTRRs */
30 31 32
	{}
};

L
Linus Torvalds 已提交
33
static unsigned long smp_changes_mask;
34
static int mtrr_state_set;
35
u64 mtrr_tom2;
L
Linus Torvalds 已提交
36

37
struct mtrr_state_type mtrr_state;
S
Sheng Yang 已提交
38 39
EXPORT_SYMBOL_GPL(mtrr_state);

40
/*
41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65
 * BIOS is expected to clear MtrrFixDramModEn bit, see for example
 * "BIOS and Kernel Developer's Guide for the AMD Athlon 64 and AMD
 * Opteron Processors" (26094 Rev. 3.30 February 2006), section
 * "13.2.1.2 SYSCFG Register": "The MtrrFixDramModEn bit should be set
 * to 1 during BIOS initalization of the fixed MTRRs, then cleared to
 * 0 for operation."
 */
static inline void k8_check_syscfg_dram_mod_en(void)
{
	u32 lo, hi;

	if (!((boot_cpu_data.x86_vendor == X86_VENDOR_AMD) &&
	      (boot_cpu_data.x86 >= 0x0f)))
		return;

	rdmsr(MSR_K8_SYSCFG, lo, hi);
	if (lo & K8_MTRRFIXRANGE_DRAM_MODIFY) {
		printk(KERN_ERR FW_WARN "MTRR: CPU %u: SYSCFG[MtrrFixDramModEn]"
		       " not cleared by BIOS, clearing this bit\n",
		       smp_processor_id());
		lo &= ~K8_MTRRFIXRANGE_DRAM_MODIFY;
		mtrr_wrmsr(MSR_K8_SYSCFG, lo, hi);
	}
}

66 67 68 69 70 71 72 73 74 75 76 77
/* Get the size of contiguous MTRR range */
static u64 get_mtrr_size(u64 mask)
{
	u64 size;

	mask >>= PAGE_SHIFT;
	mask |= size_or_mask;
	size = -mask;
	size <<= PAGE_SHIFT;
	return size;
}

78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104
/*
 * Check and return the effective type for MTRR-MTRR type overlap.
 * Returns 1 if the effective type is UNCACHEABLE, else returns 0
 */
static int check_type_overlap(u8 *prev, u8 *curr)
{
	if (*prev == MTRR_TYPE_UNCACHABLE || *curr == MTRR_TYPE_UNCACHABLE) {
		*prev = MTRR_TYPE_UNCACHABLE;
		*curr = MTRR_TYPE_UNCACHABLE;
		return 1;
	}

	if ((*prev == MTRR_TYPE_WRBACK && *curr == MTRR_TYPE_WRTHROUGH) ||
	    (*prev == MTRR_TYPE_WRTHROUGH && *curr == MTRR_TYPE_WRBACK)) {
		*prev = MTRR_TYPE_WRTHROUGH;
		*curr = MTRR_TYPE_WRTHROUGH;
	}

	if (*prev != *curr) {
		*prev = MTRR_TYPE_UNCACHABLE;
		*curr = MTRR_TYPE_UNCACHABLE;
		return 1;
	}

	return 0;
}

105
/*
106 107 108 109 110
 * Error/Semi-error returns:
 * 0xFF - when MTRR is not enabled
 * *repeat == 1 implies [start:end] spanned across MTRR range and type returned
 *		corresponds only to [start:*partial_end].
 *		Caller has to lookup again for [*partial_end:end].
111
 */
112
static u8 __mtrr_type_lookup(u64 start, u64 end, u64 *partial_end, int *repeat)
113 114 115 116 117
{
	int i;
	u64 base, mask;
	u8 prev_match, curr_match;

118
	*repeat = 0;
119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151
	if (!mtrr_state_set)
		return 0xFF;

	if (!mtrr_state.enabled)
		return 0xFF;

	/* Make end inclusive end, instead of exclusive */
	end--;

	/* Look in fixed ranges. Just return the type as per start */
	if (mtrr_state.have_fixed && (start < 0x100000)) {
		int idx;

		if (start < 0x80000) {
			idx = 0;
			idx += (start >> 16);
			return mtrr_state.fixed_ranges[idx];
		} else if (start < 0xC0000) {
			idx = 1 * 8;
			idx += ((start - 0x80000) >> 14);
			return mtrr_state.fixed_ranges[idx];
		} else if (start < 0x1000000) {
			idx = 3 * 8;
			idx += ((start - 0xC0000) >> 12);
			return mtrr_state.fixed_ranges[idx];
		}
	}

	/*
	 * Look in variable ranges
	 * Look of multiple ranges matching this address and pick type
	 * as per MTRR precedence
	 */
152
	if (!(mtrr_state.enabled & 2))
153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168
		return mtrr_state.def_type;

	prev_match = 0xFF;
	for (i = 0; i < num_var_ranges; ++i) {
		unsigned short start_state, end_state;

		if (!(mtrr_state.var_ranges[i].mask_lo & (1 << 11)))
			continue;

		base = (((u64)mtrr_state.var_ranges[i].base_hi) << 32) +
		       (mtrr_state.var_ranges[i].base_lo & PAGE_MASK);
		mask = (((u64)mtrr_state.var_ranges[i].mask_hi) << 32) +
		       (mtrr_state.var_ranges[i].mask_lo & PAGE_MASK);

		start_state = ((start & mask) == (base & mask));
		end_state = ((end & mask) == (base & mask));
169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196

		if (start_state != end_state) {
			/*
			 * We have start:end spanning across an MTRR.
			 * We split the region into
			 * either
			 * (start:mtrr_end) (mtrr_end:end)
			 * or
			 * (start:mtrr_start) (mtrr_start:end)
			 * depending on kind of overlap.
			 * Return the type for first region and a pointer to
			 * the start of second region so that caller will
			 * lookup again on the second region.
			 * Note: This way we handle multiple overlaps as well.
			 */
			if (start_state)
				*partial_end = base + get_mtrr_size(mask);
			else
				*partial_end = base;

			if (unlikely(*partial_end <= start)) {
				WARN_ON(1);
				*partial_end = start + PAGE_SIZE;
			}

			end = *partial_end - 1; /* end is inclusive */
			*repeat = 1;
		}
197

198
		if ((start & mask) != (base & mask))
199 200 201 202 203 204 205 206
			continue;

		curr_match = mtrr_state.var_ranges[i].base_lo & 0xff;
		if (prev_match == 0xFF) {
			prev_match = curr_match;
			continue;
		}

207 208
		if (check_type_overlap(&prev_match, &curr_match))
			return curr_match;
209 210
	}

211 212
	if (mtrr_tom2) {
		if (start >= (1ULL<<32) && (end < mtrr_tom2))
213 214 215
			return MTRR_TYPE_WRBACK;
	}

216 217 218 219 220 221
	if (prev_match != 0xFF)
		return prev_match;

	return mtrr_state.def_type;
}

222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251
/*
 * Returns the effective MTRR type for the region
 * Error return:
 * 0xFF - when MTRR is not enabled
 */
u8 mtrr_type_lookup(u64 start, u64 end)
{
	u8 type, prev_type;
	int repeat;
	u64 partial_end;

	type = __mtrr_type_lookup(start, end, &partial_end, &repeat);

	/*
	 * Common path is with repeat = 0.
	 * However, we can have cases where [start:end] spans across some
	 * MTRR range. Do repeated lookups for that case here.
	 */
	while (repeat) {
		prev_type = type;
		start = partial_end;
		type = __mtrr_type_lookup(start, end, &partial_end, &repeat);

		if (check_type_overlap(&prev_type, &type))
			return type;
	}

	return type;
}

252
/* Get the MSR pair relating to a var range */
253
static void
L
Linus Torvalds 已提交
254 255 256 257 258 259
get_mtrr_var_range(unsigned int index, struct mtrr_var_range *vr)
{
	rdmsr(MTRRphysBase_MSR(index), vr->base_lo, vr->base_hi);
	rdmsr(MTRRphysMask_MSR(index), vr->mask_lo, vr->mask_hi);
}

260
/* Fill the MSR pair relating to a var range */
261 262 263 264 265 266 267 268 269 270 271 272 273
void fill_mtrr_var_range(unsigned int index,
		u32 base_lo, u32 base_hi, u32 mask_lo, u32 mask_hi)
{
	struct mtrr_var_range *vr;

	vr = mtrr_state.var_ranges;

	vr[index].base_lo = base_lo;
	vr[index].base_hi = base_hi;
	vr[index].mask_lo = mask_lo;
	vr[index].mask_hi = mask_hi;
}

274
static void get_fixed_ranges(mtrr_type *frs)
L
Linus Torvalds 已提交
275
{
276
	unsigned int *p = (unsigned int *)frs;
L
Linus Torvalds 已提交
277 278
	int i;

279 280
	k8_check_syscfg_dram_mod_en();

281
	rdmsr(MSR_MTRRfix64K_00000, p[0], p[1]);
L
Linus Torvalds 已提交
282 283

	for (i = 0; i < 2; i++)
284
		rdmsr(MSR_MTRRfix16K_80000 + i, p[2 + i * 2], p[3 + i * 2]);
L
Linus Torvalds 已提交
285
	for (i = 0; i < 8; i++)
286
		rdmsr(MSR_MTRRfix4K_C0000 + i, p[6 + i * 2], p[7 + i * 2]);
L
Linus Torvalds 已提交
287 288
}

289 290
void mtrr_save_fixed_ranges(void *info)
{
A
Andrew Morton 已提交
291 292
	if (cpu_has_mtrr)
		get_fixed_ranges(mtrr_state.fixed_ranges);
293 294
}

295 296 297 298 299 300 301 302 303
static unsigned __initdata last_fixed_start;
static unsigned __initdata last_fixed_end;
static mtrr_type __initdata last_fixed_type;

static void __init print_fixed_last(void)
{
	if (!last_fixed_end)
		return;

304 305
	pr_debug("  %05X-%05X %s\n", last_fixed_start,
		 last_fixed_end - 1, mtrr_attrib_to_str(last_fixed_type));
306 307 308 309 310

	last_fixed_end = 0;
}

static void __init update_fixed_last(unsigned base, unsigned end,
311
				     mtrr_type type)
312 313 314 315 316 317
{
	last_fixed_start = base;
	last_fixed_end = end;
	last_fixed_type = type;
}

318 319
static void __init
print_fixed(unsigned base, unsigned step, const mtrr_type *types)
J
Jan Beulich 已提交
320 321 322
{
	unsigned i;

323 324 325 326 327 328 329 330 331 332 333 334 335
	for (i = 0; i < 8; ++i, ++types, base += step) {
		if (last_fixed_end == 0) {
			update_fixed_last(base, base + step, *types);
			continue;
		}
		if (last_fixed_end == base && last_fixed_type == *types) {
			last_fixed_end = base + step;
			continue;
		}
		/* new segments: gap or different type */
		print_fixed_last();
		update_fixed_last(base, base + step, *types);
	}
J
Jan Beulich 已提交
336 337
}

338 339 340
static void prepare_set(void);
static void post_set(void);

Y
Yinghai Lu 已提交
341 342 343 344 345
static void __init print_mtrr_state(void)
{
	unsigned int i;
	int high_width;

346 347
	pr_debug("MTRR default type: %s\n",
		 mtrr_attrib_to_str(mtrr_state.def_type));
Y
Yinghai Lu 已提交
348
	if (mtrr_state.have_fixed) {
349 350
		pr_debug("MTRR fixed ranges %sabled:\n",
			 mtrr_state.enabled & 1 ? "en" : "dis");
Y
Yinghai Lu 已提交
351 352
		print_fixed(0x00000, 0x10000, mtrr_state.fixed_ranges + 0);
		for (i = 0; i < 2; ++i)
353 354
			print_fixed(0x80000 + i * 0x20000, 0x04000,
				    mtrr_state.fixed_ranges + (i + 1) * 8);
Y
Yinghai Lu 已提交
355
		for (i = 0; i < 8; ++i)
356 357
			print_fixed(0xC0000 + i * 0x08000, 0x01000,
				    mtrr_state.fixed_ranges + (i + 3) * 8);
358 359 360

		/* tail */
		print_fixed_last();
Y
Yinghai Lu 已提交
361
	}
362 363
	pr_debug("MTRR variable ranges %sabled:\n",
		 mtrr_state.enabled & 2 ? "en" : "dis");
364
	high_width = (__ffs64(size_or_mask) - (32 - PAGE_SHIFT) + 3) / 4;
365

Y
Yinghai Lu 已提交
366 367
	for (i = 0; i < num_var_ranges; ++i) {
		if (mtrr_state.var_ranges[i].mask_lo & (1 << 11))
368 369 370 371 372 373 374 375 376
			pr_debug("  %u base %0*X%05X000 mask %0*X%05X000 %s\n",
				 i,
				 high_width,
				 mtrr_state.var_ranges[i].base_hi,
				 mtrr_state.var_ranges[i].base_lo >> 12,
				 high_width,
				 mtrr_state.var_ranges[i].mask_hi,
				 mtrr_state.var_ranges[i].mask_lo >> 12,
				 mtrr_attrib_to_str(mtrr_state.var_ranges[i].base_lo & 0xff));
Y
Yinghai Lu 已提交
377
		else
378
			pr_debug("  %u disabled\n", i);
Y
Yinghai Lu 已提交
379
	}
380 381
	if (mtrr_tom2)
		pr_debug("TOM2: %016llx aka %lldM\n", mtrr_tom2, mtrr_tom2>>20);
Y
Yinghai Lu 已提交
382 383
}

384
/* Grab all of the MTRR state for this CPU into *state */
385
void __init get_mtrr_state(void)
L
Linus Torvalds 已提交
386 387
{
	struct mtrr_var_range *vrs;
388
	unsigned long flags;
389 390
	unsigned lo, dummy;
	unsigned int i;
L
Linus Torvalds 已提交
391 392 393

	vrs = mtrr_state.var_ranges;

394
	rdmsr(MSR_MTRRcap, lo, dummy);
J
Jan Beulich 已提交
395 396
	mtrr_state.have_fixed = (lo >> 8) & 1;

L
Linus Torvalds 已提交
397 398
	for (i = 0; i < num_var_ranges; i++)
		get_mtrr_var_range(i, &vrs[i]);
J
Jan Beulich 已提交
399 400
	if (mtrr_state.have_fixed)
		get_fixed_ranges(mtrr_state.fixed_ranges);
L
Linus Torvalds 已提交
401

402
	rdmsr(MSR_MTRRdefType, lo, dummy);
L
Linus Torvalds 已提交
403 404
	mtrr_state.def_type = (lo & 0xff);
	mtrr_state.enabled = (lo & 0xc00) >> 10;
J
Jan Beulich 已提交
405

406
	if (amd_special_default_mtrr()) {
407
		unsigned low, high;
408

409
		/* TOP_MEM2 */
410
		rdmsr(MSR_K8_TOP_MEM2, low, high);
411 412 413
		mtrr_tom2 = high;
		mtrr_tom2 <<= 32;
		mtrr_tom2 |= low;
Y
Yinghai Lu 已提交
414
		mtrr_tom2 &= 0xffffff800000ULL;
415
	}
Y
Yinghai Lu 已提交
416 417 418

	print_mtrr_state();

419 420 421 422 423 424 425 426 427 428
	mtrr_state_set = 1;

	/* PAT setup for BP. We need to go through sync steps here */
	local_irq_save(flags);
	prepare_set();

	pat_init();

	post_set();
	local_irq_restore(flags);
L
Linus Torvalds 已提交
429 430
}

431
/* Some BIOS's are messed up and don't set all MTRRs the same! */
L
Linus Torvalds 已提交
432 433 434 435 436 437 438
void __init mtrr_state_warn(void)
{
	unsigned long mask = smp_changes_mask;

	if (!mask)
		return;
	if (mask & MTRR_CHANGE_MASK_FIXED)
439
		pr_warning("mtrr: your CPUs had inconsistent fixed MTRR settings\n");
L
Linus Torvalds 已提交
440
	if (mask & MTRR_CHANGE_MASK_VARIABLE)
441
		pr_warning("mtrr: your CPUs had inconsistent variable MTRR settings\n");
L
Linus Torvalds 已提交
442
	if (mask & MTRR_CHANGE_MASK_DEFTYPE)
443 444
		pr_warning("mtrr: your CPUs had inconsistent MTRRdefType settings\n");

L
Linus Torvalds 已提交
445 446 447 448
	printk(KERN_INFO "mtrr: probably your BIOS does not setup all CPUs.\n");
	printk(KERN_INFO "mtrr: corrected configuration.\n");
}

449 450 451 452 453
/*
 * Doesn't attempt to pass an error out to MTRR users
 * because it's quite complicated in some cases and probably not
 * worth it because the best error handling is to ignore it.
 */
L
Linus Torvalds 已提交
454 455
void mtrr_wrmsr(unsigned msr, unsigned a, unsigned b)
{
456
	if (wrmsr_safe(msr, a, b) < 0) {
L
Linus Torvalds 已提交
457 458 459
		printk(KERN_ERR
			"MTRR: CPU %u: Writing MSR %x to %x:%x failed\n",
			smp_processor_id(), msr, a, b);
460
	}
L
Linus Torvalds 已提交
461 462
}

463
/**
464 465
 * set_fixed_range - checks & updates a fixed-range MTRR if it
 *		     differs from the value it should have
466 467 468
 * @msr: MSR address of the MTTR which should be checked and updated
 * @changed: pointer which indicates whether the MTRR needed to be changed
 * @msrwords: pointer to the MSR values which the MSR should have
469
 */
470
static void set_fixed_range(int msr, bool *changed, unsigned int *msrwords)
471 472 473 474 475 476 477
{
	unsigned lo, hi;

	rdmsr(msr, lo, hi);

	if (lo != msrwords[0] || hi != msrwords[1]) {
		mtrr_wrmsr(msr, msrwords[0], msrwords[1]);
478
		*changed = true;
479 480 481
	}
}

482 483 484 485 486 487 488 489
/**
 * generic_get_free_region - Get a free MTRR.
 * @base: The starting (base) address of the region.
 * @size: The size (in bytes) of the region.
 * @replace_reg: mtrr index to be replaced; set to invalid value if none.
 *
 * Returns: The index of the region on success, else negative on error.
 */
490 491
int
generic_get_free_region(unsigned long base, unsigned long size, int replace_reg)
L
Linus Torvalds 已提交
492
{
J
Jan Beulich 已提交
493
	unsigned long lbase, lsize;
494 495
	mtrr_type ltype;
	int i, max;
L
Linus Torvalds 已提交
496 497

	max = num_var_ranges;
J
Jan Beulich 已提交
498 499
	if (replace_reg >= 0 && replace_reg < max)
		return replace_reg;
500

L
Linus Torvalds 已提交
501 502 503 504 505
	for (i = 0; i < max; ++i) {
		mtrr_if->get(i, &lbase, &lsize, &ltype);
		if (lsize == 0)
			return i;
	}
506

L
Linus Torvalds 已提交
507 508 509
	return -ENOSPC;
}

A
Adrian Bunk 已提交
510
static void generic_get_mtrr(unsigned int reg, unsigned long *base,
J
Jan Beulich 已提交
511
			     unsigned long *size, mtrr_type *type)
L
Linus Torvalds 已提交
512
{
513 514 515
	u32 mask_lo, mask_hi, base_lo, base_hi;
	unsigned int hi;
	u64 tmp, mask;
L
Linus Torvalds 已提交
516

Y
Yinghai Lu 已提交
517 518 519 520
	/*
	 * get_mtrr doesn't need to update mtrr_state, also it could be called
	 * from any cpu, so try to print it out directly.
	 */
521
	get_cpu();
522

L
Linus Torvalds 已提交
523
	rdmsr(MTRRphysMask_MSR(reg), mask_lo, mask_hi);
Y
Yinghai Lu 已提交
524

L
Linus Torvalds 已提交
525
	if ((mask_lo & 0x800) == 0) {
526
		/*  Invalid (i.e. free) range */
L
Linus Torvalds 已提交
527 528 529
		*base = 0;
		*size = 0;
		*type = 0;
530
		goto out_put_cpu;
L
Linus Torvalds 已提交
531 532 533 534
	}

	rdmsr(MTRRphysBase_MSR(reg), base_lo, base_hi);

535
	/* Work out the shifted address mask: */
536 537
	tmp = (u64)mask_hi << (32 - PAGE_SHIFT) | mask_lo >> PAGE_SHIFT;
	mask = size_or_mask | tmp;
538 539

	/* Expand tmp with high bits to all 1s: */
540
	hi = fls64(tmp);
Y
Yinghai Lu 已提交
541
	if (hi > 0) {
542
		tmp |= ~((1ULL<<(hi - 1)) - 1);
Y
Yinghai Lu 已提交
543

544
		if (tmp != mask) {
A
Alan Cox 已提交
545
			printk(KERN_WARNING "mtrr: your BIOS has configured an incorrect mask, fixing it.\n");
546
			add_taint(TAINT_FIRMWARE_WORKAROUND, LOCKDEP_STILL_OK);
547
			mask = tmp;
Y
Yinghai Lu 已提交
548 549
		}
	}
L
Linus Torvalds 已提交
550

551 552 553 554
	/*
	 * This works correctly if size is a power of two, i.e. a
	 * contiguous range:
	 */
555 556
	*size = -mask;
	*base = (u64)base_hi << (32 - PAGE_SHIFT) | base_lo >> PAGE_SHIFT;
L
Linus Torvalds 已提交
557
	*type = base_lo & 0xff;
Y
Yinghai Lu 已提交
558

559 560
out_put_cpu:
	put_cpu();
L
Linus Torvalds 已提交
561 562
}

563
/**
564 565
 * set_fixed_ranges - checks & updates the fixed-range MTRRs if they
 *		      differ from the saved set
566
 * @frs: pointer to fixed-range MTRR values, saved by get_fixed_ranges()
567
 */
568
static int set_fixed_ranges(mtrr_type *frs)
L
Linus Torvalds 已提交
569
{
570
	unsigned long long *saved = (unsigned long long *)frs;
571
	bool changed = false;
572
	int block = -1, range;
L
Linus Torvalds 已提交
573

574 575
	k8_check_syscfg_dram_mod_en();

576 577 578 579 580
	while (fixed_range_blocks[++block].ranges) {
		for (range = 0; range < fixed_range_blocks[block].ranges; range++)
			set_fixed_range(fixed_range_blocks[block].base_msr + range,
					&changed, (unsigned int *)saved++);
	}
L
Linus Torvalds 已提交
581 582 583 584

	return changed;
}

585 586 587 588
/*
 * Set the MSR pair relating to a var range.
 * Returns true if changes are made.
 */
589
static bool set_mtrr_var_ranges(unsigned int index, struct mtrr_var_range *vr)
L
Linus Torvalds 已提交
590 591
{
	unsigned int lo, hi;
592
	bool changed = false;
L
Linus Torvalds 已提交
593 594 595

	rdmsr(MTRRphysBase_MSR(index), lo, hi);
	if ((vr->base_lo & 0xfffff0ffUL) != (lo & 0xfffff0ffUL)
596 597
	    || (vr->base_hi & (size_and_mask >> (32 - PAGE_SHIFT))) !=
		(hi & (size_and_mask >> (32 - PAGE_SHIFT)))) {
598

L
Linus Torvalds 已提交
599
		mtrr_wrmsr(MTRRphysBase_MSR(index), vr->base_lo, vr->base_hi);
600
		changed = true;
L
Linus Torvalds 已提交
601 602 603 604 605
	}

	rdmsr(MTRRphysMask_MSR(index), lo, hi);

	if ((vr->mask_lo & 0xfffff800UL) != (lo & 0xfffff800UL)
606 607
	    || (vr->mask_hi & (size_and_mask >> (32 - PAGE_SHIFT))) !=
		(hi & (size_and_mask >> (32 - PAGE_SHIFT)))) {
L
Linus Torvalds 已提交
608
		mtrr_wrmsr(MTRRphysMask_MSR(index), vr->mask_lo, vr->mask_hi);
609
		changed = true;
L
Linus Torvalds 已提交
610 611 612 613
	}
	return changed;
}

J
Jan Beulich 已提交
614 615
static u32 deftype_lo, deftype_hi;

616 617 618 619 620 621
/**
 * set_mtrr_state - Set the MTRR state for this CPU.
 *
 * NOTE: The CPU must already be in a safe state for MTRR changes.
 * RETURNS: 0 if no changes made, else a mask indicating what was changed.
 */
J
Jan Beulich 已提交
622
static unsigned long set_mtrr_state(void)
L
Linus Torvalds 已提交
623 624
{
	unsigned long change_mask = 0;
625
	unsigned int i;
L
Linus Torvalds 已提交
626

627
	for (i = 0; i < num_var_ranges; i++) {
L
Linus Torvalds 已提交
628 629
		if (set_mtrr_var_ranges(i, &mtrr_state.var_ranges[i]))
			change_mask |= MTRR_CHANGE_MASK_VARIABLE;
630
	}
L
Linus Torvalds 已提交
631

J
Jan Beulich 已提交
632
	if (mtrr_state.have_fixed && set_fixed_ranges(mtrr_state.fixed_ranges))
L
Linus Torvalds 已提交
633 634
		change_mask |= MTRR_CHANGE_MASK_FIXED;

635 636 637 638
	/*
	 * Set_mtrr_restore restores the old value of MTRRdefType,
	 * so to set it we fiddle with the saved value:
	 */
L
Linus Torvalds 已提交
639 640
	if ((deftype_lo & 0xff) != mtrr_state.def_type
	    || ((deftype_lo & 0xc00) >> 10) != mtrr_state.enabled) {
641 642 643

		deftype_lo = (deftype_lo & ~0xcff) | mtrr_state.def_type |
			     (mtrr_state.enabled << 10);
L
Linus Torvalds 已提交
644 645 646 647 648 649 650
		change_mask |= MTRR_CHANGE_MASK_DEFTYPE;
	}

	return change_mask;
}


651
static unsigned long cr4;
652
static DEFINE_RAW_SPINLOCK(set_atomicity_lock);
L
Linus Torvalds 已提交
653 654

/*
655 656 657 658 659
 * Since we are disabling the cache don't allow any interrupts,
 * they would run extremely slow and would only increase the pain.
 *
 * The caller must ensure that local interrupts are disabled and
 * are reenabled after post_set() has been called.
L
Linus Torvalds 已提交
660
 */
661
static void prepare_set(void) __acquires(set_atomicity_lock)
L
Linus Torvalds 已提交
662 663 664
{
	unsigned long cr0;

665 666 667 668 669 670
	/*
	 * Note that this is not ideal
	 * since the cache is only flushed/disabled for this CPU while the
	 * MTRRs are changed, but changing this requires more invasive
	 * changes to the way the kernel boots
	 */
L
Linus Torvalds 已提交
671

672
	raw_spin_lock(&set_atomicity_lock);
L
Linus Torvalds 已提交
673

674
	/* Enter the no-fill (CD=1, NW=0) cache mode and flush caches. */
D
Dave Jones 已提交
675
	cr0 = read_cr0() | X86_CR0_CD;
L
Linus Torvalds 已提交
676 677 678
	write_cr0(cr0);
	wbinvd();

679 680
	/* Save value of CR4 and clear Page Global Enable (bit 7) */
	if (cpu_has_pge) {
L
Linus Torvalds 已提交
681 682 683 684 685
		cr4 = read_cr4();
		write_cr4(cr4 & ~X86_CR4_PGE);
	}

	/* Flush all TLBs via a mov %cr3, %reg; mov %reg, %cr3 */
686
	count_vm_event(NR_TLB_LOCAL_FLUSH_ALL);
L
Linus Torvalds 已提交
687 688
	__flush_tlb();

689
	/* Save MTRR state */
690
	rdmsr(MSR_MTRRdefType, deftype_lo, deftype_hi);
L
Linus Torvalds 已提交
691

692
	/* Disable MTRRs, and set the default type to uncached */
693
	mtrr_wrmsr(MSR_MTRRdefType, deftype_lo & ~0xcff, deftype_hi);
694
	wbinvd();
L
Linus Torvalds 已提交
695 696
}

697
static void post_set(void) __releases(set_atomicity_lock)
L
Linus Torvalds 已提交
698
{
699
	/* Flush TLBs (no need to flush caches - they are disabled) */
700
	count_vm_event(NR_TLB_LOCAL_FLUSH_ALL);
L
Linus Torvalds 已提交
701 702 703
	__flush_tlb();

	/* Intel (P6) standard MTRRs */
704
	mtrr_wrmsr(MSR_MTRRdefType, deftype_lo, deftype_hi);
705 706

	/* Enable caches */
707
	write_cr0(read_cr0() & ~X86_CR0_CD);
L
Linus Torvalds 已提交
708

709 710
	/* Restore value of CR4 */
	if (cpu_has_pge)
L
Linus Torvalds 已提交
711
		write_cr4(cr4);
712
	raw_spin_unlock(&set_atomicity_lock);
L
Linus Torvalds 已提交
713 714 715 716 717 718 719 720 721 722 723
}

static void generic_set_all(void)
{
	unsigned long mask, count;
	unsigned long flags;

	local_irq_save(flags);
	prepare_set();

	/* Actually set the state */
J
Jan Beulich 已提交
724
	mask = set_mtrr_state();
L
Linus Torvalds 已提交
725

726 727 728
	/* also set PAT */
	pat_init();

L
Linus Torvalds 已提交
729 730 731
	post_set();
	local_irq_restore(flags);

732
	/* Use the atomic bitops to update the global mask */
L
Linus Torvalds 已提交
733 734 735 736 737
	for (count = 0; count < sizeof mask * 8; ++count) {
		if (mask & 0x01)
			set_bit(count, &smp_changes_mask);
		mask >>= 1;
	}
738

L
Linus Torvalds 已提交
739 740
}

741 742 743 744 745 746 747 748 749 750
/**
 * generic_set_mtrr - set variable MTRR register on the local CPU.
 *
 * @reg: The register to set.
 * @base: The base address of the region.
 * @size: The size of the region. If this is 0 the region is disabled.
 * @type: The type of the region.
 *
 * Returns nothing.
 */
L
Linus Torvalds 已提交
751 752 753 754
static void generic_set_mtrr(unsigned int reg, unsigned long base,
			     unsigned long size, mtrr_type type)
{
	unsigned long flags;
S
Shaohua Li 已提交
755 756 757
	struct mtrr_var_range *vr;

	vr = &mtrr_state.var_ranges[reg];
L
Linus Torvalds 已提交
758 759 760 761 762

	local_irq_save(flags);
	prepare_set();

	if (size == 0) {
763 764 765 766
		/*
		 * The invalid bit is kept in the mask, so we simply
		 * clear the relevant mask register to disable a range.
		 */
L
Linus Torvalds 已提交
767
		mtrr_wrmsr(MTRRphysMask_MSR(reg), 0, 0);
S
Shaohua Li 已提交
768
		memset(vr, 0, sizeof(struct mtrr_var_range));
L
Linus Torvalds 已提交
769
	} else {
S
Shaohua Li 已提交
770 771 772 773 774 775 776
		vr->base_lo = base << PAGE_SHIFT | type;
		vr->base_hi = (base & size_and_mask) >> (32 - PAGE_SHIFT);
		vr->mask_lo = -size << PAGE_SHIFT | 0x800;
		vr->mask_hi = (-size & size_and_mask) >> (32 - PAGE_SHIFT);

		mtrr_wrmsr(MTRRphysBase_MSR(reg), vr->base_lo, vr->base_hi);
		mtrr_wrmsr(MTRRphysMask_MSR(reg), vr->mask_lo, vr->mask_hi);
L
Linus Torvalds 已提交
777 778 779 780 781 782
	}

	post_set();
	local_irq_restore(flags);
}

783 784
int generic_validate_add_page(unsigned long base, unsigned long size,
			      unsigned int type)
L
Linus Torvalds 已提交
785 786 787
{
	unsigned long lbase, last;

788 789 790 791
	/*
	 * For Intel PPro stepping <= 7
	 * must be 4 MiB aligned and not touch 0x70000000 -> 0x7003FFFF
	 */
L
Linus Torvalds 已提交
792 793 794 795
	if (is_cpu(INTEL) && boot_cpu_data.x86 == 6 &&
	    boot_cpu_data.x86_model == 1 &&
	    boot_cpu_data.x86_mask <= 7) {
		if (base & ((1 << (22 - PAGE_SHIFT)) - 1)) {
796
			pr_warning("mtrr: base(0x%lx000) is not 4 MiB aligned\n", base);
L
Linus Torvalds 已提交
797 798
			return -EINVAL;
		}
799
		if (!(base + size < 0x70000 || base > 0x7003F) &&
L
Linus Torvalds 已提交
800 801
		    (type == MTRR_TYPE_WRCOMB
		     || type == MTRR_TYPE_WRBACK)) {
802
			pr_warning("mtrr: writable mtrr between 0x70000000 and 0x7003FFFF may hang the CPU.\n");
L
Linus Torvalds 已提交
803 804 805 806
			return -EINVAL;
		}
	}

807 808 809 810
	/*
	 * Check upper bits of base and last are equal and lower bits are 0
	 * for base and 1 for last
	 */
L
Linus Torvalds 已提交
811 812
	last = base + size - 1;
	for (lbase = base; !(lbase & 1) && (last & 1);
813 814
	     lbase = lbase >> 1, last = last >> 1)
		;
L
Linus Torvalds 已提交
815
	if (lbase != last) {
816
		pr_warning("mtrr: base(0x%lx000) is not aligned on a size(0x%lx000) boundary\n", base, size);
L
Linus Torvalds 已提交
817 818 819 820 821 822 823 824
		return -EINVAL;
	}
	return 0;
}

static int generic_have_wrcomb(void)
{
	unsigned long config, dummy;
825
	rdmsr(MSR_MTRRcap, config, dummy);
826
	return config & (1 << 10);
L
Linus Torvalds 已提交
827 828 829 830 831 832 833
}

int positive_have_wrcomb(void)
{
	return 1;
}

834 835
/*
 * Generic structure...
L
Linus Torvalds 已提交
836
 */
837
const struct mtrr_ops generic_mtrr_ops = {
838 839 840 841 842 843 844
	.use_intel_if		= 1,
	.set_all		= generic_set_all,
	.get			= generic_get_mtrr,
	.get_free_region	= generic_get_free_region,
	.set			= generic_set_mtrr,
	.validate_add_page	= generic_validate_add_page,
	.have_wrcomb		= generic_have_wrcomb,
L
Linus Torvalds 已提交
845
};