0001
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;
0021
0022 local_irq_save(flags);
0023
0024 ccr3 = getCx86(CX86_CCR3);
0025 setCx86(CX86_CCR3, (ccr3 & 0x0f) | 0x10);
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);
0031
0032 local_irq_restore(flags);
0033
0034 shift = ((unsigned char *) base)[1] & 0x0f;
0035 *base >>= PAGE_SHIFT;
0036
0037
0038
0039
0040
0041 if (shift)
0042 *size = (reg < 7 ? 0x1UL : 0x40UL) << (shift - 1);
0043 else
0044 *size = 0;
0045
0046
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
0084
0085
0086
0087
0088
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
0113 if (size > 0x2000) {
0114 cyrix_get_arr(7, &lbase, &lsize, <ype);
0115 if (lsize == 0)
0116 return 7;
0117
0118 } else {
0119 for (i = 0; i < 7; i++) {
0120 cyrix_get_arr(i, &lbase, &lsize, <ype);
0121 if (lsize == 0)
0122 return i;
0123 }
0124
0125
0126
0127
0128 cyrix_get_arr(i, &lbase, &lsize, <ype);
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
0142 if (boot_cpu_has(X86_FEATURE_PGE)) {
0143 cr4 = __read_cr4();
0144 __write_cr4(cr4 & ~X86_CR4_PGE);
0145 }
0146
0147
0148
0149
0150
0151 cr0 = read_cr0() | X86_CR0_CD;
0152 wbinvd();
0153 write_cr0(cr0);
0154 wbinvd();
0155
0156
0157 ccr3 = getCx86(CX86_CCR3);
0158
0159
0160 setCx86(CX86_CCR3, (ccr3 & 0x0f) | 0x10);
0161 }
0162
0163 static void post_set(void)
0164 {
0165
0166 wbinvd();
0167
0168
0169 setCx86(CX86_CCR3, ccr3);
0170
0171
0172 write_cr0(read_cr0() & ~X86_CR0_CD);
0173
0174
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;
0185
0186
0187 if (reg >= 7)
0188 size >>= 6;
0189
0190 size &= 0x7fff;
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
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 }