[PATCH v1 4/4] scsi: ufs-qcom: fix bug with read/modify write of UFS_CFG1

2016-12-05 Thread Subhash Jadavani
ufs_qcom_print_hw_debug_reg_all() function is having a bug
where it might incorrectly modify undesired bits in UFS_CFG1 register,
this change fixes it.

Reviewed-by: Venkat Gopalakrishnan <venk...@codeaurora.org>
Signed-off-by: Subhash Jadavani <subha...@codeaurora.org>
---
 drivers/scsi/ufs/ufs-qcom.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/drivers/scsi/ufs/ufs-qcom.c b/drivers/scsi/ufs/ufs-qcom.c
index 2943a68..abe6173 100644
--- a/drivers/scsi/ufs/ufs-qcom.c
+++ b/drivers/scsi/ufs/ufs-qcom.c
@@ -1470,7 +1470,8 @@ static void ufs_qcom_print_hw_debug_reg_all(struct 
ufs_hba *hba,
reg = ufs_qcom_get_debug_reg_offset(host, UFS_UFS_DBG_RD_PRDT_RAM);
print_fn(hba, reg, 64, "UFS_UFS_DBG_RD_PRDT_RAM ", priv);
 
-   ufshcd_writel(hba, (reg & ~UFS_BIT(17)), REG_UFS_CFG1);
+   /* clear bit 17 - UTP_DBG_RAMS_EN */
+   ufshcd_rmwl(hba, UFS_BIT(17), 0, REG_UFS_CFG1);
 
reg = ufs_qcom_get_debug_reg_offset(host, UFS_DBG_RD_REG_UAWM);
print_fn(hba, reg, 4, "UFS_DBG_RD_REG_UAWM ", priv);
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project



[PATCH v1 4/4] scsi: ufs-qcom: fix bug with read/modify write of UFS_CFG1

2016-12-05 Thread Subhash Jadavani
ufs_qcom_print_hw_debug_reg_all() function is having a bug
where it might incorrectly modify undesired bits in UFS_CFG1 register,
this change fixes it.

Reviewed-by: Venkat Gopalakrishnan 
Signed-off-by: Subhash Jadavani 
---
 drivers/scsi/ufs/ufs-qcom.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/drivers/scsi/ufs/ufs-qcom.c b/drivers/scsi/ufs/ufs-qcom.c
index 2943a68..abe6173 100644
--- a/drivers/scsi/ufs/ufs-qcom.c
+++ b/drivers/scsi/ufs/ufs-qcom.c
@@ -1470,7 +1470,8 @@ static void ufs_qcom_print_hw_debug_reg_all(struct 
ufs_hba *hba,
reg = ufs_qcom_get_debug_reg_offset(host, UFS_UFS_DBG_RD_PRDT_RAM);
print_fn(hba, reg, 64, "UFS_UFS_DBG_RD_PRDT_RAM ", priv);
 
-   ufshcd_writel(hba, (reg & ~UFS_BIT(17)), REG_UFS_CFG1);
+   /* clear bit 17 - UTP_DBG_RAMS_EN */
+   ufshcd_rmwl(hba, UFS_BIT(17), 0, REG_UFS_CFG1);
 
reg = ufs_qcom_get_debug_reg_offset(host, UFS_DBG_RD_REG_UAWM);
print_fn(hba, reg, 4, "UFS_DBG_RD_REG_UAWM ", priv);
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project



[PATCH v1 2/4] scsi: ufs-qcom: add probe_defer in case phy driver not probed yet

2016-12-05 Thread Subhash Jadavani
From: Yaniv Gardi <yga...@codeaurora.org>

In case UFS driver is probed before the phy driver does, the
UFS driver should return a PROBE_DEFER code.

Signed-off-by: Yaniv Gardi <yga...@codeaurora.org>
Signed-off-by: Subhash Jadavani <subha...@codeaurora.org>
---
 drivers/scsi/ufs/ufs-qcom.c | 11 ++-
 1 file changed, 10 insertions(+), 1 deletion(-)

diff --git a/drivers/scsi/ufs/ufs-qcom.c b/drivers/scsi/ufs/ufs-qcom.c
index aa43bfe..ff61461 100644
--- a/drivers/scsi/ufs/ufs-qcom.c
+++ b/drivers/scsi/ufs/ufs-qcom.c
@@ -1194,7 +1194,16 @@ static int ufs_qcom_init(struct ufs_hba *hba)
 */
host->generic_phy = devm_phy_get(dev, "ufsphy");
 
-   if (IS_ERR(host->generic_phy)) {
+   if (host->generic_phy == ERR_PTR(-EPROBE_DEFER)) {
+   /*
+* UFS driver might be probed before the phy driver does.
+* In that case we would like to return EPROBE_DEFER code.
+*/
+   err = -EPROBE_DEFER;
+   dev_warn(dev, "%s: required phy device. hasn't probed yet. err 
= %d\n",
+   __func__, err);
+   goto out_variant_clear;
+   } else if (IS_ERR(host->generic_phy)) {
err = PTR_ERR(host->generic_phy);
dev_err(dev, "%s: PHY get failed %d\n", __func__, err);
goto out_variant_clear;
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project



[PATCH v1 3/4] scsi: ufs: add quirk to increase host PA_SaveConfigTime

2016-12-05 Thread Subhash Jadavani
The maximum value PA_SaveConfigTime is 250 (10us) but this is not enough
for some vendors. Gear switch from PWM to HS may fail even with this max.
PA_SaveConfigTime. Gear switch can be issued by host controller as an
error recovery and any software delay will not help on this case so we
need to increase PA_SaveConfigTime to >32us as per vendor recommendation.
This change adds a quirk to increase the PA_SaveConfigTime parameter.

Reviewed-by: Venkat Gopalakrishnan <venk...@codeaurora.org>
Signed-off-by: Subhash Jadavani <subha...@codeaurora.org>
---
 drivers/scsi/ufs/ufs-qcom.c   | 30 ++
 drivers/scsi/ufs/ufs-qcom.h   |  1 +
 drivers/scsi/ufs/ufs_quirks.h | 30 +-
 drivers/scsi/ufs/ufshcd.c | 26 ++
 drivers/scsi/ufs/ufshcd.h | 12 ++--
 5 files changed, 76 insertions(+), 23 deletions(-)

diff --git a/drivers/scsi/ufs/ufs-qcom.c b/drivers/scsi/ufs/ufs-qcom.c
index ff61461..2943a68 100644
--- a/drivers/scsi/ufs/ufs-qcom.c
+++ b/drivers/scsi/ufs/ufs-qcom.c
@@ -23,6 +23,7 @@
 #include "unipro.h"
 #include "ufs-qcom.h"
 #include "ufshci.h"
+#include "ufs_quirks.h"
 #define UFS_QCOM_DEFAULT_DBG_PRINT_EN  \
(UFS_QCOM_DBG_PRINT_REGS_EN | UFS_QCOM_DBG_PRINT_TEST_BUS_EN)
 
@@ -1031,6 +1032,34 @@ static int ufs_qcom_pwr_change_notify(struct ufs_hba 
*hba,
return ret;
 }
 
+static int ufs_qcom_quirk_host_pa_saveconfigtime(struct ufs_hba *hba)
+{
+   int err;
+   u32 pa_vs_config_reg1;
+
+   err = ufshcd_dme_get(hba, UIC_ARG_MIB(PA_VS_CONFIG_REG1),
+_vs_config_reg1);
+   if (err)
+   goto out;
+
+   /* Allow extension of MSB bits of PA_SaveConfigTime attribute */
+   err = ufshcd_dme_set(hba, UIC_ARG_MIB(PA_VS_CONFIG_REG1),
+   (pa_vs_config_reg1 | (1 << 12)));
+
+out:
+   return err;
+}
+
+static int ufs_qcom_apply_dev_quirks(struct ufs_hba *hba)
+{
+   int err = 0;
+
+   if (hba->dev_quirks & UFS_DEVICE_QUIRK_HOST_PA_SAVECONFIGTIME)
+   err = ufs_qcom_quirk_host_pa_saveconfigtime(hba);
+
+   return err;
+}
+
 static u32 ufs_qcom_get_ufs_hci_version(struct ufs_hba *hba)
 {
struct ufs_qcom_host *host = ufshcd_get_variant(hba);
@@ -1618,6 +1647,7 @@ static void ufs_qcom_dump_dbg_regs(struct ufs_hba *hba)
.hce_enable_notify  = ufs_qcom_hce_enable_notify,
.link_startup_notify= ufs_qcom_link_startup_notify,
.pwr_change_notify  = ufs_qcom_pwr_change_notify,
+   .apply_dev_quirks   = ufs_qcom_apply_dev_quirks,
.suspend= ufs_qcom_suspend,
.resume = ufs_qcom_resume,
.dbg_register_dump  = ufs_qcom_dump_dbg_regs,
diff --git a/drivers/scsi/ufs/ufs-qcom.h b/drivers/scsi/ufs/ufs-qcom.h
index a19307a..fe517cd 100644
--- a/drivers/scsi/ufs/ufs-qcom.h
+++ b/drivers/scsi/ufs/ufs-qcom.h
@@ -142,6 +142,7 @@ enum ufs_qcom_phy_init_type {
 UFS_QCOM_DBG_PRINT_TEST_BUS_EN)
 
 /* QUniPro Vendor specific attributes */
+#define PA_VS_CONFIG_REG1  0x9000
 #define DME_VS_CORE_CLK_CTRL   0xD002
 /* bit and mask definitions for DME_VS_CORE_CLK_CTRL attribute */
 #define DME_VS_CORE_CLK_CTRL_CORE_CLK_DIV_EN_BIT   BIT(8)
diff --git a/drivers/scsi/ufs/ufs_quirks.h b/drivers/scsi/ufs/ufs_quirks.h
index f798305..08b799d 100644
--- a/drivers/scsi/ufs/ufs_quirks.h
+++ b/drivers/scsi/ufs/ufs_quirks.h
@@ -134,29 +134,17 @@ struct ufs_dev_fix {
  */
 #define UFS_DEVICE_QUIRK_HOST_PA_TACTIVATE (1 << 7)
 
+/*
+ * The max. value PA_SaveConfigTime is 250 (10us) but this is not enough for
+ * some vendors.
+ * Gear switch from PWM to HS may fail even with this max. PA_SaveConfigTime.
+ * Gear switch can be issued by host controller as an error recovery and any
+ * software delay will not help on this case so we need to increase
+ * PA_SaveConfigTime to >32us as per vendor recommendation.
+ */
+#define UFS_DEVICE_QUIRK_HOST_PA_SAVECONFIGTIME(1 << 8)
 
 struct ufs_hba;
 void ufs_advertise_fixup_device(struct ufs_hba *hba);
 
-static struct ufs_dev_fix ufs_fixups[] = {
-   /* UFS cards deviations table */
-   UFS_FIX(UFS_VENDOR_SAMSUNG, UFS_ANY_MODEL,
-   UFS_DEVICE_QUIRK_DELAY_BEFORE_LPM),
-   UFS_FIX(UFS_VENDOR_SAMSUNG, UFS_ANY_MODEL, UFS_DEVICE_NO_VCCQ),
-   UFS_FIX(UFS_VENDOR_SAMSUNG, UFS_ANY_MODEL,
-   UFS_DEVICE_QUIRK_RECOVERY_FROM_DL_NAC_ERRORS),
-   UFS_FIX(UFS_VENDOR_SAMSUNG, UFS_ANY_MODEL,
-   UFS_DEVICE_NO_FASTAUTO),
-   UFS_FIX(UFS_VENDOR_SAMSUNG, UFS_ANY_MODEL,
-   UFS_DEVICE_QUIRK_HOST_PA_TACTIVATE),
-   UFS_FIX(UFS_VENDOR_TOSHIBA, UFS_ANY_MODEL,
-   UFS_DEVICE_QUIRK_DELAY_BEFORE_LPM),
-   UFS_FIX(UFS_VENDOR_TOSHIBA, "THGLF2G9C8KBADG",
-   UFS_DEVICE_QUIRK_PA_TACTIVATE),
-  

[PATCH v1 2/4] scsi: ufs-qcom: add probe_defer in case phy driver not probed yet

2016-12-05 Thread Subhash Jadavani
From: Yaniv Gardi 

In case UFS driver is probed before the phy driver does, the
UFS driver should return a PROBE_DEFER code.

Signed-off-by: Yaniv Gardi 
Signed-off-by: Subhash Jadavani 
---
 drivers/scsi/ufs/ufs-qcom.c | 11 ++-
 1 file changed, 10 insertions(+), 1 deletion(-)

diff --git a/drivers/scsi/ufs/ufs-qcom.c b/drivers/scsi/ufs/ufs-qcom.c
index aa43bfe..ff61461 100644
--- a/drivers/scsi/ufs/ufs-qcom.c
+++ b/drivers/scsi/ufs/ufs-qcom.c
@@ -1194,7 +1194,16 @@ static int ufs_qcom_init(struct ufs_hba *hba)
 */
host->generic_phy = devm_phy_get(dev, "ufsphy");
 
-   if (IS_ERR(host->generic_phy)) {
+   if (host->generic_phy == ERR_PTR(-EPROBE_DEFER)) {
+   /*
+* UFS driver might be probed before the phy driver does.
+* In that case we would like to return EPROBE_DEFER code.
+*/
+   err = -EPROBE_DEFER;
+   dev_warn(dev, "%s: required phy device. hasn't probed yet. err 
= %d\n",
+   __func__, err);
+   goto out_variant_clear;
+   } else if (IS_ERR(host->generic_phy)) {
err = PTR_ERR(host->generic_phy);
dev_err(dev, "%s: PHY get failed %d\n", __func__, err);
goto out_variant_clear;
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project



[PATCH v1 3/4] scsi: ufs: add quirk to increase host PA_SaveConfigTime

2016-12-05 Thread Subhash Jadavani
The maximum value PA_SaveConfigTime is 250 (10us) but this is not enough
for some vendors. Gear switch from PWM to HS may fail even with this max.
PA_SaveConfigTime. Gear switch can be issued by host controller as an
error recovery and any software delay will not help on this case so we
need to increase PA_SaveConfigTime to >32us as per vendor recommendation.
This change adds a quirk to increase the PA_SaveConfigTime parameter.

Reviewed-by: Venkat Gopalakrishnan 
Signed-off-by: Subhash Jadavani 
---
 drivers/scsi/ufs/ufs-qcom.c   | 30 ++
 drivers/scsi/ufs/ufs-qcom.h   |  1 +
 drivers/scsi/ufs/ufs_quirks.h | 30 +-
 drivers/scsi/ufs/ufshcd.c | 26 ++
 drivers/scsi/ufs/ufshcd.h | 12 ++--
 5 files changed, 76 insertions(+), 23 deletions(-)

diff --git a/drivers/scsi/ufs/ufs-qcom.c b/drivers/scsi/ufs/ufs-qcom.c
index ff61461..2943a68 100644
--- a/drivers/scsi/ufs/ufs-qcom.c
+++ b/drivers/scsi/ufs/ufs-qcom.c
@@ -23,6 +23,7 @@
 #include "unipro.h"
 #include "ufs-qcom.h"
 #include "ufshci.h"
+#include "ufs_quirks.h"
 #define UFS_QCOM_DEFAULT_DBG_PRINT_EN  \
(UFS_QCOM_DBG_PRINT_REGS_EN | UFS_QCOM_DBG_PRINT_TEST_BUS_EN)
 
@@ -1031,6 +1032,34 @@ static int ufs_qcom_pwr_change_notify(struct ufs_hba 
*hba,
return ret;
 }
 
+static int ufs_qcom_quirk_host_pa_saveconfigtime(struct ufs_hba *hba)
+{
+   int err;
+   u32 pa_vs_config_reg1;
+
+   err = ufshcd_dme_get(hba, UIC_ARG_MIB(PA_VS_CONFIG_REG1),
+_vs_config_reg1);
+   if (err)
+   goto out;
+
+   /* Allow extension of MSB bits of PA_SaveConfigTime attribute */
+   err = ufshcd_dme_set(hba, UIC_ARG_MIB(PA_VS_CONFIG_REG1),
+   (pa_vs_config_reg1 | (1 << 12)));
+
+out:
+   return err;
+}
+
+static int ufs_qcom_apply_dev_quirks(struct ufs_hba *hba)
+{
+   int err = 0;
+
+   if (hba->dev_quirks & UFS_DEVICE_QUIRK_HOST_PA_SAVECONFIGTIME)
+   err = ufs_qcom_quirk_host_pa_saveconfigtime(hba);
+
+   return err;
+}
+
 static u32 ufs_qcom_get_ufs_hci_version(struct ufs_hba *hba)
 {
struct ufs_qcom_host *host = ufshcd_get_variant(hba);
@@ -1618,6 +1647,7 @@ static void ufs_qcom_dump_dbg_regs(struct ufs_hba *hba)
.hce_enable_notify  = ufs_qcom_hce_enable_notify,
.link_startup_notify= ufs_qcom_link_startup_notify,
.pwr_change_notify  = ufs_qcom_pwr_change_notify,
+   .apply_dev_quirks   = ufs_qcom_apply_dev_quirks,
.suspend= ufs_qcom_suspend,
.resume = ufs_qcom_resume,
.dbg_register_dump  = ufs_qcom_dump_dbg_regs,
diff --git a/drivers/scsi/ufs/ufs-qcom.h b/drivers/scsi/ufs/ufs-qcom.h
index a19307a..fe517cd 100644
--- a/drivers/scsi/ufs/ufs-qcom.h
+++ b/drivers/scsi/ufs/ufs-qcom.h
@@ -142,6 +142,7 @@ enum ufs_qcom_phy_init_type {
 UFS_QCOM_DBG_PRINT_TEST_BUS_EN)
 
 /* QUniPro Vendor specific attributes */
+#define PA_VS_CONFIG_REG1  0x9000
 #define DME_VS_CORE_CLK_CTRL   0xD002
 /* bit and mask definitions for DME_VS_CORE_CLK_CTRL attribute */
 #define DME_VS_CORE_CLK_CTRL_CORE_CLK_DIV_EN_BIT   BIT(8)
diff --git a/drivers/scsi/ufs/ufs_quirks.h b/drivers/scsi/ufs/ufs_quirks.h
index f798305..08b799d 100644
--- a/drivers/scsi/ufs/ufs_quirks.h
+++ b/drivers/scsi/ufs/ufs_quirks.h
@@ -134,29 +134,17 @@ struct ufs_dev_fix {
  */
 #define UFS_DEVICE_QUIRK_HOST_PA_TACTIVATE (1 << 7)
 
+/*
+ * The max. value PA_SaveConfigTime is 250 (10us) but this is not enough for
+ * some vendors.
+ * Gear switch from PWM to HS may fail even with this max. PA_SaveConfigTime.
+ * Gear switch can be issued by host controller as an error recovery and any
+ * software delay will not help on this case so we need to increase
+ * PA_SaveConfigTime to >32us as per vendor recommendation.
+ */
+#define UFS_DEVICE_QUIRK_HOST_PA_SAVECONFIGTIME(1 << 8)
 
 struct ufs_hba;
 void ufs_advertise_fixup_device(struct ufs_hba *hba);
 
-static struct ufs_dev_fix ufs_fixups[] = {
-   /* UFS cards deviations table */
-   UFS_FIX(UFS_VENDOR_SAMSUNG, UFS_ANY_MODEL,
-   UFS_DEVICE_QUIRK_DELAY_BEFORE_LPM),
-   UFS_FIX(UFS_VENDOR_SAMSUNG, UFS_ANY_MODEL, UFS_DEVICE_NO_VCCQ),
-   UFS_FIX(UFS_VENDOR_SAMSUNG, UFS_ANY_MODEL,
-   UFS_DEVICE_QUIRK_RECOVERY_FROM_DL_NAC_ERRORS),
-   UFS_FIX(UFS_VENDOR_SAMSUNG, UFS_ANY_MODEL,
-   UFS_DEVICE_NO_FASTAUTO),
-   UFS_FIX(UFS_VENDOR_SAMSUNG, UFS_ANY_MODEL,
-   UFS_DEVICE_QUIRK_HOST_PA_TACTIVATE),
-   UFS_FIX(UFS_VENDOR_TOSHIBA, UFS_ANY_MODEL,
-   UFS_DEVICE_QUIRK_DELAY_BEFORE_LPM),
-   UFS_FIX(UFS_VENDOR_TOSHIBA, "THGLF2G9C8KBADG",
-   UFS_DEVICE_QUIRK_PA_TACTIVATE),
-   UFS_FIX(UFS_VENDOR_TOSHIBA, "THGLF2G9D8KBADG",
- 

[PATCH v1 1/4] scsi: ufs: add support for UFS HCI 2.1

2016-12-05 Thread Subhash Jadavani
From: Yaniv Gardi <yga...@codeaurora.org>

The UFS HCI v2.1 includes a few additional registers. This change
updates the HCI register, the UFS version register content and
the Interrupt Status register.

Signed-off-by: Yaniv Gardi <yga...@codeaurora.org>
Signed-off-by: Subhash Jadavani <subha...@codeaurora.org>
---
 drivers/scsi/ufs/ufshcd.c | 29 +
 drivers/scsi/ufs/ufshci.h |  7 +++
 2 files changed, 32 insertions(+), 4 deletions(-)

diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index 0c75c75..7af70aa 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -288,10 +288,24 @@ int ufshcd_wait_for_register(struct ufs_hba *hba, u32 
reg, u32 mask,
  */
 static inline u32 ufshcd_get_intr_mask(struct ufs_hba *hba)
 {
-   if (hba->ufs_version == UFSHCI_VERSION_10)
-   return INTERRUPT_MASK_ALL_VER_10;
-   else
-   return INTERRUPT_MASK_ALL_VER_11;
+   u32 intr_mask = 0;
+
+   switch (hba->ufs_version) {
+   case UFSHCI_VERSION_10:
+   intr_mask = INTERRUPT_MASK_ALL_VER_10;
+   break;
+   /* allow fall through */
+   case UFSHCI_VERSION_11:
+   case UFSHCI_VERSION_20:
+   intr_mask = INTERRUPT_MASK_ALL_VER_11;
+   break;
+   /* allow fall through */
+   case UFSHCI_VERSION_21:
+   default:
+   intr_mask = INTERRUPT_MASK_ALL_VER_21;
+   }
+
+   return intr_mask;
 }
 
 /**
@@ -6667,6 +6681,13 @@ int ufshcd_init(struct ufs_hba *hba, void __iomem 
*mmio_base, unsigned int irq)
/* Get UFS version supported by the controller */
hba->ufs_version = ufshcd_get_ufs_version(hba);
 
+   if ((hba->ufs_version != UFSHCI_VERSION_10) &&
+   (hba->ufs_version != UFSHCI_VERSION_11) &&
+   (hba->ufs_version != UFSHCI_VERSION_20) &&
+   (hba->ufs_version != UFSHCI_VERSION_21))
+   dev_err(hba->dev, "invalid UFS version 0x%x\n",
+   hba->ufs_version);
+
/* Get Interrupt bit mask per version */
hba->intr_mask = ufshcd_get_intr_mask(hba);
 
diff --git a/drivers/scsi/ufs/ufshci.h b/drivers/scsi/ufs/ufshci.h
index 5d97886..8c5190e 100644
--- a/drivers/scsi/ufs/ufshci.h
+++ b/drivers/scsi/ufs/ufshci.h
@@ -72,6 +72,10 @@ enum {
REG_UIC_COMMAND_ARG_1   = 0x94,
REG_UIC_COMMAND_ARG_2   = 0x98,
REG_UIC_COMMAND_ARG_3   = 0x9C,
+   REG_UFS_CCAP= 0x100,
+   REG_UFS_CRYPTOCAP   = 0x104,
+
+   UFSHCI_CRYPTO_REG_SPACE_SIZE= 0x400,
 };
 
 /* Controller capability masks */
@@ -275,6 +279,9 @@ enum {
 
/* Interrupt disable mask for UFSHCI v1.1 */
INTERRUPT_MASK_ALL_VER_11   = 0x31FFF,
+
+   /* Interrupt disable mask for UFSHCI v2.1 */
+   INTERRUPT_MASK_ALL_VER_21   = 0x71FFF,
 };
 
 /*
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project



[PATCH v1 1/4] scsi: ufs: add support for UFS HCI 2.1

2016-12-05 Thread Subhash Jadavani
From: Yaniv Gardi 

The UFS HCI v2.1 includes a few additional registers. This change
updates the HCI register, the UFS version register content and
the Interrupt Status register.

Signed-off-by: Yaniv Gardi 
Signed-off-by: Subhash Jadavani 
---
 drivers/scsi/ufs/ufshcd.c | 29 +
 drivers/scsi/ufs/ufshci.h |  7 +++
 2 files changed, 32 insertions(+), 4 deletions(-)

diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index 0c75c75..7af70aa 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -288,10 +288,24 @@ int ufshcd_wait_for_register(struct ufs_hba *hba, u32 
reg, u32 mask,
  */
 static inline u32 ufshcd_get_intr_mask(struct ufs_hba *hba)
 {
-   if (hba->ufs_version == UFSHCI_VERSION_10)
-   return INTERRUPT_MASK_ALL_VER_10;
-   else
-   return INTERRUPT_MASK_ALL_VER_11;
+   u32 intr_mask = 0;
+
+   switch (hba->ufs_version) {
+   case UFSHCI_VERSION_10:
+   intr_mask = INTERRUPT_MASK_ALL_VER_10;
+   break;
+   /* allow fall through */
+   case UFSHCI_VERSION_11:
+   case UFSHCI_VERSION_20:
+   intr_mask = INTERRUPT_MASK_ALL_VER_11;
+   break;
+   /* allow fall through */
+   case UFSHCI_VERSION_21:
+   default:
+   intr_mask = INTERRUPT_MASK_ALL_VER_21;
+   }
+
+   return intr_mask;
 }
 
 /**
@@ -6667,6 +6681,13 @@ int ufshcd_init(struct ufs_hba *hba, void __iomem 
*mmio_base, unsigned int irq)
/* Get UFS version supported by the controller */
hba->ufs_version = ufshcd_get_ufs_version(hba);
 
+   if ((hba->ufs_version != UFSHCI_VERSION_10) &&
+   (hba->ufs_version != UFSHCI_VERSION_11) &&
+   (hba->ufs_version != UFSHCI_VERSION_20) &&
+   (hba->ufs_version != UFSHCI_VERSION_21))
+   dev_err(hba->dev, "invalid UFS version 0x%x\n",
+   hba->ufs_version);
+
/* Get Interrupt bit mask per version */
hba->intr_mask = ufshcd_get_intr_mask(hba);
 
diff --git a/drivers/scsi/ufs/ufshci.h b/drivers/scsi/ufs/ufshci.h
index 5d97886..8c5190e 100644
--- a/drivers/scsi/ufs/ufshci.h
+++ b/drivers/scsi/ufs/ufshci.h
@@ -72,6 +72,10 @@ enum {
REG_UIC_COMMAND_ARG_1   = 0x94,
REG_UIC_COMMAND_ARG_2   = 0x98,
REG_UIC_COMMAND_ARG_3   = 0x9C,
+   REG_UFS_CCAP= 0x100,
+   REG_UFS_CRYPTOCAP   = 0x104,
+
+   UFSHCI_CRYPTO_REG_SPACE_SIZE= 0x400,
 };
 
 /* Controller capability masks */
@@ -275,6 +279,9 @@ enum {
 
/* Interrupt disable mask for UFSHCI v1.1 */
INTERRUPT_MASK_ALL_VER_11   = 0x31FFF,
+
+   /* Interrupt disable mask for UFSHCI v2.1 */
+   INTERRUPT_MASK_ALL_VER_21   = 0x71FFF,
 };
 
 /*
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project



[PATCH v1 11/11] scsi: ufs: fix default power mode to FAST/SLOW

2016-11-23 Thread Subhash Jadavani
We would by default like to run in FAST/SLOW mode instead
of FASTAUTO/SLOWAUTO mode for performance reasons. This
change sets the default speed mode to FAST/SLOW mode.

Reviewed-by: Venkat Gopalakrishnan <venk...@codeaurora.org>
Signed-off-by: Subhash Jadavani <subha...@codeaurora.org>
---
 drivers/scsi/ufs/ufshcd.c | 8 
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index 4b6cc07..0c75c75 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -2821,8 +2821,8 @@ static int ufshcd_get_max_pwr_mode(struct ufs_hba *hba)
if (hba->max_pwr_info.is_valid)
return 0;
 
-   pwr_info->pwr_tx = FASTAUTO_MODE;
-   pwr_info->pwr_rx = FASTAUTO_MODE;
+   pwr_info->pwr_tx = FAST_MODE;
+   pwr_info->pwr_rx = FAST_MODE;
pwr_info->hs_rate = PA_HS_MODE_B;
 
/* Get the connected lane count */
@@ -2853,7 +2853,7 @@ static int ufshcd_get_max_pwr_mode(struct ufs_hba *hba)
__func__, pwr_info->gear_rx);
return -EINVAL;
}
-   pwr_info->pwr_rx = SLOWAUTO_MODE;
+   pwr_info->pwr_rx = SLOW_MODE;
}
 
ufshcd_dme_peer_get(hba, UIC_ARG_MIB(PA_MAXRXHSGEAR),
@@ -2866,7 +2866,7 @@ static int ufshcd_get_max_pwr_mode(struct ufs_hba *hba)
__func__, pwr_info->gear_tx);
return -EINVAL;
}
-   pwr_info->pwr_tx = SLOWAUTO_MODE;
+   pwr_info->pwr_tx = SLOW_MODE;
}
 
hba->max_pwr_info.is_valid = true;
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project



[PATCH v1 11/11] scsi: ufs: fix default power mode to FAST/SLOW

2016-11-23 Thread Subhash Jadavani
We would by default like to run in FAST/SLOW mode instead
of FASTAUTO/SLOWAUTO mode for performance reasons. This
change sets the default speed mode to FAST/SLOW mode.

Reviewed-by: Venkat Gopalakrishnan 
Signed-off-by: Subhash Jadavani 
---
 drivers/scsi/ufs/ufshcd.c | 8 
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index 4b6cc07..0c75c75 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -2821,8 +2821,8 @@ static int ufshcd_get_max_pwr_mode(struct ufs_hba *hba)
if (hba->max_pwr_info.is_valid)
return 0;
 
-   pwr_info->pwr_tx = FASTAUTO_MODE;
-   pwr_info->pwr_rx = FASTAUTO_MODE;
+   pwr_info->pwr_tx = FAST_MODE;
+   pwr_info->pwr_rx = FAST_MODE;
pwr_info->hs_rate = PA_HS_MODE_B;
 
/* Get the connected lane count */
@@ -2853,7 +2853,7 @@ static int ufshcd_get_max_pwr_mode(struct ufs_hba *hba)
__func__, pwr_info->gear_rx);
return -EINVAL;
}
-   pwr_info->pwr_rx = SLOWAUTO_MODE;
+   pwr_info->pwr_rx = SLOW_MODE;
}
 
ufshcd_dme_peer_get(hba, UIC_ARG_MIB(PA_MAXRXHSGEAR),
@@ -2866,7 +2866,7 @@ static int ufshcd_get_max_pwr_mode(struct ufs_hba *hba)
__func__, pwr_info->gear_tx);
return -EINVAL;
}
-   pwr_info->pwr_tx = SLOWAUTO_MODE;
+   pwr_info->pwr_tx = SLOW_MODE;
}
 
hba->max_pwr_info.is_valid = true;
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project



[PATCH v1 03/11] scsi: ufs: update device descriptor maximum size

2016-11-23 Thread Subhash Jadavani
From: Yaniv Gardi <yga...@codeaurora.org>

According to JESD220B - UFS v2.0, the maximum size of device descriptor
has changed from 0x1F to 0x40. This patch updates the maximum size of
this descriptor.

Signed-off-by: Yaniv Gardi <yga...@codeaurora.org>
Signed-off-by: Subhash Jadavani <subha...@codeaurora.org>
---
 drivers/scsi/ufs/ufs.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/scsi/ufs/ufs.h b/drivers/scsi/ufs/ufs.h
index 7a6ccb6..8e6709a 100644
--- a/drivers/scsi/ufs/ufs.h
+++ b/drivers/scsi/ufs/ufs.h
@@ -163,7 +163,7 @@ enum desc_header_offset {
 };
 
 enum ufs_desc_max_size {
-   QUERY_DESC_DEVICE_MAX_SIZE  = 0x1F,
+   QUERY_DESC_DEVICE_MAX_SIZE  = 0x40,
QUERY_DESC_CONFIGURAION_MAX_SIZE= 0x90,
QUERY_DESC_UNIT_MAX_SIZE= 0x23,
QUERY_DESC_INTERCONNECT_MAX_SIZE= 0x06,
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project



[PATCH v1 03/11] scsi: ufs: update device descriptor maximum size

2016-11-23 Thread Subhash Jadavani
From: Yaniv Gardi 

According to JESD220B - UFS v2.0, the maximum size of device descriptor
has changed from 0x1F to 0x40. This patch updates the maximum size of
this descriptor.

Signed-off-by: Yaniv Gardi 
Signed-off-by: Subhash Jadavani 
---
 drivers/scsi/ufs/ufs.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/scsi/ufs/ufs.h b/drivers/scsi/ufs/ufs.h
index 7a6ccb6..8e6709a 100644
--- a/drivers/scsi/ufs/ufs.h
+++ b/drivers/scsi/ufs/ufs.h
@@ -163,7 +163,7 @@ enum desc_header_offset {
 };
 
 enum ufs_desc_max_size {
-   QUERY_DESC_DEVICE_MAX_SIZE  = 0x1F,
+   QUERY_DESC_DEVICE_MAX_SIZE  = 0x40,
QUERY_DESC_CONFIGURAION_MAX_SIZE= 0x90,
QUERY_DESC_UNIT_MAX_SIZE= 0x23,
QUERY_DESC_INTERCONNECT_MAX_SIZE= 0x06,
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project



[PATCH v1 07/11] scsi: ufs: issue link starup 2 times if device isn't active

2016-11-23 Thread Subhash Jadavani
If we issue the link startup to the device while its UniPro state is
LinkDown (and device state is sleep/power-down) then link startup
will not move the device state to Active. Device will only move to
active state if the link starup is issued when its UniPro state is
LinkUp. So in this case, we would have to issue the link startup 2
times to make sure that device moves to active state.

Reviewed-by: Gilad Broner <gbro...@codeaurora.org>
Signed-off-by: Subhash Jadavani <subha...@codeaurora.org>
---
 drivers/scsi/ufs/ufshcd.c | 23 ---
 1 file changed, 20 insertions(+), 3 deletions(-)

diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index 28cbca2..16c5c50 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -3185,7 +3185,16 @@ static int ufshcd_link_startup(struct ufs_hba *hba)
 {
int ret;
int retries = DME_LINKSTARTUP_RETRIES;
+   bool link_startup_again = false;
 
+   /*
+* If UFS device isn't active then we will have to issue link startup
+* 2 times to make sure the device state move to active.
+*/
+   if (!ufshcd_is_ufs_dev_active(hba))
+   link_startup_again = true;
+
+link_startup:
do {
ufshcd_vops_link_startup_notify(hba, PRE_CHANGE);
 
@@ -3211,6 +3220,12 @@ static int ufshcd_link_startup(struct ufs_hba *hba)
/* failed to get the link up... retire */
goto out;
 
+   if (link_startup_again) {
+   link_startup_again = false;
+   retries = DME_LINKSTARTUP_RETRIES;
+   goto link_startup;
+   }
+
if (hba->quirks & UFSHCD_QUIRK_BROKEN_LCC) {
ret = ufshcd_disable_device_tx_lcc(hba);
if (ret)
@@ -6744,10 +6759,12 @@ int ufshcd_init(struct ufs_hba *hba, void __iomem 
*mmio_base, unsigned int irq)
pm_runtime_get_sync(dev);
 
/*
-* The device-initialize-sequence hasn't been invoked yet.
-* Set the device to power-off state
+* We are assuming that device wasn't put in sleep/power-down
+* state exclusively during the boot stage before kernel.
+* This assumption helps avoid doing link startup twice during
+* ufshcd_probe_hba().
 */
-   ufshcd_set_ufs_dev_poweroff(hba);
+   ufshcd_set_ufs_dev_active(hba);
 
async_schedule(ufshcd_async_scan, hba);
 
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project



[PATCH v1 07/11] scsi: ufs: issue link starup 2 times if device isn't active

2016-11-23 Thread Subhash Jadavani
If we issue the link startup to the device while its UniPro state is
LinkDown (and device state is sleep/power-down) then link startup
will not move the device state to Active. Device will only move to
active state if the link starup is issued when its UniPro state is
LinkUp. So in this case, we would have to issue the link startup 2
times to make sure that device moves to active state.

Reviewed-by: Gilad Broner 
Signed-off-by: Subhash Jadavani 
---
 drivers/scsi/ufs/ufshcd.c | 23 ---
 1 file changed, 20 insertions(+), 3 deletions(-)

diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index 28cbca2..16c5c50 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -3185,7 +3185,16 @@ static int ufshcd_link_startup(struct ufs_hba *hba)
 {
int ret;
int retries = DME_LINKSTARTUP_RETRIES;
+   bool link_startup_again = false;
 
+   /*
+* If UFS device isn't active then we will have to issue link startup
+* 2 times to make sure the device state move to active.
+*/
+   if (!ufshcd_is_ufs_dev_active(hba))
+   link_startup_again = true;
+
+link_startup:
do {
ufshcd_vops_link_startup_notify(hba, PRE_CHANGE);
 
@@ -3211,6 +3220,12 @@ static int ufshcd_link_startup(struct ufs_hba *hba)
/* failed to get the link up... retire */
goto out;
 
+   if (link_startup_again) {
+   link_startup_again = false;
+   retries = DME_LINKSTARTUP_RETRIES;
+   goto link_startup;
+   }
+
if (hba->quirks & UFSHCD_QUIRK_BROKEN_LCC) {
ret = ufshcd_disable_device_tx_lcc(hba);
if (ret)
@@ -6744,10 +6759,12 @@ int ufshcd_init(struct ufs_hba *hba, void __iomem 
*mmio_base, unsigned int irq)
pm_runtime_get_sync(dev);
 
/*
-* The device-initialize-sequence hasn't been invoked yet.
-* Set the device to power-off state
+* We are assuming that device wasn't put in sleep/power-down
+* state exclusively during the boot stage before kernel.
+* This assumption helps avoid doing link startup twice during
+* ufshcd_probe_hba().
 */
-   ufshcd_set_ufs_dev_poweroff(hba);
+   ufshcd_set_ufs_dev_active(hba);
 
async_schedule(ufshcd_async_scan, hba);
 
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project



[PATCH v1 04/11] scsi: ufs: fix failure to read the string descriptor

2016-11-23 Thread Subhash Jadavani
While reading variable size descriptors (like string descriptor), some UFS
devices may report the "LENGTH" (field in "Transaction Specific fields" of
Query Response UPIU) same as what was requested in Query Request UPIU
instead of reporting the actual size of the variable size descriptor.
Although it's safe to ignore the "LENGTH" field for variable size
descriptors as we can always derive the length of the descriptor from
the descriptor header fields. Hence this change impose the length match
check only for fixed size descriptors (for which we always request the
correct size as part of Query Request UPIU).

Reviewed-by: Venkat Gopalakrishnan <venk...@codeaurora.org>
Signed-off-by: Subhash Jadavani <subha...@codeaurora.org>
---
 drivers/scsi/ufs/ufshcd.c | 40 +++-
 1 file changed, 31 insertions(+), 9 deletions(-)

diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index 9abc11e..d6e87dc 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -2108,16 +2108,38 @@ static int ufshcd_read_desc_param(struct ufs_hba *hba,
desc_id, desc_index, 0, desc_buf,
_len);
 
-   if (ret || (buff_len < ufs_query_desc_max_size[desc_id]) ||
-   (desc_buf[QUERY_DESC_LENGTH_OFFSET] !=
-ufs_query_desc_max_size[desc_id])
-   || (desc_buf[QUERY_DESC_DESC_TYPE_OFFSET] != desc_id)) {
-   dev_err(hba->dev, "%s: Failed reading descriptor. desc_id %d, 
param_offset %d, buff_len %d ,index %d, ret %d",
-   __func__, desc_id, param_offset, buff_len,
-   desc_index, ret);
-   if (!ret)
-   ret = -EINVAL;
+   if (ret) {
+   dev_err(hba->dev, "%s: Failed reading descriptor. desc_id %d, 
desc_index %d, param_offset %d, ret %d",
+   __func__, desc_id, desc_index, param_offset, ret);
+
+   goto out;
+   }
+
+   /* Sanity check */
+   if (desc_buf[QUERY_DESC_DESC_TYPE_OFFSET] != desc_id) {
+   dev_err(hba->dev, "%s: invalid desc_id %d in descriptor header",
+   __func__, desc_buf[QUERY_DESC_DESC_TYPE_OFFSET]);
+   ret = -EINVAL;
+   goto out;
+   }
 
+   /*
+* While reading variable size descriptors (like string descriptor),
+* some UFS devices may report the "LENGTH" (field in "Transaction
+* Specific fields" of Query Response UPIU) same as what was requested
+* in Query Request UPIU instead of reporting the actual size of the
+* variable size descriptor.
+* Although it's safe to ignore the "LENGTH" field for variable size
+* descriptors as we can always derive the length of the descriptor from
+* the descriptor header fields. Hence this change impose the length
+* match check only for fixed size descriptors (for which we always
+* request the correct size as part of Query Request UPIU).
+*/
+   if ((desc_id != QUERY_DESC_IDN_STRING) &&
+   (buff_len != desc_buf[QUERY_DESC_LENGTH_OFFSET])) {
+   dev_err(hba->dev, "%s: desc_buf length mismatch: buff_len %d, 
buff_len(desc_header) %d",
+   __func__, buff_len, desc_buf[QUERY_DESC_LENGTH_OFFSET]);
+   ret = -EINVAL;
goto out;
}
 
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project



[PATCH v1 04/11] scsi: ufs: fix failure to read the string descriptor

2016-11-23 Thread Subhash Jadavani
While reading variable size descriptors (like string descriptor), some UFS
devices may report the "LENGTH" (field in "Transaction Specific fields" of
Query Response UPIU) same as what was requested in Query Request UPIU
instead of reporting the actual size of the variable size descriptor.
Although it's safe to ignore the "LENGTH" field for variable size
descriptors as we can always derive the length of the descriptor from
the descriptor header fields. Hence this change impose the length match
check only for fixed size descriptors (for which we always request the
correct size as part of Query Request UPIU).

Reviewed-by: Venkat Gopalakrishnan 
Signed-off-by: Subhash Jadavani 
---
 drivers/scsi/ufs/ufshcd.c | 40 +++-
 1 file changed, 31 insertions(+), 9 deletions(-)

diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index 9abc11e..d6e87dc 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -2108,16 +2108,38 @@ static int ufshcd_read_desc_param(struct ufs_hba *hba,
desc_id, desc_index, 0, desc_buf,
_len);
 
-   if (ret || (buff_len < ufs_query_desc_max_size[desc_id]) ||
-   (desc_buf[QUERY_DESC_LENGTH_OFFSET] !=
-ufs_query_desc_max_size[desc_id])
-   || (desc_buf[QUERY_DESC_DESC_TYPE_OFFSET] != desc_id)) {
-   dev_err(hba->dev, "%s: Failed reading descriptor. desc_id %d, 
param_offset %d, buff_len %d ,index %d, ret %d",
-   __func__, desc_id, param_offset, buff_len,
-   desc_index, ret);
-   if (!ret)
-   ret = -EINVAL;
+   if (ret) {
+   dev_err(hba->dev, "%s: Failed reading descriptor. desc_id %d, 
desc_index %d, param_offset %d, ret %d",
+   __func__, desc_id, desc_index, param_offset, ret);
+
+   goto out;
+   }
+
+   /* Sanity check */
+   if (desc_buf[QUERY_DESC_DESC_TYPE_OFFSET] != desc_id) {
+   dev_err(hba->dev, "%s: invalid desc_id %d in descriptor header",
+   __func__, desc_buf[QUERY_DESC_DESC_TYPE_OFFSET]);
+   ret = -EINVAL;
+   goto out;
+   }
 
+   /*
+* While reading variable size descriptors (like string descriptor),
+* some UFS devices may report the "LENGTH" (field in "Transaction
+* Specific fields" of Query Response UPIU) same as what was requested
+* in Query Request UPIU instead of reporting the actual size of the
+* variable size descriptor.
+* Although it's safe to ignore the "LENGTH" field for variable size
+* descriptors as we can always derive the length of the descriptor from
+* the descriptor header fields. Hence this change impose the length
+* match check only for fixed size descriptors (for which we always
+* request the correct size as part of Query Request UPIU).
+*/
+   if ((desc_id != QUERY_DESC_IDN_STRING) &&
+   (buff_len != desc_buf[QUERY_DESC_LENGTH_OFFSET])) {
+   dev_err(hba->dev, "%s: desc_buf length mismatch: buff_len %d, 
buff_len(desc_header) %d",
+   __func__, buff_len, desc_buf[QUERY_DESC_LENGTH_OFFSET]);
+   ret = -EINVAL;
goto out;
}
 
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project



[PATCH v1 01/11] scsi: ufs: add queries retry mechanism

2016-11-23 Thread Subhash Jadavani
From: Dolev Raviv <dra...@codeaurora.org>

Some of the queries might fail during init. To avoid
system failure, we add retry mechanism to issue queries
several times.

Signed-off-by: Dolev Raviv <dra...@codeaurora.org>
Signed-off-by: Subhash Jadavani <subha...@codeaurora.org>
---
 drivers/scsi/ufs/ufshcd.c | 54 +++
 1 file changed, 45 insertions(+), 9 deletions(-)

diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index f91e50b..0b278a1 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -2141,7 +2141,18 @@ static inline int ufshcd_read_power_desc(struct ufs_hba 
*hba,
 u8 *buf,
 u32 size)
 {
-   return ufshcd_read_desc(hba, QUERY_DESC_IDN_POWER, 0, buf, size);
+   int err = 0;
+   int retries;
+
+   for (retries = QUERY_REQ_RETRIES; retries > 0; retries--) {
+   /* Read descriptor*/
+   err = ufshcd_read_desc(hba, QUERY_DESC_IDN_POWER, 0, buf, size);
+   if (!err)
+   break;
+   dev_dbg(hba->dev, "%s: error %d retrying\n", __func__, err);
+   }
+
+   return err;
 }
 
 int ufshcd_read_device_desc(struct ufs_hba *hba, u8 *buf, u32 size)
@@ -3251,16 +3262,24 @@ static void ufshcd_set_queue_depth(struct scsi_device 
*sdev)
 {
int ret = 0;
u8 lun_qdepth;
+   int retries;
struct ufs_hba *hba;
 
hba = shost_priv(sdev->host);
 
lun_qdepth = hba->nutrs;
-   ret = ufshcd_read_unit_desc_param(hba,
- ufshcd_scsi_to_upiu_lun(sdev->lun),
- UNIT_DESC_PARAM_LU_Q_DEPTH,
- _qdepth,
- sizeof(lun_qdepth));
+   for (retries = QUERY_REQ_RETRIES; retries > 0; retries--) {
+   /* Read descriptor*/
+   ret = ufshcd_read_unit_desc_param(hba,
+ ufshcd_scsi_to_upiu_lun(sdev->lun),
+ UNIT_DESC_PARAM_LU_Q_DEPTH,
+ _qdepth,
+ sizeof(lun_qdepth));
+   if (!ret || ret == -ENOTSUPP)
+   break;
+
+   dev_dbg(hba->dev, "%s: error %d retrying\n", __func__, ret);
+   }
 
/* Some WLUN doesn't support unit descriptor */
if (ret == -EOPNOTSUPP)
@@ -4796,6 +4815,24 @@ static u32 ufshcd_find_max_sup_active_icc_level(struct 
ufs_hba *hba,
return icc_level;
 }
 
+static int ufshcd_set_icc_levels_attr(struct ufs_hba *hba, u32 icc_level)
+{
+   int ret = 0;
+   int retries;
+
+   for (retries = QUERY_REQ_RETRIES; retries > 0; retries--) {
+   /* write attribute */
+   ret = ufshcd_query_attr(hba, UPIU_QUERY_OPCODE_WRITE_ATTR,
+   QUERY_ATTR_IDN_ACTIVE_ICC_LVL, 0, 0, _level);
+   if (!ret)
+   break;
+
+   dev_dbg(hba->dev, "%s: failed with error %d\n", __func__, ret);
+   }
+
+   return ret;
+}
+
 static void ufshcd_init_icc_levels(struct ufs_hba *hba)
 {
int ret;
@@ -4816,9 +4853,8 @@ static void ufshcd_init_icc_levels(struct ufs_hba *hba)
dev_dbg(hba->dev, "%s: setting icc_level 0x%x",
__func__, hba->init_prefetch_data.icc_level);
 
-   ret = ufshcd_query_attr_retry(hba, UPIU_QUERY_OPCODE_WRITE_ATTR,
-   QUERY_ATTR_IDN_ACTIVE_ICC_LVL, 0, 0,
-   >init_prefetch_data.icc_level);
+   ret = ufshcd_set_icc_levels_attr(hba,
+hba->init_prefetch_data.icc_level);
 
if (ret)
dev_err(hba->dev,
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project



[PATCH v1 09/11] scsi: ufs: fix condition in which DME command failure msg is printed out

2016-11-23 Thread Subhash Jadavani
From: Yaniv Gardi <yga...@codeaurora.org>

The condition in which error message is printed out was incorrect and
resulted error message only if retries exhausted.
But retries happens only if DME command is a peer command, and thus
DME commands which are not peer commands and fail are not printed out.
This change fixes this issue.

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

diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index ec4c99a..b826078 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -2516,10 +2516,10 @@ int ufshcd_dme_set_attr(struct ufs_hba *hba, u32 
attr_sel,
set, UIC_GET_ATTR_ID(attr_sel), mib_val, ret);
} while (ret && peer && --retries);
 
-   if (!retries)
+   if (ret)
dev_err(hba->dev, "%s: attr-id 0x%x val 0x%x failed %d 
retries\n",
-   set, UIC_GET_ATTR_ID(attr_sel), mib_val,
-   retries);
+   set, UIC_GET_ATTR_ID(attr_sel), mib_val,
+   UFS_UIC_COMMAND_RETRIES - retries);
 
return ret;
 }
@@ -2583,9 +2583,10 @@ int ufshcd_dme_get_attr(struct ufs_hba *hba, u32 
attr_sel,
get, UIC_GET_ATTR_ID(attr_sel), ret);
} while (ret && peer && --retries);
 
-   if (!retries)
+   if (ret)
dev_err(hba->dev, "%s: attr-id 0x%x failed %d retries\n",
-   get, UIC_GET_ATTR_ID(attr_sel), retries);
+   get, UIC_GET_ATTR_ID(attr_sel),
+   UFS_UIC_COMMAND_RETRIES - retries);
 
if (mib_val && !ret)
*mib_val = uic_cmd.argument3;
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project



[PATCH v1 05/11] scsi: ufs: increase the scsi query response timeout

2016-11-23 Thread Subhash Jadavani
It is found thats UFS device may take longer than 30ms to respond to
query requests and in this case we might run into following scenario:

1. UFS host SW sends a query request to UFS device to read an attribute
   value. SW uses tag #31 for this purpose.
2. UFS host SW waits for 30ms to get the query response (and doorbell
   to be cleared by UFS host HW).
3. UFS device doesn't respond back within 30ms hence UFS host SW times
   out waiting for the query response.
4. UFS host SW clears the tag#31 from UTRLCLR register.
5. UFS host SW waits until UFS host HW to clear tag#31 from the doorbell
   register.
6. UFS host SW retries the same query request on same tag#31 (sends a query
   request to device to read an attribute value).
7. UFS host HW gets the query response from the device but this was
   intended as a query response for the 1st query request sent (step-1).
8. Now UFS device sends another query response to host (for query request
   sent @step-6).

Now there are 2 issues that could happen with above scenario:
1. UFS device should have actually responded back with only one query
   response but it is found that device may respond back with 2 query
   responses.
2. If UFS device responds back with 2 resposes on same tag, host HW/SW
   behaviour isn't predictable.

To avoid running into above scenario, we would basically allow device
to take longer (upto 1.5 seconds) for query response.

Reviewed-by: Gilad Broner <gbro...@codeaurora.org>
Signed-off-by: Subhash Jadavani <subha...@codeaurora.org>
---
 drivers/scsi/ufs/ufshcd.c | 13 ++---
 1 file changed, 2 insertions(+), 11 deletions(-)

diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index d6e87dc..393f6d5 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -59,15 +59,9 @@
 #define NOP_OUT_TIMEOUT30 /* msecs */
 
 /* Query request retries */
-#define QUERY_REQ_RETRIES 10
+#define QUERY_REQ_RETRIES 3
 /* Query request timeout */
-#define QUERY_REQ_TIMEOUT 30 /* msec */
-/*
- * Query request timeout for fDeviceInit flag
- * fDeviceInit query response time for some devices is too large that default
- * QUERY_REQ_TIMEOUT may not be enough for such devices.
- */
-#define QUERY_FDEVICEINIT_REQ_TIMEOUT 600 /* msec */
+#define QUERY_REQ_TIMEOUT 1500 /* 1.5 seconds */
 
 /* Task management command timeout */
 #define TM_CMD_TIMEOUT 100 /* msecs */
@@ -1842,9 +1836,6 @@ int ufshcd_query_flag(struct ufs_hba *hba, enum 
query_opcode opcode,
goto out_unlock;
}
 
-   if (idn == QUERY_FLAG_IDN_FDEVICEINIT)
-   timeout = QUERY_FDEVICEINIT_REQ_TIMEOUT;
-
err = ufshcd_exec_dev_cmd(hba, DEV_CMD_TYPE_QUERY, timeout);
 
if (err) {
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project



[PATCH v1 06/11] scsi: ufs: ensure that host pa_tactivate is higher than device

2016-11-23 Thread Subhash Jadavani
Some UFS devices require host PA_TACTIVATE to be higher than
device PA_TACTIVATE otherwise it may get stuck during hibern8 sequence.
This change allows this by using quirk.

Reviewed-by: Venkat Gopalakrishnan <venk...@codeaurora.org>
Signed-off-by: Subhash Jadavani <subha...@codeaurora.org>
---
 drivers/scsi/ufs/ufs_quirks.h |  9 ++
 drivers/scsi/ufs/ufshcd.c | 73 +++
 drivers/scsi/ufs/unipro.h |  4 +++
 3 files changed, 86 insertions(+)

diff --git a/drivers/scsi/ufs/ufs_quirks.h b/drivers/scsi/ufs/ufs_quirks.h
index 22f881e..f798305 100644
--- a/drivers/scsi/ufs/ufs_quirks.h
+++ b/drivers/scsi/ufs/ufs_quirks.h
@@ -128,6 +128,13 @@ struct ufs_dev_fix {
  */
 #define UFS_DEVICE_QUIRK_DELAY_BEFORE_LPM  (1 << 6)
 
+/*
+ * Some UFS devices require host PA_TACTIVATE to be lower than device
+ * PA_TACTIVATE, enabling this quirk ensure this.
+ */
+#define UFS_DEVICE_QUIRK_HOST_PA_TACTIVATE (1 << 7)
+
+
 struct ufs_hba;
 void ufs_advertise_fixup_device(struct ufs_hba *hba);
 
@@ -140,6 +147,8 @@ struct ufs_dev_fix {
UFS_DEVICE_QUIRK_RECOVERY_FROM_DL_NAC_ERRORS),
UFS_FIX(UFS_VENDOR_SAMSUNG, UFS_ANY_MODEL,
UFS_DEVICE_NO_FASTAUTO),
+   UFS_FIX(UFS_VENDOR_SAMSUNG, UFS_ANY_MODEL,
+   UFS_DEVICE_QUIRK_HOST_PA_TACTIVATE),
UFS_FIX(UFS_VENDOR_TOSHIBA, UFS_ANY_MODEL,
UFS_DEVICE_QUIRK_DELAY_BEFORE_LPM),
UFS_FIX(UFS_VENDOR_TOSHIBA, "THGLF2G9C8KBADG",
diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index 393f6d5..28cbca2 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -5089,6 +5089,76 @@ static int ufshcd_tune_pa_hibern8time(struct ufs_hba 
*hba)
return ret;
 }
 
+/**
+ * ufshcd_quirk_tune_host_pa_tactivate - Ensures that host PA_TACTIVATE is
+ * less than device PA_TACTIVATE time.
+ * @hba: per-adapter instance
+ *
+ * Some UFS devices require host PA_TACTIVATE to be lower than device
+ * PA_TACTIVATE, we need to enable UFS_DEVICE_QUIRK_HOST_PA_TACTIVATE quirk
+ * for such devices.
+ *
+ * Returns zero on success, non-zero error value on failure.
+ */
+static int ufshcd_quirk_tune_host_pa_tactivate(struct ufs_hba *hba)
+{
+   int ret = 0;
+   u32 granularity, peer_granularity;
+   u32 pa_tactivate, peer_pa_tactivate;
+   u32 pa_tactivate_us, peer_pa_tactivate_us;
+   u8 gran_to_us_table[] = {1, 4, 8, 16, 32, 100};
+
+   ret = ufshcd_dme_get(hba, UIC_ARG_MIB(PA_GRANULARITY),
+ );
+   if (ret)
+   goto out;
+
+   ret = ufshcd_dme_peer_get(hba, UIC_ARG_MIB(PA_GRANULARITY),
+ _granularity);
+   if (ret)
+   goto out;
+
+   if ((granularity < PA_GRANULARITY_MIN_VAL) ||
+   (granularity > PA_GRANULARITY_MAX_VAL)) {
+   dev_err(hba->dev, "%s: invalid host PA_GRANULARITY %d",
+   __func__, granularity);
+   return -EINVAL;
+   }
+
+   if ((peer_granularity < PA_GRANULARITY_MIN_VAL) ||
+   (peer_granularity > PA_GRANULARITY_MAX_VAL)) {
+   dev_err(hba->dev, "%s: invalid device PA_GRANULARITY %d",
+   __func__, peer_granularity);
+   return -EINVAL;
+   }
+
+   ret = ufshcd_dme_get(hba, UIC_ARG_MIB(PA_TACTIVATE), _tactivate);
+   if (ret)
+   goto out;
+
+   ret = ufshcd_dme_peer_get(hba, UIC_ARG_MIB(PA_TACTIVATE),
+ _pa_tactivate);
+   if (ret)
+   goto out;
+
+   pa_tactivate_us = pa_tactivate * gran_to_us_table[granularity - 1];
+   peer_pa_tactivate_us = peer_pa_tactivate *
+gran_to_us_table[peer_granularity - 1];
+
+   if (pa_tactivate_us > peer_pa_tactivate_us) {
+   u32 new_peer_pa_tactivate;
+
+   new_peer_pa_tactivate = pa_tactivate_us /
+ gran_to_us_table[peer_granularity - 1];
+   new_peer_pa_tactivate++;
+   ret = ufshcd_dme_peer_set(hba, UIC_ARG_MIB(PA_TACTIVATE),
+ new_peer_pa_tactivate);
+   }
+
+out:
+   return ret;
+}
+
 static void ufshcd_tune_unipro_params(struct ufs_hba *hba)
 {
if (ufshcd_is_unipro_pa_params_tuning_req(hba)) {
@@ -5099,6 +5169,9 @@ static void ufshcd_tune_unipro_params(struct ufs_hba *hba)
if (hba->dev_quirks & UFS_DEVICE_QUIRK_PA_TACTIVATE)
/* set 1ms timeout for PA_TACTIVATE */
ufshcd_dme_set(hba, UIC_ARG_MIB(PA_TACTIVATE), 10);
+
+   if (hba->dev_quirks & UFS_DEVICE_QUIRK_HOST_PA_TACTIVATE)
+   ufshcd_quirk_tune_host_pa_tactivate(hba);
 }
 
 /**
diff --git a/drivers/scsi/ufs/unipro.h b/drivers/scsi/ufs/unipro.h
index eff8b56..23129d7 100644
--- a/drivers/scsi

[PATCH v1 08/11] scsi: ufs: handle errors from PHY_ADAPTER_ERROR register

2016-11-23 Thread Subhash Jadavani
From: Dolev Raviv <dra...@codeaurora.org>

The PHY_ADAPTER_ERROR status register indicates PHY lane errors
reported by the M-PHY layer. In some occasions the controller
can recover from such errors. When the error is not recoverable,
a stuck DB error will occur. Since the stuck DB error is spotted
separately, no action other than clearing the register is necessary.

Signed-off-by: Dolev Raviv <dra...@codeaurora.org>
Signed-off-by: Subhash Jadavani <subha...@codeaurora.org>
---
 drivers/scsi/ufs/ufshcd.c | 11 +++
 drivers/scsi/ufs/ufshci.h |  1 +
 2 files changed, 12 insertions(+)

diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index 16c5c50..ec4c99a 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -4215,6 +4215,17 @@ static void ufshcd_update_uic_error(struct ufs_hba *hba)
 {
u32 reg;
 
+   /* 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))
+   /*
+* To know whether this error is fatal or not, DB timeout
+* must be checked but this error is handled separately.
+*/
+   dev_dbg(hba->dev, "%s: UIC Lane error reported\n", __func__);
+
/* PA_INIT_ERROR is fatal and needs UIC reset */
reg = ufshcd_readl(hba, REG_UIC_ERROR_CODE_DATA_LINK_LAYER);
if (reg & UIC_DATA_LINK_LAYER_ERROR_PA_INIT)
diff --git a/drivers/scsi/ufs/ufshci.h b/drivers/scsi/ufs/ufshci.h
index 9599741..bfabb08 100644
--- a/drivers/scsi/ufs/ufshci.h
+++ b/drivers/scsi/ufs/ufshci.h
@@ -166,6 +166,7 @@ enum {
 /* UECPA - Host UIC Error Code PHY Adapter Layer 38h */
 #define UIC_PHY_ADAPTER_LAYER_ERRORUFS_BIT(31)
 #define UIC_PHY_ADAPTER_LAYER_ERROR_CODE_MASK  0x1F
+#define UIC_PHY_ADAPTER_LAYER_LANE_ERR_MASK0xF
 
 /* UECDL - Host UIC Error Code Data Link Layer 3Ch */
 #define UIC_DATA_LINK_LAYER_ERROR  UFS_BIT(31)
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project



[PATCH v1 10/11] scsi: ufs: optimize system suspend handling

2016-11-23 Thread Subhash Jadavani
Consider following sequence of events:
1. UFS is runtime suspended, link_state = Hibern8, device_state = sleep
2. System goes into system suspend, ufshcd_system_suspend() brings both
   link and device to active state and then puts the device in Power_Down
   state and link in OFF state.
3. System resumes at some later point in time, ufshcd_system_resume()
   doesn't do anything as UFS state is runtime suspended. Note that link
   is still on OFF state and device is in Power_Down state.
4. Now system again goes into suspend without any UFS accesses before it.
   ufshcd_system_suspend() again brings both link and device to active
   state and then puts the device in Power_Down state and link if OFF
   state. But it's unnecessary to bring the link & device in active state
   as both link and device are already in desired low power states. This
   change fixes this issue by adding proper state checks in
   ufshcd_system_suspend().

Reviewed-by: Gilad Broner <gbro...@codeaurora.org>
Signed-off-by: Subhash Jadavani <subha...@codeaurora.org>
---
 drivers/scsi/ufs/ufshcd.c | 15 ++-
 1 file changed, 6 insertions(+), 9 deletions(-)

diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index b826078..4b6cc07 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -6272,16 +6272,13 @@ int ufshcd_system_suspend(struct ufs_hba *hba)
if (!hba || !hba->is_powered)
return 0;
 
-   if (pm_runtime_suspended(hba->dev)) {
-   if (hba->rpm_lvl == hba->spm_lvl)
-   /*
-* There is possibility that device may still be in
-* active state during the runtime suspend.
-*/
-   if ((ufs_get_pm_lvl_to_dev_pwr_mode(hba->spm_lvl) ==
-   hba->curr_dev_pwr_mode) && !hba->auto_bkops_enabled)
-   goto out;
+   if ((ufs_get_pm_lvl_to_dev_pwr_mode(hba->spm_lvl) ==
+hba->curr_dev_pwr_mode) &&
+   (ufs_get_pm_lvl_to_link_pwr_state(hba->spm_lvl) ==
+hba->uic_link_state))
+   goto out;
 
+   if (pm_runtime_suspended(hba->dev)) {
/*
 * UFS device and/or UFS link low power states during runtime
 * suspend seems to be different than what is expected during
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project



[PATCH v1 01/11] scsi: ufs: add queries retry mechanism

2016-11-23 Thread Subhash Jadavani
From: Dolev Raviv 

Some of the queries might fail during init. To avoid
system failure, we add retry mechanism to issue queries
several times.

Signed-off-by: Dolev Raviv 
Signed-off-by: Subhash Jadavani 
---
 drivers/scsi/ufs/ufshcd.c | 54 +++
 1 file changed, 45 insertions(+), 9 deletions(-)

diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index f91e50b..0b278a1 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -2141,7 +2141,18 @@ static inline int ufshcd_read_power_desc(struct ufs_hba 
*hba,
 u8 *buf,
 u32 size)
 {
-   return ufshcd_read_desc(hba, QUERY_DESC_IDN_POWER, 0, buf, size);
+   int err = 0;
+   int retries;
+
+   for (retries = QUERY_REQ_RETRIES; retries > 0; retries--) {
+   /* Read descriptor*/
+   err = ufshcd_read_desc(hba, QUERY_DESC_IDN_POWER, 0, buf, size);
+   if (!err)
+   break;
+   dev_dbg(hba->dev, "%s: error %d retrying\n", __func__, err);
+   }
+
+   return err;
 }
 
 int ufshcd_read_device_desc(struct ufs_hba *hba, u8 *buf, u32 size)
@@ -3251,16 +3262,24 @@ static void ufshcd_set_queue_depth(struct scsi_device 
*sdev)
 {
int ret = 0;
u8 lun_qdepth;
+   int retries;
struct ufs_hba *hba;
 
hba = shost_priv(sdev->host);
 
lun_qdepth = hba->nutrs;
-   ret = ufshcd_read_unit_desc_param(hba,
- ufshcd_scsi_to_upiu_lun(sdev->lun),
- UNIT_DESC_PARAM_LU_Q_DEPTH,
- _qdepth,
- sizeof(lun_qdepth));
+   for (retries = QUERY_REQ_RETRIES; retries > 0; retries--) {
+   /* Read descriptor*/
+   ret = ufshcd_read_unit_desc_param(hba,
+ ufshcd_scsi_to_upiu_lun(sdev->lun),
+ UNIT_DESC_PARAM_LU_Q_DEPTH,
+ _qdepth,
+ sizeof(lun_qdepth));
+   if (!ret || ret == -ENOTSUPP)
+   break;
+
+   dev_dbg(hba->dev, "%s: error %d retrying\n", __func__, ret);
+   }
 
/* Some WLUN doesn't support unit descriptor */
if (ret == -EOPNOTSUPP)
@@ -4796,6 +4815,24 @@ static u32 ufshcd_find_max_sup_active_icc_level(struct 
ufs_hba *hba,
return icc_level;
 }
 
+static int ufshcd_set_icc_levels_attr(struct ufs_hba *hba, u32 icc_level)
+{
+   int ret = 0;
+   int retries;
+
+   for (retries = QUERY_REQ_RETRIES; retries > 0; retries--) {
+   /* write attribute */
+   ret = ufshcd_query_attr(hba, UPIU_QUERY_OPCODE_WRITE_ATTR,
+   QUERY_ATTR_IDN_ACTIVE_ICC_LVL, 0, 0, _level);
+   if (!ret)
+   break;
+
+   dev_dbg(hba->dev, "%s: failed with error %d\n", __func__, ret);
+   }
+
+   return ret;
+}
+
 static void ufshcd_init_icc_levels(struct ufs_hba *hba)
 {
int ret;
@@ -4816,9 +4853,8 @@ static void ufshcd_init_icc_levels(struct ufs_hba *hba)
dev_dbg(hba->dev, "%s: setting icc_level 0x%x",
__func__, hba->init_prefetch_data.icc_level);
 
-   ret = ufshcd_query_attr_retry(hba, UPIU_QUERY_OPCODE_WRITE_ATTR,
-   QUERY_ATTR_IDN_ACTIVE_ICC_LVL, 0, 0,
-   >init_prefetch_data.icc_level);
+   ret = ufshcd_set_icc_levels_attr(hba,
+hba->init_prefetch_data.icc_level);
 
if (ret)
dev_err(hba->dev,
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project



[PATCH v1 09/11] scsi: ufs: fix condition in which DME command failure msg is printed out

2016-11-23 Thread Subhash Jadavani
From: Yaniv Gardi 

The condition in which error message is printed out was incorrect and
resulted error message only if retries exhausted.
But retries happens only if DME command is a peer command, and thus
DME commands which are not peer commands and fail are not printed out.
This change fixes this issue.

Signed-off-by: Yaniv Gardi 
Signed-off-by: Subhash Jadavani 
---
 drivers/scsi/ufs/ufshcd.c | 11 ++-
 1 file changed, 6 insertions(+), 5 deletions(-)

diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index ec4c99a..b826078 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -2516,10 +2516,10 @@ int ufshcd_dme_set_attr(struct ufs_hba *hba, u32 
attr_sel,
set, UIC_GET_ATTR_ID(attr_sel), mib_val, ret);
} while (ret && peer && --retries);
 
-   if (!retries)
+   if (ret)
dev_err(hba->dev, "%s: attr-id 0x%x val 0x%x failed %d 
retries\n",
-   set, UIC_GET_ATTR_ID(attr_sel), mib_val,
-   retries);
+   set, UIC_GET_ATTR_ID(attr_sel), mib_val,
+   UFS_UIC_COMMAND_RETRIES - retries);
 
return ret;
 }
@@ -2583,9 +2583,10 @@ int ufshcd_dme_get_attr(struct ufs_hba *hba, u32 
attr_sel,
get, UIC_GET_ATTR_ID(attr_sel), ret);
} while (ret && peer && --retries);
 
-   if (!retries)
+   if (ret)
dev_err(hba->dev, "%s: attr-id 0x%x failed %d retries\n",
-   get, UIC_GET_ATTR_ID(attr_sel), retries);
+   get, UIC_GET_ATTR_ID(attr_sel),
+   UFS_UIC_COMMAND_RETRIES - retries);
 
if (mib_val && !ret)
*mib_val = uic_cmd.argument3;
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project



[PATCH v1 05/11] scsi: ufs: increase the scsi query response timeout

2016-11-23 Thread Subhash Jadavani
It is found thats UFS device may take longer than 30ms to respond to
query requests and in this case we might run into following scenario:

1. UFS host SW sends a query request to UFS device to read an attribute
   value. SW uses tag #31 for this purpose.
2. UFS host SW waits for 30ms to get the query response (and doorbell
   to be cleared by UFS host HW).
3. UFS device doesn't respond back within 30ms hence UFS host SW times
   out waiting for the query response.
4. UFS host SW clears the tag#31 from UTRLCLR register.
5. UFS host SW waits until UFS host HW to clear tag#31 from the doorbell
   register.
6. UFS host SW retries the same query request on same tag#31 (sends a query
   request to device to read an attribute value).
7. UFS host HW gets the query response from the device but this was
   intended as a query response for the 1st query request sent (step-1).
8. Now UFS device sends another query response to host (for query request
   sent @step-6).

Now there are 2 issues that could happen with above scenario:
1. UFS device should have actually responded back with only one query
   response but it is found that device may respond back with 2 query
   responses.
2. If UFS device responds back with 2 resposes on same tag, host HW/SW
   behaviour isn't predictable.

To avoid running into above scenario, we would basically allow device
to take longer (upto 1.5 seconds) for query response.

Reviewed-by: Gilad Broner 
Signed-off-by: Subhash Jadavani 
---
 drivers/scsi/ufs/ufshcd.c | 13 ++---
 1 file changed, 2 insertions(+), 11 deletions(-)

diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index d6e87dc..393f6d5 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -59,15 +59,9 @@
 #define NOP_OUT_TIMEOUT30 /* msecs */
 
 /* Query request retries */
-#define QUERY_REQ_RETRIES 10
+#define QUERY_REQ_RETRIES 3
 /* Query request timeout */
-#define QUERY_REQ_TIMEOUT 30 /* msec */
-/*
- * Query request timeout for fDeviceInit flag
- * fDeviceInit query response time for some devices is too large that default
- * QUERY_REQ_TIMEOUT may not be enough for such devices.
- */
-#define QUERY_FDEVICEINIT_REQ_TIMEOUT 600 /* msec */
+#define QUERY_REQ_TIMEOUT 1500 /* 1.5 seconds */
 
 /* Task management command timeout */
 #define TM_CMD_TIMEOUT 100 /* msecs */
@@ -1842,9 +1836,6 @@ int ufshcd_query_flag(struct ufs_hba *hba, enum 
query_opcode opcode,
goto out_unlock;
}
 
-   if (idn == QUERY_FLAG_IDN_FDEVICEINIT)
-   timeout = QUERY_FDEVICEINIT_REQ_TIMEOUT;
-
err = ufshcd_exec_dev_cmd(hba, DEV_CMD_TYPE_QUERY, timeout);
 
if (err) {
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project



[PATCH v1 06/11] scsi: ufs: ensure that host pa_tactivate is higher than device

2016-11-23 Thread Subhash Jadavani
Some UFS devices require host PA_TACTIVATE to be higher than
device PA_TACTIVATE otherwise it may get stuck during hibern8 sequence.
This change allows this by using quirk.

Reviewed-by: Venkat Gopalakrishnan 
Signed-off-by: Subhash Jadavani 
---
 drivers/scsi/ufs/ufs_quirks.h |  9 ++
 drivers/scsi/ufs/ufshcd.c | 73 +++
 drivers/scsi/ufs/unipro.h |  4 +++
 3 files changed, 86 insertions(+)

diff --git a/drivers/scsi/ufs/ufs_quirks.h b/drivers/scsi/ufs/ufs_quirks.h
index 22f881e..f798305 100644
--- a/drivers/scsi/ufs/ufs_quirks.h
+++ b/drivers/scsi/ufs/ufs_quirks.h
@@ -128,6 +128,13 @@ struct ufs_dev_fix {
  */
 #define UFS_DEVICE_QUIRK_DELAY_BEFORE_LPM  (1 << 6)
 
+/*
+ * Some UFS devices require host PA_TACTIVATE to be lower than device
+ * PA_TACTIVATE, enabling this quirk ensure this.
+ */
+#define UFS_DEVICE_QUIRK_HOST_PA_TACTIVATE (1 << 7)
+
+
 struct ufs_hba;
 void ufs_advertise_fixup_device(struct ufs_hba *hba);
 
@@ -140,6 +147,8 @@ struct ufs_dev_fix {
UFS_DEVICE_QUIRK_RECOVERY_FROM_DL_NAC_ERRORS),
UFS_FIX(UFS_VENDOR_SAMSUNG, UFS_ANY_MODEL,
UFS_DEVICE_NO_FASTAUTO),
+   UFS_FIX(UFS_VENDOR_SAMSUNG, UFS_ANY_MODEL,
+   UFS_DEVICE_QUIRK_HOST_PA_TACTIVATE),
UFS_FIX(UFS_VENDOR_TOSHIBA, UFS_ANY_MODEL,
UFS_DEVICE_QUIRK_DELAY_BEFORE_LPM),
UFS_FIX(UFS_VENDOR_TOSHIBA, "THGLF2G9C8KBADG",
diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index 393f6d5..28cbca2 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -5089,6 +5089,76 @@ static int ufshcd_tune_pa_hibern8time(struct ufs_hba 
*hba)
return ret;
 }
 
+/**
+ * ufshcd_quirk_tune_host_pa_tactivate - Ensures that host PA_TACTIVATE is
+ * less than device PA_TACTIVATE time.
+ * @hba: per-adapter instance
+ *
+ * Some UFS devices require host PA_TACTIVATE to be lower than device
+ * PA_TACTIVATE, we need to enable UFS_DEVICE_QUIRK_HOST_PA_TACTIVATE quirk
+ * for such devices.
+ *
+ * Returns zero on success, non-zero error value on failure.
+ */
+static int ufshcd_quirk_tune_host_pa_tactivate(struct ufs_hba *hba)
+{
+   int ret = 0;
+   u32 granularity, peer_granularity;
+   u32 pa_tactivate, peer_pa_tactivate;
+   u32 pa_tactivate_us, peer_pa_tactivate_us;
+   u8 gran_to_us_table[] = {1, 4, 8, 16, 32, 100};
+
+   ret = ufshcd_dme_get(hba, UIC_ARG_MIB(PA_GRANULARITY),
+ );
+   if (ret)
+   goto out;
+
+   ret = ufshcd_dme_peer_get(hba, UIC_ARG_MIB(PA_GRANULARITY),
+ _granularity);
+   if (ret)
+   goto out;
+
+   if ((granularity < PA_GRANULARITY_MIN_VAL) ||
+   (granularity > PA_GRANULARITY_MAX_VAL)) {
+   dev_err(hba->dev, "%s: invalid host PA_GRANULARITY %d",
+   __func__, granularity);
+   return -EINVAL;
+   }
+
+   if ((peer_granularity < PA_GRANULARITY_MIN_VAL) ||
+   (peer_granularity > PA_GRANULARITY_MAX_VAL)) {
+   dev_err(hba->dev, "%s: invalid device PA_GRANULARITY %d",
+   __func__, peer_granularity);
+   return -EINVAL;
+   }
+
+   ret = ufshcd_dme_get(hba, UIC_ARG_MIB(PA_TACTIVATE), _tactivate);
+   if (ret)
+   goto out;
+
+   ret = ufshcd_dme_peer_get(hba, UIC_ARG_MIB(PA_TACTIVATE),
+ _pa_tactivate);
+   if (ret)
+   goto out;
+
+   pa_tactivate_us = pa_tactivate * gran_to_us_table[granularity - 1];
+   peer_pa_tactivate_us = peer_pa_tactivate *
+gran_to_us_table[peer_granularity - 1];
+
+   if (pa_tactivate_us > peer_pa_tactivate_us) {
+   u32 new_peer_pa_tactivate;
+
+   new_peer_pa_tactivate = pa_tactivate_us /
+ gran_to_us_table[peer_granularity - 1];
+   new_peer_pa_tactivate++;
+   ret = ufshcd_dme_peer_set(hba, UIC_ARG_MIB(PA_TACTIVATE),
+ new_peer_pa_tactivate);
+   }
+
+out:
+   return ret;
+}
+
 static void ufshcd_tune_unipro_params(struct ufs_hba *hba)
 {
if (ufshcd_is_unipro_pa_params_tuning_req(hba)) {
@@ -5099,6 +5169,9 @@ static void ufshcd_tune_unipro_params(struct ufs_hba *hba)
if (hba->dev_quirks & UFS_DEVICE_QUIRK_PA_TACTIVATE)
/* set 1ms timeout for PA_TACTIVATE */
ufshcd_dme_set(hba, UIC_ARG_MIB(PA_TACTIVATE), 10);
+
+   if (hba->dev_quirks & UFS_DEVICE_QUIRK_HOST_PA_TACTIVATE)
+   ufshcd_quirk_tune_host_pa_tactivate(hba);
 }
 
 /**
diff --git a/drivers/scsi/ufs/unipro.h b/drivers/scsi/ufs/unipro.h
index eff8b56..23129d7 100644
--- a/drivers/scsi/ufs/unipro.h
+++ b/drivers/scsi/ufs/unipro.h
@@ -123,6 +123,7 @@

[PATCH v1 10/11] scsi: ufs: optimize system suspend handling

2016-11-23 Thread Subhash Jadavani
Consider following sequence of events:
1. UFS is runtime suspended, link_state = Hibern8, device_state = sleep
2. System goes into system suspend, ufshcd_system_suspend() brings both
   link and device to active state and then puts the device in Power_Down
   state and link in OFF state.
3. System resumes at some later point in time, ufshcd_system_resume()
   doesn't do anything as UFS state is runtime suspended. Note that link
   is still on OFF state and device is in Power_Down state.
4. Now system again goes into suspend without any UFS accesses before it.
   ufshcd_system_suspend() again brings both link and device to active
   state and then puts the device in Power_Down state and link if OFF
   state. But it's unnecessary to bring the link & device in active state
   as both link and device are already in desired low power states. This
   change fixes this issue by adding proper state checks in
   ufshcd_system_suspend().

Reviewed-by: Gilad Broner 
Signed-off-by: Subhash Jadavani 
---
 drivers/scsi/ufs/ufshcd.c | 15 ++-
 1 file changed, 6 insertions(+), 9 deletions(-)

diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index b826078..4b6cc07 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -6272,16 +6272,13 @@ int ufshcd_system_suspend(struct ufs_hba *hba)
if (!hba || !hba->is_powered)
return 0;
 
-   if (pm_runtime_suspended(hba->dev)) {
-   if (hba->rpm_lvl == hba->spm_lvl)
-   /*
-* There is possibility that device may still be in
-* active state during the runtime suspend.
-*/
-   if ((ufs_get_pm_lvl_to_dev_pwr_mode(hba->spm_lvl) ==
-   hba->curr_dev_pwr_mode) && !hba->auto_bkops_enabled)
-   goto out;
+   if ((ufs_get_pm_lvl_to_dev_pwr_mode(hba->spm_lvl) ==
+hba->curr_dev_pwr_mode) &&
+   (ufs_get_pm_lvl_to_link_pwr_state(hba->spm_lvl) ==
+hba->uic_link_state))
+   goto out;
 
+   if (pm_runtime_suspended(hba->dev)) {
/*
 * UFS device and/or UFS link low power states during runtime
 * suspend seems to be different than what is expected during
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project



[PATCH v1 08/11] scsi: ufs: handle errors from PHY_ADAPTER_ERROR register

2016-11-23 Thread Subhash Jadavani
From: Dolev Raviv 

The PHY_ADAPTER_ERROR status register indicates PHY lane errors
reported by the M-PHY layer. In some occasions the controller
can recover from such errors. When the error is not recoverable,
a stuck DB error will occur. Since the stuck DB error is spotted
separately, no action other than clearing the register is necessary.

Signed-off-by: Dolev Raviv 
Signed-off-by: Subhash Jadavani 
---
 drivers/scsi/ufs/ufshcd.c | 11 +++
 drivers/scsi/ufs/ufshci.h |  1 +
 2 files changed, 12 insertions(+)

diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index 16c5c50..ec4c99a 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -4215,6 +4215,17 @@ static void ufshcd_update_uic_error(struct ufs_hba *hba)
 {
u32 reg;
 
+   /* 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))
+   /*
+* To know whether this error is fatal or not, DB timeout
+* must be checked but this error is handled separately.
+*/
+   dev_dbg(hba->dev, "%s: UIC Lane error reported\n", __func__);
+
/* PA_INIT_ERROR is fatal and needs UIC reset */
reg = ufshcd_readl(hba, REG_UIC_ERROR_CODE_DATA_LINK_LAYER);
if (reg & UIC_DATA_LINK_LAYER_ERROR_PA_INIT)
diff --git a/drivers/scsi/ufs/ufshci.h b/drivers/scsi/ufs/ufshci.h
index 9599741..bfabb08 100644
--- a/drivers/scsi/ufs/ufshci.h
+++ b/drivers/scsi/ufs/ufshci.h
@@ -166,6 +166,7 @@ enum {
 /* UECPA - Host UIC Error Code PHY Adapter Layer 38h */
 #define UIC_PHY_ADAPTER_LAYER_ERRORUFS_BIT(31)
 #define UIC_PHY_ADAPTER_LAYER_ERROR_CODE_MASK  0x1F
+#define UIC_PHY_ADAPTER_LAYER_LANE_ERR_MASK0xF
 
 /* UECDL - Host UIC Error Code Data Link Layer 3Ch */
 #define UIC_DATA_LINK_LAYER_ERROR  UFS_BIT(31)
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project



[PATCH v1 02/11] scsi: ufs: add index details to query error messages

2016-11-23 Thread Subhash Jadavani
From: Yaniv Gardi <yga...@codeaurora.org>

When sending query to the device, the index  of the failure
is additional useful information that should be printed out as it
might specify the logical unit (LU) where the error occurred.

Signed-off-by: Yaniv Gardi <yga...@codeaurora.org>
Signed-off-by: Subhash Jadavani <subha...@codeaurora.org>
---
 drivers/scsi/ufs/ufshcd.c | 13 +++--
 1 file changed, 7 insertions(+), 6 deletions(-)

diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index 0b278a1..9abc11e 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -1914,8 +1914,8 @@ static int ufshcd_query_attr(struct ufs_hba *hba, enum 
query_opcode opcode,
err = ufshcd_exec_dev_cmd(hba, DEV_CMD_TYPE_QUERY, QUERY_REQ_TIMEOUT);
 
if (err) {
-   dev_err(hba->dev, "%s: opcode 0x%.2x for idn %d failed, err = 
%d\n",
-   __func__, opcode, idn, err);
+   dev_err(hba->dev, "%s: opcode 0x%.2x for idn %d failed, index 
%d, err = %d\n",
+   __func__, opcode, idn, index, err);
goto out_unlock;
}
 
@@ -2014,8 +2014,8 @@ static int __ufshcd_query_descriptor(struct ufs_hba *hba,
err = ufshcd_exec_dev_cmd(hba, DEV_CMD_TYPE_QUERY, QUERY_REQ_TIMEOUT);
 
if (err) {
-   dev_err(hba->dev, "%s: opcode 0x%.2x for idn %d failed, err = 
%d\n",
-   __func__, opcode, idn, err);
+   dev_err(hba->dev, "%s: opcode 0x%.2x for idn %d failed, index 
%d, err = %d\n",
+   __func__, opcode, idn, index, err);
goto out_unlock;
}
 
@@ -2112,8 +2112,9 @@ static int ufshcd_read_desc_param(struct ufs_hba *hba,
(desc_buf[QUERY_DESC_LENGTH_OFFSET] !=
 ufs_query_desc_max_size[desc_id])
|| (desc_buf[QUERY_DESC_DESC_TYPE_OFFSET] != desc_id)) {
-   dev_err(hba->dev, "%s: Failed reading descriptor. desc_id %d 
param_offset %d buff_len %d ret %d",
-   __func__, desc_id, param_offset, buff_len, ret);
+   dev_err(hba->dev, "%s: Failed reading descriptor. desc_id %d, 
param_offset %d, buff_len %d ,index %d, ret %d",
+   __func__, desc_id, param_offset, buff_len,
+   desc_index, ret);
if (!ret)
ret = -EINVAL;
 
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project



[PATCH v1 02/11] scsi: ufs: add index details to query error messages

2016-11-23 Thread Subhash Jadavani
From: Yaniv Gardi 

When sending query to the device, the index  of the failure
is additional useful information that should be printed out as it
might specify the logical unit (LU) where the error occurred.

Signed-off-by: Yaniv Gardi 
Signed-off-by: Subhash Jadavani 
---
 drivers/scsi/ufs/ufshcd.c | 13 +++--
 1 file changed, 7 insertions(+), 6 deletions(-)

diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index 0b278a1..9abc11e 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -1914,8 +1914,8 @@ static int ufshcd_query_attr(struct ufs_hba *hba, enum 
query_opcode opcode,
err = ufshcd_exec_dev_cmd(hba, DEV_CMD_TYPE_QUERY, QUERY_REQ_TIMEOUT);
 
if (err) {
-   dev_err(hba->dev, "%s: opcode 0x%.2x for idn %d failed, err = 
%d\n",
-   __func__, opcode, idn, err);
+   dev_err(hba->dev, "%s: opcode 0x%.2x for idn %d failed, index 
%d, err = %d\n",
+   __func__, opcode, idn, index, err);
goto out_unlock;
}
 
@@ -2014,8 +2014,8 @@ static int __ufshcd_query_descriptor(struct ufs_hba *hba,
err = ufshcd_exec_dev_cmd(hba, DEV_CMD_TYPE_QUERY, QUERY_REQ_TIMEOUT);
 
if (err) {
-   dev_err(hba->dev, "%s: opcode 0x%.2x for idn %d failed, err = 
%d\n",
-   __func__, opcode, idn, err);
+   dev_err(hba->dev, "%s: opcode 0x%.2x for idn %d failed, index 
%d, err = %d\n",
+   __func__, opcode, idn, index, err);
goto out_unlock;
}
 
@@ -2112,8 +2112,9 @@ static int ufshcd_read_desc_param(struct ufs_hba *hba,
(desc_buf[QUERY_DESC_LENGTH_OFFSET] !=
 ufs_query_desc_max_size[desc_id])
|| (desc_buf[QUERY_DESC_DESC_TYPE_OFFSET] != desc_id)) {
-   dev_err(hba->dev, "%s: Failed reading descriptor. desc_id %d 
param_offset %d buff_len %d ret %d",
-   __func__, desc_id, param_offset, buff_len, ret);
+   dev_err(hba->dev, "%s: Failed reading descriptor. desc_id %d, 
param_offset %d, buff_len %d ,index %d, ret %d",
+   __func__, desc_id, param_offset, buff_len,
+   desc_index, ret);
if (!ret)
ret = -EINVAL;
 
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project



Re: [PATCH v2] ufs: qcom: Properly clear hba priv on failure

2016-11-21 Thread Subhash Jadavani

On 2016-11-19 22:34, Bjorn Andersson wrote:

ufs_qcom_init() sets the hba priv data before attempting to acquire the
phy handle, so make sure to clear this in the case of an error. Failing
to do this will make ufs_qcom_setup_clocks() operate on the 
uninitalized

host object.

Signed-off-by: Bjorn Andersson <bjorn.anders...@linaro.org>
---
 drivers/scsi/ufs/ufs-qcom.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/drivers/scsi/ufs/ufs-qcom.c b/drivers/scsi/ufs/ufs-qcom.c
index d345434b084f..4de372d271b0 100644
--- a/drivers/scsi/ufs/ufs-qcom.c
+++ b/drivers/scsi/ufs/ufs-qcom.c
@@ -1197,12 +1197,12 @@ static int ufs_qcom_init(struct ufs_hba *hba)
if (IS_ERR(host->generic_phy)) {
err = PTR_ERR(host->generic_phy);
dev_err(dev, "%s: PHY get failed %d\n", __func__, err);
-   goto out;
+   goto out_variant_clear;
}

err = ufs_qcom_bus_register(host);
if (err)
-   goto out_host_free;
+   goto out_variant_clear;

ufs_qcom_get_controller_revision(hba, >hw_ver.major,
>hw_ver.minor, >hw_ver.step);
@@ -1267,7 +1267,7 @@ static int ufs_qcom_init(struct ufs_hba *hba)
phy_power_off(host->generic_phy);
 out_unregister_bus:
phy_exit(host->generic_phy);
-out_host_free:
+out_variant_clear:
ufshcd_set_variant(hba, NULL);
 out:
return err;


Looks good to me.
Reviewed-by: Subhash Jadavani <subha...@codeaurora.org>

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


Re: [PATCH v2] ufs: qcom: Properly clear hba priv on failure

2016-11-21 Thread Subhash Jadavani

On 2016-11-19 22:34, Bjorn Andersson wrote:

ufs_qcom_init() sets the hba priv data before attempting to acquire the
phy handle, so make sure to clear this in the case of an error. Failing
to do this will make ufs_qcom_setup_clocks() operate on the 
uninitalized

host object.

Signed-off-by: Bjorn Andersson 
---
 drivers/scsi/ufs/ufs-qcom.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/drivers/scsi/ufs/ufs-qcom.c b/drivers/scsi/ufs/ufs-qcom.c
index d345434b084f..4de372d271b0 100644
--- a/drivers/scsi/ufs/ufs-qcom.c
+++ b/drivers/scsi/ufs/ufs-qcom.c
@@ -1197,12 +1197,12 @@ static int ufs_qcom_init(struct ufs_hba *hba)
if (IS_ERR(host->generic_phy)) {
err = PTR_ERR(host->generic_phy);
dev_err(dev, "%s: PHY get failed %d\n", __func__, err);
-   goto out;
+   goto out_variant_clear;
}

err = ufs_qcom_bus_register(host);
if (err)
-   goto out_host_free;
+   goto out_variant_clear;

ufs_qcom_get_controller_revision(hba, >hw_ver.major,
>hw_ver.minor, >hw_ver.step);
@@ -1267,7 +1267,7 @@ static int ufs_qcom_init(struct ufs_hba *hba)
phy_power_off(host->generic_phy);
 out_unregister_bus:
phy_exit(host->generic_phy);
-out_host_free:
+out_variant_clear:
ufshcd_set_variant(hba, NULL);
 out:
return err;


Looks good to me.
Reviewed-by: Subhash Jadavani 

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


Re: [PATCH] ufs: qcom: Properly clear hba priv on failure

2016-11-21 Thread Subhash Jadavani

On 2016-11-19 22:15, Bjorn Andersson wrote:

On Sat 19 Nov 12:30 PST 2016, Subhash Jadavani wrote:


On 2016-11-18 12:55, Bjorn Andersson wrote:
>In the case where we fail to acquire the phy the hba priv will be set
>already, so during cleanup ufs_qcom_setup_clocks() will dereference the
>now free, but still "valid looking" pointer "host".

host (ufs_qcom_host) was allocated with devm_kzalloc() so i am not 
sure why

it would be freed up before probe() returns failure.



Sorry, I missed the fact that the devm_kfree() was dropped, the actual
problem still remains, although it no longer results in a panic.


Agreed.



As ufs_qcom_init() returns from not having found the phy it the variant
data will be a zero-initialized object.  The error path of
ufshcd_hba_init() will then take us through ufs_qcom_setup_clocks(),
which will pass the check for a NULL variant data and use the
uninitialized host object.


Yes, Make sense.



I can update the commit message to reflect the new state of things.


Your new patch set looks good, will add my ack.



Regards,
Bjorn


>Signed-off-by: Bjorn Andersson <bjorn.anders...@linaro.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 d345434b084f..7bd88ffee47a 100644
>--- a/drivers/scsi/ufs/ufs-qcom.c
>+++ b/drivers/scsi/ufs/ufs-qcom.c
>@@ -1197,7 +1197,7 @@ static int ufs_qcom_init(struct ufs_hba *hba)
>if (IS_ERR(host->generic_phy)) {
>err = PTR_ERR(host->generic_phy);
>dev_err(dev, "%s: PHY get failed %d\n", __func__, err);
>-   goto out;
>+   goto out_host_free;
>}
>
>err = ufs_qcom_bus_register(host);

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

--
To unsubscribe from this list: send the line "unsubscribe linux-scsi" 
in

the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


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


Re: [PATCH] ufs: qcom: Properly clear hba priv on failure

2016-11-21 Thread Subhash Jadavani

On 2016-11-19 22:15, Bjorn Andersson wrote:

On Sat 19 Nov 12:30 PST 2016, Subhash Jadavani wrote:


On 2016-11-18 12:55, Bjorn Andersson wrote:
>In the case where we fail to acquire the phy the hba priv will be set
>already, so during cleanup ufs_qcom_setup_clocks() will dereference the
>now free, but still "valid looking" pointer "host".

host (ufs_qcom_host) was allocated with devm_kzalloc() so i am not 
sure why

it would be freed up before probe() returns failure.



Sorry, I missed the fact that the devm_kfree() was dropped, the actual
problem still remains, although it no longer results in a panic.


Agreed.



As ufs_qcom_init() returns from not having found the phy it the variant
data will be a zero-initialized object.  The error path of
ufshcd_hba_init() will then take us through ufs_qcom_setup_clocks(),
which will pass the check for a NULL variant data and use the
uninitialized host object.


Yes, Make sense.



I can update the commit message to reflect the new state of things.


Your new patch set looks good, will add my ack.



Regards,
Bjorn


>Signed-off-by: Bjorn Andersson 
>---
> 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 d345434b084f..7bd88ffee47a 100644
>--- a/drivers/scsi/ufs/ufs-qcom.c
>+++ b/drivers/scsi/ufs/ufs-qcom.c
>@@ -1197,7 +1197,7 @@ static int ufs_qcom_init(struct ufs_hba *hba)
>if (IS_ERR(host->generic_phy)) {
>err = PTR_ERR(host->generic_phy);
>dev_err(dev, "%s: PHY get failed %d\n", __func__, err);
>-   goto out;
>+   goto out_host_free;
>}
>
>err = ufs_qcom_bus_register(host);

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

--
To unsubscribe from this list: send the line "unsubscribe linux-scsi" 
in

the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


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


Re: [PATCH] ufs: qcom: Properly clear hba priv on failure

2016-11-19 Thread Subhash Jadavani

On 2016-11-18 12:55, Bjorn Andersson wrote:

In the case where we fail to acquire the phy the hba priv will be set
already, so during cleanup ufs_qcom_setup_clocks() will dereference the
now free, but still "valid looking" pointer "host".


host (ufs_qcom_host) was allocated with devm_kzalloc() so i am not sure 
why it would be freed up before probe() returns failure.



Signed-off-by: Bjorn Andersson 
---
 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 d345434b084f..7bd88ffee47a 100644
--- a/drivers/scsi/ufs/ufs-qcom.c
+++ b/drivers/scsi/ufs/ufs-qcom.c
@@ -1197,7 +1197,7 @@ static int ufs_qcom_init(struct ufs_hba *hba)
if (IS_ERR(host->generic_phy)) {
err = PTR_ERR(host->generic_phy);
dev_err(dev, "%s: PHY get failed %d\n", __func__, err);
-   goto out;
+   goto out_host_free;
}

err = ufs_qcom_bus_register(host);


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


Re: [PATCH] ufs: qcom: Properly clear hba priv on failure

2016-11-19 Thread Subhash Jadavani

On 2016-11-18 12:55, Bjorn Andersson wrote:

In the case where we fail to acquire the phy the hba priv will be set
already, so during cleanup ufs_qcom_setup_clocks() will dereference the
now free, but still "valid looking" pointer "host".


host (ufs_qcom_host) was allocated with devm_kzalloc() so i am not sure 
why it would be freed up before probe() returns failure.



Signed-off-by: Bjorn Andersson 
---
 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 d345434b084f..7bd88ffee47a 100644
--- a/drivers/scsi/ufs/ufs-qcom.c
+++ b/drivers/scsi/ufs/ufs-qcom.c
@@ -1197,7 +1197,7 @@ static int ufs_qcom_init(struct ufs_hba *hba)
if (IS_ERR(host->generic_phy)) {
err = PTR_ERR(host->generic_phy);
dev_err(dev, "%s: PHY get failed %d\n", __func__, err);
-   goto out;
+   goto out_host_free;
}

err = ufs_qcom_bus_register(host);


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


Re: [PATCH v2 2/2] scsi: ufs: Use the resource-managed function to add devfreq device

2016-11-08 Thread Subhash Jadavani

On 2016-11-08 01:16, Chanwoo Choi wrote:

This patch uses the resource-managed to add the devfreq device.
This function will make it easy to handle the devfreq device.

- struct devfreq *devm_devfreq_add_device(struct device *dev,
  struct devfreq_dev_profile *profile,
  const char *governor_name,
  void *data);
Cc: Vinayak Holikatti <vinholika...@gmail.com>
Cc: James E.J. Bottomley <j...@linux.vnet.ibm.com>
Cc: Martin K. Petersen <martin.peter...@oracle.com>
Cc: linux-s...@vger.kernel.org
Signed-off-by: Chanwoo Choi <cw00.c...@samsung.com>
---
 drivers/scsi/ufs/ufshcd.c | 4 +---
 1 file changed, 1 insertion(+), 3 deletions(-)

diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index e491c4bda32f..e8c5ba274830 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -6250,8 +6250,6 @@ void ufshcd_remove(struct ufs_hba *hba)
ufshcd_hba_stop(hba, true);

ufshcd_exit_clk_gating(hba);
-   if (ufshcd_is_clkscaling_enabled(hba))
-   devfreq_remove_device(hba->devfreq);
ufshcd_hba_exit(hba);
 }
 EXPORT_SYMBOL_GPL(ufshcd_remove);
@@ -6579,7 +6577,7 @@ int ufshcd_init(struct ufs_hba *hba, void
__iomem *mmio_base, unsigned int irq)
}

if (ufshcd_is_clkscaling_enabled(hba)) {
-   hba->devfreq = devfreq_add_device(dev, _devfreq_profile,
+   hba->devfreq = devm_devfreq_add_device(dev, 
_devfreq_profile,
   "simple_ondemand", NULL);
if (IS_ERR(hba->devfreq)) {
dev_err(hba->dev, "Unable to register with devfreq 
%ld\n",


LGTM.
Reviewed-by: Subhash Jadavani <subha...@codeaurora.org>

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


Re: [PATCH v2 2/2] scsi: ufs: Use the resource-managed function to add devfreq device

2016-11-08 Thread Subhash Jadavani

On 2016-11-08 01:16, Chanwoo Choi wrote:

This patch uses the resource-managed to add the devfreq device.
This function will make it easy to handle the devfreq device.

- struct devfreq *devm_devfreq_add_device(struct device *dev,
  struct devfreq_dev_profile *profile,
  const char *governor_name,
  void *data);
Cc: Vinayak Holikatti 
Cc: James E.J. Bottomley 
Cc: Martin K. Petersen 
Cc: linux-s...@vger.kernel.org
Signed-off-by: Chanwoo Choi 
---
 drivers/scsi/ufs/ufshcd.c | 4 +---
 1 file changed, 1 insertion(+), 3 deletions(-)

diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index e491c4bda32f..e8c5ba274830 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -6250,8 +6250,6 @@ void ufshcd_remove(struct ufs_hba *hba)
ufshcd_hba_stop(hba, true);

ufshcd_exit_clk_gating(hba);
-   if (ufshcd_is_clkscaling_enabled(hba))
-   devfreq_remove_device(hba->devfreq);
ufshcd_hba_exit(hba);
 }
 EXPORT_SYMBOL_GPL(ufshcd_remove);
@@ -6579,7 +6577,7 @@ int ufshcd_init(struct ufs_hba *hba, void
__iomem *mmio_base, unsigned int irq)
}

if (ufshcd_is_clkscaling_enabled(hba)) {
-   hba->devfreq = devfreq_add_device(dev, _devfreq_profile,
+   hba->devfreq = devm_devfreq_add_device(dev, 
_devfreq_profile,
   "simple_ondemand", NULL);
if (IS_ERR(hba->devfreq)) {
dev_err(hba->dev, "Unable to register with devfreq 
%ld\n",


LGTM.
Reviewed-by: Subhash Jadavani 

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


[PATCH v1 3/4] scsi: ufs: suspend clock scaling at the start of suspend

2016-10-27 Thread Subhash Jadavani
Currently clock scaling is suspended only after the host and device
are put in low power mode but we should avoid clock scaling running
after UFS link is put in low power mode (hibern8). This change
suspends clock scaling before putting host/device in low power mode.

Reviewed-by: Sahitya Tummala <stumm...@codeaurora.org>
Signed-off-by: Subhash Jadavani <subha...@codeaurora.org>
---
 drivers/scsi/ufs/ufshcd.c | 14 +-
 1 file changed, 5 insertions(+), 9 deletions(-)

diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index 6c0082e..9ed96ae 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -5892,6 +5892,8 @@ static int ufshcd_suspend(struct ufs_hba *hba, enum 
ufs_pm_op pm_op)
ufshcd_hold(hba, false);
hba->clk_gating.is_suspended = true;
 
+   ufshcd_suspend_clkscaling(hba);
+
if (req_dev_pwr_mode == UFS_ACTIVE_PWR_MODE &&
req_link_state == UIC_LINK_ACTIVE_STATE) {
goto disable_clks;
@@ -5899,12 +5901,12 @@ static int ufshcd_suspend(struct ufs_hba *hba, enum 
ufs_pm_op pm_op)
 
if ((req_dev_pwr_mode == hba->curr_dev_pwr_mode) &&
(req_link_state == hba->uic_link_state))
-   goto out;
+   goto enable_gating;
 
/* UFS device & link must be active before we enter in this function */
if (!ufshcd_is_ufs_dev_active(hba) || !ufshcd_is_link_active(hba)) {
ret = -EINVAL;
-   goto out;
+   goto enable_gating;
}
 
if (ufshcd_is_runtime_pm(pm_op)) {
@@ -5941,13 +5943,6 @@ static int ufshcd_suspend(struct ufs_hba *hba, enum 
ufs_pm_op pm_op)
 
 disable_clks:
/*
-* The clock scaling needs access to controller registers. Hence, Wait
-* for pending clock scaling work to be done before clocks are
-* turned off.
-*/
-   ufshcd_suspend_clkscaling(hba);
-
-   /*
 * Call vendor specific suspend callback. As these callbacks may access
 * vendor specific host controller register space call them before the
 * host clocks are ON.
@@ -5983,6 +5978,7 @@ static int ufshcd_suspend(struct ufs_hba *hba, enum 
ufs_pm_op pm_op)
if (!ufshcd_set_dev_pwr_mode(hba, UFS_ACTIVE_PWR_MODE))
ufshcd_disable_auto_bkops(hba);
 enable_gating:
+   ufshcd_resume_clkscaling(hba);
hba->clk_gating.is_suspended = false;
ufshcd_release(hba);
 out:
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project



[PATCH v1 3/4] scsi: ufs: suspend clock scaling at the start of suspend

2016-10-27 Thread Subhash Jadavani
Currently clock scaling is suspended only after the host and device
are put in low power mode but we should avoid clock scaling running
after UFS link is put in low power mode (hibern8). This change
suspends clock scaling before putting host/device in low power mode.

Reviewed-by: Sahitya Tummala 
Signed-off-by: Subhash Jadavani 
---
 drivers/scsi/ufs/ufshcd.c | 14 +-
 1 file changed, 5 insertions(+), 9 deletions(-)

diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index 6c0082e..9ed96ae 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -5892,6 +5892,8 @@ static int ufshcd_suspend(struct ufs_hba *hba, enum 
ufs_pm_op pm_op)
ufshcd_hold(hba, false);
hba->clk_gating.is_suspended = true;
 
+   ufshcd_suspend_clkscaling(hba);
+
if (req_dev_pwr_mode == UFS_ACTIVE_PWR_MODE &&
req_link_state == UIC_LINK_ACTIVE_STATE) {
goto disable_clks;
@@ -5899,12 +5901,12 @@ static int ufshcd_suspend(struct ufs_hba *hba, enum 
ufs_pm_op pm_op)
 
if ((req_dev_pwr_mode == hba->curr_dev_pwr_mode) &&
(req_link_state == hba->uic_link_state))
-   goto out;
+   goto enable_gating;
 
/* UFS device & link must be active before we enter in this function */
if (!ufshcd_is_ufs_dev_active(hba) || !ufshcd_is_link_active(hba)) {
ret = -EINVAL;
-   goto out;
+   goto enable_gating;
}
 
if (ufshcd_is_runtime_pm(pm_op)) {
@@ -5941,13 +5943,6 @@ static int ufshcd_suspend(struct ufs_hba *hba, enum 
ufs_pm_op pm_op)
 
 disable_clks:
/*
-* The clock scaling needs access to controller registers. Hence, Wait
-* for pending clock scaling work to be done before clocks are
-* turned off.
-*/
-   ufshcd_suspend_clkscaling(hba);
-
-   /*
 * Call vendor specific suspend callback. As these callbacks may access
 * vendor specific host controller register space call them before the
 * host clocks are ON.
@@ -5983,6 +5978,7 @@ static int ufshcd_suspend(struct ufs_hba *hba, enum 
ufs_pm_op pm_op)
if (!ufshcd_set_dev_pwr_mode(hba, UFS_ACTIVE_PWR_MODE))
ufshcd_disable_auto_bkops(hba);
 enable_gating:
+   ufshcd_resume_clkscaling(hba);
hba->clk_gating.is_suspended = false;
ufshcd_release(hba);
 out:
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project



[PATCH v1 2/4] scsi: ufshcd: release resources if probe fails

2016-10-27 Thread Subhash Jadavani
If ufshcd pltfrm/pci driver's probe fails for some reason then ensure that
scsi host is released to avoid memory leak but managed memory allocations
(via devm_* calls) need not to be freed explicitly on probe failure as
memory allocated with these functions is automatically freed on driver
detach.

Reviewed-by: Sahitya Tummala <stumm...@codeaurora.org>
Signed-off-by: Subhash Jadavani <subha...@codeaurora.org>
---
 drivers/scsi/ufs/ufshcd-pci.c| 2 ++
 drivers/scsi/ufs/ufshcd-pltfrm.c | 5 +
 drivers/scsi/ufs/ufshcd.c| 3 ---
 3 files changed, 3 insertions(+), 7 deletions(-)

diff --git a/drivers/scsi/ufs/ufshcd-pci.c b/drivers/scsi/ufs/ufshcd-pci.c
index d15eaa4..52b546f 100644
--- a/drivers/scsi/ufs/ufshcd-pci.c
+++ b/drivers/scsi/ufs/ufshcd-pci.c
@@ -104,6 +104,7 @@ static void ufshcd_pci_remove(struct pci_dev *pdev)
pm_runtime_forbid(>dev);
pm_runtime_get_noresume(>dev);
ufshcd_remove(hba);
+   ufshcd_dealloc_host(hba);
 }
 
 /**
@@ -147,6 +148,7 @@ static void ufshcd_pci_remove(struct pci_dev *pdev)
err = ufshcd_init(hba, mmio_base, pdev->irq);
if (err) {
dev_err(>dev, "Initialization failed\n");
+   ufshcd_dealloc_host(hba);
return err;
}
 
diff --git a/drivers/scsi/ufs/ufshcd-pltfrm.c b/drivers/scsi/ufs/ufshcd-pltfrm.c
index db53f38..a72a4ba 100644
--- a/drivers/scsi/ufs/ufshcd-pltfrm.c
+++ b/drivers/scsi/ufs/ufshcd-pltfrm.c
@@ -163,7 +163,7 @@ static int ufshcd_populate_vreg(struct device *dev, const 
char *name,
if (ret) {
dev_err(dev, "%s: unable to find %s err %d\n",
__func__, prop_name, ret);
-   goto out_free;
+   goto out;
}
 
vreg->min_uA = 0;
@@ -185,9 +185,6 @@ static int ufshcd_populate_vreg(struct device *dev, const 
char *name,
 
goto out;
 
-out_free:
-   devm_kfree(dev, vreg);
-   vreg = NULL;
 out:
if (!ret)
*out_vreg = vreg;
diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index 5c931d1..6c0082e 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -6253,8 +6253,6 @@ void ufshcd_remove(struct ufs_hba *hba)
ufshcd_disable_intr(hba, hba->intr_mask);
ufshcd_hba_stop(hba, true);
 
-   scsi_host_put(hba->host);
-
ufshcd_exit_clk_gating(hba);
if (ufshcd_is_clkscaling_enabled(hba))
devfreq_remove_device(hba->devfreq);
@@ -6616,7 +6614,6 @@ int ufshcd_init(struct ufs_hba *hba, void __iomem 
*mmio_base, unsigned int irq)
ufshcd_exit_clk_gating(hba);
 out_disable:
hba->is_irq_enabled = false;
-   scsi_host_put(host);
ufshcd_hba_exit(hba);
 out_error:
return err;
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project



[PATCH v1 4/4] scsi: ufs: change device rails hpm mode ramp up sequence

2016-10-27 Thread Subhash Jadavani
When we are resuming the UFS device rails in HPM mode, we are first
powering on the VCC rail while VCCQ and VCCQ2 rails still being in LPM
mode. Some UFS devices may take VCC on event as hint that host wants
UFS device to be resumed and may start drawing more power from the
VCCQ/VCCQ2 rails (while they are still in LPM mode) causing voltage drop
on these rails. This change fixes this issue by bringing VCCQ & VCCQ2 rails
out of LPM before powering on VCC rail.

Reviewed-by: Venkat Gopalakrishnan <venk...@codeaurora.org>
Signed-off-by: Subhash Jadavani <subha...@codeaurora.org>
---
 drivers/scsi/ufs/ufshcd.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index 9ed96ae..8cf5d8f 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -5819,7 +5819,6 @@ static int ufshcd_vreg_set_hpm(struct ufs_hba *hba)
!hba->dev_info.is_lu_power_on_wp) {
ret = ufshcd_setup_vreg(hba, true);
} else if (!ufshcd_is_ufs_dev_active(hba)) {
-   ret = ufshcd_toggle_vreg(hba->dev, hba->vreg_info.vcc, true);
if (!ret && !ufshcd_is_link_active(hba)) {
ret = ufshcd_config_vreg_hpm(hba, hba->vreg_info.vccq);
if (ret)
@@ -5828,6 +5827,7 @@ static int ufshcd_vreg_set_hpm(struct ufs_hba *hba)
if (ret)
goto vccq_lpm;
}
+   ret = ufshcd_toggle_vreg(hba->dev, hba->vreg_info.vcc, true);
}
goto out;
 
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project



[PATCH v1 2/4] scsi: ufshcd: release resources if probe fails

2016-10-27 Thread Subhash Jadavani
If ufshcd pltfrm/pci driver's probe fails for some reason then ensure that
scsi host is released to avoid memory leak but managed memory allocations
(via devm_* calls) need not to be freed explicitly on probe failure as
memory allocated with these functions is automatically freed on driver
detach.

Reviewed-by: Sahitya Tummala 
Signed-off-by: Subhash Jadavani 
---
 drivers/scsi/ufs/ufshcd-pci.c| 2 ++
 drivers/scsi/ufs/ufshcd-pltfrm.c | 5 +
 drivers/scsi/ufs/ufshcd.c| 3 ---
 3 files changed, 3 insertions(+), 7 deletions(-)

diff --git a/drivers/scsi/ufs/ufshcd-pci.c b/drivers/scsi/ufs/ufshcd-pci.c
index d15eaa4..52b546f 100644
--- a/drivers/scsi/ufs/ufshcd-pci.c
+++ b/drivers/scsi/ufs/ufshcd-pci.c
@@ -104,6 +104,7 @@ static void ufshcd_pci_remove(struct pci_dev *pdev)
pm_runtime_forbid(>dev);
pm_runtime_get_noresume(>dev);
ufshcd_remove(hba);
+   ufshcd_dealloc_host(hba);
 }
 
 /**
@@ -147,6 +148,7 @@ static void ufshcd_pci_remove(struct pci_dev *pdev)
err = ufshcd_init(hba, mmio_base, pdev->irq);
if (err) {
dev_err(>dev, "Initialization failed\n");
+   ufshcd_dealloc_host(hba);
return err;
}
 
diff --git a/drivers/scsi/ufs/ufshcd-pltfrm.c b/drivers/scsi/ufs/ufshcd-pltfrm.c
index db53f38..a72a4ba 100644
--- a/drivers/scsi/ufs/ufshcd-pltfrm.c
+++ b/drivers/scsi/ufs/ufshcd-pltfrm.c
@@ -163,7 +163,7 @@ static int ufshcd_populate_vreg(struct device *dev, const 
char *name,
if (ret) {
dev_err(dev, "%s: unable to find %s err %d\n",
__func__, prop_name, ret);
-   goto out_free;
+   goto out;
}
 
vreg->min_uA = 0;
@@ -185,9 +185,6 @@ static int ufshcd_populate_vreg(struct device *dev, const 
char *name,
 
goto out;
 
-out_free:
-   devm_kfree(dev, vreg);
-   vreg = NULL;
 out:
if (!ret)
*out_vreg = vreg;
diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index 5c931d1..6c0082e 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -6253,8 +6253,6 @@ void ufshcd_remove(struct ufs_hba *hba)
ufshcd_disable_intr(hba, hba->intr_mask);
ufshcd_hba_stop(hba, true);
 
-   scsi_host_put(hba->host);
-
ufshcd_exit_clk_gating(hba);
if (ufshcd_is_clkscaling_enabled(hba))
devfreq_remove_device(hba->devfreq);
@@ -6616,7 +6614,6 @@ int ufshcd_init(struct ufs_hba *hba, void __iomem 
*mmio_base, unsigned int irq)
ufshcd_exit_clk_gating(hba);
 out_disable:
hba->is_irq_enabled = false;
-   scsi_host_put(host);
ufshcd_hba_exit(hba);
 out_error:
return err;
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project



[PATCH v1 4/4] scsi: ufs: change device rails hpm mode ramp up sequence

2016-10-27 Thread Subhash Jadavani
When we are resuming the UFS device rails in HPM mode, we are first
powering on the VCC rail while VCCQ and VCCQ2 rails still being in LPM
mode. Some UFS devices may take VCC on event as hint that host wants
UFS device to be resumed and may start drawing more power from the
VCCQ/VCCQ2 rails (while they are still in LPM mode) causing voltage drop
on these rails. This change fixes this issue by bringing VCCQ & VCCQ2 rails
out of LPM before powering on VCC rail.

Reviewed-by: Venkat Gopalakrishnan 
Signed-off-by: Subhash Jadavani 
---
 drivers/scsi/ufs/ufshcd.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index 9ed96ae..8cf5d8f 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -5819,7 +5819,6 @@ static int ufshcd_vreg_set_hpm(struct ufs_hba *hba)
!hba->dev_info.is_lu_power_on_wp) {
ret = ufshcd_setup_vreg(hba, true);
} else if (!ufshcd_is_ufs_dev_active(hba)) {
-   ret = ufshcd_toggle_vreg(hba->dev, hba->vreg_info.vcc, true);
if (!ret && !ufshcd_is_link_active(hba)) {
ret = ufshcd_config_vreg_hpm(hba, hba->vreg_info.vccq);
if (ret)
@@ -5828,6 +5827,7 @@ static int ufshcd_vreg_set_hpm(struct ufs_hba *hba)
if (ret)
goto vccq_lpm;
}
+   ret = ufshcd_toggle_vreg(hba->dev, hba->vreg_info.vcc, true);
}
goto out;
 
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project



[PATCH v1 1/4] scsi: ufs: fix race between clock gating and devfreq scaling work

2016-10-27 Thread Subhash Jadavani
UFS devfreq clock scaling work may require clocks to be ON if it need to
execute some UFS commands hence it may request for clock hold before
issuing the command. But if UFS clock gating work is already running in
parallel, ungate work would end up waiting for the clock gating work to
finish and as clock gating work would also wait for the clock scaling work
to finish, we would enter in deadlock state. Here is the call trace during
this deadlock state:

Workqueue: devfreq_wq devfreq_monitor
__switch_to
__schedule
schedule
schedule_timeout
wait_for_common
wait_for_completion
flush_work
ufshcd_hold
ufshcd_send_uic_cmd
ufshcd_dme_get_attr
ufs_qcom_set_dme_vs_core_clk_ctrl_clear_div
ufs_qcom_clk_scale_notify
ufshcd_scale_clks
ufshcd_devfreq_target
update_devfreq
devfreq_monitor
process_one_work
worker_thread
kthread
ret_from_fork

Workqueue: events ufshcd_gate_work
__switch_to
__schedule
schedule
schedule_preempt_disabled
__mutex_lock_slowpath
mutex_lock
devfreq_monitor_suspend
devfreq_simple_ondemand_handler
devfreq_suspend_device
ufshcd_gate_work
process_one_work
worker_thread
kthread
ret_from_fork

Workqueue: events ufshcd_ungate_work
__switch_to
__schedule
schedule
schedule_timeout
wait_for_common
wait_for_completion
flush_work
__cancel_work_timer
cancel_delayed_work_sync
ufshcd_ungate_work
process_one_work
worker_thread
kthread
ret_from_fork

This change fixes this deadlock by doing this in devfreq work (devfreq_wq):
Try cancelling clock gating work. If we are able to cancel gating work
or it wasn't scheduled, hold the clock reference count until scaling is
in progress. If gate work is already running in parallel, let's skip
the frequecy scaling at this time and it will be retried once next scaling
window expires.

Reviewed-by: Sahitya Tummala <stumm...@codeaurora.org>
Signed-off-by: Subhash Jadavani <subha...@codeaurora.org>
---
 drivers/scsi/ufs/ufshcd.c | 32 
 1 file changed, 32 insertions(+)

diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index 304adce..5c931d1 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -6379,15 +6379,47 @@ static int ufshcd_devfreq_target(struct device *dev,
 {
int err = 0;
struct ufs_hba *hba = dev_get_drvdata(dev);
+   bool release_clk_hold = false;
+   unsigned long irq_flags;
 
if (!ufshcd_is_clkscaling_enabled(hba))
return -EINVAL;
 
+   spin_lock_irqsave(hba->host->host_lock, irq_flags);
+   if (ufshcd_eh_in_progress(hba)) {
+   spin_unlock_irqrestore(hba->host->host_lock, irq_flags);
+   return 0;
+   }
+
+   if (ufshcd_is_clkgating_allowed(hba) &&
+   (hba->clk_gating.state != CLKS_ON)) {
+   if (cancel_delayed_work(>clk_gating.gate_work)) {
+   /* hold the vote until the scaling work is completed */
+   hba->clk_gating.active_reqs++;
+   release_clk_hold = true;
+   hba->clk_gating.state = CLKS_ON;
+   } else {
+   /*
+* Clock gating work seems to be running in parallel
+* hence skip scaling work to avoid deadlock between
+* current scaling work and gating work.
+*/
+   spin_unlock_irqrestore(hba->host->host_lock, irq_flags);
+   return 0;
+   }
+   }
+   spin_unlock_irqrestore(hba->host->host_lock, irq_flags);
+
if (*freq == UINT_MAX)
err = ufshcd_scale_clks(hba, true);
else if (*freq == 0)
err = ufshcd_scale_clks(hba, false);
 
+   spin_lock_irqsave(hba->host->host_lock, irq_flags);
+   if (release_clk_hold)
+   __ufshcd_release(hba);
+   spin_unlock_irqrestore(hba->host->host_lock, irq_flags);
+
return err;
 }
 
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project



[PATCH v1 1/4] scsi: ufs: fix race between clock gating and devfreq scaling work

2016-10-27 Thread Subhash Jadavani
UFS devfreq clock scaling work may require clocks to be ON if it need to
execute some UFS commands hence it may request for clock hold before
issuing the command. But if UFS clock gating work is already running in
parallel, ungate work would end up waiting for the clock gating work to
finish and as clock gating work would also wait for the clock scaling work
to finish, we would enter in deadlock state. Here is the call trace during
this deadlock state:

Workqueue: devfreq_wq devfreq_monitor
__switch_to
__schedule
schedule
schedule_timeout
wait_for_common
wait_for_completion
flush_work
ufshcd_hold
ufshcd_send_uic_cmd
ufshcd_dme_get_attr
ufs_qcom_set_dme_vs_core_clk_ctrl_clear_div
ufs_qcom_clk_scale_notify
ufshcd_scale_clks
ufshcd_devfreq_target
update_devfreq
devfreq_monitor
process_one_work
worker_thread
kthread
ret_from_fork

Workqueue: events ufshcd_gate_work
__switch_to
__schedule
schedule
schedule_preempt_disabled
__mutex_lock_slowpath
mutex_lock
devfreq_monitor_suspend
devfreq_simple_ondemand_handler
devfreq_suspend_device
ufshcd_gate_work
process_one_work
worker_thread
kthread
ret_from_fork

Workqueue: events ufshcd_ungate_work
__switch_to
__schedule
schedule
schedule_timeout
wait_for_common
wait_for_completion
flush_work
__cancel_work_timer
cancel_delayed_work_sync
ufshcd_ungate_work
process_one_work
worker_thread
kthread
ret_from_fork

This change fixes this deadlock by doing this in devfreq work (devfreq_wq):
Try cancelling clock gating work. If we are able to cancel gating work
or it wasn't scheduled, hold the clock reference count until scaling is
in progress. If gate work is already running in parallel, let's skip
the frequecy scaling at this time and it will be retried once next scaling
window expires.

Reviewed-by: Sahitya Tummala 
Signed-off-by: Subhash Jadavani 
---
 drivers/scsi/ufs/ufshcd.c | 32 
 1 file changed, 32 insertions(+)

diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index 304adce..5c931d1 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -6379,15 +6379,47 @@ static int ufshcd_devfreq_target(struct device *dev,
 {
int err = 0;
struct ufs_hba *hba = dev_get_drvdata(dev);
+   bool release_clk_hold = false;
+   unsigned long irq_flags;
 
if (!ufshcd_is_clkscaling_enabled(hba))
return -EINVAL;
 
+   spin_lock_irqsave(hba->host->host_lock, irq_flags);
+   if (ufshcd_eh_in_progress(hba)) {
+   spin_unlock_irqrestore(hba->host->host_lock, irq_flags);
+   return 0;
+   }
+
+   if (ufshcd_is_clkgating_allowed(hba) &&
+   (hba->clk_gating.state != CLKS_ON)) {
+   if (cancel_delayed_work(>clk_gating.gate_work)) {
+   /* hold the vote until the scaling work is completed */
+   hba->clk_gating.active_reqs++;
+   release_clk_hold = true;
+   hba->clk_gating.state = CLKS_ON;
+   } else {
+   /*
+* Clock gating work seems to be running in parallel
+* hence skip scaling work to avoid deadlock between
+* current scaling work and gating work.
+*/
+   spin_unlock_irqrestore(hba->host->host_lock, irq_flags);
+   return 0;
+   }
+   }
+   spin_unlock_irqrestore(hba->host->host_lock, irq_flags);
+
if (*freq == UINT_MAX)
err = ufshcd_scale_clks(hba, true);
else if (*freq == 0)
err = ufshcd_scale_clks(hba, false);
 
+   spin_lock_irqsave(hba->host->host_lock, irq_flags);
+   if (release_clk_hold)
+   __ufshcd_release(hba);
+   spin_unlock_irqrestore(hba->host->host_lock, irq_flags);
+
return err;
 }
 
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project



Re: [PATCH 2/2] scsi: ufs: Use the resource-managed function to add devfreq device

2016-10-26 Thread Subhash Jadavani

On 2016-10-26 00:38, Chanwoo Choi wrote:

This patch uses the resource-managed to add the devfreq device.
This function will make it easy to handle the devfreq device.

- struct devfreq *devm_devfreq_add_device(struct device *dev,
  struct devfreq_dev_profile *profile,
  const char *governor_name,
  void *data);
Cc: Vinayak Holikatti 
Cc: James E.J. Bottomley 
Cc: Martin K. Petersen 
Cc: linux-s...@vger.kernel.org
Signed-off-by: Chanwoo Choi 
---
 drivers/scsi/ufs/ufshcd.c | 4 +---
 1 file changed, 1 insertion(+), 3 deletions(-)

diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index f08d41a2d70b..e639071fd3a1 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -6198,8 +6198,6 @@ void ufshcd_remove(struct ufs_hba *hba)
scsi_host_put(hba->host);

ufshcd_exit_clk_gating(hba);
-   if (ufshcd_is_clkscaling_enabled(hba))
-   devfreq_remove_device(hba->devfreq);
ufshcd_hba_exit(hba);
 }
 EXPORT_SYMBOL_GPL(ufshcd_remove);
@@ -6495,7 +6493,7 @@ int ufshcd_init(struct ufs_hba *hba, void
__iomem *mmio_base, unsigned int irq)
}

if (ufshcd_is_clkscaling_enabled(hba)) {
-   hba->devfreq = devfreq_add_device(dev, _devfreq_profile,
+   hba->devfreq = devm_devfreq_add_device(dev, 
_devfreq_profile,
   "simple_ondemand", NULL);
if (IS_ERR(hba->devfreq)) {
dev_err(hba->dev, "Unable to register with devfreq 
%ld\n",


This change looks good to me but this will have merge conflicts if this 
gets in after my patch series "	[PATCH v1 00/11] scsi: ufs: bug fixes 
patch series #1" (due to "[PATCH v1 06/11] scsi: ufs: suspend clock 
scaling for failed runtime_resume"). so if you can, please pull in my 
patch series and rebase your change on top of it and send it out again.


Thanks,
Subhash

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


Re: [PATCH 2/2] scsi: ufs: Use the resource-managed function to add devfreq device

2016-10-26 Thread Subhash Jadavani

On 2016-10-26 00:38, Chanwoo Choi wrote:

This patch uses the resource-managed to add the devfreq device.
This function will make it easy to handle the devfreq device.

- struct devfreq *devm_devfreq_add_device(struct device *dev,
  struct devfreq_dev_profile *profile,
  const char *governor_name,
  void *data);
Cc: Vinayak Holikatti 
Cc: James E.J. Bottomley 
Cc: Martin K. Petersen 
Cc: linux-s...@vger.kernel.org
Signed-off-by: Chanwoo Choi 
---
 drivers/scsi/ufs/ufshcd.c | 4 +---
 1 file changed, 1 insertion(+), 3 deletions(-)

diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index f08d41a2d70b..e639071fd3a1 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -6198,8 +6198,6 @@ void ufshcd_remove(struct ufs_hba *hba)
scsi_host_put(hba->host);

ufshcd_exit_clk_gating(hba);
-   if (ufshcd_is_clkscaling_enabled(hba))
-   devfreq_remove_device(hba->devfreq);
ufshcd_hba_exit(hba);
 }
 EXPORT_SYMBOL_GPL(ufshcd_remove);
@@ -6495,7 +6493,7 @@ int ufshcd_init(struct ufs_hba *hba, void
__iomem *mmio_base, unsigned int irq)
}

if (ufshcd_is_clkscaling_enabled(hba)) {
-   hba->devfreq = devfreq_add_device(dev, _devfreq_profile,
+   hba->devfreq = devm_devfreq_add_device(dev, 
_devfreq_profile,
   "simple_ondemand", NULL);
if (IS_ERR(hba->devfreq)) {
dev_err(hba->dev, "Unable to register with devfreq 
%ld\n",


This change looks good to me but this will have merge conflicts if this 
gets in after my patch series "	[PATCH v1 00/11] scsi: ufs: bug fixes 
patch series #1" (due to "[PATCH v1 06/11] scsi: ufs: suspend clock 
scaling for failed runtime_resume"). so if you can, please pull in my 
patch series and rebase your change on top of it and send it out again.


Thanks,
Subhash

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


Re: [PATCH 08/10] ufs-qcom: phy/hcd: Refactoring phy clock handling

2016-10-19 Thread Subhash Jadavani

On 2016-10-19 10:45, Vivek Gautam wrote:

Hi,


On Wed, Oct 19, 2016 at 1:43 AM, Subhash Jadavani
<subha...@codeaurora.org> wrote:

On 2016-10-18 07:28, Vivek Gautam wrote:


Add phy clock enable code to phy_power_on/off callbacks, and
remove explicit calls to enable these phy clocks from the
ufs-qcom hcd driver.

Signed-off-by: Vivek Gautam <vivek.gau...@codeaurora.org>
---

Changes since v1:
 - staticized ufs_qcom_phy_enable(/disable)_ref_clk(),
 - staticized ufs_qcom_phy_enable(/disable)_iface_clk()
 - removed function declaration and export symbol for these APIs.


[snip]


--- a/drivers/scsi/ufs/ufs-qcom.c
+++ b/drivers/scsi/ufs/ufs-qcom.c
@@ -1112,17 +1112,6 @@ static int ufs_qcom_setup_clocks(struct 
ufs_hba

*hba, bool on)
return 0;

if (on) {
-   err = 
ufs_qcom_phy_enable_iface_clk(host->generic_phy);

-   if (err)
-   goto out;
-
-   err = ufs_qcom_phy_enable_ref_clk(host->generic_phy);
-   if (err) {
-   dev_err(hba->dev, "%s enable phy ref clock 
failed,

err=%d\n",
-   __func__, err);
-   
ufs_qcom_phy_disable_iface_clk(host->generic_phy);

-   goto out;
-   }



Now that you are moving these ref clk enable/disable to 
phy_power_on/off and
these phy_power_on/off are called only in runtime suspend/resume (3 
seconds

after last UFS access).
Goal is to disable the phy reference clock during aggressive gating 
(10ms
from last UFS access) so shouldn't we call the phy_power_on/off from 
these

setup_clocks() function as well?



So setup_clocks() is called for aggressive clock gating as well ?
If that's the case then yes, we may need to call. But we should try to
understand here. The phy_power_off turns off all the clocks - reflclk,
and other interface clocks. Do we want all of them to be turned off ?


Yes, we want to turn off the ref clock (& other clocks) during 
aggressive gating.




phy_power_off will also turn off the PHY. Do we want all this for 
aggressive

clock gating ?


Yes, PHY rails can be powered off both during the aggressive clk gating 
and runtime suspend. But as the regulator on/off latencies could be 
higher (especially for the shared rail), we were turning them off doing 
it in runtime suspend only (via phy_power_off()).
Now that phy_power_on/off is managing both clocks and regulators, and we 
will really want to turn off the ref clocks during clock gating, there 
is no option but to call phy_power_on/off during aggressive gating.





[snip]


Regards
Vivek


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


Re: [PATCH 08/10] ufs-qcom: phy/hcd: Refactoring phy clock handling

2016-10-19 Thread Subhash Jadavani

On 2016-10-19 10:45, Vivek Gautam wrote:

Hi,


On Wed, Oct 19, 2016 at 1:43 AM, Subhash Jadavani
 wrote:

On 2016-10-18 07:28, Vivek Gautam wrote:


Add phy clock enable code to phy_power_on/off callbacks, and
remove explicit calls to enable these phy clocks from the
ufs-qcom hcd driver.

Signed-off-by: Vivek Gautam 
---

Changes since v1:
 - staticized ufs_qcom_phy_enable(/disable)_ref_clk(),
 - staticized ufs_qcom_phy_enable(/disable)_iface_clk()
 - removed function declaration and export symbol for these APIs.


[snip]


--- a/drivers/scsi/ufs/ufs-qcom.c
+++ b/drivers/scsi/ufs/ufs-qcom.c
@@ -1112,17 +1112,6 @@ static int ufs_qcom_setup_clocks(struct 
ufs_hba

*hba, bool on)
return 0;

if (on) {
-   err = 
ufs_qcom_phy_enable_iface_clk(host->generic_phy);

-   if (err)
-   goto out;
-
-   err = ufs_qcom_phy_enable_ref_clk(host->generic_phy);
-   if (err) {
-   dev_err(hba->dev, "%s enable phy ref clock 
failed,

err=%d\n",
-   __func__, err);
-   
ufs_qcom_phy_disable_iface_clk(host->generic_phy);

-   goto out;
-   }



Now that you are moving these ref clk enable/disable to 
phy_power_on/off and
these phy_power_on/off are called only in runtime suspend/resume (3 
seconds

after last UFS access).
Goal is to disable the phy reference clock during aggressive gating 
(10ms
from last UFS access) so shouldn't we call the phy_power_on/off from 
these

setup_clocks() function as well?



So setup_clocks() is called for aggressive clock gating as well ?
If that's the case then yes, we may need to call. But we should try to
understand here. The phy_power_off turns off all the clocks - reflclk,
and other interface clocks. Do we want all of them to be turned off ?


Yes, we want to turn off the ref clock (& other clocks) during 
aggressive gating.




phy_power_off will also turn off the PHY. Do we want all this for 
aggressive

clock gating ?


Yes, PHY rails can be powered off both during the aggressive clk gating 
and runtime suspend. But as the regulator on/off latencies could be 
higher (especially for the shared rail), we were turning them off doing 
it in runtime suspend only (via phy_power_off()).
Now that phy_power_on/off is managing both clocks and regulators, and we 
will really want to turn off the ref clocks during clock gating, there 
is no option but to call phy_power_on/off during aggressive gating.





[snip]


Regards
Vivek


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


Re: [PATCH v2 10/10] phy: qcom-ufs: Remove common layer phy exit callback

2016-10-18 Thread Subhash Jadavani

On 2016-10-18 07:28, Vivek Gautam wrote:

The common layer phy exit callback ufs_qcom_phy_exit()
calls phy_power_off() that has no meaning when phy_power_off()
callback is already registered with the phy provider and
the consumer makes use of the same.
Instead, add a no-op specific phy_exit() callback for now
to add the exit sequence at a later point.

Signed-off-by: Vivek Gautam <vivek.gau...@codeaurora.org>
---

New patch added in v2 series.

 drivers/phy/phy-qcom-ufs-i.h|  1 -
 drivers/phy/phy-qcom-ufs-qmp-14nm.c |  7 ++-
 drivers/phy/phy-qcom-ufs-qmp-20nm.c |  7 ++-
 drivers/phy/phy-qcom-ufs.c  | 17 ++---
 4 files changed, 18 insertions(+), 14 deletions(-)

diff --git a/drivers/phy/phy-qcom-ufs-i.h 
b/drivers/phy/phy-qcom-ufs-i.h

index 69e836d..d505d98 100644
--- a/drivers/phy/phy-qcom-ufs-i.h
+++ b/drivers/phy/phy-qcom-ufs-i.h
@@ -141,7 +141,6 @@ struct ufs_qcom_phy_specific_ops {
 struct ufs_qcom_phy *get_ufs_qcom_phy(struct phy *generic_phy);
 int ufs_qcom_phy_power_on(struct phy *generic_phy);
 int ufs_qcom_phy_power_off(struct phy *generic_phy);
-int ufs_qcom_phy_exit(struct phy *generic_phy);
 int ufs_qcom_phy_init_clks(struct ufs_qcom_phy *phy_common);
 int ufs_qcom_phy_init_vregulators(struct ufs_qcom_phy *phy_common);
 int ufs_qcom_phy_remove(struct phy *generic_phy,
diff --git a/drivers/phy/phy-qcom-ufs-qmp-14nm.c
b/drivers/phy/phy-qcom-ufs-qmp-14nm.c
index a60cf34..061604f 100644
--- a/drivers/phy/phy-qcom-ufs-qmp-14nm.c
+++ b/drivers/phy/phy-qcom-ufs-qmp-14nm.c
@@ -47,6 +47,11 @@ static int ufs_qcom_phy_qmp_14nm_init(struct phy
*generic_phy)
return 0;
 }

+static int ufs_qcom_phy_qmp_14nm_exit(struct phy *generic_phy)
+{
+   return 0;
+}
+
 static
 void ufs_qcom_phy_qmp_14nm_power_control(struct ufs_qcom_phy *phy, 
bool val)

 {
@@ -94,7 +99,7 @@ static int ufs_qcom_phy_qmp_14nm_is_pcs_ready(struct
ufs_qcom_phy *phy_common)

 static const struct phy_ops ufs_qcom_phy_qmp_14nm_phy_ops = {
.init   = ufs_qcom_phy_qmp_14nm_init,
-   .exit   = ufs_qcom_phy_exit,
+   .exit   = ufs_qcom_phy_qmp_14nm_exit,
.power_on   = ufs_qcom_phy_power_on,
.power_off  = ufs_qcom_phy_power_off,
.owner  = THIS_MODULE,
diff --git a/drivers/phy/phy-qcom-ufs-qmp-20nm.c
b/drivers/phy/phy-qcom-ufs-qmp-20nm.c
index dfc5175..1a26a64 100644
--- a/drivers/phy/phy-qcom-ufs-qmp-20nm.c
+++ b/drivers/phy/phy-qcom-ufs-qmp-20nm.c
@@ -66,6 +66,11 @@ static int ufs_qcom_phy_qmp_20nm_init(struct phy
*generic_phy)
return 0;
 }

+static int ufs_qcom_phy_qmp_20nm_exit(struct phy *generic_phy)
+{
+   return 0;
+}
+
 static
 void ufs_qcom_phy_qmp_20nm_power_control(struct ufs_qcom_phy *phy, 
bool val)

 {
@@ -152,7 +157,7 @@ static int
ufs_qcom_phy_qmp_20nm_is_pcs_ready(struct ufs_qcom_phy *phy_common)

 static const struct phy_ops ufs_qcom_phy_qmp_20nm_phy_ops = {
.init   = ufs_qcom_phy_qmp_20nm_init,
-   .exit   = ufs_qcom_phy_exit,
+   .exit   = ufs_qcom_phy_qmp_20nm_exit,
.power_on   = ufs_qcom_phy_power_on,
.power_off  = ufs_qcom_phy_power_off,
.owner  = THIS_MODULE,
diff --git a/drivers/phy/phy-qcom-ufs.c b/drivers/phy/phy-qcom-ufs.c
index a425cc2..494f90f 100644
--- a/drivers/phy/phy-qcom-ufs.c
+++ b/drivers/phy/phy-qcom-ufs.c
@@ -615,17 +615,6 @@ int ufs_qcom_phy_calibrate_phy(struct phy
*generic_phy, bool is_rate_B)
 }
 EXPORT_SYMBOL_GPL(ufs_qcom_phy_calibrate_phy);

-int ufs_qcom_phy_exit(struct phy *generic_phy)
-{
-   struct ufs_qcom_phy *ufs_qcom_phy = get_ufs_qcom_phy(generic_phy);
-
-   if (ufs_qcom_phy->is_powered_on)
-   phy_power_off(generic_phy);
-
-   return 0;
-}
-EXPORT_SYMBOL_GPL(ufs_qcom_phy_exit);
-
 int ufs_qcom_phy_is_pcs_ready(struct phy *generic_phy)
 {
struct ufs_qcom_phy *ufs_qcom_phy = get_ufs_qcom_phy(generic_phy);
@@ -647,6 +636,9 @@ int ufs_qcom_phy_power_on(struct phy *generic_phy)
struct device *dev = phy_common->dev;
int err;

+   if (phy_common->is_powered_on)
+   return 0;
+
err = ufs_qcom_phy_enable_vreg(dev, _common->vdda_phy);
if (err) {
dev_err(dev, "%s enable vdda_phy failed, err=%d\n",
@@ -709,6 +701,9 @@ int ufs_qcom_phy_power_off(struct phy *generic_phy)
 {
struct ufs_qcom_phy *phy_common = get_ufs_qcom_phy(generic_phy);

+   if (!phy_common->is_powered_on)
+   return 0;
+
phy_common->phy_spec_ops->power_control(phy_common, false);

if (phy_common->vddp_ref_clk.reg)


LGTM , Reviewed-by: Subhash Jadavani <subha...@codeaurora.org>

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


Re: [PATCH v2 10/10] phy: qcom-ufs: Remove common layer phy exit callback

2016-10-18 Thread Subhash Jadavani

On 2016-10-18 07:28, Vivek Gautam wrote:

The common layer phy exit callback ufs_qcom_phy_exit()
calls phy_power_off() that has no meaning when phy_power_off()
callback is already registered with the phy provider and
the consumer makes use of the same.
Instead, add a no-op specific phy_exit() callback for now
to add the exit sequence at a later point.

Signed-off-by: Vivek Gautam 
---

New patch added in v2 series.

 drivers/phy/phy-qcom-ufs-i.h|  1 -
 drivers/phy/phy-qcom-ufs-qmp-14nm.c |  7 ++-
 drivers/phy/phy-qcom-ufs-qmp-20nm.c |  7 ++-
 drivers/phy/phy-qcom-ufs.c  | 17 ++---
 4 files changed, 18 insertions(+), 14 deletions(-)

diff --git a/drivers/phy/phy-qcom-ufs-i.h 
b/drivers/phy/phy-qcom-ufs-i.h

index 69e836d..d505d98 100644
--- a/drivers/phy/phy-qcom-ufs-i.h
+++ b/drivers/phy/phy-qcom-ufs-i.h
@@ -141,7 +141,6 @@ struct ufs_qcom_phy_specific_ops {
 struct ufs_qcom_phy *get_ufs_qcom_phy(struct phy *generic_phy);
 int ufs_qcom_phy_power_on(struct phy *generic_phy);
 int ufs_qcom_phy_power_off(struct phy *generic_phy);
-int ufs_qcom_phy_exit(struct phy *generic_phy);
 int ufs_qcom_phy_init_clks(struct ufs_qcom_phy *phy_common);
 int ufs_qcom_phy_init_vregulators(struct ufs_qcom_phy *phy_common);
 int ufs_qcom_phy_remove(struct phy *generic_phy,
diff --git a/drivers/phy/phy-qcom-ufs-qmp-14nm.c
b/drivers/phy/phy-qcom-ufs-qmp-14nm.c
index a60cf34..061604f 100644
--- a/drivers/phy/phy-qcom-ufs-qmp-14nm.c
+++ b/drivers/phy/phy-qcom-ufs-qmp-14nm.c
@@ -47,6 +47,11 @@ static int ufs_qcom_phy_qmp_14nm_init(struct phy
*generic_phy)
return 0;
 }

+static int ufs_qcom_phy_qmp_14nm_exit(struct phy *generic_phy)
+{
+   return 0;
+}
+
 static
 void ufs_qcom_phy_qmp_14nm_power_control(struct ufs_qcom_phy *phy, 
bool val)

 {
@@ -94,7 +99,7 @@ static int ufs_qcom_phy_qmp_14nm_is_pcs_ready(struct
ufs_qcom_phy *phy_common)

 static const struct phy_ops ufs_qcom_phy_qmp_14nm_phy_ops = {
.init   = ufs_qcom_phy_qmp_14nm_init,
-   .exit   = ufs_qcom_phy_exit,
+   .exit   = ufs_qcom_phy_qmp_14nm_exit,
.power_on   = ufs_qcom_phy_power_on,
.power_off  = ufs_qcom_phy_power_off,
.owner  = THIS_MODULE,
diff --git a/drivers/phy/phy-qcom-ufs-qmp-20nm.c
b/drivers/phy/phy-qcom-ufs-qmp-20nm.c
index dfc5175..1a26a64 100644
--- a/drivers/phy/phy-qcom-ufs-qmp-20nm.c
+++ b/drivers/phy/phy-qcom-ufs-qmp-20nm.c
@@ -66,6 +66,11 @@ static int ufs_qcom_phy_qmp_20nm_init(struct phy
*generic_phy)
return 0;
 }

+static int ufs_qcom_phy_qmp_20nm_exit(struct phy *generic_phy)
+{
+   return 0;
+}
+
 static
 void ufs_qcom_phy_qmp_20nm_power_control(struct ufs_qcom_phy *phy, 
bool val)

 {
@@ -152,7 +157,7 @@ static int
ufs_qcom_phy_qmp_20nm_is_pcs_ready(struct ufs_qcom_phy *phy_common)

 static const struct phy_ops ufs_qcom_phy_qmp_20nm_phy_ops = {
.init   = ufs_qcom_phy_qmp_20nm_init,
-   .exit   = ufs_qcom_phy_exit,
+   .exit   = ufs_qcom_phy_qmp_20nm_exit,
.power_on   = ufs_qcom_phy_power_on,
.power_off  = ufs_qcom_phy_power_off,
.owner  = THIS_MODULE,
diff --git a/drivers/phy/phy-qcom-ufs.c b/drivers/phy/phy-qcom-ufs.c
index a425cc2..494f90f 100644
--- a/drivers/phy/phy-qcom-ufs.c
+++ b/drivers/phy/phy-qcom-ufs.c
@@ -615,17 +615,6 @@ int ufs_qcom_phy_calibrate_phy(struct phy
*generic_phy, bool is_rate_B)
 }
 EXPORT_SYMBOL_GPL(ufs_qcom_phy_calibrate_phy);

-int ufs_qcom_phy_exit(struct phy *generic_phy)
-{
-   struct ufs_qcom_phy *ufs_qcom_phy = get_ufs_qcom_phy(generic_phy);
-
-   if (ufs_qcom_phy->is_powered_on)
-   phy_power_off(generic_phy);
-
-   return 0;
-}
-EXPORT_SYMBOL_GPL(ufs_qcom_phy_exit);
-
 int ufs_qcom_phy_is_pcs_ready(struct phy *generic_phy)
 {
struct ufs_qcom_phy *ufs_qcom_phy = get_ufs_qcom_phy(generic_phy);
@@ -647,6 +636,9 @@ int ufs_qcom_phy_power_on(struct phy *generic_phy)
struct device *dev = phy_common->dev;
int err;

+   if (phy_common->is_powered_on)
+   return 0;
+
err = ufs_qcom_phy_enable_vreg(dev, _common->vdda_phy);
if (err) {
dev_err(dev, "%s enable vdda_phy failed, err=%d\n",
@@ -709,6 +701,9 @@ int ufs_qcom_phy_power_off(struct phy *generic_phy)
 {
struct ufs_qcom_phy *phy_common = get_ufs_qcom_phy(generic_phy);

+   if (!phy_common->is_powered_on)
+   return 0;
+
phy_common->phy_spec_ops->power_control(phy_common, false);

if (phy_common->vddp_ref_clk.reg)


LGTM , Reviewed-by: Subhash Jadavani 

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


Re: [PATCH v2 09/10] scsi/ufs: qcom: Add phy_exit call in hcd exit path

2016-10-18 Thread Subhash Jadavani

On 2016-10-18 07:28, Vivek Gautam wrote:

Do a phy_exit() over the ufs phy in the ufs qcom exit path
to de-initialize the phy.

Signed-off-by: Vivek Gautam <vivek.gau...@codeaurora.org>
---

New patch added in v2 series.

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

diff --git a/drivers/scsi/ufs/ufs-qcom.c b/drivers/scsi/ufs/ufs-qcom.c
index 6e4ce5f..dfd2af8 100644
--- a/drivers/scsi/ufs/ufs-qcom.c
+++ b/drivers/scsi/ufs/ufs-qcom.c
@@ -1272,6 +1272,7 @@ static void ufs_qcom_exit(struct ufs_hba *hba)

ufs_qcom_disable_lane_clks(host);
phy_power_off(host->generic_phy);
+   phy_exit(host->generic_phy);
 }

 static int ufs_qcom_set_dme_vs_core_clk_ctrl_clear_div(struct ufs_hba 
*hba,


LGTM.
Reviewed-by: Subhash Jadavani <subha...@codeaurora.org>

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


Re: [PATCH v2 09/10] scsi/ufs: qcom: Add phy_exit call in hcd exit path

2016-10-18 Thread Subhash Jadavani

On 2016-10-18 07:28, Vivek Gautam wrote:

Do a phy_exit() over the ufs phy in the ufs qcom exit path
to de-initialize the phy.

Signed-off-by: Vivek Gautam 
---

New patch added in v2 series.

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

diff --git a/drivers/scsi/ufs/ufs-qcom.c b/drivers/scsi/ufs/ufs-qcom.c
index 6e4ce5f..dfd2af8 100644
--- a/drivers/scsi/ufs/ufs-qcom.c
+++ b/drivers/scsi/ufs/ufs-qcom.c
@@ -1272,6 +1272,7 @@ static void ufs_qcom_exit(struct ufs_hba *hba)

ufs_qcom_disable_lane_clks(host);
phy_power_off(host->generic_phy);
+   phy_exit(host->generic_phy);
 }

 static int ufs_qcom_set_dme_vs_core_clk_ctrl_clear_div(struct ufs_hba 
*hba,


LGTM.
Reviewed-by: Subhash Jadavani 

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


Re: [PATCH 08/10] ufs-qcom: phy/hcd: Refactoring phy clock handling

2016-10-18 Thread Subhash Jadavani

On 2016-10-18 07:28, Vivek Gautam wrote:

Add phy clock enable code to phy_power_on/off callbacks, and
remove explicit calls to enable these phy clocks from the
ufs-qcom hcd driver.

Signed-off-by: Vivek Gautam 
---

Changes since v1:
 - staticized ufs_qcom_phy_enable(/disable)_ref_clk(),
 - staticized ufs_qcom_phy_enable(/disable)_iface_clk()
 - removed function declaration and export symbol for these APIs.

 drivers/phy/phy-qcom-ufs.c   | 36 
++--

 drivers/scsi/ufs/ufs-qcom.c  | 15 ---
 include/linux/phy/phy-qcom-ufs.h | 18 --
 3 files changed, 18 insertions(+), 51 deletions(-)

diff --git a/drivers/phy/phy-qcom-ufs.c b/drivers/phy/phy-qcom-ufs.c
index 144b11f..a425cc2 100644
--- a/drivers/phy/phy-qcom-ufs.c
+++ b/drivers/phy/phy-qcom-ufs.c
@@ -373,10 +373,9 @@ out:
return ret;
 }

-int ufs_qcom_phy_enable_ref_clk(struct phy *generic_phy)
+static int ufs_qcom_phy_enable_ref_clk(struct ufs_qcom_phy *phy)
 {
int ret = 0;
-   struct ufs_qcom_phy *phy = get_ufs_qcom_phy(generic_phy);

if (phy->is_ref_clk_enabled)
goto out;
@@ -423,7 +422,6 @@ out_disable_src:
 out:
return ret;
 }
-EXPORT_SYMBOL_GPL(ufs_qcom_phy_enable_ref_clk);

 static
 int ufs_qcom_phy_disable_vreg(struct device *dev,
@@ -448,10 +446,8 @@ out:
return ret;
 }

-void ufs_qcom_phy_disable_ref_clk(struct phy *generic_phy)
+static void ufs_qcom_phy_disable_ref_clk(struct ufs_qcom_phy *phy)
 {
-   struct ufs_qcom_phy *phy = get_ufs_qcom_phy(generic_phy);
-
if (phy->is_ref_clk_enabled) {
clk_disable_unprepare(phy->ref_clk);
/*
@@ -464,7 +460,6 @@ void ufs_qcom_phy_disable_ref_clk(struct phy 
*generic_phy)

phy->is_ref_clk_enabled = false;
}
 }
-EXPORT_SYMBOL_GPL(ufs_qcom_phy_disable_ref_clk);

 #define UFS_REF_CLK_EN (1 << 5)

@@ -517,9 +512,8 @@ void ufs_qcom_phy_disable_dev_ref_clk(struct phy
*generic_phy)
 EXPORT_SYMBOL_GPL(ufs_qcom_phy_disable_dev_ref_clk);

 /* Turn ON M-PHY RMMI interface clocks */
-int ufs_qcom_phy_enable_iface_clk(struct phy *generic_phy)
+static int ufs_qcom_phy_enable_iface_clk(struct ufs_qcom_phy *phy)
 {
-   struct ufs_qcom_phy *phy = get_ufs_qcom_phy(generic_phy);
int ret = 0;

if (phy->is_iface_clk_enabled)
@@ -543,20 +537,16 @@ int ufs_qcom_phy_enable_iface_clk(struct phy 
*generic_phy)

 out:
return ret;
 }
-EXPORT_SYMBOL_GPL(ufs_qcom_phy_enable_iface_clk);

 /* Turn OFF M-PHY RMMI interface clocks */
-void ufs_qcom_phy_disable_iface_clk(struct phy *generic_phy)
+void ufs_qcom_phy_disable_iface_clk(struct ufs_qcom_phy *phy)
 {
-   struct ufs_qcom_phy *phy = get_ufs_qcom_phy(generic_phy);
-
if (phy->is_iface_clk_enabled) {
clk_disable_unprepare(phy->tx_iface_clk);
clk_disable_unprepare(phy->rx_iface_clk);
phy->is_iface_clk_enabled = false;
}
 }
-EXPORT_SYMBOL_GPL(ufs_qcom_phy_disable_iface_clk);

 int ufs_qcom_phy_start_serdes(struct phy *generic_phy)
 {
@@ -674,13 +664,20 @@ int ufs_qcom_phy_power_on(struct phy 
*generic_phy)

goto out_disable_phy;
}

-   err = ufs_qcom_phy_enable_ref_clk(generic_phy);
+   err = ufs_qcom_phy_enable_iface_clk(phy_common);
if (err) {
-   dev_err(dev, "%s enable phy ref clock failed, err=%d\n",
+   dev_err(dev, "%s enable phy iface clock failed, err=%d\n",
__func__, err);
goto out_disable_pll;
}

+   err = ufs_qcom_phy_enable_ref_clk(phy_common);
+   if (err) {
+   dev_err(dev, "%s enable phy ref clock failed, err=%d\n",
+   __func__, err);
+   goto out_disable_iface_clk;
+   }
+
/* enable device PHY ref_clk pad rail */
if (phy_common->vddp_ref_clk.reg) {
err = ufs_qcom_phy_enable_vreg(dev,
@@ -696,7 +693,9 @@ int ufs_qcom_phy_power_on(struct phy *generic_phy)
goto out;

 out_disable_ref_clk:
-   ufs_qcom_phy_disable_ref_clk(generic_phy);
+   ufs_qcom_phy_disable_ref_clk(phy_common);
+out_disable_iface_clk:
+   ufs_qcom_phy_disable_iface_clk(phy_common);
 out_disable_pll:
ufs_qcom_phy_disable_vreg(dev, _common->vdda_pll);
 out_disable_phy:
@@ -715,7 +714,8 @@ int ufs_qcom_phy_power_off(struct phy *generic_phy)
if (phy_common->vddp_ref_clk.reg)
ufs_qcom_phy_disable_vreg(phy_common->dev,
  _common->vddp_ref_clk);
-   ufs_qcom_phy_disable_ref_clk(generic_phy);
+   ufs_qcom_phy_disable_ref_clk(phy_common);
+   ufs_qcom_phy_disable_iface_clk(phy_common);

ufs_qcom_phy_disable_vreg(phy_common->dev, _common->vdda_pll);
ufs_qcom_phy_disable_vreg(phy_common->dev, _common->vdda_phy);
diff --git a/drivers/scsi/ufs/ufs-qcom.c b/drivers/scsi/ufs/ufs-qcom.c
index 

Re: [PATCH 08/10] ufs-qcom: phy/hcd: Refactoring phy clock handling

2016-10-18 Thread Subhash Jadavani

On 2016-10-18 07:28, Vivek Gautam wrote:

Add phy clock enable code to phy_power_on/off callbacks, and
remove explicit calls to enable these phy clocks from the
ufs-qcom hcd driver.

Signed-off-by: Vivek Gautam 
---

Changes since v1:
 - staticized ufs_qcom_phy_enable(/disable)_ref_clk(),
 - staticized ufs_qcom_phy_enable(/disable)_iface_clk()
 - removed function declaration and export symbol for these APIs.

 drivers/phy/phy-qcom-ufs.c   | 36 
++--

 drivers/scsi/ufs/ufs-qcom.c  | 15 ---
 include/linux/phy/phy-qcom-ufs.h | 18 --
 3 files changed, 18 insertions(+), 51 deletions(-)

diff --git a/drivers/phy/phy-qcom-ufs.c b/drivers/phy/phy-qcom-ufs.c
index 144b11f..a425cc2 100644
--- a/drivers/phy/phy-qcom-ufs.c
+++ b/drivers/phy/phy-qcom-ufs.c
@@ -373,10 +373,9 @@ out:
return ret;
 }

-int ufs_qcom_phy_enable_ref_clk(struct phy *generic_phy)
+static int ufs_qcom_phy_enable_ref_clk(struct ufs_qcom_phy *phy)
 {
int ret = 0;
-   struct ufs_qcom_phy *phy = get_ufs_qcom_phy(generic_phy);

if (phy->is_ref_clk_enabled)
goto out;
@@ -423,7 +422,6 @@ out_disable_src:
 out:
return ret;
 }
-EXPORT_SYMBOL_GPL(ufs_qcom_phy_enable_ref_clk);

 static
 int ufs_qcom_phy_disable_vreg(struct device *dev,
@@ -448,10 +446,8 @@ out:
return ret;
 }

-void ufs_qcom_phy_disable_ref_clk(struct phy *generic_phy)
+static void ufs_qcom_phy_disable_ref_clk(struct ufs_qcom_phy *phy)
 {
-   struct ufs_qcom_phy *phy = get_ufs_qcom_phy(generic_phy);
-
if (phy->is_ref_clk_enabled) {
clk_disable_unprepare(phy->ref_clk);
/*
@@ -464,7 +460,6 @@ void ufs_qcom_phy_disable_ref_clk(struct phy 
*generic_phy)

phy->is_ref_clk_enabled = false;
}
 }
-EXPORT_SYMBOL_GPL(ufs_qcom_phy_disable_ref_clk);

 #define UFS_REF_CLK_EN (1 << 5)

@@ -517,9 +512,8 @@ void ufs_qcom_phy_disable_dev_ref_clk(struct phy
*generic_phy)
 EXPORT_SYMBOL_GPL(ufs_qcom_phy_disable_dev_ref_clk);

 /* Turn ON M-PHY RMMI interface clocks */
-int ufs_qcom_phy_enable_iface_clk(struct phy *generic_phy)
+static int ufs_qcom_phy_enable_iface_clk(struct ufs_qcom_phy *phy)
 {
-   struct ufs_qcom_phy *phy = get_ufs_qcom_phy(generic_phy);
int ret = 0;

if (phy->is_iface_clk_enabled)
@@ -543,20 +537,16 @@ int ufs_qcom_phy_enable_iface_clk(struct phy 
*generic_phy)

 out:
return ret;
 }
-EXPORT_SYMBOL_GPL(ufs_qcom_phy_enable_iface_clk);

 /* Turn OFF M-PHY RMMI interface clocks */
-void ufs_qcom_phy_disable_iface_clk(struct phy *generic_phy)
+void ufs_qcom_phy_disable_iface_clk(struct ufs_qcom_phy *phy)
 {
-   struct ufs_qcom_phy *phy = get_ufs_qcom_phy(generic_phy);
-
if (phy->is_iface_clk_enabled) {
clk_disable_unprepare(phy->tx_iface_clk);
clk_disable_unprepare(phy->rx_iface_clk);
phy->is_iface_clk_enabled = false;
}
 }
-EXPORT_SYMBOL_GPL(ufs_qcom_phy_disable_iface_clk);

 int ufs_qcom_phy_start_serdes(struct phy *generic_phy)
 {
@@ -674,13 +664,20 @@ int ufs_qcom_phy_power_on(struct phy 
*generic_phy)

goto out_disable_phy;
}

-   err = ufs_qcom_phy_enable_ref_clk(generic_phy);
+   err = ufs_qcom_phy_enable_iface_clk(phy_common);
if (err) {
-   dev_err(dev, "%s enable phy ref clock failed, err=%d\n",
+   dev_err(dev, "%s enable phy iface clock failed, err=%d\n",
__func__, err);
goto out_disable_pll;
}

+   err = ufs_qcom_phy_enable_ref_clk(phy_common);
+   if (err) {
+   dev_err(dev, "%s enable phy ref clock failed, err=%d\n",
+   __func__, err);
+   goto out_disable_iface_clk;
+   }
+
/* enable device PHY ref_clk pad rail */
if (phy_common->vddp_ref_clk.reg) {
err = ufs_qcom_phy_enable_vreg(dev,
@@ -696,7 +693,9 @@ int ufs_qcom_phy_power_on(struct phy *generic_phy)
goto out;

 out_disable_ref_clk:
-   ufs_qcom_phy_disable_ref_clk(generic_phy);
+   ufs_qcom_phy_disable_ref_clk(phy_common);
+out_disable_iface_clk:
+   ufs_qcom_phy_disable_iface_clk(phy_common);
 out_disable_pll:
ufs_qcom_phy_disable_vreg(dev, _common->vdda_pll);
 out_disable_phy:
@@ -715,7 +714,8 @@ int ufs_qcom_phy_power_off(struct phy *generic_phy)
if (phy_common->vddp_ref_clk.reg)
ufs_qcom_phy_disable_vreg(phy_common->dev,
  _common->vddp_ref_clk);
-   ufs_qcom_phy_disable_ref_clk(generic_phy);
+   ufs_qcom_phy_disable_ref_clk(phy_common);
+   ufs_qcom_phy_disable_iface_clk(phy_common);

ufs_qcom_phy_disable_vreg(phy_common->dev, _common->vdda_pll);
ufs_qcom_phy_disable_vreg(phy_common->dev, _common->vdda_phy);
diff --git a/drivers/scsi/ufs/ufs-qcom.c b/drivers/scsi/ufs/ufs-qcom.c
index 3aedf73..6e4ce5f 100644
--- 

Re: [PATCH v2 06/10] phy: qcom-ufs: Remove unnecessary function declarations

2016-10-18 Thread Subhash Jadavani
/* vddp-ref-clk-* properties are optional */
-   __ufs_qcom_phy_init_vreg(phy_common->dev, _common->vddp_ref_clk,
-"vddp-ref-clk", true);
-out:
-   return err;
-}
-EXPORT_SYMBOL_GPL(ufs_qcom_phy_init_vregulators);
-
 static int __ufs_qcom_phy_init_vreg(struct device *dev,
struct ufs_qcom_phy_vreg *vreg, const char *name, bool optional)
 {
@@ -316,6 +285,30 @@ static int ufs_qcom_phy_init_vreg(struct device 
*dev,

return __ufs_qcom_phy_init_vreg(dev, vreg, name, false);
 }

+int
+ufs_qcom_phy_init_vregulators(struct ufs_qcom_phy *phy_common)
+{
+   int err;
+
+   err = ufs_qcom_phy_init_vreg(phy_common->dev, _common->vdda_pll,
+   "vdda-pll");
+   if (err)
+   goto out;
+
+   err = ufs_qcom_phy_init_vreg(phy_common->dev, _common->vdda_phy,
+   "vdda-phy");
+
+   if (err)
+   goto out;
+
+   /* vddp-ref-clk-* properties are optional */
+   __ufs_qcom_phy_init_vreg(phy_common->dev, _common->vddp_ref_clk,
+"vddp-ref-clk", true);
+out:
+   return err;
+}
+EXPORT_SYMBOL_GPL(ufs_qcom_phy_init_vregulators);
+
 static
 int ufs_qcom_phy_cfg_vreg(struct device *dev,
  struct ufs_qcom_phy_vreg *vreg, bool on)


LGTM.
Reviewed-by: Subhash Jadavani <subha...@codeaurora.org>


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


Re: [PATCH v2 06/10] phy: qcom-ufs: Remove unnecessary function declarations

2016-10-18 Thread Subhash Jadavani
_ufs_qcom_phy_init_vreg(phy_common->dev, _common->vddp_ref_clk,
-"vddp-ref-clk", true);
-out:
-   return err;
-}
-EXPORT_SYMBOL_GPL(ufs_qcom_phy_init_vregulators);
-
 static int __ufs_qcom_phy_init_vreg(struct device *dev,
struct ufs_qcom_phy_vreg *vreg, const char *name, bool optional)
 {
@@ -316,6 +285,30 @@ static int ufs_qcom_phy_init_vreg(struct device 
*dev,

return __ufs_qcom_phy_init_vreg(dev, vreg, name, false);
 }

+int
+ufs_qcom_phy_init_vregulators(struct ufs_qcom_phy *phy_common)
+{
+   int err;
+
+   err = ufs_qcom_phy_init_vreg(phy_common->dev, _common->vdda_pll,
+   "vdda-pll");
+   if (err)
+   goto out;
+
+   err = ufs_qcom_phy_init_vreg(phy_common->dev, _common->vdda_phy,
+   "vdda-phy");
+
+   if (err)
+   goto out;
+
+   /* vddp-ref-clk-* properties are optional */
+   __ufs_qcom_phy_init_vreg(phy_common->dev, _common->vddp_ref_clk,
+"vddp-ref-clk", true);
+out:
+   return err;
+}
+EXPORT_SYMBOL_GPL(ufs_qcom_phy_init_vregulators);
+
 static
 int ufs_qcom_phy_cfg_vreg(struct device *dev,
  struct ufs_qcom_phy_vreg *vreg, bool on)


LGTM.
Reviewed-by: Subhash Jadavani 


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


Re: [PATCH v2 01/10] phy: qcom-ufs: remove failure when rx/tx_iface_clk are absent

2016-10-18 Thread Subhash Jadavani

On 2016-10-18 07:28, Vivek Gautam wrote:

From: Yaniv Gardi 

Since in future UFS Phy's the tx_iface_clk and rx_iface_clk
are no longer exist, we should not fail when their initialization
fail, but rather just report with debug message.


You may also want to update the device tree binding (documentation) to 
update these as optional properties.




Signed-off-by: Yaniv Gardi 
Signed-off-by: Vivek Gautam 
---

No change since v1.

 drivers/phy/phy-qcom-ufs.c | 15 +--
 1 file changed, 13 insertions(+), 2 deletions(-)

diff --git a/drivers/phy/phy-qcom-ufs.c b/drivers/phy/phy-qcom-ufs.c
index 107cb57..183ec04 100644
--- a/drivers/phy/phy-qcom-ufs.c
+++ b/drivers/phy/phy-qcom-ufs.c
@@ -186,16 +186,27 @@ ufs_qcom_phy_init_clks(struct phy *generic_phy,
   struct ufs_qcom_phy *phy_common)
 {
int err;
+   struct ufs_qcom_phy *phy = get_ufs_qcom_phy(generic_phy);

err = ufs_qcom_phy_clk_get(generic_phy, "tx_iface_clk",
   _common->tx_iface_clk);
+   /*
+* tx_iface_clk does not exist in newer version of ufs-phy HW,
+* so don't return error if it is not found
+*/
if (err)
-   goto out;
+   dev_dbg(phy->dev, "%s: failed to get tx_iface_clk\n",
+   __func__);

err = ufs_qcom_phy_clk_get(generic_phy, "rx_iface_clk",
   _common->rx_iface_clk);
+   /*
+* rx_iface_clk does not exist in newer version of ufs-phy HW,
+* so don't return error if it is not found
+*/
if (err)
-   goto out;
+   dev_dbg(phy->dev, "%s: failed to get rx_iface_clk\n",
+   __func__);

err = ufs_qcom_phy_clk_get(generic_phy, "ref_clk_src",
   _common->ref_clk_src);


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


Re: [PATCH v2 01/10] phy: qcom-ufs: remove failure when rx/tx_iface_clk are absent

2016-10-18 Thread Subhash Jadavani

On 2016-10-18 07:28, Vivek Gautam wrote:

From: Yaniv Gardi 

Since in future UFS Phy's the tx_iface_clk and rx_iface_clk
are no longer exist, we should not fail when their initialization
fail, but rather just report with debug message.


You may also want to update the device tree binding (documentation) to 
update these as optional properties.




Signed-off-by: Yaniv Gardi 
Signed-off-by: Vivek Gautam 
---

No change since v1.

 drivers/phy/phy-qcom-ufs.c | 15 +--
 1 file changed, 13 insertions(+), 2 deletions(-)

diff --git a/drivers/phy/phy-qcom-ufs.c b/drivers/phy/phy-qcom-ufs.c
index 107cb57..183ec04 100644
--- a/drivers/phy/phy-qcom-ufs.c
+++ b/drivers/phy/phy-qcom-ufs.c
@@ -186,16 +186,27 @@ ufs_qcom_phy_init_clks(struct phy *generic_phy,
   struct ufs_qcom_phy *phy_common)
 {
int err;
+   struct ufs_qcom_phy *phy = get_ufs_qcom_phy(generic_phy);

err = ufs_qcom_phy_clk_get(generic_phy, "tx_iface_clk",
   _common->tx_iface_clk);
+   /*
+* tx_iface_clk does not exist in newer version of ufs-phy HW,
+* so don't return error if it is not found
+*/
if (err)
-   goto out;
+   dev_dbg(phy->dev, "%s: failed to get tx_iface_clk\n",
+   __func__);

err = ufs_qcom_phy_clk_get(generic_phy, "rx_iface_clk",
   _common->rx_iface_clk);
+   /*
+* rx_iface_clk does not exist in newer version of ufs-phy HW,
+* so don't return error if it is not found
+*/
if (err)
-   goto out;
+   dev_dbg(phy->dev, "%s: failed to get rx_iface_clk\n",
+   __func__);

err = ufs_qcom_phy_clk_get(generic_phy, "ref_clk_src",
   _common->ref_clk_src);


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


Re: [RESEND PATCH] scsi: ufs: fix race between clock gating and devfreq scaling work

2016-10-17 Thread Subhash Jadavani

On 2016-10-14 13:47, Martin K. Petersen wrote:

"Subhash" == Subhash Jadavani <subha...@codeaurora.org> writes:


Subhash> UFS devfreq clock scaling work may require clocks to be ON if
Subhash> it need to execute some UFS commands hence it may request for
Subhash> clock hold before issuing the command. But if UFS clock gating
Subhash> work is already running in parallel, ungate work would end up
Subhash> waiting for the clock gating work to finish and as clock 
gating

Subhash> work would also wait for the clock scaling work to finish, we
Subhash> would enter in deadlock state. Here is the call trace during
Subhash> this deadlock state:

Somebody from the UFS camp, please review!


As there was no review so far, i have moved this patch as first patch in 
the new UFS bug fixes patch series ([PATCH v1 00/11] scsi: ufs: bug 
fixes patch series #1) sent by me today.


Thanks,
Subhash

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


Re: [RESEND PATCH] scsi: ufs: fix race between clock gating and devfreq scaling work

2016-10-17 Thread Subhash Jadavani

On 2016-10-14 13:47, Martin K. Petersen wrote:

"Subhash" == Subhash Jadavani  writes:


Subhash> UFS devfreq clock scaling work may require clocks to be ON if
Subhash> it need to execute some UFS commands hence it may request for
Subhash> clock hold before issuing the command. But if UFS clock gating
Subhash> work is already running in parallel, ungate work would end up
Subhash> waiting for the clock gating work to finish and as clock 
gating

Subhash> work would also wait for the clock scaling work to finish, we
Subhash> would enter in deadlock state. Here is the call trace during
Subhash> this deadlock state:

Somebody from the UFS camp, please review!


As there was no review so far, i have moved this patch as first patch in 
the new UFS bug fixes patch series ([PATCH v1 00/11] scsi: ufs: bug 
fixes patch series #1) sent by me today.


Thanks,
Subhash

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


[PATCH v1 11/11] scsi: ufs: optimize clock gate work

2016-10-17 Thread Subhash Jadavani
From: Venkat Gopalakrishnan <venk...@codeaurora.org>

In a case where gate work is called as part of cancel work
from ungate path the clk state would be marked as REQ_CLKS_ON.
There is no point gating the clocks and then end up turning
them ON immediately in ungate work, save time by skipping the
gate work and change the clk state to CLKS_ON as they are not
turned off yet.

Signed-off-by: Venkat Gopalakrishnan <venk...@codeaurora.org>
Signed-off-by: Subhash Jadavani <subha...@codeaurora.org>
---
 drivers/scsi/ufs/ufshcd.c | 9 -
 1 file changed, 8 insertions(+), 1 deletion(-)

diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index 7959793..8cf5d8f 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -739,7 +739,14 @@ static void ufshcd_gate_work(struct work_struct *work)
unsigned long flags;
 
spin_lock_irqsave(hba->host->host_lock, flags);
-   if (hba->clk_gating.is_suspended) {
+   /*
+* In case you are here to cancel this work the gating state
+* would be marked as REQ_CLKS_ON. In this case save time by
+* skipping the gating work and exit after changing the clock
+* state to CLKS_ON.
+*/
+   if (hba->clk_gating.is_suspended ||
+   (hba->clk_gating.state == REQ_CLKS_ON)) {
hba->clk_gating.state = CLKS_ON;
goto rel_lock;
}
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project



[PATCH v1 11/11] scsi: ufs: optimize clock gate work

2016-10-17 Thread Subhash Jadavani
From: Venkat Gopalakrishnan 

In a case where gate work is called as part of cancel work
from ungate path the clk state would be marked as REQ_CLKS_ON.
There is no point gating the clocks and then end up turning
them ON immediately in ungate work, save time by skipping the
gate work and change the clk state to CLKS_ON as they are not
turned off yet.

Signed-off-by: Venkat Gopalakrishnan 
Signed-off-by: Subhash Jadavani 
---
 drivers/scsi/ufs/ufshcd.c | 9 -
 1 file changed, 8 insertions(+), 1 deletion(-)

diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index 7959793..8cf5d8f 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -739,7 +739,14 @@ static void ufshcd_gate_work(struct work_struct *work)
unsigned long flags;
 
spin_lock_irqsave(hba->host->host_lock, flags);
-   if (hba->clk_gating.is_suspended) {
+   /*
+* In case you are here to cancel this work the gating state
+* would be marked as REQ_CLKS_ON. In this case save time by
+* skipping the gating work and exit after changing the clock
+* state to CLKS_ON.
+*/
+   if (hba->clk_gating.is_suspended ||
+   (hba->clk_gating.state == REQ_CLKS_ON)) {
hba->clk_gating.state = CLKS_ON;
goto rel_lock;
}
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project



[PATCH v1 10/11] scsi: ufshcd: Fix race between clk scaling and ungate work

2016-10-17 Thread Subhash Jadavani
From: Venkat Gopalakrishnan <venk...@codeaurora.org>

The ungate work turns on the clock before it exits hibern8,
if the link was put in hibern8 during clock gating work.
There occurs a race condition when clock scaling work calls
ufshcd_hold() to make sure low power states cannot be entered,
but that returns by checking only whether the clocks are on.
This causes the clock scaling work to issue UIC commands when
the link is in hibern8 causing failures. Make sure we exit
hibern8 state before returning from ufshcd_hold().

Callstacks for race condition:

 ufshcd_scale_gear
 ufshcd_devfreq_scale
 ufshcd_devfreq_target
 update_devfreq
 devfreq_monitor
 process_one_work
 worker_thread
 kthread
 ret_from_fork

 ufshcd_uic_hibern8_exit
 ufshcd_ungate_work
 process_one_work
 worker_thread
 kthread
 ret_from_fork

Signed-off-by: Venkat Gopalakrishnan <venk...@codeaurora.org>
Signed-off-by: Subhash Jadavani <subha...@codeaurora.org>
---
 drivers/scsi/ufs/ufshcd.c | 15 +++
 1 file changed, 15 insertions(+)

diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index ea97fd0..7959793 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -675,6 +675,21 @@ int ufshcd_hold(struct ufs_hba *hba, bool async)
 start:
switch (hba->clk_gating.state) {
case CLKS_ON:
+   /*
+* Wait for the ungate work to complete if in progress.
+* Though the clocks may be in ON state, the link could
+* still be in hibner8 state if hibern8 is allowed
+* during clock gating.
+* Make sure we exit hibern8 state also in addition to
+* clocks being ON.
+*/
+   if (ufshcd_can_hibern8_during_gating(hba) &&
+   ufshcd_is_link_hibern8(hba)) {
+   spin_unlock_irqrestore(hba->host->host_lock, flags);
+   flush_work(>clk_gating.ungate_work);
+   spin_lock_irqsave(hba->host->host_lock, flags);
+   goto start;
+   }
break;
case REQ_CLKS_OFF:
if (cancel_delayed_work(>clk_gating.gate_work)) {
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project



[PATCH v1 10/11] scsi: ufshcd: Fix race between clk scaling and ungate work

2016-10-17 Thread Subhash Jadavani
From: Venkat Gopalakrishnan 

The ungate work turns on the clock before it exits hibern8,
if the link was put in hibern8 during clock gating work.
There occurs a race condition when clock scaling work calls
ufshcd_hold() to make sure low power states cannot be entered,
but that returns by checking only whether the clocks are on.
This causes the clock scaling work to issue UIC commands when
the link is in hibern8 causing failures. Make sure we exit
hibern8 state before returning from ufshcd_hold().

Callstacks for race condition:

 ufshcd_scale_gear
 ufshcd_devfreq_scale
 ufshcd_devfreq_target
 update_devfreq
 devfreq_monitor
 process_one_work
 worker_thread
 kthread
 ret_from_fork

 ufshcd_uic_hibern8_exit
 ufshcd_ungate_work
 process_one_work
 worker_thread
 kthread
 ret_from_fork

Signed-off-by: Venkat Gopalakrishnan 
Signed-off-by: Subhash Jadavani 
---
 drivers/scsi/ufs/ufshcd.c | 15 +++
 1 file changed, 15 insertions(+)

diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index ea97fd0..7959793 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -675,6 +675,21 @@ int ufshcd_hold(struct ufs_hba *hba, bool async)
 start:
switch (hba->clk_gating.state) {
case CLKS_ON:
+   /*
+* Wait for the ungate work to complete if in progress.
+* Though the clocks may be in ON state, the link could
+* still be in hibner8 state if hibern8 is allowed
+* during clock gating.
+* Make sure we exit hibern8 state also in addition to
+* clocks being ON.
+*/
+   if (ufshcd_can_hibern8_during_gating(hba) &&
+   ufshcd_is_link_hibern8(hba)) {
+   spin_unlock_irqrestore(hba->host->host_lock, flags);
+   flush_work(>clk_gating.ungate_work);
+   spin_lock_irqsave(hba->host->host_lock, flags);
+   goto start;
+   }
break;
case REQ_CLKS_OFF:
if (cancel_delayed_work(>clk_gating.gate_work)) {
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project



[PATCH v1 03/11] scsi: ufs: fix bugs related to null pointer access and array size

2016-10-17 Thread Subhash Jadavani
From: Yaniv Gardi <yga...@codeaurora.org>

In this change there are a few fixes of possible NULL pointer access
and possible access to index that exceeds array boundaries.

Signed-off-by: Yaniv Gardi <yga...@codeaurora.org>
Signed-off-by: Subhash Jadavani <subha...@codeaurora.org>
---
 drivers/scsi/ufs/ufs.h|  3 ++-
 drivers/scsi/ufs/ufshcd.c | 25 +++--
 2 files changed, 21 insertions(+), 7 deletions(-)

diff --git a/drivers/scsi/ufs/ufs.h b/drivers/scsi/ufs/ufs.h
index 845b874..7a6ccb6 100644
--- a/drivers/scsi/ufs/ufs.h
+++ b/drivers/scsi/ufs/ufs.h
@@ -46,6 +46,7 @@
 #define QUERY_DESC_HDR_SIZE   2
 #define QUERY_OSF_SIZE(GENERAL_UPIU_REQUEST_SIZE - \
(sizeof(struct utp_upiu_header)))
+#define RESPONSE_UPIU_SENSE_DATA_LENGTH18
 
 #define UPIU_HEADER_DWORD(byte3, byte2, byte1, byte0)\
cpu_to_be32((byte3 << 24) | (byte2 << 16) |\
@@ -416,7 +417,7 @@ struct utp_cmd_rsp {
__be32 residual_transfer_count;
__be32 reserved[4];
__be16 sense_data_len;
-   u8 sense_data[18];
+   u8 sense_data[RESPONSE_UPIU_SENSE_DATA_LENGTH];
 };
 
 /**
diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index 834a28c..a99f57b 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -889,10 +889,14 @@ static inline void ufshcd_copy_sense_data(struct 
ufshcd_lrb *lrbp)
int len;
if (lrbp->sense_buffer &&
ufshcd_get_rsp_upiu_data_seg_len(lrbp->ucd_rsp_ptr)) {
+   int len_to_copy;
+
len = be16_to_cpu(lrbp->ucd_rsp_ptr->sr.sense_data_len);
+   len_to_copy = min_t(int, RESPONSE_UPIU_SENSE_DATA_LENGTH, len);
+
memcpy(lrbp->sense_buffer,
lrbp->ucd_rsp_ptr->sr.sense_data,
-   min_t(int, len, SCSI_SENSE_BUFFERSIZE));
+   min_t(int, len_to_copy, SCSI_SENSE_BUFFERSIZE));
}
 }
 
@@ -6091,7 +6095,10 @@ EXPORT_SYMBOL(ufshcd_system_suspend);
 
 int ufshcd_system_resume(struct ufs_hba *hba)
 {
-   if (!hba || !hba->is_powered || pm_runtime_suspended(hba->dev))
+   if (!hba)
+   return -EINVAL;
+
+   if (!hba->is_powered || pm_runtime_suspended(hba->dev))
/*
 * Let the runtime resume take care of resuming
 * if runtime suspended.
@@ -6112,7 +6119,10 @@ EXPORT_SYMBOL(ufshcd_system_resume);
  */
 int ufshcd_runtime_suspend(struct ufs_hba *hba)
 {
-   if (!hba || !hba->is_powered)
+   if (!hba)
+   return -EINVAL;
+
+   if (!hba->is_powered)
return 0;
 
return ufshcd_suspend(hba, UFS_RUNTIME_PM);
@@ -6142,10 +6152,13 @@ EXPORT_SYMBOL(ufshcd_runtime_suspend);
  */
 int ufshcd_runtime_resume(struct ufs_hba *hba)
 {
-   if (!hba || !hba->is_powered)
+   if (!hba)
+   return -EINVAL;
+
+   if (!hba->is_powered)
return 0;
-   else
-   return ufshcd_resume(hba, UFS_RUNTIME_PM);
+
+   return ufshcd_resume(hba, UFS_RUNTIME_PM);
 }
 EXPORT_SYMBOL(ufshcd_runtime_resume);
 
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project



[PATCH v1 05/11] scsi: ufs: fix sense buffer size to 18 bytes

2016-10-17 Thread Subhash Jadavani
From: Gilad Broner <gbro...@codeaurora.org>

According to UFS device specification, sense data can be only 18 bytes
long, this change makes the changes accordingly.

Signed-off-by: Gilad Broner <gbro...@codeaurora.org>
Signed-off-by: Subhash Jadavani <subha...@codeaurora.org>
---
 drivers/scsi/ufs/ufshcd.c | 12 +++-
 1 file changed, 7 insertions(+), 5 deletions(-)

diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index beb4988..f549be3 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -45,6 +45,8 @@
 #include "ufs_quirks.h"
 #include "unipro.h"
 
+#define UFSHCD_REQ_SENSE_SIZE  18
+
 #define UFSHCD_ENABLE_INTRS(UTP_TRANSFER_REQ_COMPL |\
 UTP_TASK_REQ_COMPL |\
 UFSHCD_ERROR_MASK)
@@ -898,7 +900,7 @@ static inline void ufshcd_copy_sense_data(struct ufshcd_lrb 
*lrbp)
 
memcpy(lrbp->sense_buffer,
lrbp->ucd_rsp_ptr->sr.sense_data,
-   min_t(int, len_to_copy, SCSI_SENSE_BUFFERSIZE));
+   min_t(int, len_to_copy, UFSHCD_REQ_SENSE_SIZE));
}
 }
 
@@ -1463,7 +1465,7 @@ static int ufshcd_queuecommand(struct Scsi_Host *host, 
struct scsi_cmnd *cmd)
 
WARN_ON(lrbp->cmd);
lrbp->cmd = cmd;
-   lrbp->sense_bufflen = SCSI_SENSE_BUFFERSIZE;
+   lrbp->sense_bufflen = UFSHCD_REQ_SENSE_SIZE;
lrbp->sense_buffer = cmd->sense_buffer;
lrbp->task_tag = tag;
lrbp->lun = ufshcd_scsi_to_upiu_lun(cmd->device->lun);
@@ -5594,19 +5596,19 @@ ufshcd_send_request_sense(struct ufs_hba *hba, struct 
scsi_device *sdp)
0,
0,
0,
-   SCSI_SENSE_BUFFERSIZE,
+   UFSHCD_REQ_SENSE_SIZE,
0};
char *buffer;
int ret;
 
-   buffer = kzalloc(SCSI_SENSE_BUFFERSIZE, GFP_KERNEL);
+   buffer = kzalloc(UFSHCD_REQ_SENSE_SIZE, GFP_KERNEL);
if (!buffer) {
ret = -ENOMEM;
goto out;
}
 
ret = scsi_execute_req_flags(sdp, cmd, DMA_FROM_DEVICE, buffer,
-   SCSI_SENSE_BUFFERSIZE, NULL,
+   UFSHCD_REQ_SENSE_SIZE, NULL,
msecs_to_jiffies(1000), 3, NULL, REQ_PM);
if (ret)
pr_err("%s: failed with err %d\n", __func__, ret);
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project



[PATCH v1 09/11] scsi: ufs: change device rails hpm mode ramp up sequence

2016-10-17 Thread Subhash Jadavani
When we are resuming the UFS device rails in HPM mode, we are first
powering on the VCC rail while VCCQ and VCCQ2 rails still being in LPM
mode. Some UFS devices may take VCC on event as hint that host wants
UFS device to be resumed and may start drawing more power from the
VCCQ/VCCQ2 rails (while they are still in LPM mode) causing voltage drop
on these rails. This change fixes this issue by bringing VCCQ & VCCQ2 rails
out of LPM before powering on VCC rail.

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

diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index 43f1c55..ea97fd0 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -5797,7 +5797,6 @@ static int ufshcd_vreg_set_hpm(struct ufs_hba *hba)
!hba->dev_info.is_lu_power_on_wp) {
ret = ufshcd_setup_vreg(hba, true);
} else if (!ufshcd_is_ufs_dev_active(hba)) {
-   ret = ufshcd_toggle_vreg(hba->dev, hba->vreg_info.vcc, true);
if (!ret && !ufshcd_is_link_active(hba)) {
ret = ufshcd_config_vreg_hpm(hba, hba->vreg_info.vccq);
if (ret)
@@ -5806,6 +5805,7 @@ static int ufshcd_vreg_set_hpm(struct ufs_hba *hba)
if (ret)
goto vccq_lpm;
}
+   ret = ufshcd_toggle_vreg(hba->dev, hba->vreg_info.vcc, true);
}
goto out;
 
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project



[PATCH v1 03/11] scsi: ufs: fix bugs related to null pointer access and array size

2016-10-17 Thread Subhash Jadavani
From: Yaniv Gardi 

In this change there are a few fixes of possible NULL pointer access
and possible access to index that exceeds array boundaries.

Signed-off-by: Yaniv Gardi 
Signed-off-by: Subhash Jadavani 
---
 drivers/scsi/ufs/ufs.h|  3 ++-
 drivers/scsi/ufs/ufshcd.c | 25 +++--
 2 files changed, 21 insertions(+), 7 deletions(-)

diff --git a/drivers/scsi/ufs/ufs.h b/drivers/scsi/ufs/ufs.h
index 845b874..7a6ccb6 100644
--- a/drivers/scsi/ufs/ufs.h
+++ b/drivers/scsi/ufs/ufs.h
@@ -46,6 +46,7 @@
 #define QUERY_DESC_HDR_SIZE   2
 #define QUERY_OSF_SIZE(GENERAL_UPIU_REQUEST_SIZE - \
(sizeof(struct utp_upiu_header)))
+#define RESPONSE_UPIU_SENSE_DATA_LENGTH18
 
 #define UPIU_HEADER_DWORD(byte3, byte2, byte1, byte0)\
cpu_to_be32((byte3 << 24) | (byte2 << 16) |\
@@ -416,7 +417,7 @@ struct utp_cmd_rsp {
__be32 residual_transfer_count;
__be32 reserved[4];
__be16 sense_data_len;
-   u8 sense_data[18];
+   u8 sense_data[RESPONSE_UPIU_SENSE_DATA_LENGTH];
 };
 
 /**
diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index 834a28c..a99f57b 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -889,10 +889,14 @@ static inline void ufshcd_copy_sense_data(struct 
ufshcd_lrb *lrbp)
int len;
if (lrbp->sense_buffer &&
ufshcd_get_rsp_upiu_data_seg_len(lrbp->ucd_rsp_ptr)) {
+   int len_to_copy;
+
len = be16_to_cpu(lrbp->ucd_rsp_ptr->sr.sense_data_len);
+   len_to_copy = min_t(int, RESPONSE_UPIU_SENSE_DATA_LENGTH, len);
+
memcpy(lrbp->sense_buffer,
lrbp->ucd_rsp_ptr->sr.sense_data,
-   min_t(int, len, SCSI_SENSE_BUFFERSIZE));
+   min_t(int, len_to_copy, SCSI_SENSE_BUFFERSIZE));
}
 }
 
@@ -6091,7 +6095,10 @@ EXPORT_SYMBOL(ufshcd_system_suspend);
 
 int ufshcd_system_resume(struct ufs_hba *hba)
 {
-   if (!hba || !hba->is_powered || pm_runtime_suspended(hba->dev))
+   if (!hba)
+   return -EINVAL;
+
+   if (!hba->is_powered || pm_runtime_suspended(hba->dev))
/*
 * Let the runtime resume take care of resuming
 * if runtime suspended.
@@ -6112,7 +6119,10 @@ EXPORT_SYMBOL(ufshcd_system_resume);
  */
 int ufshcd_runtime_suspend(struct ufs_hba *hba)
 {
-   if (!hba || !hba->is_powered)
+   if (!hba)
+   return -EINVAL;
+
+   if (!hba->is_powered)
return 0;
 
return ufshcd_suspend(hba, UFS_RUNTIME_PM);
@@ -6142,10 +6152,13 @@ EXPORT_SYMBOL(ufshcd_runtime_suspend);
  */
 int ufshcd_runtime_resume(struct ufs_hba *hba)
 {
-   if (!hba || !hba->is_powered)
+   if (!hba)
+   return -EINVAL;
+
+   if (!hba->is_powered)
return 0;
-   else
-   return ufshcd_resume(hba, UFS_RUNTIME_PM);
+
+   return ufshcd_resume(hba, UFS_RUNTIME_PM);
 }
 EXPORT_SYMBOL(ufshcd_runtime_resume);
 
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project



[PATCH v1 05/11] scsi: ufs: fix sense buffer size to 18 bytes

2016-10-17 Thread Subhash Jadavani
From: Gilad Broner 

According to UFS device specification, sense data can be only 18 bytes
long, this change makes the changes accordingly.

Signed-off-by: Gilad Broner 
Signed-off-by: Subhash Jadavani 
---
 drivers/scsi/ufs/ufshcd.c | 12 +++-
 1 file changed, 7 insertions(+), 5 deletions(-)

diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index beb4988..f549be3 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -45,6 +45,8 @@
 #include "ufs_quirks.h"
 #include "unipro.h"
 
+#define UFSHCD_REQ_SENSE_SIZE  18
+
 #define UFSHCD_ENABLE_INTRS(UTP_TRANSFER_REQ_COMPL |\
 UTP_TASK_REQ_COMPL |\
 UFSHCD_ERROR_MASK)
@@ -898,7 +900,7 @@ static inline void ufshcd_copy_sense_data(struct ufshcd_lrb 
*lrbp)
 
memcpy(lrbp->sense_buffer,
lrbp->ucd_rsp_ptr->sr.sense_data,
-   min_t(int, len_to_copy, SCSI_SENSE_BUFFERSIZE));
+   min_t(int, len_to_copy, UFSHCD_REQ_SENSE_SIZE));
}
 }
 
@@ -1463,7 +1465,7 @@ static int ufshcd_queuecommand(struct Scsi_Host *host, 
struct scsi_cmnd *cmd)
 
WARN_ON(lrbp->cmd);
lrbp->cmd = cmd;
-   lrbp->sense_bufflen = SCSI_SENSE_BUFFERSIZE;
+   lrbp->sense_bufflen = UFSHCD_REQ_SENSE_SIZE;
lrbp->sense_buffer = cmd->sense_buffer;
lrbp->task_tag = tag;
lrbp->lun = ufshcd_scsi_to_upiu_lun(cmd->device->lun);
@@ -5594,19 +5596,19 @@ ufshcd_send_request_sense(struct ufs_hba *hba, struct 
scsi_device *sdp)
0,
0,
0,
-   SCSI_SENSE_BUFFERSIZE,
+   UFSHCD_REQ_SENSE_SIZE,
0};
char *buffer;
int ret;
 
-   buffer = kzalloc(SCSI_SENSE_BUFFERSIZE, GFP_KERNEL);
+   buffer = kzalloc(UFSHCD_REQ_SENSE_SIZE, GFP_KERNEL);
if (!buffer) {
ret = -ENOMEM;
goto out;
}
 
ret = scsi_execute_req_flags(sdp, cmd, DMA_FROM_DEVICE, buffer,
-   SCSI_SENSE_BUFFERSIZE, NULL,
+   UFSHCD_REQ_SENSE_SIZE, NULL,
msecs_to_jiffies(1000), 3, NULL, REQ_PM);
if (ret)
pr_err("%s: failed with err %d\n", __func__, ret);
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project



[PATCH v1 09/11] scsi: ufs: change device rails hpm mode ramp up sequence

2016-10-17 Thread Subhash Jadavani
When we are resuming the UFS device rails in HPM mode, we are first
powering on the VCC rail while VCCQ and VCCQ2 rails still being in LPM
mode. Some UFS devices may take VCC on event as hint that host wants
UFS device to be resumed and may start drawing more power from the
VCCQ/VCCQ2 rails (while they are still in LPM mode) causing voltage drop
on these rails. This change fixes this issue by bringing VCCQ & VCCQ2 rails
out of LPM before powering on VCC rail.

Signed-off-by: Subhash Jadavani 
---
 drivers/scsi/ufs/ufshcd.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index 43f1c55..ea97fd0 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -5797,7 +5797,6 @@ static int ufshcd_vreg_set_hpm(struct ufs_hba *hba)
!hba->dev_info.is_lu_power_on_wp) {
ret = ufshcd_setup_vreg(hba, true);
} else if (!ufshcd_is_ufs_dev_active(hba)) {
-   ret = ufshcd_toggle_vreg(hba->dev, hba->vreg_info.vcc, true);
if (!ret && !ufshcd_is_link_active(hba)) {
ret = ufshcd_config_vreg_hpm(hba, hba->vreg_info.vccq);
if (ret)
@@ -5806,6 +5805,7 @@ static int ufshcd_vreg_set_hpm(struct ufs_hba *hba)
if (ret)
goto vccq_lpm;
}
+   ret = ufshcd_toggle_vreg(hba->dev, hba->vreg_info.vcc, true);
}
goto out;
 
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project



[PATCH v1 04/11] scsi: ufs: commit descriptors before setting the doorbell

2016-10-17 Thread Subhash Jadavani
From: Gilad Broner <gbro...@codeaurora.org>

Add a write memory barrier to make sure descriptors prepared are actually
written to memory before ringing the doorbell. We have also added the
write memory barrier after ringing the doorbell register so that
controller sees the new request immediately.

Signed-off-by: Gilad Broner <gbro...@codeaurora.org>
Signed-off-by: Subhash Jadavani <subha...@codeaurora.org>
---
 drivers/scsi/ufs/ufshcd.c | 8 
 1 file changed, 8 insertions(+)

diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index a99f57b..beb4988 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -878,6 +878,8 @@ void ufshcd_send_command(struct ufs_hba *hba, unsigned int 
task_tag)
ufshcd_clk_scaling_start_busy(hba);
__set_bit(task_tag, >outstanding_reqs);
ufshcd_writel(hba, 1 << task_tag, REG_UTP_TRANSFER_REQ_DOOR_BELL);
+   /* Make sure that doorbell is committed immediately */
+   wmb();
 }
 
 /**
@@ -1475,6 +1477,8 @@ static int ufshcd_queuecommand(struct Scsi_Host *host, 
struct scsi_cmnd *cmd)
clear_bit_unlock(tag, >lrb_in_use);
goto out;
}
+   /* Make sure descriptors are ready before ringing the doorbell */
+   wmb();
 
/* issue command to the controller */
spin_lock_irqsave(hba->host->host_lock, flags);
@@ -1585,6 +1589,8 @@ static int ufshcd_wait_for_dev_cmd(struct ufs_hba *hba,
time_left = wait_for_completion_timeout(hba->dev_cmd.complete,
msecs_to_jiffies(max_timeout));
 
+   /* Make sure descriptors are ready before ringing the doorbell */
+   wmb();
spin_lock_irqsave(hba->host->host_lock, flags);
hba->dev_cmd.complete = NULL;
if (likely(time_left)) {
@@ -4322,6 +4328,8 @@ static int ufshcd_issue_tm_cmd(struct ufs_hba *hba, int 
lun_id, int task_id,
wmb();
 
ufshcd_writel(hba, 1 << free_slot, REG_UTP_TASK_REQ_DOOR_BELL);
+   /* Make sure that doorbell is committed immediately */
+   wmb();
 
spin_unlock_irqrestore(host->host_lock, flags);
 
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project



[PATCH v1 04/11] scsi: ufs: commit descriptors before setting the doorbell

2016-10-17 Thread Subhash Jadavani
From: Gilad Broner 

Add a write memory barrier to make sure descriptors prepared are actually
written to memory before ringing the doorbell. We have also added the
write memory barrier after ringing the doorbell register so that
controller sees the new request immediately.

Signed-off-by: Gilad Broner 
Signed-off-by: Subhash Jadavani 
---
 drivers/scsi/ufs/ufshcd.c | 8 
 1 file changed, 8 insertions(+)

diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index a99f57b..beb4988 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -878,6 +878,8 @@ void ufshcd_send_command(struct ufs_hba *hba, unsigned int 
task_tag)
ufshcd_clk_scaling_start_busy(hba);
__set_bit(task_tag, >outstanding_reqs);
ufshcd_writel(hba, 1 << task_tag, REG_UTP_TRANSFER_REQ_DOOR_BELL);
+   /* Make sure that doorbell is committed immediately */
+   wmb();
 }
 
 /**
@@ -1475,6 +1477,8 @@ static int ufshcd_queuecommand(struct Scsi_Host *host, 
struct scsi_cmnd *cmd)
clear_bit_unlock(tag, >lrb_in_use);
goto out;
}
+   /* Make sure descriptors are ready before ringing the doorbell */
+   wmb();
 
/* issue command to the controller */
spin_lock_irqsave(hba->host->host_lock, flags);
@@ -1585,6 +1589,8 @@ static int ufshcd_wait_for_dev_cmd(struct ufs_hba *hba,
time_left = wait_for_completion_timeout(hba->dev_cmd.complete,
msecs_to_jiffies(max_timeout));
 
+   /* Make sure descriptors are ready before ringing the doorbell */
+   wmb();
spin_lock_irqsave(hba->host->host_lock, flags);
hba->dev_cmd.complete = NULL;
if (likely(time_left)) {
@@ -4322,6 +4328,8 @@ static int ufshcd_issue_tm_cmd(struct ufs_hba *hba, int 
lun_id, int task_id,
wmb();
 
ufshcd_writel(hba, 1 << free_slot, REG_UTP_TASK_REQ_DOOR_BELL);
+   /* Make sure that doorbell is committed immediately */
+   wmb();
 
spin_unlock_irqrestore(host->host_lock, flags);
 
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project



[PATCH v1 07/11] scsi: ufs: fail ufshcd_probe_hba() if power configuration fails

2016-10-17 Thread Subhash Jadavani
From: Dov Levenglick <d...@codeaurora.org>

In case the power configuration fails, skip further processing
of the  probing function and return immediately. This has 2 reasons:
1. Don't allow the UFS to continue running in PWM
2. Avoid multiple calls to pm_runtime_put_sync() when not
   in error handling or power management contexts

Signed-off-by: Dov Levenglick <d...@codeaurora.org>
Signed-off-by: Subhash Jadavani <subha...@codeaurora.org>
---
 drivers/scsi/ufs/ufshcd.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index c6fa3c0..fced52f 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -5051,9 +5051,11 @@ static int ufshcd_probe_hba(struct ufs_hba *hba)
__func__);
} else {
ret = ufshcd_config_pwr_mode(hba, >max_pwr_info.info);
-   if (ret)
+   if (ret) {
dev_err(hba->dev, "%s: Failed setting power mode, err = 
%d\n",
__func__, ret);
+   goto out;
+   }
}
 
/* set the state as operational after switching to desired gear */
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project



[PATCH v1 08/11] scsi: ufs: suspend clock scaling at the start of suspend

2016-10-17 Thread Subhash Jadavani
Currently clock scaling is suspended only after the host and device
are put in low power mode but we should avoid clock scaling running
after UFS link is put in low power mode (hibern8). This change
suspends clock scaling before putting host/device in low power mode.

Signed-off-by: Subhash Jadavani <subha...@codeaurora.org>
---
 drivers/scsi/ufs/ufshcd.c | 14 +-
 1 file changed, 5 insertions(+), 9 deletions(-)

diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index fced52f..43f1c55 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -5870,6 +5870,8 @@ static int ufshcd_suspend(struct ufs_hba *hba, enum 
ufs_pm_op pm_op)
ufshcd_hold(hba, false);
hba->clk_gating.is_suspended = true;
 
+   ufshcd_suspend_clkscaling(hba);
+
if (req_dev_pwr_mode == UFS_ACTIVE_PWR_MODE &&
req_link_state == UIC_LINK_ACTIVE_STATE) {
goto disable_clks;
@@ -5877,12 +5879,12 @@ static int ufshcd_suspend(struct ufs_hba *hba, enum 
ufs_pm_op pm_op)
 
if ((req_dev_pwr_mode == hba->curr_dev_pwr_mode) &&
(req_link_state == hba->uic_link_state))
-   goto out;
+   goto enable_gating;
 
/* UFS device & link must be active before we enter in this function */
if (!ufshcd_is_ufs_dev_active(hba) || !ufshcd_is_link_active(hba)) {
ret = -EINVAL;
-   goto out;
+   goto enable_gating;
}
 
if (ufshcd_is_runtime_pm(pm_op)) {
@@ -5919,13 +5921,6 @@ static int ufshcd_suspend(struct ufs_hba *hba, enum 
ufs_pm_op pm_op)
 
 disable_clks:
/*
-* The clock scaling needs access to controller registers. Hence, Wait
-* for pending clock scaling work to be done before clocks are
-* turned off.
-*/
-   ufshcd_suspend_clkscaling(hba);
-
-   /*
 * Call vendor specific suspend callback. As these callbacks may access
 * vendor specific host controller register space call them before the
 * host clocks are ON.
@@ -5961,6 +5956,7 @@ set_dev_active:
if (!ufshcd_set_dev_pwr_mode(hba, UFS_ACTIVE_PWR_MODE))
ufshcd_disable_auto_bkops(hba);
 enable_gating:
+   ufshcd_resume_clkscaling(hba);
hba->clk_gating.is_suspended = false;
ufshcd_release(hba);
 out:
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project



[PATCH v1 07/11] scsi: ufs: fail ufshcd_probe_hba() if power configuration fails

2016-10-17 Thread Subhash Jadavani
From: Dov Levenglick 

In case the power configuration fails, skip further processing
of the  probing function and return immediately. This has 2 reasons:
1. Don't allow the UFS to continue running in PWM
2. Avoid multiple calls to pm_runtime_put_sync() when not
   in error handling or power management contexts

Signed-off-by: Dov Levenglick 
Signed-off-by: Subhash Jadavani 
---
 drivers/scsi/ufs/ufshcd.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index c6fa3c0..fced52f 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -5051,9 +5051,11 @@ static int ufshcd_probe_hba(struct ufs_hba *hba)
__func__);
} else {
ret = ufshcd_config_pwr_mode(hba, >max_pwr_info.info);
-   if (ret)
+   if (ret) {
dev_err(hba->dev, "%s: Failed setting power mode, err = 
%d\n",
__func__, ret);
+   goto out;
+   }
}
 
/* set the state as operational after switching to desired gear */
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project



[PATCH v1 08/11] scsi: ufs: suspend clock scaling at the start of suspend

2016-10-17 Thread Subhash Jadavani
Currently clock scaling is suspended only after the host and device
are put in low power mode but we should avoid clock scaling running
after UFS link is put in low power mode (hibern8). This change
suspends clock scaling before putting host/device in low power mode.

Signed-off-by: Subhash Jadavani 
---
 drivers/scsi/ufs/ufshcd.c | 14 +-
 1 file changed, 5 insertions(+), 9 deletions(-)

diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index fced52f..43f1c55 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -5870,6 +5870,8 @@ static int ufshcd_suspend(struct ufs_hba *hba, enum 
ufs_pm_op pm_op)
ufshcd_hold(hba, false);
hba->clk_gating.is_suspended = true;
 
+   ufshcd_suspend_clkscaling(hba);
+
if (req_dev_pwr_mode == UFS_ACTIVE_PWR_MODE &&
req_link_state == UIC_LINK_ACTIVE_STATE) {
goto disable_clks;
@@ -5877,12 +5879,12 @@ static int ufshcd_suspend(struct ufs_hba *hba, enum 
ufs_pm_op pm_op)
 
if ((req_dev_pwr_mode == hba->curr_dev_pwr_mode) &&
(req_link_state == hba->uic_link_state))
-   goto out;
+   goto enable_gating;
 
/* UFS device & link must be active before we enter in this function */
if (!ufshcd_is_ufs_dev_active(hba) || !ufshcd_is_link_active(hba)) {
ret = -EINVAL;
-   goto out;
+   goto enable_gating;
}
 
if (ufshcd_is_runtime_pm(pm_op)) {
@@ -5919,13 +5921,6 @@ static int ufshcd_suspend(struct ufs_hba *hba, enum 
ufs_pm_op pm_op)
 
 disable_clks:
/*
-* The clock scaling needs access to controller registers. Hence, Wait
-* for pending clock scaling work to be done before clocks are
-* turned off.
-*/
-   ufshcd_suspend_clkscaling(hba);
-
-   /*
 * Call vendor specific suspend callback. As these callbacks may access
 * vendor specific host controller register space call them before the
 * host clocks are ON.
@@ -5961,6 +5956,7 @@ set_dev_active:
if (!ufshcd_set_dev_pwr_mode(hba, UFS_ACTIVE_PWR_MODE))
ufshcd_disable_auto_bkops(hba);
 enable_gating:
+   ufshcd_resume_clkscaling(hba);
hba->clk_gating.is_suspended = false;
ufshcd_release(hba);
 out:
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project



[PATCH v1 06/11] scsi: ufs: suspend clock scaling for failed runtime_resume

2016-10-17 Thread Subhash Jadavani
From: Gilad Broner <gbro...@codeaurora.org>

During runtime resume operation, clock scaling may get indirectly
resumed via call to ufshcd_set_dev_pwr_mode(): Start/Stop Unit command
times out and SCSI error handling ultimately calls the host reset handler
to recover, during which clock scaling is resumed.
Error case exit path of runtime resume will disable clocks.
As clock scaling was already resumed, it will get scheduled later on and
try to access UFS registers while clocks are disabled, resulting in
unclocked register access.

Signed-off-by: Gilad Broner <gbro...@codeaurora.org>
Signed-off-by: Subhash Jadavani <subha...@codeaurora.org>
---
 drivers/scsi/ufs/ufshcd.c | 40 
 1 file changed, 24 insertions(+), 16 deletions(-)

diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index f549be3..c6fa3c0 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -600,6 +600,20 @@ static bool ufshcd_is_unipro_pa_params_tuning_req(struct 
ufs_hba *hba)
return false;
 }
 
+static void ufshcd_suspend_clkscaling(struct ufs_hba *hba)
+{
+   if (ufshcd_is_clkscaling_enabled(hba)) {
+   devfreq_suspend_device(hba->devfreq);
+   hba->clk_scaling.window_start_t = 0;
+   }
+}
+
+static void ufshcd_resume_clkscaling(struct ufs_hba *hba)
+{
+   if (ufshcd_is_clkscaling_enabled(hba))
+   devfreq_resume_device(hba->devfreq);
+}
+
 static void ufshcd_ungate_work(struct work_struct *work)
 {
int ret;
@@ -633,8 +647,7 @@ static void ufshcd_ungate_work(struct work_struct *work)
hba->clk_gating.is_suspended = false;
}
 unblock_reqs:
-   if (ufshcd_is_clkscaling_enabled(hba))
-   devfreq_resume_device(hba->devfreq);
+   ufshcd_resume_clkscaling(hba);
scsi_unblock_requests(hba->host);
 }
 
@@ -733,10 +746,7 @@ static void ufshcd_gate_work(struct work_struct *work)
ufshcd_set_link_hibern8(hba);
}
 
-   if (ufshcd_is_clkscaling_enabled(hba)) {
-   devfreq_suspend_device(hba->devfreq);
-   hba->clk_scaling.window_start_t = 0;
-   }
+   ufshcd_suspend_clkscaling(hba);
 
if (!ufshcd_is_link_active(hba))
ufshcd_setup_clocks(hba, false);
@@ -5076,8 +5086,7 @@ static int ufshcd_probe_hba(struct ufs_hba *hba)
hba->is_init_prefetch = true;
 
/* Resume devfreq after UFS device is detected */
-   if (ufshcd_is_clkscaling_enabled(hba))
-   devfreq_resume_device(hba->devfreq);
+   ufshcd_resume_clkscaling(hba);
 
 out:
/*
@@ -5583,6 +5592,7 @@ static void ufshcd_hba_exit(struct ufs_hba *hba)
if (hba->is_powered) {
ufshcd_variant_hba_exit(hba);
ufshcd_setup_vreg(hba, false);
+   ufshcd_suspend_clkscaling(hba);
ufshcd_setup_clocks(hba, false);
ufshcd_setup_hba_vreg(hba, false);
hba->is_powered = false;
@@ -5911,10 +5921,8 @@ disable_clks:
 * for pending clock scaling work to be done before clocks are
 * turned off.
 */
-   if (ufshcd_is_clkscaling_enabled(hba)) {
-   devfreq_suspend_device(hba->devfreq);
-   hba->clk_scaling.window_start_t = 0;
-   }
+   ufshcd_suspend_clkscaling(hba);
+
/*
 * Call vendor specific suspend callback. As these callbacks may access
 * vendor specific host controller register space call them before the
@@ -5941,6 +5949,7 @@ disable_clks:
goto out;
 
 set_link_active:
+   ufshcd_resume_clkscaling(hba);
ufshcd_vreg_set_hpm(hba);
if (ufshcd_is_link_hibern8(hba) && !ufshcd_uic_hibern8_exit(hba))
ufshcd_set_link_active(hba);
@@ -6028,8 +6037,7 @@ static int ufshcd_resume(struct ufs_hba *hba, enum 
ufs_pm_op pm_op)
ufshcd_urgent_bkops(hba);
hba->clk_gating.is_suspended = false;
 
-   if (ufshcd_is_clkscaling_enabled(hba))
-   devfreq_resume_device(hba->devfreq);
+   ufshcd_resume_clkscaling(hba);
 
/* Schedule clock gating in case of no access to UFS device yet */
ufshcd_release(hba);
@@ -6043,6 +6051,7 @@ disable_vreg:
ufshcd_vreg_set_lpm(hba);
 disable_irq_and_vops_clks:
ufshcd_disable_irq(hba);
+   ufshcd_suspend_clkscaling(hba);
ufshcd_setup_clocks(hba, false);
 out:
hba->pm_op_in_progress = 0;
@@ -6559,8 +6568,7 @@ int ufshcd_init(struct ufs_hba *hba, void __iomem 
*mmio_base, unsigned int irq)
goto out_remove_scsi_host;
}
/* Suspend devfreq until the UFS device is detected */
-   devfreq_suspend_device(hba->devfreq);
-   hba->clk_scaling.window_start_t = 0;
+   ufshcd_suspend_clkscaling(hba);
}
 
   

[PATCH v1 06/11] scsi: ufs: suspend clock scaling for failed runtime_resume

2016-10-17 Thread Subhash Jadavani
From: Gilad Broner 

During runtime resume operation, clock scaling may get indirectly
resumed via call to ufshcd_set_dev_pwr_mode(): Start/Stop Unit command
times out and SCSI error handling ultimately calls the host reset handler
to recover, during which clock scaling is resumed.
Error case exit path of runtime resume will disable clocks.
As clock scaling was already resumed, it will get scheduled later on and
try to access UFS registers while clocks are disabled, resulting in
unclocked register access.

Signed-off-by: Gilad Broner 
Signed-off-by: Subhash Jadavani 
---
 drivers/scsi/ufs/ufshcd.c | 40 
 1 file changed, 24 insertions(+), 16 deletions(-)

diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index f549be3..c6fa3c0 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -600,6 +600,20 @@ static bool ufshcd_is_unipro_pa_params_tuning_req(struct 
ufs_hba *hba)
return false;
 }
 
+static void ufshcd_suspend_clkscaling(struct ufs_hba *hba)
+{
+   if (ufshcd_is_clkscaling_enabled(hba)) {
+   devfreq_suspend_device(hba->devfreq);
+   hba->clk_scaling.window_start_t = 0;
+   }
+}
+
+static void ufshcd_resume_clkscaling(struct ufs_hba *hba)
+{
+   if (ufshcd_is_clkscaling_enabled(hba))
+   devfreq_resume_device(hba->devfreq);
+}
+
 static void ufshcd_ungate_work(struct work_struct *work)
 {
int ret;
@@ -633,8 +647,7 @@ static void ufshcd_ungate_work(struct work_struct *work)
hba->clk_gating.is_suspended = false;
}
 unblock_reqs:
-   if (ufshcd_is_clkscaling_enabled(hba))
-   devfreq_resume_device(hba->devfreq);
+   ufshcd_resume_clkscaling(hba);
scsi_unblock_requests(hba->host);
 }
 
@@ -733,10 +746,7 @@ static void ufshcd_gate_work(struct work_struct *work)
ufshcd_set_link_hibern8(hba);
}
 
-   if (ufshcd_is_clkscaling_enabled(hba)) {
-   devfreq_suspend_device(hba->devfreq);
-   hba->clk_scaling.window_start_t = 0;
-   }
+   ufshcd_suspend_clkscaling(hba);
 
if (!ufshcd_is_link_active(hba))
ufshcd_setup_clocks(hba, false);
@@ -5076,8 +5086,7 @@ static int ufshcd_probe_hba(struct ufs_hba *hba)
hba->is_init_prefetch = true;
 
/* Resume devfreq after UFS device is detected */
-   if (ufshcd_is_clkscaling_enabled(hba))
-   devfreq_resume_device(hba->devfreq);
+   ufshcd_resume_clkscaling(hba);
 
 out:
/*
@@ -5583,6 +5592,7 @@ static void ufshcd_hba_exit(struct ufs_hba *hba)
if (hba->is_powered) {
ufshcd_variant_hba_exit(hba);
ufshcd_setup_vreg(hba, false);
+   ufshcd_suspend_clkscaling(hba);
ufshcd_setup_clocks(hba, false);
ufshcd_setup_hba_vreg(hba, false);
hba->is_powered = false;
@@ -5911,10 +5921,8 @@ disable_clks:
 * for pending clock scaling work to be done before clocks are
 * turned off.
 */
-   if (ufshcd_is_clkscaling_enabled(hba)) {
-   devfreq_suspend_device(hba->devfreq);
-   hba->clk_scaling.window_start_t = 0;
-   }
+   ufshcd_suspend_clkscaling(hba);
+
/*
 * Call vendor specific suspend callback. As these callbacks may access
 * vendor specific host controller register space call them before the
@@ -5941,6 +5949,7 @@ disable_clks:
goto out;
 
 set_link_active:
+   ufshcd_resume_clkscaling(hba);
ufshcd_vreg_set_hpm(hba);
if (ufshcd_is_link_hibern8(hba) && !ufshcd_uic_hibern8_exit(hba))
ufshcd_set_link_active(hba);
@@ -6028,8 +6037,7 @@ static int ufshcd_resume(struct ufs_hba *hba, enum 
ufs_pm_op pm_op)
ufshcd_urgent_bkops(hba);
hba->clk_gating.is_suspended = false;
 
-   if (ufshcd_is_clkscaling_enabled(hba))
-   devfreq_resume_device(hba->devfreq);
+   ufshcd_resume_clkscaling(hba);
 
/* Schedule clock gating in case of no access to UFS device yet */
ufshcd_release(hba);
@@ -6043,6 +6051,7 @@ disable_vreg:
ufshcd_vreg_set_lpm(hba);
 disable_irq_and_vops_clks:
ufshcd_disable_irq(hba);
+   ufshcd_suspend_clkscaling(hba);
ufshcd_setup_clocks(hba, false);
 out:
hba->pm_op_in_progress = 0;
@@ -6559,8 +6568,7 @@ int ufshcd_init(struct ufs_hba *hba, void __iomem 
*mmio_base, unsigned int irq)
goto out_remove_scsi_host;
}
/* Suspend devfreq until the UFS device is detected */
-   devfreq_suspend_device(hba->devfreq);
-   hba->clk_scaling.window_start_t = 0;
+   ufshcd_suspend_clkscaling(hba);
}
 
/* Hold auto suspend until async scan completes */
-- 
The Qualcomm Innovation Cent

[PATCH v1 02/11] scsi: ufshcd: release resources if probe fails

2016-10-17 Thread Subhash Jadavani
If ufshcd pltfrm/pci driver's probe fails for some reason then ensure that
scsi host is released to avoid memory leak but managed memory allocations
(via devm_* calls) need not to be freed explicitly on probe failure as
memory allocated with these functions is automatically freed on driver
detach.

Signed-off-by: Subhash Jadavani <subha...@codeaurora.org>
---
 drivers/scsi/ufs/ufshcd-pci.c| 2 ++
 drivers/scsi/ufs/ufshcd-pltfrm.c | 5 +
 drivers/scsi/ufs/ufshcd.c| 3 ---
 3 files changed, 3 insertions(+), 7 deletions(-)

diff --git a/drivers/scsi/ufs/ufshcd-pci.c b/drivers/scsi/ufs/ufshcd-pci.c
index d15eaa4..52b546f 100644
--- a/drivers/scsi/ufs/ufshcd-pci.c
+++ b/drivers/scsi/ufs/ufshcd-pci.c
@@ -104,6 +104,7 @@ static void ufshcd_pci_remove(struct pci_dev *pdev)
pm_runtime_forbid(>dev);
pm_runtime_get_noresume(>dev);
ufshcd_remove(hba);
+   ufshcd_dealloc_host(hba);
 }
 
 /**
@@ -147,6 +148,7 @@ ufshcd_pci_probe(struct pci_dev *pdev, const struct 
pci_device_id *id)
err = ufshcd_init(hba, mmio_base, pdev->irq);
if (err) {
dev_err(>dev, "Initialization failed\n");
+   ufshcd_dealloc_host(hba);
return err;
}
 
diff --git a/drivers/scsi/ufs/ufshcd-pltfrm.c b/drivers/scsi/ufs/ufshcd-pltfrm.c
index db53f38..a72a4ba 100644
--- a/drivers/scsi/ufs/ufshcd-pltfrm.c
+++ b/drivers/scsi/ufs/ufshcd-pltfrm.c
@@ -163,7 +163,7 @@ static int ufshcd_populate_vreg(struct device *dev, const 
char *name,
if (ret) {
dev_err(dev, "%s: unable to find %s err %d\n",
__func__, prop_name, ret);
-   goto out_free;
+   goto out;
}
 
vreg->min_uA = 0;
@@ -185,9 +185,6 @@ static int ufshcd_populate_vreg(struct device *dev, const 
char *name,
 
goto out;
 
-out_free:
-   devm_kfree(dev, vreg);
-   vreg = NULL;
 out:
if (!ret)
*out_vreg = vreg;
diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index 77700ee..834a28c 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -6197,8 +6197,6 @@ void ufshcd_remove(struct ufs_hba *hba)
ufshcd_disable_intr(hba, hba->intr_mask);
ufshcd_hba_stop(hba, true);
 
-   scsi_host_put(hba->host);
-
ufshcd_exit_clk_gating(hba);
if (ufshcd_is_clkscaling_enabled(hba))
devfreq_remove_device(hba->devfreq);
@@ -6561,7 +6559,6 @@ exit_gating:
ufshcd_exit_clk_gating(hba);
 out_disable:
hba->is_irq_enabled = false;
-   scsi_host_put(host);
ufshcd_hba_exit(hba);
 out_error:
return err;
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project



[PATCH v1 02/11] scsi: ufshcd: release resources if probe fails

2016-10-17 Thread Subhash Jadavani
If ufshcd pltfrm/pci driver's probe fails for some reason then ensure that
scsi host is released to avoid memory leak but managed memory allocations
(via devm_* calls) need not to be freed explicitly on probe failure as
memory allocated with these functions is automatically freed on driver
detach.

Signed-off-by: Subhash Jadavani 
---
 drivers/scsi/ufs/ufshcd-pci.c| 2 ++
 drivers/scsi/ufs/ufshcd-pltfrm.c | 5 +
 drivers/scsi/ufs/ufshcd.c| 3 ---
 3 files changed, 3 insertions(+), 7 deletions(-)

diff --git a/drivers/scsi/ufs/ufshcd-pci.c b/drivers/scsi/ufs/ufshcd-pci.c
index d15eaa4..52b546f 100644
--- a/drivers/scsi/ufs/ufshcd-pci.c
+++ b/drivers/scsi/ufs/ufshcd-pci.c
@@ -104,6 +104,7 @@ static void ufshcd_pci_remove(struct pci_dev *pdev)
pm_runtime_forbid(>dev);
pm_runtime_get_noresume(>dev);
ufshcd_remove(hba);
+   ufshcd_dealloc_host(hba);
 }
 
 /**
@@ -147,6 +148,7 @@ ufshcd_pci_probe(struct pci_dev *pdev, const struct 
pci_device_id *id)
err = ufshcd_init(hba, mmio_base, pdev->irq);
if (err) {
dev_err(>dev, "Initialization failed\n");
+   ufshcd_dealloc_host(hba);
return err;
}
 
diff --git a/drivers/scsi/ufs/ufshcd-pltfrm.c b/drivers/scsi/ufs/ufshcd-pltfrm.c
index db53f38..a72a4ba 100644
--- a/drivers/scsi/ufs/ufshcd-pltfrm.c
+++ b/drivers/scsi/ufs/ufshcd-pltfrm.c
@@ -163,7 +163,7 @@ static int ufshcd_populate_vreg(struct device *dev, const 
char *name,
if (ret) {
dev_err(dev, "%s: unable to find %s err %d\n",
__func__, prop_name, ret);
-   goto out_free;
+   goto out;
}
 
vreg->min_uA = 0;
@@ -185,9 +185,6 @@ static int ufshcd_populate_vreg(struct device *dev, const 
char *name,
 
goto out;
 
-out_free:
-   devm_kfree(dev, vreg);
-   vreg = NULL;
 out:
if (!ret)
*out_vreg = vreg;
diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index 77700ee..834a28c 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -6197,8 +6197,6 @@ void ufshcd_remove(struct ufs_hba *hba)
ufshcd_disable_intr(hba, hba->intr_mask);
ufshcd_hba_stop(hba, true);
 
-   scsi_host_put(hba->host);
-
ufshcd_exit_clk_gating(hba);
if (ufshcd_is_clkscaling_enabled(hba))
devfreq_remove_device(hba->devfreq);
@@ -6561,7 +6559,6 @@ exit_gating:
ufshcd_exit_clk_gating(hba);
 out_disable:
hba->is_irq_enabled = false;
-   scsi_host_put(host);
ufshcd_hba_exit(hba);
 out_error:
return err;
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project



[PATCH v1 01/11] scsi: ufs: fix race between clock gating and devfreq scaling work

2016-10-17 Thread Subhash Jadavani
UFS devfreq clock scaling work may require clocks to be ON if it need to
execute some UFS commands hence it may request for clock hold before
issuing the command. But if UFS clock gating work is already running in
parallel, ungate work would end up waiting for the clock gating work to
finish and as clock gating work would also wait for the clock scaling work
to finish, we would enter in deadlock state. Here is the call trace during
this deadlock state:

Workqueue: devfreq_wq devfreq_monitor
__switch_to
__schedule
schedule
schedule_timeout
wait_for_common
wait_for_completion
flush_work
ufshcd_hold
ufshcd_send_uic_cmd
ufshcd_dme_get_attr
ufs_qcom_set_dme_vs_core_clk_ctrl_clear_div
ufs_qcom_clk_scale_notify
ufshcd_scale_clks
ufshcd_devfreq_target
update_devfreq
devfreq_monitor
process_one_work
worker_thread
kthread
ret_from_fork

Workqueue: events ufshcd_gate_work
__switch_to
__schedule
schedule
schedule_preempt_disabled
__mutex_lock_slowpath
mutex_lock
devfreq_monitor_suspend
devfreq_simple_ondemand_handler
devfreq_suspend_device
ufshcd_gate_work
process_one_work
worker_thread
kthread
ret_from_fork

Workqueue: events ufshcd_ungate_work
__switch_to
__schedule
schedule
schedule_timeout
wait_for_common
wait_for_completion
flush_work
__cancel_work_timer
cancel_delayed_work_sync
ufshcd_ungate_work
process_one_work
worker_thread
kthread
ret_from_fork

This change fixes this deadlock by doing this in devfreq work (devfreq_wq):
Try cancelling clock gating work. If we are able to cancel gating work
or it wasn't scheduled, hold the clock reference count until scaling is
in progress. If gate work is already running in parallel, let's skip
the frequecy scaling at this time and it will be retried once next scaling
window expires.

Signed-off-by: Subhash Jadavani <subha...@codeaurora.org>
---
 drivers/scsi/ufs/ufshcd.c | 32 
 1 file changed, 32 insertions(+)

diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index 571a2f6..77700ee 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -6323,15 +6323,47 @@ static int ufshcd_devfreq_target(struct device *dev,
 {
int err = 0;
struct ufs_hba *hba = dev_get_drvdata(dev);
+   bool release_clk_hold = false;
+   unsigned long irq_flags;
 
if (!ufshcd_is_clkscaling_enabled(hba))
return -EINVAL;
 
+   spin_lock_irqsave(hba->host->host_lock, irq_flags);
+   if (ufshcd_eh_in_progress(hba)) {
+   spin_unlock_irqrestore(hba->host->host_lock, irq_flags);
+   return 0;
+   }
+
+   if (ufshcd_is_clkgating_allowed(hba) &&
+   (hba->clk_gating.state != CLKS_ON)) {
+   if (cancel_delayed_work(>clk_gating.gate_work)) {
+   /* hold the vote until the scaling work is completed */
+   hba->clk_gating.active_reqs++;
+   release_clk_hold = true;
+   hba->clk_gating.state = CLKS_ON;
+   } else {
+   /*
+* Clock gating work seems to be running in parallel
+* hence skip scaling work to avoid deadlock between
+* current scaling work and gating work.
+*/
+   spin_unlock_irqrestore(hba->host->host_lock, irq_flags);
+   return 0;
+   }
+   }
+   spin_unlock_irqrestore(hba->host->host_lock, irq_flags);
+
if (*freq == UINT_MAX)
err = ufshcd_scale_clks(hba, true);
else if (*freq == 0)
err = ufshcd_scale_clks(hba, false);
 
+   spin_lock_irqsave(hba->host->host_lock, irq_flags);
+   if (release_clk_hold)
+   __ufshcd_release(hba);
+   spin_unlock_irqrestore(hba->host->host_lock, irq_flags);
+
return err;
 }
 
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project



[PATCH v1 01/11] scsi: ufs: fix race between clock gating and devfreq scaling work

2016-10-17 Thread Subhash Jadavani
UFS devfreq clock scaling work may require clocks to be ON if it need to
execute some UFS commands hence it may request for clock hold before
issuing the command. But if UFS clock gating work is already running in
parallel, ungate work would end up waiting for the clock gating work to
finish and as clock gating work would also wait for the clock scaling work
to finish, we would enter in deadlock state. Here is the call trace during
this deadlock state:

Workqueue: devfreq_wq devfreq_monitor
__switch_to
__schedule
schedule
schedule_timeout
wait_for_common
wait_for_completion
flush_work
ufshcd_hold
ufshcd_send_uic_cmd
ufshcd_dme_get_attr
ufs_qcom_set_dme_vs_core_clk_ctrl_clear_div
ufs_qcom_clk_scale_notify
ufshcd_scale_clks
ufshcd_devfreq_target
update_devfreq
devfreq_monitor
process_one_work
worker_thread
kthread
ret_from_fork

Workqueue: events ufshcd_gate_work
__switch_to
__schedule
schedule
schedule_preempt_disabled
__mutex_lock_slowpath
mutex_lock
devfreq_monitor_suspend
devfreq_simple_ondemand_handler
devfreq_suspend_device
ufshcd_gate_work
process_one_work
worker_thread
kthread
ret_from_fork

Workqueue: events ufshcd_ungate_work
__switch_to
__schedule
schedule
schedule_timeout
wait_for_common
wait_for_completion
flush_work
__cancel_work_timer
cancel_delayed_work_sync
ufshcd_ungate_work
process_one_work
worker_thread
kthread
ret_from_fork

This change fixes this deadlock by doing this in devfreq work (devfreq_wq):
Try cancelling clock gating work. If we are able to cancel gating work
or it wasn't scheduled, hold the clock reference count until scaling is
in progress. If gate work is already running in parallel, let's skip
the frequecy scaling at this time and it will be retried once next scaling
window expires.

Signed-off-by: Subhash Jadavani 
---
 drivers/scsi/ufs/ufshcd.c | 32 
 1 file changed, 32 insertions(+)

diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index 571a2f6..77700ee 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -6323,15 +6323,47 @@ static int ufshcd_devfreq_target(struct device *dev,
 {
int err = 0;
struct ufs_hba *hba = dev_get_drvdata(dev);
+   bool release_clk_hold = false;
+   unsigned long irq_flags;
 
if (!ufshcd_is_clkscaling_enabled(hba))
return -EINVAL;
 
+   spin_lock_irqsave(hba->host->host_lock, irq_flags);
+   if (ufshcd_eh_in_progress(hba)) {
+   spin_unlock_irqrestore(hba->host->host_lock, irq_flags);
+   return 0;
+   }
+
+   if (ufshcd_is_clkgating_allowed(hba) &&
+   (hba->clk_gating.state != CLKS_ON)) {
+   if (cancel_delayed_work(>clk_gating.gate_work)) {
+   /* hold the vote until the scaling work is completed */
+   hba->clk_gating.active_reqs++;
+   release_clk_hold = true;
+   hba->clk_gating.state = CLKS_ON;
+   } else {
+   /*
+* Clock gating work seems to be running in parallel
+* hence skip scaling work to avoid deadlock between
+* current scaling work and gating work.
+*/
+   spin_unlock_irqrestore(hba->host->host_lock, irq_flags);
+   return 0;
+   }
+   }
+   spin_unlock_irqrestore(hba->host->host_lock, irq_flags);
+
if (*freq == UINT_MAX)
err = ufshcd_scale_clks(hba, true);
else if (*freq == 0)
err = ufshcd_scale_clks(hba, false);
 
+   spin_lock_irqsave(hba->host->host_lock, irq_flags);
+   if (release_clk_hold)
+   __ufshcd_release(hba);
+   spin_unlock_irqrestore(hba->host->host_lock, irq_flags);
+
return err;
 }
 
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project



Re: [PATCH] ufs: changing maintainer

2016-10-13 Thread Subhash Jadavani

On 2016-10-13 10:23, Joao Pinto wrote:

Signed-off-by: Joao Pinto 
---
 MAINTAINERS | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/MAINTAINERS b/MAINTAINERS
index 5ac91d8a..d9855b5 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -12084,7 +12084,8 @@ F:  Documentation/scsi/ufs.txt
 F: drivers/scsi/ufs/

 UNIVERSAL FLASH STORAGE HOST CONTROLLER DRIVER DWC HOOKS
-M: Joao Pinto 
+M: Manjunath M Bettegowda 
+M: Prabu Thangamuthu 
 L: linux-s...@vger.kernel.org
 S: Supported
 F: drivers/scsi/ufs/*dwc*


Looking at the commit text, it gives the impression that we are changing 
the maintainer for whole UFS driver.
Can you make it specific? May be the commit text header should be "ufs: 
changing maintainer for DWC"?


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


Re: [PATCH] ufs: changing maintainer

2016-10-13 Thread Subhash Jadavani

On 2016-10-13 10:23, Joao Pinto wrote:

Signed-off-by: Joao Pinto 
---
 MAINTAINERS | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/MAINTAINERS b/MAINTAINERS
index 5ac91d8a..d9855b5 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -12084,7 +12084,8 @@ F:  Documentation/scsi/ufs.txt
 F: drivers/scsi/ufs/

 UNIVERSAL FLASH STORAGE HOST CONTROLLER DRIVER DWC HOOKS
-M: Joao Pinto 
+M: Manjunath M Bettegowda 
+M: Prabu Thangamuthu 
 L: linux-s...@vger.kernel.org
 S: Supported
 F: drivers/scsi/ufs/*dwc*


Looking at the commit text, it gives the impression that we are changing 
the maintainer for whole UFS driver.
Can you make it specific? May be the commit text header should be "ufs: 
changing maintainer for DWC"?


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


[RESEND PATCH] scsi: ufs: fix race between clock gating and devfreq scaling work

2016-10-11 Thread Subhash Jadavani
UFS devfreq clock scaling work may require clocks to be ON if it need to
execute some UFS commands hence it may request for clock hold before
issuing the command. But if UFS clock gating work is already running in
parallel, ungate work would end up waiting for the clock gating work to
finish and as clock gating work would also wait for the clock scaling work
to finish, we would enter in deadlock state. Here is the call trace during
this deadlock state:

Workqueue: devfreq_wq devfreq_monitor
__switch_to
__schedule
schedule
schedule_timeout
wait_for_common
wait_for_completion
flush_work
ufshcd_hold
ufshcd_send_uic_cmd
ufshcd_dme_get_attr
ufs_qcom_set_dme_vs_core_clk_ctrl_clear_div
ufs_qcom_clk_scale_notify
ufshcd_scale_clks
ufshcd_devfreq_target
update_devfreq
devfreq_monitor
process_one_work
worker_thread
kthread
ret_from_fork

Workqueue: events ufshcd_gate_work
__switch_to
__schedule
schedule
schedule_preempt_disabled
__mutex_lock_slowpath
mutex_lock
devfreq_monitor_suspend
devfreq_simple_ondemand_handler
devfreq_suspend_device
ufshcd_gate_work
process_one_work
worker_thread
kthread
ret_from_fork

Workqueue: events ufshcd_ungate_work
__switch_to
__schedule
schedule
schedule_timeout
wait_for_common
wait_for_completion
flush_work
__cancel_work_timer
cancel_delayed_work_sync
ufshcd_ungate_work
process_one_work
worker_thread
kthread
ret_from_fork

This change fixes this deadlock by doing this in devfreq work (devfreq_wq):
Try cancelling clock gating work. If we are able to cancel gating work
or it wasn't scheduled, hold the clock reference count until scaling is
in progress. If gate work is already running in parallel, let's skip
the frequecy scaling at this time and it will be retried once next scaling
window expires.

Signed-off-by: Subhash Jadavani <subha...@codeaurora.org>
---
 drivers/scsi/ufs/ufshcd.c | 32 
 1 file changed, 32 insertions(+)

diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index 571a2f6..77700ee 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -6323,15 +6323,47 @@ static int ufshcd_devfreq_target(struct device *dev,
 {
int err = 0;
struct ufs_hba *hba = dev_get_drvdata(dev);
+   bool release_clk_hold = false;
+   unsigned long irq_flags;
 
if (!ufshcd_is_clkscaling_enabled(hba))
return -EINVAL;
 
+   spin_lock_irqsave(hba->host->host_lock, irq_flags);
+   if (ufshcd_eh_in_progress(hba)) {
+   spin_unlock_irqrestore(hba->host->host_lock, irq_flags);
+   return 0;
+   }
+
+   if (ufshcd_is_clkgating_allowed(hba) &&
+   (hba->clk_gating.state != CLKS_ON)) {
+   if (cancel_delayed_work(>clk_gating.gate_work)) {
+   /* hold the vote until the scaling work is completed */
+   hba->clk_gating.active_reqs++;
+   release_clk_hold = true;
+   hba->clk_gating.state = CLKS_ON;
+   } else {
+   /*
+* Clock gating work seems to be running in parallel
+* hence skip scaling work to avoid deadlock between
+* current scaling work and gating work.
+*/
+   spin_unlock_irqrestore(hba->host->host_lock, irq_flags);
+   return 0;
+   }
+   }
+   spin_unlock_irqrestore(hba->host->host_lock, irq_flags);
+
if (*freq == UINT_MAX)
err = ufshcd_scale_clks(hba, true);
else if (*freq == 0)
err = ufshcd_scale_clks(hba, false);
 
+   spin_lock_irqsave(hba->host->host_lock, irq_flags);
+   if (release_clk_hold)
+   __ufshcd_release(hba);
+   spin_unlock_irqrestore(hba->host->host_lock, irq_flags);
+
return err;
 }
 
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project



[RESEND PATCH] scsi: ufs: fix race between clock gating and devfreq scaling work

2016-10-11 Thread Subhash Jadavani
UFS devfreq clock scaling work may require clocks to be ON if it need to
execute some UFS commands hence it may request for clock hold before
issuing the command. But if UFS clock gating work is already running in
parallel, ungate work would end up waiting for the clock gating work to
finish and as clock gating work would also wait for the clock scaling work
to finish, we would enter in deadlock state. Here is the call trace during
this deadlock state:

Workqueue: devfreq_wq devfreq_monitor
__switch_to
__schedule
schedule
schedule_timeout
wait_for_common
wait_for_completion
flush_work
ufshcd_hold
ufshcd_send_uic_cmd
ufshcd_dme_get_attr
ufs_qcom_set_dme_vs_core_clk_ctrl_clear_div
ufs_qcom_clk_scale_notify
ufshcd_scale_clks
ufshcd_devfreq_target
update_devfreq
devfreq_monitor
process_one_work
worker_thread
kthread
ret_from_fork

Workqueue: events ufshcd_gate_work
__switch_to
__schedule
schedule
schedule_preempt_disabled
__mutex_lock_slowpath
mutex_lock
devfreq_monitor_suspend
devfreq_simple_ondemand_handler
devfreq_suspend_device
ufshcd_gate_work
process_one_work
worker_thread
kthread
ret_from_fork

Workqueue: events ufshcd_ungate_work
__switch_to
__schedule
schedule
schedule_timeout
wait_for_common
wait_for_completion
flush_work
__cancel_work_timer
cancel_delayed_work_sync
ufshcd_ungate_work
process_one_work
worker_thread
kthread
ret_from_fork

This change fixes this deadlock by doing this in devfreq work (devfreq_wq):
Try cancelling clock gating work. If we are able to cancel gating work
or it wasn't scheduled, hold the clock reference count until scaling is
in progress. If gate work is already running in parallel, let's skip
the frequecy scaling at this time and it will be retried once next scaling
window expires.

Signed-off-by: Subhash Jadavani 
---
 drivers/scsi/ufs/ufshcd.c | 32 
 1 file changed, 32 insertions(+)

diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index 571a2f6..77700ee 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -6323,15 +6323,47 @@ static int ufshcd_devfreq_target(struct device *dev,
 {
int err = 0;
struct ufs_hba *hba = dev_get_drvdata(dev);
+   bool release_clk_hold = false;
+   unsigned long irq_flags;
 
if (!ufshcd_is_clkscaling_enabled(hba))
return -EINVAL;
 
+   spin_lock_irqsave(hba->host->host_lock, irq_flags);
+   if (ufshcd_eh_in_progress(hba)) {
+   spin_unlock_irqrestore(hba->host->host_lock, irq_flags);
+   return 0;
+   }
+
+   if (ufshcd_is_clkgating_allowed(hba) &&
+   (hba->clk_gating.state != CLKS_ON)) {
+   if (cancel_delayed_work(>clk_gating.gate_work)) {
+   /* hold the vote until the scaling work is completed */
+   hba->clk_gating.active_reqs++;
+   release_clk_hold = true;
+   hba->clk_gating.state = CLKS_ON;
+   } else {
+   /*
+* Clock gating work seems to be running in parallel
+* hence skip scaling work to avoid deadlock between
+* current scaling work and gating work.
+*/
+   spin_unlock_irqrestore(hba->host->host_lock, irq_flags);
+   return 0;
+   }
+   }
+   spin_unlock_irqrestore(hba->host->host_lock, irq_flags);
+
if (*freq == UINT_MAX)
err = ufshcd_scale_clks(hba, true);
else if (*freq == 0)
err = ufshcd_scale_clks(hba, false);
 
+   spin_lock_irqsave(hba->host->host_lock, irq_flags);
+   if (release_clk_hold)
+   __ufshcd_release(hba);
+   spin_unlock_irqrestore(hba->host->host_lock, irq_flags);
+
return err;
 }
 
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project



[RESEND PATCH v3] scsi: ufshcd: fix possible unclocked register access

2016-10-06 Thread Subhash Jadavani
Vendor specific setup_clocks callback may require the clocks managed
by ufshcd driver to be ON. So if the vendor specific setup_clocks callback
is called while the required clocks are turned off, it could result into
unclocked register access.

To prevent possible unclock register access, this change adds one more
argument to setup_clocks callback to let it know whether it is called
pre/post the clock changes by core driver.

Signed-off-by: Subhash Jadavani <subha...@codeaurora.org>
---
Changes from v2:
* Added one more argument to setup_clocks callback, this should address
  Kiwoong Kim's comments on v2.

Changes from v1:
* Don't call ufshcd_vops_setup_clocks() again for clock off
---
 drivers/scsi/ufs/ufs-qcom.c | 10 ++
 drivers/scsi/ufs/ufshcd.c   | 17 -
 drivers/scsi/ufs/ufshcd.h   |  8 +---
 3 files changed, 19 insertions(+), 16 deletions(-)

diff --git a/drivers/scsi/ufs/ufs-qcom.c b/drivers/scsi/ufs/ufs-qcom.c
index 3aedf73..3c4f602 100644
--- a/drivers/scsi/ufs/ufs-qcom.c
+++ b/drivers/scsi/ufs/ufs-qcom.c
@@ -1094,10 +1094,12 @@ static void ufs_qcom_set_caps(struct ufs_hba *hba)
  * ufs_qcom_setup_clocks - enables/disable clocks
  * @hba: host controller instance
  * @on: If true, enable clocks else disable them.
+ * @status: PRE_CHANGE or POST_CHANGE notify
  *
  * Returns 0 on success, non-zero on failure.
  */
-static int ufs_qcom_setup_clocks(struct ufs_hba *hba, bool on)
+static int ufs_qcom_setup_clocks(struct ufs_hba *hba, bool on,
+enum ufs_notify_change_status status)
 {
struct ufs_qcom_host *host = ufshcd_get_variant(hba);
int err;
@@ -,7 +1113,7 @@ static int ufs_qcom_setup_clocks(struct ufs_hba *hba, 
bool on)
if (!host)
return 0;
 
-   if (on) {
+   if (on && (status == POST_CHANGE)) {
err = ufs_qcom_phy_enable_iface_clk(host->generic_phy);
if (err)
goto out;
@@ -1130,7 +1132,7 @@ static int ufs_qcom_setup_clocks(struct ufs_hba *hba, 
bool on)
if (vote == host->bus_vote.min_bw_vote)
ufs_qcom_update_bus_bw_vote(host);
 
-   } else {
+   } else if (!on && (status == PRE_CHANGE)) {
 
/* M-PHY RMMI interface clocks can be turned off */
ufs_qcom_phy_disable_iface_clk(host->generic_phy);
@@ -1254,7 +1256,7 @@ static int ufs_qcom_init(struct ufs_hba *hba)
ufs_qcom_set_caps(hba);
ufs_qcom_advertise_quirks(hba);
 
-   ufs_qcom_setup_clocks(hba, true);
+   ufs_qcom_setup_clocks(hba, true, POST_CHANGE);
 
if (hba->dev->id < MAX_UFS_QCOM_HOSTS)
ufs_qcom_hosts[hba->dev->id] = host;
diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index 05c7456..571a2f6 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -5389,6 +5389,10 @@ static int __ufshcd_setup_clocks(struct ufs_hba *hba, 
bool on,
if (!head || list_empty(head))
goto out;
 
+   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)) {
if (skip_ref_clk && !strcmp(clki->name, "ref_clk"))
@@ -5410,7 +5414,10 @@ static int __ufshcd_setup_clocks(struct ufs_hba *hba, 
bool on,
}
}
 
-   ret = ufshcd_vops_setup_clocks(hba, on);
+   ret = ufshcd_vops_setup_clocks(hba, on, POST_CHANGE);
+   if (ret)
+   return ret;
+
 out:
if (ret) {
list_for_each_entry(clki, head, list) {
@@ -5500,8 +5507,6 @@ static void ufshcd_variant_hba_exit(struct ufs_hba *hba)
if (!hba->vops)
return;
 
-   ufshcd_vops_setup_clocks(hba, false);
-
ufshcd_vops_setup_regulators(hba, false);
 
ufshcd_vops_exit(hba);
@@ -5905,10 +5910,6 @@ disable_clks:
if (ret)
goto set_link_active;
 
-   ret = ufshcd_vops_setup_clocks(hba, false);
-   if (ret)
-   goto vops_resume;
-
if (!ufshcd_is_link_active(hba))
ufshcd_setup_clocks(hba, false);
else
@@ -5925,8 +5926,6 @@ disable_clks:
ufshcd_hba_vreg_set_lpm(hba);
goto out;
 
-vops_resume:
-   ufshcd_vops_resume(hba, pm_op);
 set_link_active:
ufshcd_vreg_set_hpm(hba);
if (ufshcd_is_link_hibern8(hba) && !ufshcd_uic_hibern8_exit(hba))
diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h
index 430bef1..afff7f4 100644
--- a/drivers/scsi/ufs/ufshcd.h
+++ b/drivers/scsi/ufs/ufshcd.h
@@ -273,7 +273,8 @@ struct ufs_hba_variant_ops {
u32 (*get_ufs_hci_version)(struct ufs_hba *);
int (*clk_scale_notify)(struct ufs_hba *, bool,
enum ufs_notify_cha

[RESEND PATCH v3] scsi: ufshcd: fix possible unclocked register access

2016-10-06 Thread Subhash Jadavani
Vendor specific setup_clocks callback may require the clocks managed
by ufshcd driver to be ON. So if the vendor specific setup_clocks callback
is called while the required clocks are turned off, it could result into
unclocked register access.

To prevent possible unclock register access, this change adds one more
argument to setup_clocks callback to let it know whether it is called
pre/post the clock changes by core driver.

Signed-off-by: Subhash Jadavani 
---
Changes from v2:
* Added one more argument to setup_clocks callback, this should address
  Kiwoong Kim's comments on v2.

Changes from v1:
* Don't call ufshcd_vops_setup_clocks() again for clock off
---
 drivers/scsi/ufs/ufs-qcom.c | 10 ++
 drivers/scsi/ufs/ufshcd.c   | 17 -
 drivers/scsi/ufs/ufshcd.h   |  8 +---
 3 files changed, 19 insertions(+), 16 deletions(-)

diff --git a/drivers/scsi/ufs/ufs-qcom.c b/drivers/scsi/ufs/ufs-qcom.c
index 3aedf73..3c4f602 100644
--- a/drivers/scsi/ufs/ufs-qcom.c
+++ b/drivers/scsi/ufs/ufs-qcom.c
@@ -1094,10 +1094,12 @@ static void ufs_qcom_set_caps(struct ufs_hba *hba)
  * ufs_qcom_setup_clocks - enables/disable clocks
  * @hba: host controller instance
  * @on: If true, enable clocks else disable them.
+ * @status: PRE_CHANGE or POST_CHANGE notify
  *
  * Returns 0 on success, non-zero on failure.
  */
-static int ufs_qcom_setup_clocks(struct ufs_hba *hba, bool on)
+static int ufs_qcom_setup_clocks(struct ufs_hba *hba, bool on,
+enum ufs_notify_change_status status)
 {
struct ufs_qcom_host *host = ufshcd_get_variant(hba);
int err;
@@ -,7 +1113,7 @@ static int ufs_qcom_setup_clocks(struct ufs_hba *hba, 
bool on)
if (!host)
return 0;
 
-   if (on) {
+   if (on && (status == POST_CHANGE)) {
err = ufs_qcom_phy_enable_iface_clk(host->generic_phy);
if (err)
goto out;
@@ -1130,7 +1132,7 @@ static int ufs_qcom_setup_clocks(struct ufs_hba *hba, 
bool on)
if (vote == host->bus_vote.min_bw_vote)
ufs_qcom_update_bus_bw_vote(host);
 
-   } else {
+   } else if (!on && (status == PRE_CHANGE)) {
 
/* M-PHY RMMI interface clocks can be turned off */
ufs_qcom_phy_disable_iface_clk(host->generic_phy);
@@ -1254,7 +1256,7 @@ static int ufs_qcom_init(struct ufs_hba *hba)
ufs_qcom_set_caps(hba);
ufs_qcom_advertise_quirks(hba);
 
-   ufs_qcom_setup_clocks(hba, true);
+   ufs_qcom_setup_clocks(hba, true, POST_CHANGE);
 
if (hba->dev->id < MAX_UFS_QCOM_HOSTS)
ufs_qcom_hosts[hba->dev->id] = host;
diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index 05c7456..571a2f6 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -5389,6 +5389,10 @@ static int __ufshcd_setup_clocks(struct ufs_hba *hba, 
bool on,
if (!head || list_empty(head))
goto out;
 
+   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)) {
if (skip_ref_clk && !strcmp(clki->name, "ref_clk"))
@@ -5410,7 +5414,10 @@ static int __ufshcd_setup_clocks(struct ufs_hba *hba, 
bool on,
}
}
 
-   ret = ufshcd_vops_setup_clocks(hba, on);
+   ret = ufshcd_vops_setup_clocks(hba, on, POST_CHANGE);
+   if (ret)
+   return ret;
+
 out:
if (ret) {
list_for_each_entry(clki, head, list) {
@@ -5500,8 +5507,6 @@ static void ufshcd_variant_hba_exit(struct ufs_hba *hba)
if (!hba->vops)
return;
 
-   ufshcd_vops_setup_clocks(hba, false);
-
ufshcd_vops_setup_regulators(hba, false);
 
ufshcd_vops_exit(hba);
@@ -5905,10 +5910,6 @@ disable_clks:
if (ret)
goto set_link_active;
 
-   ret = ufshcd_vops_setup_clocks(hba, false);
-   if (ret)
-   goto vops_resume;
-
if (!ufshcd_is_link_active(hba))
ufshcd_setup_clocks(hba, false);
else
@@ -5925,8 +5926,6 @@ disable_clks:
ufshcd_hba_vreg_set_lpm(hba);
goto out;
 
-vops_resume:
-   ufshcd_vops_resume(hba, pm_op);
 set_link_active:
ufshcd_vreg_set_hpm(hba);
if (ufshcd_is_link_hibern8(hba) && !ufshcd_uic_hibern8_exit(hba))
diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h
index 430bef1..afff7f4 100644
--- a/drivers/scsi/ufs/ufshcd.h
+++ b/drivers/scsi/ufs/ufshcd.h
@@ -273,7 +273,8 @@ struct ufs_hba_variant_ops {
u32 (*get_ufs_hci_version)(struct ufs_hba *);
int (*clk_scale_notify)(struct ufs_hba *, bool,
enum ufs_notify_change_status);
-   int (*setup_cloc

[PATCH v3] scsi: ufshcd: fix possible unclocked register access

2016-10-06 Thread Subhash Jadavani
Vendor specific setup_clocks callback may require the clocks managed
by ufshcd driver to be ON. So if the vendor specific setup_clocks callback
is called while the required clocks are turned off, it could result into
unclocked register access.

To prevent possible unclock register access, this change adds one more
argument to setup_clocks callback to let it know whether it is called
pre/post the clock changes by core driver.

Signed-off-by: Subhash Jadavani <subha...@codeaurora.org>
---
 drivers/scsi/ufs/ufs-qcom.c | 10 ++
 drivers/scsi/ufs/ufshcd.c   | 17 -
 drivers/scsi/ufs/ufshcd.h   |  8 +---
 3 files changed, 19 insertions(+), 16 deletions(-)

diff --git a/drivers/scsi/ufs/ufs-qcom.c b/drivers/scsi/ufs/ufs-qcom.c
index 3aedf73..3c4f602 100644
--- a/drivers/scsi/ufs/ufs-qcom.c
+++ b/drivers/scsi/ufs/ufs-qcom.c
@@ -1094,10 +1094,12 @@ static void ufs_qcom_set_caps(struct ufs_hba *hba)
  * ufs_qcom_setup_clocks - enables/disable clocks
  * @hba: host controller instance
  * @on: If true, enable clocks else disable them.
+ * @status: PRE_CHANGE or POST_CHANGE notify
  *
  * Returns 0 on success, non-zero on failure.
  */
-static int ufs_qcom_setup_clocks(struct ufs_hba *hba, bool on)
+static int ufs_qcom_setup_clocks(struct ufs_hba *hba, bool on,
+enum ufs_notify_change_status status)
 {
struct ufs_qcom_host *host = ufshcd_get_variant(hba);
int err;
@@ -,7 +1113,7 @@ static int ufs_qcom_setup_clocks(struct ufs_hba *hba, 
bool on)
if (!host)
return 0;
 
-   if (on) {
+   if (on && (status == POST_CHANGE)) {
err = ufs_qcom_phy_enable_iface_clk(host->generic_phy);
if (err)
goto out;
@@ -1130,7 +1132,7 @@ static int ufs_qcom_setup_clocks(struct ufs_hba *hba, 
bool on)
if (vote == host->bus_vote.min_bw_vote)
ufs_qcom_update_bus_bw_vote(host);
 
-   } else {
+   } else if (!on && (status == PRE_CHANGE)) {
 
/* M-PHY RMMI interface clocks can be turned off */
ufs_qcom_phy_disable_iface_clk(host->generic_phy);
@@ -1254,7 +1256,7 @@ static int ufs_qcom_init(struct ufs_hba *hba)
ufs_qcom_set_caps(hba);
ufs_qcom_advertise_quirks(hba);
 
-   ufs_qcom_setup_clocks(hba, true);
+   ufs_qcom_setup_clocks(hba, true, POST_CHANGE);
 
if (hba->dev->id < MAX_UFS_QCOM_HOSTS)
ufs_qcom_hosts[hba->dev->id] = host;
diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index 05c7456..571a2f6 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -5389,6 +5389,10 @@ static int __ufshcd_setup_clocks(struct ufs_hba *hba, 
bool on,
if (!head || list_empty(head))
goto out;
 
+   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)) {
if (skip_ref_clk && !strcmp(clki->name, "ref_clk"))
@@ -5410,7 +5414,10 @@ static int __ufshcd_setup_clocks(struct ufs_hba *hba, 
bool on,
}
}
 
-   ret = ufshcd_vops_setup_clocks(hba, on);
+   ret = ufshcd_vops_setup_clocks(hba, on, POST_CHANGE);
+   if (ret)
+   return ret;
+
 out:
if (ret) {
list_for_each_entry(clki, head, list) {
@@ -5500,8 +5507,6 @@ static void ufshcd_variant_hba_exit(struct ufs_hba *hba)
if (!hba->vops)
return;
 
-   ufshcd_vops_setup_clocks(hba, false);
-
ufshcd_vops_setup_regulators(hba, false);
 
ufshcd_vops_exit(hba);
@@ -5905,10 +5910,6 @@ disable_clks:
if (ret)
goto set_link_active;
 
-   ret = ufshcd_vops_setup_clocks(hba, false);
-   if (ret)
-   goto vops_resume;
-
if (!ufshcd_is_link_active(hba))
ufshcd_setup_clocks(hba, false);
else
@@ -5925,8 +5926,6 @@ disable_clks:
ufshcd_hba_vreg_set_lpm(hba);
goto out;
 
-vops_resume:
-   ufshcd_vops_resume(hba, pm_op);
 set_link_active:
ufshcd_vreg_set_hpm(hba);
if (ufshcd_is_link_hibern8(hba) && !ufshcd_uic_hibern8_exit(hba))
diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h
index 430bef1..afff7f4 100644
--- a/drivers/scsi/ufs/ufshcd.h
+++ b/drivers/scsi/ufs/ufshcd.h
@@ -273,7 +273,8 @@ struct ufs_hba_variant_ops {
u32 (*get_ufs_hci_version)(struct ufs_hba *);
int (*clk_scale_notify)(struct ufs_hba *, bool,
enum ufs_notify_change_status);
-   int (*setup_clocks)(struct ufs_hba *, bool);
+   int (*setup_clocks)(struct ufs_hba *, bool,
+   enum ufs_notify_change_status);
int (*setup

[PATCH v3] scsi: ufshcd: fix possible unclocked register access

2016-10-06 Thread Subhash Jadavani
Vendor specific setup_clocks callback may require the clocks managed
by ufshcd driver to be ON. So if the vendor specific setup_clocks callback
is called while the required clocks are turned off, it could result into
unclocked register access.

To prevent possible unclock register access, this change adds one more
argument to setup_clocks callback to let it know whether it is called
pre/post the clock changes by core driver.

Signed-off-by: Subhash Jadavani 
---
 drivers/scsi/ufs/ufs-qcom.c | 10 ++
 drivers/scsi/ufs/ufshcd.c   | 17 -
 drivers/scsi/ufs/ufshcd.h   |  8 +---
 3 files changed, 19 insertions(+), 16 deletions(-)

diff --git a/drivers/scsi/ufs/ufs-qcom.c b/drivers/scsi/ufs/ufs-qcom.c
index 3aedf73..3c4f602 100644
--- a/drivers/scsi/ufs/ufs-qcom.c
+++ b/drivers/scsi/ufs/ufs-qcom.c
@@ -1094,10 +1094,12 @@ static void ufs_qcom_set_caps(struct ufs_hba *hba)
  * ufs_qcom_setup_clocks - enables/disable clocks
  * @hba: host controller instance
  * @on: If true, enable clocks else disable them.
+ * @status: PRE_CHANGE or POST_CHANGE notify
  *
  * Returns 0 on success, non-zero on failure.
  */
-static int ufs_qcom_setup_clocks(struct ufs_hba *hba, bool on)
+static int ufs_qcom_setup_clocks(struct ufs_hba *hba, bool on,
+enum ufs_notify_change_status status)
 {
struct ufs_qcom_host *host = ufshcd_get_variant(hba);
int err;
@@ -,7 +1113,7 @@ static int ufs_qcom_setup_clocks(struct ufs_hba *hba, 
bool on)
if (!host)
return 0;
 
-   if (on) {
+   if (on && (status == POST_CHANGE)) {
err = ufs_qcom_phy_enable_iface_clk(host->generic_phy);
if (err)
goto out;
@@ -1130,7 +1132,7 @@ static int ufs_qcom_setup_clocks(struct ufs_hba *hba, 
bool on)
if (vote == host->bus_vote.min_bw_vote)
ufs_qcom_update_bus_bw_vote(host);
 
-   } else {
+   } else if (!on && (status == PRE_CHANGE)) {
 
/* M-PHY RMMI interface clocks can be turned off */
ufs_qcom_phy_disable_iface_clk(host->generic_phy);
@@ -1254,7 +1256,7 @@ static int ufs_qcom_init(struct ufs_hba *hba)
ufs_qcom_set_caps(hba);
ufs_qcom_advertise_quirks(hba);
 
-   ufs_qcom_setup_clocks(hba, true);
+   ufs_qcom_setup_clocks(hba, true, POST_CHANGE);
 
if (hba->dev->id < MAX_UFS_QCOM_HOSTS)
ufs_qcom_hosts[hba->dev->id] = host;
diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index 05c7456..571a2f6 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -5389,6 +5389,10 @@ static int __ufshcd_setup_clocks(struct ufs_hba *hba, 
bool on,
if (!head || list_empty(head))
goto out;
 
+   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)) {
if (skip_ref_clk && !strcmp(clki->name, "ref_clk"))
@@ -5410,7 +5414,10 @@ static int __ufshcd_setup_clocks(struct ufs_hba *hba, 
bool on,
}
}
 
-   ret = ufshcd_vops_setup_clocks(hba, on);
+   ret = ufshcd_vops_setup_clocks(hba, on, POST_CHANGE);
+   if (ret)
+   return ret;
+
 out:
if (ret) {
list_for_each_entry(clki, head, list) {
@@ -5500,8 +5507,6 @@ static void ufshcd_variant_hba_exit(struct ufs_hba *hba)
if (!hba->vops)
return;
 
-   ufshcd_vops_setup_clocks(hba, false);
-
ufshcd_vops_setup_regulators(hba, false);
 
ufshcd_vops_exit(hba);
@@ -5905,10 +5910,6 @@ disable_clks:
if (ret)
goto set_link_active;
 
-   ret = ufshcd_vops_setup_clocks(hba, false);
-   if (ret)
-   goto vops_resume;
-
if (!ufshcd_is_link_active(hba))
ufshcd_setup_clocks(hba, false);
else
@@ -5925,8 +5926,6 @@ disable_clks:
ufshcd_hba_vreg_set_lpm(hba);
goto out;
 
-vops_resume:
-   ufshcd_vops_resume(hba, pm_op);
 set_link_active:
ufshcd_vreg_set_hpm(hba);
if (ufshcd_is_link_hibern8(hba) && !ufshcd_uic_hibern8_exit(hba))
diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h
index 430bef1..afff7f4 100644
--- a/drivers/scsi/ufs/ufshcd.h
+++ b/drivers/scsi/ufs/ufshcd.h
@@ -273,7 +273,8 @@ struct ufs_hba_variant_ops {
u32 (*get_ufs_hci_version)(struct ufs_hba *);
int (*clk_scale_notify)(struct ufs_hba *, bool,
enum ufs_notify_change_status);
-   int (*setup_clocks)(struct ufs_hba *, bool);
+   int (*setup_clocks)(struct ufs_hba *, bool,
+   enum ufs_notify_change_status);
int (*setup_regulators)(s

Re: [PATCH v2] scsi: ufshcd: fix possible unclocked register access

2016-10-06 Thread Subhash Jadavani

On 2016-10-06 18:16, Kiwoong Kim wrote:

Hi, Subhash.


Thanks Kim for the response.

On 2016-10-06 03:28, Kiwoong Kim wrote:
> Hi, Subhash.
>
> Some UFS host controllers may need to call the vendor specific
> callback before and after controlling by clock control framework,
> regardless of whether available clocks are turned on or off.

Are you suggesting to call ufshcd_vops_setup_clocks() 2 times, one 
before
the on/off by ufshcd core driver and one after the on/off? If yes, 
then we

also have add 3rd argument clarifying if this is PRE_CHANGE or

POST_CHANGE.


>
> Is there any special reason to limit to invoke the callback
> only when the clocks are turned on or not?
>
> Besides, the callback is acknowledged from core driver
> because 2nd argument is whether the clocks are turned on or not.
>
> If you have any other idea, please let me know.

This is my suggestion:
1. Add 3rd argument to setup_clocks ops to let the vendor callback
function know if this is called PRE_CHANGE or POST_CHANGE.
2. If #1 is in place, call setup_clocks 2 times, one with PRE_CHANGE
argument before making any clock changes in core driver, 2nd with
POST_CHANGE argument after making the clock changes to core driver.


Yes, that's exactly the same what I mean.


Thanks, Will send out new version adding that.



Thanks




Let me know if this would work or not.

Thanks,
Subhash

>
> Thanks
> Regards
>
>> Vendor specific setup_clocks callback may require the clocks managed
>> by ufshcd driver to be ON. So if the vendor specific setup_clocks
>> callback
>> is called while the required clocks are turned off, it could result
>> into
>> unclocked register access.
>>
>> To prevent possible unclock register access, this change makes sure
>> that
>> required clocks remain enabled before calling into vendor specific
>> setup_clocks callback.
>>
>> Signed-off-by: Subhash Jadavani <subha...@codeaurora.org>
>> ---
>> Changes from v2:
>> * Don't call ufshcd_vops_setup_clocks() again for clock off
>> ---
>>  drivers/scsi/ufs/ufshcd.c | 22 +-
>>  1 file changed, 21 insertions(+), 1 deletion(-)
>>
>> diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
>> index 05c7456..c1a77d3 100644
>> --- a/drivers/scsi/ufs/ufshcd.c
>> +++ b/drivers/scsi/ufs/ufshcd.c
>> @@ -5389,6 +5389,17 @@ static int __ufshcd_setup_clocks(struct ufs_hba
>> *hba, bool on,
>>if (!head || list_empty(head))
>>goto out;
>>
>> +  /*
>> +   * 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);
>> +  if (ret)
>> +  return ret;
>> +  }
>> +
>>list_for_each_entry(clki, head, list) {
>>if (!IS_ERR_OR_NULL(clki->clk)) {
>>if (skip_ref_clk && !strcmp(clki->name, "ref_clk"))
>> @@ -5410,7 +5421,16 @@ static int __ufshcd_setup_clocks(struct ufs_hba
>> *hba, bool on,
>>}
>>}
>>
>> -  ret = ufshcd_vops_setup_clocks(hba, on);
>> +  /*
>> +   * 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);
>> +  if (ret)
>> +  return ret;
>> +  }
>>  out:
>>if (ret) {
>>list_for_each_entry(clki, head, list) {
>> --
>> The Qualcomm Innovation Center, Inc. is a member of the Code Aurora
>> Forum,
>> a Linux Foundation Collaborative Project
>>
>> --
>> To unsubscribe from this list: send the line "unsubscribe linux-scsi"
>> in
>> the body of a message to majord...@vger.kernel.org
>> More majordomo info at  http://vger.kernel.org/majordomo-info.html
>
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-scsi"
> in
> the body of a message to majord...@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

--
The Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
a Linux Foundation Collaborative Project
--
To unsubscribe from this list: send the line "unsubscribe linux-scsi" 
in

the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html



--
To unsubscribe from this list: send the line "unsubscribe linux-scsi" 
in

the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


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


Re: [PATCH v2] scsi: ufshcd: fix possible unclocked register access

2016-10-06 Thread Subhash Jadavani

On 2016-10-06 18:16, Kiwoong Kim wrote:

Hi, Subhash.


Thanks Kim for the response.

On 2016-10-06 03:28, Kiwoong Kim wrote:
> Hi, Subhash.
>
> Some UFS host controllers may need to call the vendor specific
> callback before and after controlling by clock control framework,
> regardless of whether available clocks are turned on or off.

Are you suggesting to call ufshcd_vops_setup_clocks() 2 times, one 
before
the on/off by ufshcd core driver and one after the on/off? If yes, 
then we

also have add 3rd argument clarifying if this is PRE_CHANGE or

POST_CHANGE.


>
> Is there any special reason to limit to invoke the callback
> only when the clocks are turned on or not?
>
> Besides, the callback is acknowledged from core driver
> because 2nd argument is whether the clocks are turned on or not.
>
> If you have any other idea, please let me know.

This is my suggestion:
1. Add 3rd argument to setup_clocks ops to let the vendor callback
function know if this is called PRE_CHANGE or POST_CHANGE.
2. If #1 is in place, call setup_clocks 2 times, one with PRE_CHANGE
argument before making any clock changes in core driver, 2nd with
POST_CHANGE argument after making the clock changes to core driver.


Yes, that's exactly the same what I mean.


Thanks, Will send out new version adding that.



Thanks




Let me know if this would work or not.

Thanks,
Subhash

>
> Thanks
> Regards
>
>> Vendor specific setup_clocks callback may require the clocks managed
>> by ufshcd driver to be ON. So if the vendor specific setup_clocks
>> callback
>> is called while the required clocks are turned off, it could result
>> into
>> unclocked register access.
>>
>> To prevent possible unclock register access, this change makes sure
>> that
>> required clocks remain enabled before calling into vendor specific
>> setup_clocks callback.
>>
>> Signed-off-by: Subhash Jadavani 
>> ---
>> Changes from v2:
>> * Don't call ufshcd_vops_setup_clocks() again for clock off
>> ---
>>  drivers/scsi/ufs/ufshcd.c | 22 +-
>>  1 file changed, 21 insertions(+), 1 deletion(-)
>>
>> diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
>> index 05c7456..c1a77d3 100644
>> --- a/drivers/scsi/ufs/ufshcd.c
>> +++ b/drivers/scsi/ufs/ufshcd.c
>> @@ -5389,6 +5389,17 @@ static int __ufshcd_setup_clocks(struct ufs_hba
>> *hba, bool on,
>>if (!head || list_empty(head))
>>goto out;
>>
>> +  /*
>> +   * 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);
>> +  if (ret)
>> +  return ret;
>> +  }
>> +
>>list_for_each_entry(clki, head, list) {
>>if (!IS_ERR_OR_NULL(clki->clk)) {
>>if (skip_ref_clk && !strcmp(clki->name, "ref_clk"))
>> @@ -5410,7 +5421,16 @@ static int __ufshcd_setup_clocks(struct ufs_hba
>> *hba, bool on,
>>}
>>}
>>
>> -  ret = ufshcd_vops_setup_clocks(hba, on);
>> +  /*
>> +   * 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);
>> +  if (ret)
>> +  return ret;
>> +  }
>>  out:
>>if (ret) {
>>list_for_each_entry(clki, head, list) {
>> --
>> The Qualcomm Innovation Center, Inc. is a member of the Code Aurora
>> Forum,
>> a Linux Foundation Collaborative Project
>>
>> --
>> To unsubscribe from this list: send the line "unsubscribe linux-scsi"
>> in
>> the body of a message to majord...@vger.kernel.org
>> More majordomo info at  http://vger.kernel.org/majordomo-info.html
>
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-scsi"
> in
> the body of a message to majord...@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

--
The Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
a Linux Foundation Collaborative Project
--
To unsubscribe from this list: send the line "unsubscribe linux-scsi" 
in

the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html



--
To unsubscribe from this list: send the line "unsubscribe linux-scsi" 
in

the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


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


[PATCH] scsi: ufs: fix race between clock gating and devfreq scaling work

2016-10-06 Thread Subhash Jadavani
UFS devfreq clock scaling work may require clocks to be ON if it need to
execute some UFS commands hence it may request for clock hold before
issuing the command. But if UFS clock gating work is already running in
parallel, ungate work would end up waiting for the clock gating work to
finish and as clock gating work would also wait for the clock scaling work
to finish, we would enter in deadlock state. Here is the call trace during
this deadlock state:

Workqueue: devfreq_wq devfreq_monitor
__switch_to
__schedule
schedule
schedule_timeout
wait_for_common
wait_for_completion
flush_work
ufshcd_hold
ufshcd_send_uic_cmd
ufshcd_dme_get_attr
ufs_qcom_set_dme_vs_core_clk_ctrl_clear_div
ufs_qcom_clk_scale_notify
ufshcd_scale_clks
ufshcd_devfreq_target
update_devfreq
devfreq_monitor
process_one_work
worker_thread
kthread
ret_from_fork

Workqueue: events ufshcd_gate_work
__switch_to
__schedule
schedule
schedule_preempt_disabled
__mutex_lock_slowpath
mutex_lock
devfreq_monitor_suspend
devfreq_simple_ondemand_handler
devfreq_suspend_device
ufshcd_gate_work
process_one_work
worker_thread
kthread
ret_from_fork

Workqueue: events ufshcd_ungate_work
__switch_to
__schedule
schedule
schedule_timeout
wait_for_common
wait_for_completion
flush_work
__cancel_work_timer
cancel_delayed_work_sync
ufshcd_ungate_work
process_one_work
worker_thread
kthread
ret_from_fork

This change fixes this deadlock by doing this in devfreq work (devfreq_wq):
Try cancelling clock gating work. If we are able to cancel gating work
or it wasn't scheduled, hold the clock reference count until scaling is
in progress. If gate work is already running in parallel, let's skip
the frequecy scaling at this time and it will be retried once next scaling
window expires.

Signed-off-by: Subhash Jadavani <subha...@codeaurora.org>
---
 drivers/scsi/ufs/ufshcd.c | 32 
 1 file changed, 32 insertions(+)

diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index 05c7456..4011887 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -6324,15 +6324,47 @@ static int ufshcd_devfreq_target(struct device *dev,
 {
int err = 0;
struct ufs_hba *hba = dev_get_drvdata(dev);
+   bool release_clk_hold = false;
+   unsigned long irq_flags;
 
if (!ufshcd_is_clkscaling_enabled(hba))
return -EINVAL;
 
+   spin_lock_irqsave(hba->host->host_lock, irq_flags);
+   if (ufshcd_eh_in_progress(hba)) {
+   spin_unlock_irqrestore(hba->host->host_lock, irq_flags);
+   return 0;
+   }
+
+   if (ufshcd_is_clkgating_allowed(hba) &&
+   (hba->clk_gating.state != CLKS_ON)) {
+   if (cancel_delayed_work(>clk_gating.gate_work)) {
+   /* hold the vote until the scaling work is completed */
+   hba->clk_gating.active_reqs++;
+   release_clk_hold = true;
+   hba->clk_gating.state = CLKS_ON;
+   } else {
+   /*
+* Clock gating work seems to be running in parallel
+* hence skip scaling work to avoid deadlock between
+* current scaling work and gating work.
+*/
+   spin_unlock_irqrestore(hba->host->host_lock, irq_flags);
+   return 0;
+   }
+   }
+   spin_unlock_irqrestore(hba->host->host_lock, irq_flags);
+
if (*freq == UINT_MAX)
err = ufshcd_scale_clks(hba, true);
else if (*freq == 0)
err = ufshcd_scale_clks(hba, false);
 
+   spin_lock_irqsave(hba->host->host_lock, irq_flags);
+   if (release_clk_hold)
+   __ufshcd_release(hba);
+   spin_unlock_irqrestore(hba->host->host_lock, irq_flags);
+
return err;
 }
 
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project



[PATCH] scsi: ufs: fix race between clock gating and devfreq scaling work

2016-10-06 Thread Subhash Jadavani
UFS devfreq clock scaling work may require clocks to be ON if it need to
execute some UFS commands hence it may request for clock hold before
issuing the command. But if UFS clock gating work is already running in
parallel, ungate work would end up waiting for the clock gating work to
finish and as clock gating work would also wait for the clock scaling work
to finish, we would enter in deadlock state. Here is the call trace during
this deadlock state:

Workqueue: devfreq_wq devfreq_monitor
__switch_to
__schedule
schedule
schedule_timeout
wait_for_common
wait_for_completion
flush_work
ufshcd_hold
ufshcd_send_uic_cmd
ufshcd_dme_get_attr
ufs_qcom_set_dme_vs_core_clk_ctrl_clear_div
ufs_qcom_clk_scale_notify
ufshcd_scale_clks
ufshcd_devfreq_target
update_devfreq
devfreq_monitor
process_one_work
worker_thread
kthread
ret_from_fork

Workqueue: events ufshcd_gate_work
__switch_to
__schedule
schedule
schedule_preempt_disabled
__mutex_lock_slowpath
mutex_lock
devfreq_monitor_suspend
devfreq_simple_ondemand_handler
devfreq_suspend_device
ufshcd_gate_work
process_one_work
worker_thread
kthread
ret_from_fork

Workqueue: events ufshcd_ungate_work
__switch_to
__schedule
schedule
schedule_timeout
wait_for_common
wait_for_completion
flush_work
__cancel_work_timer
cancel_delayed_work_sync
ufshcd_ungate_work
process_one_work
worker_thread
kthread
ret_from_fork

This change fixes this deadlock by doing this in devfreq work (devfreq_wq):
Try cancelling clock gating work. If we are able to cancel gating work
or it wasn't scheduled, hold the clock reference count until scaling is
in progress. If gate work is already running in parallel, let's skip
the frequecy scaling at this time and it will be retried once next scaling
window expires.

Signed-off-by: Subhash Jadavani 
---
 drivers/scsi/ufs/ufshcd.c | 32 
 1 file changed, 32 insertions(+)

diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index 05c7456..4011887 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -6324,15 +6324,47 @@ static int ufshcd_devfreq_target(struct device *dev,
 {
int err = 0;
struct ufs_hba *hba = dev_get_drvdata(dev);
+   bool release_clk_hold = false;
+   unsigned long irq_flags;
 
if (!ufshcd_is_clkscaling_enabled(hba))
return -EINVAL;
 
+   spin_lock_irqsave(hba->host->host_lock, irq_flags);
+   if (ufshcd_eh_in_progress(hba)) {
+   spin_unlock_irqrestore(hba->host->host_lock, irq_flags);
+   return 0;
+   }
+
+   if (ufshcd_is_clkgating_allowed(hba) &&
+   (hba->clk_gating.state != CLKS_ON)) {
+   if (cancel_delayed_work(>clk_gating.gate_work)) {
+   /* hold the vote until the scaling work is completed */
+   hba->clk_gating.active_reqs++;
+   release_clk_hold = true;
+   hba->clk_gating.state = CLKS_ON;
+   } else {
+   /*
+* Clock gating work seems to be running in parallel
+* hence skip scaling work to avoid deadlock between
+* current scaling work and gating work.
+*/
+   spin_unlock_irqrestore(hba->host->host_lock, irq_flags);
+   return 0;
+   }
+   }
+   spin_unlock_irqrestore(hba->host->host_lock, irq_flags);
+
if (*freq == UINT_MAX)
err = ufshcd_scale_clks(hba, true);
else if (*freq == 0)
err = ufshcd_scale_clks(hba, false);
 
+   spin_lock_irqsave(hba->host->host_lock, irq_flags);
+   if (release_clk_hold)
+   __ufshcd_release(hba);
+   spin_unlock_irqrestore(hba->host->host_lock, irq_flags);
+
return err;
 }
 
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project



Re: [PATCH v2] scsi: ufshcd: fix possible unclocked register access

2016-10-06 Thread Subhash Jadavani

Thanks Kim for the response.

On 2016-10-06 03:28, Kiwoong Kim wrote:

Hi, Subhash.

Some UFS host controllers may need to call the vendor specific callback
before and after controlling by clock control framework,
regardless of whether available clocks are turned on or off.


Are you suggesting to call ufshcd_vops_setup_clocks() 2 times, one 
before the on/off by ufshcd core driver and one after the on/off? If 
yes, then we also have add 3rd argument clarifying if this is PRE_CHANGE 
or POST_CHANGE.




Is there any special reason to limit to invoke the callback
only when the clocks are turned on or not?

Besides, the callback is acknowledged from core driver
because 2nd argument is whether the clocks are turned on or not.

If you have any other idea, please let me know.


This is my suggestion:
1. Add 3rd argument to setup_clocks ops to let the vendor callback 
function know if this is called PRE_CHANGE or POST_CHANGE.
2. If #1 is in place, call setup_clocks 2 times, one with PRE_CHANGE 
argument before making any clock changes in core driver, 2nd with 
POST_CHANGE argument after making the clock changes to core driver.


Let me know if this would work or not.

Thanks,
Subhash



Thanks
Regards


Vendor specific setup_clocks callback may require the clocks managed
by ufshcd driver to be ON. So if the vendor specific setup_clocks 
callback
is called while the required clocks are turned off, it could result 
into

unclocked register access.

To prevent possible unclock register access, this change makes sure 
that

required clocks remain enabled before calling into vendor specific
setup_clocks callback.

Signed-off-by: Subhash Jadavani <subha...@codeaurora.org>
---
Changes from v2:
* Don't call ufshcd_vops_setup_clocks() again for clock off
---
 drivers/scsi/ufs/ufshcd.c | 22 +-
 1 file changed, 21 insertions(+), 1 deletion(-)

diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index 05c7456..c1a77d3 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -5389,6 +5389,17 @@ static int __ufshcd_setup_clocks(struct ufs_hba
*hba, bool on,
if (!head || list_empty(head))
goto out;

+   /*
+* 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);
+   if (ret)
+   return ret;
+   }
+
list_for_each_entry(clki, head, list) {
if (!IS_ERR_OR_NULL(clki->clk)) {
if (skip_ref_clk && !strcmp(clki->name, "ref_clk"))
@@ -5410,7 +5421,16 @@ static int __ufshcd_setup_clocks(struct ufs_hba
*hba, bool on,
}
}

-   ret = ufshcd_vops_setup_clocks(hba, on);
+   /*
+* 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);
+   if (ret)
+   return ret;
+   }
 out:
if (ret) {
list_for_each_entry(clki, head, list) {
--
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora 
Forum,

a Linux Foundation Collaborative Project

--
To unsubscribe from this list: send the line "unsubscribe linux-scsi" 
in

the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html



--
To unsubscribe from this list: send the line "unsubscribe linux-scsi" 
in

the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


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


Re: [PATCH v2] scsi: ufshcd: fix possible unclocked register access

2016-10-06 Thread Subhash Jadavani

Thanks Kim for the response.

On 2016-10-06 03:28, Kiwoong Kim wrote:

Hi, Subhash.

Some UFS host controllers may need to call the vendor specific callback
before and after controlling by clock control framework,
regardless of whether available clocks are turned on or off.


Are you suggesting to call ufshcd_vops_setup_clocks() 2 times, one 
before the on/off by ufshcd core driver and one after the on/off? If 
yes, then we also have add 3rd argument clarifying if this is PRE_CHANGE 
or POST_CHANGE.




Is there any special reason to limit to invoke the callback
only when the clocks are turned on or not?

Besides, the callback is acknowledged from core driver
because 2nd argument is whether the clocks are turned on or not.

If you have any other idea, please let me know.


This is my suggestion:
1. Add 3rd argument to setup_clocks ops to let the vendor callback 
function know if this is called PRE_CHANGE or POST_CHANGE.
2. If #1 is in place, call setup_clocks 2 times, one with PRE_CHANGE 
argument before making any clock changes in core driver, 2nd with 
POST_CHANGE argument after making the clock changes to core driver.


Let me know if this would work or not.

Thanks,
Subhash



Thanks
Regards


Vendor specific setup_clocks callback may require the clocks managed
by ufshcd driver to be ON. So if the vendor specific setup_clocks 
callback
is called while the required clocks are turned off, it could result 
into

unclocked register access.

To prevent possible unclock register access, this change makes sure 
that

required clocks remain enabled before calling into vendor specific
setup_clocks callback.

Signed-off-by: Subhash Jadavani 
---
Changes from v2:
* Don't call ufshcd_vops_setup_clocks() again for clock off
---
 drivers/scsi/ufs/ufshcd.c | 22 +-
 1 file changed, 21 insertions(+), 1 deletion(-)

diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index 05c7456..c1a77d3 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -5389,6 +5389,17 @@ static int __ufshcd_setup_clocks(struct ufs_hba
*hba, bool on,
if (!head || list_empty(head))
goto out;

+   /*
+* 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);
+   if (ret)
+   return ret;
+   }
+
list_for_each_entry(clki, head, list) {
if (!IS_ERR_OR_NULL(clki->clk)) {
if (skip_ref_clk && !strcmp(clki->name, "ref_clk"))
@@ -5410,7 +5421,16 @@ static int __ufshcd_setup_clocks(struct ufs_hba
*hba, bool on,
}
}

-   ret = ufshcd_vops_setup_clocks(hba, on);
+   /*
+* 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);
+   if (ret)
+   return ret;
+   }
 out:
if (ret) {
list_for_each_entry(clki, head, list) {
--
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora 
Forum,

a Linux Foundation Collaborative Project

--
To unsubscribe from this list: send the line "unsubscribe linux-scsi" 
in

the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html



--
To unsubscribe from this list: send the line "unsubscribe linux-scsi" 
in

the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


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


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

2016-10-05 Thread Subhash Jadavani
Vendor specific setup_clocks callback may require the clocks managed
by ufshcd driver to be ON. So if the vendor specific setup_clocks callback
is called while the required clocks are turned off, it could result into
unclocked register access.

To prevent possible unclock register access, this change makes sure that
required clocks remain enabled before calling into vendor specific
setup_clocks callback.

Signed-off-by: Subhash Jadavani <subha...@codeaurora.org>
---
Changes from v2:
* Don't call ufshcd_vops_setup_clocks() again for clock off
---
 drivers/scsi/ufs/ufshcd.c | 22 +-
 1 file changed, 21 insertions(+), 1 deletion(-)

diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index 05c7456..c1a77d3 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -5389,6 +5389,17 @@ static int __ufshcd_setup_clocks(struct ufs_hba *hba, 
bool on,
if (!head || list_empty(head))
goto out;
 
+   /*
+* 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);
+   if (ret)
+   return ret;
+   }
+
list_for_each_entry(clki, head, list) {
if (!IS_ERR_OR_NULL(clki->clk)) {
if (skip_ref_clk && !strcmp(clki->name, "ref_clk"))
@@ -5410,7 +5421,16 @@ static int __ufshcd_setup_clocks(struct ufs_hba *hba, 
bool on,
}
}
 
-   ret = ufshcd_vops_setup_clocks(hba, on);
+   /*
+* 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);
+   if (ret)
+   return ret;
+   }
 out:
if (ret) {
list_for_each_entry(clki, head, list) {
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project



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

2016-10-05 Thread Subhash Jadavani
Vendor specific setup_clocks callback may require the clocks managed
by ufshcd driver to be ON. So if the vendor specific setup_clocks callback
is called while the required clocks are turned off, it could result into
unclocked register access.

To prevent possible unclock register access, this change makes sure that
required clocks remain enabled before calling into vendor specific
setup_clocks callback.

Signed-off-by: Subhash Jadavani 
---
Changes from v2:
* Don't call ufshcd_vops_setup_clocks() again for clock off
---
 drivers/scsi/ufs/ufshcd.c | 22 +-
 1 file changed, 21 insertions(+), 1 deletion(-)

diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index 05c7456..c1a77d3 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -5389,6 +5389,17 @@ static int __ufshcd_setup_clocks(struct ufs_hba *hba, 
bool on,
if (!head || list_empty(head))
goto out;
 
+   /*
+* 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);
+   if (ret)
+   return ret;
+   }
+
list_for_each_entry(clki, head, list) {
if (!IS_ERR_OR_NULL(clki->clk)) {
if (skip_ref_clk && !strcmp(clki->name, "ref_clk"))
@@ -5410,7 +5421,16 @@ static int __ufshcd_setup_clocks(struct ufs_hba *hba, 
bool on,
}
}
 
-   ret = ufshcd_vops_setup_clocks(hba, on);
+   /*
+* 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);
+   if (ret)
+   return ret;
+   }
 out:
if (ret) {
list_for_each_entry(clki, head, list) {
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project



<    1   2   3   4   >