Annotation of sys/arch/i386/i386/k6_mem.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: k6_mem.c,v 1.7 2006/06/10 18:00:48 gwk Exp $ */
! 2: /*-
! 3: * Copyright (c) 1999 Brian Fundakowski Feldman
! 4: * All rights reserved.
! 5: *
! 6: * Redistribution and use in source and binary forms, with or without
! 7: * modification, are permitted provided that the following conditions
! 8: * are met:
! 9: * 1. Redistributions of source code must retain the above copyright
! 10: * notice, this list of conditions and the following disclaimer.
! 11: * 2. Redistributions in binary form must reproduce the above copyright
! 12: * notice, this list of conditions and the following disclaimer in the
! 13: * documentation and/or other materials provided with the distribution.
! 14: *
! 15: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
! 16: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
! 17: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
! 18: * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
! 19: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
! 20: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
! 21: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
! 22: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
! 23: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
! 24: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
! 25: * SUCH DAMAGE.
! 26: *
! 27: * $FreeBSD: src/sys/i386/i386/k6_mem.c,v 1.4 1999/09/05 15:45:57 green Exp $
! 28: *
! 29: */
! 30:
! 31: #include <sys/param.h>
! 32: #include <sys/kernel.h>
! 33: #include <sys/systm.h>
! 34: #include <sys/ioccom.h>
! 35: #include <sys/malloc.h>
! 36: #include <sys/memrange.h>
! 37:
! 38: #include <machine/cpufunc.h>
! 39: #include <machine/specialreg.h>
! 40:
! 41: /*
! 42: * A K6-2 MTRR is defined as the highest 15 bits having the address, the next
! 43: * 15 having the mask, the 1st bit being "write-combining" and the 0th bit
! 44: * being "uncacheable".
! 45: *
! 46: * Address Mask WC UC
! 47: * | XXXXXXXXXXXXXXX | XXXXXXXXXXXXXXX | X | X |
! 48: *
! 49: * There are two of these in the 64-bit UWCCR.
! 50: */
! 51: #define UWCCR 0xc0000085
! 52:
! 53: #define k6_reg_get(reg, addr, mask, wc, uc) do { \
! 54: addr = (reg) & 0xfffe0000; \
! 55: mask = ((reg) & 0x1fffc) >> 2; \
! 56: wc = ((reg) & 0x2) >> 1; \
! 57: uc = (reg) & 0x1; \
! 58: } while (0)
! 59:
! 60: #define k6_reg_make(addr, mask, wc, uc) \
! 61: ((addr) | ((mask) << 2) | ((wc) << 1) | uc)
! 62:
! 63: void k6_mrinit(struct mem_range_softc *sc);
! 64: int k6_mrset(struct mem_range_softc *, struct mem_range_desc *, int *);
! 65: __inline int k6_mrmake(struct mem_range_desc *, u_int32_t *);
! 66:
! 67: struct mem_range_ops k6_mrops = {
! 68: k6_mrinit,
! 69: k6_mrset,
! 70: NULL
! 71: };
! 72:
! 73: __inline int
! 74: k6_mrmake(struct mem_range_desc *desc, u_int32_t *mtrr)
! 75: {
! 76: u_int32_t len = 0, wc, uc;
! 77: int bit;
! 78:
! 79: if (desc->mr_base &~ 0xfffe0000)
! 80: return EINVAL;
! 81: if (desc->mr_len < 131072 || !powerof2(desc->mr_len))
! 82: return EINVAL;
! 83: if (desc->mr_flags &~ (MDF_WRITECOMBINE|MDF_UNCACHEABLE))
! 84: return EOPNOTSUPP;
! 85:
! 86: for (bit = ffs(desc->mr_len >> 17) - 1; bit < 15; bit++)
! 87: len |= 1 << bit;
! 88: wc = (desc->mr_flags & MDF_WRITECOMBINE) ? 1 : 0;
! 89: uc = (desc->mr_flags & MDF_UNCACHEABLE) ? 1 : 0;
! 90:
! 91: *mtrr = k6_reg_make(desc->mr_base, len, wc, uc);
! 92: return 0;
! 93: }
! 94:
! 95: void
! 96: k6_mrinit(struct mem_range_softc *sc)
! 97: {
! 98: u_int64_t reg;
! 99: u_int32_t addr, mask, wc, uc;
! 100: int d;
! 101:
! 102: sc->mr_cap = 0;
! 103: sc->mr_ndesc = 2; /* XXX (BFF) For now, we only have one msr for this */
! 104: sc->mr_desc = malloc(sc->mr_ndesc * sizeof(struct mem_range_desc),
! 105: M_MEMDESC, M_NOWAIT);
! 106: if (sc->mr_desc == NULL)
! 107: panic("k6_mrinit: malloc returns NULL");
! 108:
! 109: bzero(sc->mr_desc, sc->mr_ndesc * sizeof(struct mem_range_desc));
! 110:
! 111: reg = rdmsr(UWCCR);
! 112: for (d = 0; d < sc->mr_ndesc; d++) {
! 113: u_int32_t one = (reg & (0xffffffff << (32 * d))) >> (32 * d);
! 114:
! 115: k6_reg_get(one, addr, mask, wc, uc);
! 116: sc->mr_desc[d].mr_base = addr;
! 117: sc->mr_desc[d].mr_len = ffs(mask) << 17;
! 118: if (wc)
! 119: sc->mr_desc[d].mr_flags |= MDF_WRITECOMBINE;
! 120: if (uc)
! 121: sc->mr_desc[d].mr_flags |= MDF_UNCACHEABLE;
! 122: }
! 123:
! 124: printf("mtrr: K6-family MTRR support (%d registers)\n", sc->mr_ndesc);
! 125: }
! 126:
! 127: int
! 128: k6_mrset(struct mem_range_softc *sc, struct mem_range_desc *desc, int *arg)
! 129: {
! 130: u_int64_t reg;
! 131: u_int32_t mtrr;
! 132: int error, d;
! 133:
! 134: switch (*arg) {
! 135: case MEMRANGE_SET_UPDATE:
! 136: error = k6_mrmake(desc, &mtrr);
! 137: if (error)
! 138: return error;
! 139: for (d = 0; d < sc->mr_ndesc; d++) {
! 140: if (!sc->mr_desc[d].mr_len) {
! 141: sc->mr_desc[d] = *desc;
! 142: goto out;
! 143: }
! 144: if (sc->mr_desc[d].mr_base == desc->mr_base &&
! 145: sc->mr_desc[d].mr_len == desc->mr_len)
! 146: return EEXIST;
! 147: }
! 148:
! 149: return ENOSPC;
! 150: case MEMRANGE_SET_REMOVE:
! 151: mtrr = 0;
! 152: for (d = 0; d < sc->mr_ndesc; d++)
! 153: if (sc->mr_desc[d].mr_base == desc->mr_base &&
! 154: sc->mr_desc[d].mr_len == desc->mr_len) {
! 155: bzero(&sc->mr_desc[d], sizeof(sc->mr_desc[d]));
! 156: goto out;
! 157: }
! 158:
! 159: return ENOENT;
! 160: default:
! 161: return EOPNOTSUPP;
! 162: }
! 163:
! 164: out:
! 165:
! 166: disable_intr();
! 167: wbinvd();
! 168: reg = rdmsr(UWCCR);
! 169: reg &= ~(0xffffffff << (32 * d));
! 170: reg |= mtrr << (32 * d);
! 171: wrmsr(UWCCR, reg);
! 172: wbinvd();
! 173: enable_intr();
! 174:
! 175: return 0;
! 176: }
CVSweb