linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v2 1/1] scsi: ufs: make UFS Tx lane1 clock optional for QCOM platforms
@ 2018-10-11 12:33 Can Guo
  2018-10-11 20:21 ` Doug Anderson
  0 siblings, 1 reply; 3+ messages in thread
From: Can Guo @ 2018-10-11 12:33 UTC (permalink / raw)
  To: dianders, subhashj, asutoshd, vivek.gautam, evgreen, rnayak,
	vinholikatti, jejb, martin.petersen
  Cc: linux-scsi, linux-arm-msm, Venkat Gopalakrishnan, Can Guo, open list

From: Venkat Gopalakrishnan <venkatg@codeaurora.org>

Per Qcom's UFS host controller HW design, the UFS Tx lane1 clock could be
muxed with Tx lane0 clock, hence keep Tx lane1 clock optional by ignoring
it if it is not provided in device tree. This change also performs some
cleanup to lanes per direction checks when enable/disable lane clocks just
for symmetry.

Signed-off-by: Venkat Gopalakrishnan <venkatg@codeaurora.org>
Signed-off-by: Subhash Jadavani <subhashj@codeaurora.org>
Signed-off-by: Can Guo <cang@codeaurora.org>
---

Changes since v1:
- Incorporated review comments from Doug.
- Update the commit title and commit message.

 drivers/scsi/ufs/ufs-qcom.c | 33 ++++++++++++++++++++-------------
 1 file changed, 20 insertions(+), 13 deletions(-)

diff --git a/drivers/scsi/ufs/ufs-qcom.c b/drivers/scsi/ufs/ufs-qcom.c
index 2b38db2..a7ec959 100644
--- a/drivers/scsi/ufs/ufs-qcom.c
+++ b/drivers/scsi/ufs/ufs-qcom.c
@@ -79,13 +79,19 @@ static int ufs_qcom_get_connected_tx_lanes(struct ufs_hba *hba, u32 *tx_lanes)
 }
 
 static int ufs_qcom_host_clk_get(struct device *dev,
-		const char *name, struct clk **clk_out)
+		const char *name, struct clk **clk_out, bool optional)
 {
 	struct clk *clk;
 	int err = 0;
 
 	clk = devm_clk_get(dev, name);
-	if (IS_ERR(clk)) {
+	if (clk == ERR_PTR(-EPROBE_DEFER)) {
+		err = -EPROBE_DEFER;
+		dev_warn(dev, "required clock %s hasn't probed yet, err %d\n",
+				name, err);
+	} else if (IS_ERR(clk)) {
+		if (optional)
+			return 0;
 		err = PTR_ERR(clk);
 		dev_err(dev, "%s: failed to get %s err %d",
 				__func__, name, err);
@@ -113,10 +119,10 @@ static void ufs_qcom_disable_lane_clks(struct ufs_qcom_host *host)
 	if (!host->is_lane_clks_enabled)
 		return;
 
-	if (host->hba->lanes_per_direction > 1)
+	if (host->tx_l1_sync_clk)
 		clk_disable_unprepare(host->tx_l1_sync_clk);
 	clk_disable_unprepare(host->tx_l0_sync_clk);
-	if (host->hba->lanes_per_direction > 1)
+	if (host->rx_l1_sync_clk)
 		clk_disable_unprepare(host->rx_l1_sync_clk);
 	clk_disable_unprepare(host->rx_l0_sync_clk);
 
@@ -141,12 +147,14 @@ static int ufs_qcom_enable_lane_clks(struct ufs_qcom_host *host)
 	if (err)
 		goto disable_rx_l0;
 
-	if (host->hba->lanes_per_direction > 1) {
+	if (host->rx_l1_sync_clk) {
 		err = ufs_qcom_host_clk_enable(dev, "rx_lane1_sync_clk",
 			host->rx_l1_sync_clk);
 		if (err)
 			goto disable_tx_l0;
+	}
 
+	if (host->tx_l1_sync_clk) {
 		err = ufs_qcom_host_clk_enable(dev, "tx_lane1_sync_clk",
 			host->tx_l1_sync_clk);
 		if (err)
@@ -157,8 +165,7 @@ static int ufs_qcom_enable_lane_clks(struct ufs_qcom_host *host)
 	goto out;
 
 disable_rx_l1:
-	if (host->hba->lanes_per_direction > 1)
-		clk_disable_unprepare(host->rx_l1_sync_clk);
+	clk_disable_unprepare(host->rx_l1_sync_clk);
 disable_tx_l0:
 	clk_disable_unprepare(host->tx_l0_sync_clk);
 disable_rx_l0:
@@ -172,25 +179,25 @@ static int ufs_qcom_init_lane_clks(struct ufs_qcom_host *host)
 	int err = 0;
 	struct device *dev = host->hba->dev;
 
-	err = ufs_qcom_host_clk_get(dev,
-			"rx_lane0_sync_clk", &host->rx_l0_sync_clk);
+	err = ufs_qcom_host_clk_get(dev, "rx_lane0_sync_clk",
+					&host->rx_l0_sync_clk, false);
 	if (err)
 		goto out;
 
-	err = ufs_qcom_host_clk_get(dev,
-			"tx_lane0_sync_clk", &host->tx_l0_sync_clk);
+	err = ufs_qcom_host_clk_get(dev, "tx_lane0_sync_clk",
+					&host->tx_l0_sync_clk, false);
 	if (err)
 		goto out;
 
 	/* In case of single lane per direction, don't read lane1 clocks */
 	if (host->hba->lanes_per_direction > 1) {
 		err = ufs_qcom_host_clk_get(dev, "rx_lane1_sync_clk",
-			&host->rx_l1_sync_clk);
+			&host->rx_l1_sync_clk, false);
 		if (err)
 			goto out;
 
 		err = ufs_qcom_host_clk_get(dev, "tx_lane1_sync_clk",
-			&host->tx_l1_sync_clk);
+			&host->tx_l1_sync_clk, true);
 	}
 out:
 	return err;
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project


^ permalink raw reply related	[flat|nested] 3+ messages in thread

* Re: [PATCH v2 1/1] scsi: ufs: make UFS Tx lane1 clock optional for QCOM platforms
  2018-10-11 12:33 [PATCH v2 1/1] scsi: ufs: make UFS Tx lane1 clock optional for QCOM platforms Can Guo
@ 2018-10-11 20:21 ` Doug Anderson
  2018-10-12  0:55   ` cang
  0 siblings, 1 reply; 3+ messages in thread
From: Doug Anderson @ 2018-10-11 20:21 UTC (permalink / raw)
  To: cang
  Cc: subhashj, Asutosh Das, Vivek Gautam, Evan Green, Rajendra Nayak,
	Vinayak Holikatti, jejb, Martin K. Petersen, linux-scsi,
	linux-arm-msm, venkatg, LKML

Hi,

On Thu, Oct 11, 2018 at 5:33 AM Can Guo <cang@codeaurora.org> wrote:
>  static int ufs_qcom_host_clk_get(struct device *dev,
> -               const char *name, struct clk **clk_out)
> +               const char *name, struct clk **clk_out, bool optional)
>  {
>         struct clk *clk;
>         int err = 0;
>
>         clk = devm_clk_get(dev, name);
> -       if (IS_ERR(clk)) {
> +       if (clk == ERR_PTR(-EPROBE_DEFER)) {
> +               err = -EPROBE_DEFER;
> +               dev_warn(dev, "required clock %s hasn't probed yet, err %d\n",
> +                               name, err);
> +       } else if (IS_ERR(clk)) {
> +               if (optional)
> +                       return 0;

Change this function to:

static int ufs_qcom_host_clk_get(struct device *dev,
    const char *name, struct clk **clk_out, bool optional)
{
  struct clk *clk;
  int err;

  clk = devm_clk_get(dev, name);
  if (!IS_ERR(clk)) {
    *clk_out = clk;
    return 0;
  }

  err = PTR_ERR(clk);

  if (optional && err == -ENOENT) {
    *clk_out = NULL;
    return 0;
  }

  if (err != -EPROBE_DEFER)
    dev_err(dev, "failed to get %s err %d",
        name, err);

  return err;
}

Specifically:

* Typically it just spams the log to print something when you see an
-EPROBE_DEFER.

* If a clock is optional you should only consider things a success
only if "-ENOENT" was returned.  All other errors should be considered
fatal.

* If a clock is optional it's slightly cleaner to set *clk_out to
NULL.  I know you're initting global data that happened to already be
NULL by default, but it still feels nice for the abstraction of the
function to do this.

* Please don't pass __func__ to your error messages.


>                 err = PTR_ERR(clk);
>                 dev_err(dev, "%s: failed to get %s err %d",
>                                 __func__, name, err);
> @@ -113,10 +119,10 @@ static void ufs_qcom_disable_lane_clks(struct ufs_qcom_host *host)
>         if (!host->is_lane_clks_enabled)
>                 return;
>
> -       if (host->hba->lanes_per_direction > 1)
> +       if (host->tx_l1_sync_clk)

Remove this "if".  Always call clk_disable_unprepare() which will be a
no-op if "host->tx_l1_sync_clk" is NULL.  clk_disable_unprepare() is a
no-op for NULL clocks by design specifically to make code like this
cleaner.


>                 clk_disable_unprepare(host->tx_l1_sync_clk);
>         clk_disable_unprepare(host->tx_l0_sync_clk);
> -       if (host->hba->lanes_per_direction > 1)
> +       if (host->rx_l1_sync_clk)

Remove this "if".  Always call clk_disable_unprepare() which will be a
no-op if "host->rx_l1_sync_clk" is NULL.  clk_disable_unprepare() is a
no-op for NULL clocks by design specifically to make code like this
cleaner.


>                 clk_disable_unprepare(host->rx_l1_sync_clk);
>         clk_disable_unprepare(host->rx_l0_sync_clk);
>
> @@ -141,12 +147,14 @@ static int ufs_qcom_enable_lane_clks(struct ufs_qcom_host *host)
>         if (err)
>                 goto disable_rx_l0;
>
> -       if (host->hba->lanes_per_direction > 1) {
> +       if (host->rx_l1_sync_clk) {

Remove this "if".  Always call ufs_qcom_host_clk_enable().  The
clk_prepare_enable() inside ufs_qcom_host_clk_enable() will be a no-op
if "host->rx_l1_sync_clk" is NULL and will return 0 (no error).


>                 err = ufs_qcom_host_clk_enable(dev, "rx_lane1_sync_clk",
>                         host->rx_l1_sync_clk);
>                 if (err)
>                         goto disable_tx_l0;
> +       }
>
> +       if (host->tx_l1_sync_clk) {

Remove this "if".  Always call ufs_qcom_host_clk_enable().  The
clk_prepare_enable() inside ufs_qcom_host_clk_enable() will be a no-op
if "host->tx_l1_sync_clk" is NULL and will return 0 (no error).


-Doug

^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: [PATCH v2 1/1] scsi: ufs: make UFS Tx lane1 clock optional for QCOM platforms
  2018-10-11 20:21 ` Doug Anderson
@ 2018-10-12  0:55   ` cang
  0 siblings, 0 replies; 3+ messages in thread
From: cang @ 2018-10-12  0:55 UTC (permalink / raw)
  To: Doug Anderson
  Cc: subhashj, Asutosh Das, Vivek Gautam, Evan Green, Rajendra Nayak,
	Vinayak Holikatti, jejb, Martin K. Petersen, linux-scsi,
	linux-arm-msm, venkatg, LKML

Hi Doug,

On 2018-10-12 04:21, Doug Anderson wrote:
> Hi,
> 
> On Thu, Oct 11, 2018 at 5:33 AM Can Guo <cang@codeaurora.org> wrote:
>>  static int ufs_qcom_host_clk_get(struct device *dev,
>> -               const char *name, struct clk **clk_out)
>> +               const char *name, struct clk **clk_out, bool optional)
>>  {
>>         struct clk *clk;
>>         int err = 0;
>> 
>>         clk = devm_clk_get(dev, name);
>> -       if (IS_ERR(clk)) {
>> +       if (clk == ERR_PTR(-EPROBE_DEFER)) {
>> +               err = -EPROBE_DEFER;
>> +               dev_warn(dev, "required clock %s hasn't probed yet, 
>> err %d\n",
>> +                               name, err);
>> +       } else if (IS_ERR(clk)) {
>> +               if (optional)
>> +                       return 0;
> 
> Change this function to:
> 
> static int ufs_qcom_host_clk_get(struct device *dev,
>     const char *name, struct clk **clk_out, bool optional)
> {
>   struct clk *clk;
>   int err;
> 
>   clk = devm_clk_get(dev, name);
>   if (!IS_ERR(clk)) {
>     *clk_out = clk;
>     return 0;
>   }
> 
>   err = PTR_ERR(clk);
> 
>   if (optional && err == -ENOENT) {
>     *clk_out = NULL;
>     return 0;
>   }
> 
>   if (err != -EPROBE_DEFER)
>     dev_err(dev, "failed to get %s err %d",
>         name, err);
> 
>   return err;
> }
> 
> Specifically:
> 
> * Typically it just spams the log to print something when you see an
> -EPROBE_DEFER.
> 
> * If a clock is optional you should only consider things a success
> only if "-ENOENT" was returned.  All other errors should be considered
> fatal.
> 
> * If a clock is optional it's slightly cleaner to set *clk_out to
> NULL.  I know you're initting global data that happened to already be
> NULL by default, but it still feels nice for the abstraction of the
> function to do this.
> 
> * Please don't pass __func__ to your error messages.
> 
> 

Thank you for the detailed instructions. Shall make the change like so.

>>                 err = PTR_ERR(clk);
>>                 dev_err(dev, "%s: failed to get %s err %d",
>>                                 __func__, name, err);
>> @@ -113,10 +119,10 @@ static void ufs_qcom_disable_lane_clks(struct 
>> ufs_qcom_host *host)
>>         if (!host->is_lane_clks_enabled)
>>                 return;
>> 
>> -       if (host->hba->lanes_per_direction > 1)
>> +       if (host->tx_l1_sync_clk)
> 
> Remove this "if".  Always call clk_disable_unprepare() which will be a
> no-op if "host->tx_l1_sync_clk" is NULL.  clk_disable_unprepare() is a
> no-op for NULL clocks by design specifically to make code like this
> cleaner.
> 
> 

Shall do.

>>                 clk_disable_unprepare(host->tx_l1_sync_clk);
>>         clk_disable_unprepare(host->tx_l0_sync_clk);
>> -       if (host->hba->lanes_per_direction > 1)
>> +       if (host->rx_l1_sync_clk)
> 
> Remove this "if".  Always call clk_disable_unprepare() which will be a
> no-op if "host->rx_l1_sync_clk" is NULL.  clk_disable_unprepare() is a
> no-op for NULL clocks by design specifically to make code like this
> cleaner.
> 
> 

Shall do.

>>                 clk_disable_unprepare(host->rx_l1_sync_clk);
>>         clk_disable_unprepare(host->rx_l0_sync_clk);
>> 
>> @@ -141,12 +147,14 @@ static int ufs_qcom_enable_lane_clks(struct 
>> ufs_qcom_host *host)
>>         if (err)
>>                 goto disable_rx_l0;
>> 
>> -       if (host->hba->lanes_per_direction > 1) {
>> +       if (host->rx_l1_sync_clk) {
> 
> Remove this "if".  Always call ufs_qcom_host_clk_enable().  The
> clk_prepare_enable() inside ufs_qcom_host_clk_enable() will be a no-op
> if "host->rx_l1_sync_clk" is NULL and will return 0 (no error).
> 
> 

Shall do so.

>>                 err = ufs_qcom_host_clk_enable(dev, 
>> "rx_lane1_sync_clk",
>>                         host->rx_l1_sync_clk);
>>                 if (err)
>>                         goto disable_tx_l0;
>> +       }
>> 
>> +       if (host->tx_l1_sync_clk) {
> 
> Remove this "if".  Always call ufs_qcom_host_clk_enable().  The
> clk_prepare_enable() inside ufs_qcom_host_clk_enable() will be a no-op
> if "host->tx_l1_sync_clk" is NULL and will return 0 (no error).
> 
> 
> -Doug

Shall do so. Thank you.

-Can Guo

^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2018-10-12  0:55 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-10-11 12:33 [PATCH v2 1/1] scsi: ufs: make UFS Tx lane1 clock optional for QCOM platforms Can Guo
2018-10-11 20:21 ` Doug Anderson
2018-10-12  0:55   ` cang

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).