linux/arch/i386/kernel/cpu/mtrr/cyrix.c
<<
>>
Prefs
   1#include <linux/init.h>
   2#include <linux/mm.h>
   3#include <asm/mtrr.h>
   4#include <asm/msr.h>
   5#include <asm/io.h>
   6#include "mtrr.h"
   7
   8int arr3_protected;
   9
  10static void
  11cyrix_get_arr(unsigned int reg, unsigned long *base,
  12              unsigned int *size, mtrr_type * type)
  13{
  14        unsigned long flags;
  15        unsigned char arr, ccr3, rcr, shift;
  16
  17        arr = CX86_ARR_BASE + (reg << 1) + reg; /* avoid multiplication by 3 */
  18
  19        /* Save flags and disable interrupts */
  20        local_irq_save(flags);
  21
  22        ccr3 = getCx86(CX86_CCR3);
  23        setCx86(CX86_CCR3, (ccr3 & 0x0f) | 0x10);       /* enable MAPEN */
  24        ((unsigned char *) base)[3] = getCx86(arr);
  25        ((unsigned char *) base)[2] = getCx86(arr + 1);
  26        ((unsigned char *) base)[1] = getCx86(arr + 2);
  27        rcr = getCx86(CX86_RCR_BASE + reg);
  28        setCx86(CX86_CCR3, ccr3);       /* disable MAPEN */
  29
  30        /* Enable interrupts if it was enabled previously */
  31        local_irq_restore(flags);
  32        shift = ((unsigned char *) base)[1] & 0x0f;
  33        *base >>= PAGE_SHIFT;
  34
  35        /* Power of two, at least 4K on ARR0-ARR6, 256K on ARR7
  36         * Note: shift==0xf means 4G, this is unsupported.
  37         */
  38        if (shift)
  39                *size = (reg < 7 ? 0x1UL : 0x40UL) << (shift - 1);
  40        else
  41                *size = 0;
  42
  43        /* Bit 0 is Cache Enable on ARR7, Cache Disable on ARR0-ARR6 */
  44        if (reg < 7) {
  45                switch (rcr) {
  46                case 1:
  47                        *type = MTRR_TYPE_UNCACHABLE;
  48                        break;
  49                case 8:
  50                        *type = MTRR_TYPE_WRBACK;
  51                        break;
  52                case 9:
  53                        *type = MTRR_TYPE_WRCOMB;
  54                        break;
  55                case 24:
  56                default:
  57                        *type = MTRR_TYPE_WRTHROUGH;
  58                        break;
  59                }
  60        } else {
  61                switch (rcr) {
  62                case 0:
  63                        *type = MTRR_TYPE_UNCACHABLE;
  64                        break;
  65                case 8:
  66                        *type = MTRR_TYPE_WRCOMB;
  67                        break;
  68                case 9:
  69                        *type = MTRR_TYPE_WRBACK;
  70                        break;
  71                case 25:
  72                default:
  73                        *type = MTRR_TYPE_WRTHROUGH;
  74                        break;
  75                }
  76        }
  77}
  78
  79static int
  80cyrix_get_free_region(unsigned long base, unsigned long size)
  81/*  [SUMMARY] Get a free ARR.
  82    <base> The starting (base) address of the region.
  83    <size> The size (in bytes) of the region.
  84    [RETURNS] The index of the region on success, else -1 on error.
  85*/
  86{
  87        int i;
  88        mtrr_type ltype;
  89        unsigned long lbase;
  90        unsigned int  lsize;
  91
  92        /* If we are to set up a region >32M then look at ARR7 immediately */
  93        if (size > 0x2000) {
  94                cyrix_get_arr(7, &lbase, &lsize, &ltype);
  95                if (lsize == 0)
  96                        return 7;
  97                /*  Else try ARR0-ARR6 first  */
  98        } else {
  99                for (i = 0; i < 7; i++) {
 100                        cyrix_get_arr(i, &lbase, &lsize, &ltype);
 101                        if ((i == 3) && arr3_protected)
 102                                continue;
 103                        if (lsize == 0)
 104                                return i;
 105                }
 106                /* ARR0-ARR6 isn't free, try ARR7 but its size must be at least 256K */
 107                cyrix_get_arr(i, &lbase, &lsize, &ltype);
 108                if ((lsize == 0) && (size >= 0x40))
 109                        return i;
 110        }
 111        return -ENOSPC;
 112}
 113
 114static u32 cr4 = 0;
 115static u32 ccr3;
 116
 117static void prepare_set(void)
 118{
 119        u32 cr0;
 120
 121        /*  Save value of CR4 and clear Page Global Enable (bit 7)  */
 122        if ( cpu_has_pge ) {
 123                cr4 = read_cr4();
 124                write_cr4(cr4 & (unsigned char) ~(1 << 7));
 125        }
 126
 127        /*  Disable and flush caches. Note that wbinvd flushes the TLBs as
 128            a side-effect  */
 129        cr0 = read_cr0() | 0x40000000;
 130        wbinvd();
 131        write_cr0(cr0);
 132        wbinvd();
 133
 134        /* Cyrix ARRs - everything else were excluded at the top */
 135        ccr3 = getCx86(CX86_CCR3);
 136
 137        /* Cyrix ARRs - everything else were excluded at the top */
 138        setCx86(CX86_CCR3, (ccr3 & 0x0f) | 0x10);
 139
 140}
 141
 142static void post_set(void)
 143{
 144        /*  Flush caches and TLBs  */
 145        wbinvd();
 146
 147        /* Cyrix ARRs - everything else was excluded at the top */
 148        setCx86(CX86_CCR3, ccr3);
 149                
 150        /*  Enable caches  */
 151        write_cr0(read_cr0() & 0xbfffffff);
 152
 153        /*  Restore value of CR4  */
 154        if ( cpu_has_pge )
 155                write_cr4(cr4);
 156}
 157
 158static void cyrix_set_arr(unsigned int reg, unsigned long base,
 159                          unsigned long size, mtrr_type type)
 160{
 161        unsigned char arr, arr_type, arr_size;
 162
 163        arr = CX86_ARR_BASE + (reg << 1) + reg; /* avoid multiplication by 3 */
 164
 165        /* count down from 32M (ARR0-ARR6) or from 2G (ARR7) */
 166        if (reg >= 7)
 167                size >>= 6;
 168
 169        size &= 0x7fff;         /* make sure arr_size <= 14 */
 170        for (arr_size = 0; size; arr_size++, size >>= 1) ;
 171
 172        if (reg < 7) {
 173                switch (type) {
 174                case MTRR_TYPE_UNCACHABLE:
 175                        arr_type = 1;
 176                        break;
 177                case MTRR_TYPE_WRCOMB:
 178                        arr_type = 9;
 179                        break;
 180                case MTRR_TYPE_WRTHROUGH:
 181                        arr_type = 24;
 182                        break;
 183                default:
 184                        arr_type = 8;
 185                        break;
 186                }
 187        } else {
 188                switch (type) {
 189                case MTRR_TYPE_UNCACHABLE:
 190                        arr_type = 0;
 191                        break;
 192                case MTRR_TYPE_WRCOMB:
 193                        arr_type = 8;
 194                        break;
 195                case MTRR_TYPE_WRTHROUGH:
 196                        arr_type = 25;
 197                        break;
 198                default:
 199                        arr_type = 9;
 200                        break;
 201                }
 202        }
 203
 204        prepare_set();
 205
 206        base <<= PAGE_SHIFT;
 207        setCx86(arr, ((unsigned char *) &base)[3]);
 208        setCx86(arr + 1, ((unsigned char *) &base)[2]);
 209        setCx86(arr + 2, (((unsigned char *) &base)[1]) | arr_size);
 210        setCx86(CX86_RCR_BASE + reg, arr_type);
 211
 212        post_set();
 213}
 214
 215typedef struct {
 216        unsigned long base;
 217        unsigned int size;
 218        mtrr_type type;
 219} arr_state_t;
 220
 221arr_state_t arr_state[8] __initdata = {
 222        {0UL, 0UL, 0UL}, {0UL, 0UL, 0UL}, {0UL, 0UL, 0UL}, {0UL, 0UL, 0UL},
 223        {0UL, 0UL, 0UL}, {0UL, 0UL, 0UL}, {0UL, 0UL, 0UL}, {0UL, 0UL, 0UL}
 224};
 225
 226unsigned char ccr_state[7] __initdata = { 0, 0, 0, 0, 0, 0, 0 };
 227
 228static void cyrix_set_all(void)
 229{
 230        int i;
 231
 232        prepare_set();
 233
 234        /* the CCRs are not contiguous */
 235        for (i = 0; i < 4; i++)
 236                setCx86(CX86_CCR0 + i, ccr_state[i]);
 237        for (; i < 7; i++)
 238                setCx86(CX86_CCR4 + i, ccr_state[i]);
 239        for (i = 0; i < 8; i++)
 240                cyrix_set_arr(i, arr_state[i].base, 
 241                              arr_state[i].size, arr_state[i].type);
 242
 243        post_set();
 244}
 245
 246/*
 247 * On Cyrix 6x86(MX) and M II the ARR3 is special: it has connection
 248 * with the SMM (System Management Mode) mode. So we need the following:
 249 * Check whether SMI_LOCK (CCR3 bit 0) is set
 250 *   if it is set, write a warning message: ARR3 cannot be changed!
 251 *     (it cannot be changed until the next processor reset)
 252 *   if it is reset, then we can change it, set all the needed bits:
 253 *   - disable access to SMM memory through ARR3 range (CCR1 bit 7 reset)
 254 *   - disable access to SMM memory (CCR1 bit 2 reset)
 255 *   - disable SMM mode (CCR1 bit 1 reset)
 256 *   - disable write protection of ARR3 (CCR6 bit 1 reset)
 257 *   - (maybe) disable ARR3
 258 * Just to be sure, we enable ARR usage by the processor (CCR5 bit 5 set)
 259 */
 260static void __init
 261cyrix_arr_init(void)
 262{
 263        struct set_mtrr_context ctxt;
 264        unsigned char ccr[7];
 265        int ccrc[7] = { 0, 0, 0, 0, 0, 0, 0 };
 266#ifdef CONFIG_SMP
 267        int i;
 268#endif
 269
 270        /* flush cache and enable MAPEN */
 271        set_mtrr_prepare_save(&ctxt);
 272        set_mtrr_cache_disable(&ctxt);
 273
 274        /* Save all CCRs locally */
 275        ccr[0] = getCx86(CX86_CCR0);
 276        ccr[1] = getCx86(CX86_CCR1);
 277        ccr[2] = getCx86(CX86_CCR2);
 278        ccr[3] = ctxt.ccr3;
 279        ccr[4] = getCx86(CX86_CCR4);
 280        ccr[5] = getCx86(CX86_CCR5);
 281        ccr[6] = getCx86(CX86_CCR6);
 282
 283        if (ccr[3] & 1) {
 284                ccrc[3] = 1;
 285                arr3_protected = 1;
 286        } else {
 287                /* Disable SMM mode (bit 1), access to SMM memory (bit 2) and
 288                 * access to SMM memory through ARR3 (bit 7).
 289                 */
 290                if (ccr[1] & 0x80) {
 291                        ccr[1] &= 0x7f;
 292                        ccrc[1] |= 0x80;
 293                }
 294                if (ccr[1] & 0x04) {
 295                        ccr[1] &= 0xfb;
 296                        ccrc[1] |= 0x04;
 297                }
 298                if (ccr[1] & 0x02) {
 299                        ccr[1] &= 0xfd;
 300                        ccrc[1] |= 0x02;
 301                }
 302                arr3_protected = 0;
 303                if (ccr[6] & 0x02) {
 304                        ccr[6] &= 0xfd;
 305                        ccrc[6] = 1;    /* Disable write protection of ARR3 */
 306                        setCx86(CX86_CCR6, ccr[6]);
 307                }
 308                /* Disable ARR3. This is safe now that we disabled SMM. */
 309                /* cyrix_set_arr_up (3, 0, 0, 0, FALSE); */
 310        }
 311        /* If we changed CCR1 in memory, change it in the processor, too. */
 312        if (ccrc[1])
 313                setCx86(CX86_CCR1, ccr[1]);
 314
 315        /* Enable ARR usage by the processor */
 316        if (!(ccr[5] & 0x20)) {
 317                ccr[5] |= 0x20;
 318                ccrc[5] = 1;
 319                setCx86(CX86_CCR5, ccr[5]);
 320        }
 321#ifdef CONFIG_SMP
 322        for (i = 0; i < 7; i++)
 323                ccr_state[i] = ccr[i];
 324        for (i = 0; i < 8; i++)
 325                cyrix_get_arr(i,
 326                              &arr_state[i].base, &arr_state[i].size,
 327                              &arr_state[i].type);
 328#endif
 329
 330        set_mtrr_done(&ctxt);   /* flush cache and disable MAPEN */
 331
 332        if (ccrc[5])
 333                printk(KERN_INFO "mtrr: ARR usage was not enabled, enabled manually\n");
 334        if (ccrc[3])
 335                printk(KERN_INFO "mtrr: ARR3 cannot be changed\n");
 336/*
 337    if ( ccrc[1] & 0x80) printk ("mtrr: SMM memory access through ARR3 disabled\n");
 338    if ( ccrc[1] & 0x04) printk ("mtrr: SMM memory access disabled\n");
 339    if ( ccrc[1] & 0x02) printk ("mtrr: SMM mode disabled\n");
 340*/
 341        if (ccrc[6])
 342                printk(KERN_INFO "mtrr: ARR3 was write protected, unprotected\n");
 343}
 344
 345static struct mtrr_ops cyrix_mtrr_ops = {
 346        .vendor            = X86_VENDOR_CYRIX,
 347        .init              = cyrix_arr_init,
 348        .set_all           = cyrix_set_all,
 349        .set               = cyrix_set_arr,
 350        .get               = cyrix_get_arr,
 351        .get_free_region   = cyrix_get_free_region,
 352        .validate_add_page = generic_validate_add_page,
 353        .have_wrcomb       = positive_have_wrcomb,
 354};
 355
 356int __init cyrix_init_mtrr(void)
 357{
 358        set_mtrr_ops(&cyrix_mtrr_ops);
 359        return 0;
 360}
 361
 362//arch_initcall(cyrix_init_mtrr);
 363
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.