History

drm/nouveau: punt fbcon resume out to a workqueue

Preparation for some runtime pm fixes. Currently we skip over fbcon suspend/resume in the runtime path, which causes issues on resume if fbcon tries to write to the framebuffer before the BAR subdev has been resumed to restore the BAR1 VM setup. As we might be woken up via a sysfs connector, we are unable to call fb_set_suspend() in the resume path as it could make its way down to a modeset and cause all sorts of locking hilarity. To solve this, we'll just delay the fbcon resume to a workqueue.

Ben Skeggs committed 12 years ago

Commit 634ffcc1 parent f2f9a2c2 files · +18 −6Browse files

Unified · Split

2 files
  1. drivers/gpu/drm/nouveau/nouveau_fbcon.c +17 −6
  2. drivers/gpu/drm/nouveau/nouveau_fbcon.h +1 −0
drivers/gpu/drm/nouveau/nouveau_fbcon.c+17−6
@@ -486,6 +486,16 @@ static const struct drm_fb_helper_funcs nouveau_fbcon_helper_funcs = { · 485 unmodified lines
486486 .fb_probe = nouveau_fbcon_create,
487487 };
488488
489+static void
490+nouveau_fbcon_set_suspend_work(struct work_struct *work)
491+{
492+ struct nouveau_fbdev *fbcon = container_of(work, typeof(*fbcon), work);
493+ console_lock();
494+ nouveau_fbcon_accel_restore(fbcon->dev);
495+ nouveau_fbcon_zfill(fbcon->dev, fbcon);
496+ fb_set_suspend(fbcon->helper.fbdev, FBINFO_STATE_RUNNING);
497+ console_unlock();
498+}
489499
490500 int
491501 nouveau_fbcon_init(struct drm_device *dev)
@@ -503,6 +513,7 @@ nouveau_fbcon_init(struct drm_device *dev) · 11 unmodified lines
503513 if (!fbcon)
504514 return -ENOMEM;
505515
516+ INIT_WORK(&fbcon->work, nouveau_fbcon_set_suspend_work);
506517 fbcon->dev = dev;
507518 drm->fbcon = fbcon;
508519
@@ -551,14 +562,14 @@ nouveau_fbcon_set_suspend(struct drm_device *dev, int state) · 42 unmodified lines
551562 {
552563 struct nouveau_drm *drm = nouveau_drm(dev);
553564 if (drm->fbcon) {
554− console_lock();
555− if (state == 0) {
556− nouveau_fbcon_accel_restore(dev);
557− nouveau_fbcon_zfill(dev, drm->fbcon);
565+ if (state == FBINFO_STATE_RUNNING) {
566+ schedule_work(&drm->fbcon->work);
567+ return;
558568 }
569+ flush_work(&drm->fbcon->work);
570+ console_lock();
559571 fb_set_suspend(drm->fbcon->helper.fbdev, state);
560− if (state == 1)
561− nouveau_fbcon_accel_save_disable(dev);
572+ nouveau_fbcon_accel_save_disable(dev);
562573 console_unlock();
563574 }
564575 }
drivers/gpu/drm/nouveau/nouveau_fbcon.h+1−0
@@ -36,6 +36,7 @@ struct nouveau_fbdev { · 35 unmodified lines
3636 struct nouveau_framebuffer nouveau_fb;
3737 struct list_head fbdev_list;
3838 struct drm_device *dev;
39+ struct work_struct work;
3940 unsigned int saved_flags;
4041 struct nvif_object surf2d;
4142 struct nvif_object clip;