• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
centaur_get_free_region(unsigned long base,unsigned long size,int replace_reg)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, &ltype);
38 		if (lsize == 0)
39 			return i;
40 	}
41 	return -ENOSPC;
42 }
43 
44 void
mtrr_centaur_report_mcr(int mcr,u32 lo,u32 hi)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
centaur_get_mcr(unsigned int reg,unsigned long * base,unsigned long * size,mtrr_type * type)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 
centaur_set_mcr(unsigned int reg,unsigned long base,unsigned long size,mtrr_type type)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 
centaur_validate_add_page(unsigned long base,unsigned long size,unsigned int type)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 
centaur_init_mtrr(void)218 int __init centaur_init_mtrr(void)
219 {
220 	set_mtrr_ops(&centaur_mtrr_ops);
221 	return 0;
222 }
223 
224 //arch_initcall(centaur_init_mtrr);
225