diff options
author | Zhang Rui <rui.zhang@intel.com> | 2013-02-05 02:41:53 -0500 |
---|---|---|
committer | Daniel Vetter <daniel.vetter@ffwll.ch> | 2013-02-13 18:47:51 -0500 |
commit | b8efb17b3d687695b81485f606fc4e6c35a50f9a (patch) | |
tree | 146a7df21a8ab0709ea8c58741af4ed6e4215c89 | |
parent | 7083e05072b88d503d257b6f012ce56367f3ac97 (diff) |
i915: ignore lid open event when resuming
i915 driver needs to do modeset when
1. system resumes from sleep
2. lid is opened
In PM_SUSPEND_MEM state, all the GPEs are cleared when system resumes,
thus it is the i915_resume code does the modeset rather than intel_lid_notify().
But in PM_SUSPEND_FREEZE state, this will be broken because
system is still responsive to the lid events.
1. When we close the lid in Freeze state, intel_lid_notify() sets modeset_on_lid.
2. When we reopen the lid, intel_lid_notify() will do a modeset,
before the system is resumed.
here is the error log,
[92146.548074] WARNING: at drivers/gpu/drm/i915/intel_display.c:1028 intel_wait_for_pipe_off+0x184/0x190 [i915]()
[92146.548076] Hardware name: VGN-Z540N
[92146.548078] pipe_off wait timed out
[92146.548167] Modules linked in: hid_generic usbhid hid snd_hda_codec_realtek snd_hda_intel snd_hda_codec parport_pc snd_hwdep ppdev snd_pcm_oss i915 snd_mixer_oss snd_pcm arc4 iwldvm snd_seq_dummy mac80211 snd_seq_oss snd_seq_midi fbcon tileblit font bitblit softcursor drm_kms_helper snd_rawmidi snd_seq_midi_event coretemp drm snd_seq kvm btusb bluetooth snd_timer iwlwifi pcmcia tpm_infineon i2c_algo_bit joydev snd_seq_device intel_agp cfg80211 snd intel_gtt yenta_socket pcmcia_rsrc sony_laptop agpgart microcode psmouse tpm_tis serio_raw mxm_wmi soundcore snd_page_alloc tpm acpi_cpufreq lpc_ich pcmcia_core tpm_bios mperf processor lp parport firewire_ohci firewire_core crc_itu_t sdhci_pci sdhci thermal e1000e
[92146.548173] Pid: 4304, comm: kworker/0:0 Tainted: G W 3.8.0-rc3-s0i3-v3-test+ #9
[92146.548175] Call Trace:
[92146.548189] [<c10378e2>] warn_slowpath_common+0x72/0xa0
[92146.548227] [<f86398b4>] ? intel_wait_for_pipe_off+0x184/0x190 [i915]
[92146.548263] [<f86398b4>] ? intel_wait_for_pipe_off+0x184/0x190 [i915]
[92146.548270] [<c10379b3>] warn_slowpath_fmt+0x33/0x40
[92146.548307] [<f86398b4>] intel_wait_for_pipe_off+0x184/0x190 [i915]
[92146.548344] [<f86399c2>] intel_disable_pipe+0x102/0x190 [i915]
[92146.548380] [<f8639ea4>] ? intel_disable_plane+0x64/0x80 [i915]
[92146.548417] [<f8639f7c>] i9xx_crtc_disable+0xbc/0x150 [i915]
[92146.548456] [<f863ebee>] intel_crtc_update_dpms+0x5e/0x90 [i915]
[92146.548493] [<f86437cf>] intel_modeset_setup_hw_state+0x42f/0x8f0 [i915]
[92146.548535] [<f8645b0b>] intel_lid_notify+0x9b/0xc0 [i915]
[92146.548543] [<c15610d3>] notifier_call_chain+0x43/0x60
[92146.548550] [<c105d1e1>] __blocking_notifier_call_chain+0x41/0x80
[92146.548556] [<c105d23f>] blocking_notifier_call_chain+0x1f/0x30
[92146.548563] [<c131a684>] acpi_lid_send_state+0x78/0xa4
[92146.548569] [<c131aa9e>] acpi_button_notify+0x3b/0xf1
[92146.548577] [<c12df56a>] ? acpi_os_execute+0x17/0x19
[92146.548582] [<c12e591a>] ? acpi_ec_sync_query+0xa5/0xbc
[92146.548589] [<c12e2b82>] acpi_device_notify+0x16/0x18
[92146.548595] [<c12f4904>] acpi_ev_notify_dispatch+0x38/0x4f
[92146.548600] [<c12df0e8>] acpi_os_execute_deferred+0x20/0x2b
[92146.548607] [<c1051208>] process_one_work+0x128/0x3f0
[92146.548613] [<c1564f73>] ? common_interrupt+0x33/0x38
[92146.548618] [<c104f8c0>] ? wake_up_worker+0x30/0x30
[92146.548624] [<c12df0c8>] ? acpi_os_wait_events_complete+0x1e/0x1e
[92146.548629] [<c10524f9>] worker_thread+0x119/0x3b0
[92146.548634] [<c10523e0>] ? manage_workers+0x240/0x240
[92146.548640] [<c1056e84>] kthread+0x94/0xa0
[92146.548647] [<c1060000>] ? ftrace_raw_output_sched_stat_runtime+0x70/0xf0
[92146.548652] [<c15649b7>] ret_from_kernel_thread+0x1b/0x28
[92146.548658] [<c1056df0>] ? kthread_create_on_node+0xc0/0xc0
three different modeset flags are introduced in this patch
MODESET_ON_LID_OPEN: do modeset on next lid open event
MODESET_DONE: modeset already done
MODESET_SUSPENDED: suspended, only do modeset when system is resumed
In this way,
1. when lid is closed, MODESET_ON_LID_OPEN is set so that
we'll do modeset on next lid open event.
2. when lid is opened, MODESET_DONE is set
so that duplicate lid open events will be ignored.
3. when system suspends, MODESET_SUSPENDED is set.
In this case, we will not do modeset on any lid events.
Plus, locking mechanism is also introduced to avoid racing.
Signed-off-by: Zhang Rui <rui.zhang@intel.com>
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
-rw-r--r-- | drivers/gpu/drm/i915/i915_dma.c | 1 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/i915_drv.c | 13 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/i915_drv.h | 10 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/intel_lvds.c | 33 |
4 files changed, 37 insertions, 20 deletions
diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index cf0610330135..4fa6beb14c77 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c | |||
@@ -1610,6 +1610,7 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags) | |||
1610 | mutex_init(&dev_priv->dpio_lock); | 1610 | mutex_init(&dev_priv->dpio_lock); |
1611 | 1611 | ||
1612 | mutex_init(&dev_priv->rps.hw_lock); | 1612 | mutex_init(&dev_priv->rps.hw_lock); |
1613 | mutex_init(&dev_priv->modeset_restore_lock); | ||
1613 | 1614 | ||
1614 | if (IS_IVYBRIDGE(dev) || IS_HASWELL(dev)) | 1615 | if (IS_IVYBRIDGE(dev) || IS_HASWELL(dev)) |
1615 | dev_priv->num_pipe = 3; | 1616 | dev_priv->num_pipe = 3; |
diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index d159d7a402e9..c5b8c81b9440 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c | |||
@@ -470,6 +470,11 @@ static int i915_drm_freeze(struct drm_device *dev) | |||
470 | { | 470 | { |
471 | struct drm_i915_private *dev_priv = dev->dev_private; | 471 | struct drm_i915_private *dev_priv = dev->dev_private; |
472 | 472 | ||
473 | /* ignore lid events during suspend */ | ||
474 | mutex_lock(&dev_priv->modeset_restore_lock); | ||
475 | dev_priv->modeset_restore = MODESET_SUSPENDED; | ||
476 | mutex_unlock(&dev_priv->modeset_restore_lock); | ||
477 | |||
473 | intel_set_power_well(dev, true); | 478 | intel_set_power_well(dev, true); |
474 | 479 | ||
475 | drm_kms_helper_poll_disable(dev); | 480 | drm_kms_helper_poll_disable(dev); |
@@ -496,9 +501,6 @@ static int i915_drm_freeze(struct drm_device *dev) | |||
496 | 501 | ||
497 | intel_opregion_fini(dev); | 502 | intel_opregion_fini(dev); |
498 | 503 | ||
499 | /* Modeset on resume, not lid events */ | ||
500 | dev_priv->modeset_on_lid = 0; | ||
501 | |||
502 | console_lock(); | 504 | console_lock(); |
503 | intel_fbdev_set_suspend(dev, 1); | 505 | intel_fbdev_set_suspend(dev, 1); |
504 | console_unlock(); | 506 | console_unlock(); |
@@ -574,8 +576,6 @@ static int __i915_drm_thaw(struct drm_device *dev) | |||
574 | 576 | ||
575 | intel_opregion_init(dev); | 577 | intel_opregion_init(dev); |
576 | 578 | ||
577 | dev_priv->modeset_on_lid = 0; | ||
578 | |||
579 | /* | 579 | /* |
580 | * The console lock can be pretty contented on resume due | 580 | * The console lock can be pretty contented on resume due |
581 | * to all the printk activity. Try to keep it out of the hot | 581 | * to all the printk activity. Try to keep it out of the hot |
@@ -588,6 +588,9 @@ static int __i915_drm_thaw(struct drm_device *dev) | |||
588 | schedule_work(&dev_priv->console_resume_work); | 588 | schedule_work(&dev_priv->console_resume_work); |
589 | } | 589 | } |
590 | 590 | ||
591 | mutex_lock(&dev_priv->modeset_restore_lock); | ||
592 | dev_priv->modeset_restore = MODESET_DONE; | ||
593 | mutex_unlock(&dev_priv->modeset_restore_lock); | ||
591 | return error; | 594 | return error; |
592 | } | 595 | } |
593 | 596 | ||
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index c338b4443fd9..4e5a3776a3ea 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h | |||
@@ -846,6 +846,12 @@ struct i915_gpu_error { | |||
846 | unsigned int stop_rings; | 846 | unsigned int stop_rings; |
847 | }; | 847 | }; |
848 | 848 | ||
849 | enum modeset_restore { | ||
850 | MODESET_ON_LID_OPEN, | ||
851 | MODESET_DONE, | ||
852 | MODESET_SUSPENDED, | ||
853 | }; | ||
854 | |||
849 | typedef struct drm_i915_private { | 855 | typedef struct drm_i915_private { |
850 | struct drm_device *dev; | 856 | struct drm_device *dev; |
851 | struct kmem_cache *slab; | 857 | struct kmem_cache *slab; |
@@ -967,8 +973,8 @@ typedef struct drm_i915_private { | |||
967 | 973 | ||
968 | unsigned long quirks; | 974 | unsigned long quirks; |
969 | 975 | ||
970 | /* Register state */ | 976 | enum modeset_restore modeset_restore; |
971 | bool modeset_on_lid; | 977 | struct mutex modeset_restore_lock; |
972 | 978 | ||
973 | struct i915_gtt gtt; | 979 | struct i915_gtt gtt; |
974 | 980 | ||
diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c index 5e3f08e3fd8b..bff78a3ec37b 100644 --- a/drivers/gpu/drm/i915/intel_lvds.c +++ b/drivers/gpu/drm/i915/intel_lvds.c | |||
@@ -547,13 +547,14 @@ static const struct dmi_system_id intel_no_modeset_on_lid[] = { | |||
547 | }; | 547 | }; |
548 | 548 | ||
549 | /* | 549 | /* |
550 | * Lid events. Note the use of 'modeset_on_lid': | 550 | * Lid events. Note the use of 'modeset': |
551 | * - we set it on lid close, and reset it on open | 551 | * - we set it to MODESET_ON_LID_OPEN on lid close, |
552 | * and set it to MODESET_DONE on open | ||
552 | * - we use it as a "only once" bit (ie we ignore | 553 | * - we use it as a "only once" bit (ie we ignore |
553 | * duplicate events where it was already properly | 554 | * duplicate events where it was already properly set) |
554 | * set/reset) | 555 | * - the suspend/resume paths will set it to |
555 | * - the suspend/resume paths will also set it to | 556 | * MODESET_SUSPENDED and ignore the lid open event, |
556 | * zero, since they restore the mode ("lid open"). | 557 | * because they restore the mode ("lid open"). |
557 | */ | 558 | */ |
558 | static int intel_lid_notify(struct notifier_block *nb, unsigned long val, | 559 | static int intel_lid_notify(struct notifier_block *nb, unsigned long val, |
559 | void *unused) | 560 | void *unused) |
@@ -567,6 +568,9 @@ static int intel_lid_notify(struct notifier_block *nb, unsigned long val, | |||
567 | if (dev->switch_power_state != DRM_SWITCH_POWER_ON) | 568 | if (dev->switch_power_state != DRM_SWITCH_POWER_ON) |
568 | return NOTIFY_OK; | 569 | return NOTIFY_OK; |
569 | 570 | ||
571 | mutex_lock(&dev_priv->modeset_restore_lock); | ||
572 | if (dev_priv->modeset_restore == MODESET_SUSPENDED) | ||
573 | goto exit; | ||
570 | /* | 574 | /* |
571 | * check and update the status of LVDS connector after receiving | 575 | * check and update the status of LVDS connector after receiving |
572 | * the LID nofication event. | 576 | * the LID nofication event. |
@@ -575,21 +579,24 @@ static int intel_lid_notify(struct notifier_block *nb, unsigned long val, | |||
575 | 579 | ||
576 | /* Don't force modeset on machines where it causes a GPU lockup */ | 580 | /* Don't force modeset on machines where it causes a GPU lockup */ |
577 | if (dmi_check_system(intel_no_modeset_on_lid)) | 581 | if (dmi_check_system(intel_no_modeset_on_lid)) |
578 | return NOTIFY_OK; | 582 | goto exit; |
579 | if (!acpi_lid_open()) { | 583 | if (!acpi_lid_open()) { |
580 | dev_priv->modeset_on_lid = 1; | 584 | /* do modeset on next lid open event */ |
581 | return NOTIFY_OK; | 585 | dev_priv->modeset_restore = MODESET_ON_LID_OPEN; |
586 | goto exit; | ||
582 | } | 587 | } |
583 | 588 | ||
584 | if (!dev_priv->modeset_on_lid) | 589 | if (dev_priv->modeset_restore == MODESET_DONE) |
585 | return NOTIFY_OK; | 590 | goto exit; |
586 | |||
587 | dev_priv->modeset_on_lid = 0; | ||
588 | 591 | ||
589 | drm_modeset_lock_all(dev); | 592 | drm_modeset_lock_all(dev); |
590 | intel_modeset_setup_hw_state(dev, true); | 593 | intel_modeset_setup_hw_state(dev, true); |
591 | drm_modeset_unlock_all(dev); | 594 | drm_modeset_unlock_all(dev); |
592 | 595 | ||
596 | dev_priv->modeset_restore = MODESET_DONE; | ||
597 | |||
598 | exit: | ||
599 | mutex_unlock(&dev_priv->modeset_restore_lock); | ||
593 | return NOTIFY_OK; | 600 | return NOTIFY_OK; |
594 | } | 601 | } |
595 | 602 | ||