OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [trunk/] [uclinux/] [uClinux-2.0.x/] [arch/] [i386/] [kernel/] [mtrr.c] - Blame information for rev 1767

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 199 simons
/*
2
 *      Read and write Memory Type Range Registers (MTRRs)
3
 *
4
 *      These machine specific registers contain information about
5
 *      caching of memory regions on Intel processors.
6
 *
7
 *      This code has been derived from pform_mod.c by M. Tisch"auser
8
 *      (email martin@ikcbarka.fzk.de). Special thanks to mingo for
9
 *      his hint.
10
 *
11
 *      (c) 1997 M. Ohlenroth <moh@informatik.tu-chemnitz.de>
12
 *      NO WARRANTY: use this code at your own risk!
13
 *
14
 *      This code is released under the GNU public license version 2 or
15
 *      later.
16
 *
17
 *      modified to have a /proc/mtrr interface by M. Fr"ohlich, Jan. 1998
18
 *      <frohlich@na.uni-tuebingen.de>
19
 *         the user Interface is partly taken form mtrr-patch-v1.5
20
 *      Richard Gooch may be reached by email at  rgooch@atnf.csiro.au
21
 *        The postal address is:
22
 *      Richard Gooch, c/o ATNF, P. O. Box 76, Epping, N.S.W., 2121, Australia.
23
 *
24
 */
25
 
26
#include <linux/kernel.h>
27
#include <linux/ctype.h>
28
#include <linux/proc_fs.h>
29
#include <linux/smp.h>
30
#include <linux/interrupt.h>
31
#include <asm/system.h>
32
#include <asm/processor.h>
33
#include <asm/mtrr.h>
34
 
35
#define MTRR_CAP        0x0fe   /* MTRRcap register */
36
#define MTRR_VARIABLE   0x200   /* variable length registers */
37
#define MTRR_FIXED64K   0x250   /* fixed size registers 64k */
38
#define MTRR_FIXED16K   0x258   /* fixed size registers 16K */
39
#define MTRR_FIXED4K    0x268   /* fixed size registers 4K */
40
#define MTRR_DEFTYPE    0x2ff   /* MTRRdefType register */
41
 
42
/*
43
 * data type for the MTRRcap register
44
 */
45
typedef struct {
46
        __u64   VCNT          :  8  __attribute__ ((packed)),
47
                FIX           :  1  __attribute__ ((packed)),
48
                __reserved_2  :  1  __attribute__ ((packed)),
49
                WC            :  1  __attribute__ ((packed)),
50
                __reserved_1  :  53 __attribute__ ((packed));
51
} MTRRcap_t __attribute__ ((packed));
52
 
53
 
54
/*
55
 * data type for the MTRRdefType register
56
 */
57
typedef struct {
58
        __u64   Type          :  8  __attribute__ ((packed)),
59
                __reserved_1  :  2  __attribute__ ((packed)),
60
                FE            :  1  __attribute__ ((packed)),
61
                E             :  1  __attribute__ ((packed)),
62
                __reserved_2  :  52 __attribute__ ((packed));
63
} MTRRdefType_t __attribute__ ((packed));
64
 
65
/* FIXME implement the entry struct */
66
typedef struct MTRRfix64K_t {
67
        __u64   raw;
68
} MTRRfix64K_t __attribute__ ((packed));
69
 
70
typedef struct MTRRfix16K_t {
71
        __u64   raw;
72
} MTRRfix16K_t __attribute__ ((packed));
73
 
74
typedef struct MTRRfix4K_t {
75
        __u64   raw;
76
} MTRRfix4K_t __attribute__ ((packed));
77
 
78
/*
79
 * data type for a pair of variable MTRR registers
80
 */
81
typedef struct {
82
        struct {
83
                __u64   Type          :  8  __attribute__ ((packed)),
84
                        __reserved_1  :  4  __attribute__ ((packed)),
85
                        PhysBase      :  24 __attribute__ ((packed)),
86
                        __reserved_2  :  28 __attribute__ ((packed));
87
        } MTRRphysBase  __attribute__ ((packed));
88
 
89
        struct {
90
                __u64   __reserved_3  :  11 __attribute__ ((packed)),
91
                        V             :  1  __attribute__ ((packed)),
92
                        PhysMask      :  24 __attribute__ ((packed)),
93
                        __reserved_4  :  28 __attribute__ ((packed));
94
        } MTRRphysMask __attribute__ ((packed));
95
} MTRRvar_t __attribute__ ((packed));
96
 
97
#define RAW_ACCESS64(data) (*(unsigned long long *)(&(data)))
98
 
99
/*
100
 * MTRR configuration struct
101
 */
102
struct mtrr_cntl_t {
103
        MTRRcap_t      MTRRcap;     /* MTRR capability register */
104
        MTRRdefType_t  MTRRdefType; /* MTRR default type register */
105
        MTRRfix64K_t   fixed64;     /* fixed length entries (raw data) */
106
        MTRRfix16K_t   fixed16[2];
107
        MTRRfix4K_t    fixed4[8];
108
        MTRRvar_t      variable[0]; /* variable type entries */
109
};
110
 
111
static struct mtrr_cntl_t *mtrrcntl      = NULL;
112
 
113
/*
114
 * Deletes the variable MTRR *MTRRvar
115
 */
116
static inline void MTRRvar_delete(MTRRvar_t *MTRRvar)
117
{
118
        RAW_ACCESS64(MTRRvar->MTRRphysBase) = 0;
119
        RAW_ACCESS64(MTRRvar->MTRRphysMask) = 0;
120
}
121
 
122
 
123
/*
124
 * Sets the variable MTRR *MTRRvar
125
 */
126
static inline void MTRRvar_set(MTRRvar_t *MTRRvar, unsigned int type,
127
                               unsigned long base, unsigned long size)
128
{
129
        unsigned long val;
130
        base >>= 12;
131
        size >>= 12;
132
 
133
        MTRRvar->MTRRphysBase.Type = type;
134
        MTRRvar->MTRRphysBase.PhysBase = base;
135
 
136
        MTRRvar->MTRRphysMask.V = 1;
137
        val = 1<<25;
138
        while (0 == (val & size)) val |= (val>>1);
139
        MTRRvar->MTRRphysMask.PhysMask = val;
140
}
141
 
142
 
143
/*
144
 * returns 1 if the variable MTRR entry *MTRRvar is valid, 0 otherwise
145
 */
146
static inline int MTRRvar_is_valid(const MTRRvar_t *MTRRvar)
147
{
148
        return MTRRvar->MTRRphysMask.V;
149
}
150
 
151
/*
152
 * returns the type of the variable MTRR entry *MTRRvar
153
 */
154
static inline int MTRRvar_get_type(const MTRRvar_t *MTRRvar)
155
{
156
        return MTRRvar->MTRRphysBase.Type;
157
}
158
 
159
/*
160
 * returns the base of the variable MTRR entry *MTRRvar
161
 */
162
static inline unsigned long long MTRRvar_get_base(const MTRRvar_t *MTRRvar)
163
{
164
        return ((unsigned long long)MTRRvar->MTRRphysBase.PhysBase) << 12;
165
}
166
 
167
/*
168
 * returns the size of the variable MTRR entry *MTRRvar
169
 */
170
static inline unsigned long long MTRRvar_get_size(const MTRRvar_t *MTRRvar)
171
{
172
        if (MTRRvar->MTRRphysMask.PhysMask == 0) {
173
                return 0;
174
        } else {
175
                unsigned long size = 1;
176
                const unsigned long Mask = MTRRvar->MTRRphysMask.PhysMask;
177
                while (0 == (Mask & size)) size <<= 1;
178
                return ((unsigned long long)size) << 12;
179
        }
180
}
181
 
182
/*
183
 *  returns the eflags register
184
 */
185
static inline int read_eflags(void)
186
{
187
        int ret;
188
        asm volatile (
189
                "pushfl\n\t"
190
                "popl %%eax\n\t"
191
                :"=a" (ret)
192
                :
193
                );
194
        return ret;
195
}
196
 
197
/*
198
 *  writes the eflags register
199
 */
200
static inline void write_eflags(int flag)
201
{
202
        asm volatile (
203
                "pushl %%eax\n\t"
204
                "popfl\n\t"
205
                :
206
                :"a" (flag)
207
                );
208
}
209
 
210
/*
211
 * returns 1 if the mtrr's are supported by the current processor, 0 otherwise
212
 */
213
static inline int mtrr_detect(void) {
214
        unsigned long flags;
215
        int eflags;
216
        int val;
217
 
218
#define MSR_MASK 0x20
219
#define MTRR_MASK 0x1000
220
#define CPUID_MASK 0x200000
221
        /* this function may be called before the cpu_data array has
222
                been initialized */
223
        save_flags(flags); sti();
224
        eflags = read_eflags();
225
        write_eflags(eflags ^ CPUID_MASK);
226
        if (!((eflags ^ read_eflags()) & CPUID_MASK)) {
227
                write_eflags(eflags);
228
                restore_flags(flags);
229
                return 0;
230
        }
231
        write_eflags(eflags);
232
        restore_flags(flags);
233
 
234
        /* get the cpuid level */
235
        asm volatile (
236
                "xorl %%eax,%%eax\n\t"
237
                "cpuid"
238
                :"=a"(val)::"ebx","ecx","edx"
239
        );
240
        if (val < 1) return 0;
241
        /* get the x86_capability value */
242
        asm volatile (
243
                "movl $1,%%eax\n\t"
244
                "cpuid"
245
                :"=d"(val)::"ebx","ecx","eax"
246
        );
247
        if (!(val & MSR_MASK)) return 0;
248
        if (!(val & MTRR_MASK)) return 0;
249
 
250
        return 1;
251
#undef MSR_MASK
252
#undef MTRR_MASK
253
#undef CPUID_MASK
254
}
255
 
256
 
257
/*
258
 * reads the mtrr configuration of the actual processor and returns
259
 * this configuration on sucess. returns NULL if an error occured or
260
 * if mtrr's are not supported.
261
 */
262
static struct mtrr_cntl_t *read_mtrr_configuration (void) {
263
        struct mtrr_cntl_t *mtrrcntl;
264
        int i;
265
        size_t size;
266
        MTRRcap_t MTRRcap;
267
 
268
        if (!mtrr_detect()) {
269
                printk("/proc/mtrr: MTRR's are NOT supported\n");
270
                return NULL;
271
        }
272
 
273
        RAW_ACCESS64(MTRRcap) = rdmsr(MTRR_CAP);
274
 
275
/* #define DUMP_MTRR */
276
#ifdef DUMP_MTRR
277
        {
278
                /* Written for a bugreport to Gigabyte ... */
279
                inline void print_msr(int num) {
280
                        unsigned long long tmp = rdmsr(num);
281
                        printk("MSR #%#06x: 0x%08lx%08lx\n",
282
                               num , (unsigned long)(tmp >> 32),
283
                               (unsigned long)tmp);
284
                }
285
 
286
                print_msr(MTRR_CAP);
287
                /* all variable type */
288
                for (i=0;i < MTRRcap.VCNT;i++) {
289
                        print_msr(MTRR_VARIABLE+2*i);
290
                        print_msr(MTRR_VARIABLE+2*i+1);
291
                }
292
                /* all fixed type */
293
                print_msr(MTRR_FIXED64K);
294
                print_msr(MTRR_FIXED16K);
295
                print_msr(MTRR_FIXED16K+1);
296
                for (i=0;i<8;i++)
297
                        print_msr(MTRR_FIXED4K+i);
298
                print_msr(MTRR_DEFTYPE);
299
        }
300
#endif
301
 
302
        size = sizeof(struct mtrr_cntl_t) + sizeof(MTRRvar_t)*MTRRcap.VCNT;
303
        if (NULL == (mtrrcntl = kmalloc(size, GFP_KERNEL))) return NULL;
304
        memset(mtrrcntl, 0, size);
305
 
306
        /* read MTRRcap register */
307
        mtrrcntl->MTRRcap = MTRRcap;
308
 
309
        /* read MTRRdefType register */
310
        RAW_ACCESS64(mtrrcntl->MTRRdefType) = rdmsr(MTRR_DEFTYPE);
311
 
312
        /* read fixed length entries */
313
        if (mtrrcntl->MTRRdefType.E && mtrrcntl->MTRRdefType.FE) {
314
                mtrrcntl->fixed64.raw = rdmsr(MTRR_FIXED64K);
315
                mtrrcntl->fixed16[0].raw = rdmsr(MTRR_FIXED16K);
316
                mtrrcntl->fixed16[1].raw = rdmsr(MTRR_FIXED16K+1);
317
                for (i=0;i<8;i++)
318
                        mtrrcntl->fixed4[i].raw = rdmsr(MTRR_FIXED4K+i);
319
        }
320
 
321
        /* read variable length entries */
322
        if (mtrrcntl->MTRRdefType.E) {
323
                const int vcnt = mtrrcntl->MTRRcap.VCNT;
324
                for (i = 0 ; i < vcnt ; i++) {
325
                        RAW_ACCESS64(mtrrcntl->variable[i].MTRRphysBase) =
326
                                rdmsr(MTRR_VARIABLE + 2*i);
327
                        RAW_ACCESS64(mtrrcntl->variable[i].MTRRphysMask) =
328
                                rdmsr(MTRR_VARIABLE + 2*i + 1);
329
                }
330
        }
331
 
332
        return mtrrcntl;
333
}
334
 
335
/*
336
 * initializes the global mtrr configuration
337
 */
338
/*__init_function(void init_mtrr_config(void)) FIXME*/
339
void init_mtrr_config(void)
340
{
341
        mtrrcntl = read_mtrr_configuration();
342
}
343
 
344
 
345
/* write back and invalidate cache */
346
static inline void wbinvd(void)
347
{
348
        asm volatile("wbinvd");
349
}
350
 
351
/* flush tlb's */
352
static inline void flush__tlb(void)
353
{
354
        asm volatile (
355
                "movl  %%cr3, %%eax\n\t"
356
                "movl  %%eax, %%cr3\n\t"
357
                :
358
                :
359
                : "memory", "eax");
360
}
361
 
362
/* clear page global enable and return previous value */
363
static inline unsigned long clear_pge(void)
364
{
365
        unsigned long ret;
366
        asm volatile (
367
                "movl  %%cr4, %%eax\n\t"
368
                "movl  %%eax, %%edx\n\t"
369
                "andl  $0x7f, %%edx\n\t"
370
                "movl  %%edx, %%cr4\n\t"
371
                : "=a" (ret)
372
                :
373
                : "memory", "cc", "eax", "edx");
374
        return ret;
375
}
376
 
377
/* restores page global enable bit */
378
static inline void restore_pge(unsigned long cr4)
379
{
380
        asm volatile (
381
                "movl  %0, %%cr4\n\t"
382
                :
383
                : "r" (cr4)
384
                : "memory");
385
}
386
 
387
/* ... */
388
static inline void disable_cache(void)
389
{
390
        asm volatile (
391
                "movl  %%cr0, %%eax\n\t"
392
                "orl   $0x40000000, %%eax\n\t"
393
                "movl  %%eax, %%cr0\n\t"
394
                :
395
                :
396
                :"memory", "cc", "eax");
397
}
398
 
399
/* ... */
400
static inline void enable_cache(void)
401
{
402
        asm volatile (
403
                "movl  %%cr0, %%eax\n\t"
404
                "andl  $0xbfffffff, %%eax\n\t"
405
                "movl  %%eax, %%cr0"
406
                :
407
                :
408
                :"memory", "cc", "eax");
409
}
410
 
411
/* clear the MTRRdefType.E and MTRRdefType.FE flag to disable these MTRR's */
412
static inline void disable_mtrr(void)
413
{
414
        MTRRdefType_t MTRRdefType;
415
 
416
        RAW_ACCESS64(MTRRdefType) = rdmsr(MTRR_DEFTYPE);
417
        MTRRdefType.E = 0;
418
        MTRRdefType.FE = 0;
419
        wrmsr(MTRR_DEFTYPE, RAW_ACCESS64(MTRRdefType));
420
}
421
 
422
/*
423
 * written from pseudocode from intel
424
 *  (PentiumPro Family Developers manual Volume 3, P 322)
425
 *
426
 */
427
static inline unsigned long pre_mtrr_change(void)
428
{
429
        unsigned long cr4;
430
 
431
        cr4 = clear_pge();
432
 
433
        wbinvd();
434
 
435
        disable_cache();
436
 
437
        wbinvd();
438
 
439
        flush__tlb();
440
 
441
        disable_mtrr();
442
 
443
        return cr4;
444
}
445
 
446
/*
447
 * written from pseudocode from intel
448
 *  (PentiumPro Family Developers manual Volume 3, P 322)
449
 */
450
static inline void post_mtrr_change(MTRRdefType_t MTRRdefType,unsigned long cr4)
451
{
452
        wbinvd();
453
 
454
        flush__tlb();
455
 
456
        wrmsr(MTRR_DEFTYPE, RAW_ACCESS64(MTRRdefType));
457
 
458
        enable_cache();
459
 
460
        restore_pge(cr4);
461
}
462
 
463
/*
464
 * writes all fixed mtrr's
465
 */
466
static inline void set_mtrr_fixed(void) {
467
        int i;
468
 
469
        wrmsr(MTRR_FIXED64K,mtrrcntl->fixed64.raw);
470
        wrmsr(MTRR_FIXED16K+0,mtrrcntl->fixed16[0].raw);
471
        wrmsr(MTRR_FIXED16K+1,mtrrcntl->fixed16[1].raw);
472
        for (i=0;i<8;i++)
473
                wrmsr(MTRR_FIXED4K+i,mtrrcntl->fixed4[i].raw);
474
}
475
 
476
/*
477
 * writes all variable mtrr's
478
 */
479
static inline void set_mtrr_variable(void) {
480
        int i;
481
        const int vcnt = mtrrcntl->MTRRcap.VCNT;
482
 
483
        for (i = 0 ; i < vcnt ; i++ ) {
484
                wrmsr(MTRR_VARIABLE +2*i,
485
                      RAW_ACCESS64(mtrrcntl->variable[i].MTRRphysBase));
486
                wrmsr(MTRR_VARIABLE +2*i+1,
487
                      RAW_ACCESS64(mtrrcntl->variable[i].MTRRphysMask));
488
        }
489
}
490
 
491
 
492
/*
493
 * compares the mtrr_cntl_t structure second with that set by
494
 * the boot processor,
495
 * returns 0 if equal,
496
 *        -1 if the structs are not initialized,
497
 *         1 if they are different
498
 *
499
 * the *second struct is assumed to be local, it is not locked!
500
 */
501
static inline int compare_mtrr_configuration(struct mtrr_cntl_t *second) {
502
        int i, result = 0;
503
 
504
        if (NULL == mtrrcntl) { result = -1; goto end; }
505
        if (NULL == second) { result = -1; goto end; }
506
        if (RAW_ACCESS64(mtrrcntl->MTRRcap)
507
            != RAW_ACCESS64(second->MTRRcap)) {
508
                result = 1; goto end;
509
        }
510
 
511
        if (RAW_ACCESS64(mtrrcntl->MTRRdefType)
512
            != RAW_ACCESS64(second->MTRRdefType)) {
513
                result = 1; goto end;
514
        }
515
 
516
        if (mtrrcntl->fixed64.raw != second->fixed64.raw) {
517
                result = 1; goto end;
518
        }
519
        if (mtrrcntl->fixed16[0].raw != second->fixed16[0].raw) {
520
                result = 1; goto end;
521
        }
522
        if (mtrrcntl->fixed16[1].raw != second->fixed16[1].raw) {
523
                result = 1; goto end;
524
        }
525
 
526
        for (i=0;i<8;i++)
527
                if (mtrrcntl->fixed4[i].raw != second->fixed4[i].raw) {
528
                        result = 1; goto end;
529
                }
530
        {
531
                const int vcnt = mtrrcntl->MTRRcap.VCNT;
532
                for (i = 0; i < vcnt; i++) {
533
                        if (RAW_ACCESS64(mtrrcntl->variable[i].MTRRphysBase) !=
534
                            RAW_ACCESS64(second->variable[i].MTRRphysBase)) {
535
                                result = 1; goto end;
536
                        }
537
                        if (RAW_ACCESS64(mtrrcntl->variable[i].MTRRphysMask) !=
538
                            RAW_ACCESS64(second->variable[i].MTRRphysMask)) {
539
                                result = 1; goto end;
540
                        }
541
                }
542
        }
543
 
544
        end:
545
 
546
        return result;
547
}
548
 
549
/*
550
 * compares the mtrr configuration of the current processor with the
551
 * main configuration and overwrites the mtrr's in the processor if they
552
 * differ. (fixes a bug in the GA-686DX mainboard BIOS)
553
 */
554
void check_mtrr_config(void) {
555
        unsigned long cr4;
556
        unsigned long flags;
557
        struct mtrr_cntl_t *this_cpu_setting;
558
        int result;
559
 
560
        save_flags(flags); sti();
561
 
562
        /* if global struct is not initialized return */
563
        if (mtrrcntl == NULL) {
564
                restore_flags(flags);
565
                return;
566
        }
567
 
568
        /* disable MTRR feature if this_cpu_setting == NULL */
569
        /* read mtrr configuration of this cpu */
570
        this_cpu_setting = read_mtrr_configuration();
571
        if (this_cpu_setting == NULL) {
572
                printk("/proc/mtrr: MTRR's are NOT supported by cpu %i.\n",
573
                       smp_processor_id());
574
                restore_flags(flags);
575
 
576
                return;
577
        }
578
        /* compare mtrr configuration */
579
        result = compare_mtrr_configuration(this_cpu_setting);
580
        kfree(this_cpu_setting);
581
        /* return if mtrr setting is correct */
582
        if (0 >= result) {
583
                restore_flags(flags);
584
                return;
585
        }
586
 
587
        /* prepare cpu's for setting mtrr's */
588
        cr4 = pre_mtrr_change();
589
 
590
        /* set all mtrr's */
591
        set_mtrr_fixed();
592
        set_mtrr_variable();
593
 
594
        /* prepare cpu's for running */
595
        post_mtrr_change(mtrrcntl->MTRRdefType, cr4);
596
 
597
        restore_flags(flags);
598
 
599
        printk("\nBIOS bug workaround: MTRR configuration changed on cpu "
600
               "%i.\n", smp_processor_id());
601
}
602
 

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.