aboutsummaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
Diffstat (limited to 'arch')
-rw-r--r--arch/i386/kernel/cpu/mtrr/generic.c85
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
23struct fixed_range_block {
24 int base_msr; /* start address of an MTRR block */
25 int ranges; /* number of MTRRs in this block */
26};
27
28static 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
23static unsigned long smp_changes_mask; 35static unsigned long smp_changes_mask;
24static struct mtrr_state mtrr_state = {}; 36static 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 */
171static 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 */
189static 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
155int generic_get_free_region(unsigned long base, unsigned long size, int replace_reg) 205int 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 */
204static int set_fixed_ranges(mtrr_type * frs) 258static 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