I suppose that this is nearly done. It works, it seems, but I have no idea what I can do to truly test it. I need to implement probing/matching so that it only works on the CPUs that support it, I suppose. I'd like people to check it out for now. I make no guarantees, but it seems to work here.
Brian Feldman _ __ ___ ____ ___ ___ ___ gr...@unixhelp.org _ __ ___ | _ ) __| \ FreeBSD: The Power to Serve! _ __ | _ \ _ \ |) | http://www.freebsd.org _ |___)___/___/ /*- * Copyright (c) 1999 Brian Fundakowski Feldman * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $Id$ * */ #include <sys/param.h> #include <sys/kernel.h> #include <sys/systm.h> #include <sys/ioccom.h> #include <sys/malloc.h> #include <sys/memrange.h> #include <machine/md_var.h> #include <machine/specialreg.h> /* * A K6 MTRR is defined as the highest 15 bits having the address, the next * 15 having the mask, the 1st bit being "write-combining" and the 0th bit * being "uncacheable". * * Address Mask WC UC * | XXXXXXXXXXXXXXX | XXXXXXXXXXXXXXX | X | X | * * There are two of these in the 64-bit UWCCR. */ #define UWCCR 0xc0000085 #define k6_reg_get(reg, addr, mask, wc, uc) \ addr = ((reg) & 0xfffe0000) >> 17; \ mask = ((reg) & 0x1fffc) >> 2; \ wc = ((reg) & 0x2) >> 1; \ uc = (reg) & 0x1; #define k6_reg_make(addr, mask, wc, uc) \ (((addr) << 17) | ((mask) << 2) | ((wc) << 1) | uc) static void k6_mrinit(struct mem_range_softc *sc); static int k6_mrset(struct mem_range_softc *, struct mem_range_desc *, int *); static __inline int k6_mrmake(struct mem_range_desc *, u_int32_t *); static void k6_mem_drvinit(void *); static struct mem_range_ops k6_mrops = { k6_mrinit, k6_mrset, NULL }; static __inline int k6_mrmake(struct mem_range_desc *desc, u_int32_t *mtrr) { u_int base, len = 0, wc, uc; register int bit; if (desc->mr_base &~ 0xfffe0000) return EINVAL; if (desc->mr_len < 131072 || !powerof2(desc->mr_len)) return EINVAL; if (desc->mr_flags &~ 0x3) return EOPNOTSUPP; base = desc->mr_base & 0xfffe0000; for (bit = ffs(desc->mr_len >> 17) - 1; bit < 15; bit++) len |= 1 << (14 - bit); wc = (desc->mr_flags & MDF_WRITECOMBINE) ? 1 : 0; uc = (desc->mr_flags & MDF_UNCACHEABLE) ? 1 : 0; *mtrr = k6_reg_make(base, len, wc, uc); return 0; } static void k6_mrinit(struct mem_range_softc *sc) { u_int64_t reg; u_int32_t addr, mask, wc, uc; int d; sc->mr_cap = 0; bzero(sc->mr_desc = malloc((sc->mr_ndesc = 2) * sizeof(struct mem_range_desc), M_MEMDESC, M_WAITOK), 2 * sizeof(struct mem_range_desc)); reg = rdmsr(UWCCR); for (d = 0; d < sc->mr_ndesc; d++) { u_int32_t one = (reg & (0xffffffff << (32 * d))) >> (32 * d); k6_reg_get(one, addr, mask, wc, uc); sc->mr_desc[d].mr_base = addr << 17; sc->mr_desc[d].mr_len = ffs(mask) << 17; if (wc) sc->mr_desc[d].mr_flags |= MDF_WRITECOMBINE; if (uc) sc->mr_desc[d].mr_flags |= MDF_UNCACHEABLE; } printf("K6 MTRR support enabled\n"); } static int k6_mrset(struct mem_range_softc *sc, struct mem_range_desc *desc, int *arg) { u_int64_t reg; u_int32_t mtrr; int error, d; switch (*arg) { case MEMRANGE_SET_UPDATE: error = k6_mrmake(desc, &mtrr); if (error) return error; for (d = 0; d < sc->mr_ndesc; d++) { if (!sc->mr_desc[d].mr_base) { sc->mr_desc[d] = *desc; goto out; } if (sc->mr_desc[d].mr_base == desc->mr_base && sc->mr_desc[d].mr_len == desc->mr_len) return EEXIST; } return ENOSPC; case MEMRANGE_SET_REMOVE: mtrr = 0; for (d = 0; d < sc->mr_ndesc; d++) if (sc->mr_desc[d].mr_base == desc->mr_base && sc->mr_desc[d].mr_len == desc->mr_len) { bzero(&sc->mr_desc[d], sizeof(sc->mr_desc[d])); goto out; } return ENOENT; default: return EOPNOTSUPP; } out: disable_intr(); wbinvd(); invltlb(); reg = rdmsr(UWCCR); reg &= 0xffffffff << (32 * d); reg |= mtrr << (32 * d); wrmsr(UWCCR, reg); wbinvd(); invltlb(); enable_intr(); return 0; } static void k6_mem_drvinit(void *unused) { mem_range_softc.mr_op = &k6_mrops; } SYSINIT(k6memdev, SI_SUB_DRIVERS, SI_ORDER_FIRST, k6_mem_drvinit, NULL) To Unsubscribe: send mail to majord...@freebsd.org with "unsubscribe freebsd-hackers" in the body of the message