diff options
| author | Ben Skeggs <bskeggs@redhat.com> | 2014-10-01 23:22:27 -0400 |
|---|---|---|
| committer | Ben Skeggs <bskeggs@redhat.com> | 2014-10-01 23:32:24 -0400 |
| commit | 6fbb702e27d78ad2458df048b58cca3454bc0965 (patch) | |
| tree | 0b231d0faa47f6ffd47302f83292f29b4150ed86 | |
| parent | 634ffcccfbe59d77652804e1beb415d3329b1bc6 (diff) | |
drm/nouveau: make sure display hardware is reinitialised on runtime resume
Linus commit 05c63c2ff23a80b654d6c088ac3ba21628db0173 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: Ben Skeggs <bskeggs@redhat.com>
| -rw-r--r-- | drivers/gpu/drm/nouveau/nouveau_display.c | 23 | ||||
| -rw-r--r-- | drivers/gpu/drm/nouveau/nouveau_display.h | 5 | ||||
| -rw-r--r-- | drivers/gpu/drm/nouveau/nouveau_drm.c | 51 |
3 files changed, 26 insertions, 53 deletions
diff --git a/drivers/gpu/drm/nouveau/nouveau_display.c b/drivers/gpu/drm/nouveau/nouveau_display.c index 65b4fd53dd4e..4a21b2b06ce2 100644 --- a/drivers/gpu/drm/nouveau/nouveau_display.c +++ b/drivers/gpu/drm/nouveau/nouveau_display.c | |||
| @@ -550,14 +550,12 @@ nouveau_display_destroy(struct drm_device *dev) | |||
| 550 | } | 550 | } |
| 551 | 551 | ||
| 552 | int | 552 | int |
| 553 | nouveau_display_suspend(struct drm_device *dev) | 553 | nouveau_display_suspend(struct drm_device *dev, bool runtime) |
| 554 | { | 554 | { |
| 555 | struct nouveau_drm *drm = nouveau_drm(dev); | ||
| 556 | struct drm_crtc *crtc; | 555 | struct drm_crtc *crtc; |
| 557 | 556 | ||
| 558 | nouveau_display_fini(dev); | 557 | nouveau_display_fini(dev); |
| 559 | 558 | ||
| 560 | NV_INFO(drm, "unpinning framebuffer(s)...\n"); | ||
| 561 | list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { | 559 | list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { |
| 562 | struct nouveau_framebuffer *nouveau_fb; | 560 | struct nouveau_framebuffer *nouveau_fb; |
| 563 | 561 | ||
| @@ -579,12 +577,13 @@ nouveau_display_suspend(struct drm_device *dev) | |||
| 579 | } | 577 | } |
| 580 | 578 | ||
| 581 | void | 579 | void |
| 582 | nouveau_display_repin(struct drm_device *dev) | 580 | nouveau_display_resume(struct drm_device *dev, bool runtime) |
| 583 | { | 581 | { |
| 584 | struct nouveau_drm *drm = nouveau_drm(dev); | 582 | struct nouveau_drm *drm = nouveau_drm(dev); |
| 585 | struct drm_crtc *crtc; | 583 | struct drm_crtc *crtc; |
| 586 | int ret; | 584 | int ret, head; |
| 587 | 585 | ||
| 586 | /* re-pin fb/cursors */ | ||
| 588 | list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { | 587 | list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { |
| 589 | struct nouveau_framebuffer *nouveau_fb; | 588 | struct nouveau_framebuffer *nouveau_fb; |
| 590 | 589 | ||
| @@ -606,13 +605,6 @@ nouveau_display_repin(struct drm_device *dev) | |||
| 606 | if (ret) | 605 | if (ret) |
| 607 | NV_ERROR(drm, "Could not pin/map cursor.\n"); | 606 | NV_ERROR(drm, "Could not pin/map cursor.\n"); |
| 608 | } | 607 | } |
| 609 | } | ||
| 610 | |||
| 611 | void | ||
| 612 | nouveau_display_resume(struct drm_device *dev) | ||
| 613 | { | ||
| 614 | struct drm_crtc *crtc; | ||
| 615 | int head; | ||
| 616 | 608 | ||
| 617 | nouveau_display_init(dev); | 609 | nouveau_display_init(dev); |
| 618 | 610 | ||
| @@ -627,6 +619,13 @@ nouveau_display_resume(struct drm_device *dev) | |||
| 627 | for (head = 0; head < dev->mode_config.num_crtc; head++) | 619 | for (head = 0; head < dev->mode_config.num_crtc; head++) |
| 628 | drm_vblank_on(dev, head); | 620 | drm_vblank_on(dev, head); |
| 629 | 621 | ||
| 622 | /* This should ensure we don't hit a locking problem when someone | ||
| 623 | * wakes us up via a connector. We should never go into suspend | ||
| 624 | * while the display is on anyways. | ||
| 625 | */ | ||
| 626 | if (runtime) | ||
| 627 | return; | ||
| 628 | |||
| 630 | drm_helper_resume_force_mode(dev); | 629 | drm_helper_resume_force_mode(dev); |
| 631 | 630 | ||
| 632 | list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { | 631 | list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { |
diff --git a/drivers/gpu/drm/nouveau/nouveau_display.h b/drivers/gpu/drm/nouveau/nouveau_display.h index 88ca177cb1c7..be3d5947c6be 100644 --- a/drivers/gpu/drm/nouveau/nouveau_display.h +++ b/drivers/gpu/drm/nouveau/nouveau_display.h | |||
| @@ -63,9 +63,8 @@ int nouveau_display_create(struct drm_device *dev); | |||
| 63 | void nouveau_display_destroy(struct drm_device *dev); | 63 | void nouveau_display_destroy(struct drm_device *dev); |
| 64 | int nouveau_display_init(struct drm_device *dev); | 64 | int nouveau_display_init(struct drm_device *dev); |
| 65 | void nouveau_display_fini(struct drm_device *dev); | 65 | void nouveau_display_fini(struct drm_device *dev); |
| 66 | int nouveau_display_suspend(struct drm_device *dev); | 66 | int nouveau_display_suspend(struct drm_device *dev, bool runtime); |
| 67 | void nouveau_display_repin(struct drm_device *dev); | 67 | void nouveau_display_resume(struct drm_device *dev, bool runtime); |
| 68 | void nouveau_display_resume(struct drm_device *dev); | ||
| 69 | int nouveau_display_vblank_enable(struct drm_device *, int); | 68 | int nouveau_display_vblank_enable(struct drm_device *, int); |
| 70 | void nouveau_display_vblank_disable(struct drm_device *, int); | 69 | void nouveau_display_vblank_disable(struct drm_device *, int); |
| 71 | int nouveau_display_scanoutpos(struct drm_device *, int, unsigned int, | 70 | int nouveau_display_scanoutpos(struct drm_device *, int, unsigned int, |
diff --git a/drivers/gpu/drm/nouveau/nouveau_drm.c b/drivers/gpu/drm/nouveau/nouveau_drm.c index 9c3af96a7153..3ed32dd90303 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drm.c +++ b/drivers/gpu/drm/nouveau/nouveau_drm.c | |||
| @@ -547,9 +547,11 @@ nouveau_do_suspend(struct drm_device *dev, bool runtime) | |||
| 547 | struct nouveau_cli *cli; | 547 | struct nouveau_cli *cli; |
| 548 | int ret; | 548 | int ret; |
| 549 | 549 | ||
| 550 | if (dev->mode_config.num_crtc && !runtime) { | 550 | if (dev->mode_config.num_crtc) { |
| 551 | NV_INFO(drm, "suspending console...\n"); | ||
| 552 | nouveau_fbcon_set_suspend(dev, 1); | ||
| 551 | NV_INFO(drm, "suspending display...\n"); | 553 | NV_INFO(drm, "suspending display...\n"); |
| 552 | ret = nouveau_display_suspend(dev); | 554 | ret = nouveau_display_suspend(dev, runtime); |
| 553 | if (ret) | 555 | if (ret) |
| 554 | return ret; | 556 | return ret; |
| 555 | } | 557 | } |
| @@ -603,7 +605,7 @@ fail_client: | |||
| 603 | fail_display: | 605 | fail_display: |
| 604 | if (dev->mode_config.num_crtc) { | 606 | if (dev->mode_config.num_crtc) { |
| 605 | NV_INFO(drm, "resuming display...\n"); | 607 | NV_INFO(drm, "resuming display...\n"); |
| 606 | nouveau_display_resume(dev); | 608 | nouveau_display_resume(dev, runtime); |
| 607 | } | 609 | } |
| 608 | return ret; | 610 | return ret; |
| 609 | } | 611 | } |
| @@ -618,9 +620,6 @@ int nouveau_pmops_suspend(struct device *dev) | |||
| 618 | drm_dev->switch_power_state == DRM_SWITCH_POWER_DYNAMIC_OFF) | 620 | drm_dev->switch_power_state == DRM_SWITCH_POWER_DYNAMIC_OFF) |
| 619 | return 0; | 621 | return 0; |
| 620 | 622 | ||
| 621 | if (drm_dev->mode_config.num_crtc) | ||
| 622 | nouveau_fbcon_set_suspend(drm_dev, 1); | ||
| 623 | |||
| 624 | ret = nouveau_do_suspend(drm_dev, false); | 623 | ret = nouveau_do_suspend(drm_dev, false); |
| 625 | if (ret) | 624 | if (ret) |
| 626 | return ret; | 625 | return ret; |
| @@ -633,7 +632,7 @@ int nouveau_pmops_suspend(struct device *dev) | |||
| 633 | } | 632 | } |
| 634 | 633 | ||
| 635 | static int | 634 | static int |
| 636 | nouveau_do_resume(struct drm_device *dev) | 635 | nouveau_do_resume(struct drm_device *dev, bool runtime) |
| 637 | { | 636 | { |
| 638 | struct nouveau_drm *drm = nouveau_drm(dev); | 637 | struct nouveau_drm *drm = nouveau_drm(dev); |
| 639 | struct nouveau_cli *cli; | 638 | struct nouveau_cli *cli; |
| @@ -658,7 +657,9 @@ nouveau_do_resume(struct drm_device *dev) | |||
| 658 | 657 | ||
| 659 | if (dev->mode_config.num_crtc) { | 658 | if (dev->mode_config.num_crtc) { |
| 660 | NV_INFO(drm, "resuming display...\n"); | 659 | NV_INFO(drm, "resuming display...\n"); |
| 661 | nouveau_display_repin(dev); | 660 | nouveau_display_resume(dev, runtime); |
| 661 | NV_INFO(drm, "resuming console...\n"); | ||
| 662 | nouveau_fbcon_set_suspend(dev, 0); | ||
| 662 | } | 663 | } |
| 663 | 664 | ||
| 664 | return 0; | 665 | return 0; |
| @@ -681,47 +682,21 @@ int nouveau_pmops_resume(struct device *dev) | |||
| 681 | return ret; | 682 | return ret; |
| 682 | pci_set_master(pdev); | 683 | pci_set_master(pdev); |
| 683 | 684 | ||
| 684 | ret = nouveau_do_resume(drm_dev); | 685 | return nouveau_do_resume(drm_dev, false); |
| 685 | if (ret) | ||
| 686 | return ret; | ||
| 687 | |||
| 688 | if (drm_dev->mode_config.num_crtc) { | ||
| 689 | nouveau_display_resume(drm_dev); | ||
| 690 | nouveau_fbcon_set_suspend(drm_dev, 0); | ||
| 691 | } | ||
| 692 | |||
| 693 | return 0; | ||
| 694 | } | 686 | } |
| 695 | 687 | ||
| 696 | static int nouveau_pmops_freeze(struct device *dev) | 688 | static int nouveau_pmops_freeze(struct device *dev) |
| 697 | { | 689 | { |
| 698 | struct pci_dev *pdev = to_pci_dev(dev); | 690 | struct pci_dev *pdev = to_pci_dev(dev); |
| 699 | struct drm_device *drm_dev = pci_get_drvdata(pdev); | 691 | struct drm_device *drm_dev = pci_get_drvdata(pdev); |
| 700 | int ret; | 692 | return nouveau_do_suspend(drm_dev, false); |
| 701 | |||
| 702 | if (drm_dev->mode_config.num_crtc) | ||
| 703 | nouveau_fbcon_set_suspend(drm_dev, 1); | ||
| 704 | |||
| 705 | ret = nouveau_do_suspend(drm_dev, false); | ||
| 706 | return ret; | ||
| 707 | } | 693 | } |
| 708 | 694 | ||
| 709 | static int nouveau_pmops_thaw(struct device *dev) | 695 | static int nouveau_pmops_thaw(struct device *dev) |
| 710 | { | 696 | { |
| 711 | struct pci_dev *pdev = to_pci_dev(dev); | 697 | struct pci_dev *pdev = to_pci_dev(dev); |
| 712 | struct drm_device *drm_dev = pci_get_drvdata(pdev); | 698 | struct drm_device *drm_dev = pci_get_drvdata(pdev); |
| 713 | int ret; | 699 | return nouveau_do_resume(drm_dev, false); |
| 714 | |||
| 715 | ret = nouveau_do_resume(drm_dev); | ||
| 716 | if (ret) | ||
| 717 | return ret; | ||
| 718 | |||
| 719 | if (drm_dev->mode_config.num_crtc) { | ||
| 720 | nouveau_display_resume(drm_dev); | ||
| 721 | nouveau_fbcon_set_suspend(drm_dev, 0); | ||
| 722 | } | ||
| 723 | |||
| 724 | return 0; | ||
| 725 | } | 700 | } |
| 726 | 701 | ||
| 727 | 702 | ||
| @@ -977,7 +952,7 @@ static int nouveau_pmops_runtime_resume(struct device *dev) | |||
| 977 | return ret; | 952 | return ret; |
| 978 | pci_set_master(pdev); | 953 | pci_set_master(pdev); |
| 979 | 954 | ||
| 980 | ret = nouveau_do_resume(drm_dev); | 955 | ret = nouveau_do_resume(drm_dev, true); |
| 981 | drm_kms_helper_poll_enable(drm_dev); | 956 | drm_kms_helper_poll_enable(drm_dev); |
| 982 | /* do magic */ | 957 | /* do magic */ |
| 983 | nvif_mask(device, 0x88488, (1 << 25), (1 << 25)); | 958 | nvif_mask(device, 0x88488, (1 << 25), (1 << 25)); |
