From 016be156e0964094bf2d383d94aef409a35dc78c Mon Sep 17 00:00:00 2001 From: rnoland Date: Tue, 9 Sep 2008 02:05:03 +0000 Subject: We should never call drm_pci_alloc() while holding locks, due the the calls to bus_dma. There were multiple paths that held different locks or no locks at all. This patch ensures that all of the calling paths drop their lock(s) before calling drm_pci_alloc(). Reviewed by: kib --- sys/dev/drm/ati_pcigart.c | 13 +++++++++---- sys/dev/drm/drm_bufs.c | 2 ++ sys/dev/drm/drm_pci.c | 11 +++++++---- sys/dev/drm/i915_dma.c | 18 ++++++++++++------ sys/dev/drm/mach64_dma.c | 6 ++++++ 5 files changed, 36 insertions(+), 14 deletions(-) diff --git a/sys/dev/drm/ati_pcigart.c b/sys/dev/drm/ati_pcigart.c index dac400d..597479c 100644 --- a/sys/dev/drm/ati_pcigart.c +++ b/sys/dev/drm/ati_pcigart.c @@ -45,12 +45,17 @@ __FBSDID("$FreeBSD$"); static int drm_ati_alloc_pcigart_table(struct drm_device *dev, struct drm_ati_pcigart_info *gart_info) { - dev->sg->dmah = drm_pci_alloc(dev, gart_info->table_size, - PAGE_SIZE, - gart_info->table_mask); - if (dev->sg->dmah == NULL) + drm_dma_handle_t *dmah; + + DRM_UNLOCK(); + dmah = drm_pci_alloc(dev, gart_info->table_size, PAGE_SIZE, + gart_info->table_mask); + DRM_LOCK(); + if (dmah == NULL) return ENOMEM; + dev->sg->dmah = dmah; + return 0; } diff --git a/sys/dev/drm/drm_bufs.c b/sys/dev/drm/drm_bufs.c index 9ad13d7..b07359c 100644 --- a/sys/dev/drm/drm_bufs.c +++ b/sys/dev/drm/drm_bufs.c @@ -598,8 +598,10 @@ static int drm_do_addbufs_pci(struct drm_device *dev, drm_buf_desc_t *request) page_count = 0; while ( entry->buf_count < count ) { + DRM_SPINUNLOCK(&dev->dma_lock); drm_dma_handle_t *dmah = drm_pci_alloc(dev, size, alignment, 0xfffffffful); + DRM_SPINLOCK(&dev->dma_lock); if (dmah == NULL) { /* Set count correctly so we free the proper amount. */ entry->buf_count = count; diff --git a/sys/dev/drm/drm_pci.c b/sys/dev/drm/drm_pci.c index a6ddfdf..4aa6d03 100644 --- a/sys/dev/drm/drm_pci.c +++ b/sys/dev/drm/drm_pci.c @@ -74,7 +74,12 @@ drm_pci_alloc(struct drm_device *dev, size_t size, return NULL; #ifdef __FreeBSD__ - DRM_UNLOCK(); + /* Make sure we aren't holding locks here */ + if (mtx_owned(&dev->dev_lock)) + DRM_ERROR("called while holding dev_lock\n"); + if (mtx_owned(&dev->dma_lock)) + DRM_ERROR("called while holding dma_lock\n"); + ret = bus_dma_tag_create(NULL, align, 0, /* tag, align, boundary */ maxaddr, BUS_SPACE_MAXADDR, /* lowaddr, highaddr */ NULL, NULL, /* filtfunc, filtfuncargs */ @@ -83,7 +88,6 @@ drm_pci_alloc(struct drm_device *dev, size_t size, &dmah->tag); if (ret != 0) { free(dmah, M_DRM); - DRM_LOCK(); return NULL; } @@ -92,10 +96,9 @@ drm_pci_alloc(struct drm_device *dev, size_t size, if (ret != 0) { bus_dma_tag_destroy(dmah->tag); free(dmah, M_DRM); - DRM_LOCK(); return NULL; } - DRM_LOCK(); + ret = bus_dmamap_load(dmah->tag, dmah->map, dmah->vaddr, size, drm_pci_busdma_callback, dmah, 0); if (ret != 0) { diff --git a/sys/dev/drm/i915_dma.c b/sys/dev/drm/i915_dma.c index 8cfdfb0..79e687e 100644 --- a/sys/dev/drm/i915_dma.c +++ b/sys/dev/drm/i915_dma.c @@ -250,16 +250,22 @@ static int i915_initialize(struct drm_device * dev, /* Program Hardware Status Page */ if (!I915_NEED_GFX_HWS(dev)) { - dev_priv->status_page_dmah = - drm_pci_alloc(dev, PAGE_SIZE, PAGE_SIZE, 0xffffffff); - - if (!dev_priv->status_page_dmah) { + drm_dma_handle_t *dmah; +#ifdef __FreeBSD__ + DRM_UNLOCK(); +#endif + dmah = drm_pci_alloc(dev, PAGE_SIZE, PAGE_SIZE, 0xffffffff); +#ifdef __FreeBSD__ + DRM_LOCK(); +#endif + if (!dmah) { i915_dma_cleanup(dev); DRM_ERROR("Can not allocate hardware status page\n"); return -ENOMEM; } - dev_priv->hw_status_page = dev_priv->status_page_dmah->vaddr; - dev_priv->dma_status_page = dev_priv->status_page_dmah->busaddr; + dev_priv->status_page_dmah = dmah; + dev_priv->hw_status_page = dmah->vaddr; + dev_priv->dma_status_page = dmah->busaddr; memset(dev_priv->hw_status_page, 0, PAGE_SIZE); diff --git a/sys/dev/drm/mach64_dma.c b/sys/dev/drm/mach64_dma.c index 1cb7779..6068c85 100644 --- a/sys/dev/drm/mach64_dma.c +++ b/sys/dev/drm/mach64_dma.c @@ -837,8 +837,14 @@ static int mach64_bm_dma_test(struct drm_device * dev) /* FIXME: get a dma buffer from the freelist here */ DRM_DEBUG("Allocating data memory ...\n"); +#ifdef __FreeBSD__ + DRM_UNLOCK(); +#endif cpu_addr_dmah = drm_pci_alloc(dev, 0x1000, 0x1000, 0xfffffffful); +#ifdef __FreeBSD__ + DRM_LOCK(); +#endif if (!cpu_addr_dmah) { DRM_INFO("data-memory allocation failed!\n"); return -ENOMEM; -- cgit v1.1