diff mbox

omapdss: extend pm notifier to handle hibernation

Message ID 1424883836-9119-1-git-send-email-grygorii.strashko@linaro.org (mailing list archive)
State New, archived
Headers show

Commit Message

Grygorii.Strashko@linaro.org Feb. 25, 2015, 5:03 p.m. UTC
From: Grygorii Strashko <Grygorii.Strashko@linaro.org>

Add handling of missed events in omap_dss_pm_notif which are
needed to support hibernation (suspend to disk).

Signed-off-by: Grygorii Strashko <Grygorii.Strashko@linaro.org>
---
 drivers/video/fbdev/omap2/dss/core.c | 4 ++++
 1 file changed, 4 insertions(+)

Comments

Tomi Valkeinen March 20, 2015, 12:20 p.m. UTC | #1
On 25/02/15 19:03, grygorii.strashko@linaro.org wrote:
> From: Grygorii Strashko <Grygorii.Strashko@linaro.org>
> 
> Add handling of missed events in omap_dss_pm_notif which are
> needed to support hibernation (suspend to disk).
> 
> Signed-off-by: Grygorii Strashko <Grygorii.Strashko@linaro.org>
> ---
>  drivers/video/fbdev/omap2/dss/core.c | 4 ++++
>  1 file changed, 4 insertions(+)
> 
> diff --git a/drivers/video/fbdev/omap2/dss/core.c b/drivers/video/fbdev/omap2/dss/core.c
> index 6b74f73..e60976a 100644
> --- a/drivers/video/fbdev/omap2/dss/core.c
> +++ b/drivers/video/fbdev/omap2/dss/core.c
> @@ -178,11 +178,15 @@ static int omap_dss_pm_notif(struct notifier_block *b, unsigned long v, void *d)
>  	DSSDBG("pm notif %lu\n", v);
>  
>  	switch (v) {
> +	case PM_HIBERNATION_PREPARE:
>  	case PM_SUSPEND_PREPARE:
> +	case PM_RESTORE_PREPARE:
>  		DSSDBG("suspending displays\n");
>  		return dss_suspend_all_devices();
>  
>  	case PM_POST_SUSPEND:
> +	case PM_POST_HIBERNATION:
> +	case PM_POST_RESTORE:
>  		DSSDBG("resuming displays\n");
>  		return dss_resume_all_devices();
>  

Why suspend displays when PM_RESTORE_PREPARE happens? Why resume when
PM_POST_RESTORE happens?

 Tomi
Grygorii.Strashko@linaro.org March 20, 2015, 2:57 p.m. UTC | #2
Hi Tomi,

On 03/20/2015 02:20 PM, Tomi Valkeinen wrote:
> On 25/02/15 19:03, grygorii.strashko@linaro.org wrote:
>> From: Grygorii Strashko <Grygorii.Strashko@linaro.org>
>>
>> Add handling of missed events in omap_dss_pm_notif which are
>> needed to support hibernation (suspend to disk).
>>
>> Signed-off-by: Grygorii Strashko <Grygorii.Strashko@linaro.org>
>> ---
>>   drivers/video/fbdev/omap2/dss/core.c | 4 ++++
>>   1 file changed, 4 insertions(+)
>>
>> diff --git a/drivers/video/fbdev/omap2/dss/core.c b/drivers/video/fbdev/omap2/dss/core.c
>> index 6b74f73..e60976a 100644
>> --- a/drivers/video/fbdev/omap2/dss/core.c
>> +++ b/drivers/video/fbdev/omap2/dss/core.c
>> @@ -178,11 +178,15 @@ static int omap_dss_pm_notif(struct notifier_block *b, unsigned long v, void *d)
>>   	DSSDBG("pm notif %lu\n", v);
>>   
>>   	switch (v) {
>> +	case PM_HIBERNATION_PREPARE:
>>   	case PM_SUSPEND_PREPARE:
>> +	case PM_RESTORE_PREPARE:
>>   		DSSDBG("suspending displays\n");
>>   		return dss_suspend_all_devices();
>>   
>>   	case PM_POST_SUSPEND:
>> +	case PM_POST_HIBERNATION:
>> +	case PM_POST_RESTORE:
>>   		DSSDBG("resuming displays\n");
>>   		return dss_resume_all_devices();
>>   
> 
> Why suspend displays when PM_RESTORE_PREPARE happens? Why resume when
> PM_POST_RESTORE happens?

We have following sequence when system is restored from hibernation:
- original kernel booted;
- late_initcall_sync(software_resume);
  - pm_notifier_call_chain(PM_RESTORE_PREPARE);
  - freeze_processes
  - check & read hibernation image
  - suspend all devices (.freeze())
  - jump to stored kernel
  - restore devices
  ...

So, all devices should be in frozen/suspended state when we will jump to stored kernel
(device's state should be the same as before creating hib image).

Without this patch I can see a lot of log messages like below:

[    3.642499] Freezing user space processes ... 
[    3.647029]  mmcblk1boot1: unknown partition table
[    3.647043] (elapsed 0.000 seconds) done.
[    3.686414]  mmcblk1boot0: unknown partition table
[    3.714552] PM: Using 1 thread(s) for decompression.
[    3.714552] PM: Loading and decompressing image data (144641 pages)...
[    4.520388] PM: Image loading progress:   0%
[    5.153715] PM: Image loading progress:  10%
[    5.847731] PM: Image loading progress:  20%
[    6.622024] PM: Image loading progress:  30%
[    7.023830] PM: Image loading progress:  40%
[    7.455959] PM: Image loading progress:  50%
[    8.137186] PM: Image loading progress:  60%
[    8.567899] PM: Image loading progress:  70%
[    9.670371] PM: Image loading progress:  80%
[   10.130646] PM: Image loading progress:  90%
[   10.525035] PM: Image loading progress: 100%
[   10.529565] PM: Image loading done.
[   10.533262] PM: Read 578564 kbytes in 6.80 seconds (85.08 MB/s)
[   10.545313] Suspending console(s) (use no_console_suspend to debug)
[  193.721284] PM: freeze of devices complete after 7.891 msecs
[  193.722618] PM: late freeze of devices complete after 1.325 msecs
[  193.723969] PM: noirq freeze of devices complete after 1.343 msecs
[  193.724133] Disabling non-boot CPUs ...
[  193.724792] CPU1: shutdown
[  193.725387] PM: Creating hibernation image:
[  193.725387] PM: Need to copy 144499 pages
[  193.725439] Enabling non-boot CPUs ...
[  193.725783] CPU1: smp_ops.cpu_die() returned, trying to resuscitate
[  193.725790] CPU1: Booted secondary processor
[  193.726069] CPU1 is up
[  193.743772] PM: noirq restore of devices complete after 17.693 msecs
[  193.744691] PM: early restore of devices complete after 0.634 msecs
[  193.951382] [drm:omap_crtc_error_irq] *ERROR* tv: errors: 00008000
[  193.951389] [drm:omap_plane_error_irq] *ERROR* gfx: errors: 00000040
[  193.951402] [drm:omap_crtc_error_irq] *ERROR* tv: errors: 00008000
[  193.951413] [drm:omap_crtc_error_irq] *ERROR* tv: errors: 00008000
[  193.951424] [drm:omap_crtc_error_irq] *ERROR* tv: errors: 00008000
[  193.951435] [drm:omap_crtc_error_irq] *ERROR* tv: errors: 00008000
[  193.951445] [drm:omap_crtc_error_irq] *ERROR* tv: errors: 00008000
[  193.951455] [drm:omap_crtc_error_irq] *ERROR* tv: errors: 00008000
[  193.951465] [drm:omap_crtc_error_irq] *ERROR* tv: errors: 00008000
[  193.951475] [drm:omap_crtc_error_irq] *ERROR* tv: errors: 00008000
[  193.951484] [drm:omap_crtc_error_irq] *ERROR* tv: errors: 00008000
[  193.951567] omap_l3_noc 44000000.ocp: L3 application error: target 2 mod:1 (unclearable)
[  193.951605] omap_l3_noc 44000000.ocp: L3 debug error: target 2 mod:1 (unclearable)
[  194.293226] ata1: SATA link down (SStatus 0 SControl 300)
[  194.560684] PM: restore of devices complete after 610.740 msecs
Tomi Valkeinen March 20, 2015, 3:21 p.m. UTC | #3
On 20/03/15 16:57, Grygorii.Strashko@linaro.org wrote:
> Hi Tomi,
> 
> On 03/20/2015 02:20 PM, Tomi Valkeinen wrote:
>> On 25/02/15 19:03, grygorii.strashko@linaro.org wrote:
>>> From: Grygorii Strashko <Grygorii.Strashko@linaro.org>
>>>
>>> Add handling of missed events in omap_dss_pm_notif which are
>>> needed to support hibernation (suspend to disk).
>>>
>>> Signed-off-by: Grygorii Strashko <Grygorii.Strashko@linaro.org>
>>> ---
>>>   drivers/video/fbdev/omap2/dss/core.c | 4 ++++
>>>   1 file changed, 4 insertions(+)
>>>
>>> diff --git a/drivers/video/fbdev/omap2/dss/core.c b/drivers/video/fbdev/omap2/dss/core.c
>>> index 6b74f73..e60976a 100644
>>> --- a/drivers/video/fbdev/omap2/dss/core.c
>>> +++ b/drivers/video/fbdev/omap2/dss/core.c
>>> @@ -178,11 +178,15 @@ static int omap_dss_pm_notif(struct notifier_block *b, unsigned long v, void *d)
>>>   	DSSDBG("pm notif %lu\n", v);
>>>   
>>>   	switch (v) {
>>> +	case PM_HIBERNATION_PREPARE:
>>>   	case PM_SUSPEND_PREPARE:
>>> +	case PM_RESTORE_PREPARE:
>>>   		DSSDBG("suspending displays\n");
>>>   		return dss_suspend_all_devices();
>>>   
>>>   	case PM_POST_SUSPEND:
>>> +	case PM_POST_HIBERNATION:
>>> +	case PM_POST_RESTORE:
>>>   		DSSDBG("resuming displays\n");
>>>   		return dss_resume_all_devices();
>>>   
>>
>> Why suspend displays when PM_RESTORE_PREPARE happens? Why resume when
>> PM_POST_RESTORE happens?
> 
> We have following sequence when system is restored from hibernation:
> - original kernel booted;
> - late_initcall_sync(software_resume);
>   - pm_notifier_call_chain(PM_RESTORE_PREPARE);
>   - freeze_processes
>   - check & read hibernation image
>   - suspend all devices (.freeze())
>   - jump to stored kernel
>   - restore devices
>   ...
> 
> So, all devices should be in frozen/suspended state when we will jump to stored kernel
> (device's state should be the same as before creating hib image).
> 
> Without this patch I can see a lot of log messages like below:

Yes, I am sure a fix is needed for hibernation. But I still don't quite
understand PM_RESTORE_PREPARE and PM_POST_RESTORE.

When we enter hibernation, there's only PM_HIBERNATION_PREPARE?

When waking from hibernation, there's first PM_RESTORE_PREPARE, where we
need to disable displays that were enabled during boot. Then either
PM_POST_HIBERNATION if all went well, or PM_POST_RESTORE if there was an
error, and in both cases we want to enable the displays?

 Tomi
Grygorii.Strashko@linaro.org March 20, 2015, 5:19 p.m. UTC | #4
On 03/20/2015 05:21 PM, Tomi Valkeinen wrote:
> On 20/03/15 16:57, Grygorii.Strashko@linaro.org wrote:
>> On 03/20/2015 02:20 PM, Tomi Valkeinen wrote:
>>> On 25/02/15 19:03, grygorii.strashko@linaro.org wrote:
>>>> From: Grygorii Strashko <Grygorii.Strashko@linaro.org>
>>>>
>>>> Add handling of missed events in omap_dss_pm_notif which are
>>>> needed to support hibernation (suspend to disk).
>>>>
>>>> Signed-off-by: Grygorii Strashko <Grygorii.Strashko@linaro.org>
>>>> ---
>>>>    drivers/video/fbdev/omap2/dss/core.c | 4 ++++
>>>>    1 file changed, 4 insertions(+)
>>>>
>>>> diff --git a/drivers/video/fbdev/omap2/dss/core.c b/drivers/video/fbdev/omap2/dss/core.c
>>>> index 6b74f73..e60976a 100644
>>>> --- a/drivers/video/fbdev/omap2/dss/core.c
>>>> +++ b/drivers/video/fbdev/omap2/dss/core.c
>>>> @@ -178,11 +178,15 @@ static int omap_dss_pm_notif(struct notifier_block *b, unsigned long v, void *d)
>>>>    	DSSDBG("pm notif %lu\n", v);
>>>>    
>>>>    	switch (v) {
>>>> +	case PM_HIBERNATION_PREPARE:
>>>>    	case PM_SUSPEND_PREPARE:
>>>> +	case PM_RESTORE_PREPARE:
>>>>    		DSSDBG("suspending displays\n");
>>>>    		return dss_suspend_all_devices();
>>>>    
>>>>    	case PM_POST_SUSPEND:
>>>> +	case PM_POST_HIBERNATION:
>>>> +	case PM_POST_RESTORE:
>>>>    		DSSDBG("resuming displays\n");
>>>>    		return dss_resume_all_devices();
>>>>    
>>>
>>> Why suspend displays when PM_RESTORE_PREPARE happens? Why resume when
>>> PM_POST_RESTORE happens?
>>
>> We have following sequence when system is restored from hibernation:
>> - original kernel booted;
>> - late_initcall_sync(software_resume);
>>    - pm_notifier_call_chain(PM_RESTORE_PREPARE);
>>    - freeze_processes
>>    - check & read hibernation image
>>    - suspend all devices (.freeze())
>>    - jump to stored kernel
>>    - restore devices
>>    ...
>>
>> So, all devices should be in frozen/suspended state when we will jump to stored kernel
>> (device's state should be the same as before creating hib image).
>>
>> Without this patch I can see a lot of log messages like below:
> 
> Yes, I am sure a fix is needed for hibernation. But I still don't quite
> understand PM_RESTORE_PREPARE and PM_POST_RESTORE.
> 
> When we enter hibernation, there's only PM_HIBERNATION_PREPARE?

No. There is always PM_POST_HIBERNATION:
    - original Kernel in case of failure
    - restored Kernel on success

> 
> When waking from hibernation, there's first PM_RESTORE_PREPARE, where we
> need to disable displays that were enabled during boot. Then either
> PM_POST_HIBERNATION if all went well, or PM_POST_RESTORE if there was an
> error, and in both cases we want to enable the displays?

Yes.

====
int hibernate(void)
	error = pm_notifier_call_chain(PM_HIBERNATION_PREPARE);
...
	error = hibernation_snapshot(hibernation_mode == HIBERNATION_PLATFORM);
		^^^ restored kernel will start from here

	if (error || freezer_test_done)
		goto Free_bitmaps;

	if (in_suspend) {
...

		pr_debug("PM: writing image.\n");
		error = swsusp_write(flags);
		swsusp_free();
		if (!error)
			power_down();
		in_suspend = 0;
		pm_restore_gfp_mask();
		^^ this part will be executed by Kernel requested Hibernation

	} else {
		pr_debug("PM: Image restored successfully.\n");
		^^ this part will be executed by Kernel restored from Hibernation
	}

...
	pm_notifier_call_chain(PM_POST_HIBERNATION);
^^^ Both Kernels will be notified here:
    - original Kernel in case of failure
    - restored Kernel on success
    
    


====
static int software_resume(void)
	error = pm_notifier_call_chain(PM_RESTORE_PREPARE);
	error = swsusp_read(&flags);
	swsusp_close(FMODE_READ);
	if (!error)
		hibernation_restore(flags & SF_PLATFORM_MODE);
                ^^^ if ok we will never return from this function

	printk(KERN_ERR "PM: Failed to load hibernation image, recovering.\n");
	pm_notifier_call_chain(PM_POST_RESTORE);
^^^
   if fail - just continue work as usual
diff mbox

Patch

diff --git a/drivers/video/fbdev/omap2/dss/core.c b/drivers/video/fbdev/omap2/dss/core.c
index 6b74f73..e60976a 100644
--- a/drivers/video/fbdev/omap2/dss/core.c
+++ b/drivers/video/fbdev/omap2/dss/core.c
@@ -178,11 +178,15 @@  static int omap_dss_pm_notif(struct notifier_block *b, unsigned long v, void *d)
 	DSSDBG("pm notif %lu\n", v);
 
 	switch (v) {
+	case PM_HIBERNATION_PREPARE:
 	case PM_SUSPEND_PREPARE:
+	case PM_RESTORE_PREPARE:
 		DSSDBG("suspending displays\n");
 		return dss_suspend_all_devices();
 
 	case PM_POST_SUSPEND:
+	case PM_POST_HIBERNATION:
+	case PM_POST_RESTORE:
 		DSSDBG("resuming displays\n");
 		return dss_resume_all_devices();