drm/nouveau: hold mutex while syncing to kernel channel
Subsystems (3)
PATCH 1/2 drm/nouveau: hold mutex while syncing to kernel channel
Not holding the mutex potentially causes corruption of the kernel channel when page flipping.
Cc [email protected] #3.13
Signed-off-by Maarten Lankhorst <[email protected]>
---
drivers/gpu/drm/nouveau/nouveau_display.c +8 -7
@@ -603,6 +603,14 @@ nouveau_crtc_page_flip(struct drm_crtc *crtc, struct drm_framebuffer *fb,if (!s)return -ENOMEM ; +if (new_bo != old_bo) { + ret =nouveau_bo_pin (new_bo,TTM_PL_FLAG_VRAM ); +if (ret) + goto fail_free; + } + +mutex_lock (&chan->cli->mutex); +/* synchronise rendering channel with the kernel's channel */ spin_lock (&new_bo->bo.bdev->fence_lock); fence =nouveau_fence_ref (new_bo->bo.sync_obj);
@@ -612,13 +620,6 @@ nouveau_crtc_page_flip(struct drm_crtc *crtc, struct drm_framebuffer *fb,if (ret)return ret; -if (new_bo != old_bo) { - ret =nouveau_bo_pin (new_bo,TTM_PL_FLAG_VRAM ); -if (ret) - goto fail_free; - } - -mutex_lock (&chan->cli->mutex); ret =ttm_bo_reserve (&old_bo->bo, true, false, false,NULL );if (ret) goto fail_unpin;
PATCH 2/2 drm/nouveau: require cli->mutex in RING_SPACE
There are some cases where it's fine to not hold the cli->mutex, but in those cases we are the only caller and we should really be able to acquire cli->mutex without blocking.
This patch will prevent future occurrences where commands are sent to a channel without proper locking.
Signed-off-by Maarten Lankhorst<[email protected]>
---
drivers/gpu/drm/nouveau/nouveau_abi16.c +2 -0
@@ -153,10 +153,12 @@ nouveau_abi16_fini(struct nouveau_abi16 *abi16)struct nouveau_cli *cli = (void *)abi16->client;struct nouveau_abi16_chan *chan, *temp; +mutex_lock (&cli->mutex);/* cleanup channels */ list_for_each_entry_safe (chan, temp, &abi16->channels, head) {nouveau_abi16_chan_fini (abi16, chan); } +mutex_unlock (&cli->mutex);/* destroy the device object */ nouveau_object_del (abi16->client,NVDRM_CLIENT ,NVDRM_DEVICE );
drivers/gpu/drm/nouveau/nouveau_dma.h +1 -0
@@ -107,6 +107,7 @@ RING_SPACE(struct nouveau_channel *chan, int size) {int ret; +lockdep_assert_held (&chan->cli->mutex); ret =nouveau_dma_wait (chan,1 , size);if (ret)return ret;
drivers/gpu/drm/nouveau/nouveau_drm.c +10 -8
@@ -476,7 +476,9 @@ nouveau_drm_load(struct drm_device *dev, unsigned long flags)nouveau_sysfs_init (dev);nouveau_hwmon_init (dev); +mutex_lock (&drm->client.mutex);nouveau_accel_init (drm); +mutex_unlock (&drm->client.mutex);nouveau_fbcon_init (dev);if (nouveau_runtime_pm !=0 ) {
@@ -562,17 +564,17 @@ nouveau_do_suspend(struct drm_device *dev)ttm_bo_evict_mm (&drm->ttm.bdev,TTM_PL_VRAM );NV_INFO (drm,"waiting for kernel channels to go idle...\n" ); -if (drm->cechan) { + ret =0 ; +mutex_lock (&drm->client.mutex); +if (drm->cechan) ret =nouveau_channel_idle (drm->cechan); -if (ret) -return ret; - } -if (drm->channel) { +if (drm->channel && !ret) ret =nouveau_channel_idle (drm->channel); -if (ret) -return ret; - } +mutex_unlock (&drm->client.mutex); +if (ret) +return ret; +NV_INFO (drm,"suspending client object trees...\n" );if (drm->fence &&nouveau_fence (drm)->suspend) {
drivers/gpu/drm/nouveau/nouveau_fbcon.c +2 -1
@@ -357,7 +357,7 @@ nouveau_fbcon_create(struct drm_fb_helper *helper,mutex_unlock (&dev->struct_mutex); -if (chan) { +if (chan && !WARN_ON (!mutex_trylock (&drm->client.mutex))) { ret = -ENODEV ;if (device->card_type <NV_50 ) ret =nv04_fbcon_accel_init (info);
@@ -366,6 +366,7 @@ nouveau_fbcon_create(struct drm_fb_helper *helper, ret =nv50_fbcon_accel_init (info); else ret =nvc0_fbcon_accel_init (info); +mutex_unlock (&drm->client.mutex);if (ret ==0 ) info->fbops = &nouveau_fbcon_ops;