A few steps down the yellow brick road toward bus_dma-ification:

- Add drm_dmamem_alloc/drm_dmamem_free to drm_memory.c to nicely wrap up
   the bus_dma API.

 - Start using the above in drm_pci.c.

 - Add DRM_NETBSD_DMA_ADDR/DRM_NETBSD_DMA_VADDR macros.

 Locking:

 - Use IPL_NONE for all locks except the IRQ lock, which runs at IPL_VM.

 - Use IPL_VM instead of IPL_TTY with pci_intr_establish() for consistency's
   sake. These two changes seem to eliminate the presistent lockups I was
   having (NetBSD-current/amd64 r300).

 - Start getting rid of DRM_SPININIT/DRM_SPINUNINIT and DRM_SPINLOCK/
   DRM_SPINUNLOCK ... these annoy me to no end--not to mention that they
   locks may or may not be spinlocks!  It's a linux frob, really.
   We're way beyond merging any useful bsd-core code on a large scale, which
   was the only good reason to keep them around.

 Memory allocation:

  - Change drm_memory.c so that it contains generally useful, memory
    allocation functions using kmem(9) (mostly used by the drivers
    themselves).  However, I expect to use this more in the future
    in the "bsd core".  These functions always use KM_NOSLEEP.
    The new drm_dmamem_alloc function has a wait argument which
    takes DRM_DMA_WAIT/DRM_DMA_NOWAIT (defined as their bus_dma
    counterparts), and honors this hint in its calls to kmem(9)
    and bus_dma(9) functions.

  - Got rid of these functions' "area" argument--it's been deprecated for
    ages.  Provide macros in drmP.h to deal with the os-independent code.

  - Declare these functions inline -- I believe they're used enough
    by the i915 and radeon drivers to justify it.  Please let me know
    if I am mistaken.

    NOTE: With these changes, a glxgears score which was previously
    ~3900fps is now ~4400fps (same setup as mentioned above).  I realize
    that using kmem(9) could cause problems, but I can't seem to run into
    any with my test setup.  If anyone smells regression, please let me
    know.
This commit is contained in:
bjs 2008-05-06 01:26:14 +00:00
parent c63ddfd726
commit a65a4adb77
4 changed files with 155 additions and 98 deletions

View File

@ -1,4 +1,4 @@
/* $NetBSD: drmP.h,v 1.20 2008/05/05 14:00:10 jmcneill Exp $ */
/* $NetBSD: drmP.h,v 1.21 2008/05/06 01:26:14 bjs Exp $ */
/* drmP.h -- Private header for Direct Rendering Manager -*- linux-c -*-
* Created: Mon Jan 4 10:05:05 1999 by faith@precisioninsight.com
@ -56,6 +56,7 @@ typedef struct drm_file drm_file_t;
#include <sys/param.h>
#include <sys/queue.h>
#include <sys/kmem.h>
#include <sys/malloc.h>
#include <sys/kernel.h>
#ifdef __FreeBSD__
@ -230,7 +231,7 @@ MALLOC_DECLARE(M_DRM);
#define DRM_STRUCTPROC struct proc
#define DRM_STRUCTCDEVPROC struct lwp
#define DRM_SPINTYPE kmutex_t
#define DRM_SPININIT(l,name) mutex_init(l, MUTEX_DEFAULT, IPL_VM)
#define DRM_SPININIT(l,name) mutex_init(l, MUTEX_DEFAULT, IPL_NONE)
#define DRM_SPINUNINIT(l) mutex_destroy(l)
#define DRM_SPINLOCK(l) mutex_enter(l)
#define DRM_SPINUNLOCK(u) mutex_exit(u)
@ -257,6 +258,7 @@ MALLOC_DECLARE(M_DRM);
#endif /* __NetBSD__ */
#endif /* __NetBSD__ || __OpenBSD__ */
/* Currently our DRMFILE (filp) is a void * which is actually the pid
* of the current process. It should be a per-open unique pointer, but
* code for that is not yet written */
@ -312,6 +314,11 @@ extern drm_device_t *drm_units[];
#define DRM_NETBSD_ADDR2HANDLE(addr) (addr)
#define DRM_NETBSD_HANDLE2ADDR(handle) (handle)
#endif
/* see struct drm_dmamem */
#define DRM_NETBSD_DMA_VADDR(p) ((p)->dm_kva)
#define DRM_NETBSD_DMA_ADDR(p) ((p)->dm_segs[0].ds_addr)
#define DRM_DMA_WAITOK BUS_DMA_WAITOK
#define DRM_DMA_NOWAIT BUS_DMA_NOWAIT
#elif defined(__OpenBSD__)
#define DRM_DEVICE \
#define DRM_SUSER(p) (suser(p->p_ucred, &p->p_acflag) == 0)
@ -603,16 +610,21 @@ typedef struct drm_freelist {
int high_mark; /* High water mark */
} drm_freelist_t;
struct drm_dmamem {
bus_dma_tag_t dm_tag;
bus_dmamap_t dm_map;
bus_dma_segment_t *dm_segs;
int dm_nsegs;
size_t dm_size;
void *dm_kva;
};
typedef struct drm_dma_handle {
void *vaddr;
bus_addr_t busaddr;
bus_dma_tag_t dmat;
bus_dmamap_t map;
bus_dma_segment_t segs[1];
size_t size;
void *addr;
struct drm_dmamem *dmam;
} drm_dma_handle_t;
#define DRM_PCI_DMAADDR(p) ((p)->map->dm_segs[0].ds_addr)
typedef struct drm_buf_entry {
int buf_size;
@ -695,6 +707,7 @@ typedef struct drm_sg_mem {
int pages;
dma_addr_t *busaddr;
drm_dma_handle_t *dmah; /* Handle to PCI memory for ATI PCIGART table */
struct drm_dmamem *dmam;
} drm_sg_mem_t;
typedef TAILQ_HEAD(drm_map_list, drm_local_map) drm_map_list_t;
@ -970,16 +983,29 @@ extern drm_file_t *drm_find_file_by_proc(drm_device_t *dev,
DRM_STRUCTPROC *p);
#endif /* __NetBSD__ || __OpenBSD__ */
/* Memory management support (drm_memory.c) */
void drm_mem_init(void);
void drm_mem_uninit(void);
void *drm_alloc(size_t size, int area);
void *drm_calloc(size_t nmemb, size_t size, int area);
void *drm_realloc(void *oldpt, size_t oldsize, size_t size,
int area);
void drm_free(void *pt, size_t size, int area);
void drm_mem_init(void); /* XXX unused */
void drm_mem_uninit(void); /* XXX unused */
/* NetBSD-specific memory allocation functions */
inline void *drm_mem_alloc(size_t size);
inline void *drm_mem_zalloc(size_t size);
inline void *drm_mem_calloc(size_t nmemb, size_t size);
inline void *drm_mem_realloc(void *oldpt, size_t oldsize, size_t size);
inline void drm_mem_free(void *pt, size_t size);
/* NetBSD-specific DMA memory management */
inline struct drm_dmamem *drm_dmamem_alloc(bus_dma_tag_t tag, size_t size, int wait);
inline void drm_dmamem_free(struct drm_dmamem *dmam);
/* macros for os-independent code (discards deprecated 'area' argument) */
#define drm_alloc(sz, a) drm_mem_alloc(sz)
#define drm_calloc(sz, a) drm_mem_zalloc(sz)
#define drm_realloc(old, oldsz, sz, a) drm_mem_realloc(old, oldsz, sz)
#define drm_free(p, sz, a) drm_mem_free(p, sz)
void *drm_ioremap(drm_device_t *dev, drm_local_map_t *map);
void drm_ioremapfree(drm_local_map_t *map);
int drm_mtrr_add(unsigned long offset, size_t size, int flags);
int drm_mtrr_del(int handle, unsigned long offset, size_t size, int flags);

View File

@ -1,4 +1,4 @@
/* $NetBSD: drm_irq.c,v 1.8 2008/04/08 07:39:11 cegger Exp $ */
/* $NetBSD: drm_irq.c,v 1.9 2008/05/06 01:26:14 bjs Exp $ */
/* drm_irq.c -- IRQ IOCTL and function support
* Created: Fri Oct 18 2003 by anholt@FreeBSD.org
@ -31,7 +31,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: drm_irq.c,v 1.8 2008/04/08 07:39:11 cegger Exp $");
__KERNEL_RCSID(0, "$NetBSD: drm_irq.c,v 1.9 2008/05/06 01:26:14 bjs Exp $");
/*
__FBSDID("$FreeBSD: src/sys/dev/drm/drm_irq.c,v 1.2 2005/11/28 23:13:52 anholt Exp $");
*/
@ -68,9 +68,9 @@ drm_irq_handler_wrap(DRM_IRQ_ARGS)
irqreturn_t ret;
drm_device_t *dev = (drm_device_t *)arg;
DRM_SPINLOCK(&dev->irq_lock);
mutex_enter(&dev->irq_lock);
ret = dev->driver.irq_handler(arg);
DRM_SPINUNLOCK(&dev->irq_lock);
mutex_exit(&dev->irq_lock);
return ret;
}
@ -94,7 +94,7 @@ int drm_irq_install(drm_device_t *dev)
dev->context_flag = 0;
DRM_SPININIT(&dev->irq_lock, "DRM IRQ lock");
mutex_init(&dev->irq_lock, MUTEX_DEFAULT, IPL_VM);
/* Before installing handler */
@ -107,7 +107,7 @@ int drm_irq_install(drm_device_t *dev)
goto err;
}
istr = pci_intr_string(dev->pa.pa_pc, ih);
dev->irqh = pci_intr_establish(dev->pa.pa_pc, ih, IPL_TTY,
dev->irqh = pci_intr_establish(dev->pa.pa_pc, ih, IPL_VM,
drm_irq_handler_wrap, dev);
if (!dev->irqh) {
retcode = ENOENT;
@ -124,7 +124,7 @@ int drm_irq_install(drm_device_t *dev)
err:
DRM_LOCK();
dev->irq_enabled = 0;
DRM_SPINUNINIT(&dev->irq_lock);
mutex_destroy(&dev->irq_lock);
DRM_UNLOCK();
return retcode;
}
@ -141,7 +141,7 @@ int drm_irq_uninstall(drm_device_t *dev)
dev->driver.irq_uninstall(dev);
pci_intr_disestablish(dev->pa.pa_pc, dev->irqh);
DRM_SPINUNINIT(&dev->irq_lock);
mutex_destroy(&dev->irq_lock);
return 0;
}
@ -209,9 +209,9 @@ int drm_wait_vblank(DRM_IOCTL_ARGS)
vblwait.reply.sequence = atomic_read(&dev->vbl_received);
DRM_SPINLOCK(&dev->irq_lock);
mutex_enter(&dev->irq_lock);
TAILQ_INSERT_HEAD(&dev->vbl_sig_list, vbl_sig, link);
DRM_SPINUNLOCK(&dev->irq_lock);
mutex_exit(&dev->irq_lock);
ret = 0;
#endif
ret = EINVAL;

View File

@ -1,4 +1,4 @@
/* $NetBSD: drm_memory.c,v 1.8 2008/03/13 05:35:43 bjs Exp $ */
/* $NetBSD: drm_memory.c,v 1.9 2008/05/06 01:26:14 bjs Exp $ */
/* drm_memory.h -- Memory management wrappers for DRM -*- linux-c -*-
* Created: Thu Feb 4 14:00:34 1999 by faith@valinux.com
@ -34,7 +34,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: drm_memory.c,v 1.8 2008/03/13 05:35:43 bjs Exp $");
__KERNEL_RCSID(0, "$NetBSD: drm_memory.c,v 1.9 2008/05/06 01:26:14 bjs Exp $");
/*
__FBSDID("$FreeBSD: src/sys/dev/drm/drm_memory.c,v 1.2 2005/11/28 23:13:52 anholt Exp $");
*/
@ -54,42 +54,53 @@ MALLOC_DEFINE(M_DRM, "drm", "DRM Data Structures");
void drm_mem_init(void)
{
/*
malloc_type_attach(M_DRM);
*/
}
void drm_mem_uninit(void)
{
}
void *drm_alloc(size_t size, int area)
inline void *drm_mem_alloc(size_t size)
{
return malloc(size, M_DRM, M_NOWAIT);
return kmem_alloc(size, KM_NOSLEEP);
}
void *drm_calloc(size_t nmemb, size_t size, int area)
inline void *drm_mem_zalloc(size_t size)
{
return malloc(size * nmemb, M_DRM, M_NOWAIT | M_ZERO);
return kmem_zalloc(size, KM_NOSLEEP);
}
void *drm_realloc(void *oldpt, size_t oldsize, size_t size, int area)
inline void *drm_mem_calloc(size_t nmemb, size_t size)
{
return kmem_zalloc(size * nmemb, KM_NOSLEEP);
}
inline void *drm_mem_realloc(void *oldpt, size_t oldsize, size_t size)
{
void *pt;
pt = malloc(size, M_DRM, M_NOWAIT);
pt = drm_mem_alloc(size);
if (pt == NULL)
return NULL;
if (oldpt && oldsize) {
memcpy(pt, oldpt, oldsize);
free(oldpt, M_DRM);
drm_mem_free(oldpt, oldsize);
}
return pt;
}
void drm_free(void *pt, size_t size, int area)
inline void drm_mem_free(void *pt, size_t size)
{
free(pt, M_DRM);
#if 0
KASSERT(pt == NULL)
#else
if (pt == NULL) {
DRM_DEBUG("drm_mem_free: told to free a null pointer!");
return;
}
#endif
kmem_free(pt, size);
}
void *drm_ioremap(drm_device_t *dev, drm_local_map_t *map)
@ -227,3 +238,60 @@ drm_mtrr_del(int __unused handle, unsigned long offset, size_t size, int flags)
return 0;
#endif
}
inline struct drm_dmamem *
drm_dmamem_alloc(bus_dma_tag_t tag, size_t size, int wait)
{
struct drm_dmamem *dma;
int kmflag;
kmflag = (wait & DRM_DMA_NOWAIT) != 0 ? KM_NOSLEEP : KM_SLEEP;
dma = kmem_zalloc(sizeof(*dma), kmflag);
if (dma == NULL)
return NULL;
dma->dm_size = size;
dma->dm_tag = tag;
if (bus_dmamap_create(dma->dm_tag, size, size / PAGE_SIZE + 1, size, 0,
wait|BUS_DMA_ALLOCNOW, &dma->dm_map) != 0)
goto dmafree;
if (bus_dmamem_alloc(dma->dm_tag, size, PAGE_SIZE, 0, dma->dm_segs,
1, &dma->dm_nsegs, wait) != 0)
goto destroy;
if (bus_dmamem_map(dma->dm_tag, dma->dm_segs, dma->dm_nsegs, size,
&dma->dm_kva, wait|BUS_DMA_COHERENT) != 0)
goto free;
if (bus_dmamap_load(dma->dm_tag, dma->dm_map, dma->dm_kva, size,
NULL, wait) != 0)
goto unmap;
return dma;
unmap:
bus_dmamem_unmap(dma->dm_tag, dma->dm_kva, size);
free:
bus_dmamem_free(dma->dm_tag, dma->dm_segs, dma->dm_nsegs);
destroy:
bus_dmamap_destroy(dma->dm_tag, dma->dm_map);
dmafree:
kmem_free(dma, sizeof(*dma));
return NULL;
}
inline void
drm_dmamem_free(struct drm_dmamem *dma)
{
if (dma != NULL) {
bus_dmamap_unload(dma->dm_tag, dma->dm_map);
bus_dmamem_unmap(dma->dm_tag, dma->dm_kva, dma->dm_size);
bus_dmamem_free(dma->dm_tag, dma->dm_segs, dma->dm_nsegs);
bus_dmamap_destroy(dma->dm_tag, dma->dm_map);
kmem_free(dma, sizeof(*dma));
}
}

View File

@ -1,4 +1,4 @@
/* $NetBSD: drm_pci.c,v 1.8 2008/03/02 07:12:15 bjs Exp $ */
/* $NetBSD: drm_pci.c,v 1.9 2008/05/06 01:26:14 bjs Exp $ */
/*
* Copyright 2003 Eric Anholt.
@ -24,7 +24,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: drm_pci.c,v 1.8 2008/03/02 07:12:15 bjs Exp $");
__KERNEL_RCSID(0, "$NetBSD: drm_pci.c,v 1.9 2008/05/06 01:26:14 bjs Exp $");
/*
__FBSDID("$FreeBSD: src/sys/dev/drm/drm_pci.c,v 1.2 2005/11/28 23:13:52 anholt Exp $");
*/
@ -34,72 +34,35 @@ __FBSDID("$FreeBSD: src/sys/dev/drm/drm_pci.c,v 1.2 2005/11/28 23:13:52 anholt E
drm_dma_handle_t *
drm_pci_alloc(drm_device_t *dev, size_t size, size_t align, dma_addr_t maxaddr)
{
drm_dma_handle_t *h;
int error, nsegs;
drm_dma_handle_t *hdl;
struct drm_dmamem *dmam;
hdl = drm_mem_zalloc(sizeof(drm_dma_handle_t));
if (hdl == NULL)
goto err;
/* Need power-of-two alignment, so fail the allocation if it isn't. */
if ((align & (align - 1)) != 0) {
DRM_ERROR("drm_pci_alloc with non-power-of-two alignment %d\n",
(int)align);
return NULL;
}
dmam = drm_dmamem_alloc(dev->pa.pa_dmat, size, DRM_DMA_NOWAIT);
if (dmam == NULL)
goto free;
h = malloc(sizeof(drm_dma_handle_t), M_DRM, M_ZERO | M_NOWAIT);
hdl->busaddr = DRM_NETBSD_DMA_ADDR(dmam);
hdl->vaddr = DRM_NETBSD_DMA_VADDR(dmam);
hdl->size = size;
return hdl;
if (h == NULL)
return NULL;
if ((error = bus_dmamem_alloc(dev->pa.pa_dmat, size, align, 0,
h->segs, 1, &nsegs, BUS_DMA_NOWAIT)) != 0) {
printf("drm: Unable to allocate DMA, error %d\n", error);
goto fail;
}
if ((error = bus_dmamem_map(dev->pa.pa_dmat, h->segs, nsegs, size,
&h->addr, BUS_DMA_NOWAIT | BUS_DMA_COHERENT)) != 0) {
printf("drm: Unable to map DMA, error %d\n", error);
goto free;
}
if ((error = bus_dmamap_create(dev->pa.pa_dmat, size, 1, size, 0,
BUS_DMA_NOWAIT | BUS_DMA_ALLOCNOW, &h->map)) != 0) {
printf("drm: Unable to create DMA map, error %d\n", error);
goto unmap;
}
if ((error = bus_dmamap_load(dev->pa.pa_dmat, h->map, h->addr, size,
NULL, BUS_DMA_NOWAIT)) != 0) {
printf("drm: Unable to load DMA map, error %d\n", error);
goto destroy;
}
h->busaddr = DRM_PCI_DMAADDR(h);
h->vaddr = h->addr;
h->size = size;
return h;
destroy:
bus_dmamap_destroy(dev->pa.pa_dmat, h->map);
unmap:
bus_dmamem_unmap(dev->pa.pa_dmat, h->addr, size);
free:
bus_dmamem_free(dev->pa.pa_dmat, h->segs, 1);
fail:
free(h, M_DRM);
drm_mem_free(hdl, sizeof(*hdl));
err:
return NULL;
}
/*
* Free a DMA-accessible consistent memory block.
*/
void
drm_pci_free(drm_device_t *dev, drm_dma_handle_t *h)
drm_pci_free(drm_device_t *dev, drm_dma_handle_t *hdl)
{
if (h == NULL)
return;
bus_dmamap_unload(dev->pa.pa_dmat, h->map);
bus_dmamap_destroy(dev->pa.pa_dmat, h->map);
bus_dmamem_unmap(dev->pa.pa_dmat, h->addr, h->size);
bus_dmamem_free(dev->pa.pa_dmat, h->segs, 1);
free(h, M_DRM);
if (hdl != NULL) {
if (hdl->dmam != NULL)
drm_dmamem_free(hdl->dmam);
drm_mem_free(hdl, sizeof(*hdl));
}
}