diff mbox

[v1,07/12] scsi: ufs: add option to change default UFS power management level

Message ID 1481590462-9981-1-git-send-email-subhashj@codeaurora.org (mailing list archive)
State Superseded, archived
Headers show

Commit Message

subhashj@codeaurora.org Dec. 13, 2016, 12:54 a.m. UTC
UFS device and link can be put in multiple different low power modes hence
UFS driver supports multiple different low power modes. By default UFS
driver selects the default (optimal) low power mode (which gives moderate
power savings and have relatively less enter and exit latencies) but
we might have to tune this default power mode for different chipset
platforms to meet the low power requirements/goals. Hence this patch
adds option to change default UFS low power mode (level).

Reviewed-by: Yaniv Gardi <ygardi@codeaurora.org>
Signed-off-by: Subhash Jadavani <subhashj@codeaurora.org>
---
 .../devicetree/bindings/ufs/ufshcd-pltfrm.txt      | 10 ++++++
 drivers/scsi/ufs/ufshcd-pltfrm.c                   | 14 ++++++++
 drivers/scsi/ufs/ufshcd.c                          | 39 ++++++++++++++++++++++
 drivers/scsi/ufs/ufshcd.h                          |  4 +--
 4 files changed, 65 insertions(+), 2 deletions(-)

Comments

Rob Herring (Arm) Dec. 13, 2016, 8:04 p.m. UTC | #1
On Mon, Dec 12, 2016 at 04:54:20PM -0800, Subhash Jadavani wrote:
> UFS device and link can be put in multiple different low power modes hence
> UFS driver supports multiple different low power modes. By default UFS
> driver selects the default (optimal) low power mode (which gives moderate
> power savings and have relatively less enter and exit latencies) but
> we might have to tune this default power mode for different chipset
> platforms to meet the low power requirements/goals. Hence this patch
> adds option to change default UFS low power mode (level).
> 
> Reviewed-by: Yaniv Gardi <ygardi@codeaurora.org>
> Signed-off-by: Subhash Jadavani <subhashj@codeaurora.org>
> ---
>  .../devicetree/bindings/ufs/ufshcd-pltfrm.txt      | 10 ++++++
>  drivers/scsi/ufs/ufshcd-pltfrm.c                   | 14 ++++++++
>  drivers/scsi/ufs/ufshcd.c                          | 39 ++++++++++++++++++++++
>  drivers/scsi/ufs/ufshcd.h                          |  4 +--
>  4 files changed, 65 insertions(+), 2 deletions(-)
> 
> diff --git a/Documentation/devicetree/bindings/ufs/ufshcd-pltfrm.txt b/Documentation/devicetree/bindings/ufs/ufshcd-pltfrm.txt
> index a99ed55..c3836c5 100644
> --- a/Documentation/devicetree/bindings/ufs/ufshcd-pltfrm.txt
> +++ b/Documentation/devicetree/bindings/ufs/ufshcd-pltfrm.txt
> @@ -41,6 +41,14 @@ Optional properties:
>  -lanes-per-direction	: number of lanes available per direction - either 1 or 2.
>  			  Note that it is assume same number of lanes is used both
>  			  directions at once. If not specified, default is 2 lanes per direction.
> +- rpm-level		: UFS Runtime power management level. Following PM levels are supported:
> +			  0 - Both UFS device and Link in active state (Highest power consumption)
> +			  1 - UFS device in active state but Link in Hibern8 state
> +			  2 - UFS device in Sleep state but Link in active state
> +			  3 - UFS device in Sleep state and Link in hibern8 state (default PM level)
> +			  4 - UFS device in Power-down state and Link in Hibern8 state
> +			  5 - UFS device in Power-down state and Link in OFF state (Lowest power consumption)
> +- spm-level		: UFS System power management level. Allowed PM levels are same as rpm-level.

This looks like you are putting policy for Linux into DT.

What I would expect to see here is disabling of states that don't work 
due to some h/w limitation. Otherwise, it is a user decision for what 
modes to go into. Also, I think link and device states should be 
separate.

Rob
--
To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
subhashj@codeaurora.org Dec. 13, 2016, 8:16 p.m. UTC | #2
On 2016-12-13 12:04, Rob Herring wrote:
> On Mon, Dec 12, 2016 at 04:54:20PM -0800, Subhash Jadavani wrote:
>> UFS device and link can be put in multiple different low power modes 
>> hence
>> UFS driver supports multiple different low power modes. By default UFS
>> driver selects the default (optimal) low power mode (which gives 
>> moderate
>> power savings and have relatively less enter and exit latencies) but
>> we might have to tune this default power mode for different chipset
>> platforms to meet the low power requirements/goals. Hence this patch
>> adds option to change default UFS low power mode (level).
>> 
>> Reviewed-by: Yaniv Gardi <ygardi@codeaurora.org>
>> Signed-off-by: Subhash Jadavani <subhashj@codeaurora.org>
>> ---
>>  .../devicetree/bindings/ufs/ufshcd-pltfrm.txt      | 10 ++++++
>>  drivers/scsi/ufs/ufshcd-pltfrm.c                   | 14 ++++++++
>>  drivers/scsi/ufs/ufshcd.c                          | 39 
>> ++++++++++++++++++++++
>>  drivers/scsi/ufs/ufshcd.h                          |  4 +--
>>  4 files changed, 65 insertions(+), 2 deletions(-)
>> 
>> diff --git a/Documentation/devicetree/bindings/ufs/ufshcd-pltfrm.txt 
>> b/Documentation/devicetree/bindings/ufs/ufshcd-pltfrm.txt
>> index a99ed55..c3836c5 100644
>> --- a/Documentation/devicetree/bindings/ufs/ufshcd-pltfrm.txt
>> +++ b/Documentation/devicetree/bindings/ufs/ufshcd-pltfrm.txt
>> @@ -41,6 +41,14 @@ Optional properties:
>>  -lanes-per-direction	: number of lanes available per direction - 
>> either 1 or 2.
>>  			  Note that it is assume same number of lanes is used both
>>  			  directions at once. If not specified, default is 2 lanes per 
>> direction.
>> +- rpm-level		: UFS Runtime power management level. Following PM 
>> levels are supported:
>> +			  0 - Both UFS device and Link in active state (Highest power 
>> consumption)
>> +			  1 - UFS device in active state but Link in Hibern8 state
>> +			  2 - UFS device in Sleep state but Link in active state
>> +			  3 - UFS device in Sleep state and Link in hibern8 state (default 
>> PM level)
>> +			  4 - UFS device in Power-down state and Link in Hibern8 state
>> +			  5 - UFS device in Power-down state and Link in OFF state (Lowest 
>> power consumption)
>> +- spm-level		: UFS System power management level. Allowed PM levels 
>> are same as rpm-level.
> 
> This looks like you are putting policy for Linux into DT.
> 
> What I would expect to see here is disabling of states that don't work
> due to some h/w limitation. Otherwise, it is a user decision for what
> modes to go into. Also, I think link and device states should be
> separate.

Yes, generally default level (3) is good enough (and recommended) for 
all platforms and most likely user is only expected to change this if 
they see issues (most H/W) on their platform or they want even more 
aggressive power state (level-4 or level-5) and ready to take the 
performance hit associated with resume latencies.

Also, I think it is better to keep Link and device states tied, one 
reason is that we can't keep device in sleep/active state when Link is 
in OFF state.

> 
> Rob
Rob Herring (Arm) Dec. 19, 2016, 6:38 p.m. UTC | #3
On Tue, Dec 13, 2016 at 2:16 PM, Subhash Jadavani
<subhashj@codeaurora.org> wrote:
> On 2016-12-13 12:04, Rob Herring wrote:
>>
>> On Mon, Dec 12, 2016 at 04:54:20PM -0800, Subhash Jadavani wrote:
>>>
>>> UFS device and link can be put in multiple different low power modes
>>> hence
>>> UFS driver supports multiple different low power modes. By default UFS
>>> driver selects the default (optimal) low power mode (which gives moderate
>>> power savings and have relatively less enter and exit latencies) but
>>> we might have to tune this default power mode for different chipset
>>> platforms to meet the low power requirements/goals. Hence this patch
>>> adds option to change default UFS low power mode (level).
>>>
>>> Reviewed-by: Yaniv Gardi <ygardi@codeaurora.org>
>>> Signed-off-by: Subhash Jadavani <subhashj@codeaurora.org>
>>> ---
>>>  .../devicetree/bindings/ufs/ufshcd-pltfrm.txt      | 10 ++++++
>>>  drivers/scsi/ufs/ufshcd-pltfrm.c                   | 14 ++++++++
>>>  drivers/scsi/ufs/ufshcd.c                          | 39
>>> ++++++++++++++++++++++
>>>  drivers/scsi/ufs/ufshcd.h                          |  4 +--
>>>  4 files changed, 65 insertions(+), 2 deletions(-)
>>>
>>> diff --git a/Documentation/devicetree/bindings/ufs/ufshcd-pltfrm.txt
>>> b/Documentation/devicetree/bindings/ufs/ufshcd-pltfrm.txt
>>> index a99ed55..c3836c5 100644
>>> --- a/Documentation/devicetree/bindings/ufs/ufshcd-pltfrm.txt
>>> +++ b/Documentation/devicetree/bindings/ufs/ufshcd-pltfrm.txt
>>> @@ -41,6 +41,14 @@ Optional properties:
>>>  -lanes-per-direction   : number of lanes available per direction -
>>> either 1 or 2.
>>>                           Note that it is assume same number of lanes is
>>> used both
>>>                           directions at once. If not specified, default
>>> is 2 lanes per direction.
>>> +- rpm-level            : UFS Runtime power management level. Following
>>> PM levels are supported:
>>> +                         0 - Both UFS device and Link in active state
>>> (Highest power consumption)
>>> +                         1 - UFS device in active state but Link in
>>> Hibern8 state
>>> +                         2 - UFS device in Sleep state but Link in
>>> active state
>>> +                         3 - UFS device in Sleep state and Link in
>>> hibern8 state (default PM level)
>>> +                         4 - UFS device in Power-down state and Link in
>>> Hibern8 state
>>> +                         5 - UFS device in Power-down state and Link in
>>> OFF state (Lowest power consumption)
>>> +- spm-level            : UFS System power management level. Allowed PM
>>> levels are same as rpm-level.
>>
>>
>> This looks like you are putting policy for Linux into DT.
>>
>> What I would expect to see here is disabling of states that don't work
>> due to some h/w limitation. Otherwise, it is a user decision for what
>> modes to go into. Also, I think link and device states should be
>> separate.
>
>
> Yes, generally default level (3) is good enough (and recommended) for all
> platforms and most likely user is only expected to change this if they see
> issues (most H/W) on their platform or they want even more aggressive power
> state (level-4 or level-5) and ready to take the performance hit associated
> with resume latencies.

What latencies can be tolerated is going to depend on the application
and could vary while running, so putting in DT doesn't make sense. I
would break down settings like this:

broken h/w -> DT
user tuning/config -> sysfs
sensible defaults -> driver

> Also, I think it is better to keep Link and device states tied, one reason
> is that we can't keep device in sleep/active state when Link is in OFF
> state.

The driver can tie the states to together if needed. Just document
what's broken in DT and let the driver make decisions.

Rob
--
To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
subhashj@codeaurora.org Dec. 20, 2016, 7:36 p.m. UTC | #4
On 2016-12-19 10:38, Rob Herring wrote:
> On Tue, Dec 13, 2016 at 2:16 PM, Subhash Jadavani
> <subhashj@codeaurora.org> wrote:
>> On 2016-12-13 12:04, Rob Herring wrote:
>>> 
>>> On Mon, Dec 12, 2016 at 04:54:20PM -0800, Subhash Jadavani wrote:
>>>> 
>>>> UFS device and link can be put in multiple different low power modes
>>>> hence
>>>> UFS driver supports multiple different low power modes. By default 
>>>> UFS
>>>> driver selects the default (optimal) low power mode (which gives 
>>>> moderate
>>>> power savings and have relatively less enter and exit latencies) but
>>>> we might have to tune this default power mode for different chipset
>>>> platforms to meet the low power requirements/goals. Hence this patch
>>>> adds option to change default UFS low power mode (level).
>>>> 
>>>> Reviewed-by: Yaniv Gardi <ygardi@codeaurora.org>
>>>> Signed-off-by: Subhash Jadavani <subhashj@codeaurora.org>
>>>> ---
>>>>  .../devicetree/bindings/ufs/ufshcd-pltfrm.txt      | 10 ++++++
>>>>  drivers/scsi/ufs/ufshcd-pltfrm.c                   | 14 ++++++++
>>>>  drivers/scsi/ufs/ufshcd.c                          | 39
>>>> ++++++++++++++++++++++
>>>>  drivers/scsi/ufs/ufshcd.h                          |  4 +--
>>>>  4 files changed, 65 insertions(+), 2 deletions(-)
>>>> 
>>>> diff --git a/Documentation/devicetree/bindings/ufs/ufshcd-pltfrm.txt
>>>> b/Documentation/devicetree/bindings/ufs/ufshcd-pltfrm.txt
>>>> index a99ed55..c3836c5 100644
>>>> --- a/Documentation/devicetree/bindings/ufs/ufshcd-pltfrm.txt
>>>> +++ b/Documentation/devicetree/bindings/ufs/ufshcd-pltfrm.txt
>>>> @@ -41,6 +41,14 @@ Optional properties:
>>>>  -lanes-per-direction   : number of lanes available per direction -
>>>> either 1 or 2.
>>>>                           Note that it is assume same number of 
>>>> lanes is
>>>> used both
>>>>                           directions at once. If not specified, 
>>>> default
>>>> is 2 lanes per direction.
>>>> +- rpm-level            : UFS Runtime power management level. 
>>>> Following
>>>> PM levels are supported:
>>>> +                         0 - Both UFS device and Link in active 
>>>> state
>>>> (Highest power consumption)
>>>> +                         1 - UFS device in active state but Link in
>>>> Hibern8 state
>>>> +                         2 - UFS device in Sleep state but Link in
>>>> active state
>>>> +                         3 - UFS device in Sleep state and Link in
>>>> hibern8 state (default PM level)
>>>> +                         4 - UFS device in Power-down state and 
>>>> Link in
>>>> Hibern8 state
>>>> +                         5 - UFS device in Power-down state and 
>>>> Link in
>>>> OFF state (Lowest power consumption)
>>>> +- spm-level            : UFS System power management level. Allowed 
>>>> PM
>>>> levels are same as rpm-level.
>>> 
>>> 
>>> This looks like you are putting policy for Linux into DT.
>>> 
>>> What I would expect to see here is disabling of states that don't 
>>> work
>>> due to some h/w limitation. Otherwise, it is a user decision for what
>>> modes to go into. Also, I think link and device states should be
>>> separate.
>> 
>> 
>> Yes, generally default level (3) is good enough (and recommended) for 
>> all
>> platforms and most likely user is only expected to change this if they 
>> see
>> issues (most H/W) on their platform or they want even more aggressive 
>> power
>> state (level-4 or level-5) and ready to take the performance hit 
>> associated
>> with resume latencies.
> 
> What latencies can be tolerated is going to depend on the application
> and could vary while running, so putting in DT doesn't make sense. I
> would break down settings like this:
> 
> broken h/w -> DT
> user tuning/config -> sysfs
> sensible defaults -> driver

Make sense.
we already have #2 and #3 in place, will rework this patch so we have a 
way to specify what is broken in h/w.

> 
>> Also, I think it is better to keep Link and device states tied, one 
>> reason
>> is that we can't keep device in sleep/active state when Link is in OFF
>> state.
> 
> The driver can tie the states to together if needed. Just document
> what's broken in DT and let the driver make decisions.

Yes, agreed.  will rework this patch so we have a way to specify what is 
broken in h/w and separate the device and link states (something like 
broken-hibern8, broken-sleep etc.)
Thanks for the suggestions.

> 
> Rob
diff mbox

Patch

diff --git a/Documentation/devicetree/bindings/ufs/ufshcd-pltfrm.txt b/Documentation/devicetree/bindings/ufs/ufshcd-pltfrm.txt
index a99ed55..c3836c5 100644
--- a/Documentation/devicetree/bindings/ufs/ufshcd-pltfrm.txt
+++ b/Documentation/devicetree/bindings/ufs/ufshcd-pltfrm.txt
@@ -41,6 +41,14 @@  Optional properties:
 -lanes-per-direction	: number of lanes available per direction - either 1 or 2.
 			  Note that it is assume same number of lanes is used both
 			  directions at once. If not specified, default is 2 lanes per direction.
+- rpm-level		: UFS Runtime power management level. Following PM levels are supported:
+			  0 - Both UFS device and Link in active state (Highest power consumption)
+			  1 - UFS device in active state but Link in Hibern8 state
+			  2 - UFS device in Sleep state but Link in active state
+			  3 - UFS device in Sleep state and Link in hibern8 state (default PM level)
+			  4 - UFS device in Power-down state and Link in Hibern8 state
+			  5 - UFS device in Power-down state and Link in OFF state (Lowest power consumption)
+- spm-level		: UFS System power management level. Allowed PM levels are same as rpm-level.
 
 Note: If above properties are not defined it can be assumed that the supply
 regulators or clocks are always on.
@@ -66,4 +74,6 @@  Example:
 		freq-table-hz = <100000000 200000000>, <0 0>, <0 0>;
 		phys = <&ufsphy1>;
 		phy-names = "ufsphy";
+		rpm-level = <3>;
+		spm-level = <5>;
 	};
diff --git a/drivers/scsi/ufs/ufshcd-pltfrm.c b/drivers/scsi/ufs/ufshcd-pltfrm.c
index a72a4ba..896943d 100644
--- a/drivers/scsi/ufs/ufshcd-pltfrm.c
+++ b/drivers/scsi/ufs/ufshcd-pltfrm.c
@@ -223,6 +223,19 @@  static int ufshcd_parse_regulator_info(struct ufs_hba *hba)
 	return err;
 }
 
+static void ufshcd_parse_pm_levels(struct ufs_hba *hba)
+{
+	struct device *dev = hba->dev;
+	struct device_node *np = dev->of_node;
+
+	if (np) {
+		if (of_property_read_u32(np, "rpm-level", &hba->rpm_lvl))
+			hba->rpm_lvl = -1;
+		if (of_property_read_u32(np, "spm-level", &hba->spm_lvl))
+			hba->spm_lvl = -1;
+	}
+}
+
 #ifdef CONFIG_PM
 /**
  * ufshcd_pltfrm_suspend - suspend power management function
@@ -342,6 +355,7 @@  int ufshcd_pltfrm_init(struct platform_device *pdev,
 		goto dealloc_host;
 	}
 
+	ufshcd_parse_pm_levels(hba);
 	pm_runtime_set_active(&pdev->dev);
 	pm_runtime_enable(&pdev->dev);
 
diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index 470ea99..43f9b44 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -191,6 +191,22 @@  enum {
 	return ufs_pm_lvl_states[lvl].link_state;
 }
 
+static inline enum ufs_pm_level
+ufs_get_desired_pm_lvl_for_dev_link_state(enum ufs_dev_pwr_mode dev_state,
+					enum uic_link_state link_state)
+{
+	enum ufs_pm_level lvl;
+
+	for (lvl = UFS_PM_LVL_0; lvl < UFS_PM_LVL_MAX; lvl++) {
+		if ((ufs_pm_lvl_states[lvl].dev_state == dev_state) &&
+			(ufs_pm_lvl_states[lvl].link_state == link_state))
+			return lvl;
+	}
+
+	/* if no match found, return the level 0 */
+	return UFS_PM_LVL_0;
+}
+
 static struct ufs_dev_fix ufs_fixups[] = {
 	/* UFS cards deviations table */
 	UFS_FIX(UFS_VENDOR_SAMSUNG, UFS_ANY_MODEL,
@@ -215,6 +231,14 @@  enum {
 	END_FIX
 };
 
+static inline bool ufshcd_is_valid_pm_lvl(int lvl)
+{
+	if (lvl >= 0 && lvl < ARRAY_SIZE(ufs_pm_lvl_states))
+		return true;
+	else
+		return false;
+}
+
 static void ufshcd_tmc_handler(struct ufs_hba *hba);
 static void ufshcd_async_scan(void *data, async_cookie_t cookie);
 static int ufshcd_reset_and_restore(struct ufs_hba *hba);
@@ -7290,6 +7314,21 @@  int ufshcd_init(struct ufs_hba *hba, void __iomem *mmio_base, unsigned int irq)
 		ufshcd_clkscaling_init_sysfs(hba);
 	}
 
+	/*
+	 * If rpm_lvl and and spm_lvl are not already set to valid levels,
+	 * set the default power management level for UFS runtime and system
+	 * suspend. Default power saving mode selected is keeping UFS link in
+	 * Hibern8 state and UFS device in sleep.
+	 */
+	if (!ufshcd_is_valid_pm_lvl(hba->rpm_lvl))
+		hba->rpm_lvl = ufs_get_desired_pm_lvl_for_dev_link_state(
+							UFS_SLEEP_PWR_MODE,
+							UIC_LINK_HIBERN8_STATE);
+	if (!ufshcd_is_valid_pm_lvl(hba->spm_lvl))
+		hba->spm_lvl = ufs_get_desired_pm_lvl_for_dev_link_state(
+							UFS_SLEEP_PWR_MODE,
+							UIC_LINK_HIBERN8_STATE);
+
 	/* Hold auto suspend until async scan completes */
 	pm_runtime_get_sync(dev);
 
diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h
index 787323b..97fbe4a 100644
--- a/drivers/scsi/ufs/ufshcd.h
+++ b/drivers/scsi/ufs/ufshcd.h
@@ -432,9 +432,9 @@  struct ufs_hba {
 	enum ufs_dev_pwr_mode curr_dev_pwr_mode;
 	enum uic_link_state uic_link_state;
 	/* Desired UFS power management level during runtime PM */
-	enum ufs_pm_level rpm_lvl;
+	int rpm_lvl;
 	/* Desired UFS power management level during system PM */
-	enum ufs_pm_level spm_lvl;
+	int spm_lvl;
 	struct device_attribute rpm_lvl_attr;
 	struct device_attribute spm_lvl_attr;
 	int pm_op_in_progress;