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