From e05d7eaeba57921abad0ef564b0875e225171de8 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Wed, 1 Sep 2010 15:24:38 +1000 Subject: drm/nouveau: protect gpuobj list + global instmem heap with spinlock Reviewed-by: Francisco Jerez Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_drv.h | 8 +++----- drivers/gpu/drm/nouveau/nouveau_object.c | 28 ++++++++++++++++++++++++---- 2 files changed, 27 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.h b/drivers/gpu/drm/nouveau/nouveau_drv.h index 8ee854a4b3f5..0844f27651c0 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drv.h +++ b/drivers/gpu/drm/nouveau/nouveau_drv.h @@ -514,11 +514,13 @@ struct drm_nouveau_private { void __iomem *mmio; + spinlock_t ramin_lock; void __iomem *ramin; u32 ramin_size; u32 ramin_base; bool ramin_available; - spinlock_t ramin_lock; + struct drm_mm ramin_heap; + struct list_head gpuobj_list; struct nouveau_bo *vga_ram; @@ -592,10 +594,6 @@ struct drm_nouveau_private { struct nouveau_gpuobj *vm_vram_pt[NV50_VM_VRAM_NR]; int vm_vram_pt_nr; - struct drm_mm ramin_heap; - - struct list_head gpuobj_list; - struct nvbios vbios; struct nv04_mode_state mode_reg; diff --git a/drivers/gpu/drm/nouveau/nouveau_object.c b/drivers/gpu/drm/nouveau/nouveau_object.c index 02a0151b0738..37615a447a4a 100644 --- a/drivers/gpu/drm/nouveau/nouveau_object.c +++ b/drivers/gpu/drm/nouveau/nouveau_object.c @@ -93,7 +93,9 @@ nouveau_gpuobj_new(struct drm_device *dev, struct nouveau_channel *chan, kref_init(&gpuobj->refcount); gpuobj->size = size; + spin_lock(&dev_priv->ramin_lock); list_add_tail(&gpuobj->list, &dev_priv->gpuobj_list); + spin_unlock(&dev_priv->ramin_lock); if (chan) { NV_DEBUG(dev, "channel heap\n"); @@ -117,9 +119,22 @@ nouveau_gpuobj_new(struct drm_device *dev, struct nouveau_channel *chan, } /* try and get aperture space */ - ramin = drm_mm_search_free(&dev_priv->ramin_heap, size, align, 0); - if (ramin) - ramin = drm_mm_get_block(ramin, size, align); + do { + if (drm_mm_pre_get(&dev_priv->ramin_heap)) + return -ENOMEM; + + spin_lock(&dev_priv->ramin_lock); + ramin = drm_mm_search_free(&dev_priv->ramin_heap, size, + align, 0); + if (ramin == NULL) { + spin_unlock(&dev_priv->ramin_lock); + nouveau_gpuobj_ref(NULL, &gpuobj); + return ret; + } + + ramin = drm_mm_get_block_atomic(ramin, size, align); + spin_unlock(&dev_priv->ramin_lock); + } while (ramin == NULL); /* on nv50 it's ok to fail, we have a fallback path */ if (!ramin && dev_priv->card_type < NV_50) { @@ -226,10 +241,11 @@ nouveau_gpuobj_del(struct kref *ref) if (gpuobj->im_backing) engine->instmem.clear(dev, gpuobj); + spin_lock(&dev_priv->ramin_lock); if (gpuobj->im_pramin) drm_mm_put_block(gpuobj->im_pramin); - list_del(&gpuobj->list); + spin_unlock(&dev_priv->ramin_lock); kfree(gpuobj); } @@ -276,7 +292,9 @@ nouveau_gpuobj_new_fake(struct drm_device *dev, u32 pinst, u64 vinst, dev_priv->engine.instmem.flush(dev); } + spin_lock(&dev_priv->ramin_lock); list_add_tail(&gpuobj->list, &dev_priv->gpuobj_list); + spin_unlock(&dev_priv->ramin_lock); *pgpuobj = gpuobj; return 0; } @@ -553,7 +571,9 @@ nouveau_gpuobj_sw_new(struct nouveau_channel *chan, int class, kref_init(&gpuobj->refcount); gpuobj->cinst = 0x40; + spin_lock(&dev_priv->ramin_lock); list_add_tail(&gpuobj->list, &dev_priv->gpuobj_list); + spin_unlock(&dev_priv->ramin_lock); *gpuobj_ret = gpuobj; return 0; } -- cgit v1.2.3