summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorrnoland <rnoland@FreeBSD.org>2008-09-09 02:05:03 +0000
committerrnoland <rnoland@FreeBSD.org>2008-09-09 02:05:03 +0000
commit016be156e0964094bf2d383d94aef409a35dc78c (patch)
treeb049bd3bd13dc9dbf8c993171dae2fd568b69bed
parent1af31f868a04970e4e460e2e08c563289e42b042 (diff)
downloadFreeBSD-src-016be156e0964094bf2d383d94aef409a35dc78c.zip
FreeBSD-src-016be156e0964094bf2d383d94aef409a35dc78c.tar.gz
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
-rw-r--r--sys/dev/drm/ati_pcigart.c13
-rw-r--r--sys/dev/drm/drm_bufs.c2
-rw-r--r--sys/dev/drm/drm_pci.c11
-rw-r--r--sys/dev/drm/i915_dma.c18
-rw-r--r--sys/dev/drm/mach64_dma.c6
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;
OpenPOWER on IntegriCloud