Re: [RFC PATCH V2] scsi: ufs: Add specific callback for setting DMA mask

2018-05-16 Thread Subhash Jadavani

On 2018-05-15 21:31, Alim Akhtar wrote:

Ping !!!

On Thu, Mar 8, 2018 at 4:33 PM, Alim Akhtar  
wrote:

Currently DMA mask for UFS HCI is set by reading CAP register's
[64AS] bit. Some HCI controller like Exynos support 36-bit bus 
address.

This works perfectly fine with DMA mask set as 64 in case there is no
IOMMU attached to HCI.
In case if HCI is behind an IOMMU, setting DMA mask as 64 bit won't
work as HCI has only 36bit addressing and SMMU has created mapping of
64 bit and as the device truncates the address, its mapping will not
be found by iommu.
To resolve such issues, let the variant driver sets its own DMA mask.

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

I am not sure if there are other ways available to handle such cases.
The IOMMU I am talking about is arm-smmu and it DT binding does not
give much idea about handling such cases.
Have tested this patch with HCI controller with IOMMU attached.

Changes Since V1:
- Fixed build issue as reported by Kbuild test robot.

diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index a355d98..9a1374e 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -7781,6 +7781,9 @@ EXPORT_SYMBOL_GPL(ufshcd_dealloc_host);
  */
 static int ufshcd_set_dma_mask(struct ufs_hba *hba)
 {
+   if (hba->vops && hba->vops->set_dma_mask)
+   return hba->vops->set_dma_mask(hba);
+
if (hba->capabilities & MASK_64_ADDRESSING_SUPPORT) {
if (!dma_set_mask_and_coherent(hba->dev, 
DMA_BIT_MASK(64)))

return 0;
diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h
index 1332e54..89c6dae 100644
--- a/drivers/scsi/ufs/ufshcd.h
+++ b/drivers/scsi/ufs/ufshcd.h
@@ -297,6 +297,7 @@ struct ufs_pwr_mode_info {
  * @resume: called during host controller PM callback
  * @dbg_register_dump: used to dump controller debug information
  * @phy_initialization: used to initialize phys
+ * @set_dma_mask: used to set variant specific DMA mask
  */
 struct ufs_hba_variant_ops {
const char *name;
@@ -325,6 +326,7 @@ struct ufs_hba_variant_ops {
int (*resume)(struct ufs_hba *, enum ufs_pm_op);
void(*dbg_register_dump)(struct ufs_hba *hba);
int (*phy_initialization)(struct ufs_hba *);
+   int (*set_dma_mask)(struct ufs_hba *hba);
 };

 /* clock gating state  */
--
2.7.4



Looks reasonable to me, you may try posting non-RFC version.

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


Re: [RFC PATCH V2] scsi: ufs: Add specific callback for setting DMA mask

2018-05-16 Thread Subhash Jadavani

On 2018-05-15 21:31, Alim Akhtar wrote:

Ping !!!

On Thu, Mar 8, 2018 at 4:33 PM, Alim Akhtar  
wrote:

Currently DMA mask for UFS HCI is set by reading CAP register's
[64AS] bit. Some HCI controller like Exynos support 36-bit bus 
address.

This works perfectly fine with DMA mask set as 64 in case there is no
IOMMU attached to HCI.
In case if HCI is behind an IOMMU, setting DMA mask as 64 bit won't
work as HCI has only 36bit addressing and SMMU has created mapping of
64 bit and as the device truncates the address, its mapping will not
be found by iommu.
To resolve such issues, let the variant driver sets its own DMA mask.

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

I am not sure if there are other ways available to handle such cases.
The IOMMU I am talking about is arm-smmu and it DT binding does not
give much idea about handling such cases.
Have tested this patch with HCI controller with IOMMU attached.

Changes Since V1:
- Fixed build issue as reported by Kbuild test robot.

diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index a355d98..9a1374e 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -7781,6 +7781,9 @@ EXPORT_SYMBOL_GPL(ufshcd_dealloc_host);
  */
 static int ufshcd_set_dma_mask(struct ufs_hba *hba)
 {
+   if (hba->vops && hba->vops->set_dma_mask)
+   return hba->vops->set_dma_mask(hba);
+
if (hba->capabilities & MASK_64_ADDRESSING_SUPPORT) {
if (!dma_set_mask_and_coherent(hba->dev, 
DMA_BIT_MASK(64)))

return 0;
diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h
index 1332e54..89c6dae 100644
--- a/drivers/scsi/ufs/ufshcd.h
+++ b/drivers/scsi/ufs/ufshcd.h
@@ -297,6 +297,7 @@ struct ufs_pwr_mode_info {
  * @resume: called during host controller PM callback
  * @dbg_register_dump: used to dump controller debug information
  * @phy_initialization: used to initialize phys
+ * @set_dma_mask: used to set variant specific DMA mask
  */
 struct ufs_hba_variant_ops {
const char *name;
@@ -325,6 +326,7 @@ struct ufs_hba_variant_ops {
int (*resume)(struct ufs_hba *, enum ufs_pm_op);
void(*dbg_register_dump)(struct ufs_hba *hba);
int (*phy_initialization)(struct ufs_hba *);
+   int (*set_dma_mask)(struct ufs_hba *hba);
 };

 /* clock gating state  */
--
2.7.4



Looks reasonable to me, you may try posting non-RFC version.

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


Re: [PATCH 4/4] scsi: ufs: make ufshcd_config_pwr_mode of non-static func

2018-05-16 Thread Subhash Jadavani

On 2018-05-06 03:14, Alim Akhtar wrote:

This makes ufshcd_config_pwr_mode non-static so that other vendors
like exynos can use the same.

Signed-off-by: Seungwon Jeon <ess...@gmail.com>
Signed-off-by: Alim Akhtar <alim.akh...@samsung.com>
---
 drivers/scsi/ufs/ufshcd.c | 5 ++---
 drivers/scsi/ufs/ufshcd.h | 2 ++
 2 files changed, 4 insertions(+), 3 deletions(-)

diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index 5bfd385..68aefcd 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -233,8 +233,6 @@ static void ufshcd_suspend_clkscaling(struct 
ufs_hba *hba);

 static void __ufshcd_suspend_clkscaling(struct ufs_hba *hba);
 static int ufshcd_scale_clks(struct ufs_hba *hba, bool scale_up);
 static irqreturn_t ufshcd_intr(int irq, void *__hba);
-static int ufshcd_config_pwr_mode(struct ufs_hba *hba,
-   struct ufs_pa_layer_attr *desired_pwr_mode);
 static int ufshcd_change_power_mode(struct ufs_hba *hba,
 struct ufs_pa_layer_attr *pwr_mode);
 static inline bool ufshcd_valid_tag(struct ufs_hba *hba, int tag)
@@ -3969,7 +3967,7 @@ static int ufshcd_change_power_mode(struct 
ufs_hba *hba,

  * @hba: per-adapter instance
  * @desired_pwr_mode: desired power configuration
  */
-static int ufshcd_config_pwr_mode(struct ufs_hba *hba,
+int ufshcd_config_pwr_mode(struct ufs_hba *hba,
struct ufs_pa_layer_attr *desired_pwr_mode)
 {
struct ufs_pa_layer_attr final_params = { 0 };
@@ -3987,6 +3985,7 @@ static int ufshcd_config_pwr_mode(struct ufs_hba 
*hba,


return ret;
 }
+EXPORT_SYMBOL_GPL(ufshcd_config_pwr_mode);

 /**
  * ufshcd_complete_dev_init() - checks device readiness
diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h
index 013a07e..b42a5a3 100644
--- a/drivers/scsi/ufs/ufshcd.h
+++ b/drivers/scsi/ufs/ufshcd.h
@@ -805,6 +805,8 @@ extern int ufshcd_dme_set_attr(struct ufs_hba
*hba, u32 attr_sel,
   u8 attr_set, u32 mib_val, u8 peer);
 extern int ufshcd_dme_get_attr(struct ufs_hba *hba, u32 attr_sel,
   u32 *mib_val, u8 peer);
+extern int ufshcd_config_pwr_mode(struct ufs_hba *hba,
+   struct ufs_pa_layer_attr *desired_pwr_mode);

 /* UIC command interfaces for DME primitives */
 #define DME_LOCAL  0


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 4/4] scsi: ufs: make ufshcd_config_pwr_mode of non-static func

2018-05-16 Thread Subhash Jadavani

On 2018-05-06 03:14, Alim Akhtar wrote:

This makes ufshcd_config_pwr_mode non-static so that other vendors
like exynos can use the same.

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

diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index 5bfd385..68aefcd 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -233,8 +233,6 @@ static void ufshcd_suspend_clkscaling(struct 
ufs_hba *hba);

 static void __ufshcd_suspend_clkscaling(struct ufs_hba *hba);
 static int ufshcd_scale_clks(struct ufs_hba *hba, bool scale_up);
 static irqreturn_t ufshcd_intr(int irq, void *__hba);
-static int ufshcd_config_pwr_mode(struct ufs_hba *hba,
-   struct ufs_pa_layer_attr *desired_pwr_mode);
 static int ufshcd_change_power_mode(struct ufs_hba *hba,
 struct ufs_pa_layer_attr *pwr_mode);
 static inline bool ufshcd_valid_tag(struct ufs_hba *hba, int tag)
@@ -3969,7 +3967,7 @@ static int ufshcd_change_power_mode(struct 
ufs_hba *hba,

  * @hba: per-adapter instance
  * @desired_pwr_mode: desired power configuration
  */
-static int ufshcd_config_pwr_mode(struct ufs_hba *hba,
+int ufshcd_config_pwr_mode(struct ufs_hba *hba,
struct ufs_pa_layer_attr *desired_pwr_mode)
 {
struct ufs_pa_layer_attr final_params = { 0 };
@@ -3987,6 +3985,7 @@ static int ufshcd_config_pwr_mode(struct ufs_hba 
*hba,


return ret;
 }
+EXPORT_SYMBOL_GPL(ufshcd_config_pwr_mode);

 /**
  * ufshcd_complete_dev_init() - checks device readiness
diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h
index 013a07e..b42a5a3 100644
--- a/drivers/scsi/ufs/ufshcd.h
+++ b/drivers/scsi/ufs/ufshcd.h
@@ -805,6 +805,8 @@ extern int ufshcd_dme_set_attr(struct ufs_hba
*hba, u32 attr_sel,
   u8 attr_set, u32 mib_val, u8 peer);
 extern int ufshcd_dme_get_attr(struct ufs_hba *hba, u32 attr_sel,
   u32 *mib_val, u8 peer);
+extern int ufshcd_config_pwr_mode(struct ufs_hba *hba,
+   struct ufs_pa_layer_attr *desired_pwr_mode);

 /* UIC command interfaces for DME primitives */
 #define DME_LOCAL  0


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 3/4] scsi: ufs: add quirk to enable host controller without hce

2018-05-16 Thread Subhash Jadavani

On 2018-05-06 03:14, Alim Akhtar wrote:

Some host controller doesn't support host controller enable via HCE.

Signed-off-by: Seungwon Jeon <ess...@gmail.com>
Signed-off-by: Alim Akhtar <alim.akh...@samsung.com>
---
 drivers/scsi/ufs/ufshcd.c | 75 
+--

 drivers/scsi/ufs/ufshcd.h |  5 
 2 files changed, 78 insertions(+), 2 deletions(-)

diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index 253257c..5bfd385 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -3400,6 +3400,52 @@ static int ufshcd_dme_link_startup(struct 
ufs_hba *hba)

"dme-link-startup: error code %d\n", ret);
return ret;
 }
+/**
+ * ufshcd_dme_reset - UIC command for DME_RESET
+ * @hba: per adapter instance
+ *
+ * DME_RESET command is issued in order to reset UniPro stack.
+ * This function now deal with cold reset.
+ *
+ * Returns 0 on success, non-zero value on failure
+ */
+static int ufshcd_dme_reset(struct ufs_hba *hba)
+{
+   struct uic_command uic_cmd = {0};
+   int ret;
+
+   uic_cmd.command = UIC_CMD_DME_RESET;
+
+   ret = ufshcd_send_uic_cmd(hba, _cmd);
+   if (ret)
+   dev_err(hba->dev,
+   "dme-reset: error code %d\n", ret);
+
+   return ret;
+}
+
+/**
+ * ufshcd_dme_enable - UIC command for DME_ENABLE
+ * @hba: per adapter instance
+ *
+ * DME_ENABLE command is issued in order to enable UniPro stack.
+ *
+ * Returns 0 on success, non-zero value on failure
+ */
+static int ufshcd_dme_enable(struct ufs_hba *hba)
+{
+   struct uic_command uic_cmd = {0};
+   int ret;
+
+   uic_cmd.command = UIC_CMD_DME_ENABLE;
+
+   ret = ufshcd_send_uic_cmd(hba, _cmd);
+   if (ret)
+   dev_err(hba->dev,
+   "dme-reset: error code %d\n", ret);
+
+   return ret;
+}

 static inline void ufshcd_add_delay_before_dme_cmd(struct ufs_hba 
*hba)

 {
@@ -4058,7 +4104,7 @@ static inline void ufshcd_hba_stop(struct
ufs_hba *hba, bool can_sleep)
 }

 /**
- * ufshcd_hba_enable - initialize the controller
+ * ufshcd_hba_execute_hce - initialize the controller
  * @hba: per adapter instance
  *
  * The controller resets itself and controller firmware initialization
@@ -4067,7 +4113,7 @@ static inline void ufshcd_hba_stop(struct
ufs_hba *hba, bool can_sleep)
  *
  * Returns 0 on success, non-zero value on failure
  */
-static int ufshcd_hba_enable(struct ufs_hba *hba)
+static int ufshcd_hba_execute_hce(struct ufs_hba *hba)
 {
int retry;

@@ -4122,6 +4168,31 @@ static int ufshcd_hba_enable(struct ufs_hba 
*hba)

return 0;
 }

+static int ufshcd_hba_enable(struct ufs_hba *hba)
+{
+   int ret;
+
+   if (hba->quirks & UFSHCI_QUIRK_BROKEN_HCE) {
+   ufshcd_set_link_off(hba);
+   ufshcd_vops_hce_enable_notify(hba, PRE_CHANGE);
+
+   /* enable UIC related interrupts */
+   ufshcd_enable_intr(hba, UFSHCD_UIC_MASK);
+   ret = ufshcd_dme_reset(hba);
+   if (!ret) {
+   ret = ufshcd_dme_enable(hba);
+   if (!ret)
+   ufshcd_vops_hce_enable_notify(hba, POST_CHANGE);
+   if (ret)
+   dev_err(hba->dev,
+   "Host controller enable failed with 
non-hce\n");
+   }
+   } else {
+   ret = ufshcd_hba_execute_hce(hba);
+   }
+
+   return ret;
+}
 static int ufshcd_disable_tx_lcc(struct ufs_hba *hba, bool peer)
 {
int tx_lanes, i, err = 0;
diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h
index 5c91ff1..013a07e 100644
--- a/drivers/scsi/ufs/ufshcd.h
+++ b/drivers/scsi/ufs/ufshcd.h
@@ -606,6 +606,11 @@ struct ufs_hba {
 */
#define UFSHCI_QUIRK_SKIP_RESET_INTR_AGGR   0x200

+   /*
+* This quirks needs to be enabled if host controller cannot be
+* enabled via HCE register.
+*/
+   #define UFSHCI_QUIRK_BROKEN_HCE 0x400
unsigned int quirks;/* Deviations from standard UFSHCI spec. */

/* Device deviations from standard UFS device spec. */


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 3/4] scsi: ufs: add quirk to enable host controller without hce

2018-05-16 Thread Subhash Jadavani

On 2018-05-06 03:14, Alim Akhtar wrote:

Some host controller doesn't support host controller enable via HCE.

Signed-off-by: Seungwon Jeon 
Signed-off-by: Alim Akhtar 
---
 drivers/scsi/ufs/ufshcd.c | 75 
+--

 drivers/scsi/ufs/ufshcd.h |  5 
 2 files changed, 78 insertions(+), 2 deletions(-)

diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index 253257c..5bfd385 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -3400,6 +3400,52 @@ static int ufshcd_dme_link_startup(struct 
ufs_hba *hba)

"dme-link-startup: error code %d\n", ret);
return ret;
 }
+/**
+ * ufshcd_dme_reset - UIC command for DME_RESET
+ * @hba: per adapter instance
+ *
+ * DME_RESET command is issued in order to reset UniPro stack.
+ * This function now deal with cold reset.
+ *
+ * Returns 0 on success, non-zero value on failure
+ */
+static int ufshcd_dme_reset(struct ufs_hba *hba)
+{
+   struct uic_command uic_cmd = {0};
+   int ret;
+
+   uic_cmd.command = UIC_CMD_DME_RESET;
+
+   ret = ufshcd_send_uic_cmd(hba, _cmd);
+   if (ret)
+   dev_err(hba->dev,
+   "dme-reset: error code %d\n", ret);
+
+   return ret;
+}
+
+/**
+ * ufshcd_dme_enable - UIC command for DME_ENABLE
+ * @hba: per adapter instance
+ *
+ * DME_ENABLE command is issued in order to enable UniPro stack.
+ *
+ * Returns 0 on success, non-zero value on failure
+ */
+static int ufshcd_dme_enable(struct ufs_hba *hba)
+{
+   struct uic_command uic_cmd = {0};
+   int ret;
+
+   uic_cmd.command = UIC_CMD_DME_ENABLE;
+
+   ret = ufshcd_send_uic_cmd(hba, _cmd);
+   if (ret)
+   dev_err(hba->dev,
+   "dme-reset: error code %d\n", ret);
+
+   return ret;
+}

 static inline void ufshcd_add_delay_before_dme_cmd(struct ufs_hba 
*hba)

 {
@@ -4058,7 +4104,7 @@ static inline void ufshcd_hba_stop(struct
ufs_hba *hba, bool can_sleep)
 }

 /**
- * ufshcd_hba_enable - initialize the controller
+ * ufshcd_hba_execute_hce - initialize the controller
  * @hba: per adapter instance
  *
  * The controller resets itself and controller firmware initialization
@@ -4067,7 +4113,7 @@ static inline void ufshcd_hba_stop(struct
ufs_hba *hba, bool can_sleep)
  *
  * Returns 0 on success, non-zero value on failure
  */
-static int ufshcd_hba_enable(struct ufs_hba *hba)
+static int ufshcd_hba_execute_hce(struct ufs_hba *hba)
 {
int retry;

@@ -4122,6 +4168,31 @@ static int ufshcd_hba_enable(struct ufs_hba 
*hba)

return 0;
 }

+static int ufshcd_hba_enable(struct ufs_hba *hba)
+{
+   int ret;
+
+   if (hba->quirks & UFSHCI_QUIRK_BROKEN_HCE) {
+   ufshcd_set_link_off(hba);
+   ufshcd_vops_hce_enable_notify(hba, PRE_CHANGE);
+
+   /* enable UIC related interrupts */
+   ufshcd_enable_intr(hba, UFSHCD_UIC_MASK);
+   ret = ufshcd_dme_reset(hba);
+   if (!ret) {
+   ret = ufshcd_dme_enable(hba);
+   if (!ret)
+   ufshcd_vops_hce_enable_notify(hba, POST_CHANGE);
+   if (ret)
+   dev_err(hba->dev,
+   "Host controller enable failed with 
non-hce\n");
+   }
+   } else {
+   ret = ufshcd_hba_execute_hce(hba);
+   }
+
+   return ret;
+}
 static int ufshcd_disable_tx_lcc(struct ufs_hba *hba, bool peer)
 {
int tx_lanes, i, err = 0;
diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h
index 5c91ff1..013a07e 100644
--- a/drivers/scsi/ufs/ufshcd.h
+++ b/drivers/scsi/ufs/ufshcd.h
@@ -606,6 +606,11 @@ struct ufs_hba {
 */
#define UFSHCI_QUIRK_SKIP_RESET_INTR_AGGR   0x200

+   /*
+* This quirks needs to be enabled if host controller cannot be
+* enabled via HCE register.
+*/
+   #define UFSHCI_QUIRK_BROKEN_HCE 0x400
unsigned int quirks;/* Deviations from standard UFSHCI spec. */

/* Device deviations from standard UFS device spec. */


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 2/4] scsi: ufs: add quirk not to allow reset of interrupt aggregation

2018-05-16 Thread Subhash Jadavani

On 2018-05-06 03:14, Alim Akhtar wrote:

Some host controller supports interrupt aggregation, but doesn't
allow to reset counter and timer by s/w.

Signed-off-by: Seungwon Jeon <ess...@gmail.com>
Signed-off-by: Alim Akhtar <alim.akh...@samsung.com>
---
 drivers/scsi/ufs/ufshcd.c | 3 ++-
 drivers/scsi/ufs/ufshcd.h | 6 ++
 2 files changed, 8 insertions(+), 1 deletion(-)

diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index 9898ce5..253257c 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -4695,7 +4695,8 @@ static void ufshcd_transfer_req_compl(struct 
ufs_hba *hba)
 	 * false interrupt if device completes another request after 
resetting

 * aggregation and before reading the DB.
 */
-   if (ufshcd_is_intr_aggr_allowed(hba))
+   if (ufshcd_is_intr_aggr_allowed(hba) &&
+   !(hba->quirks & UFSHCI_QUIRK_SKIP_RESET_INTR_AGGR))
ufshcd_reset_intr_aggr(hba);

tr_doorbell = ufshcd_readl(hba, REG_UTP_TRANSFER_REQ_DOOR_BELL);
diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h
index 43035f8..5c91ff1 100644
--- a/drivers/scsi/ufs/ufshcd.h
+++ b/drivers/scsi/ufs/ufshcd.h
@@ -600,6 +600,12 @@ struct ufs_hba {
 */
#define UFSHCI_QUIRK_BROKEN_REQ_LIST_CLR0x100

+   /*
+* This quirk needs to be enabled if host controller doesn't allow
+* that the interrupt aggregation timer and counter are reset by s/w.
+*/
+   #define UFSHCI_QUIRK_SKIP_RESET_INTR_AGGR   0x200
+
unsigned int quirks;/* Deviations from standard UFSHCI spec. */

/* Device deviations from standard UFS device spec. */


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 2/4] scsi: ufs: add quirk not to allow reset of interrupt aggregation

2018-05-16 Thread Subhash Jadavani

On 2018-05-06 03:14, Alim Akhtar wrote:

Some host controller supports interrupt aggregation, but doesn't
allow to reset counter and timer by s/w.

Signed-off-by: Seungwon Jeon 
Signed-off-by: Alim Akhtar 
---
 drivers/scsi/ufs/ufshcd.c | 3 ++-
 drivers/scsi/ufs/ufshcd.h | 6 ++
 2 files changed, 8 insertions(+), 1 deletion(-)

diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index 9898ce5..253257c 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -4695,7 +4695,8 @@ static void ufshcd_transfer_req_compl(struct 
ufs_hba *hba)
 	 * false interrupt if device completes another request after 
resetting

 * aggregation and before reading the DB.
 */
-   if (ufshcd_is_intr_aggr_allowed(hba))
+   if (ufshcd_is_intr_aggr_allowed(hba) &&
+   !(hba->quirks & UFSHCI_QUIRK_SKIP_RESET_INTR_AGGR))
ufshcd_reset_intr_aggr(hba);

tr_doorbell = ufshcd_readl(hba, REG_UTP_TRANSFER_REQ_DOOR_BELL);
diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h
index 43035f8..5c91ff1 100644
--- a/drivers/scsi/ufs/ufshcd.h
+++ b/drivers/scsi/ufs/ufshcd.h
@@ -600,6 +600,12 @@ struct ufs_hba {
 */
#define UFSHCI_QUIRK_BROKEN_REQ_LIST_CLR0x100

+   /*
+* This quirk needs to be enabled if host controller doesn't allow
+* that the interrupt aggregation timer and counter are reset by s/w.
+*/
+   #define UFSHCI_QUIRK_SKIP_RESET_INTR_AGGR   0x200
+
unsigned int quirks;/* Deviations from standard UFSHCI spec. */

/* Device deviations from standard UFS device spec. */


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 1/4] scsi: ufs: add quirk to fix mishandling utrlclr/utmrlclr

2018-05-16 Thread Subhash Jadavani

On 2018-05-06 03:14, Alim Akhtar wrote:

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

Signed-off-by: Seungwon Jeon <ess...@gmail.com>
Signed-off-by: Alim Akhtar <alim.akh...@samsung.com>
---
 drivers/scsi/ufs/ufshcd.c | 21 +++--
 drivers/scsi/ufs/ufshcd.h |  5 +
 2 files changed, 24 insertions(+), 2 deletions(-)

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

 /**
@@ -5398,7 +5415,7 @@ static int ufshcd_clear_tm_cmd(struct ufs_hba
*hba, int tag)
goto out;

spin_lock_irqsave(hba->host->host_lock, flags);
-   ufshcd_writel(hba, ~(1 << tag), REG_UTP_TASK_REQ_LIST_CLEAR);
+   ufshcd_utmrl_clear(hba, tag);
spin_unlock_irqrestore(hba->host->host_lock, flags);

/* poll for max. 1 sec to clear door bell register by h/w */
diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h
index 8110dcd..43035f8 100644
--- a/drivers/scsi/ufs/ufshcd.h
+++ b/drivers/scsi/ufs/ufshcd.h
@@ -595,6 +595,11 @@ struct ufs_hba {
 */
#define UFSHCD_QUIRK_PRDT_BYTE_GRAN 0x80

+   /*
+* Cleaer handling for transfer/task request list is just opposite.
+*/
+   #define UFSHCI_QUIRK_BROKEN_REQ_LIST_CLR0x100
+
unsigned int quirks;/* Deviations from standard UFSHCI spec. */

/* Device deviations from standard UFS device spec. */


Looks good to me.
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 1/4] scsi: ufs: add quirk to fix mishandling utrlclr/utmrlclr

2018-05-16 Thread Subhash Jadavani

On 2018-05-06 03:14, Alim Akhtar wrote:

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

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

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

 /**
@@ -5398,7 +5415,7 @@ static int ufshcd_clear_tm_cmd(struct ufs_hba
*hba, int tag)
goto out;

spin_lock_irqsave(hba->host->host_lock, flags);
-   ufshcd_writel(hba, ~(1 << tag), REG_UTP_TASK_REQ_LIST_CLEAR);
+   ufshcd_utmrl_clear(hba, tag);
spin_unlock_irqrestore(hba->host->host_lock, flags);

/* poll for max. 1 sec to clear door bell register by h/w */
diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h
index 8110dcd..43035f8 100644
--- a/drivers/scsi/ufs/ufshcd.h
+++ b/drivers/scsi/ufs/ufshcd.h
@@ -595,6 +595,11 @@ struct ufs_hba {
 */
#define UFSHCD_QUIRK_PRDT_BYTE_GRAN 0x80

+   /*
+* Cleaer handling for transfer/task request list is just opposite.
+*/
+   #define UFSHCI_QUIRK_BROKEN_REQ_LIST_CLR0x100
+
unsigned int quirks;/* Deviations from standard UFSHCI spec. */

/* Device deviations from standard UFS device spec. */


Looks good to me.
Reviewed-by: Subhash Jadavani 

--
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 freq table with devfreq

2018-05-16 Thread Subhash Jadavani

On 2018-05-04 15:44, Bjorn Andersson wrote:

devfreq requires that the client operates on actual frequencies, not
only 0 and UMAX_INT and as such UFS brok with the introduction of
f1d981eaecf8 ("PM / devfreq: Use the available min/max frequency").

This patch registers the frequencies of the first clock as opp levels
and use these to determine if we're trying to step up or down.

Signed-off-by: Bjorn Andersson <bjorn.anders...@linaro.org>
---

Chances since v1:
- Register min_freq and max_freq as opp levels.
- Unregister opp levels on removal, to make e.g. probe defer working

 drivers/scsi/ufs/ufshcd.c | 47 +--
 1 file changed, 40 insertions(+), 7 deletions(-)

diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index 2253f24309ec..257614b889bd 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -1168,16 +1168,13 @@ static int ufshcd_devfreq_target(struct device 
*dev,

struct ufs_hba *hba = dev_get_drvdata(dev);
ktime_t start;
bool scale_up, sched_clk_scaling_suspend_work = false;
+   struct list_head *clk_list = >clk_list_head;
+   struct ufs_clk_info *clki;
unsigned long irq_flags;

if (!ufshcd_is_clkscaling_supported(hba))
return -EINVAL;

-   if ((*freq > 0) && (*freq < UINT_MAX)) {
-   dev_err(hba->dev, "%s: invalid freq = %lu\n", __func__, *freq);
-   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);
@@ -1187,7 +1184,13 @@ static int ufshcd_devfreq_target(struct device 
*dev,

if (!hba->clk_scaling.active_reqs)
sched_clk_scaling_suspend_work = true;

-   scale_up = (*freq == UINT_MAX) ? true : false;
+   if (list_empty(clk_list)) {
+   spin_unlock_irqrestore(hba->host->host_lock, irq_flags);
+   goto out;
+   }
+
+   clki = list_first_entry(clk_list, struct ufs_clk_info, list);
+   scale_up = (*freq == clki->max_freq) ? true : false;
if (!ufshcd_is_devfreq_scaling_required(hba, scale_up)) {
spin_unlock_irqrestore(hba->host->host_lock, irq_flags);
ret = 0;
@@ -1257,16 +1260,29 @@ static struct devfreq_dev_profile
ufs_devfreq_profile = {

 static int ufshcd_devfreq_init(struct ufs_hba *hba)
 {
+   struct list_head *clk_list = >clk_list_head;
+   struct ufs_clk_info *clki;
struct devfreq *devfreq;
int ret;

-   devfreq = devm_devfreq_add_device(hba->dev,
+   /* Skip devfreq if we don't have any clocks in the list */
+   if (list_empty(clk_list))
+   return 0;
+
+   clki = list_first_entry(clk_list, struct ufs_clk_info, list);
+   dev_pm_opp_add(hba->dev, clki->min_freq, 0);
+   dev_pm_opp_add(hba->dev, clki->max_freq, 0);
+
+   devfreq = devfreq_add_device(hba->dev,
_devfreq_profile,
"simple_ondemand",
NULL);
if (IS_ERR(devfreq)) {
ret = PTR_ERR(devfreq);
dev_err(hba->dev, "Unable to register with devfreq %d\n", ret);
+
+   dev_pm_opp_remove(hba->dev, clki->min_freq);
+   dev_pm_opp_remove(hba->dev, clki->max_freq);
return ret;
}

@@ -1275,6 +1291,22 @@ static int ufshcd_devfreq_init(struct ufs_hba 
*hba)

return 0;
 }

+static void ufshcd_devfreq_remove(struct ufs_hba *hba)
+{
+   struct list_head *clk_list = >clk_list_head;
+   struct ufs_clk_info *clki;
+
+   if (!hba->devfreq)
+   return;
+
+   devfreq_remove_device(hba->devfreq);
+   hba->devfreq = NULL;
+
+   clki = list_first_entry(clk_list, struct ufs_clk_info, list);
+   dev_pm_opp_remove(hba->dev, clki->min_freq);
+   dev_pm_opp_remove(hba->dev, clki->max_freq);
+}
+
 static void __ufshcd_suspend_clkscaling(struct ufs_hba *hba)
 {
unsigned long flags;
@@ -6966,6 +6998,7 @@ static void ufshcd_hba_exit(struct ufs_hba *hba)
if (hba->devfreq)
ufshcd_suspend_clkscaling(hba);
destroy_workqueue(hba->clk_scaling.workq);
+   ufshcd_devfreq_remove(hba);
    }
ufshcd_setup_clocks(hba, false);
ufshcd_setup_hba_vreg(hba, false);


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 2/2] scsi: ufs: Use freq table with devfreq

2018-05-16 Thread Subhash Jadavani

On 2018-05-04 15:44, Bjorn Andersson wrote:

devfreq requires that the client operates on actual frequencies, not
only 0 and UMAX_INT and as such UFS brok with the introduction of
f1d981eaecf8 ("PM / devfreq: Use the available min/max frequency").

This patch registers the frequencies of the first clock as opp levels
and use these to determine if we're trying to step up or down.

Signed-off-by: Bjorn Andersson 
---

Chances since v1:
- Register min_freq and max_freq as opp levels.
- Unregister opp levels on removal, to make e.g. probe defer working

 drivers/scsi/ufs/ufshcd.c | 47 +--
 1 file changed, 40 insertions(+), 7 deletions(-)

diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index 2253f24309ec..257614b889bd 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -1168,16 +1168,13 @@ static int ufshcd_devfreq_target(struct device 
*dev,

struct ufs_hba *hba = dev_get_drvdata(dev);
ktime_t start;
bool scale_up, sched_clk_scaling_suspend_work = false;
+   struct list_head *clk_list = >clk_list_head;
+   struct ufs_clk_info *clki;
unsigned long irq_flags;

if (!ufshcd_is_clkscaling_supported(hba))
return -EINVAL;

-   if ((*freq > 0) && (*freq < UINT_MAX)) {
-   dev_err(hba->dev, "%s: invalid freq = %lu\n", __func__, *freq);
-   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);
@@ -1187,7 +1184,13 @@ static int ufshcd_devfreq_target(struct device 
*dev,

if (!hba->clk_scaling.active_reqs)
sched_clk_scaling_suspend_work = true;

-   scale_up = (*freq == UINT_MAX) ? true : false;
+   if (list_empty(clk_list)) {
+   spin_unlock_irqrestore(hba->host->host_lock, irq_flags);
+   goto out;
+   }
+
+   clki = list_first_entry(clk_list, struct ufs_clk_info, list);
+   scale_up = (*freq == clki->max_freq) ? true : false;
if (!ufshcd_is_devfreq_scaling_required(hba, scale_up)) {
spin_unlock_irqrestore(hba->host->host_lock, irq_flags);
ret = 0;
@@ -1257,16 +1260,29 @@ static struct devfreq_dev_profile
ufs_devfreq_profile = {

 static int ufshcd_devfreq_init(struct ufs_hba *hba)
 {
+   struct list_head *clk_list = >clk_list_head;
+   struct ufs_clk_info *clki;
struct devfreq *devfreq;
int ret;

-   devfreq = devm_devfreq_add_device(hba->dev,
+   /* Skip devfreq if we don't have any clocks in the list */
+   if (list_empty(clk_list))
+   return 0;
+
+   clki = list_first_entry(clk_list, struct ufs_clk_info, list);
+   dev_pm_opp_add(hba->dev, clki->min_freq, 0);
+   dev_pm_opp_add(hba->dev, clki->max_freq, 0);
+
+   devfreq = devfreq_add_device(hba->dev,
_devfreq_profile,
"simple_ondemand",
NULL);
if (IS_ERR(devfreq)) {
ret = PTR_ERR(devfreq);
dev_err(hba->dev, "Unable to register with devfreq %d\n", ret);
+
+   dev_pm_opp_remove(hba->dev, clki->min_freq);
+   dev_pm_opp_remove(hba->dev, clki->max_freq);
return ret;
}

@@ -1275,6 +1291,22 @@ static int ufshcd_devfreq_init(struct ufs_hba 
*hba)

return 0;
 }

+static void ufshcd_devfreq_remove(struct ufs_hba *hba)
+{
+   struct list_head *clk_list = >clk_list_head;
+   struct ufs_clk_info *clki;
+
+   if (!hba->devfreq)
+   return;
+
+   devfreq_remove_device(hba->devfreq);
+   hba->devfreq = NULL;
+
+   clki = list_first_entry(clk_list, struct ufs_clk_info, list);
+   dev_pm_opp_remove(hba->dev, clki->min_freq);
+   dev_pm_opp_remove(hba->dev, clki->max_freq);
+}
+
 static void __ufshcd_suspend_clkscaling(struct ufs_hba *hba)
 {
unsigned long flags;
@@ -6966,6 +6998,7 @@ static void ufshcd_hba_exit(struct ufs_hba *hba)
if (hba->devfreq)
ufshcd_suspend_clkscaling(hba);
destroy_workqueue(hba->clk_scaling.workq);
+   ufshcd_devfreq_remove(hba);
    }
ufshcd_setup_clocks(hba, false);
ufshcd_setup_hba_vreg(hba, false);


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 v2 10/10] scsi: ufs: Add clock ungating to a separate workqueue

2018-05-16 Thread Subhash Jadavani

On 2018-05-03 04:07, Asutosh Das wrote:

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

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

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

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

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

@@ -1676,6 +1679,11 @@ static void ufshcd_init_clk_gating(struct 
ufs_hba *hba)

INIT_DELAYED_WORK(>clk_gating.gate_work, ufshcd_gate_work);
INIT_WORK(>clk_gating.ungate_work, ufshcd_ungate_work);

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

hba->clk_gating.delay_attr.show = ufshcd_clkgate_delay_show;
@@ -1703,6 +1711,7 @@ static void ufshcd_exit_clk_gating(struct ufs_hba 
*hba)

device_remove_file(hba->dev, >clk_gating.enable_attr);
cancel_work_sync(>clk_gating.ungate_work);
cancel_delayed_work_sync(>clk_gating.gate_work);
+   destroy_workqueue(hba->clk_gating.clk_gating_workq);
 }

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

 struct ufs_saved_pwr_info {


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 10/10] scsi: ufs: Add clock ungating to a separate workqueue

2018-05-16 Thread Subhash Jadavani

On 2018-05-03 04:07, Asutosh Das wrote:

From: Vijay Viswanath 

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

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

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

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

@@ -1676,6 +1679,11 @@ static void ufshcd_init_clk_gating(struct 
ufs_hba *hba)

INIT_DELAYED_WORK(>clk_gating.gate_work, ufshcd_gate_work);
INIT_WORK(>clk_gating.ungate_work, ufshcd_ungate_work);

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

hba->clk_gating.delay_attr.show = ufshcd_clkgate_delay_show;
@@ -1703,6 +1711,7 @@ static void ufshcd_exit_clk_gating(struct ufs_hba 
*hba)

device_remove_file(hba->dev, >clk_gating.enable_attr);
cancel_work_sync(>clk_gating.ungate_work);
cancel_delayed_work_sync(>clk_gating.gate_work);
+   destroy_workqueue(hba->clk_gating.clk_gating_workq);
 }

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

 struct ufs_saved_pwr_info {


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 v2 07/10] scsi: ufs-qcom: remove broken hci version quirk

2018-05-16 Thread Subhash Jadavani

On 2018-05-03 04:07, Asutosh Das wrote:

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

UFSHCD_QUIRK_BROKEN_UFS_HCI_VERSION is only applicable for QCOM UFS 
host

controller version 2.x.y and this has been fixed from version 3.x.y
onwards, hence this change removes this quirk for version 3.x.y 
onwards.


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

diff --git a/drivers/scsi/ufs/ufs-qcom.c b/drivers/scsi/ufs/ufs-qcom.c
index d9edef8..27be327 100644
--- a/drivers/scsi/ufs/ufs-qcom.c
+++ b/drivers/scsi/ufs/ufs-qcom.c
@@ -1103,7 +1103,7 @@ static void ufs_qcom_advertise_quirks(struct 
ufs_hba *hba)

hba->quirks |= UFSHCD_QUIRK_BROKEN_LCC;
}

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


Looks good to me.

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


Re: [PATCH v2 08/10] scsi: ufs: make sure all interrupts are processed

2018-05-16 Thread Subhash Jadavani

On 2018-05-03 04:07, Asutosh Das wrote:

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

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

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

diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index c35a076..09b7a3f 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -5383,19 +5383,30 @@ static irqreturn_t ufshcd_intr(int irq, void 
*__hba)

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

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

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

-   if (enabled_intr_status) {
-   ufshcd_sl_intr(hba, enabled_intr_status);
-   retval = IRQ_HANDLED;
-   }
spin_unlock(hba->host->host_lock);
    return retval;
 }


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 07/10] scsi: ufs-qcom: remove broken hci version quirk

2018-05-16 Thread Subhash Jadavani

On 2018-05-03 04:07, Asutosh Das wrote:

From: Subhash Jadavani 

UFSHCD_QUIRK_BROKEN_UFS_HCI_VERSION is only applicable for QCOM UFS 
host

controller version 2.x.y and this has been fixed from version 3.x.y
onwards, hence this change removes this quirk for version 3.x.y 
onwards.


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

diff --git a/drivers/scsi/ufs/ufs-qcom.c b/drivers/scsi/ufs/ufs-qcom.c
index d9edef8..27be327 100644
--- a/drivers/scsi/ufs/ufs-qcom.c
+++ b/drivers/scsi/ufs/ufs-qcom.c
@@ -1103,7 +1103,7 @@ static void ufs_qcom_advertise_quirks(struct 
ufs_hba *hba)

hba->quirks |= UFSHCD_QUIRK_BROKEN_LCC;
}

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


Looks good to me.

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


Re: [PATCH v2 08/10] scsi: ufs: make sure all interrupts are processed

2018-05-16 Thread Subhash Jadavani

On 2018-05-03 04:07, Asutosh Das wrote:

From: Venkat Gopalakrishnan 

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

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

diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index c35a076..09b7a3f 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -5383,19 +5383,30 @@ static irqreturn_t ufshcd_intr(int irq, void 
*__hba)

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

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

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

-   if (enabled_intr_status) {
-   ufshcd_sl_intr(hba, enabled_intr_status);
-   retval = IRQ_HANDLED;
-   }
spin_unlock(hba->host->host_lock);
return retval;
 }


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 v2 06/10] scsi: ufs: add reference counting for scsi block requests

2018-05-16 Thread Subhash Jadavani

On 2018-05-03 04:07, Asutosh Das wrote:

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

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

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

Better solution would be to fix this by adding reference counting.

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

diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index dfeb194..c35a076 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -264,6 +264,18 @@ static inline void ufshcd_disable_irq(struct 
ufs_hba *hba)

}
 }

+static void ufshcd_scsi_unblock_requests(struct ufs_hba *hba)
+{
+   if (atomic_dec_and_test(>scsi_block_reqs_cnt))
+   scsi_unblock_requests(hba->host);
+}
+
+static void ufshcd_scsi_block_requests(struct ufs_hba *hba)
+{
+   if (atomic_inc_return(>scsi_block_reqs_cnt) == 1)
+   scsi_block_requests(hba->host);
+}
+
 /* replace non-printable or non-ASCII characters with spaces */
 static inline void ufshcd_remove_non_printable(char *val)
 {
@@ -1077,12 +1089,12 @@ static int ufshcd_clock_scaling_prepare(struct
ufs_hba *hba)
 * make sure that there are no outstanding requests when
 * clock scaling is in progress
 */
-   scsi_block_requests(hba->host);
+   ufshcd_scsi_block_requests(hba);
down_write(>clk_scaling_lock);
if (ufshcd_wait_for_doorbell_clr(hba, DOORBELL_CLR_TOUT_US)) {
ret = -EBUSY;
up_write(>clk_scaling_lock);
-   scsi_unblock_requests(hba->host);
+   ufshcd_scsi_unblock_requests(hba);
}

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

 /**
@@ -1411,7 +1423,7 @@ static void ufshcd_ungate_work(struct work_struct 
*work)

hba->clk_gating.is_suspended = false;
}
 unblock_reqs:
-   scsi_unblock_requests(hba->host);
+   ufshcd_scsi_unblock_requests(hba);
 }

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


 out:
spin_unlock_irqrestore(hba->host->host_lock, flags);
-   scsi_unblock_requests(hba->host);
+   ufshcd_scsi_unblock_requests(hba);
ufshcd_release(hba);
pm_runtime_put_sync(hba->dev);
 }
@@ -5294,7 +5306,7 @@ static void ufshcd_check_errors(struct ufs_hba 
*hba)

/* handle fatal errors only when link is functional */
if (hba->ufshcd_state == UFSHCD_STATE_OPERATIONAL) {
/* block commands from scsi mid-layer */
-   scsi_block_requests(hba->host);
+   ufshcd_scsi_block_requests(hba);

hba->ufshcd_state = UFSHCD_STATE_EH_SCHEDULED;

@@ -8017,7 +8029,7 @@ int ufshcd_init(struct ufs_hba *hba, void
__iomem *mmio_base, unsigned int irq)

/* Hold auto suspend until async scan completes */
pm_runtime_get_sync(dev);
-
+   atomic_set(>scsi_block_reqs_cnt, 0);
/*
 * We are assuming that device wasn't put in sleep/power-down
 * state exclusively during the boot stage before kernel.
diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h
index 0417c42..76c31d5 100644
--- a/drivers/scsi/ufs/ufshcd.h
+++ b/drivers/scsi/ufs/ufshcd.h
@@ -498,6 +498,7 @@ struct ufs_stats {
  * @urgent_bkops_lvl: keeps track of urgent bkops level for 

Re: [PATCH v2 06/10] scsi: ufs: add reference counting for scsi block requests

2018-05-16 Thread Subhash Jadavani

On 2018-05-03 04:07, Asutosh Das wrote:

From: Subhash Jadavani 

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

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

Better solution would be to fix this by adding reference counting.

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

diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index dfeb194..c35a076 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -264,6 +264,18 @@ static inline void ufshcd_disable_irq(struct 
ufs_hba *hba)

}
 }

+static void ufshcd_scsi_unblock_requests(struct ufs_hba *hba)
+{
+   if (atomic_dec_and_test(>scsi_block_reqs_cnt))
+   scsi_unblock_requests(hba->host);
+}
+
+static void ufshcd_scsi_block_requests(struct ufs_hba *hba)
+{
+   if (atomic_inc_return(>scsi_block_reqs_cnt) == 1)
+   scsi_block_requests(hba->host);
+}
+
 /* replace non-printable or non-ASCII characters with spaces */
 static inline void ufshcd_remove_non_printable(char *val)
 {
@@ -1077,12 +1089,12 @@ static int ufshcd_clock_scaling_prepare(struct
ufs_hba *hba)
 * make sure that there are no outstanding requests when
 * clock scaling is in progress
 */
-   scsi_block_requests(hba->host);
+   ufshcd_scsi_block_requests(hba);
down_write(>clk_scaling_lock);
if (ufshcd_wait_for_doorbell_clr(hba, DOORBELL_CLR_TOUT_US)) {
ret = -EBUSY;
up_write(>clk_scaling_lock);
-   scsi_unblock_requests(hba->host);
+   ufshcd_scsi_unblock_requests(hba);
}

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

 /**
@@ -1411,7 +1423,7 @@ static void ufshcd_ungate_work(struct work_struct 
*work)

hba->clk_gating.is_suspended = false;
}
 unblock_reqs:
-   scsi_unblock_requests(hba->host);
+   ufshcd_scsi_unblock_requests(hba);
 }

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


 out:
spin_unlock_irqrestore(hba->host->host_lock, flags);
-   scsi_unblock_requests(hba->host);
+   ufshcd_scsi_unblock_requests(hba);
ufshcd_release(hba);
pm_runtime_put_sync(hba->dev);
 }
@@ -5294,7 +5306,7 @@ static void ufshcd_check_errors(struct ufs_hba 
*hba)

/* handle fatal errors only when link is functional */
if (hba->ufshcd_state == UFSHCD_STATE_OPERATIONAL) {
/* block commands from scsi mid-layer */
-   scsi_block_requests(hba->host);
+   ufshcd_scsi_block_requests(hba);

hba->ufshcd_state = UFSHCD_STATE_EH_SCHEDULED;

@@ -8017,7 +8029,7 @@ int ufshcd_init(struct ufs_hba *hba, void
__iomem *mmio_base, unsigned int irq)

/* Hold auto suspend until async scan completes */
pm_runtime_get_sync(dev);
-
+   atomic_set(>scsi_block_reqs_cnt, 0);
/*
 * We are assuming that device wasn't put in sleep/power-down
 * state exclusively during the boot stage before kernel.
diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h
index 0417c42..76c31d5 100644
--- a/drivers/scsi/ufs/ufshcd.h
+++ b/drivers/scsi/ufs/ufshcd.h
@@ -498,6 +498,7 @@ struct ufs_stats {
  * @urgent_bkops_lvl: keeps track of urgent bkops level for device
  * @is_urgent_bkops_lvl_checked: keeps track if the urgent bkops level 
for

  *  device is known or not.
+ * @scsi

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

2018-05-16 Thread Subhash Jadavani

On 2018-05-03 04:07, Asutosh Das wrote:

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

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

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

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

diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index 838ba8f0..dfeb194 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -6780,9 +6780,16 @@ static int __ufshcd_setup_clocks(struct ufs_hba
*hba, bool on,
if (list_empty(head))
goto out;

-   ret = ufshcd_vops_setup_clocks(hba, on, PRE_CHANGE);
-   if (ret)
-   return ret;
+   /*
+* vendor specific setup_clocks ops may depend on clocks managed by
+* this standard driver hence call the vendor specific setup_clocks
+* before disabling the clocks managed here.
+*/
+   if (!on) {
+   ret = ufshcd_vops_setup_clocks(hba, on, PRE_CHANGE);
+   if (ret)
+   return ret;
+   }

list_for_each_entry(clki, head, list) {
if (!IS_ERR_OR_NULL(clki->clk)) {
@@ -6806,9 +6813,16 @@ static int __ufshcd_setup_clocks(struct ufs_hba
*hba, bool on,
}
}

-   ret = ufshcd_vops_setup_clocks(hba, on, POST_CHANGE);
-   if (ret)
-   return ret;
+   /*
+* vendor specific setup_clocks ops may depend on clocks managed by
+* this standard driver hence call the vendor specific setup_clocks
+* after enabling the clocks managed here.
+*/
+   if (on) {
+   ret = ufshcd_vops_setup_clocks(hba, on, POST_CHANGE);
+   if (ret)
+   return ret;
+   }

 out:
if (ret) {


Looks good to me.

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


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

2018-05-16 Thread Subhash Jadavani

On 2018-05-03 04:07, Asutosh Das wrote:

From: Subhash Jadavani 

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

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

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

diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index 838ba8f0..dfeb194 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -6780,9 +6780,16 @@ static int __ufshcd_setup_clocks(struct ufs_hba
*hba, bool on,
if (list_empty(head))
goto out;

-   ret = ufshcd_vops_setup_clocks(hba, on, PRE_CHANGE);
-   if (ret)
-   return ret;
+   /*
+* vendor specific setup_clocks ops may depend on clocks managed by
+* this standard driver hence call the vendor specific setup_clocks
+* before disabling the clocks managed here.
+*/
+   if (!on) {
+   ret = ufshcd_vops_setup_clocks(hba, on, PRE_CHANGE);
+   if (ret)
+   return ret;
+   }

list_for_each_entry(clki, head, list) {
if (!IS_ERR_OR_NULL(clki->clk)) {
@@ -6806,9 +6813,16 @@ static int __ufshcd_setup_clocks(struct ufs_hba
*hba, bool on,
}
}

-   ret = ufshcd_vops_setup_clocks(hba, on, POST_CHANGE);
-   if (ret)
-   return ret;
+   /*
+* vendor specific setup_clocks ops may depend on clocks managed by
+* this standard driver hence call the vendor specific setup_clocks
+* after enabling the clocks managed here.
+*/
+   if (on) {
+   ret = ufshcd_vops_setup_clocks(hba, on, POST_CHANGE);
+   if (ret)
+   return ret;
+   }

 out:
if (ret) {


Looks good to me.

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


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

2018-05-16 Thread Subhash Jadavani

On 2018-05-03 04:07, Asutosh Das wrote:

From: Maya Erez <me...@codeaurora.org>

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

handling and may not respond within the 100ms timeout.

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

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

diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index 6dabce8..838ba8f0 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -4967,6 +4967,7 @@ static void
ufshcd_exception_event_handler(struct work_struct *work)
hba = container_of(work, struct ufs_hba, eeh_work);

pm_runtime_get_sync(hba->dev);
+   scsi_block_requests(hba->host);
err = ufshcd_get_ee_status(hba, );
if (err) {
dev_err(hba->dev, "%s: failed to get exception status %d\n",
@@ -4980,6 +4981,7 @@ static void
ufshcd_exception_event_handler(struct work_struct *work)
ufshcd_bkops_exception_event_handler(hba);

 out:
+   scsi_unblock_requests(hba->host);
pm_runtime_put_sync(hba->dev);
    return;
 }


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 04/10] scsi: ufs: fix exception event handling

2018-05-16 Thread Subhash Jadavani

On 2018-05-03 04:07, Asutosh Das wrote:

From: Maya Erez 

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

handling and may not respond within the 100ms timeout.

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

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

diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index 6dabce8..838ba8f0 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -4967,6 +4967,7 @@ static void
ufshcd_exception_event_handler(struct work_struct *work)
hba = container_of(work, struct ufs_hba, eeh_work);

pm_runtime_get_sync(hba->dev);
+   scsi_block_requests(hba->host);
err = ufshcd_get_ee_status(hba, );
if (err) {
dev_err(hba->dev, "%s: failed to get exception status %d\n",
@@ -4980,6 +4981,7 @@ static void
ufshcd_exception_event_handler(struct work_struct *work)
ufshcd_bkops_exception_event_handler(hba);

 out:
+   scsi_unblock_requests(hba->host);
pm_runtime_put_sync(hba->dev);
return;
 }


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 v2 03/10] scsi: ufs: Add LCC quirk for host and device

2018-05-16 Thread Subhash Jadavani

On 2018-05-03 04:07, Asutosh Das wrote:

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

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

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

diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index f3083fe..6dabce8 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -4116,6 +4116,11 @@ static int ufshcd_disable_tx_lcc(struct ufs_hba
*hba, bool peer)
return err;
 }

+static inline int ufshcd_disable_host_tx_lcc(struct ufs_hba *hba)
+{
+   return ufshcd_disable_tx_lcc(hba, false);
+}
+
 static inline int ufshcd_disable_device_tx_lcc(struct ufs_hba *hba)
 {
return ufshcd_disable_tx_lcc(hba, true);
@@ -4172,6 +4177,17 @@ static int ufshcd_link_startup(struct ufs_hba 
*hba)

ufshcd_dme_set(hba, UIC_ARG_MIB(TX_LCC_ENABLE), 1);
}

+   if (hba->quirks & UFSHCD_BROKEN_LCC_PROCESSING_ON_HOST) {
+   ret = ufshcd_disable_device_tx_lcc(hba);
+   if (ret)
+   goto out;
+   }
+
+   if (hba->quirks & UFSHCD_BROKEN_LCC_PROCESSING_ON_DEVICE) {
+   ret = ufshcd_disable_host_tx_lcc(hba);
+   if (ret)
+   goto out;
+   }
if (link_startup_again) {
link_startup_again = false;
retries = DME_LINKSTARTUP_RETRIES;
diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h
index bb4ecfb..0417c42 100644
--- a/drivers/scsi/ufs/ufshcd.h
+++ b/drivers/scsi/ufs/ufshcd.h
@@ -598,6 +598,18 @@ struct ufs_hba {
 * TX_LCC.
 */
#define UFSHCD_QUIRK_BROKEN_PWR_MODE_CHANGE UFS_BIT(8)
+
+   /*
+* If UFS device is having issue in processing LCC (Line Control
+* Command) coming from UFS host controller then enable this quirk.
+* When this quirk is enabled, host controller driver should disable
+* the LCC transmission on UFS host controller (by clearing
+* TX_LCC_ENABLE attribute of host to 0).
+*/
+   #define UFSHCD_BROKEN_LCC_PROCESSING_ON_DEVICE  0x100
+
+   #define UFSHCD_BROKEN_LCC_PROCESSING_ON_HOST0x200
+
unsigned int quirks;/* Deviations from standard UFSHCI spec. */

/* Device deviations from standard UFS device spec. */


Please check if these quirks are really needed for commercial version of 
UFS host controllers.


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


Re: [PATCH v2 03/10] scsi: ufs: Add LCC quirk for host and device

2018-05-16 Thread Subhash Jadavani

On 2018-05-03 04:07, Asutosh Das wrote:

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

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

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

diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index f3083fe..6dabce8 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -4116,6 +4116,11 @@ static int ufshcd_disable_tx_lcc(struct ufs_hba
*hba, bool peer)
return err;
 }

+static inline int ufshcd_disable_host_tx_lcc(struct ufs_hba *hba)
+{
+   return ufshcd_disable_tx_lcc(hba, false);
+}
+
 static inline int ufshcd_disable_device_tx_lcc(struct ufs_hba *hba)
 {
return ufshcd_disable_tx_lcc(hba, true);
@@ -4172,6 +4177,17 @@ static int ufshcd_link_startup(struct ufs_hba 
*hba)

ufshcd_dme_set(hba, UIC_ARG_MIB(TX_LCC_ENABLE), 1);
}

+   if (hba->quirks & UFSHCD_BROKEN_LCC_PROCESSING_ON_HOST) {
+   ret = ufshcd_disable_device_tx_lcc(hba);
+   if (ret)
+   goto out;
+   }
+
+   if (hba->quirks & UFSHCD_BROKEN_LCC_PROCESSING_ON_DEVICE) {
+   ret = ufshcd_disable_host_tx_lcc(hba);
+   if (ret)
+   goto out;
+   }
if (link_startup_again) {
link_startup_again = false;
retries = DME_LINKSTARTUP_RETRIES;
diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h
index bb4ecfb..0417c42 100644
--- a/drivers/scsi/ufs/ufshcd.h
+++ b/drivers/scsi/ufs/ufshcd.h
@@ -598,6 +598,18 @@ struct ufs_hba {
 * TX_LCC.
 */
#define UFSHCD_QUIRK_BROKEN_PWR_MODE_CHANGE UFS_BIT(8)
+
+   /*
+* If UFS device is having issue in processing LCC (Line Control
+* Command) coming from UFS host controller then enable this quirk.
+* When this quirk is enabled, host controller driver should disable
+* the LCC transmission on UFS host controller (by clearing
+* TX_LCC_ENABLE attribute of host to 0).
+*/
+   #define UFSHCD_BROKEN_LCC_PROCESSING_ON_DEVICE  0x100
+
+   #define UFSHCD_BROKEN_LCC_PROCESSING_ON_HOST0x200
+
unsigned int quirks;/* Deviations from standard UFSHCI spec. */

/* Device deviations from standard UFS device spec. */


Please check if these quirks are really needed for commercial version of 
UFS host controllers.


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


Re: [PATCH v2 02/10] scsi: ufs-qcom: Enable UFSHCD_QUIRK_BROKEN_PWR_MODE_CHANGE quirk

2018-05-16 Thread Subhash Jadavani

On 2018-05-03 04:07, Asutosh Das wrote:

Enable UFSHCD_QUIRK_BROKEN_PWR_MODE_CHANGE quirk to avoid failures
in seen on some UFS devices.

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

diff --git a/drivers/scsi/ufs/ufs-qcom.c b/drivers/scsi/ufs/ufs-qcom.c
index 4563d2e..d9edef8 100644
--- a/drivers/scsi/ufs/ufs-qcom.c
+++ b/drivers/scsi/ufs/ufs-qcom.c
@@ -1105,7 +1105,7 @@ static void ufs_qcom_advertise_quirks(struct 
ufs_hba *hba)


if (host->hw_ver.major >= 0x2) {
hba->quirks |= UFSHCD_QUIRK_BROKEN_UFS_HCI_VERSION;
-
+   hba->quirks |= UFSHCD_QUIRK_BROKEN_PWR_MODE_CHANGE;
if (!ufs_qcom_cap_qunipro(host))
/* Legacy UniPro mode still need following quirks */
hba->quirks |= (UFSHCD_QUIRK_DELAY_BEFORE_DME_CMDS


We may not need this.

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


Re: [PATCH v2 02/10] scsi: ufs-qcom: Enable UFSHCD_QUIRK_BROKEN_PWR_MODE_CHANGE quirk

2018-05-16 Thread Subhash Jadavani

On 2018-05-03 04:07, Asutosh Das wrote:

Enable UFSHCD_QUIRK_BROKEN_PWR_MODE_CHANGE quirk to avoid failures
in seen on some UFS devices.

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

diff --git a/drivers/scsi/ufs/ufs-qcom.c b/drivers/scsi/ufs/ufs-qcom.c
index 4563d2e..d9edef8 100644
--- a/drivers/scsi/ufs/ufs-qcom.c
+++ b/drivers/scsi/ufs/ufs-qcom.c
@@ -1105,7 +1105,7 @@ static void ufs_qcom_advertise_quirks(struct 
ufs_hba *hba)


if (host->hw_ver.major >= 0x2) {
hba->quirks |= UFSHCD_QUIRK_BROKEN_UFS_HCI_VERSION;
-
+   hba->quirks |= UFSHCD_QUIRK_BROKEN_PWR_MODE_CHANGE;
if (!ufs_qcom_cap_qunipro(host))
/* Legacy UniPro mode still need following quirks */
hba->quirks |= (UFSHCD_QUIRK_DELAY_BEFORE_DME_CMDS


We may not need this.

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


Re: [PATCH v2 01/10] scsi: ufs: Allowing power mode change

2018-05-16 Thread Subhash Jadavani

On 2018-05-03 04:07, Asutosh Das wrote:

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

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

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

diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index 5bc9dc1..f3083fe 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -4162,9 +4162,15 @@ static int ufshcd_link_startup(struct ufs_hba 
*hba)

goto out;
} while (ret && retries--);

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

if (link_startup_again) {
link_startup_again = false;
diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h
index cbe46f6..bb4ecfb 100644
--- a/drivers/scsi/ufs/ufshcd.h
+++ b/drivers/scsi/ufs/ufshcd.h
@@ -591,6 +591,13 @@ struct ufs_hba {
 */
#define UFSHCD_QUIRK_PRDT_BYTE_GRAN UFS_BIT(7)

+   /*
+	 * Needs to be enabled if moving from HS to any other gear/mode or 
even

+* hibern8 causes unpredicted behavior of device.
+* If this quirk is enabled, standard UFS driver will disable/enable
+* TX_LCC.
+*/
+   #define UFSHCD_QUIRK_BROKEN_PWR_MODE_CHANGE UFS_BIT(8)
unsigned int quirks;/* Deviations from standard UFSHCI spec. */

/* Device deviations from standard UFS device spec. */


This was probably needed in early generation of UFS devices (non 
commercial) and may not be really needed now. I believe we can skip this 
patch.


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


Re: [PATCH v2 01/10] scsi: ufs: Allowing power mode change

2018-05-16 Thread Subhash Jadavani

On 2018-05-03 04:07, Asutosh Das wrote:

From: Yaniv Gardi 

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

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

diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index 5bc9dc1..f3083fe 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -4162,9 +4162,15 @@ static int ufshcd_link_startup(struct ufs_hba 
*hba)

goto out;
} while (ret && retries--);

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

if (link_startup_again) {
link_startup_again = false;
diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h
index cbe46f6..bb4ecfb 100644
--- a/drivers/scsi/ufs/ufshcd.h
+++ b/drivers/scsi/ufs/ufshcd.h
@@ -591,6 +591,13 @@ struct ufs_hba {
 */
#define UFSHCD_QUIRK_PRDT_BYTE_GRAN UFS_BIT(7)

+   /*
+	 * Needs to be enabled if moving from HS to any other gear/mode or 
even

+* hibern8 causes unpredicted behavior of device.
+* If this quirk is enabled, standard UFS driver will disable/enable
+* TX_LCC.
+*/
+   #define UFSHCD_QUIRK_BROKEN_PWR_MODE_CHANGE UFS_BIT(8)
unsigned int quirks;/* Deviations from standard UFSHCI spec. */

/* Device deviations from standard UFS device spec. */


This was probably needed in early generation of UFS devices (non 
commercial) and may not be really needed now. I believe we can skip this 
patch.


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


Re: [PATCH] scsi: ufs: ufshcd: Remove VLA usage

2018-05-16 Thread Subhash Jadavani

On 2018-05-02 16:58, Kees Cook wrote:

On the quest to remove all VLAs from the kernel[1] this moves buffers
off the stack. In the second instance, this collapses two separately
allocated buffers into a single buffer, since they are used 
consecutively,

which saves 256 bytes (QUERY_DESC_MAX_SIZE + 1) of stack space.

[1]
https://lkml.kernel.org/r/CA+55aFzCG-zNmZwX4A2FQpadafLfEzK6CC=qpxydaacu1rq...@mail.gmail.com

Signed-off-by: Kees Cook <keesc...@chromium.org>
---
 drivers/scsi/ufs/ufshcd.c | 34 ++
 1 file changed, 26 insertions(+), 8 deletions(-)

diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index 00e79057f870..a271534362f6 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -5958,14 +5958,18 @@ static void ufshcd_init_icc_levels(struct 
ufs_hba *hba)

 {
int ret;
int buff_len = hba->desc_size.pwr_desc;
-   u8 desc_buf[hba->desc_size.pwr_desc];
+   u8 *desc_buf;
+
+   desc_buf = kmalloc(buff_len, GFP_KERNEL);
+   if (!desc_buf)
+   return;

ret = ufshcd_read_power_desc(hba, desc_buf, buff_len);
if (ret) {
dev_err(hba->dev,
"%s: Failed reading power descriptor.len = %d ret = %d",
__func__, buff_len, ret);
-   return;
+   goto out;
}

hba->init_prefetch_data.icc_level =
@@ -5983,6 +5987,8 @@ static void ufshcd_init_icc_levels(struct ufs_hba 
*hba)

"%s: Failed configuring bActiveICCLevel = %d ret = %d",
__func__, hba->init_prefetch_data.icc_level , ret);

+out:
+   kfree(desc_buf);
 }

 /**
@@ -6052,9 +6058,17 @@ static int ufs_get_device_desc(struct ufs_hba 
*hba,

   struct ufs_dev_desc *dev_desc)
 {
int err;
+   size_t buff_len;
u8 model_index;
-   u8 str_desc_buf[QUERY_DESC_MAX_SIZE + 1] = {0};
-   u8 desc_buf[hba->desc_size.dev_desc];
+   u8 *desc_buf;
+
+   buff_len = max_t(size_t, hba->desc_size.dev_desc,
+QUERY_DESC_MAX_SIZE + 1);
+   desc_buf = kmalloc(buff_len, GFP_KERNEL);
+   if (!desc_buf) {
+   err = -ENOMEM;
+   goto out;
+   }

 	err = ufshcd_read_device_desc(hba, desc_buf, 
hba->desc_size.dev_desc);

if (err) {
@@ -6072,7 +6086,10 @@ static int ufs_get_device_desc(struct ufs_hba 
*hba,


model_index = desc_buf[DEVICE_DESC_PARAM_PRDCT_NAME];

-   err = ufshcd_read_string_desc(hba, model_index, str_desc_buf,
+   /* Zero-pad entire buffer for string termination. */
+   memset(desc_buf, 0, buff_len);
+
+   err = ufshcd_read_string_desc(hba, model_index, desc_buf,
  QUERY_DESC_MAX_SIZE, true/*ASCII*/);
if (err) {
dev_err(hba->dev, "%s: Failed reading Product Name. err = %d\n",
@@ -6080,15 +6097,16 @@ static int ufs_get_device_desc(struct ufs_hba 
*hba,

goto out;
}

-   str_desc_buf[QUERY_DESC_MAX_SIZE] = '\0';
-   strlcpy(dev_desc->model, (str_desc_buf + QUERY_DESC_HDR_SIZE),
-   min_t(u8, str_desc_buf[QUERY_DESC_LENGTH_OFFSET],
+   desc_buf[QUERY_DESC_MAX_SIZE] = '\0';
+   strlcpy(dev_desc->model, (desc_buf + QUERY_DESC_HDR_SIZE),
+   min_t(u8, desc_buf[QUERY_DESC_LENGTH_OFFSET],
  MAX_MODEL_LEN));

/* Null terminate the model string */
dev_desc->model[MAX_MODEL_LEN] = '\0';

 out:
+   kfree(desc_buf);
    return err;
 }

--
2.17.0



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] scsi: ufs: ufshcd: Remove VLA usage

2018-05-16 Thread Subhash Jadavani

On 2018-05-02 16:58, Kees Cook wrote:

On the quest to remove all VLAs from the kernel[1] this moves buffers
off the stack. In the second instance, this collapses two separately
allocated buffers into a single buffer, since they are used 
consecutively,

which saves 256 bytes (QUERY_DESC_MAX_SIZE + 1) of stack space.

[1]
https://lkml.kernel.org/r/CA+55aFzCG-zNmZwX4A2FQpadafLfEzK6CC=qpxydaacu1rq...@mail.gmail.com

Signed-off-by: Kees Cook 
---
 drivers/scsi/ufs/ufshcd.c | 34 ++
 1 file changed, 26 insertions(+), 8 deletions(-)

diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index 00e79057f870..a271534362f6 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -5958,14 +5958,18 @@ static void ufshcd_init_icc_levels(struct 
ufs_hba *hba)

 {
int ret;
int buff_len = hba->desc_size.pwr_desc;
-   u8 desc_buf[hba->desc_size.pwr_desc];
+   u8 *desc_buf;
+
+   desc_buf = kmalloc(buff_len, GFP_KERNEL);
+   if (!desc_buf)
+   return;

ret = ufshcd_read_power_desc(hba, desc_buf, buff_len);
if (ret) {
dev_err(hba->dev,
"%s: Failed reading power descriptor.len = %d ret = %d",
__func__, buff_len, ret);
-   return;
+   goto out;
}

hba->init_prefetch_data.icc_level =
@@ -5983,6 +5987,8 @@ static void ufshcd_init_icc_levels(struct ufs_hba 
*hba)

"%s: Failed configuring bActiveICCLevel = %d ret = %d",
__func__, hba->init_prefetch_data.icc_level , ret);

+out:
+   kfree(desc_buf);
 }

 /**
@@ -6052,9 +6058,17 @@ static int ufs_get_device_desc(struct ufs_hba 
*hba,

   struct ufs_dev_desc *dev_desc)
 {
int err;
+   size_t buff_len;
u8 model_index;
-   u8 str_desc_buf[QUERY_DESC_MAX_SIZE + 1] = {0};
-   u8 desc_buf[hba->desc_size.dev_desc];
+   u8 *desc_buf;
+
+   buff_len = max_t(size_t, hba->desc_size.dev_desc,
+QUERY_DESC_MAX_SIZE + 1);
+   desc_buf = kmalloc(buff_len, GFP_KERNEL);
+   if (!desc_buf) {
+   err = -ENOMEM;
+   goto out;
+   }

 	err = ufshcd_read_device_desc(hba, desc_buf, 
hba->desc_size.dev_desc);

if (err) {
@@ -6072,7 +6086,10 @@ static int ufs_get_device_desc(struct ufs_hba 
*hba,


model_index = desc_buf[DEVICE_DESC_PARAM_PRDCT_NAME];

-   err = ufshcd_read_string_desc(hba, model_index, str_desc_buf,
+   /* Zero-pad entire buffer for string termination. */
+   memset(desc_buf, 0, buff_len);
+
+   err = ufshcd_read_string_desc(hba, model_index, desc_buf,
  QUERY_DESC_MAX_SIZE, true/*ASCII*/);
if (err) {
dev_err(hba->dev, "%s: Failed reading Product Name. err = %d\n",
@@ -6080,15 +6097,16 @@ static int ufs_get_device_desc(struct ufs_hba 
*hba,

goto out;
}

-   str_desc_buf[QUERY_DESC_MAX_SIZE] = '\0';
-   strlcpy(dev_desc->model, (str_desc_buf + QUERY_DESC_HDR_SIZE),
-   min_t(u8, str_desc_buf[QUERY_DESC_LENGTH_OFFSET],
+   desc_buf[QUERY_DESC_MAX_SIZE] = '\0';
+   strlcpy(dev_desc->model, (desc_buf + QUERY_DESC_HDR_SIZE),
+   min_t(u8, desc_buf[QUERY_DESC_LENGTH_OFFSET],
  MAX_MODEL_LEN));

/* Null terminate the model string */
dev_desc->model[MAX_MODEL_LEN] = '\0';

 out:
+   kfree(desc_buf);
    return err;
 }

--
2.17.0



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 3/3] scsi: ufs: Use freq table with devfreq

2018-04-24 Thread Subhash Jadavani

On 2018-04-23 17:20, Bjorn Andersson wrote:

devfreq requires that the client operates on actual frequencies, not
only 0 and UMAX_INT and as such UFS brok with the introduction of
f1d981eaecf8 ("PM / devfreq: Use the available min/max frequency").

This patch registers the frequencies of the first clock with devfreq 
and

use these to determine if we're trying to step up or down.

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

diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index 2253f24309ec..07b1f3c7bd2d 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -1168,16 +1168,13 @@ static int ufshcd_devfreq_target(struct device 
*dev,

struct ufs_hba *hba = dev_get_drvdata(dev);
ktime_t start;
bool scale_up, sched_clk_scaling_suspend_work = false;
+   struct list_head *clk_list = >clk_list_head;
+   struct ufs_clk_info *clki;
unsigned long irq_flags;

if (!ufshcd_is_clkscaling_supported(hba))
return -EINVAL;

-   if ((*freq > 0) && (*freq < UINT_MAX)) {
-   dev_err(hba->dev, "%s: invalid freq = %lu\n", __func__, *freq);
-   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);
@@ -1187,7 +1184,13 @@ static int ufshcd_devfreq_target(struct device 
*dev,

if (!hba->clk_scaling.active_reqs)
sched_clk_scaling_suspend_work = true;

-   scale_up = (*freq == UINT_MAX) ? true : false;
+   if (list_empty(clk_list)) {
+   spin_unlock_irqrestore(hba->host->host_lock, irq_flags);
+   goto out;
+   }
+
+	clki = list_first_entry(>clk_list_head, struct ufs_clk_info, 
list);

+   scale_up = (*freq == clki->max_freq) ? true : false;
if (!ufshcd_is_devfreq_scaling_required(hba, scale_up)) {
spin_unlock_irqrestore(hba->host->host_lock, irq_flags);
ret = 0;
@@ -1257,11 +1260,33 @@ static struct devfreq_dev_profile
ufs_devfreq_profile = {

 static int ufshcd_devfreq_init(struct ufs_hba *hba)
 {
+   struct devfreq_dev_profile *profile;
+   struct list_head *clk_list = >clk_list_head;
+   struct ufs_clk_info *clki;
struct devfreq *devfreq;
int ret;

+   /* Skip devfreq if we don't have any clocks in the list */
+   if (list_empty(clk_list))
+   return 0;
+
+   profile = devm_kmemdup(hba->dev, _devfreq_profile,
+  sizeof(ufs_devfreq_profile), GFP_KERNEL);
+   if (!profile)
+   return -ENOMEM;
+
+   profile->max_state = 2;
+   profile->freq_table = devm_kcalloc(hba->dev, profile->max_state,
+  sizeof(unsigned long), GFP_KERNEL);
+   if (!profile->freq_table)
+   return -ENOMEM;
+
+	clki = list_first_entry(>clk_list_head, struct ufs_clk_info, 
list);

+   profile->freq_table[0] = clki->min_freq;
+   profile->freq_table[1] = clki->max_freq;
+
devfreq = devm_devfreq_add_device(hba->dev,
-   _devfreq_profile,
+   profile,
"simple_ondemand",
NULL);
if (IS_ERR(devfreq)) {


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 3/3] scsi: ufs: Use freq table with devfreq

2018-04-24 Thread Subhash Jadavani

On 2018-04-23 17:20, Bjorn Andersson wrote:

devfreq requires that the client operates on actual frequencies, not
only 0 and UMAX_INT and as such UFS brok with the introduction of
f1d981eaecf8 ("PM / devfreq: Use the available min/max frequency").

This patch registers the frequencies of the first clock with devfreq 
and

use these to determine if we're trying to step up or down.

Signed-off-by: Bjorn Andersson 
---
 drivers/scsi/ufs/ufshcd.c | 39 ---
 1 file changed, 32 insertions(+), 7 deletions(-)

diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index 2253f24309ec..07b1f3c7bd2d 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -1168,16 +1168,13 @@ static int ufshcd_devfreq_target(struct device 
*dev,

struct ufs_hba *hba = dev_get_drvdata(dev);
ktime_t start;
bool scale_up, sched_clk_scaling_suspend_work = false;
+   struct list_head *clk_list = >clk_list_head;
+   struct ufs_clk_info *clki;
unsigned long irq_flags;

if (!ufshcd_is_clkscaling_supported(hba))
return -EINVAL;

-   if ((*freq > 0) && (*freq < UINT_MAX)) {
-   dev_err(hba->dev, "%s: invalid freq = %lu\n", __func__, *freq);
-   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);
@@ -1187,7 +1184,13 @@ static int ufshcd_devfreq_target(struct device 
*dev,

if (!hba->clk_scaling.active_reqs)
sched_clk_scaling_suspend_work = true;

-   scale_up = (*freq == UINT_MAX) ? true : false;
+   if (list_empty(clk_list)) {
+   spin_unlock_irqrestore(hba->host->host_lock, irq_flags);
+   goto out;
+   }
+
+	clki = list_first_entry(>clk_list_head, struct ufs_clk_info, 
list);

+   scale_up = (*freq == clki->max_freq) ? true : false;
if (!ufshcd_is_devfreq_scaling_required(hba, scale_up)) {
spin_unlock_irqrestore(hba->host->host_lock, irq_flags);
ret = 0;
@@ -1257,11 +1260,33 @@ static struct devfreq_dev_profile
ufs_devfreq_profile = {

 static int ufshcd_devfreq_init(struct ufs_hba *hba)
 {
+   struct devfreq_dev_profile *profile;
+   struct list_head *clk_list = >clk_list_head;
+   struct ufs_clk_info *clki;
struct devfreq *devfreq;
int ret;

+   /* Skip devfreq if we don't have any clocks in the list */
+   if (list_empty(clk_list))
+   return 0;
+
+   profile = devm_kmemdup(hba->dev, _devfreq_profile,
+  sizeof(ufs_devfreq_profile), GFP_KERNEL);
+   if (!profile)
+   return -ENOMEM;
+
+   profile->max_state = 2;
+   profile->freq_table = devm_kcalloc(hba->dev, profile->max_state,
+  sizeof(unsigned long), GFP_KERNEL);
+   if (!profile->freq_table)
+   return -ENOMEM;
+
+	clki = list_first_entry(>clk_list_head, struct ufs_clk_info, 
list);

+   profile->freq_table[0] = clki->min_freq;
+   profile->freq_table[1] = clki->max_freq;
+
devfreq = devm_devfreq_add_device(hba->dev,
-   _devfreq_profile,
+   profile,
"simple_ondemand",
NULL);
if (IS_ERR(devfreq)) {


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 2/3] scsi: ufs: Extract devfreq registration

2018-04-24 Thread Subhash Jadavani

On 2018-04-23 17:20, Bjorn Andersson wrote:

Failing to register with devfreq leaves hba->devfreq assigned, which
causes the error path to dereference the ERR_PTR(). Rather than bolting
on more conditionals, move the call of devm_devfreq_add_device() into
it's own function and only update hba->devfreq once it's successfully
registered.

The subsequent patch builds upon this to make UFS actually work again,
as it's been broken since f1d981eaecf8 ("PM / devfreq: Use the 
available

min/max frequency")

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

diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index 8f22a980b1a7..2253f24309ec 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -1255,6 +1255,26 @@ static struct devfreq_dev_profile 
ufs_devfreq_profile = {

.get_dev_status = ufshcd_devfreq_get_dev_status,
 };

+static int ufshcd_devfreq_init(struct ufs_hba *hba)
+{
+   struct devfreq *devfreq;
+   int ret;
+
+   devfreq = devm_devfreq_add_device(hba->dev,
+   _devfreq_profile,
+   "simple_ondemand",
+   NULL);
+   if (IS_ERR(devfreq)) {
+   ret = PTR_ERR(devfreq);
+   dev_err(hba->dev, "Unable to register with devfreq %d\n", ret);
+   return ret;
+   }
+
+   hba->devfreq = devfreq;
+
+   return 0;
+}
+
 static void __ufshcd_suspend_clkscaling(struct ufs_hba *hba)
 {
unsigned long flags;
@@ -6399,16 +6419,9 @@ static int ufshcd_probe_hba(struct ufs_hba *hba)
sizeof(struct ufs_pa_layer_attr));
hba->clk_scaling.saved_pwr_info.is_valid = true;
if (!hba->devfreq) {
-   hba->devfreq = devm_devfreq_add_device(hba->dev,
-   _devfreq_profile,
-   "simple_ondemand",
-   NULL);
-   if (IS_ERR(hba->devfreq)) {
-   ret = PTR_ERR(hba->devfreq);
-   dev_err(hba->dev, "Unable to register with 
devfreq %d\n",
-   ret);
+   ret = ufshcd_devfreq_init(hba);
+   if (ret)
goto out;
-   }
}
    hba->clk_scaling.is_allowed = true;
}


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 2/3] scsi: ufs: Extract devfreq registration

2018-04-24 Thread Subhash Jadavani

On 2018-04-23 17:20, Bjorn Andersson wrote:

Failing to register with devfreq leaves hba->devfreq assigned, which
causes the error path to dereference the ERR_PTR(). Rather than bolting
on more conditionals, move the call of devm_devfreq_add_device() into
it's own function and only update hba->devfreq once it's successfully
registered.

The subsequent patch builds upon this to make UFS actually work again,
as it's been broken since f1d981eaecf8 ("PM / devfreq: Use the 
available

min/max frequency")

Signed-off-by: Bjorn Andersson 
---
 drivers/scsi/ufs/ufshcd.c | 31 ++-
 1 file changed, 22 insertions(+), 9 deletions(-)

diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index 8f22a980b1a7..2253f24309ec 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -1255,6 +1255,26 @@ static struct devfreq_dev_profile 
ufs_devfreq_profile = {

.get_dev_status = ufshcd_devfreq_get_dev_status,
 };

+static int ufshcd_devfreq_init(struct ufs_hba *hba)
+{
+   struct devfreq *devfreq;
+   int ret;
+
+   devfreq = devm_devfreq_add_device(hba->dev,
+   _devfreq_profile,
+   "simple_ondemand",
+   NULL);
+   if (IS_ERR(devfreq)) {
+   ret = PTR_ERR(devfreq);
+   dev_err(hba->dev, "Unable to register with devfreq %d\n", ret);
+   return ret;
+   }
+
+   hba->devfreq = devfreq;
+
+   return 0;
+}
+
 static void __ufshcd_suspend_clkscaling(struct ufs_hba *hba)
 {
unsigned long flags;
@@ -6399,16 +6419,9 @@ static int ufshcd_probe_hba(struct ufs_hba *hba)
sizeof(struct ufs_pa_layer_attr));
hba->clk_scaling.saved_pwr_info.is_valid = true;
if (!hba->devfreq) {
-   hba->devfreq = devm_devfreq_add_device(hba->dev,
-   _devfreq_profile,
-   "simple_ondemand",
-   NULL);
-   if (IS_ERR(hba->devfreq)) {
-   ret = PTR_ERR(hba->devfreq);
-   dev_err(hba->dev, "Unable to register with 
devfreq %d\n",
-   ret);
+   ret = ufshcd_devfreq_init(hba);
+   if (ret)
goto out;
-   }
}
hba->clk_scaling.is_allowed = true;
}


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 1/1] scsi: ufs: fix exception event handling

2018-02-08 Thread Subhash Jadavani

On 2018-01-28 20:34, Asutosh Das wrote:

From: Maya Erez <me...@codeaurora.org>

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

handling and may not respond within the 100ms timeout.

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

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

diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index 8af2af3..2dd488f 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -4955,6 +4955,7 @@ static void
ufshcd_exception_event_handler(struct work_struct *work)
hba = container_of(work, struct ufs_hba, eeh_work);

pm_runtime_get_sync(hba->dev);
+   scsi_block_requests(hba->host);
err = ufshcd_get_ee_status(hba, );
if (err) {
dev_err(hba->dev, "%s: failed to get exception status %d\n",
@@ -4968,6 +4969,7 @@ static void
ufshcd_exception_event_handler(struct work_struct *work)
ufshcd_bkops_exception_event_handler(hba);

 out:
+   scsi_unblock_requests(hba->host);
pm_runtime_put_sync(hba->dev);
    return;
 }


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 1/1] scsi: ufs: fix exception event handling

2018-02-08 Thread Subhash Jadavani

On 2018-01-28 20:34, Asutosh Das wrote:

From: Maya Erez 

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

handling and may not respond within the 100ms timeout.

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

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

diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index 8af2af3..2dd488f 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -4955,6 +4955,7 @@ static void
ufshcd_exception_event_handler(struct work_struct *work)
hba = container_of(work, struct ufs_hba, eeh_work);

pm_runtime_get_sync(hba->dev);
+   scsi_block_requests(hba->host);
err = ufshcd_get_ee_status(hba, );
if (err) {
dev_err(hba->dev, "%s: failed to get exception status %d\n",
@@ -4968,6 +4969,7 @@ static void
ufshcd_exception_event_handler(struct work_struct *work)
ufshcd_bkops_exception_event_handler(hba);

 out:
+   scsi_unblock_requests(hba->host);
pm_runtime_put_sync(hba->dev);
return;
 }


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] phy: qcom-ufs: add missing MODULE_DESCRIPTION/LICENSE

2017-11-21 Thread Subhash Jadavani

On 2017-11-20 13:33, Jesse Chan wrote:

This change resolves a new compile-time warning
when built as a loadable module:

WARNING: modpost: missing MODULE_LICENSE() in
drivers/phy/qualcomm/phy-qcom-ufs.o
see include/linux/module.h for more information

This adds the license as "GPL v2", which matches the header of the 
file.


MODULE_DESCRIPTION is also added.

Signed-off-by: Jesse Chan <j...@linux.com>
---
 drivers/phy/qualcomm/phy-qcom-ufs.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/drivers/phy/qualcomm/phy-qcom-ufs.c
b/drivers/phy/qualcomm/phy-qcom-ufs.c
index c5ff4525edef..124dc70f6986 100644
--- a/drivers/phy/qualcomm/phy-qcom-ufs.c
+++ b/drivers/phy/qualcomm/phy-qcom-ufs.c
@@ -675,3 +675,6 @@ int ufs_qcom_phy_power_off(struct phy *generic_phy)
return 0;
 }
 EXPORT_SYMBOL_GPL(ufs_qcom_phy_power_off);
+
+MODULE_DESCRIPTION("Universal Flash Storage (UFS) QCOM PHY");
+MODULE_LICENSE("GPL v2");


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] phy: qcom-ufs: add missing MODULE_DESCRIPTION/LICENSE

2017-11-21 Thread Subhash Jadavani

On 2017-11-20 13:33, Jesse Chan wrote:

This change resolves a new compile-time warning
when built as a loadable module:

WARNING: modpost: missing MODULE_LICENSE() in
drivers/phy/qualcomm/phy-qcom-ufs.o
see include/linux/module.h for more information

This adds the license as "GPL v2", which matches the header of the 
file.


MODULE_DESCRIPTION is also added.

Signed-off-by: Jesse Chan 
---
 drivers/phy/qualcomm/phy-qcom-ufs.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/drivers/phy/qualcomm/phy-qcom-ufs.c
b/drivers/phy/qualcomm/phy-qcom-ufs.c
index c5ff4525edef..124dc70f6986 100644
--- a/drivers/phy/qualcomm/phy-qcom-ufs.c
+++ b/drivers/phy/qualcomm/phy-qcom-ufs.c
@@ -675,3 +675,6 @@ int ufs_qcom_phy_power_off(struct phy *generic_phy)
return 0;
 }
 EXPORT_SYMBOL_GPL(ufs_qcom_phy_power_off);
+
+MODULE_DESCRIPTION("Universal Flash Storage (UFS) QCOM PHY");
+MODULE_LICENSE("GPL v2");


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] scsi: ufs: ufshcd: fix potential NULL pointer dereference in ufshcd_config_vreg

2017-11-21 Thread Subhash Jadavani

On 2017-11-20 06:12, Gustavo A. R. Silva wrote:
_vreg_ is being dereferenced before it is null checked, hence there is 
a

potential null pointer dereference.

Fix this by moving the pointer dereference after _vreg_ has been null
checked.

This issue was detected with the help of Coccinelle.

Fixes: aa4976130934 ("ufs: Add regulator enable support")
Signed-off-by: Gustavo A. R. Silva <garsi...@embeddedor.com>
---
 drivers/scsi/ufs/ufshcd.c | 7 +--
 1 file changed, 5 insertions(+), 2 deletions(-)

diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index 011c336..a355d98 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -6559,12 +6559,15 @@ static int ufshcd_config_vreg(struct device 
*dev,

struct ufs_vreg *vreg, bool on)
 {
int ret = 0;
-   struct regulator *reg = vreg->reg;
-   const char *name = vreg->name;
+   struct regulator *reg;
+   const char *name;
int min_uV, uA_load;

BUG_ON(!vreg);

+   reg = vreg->reg;
+   name = vreg->name;
+
if (regulator_count_voltages(reg) > 0) {
min_uV = on ? vreg->min_uV : 0;
ret = regulator_set_voltage(reg, min_uV, vreg->max_uV);


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] scsi: ufs: ufshcd: fix potential NULL pointer dereference in ufshcd_config_vreg

2017-11-21 Thread Subhash Jadavani

On 2017-11-20 06:12, Gustavo A. R. Silva wrote:
_vreg_ is being dereferenced before it is null checked, hence there is 
a

potential null pointer dereference.

Fix this by moving the pointer dereference after _vreg_ has been null
checked.

This issue was detected with the help of Coccinelle.

Fixes: aa4976130934 ("ufs: Add regulator enable support")
Signed-off-by: Gustavo A. R. Silva 
---
 drivers/scsi/ufs/ufshcd.c | 7 +--
 1 file changed, 5 insertions(+), 2 deletions(-)

diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index 011c336..a355d98 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -6559,12 +6559,15 @@ static int ufshcd_config_vreg(struct device 
*dev,

struct ufs_vreg *vreg, bool on)
 {
int ret = 0;
-   struct regulator *reg = vreg->reg;
-   const char *name = vreg->name;
+   struct regulator *reg;
+   const char *name;
int min_uV, uA_load;

BUG_ON(!vreg);

+   reg = vreg->reg;
+   name = vreg->name;
+
if (regulator_count_voltages(reg) > 0) {
min_uV = on ? vreg->min_uV : 0;
ret = regulator_set_voltage(reg, min_uV, vreg->max_uV);


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 v2 5/5] ufs/phy: qcom: Refactor to use phy_init call

2017-10-13 Thread Subhash Jadavani
t = 
%d\n",
-   __func__, ret);
-
ufs_qcom_select_unipro_mode(host);

+   return 0;
+
+out_disable_phy:
+   ufs_qcom_assert_reset(hba);
+   phy_exit(phy);
 out:
return ret;
 }
@@ -1276,14 +1277,9 @@ static int ufs_qcom_init(struct ufs_hba *hba)
ufs_qcom_phy_save_controller_version(host->generic_phy,
host->hw_ver.major, host->hw_ver.minor, host->hw_ver.step);

-   phy_init(host->generic_phy);
-   err = phy_power_on(host->generic_phy);
-   if (err)
-   goto out_unregister_bus;
-
err = ufs_qcom_init_lane_clks(host);
if (err)
-   goto out_disable_phy;
+   goto out_variant_clear;

ufs_qcom_set_caps(hba);
ufs_qcom_advertise_quirks(hba);
@@ -1304,10 +1300,6 @@ static int ufs_qcom_init(struct ufs_hba *hba)

goto out;

-out_disable_phy:
-   phy_power_off(host->generic_phy);
-out_unregister_bus:
-   phy_exit(host->generic_phy);
 out_variant_clear:
ufshcd_set_variant(hba, NULL);
 out:
diff --git a/include/linux/phy/phy-qcom-ufs.h 
b/include/linux/phy/phy-qcom-ufs.h

index 35c070ea6ea3..0a2c18a9771d 100644
--- a/include/linux/phy/phy-qcom-ufs.h
+++ b/include/linux/phy/phy-qcom-ufs.h
@@ -31,10 +31,7 @@
  */
 void ufs_qcom_phy_disable_dev_ref_clk(struct phy *phy);

-int ufs_qcom_phy_start_serdes(struct phy *phy);
 int ufs_qcom_phy_set_tx_lane_enable(struct phy *phy, u32 tx_lanes);
-int ufs_qcom_phy_calibrate_phy(struct phy *phy, bool is_rate_B);
-int ufs_qcom_phy_is_pcs_ready(struct phy *phy);
 void ufs_qcom_phy_save_controller_version(struct phy *phy,
u8 major, u16 minor, u16 step);


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 5/5] ufs/phy: qcom: Refactor to use phy_init call

2017-10-13 Thread Subhash Jadavani
 __func__, ret);
-
ufs_qcom_select_unipro_mode(host);

+   return 0;
+
+out_disable_phy:
+   ufs_qcom_assert_reset(hba);
+   phy_exit(phy);
 out:
return ret;
 }
@@ -1276,14 +1277,9 @@ static int ufs_qcom_init(struct ufs_hba *hba)
ufs_qcom_phy_save_controller_version(host->generic_phy,
host->hw_ver.major, host->hw_ver.minor, host->hw_ver.step);

-   phy_init(host->generic_phy);
-   err = phy_power_on(host->generic_phy);
-   if (err)
-   goto out_unregister_bus;
-
err = ufs_qcom_init_lane_clks(host);
if (err)
-   goto out_disable_phy;
+   goto out_variant_clear;

ufs_qcom_set_caps(hba);
ufs_qcom_advertise_quirks(hba);
@@ -1304,10 +1300,6 @@ static int ufs_qcom_init(struct ufs_hba *hba)

goto out;

-out_disable_phy:
-   phy_power_off(host->generic_phy);
-out_unregister_bus:
-   phy_exit(host->generic_phy);
 out_variant_clear:
ufshcd_set_variant(hba, NULL);
 out:
diff --git a/include/linux/phy/phy-qcom-ufs.h 
b/include/linux/phy/phy-qcom-ufs.h

index 35c070ea6ea3..0a2c18a9771d 100644
--- a/include/linux/phy/phy-qcom-ufs.h
+++ b/include/linux/phy/phy-qcom-ufs.h
@@ -31,10 +31,7 @@
  */
 void ufs_qcom_phy_disable_dev_ref_clk(struct phy *phy);

-int ufs_qcom_phy_start_serdes(struct phy *phy);
 int ufs_qcom_phy_set_tx_lane_enable(struct phy *phy, u32 tx_lanes);
-int ufs_qcom_phy_calibrate_phy(struct phy *phy, bool is_rate_B);
-int ufs_qcom_phy_is_pcs_ready(struct phy *phy);
 void ufs_qcom_phy_save_controller_version(struct phy *phy,
u8 major, u16 minor, u16 step);


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 5/5] ufs/phy: qcom: Refactor to use phy_init call

2017-09-26 Thread Subhash Jadavani

Hi Vivek,

Please find one comment inline below, rest look good.

Regards,
Subhash

On 2017-08-03 23:48, Vivek Gautam wrote:

Refactor ufs_qcom_power_up_sequence() to get rid of ugly
exported phy APIs and use the phy_init() and phy_power_on()
to do the phy initialization.

Signed-off-by: Vivek Gautam 
---
 drivers/phy/qualcomm/phy-qcom-ufs-i.h|  2 --
 drivers/phy/qualcomm/phy-qcom-ufs-qmp-14nm.c |  9 +--
 drivers/phy/qualcomm/phy-qcom-ufs-qmp-20nm.c |  9 +--
 drivers/phy/qualcomm/phy-qcom-ufs.c  | 38 

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

 include/linux/phy/phy-qcom-ufs.h |  3 ---
 6 files changed, 38 insertions(+), 59 deletions(-)

diff --git a/drivers/phy/qualcomm/phy-qcom-ufs-i.h
b/drivers/phy/qualcomm/phy-qcom-ufs-i.h
index 94326ed107c3..495fd5941231 100644
--- a/drivers/phy/qualcomm/phy-qcom-ufs-i.h
+++ b/drivers/phy/qualcomm/phy-qcom-ufs-i.h
@@ -123,7 +123,6 @@ struct ufs_qcom_phy {
  * struct ufs_qcom_phy_specific_ops - set of pointers to functions 
which have a

  * specific implementation per phy. Each UFS phy, should implement
  * those functions according to its spec and requirements
- * @calibrate_phy: pointer to a function that calibrate the phy
  * @start_serdes: pointer to a function that starts the serdes
  * @is_physical_coding_sublayer_ready: pointer to a function that
  * checks pcs readiness. returns 0 for success and non-zero for error.
@@ -132,7 +131,6 @@ struct ufs_qcom_phy {
  * and writes to QSERDES_RX_SIGDET_CNTRL attribute
  */
 struct ufs_qcom_phy_specific_ops {
-   int (*calibrate_phy)(struct ufs_qcom_phy *phy, bool is_rate_B);
void (*start_serdes)(struct ufs_qcom_phy *phy);
int (*is_physical_coding_sublayer_ready)(struct ufs_qcom_phy *phy);
void (*set_tx_lane_enable)(struct ufs_qcom_phy *phy, u32 val);
diff --git a/drivers/phy/qualcomm/phy-qcom-ufs-qmp-14nm.c
b/drivers/phy/qualcomm/phy-qcom-ufs-qmp-14nm.c
index af65785230b5..c39440b56b6d 100644
--- a/drivers/phy/qualcomm/phy-qcom-ufs-qmp-14nm.c
+++ b/drivers/phy/qualcomm/phy-qcom-ufs-qmp-14nm.c
@@ -44,7 +44,13 @@ void ufs_qcom_phy_qmp_14nm_advertise_quirks(struct
ufs_qcom_phy *phy_common)

 static int ufs_qcom_phy_qmp_14nm_init(struct phy *generic_phy)
 {
-   return 0;
+   struct ufs_qcom_phy *phy_common = get_ufs_qcom_phy(generic_phy);
+   bool is_rate_B = false;
+
+   if (phy_common->mode == PHY_MODE_UFS_HS_B)
+   is_rate_B = true;
+
+   return ufs_qcom_phy_qmp_14nm_phy_calibrate(phy_common, is_rate_B);
 }

 static int ufs_qcom_phy_qmp_14nm_exit(struct phy *generic_phy)
@@ -120,7 +126,6 @@ static int
ufs_qcom_phy_qmp_14nm_is_pcs_ready(struct ufs_qcom_phy *phy_common)
 };

 static struct ufs_qcom_phy_specific_ops phy_14nm_ops = {
-   .calibrate_phy  = ufs_qcom_phy_qmp_14nm_phy_calibrate,
.start_serdes   = ufs_qcom_phy_qmp_14nm_start_serdes,
 	.is_physical_coding_sublayer_ready = 
ufs_qcom_phy_qmp_14nm_is_pcs_ready,

.set_tx_lane_enable = ufs_qcom_phy_qmp_14nm_set_tx_lane_enable,
diff --git a/drivers/phy/qualcomm/phy-qcom-ufs-qmp-20nm.c
b/drivers/phy/qualcomm/phy-qcom-ufs-qmp-20nm.c
index 5c18c41dbdb4..5705a2d4c6d2 100644
--- a/drivers/phy/qualcomm/phy-qcom-ufs-qmp-20nm.c
+++ b/drivers/phy/qualcomm/phy-qcom-ufs-qmp-20nm.c
@@ -63,7 +63,13 @@ void ufs_qcom_phy_qmp_20nm_advertise_quirks(struct
ufs_qcom_phy *phy_common)

 static int ufs_qcom_phy_qmp_20nm_init(struct phy *generic_phy)
 {
-   return 0;
+   struct ufs_qcom_phy *phy_common = get_ufs_qcom_phy(generic_phy);
+   bool is_rate_B = false;
+
+   if (phy_common->mode == PHY_MODE_UFS_HS_B)
+   is_rate_B = true;
+
+   return ufs_qcom_phy_qmp_20nm_phy_calibrate(phy_common, is_rate_B);
 }

 static int ufs_qcom_phy_qmp_20nm_exit(struct phy *generic_phy)
@@ -178,7 +184,6 @@ static int
ufs_qcom_phy_qmp_20nm_is_pcs_ready(struct ufs_qcom_phy *phy_common)
 };

 static struct ufs_qcom_phy_specific_ops phy_20nm_ops = {
-   .calibrate_phy  = ufs_qcom_phy_qmp_20nm_phy_calibrate,
.start_serdes   = ufs_qcom_phy_qmp_20nm_start_serdes,
 	.is_physical_coding_sublayer_ready = 
ufs_qcom_phy_qmp_20nm_is_pcs_ready,

.set_tx_lane_enable = ufs_qcom_phy_qmp_20nm_set_tx_lane_enable,
diff --git a/drivers/phy/qualcomm/phy-qcom-ufs.c
b/drivers/phy/qualcomm/phy-qcom-ufs.c
index 43865ef340e2..1febe3294fe3 100644
--- a/drivers/phy/qualcomm/phy-qcom-ufs.c
+++ b/drivers/phy/qualcomm/phy-qcom-ufs.c
@@ -518,9 +518,8 @@ void ufs_qcom_phy_disable_iface_clk(struct
ufs_qcom_phy *phy)
}
 }

-int ufs_qcom_phy_start_serdes(struct phy *generic_phy)
+static int ufs_qcom_phy_start_serdes(struct ufs_qcom_phy 
*ufs_qcom_phy)

 {
-   struct ufs_qcom_phy *ufs_qcom_phy = get_ufs_qcom_phy(generic_phy);
int ret = 0;

if (!ufs_qcom_phy->phy_spec_ops->start_serdes) {
@@ -533,7 +532,6 @@ int 

Re: [PATCH 5/5] ufs/phy: qcom: Refactor to use phy_init call

2017-09-26 Thread Subhash Jadavani

Hi Vivek,

Please find one comment inline below, rest look good.

Regards,
Subhash

On 2017-08-03 23:48, Vivek Gautam wrote:

Refactor ufs_qcom_power_up_sequence() to get rid of ugly
exported phy APIs and use the phy_init() and phy_power_on()
to do the phy initialization.

Signed-off-by: Vivek Gautam 
---
 drivers/phy/qualcomm/phy-qcom-ufs-i.h|  2 --
 drivers/phy/qualcomm/phy-qcom-ufs-qmp-14nm.c |  9 +--
 drivers/phy/qualcomm/phy-qcom-ufs-qmp-20nm.c |  9 +--
 drivers/phy/qualcomm/phy-qcom-ufs.c  | 38 

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

 include/linux/phy/phy-qcom-ufs.h |  3 ---
 6 files changed, 38 insertions(+), 59 deletions(-)

diff --git a/drivers/phy/qualcomm/phy-qcom-ufs-i.h
b/drivers/phy/qualcomm/phy-qcom-ufs-i.h
index 94326ed107c3..495fd5941231 100644
--- a/drivers/phy/qualcomm/phy-qcom-ufs-i.h
+++ b/drivers/phy/qualcomm/phy-qcom-ufs-i.h
@@ -123,7 +123,6 @@ struct ufs_qcom_phy {
  * struct ufs_qcom_phy_specific_ops - set of pointers to functions 
which have a

  * specific implementation per phy. Each UFS phy, should implement
  * those functions according to its spec and requirements
- * @calibrate_phy: pointer to a function that calibrate the phy
  * @start_serdes: pointer to a function that starts the serdes
  * @is_physical_coding_sublayer_ready: pointer to a function that
  * checks pcs readiness. returns 0 for success and non-zero for error.
@@ -132,7 +131,6 @@ struct ufs_qcom_phy {
  * and writes to QSERDES_RX_SIGDET_CNTRL attribute
  */
 struct ufs_qcom_phy_specific_ops {
-   int (*calibrate_phy)(struct ufs_qcom_phy *phy, bool is_rate_B);
void (*start_serdes)(struct ufs_qcom_phy *phy);
int (*is_physical_coding_sublayer_ready)(struct ufs_qcom_phy *phy);
void (*set_tx_lane_enable)(struct ufs_qcom_phy *phy, u32 val);
diff --git a/drivers/phy/qualcomm/phy-qcom-ufs-qmp-14nm.c
b/drivers/phy/qualcomm/phy-qcom-ufs-qmp-14nm.c
index af65785230b5..c39440b56b6d 100644
--- a/drivers/phy/qualcomm/phy-qcom-ufs-qmp-14nm.c
+++ b/drivers/phy/qualcomm/phy-qcom-ufs-qmp-14nm.c
@@ -44,7 +44,13 @@ void ufs_qcom_phy_qmp_14nm_advertise_quirks(struct
ufs_qcom_phy *phy_common)

 static int ufs_qcom_phy_qmp_14nm_init(struct phy *generic_phy)
 {
-   return 0;
+   struct ufs_qcom_phy *phy_common = get_ufs_qcom_phy(generic_phy);
+   bool is_rate_B = false;
+
+   if (phy_common->mode == PHY_MODE_UFS_HS_B)
+   is_rate_B = true;
+
+   return ufs_qcom_phy_qmp_14nm_phy_calibrate(phy_common, is_rate_B);
 }

 static int ufs_qcom_phy_qmp_14nm_exit(struct phy *generic_phy)
@@ -120,7 +126,6 @@ static int
ufs_qcom_phy_qmp_14nm_is_pcs_ready(struct ufs_qcom_phy *phy_common)
 };

 static struct ufs_qcom_phy_specific_ops phy_14nm_ops = {
-   .calibrate_phy  = ufs_qcom_phy_qmp_14nm_phy_calibrate,
.start_serdes   = ufs_qcom_phy_qmp_14nm_start_serdes,
 	.is_physical_coding_sublayer_ready = 
ufs_qcom_phy_qmp_14nm_is_pcs_ready,

.set_tx_lane_enable = ufs_qcom_phy_qmp_14nm_set_tx_lane_enable,
diff --git a/drivers/phy/qualcomm/phy-qcom-ufs-qmp-20nm.c
b/drivers/phy/qualcomm/phy-qcom-ufs-qmp-20nm.c
index 5c18c41dbdb4..5705a2d4c6d2 100644
--- a/drivers/phy/qualcomm/phy-qcom-ufs-qmp-20nm.c
+++ b/drivers/phy/qualcomm/phy-qcom-ufs-qmp-20nm.c
@@ -63,7 +63,13 @@ void ufs_qcom_phy_qmp_20nm_advertise_quirks(struct
ufs_qcom_phy *phy_common)

 static int ufs_qcom_phy_qmp_20nm_init(struct phy *generic_phy)
 {
-   return 0;
+   struct ufs_qcom_phy *phy_common = get_ufs_qcom_phy(generic_phy);
+   bool is_rate_B = false;
+
+   if (phy_common->mode == PHY_MODE_UFS_HS_B)
+   is_rate_B = true;
+
+   return ufs_qcom_phy_qmp_20nm_phy_calibrate(phy_common, is_rate_B);
 }

 static int ufs_qcom_phy_qmp_20nm_exit(struct phy *generic_phy)
@@ -178,7 +184,6 @@ static int
ufs_qcom_phy_qmp_20nm_is_pcs_ready(struct ufs_qcom_phy *phy_common)
 };

 static struct ufs_qcom_phy_specific_ops phy_20nm_ops = {
-   .calibrate_phy  = ufs_qcom_phy_qmp_20nm_phy_calibrate,
.start_serdes   = ufs_qcom_phy_qmp_20nm_start_serdes,
 	.is_physical_coding_sublayer_ready = 
ufs_qcom_phy_qmp_20nm_is_pcs_ready,

.set_tx_lane_enable = ufs_qcom_phy_qmp_20nm_set_tx_lane_enable,
diff --git a/drivers/phy/qualcomm/phy-qcom-ufs.c
b/drivers/phy/qualcomm/phy-qcom-ufs.c
index 43865ef340e2..1febe3294fe3 100644
--- a/drivers/phy/qualcomm/phy-qcom-ufs.c
+++ b/drivers/phy/qualcomm/phy-qcom-ufs.c
@@ -518,9 +518,8 @@ void ufs_qcom_phy_disable_iface_clk(struct
ufs_qcom_phy *phy)
}
 }

-int ufs_qcom_phy_start_serdes(struct phy *generic_phy)
+static int ufs_qcom_phy_start_serdes(struct ufs_qcom_phy 
*ufs_qcom_phy)

 {
-   struct ufs_qcom_phy *ufs_qcom_phy = get_ufs_qcom_phy(generic_phy);
int ret = 0;

if (!ufs_qcom_phy->phy_spec_ops->start_serdes) {
@@ -533,7 +532,6 @@ int ufs_qcom_phy_start_serdes(struct phy 

Re: [PATCH 4/5] scsi/ufs: qcom: Set phy mode based on the controllers HS MODE

2017-09-26 Thread Subhash Jadavani

On 2017-08-03 23:48, Vivek Gautam wrote:

Set the phy mode based on the UFS HS PA mode. This lets the
controller let phy know the mode in which the PHY Adapter is
running and set the phy rates accordingly.

Signed-off-by: Vivek Gautam <vivek.gau...@codeaurora.org>
---
 drivers/scsi/ufs/ufs-qcom.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/drivers/scsi/ufs/ufs-qcom.c b/drivers/scsi/ufs/ufs-qcom.c
index c87d770b519a..44c21d5818ee 100644
--- a/drivers/scsi/ufs/ufs-qcom.c
+++ b/drivers/scsi/ufs/ufs-qcom.c
@@ -273,6 +273,9 @@ static int ufs_qcom_power_up_sequence(struct 
ufs_hba *hba)

bool is_rate_B = (UFS_QCOM_LIMIT_HS_RATE == PA_HS_MODE_B)
? true : false;

+   if (is_rate_B)
+   phy_set_mode(phy, PHY_MODE_UFS_HS_B);
+
/* Assert PHY reset and apply PHY calibration values */
ufs_qcom_assert_reset(hba);
/* provide 1ms delay to let the reset pulse propagate */


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 4/5] scsi/ufs: qcom: Set phy mode based on the controllers HS MODE

2017-09-26 Thread Subhash Jadavani

On 2017-08-03 23:48, Vivek Gautam wrote:

Set the phy mode based on the UFS HS PA mode. This lets the
controller let phy know the mode in which the PHY Adapter is
running and set the phy rates accordingly.

Signed-off-by: Vivek Gautam 
---
 drivers/scsi/ufs/ufs-qcom.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/drivers/scsi/ufs/ufs-qcom.c b/drivers/scsi/ufs/ufs-qcom.c
index c87d770b519a..44c21d5818ee 100644
--- a/drivers/scsi/ufs/ufs-qcom.c
+++ b/drivers/scsi/ufs/ufs-qcom.c
@@ -273,6 +273,9 @@ static int ufs_qcom_power_up_sequence(struct 
ufs_hba *hba)

bool is_rate_B = (UFS_QCOM_LIMIT_HS_RATE == PA_HS_MODE_B)
? true : false;

+   if (is_rate_B)
+   phy_set_mode(phy, PHY_MODE_UFS_HS_B);
+
/* Assert PHY reset and apply PHY calibration values */
ufs_qcom_assert_reset(hba);
/* provide 1ms delay to let the reset pulse propagate */


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] scsi: ufs: fix wrong command type of UTRD for UFSHCI v2.1

2017-09-26 Thread Subhash Jadavani

On 2017-09-06 02:58, kehuanlin wrote:
Since the command type of UTRD in UFS 2.1 specification is the same 
with
UFS 2.0. And it assumes the future UFS specification will follow the 
same

definition.

Signed-off-by: kehuanlin <kehuan...@pinecone.net>
---
 drivers/scsi/ufs/ufshcd.c | 14 --
 1 file changed, 8 insertions(+), 6 deletions(-)

diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index 5bc9dc1..c33a2f8 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -2195,10 +2195,11 @@ static int ufshcd_comp_devman_upiu(struct
ufs_hba *hba, struct ufshcd_lrb *lrbp)
u32 upiu_flags;
int ret = 0;

-   if (hba->ufs_version == UFSHCI_VERSION_20)
-   lrbp->command_type = UTP_CMD_TYPE_UFS_STORAGE;
-   else
+   if ((hba->ufs_version == UFSHCI_VERSION_10) ||
+   (hba->ufs_version == UFSHCI_VERSION_11))
lrbp->command_type = UTP_CMD_TYPE_DEV_MANAGE;
+   else
+   lrbp->command_type = UTP_CMD_TYPE_UFS_STORAGE;

ufshcd_prepare_req_desc_hdr(lrbp, _flags, DMA_NONE);
if (hba->dev_cmd.type == DEV_CMD_TYPE_QUERY)
@@ -,10 +2223,11 @@ static int ufshcd_comp_scsi_upiu(struct
ufs_hba *hba, struct ufshcd_lrb *lrbp)
u32 upiu_flags;
int ret = 0;

-   if (hba->ufs_version == UFSHCI_VERSION_20)
-   lrbp->command_type = UTP_CMD_TYPE_UFS_STORAGE;
-   else
+   if ((hba->ufs_version == UFSHCI_VERSION_10) ||
+   (hba->ufs_version == UFSHCI_VERSION_11))
lrbp->command_type = UTP_CMD_TYPE_SCSI;
+   else
+   lrbp->command_type = UTP_CMD_TYPE_UFS_STORAGE;

if (likely(lrbp->cmd)) {
ufshcd_prepare_req_desc_hdr(lrbp, _flags,


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] scsi: ufs: fix wrong command type of UTRD for UFSHCI v2.1

2017-09-26 Thread Subhash Jadavani

On 2017-09-06 02:58, kehuanlin wrote:
Since the command type of UTRD in UFS 2.1 specification is the same 
with
UFS 2.0. And it assumes the future UFS specification will follow the 
same

definition.

Signed-off-by: kehuanlin 
---
 drivers/scsi/ufs/ufshcd.c | 14 --
 1 file changed, 8 insertions(+), 6 deletions(-)

diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index 5bc9dc1..c33a2f8 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -2195,10 +2195,11 @@ static int ufshcd_comp_devman_upiu(struct
ufs_hba *hba, struct ufshcd_lrb *lrbp)
u32 upiu_flags;
int ret = 0;

-   if (hba->ufs_version == UFSHCI_VERSION_20)
-   lrbp->command_type = UTP_CMD_TYPE_UFS_STORAGE;
-   else
+   if ((hba->ufs_version == UFSHCI_VERSION_10) ||
+   (hba->ufs_version == UFSHCI_VERSION_11))
lrbp->command_type = UTP_CMD_TYPE_DEV_MANAGE;
+   else
+   lrbp->command_type = UTP_CMD_TYPE_UFS_STORAGE;

ufshcd_prepare_req_desc_hdr(lrbp, _flags, DMA_NONE);
if (hba->dev_cmd.type == DEV_CMD_TYPE_QUERY)
@@ -,10 +2223,11 @@ static int ufshcd_comp_scsi_upiu(struct
ufs_hba *hba, struct ufshcd_lrb *lrbp)
u32 upiu_flags;
int ret = 0;

-   if (hba->ufs_version == UFSHCI_VERSION_20)
-   lrbp->command_type = UTP_CMD_TYPE_UFS_STORAGE;
-   else
+   if ((hba->ufs_version == UFSHCI_VERSION_10) ||
+   (hba->ufs_version == UFSHCI_VERSION_11))
lrbp->command_type = UTP_CMD_TYPE_SCSI;
+   else
+   lrbp->command_type = UTP_CMD_TYPE_UFS_STORAGE;

if (likely(lrbp->cmd)) {
ufshcd_prepare_req_desc_hdr(lrbp, _flags,


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] scsi: ufs: continue to boot even with Boot LUN is disabled

2017-09-26 Thread Subhash Jadavani

On 2017-09-22 03:31, Huanlin Ke wrote:

Several configurable fields of the Device Descriptor and the Unit
Descriptors determine the Boot LUN status. The bBootEnable field and
the bBootLunEn attribute is set to zero by default, so the Boot LUN is
disabled by default.

At which point the scsi device add for Boot LUN will fail, but we can
continue to use the ufs device in fact. This failure shouldn't abort 
the

device boot.

Signed-off-by: Huanlin Ke <kehuan...@pinecone.net>
---
 drivers/scsi/ufs/ufshcd.c | 19 ---
 1 file changed, 8 insertions(+), 11 deletions(-)

diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index 794a460..bff84be 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -5998,25 +5998,22 @@ static int ufshcd_scsi_add_wlus(struct ufs_hba 
*hba)

}
scsi_device_put(hba->sdev_ufs_device);

-   sdev_boot = __scsi_add_device(hba->host, 0, 0,
-   ufshcd_upiu_wlun_to_scsi_wlun(UFS_UPIU_BOOT_WLUN), NULL);
-   if (IS_ERR(sdev_boot)) {
-   ret = PTR_ERR(sdev_boot);
-   goto remove_sdev_ufs_device;
-   }
-   scsi_device_put(sdev_boot);
-
sdev_rpmb = __scsi_add_device(hba->host, 0, 0,
ufshcd_upiu_wlun_to_scsi_wlun(UFS_UPIU_RPMB_WLUN), NULL);
if (IS_ERR(sdev_rpmb)) {
ret = PTR_ERR(sdev_rpmb);
-   goto remove_sdev_boot;
+   goto remove_sdev_ufs_device;
}
scsi_device_put(sdev_rpmb);
+
+   sdev_boot = __scsi_add_device(hba->host, 0, 0,
+   ufshcd_upiu_wlun_to_scsi_wlun(UFS_UPIU_BOOT_WLUN), NULL);
+   if (IS_ERR(sdev_boot))
+   dev_err(hba->dev, "%s: BOOT WLUN not found\n", __func__);
+   else
+   scsi_device_put(sdev_boot);
goto out;

-remove_sdev_boot:
-   scsi_remove_device(sdev_boot);
 remove_sdev_ufs_device:
scsi_remove_device(hba->sdev_ufs_device);
 out:


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] scsi: ufs: continue to boot even with Boot LUN is disabled

2017-09-26 Thread Subhash Jadavani

On 2017-09-22 03:31, Huanlin Ke wrote:

Several configurable fields of the Device Descriptor and the Unit
Descriptors determine the Boot LUN status. The bBootEnable field and
the bBootLunEn attribute is set to zero by default, so the Boot LUN is
disabled by default.

At which point the scsi device add for Boot LUN will fail, but we can
continue to use the ufs device in fact. This failure shouldn't abort 
the

device boot.

Signed-off-by: Huanlin Ke 
---
 drivers/scsi/ufs/ufshcd.c | 19 ---
 1 file changed, 8 insertions(+), 11 deletions(-)

diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index 794a460..bff84be 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -5998,25 +5998,22 @@ static int ufshcd_scsi_add_wlus(struct ufs_hba 
*hba)

}
scsi_device_put(hba->sdev_ufs_device);

-   sdev_boot = __scsi_add_device(hba->host, 0, 0,
-   ufshcd_upiu_wlun_to_scsi_wlun(UFS_UPIU_BOOT_WLUN), NULL);
-   if (IS_ERR(sdev_boot)) {
-   ret = PTR_ERR(sdev_boot);
-   goto remove_sdev_ufs_device;
-   }
-   scsi_device_put(sdev_boot);
-
sdev_rpmb = __scsi_add_device(hba->host, 0, 0,
ufshcd_upiu_wlun_to_scsi_wlun(UFS_UPIU_RPMB_WLUN), NULL);
if (IS_ERR(sdev_rpmb)) {
ret = PTR_ERR(sdev_rpmb);
-   goto remove_sdev_boot;
+   goto remove_sdev_ufs_device;
}
scsi_device_put(sdev_rpmb);
+
+   sdev_boot = __scsi_add_device(hba->host, 0, 0,
+   ufshcd_upiu_wlun_to_scsi_wlun(UFS_UPIU_BOOT_WLUN), NULL);
+   if (IS_ERR(sdev_boot))
+   dev_err(hba->dev, "%s: BOOT WLUN not found\n", __func__);
+   else
+   scsi_device_put(sdev_boot);
goto out;

-remove_sdev_boot:
-   scsi_remove_device(sdev_boot);
 remove_sdev_ufs_device:
scsi_remove_device(hba->sdev_ufs_device);
 out:


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 v2 2/5] dt-bindings: scsi: ufs: add document for hi3660-ufs

2017-06-22 Thread Subhash Jadavani

On 2017-06-22 04:51, Arnd Bergmann wrote:

On Thu, Jun 22, 2017 at 1:44 PM, Bu Tao  wrote:

在 2017/6/17 5:51, Arnd Bergmann 写道:

On Fri, Jun 16, 2017 at 8:51 AM, Bu Tao  wrote:

+Optional properties for board device:
+- ufs-hi3660-use-rate-B: specifies UFS rate-B
+- ufs-hi3660-broken-fastauto   : specifies no fastauto
+- ufs-hi3660-use-HS-GEAR3  : specifies UFS HS-GEAR3
+- ufs-hi3660-use-HS-GEAR2  : specifies UFS HS-GEAR2
+- ufs-hi3660-use-HS-GEAR1  : specifies UFS HS-GEAR1
+- ufs-hi3660-broken-clk-gate-bypass: specifies no clk-gate
+- ufs-hi3660-use-one-line  : specifies UFS use one line work
+- reset-gpio   : specifies to reset devices



Some of these sound rather generic and might apply to UFS 
implementations
other than hi3660, so I'd suggest adding them to the base ufs binding 
with

a generic name instead.

Any DT properties that might be useful across multiple 
implementations

should be parsed in generic code that gets called by the individual
drivers,
and then the properties that are specific to the integration work 
done by
hisilicon should be prefixed with "hisilicon,", but not normally with 
the
SoC name: it is quite possible that another SoC will be derived from 
this

chip and it should reuse the properties.



I do not know wheher other SoC need to use the optional properties as
abover. So here the name of the optional properties has "hi3660".


They should not have "hi3660" in their names either way, independent
of where they are used.



Yes, i agree with Arnd that SoCs might also need these so please make 
these properties generic (put them under 
Documentation/devicetree/bindings/ufs/ufshcd-pltfrm.txt) and also move 
their parsing code in generic driver (ufshcd.c or ufshcd-pltfrm.c).




(note: this is different from the value of the "compatible" property 
that

is meant to be as specific as possible".

Also, please clarify how your binding relates to the ufshcd binding
in Documentation/devicetree/bindings/ufs/ufshcd-pltfrm.txt: does
hi3660 implement any registers that are shared with ufshcd, or does
it use the same physical interface with a different register set?


No, only show how to use the dt-binding for hi3660 SoC


My question was about the hardware: does hi3660 implement ufshcd
or not?

  Arnd


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


Re: [PATCH v2 2/5] dt-bindings: scsi: ufs: add document for hi3660-ufs

2017-06-22 Thread Subhash Jadavani

On 2017-06-22 04:51, Arnd Bergmann wrote:

On Thu, Jun 22, 2017 at 1:44 PM, Bu Tao  wrote:

在 2017/6/17 5:51, Arnd Bergmann 写道:

On Fri, Jun 16, 2017 at 8:51 AM, Bu Tao  wrote:

+Optional properties for board device:
+- ufs-hi3660-use-rate-B: specifies UFS rate-B
+- ufs-hi3660-broken-fastauto   : specifies no fastauto
+- ufs-hi3660-use-HS-GEAR3  : specifies UFS HS-GEAR3
+- ufs-hi3660-use-HS-GEAR2  : specifies UFS HS-GEAR2
+- ufs-hi3660-use-HS-GEAR1  : specifies UFS HS-GEAR1
+- ufs-hi3660-broken-clk-gate-bypass: specifies no clk-gate
+- ufs-hi3660-use-one-line  : specifies UFS use one line work
+- reset-gpio   : specifies to reset devices



Some of these sound rather generic and might apply to UFS 
implementations
other than hi3660, so I'd suggest adding them to the base ufs binding 
with

a generic name instead.

Any DT properties that might be useful across multiple 
implementations

should be parsed in generic code that gets called by the individual
drivers,
and then the properties that are specific to the integration work 
done by
hisilicon should be prefixed with "hisilicon,", but not normally with 
the
SoC name: it is quite possible that another SoC will be derived from 
this

chip and it should reuse the properties.



I do not know wheher other SoC need to use the optional properties as
abover. So here the name of the optional properties has "hi3660".


They should not have "hi3660" in their names either way, independent
of where they are used.



Yes, i agree with Arnd that SoCs might also need these so please make 
these properties generic (put them under 
Documentation/devicetree/bindings/ufs/ufshcd-pltfrm.txt) and also move 
their parsing code in generic driver (ufshcd.c or ufshcd-pltfrm.c).




(note: this is different from the value of the "compatible" property 
that

is meant to be as specific as possible".

Also, please clarify how your binding relates to the ufshcd binding
in Documentation/devicetree/bindings/ufs/ufshcd-pltfrm.txt: does
hi3660 implement any registers that are shared with ufshcd, or does
it use the same physical interface with a different register set?


No, only show how to use the dt-binding for hi3660 SoC


My question was about the hardware: does hi3660 implement ufshcd
or not?

  Arnd


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


Re: [PATCH 1/3] scsi:ufs:add AHIT for hi3660 ufs

2017-06-12 Thread Subhash Jadavani

On 2017-06-09 18:20, butao wrote:

add Auto-Hibernate Idle Timer value for hi3660 ufs

Signed-off-by: Bu Tao 
Signed-off-by: Geng Jianfeng 
Signed-off-by: Zang Leigang 
Signed-off-by: Yu Jianfeng 
---
 drivers/scsi/ufs/ufshci.h | 3 +++
 1 file changed, 3 insertions(+)
 mode change 100644 => 100755 drivers/scsi/ufs/ufshci.h

diff --git a/drivers/scsi/ufs/ufshci.h b/drivers/scsi/ufs/ufshci.h
old mode 100644
new mode 100755
index f60145d4a66e..5ab9dfe4280e
--- a/drivers/scsi/ufs/ufshci.h
+++ b/drivers/scsi/ufs/ufshci.h
@@ -151,6 +151,9 @@ enum {
CONTROLLER_FATAL_ERROR |\
SYSTEM_BUS_FATAL_ERROR)

+/* AHIT - Auto-Hibernate Idle Timer */
+#define UFS_AHIT_AH8ITV_MASK   0x3FF


This should be added only when we would need it in the driver.


+
 /* HCS - Host Controller Status 30h */
 #define DEVICE_PRESENT UFS_BIT(0)
 #define UTP_TRANSFER_REQ_LIST_READYUFS_BIT(1)


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


Re: [PATCH 1/3] scsi:ufs:add AHIT for hi3660 ufs

2017-06-12 Thread Subhash Jadavani

On 2017-06-09 18:20, butao wrote:

add Auto-Hibernate Idle Timer value for hi3660 ufs

Signed-off-by: Bu Tao 
Signed-off-by: Geng Jianfeng 
Signed-off-by: Zang Leigang 
Signed-off-by: Yu Jianfeng 
---
 drivers/scsi/ufs/ufshci.h | 3 +++
 1 file changed, 3 insertions(+)
 mode change 100644 => 100755 drivers/scsi/ufs/ufshci.h

diff --git a/drivers/scsi/ufs/ufshci.h b/drivers/scsi/ufs/ufshci.h
old mode 100644
new mode 100755
index f60145d4a66e..5ab9dfe4280e
--- a/drivers/scsi/ufs/ufshci.h
+++ b/drivers/scsi/ufs/ufshci.h
@@ -151,6 +151,9 @@ enum {
CONTROLLER_FATAL_ERROR |\
SYSTEM_BUS_FATAL_ERROR)

+/* AHIT - Auto-Hibernate Idle Timer */
+#define UFS_AHIT_AH8ITV_MASK   0x3FF


This should be added only when we would need it in the driver.


+
 /* HCS - Host Controller Status 30h */
 #define DEVICE_PRESENT UFS_BIT(0)
 #define UTP_TRANSFER_REQ_LIST_READYUFS_BIT(1)


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


Re: [PATCH 2/2] scsi: ufshcd-intel-pci: Add PCI driver for Intel Host controllers

2017-06-05 Thread Subhash Jadavani

On 2017-06-05 01:36, Adrian Hunter wrote:

From: Szymon Mielczarek 

This patch adds a glue pci driver for Intel UFS Host controllers.

Signed-off-by: Szymon Mielczarek 
Signed-off-by: Adrian Hunter 
---
 drivers/scsi/ufs/Kconfig|  11 +++
 drivers/scsi/ufs/Makefile   |   1 +
 drivers/scsi/ufs/ufshcd-intel-pci.c | 183 


 3 files changed, 195 insertions(+)
 create mode 100644 drivers/scsi/ufs/ufshcd-intel-pci.c

diff --git a/drivers/scsi/ufs/Kconfig b/drivers/scsi/ufs/Kconfig
index e27b4d4e6ae2..702420bc0fac 100644
--- a/drivers/scsi/ufs/Kconfig
+++ b/drivers/scsi/ufs/Kconfig
@@ -69,6 +69,17 @@ config SCSI_UFS_DWC_TC_PCI

  If unsure, say N.

+config SCSI_UFSHCD_INTEL_PCI
+   tristate "Intel PCI bus based UFS Controller support"
+   depends on SCSI_UFSHCD && PCI
+   ---help---
+	This selects the Intel PCI UFS Host Controller Interface. Select this 
if

+   you have Intel UFS Host Controller with PCI Interface.
+
+ If you have a controller with this interface, say Y or M here.
+
+ If unsure, say N.
+
 config SCSI_UFSHCD_PLATFORM
tristate "Platform bus based UFS Controller support"
depends on SCSI_UFSHCD
diff --git a/drivers/scsi/ufs/Makefile b/drivers/scsi/ufs/Makefile
index 6e77cb0bfee9..be817e1a 100644
--- a/drivers/scsi/ufs/Makefile
+++ b/drivers/scsi/ufs/Makefile
@@ -4,4 +4,5 @@ obj-$(CONFIG_SCSI_UFS_DWC_TC_PLATFORM) +=
tc-dwc-g210-pltfrm.o ufshcd-dwc.o tc-d
 obj-$(CONFIG_SCSI_UFS_QCOM) += ufs-qcom.o
 obj-$(CONFIG_SCSI_UFSHCD) += ufshcd.o
 obj-$(CONFIG_SCSI_UFSHCD_PCI) += ufshcd-pci.o
+obj-$(CONFIG_SCSI_UFSHCD_INTEL_PCI) += ufshcd-intel-pci.o
 obj-$(CONFIG_SCSI_UFSHCD_PLATFORM) += ufshcd-pltfrm.o
diff --git a/drivers/scsi/ufs/ufshcd-intel-pci.c
b/drivers/scsi/ufs/ufshcd-intel-pci.c
new file mode 100644
index ..c2d379f612aa
--- /dev/null
+++ b/drivers/scsi/ufs/ufshcd-intel-pci.c
@@ -0,0 +1,183 @@
+/*
+ * Universal Flash Storage Intel Host controller PCI driver
+ *
+ * Copyright (c) 2017, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or 
modify it

+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but 
WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 
or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public 
License for

+ * more details.
+ */
+
+#include "ufshcd.h"
+#include 
+#include 
+
+static int ufs_intel_disable_lcc(struct ufs_hba *hba)
+{
+   u32 attr = UIC_ARG_MIB(PA_LOCAL_TX_LCC_ENABLE);
+   u32 lcc_enable = 0;
+
+   ufshcd_dme_get(hba, attr, _enable);
+   if (lcc_enable)
+   ufshcd_dme_set(hba, attr, 0);
+
+   return 0;
+}
+
+static int ufs_intel_link_startup_notify(struct ufs_hba *hba,
+enum ufs_notify_change_status status)
+{
+   int err = 0;
+
+   switch (status) {
+   case PRE_CHANGE:
+   err = ufs_intel_disable_lcc(hba);
+   break;
+   case POST_CHANGE:
+   break;
+   default:
+   break;
+   }
+
+   return err;
+}
+
+static struct ufs_hba_variant_ops ufs_intel_hba_vops = {
+   .name   = "intel",



How about s/intel/intel-pci ? Rest looks good to me.



+   .link_startup_notify= ufs_intel_link_startup_notify,
+};
+
+#ifdef CONFIG_PM_SLEEP
+static int ufs_intel_suspend(struct device *dev)
+{
+   return ufshcd_system_suspend(dev_get_drvdata(dev));
+}
+
+static int ufs_intel_resume(struct device *dev)
+{
+   return ufshcd_system_resume(dev_get_drvdata(dev));
+}
+#endif /* !CONFIG_PM_SLEEP */
+
+#ifdef CONFIG_PM
+static int ufs_intel_runtime_suspend(struct device *dev)
+{
+   return ufshcd_runtime_suspend(dev_get_drvdata(dev));
+}
+
+static int ufs_intel_runtime_resume(struct device *dev)
+{
+   return ufshcd_runtime_resume(dev_get_drvdata(dev));
+}
+
+static int ufs_intel_runtime_idle(struct device *dev)
+{
+   return ufshcd_runtime_idle(dev_get_drvdata(dev));
+}
+#endif /* !CONFIG_PM */
+
+static void ufs_intel_shutdown(struct pci_dev *pdev)
+{
+   ufshcd_shutdown((struct ufs_hba *)pci_get_drvdata(pdev));
+}
+
+static void ufs_intel_remove(struct pci_dev *pdev)
+{
+   struct ufs_hba *hba = pci_get_drvdata(pdev);
+
+   pm_runtime_forbid(>dev);
+   pm_runtime_get_noresume(>dev);
+   ufshcd_remove(hba);
+   ufshcd_dealloc_host(hba);
+}
+
+static int ufs_intel_probe(struct pci_dev *pdev, const struct
pci_device_id *id)
+{
+   struct ufs_hba *hba;
+   void __iomem *mmio_base;
+   int err;
+
+   dev_info(>dev, "UFS controller found [%04x:%04x]\n",
+(int)pdev->vendor, (int)pdev->device);
+
+   err = 

Re: [PATCH 2/2] scsi: ufshcd-intel-pci: Add PCI driver for Intel Host controllers

2017-06-05 Thread Subhash Jadavani

On 2017-06-05 01:36, Adrian Hunter wrote:

From: Szymon Mielczarek 

This patch adds a glue pci driver for Intel UFS Host controllers.

Signed-off-by: Szymon Mielczarek 
Signed-off-by: Adrian Hunter 
---
 drivers/scsi/ufs/Kconfig|  11 +++
 drivers/scsi/ufs/Makefile   |   1 +
 drivers/scsi/ufs/ufshcd-intel-pci.c | 183 


 3 files changed, 195 insertions(+)
 create mode 100644 drivers/scsi/ufs/ufshcd-intel-pci.c

diff --git a/drivers/scsi/ufs/Kconfig b/drivers/scsi/ufs/Kconfig
index e27b4d4e6ae2..702420bc0fac 100644
--- a/drivers/scsi/ufs/Kconfig
+++ b/drivers/scsi/ufs/Kconfig
@@ -69,6 +69,17 @@ config SCSI_UFS_DWC_TC_PCI

  If unsure, say N.

+config SCSI_UFSHCD_INTEL_PCI
+   tristate "Intel PCI bus based UFS Controller support"
+   depends on SCSI_UFSHCD && PCI
+   ---help---
+	This selects the Intel PCI UFS Host Controller Interface. Select this 
if

+   you have Intel UFS Host Controller with PCI Interface.
+
+ If you have a controller with this interface, say Y or M here.
+
+ If unsure, say N.
+
 config SCSI_UFSHCD_PLATFORM
tristate "Platform bus based UFS Controller support"
depends on SCSI_UFSHCD
diff --git a/drivers/scsi/ufs/Makefile b/drivers/scsi/ufs/Makefile
index 6e77cb0bfee9..be817e1a 100644
--- a/drivers/scsi/ufs/Makefile
+++ b/drivers/scsi/ufs/Makefile
@@ -4,4 +4,5 @@ obj-$(CONFIG_SCSI_UFS_DWC_TC_PLATFORM) +=
tc-dwc-g210-pltfrm.o ufshcd-dwc.o tc-d
 obj-$(CONFIG_SCSI_UFS_QCOM) += ufs-qcom.o
 obj-$(CONFIG_SCSI_UFSHCD) += ufshcd.o
 obj-$(CONFIG_SCSI_UFSHCD_PCI) += ufshcd-pci.o
+obj-$(CONFIG_SCSI_UFSHCD_INTEL_PCI) += ufshcd-intel-pci.o
 obj-$(CONFIG_SCSI_UFSHCD_PLATFORM) += ufshcd-pltfrm.o
diff --git a/drivers/scsi/ufs/ufshcd-intel-pci.c
b/drivers/scsi/ufs/ufshcd-intel-pci.c
new file mode 100644
index ..c2d379f612aa
--- /dev/null
+++ b/drivers/scsi/ufs/ufshcd-intel-pci.c
@@ -0,0 +1,183 @@
+/*
+ * Universal Flash Storage Intel Host controller PCI driver
+ *
+ * Copyright (c) 2017, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or 
modify it

+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but 
WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 
or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public 
License for

+ * more details.
+ */
+
+#include "ufshcd.h"
+#include 
+#include 
+
+static int ufs_intel_disable_lcc(struct ufs_hba *hba)
+{
+   u32 attr = UIC_ARG_MIB(PA_LOCAL_TX_LCC_ENABLE);
+   u32 lcc_enable = 0;
+
+   ufshcd_dme_get(hba, attr, _enable);
+   if (lcc_enable)
+   ufshcd_dme_set(hba, attr, 0);
+
+   return 0;
+}
+
+static int ufs_intel_link_startup_notify(struct ufs_hba *hba,
+enum ufs_notify_change_status status)
+{
+   int err = 0;
+
+   switch (status) {
+   case PRE_CHANGE:
+   err = ufs_intel_disable_lcc(hba);
+   break;
+   case POST_CHANGE:
+   break;
+   default:
+   break;
+   }
+
+   return err;
+}
+
+static struct ufs_hba_variant_ops ufs_intel_hba_vops = {
+   .name   = "intel",



How about s/intel/intel-pci ? Rest looks good to me.



+   .link_startup_notify= ufs_intel_link_startup_notify,
+};
+
+#ifdef CONFIG_PM_SLEEP
+static int ufs_intel_suspend(struct device *dev)
+{
+   return ufshcd_system_suspend(dev_get_drvdata(dev));
+}
+
+static int ufs_intel_resume(struct device *dev)
+{
+   return ufshcd_system_resume(dev_get_drvdata(dev));
+}
+#endif /* !CONFIG_PM_SLEEP */
+
+#ifdef CONFIG_PM
+static int ufs_intel_runtime_suspend(struct device *dev)
+{
+   return ufshcd_runtime_suspend(dev_get_drvdata(dev));
+}
+
+static int ufs_intel_runtime_resume(struct device *dev)
+{
+   return ufshcd_runtime_resume(dev_get_drvdata(dev));
+}
+
+static int ufs_intel_runtime_idle(struct device *dev)
+{
+   return ufshcd_runtime_idle(dev_get_drvdata(dev));
+}
+#endif /* !CONFIG_PM */
+
+static void ufs_intel_shutdown(struct pci_dev *pdev)
+{
+   ufshcd_shutdown((struct ufs_hba *)pci_get_drvdata(pdev));
+}
+
+static void ufs_intel_remove(struct pci_dev *pdev)
+{
+   struct ufs_hba *hba = pci_get_drvdata(pdev);
+
+   pm_runtime_forbid(>dev);
+   pm_runtime_get_noresume(>dev);
+   ufshcd_remove(hba);
+   ufshcd_dealloc_host(hba);
+}
+
+static int ufs_intel_probe(struct pci_dev *pdev, const struct
pci_device_id *id)
+{
+   struct ufs_hba *hba;
+   void __iomem *mmio_base;
+   int err;
+
+   dev_info(>dev, "UFS controller found [%04x:%04x]\n",
+(int)pdev->vendor, (int)pdev->device);
+
+   err = pcim_enable_device(pdev);
+   if (err)
+   return err;
+
+   

Re: [PATCH 1/2] scsi: ufs: Tidy clocks list head usage

2017-06-05 Thread Subhash Jadavani

On 2017-06-05 01:36, Adrian Hunter wrote:

From: Szymon Mielczarek <szymonx.mielcza...@intel.com>

Move the initialization of clocks list head to ufshcd_alloc_host() so 
that
every driver doesn't have to do it. Remove checks for the list head 
being

NULL because that is not possible.

Signed-off-by: Szymon Mielczarek <szymonx.mielcza...@intel.com>
Signed-off-by: Adrian Hunter <adrian.hun...@intel.com>
---
 drivers/scsi/ufs/tc-dwc-g210-pci.c |  2 --
 drivers/scsi/ufs/ufshcd-pci.c  |  2 --
 drivers/scsi/ufs/ufshcd-pltfrm.c   |  2 --
 drivers/scsi/ufs/ufshcd.c  | 12 +++-
 4 files changed, 7 insertions(+), 11 deletions(-)

diff --git a/drivers/scsi/ufs/tc-dwc-g210-pci.c
b/drivers/scsi/ufs/tc-dwc-g210-pci.c
index c09a0fef0fe6..325d5e14fc0d 100644
--- a/drivers/scsi/ufs/tc-dwc-g210-pci.c
+++ b/drivers/scsi/ufs/tc-dwc-g210-pci.c
@@ -130,8 +130,6 @@ static void tc_dwc_g210_pci_remove(struct pci_dev 
*pdev)

return err;
}

-   INIT_LIST_HEAD(>clk_list_head);
-
hba->vops = _dwc_g210_pci_hba_vops;

err = ufshcd_init(hba, mmio_base, pdev->irq);
diff --git a/drivers/scsi/ufs/ufshcd-pci.c 
b/drivers/scsi/ufs/ufshcd-pci.c

index 52b546fb509b..5dd4122cbd85 100644
--- a/drivers/scsi/ufs/ufshcd-pci.c
+++ b/drivers/scsi/ufs/ufshcd-pci.c
@@ -143,8 +143,6 @@ static void ufshcd_pci_remove(struct pci_dev *pdev)
return err;
}

-   INIT_LIST_HEAD(>clk_list_head);
-
err = ufshcd_init(hba, mmio_base, pdev->irq);
if (err) {
dev_err(>dev, "Initialization failed\n");
diff --git a/drivers/scsi/ufs/ufshcd-pltfrm.c 
b/drivers/scsi/ufs/ufshcd-pltfrm.c

index 8e5e6c04c035..e82bde077296 100644
--- a/drivers/scsi/ufs/ufshcd-pltfrm.c
+++ b/drivers/scsi/ufs/ufshcd-pltfrm.c
@@ -58,8 +58,6 @@ static int ufshcd_parse_clock_info(struct ufs_hba 
*hba)

if (!np)
goto out;

-   INIT_LIST_HEAD(>clk_list_head);
-
cnt = of_property_count_strings(np, "clock-names");
if (!cnt || (cnt == -EINVAL)) {
dev_info(dev, "%s: Unable to find clocks, assuming enabled\n",
diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index ffe8d8608818..88ccd63f83c1 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -314,7 +314,7 @@ static void ufshcd_print_clk_freqs(struct ufs_hba 
*hba)

struct ufs_clk_info *clki;
struct list_head *head = >clk_list_head;

-   if (!head || list_empty(head))
+   if (list_empty(head))
return;

list_for_each_entry(clki, head, list) {
@@ -869,7 +869,7 @@ static int ufshcd_scale_clks(struct ufs_hba *hba,
bool scale_up)
ktime_t start = ktime_get();
bool clk_state_changed = false;

-   if (!head || list_empty(head))
+   if (list_empty(head))
goto out;

ret = ufshcd_vops_clk_scale_notify(hba, scale_up, PRE_CHANGE);
@@ -943,7 +943,7 @@ static bool
ufshcd_is_devfreq_scaling_required(struct ufs_hba *hba,
struct ufs_clk_info *clki;
struct list_head *head = >clk_list_head;

-   if (!head || list_empty(head))
+   if (list_empty(head))
return false;

list_for_each_entry(clki, head, list) {
@@ -6752,7 +6752,7 @@ static int __ufshcd_setup_clocks(struct ufs_hba
*hba, bool on,
ktime_t start = ktime_get();
bool clk_state_changed = false;

-   if (!head || list_empty(head))
+   if (list_empty(head))
goto out;

ret = ufshcd_vops_setup_clocks(hba, on, PRE_CHANGE);
@@ -6818,7 +6818,7 @@ static int ufshcd_init_clocks(struct ufs_hba 
*hba)

struct device *dev = hba->dev;
struct list_head *head = >clk_list_head;

-   if (!head || list_empty(head))
+   if (list_empty(head))
goto out;

list_for_each_entry(clki, head, list) {
@@ -7811,6 +7811,8 @@ int ufshcd_alloc_host(struct device *dev, struct
ufs_hba **hba_handle)
hba->dev = dev;
*hba_handle = hba;

+   INIT_LIST_HEAD(>clk_list_head);
+
 out_error:
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 1/2] scsi: ufs: Tidy clocks list head usage

2017-06-05 Thread Subhash Jadavani

On 2017-06-05 01:36, Adrian Hunter wrote:

From: Szymon Mielczarek 

Move the initialization of clocks list head to ufshcd_alloc_host() so 
that
every driver doesn't have to do it. Remove checks for the list head 
being

NULL because that is not possible.

Signed-off-by: Szymon Mielczarek 
Signed-off-by: Adrian Hunter 
---
 drivers/scsi/ufs/tc-dwc-g210-pci.c |  2 --
 drivers/scsi/ufs/ufshcd-pci.c  |  2 --
 drivers/scsi/ufs/ufshcd-pltfrm.c   |  2 --
 drivers/scsi/ufs/ufshcd.c  | 12 +++-
 4 files changed, 7 insertions(+), 11 deletions(-)

diff --git a/drivers/scsi/ufs/tc-dwc-g210-pci.c
b/drivers/scsi/ufs/tc-dwc-g210-pci.c
index c09a0fef0fe6..325d5e14fc0d 100644
--- a/drivers/scsi/ufs/tc-dwc-g210-pci.c
+++ b/drivers/scsi/ufs/tc-dwc-g210-pci.c
@@ -130,8 +130,6 @@ static void tc_dwc_g210_pci_remove(struct pci_dev 
*pdev)

return err;
}

-   INIT_LIST_HEAD(>clk_list_head);
-
hba->vops = _dwc_g210_pci_hba_vops;

err = ufshcd_init(hba, mmio_base, pdev->irq);
diff --git a/drivers/scsi/ufs/ufshcd-pci.c 
b/drivers/scsi/ufs/ufshcd-pci.c

index 52b546fb509b..5dd4122cbd85 100644
--- a/drivers/scsi/ufs/ufshcd-pci.c
+++ b/drivers/scsi/ufs/ufshcd-pci.c
@@ -143,8 +143,6 @@ static void ufshcd_pci_remove(struct pci_dev *pdev)
return err;
}

-   INIT_LIST_HEAD(>clk_list_head);
-
err = ufshcd_init(hba, mmio_base, pdev->irq);
if (err) {
dev_err(>dev, "Initialization failed\n");
diff --git a/drivers/scsi/ufs/ufshcd-pltfrm.c 
b/drivers/scsi/ufs/ufshcd-pltfrm.c

index 8e5e6c04c035..e82bde077296 100644
--- a/drivers/scsi/ufs/ufshcd-pltfrm.c
+++ b/drivers/scsi/ufs/ufshcd-pltfrm.c
@@ -58,8 +58,6 @@ static int ufshcd_parse_clock_info(struct ufs_hba 
*hba)

if (!np)
goto out;

-   INIT_LIST_HEAD(>clk_list_head);
-
cnt = of_property_count_strings(np, "clock-names");
if (!cnt || (cnt == -EINVAL)) {
dev_info(dev, "%s: Unable to find clocks, assuming enabled\n",
diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index ffe8d8608818..88ccd63f83c1 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -314,7 +314,7 @@ static void ufshcd_print_clk_freqs(struct ufs_hba 
*hba)

struct ufs_clk_info *clki;
struct list_head *head = >clk_list_head;

-   if (!head || list_empty(head))
+   if (list_empty(head))
return;

list_for_each_entry(clki, head, list) {
@@ -869,7 +869,7 @@ static int ufshcd_scale_clks(struct ufs_hba *hba,
bool scale_up)
ktime_t start = ktime_get();
bool clk_state_changed = false;

-   if (!head || list_empty(head))
+   if (list_empty(head))
goto out;

ret = ufshcd_vops_clk_scale_notify(hba, scale_up, PRE_CHANGE);
@@ -943,7 +943,7 @@ static bool
ufshcd_is_devfreq_scaling_required(struct ufs_hba *hba,
struct ufs_clk_info *clki;
struct list_head *head = >clk_list_head;

-   if (!head || list_empty(head))
+   if (list_empty(head))
return false;

list_for_each_entry(clki, head, list) {
@@ -6752,7 +6752,7 @@ static int __ufshcd_setup_clocks(struct ufs_hba
*hba, bool on,
ktime_t start = ktime_get();
bool clk_state_changed = false;

-   if (!head || list_empty(head))
+   if (list_empty(head))
goto out;

ret = ufshcd_vops_setup_clocks(hba, on, PRE_CHANGE);
@@ -6818,7 +6818,7 @@ static int ufshcd_init_clocks(struct ufs_hba 
*hba)

struct device *dev = hba->dev;
struct list_head *head = >clk_list_head;

-   if (!head || list_empty(head))
+   if (list_empty(head))
goto out;

list_for_each_entry(clki, head, list) {
@@ -7811,6 +7811,8 @@ int ufshcd_alloc_host(struct device *dev, struct
ufs_hba **hba_handle)
hba->dev = dev;
*hba_handle = hba;

+   INIT_LIST_HEAD(>clk_list_head);
+
 out_error:
    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 3/3] scsi: ufs: Delete an unnecessary return statement in ufshcd_exception_event_handler()

2017-04-26 Thread Subhash Jadavani

On 2017-04-25 13:30, SF Markus Elfring wrote:

From: Markus Elfring <elfr...@users.sourceforge.net>
Date: Tue, 25 Apr 2017 22:00:05 +0200

The script "checkpatch.pl" pointed information out like the following.

WARNING: void function return statements are not generally useful

Thus remove such a statement here.

Signed-off-by: Markus Elfring <elfr...@users.sourceforge.net>
---
 drivers/scsi/ufs/ufshcd.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index 5216e33e61a3..9018f26a5667 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -4966,7 +4966,6 @@ static void
ufshcd_exception_event_handler(struct work_struct *work)

 out:
pm_runtime_put_sync(hba->dev);
-   return;
 }

 /* Complete requests that have door-bell cleared */


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 3/3] scsi: ufs: Delete an unnecessary return statement in ufshcd_exception_event_handler()

2017-04-26 Thread Subhash Jadavani

On 2017-04-25 13:30, SF Markus Elfring wrote:

From: Markus Elfring 
Date: Tue, 25 Apr 2017 22:00:05 +0200

The script "checkpatch.pl" pointed information out like the following.

WARNING: void function return statements are not generally useful

Thus remove such a statement here.

Signed-off-by: Markus Elfring 
---
 drivers/scsi/ufs/ufshcd.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index 5216e33e61a3..9018f26a5667 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -4966,7 +4966,6 @@ static void
ufshcd_exception_event_handler(struct work_struct *work)

 out:
pm_runtime_put_sync(hba->dev);
-   return;
 }

 /* Complete requests that have door-bell cleared */


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 2/3] scsi: ufs: Delete an error message for a failed memory allocation in ufshcd_memory_alloc()

2017-04-26 Thread Subhash Jadavani

On 2017-04-25 13:28, SF Markus Elfring wrote:

From: Markus Elfring <elfr...@users.sourceforge.net>
Date: Tue, 25 Apr 2017 21:50:43 +0200

The script "checkpatch.pl" pointed information out like the following.

WARNING: Possible unnecessary 'out of memory' message

Thus remove such a statement here.

Link:
http://events.linuxfoundation.org/sites/events/files/slides/LCJ16-Refactor_Strings-WSang_0.pdf
Signed-off-by: Markus Elfring <elfr...@users.sourceforge.net>
---
 drivers/scsi/ufs/ufshcd.c | 5 ++---
 1 file changed, 2 insertions(+), 3 deletions(-)

diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index ce385911a20e..5216e33e61a3 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -3274,8 +3274,7 @@ static int ufshcd_memory_alloc(struct ufs_hba 
*hba)

GFP_KERNEL);
-   if (!hba->lrb) {
-   dev_err(hba->dev, "LRB Memory allocation failed\n");
+   if (!hba->lrb)
goto out;
-   }
+
return 0;
 out:
return -ENOMEM;


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

PS: ufshcd_memory_alloc() also does some DMA coherent memory allocation 
(via dmam_alloc_coherent() APIs) and tries to print out the message on 
allocation failure. Although i don't know "out of memory" messages will 
be printed out by dmam_alloc_coherent() APIs or not. If it does print it 
out then we might want to remove our local memory allocation failure log 
messages.



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


Re: [PATCH 2/3] scsi: ufs: Delete an error message for a failed memory allocation in ufshcd_memory_alloc()

2017-04-26 Thread Subhash Jadavani

On 2017-04-25 13:28, SF Markus Elfring wrote:

From: Markus Elfring 
Date: Tue, 25 Apr 2017 21:50:43 +0200

The script "checkpatch.pl" pointed information out like the following.

WARNING: Possible unnecessary 'out of memory' message

Thus remove such a statement here.

Link:
http://events.linuxfoundation.org/sites/events/files/slides/LCJ16-Refactor_Strings-WSang_0.pdf
Signed-off-by: Markus Elfring 
---
 drivers/scsi/ufs/ufshcd.c | 5 ++---
 1 file changed, 2 insertions(+), 3 deletions(-)

diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index ce385911a20e..5216e33e61a3 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -3274,8 +3274,7 @@ static int ufshcd_memory_alloc(struct ufs_hba 
*hba)

GFP_KERNEL);
-   if (!hba->lrb) {
-   dev_err(hba->dev, "LRB Memory allocation failed\n");
+   if (!hba->lrb)
goto out;
-   }
+
return 0;
 out:
return -ENOMEM;


Looks good to me.
Reviewed-by: Subhash Jadavani 

PS: ufshcd_memory_alloc() also does some DMA coherent memory allocation 
(via dmam_alloc_coherent() APIs) and tries to print out the message on 
allocation failure. Although i don't know "out of memory" messages will 
be printed out by dmam_alloc_coherent() APIs or not. If it does print it 
out then we might want to remove our local memory allocation failure log 
messages.



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


Re: [PATCH 1/3] scsi: ufs: Use devm_kcalloc() in ufshcd_memory_alloc()

2017-04-26 Thread Subhash Jadavani

On 2017-04-25 13:26, SF Markus Elfring wrote:

From: Markus Elfring <elfr...@users.sourceforge.net>
Date: Tue, 25 Apr 2017 21:45:25 +0200

* A multiplication for the size determination of a memory allocation
  indicated that an array data structure should be processed.
  Thus use the corresponding function "devm_kcalloc".

* Replace the specification of a data structure by a pointer 
dereference

  to make the corresponding size determination a bit safer according to
  the Linux coding style convention.

Signed-off-by: Markus Elfring <elfr...@users.sourceforge.net>
---
 drivers/scsi/ufs/ufshcd.c | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index 9ef8ce7f01a2..ce385911a20e 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -3270,8 +3270,7 @@ static int ufshcd_memory_alloc(struct ufs_hba 
*hba)

}

/* Allocate memory for local reference block */
-   hba->lrb = devm_kzalloc(hba->dev,
-   hba->nutrs * sizeof(struct ufshcd_lrb),
+   hba->lrb = devm_kcalloc(hba->dev, hba->nutrs, sizeof(*hba->lrb),
GFP_KERNEL);
if (!hba->lrb) {
dev_err(hba->dev, "LRB Memory allocation failed\n");


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 1/3] scsi: ufs: Use devm_kcalloc() in ufshcd_memory_alloc()

2017-04-26 Thread Subhash Jadavani

On 2017-04-25 13:26, SF Markus Elfring wrote:

From: Markus Elfring 
Date: Tue, 25 Apr 2017 21:45:25 +0200

* A multiplication for the size determination of a memory allocation
  indicated that an array data structure should be processed.
  Thus use the corresponding function "devm_kcalloc".

* Replace the specification of a data structure by a pointer 
dereference

  to make the corresponding size determination a bit safer according to
  the Linux coding style convention.

Signed-off-by: Markus Elfring 
---
 drivers/scsi/ufs/ufshcd.c | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index 9ef8ce7f01a2..ce385911a20e 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -3270,8 +3270,7 @@ static int ufshcd_memory_alloc(struct ufs_hba 
*hba)

}

/* Allocate memory for local reference block */
-   hba->lrb = devm_kzalloc(hba->dev,
-   hba->nutrs * sizeof(struct ufshcd_lrb),
+   hba->lrb = devm_kcalloc(hba->dev, hba->nutrs, sizeof(*hba->lrb),
GFP_KERNEL);
if (!hba->lrb) {
dev_err(hba->dev, "LRB Memory allocation failed\n");


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] scsi: ufs: remove the duplicated checking for supporting clkscaling

2017-03-24 Thread Subhash Jadavani

On 2017-03-21 05:19, Jaehoon Chung wrote:

There are same conditions for checking whether supporting clkscaling or
not.
When ufshcd is supporting clkscaling, active_reqs should be decreased 
by

two.

Signed-off-by: Jaehoon Chung <jh80.ch...@samsung.com>
---
 drivers/scsi/ufs/ufshcd.c | 2 --
 1 file changed, 2 deletions(-)

diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index dc6efbd..f2cbc71 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -4598,8 +4598,6 @@ static void __ufshcd_transfer_req_compl(struct
ufs_hba *hba,
}
if (ufshcd_is_clkscaling_supported(hba))
hba->clk_scaling.active_reqs--;
-   if (ufshcd_is_clkscaling_supported(hba))
-   hba->clk_scaling.active_reqs--;
}

/* clear corresponding bits of completed commands */


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] scsi: ufs: remove the duplicated checking for supporting clkscaling

2017-03-24 Thread Subhash Jadavani

On 2017-03-21 05:19, Jaehoon Chung wrote:

There are same conditions for checking whether supporting clkscaling or
not.
When ufshcd is supporting clkscaling, active_reqs should be decreased 
by

two.

Signed-off-by: Jaehoon Chung 
---
 drivers/scsi/ufs/ufshcd.c | 2 --
 1 file changed, 2 deletions(-)

diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index dc6efbd..f2cbc71 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -4598,8 +4598,6 @@ static void __ufshcd_transfer_req_compl(struct
ufs_hba *hba,
}
if (ufshcd_is_clkscaling_supported(hba))
hba->clk_scaling.active_reqs--;
-   if (ufshcd_is_clkscaling_supported(hba))
-   hba->clk_scaling.active_reqs--;
}

/* clear corresponding bits of completed commands */


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: [scsi] scsi: ufshcd-platform: remove the useless cast in ERR_PTR/IS_ERR

2017-03-15 Thread Subhash Jadavani

On 2017-03-14 05:19, Tomas Winkler wrote:

IS_ERR and ERR_PTR already forcefully cast their argument,
hence there is no need for additional (complex) casting.

Signed-off-by: Tomas Winkler <tomas.wink...@intel.com>
---
 drivers/scsi/ufs/ufshcd-pltfrm.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/scsi/ufs/ufshcd-pltfrm.c 
b/drivers/scsi/ufs/ufshcd-pltfrm.c

index a72a4ba78125..8e5e6c04c035 100644
--- a/drivers/scsi/ufs/ufshcd-pltfrm.c
+++ b/drivers/scsi/ufs/ufshcd-pltfrm.c
@@ -309,8 +309,8 @@ int ufshcd_pltfrm_init(struct platform_device 
*pdev,


mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
mmio_base = devm_ioremap_resource(dev, mem_res);
-   if (IS_ERR(*(void **)_base)) {
-   err = PTR_ERR(*(void **)_base);
+   if (IS_ERR(mmio_base)) {
+   err = PTR_ERR(mmio_base);
goto out;
}


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: [scsi] scsi: ufshcd-platform: remove the useless cast in ERR_PTR/IS_ERR

2017-03-15 Thread Subhash Jadavani

On 2017-03-14 05:19, Tomas Winkler wrote:

IS_ERR and ERR_PTR already forcefully cast their argument,
hence there is no need for additional (complex) casting.

Signed-off-by: Tomas Winkler 
---
 drivers/scsi/ufs/ufshcd-pltfrm.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/scsi/ufs/ufshcd-pltfrm.c 
b/drivers/scsi/ufs/ufshcd-pltfrm.c

index a72a4ba78125..8e5e6c04c035 100644
--- a/drivers/scsi/ufs/ufshcd-pltfrm.c
+++ b/drivers/scsi/ufs/ufshcd-pltfrm.c
@@ -309,8 +309,8 @@ int ufshcd_pltfrm_init(struct platform_device 
*pdev,


mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
mmio_base = devm_ioremap_resource(dev, mem_res);
-   if (IS_ERR(*(void **)_base)) {
-   err = PTR_ERR(*(void **)_base);
+   if (IS_ERR(mmio_base)) {
+   err = PTR_ERR(mmio_base);
goto out;
}


LGTM.
Reviewed-by: Subhash Jadavani 

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


Re: [scsi] scsi: ufs: don't check unsigned type for a negative value

2017-03-15 Thread Subhash Jadavani

On 2017-03-15 10:26, James Bottomley wrote:

On Mon, 2017-03-13 at 17:19 -0700, Subhash Jadavani wrote:

On 2017-03-12 03:22, Tomas Winkler wrote:
> Fix compilation warning
>
> drivers/scsi/ufs/ufshcd.c:7645:13: warning: comparison of unsigned
> expression < 0 is always false [-Wtype-limits]
> if ((value < UFS_PM_LVL_0) || (value >= UFS_PM_LVL_MAX))
>
> Signed-off-by: Tomas Winkler <tomas.wink...@intel.com>
> ---
>  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 1359913bf840..e8c26e6e6237 100644
> --- a/drivers/scsi/ufs/ufshcd.c
> +++ b/drivers/scsi/ufs/ufshcd.c
> @@ -7642,7 +7642,7 @@ static inline ssize_t
> ufshcd_pm_lvl_store(struct
> device *dev,
>if (kstrtoul(buf, 0, ))
>return -EINVAL;
>
> -  if ((value < UFS_PM_LVL_0) || (value >= UFS_PM_LVL_MAX))
> +  if (value >= UFS_PM_LVL_MAX)
>    return -EINVAL;
>
>spin_lock_irqsave(hba->host->host_lock, flags);

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


Mis-spelling someone else's email can be cut and paste; mis-spelling
your own might be the early indications of an identity crisis.

We do cut and paste these tags, so getting your own name right for the
purposes of git history is useful.

James


Oops, sorry for this. If you haven't already corrected this:
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: [scsi] scsi: ufs: don't check unsigned type for a negative value

2017-03-15 Thread Subhash Jadavani

On 2017-03-15 10:26, James Bottomley wrote:

On Mon, 2017-03-13 at 17:19 -0700, Subhash Jadavani wrote:

On 2017-03-12 03:22, Tomas Winkler wrote:
> Fix compilation warning
>
> drivers/scsi/ufs/ufshcd.c:7645:13: warning: comparison of unsigned
> expression < 0 is always false [-Wtype-limits]
> if ((value < UFS_PM_LVL_0) || (value >= UFS_PM_LVL_MAX))
>
> Signed-off-by: Tomas Winkler 
> ---
>  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 1359913bf840..e8c26e6e6237 100644
> --- a/drivers/scsi/ufs/ufshcd.c
> +++ b/drivers/scsi/ufs/ufshcd.c
> @@ -7642,7 +7642,7 @@ static inline ssize_t
> ufshcd_pm_lvl_store(struct
> device *dev,
>if (kstrtoul(buf, 0, ))
>return -EINVAL;
>
> -  if ((value < UFS_PM_LVL_0) || (value >= UFS_PM_LVL_MAX))
> +  if (value >= UFS_PM_LVL_MAX)
>return -EINVAL;
>
>spin_lock_irqsave(hba->host->host_lock, flags);

LGTM.
Reviewed-by: Subhash Jadavani 


Mis-spelling someone else's email can be cut and paste; mis-spelling
your own might be the early indications of an identity crisis.

We do cut and paste these tags, so getting your own name right for the
purposes of git history is useful.

James


Oops, sorry for this. If you haven't already corrected this:
Reviewed-by: Subhash Jadavani 



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


Re: [scsi] scsi: ufs: don't check unsigned type for a negative value

2017-03-13 Thread Subhash Jadavani

On 2017-03-12 03:22, Tomas Winkler wrote:

Fix compilation warning

drivers/scsi/ufs/ufshcd.c:7645:13: warning: comparison of unsigned
expression < 0 is always false [-Wtype-limits]
if ((value < UFS_PM_LVL_0) || (value >= UFS_PM_LVL_MAX))

Signed-off-by: Tomas Winkler <tomas.wink...@intel.com>
---
 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 1359913bf840..e8c26e6e6237 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -7642,7 +7642,7 @@ static inline ssize_t ufshcd_pm_lvl_store(struct
device *dev,
if (kstrtoul(buf, 0, ))
return -EINVAL;

-   if ((value < UFS_PM_LVL_0) || (value >= UFS_PM_LVL_MAX))
+   if (value >= UFS_PM_LVL_MAX)
return -EINVAL;

spin_lock_irqsave(hba->host->host_lock, flags);


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

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


Re: [scsi] scsi: ufs: don't check unsigned type for a negative value

2017-03-13 Thread Subhash Jadavani

On 2017-03-12 03:22, Tomas Winkler wrote:

Fix compilation warning

drivers/scsi/ufs/ufshcd.c:7645:13: warning: comparison of unsigned
expression < 0 is always false [-Wtype-limits]
if ((value < UFS_PM_LVL_0) || (value >= UFS_PM_LVL_MAX))

Signed-off-by: Tomas Winkler 
---
 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 1359913bf840..e8c26e6e6237 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -7642,7 +7642,7 @@ static inline ssize_t ufshcd_pm_lvl_store(struct
device *dev,
if (kstrtoul(buf, 0, ))
return -EINVAL;

-   if ((value < UFS_PM_LVL_0) || (value >= UFS_PM_LVL_MAX))
+   if (value >= UFS_PM_LVL_MAX)
return -EINVAL;

spin_lock_irqsave(hba->host->host_lock, flags);


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] scsi: ufs: Factor out ufshcd_read_desc_param

2017-03-01 Thread Subhash Jadavani

On 2017-02-27 19:24, Martin K. Petersen wrote:

"Michal" == Potomski, MichalX  writes:


Michal> Since in UFS 2.1 specification some of the descriptor lengths
Michal> differs from 2.0 specification and some devices, which are
Michal> reporting spec version 2.0 have different descriptor lengths we
Michal> can not rely on hardcoded values taken from 2.0
Michal> specification. This patch introduces reading these lengths per
Michal> each device from descriptor headers at probe time to ensure
Michal> their correctness.

Subhash: I assume v2 still carries your Reviewed-by:?


Yes, v2 also looks good to me.

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


Re: [PATCH v2] scsi: ufs: Factor out ufshcd_read_desc_param

2017-03-01 Thread Subhash Jadavani

On 2017-02-27 19:24, Martin K. Petersen wrote:

"Michal" == Potomski, MichalX  writes:


Michal> Since in UFS 2.1 specification some of the descriptor lengths
Michal> differs from 2.0 specification and some devices, which are
Michal> reporting spec version 2.0 have different descriptor lengths we
Michal> can not rely on hardcoded values taken from 2.0
Michal> specification. This patch introduces reading these lengths per
Michal> each device from descriptor headers at probe time to ensure
Michal> their correctness.

Subhash: I assume v2 still carries your Reviewed-by:?


Yes, v2 also looks good to me.

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


Re: [PATCH v1 1/1] scsi: ufs-qcom: remove redundant condition check

2017-02-22 Thread Subhash Jadavani

On 2017-02-20 19:06, Martin K. Petersen wrote:

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


Subhash,

Subhash> Dan Carpenter <dan.carpen...@oracle.com> reported this: --- 
The

Subhash> patch 9c46b8676271: "scsi: ufs-qcom: dump additional testbus
Subhash> registers" from Feb 3, 2017, leads to the following static
Subhash> checker warning:

You had used "---" to enclose Dan's email. But that's also the "ignore
everything beyond this point" delimiter so I ended up with an empty
commit message.

I fixed it up. Applied to 4.11/scsi-queue.


Thanks and sorry about that, was skeptical about it.



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


Re: [PATCH v1 1/1] scsi: ufs-qcom: remove redundant condition check

2017-02-22 Thread Subhash Jadavani

On 2017-02-20 19:06, Martin K. Petersen wrote:

"Subhash" == Subhash Jadavani  writes:


Subhash,

Subhash> Dan Carpenter  reported this: --- 
The

Subhash> patch 9c46b8676271: "scsi: ufs-qcom: dump additional testbus
Subhash> registers" from Feb 3, 2017, leads to the following static
Subhash> checker warning:

You had used "---" to enclose Dan's email. But that's also the "ignore
everything beyond this point" delimiter so I ended up with an empty
commit message.

I fixed it up. Applied to 4.11/scsi-queue.


Thanks and sorry about that, was skeptical about it.



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


Re: [PATCH] scsi: ufs: Factor out ufshcd_read_desc_param

2017-02-22 Thread Subhash Jadavani
f (ret)
goto out;

+   /* Init check for device descriptor sizes */
+   ufshcd_init_desc_sizes(hba);
+
ufs_advertise_fixup_device(hba);
ufshcd_tune_unipro_params(hba);

@@ -5300,6 +5410,7 @@ static int ufshcd_probe_hba(struct ufs_hba *hba)

/* set the state as operational after switching to desired gear */
hba->ufshcd_state = UFSHCD_STATE_OPERATIONAL;
+
/*
 	 * If we are in error handling context or in power management 
callbacks

 * context, no need to scan the host
@@ -6697,6 +6808,9 @@ int ufshcd_init(struct ufs_hba *hba, void
__iomem *mmio_base, unsigned int irq)
hba->mmio_base = mmio_base;
hba->irq = irq;

+   /* Set descriptor lengths to specification defaults */
+   ufshcd_def_desc_sizes(hba);
+
err = ufshcd_hba_init(hba);
if (err)
goto out_error;
diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h
index 08cd26e..308675a 100644
--- a/drivers/scsi/ufs/ufshcd.h
+++ b/drivers/scsi/ufs/ufshcd.h
@@ -205,6 +205,15 @@ struct ufs_dev_cmd {
struct ufs_query query;
 };

+struct ufs_desc_size {
+   int dev_desc;
+   int pwr_desc;
+   int geom_desc;
+   int interc_desc;
+   int unit_desc;
+   int conf_desc;
+};
+
 /**
  * struct ufs_clk_info - UFS clock related info
  * @list: list headed by hba->clk_list_head
@@ -398,6 +407,7 @@ struct ufs_init_prefetch {
  * @clk_list_head: UFS host controller clocks list node head
  * @pwr_info: holds current power mode
  * @max_pwr_info: keeps the device max valid pwm
+ * @desc_size: descriptor sizes reported by device
  * @urgent_bkops_lvl: keeps track of urgent bkops level for device
  * @is_urgent_bkops_lvl_checked: keeps track if the urgent bkops level 
for

  *  device is known or not.
@@ -565,6 +575,7 @@ struct ufs_hba {

enum bkops_status urgent_bkops_lvl;
bool is_urgent_bkops_lvl_checked;
+   struct ufs_desc_size desc_size;
 };

 /* Returns true if clocks can be gated. Otherwise false */
@@ -733,6 +744,10 @@ int ufshcd_query_flag(struct ufs_hba *hba, enum
query_opcode opcode,
enum flag_idn idn, bool *flag_res);
 int ufshcd_hold(struct ufs_hba *hba, bool async);
 void ufshcd_release(struct ufs_hba *hba);
+
+int ufshcd_map_desc_id_to_length(struct ufs_hba *hba, enum desc_idn 
desc_id,

+   int *desc_length);
+
 u32 ufshcd_get_local_unipro_ver(struct ufs_hba *hba);

 /* Wrapper functions for safely calling variant operations */


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] scsi: ufs: Factor out ufshcd_read_desc_param

2017-02-22 Thread Subhash Jadavani
it check for device descriptor sizes */
+   ufshcd_init_desc_sizes(hba);
+
ufs_advertise_fixup_device(hba);
ufshcd_tune_unipro_params(hba);

@@ -5300,6 +5410,7 @@ static int ufshcd_probe_hba(struct ufs_hba *hba)

/* set the state as operational after switching to desired gear */
hba->ufshcd_state = UFSHCD_STATE_OPERATIONAL;
+
/*
 	 * If we are in error handling context or in power management 
callbacks

 * context, no need to scan the host
@@ -6697,6 +6808,9 @@ int ufshcd_init(struct ufs_hba *hba, void
__iomem *mmio_base, unsigned int irq)
hba->mmio_base = mmio_base;
hba->irq = irq;

+   /* Set descriptor lengths to specification defaults */
+   ufshcd_def_desc_sizes(hba);
+
err = ufshcd_hba_init(hba);
if (err)
goto out_error;
diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h
index 08cd26e..308675a 100644
--- a/drivers/scsi/ufs/ufshcd.h
+++ b/drivers/scsi/ufs/ufshcd.h
@@ -205,6 +205,15 @@ struct ufs_dev_cmd {
struct ufs_query query;
 };

+struct ufs_desc_size {
+   int dev_desc;
+   int pwr_desc;
+   int geom_desc;
+   int interc_desc;
+   int unit_desc;
+   int conf_desc;
+};
+
 /**
  * struct ufs_clk_info - UFS clock related info
  * @list: list headed by hba->clk_list_head
@@ -398,6 +407,7 @@ struct ufs_init_prefetch {
  * @clk_list_head: UFS host controller clocks list node head
  * @pwr_info: holds current power mode
  * @max_pwr_info: keeps the device max valid pwm
+ * @desc_size: descriptor sizes reported by device
  * @urgent_bkops_lvl: keeps track of urgent bkops level for device
  * @is_urgent_bkops_lvl_checked: keeps track if the urgent bkops level 
for

  *  device is known or not.
@@ -565,6 +575,7 @@ struct ufs_hba {

enum bkops_status urgent_bkops_lvl;
bool is_urgent_bkops_lvl_checked;
+   struct ufs_desc_size desc_size;
 };

 /* Returns true if clocks can be gated. Otherwise false */
@@ -733,6 +744,10 @@ int ufshcd_query_flag(struct ufs_hba *hba, enum
query_opcode opcode,
enum flag_idn idn, bool *flag_res);
 int ufshcd_hold(struct ufs_hba *hba, bool async);
 void ufshcd_release(struct ufs_hba *hba);
+
+int ufshcd_map_desc_id_to_length(struct ufs_hba *hba, enum desc_idn 
desc_id,

+   int *desc_length);
+
 u32 ufshcd_get_local_unipro_ver(struct ufs_hba *hba);

 /* Wrapper functions for safely calling variant operations */


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


[PATCH v1 1/1] scsi: ufs-qcom: remove redundant condition check

2017-02-17 Thread Subhash Jadavani
Dan Carpenter <dan.carpen...@oracle.com> reported this:
---
The patch 9c46b8676271: "scsi: ufs-qcom: dump additional testbus
registers" from Feb 3, 2017, leads to the following static checker
warning:

drivers/scsi/ufs/ufs-qcom.c:1531 ufs_qcom_testbus_cfg_is_ok()
warn: impossible condition
'(host->testbus.select_minor > 255) => (0-255 > 255)'

drivers/scsi/ufs/ufs-qcom.c
  1517  static bool ufs_qcom_testbus_cfg_is_ok(struct ufs_qcom_host *host)
  1518  {
  1519  if (host->testbus.select_major >= TSTBUS_MAX) {
  1520   dev_err(host->hba->dev,
  1521 "%s: UFS_CFG1[TEST_BUS_SEL} may not equal 0x%05X\n",
  1522  __func__, host->testbus.select_major);
  1523  return false;
  1524  }
  1525
  1526  /*
  1527   * Not performing check for each individual select_major
  1528   * mappings of select_minor, since there is no harm in
  1529   * configuring a non-existent select_minor
  1530   */
  1531  if (host->testbus.select_minor > 0xFF) {
^

It might make sense to keep this check.  I don't know.  But it's
confusing that 0xFF is a magic number.  Better to make it a define.

  1532  dev_err(host->hba->dev,
  1533   "%s: 0x%05X is not a legal testbus option\n",
  1534__func__, host->testbus.select_minor);
  1535  return false;
  1536  }
  1537
  1538  return true;
  1539  }
---

As data type of "select_minor" is u8, above check is redundant. This change
removes it.

Reported-by: Dan Carpenter <dan.carpen...@oracle.com>
Signed-off-by: Subhash Jadavani <subha...@codeaurora.org>
---
 drivers/scsi/ufs/ufs-qcom.c | 12 
 1 file changed, 12 deletions(-)

diff --git a/drivers/scsi/ufs/ufs-qcom.c b/drivers/scsi/ufs/ufs-qcom.c
index ce5d023..c87d770 100644
--- a/drivers/scsi/ufs/ufs-qcom.c
+++ b/drivers/scsi/ufs/ufs-qcom.c
@@ -1523,18 +1523,6 @@ static bool ufs_qcom_testbus_cfg_is_ok(struct 
ufs_qcom_host *host)
return false;
}
 
-   /*
-* Not performing check for each individual select_major
-* mappings of select_minor, since there is no harm in
-* configuring a non-existent select_minor
-*/
-   if (host->testbus.select_minor > 0xFF) {
-   dev_err(host->hba->dev,
-   "%s: 0x%05X is not a legal testbus option\n",
-   __func__, host->testbus.select_minor);
-   return false;
-   }
-
return true;
 }
 
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project



[PATCH v1 1/1] scsi: ufs-qcom: remove redundant condition check

2017-02-17 Thread Subhash Jadavani
Dan Carpenter  reported this:
---
The patch 9c46b8676271: "scsi: ufs-qcom: dump additional testbus
registers" from Feb 3, 2017, leads to the following static checker
warning:

drivers/scsi/ufs/ufs-qcom.c:1531 ufs_qcom_testbus_cfg_is_ok()
warn: impossible condition
'(host->testbus.select_minor > 255) => (0-255 > 255)'

drivers/scsi/ufs/ufs-qcom.c
  1517  static bool ufs_qcom_testbus_cfg_is_ok(struct ufs_qcom_host *host)
  1518  {
  1519  if (host->testbus.select_major >= TSTBUS_MAX) {
  1520   dev_err(host->hba->dev,
  1521 "%s: UFS_CFG1[TEST_BUS_SEL} may not equal 0x%05X\n",
  1522  __func__, host->testbus.select_major);
  1523  return false;
  1524  }
  1525
  1526  /*
  1527   * Not performing check for each individual select_major
  1528   * mappings of select_minor, since there is no harm in
  1529   * configuring a non-existent select_minor
  1530   */
  1531  if (host->testbus.select_minor > 0xFF) {
^

It might make sense to keep this check.  I don't know.  But it's
confusing that 0xFF is a magic number.  Better to make it a define.

  1532  dev_err(host->hba->dev,
  1533   "%s: 0x%05X is not a legal testbus option\n",
  1534__func__, host->testbus.select_minor);
  1535  return false;
  1536  }
  1537
  1538  return true;
  1539  }
---

As data type of "select_minor" is u8, above check is redundant. This change
removes it.

Reported-by: Dan Carpenter 
Signed-off-by: Subhash Jadavani 
---
 drivers/scsi/ufs/ufs-qcom.c | 12 
 1 file changed, 12 deletions(-)

diff --git a/drivers/scsi/ufs/ufs-qcom.c b/drivers/scsi/ufs/ufs-qcom.c
index ce5d023..c87d770 100644
--- a/drivers/scsi/ufs/ufs-qcom.c
+++ b/drivers/scsi/ufs/ufs-qcom.c
@@ -1523,18 +1523,6 @@ static bool ufs_qcom_testbus_cfg_is_ok(struct 
ufs_qcom_host *host)
return false;
}
 
-   /*
-* Not performing check for each individual select_major
-* mappings of select_minor, since there is no harm in
-* configuring a non-existent select_minor
-*/
-   if (host->testbus.select_minor > 0xFF) {
-   dev_err(host->hba->dev,
-   "%s: 0x%05X is not a legal testbus option\n",
-   __func__, host->testbus.select_minor);
-   return false;
-   }
-
return true;
 }
 
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project



[PATCH v1 8/8] scsi: ufs: dump hw regs on link failures

2017-02-03 Thread Subhash Jadavani
From: Venkat Gopalakrishnan <venk...@codeaurora.org>

Dump host state, power info and host/vendor specific registers
on link failures. This provides useful info to debug the failures.

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

diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index a99a673..8b721f4 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -3554,6 +3554,12 @@ static int ufshcd_uic_pwr_ctrl(struct ufs_hba *hba, 
struct uic_command *cmd)
ret = (status != PWR_OK) ? status : -1;
}
 out:
+   if (ret) {
+   ufshcd_print_host_state(hba);
+   ufshcd_print_pwr_info(hba);
+   ufshcd_print_host_regs(hba);
+   }
+
spin_lock_irqsave(hba->host->host_lock, flags);
hba->active_uic_cmd = NULL;
hba->uic_async_done = NULL;
@@ -4146,8 +4152,12 @@ static int ufshcd_link_startup(struct ufs_hba *hba)
 
ret = ufshcd_make_hba_operational(hba);
 out:
-   if (ret)
+   if (ret) {
dev_err(hba->dev, "link startup failed %d\n", ret);
+   ufshcd_print_host_state(hba);
+   ufshcd_print_pwr_info(hba);
+   ufshcd_print_host_regs(hba);
+   }
return ret;
 }
 
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project



[PATCH v1 8/8] scsi: ufs: dump hw regs on link failures

2017-02-03 Thread Subhash Jadavani
From: Venkat Gopalakrishnan 

Dump host state, power info and host/vendor specific registers
on link failures. This provides useful info to debug the failures.

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

diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index a99a673..8b721f4 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -3554,6 +3554,12 @@ static int ufshcd_uic_pwr_ctrl(struct ufs_hba *hba, 
struct uic_command *cmd)
ret = (status != PWR_OK) ? status : -1;
}
 out:
+   if (ret) {
+   ufshcd_print_host_state(hba);
+   ufshcd_print_pwr_info(hba);
+   ufshcd_print_host_regs(hba);
+   }
+
spin_lock_irqsave(hba->host->host_lock, flags);
hba->active_uic_cmd = NULL;
hba->uic_async_done = NULL;
@@ -4146,8 +4152,12 @@ static int ufshcd_link_startup(struct ufs_hba *hba)
 
ret = ufshcd_make_hba_operational(hba);
 out:
-   if (ret)
+   if (ret) {
dev_err(hba->dev, "link startup failed %d\n", ret);
+   ufshcd_print_host_state(hba);
+   ufshcd_print_pwr_info(hba);
+   ufshcd_print_host_regs(hba);
+   }
return ret;
 }
 
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project



[PATCH v1 7/8] scsi: ufs-qcom: dump additional testbus registers

2017-02-03 Thread Subhash Jadavani
From: Venkat Gopalakrishnan <venk...@codeaurora.org>

Change testbus default config, dump additional testbus registers along
with other debug vendor specific registers. These additional info are
useful in debugging link related failures.

Signed-off-by: Venkat Gopalakrishnan <venk...@codeaurora.org>
Signed-off-by: Subhash Jadavani <subha...@codeaurora.org>
---
 drivers/scsi/ufs/ufs-qcom.c | 48 +++--
 drivers/scsi/ufs/ufs-qcom.h |  1 +
 2 files changed, 43 insertions(+), 6 deletions(-)

diff --git a/drivers/scsi/ufs/ufs-qcom.c b/drivers/scsi/ufs/ufs-qcom.c
index 5ff8a6b..ce5d023 100644
--- a/drivers/scsi/ufs/ufs-qcom.c
+++ b/drivers/scsi/ufs/ufs-qcom.c
@@ -1497,17 +1497,21 @@ static void ufs_qcom_print_hw_debug_reg_all(struct 
ufs_hba *hba,
 
 static void ufs_qcom_enable_test_bus(struct ufs_qcom_host *host)
 {
-   if (host->dbg_print_en & UFS_QCOM_DBG_PRINT_TEST_BUS_EN)
+   if (host->dbg_print_en & UFS_QCOM_DBG_PRINT_TEST_BUS_EN) {
+   ufshcd_rmwl(host->hba, UFS_REG_TEST_BUS_EN,
+   UFS_REG_TEST_BUS_EN, REG_UFS_CFG1);
ufshcd_rmwl(host->hba, TEST_BUS_EN, TEST_BUS_EN, REG_UFS_CFG1);
-   else
+   } else {
+   ufshcd_rmwl(host->hba, UFS_REG_TEST_BUS_EN, 0, REG_UFS_CFG1);
ufshcd_rmwl(host->hba, TEST_BUS_EN, 0, REG_UFS_CFG1);
+   }
 }
 
 static void ufs_qcom_get_default_testbus_cfg(struct ufs_qcom_host *host)
 {
/* provide a legal default configuration */
-   host->testbus.select_major = TSTBUS_UAWM;
-   host->testbus.select_minor = 1;
+   host->testbus.select_major = TSTBUS_UNIPRO;
+   host->testbus.select_minor = 37;
 }
 
 static bool ufs_qcom_testbus_cfg_is_ok(struct ufs_qcom_host *host)
@@ -1524,7 +1528,7 @@ static bool ufs_qcom_testbus_cfg_is_ok(struct 
ufs_qcom_host *host)
 * mappings of select_minor, since there is no harm in
 * configuring a non-existent select_minor
 */
-   if (host->testbus.select_minor > 0x1F) {
+   if (host->testbus.select_minor > 0xFF) {
dev_err(host->hba->dev,
"%s: 0x%05X is not a legal testbus option\n",
__func__, host->testbus.select_minor);
@@ -1593,7 +1597,8 @@ int ufs_qcom_testbus_config(struct ufs_qcom_host *host)
break;
case TSTBUS_UNIPRO:
reg = UFS_UNIPRO_CFG;
-   offset = 1;
+   offset = 20;
+   mask = 0xFFF;
break;
/*
 * No need for a default case, since
@@ -1612,6 +1617,11 @@ int ufs_qcom_testbus_config(struct ufs_qcom_host *host)
(u32)host->testbus.select_minor << offset,
reg);
ufs_qcom_enable_test_bus(host);
+   /*
+* Make sure the test bus configuration is
+* committed before returning.
+*/
+   mb();
ufshcd_release(host->hba);
pm_runtime_put_sync(host->hba->dev);
 
@@ -1623,13 +1633,39 @@ static void ufs_qcom_testbus_read(struct ufs_hba *hba)
ufs_qcom_dump_regs(hba, UFS_TEST_BUS, 1, "UFS_TEST_BUS ");
 }
 
+static void ufs_qcom_print_unipro_testbus(struct ufs_hba *hba)
+{
+   struct ufs_qcom_host *host = ufshcd_get_variant(hba);
+   u32 *testbus = NULL;
+   int i, nminor = 256, testbus_len = nminor * sizeof(u32);
+
+   testbus = kmalloc(testbus_len, GFP_KERNEL);
+   if (!testbus)
+   return;
+
+   host->testbus.select_major = TSTBUS_UNIPRO;
+   for (i = 0; i < nminor; i++) {
+   host->testbus.select_minor = i;
+   ufs_qcom_testbus_config(host);
+   testbus[i] = ufshcd_readl(hba, UFS_TEST_BUS);
+   }
+   print_hex_dump(KERN_ERR, "UNIPRO_TEST_BUS ", DUMP_PREFIX_OFFSET,
+   16, 4, testbus, testbus_len, false);
+   kfree(testbus);
+}
+
 static void ufs_qcom_dump_dbg_regs(struct ufs_hba *hba)
 {
ufs_qcom_dump_regs(hba, REG_UFS_SYS1CLK_1US, 16,
"HCI Vendor Specific Registers ");
 
+   /* sleep a bit intermittently as we are dumping too much data */
ufs_qcom_print_hw_debug_reg_all(hba, NULL, ufs_qcom_dump_regs_wrapper);
+   usleep_range(1000, 1100);
ufs_qcom_testbus_read(hba);
+   usleep_range(1000, 1100);
+   ufs_qcom_print_unipro_testbus(hba);
+   usleep_range(1000, 1100);
 }
 
 /**
diff --git a/drivers/scsi/ufs/ufs-qcom.h b/drivers/scsi/ufs/ufs-qcom.h
index fe517cd..076f528 100644
--- a/drivers/scsi/ufs/ufs-qcom.h
+++ b/drivers/scsi/ufs/ufs-qcom.h
@@ -95,6 +95,7 @@ enum {
 #define QUNIPRO_SELUFS_BIT(0)
 #define TEST_BUS_ENBIT(18)
 #define TEST_BUS_SEL   GENMASK(22, 19)
+#define UFS_REG_TEST_BUS_ENBIT(30)
 
 /* bit definitions for REG_UFS_CFG2 register */
 #define

[PATCH v1 6/8] scsi: ufs: kick start clock scaling only after device detection

2017-02-03 Thread Subhash Jadavani
UFS clock scaling might start kicking in even before the device
is running at the fastest interface speed which is undesirable.
This change moves the clock scaling kick start only after the
device is detected and running at the fastest interface speed.

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

diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index 4f6ba24..a99a673 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -6330,19 +6330,31 @@ static int ufshcd_probe_hba(struct ufs_hba *hba)
if (ufshcd_scsi_add_wlus(hba))
goto out;
 
+   /* Initialize devfreq after UFS device is detected */
+   if (ufshcd_is_clkscaling_supported(hba)) {
+   memcpy(>clk_scaling.saved_pwr_info.info,
+   >pwr_info,
+   sizeof(struct ufs_pa_layer_attr));
+   hba->clk_scaling.saved_pwr_info.is_valid = true;
+   if (!hba->devfreq) {
+   hba->devfreq = devm_devfreq_add_device(hba->dev,
+   _devfreq_profile,
+   "simple_ondemand",
+   NULL);
+   if (IS_ERR(hba->devfreq)) {
+   ret = PTR_ERR(hba->devfreq);
+   dev_err(hba->dev, "Unable to register 
with devfreq %d\n",
+   ret);
+   goto out;
+   }
+   }
+   hba->clk_scaling.is_allowed = true;
+   }
+
scsi_scan_host(hba->host);
pm_runtime_put_sync(hba->dev);
}
 
-   /* Resume devfreq after UFS device is detected */
-   if (ufshcd_is_clkscaling_supported(hba)) {
-   memcpy(>clk_scaling.saved_pwr_info.info, >pwr_info,
-  sizeof(struct ufs_pa_layer_attr));
-   hba->clk_scaling.saved_pwr_info.is_valid = true;
-   ufshcd_resume_clkscaling(hba);
-   hba->clk_scaling.is_allowed = true;
-   }
-
if (!hba->is_init_prefetch)
hba->is_init_prefetch = true;
 
@@ -6865,7 +6877,8 @@ static void ufshcd_hba_exit(struct ufs_hba *hba)
ufshcd_setup_vreg(hba, false);
ufshcd_suspend_clkscaling(hba);
if (ufshcd_is_clkscaling_supported(hba)) {
-   ufshcd_suspend_clkscaling(hba);
+   if (hba->devfreq)
+   ufshcd_suspend_clkscaling(hba);
destroy_workqueue(hba->clk_scaling.workq);
}
ufshcd_setup_clocks(hba, false);
@@ -7859,16 +7872,6 @@ int ufshcd_init(struct ufs_hba *hba, void __iomem 
*mmio_base, unsigned int irq)
if (ufshcd_is_clkscaling_supported(hba)) {
char wq_name[sizeof("ufs_clkscaling_00")];
 
-   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",
-   PTR_ERR(hba->devfreq));
-   err = PTR_ERR(hba->devfreq);
-   goto out_remove_scsi_host;
-   }
-   hba->clk_scaling.is_suspended = false;
-
INIT_WORK(>clk_scaling.suspend_work,
  ufshcd_clk_scaling_suspend_work);
INIT_WORK(>clk_scaling.resume_work,
@@ -7878,8 +7881,6 @@ int ufshcd_init(struct ufs_hba *hba, void __iomem 
*mmio_base, unsigned int irq)
 host->host_no);
hba->clk_scaling.workq = create_singlethread_workqueue(wq_name);
 
-   /* Suspend devfreq until the UFS device is detected */
-   ufshcd_suspend_clkscaling(hba);
ufshcd_clkscaling_init_sysfs(hba);
}
 
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project



[PATCH v1 7/8] scsi: ufs-qcom: dump additional testbus registers

2017-02-03 Thread Subhash Jadavani
From: Venkat Gopalakrishnan 

Change testbus default config, dump additional testbus registers along
with other debug vendor specific registers. These additional info are
useful in debugging link related failures.

Signed-off-by: Venkat Gopalakrishnan 
Signed-off-by: Subhash Jadavani 
---
 drivers/scsi/ufs/ufs-qcom.c | 48 +++--
 drivers/scsi/ufs/ufs-qcom.h |  1 +
 2 files changed, 43 insertions(+), 6 deletions(-)

diff --git a/drivers/scsi/ufs/ufs-qcom.c b/drivers/scsi/ufs/ufs-qcom.c
index 5ff8a6b..ce5d023 100644
--- a/drivers/scsi/ufs/ufs-qcom.c
+++ b/drivers/scsi/ufs/ufs-qcom.c
@@ -1497,17 +1497,21 @@ static void ufs_qcom_print_hw_debug_reg_all(struct 
ufs_hba *hba,
 
 static void ufs_qcom_enable_test_bus(struct ufs_qcom_host *host)
 {
-   if (host->dbg_print_en & UFS_QCOM_DBG_PRINT_TEST_BUS_EN)
+   if (host->dbg_print_en & UFS_QCOM_DBG_PRINT_TEST_BUS_EN) {
+   ufshcd_rmwl(host->hba, UFS_REG_TEST_BUS_EN,
+   UFS_REG_TEST_BUS_EN, REG_UFS_CFG1);
ufshcd_rmwl(host->hba, TEST_BUS_EN, TEST_BUS_EN, REG_UFS_CFG1);
-   else
+   } else {
+   ufshcd_rmwl(host->hba, UFS_REG_TEST_BUS_EN, 0, REG_UFS_CFG1);
ufshcd_rmwl(host->hba, TEST_BUS_EN, 0, REG_UFS_CFG1);
+   }
 }
 
 static void ufs_qcom_get_default_testbus_cfg(struct ufs_qcom_host *host)
 {
/* provide a legal default configuration */
-   host->testbus.select_major = TSTBUS_UAWM;
-   host->testbus.select_minor = 1;
+   host->testbus.select_major = TSTBUS_UNIPRO;
+   host->testbus.select_minor = 37;
 }
 
 static bool ufs_qcom_testbus_cfg_is_ok(struct ufs_qcom_host *host)
@@ -1524,7 +1528,7 @@ static bool ufs_qcom_testbus_cfg_is_ok(struct 
ufs_qcom_host *host)
 * mappings of select_minor, since there is no harm in
 * configuring a non-existent select_minor
 */
-   if (host->testbus.select_minor > 0x1F) {
+   if (host->testbus.select_minor > 0xFF) {
dev_err(host->hba->dev,
"%s: 0x%05X is not a legal testbus option\n",
__func__, host->testbus.select_minor);
@@ -1593,7 +1597,8 @@ int ufs_qcom_testbus_config(struct ufs_qcom_host *host)
break;
case TSTBUS_UNIPRO:
reg = UFS_UNIPRO_CFG;
-   offset = 1;
+   offset = 20;
+   mask = 0xFFF;
break;
/*
 * No need for a default case, since
@@ -1612,6 +1617,11 @@ int ufs_qcom_testbus_config(struct ufs_qcom_host *host)
(u32)host->testbus.select_minor << offset,
reg);
ufs_qcom_enable_test_bus(host);
+   /*
+* Make sure the test bus configuration is
+* committed before returning.
+*/
+   mb();
ufshcd_release(host->hba);
pm_runtime_put_sync(host->hba->dev);
 
@@ -1623,13 +1633,39 @@ static void ufs_qcom_testbus_read(struct ufs_hba *hba)
ufs_qcom_dump_regs(hba, UFS_TEST_BUS, 1, "UFS_TEST_BUS ");
 }
 
+static void ufs_qcom_print_unipro_testbus(struct ufs_hba *hba)
+{
+   struct ufs_qcom_host *host = ufshcd_get_variant(hba);
+   u32 *testbus = NULL;
+   int i, nminor = 256, testbus_len = nminor * sizeof(u32);
+
+   testbus = kmalloc(testbus_len, GFP_KERNEL);
+   if (!testbus)
+   return;
+
+   host->testbus.select_major = TSTBUS_UNIPRO;
+   for (i = 0; i < nminor; i++) {
+   host->testbus.select_minor = i;
+   ufs_qcom_testbus_config(host);
+   testbus[i] = ufshcd_readl(hba, UFS_TEST_BUS);
+   }
+   print_hex_dump(KERN_ERR, "UNIPRO_TEST_BUS ", DUMP_PREFIX_OFFSET,
+   16, 4, testbus, testbus_len, false);
+   kfree(testbus);
+}
+
 static void ufs_qcom_dump_dbg_regs(struct ufs_hba *hba)
 {
ufs_qcom_dump_regs(hba, REG_UFS_SYS1CLK_1US, 16,
"HCI Vendor Specific Registers ");
 
+   /* sleep a bit intermittently as we are dumping too much data */
ufs_qcom_print_hw_debug_reg_all(hba, NULL, ufs_qcom_dump_regs_wrapper);
+   usleep_range(1000, 1100);
ufs_qcom_testbus_read(hba);
+   usleep_range(1000, 1100);
+   ufs_qcom_print_unipro_testbus(hba);
+   usleep_range(1000, 1100);
 }
 
 /**
diff --git a/drivers/scsi/ufs/ufs-qcom.h b/drivers/scsi/ufs/ufs-qcom.h
index fe517cd..076f528 100644
--- a/drivers/scsi/ufs/ufs-qcom.h
+++ b/drivers/scsi/ufs/ufs-qcom.h
@@ -95,6 +95,7 @@ enum {
 #define QUNIPRO_SELUFS_BIT(0)
 #define TEST_BUS_ENBIT(18)
 #define TEST_BUS_SEL   GENMASK(22, 19)
+#define UFS_REG_TEST_BUS_ENBIT(30)
 
 /* bit definitions for REG_UFS_CFG2 register */
 #define UAWM_HW_CGC_EN (1 << 0)
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project



[PATCH v1 6/8] scsi: ufs: kick start clock scaling only after device detection

2017-02-03 Thread Subhash Jadavani
UFS clock scaling might start kicking in even before the device
is running at the fastest interface speed which is undesirable.
This change moves the clock scaling kick start only after the
device is detected and running at the fastest interface speed.

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

diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index 4f6ba24..a99a673 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -6330,19 +6330,31 @@ static int ufshcd_probe_hba(struct ufs_hba *hba)
if (ufshcd_scsi_add_wlus(hba))
goto out;
 
+   /* Initialize devfreq after UFS device is detected */
+   if (ufshcd_is_clkscaling_supported(hba)) {
+   memcpy(>clk_scaling.saved_pwr_info.info,
+   >pwr_info,
+   sizeof(struct ufs_pa_layer_attr));
+   hba->clk_scaling.saved_pwr_info.is_valid = true;
+   if (!hba->devfreq) {
+   hba->devfreq = devm_devfreq_add_device(hba->dev,
+   _devfreq_profile,
+   "simple_ondemand",
+   NULL);
+   if (IS_ERR(hba->devfreq)) {
+   ret = PTR_ERR(hba->devfreq);
+   dev_err(hba->dev, "Unable to register 
with devfreq %d\n",
+   ret);
+   goto out;
+   }
+   }
+   hba->clk_scaling.is_allowed = true;
+   }
+
scsi_scan_host(hba->host);
pm_runtime_put_sync(hba->dev);
}
 
-   /* Resume devfreq after UFS device is detected */
-   if (ufshcd_is_clkscaling_supported(hba)) {
-   memcpy(>clk_scaling.saved_pwr_info.info, >pwr_info,
-  sizeof(struct ufs_pa_layer_attr));
-   hba->clk_scaling.saved_pwr_info.is_valid = true;
-   ufshcd_resume_clkscaling(hba);
-   hba->clk_scaling.is_allowed = true;
-   }
-
if (!hba->is_init_prefetch)
hba->is_init_prefetch = true;
 
@@ -6865,7 +6877,8 @@ static void ufshcd_hba_exit(struct ufs_hba *hba)
ufshcd_setup_vreg(hba, false);
ufshcd_suspend_clkscaling(hba);
if (ufshcd_is_clkscaling_supported(hba)) {
-   ufshcd_suspend_clkscaling(hba);
+   if (hba->devfreq)
+   ufshcd_suspend_clkscaling(hba);
destroy_workqueue(hba->clk_scaling.workq);
}
ufshcd_setup_clocks(hba, false);
@@ -7859,16 +7872,6 @@ int ufshcd_init(struct ufs_hba *hba, void __iomem 
*mmio_base, unsigned int irq)
if (ufshcd_is_clkscaling_supported(hba)) {
char wq_name[sizeof("ufs_clkscaling_00")];
 
-   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",
-   PTR_ERR(hba->devfreq));
-   err = PTR_ERR(hba->devfreq);
-   goto out_remove_scsi_host;
-   }
-   hba->clk_scaling.is_suspended = false;
-
INIT_WORK(>clk_scaling.suspend_work,
  ufshcd_clk_scaling_suspend_work);
INIT_WORK(>clk_scaling.resume_work,
@@ -7878,8 +7881,6 @@ int ufshcd_init(struct ufs_hba *hba, void __iomem 
*mmio_base, unsigned int irq)
 host->host_no);
hba->clk_scaling.workq = create_singlethread_workqueue(wq_name);
 
-   /* Suspend devfreq until the UFS device is detected */
-   ufshcd_suspend_clkscaling(hba);
ufshcd_clkscaling_init_sysfs(hba);
}
 
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project



[PATCH v1 5/8] scsi: ufs: don't suspend clock scaling during clock gating

2017-02-03 Thread Subhash Jadavani
Currently we are suspending clock scaling during clock gating which doesn't
allow us to have clock gating timeout lower than clock scaling polling
window. If clock gating timeout is smaller than the clock scaling polling
window then we will mostly suspend the clock scaling before clock scaling
polling window expires and we might get stuck in same state (scaled down
or scaled up) for quite a long time. And for this reason, we have clock
gating timeout (150ms) greater than clock scaling polling window (100ms).

We would like to have aggressive clock gating timeout even lower than the
clock scaling polling window hence this change is decoupling the clock
scaling suspend/resume from clock gate/ungate. We will not suspend the
clock scaling as part of clock gating instead clock scaling context will
schedule scaling suspend work if there are no more pending transfer
requests.

Signed-off-by: Subhash Jadavani <subha...@codeaurora.org>
---
 drivers/scsi/ufs/ufshcd.c | 185 --
 drivers/scsi/ufs/ufshcd.h |  31 +++-
 2 files changed, 171 insertions(+), 45 deletions(-)

diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index 056e912..4f6ba24 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -248,6 +248,7 @@ static int __ufshcd_setup_clocks(struct ufs_hba *hba, bool 
on,
 static int ufshcd_host_reset_and_restore(struct ufs_hba *hba);
 static void ufshcd_resume_clkscaling(struct ufs_hba *hba);
 static void ufshcd_suspend_clkscaling(struct ufs_hba *hba);
+static void __ufshcd_suspend_clkscaling(struct ufs_hba *hba);
 static int ufshcd_scale_clks(struct ufs_hba *hba, bool scale_up);
 static irqreturn_t ufshcd_intr(int irq, void *__hba);
 static int ufshcd_config_pwr_mode(struct ufs_hba *hba,
@@ -1135,6 +1136,9 @@ static int ufshcd_devfreq_scale(struct ufs_hba *hba, bool 
scale_up)
 {
int ret = 0;
 
+   /* let's not get into low power until clock scaling is completed */
+   ufshcd_hold(hba, false);
+
ret = ufshcd_clock_scaling_prepare(hba);
if (ret)
return ret;
@@ -1166,16 +1170,51 @@ static int ufshcd_devfreq_scale(struct ufs_hba *hba, 
bool scale_up)
 
 out:
ufshcd_clock_scaling_unprepare(hba);
+   ufshcd_release(hba);
return ret;
 }
 
+static void ufshcd_clk_scaling_suspend_work(struct work_struct *work)
+{
+   struct ufs_hba *hba = container_of(work, struct ufs_hba,
+  clk_scaling.suspend_work);
+   unsigned long irq_flags;
+
+   spin_lock_irqsave(hba->host->host_lock, irq_flags);
+   if (hba->clk_scaling.active_reqs || hba->clk_scaling.is_suspended) {
+   spin_unlock_irqrestore(hba->host->host_lock, irq_flags);
+   return;
+   }
+   hba->clk_scaling.is_suspended = true;
+   spin_unlock_irqrestore(hba->host->host_lock, irq_flags);
+
+   __ufshcd_suspend_clkscaling(hba);
+}
+
+static void ufshcd_clk_scaling_resume_work(struct work_struct *work)
+{
+   struct ufs_hba *hba = container_of(work, struct ufs_hba,
+  clk_scaling.resume_work);
+   unsigned long irq_flags;
+
+   spin_lock_irqsave(hba->host->host_lock, irq_flags);
+   if (!hba->clk_scaling.is_suspended) {
+   spin_unlock_irqrestore(hba->host->host_lock, irq_flags);
+   return;
+   }
+   hba->clk_scaling.is_suspended = false;
+   spin_unlock_irqrestore(hba->host->host_lock, irq_flags);
+
+   devfreq_resume_device(hba->devfreq);
+}
+
 static int ufshcd_devfreq_target(struct device *dev,
unsigned long *freq, u32 flags)
 {
int ret = 0;
struct ufs_hba *hba = dev_get_drvdata(dev);
ktime_t start;
-   bool scale_up, release_clk_hold = false;
+   bool scale_up, sched_clk_scaling_suspend_work = false;
unsigned long irq_flags;
 
if (!ufshcd_is_clkscaling_supported(hba))
@@ -1186,50 +1225,35 @@ static int ufshcd_devfreq_target(struct device *dev,
return -EINVAL;
}
 
-   scale_up = (*freq == UINT_MAX) ? true : false;
-   if (!ufshcd_is_devfreq_scaling_required(hba, scale_up))
-   return 0; /* no state change required */
-
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)) {
-   if (cancel_delayed_work(>clk_gating.gate_work) ||
-   (hba->clk_gating.state == CLKS_ON)) {
-   /* hold the vote until the scaling work is completed */
-   hba->clk_gating.active_reqs++;
-   release_clk_hold = true;
-   if (hba->clk_gating

[PATCH v1 5/8] scsi: ufs: don't suspend clock scaling during clock gating

2017-02-03 Thread Subhash Jadavani
Currently we are suspending clock scaling during clock gating which doesn't
allow us to have clock gating timeout lower than clock scaling polling
window. If clock gating timeout is smaller than the clock scaling polling
window then we will mostly suspend the clock scaling before clock scaling
polling window expires and we might get stuck in same state (scaled down
or scaled up) for quite a long time. And for this reason, we have clock
gating timeout (150ms) greater than clock scaling polling window (100ms).

We would like to have aggressive clock gating timeout even lower than the
clock scaling polling window hence this change is decoupling the clock
scaling suspend/resume from clock gate/ungate. We will not suspend the
clock scaling as part of clock gating instead clock scaling context will
schedule scaling suspend work if there are no more pending transfer
requests.

Signed-off-by: Subhash Jadavani 
---
 drivers/scsi/ufs/ufshcd.c | 185 --
 drivers/scsi/ufs/ufshcd.h |  31 +++-
 2 files changed, 171 insertions(+), 45 deletions(-)

diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index 056e912..4f6ba24 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -248,6 +248,7 @@ static int __ufshcd_setup_clocks(struct ufs_hba *hba, bool 
on,
 static int ufshcd_host_reset_and_restore(struct ufs_hba *hba);
 static void ufshcd_resume_clkscaling(struct ufs_hba *hba);
 static void ufshcd_suspend_clkscaling(struct ufs_hba *hba);
+static void __ufshcd_suspend_clkscaling(struct ufs_hba *hba);
 static int ufshcd_scale_clks(struct ufs_hba *hba, bool scale_up);
 static irqreturn_t ufshcd_intr(int irq, void *__hba);
 static int ufshcd_config_pwr_mode(struct ufs_hba *hba,
@@ -1135,6 +1136,9 @@ static int ufshcd_devfreq_scale(struct ufs_hba *hba, bool 
scale_up)
 {
int ret = 0;
 
+   /* let's not get into low power until clock scaling is completed */
+   ufshcd_hold(hba, false);
+
ret = ufshcd_clock_scaling_prepare(hba);
if (ret)
return ret;
@@ -1166,16 +1170,51 @@ static int ufshcd_devfreq_scale(struct ufs_hba *hba, 
bool scale_up)
 
 out:
ufshcd_clock_scaling_unprepare(hba);
+   ufshcd_release(hba);
return ret;
 }
 
+static void ufshcd_clk_scaling_suspend_work(struct work_struct *work)
+{
+   struct ufs_hba *hba = container_of(work, struct ufs_hba,
+  clk_scaling.suspend_work);
+   unsigned long irq_flags;
+
+   spin_lock_irqsave(hba->host->host_lock, irq_flags);
+   if (hba->clk_scaling.active_reqs || hba->clk_scaling.is_suspended) {
+   spin_unlock_irqrestore(hba->host->host_lock, irq_flags);
+   return;
+   }
+   hba->clk_scaling.is_suspended = true;
+   spin_unlock_irqrestore(hba->host->host_lock, irq_flags);
+
+   __ufshcd_suspend_clkscaling(hba);
+}
+
+static void ufshcd_clk_scaling_resume_work(struct work_struct *work)
+{
+   struct ufs_hba *hba = container_of(work, struct ufs_hba,
+  clk_scaling.resume_work);
+   unsigned long irq_flags;
+
+   spin_lock_irqsave(hba->host->host_lock, irq_flags);
+   if (!hba->clk_scaling.is_suspended) {
+   spin_unlock_irqrestore(hba->host->host_lock, irq_flags);
+   return;
+   }
+   hba->clk_scaling.is_suspended = false;
+   spin_unlock_irqrestore(hba->host->host_lock, irq_flags);
+
+   devfreq_resume_device(hba->devfreq);
+}
+
 static int ufshcd_devfreq_target(struct device *dev,
unsigned long *freq, u32 flags)
 {
int ret = 0;
struct ufs_hba *hba = dev_get_drvdata(dev);
ktime_t start;
-   bool scale_up, release_clk_hold = false;
+   bool scale_up, sched_clk_scaling_suspend_work = false;
unsigned long irq_flags;
 
if (!ufshcd_is_clkscaling_supported(hba))
@@ -1186,50 +1225,35 @@ static int ufshcd_devfreq_target(struct device *dev,
return -EINVAL;
}
 
-   scale_up = (*freq == UINT_MAX) ? true : false;
-   if (!ufshcd_is_devfreq_scaling_required(hba, scale_up))
-   return 0; /* no state change required */
-
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)) {
-   if (cancel_delayed_work(>clk_gating.gate_work) ||
-   (hba->clk_gating.state == CLKS_ON)) {
-   /* hold the vote until the scaling work is completed */
-   hba->clk_gating.active_reqs++;
-   release_clk_hold = true;
-   if (hba->clk_gating.state

[PATCH v1 4/8] scsi: ufs: add host state prints in failure cases

2017-02-03 Thread Subhash Jadavani
From: Gilad Broner <gbro...@codeaurora.org>

Whenever some UFS failure occurs the driver prints the UFS
registers in order to help with analysis of the failure.
However this may not be sufficient in some cases, so having
the host controller state as it is represented and managed in
the driver will contribute to analysis efforts.
Added prints of various fields in the hba struct which may be
of interest.

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

diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index e75e50d..056e912 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -453,6 +453,28 @@ static void ufshcd_print_tmrs(struct ufs_hba *hba, 
unsigned long bitmap)
}
 }
 
+static void ufshcd_print_host_state(struct ufs_hba *hba)
+{
+   dev_err(hba->dev, "UFS Host state=%d\n", hba->ufshcd_state);
+   dev_err(hba->dev, "lrb in use=0x%lx, outstanding reqs=0x%lx 
tasks=0x%lx\n",
+   hba->lrb_in_use, hba->outstanding_tasks, hba->outstanding_reqs);
+   dev_err(hba->dev, "saved_err=0x%x, saved_uic_err=0x%x\n",
+   hba->saved_err, hba->saved_uic_err);
+   dev_err(hba->dev, "Device power mode=%d, UIC link state=%d\n",
+   hba->curr_dev_pwr_mode, hba->uic_link_state);
+   dev_err(hba->dev, "PM in progress=%d, sys. suspended=%d\n",
+   hba->pm_op_in_progress, hba->is_sys_suspended);
+   dev_err(hba->dev, "Auto BKOPS=%d, Host self-block=%d\n",
+   hba->auto_bkops_enabled, hba->host->host_self_blocked);
+   dev_err(hba->dev, "Clk gate=%d\n", hba->clk_gating.state);
+   dev_err(hba->dev, "error handling flags=0x%x, req. abort count=%d\n",
+   hba->eh_flags, hba->req_abort_count);
+   dev_err(hba->dev, "Host capabilities=0x%x, caps=0x%x\n",
+   hba->capabilities, hba->caps);
+   dev_err(hba->dev, "quirks=0x%x, dev. quirks=0x%x\n", hba->quirks,
+   hba->dev_quirks);
+}
+
 /**
  * ufshcd_print_pwr_info - print power params as saved in hba
  * power info
@@ -4426,6 +4448,7 @@ static int ufshcd_task_req_compl(struct ufs_hba *hba, u32 
index, u8 *resp)
"OCS error from controller = %x for tag %d\n",
ocs, lrbp->task_tag);
ufshcd_print_host_regs(hba);
+   ufshcd_print_host_state(hba);
break;
} /* end of switch */
 
@@ -5477,6 +5500,7 @@ static int ufshcd_abort(struct scsi_cmnd *cmd)
scsi_print_command(hba->lrb[tag].cmd);
if (!hba->req_abort_count) {
ufshcd_print_host_regs(hba);
+   ufshcd_print_host_state(hba);
ufshcd_print_pwr_info(hba);
ufshcd_print_trs(hba, 1 << tag, true);
} else {
@@ -7738,6 +7762,7 @@ int ufshcd_init(struct ufs_hba *hba, void __iomem 
*mmio_base, unsigned int irq)
if (err) {
dev_err(hba->dev, "Host controller enable failed\n");
ufshcd_print_host_regs(hba);
+   ufshcd_print_host_state(hba);
goto out_remove_scsi_host;
}
 
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project



[PATCH v1 4/8] scsi: ufs: add host state prints in failure cases

2017-02-03 Thread Subhash Jadavani
From: Gilad Broner 

Whenever some UFS failure occurs the driver prints the UFS
registers in order to help with analysis of the failure.
However this may not be sufficient in some cases, so having
the host controller state as it is represented and managed in
the driver will contribute to analysis efforts.
Added prints of various fields in the hba struct which may be
of interest.

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

diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index e75e50d..056e912 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -453,6 +453,28 @@ static void ufshcd_print_tmrs(struct ufs_hba *hba, 
unsigned long bitmap)
}
 }
 
+static void ufshcd_print_host_state(struct ufs_hba *hba)
+{
+   dev_err(hba->dev, "UFS Host state=%d\n", hba->ufshcd_state);
+   dev_err(hba->dev, "lrb in use=0x%lx, outstanding reqs=0x%lx 
tasks=0x%lx\n",
+   hba->lrb_in_use, hba->outstanding_tasks, hba->outstanding_reqs);
+   dev_err(hba->dev, "saved_err=0x%x, saved_uic_err=0x%x\n",
+   hba->saved_err, hba->saved_uic_err);
+   dev_err(hba->dev, "Device power mode=%d, UIC link state=%d\n",
+   hba->curr_dev_pwr_mode, hba->uic_link_state);
+   dev_err(hba->dev, "PM in progress=%d, sys. suspended=%d\n",
+   hba->pm_op_in_progress, hba->is_sys_suspended);
+   dev_err(hba->dev, "Auto BKOPS=%d, Host self-block=%d\n",
+   hba->auto_bkops_enabled, hba->host->host_self_blocked);
+   dev_err(hba->dev, "Clk gate=%d\n", hba->clk_gating.state);
+   dev_err(hba->dev, "error handling flags=0x%x, req. abort count=%d\n",
+   hba->eh_flags, hba->req_abort_count);
+   dev_err(hba->dev, "Host capabilities=0x%x, caps=0x%x\n",
+   hba->capabilities, hba->caps);
+   dev_err(hba->dev, "quirks=0x%x, dev. quirks=0x%x\n", hba->quirks,
+   hba->dev_quirks);
+}
+
 /**
  * ufshcd_print_pwr_info - print power params as saved in hba
  * power info
@@ -4426,6 +4448,7 @@ static int ufshcd_task_req_compl(struct ufs_hba *hba, u32 
index, u8 *resp)
"OCS error from controller = %x for tag %d\n",
ocs, lrbp->task_tag);
ufshcd_print_host_regs(hba);
+   ufshcd_print_host_state(hba);
break;
} /* end of switch */
 
@@ -5477,6 +5500,7 @@ static int ufshcd_abort(struct scsi_cmnd *cmd)
scsi_print_command(hba->lrb[tag].cmd);
if (!hba->req_abort_count) {
ufshcd_print_host_regs(hba);
+   ufshcd_print_host_state(hba);
ufshcd_print_pwr_info(hba);
ufshcd_print_trs(hba, 1 << tag, true);
} else {
@@ -7738,6 +7762,7 @@ int ufshcd_init(struct ufs_hba *hba, void __iomem 
*mmio_base, unsigned int irq)
if (err) {
dev_err(hba->dev, "Host controller enable failed\n");
ufshcd_print_host_regs(hba);
+   ufshcd_print_host_state(hba);
goto out_remove_scsi_host;
}
 
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project



[PATCH v1 3/8] scsi: ufs: add load based scaling of UFS gear

2017-02-03 Thread Subhash Jadavani
UFS driver's load based clock scaling feature scales down the ufs related
clocks in order to allow low power modes of chipsets. UniPro 1.6 supports
maximum gear up to HS-G3 (High Speed Gear3) and some of the chipsets
low power modes may not be allowed in HS-G3 hence this change adds support
to scale gear between HS-G3 and HS-G1 based on same existing load based
clock scaling logic.

Signed-off-by: Subhash Jadavani <subha...@codeaurora.org>
---
 drivers/scsi/ufs/ufshcd.c | 594 --
 drivers/scsi/ufs/ufshcd.h |   9 +
 2 files changed, 428 insertions(+), 175 deletions(-)

diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index 64d619a..e75e50d 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -867,6 +867,396 @@ static bool ufshcd_is_unipro_pa_params_tuning_req(struct 
ufs_hba *hba)
return false;
 }
 
+static int ufshcd_scale_clks(struct ufs_hba *hba, bool scale_up)
+{
+   int ret = 0;
+   struct ufs_clk_info *clki;
+   struct list_head *head = >clk_list_head;
+   ktime_t start = ktime_get();
+   bool clk_state_changed = false;
+
+   if (!head || list_empty(head))
+   goto out;
+
+   ret = ufshcd_vops_clk_scale_notify(hba, scale_up, PRE_CHANGE);
+   if (ret)
+   return ret;
+
+   list_for_each_entry(clki, head, list) {
+   if (!IS_ERR_OR_NULL(clki->clk)) {
+   if (scale_up && clki->max_freq) {
+   if (clki->curr_freq == clki->max_freq)
+   continue;
+
+   clk_state_changed = true;
+   ret = clk_set_rate(clki->clk, clki->max_freq);
+   if (ret) {
+   dev_err(hba->dev, "%s: %s clk set 
rate(%dHz) failed, %d\n",
+   __func__, clki->name,
+   clki->max_freq, ret);
+   break;
+   }
+   trace_ufshcd_clk_scaling(dev_name(hba->dev),
+   "scaled up", clki->name,
+   clki->curr_freq,
+   clki->max_freq);
+
+   clki->curr_freq = clki->max_freq;
+
+   } else if (!scale_up && clki->min_freq) {
+   if (clki->curr_freq == clki->min_freq)
+   continue;
+
+   clk_state_changed = true;
+   ret = clk_set_rate(clki->clk, clki->min_freq);
+   if (ret) {
+   dev_err(hba->dev, "%s: %s clk set 
rate(%dHz) failed, %d\n",
+   __func__, clki->name,
+   clki->min_freq, ret);
+   break;
+   }
+   trace_ufshcd_clk_scaling(dev_name(hba->dev),
+   "scaled down", clki->name,
+   clki->curr_freq,
+   clki->min_freq);
+   clki->curr_freq = clki->min_freq;
+   }
+   }
+   dev_dbg(hba->dev, "%s: clk: %s, rate: %lu\n", __func__,
+   clki->name, clk_get_rate(clki->clk));
+   }
+
+   ret = ufshcd_vops_clk_scale_notify(hba, scale_up, POST_CHANGE);
+
+out:
+   if (clk_state_changed)
+   trace_ufshcd_profile_clk_scaling(dev_name(hba->dev),
+   (scale_up ? "up" : "down"),
+   ktime_to_us(ktime_sub(ktime_get(), start)), ret);
+   return ret;
+}
+
+/**
+ * ufshcd_is_devfreq_scaling_required - check if scaling is required or not
+ * @hba: per adapter instance
+ * @scale_up: True if scaling up and false if scaling down
+ *
+ * Returns true if scaling is required, false otherwise.
+ */
+static bool ufshcd_is_devfreq_scaling_required(struct ufs_hba *hba,
+  bool scale_up)
+{
+   struct ufs_clk_info *clki;
+   struct list_head *head = >clk_list_head;
+
+   if (!head || list_empty(head))
+   return false;
+
+   list_for_each_entry(clki, head, list) {
+   if (!IS_ERR_OR_NULL(clki->clk)) {
+   if (scale_up && clki->max_freq) {
+

[PATCH v1 3/8] scsi: ufs: add load based scaling of UFS gear

2017-02-03 Thread Subhash Jadavani
UFS driver's load based clock scaling feature scales down the ufs related
clocks in order to allow low power modes of chipsets. UniPro 1.6 supports
maximum gear up to HS-G3 (High Speed Gear3) and some of the chipsets
low power modes may not be allowed in HS-G3 hence this change adds support
to scale gear between HS-G3 and HS-G1 based on same existing load based
clock scaling logic.

Signed-off-by: Subhash Jadavani 
---
 drivers/scsi/ufs/ufshcd.c | 594 --
 drivers/scsi/ufs/ufshcd.h |   9 +
 2 files changed, 428 insertions(+), 175 deletions(-)

diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index 64d619a..e75e50d 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -867,6 +867,396 @@ static bool ufshcd_is_unipro_pa_params_tuning_req(struct 
ufs_hba *hba)
return false;
 }
 
+static int ufshcd_scale_clks(struct ufs_hba *hba, bool scale_up)
+{
+   int ret = 0;
+   struct ufs_clk_info *clki;
+   struct list_head *head = >clk_list_head;
+   ktime_t start = ktime_get();
+   bool clk_state_changed = false;
+
+   if (!head || list_empty(head))
+   goto out;
+
+   ret = ufshcd_vops_clk_scale_notify(hba, scale_up, PRE_CHANGE);
+   if (ret)
+   return ret;
+
+   list_for_each_entry(clki, head, list) {
+   if (!IS_ERR_OR_NULL(clki->clk)) {
+   if (scale_up && clki->max_freq) {
+   if (clki->curr_freq == clki->max_freq)
+   continue;
+
+   clk_state_changed = true;
+   ret = clk_set_rate(clki->clk, clki->max_freq);
+   if (ret) {
+   dev_err(hba->dev, "%s: %s clk set 
rate(%dHz) failed, %d\n",
+   __func__, clki->name,
+   clki->max_freq, ret);
+   break;
+   }
+   trace_ufshcd_clk_scaling(dev_name(hba->dev),
+   "scaled up", clki->name,
+   clki->curr_freq,
+   clki->max_freq);
+
+   clki->curr_freq = clki->max_freq;
+
+   } else if (!scale_up && clki->min_freq) {
+   if (clki->curr_freq == clki->min_freq)
+   continue;
+
+   clk_state_changed = true;
+   ret = clk_set_rate(clki->clk, clki->min_freq);
+   if (ret) {
+   dev_err(hba->dev, "%s: %s clk set 
rate(%dHz) failed, %d\n",
+   __func__, clki->name,
+   clki->min_freq, ret);
+   break;
+   }
+   trace_ufshcd_clk_scaling(dev_name(hba->dev),
+   "scaled down", clki->name,
+   clki->curr_freq,
+   clki->min_freq);
+   clki->curr_freq = clki->min_freq;
+   }
+   }
+   dev_dbg(hba->dev, "%s: clk: %s, rate: %lu\n", __func__,
+   clki->name, clk_get_rate(clki->clk));
+   }
+
+   ret = ufshcd_vops_clk_scale_notify(hba, scale_up, POST_CHANGE);
+
+out:
+   if (clk_state_changed)
+   trace_ufshcd_profile_clk_scaling(dev_name(hba->dev),
+   (scale_up ? "up" : "down"),
+   ktime_to_us(ktime_sub(ktime_get(), start)), ret);
+   return ret;
+}
+
+/**
+ * ufshcd_is_devfreq_scaling_required - check if scaling is required or not
+ * @hba: per adapter instance
+ * @scale_up: True if scaling up and false if scaling down
+ *
+ * Returns true if scaling is required, false otherwise.
+ */
+static bool ufshcd_is_devfreq_scaling_required(struct ufs_hba *hba,
+  bool scale_up)
+{
+   struct ufs_clk_info *clki;
+   struct list_head *head = >clk_list_head;
+
+   if (!head || list_empty(head))
+   return false;
+
+   list_for_each_entry(clki, head, list) {
+   if (!IS_ERR_OR_NULL(clki->clk)) {
+   if (scale_up && clki->max_freq) {
+   if (clki->curr_freq == clki->max_freq)
+

[PATCH v1 2/8] scsi: ufs: reduce printout for aborted requests

2017-02-03 Thread Subhash Jadavani
From: Gilad Broner <gbro...@codeaurora.org>

Details printed for each request that is aborted can overload the
target as there can be several requests that are aborted at once.
This change will print full request details only for the first
aborted request since the last link reset, and minimal details
for other subsequent requests.

Signed-off-by: Gilad Broner <gbro...@codeaurora.org>
Signed-off-by: Subhash Jadavani <subha...@codeaurora.org>
---
 drivers/scsi/ufs/ufshcd.c | 46 --
 drivers/scsi/ufs/ufshcd.h |  3 +++
 2 files changed, 35 insertions(+), 14 deletions(-)

diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index 61fea17..64d619a 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -396,6 +396,7 @@ static void ufshcd_print_host_regs(struct ufs_hba *hba)
 void ufshcd_print_trs(struct ufs_hba *hba, unsigned long bitmap, bool pr_prdt)
 {
struct ufshcd_lrb *lrbp;
+   int prdt_length;
int tag;
 
for_each_set_bit(tag, , hba->nutrs) {
@@ -417,18 +418,17 @@ void ufshcd_print_trs(struct ufs_hba *hba, unsigned long 
bitmap, bool pr_prdt)
(u64)lrbp->ucd_rsp_dma_addr);
ufshcd_hex_dump("UPIU RSP: ", lrbp->ucd_rsp_ptr,
sizeof(struct utp_upiu_rsp));
-   if (pr_prdt) {
-   int prdt_length = le16_to_cpu(
-   lrbp->utr_descriptor_ptr->prd_table_length);
 
-   dev_err(hba->dev,
-   "UPIU[%d] - PRDT - %d entries  phys@0x%llx\n",
-   tag, prdt_length,
-   (u64)lrbp->ucd_prdt_dma_addr);
+   prdt_length = le16_to_cpu(
+   lrbp->utr_descriptor_ptr->prd_table_length);
+   dev_err(hba->dev,
+   "UPIU[%d] - PRDT - %d entries  phys@0x%llx\n",
+   tag, prdt_length,
+   (u64)lrbp->ucd_prdt_dma_addr);
+
+   if (pr_prdt)
ufshcd_hex_dump("UPIU PRDT: ", lrbp->ucd_prdt_ptr,
-   sizeof(struct ufshcd_sg_entry) *
-   prdt_length);
-   }
+   sizeof(struct ufshcd_sg_entry) * prdt_length);
}
 }
 
@@ -1848,6 +1848,8 @@ static int ufshcd_queuecommand(struct Scsi_Host *host, 
struct scsi_cmnd *cmd)
}
spin_unlock_irqrestore(hba->host->host_lock, flags);
 
+   hba->req_abort_count = 0;
+
/* acquire the tag to make sure device cmds don't use it */
if (test_and_set_bit_lock(tag, >lrb_in_use)) {
/*
@@ -4970,7 +4972,9 @@ static int ufshcd_eh_device_reset_handler(struct 
scsi_cmnd *cmd)
spin_lock_irqsave(host->host_lock, flags);
ufshcd_transfer_req_compl(hba);
spin_unlock_irqrestore(host->host_lock, flags);
+
 out:
+   hba->req_abort_count = 0;
if (!err) {
err = SUCCESS;
} else {
@@ -5054,11 +5058,23 @@ static int ufshcd_abort(struct scsi_cmnd *cmd)
 
/* Print Transfer Request of aborted task */
dev_err(hba->dev, "%s: Device abort task at tag %d\n", __func__, tag);
-   scsi_print_command(hba->lrb[tag].cmd);
-   ufshcd_print_host_regs(hba);
-   ufshcd_print_pwr_info(hba);
-   ufshcd_print_trs(hba, 1 << tag, true);
 
+   /*
+* Print detailed info about aborted request.
+* As more than one request might get aborted at the same time,
+* print full information only for the first aborted request in order
+* to reduce repeated printouts. For other aborted requests only print
+* basic details.
+*/
+   scsi_print_command(hba->lrb[tag].cmd);
+   if (!hba->req_abort_count) {
+   ufshcd_print_host_regs(hba);
+   ufshcd_print_pwr_info(hba);
+   ufshcd_print_trs(hba, 1 << tag, true);
+   } else {
+   ufshcd_print_trs(hba, 1 << tag, false);
+   }
+   hba->req_abort_count++;
 
/* Skip task abort in case previous aborts failed and report failure */
if (lrbp->req_abort_skip) {
@@ -5707,6 +5723,8 @@ static void ufshcd_clear_dbg_ufs_stats(struct ufs_hba 
*hba)
memset(>ufs_stats.nl_err, 0, err_reg_hist_size);
memset(>ufs_stats.tl_err, 0, err_reg_hist_size);
memset(>ufs_stats.dme_err, 0, err_reg_hist_size);
+
+   hba->req_abort_count = 0;
 }
 
 /**
diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h
index 292fc14..b7ce129 100644
--- a/drivers/scsi/ufs/ufshcd.h
+++ b/drivers/scsi/ufs/ufshcd.h
@@ -594,6 +594,9 @@ struct ufs_hba {
 
bool wlun_dev_clr_ua;
 
+   /* Number of r

[PATCH v1 2/8] scsi: ufs: reduce printout for aborted requests

2017-02-03 Thread Subhash Jadavani
From: Gilad Broner 

Details printed for each request that is aborted can overload the
target as there can be several requests that are aborted at once.
This change will print full request details only for the first
aborted request since the last link reset, and minimal details
for other subsequent requests.

Signed-off-by: Gilad Broner 
Signed-off-by: Subhash Jadavani 
---
 drivers/scsi/ufs/ufshcd.c | 46 --
 drivers/scsi/ufs/ufshcd.h |  3 +++
 2 files changed, 35 insertions(+), 14 deletions(-)

diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index 61fea17..64d619a 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -396,6 +396,7 @@ static void ufshcd_print_host_regs(struct ufs_hba *hba)
 void ufshcd_print_trs(struct ufs_hba *hba, unsigned long bitmap, bool pr_prdt)
 {
struct ufshcd_lrb *lrbp;
+   int prdt_length;
int tag;
 
for_each_set_bit(tag, , hba->nutrs) {
@@ -417,18 +418,17 @@ void ufshcd_print_trs(struct ufs_hba *hba, unsigned long 
bitmap, bool pr_prdt)
(u64)lrbp->ucd_rsp_dma_addr);
ufshcd_hex_dump("UPIU RSP: ", lrbp->ucd_rsp_ptr,
sizeof(struct utp_upiu_rsp));
-   if (pr_prdt) {
-   int prdt_length = le16_to_cpu(
-   lrbp->utr_descriptor_ptr->prd_table_length);
 
-   dev_err(hba->dev,
-   "UPIU[%d] - PRDT - %d entries  phys@0x%llx\n",
-   tag, prdt_length,
-   (u64)lrbp->ucd_prdt_dma_addr);
+   prdt_length = le16_to_cpu(
+   lrbp->utr_descriptor_ptr->prd_table_length);
+   dev_err(hba->dev,
+   "UPIU[%d] - PRDT - %d entries  phys@0x%llx\n",
+   tag, prdt_length,
+   (u64)lrbp->ucd_prdt_dma_addr);
+
+   if (pr_prdt)
ufshcd_hex_dump("UPIU PRDT: ", lrbp->ucd_prdt_ptr,
-   sizeof(struct ufshcd_sg_entry) *
-   prdt_length);
-   }
+   sizeof(struct ufshcd_sg_entry) * prdt_length);
}
 }
 
@@ -1848,6 +1848,8 @@ static int ufshcd_queuecommand(struct Scsi_Host *host, 
struct scsi_cmnd *cmd)
}
spin_unlock_irqrestore(hba->host->host_lock, flags);
 
+   hba->req_abort_count = 0;
+
/* acquire the tag to make sure device cmds don't use it */
if (test_and_set_bit_lock(tag, >lrb_in_use)) {
/*
@@ -4970,7 +4972,9 @@ static int ufshcd_eh_device_reset_handler(struct 
scsi_cmnd *cmd)
spin_lock_irqsave(host->host_lock, flags);
ufshcd_transfer_req_compl(hba);
spin_unlock_irqrestore(host->host_lock, flags);
+
 out:
+   hba->req_abort_count = 0;
if (!err) {
err = SUCCESS;
} else {
@@ -5054,11 +5058,23 @@ static int ufshcd_abort(struct scsi_cmnd *cmd)
 
/* Print Transfer Request of aborted task */
dev_err(hba->dev, "%s: Device abort task at tag %d\n", __func__, tag);
-   scsi_print_command(hba->lrb[tag].cmd);
-   ufshcd_print_host_regs(hba);
-   ufshcd_print_pwr_info(hba);
-   ufshcd_print_trs(hba, 1 << tag, true);
 
+   /*
+* Print detailed info about aborted request.
+* As more than one request might get aborted at the same time,
+* print full information only for the first aborted request in order
+* to reduce repeated printouts. For other aborted requests only print
+* basic details.
+*/
+   scsi_print_command(hba->lrb[tag].cmd);
+   if (!hba->req_abort_count) {
+   ufshcd_print_host_regs(hba);
+   ufshcd_print_pwr_info(hba);
+   ufshcd_print_trs(hba, 1 << tag, true);
+   } else {
+   ufshcd_print_trs(hba, 1 << tag, false);
+   }
+   hba->req_abort_count++;
 
/* Skip task abort in case previous aborts failed and report failure */
if (lrbp->req_abort_skip) {
@@ -5707,6 +5723,8 @@ static void ufshcd_clear_dbg_ufs_stats(struct ufs_hba 
*hba)
memset(>ufs_stats.nl_err, 0, err_reg_hist_size);
memset(>ufs_stats.tl_err, 0, err_reg_hist_size);
memset(>ufs_stats.dme_err, 0, err_reg_hist_size);
+
+   hba->req_abort_count = 0;
 }
 
 /**
diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h
index 292fc14..b7ce129 100644
--- a/drivers/scsi/ufs/ufshcd.h
+++ b/drivers/scsi/ufs/ufshcd.h
@@ -594,6 +594,9 @@ struct ufs_hba {
 
bool wlun_dev_clr_ua;
 
+   /* Number of requests aborts */
+   int req_abort_count;
+
/* Number of lanes available (1 or 2

[PATCH v1 1/8] scsi: ufs: skip request abort task when previous aborts failed

2017-02-03 Thread Subhash Jadavani
From: Gilad Broner <gbro...@codeaurora.org>

On certain error conditions request abort task itself might fail
when aborting a request. In such case, subsequent request aborts
should skip issuing the abort task as it is expected to fail as well,
and device reset handler will be called next.

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

diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index a70bf06..61fea17 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -1877,6 +1877,7 @@ static int ufshcd_queuecommand(struct Scsi_Host *host, 
struct scsi_cmnd *cmd)
lrbp->task_tag = tag;
lrbp->lun = ufshcd_scsi_to_upiu_lun(cmd->device->lun);
lrbp->intr_cmd = !ufshcd_is_intr_aggr_allowed(hba) ? true : false;
+   lrbp->req_abort_skip = false;
 
ufshcd_comp_scsi_upiu(hba, lrbp);
 
@@ -4979,6 +4980,17 @@ static int ufshcd_eh_device_reset_handler(struct 
scsi_cmnd *cmd)
return err;
 }
 
+static void ufshcd_set_req_abort_skip(struct ufs_hba *hba, unsigned long 
bitmap)
+{
+   struct ufshcd_lrb *lrbp;
+   int tag;
+
+   for_each_set_bit(tag, , hba->nutrs) {
+   lrbp = >lrb[tag];
+   lrbp->req_abort_skip = true;
+   }
+}
+
 /**
  * ufshcd_abort - abort a specific command
  * @cmd: SCSI command pointer
@@ -5047,6 +5059,13 @@ static int ufshcd_abort(struct scsi_cmnd *cmd)
ufshcd_print_pwr_info(hba);
ufshcd_print_trs(hba, 1 << tag, true);
 
+
+   /* Skip task abort in case previous aborts failed and report failure */
+   if (lrbp->req_abort_skip) {
+   err = -EIO;
+   goto out;
+   }
+
for (poll_cnt = 100; poll_cnt; poll_cnt--) {
err = ufshcd_issue_tm_cmd(hba, lrbp->lun, lrbp->task_tag,
UFS_QUERY_TASK, );
@@ -5120,6 +5139,7 @@ static int ufshcd_abort(struct scsi_cmnd *cmd)
err = SUCCESS;
} else {
dev_err(hba->dev, "%s: failed with err %d\n", __func__, err);
+   ufshcd_set_req_abort_skip(hba, hba->outstanding_reqs);
err = FAILED;
}
 
diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h
index 7ffcde2..292fc14 100644
--- a/drivers/scsi/ufs/ufshcd.h
+++ b/drivers/scsi/ufs/ufshcd.h
@@ -165,6 +165,7 @@ struct ufs_pm_lvl_states {
  * @lun: LUN of the command
  * @intr_cmd: Interrupt command (doesn't participate in interrupt aggregation)
  * @issue_time_stamp: time stamp for debug purposes
+ * @req_abort_skip: skip request abort task flag
  */
 struct ufshcd_lrb {
struct utp_transfer_req_desc *utr_descriptor_ptr;
@@ -187,6 +188,8 @@ struct ufshcd_lrb {
u8 lun; /* UPIU LUN id field is only 8-bit wide */
bool intr_cmd;
ktime_t issue_time_stamp;
+
+   bool req_abort_skip;
 };
 
 /**
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project



[PATCH v1 1/8] scsi: ufs: skip request abort task when previous aborts failed

2017-02-03 Thread Subhash Jadavani
From: Gilad Broner 

On certain error conditions request abort task itself might fail
when aborting a request. In such case, subsequent request aborts
should skip issuing the abort task as it is expected to fail as well,
and device reset handler will be called next.

Signed-off-by: Gilad Broner 
Signed-off-by: Subhash Jadavani 
---
 drivers/scsi/ufs/ufshcd.c | 20 
 drivers/scsi/ufs/ufshcd.h |  3 +++
 2 files changed, 23 insertions(+)

diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index a70bf06..61fea17 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -1877,6 +1877,7 @@ static int ufshcd_queuecommand(struct Scsi_Host *host, 
struct scsi_cmnd *cmd)
lrbp->task_tag = tag;
lrbp->lun = ufshcd_scsi_to_upiu_lun(cmd->device->lun);
lrbp->intr_cmd = !ufshcd_is_intr_aggr_allowed(hba) ? true : false;
+   lrbp->req_abort_skip = false;
 
ufshcd_comp_scsi_upiu(hba, lrbp);
 
@@ -4979,6 +4980,17 @@ static int ufshcd_eh_device_reset_handler(struct 
scsi_cmnd *cmd)
return err;
 }
 
+static void ufshcd_set_req_abort_skip(struct ufs_hba *hba, unsigned long 
bitmap)
+{
+   struct ufshcd_lrb *lrbp;
+   int tag;
+
+   for_each_set_bit(tag, , hba->nutrs) {
+   lrbp = >lrb[tag];
+   lrbp->req_abort_skip = true;
+   }
+}
+
 /**
  * ufshcd_abort - abort a specific command
  * @cmd: SCSI command pointer
@@ -5047,6 +5059,13 @@ static int ufshcd_abort(struct scsi_cmnd *cmd)
ufshcd_print_pwr_info(hba);
ufshcd_print_trs(hba, 1 << tag, true);
 
+
+   /* Skip task abort in case previous aborts failed and report failure */
+   if (lrbp->req_abort_skip) {
+   err = -EIO;
+   goto out;
+   }
+
for (poll_cnt = 100; poll_cnt; poll_cnt--) {
err = ufshcd_issue_tm_cmd(hba, lrbp->lun, lrbp->task_tag,
UFS_QUERY_TASK, );
@@ -5120,6 +5139,7 @@ static int ufshcd_abort(struct scsi_cmnd *cmd)
err = SUCCESS;
} else {
dev_err(hba->dev, "%s: failed with err %d\n", __func__, err);
+   ufshcd_set_req_abort_skip(hba, hba->outstanding_reqs);
err = FAILED;
}
 
diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h
index 7ffcde2..292fc14 100644
--- a/drivers/scsi/ufs/ufshcd.h
+++ b/drivers/scsi/ufs/ufshcd.h
@@ -165,6 +165,7 @@ struct ufs_pm_lvl_states {
  * @lun: LUN of the command
  * @intr_cmd: Interrupt command (doesn't participate in interrupt aggregation)
  * @issue_time_stamp: time stamp for debug purposes
+ * @req_abort_skip: skip request abort task flag
  */
 struct ufshcd_lrb {
struct utp_transfer_req_desc *utr_descriptor_ptr;
@@ -187,6 +188,8 @@ struct ufshcd_lrb {
u8 lun; /* UPIU LUN id field is only 8-bit wide */
bool intr_cmd;
ktime_t issue_time_stamp;
+
+   bool req_abort_skip;
 };
 
 /**
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project



Re: [PATCH 4/4] phy: qcom-ufs: Suppress extraneous logging

2017-01-20 Thread Subhash Jadavani

On 2017-01-19 02:47, Bjorn Andersson wrote:

The error paths of the common qcom-ufs functions for registering the
phy, acquiring clocks and acquiring regulators all print specific error
messages before returning an error, so there is no value in printing 
yet

another - more generic - message when this occur.

Cc: Subhash Jadavani <subha...@codeaurora.org>
Cc: Vivek Gautam <vivek.gau...@codeaurora.org>
Signed-off-by: Bjorn Andersson <bjorn.anders...@linaro.org>
---
 drivers/phy/phy-qcom-ufs-qmp-14nm.c | 15 +++
 drivers/phy/phy-qcom-ufs-qmp-20nm.c | 12 ++--
 2 files changed, 5 insertions(+), 22 deletions(-)

diff --git a/drivers/phy/phy-qcom-ufs-qmp-14nm.c
b/drivers/phy/phy-qcom-ufs-qmp-14nm.c
index c71c84734916..12a1b498dc4b 100644
--- a/drivers/phy/phy-qcom-ufs-qmp-14nm.c
+++ b/drivers/phy/phy-qcom-ufs-qmp-14nm.c
@@ -132,27 +132,18 @@ static int ufs_qcom_phy_qmp_14nm_probe(struct
platform_device *pdev)
_qcom_phy_qmp_14nm_phy_ops, _14nm_ops);

if (!generic_phy) {
-   dev_err(dev, "%s: ufs_qcom_phy_generic_probe() failed\n",
-   __func__);
err = -EIO;
goto out;
}

err = ufs_qcom_phy_init_clks(phy_common);
-   if (err) {
-   dev_err(phy_common->dev,
-   "%s: ufs_qcom_phy_init_clks() failed %d\n",
-   __func__, err);
+   if (err)
goto out;
-   }

err = ufs_qcom_phy_init_vregulators(phy_common);
-   if (err) {
-   dev_err(phy_common->dev,
-   "%s: ufs_qcom_phy_init_vregulators() failed %d\n",
-   __func__, err);
+   if (err)
goto out;
-   }
+
phy_common->vdda_phy.max_uV = UFS_PHY_VDDA_PHY_UV;
phy_common->vdda_phy.min_uV = UFS_PHY_VDDA_PHY_UV;

diff --git a/drivers/phy/phy-qcom-ufs-qmp-20nm.c
b/drivers/phy/phy-qcom-ufs-qmp-20nm.c
index 1a26a64e06d3..4f68acb58b73 100644
--- a/drivers/phy/phy-qcom-ufs-qmp-20nm.c
+++ b/drivers/phy/phy-qcom-ufs-qmp-20nm.c
@@ -190,25 +190,17 @@ static int ufs_qcom_phy_qmp_20nm_probe(struct
platform_device *pdev)
_qcom_phy_qmp_20nm_phy_ops, _20nm_ops);

if (!generic_phy) {
-   dev_err(dev, "%s: ufs_qcom_phy_generic_probe() failed\n",
-   __func__);
err = -EIO;
goto out;
}

err = ufs_qcom_phy_init_clks(phy_common);
-   if (err) {
-   dev_err(phy_common->dev, "%s: ufs_qcom_phy_init_clks() failed 
%d\n",
-   __func__, err);
+   if (err)
goto out;
-   }

err = ufs_qcom_phy_init_vregulators(phy_common);
-   if (err) {
-		dev_err(phy_common->dev, "%s: ufs_qcom_phy_init_vregulators() failed 
%d\n",

-   __func__, err);
+   if (err)
goto out;
-   }

    ufs_qcom_phy_qmp_20nm_advertise_quirks(phy_common);


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 4/4] phy: qcom-ufs: Suppress extraneous logging

2017-01-20 Thread Subhash Jadavani

On 2017-01-19 02:47, Bjorn Andersson wrote:

The error paths of the common qcom-ufs functions for registering the
phy, acquiring clocks and acquiring regulators all print specific error
messages before returning an error, so there is no value in printing 
yet

another - more generic - message when this occur.

Cc: Subhash Jadavani 
Cc: Vivek Gautam 
Signed-off-by: Bjorn Andersson 
---
 drivers/phy/phy-qcom-ufs-qmp-14nm.c | 15 +++
 drivers/phy/phy-qcom-ufs-qmp-20nm.c | 12 ++--
 2 files changed, 5 insertions(+), 22 deletions(-)

diff --git a/drivers/phy/phy-qcom-ufs-qmp-14nm.c
b/drivers/phy/phy-qcom-ufs-qmp-14nm.c
index c71c84734916..12a1b498dc4b 100644
--- a/drivers/phy/phy-qcom-ufs-qmp-14nm.c
+++ b/drivers/phy/phy-qcom-ufs-qmp-14nm.c
@@ -132,27 +132,18 @@ static int ufs_qcom_phy_qmp_14nm_probe(struct
platform_device *pdev)
_qcom_phy_qmp_14nm_phy_ops, _14nm_ops);

if (!generic_phy) {
-   dev_err(dev, "%s: ufs_qcom_phy_generic_probe() failed\n",
-   __func__);
err = -EIO;
goto out;
}

err = ufs_qcom_phy_init_clks(phy_common);
-   if (err) {
-   dev_err(phy_common->dev,
-   "%s: ufs_qcom_phy_init_clks() failed %d\n",
-   __func__, err);
+   if (err)
goto out;
-   }

err = ufs_qcom_phy_init_vregulators(phy_common);
-   if (err) {
-   dev_err(phy_common->dev,
-   "%s: ufs_qcom_phy_init_vregulators() failed %d\n",
-   __func__, err);
+   if (err)
goto out;
-   }
+
phy_common->vdda_phy.max_uV = UFS_PHY_VDDA_PHY_UV;
phy_common->vdda_phy.min_uV = UFS_PHY_VDDA_PHY_UV;

diff --git a/drivers/phy/phy-qcom-ufs-qmp-20nm.c
b/drivers/phy/phy-qcom-ufs-qmp-20nm.c
index 1a26a64e06d3..4f68acb58b73 100644
--- a/drivers/phy/phy-qcom-ufs-qmp-20nm.c
+++ b/drivers/phy/phy-qcom-ufs-qmp-20nm.c
@@ -190,25 +190,17 @@ static int ufs_qcom_phy_qmp_20nm_probe(struct
platform_device *pdev)
_qcom_phy_qmp_20nm_phy_ops, _20nm_ops);

if (!generic_phy) {
-   dev_err(dev, "%s: ufs_qcom_phy_generic_probe() failed\n",
-   __func__);
err = -EIO;
goto out;
}

err = ufs_qcom_phy_init_clks(phy_common);
-   if (err) {
-   dev_err(phy_common->dev, "%s: ufs_qcom_phy_init_clks() failed 
%d\n",
-   __func__, err);
+   if (err)
goto out;
-   }

err = ufs_qcom_phy_init_vregulators(phy_common);
-   if (err) {
-		dev_err(phy_common->dev, "%s: ufs_qcom_phy_init_vregulators() failed 
%d\n",

-   __func__, err);
+   if (err)
goto out;
-   }

ufs_qcom_phy_qmp_20nm_advertise_quirks(phy_common);


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


  1   2   3   4   >