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
This commit is contained in:
parent
2d5db3709b
commit
eecadc7023
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=213383
@ -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
|
||||
|
@ -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"
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user