Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 #include <linux/init.h>
0003 #include <linux/io.h>
0004 #include <linux/mm.h>
0005 
0006 #include <asm/processor-cyrix.h>
0007 #include <asm/processor-flags.h>
0008 #include <asm/mtrr.h>
0009 #include <asm/msr.h>
0010 
0011 #include "mtrr.h"
0012 
0013 static void
0014 cyrix_get_arr(unsigned int reg, unsigned long *base,
0015           unsigned long *size, mtrr_type * type)
0016 {
0017     unsigned char arr, ccr3, rcr, shift;
0018     unsigned long flags;
0019 
0020     arr = CX86_ARR_BASE + (reg << 1) + reg; /* avoid multiplication by 3 */
0021 
0022     local_irq_save(flags);
0023 
0024     ccr3 = getCx86(CX86_CCR3);
0025     setCx86(CX86_CCR3, (ccr3 & 0x0f) | 0x10);   /* enable MAPEN */
0026     ((unsigned char *)base)[3] = getCx86(arr);
0027     ((unsigned char *)base)[2] = getCx86(arr + 1);
0028     ((unsigned char *)base)[1] = getCx86(arr + 2);
0029     rcr = getCx86(CX86_RCR_BASE + reg);
0030     setCx86(CX86_CCR3, ccr3);           /* disable MAPEN */
0031 
0032     local_irq_restore(flags);
0033 
0034     shift = ((unsigned char *) base)[1] & 0x0f;
0035     *base >>= PAGE_SHIFT;
0036 
0037     /*
0038      * Power of two, at least 4K on ARR0-ARR6, 256K on ARR7
0039      * Note: shift==0xf means 4G, this is unsupported.
0040      */
0041     if (shift)
0042         *size = (reg < 7 ? 0x1UL : 0x40UL) << (shift - 1);
0043     else
0044         *size = 0;
0045 
0046     /* Bit 0 is Cache Enable on ARR7, Cache Disable on ARR0-ARR6 */
0047     if (reg < 7) {
0048         switch (rcr) {
0049         case 1:
0050             *type = MTRR_TYPE_UNCACHABLE;
0051             break;
0052         case 8:
0053             *type = MTRR_TYPE_WRBACK;
0054             break;
0055         case 9:
0056             *type = MTRR_TYPE_WRCOMB;
0057             break;
0058         case 24:
0059         default:
0060             *type = MTRR_TYPE_WRTHROUGH;
0061             break;
0062         }
0063     } else {
0064         switch (rcr) {
0065         case 0:
0066             *type = MTRR_TYPE_UNCACHABLE;
0067             break;
0068         case 8:
0069             *type = MTRR_TYPE_WRCOMB;
0070             break;
0071         case 9:
0072             *type = MTRR_TYPE_WRBACK;
0073             break;
0074         case 25:
0075         default:
0076             *type = MTRR_TYPE_WRTHROUGH;
0077             break;
0078         }
0079     }
0080 }
0081 
0082 /*
0083  * cyrix_get_free_region - get a free ARR.
0084  *
0085  * @base: the starting (base) address of the region.
0086  * @size: the size (in bytes) of the region.
0087  *
0088  * Returns: the index of the region on success, else -1 on error.
0089 */
0090 static int
0091 cyrix_get_free_region(unsigned long base, unsigned long size, int replace_reg)
0092 {
0093     unsigned long lbase, lsize;
0094     mtrr_type ltype;
0095     int i;
0096 
0097     switch (replace_reg) {
0098     case 7:
0099         if (size < 0x40)
0100             break;
0101         fallthrough;
0102     case 6:
0103     case 5:
0104     case 4:
0105         return replace_reg;
0106     case 3:
0107     case 2:
0108     case 1:
0109     case 0:
0110         return replace_reg;
0111     }
0112     /* If we are to set up a region >32M then look at ARR7 immediately */
0113     if (size > 0x2000) {
0114         cyrix_get_arr(7, &lbase, &lsize, &ltype);
0115         if (lsize == 0)
0116             return 7;
0117         /* Else try ARR0-ARR6 first  */
0118     } else {
0119         for (i = 0; i < 7; i++) {
0120             cyrix_get_arr(i, &lbase, &lsize, &ltype);
0121             if (lsize == 0)
0122                 return i;
0123         }
0124         /*
0125          * ARR0-ARR6 isn't free
0126          * try ARR7 but its size must be at least 256K
0127          */
0128         cyrix_get_arr(i, &lbase, &lsize, &ltype);
0129         if ((lsize == 0) && (size >= 0x40))
0130             return i;
0131     }
0132     return -ENOSPC;
0133 }
0134 
0135 static u32 cr4, ccr3;
0136 
0137 static void prepare_set(void)
0138 {
0139     u32 cr0;
0140 
0141     /*  Save value of CR4 and clear Page Global Enable (bit 7)  */
0142     if (boot_cpu_has(X86_FEATURE_PGE)) {
0143         cr4 = __read_cr4();
0144         __write_cr4(cr4 & ~X86_CR4_PGE);
0145     }
0146 
0147     /*
0148      * Disable and flush caches.
0149      * Note that wbinvd flushes the TLBs as a side-effect
0150      */
0151     cr0 = read_cr0() | X86_CR0_CD;
0152     wbinvd();
0153     write_cr0(cr0);
0154     wbinvd();
0155 
0156     /* Cyrix ARRs - everything else was excluded at the top */
0157     ccr3 = getCx86(CX86_CCR3);
0158 
0159     /* Cyrix ARRs - everything else was excluded at the top */
0160     setCx86(CX86_CCR3, (ccr3 & 0x0f) | 0x10);
0161 }
0162 
0163 static void post_set(void)
0164 {
0165     /* Flush caches and TLBs */
0166     wbinvd();
0167 
0168     /* Cyrix ARRs - everything else was excluded at the top */
0169     setCx86(CX86_CCR3, ccr3);
0170 
0171     /* Enable caches */
0172     write_cr0(read_cr0() & ~X86_CR0_CD);
0173 
0174     /* Restore value of CR4 */
0175     if (boot_cpu_has(X86_FEATURE_PGE))
0176         __write_cr4(cr4);
0177 }
0178 
0179 static void cyrix_set_arr(unsigned int reg, unsigned long base,
0180               unsigned long size, mtrr_type type)
0181 {
0182     unsigned char arr, arr_type, arr_size;
0183 
0184     arr = CX86_ARR_BASE + (reg << 1) + reg; /* avoid multiplication by 3 */
0185 
0186     /* count down from 32M (ARR0-ARR6) or from 2G (ARR7) */
0187     if (reg >= 7)
0188         size >>= 6;
0189 
0190     size &= 0x7fff;     /* make sure arr_size <= 14 */
0191     for (arr_size = 0; size; arr_size++, size >>= 1)
0192         ;
0193 
0194     if (reg < 7) {
0195         switch (type) {
0196         case MTRR_TYPE_UNCACHABLE:
0197             arr_type = 1;
0198             break;
0199         case MTRR_TYPE_WRCOMB:
0200             arr_type = 9;
0201             break;
0202         case MTRR_TYPE_WRTHROUGH:
0203             arr_type = 24;
0204             break;
0205         default:
0206             arr_type = 8;
0207             break;
0208         }
0209     } else {
0210         switch (type) {
0211         case MTRR_TYPE_UNCACHABLE:
0212             arr_type = 0;
0213             break;
0214         case MTRR_TYPE_WRCOMB:
0215             arr_type = 8;
0216             break;
0217         case MTRR_TYPE_WRTHROUGH:
0218             arr_type = 25;
0219             break;
0220         default:
0221             arr_type = 9;
0222             break;
0223         }
0224     }
0225 
0226     prepare_set();
0227 
0228     base <<= PAGE_SHIFT;
0229     setCx86(arr + 0,  ((unsigned char *)&base)[3]);
0230     setCx86(arr + 1,  ((unsigned char *)&base)[2]);
0231     setCx86(arr + 2, (((unsigned char *)&base)[1]) | arr_size);
0232     setCx86(CX86_RCR_BASE + reg, arr_type);
0233 
0234     post_set();
0235 }
0236 
0237 typedef struct {
0238     unsigned long   base;
0239     unsigned long   size;
0240     mtrr_type   type;
0241 } arr_state_t;
0242 
0243 static arr_state_t arr_state[8] = {
0244     {0UL, 0UL, 0UL}, {0UL, 0UL, 0UL}, {0UL, 0UL, 0UL}, {0UL, 0UL, 0UL},
0245     {0UL, 0UL, 0UL}, {0UL, 0UL, 0UL}, {0UL, 0UL, 0UL}, {0UL, 0UL, 0UL}
0246 };
0247 
0248 static unsigned char ccr_state[7] = { 0, 0, 0, 0, 0, 0, 0 };
0249 
0250 static void cyrix_set_all(void)
0251 {
0252     int i;
0253 
0254     prepare_set();
0255 
0256     /* the CCRs are not contiguous */
0257     for (i = 0; i < 4; i++)
0258         setCx86(CX86_CCR0 + i, ccr_state[i]);
0259     for (; i < 7; i++)
0260         setCx86(CX86_CCR4 + i, ccr_state[i]);
0261 
0262     for (i = 0; i < 8; i++) {
0263         cyrix_set_arr(i, arr_state[i].base,
0264                   arr_state[i].size, arr_state[i].type);
0265     }
0266 
0267     post_set();
0268 }
0269 
0270 static const struct mtrr_ops cyrix_mtrr_ops = {
0271     .vendor            = X86_VENDOR_CYRIX,
0272     .set_all       = cyrix_set_all,
0273     .set               = cyrix_set_arr,
0274     .get               = cyrix_get_arr,
0275     .get_free_region   = cyrix_get_free_region,
0276     .validate_add_page = generic_validate_add_page,
0277     .have_wrcomb       = positive_have_wrcomb,
0278 };
0279 
0280 int __init cyrix_init_mtrr(void)
0281 {
0282     set_mtrr_ops(&cyrix_mtrr_ops);
0283     return 0;
0284 }