Commit 2158205a authored by Ben Skeggs's avatar Ben Skeggs Committed by Luis Henriques

drm/nouveau: make sure display hardware is reinitialised on runtime resume

commit 6fbb702e upstream.

Linus commit 05c63c2f modified the
runtime suspend/resume paths to skip over display-related tasks to
avoid locking issues on resume.

Unfortunately, this resulted in the display hardware being left in
a partially initialised state, preventing subsequent modesets from
completing.

This commit unifies the (many) suspend/resume paths, bringing back
display (and fbcon) handling in the runtime paths.
Signed-off-by: default avatarBen Skeggs <bskeggs@redhat.com>
Cc: Sven Joachim <svenjoac@gmx.de>
Signed-off-by: default avatarLuis Henriques <luis.henriques@canonical.com>
parent e909d634
......@@ -565,14 +565,12 @@ nouveau_display_destroy(struct drm_device *dev)
}
int
nouveau_display_suspend(struct drm_device *dev)
nouveau_display_suspend(struct drm_device *dev, bool runtime)
{
struct nouveau_drm *drm = nouveau_drm(dev);
struct drm_crtc *crtc;
nouveau_display_fini(dev);
NV_INFO(drm, "unpinning framebuffer(s)...\n");
list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
struct nouveau_framebuffer *nouveau_fb;
......@@ -594,12 +592,13 @@ nouveau_display_suspend(struct drm_device *dev)
}
void
nouveau_display_repin(struct drm_device *dev)
nouveau_display_resume(struct drm_device *dev, bool runtime)
{
struct nouveau_drm *drm = nouveau_drm(dev);
struct drm_crtc *crtc;
int ret;
int ret, head;
/* re-pin fb/cursors */
list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
struct nouveau_framebuffer *nouveau_fb;
......@@ -619,13 +618,6 @@ nouveau_display_repin(struct drm_device *dev)
if (ret)
NV_ERROR(drm, "Could not pin/map cursor.\n");
}
}
void
nouveau_display_resume(struct drm_device *dev)
{
struct drm_crtc *crtc;
int head;
nouveau_display_init(dev);
......@@ -640,6 +632,13 @@ nouveau_display_resume(struct drm_device *dev)
for (head = 0; head < dev->mode_config.num_crtc; head++)
drm_vblank_on(dev, head);
/* This should ensure we don't hit a locking problem when someone
* wakes us up via a connector. We should never go into suspend
* while the display is on anyways.
*/
if (runtime)
return;
drm_helper_resume_force_mode(dev);
list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
......
......@@ -59,9 +59,8 @@ int nouveau_display_create(struct drm_device *dev);
void nouveau_display_destroy(struct drm_device *dev);
int nouveau_display_init(struct drm_device *dev);
void nouveau_display_fini(struct drm_device *dev);
int nouveau_display_suspend(struct drm_device *dev);
void nouveau_display_repin(struct drm_device *dev);
void nouveau_display_resume(struct drm_device *dev);
int nouveau_display_suspend(struct drm_device *dev, bool runtime);
void nouveau_display_resume(struct drm_device *dev, bool runtime);
int nouveau_display_vblank_enable(struct drm_device *, int);
void nouveau_display_vblank_disable(struct drm_device *, int);
int nouveau_display_scanoutpos(struct drm_device *, int, unsigned int,
......
......@@ -516,9 +516,11 @@ nouveau_do_suspend(struct drm_device *dev, bool runtime)
struct nouveau_cli *cli;
int ret;
if (dev->mode_config.num_crtc && !runtime) {
if (dev->mode_config.num_crtc) {
NV_INFO(drm, "suspending console...\n");
nouveau_fbcon_set_suspend(dev, 1);
NV_INFO(drm, "suspending display...\n");
ret = nouveau_display_suspend(dev);
ret = nouveau_display_suspend(dev, runtime);
if (ret)
return ret;
}
......@@ -572,7 +574,7 @@ nouveau_do_suspend(struct drm_device *dev, bool runtime)
fail_display:
if (dev->mode_config.num_crtc) {
NV_INFO(drm, "resuming display...\n");
nouveau_display_resume(dev);
nouveau_display_resume(dev, runtime);
}
return ret;
}
......@@ -587,9 +589,6 @@ int nouveau_pmops_suspend(struct device *dev)
drm_dev->switch_power_state == DRM_SWITCH_POWER_DYNAMIC_OFF)
return 0;
if (drm_dev->mode_config.num_crtc)
nouveau_fbcon_set_suspend(drm_dev, 1);
ret = nouveau_do_suspend(drm_dev, false);
if (ret)
return ret;
......@@ -602,7 +601,7 @@ int nouveau_pmops_suspend(struct device *dev)
}
static int
nouveau_do_resume(struct drm_device *dev)
nouveau_do_resume(struct drm_device *dev, bool runtime)
{
struct nouveau_drm *drm = nouveau_drm(dev);
struct nouveau_cli *cli;
......@@ -627,7 +626,9 @@ nouveau_do_resume(struct drm_device *dev)
if (dev->mode_config.num_crtc) {
NV_INFO(drm, "resuming display...\n");
nouveau_display_repin(dev);
nouveau_display_resume(dev, runtime);
NV_INFO(drm, "resuming console...\n");
nouveau_fbcon_set_suspend(dev, 0);
}
return 0;
......@@ -650,47 +651,21 @@ int nouveau_pmops_resume(struct device *dev)
return ret;
pci_set_master(pdev);
ret = nouveau_do_resume(drm_dev);
if (ret)
return ret;
if (drm_dev->mode_config.num_crtc) {
nouveau_display_resume(drm_dev);
nouveau_fbcon_set_suspend(drm_dev, 0);
}
return 0;
return nouveau_do_resume(drm_dev, false);
}
static int nouveau_pmops_freeze(struct device *dev)
{
struct pci_dev *pdev = to_pci_dev(dev);
struct drm_device *drm_dev = pci_get_drvdata(pdev);
int ret;
if (drm_dev->mode_config.num_crtc)
nouveau_fbcon_set_suspend(drm_dev, 1);
ret = nouveau_do_suspend(drm_dev, false);
return ret;
return nouveau_do_suspend(drm_dev, false);
}
static int nouveau_pmops_thaw(struct device *dev)
{
struct pci_dev *pdev = to_pci_dev(dev);
struct drm_device *drm_dev = pci_get_drvdata(pdev);
int ret;
ret = nouveau_do_resume(drm_dev);
if (ret)
return ret;
if (drm_dev->mode_config.num_crtc) {
nouveau_display_resume(drm_dev);
nouveau_fbcon_set_suspend(drm_dev, 0);
}
return 0;
return nouveau_do_resume(drm_dev, false);
}
......@@ -934,7 +909,7 @@ static int nouveau_pmops_runtime_resume(struct device *dev)
return ret;
pci_set_master(pdev);
ret = nouveau_do_resume(drm_dev);
ret = nouveau_do_resume(drm_dev, true);
drm_kms_helper_poll_enable(drm_dev);
/* do magic */
nv_mask(device, 0x88488, (1 << 25), (1 << 25));
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment