aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/nouveau/nouveau_fbcon.c
diff options
context:
space:
mode:
authorBen Skeggs <bskeggs@redhat.com>2010-10-05 02:53:48 -0400
committerBen Skeggs <bskeggs@redhat.com>2010-12-03 00:05:10 -0500
commit6a6b73f254123851f7f73ab5e57344a569d6a0ab (patch)
tree5db28f577f0a7b15525aeef57d45a34ea4366bb8 /drivers/gpu/drm/nouveau/nouveau_fbcon.c
parentceed5f30bf0f515b52246230e5faacf89983fd8f (diff)
drm/nouveau: add per-channel mutex, use to lock access to drm's channel
This fixes a race condition between fbcon acceleration and TTM buffer moves. To reproduce: - start X - switch to vt and "while (true); do dmesg; done" - switch to another vt and "sleep 2 && cat /path/to/debugfs/dri/0/evict_vram" - switch back to vt running dmesg We don't make use of this on any other channel yet, they're currently protected by drm_global_mutex. This will change in the near future. Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
Diffstat (limited to 'drivers/gpu/drm/nouveau/nouveau_fbcon.c')
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_fbcon.c17
1 files changed, 14 insertions, 3 deletions
diff --git a/drivers/gpu/drm/nouveau/nouveau_fbcon.c b/drivers/gpu/drm/nouveau/nouveau_fbcon.c
index 22e83adcc930..bc30dbe11d00 100644
--- a/drivers/gpu/drm/nouveau/nouveau_fbcon.c
+++ b/drivers/gpu/drm/nouveau/nouveau_fbcon.c
@@ -62,11 +62,13 @@ nouveau_fbcon_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
62 62
63 ret = -ENODEV; 63 ret = -ENODEV;
64 if (!in_interrupt() && !(info->flags & FBINFO_HWACCEL_DISABLED)) { 64 if (!in_interrupt() && !(info->flags & FBINFO_HWACCEL_DISABLED)) {
65 mutex_lock(&dev_priv->channel->mutex);
65 if (dev_priv->card_type < NV_50) 66 if (dev_priv->card_type < NV_50)
66 ret = nv04_fbcon_fillrect(info, rect); 67 ret = nv04_fbcon_fillrect(info, rect);
67 else 68 else
68 if (dev_priv->card_type < NV_C0) 69 if (dev_priv->card_type < NV_C0)
69 ret = nv50_fbcon_fillrect(info, rect); 70 ret = nv50_fbcon_fillrect(info, rect);
71 mutex_unlock(&dev_priv->channel->mutex);
70 } 72 }
71 73
72 if (ret == 0) 74 if (ret == 0)
@@ -90,11 +92,13 @@ nouveau_fbcon_copyarea(struct fb_info *info, const struct fb_copyarea *image)
90 92
91 ret = -ENODEV; 93 ret = -ENODEV;
92 if (!in_interrupt() && !(info->flags & FBINFO_HWACCEL_DISABLED)) { 94 if (!in_interrupt() && !(info->flags & FBINFO_HWACCEL_DISABLED)) {
95 mutex_lock(&dev_priv->channel->mutex);
93 if (dev_priv->card_type < NV_50) 96 if (dev_priv->card_type < NV_50)
94 ret = nv04_fbcon_copyarea(info, image); 97 ret = nv04_fbcon_copyarea(info, image);
95 else 98 else
96 if (dev_priv->card_type < NV_C0) 99 if (dev_priv->card_type < NV_C0)
97 ret = nv50_fbcon_copyarea(info, image); 100 ret = nv50_fbcon_copyarea(info, image);
101 mutex_unlock(&dev_priv->channel->mutex);
98 } 102 }
99 103
100 if (ret == 0) 104 if (ret == 0)
@@ -118,11 +122,13 @@ nouveau_fbcon_imageblit(struct fb_info *info, const struct fb_image *image)
118 122
119 ret = -ENODEV; 123 ret = -ENODEV;
120 if (!in_interrupt() && !(info->flags & FBINFO_HWACCEL_DISABLED)) { 124 if (!in_interrupt() && !(info->flags & FBINFO_HWACCEL_DISABLED)) {
125 mutex_lock(&dev_priv->channel->mutex);
121 if (dev_priv->card_type < NV_50) 126 if (dev_priv->card_type < NV_50)
122 ret = nv04_fbcon_imageblit(info, image); 127 ret = nv04_fbcon_imageblit(info, image);
123 else 128 else
124 if (dev_priv->card_type < NV_C0) 129 if (dev_priv->card_type < NV_C0)
125 ret = nv50_fbcon_imageblit(info, image); 130 ret = nv50_fbcon_imageblit(info, image);
131 mutex_unlock(&dev_priv->channel->mutex);
126 } 132 }
127 133
128 if (ret == 0) 134 if (ret == 0)
@@ -142,12 +148,15 @@ nouveau_fbcon_sync(struct fb_info *info)
142 struct nouveau_channel *chan = dev_priv->channel; 148 struct nouveau_channel *chan = dev_priv->channel;
143 int ret, i; 149 int ret, i;
144 150
145 if (!chan || !chan->accel_done || 151 if (!chan || !chan->accel_done || in_interrupt() ||
146 info->state != FBINFO_STATE_RUNNING || 152 info->state != FBINFO_STATE_RUNNING ||
147 info->flags & FBINFO_HWACCEL_DISABLED) 153 info->flags & FBINFO_HWACCEL_DISABLED)
148 return 0; 154 return 0;
149 155
150 if (RING_SPACE(chan, 4)) { 156 mutex_lock(&chan->mutex);
157 ret = RING_SPACE(chan, 4);
158 if (ret) {
159 mutex_unlock(&chan->mutex);
151 nouveau_fbcon_gpu_lockup(info); 160 nouveau_fbcon_gpu_lockup(info);
152 return 0; 161 return 0;
153 } 162 }
@@ -158,6 +167,7 @@ nouveau_fbcon_sync(struct fb_info *info)
158 OUT_RING(chan, 0); 167 OUT_RING(chan, 0);
159 nouveau_bo_wr32(chan->notifier_bo, chan->m2mf_ntfy + 3, 0xffffffff); 168 nouveau_bo_wr32(chan->notifier_bo, chan->m2mf_ntfy + 3, 0xffffffff);
160 FIRE_RING(chan); 169 FIRE_RING(chan);
170 mutex_unlock(&chan->mutex);
161 171
162 ret = -EBUSY; 172 ret = -EBUSY;
163 for (i = 0; i < 100000; i++) { 173 for (i = 0; i < 100000; i++) {
@@ -353,6 +363,8 @@ nouveau_fbcon_create(struct nouveau_fbdev *nfbdev,
353 info->pixmap.flags = FB_PIXMAP_SYSTEM; 363 info->pixmap.flags = FB_PIXMAP_SYSTEM;
354 info->pixmap.scan_align = 1; 364 info->pixmap.scan_align = 1;
355 365
366 mutex_unlock(&dev->struct_mutex);
367
356 if (dev_priv->channel && !nouveau_nofbaccel) { 368 if (dev_priv->channel && !nouveau_nofbaccel) {
357 ret = -ENODEV; 369 ret = -ENODEV;
358 if (dev_priv->card_type < NV_50) 370 if (dev_priv->card_type < NV_50)
@@ -373,7 +385,6 @@ nouveau_fbcon_create(struct nouveau_fbdev *nfbdev,
373 nouveau_fb->base.height, 385 nouveau_fb->base.height,
374 nvbo->bo.offset, nvbo); 386 nvbo->bo.offset, nvbo);
375 387
376 mutex_unlock(&dev->struct_mutex);
377 vga_switcheroo_client_fb_set(dev->pdev, info); 388 vga_switcheroo_client_fb_set(dev->pdev, info);
378 return 0; 389 return 0;
379 390