[BACK]Return to k6_mem.c CVS log [TXT][DIR] Up to [local] / sys / arch / i386 / i386

Annotation of sys/arch/i386/i386/k6_mem.c, Revision 1.1.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