[PATCH v1 9/9] scsi: ufs: enable FASTAUTO mode during low load condition

2018-07-06 Thread Asutosh Das
From: Subhash Jadavani 

We are currently running UFS link in HS-G3 FAST mode during high load
condition for best possible performance and in HS-G2 FAST mode during
low load condition to save power. As we are anyway scaling down from
HS-G3 to HS-G2, we can also change the mode from FAST to FASTAUTO.
So we looked at the performance numbers with HS-G2 FASTAUTO mode and
they are good enough for most of the low bandwidth usecases. But Samsung
UFS memory devices are exception which has really low sequential read
throughput in FAST AUTO mode hence we will only be enabling FAST AUTO mode
for other UFS device vendors.

Signed-off-by: Subhash Jadavani 
Signed-off-by: Can Guo 
Signed-off-by: Asutosh Das 
---
 drivers/scsi/ufs/ufshcd.c | 4 
 1 file changed, 4 insertions(+)

diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index 50588cf..a6e43f9 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -1088,6 +1088,10 @@ static int ufshcd_scale_gear(struct ufs_hba *hba, bool 
scale_up)
/* scale down gear */
new_pwr_info.gear_tx = UFS_MIN_GEAR_TO_SCALE_DOWN;
new_pwr_info.gear_rx = UFS_MIN_GEAR_TO_SCALE_DOWN;
+   if (!(hba->dev_quirks & UFS_DEVICE_NO_FASTAUTO)) {
+   new_pwr_info.pwr_tx = FASTAUTO_MODE;
+   new_pwr_info.pwr_rx = FASTAUTO_MODE;
+   }
}
}
 
-- 
Qualcomm India Private Limited, on behalf of Qualcomm Innovation Center, Inc. 
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, a Linux 
Foundation Collaborative Project.



[PATCH v1 4/9] scsi: ufs: add option to change default UFS power management level

2018-07-06 Thread Asutosh Das
From: Subhash Jadavani 

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).

Signed-off-by: Subhash Jadavani 
Signed-off-by: Venkat Gopalakrishnan 
Signed-off-by: Can Guo 
Signed-off-by: Asutosh Das 
---
 .../devicetree/bindings/ufs/ufshcd-pltfrm.txt  | 11 
 drivers/scsi/ufs/ufshcd-pltfrm.c   | 14 +++
 drivers/scsi/ufs/ufshcd.c  | 29 +++---
 drivers/scsi/ufs/ufshcd.h  |  4 +--
 4 files changed, 47 insertions(+), 11 deletions(-)

diff --git a/Documentation/devicetree/bindings/ufs/ufshcd-pltfrm.txt 
b/Documentation/devicetree/bindings/ufs/ufshcd-pltfrm.txt
index c39dfef..f564d9a 100644
--- a/Documentation/devicetree/bindings/ufs/ufshcd-pltfrm.txt
+++ b/Documentation/devicetree/bindings/ufs/ufshcd-pltfrm.txt
@@ -38,6 +38,15 @@ Optional properties:
  defined or a value in the array is "0" then it is 
assumed
  that the frequency is set by the parent clock or a
  fixed rate clock source.
+- 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.
+
 -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.
@@ -66,4 +75,6 @@ Example:
freq-table-hz = <1 2>, <0 0>, <0 0>;
phys = <>;
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 e82bde0..7dba799 100644
--- a/drivers/scsi/ufs/ufshcd-pltfrm.c
+++ b/drivers/scsi/ufs/ufshcd-pltfrm.c
@@ -221,6 +221,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", >rpm_lvl))
+   hba->rpm_lvl = -1;
+   if (of_property_read_u32(np, "spm-level", >spm_lvl))
+   hba->spm_lvl = -1;
+   }
+}
+
 #ifdef CONFIG_PM
 /**
  * ufshcd_pltfrm_suspend - suspend power management function
@@ -340,6 +353,7 @@ int ufshcd_pltfrm_init(struct platform_device *pdev,
goto dealloc_host;
}
 
+   ufshcd_parse_pm_levels(hba);
pm_runtime_set_active(>dev);
pm_runtime_enable(>dev);
 
diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index b03f3ea..e950204 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -192,6 +192,14 @@ struct ufs_pm_lvl_states ufs_pm_lvl_states[] = {
return UFS_PM_LVL_0;
 }
 
+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 struct ufs_dev_fix ufs_fixups[] = {
/* UFS cards deviations table */
UFS_FIX(UFS_VENDOR_SAMSUNG, UFS_ANY_MODEL,
@@ -8051,16 +8059,19 @@ int ufshcd_init(struct ufs_hba *hba, void __iomem 
*mmio_base, unsigned int irq)
}
 
/*
-* Set the default power management level for runtime and system PM.
-* Default power saving mode is to keep UFS link in Hibern8 state
-* and UFS device in sleep state.
+* 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 state.
 

[PATCH v1 6/9] scsi: ufs: optimize clock, pm_qos, hibern8 handling in queuecommand

2018-07-06 Thread Asutosh Das
From: Subhash Jadavani 

ufshcd_queuecommand() vote for the resources in this order: clocks,
pm_qos latency, hibern8 exit. If any of these votes are not already
applied, each one has to be applied asynchronously and in that case we are
releasing all the previously applied resource votes (for example, if
hibern8 exit has to be completed asynchronously, we release the votes for
pm_qos and clocks as well). This is not a optimal solution instead we
should skip scheduling the unvoting work for already voted resources.

Signed-off-by: Subhash Jadavani 
Signed-off-by: Can Guo 
Signed-off-by: Asutosh Das 
---
 drivers/scsi/ufs/ufs-qcom.c |  2 +-
 drivers/scsi/ufs/ufshcd.c   | 33 +
 drivers/scsi/ufs/ufshcd.h   |  2 +-
 3 files changed, 19 insertions(+), 18 deletions(-)

diff --git a/drivers/scsi/ufs/ufs-qcom.c b/drivers/scsi/ufs/ufs-qcom.c
index 221820a..fa01924 100644
--- a/drivers/scsi/ufs/ufs-qcom.c
+++ b/drivers/scsi/ufs/ufs-qcom.c
@@ -1605,7 +1605,7 @@ int ufs_qcom_testbus_config(struct ufs_qcom_host *host)
 * committed before returning.
 */
mb();
-   ufshcd_release(host->hba);
+   ufshcd_release(host->hba, false);
pm_runtime_put_sync(host->hba->dev);
 
return 0;
diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index 8a56ef6..40d9c35 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -1175,7 +1175,7 @@ static int ufshcd_devfreq_scale(struct ufs_hba *hba, bool 
scale_up)
 
 out:
ufshcd_clock_scaling_unprepare(hba);
-   ufshcd_release(hba);
+   ufshcd_release_all(hba);
return ret;
 }
 
@@ -1447,7 +1447,7 @@ static ssize_t ufshcd_clkscale_enable_store(struct device 
*dev,
__func__, err);
}
 
-   ufshcd_release(hba);
+   ufshcd_release(hba, false);
pm_runtime_put_sync(hba->dev);
 out:
return count;
@@ -1662,7 +1662,7 @@ static void ufshcd_gate_work(struct work_struct *work)
 }
 
 /* host lock must be held before calling this variant */
-static void __ufshcd_release(struct ufs_hba *hba)
+static void __ufshcd_release(struct ufs_hba *hba, bool no_sched)
 {
if (!ufshcd_is_clkgating_allowed(hba))
return;
@@ -1673,7 +1673,7 @@ static void __ufshcd_release(struct ufs_hba *hba)
|| hba->ufshcd_state != UFSHCD_STATE_OPERATIONAL
|| hba->lrb_in_use || hba->outstanding_tasks
|| hba->active_uic_cmd || hba->uic_async_done
-   || ufshcd_eh_in_progress(hba))
+   || ufshcd_eh_in_progress(hba) || no_sched)
return;
 
hba->clk_gating.state = REQ_CLKS_OFF;
@@ -1682,12 +1682,12 @@ static void __ufshcd_release(struct ufs_hba *hba)
msecs_to_jiffies(hba->clk_gating.delay_ms));
 }
 
-void ufshcd_release(struct ufs_hba *hba)
+void ufshcd_release(struct ufs_hba *hba, bool no_sched)
 {
unsigned long flags;
 
spin_lock_irqsave(hba->host->host_lock, flags);
-   __ufshcd_release(hba);
+   __ufshcd_release(hba, no_sched);
spin_unlock_irqrestore(hba->host->host_lock, flags);
 }
 EXPORT_SYMBOL_GPL(ufshcd_release);
@@ -1738,7 +1738,7 @@ static ssize_t ufshcd_clkgate_enable_store(struct device 
*dev,
goto out;
 
if (value) {
-   ufshcd_release(hba);
+   ufshcd_release(hba, false);
} else {
spin_lock_irqsave(hba->host->host_lock, flags);
hba->clk_gating.active_reqs++;
@@ -1870,7 +1870,7 @@ int ufshcd_hibern8_hold(struct ufs_hba *hba, bool async)
 }
 
 /* host lock must be held before calling this variant */
-static void __ufshcd_hibern8_release(struct ufs_hba *hba)
+static void __ufshcd_hibern8_release(struct ufs_hba *hba, bool no_sched)
 {
unsigned long delay_in_jiffies;
 
@@ -1884,7 +1884,8 @@ static void __ufshcd_hibern8_release(struct ufs_hba *hba)
|| hba->hibern8_on_idle.is_suspended
|| hba->ufshcd_state != UFSHCD_STATE_OPERATIONAL
|| hba->lrb_in_use || hba->outstanding_tasks
-   || hba->active_uic_cmd || hba->uic_async_done)
+   || hba->active_uic_cmd || hba->uic_async_done
+   || ufshcd_eh_in_progress(hba) || no_sched)
return;
 
hba->hibern8_on_idle.state = REQ_HIBERN8_ENTER;
@@ -1907,12 +1908,12 @@ static void __ufshcd_hibern8_release(struct ufs_hba 
*hba)
  delay_in_jiffies);
 }
 
-void ufshcd_hibern8_release(struct ufs_hba *hba)
+void ufshcd_hibern8_release(struct ufs_hba *hba, bool no_sched)
 {
unsigned long flags;
 
spin_lock_irqsave(hba->host->host_lock, flags);
-   __ufshcd_hibern8_release(hba);
+   __ufshcd_hibern8_release(hba, no_sched);
spin_unlock_irqrestore(hba->host->host_lock, flags);
 }
 
@@ -2034,8 +2035,8 @@ static void ufshcd_hold_all(struct ufs_hba *hba)
 
 static void 

[PATCH v1 2/9] scsi: Allow auto suspend override by low-level driver

2018-07-06 Thread Asutosh Das
From: Sujit Reddy Thumma 

Until now the scsi mid-layer forbids runtime suspend till userspace
enables it. This is mainly to quarantine some disks with broken
runtime power management or have high latencies executing suspend
resume callbacks. If the userspace doesn't enable the runtime suspend
the underlying hardware will be always on even when it is not doing
any useful work and thus wasting power.

Some low-level drivers for the controllers can efficiently use runtime
power management to reduce power consumption and improve battery life.
Allow runtime suspend parameters override within the LLD itself
instead of waiting for userspace to control the power management.

Signed-off-by: Sujit Reddy Thumma 
Signed-off-by: Subhash Jadavani 
Signed-off-by: Asutosh Das 
---
 drivers/scsi/scsi_scan.c   | 4 
 drivers/scsi/scsi_sysfs.c  | 3 ++-
 drivers/scsi/sd.c  | 2 ++
 include/scsi/scsi_device.h | 3 +++
 4 files changed, 11 insertions(+), 1 deletion(-)

diff --git a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c
index 0880d97..5b7232a 100644
--- a/drivers/scsi/scsi_scan.c
+++ b/drivers/scsi/scsi_scan.c
@@ -969,6 +969,10 @@ static int scsi_add_lun(struct scsi_device *sdev, unsigned 
char *inq_result,
 
transport_configure_device(>sdev_gendev);
 
+   /* The LLD can override auto suspend tunables in ->slave_configure() */
+   sdev->use_rpm_auto = 0;
+   sdev->autosuspend_delay = SCSI_DEFAULT_AUTOSUSPEND_DELAY;
+
if (sdev->host->hostt->slave_configure) {
ret = sdev->host->hostt->slave_configure(sdev);
if (ret) {
diff --git a/drivers/scsi/scsi_sysfs.c b/drivers/scsi/scsi_sysfs.c
index 7943b76..706e778 100644
--- a/drivers/scsi/scsi_sysfs.c
+++ b/drivers/scsi/scsi_sysfs.c
@@ -1266,7 +1266,8 @@ int scsi_sysfs_add_sdev(struct scsi_device *sdev)
device_enable_async_suspend(>sdev_gendev);
scsi_autopm_get_target(starget);
pm_runtime_set_active(>sdev_gendev);
-   pm_runtime_forbid(>sdev_gendev);
+   if (!sdev->use_rpm_auto)
+   pm_runtime_forbid(>sdev_gendev);
pm_runtime_enable(>sdev_gendev);
scsi_autopm_put_target(starget);
 
diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c
index a6201e6..205624f 100644
--- a/drivers/scsi/sd.c
+++ b/drivers/scsi/sd.c
@@ -3269,6 +3269,8 @@ static void sd_probe_async(void *data, async_cookie_t 
cookie)
}
 
blk_pm_runtime_init(sdp->request_queue, dev);
+   if (sdp->autosuspend_delay >= 0)
+   pm_runtime_set_autosuspend_delay(dev, sdp->autosuspend_delay);
device_add_disk(dev, gd);
if (sdkp->capacity)
sd_dif_config_host(sdkp);
diff --git a/include/scsi/scsi_device.h b/include/scsi/scsi_device.h
index 4c36af6..1d5ae90 100644
--- a/include/scsi/scsi_device.h
+++ b/include/scsi/scsi_device.h
@@ -197,7 +197,10 @@ struct scsi_device {
unsigned broken_fua:1;  /* Don't set FUA bit */
unsigned lun_in_cdb:1;  /* Store LUN bits in CDB[1] */
unsigned unmap_limit_for_ws:1;  /* Use the UNMAP limit for WRITE SAME */
+   unsigned use_rpm_auto:1; /* Enable runtime PM auto suspend */
 
+#define SCSI_DEFAULT_AUTOSUSPEND_DELAY  -1
+   int autosuspend_delay;
atomic_t disk_events_disable_depth; /* disable depth for disk events */
 
DECLARE_BITMAP(supported_events, SDEV_EVT_MAXBITS); /* supported events 
*/
-- 
Qualcomm India Private Limited, on behalf of Qualcomm Innovation Center, Inc. 
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, a Linux 
Foundation Collaborative Project.



[PATCH v1 8/9] scsi: ufs: enable runtime pm only after ufshcd init

2018-07-06 Thread Asutosh Das
From: Gilad Broner 

Previous code enables runtime pm before ufshcd_init() is completed,
and before the hba struct is stored in the platform device private
data. This means that pm runtime calls will have null hba pointer
as well as partially initialized driver.
Instead, enable pm runtime only after ufshcd_init() is done and
after hba struct is stored in the platform device private data.

Signed-off-by: Gilad Broner 
Signed-off-by: Can Guo 
Signed-off-by: Asutosh Das 
---
 drivers/scsi/ufs/ufshcd-pltfrm.c | 11 ---
 1 file changed, 4 insertions(+), 7 deletions(-)

diff --git a/drivers/scsi/ufs/ufshcd-pltfrm.c b/drivers/scsi/ufs/ufshcd-pltfrm.c
index 7dba799..8332d99 100644
--- a/drivers/scsi/ufs/ufshcd-pltfrm.c
+++ b/drivers/scsi/ufs/ufshcd-pltfrm.c
@@ -354,24 +354,21 @@ int ufshcd_pltfrm_init(struct platform_device *pdev,
}
 
ufshcd_parse_pm_levels(hba);
-   pm_runtime_set_active(>dev);
-   pm_runtime_enable(>dev);
 
ufshcd_init_lanes_per_dir(hba);
 
err = ufshcd_init(hba, mmio_base, irq);
if (err) {
dev_err(dev, "Initialization failed\n");
-   goto out_disable_rpm;
+   goto dealloc_host;
}
 
platform_set_drvdata(pdev, hba);
 
-   return 0;
+   pm_runtime_set_active(>dev);
+   pm_runtime_enable(>dev);
 
-out_disable_rpm:
-   pm_runtime_disable(>dev);
-   pm_runtime_set_suspended(>dev);
+   return 0;
 dealloc_host:
ufshcd_dealloc_host(hba);
 out:
-- 
Qualcomm India Private Limited, on behalf of Qualcomm Innovation Center, Inc. 
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, a Linux 
Foundation Collaborative Project.



[PATCH v1 5/9] scsi: ufs: add support for hibern8 on idle

2018-07-06 Thread Asutosh Das
From: Subhash Jadavani 

In order to save power we should put the UFS link into hibern8 as soon as
UFS link is idle and power measurement of active usecases (like audio/video
playback/recording) show that putting UFS link in hibern8 @ 10ms of idle
(if not earlier) would save significant power.

Our current available solution is to do hibern8 with clock gating @idle
timeout of 150ms. As clock gating has huge latencies (7ms each in enter and
exit), we cannot bring down the idle timeout to <=10ms without degrading
UFS throughput. Hence this change has added support to enter into hibern8
with another idle timer.

Signed-off-by: Subhash Jadavani 
Signed-off-by: Can Guo 
Signed-off-by: Asutosh Das 
---
 drivers/scsi/ufs/ufshcd.c  | 372 -
 drivers/scsi/ufs/ufshcd.h  |  39 +
 include/trace/events/ufs.h |  20 +++
 3 files changed, 397 insertions(+), 34 deletions(-)

diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index e950204..8a56ef6 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -246,6 +246,8 @@ static int __ufshcd_setup_clocks(struct ufs_hba *hba, bool 
on,
 static irqreturn_t ufshcd_intr(int irq, void *__hba);
 static int ufshcd_change_power_mode(struct ufs_hba *hba,
 struct ufs_pa_layer_attr *pwr_mode);
+static void ufshcd_hold_all(struct ufs_hba *hba);
+static void ufshcd_release_all(struct ufs_hba *hba);
 static inline bool ufshcd_valid_tag(struct ufs_hba *hba, int tag)
 {
return tag >= 0 && tag < hba->nutrs;
@@ -853,6 +855,18 @@ static inline bool ufshcd_is_hba_active(struct ufs_hba 
*hba)
? false : true;
 }
 
+static const char *ufshcd_hibern8_on_idle_state_to_string(
+   enum ufshcd_hibern8_on_idle_state state)
+{
+   switch (state) {
+   case HIBERN8_ENTERED:   return "HIBERN8_ENTERED";
+   case HIBERN8_EXITED:return "HIBERN8_EXITED";
+   case REQ_HIBERN8_ENTER: return "REQ_HIBERN8_ENTER";
+   case REQ_HIBERN8_EXIT:  return "REQ_HIBERN8_EXIT";
+   default:return "UNKNOWN_STATE";
+   }
+}
+
 u32 ufshcd_get_local_unipro_ver(struct ufs_hba *hba)
 {
/* HCI version 1.0 and 1.1 supports UniPro 1.41 */
@@ -993,7 +1007,7 @@ static int ufshcd_wait_for_doorbell_clr(struct ufs_hba 
*hba,
bool timeout = false, do_last_check = false;
ktime_t start;
 
-   ufshcd_hold(hba, false);
+   ufshcd_hold_all(hba);
spin_lock_irqsave(hba->host->host_lock, flags);
/*
 * Wait for all the outstanding tasks/transfer requests.
@@ -1038,7 +1052,7 @@ static int ufshcd_wait_for_doorbell_clr(struct ufs_hba 
*hba,
}
 out:
spin_unlock_irqrestore(hba->host->host_lock, flags);
-   ufshcd_release(hba);
+   ufshcd_release_all(hba);
return ret;
 }
 
@@ -1601,8 +1615,16 @@ static void ufshcd_gate_work(struct work_struct *work)
 
spin_unlock_irqrestore(hba->host->host_lock, flags);
 
+   if (ufshcd_is_hibern8_on_idle_allowed(hba))
+   /*
+* Hibern8 enter work (on Idle) needs clocks to be ON hence
+* make sure that it is flushed before turning off the clocks.
+*/
+   flush_delayed_work(>hibern8_on_idle.enter_work);
+
/* put the link into hibern8 mode before turning off clocks */
-   if (ufshcd_can_hibern8_during_gating(hba)) {
+   if (ufshcd_can_hibern8_during_gating(hba) &&
+   ufshcd_is_link_active(hba)) {
if (ufshcd_uic_hibern8_enter(hba)) {
hba->clk_gating.state = CLKS_ON;
trace_ufshcd_clk_gating(dev_name(hba->dev),
@@ -1732,6 +1754,8 @@ static void ufshcd_init_clk_gating(struct ufs_hba *hba)
 {
char wq_name[sizeof("ufs_clk_gating_00")];
 
+   hba->clk_gating.state = CLKS_ON;
+
if (!ufshcd_is_clkgating_allowed(hba))
return;
 
@@ -1774,6 +1798,246 @@ static void ufshcd_exit_clk_gating(struct ufs_hba *hba)
destroy_workqueue(hba->clk_gating.clk_gating_workq);
 }
 
+/**
+ * ufshcd_hibern8_hold - Make sure that link is not in hibern8.
+ *
+ * @hba: per adapter instance
+ * @async: This indicates whether caller wants to exit hibern8 asynchronously.
+ *
+ * Exit from hibern8 mode and set the link as active.
+ *
+ * Return 0 on success, non-zero on failure.
+ */
+int ufshcd_hibern8_hold(struct ufs_hba *hba, bool async)
+{
+   int rc = 0;
+   unsigned long flags;
+
+   if (!ufshcd_is_hibern8_on_idle_allowed(hba))
+   goto out;
+
+   spin_lock_irqsave(hba->host->host_lock, flags);
+   hba->hibern8_on_idle.active_reqs++;
+
+start:
+   switch (hba->hibern8_on_idle.state) {
+   case HIBERN8_EXITED:
+   break;
+   case REQ_HIBERN8_ENTER:
+   if (cancel_delayed_work(>hibern8_on_idle.enter_work)) {
+   

[PATCH v1 3/9] scsi: ufs: Override auto suspend tunables for ufs

2018-07-06 Thread Asutosh Das
From: Sujit Reddy Thumma 

Override auto suspend tunables for UFS device LUNs during
initialization so as to efficiently manage background operations
and the power consumption.

Signed-off-by: Sujit Reddy Thumma 
Signed-off-by: Gilad Broner 
Signed-off-by: Asutosh Das 
---
 drivers/scsi/ufs/ufshcd.c | 6 ++
 1 file changed, 6 insertions(+)

diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index 77e2b3e..b03f3ea 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -89,6 +89,9 @@
 /* Interrupt aggregation default timeout, unit: 40us */
 #define INT_AGGR_DEF_TO0x02
 
+/* default value of auto suspend is 3 seconds */
+#define UFSHCD_AUTO_SUSPEND_DELAY_MS 3000 /* millisecs */
+
 #define ufshcd_toggle_vreg(_dev, _vreg, _on)   \
({  \
int _ret;   \
@@ -4528,6 +4531,9 @@ static int ufshcd_slave_configure(struct scsi_device 
*sdev)
blk_queue_update_dma_pad(q, PRDT_DATA_BYTE_COUNT_PAD - 1);
blk_queue_max_segment_size(q, PRDT_DATA_BYTE_COUNT_MAX);
 
+   sdev->autosuspend_delay = UFSHCD_AUTO_SUSPEND_DELAY_MS;
+   sdev->use_rpm_auto = 1;
+
return 0;
 }
 
-- 
Qualcomm India Private Limited, on behalf of Qualcomm Innovation Center, Inc. 
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, a Linux 
Foundation Collaborative Project.



[PATCH v1 0/9] UFS: Fixes and enhancements

2018-07-06 Thread Asutosh Das
This patch series adds some enhancements and fixes to UFS driver.

Gilad Broner (1):
  scsi: ufs: enable runtime pm only after ufshcd init

Subhash Jadavani (6):
  scsi: ufs: add support to allow non standard behaviours (quirks)
  scsi: ufs: add option to change default UFS power management level
  scsi: ufs: add support for hibern8 on idle
  scsi: ufs: optimize clock, pm_qos, hibern8 handling in queuecommand
  scsi: ufs: add UFS power collapse support during hibern8
  scsi: ufs: enable FASTAUTO mode during low load condition

Sujit Reddy Thumma (2):
  scsi: Allow auto suspend override by low-level driver
  scsi: ufs: Override auto suspend tunables for ufs

 .../devicetree/bindings/ufs/ufshcd-pltfrm.txt  |  11 +
 drivers/scsi/scsi_scan.c   |   4 +
 drivers/scsi/scsi_sysfs.c  |   3 +-
 drivers/scsi/sd.c  |   2 +
 drivers/scsi/ufs/ufs-qcom.c|   2 +-
 drivers/scsi/ufs/ufshcd-pltfrm.c   |  25 +-
 drivers/scsi/ufs/ufshcd.c  | 436 ++---
 drivers/scsi/ufs/ufshcd.h  |  61 ++-
 include/scsi/scsi_device.h |   3 +
 include/trace/events/ufs.h |  20 +
 10 files changed, 501 insertions(+), 66 deletions(-)

-- 
Qualcomm India Private Limited, on behalf of Qualcomm Innovation Center, Inc. 
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, a Linux 
Foundation Collaborative Project.



[PATCH v1 1/9] scsi: ufs: add support to allow non standard behaviours (quirks)

2018-07-06 Thread Asutosh Das
From: Subhash Jadavani 

Some implementation of UFS host controller HW might have some
non-standard behaviours (quirks) when compared to behaviour
specified by UFSHCI specification. This patch adds a quirk
for broken hibernate support.

Signed-off-by: Subhash Jadavani 
Signed-off-by: Can Guo 
Signed-off-by: Asutosh Das 
---
 drivers/scsi/ufs/ufshcd.h | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h
index f51758f..e996a08 100644
--- a/drivers/scsi/ufs/ufshcd.h
+++ b/drivers/scsi/ufs/ufshcd.h
@@ -613,6 +613,9 @@ struct ufs_hba {
 * enabled via HCE register.
 */
#define UFSHCI_QUIRK_BROKEN_HCE 0x400
+
+   /* HIBERN8 support is broken */
+   #define UFSHCD_QUIRK_BROKEN_HIBERN8 0x800
unsigned int quirks;/* Deviations from standard UFSHCI spec. */
 
/* Device deviations from standard UFS device spec. */
-- 
Qualcomm India Private Limited, on behalf of Qualcomm Innovation Center, Inc. 
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, a Linux 
Foundation Collaborative Project.



[PATCH v1 7/9] scsi: ufs: add UFS power collapse support during hibern8

2018-07-06 Thread Asutosh Das
From: Subhash Jadavani 

UFS host controller hardware may allow the host controller
to be power collapsed when UFS link is hibern8 state, this
change allows the UFS host controller to be power collapsed
during hibern8.

Signed-off-by: Subhash Jadavani 
Signed-off-by: Venkat Gopalakrishnan 
Signed-off-by: Can Guo 
Signed-off-by: Asutosh Das 
---
 drivers/scsi/ufs/ufshcd.c |  8 ++--
 drivers/scsi/ufs/ufshcd.h | 13 -
 2 files changed, 18 insertions(+), 3 deletions(-)

diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index 40d9c35..50588cf 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -7673,13 +7673,17 @@ static int ufshcd_vreg_set_hpm(struct ufs_hba *hba)
 
 static void ufshcd_hba_vreg_set_lpm(struct ufs_hba *hba)
 {
-   if (ufshcd_is_link_off(hba))
+   if (ufshcd_is_link_off(hba) ||
+   (ufshcd_is_link_hibern8(hba)
+&& ufshcd_is_power_collapse_during_hibern8_allowed(hba)))
ufshcd_setup_hba_vreg(hba, false);
 }
 
 static void ufshcd_hba_vreg_set_hpm(struct ufs_hba *hba)
 {
-   if (ufshcd_is_link_off(hba))
+   if (ufshcd_is_link_off(hba) ||
+   (ufshcd_is_link_hibern8(hba)
+&& ufshcd_is_power_collapse_during_hibern8_allowed(hba)))
ufshcd_setup_hba_vreg(hba, true);
 }
 
diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h
index f79a639..8c5f987 100644
--- a/drivers/scsi/ufs/ufshcd.h
+++ b/drivers/scsi/ufs/ufshcd.h
@@ -728,7 +728,12 @@ struct ufs_hba {
 * to do background operation when it's active but it might degrade
 * the performance of ongoing read/write operations.
 */
-#define UFSHCD_CAP_KEEP_AUTO_BKOPS_ENABLED_EXCEPT_SUSPEND (1 << 5)
+#define UFSHCD_CAP_KEEP_AUTO_BKOPS_ENABLED_EXCEPT_SUSPEND (1 << 6)
+   /*
+* If host controller hardware can be power collapsed when UFS link is
+* in hibern8 then enable this cap.
+*/
+#define UFSHCD_CAP_POWER_COLLAPSE_DURING_HIBERN8 (1 << 7)
 
struct devfreq *devfreq;
struct ufs_clk_scaling clk_scaling;
@@ -764,6 +769,12 @@ static inline bool 
ufshcd_is_hibern8_on_idle_allowed(struct ufs_hba *hba)
return hba->caps & UFSHCD_CAP_HIBERN8_ENTER_ON_IDLE;
 }
 
+static inline bool ufshcd_is_power_collapse_during_hibern8_allowed(
+   struct ufs_hba *hba)
+{
+   return !!(hba->caps & UFSHCD_CAP_POWER_COLLAPSE_DURING_HIBERN8);
+}
+
 static inline bool ufshcd_is_intr_aggr_allowed(struct ufs_hba *hba)
 {
 /* DWC UFS Core has the Interrupt aggregation feature but is not detectable*/
-- 
Qualcomm India Private Limited, on behalf of Qualcomm Innovation Center, Inc. 
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, a Linux 
Foundation Collaborative Project.



[PATCH V5 0/2] Add ufs provisioning support in driver

2018-07-06 Thread Sayali Lokhande
This patch adds Configfs support to provision ufs device at
runtime. This feature can be primarily useful in factory or
assembly line as some devices may be required to be configured
multiple times during initial system development phase.
Configuration Descriptors can be written multiple times until
bConfigDescrLock attribute is zero.

Configuration descriptor buffer consists of Device and Unit
descriptor configurable parameters which are parsed from vendor
specific provisioning file and then passed via configfs node at
runtime to provision ufs device.

Chages since V4:
1)scsi: ufs: set the device reference clock setting
Used "assigned-clock-rates" DT property to pass required ref clk
frequency.

2)scsi: ufs: Add configfs support for ufs provisioning
Combined previous patch(2) and patch(3) into single patch which
adds configfs provisioning support in driver.
Removed extra sw provisioning related fields (like lun_to_grow,
commit) and its related code.
Updated Documentation to match configuration descriptor buffer
parameters to be passed as per specs. Removed global ufs_hba ptr
added in ufs-configfs file and instead passed *hba in ufs configfs
init()/store()/show() api's. This is to support embedded as well as
removable ufs card provisioning via configfs.

Changes since V3:
1)scsi: ufs: set the device reference clock setting
  Updated logic to retain default ref_clk frequency setting
  programmed in device in case if invalid value is passed via
  devicetree setting.
  Replaced of_property_read_u32() with device_property_read_u32().
  Removed invalid checks.

2)scsi: ufs: Add ufs provisioning support
  Added pm_runtime_get/put_sync and scsi_block/unblock_request
  in runtime provisioning for stable operation.
 
3)scsi: ufs: Add configfs support for ufs provisioning
  Updated Documentation with missing buffer entries required for
  runtime provisioning. Used config option to support conditional
  compilation for configfs api's.

Changes since V2:
Added configfs support for ufs provisioning and removed sysfs
support.

Changes since V1:
Added device tree entry to parse reference clock frequency
instead of hardcoding 19.2 MHz, as it can vary for different
vendors. Also removed setting ref_clk again during runtime
provisioning as it will be already set during probe.
Used get_unaligned_be*/put_unaligned_be* where applicable.

Changes since RFC:
Added check to avoid ufs runtime provisioning if
Configuration decriptor lock attribute is set to one.
Instead of parsing ref_clk frequency via device tree, used
correct enum ref_clk_freq value(19.2 Mhz for proviosioning).
Added config_descriptor sysfs entry to provision ufs and also
updated documentation for its correct usage.
Added more protection against bad data handling in sysfs code.

Sayali Lokhande (1):
  scsi: ufs: Add configfs support for ufs provisioning

Subhash Jadavani (1):
  scsi: ufs: set the device reference clock setting

 Documentation/ABI/testing/configfs-driver-ufs  |  18 +++
 .../devicetree/bindings/ufs/ufshcd-pltfrm.txt  |   7 +
 drivers/scsi/ufs/Makefile  |   1 +
 drivers/scsi/ufs/ufs-configfs.c| 172 +
 drivers/scsi/ufs/ufs.h |   9 ++
 drivers/scsi/ufs/ufshcd-pltfrm.c   |   2 +
 drivers/scsi/ufs/ufshcd.c  |  64 
 drivers/scsi/ufs/ufshcd.h  |  21 +++
 8 files changed, 294 insertions(+)
 create mode 100644 Documentation/ABI/testing/configfs-driver-ufs
 create mode 100644 drivers/scsi/ufs/ufs-configfs.c

-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project