[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

[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, fl

[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

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



Re: [PATCH 1/4] scsi: ufs: add quirk to fix mishandling utrlclr/utmrlclr

2018-05-16 Thread Asutosh Das (asd)

On 5/6/2018 3:44 PM, Alim Akhtar wrote:

In the right behavior, setting the bit to '0' indicates clear and
'1' indicates no change. If host controller handles this the other way,
UFSHCI_QUIRK_BROKEN_REQ_LIST_CLR can be used.

Signed-off-by: Seungwon Jeon 
Signed-off-by: Alim Akhtar 
---
  drivers/scsi/ufs/ufshcd.c | 21 +++--
  drivers/scsi/ufs/ufshcd.h |  5 +
  2 files changed, 24 insertions(+), 2 deletions(-)

diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index 00e7905..9898ce5 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -675,7 +675,24 @@ static inline void ufshcd_put_tm_slot(struct ufs_hba *hba, 
int slot)
   */
  static inline void ufshcd_utrl_clear(struct ufs_hba *hba, u32 pos)
  {
-   ufshcd_writel(hba, ~(1 << pos), REG_UTP_TRANSFER_REQ_LIST_CLEAR);
+   if (hba->quirks & UFSHCI_QUIRK_BROKEN_REQ_LIST_CLR)
+   ufshcd_writel(hba, (1 << pos), REG_UTP_TRANSFER_REQ_LIST_CLEAR);
+   else
+   ufshcd_writel(hba, ~(1 << pos),
+   REG_UTP_TRANSFER_REQ_LIST_CLEAR);
+}
+
+/**
+ * ufshcd_utmrl_clear - Clear a bit in UTRMLCLR register
+ * @hba: per adapter instance
+ * @pos: position of the bit to be cleared
+ */
+static inline void ufshcd_utmrl_clear(struct ufs_hba *hba, u32 pos)
+{
+   if (hba->quirks & UFSHCI_QUIRK_BROKEN_REQ_LIST_CLR)
+   ufshcd_writel(hba, (1 << pos), REG_UTP_TASK_REQ_LIST_CLEAR);
+   else
+   ufshcd_writel(hba, ~(1 << pos), REG_UTP_TASK_REQ_LIST_CLEAR);
  }
  
  /**

@@ -5398,7 +5415,7 @@ static int ufshcd_clear_tm_cmd(struct ufs_hba *hba, int 
tag)
goto out;
  
  	spin_lock_irqsave(hba->host->host_lock, flags);

-   ufshcd_writel(hba, ~(1 << tag), REG_UTP_TASK_REQ_LIST_CLEAR);
+   ufshcd_utmrl_clear(hba, tag);
spin_unlock_irqrestore(hba->host->host_lock, flags);
  
  	/* poll for max. 1 sec to clear door bell register by h/w */

diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h
index 8110dcd..43035f8 100644
--- a/drivers/scsi/ufs/ufshcd.h
+++ b/drivers/scsi/ufs/ufshcd.h
@@ -595,6 +595,11 @@ struct ufs_hba {
 */
#define UFSHCD_QUIRK_PRDT_BYTE_GRAN 0x80
  
+	/*

+* Cleaer handling for transfer/task request list is just opposite.
+*/

Spell check - should be 'Clear'

+   #define UFSHCI_QUIRK_BROKEN_REQ_LIST_CLR0x100
+
unsigned int quirks;/* Deviations from standard UFSHCI spec. */
  
  	/* Device deviations from standard UFS device spec. */




Looks good to me, except the spell-check.

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


[PATCH v2 10/10] scsi: ufs: Add clock ungating to a separate workqueue

2018-05-03 Thread Asutosh Das
From: Vijay Viswanath <vvisw...@codeaurora.org>

UFS driver can receive a request during memory reclaim by kswapd.
So when ufs driver puts the ungate work in queue, and if there are no
idle workers, kthreadd is invoked to create a new kworker. Since
kswapd task holds a mutex which kthreadd also needs, this can cause
a deadlock situation. So ungate work must be done in a separate
work queue with WQ_MEM_RECLAIM flag enabled.
Such a workqueue will have a rescue thread which will be called
when the above deadlock condition is possible.

Signed-off-by: Vijay Viswanath <vvisw...@codeaurora.org>
Signed-off-by: Can Guo <c...@codeaurora.org>
Signed-off-by: Asutosh Das <asuto...@codeaurora.org>
---
 drivers/scsi/ufs/ufshcd.c | 11 ++-
 drivers/scsi/ufs/ufshcd.h |  1 +
 2 files changed, 11 insertions(+), 1 deletion(-)

diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index 557d538..3be61b7 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -1483,7 +1483,8 @@ int ufshcd_hold(struct ufs_hba *hba, bool async)
hba->clk_gating.state = REQ_CLKS_ON;
trace_ufshcd_clk_gating(dev_name(hba->dev),
hba->clk_gating.state);
-   schedule_work(>clk_gating.ungate_work);
+   queue_work(hba->clk_gating.clk_gating_workq,
+  >clk_gating.ungate_work);
/*
 * fall through to check if we should wait for this
 * work to be done or not.
@@ -1669,6 +1670,8 @@ static ssize_t ufshcd_clkgate_enable_store(struct device 
*dev,
 
 static void ufshcd_init_clk_gating(struct ufs_hba *hba)
 {
+   char wq_name[sizeof("ufs_clk_gating_00")];
+
if (!ufshcd_is_clkgating_allowed(hba))
return;
 
@@ -1676,6 +1679,11 @@ static void ufshcd_init_clk_gating(struct ufs_hba *hba)
INIT_DELAYED_WORK(>clk_gating.gate_work, ufshcd_gate_work);
INIT_WORK(>clk_gating.ungate_work, ufshcd_ungate_work);
 
+   snprintf(wq_name, ARRAY_SIZE(wq_name), "ufs_clk_gating_%d",
+hba->host->host_no);
+   hba->clk_gating.clk_gating_workq = alloc_ordered_workqueue(wq_name,
+  WQ_MEM_RECLAIM);
+
hba->clk_gating.is_enabled = true;
 
hba->clk_gating.delay_attr.show = ufshcd_clkgate_delay_show;
@@ -1703,6 +1711,7 @@ static void ufshcd_exit_clk_gating(struct ufs_hba *hba)
device_remove_file(hba->dev, >clk_gating.enable_attr);
cancel_work_sync(>clk_gating.ungate_work);
cancel_delayed_work_sync(>clk_gating.gate_work);
+   destroy_workqueue(hba->clk_gating.clk_gating_workq);
 }
 
 /* Must be called with host lock acquired */
diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h
index 76c31d5..2e6bdc0 100644
--- a/drivers/scsi/ufs/ufshcd.h
+++ b/drivers/scsi/ufs/ufshcd.h
@@ -361,6 +361,7 @@ struct ufs_clk_gating {
struct device_attribute enable_attr;
bool is_enabled;
int active_reqs;
+   struct workqueue_struct *clk_gating_workq;
 };
 
 struct ufs_saved_pwr_info {
-- 
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 v2 02/10] scsi: ufs-qcom: Enable UFSHCD_QUIRK_BROKEN_PWR_MODE_CHANGE quirk

2018-05-03 Thread Asutosh Das
Enable UFSHCD_QUIRK_BROKEN_PWR_MODE_CHANGE quirk to avoid failures
in seen on some UFS devices.

Signed-off-by: Asutosh Das <asuto...@codeaurora.org>
---
 drivers/scsi/ufs/ufs-qcom.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/scsi/ufs/ufs-qcom.c b/drivers/scsi/ufs/ufs-qcom.c
index 4563d2e..d9edef8 100644
--- a/drivers/scsi/ufs/ufs-qcom.c
+++ b/drivers/scsi/ufs/ufs-qcom.c
@@ -1105,7 +1105,7 @@ static void ufs_qcom_advertise_quirks(struct ufs_hba *hba)
 
if (host->hw_ver.major >= 0x2) {
hba->quirks |= UFSHCD_QUIRK_BROKEN_UFS_HCI_VERSION;
-
+   hba->quirks |= UFSHCD_QUIRK_BROKEN_PWR_MODE_CHANGE;
if (!ufs_qcom_cap_qunipro(host))
/* Legacy UniPro mode still need following quirks */
hba->quirks |= (UFSHCD_QUIRK_DELAY_BEFORE_DME_CMDS
-- 
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 v2 01/10] scsi: ufs: Allowing power mode change

2018-05-03 Thread Asutosh Das
From: Yaniv Gardi <yga...@codeaurora.org>

Due to M-PHY issues, moving from HS to any other mode or gear or
even Hibern8 may cause some un-predicted behavior
of the device.
This patch adds provides a quirk to address that.

Signed-off-by: Yaniv Gardi <yga...@codeaurora.org>
Signed-off-by: Subhash Jadavani <subha...@codeaurora.org>
Signed-off-by: Can Guo <c...@codeaurora.org>
Signed-off-by: Asutosh Das <asuto...@codeaurora.org>
---
 drivers/scsi/ufs/ufshcd.c | 8 +++-
 drivers/scsi/ufs/ufshcd.h | 7 +++
 2 files changed, 14 insertions(+), 1 deletion(-)

diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index 5bc9dc1..f3083fe 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -4162,9 +4162,15 @@ static int ufshcd_link_startup(struct ufs_hba *hba)
goto out;
} while (ret && retries--);
 
-   if (ret)
+   if (ret) {
/* failed to get the link up... retire */
goto out;
+   }
+
+   if (hba->quirks & UFSHCD_QUIRK_BROKEN_PWR_MODE_CHANGE) {
+   ufshcd_dme_set(hba, UIC_ARG_MIB(TX_LCC_ENABLE), 0);
+   ufshcd_dme_set(hba, UIC_ARG_MIB(TX_LCC_ENABLE), 1);
+   }
 
if (link_startup_again) {
link_startup_again = false;
diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h
index cbe46f6..bb4ecfb 100644
--- a/drivers/scsi/ufs/ufshcd.h
+++ b/drivers/scsi/ufs/ufshcd.h
@@ -591,6 +591,13 @@ struct ufs_hba {
 */
#define UFSHCD_QUIRK_PRDT_BYTE_GRAN UFS_BIT(7)
 
+   /*
+* Needs to be enabled if moving from HS to any other gear/mode or even
+* hibern8 causes unpredicted behavior of device.
+* If this quirk is enabled, standard UFS driver will disable/enable
+* TX_LCC.
+*/
+   #define UFSHCD_QUIRK_BROKEN_PWR_MODE_CHANGE UFS_BIT(8)
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 v2 06/10] scsi: ufs: add reference counting for scsi block requests

2018-05-03 Thread Asutosh Das
From: Subhash Jadavani <subha...@codeaurora.org>

Currently we call the scsi_block_requests()/scsi_unblock_requests()
whenever we want to block/unblock scsi requests but as there is no
reference counting, nesting of these calls could leave us in undesired
state sometime. Consider following call flow sequence:
1. func1() calls scsi_block_requests() but calls func2() before
   calling scsi_unblock_requests()
2. func2() calls scsi_block_requests()
3. func2() calls scsi_unblock_requests()
4. func1() calls scsi_unblock_requests()

As there is no reference counting, we will have scsi requests unblocked
after #3 instead of it to be unblocked only after #4. Though we may not
have failures seen with this, we might run into some failures in future.
Better solution would be to fix this by adding reference counting.

Signed-off-by: Subhash Jadavani <subha...@codeaurora.org>
Signed-off-by: Can Guo <c...@codeaurora.org>
Signed-off-by: Asutosh Das <asuto...@codeaurora.org>
---
 drivers/scsi/ufs/ufshcd.c | 28 
 drivers/scsi/ufs/ufshcd.h |  2 ++
 2 files changed, 22 insertions(+), 8 deletions(-)

diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index dfeb194..c35a076 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -264,6 +264,18 @@ static inline void ufshcd_disable_irq(struct ufs_hba *hba)
}
 }
 
+static void ufshcd_scsi_unblock_requests(struct ufs_hba *hba)
+{
+   if (atomic_dec_and_test(>scsi_block_reqs_cnt))
+   scsi_unblock_requests(hba->host);
+}
+
+static void ufshcd_scsi_block_requests(struct ufs_hba *hba)
+{
+   if (atomic_inc_return(>scsi_block_reqs_cnt) == 1)
+   scsi_block_requests(hba->host);
+}
+
 /* replace non-printable or non-ASCII characters with spaces */
 static inline void ufshcd_remove_non_printable(char *val)
 {
@@ -1077,12 +1089,12 @@ static int ufshcd_clock_scaling_prepare(struct ufs_hba 
*hba)
 * make sure that there are no outstanding requests when
 * clock scaling is in progress
 */
-   scsi_block_requests(hba->host);
+   ufshcd_scsi_block_requests(hba);
down_write(>clk_scaling_lock);
if (ufshcd_wait_for_doorbell_clr(hba, DOORBELL_CLR_TOUT_US)) {
ret = -EBUSY;
up_write(>clk_scaling_lock);
-   scsi_unblock_requests(hba->host);
+   ufshcd_scsi_unblock_requests(hba);
}
 
return ret;
@@ -1091,7 +1103,7 @@ static int ufshcd_clock_scaling_prepare(struct ufs_hba 
*hba)
 static void ufshcd_clock_scaling_unprepare(struct ufs_hba *hba)
 {
up_write(>clk_scaling_lock);
-   scsi_unblock_requests(hba->host);
+   ufshcd_scsi_unblock_requests(hba);
 }
 
 /**
@@ -1411,7 +1423,7 @@ static void ufshcd_ungate_work(struct work_struct *work)
hba->clk_gating.is_suspended = false;
}
 unblock_reqs:
-   scsi_unblock_requests(hba->host);
+   ufshcd_scsi_unblock_requests(hba);
 }
 
 /**
@@ -1467,7 +1479,7 @@ int ufshcd_hold(struct ufs_hba *hba, bool async)
 * work and to enable clocks.
 */
case CLKS_OFF:
-   scsi_block_requests(hba->host);
+   ufshcd_scsi_block_requests(hba);
hba->clk_gating.state = REQ_CLKS_ON;
trace_ufshcd_clk_gating(dev_name(hba->dev),
hba->clk_gating.state);
@@ -5192,7 +5204,7 @@ static void ufshcd_err_handler(struct work_struct *work)
 
 out:
spin_unlock_irqrestore(hba->host->host_lock, flags);
-   scsi_unblock_requests(hba->host);
+   ufshcd_scsi_unblock_requests(hba);
ufshcd_release(hba);
pm_runtime_put_sync(hba->dev);
 }
@@ -5294,7 +5306,7 @@ static void ufshcd_check_errors(struct ufs_hba *hba)
/* handle fatal errors only when link is functional */
if (hba->ufshcd_state == UFSHCD_STATE_OPERATIONAL) {
/* block commands from scsi mid-layer */
-   scsi_block_requests(hba->host);
+   ufshcd_scsi_block_requests(hba);
 
hba->ufshcd_state = UFSHCD_STATE_EH_SCHEDULED;
 
@@ -8017,7 +8029,7 @@ int ufshcd_init(struct ufs_hba *hba, void __iomem 
*mmio_base, unsigned int irq)
 
/* Hold auto suspend until async scan completes */
pm_runtime_get_sync(dev);
-
+   atomic_set(>scsi_block_reqs_cnt, 0);
/*
 * We are assuming that device wasn't put in sleep/power-down
 * state exclusively during the boot stage before kernel.
diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h
index 0417c42..76c31d5 100644
--- a/drivers/scsi/ufs/ufshcd.h
+++ b/drivers/scsi/ufs/ufshcd.h
@@ -498,6 +498,7 @@ struct ufs_stats {
  * @urgent_bkops_lvl: keeps track of urgent bkops level for device
  * @is_urgent_bkops_lvl_checked:

[PATCH v2 04/10] scsi: ufs: fix exception event handling

2018-05-03 Thread Asutosh Das
From: Maya Erez <me...@codeaurora.org>

The device can set the exception event bit in one of the response UPIU,
for example to notify the need for urgent BKOPs operation.
In such a case the host driver calls ufshcd_exception_event_handler to
handle this notification.
When trying to check the exception event status (for finding the cause for
the exception event), the device may be busy with additional SCSI commands
handling and may not respond within the 100ms timeout.

To prevent that, we need to block SCSI commands during handling of
exception events and allow retransmissions of the query requests,
in case of timeout.

Signed-off-by: Subhash Jadavani <subha...@codeaurora.org>
Signed-off-by: Maya Erez <me...@codeaurora.org>
Signed-off-by: Can Guo <c...@codeaurora.org>
Signed-off-by: Asutosh Das <asuto...@codeaurora.org>
---
 drivers/scsi/ufs/ufshcd.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index 6dabce8..838ba8f0 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -4967,6 +4967,7 @@ static void ufshcd_exception_event_handler(struct 
work_struct *work)
hba = container_of(work, struct ufs_hba, eeh_work);
 
pm_runtime_get_sync(hba->dev);
+   scsi_block_requests(hba->host);
err = ufshcd_get_ee_status(hba, );
if (err) {
dev_err(hba->dev, "%s: failed to get exception status %d\n",
@@ -4980,6 +4981,7 @@ static void ufshcd_exception_event_handler(struct 
work_struct *work)
ufshcd_bkops_exception_event_handler(hba);
 
 out:
+   scsi_unblock_requests(hba->host);
pm_runtime_put_sync(hba->dev);
return;
 }
-- 
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 v2 08/10] scsi: ufs: make sure all interrupts are processed

2018-05-03 Thread Asutosh Das
From: Venkat Gopalakrishnan <venk...@codeaurora.org>

As multiple requests are submitted to the ufs host controller in
parallel there could be instances where the command completion
interrupt arrives later for a request that is already processed
earlier as the corresponding doorbell was cleared when handling
the previous interrupt. Read the interrupt status in a loop after
processing the received interrupt to catch such interrupts and
handle it.

Signed-off-by: Venkat Gopalakrishnan <venk...@codeaurora.org>
Signed-off-by: Asutosh Das <asuto...@codeaurora.org>
---
 drivers/scsi/ufs/ufshcd.c | 27 +++
 1 file changed, 19 insertions(+), 8 deletions(-)

diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index c35a076..09b7a3f 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -5383,19 +5383,30 @@ static irqreturn_t ufshcd_intr(int irq, void *__hba)
u32 intr_status, enabled_intr_status;
irqreturn_t retval = IRQ_NONE;
struct ufs_hba *hba = __hba;
+   int retries = hba->nutrs;
 
spin_lock(hba->host->host_lock);
intr_status = ufshcd_readl(hba, REG_INTERRUPT_STATUS);
-   enabled_intr_status =
-   intr_status & ufshcd_readl(hba, REG_INTERRUPT_ENABLE);
 
-   if (intr_status)
-   ufshcd_writel(hba, intr_status, REG_INTERRUPT_STATUS);
+   /*
+* There could be max of hba->nutrs reqs in flight and in worst case
+* if the reqs get finished 1 by 1 after the interrupt status is
+* read, make sure we handle them by checking the interrupt status
+* again in a loop until we process all of the reqs before returning.
+*/
+   do {
+   enabled_intr_status =
+   intr_status & ufshcd_readl(hba, REG_INTERRUPT_ENABLE);
+   if (intr_status)
+   ufshcd_writel(hba, intr_status, REG_INTERRUPT_STATUS);
+   if (enabled_intr_status) {
+   ufshcd_sl_intr(hba, enabled_intr_status);
+   retval = IRQ_HANDLED;
+   }
+
+   intr_status = ufshcd_readl(hba, REG_INTERRUPT_STATUS);
+   } while (intr_status && --retries);
 
-   if (enabled_intr_status) {
-   ufshcd_sl_intr(hba, enabled_intr_status);
-   retval = IRQ_HANDLED;
-   }
spin_unlock(hba->host->host_lock);
return retval;
 }
-- 
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 v2 09/10] scsi: ufs: fix irq return code

2018-05-03 Thread Asutosh Das
From: Venkat Gopalakrishnan <venk...@codeaurora.org>

Return IRQ_HANDLED only if the irq is really handled, this will
help in catching spurious interrupts that go unhandled.

Signed-off-by: Venkat Gopalakrishnan <venk...@codeaurora.org>
Signed-off-by: Can Guo <c...@codeaurora.org>
Signed-off-by: Asutosh Das <asuto...@codeaurora.org>
---
 drivers/scsi/ufs/ufshcd.c | 137 ++
 1 file changed, 101 insertions(+), 36 deletions(-)

diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index 09b7a3f..557d538 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -211,7 +211,7 @@ enum {
END_FIX
 };
 
-static void ufshcd_tmc_handler(struct ufs_hba *hba);
+static irqreturn_t 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);
 static int ufshcd_eh_host_reset_handler(struct scsi_cmnd *cmd);
@@ -4609,19 +4609,29 @@ static int ufshcd_task_req_compl(struct ufs_hba *hba, 
u32 index, u8 *resp)
  * ufshcd_uic_cmd_compl - handle completion of uic command
  * @hba: per adapter instance
  * @intr_status: interrupt status generated by the controller
+ *
+ * Returns
+ *  IRQ_HANDLED - If interrupt is valid
+ *  IRQ_NONE- If invalid interrupt
  */
-static void ufshcd_uic_cmd_compl(struct ufs_hba *hba, u32 intr_status)
+static irqreturn_t ufshcd_uic_cmd_compl(struct ufs_hba *hba, u32 intr_status)
 {
+   irqreturn_t retval = IRQ_NONE;
+
if ((intr_status & UIC_COMMAND_COMPL) && hba->active_uic_cmd) {
hba->active_uic_cmd->argument2 |=
ufshcd_get_uic_cmd_result(hba);
hba->active_uic_cmd->argument3 =
ufshcd_get_dme_attr_val(hba);
complete(>active_uic_cmd->done);
+   retval = IRQ_HANDLED;
}
 
-   if ((intr_status & UFSHCD_UIC_PWR_MASK) && hba->uic_async_done)
+   if ((intr_status & UFSHCD_UIC_PWR_MASK) && hba->uic_async_done) {
complete(hba->uic_async_done);
+   retval = IRQ_HANDLED;
+   }
+   return retval;
 }
 
 /**
@@ -4675,8 +4685,12 @@ static void __ufshcd_transfer_req_compl(struct ufs_hba 
*hba,
 /**
  * ufshcd_transfer_req_compl - handle SCSI and query command completion
  * @hba: per adapter instance
+ *
+ * Returns
+ *  IRQ_HANDLED - If interrupt is valid
+ *  IRQ_NONE- If invalid interrupt
  */
-static void ufshcd_transfer_req_compl(struct ufs_hba *hba)
+static irqreturn_t ufshcd_transfer_req_compl(struct ufs_hba *hba)
 {
unsigned long completed_reqs;
u32 tr_doorbell;
@@ -4694,7 +4708,12 @@ static void ufshcd_transfer_req_compl(struct ufs_hba 
*hba)
tr_doorbell = ufshcd_readl(hba, REG_UTP_TRANSFER_REQ_DOOR_BELL);
completed_reqs = tr_doorbell ^ hba->outstanding_reqs;
 
-   __ufshcd_transfer_req_compl(hba, completed_reqs);
+   if (completed_reqs) {
+   __ufshcd_transfer_req_compl(hba, completed_reqs);
+   return IRQ_HANDLED;
+   } else {
+   return IRQ_NONE;
+   }
 }
 
 /**
@@ -5220,16 +5239,21 @@ static void ufshcd_update_uic_reg_hist(struct 
ufs_uic_err_reg_hist *reg_hist,
 /**
  * ufshcd_update_uic_error - check and set fatal UIC error flags.
  * @hba: per-adapter instance
+ *
+ * Returns
+ *  IRQ_HANDLED - If interrupt is valid
+ *  IRQ_NONE- If invalid interrupt
  */
-static void ufshcd_update_uic_error(struct ufs_hba *hba)
+static irqreturn_t ufshcd_update_uic_error(struct ufs_hba *hba)
 {
u32 reg;
+   irqreturn_t retval = IRQ_NONE;
 
/* PHY layer lane error */
reg = ufshcd_readl(hba, REG_UIC_ERROR_CODE_PHY_ADAPTER_LAYER);
/* Ignore LINERESET indication, as this is not an error */
if ((reg & UIC_PHY_ADAPTER_LAYER_ERROR) &&
-   (reg & UIC_PHY_ADAPTER_LAYER_LANE_ERR_MASK)) {
+   (reg & UIC_PHY_ADAPTER_LAYER_ERROR_CODE_MASK)) {
/*
 * To know whether this error is fatal or not, DB timeout
 * must be checked but this error is handled separately.
@@ -5240,57 +5264,73 @@ static void ufshcd_update_uic_error(struct ufs_hba *hba)
 
/* PA_INIT_ERROR is fatal and needs UIC reset */
reg = ufshcd_readl(hba, REG_UIC_ERROR_CODE_DATA_LINK_LAYER);
-   if (reg)
+   if ((reg & UIC_DATA_LINK_LAYER_ERROR) &&
+   (reg & UIC_DATA_LINK_LAYER_ERROR_CODE_MASK)) {
ufshcd_update_uic_reg_hist(>ufs_stats.dl_err, reg);
-
-   if (reg & UIC_DATA_LINK_LAYER_ERROR_PA_INIT)
-   hba->uic_error |= UFSHCD_UIC_DL_PA_INIT_ERROR;
-   else if (hba->dev_quirks &
-  UFS_DEVICE_QUIRK_RECOVERY_FROM_DL_NAC_ERRORS) {
-   if (reg &a

[PATCH v2 05/10] scsi: ufshcd: fix possible unclocked register access

2018-05-03 Thread Asutosh Das
From: Subhash Jadavani <subha...@codeaurora.org>

vendor specific setup_clocks ops may depend on clocks managed by ufshcd
driver so if the vendor specific setup_clocks callback is called when
the required clocks are turned off, it results into unclocked register
access.

This change make sure that required clocks are enabled before vendor
specific setup_clocks callback is called.

Signed-off-by: Subhash Jadavani <subha...@codeaurora.org>
Signed-off-by: Venkat Gopalakrishnan <venk...@codeaurora.org>
Signed-off-by: Can Guo <c...@codeaurora.org>
Signed-off-by: Asutosh Das <asuto...@codeaurora.org>
---
 drivers/scsi/ufs/ufshcd.c | 26 --
 1 file changed, 20 insertions(+), 6 deletions(-)

diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index 838ba8f0..dfeb194 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -6780,9 +6780,16 @@ static int __ufshcd_setup_clocks(struct ufs_hba *hba, 
bool on,
if (list_empty(head))
goto out;
 
-   ret = ufshcd_vops_setup_clocks(hba, on, PRE_CHANGE);
-   if (ret)
-   return ret;
+   /*
+* vendor specific setup_clocks ops may depend on clocks managed by
+* this standard driver hence call the vendor specific setup_clocks
+* before disabling the clocks managed here.
+*/
+   if (!on) {
+   ret = ufshcd_vops_setup_clocks(hba, on, PRE_CHANGE);
+   if (ret)
+   return ret;
+   }
 
list_for_each_entry(clki, head, list) {
if (!IS_ERR_OR_NULL(clki->clk)) {
@@ -6806,9 +6813,16 @@ static int __ufshcd_setup_clocks(struct ufs_hba *hba, 
bool on,
}
}
 
-   ret = ufshcd_vops_setup_clocks(hba, on, POST_CHANGE);
-   if (ret)
-   return ret;
+   /*
+* vendor specific setup_clocks ops may depend on clocks managed by
+* this standard driver hence call the vendor specific setup_clocks
+* after enabling the clocks managed here.
+*/
+   if (on) {
+   ret = ufshcd_vops_setup_clocks(hba, on, POST_CHANGE);
+   if (ret)
+   return ret;
+   }
 
 out:
if (ret) {
-- 
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 v2 07/10] scsi: ufs-qcom: remove broken hci version quirk

2018-05-03 Thread Asutosh Das
From: Subhash Jadavani <subha...@codeaurora.org>

UFSHCD_QUIRK_BROKEN_UFS_HCI_VERSION is only applicable for QCOM UFS host
controller version 2.x.y and this has been fixed from version 3.x.y
onwards, hence this change removes this quirk for version 3.x.y onwards.

Signed-off-by: Subhash Jadavani <subha...@codeaurora.org>
Signed-off-by: Asutosh Das <asuto...@codeaurora.org>
---
 drivers/scsi/ufs/ufs-qcom.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/scsi/ufs/ufs-qcom.c b/drivers/scsi/ufs/ufs-qcom.c
index d9edef8..27be327 100644
--- a/drivers/scsi/ufs/ufs-qcom.c
+++ b/drivers/scsi/ufs/ufs-qcom.c
@@ -1103,7 +1103,7 @@ static void ufs_qcom_advertise_quirks(struct ufs_hba *hba)
hba->quirks |= UFSHCD_QUIRK_BROKEN_LCC;
}
 
-   if (host->hw_ver.major >= 0x2) {
+   if (host->hw_ver.major == 0x2) {
hba->quirks |= UFSHCD_QUIRK_BROKEN_UFS_HCI_VERSION;
hba->quirks |= UFSHCD_QUIRK_BROKEN_PWR_MODE_CHANGE;
if (!ufs_qcom_cap_qunipro(host))
-- 
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 v2 03/10] scsi: ufs: Add LCC quirk for host and device

2018-05-03 Thread Asutosh Das
LCC (Line Control Command) is being used for communication between
UFS host and UFS device. But some hosts might have the issue with
issuing the LCC commands to UFS device and in this case LCC could be
explicitly disabled.

But there could be a need where we don't want to disable the LCC
on both host & device; hence this change splits the quirk in 2 parts
one for host and one for device.

Signed-off-by: Subhash Jadavani <subha...@codeaurora.org>
Signed-off-by: Venkat Gopalakrishnan <venk...@codeaurora.org>
Signed-off-by: Can Guo <c...@codeaurora.org>
Signed-off-by: Asutosh Das <asuto...@codeaurora.org>
---
 drivers/scsi/ufs/ufshcd.c | 16 
 drivers/scsi/ufs/ufshcd.h | 12 
 2 files changed, 28 insertions(+)

diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index f3083fe..6dabce8 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -4116,6 +4116,11 @@ static int ufshcd_disable_tx_lcc(struct ufs_hba *hba, 
bool peer)
return err;
 }
 
+static inline int ufshcd_disable_host_tx_lcc(struct ufs_hba *hba)
+{
+   return ufshcd_disable_tx_lcc(hba, false);
+}
+
 static inline int ufshcd_disable_device_tx_lcc(struct ufs_hba *hba)
 {
return ufshcd_disable_tx_lcc(hba, true);
@@ -4172,6 +4177,17 @@ static int ufshcd_link_startup(struct ufs_hba *hba)
ufshcd_dme_set(hba, UIC_ARG_MIB(TX_LCC_ENABLE), 1);
}
 
+   if (hba->quirks & UFSHCD_BROKEN_LCC_PROCESSING_ON_HOST) {
+   ret = ufshcd_disable_device_tx_lcc(hba);
+   if (ret)
+   goto out;
+   }
+
+   if (hba->quirks & UFSHCD_BROKEN_LCC_PROCESSING_ON_DEVICE) {
+   ret = ufshcd_disable_host_tx_lcc(hba);
+   if (ret)
+   goto out;
+   }
if (link_startup_again) {
link_startup_again = false;
retries = DME_LINKSTARTUP_RETRIES;
diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h
index bb4ecfb..0417c42 100644
--- a/drivers/scsi/ufs/ufshcd.h
+++ b/drivers/scsi/ufs/ufshcd.h
@@ -598,6 +598,18 @@ struct ufs_hba {
 * TX_LCC.
 */
#define UFSHCD_QUIRK_BROKEN_PWR_MODE_CHANGE UFS_BIT(8)
+
+   /*
+* If UFS device is having issue in processing LCC (Line Control
+* Command) coming from UFS host controller then enable this quirk.
+* When this quirk is enabled, host controller driver should disable
+* the LCC transmission on UFS host controller (by clearing
+* TX_LCC_ENABLE attribute of host to 0).
+*/
+   #define UFSHCD_BROKEN_LCC_PROCESSING_ON_DEVICE  0x100
+
+   #define UFSHCD_BROKEN_LCC_PROCESSING_ON_HOST0x200
+
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 v2 00/10] ufshcd optimizations and fixes

2018-05-03 Thread Asutosh Das
This patch set has a bunch of optimizations for UFS HCI.

Changes since v1:
  Addressed the review comments

Asutosh Das (2):
  scsi: ufs-qcom: Enable UFSHCD_QUIRK_BROKEN_PWR_MODE_CHANGE quirk
  scsi: ufs: Add LCC quirk for host and device

Maya Erez (1):
  scsi: ufs: fix exception event handling

Subhash Jadavani (3):
  scsi: ufshcd: fix possible unclocked register access
  scsi: ufs: add reference counting for scsi block requests
  scsi: ufs-qcom: remove broken hci version quirk

Venkat Gopalakrishnan (2):
  scsi: ufs: make sure all interrupts are processed
  scsi: ufs: fix irq return code

Vijay Viswanath (1):
  scsi: ufs: Add clock ungating to a separate workqueue

Yaniv Gardi (1):
  scsi: ufs: Allowing power mode change

 drivers/scsi/ufs/ufs-qcom.c |   4 +-
 drivers/scsi/ufs/ufshcd.c   | 245 ++--
 drivers/scsi/ufs/ufshcd.h   |  22 
 3 files changed, 214 insertions(+), 57 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.



Re: [PATCH 9/9] scsi: ufs: Add clock ungating to a separate workqueue

2018-02-25 Thread Asutosh Das (asd)

On 2/24/2018 5:27 AM, Miguel Ojeda wrote:

On Wed, Feb 21, 2018 at 5:56 AM, Asutosh Das <asuto...@codeaurora.org> wrote:

From: Vijay Viswanath <vvisw...@codeaurora.org>

UFS driver can receive a request during memory reclaim by kswapd.
So when ufs driver puts the ungate work in queue, and if there are no
idle workers, kthreadd is invoked to create a new kworker. Since
kswapd task holds a mutex which kthreadd also needs, this can cause
a deadlock situation. So ungate work must be done in a separate
work queue with WQ__RECLAIM flag enabled.Such a workqueue will have


WQ_MEM_RECLAIM here. Also space after dot.


a rescue thread which will be called when the above deadlock
condition is possible.

Signed-off-by: Vijay Viswanath <vvisw...@codeaurora.org>
Signed-off-by: Can Guo <c...@codeaurora.org>
Signed-off-by: Asutosh Das <asuto...@codeaurora.org>
---
  drivers/scsi/ufs/ufshcd.c | 10 +-
  drivers/scsi/ufs/ufshcd.h |  1 +
  2 files changed, 10 insertions(+), 1 deletion(-)

diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index 6541e1d..bb3382a 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -1503,7 +1503,8 @@ int ufshcd_hold(struct ufs_hba *hba, bool async)
 hba->clk_gating.state = REQ_CLKS_ON;
 trace_ufshcd_clk_gating(dev_name(hba->dev),
 hba->clk_gating.state);
-   schedule_work(>clk_gating.ungate_work);
+   queue_work(hba->clk_gating.clk_gating_workq,
+  >clk_gating.ungate_work);
 /*
  * fall through to check if we should wait for this
  * work to be done or not.
@@ -1689,6 +1690,8 @@ static ssize_t ufshcd_clkgate_enable_store(struct device 
*dev,

  static void ufshcd_init_clk_gating(struct ufs_hba *hba)
  {
+   char wq_name[sizeof("ufs_clk_gating_00")];
+
 if (!ufshcd_is_clkgating_allowed(hba))
 return;

@@ -1696,6 +1699,10 @@ static void ufshcd_init_clk_gating(struct ufs_hba *hba)
 INIT_DELAYED_WORK(>clk_gating.gate_work, ufshcd_gate_work);
 INIT_WORK(>clk_gating.ungate_work, ufshcd_ungate_work);

+   snprintf(wq_name, ARRAY_SIZE(wq_name), "ufs_clk_gating_%d",
+hba->host->host_no);
+   hba->clk_gating.clk_gating_workq = 
create_singlethread_workqueue(wq_name);


Shouldn't this be alloc_ordered_workqueue() with WQ_MEM_RECLAIM then?
(create_singlethread_workqueue() and friends are deprecated).

Cheers,
Miguel


+
 hba->clk_gating.is_enabled = true;

 hba->clk_gating.delay_attr.show = ufshcd_clkgate_delay_show;
@@ -1723,6 +1730,7 @@ static void ufshcd_exit_clk_gating(struct ufs_hba *hba)
 device_remove_file(hba->dev, >clk_gating.enable_attr);
 cancel_work_sync(>clk_gating.ungate_work);
 cancel_delayed_work_sync(>clk_gating.gate_work);
+   destroy_workqueue(hba->clk_gating.clk_gating_workq);
  }

  /* Must be called with host lock acquired */
diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h
index 4385741..570c33e 100644
--- a/drivers/scsi/ufs/ufshcd.h
+++ b/drivers/scsi/ufs/ufshcd.h
@@ -361,6 +361,7 @@ struct ufs_clk_gating {
 struct device_attribute enable_attr;
 bool is_enabled;
 int active_reqs;
+   struct workqueue_struct *clk_gating_workq;
  };

  struct ufs_saved_pwr_info {
--
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.



Hi Miguel
Thanks for the review.

I'll check this and put up the changes in v2.


-asd

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


Re: [PATCH 1/9] scsi: ufs: Allowing power mode change

2018-02-22 Thread Asutosh Das (asd)

On 2/23/2018 10:40 AM, Kyuho Choi wrote:

Hi Asutosh,

I've simple question in below.

On 2/21/18, Asutosh Das <asuto...@codeaurora.org> wrote:

From: Yaniv Gardi <yga...@codeaurora.org>

Due to M-PHY issues, moving from HS to any other mode or gear or
even Hibern8 causes some un-predicted behavior of the device.
This patch fixes this issues.

Signed-off-by: Yaniv Gardi <yga...@codeaurora.org>
Signed-off-by: Subhash Jadavani <subha...@codeaurora.org>
Signed-off-by: Can Guo <c...@codeaurora.org>
Signed-off-by: Asutosh Das <asuto...@codeaurora.org>
---
  drivers/scsi/ufs/ufshcd.c | 6 +-
  1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index 011c336..d74d529 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -4167,9 +4167,13 @@ static int ufshcd_link_startup(struct ufs_hba *hba)
goto out;
} while (ret && retries--);

-   if (ret)
+   if (ret) {
/* failed to get the link up... retire */
goto out;
+   } else {
+   ufshcd_dme_set(hba, UIC_ARG_MIB(TX_LCC_ENABLE), 0);
+   ufshcd_dme_set(hba, UIC_ARG_MIB(TX_LCC_ENABLE), 1);
+   }



Every ufs host has same issue and affected?.


if (link_startup_again) {
link_startup_again = false;
--
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.



Hi Choi
Thanks for the review.

No - I can't say if every host has the same issue. However, I get your 
point. It could be done with a quirk.


I'll fix this in v2 after collating all the comments from the rest of 
the patches.


-asd

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


Re: [PATCH 5/9] scsi: ufs: add reference counting for scsi block requests

2018-02-22 Thread Asutosh Das (asd)

On 2/21/2018 6:48 PM, Stanislav Nijnikov wrote:




-Original Message-
From: linux-scsi-ow...@vger.kernel.org [mailto:linux-scsi-
ow...@vger.kernel.org] On Behalf Of Asutosh Das
Sent: Wednesday, February 21, 2018 6:57 AM
To: subha...@codeaurora.org; c...@codeaurora.org;
vivek.gau...@codeaurora.org; rna...@codeaurora.org;
vinholika...@gmail.com; j...@linux.vnet.ibm.com;
martin.peter...@oracle.com
Cc: linux-scsi@vger.kernel.org; Asutosh Das <asuto...@codeaurora.org>;
open list <linux-ker...@vger.kernel.org>
Subject: [PATCH 5/9] scsi: ufs: add reference counting for scsi block requests

From: Subhash Jadavani <subha...@codeaurora.org>

Currently we call the scsi_block_requests()/scsi_unblock_requests()
whenever we want to block/unblock scsi requests but as there is no
reference counting, nesting of these calls could leave us in undesired state
sometime. Consider following call flow sequence:
1. func1() calls scsi_block_requests() but calls func2() before
calling scsi_unblock_requests()
2. func2() calls scsi_block_requests()
3. func2() calls scsi_unblock_requests() 4. func1() calls
scsi_unblock_requests()

As there is no reference counting, we will have scsi requests unblocked after
#3 instead of it to be unblocked only after #4. Though we may not have
failures seen with this, we might run into some failures in future.
Better solution would be to fix this by adding reference counting.

Signed-off-by: Subhash Jadavani <subha...@codeaurora.org>
Signed-off-by: Can Guo <c...@codeaurora.org>
Signed-off-by: Asutosh Das <asuto...@codeaurora.org>
---
  drivers/scsi/ufs/ufshcd.c | 44
+---
  drivers/scsi/ufs/ufshcd.h |  5 +
  2 files changed, 42 insertions(+), 7 deletions(-)

diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c index
7a4df95..987b81b 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -264,6 +264,36 @@ static inline void ufshcd_disable_irq(struct ufs_hba
*hba)
}
  }

+void ufshcd_scsi_unblock_requests(struct ufs_hba *hba) {
+   unsigned long flags;
+   bool unblock = false;
+
+   spin_lock_irqsave(hba->host->host_lock, flags);
+   hba->scsi_block_reqs_cnt--;
+   unblock = !hba->scsi_block_reqs_cnt;
+   spin_unlock_irqrestore(hba->host->host_lock, flags);
+   if (unblock)
+   scsi_unblock_requests(hba->host);
+}
+EXPORT_SYMBOL(ufshcd_scsi_unblock_requests);
+
+static inline void __ufshcd_scsi_block_requests(struct ufs_hba *hba) {
+   if (!hba->scsi_block_reqs_cnt++)
+   scsi_block_requests(hba->host);
+}
+
+void ufshcd_scsi_block_requests(struct ufs_hba *hba) {
+   unsigned long flags;
+
+   spin_lock_irqsave(hba->host->host_lock, flags);
+   __ufshcd_scsi_block_requests(hba);
+   spin_unlock_irqrestore(hba->host->host_lock, flags); }
+EXPORT_SYMBOL(ufshcd_scsi_block_requests);
+
  /* replace non-printable or non-ASCII characters with spaces */  static inline
void ufshcd_remove_non_printable(char *val)  { @@ -1079,12 +1109,12 @@
static int ufshcd_clock_scaling_prepare(struct ufs_hba *hba)
 * make sure that there are no outstanding requests when
 * clock scaling is in progress
 */
-   scsi_block_requests(hba->host);
+   ufshcd_scsi_block_requests(hba);
down_write(>clk_scaling_lock);
if (ufshcd_wait_for_doorbell_clr(hba, DOORBELL_CLR_TOUT_US)) {
ret = -EBUSY;
up_write(>clk_scaling_lock);
-   scsi_unblock_requests(hba->host);
+   ufshcd_scsi_unblock_requests(hba);
}

return ret;
@@ -1093,7 +1123,7 @@ static int ufshcd_clock_scaling_prepare(struct
ufs_hba *hba)  static void ufshcd_clock_scaling_unprepare(struct ufs_hba
*hba)  {
up_write(>clk_scaling_lock);
-   scsi_unblock_requests(hba->host);
+   ufshcd_scsi_unblock_requests(hba);
  }

  /**
@@ -1413,7 +1443,7 @@ static void ufshcd_ungate_work(struct work_struct
*work)
hba->clk_gating.is_suspended = false;
}
  unblock_reqs:
-   scsi_unblock_requests(hba->host);
+   ufshcd_scsi_unblock_requests(hba);
  }

  /**
@@ -1469,7 +1499,7 @@ int ufshcd_hold(struct ufs_hba *hba, bool async)
 * work and to enable clocks.
 */
case CLKS_OFF:
-   scsi_block_requests(hba->host);
+   __ufshcd_scsi_block_requests(hba);
hba->clk_gating.state = REQ_CLKS_ON;
trace_ufshcd_clk_gating(dev_name(hba->dev),
hba->clk_gating.state);
@@ -5197,7 +5227,7 @@ static void ufshcd_err_handler(struct work_struct
*work)

  out:
spin_unlock_irqrestore(hba->host->host_lock, flags);
-   scsi_unblock_requests(hba->host);
+   ufshcd_scsi_unblock_requests(hba);
ufshcd_release(hb

[PATCH 1/9] scsi: ufs: Allowing power mode change

2018-02-20 Thread Asutosh Das
From: Yaniv Gardi <yga...@codeaurora.org>

Due to M-PHY issues, moving from HS to any other mode or gear or
even Hibern8 causes some un-predicted behavior of the device.
This patch fixes this issues.

Signed-off-by: Yaniv Gardi <yga...@codeaurora.org>
Signed-off-by: Subhash Jadavani <subha...@codeaurora.org>
Signed-off-by: Can Guo <c...@codeaurora.org>
Signed-off-by: Asutosh Das <asuto...@codeaurora.org>
---
 drivers/scsi/ufs/ufshcd.c | 6 +-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index 011c336..d74d529 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -4167,9 +4167,13 @@ static int ufshcd_link_startup(struct ufs_hba *hba)
goto out;
} while (ret && retries--);
 
-   if (ret)
+   if (ret) {
/* failed to get the link up... retire */
goto out;
+   } else {
+   ufshcd_dme_set(hba, UIC_ARG_MIB(TX_LCC_ENABLE), 0);
+   ufshcd_dme_set(hba, UIC_ARG_MIB(TX_LCC_ENABLE), 1);
+   }
 
if (link_startup_again) {
link_startup_again = false;
-- 
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 8/9] scsi: ufs: fix irq return code

2018-02-20 Thread Asutosh Das
From: Venkat Gopalakrishnan <venk...@codeaurora.org>

Return IRQ_HANDLED only if the irq is really handled, this will
help in catching spurious interrupts that go unhandled.

Signed-off-by: Venkat Gopalakrishnan <venk...@codeaurora.org>
Signed-off-by: Can Guo <c...@codeaurora.org>
Signed-off-by: Asutosh Das <asuto...@codeaurora.org>
---
 drivers/scsi/ufs/ufshcd.c | 137 ++
 1 file changed, 101 insertions(+), 36 deletions(-)

diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index 4d4c7d6..6541e1d 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -211,7 +211,7 @@ enum {
END_FIX
 };
 
-static void ufshcd_tmc_handler(struct ufs_hba *hba);
+static irqreturn_t 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);
 static int ufshcd_eh_host_reset_handler(struct scsi_cmnd *cmd);
@@ -4630,19 +4630,29 @@ static int ufshcd_task_req_compl(struct ufs_hba *hba, 
u32 index, u8 *resp)
  * ufshcd_uic_cmd_compl - handle completion of uic command
  * @hba: per adapter instance
  * @intr_status: interrupt status generated by the controller
+ *
+ * Returns
+ *  IRQ_HANDLED - If interrupt is valid
+ *  IRQ_NONE- If invalid interrupt
  */
-static void ufshcd_uic_cmd_compl(struct ufs_hba *hba, u32 intr_status)
+static irqreturn_t ufshcd_uic_cmd_compl(struct ufs_hba *hba, u32 intr_status)
 {
+   irqreturn_t retval = IRQ_NONE;
+
if ((intr_status & UIC_COMMAND_COMPL) && hba->active_uic_cmd) {
hba->active_uic_cmd->argument2 |=
ufshcd_get_uic_cmd_result(hba);
hba->active_uic_cmd->argument3 =
ufshcd_get_dme_attr_val(hba);
complete(>active_uic_cmd->done);
+   retval = IRQ_HANDLED;
}
 
-   if ((intr_status & UFSHCD_UIC_PWR_MASK) && hba->uic_async_done)
+   if ((intr_status & UFSHCD_UIC_PWR_MASK) && hba->uic_async_done) {
complete(hba->uic_async_done);
+   retval = IRQ_HANDLED;
+   }
+   return retval;
 }
 
 /**
@@ -4698,8 +4708,12 @@ static void __ufshcd_transfer_req_compl(struct ufs_hba 
*hba,
 /**
  * ufshcd_transfer_req_compl - handle SCSI and query command completion
  * @hba: per adapter instance
+ *
+ * Returns
+ *  IRQ_HANDLED - If interrupt is valid
+ *  IRQ_NONE- If invalid interrupt
  */
-static void ufshcd_transfer_req_compl(struct ufs_hba *hba)
+static irqreturn_t ufshcd_transfer_req_compl(struct ufs_hba *hba)
 {
unsigned long completed_reqs;
u32 tr_doorbell;
@@ -4717,7 +4731,12 @@ static void ufshcd_transfer_req_compl(struct ufs_hba 
*hba)
tr_doorbell = ufshcd_readl(hba, REG_UTP_TRANSFER_REQ_DOOR_BELL);
completed_reqs = tr_doorbell ^ hba->outstanding_reqs;
 
-   __ufshcd_transfer_req_compl(hba, completed_reqs);
+   if (completed_reqs) {
+   __ufshcd_transfer_req_compl(hba, completed_reqs);
+   return IRQ_HANDLED;
+   } else {
+   return IRQ_NONE;
+   }
 }
 
 /**
@@ -5243,16 +5262,21 @@ static void ufshcd_update_uic_reg_hist(struct 
ufs_uic_err_reg_hist *reg_hist,
 /**
  * ufshcd_update_uic_error - check and set fatal UIC error flags.
  * @hba: per-adapter instance
+ *
+ * Returns
+ *  IRQ_HANDLED - If interrupt is valid
+ *  IRQ_NONE- If invalid interrupt
  */
-static void ufshcd_update_uic_error(struct ufs_hba *hba)
+static irqreturn_t ufshcd_update_uic_error(struct ufs_hba *hba)
 {
u32 reg;
+   irqreturn_t retval = IRQ_NONE;
 
/* PHY layer lane error */
reg = ufshcd_readl(hba, REG_UIC_ERROR_CODE_PHY_ADAPTER_LAYER);
/* Ignore LINERESET indication, as this is not an error */
if ((reg & UIC_PHY_ADAPTER_LAYER_ERROR) &&
-   (reg & UIC_PHY_ADAPTER_LAYER_LANE_ERR_MASK)) {
+   (reg & UIC_PHY_ADAPTER_LAYER_ERROR_CODE_MASK)) {
/*
 * To know whether this error is fatal or not, DB timeout
 * must be checked but this error is handled separately.
@@ -5263,57 +5287,73 @@ static void ufshcd_update_uic_error(struct ufs_hba *hba)
 
/* PA_INIT_ERROR is fatal and needs UIC reset */
reg = ufshcd_readl(hba, REG_UIC_ERROR_CODE_DATA_LINK_LAYER);
-   if (reg)
+   if ((reg & UIC_DATA_LINK_LAYER_ERROR) &&
+   (reg & UIC_DATA_LINK_LAYER_ERROR_CODE_MASK)) {
ufshcd_update_uic_reg_hist(>ufs_stats.dl_err, reg);
-
-   if (reg & UIC_DATA_LINK_LAYER_ERROR_PA_INIT)
-   hba->uic_error |= UFSHCD_UIC_DL_PA_INIT_ERROR;
-   else if (hba->dev_quirks &
-  UFS_DEVICE_QUIRK_RECOVERY_FROM_DL_NAC_ERRORS) {
-   if (reg &a

[PATCH 3/9] scsi: ufs: fix exception event handling

2018-02-20 Thread Asutosh Das
From: Maya Erez <me...@codeaurora.org>

The device can set the exception event bit in one of the response UPIU,
for example to notify the need for urgent BKOPs operation.
In such a case the host driver calls ufshcd_exception_event_handler to
handle this notification.
When trying to check the exception event status (for finding the cause for
the exception event), the device may be busy with additional SCSI commands
handling and may not respond within the 100ms timeout.

To prevent that, we need to block SCSI commands during handling of
exception events and allow retransmissions of the query requests,
in case of timeout.

Signed-off-by: Subhash Jadavani <subha...@codeaurora.org>
Signed-off-by: Maya Erez <me...@codeaurora.org>
Signed-off-by: Can Guo <c...@codeaurora.org>
Signed-off-by: Asutosh Das <asuto...@codeaurora.org>
---
 drivers/scsi/ufs/ufshcd.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index cc7eb1e..8d3f8ce 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -4972,6 +4972,7 @@ static void ufshcd_exception_event_handler(struct 
work_struct *work)
hba = container_of(work, struct ufs_hba, eeh_work);
 
pm_runtime_get_sync(hba->dev);
+   scsi_block_requests(hba->host);
err = ufshcd_get_ee_status(hba, );
if (err) {
dev_err(hba->dev, "%s: failed to get exception status %d\n",
@@ -4985,6 +4986,7 @@ static void ufshcd_exception_event_handler(struct 
work_struct *work)
ufshcd_bkops_exception_event_handler(hba);
 
 out:
+   scsi_unblock_requests(hba->host);
pm_runtime_put_sync(hba->dev);
return;
 }
-- 
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 2/9] scsi: ufs: Add LCC quirk for host and device

2018-02-20 Thread Asutosh Das
From: Subhash Jadavani <subha...@codeaurora.org>

LCC (Line Control Command) is being used for communication between
UFS host and UFS device. But some hosts might have the issue with
issuing the LCC commands to UFS device and in this case LCC could be
explicitly disabled.

But there could be a need where we don't want to disable the LCC
on both host & device; hence this change splits the quirk in 2 parts
one for host and one for device.

Signed-off-by: Subhash Jadavani <subha...@codeaurora.org>
Signed-off-by: Venkat Gopalakrishnan <venk...@codeaurora.org>
Signed-off-by: Can Guo <c...@codeaurora.org>
Signed-off-by: Asutosh Das <asuto...@codeaurora.org>
---
 drivers/scsi/ufs/ufshcd.c | 16 
 drivers/scsi/ufs/ufshcd.h | 11 +++
 2 files changed, 27 insertions(+)

diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index d74d529..cc7eb1e 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -4121,6 +4121,11 @@ static int ufshcd_disable_tx_lcc(struct ufs_hba *hba, 
bool peer)
return err;
 }
 
+static inline int ufshcd_disable_host_tx_lcc(struct ufs_hba *hba)
+{
+   return ufshcd_disable_tx_lcc(hba, false);
+}
+
 static inline int ufshcd_disable_device_tx_lcc(struct ufs_hba *hba)
 {
return ufshcd_disable_tx_lcc(hba, true);
@@ -4175,6 +4180,17 @@ static int ufshcd_link_startup(struct ufs_hba *hba)
ufshcd_dme_set(hba, UIC_ARG_MIB(TX_LCC_ENABLE), 1);
}
 
+   if (hba->quirks & UFSHCD_BROKEN_LCC_PROCESSING_ON_HOST) {
+   ret = ufshcd_disable_device_tx_lcc(hba);
+   if (ret)
+   goto out;
+   }
+
+   if (hba->quirks & UFSHCD_BROKEN_LCC_PROCESSING_ON_DEVICE) {
+   ret = ufshcd_disable_host_tx_lcc(hba);
+   if (ret)
+   goto out;
+   }
if (link_startup_again) {
link_startup_again = false;
retries = DME_LINKSTARTUP_RETRIES;
diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h
index 1332e54..7a2dad3 100644
--- a/drivers/scsi/ufs/ufshcd.h
+++ b/drivers/scsi/ufs/ufshcd.h
@@ -591,6 +591,17 @@ struct ufs_hba {
 */
#define UFSHCD_QUIRK_PRDT_BYTE_GRAN 0x80
 
+   /*
+* If UFS device is having issue in processing LCC (Line Control
+* Command) coming from UFS host controller then enable this quirk.
+* When this quirk is enabled, host controller driver should disable
+* the LCC transmission on UFS host controller (by clearing
+* TX_LCC_ENABLE attribute of host to 0).
+*/
+   #define UFSHCD_BROKEN_LCC_PROCESSING_ON_DEVICE  0x100
+
+   #define UFSHCD_BROKEN_LCC_PROCESSING_ON_HOST0x200
+
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 5/9] scsi: ufs: add reference counting for scsi block requests

2018-02-20 Thread Asutosh Das
From: Subhash Jadavani <subha...@codeaurora.org>

Currently we call the scsi_block_requests()/scsi_unblock_requests()
whenever we want to block/unblock scsi requests but as there is no
reference counting, nesting of these calls could leave us in undesired
state sometime. Consider following call flow sequence:
1. func1() calls scsi_block_requests() but calls func2() before
   calling scsi_unblock_requests()
2. func2() calls scsi_block_requests()
3. func2() calls scsi_unblock_requests()
4. func1() calls scsi_unblock_requests()

As there is no reference counting, we will have scsi requests unblocked
after #3 instead of it to be unblocked only after #4. Though we may not
have failures seen with this, we might run into some failures in future.
Better solution would be to fix this by adding reference counting.

Signed-off-by: Subhash Jadavani <subha...@codeaurora.org>
Signed-off-by: Can Guo <c...@codeaurora.org>
Signed-off-by: Asutosh Das <asuto...@codeaurora.org>
---
 drivers/scsi/ufs/ufshcd.c | 44 +---
 drivers/scsi/ufs/ufshcd.h |  5 +
 2 files changed, 42 insertions(+), 7 deletions(-)

diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index 7a4df95..987b81b 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -264,6 +264,36 @@ static inline void ufshcd_disable_irq(struct ufs_hba *hba)
}
 }
 
+void ufshcd_scsi_unblock_requests(struct ufs_hba *hba)
+{
+   unsigned long flags;
+   bool unblock = false;
+
+   spin_lock_irqsave(hba->host->host_lock, flags);
+   hba->scsi_block_reqs_cnt--;
+   unblock = !hba->scsi_block_reqs_cnt;
+   spin_unlock_irqrestore(hba->host->host_lock, flags);
+   if (unblock)
+   scsi_unblock_requests(hba->host);
+}
+EXPORT_SYMBOL(ufshcd_scsi_unblock_requests);
+
+static inline void __ufshcd_scsi_block_requests(struct ufs_hba *hba)
+{
+   if (!hba->scsi_block_reqs_cnt++)
+   scsi_block_requests(hba->host);
+}
+
+void ufshcd_scsi_block_requests(struct ufs_hba *hba)
+{
+   unsigned long flags;
+
+   spin_lock_irqsave(hba->host->host_lock, flags);
+   __ufshcd_scsi_block_requests(hba);
+   spin_unlock_irqrestore(hba->host->host_lock, flags);
+}
+EXPORT_SYMBOL(ufshcd_scsi_block_requests);
+
 /* replace non-printable or non-ASCII characters with spaces */
 static inline void ufshcd_remove_non_printable(char *val)
 {
@@ -1079,12 +1109,12 @@ static int ufshcd_clock_scaling_prepare(struct ufs_hba 
*hba)
 * make sure that there are no outstanding requests when
 * clock scaling is in progress
 */
-   scsi_block_requests(hba->host);
+   ufshcd_scsi_block_requests(hba);
down_write(>clk_scaling_lock);
if (ufshcd_wait_for_doorbell_clr(hba, DOORBELL_CLR_TOUT_US)) {
ret = -EBUSY;
up_write(>clk_scaling_lock);
-   scsi_unblock_requests(hba->host);
+   ufshcd_scsi_unblock_requests(hba);
}
 
return ret;
@@ -1093,7 +1123,7 @@ static int ufshcd_clock_scaling_prepare(struct ufs_hba 
*hba)
 static void ufshcd_clock_scaling_unprepare(struct ufs_hba *hba)
 {
up_write(>clk_scaling_lock);
-   scsi_unblock_requests(hba->host);
+   ufshcd_scsi_unblock_requests(hba);
 }
 
 /**
@@ -1413,7 +1443,7 @@ static void ufshcd_ungate_work(struct work_struct *work)
hba->clk_gating.is_suspended = false;
}
 unblock_reqs:
-   scsi_unblock_requests(hba->host);
+   ufshcd_scsi_unblock_requests(hba);
 }
 
 /**
@@ -1469,7 +1499,7 @@ int ufshcd_hold(struct ufs_hba *hba, bool async)
 * work and to enable clocks.
 */
case CLKS_OFF:
-   scsi_block_requests(hba->host);
+   __ufshcd_scsi_block_requests(hba);
hba->clk_gating.state = REQ_CLKS_ON;
trace_ufshcd_clk_gating(dev_name(hba->dev),
hba->clk_gating.state);
@@ -5197,7 +5227,7 @@ static void ufshcd_err_handler(struct work_struct *work)
 
 out:
spin_unlock_irqrestore(hba->host->host_lock, flags);
-   scsi_unblock_requests(hba->host);
+   ufshcd_scsi_unblock_requests(hba);
ufshcd_release(hba);
pm_runtime_put_sync(hba->dev);
 }
@@ -5299,7 +5329,7 @@ static void ufshcd_check_errors(struct ufs_hba *hba)
/* handle fatal errors only when link is functional */
if (hba->ufshcd_state == UFSHCD_STATE_OPERATIONAL) {
/* block commands from scsi mid-layer */
-   scsi_block_requests(hba->host);
+   __ufshcd_scsi_block_requests(hba);
 
hba->ufshcd_state = UFSHCD_STATE_EH_SCHEDULED;
 
diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h
index 7a2d

[PATCH 7/9] scsi: ufs: make sure all interrupts are processed

2018-02-20 Thread Asutosh Das
From: Venkat Gopalakrishnan <venk...@codeaurora.org>

As multiple requests are submitted to the ufs host controller in
parallel there could be instances where the command completion
interrupt arrives later for a request that is already processed
earlier as the corresponding doorbell was cleared when handling
the previous interrupt. Read the interrupt status in a loop after
processing the received interrupt to catch such interrupts and
handle it.

Signed-off-by: Venkat Gopalakrishnan <venk...@codeaurora.org>
Signed-off-by: Asutosh Das <asuto...@codeaurora.org>
---
 drivers/scsi/ufs/ufshcd.c | 27 +++
 1 file changed, 19 insertions(+), 8 deletions(-)

diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index 987b81b..4d4c7d6 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -5406,19 +5406,30 @@ static irqreturn_t ufshcd_intr(int irq, void *__hba)
u32 intr_status, enabled_intr_status;
irqreturn_t retval = IRQ_NONE;
struct ufs_hba *hba = __hba;
+   int retries = hba->nutrs;
 
spin_lock(hba->host->host_lock);
intr_status = ufshcd_readl(hba, REG_INTERRUPT_STATUS);
-   enabled_intr_status =
-   intr_status & ufshcd_readl(hba, REG_INTERRUPT_ENABLE);
 
-   if (intr_status)
-   ufshcd_writel(hba, intr_status, REG_INTERRUPT_STATUS);
+   /*
+* There could be max of hba->nutrs reqs in flight and in worst case
+* if the reqs get finished 1 by 1 after the interrupt status is
+* read, make sure we handle them by checking the interrupt status
+* again in a loop until we process all of the reqs before returning.
+*/
+   do {
+   enabled_intr_status =
+   intr_status & ufshcd_readl(hba, REG_INTERRUPT_ENABLE);
+   if (intr_status)
+   ufshcd_writel(hba, intr_status, REG_INTERRUPT_STATUS);
+   if (enabled_intr_status) {
+   ufshcd_sl_intr(hba, enabled_intr_status);
+   retval = IRQ_HANDLED;
+   }
+
+   intr_status = ufshcd_readl(hba, REG_INTERRUPT_STATUS);
+   } while (intr_status && --retries);
 
-   if (enabled_intr_status) {
-   ufshcd_sl_intr(hba, enabled_intr_status);
-   retval = IRQ_HANDLED;
-   }
spin_unlock(hba->host->host_lock);
return retval;
 }
-- 
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 4/9] scsi: ufshcd: fix possible unclocked register access

2018-02-20 Thread Asutosh Das
From: Subhash Jadavani <subha...@codeaurora.org>

vendor specific setup_clocks ops may depend on clocks managed by ufshcd
driver so if the vendor specific setup_clocks callback is called when
the required clocks are turned off, it results into unclocked register
access.

This change make sure that required clocks are enabled before vendor
specific setup_clocks callback is called.

Signed-off-by: Subhash Jadavani <subha...@codeaurora.org>
Signed-off-by: Venkat Gopalakrishnan <venk...@codeaurora.org>
Signed-off-by: Can Guo <c...@codeaurora.org>
Signed-off-by: Asutosh Das <asuto...@codeaurora.org>
---
 drivers/scsi/ufs/ufshcd.c | 26 --
 1 file changed, 20 insertions(+), 6 deletions(-)

diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index 8d3f8ce..7a4df95 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -6782,9 +6782,16 @@ static int __ufshcd_setup_clocks(struct ufs_hba *hba, 
bool on,
if (list_empty(head))
goto out;
 
-   ret = ufshcd_vops_setup_clocks(hba, on, PRE_CHANGE);
-   if (ret)
-   return ret;
+   /*
+* vendor specific setup_clocks ops may depend on clocks managed by
+* this standard driver hence call the vendor specific setup_clocks
+* before disabling the clocks managed here.
+*/
+   if (!on) {
+   ret = ufshcd_vops_setup_clocks(hba, on, PRE_CHANGE);
+   if (ret)
+   return ret;
+   }
 
list_for_each_entry(clki, head, list) {
if (!IS_ERR_OR_NULL(clki->clk)) {
@@ -6808,9 +6815,16 @@ static int __ufshcd_setup_clocks(struct ufs_hba *hba, 
bool on,
}
}
 
-   ret = ufshcd_vops_setup_clocks(hba, on, POST_CHANGE);
-   if (ret)
-   return ret;
+   /*
+* vendor specific setup_clocks ops may depend on clocks managed by
+* this standard driver hence call the vendor specific setup_clocks
+* after enabling the clocks managed here.
+*/
+   if (on) {
+   ret = ufshcd_vops_setup_clocks(hba, on, POST_CHANGE);
+   if (ret)
+   return ret;
+   }
 
 out:
if (ret) {
-- 
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 9/9] scsi: ufs: Add clock ungating to a separate workqueue

2018-02-20 Thread Asutosh Das
From: Vijay Viswanath <vvisw...@codeaurora.org>

UFS driver can receive a request during memory reclaim by kswapd.
So when ufs driver puts the ungate work in queue, and if there are no
idle workers, kthreadd is invoked to create a new kworker. Since
kswapd task holds a mutex which kthreadd also needs, this can cause
a deadlock situation. So ungate work must be done in a separate
work queue with WQ__RECLAIM flag enabled.Such a workqueue will have
a rescue thread which will be called when the above deadlock
condition is possible.

Signed-off-by: Vijay Viswanath <vvisw...@codeaurora.org>
Signed-off-by: Can Guo <c...@codeaurora.org>
Signed-off-by: Asutosh Das <asuto...@codeaurora.org>
---
 drivers/scsi/ufs/ufshcd.c | 10 +-
 drivers/scsi/ufs/ufshcd.h |  1 +
 2 files changed, 10 insertions(+), 1 deletion(-)

diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index 6541e1d..bb3382a 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -1503,7 +1503,8 @@ int ufshcd_hold(struct ufs_hba *hba, bool async)
hba->clk_gating.state = REQ_CLKS_ON;
trace_ufshcd_clk_gating(dev_name(hba->dev),
hba->clk_gating.state);
-   schedule_work(>clk_gating.ungate_work);
+   queue_work(hba->clk_gating.clk_gating_workq,
+  >clk_gating.ungate_work);
/*
 * fall through to check if we should wait for this
 * work to be done or not.
@@ -1689,6 +1690,8 @@ static ssize_t ufshcd_clkgate_enable_store(struct device 
*dev,
 
 static void ufshcd_init_clk_gating(struct ufs_hba *hba)
 {
+   char wq_name[sizeof("ufs_clk_gating_00")];
+
if (!ufshcd_is_clkgating_allowed(hba))
return;
 
@@ -1696,6 +1699,10 @@ static void ufshcd_init_clk_gating(struct ufs_hba *hba)
INIT_DELAYED_WORK(>clk_gating.gate_work, ufshcd_gate_work);
INIT_WORK(>clk_gating.ungate_work, ufshcd_ungate_work);
 
+   snprintf(wq_name, ARRAY_SIZE(wq_name), "ufs_clk_gating_%d",
+hba->host->host_no);
+   hba->clk_gating.clk_gating_workq = 
create_singlethread_workqueue(wq_name);
+
hba->clk_gating.is_enabled = true;
 
hba->clk_gating.delay_attr.show = ufshcd_clkgate_delay_show;
@@ -1723,6 +1730,7 @@ static void ufshcd_exit_clk_gating(struct ufs_hba *hba)
device_remove_file(hba->dev, >clk_gating.enable_attr);
cancel_work_sync(>clk_gating.ungate_work);
cancel_delayed_work_sync(>clk_gating.gate_work);
+   destroy_workqueue(hba->clk_gating.clk_gating_workq);
 }
 
 /* Must be called with host lock acquired */
diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h
index 4385741..570c33e 100644
--- a/drivers/scsi/ufs/ufshcd.h
+++ b/drivers/scsi/ufs/ufshcd.h
@@ -361,6 +361,7 @@ struct ufs_clk_gating {
struct device_attribute enable_attr;
bool is_enabled;
int active_reqs;
+   struct workqueue_struct *clk_gating_workq;
 };
 
 struct ufs_saved_pwr_info {
-- 
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 6/9] scsi: ufs-qcom: remove broken hci version quirk

2018-02-20 Thread Asutosh Das
From: Subhash Jadavani <subha...@codeaurora.org>

UFSHCD_QUIRK_BROKEN_UFS_HCI_VERSION is only applicable for QCOM UFS host
controller version 2.x.y and this has been fixed from version 3.x.y
onwards, hence this change removes this quirk for version 3.x.y onwards.

Signed-off-by: Subhash Jadavani <subha...@codeaurora.org>
Signed-off-by: Asutosh Das <asuto...@codeaurora.org>
---
 drivers/scsi/ufs/ufs-qcom.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/scsi/ufs/ufs-qcom.c b/drivers/scsi/ufs/ufs-qcom.c
index 2b38db2..221820a 100644
--- a/drivers/scsi/ufs/ufs-qcom.c
+++ b/drivers/scsi/ufs/ufs-qcom.c
@@ -1098,7 +1098,7 @@ static void ufs_qcom_advertise_quirks(struct ufs_hba *hba)
hba->quirks |= UFSHCD_QUIRK_BROKEN_LCC;
}
 
-   if (host->hw_ver.major >= 0x2) {
+   if (host->hw_ver.major == 0x2) {
hba->quirks |= UFSHCD_QUIRK_BROKEN_UFS_HCI_VERSION;
 
if (!ufs_qcom_cap_qunipro(host))
-- 
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 0/9] ufshcd optimizations and fixes

2018-02-20 Thread Asutosh Das
This patch set has a bunch of optimizations for UFS HCI.


Maya Erez (1):
  scsi: ufs: fix exception event handling

Subhash Jadavani (4):
  scsi: ufs: Add LCC quirk for host and device
  scsi: ufshcd: fix possible unclocked register access
  scsi: ufs: add reference counting for scsi block requests
  scsi: ufs-qcom: remove broken hci version quirk

Venkat Gopalakrishnan (2):
  scsi: ufs: make sure all interrupts are processed
  scsi: ufs: fix irq return code

Vijay Viswanath (1):
  scsi: ufs: Add clock ungating to a separate workqueue

Yaniv Gardi (1):
  scsi: ufs: Allowing power mode change

 drivers/scsi/ufs/ufs-qcom.c |   2 +-
 drivers/scsi/ufs/ufshcd.c   | 258 ++--
 drivers/scsi/ufs/ufshcd.h   |  17 +++
 3 files changed, 222 insertions(+), 55 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.



Re: [PATCH 1/1] scsi: ufs: make sure all interrupts are processed

2018-02-04 Thread Asutosh Das (asd)

On 2/2/2018 8:53 AM, Asutosh Das (asd) wrote:

On 1/31/2018 1:09 PM, Avri Altman wrote:

Hi,
Can you elaborate how this can even happen?
Isn't the interrupt aggregation capability should attend for those cases?

Thanks,
Avri


-Original Message-
From: linux-scsi-ow...@vger.kernel.org [mailto:linux-scsi-
ow...@vger.kernel.org] On Behalf Of Asutosh Das
Sent: Tuesday, January 30, 2018 6:54 AM
To: subha...@codeaurora.org; c...@codeaurora.org;
vivek.gau...@codeaurora.org; rna...@codeaurora.org;
vinholika...@gmail.com; j...@linux.vnet.ibm.com;
martin.peter...@oracle.com
Cc: linux-scsi@vger.kernel.org; Venkat Gopalakrishnan
<venk...@codeaurora.org>; Asutosh Das <asuto...@codeaurora.org>; open
list <linux-ker...@vger.kernel.org>
Subject: [PATCH 1/1] scsi: ufs: make sure all interrupts are processed

From: Venkat Gopalakrishnan <venk...@codeaurora.org>

As multiple requests are submitted to the ufs host controller in 
parallel there
could be instances where the command completion interrupt arrives 
later for a
request that is already processed earlier as the corresponding 
doorbell was
cleared when handling the previous interrupt. Read the interrupt 
status in a
loop after processing the received interrupt to catch such interrupts 
and handle

it.

Signed-off-by: Venkat Gopalakrishnan <venk...@codeaurora.org>
Signed-off-by: Asutosh Das <asuto...@codeaurora.org>
---
  drivers/scsi/ufs/ufshcd.c | 27 +++
  1 file changed, 19 insertions(+), 8 deletions(-)

diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c index
8af2af3..58d81de 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -5357,19 +5357,30 @@ static irqreturn_t ufshcd_intr(int irq, void 
*__hba)

  u32 intr_status, enabled_intr_status;
  irqreturn_t retval = IRQ_NONE;
  struct ufs_hba *hba = __hba;
+    int retries = hba->nutrs;

  spin_lock(hba->host->host_lock);
  intr_status = ufshcd_readl(hba, REG_INTERRUPT_STATUS);
-    enabled_intr_status =
-    intr_status & ufshcd_readl(hba, REG_INTERRUPT_ENABLE);

-    if (intr_status)
-    ufshcd_writel(hba, intr_status, REG_INTERRUPT_STATUS);
+    /*
+ * There could be max of hba->nutrs reqs in flight and in worst 
case

+ * if the reqs get finished 1 by 1 after the interrupt status is
+ * read, make sure we handle them by checking the interrupt status
+ * again in a loop until we process all of the reqs before 
returning.

+ */
+    do {
+    enabled_intr_status =
+    intr_status & ufshcd_readl(hba,
REG_INTERRUPT_ENABLE);
+    if (intr_status)
+    ufshcd_writel(hba, intr_status,
REG_INTERRUPT_STATUS);
+    if (enabled_intr_status) {
+    ufshcd_sl_intr(hba, enabled_intr_status);
+    retval = IRQ_HANDLED;
+    }
+
+    intr_status = ufshcd_readl(hba, REG_INTERRUPT_STATUS);
+    } while (intr_status && --retries);

-    if (enabled_intr_status) {
-    ufshcd_sl_intr(hba, enabled_intr_status);
-    retval = IRQ_HANDLED;
-    }
  spin_unlock(hba->host->host_lock);
  return retval;
  }
--
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.




Hi
yes - interrupt aggregation makes sense here. But there were some 
performance concerns with it; well, I don't have the data to back that 
up now though.

However, I can code it up and check it.
Will post it in some time.

-asd


Hi Avri,
I went through the UFS HCI - v2.1 spec. Specifically, in sec 7.2.3 it 
explicitly mentions that the software should determine if new TRs were 
completed since the interrupt status was last read/cleared. This step is 
independent of aggregation.


So I think the above implementation makes sense. Please let me know if I 
understood your concern correctly.


-asd

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


Re: [PATCH 1/1] scsi: ufs: make sure all interrupts are processed

2018-02-01 Thread Asutosh Das (asd)

On 1/31/2018 1:09 PM, Avri Altman wrote:

Hi,
Can you elaborate how this can even happen?
Isn't the interrupt aggregation capability should attend for those cases?

Thanks,
Avri


-Original Message-
From: linux-scsi-ow...@vger.kernel.org [mailto:linux-scsi-
ow...@vger.kernel.org] On Behalf Of Asutosh Das
Sent: Tuesday, January 30, 2018 6:54 AM
To: subha...@codeaurora.org; c...@codeaurora.org;
vivek.gau...@codeaurora.org; rna...@codeaurora.org;
vinholika...@gmail.com; j...@linux.vnet.ibm.com;
martin.peter...@oracle.com
Cc: linux-scsi@vger.kernel.org; Venkat Gopalakrishnan
<venk...@codeaurora.org>; Asutosh Das <asuto...@codeaurora.org>; open
list <linux-ker...@vger.kernel.org>
Subject: [PATCH 1/1] scsi: ufs: make sure all interrupts are processed

From: Venkat Gopalakrishnan <venk...@codeaurora.org>

As multiple requests are submitted to the ufs host controller in parallel there
could be instances where the command completion interrupt arrives later for a
request that is already processed earlier as the corresponding doorbell was
cleared when handling the previous interrupt. Read the interrupt status in a
loop after processing the received interrupt to catch such interrupts and handle
it.

Signed-off-by: Venkat Gopalakrishnan <venk...@codeaurora.org>
Signed-off-by: Asutosh Das <asuto...@codeaurora.org>
---
  drivers/scsi/ufs/ufshcd.c | 27 +++
  1 file changed, 19 insertions(+), 8 deletions(-)

diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c index
8af2af3..58d81de 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -5357,19 +5357,30 @@ static irqreturn_t ufshcd_intr(int irq, void *__hba)
u32 intr_status, enabled_intr_status;
irqreturn_t retval = IRQ_NONE;
struct ufs_hba *hba = __hba;
+   int retries = hba->nutrs;

spin_lock(hba->host->host_lock);
intr_status = ufshcd_readl(hba, REG_INTERRUPT_STATUS);
-   enabled_intr_status =
-   intr_status & ufshcd_readl(hba, REG_INTERRUPT_ENABLE);

-   if (intr_status)
-   ufshcd_writel(hba, intr_status, REG_INTERRUPT_STATUS);
+   /*
+* There could be max of hba->nutrs reqs in flight and in worst case
+* if the reqs get finished 1 by 1 after the interrupt status is
+* read, make sure we handle them by checking the interrupt status
+* again in a loop until we process all of the reqs before returning.
+*/
+   do {
+   enabled_intr_status =
+   intr_status & ufshcd_readl(hba,
REG_INTERRUPT_ENABLE);
+   if (intr_status)
+   ufshcd_writel(hba, intr_status,
REG_INTERRUPT_STATUS);
+   if (enabled_intr_status) {
+   ufshcd_sl_intr(hba, enabled_intr_status);
+   retval = IRQ_HANDLED;
+   }
+
+   intr_status = ufshcd_readl(hba, REG_INTERRUPT_STATUS);
+   } while (intr_status && --retries);

-   if (enabled_intr_status) {
-   ufshcd_sl_intr(hba, enabled_intr_status);
-   retval = IRQ_HANDLED;
-   }
spin_unlock(hba->host->host_lock);
return retval;
  }
--
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.




Hi
yes - interrupt aggregation makes sense here. But there were some 
performance concerns with it; well, I don't have the data to back that 
up now though.

However, I can code it up and check it.
Will post it in some time.

-asd

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


Re: [PATCH 1/1] scsi: ufs-qcom: remove broken hci version quirk

2018-01-29 Thread Asutosh Das (asd)

On 1/30/2018 11:33 AM, Vivek Gautam wrote:

Hi Asutosh,


On 1/30/2018 10:11 AM, Asutosh Das wrote:

From: Subhash Jadavani <subha...@codeaurora.org>

UFSHCD_QUIRK_BROKEN_UFS_HCI_VERSION is only applicable for QCOM UFS host
controller version 2.x.y and this has been fixed from version 3.x.y
onwards, hence this change removes this quirk for version 3.x.y onwards.

Signed-off-by: Subhash Jadavani <subha...@codeaurora.org>
Signed-off-by: Asutosh Das <asuto...@codeaurora.org>
---


This patch and all other ufs patches that you have posted recently,
do they all fall under one 'ufs-qcom fixes' patch series for fixes that
we would want to do?
If it is so, then please club them together in a series, so that
it's easy for reviewers and maintainers to review, and keep track
of all the patches that can get-in after the reviews.
If they belong to two or more separate patch-series then please
create such patch series.
It's difficult to read through a lot of [PATCH 1/1] ... patch.

Sure Vivek - Makes sense. Will resend it.



Regards
Vivek


  drivers/scsi/ufs/ufs-qcom.c | 2 +-
  1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/scsi/ufs/ufs-qcom.c b/drivers/scsi/ufs/ufs-qcom.c
index 2b38db2..221820a 100644
--- a/drivers/scsi/ufs/ufs-qcom.c
+++ b/drivers/scsi/ufs/ufs-qcom.c
@@ -1098,7 +1098,7 @@ static void ufs_qcom_advertise_quirks(struct 
ufs_hba *hba)

  hba->quirks |= UFSHCD_QUIRK_BROKEN_LCC;
  }
-    if (host->hw_ver.major >= 0x2) {
+    if (host->hw_ver.major == 0x2) {
  hba->quirks |= UFSHCD_QUIRK_BROKEN_UFS_HCI_VERSION;
  if (!ufs_qcom_cap_qunipro(host))





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


[PATCH 1/1] scsi: ufs: make sure all interrupts are processed

2018-01-29 Thread Asutosh Das
From: Venkat Gopalakrishnan <venk...@codeaurora.org>

As multiple requests are submitted to the ufs host controller in
parallel there could be instances where the command completion
interrupt arrives later for a request that is already processed
earlier as the corresponding doorbell was cleared when handling
the previous interrupt. Read the interrupt status in a loop after
processing the received interrupt to catch such interrupts and
handle it.

Signed-off-by: Venkat Gopalakrishnan <venk...@codeaurora.org>
Signed-off-by: Asutosh Das <asuto...@codeaurora.org>
---
 drivers/scsi/ufs/ufshcd.c | 27 +++
 1 file changed, 19 insertions(+), 8 deletions(-)

diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index 8af2af3..58d81de 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -5357,19 +5357,30 @@ static irqreturn_t ufshcd_intr(int irq, void *__hba)
u32 intr_status, enabled_intr_status;
irqreturn_t retval = IRQ_NONE;
struct ufs_hba *hba = __hba;
+   int retries = hba->nutrs;
 
spin_lock(hba->host->host_lock);
intr_status = ufshcd_readl(hba, REG_INTERRUPT_STATUS);
-   enabled_intr_status =
-   intr_status & ufshcd_readl(hba, REG_INTERRUPT_ENABLE);
 
-   if (intr_status)
-   ufshcd_writel(hba, intr_status, REG_INTERRUPT_STATUS);
+   /*
+* There could be max of hba->nutrs reqs in flight and in worst case
+* if the reqs get finished 1 by 1 after the interrupt status is
+* read, make sure we handle them by checking the interrupt status
+* again in a loop until we process all of the reqs before returning.
+*/
+   do {
+   enabled_intr_status =
+   intr_status & ufshcd_readl(hba, REG_INTERRUPT_ENABLE);
+   if (intr_status)
+   ufshcd_writel(hba, intr_status, REG_INTERRUPT_STATUS);
+   if (enabled_intr_status) {
+   ufshcd_sl_intr(hba, enabled_intr_status);
+   retval = IRQ_HANDLED;
+   }
+
+   intr_status = ufshcd_readl(hba, REG_INTERRUPT_STATUS);
+   } while (intr_status && --retries);
 
-   if (enabled_intr_status) {
-   ufshcd_sl_intr(hba, enabled_intr_status);
-   retval = IRQ_HANDLED;
-   }
spin_unlock(hba->host->host_lock);
return retval;
 }
-- 
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 1/1] scsi: ufs-qcom: remove broken hci version quirk

2018-01-29 Thread Asutosh Das
From: Subhash Jadavani <subha...@codeaurora.org>

UFSHCD_QUIRK_BROKEN_UFS_HCI_VERSION is only applicable for QCOM UFS host
controller version 2.x.y and this has been fixed from version 3.x.y
onwards, hence this change removes this quirk for version 3.x.y onwards.

Signed-off-by: Subhash Jadavani <subha...@codeaurora.org>
Signed-off-by: Asutosh Das <asuto...@codeaurora.org>
---
 drivers/scsi/ufs/ufs-qcom.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/scsi/ufs/ufs-qcom.c b/drivers/scsi/ufs/ufs-qcom.c
index 2b38db2..221820a 100644
--- a/drivers/scsi/ufs/ufs-qcom.c
+++ b/drivers/scsi/ufs/ufs-qcom.c
@@ -1098,7 +1098,7 @@ static void ufs_qcom_advertise_quirks(struct ufs_hba *hba)
hba->quirks |= UFSHCD_QUIRK_BROKEN_LCC;
}
 
-   if (host->hw_ver.major >= 0x2) {
+   if (host->hw_ver.major == 0x2) {
hba->quirks |= UFSHCD_QUIRK_BROKEN_UFS_HCI_VERSION;
 
if (!ufs_qcom_cap_qunipro(host))
-- 
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 1/1] scsi: ufs: add reference counting for scsi block requests

2018-01-29 Thread Asutosh Das
From: Subhash Jadavani <subha...@codeaurora.org>

Currently we call the scsi_block_requests()/scsi_unblock_requests()
whenever we want to block/unblock scsi requests but as there is no
reference counting, nesting of these calls could leave us in undesired
state sometime. Consider following call flow sequence:
1. func1() calls scsi_block_requests() but calls func2() before
   calling scsi_unblock_requests()
2. func2() calls scsi_block_requests()
3. func2() calls scsi_unblock_requests()
4. func1() calls scsi_unblock_requests()

As there is no reference counting, we will have scsi requests unblocked
after #3 instead of it to be unblocked only after #4. Though we may not
have failures seen with this, we might run into some failures in future.
Better solution would be to fix this by adding reference counting.

Signed-off-by: Subhash Jadavani <subha...@codeaurora.org>
Signed-off-by: Can Guo <c...@codeaurora.org>
Signed-off-by: Asutosh Das <asuto...@codeaurora.org>
---
 drivers/scsi/ufs/ufshcd.c | 44 +---
 drivers/scsi/ufs/ufshcd.h |  5 +
 2 files changed, 42 insertions(+), 7 deletions(-)

diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index 8af2af3..a9ebc8d 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -264,6 +264,36 @@ static inline void ufshcd_disable_irq(struct ufs_hba *hba)
}
 }
 
+void ufshcd_scsi_unblock_requests(struct ufs_hba *hba)
+{
+   unsigned long flags;
+   bool unblock = false;
+
+   spin_lock_irqsave(hba->host->host_lock, flags);
+   hba->scsi_block_reqs_cnt--;
+   unblock = !hba->scsi_block_reqs_cnt;
+   spin_unlock_irqrestore(hba->host->host_lock, flags);
+   if (unblock)
+   scsi_unblock_requests(hba->host);
+}
+EXPORT_SYMBOL(ufshcd_scsi_unblock_requests);
+
+static inline void __ufshcd_scsi_block_requests(struct ufs_hba *hba)
+{
+   if (!hba->scsi_block_reqs_cnt++)
+   scsi_block_requests(hba->host);
+}
+
+void ufshcd_scsi_block_requests(struct ufs_hba *hba)
+{
+   unsigned long flags;
+
+   spin_lock_irqsave(hba->host->host_lock, flags);
+   __ufshcd_scsi_block_requests(hba);
+   spin_unlock_irqrestore(hba->host->host_lock, flags);
+}
+EXPORT_SYMBOL(ufshcd_scsi_block_requests);
+
 /* replace non-printable or non-ASCII characters with spaces */
 static inline void ufshcd_remove_non_printable(char *val)
 {
@@ -1079,12 +1109,12 @@ static int ufshcd_clock_scaling_prepare(struct ufs_hba 
*hba)
 * make sure that there are no outstanding requests when
 * clock scaling is in progress
 */
-   scsi_block_requests(hba->host);
+   ufshcd_scsi_block_requests(hba);
down_write(>clk_scaling_lock);
if (ufshcd_wait_for_doorbell_clr(hba, DOORBELL_CLR_TOUT_US)) {
ret = -EBUSY;
up_write(>clk_scaling_lock);
-   scsi_unblock_requests(hba->host);
+   ufshcd_scsi_unblock_requests(hba);
}
 
return ret;
@@ -1093,7 +1123,7 @@ static int ufshcd_clock_scaling_prepare(struct ufs_hba 
*hba)
 static void ufshcd_clock_scaling_unprepare(struct ufs_hba *hba)
 {
up_write(>clk_scaling_lock);
-   scsi_unblock_requests(hba->host);
+   ufshcd_scsi_unblock_requests(hba);
 }
 
 /**
@@ -1413,7 +1443,7 @@ static void ufshcd_ungate_work(struct work_struct *work)
hba->clk_gating.is_suspended = false;
}
 unblock_reqs:
-   scsi_unblock_requests(hba->host);
+   ufshcd_scsi_unblock_requests(hba);
 }
 
 /**
@@ -1469,7 +1499,7 @@ int ufshcd_hold(struct ufs_hba *hba, bool async)
 * work and to enable clocks.
 */
case CLKS_OFF:
-   scsi_block_requests(hba->host);
+   __ufshcd_scsi_block_requests(hba);
hba->clk_gating.state = REQ_CLKS_ON;
trace_ufshcd_clk_gating(dev_name(hba->dev),
hba->clk_gating.state);
@@ -5178,7 +5208,7 @@ static void ufshcd_err_handler(struct work_struct *work)
 
 out:
spin_unlock_irqrestore(hba->host->host_lock, flags);
-   scsi_unblock_requests(hba->host);
+   ufshcd_scsi_unblock_requests(hba);
ufshcd_release(hba);
pm_runtime_put_sync(hba->dev);
 }
@@ -5280,7 +5310,7 @@ static void ufshcd_check_errors(struct ufs_hba *hba)
/* handle fatal errors only when link is functional */
if (hba->ufshcd_state == UFSHCD_STATE_OPERATIONAL) {
/* block commands from scsi mid-layer */
-   scsi_block_requests(hba->host);
+   __ufshcd_scsi_block_requests(hba);
 
hba->ufshcd_state = UFSHCD_STATE_EH_SCHEDULED;
 
diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h
index 1332

[PATCH 1/1] scsi: ufshcd: fix possible unclocked register access

2018-01-29 Thread Asutosh Das
From: Subhash Jadavani <subha...@codeaurora.org>

vendor specific setup_clocks ops may depend on clocks managed by ufshcd
driver so if the vendor specific setup_clocks callback is called when
the required clocks are turned off, it results into unclocked register
access.

This change make sure that required clocks are enabled before vendor
specific setup_clocks callback is called.

Signed-off-by: Subhash Jadavani <subha...@codeaurora.org>
Signed-off-by: Venkat Gopalakrishnan <venk...@codeaurora.org>
Signed-off-by: Can Guo <c...@codeaurora.org>
Signed-off-by: Asutosh Das <asuto...@codeaurora.org>
---
 drivers/scsi/ufs/ufshcd.c | 26 --
 1 file changed, 20 insertions(+), 6 deletions(-)

diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index 8af2af3..c5ee686 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -6763,9 +6763,16 @@ static int __ufshcd_setup_clocks(struct ufs_hba *hba, 
bool on,
if (list_empty(head))
goto out;
 
-   ret = ufshcd_vops_setup_clocks(hba, on, PRE_CHANGE);
-   if (ret)
-   return ret;
+   /*
+* vendor specific setup_clocks ops may depend on clocks managed by
+* this standard driver hence call the vendor specific setup_clocks
+* before disabling the clocks managed here.
+*/
+   if (!on) {
+   ret = ufshcd_vops_setup_clocks(hba, on, PRE_CHANGE);
+   if (ret)
+   return ret;
+   }
 
list_for_each_entry(clki, head, list) {
if (!IS_ERR_OR_NULL(clki->clk)) {
@@ -6789,9 +6796,16 @@ static int __ufshcd_setup_clocks(struct ufs_hba *hba, 
bool on,
}
}
 
-   ret = ufshcd_vops_setup_clocks(hba, on, POST_CHANGE);
-   if (ret)
-   return ret;
+   /*
+* vendor specific setup_clocks ops may depend on clocks managed by
+* this standard driver hence call the vendor specific setup_clocks
+* after enabling the clocks managed here.
+*/
+   if (on) {
+   ret = ufshcd_vops_setup_clocks(hba, on, POST_CHANGE);
+   if (ret)
+   return ret;
+   }
 
 out:
if (ret) {
-- 
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 1/1] scsi: ufs: fix exception event handling

2018-01-28 Thread Asutosh Das
From: Maya Erez <me...@codeaurora.org>

The device can set the exception event bit in one of the response UPIU,
for example to notify the need for urgent BKOPs operation.
In such a case the host driver calls ufshcd_exception_event_handler to
handle this notification.
When trying to check the exception event status (for finding the cause for
the exception event), the device may be busy with additional SCSI commands
handling and may not respond within the 100ms timeout.

To prevent that, we need to block SCSI commands during handling of
exception events and allow retransmissions of the query requests,
in case of timeout.

Signed-off-by: Subhash Jadavani <subha...@codeaurora.org>
Signed-off-by: Maya Erez <me...@codeaurora.org>
Signed-off-by: Can Guo <c...@codeaurora.org>
Signed-off-by: Asutosh Das <asuto...@codeaurora.org>
---
 drivers/scsi/ufs/ufshcd.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index 8af2af3..2dd488f 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -4955,6 +4955,7 @@ static void ufshcd_exception_event_handler(struct 
work_struct *work)
hba = container_of(work, struct ufs_hba, eeh_work);
 
pm_runtime_get_sync(hba->dev);
+   scsi_block_requests(hba->host);
err = ufshcd_get_ee_status(hba, );
if (err) {
dev_err(hba->dev, "%s: failed to get exception status %d\n",
@@ -4968,6 +4969,7 @@ static void ufshcd_exception_event_handler(struct 
work_struct *work)
ufshcd_bkops_exception_event_handler(hba);
 
 out:
+   scsi_unblock_requests(hba->host);
pm_runtime_put_sync(hba->dev);
return;
 }
-- 
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 1/1] scsi: ufs: Add LCC quirk for host and device

2018-01-25 Thread Asutosh Das
From: Subhash Jadavani <subha...@codeaurora.org>

LCC (Line Control Command) is being used for communication between
UFS host and UFS device. But some hosts might have the issue with
issuing the LCC commands to UFS device and in this case LCC could be
explicitly disabled.

But there could be a need where we don't want to disable the LCC
on both host & device; hence this change splits the quirk in 2 parts
one for host and one for device.

Signed-off-by: Subhash Jadavani <subha...@codeaurora.org>
Signed-off-by: Venkat Gopalakrishnan <venk...@codeaurora.org>
Signed-off-by: Can Guo <c...@codeaurora.org>
Signed-off-by: Asutosh Das <asuto...@codeaurora.org>
---
 drivers/scsi/ufs/ufshcd.c | 16 
 drivers/scsi/ufs/ufshcd.h | 11 +++
 2 files changed, 27 insertions(+)

diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index 8af2af3..d6fc88d 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -4121,6 +4121,11 @@ static int ufshcd_disable_tx_lcc(struct ufs_hba *hba, 
bool peer)
return err;
 }
 
+static inline int ufshcd_disable_host_tx_lcc(struct ufs_hba *hba)
+{
+   return ufshcd_disable_tx_lcc(hba, false);
+}
+
 static inline int ufshcd_disable_device_tx_lcc(struct ufs_hba *hba)
 {
return ufshcd_disable_tx_lcc(hba, true);
@@ -4171,6 +4176,17 @@ static int ufshcd_link_startup(struct ufs_hba *hba)
/* failed to get the link up... retire */
goto out;
 
+   if (hba->quirks & UFSHCD_BROKEN_LCC_PROCESSING_ON_HOST) {
+   ret = ufshcd_disable_device_tx_lcc(hba);
+   if (ret)
+   goto out;
+   }
+
+   if (hba->quirks & UFSHCD_BROKEN_LCC_PROCESSING_ON_DEVICE) {
+   ret = ufshcd_disable_host_tx_lcc(hba);
+   if (ret)
+   goto out;
+   }
if (link_startup_again) {
link_startup_again = false;
retries = DME_LINKSTARTUP_RETRIES;
diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h
index 1332e54..7a2dad3 100644
--- a/drivers/scsi/ufs/ufshcd.h
+++ b/drivers/scsi/ufs/ufshcd.h
@@ -591,6 +591,17 @@ struct ufs_hba {
 */
#define UFSHCD_QUIRK_PRDT_BYTE_GRAN 0x80
 
+   /*
+* If UFS device is having issue in processing LCC (Line Control
+* Command) coming from UFS host controller then enable this quirk.
+* When this quirk is enabled, host controller driver should disable
+* the LCC transmission on UFS host controller (by clearing
+* TX_LCC_ENABLE attribute of host to 0).
+*/
+   #define UFSHCD_BROKEN_LCC_PROCESSING_ON_DEVICE  0x100
+
+   #define UFSHCD_BROKEN_LCC_PROCESSING_ON_HOST0x200
+
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 1/1] scsi: ufs: Enable quirk to ignore sending WRITE_SAME command

2018-01-23 Thread Asutosh Das
From: Sujit Reddy Thumma <sthu...@codeaurora.org>

WRITE_SAME command is not supported by UFS. Enable a quirk for
the upper level drivers to not send WRITE SAME command.

Signed-off-by: Sujit Reddy Thumma <sthu...@codeaurora.org>
Signed-off-by: Subhash Jadavani <subha...@codeaurora.org>
Signed-off-by: Asutosh Das <asuto...@codeaurora.org>
---
 drivers/scsi/ufs/ufshcd.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index 8af2af3..5a8dc3b 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -4356,6 +4356,9 @@ static int ufshcd_slave_alloc(struct scsi_device *sdev)
/* WRITE_SAME command is not supported*/
sdev->no_write_same = 1;
 
+   /* WRITE_SAME command is not supported*/
+   sdev->no_write_same = 1;
+
ufshcd_set_queue_depth(sdev);
 
ufshcd_get_lu_power_on_wp_status(hba, sdev);
-- 
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 1/1] scsi: ufs: Allowing power mode change

2018-01-23 Thread Asutosh Das
From: Yaniv Gardi <yga...@codeaurora.org>

Due to M-PHY issues, moving from HS to any other mode or gear or
even Hibern8 causes some un-predicted behavior of the device.
This patch fixes this issues.

Signed-off-by: Yaniv Gardi <yga...@codeaurora.org>
Signed-off-by: Subhash Jadavani <subha...@codeaurora.org>
Signed-off-by: Can Guo <c...@codeaurora.org>
Signed-off-by: Asutosh Das <asuto...@codeaurora.org>
---
 drivers/scsi/ufs/ufshcd.c | 6 +-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index 011c336..d74d529 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -4167,9 +4167,13 @@ static int ufshcd_link_startup(struct ufs_hba *hba)
goto out;
} while (ret && retries--);
 
-   if (ret)
+   if (ret) {
/* failed to get the link up... retire */
goto out;
+   } else {
+   ufshcd_dme_set(hba, UIC_ARG_MIB(TX_LCC_ENABLE), 0);
+   ufshcd_dme_set(hba, UIC_ARG_MIB(TX_LCC_ENABLE), 1);
+   }
 
if (link_startup_again) {
link_startup_again = false;
-- 
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.



Re: [PATCH 0/5] qcom-ufs: phy/hcd: Refactor phy initialization code

2017-08-13 Thread Asutosh Das (asd)

Vivek,

On 8/11/2017 12:42 PM, Vivek Gautam wrote:

On Fri, Aug 11, 2017 at 5:33 AM, Martin K. Petersen
<martin.peter...@oracle.com> wrote:


Vivek,


Can you kindly review this patch series (for UFS controller changes)
and consider giving your Ack so that Kishon can pull in the series
through phy tree.


SCSI piece looks OK.


Thank you Martin for your review.


Would still like Subhash to review the rest.


Subhash is on vacation with limited access to emails. I will ask
his team to take a look.


Looks good to me.

regards
Vivek



--
Martin K. Petersen  Oracle Linux Engineering
--
To unsubscribe from this list: send the line "unsubscribe linux-arm-msm" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html






--
Asutosh Das (asd)
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, a 
Linux Foundation Collaborative Project


Re: [ufs]: [scsi]: BUG: spinlock recursion on CPU#4

2017-06-05 Thread Asutosh Das (asd)



On 6/1/2017 7:32 PM, Bart Van Assche wrote:

On Thu, 2017-06-01 at 12:28 +0530, Asutosh Das (asd) wrote:

Please can you check if this is actually a bug and my understanding is
correct.


Hello Asutosh,

Spinlock recursion is always a bug. With what kernel version did you encounter
this? Was it with a kernel from kernel.org, a distro kernel or an Android 
kernel?
Have you already tried to reproduce this with kernel debugging enabled? Enabling
CONFIG_DEBUG_SPINLOCK and CONFIG_PROVE_LOCKING should provide more detailed
information.

Bart.



Hello Bart,
Thanks.

It's on 4.4 and its an Android kernel.

No - I haven't tried it out yet. I could get some clues from the 
call-stack itself, like I explained before. I can try these configs 
though. While I do that, I'd like to know your thoughts on my analysis. 
Do you think with the current data, it makes sense?


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


[ufs]: [scsi]: BUG: spinlock recursion on CPU#4

2017-06-01 Thread Asutosh Das (asd)

Hi All,

Recently, I came across an issue with the below call stack.

-000|arch_counter_get_cntvct(inline)
-000|__delay()
-001|__const_udelay(?)
-002|msm_trigger_wdog_bite()
-003|spin_dump(inline)
-003|spin_bug(lock = ?, ?)
-004|current_thread_info(inline)
-004|debug_spin_lock_before(inline)
-004|do_raw_spin_lock()
-005|raw_spin_lock_irqsave(lock = ?)
-006|blk_end_bidi_request(inline)
-006|blk_end_request_all(rq = ?, error = 0) <-- this tries to acquire 
the lock acquired by blk_delay_work (-024) and spinbug recursion occurs


-007|dm_end_request(clone = ?, error = 0)
-008|dm_done(inline)
-008|dm_softirq_done()
-009|blk_done_softirq()
-010|__read_once_size(inline)
-010|static_key_count(inline)
-010|static_key_false(inline)
-010|trace_softirq_exit(inline)
-010|__do_softirq()
-011|do_softirq_own_stack(inline)
-011|invoke_softirq(inline) <-- softirq is triggered because 
scsi_request_fn (-016) enabled interrupts on this cpu


-011|irq_exit()
-012|handle_IPI()
-013|gic_handle_irq()
-014|el1_irq(asm)
 -->|exception
-015|__raw_spin_unlock_irq(inline)
-015|raw_spin_unlock_irq(lock = ?)
-016|scsi_request_fn() <-- Unlocks the queue using spin_unlock, doesn't 
restore the flags, thus enabling the interrupts


-017|__blk_run_queue_uncond(inline)
-017|__blk_run_queue(q = ?)
-018|__elv_add_request()
-019|blk_insert_cloned_request() <-- acquires the queue lock & saves the 
flags


-020|dm_dispatch_clone_request(clone = ?, rq = ?)
-021|map_request()
-022|dm_request_fn()
-023|__blk_run_queue_uncond(inline)
-023|__blk_run_queue
-024|spin_unlock_irq(inline)
-024|blk_delay_work(?) <-- also acquires a queue lock, but this is a 
different queue, blk_end_request_all will reference this queue


-025|__read_once_size(inline)
-025|static_key_count(inline)
-025|static_key_false(inline)
-025|trace_workqueue_execute_end(inline)
-025|process_one_work()
-026|worker_thread()
-027|kthread()
-028|ret_from_fork(asm)
 ---|end of frame

Please can you check if this is actually a bug and my understanding is 
correct.

If so, I can put up a patch for the same.

--
Asutosh Das (asd)

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