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 <asm/processor-cyrix.h> 7 #include <asm/processor-flags.h> 8 #include "mtrr.h" 9 10 static void 11 cyrix_get_arr(unsigned int reg, unsigned long *base, 12 unsigned long *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 79 static int 80 cyrix_get_free_region(unsigned long base, unsigned long size, int replace_reg) 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, lsize; 90 91 switch (replace_reg) { 92 case 7: 93 if (size < 0x40) 94 break; 95 case 6: 96 case 5: 97 case 4: 98 return replace_reg; 99 case 3: 100 case 2: 101 case 1: 102 case 0: 103 return replace_reg; 104 } 105 /* If we are to set up a region >32M then look at ARR7 immediately */ 106 if (size > 0x2000) { 107 cyrix_get_arr(7, &lbase, &lsize, <ype); 108 if (lsize == 0) 109 return 7; 110 /* Else try ARR0-ARR6 first */ 111 } else { 112 for (i = 0; i < 7; i++) { 113 cyrix_get_arr(i, &lbase, &lsize, <ype); 114 if (lsize == 0) 115 return i; 116 } 117 /* ARR0-ARR6 isn't free, try ARR7 but its size must be at least 256K */ 118 cyrix_get_arr(i, &lbase, &lsize, <ype); 119 if ((lsize == 0) && (size >= 0x40)) 120 return i; 121 } 122 return -ENOSPC; 123 } 124 125 static u32 cr4 = 0; 126 static u32 ccr3; 127 128 static void prepare_set(void) 129 { 130 u32 cr0; 131 132 /* Save value of CR4 and clear Page Global Enable (bit 7) */ 133 if ( cpu_has_pge ) { 134 cr4 = read_cr4(); 135 write_cr4(cr4 & ~X86_CR4_PGE); 136 } 137 138 /* Disable and flush caches. Note that wbinvd flushes the TLBs as 139 a side-effect */ 140 cr0 = read_cr0() | X86_CR0_CD; 141 wbinvd(); 142 write_cr0(cr0); 143 wbinvd(); 144 145 /* Cyrix ARRs - everything else was excluded at the top */ 146 ccr3 = getCx86(CX86_CCR3); 147 148 /* Cyrix ARRs - everything else was excluded at the top */ 149 setCx86(CX86_CCR3, (ccr3 & 0x0f) | 0x10); 150 151 } 152 153 static void post_set(void) 154 { 155 /* Flush caches and TLBs */ 156 wbinvd(); 157 158 /* Cyrix ARRs - everything else was excluded at the top */ 159 setCx86(CX86_CCR3, ccr3); 160 161 /* Enable caches */ 162 write_cr0(read_cr0() & 0xbfffffff); 163 164 /* Restore value of CR4 */ 165 if ( cpu_has_pge ) 166 write_cr4(cr4); 167 } 168 169 static void cyrix_set_arr(unsigned int reg, unsigned long base, 170 unsigned long size, mtrr_type type) 171 { 172 unsigned char arr, arr_type, arr_size; 173 174 arr = CX86_ARR_BASE + (reg << 1) + reg; /* avoid multiplication by 3 */ 175 176 /* count down from 32M (ARR0-ARR6) or from 2G (ARR7) */ 177 if (reg >= 7) 178 size >>= 6; 179 180 size &= 0x7fff; /* make sure arr_size <= 14 */ 181 for (arr_size = 0; size; arr_size++, size >>= 1) ; 182 183 if (reg < 7) { 184 switch (type) { 185 case MTRR_TYPE_UNCACHABLE: 186 arr_type = 1; 187 break; 188 case MTRR_TYPE_WRCOMB: 189 arr_type = 9; 190 break; 191 case MTRR_TYPE_WRTHROUGH: 192 arr_type = 24; 193 break; 194 default: 195 arr_type = 8; 196 break; 197 } 198 } else { 199 switch (type) { 200 case MTRR_TYPE_UNCACHABLE: 201 arr_type = 0; 202 break; 203 case MTRR_TYPE_WRCOMB: 204 arr_type = 8; 205 break; 206 case MTRR_TYPE_WRTHROUGH: 207 arr_type = 25; 208 break; 209 default: 210 arr_type = 9; 211 break; 212 } 213 } 214 215 prepare_set(); 216 217 base <<= PAGE_SHIFT; 218 setCx86(arr, ((unsigned char *) &base)[3]); 219 setCx86(arr + 1, ((unsigned char *) &base)[2]); 220 setCx86(arr + 2, (((unsigned char *) &base)[1]) | arr_size); 221 setCx86(CX86_RCR_BASE + reg, arr_type); 222 223 post_set(); 224 } 225 226 typedef struct { 227 unsigned long base; 228 unsigned long size; 229 mtrr_type type; 230 } arr_state_t; 231 232 static arr_state_t arr_state[8] = { 233 {0UL, 0UL, 0UL}, {0UL, 0UL, 0UL}, {0UL, 0UL, 0UL}, {0UL, 0UL, 0UL}, 234 {0UL, 0UL, 0UL}, {0UL, 0UL, 0UL}, {0UL, 0UL, 0UL}, {0UL, 0UL, 0UL} 235 }; 236 237 static unsigned char ccr_state[7] = { 0, 0, 0, 0, 0, 0, 0 }; 238 239 static void cyrix_set_all(void) 240 { 241 int i; 242 243 prepare_set(); 244 245 /* the CCRs are not contiguous */ 246 for (i = 0; i < 4; i++) 247 setCx86(CX86_CCR0 + i, ccr_state[i]); 248 for (; i < 7; i++) 249 setCx86(CX86_CCR4 + i, ccr_state[i]); 250 for (i = 0; i < 8; i++) 251 cyrix_set_arr(i, arr_state[i].base, 252 arr_state[i].size, arr_state[i].type); 253 254 post_set(); 255 } 256 257 static struct mtrr_ops cyrix_mtrr_ops = { 258 .vendor = X86_VENDOR_CYRIX, 259 // .init = cyrix_arr_init, 260 .set_all = cyrix_set_all, 261 .set = cyrix_set_arr, 262 .get = cyrix_get_arr, 263 .get_free_region = cyrix_get_free_region, 264 .validate_add_page = generic_validate_add_page, 265 .have_wrcomb = positive_have_wrcomb, 266 }; 267 268 int __init cyrix_init_mtrr(void) 269 { 270 set_mtrr_ops(&cyrix_mtrr_ops); 271 return 0; 272 } 273 274 //arch_initcall(cyrix_init_mtrr); 275