summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sys/conf/files.powerpc1
-rw-r--r--sys/modules/mem/Makefile2
-rw-r--r--sys/powerpc/include/memdev.h2
-rw-r--r--sys/powerpc/powerpc/mem.c152
4 files changed, 154 insertions, 3 deletions
diff --git a/sys/conf/files.powerpc b/sys/conf/files.powerpc
index 1a4a8ff..e7d1d4d 100644
--- a/sys/conf/files.powerpc
+++ b/sys/conf/files.powerpc
@@ -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
diff --git a/sys/modules/mem/Makefile b/sys/modules/mem/Makefile
index b4fdb9c..c24e18f 100644
--- a/sys/modules/mem/Makefile
+++ b/sys/modules/mem/Makefile
@@ -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"
diff --git a/sys/powerpc/include/memdev.h b/sys/powerpc/include/memdev.h
index 584eb4c..97000c9 100644
--- a/sys/powerpc/include/memdev.h
+++ b/sys/powerpc/include/memdev.h
@@ -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);
diff --git a/sys/powerpc/powerpc/mem.c b/sys/powerpc/powerpc/mem.c
index e4b70c6..b4636ec 100644
--- a/sys/powerpc/powerpc/mem.c
+++ b/sys/powerpc/powerpc/mem.c
@@ -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 offset, vm_paddr_t *paddr,
*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);
}
+
OpenPOWER on IntegriCloud