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>
This commit is contained in:
Родитель
ceed5f30bf
Коммит
6a6b73f254
|
@ -683,17 +683,24 @@ nouveau_bo_move_m2mf(struct ttm_buffer_object *bo, int evict, bool intr,
|
|||
int ret;
|
||||
|
||||
chan = nvbo->channel;
|
||||
if (!chan || nvbo->no_vm)
|
||||
if (!chan || nvbo->no_vm) {
|
||||
chan = dev_priv->channel;
|
||||
mutex_lock(&chan->mutex);
|
||||
}
|
||||
|
||||
if (dev_priv->card_type < NV_50)
|
||||
ret = nv04_bo_move_m2mf(chan, bo, &bo->mem, new_mem);
|
||||
else
|
||||
ret = nv50_bo_move_m2mf(chan, bo, &bo->mem, new_mem);
|
||||
if (ret)
|
||||
return ret;
|
||||
if (ret == 0) {
|
||||
ret = nouveau_bo_move_accel_cleanup(chan, nvbo, evict,
|
||||
no_wait_reserve,
|
||||
no_wait_gpu, new_mem);
|
||||
}
|
||||
|
||||
return nouveau_bo_move_accel_cleanup(chan, nvbo, evict, no_wait_reserve, no_wait_gpu, new_mem);
|
||||
if (chan == dev_priv->channel)
|
||||
mutex_unlock(&chan->mutex);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int
|
||||
|
|
|
@ -145,6 +145,7 @@ nouveau_channel_alloc(struct drm_device *dev, struct nouveau_channel **chan_ret,
|
|||
chan->file_priv = file_priv;
|
||||
chan->vram_handle = vram_handle;
|
||||
chan->gart_handle = tt_handle;
|
||||
mutex_init(&chan->mutex);
|
||||
|
||||
NV_INFO(dev, "Allocating FIFO number %d\n", channel);
|
||||
|
||||
|
|
|
@ -166,6 +166,8 @@ struct nouveau_channel {
|
|||
struct drm_device *dev;
|
||||
int id;
|
||||
|
||||
struct mutex mutex;
|
||||
|
||||
/* owner of this fifo */
|
||||
struct drm_file *file_priv;
|
||||
/* mapping of the fifo itself */
|
||||
|
|
|
@ -62,11 +62,13 @@ nouveau_fbcon_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
|
|||
|
||||
ret = -ENODEV;
|
||||
if (!in_interrupt() && !(info->flags & FBINFO_HWACCEL_DISABLED)) {
|
||||
mutex_lock(&dev_priv->channel->mutex);
|
||||
if (dev_priv->card_type < NV_50)
|
||||
ret = nv04_fbcon_fillrect(info, rect);
|
||||
else
|
||||
if (dev_priv->card_type < NV_C0)
|
||||
ret = nv50_fbcon_fillrect(info, rect);
|
||||
mutex_unlock(&dev_priv->channel->mutex);
|
||||
}
|
||||
|
||||
if (ret == 0)
|
||||
|
@ -90,11 +92,13 @@ nouveau_fbcon_copyarea(struct fb_info *info, const struct fb_copyarea *image)
|
|||
|
||||
ret = -ENODEV;
|
||||
if (!in_interrupt() && !(info->flags & FBINFO_HWACCEL_DISABLED)) {
|
||||
mutex_lock(&dev_priv->channel->mutex);
|
||||
if (dev_priv->card_type < NV_50)
|
||||
ret = nv04_fbcon_copyarea(info, image);
|
||||
else
|
||||
if (dev_priv->card_type < NV_C0)
|
||||
ret = nv50_fbcon_copyarea(info, image);
|
||||
mutex_unlock(&dev_priv->channel->mutex);
|
||||
}
|
||||
|
||||
if (ret == 0)
|
||||
|
@ -118,11 +122,13 @@ nouveau_fbcon_imageblit(struct fb_info *info, const struct fb_image *image)
|
|||
|
||||
ret = -ENODEV;
|
||||
if (!in_interrupt() && !(info->flags & FBINFO_HWACCEL_DISABLED)) {
|
||||
mutex_lock(&dev_priv->channel->mutex);
|
||||
if (dev_priv->card_type < NV_50)
|
||||
ret = nv04_fbcon_imageblit(info, image);
|
||||
else
|
||||
if (dev_priv->card_type < NV_C0)
|
||||
ret = nv50_fbcon_imageblit(info, image);
|
||||
mutex_unlock(&dev_priv->channel->mutex);
|
||||
}
|
||||
|
||||
if (ret == 0)
|
||||
|
@ -142,12 +148,15 @@ nouveau_fbcon_sync(struct fb_info *info)
|
|||
struct nouveau_channel *chan = dev_priv->channel;
|
||||
int ret, i;
|
||||
|
||||
if (!chan || !chan->accel_done ||
|
||||
if (!chan || !chan->accel_done || in_interrupt() ||
|
||||
info->state != FBINFO_STATE_RUNNING ||
|
||||
info->flags & FBINFO_HWACCEL_DISABLED)
|
||||
return 0;
|
||||
|
||||
if (RING_SPACE(chan, 4)) {
|
||||
mutex_lock(&chan->mutex);
|
||||
ret = RING_SPACE(chan, 4);
|
||||
if (ret) {
|
||||
mutex_unlock(&chan->mutex);
|
||||
nouveau_fbcon_gpu_lockup(info);
|
||||
return 0;
|
||||
}
|
||||
|
@ -158,6 +167,7 @@ nouveau_fbcon_sync(struct fb_info *info)
|
|||
OUT_RING(chan, 0);
|
||||
nouveau_bo_wr32(chan->notifier_bo, chan->m2mf_ntfy + 3, 0xffffffff);
|
||||
FIRE_RING(chan);
|
||||
mutex_unlock(&chan->mutex);
|
||||
|
||||
ret = -EBUSY;
|
||||
for (i = 0; i < 100000; i++) {
|
||||
|
@ -353,6 +363,8 @@ nouveau_fbcon_create(struct nouveau_fbdev *nfbdev,
|
|||
info->pixmap.flags = FB_PIXMAP_SYSTEM;
|
||||
info->pixmap.scan_align = 1;
|
||||
|
||||
mutex_unlock(&dev->struct_mutex);
|
||||
|
||||
if (dev_priv->channel && !nouveau_nofbaccel) {
|
||||
ret = -ENODEV;
|
||||
if (dev_priv->card_type < NV_50)
|
||||
|
@ -373,7 +385,6 @@ nouveau_fbcon_create(struct nouveau_fbdev *nfbdev,
|
|||
nouveau_fb->base.height,
|
||||
nvbo->bo.offset, nvbo);
|
||||
|
||||
mutex_unlock(&dev->struct_mutex);
|
||||
vga_switcheroo_client_fb_set(dev->pdev, info);
|
||||
return 0;
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче