Commit 6fbb702e authored by Ben Skeggs's avatar Ben Skeggs

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

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>
parent 634ffccc
...@@ -550,14 +550,12 @@ nouveau_display_destroy(struct drm_device *dev) ...@@ -550,14 +550,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;
...@@ -579,12 +577,13 @@ nouveau_display_suspend(struct drm_device *dev) ...@@ -579,12 +577,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;
...@@ -606,13 +605,6 @@ nouveau_display_repin(struct drm_device *dev) ...@@ -606,13 +605,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);
...@@ -627,6 +619,13 @@ nouveau_display_resume(struct drm_device *dev) ...@@ -627,6 +619,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) {
......
...@@ -63,9 +63,8 @@ int nouveau_display_create(struct drm_device *dev); ...@@ -63,9 +63,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,
......
...@@ -547,9 +547,11 @@ nouveau_do_suspend(struct drm_device *dev, bool runtime) ...@@ -547,9 +547,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;
} }
...@@ -603,7 +605,7 @@ nouveau_do_suspend(struct drm_device *dev, bool runtime) ...@@ -603,7 +605,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;
} }
...@@ -618,9 +620,6 @@ int nouveau_pmops_suspend(struct device *dev) ...@@ -618,9 +620,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;
...@@ -633,7 +632,7 @@ int nouveau_pmops_suspend(struct device *dev) ...@@ -633,7 +632,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;
...@@ -658,7 +657,9 @@ nouveau_do_resume(struct drm_device *dev) ...@@ -658,7 +657,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;
...@@ -681,47 +682,21 @@ int nouveau_pmops_resume(struct device *dev) ...@@ -681,47 +682,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;
} }
...@@ -977,7 +952,7 @@ static int nouveau_pmops_runtime_resume(struct device *dev) ...@@ -977,7 +952,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 */
nvif_mask(device, 0x88488, (1 << 25), (1 << 25)); nvif_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