1f7627e25SThomas Gleixner #include <linux/kernel.h> 2f7627e25SThomas Gleixner #include <linux/init.h> 3f7627e25SThomas Gleixner #include <linux/bitops.h> 4*edc05e6dSIngo Molnar 5f7627e25SThomas Gleixner #include <asm/processor.h> 6f7627e25SThomas Gleixner #include <asm/msr.h> 7f7627e25SThomas Gleixner #include <asm/e820.h> 8f7627e25SThomas Gleixner #include <asm/mtrr.h> 9*edc05e6dSIngo Molnar 10f7627e25SThomas Gleixner #include "cpu.h" 11f7627e25SThomas Gleixner 12f7627e25SThomas Gleixner #ifdef CONFIG_X86_OOSTORE 13f7627e25SThomas Gleixner 14f7627e25SThomas Gleixner static u32 __cpuinit power2(u32 x) 15f7627e25SThomas Gleixner { 16f7627e25SThomas Gleixner u32 s = 1; 17*edc05e6dSIngo Molnar 18f7627e25SThomas Gleixner while (s <= x) 19f7627e25SThomas Gleixner s <<= 1; 20*edc05e6dSIngo Molnar 21f7627e25SThomas Gleixner return s >>= 1; 22f7627e25SThomas Gleixner } 23f7627e25SThomas Gleixner 24f7627e25SThomas Gleixner 25f7627e25SThomas Gleixner /* 26f7627e25SThomas Gleixner * Set up an actual MCR 27f7627e25SThomas Gleixner */ 28f7627e25SThomas Gleixner static void __cpuinit centaur_mcr_insert(int reg, u32 base, u32 size, int key) 29f7627e25SThomas Gleixner { 30f7627e25SThomas Gleixner u32 lo, hi; 31f7627e25SThomas Gleixner 32f7627e25SThomas Gleixner hi = base & ~0xFFF; 33f7627e25SThomas Gleixner lo = ~(size-1); /* Size is a power of 2 so this makes a mask */ 34f7627e25SThomas Gleixner lo &= ~0xFFF; /* Remove the ctrl value bits */ 35f7627e25SThomas Gleixner lo |= key; /* Attribute we wish to set */ 36f7627e25SThomas Gleixner wrmsr(reg+MSR_IDT_MCR0, lo, hi); 37f7627e25SThomas Gleixner mtrr_centaur_report_mcr(reg, lo, hi); /* Tell the mtrr driver */ 38f7627e25SThomas Gleixner } 39f7627e25SThomas Gleixner 40f7627e25SThomas Gleixner /* 41f7627e25SThomas Gleixner * Figure what we can cover with MCR's 42f7627e25SThomas Gleixner * 43f7627e25SThomas Gleixner * Shortcut: We know you can't put 4Gig of RAM on a winchip 44f7627e25SThomas Gleixner */ 45*edc05e6dSIngo Molnar static u32 __cpuinit ramtop(void) 46f7627e25SThomas Gleixner { 47f7627e25SThomas Gleixner u32 clip = 0xFFFFFFFFUL; 48*edc05e6dSIngo Molnar u32 top = 0; 49*edc05e6dSIngo Molnar int i; 50f7627e25SThomas Gleixner 51f7627e25SThomas Gleixner for (i = 0; i < e820.nr_map; i++) { 52f7627e25SThomas Gleixner unsigned long start, end; 53f7627e25SThomas Gleixner 54f7627e25SThomas Gleixner if (e820.map[i].addr > 0xFFFFFFFFUL) 55f7627e25SThomas Gleixner continue; 56f7627e25SThomas Gleixner /* 57f7627e25SThomas Gleixner * Don't MCR over reserved space. Ignore the ISA hole 5827b46d76SSimon Arlott * we frob around that catastrophe already 59f7627e25SThomas Gleixner */ 60*edc05e6dSIngo Molnar if (e820.map[i].type == E820_RESERVED) { 61*edc05e6dSIngo Molnar if (e820.map[i].addr >= 0x100000UL && 62*edc05e6dSIngo Molnar e820.map[i].addr < clip) 63f7627e25SThomas Gleixner clip = e820.map[i].addr; 64f7627e25SThomas Gleixner continue; 65f7627e25SThomas Gleixner } 66f7627e25SThomas Gleixner start = e820.map[i].addr; 67f7627e25SThomas Gleixner end = e820.map[i].addr + e820.map[i].size; 68f7627e25SThomas Gleixner if (start >= end) 69f7627e25SThomas Gleixner continue; 70f7627e25SThomas Gleixner if (end > top) 71f7627e25SThomas Gleixner top = end; 72f7627e25SThomas Gleixner } 73*edc05e6dSIngo Molnar /* 74*edc05e6dSIngo Molnar * Everything below 'top' should be RAM except for the ISA hole. 75*edc05e6dSIngo Molnar * Because of the limited MCR's we want to map NV/ACPI into our 76*edc05e6dSIngo Molnar * MCR range for gunk in RAM 77*edc05e6dSIngo Molnar * 78*edc05e6dSIngo Molnar * Clip might cause us to MCR insufficient RAM but that is an 79*edc05e6dSIngo Molnar * acceptable failure mode and should only bite obscure boxes with 80*edc05e6dSIngo Molnar * a VESA hole at 15Mb 81*edc05e6dSIngo Molnar * 82*edc05e6dSIngo Molnar * The second case Clip sometimes kicks in is when the EBDA is marked 83*edc05e6dSIngo Molnar * as reserved. Again we fail safe with reasonable results 84f7627e25SThomas Gleixner */ 85f7627e25SThomas Gleixner if (top > clip) 86f7627e25SThomas Gleixner top = clip; 87f7627e25SThomas Gleixner 88f7627e25SThomas Gleixner return top; 89f7627e25SThomas Gleixner } 90f7627e25SThomas Gleixner 91f7627e25SThomas Gleixner /* 92f7627e25SThomas Gleixner * Compute a set of MCR's to give maximum coverage 93f7627e25SThomas Gleixner */ 94f7627e25SThomas Gleixner static int __cpuinit centaur_mcr_compute(int nr, int key) 95f7627e25SThomas Gleixner { 96f7627e25SThomas Gleixner u32 mem = ramtop(); 97f7627e25SThomas Gleixner u32 root = power2(mem); 98f7627e25SThomas Gleixner u32 base = root; 99f7627e25SThomas Gleixner u32 top = root; 100f7627e25SThomas Gleixner u32 floor = 0; 101f7627e25SThomas Gleixner int ct = 0; 102f7627e25SThomas Gleixner 103*edc05e6dSIngo Molnar while (ct < nr) { 104f7627e25SThomas Gleixner u32 fspace = 0; 105*edc05e6dSIngo Molnar u32 high; 106*edc05e6dSIngo Molnar u32 low; 107f7627e25SThomas Gleixner 108f7627e25SThomas Gleixner /* 109f7627e25SThomas Gleixner * Find the largest block we will fill going upwards 110f7627e25SThomas Gleixner */ 111*edc05e6dSIngo Molnar high = power2(mem-top); 112f7627e25SThomas Gleixner 113f7627e25SThomas Gleixner /* 114f7627e25SThomas Gleixner * Find the largest block we will fill going downwards 115f7627e25SThomas Gleixner */ 116*edc05e6dSIngo Molnar low = base/2; 117f7627e25SThomas Gleixner 118f7627e25SThomas Gleixner /* 119f7627e25SThomas Gleixner * Don't fill below 1Mb going downwards as there 120f7627e25SThomas Gleixner * is an ISA hole in the way. 121f7627e25SThomas Gleixner */ 122f7627e25SThomas Gleixner if (base <= 1024*1024) 123f7627e25SThomas Gleixner low = 0; 124f7627e25SThomas Gleixner 125f7627e25SThomas Gleixner /* 126f7627e25SThomas Gleixner * See how much space we could cover by filling below 127f7627e25SThomas Gleixner * the ISA hole 128f7627e25SThomas Gleixner */ 129f7627e25SThomas Gleixner 130f7627e25SThomas Gleixner if (floor == 0) 131f7627e25SThomas Gleixner fspace = 512*1024; 132f7627e25SThomas Gleixner else if (floor == 512*1024) 133f7627e25SThomas Gleixner fspace = 128*1024; 134f7627e25SThomas Gleixner 135f7627e25SThomas Gleixner /* And forget ROM space */ 136f7627e25SThomas Gleixner 137f7627e25SThomas Gleixner /* 138f7627e25SThomas Gleixner * Now install the largest coverage we get 139f7627e25SThomas Gleixner */ 140*edc05e6dSIngo Molnar if (fspace > high && fspace > low) { 141f7627e25SThomas Gleixner centaur_mcr_insert(ct, floor, fspace, key); 142f7627e25SThomas Gleixner floor += fspace; 143*edc05e6dSIngo Molnar } else if (high > low) { 144f7627e25SThomas Gleixner centaur_mcr_insert(ct, top, high, key); 145f7627e25SThomas Gleixner top += high; 146*edc05e6dSIngo Molnar } else if (low > 0) { 147f7627e25SThomas Gleixner base -= low; 148f7627e25SThomas Gleixner centaur_mcr_insert(ct, base, low, key); 149*edc05e6dSIngo Molnar } else 150*edc05e6dSIngo Molnar break; 151f7627e25SThomas Gleixner ct++; 152f7627e25SThomas Gleixner } 153f7627e25SThomas Gleixner /* 154f7627e25SThomas Gleixner * We loaded ct values. We now need to set the mask. The caller 155f7627e25SThomas Gleixner * must do this bit. 156f7627e25SThomas Gleixner */ 157f7627e25SThomas Gleixner return ct; 158f7627e25SThomas Gleixner } 159f7627e25SThomas Gleixner 160f7627e25SThomas Gleixner static void __cpuinit centaur_create_optimal_mcr(void) 161f7627e25SThomas Gleixner { 162*edc05e6dSIngo Molnar int used; 163f7627e25SThomas Gleixner int i; 164*edc05e6dSIngo Molnar 165f7627e25SThomas Gleixner /* 166f7627e25SThomas Gleixner * Allocate up to 6 mcrs to mark as much of ram as possible 167f7627e25SThomas Gleixner * as write combining and weak write ordered. 168f7627e25SThomas Gleixner * 169f7627e25SThomas Gleixner * To experiment with: Linux never uses stack operations for 170f7627e25SThomas Gleixner * mmio spaces so we could globally enable stack operation wc 171f7627e25SThomas Gleixner * 172f7627e25SThomas Gleixner * Load the registers with type 31 - full write combining, all 173f7627e25SThomas Gleixner * writes weakly ordered. 174f7627e25SThomas Gleixner */ 175*edc05e6dSIngo Molnar used = centaur_mcr_compute(6, 31); 176f7627e25SThomas Gleixner 177f7627e25SThomas Gleixner /* 178f7627e25SThomas Gleixner * Wipe unused MCRs 179f7627e25SThomas Gleixner */ 180f7627e25SThomas Gleixner for (i = used; i < 8; i++) 181f7627e25SThomas Gleixner wrmsr(MSR_IDT_MCR0+i, 0, 0); 182f7627e25SThomas Gleixner } 183f7627e25SThomas Gleixner 184f7627e25SThomas Gleixner static void __cpuinit winchip2_create_optimal_mcr(void) 185f7627e25SThomas Gleixner { 186f7627e25SThomas Gleixner u32 lo, hi; 187*edc05e6dSIngo Molnar int used; 188f7627e25SThomas Gleixner int i; 189f7627e25SThomas Gleixner 190f7627e25SThomas Gleixner /* 191f7627e25SThomas Gleixner * Allocate up to 6 mcrs to mark as much of ram as possible 192f7627e25SThomas Gleixner * as write combining, weak store ordered. 193f7627e25SThomas Gleixner * 194f7627e25SThomas Gleixner * Load the registers with type 25 195f7627e25SThomas Gleixner * 8 - weak write ordering 196f7627e25SThomas Gleixner * 16 - weak read ordering 197f7627e25SThomas Gleixner * 1 - write combining 198f7627e25SThomas Gleixner */ 199*edc05e6dSIngo Molnar used = centaur_mcr_compute(6, 25); 200f7627e25SThomas Gleixner 201f7627e25SThomas Gleixner /* 202f7627e25SThomas Gleixner * Mark the registers we are using. 203f7627e25SThomas Gleixner */ 204f7627e25SThomas Gleixner rdmsr(MSR_IDT_MCR_CTRL, lo, hi); 205f7627e25SThomas Gleixner for (i = 0; i < used; i++) 206f7627e25SThomas Gleixner lo |= 1<<(9+i); 207f7627e25SThomas Gleixner wrmsr(MSR_IDT_MCR_CTRL, lo, hi); 208f7627e25SThomas Gleixner 209f7627e25SThomas Gleixner /* 210f7627e25SThomas Gleixner * Wipe unused MCRs 211f7627e25SThomas Gleixner */ 212f7627e25SThomas Gleixner 213f7627e25SThomas Gleixner for (i = used; i < 8; i++) 214f7627e25SThomas Gleixner wrmsr(MSR_IDT_MCR0+i, 0, 0); 215f7627e25SThomas Gleixner } 216f7627e25SThomas Gleixner 217f7627e25SThomas Gleixner /* 218f7627e25SThomas Gleixner * Handle the MCR key on the Winchip 2. 219f7627e25SThomas Gleixner */ 220f7627e25SThomas Gleixner static void __cpuinit winchip2_unprotect_mcr(void) 221f7627e25SThomas Gleixner { 222f7627e25SThomas Gleixner u32 lo, hi; 223f7627e25SThomas Gleixner u32 key; 224f7627e25SThomas Gleixner 225f7627e25SThomas Gleixner rdmsr(MSR_IDT_MCR_CTRL, lo, hi); 226f7627e25SThomas Gleixner lo &= ~0x1C0; /* blank bits 8-6 */ 227f7627e25SThomas Gleixner key = (lo>>17) & 7; 228f7627e25SThomas Gleixner lo |= key<<6; /* replace with unlock key */ 229f7627e25SThomas Gleixner wrmsr(MSR_IDT_MCR_CTRL, lo, hi); 230f7627e25SThomas Gleixner } 231f7627e25SThomas Gleixner 232f7627e25SThomas Gleixner static void __cpuinit winchip2_protect_mcr(void) 233f7627e25SThomas Gleixner { 234f7627e25SThomas Gleixner u32 lo, hi; 235f7627e25SThomas Gleixner 236f7627e25SThomas Gleixner rdmsr(MSR_IDT_MCR_CTRL, lo, hi); 237f7627e25SThomas Gleixner lo &= ~0x1C0; /* blank bits 8-6 */ 238f7627e25SThomas Gleixner wrmsr(MSR_IDT_MCR_CTRL, lo, hi); 239f7627e25SThomas Gleixner } 240f7627e25SThomas Gleixner #endif /* CONFIG_X86_OOSTORE */ 241f7627e25SThomas Gleixner 242f7627e25SThomas Gleixner #define ACE_PRESENT (1 << 6) 243f7627e25SThomas Gleixner #define ACE_ENABLED (1 << 7) 244f7627e25SThomas Gleixner #define ACE_FCR (1 << 28) /* MSR_VIA_FCR */ 245f7627e25SThomas Gleixner 246f7627e25SThomas Gleixner #define RNG_PRESENT (1 << 2) 247f7627e25SThomas Gleixner #define RNG_ENABLED (1 << 3) 248f7627e25SThomas Gleixner #define RNG_ENABLE (1 << 6) /* MSR_VIA_RNG */ 249f7627e25SThomas Gleixner 250f7627e25SThomas Gleixner static void __cpuinit init_c3(struct cpuinfo_x86 *c) 251f7627e25SThomas Gleixner { 252f7627e25SThomas Gleixner u32 lo, hi; 253f7627e25SThomas Gleixner 254f7627e25SThomas Gleixner /* Test for Centaur Extended Feature Flags presence */ 255f7627e25SThomas Gleixner if (cpuid_eax(0xC0000000) >= 0xC0000001) { 256f7627e25SThomas Gleixner u32 tmp = cpuid_edx(0xC0000001); 257f7627e25SThomas Gleixner 258f7627e25SThomas Gleixner /* enable ACE unit, if present and disabled */ 259f7627e25SThomas Gleixner if ((tmp & (ACE_PRESENT | ACE_ENABLED)) == ACE_PRESENT) { 260f7627e25SThomas Gleixner rdmsr(MSR_VIA_FCR, lo, hi); 261f7627e25SThomas Gleixner lo |= ACE_FCR; /* enable ACE unit */ 262f7627e25SThomas Gleixner wrmsr(MSR_VIA_FCR, lo, hi); 263f7627e25SThomas Gleixner printk(KERN_INFO "CPU: Enabled ACE h/w crypto\n"); 264f7627e25SThomas Gleixner } 265f7627e25SThomas Gleixner 266f7627e25SThomas Gleixner /* enable RNG unit, if present and disabled */ 267f7627e25SThomas Gleixner if ((tmp & (RNG_PRESENT | RNG_ENABLED)) == RNG_PRESENT) { 268f7627e25SThomas Gleixner rdmsr(MSR_VIA_RNG, lo, hi); 269f7627e25SThomas Gleixner lo |= RNG_ENABLE; /* enable RNG unit */ 270f7627e25SThomas Gleixner wrmsr(MSR_VIA_RNG, lo, hi); 271f7627e25SThomas Gleixner printk(KERN_INFO "CPU: Enabled h/w RNG\n"); 272f7627e25SThomas Gleixner } 273f7627e25SThomas Gleixner 274f7627e25SThomas Gleixner /* store Centaur Extended Feature Flags as 275f7627e25SThomas Gleixner * word 5 of the CPU capability bit array 276f7627e25SThomas Gleixner */ 277f7627e25SThomas Gleixner c->x86_capability[5] = cpuid_edx(0xC0000001); 278f7627e25SThomas Gleixner } 279f7627e25SThomas Gleixner 28027b46d76SSimon Arlott /* Cyrix III family needs CX8 & PGE explicitly enabled. */ 281f7627e25SThomas Gleixner if (c->x86_model >= 6 && c->x86_model <= 9) { 282f7627e25SThomas Gleixner rdmsr(MSR_VIA_FCR, lo, hi); 283f7627e25SThomas Gleixner lo |= (1<<1 | 1<<7); 284f7627e25SThomas Gleixner wrmsr(MSR_VIA_FCR, lo, hi); 285f7627e25SThomas Gleixner set_bit(X86_FEATURE_CX8, c->x86_capability); 286f7627e25SThomas Gleixner } 287f7627e25SThomas Gleixner 288f7627e25SThomas Gleixner /* Before Nehemiah, the C3's had 3dNOW! */ 289f7627e25SThomas Gleixner if (c->x86_model >= 6 && c->x86_model < 9) 290f7627e25SThomas Gleixner set_bit(X86_FEATURE_3DNOW, c->x86_capability); 291f7627e25SThomas Gleixner 292f7627e25SThomas Gleixner get_model_name(c); 293f7627e25SThomas Gleixner display_cacheinfo(c); 294f7627e25SThomas Gleixner } 295f7627e25SThomas Gleixner 296f7627e25SThomas Gleixner enum { 297f7627e25SThomas Gleixner ECX8 = 1<<1, 298f7627e25SThomas Gleixner EIERRINT = 1<<2, 299f7627e25SThomas Gleixner DPM = 1<<3, 300f7627e25SThomas Gleixner DMCE = 1<<4, 301f7627e25SThomas Gleixner DSTPCLK = 1<<5, 302f7627e25SThomas Gleixner ELINEAR = 1<<6, 303f7627e25SThomas Gleixner DSMC = 1<<7, 304f7627e25SThomas Gleixner DTLOCK = 1<<8, 305f7627e25SThomas Gleixner EDCTLB = 1<<8, 306f7627e25SThomas Gleixner EMMX = 1<<9, 307f7627e25SThomas Gleixner DPDC = 1<<11, 308f7627e25SThomas Gleixner EBRPRED = 1<<12, 309f7627e25SThomas Gleixner DIC = 1<<13, 310f7627e25SThomas Gleixner DDC = 1<<14, 311f7627e25SThomas Gleixner DNA = 1<<15, 312f7627e25SThomas Gleixner ERETSTK = 1<<16, 313f7627e25SThomas Gleixner E2MMX = 1<<19, 314f7627e25SThomas Gleixner EAMD3D = 1<<20, 315f7627e25SThomas Gleixner }; 316f7627e25SThomas Gleixner 317*edc05e6dSIngo Molnar static void __cpuinit init_centaur(struct cpuinfo_x86 *c) 318*edc05e6dSIngo Molnar { 319*edc05e6dSIngo Molnar 320f7627e25SThomas Gleixner char *name; 321f7627e25SThomas Gleixner u32 fcr_set = 0; 322f7627e25SThomas Gleixner u32 fcr_clr = 0; 323f7627e25SThomas Gleixner u32 lo, hi, newlo; 324f7627e25SThomas Gleixner u32 aa, bb, cc, dd; 325f7627e25SThomas Gleixner 326*edc05e6dSIngo Molnar /* 327*edc05e6dSIngo Molnar * Bit 31 in normal CPUID used for nonstandard 3DNow ID; 328*edc05e6dSIngo Molnar * 3DNow is IDd by bit 31 in extended CPUID (1*32+31) anyway 329*edc05e6dSIngo Molnar */ 330f7627e25SThomas Gleixner clear_bit(0*32+31, c->x86_capability); 331f7627e25SThomas Gleixner 332f7627e25SThomas Gleixner switch (c->x86) { 333f7627e25SThomas Gleixner case 5: 334f7627e25SThomas Gleixner switch (c->x86_model) { 335f7627e25SThomas Gleixner case 4: 336f7627e25SThomas Gleixner name = "C6"; 337f7627e25SThomas Gleixner fcr_set = ECX8|DSMC|EDCTLB|EMMX|ERETSTK; 338f7627e25SThomas Gleixner fcr_clr = DPDC; 339f7627e25SThomas Gleixner printk(KERN_NOTICE "Disabling bugged TSC.\n"); 340f7627e25SThomas Gleixner clear_bit(X86_FEATURE_TSC, c->x86_capability); 341f7627e25SThomas Gleixner #ifdef CONFIG_X86_OOSTORE 342f7627e25SThomas Gleixner centaur_create_optimal_mcr(); 343*edc05e6dSIngo Molnar /* 344*edc05e6dSIngo Molnar * Enable: 345*edc05e6dSIngo Molnar * write combining on non-stack, non-string 346*edc05e6dSIngo Molnar * write combining on string, all types 347*edc05e6dSIngo Molnar * weak write ordering 348*edc05e6dSIngo Molnar * 349*edc05e6dSIngo Molnar * The C6 original lacks weak read order 350*edc05e6dSIngo Molnar * 351*edc05e6dSIngo Molnar * Note 0x120 is write only on Winchip 1 352*edc05e6dSIngo Molnar */ 353f7627e25SThomas Gleixner wrmsr(MSR_IDT_MCR_CTRL, 0x01F0001F, 0); 354f7627e25SThomas Gleixner #endif 355f7627e25SThomas Gleixner break; 356f7627e25SThomas Gleixner case 8: 357f7627e25SThomas Gleixner switch (c->x86_mask) { 358f7627e25SThomas Gleixner default: 359f7627e25SThomas Gleixner name = "2"; 360f7627e25SThomas Gleixner break; 361f7627e25SThomas Gleixner case 7 ... 9: 362f7627e25SThomas Gleixner name = "2A"; 363f7627e25SThomas Gleixner break; 364f7627e25SThomas Gleixner case 10 ... 15: 365f7627e25SThomas Gleixner name = "2B"; 366f7627e25SThomas Gleixner break; 367f7627e25SThomas Gleixner } 368*edc05e6dSIngo Molnar fcr_set = ECX8|DSMC|DTLOCK|EMMX|EBRPRED|ERETSTK| 369*edc05e6dSIngo Molnar E2MMX|EAMD3D; 370f7627e25SThomas Gleixner fcr_clr = DPDC; 371f7627e25SThomas Gleixner #ifdef CONFIG_X86_OOSTORE 372f7627e25SThomas Gleixner winchip2_unprotect_mcr(); 373f7627e25SThomas Gleixner winchip2_create_optimal_mcr(); 374f7627e25SThomas Gleixner rdmsr(MSR_IDT_MCR_CTRL, lo, hi); 375*edc05e6dSIngo Molnar /* 376*edc05e6dSIngo Molnar * Enable: 377*edc05e6dSIngo Molnar * write combining on non-stack, non-string 378*edc05e6dSIngo Molnar * write combining on string, all types 379*edc05e6dSIngo Molnar * weak write ordering 380f7627e25SThomas Gleixner */ 381f7627e25SThomas Gleixner lo |= 31; 382f7627e25SThomas Gleixner wrmsr(MSR_IDT_MCR_CTRL, lo, hi); 383f7627e25SThomas Gleixner winchip2_protect_mcr(); 384f7627e25SThomas Gleixner #endif 385f7627e25SThomas Gleixner break; 386f7627e25SThomas Gleixner case 9: 387f7627e25SThomas Gleixner name = "3"; 388*edc05e6dSIngo Molnar fcr_set = ECX8|DSMC|DTLOCK|EMMX|EBRPRED|ERETSTK| 389*edc05e6dSIngo Molnar E2MMX|EAMD3D; 390f7627e25SThomas Gleixner fcr_clr = DPDC; 391f7627e25SThomas Gleixner #ifdef CONFIG_X86_OOSTORE 392f7627e25SThomas Gleixner winchip2_unprotect_mcr(); 393f7627e25SThomas Gleixner winchip2_create_optimal_mcr(); 394f7627e25SThomas Gleixner rdmsr(MSR_IDT_MCR_CTRL, lo, hi); 395*edc05e6dSIngo Molnar /* 396*edc05e6dSIngo Molnar * Enable: 397*edc05e6dSIngo Molnar * write combining on non-stack, non-string 398*edc05e6dSIngo Molnar * write combining on string, all types 399*edc05e6dSIngo Molnar * weak write ordering 400f7627e25SThomas Gleixner */ 401f7627e25SThomas Gleixner lo |= 31; 402f7627e25SThomas Gleixner wrmsr(MSR_IDT_MCR_CTRL, lo, hi); 403f7627e25SThomas Gleixner winchip2_protect_mcr(); 404f7627e25SThomas Gleixner #endif 405f7627e25SThomas Gleixner break; 406f7627e25SThomas Gleixner default: 407f7627e25SThomas Gleixner name = "??"; 408f7627e25SThomas Gleixner } 409f7627e25SThomas Gleixner 410f7627e25SThomas Gleixner rdmsr(MSR_IDT_FCR1, lo, hi); 411f7627e25SThomas Gleixner newlo = (lo|fcr_set) & (~fcr_clr); 412f7627e25SThomas Gleixner 413f7627e25SThomas Gleixner if (newlo != lo) { 414*edc05e6dSIngo Molnar printk(KERN_INFO "Centaur FCR was 0x%X now 0x%X\n", 415*edc05e6dSIngo Molnar lo, newlo); 416f7627e25SThomas Gleixner wrmsr(MSR_IDT_FCR1, newlo, hi); 417f7627e25SThomas Gleixner } else { 418f7627e25SThomas Gleixner printk(KERN_INFO "Centaur FCR is 0x%X\n", lo); 419f7627e25SThomas Gleixner } 420f7627e25SThomas Gleixner /* Emulate MTRRs using Centaur's MCR. */ 421f7627e25SThomas Gleixner set_bit(X86_FEATURE_CENTAUR_MCR, c->x86_capability); 422f7627e25SThomas Gleixner /* Report CX8 */ 423f7627e25SThomas Gleixner set_bit(X86_FEATURE_CX8, c->x86_capability); 424f7627e25SThomas Gleixner /* Set 3DNow! on Winchip 2 and above. */ 425f7627e25SThomas Gleixner if (c->x86_model >= 8) 426f7627e25SThomas Gleixner set_bit(X86_FEATURE_3DNOW, c->x86_capability); 427f7627e25SThomas Gleixner /* See if we can find out some more. */ 428f7627e25SThomas Gleixner if (cpuid_eax(0x80000000) >= 0x80000005) { 429f7627e25SThomas Gleixner /* Yes, we can. */ 430f7627e25SThomas Gleixner cpuid(0x80000005, &aa, &bb, &cc, &dd); 431f7627e25SThomas Gleixner /* Add L1 data and code cache sizes. */ 432f7627e25SThomas Gleixner c->x86_cache_size = (cc>>24)+(dd>>24); 433f7627e25SThomas Gleixner } 434f7627e25SThomas Gleixner sprintf(c->x86_model_id, "WinChip %s", name); 435f7627e25SThomas Gleixner break; 436f7627e25SThomas Gleixner 437f7627e25SThomas Gleixner case 6: 438f7627e25SThomas Gleixner init_c3(c); 439f7627e25SThomas Gleixner break; 440f7627e25SThomas Gleixner } 441f7627e25SThomas Gleixner } 442f7627e25SThomas Gleixner 443*edc05e6dSIngo Molnar static unsigned int __cpuinit 444*edc05e6dSIngo Molnar centaur_size_cache(struct cpuinfo_x86 *c, unsigned int size) 445f7627e25SThomas Gleixner { 446f7627e25SThomas Gleixner /* VIA C3 CPUs (670-68F) need further shifting. */ 447f7627e25SThomas Gleixner if ((c->x86 == 6) && ((c->x86_model == 7) || (c->x86_model == 8))) 448f7627e25SThomas Gleixner size >>= 8; 449f7627e25SThomas Gleixner 450*edc05e6dSIngo Molnar /* 451*edc05e6dSIngo Molnar * There's also an erratum in Nehemiah stepping 1, which 452*edc05e6dSIngo Molnar * returns '65KB' instead of '64KB' 453*edc05e6dSIngo Molnar * - Note, it seems this may only be in engineering samples. 454*edc05e6dSIngo Molnar */ 455*edc05e6dSIngo Molnar if ((c->x86 == 6) && (c->x86_model == 9) && 456*edc05e6dSIngo Molnar (c->x86_mask == 1) && (size == 65)) 457f7627e25SThomas Gleixner size -= 1; 458f7627e25SThomas Gleixner 459f7627e25SThomas Gleixner return size; 460f7627e25SThomas Gleixner } 461f7627e25SThomas Gleixner 462f7627e25SThomas Gleixner static struct cpu_dev centaur_cpu_dev __cpuinitdata = { 463f7627e25SThomas Gleixner .c_vendor = "Centaur", 464f7627e25SThomas Gleixner .c_ident = { "CentaurHauls" }, 465f7627e25SThomas Gleixner .c_init = init_centaur, 466f7627e25SThomas Gleixner .c_size_cache = centaur_size_cache, 467f7627e25SThomas Gleixner }; 468f7627e25SThomas Gleixner 46903ae5768SThomas Petazzoni cpu_vendor_dev_register(X86_VENDOR_CENTAUR, ¢aur_cpu_dev); 470