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