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