xref: /netbsd/sys/arch/i386/i386/mtrr_k6.c (revision bf9ec67e)
1 /*	$NetBSD: mtrr_k6.c,v 1.2 2001/11/15 07:03:30 lukem Exp $	*/
2 
3 /*
4  * Copyright 2001 Wasabi Systems, Inc.
5  * All rights reserved.
6  *
7  * Written by Jason R. Thorpe for Wasabi Systems, Inc.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer.
14  * 2. Redistributions in binary form must reproduce the above copyright
15  *    notice, this list of conditions and the following disclaimer in the
16  *    documentation and/or other materials provided with the distribution.
17  * 3. All advertising materials mentioning features or use of this software
18  *    must display the following acknowledgement:
19  *	This product includes software developed for the NetBSD Project by
20  *	Wasabi Systems, Inc.
21  * 4. The name of Wasabi Systems, Inc. may not be used to endorse
22  *    or promote products derived from this software without specific prior
23  *    written permission.
24  *
25  * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND
26  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
27  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
28  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL WASABI SYSTEMS, INC
29  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
30  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
31  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
32  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
33  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
34  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
35  * POSSIBILITY OF SUCH DAMAGE.
36  */
37 
38 /*
39  * AMD K6 MTRR support.
40  */
41 
42 #include <sys/cdefs.h>
43 __KERNEL_RCSID(0, "$NetBSD: mtrr_k6.c,v 1.2 2001/11/15 07:03:30 lukem Exp $");
44 
45 #include <sys/param.h>
46 #include <sys/systm.h>
47 #include <sys/proc.h>
48 #include <sys/malloc.h>
49 
50 #include <machine/specialreg.h>
51 #include <machine/cpufunc.h>
52 #include <machine/mtrr.h>
53 
54 static void	k6_mtrr_init_cpu(struct cpu_info *);
55 static void	k6_mtrr_reload_cpu(struct cpu_info *);
56 static void	k6_mtrr_clean(struct proc *);
57 static int	k6_mtrr_set(struct mtrr *, int *, struct proc *, int);
58 static int	k6_mtrr_get(struct mtrr *, int *, struct proc *, int);
59 static void	k6_mtrr_commit(void);
60 static void	k6_mtrr_dump(const char *);
61 
62 static int	k6_mtrr_validate(struct mtrr *, struct proc *);
63 static void	k6_raw2soft(void);
64 static void	k6_soft2raw(void);
65 
66 static struct mtrr_state
67 mtrr_var_raw[] = {
68 	{ 0 },
69 	{ 1 },
70 };
71 
72 static struct mtrr *mtrr_var;
73 
74 struct mtrr_funcs k6_mtrr_funcs = {
75 	k6_mtrr_init_cpu,
76 	k6_mtrr_reload_cpu,
77 	k6_mtrr_clean,
78 	k6_mtrr_set,
79 	k6_mtrr_get,
80 	k6_mtrr_commit,
81 	k6_mtrr_dump
82 };
83 
84 static void
85 k6_mtrr_dump(const char *tag)
86 {
87 	uint64_t uwccr;
88 	int i;
89 
90 	uwccr = rdmsr(MSR_K6_UWCCR);
91 
92 	for (i = 0; i < MTRR_K6_NVAR; i++)
93 		printf("%s: %x: 0x%08llx\n", tag, mtrr_var_raw[i].msraddr,
94 		    (uwccr >> (32 * mtrr_var_raw[i].msraddr)) & 0xffffffff);
95 }
96 
97 /*
98  * There are no multiprocessor K6 systems, so we don't have to deal with
99  * any multiprocessor stuff here.
100  */
101 static void
102 k6_mtrr_reload(void)
103 {
104 	uint64_t uwccr;
105 	int i;
106 
107 	disable_intr();
108 
109 	wbinvd();
110 
111 	for (i = 0, uwccr = 0; i < MTRR_K6_NVAR; i++) {
112 		uwccr |= mtrr_var_raw[i].msrval <<
113 		    (32 * mtrr_var_raw[i].msraddr);
114 	}
115 
116 	wrmsr(MSR_K6_UWCCR, uwccr);
117 
118 	wbinvd();
119 
120 	enable_intr();
121 }
122 
123 static void
124 k6_mtrr_reload_cpu(struct cpu_info *ci)
125 {
126 
127 	k6_mtrr_reload();
128 }
129 
130 void
131 k6_mtrr_init_first(void)
132 {
133 	uint64_t uwccr;
134 	int i;
135 
136 	uwccr = rdmsr(MSR_K6_UWCCR);
137 
138 	for (i = 0; i < MTRR_K6_NVAR; i++) {
139 		mtrr_var_raw[i].msrval =
140 		    (uwccr >> (32 * mtrr_var_raw[i].msraddr)) & 0xffffffff;
141 	}
142 #if 0
143 	mtrr_dump("init mtrr");
144 #endif
145 
146 	mtrr_var = (struct mtrr *)
147 	    malloc(MTRR_K6_NVAR * sizeof(struct mtrr), M_TEMP, M_NOWAIT);
148 	if (mtrr_var == NULL)
149 		panic("can't allocate variable MTRR array");
150 
151 	k6_raw2soft();
152 }
153 
154 static void
155 k6_raw2soft(void)
156 {
157 	struct mtrr *mtrrp;
158 	uint32_t base, mask;
159 	int i;
160 
161 	for (i = 0; i < MTRR_K6_NVAR; i++) {
162 		mtrrp = &mtrr_var[i];
163 		memset(mtrrp, 0, sizeof(*mtrrp));
164 		base = mtrr_var_raw[i].msrval & MTRR_K6_ADDR;
165 		mask = (mtrr_var_raw[i].msrval & MTRR_K6_MASK) >>
166 		    MTRR_K6_MASK_SHIFT;
167 		if (mask == 0)
168 			continue;
169 		mtrrp->base = base;
170 		mtrrp->len = ffs(mask) << MTRR_K6_ADDR_SHIFT;
171 		/* XXXJRT can both UC and WC be set? */
172 		if (mtrr_var_raw[i].msrval & MTRR_K6_UC)
173 			mtrrp->type = MTRR_TYPE_UC;
174 		else if (mtrr_var_raw[i].msrval & MTRR_K6_WC)
175 			mtrrp->type = MTRR_TYPE_WC;
176 		else	/* XXXJRT Correct default? */
177 			mtrrp->type = MTRR_TYPE_WT;
178 		mtrrp->flags |= MTRR_VALID;
179 	}
180 }
181 
182 static void
183 k6_soft2raw(void)
184 {
185 	struct mtrr *mtrrp;
186 	uint32_t mask;
187 	int i, bit;
188 
189 	for (i = 0; i < MTRR_K6_NVAR; i++) {
190 		mtrrp = &mtrr_var[i];
191 		if ((mtrrp->flags & MTRR_VALID) == 0) {
192 			mtrr_var_raw[i].msrval = 0;
193 			continue;
194 		}
195 		mtrr_var_raw[i].msrval = mtrrp->base;
196 		for (bit = ffs(mtrrp->len >> MTRR_K6_ADDR_SHIFT) - 1, mask = 0;
197 		     bit < 15; bit++)
198 			mask |= 1U << bit;
199 		mtrr_var_raw[i].msrval |= mask << MTRR_K6_MASK_SHIFT;
200 		if (mtrrp->type == MTRR_TYPE_UC)
201 			mtrr_var_raw[i].msrval |= MTRR_K6_UC;
202 		else if (mtrrp->type == MTRR_TYPE_WC)
203 			mtrr_var_raw[i].msrval |= MTRR_K6_WC;
204 	}
205 }
206 
207 static void
208 k6_mtrr_init_cpu(struct cpu_info *ci)
209 {
210 
211 	k6_mtrr_reload();
212 #if 0
213 	mtrr_dump(ci->ci_dev->dv_xname);
214 #endif
215 }
216 
217 static int
218 k6_mtrr_validate(struct mtrr *mtrrp, struct proc *p)
219 {
220 
221 	/*
222 	 * Must be at least 128K aligned.
223 	 */
224 	if (mtrrp->base & ~MTRR_K6_ADDR)
225 		return (EINVAL);
226 
227 	/*
228 	 * Must be at least 128K long, and must be a power of 2.
229 	 */
230 	if (mtrrp->len < (128 * 1024) || powerof2(mtrrp->len) == 0)
231 		return (EINVAL);
232 
233 	/*
234 	 * Filter out bad types.
235 	 */
236 	switch (mtrrp->type) {
237 	case MTRR_TYPE_UC:
238 	case MTRR_TYPE_WC:
239 	case MTRR_TYPE_WT:
240 		/* These are fine. */
241 		break;
242 
243 	default:
244 		return (EINVAL);
245 	}
246 
247 	return (0);
248 }
249 
250 /*
251  * Try to find a non-conflicting match on physical MTRRs for the
252  * requested range.
253  */
254 static int
255 k6_mtrr_setone(struct mtrr *mtrrp, struct proc *p)
256 {
257 	struct mtrr *freep;
258 	uint32_t low, high, curlow, curhigh;
259 	int i;
260 
261 	/*
262 	 * Try one of the variable range registers.
263 	 * XXX could be more sophisticated here by merging ranges.
264 	 */
265 	low = mtrrp->base;
266 	high = low + mtrrp->len;
267 	freep = NULL;
268 	for (i = 0; i < MTRR_K6_NVAR; i++) {
269 		if ((mtrr_var[i].flags & MTRR_VALID) == 0) {
270 			freep = &mtrr_var[i];
271 			continue;
272 		}
273 		curlow = mtrr_var[i].base;
274 		curhigh = curlow + mtrr_var[i].len;
275 		if (low == curlow && high == curhigh &&
276 		    (!(mtrr_var[i].flags & MTRR_PRIVATE) ||
277 		     mtrr_var[i].owner == p->p_pid)) {
278 			freep = &mtrr_var[i];
279 			break;
280 		}
281 		if (((high >= curlow && high < curhigh) ||
282 		    (low >= curlow && low < curhigh)) &&
283 		    ((mtrr_var[i].type != mtrrp->type) ||
284 		     ((mtrr_var[i].flags & MTRR_PRIVATE) &&
285 		      mtrr_var[i].owner != p->p_pid))) {
286 			return (EBUSY);
287 		}
288 	}
289 	if (freep == NULL)
290 		return (EBUSY);
291 	mtrrp->flags &= ~MTRR_CANTSET;
292 	*freep = *mtrrp;
293 	freep->owner = mtrrp->flags & MTRR_PRIVATE ? p->p_pid : 0;
294 
295 	return (0);
296 }
297 
298 static void
299 k6_mtrr_clean(struct proc *p)
300 {
301 	int i;
302 
303 	for (i = 0; i < MTRR_K6_NVAR; i++) {
304 		if ((mtrr_var[i].flags & MTRR_PRIVATE) &&
305 		    (mtrr_var[i].owner == p->p_pid))
306 			mtrr_var[i].flags &= ~(MTRR_PRIVATE | MTRR_VALID);
307 	}
308 
309 	k6_mtrr_commit();
310 }
311 
312 static int
313 k6_mtrr_set(struct mtrr *mtrrp, int *n, struct proc *p, int flags)
314 {
315 	struct mtrr mtrr;
316 	int i, error;
317 
318 	error = 0;
319 	for (i = 0; i < *n; i++) {
320 		if (flags & MTRR_GETSET_USER) {
321 			error = copyin(&mtrrp[i], &mtrr, sizeof(mtrr));
322 			if (error != 0)
323 				break;
324 		} else
325 			mtrr = mtrrp[i];
326 		error = k6_mtrr_validate(&mtrr, p);
327 		if (error != 0)
328 			break;
329 		error = k6_mtrr_setone(&mtrr, p);
330 		if (error != 0)
331 			break;
332 		if (mtrr.flags & MTRR_PRIVATE)
333 			p->p_md.md_flags |= MDP_USEDMTRR;
334 	}
335 	*n = i;
336 	return (error);
337 }
338 
339 static int
340 k6_mtrr_get(struct mtrr *mtrrp, int *n, struct proc *p, int flags)
341 {
342 	int i, error;
343 
344 	if (mtrrp == NULL) {
345 		*n = MTRR_K6_NVAR;
346 		return (0);
347 	}
348 
349 	for (i = 0; i < MTRR_K6_NVAR && i < *n; i++) {
350 		if (flags & MTRR_GETSET_USER) {
351 			error = copyout(&mtrr_var[i], &mtrrp[i],
352 			    sizeof(*mtrrp));
353 			if (error != 0)
354 				break;
355 		} else
356 			memcpy(&mtrrp[i], &mtrr_var[i], sizeof(*mtrrp));
357 	}
358 	*n = i;
359 	return (error);
360 }
361 
362 static void
363 k6_mtrr_commit(void)
364 {
365 
366 	k6_soft2raw();
367 	k6_mtrr_reload();
368 }
369