1 #include <linux/init.h> 2 #include <linux/mm.h> 3 #include <asm/mtrr.h> 4 #include <asm/msr.h> 5 #include "mtrr.h" 6 7 static struct { 8 unsigned long high; 9 unsigned long low; 10 } centaur_mcr[8]; 11 12 static u8 centaur_mcr_reserved; 13 static u8 centaur_mcr_type; /* 0 for winchip, 1 for winchip2 */ 14 15 /* 16 * Report boot time MCR setups 17 */ 18 19 static int 20 centaur_get_free_region(unsigned long base, unsigned long size, int replace_reg) 21 /* [SUMMARY] Get a free MTRR. 22 <base> The starting (base) address of the region. 23 <size> The size (in bytes) of the region. 24 [RETURNS] The index of the region on success, else -1 on error. 25 */ 26 { 27 int i, max; 28 mtrr_type ltype; 29 unsigned long lbase, lsize; 30 31 max = num_var_ranges; 32 if (replace_reg >= 0 && replace_reg < max) 33 return replace_reg; 34 for (i = 0; i < max; ++i) { 35 if (centaur_mcr_reserved & (1 << i)) 36 continue; 37 mtrr_if->get(i, &lbase, &lsize, <ype); 38 if (lsize == 0) 39 return i; 40 } 41 return -ENOSPC; 42 } 43 44 void 45 mtrr_centaur_report_mcr(int mcr, u32 lo, u32 hi) 46 { 47 centaur_mcr[mcr].low = lo; 48 centaur_mcr[mcr].high = hi; 49 } 50 51 static void 52 centaur_get_mcr(unsigned int reg, unsigned long *base, 53 unsigned long *size, mtrr_type * type) 54 { 55 *base = centaur_mcr[reg].high >> PAGE_SHIFT; 56 *size = -(centaur_mcr[reg].low & 0xfffff000) >> PAGE_SHIFT; 57 *type = MTRR_TYPE_WRCOMB; /* If it is there, it is write-combining */ 58 if (centaur_mcr_type == 1 && ((centaur_mcr[reg].low & 31) & 2)) 59 *type = MTRR_TYPE_UNCACHABLE; 60 if (centaur_mcr_type == 1 && (centaur_mcr[reg].low & 31) == 25) 61 *type = MTRR_TYPE_WRBACK; 62 if (centaur_mcr_type == 0 && (centaur_mcr[reg].low & 31) == 31) 63 *type = MTRR_TYPE_WRBACK; 64 65 } 66 67 static void centaur_set_mcr(unsigned int reg, unsigned long base, 68 unsigned long size, mtrr_type type) 69 { 70 unsigned long low, high; 71 72 if (size == 0) { 73 /* Disable */ 74 high = low = 0; 75 } else { 76 high = base << PAGE_SHIFT; 77 if (centaur_mcr_type == 0) 78 low = -size << PAGE_SHIFT | 0x1f; /* only support write-combining... */ 79 else { 80 if (type == MTRR_TYPE_UNCACHABLE) 81 low = -size << PAGE_SHIFT | 0x02; /* NC */ 82 else 83 low = -size << PAGE_SHIFT | 0x09; /* WWO,WC */ 84 } 85 } 86 centaur_mcr[reg].high = high; 87 centaur_mcr[reg].low = low; 88 wrmsr(MSR_IDT_MCR0 + reg, low, high); 89 } 90 91 #if 0 92 /* 93 * Initialise the later (saner) Winchip MCR variant. In this version 94 * the BIOS can pass us the registers it has used (but not their values) 95 * and the control register is read/write 96 */ 97 98 static void __init 99 centaur_mcr1_init(void) 100 { 101 unsigned i; 102 u32 lo, hi; 103 104 /* Unfortunately, MCR's are read-only, so there is no way to 105 * find out what the bios might have done. 106 */ 107 108 rdmsr(MSR_IDT_MCR_CTRL, lo, hi); 109 if (((lo >> 17) & 7) == 1) { /* Type 1 Winchip2 MCR */ 110 lo &= ~0x1C0; /* clear key */ 111 lo |= 0x040; /* set key to 1 */ 112 wrmsr(MSR_IDT_MCR_CTRL, lo, hi); /* unlock MCR */ 113 } 114 115 centaur_mcr_type = 1; 116 117 /* 118 * Clear any unconfigured MCR's. 119 */ 120 121 for (i = 0; i < 8; ++i) { 122 if (centaur_mcr[i].high == 0 && centaur_mcr[i].low == 0) { 123 if (!(lo & (1 << (9 + i)))) 124 wrmsr(MSR_IDT_MCR0 + i, 0, 0); 125 else 126 /* 127 * If the BIOS set up an MCR we cannot see it 128 * but we don't wish to obliterate it 129 */ 130 centaur_mcr_reserved |= (1 << i); 131 } 132 } 133 /* 134 * Throw the main write-combining switch... 135 * However if OOSTORE is enabled then people have already done far 136 * cleverer things and we should behave. 137 */ 138 139 lo |= 15; /* Write combine enables */ 140 wrmsr(MSR_IDT_MCR_CTRL, lo, hi); 141 } 142 143 /* 144 * Initialise the original winchip with read only MCR registers 145 * no used bitmask for the BIOS to pass on and write only control 146 */ 147 148 static void __init 149 centaur_mcr0_init(void) 150 { 151 unsigned i; 152 153 /* Unfortunately, MCR's are read-only, so there is no way to 154 * find out what the bios might have done. 155 */ 156 157 /* Clear any unconfigured MCR's. 158 * This way we are sure that the centaur_mcr array contains the actual 159 * values. The disadvantage is that any BIOS tweaks are thus undone. 160 * 161 */ 162 for (i = 0; i < 8; ++i) { 163 if (centaur_mcr[i].high == 0 && centaur_mcr[i].low == 0) 164 wrmsr(MSR_IDT_MCR0 + i, 0, 0); 165 } 166 167 wrmsr(MSR_IDT_MCR_CTRL, 0x01F0001F, 0); /* Write only */ 168 } 169 170 /* 171 * Initialise Winchip series MCR registers 172 */ 173 174 static void __init 175 centaur_mcr_init(void) 176 { 177 struct set_mtrr_context ctxt; 178 179 set_mtrr_prepare_save(&ctxt); 180 set_mtrr_cache_disable(&ctxt); 181 182 if (boot_cpu_data.x86_model == 4) 183 centaur_mcr0_init(); 184 else if (boot_cpu_data.x86_model == 8 || boot_cpu_data.x86_model == 9) 185 centaur_mcr1_init(); 186 187 set_mtrr_done(&ctxt); 188 } 189 #endif 190 191 static int centaur_validate_add_page(unsigned long base, 192 unsigned long size, unsigned int type) 193 { 194 /* 195 * FIXME: Winchip2 supports uncached 196 */ 197 if (type != MTRR_TYPE_WRCOMB && 198 (centaur_mcr_type == 0 || type != MTRR_TYPE_UNCACHABLE)) { 199 printk(KERN_WARNING 200 "mtrr: only write-combining%s supported\n", 201 centaur_mcr_type ? " and uncacheable are" 202 : " is"); 203 return -EINVAL; 204 } 205 return 0; 206 } 207 208 static struct mtrr_ops centaur_mtrr_ops = { 209 .vendor = X86_VENDOR_CENTAUR, 210 // .init = centaur_mcr_init, 211 .set = centaur_set_mcr, 212 .get = centaur_get_mcr, 213 .get_free_region = centaur_get_free_region, 214 .validate_add_page = centaur_validate_add_page, 215 .have_wrcomb = positive_have_wrcomb, 216 }; 217 218 int __init centaur_init_mtrr(void) 219 { 220 set_mtrr_ops(¢aur_mtrr_ops); 221 return 0; 222 } 223 224 //arch_initcall(centaur_init_mtrr); 225