diff mbox

[RFC/PATCH] mmc: core: Signal wakeup event at card insert/removal

Message ID 1379670523-13229-1-git-send-email-ulf.hansson@linaro.org (mailing list archive)
State New, archived
Headers show

Commit Message

Ulf Hansson Sept. 20, 2013, 9:48 a.m. UTC
We want to give user space provision to fully consume a card
insert/remove event, when the event was caused by a wakeup irq.

By signaling the wakeup event for a time of 5 s for devices configured
as wakeup capable, we likely will be prevent a sleep long enough to let
user space consume the event.

To enable this feature, host drivers must thus configure their devices
as wakeup capable.

This is a reworked implementation of the old wakelocks for the mmc
subsystem, originally authored by Colin Cross and San Mehat for the
Android kernel. Zoran Markovic shall also be given cred for recently
re-trying to upstream this feature.

Cc: San Mehat <san@google.com>
Cc: Colin Cross <ccross@android.com>
Cc: John Stultz <john.stultz@linaro.org>
Cc: Zoran Markovic <zoran.markovic@linaro.org>
Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
---

This patch has just been compile tested, since I at very moment did not
have a good board to test it on. I am working on that.

Any help in testing this patch is thus greatly appreciated. While
testing also don't forget to enable the host device as wakeup capable.
Use "device_init_wakeup" from the host probe function.

---
 drivers/mmc/core/core.c |   39 +++++++++++++++++++++++++++------------
 1 file changed, 27 insertions(+), 12 deletions(-)

Comments

Jaehoon Chung Sept. 23, 2013, 10:55 a.m. UTC | #1
Hi Ulf,

On 09/20/2013 06:48 PM, Ulf Hansson wrote:
> We want to give user space provision to fully consume a card
> insert/remove event, when the event was caused by a wakeup irq.
> 
> By signaling the wakeup event for a time of 5 s for devices configured
> as wakeup capable, we likely will be prevent a sleep long enough to let
> user space consume the event.
> 
> To enable this feature, host drivers must thus configure their devices
> as wakeup capable.
> 
> This is a reworked implementation of the old wakelocks for the mmc
> subsystem, originally authored by Colin Cross and San Mehat for the
> Android kernel. Zoran Markovic shall also be given cred for recently
> re-trying to upstream this feature.
> 
> Cc: San Mehat <san@google.com>
> Cc: Colin Cross <ccross@android.com>
> Cc: John Stultz <john.stultz@linaro.org>
> Cc: Zoran Markovic <zoran.markovic@linaro.org>
> Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
> ---
> 
> This patch has just been compile tested, since I at very moment did not
> have a good board to test it on. I am working on that.
> 
> Any help in testing this patch is thus greatly appreciated. While
> testing also don't forget to enable the host device as wakeup capable.
> Use "device_init_wakeup" from the host probe function.

I used the device_init_wakeup(&pdev->dev, 1) into host controller. (Also enabled the irq for wakeup)
It didn't work when device is suspended.
Well, i might missed something.
As my understanding, it's helpful that wakeup-event is used when device is suspended.
How do you call mmc_detect_change() during suspended?

Best Regards,
Jaehoon Chung
> 
> ---
>  drivers/mmc/core/core.c |   39 +++++++++++++++++++++++++++------------
>  1 file changed, 27 insertions(+), 12 deletions(-)
> 
> diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
> index bf18b6b..3e8229e 100644
> --- a/drivers/mmc/core/core.c
> +++ b/drivers/mmc/core/core.c
> @@ -23,6 +23,7 @@
>  #include <linux/log2.h>
>  #include <linux/regulator/consumer.h>
>  #include <linux/pm_runtime.h>
> +#include <linux/pm_wakeup.h>
>  #include <linux/suspend.h>
>  #include <linux/fault-inject.h>
>  #include <linux/random.h>
> @@ -1723,6 +1724,28 @@ void mmc_detach_bus(struct mmc_host *host)
>  	mmc_bus_put(host);
>  }
>  
> +static void _mmc_detect_change(struct mmc_host *host, unsigned long delay,
> +				bool cd_irq)
> +{
> +#ifdef CONFIG_MMC_DEBUG
> +	unsigned long flags;
> +	spin_lock_irqsave(&host->lock, flags);
> +	WARN_ON(host->removed);
> +	spin_unlock_irqrestore(&host->lock, flags);
> +#endif
> +
> +	/*
> +	 * If the device is configured as wakeup, we prevent a new sleep for
> +	 * 5 s to give provision for user space to consume the event.
> +	 */
> +	if (cd_irq && !(host->caps & MMC_CAP_NEEDS_POLL) &&
> +		device_can_wakeup(mmc_dev(host)))
> +		pm_wakeup_event(mmc_dev(host), 5000);
> +
> +	host->detect_change = 1;
> +	mmc_schedule_delayed_work(&host->detect, delay);
> +}
> +
>  /**
>   *	mmc_detect_change - process change of state on a MMC socket
>   *	@host: host which changed state.
> @@ -1735,16 +1758,8 @@ void mmc_detach_bus(struct mmc_host *host)
>   */
>  void mmc_detect_change(struct mmc_host *host, unsigned long delay)
>  {
> -#ifdef CONFIG_MMC_DEBUG
> -	unsigned long flags;
> -	spin_lock_irqsave(&host->lock, flags);
> -	WARN_ON(host->removed);
> -	spin_unlock_irqrestore(&host->lock, flags);
> -#endif
> -	host->detect_change = 1;
> -	mmc_schedule_delayed_work(&host->detect, delay);
> +	_mmc_detect_change(host, delay, true);
>  }
> -
>  EXPORT_SYMBOL(mmc_detect_change);
>  
>  void mmc_init_erase(struct mmc_card *card)
> @@ -2423,7 +2438,7 @@ int mmc_detect_card_removed(struct mmc_host *host)
>  			 * rescan handle the card removal.
>  			 */
>  			cancel_delayed_work(&host->detect);
> -			mmc_detect_change(host, 0);
> +			_mmc_detect_change(host, 0, false);
>  		}
>  	}
>  
> @@ -2505,7 +2520,7 @@ void mmc_start_host(struct mmc_host *host)
>  		mmc_power_off(host);
>  	else
>  		mmc_power_up(host);
> -	mmc_detect_change(host, 0);
> +	_mmc_detect_change(host, 0, false);
>  }
>  
>  void mmc_stop_host(struct mmc_host *host)
> @@ -2724,7 +2739,7 @@ int mmc_pm_notify(struct notifier_block *notify_block,
>  		spin_lock_irqsave(&host->lock, flags);
>  		host->rescan_disable = 0;
>  		spin_unlock_irqrestore(&host->lock, flags);
> -		mmc_detect_change(host, 0);
> +		_mmc_detect_change(host, 0, false);
>  
>  	}
>  
> 

--
To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Ulf Hansson Sept. 23, 2013, 12:11 p.m. UTC | #2
On 23 September 2013 12:55, Jaehoon Chung <jh80.chung@samsung.com> wrote:
> Hi Ulf,
>
> On 09/20/2013 06:48 PM, Ulf Hansson wrote:
>> We want to give user space provision to fully consume a card
>> insert/remove event, when the event was caused by a wakeup irq.
>>
>> By signaling the wakeup event for a time of 5 s for devices configured
>> as wakeup capable, we likely will be prevent a sleep long enough to let
>> user space consume the event.
>>
>> To enable this feature, host drivers must thus configure their devices
>> as wakeup capable.
>>
>> This is a reworked implementation of the old wakelocks for the mmc
>> subsystem, originally authored by Colin Cross and San Mehat for the
>> Android kernel. Zoran Markovic shall also be given cred for recently
>> re-trying to upstream this feature.
>>
>> Cc: San Mehat <san@google.com>
>> Cc: Colin Cross <ccross@android.com>
>> Cc: John Stultz <john.stultz@linaro.org>
>> Cc: Zoran Markovic <zoran.markovic@linaro.org>
>> Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
>> ---
>>
>> This patch has just been compile tested, since I at very moment did not
>> have a good board to test it on. I am working on that.
>>
>> Any help in testing this patch is thus greatly appreciated. While
>> testing also don't forget to enable the host device as wakeup capable.
>> Use "device_init_wakeup" from the host probe function.
>

Hi Jaehoon,

Thanks for helping out testing this patch!

> I used the device_init_wakeup(&pdev->dev, 1) into host controller. (Also enabled the irq for wakeup)
> It didn't work when device is suspended.
> Well, i might missed something.

Not sure what you mean by didn't work here. Did the card detect irq
wake up the platform and thus triggered a resume? Or you mean that
even that did not work?

> As my understanding, it's helpful that wakeup-event is used when device is suspended.

This feature is typically used for devices using "autosuspend", like
Android devices. Otherwise you likely do not want to wakeup the
platform when inserting/removing a card, but that is another story.
:-)

> How do you call mmc_detect_change() during suspended?

To try to clarify things a bit, the sequence is typically like this:

1. We enter suspend.
2. A card is inserted and a card detect irq is triggered. The
corresponding irq handler gets called which then issue
mmc_detect_change.
3. mmc_detect_change recognize the device as a wakeup capable device
and thus issue a pm_wakeup_event(5s) to prevent a new trigger of
suspend.
4. A rescan work is scheduled.
5. System continues resuming.
6. After PM_POST_SUSPEND notification (mmc_pm_notify), rescan is
enabled and a new work re-scheduled.
7. The rescan work detects the new card and user space soon gets
notified about it.
8. User space gets the notification and can act on it.
9. The timeout of the pm_wakeup_event has elapsed, allowing a new
suspend to be triggered.


Kind regards
Ulf Hansson

>
> Best Regards,
> Jaehoon Chung
>>
>> ---
>>  drivers/mmc/core/core.c |   39 +++++++++++++++++++++++++++------------
>>  1 file changed, 27 insertions(+), 12 deletions(-)
>>
>> diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
>> index bf18b6b..3e8229e 100644
>> --- a/drivers/mmc/core/core.c
>> +++ b/drivers/mmc/core/core.c
>> @@ -23,6 +23,7 @@
>>  #include <linux/log2.h>
>>  #include <linux/regulator/consumer.h>
>>  #include <linux/pm_runtime.h>
>> +#include <linux/pm_wakeup.h>
>>  #include <linux/suspend.h>
>>  #include <linux/fault-inject.h>
>>  #include <linux/random.h>
>> @@ -1723,6 +1724,28 @@ void mmc_detach_bus(struct mmc_host *host)
>>       mmc_bus_put(host);
>>  }
>>
>> +static void _mmc_detect_change(struct mmc_host *host, unsigned long delay,
>> +                             bool cd_irq)
>> +{
>> +#ifdef CONFIG_MMC_DEBUG
>> +     unsigned long flags;
>> +     spin_lock_irqsave(&host->lock, flags);
>> +     WARN_ON(host->removed);
>> +     spin_unlock_irqrestore(&host->lock, flags);
>> +#endif
>> +
>> +     /*
>> +      * If the device is configured as wakeup, we prevent a new sleep for
>> +      * 5 s to give provision for user space to consume the event.
>> +      */
>> +     if (cd_irq && !(host->caps & MMC_CAP_NEEDS_POLL) &&
>> +             device_can_wakeup(mmc_dev(host)))
>> +             pm_wakeup_event(mmc_dev(host), 5000);
>> +
>> +     host->detect_change = 1;
>> +     mmc_schedule_delayed_work(&host->detect, delay);
>> +}
>> +
>>  /**
>>   *   mmc_detect_change - process change of state on a MMC socket
>>   *   @host: host which changed state.
>> @@ -1735,16 +1758,8 @@ void mmc_detach_bus(struct mmc_host *host)
>>   */
>>  void mmc_detect_change(struct mmc_host *host, unsigned long delay)
>>  {
>> -#ifdef CONFIG_MMC_DEBUG
>> -     unsigned long flags;
>> -     spin_lock_irqsave(&host->lock, flags);
>> -     WARN_ON(host->removed);
>> -     spin_unlock_irqrestore(&host->lock, flags);
>> -#endif
>> -     host->detect_change = 1;
>> -     mmc_schedule_delayed_work(&host->detect, delay);
>> +     _mmc_detect_change(host, delay, true);
>>  }
>> -
>>  EXPORT_SYMBOL(mmc_detect_change);
>>
>>  void mmc_init_erase(struct mmc_card *card)
>> @@ -2423,7 +2438,7 @@ int mmc_detect_card_removed(struct mmc_host *host)
>>                        * rescan handle the card removal.
>>                        */
>>                       cancel_delayed_work(&host->detect);
>> -                     mmc_detect_change(host, 0);
>> +                     _mmc_detect_change(host, 0, false);
>>               }
>>       }
>>
>> @@ -2505,7 +2520,7 @@ void mmc_start_host(struct mmc_host *host)
>>               mmc_power_off(host);
>>       else
>>               mmc_power_up(host);
>> -     mmc_detect_change(host, 0);
>> +     _mmc_detect_change(host, 0, false);
>>  }
>>
>>  void mmc_stop_host(struct mmc_host *host)
>> @@ -2724,7 +2739,7 @@ int mmc_pm_notify(struct notifier_block *notify_block,
>>               spin_lock_irqsave(&host->lock, flags);
>>               host->rescan_disable = 0;
>>               spin_unlock_irqrestore(&host->lock, flags);
>> -             mmc_detect_change(host, 0);
>> +             _mmc_detect_change(host, 0, false);
>>
>>       }
>>
>>
>
--
To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Jaehoon Chung Sept. 23, 2013, 12:46 p.m. UTC | #3
On 09/23/2013 09:11 PM, Ulf Hansson wrote:
> On 23 September 2013 12:55, Jaehoon Chung <jh80.chung@samsung.com> wrote:
>> Hi Ulf,
>>
>> On 09/20/2013 06:48 PM, Ulf Hansson wrote:
>>> We want to give user space provision to fully consume a card
>>> insert/remove event, when the event was caused by a wakeup irq.
>>>
>>> By signaling the wakeup event for a time of 5 s for devices configured
>>> as wakeup capable, we likely will be prevent a sleep long enough to let
>>> user space consume the event.
>>>
>>> To enable this feature, host drivers must thus configure their devices
>>> as wakeup capable.
>>>
>>> This is a reworked implementation of the old wakelocks for the mmc
>>> subsystem, originally authored by Colin Cross and San Mehat for the
>>> Android kernel. Zoran Markovic shall also be given cred for recently
>>> re-trying to upstream this feature.
>>>
>>> Cc: San Mehat <san@google.com>
>>> Cc: Colin Cross <ccross@android.com>
>>> Cc: John Stultz <john.stultz@linaro.org>
>>> Cc: Zoran Markovic <zoran.markovic@linaro.org>
>>> Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
>>> ---
>>>
>>> This patch has just been compile tested, since I at very moment did not
>>> have a good board to test it on. I am working on that.
>>>
>>> Any help in testing this patch is thus greatly appreciated. While
>>> testing also don't forget to enable the host device as wakeup capable.
>>> Use "device_init_wakeup" from the host probe function.
>>
> 
> Hi Jaehoon,
> 
> Thanks for helping out testing this patch!
> 
>> I used the device_init_wakeup(&pdev->dev, 1) into host controller. (Also enabled the irq for wakeup)
>> It didn't work when device is suspended.
>> Well, i might missed something.
> 
> Not sure what you mean by didn't work here. Did the card detect irq
> wake up the platform and thus triggered a resume? Or you mean that
> even that did not work?
> 
>> As my understanding, it's helpful that wakeup-event is used when device is suspended.
> 
> This feature is typically used for devices using "autosuspend", like
> Android devices. Otherwise you likely do not want to wakeup the
> platform when inserting/removing a card, but that is another story.
> :-)
Hi Ulf,

Then, my case should be another story. I will re-test with using "autosuspend".
I didn't use the autosuspend.
> 
>> How do you call mmc_detect_change() during suspended?

In my case,
1, entered suspended.
2. card is inserted..then didn't get the triggered irq.
If get the triggered irq, need to set irq_set_irq_wake(cd_irq, 1).

So i have asked to you how called mmc_detect_change().
In my-case, didn't call mmc_detect_change().

I will re-test and share the result.

Best Regards,
Jaehoon Chung
> 
> To try to clarify things a bit, the sequence is typically like this:
> 
> 1. We enter suspend.
> 2. A card is inserted and a card detect irq is triggered. The
> corresponding irq handler gets called which then issue
> mmc_detect_change.
> 3. mmc_detect_change recognize the device as a wakeup capable device
> and thus issue a pm_wakeup_event(5s) to prevent a new trigger of
> suspend.
> 4. A rescan work is scheduled.
> 5. System continues resuming.
> 6. After PM_POST_SUSPEND notification (mmc_pm_notify), rescan is
> enabled and a new work re-scheduled.
> 7. The rescan work detects the new card and user space soon gets
> notified about it.
> 8. User space gets the notification and can act on it.
> 9. The timeout of the pm_wakeup_event has elapsed, allowing a new
> suspend to be triggered.
> 
> 
> Kind regards
> Ulf Hansson
> 
>>
>> Best Regards,
>> Jaehoon Chung
>>>
>>> ---
>>>  drivers/mmc/core/core.c |   39 +++++++++++++++++++++++++++------------
>>>  1 file changed, 27 insertions(+), 12 deletions(-)
>>>
>>> diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
>>> index bf18b6b..3e8229e 100644
>>> --- a/drivers/mmc/core/core.c
>>> +++ b/drivers/mmc/core/core.c
>>> @@ -23,6 +23,7 @@
>>>  #include <linux/log2.h>
>>>  #include <linux/regulator/consumer.h>
>>>  #include <linux/pm_runtime.h>
>>> +#include <linux/pm_wakeup.h>
>>>  #include <linux/suspend.h>
>>>  #include <linux/fault-inject.h>
>>>  #include <linux/random.h>
>>> @@ -1723,6 +1724,28 @@ void mmc_detach_bus(struct mmc_host *host)
>>>       mmc_bus_put(host);
>>>  }
>>>
>>> +static void _mmc_detect_change(struct mmc_host *host, unsigned long delay,
>>> +                             bool cd_irq)
>>> +{
>>> +#ifdef CONFIG_MMC_DEBUG
>>> +     unsigned long flags;
>>> +     spin_lock_irqsave(&host->lock, flags);
>>> +     WARN_ON(host->removed);
>>> +     spin_unlock_irqrestore(&host->lock, flags);
>>> +#endif
>>> +
>>> +     /*
>>> +      * If the device is configured as wakeup, we prevent a new sleep for
>>> +      * 5 s to give provision for user space to consume the event.
>>> +      */
>>> +     if (cd_irq && !(host->caps & MMC_CAP_NEEDS_POLL) &&
>>> +             device_can_wakeup(mmc_dev(host)))
>>> +             pm_wakeup_event(mmc_dev(host), 5000);
>>> +
>>> +     host->detect_change = 1;
>>> +     mmc_schedule_delayed_work(&host->detect, delay);
>>> +}
>>> +
>>>  /**
>>>   *   mmc_detect_change - process change of state on a MMC socket
>>>   *   @host: host which changed state.
>>> @@ -1735,16 +1758,8 @@ void mmc_detach_bus(struct mmc_host *host)
>>>   */
>>>  void mmc_detect_change(struct mmc_host *host, unsigned long delay)
>>>  {
>>> -#ifdef CONFIG_MMC_DEBUG
>>> -     unsigned long flags;
>>> -     spin_lock_irqsave(&host->lock, flags);
>>> -     WARN_ON(host->removed);
>>> -     spin_unlock_irqrestore(&host->lock, flags);
>>> -#endif
>>> -     host->detect_change = 1;
>>> -     mmc_schedule_delayed_work(&host->detect, delay);
>>> +     _mmc_detect_change(host, delay, true);
>>>  }
>>> -
>>>  EXPORT_SYMBOL(mmc_detect_change);
>>>
>>>  void mmc_init_erase(struct mmc_card *card)
>>> @@ -2423,7 +2438,7 @@ int mmc_detect_card_removed(struct mmc_host *host)
>>>                        * rescan handle the card removal.
>>>                        */
>>>                       cancel_delayed_work(&host->detect);
>>> -                     mmc_detect_change(host, 0);
>>> +                     _mmc_detect_change(host, 0, false);
>>>               }
>>>       }
>>>
>>> @@ -2505,7 +2520,7 @@ void mmc_start_host(struct mmc_host *host)
>>>               mmc_power_off(host);
>>>       else
>>>               mmc_power_up(host);
>>> -     mmc_detect_change(host, 0);
>>> +     _mmc_detect_change(host, 0, false);
>>>  }
>>>
>>>  void mmc_stop_host(struct mmc_host *host)
>>> @@ -2724,7 +2739,7 @@ int mmc_pm_notify(struct notifier_block *notify_block,
>>>               spin_lock_irqsave(&host->lock, flags);
>>>               host->rescan_disable = 0;
>>>               spin_unlock_irqrestore(&host->lock, flags);
>>> -             mmc_detect_change(host, 0);
>>> +             _mmc_detect_change(host, 0, false);
>>>
>>>       }
>>>
>>>
>>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> 

--
To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Zoran Markovic Sept. 23, 2013, 9:14 p.m. UTC | #4
Hi Ulf,
I like the fact that wakeups are now quite simplified. A couple of
comments below:

> By signaling the wakeup event for a time of 5 s for devices configured
> as wakeup capable, we likely will be prevent a sleep long enough to let
> user space consume the event.
Given that there is no pm_relax(), 5 seconds is probably too long.
User space should grab a wakeup_source of its own if it needs to
extend the awake state. I recommend putting just enough to start the
mount process - probably 0.5-1 second - but Android guys would know
better.

> +       /*
> +        * If the device is configured as wakeup, we prevent a new sleep for
> +        * 5 s to give provision for user space to consume the event.
> +        */
> +       if (cd_irq && !(host->caps & MMC_CAP_NEEDS_POLL) &&
> +               device_can_wakeup(mmc_dev(host)))
> +               pm_wakeup_event(mmc_dev(host), 5000);
It seems like device_can_wakeup() is redundant here and I'm not sure
what happens if a device is not wakeup capable. Was the intention to
go into autosleep until something else wakes up the system long enough
to complete the mount? Also is it ok if MMCs that require polling
exhibit wakeup behaviour of their own?

Zoran
--
To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Ulf Hansson Sept. 24, 2013, 7:55 a.m. UTC | #5
Hi Zoran,

On 23 September 2013 23:14, Zoran Markovic <zoran.markovic@linaro.org> wrote:
> Hi Ulf,
> I like the fact that wakeups are now quite simplified. A couple of
> comments below:
>
>> By signaling the wakeup event for a time of 5 s for devices configured
>> as wakeup capable, we likely will be prevent a sleep long enough to let
>> user space consume the event.
> Given that there is no pm_relax(), 5 seconds is probably too long.
> User space should grab a wakeup_source of its own if it needs to
> extend the awake state. I recommend putting just enough to start the
> mount process - probably 0.5-1 second - but Android guys would know
> better.

The total time before users pace gets notified can be summarized like this:

1.
Total system resume time, which has quite a big span of expected
consumed time. Do note, if other (e)MMC and/or SD-cards are already
inserted, these will be re-initialized as a part the resume and this
affect the resume time significantly. Typically an eMMC takes 200-400
ms and an SD-card 250-1100ms.

2. The scheduled rescan work shall be given priority to execute and
then complete the initialization of the recently inserted card. If we
assume it will be and SD-card, 250-1100 ms.

3. Once the card device is created from the rescan work, notification
is propagated upwards to user space. For this task I have no relevant
estimation on consumed time.

Not sure how to set the time-out value to meet all expectations. I
believe we could also consider that inserting/removing a card is a
quite seldom operation, so using a bit higher value than necessary
might be okay. What do you think?

>
>> +       /*
>> +        * If the device is configured as wakeup, we prevent a new sleep for
>> +        * 5 s to give provision for user space to consume the event.
>> +        */
>> +       if (cd_irq && !(host->caps & MMC_CAP_NEEDS_POLL) &&
>> +               device_can_wakeup(mmc_dev(host)))
>> +               pm_wakeup_event(mmc_dev(host), 5000);
> It seems like device_can_wakeup() is redundant here and I'm not sure
> what happens if a device is not wakeup capable. Was the intention to
> go into autosleep until something else wakes up the system long enough
> to complete the mount? Also is it ok if MMCs that require polling
> exhibit wakeup behaviour of their own?

I did not want to change present behaviour for all host drivers and
platforms, but instead host drivers need take an action of enabling
wakeup. If they consider to use card detect as wakeup irq, they need
adapt anyway, the irq is not default a wakeup irq.

In polling mode, new inserted cards will never be detected in suspend
state, since the entire system needs to be resumed to be able to
"poll". This is just not feasible. :-)

Kind regards
Ulf Hansson

>
> Zoran
--
To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Ulf Hansson Sept. 24, 2013, 9:58 a.m. UTC | #6
On 20 September 2013 11:48, Ulf Hansson <ulf.hansson@linaro.org> wrote:
> We want to give user space provision to fully consume a card
> insert/remove event, when the event was caused by a wakeup irq.
>
> By signaling the wakeup event for a time of 5 s for devices configured
> as wakeup capable, we likely will be prevent a sleep long enough to let
> user space consume the event.
>
> To enable this feature, host drivers must thus configure their devices
> as wakeup capable.
>
> This is a reworked implementation of the old wakelocks for the mmc
> subsystem, originally authored by Colin Cross and San Mehat for the
> Android kernel. Zoran Markovic shall also be given cred for recently
> re-trying to upstream this feature.
>
> Cc: San Mehat <san@google.com>
> Cc: Colin Cross <ccross@android.com>
> Cc: John Stultz <john.stultz@linaro.org>
> Cc: Zoran Markovic <zoran.markovic@linaro.org>
> Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
> ---
>
> This patch has just been compile tested, since I at very moment did not
> have a good board to test it on. I am working on that.
>
> Any help in testing this patch is thus greatly appreciated. While
> testing also don't forget to enable the host device as wakeup capable.
> Use "device_init_wakeup" from the host probe function.

Testing now done on a ux500 SoC. Changes done to configuring card
detect irq as wakeup. Sysfs nodes is behaving as expected. :-)

>
> ---
>  drivers/mmc/core/core.c |   39 +++++++++++++++++++++++++++------------
>  1 file changed, 27 insertions(+), 12 deletions(-)
>
> diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
> index bf18b6b..3e8229e 100644
> --- a/drivers/mmc/core/core.c
> +++ b/drivers/mmc/core/core.c
> @@ -23,6 +23,7 @@
>  #include <linux/log2.h>
>  #include <linux/regulator/consumer.h>
>  #include <linux/pm_runtime.h>
> +#include <linux/pm_wakeup.h>
>  #include <linux/suspend.h>
>  #include <linux/fault-inject.h>
>  #include <linux/random.h>
> @@ -1723,6 +1724,28 @@ void mmc_detach_bus(struct mmc_host *host)
>         mmc_bus_put(host);
>  }
>
> +static void _mmc_detect_change(struct mmc_host *host, unsigned long delay,
> +                               bool cd_irq)
> +{
> +#ifdef CONFIG_MMC_DEBUG
> +       unsigned long flags;
> +       spin_lock_irqsave(&host->lock, flags);
> +       WARN_ON(host->removed);
> +       spin_unlock_irqrestore(&host->lock, flags);
> +#endif
> +
> +       /*
> +        * If the device is configured as wakeup, we prevent a new sleep for
> +        * 5 s to give provision for user space to consume the event.
> +        */
> +       if (cd_irq && !(host->caps & MMC_CAP_NEEDS_POLL) &&
> +               device_can_wakeup(mmc_dev(host)))
> +               pm_wakeup_event(mmc_dev(host), 5000);
> +
> +       host->detect_change = 1;
> +       mmc_schedule_delayed_work(&host->detect, delay);
> +}
> +
>  /**
>   *     mmc_detect_change - process change of state on a MMC socket
>   *     @host: host which changed state.
> @@ -1735,16 +1758,8 @@ void mmc_detach_bus(struct mmc_host *host)
>   */
>  void mmc_detect_change(struct mmc_host *host, unsigned long delay)
>  {
> -#ifdef CONFIG_MMC_DEBUG
> -       unsigned long flags;
> -       spin_lock_irqsave(&host->lock, flags);
> -       WARN_ON(host->removed);
> -       spin_unlock_irqrestore(&host->lock, flags);
> -#endif
> -       host->detect_change = 1;
> -       mmc_schedule_delayed_work(&host->detect, delay);
> +       _mmc_detect_change(host, delay, true);
>  }
> -
>  EXPORT_SYMBOL(mmc_detect_change);
>
>  void mmc_init_erase(struct mmc_card *card)
> @@ -2423,7 +2438,7 @@ int mmc_detect_card_removed(struct mmc_host *host)
>                          * rescan handle the card removal.
>                          */
>                         cancel_delayed_work(&host->detect);
> -                       mmc_detect_change(host, 0);
> +                       _mmc_detect_change(host, 0, false);
>                 }
>         }
>
> @@ -2505,7 +2520,7 @@ void mmc_start_host(struct mmc_host *host)
>                 mmc_power_off(host);
>         else
>                 mmc_power_up(host);
> -       mmc_detect_change(host, 0);
> +       _mmc_detect_change(host, 0, false);
>  }
>
>  void mmc_stop_host(struct mmc_host *host)
> @@ -2724,7 +2739,7 @@ int mmc_pm_notify(struct notifier_block *notify_block,
>                 spin_lock_irqsave(&host->lock, flags);
>                 host->rescan_disable = 0;
>                 spin_unlock_irqrestore(&host->lock, flags);
> -               mmc_detect_change(host, 0);
> +               _mmc_detect_change(host, 0, false);
>
>         }
>
> --
> 1.7.9.5
>
--
To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
John Stultz Sept. 24, 2013, 4:58 p.m. UTC | #7
On 09/24/2013 12:55 AM, Ulf Hansson wrote:
> Hi Zoran,
>
> On 23 September 2013 23:14, Zoran Markovic <zoran.markovic@linaro.org> wrote:
>> Hi Ulf,
>> I like the fact that wakeups are now quite simplified. A couple of
>> comments below:
>>
>>> By signaling the wakeup event for a time of 5 s for devices configured
>>> as wakeup capable, we likely will be prevent a sleep long enough to let
>>> user space consume the event.
>> Given that there is no pm_relax(), 5 seconds is probably too long.
>> User space should grab a wakeup_source of its own if it needs to
>> extend the awake state. I recommend putting just enough to start the
>> mount process - probably 0.5-1 second - but Android guys would know
>> better.
> The total time before users pace gets notified can be summarized like this:
>
> 1.
> Total system resume time, which has quite a big span of expected
> consumed time. Do note, if other (e)MMC and/or SD-cards are already
> inserted, these will be re-initialized as a part the resume and this
> affect the resume time significantly. Typically an eMMC takes 200-400
> ms and an SD-card 250-1100ms.
>
> 2. The scheduled rescan work shall be given priority to execute and
> then complete the initialization of the recently inserted card. If we
> assume it will be and SD-card, 250-1100 ms.
>
> 3. Once the card device is created from the rescan work, notification
> is propagated upwards to user space. For this task I have no relevant
> estimation on consumed time.

So how does the notification done to userspace? I wonder if you could
use the select/lock/read style method for releasing the kernel space
wakeup_source, as is done in the input layer?


> Not sure how to set the time-out value to meet all expectations. I
> believe we could also consider that inserting/removing a card is a
> quite seldom operation, so using a bit higher value than necessary
> might be okay. What do you think?

As long as its sure to be *very* rare, then slightly longer delays
aren't a major problem.  The trouble with the timeout style wakelocks is
that they are easy to misuse and that hurts power efficiency. (I've
heard stories of badly written wifi drivers that took 5 minute timed
wakelocks on packets, which effectively kept devices from ever sleeping).

So if possible, its much better to have a normal path where the pm_relax
is called in most cases, using the timeout for only the few places where
you really can't get an end point.

thanks
-john
--
To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Ulf Hansson Oct. 1, 2013, 9:22 a.m. UTC | #8
Hi John,

> So how does the notification done to userspace? I wonder if you could
> use the select/lock/read style method for releasing the kernel space
> wakeup_source, as is done in the input layer?

If I understand what you mean correctly, it is very similar what Zoran
tried to do before in his patch!?

For the mmc subsystem, especially considering the pitfalls around the
scheduled detect work, I think it will be hard to get this right, if
implementing like this. I fear we might end up in situations were the
wakeup_source is never "relaxed".

>
>
>> Not sure how to set the time-out value to meet all expectations. I
>> believe we could also consider that inserting/removing a card is a
>> quite seldom operation, so using a bit higher value than necessary
>> might be okay. What do you think?
>
> As long as its sure to be *very* rare, then slightly longer delays
> aren't a major problem.  The trouble with the timeout style wakelocks is
> that they are easy to misuse and that hurts power efficiency. (I've
> heard stories of badly written wifi drivers that took 5 minute timed
> wakelocks on packets, which effectively kept devices from ever sleeping).

In this case, I am more confident that this would actually simplify
code that much, so we can get around all the scary pitfalls.

I can only think of one case which could lead to problem. If there is
a host driver, enabled for wakeup, that gets spurious card detect
irqs, outside the window were you expect a card to be
detected/removed, and at the same time do not have a software
mechanism to "debounce" the irqs. But, should we even consider this as
a valid case?

Kind regards
Ulf Hansson

>
> So if possible, its much better to have a normal path where the pm_relax
> is called in most cases, using the timeout for only the few places where
> you really can't get an end point.
>
> thanks
> -john
--
To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Zoran Markovic Oct. 10, 2013, 6:41 p.m. UTC | #9
I like the simplified approach taken in this patch. Shortening the
awake time by trying to call __pm_relax() in all corner cases turned
out to be too complex.

Reviewed-by: Zoran Markovic <zoran.markovic@linaro.org>

Regards, Zoran

On 1 October 2013 02:22, Ulf Hansson <ulf.hansson@linaro.org> wrote:
> Hi John,
>
>> So how does the notification done to userspace? I wonder if you could
>> use the select/lock/read style method for releasing the kernel space
>> wakeup_source, as is done in the input layer?
>
> If I understand what you mean correctly, it is very similar what Zoran
> tried to do before in his patch!?
>
> For the mmc subsystem, especially considering the pitfalls around the
> scheduled detect work, I think it will be hard to get this right, if
> implementing like this. I fear we might end up in situations were the
> wakeup_source is never "relaxed".
>
>>
>>
>>> Not sure how to set the time-out value to meet all expectations. I
>>> believe we could also consider that inserting/removing a card is a
>>> quite seldom operation, so using a bit higher value than necessary
>>> might be okay. What do you think?
>>
>> As long as its sure to be *very* rare, then slightly longer delays
>> aren't a major problem.  The trouble with the timeout style wakelocks is
>> that they are easy to misuse and that hurts power efficiency. (I've
>> heard stories of badly written wifi drivers that took 5 minute timed
>> wakelocks on packets, which effectively kept devices from ever sleeping).
>
> In this case, I am more confident that this would actually simplify
> code that much, so we can get around all the scary pitfalls.
>
> I can only think of one case which could lead to problem. If there is
> a host driver, enabled for wakeup, that gets spurious card detect
> irqs, outside the window were you expect a card to be
> detected/removed, and at the same time do not have a software
> mechanism to "debounce" the irqs. But, should we even consider this as
> a valid case?
>
> Kind regards
> Ulf Hansson
>
>>
>> So if possible, its much better to have a normal path where the pm_relax
>> is called in most cases, using the timeout for only the few places where
>> you really can't get an end point.
>>
>> thanks
>> -john
--
To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
diff mbox

Patch

diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index bf18b6b..3e8229e 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -23,6 +23,7 @@ 
 #include <linux/log2.h>
 #include <linux/regulator/consumer.h>
 #include <linux/pm_runtime.h>
+#include <linux/pm_wakeup.h>
 #include <linux/suspend.h>
 #include <linux/fault-inject.h>
 #include <linux/random.h>
@@ -1723,6 +1724,28 @@  void mmc_detach_bus(struct mmc_host *host)
 	mmc_bus_put(host);
 }
 
+static void _mmc_detect_change(struct mmc_host *host, unsigned long delay,
+				bool cd_irq)
+{
+#ifdef CONFIG_MMC_DEBUG
+	unsigned long flags;
+	spin_lock_irqsave(&host->lock, flags);
+	WARN_ON(host->removed);
+	spin_unlock_irqrestore(&host->lock, flags);
+#endif
+
+	/*
+	 * If the device is configured as wakeup, we prevent a new sleep for
+	 * 5 s to give provision for user space to consume the event.
+	 */
+	if (cd_irq && !(host->caps & MMC_CAP_NEEDS_POLL) &&
+		device_can_wakeup(mmc_dev(host)))
+		pm_wakeup_event(mmc_dev(host), 5000);
+
+	host->detect_change = 1;
+	mmc_schedule_delayed_work(&host->detect, delay);
+}
+
 /**
  *	mmc_detect_change - process change of state on a MMC socket
  *	@host: host which changed state.
@@ -1735,16 +1758,8 @@  void mmc_detach_bus(struct mmc_host *host)
  */
 void mmc_detect_change(struct mmc_host *host, unsigned long delay)
 {
-#ifdef CONFIG_MMC_DEBUG
-	unsigned long flags;
-	spin_lock_irqsave(&host->lock, flags);
-	WARN_ON(host->removed);
-	spin_unlock_irqrestore(&host->lock, flags);
-#endif
-	host->detect_change = 1;
-	mmc_schedule_delayed_work(&host->detect, delay);
+	_mmc_detect_change(host, delay, true);
 }
-
 EXPORT_SYMBOL(mmc_detect_change);
 
 void mmc_init_erase(struct mmc_card *card)
@@ -2423,7 +2438,7 @@  int mmc_detect_card_removed(struct mmc_host *host)
 			 * rescan handle the card removal.
 			 */
 			cancel_delayed_work(&host->detect);
-			mmc_detect_change(host, 0);
+			_mmc_detect_change(host, 0, false);
 		}
 	}
 
@@ -2505,7 +2520,7 @@  void mmc_start_host(struct mmc_host *host)
 		mmc_power_off(host);
 	else
 		mmc_power_up(host);
-	mmc_detect_change(host, 0);
+	_mmc_detect_change(host, 0, false);
 }
 
 void mmc_stop_host(struct mmc_host *host)
@@ -2724,7 +2739,7 @@  int mmc_pm_notify(struct notifier_block *notify_block,
 		spin_lock_irqsave(&host->lock, flags);
 		host->rescan_disable = 0;
 		spin_unlock_irqrestore(&host->lock, flags);
-		mmc_detect_change(host, 0);
+		_mmc_detect_change(host, 0, false);
 
 	}