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) ...@@ -565,14 +565,12 @@ nouveau_display_destroy(struct drm_device *dev)
} }
int 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; struct drm_crtc *crtc;
nouveau_display_fini(dev); nouveau_display_fini(dev);
NV_INFO(drm, "unpinning framebuffer(s)...\n");
list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
struct nouveau_framebuffer *nouveau_fb; struct nouveau_framebuffer *nouveau_fb;
...@@ -594,12 +592,13 @@ nouveau_display_suspend(struct drm_device *dev) ...@@ -594,12 +592,13 @@ nouveau_display_suspend(struct drm_device *dev)
} }
void 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 nouveau_drm *drm = nouveau_drm(dev);
struct drm_crtc *crtc; struct drm_crtc *crtc;
int ret; int ret, head;
/* re-pin fb/cursors */
list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
struct nouveau_framebuffer *nouveau_fb; struct nouveau_framebuffer *nouveau_fb;
...@@ -619,13 +618,6 @@ nouveau_display_repin(struct drm_device *dev) ...@@ -619,13 +618,6 @@ nouveau_display_repin(struct drm_device *dev)
if (ret) if (ret)
NV_ERROR(drm, "Could not pin/map cursor.\n"); 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); nouveau_display_init(dev);
...@@ -640,6 +632,13 @@ nouveau_display_resume(struct drm_device *dev) ...@@ -640,6 +632,13 @@ nouveau_display_resume(struct drm_device *dev)
for (head = 0; head < dev->mode_config.num_crtc; head++) for (head = 0; head < dev->mode_config.num_crtc; head++)
drm_vblank_on(dev, 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); drm_helper_resume_force_mode(dev);
list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
......
...@@ -59,9 +59,8 @@ int nouveau_display_create(struct drm_device *dev); ...@@ -59,9 +59,8 @@ int nouveau_display_create(struct drm_device *dev);
void nouveau_display_destroy(struct drm_device *dev); void nouveau_display_destroy(struct drm_device *dev);
int nouveau_display_init(struct drm_device *dev); int nouveau_display_init(struct drm_device *dev);
void nouveau_display_fini(struct drm_device *dev); void nouveau_display_fini(struct drm_device *dev);
int nouveau_display_suspend(struct drm_device *dev); int nouveau_display_suspend(struct drm_device *dev, bool runtime);
void nouveau_display_repin(struct drm_device *dev); void nouveau_display_resume(struct drm_device *dev, bool runtime);
void nouveau_display_resume(struct drm_device *dev);
int nouveau_display_vblank_enable(struct drm_device *, int); int nouveau_display_vblank_enable(struct drm_device *, int);
void nouveau_display_vblank_disable(struct drm_device *, int); void nouveau_display_vblank_disable(struct drm_device *, int);
int nouveau_display_scanoutpos(struct drm_device *, int, unsigned int, int nouveau_display_scanoutpos(struct drm_device *, int, unsigned int,
......
...@@ -516,9 +516,11 @@ nouveau_do_suspend(struct drm_device *dev, bool runtime) ...@@ -516,9 +516,11 @@ nouveau_do_suspend(struct drm_device *dev, bool runtime)
struct nouveau_cli *cli; struct nouveau_cli *cli;
int ret; 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"); NV_INFO(drm, "suspending display...\n");
ret = nouveau_display_suspend(dev); ret = nouveau_display_suspend(dev, runtime);
if (ret) if (ret)
return ret; return ret;
} }
...@@ -572,7 +574,7 @@ nouveau_do_suspend(struct drm_device *dev, bool runtime) ...@@ -572,7 +574,7 @@ nouveau_do_suspend(struct drm_device *dev, bool runtime)
fail_display: fail_display:
if (dev->mode_config.num_crtc) { if (dev->mode_config.num_crtc) {
NV_INFO(drm, "resuming display...\n"); NV_INFO(drm, "resuming display...\n");
nouveau_display_resume(dev); nouveau_display_resume(dev, runtime);
} }
return ret; return ret;
} }
...@@ -587,9 +589,6 @@ int nouveau_pmops_suspend(struct device *dev) ...@@ -587,9 +589,6 @@ int nouveau_pmops_suspend(struct device *dev)
drm_dev->switch_power_state == DRM_SWITCH_POWER_DYNAMIC_OFF) drm_dev->switch_power_state == DRM_SWITCH_POWER_DYNAMIC_OFF)
return 0; return 0;
if (drm_dev->mode_config.num_crtc)
nouveau_fbcon_set_suspend(drm_dev, 1);
ret = nouveau_do_suspend(drm_dev, false); ret = nouveau_do_suspend(drm_dev, false);
if (ret) if (ret)
return ret; return ret;
...@@ -602,7 +601,7 @@ int nouveau_pmops_suspend(struct device *dev) ...@@ -602,7 +601,7 @@ int nouveau_pmops_suspend(struct device *dev)
} }
static int 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_drm *drm = nouveau_drm(dev);
struct nouveau_cli *cli; struct nouveau_cli *cli;
...@@ -627,7 +626,9 @@ nouveau_do_resume(struct drm_device *dev) ...@@ -627,7 +626,9 @@ nouveau_do_resume(struct drm_device *dev)
if (dev->mode_config.num_crtc) { if (dev->mode_config.num_crtc) {
NV_INFO(drm, "resuming display...\n"); 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; return 0;
...@@ -650,47 +651,21 @@ int nouveau_pmops_resume(struct device *dev) ...@@ -650,47 +651,21 @@ int nouveau_pmops_resume(struct device *dev)
return ret; return ret;
pci_set_master(pdev); pci_set_master(pdev);
ret = nouveau_do_resume(drm_dev); return nouveau_do_resume(drm_dev, false);
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;
} }
static int nouveau_pmops_freeze(struct device *dev) static int nouveau_pmops_freeze(struct device *dev)
{ {
struct pci_dev *pdev = to_pci_dev(dev); struct pci_dev *pdev = to_pci_dev(dev);
struct drm_device *drm_dev = pci_get_drvdata(pdev); struct drm_device *drm_dev = pci_get_drvdata(pdev);
int ret; return nouveau_do_suspend(drm_dev, false);
if (drm_dev->mode_config.num_crtc)
nouveau_fbcon_set_suspend(drm_dev, 1);
ret = nouveau_do_suspend(drm_dev, false);
return ret;
} }
static int nouveau_pmops_thaw(struct device *dev) static int nouveau_pmops_thaw(struct device *dev)
{ {
struct pci_dev *pdev = to_pci_dev(dev); struct pci_dev *pdev = to_pci_dev(dev);
struct drm_device *drm_dev = pci_get_drvdata(pdev); struct drm_device *drm_dev = pci_get_drvdata(pdev);
int ret; return nouveau_do_resume(drm_dev, false);
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;
} }
...@@ -934,7 +909,7 @@ static int nouveau_pmops_runtime_resume(struct device *dev) ...@@ -934,7 +909,7 @@ static int nouveau_pmops_runtime_resume(struct device *dev)
return ret; return ret;
pci_set_master(pdev); pci_set_master(pdev);
ret = nouveau_do_resume(drm_dev); ret = nouveau_do_resume(drm_dev, true);
drm_kms_helper_poll_enable(drm_dev); drm_kms_helper_poll_enable(drm_dev);
/* do magic */ /* do magic */
nv_mask(device, 0x88488, (1 << 25), (1 << 25)); 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