Linux Kernel
3.7.1
Main Page
Related Pages
Modules
Namespaces
Data Structures
Files
File List
Globals
All
Data Structures
Namespaces
Files
Functions
Variables
Typedefs
Enumerations
Enumerator
Macros
Groups
Pages
arch
x86
kernel
cpu
mtrr
amd.c
Go to the documentation of this file.
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
8
static
void
9
amd_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
/* Upper dword is region 1, lower is region 0 */
16
if
(reg == 1)
17
low =
high
;
18
/* The base masks off on the right alignment */
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
* This needs a little explaining. The size is stored as an
31
* inverted mask of bits of 128K granularity 15 bits long offset
32
* 2 bits.
33
*
34
* So to get a size we do invert the mask and add 1 to the lowest
35
* mask bit (4 as its 2 bits in). This gives us a size we then shift
36
* to turn into 128K blocks.
37
*
38
* eg 111 1111 1111 1100 is 512K
39
*
40
* invert 000 0000 0000 0011
41
* +1 000 0000 0000 0100
42
* *128K ...
43
*/
44
low = (~low) & 0x1FFFC;
45
*size = (low + 4) << (15 -
PAGE_SHIFT
);
46
}
47
58
static
void
59
amd_set_mtrr(
unsigned
int
reg,
unsigned
long
base,
unsigned
long
size,
mtrr_type
type)
60
{
61
u32
regs
[2];
62
63
/*
64
* Low is MTRR0, High MTRR 1
65
*/
66
rdmsr
(
MSR_K6_UWCCR
, regs[0], regs[1]);
67
/*
68
* Blank to disable
69
*/
70
if
(size == 0) {
71
regs[
reg
] = 0;
72
}
else
{
73
/*
74
* Set the register to the base, the type (off by one) and an
75
* inverted bitmask of the size The size is the only odd
76
* bit. We are fed say 512K We invert this and we get 111 1111
77
* 1111 1011 but if you subtract one and invert you get the
78
* desired 111 1111 1111 1100 mask
79
*
80
* But ~(x - 1) == ~x + 1 == -x. Two's complement rocks!
81
*/
82
regs[
reg
] = (-size >> (15 -
PAGE_SHIFT
) & 0x0001FFFC)
83
| (base <<
PAGE_SHIFT
) | (type + 1);
84
}
85
86
/*
87
* The writeback rule is quite specific. See the manual. Its
88
* disable local interrupts, write back the cache, set the mtrr
89
*/
90
wbinvd();
91
wrmsr
(
MSR_K6_UWCCR
, regs[0], regs[1]);
92
}
93
94
static
int
95
amd_validate_add_page(
unsigned
long
base,
unsigned
long
size,
unsigned
int
type)
96
{
97
/*
98
* Apply the K6 block alignment and size rules
99
* In order
100
* o Uncached or gathering only
101
* o 128K or bigger block
102
* o Power of 2 block
103
* o base suitably aligned to the power
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
111
static
const
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
120
int
__init
amd_init_mtrr
(
void
)
121
{
122
set_mtrr_ops
(&amd_mtrr_ops);
123
return
0;
124
}
Generated on Thu Jan 10 2013 13:20:25 for Linux Kernel by
1.8.2