diff options
Diffstat (limited to 'arch')
-rw-r--r-- | arch/i386/kernel/cpu/mtrr/generic.c | 85 |
1 files changed, 60 insertions, 25 deletions
diff --git a/arch/i386/kernel/cpu/mtrr/generic.c b/arch/i386/kernel/cpu/mtrr/generic.c index 150cf5055a3c..000c07e86433 100644 --- a/arch/i386/kernel/cpu/mtrr/generic.c +++ b/arch/i386/kernel/cpu/mtrr/generic.c | |||
@@ -20,6 +20,18 @@ struct mtrr_state { | |||
20 | mtrr_type def_type; | 20 | mtrr_type def_type; |
21 | }; | 21 | }; |
22 | 22 | ||
23 | struct fixed_range_block { | ||
24 | int base_msr; /* start address of an MTRR block */ | ||
25 | int ranges; /* number of MTRRs in this block */ | ||
26 | }; | ||
27 | |||
28 | static struct fixed_range_block fixed_range_blocks[] = { | ||
29 | { MTRRfix64K_00000_MSR, 1 }, /* one 64k MTRR */ | ||
30 | { MTRRfix16K_80000_MSR, 2 }, /* two 16k MTRRs */ | ||
31 | { MTRRfix4K_C0000_MSR, 8 }, /* eight 4k MTRRs */ | ||
32 | {} | ||
33 | }; | ||
34 | |||
23 | static unsigned long smp_changes_mask; | 35 | static unsigned long smp_changes_mask; |
24 | static struct mtrr_state mtrr_state = {}; | 36 | static struct mtrr_state mtrr_state = {}; |
25 | 37 | ||
@@ -152,6 +164,44 @@ void mtrr_wrmsr(unsigned msr, unsigned a, unsigned b) | |||
152 | smp_processor_id(), msr, a, b); | 164 | smp_processor_id(), msr, a, b); |
153 | } | 165 | } |
154 | 166 | ||
167 | /** | ||
168 | * Enable and allow read/write of extended fixed-range MTRR bits on K8 CPUs | ||
169 | * see AMD publication no. 24593, chapter 3.2.1 for more information | ||
170 | */ | ||
171 | static inline void k8_enable_fixed_iorrs(void) | ||
172 | { | ||
173 | unsigned lo, hi; | ||
174 | |||
175 | rdmsr(MSR_K8_SYSCFG, lo, hi); | ||
176 | mtrr_wrmsr(MSR_K8_SYSCFG, lo | ||
177 | | K8_MTRRFIXRANGE_DRAM_ENABLE | ||
178 | | K8_MTRRFIXRANGE_DRAM_MODIFY, hi); | ||
179 | } | ||
180 | |||
181 | /** | ||
182 | * Checks and updates an fixed-range MTRR if it differs from the value it | ||
183 | * should have. If K8 extenstions are wanted, update the K8 SYSCFG MSR also. | ||
184 | * see AMD publication no. 24593, chapter 7.8.1, page 233 for more information | ||
185 | * \param msr MSR address of the MTTR which should be checked and updated | ||
186 | * \param changed pointer which indicates whether the MTRR needed to be changed | ||
187 | * \param msrwords pointer to the MSR values which the MSR should have | ||
188 | */ | ||
189 | static void set_fixed_range(int msr, int * changed, unsigned int * msrwords) | ||
190 | { | ||
191 | unsigned lo, hi; | ||
192 | |||
193 | rdmsr(msr, lo, hi); | ||
194 | |||
195 | if (lo != msrwords[0] || hi != msrwords[1]) { | ||
196 | if (boot_cpu_data.x86_vendor == X86_VENDOR_AMD && | ||
197 | boot_cpu_data.x86 == 15 && | ||
198 | ((msrwords[0] | msrwords[1]) & K8_MTRR_RDMEM_WRMEM_MASK)) | ||
199 | k8_enable_fixed_iorrs(); | ||
200 | mtrr_wrmsr(msr, msrwords[0], msrwords[1]); | ||
201 | *changed = TRUE; | ||
202 | } | ||
203 | } | ||
204 | |||
155 | int generic_get_free_region(unsigned long base, unsigned long size, int replace_reg) | 205 | int generic_get_free_region(unsigned long base, unsigned long size, int replace_reg) |
156 | /* [SUMMARY] Get a free MTRR. | 206 | /* [SUMMARY] Get a free MTRR. |
157 | <base> The starting (base) address of the region. | 207 | <base> The starting (base) address of the region. |
@@ -201,36 +251,21 @@ static void generic_get_mtrr(unsigned int reg, unsigned long *base, | |||
201 | *type = base_lo & 0xff; | 251 | *type = base_lo & 0xff; |
202 | } | 252 | } |
203 | 253 | ||
254 | /** | ||
255 | * Checks and updates the fixed-range MTRRs if they differ from the saved set | ||
256 | * \param frs pointer to fixed-range MTRR values, saved by get_fixed_ranges() | ||
257 | */ | ||
204 | static int set_fixed_ranges(mtrr_type * frs) | 258 | static int set_fixed_ranges(mtrr_type * frs) |
205 | { | 259 | { |
206 | unsigned int *p = (unsigned int *) frs; | 260 | unsigned long long *saved = (unsigned long long *) frs; |
207 | int changed = FALSE; | 261 | int changed = FALSE; |
208 | int i; | 262 | int block=-1, range; |
209 | unsigned int lo, hi; | ||
210 | 263 | ||
211 | rdmsr(MTRRfix64K_00000_MSR, lo, hi); | 264 | while (fixed_range_blocks[++block].ranges) |
212 | if (p[0] != lo || p[1] != hi) { | 265 | for (range=0; range < fixed_range_blocks[block].ranges; range++) |
213 | mtrr_wrmsr(MTRRfix64K_00000_MSR, p[0], p[1]); | 266 | set_fixed_range(fixed_range_blocks[block].base_msr + range, |
214 | changed = TRUE; | 267 | &changed, (unsigned int *) saved++); |
215 | } | ||
216 | |||
217 | for (i = 0; i < 2; i++) { | ||
218 | rdmsr(MTRRfix16K_80000_MSR + i, lo, hi); | ||
219 | if (p[2 + i * 2] != lo || p[3 + i * 2] != hi) { | ||
220 | mtrr_wrmsr(MTRRfix16K_80000_MSR + i, p[2 + i * 2], | ||
221 | p[3 + i * 2]); | ||
222 | changed = TRUE; | ||
223 | } | ||
224 | } | ||
225 | 268 | ||
226 | for (i = 0; i < 8; i++) { | ||
227 | rdmsr(MTRRfix4K_C0000_MSR + i, lo, hi); | ||
228 | if (p[6 + i * 2] != lo || p[7 + i * 2] != hi) { | ||
229 | mtrr_wrmsr(MTRRfix4K_C0000_MSR + i, p[6 + i * 2], | ||
230 | p[7 + i * 2]); | ||
231 | changed = TRUE; | ||
232 | } | ||
233 | } | ||
234 | return changed; | 269 | return changed; |
235 | } | 270 | } |
236 | 271 | ||