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);
+}
+
_______________________________________________
svn-src-head@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"

Reply via email to