xref: /openbmc/linux/arch/x86/kernel/cpu/centaur.c (revision 27b46d7661dc720224813eb4f452e424f1bf3a9a)
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] = &centaur_cpu_dev;
470f7627e25SThomas Gleixner 	return 0;
471f7627e25SThomas Gleixner }
472