Skip to content
This repository has been archived by the owner on Dec 14, 2022. It is now read-only.

Commit

Permalink
drm/nouveau: Handle fbcon suspend/resume in seperate worker
Browse files Browse the repository at this point in the history
[ Upstream commit 15266ae ]

Resuming from RPM can happen while already holding
dev->mode_config.mutex. This means we can't actually handle fbcon in
any RPM resume workers, since restoring fbcon requires grabbing
dev->mode_config.mutex again. So move the fbcon suspend/resume code into
it's own worker, and rely on that instead to avoid deadlocking.

This fixes more deadlocks for runtime suspending the GPU on the ThinkPad
W541. Reproduction recipe:

 - Get a machine with both optimus and a nvidia card with connectors
   attached to it
 - Wait for the nvidia GPU to suspend
 - Attempt to manually reprobe any of the connectors on the nvidia GPU
   using sysfs
 - *deadlock*

[airlied: use READ_ONCE to address Hans's comment]

Signed-off-by: Lyude <[email protected]>
Cc: Hans de Goede <[email protected]>
Cc: Kilian Singer <[email protected]>
Cc: Lukas Wunner <[email protected]>
Cc: David Airlie <[email protected]>
Signed-off-by: Dave Airlie <[email protected]>
Signed-off-by: Sasha Levin <[email protected]>
Signed-off-by: Greg Kroah-Hartman <[email protected]>
  • Loading branch information
Lyude authored and gregkh committed Jun 17, 2017
1 parent d2beb1a commit c7a29cf
Show file tree
Hide file tree
Showing 2 changed files with 36 additions and 9 deletions.
2 changes: 2 additions & 0 deletions drivers/gpu/drm/nouveau/nouveau_drv.h
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,8 @@ struct nouveau_drm {
struct nouveau_display *display;
struct backlight_device *backlight;
struct work_struct hpd_work;
struct work_struct fbcon_work;
int fbcon_new_state;
#ifdef CONFIG_ACPI
struct notifier_block acpi_nb;
#endif
Expand Down
43 changes: 34 additions & 9 deletions drivers/gpu/drm/nouveau/nouveau_fbcon.c
Original file line number Diff line number Diff line change
Expand Up @@ -491,19 +491,43 @@ static const struct drm_fb_helper_funcs nouveau_fbcon_helper_funcs = {
.fb_probe = nouveau_fbcon_create,
};

static void
nouveau_fbcon_set_suspend_work(struct work_struct *work)
{
struct nouveau_drm *drm = container_of(work, typeof(*drm), fbcon_work);
int state = READ_ONCE(drm->fbcon_new_state);

if (state == FBINFO_STATE_RUNNING)
pm_runtime_get_sync(drm->dev->dev);

console_lock();
if (state == FBINFO_STATE_RUNNING)
nouveau_fbcon_accel_restore(drm->dev);
drm_fb_helper_set_suspend(&drm->fbcon->helper, state);
if (state != FBINFO_STATE_RUNNING)
nouveau_fbcon_accel_save_disable(drm->dev);
console_unlock();

if (state == FBINFO_STATE_RUNNING) {
pm_runtime_mark_last_busy(drm->dev->dev);
pm_runtime_put_sync(drm->dev->dev);
}
}

void
nouveau_fbcon_set_suspend(struct drm_device *dev, int state)
{
struct nouveau_drm *drm = nouveau_drm(dev);
if (drm->fbcon) {
console_lock();
if (state == FBINFO_STATE_RUNNING)
nouveau_fbcon_accel_restore(dev);
drm_fb_helper_set_suspend(&drm->fbcon->helper, state);
if (state != FBINFO_STATE_RUNNING)
nouveau_fbcon_accel_save_disable(dev);
console_unlock();
}

if (!drm->fbcon)
return;

drm->fbcon_new_state = state;
/* Since runtime resume can happen as a result of a sysfs operation,
* it's possible we already have the console locked. So handle fbcon
* init/deinit from a seperate work thread
*/
schedule_work(&drm->fbcon_work);
}

int
Expand All @@ -524,6 +548,7 @@ nouveau_fbcon_init(struct drm_device *dev)

fbcon->dev = dev;
drm->fbcon = fbcon;
INIT_WORK(&drm->fbcon_work, nouveau_fbcon_set_suspend_work);

drm_fb_helper_prepare(dev, &fbcon->helper, &nouveau_fbcon_helper_funcs);

Expand Down

0 comments on commit c7a29cf

Please sign in to comment.