summaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
authorMartin Pieuchot <mpi@cvs.openbsd.org>2012-12-06 15:05:22 +0000
committerMartin Pieuchot <mpi@cvs.openbsd.org>2012-12-06 15:05:22 +0000
commit223be7445c07a06689f50f0a5ef3aac469322bd4 (patch)
treecd1424232a30329c570265466cfc95f72befc643 /sys
parent640919dd496ff4311222ad1c5ccad0ee54e5cb1a (diff)
Rework how AGP memory regions are mapped and add support for AGP bridges
that do not support remapping for processor accesses. Add new functions to map/unmap/mmap agp memory and let the agp layer decides how these memory regions should be accessed. It's assumed here that the bridge does not support remapping if its aperture address is 0. This is the last diff required for having drm(4) on macppc using agp(4). Joint work with and ok kettenis@
Diffstat (limited to 'sys')
-rw-r--r--sys/dev/pci/agp.c145
-rw-r--r--sys/dev/pci/agpvar.h12
-rw-r--r--sys/dev/pci/drm/drmP.h6
-rw-r--r--sys/dev/pci/drm/drm_agpsupport.c4
-rw-r--r--sys/dev/pci/drm/drm_drv.c6
-rw-r--r--sys/dev/pci/drm/drm_memory.c44
-rw-r--r--sys/dev/pci/drm/radeon_cp.c8
7 files changed, 185 insertions, 40 deletions
diff --git a/sys/dev/pci/agp.c b/sys/dev/pci/agp.c
index bd2a20f664d..64b7b3dd794 100644
--- a/sys/dev/pci/agp.c
+++ b/sys/dev/pci/agp.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: agp.c,v 1.35 2012/11/13 13:37:24 mpi Exp $ */
+/* $OpenBSD: agp.c,v 1.36 2012/12/06 15:05:21 mpi Exp $ */
/*-
* Copyright (c) 2000 Doug Rabson
* All rights reserved.
@@ -65,7 +65,9 @@ int agpioctl(dev_t, u_long, caddr_t, int, struct proc *);
int agpopen(dev_t, int, int, struct proc *);
int agpclose(dev_t, int, int , struct proc *);
-struct agp_memory *agp_find_memory(struct agp_softc *sc, int id);
+struct agp_memory *agp_find_memory(struct agp_softc *, int);
+struct agp_memory *agp_lookup_memory(struct agp_softc *, off_t);
+
/* userland ioctl functions */
int agpvga_match(struct pci_attach_args *);
int agp_info_user(void *, agp_info *);
@@ -188,6 +190,7 @@ agp_attach(struct device *parent, struct device *self, void *aux)
sc->sc_pc = pa->pa_pc;
sc->sc_id = pa->pa_id;
sc->sc_dmat = pa->pa_dmat;
+ sc->sc_memt = pa->pa_memt;
pci_get_capability(sc->sc_pc, sc->sc_pcitag, PCI_CAP_AGP,
&sc->sc_capoff, NULL);
@@ -210,23 +213,11 @@ agpmmap(dev_t dev, off_t off, int prot)
{
struct agp_softc *sc = agp_find_device(AGPUNIT(dev));
- if (sc == NULL || sc->sc_chipc == NULL)
+ if (sc == NULL)
return (-1);
- if (sc->sc_apaddr) {
-
- if (off > sc->sc_apsize)
- return (-1);
-
- /*
- * XXX this should use bus_space_mmap() but it's not
- * availiable on all archs.
- */
- return (sc->sc_apaddr + off);
- }
- return (-1);
+ return agp_mmap(sc, off, prot);
}
-
int
agpopen(dev_t dev, int oflags, int devtype, struct proc *p)
{
@@ -323,7 +314,24 @@ agp_find_memory(struct agp_softc *sc, int id)
if (mem->am_id == id)
return (mem);
}
- return (0);
+ return (NULL);
+}
+
+
+struct agp_memory *
+agp_lookup_memory(struct agp_softc *sc, off_t off)
+{
+ struct agp_memory* mem;
+
+ AGP_DPF("searching for memory offset 0x%lx\n", (unsigned long)off);
+ TAILQ_FOREACH(mem, &sc->sc_memory, am_link) {
+ if (mem->am_is_bound == 0)
+ continue;
+ if (off >= mem->am_offset &&
+ off < (mem->am_offset + mem->am_size))
+ return (mem);
+ }
+ return (NULL);
}
struct agp_gatt *
@@ -566,6 +574,11 @@ agp_generic_unbind_memory(struct agp_softc *sc, struct agp_memory *mem)
return (EINVAL);
}
+ if (mem->am_mapref > 0) {
+ printf("AGP: memory is mapped\n");
+ rw_exit_write(&sc->sc_lock);
+ return (EINVAL);
+ }
/*
* Unbind the individual pages and flush the chipset's
@@ -904,3 +917,101 @@ agp_memory_info(void *dev, void *handle, struct agp_memory_info *mi)
mi->ami_offset = mem->am_offset;
mi->ami_is_bound = mem->am_is_bound;
}
+
+void *
+agp_map(struct agp_softc *sc, bus_size_t address, bus_size_t size,
+ bus_space_handle_t *memh)
+{
+ struct agp_memory* mem;
+
+ if (sc->sc_chipc == NULL)
+ return (NULL);
+
+ if (address >= sc->sc_apsize)
+ return (NULL);
+
+ if (sc->sc_apaddr) {
+ if (bus_space_map(sc->sc_memt, sc->sc_apaddr + address, size,
+ BUS_SPACE_MAP_LINEAR | BUS_SPACE_MAP_PREFETCHABLE, memh))
+ return (NULL);
+ } else {
+ /*
+ * If the aperture base address is 0 assume that the AGP
+ * bridge does not support remapping for processor accesses.
+ */
+ mem = agp_lookup_memory(sc, address);
+ if (mem == NULL)
+ return (NULL);
+
+ /*
+ * Map the whole memory region because it is easier to
+ * do so and it is improbable that only a part of it
+ * will be used.
+ */
+ if (mem->am_mapref == 0)
+ if (bus_dmamem_map(sc->sc_dmat, mem->am_dmaseg,
+ mem->am_nseg, mem->am_size, &mem->am_kva,
+ BUS_DMA_NOWAIT | BUS_DMA_NOCACHE))
+ return (NULL);
+
+ mem->am_mapref++;
+
+ /*
+ * XXX Fake a bus handle even if it is managed memory,
+ * this is needed at least by radeondrm(4).
+ */
+ *memh = (bus_space_handle_t)(mem->am_kva + address);
+ }
+
+ return bus_space_vaddr(sc->sc_memt, *memh);
+}
+
+void
+agp_unmap(struct agp_softc *sc, void *address, size_t size,
+ bus_space_handle_t memh)
+{
+ struct agp_memory* mem;
+ caddr_t kva;
+
+ if (sc->sc_apaddr)
+ return bus_space_unmap(sc->sc_memt, memh, size);
+
+ kva = (caddr_t)address;
+ TAILQ_FOREACH(mem, &sc->sc_memory, am_link) {
+ if (mem->am_is_bound == 0)
+ continue;
+
+ if (kva >= mem->am_kva && kva < (mem->am_kva + mem->am_size)) {
+ mem->am_mapref--;
+
+ if (mem->am_mapref == 0) {
+ bus_dmamem_unmap(sc->sc_dmat, mem->am_kva,
+ mem->am_size);
+ mem->am_kva = 0;
+ }
+ break;
+ }
+ }
+}
+
+paddr_t
+agp_mmap(struct agp_softc *sc, off_t off, int prot)
+{
+ struct agp_memory* mem;
+
+ if (sc->sc_chipc == NULL)
+ return (-1);
+
+ if (off >= sc->sc_apsize)
+ return (-1);
+
+ if (sc->sc_apaddr)
+ return bus_space_mmap(sc->sc_memt, sc->sc_apaddr, off, prot, 0);
+
+ mem = agp_lookup_memory(sc, off);
+ if (mem == NULL)
+ return (-1);
+
+ return bus_dmamem_mmap(sc->sc_dmat, mem->am_dmaseg, mem->am_nseg, off,
+ prot, BUS_DMA_NOCACHE);
+}
diff --git a/sys/dev/pci/agpvar.h b/sys/dev/pci/agpvar.h
index 2a9f6be4694..d394060f7c4 100644
--- a/sys/dev/pci/agpvar.h
+++ b/sys/dev/pci/agpvar.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: agpvar.h,v 1.22 2010/05/10 22:06:04 oga Exp $ */
+/* $OpenBSD: agpvar.h,v 1.23 2012/12/06 15:05:21 mpi Exp $ */
/* $NetBSD: agpvar.h,v 1.4 2001/10/01 21:54:48 fvdl Exp $ */
/*-
@@ -73,6 +73,8 @@ struct agp_memory {
bus_size_t am_size; /* number of bytes allocated */
bus_size_t am_offset; /* page offset if bound */
paddr_t am_physical;
+ caddr_t am_kva; /* kva if mapped */
+ u_int32_t am_mapref; /* mapping reference count */
int am_id; /* unique id for block */
int am_is_bound; /* non-zero if bound */
int am_nseg;
@@ -124,6 +126,7 @@ struct agp_softc {
void *sc_chipc; /* chipset softc */
bus_dma_tag_t sc_dmat;
+ bus_space_tag_t sc_memt;
pci_chipset_tag_t sc_pc;
pcitag_t sc_pcitag;
bus_addr_t sc_apaddr;
@@ -179,12 +182,17 @@ void agp_free_dmamem(bus_dma_tag_t, size_t, bus_dmamap_t,
int agpdev_print(void *, const char *);
int agpbus_probe(struct agp_attach_args *aa);
-
int agp_bus_dma_init(struct agp_softc *, bus_addr_t, bus_addr_t,
bus_dma_tag_t *);
void agp_bus_dma_destroy(struct agp_softc *, bus_dma_tag_t);
void agp_bus_dma_set_alignment(bus_dma_tag_t, bus_dmamap_t,
u_long);
+
+void *agp_map(struct agp_softc *, bus_addr_t, bus_size_t,
+ bus_space_handle_t *);
+void agp_unmap(struct agp_softc *, void *, size_t, bus_space_handle_t);
+paddr_t agp_mmap(struct agp_softc *, off_t, int);
+
/*
* Kernel API
*/
diff --git a/sys/dev/pci/drm/drmP.h b/sys/dev/pci/drm/drmP.h
index 6c087a638f7..08261e61b4c 100644
--- a/sys/dev/pci/drm/drmP.h
+++ b/sys/dev/pci/drm/drmP.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: drmP.h,v 1.132 2012/09/08 16:42:20 mpi Exp $ */
+/* $OpenBSD: drmP.h,v 1.133 2012/12/06 15:05:21 mpi Exp $ */
/* drmP.h -- Private header for Direct Rendering Manager -*- linux-c -*-
* Created: Mon Jan 4 10:05:05 1999 by faith@precisioninsight.com
*/
@@ -297,7 +297,7 @@ struct drm_agp_mem {
};
struct drm_agp_head {
- struct device *agpdev;
+ struct agp_softc *agpdev;
const char *chipset;
TAILQ_HEAD(agp_memlist, drm_agp_mem) memory;
struct agp_info info;
@@ -585,7 +585,7 @@ void drm_free(void *);
/* XXX until we get PAT support */
#define drm_core_ioremap_wc drm_core_ioremap
void drm_core_ioremap(struct drm_local_map *, struct drm_device *);
-void drm_core_ioremapfree(struct drm_local_map *);
+void drm_core_ioremapfree(struct drm_local_map *, struct drm_device *);
int drm_mtrr_add(unsigned long, size_t, int);
int drm_mtrr_del(int, unsigned long, size_t, int);
diff --git a/sys/dev/pci/drm/drm_agpsupport.c b/sys/dev/pci/drm/drm_agpsupport.c
index 51fe6c88b42..757c8f65247 100644
--- a/sys/dev/pci/drm/drm_agpsupport.c
+++ b/sys/dev/pci/drm/drm_agpsupport.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: drm_agpsupport.c,v 1.23 2012/12/06 14:46:17 mpi Exp $ */
+/* $OpenBSD: drm_agpsupport.c,v 1.24 2012/12/06 15:05:21 mpi Exp $ */
/*-
* Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
* Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
@@ -353,7 +353,7 @@ drm_agp_free_ioctl(struct drm_device *dev, void *data,
struct drm_agp_head *
drm_agp_init(void)
{
- struct device *agpdev;
+ struct agp_softc *agpdev;
struct drm_agp_head *head = NULL;
int agp_available = 1;
diff --git a/sys/dev/pci/drm/drm_drv.c b/sys/dev/pci/drm/drm_drv.c
index e79fbe84107..16b0f32e2bd 100644
--- a/sys/dev/pci/drm/drm_drv.c
+++ b/sys/dev/pci/drm/drm_drv.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: drm_drv.c,v 1.98 2012/09/08 16:42:20 mpi Exp $ */
+/* $OpenBSD: drm_drv.c,v 1.99 2012/12/06 15:05:21 mpi Exp $ */
/*-
* Copyright 2007-2009 Owain G. Ainsworth <oga@openbsd.org>
* Copyright © 2008 Intel Corporation
@@ -906,9 +906,11 @@ drmmmap(dev_t kdev, off_t offset, int prot)
DRM_UNLOCK();
switch (type) {
+ case _DRM_AGP:
+ return agp_mmap(dev->agp->agpdev,
+ offset + map->offset - dev->agp->base, prot);
case _DRM_FRAME_BUFFER:
case _DRM_REGISTERS:
- case _DRM_AGP:
return (offset + map->offset);
break;
/* XXX unify all the bus_dmamem_mmap bits */
diff --git a/sys/dev/pci/drm/drm_memory.c b/sys/dev/pci/drm/drm_memory.c
index 4b59315ace7..2d50e351365 100644
--- a/sys/dev/pci/drm/drm_memory.c
+++ b/sys/dev/pci/drm/drm_memory.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: drm_memory.c,v 1.23 2012/09/08 16:53:01 mpi Exp $ */
+/* $OpenBSD: drm_memory.c,v 1.24 2012/12/06 15:05:21 mpi Exp $ */
/*-
*Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
* Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
@@ -90,14 +90,23 @@ drm_core_ioremap(struct drm_local_map *map, struct drm_device *dev)
/* default to failure. */
map->handle = 0;
- if (map->type == _DRM_AGP || map->type == _DRM_FRAME_BUFFER) {
- /*
- * there can be multiple agp maps in the same BAR, agp also
- * quite possibly isn't the same as the vga device, just try
- * to map it.
- */
+ switch (map->type) {
+#if __OS_HAS_AGP
+ case _DRM_AGP:
DRM_DEBUG("AGP map\n");
map->bst = dev->bst;
+ /* handles are still supposed to be kernel virtual addresses */
+ map->handle = agp_map(dev->agp->agpdev,
+ map->offset - dev->agp->base, map->size, &map->bsh);
+ if (map->handle == 0) {
+ DRM_ERROR("ioremap fail\n");
+ return;
+ }
+ break;
+#endif
+ case _DRM_FRAME_BUFFER:
+ DRM_DEBUG("FRAME_BUFFER map\n");
+ map->bst = dev->bst;
if (bus_space_map(map->bst, map->offset,
map->size, BUS_SPACE_MAP_LINEAR |
BUS_SPACE_MAP_PREFETCHABLE, &map->bsh)) {
@@ -106,16 +115,31 @@ drm_core_ioremap(struct drm_local_map *map, struct drm_device *dev)
}
/* handles are still supposed to be kernel virtual addresses */
map->handle = bus_space_vaddr(map->bst, map->bsh);
+ break;
+ default:
+ break;
}
}
void
-drm_core_ioremapfree(struct drm_local_map *map)
+drm_core_ioremapfree(struct drm_local_map *map, struct drm_device *dev)
{
- if (map->handle && map->size && (map->type == _DRM_AGP ||
- map->type == _DRM_FRAME_BUFFER)) {
+ if (map->handle == 0 || map->size == 0)
+ return;
+
+ switch (map->type) {
+#if __OS_HAS_AGP
+ case _DRM_AGP:
+ agp_unmap(dev->agp->agpdev, map->handle, map->size, map->bsh);
+ map->handle = 0;
+ break;
+#endif
+ case _DRM_FRAME_BUFFER:
bus_space_unmap(map->bst, map->bsh, map->size);
map->handle = 0;
+ break;
+ default:
+ break;
}
}
diff --git a/sys/dev/pci/drm/radeon_cp.c b/sys/dev/pci/drm/radeon_cp.c
index cfeba89d3e6..aaccfc72d5d 100644
--- a/sys/dev/pci/drm/radeon_cp.c
+++ b/sys/dev/pci/drm/radeon_cp.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: radeon_cp.c,v 1.48 2011/06/02 18:22:00 weerd Exp $ */
+/* $OpenBSD: radeon_cp.c,v 1.49 2012/12/06 15:05:21 mpi Exp $ */
/* radeon_cp.c -- CP support for Radeon -*- linux-c -*- */
/*
* Copyright 2000 Precision Insight, Inc., Cedar Park, Texas.
@@ -3274,11 +3274,11 @@ radeon_do_cleanup_cp(struct drm_device *dev)
#if __OS_HAS_AGP
if (dev_priv->flags & RADEON_IS_AGP) {
if (dev_priv->cp_ring != NULL)
- drm_core_ioremapfree(dev_priv->cp_ring);
+ drm_core_ioremapfree(dev_priv->cp_ring, dev);
if (dev_priv->ring_rptr != NULL)
- drm_core_ioremapfree(dev_priv->ring_rptr);
+ drm_core_ioremapfree(dev_priv->ring_rptr, dev);
if (dev->agp_buffer_map != NULL)
- drm_core_ioremapfree(dev->agp_buffer_map);
+ drm_core_ioremapfree(dev->agp_buffer_map, dev);
} else
#endif
{