1#include <linux/init.h>
2#include <linux/mm.h>
3#include <asm/mtrr.h>
4#include <asm/msr.h>
5
6#include "mtrr.h"
7
8static void
9amd_get_mtrr(unsigned int reg, unsigned long *base,
10 unsigned long *size, mtrr_type *type)
11{
12 unsigned long low, high;
13
14 rdmsr(MSR_K6_UWCCR, low, high);
15
16 if (reg == 1)
17 low = high;
18
19 *base = (low & 0xFFFE0000) >> PAGE_SHIFT;
20 *type = 0;
21 if (low & 1)
22 *type = MTRR_TYPE_UNCACHABLE;
23 if (low & 2)
24 *type = MTRR_TYPE_WRCOMB;
25 if (!(low & 3)) {
26 *size = 0;
27 return;
28 }
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44 low = (~low) & 0x1FFFC;
45 *size = (low + 4) << (15 - PAGE_SHIFT);
46}
47
48
49
50
51
52
53
54
55
56
57
58static void
59amd_set_mtrr(unsigned int reg, unsigned long base, unsigned long size, mtrr_type type)
60{
61 u32 regs[2];
62
63
64
65
66 rdmsr(MSR_K6_UWCCR, regs[0], regs[1]);
67
68
69
70 if (size == 0) {
71 regs[reg] = 0;
72 } else {
73
74
75
76
77
78
79
80
81
82 regs[reg] = (-size >> (15 - PAGE_SHIFT) & 0x0001FFFC)
83 | (base << PAGE_SHIFT) | (type + 1);
84 }
85
86
87
88
89
90 wbinvd();
91 wrmsr(MSR_K6_UWCCR, regs[0], regs[1]);
92}
93
94static int
95amd_validate_add_page(unsigned long base, unsigned long size, unsigned int type)
96{
97
98
99
100
101
102
103
104
105 if (type > MTRR_TYPE_WRCOMB || size < (1 << (17 - PAGE_SHIFT))
106 || (size & ~(size - 1)) - size || (base & (size - 1)))
107 return -EINVAL;
108 return 0;
109}
110
111static struct mtrr_ops amd_mtrr_ops = {
112 .vendor = X86_VENDOR_AMD,
113 .set = amd_set_mtrr,
114 .get = amd_get_mtrr,
115 .get_free_region = generic_get_free_region,
116 .validate_add_page = amd_validate_add_page,
117 .have_wrcomb = positive_have_wrcomb,
118};
119
120int __init amd_init_mtrr(void)
121{
122 set_mtrr_ops(&amd_mtrr_ops);
123 return 0;
124}
125