Date: Sun, 3 Oct 2010 16:02:53 +0000 (UTC) From: Nathan Whitehorn <nwhitehorn@FreeBSD.org> To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r213383 - in head/sys: conf modules/mem powerpc/include powerpc/powerpc Message-ID: <201010031602.o93G2rqn080117@svn.freebsd.org>
next in thread | raw e-mail | index | archive | help
Author: nwhitehorn Date: Sun Oct 3 16:02:53 2010 New Revision: 213383 URL: http://svn.freebsd.org/changeset/base/213383 Log: Add a memory-range interface to /dev/mem on PowerPC using PAT attributes. Unlike actual MTRR, this only controls the mapping attributes for subsequent mmap() of /dev/mem. Nonetheless, the support is sufficiently MTRR-like that Xorg can use it, which translates into an enormous increase in graphics performance on PowerPC. MFC after: 2 weeks Modified: head/sys/conf/files.powerpc head/sys/modules/mem/Makefile head/sys/powerpc/include/memdev.h head/sys/powerpc/powerpc/mem.c Modified: head/sys/conf/files.powerpc ============================================================================== --- head/sys/conf/files.powerpc Sun Oct 3 13:52:17 2010 (r213382) +++ head/sys/conf/files.powerpc Sun Oct 3 16:02:53 2010 (r213383) @@ -27,6 +27,7 @@ dev/fb/fb.c optional sc dev/fdt/fdt_powerpc.c optional fdt dev/hwpmc/hwpmc_powerpc.c optional hwpmc dev/kbd/kbd.c optional sc +dev/mem/memutil.c optional mem dev/ofw/openfirm.c optional aim | fdt dev/ofw/openfirmio.c optional aim | fdt dev/ofw/ofw_bus_if.m optional aim | fdt Modified: head/sys/modules/mem/Makefile ============================================================================== --- head/sys/modules/mem/Makefile Sun Oct 3 13:52:17 2010 (r213382) +++ head/sys/modules/mem/Makefile Sun Oct 3 16:02:53 2010 (r213383) @@ -6,7 +6,7 @@ KMOD= mem SRCS= memdev.c mem.c -.if ${MACHINE_CPUARCH} == "amd64" || ${MACHINE_CPUARCH} == "i386" +.if ${MACHINE_CPUARCH} == "amd64" || ${MACHINE_CPUARCH} == "i386" || ${MACHINE_CPUARCH} = "powerpc" SRCS+= memutil.c .endif .if ${MACHINE_CPUARCH} == "i386" Modified: head/sys/powerpc/include/memdev.h ============================================================================== --- head/sys/powerpc/include/memdev.h Sun Oct 3 13:52:17 2010 (r213382) +++ head/sys/powerpc/include/memdev.h Sun Oct 3 16:02:53 2010 (r213383) @@ -31,7 +31,7 @@ d_open_t memopen; d_read_t memrw; -#define memioctl (d_ioctl_t *)NULL +d_ioctl_t memioctl; d_mmap_t memmmap; void dev_mem_md_init(void); Modified: head/sys/powerpc/powerpc/mem.c ============================================================================== --- head/sys/powerpc/powerpc/mem.c Sun Oct 3 13:52:17 2010 (r213382) +++ head/sys/powerpc/powerpc/mem.c Sun Oct 3 16:02:53 2010 (r213383) @@ -48,6 +48,7 @@ __FBSDID("$FreeBSD$"); #include <sys/fcntl.h> #include <sys/kernel.h> #include <sys/lock.h> +#include <sys/ioccom.h> #include <sys/malloc.h> #include <sys/memrange.h> #include <sys/module.h> @@ -68,7 +69,21 @@ __FBSDID("$FreeBSD$"); #include <machine/memdev.h> -struct mem_range_softc mem_range_softc; +static void ppc_mrinit(struct mem_range_softc *); +static int ppc_mrset(struct mem_range_softc *, struct mem_range_desc *, int *); + +MALLOC_DEFINE(M_MEMDESC, "memdesc", "memory range descriptors"); + +static struct mem_range_ops ppc_mem_range_ops = { + ppc_mrinit, + ppc_mrset, + NULL, + NULL +}; +struct mem_range_softc mem_range_softc = { + &ppc_mem_range_ops, + 0, 0, 0 +}; /* ARGSUSED */ int @@ -162,6 +177,8 @@ int memmmap(struct cdev *dev, vm_ooffset_t offset, vm_paddr_t *paddr, int prot, vm_memattr_t *memattr) { + int i; + /* * /dev/mem is the only one that makes sense through this * interface. For /dev/kmem any physaddr we return here @@ -178,10 +195,143 @@ memmmap(struct cdev *dev, vm_ooffset_t o *paddr = offset; + for (i = 0; i < mem_range_softc.mr_ndesc; i++) { + if (!(mem_range_softc.mr_desc[i].mr_flags & MDF_ACTIVE)) + continue; + + if (offset >= mem_range_softc.mr_desc[i].mr_base && + offset < mem_range_softc.mr_desc[i].mr_base + + mem_range_softc.mr_desc[i].mr_len) { + switch (mem_range_softc.mr_desc[i].mr_flags & + MDF_ATTRMASK) { + case MDF_WRITEBACK: + *memattr = VM_MEMATTR_WRITE_BACK; + break; + case MDF_WRITECOMBINE: + *memattr = VM_MEMATTR_WRITE_COMBINING; + break; + case MDF_UNCACHEABLE: + *memattr = VM_MEMATTR_UNCACHEABLE; + break; + case MDF_WRITETHROUGH: + *memattr = VM_MEMATTR_WRITE_THROUGH; + break; + } + + break; + } + } + return (0); } void dev_mem_md_init(void) { + mem_range_softc.mr_op->init(&mem_range_softc); +} + +static void +ppc_mrinit(struct mem_range_softc *sc) +{ + sc->mr_cap = 0; + sc->mr_ndesc = 8; /* XXX: Should be dynamically expandable */ + sc->mr_desc = malloc(sc->mr_ndesc * sizeof(struct mem_range_desc), + M_MEMDESC, M_NOWAIT | M_ZERO); + if (sc->mr_desc == NULL) + panic("%s: malloc returns NULL", __func__); +} + +static int +ppc_mrset(struct mem_range_softc *sc, struct mem_range_desc *desc, int *arg) +{ + int i; + + switch(*arg) { + case MEMRANGE_SET_UPDATE: + for (i = 0; i < sc->mr_ndesc; i++) { + if (!sc->mr_desc[i].mr_len) { + sc->mr_desc[i] = *desc; + sc->mr_desc[i].mr_flags |= MDF_ACTIVE; + return (0); + } + if (sc->mr_desc[i].mr_base == desc->mr_base && + sc->mr_desc[i].mr_len == desc->mr_len) + return (EEXIST); + } + return (ENOSPC); + case MEMRANGE_SET_REMOVE: + for (i = 0; i < sc->mr_ndesc; i++) + if (sc->mr_desc[i].mr_base == desc->mr_base && + sc->mr_desc[i].mr_len == desc->mr_len) { + bzero(&sc->mr_desc[i], sizeof(sc->mr_desc[i])); + return (0); + } + return (ENOENT); + default: + return (EOPNOTSUPP); + } + + return (0); } + +/* + * Operations for changing memory attributes. + * + * This is basically just an ioctl shim for mem_range_attr_get + * and mem_range_attr_set. + */ +/* ARGSUSED */ +int +memioctl(struct cdev *dev __unused, u_long cmd, caddr_t data, int flags, + struct thread *td) +{ + int nd, error = 0; + struct mem_range_op *mo = (struct mem_range_op *)data; + struct mem_range_desc *md; + + /* is this for us? */ + if ((cmd != MEMRANGE_GET) && + (cmd != MEMRANGE_SET)) + return (ENOTTY); + + /* any chance we can handle this? */ + if (mem_range_softc.mr_op == NULL) + return (EOPNOTSUPP); + + /* do we have any descriptors? */ + if (mem_range_softc.mr_ndesc == 0) + return (ENXIO); + + switch (cmd) { + case MEMRANGE_GET: + nd = imin(mo->mo_arg[0], mem_range_softc.mr_ndesc); + if (nd > 0) { + md = (struct mem_range_desc *) + malloc(nd * sizeof(struct mem_range_desc), + M_MEMDESC, M_WAITOK); + error = mem_range_attr_get(md, &nd); + if (!error) + error = copyout(md, mo->mo_desc, + nd * sizeof(struct mem_range_desc)); + free(md, M_MEMDESC); + } + else + nd = mem_range_softc.mr_ndesc; + mo->mo_arg[0] = nd; + break; + + case MEMRANGE_SET: + md = (struct mem_range_desc *)malloc(sizeof(struct mem_range_desc), + M_MEMDESC, M_WAITOK); + error = copyin(mo->mo_desc, md, sizeof(struct mem_range_desc)); + /* clamp description string */ + md->mr_owner[sizeof(md->mr_owner) - 1] = 0; + if (error == 0) + error = mem_range_attr_set(md, &mo->mo_arg[0]); + free(md, M_MEMDESC); + break; + } + return (error); +} +
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201010031602.o93G2rqn080117>