RE: [PATCH v5 03/15] scsi: ufs: implement scsi host timeout handler

2016-03-08 Thread Dolev Raviv
t;> only the race condition is still there, and can pop-out at any other 
>>> point in the future, but also, not sure what are the consequences of 
>>> ufshcd_hold(hba, false) unstead of "true".
>> Well ... seeing it's your driver, I would've thought _you_ should 
>> know ...
>>
>>> so, changing the already tested and working code, (not to return 
>>> BUSY from
>>> queuecommand) is not a fix.
>> Hey, I did _not_ suggest not to retury BUSY from queuecommand.
>>
>> I was suggesting this patch:
>>
>> diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c 
>> index 9c1b94b..b9295ad 100644
>> --- a/drivers/scsi/ufs/ufshcd.c
>> +++ b/drivers/scsi/ufs/ufshcd.c
>> @@ -1388,7 +1388,7 @@ static int ufshcd_queuecommand(struct Scsi_Host 
>> *host, struct scsi_cmnd *cmd)
>> goto out;
>> }
>>
>> -   err = ufshcd_hold(hba, true);
>> +   err = ufshcd_hold(hba, false);
>>     if (err) {
>> err = SCSI_MLQUEUE_HOST_BUSY;
>> clear_bit_unlock(tag, >lrb_in_use);
>>
>> which, by reading the code, should be avoiding this issue.
>
>
> Hannes,
> we are not trying to avoid returning BUSY from queuecommand().
> On the contrary. By returning BUSY we actually re-queuing the request 
> which is exactly what we need to do.
> your patch doesn't fix the race condition.
>
> thanks,
> Yaniv
>
>> I was just asking you if you could give this patch a spin and see if 
>> it works. If not (for whatever reason) I'm happy to accept your patch.
>> But first I would like to have an explanation why the above would 
>> _not_ work.
>>
>> Unfortunately I don't have the hardware otherwise I'd be running the 
>> tests myself.
>>
>> Cheers,
>>
>> Hannes
>> --
>> Dr. Hannes ReineckezSeries & Storage
>> h...@suse.de   +49 911 74053 688
>> SUSE LINUX Products GmbH, Maxfeldstr. 5, 90409 Nürnberg
>> GF: J. Hawn, J. Guild, F. Imendörffer, HRB 16746 (AG Nürnberg)
>> --
>> To unsubscribe from this list: send the line "unsubscribe linux-scsi" 
>> in the body of a message to majord...@vger.kernel.org More majordomo 
>> info at  http://vger.kernel.org/majordomo-info.html
>>
>
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-scsi" 
> in the body of a message to majord...@vger.kernel.org More majordomo 
> info at  http://vger.kernel.org/majordomo-info.html
>

I reviewed the patch, you can add 

Reviewed-by: Dolev Raviv <dra...@codeaurora.org>

Thanks,
Dolev
-- 
Qualcomm Israel, on behalf of Qualcomm Innovation Center, Inc.
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, a Linux
Foundation Collaborative Project

--
To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


RE: [PATCH v5 00/15] Big fixes, retries, handle a race condition

2015-10-28 Thread Dolev Raviv
Reviewed-by: Dolev Raviv <dra...@codeaurora.org>

Thanks,
Dolev
-- 
Qualcomm Israel, on behalf of Qualcomm Innovation Center, Inc.
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, a Linux
Foundation Collaborative Project

-Original Message-
From: Yaniv Gardi [mailto:yga...@codeaurora.org] 
Sent: Tuesday, October 27, 2015 12:44 PM
To: robherri...@gmail.com; james.bottom...@hansenpartnership.com;
pebo...@tiscali.nl; h...@infradead.org
Cc: linux-ker...@vger.kernel.org; linux-scsi@vger.kernel.org;
linux-arm-...@vger.kernel.org; santos...@gmail.com;
linux-scsi-ow...@vger.kernel.org; subha...@codeaurora.org;
yga...@codeaurora.org; gbro...@codeaurora.org; dra...@codeaurora.org
Subject: [PATCH v5 00/15] Big fixes, retries, handle a race condition

Important:
This serie of 15 small patches should be pushed after the series of 8
patches "Fix error message and present UFS variant probe"

V5:
removed un-necessary wmb()

V4:
fixing a few comments from reviewers

V3:
removed specific calls to wmb() since they are redundant.

V2:
a few minor changes

V1:
This serie of 15 small patches should be pushed after the series of 8
patches I have uploaded to the upstream a week ago:
"Fix error message and present UFS variant probe"

Yaniv Gardi (15):
  scsi: ufs: clear UTRD, UPIU req and rsp before new transfers
  scsi: ufs: clear fields UTRD, UPIU req and rsp before new transfers
  scsi: ufs: verify command tag validity
  scsi: ufs: clear outstanding_request bit in case query timeout
  scsi: ufs: increase fDeviceInit query response timeout
  scsi: ufs: avoid exception event handler racing with PM callbacks
  scsi: ufs: set REQUEST_SENSE command size to 18 bytes
  scsi: ufs: add retries to dme_peer get and set attribute
  scsi: ufs: add retries for hibern8 enter
  scsi: ufs: fix error recovery after the hibern8 exit failure
  scsi: ufs: retry failed query flag requests
  scsi: ufs: reduce the interrupts for power mode change requests
  scsi: ufs: add missing memory barriers
  scsi: ufs: commit descriptors before setting the doorbell
  scsi: ufs: add wrapper for retrying sending query attribute

 drivers/scsi/ufs/ufshcd.c | 408
--
 drivers/scsi/ufs/ufshcd.h |   4 +
 2 files changed, 327 insertions(+), 85 deletions(-)

--
1.8.5.2

--
QUALCOMM ISRAEL, on behalf of Qualcomm Innovation Center, Inc. is a member
of Code Aurora Forum, hosted by The Linux Foundation

--
To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [PATCH 0/6] various fixes for UFS-PM series

2014-11-20 Thread Dolev Raviv

 On Sun, Oct 26, 2014 at 11:04:06AM -, Dolev Raviv wrote:
  Btw, MAINTAINERS doesn't mention you for the ufs driver, should it?

 No it shouldn't.

 It seems like I'm getting a lot of the series from you and your signoff,
 why shouldn't you be listed in MAINTAINERS?  From the list activity it
 seems like you and Sujit are the defator maintainers.


Thank you,
Sorry this mail was forgotten in the archives.
I'll have to pass, as I will not be able to be fully committed.

 Santosh just send a patch to remove himself, and I only see very little
 activity from Vinayak, with his last ACK in early July and a few
 more earlier in the year.




-- 
Thanks,
Dolev

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


--
To unsubscribe from this list: send the line unsubscribe linux-scsi in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [PATCH 0/6] various fixes for UFS-PM series

2014-10-26 Thread Dolev Raviv

 On Fri, Oct 24, 2014 at 07:53:23AM -, Dolev Raviv wrote:
 The first patch is Akinobu Mita's patch.
 You can add my ack on it.

Sorry I meant 'reviewed-by'.


 Given that you passed them on to me you should normally sign off on them
 as well.

My mistake.


 Btw, MAINTAINERS doesn't mention you for the ufs driver, should it?

No it shouldn't.

Thanks,
Dolev

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


--
To unsubscribe from this list: send the line unsubscribe linux-scsi in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [PATCH 0/6] various fixes for UFS-PM series

2014-10-24 Thread Dolev Raviv

 On Thu, Oct 23, 2014 at 01:25:11PM +0300, Dolev Raviv wrote:
 Contains a couple of bug fixes reported by Akinobu Mita, In adition to
 static checker warnings reported by Dan Carpenter.

 Any reason you didn't add a signoff to the first patch?

The first patch is Akinobu Mita's patch.
You can add my ack on it.


 I'll happily apply these after I get a second review for them,
 preferably from the ufs community.



-- 
QUALCOMM ISRAEL, on behalf of Qualcomm Innovation Center, Inc. is a member
of Code Aurora Forum, hosted by The Linux Foundation


--
To unsubscribe from this list: send the line unsubscribe linux-scsi in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


RE: ufs: add UFS power management support

2014-10-23 Thread Dolev Raviv
Hi Dan,
This seem like a false alarm, please let me know if it requires a fix.

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

-Original Message-
From: Dan Carpenter [mailto:dan.carpen...@oracle.com] 
Sent: Thursday, October 02, 2014 6:31 PM
To: subha...@codeaurora.org
Cc: linux-scsi@vger.kernel.org
Subject: re: ufs: add UFS power management support

Hello Subhash Jadavani,

The patch 57d104c153d3: ufs: add UFS power management support from Sep 25,
2014, leads to the following static checker warning:

drivers/scsi/ufs/ufshcd.c:4746 ufshcd_link_state_transition()
warn: we tested 'check_for_bkops' before and it was 'true'

drivers/scsi/ufs/ufshcd.c
  4734  if (req_link_state == UIC_LINK_HIBERN8_STATE) {
  4735  ret = ufshcd_uic_hibern8_enter(hba);
  4736  if (!ret)
  4737  ufshcd_set_link_hibern8(hba);
  4738  else
  4739  goto out;
  4740  }
  4741  /*
  4742   * If autobkops is enabled, link can't be turned off because
  4743   * turning off the link would also turn off the device.
  4744   */
  4745  else if ((req_link_state == UIC_LINK_OFF_STATE) 
  4746 (!check_for_bkops || (check_for_bkops 
 ^^^ Not needed.

  4747  !hba-auto_bkops_enabled))) {
  4748  /*
  4749   * Change controller state to reset state which
  4750   * should also put the link in off/reset state
  4751   */
  4752  ufshcd_hba_stop(hba);
  4753  /*
  4754   * TODO: Check if we need any delay to make sure
that
  4755   * controller is reset
  4756   */
  4757  ufshcd_set_link_off(hba);
  4758  }
  4759
  4760  out:
  4761  return ret;
  4762  }

regards,
dan carpenter

--
To unsubscribe from this list: send the line unsubscribe linux-scsi in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH 5/6] scsi: ufs: fix static checker warning in __ufshcd_setup_clocks

2014-10-23 Thread Dolev Raviv
This patch fixes newly introduced static checker warning in
__ufshcd_setup_clocks, introduced by UFS power management series.

Warning:
drivers/scsi/ufs/ufshcd.c:4474 __ufshcd_setup_clocks()
warn: we tested 'ret' before and it was 'false'

To fix it we remove the (!ret) from the condition.

Signed-off-by: Dolev Raviv dra...@codeaurora.org

diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index d3f6ddb..b9da446 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -4473,7 +4473,7 @@ out:
if (!IS_ERR_OR_NULL(clki-clk)  clki-enabled)
clk_disable_unprepare(clki-clk);
}
-   } else if (!ret  on) {
+   } else if (on) {
spin_lock_irqsave(hba-host-host_lock, flags);
hba-clk_gating.state = CLKS_ON;
spin_unlock_irqrestore(hba-host-host_lock, flags);
-- 
1.8.5.2
-- 
Qualcomm Israel, on behalf of Qualcomm Innovation Center, Inc.
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, a Linux 
Foundation Collaborative Project

--
To unsubscribe from this list: send the line unsubscribe linux-scsi in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH 2/6] scsi: ufs: fix power info after link start-up

2014-10-23 Thread Dolev Raviv
From: Yaniv Gardi yga...@codeaurora.org

After link start-up power mode will always be PWM G1. This is not
reflected in the pwr_info struct which will keep the previous values.
Since ufshcd_change_power_mode() tries to avoid unnecessary power mode
change if the requested power mode and current power mode are same,
power mode change won't execute again after driver initialization.

This patch solves the problem by setting pwr_info to PWM G1 after link
start-up.

Signed-off-by: Yaniv Gardi yga...@codeaurora.org
Signed-off-by: Dolev Raviv dra...@codeaurora.org

diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index 59b6544..77a4e38 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -2246,6 +2246,22 @@ static int ufshcd_uic_hibern8_exit(struct ufs_hba *hba)
return ret;
 }
 
+ /**
+ * ufshcd_init_pwr_info - setting the POR (power on reset)
+ * values in hba power info
+ * @hba: per-adapter instance
+ */
+static void ufshcd_init_pwr_info(struct ufs_hba *hba)
+{
+   hba-pwr_info.gear_rx = UFS_PWM_G1;
+   hba-pwr_info.gear_tx = UFS_PWM_G1;
+   hba-pwr_info.lane_rx = 1;
+   hba-pwr_info.lane_tx = 1;
+   hba-pwr_info.pwr_rx = SLOWAUTO_MODE;
+   hba-pwr_info.pwr_tx = SLOWAUTO_MODE;
+   hba-pwr_info.hs_rate = 0;
+}
+
 /**
  * ufshcd_get_max_pwr_mode - reads the max power mode negotiated with device
  * @hba: per-adapter instance
@@ -4118,6 +4134,8 @@ static int ufshcd_probe_hba(struct ufs_hba *hba)
if (ret)
goto out;
 
+   ufshcd_init_pwr_info(hba);
+
/* UniPro link is active now */
ufshcd_set_link_active(hba);
 
-- 
1.8.5.2
-- 
Qualcomm Israel, on behalf of Qualcomm Innovation Center, Inc.
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, a Linux 
Foundation Collaborative Project

--
To unsubscribe from this list: send the line unsubscribe linux-scsi in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH 4/6] scsi: ufs: fix static checker warning in ufshcd_populate_vreg

2014-10-23 Thread Dolev Raviv
This patch fixes newly introduced static checker warning in
ufshcd_populate_vreg, introduced by UFS power management series.

Warning:
drivers/scsi/ufs/ufshcd-pltfrm.c:167 ufshcd_populate_vreg()
warn: missing error code here? 'devm_kzalloc()' failed. 'ret' = '0'

To fix it we return -ENOMEM and skip the message print.

Signed-off-by: Dolev Raviv dra...@codeaurora.org

diff --git a/drivers/scsi/ufs/ufshcd-pltfrm.c b/drivers/scsi/ufs/ufshcd-pltfrm.c
index 8adf067..2cdec78 100644
--- a/drivers/scsi/ufs/ufshcd-pltfrm.c
+++ b/drivers/scsi/ufs/ufshcd-pltfrm.c
@@ -162,10 +162,8 @@ static int ufshcd_populate_vreg(struct device *dev, const 
char *name,
}
 
vreg = devm_kzalloc(dev, sizeof(*vreg), GFP_KERNEL);
-   if (!vreg) {
-   dev_err(dev, No memory for %s regulator\n, name);
-   goto out;
-   }
+   if (!vreg)
+   return -ENOMEM;
 
vreg-name = kstrdup(name, GFP_KERNEL);
 
-- 
1.8.5.2
-- 
Qualcomm Israel, on behalf of Qualcomm Innovation Center, Inc.
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, a Linux 
Foundation Collaborative Project

--
To unsubscribe from this list: send the line unsubscribe linux-scsi in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH 0/6] various fixes for UFS-PM series

2014-10-23 Thread Dolev Raviv
Contains a couple of bug fixes reported by Akinobu Mita, In adition to
static checker warnings reported by Dan Carpenter.

Akinobu Mita (1):
  scsi: ufs: fix reference counting of W-LUs

Dolev Raviv (4):
  scsi: ufs: fix static checker errors in ufshcd_system_suspend
  scsi: ufs: fix static checker warning in ufshcd_populate_vreg
  scsi: ufs: fix static checker warning in __ufshcd_setup_clocks
  scsi: ufs: fix static checker warning in ufshcd_parse_clock_info

Yaniv Gardi (1):
  scsi: ufs: fix power info after link start-up

 drivers/scsi/ufs/ufshcd-pltfrm.c | 15 +++
 drivers/scsi/ufs/ufshcd.c| 96 +++-
 drivers/scsi/ufs/ufshcd.h|  2 -
 3 files changed, 61 insertions(+), 52 deletions(-)

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

--
To unsubscribe from this list: send the line unsubscribe linux-scsi in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH 6/6] scsi: ufs: fix static checker warning in ufshcd_parse_clock_info

2014-10-23 Thread Dolev Raviv
This patch fixes newly introduced static checker warning in
ufshcd_parse_clock_info, introduced by UFS power management series.

Warning:
drivers/scsi/ufs/ufshcd-pltfrm.c:138 ufshcd_parse_clock_info()
warn: passing devm_ allocated variable to kfree. 'clkfreq'

To fix it we remove the kfree(clkfreq) statement.
In addition we removed the redundant goto label.

Signed-off-by: Dolev Raviv dra...@codeaurora.org

diff --git a/drivers/scsi/ufs/ufshcd-pltfrm.c b/drivers/scsi/ufs/ufshcd-pltfrm.c
index 2cdec78..1c3467b 100644
--- a/drivers/scsi/ufs/ufshcd-pltfrm.c
+++ b/drivers/scsi/ufs/ufshcd-pltfrm.c
@@ -102,7 +102,6 @@ static int ufshcd_parse_clock_info(struct ufs_hba *hba)
clkfreq = devm_kzalloc(dev, sz * sizeof(*clkfreq),
GFP_KERNEL);
if (!clkfreq) {
-   dev_err(dev, %s: no memory\n, freq-table-hz);
ret = -ENOMEM;
goto out;
}
@@ -112,19 +111,19 @@ static int ufshcd_parse_clock_info(struct ufs_hba *hba)
if (ret  (ret != -EINVAL)) {
dev_err(dev, %s: error reading array %d\n,
freq-table-hz, ret);
-   goto free_clkfreq;
+   return ret;
}
 
for (i = 0; i  sz; i += 2) {
ret = of_property_read_string_index(np,
clock-names, i/2, (const char **)name);
if (ret)
-   goto free_clkfreq;
+   goto out;
 
clki = devm_kzalloc(dev, sizeof(*clki), GFP_KERNEL);
if (!clki) {
ret = -ENOMEM;
-   goto free_clkfreq;
+   goto out;
}
 
clki-min_freq = clkfreq[i];
@@ -134,8 +133,6 @@ static int ufshcd_parse_clock_info(struct ufs_hba *hba)
clki-min_freq, clki-max_freq, clki-name);
list_add_tail(clki-list, hba-clk_list_head);
}
-free_clkfreq:
-   kfree(clkfreq);
 out:
return ret;
 }
-- 
1.8.5.2
-- 
Qualcomm Israel, on behalf of Qualcomm Innovation Center, Inc.
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, a Linux 
Foundation Collaborative Project

--
To unsubscribe from this list: send the line unsubscribe linux-scsi in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH 3/6] scsi: ufs: fix static checker errors in ufshcd_system_suspend

2014-10-23 Thread Dolev Raviv
This patch fixes newly introduced sparse warning in
ufshcd_system_suspend, introduced by UFS power management series.

Sparse warning:
drivers/scsi/ufs/ufshcd.c:5118 ufshcd_system_suspend()
error: we previously assumed 'hba' could be null (see line 5089)

To fix it, we return 0 in case HBA is not initialized or is
not powered.

Signed-off-by: Dolev Raviv dra...@codeaurora.org

diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index 77a4e38..d3f6ddb 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -5104,7 +5104,7 @@ int ufshcd_system_suspend(struct ufs_hba *hba)
int ret = 0;
 
if (!hba || !hba-is_powered)
-   goto out;
+   return 0;
 
if (pm_runtime_suspended(hba-dev)) {
if (hba-rpm_lvl == hba-spm_lvl)
-- 
1.8.5.2
-- 
Qualcomm Israel, on behalf of Qualcomm Innovation Center, Inc.
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, a Linux 
Foundation Collaborative Project

--
To unsubscribe from this list: send the line unsubscribe linux-scsi in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH 1/6] scsi: ufs: fix reference counting of W-LUs

2014-10-23 Thread Dolev Raviv
From: Akinobu Mita akinobu.m...@gmail.com

UFS driver adds three well known LUs in the initialization, but those
reference counts are not decremented, so it makes ufshcd module
impossible to unload.

This fixes it by putting scsi_device_put() in the initalization, and in
order to protect concurrent access to hba-sdev_ufs_device (UFS Device
W-LU) from manual delete, increment the reference count while requesting
device power mode setting.

The rest of W-LUs (hba-sdev_boot and hba-sdev_rpmb) are not directly
used from driver, so these references in struct ufs_hba are removed.

Signed-off-by: Akinobu Mita m...@fixstars.com
Cc: Vinayak Holikatti vinholika...@gmail.com
Cc: Santosh Y santos...@gmail.com
Cc: Dolev Raviv dra...@codeaurora.org
Cc: Subhash Jadavani subha...@codeaurora.org
Cc: Yaniv Gardi yga...@codeaurora.org
Cc: Christoph Hellwig h...@lst.de
Cc: James E.J. Bottomley jbottom...@parallels.com
Cc: linux-scsi@vger.kernel.org

diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index 497c38a..59b6544 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -2844,8 +2844,13 @@ static void ufshcd_slave_destroy(struct scsi_device 
*sdev)
hba = shost_priv(sdev-host);
scsi_deactivate_tcq(sdev, hba-nutrs);
/* Drop the reference as it won't be needed anymore */
-   if (ufshcd_scsi_to_upiu_lun(sdev-lun) == UFS_UPIU_UFS_DEVICE_WLUN)
+   if (ufshcd_scsi_to_upiu_lun(sdev-lun) == UFS_UPIU_UFS_DEVICE_WLUN) {
+   unsigned long flags;
+
+   spin_lock_irqsave(hba-host-host_lock, flags);
hba-sdev_ufs_device = NULL;
+   spin_unlock_irqrestore(hba-host-host_lock, flags);
+   }
 }
 
 /**
@@ -4062,6 +4067,8 @@ static void ufshcd_init_icc_levels(struct ufs_hba *hba)
 static int ufshcd_scsi_add_wlus(struct ufs_hba *hba)
 {
int ret = 0;
+   struct scsi_device *sdev_rpmb;
+   struct scsi_device *sdev_boot;
 
hba-sdev_ufs_device = __scsi_add_device(hba-host, 0, 0,
ufshcd_upiu_wlun_to_scsi_wlun(UFS_UPIU_UFS_DEVICE_WLUN), NULL);
@@ -4070,26 +4077,27 @@ static int ufshcd_scsi_add_wlus(struct ufs_hba *hba)
hba-sdev_ufs_device = NULL;
goto out;
}
+   scsi_device_put(hba-sdev_ufs_device);
 
-   hba-sdev_boot = __scsi_add_device(hba-host, 0, 0,
+   sdev_boot = __scsi_add_device(hba-host, 0, 0,
ufshcd_upiu_wlun_to_scsi_wlun(UFS_UPIU_BOOT_WLUN), NULL);
-   if (IS_ERR(hba-sdev_boot)) {
-   ret = PTR_ERR(hba-sdev_boot);
-   hba-sdev_boot = NULL;
+   if (IS_ERR(sdev_boot)) {
+   ret = PTR_ERR(sdev_boot);
goto remove_sdev_ufs_device;
}
+   scsi_device_put(sdev_boot);
 
-   hba-sdev_rpmb = __scsi_add_device(hba-host, 0, 0,
+   sdev_rpmb = __scsi_add_device(hba-host, 0, 0,
ufshcd_upiu_wlun_to_scsi_wlun(UFS_UPIU_RPMB_WLUN), NULL);
-   if (IS_ERR(hba-sdev_rpmb)) {
-   ret = PTR_ERR(hba-sdev_rpmb);
-   hba-sdev_rpmb = NULL;
+   if (IS_ERR(sdev_rpmb)) {
+   ret = PTR_ERR(sdev_rpmb);
goto remove_sdev_boot;
}
+   scsi_device_put(sdev_rpmb);
goto out;
 
 remove_sdev_boot:
-   scsi_remove_device(hba-sdev_boot);
+   scsi_remove_device(sdev_boot);
 remove_sdev_ufs_device:
scsi_remove_device(hba-sdev_ufs_device);
 out:
@@ -4097,30 +4105,6 @@ out:
 }
 
 /**
- * ufshcd_scsi_remove_wlus - Removes the W-LUs which were added by
- *  ufshcd_scsi_add_wlus()
- * @hba: per-adapter instance
- *
- */
-static void ufshcd_scsi_remove_wlus(struct ufs_hba *hba)
-{
-   if (hba-sdev_ufs_device) {
-   scsi_remove_device(hba-sdev_ufs_device);
-   hba-sdev_ufs_device = NULL;
-   }
-
-   if (hba-sdev_boot) {
-   scsi_remove_device(hba-sdev_boot);
-   hba-sdev_boot = NULL;
-   }
-
-   if (hba-sdev_rpmb) {
-   scsi_remove_device(hba-sdev_rpmb);
-   hba-sdev_rpmb = NULL;
-   }
-}
-
-/**
  * ufshcd_probe_hba - probe hba to detect device and initialize
  * @hba: per-adapter instance
  *
@@ -4675,11 +4659,25 @@ static int ufshcd_set_dev_pwr_mode(struct ufs_hba *hba,
 {
unsigned char cmd[6] = { START_STOP };
struct scsi_sense_hdr sshdr;
-   struct scsi_device *sdp = hba-sdev_ufs_device;
+   struct scsi_device *sdp;
+   unsigned long flags;
int ret;
 
-   if (!sdp || !scsi_device_online(sdp))
-   return -ENODEV;
+   spin_lock_irqsave(hba-host-host_lock, flags);
+   sdp = hba-sdev_ufs_device;
+   if (sdp) {
+   ret = scsi_device_get(sdp);
+   if (!ret  !scsi_device_online(sdp)) {
+   ret = -ENODEV;
+   scsi_device_put(sdp);
+   }
+   } else {
+   ret = -ENODEV

[PATCH 1/1] ufs: scsi: fix sparse errors in ufshcd_system_suspend

2014-10-05 Thread Dolev Raviv
This patch fixes newly introduced sparse warning in
ufshcd_system_suspend, introduced by UFS power management series.

Sparse warning:
drivers/scsi/ufs/ufshcd.c:5118 ufshcd_system_suspend()
error: we previously assumed 'hba' could be null (see line 5089)

To fix it, we return 0 in case HBA is not initialized or is
not powered.

Signed-off-by: Dolev Raviv dra...@codeaurora.org

diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index 497c38a..836ea72 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -5087,7 +5087,7 @@ int ufshcd_system_suspend(struct ufs_hba *hba)
int ret = 0;
 
if (!hba || !hba-is_powered)
-   goto out;
+   return 0;
 
if (pm_runtime_suspended(hba-dev)) {
if (hba-rpm_lvl == hba-spm_lvl)
-- 
1.8.5.2
--
QUALCOMM ISRAEL, on behalf of Qualcomm Innovation Center, Inc. is a member
of Code Aurora Forum, hosted by The Linux Foundation

--
To unsubscribe from this list: send the line unsubscribe linux-scsi in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH 1/2] scsi: fix sparse warning

2014-09-29 Thread Dolev Raviv
This patch fixes newly introduced sparse warning, introduced by
scis: fixing the type for well known LUs.

Sparse warning:
 drivers/scsi/scsi_scan.c:825: warning: format '%16p' expects type
'void *', but argument 6 has type 'u64'

Signed-off-by: Dolev Raviv dra...@codeaurora.org

diff --git a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c
index c6c5716..74b28c9 100644
--- a/drivers/scsi/scsi_scan.c
+++ b/drivers/scsi/scsi_scan.c
@@ -813,8 +813,8 @@ static int scsi_add_lun(struct scsi_device *sdev, unsigned 
char *inq_result,
 */
if (scsi_is_wlun(sdev-lun)  sdev-type != TYPE_WLUN) {
sdev_printk(KERN_WARNING, sdev,
-   %s: correcting incorrect peripheral device 
type 0x%x for W-LUN 0x%16phN\n,
-   __func__, sdev-type, sdev-lun);
+   %s: correcting incorrect peripheral device 
type 0x%x for W-LUN 0x%16xhN\n,
+   __func__, sdev-type, (unsigned int)sdev-lun);
sdev-type = TYPE_WLUN;
}
 
-- 
1.8.5.2

-- 
QUALCOMM ISRAEL, on behalf of Qualcomm Innovation Center, Inc. is a member
of Code Aurora Forum, hosted by The Linux Foundation

--
To unsubscribe from this list: send the line unsubscribe linux-scsi in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH 2/2] scsi: ufs: fix sparse warning

2014-09-29 Thread Dolev Raviv
This patch fixes newly introduced sparse warning, introduced by
UFS power management series.

Sparse warning:
 drivers/scsi/ufs/ufshcd.c:1867:5: sparse: symbol
'ufshcd_uic_pwr_ctrl' was not declared. Should it be static?
 drivers/scsi/ufs/ufshcd.c:2025:5: sparse: symbol
'ufshcd_change_power_mode' was not declared. Should it be static?

Signed-off-by: Dolev Raviv dra...@codeaurora.org

diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index 5c78c3d..497c38a 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -2146,7 +2146,7 @@ EXPORT_SYMBOL_GPL(ufshcd_dme_get_attr);
  *
  * Returns 0 on success, non-zero value on failure
  */
-int ufshcd_uic_pwr_ctrl(struct ufs_hba *hba, struct uic_command *cmd)
+static int ufshcd_uic_pwr_ctrl(struct ufs_hba *hba, struct uic_command *cmd)
 {
struct completion uic_async_done;
unsigned long flags;
@@ -2309,7 +2309,7 @@ static int ufshcd_get_max_pwr_mode(struct ufs_hba *hba)
return 0;
 }
 
-int ufshcd_change_power_mode(struct ufs_hba *hba,
+static int ufshcd_change_power_mode(struct ufs_hba *hba,
 struct ufs_pa_layer_attr *pwr_mode)
 {
int ret;
-- 
1.8.5.2

-- 
QUALCOMM ISRAEL, on behalf of Qualcomm Innovation Center, Inc. is a member
of Code Aurora Forum, hosted by The Linux Foundation

--
To unsubscribe from this list: send the line unsubscribe linux-scsi in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [PATCH V5 11/17] scsi: ufs: add UFS power management support

2014-09-25 Thread Dolev Raviv
Thanks Mita,
You are right these are careless mistakes.
I will fix all of them and upload a new version shortly.

 __ufshcd_send_uic_cmd() is called with host_lock held here, but
 host_lock is acquired again in __ufshcd_send_uic_cmd().  So it causes
 recursive deadlock.

Correct I forgot to complete the fix.


 ufshcd_wait_for_uic_cmd() is already called in the previous
 __ufshcd_send_uic_cmd() call.

 These two issues don't exist in v3.

Same fix I forgot to complete from earlier comment.


 I was still seeing null pointer derefence with v4 which I was reported
 (http://marc.info/?l=linux-scsim=141087506802548) and nothing
 changed in v5.  Could you check if the fix is needed?

Sure, my mistake. I'll defiantly add a null pointer check in
ufshcd_config_vreg_hpm  ufshcd_config_vreg_lpm, to reduce overhead when
vregs are not initialized.

Thanks,
Dolev

-- 
QUALCOMM ISRAEL, on behalf of Qualcomm Innovation Center, Inc. is a member
of Code Aurora Forum, hosted by The Linux Foundation


--
To unsubscribe from this list: send the line unsubscribe linux-scsi in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH/RESEND V6 00/18] UFS: Power management support

2014-09-25 Thread Dolev Raviv
This patch seies introduces support for power management in the driver as well 
as vendor specific initialization - registers, clocks, voltage regulators etc.

It includes also a rework for the init sequence and other PM pre-requisite such 
as write protection support, handling well-known LUN, error handling (retries), 
bkops, START_STOP unit command, and ICC levels settings.

--
Changes from V5:
 - Add a print to [01/18] scsi: fixing the type for well known LUs
   indicating on the type change.
 - Moved sdev-is_visible test to scsi_sysfs_add_devices
 - Reverted the squashed between
   [10/17] scsi: ufs: introduce well known logical unit in ufs and
   [09/17] scsi: ufs: manually add well known logical
   and addressed othe comments by Chris.
 - Fixed a bug and comments reported by Akinobu Mita akinobu.m...@gmail.com

Changes from V4:
 - Restored [01/16] scsi: support well known logical units to fix type issue
   and renamed [01/17] scsi: fixing the type for well known LUs
 - Add [02/17] scsi: sysfs: don't add scsi_device if its already added
   to help addressing Chris comments.
 - Squashed [10/17] scsi: ufs: introduce well known logical unit in ufs and
   [09/17] scsi: ufs: manually add well known logical and addressed most of
   Chris comments here.
 - Cleanup in [11/16] scsi: ufs: add UFS power management support to align
   it with comments made on previous patches.

Changes from V3:
 - Replaced [01/16] scsi: support well known logical units with
   [09/17] scsi: ufs: manually add well known logical
 - add patch [PATCH V4 05/17] scsi: ufs: add voting support for host
 - Fix couple of compilation issues introduced in V3
 - Add a NULL pointer test to hba-vops before accessing it
 - Changed disable/enable irq with request/free irq

Changes from V2:
 - Reordered scsi core patches
 - add patch [PATCH V3 02/16] scsi: balance out autopm get/put calls in
 - Minor changes/fixes to the patches:
* [PATCH V3 10/16] scsi: ufs: add UFS power management support
* [PATCH V3 12/16] scsi: ufs: Add support for clock gating
* [PATCH V3 16/16] scsi: ufs: definitions for phy interface
   In order to address community concerns, and as a result of further
   development and testing.

Changes from V1:
 - 6 new patches apended at the end
 - Allow overriding power configuration with controller support and
   preferences/capabilities Dolev Raviv
 - Allow overriding power choice with controller capabilities Dolev Raviv
 - Add support for clock gating and clock scaling Sahitya Tummala
 - Add capability to control the auto bkops during suspend Subhash Jadavani
 - Add misc changes for phy/unipro driver usage Dolev Raviv

Dolev Raviv (2):
  scsi: ufs: refactor configuring power mode
  scsi: ufs: definitions for phy interface

Raviv Shvili (1):
  scsi: ufs: add voting support for host controller power

Sahitya Tummala (3):
  scsi: ufs: Add support for clock gating
  scsi: ufs: Add freq-table-hz property for UFS device
  scsi: ufs: Add support for clock scaling using devfreq framework

Subhash Jadavani (7):
  scsi: fixing the type for well known LUs
  scsi: sysfs: don't add scsi_device if its already added
  scsi: ufs: refactor query descriptor API support
  scsi: ufs: manually add well known logical units
  scsi: ufs: introduce well known logical unit in ufs
  scsi: ufs: add UFS power management support
  scsi: ufs: tune bkops while power managment events

Sujit Reddy Thumma (4):
  scsi: ufs: Allow vendor specific initialization
  scsi: ufs: Add regulator enable support
  scsi: ufs: Add clock initialization support
  scsi: ufs: improve init sequence

Yaniv Gardi (1):
  scsi: ufs: Active Power Mode - configuring bActiveICCLevel

 .../devicetree/bindings/ufs/ufshcd-pltfrm.txt  |   41 +
 drivers/scsi/scsi_scan.c   |   16 +
 drivers/scsi/ufs/Kconfig   |2 +
 drivers/scsi/ufs/ufs.h |  132 +-
 drivers/scsi/ufs/ufshcd-pci.c  |   55 +-
 drivers/scsi/ufs/ufshcd-pltfrm.c   |  291 ++-
 drivers/scsi/ufs/ufshcd.c  | 2592 ++--
 drivers/scsi/ufs/ufshcd.h  |  280 ++-
 drivers/scsi/ufs/ufshci.h  |9 +-
 drivers/scsi/ufs/unipro.h  |   56 +
 include/scsi/scsi.h|1 +
 11 files changed, 3150 insertions(+), 325 deletions(-)

-- 
1.8.5.2
-- 
QUALCOMM ISRAEL, on behalf of Qualcomm Innovation Center, Inc. is a member
of Code Aurora Forum, hosted by The Linux Foundation

--
To unsubscribe from this list: send the line unsubscribe linux-scsi in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH V6 01/18] scsi: fixing the type for well known LUs

2014-09-25 Thread Dolev Raviv
From: Subhash Jadavani subha...@codeaurora.org

Some devices may respond with wrong type for well-known logical units.
This patch forces well-known type for devices which doesn't report it
correct.

Signed-off-by: Subhash Jadavani subha...@codeaurora.org
Signed-off-by: Sujit Reddy Thumma sthu...@codeaurora.org
Signed-off-by: Dolev Raviv dra...@codeaurora.org

diff --git a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c
index 56675db..1095d5a 100644
--- a/drivers/scsi/scsi_scan.c
+++ b/drivers/scsi/scsi_scan.c
@@ -805,6 +805,19 @@ static int scsi_add_lun(struct scsi_device *sdev, unsigned 
char *inq_result,
} else {
sdev-type = (inq_result[0]  0x1f);
sdev-removable = (inq_result[1]  0x80)  7;
+
+   /*
+* some devices may respond with wrong type for
+* well-known logical units. Force well-known type
+* to enumerate them correctly.
+*/
+   if (scsi_is_wlun(sdev-lun)  sdev-type != TYPE_WLUN) {
+   sdev_printk(KERN_WARNING, sdev,
+   %s: correcting incorrect peripheral device 
type 0x%x for W-LUN 0x%16phN\n,
+   __func__, sdev-type, sdev-lun);
+   sdev-type = TYPE_WLUN;
+   }
+
}
 
if (sdev-type == TYPE_RBC || sdev-type == TYPE_ROM) {
diff --git a/include/scsi/scsi.h b/include/scsi/scsi.h
index 261e708..d17178e 100644
--- a/include/scsi/scsi.h
+++ b/include/scsi/scsi.h
@@ -333,6 +333,7 @@ static inline int scsi_status_is_good(int status)
 #define TYPE_RBC   0x0e
 #define TYPE_OSD0x11
 #define TYPE_ZBC0x14
+#define TYPE_WLUN   0x1e/* well-known logical unit */
 #define TYPE_NO_LUN 0x7f
 
 /* SCSI protocols; these are taken from SPC-3 section 7.5 */
-- 
1.8.5.2
-- 
QUALCOMM ISRAEL, on behalf of Qualcomm Innovation Center, Inc. is a member
of Code Aurora Forum, hosted by The Linux Foundation

--
To unsubscribe from this list: send the line unsubscribe linux-scsi in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH V6 02/18] scsi: sysfs: don't add scsi_device if its already added

2014-09-25 Thread Dolev Raviv
From: Subhash Jadavani subha...@codeaurora.org

If LLD has added scsi device (by calling scsi_add_device) before scheduling
async scsi_scan_host then scsi_finish_async_scan() will end up calling
scsi_sysfs_add_sdev for scsi device which was already added by LLD.
This patch fixes this issue by skipping the call to scsi_sysfs_add_sdev()
if it's already visible to rest of the kernel.

Signed-off-by: Subhash Jadavani subha...@codeaurora.org
Signed-off-by: Dolev Raviv dra...@codeaurora.org

diff --git a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c
index 1095d5a..c6c5716 100644
--- a/drivers/scsi/scsi_scan.c
+++ b/drivers/scsi/scsi_scan.c
@@ -1746,6 +1746,9 @@ static void scsi_sysfs_add_devices(struct Scsi_Host 
*shost)
/* target removed before the device could be added */
if (sdev-sdev_state == SDEV_DEL)
continue;
+   /* If device is already visible, skip adding it to sysfs */
+   if (sdev-is_visible)
+   continue;
if (!scsi_host_scan_allowed(shost) ||
scsi_sysfs_add_sdev(sdev) != 0)
__scsi_remove_device(sdev);
-- 
1.8.5.2
-- 
QUALCOMM ISRAEL, on behalf of Qualcomm Innovation Center, Inc. is a member
of Code Aurora Forum, hosted by The Linux Foundation

--
To unsubscribe from this list: send the line unsubscribe linux-scsi in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH/RESEND V6 04/18] scsi: ufs: Add regulator enable support

2014-09-25 Thread Dolev Raviv
From: Sujit Reddy Thumma sthu...@codeaurora.org

UFS devices are powered by at most three external power supplies -
- VCC - The flash memory core power supply, 2.7V to 3.6V or 1.70V to 1.95V
- VCCQ - The controller and I/O power supply, 1.1V to 1.3V
- VCCQ2 - Secondary controller and/or I/O power supply, 1.65V to 1.95V

For some devices VCCQ or VCCQ2 are optional as they can be
generated using internal LDO inside the UFS device.

Add DT bindings for voltage regulators that can be controlled
from host driver.

Signed-off-by: Sujit Reddy Thumma sthu...@codeaurora.org
Signed-off-by: Dolev Raviv dra...@codeaurora.org

diff --git a/Documentation/devicetree/bindings/ufs/ufshcd-pltfrm.txt 
b/Documentation/devicetree/bindings/ufs/ufshcd-pltfrm.txt
index 20468b2..65e3117 100644
--- a/Documentation/devicetree/bindings/ufs/ufshcd-pltfrm.txt
+++ b/Documentation/devicetree/bindings/ufs/ufshcd-pltfrm.txt
@@ -8,9 +8,33 @@ Required properties:
 - interrupts: interrupt mapping for UFS host controller IRQ
 - reg   : registers mapping
 
+Optional properties:
+- vcc-supply: phandle to VCC supply regulator node
+- vccq-supply   : phandle to VCCQ supply regulator node
+- vccq2-supply  : phandle to VCCQ2 supply regulator node
+- vcc-supply-1p8: For embedded UFS devices, valid VCC range is 
1.7-1.95V
+  or 2.7-3.6V. This boolean property when set, 
specifies
+ to use low voltage range of 1.7-1.95V. Note for 
external
+ UFS cards this property is invalid and valid VCC 
range is
+ always 2.7-3.6V.
+- vcc-max-microamp  : specifies max. load that can be drawn from vcc supply
+- vccq-max-microamp : specifies max. load that can be drawn from vccq 
supply
+- vccq2-max-microamp: specifies max. load that can be drawn from vccq2 
supply
+
+Note: If above properties are not defined it can be assumed that the supply
+regulators are always on.
+
 Example:
ufshc@0xfc598000 {
compatible = jedec,ufs-1.1;
reg = 0xfc598000 0x800;
interrupts = 0 28 0;
+
+   vcc-supply = xxx_reg1;
+   vcc-supply-1p8;
+   vccq-supply = xxx_reg2;
+   vccq2-supply = xxx_reg3;
+   vcc-max-microamp = 50;
+   vccq-max-microamp = 20;
+   vccq2-max-microamp = 20;
};
diff --git a/drivers/scsi/ufs/ufs.h b/drivers/scsi/ufs/ufs.h
index fafcf5e..729ce7d 100644
--- a/drivers/scsi/ufs/ufs.h
+++ b/drivers/scsi/ufs/ufs.h
@@ -362,4 +362,29 @@ struct ufs_query_res {
struct utp_upiu_query upiu_res;
 };
 
+#define UFS_VREG_VCC_MIN_UV   270 /* uV */
+#define UFS_VREG_VCC_MAX_UV   360 /* uV */
+#define UFS_VREG_VCC_1P8_MIN_UV170 /* uV */
+#define UFS_VREG_VCC_1P8_MAX_UV195 /* uV */
+#define UFS_VREG_VCCQ_MIN_UV  110 /* uV */
+#define UFS_VREG_VCCQ_MAX_UV  130 /* uV */
+#define UFS_VREG_VCCQ2_MIN_UV 165 /* uV */
+#define UFS_VREG_VCCQ2_MAX_UV 195 /* uV */
+
+struct ufs_vreg {
+   struct regulator *reg;
+   const char *name;
+   bool enabled;
+   int min_uV;
+   int max_uV;
+   int min_uA;
+   int max_uA;
+};
+
+struct ufs_vreg_info {
+   struct ufs_vreg *vcc;
+   struct ufs_vreg *vccq;
+   struct ufs_vreg *vccq2;
+};
+
 #endif /* End of Header */
diff --git a/drivers/scsi/ufs/ufshcd-pltfrm.c b/drivers/scsi/ufs/ufshcd-pltfrm.c
index d727b1a..51e47c4 100644
--- a/drivers/scsi/ufs/ufshcd-pltfrm.c
+++ b/drivers/scsi/ufs/ufshcd-pltfrm.c
@@ -53,6 +53,99 @@ static struct ufs_hba_variant_ops *get_variant_ops(struct 
device *dev)
return NULL;
 }
 
+#define MAX_PROP_SIZE 32
+static int ufshcd_populate_vreg(struct device *dev, const char *name,
+   struct ufs_vreg **out_vreg)
+{
+   int ret = 0;
+   char prop_name[MAX_PROP_SIZE];
+   struct ufs_vreg *vreg = NULL;
+   struct device_node *np = dev-of_node;
+
+   if (!np) {
+   dev_err(dev, %s: non DT initialization\n, __func__);
+   goto out;
+   }
+
+   snprintf(prop_name, MAX_PROP_SIZE, %s-supply, name);
+   if (!of_parse_phandle(np, prop_name, 0)) {
+   dev_info(dev, %s: Unable to find %s regulator, assuming 
enabled\n,
+   __func__, prop_name);
+   goto out;
+   }
+
+   vreg = devm_kzalloc(dev, sizeof(*vreg), GFP_KERNEL);
+   if (!vreg) {
+   dev_err(dev, No memory for %s regulator\n, name);
+   goto out;
+   }
+
+   vreg-name = kstrdup(name, GFP_KERNEL);
+
+   snprintf(prop_name, MAX_PROP_SIZE, %s-max-microamp, name);
+   ret = of_property_read_u32(np, prop_name, vreg-max_uA);
+   if (ret) {
+   dev_err(dev, %s: unable to find %s err %d\n,
+   __func__, prop_name, ret);
+   goto out_free

[PATCH/RESEND V6 06/18] scsi: ufs: add voting support for host controller power

2014-09-25 Thread Dolev Raviv
From: Raviv Shvili rshv...@codeaurora.org

Add the support for voting of the regulator powering the
host controller logic.

Signed-off-by: Raviv Shvili rshv...@codeaurora.org
Signed-off-by: Subhash Jadavani subha...@codeaurora.org
Signed-off-by: Dolev Raviv dra...@codeaurora.org

diff --git a/Documentation/devicetree/bindings/ufs/ufshcd-pltfrm.txt 
b/Documentation/devicetree/bindings/ufs/ufshcd-pltfrm.txt
index b0f791a..fb1234e 100644
--- a/Documentation/devicetree/bindings/ufs/ufshcd-pltfrm.txt
+++ b/Documentation/devicetree/bindings/ufs/ufshcd-pltfrm.txt
@@ -9,6 +9,7 @@ Required properties:
 - reg   : registers mapping
 
 Optional properties:
+- vdd-hba-supply: phandle to UFS host controller supply regulator node
 - vcc-supply: phandle to VCC supply regulator node
 - vccq-supply   : phandle to VCCQ supply regulator node
 - vccq2-supply  : phandle to VCCQ2 supply regulator node
@@ -20,6 +21,7 @@ Optional properties:
 - vcc-max-microamp  : specifies max. load that can be drawn from vcc supply
 - vccq-max-microamp : specifies max. load that can be drawn from vccq 
supply
 - vccq2-max-microamp: specifies max. load that can be drawn from vccq2 
supply
+- name-fixed-regulator : boolean property specifying that name-supply is a 
fixed regulator
 
 - clocks: List of phandle and clock specifier pairs
 - clock-names   : List of clock input name strings sorted in the same
@@ -39,6 +41,8 @@ Example:
reg = 0xfc598000 0x800;
interrupts = 0 28 0;
 
+   vdd-hba-supply = xxx_reg0;
+   vdd-hba-fixed-regulator;
vcc-supply = xxx_reg1;
vcc-supply-1p8;
vccq-supply = xxx_reg2;
diff --git a/drivers/scsi/ufs/ufs.h b/drivers/scsi/ufs/ufs.h
index 729ce7d..9bb6919 100644
--- a/drivers/scsi/ufs/ufs.h
+++ b/drivers/scsi/ufs/ufs.h
@@ -385,6 +385,7 @@ struct ufs_vreg_info {
struct ufs_vreg *vcc;
struct ufs_vreg *vccq;
struct ufs_vreg *vccq2;
+   struct ufs_vreg *vdd_hba;
 };
 
 #endif /* End of Header */
diff --git a/drivers/scsi/ufs/ufshcd-pltfrm.c b/drivers/scsi/ufs/ufshcd-pltfrm.c
index 642d80f..dde4e6e 100644
--- a/drivers/scsi/ufs/ufshcd-pltfrm.c
+++ b/drivers/scsi/ufs/ufshcd-pltfrm.c
@@ -147,6 +147,11 @@ static int ufshcd_populate_vreg(struct device *dev, const 
char *name,
 
vreg-name = kstrdup(name, GFP_KERNEL);
 
+   /* if fixed regulator no need further initialization */
+   snprintf(prop_name, MAX_PROP_SIZE, %s-fixed-regulator, name);
+   if (of_property_read_bool(np, prop_name))
+   goto out;
+
snprintf(prop_name, MAX_PROP_SIZE, %s-max-microamp, name);
ret = of_property_read_u32(np, prop_name, vreg-max_uA);
if (ret) {
@@ -198,6 +203,10 @@ static int ufshcd_parse_regulator_info(struct ufs_hba *hba)
struct device *dev = hba-dev;
struct ufs_vreg_info *info = hba-vreg_info;
 
+   err = ufshcd_populate_vreg(dev, vdd-hba, info-vdd_hba);
+   if (err)
+   goto out;
+
err = ufshcd_populate_vreg(dev, vcc, info-vcc);
if (err)
goto out;
diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index b033702..26301b8 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -3311,6 +3311,16 @@ out:
return ret;
 }
 
+static int ufshcd_setup_hba_vreg(struct ufs_hba *hba, bool on)
+{
+   struct ufs_vreg_info *info = hba-vreg_info;
+
+   if (info)
+   return ufshcd_toggle_vreg(hba-dev, info-vdd_hba, on);
+
+   return 0;
+}
+
 static int ufshcd_get_vreg(struct device *dev, struct ufs_vreg *vreg)
 {
int ret = 0;
@@ -3350,6 +3360,16 @@ out:
return ret;
 }
 
+static int ufshcd_init_hba_vreg(struct ufs_hba *hba)
+{
+   struct ufs_vreg_info *info = hba-vreg_info;
+
+   if (info)
+   return ufshcd_get_vreg(hba-dev, info-vdd_hba);
+
+   return 0;
+}
+
 static int ufshcd_setup_clocks(struct ufs_hba *hba, bool on)
 {
int ret = 0;
@@ -3483,14 +3503,29 @@ static int ufshcd_hba_init(struct ufs_hba *hba)
 {
int err;
 
-   err = ufshcd_init_clocks(hba);
+   /*
+* Handle host controller power separately from the UFS device power
+* rails as it will help controlling the UFS host controller power
+* collapse easily which is different than UFS device power collapse.
+* Also, enable the host controller power before we go ahead with rest
+* of the initialization here.
+*/
+   err = ufshcd_init_hba_vreg(hba);
if (err)
goto out;
 
-   err = ufshcd_setup_clocks(hba, true);
+   err = ufshcd_setup_hba_vreg(hba, true);
if (err)
goto out;
 
+   err = ufshcd_init_clocks(hba);
+   if (err)
+   goto out_disable_hba_vreg;
+
+   err = ufshcd_setup_clocks(hba, true);
+   if (err

[PATCH/RESEND V6 07/18] scsi: ufs: refactor query descriptor API support

2014-09-25 Thread Dolev Raviv
From: Subhash Jadavani subha...@codeaurora.org

Currently reading query descriptor is more tightened to each
descriptor type. This patch generalize the approach and allows
reading any parameter from any query descriptor.

Signed-off-by: Subhash Jadavani subha...@codeaurora.org
Signed-off-by: Dolev Raviv dra...@codeaurora.org

diff --git a/drivers/scsi/ufs/ufs.h b/drivers/scsi/ufs/ufs.h
index 9bb6919..f76a304 100644
--- a/drivers/scsi/ufs/ufs.h
+++ b/drivers/scsi/ufs/ufs.h
@@ -50,6 +50,8 @@
cpu_to_be32((byte3  24) | (byte2  16) |\
 (byte1  8) | (byte0))
 
+#define UFS_UPIU_MAX_GENERAL_LUN   8
+
 /*
  * UFS Protocol Information Unit related definitions
  */
@@ -129,10 +131,29 @@ enum desc_idn {
QUERY_DESC_IDN_RFU_1= 0x6,
QUERY_DESC_IDN_GEOMETRY = 0x7,
QUERY_DESC_IDN_POWER= 0x8,
-   QUERY_DESC_IDN_RFU_2= 0x9,
+   QUERY_DESC_IDN_MAX,
+};
+
+enum desc_header_offset {
+   QUERY_DESC_LENGTH_OFFSET= 0x00,
+   QUERY_DESC_DESC_TYPE_OFFSET = 0x01,
+};
+
+enum ufs_desc_max_size {
+   QUERY_DESC_DEVICE_MAX_SIZE  = 0x1F,
+   QUERY_DESC_CONFIGURAION_MAX_SIZE= 0x90,
+   QUERY_DESC_UNIT_MAX_SIZE= 0x23,
+   QUERY_DESC_INTERCONNECT_MAX_SIZE= 0x06,
+   /*
+* Max. 126 UNICODE characters (2 bytes per character) plus 2 bytes
+* of descriptor header.
+*/
+   QUERY_DESC_STRING_MAX_SIZE  = 0xFE,
+   QUERY_DESC_GEOMETRY_MAZ_SIZE= 0x44,
+   QUERY_DESC_POWER_MAX_SIZE   = 0x62,
+   QUERY_DESC_RFU_MAX_SIZE = 0x00,
 };
 
-#define UNIT_DESC_MAX_SIZE   0x22
 /* Unit descriptor parameters offsets in bytes*/
 enum unit_desc_param {
UNIT_DESC_PARAM_LEN = 0x0,
diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index 26301b8..3f2b30d 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -78,6 +78,19 @@
_ret;   \
})
 
+static u32 ufs_query_desc_max_size[] = {
+   QUERY_DESC_DEVICE_MAX_SIZE,
+   QUERY_DESC_CONFIGURAION_MAX_SIZE,
+   QUERY_DESC_UNIT_MAX_SIZE,
+   QUERY_DESC_RFU_MAX_SIZE,
+   QUERY_DESC_INTERCONNECT_MAX_SIZE,
+   QUERY_DESC_STRING_MAX_SIZE,
+   QUERY_DESC_RFU_MAX_SIZE,
+   QUERY_DESC_GEOMETRY_MAZ_SIZE,
+   QUERY_DESC_POWER_MAX_SIZE,
+   QUERY_DESC_RFU_MAX_SIZE,
+};
+
 enum {
UFSHCD_MAX_CHANNEL  = 0,
UFSHCD_MAX_ID   = 1,
@@ -124,8 +137,6 @@ static void ufshcd_tmc_handler(struct ufs_hba *hba);
 static void ufshcd_async_scan(void *data, async_cookie_t cookie);
 static int ufshcd_reset_and_restore(struct ufs_hba *hba);
 static int ufshcd_clear_tm_cmd(struct ufs_hba *hba, int tag);
-static int ufshcd_read_sdev_qdepth(struct ufs_hba *hba,
-   struct scsi_device *sdev);
 
 /*
  * ufshcd_wait_for_register - wait for register value to change
@@ -1393,6 +1404,115 @@ out:
 }
 
 /**
+ * ufshcd_read_desc_param - read the specified descriptor parameter
+ * @hba: Pointer to adapter instance
+ * @desc_id: descriptor idn value
+ * @desc_index: descriptor index
+ * @param_offset: offset of the parameter to read
+ * @param_read_buf: pointer to buffer where parameter would be read
+ * @param_size: sizeof(param_read_buf)
+ *
+ * Return 0 in case of success, non-zero otherwise
+ */
+static int ufshcd_read_desc_param(struct ufs_hba *hba,
+ enum desc_idn desc_id,
+ int desc_index,
+ u32 param_offset,
+ u8 *param_read_buf,
+ u32 param_size)
+{
+   int ret;
+   u8 *desc_buf;
+   u32 buff_len;
+   bool is_kmalloc = true;
+
+   /* safety checks */
+   if (desc_id = QUERY_DESC_IDN_MAX)
+   return -EINVAL;
+
+   buff_len = ufs_query_desc_max_size[desc_id];
+   if ((param_offset + param_size)  buff_len)
+   return -EINVAL;
+
+   if (!param_offset  (param_size == buff_len)) {
+   /* memory space already available to hold full descriptor */
+   desc_buf = param_read_buf;
+   is_kmalloc = false;
+   } else {
+   /* allocate memory to hold full descriptor */
+   desc_buf = kmalloc(buff_len, GFP_KERNEL);
+   if (!desc_buf)
+   return -ENOMEM;
+   }
+
+   ret = ufshcd_query_descriptor(hba, UPIU_QUERY_OPCODE_READ_DESC,
+ desc_id, desc_index, 0, desc_buf,
+ buff_len);
+
+   if (ret || (buff_len  ufs_query_desc_max_size[desc_id]) ||
+   (desc_buf[QUERY_DESC_LENGTH_OFFSET] !=
+ufs_query_desc_max_size[desc_id

[PATCH/RESEND V6 05/18] scsi: ufs: Add clock initialization support

2014-09-25 Thread Dolev Raviv
From: Sujit Reddy Thumma sthu...@codeaurora.org

Add generic clock initialization support for UFSHCD platform
driver. The clock info is read from device tree using standard
clock bindings. A generic max-clock-frequency-hz property is
defined to save information on maximum operating clock frequency
the h/w supports.

Signed-off-by: Sujit Reddy Thumma sthu...@codeaurora.org
Signed-off-by: Dolev Raviv dra...@codeaurora.org

diff --git a/Documentation/devicetree/bindings/ufs/ufshcd-pltfrm.txt 
b/Documentation/devicetree/bindings/ufs/ufshcd-pltfrm.txt
index 65e3117..b0f791a 100644
--- a/Documentation/devicetree/bindings/ufs/ufshcd-pltfrm.txt
+++ b/Documentation/devicetree/bindings/ufs/ufshcd-pltfrm.txt
@@ -21,8 +21,17 @@ Optional properties:
 - vccq-max-microamp : specifies max. load that can be drawn from vccq 
supply
 - vccq2-max-microamp: specifies max. load that can be drawn from vccq2 
supply
 
+- clocks: List of phandle and clock specifier pairs
+- clock-names   : List of clock input name strings sorted in the same
+  order as the clocks property.
+- max-clock-frequency-hz : List of maximum operating frequency stored in the 
same
+   order as the clocks property. If this property is 
not
+  defined or a value in the array is 0 then it is 
assumed
+  that the frequency is set by the parent clock or a
+  fixed rate clock source.
+
 Note: If above properties are not defined it can be assumed that the supply
-regulators are always on.
+regulators or clocks are always on.
 
 Example:
ufshc@0xfc598000 {
@@ -37,4 +46,8 @@ Example:
vcc-max-microamp = 50;
vccq-max-microamp = 20;
vccq2-max-microamp = 20;
+
+   clocks = core 0, ref 0, iface 0;
+   clock-names = core_clk, ref_clk, iface_clk;
+   max-clock-frequency-hz = 1 1920 0;
};
diff --git a/drivers/scsi/ufs/ufshcd-pci.c b/drivers/scsi/ufs/ufshcd-pci.c
index 7a6edbc..2a26faa 100644
--- a/drivers/scsi/ufs/ufshcd-pci.c
+++ b/drivers/scsi/ufs/ufshcd-pci.c
@@ -170,6 +170,8 @@ ufshcd_pci_probe(struct pci_dev *pdev, const struct 
pci_device_id *id)
return err;
}
 
+   INIT_LIST_HEAD(hba-clk_list_head);
+
err = ufshcd_init(hba, mmio_base, pdev-irq);
if (err) {
dev_err(pdev-dev, Initialization failed\n);
diff --git a/drivers/scsi/ufs/ufshcd-pltfrm.c b/drivers/scsi/ufs/ufshcd-pltfrm.c
index 51e47c4..642d80f 100644
--- a/drivers/scsi/ufs/ufshcd-pltfrm.c
+++ b/drivers/scsi/ufs/ufshcd-pltfrm.c
@@ -53,6 +53,71 @@ static struct ufs_hba_variant_ops *get_variant_ops(struct 
device *dev)
return NULL;
 }
 
+static int ufshcd_parse_clock_info(struct ufs_hba *hba)
+{
+   int ret = 0;
+   int cnt;
+   int i;
+   struct device *dev = hba-dev;
+   struct device_node *np = dev-of_node;
+   char *name;
+   u32 *clkfreq = NULL;
+   struct ufs_clk_info *clki;
+
+   if (!np)
+   goto out;
+
+   INIT_LIST_HEAD(hba-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,
+   __func__);
+   } else if (cnt  0) {
+   dev_err(dev, %s: count clock strings failed, err %d\n,
+   __func__, cnt);
+   ret = cnt;
+   }
+
+   if (cnt = 0)
+   goto out;
+
+   clkfreq = kzalloc(cnt * sizeof(*clkfreq), GFP_KERNEL);
+   if (!clkfreq) {
+   ret = -ENOMEM;
+   dev_err(dev, %s: memory alloc failed\n, __func__);
+   goto out;
+   }
+
+   ret = of_property_read_u32_array(np,
+   max-clock-frequency-hz, clkfreq, cnt);
+   if (ret  (ret != -EINVAL)) {
+   dev_err(dev, %s: invalid max-clock-frequency-hz property, 
%d\n,
+   __func__, ret);
+   goto out;
+   }
+
+   for (i = 0; i  cnt; i++) {
+   ret = of_property_read_string_index(np,
+   clock-names, i, (const char **)name);
+   if (ret)
+   goto out;
+
+   clki = devm_kzalloc(dev, sizeof(*clki), GFP_KERNEL);
+   if (!clki) {
+   ret = -ENOMEM;
+   goto out;
+   }
+
+   clki-max_freq = clkfreq[i];
+   clki-name = kstrdup(name, GFP_KERNEL);
+   list_add_tail(clki-list, hba-clk_list_head);
+   }
+out:
+   kfree(clkfreq);
+   return ret;
+}
+
 #define MAX_PROP_SIZE 32
 static int ufshcd_populate_vreg(struct device *dev, const char *name,
struct ufs_vreg **out_vreg)
@@ -266,6 +331,12 @@ static int

[PATCH/RESEND V6 03/18] scsi: ufs: Allow vendor specific initialization

2014-09-25 Thread Dolev Raviv
From: Sujit Reddy Thumma sthu...@codeaurora.org

Some vendor specific controller versions might need to configure
vendor specific - registers, clocks, voltage regulators etc. to
initialize the host controller UTP layer and Uni-Pro stack.
Provide some common initialization operations that can be used
to configure vendor specifics. The methods can be extended in
future, for example, for power mode transitions.

The operations are vendor/board specific and hence determined with
the help of compatible property in device tree.

Signed-off-by: Sujit Reddy Thumma sthu...@codeaurora.org
Signed-off-by: Dolev Raviv dra...@codeaurora.org

diff --git a/drivers/scsi/ufs/ufshcd-pci.c b/drivers/scsi/ufs/ufshcd-pci.c
index afaabe2..7a6edbc 100644
--- a/drivers/scsi/ufs/ufshcd-pci.c
+++ b/drivers/scsi/ufs/ufshcd-pci.c
@@ -164,7 +164,13 @@ ufshcd_pci_probe(struct pci_dev *pdev, const struct 
pci_device_id *id)
 
mmio_base = pcim_iomap_table(pdev)[0];
 
-   err = ufshcd_init(pdev-dev, hba, mmio_base, pdev-irq);
+   err = ufshcd_alloc_host(pdev-dev, hba);
+   if (err) {
+   dev_err(pdev-dev, Allocation failed\n);
+   return err;
+   }
+
+   err = ufshcd_init(hba, mmio_base, pdev-irq);
if (err) {
dev_err(pdev-dev, Initialization failed\n);
return err;
diff --git a/drivers/scsi/ufs/ufshcd-pltfrm.c b/drivers/scsi/ufs/ufshcd-pltfrm.c
index 5e46232..d727b1a 100644
--- a/drivers/scsi/ufs/ufshcd-pltfrm.c
+++ b/drivers/scsi/ufs/ufshcd-pltfrm.c
@@ -35,9 +35,24 @@
 
 #include linux/platform_device.h
 #include linux/pm_runtime.h
+#include linux/of.h
 
 #include ufshcd.h
 
+static const struct of_device_id ufs_of_match[];
+static struct ufs_hba_variant_ops *get_variant_ops(struct device *dev)
+{
+   if (dev-of_node) {
+   const struct of_device_id *match;
+
+   match = of_match_node(ufs_of_match, dev-of_node);
+   if (match)
+   return (struct ufs_hba_variant_ops *)match-data;
+   }
+
+   return NULL;
+}
+
 #ifdef CONFIG_PM
 /**
  * ufshcd_pltfrm_suspend - suspend power management function
@@ -138,8 +153,8 @@ static int ufshcd_pltfrm_probe(struct platform_device *pdev)
 
mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
mmio_base = devm_ioremap_resource(dev, mem_res);
-   if (IS_ERR(mmio_base)) {
-   err = PTR_ERR(mmio_base);
+   if (IS_ERR(*(void **)mmio_base)) {
+   err = PTR_ERR(*(void **)mmio_base);
goto out;
}
 
@@ -150,10 +165,18 @@ static int ufshcd_pltfrm_probe(struct platform_device 
*pdev)
goto out;
}
 
+   err = ufshcd_alloc_host(dev, hba);
+   if (err) {
+   dev_err(pdev-dev, Allocation failed\n);
+   goto out;
+   }
+
+   hba-vops = get_variant_ops(pdev-dev);
+
pm_runtime_set_active(pdev-dev);
pm_runtime_enable(pdev-dev);
 
-   err = ufshcd_init(dev, hba, mmio_base, irq);
+   err = ufshcd_init(hba, mmio_base, irq);
if (err) {
dev_err(dev, Intialization failed\n);
goto out_disable_rpm;
diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index ba27215..d0565b0 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -3,6 +3,7 @@
  *
  * This code is based on drivers/scsi/ufs/ufshcd.c
  * Copyright (C) 2011-2013 Samsung India Software Operations
+ * Copyright (c) 2013-2014, The Linux Foundation. All rights reserved.
  *
  * Authors:
  * Santosh Yaraganavi santosh...@samsung.com
@@ -31,6 +32,9 @@
  * circumstances will the contributor of this Program be liable for
  * any damages of any kind arising from your use or distribution of
  * this program.
+ *
+ * The Linux Foundation chooses to take subject only to the GPLv2
+ * license terms, and distributes only under these terms.
  */
 
 #include linux/async.h
@@ -175,13 +179,14 @@ static inline u32 ufshcd_get_ufs_version(struct ufs_hba 
*hba)
 /**
  * ufshcd_is_device_present - Check if any device connected to
  *   the host controller
- * @reg_hcs - host controller status register value
+ * @hba: pointer to adapter instance
  *
  * Returns 1 if device present, 0 if no device detected
  */
-static inline int ufshcd_is_device_present(u32 reg_hcs)
+static inline int ufshcd_is_device_present(struct ufs_hba *hba)
 {
-   return (DEVICE_PRESENT  reg_hcs) ? 1 : 0;
+   return (ufshcd_readl(hba, REG_CONTROLLER_STATUS) 
+   DEVICE_PRESENT) ? 1 : 0;
 }
 
 /**
@@ -1798,11 +1803,10 @@ out:
  * @hba: per adapter instance
  *
  * To bring UFS host controller to operational state,
- * 1. Check if device is present
- * 2. Enable required interrupts
- * 3. Configure interrupt aggregation
- * 4. Program UTRL and UTMRL base addres
- * 5. Configure run-stop-registers
+ * 1. Enable required interrupts
+ * 2. Configure interrupt

[PATCH/RESEND V6 14/18] scsi: ufs: Add support for clock gating

2014-09-25 Thread Dolev Raviv
From: Sahitya Tummala stumm...@codeaurora.org

The UFS controller clocks can be gated after certain period of
inactivity, which is typically less than runtime suspend timeout.
In addition to clocks the link will also be put into Hibern8 mode
to save more power.

The clock gating can be turned on by enabling the capability
UFSHCD_CAP_CLK_GATING. To enable entering into Hibern8 mode as part of
clock gating, set the capability UFSHCD_CAP_HIBERN8_WITH_CLK_GATING.

The tracing events for clock gating can be enabled through debugfs as:
echo 1  /sys/kernel/debug/tracing/events/ufs/ufshcd_clk_gating/enable
cat /sys/kernel/debug/tracing/trace_pipe

Signed-off-by: Sahitya Tummala stumm...@codeaurora.org
Signed-off-by: Dolev Raviv dra...@codeaurora.org

diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index 052f940..fe3511e 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -177,6 +177,11 @@ static int ufshcd_reset_and_restore(struct ufs_hba *hba);
 static int ufshcd_clear_tm_cmd(struct ufs_hba *hba, int tag);
 static void ufshcd_hba_exit(struct ufs_hba *hba);
 static int ufshcd_probe_hba(struct ufs_hba *hba);
+static int __ufshcd_setup_clocks(struct ufs_hba *hba, bool on,
+bool skip_ref_clk);
+static int ufshcd_setup_clocks(struct ufs_hba *hba, bool on);
+static int ufshcd_uic_hibern8_exit(struct ufs_hba *hba);
+static int ufshcd_uic_hibern8_enter(struct ufs_hba *hba);
 static int ufshcd_host_reset_and_restore(struct ufs_hba *hba);
 static irqreturn_t ufshcd_intr(int irq, void *__hba);
 static int ufshcd_config_pwr_mode(struct ufs_hba *hba,
@@ -507,6 +512,231 @@ static inline int ufshcd_is_hba_active(struct ufs_hba 
*hba)
return (ufshcd_readl(hba, REG_CONTROLLER_ENABLE)  0x1) ? 0 : 1;
 }
 
+static void ufshcd_ungate_work(struct work_struct *work)
+{
+   int ret;
+   unsigned long flags;
+   struct ufs_hba *hba = container_of(work, struct ufs_hba,
+   clk_gating.ungate_work);
+
+   cancel_delayed_work_sync(hba-clk_gating.gate_work);
+
+   spin_lock_irqsave(hba-host-host_lock, flags);
+   if (hba-clk_gating.state == CLKS_ON) {
+   spin_unlock_irqrestore(hba-host-host_lock, flags);
+   goto unblock_reqs;
+   }
+
+   spin_unlock_irqrestore(hba-host-host_lock, flags);
+   ufshcd_setup_clocks(hba, true);
+
+   /* Exit from hibern8 */
+   if (ufshcd_can_hibern8_during_gating(hba)) {
+   /* Prevent gating in this path */
+   hba-clk_gating.is_suspended = true;
+   if (ufshcd_is_link_hibern8(hba)) {
+   ret = ufshcd_uic_hibern8_exit(hba);
+   if (ret)
+   dev_err(hba-dev, %s: hibern8 exit failed 
%d\n,
+   __func__, ret);
+   else
+   ufshcd_set_link_active(hba);
+   }
+   hba-clk_gating.is_suspended = false;
+   }
+unblock_reqs:
+   scsi_unblock_requests(hba-host);
+}
+
+/**
+ * ufshcd_hold - Enable clocks that were gated earlier due to ufshcd_release.
+ * Also, exit from hibern8 mode and set the link as active.
+ * @hba: per adapter instance
+ * @async: This indicates whether caller should ungate clocks asynchronously.
+ */
+int ufshcd_hold(struct ufs_hba *hba, bool async)
+{
+   int rc = 0;
+   unsigned long flags;
+
+   if (!ufshcd_is_clkgating_allowed(hba))
+   goto out;
+start:
+   spin_lock_irqsave(hba-host-host_lock, flags);
+   hba-clk_gating.active_reqs++;
+
+   switch (hba-clk_gating.state) {
+   case CLKS_ON:
+   break;
+   case REQ_CLKS_OFF:
+   if (cancel_delayed_work(hba-clk_gating.gate_work)) {
+   hba-clk_gating.state = CLKS_ON;
+   break;
+   }
+   /*
+* If we here, it means gating work is either done or
+* currently running. Hence, fall through to cancel gating
+* work and to enable clocks.
+*/
+   case CLKS_OFF:
+   scsi_block_requests(hba-host);
+   hba-clk_gating.state = REQ_CLKS_ON;
+   schedule_work(hba-clk_gating.ungate_work);
+   /*
+* fall through to check if we should wait for this
+* work to be done or not.
+*/
+   case REQ_CLKS_ON:
+   if (async) {
+   rc = -EAGAIN;
+   hba-clk_gating.active_reqs--;
+   break;
+   }
+
+   spin_unlock_irqrestore(hba-host-host_lock, flags);
+   flush_work(hba-clk_gating.ungate_work);
+   /* Make sure state is CLKS_ON before returning */
+   goto start;
+   default:
+   dev_err(hba-dev, %s: clk gating is in invalid state %d\n

[PATCH/RESEND V6 13/18] scsi: ufs: refactor configuring power mode

2014-09-25 Thread Dolev Raviv
Sometimes, the device shall report its maximum power and speed
capabilities, but we might not wish to configure it to use those
maximum capabilities.
This change adds support for the vendor specific host driver to
implement power change notify callback.

To enable configuring different power modes (number of lanes,
gear number and fast/slow modes) it is necessary to split the
configuration stage from the stage that reads the device max power mode.
In addition, it is not required to read the configuration more than
once, thus the configuration is stored after reading it once.

Signed-off-by: Dolev Raviv dra...@codeaurora.org
Signed-off-by: Yaniv Gardi yga...@codeaurora.org

diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index fad039e..052f940 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -179,6 +179,8 @@ static void ufshcd_hba_exit(struct ufs_hba *hba);
 static int ufshcd_probe_hba(struct ufs_hba *hba);
 static int ufshcd_host_reset_and_restore(struct ufs_hba *hba);
 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 inline int ufshcd_enable_irq(struct ufs_hba *hba)
 {
@@ -1958,40 +1960,83 @@ static int ufshcd_uic_hibern8_exit(struct ufs_hba *hba)
 }
 
 /**
- * ufshcd_config_max_pwr_mode - Set  Change power mode with
- * maximum capability attribute information.
- * @hba: per adapter instance
- *
- * Returns 0 on success, non-zero value on failure
+ * ufshcd_get_max_pwr_mode - reads the max power mode negotiated with device
+ * @hba: per-adapter instance
  */
-static int ufshcd_config_max_pwr_mode(struct ufs_hba *hba)
+static int ufshcd_get_max_pwr_mode(struct ufs_hba *hba)
 {
-   enum {RX = 0, TX = 1};
-   u32 lanes[] = {1, 1};
-   u32 gear[] = {1, 1};
-   u8 pwr[] = {FASTAUTO_MODE, FASTAUTO_MODE};
-   int ret;
+   struct ufs_pa_layer_attr *pwr_info = hba-max_pwr_info.info;
+
+   if (hba-max_pwr_info.is_valid)
+   return 0;
+
+   pwr_info-pwr_tx = FASTAUTO_MODE;
+   pwr_info-pwr_rx = FASTAUTO_MODE;
+   pwr_info-hs_rate = PA_HS_MODE_B;
 
/* Get the connected lane count */
-   ufshcd_dme_get(hba, UIC_ARG_MIB(PA_CONNECTEDRXDATALANES), lanes[RX]);
-   ufshcd_dme_get(hba, UIC_ARG_MIB(PA_CONNECTEDTXDATALANES), lanes[TX]);
+   ufshcd_dme_get(hba, UIC_ARG_MIB(PA_CONNECTEDRXDATALANES),
+   pwr_info-lane_rx);
+   ufshcd_dme_get(hba, UIC_ARG_MIB(PA_CONNECTEDTXDATALANES),
+   pwr_info-lane_tx);
+
+   if (!pwr_info-lane_rx || !pwr_info-lane_tx) {
+   dev_err(hba-dev, %s: invalid connected lanes value. rx=%d, 
tx=%d\n,
+   __func__,
+   pwr_info-lane_rx,
+   pwr_info-lane_tx);
+   return -EINVAL;
+   }
 
/*
 * First, get the maximum gears of HS speed.
 * If a zero value, it means there is no HSGEAR capability.
 * Then, get the maximum gears of PWM speed.
 */
-   ufshcd_dme_get(hba, UIC_ARG_MIB(PA_MAXRXHSGEAR), gear[RX]);
-   if (!gear[RX]) {
-   ufshcd_dme_get(hba, UIC_ARG_MIB(PA_MAXRXPWMGEAR), gear[RX]);
-   pwr[RX] = SLOWAUTO_MODE;
+   ufshcd_dme_get(hba, UIC_ARG_MIB(PA_MAXRXHSGEAR), pwr_info-gear_rx);
+   if (!pwr_info-gear_rx) {
+   ufshcd_dme_get(hba, UIC_ARG_MIB(PA_MAXRXPWMGEAR),
+   pwr_info-gear_rx);
+   if (!pwr_info-gear_rx) {
+   dev_err(hba-dev, %s: invalid max pwm rx gear read = 
%d\n,
+   __func__, pwr_info-gear_rx);
+   return -EINVAL;
+   }
+   pwr_info-pwr_rx = SLOWAUTO_MODE;
}
 
-   ufshcd_dme_peer_get(hba, UIC_ARG_MIB(PA_MAXRXHSGEAR), gear[TX]);
-   if (!gear[TX]) {
+   ufshcd_dme_peer_get(hba, UIC_ARG_MIB(PA_MAXRXHSGEAR),
+   pwr_info-gear_tx);
+   if (!pwr_info-gear_tx) {
ufshcd_dme_peer_get(hba, UIC_ARG_MIB(PA_MAXRXPWMGEAR),
-   gear[TX]);
-   pwr[TX] = SLOWAUTO_MODE;
+   pwr_info-gear_tx);
+   if (!pwr_info-gear_tx) {
+   dev_err(hba-dev, %s: invalid max pwm tx gear read = 
%d\n,
+   __func__, pwr_info-gear_tx);
+   return -EINVAL;
+   }
+   pwr_info-pwr_tx = SLOWAUTO_MODE;
+   }
+
+   hba-max_pwr_info.is_valid = true;
+   return 0;
+}
+
+int ufshcd_change_power_mode(struct ufs_hba *hba,
+struct ufs_pa_layer_attr *pwr_mode)
+{
+   int ret;
+
+   /* if already configured to the requested pwr_mode */
+   if (pwr_mode-gear_rx == hba-pwr_info.gear_rx 
+   pwr_mode-gear_tx == hba

[PATCH/RESEND V6 18/18] scsi: ufs: definitions for phy interface

2014-09-25 Thread Dolev Raviv
- Adding some of the definitions missing in unipro.h, including power
  enumeration.
- Read Modify Write Line helper function
- Indication for the type of suspend

Signed-off-by: Dolev Raviv dra...@codeaurora.org
Signed-off-by: Subhash Jadavani subha...@codeaurora.org
Signed-off-by: Yaniv Gardi yga...@codeaurora.org

diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index 60260e8..5c78c3d 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -5114,6 +5114,8 @@ int ufshcd_system_suspend(struct ufs_hba *hba)
 
ret = ufshcd_suspend(hba, UFS_SYSTEM_PM);
 out:
+   if (!ret)
+   hba-is_sys_suspended = true;
return ret;
 }
 EXPORT_SYMBOL(ufshcd_system_suspend);
diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h
index d7fec86..58ecdff 100644
--- a/drivers/scsi/ufs/ufshcd.h
+++ b/drivers/scsi/ufs/ufshcd.h
@@ -474,6 +474,7 @@ struct ufs_hba {
 
struct devfreq *devfreq;
struct ufs_clk_scaling clk_scaling;
+   bool is_sys_suspended;
 };
 
 /* Returns true if clocks can be gated. Otherwise false */
@@ -499,6 +500,23 @@ static inline bool 
ufshcd_can_autobkops_during_suspend(struct ufs_hba *hba)
 #define ufshcd_readl(hba, reg) \
readl((hba)-mmio_base + (reg))
 
+/**
+ * ufshcd_rmwl - read modify write into a register
+ * @hba - per adapter instance
+ * @mask - mask to apply on read value
+ * @val - actual value to write
+ * @reg - register address
+ */
+static inline void ufshcd_rmwl(struct ufs_hba *hba, u32 mask, u32 val, u32 reg)
+{
+   u32 tmp;
+
+   tmp = ufshcd_readl(hba, reg);
+   tmp = ~mask;
+   tmp |= (val  mask);
+   ufshcd_writel(hba, tmp, reg);
+}
+
 int ufshcd_alloc_host(struct device *, struct ufs_hba **);
 int ufshcd_init(struct ufs_hba * , void __iomem * , unsigned int);
 void ufshcd_remove(struct ufs_hba *);
diff --git a/drivers/scsi/ufs/unipro.h b/drivers/scsi/ufs/unipro.h
index 0bb8041..3fc3e21 100644
--- a/drivers/scsi/ufs/unipro.h
+++ b/drivers/scsi/ufs/unipro.h
@@ -13,6 +13,44 @@
 #define _UNIPRO_H_
 
 /*
+ * M-TX Configuration Attributes
+ */
+#define TX_MODE0x0021
+#define TX_HSRATE_SERIES   0x0022
+#define TX_HSGEAR  0x0023
+#define TX_PWMGEAR 0x0024
+#define TX_AMPLITUDE   0x0025
+#define TX_HS_SLEWRATE 0x0026
+#define TX_SYNC_SOURCE 0x0027
+#define TX_HS_SYNC_LENGTH  0x0028
+#define TX_HS_PREPARE_LENGTH   0x0029
+#define TX_LS_PREPARE_LENGTH   0x002A
+#define TX_HIBERN8_CONTROL 0x002B
+#define TX_LCC_ENABLE  0x002C
+#define TX_PWM_BURST_CLOSURE_EXTENSION 0x002D
+#define TX_BYPASS_8B10B_ENABLE 0x002E
+#define TX_DRIVER_POLARITY 0x002F
+#define TX_HS_UNTERMINATED_LINE_DRIVE_ENABLE   0x0030
+#define TX_LS_TERMINATED_LINE_DRIVE_ENABLE 0x0031
+#define TX_LCC_SEQUENCER   0x0032
+#define TX_MIN_ACTIVATETIME0x0033
+#define TX_PWM_G6_G7_SYNC_LENGTH   0x0034
+
+/*
+ * M-RX Configuration Attributes
+ */
+#define RX_MODE0x00A1
+#define RX_HSRATE_SERIES   0x00A2
+#define RX_HSGEAR  0x00A3
+#define RX_PWMGEAR 0x00A4
+#define RX_LS_TERMINATED_ENABLE0x00A5
+#define RX_HS_UNTERMINATED_ENABLE  0x00A6
+#define RX_ENTER_HIBERN8   0x00A7
+#define RX_BYPASS_8B10B_ENABLE 0x00A8
+#define RX_TERMINATION_FORCE_ENABLE0x0089
+
+#define is_mphy_tx_attr(attr)  (attr  RX_MODE)
+/*
  * PHY Adpater attributes
  */
 #define PA_ACTIVETXDATALANES   0x1560
@@ -87,6 +125,24 @@ enum {
PA_HS_MODE_B= 2,
 };
 
+enum ufs_pwm_gear_tag {
+   UFS_PWM_DONT_CHANGE,/* Don't change Gear */
+   UFS_PWM_G1, /* PWM Gear 1 (default for reset) */
+   UFS_PWM_G2, /* PWM Gear 2 */
+   UFS_PWM_G3, /* PWM Gear 3 */
+   UFS_PWM_G4, /* PWM Gear 4 */
+   UFS_PWM_G5, /* PWM Gear 5 */
+   UFS_PWM_G6, /* PWM Gear 6 */
+   UFS_PWM_G7, /* PWM Gear 7 */
+};
+
+enum ufs_hs_gear_tag {
+   UFS_HS_DONT_CHANGE, /* Don't change Gear */
+   UFS_HS_G1,  /* HS Gear 1 (default for reset) */
+   UFS_HS_G2,  /* HS Gear 2 */
+   UFS_HS_G3,  /* HS Gear 3 */
+};
+
 /*
  * Data Link Layer Attributes
  */
-- 
1.8.5.2
-- 
QUALCOMM ISRAEL, on behalf of Qualcomm Innovation Center, Inc. is a member
of Code Aurora Forum, hosted by The Linux Foundation

--
To unsubscribe from this list: send the line unsubscribe linux-scsi in
the body of a message to majord...@vger.kernel.org

[PATCH/RESEND V6 17/18] scsi: ufs: tune bkops while power managment events

2014-09-25 Thread Dolev Raviv
From: Subhash Jadavani subha...@codeaurora.org

Add capability to control the auto bkops during suspend.
If host explicitly enables the auto bkops (background operation) on device
then only device would perform the bkops on its own. If auto bkops is not
enabled explicitly and if the device reaches to state where it must do
background operation, device would raise the urgent bkops exception event
to host and then host will enable the auto bkops on device. This patch
adds the option to choose whether auto bkops should be enabled during
runtime suspend or not. Since we don't want to keep the device active to
perform the non critical bkops, host will enable urgent bkops only.

Keep auto-bkops enabled after resume if urgent bkops needed.
If device bkops status shows that its in critical need of executing
background operations, host should allow the device to continue doing
background operations.

Signed-off-by: Subhash Jadavani subha...@codeaurora.org
Signed-off-by: Dolev Raviv dra...@codeaurora.org

diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index 1679cbfb..60260e8 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -4884,13 +4884,19 @@ static int ufshcd_suspend(struct ufs_hba *hba, enum 
ufs_pm_op pm_op)
}
 
if (ufshcd_is_runtime_pm(pm_op)) {
-   /*
-* The device is idle with no requests in the queue,
-* allow background operations if needed.
-*/
-   ret = ufshcd_bkops_ctrl(hba, BKOPS_STATUS_NON_CRITICAL);
-   if (ret)
-   goto enable_gating;
+   if (ufshcd_can_autobkops_during_suspend(hba)) {
+   /*
+* The device is idle with no requests in the queue,
+* allow background operations if bkops status shows
+* that performance might be impacted.
+*/
+   ret = ufshcd_urgent_bkops(hba);
+   if (ret)
+   goto enable_gating;
+   } else {
+   /* make sure that auto bkops is disabled */
+   ufshcd_disable_auto_bkops(hba);
+   }
}
 
if ((req_dev_pwr_mode != hba-curr_dev_pwr_mode) 
@@ -5038,7 +5044,11 @@ static int ufshcd_resume(struct ufs_hba *hba, enum 
ufs_pm_op pm_op)
goto set_old_link_state;
}
 
-   ufshcd_disable_auto_bkops(hba);
+   /*
+* If BKOPs operations are urgently needed at this moment then
+* keep auto-bkops enabled or else disable it.
+*/
+   ufshcd_urgent_bkops(hba);
hba-clk_gating.is_suspended = false;
 
if (ufshcd_is_clkscaling_enabled(hba))
diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h
index 908db3e..d7fec86 100644
--- a/drivers/scsi/ufs/ufshcd.h
+++ b/drivers/scsi/ufs/ufshcd.h
@@ -469,6 +469,8 @@ struct ufs_hba {
 #define UFSHCD_CAP_HIBERN8_WITH_CLK_GATING (1  1)
/* Allow dynamic clk scaling */
 #define UFSHCD_CAP_CLK_SCALING (1  2)
+   /* Allow auto bkops to enabled during runtime suspend */
+#define UFSHCD_CAP_AUTO_BKOPS_SUSPEND (1  3)
 
struct devfreq *devfreq;
struct ufs_clk_scaling clk_scaling;
@@ -487,6 +489,11 @@ static inline int ufshcd_is_clkscaling_enabled(struct 
ufs_hba *hba)
 {
return hba-caps  UFSHCD_CAP_CLK_SCALING;
 }
+static inline bool ufshcd_can_autobkops_during_suspend(struct ufs_hba *hba)
+{
+   return hba-caps  UFSHCD_CAP_AUTO_BKOPS_SUSPEND;
+}
+
 #define ufshcd_writel(hba, val, reg)   \
writel((val), (hba)-mmio_base + (reg))
 #define ufshcd_readl(hba, reg) \
-- 
1.8.5.2
-- 
QUALCOMM ISRAEL, on behalf of Qualcomm Innovation Center, Inc. is a member
of Code Aurora Forum, hosted by The Linux Foundation

--
To unsubscribe from this list: send the line unsubscribe linux-scsi in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH/RESEND V6 15/18] scsi: ufs: Add freq-table-hz property for UFS device

2014-09-25 Thread Dolev Raviv
From: Sahitya Tummala stumm...@codeaurora.org

Add freq-table-hz propery for UFS device to keep track of
min max frequencies supported by UFS clocks.

Signed-off-by: Sahitya Tummala stumm...@codeaurora.org
Signed-off-by: Dolev Raviv dra...@codeaurora.org

diff --git a/Documentation/devicetree/bindings/ufs/ufshcd-pltfrm.txt 
b/Documentation/devicetree/bindings/ufs/ufshcd-pltfrm.txt
index fb1234e..5357919 100644
--- a/Documentation/devicetree/bindings/ufs/ufshcd-pltfrm.txt
+++ b/Documentation/devicetree/bindings/ufs/ufshcd-pltfrm.txt
@@ -26,11 +26,11 @@ Optional properties:
 - clocks: List of phandle and clock specifier pairs
 - clock-names   : List of clock input name strings sorted in the same
   order as the clocks property.
-- max-clock-frequency-hz : List of maximum operating frequency stored in the 
same
-   order as the clocks property. If this property is 
not
-  defined or a value in the array is 0 then it is 
assumed
-  that the frequency is set by the parent clock or a
-  fixed rate clock source.
+- freq-table-hz: Array of min max operating frequencies 
stored in the same
+  order as the clocks property. If this property is not
+ defined or a value in the array is 0 then it is 
assumed
+ that the frequency is set by the parent clock or a
+ fixed rate clock source.
 
 Note: If above properties are not defined it can be assumed that the supply
 regulators or clocks are always on.
@@ -53,5 +53,5 @@ Example:
 
clocks = core 0, ref 0, iface 0;
clock-names = core_clk, ref_clk, iface_clk;
-   max-clock-frequency-hz = 1 1920 0;
+   freq-table-hz = 1 2, 0 0, 0 0;
};
diff --git a/drivers/scsi/ufs/ufshcd-pltfrm.c b/drivers/scsi/ufs/ufshcd-pltfrm.c
index 2482bba..8adf067 100644
--- a/drivers/scsi/ufs/ufshcd-pltfrm.c
+++ b/drivers/scsi/ufs/ufshcd-pltfrm.c
@@ -63,6 +63,8 @@ static int ufshcd_parse_clock_info(struct ufs_hba *hba)
char *name;
u32 *clkfreq = NULL;
struct ufs_clk_info *clki;
+   int len = 0;
+   size_t sz = 0;
 
if (!np)
goto out;
@@ -82,39 +84,59 @@ static int ufshcd_parse_clock_info(struct ufs_hba *hba)
if (cnt = 0)
goto out;
 
-   clkfreq = kzalloc(cnt * sizeof(*clkfreq), GFP_KERNEL);
+   if (!of_get_property(np, freq-table-hz, len)) {
+   dev_info(dev, freq-table-hz property not specified\n);
+   goto out;
+   }
+
+   if (len = 0)
+   goto out;
+
+   sz = len / sizeof(*clkfreq);
+   if (sz != 2 * cnt) {
+   dev_err(dev, %s len mismatch\n, freq-table-hz);
+   ret = -EINVAL;
+   goto out;
+   }
+
+   clkfreq = devm_kzalloc(dev, sz * sizeof(*clkfreq),
+   GFP_KERNEL);
if (!clkfreq) {
+   dev_err(dev, %s: no memory\n, freq-table-hz);
ret = -ENOMEM;
-   dev_err(dev, %s: memory alloc failed\n, __func__);
goto out;
}
 
-   ret = of_property_read_u32_array(np,
-   max-clock-frequency-hz, clkfreq, cnt);
+   ret = of_property_read_u32_array(np, freq-table-hz,
+   clkfreq, sz);
if (ret  (ret != -EINVAL)) {
-   dev_err(dev, %s: invalid max-clock-frequency-hz property, 
%d\n,
-   __func__, ret);
-   goto out;
+   dev_err(dev, %s: error reading array %d\n,
+   freq-table-hz, ret);
+   goto free_clkfreq;
}
 
-   for (i = 0; i  cnt; i++) {
+   for (i = 0; i  sz; i += 2) {
ret = of_property_read_string_index(np,
-   clock-names, i, (const char **)name);
+   clock-names, i/2, (const char **)name);
if (ret)
-   goto out;
+   goto free_clkfreq;
 
clki = devm_kzalloc(dev, sizeof(*clki), GFP_KERNEL);
if (!clki) {
ret = -ENOMEM;
-   goto out;
+   goto free_clkfreq;
}
 
-   clki-max_freq = clkfreq[i];
+   clki-min_freq = clkfreq[i];
+   clki-max_freq = clkfreq[i+1];
clki-name = kstrdup(name, GFP_KERNEL);
+   dev_dbg(dev, %s: min %u max %u name %s\n, freq-table-hz,
+   clki-min_freq, clki-max_freq, clki-name);
list_add_tail(clki-list, hba-clk_list_head);
}
-out:
+free_clkfreq:
kfree(clkfreq);
+out:
return ret;
 }
 
diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi

[PATCH/RESEND V6 08/18] scsi: ufs: improve init sequence

2014-09-25 Thread Dolev Raviv
From: Sujit Reddy Thumma sthu...@codeaurora.org

In -hce_enable_notify() callback the vendor specific initialization
may carry out additional DME configuration using UIC commands and
hence the UIC command completion interrupt enable bit should be set
before the post reset notification.
Add retries if the link-startup fails. This is required since due to
hardware timing issues, the Uni-Pro link-startup might fail. The UFS
HCI recovery procedure contradicts the Uni-Pro sequence. The UFS HCI
specifies to resend DME_LINKSTARTUP command after IS.ULLS (link-lost
interrupt) is received. The Uni-Pro specifies that if link-startup
fails the link is in down state. The link-lost is indicated to the
DME user only when the link is up. Hence, the UFS HCI recovery procedure
of waiting for IS.ULLS and retrying link-startup may not work properly.

At the end, if detection fails, power off (disable clocks, regulators,
phy) if the UFS device detection fails. This saves power while UFS device
is not embedded into the system.

Signed-off-by: Sujit Reddy Thumma sthu...@codeaurora.org
Signed-off-by: Dolev Raviv dra...@codeaurora.org

diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index 3f2b30d..af29d4c 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -62,6 +62,12 @@
 /* Task management command timeout */
 #define TM_CMD_TIMEOUT 100 /* msecs */
 
+/* maximum number of link-startup retries */
+#define DME_LINKSTARTUP_RETRIES 3
+
+/* maximum number of reset retries before giving up */
+#define MAX_HOST_RESET_RETRIES 5
+
 /* Expose the flag value from utp_upiu_query.value */
 #define MASK_QUERY_UPIU_FLAG_LOC 0xFF
 
@@ -137,6 +143,8 @@ static void ufshcd_tmc_handler(struct ufs_hba *hba);
 static void ufshcd_async_scan(void *data, async_cookie_t cookie);
 static int ufshcd_reset_and_restore(struct ufs_hba *hba);
 static int ufshcd_clear_tm_cmd(struct ufs_hba *hba, int tag);
+static void ufshcd_hba_exit(struct ufs_hba *hba);
+static int ufshcd_probe_hba(struct ufs_hba *hba);
 
 /*
  * ufshcd_wait_for_register - wait for register value to change
@@ -2043,6 +2051,9 @@ static int ufshcd_hba_enable(struct ufs_hba *hba)
msleep(5);
}
 
+   /* enable UIC related interrupts */
+   ufshcd_enable_intr(hba, UIC_COMMAND_COMPL);
+
if (hba-vops  hba-vops-hce_enable_notify)
hba-vops-hce_enable_notify(hba, POST_CHANGE);
 
@@ -2058,23 +2069,33 @@ static int ufshcd_hba_enable(struct ufs_hba *hba)
 static int ufshcd_link_startup(struct ufs_hba *hba)
 {
int ret;
+   int retries = DME_LINKSTARTUP_RETRIES;
 
-   /* enable UIC related interrupts */
-   ufshcd_enable_intr(hba, UIC_COMMAND_COMPL);
+   do {
+   if (hba-vops  hba-vops-link_startup_notify)
+   hba-vops-link_startup_notify(hba, PRE_CHANGE);
 
-   if (hba-vops  hba-vops-link_startup_notify)
-   hba-vops-link_startup_notify(hba, PRE_CHANGE);
+   ret = ufshcd_dme_link_startup(hba);
 
-   ret = ufshcd_dme_link_startup(hba);
-   if (ret)
-   goto out;
+   /* check if device is detected by inter-connect layer */
+   if (!ret  !ufshcd_is_device_present(hba)) {
+   dev_err(hba-dev, %s: Device not present\n, __func__);
+   ret = -ENXIO;
+   goto out;
+   }
 
-   /* check if device is detected by inter-connect layer */
-   if (!ufshcd_is_device_present(hba)) {
-   dev_err(hba-dev, %s: Device not present\n, __func__);
-   ret = -ENXIO;
+   /*
+* DME link lost indication is only received when link is up,
+* but we can't be sure if the link is up until link startup
+* succeeds. So reset the local Uni-Pro and try again.
+*/
+   if (ret  ufshcd_hba_enable(hba))
+   goto out;
+   } while (ret  retries--);
+
+   if (ret)
+   /* failed to get the link up... retire */
goto out;
-   }
 
/* Include any host controller configuration via UIC commands */
if (hba-vops  hba-vops-link_startup_notify) {
@@ -3139,7 +3160,6 @@ out:
 static int ufshcd_host_reset_and_restore(struct ufs_hba *hba)
 {
int err;
-   async_cookie_t cookie;
unsigned long flags;
 
/* Reset the host controller */
@@ -3152,10 +3172,9 @@ static int ufshcd_host_reset_and_restore(struct ufs_hba 
*hba)
goto out;
 
/* Establish the link again and restore the device */
-   cookie = async_schedule(ufshcd_async_scan, hba);
-   /* wait for async scan to be completed */
-   async_synchronize_cookie(++cookie);
-   if (hba-ufshcd_state != UFSHCD_STATE_OPERATIONAL)
+   err = ufshcd_probe_hba(hba);
+
+   if (!err  (hba-ufshcd_state != UFSHCD_STATE_OPERATIONAL))
err = -EIO;
 out

[PATCH V6 12/18] scsi: ufs: add UFS power management support

2014-09-25 Thread Dolev Raviv
From: Subhash Jadavani subha...@codeaurora.org

This patch adds support for UFS device and UniPro link power management
during runtime/system PM.

Main idea is to define multiple UFS low power levels based on UFS device
and UFS link power states. This would allow any specific platform or pci
driver to choose the best suited low power level during runtime and
system suspend based on their power goals.

bkops handlig:
To put the UFS device in sleep state when bkops is disabled, first query
the bkops status from the device and enable bkops on device only if
device needs time to perform the bkops.

START_STOP handling:
Before sending START_STOP_UNIT to the device well-known logical unit
(w-lun) to make sure that the device w-lun unit attention condition is
cleared.

Write protection:
UFS device specification allows LUs to be write protected, either
permanently or power on write protected. If any LU is power on write
protected and if the card is power cycled (by powering off VCCQ and/or
VCC rails), LU's write protect status would be lost. So this means those
LUs can be written now. To ensures that UFS device is power cycled only
if the power on protect is not set for any of the LUs, check if power on
write protect is set and if device is in sleep/power-off state  link in
inactive state (Hibern8 or OFF state).
If none of the Logical Units on UFS device is power on write protected
then all UFS device power rails (VCC, VCCQ  VCCQ2) can be turned off if
UFS device is in power-off state and UFS link is in OFF state. But current
implementation would disable all device power rails even if UFS link is
not in OFF state.

Low power mode:
If UFS link is in OFF state then UFS host controller can be power collapsed
to avoid leakage current from it. Note that if UFS host controller is power
collapsed, full UFS reinitialization will be required on resume to
re-establish the link between host and device.

Signed-off-by: Subhash Jadavani subha...@codeaurora.org
Signed-off-by: Dolev Raviv dra...@codeaurora.org
Signed-off-by: Sujit Reddy Thumma sthu...@codeaurora.org

diff --git a/drivers/scsi/ufs/ufs.h b/drivers/scsi/ufs/ufs.h
index 37d64c1..42c459a 100644
--- a/drivers/scsi/ufs/ufs.h
+++ b/drivers/scsi/ufs/ufs.h
@@ -129,6 +129,7 @@ enum {
 /* Flag idn for Query Requests*/
 enum flag_idn {
QUERY_FLAG_IDN_FDEVICEINIT  = 0x01,
+   QUERY_FLAG_IDN_PWR_ON_WPE   = 0x03,
QUERY_FLAG_IDN_BKOPS_EN = 0x04,
 };
 
@@ -194,6 +195,18 @@ enum unit_desc_param {
UNIT_DESC_PARAM_LARGE_UNIT_SIZE_M1  = 0x22,
 };
 
+/*
+ * Logical Unit Write Protect
+ * 00h: LU not write protected
+ * 01h: LU write protected when fPowerOnWPEn =1
+ * 02h: LU permanently write protected when fPermanentWPEn =1
+ */
+enum ufs_lu_wp_type {
+   UFS_LU_NO_WP= 0x00,
+   UFS_LU_POWER_ON_WP  = 0x01,
+   UFS_LU_PERM_WP  = 0x02,
+};
+
 /* bActiveICCLevel parameter current units */
 enum {
UFSHCD_NANO_AMP = 0,
@@ -226,11 +239,12 @@ enum {
 };
 
 /* Background operation status */
-enum {
+enum bkops_status {
BKOPS_STATUS_NO_OP   = 0x0,
BKOPS_STATUS_NON_CRITICAL= 0x1,
BKOPS_STATUS_PERF_IMPACT = 0x2,
BKOPS_STATUS_CRITICAL= 0x3,
+   BKOPS_STATUS_MAX = BKOPS_STATUS_CRITICAL,
 };
 
 /* UTP QUERY Transaction Specific Fields OpCode */
@@ -291,6 +305,14 @@ enum {
UPIU_TASK_MANAGEMENT_FUNC_FAILED= 0x05,
UPIU_INCORRECT_LOGICAL_UNIT_NO  = 0x09,
 };
+
+/* UFS device power modes */
+enum ufs_dev_pwr_mode {
+   UFS_ACTIVE_PWR_MODE = 1,
+   UFS_SLEEP_PWR_MODE  = 2,
+   UFS_POWERDOWN_PWR_MODE  = 3,
+};
+
 /**
  * struct utp_upiu_header - UPIU header structure
  * @dword_0: UPIU header DW-0
@@ -437,6 +459,12 @@ struct ufs_query_res {
 #define UFS_VREG_VCCQ2_MIN_UV 165 /* uV */
 #define UFS_VREG_VCCQ2_MAX_UV 195 /* uV */
 
+/*
+ * VCCQ  VCCQ2 current requirement when UFS device is in sleep state
+ * and link is in Hibern8 state.
+ */
+#define UFS_VREG_LPM_LOAD_UA   1000 /* uA */
+
 struct ufs_vreg {
struct regulator *reg;
const char *name;
@@ -454,4 +482,10 @@ struct ufs_vreg_info {
struct ufs_vreg *vdd_hba;
 };
 
+struct ufs_dev_info {
+   bool f_power_on_wp_en;
+   /* Keeps information if any of the LU is power on write protected */
+   bool is_lu_power_on_wp;
+};
+
 #endif /* End of Header */
diff --git a/drivers/scsi/ufs/ufshcd-pci.c b/drivers/scsi/ufs/ufshcd-pci.c
index 2a26faa..955ed55 100644
--- a/drivers/scsi/ufs/ufshcd-pci.c
+++ b/drivers/scsi/ufs/ufshcd-pci.c
@@ -43,34 +43,24 @@
  * @pdev: pointer to PCI device handle
  * @state: power state
  *
- * Returns -ENOSYS
+ * Returns 0 if successful
+ * Returns non-zero otherwise
  */
 static int ufshcd_pci_suspend(struct device *dev)
 {
-   /*
-* TODO:
-* 1. Call ufshcd_suspend
-* 2. Do bus specific power management

[PATCH V6 11/18] scsi: ufs: introduce well known logical unit in ufs

2014-09-25 Thread Dolev Raviv
From: Subhash Jadavani subha...@codeaurora.org

UFS device may have standard LUs and LUN id could be from 0x00 to 0x7F.
UFS device specification use Peripheral Device Addressing Format
(SCSI SAM-5) for standard LUs.

UFS device may also have the Well Known LUs (also referred as W-LU) which
again could be from 0x00 to 0x7F. For W-LUs, UFS device specification only
allows the Extended Addressing Format (SCSI SAM-5) which means the W-LUNs
would start from 0xC100 onwards.

This means max. LUN number reported from UFS device could be 0xC17F hence
this patch advertise the max_lun as 0xC17F which will allow SCSI mid
layer to detect the W-LUs as well.

But once the W-LUs are detected, UFSHCD driver may get the commands with
SCSI LUN id upto 0xC17F but UPIU LUN id field is only 8-bit wide so it
requires the mapping of SCSI LUN id to UPIU LUN id. This patch also add
support for this mapping.

Signed-off-by: Subhash Jadavani subha...@codeaurora.org
Signed-off-by: Dolev Raviv dra...@codeaurora.org
Signed-off-by: Sujit Reddy Thumma sthu...@codeaurora.org

diff --git a/drivers/scsi/ufs/ufs.h b/drivers/scsi/ufs/ufs.h
index 4ca99ed..37d64c1 100644
--- a/drivers/scsi/ufs/ufs.h
+++ b/drivers/scsi/ufs/ufs.h
@@ -49,9 +49,28 @@
 #define UPIU_HEADER_DWORD(byte3, byte2, byte1, byte0)\
cpu_to_be32((byte3  24) | (byte2  16) |\
 (byte1  8) | (byte0))
-
+/*
+ * UFS device may have standard LUs and LUN id could be from 0x00 to
+ * 0x7F. Standard LUs use Peripheral Device Addressing Format.
+ * UFS device may also have the Well Known LUs (also referred as W-LU)
+ * which again could be from 0x00 to 0x7F. For W-LUs, device only use
+ * the Extended Addressing Format which means the W-LUNs would be
+ * from 0xc100 (SCSI_W_LUN_BASE) onwards.
+ * This means max. LUN number reported from UFS device could be 0xC17F.
+ */
+#define UFS_UPIU_MAX_UNIT_NUM_ID   0x7F
+#define UFS_MAX_LUNS   (SCSI_W_LUN_BASE + UFS_UPIU_MAX_UNIT_NUM_ID)
+#define UFS_UPIU_WLUN_ID   (1  7)
 #define UFS_UPIU_MAX_GENERAL_LUN   8
 
+/* Well known logical unit id in LUN field of UPIU */
+enum {
+   UFS_UPIU_REPORT_LUNS_WLUN   = 0x81,
+   UFS_UPIU_UFS_DEVICE_WLUN= 0xD0,
+   UFS_UPIU_BOOT_WLUN  = 0xB0,
+   UFS_UPIU_RPMB_WLUN  = 0xC4,
+};
+
 /*
  * UFS Protocol Information Unit related definitions
  */
diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index 692fd7a..a1eae49 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -100,7 +100,6 @@ static u32 ufs_query_desc_max_size[] = {
 enum {
UFSHCD_MAX_CHANNEL  = 0,
UFSHCD_MAX_ID   = 1,
-   UFSHCD_MAX_LUNS = 8,
UFSHCD_CMD_PER_LUN  = 32,
UFSHCD_CAN_QUEUE= 32,
 };
@@ -901,6 +900,21 @@ static int ufshcd_compose_upiu(struct ufs_hba *hba, struct 
ufshcd_lrb *lrbp)
return ret;
 }
 
+/*
+ * ufshcd_scsi_to_upiu_lun - maps scsi LUN to UPIU LUN
+ * @scsi_lun: scsi LUN id
+ *
+ * Returns UPIU LUN id
+ */
+static inline u8 ufshcd_scsi_to_upiu_lun(unsigned int scsi_lun)
+{
+   if (scsi_is_wlun(scsi_lun))
+   return (scsi_lun  UFS_UPIU_MAX_UNIT_NUM_ID)
+   | UFS_UPIU_WLUN_ID;
+   else
+   return scsi_lun  UFS_UPIU_MAX_UNIT_NUM_ID;
+}
+
 /**
  * ufshcd_upiu_wlun_to_scsi_wlun - maps UPIU W-LUN id to SCSI W-LUN ID
  * @scsi_lun: UPIU W-LUN id
@@ -970,7 +984,7 @@ static int ufshcd_queuecommand(struct Scsi_Host *host, 
struct scsi_cmnd *cmd)
lrbp-sense_bufflen = SCSI_SENSE_BUFFERSIZE;
lrbp-sense_buffer = cmd-sense_buffer;
lrbp-task_tag = tag;
-   lrbp-lun = cmd-device-lun;
+   lrbp-lun = ufshcd_scsi_to_upiu_lun(cmd-device-lun);
lrbp-intr_cmd = false;
lrbp-command_type = UTP_CMD_TYPE_SCSI;
 
@@ -1524,7 +1538,7 @@ static inline int ufshcd_read_unit_desc_param(struct 
ufs_hba *hba,
 * Unit descriptors are only available for general purpose LUs (LUN id
 * from 0 to 7) and RPMB Well known LU.
 */
-   if (lun = UFS_UPIU_MAX_GENERAL_LUN)
+   if (lun != UFS_UPIU_RPMB_WLUN  (lun = UFS_UPIU_MAX_GENERAL_LUN))
return -EOPNOTSUPP;
 
return ufshcd_read_desc_param(hba, QUERY_DESC_IDN_UNIT, lun,
@@ -2155,6 +2169,44 @@ static int ufshcd_verify_dev_init(struct ufs_hba *hba)
 }
 
 /**
+ * ufshcd_set_queue_depth - set lun queue depth
+ * @sdev: pointer to SCSI device
+ *
+ * Read bLUQueueDepth value and activate scsi tagged command
+ * queueing. For WLUN, queue depth is set to 1. For best-effort
+ * cases (bLUQueueDepth = 0) the queue depth is set to a maximum
+ * value that host can queue.
+ */
+static void ufshcd_set_queue_depth(struct scsi_device *sdev)
+{
+   int ret = 0;
+   u8 lun_qdepth;
+   struct ufs_hba *hba;
+
+   hba = shost_priv(sdev-host);
+
+   lun_qdepth = hba-nutrs;
+   ret = ufshcd_read_unit_desc_param(hba

[PATCH/RESEND V6 09/18] scsi: ufs: Active Power Mode - configuring bActiveICCLevel

2014-09-25 Thread Dolev Raviv
From: Yaniv Gardi yga...@codeaurora.org

The maximum power consumption in active is determined by bActiveICCLevel.
The configuration is done by reading max current supported by the
regulators connected to VCC, VCCQ and VCCQ2 rails on the boards, and
reading the current consumption levels from the device for each rails
(vcc/vccq/vccq2) using power descriptor.
We configure the bActiveICCLevel attribute, with the max value that
correspond to the minimum-of(VCC-current-level,VCCQ-current-level,
VCCQ2-current-level).
In order to minimize resume latency, pre-fetch icc levels and reference
clock during initialization and avoid reading them each link startup
during resume.

Signed-off-by: Raviv Shvili rshv...@codeaurora.org
Signed-off-by: Yaniv Gardi yga...@codeaurora.org
Signed-off-by: Dolev Raviv dra...@codeaurora.org

diff --git a/drivers/scsi/ufs/ufs.h b/drivers/scsi/ufs/ufs.h
index f76a304..4ca99ed 100644
--- a/drivers/scsi/ufs/ufs.h
+++ b/drivers/scsi/ufs/ufs.h
@@ -115,6 +115,7 @@ enum flag_idn {
 
 /* Attribute idn for Query requests */
 enum attr_idn {
+   QUERY_ATTR_IDN_ACTIVE_ICC_LVL   = 0x03,
QUERY_ATTR_IDN_BKOPS_STATUS = 0x05,
QUERY_ATTR_IDN_EE_CONTROL   = 0x0D,
QUERY_ATTR_IDN_EE_STATUS= 0x0E,
@@ -174,6 +175,31 @@ enum unit_desc_param {
UNIT_DESC_PARAM_LARGE_UNIT_SIZE_M1  = 0x22,
 };
 
+/* bActiveICCLevel parameter current units */
+enum {
+   UFSHCD_NANO_AMP = 0,
+   UFSHCD_MICRO_AMP= 1,
+   UFSHCD_MILI_AMP = 2,
+   UFSHCD_AMP  = 3,
+};
+
+#define POWER_DESC_MAX_SIZE0x62
+#define POWER_DESC_MAX_ACTV_ICC_LVLS   16
+
+/* Attribute  bActiveICCLevel parameter bit masks definitions */
+#define ATTR_ICC_LVL_UNIT_OFFSET   14
+#define ATTR_ICC_LVL_UNIT_MASK (0x3  ATTR_ICC_LVL_UNIT_OFFSET)
+#define ATTR_ICC_LVL_VALUE_MASK0x3FF
+
+/* Power descriptor parameters offsets in bytes */
+enum power_desc_param_offset {
+   PWR_DESC_LEN= 0x0,
+   PWR_DESC_TYPE   = 0x1,
+   PWR_DESC_ACTIVE_LVLS_VCC_0  = 0x2,
+   PWR_DESC_ACTIVE_LVLS_VCCQ_0 = 0x22,
+   PWR_DESC_ACTIVE_LVLS_VCCQ2_0= 0x42,
+};
+
 /* Exception event mask values */
 enum {
MASK_EE_STATUS  = 0x,
diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index af29d4c..dc89c48 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -3265,6 +3265,125 @@ static int ufshcd_eh_host_reset_handler(struct 
scsi_cmnd *cmd)
 }
 
 /**
+ * ufshcd_get_max_icc_level - calculate the ICC level
+ * @sup_curr_uA: max. current supported by the regulator
+ * @start_scan: row at the desc table to start scan from
+ * @buff: power descriptor buffer
+ *
+ * Returns calculated max ICC level for specific regulator
+ */
+static u32 ufshcd_get_max_icc_level(int sup_curr_uA, u32 start_scan, char 
*buff)
+{
+   int i;
+   int curr_uA;
+   u16 data;
+   u16 unit;
+
+   for (i = start_scan; i = 0; i--) {
+   data = be16_to_cpu(*((u16 *)(buff + 2*i)));
+   unit = (data  ATTR_ICC_LVL_UNIT_MASK) 
+   ATTR_ICC_LVL_UNIT_OFFSET;
+   curr_uA = data  ATTR_ICC_LVL_VALUE_MASK;
+   switch (unit) {
+   case UFSHCD_NANO_AMP:
+   curr_uA = curr_uA / 1000;
+   break;
+   case UFSHCD_MILI_AMP:
+   curr_uA = curr_uA * 1000;
+   break;
+   case UFSHCD_AMP:
+   curr_uA = curr_uA * 1000 * 1000;
+   break;
+   case UFSHCD_MICRO_AMP:
+   default:
+   break;
+   }
+   if (sup_curr_uA = curr_uA)
+   break;
+   }
+   if (i  0) {
+   i = 0;
+   pr_err(%s: Couldn't find valid icc_level = %d, __func__, i);
+   }
+
+   return (u32)i;
+}
+
+/**
+ * ufshcd_calc_icc_level - calculate the max ICC level
+ * In case regulators are not initialized we'll return 0
+ * @hba: per-adapter instance
+ * @desc_buf: power descriptor buffer to extract ICC levels from.
+ * @len: length of desc_buff
+ *
+ * Returns calculated ICC level
+ */
+static u32 ufshcd_find_max_sup_active_icc_level(struct ufs_hba *hba,
+   u8 *desc_buf, int len)
+{
+   u32 icc_level = 0;
+
+   if (!hba-vreg_info.vcc || !hba-vreg_info.vccq ||
+   !hba-vreg_info.vccq2) {
+   dev_err(hba-dev,
+   %s: Regulator capability was not set, actvIccLevel=%d,
+   __func__, icc_level);
+   goto out;
+   }
+
+   if (hba-vreg_info.vcc)
+   icc_level = ufshcd_get_max_icc_level

[PATCH/RESEND V6 16/18] scsi: ufs: Add support for clock scaling using devfreq framework

2014-09-25 Thread Dolev Raviv
From: Sahitya Tummala stumm...@codeaurora.org

The clocks for UFS device will be managed by generic DVFS (Dynamic
Voltage and Frequency Scaling) framework within kernel. This devfreq
framework works with different governors to scale the clocks. By default,
UFS devices uses simple_ondemand governor which scales the clocks up if
the load is more than upthreshold and scales down if the load is less than
downthreshold.

Signed-off-by: Sahitya Tummala stumm...@codeaurora.org
Signed-off-by: Dolev Raviv dra...@codeaurora.org

diff --git a/drivers/scsi/ufs/Kconfig b/drivers/scsi/ufs/Kconfig
index f07f901..6e07b2a 100644
--- a/drivers/scsi/ufs/Kconfig
+++ b/drivers/scsi/ufs/Kconfig
@@ -35,6 +35,8 @@
 config SCSI_UFSHCD
tristate Universal Flash Storage Controller Driver Core
depends on SCSI  SCSI_DMA
+   select PM_DEVFREQ
+   select DEVFREQ_GOV_SIMPLE_ONDEMAND
---help---
This selects the support for UFS devices in Linux, say Y and make
  sure that you know the name of your UFS host adapter (the card
diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index fe3511e..1679cbfb 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -38,6 +38,7 @@
  */
 
 #include linux/async.h
+#include linux/devfreq.h
 
 #include ufshcd.h
 #include unipro.h
@@ -545,6 +546,8 @@ static void ufshcd_ungate_work(struct work_struct *work)
hba-clk_gating.is_suspended = false;
}
 unblock_reqs:
+   if (ufshcd_is_clkscaling_enabled(hba))
+   devfreq_resume_device(hba-devfreq);
scsi_unblock_requests(hba-host);
 }
 
@@ -561,10 +564,10 @@ int ufshcd_hold(struct ufs_hba *hba, bool async)
 
if (!ufshcd_is_clkgating_allowed(hba))
goto out;
-start:
spin_lock_irqsave(hba-host-host_lock, flags);
hba-clk_gating.active_reqs++;
 
+start:
switch (hba-clk_gating.state) {
case CLKS_ON:
break;
@@ -596,6 +599,7 @@ start:
spin_unlock_irqrestore(hba-host-host_lock, flags);
flush_work(hba-clk_gating.ungate_work);
/* Make sure state is CLKS_ON before returning */
+   spin_lock_irqsave(hba-host-host_lock, flags);
goto start;
default:
dev_err(hba-dev, %s: clk gating is in invalid state %d\n,
@@ -636,6 +640,11 @@ static void ufshcd_gate_work(struct work_struct *work)
ufshcd_set_link_hibern8(hba);
}
 
+   if (ufshcd_is_clkscaling_enabled(hba)) {
+   devfreq_suspend_device(hba-devfreq);
+   hba-clk_scaling.window_start_t = 0;
+   }
+
if (!ufshcd_is_link_active(hba))
ufshcd_setup_clocks(hba, false);
else
@@ -737,6 +746,32 @@ static void ufshcd_exit_clk_gating(struct ufs_hba *hba)
device_remove_file(hba-dev, hba-clk_gating.delay_attr);
 }
 
+/* Must be called with host lock acquired */
+static void ufshcd_clk_scaling_start_busy(struct ufs_hba *hba)
+{
+   if (!ufshcd_is_clkscaling_enabled(hba))
+   return;
+
+   if (!hba-clk_scaling.is_busy_started) {
+   hba-clk_scaling.busy_start_t = ktime_get();
+   hba-clk_scaling.is_busy_started = true;
+   }
+}
+
+static void ufshcd_clk_scaling_update_busy(struct ufs_hba *hba)
+{
+   struct ufs_clk_scaling *scaling = hba-clk_scaling;
+
+   if (!ufshcd_is_clkscaling_enabled(hba))
+   return;
+
+   if (!hba-outstanding_reqs  scaling-is_busy_started) {
+   scaling-tot_busy_t += ktime_to_us(ktime_sub(ktime_get(),
+   scaling-busy_start_t));
+   scaling-busy_start_t = ktime_set(0, 0);
+   scaling-is_busy_started = false;
+   }
+}
 /**
  * ufshcd_send_command - Send SCSI or device management commands
  * @hba: per adapter instance
@@ -745,6 +780,7 @@ static void ufshcd_exit_clk_gating(struct ufs_hba *hba)
 static inline
 void ufshcd_send_command(struct ufs_hba *hba, unsigned int task_tag)
 {
+   ufshcd_clk_scaling_start_busy(hba);
__set_bit(task_tag, hba-outstanding_reqs);
ufshcd_writel(hba, 1  task_tag, REG_UTP_TRANSFER_REQ_DOOR_BELL);
 }
@@ -3027,6 +3063,8 @@ static void ufshcd_transfer_req_compl(struct ufs_hba *hba)
/* clear corresponding bits of completed commands */
hba-outstanding_reqs ^= completed_reqs;
 
+   ufshcd_clk_scaling_update_busy(hba);
+
/* we might have free'd some tags above */
wake_up(hba-dev_cmd.tag_wq);
 }
@@ -4151,6 +4189,10 @@ static int ufshcd_probe_hba(struct ufs_hba *hba)
if (!hba-is_init_prefetch)
hba-is_init_prefetch = true;
 
+   /* Resume devfreq after UFS device is detected */
+   if (ufshcd_is_clkscaling_enabled(hba))
+   devfreq_resume_device(hba-devfreq);
+
 out:
/*
 * If we failed to initialize the device or the device is not
@@ -4472,6 +4514,7 @@ static

[PATCH V6 10/18] scsi: ufs: manually add well known logical units

2014-09-25 Thread Dolev Raviv
From: Subhash Jadavani subha...@codeaurora.org

UFS device specification requires the UFS devices to support 4 well known
logical units:
REPORT_LUNS (address: 01h)
UFS Device (address: 50h)
RPMB (address: 44h)
BOOT (address: 30h)

UFS device's power management needs to be controlled by POWER CONDITION
field of SSU (START STOP UNIT) command. But this power condition field
will take effect only when its sent to UFS device well known logical unit
hence we require the scsi_device instance to represent this logical unit in
order for the UFS host driver to send the SSU command for power management.

We also require the scsi_device instance for RPMB (Replay Protected
Memory Block) LU so user space process can control this LU. User space may
also want to have access to BOOT LU.

This patch adds the scsi device instances for each of all well known LUs
(except REPORT LUNS LU).

Signed-off-by: Subhash Jadavani subha...@codeaurora.org
Signed-off-by: Dolev Raviv dra...@codeaurora.org

diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index dc89c48..692fd7a 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -902,6 +902,17 @@ static int ufshcd_compose_upiu(struct ufs_hba *hba, struct 
ufshcd_lrb *lrbp)
 }
 
 /**
+ * ufshcd_upiu_wlun_to_scsi_wlun - maps UPIU W-LUN id to SCSI W-LUN ID
+ * @scsi_lun: UPIU W-LUN id
+ *
+ * Returns SCSI W-LUN id
+ */
+static inline u16 ufshcd_upiu_wlun_to_scsi_wlun(u8 upiu_wlun_id)
+{
+   return (upiu_wlun_id  ~UFS_UPIU_WLUN_ID) | SCSI_W_LUN_BASE;
+}
+
+/**
  * ufshcd_queuecommand - main entry point for SCSI requests
  * @cmd: command from SCSI Midlayer
  * @done: call back function
@@ -3384,6 +3395,93 @@ static void ufshcd_init_icc_levels(struct ufs_hba *hba)
 }
 
 /**
+ * ufshcd_scsi_add_wlus - Adds required W-LUs
+ * @hba: per-adapter instance
+ *
+ * UFS device specification requires the UFS devices to support 4 well known
+ * logical units:
+ * REPORT_LUNS (address: 01h)
+ * UFS Device (address: 50h)
+ * RPMB (address: 44h)
+ * BOOT (address: 30h)
+ * UFS device's power management needs to be controlled by POWER CONDITION
+ * field of SSU (START STOP UNIT) command. But this power condition field
+ * will take effect only when its sent to UFS device well known logical unit
+ * hence we require the scsi_device instance to represent this logical unit in
+ * order for the UFS host driver to send the SSU command for power management.
+
+ * We also require the scsi_device instance for RPMB (Replay Protected Memory
+ * Block) LU so user space process can control this LU. User space may also
+ * want to have access to BOOT LU.
+
+ * This function adds scsi device instances for each of all well known LUs
+ * (except REPORT LUNS LU).
+ *
+ * Returns zero on success (all required W-LUs are added successfully),
+ * non-zero error value on failure (if failed to add any of the required W-LU).
+ */
+static int ufshcd_scsi_add_wlus(struct ufs_hba *hba)
+{
+   int ret = 0;
+
+   hba-sdev_ufs_device = __scsi_add_device(hba-host, 0, 0,
+   ufshcd_upiu_wlun_to_scsi_wlun(UFS_UPIU_UFS_DEVICE_WLUN), NULL);
+   if (IS_ERR(hba-sdev_ufs_device)) {
+   ret = PTR_ERR(hba-sdev_ufs_device);
+   hba-sdev_ufs_device = NULL;
+   goto out;
+   }
+
+   hba-sdev_boot = __scsi_add_device(hba-host, 0, 0,
+   ufshcd_upiu_wlun_to_scsi_wlun(UFS_UPIU_BOOT_WLUN), NULL);
+   if (IS_ERR(hba-sdev_boot)) {
+   ret = PTR_ERR(hba-sdev_boot);
+   hba-sdev_boot = NULL;
+   goto remove_sdev_ufs_device;
+   }
+
+   hba-sdev_rpmb = __scsi_add_device(hba-host, 0, 0,
+   ufshcd_upiu_wlun_to_scsi_wlun(UFS_UPIU_RPMB_WLUN), NULL);
+   if (IS_ERR(hba-sdev_rpmb)) {
+   ret = PTR_ERR(hba-sdev_rpmb);
+   hba-sdev_rpmb = NULL;
+   goto remove_sdev_boot;
+   }
+   goto out;
+
+remove_sdev_boot:
+   scsi_remove_device(hba-sdev_boot);
+remove_sdev_ufs_device:
+   scsi_remove_device(hba-sdev_ufs_device);
+out:
+   return ret;
+}
+
+/**
+ * ufshcd_scsi_remove_wlus - Removes the W-LUs which were added by
+ *  ufshcd_scsi_add_wlus()
+ * @hba: per-adapter instance
+ *
+ */
+static void ufshcd_scsi_remove_wlus(struct ufs_hba *hba)
+{
+   if (hba-sdev_ufs_device) {
+   scsi_remove_device(hba-sdev_ufs_device);
+   hba-sdev_ufs_device = NULL;
+   }
+
+   if (hba-sdev_boot) {
+   scsi_remove_device(hba-sdev_boot);
+   hba-sdev_boot = NULL;
+   }
+
+   if (hba-sdev_rpmb) {
+   scsi_remove_device(hba-sdev_rpmb);
+   hba-sdev_rpmb = NULL;
+   }
+}
+
+/**
  * ufshcd_probe_hba - probe hba to detect device and initialize
  * @hba: per-adapter instance
  *
@@ -3415,6 +3513,10 @@ static int ufshcd_probe_hba(struct ufs_hba *hba)
if (!hba

[PATCH/RESEND V5 14/17] scsi: ufs: Add freq-table-hz property for UFS device

2014-09-24 Thread Dolev Raviv
From: Sahitya Tummala stumm...@codeaurora.org

Add freq-table-hz propery for UFS device to keep track of
min max frequencies supported by UFS clocks.

Signed-off-by: Sahitya Tummala stumm...@codeaurora.org
Signed-off-by: Dolev Raviv dra...@codeaurora.org

diff --git a/Documentation/devicetree/bindings/ufs/ufshcd-pltfrm.txt 
b/Documentation/devicetree/bindings/ufs/ufshcd-pltfrm.txt
index fb1234e..5357919 100644
--- a/Documentation/devicetree/bindings/ufs/ufshcd-pltfrm.txt
+++ b/Documentation/devicetree/bindings/ufs/ufshcd-pltfrm.txt
@@ -26,11 +26,11 @@ Optional properties:
 - clocks: List of phandle and clock specifier pairs
 - clock-names   : List of clock input name strings sorted in the same
   order as the clocks property.
-- max-clock-frequency-hz : List of maximum operating frequency stored in the 
same
-   order as the clocks property. If this property is 
not
-  defined or a value in the array is 0 then it is 
assumed
-  that the frequency is set by the parent clock or a
-  fixed rate clock source.
+- freq-table-hz: Array of min max operating frequencies 
stored in the same
+  order as the clocks property. If this property is not
+ defined or a value in the array is 0 then it is 
assumed
+ that the frequency is set by the parent clock or a
+ fixed rate clock source.
 
 Note: If above properties are not defined it can be assumed that the supply
 regulators or clocks are always on.
@@ -53,5 +53,5 @@ Example:
 
clocks = core 0, ref 0, iface 0;
clock-names = core_clk, ref_clk, iface_clk;
-   max-clock-frequency-hz = 1 1920 0;
+   freq-table-hz = 1 2, 0 0, 0 0;
};
diff --git a/drivers/scsi/ufs/ufshcd-pltfrm.c b/drivers/scsi/ufs/ufshcd-pltfrm.c
index 2482bba..8adf067 100644
--- a/drivers/scsi/ufs/ufshcd-pltfrm.c
+++ b/drivers/scsi/ufs/ufshcd-pltfrm.c
@@ -63,6 +63,8 @@ static int ufshcd_parse_clock_info(struct ufs_hba *hba)
char *name;
u32 *clkfreq = NULL;
struct ufs_clk_info *clki;
+   int len = 0;
+   size_t sz = 0;
 
if (!np)
goto out;
@@ -82,39 +84,59 @@ static int ufshcd_parse_clock_info(struct ufs_hba *hba)
if (cnt = 0)
goto out;
 
-   clkfreq = kzalloc(cnt * sizeof(*clkfreq), GFP_KERNEL);
+   if (!of_get_property(np, freq-table-hz, len)) {
+   dev_info(dev, freq-table-hz property not specified\n);
+   goto out;
+   }
+
+   if (len = 0)
+   goto out;
+
+   sz = len / sizeof(*clkfreq);
+   if (sz != 2 * cnt) {
+   dev_err(dev, %s len mismatch\n, freq-table-hz);
+   ret = -EINVAL;
+   goto out;
+   }
+
+   clkfreq = devm_kzalloc(dev, sz * sizeof(*clkfreq),
+   GFP_KERNEL);
if (!clkfreq) {
+   dev_err(dev, %s: no memory\n, freq-table-hz);
ret = -ENOMEM;
-   dev_err(dev, %s: memory alloc failed\n, __func__);
goto out;
}
 
-   ret = of_property_read_u32_array(np,
-   max-clock-frequency-hz, clkfreq, cnt);
+   ret = of_property_read_u32_array(np, freq-table-hz,
+   clkfreq, sz);
if (ret  (ret != -EINVAL)) {
-   dev_err(dev, %s: invalid max-clock-frequency-hz property, 
%d\n,
-   __func__, ret);
-   goto out;
+   dev_err(dev, %s: error reading array %d\n,
+   freq-table-hz, ret);
+   goto free_clkfreq;
}
 
-   for (i = 0; i  cnt; i++) {
+   for (i = 0; i  sz; i += 2) {
ret = of_property_read_string_index(np,
-   clock-names, i, (const char **)name);
+   clock-names, i/2, (const char **)name);
if (ret)
-   goto out;
+   goto free_clkfreq;
 
clki = devm_kzalloc(dev, sizeof(*clki), GFP_KERNEL);
if (!clki) {
ret = -ENOMEM;
-   goto out;
+   goto free_clkfreq;
}
 
-   clki-max_freq = clkfreq[i];
+   clki-min_freq = clkfreq[i];
+   clki-max_freq = clkfreq[i+1];
clki-name = kstrdup(name, GFP_KERNEL);
+   dev_dbg(dev, %s: min %u max %u name %s\n, freq-table-hz,
+   clki-min_freq, clki-max_freq, clki-name);
list_add_tail(clki-list, hba-clk_list_head);
}
-out:
+free_clkfreq:
kfree(clkfreq);
+out:
return ret;
 }
 
diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi

[PATCH/RESEND V5 08/17] scsi: ufs: improve init sequence

2014-09-24 Thread Dolev Raviv
From: Sujit Reddy Thumma sthu...@codeaurora.org

In -hce_enable_notify() callback the vendor specific initialization
may carry out additional DME configuration using UIC commands and
hence the UIC command completion interrupt enable bit should be set
before the post reset notification.
Add retries if the link-startup fails. This is required since due to
hardware timing issues, the Uni-Pro link-startup might fail. The UFS
HCI recovery procedure contradicts the Uni-Pro sequence. The UFS HCI
specifies to resend DME_LINKSTARTUP command after IS.ULLS (link-lost
interrupt) is received. The Uni-Pro specifies that if link-startup
fails the link is in down state. The link-lost is indicated to the
DME user only when the link is up. Hence, the UFS HCI recovery procedure
of waiting for IS.ULLS and retrying link-startup may not work properly.

At the end, if detection fails, power off (disable clocks, regulators,
phy) if the UFS device detection fails. This saves power while UFS device
is not embedded into the system.

Signed-off-by: Sujit Reddy Thumma sthu...@codeaurora.org
Signed-off-by: Dolev Raviv dra...@codeaurora.org

diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index 3f2b30d..af29d4c 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -62,6 +62,12 @@
 /* Task management command timeout */
 #define TM_CMD_TIMEOUT 100 /* msecs */
 
+/* maximum number of link-startup retries */
+#define DME_LINKSTARTUP_RETRIES 3
+
+/* maximum number of reset retries before giving up */
+#define MAX_HOST_RESET_RETRIES 5
+
 /* Expose the flag value from utp_upiu_query.value */
 #define MASK_QUERY_UPIU_FLAG_LOC 0xFF
 
@@ -137,6 +143,8 @@ static void ufshcd_tmc_handler(struct ufs_hba *hba);
 static void ufshcd_async_scan(void *data, async_cookie_t cookie);
 static int ufshcd_reset_and_restore(struct ufs_hba *hba);
 static int ufshcd_clear_tm_cmd(struct ufs_hba *hba, int tag);
+static void ufshcd_hba_exit(struct ufs_hba *hba);
+static int ufshcd_probe_hba(struct ufs_hba *hba);
 
 /*
  * ufshcd_wait_for_register - wait for register value to change
@@ -2043,6 +2051,9 @@ static int ufshcd_hba_enable(struct ufs_hba *hba)
msleep(5);
}
 
+   /* enable UIC related interrupts */
+   ufshcd_enable_intr(hba, UIC_COMMAND_COMPL);
+
if (hba-vops  hba-vops-hce_enable_notify)
hba-vops-hce_enable_notify(hba, POST_CHANGE);
 
@@ -2058,23 +2069,33 @@ static int ufshcd_hba_enable(struct ufs_hba *hba)
 static int ufshcd_link_startup(struct ufs_hba *hba)
 {
int ret;
+   int retries = DME_LINKSTARTUP_RETRIES;
 
-   /* enable UIC related interrupts */
-   ufshcd_enable_intr(hba, UIC_COMMAND_COMPL);
+   do {
+   if (hba-vops  hba-vops-link_startup_notify)
+   hba-vops-link_startup_notify(hba, PRE_CHANGE);
 
-   if (hba-vops  hba-vops-link_startup_notify)
-   hba-vops-link_startup_notify(hba, PRE_CHANGE);
+   ret = ufshcd_dme_link_startup(hba);
 
-   ret = ufshcd_dme_link_startup(hba);
-   if (ret)
-   goto out;
+   /* check if device is detected by inter-connect layer */
+   if (!ret  !ufshcd_is_device_present(hba)) {
+   dev_err(hba-dev, %s: Device not present\n, __func__);
+   ret = -ENXIO;
+   goto out;
+   }
 
-   /* check if device is detected by inter-connect layer */
-   if (!ufshcd_is_device_present(hba)) {
-   dev_err(hba-dev, %s: Device not present\n, __func__);
-   ret = -ENXIO;
+   /*
+* DME link lost indication is only received when link is up,
+* but we can't be sure if the link is up until link startup
+* succeeds. So reset the local Uni-Pro and try again.
+*/
+   if (ret  ufshcd_hba_enable(hba))
+   goto out;
+   } while (ret  retries--);
+
+   if (ret)
+   /* failed to get the link up... retire */
goto out;
-   }
 
/* Include any host controller configuration via UIC commands */
if (hba-vops  hba-vops-link_startup_notify) {
@@ -3139,7 +3160,6 @@ out:
 static int ufshcd_host_reset_and_restore(struct ufs_hba *hba)
 {
int err;
-   async_cookie_t cookie;
unsigned long flags;
 
/* Reset the host controller */
@@ -3152,10 +3172,9 @@ static int ufshcd_host_reset_and_restore(struct ufs_hba 
*hba)
goto out;
 
/* Establish the link again and restore the device */
-   cookie = async_schedule(ufshcd_async_scan, hba);
-   /* wait for async scan to be completed */
-   async_synchronize_cookie(++cookie);
-   if (hba-ufshcd_state != UFSHCD_STATE_OPERATIONAL)
+   err = ufshcd_probe_hba(hba);
+
+   if (!err  (hba-ufshcd_state != UFSHCD_STATE_OPERATIONAL))
err = -EIO;
 out

[PATCH V5 11/17] scsi: ufs: add UFS power management support

2014-09-24 Thread Dolev Raviv
From: Subhash Jadavani subha...@codeaurora.org

This patch adds support for UFS device and UniPro link power management
during runtime/system PM.

Main idea is to define multiple UFS low power levels based on UFS device
and UFS link power states. This would allow any specific platform or pci
driver to choose the best suited low power level during runtime and
system suspend based on their power goals.

bkops handlig:
To put the UFS device in sleep state when bkops is disabled, first query
the bkops status from the device and enable bkops on device only if
device needs time to perform the bkops.

START_STOP handling:
Before sending START_STOP_UNIT to the device well-known logical unit
(w-lun) to make sure that the device w-lun unit attention condition is
cleared.

Write protection:
UFS device specification allows LUs to be write protected, either
permanently or power on write protected. If any LU is power on write
protected and if the card is power cycled (by powering off VCCQ and/or
VCC rails), LU's write protect status would be lost. So this means those
LUs can be written now. To ensures that UFS device is power cycled only
if the power on protect is not set for any of the LUs, check if power on
write protect is set and if device is in sleep/power-off state  link in
inactive state (Hibern8 or OFF state).
If none of the Logical Units on UFS device is power on write protected
then all UFS device power rails (VCC, VCCQ  VCCQ2) can be turned off if
UFS device is in power-off state and UFS link is in OFF state. But current
implementation would disable all device power rails even if UFS link is
not in OFF state.

Low power mode:
If UFS link is in OFF state then UFS host controller can be power collapsed
to avoid leakage current from it. Note that if UFS host controller is power
collapsed, full UFS reinitialization will be required on resume to
re-establish the link between host and device.

Signed-off-by: Subhash Jadavani subha...@codeaurora.org
Signed-off-by: Dolev Raviv dra...@codeaurora.org
Signed-off-by: Sujit Reddy Thumma sthu...@codeaurora.org

diff --git a/drivers/scsi/ufs/ufs.h b/drivers/scsi/ufs/ufs.h
index 37d64c1..42c459a 100644
--- a/drivers/scsi/ufs/ufs.h
+++ b/drivers/scsi/ufs/ufs.h
@@ -129,6 +129,7 @@ enum {
 /* Flag idn for Query Requests*/
 enum flag_idn {
QUERY_FLAG_IDN_FDEVICEINIT  = 0x01,
+   QUERY_FLAG_IDN_PWR_ON_WPE   = 0x03,
QUERY_FLAG_IDN_BKOPS_EN = 0x04,
 };
 
@@ -194,6 +195,18 @@ enum unit_desc_param {
UNIT_DESC_PARAM_LARGE_UNIT_SIZE_M1  = 0x22,
 };
 
+/*
+ * Logical Unit Write Protect
+ * 00h: LU not write protected
+ * 01h: LU write protected when fPowerOnWPEn =1
+ * 02h: LU permanently write protected when fPermanentWPEn =1
+ */
+enum ufs_lu_wp_type {
+   UFS_LU_NO_WP= 0x00,
+   UFS_LU_POWER_ON_WP  = 0x01,
+   UFS_LU_PERM_WP  = 0x02,
+};
+
 /* bActiveICCLevel parameter current units */
 enum {
UFSHCD_NANO_AMP = 0,
@@ -226,11 +239,12 @@ enum {
 };
 
 /* Background operation status */
-enum {
+enum bkops_status {
BKOPS_STATUS_NO_OP   = 0x0,
BKOPS_STATUS_NON_CRITICAL= 0x1,
BKOPS_STATUS_PERF_IMPACT = 0x2,
BKOPS_STATUS_CRITICAL= 0x3,
+   BKOPS_STATUS_MAX = BKOPS_STATUS_CRITICAL,
 };
 
 /* UTP QUERY Transaction Specific Fields OpCode */
@@ -291,6 +305,14 @@ enum {
UPIU_TASK_MANAGEMENT_FUNC_FAILED= 0x05,
UPIU_INCORRECT_LOGICAL_UNIT_NO  = 0x09,
 };
+
+/* UFS device power modes */
+enum ufs_dev_pwr_mode {
+   UFS_ACTIVE_PWR_MODE = 1,
+   UFS_SLEEP_PWR_MODE  = 2,
+   UFS_POWERDOWN_PWR_MODE  = 3,
+};
+
 /**
  * struct utp_upiu_header - UPIU header structure
  * @dword_0: UPIU header DW-0
@@ -437,6 +459,12 @@ struct ufs_query_res {
 #define UFS_VREG_VCCQ2_MIN_UV 165 /* uV */
 #define UFS_VREG_VCCQ2_MAX_UV 195 /* uV */
 
+/*
+ * VCCQ  VCCQ2 current requirement when UFS device is in sleep state
+ * and link is in Hibern8 state.
+ */
+#define UFS_VREG_LPM_LOAD_UA   1000 /* uA */
+
 struct ufs_vreg {
struct regulator *reg;
const char *name;
@@ -454,4 +482,10 @@ struct ufs_vreg_info {
struct ufs_vreg *vdd_hba;
 };
 
+struct ufs_dev_info {
+   bool f_power_on_wp_en;
+   /* Keeps information if any of the LU is power on write protected */
+   bool is_lu_power_on_wp;
+};
+
 #endif /* End of Header */
diff --git a/drivers/scsi/ufs/ufshcd-pci.c b/drivers/scsi/ufs/ufshcd-pci.c
index 2a26faa..955ed55 100644
--- a/drivers/scsi/ufs/ufshcd-pci.c
+++ b/drivers/scsi/ufs/ufshcd-pci.c
@@ -43,34 +43,24 @@
  * @pdev: pointer to PCI device handle
  * @state: power state
  *
- * Returns -ENOSYS
+ * Returns 0 if successful
+ * Returns non-zero otherwise
  */
 static int ufshcd_pci_suspend(struct device *dev)
 {
-   /*
-* TODO:
-* 1. Call ufshcd_suspend
-* 2. Do bus specific power management

[PATCH/RESEND V5 17/17] scsi: ufs: definitions for phy interface

2014-09-24 Thread Dolev Raviv
- Adding some of the definitions missing in unipro.h, including power
  enumeration.
- Read Modify Write Line helper function
- Indication for the type of suspend

Signed-off-by: Dolev Raviv dra...@codeaurora.org
Signed-off-by: Subhash Jadavani subha...@codeaurora.org
Signed-off-by: Yaniv Gardi yga...@codeaurora.org

diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index d35719d..91c7adc 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -5088,6 +5088,8 @@ int ufshcd_system_suspend(struct ufs_hba *hba)
 
ret = ufshcd_suspend(hba, UFS_SYSTEM_PM);
 out:
+   if (!ret)
+   hba-is_sys_suspended = true;
return ret;
 }
 EXPORT_SYMBOL(ufshcd_system_suspend);
diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h
index d7fec86..58ecdff 100644
--- a/drivers/scsi/ufs/ufshcd.h
+++ b/drivers/scsi/ufs/ufshcd.h
@@ -474,6 +474,7 @@ struct ufs_hba {
 
struct devfreq *devfreq;
struct ufs_clk_scaling clk_scaling;
+   bool is_sys_suspended;
 };
 
 /* Returns true if clocks can be gated. Otherwise false */
@@ -499,6 +500,23 @@ static inline bool 
ufshcd_can_autobkops_during_suspend(struct ufs_hba *hba)
 #define ufshcd_readl(hba, reg) \
readl((hba)-mmio_base + (reg))
 
+/**
+ * ufshcd_rmwl - read modify write into a register
+ * @hba - per adapter instance
+ * @mask - mask to apply on read value
+ * @val - actual value to write
+ * @reg - register address
+ */
+static inline void ufshcd_rmwl(struct ufs_hba *hba, u32 mask, u32 val, u32 reg)
+{
+   u32 tmp;
+
+   tmp = ufshcd_readl(hba, reg);
+   tmp = ~mask;
+   tmp |= (val  mask);
+   ufshcd_writel(hba, tmp, reg);
+}
+
 int ufshcd_alloc_host(struct device *, struct ufs_hba **);
 int ufshcd_init(struct ufs_hba * , void __iomem * , unsigned int);
 void ufshcd_remove(struct ufs_hba *);
diff --git a/drivers/scsi/ufs/unipro.h b/drivers/scsi/ufs/unipro.h
index 0bb8041..3fc3e21 100644
--- a/drivers/scsi/ufs/unipro.h
+++ b/drivers/scsi/ufs/unipro.h
@@ -13,6 +13,44 @@
 #define _UNIPRO_H_
 
 /*
+ * M-TX Configuration Attributes
+ */
+#define TX_MODE0x0021
+#define TX_HSRATE_SERIES   0x0022
+#define TX_HSGEAR  0x0023
+#define TX_PWMGEAR 0x0024
+#define TX_AMPLITUDE   0x0025
+#define TX_HS_SLEWRATE 0x0026
+#define TX_SYNC_SOURCE 0x0027
+#define TX_HS_SYNC_LENGTH  0x0028
+#define TX_HS_PREPARE_LENGTH   0x0029
+#define TX_LS_PREPARE_LENGTH   0x002A
+#define TX_HIBERN8_CONTROL 0x002B
+#define TX_LCC_ENABLE  0x002C
+#define TX_PWM_BURST_CLOSURE_EXTENSION 0x002D
+#define TX_BYPASS_8B10B_ENABLE 0x002E
+#define TX_DRIVER_POLARITY 0x002F
+#define TX_HS_UNTERMINATED_LINE_DRIVE_ENABLE   0x0030
+#define TX_LS_TERMINATED_LINE_DRIVE_ENABLE 0x0031
+#define TX_LCC_SEQUENCER   0x0032
+#define TX_MIN_ACTIVATETIME0x0033
+#define TX_PWM_G6_G7_SYNC_LENGTH   0x0034
+
+/*
+ * M-RX Configuration Attributes
+ */
+#define RX_MODE0x00A1
+#define RX_HSRATE_SERIES   0x00A2
+#define RX_HSGEAR  0x00A3
+#define RX_PWMGEAR 0x00A4
+#define RX_LS_TERMINATED_ENABLE0x00A5
+#define RX_HS_UNTERMINATED_ENABLE  0x00A6
+#define RX_ENTER_HIBERN8   0x00A7
+#define RX_BYPASS_8B10B_ENABLE 0x00A8
+#define RX_TERMINATION_FORCE_ENABLE0x0089
+
+#define is_mphy_tx_attr(attr)  (attr  RX_MODE)
+/*
  * PHY Adpater attributes
  */
 #define PA_ACTIVETXDATALANES   0x1560
@@ -87,6 +125,24 @@ enum {
PA_HS_MODE_B= 2,
 };
 
+enum ufs_pwm_gear_tag {
+   UFS_PWM_DONT_CHANGE,/* Don't change Gear */
+   UFS_PWM_G1, /* PWM Gear 1 (default for reset) */
+   UFS_PWM_G2, /* PWM Gear 2 */
+   UFS_PWM_G3, /* PWM Gear 3 */
+   UFS_PWM_G4, /* PWM Gear 4 */
+   UFS_PWM_G5, /* PWM Gear 5 */
+   UFS_PWM_G6, /* PWM Gear 6 */
+   UFS_PWM_G7, /* PWM Gear 7 */
+};
+
+enum ufs_hs_gear_tag {
+   UFS_HS_DONT_CHANGE, /* Don't change Gear */
+   UFS_HS_G1,  /* HS Gear 1 (default for reset) */
+   UFS_HS_G2,  /* HS Gear 2 */
+   UFS_HS_G3,  /* HS Gear 3 */
+};
+
 /*
  * Data Link Layer Attributes
  */
-- 
1.8.5.2
-- 
QUALCOMM ISRAEL, on behalf of Qualcomm Innovation Center, Inc. is a member
of Code Aurora Forum, hosted by The Linux Foundation

--
To unsubscribe from this list: send the line unsubscribe linux-scsi in
the body of a message to majord...@vger.kernel.org

[PATCH/RESEND V5 03/17] scsi: ufs: Allow vendor specific initialization

2014-09-24 Thread Dolev Raviv
From: Sujit Reddy Thumma sthu...@codeaurora.org

Some vendor specific controller versions might need to configure
vendor specific - registers, clocks, voltage regulators etc. to
initialize the host controller UTP layer and Uni-Pro stack.
Provide some common initialization operations that can be used
to configure vendor specifics. The methods can be extended in
future, for example, for power mode transitions.

The operations are vendor/board specific and hence determined with
the help of compatible property in device tree.

Signed-off-by: Sujit Reddy Thumma sthu...@codeaurora.org
Signed-off-by: Dolev Raviv dra...@codeaurora.org

diff --git a/drivers/scsi/ufs/ufshcd-pci.c b/drivers/scsi/ufs/ufshcd-pci.c
index afaabe2..7a6edbc 100644
--- a/drivers/scsi/ufs/ufshcd-pci.c
+++ b/drivers/scsi/ufs/ufshcd-pci.c
@@ -164,7 +164,13 @@ ufshcd_pci_probe(struct pci_dev *pdev, const struct 
pci_device_id *id)
 
mmio_base = pcim_iomap_table(pdev)[0];
 
-   err = ufshcd_init(pdev-dev, hba, mmio_base, pdev-irq);
+   err = ufshcd_alloc_host(pdev-dev, hba);
+   if (err) {
+   dev_err(pdev-dev, Allocation failed\n);
+   return err;
+   }
+
+   err = ufshcd_init(hba, mmio_base, pdev-irq);
if (err) {
dev_err(pdev-dev, Initialization failed\n);
return err;
diff --git a/drivers/scsi/ufs/ufshcd-pltfrm.c b/drivers/scsi/ufs/ufshcd-pltfrm.c
index 5e46232..d727b1a 100644
--- a/drivers/scsi/ufs/ufshcd-pltfrm.c
+++ b/drivers/scsi/ufs/ufshcd-pltfrm.c
@@ -35,9 +35,24 @@
 
 #include linux/platform_device.h
 #include linux/pm_runtime.h
+#include linux/of.h
 
 #include ufshcd.h
 
+static const struct of_device_id ufs_of_match[];
+static struct ufs_hba_variant_ops *get_variant_ops(struct device *dev)
+{
+   if (dev-of_node) {
+   const struct of_device_id *match;
+
+   match = of_match_node(ufs_of_match, dev-of_node);
+   if (match)
+   return (struct ufs_hba_variant_ops *)match-data;
+   }
+
+   return NULL;
+}
+
 #ifdef CONFIG_PM
 /**
  * ufshcd_pltfrm_suspend - suspend power management function
@@ -138,8 +153,8 @@ static int ufshcd_pltfrm_probe(struct platform_device *pdev)
 
mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
mmio_base = devm_ioremap_resource(dev, mem_res);
-   if (IS_ERR(mmio_base)) {
-   err = PTR_ERR(mmio_base);
+   if (IS_ERR(*(void **)mmio_base)) {
+   err = PTR_ERR(*(void **)mmio_base);
goto out;
}
 
@@ -150,10 +165,18 @@ static int ufshcd_pltfrm_probe(struct platform_device 
*pdev)
goto out;
}
 
+   err = ufshcd_alloc_host(dev, hba);
+   if (err) {
+   dev_err(pdev-dev, Allocation failed\n);
+   goto out;
+   }
+
+   hba-vops = get_variant_ops(pdev-dev);
+
pm_runtime_set_active(pdev-dev);
pm_runtime_enable(pdev-dev);
 
-   err = ufshcd_init(dev, hba, mmio_base, irq);
+   err = ufshcd_init(hba, mmio_base, irq);
if (err) {
dev_err(dev, Intialization failed\n);
goto out_disable_rpm;
diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index ba27215..d0565b0 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -3,6 +3,7 @@
  *
  * This code is based on drivers/scsi/ufs/ufshcd.c
  * Copyright (C) 2011-2013 Samsung India Software Operations
+ * Copyright (c) 2013-2014, The Linux Foundation. All rights reserved.
  *
  * Authors:
  * Santosh Yaraganavi santosh...@samsung.com
@@ -31,6 +32,9 @@
  * circumstances will the contributor of this Program be liable for
  * any damages of any kind arising from your use or distribution of
  * this program.
+ *
+ * The Linux Foundation chooses to take subject only to the GPLv2
+ * license terms, and distributes only under these terms.
  */
 
 #include linux/async.h
@@ -175,13 +179,14 @@ static inline u32 ufshcd_get_ufs_version(struct ufs_hba 
*hba)
 /**
  * ufshcd_is_device_present - Check if any device connected to
  *   the host controller
- * @reg_hcs - host controller status register value
+ * @hba: pointer to adapter instance
  *
  * Returns 1 if device present, 0 if no device detected
  */
-static inline int ufshcd_is_device_present(u32 reg_hcs)
+static inline int ufshcd_is_device_present(struct ufs_hba *hba)
 {
-   return (DEVICE_PRESENT  reg_hcs) ? 1 : 0;
+   return (ufshcd_readl(hba, REG_CONTROLLER_STATUS) 
+   DEVICE_PRESENT) ? 1 : 0;
 }
 
 /**
@@ -1798,11 +1803,10 @@ out:
  * @hba: per adapter instance
  *
  * To bring UFS host controller to operational state,
- * 1. Check if device is present
- * 2. Enable required interrupts
- * 3. Configure interrupt aggregation
- * 4. Program UTRL and UTMRL base addres
- * 5. Configure run-stop-registers
+ * 1. Enable required interrupts
+ * 2. Configure interrupt

[PATCH/RESEND V5 16/17] scsi: ufs: tune bkops while power managment events

2014-09-24 Thread Dolev Raviv
From: Subhash Jadavani subha...@codeaurora.org

Add capability to control the auto bkops during suspend.
If host explicitly enables the auto bkops (background operation) on device
then only device would perform the bkops on its own. If auto bkops is not
enabled explicitly and if the device reaches to state where it must do
background operation, device would raise the urgent bkops exception event
to host and then host will enable the auto bkops on device. This patch
adds the option to choose whether auto bkops should be enabled during
runtime suspend or not. Since we don't want to keep the device active to
perform the non critical bkops, host will enable urgent bkops only.

Keep auto-bkops enabled after resume if urgent bkops needed.
If device bkops status shows that its in critical need of executing
background operations, host should allow the device to continue doing
background operations.

Signed-off-by: Subhash Jadavani subha...@codeaurora.org
Signed-off-by: Dolev Raviv dra...@codeaurora.org

diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index dcab003..d35719d 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -4858,13 +4858,19 @@ static int ufshcd_suspend(struct ufs_hba *hba, enum 
ufs_pm_op pm_op)
}
 
if (ufshcd_is_runtime_pm(pm_op)) {
-   /*
-* The device is idle with no requests in the queue,
-* allow background operations if needed.
-*/
-   ret = ufshcd_bkops_ctrl(hba, BKOPS_STATUS_NON_CRITICAL);
-   if (ret)
-   goto enable_gating;
+   if (ufshcd_can_autobkops_during_suspend(hba)) {
+   /*
+* The device is idle with no requests in the queue,
+* allow background operations if bkops status shows
+* that performance might be impacted.
+*/
+   ret = ufshcd_urgent_bkops(hba);
+   if (ret)
+   goto enable_gating;
+   } else {
+   /* make sure that auto bkops is disabled */
+   ufshcd_disable_auto_bkops(hba);
+   }
}
 
if ((req_dev_pwr_mode != hba-curr_dev_pwr_mode) 
@@ -5012,7 +5018,11 @@ static int ufshcd_resume(struct ufs_hba *hba, enum 
ufs_pm_op pm_op)
goto set_old_link_state;
}
 
-   ufshcd_disable_auto_bkops(hba);
+   /*
+* If BKOPs operations are urgently needed at this moment then
+* keep auto-bkops enabled or else disable it.
+*/
+   ufshcd_urgent_bkops(hba);
hba-clk_gating.is_suspended = false;
 
if (ufshcd_is_clkscaling_enabled(hba))
diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h
index 908db3e..d7fec86 100644
--- a/drivers/scsi/ufs/ufshcd.h
+++ b/drivers/scsi/ufs/ufshcd.h
@@ -469,6 +469,8 @@ struct ufs_hba {
 #define UFSHCD_CAP_HIBERN8_WITH_CLK_GATING (1  1)
/* Allow dynamic clk scaling */
 #define UFSHCD_CAP_CLK_SCALING (1  2)
+   /* Allow auto bkops to enabled during runtime suspend */
+#define UFSHCD_CAP_AUTO_BKOPS_SUSPEND (1  3)
 
struct devfreq *devfreq;
struct ufs_clk_scaling clk_scaling;
@@ -487,6 +489,11 @@ static inline int ufshcd_is_clkscaling_enabled(struct 
ufs_hba *hba)
 {
return hba-caps  UFSHCD_CAP_CLK_SCALING;
 }
+static inline bool ufshcd_can_autobkops_during_suspend(struct ufs_hba *hba)
+{
+   return hba-caps  UFSHCD_CAP_AUTO_BKOPS_SUSPEND;
+}
+
 #define ufshcd_writel(hba, val, reg)   \
writel((val), (hba)-mmio_base + (reg))
 #define ufshcd_readl(hba, reg) \
-- 
1.8.5.2
-- 
QUALCOMM ISRAEL, on behalf of Qualcomm Innovation Center, Inc. is a member
of Code Aurora Forum, hosted by The Linux Foundation

--
To unsubscribe from this list: send the line unsubscribe linux-scsi in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH V5 10/17] scsi: ufs: manually add well known logical units

2014-09-24 Thread Dolev Raviv
From: Subhash Jadavani subha...@codeaurora.org

UFS device specification requires the UFS devices to support 4 well known
logical units:
REPORT_LUNS (address: 01h)
UFS Device (address: 50h)
RPMB (address: 44h)
BOOT (address: 30h)

UFS device may have standard LUs and LUN id could be from 0x00 to 0x7F.
UFS device specification use Peripheral Device Addressing Format
(SCSI SAM-5) for standard LUs.

UFS device akso have the Well Known LUs (also referred as W-LU) which
again could be from 0x00 to 0x7F. For W-LUs, UFS device specification only
allows the Extended Addressing Format (SCSI SAM-5) which means the W-LUNs
would start from 0xC100 onwards.

UFS device's power management needs to be controlled by POWER CONDITION
field of SSU (START STOP UNIT) command. But this power condition field
will take effect only when its sent to UFS device well known logical unit
hence we require the scsi_device instance to represent this logical unit in
order for the UFS host driver to send the SSU command for power management.

We also require the scsi_device instance for RPMB (Replay Protected
Memory Block) LU so user space process can control this LU. User space may
also want to have access to BOOT LU.

This patch adds the scsi device instances for each of all well known LUs
(except REPORT LUNS LU).

Signed-off-by: Subhash Jadavani subha...@codeaurora.org
Signed-off-by: Dolev Raviv dra...@codeaurora.org
Signed-off-by: Sujit Reddy Thumma sthu...@codeaurora.org

diff --git a/drivers/scsi/ufs/ufs.h b/drivers/scsi/ufs/ufs.h
index 4ca99ed..37d64c1 100644
--- a/drivers/scsi/ufs/ufs.h
+++ b/drivers/scsi/ufs/ufs.h
@@ -49,9 +49,28 @@
 #define UPIU_HEADER_DWORD(byte3, byte2, byte1, byte0)\
cpu_to_be32((byte3  24) | (byte2  16) |\
 (byte1  8) | (byte0))
-
+/*
+ * UFS device may have standard LUs and LUN id could be from 0x00 to
+ * 0x7F. Standard LUs use Peripheral Device Addressing Format.
+ * UFS device may also have the Well Known LUs (also referred as W-LU)
+ * which again could be from 0x00 to 0x7F. For W-LUs, device only use
+ * the Extended Addressing Format which means the W-LUNs would be
+ * from 0xc100 (SCSI_W_LUN_BASE) onwards.
+ * This means max. LUN number reported from UFS device could be 0xC17F.
+ */
+#define UFS_UPIU_MAX_UNIT_NUM_ID   0x7F
+#define UFS_MAX_LUNS   (SCSI_W_LUN_BASE + UFS_UPIU_MAX_UNIT_NUM_ID)
+#define UFS_UPIU_WLUN_ID   (1  7)
 #define UFS_UPIU_MAX_GENERAL_LUN   8
 
+/* Well known logical unit id in LUN field of UPIU */
+enum {
+   UFS_UPIU_REPORT_LUNS_WLUN   = 0x81,
+   UFS_UPIU_UFS_DEVICE_WLUN= 0xD0,
+   UFS_UPIU_BOOT_WLUN  = 0xB0,
+   UFS_UPIU_RPMB_WLUN  = 0xC4,
+};
+
 /*
  * UFS Protocol Information Unit related definitions
  */
diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index dc89c48..eede10a 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -100,7 +100,6 @@ static u32 ufs_query_desc_max_size[] = {
 enum {
UFSHCD_MAX_CHANNEL  = 0,
UFSHCD_MAX_ID   = 1,
-   UFSHCD_MAX_LUNS = 8,
UFSHCD_CMD_PER_LUN  = 32,
UFSHCD_CAN_QUEUE= 32,
 };
@@ -901,6 +900,32 @@ static int ufshcd_compose_upiu(struct ufs_hba *hba, struct 
ufshcd_lrb *lrbp)
return ret;
 }
 
+/*
+ * ufshcd_scsi_to_upiu_lun - maps scsi LUN to UPIU LUN
+ * @scsi_lun: scsi LUN id
+ *
+ * Returns UPIU LUN id
+ */
+static inline u8 ufshcd_scsi_to_upiu_lun(unsigned int scsi_lun)
+{
+   if (scsi_is_wlun(scsi_lun))
+   return (scsi_lun  UFS_UPIU_MAX_UNIT_NUM_ID)
+   | UFS_UPIU_WLUN_ID;
+   else
+   return scsi_lun  UFS_UPIU_MAX_UNIT_NUM_ID;
+}
+
+/**
+ * ufshcd_upiu_wlun_to_scsi_wlun - maps UPIU W-LUN id to SCSI W-LUN ID
+ * @scsi_lun: UPIU W-LUN id
+ *
+ * Returns SCSI W-LUN id
+ */
+static inline u16 ufshcd_upiu_wlun_to_scsi_wlun(u8 upiu_wlun_id)
+{
+   return (upiu_wlun_id  ~UFS_UPIU_WLUN_ID) | SCSI_W_LUN_BASE;
+}
+
 /**
  * ufshcd_queuecommand - main entry point for SCSI requests
  * @cmd: command from SCSI Midlayer
@@ -959,7 +984,7 @@ static int ufshcd_queuecommand(struct Scsi_Host *host, 
struct scsi_cmnd *cmd)
lrbp-sense_bufflen = SCSI_SENSE_BUFFERSIZE;
lrbp-sense_buffer = cmd-sense_buffer;
lrbp-task_tag = tag;
-   lrbp-lun = cmd-device-lun;
+   lrbp-lun = ufshcd_scsi_to_upiu_lun(cmd-device-lun);
lrbp-intr_cmd = false;
lrbp-command_type = UTP_CMD_TYPE_SCSI;
 
@@ -1513,7 +1538,7 @@ static inline int ufshcd_read_unit_desc_param(struct 
ufs_hba *hba,
 * Unit descriptors are only available for general purpose LUs (LUN id
 * from 0 to 7) and RPMB Well known LU.
 */
-   if (lun = UFS_UPIU_MAX_GENERAL_LUN)
+   if (lun != UFS_UPIU_RPMB_WLUN  (lun = UFS_UPIU_MAX_GENERAL_LUN))
return -EOPNOTSUPP;
 
return ufshcd_read_desc_param(hba

[PATCH V5 02/17] scsi: sysfs: don't add scsi_device if its already added

2014-09-24 Thread Dolev Raviv
From: Subhash Jadavani subha...@codeaurora.org

If LLD has added scsi device (by calling scsi_add_device) before scheduling
async scsi_scan_host then scsi_finish_async_scan() will end up calling
scsi_sysfs_add_sdev for scsi device which was already added by LLD.
This patch fixes this issue by adding a check at the start of
scsi_sysfs_add_sdev() to skip the device add if it's already visible to
rest of the kernel.

Signed-off-by: Subhash Jadavani subha...@codeaurora.org
Signed-off-by: Dolev Raviv dra...@codeaurora.org

diff --git a/drivers/scsi/scsi_sysfs.c b/drivers/scsi/scsi_sysfs.c
index 3524b68..00890b3 100644
--- a/drivers/scsi/scsi_sysfs.c
+++ b/drivers/scsi/scsi_sysfs.c
@@ -1027,6 +1027,9 @@ int scsi_sysfs_add_sdev(struct scsi_device *sdev)
struct request_queue *rq = sdev-request_queue;
struct scsi_target *starget = sdev-sdev_target;
 
+   if (sdev-is_visible)
+   return 0;
+
error = scsi_device_set_state(sdev, SDEV_RUNNING);
if (error)
return error;
-- 
1.8.5.2
-- 
QUALCOMM ISRAEL, on behalf of Qualcomm Innovation Center, Inc. is a member
of Code Aurora Forum, hosted by The Linux Foundation

--
To unsubscribe from this list: send the line unsubscribe linux-scsi in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH/RESEND V5 15/17] scsi: ufs: Add support for clock scaling using devfreq framework

2014-09-24 Thread Dolev Raviv
From: Sahitya Tummala stumm...@codeaurora.org

The clocks for UFS device will be managed by generic DVFS (Dynamic
Voltage and Frequency Scaling) framework within kernel. This devfreq
framework works with different governors to scale the clocks. By default,
UFS devices uses simple_ondemand governor which scales the clocks up if
the load is more than upthreshold and scales down if the load is less than
downthreshold.

Signed-off-by: Sahitya Tummala stumm...@codeaurora.org
Signed-off-by: Dolev Raviv dra...@codeaurora.org

diff --git a/drivers/scsi/ufs/Kconfig b/drivers/scsi/ufs/Kconfig
index f07f901..6e07b2a 100644
--- a/drivers/scsi/ufs/Kconfig
+++ b/drivers/scsi/ufs/Kconfig
@@ -35,6 +35,8 @@
 config SCSI_UFSHCD
tristate Universal Flash Storage Controller Driver Core
depends on SCSI  SCSI_DMA
+   select PM_DEVFREQ
+   select DEVFREQ_GOV_SIMPLE_ONDEMAND
---help---
This selects the support for UFS devices in Linux, say Y and make
  sure that you know the name of your UFS host adapter (the card
diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index ff889723..dcab003 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -38,6 +38,7 @@
  */
 
 #include linux/async.h
+#include linux/devfreq.h
 
 #include ufshcd.h
 #include unipro.h
@@ -545,6 +546,8 @@ static void ufshcd_ungate_work(struct work_struct *work)
hba-clk_gating.is_suspended = false;
}
 unblock_reqs:
+   if (ufshcd_is_clkscaling_enabled(hba))
+   devfreq_resume_device(hba-devfreq);
scsi_unblock_requests(hba-host);
 }
 
@@ -561,10 +564,10 @@ int ufshcd_hold(struct ufs_hba *hba, bool async)
 
if (!ufshcd_is_clkgating_allowed(hba))
goto out;
-start:
spin_lock_irqsave(hba-host-host_lock, flags);
hba-clk_gating.active_reqs++;
 
+start:
switch (hba-clk_gating.state) {
case CLKS_ON:
break;
@@ -596,6 +599,7 @@ start:
spin_unlock_irqrestore(hba-host-host_lock, flags);
flush_work(hba-clk_gating.ungate_work);
/* Make sure state is CLKS_ON before returning */
+   spin_lock_irqsave(hba-host-host_lock, flags);
goto start;
default:
dev_err(hba-dev, %s: clk gating is in invalid state %d\n,
@@ -636,6 +640,11 @@ static void ufshcd_gate_work(struct work_struct *work)
ufshcd_set_link_hibern8(hba);
}
 
+   if (ufshcd_is_clkscaling_enabled(hba)) {
+   devfreq_suspend_device(hba-devfreq);
+   hba-clk_scaling.window_start_t = 0;
+   }
+
if (!ufshcd_is_link_active(hba))
ufshcd_setup_clocks(hba, false);
else
@@ -737,6 +746,32 @@ static void ufshcd_exit_clk_gating(struct ufs_hba *hba)
device_remove_file(hba-dev, hba-clk_gating.delay_attr);
 }
 
+/* Must be called with host lock acquired */
+static void ufshcd_clk_scaling_start_busy(struct ufs_hba *hba)
+{
+   if (!ufshcd_is_clkscaling_enabled(hba))
+   return;
+
+   if (!hba-clk_scaling.is_busy_started) {
+   hba-clk_scaling.busy_start_t = ktime_get();
+   hba-clk_scaling.is_busy_started = true;
+   }
+}
+
+static void ufshcd_clk_scaling_update_busy(struct ufs_hba *hba)
+{
+   struct ufs_clk_scaling *scaling = hba-clk_scaling;
+
+   if (!ufshcd_is_clkscaling_enabled(hba))
+   return;
+
+   if (!hba-outstanding_reqs  scaling-is_busy_started) {
+   scaling-tot_busy_t += ktime_to_us(ktime_sub(ktime_get(),
+   scaling-busy_start_t));
+   scaling-busy_start_t = ktime_set(0, 0);
+   scaling-is_busy_started = false;
+   }
+}
 /**
  * ufshcd_send_command - Send SCSI or device management commands
  * @hba: per adapter instance
@@ -745,6 +780,7 @@ static void ufshcd_exit_clk_gating(struct ufs_hba *hba)
 static inline
 void ufshcd_send_command(struct ufs_hba *hba, unsigned int task_tag)
 {
+   ufshcd_clk_scaling_start_busy(hba);
__set_bit(task_tag, hba-outstanding_reqs);
ufshcd_writel(hba, 1  task_tag, REG_UTP_TRANSFER_REQ_DOOR_BELL);
 }
@@ -3025,6 +3061,8 @@ static void ufshcd_transfer_req_compl(struct ufs_hba *hba)
/* clear corresponding bits of completed commands */
hba-outstanding_reqs ^= completed_reqs;
 
+   ufshcd_clk_scaling_update_busy(hba);
+
/* we might have free'd some tags above */
wake_up(hba-dev_cmd.tag_wq);
 }
@@ -4125,6 +4163,10 @@ static int ufshcd_probe_hba(struct ufs_hba *hba)
if (!hba-is_init_prefetch)
hba-is_init_prefetch = true;
 
+   /* Resume devfreq after UFS device is detected */
+   if (ufshcd_is_clkscaling_enabled(hba))
+   devfreq_resume_device(hba-devfreq);
+
 out:
/*
 * If we failed to initialize the device or the device is not
@@ -4446,6 +4488,7 @@ static

[PATCH/RESEND V5 06/17] scsi: ufs: add voting support for host controller power

2014-09-24 Thread Dolev Raviv
From: Raviv Shvili rshv...@codeaurora.org

Add the support for voting of the regulator powering the
host controller logic.

Signed-off-by: Raviv Shvili rshv...@codeaurora.org
Signed-off-by: Subhash Jadavani subha...@codeaurora.org
Signed-off-by: Dolev Raviv dra...@codeaurora.org

diff --git a/Documentation/devicetree/bindings/ufs/ufshcd-pltfrm.txt 
b/Documentation/devicetree/bindings/ufs/ufshcd-pltfrm.txt
index b0f791a..fb1234e 100644
--- a/Documentation/devicetree/bindings/ufs/ufshcd-pltfrm.txt
+++ b/Documentation/devicetree/bindings/ufs/ufshcd-pltfrm.txt
@@ -9,6 +9,7 @@ Required properties:
 - reg   : registers mapping
 
 Optional properties:
+- vdd-hba-supply: phandle to UFS host controller supply regulator node
 - vcc-supply: phandle to VCC supply regulator node
 - vccq-supply   : phandle to VCCQ supply regulator node
 - vccq2-supply  : phandle to VCCQ2 supply regulator node
@@ -20,6 +21,7 @@ Optional properties:
 - vcc-max-microamp  : specifies max. load that can be drawn from vcc supply
 - vccq-max-microamp : specifies max. load that can be drawn from vccq 
supply
 - vccq2-max-microamp: specifies max. load that can be drawn from vccq2 
supply
+- name-fixed-regulator : boolean property specifying that name-supply is a 
fixed regulator
 
 - clocks: List of phandle and clock specifier pairs
 - clock-names   : List of clock input name strings sorted in the same
@@ -39,6 +41,8 @@ Example:
reg = 0xfc598000 0x800;
interrupts = 0 28 0;
 
+   vdd-hba-supply = xxx_reg0;
+   vdd-hba-fixed-regulator;
vcc-supply = xxx_reg1;
vcc-supply-1p8;
vccq-supply = xxx_reg2;
diff --git a/drivers/scsi/ufs/ufs.h b/drivers/scsi/ufs/ufs.h
index 729ce7d..9bb6919 100644
--- a/drivers/scsi/ufs/ufs.h
+++ b/drivers/scsi/ufs/ufs.h
@@ -385,6 +385,7 @@ struct ufs_vreg_info {
struct ufs_vreg *vcc;
struct ufs_vreg *vccq;
struct ufs_vreg *vccq2;
+   struct ufs_vreg *vdd_hba;
 };
 
 #endif /* End of Header */
diff --git a/drivers/scsi/ufs/ufshcd-pltfrm.c b/drivers/scsi/ufs/ufshcd-pltfrm.c
index 642d80f..dde4e6e 100644
--- a/drivers/scsi/ufs/ufshcd-pltfrm.c
+++ b/drivers/scsi/ufs/ufshcd-pltfrm.c
@@ -147,6 +147,11 @@ static int ufshcd_populate_vreg(struct device *dev, const 
char *name,
 
vreg-name = kstrdup(name, GFP_KERNEL);
 
+   /* if fixed regulator no need further initialization */
+   snprintf(prop_name, MAX_PROP_SIZE, %s-fixed-regulator, name);
+   if (of_property_read_bool(np, prop_name))
+   goto out;
+
snprintf(prop_name, MAX_PROP_SIZE, %s-max-microamp, name);
ret = of_property_read_u32(np, prop_name, vreg-max_uA);
if (ret) {
@@ -198,6 +203,10 @@ static int ufshcd_parse_regulator_info(struct ufs_hba *hba)
struct device *dev = hba-dev;
struct ufs_vreg_info *info = hba-vreg_info;
 
+   err = ufshcd_populate_vreg(dev, vdd-hba, info-vdd_hba);
+   if (err)
+   goto out;
+
err = ufshcd_populate_vreg(dev, vcc, info-vcc);
if (err)
goto out;
diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index b033702..26301b8 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -3311,6 +3311,16 @@ out:
return ret;
 }
 
+static int ufshcd_setup_hba_vreg(struct ufs_hba *hba, bool on)
+{
+   struct ufs_vreg_info *info = hba-vreg_info;
+
+   if (info)
+   return ufshcd_toggle_vreg(hba-dev, info-vdd_hba, on);
+
+   return 0;
+}
+
 static int ufshcd_get_vreg(struct device *dev, struct ufs_vreg *vreg)
 {
int ret = 0;
@@ -3350,6 +3360,16 @@ out:
return ret;
 }
 
+static int ufshcd_init_hba_vreg(struct ufs_hba *hba)
+{
+   struct ufs_vreg_info *info = hba-vreg_info;
+
+   if (info)
+   return ufshcd_get_vreg(hba-dev, info-vdd_hba);
+
+   return 0;
+}
+
 static int ufshcd_setup_clocks(struct ufs_hba *hba, bool on)
 {
int ret = 0;
@@ -3483,14 +3503,29 @@ static int ufshcd_hba_init(struct ufs_hba *hba)
 {
int err;
 
-   err = ufshcd_init_clocks(hba);
+   /*
+* Handle host controller power separately from the UFS device power
+* rails as it will help controlling the UFS host controller power
+* collapse easily which is different than UFS device power collapse.
+* Also, enable the host controller power before we go ahead with rest
+* of the initialization here.
+*/
+   err = ufshcd_init_hba_vreg(hba);
if (err)
goto out;
 
-   err = ufshcd_setup_clocks(hba, true);
+   err = ufshcd_setup_hba_vreg(hba, true);
if (err)
goto out;
 
+   err = ufshcd_init_clocks(hba);
+   if (err)
+   goto out_disable_hba_vreg;
+
+   err = ufshcd_setup_clocks(hba, true);
+   if (err

[PATCH V5 01/17] scsi: fixing the type for well known LUs

2014-09-24 Thread Dolev Raviv
From: Subhash Jadavani subha...@codeaurora.org

Some devices may respond with wrong type for well-known logical units.
This patch forces well-known type for devices which doesn't report it
correct.

Signed-off-by: Subhash Jadavani subha...@codeaurora.org
Signed-off-by: Sujit Reddy Thumma sthu...@codeaurora.org
Signed-off-by: Dolev Raviv dra...@codeaurora.org

diff --git a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c
index 56675db..a34db9e 100644
--- a/drivers/scsi/scsi_scan.c
+++ b/drivers/scsi/scsi_scan.c
@@ -805,6 +805,14 @@ static int scsi_add_lun(struct scsi_device *sdev, unsigned 
char *inq_result,
} else {
sdev-type = (inq_result[0]  0x1f);
sdev-removable = (inq_result[1]  0x80)  7;
+
+   /*
+* some devices may respond with wrong type for
+* well-known logical units. Force well-known type
+* to enumerate them correctly.
+*/
+   if (scsi_is_wlun(sdev-lun))
+   sdev-type = TYPE_WLUN;
}
 
if (sdev-type == TYPE_RBC || sdev-type == TYPE_ROM) {
diff --git a/include/scsi/scsi.h b/include/scsi/scsi.h
index 261e708..d17178e 100644
--- a/include/scsi/scsi.h
+++ b/include/scsi/scsi.h
@@ -333,6 +333,7 @@ static inline int scsi_status_is_good(int status)
 #define TYPE_RBC   0x0e
 #define TYPE_OSD0x11
 #define TYPE_ZBC0x14
+#define TYPE_WLUN   0x1e/* well-known logical unit */
 #define TYPE_NO_LUN 0x7f
 
 /* SCSI protocols; these are taken from SPC-3 section 7.5 */
-- 
1.8.5.2
-- 
QUALCOMM ISRAEL, on behalf of Qualcomm Innovation Center, Inc. is a member
of Code Aurora Forum, hosted by The Linux Foundation

--
To unsubscribe from this list: send the line unsubscribe linux-scsi in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH/RESEND V5 09/17] scsi: ufs: Active Power Mode - configuring bActiveICCLevel

2014-09-24 Thread Dolev Raviv
From: Yaniv Gardi yga...@codeaurora.org

The maximum power consumption in active is determined by bActiveICCLevel.
The configuration is done by reading max current supported by the
regulators connected to VCC, VCCQ and VCCQ2 rails on the boards, and
reading the current consumption levels from the device for each rails
(vcc/vccq/vccq2) using power descriptor.
We configure the bActiveICCLevel attribute, with the max value that
correspond to the minimum-of(VCC-current-level,VCCQ-current-level,
VCCQ2-current-level).
In order to minimize resume latency, pre-fetch icc levels and reference
clock during initialization and avoid reading them each link startup
during resume.

Signed-off-by: Raviv Shvili rshv...@codeaurora.org
Signed-off-by: Yaniv Gardi yga...@codeaurora.org
Signed-off-by: Dolev Raviv dra...@codeaurora.org

diff --git a/drivers/scsi/ufs/ufs.h b/drivers/scsi/ufs/ufs.h
index f76a304..4ca99ed 100644
--- a/drivers/scsi/ufs/ufs.h
+++ b/drivers/scsi/ufs/ufs.h
@@ -115,6 +115,7 @@ enum flag_idn {
 
 /* Attribute idn for Query requests */
 enum attr_idn {
+   QUERY_ATTR_IDN_ACTIVE_ICC_LVL   = 0x03,
QUERY_ATTR_IDN_BKOPS_STATUS = 0x05,
QUERY_ATTR_IDN_EE_CONTROL   = 0x0D,
QUERY_ATTR_IDN_EE_STATUS= 0x0E,
@@ -174,6 +175,31 @@ enum unit_desc_param {
UNIT_DESC_PARAM_LARGE_UNIT_SIZE_M1  = 0x22,
 };
 
+/* bActiveICCLevel parameter current units */
+enum {
+   UFSHCD_NANO_AMP = 0,
+   UFSHCD_MICRO_AMP= 1,
+   UFSHCD_MILI_AMP = 2,
+   UFSHCD_AMP  = 3,
+};
+
+#define POWER_DESC_MAX_SIZE0x62
+#define POWER_DESC_MAX_ACTV_ICC_LVLS   16
+
+/* Attribute  bActiveICCLevel parameter bit masks definitions */
+#define ATTR_ICC_LVL_UNIT_OFFSET   14
+#define ATTR_ICC_LVL_UNIT_MASK (0x3  ATTR_ICC_LVL_UNIT_OFFSET)
+#define ATTR_ICC_LVL_VALUE_MASK0x3FF
+
+/* Power descriptor parameters offsets in bytes */
+enum power_desc_param_offset {
+   PWR_DESC_LEN= 0x0,
+   PWR_DESC_TYPE   = 0x1,
+   PWR_DESC_ACTIVE_LVLS_VCC_0  = 0x2,
+   PWR_DESC_ACTIVE_LVLS_VCCQ_0 = 0x22,
+   PWR_DESC_ACTIVE_LVLS_VCCQ2_0= 0x42,
+};
+
 /* Exception event mask values */
 enum {
MASK_EE_STATUS  = 0x,
diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index af29d4c..dc89c48 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -3265,6 +3265,125 @@ static int ufshcd_eh_host_reset_handler(struct 
scsi_cmnd *cmd)
 }
 
 /**
+ * ufshcd_get_max_icc_level - calculate the ICC level
+ * @sup_curr_uA: max. current supported by the regulator
+ * @start_scan: row at the desc table to start scan from
+ * @buff: power descriptor buffer
+ *
+ * Returns calculated max ICC level for specific regulator
+ */
+static u32 ufshcd_get_max_icc_level(int sup_curr_uA, u32 start_scan, char 
*buff)
+{
+   int i;
+   int curr_uA;
+   u16 data;
+   u16 unit;
+
+   for (i = start_scan; i = 0; i--) {
+   data = be16_to_cpu(*((u16 *)(buff + 2*i)));
+   unit = (data  ATTR_ICC_LVL_UNIT_MASK) 
+   ATTR_ICC_LVL_UNIT_OFFSET;
+   curr_uA = data  ATTR_ICC_LVL_VALUE_MASK;
+   switch (unit) {
+   case UFSHCD_NANO_AMP:
+   curr_uA = curr_uA / 1000;
+   break;
+   case UFSHCD_MILI_AMP:
+   curr_uA = curr_uA * 1000;
+   break;
+   case UFSHCD_AMP:
+   curr_uA = curr_uA * 1000 * 1000;
+   break;
+   case UFSHCD_MICRO_AMP:
+   default:
+   break;
+   }
+   if (sup_curr_uA = curr_uA)
+   break;
+   }
+   if (i  0) {
+   i = 0;
+   pr_err(%s: Couldn't find valid icc_level = %d, __func__, i);
+   }
+
+   return (u32)i;
+}
+
+/**
+ * ufshcd_calc_icc_level - calculate the max ICC level
+ * In case regulators are not initialized we'll return 0
+ * @hba: per-adapter instance
+ * @desc_buf: power descriptor buffer to extract ICC levels from.
+ * @len: length of desc_buff
+ *
+ * Returns calculated ICC level
+ */
+static u32 ufshcd_find_max_sup_active_icc_level(struct ufs_hba *hba,
+   u8 *desc_buf, int len)
+{
+   u32 icc_level = 0;
+
+   if (!hba-vreg_info.vcc || !hba-vreg_info.vccq ||
+   !hba-vreg_info.vccq2) {
+   dev_err(hba-dev,
+   %s: Regulator capability was not set, actvIccLevel=%d,
+   __func__, icc_level);
+   goto out;
+   }
+
+   if (hba-vreg_info.vcc)
+   icc_level = ufshcd_get_max_icc_level

[PATCH/RESEND V5 12/17] scsi: ufs: refactor configuring power mode

2014-09-24 Thread Dolev Raviv
Sometimes, the device shall report its maximum power and speed
capabilities, but we might not wish to configure it to use those
maximum capabilities.
This change adds support for the vendor specific host driver to
implement power change notify callback.

To enable configuring different power modes (number of lanes,
gear number and fast/slow modes) it is necessary to split the
configuration stage from the stage that reads the device max power mode.
In addition, it is not required to read the configuration more than
once, thus the configuration is stored after reading it once.

Signed-off-by: Dolev Raviv dra...@codeaurora.org
Signed-off-by: Yaniv Gardi yga...@codeaurora.org

diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index 11c6320..6bc4996 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -179,6 +179,8 @@ static void ufshcd_hba_exit(struct ufs_hba *hba);
 static int ufshcd_probe_hba(struct ufs_hba *hba);
 static int ufshcd_host_reset_and_restore(struct ufs_hba *hba);
 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 inline int ufshcd_enable_irq(struct ufs_hba *hba)
 {
@@ -1959,40 +1961,83 @@ static int ufshcd_uic_hibern8_exit(struct ufs_hba *hba)
 }
 
 /**
- * ufshcd_config_max_pwr_mode - Set  Change power mode with
- * maximum capability attribute information.
- * @hba: per adapter instance
- *
- * Returns 0 on success, non-zero value on failure
+ * ufshcd_get_max_pwr_mode - reads the max power mode negotiated with device
+ * @hba: per-adapter instance
  */
-static int ufshcd_config_max_pwr_mode(struct ufs_hba *hba)
+static int ufshcd_get_max_pwr_mode(struct ufs_hba *hba)
 {
-   enum {RX = 0, TX = 1};
-   u32 lanes[] = {1, 1};
-   u32 gear[] = {1, 1};
-   u8 pwr[] = {FASTAUTO_MODE, FASTAUTO_MODE};
-   int ret;
+   struct ufs_pa_layer_attr *pwr_info = hba-max_pwr_info.info;
+
+   if (hba-max_pwr_info.is_valid)
+   return 0;
+
+   pwr_info-pwr_tx = FASTAUTO_MODE;
+   pwr_info-pwr_rx = FASTAUTO_MODE;
+   pwr_info-hs_rate = PA_HS_MODE_B;
 
/* Get the connected lane count */
-   ufshcd_dme_get(hba, UIC_ARG_MIB(PA_CONNECTEDRXDATALANES), lanes[RX]);
-   ufshcd_dme_get(hba, UIC_ARG_MIB(PA_CONNECTEDTXDATALANES), lanes[TX]);
+   ufshcd_dme_get(hba, UIC_ARG_MIB(PA_CONNECTEDRXDATALANES),
+   pwr_info-lane_rx);
+   ufshcd_dme_get(hba, UIC_ARG_MIB(PA_CONNECTEDTXDATALANES),
+   pwr_info-lane_tx);
+
+   if (!pwr_info-lane_rx || !pwr_info-lane_tx) {
+   dev_err(hba-dev, %s: invalid connected lanes value. rx=%d, 
tx=%d\n,
+   __func__,
+   pwr_info-lane_rx,
+   pwr_info-lane_tx);
+   return -EINVAL;
+   }
 
/*
 * First, get the maximum gears of HS speed.
 * If a zero value, it means there is no HSGEAR capability.
 * Then, get the maximum gears of PWM speed.
 */
-   ufshcd_dme_get(hba, UIC_ARG_MIB(PA_MAXRXHSGEAR), gear[RX]);
-   if (!gear[RX]) {
-   ufshcd_dme_get(hba, UIC_ARG_MIB(PA_MAXRXPWMGEAR), gear[RX]);
-   pwr[RX] = SLOWAUTO_MODE;
+   ufshcd_dme_get(hba, UIC_ARG_MIB(PA_MAXRXHSGEAR), pwr_info-gear_rx);
+   if (!pwr_info-gear_rx) {
+   ufshcd_dme_get(hba, UIC_ARG_MIB(PA_MAXRXPWMGEAR),
+   pwr_info-gear_rx);
+   if (!pwr_info-gear_rx) {
+   dev_err(hba-dev, %s: invalid max pwm rx gear read = 
%d\n,
+   __func__, pwr_info-gear_rx);
+   return -EINVAL;
+   }
+   pwr_info-pwr_rx = SLOWAUTO_MODE;
}
 
-   ufshcd_dme_peer_get(hba, UIC_ARG_MIB(PA_MAXRXHSGEAR), gear[TX]);
-   if (!gear[TX]) {
+   ufshcd_dme_peer_get(hba, UIC_ARG_MIB(PA_MAXRXHSGEAR),
+   pwr_info-gear_tx);
+   if (!pwr_info-gear_tx) {
ufshcd_dme_peer_get(hba, UIC_ARG_MIB(PA_MAXRXPWMGEAR),
-   gear[TX]);
-   pwr[TX] = SLOWAUTO_MODE;
+   pwr_info-gear_tx);
+   if (!pwr_info-gear_tx) {
+   dev_err(hba-dev, %s: invalid max pwm tx gear read = 
%d\n,
+   __func__, pwr_info-gear_tx);
+   return -EINVAL;
+   }
+   pwr_info-pwr_tx = SLOWAUTO_MODE;
+   }
+
+   hba-max_pwr_info.is_valid = true;
+   return 0;
+}
+
+int ufshcd_change_power_mode(struct ufs_hba *hba,
+struct ufs_pa_layer_attr *pwr_mode)
+{
+   int ret;
+
+   /* if already configured to the requested pwr_mode */
+   if (pwr_mode-gear_rx == hba-pwr_info.gear_rx 
+   pwr_mode-gear_tx == hba

[PATCH/RESEND V5 00/17] UFS: Power management support

2014-09-24 Thread Dolev Raviv
This patch seies introduces support for power management in the driver as well 
as vendor specific initialization - registers, clocks, voltage regulators etc.

It includes also a rework for the init sequence and other PM pre-requisite such 
as write protection support, handling well-known LUN, error handling (retries), 
bkops, START_STOP unit command, and ICC levels settings.

--
Changes from V4:
 - Restored [01/16] scsi: support well known logical units to fix type issue
   and renamed [01/17] scsi: fixing the type for well known LUs
 - Add [02/17] scsi: sysfs: don't add scsi_device if its already added
   to help addressing Chris comments.
 - Squashed [10/17] scsi: ufs: introduce well known logical unit in ufs and
   [09/17] scsi: ufs: manually add well known logical and addressed most of
   Chris comments here.
 - Cleanup in [11/16] scsi: ufs: add UFS power management support to align
   it with comments made on previous patches.

Changes from V3:
 - Replaced [01/16] scsi: support well known logical units with
   [09/17] scsi: ufs: manually add well known logical
 - add patch [PATCH V4 05/17] scsi: ufs: add voting support for host
 - Fix couple of compilation issues introduced in V3
 - Add a NULL pointer test to hba-vops before accessing it
 - Changed disable/enable irq with request/free irq

Changes from V2:
 - Reordered scsi core patches
 - add patch [PATCH V3 02/16] scsi: balance out autopm get/put calls in
 - Minor changes/fixes to the patches:
* [PATCH V3 10/16] scsi: ufs: add UFS power management support
* [PATCH V3 12/16] scsi: ufs: Add support for clock gating
* [PATCH V3 16/16] scsi: ufs: definitions for phy interface
   In order to address community concerns, and as a result of further
   development and testing.

Changes from V1:
 - 6 new patches apended at the end
 - Allow overriding power configuration with controller support and
   preferences/capabilities Dolev Raviv
 - Allow overriding power choice with controller capabilities Dolev Raviv
 - Add support for clock gating and clock scaling Sahitya Tummala
 - Add capability to control the auto bkops during suspend Subhash Jadavani
 - Add misc changes for phy/unipro driver usage Dolev Raviv

Dolev Raviv (2):
  scsi: ufs: refactor configuring power mode
  scsi: ufs: definitions for phy interface

Raviv Shvili (1):
  scsi: ufs: add voting support for host controller power

Sahitya Tummala (3):
  scsi: ufs: Add support for clock gating
  scsi: ufs: Add freq-table-hz property for UFS device
  scsi: ufs: Add support for clock scaling using devfreq framework

Subhash Jadavani (6):
  scsi: fixing the type for well known LUs
  scsi: sysfs: don't add scsi_device if its already added
  scsi: ufs: refactor query descriptor API support
  scsi: ufs: manually add well known logical units
  scsi: ufs: add UFS power management support
  scsi: ufs: tune bkops while power managment events

Sujit Reddy Thumma (4):
  scsi: ufs: Allow vendor specific initialization
  scsi: ufs: Add regulator enable support
  scsi: ufs: Add clock initialization support
  scsi: ufs: improve init sequence

Yaniv Gardi (1):
  scsi: ufs: Active Power Mode - configuring bActiveICCLevel

 .../devicetree/bindings/ufs/ufshcd-pltfrm.txt  |   41 +
 drivers/scsi/scsi_scan.c   |8 +
 drivers/scsi/scsi_sysfs.c  |3 +
 drivers/scsi/ufs/Kconfig   |2 +
 drivers/scsi/ufs/ufs.h |  132 +-
 drivers/scsi/ufs/ufshcd-pci.c  |   55 +-
 drivers/scsi/ufs/ufshcd-pltfrm.c   |  291 ++-
 drivers/scsi/ufs/ufshcd.c  | 2519 ++--
 drivers/scsi/ufs/ufshcd.h  |  280 ++-
 drivers/scsi/ufs/ufshci.h  |9 +-
 drivers/scsi/ufs/unipro.h  |   56 +
 include/scsi/scsi.h|1 +
 12 files changed, 3095 insertions(+), 302 deletions(-)

-- 
1.8.5.2
-- 
QUALCOMM ISRAEL, on behalf of Qualcomm Innovation Center, Inc. is a member
of Code Aurora Forum, hosted by The Linux Foundation

--
To unsubscribe from this list: send the line unsubscribe linux-scsi in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH/RESEND V5 04/17] scsi: ufs: Add regulator enable support

2014-09-24 Thread Dolev Raviv
From: Sujit Reddy Thumma sthu...@codeaurora.org

UFS devices are powered by at most three external power supplies -
- VCC - The flash memory core power supply, 2.7V to 3.6V or 1.70V to 1.95V
- VCCQ - The controller and I/O power supply, 1.1V to 1.3V
- VCCQ2 - Secondary controller and/or I/O power supply, 1.65V to 1.95V

For some devices VCCQ or VCCQ2 are optional as they can be
generated using internal LDO inside the UFS device.

Add DT bindings for voltage regulators that can be controlled
from host driver.

Signed-off-by: Sujit Reddy Thumma sthu...@codeaurora.org
Signed-off-by: Dolev Raviv dra...@codeaurora.org

diff --git a/Documentation/devicetree/bindings/ufs/ufshcd-pltfrm.txt 
b/Documentation/devicetree/bindings/ufs/ufshcd-pltfrm.txt
index 20468b2..65e3117 100644
--- a/Documentation/devicetree/bindings/ufs/ufshcd-pltfrm.txt
+++ b/Documentation/devicetree/bindings/ufs/ufshcd-pltfrm.txt
@@ -8,9 +8,33 @@ Required properties:
 - interrupts: interrupt mapping for UFS host controller IRQ
 - reg   : registers mapping
 
+Optional properties:
+- vcc-supply: phandle to VCC supply regulator node
+- vccq-supply   : phandle to VCCQ supply regulator node
+- vccq2-supply  : phandle to VCCQ2 supply regulator node
+- vcc-supply-1p8: For embedded UFS devices, valid VCC range is 
1.7-1.95V
+  or 2.7-3.6V. This boolean property when set, 
specifies
+ to use low voltage range of 1.7-1.95V. Note for 
external
+ UFS cards this property is invalid and valid VCC 
range is
+ always 2.7-3.6V.
+- vcc-max-microamp  : specifies max. load that can be drawn from vcc supply
+- vccq-max-microamp : specifies max. load that can be drawn from vccq 
supply
+- vccq2-max-microamp: specifies max. load that can be drawn from vccq2 
supply
+
+Note: If above properties are not defined it can be assumed that the supply
+regulators are always on.
+
 Example:
ufshc@0xfc598000 {
compatible = jedec,ufs-1.1;
reg = 0xfc598000 0x800;
interrupts = 0 28 0;
+
+   vcc-supply = xxx_reg1;
+   vcc-supply-1p8;
+   vccq-supply = xxx_reg2;
+   vccq2-supply = xxx_reg3;
+   vcc-max-microamp = 50;
+   vccq-max-microamp = 20;
+   vccq2-max-microamp = 20;
};
diff --git a/drivers/scsi/ufs/ufs.h b/drivers/scsi/ufs/ufs.h
index fafcf5e..729ce7d 100644
--- a/drivers/scsi/ufs/ufs.h
+++ b/drivers/scsi/ufs/ufs.h
@@ -362,4 +362,29 @@ struct ufs_query_res {
struct utp_upiu_query upiu_res;
 };
 
+#define UFS_VREG_VCC_MIN_UV   270 /* uV */
+#define UFS_VREG_VCC_MAX_UV   360 /* uV */
+#define UFS_VREG_VCC_1P8_MIN_UV170 /* uV */
+#define UFS_VREG_VCC_1P8_MAX_UV195 /* uV */
+#define UFS_VREG_VCCQ_MIN_UV  110 /* uV */
+#define UFS_VREG_VCCQ_MAX_UV  130 /* uV */
+#define UFS_VREG_VCCQ2_MIN_UV 165 /* uV */
+#define UFS_VREG_VCCQ2_MAX_UV 195 /* uV */
+
+struct ufs_vreg {
+   struct regulator *reg;
+   const char *name;
+   bool enabled;
+   int min_uV;
+   int max_uV;
+   int min_uA;
+   int max_uA;
+};
+
+struct ufs_vreg_info {
+   struct ufs_vreg *vcc;
+   struct ufs_vreg *vccq;
+   struct ufs_vreg *vccq2;
+};
+
 #endif /* End of Header */
diff --git a/drivers/scsi/ufs/ufshcd-pltfrm.c b/drivers/scsi/ufs/ufshcd-pltfrm.c
index d727b1a..51e47c4 100644
--- a/drivers/scsi/ufs/ufshcd-pltfrm.c
+++ b/drivers/scsi/ufs/ufshcd-pltfrm.c
@@ -53,6 +53,99 @@ static struct ufs_hba_variant_ops *get_variant_ops(struct 
device *dev)
return NULL;
 }
 
+#define MAX_PROP_SIZE 32
+static int ufshcd_populate_vreg(struct device *dev, const char *name,
+   struct ufs_vreg **out_vreg)
+{
+   int ret = 0;
+   char prop_name[MAX_PROP_SIZE];
+   struct ufs_vreg *vreg = NULL;
+   struct device_node *np = dev-of_node;
+
+   if (!np) {
+   dev_err(dev, %s: non DT initialization\n, __func__);
+   goto out;
+   }
+
+   snprintf(prop_name, MAX_PROP_SIZE, %s-supply, name);
+   if (!of_parse_phandle(np, prop_name, 0)) {
+   dev_info(dev, %s: Unable to find %s regulator, assuming 
enabled\n,
+   __func__, prop_name);
+   goto out;
+   }
+
+   vreg = devm_kzalloc(dev, sizeof(*vreg), GFP_KERNEL);
+   if (!vreg) {
+   dev_err(dev, No memory for %s regulator\n, name);
+   goto out;
+   }
+
+   vreg-name = kstrdup(name, GFP_KERNEL);
+
+   snprintf(prop_name, MAX_PROP_SIZE, %s-max-microamp, name);
+   ret = of_property_read_u32(np, prop_name, vreg-max_uA);
+   if (ret) {
+   dev_err(dev, %s: unable to find %s err %d\n,
+   __func__, prop_name, ret);
+   goto out_free

[PATCH/RESEND V4 07/17] scsi: ufs: improve init sequence

2014-09-23 Thread Dolev Raviv
From: Sujit Reddy Thumma sthu...@codeaurora.org

In -hce_enable_notify() callback the vendor specific initialization
may carry out additional DME configuration using UIC commands and
hence the UIC command completion interrupt enable bit should be set
before the post reset notification.
Add retries if the link-startup fails. This is required since due to
hardware timing issues, the Uni-Pro link-startup might fail. The UFS
HCI recovery procedure contradicts the Uni-Pro sequence. The UFS HCI
specifies to resend DME_LINKSTARTUP command after IS.ULLS (link-lost
interrupt) is received. The Uni-Pro specifies that if link-startup
fails the link is in down state. The link-lost is indicated to the
DME user only when the link is up. Hence, the UFS HCI recovery procedure
of waiting for IS.ULLS and retrying link-startup may not work properly.

At the end, if detection fails, power off (disable clocks, regulators,
phy) if the UFS device detection fails. This saves power while UFS device
is not embedded into the system.

Signed-off-by: Sujit Reddy Thumma sthu...@codeaurora.org
Signed-off-by: Dolev Raviv dra...@codeaurora.org

diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index 3f2b30d..af29d4c 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -62,6 +62,12 @@
 /* Task management command timeout */
 #define TM_CMD_TIMEOUT 100 /* msecs */
 
+/* maximum number of link-startup retries */
+#define DME_LINKSTARTUP_RETRIES 3
+
+/* maximum number of reset retries before giving up */
+#define MAX_HOST_RESET_RETRIES 5
+
 /* Expose the flag value from utp_upiu_query.value */
 #define MASK_QUERY_UPIU_FLAG_LOC 0xFF
 
@@ -137,6 +143,8 @@ static void ufshcd_tmc_handler(struct ufs_hba *hba);
 static void ufshcd_async_scan(void *data, async_cookie_t cookie);
 static int ufshcd_reset_and_restore(struct ufs_hba *hba);
 static int ufshcd_clear_tm_cmd(struct ufs_hba *hba, int tag);
+static void ufshcd_hba_exit(struct ufs_hba *hba);
+static int ufshcd_probe_hba(struct ufs_hba *hba);
 
 /*
  * ufshcd_wait_for_register - wait for register value to change
@@ -2043,6 +2051,9 @@ static int ufshcd_hba_enable(struct ufs_hba *hba)
msleep(5);
}
 
+   /* enable UIC related interrupts */
+   ufshcd_enable_intr(hba, UIC_COMMAND_COMPL);
+
if (hba-vops  hba-vops-hce_enable_notify)
hba-vops-hce_enable_notify(hba, POST_CHANGE);
 
@@ -2058,23 +2069,33 @@ static int ufshcd_hba_enable(struct ufs_hba *hba)
 static int ufshcd_link_startup(struct ufs_hba *hba)
 {
int ret;
+   int retries = DME_LINKSTARTUP_RETRIES;
 
-   /* enable UIC related interrupts */
-   ufshcd_enable_intr(hba, UIC_COMMAND_COMPL);
+   do {
+   if (hba-vops  hba-vops-link_startup_notify)
+   hba-vops-link_startup_notify(hba, PRE_CHANGE);
 
-   if (hba-vops  hba-vops-link_startup_notify)
-   hba-vops-link_startup_notify(hba, PRE_CHANGE);
+   ret = ufshcd_dme_link_startup(hba);
 
-   ret = ufshcd_dme_link_startup(hba);
-   if (ret)
-   goto out;
+   /* check if device is detected by inter-connect layer */
+   if (!ret  !ufshcd_is_device_present(hba)) {
+   dev_err(hba-dev, %s: Device not present\n, __func__);
+   ret = -ENXIO;
+   goto out;
+   }
 
-   /* check if device is detected by inter-connect layer */
-   if (!ufshcd_is_device_present(hba)) {
-   dev_err(hba-dev, %s: Device not present\n, __func__);
-   ret = -ENXIO;
+   /*
+* DME link lost indication is only received when link is up,
+* but we can't be sure if the link is up until link startup
+* succeeds. So reset the local Uni-Pro and try again.
+*/
+   if (ret  ufshcd_hba_enable(hba))
+   goto out;
+   } while (ret  retries--);
+
+   if (ret)
+   /* failed to get the link up... retire */
goto out;
-   }
 
/* Include any host controller configuration via UIC commands */
if (hba-vops  hba-vops-link_startup_notify) {
@@ -3139,7 +3160,6 @@ out:
 static int ufshcd_host_reset_and_restore(struct ufs_hba *hba)
 {
int err;
-   async_cookie_t cookie;
unsigned long flags;
 
/* Reset the host controller */
@@ -3152,10 +3172,9 @@ static int ufshcd_host_reset_and_restore(struct ufs_hba 
*hba)
goto out;
 
/* Establish the link again and restore the device */
-   cookie = async_schedule(ufshcd_async_scan, hba);
-   /* wait for async scan to be completed */
-   async_synchronize_cookie(++cookie);
-   if (hba-ufshcd_state != UFSHCD_STATE_OPERATIONAL)
+   err = ufshcd_probe_hba(hba);
+
+   if (!err  (hba-ufshcd_state != UFSHCD_STATE_OPERATIONAL))
err = -EIO;
 out

[PATCH/RESEND V4 06/17] scsi: ufs: refactor query descriptor API support

2014-09-23 Thread Dolev Raviv
From: Subhash Jadavani subha...@codeaurora.org

Currently reading query descriptor is more tightened to each
descriptor type. This patch generalize the approach and allows
reading any parameter from any query descriptor.

Signed-off-by: Subhash Jadavani subha...@codeaurora.org
Signed-off-by: Dolev Raviv dra...@codeaurora.org

diff --git a/drivers/scsi/ufs/ufs.h b/drivers/scsi/ufs/ufs.h
index 9bb6919..f76a304 100644
--- a/drivers/scsi/ufs/ufs.h
+++ b/drivers/scsi/ufs/ufs.h
@@ -50,6 +50,8 @@
cpu_to_be32((byte3  24) | (byte2  16) |\
 (byte1  8) | (byte0))
 
+#define UFS_UPIU_MAX_GENERAL_LUN   8
+
 /*
  * UFS Protocol Information Unit related definitions
  */
@@ -129,10 +131,29 @@ enum desc_idn {
QUERY_DESC_IDN_RFU_1= 0x6,
QUERY_DESC_IDN_GEOMETRY = 0x7,
QUERY_DESC_IDN_POWER= 0x8,
-   QUERY_DESC_IDN_RFU_2= 0x9,
+   QUERY_DESC_IDN_MAX,
+};
+
+enum desc_header_offset {
+   QUERY_DESC_LENGTH_OFFSET= 0x00,
+   QUERY_DESC_DESC_TYPE_OFFSET = 0x01,
+};
+
+enum ufs_desc_max_size {
+   QUERY_DESC_DEVICE_MAX_SIZE  = 0x1F,
+   QUERY_DESC_CONFIGURAION_MAX_SIZE= 0x90,
+   QUERY_DESC_UNIT_MAX_SIZE= 0x23,
+   QUERY_DESC_INTERCONNECT_MAX_SIZE= 0x06,
+   /*
+* Max. 126 UNICODE characters (2 bytes per character) plus 2 bytes
+* of descriptor header.
+*/
+   QUERY_DESC_STRING_MAX_SIZE  = 0xFE,
+   QUERY_DESC_GEOMETRY_MAZ_SIZE= 0x44,
+   QUERY_DESC_POWER_MAX_SIZE   = 0x62,
+   QUERY_DESC_RFU_MAX_SIZE = 0x00,
 };
 
-#define UNIT_DESC_MAX_SIZE   0x22
 /* Unit descriptor parameters offsets in bytes*/
 enum unit_desc_param {
UNIT_DESC_PARAM_LEN = 0x0,
diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index 26301b8..3f2b30d 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -78,6 +78,19 @@
_ret;   \
})
 
+static u32 ufs_query_desc_max_size[] = {
+   QUERY_DESC_DEVICE_MAX_SIZE,
+   QUERY_DESC_CONFIGURAION_MAX_SIZE,
+   QUERY_DESC_UNIT_MAX_SIZE,
+   QUERY_DESC_RFU_MAX_SIZE,
+   QUERY_DESC_INTERCONNECT_MAX_SIZE,
+   QUERY_DESC_STRING_MAX_SIZE,
+   QUERY_DESC_RFU_MAX_SIZE,
+   QUERY_DESC_GEOMETRY_MAZ_SIZE,
+   QUERY_DESC_POWER_MAX_SIZE,
+   QUERY_DESC_RFU_MAX_SIZE,
+};
+
 enum {
UFSHCD_MAX_CHANNEL  = 0,
UFSHCD_MAX_ID   = 1,
@@ -124,8 +137,6 @@ static void ufshcd_tmc_handler(struct ufs_hba *hba);
 static void ufshcd_async_scan(void *data, async_cookie_t cookie);
 static int ufshcd_reset_and_restore(struct ufs_hba *hba);
 static int ufshcd_clear_tm_cmd(struct ufs_hba *hba, int tag);
-static int ufshcd_read_sdev_qdepth(struct ufs_hba *hba,
-   struct scsi_device *sdev);
 
 /*
  * ufshcd_wait_for_register - wait for register value to change
@@ -1393,6 +1404,115 @@ out:
 }
 
 /**
+ * ufshcd_read_desc_param - read the specified descriptor parameter
+ * @hba: Pointer to adapter instance
+ * @desc_id: descriptor idn value
+ * @desc_index: descriptor index
+ * @param_offset: offset of the parameter to read
+ * @param_read_buf: pointer to buffer where parameter would be read
+ * @param_size: sizeof(param_read_buf)
+ *
+ * Return 0 in case of success, non-zero otherwise
+ */
+static int ufshcd_read_desc_param(struct ufs_hba *hba,
+ enum desc_idn desc_id,
+ int desc_index,
+ u32 param_offset,
+ u8 *param_read_buf,
+ u32 param_size)
+{
+   int ret;
+   u8 *desc_buf;
+   u32 buff_len;
+   bool is_kmalloc = true;
+
+   /* safety checks */
+   if (desc_id = QUERY_DESC_IDN_MAX)
+   return -EINVAL;
+
+   buff_len = ufs_query_desc_max_size[desc_id];
+   if ((param_offset + param_size)  buff_len)
+   return -EINVAL;
+
+   if (!param_offset  (param_size == buff_len)) {
+   /* memory space already available to hold full descriptor */
+   desc_buf = param_read_buf;
+   is_kmalloc = false;
+   } else {
+   /* allocate memory to hold full descriptor */
+   desc_buf = kmalloc(buff_len, GFP_KERNEL);
+   if (!desc_buf)
+   return -ENOMEM;
+   }
+
+   ret = ufshcd_query_descriptor(hba, UPIU_QUERY_OPCODE_READ_DESC,
+ desc_id, desc_index, 0, desc_buf,
+ buff_len);
+
+   if (ret || (buff_len  ufs_query_desc_max_size[desc_id]) ||
+   (desc_buf[QUERY_DESC_LENGTH_OFFSET] !=
+ufs_query_desc_max_size[desc_id

[PATCH V4 05/17] scsi: ufs: add voting support for host controller power

2014-09-23 Thread Dolev Raviv
From: Raviv Shvili rshv...@codeaurora.org

Add the support for voting of the regulator powering the
host controller logic.

Signed-off-by: Raviv Shvili rshv...@codeaurora.org
Signed-off-by: Subhash Jadavani subha...@codeaurora.org
Signed-off-by: Dolev Raviv dra...@codeaurora.org

diff --git a/Documentation/devicetree/bindings/ufs/ufshcd-pltfrm.txt 
b/Documentation/devicetree/bindings/ufs/ufshcd-pltfrm.txt
index b0f791a..fb1234e 100644
--- a/Documentation/devicetree/bindings/ufs/ufshcd-pltfrm.txt
+++ b/Documentation/devicetree/bindings/ufs/ufshcd-pltfrm.txt
@@ -9,6 +9,7 @@ Required properties:
 - reg   : registers mapping
 
 Optional properties:
+- vdd-hba-supply: phandle to UFS host controller supply regulator node
 - vcc-supply: phandle to VCC supply regulator node
 - vccq-supply   : phandle to VCCQ supply regulator node
 - vccq2-supply  : phandle to VCCQ2 supply regulator node
@@ -20,6 +21,7 @@ Optional properties:
 - vcc-max-microamp  : specifies max. load that can be drawn from vcc supply
 - vccq-max-microamp : specifies max. load that can be drawn from vccq 
supply
 - vccq2-max-microamp: specifies max. load that can be drawn from vccq2 
supply
+- name-fixed-regulator : boolean property specifying that name-supply is a 
fixed regulator
 
 - clocks: List of phandle and clock specifier pairs
 - clock-names   : List of clock input name strings sorted in the same
@@ -39,6 +41,8 @@ Example:
reg = 0xfc598000 0x800;
interrupts = 0 28 0;
 
+   vdd-hba-supply = xxx_reg0;
+   vdd-hba-fixed-regulator;
vcc-supply = xxx_reg1;
vcc-supply-1p8;
vccq-supply = xxx_reg2;
diff --git a/drivers/scsi/ufs/ufs.h b/drivers/scsi/ufs/ufs.h
index 729ce7d..9bb6919 100644
--- a/drivers/scsi/ufs/ufs.h
+++ b/drivers/scsi/ufs/ufs.h
@@ -385,6 +385,7 @@ struct ufs_vreg_info {
struct ufs_vreg *vcc;
struct ufs_vreg *vccq;
struct ufs_vreg *vccq2;
+   struct ufs_vreg *vdd_hba;
 };
 
 #endif /* End of Header */
diff --git a/drivers/scsi/ufs/ufshcd-pltfrm.c b/drivers/scsi/ufs/ufshcd-pltfrm.c
index 642d80f..dde4e6e 100644
--- a/drivers/scsi/ufs/ufshcd-pltfrm.c
+++ b/drivers/scsi/ufs/ufshcd-pltfrm.c
@@ -147,6 +147,11 @@ static int ufshcd_populate_vreg(struct device *dev, const 
char *name,
 
vreg-name = kstrdup(name, GFP_KERNEL);
 
+   /* if fixed regulator no need further initialization */
+   snprintf(prop_name, MAX_PROP_SIZE, %s-fixed-regulator, name);
+   if (of_property_read_bool(np, prop_name))
+   goto out;
+
snprintf(prop_name, MAX_PROP_SIZE, %s-max-microamp, name);
ret = of_property_read_u32(np, prop_name, vreg-max_uA);
if (ret) {
@@ -198,6 +203,10 @@ static int ufshcd_parse_regulator_info(struct ufs_hba *hba)
struct device *dev = hba-dev;
struct ufs_vreg_info *info = hba-vreg_info;
 
+   err = ufshcd_populate_vreg(dev, vdd-hba, info-vdd_hba);
+   if (err)
+   goto out;
+
err = ufshcd_populate_vreg(dev, vcc, info-vcc);
if (err)
goto out;
diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index b033702..26301b8 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -3311,6 +3311,16 @@ out:
return ret;
 }
 
+static int ufshcd_setup_hba_vreg(struct ufs_hba *hba, bool on)
+{
+   struct ufs_vreg_info *info = hba-vreg_info;
+
+   if (info)
+   return ufshcd_toggle_vreg(hba-dev, info-vdd_hba, on);
+
+   return 0;
+}
+
 static int ufshcd_get_vreg(struct device *dev, struct ufs_vreg *vreg)
 {
int ret = 0;
@@ -3350,6 +3360,16 @@ out:
return ret;
 }
 
+static int ufshcd_init_hba_vreg(struct ufs_hba *hba)
+{
+   struct ufs_vreg_info *info = hba-vreg_info;
+
+   if (info)
+   return ufshcd_get_vreg(hba-dev, info-vdd_hba);
+
+   return 0;
+}
+
 static int ufshcd_setup_clocks(struct ufs_hba *hba, bool on)
 {
int ret = 0;
@@ -3483,14 +3503,29 @@ static int ufshcd_hba_init(struct ufs_hba *hba)
 {
int err;
 
-   err = ufshcd_init_clocks(hba);
+   /*
+* Handle host controller power separately from the UFS device power
+* rails as it will help controlling the UFS host controller power
+* collapse easily which is different than UFS device power collapse.
+* Also, enable the host controller power before we go ahead with rest
+* of the initialization here.
+*/
+   err = ufshcd_init_hba_vreg(hba);
if (err)
goto out;
 
-   err = ufshcd_setup_clocks(hba, true);
+   err = ufshcd_setup_hba_vreg(hba, true);
if (err)
goto out;
 
+   err = ufshcd_init_clocks(hba);
+   if (err)
+   goto out_disable_hba_vreg;
+
+   err = ufshcd_setup_clocks(hba, true);
+   if (err

[PATCH/RESEND V4 00/17] UFS: Power management support

2014-09-23 Thread Dolev Raviv
This patch seies introduces support for power management in the driver as well 
as vendor specific initialization - registers, clocks, voltage regulators etc.

It includes also a rework for the init sequence and other PM pre-requisite such 
as write protection support, handling well-known LUN, error handling (retries), 
bkops, START_STOP unit command, and ICC levels settings.

--
Changes from V2:
 - Replaced [01/16] scsi: support well known logical units with
   [09/17] scsi: ufs: manually add well known logical
 - add patch [PATCH V4 05/17] scsi: ufs: add voting support for host
 - Fix couple of compilation issues introduced in V3
 - Add a NULL pointer test to hba-vops before accessing it
 - Changed disable/enable irq with request/free irq

Changes from V2:
 - Reordered scsi core patches
 - add patch [PATCH V3 02/16] scsi: balance out autopm get/put calls in
 - Minor changes/fixes to the patches:
* [PATCH V3 10/16] scsi: ufs: add UFS power management support
* [PATCH V3 12/16] scsi: ufs: Add support for clock gating
* [PATCH V3 16/16] scsi: ufs: definitions for phy interface
   In order to address community concerns, and as a result of further
   development and testing.

Changes from V1:
 - 6 new patches apended at the end
 - Allow overriding power configuration with controller support and
   preferences/capabilities Dolev Raviv
 - Allow overriding power choice with controller capabilities Dolev Raviv
 - Add support for clock gating and clock scaling Sahitya Tummala
 - Add capability to control the auto bkops during suspend Subhash Jadavani
 - Add misc changes for phy/unipro driver usage Dolev Raviv

Dolev Raviv (2):
  scsi: ufs: refactor configuring power mode
  scsi: ufs: definitions for phy interface

Raviv Shvili (1):
  scsi: ufs: add voting support for host controller power

Sahitya Tummala (3):
  scsi: ufs: Add support for clock gating
  scsi: ufs: Add freq-table-hz property for UFS device
  scsi: ufs: Add support for clock scaling using devfreq framework

Subhash Jadavani (6):
  scsi: balance out autopm get/put calls in scsi_sysfs_add_sdev()
  scsi: ufs: refactor query descriptor API support
  scsi: ufs: manually add well known logical units
  scsi: ufs: introduce well known logical unit in ufs
  scsi: ufs: add UFS power management support
  scsi: ufs: tune bkops while power managment events

Sujit Reddy Thumma (4):
  scsi: ufs: Allow vendor specific initialization
  scsi: ufs: Add regulator enable support
  scsi: ufs: Add clock initialization support
  scsi: ufs: improve init sequence

Yaniv Gardi (1):
  scsi: ufs: Active Power Mode - configuring bActiveICCLevel

 .../devicetree/bindings/ufs/ufshcd-pltfrm.txt  |   41 +
 drivers/scsi/scsi_sysfs.c  |5 +-
 drivers/scsi/sd.c  |2 +
 drivers/scsi/sr.c  |2 +
 drivers/scsi/st.c  |2 +
 drivers/scsi/ufs/Kconfig   |2 +
 drivers/scsi/ufs/ufs.h |  132 +-
 drivers/scsi/ufs/ufshcd-pci.c  |   55 +-
 drivers/scsi/ufs/ufshcd-pltfrm.c   |  291 ++-
 drivers/scsi/ufs/ufshcd.c  | 2481 ++--
 drivers/scsi/ufs/ufshcd.h  |  277 ++-
 drivers/scsi/ufs/ufshci.h  |9 +-
 drivers/scsi/ufs/unipro.h  |   56 +
 13 files changed, 3047 insertions(+), 308 deletions(-)

-- 
1.8.5.2
-- 
QUALCOMM ISRAEL, on behalf of Qualcomm Innovation Center, Inc. is a member
of Code Aurora Forum, hosted by The Linux Foundation

--
To unsubscribe from this list: send the line unsubscribe linux-scsi in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH/RESEND V4 01/17] scsi: balance out autopm get/put calls in scsi_sysfs_add_sdev()

2014-09-23 Thread Dolev Raviv
From: Subhash Jadavani subha...@codeaurora.org

SCSI Well-known logical units generally don't have any scsi driver
associated with it which means no one will call scsi_autopm_put_device()
on these wlun scsi devices and this would result in keeping the
corresponding scsi device always active (hence LLD can't be suspended as
well). Same exact problem can be seen for other scsi device representing
normal logical unit whose driver is yet to be loaded. This patch fixes
the above problem with this approach:

- make the scsi_autopm_put_device call at the end of scsi_sysfs_add_sdev
  to make it balance out the get earlier in the function.
- let drivers do paired get/put calls in their probe methods.

Signed-off-by: Subhash Jadavani subha...@codeaurora.org
Signed-off-by: Dolev Raviv dra...@codeaurora.org

diff --git a/drivers/scsi/scsi_sysfs.c b/drivers/scsi/scsi_sysfs.c
index 8b4105a..3524b68 100644
--- a/drivers/scsi/scsi_sysfs.c
+++ b/drivers/scsi/scsi_sysfs.c
@@ -1044,10 +1044,6 @@ int scsi_sysfs_add_sdev(struct scsi_device *sdev)
pm_runtime_enable(sdev-sdev_gendev);
scsi_autopm_put_target(starget);
 
-   /* The following call will keep sdev active indefinitely, until
-* its driver does a corresponding scsi_autopm_pm_device().  Only
-* drivers supporting autosuspend will do this.
-*/
scsi_autopm_get_device(sdev);
 
error = device_add(sdev-sdev_gendev);
@@ -1085,6 +1081,7 @@ int scsi_sysfs_add_sdev(struct scsi_device *sdev)
}
}
 
+   scsi_autopm_put_device(sdev);
return error;
 }
 
diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c
index aa43496..0cb5c9f 100644
--- a/drivers/scsi/sd.c
+++ b/drivers/scsi/sd.c
@@ -2965,6 +2965,7 @@ static int sd_probe(struct device *dev)
int index;
int error;
 
+   scsi_autopm_get_device(sdp);
error = -ENODEV;
if (sdp-type != TYPE_DISK  sdp-type != TYPE_MOD  sdp-type != 
TYPE_RBC)
goto out;
@@ -3041,6 +3042,7 @@ static int sd_probe(struct device *dev)
  out_free:
kfree(sdkp);
  out:
+   scsi_autopm_put_device(sdp);
return error;
 }
 
diff --git a/drivers/scsi/sr.c b/drivers/scsi/sr.c
index 7eeb936..2de44cc 100644
--- a/drivers/scsi/sr.c
+++ b/drivers/scsi/sr.c
@@ -657,6 +657,7 @@ static int sr_probe(struct device *dev)
struct scsi_cd *cd;
int minor, error;
 
+   scsi_autopm_get_device(sdev);
error = -ENODEV;
if (sdev-type != TYPE_ROM  sdev-type != TYPE_WORM)
goto fail;
@@ -744,6 +745,7 @@ fail_put:
 fail_free:
kfree(cd);
 fail:
+   scsi_autopm_put_device(sdev);
return error;
 }
 
diff --git a/drivers/scsi/st.c b/drivers/scsi/st.c
index aff9689..d3fd6e8 100644
--- a/drivers/scsi/st.c
+++ b/drivers/scsi/st.c
@@ -4105,6 +4105,7 @@ static int st_probe(struct device *dev)
return -ENODEV;
}
 
+   scsi_autopm_get_device(SDp);
i = queue_max_segments(SDp-request_queue);
if (st_max_sg_segs  i)
i = st_max_sg_segs;
@@ -4244,6 +4245,7 @@ out_put_disk:
 out_buffer_free:
kfree(buffer);
 out:
+   scsi_autopm_put_device(SDp);
return -ENODEV;
 };
 
-- 
1.8.5.2

-- 
QUALCOMM ISRAEL, on behalf of Qualcomm Innovation Center, Inc. is a member
of Code Aurora Forum, hosted by The Linux Foundation

--
To unsubscribe from this list: send the line unsubscribe linux-scsi in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH/RESEND V4 03/17] scsi: ufs: Add regulator enable support

2014-09-23 Thread Dolev Raviv
From: Sujit Reddy Thumma sthu...@codeaurora.org

UFS devices are powered by at most three external power supplies -
- VCC - The flash memory core power supply, 2.7V to 3.6V or 1.70V to 1.95V
- VCCQ - The controller and I/O power supply, 1.1V to 1.3V
- VCCQ2 - Secondary controller and/or I/O power supply, 1.65V to 1.95V

For some devices VCCQ or VCCQ2 are optional as they can be
generated using internal LDO inside the UFS device.

Add DT bindings for voltage regulators that can be controlled
from host driver.

Signed-off-by: Sujit Reddy Thumma sthu...@codeaurora.org
Signed-off-by: Dolev Raviv dra...@codeaurora.org

diff --git a/Documentation/devicetree/bindings/ufs/ufshcd-pltfrm.txt 
b/Documentation/devicetree/bindings/ufs/ufshcd-pltfrm.txt
index 20468b2..65e3117 100644
--- a/Documentation/devicetree/bindings/ufs/ufshcd-pltfrm.txt
+++ b/Documentation/devicetree/bindings/ufs/ufshcd-pltfrm.txt
@@ -8,9 +8,33 @@ Required properties:
 - interrupts: interrupt mapping for UFS host controller IRQ
 - reg   : registers mapping
 
+Optional properties:
+- vcc-supply: phandle to VCC supply regulator node
+- vccq-supply   : phandle to VCCQ supply regulator node
+- vccq2-supply  : phandle to VCCQ2 supply regulator node
+- vcc-supply-1p8: For embedded UFS devices, valid VCC range is 
1.7-1.95V
+  or 2.7-3.6V. This boolean property when set, 
specifies
+ to use low voltage range of 1.7-1.95V. Note for 
external
+ UFS cards this property is invalid and valid VCC 
range is
+ always 2.7-3.6V.
+- vcc-max-microamp  : specifies max. load that can be drawn from vcc supply
+- vccq-max-microamp : specifies max. load that can be drawn from vccq 
supply
+- vccq2-max-microamp: specifies max. load that can be drawn from vccq2 
supply
+
+Note: If above properties are not defined it can be assumed that the supply
+regulators are always on.
+
 Example:
ufshc@0xfc598000 {
compatible = jedec,ufs-1.1;
reg = 0xfc598000 0x800;
interrupts = 0 28 0;
+
+   vcc-supply = xxx_reg1;
+   vcc-supply-1p8;
+   vccq-supply = xxx_reg2;
+   vccq2-supply = xxx_reg3;
+   vcc-max-microamp = 50;
+   vccq-max-microamp = 20;
+   vccq2-max-microamp = 20;
};
diff --git a/drivers/scsi/ufs/ufs.h b/drivers/scsi/ufs/ufs.h
index fafcf5e..729ce7d 100644
--- a/drivers/scsi/ufs/ufs.h
+++ b/drivers/scsi/ufs/ufs.h
@@ -362,4 +362,29 @@ struct ufs_query_res {
struct utp_upiu_query upiu_res;
 };
 
+#define UFS_VREG_VCC_MIN_UV   270 /* uV */
+#define UFS_VREG_VCC_MAX_UV   360 /* uV */
+#define UFS_VREG_VCC_1P8_MIN_UV170 /* uV */
+#define UFS_VREG_VCC_1P8_MAX_UV195 /* uV */
+#define UFS_VREG_VCCQ_MIN_UV  110 /* uV */
+#define UFS_VREG_VCCQ_MAX_UV  130 /* uV */
+#define UFS_VREG_VCCQ2_MIN_UV 165 /* uV */
+#define UFS_VREG_VCCQ2_MAX_UV 195 /* uV */
+
+struct ufs_vreg {
+   struct regulator *reg;
+   const char *name;
+   bool enabled;
+   int min_uV;
+   int max_uV;
+   int min_uA;
+   int max_uA;
+};
+
+struct ufs_vreg_info {
+   struct ufs_vreg *vcc;
+   struct ufs_vreg *vccq;
+   struct ufs_vreg *vccq2;
+};
+
 #endif /* End of Header */
diff --git a/drivers/scsi/ufs/ufshcd-pltfrm.c b/drivers/scsi/ufs/ufshcd-pltfrm.c
index d727b1a..51e47c4 100644
--- a/drivers/scsi/ufs/ufshcd-pltfrm.c
+++ b/drivers/scsi/ufs/ufshcd-pltfrm.c
@@ -53,6 +53,99 @@ static struct ufs_hba_variant_ops *get_variant_ops(struct 
device *dev)
return NULL;
 }
 
+#define MAX_PROP_SIZE 32
+static int ufshcd_populate_vreg(struct device *dev, const char *name,
+   struct ufs_vreg **out_vreg)
+{
+   int ret = 0;
+   char prop_name[MAX_PROP_SIZE];
+   struct ufs_vreg *vreg = NULL;
+   struct device_node *np = dev-of_node;
+
+   if (!np) {
+   dev_err(dev, %s: non DT initialization\n, __func__);
+   goto out;
+   }
+
+   snprintf(prop_name, MAX_PROP_SIZE, %s-supply, name);
+   if (!of_parse_phandle(np, prop_name, 0)) {
+   dev_info(dev, %s: Unable to find %s regulator, assuming 
enabled\n,
+   __func__, prop_name);
+   goto out;
+   }
+
+   vreg = devm_kzalloc(dev, sizeof(*vreg), GFP_KERNEL);
+   if (!vreg) {
+   dev_err(dev, No memory for %s regulator\n, name);
+   goto out;
+   }
+
+   vreg-name = kstrdup(name, GFP_KERNEL);
+
+   snprintf(prop_name, MAX_PROP_SIZE, %s-max-microamp, name);
+   ret = of_property_read_u32(np, prop_name, vreg-max_uA);
+   if (ret) {
+   dev_err(dev, %s: unable to find %s err %d\n,
+   __func__, prop_name, ret);
+   goto out_free

[PATCH/RESEND V4 02/17] scsi: ufs: Allow vendor specific initialization

2014-09-23 Thread Dolev Raviv
From: Sujit Reddy Thumma sthu...@codeaurora.org

Some vendor specific controller versions might need to configure
vendor specific - registers, clocks, voltage regulators etc. to
initialize the host controller UTP layer and Uni-Pro stack.
Provide some common initialization operations that can be used
to configure vendor specifics. The methods can be extended in
future, for example, for power mode transitions.

The operations are vendor/board specific and hence determined with
the help of compatible property in device tree.

Signed-off-by: Sujit Reddy Thumma sthu...@codeaurora.org
Signed-off-by: Dolev Raviv dra...@codeaurora.org

diff --git a/drivers/scsi/ufs/ufshcd-pci.c b/drivers/scsi/ufs/ufshcd-pci.c
index afaabe2..7a6edbc 100644
--- a/drivers/scsi/ufs/ufshcd-pci.c
+++ b/drivers/scsi/ufs/ufshcd-pci.c
@@ -164,7 +164,13 @@ ufshcd_pci_probe(struct pci_dev *pdev, const struct 
pci_device_id *id)
 
mmio_base = pcim_iomap_table(pdev)[0];
 
-   err = ufshcd_init(pdev-dev, hba, mmio_base, pdev-irq);
+   err = ufshcd_alloc_host(pdev-dev, hba);
+   if (err) {
+   dev_err(pdev-dev, Allocation failed\n);
+   return err;
+   }
+
+   err = ufshcd_init(hba, mmio_base, pdev-irq);
if (err) {
dev_err(pdev-dev, Initialization failed\n);
return err;
diff --git a/drivers/scsi/ufs/ufshcd-pltfrm.c b/drivers/scsi/ufs/ufshcd-pltfrm.c
index 5e46232..d727b1a 100644
--- a/drivers/scsi/ufs/ufshcd-pltfrm.c
+++ b/drivers/scsi/ufs/ufshcd-pltfrm.c
@@ -35,9 +35,24 @@
 
 #include linux/platform_device.h
 #include linux/pm_runtime.h
+#include linux/of.h
 
 #include ufshcd.h
 
+static const struct of_device_id ufs_of_match[];
+static struct ufs_hba_variant_ops *get_variant_ops(struct device *dev)
+{
+   if (dev-of_node) {
+   const struct of_device_id *match;
+
+   match = of_match_node(ufs_of_match, dev-of_node);
+   if (match)
+   return (struct ufs_hba_variant_ops *)match-data;
+   }
+
+   return NULL;
+}
+
 #ifdef CONFIG_PM
 /**
  * ufshcd_pltfrm_suspend - suspend power management function
@@ -138,8 +153,8 @@ static int ufshcd_pltfrm_probe(struct platform_device *pdev)
 
mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
mmio_base = devm_ioremap_resource(dev, mem_res);
-   if (IS_ERR(mmio_base)) {
-   err = PTR_ERR(mmio_base);
+   if (IS_ERR(*(void **)mmio_base)) {
+   err = PTR_ERR(*(void **)mmio_base);
goto out;
}
 
@@ -150,10 +165,18 @@ static int ufshcd_pltfrm_probe(struct platform_device 
*pdev)
goto out;
}
 
+   err = ufshcd_alloc_host(dev, hba);
+   if (err) {
+   dev_err(pdev-dev, Allocation failed\n);
+   goto out;
+   }
+
+   hba-vops = get_variant_ops(pdev-dev);
+
pm_runtime_set_active(pdev-dev);
pm_runtime_enable(pdev-dev);
 
-   err = ufshcd_init(dev, hba, mmio_base, irq);
+   err = ufshcd_init(hba, mmio_base, irq);
if (err) {
dev_err(dev, Intialization failed\n);
goto out_disable_rpm;
diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index ba27215..d0565b0 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -3,6 +3,7 @@
  *
  * This code is based on drivers/scsi/ufs/ufshcd.c
  * Copyright (C) 2011-2013 Samsung India Software Operations
+ * Copyright (c) 2013-2014, The Linux Foundation. All rights reserved.
  *
  * Authors:
  * Santosh Yaraganavi santosh...@samsung.com
@@ -31,6 +32,9 @@
  * circumstances will the contributor of this Program be liable for
  * any damages of any kind arising from your use or distribution of
  * this program.
+ *
+ * The Linux Foundation chooses to take subject only to the GPLv2
+ * license terms, and distributes only under these terms.
  */
 
 #include linux/async.h
@@ -175,13 +179,14 @@ static inline u32 ufshcd_get_ufs_version(struct ufs_hba 
*hba)
 /**
  * ufshcd_is_device_present - Check if any device connected to
  *   the host controller
- * @reg_hcs - host controller status register value
+ * @hba: pointer to adapter instance
  *
  * Returns 1 if device present, 0 if no device detected
  */
-static inline int ufshcd_is_device_present(u32 reg_hcs)
+static inline int ufshcd_is_device_present(struct ufs_hba *hba)
 {
-   return (DEVICE_PRESENT  reg_hcs) ? 1 : 0;
+   return (ufshcd_readl(hba, REG_CONTROLLER_STATUS) 
+   DEVICE_PRESENT) ? 1 : 0;
 }
 
 /**
@@ -1798,11 +1803,10 @@ out:
  * @hba: per adapter instance
  *
  * To bring UFS host controller to operational state,
- * 1. Check if device is present
- * 2. Enable required interrupts
- * 3. Configure interrupt aggregation
- * 4. Program UTRL and UTMRL base addres
- * 5. Configure run-stop-registers
+ * 1. Enable required interrupts
+ * 2. Configure interrupt

[PATCH/RESEND V4 08/17] scsi: ufs: Active Power Mode - configuring bActiveICCLevel

2014-09-23 Thread Dolev Raviv
From: Yaniv Gardi yga...@codeaurora.org

The maximum power consumption in active is determined by bActiveICCLevel.
The configuration is done by reading max current supported by the
regulators connected to VCC, VCCQ and VCCQ2 rails on the boards, and
reading the current consumption levels from the device for each rails
(vcc/vccq/vccq2) using power descriptor.
We configure the bActiveICCLevel attribute, with the max value that
correspond to the minimum-of(VCC-current-level,VCCQ-current-level,
VCCQ2-current-level).
In order to minimize resume latency, pre-fetch icc levels and reference
clock during initialization and avoid reading them each link startup
during resume.

Signed-off-by: Raviv Shvili rshv...@codeaurora.org
Signed-off-by: Yaniv Gardi yga...@codeaurora.org
Signed-off-by: Dolev Raviv dra...@codeaurora.org

diff --git a/drivers/scsi/ufs/ufs.h b/drivers/scsi/ufs/ufs.h
index f76a304..4ca99ed 100644
--- a/drivers/scsi/ufs/ufs.h
+++ b/drivers/scsi/ufs/ufs.h
@@ -115,6 +115,7 @@ enum flag_idn {
 
 /* Attribute idn for Query requests */
 enum attr_idn {
+   QUERY_ATTR_IDN_ACTIVE_ICC_LVL   = 0x03,
QUERY_ATTR_IDN_BKOPS_STATUS = 0x05,
QUERY_ATTR_IDN_EE_CONTROL   = 0x0D,
QUERY_ATTR_IDN_EE_STATUS= 0x0E,
@@ -174,6 +175,31 @@ enum unit_desc_param {
UNIT_DESC_PARAM_LARGE_UNIT_SIZE_M1  = 0x22,
 };
 
+/* bActiveICCLevel parameter current units */
+enum {
+   UFSHCD_NANO_AMP = 0,
+   UFSHCD_MICRO_AMP= 1,
+   UFSHCD_MILI_AMP = 2,
+   UFSHCD_AMP  = 3,
+};
+
+#define POWER_DESC_MAX_SIZE0x62
+#define POWER_DESC_MAX_ACTV_ICC_LVLS   16
+
+/* Attribute  bActiveICCLevel parameter bit masks definitions */
+#define ATTR_ICC_LVL_UNIT_OFFSET   14
+#define ATTR_ICC_LVL_UNIT_MASK (0x3  ATTR_ICC_LVL_UNIT_OFFSET)
+#define ATTR_ICC_LVL_VALUE_MASK0x3FF
+
+/* Power descriptor parameters offsets in bytes */
+enum power_desc_param_offset {
+   PWR_DESC_LEN= 0x0,
+   PWR_DESC_TYPE   = 0x1,
+   PWR_DESC_ACTIVE_LVLS_VCC_0  = 0x2,
+   PWR_DESC_ACTIVE_LVLS_VCCQ_0 = 0x22,
+   PWR_DESC_ACTIVE_LVLS_VCCQ2_0= 0x42,
+};
+
 /* Exception event mask values */
 enum {
MASK_EE_STATUS  = 0x,
diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index af29d4c..dc89c48 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -3265,6 +3265,125 @@ static int ufshcd_eh_host_reset_handler(struct 
scsi_cmnd *cmd)
 }
 
 /**
+ * ufshcd_get_max_icc_level - calculate the ICC level
+ * @sup_curr_uA: max. current supported by the regulator
+ * @start_scan: row at the desc table to start scan from
+ * @buff: power descriptor buffer
+ *
+ * Returns calculated max ICC level for specific regulator
+ */
+static u32 ufshcd_get_max_icc_level(int sup_curr_uA, u32 start_scan, char 
*buff)
+{
+   int i;
+   int curr_uA;
+   u16 data;
+   u16 unit;
+
+   for (i = start_scan; i = 0; i--) {
+   data = be16_to_cpu(*((u16 *)(buff + 2*i)));
+   unit = (data  ATTR_ICC_LVL_UNIT_MASK) 
+   ATTR_ICC_LVL_UNIT_OFFSET;
+   curr_uA = data  ATTR_ICC_LVL_VALUE_MASK;
+   switch (unit) {
+   case UFSHCD_NANO_AMP:
+   curr_uA = curr_uA / 1000;
+   break;
+   case UFSHCD_MILI_AMP:
+   curr_uA = curr_uA * 1000;
+   break;
+   case UFSHCD_AMP:
+   curr_uA = curr_uA * 1000 * 1000;
+   break;
+   case UFSHCD_MICRO_AMP:
+   default:
+   break;
+   }
+   if (sup_curr_uA = curr_uA)
+   break;
+   }
+   if (i  0) {
+   i = 0;
+   pr_err(%s: Couldn't find valid icc_level = %d, __func__, i);
+   }
+
+   return (u32)i;
+}
+
+/**
+ * ufshcd_calc_icc_level - calculate the max ICC level
+ * In case regulators are not initialized we'll return 0
+ * @hba: per-adapter instance
+ * @desc_buf: power descriptor buffer to extract ICC levels from.
+ * @len: length of desc_buff
+ *
+ * Returns calculated ICC level
+ */
+static u32 ufshcd_find_max_sup_active_icc_level(struct ufs_hba *hba,
+   u8 *desc_buf, int len)
+{
+   u32 icc_level = 0;
+
+   if (!hba-vreg_info.vcc || !hba-vreg_info.vccq ||
+   !hba-vreg_info.vccq2) {
+   dev_err(hba-dev,
+   %s: Regulator capability was not set, actvIccLevel=%d,
+   __func__, icc_level);
+   goto out;
+   }
+
+   if (hba-vreg_info.vcc)
+   icc_level = ufshcd_get_max_icc_level

[PATCH/RESEND V4 04/17] scsi: ufs: Add clock initialization support

2014-09-23 Thread Dolev Raviv
From: Sujit Reddy Thumma sthu...@codeaurora.org

Add generic clock initialization support for UFSHCD platform
driver. The clock info is read from device tree using standard
clock bindings. A generic max-clock-frequency-hz property is
defined to save information on maximum operating clock frequency
the h/w supports.

Signed-off-by: Sujit Reddy Thumma sthu...@codeaurora.org
Signed-off-by: Dolev Raviv dra...@codeaurora.org

diff --git a/Documentation/devicetree/bindings/ufs/ufshcd-pltfrm.txt 
b/Documentation/devicetree/bindings/ufs/ufshcd-pltfrm.txt
index 65e3117..b0f791a 100644
--- a/Documentation/devicetree/bindings/ufs/ufshcd-pltfrm.txt
+++ b/Documentation/devicetree/bindings/ufs/ufshcd-pltfrm.txt
@@ -21,8 +21,17 @@ Optional properties:
 - vccq-max-microamp : specifies max. load that can be drawn from vccq 
supply
 - vccq2-max-microamp: specifies max. load that can be drawn from vccq2 
supply
 
+- clocks: List of phandle and clock specifier pairs
+- clock-names   : List of clock input name strings sorted in the same
+  order as the clocks property.
+- max-clock-frequency-hz : List of maximum operating frequency stored in the 
same
+   order as the clocks property. If this property is 
not
+  defined or a value in the array is 0 then it is 
assumed
+  that the frequency is set by the parent clock or a
+  fixed rate clock source.
+
 Note: If above properties are not defined it can be assumed that the supply
-regulators are always on.
+regulators or clocks are always on.
 
 Example:
ufshc@0xfc598000 {
@@ -37,4 +46,8 @@ Example:
vcc-max-microamp = 50;
vccq-max-microamp = 20;
vccq2-max-microamp = 20;
+
+   clocks = core 0, ref 0, iface 0;
+   clock-names = core_clk, ref_clk, iface_clk;
+   max-clock-frequency-hz = 1 1920 0;
};
diff --git a/drivers/scsi/ufs/ufshcd-pci.c b/drivers/scsi/ufs/ufshcd-pci.c
index 7a6edbc..2a26faa 100644
--- a/drivers/scsi/ufs/ufshcd-pci.c
+++ b/drivers/scsi/ufs/ufshcd-pci.c
@@ -170,6 +170,8 @@ ufshcd_pci_probe(struct pci_dev *pdev, const struct 
pci_device_id *id)
return err;
}
 
+   INIT_LIST_HEAD(hba-clk_list_head);
+
err = ufshcd_init(hba, mmio_base, pdev-irq);
if (err) {
dev_err(pdev-dev, Initialization failed\n);
diff --git a/drivers/scsi/ufs/ufshcd-pltfrm.c b/drivers/scsi/ufs/ufshcd-pltfrm.c
index 51e47c4..642d80f 100644
--- a/drivers/scsi/ufs/ufshcd-pltfrm.c
+++ b/drivers/scsi/ufs/ufshcd-pltfrm.c
@@ -53,6 +53,71 @@ static struct ufs_hba_variant_ops *get_variant_ops(struct 
device *dev)
return NULL;
 }
 
+static int ufshcd_parse_clock_info(struct ufs_hba *hba)
+{
+   int ret = 0;
+   int cnt;
+   int i;
+   struct device *dev = hba-dev;
+   struct device_node *np = dev-of_node;
+   char *name;
+   u32 *clkfreq = NULL;
+   struct ufs_clk_info *clki;
+
+   if (!np)
+   goto out;
+
+   INIT_LIST_HEAD(hba-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,
+   __func__);
+   } else if (cnt  0) {
+   dev_err(dev, %s: count clock strings failed, err %d\n,
+   __func__, cnt);
+   ret = cnt;
+   }
+
+   if (cnt = 0)
+   goto out;
+
+   clkfreq = kzalloc(cnt * sizeof(*clkfreq), GFP_KERNEL);
+   if (!clkfreq) {
+   ret = -ENOMEM;
+   dev_err(dev, %s: memory alloc failed\n, __func__);
+   goto out;
+   }
+
+   ret = of_property_read_u32_array(np,
+   max-clock-frequency-hz, clkfreq, cnt);
+   if (ret  (ret != -EINVAL)) {
+   dev_err(dev, %s: invalid max-clock-frequency-hz property, 
%d\n,
+   __func__, ret);
+   goto out;
+   }
+
+   for (i = 0; i  cnt; i++) {
+   ret = of_property_read_string_index(np,
+   clock-names, i, (const char **)name);
+   if (ret)
+   goto out;
+
+   clki = devm_kzalloc(dev, sizeof(*clki), GFP_KERNEL);
+   if (!clki) {
+   ret = -ENOMEM;
+   goto out;
+   }
+
+   clki-max_freq = clkfreq[i];
+   clki-name = kstrdup(name, GFP_KERNEL);
+   list_add_tail(clki-list, hba-clk_list_head);
+   }
+out:
+   kfree(clkfreq);
+   return ret;
+}
+
 #define MAX_PROP_SIZE 32
 static int ufshcd_populate_vreg(struct device *dev, const char *name,
struct ufs_vreg **out_vreg)
@@ -266,6 +331,12 @@ static int

[PATCH V4 09/17] scsi: ufs: manually add well known logical units

2014-09-23 Thread Dolev Raviv
From: Subhash Jadavani subha...@codeaurora.org

According to SELECT REPORT field (of REPORT LUNS command) from SPC-4
(SCSI Primary Commands) specification, device should report all the LUNs
(which support any of the addressing method specified in the description).
Note that UFS W-LUs follow the extended logical unit addressing mothod
hence according to SPC specification all the UFS W-LUs should be reported
when SELECT REPORT field is to 00h.
But it seems UFS specification has modified the meaning of SELECT REPORT
field when its set to 00h. When SELECT REPORT field is cleared, device
should only report LUs which support peripheral device addressing method.
Even UFS Test specification seems to confirm this diversion from the spec.
Hence it's reasonable for the UFS devices adhering to the UFS device
specification to not report the W-LUs when SELECT REPORT is 00h.

scsi_scan_host() would only scan LUs with SELECT REPORT set to 00h hence
this patch manually add the UFS well known logical units.

Signed-off-by: Subhash Jadavani subha...@codeaurora.org
Signed-off-by: Dolev Raviv dra...@codeaurora.org

diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index dc89c48..1c5422b 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -902,6 +902,17 @@ static int ufshcd_compose_upiu(struct ufs_hba *hba, struct 
ufshcd_lrb *lrbp)
 }
 
 /**
+ * ufshcd_upiu_wlun_to_scsi_wlun - maps UPIU W-LUN id to SCSI W-LUN ID
+ * @scsi_lun: UPIU W-LUN id
+ *
+ * Returns SCSI W-LUN id
+ */
+static inline u16 ufshcd_upiu_wlun_to_scsi_wlun(u8 upiu_wlun_id)
+{
+   return (upiu_wlun_id  ~UFS_UPIU_WLUN_ID) | SCSI_W_LUN_BASE;
+}
+
+/**
  * ufshcd_queuecommand - main entry point for SCSI requests
  * @cmd: command from SCSI Midlayer
  * @done: call back function
@@ -3415,6 +3426,15 @@ static int ufshcd_probe_hba(struct ufs_hba *hba)
if (!hba-is_init_prefetch)
ufshcd_init_icc_levels(hba);
 
+   scsi_add_device(hba-host, 0, 0,
+   ufshcd_upiu_wlun_to_scsi_wlun(
+   UFS_UPIU_UFS_DEVICE_WLUN));
+   scsi_add_device(hba-host, 0, 0,
+   ufshcd_upiu_wlun_to_scsi_wlun(
+   UFS_UPIU_BOOT_WLUN));
+   scsi_add_device(hba-host, 0, 0,
+   ufshcd_upiu_wlun_to_scsi_wlun(
+   UFS_UPIU_RPMB_WLUN));
scsi_scan_host(hba-host);
pm_runtime_put_sync(hba-dev);
}
-- 
1.8.5.2

-- 
QUALCOMM ISRAEL, on behalf of Qualcomm Innovation Center, Inc. is a member
of Code Aurora Forum, hosted by The Linux Foundation

--
To unsubscribe from this list: send the line unsubscribe linux-scsi in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH/RESEND V4 15/17] scsi: ufs: Add support for clock scaling using devfreq framework

2014-09-23 Thread Dolev Raviv
From: Sahitya Tummala stumm...@codeaurora.org

The clocks for UFS device will be managed by generic DVFS (Dynamic
Voltage and Frequency Scaling) framework within kernel. This devfreq
framework works with different governors to scale the clocks. By default,
UFS devices uses simple_ondemand governor which scales the clocks up if
the load is more than upthreshold and scales down if the load is less than
downthreshold.

Signed-off-by: Sahitya Tummala stumm...@codeaurora.org
Signed-off-by: Dolev Raviv dra...@codeaurora.org

diff --git a/drivers/scsi/ufs/Kconfig b/drivers/scsi/ufs/Kconfig
index f07f901..6e07b2a 100644
--- a/drivers/scsi/ufs/Kconfig
+++ b/drivers/scsi/ufs/Kconfig
@@ -35,6 +35,8 @@
 config SCSI_UFSHCD
tristate Universal Flash Storage Controller Driver Core
depends on SCSI  SCSI_DMA
+   select PM_DEVFREQ
+   select DEVFREQ_GOV_SIMPLE_ONDEMAND
---help---
This selects the support for UFS devices in Linux, say Y and make
  sure that you know the name of your UFS host adapter (the card
diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index b6043a6..70c1f5d 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -38,6 +38,7 @@
  */
 
 #include linux/async.h
+#include linux/devfreq.h
 
 #include ufshcd.h
 #include unipro.h
@@ -545,6 +546,8 @@ static void ufshcd_ungate_work(struct work_struct *work)
hba-clk_gating.is_suspended = false;
}
 unblock_reqs:
+   if (ufshcd_is_clkscaling_enabled(hba))
+   devfreq_resume_device(hba-devfreq);
scsi_unblock_requests(hba-host);
 }
 
@@ -561,10 +564,10 @@ int ufshcd_hold(struct ufs_hba *hba, bool async)
 
if (!ufshcd_is_clkgating_allowed(hba))
goto out;
-start:
spin_lock_irqsave(hba-host-host_lock, flags);
hba-clk_gating.active_reqs++;
 
+start:
switch (hba-clk_gating.state) {
case CLKS_ON:
break;
@@ -596,6 +599,7 @@ start:
spin_unlock_irqrestore(hba-host-host_lock, flags);
flush_work(hba-clk_gating.ungate_work);
/* Make sure state is CLKS_ON before returning */
+   spin_lock_irqsave(hba-host-host_lock, flags);
goto start;
default:
dev_err(hba-dev, %s: clk gating is in invalid state %d\n,
@@ -636,6 +640,11 @@ static void ufshcd_gate_work(struct work_struct *work)
ufshcd_set_link_hibern8(hba);
}
 
+   if (ufshcd_is_clkscaling_enabled(hba)) {
+   devfreq_suspend_device(hba-devfreq);
+   hba-clk_scaling.window_start_t = 0;
+   }
+
if (!ufshcd_is_link_active(hba))
ufshcd_setup_clocks(hba, false);
else
@@ -737,6 +746,32 @@ static void ufshcd_exit_clk_gating(struct ufs_hba *hba)
device_remove_file(hba-dev, hba-clk_gating.delay_attr);
 }
 
+/* Must be called with host lock acquired */
+static void ufshcd_clk_scaling_start_busy(struct ufs_hba *hba)
+{
+   if (!ufshcd_is_clkscaling_enabled(hba))
+   return;
+
+   if (!hba-clk_scaling.is_busy_started) {
+   hba-clk_scaling.busy_start_t = ktime_get();
+   hba-clk_scaling.is_busy_started = true;
+   }
+}
+
+static void ufshcd_clk_scaling_update_busy(struct ufs_hba *hba)
+{
+   struct ufs_clk_scaling *scaling = hba-clk_scaling;
+
+   if (!ufshcd_is_clkscaling_enabled(hba))
+   return;
+
+   if (!hba-outstanding_reqs  scaling-is_busy_started) {
+   scaling-tot_busy_t += ktime_to_us(ktime_sub(ktime_get(),
+   scaling-busy_start_t));
+   scaling-busy_start_t = ktime_set(0, 0);
+   scaling-is_busy_started = false;
+   }
+}
 /**
  * ufshcd_send_command - Send SCSI or device management commands
  * @hba: per adapter instance
@@ -745,6 +780,7 @@ static void ufshcd_exit_clk_gating(struct ufs_hba *hba)
 static inline
 void ufshcd_send_command(struct ufs_hba *hba, unsigned int task_tag)
 {
+   ufshcd_clk_scaling_start_busy(hba);
__set_bit(task_tag, hba-outstanding_reqs);
ufshcd_writel(hba, 1  task_tag, REG_UTP_TRANSFER_REQ_DOOR_BELL);
 }
@@ -3041,6 +3077,8 @@ static void ufshcd_transfer_req_compl(struct ufs_hba *hba)
/* clear corresponding bits of completed commands */
hba-outstanding_reqs ^= completed_reqs;
 
+   ufshcd_clk_scaling_update_busy(hba);
+
/* we might have free'd some tags above */
wake_up(hba-dev_cmd.tag_wq);
 }
@@ -4083,6 +4121,10 @@ static int ufshcd_probe_hba(struct ufs_hba *hba)
if (!hba-is_init_prefetch)
hba-is_init_prefetch = true;
 
+   /* Resume devfreq after UFS device is detected */
+   if (ufshcd_is_clkscaling_enabled(hba))
+   devfreq_resume_device(hba-devfreq);
+
 out:
/*
 * If we failed to initialize the device or the device is not
@@ -4404,6 +4446,7 @@ static

[PATCH V4 12/17] scsi: ufs: refactor configuring power mode

2014-09-23 Thread Dolev Raviv
Sometimes, the device shall report its maximum power and speed
capabilities, but we might not wish to configure it to use those
maximum capabilities.
This change adds support for the vendor specific host driver to
implement power change notify callback.

To enable configuring different power modes (number of lanes,
gear number and fast/slow modes) it is necessary to split the
configuration stage from the stage that reads the device max power mode.
In addition, it is not required to read the configuration more than
once, thus the configuration is stored after reading it once.

Signed-off-by: Dolev Raviv dra...@codeaurora.org
Signed-off-by: Yaniv Gardi yga...@codeaurora.org

diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index a621827..e820262 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -179,6 +179,8 @@ static void ufshcd_hba_exit(struct ufs_hba *hba);
 static int ufshcd_probe_hba(struct ufs_hba *hba);
 static int ufshcd_host_reset_and_restore(struct ufs_hba *hba);
 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 inline int ufshcd_enable_irq(struct ufs_hba *hba)
 {
@@ -1959,40 +1961,83 @@ static int ufshcd_uic_hibern8_exit(struct ufs_hba *hba)
 }
 
 /**
- * ufshcd_config_max_pwr_mode - Set  Change power mode with
- * maximum capability attribute information.
- * @hba: per adapter instance
- *
- * Returns 0 on success, non-zero value on failure
+ * ufshcd_get_max_pwr_mode - reads the max power mode negotiated with device
+ * @hba: per-adapter instance
  */
-static int ufshcd_config_max_pwr_mode(struct ufs_hba *hba)
+static int ufshcd_get_max_pwr_mode(struct ufs_hba *hba)
 {
-   enum {RX = 0, TX = 1};
-   u32 lanes[] = {1, 1};
-   u32 gear[] = {1, 1};
-   u8 pwr[] = {FASTAUTO_MODE, FASTAUTO_MODE};
-   int ret;
+   struct ufs_pa_layer_attr *pwr_info = hba-max_pwr_info.info;
+
+   if (hba-max_pwr_info.is_valid)
+   return 0;
+
+   pwr_info-pwr_tx = FASTAUTO_MODE;
+   pwr_info-pwr_rx = FASTAUTO_MODE;
+   pwr_info-hs_rate = PA_HS_MODE_B;
 
/* Get the connected lane count */
-   ufshcd_dme_get(hba, UIC_ARG_MIB(PA_CONNECTEDRXDATALANES), lanes[RX]);
-   ufshcd_dme_get(hba, UIC_ARG_MIB(PA_CONNECTEDTXDATALANES), lanes[TX]);
+   ufshcd_dme_get(hba, UIC_ARG_MIB(PA_CONNECTEDRXDATALANES),
+   pwr_info-lane_rx);
+   ufshcd_dme_get(hba, UIC_ARG_MIB(PA_CONNECTEDTXDATALANES),
+   pwr_info-lane_tx);
+
+   if (!pwr_info-lane_rx || !pwr_info-lane_tx) {
+   dev_err(hba-dev, %s: invalid connected lanes value. rx=%d, 
tx=%d\n,
+   __func__,
+   pwr_info-lane_rx,
+   pwr_info-lane_tx);
+   return -EINVAL;
+   }
 
/*
 * First, get the maximum gears of HS speed.
 * If a zero value, it means there is no HSGEAR capability.
 * Then, get the maximum gears of PWM speed.
 */
-   ufshcd_dme_get(hba, UIC_ARG_MIB(PA_MAXRXHSGEAR), gear[RX]);
-   if (!gear[RX]) {
-   ufshcd_dme_get(hba, UIC_ARG_MIB(PA_MAXRXPWMGEAR), gear[RX]);
-   pwr[RX] = SLOWAUTO_MODE;
+   ufshcd_dme_get(hba, UIC_ARG_MIB(PA_MAXRXHSGEAR), pwr_info-gear_rx);
+   if (!pwr_info-gear_rx) {
+   ufshcd_dme_get(hba, UIC_ARG_MIB(PA_MAXRXPWMGEAR),
+   pwr_info-gear_rx);
+   if (!pwr_info-gear_rx) {
+   dev_err(hba-dev, %s: invalid max pwm rx gear read = 
%d\n,
+   __func__, pwr_info-gear_rx);
+   return -EINVAL;
+   }
+   pwr_info-pwr_rx = SLOWAUTO_MODE;
}
 
-   ufshcd_dme_peer_get(hba, UIC_ARG_MIB(PA_MAXRXHSGEAR), gear[TX]);
-   if (!gear[TX]) {
+   ufshcd_dme_peer_get(hba, UIC_ARG_MIB(PA_MAXRXHSGEAR),
+   pwr_info-gear_tx);
+   if (!pwr_info-gear_tx) {
ufshcd_dme_peer_get(hba, UIC_ARG_MIB(PA_MAXRXPWMGEAR),
-   gear[TX]);
-   pwr[TX] = SLOWAUTO_MODE;
+   pwr_info-gear_tx);
+   if (!pwr_info-gear_tx) {
+   dev_err(hba-dev, %s: invalid max pwm tx gear read = 
%d\n,
+   __func__, pwr_info-gear_tx);
+   return -EINVAL;
+   }
+   pwr_info-pwr_tx = SLOWAUTO_MODE;
+   }
+
+   hba-max_pwr_info.is_valid = true;
+   return 0;
+}
+
+int ufshcd_change_power_mode(struct ufs_hba *hba,
+struct ufs_pa_layer_attr *pwr_mode)
+{
+   int ret;
+
+   /* if already configured to the requested pwr_mode */
+   if (pwr_mode-gear_rx == hba-pwr_info.gear_rx 
+   pwr_mode-gear_tx == hba

[PATCH/RESEND V4 16/17] scsi: ufs: tune bkops while power managment events

2014-09-23 Thread Dolev Raviv
From: Subhash Jadavani subha...@codeaurora.org

Add capability to control the auto bkops during suspend.
If host explicitly enables the auto bkops (background operation) on device
then only device would perform the bkops on its own. If auto bkops is not
enabled explicitly and if the device reaches to state where it must do
background operation, device would raise the urgent bkops exception event
to host and then host will enable the auto bkops on device. This patch
adds the option to choose whether auto bkops should be enabled during
runtime suspend or not. Since we don't want to keep the device active to
perform the non critical bkops, host will enable urgent bkops only.

Keep auto-bkops enabled after resume if urgent bkops needed.
If device bkops status shows that its in critical need of executing
background operations, host should allow the device to continue doing
background operations.

Signed-off-by: Subhash Jadavani subha...@codeaurora.org
Signed-off-by: Dolev Raviv dra...@codeaurora.org

diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index 70c1f5d..15ec238 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -4816,13 +4816,19 @@ static int ufshcd_suspend(struct ufs_hba *hba, enum 
ufs_pm_op pm_op)
}
 
if (ufshcd_is_runtime_pm(pm_op)) {
-   /*
-* The device is idle with no requests in the queue,
-* allow background operations if needed.
-*/
-   ret = ufshcd_bkops_ctrl(hba, BKOPS_STATUS_NON_CRITICAL);
-   if (ret)
-   goto enable_gating;
+   if (ufshcd_can_autobkops_during_suspend(hba)) {
+   /*
+* The device is idle with no requests in the queue,
+* allow background operations if bkops status shows
+* that performance might be impacted.
+*/
+   ret = ufshcd_urgent_bkops(hba);
+   if (ret)
+   goto enable_gating;
+   } else {
+   /* make sure that auto bkops is disabled */
+   ufshcd_disable_auto_bkops(hba);
+   }
}
 
if ((req_dev_pwr_mode != hba-curr_dev_pwr_mode) 
@@ -4970,7 +4976,11 @@ static int ufshcd_resume(struct ufs_hba *hba, enum 
ufs_pm_op pm_op)
goto set_old_link_state;
}
 
-   ufshcd_disable_auto_bkops(hba);
+   /*
+* If BKOPs operations are urgently needed at this moment then
+* keep auto-bkops enabled or else disable it.
+*/
+   ufshcd_urgent_bkops(hba);
hba-clk_gating.is_suspended = false;
 
if (ufshcd_is_clkscaling_enabled(hba))
diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h
index d5699d0..b94b835 100644
--- a/drivers/scsi/ufs/ufshcd.h
+++ b/drivers/scsi/ufs/ufshcd.h
@@ -466,6 +466,8 @@ struct ufs_hba {
 #define UFSHCD_CAP_HIBERN8_WITH_CLK_GATING (1  1)
/* Allow dynamic clk scaling */
 #define UFSHCD_CAP_CLK_SCALING (1  2)
+   /* Allow auto bkops to enabled during runtime suspend */
+#define UFSHCD_CAP_AUTO_BKOPS_SUSPEND (1  3)
 
struct devfreq *devfreq;
struct ufs_clk_scaling clk_scaling;
@@ -484,6 +486,11 @@ static inline int ufshcd_is_clkscaling_enabled(struct 
ufs_hba *hba)
 {
return hba-caps  UFSHCD_CAP_CLK_SCALING;
 }
+static inline bool ufshcd_can_autobkops_during_suspend(struct ufs_hba *hba)
+{
+   return hba-caps  UFSHCD_CAP_AUTO_BKOPS_SUSPEND;
+}
+
 #define ufshcd_writel(hba, val, reg)   \
writel((val), (hba)-mmio_base + (reg))
 #define ufshcd_readl(hba, reg) \
-- 
1.8.5.2

-- 
QUALCOMM ISRAEL, on behalf of Qualcomm Innovation Center, Inc. is a member
of Code Aurora Forum, hosted by The Linux Foundation

--
To unsubscribe from this list: send the line unsubscribe linux-scsi in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH/RESEND V4 10/17] scsi: ufs: introduce well known logical unit in ufs

2014-09-23 Thread Dolev Raviv
From: Subhash Jadavani subha...@codeaurora.org

UFS device may have standard LUs and LUN id could be from 0x00 to 0x7F.
UFS device specification use Peripheral Device Addressing Format
(SCSI SAM-5) for standard LUs.

UFS device may also have the Well Known LUs (also referred as W-LU) which
again could be from 0x00 to 0x7F. For W-LUs, UFS device specification only
allows the Extended Addressing Format (SCSI SAM-5) which means the W-LUNs
would start from 0xC100 onwards.

This means max. LUN number reported from UFS device could be 0xC17F hence
this patch advertise the max_lun as 0xC17F which will allow SCSI mid
layer to detect the W-LUs as well.

But once the W-LUs are detected, UFSHCD driver may get the commands with
SCSI LUN id upto 0xC17F but UPIU LUN id field is only 8-bit wide so it
requires the mapping of SCSI LUN id to UPIU LUN id. This patch also add
support for this mapping.

Signed-off-by: Subhash Jadavani subha...@codeaurora.org
Signed-off-by: Dolev Raviv dra...@codeaurora.org
Signed-off-by: Sujit Reddy Thumma sthu...@codeaurora.org

diff --git a/drivers/scsi/ufs/ufs.h b/drivers/scsi/ufs/ufs.h
index 4ca99ed..37d64c1 100644
--- a/drivers/scsi/ufs/ufs.h
+++ b/drivers/scsi/ufs/ufs.h
@@ -49,9 +49,28 @@
 #define UPIU_HEADER_DWORD(byte3, byte2, byte1, byte0)\
cpu_to_be32((byte3  24) | (byte2  16) |\
 (byte1  8) | (byte0))
-
+/*
+ * UFS device may have standard LUs and LUN id could be from 0x00 to
+ * 0x7F. Standard LUs use Peripheral Device Addressing Format.
+ * UFS device may also have the Well Known LUs (also referred as W-LU)
+ * which again could be from 0x00 to 0x7F. For W-LUs, device only use
+ * the Extended Addressing Format which means the W-LUNs would be
+ * from 0xc100 (SCSI_W_LUN_BASE) onwards.
+ * This means max. LUN number reported from UFS device could be 0xC17F.
+ */
+#define UFS_UPIU_MAX_UNIT_NUM_ID   0x7F
+#define UFS_MAX_LUNS   (SCSI_W_LUN_BASE + UFS_UPIU_MAX_UNIT_NUM_ID)
+#define UFS_UPIU_WLUN_ID   (1  7)
 #define UFS_UPIU_MAX_GENERAL_LUN   8
 
+/* Well known logical unit id in LUN field of UPIU */
+enum {
+   UFS_UPIU_REPORT_LUNS_WLUN   = 0x81,
+   UFS_UPIU_UFS_DEVICE_WLUN= 0xD0,
+   UFS_UPIU_BOOT_WLUN  = 0xB0,
+   UFS_UPIU_RPMB_WLUN  = 0xC4,
+};
+
 /*
  * UFS Protocol Information Unit related definitions
  */
diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index 1c5422b..de41630 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -100,7 +100,6 @@ static u32 ufs_query_desc_max_size[] = {
 enum {
UFSHCD_MAX_CHANNEL  = 0,
UFSHCD_MAX_ID   = 1,
-   UFSHCD_MAX_LUNS = 8,
UFSHCD_CMD_PER_LUN  = 32,
UFSHCD_CAN_QUEUE= 32,
 };
@@ -901,6 +900,21 @@ static int ufshcd_compose_upiu(struct ufs_hba *hba, struct 
ufshcd_lrb *lrbp)
return ret;
 }
 
+/*
+ * ufshcd_scsi_to_upiu_lun - maps scsi LUN to UPIU LUN
+ * @scsi_lun: scsi LUN id
+ *
+ * Returns UPIU LUN id
+ */
+static inline u8 ufshcd_scsi_to_upiu_lun(unsigned int scsi_lun)
+{
+   if (scsi_is_wlun(scsi_lun))
+   return (scsi_lun  UFS_UPIU_MAX_UNIT_NUM_ID)
+   | UFS_UPIU_WLUN_ID;
+   else
+   return scsi_lun  UFS_UPIU_MAX_UNIT_NUM_ID;
+}
+
 /**
  * ufshcd_upiu_wlun_to_scsi_wlun - maps UPIU W-LUN id to SCSI W-LUN ID
  * @scsi_lun: UPIU W-LUN id
@@ -970,7 +984,7 @@ static int ufshcd_queuecommand(struct Scsi_Host *host, 
struct scsi_cmnd *cmd)
lrbp-sense_bufflen = SCSI_SENSE_BUFFERSIZE;
lrbp-sense_buffer = cmd-sense_buffer;
lrbp-task_tag = tag;
-   lrbp-lun = cmd-device-lun;
+   lrbp-lun = ufshcd_scsi_to_upiu_lun(cmd-device-lun);
lrbp-intr_cmd = false;
lrbp-command_type = UTP_CMD_TYPE_SCSI;
 
@@ -1524,7 +1538,7 @@ static inline int ufshcd_read_unit_desc_param(struct 
ufs_hba *hba,
 * Unit descriptors are only available for general purpose LUs (LUN id
 * from 0 to 7) and RPMB Well known LU.
 */
-   if (lun = UFS_UPIU_MAX_GENERAL_LUN)
+   if (lun != UFS_UPIU_RPMB_WLUN  (lun = UFS_UPIU_MAX_GENERAL_LUN))
return -EOPNOTSUPP;
 
return ufshcd_read_desc_param(hba, QUERY_DESC_IDN_UNIT, lun,
@@ -2155,6 +2169,44 @@ static int ufshcd_verify_dev_init(struct ufs_hba *hba)
 }
 
 /**
+ * ufshcd_set_queue_depth - set lun queue depth
+ * @sdev: pointer to SCSI device
+ *
+ * Read bLUQueueDepth value and activate scsi tagged command
+ * queueing. For WLUN, queue depth is set to 1. For best-effort
+ * cases (bLUQueueDepth = 0) the queue depth is set to a maximum
+ * value that host can queue.
+ */
+static void ufshcd_set_queue_depth(struct scsi_device *sdev)
+{
+   int ret = 0;
+   u8 lun_qdepth;
+   struct ufs_hba *hba;
+
+   hba = shost_priv(sdev-host);
+
+   lun_qdepth = hba-nutrs;
+   ret = ufshcd_read_unit_desc_param(hba

[PATCH V4 11/17] scsi: ufs: add UFS power management support

2014-09-23 Thread Dolev Raviv
From: Subhash Jadavani subha...@codeaurora.org

This patch adds support for UFS device and UniPro link power management
during runtime/system PM.

Main idea is to define multiple UFS low power levels based on UFS device
and UFS link power states. This would allow any specific platform or pci
driver to choose the best suited low power level during runtime and
system suspend based on their power goals.

bkops handlig:
To put the UFS device in sleep state when bkops is disabled, first query
the bkops status from the device and enable bkops on device only if
device needs time to perform the bkops.

START_STOP handling:
Before sending START_STOP_UNIT to the device well-known logical unit
(w-lun) to make sure that the device w-lun unit attention condition is
cleared.

Write protection:
UFS device specification allows LUs to be write protected, either
permanently or power on write protected. If any LU is power on write
protected and if the card is power cycled (by powering off VCCQ and/or
VCC rails), LU's write protect status would be lost. So this means those
LUs can be written now. To ensures that UFS device is power cycled only
if the power on protect is not set for any of the LUs, check if power on
write protect is set and if device is in sleep/power-off state  link in
inactive state (Hibern8 or OFF state).
If none of the Logical Units on UFS device is power on write protected
then all UFS device power rails (VCC, VCCQ  VCCQ2) can be turned off if
UFS device is in power-off state and UFS link is in OFF state. But current
implementation would disable all device power rails even if UFS link is
not in OFF state.

Low power mode:
If UFS link is in OFF state then UFS host controller can be power collapsed
to avoid leakage current from it. Note that if UFS host controller is power
collapsed, full UFS reinitialization will be required on resume to
re-establish the link between host and device.

Signed-off-by: Subhash Jadavani subha...@codeaurora.org
Signed-off-by: Dolev Raviv dra...@codeaurora.org
Signed-off-by: Sujit Reddy Thumma sthu...@codeaurora.org

diff --git a/drivers/scsi/ufs/ufs.h b/drivers/scsi/ufs/ufs.h
index 37d64c1..42c459a 100644
--- a/drivers/scsi/ufs/ufs.h
+++ b/drivers/scsi/ufs/ufs.h
@@ -129,6 +129,7 @@ enum {
 /* Flag idn for Query Requests*/
 enum flag_idn {
QUERY_FLAG_IDN_FDEVICEINIT  = 0x01,
+   QUERY_FLAG_IDN_PWR_ON_WPE   = 0x03,
QUERY_FLAG_IDN_BKOPS_EN = 0x04,
 };
 
@@ -194,6 +195,18 @@ enum unit_desc_param {
UNIT_DESC_PARAM_LARGE_UNIT_SIZE_M1  = 0x22,
 };
 
+/*
+ * Logical Unit Write Protect
+ * 00h: LU not write protected
+ * 01h: LU write protected when fPowerOnWPEn =1
+ * 02h: LU permanently write protected when fPermanentWPEn =1
+ */
+enum ufs_lu_wp_type {
+   UFS_LU_NO_WP= 0x00,
+   UFS_LU_POWER_ON_WP  = 0x01,
+   UFS_LU_PERM_WP  = 0x02,
+};
+
 /* bActiveICCLevel parameter current units */
 enum {
UFSHCD_NANO_AMP = 0,
@@ -226,11 +239,12 @@ enum {
 };
 
 /* Background operation status */
-enum {
+enum bkops_status {
BKOPS_STATUS_NO_OP   = 0x0,
BKOPS_STATUS_NON_CRITICAL= 0x1,
BKOPS_STATUS_PERF_IMPACT = 0x2,
BKOPS_STATUS_CRITICAL= 0x3,
+   BKOPS_STATUS_MAX = BKOPS_STATUS_CRITICAL,
 };
 
 /* UTP QUERY Transaction Specific Fields OpCode */
@@ -291,6 +305,14 @@ enum {
UPIU_TASK_MANAGEMENT_FUNC_FAILED= 0x05,
UPIU_INCORRECT_LOGICAL_UNIT_NO  = 0x09,
 };
+
+/* UFS device power modes */
+enum ufs_dev_pwr_mode {
+   UFS_ACTIVE_PWR_MODE = 1,
+   UFS_SLEEP_PWR_MODE  = 2,
+   UFS_POWERDOWN_PWR_MODE  = 3,
+};
+
 /**
  * struct utp_upiu_header - UPIU header structure
  * @dword_0: UPIU header DW-0
@@ -437,6 +459,12 @@ struct ufs_query_res {
 #define UFS_VREG_VCCQ2_MIN_UV 165 /* uV */
 #define UFS_VREG_VCCQ2_MAX_UV 195 /* uV */
 
+/*
+ * VCCQ  VCCQ2 current requirement when UFS device is in sleep state
+ * and link is in Hibern8 state.
+ */
+#define UFS_VREG_LPM_LOAD_UA   1000 /* uA */
+
 struct ufs_vreg {
struct regulator *reg;
const char *name;
@@ -454,4 +482,10 @@ struct ufs_vreg_info {
struct ufs_vreg *vdd_hba;
 };
 
+struct ufs_dev_info {
+   bool f_power_on_wp_en;
+   /* Keeps information if any of the LU is power on write protected */
+   bool is_lu_power_on_wp;
+};
+
 #endif /* End of Header */
diff --git a/drivers/scsi/ufs/ufshcd-pci.c b/drivers/scsi/ufs/ufshcd-pci.c
index 2a26faa..955ed55 100644
--- a/drivers/scsi/ufs/ufshcd-pci.c
+++ b/drivers/scsi/ufs/ufshcd-pci.c
@@ -43,34 +43,24 @@
  * @pdev: pointer to PCI device handle
  * @state: power state
  *
- * Returns -ENOSYS
+ * Returns 0 if successful
+ * Returns non-zero otherwise
  */
 static int ufshcd_pci_suspend(struct device *dev)
 {
-   /*
-* TODO:
-* 1. Call ufshcd_suspend
-* 2. Do bus specific power management

[PATCH/RESEND V4 17/17] scsi: ufs: definitions for phy interface

2014-09-23 Thread Dolev Raviv
- Adding some of the definitions missing in unipro.h, including power
  enumeration.
- Read Modify Write Line helper function
- Indication for the type of suspend

Signed-off-by: Dolev Raviv dra...@codeaurora.org
Signed-off-by: Subhash Jadavani subha...@codeaurora.org
Signed-off-by: Yaniv Gardi yga...@codeaurora.org

diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index 15ec238..ce98a21 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -5046,6 +5046,8 @@ int ufshcd_system_suspend(struct ufs_hba *hba)
 
ret = ufshcd_suspend(hba, UFS_SYSTEM_PM);
 out:
+   if (!ret)
+   hba-is_sys_suspended = true;
return ret;
 }
 EXPORT_SYMBOL(ufshcd_system_suspend);
diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h
index b94b835..d502d70 100644
--- a/drivers/scsi/ufs/ufshcd.h
+++ b/drivers/scsi/ufs/ufshcd.h
@@ -471,6 +471,7 @@ struct ufs_hba {
 
struct devfreq *devfreq;
struct ufs_clk_scaling clk_scaling;
+   bool is_sys_suspended;
 };
 
 /* Returns true if clocks can be gated. Otherwise false */
@@ -496,6 +497,23 @@ static inline bool 
ufshcd_can_autobkops_during_suspend(struct ufs_hba *hba)
 #define ufshcd_readl(hba, reg) \
readl((hba)-mmio_base + (reg))
 
+/**
+ * ufshcd_rmwl - read modify write into a register
+ * @hba - per adapter instance
+ * @mask - mask to apply on read value
+ * @val - actual value to write
+ * @reg - register address
+ */
+static inline void ufshcd_rmwl(struct ufs_hba *hba, u32 mask, u32 val, u32 reg)
+{
+   u32 tmp;
+
+   tmp = ufshcd_readl(hba, reg);
+   tmp = ~mask;
+   tmp |= (val  mask);
+   ufshcd_writel(hba, tmp, reg);
+}
+
 int ufshcd_alloc_host(struct device *, struct ufs_hba **);
 int ufshcd_init(struct ufs_hba * , void __iomem * , unsigned int);
 void ufshcd_remove(struct ufs_hba *);
diff --git a/drivers/scsi/ufs/unipro.h b/drivers/scsi/ufs/unipro.h
index 0bb8041..3fc3e21 100644
--- a/drivers/scsi/ufs/unipro.h
+++ b/drivers/scsi/ufs/unipro.h
@@ -13,6 +13,44 @@
 #define _UNIPRO_H_
 
 /*
+ * M-TX Configuration Attributes
+ */
+#define TX_MODE0x0021
+#define TX_HSRATE_SERIES   0x0022
+#define TX_HSGEAR  0x0023
+#define TX_PWMGEAR 0x0024
+#define TX_AMPLITUDE   0x0025
+#define TX_HS_SLEWRATE 0x0026
+#define TX_SYNC_SOURCE 0x0027
+#define TX_HS_SYNC_LENGTH  0x0028
+#define TX_HS_PREPARE_LENGTH   0x0029
+#define TX_LS_PREPARE_LENGTH   0x002A
+#define TX_HIBERN8_CONTROL 0x002B
+#define TX_LCC_ENABLE  0x002C
+#define TX_PWM_BURST_CLOSURE_EXTENSION 0x002D
+#define TX_BYPASS_8B10B_ENABLE 0x002E
+#define TX_DRIVER_POLARITY 0x002F
+#define TX_HS_UNTERMINATED_LINE_DRIVE_ENABLE   0x0030
+#define TX_LS_TERMINATED_LINE_DRIVE_ENABLE 0x0031
+#define TX_LCC_SEQUENCER   0x0032
+#define TX_MIN_ACTIVATETIME0x0033
+#define TX_PWM_G6_G7_SYNC_LENGTH   0x0034
+
+/*
+ * M-RX Configuration Attributes
+ */
+#define RX_MODE0x00A1
+#define RX_HSRATE_SERIES   0x00A2
+#define RX_HSGEAR  0x00A3
+#define RX_PWMGEAR 0x00A4
+#define RX_LS_TERMINATED_ENABLE0x00A5
+#define RX_HS_UNTERMINATED_ENABLE  0x00A6
+#define RX_ENTER_HIBERN8   0x00A7
+#define RX_BYPASS_8B10B_ENABLE 0x00A8
+#define RX_TERMINATION_FORCE_ENABLE0x0089
+
+#define is_mphy_tx_attr(attr)  (attr  RX_MODE)
+/*
  * PHY Adpater attributes
  */
 #define PA_ACTIVETXDATALANES   0x1560
@@ -87,6 +125,24 @@ enum {
PA_HS_MODE_B= 2,
 };
 
+enum ufs_pwm_gear_tag {
+   UFS_PWM_DONT_CHANGE,/* Don't change Gear */
+   UFS_PWM_G1, /* PWM Gear 1 (default for reset) */
+   UFS_PWM_G2, /* PWM Gear 2 */
+   UFS_PWM_G3, /* PWM Gear 3 */
+   UFS_PWM_G4, /* PWM Gear 4 */
+   UFS_PWM_G5, /* PWM Gear 5 */
+   UFS_PWM_G6, /* PWM Gear 6 */
+   UFS_PWM_G7, /* PWM Gear 7 */
+};
+
+enum ufs_hs_gear_tag {
+   UFS_HS_DONT_CHANGE, /* Don't change Gear */
+   UFS_HS_G1,  /* HS Gear 1 (default for reset) */
+   UFS_HS_G2,  /* HS Gear 2 */
+   UFS_HS_G3,  /* HS Gear 3 */
+};
+
 /*
  * Data Link Layer Attributes
  */
-- 
1.8.5.2

-- 
QUALCOMM ISRAEL, on behalf of Qualcomm Innovation Center, Inc. is a member
of Code Aurora Forum, hosted by The Linux Foundation

--
To unsubscribe from this list: send the line unsubscribe linux-scsi in
the body of a message to majord...@vger.kernel.org

[PATCH V4 13/17] scsi: ufs: Add support for clock gating

2014-09-23 Thread Dolev Raviv
From: Sahitya Tummala stumm...@codeaurora.org

The UFS controller clocks can be gated after certain period of
inactivity, which is typically less than runtime suspend timeout.
In addition to clocks the link will also be put into Hibern8 mode
to save more power.

The clock gating can be turned on by enabling the capability
UFSHCD_CAP_CLK_GATING. To enable entering into Hibern8 mode as part of
clock gating, set the capability UFSHCD_CAP_HIBERN8_WITH_CLK_GATING.

The tracing events for clock gating can be enabled through debugfs as:
echo 1  /sys/kernel/debug/tracing/events/ufs/ufshcd_clk_gating/enable
cat /sys/kernel/debug/tracing/trace_pipe

Signed-off-by: Sahitya Tummala stumm...@codeaurora.org
Signed-off-by: Dolev Raviv dra...@codeaurora.org

diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index e820262..b6043a6 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -177,6 +177,11 @@ static int ufshcd_reset_and_restore(struct ufs_hba *hba);
 static int ufshcd_clear_tm_cmd(struct ufs_hba *hba, int tag);
 static void ufshcd_hba_exit(struct ufs_hba *hba);
 static int ufshcd_probe_hba(struct ufs_hba *hba);
+static int __ufshcd_setup_clocks(struct ufs_hba *hba, bool on,
+bool skip_ref_clk);
+static int ufshcd_setup_clocks(struct ufs_hba *hba, bool on);
+static int ufshcd_uic_hibern8_exit(struct ufs_hba *hba);
+static int ufshcd_uic_hibern8_enter(struct ufs_hba *hba);
 static int ufshcd_host_reset_and_restore(struct ufs_hba *hba);
 static irqreturn_t ufshcd_intr(int irq, void *__hba);
 static int ufshcd_config_pwr_mode(struct ufs_hba *hba,
@@ -507,6 +512,231 @@ static inline int ufshcd_is_hba_active(struct ufs_hba 
*hba)
return (ufshcd_readl(hba, REG_CONTROLLER_ENABLE)  0x1) ? 0 : 1;
 }
 
+static void ufshcd_ungate_work(struct work_struct *work)
+{
+   int ret;
+   unsigned long flags;
+   struct ufs_hba *hba = container_of(work, struct ufs_hba,
+   clk_gating.ungate_work);
+
+   cancel_delayed_work_sync(hba-clk_gating.gate_work);
+
+   spin_lock_irqsave(hba-host-host_lock, flags);
+   if (hba-clk_gating.state == CLKS_ON) {
+   spin_unlock_irqrestore(hba-host-host_lock, flags);
+   goto unblock_reqs;
+   }
+
+   spin_unlock_irqrestore(hba-host-host_lock, flags);
+   ufshcd_setup_clocks(hba, true);
+
+   /* Exit from hibern8 */
+   if (ufshcd_can_hibern8_during_gating(hba)) {
+   /* Prevent gating in this path */
+   hba-clk_gating.is_suspended = true;
+   if (ufshcd_is_link_hibern8(hba)) {
+   ret = ufshcd_uic_hibern8_exit(hba);
+   if (ret)
+   dev_err(hba-dev, %s: hibern8 exit failed 
%d\n,
+   __func__, ret);
+   else
+   ufshcd_set_link_active(hba);
+   }
+   hba-clk_gating.is_suspended = false;
+   }
+unblock_reqs:
+   scsi_unblock_requests(hba-host);
+}
+
+/**
+ * ufshcd_hold - Enable clocks that were gated earlier due to ufshcd_release.
+ * Also, exit from hibern8 mode and set the link as active.
+ * @hba: per adapter instance
+ * @async: This indicates whether caller should ungate clocks asynchronously.
+ */
+int ufshcd_hold(struct ufs_hba *hba, bool async)
+{
+   int rc = 0;
+   unsigned long flags;
+
+   if (!ufshcd_is_clkgating_allowed(hba))
+   goto out;
+start:
+   spin_lock_irqsave(hba-host-host_lock, flags);
+   hba-clk_gating.active_reqs++;
+
+   switch (hba-clk_gating.state) {
+   case CLKS_ON:
+   break;
+   case REQ_CLKS_OFF:
+   if (cancel_delayed_work(hba-clk_gating.gate_work)) {
+   hba-clk_gating.state = CLKS_ON;
+   break;
+   }
+   /*
+* If we here, it means gating work is either done or
+* currently running. Hence, fall through to cancel gating
+* work and to enable clocks.
+*/
+   case CLKS_OFF:
+   scsi_block_requests(hba-host);
+   hba-clk_gating.state = REQ_CLKS_ON;
+   schedule_work(hba-clk_gating.ungate_work);
+   /*
+* fall through to check if we should wait for this
+* work to be done or not.
+*/
+   case REQ_CLKS_ON:
+   if (async) {
+   rc = -EAGAIN;
+   hba-clk_gating.active_reqs--;
+   break;
+   }
+
+   spin_unlock_irqrestore(hba-host-host_lock, flags);
+   flush_work(hba-clk_gating.ungate_work);
+   /* Make sure state is CLKS_ON before returning */
+   goto start;
+   default:
+   dev_err(hba-dev, %s: clk gating is in invalid state %d\n

Re: [PATCH V4 09/17] scsi: ufs: manually add well known logical units

2014-09-23 Thread Dolev Raviv

 None of the REPORT LUNS language makes sense as we're not using it.

 Can you respon the patch with a better description, and a little comment
 in the code on why you're adding these wluns.

ok.


 Also can I assume none of the later patches relies on their existance?

In UFS power management commands such as SSU, are sent to device w-
lun. Leaving it out should only affect the ability to suspend the
device.
Other patches are not directly affected by it.

 If you do you need to check the error return from scsi_add_device, if
 not said comment should mention why it's fine to not actually find
 any of these.


Will discus it further with Subhash.

 Also if you do use one of them from kernel space later it might make
 more sense to use __scsi_add_device and store a pointer to the
 scsi_device instead of looking it up later.


I'll review all you suggestions with Subhash.


-- 
QUALCOMM ISRAEL, on behalf of Qualcomm Innovation Center, Inc. is a member
of Code Aurora Forum, hosted by The Linux Foundation


--
To unsubscribe from this list: send the line unsubscribe linux-scsi in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [PATCH V4 11/17] scsi: ufs: add UFS power management support

2014-09-23 Thread Dolev Raviv

  /**
   * ufshcd_slave_alloc - handle initial SCSI device configurations
   * @sdev: pointer to SCSI device
 @@ -2232,6 +2403,21 @@ static int ufshcd_slave_alloc(struct scsi_device
 *sdev)

  ufshcd_set_queue_depth(sdev);

 +ufshcd_get_lu_power_on_wp_status(hba, sdev);
 +
 +/*
 + * For selecting the UFS device power mode (Active / UFS_Sleep /
 + * UFS_PowerDown), SCSI power management command (START STOP UNIT)
 + * needs to be sent to a UFS device Well known Logical Unit (W-LU).
 + * As this command would be sent during the UFS host controller
 + * runtime/system PM callbacks, we need a reference to scsi_device
 + * associated to UFS device W-LU. This change saves the
 scsi_device
 + * reference for UFS device W-LU during slave_configure() callback
 + * from SCSI mid layer.
 + */
 +if (ufshcd_scsi_to_upiu_lun(sdev-lun) == UFS_UPIU_UFS_DEVICE_WLUN)
 +hba-sdev_ufs_device = sdev;
 +

 Storing the pointer in slave_alloc is not safe as you don't known if the
 probing was successful.  In addition you really need a reference to a
 scsi_device that you store somewhere as a user could easily delete the
 device through sysfs, which any access to it invalid.

 As mention earlier you should just add this wlun using __scsi_device_add
 which gives you a pointer and a reference to the fully probed device.

Sounds reasonable, I'll coordinate it with the previous patch.


 +static int
 +ufshcd_send_request_sense(struct ufs_hba *hba, struct scsi_device *sdp)
 +{
 +unsigned char cmd[6] = {REQUEST_SENSE,
 +0,
 +0,
 +0,
 +SCSI_SENSE_BUFFERSIZE,
 +0};
 +char *buffer;
 +int ret;
 +
 +buffer = kzalloc(SCSI_SENSE_BUFFERSIZE, GFP_KERNEL);
 +if (!buffer) {
 +ret = -ENOMEM;
 +goto out;
 +}
 +
 +ret = scsi_execute_req_flags(sdp, cmd, DMA_FROM_DEVICE, buffer,
 +SCSI_SENSE_BUFFERSIZE, NULL,
 +msecs_to_jiffies(1000), 3, NULL, REQ_PM);
 +if (ret)
 +pr_err(%s: failed with err %d\n, __func__, ret);
 +
 +kfree(buffer);
 +out:
 +return ret;
 +}

 It would be good to have an explanation why you need to call
 REQUEST SENSE from the driver.  OR your own START STOP later one.  This
 all seems very much against the normal model of operation for SCSI
 devices.


Let me rephrase the explanation from the commit message:
We issue request sense before sending START_STOP_UNIT to the device
well-known logical unit (w-lun) to make sure that the device w-lun
unit attention condition is cleared. Otherwise START_STOP_UNIT will fail.

As mentioned in my previous mail (in response to [9/17] patch comments),
UFS driver power management is controlled via device W-LUN during the
suspend process.
As documented in the comment above: 
 * For selecting the UFS device power mode (Active / UFS_Sleep /
 * UFS_PowerDown), SCSI power management command (START STOP UNIT)
 * needs to be sent to a UFS device Well known Logical Unit (W-LU).
 * As this command would be sent during the UFS host controller
 * runtime/system PM callbacks, 

Do you have another suggestion for making it compatible to other scsi
drivers?
Would you prefer this logic would go into core scsi?

-- 
QUALCOMM ISRAEL, on behalf of Qualcomm Innovation Center, Inc. is a member
of Code Aurora Forum, hosted by The Linux Foundation


--
To unsubscribe from this list: send the line unsubscribe linux-scsi in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [PATCH V3 10/16] scsi: ufs: add UFS power management support

2014-09-21 Thread Dolev Raviv
Hi Kiran,
Thanks for bringing it to my attention. Fortunately I already noticed it
and fixed it. It will be sent soon when all comments on this series are
addressed.

Thanks,
Dolev

 Hi Dolev,

 On Wednesday 10 September 2014 05:24 PM, Dolev Raviv wrote:
 From: Subhash Jadavani subha...@codeaurora.org

 This patch adds support for UFS device and UniPro link power management
 during runtime/system PM.


 snip

 +vccq_lpm:
 +ufshcd_config_vreg_lpm(hba, hba-vreg_info.vccq);
 +vcc_disable:
 +ufshcd_toggle_vreg(hba-dev, hba-vreg_info.vcc, false);
 +out:
 +return ret;
 +}
 +
 +static void ufshcd_hba_vreg_set_lpm(struct ufs_hba *hba)
 +{
 +if (ufshcd_is_link_off(hba))
 +ufshcd_setup_hba_vreg(hba, false);

 I didn't find any declaration and definition of above API in your patch
 set.
 During compilation of this driver I got a below error, am I missing any
 thing?

 drivers/scsi/ufs/ufshcd.c: In function ‘ufshcd_hba_vreg_set_lpm’:
 drivers/scsi/ufs/ufshcd.c:4656:3: error: implicit declaration of
 function ‘ufshcd_setup_hba_vreg’ [-Werror=implicit-function-declaration]
ufshcd_setup_hba_vreg(hba, false);
^

 +}
 +
 +static void ufshcd_hba_vreg_set_hpm(struct ufs_hba *hba)
 +{
 +if (ufshcd_is_link_off(hba))
 +ufshcd_setup_hba_vreg(hba, true);

 Ditto.

  }
 -EXPORT_SYMBOL_GPL(ufshcd_suspend);

  /**
 - * ufshcd_resume - resume power management function
 + * ufshcd_suspend - helper function for suspend operations
   * @hba: per adapter instance
 + * @pm_op: desired low power operation type
 + *
 + * This function will try to put the UFS device and link into low power
 + * mode based on the rpm_lvl (Runtime PM level) or spm_lvl
 + * (System PM level).
   *

 snip

 +int ufshcd_system_resume(struct ufs_hba *hba)
 +{
 +if (!hba || !hba-is_powered || pm_runtime_suspended(hba-dev))
 +/*
 + * Let the runtime resume take care of resuming
 + * if runtime suspended.
 + */
 +return 0;
 +else

 else is not generally useful after a break or return.

 +return ufshcd_resume(hba, UFS_SYSTEM_PM);
 +}
 +EXPORT_SYMBOL(ufshcd_system_resume);
 +
 +/**
 + * ufshcd_runtime_suspend - runtime suspend routine
 + * @hba: per adapter instance
 + *
 + * Check the description of ufshcd_suspend() function for more details.
 + *
 + * Returns 0 for success and non-zero for failure
 + */
 +int ufshcd_runtime_suspend(struct ufs_hba *hba)
 +{
 +if (!hba || !hba-is_powered)
 +return 0;
 +else

 else is not generally useful after a break or return.

 +return ufshcd_suspend(hba, UFS_RUNTIME_PM);
  }
  EXPORT_SYMBOL(ufshcd_runtime_suspend);

 +/**
 + * ufshcd_runtime_resume - runtime resume routine
 + * @hba: per adapter instance
 + *
 + * This function basically brings the UFS device, UniPro link and
 controller
 + * to active state. Following operations are done in this function:
 + *

 Thanks,
 --Kiran




-- 
QUALCOMM ISRAEL, on behalf of Qualcomm Innovation Center, Inc. is a member
of Code Aurora Forum, hosted by The Linux Foundation


--
To unsubscribe from this list: send the line unsubscribe linux-scsi in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [PATCH V3 09/16] scsi: ufs: introduce well known logical unit in ufs

2014-09-15 Thread Dolev Raviv

 2014-09-10 20:54 GMT+09:00 Dolev Raviv dra...@codeaurora.org:
 +static void ufshcd_set_queue_depth(struct scsi_device *sdev)
 +{
 +   int ret = 0;
 +   u8 lun_qdepth;
 +   struct ufs_hba *hba;
 +
 +   hba = shost_priv(sdev-host);
 +
 +   lun_qdepth = hba-nutrs;
 +   ret = ufshcd_read_unit_desc_param(hba,
 +
 ufshcd_scsi_to_upiu_lun(sdev-lun),
 + UNIT_DESC_PARAM_LU_Q_DEPTH,
 + lun_qdepth,
 + sizeof(lun_qdepth));
 +
 +   /* Some WLUN doesn't support unit descriptor */
 +   if (ret == -EOPNOTSUPP)
 +   lun_qdepth = 1;
 +   else if (!lun_qdepth)
 +   /* eventually, we can figure out the real queue depth */
 +   lun_qdepth = hba-nutrs;
 +   else
 +   lun_qdepth = min_t(int, lun_qdepth, hba-nutrs);

 If ufshcd_read_unit_desc_param() failed and its error code was not
 -EOPNOTSUPP, lun_qdepth is undefined.  In such cases lun_qdepth
 should be 1?

I'm not sure I follow your concern.
If this lun does not support command queuing (ret == -EOPNOTSUPP)
obviously, lun_qdepth should be 1.
If there was an error and lun_qdepth, was returned as 0, hba-nutrs will
be our default choice.
last, even if the query succeed we want to make sure we don't exceed the
hba-nutrs.

Thanks,
Dolev

 --
 To unsubscribe from this list: send the line unsubscribe linux-scsi in
 the body of a message to majord...@vger.kernel.org
 More majordomo info at  http://vger.kernel.org/majordomo-info.html



-- 
QUALCOMM ISRAEL, on behalf of Qualcomm Innovation Center, Inc. is a member
of Code Aurora Forum, hosted by The Linux Foundation


--
To unsubscribe from this list: send the line unsubscribe linux-scsi in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [PATCH V3 10/16] scsi: ufs: add UFS power management support

2014-09-15 Thread Dolev Raviv

 2014-09-10 20:54 GMT+09:00 Dolev Raviv dra...@codeaurora.org:
 +static inline void ufshcd_enable_irq(struct ufs_hba *hba)
 +{
 +   if (!hba-is_irq_enabled) {
 +   enable_irq(hba-irq);
 +   hba-is_irq_enabled = true;
 +   }
 +}
 +
 +static inline void ufshcd_disable_irq(struct ufs_hba *hba)
 +{
 +   if (hba-is_irq_enabled) {
 +   disable_irq(hba-irq);
 +   hba-is_irq_enabled = false;
 +   }
 +}

 This IRQ could be shared among several devices because it is requested
 with IRQF_SHARED.  So enable_irq()/disable_irq() should be replaced with
 request_irq()/free_irq()?  Otherwise other devices which share the same
 IRQ will be malfunction while disabling IRQ.

Thanks, I will test your suggestion.

 --
 To unsubscribe from this list: send the line unsubscribe linux-scsi in
 the body of a message to majord...@vger.kernel.org
 More majordomo info at  http://vger.kernel.org/majordomo-info.html



-- 
QUALCOMM ISRAEL, on behalf of Qualcomm Innovation Center, Inc. is a member
of Code Aurora Forum, hosted by The Linux Foundation


--
To unsubscribe from this list: send the line unsubscribe linux-scsi in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [PATCH V3 11/16] scsi: ufs: refactor configuring power mode

2014-09-15 Thread Dolev Raviv

 2014-09-10 20:54 GMT+09:00 Dolev Raviv dra...@codeaurora.org:
 +static 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 };
 +   int ret;
 +
 +   if (hba-vops-pwr_change_notify)

 If hba-vops is null as no vendor specific callbacks, this causes
 a null pointer dereference.  So null check for hba-vops is also needed
 just like other callbacks.

Sure, will fix both.


 +   hba-vops-pwr_change_notify(hba,
 +PRE_CHANGE, desired_pwr_mode, final_params);
 +   else
 +   memcpy(final_params, desired_pwr_mode,
 sizeof(final_params));
 +
 /*
  * Configure attributes for power mode change with below.
  * - PA_RXGEAR, PA_ACTIVERXDATALANES, PA_RXTERMINATION,
  * - PA_TXGEAR, PA_ACTIVETXDATALANES, PA_TXTERMINATION,
  * - PA_HSSERIES
  */
 -   ufshcd_dme_set(hba, UIC_ARG_MIB(PA_RXGEAR), gear[RX]);
 -   ufshcd_dme_set(hba, UIC_ARG_MIB(PA_ACTIVERXDATALANES),
 lanes[RX]);
 -   if (pwr[RX] == FASTAUTO_MODE)
 +   ufshcd_dme_set(hba, UIC_ARG_MIB(PA_RXGEAR),
 final_params.gear_rx);
 +   ufshcd_dme_set(hba, UIC_ARG_MIB(PA_ACTIVERXDATALANES),
 +   final_params.lane_rx);
 +   if (final_params.pwr_rx == FASTAUTO_MODE ||
 +   final_params.pwr_rx == FAST_MODE)
 ufshcd_dme_set(hba, UIC_ARG_MIB(PA_RXTERMINATION),
 TRUE);
 +   else
 +   ufshcd_dme_set(hba, UIC_ARG_MIB(PA_RXTERMINATION),
 FALSE);

 -   ufshcd_dme_set(hba, UIC_ARG_MIB(PA_TXGEAR), gear[TX]);
 -   ufshcd_dme_set(hba, UIC_ARG_MIB(PA_ACTIVETXDATALANES),
 lanes[TX]);
 -   if (pwr[TX] == FASTAUTO_MODE)
 +   ufshcd_dme_set(hba, UIC_ARG_MIB(PA_TXGEAR),
 final_params.gear_tx);
 +   ufshcd_dme_set(hba, UIC_ARG_MIB(PA_ACTIVETXDATALANES),
 +   final_params.lane_tx);
 +   if (final_params.pwr_tx == FASTAUTO_MODE ||
 +   final_params.pwr_tx == FAST_MODE)
 ufshcd_dme_set(hba, UIC_ARG_MIB(PA_TXTERMINATION),
 TRUE);
 -
 -   if (pwr[RX] == FASTAUTO_MODE || pwr[TX] == FASTAUTO_MODE)
 -   ufshcd_dme_set(hba, UIC_ARG_MIB(PA_HSSERIES),
 PA_HS_MODE_B);
 -
 -   ret = ufshcd_uic_change_pwr_mode(hba, pwr[RX]  4 | pwr[TX]);
 -   if (ret)
 +   else
 +   ufshcd_dme_set(hba, UIC_ARG_MIB(PA_TXTERMINATION),
 FALSE);
 +
 +   if ((final_params.pwr_rx == FASTAUTO_MODE ||
 +   final_params.pwr_tx == FASTAUTO_MODE ||
 +   final_params.pwr_rx == FAST_MODE ||
 +   final_params.pwr_tx == FAST_MODE) 
 +   final_params.hs_rate == PA_HS_MODE_B)
 +   ufshcd_dme_set(hba, UIC_ARG_MIB(PA_HSSERIES),
 +   final_params.hs_rate);
 +
 +   ret = ufshcd_uic_change_pwr_mode(hba, final_params.pwr_rx  4
 +   | final_params.pwr_tx);
 +   if (ret) {
 dev_err(hba-dev,
 pwr_mode: power mode change failed %d\n, ret);
 +   } else {
 +   if (hba-vops-pwr_change_notify)

 Ditto.

 +   hba-vops-pwr_change_notify(hba,
 +   POST_CHANGE, NULL, final_params);
 +
 +   memcpy(hba-pwr_info, final_params,
 sizeof(final_params));
 +   }
 --
 To unsubscribe from this list: send the line unsubscribe linux-scsi in
 the body of a message to majord...@vger.kernel.org
 More majordomo info at  http://vger.kernel.org/majordomo-info.html



-- 
QUALCOMM ISRAEL, on behalf of Qualcomm Innovation Center, Inc. is a member
of Code Aurora Forum, hosted by The Linux Foundation


--
To unsubscribe from this list: send the line unsubscribe linux-scsi in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH V3 02/16] scsi: balance out autopm get/put calls in scsi_sysfs_add_sdev()

2014-09-10 Thread Dolev Raviv
From: Subhash Jadavani subha...@codeaurora.org

SCSI Well-known logical units generally don't have any scsi driver
associated with it which means no one will call scsi_autopm_put_device()
on these wlun scsi devices and this would result in keeping the
corresponding scsi device always active (hence LLD can't be suspended as
well). Same exact problem can be seen for other scsi device representing
normal logical unit whose driver is yet to be loaded. This patch fixes
the above problem with this approach:

- make the scsi_autopm_put_device call at the end of scsi_sysfs_add_sdev
  to make it balance out the get earlier in the function.
- let drivers do paired get/put calls in their probe methods.

Signed-off-by: Subhash Jadavani subha...@codeaurora.org
Signed-off-by: Dolev Raviv dra...@codeaurora.org

diff --git a/drivers/scsi/scsi_sysfs.c b/drivers/scsi/scsi_sysfs.c
index 8b4105a..3524b68 100644
--- a/drivers/scsi/scsi_sysfs.c
+++ b/drivers/scsi/scsi_sysfs.c
@@ -1044,10 +1044,6 @@ int scsi_sysfs_add_sdev(struct scsi_device *sdev)
pm_runtime_enable(sdev-sdev_gendev);
scsi_autopm_put_target(starget);
 
-   /* The following call will keep sdev active indefinitely, until
-* its driver does a corresponding scsi_autopm_pm_device().  Only
-* drivers supporting autosuspend will do this.
-*/
scsi_autopm_get_device(sdev);
 
error = device_add(sdev-sdev_gendev);
@@ -1085,6 +1081,7 @@ int scsi_sysfs_add_sdev(struct scsi_device *sdev)
}
}
 
+   scsi_autopm_put_device(sdev);
return error;
 }
 
diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c
index aa43496..0cb5c9f 100644
--- a/drivers/scsi/sd.c
+++ b/drivers/scsi/sd.c
@@ -2965,6 +2965,7 @@ static int sd_probe(struct device *dev)
int index;
int error;
 
+   scsi_autopm_get_device(sdp);
error = -ENODEV;
if (sdp-type != TYPE_DISK  sdp-type != TYPE_MOD  sdp-type != 
TYPE_RBC)
goto out;
@@ -3041,6 +3042,7 @@ static int sd_probe(struct device *dev)
  out_free:
kfree(sdkp);
  out:
+   scsi_autopm_put_device(sdp);
return error;
 }
 
diff --git a/drivers/scsi/sr.c b/drivers/scsi/sr.c
index 7eeb936..2de44cc 100644
--- a/drivers/scsi/sr.c
+++ b/drivers/scsi/sr.c
@@ -657,6 +657,7 @@ static int sr_probe(struct device *dev)
struct scsi_cd *cd;
int minor, error;
 
+   scsi_autopm_get_device(sdev);
error = -ENODEV;
if (sdev-type != TYPE_ROM  sdev-type != TYPE_WORM)
goto fail;
@@ -744,6 +745,7 @@ fail_put:
 fail_free:
kfree(cd);
 fail:
+   scsi_autopm_put_device(sdev);
return error;
 }
 
diff --git a/drivers/scsi/st.c b/drivers/scsi/st.c
index aff9689..d3fd6e8 100644
--- a/drivers/scsi/st.c
+++ b/drivers/scsi/st.c
@@ -4105,6 +4105,7 @@ static int st_probe(struct device *dev)
return -ENODEV;
}
 
+   scsi_autopm_get_device(SDp);
i = queue_max_segments(SDp-request_queue);
if (st_max_sg_segs  i)
i = st_max_sg_segs;
@@ -4244,6 +4245,7 @@ out_put_disk:
 out_buffer_free:
kfree(buffer);
 out:
+   scsi_autopm_put_device(SDp);
return -ENODEV;
 };
 
-- 
1.8.5.2
-- 
QUALCOMM ISRAEL, on behalf of Qualcomm Innovation Center, Inc. is a member
of Code Aurora Forum, hosted by The Linux Foundation

--
To unsubscribe from this list: send the line unsubscribe linux-scsi in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH V3 01/16] scsi: support well known logical units

2014-09-10 Thread Dolev Raviv
From: Subhash Jadavani subha...@codeaurora.org

REPORT LUNS command has SELECT REPORT field which controls what type of
logical units to be reported by device server. According to UFS device
standard, if this field is set to 0, REPORT LUNS would report only report
standard logical units. If it's set to 1 then it would report only well
known logical unit and if it's set to 2 then device would report both
standard and well known logical units.

Signed-off-by: Subhash Jadavani subha...@codeaurora.org
Signed-off-by: Sujit Reddy Thumma sthu...@codeaurora.org
Signed-off-by: Dolev Raviv dra...@codeaurora.org

diff --git a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c
index 56675db..d7f0df8 100644
--- a/drivers/scsi/scsi_scan.c
+++ b/drivers/scsi/scsi_scan.c
@@ -805,6 +805,14 @@ static int scsi_add_lun(struct scsi_device *sdev, unsigned 
char *inq_result,
} else {
sdev-type = (inq_result[0]  0x1f);
sdev-removable = (inq_result[1]  0x80)  7;
+
+   /*
+* some devices may respond with wrong type for
+* well-known logical units. Force well-known type
+* to enumerate them correctly.
+*/
+   if (scsi_is_wlun(sdev-lun))
+   sdev-type = TYPE_WLUN;
}
 
if (sdev-type == TYPE_RBC || sdev-type == TYPE_ROM) {
@@ -1400,6 +1408,12 @@ static int scsi_report_lun_scan(struct scsi_target 
*starget, int bflags,
memset(scsi_cmd[1], 0, 5);
 
/*
+* Set SELECT REPORT field to 0x2 which will make device to
+* report well known logical units along with standard LUs.
+*/
+   scsi_cmd[2] = 0x2;
+
+   /*
 * bytes 6 - 9: length of the command.
 */
scsi_cmd[6] = (unsigned char) (length  24)  0xff;
diff --git a/include/scsi/scsi.h b/include/scsi/scsi.h
index 261e708..d17178e 100644
--- a/include/scsi/scsi.h
+++ b/include/scsi/scsi.h
@@ -333,6 +333,7 @@ static inline int scsi_status_is_good(int status)
 #define TYPE_RBC   0x0e
 #define TYPE_OSD0x11
 #define TYPE_ZBC0x14
+#define TYPE_WLUN   0x1e/* well-known logical unit */
 #define TYPE_NO_LUN 0x7f
 
 /* SCSI protocols; these are taken from SPC-3 section 7.5 */
-- 
1.8.5.2
-- 
QUALCOMM ISRAEL, on behalf of Qualcomm Innovation Center, Inc. is a member
of Code Aurora Forum, hosted by The Linux Foundation

--
To unsubscribe from this list: send the line unsubscribe linux-scsi in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH V3 00/16] UFS: Power management support

2014-09-10 Thread Dolev Raviv
This patch seies introduces support for power management in the driver as well 
as vendor specific initialization - registers, clocks, voltage regulators etc.

It includes also a rework for the init sequence and other PM pre-requisite such 
as write protection support, handling well-known LUN, error handling (retries), 
bkops, START_STOP unit command, and ICC levels settings.

--
Changes from V2:
 - Reordered scsi core patches
 - add patch [PATCH V3 02/16] scsi: balance out autopm get/put calls in
 - Minor changes/fixes to the patches:
* [PATCH V3 10/16] scsi: ufs: add UFS power management support
* [PATCH V3 12/16] scsi: ufs: Add support for clock gating
* [PATCH V3 16/16] scsi: ufs: definitions for phy interface
   In order to address community concerns, and as a result of further
   development and testing.

Changes from V1:
 - 6 new patches apended at the end
 - Allow overriding power configuration with controller support and
   preferences/capabilities Dolev Raviv
 - Allow overriding power choice with controller capabilities Dolev Raviv
 - Add support for clock gating and clock scaling Sahitya Tummala
 - Add capability to control the auto bkops during suspend Subhash Jadavani
 - Add misc changes for phy/unipro driver usage Dolev Raviv

Dolev Raviv (2):
  scsi: ufs: refactor configuring power mode
  scsi: ufs: definitions for phy interface

Sahitya Tummala (3):
  scsi: ufs: Add support for clock gating
  scsi: ufs: Add freq-table-hz property for UFS device
  scsi: ufs: Add support for clock scaling using devfreq framework

Subhash Jadavani (6):
  scsi: support well known logical units
  scsi: balance out autopm get/put calls in scsi_sysfs_add_sdev()
  scsi: ufs: refactor query descriptor API support
  scsi: ufs: introduce well known logical unit in ufs
  scsi: ufs: add UFS power management support
  scsi: ufs: tune bkops while power managment events

Sujit Reddy Thumma (4):
  scsi: ufs: Allow vendor specific initialization
  scsi: ufs: Add regulator enable support
  scsi: ufs: Add clock initialization support
  scsi: ufs: improve init sequence

Yaniv Gardi (1):
  scsi: ufs: Active Power Mode - configuring bActiveICCLevel

 .../devicetree/bindings/ufs/ufshcd-pltfrm.txt  |   37 +
 drivers/scsi/scsi_scan.c   |   14 +
 drivers/scsi/scsi_sysfs.c  |5 +-
 drivers/scsi/sd.c  |2 +
 drivers/scsi/sr.c  |2 +
 drivers/scsi/st.c  |2 +
 drivers/scsi/ufs/Kconfig   |2 +
 drivers/scsi/ufs/ufs.h |  131 +-
 drivers/scsi/ufs/ufshcd-pci.c  |   55 +-
 drivers/scsi/ufs/ufshcd-pltfrm.c   |  282 ++-
 drivers/scsi/ufs/ufshcd.c  | 2408 ++--
 drivers/scsi/ufs/ufshcd.h  |  277 ++-
 drivers/scsi/ufs/ufshci.h  |9 +-
 drivers/scsi/ufs/unipro.h  |   56 +
 include/scsi/scsi.h|1 +
 15 files changed, 2962 insertions(+), 321 deletions(-)

-- 
1.8.5.2
-- 
QUALCOMM ISRAEL, on behalf of Qualcomm Innovation Center, Inc. is a member
of Code Aurora Forum, hosted by The Linux Foundation

--
To unsubscribe from this list: send the line unsubscribe linux-scsi in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH V3 08/16] scsi: ufs: Active Power Mode - configuring bActiveICCLevel

2014-09-10 Thread Dolev Raviv
From: Yaniv Gardi yga...@codeaurora.org

The maximum power consumption in active is determined by bActiveICCLevel.
The configuration is done by reading max current supported by the
regulators connected to VCC, VCCQ and VCCQ2 rails on the boards, and
reading the current consumption levels from the device for each rails
(vcc/vccq/vccq2) using power descriptor.
We configure the bActiveICCLevel attribute, with the max value that
correspond to the minimum-of(VCC-current-level,VCCQ-current-level,
VCCQ2-current-level).
In order to minimize resume latency, pre-fetch icc levels and reference
clock during initialization and avoid reading them each link startup
during resume.

Signed-off-by: Raviv Shvili rshv...@codeaurora.org
Signed-off-by: Yaniv Gardi yga...@codeaurora.org
Signed-off-by: Dolev Raviv dra...@codeaurora.org

diff --git a/drivers/scsi/ufs/ufs.h b/drivers/scsi/ufs/ufs.h
index 7ea8e71..b0e1f62 100644
--- a/drivers/scsi/ufs/ufs.h
+++ b/drivers/scsi/ufs/ufs.h
@@ -115,6 +115,7 @@ enum flag_idn {
 
 /* Attribute idn for Query requests */
 enum attr_idn {
+   QUERY_ATTR_IDN_ACTIVE_ICC_LVL   = 0x03,
QUERY_ATTR_IDN_BKOPS_STATUS = 0x05,
QUERY_ATTR_IDN_EE_CONTROL   = 0x0D,
QUERY_ATTR_IDN_EE_STATUS= 0x0E,
@@ -174,6 +175,31 @@ enum unit_desc_param {
UNIT_DESC_PARAM_LARGE_UNIT_SIZE_M1  = 0x22,
 };
 
+/* bActiveICCLevel parameter current units */
+enum {
+   UFSHCD_NANO_AMP = 0,
+   UFSHCD_MICRO_AMP= 1,
+   UFSHCD_MILI_AMP = 2,
+   UFSHCD_AMP  = 3,
+};
+
+#define POWER_DESC_MAX_SIZE0x62
+#define POWER_DESC_MAX_ACTV_ICC_LVLS   16
+
+/* Attribute  bActiveICCLevel parameter bit masks definitions */
+#define ATTR_ICC_LVL_UNIT_OFFSET   14
+#define ATTR_ICC_LVL_UNIT_MASK (0x3  ATTR_ICC_LVL_UNIT_OFFSET)
+#define ATTR_ICC_LVL_VALUE_MASK0x3FF
+
+/* Power descriptor parameters offsets in bytes */
+enum power_desc_param_offset {
+   PWR_DESC_LEN= 0x0,
+   PWR_DESC_TYPE   = 0x1,
+   PWR_DESC_ACTIVE_LVLS_VCC_0  = 0x2,
+   PWR_DESC_ACTIVE_LVLS_VCCQ_0 = 0x22,
+   PWR_DESC_ACTIVE_LVLS_VCCQ2_0= 0x42,
+};
+
 /* Exception event mask values */
 enum {
MASK_EE_STATUS  = 0x,
diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index 1fabff4..a851323 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -3265,6 +3265,125 @@ static int ufshcd_eh_host_reset_handler(struct 
scsi_cmnd *cmd)
 }
 
 /**
+ * ufshcd_get_max_icc_level - calculate the ICC level
+ * @sup_curr_uA: max. current supported by the regulator
+ * @start_scan: row at the desc table to start scan from
+ * @buff: power descriptor buffer
+ *
+ * Returns calculated max ICC level for specific regulator
+ */
+static u32 ufshcd_get_max_icc_level(int sup_curr_uA, u32 start_scan, char 
*buff)
+{
+   int i;
+   int curr_uA;
+   u16 data;
+   u16 unit;
+
+   for (i = start_scan; i = 0; i--) {
+   data = be16_to_cpu(*((u16 *)(buff + 2*i)));
+   unit = (data  ATTR_ICC_LVL_UNIT_MASK) 
+   ATTR_ICC_LVL_UNIT_OFFSET;
+   curr_uA = data  ATTR_ICC_LVL_VALUE_MASK;
+   switch (unit) {
+   case UFSHCD_NANO_AMP:
+   curr_uA = curr_uA / 1000;
+   break;
+   case UFSHCD_MILI_AMP:
+   curr_uA = curr_uA * 1000;
+   break;
+   case UFSHCD_AMP:
+   curr_uA = curr_uA * 1000 * 1000;
+   break;
+   case UFSHCD_MICRO_AMP:
+   default:
+   break;
+   }
+   if (sup_curr_uA = curr_uA)
+   break;
+   }
+   if (i  0) {
+   i = 0;
+   pr_err(%s: Couldn't find valid icc_level = %d, __func__, i);
+   }
+
+   return (u32)i;
+}
+
+/**
+ * ufshcd_calc_icc_level - calculate the max ICC level
+ * In case regulators are not initialized we'll return 0
+ * @hba: per-adapter instance
+ * @desc_buf: power descriptor buffer to extract ICC levels from.
+ * @len: length of desc_buff
+ *
+ * Returns calculated ICC level
+ */
+static u32 ufshcd_find_max_sup_active_icc_level(struct ufs_hba *hba,
+   u8 *desc_buf, int len)
+{
+   u32 icc_level = 0;
+
+   if (!hba-vreg_info.vcc || !hba-vreg_info.vccq ||
+   !hba-vreg_info.vccq2) {
+   dev_err(hba-dev,
+   %s: Regulator capability was not set, actvIccLevel=%d,
+   __func__, icc_level);
+   goto out;
+   }
+
+   if (hba-vreg_info.vcc)
+   icc_level = ufshcd_get_max_icc_level

[PATCH V3 11/16] scsi: ufs: refactor configuring power mode

2014-09-10 Thread Dolev Raviv
Sometimes, the device shall report its maximum power and speed
capabilities, but we might not wish to configure it to use those
maximum capabilities.
This change adds support for the vendor specific host driver to
implement power change notify callback.

To enable configuring different power modes (number of lanes,
gear number and fast/slow modes) it is necessary to split the
configuration stage from the stage that reads the device max power mode.
In addition, it is not required to read the configuration more than
once, thus the configuration is stored after reading it once.

Signed-off-by: Dolev Raviv dra...@codeaurora.org
Signed-off-by: Yaniv Gardi yga...@codeaurora.org

diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index 79ef312..bfa9a75 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -178,6 +178,8 @@ static int ufshcd_clear_tm_cmd(struct ufs_hba *hba, int 
tag);
 static void ufshcd_hba_exit(struct ufs_hba *hba);
 static int ufshcd_probe_hba(struct ufs_hba *hba);
 static int ufshcd_host_reset_and_restore(struct ufs_hba *hba);
+static int ufshcd_config_pwr_mode(struct ufs_hba *hba,
+   struct ufs_pa_layer_attr *desired_pwr_mode);
 
 static inline void ufshcd_enable_irq(struct ufs_hba *hba)
 {
@@ -1933,65 +1935,129 @@ static int ufshcd_uic_hibern8_exit(struct ufs_hba *hba)
 }
 
 /**
- * ufshcd_config_max_pwr_mode - Set  Change power mode with
- * maximum capability attribute information.
- * @hba: per adapter instance
- *
- * Returns 0 on success, non-zero value on failure
+ * ufshcd_get_max_pwr_mode - reads the max power mode negotiated with device
+ * @hba: per-adapter instance
  */
-static int ufshcd_config_max_pwr_mode(struct ufs_hba *hba)
+static int ufshcd_get_max_pwr_mode(struct ufs_hba *hba)
 {
-   enum {RX = 0, TX = 1};
-   u32 lanes[] = {1, 1};
-   u32 gear[] = {1, 1};
-   u8 pwr[] = {FASTAUTO_MODE, FASTAUTO_MODE};
-   int ret;
+   struct ufs_pa_layer_attr *pwr_info = hba-max_pwr_info.info;
+
+   if (hba-max_pwr_info.is_valid)
+   return 0;
+
+   pwr_info-pwr_tx = FASTAUTO_MODE;
+   pwr_info-pwr_rx = FASTAUTO_MODE;
+   pwr_info-hs_rate = PA_HS_MODE_B;
 
/* Get the connected lane count */
-   ufshcd_dme_get(hba, UIC_ARG_MIB(PA_CONNECTEDRXDATALANES), lanes[RX]);
-   ufshcd_dme_get(hba, UIC_ARG_MIB(PA_CONNECTEDTXDATALANES), lanes[TX]);
+   ufshcd_dme_get(hba, UIC_ARG_MIB(PA_CONNECTEDRXDATALANES),
+   pwr_info-lane_rx);
+   ufshcd_dme_get(hba, UIC_ARG_MIB(PA_CONNECTEDTXDATALANES),
+   pwr_info-lane_tx);
+
+   if (!pwr_info-lane_rx || !pwr_info-lane_tx) {
+   dev_err(hba-dev, %s: invalid connected lanes value. rx=%d, 
tx=%d\n,
+   __func__,
+   pwr_info-lane_rx,
+   pwr_info-lane_tx);
+   return -EINVAL;
+   }
 
/*
 * First, get the maximum gears of HS speed.
 * If a zero value, it means there is no HSGEAR capability.
 * Then, get the maximum gears of PWM speed.
 */
-   ufshcd_dme_get(hba, UIC_ARG_MIB(PA_MAXRXHSGEAR), gear[RX]);
-   if (!gear[RX]) {
-   ufshcd_dme_get(hba, UIC_ARG_MIB(PA_MAXRXPWMGEAR), gear[RX]);
-   pwr[RX] = SLOWAUTO_MODE;
+   ufshcd_dme_get(hba, UIC_ARG_MIB(PA_MAXRXHSGEAR), pwr_info-gear_rx);
+   if (!pwr_info-gear_rx) {
+   ufshcd_dme_get(hba, UIC_ARG_MIB(PA_MAXRXPWMGEAR),
+   pwr_info-gear_rx);
+   if (!pwr_info-gear_rx) {
+   dev_err(hba-dev, %s: invalid max pwm rx gear read = 
%d\n,
+   __func__, pwr_info-gear_rx);
+   return -EINVAL;
+   }
+   pwr_info-pwr_rx = SLOWAUTO_MODE;
}
 
-   ufshcd_dme_peer_get(hba, UIC_ARG_MIB(PA_MAXRXHSGEAR), gear[TX]);
-   if (!gear[TX]) {
+   ufshcd_dme_peer_get(hba, UIC_ARG_MIB(PA_MAXRXHSGEAR),
+   pwr_info-gear_tx);
+   if (!pwr_info-gear_tx) {
ufshcd_dme_peer_get(hba, UIC_ARG_MIB(PA_MAXRXPWMGEAR),
-   gear[TX]);
-   pwr[TX] = SLOWAUTO_MODE;
+   pwr_info-gear_tx);
+   if (!pwr_info-gear_tx) {
+   dev_err(hba-dev, %s: invalid max pwm tx gear read = 
%d\n,
+   __func__, pwr_info-gear_tx);
+   return -EINVAL;
+   }
+   pwr_info-pwr_tx = SLOWAUTO_MODE;
}
 
+   hba-max_pwr_info.is_valid = true;
+   return 0;
+}
+
+/**
+ * ufshcd_config_pwr_mode - configure a new power mode
+ * @hba: per-adapter instance
+ * @desired_pwr_mode: desired power configuration
+ */
+static int ufshcd_config_pwr_mode(struct ufs_hba *hba,
+   struct ufs_pa_layer_attr *desired_pwr_mode)
+{
+   struct

[PATCH V3 07/16] scsi: ufs: improve init sequence

2014-09-10 Thread Dolev Raviv
From: Sujit Reddy Thumma sthu...@codeaurora.org

In -hce_enable_notify() callback the vendor specific initialization
may carry out additional DME configuration using UIC commands and
hence the UIC command completion interrupt enable bit should be set
before the post reset notification.
Add retries if the link-startup fails. This is required since due to
hardware timing issues, the Uni-Pro link-startup might fail. The UFS
HCI recovery procedure contradicts the Uni-Pro sequence. The UFS HCI
specifies to resend DME_LINKSTARTUP command after IS.ULLS (link-lost
interrupt) is received. The Uni-Pro specifies that if link-startup
fails the link is in down state. The link-lost is indicated to the
DME user only when the link is up. Hence, the UFS HCI recovery procedure
of waiting for IS.ULLS and retrying link-startup may not work properly.

At the end, if detection fails, power off (disable clocks, regulators,
phy) if the UFS device detection fails. This saves power while UFS device
is not embedded into the system.

Signed-off-by: Sujit Reddy Thumma sthu...@codeaurora.org
Signed-off-by: Dolev Raviv dra...@codeaurora.org

diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index 57a8dbb..1fabff4 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -62,6 +62,12 @@
 /* Task management command timeout */
 #define TM_CMD_TIMEOUT 100 /* msecs */
 
+/* maximum number of link-startup retries */
+#define DME_LINKSTARTUP_RETRIES 3
+
+/* maximum number of reset retries before giving up */
+#define MAX_HOST_RESET_RETRIES 5
+
 /* Expose the flag value from utp_upiu_query.value */
 #define MASK_QUERY_UPIU_FLAG_LOC 0xFF
 
@@ -137,6 +143,8 @@ static void ufshcd_tmc_handler(struct ufs_hba *hba);
 static void ufshcd_async_scan(void *data, async_cookie_t cookie);
 static int ufshcd_reset_and_restore(struct ufs_hba *hba);
 static int ufshcd_clear_tm_cmd(struct ufs_hba *hba, int tag);
+static void ufshcd_hba_exit(struct ufs_hba *hba);
+static int ufshcd_probe_hba(struct ufs_hba *hba);
 
 /*
  * ufshcd_wait_for_register - wait for register value to change
@@ -2043,6 +2051,9 @@ static int ufshcd_hba_enable(struct ufs_hba *hba)
msleep(5);
}
 
+   /* enable UIC related interrupts */
+   ufshcd_enable_intr(hba, UIC_COMMAND_COMPL);
+
if (hba-vops  hba-vops-hce_enable_notify)
hba-vops-hce_enable_notify(hba, POST_CHANGE);
 
@@ -2058,23 +2069,33 @@ static int ufshcd_hba_enable(struct ufs_hba *hba)
 static int ufshcd_link_startup(struct ufs_hba *hba)
 {
int ret;
+   int retries = DME_LINKSTARTUP_RETRIES;
 
-   /* enable UIC related interrupts */
-   ufshcd_enable_intr(hba, UIC_COMMAND_COMPL);
+   do {
+   if (hba-vops  hba-vops-link_startup_notify)
+   hba-vops-link_startup_notify(hba, PRE_CHANGE);
 
-   if (hba-vops  hba-vops-link_startup_notify)
-   hba-vops-link_startup_notify(hba, PRE_CHANGE);
+   ret = ufshcd_dme_link_startup(hba);
 
-   ret = ufshcd_dme_link_startup(hba);
-   if (ret)
-   goto out;
+   /* check if device is detected by inter-connect layer */
+   if (!ret  !ufshcd_is_device_present(hba)) {
+   dev_err(hba-dev, %s: Device not present\n, __func__);
+   ret = -ENXIO;
+   goto out;
+   }
+
+   /*
+* DME link lost indication is only received when link is up,
+* but we can't be sure if the link is up until link startup
+* succeeds. So reset the local Uni-Pro and try again.
+*/
+   if (ret  ufshcd_hba_enable(hba))
+   goto out;
+   } while (ret  retries--);
 
-   /* check if device is detected by inter-connect layer */
-   if (!ufshcd_is_device_present(hba)) {
-   dev_err(hba-dev, %s: Device not present\n, __func__);
-   ret = -ENXIO;
+   if (ret)
+   /* failed to get the link up... retire */
goto out;
-   }
 
/* Include any host controller configuration via UIC commands */
if (hba-vops  hba-vops-link_startup_notify) {
@@ -3139,7 +3160,6 @@ out:
 static int ufshcd_host_reset_and_restore(struct ufs_hba *hba)
 {
int err;
-   async_cookie_t cookie;
unsigned long flags;
 
/* Reset the host controller */
@@ -3152,10 +3172,9 @@ static int ufshcd_host_reset_and_restore(struct ufs_hba 
*hba)
goto out;
 
/* Establish the link again and restore the device */
-   cookie = async_schedule(ufshcd_async_scan, hba);
-   /* wait for async scan to be completed */
-   async_synchronize_cookie(++cookie);
-   if (hba-ufshcd_state != UFSHCD_STATE_OPERATIONAL)
+   err = ufshcd_probe_hba(hba);
+
+   if (!err  (hba-ufshcd_state != UFSHCD_STATE_OPERATIONAL))
err = -EIO;
 out

[PATCH V3 15/16] scsi: ufs: tune bkops while power managment events

2014-09-10 Thread Dolev Raviv
From: Subhash Jadavani subha...@codeaurora.org

Add capability to control the auto bkops during suspend.
If host explicitly enables the auto bkops (background operation) on device
then only device would perform the bkops on its own. If auto bkops is not
enabled explicitly and if the device reaches to state where it must do
background operation, device would raise the urgent bkops exception event
to host and then host will enable the auto bkops on device. This patch
adds the option to choose whether auto bkops should be enabled during
runtime suspend or not. Since we don't want to keep the device active to
perform the non critical bkops, host will enable urgent bkops only.

Keep auto-bkops enabled after resume if urgent bkops needed.
If device bkops status shows that its in critical need of executing
background operations, host should allow the device to continue doing
background operations.

Signed-off-by: Subhash Jadavani subha...@codeaurora.org
Signed-off-by: Dolev Raviv dra...@codeaurora.org

diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index 0bbb933..33984cc 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -4719,13 +4719,19 @@ static int ufshcd_suspend(struct ufs_hba *hba, enum 
ufs_pm_op pm_op)
}
 
if (ufshcd_is_runtime_pm(pm_op)) {
-   /*
-* The device is idle with no requests in the queue,
-* allow background operations if needed.
-*/
-   ret = ufshcd_bkops_ctrl(hba, BKOPS_STATUS_NON_CRITICAL);
-   if (ret)
-   goto enable_gating;
+   if (ufshcd_can_autobkops_during_suspend(hba)) {
+   /*
+* The device is idle with no requests in the queue,
+* allow background operations if bkops status shows
+* that performance might be impacted.
+*/
+   ret = ufshcd_urgent_bkops(hba);
+   if (ret)
+   goto enable_gating;
+   } else {
+   /* make sure that auto bkops is disabled */
+   ufshcd_disable_auto_bkops(hba);
+   }
}
 
if ((req_dev_pwr_mode != hba-curr_dev_pwr_mode) 
@@ -4871,7 +4877,11 @@ static int ufshcd_resume(struct ufs_hba *hba, enum 
ufs_pm_op pm_op)
goto set_old_link_state;
}
 
-   ufshcd_disable_auto_bkops(hba);
+   /*
+* If BKOPs operations are urgently needed at this moment then
+* keep auto-bkops enabled or else disable it.
+*/
+   ufshcd_urgent_bkops(hba);
hba-clk_gating.is_suspended = false;
 
if (ufshcd_is_clkscaling_enabled(hba))
diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h
index d5699d0..b94b835 100644
--- a/drivers/scsi/ufs/ufshcd.h
+++ b/drivers/scsi/ufs/ufshcd.h
@@ -466,6 +466,8 @@ struct ufs_hba {
 #define UFSHCD_CAP_HIBERN8_WITH_CLK_GATING (1  1)
/* Allow dynamic clk scaling */
 #define UFSHCD_CAP_CLK_SCALING (1  2)
+   /* Allow auto bkops to enabled during runtime suspend */
+#define UFSHCD_CAP_AUTO_BKOPS_SUSPEND (1  3)
 
struct devfreq *devfreq;
struct ufs_clk_scaling clk_scaling;
@@ -484,6 +486,11 @@ static inline int ufshcd_is_clkscaling_enabled(struct 
ufs_hba *hba)
 {
return hba-caps  UFSHCD_CAP_CLK_SCALING;
 }
+static inline bool ufshcd_can_autobkops_during_suspend(struct ufs_hba *hba)
+{
+   return hba-caps  UFSHCD_CAP_AUTO_BKOPS_SUSPEND;
+}
+
 #define ufshcd_writel(hba, val, reg)   \
writel((val), (hba)-mmio_base + (reg))
 #define ufshcd_readl(hba, reg) \
-- 
1.8.5.2
-- 
QUALCOMM ISRAEL, on behalf of Qualcomm Innovation Center, Inc. is a member
of Code Aurora Forum, hosted by The Linux Foundation

--
To unsubscribe from this list: send the line unsubscribe linux-scsi in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH V3 10/16] scsi: ufs: add UFS power management support

2014-09-10 Thread Dolev Raviv
From: Subhash Jadavani subha...@codeaurora.org

This patch adds support for UFS device and UniPro link power management
during runtime/system PM.

Main idea is to define multiple UFS low power levels based on UFS device
and UFS link power states. This would allow any specific platform or pci
driver to choose the best suited low power level during runtime and
system suspend based on their power goals.

bkops handlig:
To put the UFS device in sleep state when bkops is disabled, first query
the bkops status from the device and enable bkops on device only if
device needs time to perform the bkops.

START_STOP handling:
Before sending START_STOP_UNIT to the device well-known logical unit
(w-lun) to make sure that the device w-lun unit attention condition is
cleared.

Write protection:
UFS device specification allows LUs to be write protected, either
permanently or power on write protected. If any LU is power on write
protected and if the card is power cycled (by powering off VCCQ and/or
VCC rails), LU's write protect status would be lost. So this means those
LUs can be written now. To ensures that UFS device is power cycled only
if the power on protect is not set for any of the LUs, check if power on
write protect is set and if device is in sleep/power-off state  link in
inactive state (Hibern8 or OFF state).
If none of the Logical Units on UFS device is power on write protected
then all UFS device power rails (VCC, VCCQ  VCCQ2) can be turned off if
UFS device is in power-off state and UFS link is in OFF state. But current
implementation would disable all device power rails even if UFS link is
not in OFF state.

Low power mode:
If UFS link is in OFF state then UFS host controller can be power collapsed
to avoid leakage current from it. Note that if UFS host controller is power
collapsed, full UFS reinitialization will be required on resume to
re-establish the link between host and device.

Signed-off-by: Subhash Jadavani subha...@codeaurora.org
Signed-off-by: Dolev Raviv dra...@codeaurora.org
Signed-off-by: Sujit Reddy Thumma sthu...@codeaurora.org

diff --git a/drivers/scsi/ufs/ufs.h b/drivers/scsi/ufs/ufs.h
index bcc3a7f..2a82959 100644
--- a/drivers/scsi/ufs/ufs.h
+++ b/drivers/scsi/ufs/ufs.h
@@ -129,6 +129,7 @@ enum {
 /* Flag idn for Query Requests*/
 enum flag_idn {
QUERY_FLAG_IDN_FDEVICEINIT  = 0x01,
+   QUERY_FLAG_IDN_PWR_ON_WPE   = 0x03,
QUERY_FLAG_IDN_BKOPS_EN = 0x04,
 };
 
@@ -194,6 +195,18 @@ enum unit_desc_param {
UNIT_DESC_PARAM_LARGE_UNIT_SIZE_M1  = 0x22,
 };
 
+/*
+ * Logical Unit Write Protect
+ * 00h: LU not write protected
+ * 01h: LU write protected when fPowerOnWPEn =1
+ * 02h: LU permanently write protected when fPermanentWPEn =1
+ */
+enum ufs_lu_wp_type {
+   UFS_LU_NO_WP= 0x00,
+   UFS_LU_POWER_ON_WP  = 0x01,
+   UFS_LU_PERM_WP  = 0x02,
+};
+
 /* bActiveICCLevel parameter current units */
 enum {
UFSHCD_NANO_AMP = 0,
@@ -226,11 +239,12 @@ enum {
 };
 
 /* Background operation status */
-enum {
+enum bkops_status {
BKOPS_STATUS_NO_OP   = 0x0,
BKOPS_STATUS_NON_CRITICAL= 0x1,
BKOPS_STATUS_PERF_IMPACT = 0x2,
BKOPS_STATUS_CRITICAL= 0x3,
+   BKOPS_STATUS_MAX = BKOPS_STATUS_CRITICAL,
 };
 
 /* UTP QUERY Transaction Specific Fields OpCode */
@@ -291,6 +305,14 @@ enum {
UPIU_TASK_MANAGEMENT_FUNC_FAILED= 0x05,
UPIU_INCORRECT_LOGICAL_UNIT_NO  = 0x09,
 };
+
+/* UFS device power modes */
+enum ufs_dev_pwr_mode {
+   UFS_ACTIVE_PWR_MODE = 1,
+   UFS_SLEEP_PWR_MODE  = 2,
+   UFS_POWERDOWN_PWR_MODE  = 3,
+};
+
 /**
  * struct utp_upiu_header - UPIU header structure
  * @dword_0: UPIU header DW-0
@@ -437,6 +459,12 @@ struct ufs_query_res {
 #define UFS_VREG_VCCQ2_MIN_UV 165 /* uV */
 #define UFS_VREG_VCCQ2_MAX_UV 195 /* uV */
 
+/*
+ * VCCQ  VCCQ2 current requirement when UFS device is in sleep state
+ * and link is in Hibern8 state.
+ */
+#define UFS_VREG_LPM_LOAD_UA   1000 /* uA */
+
 struct ufs_vreg {
struct regulator *reg;
const char *name;
@@ -453,4 +481,10 @@ struct ufs_vreg_info {
struct ufs_vreg *vccq2;
 };
 
+struct ufs_dev_info {
+   bool f_power_on_wp_en;
+   /* Keeps information if any of the LU is power on write protected */
+   bool is_lu_power_on_wp;
+};
+
 #endif /* End of Header */
diff --git a/drivers/scsi/ufs/ufshcd-pci.c b/drivers/scsi/ufs/ufshcd-pci.c
index 2a26faa..955ed55 100644
--- a/drivers/scsi/ufs/ufshcd-pci.c
+++ b/drivers/scsi/ufs/ufshcd-pci.c
@@ -43,34 +43,24 @@
  * @pdev: pointer to PCI device handle
  * @state: power state
  *
- * Returns -ENOSYS
+ * Returns 0 if successful
+ * Returns non-zero otherwise
  */
 static int ufshcd_pci_suspend(struct device *dev)
 {
-   /*
-* TODO:
-* 1. Call ufshcd_suspend
-* 2. Do bus specific power management

[PATCH V3 13/16] scsi: ufs: Add freq-table-hz property for UFS device

2014-09-10 Thread Dolev Raviv
From: Sahitya Tummala stumm...@codeaurora.org

Add freq-table-hz propery for UFS device to keep track of
min max frequencies supported by UFS clocks.

Signed-off-by: Sahitya Tummala stumm...@codeaurora.org
Signed-off-by: Dolev Raviv dra...@codeaurora.org

diff --git a/Documentation/devicetree/bindings/ufs/ufshcd-pltfrm.txt 
b/Documentation/devicetree/bindings/ufs/ufshcd-pltfrm.txt
index b0f791a..e73a619 100644
--- a/Documentation/devicetree/bindings/ufs/ufshcd-pltfrm.txt
+++ b/Documentation/devicetree/bindings/ufs/ufshcd-pltfrm.txt
@@ -24,11 +24,11 @@ Optional properties:
 - clocks: List of phandle and clock specifier pairs
 - clock-names   : List of clock input name strings sorted in the same
   order as the clocks property.
-- max-clock-frequency-hz : List of maximum operating frequency stored in the 
same
-   order as the clocks property. If this property is 
not
-  defined or a value in the array is 0 then it is 
assumed
-  that the frequency is set by the parent clock or a
-  fixed rate clock source.
+- freq-table-hz: Array of min max operating frequencies 
stored in the same
+  order as the clocks property. If this property is not
+ defined or a value in the array is 0 then it is 
assumed
+ that the frequency is set by the parent clock or a
+ fixed rate clock source.
 
 Note: If above properties are not defined it can be assumed that the supply
 regulators or clocks are always on.
@@ -49,5 +49,5 @@ Example:
 
clocks = core 0, ref 0, iface 0;
clock-names = core_clk, ref_clk, iface_clk;
-   max-clock-frequency-hz = 1 1920 0;
+   freq-table-hz = 1 2, 0 0, 0 0;
};
diff --git a/drivers/scsi/ufs/ufshcd-pltfrm.c b/drivers/scsi/ufs/ufshcd-pltfrm.c
index edaccd0..551be95 100644
--- a/drivers/scsi/ufs/ufshcd-pltfrm.c
+++ b/drivers/scsi/ufs/ufshcd-pltfrm.c
@@ -63,6 +63,8 @@ static int ufshcd_parse_clock_info(struct ufs_hba *hba)
char *name;
u32 *clkfreq = NULL;
struct ufs_clk_info *clki;
+   int len = 0;
+   size_t sz = 0;
 
if (!np)
goto out;
@@ -82,39 +84,59 @@ static int ufshcd_parse_clock_info(struct ufs_hba *hba)
if (cnt = 0)
goto out;
 
-   clkfreq = kzalloc(cnt * sizeof(*clkfreq), GFP_KERNEL);
+   if (!of_get_property(np, freq-table-hz, len)) {
+   dev_info(dev, freq-table-hz property not specified\n);
+   goto out;
+   }
+
+   if (len = 0)
+   goto out;
+
+   sz = len / sizeof(*clkfreq);
+   if (sz != 2 * cnt) {
+   dev_err(dev, %s len mismatch\n, freq-table-hz);
+   ret = -EINVAL;
+   goto out;
+   }
+
+   clkfreq = devm_kzalloc(dev, sz * sizeof(*clkfreq),
+   GFP_KERNEL);
if (!clkfreq) {
+   dev_err(dev, %s: no memory\n, freq-table-hz);
ret = -ENOMEM;
-   dev_err(dev, %s: memory alloc failed\n, __func__);
goto out;
}
 
-   ret = of_property_read_u32_array(np,
-   max-clock-frequency-hz, clkfreq, cnt);
+   ret = of_property_read_u32_array(np, freq-table-hz,
+   clkfreq, sz);
if (ret  (ret != -EINVAL)) {
-   dev_err(dev, %s: invalid max-clock-frequency-hz property, 
%d\n,
-   __func__, ret);
-   goto out;
+   dev_err(dev, %s: error reading array %d\n,
+   freq-table-hz, ret);
+   goto free_clkfreq;
}
 
-   for (i = 0; i  cnt; i++) {
+   for (i = 0; i  sz; i += 2) {
ret = of_property_read_string_index(np,
-   clock-names, i, (const char **)name);
+   clock-names, i/2, (const char **)name);
if (ret)
-   goto out;
+   goto free_clkfreq;
 
clki = devm_kzalloc(dev, sizeof(*clki), GFP_KERNEL);
if (!clki) {
ret = -ENOMEM;
-   goto out;
+   goto free_clkfreq;
}
 
-   clki-max_freq = clkfreq[i];
+   clki-min_freq = clkfreq[i];
+   clki-max_freq = clkfreq[i+1];
clki-name = kstrdup(name, GFP_KERNEL);
+   dev_dbg(dev, %s: min %u max %u name %s\n, freq-table-hz,
+   clki-min_freq, clki-max_freq, clki-name);
list_add_tail(clki-list, hba-clk_list_head);
}
-out:
+free_clkfreq:
kfree(clkfreq);
+out:
return ret;
 }
 
diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi

[PATCH V3 06/16] scsi: ufs: refactor query descriptor API support

2014-09-10 Thread Dolev Raviv
From: Subhash Jadavani subha...@codeaurora.org

Currently reading query descriptor is more tightened to each
descriptor type. This patch generalize the approach and allows
reading any parameter from any query descriptor.

Signed-off-by: Subhash Jadavani subha...@codeaurora.org
Signed-off-by: Dolev Raviv dra...@codeaurora.org

diff --git a/drivers/scsi/ufs/ufs.h b/drivers/scsi/ufs/ufs.h
index 729ce7d..7ea8e71 100644
--- a/drivers/scsi/ufs/ufs.h
+++ b/drivers/scsi/ufs/ufs.h
@@ -50,6 +50,8 @@
cpu_to_be32((byte3  24) | (byte2  16) |\
 (byte1  8) | (byte0))
 
+#define UFS_UPIU_MAX_GENERAL_LUN   8
+
 /*
  * UFS Protocol Information Unit related definitions
  */
@@ -129,10 +131,29 @@ enum desc_idn {
QUERY_DESC_IDN_RFU_1= 0x6,
QUERY_DESC_IDN_GEOMETRY = 0x7,
QUERY_DESC_IDN_POWER= 0x8,
-   QUERY_DESC_IDN_RFU_2= 0x9,
+   QUERY_DESC_IDN_MAX,
+};
+
+enum desc_header_offset {
+   QUERY_DESC_LENGTH_OFFSET= 0x00,
+   QUERY_DESC_DESC_TYPE_OFFSET = 0x01,
+};
+
+enum ufs_desc_max_size {
+   QUERY_DESC_DEVICE_MAX_SIZE  = 0x1F,
+   QUERY_DESC_CONFIGURAION_MAX_SIZE= 0x90,
+   QUERY_DESC_UNIT_MAX_SIZE= 0x23,
+   QUERY_DESC_INTERCONNECT_MAX_SIZE= 0x06,
+   /*
+* Max. 126 UNICODE characters (2 bytes per character) plus 2 bytes
+* of descriptor header.
+*/
+   QUERY_DESC_STRING_MAX_SIZE  = 0xFE,
+   QUERY_DESC_GEOMETRY_MAZ_SIZE= 0x44,
+   QUERY_DESC_POWER_MAX_SIZE   = 0x62,
+   QUERY_DESC_RFU_MAX_SIZE = 0x00,
 };
 
-#define UNIT_DESC_MAX_SIZE   0x22
 /* Unit descriptor parameters offsets in bytes*/
 enum unit_desc_param {
UNIT_DESC_PARAM_LEN = 0x0,
diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index b033702..57a8dbb 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -78,6 +78,19 @@
_ret;   \
})
 
+static u32 ufs_query_desc_max_size[] = {
+   QUERY_DESC_DEVICE_MAX_SIZE,
+   QUERY_DESC_CONFIGURAION_MAX_SIZE,
+   QUERY_DESC_UNIT_MAX_SIZE,
+   QUERY_DESC_RFU_MAX_SIZE,
+   QUERY_DESC_INTERCONNECT_MAX_SIZE,
+   QUERY_DESC_STRING_MAX_SIZE,
+   QUERY_DESC_RFU_MAX_SIZE,
+   QUERY_DESC_GEOMETRY_MAZ_SIZE,
+   QUERY_DESC_POWER_MAX_SIZE,
+   QUERY_DESC_RFU_MAX_SIZE,
+};
+
 enum {
UFSHCD_MAX_CHANNEL  = 0,
UFSHCD_MAX_ID   = 1,
@@ -124,8 +137,6 @@ static void ufshcd_tmc_handler(struct ufs_hba *hba);
 static void ufshcd_async_scan(void *data, async_cookie_t cookie);
 static int ufshcd_reset_and_restore(struct ufs_hba *hba);
 static int ufshcd_clear_tm_cmd(struct ufs_hba *hba, int tag);
-static int ufshcd_read_sdev_qdepth(struct ufs_hba *hba,
-   struct scsi_device *sdev);
 
 /*
  * ufshcd_wait_for_register - wait for register value to change
@@ -1393,6 +1404,115 @@ out:
 }
 
 /**
+ * ufshcd_read_desc_param - read the specified descriptor parameter
+ * @hba: Pointer to adapter instance
+ * @desc_id: descriptor idn value
+ * @desc_index: descriptor index
+ * @param_offset: offset of the parameter to read
+ * @param_read_buf: pointer to buffer where parameter would be read
+ * @param_size: sizeof(param_read_buf)
+ *
+ * Return 0 in case of success, non-zero otherwise
+ */
+static int ufshcd_read_desc_param(struct ufs_hba *hba,
+ enum desc_idn desc_id,
+ int desc_index,
+ u32 param_offset,
+ u8 *param_read_buf,
+ u32 param_size)
+{
+   int ret;
+   u8 *desc_buf;
+   u32 buff_len;
+   bool is_kmalloc = true;
+
+   /* safety checks */
+   if (desc_id = QUERY_DESC_IDN_MAX)
+   return -EINVAL;
+
+   buff_len = ufs_query_desc_max_size[desc_id];
+   if ((param_offset + param_size)  buff_len)
+   return -EINVAL;
+
+   if (!param_offset  (param_size == buff_len)) {
+   /* memory space already available to hold full descriptor */
+   desc_buf = param_read_buf;
+   is_kmalloc = false;
+   } else {
+   /* allocate memory to hold full descriptor */
+   desc_buf = kmalloc(buff_len, GFP_KERNEL);
+   if (!desc_buf)
+   return -ENOMEM;
+   }
+
+   ret = ufshcd_query_descriptor(hba, UPIU_QUERY_OPCODE_READ_DESC,
+ desc_id, desc_index, 0, desc_buf,
+ buff_len);
+
+   if (ret || (buff_len  ufs_query_desc_max_size[desc_id]) ||
+   (desc_buf[QUERY_DESC_LENGTH_OFFSET] !=
+ufs_query_desc_max_size[desc_id

[PATCH V3 04/16] scsi: ufs: Add regulator enable support

2014-09-10 Thread Dolev Raviv
From: Sujit Reddy Thumma sthu...@codeaurora.org

UFS devices are powered by at most three external power supplies -
- VCC - The flash memory core power supply, 2.7V to 3.6V or 1.70V to 1.95V
- VCCQ - The controller and I/O power supply, 1.1V to 1.3V
- VCCQ2 - Secondary controller and/or I/O power supply, 1.65V to 1.95V

For some devices VCCQ or VCCQ2 are optional as they can be
generated using internal LDO inside the UFS device.

Add DT bindings for voltage regulators that can be controlled
from host driver.

Signed-off-by: Sujit Reddy Thumma sthu...@codeaurora.org
Signed-off-by: Dolev Raviv dra...@codeaurora.org

diff --git a/Documentation/devicetree/bindings/ufs/ufshcd-pltfrm.txt 
b/Documentation/devicetree/bindings/ufs/ufshcd-pltfrm.txt
index 20468b2..65e3117 100644
--- a/Documentation/devicetree/bindings/ufs/ufshcd-pltfrm.txt
+++ b/Documentation/devicetree/bindings/ufs/ufshcd-pltfrm.txt
@@ -8,9 +8,33 @@ Required properties:
 - interrupts: interrupt mapping for UFS host controller IRQ
 - reg   : registers mapping
 
+Optional properties:
+- vcc-supply: phandle to VCC supply regulator node
+- vccq-supply   : phandle to VCCQ supply regulator node
+- vccq2-supply  : phandle to VCCQ2 supply regulator node
+- vcc-supply-1p8: For embedded UFS devices, valid VCC range is 
1.7-1.95V
+  or 2.7-3.6V. This boolean property when set, 
specifies
+ to use low voltage range of 1.7-1.95V. Note for 
external
+ UFS cards this property is invalid and valid VCC 
range is
+ always 2.7-3.6V.
+- vcc-max-microamp  : specifies max. load that can be drawn from vcc supply
+- vccq-max-microamp : specifies max. load that can be drawn from vccq 
supply
+- vccq2-max-microamp: specifies max. load that can be drawn from vccq2 
supply
+
+Note: If above properties are not defined it can be assumed that the supply
+regulators are always on.
+
 Example:
ufshc@0xfc598000 {
compatible = jedec,ufs-1.1;
reg = 0xfc598000 0x800;
interrupts = 0 28 0;
+
+   vcc-supply = xxx_reg1;
+   vcc-supply-1p8;
+   vccq-supply = xxx_reg2;
+   vccq2-supply = xxx_reg3;
+   vcc-max-microamp = 50;
+   vccq-max-microamp = 20;
+   vccq2-max-microamp = 20;
};
diff --git a/drivers/scsi/ufs/ufs.h b/drivers/scsi/ufs/ufs.h
index fafcf5e..729ce7d 100644
--- a/drivers/scsi/ufs/ufs.h
+++ b/drivers/scsi/ufs/ufs.h
@@ -362,4 +362,29 @@ struct ufs_query_res {
struct utp_upiu_query upiu_res;
 };
 
+#define UFS_VREG_VCC_MIN_UV   270 /* uV */
+#define UFS_VREG_VCC_MAX_UV   360 /* uV */
+#define UFS_VREG_VCC_1P8_MIN_UV170 /* uV */
+#define UFS_VREG_VCC_1P8_MAX_UV195 /* uV */
+#define UFS_VREG_VCCQ_MIN_UV  110 /* uV */
+#define UFS_VREG_VCCQ_MAX_UV  130 /* uV */
+#define UFS_VREG_VCCQ2_MIN_UV 165 /* uV */
+#define UFS_VREG_VCCQ2_MAX_UV 195 /* uV */
+
+struct ufs_vreg {
+   struct regulator *reg;
+   const char *name;
+   bool enabled;
+   int min_uV;
+   int max_uV;
+   int min_uA;
+   int max_uA;
+};
+
+struct ufs_vreg_info {
+   struct ufs_vreg *vcc;
+   struct ufs_vreg *vccq;
+   struct ufs_vreg *vccq2;
+};
+
 #endif /* End of Header */
diff --git a/drivers/scsi/ufs/ufshcd-pltfrm.c b/drivers/scsi/ufs/ufshcd-pltfrm.c
index d727b1a..51e47c4 100644
--- a/drivers/scsi/ufs/ufshcd-pltfrm.c
+++ b/drivers/scsi/ufs/ufshcd-pltfrm.c
@@ -53,6 +53,99 @@ static struct ufs_hba_variant_ops *get_variant_ops(struct 
device *dev)
return NULL;
 }
 
+#define MAX_PROP_SIZE 32
+static int ufshcd_populate_vreg(struct device *dev, const char *name,
+   struct ufs_vreg **out_vreg)
+{
+   int ret = 0;
+   char prop_name[MAX_PROP_SIZE];
+   struct ufs_vreg *vreg = NULL;
+   struct device_node *np = dev-of_node;
+
+   if (!np) {
+   dev_err(dev, %s: non DT initialization\n, __func__);
+   goto out;
+   }
+
+   snprintf(prop_name, MAX_PROP_SIZE, %s-supply, name);
+   if (!of_parse_phandle(np, prop_name, 0)) {
+   dev_info(dev, %s: Unable to find %s regulator, assuming 
enabled\n,
+   __func__, prop_name);
+   goto out;
+   }
+
+   vreg = devm_kzalloc(dev, sizeof(*vreg), GFP_KERNEL);
+   if (!vreg) {
+   dev_err(dev, No memory for %s regulator\n, name);
+   goto out;
+   }
+
+   vreg-name = kstrdup(name, GFP_KERNEL);
+
+   snprintf(prop_name, MAX_PROP_SIZE, %s-max-microamp, name);
+   ret = of_property_read_u32(np, prop_name, vreg-max_uA);
+   if (ret) {
+   dev_err(dev, %s: unable to find %s err %d\n,
+   __func__, prop_name, ret);
+   goto out_free

[PATCH V3 16/16] scsi: ufs: definitions for phy interface

2014-09-10 Thread Dolev Raviv
- Adding some of the definitions missing in unipro.h, including power
  enumeration.
- Read Modify Write Line helper function
- Indication for the type of suspend

Signed-off-by: Dolev Raviv dra...@codeaurora.org
Signed-off-by: Subhash Jadavani subha...@codeaurora.org
Signed-off-by: Yaniv Gardi yga...@codeaurora.org

diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index 33984cc..8b7c332 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -4947,6 +4947,8 @@ int ufshcd_system_suspend(struct ufs_hba *hba)
 
ret = ufshcd_suspend(hba, UFS_SYSTEM_PM);
 out:
+   if (!ret)
+   hba-is_sys_suspended = true;
return ret;
 }
 EXPORT_SYMBOL(ufshcd_system_suspend);
diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h
index b94b835..d502d70 100644
--- a/drivers/scsi/ufs/ufshcd.h
+++ b/drivers/scsi/ufs/ufshcd.h
@@ -471,6 +471,7 @@ struct ufs_hba {
 
struct devfreq *devfreq;
struct ufs_clk_scaling clk_scaling;
+   bool is_sys_suspended;
 };
 
 /* Returns true if clocks can be gated. Otherwise false */
@@ -496,6 +497,23 @@ static inline bool 
ufshcd_can_autobkops_during_suspend(struct ufs_hba *hba)
 #define ufshcd_readl(hba, reg) \
readl((hba)-mmio_base + (reg))
 
+/**
+ * ufshcd_rmwl - read modify write into a register
+ * @hba - per adapter instance
+ * @mask - mask to apply on read value
+ * @val - actual value to write
+ * @reg - register address
+ */
+static inline void ufshcd_rmwl(struct ufs_hba *hba, u32 mask, u32 val, u32 reg)
+{
+   u32 tmp;
+
+   tmp = ufshcd_readl(hba, reg);
+   tmp = ~mask;
+   tmp |= (val  mask);
+   ufshcd_writel(hba, tmp, reg);
+}
+
 int ufshcd_alloc_host(struct device *, struct ufs_hba **);
 int ufshcd_init(struct ufs_hba * , void __iomem * , unsigned int);
 void ufshcd_remove(struct ufs_hba *);
diff --git a/drivers/scsi/ufs/unipro.h b/drivers/scsi/ufs/unipro.h
index 0bb8041..3fc3e21 100644
--- a/drivers/scsi/ufs/unipro.h
+++ b/drivers/scsi/ufs/unipro.h
@@ -13,6 +13,44 @@
 #define _UNIPRO_H_
 
 /*
+ * M-TX Configuration Attributes
+ */
+#define TX_MODE0x0021
+#define TX_HSRATE_SERIES   0x0022
+#define TX_HSGEAR  0x0023
+#define TX_PWMGEAR 0x0024
+#define TX_AMPLITUDE   0x0025
+#define TX_HS_SLEWRATE 0x0026
+#define TX_SYNC_SOURCE 0x0027
+#define TX_HS_SYNC_LENGTH  0x0028
+#define TX_HS_PREPARE_LENGTH   0x0029
+#define TX_LS_PREPARE_LENGTH   0x002A
+#define TX_HIBERN8_CONTROL 0x002B
+#define TX_LCC_ENABLE  0x002C
+#define TX_PWM_BURST_CLOSURE_EXTENSION 0x002D
+#define TX_BYPASS_8B10B_ENABLE 0x002E
+#define TX_DRIVER_POLARITY 0x002F
+#define TX_HS_UNTERMINATED_LINE_DRIVE_ENABLE   0x0030
+#define TX_LS_TERMINATED_LINE_DRIVE_ENABLE 0x0031
+#define TX_LCC_SEQUENCER   0x0032
+#define TX_MIN_ACTIVATETIME0x0033
+#define TX_PWM_G6_G7_SYNC_LENGTH   0x0034
+
+/*
+ * M-RX Configuration Attributes
+ */
+#define RX_MODE0x00A1
+#define RX_HSRATE_SERIES   0x00A2
+#define RX_HSGEAR  0x00A3
+#define RX_PWMGEAR 0x00A4
+#define RX_LS_TERMINATED_ENABLE0x00A5
+#define RX_HS_UNTERMINATED_ENABLE  0x00A6
+#define RX_ENTER_HIBERN8   0x00A7
+#define RX_BYPASS_8B10B_ENABLE 0x00A8
+#define RX_TERMINATION_FORCE_ENABLE0x0089
+
+#define is_mphy_tx_attr(attr)  (attr  RX_MODE)
+/*
  * PHY Adpater attributes
  */
 #define PA_ACTIVETXDATALANES   0x1560
@@ -87,6 +125,24 @@ enum {
PA_HS_MODE_B= 2,
 };
 
+enum ufs_pwm_gear_tag {
+   UFS_PWM_DONT_CHANGE,/* Don't change Gear */
+   UFS_PWM_G1, /* PWM Gear 1 (default for reset) */
+   UFS_PWM_G2, /* PWM Gear 2 */
+   UFS_PWM_G3, /* PWM Gear 3 */
+   UFS_PWM_G4, /* PWM Gear 4 */
+   UFS_PWM_G5, /* PWM Gear 5 */
+   UFS_PWM_G6, /* PWM Gear 6 */
+   UFS_PWM_G7, /* PWM Gear 7 */
+};
+
+enum ufs_hs_gear_tag {
+   UFS_HS_DONT_CHANGE, /* Don't change Gear */
+   UFS_HS_G1,  /* HS Gear 1 (default for reset) */
+   UFS_HS_G2,  /* HS Gear 2 */
+   UFS_HS_G3,  /* HS Gear 3 */
+};
+
 /*
  * Data Link Layer Attributes
  */
-- 
1.8.5.2
-- 
QUALCOMM ISRAEL, on behalf of Qualcomm Innovation Center, Inc. is a member
of Code Aurora Forum, hosted by The Linux Foundation

--
To unsubscribe from this list: send the line unsubscribe linux-scsi in
the body of a message to majord...@vger.kernel.org

[PATCH V3 14/16] scsi: ufs: Add support for clock scaling using devfreq framework

2014-09-10 Thread Dolev Raviv
From: Sahitya Tummala stumm...@codeaurora.org

The clocks for UFS device will be managed by generic DVFS (Dynamic
Voltage and Frequency Scaling) framework within kernel. This devfreq
framework works with different governors to scale the clocks. By default,
UFS devices uses simple_ondemand governor which scales the clocks up if
the load is more than upthreshold and scales down if the load is less than
downthreshold.

Signed-off-by: Sahitya Tummala stumm...@codeaurora.org
Signed-off-by: Dolev Raviv dra...@codeaurora.org

diff --git a/drivers/scsi/ufs/Kconfig b/drivers/scsi/ufs/Kconfig
index f07f901..6e07b2a 100644
--- a/drivers/scsi/ufs/Kconfig
+++ b/drivers/scsi/ufs/Kconfig
@@ -35,6 +35,8 @@
 config SCSI_UFSHCD
tristate Universal Flash Storage Controller Driver Core
depends on SCSI  SCSI_DMA
+   select PM_DEVFREQ
+   select DEVFREQ_GOV_SIMPLE_ONDEMAND
---help---
This selects the support for UFS devices in Linux, say Y and make
  sure that you know the name of your UFS host adapter (the card
diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index c762a6a..0bbb933 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -38,6 +38,7 @@
  */
 
 #include linux/async.h
+#include linux/devfreq.h
 
 #include ufshcd.h
 #include unipro.h
@@ -536,6 +537,8 @@ static void ufshcd_ungate_work(struct work_struct *work)
hba-clk_gating.is_suspended = false;
}
 unblock_reqs:
+   if (ufshcd_is_clkscaling_enabled(hba))
+   devfreq_resume_device(hba-devfreq);
scsi_unblock_requests(hba-host);
 }
 
@@ -552,10 +555,10 @@ int ufshcd_hold(struct ufs_hba *hba, bool async)
 
if (!ufshcd_is_clkgating_allowed(hba))
goto out;
-start:
spin_lock_irqsave(hba-host-host_lock, flags);
hba-clk_gating.active_reqs++;
 
+start:
switch (hba-clk_gating.state) {
case CLKS_ON:
break;
@@ -586,6 +589,7 @@ start:
spin_unlock_irqrestore(hba-host-host_lock, flags);
flush_work(hba-clk_gating.ungate_work);
/* Make sure state is CLKS_ON before returning */
+   spin_lock_irqsave(hba-host-host_lock, flags);
goto start;
}
default:
@@ -627,6 +631,11 @@ static void ufshcd_gate_work(struct work_struct *work)
ufshcd_set_link_hibern8(hba);
}
 
+   if (ufshcd_is_clkscaling_enabled(hba)) {
+   devfreq_suspend_device(hba-devfreq);
+   hba-clk_scaling.window_start_t = 0;
+   }
+
if (!ufshcd_is_link_active(hba))
ufshcd_setup_clocks(hba, false);
else
@@ -728,6 +737,32 @@ static void ufshcd_exit_clk_gating(struct ufs_hba *hba)
device_remove_file(hba-dev, hba-clk_gating.delay_attr);
 }
 
+/* Must be called with host lock acquired */
+static void ufshcd_clk_scaling_start_busy(struct ufs_hba *hba)
+{
+   if (!ufshcd_is_clkscaling_enabled(hba))
+   return;
+
+   if (!hba-clk_scaling.is_busy_started) {
+   hba-clk_scaling.busy_start_t = ktime_get();
+   hba-clk_scaling.is_busy_started = true;
+   }
+}
+
+static void ufshcd_clk_scaling_update_busy(struct ufs_hba *hba)
+{
+   struct ufs_clk_scaling *scaling = hba-clk_scaling;
+
+   if (!ufshcd_is_clkscaling_enabled(hba))
+   return;
+
+   if (!hba-outstanding_reqs  scaling-is_busy_started) {
+   scaling-tot_busy_t += ktime_to_us(ktime_sub(ktime_get(),
+   scaling-busy_start_t));
+   scaling-busy_start_t = ktime_set(0, 0);
+   scaling-is_busy_started = false;
+   }
+}
 /**
  * ufshcd_send_command - Send SCSI or device management commands
  * @hba: per adapter instance
@@ -736,6 +771,7 @@ static void ufshcd_exit_clk_gating(struct ufs_hba *hba)
 static inline
 void ufshcd_send_command(struct ufs_hba *hba, unsigned int task_tag)
 {
+   ufshcd_clk_scaling_start_busy(hba);
__set_bit(task_tag, hba-outstanding_reqs);
ufshcd_writel(hba, 1  task_tag, REG_UTP_TRANSFER_REQ_DOOR_BELL);
 }
@@ -2992,6 +3028,8 @@ static void ufshcd_transfer_req_compl(struct ufs_hba *hba)
/* clear corresponding bits of completed commands */
hba-outstanding_reqs ^= completed_reqs;
 
+   ufshcd_clk_scaling_update_busy(hba);
+
/* we might have free'd some tags above */
wake_up(hba-dev_cmd.tag_wq);
 }
@@ -4024,6 +4062,10 @@ static int ufshcd_probe_hba(struct ufs_hba *hba)
if (!hba-is_init_prefetch)
hba-is_init_prefetch = true;
 
+   /* Resume devfreq after UFS device is detected */
+   if (ufshcd_is_clkscaling_enabled(hba))
+   devfreq_resume_device(hba-devfreq);
+
 out:
/*
 * If we failed to initialize the device or the device is not
@@ -4325,6 +4367,7 @@ static int

[PATCH V3 05/16] scsi: ufs: Add clock initialization support

2014-09-10 Thread Dolev Raviv
From: Sujit Reddy Thumma sthu...@codeaurora.org

Add generic clock initialization support for UFSHCD platform
driver. The clock info is read from device tree using standard
clock bindings. A generic max-clock-frequency-hz property is
defined to save information on maximum operating clock frequency
the h/w supports.

Signed-off-by: Sujit Reddy Thumma sthu...@codeaurora.org
Signed-off-by: Dolev Raviv dra...@codeaurora.org

diff --git a/Documentation/devicetree/bindings/ufs/ufshcd-pltfrm.txt 
b/Documentation/devicetree/bindings/ufs/ufshcd-pltfrm.txt
index 65e3117..b0f791a 100644
--- a/Documentation/devicetree/bindings/ufs/ufshcd-pltfrm.txt
+++ b/Documentation/devicetree/bindings/ufs/ufshcd-pltfrm.txt
@@ -21,8 +21,17 @@ Optional properties:
 - vccq-max-microamp : specifies max. load that can be drawn from vccq 
supply
 - vccq2-max-microamp: specifies max. load that can be drawn from vccq2 
supply
 
+- clocks: List of phandle and clock specifier pairs
+- clock-names   : List of clock input name strings sorted in the same
+  order as the clocks property.
+- max-clock-frequency-hz : List of maximum operating frequency stored in the 
same
+   order as the clocks property. If this property is 
not
+  defined or a value in the array is 0 then it is 
assumed
+  that the frequency is set by the parent clock or a
+  fixed rate clock source.
+
 Note: If above properties are not defined it can be assumed that the supply
-regulators are always on.
+regulators or clocks are always on.
 
 Example:
ufshc@0xfc598000 {
@@ -37,4 +46,8 @@ Example:
vcc-max-microamp = 50;
vccq-max-microamp = 20;
vccq2-max-microamp = 20;
+
+   clocks = core 0, ref 0, iface 0;
+   clock-names = core_clk, ref_clk, iface_clk;
+   max-clock-frequency-hz = 1 1920 0;
};
diff --git a/drivers/scsi/ufs/ufshcd-pci.c b/drivers/scsi/ufs/ufshcd-pci.c
index 7a6edbc..2a26faa 100644
--- a/drivers/scsi/ufs/ufshcd-pci.c
+++ b/drivers/scsi/ufs/ufshcd-pci.c
@@ -170,6 +170,8 @@ ufshcd_pci_probe(struct pci_dev *pdev, const struct 
pci_device_id *id)
return err;
}
 
+   INIT_LIST_HEAD(hba-clk_list_head);
+
err = ufshcd_init(hba, mmio_base, pdev-irq);
if (err) {
dev_err(pdev-dev, Initialization failed\n);
diff --git a/drivers/scsi/ufs/ufshcd-pltfrm.c b/drivers/scsi/ufs/ufshcd-pltfrm.c
index 51e47c4..642d80f 100644
--- a/drivers/scsi/ufs/ufshcd-pltfrm.c
+++ b/drivers/scsi/ufs/ufshcd-pltfrm.c
@@ -53,6 +53,71 @@ static struct ufs_hba_variant_ops *get_variant_ops(struct 
device *dev)
return NULL;
 }
 
+static int ufshcd_parse_clock_info(struct ufs_hba *hba)
+{
+   int ret = 0;
+   int cnt;
+   int i;
+   struct device *dev = hba-dev;
+   struct device_node *np = dev-of_node;
+   char *name;
+   u32 *clkfreq = NULL;
+   struct ufs_clk_info *clki;
+
+   if (!np)
+   goto out;
+
+   INIT_LIST_HEAD(hba-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,
+   __func__);
+   } else if (cnt  0) {
+   dev_err(dev, %s: count clock strings failed, err %d\n,
+   __func__, cnt);
+   ret = cnt;
+   }
+
+   if (cnt = 0)
+   goto out;
+
+   clkfreq = kzalloc(cnt * sizeof(*clkfreq), GFP_KERNEL);
+   if (!clkfreq) {
+   ret = -ENOMEM;
+   dev_err(dev, %s: memory alloc failed\n, __func__);
+   goto out;
+   }
+
+   ret = of_property_read_u32_array(np,
+   max-clock-frequency-hz, clkfreq, cnt);
+   if (ret  (ret != -EINVAL)) {
+   dev_err(dev, %s: invalid max-clock-frequency-hz property, 
%d\n,
+   __func__, ret);
+   goto out;
+   }
+
+   for (i = 0; i  cnt; i++) {
+   ret = of_property_read_string_index(np,
+   clock-names, i, (const char **)name);
+   if (ret)
+   goto out;
+
+   clki = devm_kzalloc(dev, sizeof(*clki), GFP_KERNEL);
+   if (!clki) {
+   ret = -ENOMEM;
+   goto out;
+   }
+
+   clki-max_freq = clkfreq[i];
+   clki-name = kstrdup(name, GFP_KERNEL);
+   list_add_tail(clki-list, hba-clk_list_head);
+   }
+out:
+   kfree(clkfreq);
+   return ret;
+}
+
 #define MAX_PROP_SIZE 32
 static int ufshcd_populate_vreg(struct device *dev, const char *name,
struct ufs_vreg **out_vreg)
@@ -266,6 +331,12 @@ static int

[PATCH V3 12/16] scsi: ufs: Add support for clock gating

2014-09-10 Thread Dolev Raviv
From: Sahitya Tummala stumm...@codeaurora.org

The UFS controller clocks can be gated after certain period of
inactivity, which is typically less than runtime suspend timeout.
In addition to clocks the link will also be put into Hibern8 mode
to save more power.

The clock gating can be turned on by enabling the capability
UFSHCD_CAP_CLK_GATING. To enable entering into Hibern8 mode as part of
clock gating, set the capability UFSHCD_CAP_HIBERN8_WITH_CLK_GATING.

The tracing events for clock gating can be enabled through debugfs as:
echo 1  /sys/kernel/debug/tracing/events/ufs/ufshcd_clk_gating/enable
cat /sys/kernel/debug/tracing/trace_pipe

Signed-off-by: Sahitya Tummala stumm...@codeaurora.org
Signed-off-by: Dolev Raviv dra...@codeaurora.org

diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index bfa9a75..c762a6a 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -177,6 +177,11 @@ static int ufshcd_reset_and_restore(struct ufs_hba *hba);
 static int ufshcd_clear_tm_cmd(struct ufs_hba *hba, int tag);
 static void ufshcd_hba_exit(struct ufs_hba *hba);
 static int ufshcd_probe_hba(struct ufs_hba *hba);
+static int __ufshcd_setup_clocks(struct ufs_hba *hba, bool on,
+bool skip_ref_clk);
+static int ufshcd_setup_clocks(struct ufs_hba *hba, bool on);
+static int ufshcd_uic_hibern8_exit(struct ufs_hba *hba);
+static int ufshcd_uic_hibern8_enter(struct ufs_hba *hba);
 static int ufshcd_host_reset_and_restore(struct ufs_hba *hba);
 static int ufshcd_config_pwr_mode(struct ufs_hba *hba,
struct ufs_pa_layer_attr *desired_pwr_mode);
@@ -498,6 +503,231 @@ static inline int ufshcd_is_hba_active(struct ufs_hba 
*hba)
return (ufshcd_readl(hba, REG_CONTROLLER_ENABLE)  0x1) ? 0 : 1;
 }
 
+static void ufshcd_ungate_work(struct work_struct *work)
+{
+   int ret;
+   unsigned long flags;
+   struct ufs_hba *hba = container_of(work, struct ufs_hba,
+   clk_gating.ungate_work);
+
+   cancel_delayed_work_sync(hba-clk_gating.gate_work);
+
+   spin_lock_irqsave(hba-host-host_lock, flags);
+   if (hba-clk_gating.state == CLKS_ON) {
+   spin_unlock_irqrestore(hba-host-host_lock, flags);
+   goto unblock_reqs;
+   }
+
+   spin_unlock_irqrestore(hba-host-host_lock, flags);
+   ufshcd_setup_clocks(hba, true);
+
+   /* Exit from hibern8 */
+   if (ufshcd_can_hibern8_during_gating(hba)) {
+   /* Prevent gating in this path */
+   hba-clk_gating.is_suspended = true;
+   if (ufshcd_is_link_hibern8(hba)) {
+   ret = ufshcd_uic_hibern8_exit(hba);
+   if (ret)
+   dev_err(hba-dev, %s: hibern8 exit failed 
%d\n,
+   __func__, ret);
+   else
+   ufshcd_set_link_active(hba);
+   }
+   hba-clk_gating.is_suspended = false;
+   }
+unblock_reqs:
+   scsi_unblock_requests(hba-host);
+}
+
+/**
+ * ufshcd_hold - Enable clocks that were gated earlier due to ufshcd_release.
+ * Also, exit from hibern8 mode and set the link as active.
+ * @hba: per adapter instance
+ * @async: This indicates whether caller should ungate clocks asynchronously.
+ */
+int ufshcd_hold(struct ufs_hba *hba, bool async)
+{
+   int rc = 0;
+   unsigned long flags;
+
+   if (!ufshcd_is_clkgating_allowed(hba))
+   goto out;
+start:
+   spin_lock_irqsave(hba-host-host_lock, flags);
+   hba-clk_gating.active_reqs++;
+
+   switch (hba-clk_gating.state) {
+   case CLKS_ON:
+   break;
+   case REQ_CLKS_OFF:
+   if (cancel_delayed_work(hba-clk_gating.gate_work)) {
+   hba-clk_gating.state = CLKS_ON;
+   break;
+   }
+   /*
+* If we here, it means gating work is either done or
+* currently running. Hence, fall through to cancel gating
+* work and to enable clocks.
+*/
+   case CLKS_OFF:
+   scsi_block_requests(hba-host);
+   hba-clk_gating.state = REQ_CLKS_ON;
+   schedule_work(hba-clk_gating.ungate_work);
+   /*
+* fall through to check if we should wait for this
+* work to be done or not.
+*/
+   case REQ_CLKS_ON:
+   if (async) {
+   rc = -EAGAIN;
+   hba-clk_gating.active_reqs--;
+   break;
+   } else {
+   spin_unlock_irqrestore(hba-host-host_lock, flags);
+   flush_work(hba-clk_gating.ungate_work);
+   /* Make sure state is CLKS_ON before returning */
+   goto start;
+   }
+   default:
+   dev_err(hba

RE: [PATCH/RFC V2 10/16] scsi: ufs: add UFS power management support

2014-09-03 Thread Dolev Raviv
Hi all,
Thanks for reviewing the patches, I'm sorry for the late replay. I was
waiting for some comments before I address all at once and re-send the
series.


 +static int ufshcd_config_vreg_load(struct device *dev, struct ufs_vreg
 *vreg,
 +   int ua)
 +{
 +int ret = 0;
 +struct regulator *reg = vreg-reg;
 +const char *name = vreg-name;
 +
 +BUG_ON(!vreg);

 For the UFS host controller driver, which doesn't have the ufs_vreg
 structure for vcc and vccq, this function can cause kernel panic due to
 this BUG_ON(). Any reason to put a BUG_ON here instead of a NULL pointer
 checking?

 Thanks
 Chuanxiao


Sure, I'll fix this.

Thanks,
Dolev

 --
 To unsubscribe from this list: send the line unsubscribe linux-scsi in
 the body of a message to majord...@vger.kernel.org
 More majordomo info at  http://vger.kernel.org/majordomo-info.html



-- 
QUALCOMM ISRAEL, on behalf of Qualcomm Innovation Center, Inc. is a member
of Code Aurora Forum, hosted by The Linux Foundation


--
To unsubscribe from this list: send the line unsubscribe linux-scsi in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


RE: [PATCH/RFC V2 10/16] scsi: ufs: add UFS power management support

2014-09-03 Thread Dolev Raviv
Hi all,
Thanks for reviewing the patches, I'm sorry for the late replay. I was
waiting for some comments before I address all at once and re-send the
series.

  +/**
  + * ufshcd_resume - helper function for resume operations
  + * @hba: per adapter instance
  + * @pm_op: runtime PM or system PM
  + *
  + * This function basically brings the UFS device, UniPro link and
  +controller
  + * to active state.
  + *
  + * Returns 0 for success and non-zero for failure  */ static int
  +ufshcd_resume(struct ufs_hba *hba, enum ufs_pm_op pm_op)
   {
  -  if (!hba)
  -  return 0;
  +  int ret;
  +  enum uic_link_state old_link_state;
  +
  +  hba-pm_op_in_progress = 1;
  +  old_link_state = hba-uic_link_state;
  +  /* Make sure clocks are enabled before accessing controller */
  +  ret = ufshcd_setup_clocks(hba, true);
  +  if (ret)
  +  goto out;
  +
  +  if (hba-vops  hba-vops-setup_clocks) {
  +  ret = hba-vops-setup_clocks(hba, true);
  +  if (ret)
  +  goto disable_clks;
  +  }
  +
  +  /* enable the host irq as host controller would be active soon */
  +  ufshcd_enable_irq(hba);
  +
  +  ret = ufshcd_vreg_set_hpm(hba);
  +  if (ret)
  +  goto disable_irq_and_vops_clks;
 
 /*
  -   * The device is idle with no requests in the queue,
  -   * allow background operations.
  +   * Call vendor specific resume callback. As these callbacks may
 access
  +   * vendor specific host controller register space call them when the
  +   * host clocks are ON.
  */
  -  return ufshcd_enable_auto_bkops(hba);
  +  if (hba-vops  hba-vops-resume) {
  +  ret = hba-vops-resume(hba, pm_op);
  +  if (ret)
  +  goto disable_vreg;
  +  }
  +
  +  if (ufshcd_is_link_hibern8(hba)) {
  +  ret = ufshcd_uic_hibern8_exit(hba);
  +  if (!ret)
  +  ufshcd_set_link_active(hba);
  +  else
  +  goto vendor_suspend;
  +  } else if (ufshcd_is_link_off(hba)) {
  +  ret = ufshcd_host_reset_and_restore(hba);
  +  /*
  +   * ufshcd_host_reset_and_restore() should have already
  +   * set the link state as active
  +   */
  +  if (ret || !ufshcd_is_link_active(hba))
  +  goto vendor_suspend;
  +  }
  +
  +  if (!ufshcd_is_ufs_dev_active(hba)) {
  +  ret = ufshcd_set_dev_pwr_mode(hba, UFS_ACTIVE_PWR_MODE);
  +  if (ret)
  +  goto set_old_link_state;
  +  }
  +
  +  ufshcd_disable_auto_bkops(hba);

 Should be auto background operation enabled again in ufshcd_resume()? It
 is disabled during ufshcd_suspend().

 Thanks
 Chuanxiao

Chuanxiao,
If the system is going for runtime suspend, the bkops are enabled if
necessary, and in any case disabled before the suspend. On resume we make
sure, bkops are disabled.

Thanks,
Dolev

  --
  To unsubscribe from this list: send the line unsubscribe linux-scsi
 in the body
  of a message to majord...@vger.kernel.org More majordomo info at
  http://vger.kernel.org/majordomo-info.html
 --
 To unsubscribe from this list: send the line unsubscribe linux-scsi in
 the body of a message to majord...@vger.kernel.org
 More majordomo info at  http://vger.kernel.org/majordomo-info.html
 --
 To unsubscribe from this list: send the line unsubscribe linux-scsi in
 the body of a message to majord...@vger.kernel.org
 More majordomo info at  http://vger.kernel.org/majordomo-info.html



-- 
QUALCOMM ISRAEL, on behalf of Qualcomm Innovation Center, Inc. is a member
of Code Aurora Forum, hosted by The Linux Foundation

--
To unsubscribe from this list: send the line unsubscribe linux-scsi in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH/RFC V2 00/16] UFS: Power managment support

2014-08-14 Thread Dolev Raviv
This patch seies introduces support for power managment in the driver as well 
as vendor specific initialization - registers, clocks, voltage regulators etc.

It includes also a rework for the init sequnce and other PM pre-requisit such 
as write protection support, handling well-known LUN, error handling (retries), 
bkops, START_STOP unit command, and ICC levels settings.

--
Changes from V1:
 - 6 new patches apended at the end
 - Allow overriding power configuration with controller support and
   preferences/capabilities Dolev Raviv
 - Allow overriding power choice with controller capabilities Dolev Raviv
 - Add support for clock gating and clock scaling Sahitya Tummala
 - Add capability to control the auto bkops during suspend Subhash Jadavani
 - Add misc changes for phy/unipro driver usage Dolev Raviv

Dolev Raviv (2):
  scsi: ufs: refactor configuring power mode
  scsi: ufs: definitions for phy interface

Sahitya Tummala (3):
  scsi: ufs: Add support for clock gating
  scsi: ufs: Add freq-table-hz property for UFS device
  scsi: ufs: Add support for clock scaling using devfreq framework

Subhash Jadavani (5):
  scsi: ufs: refactor query descriptor API support
  scsi: support well known logical units
  scsi: ufs: introduce well known logical unit in ufs
  scsi: ufs: add UFS power management support
  scsi: ufs: add capability to control the auto bkops during suspend

Sujit Reddy Thumma (5):
  scsi: ufs: Allow vendor specific initialization
  scsi: ufs: Add regulator enable support
  scsi: ufs: Add clock initialization support
  scsi: ufs: improve init sequence
  scsi: sd: Avoid sending medium write commands if device is write
protected

Yaniv Gardi (1):
  scsi: ufs: Active Power Mode - configuring bActiveICCLevel

 .../devicetree/bindings/ufs/ufshcd-pltfrm.txt  |   37 +
 drivers/scsi/scsi_scan.c   |   16 +
 drivers/scsi/scsi_sysfs.c  |7 +
 drivers/scsi/sd.c  |6 +-
 drivers/scsi/ufs/Kconfig   |2 +
 drivers/scsi/ufs/ufs.h |  131 +-
 drivers/scsi/ufs/ufshcd-pci.c  |   55 +-
 drivers/scsi/ufs/ufshcd-pltfrm.c   |  282 ++-
 drivers/scsi/ufs/ufshcd.c  | 2400 ++--
 drivers/scsi/ufs/ufshcd.h  |  277 ++-
 drivers/scsi/ufs/ufshci.h  |9 +-
 drivers/scsi/ufs/unipro.h  |   56 +
 include/scsi/scsi.h|1 +
 include/scsi/scsi_host.h   |5 +
 14 files changed, 2959 insertions(+), 325 deletions(-)

-- 
1.8.5.2

--
To unsubscribe from this list: send the line unsubscribe linux-scsi in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH/RFC V2 01/16] scsi: ufs: Allow vendor specific initialization

2014-08-14 Thread Dolev Raviv
From: Sujit Reddy Thumma sthu...@codeaurora.org

Some vendor specific controller versions might need to configure
vendor specific - registers, clocks, voltage regulators etc. to
initialize the host controller UTP layer and Uni-Pro stack.
Provide some common initialization operations that can be used
to configure vendor specifics. The methods can be extended in
future, for example, for power mode transitions.

The operations are vendor/board specific and hence determined with
the help of compatible property in device tree.

Signed-off-by: Sujit Reddy Thumma sthu...@codeaurora.org
Signed-off-by: Dolev Raviv dra...@codeaurora.org

diff --git a/drivers/scsi/ufs/ufshcd-pci.c b/drivers/scsi/ufs/ufshcd-pci.c
index c007a7a..11a3237 100644
--- a/drivers/scsi/ufs/ufshcd-pci.c
+++ b/drivers/scsi/ufs/ufshcd-pci.c
@@ -164,7 +164,13 @@ ufshcd_pci_probe(struct pci_dev *pdev, const struct 
pci_device_id *id)
 
mmio_base = pcim_iomap_table(pdev)[0];
 
-   err = ufshcd_init(pdev-dev, hba, mmio_base, pdev-irq);
+   err = ufshcd_alloc_host(pdev-dev, hba);
+   if (err) {
+   dev_err(pdev-dev, Allocation failed\n);
+   return err;
+   }
+
+   err = ufshcd_init(hba, mmio_base, pdev-irq);
if (err) {
dev_err(pdev-dev, Initialization failed\n);
return err;
diff --git a/drivers/scsi/ufs/ufshcd-pltfrm.c b/drivers/scsi/ufs/ufshcd-pltfrm.c
index 5e46232..d727b1a 100644
--- a/drivers/scsi/ufs/ufshcd-pltfrm.c
+++ b/drivers/scsi/ufs/ufshcd-pltfrm.c
@@ -35,9 +35,24 @@
 
 #include linux/platform_device.h
 #include linux/pm_runtime.h
+#include linux/of.h
 
 #include ufshcd.h
 
+static const struct of_device_id ufs_of_match[];
+static struct ufs_hba_variant_ops *get_variant_ops(struct device *dev)
+{
+   if (dev-of_node) {
+   const struct of_device_id *match;
+
+   match = of_match_node(ufs_of_match, dev-of_node);
+   if (match)
+   return (struct ufs_hba_variant_ops *)match-data;
+   }
+
+   return NULL;
+}
+
 #ifdef CONFIG_PM
 /**
  * ufshcd_pltfrm_suspend - suspend power management function
@@ -138,8 +153,8 @@ static int ufshcd_pltfrm_probe(struct platform_device *pdev)
 
mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
mmio_base = devm_ioremap_resource(dev, mem_res);
-   if (IS_ERR(mmio_base)) {
-   err = PTR_ERR(mmio_base);
+   if (IS_ERR(*(void **)mmio_base)) {
+   err = PTR_ERR(*(void **)mmio_base);
goto out;
}
 
@@ -150,10 +165,18 @@ static int ufshcd_pltfrm_probe(struct platform_device 
*pdev)
goto out;
}
 
+   err = ufshcd_alloc_host(dev, hba);
+   if (err) {
+   dev_err(pdev-dev, Allocation failed\n);
+   goto out;
+   }
+
+   hba-vops = get_variant_ops(pdev-dev);
+
pm_runtime_set_active(pdev-dev);
pm_runtime_enable(pdev-dev);
 
-   err = ufshcd_init(dev, hba, mmio_base, irq);
+   err = ufshcd_init(hba, mmio_base, irq);
if (err) {
dev_err(dev, Intialization failed\n);
goto out_disable_rpm;
diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index ba27215..d0565b0 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -3,6 +3,7 @@
  *
  * This code is based on drivers/scsi/ufs/ufshcd.c
  * Copyright (C) 2011-2013 Samsung India Software Operations
+ * Copyright (c) 2013-2014, The Linux Foundation. All rights reserved.
  *
  * Authors:
  * Santosh Yaraganavi santosh...@samsung.com
@@ -31,6 +32,9 @@
  * circumstances will the contributor of this Program be liable for
  * any damages of any kind arising from your use or distribution of
  * this program.
+ *
+ * The Linux Foundation chooses to take subject only to the GPLv2
+ * license terms, and distributes only under these terms.
  */
 
 #include linux/async.h
@@ -175,13 +179,14 @@ static inline u32 ufshcd_get_ufs_version(struct ufs_hba 
*hba)
 /**
  * ufshcd_is_device_present - Check if any device connected to
  *   the host controller
- * @reg_hcs - host controller status register value
+ * @hba: pointer to adapter instance
  *
  * Returns 1 if device present, 0 if no device detected
  */
-static inline int ufshcd_is_device_present(u32 reg_hcs)
+static inline int ufshcd_is_device_present(struct ufs_hba *hba)
 {
-   return (DEVICE_PRESENT  reg_hcs) ? 1 : 0;
+   return (ufshcd_readl(hba, REG_CONTROLLER_STATUS) 
+   DEVICE_PRESENT) ? 1 : 0;
 }
 
 /**
@@ -1798,11 +1803,10 @@ out:
  * @hba: per adapter instance
  *
  * To bring UFS host controller to operational state,
- * 1. Check if device is present
- * 2. Enable required interrupts
- * 3. Configure interrupt aggregation
- * 4. Program UTRL and UTMRL base addres
- * 5. Configure run-stop-registers
+ * 1. Enable required interrupts
+ * 2. Configure interrupt

[PATCH/RFC V2 02/16] scsi: ufs: Add regulator enable support

2014-08-14 Thread Dolev Raviv
From: Sujit Reddy Thumma sthu...@codeaurora.org

UFS devices are powered by at most three external power supplies -
- VCC - The flash memory core power supply, 2.7V to 3.6V or 1.70V to 1.95V
- VCCQ - The controller and I/O power supply, 1.1V to 1.3V
- VCCQ2 - Secondary controller and/or I/O power supply, 1.65V to 1.95V

For some devices VCCQ or VCCQ2 are optional as they can be
generated using internal LDO inside the UFS device.

Add DT bindings for voltage regulators that can be controlled
from host driver.

Signed-off-by: Sujit Reddy Thumma sthu...@codeaurora.org
Signed-off-by: Dolev Raviv dra...@codeaurora.org

diff --git a/Documentation/devicetree/bindings/ufs/ufshcd-pltfrm.txt 
b/Documentation/devicetree/bindings/ufs/ufshcd-pltfrm.txt
index 20468b2..65e3117 100644
--- a/Documentation/devicetree/bindings/ufs/ufshcd-pltfrm.txt
+++ b/Documentation/devicetree/bindings/ufs/ufshcd-pltfrm.txt
@@ -8,9 +8,33 @@ Required properties:
 - interrupts: interrupt mapping for UFS host controller IRQ
 - reg   : registers mapping
 
+Optional properties:
+- vcc-supply: phandle to VCC supply regulator node
+- vccq-supply   : phandle to VCCQ supply regulator node
+- vccq2-supply  : phandle to VCCQ2 supply regulator node
+- vcc-supply-1p8: For embedded UFS devices, valid VCC range is 
1.7-1.95V
+  or 2.7-3.6V. This boolean property when set, 
specifies
+ to use low voltage range of 1.7-1.95V. Note for 
external
+ UFS cards this property is invalid and valid VCC 
range is
+ always 2.7-3.6V.
+- vcc-max-microamp  : specifies max. load that can be drawn from vcc supply
+- vccq-max-microamp : specifies max. load that can be drawn from vccq 
supply
+- vccq2-max-microamp: specifies max. load that can be drawn from vccq2 
supply
+
+Note: If above properties are not defined it can be assumed that the supply
+regulators are always on.
+
 Example:
ufshc@0xfc598000 {
compatible = jedec,ufs-1.1;
reg = 0xfc598000 0x800;
interrupts = 0 28 0;
+
+   vcc-supply = xxx_reg1;
+   vcc-supply-1p8;
+   vccq-supply = xxx_reg2;
+   vccq2-supply = xxx_reg3;
+   vcc-max-microamp = 50;
+   vccq-max-microamp = 20;
+   vccq2-max-microamp = 20;
};
diff --git a/drivers/scsi/ufs/ufs.h b/drivers/scsi/ufs/ufs.h
index fafcf5e..729ce7d 100644
--- a/drivers/scsi/ufs/ufs.h
+++ b/drivers/scsi/ufs/ufs.h
@@ -362,4 +362,29 @@ struct ufs_query_res {
struct utp_upiu_query upiu_res;
 };
 
+#define UFS_VREG_VCC_MIN_UV   270 /* uV */
+#define UFS_VREG_VCC_MAX_UV   360 /* uV */
+#define UFS_VREG_VCC_1P8_MIN_UV170 /* uV */
+#define UFS_VREG_VCC_1P8_MAX_UV195 /* uV */
+#define UFS_VREG_VCCQ_MIN_UV  110 /* uV */
+#define UFS_VREG_VCCQ_MAX_UV  130 /* uV */
+#define UFS_VREG_VCCQ2_MIN_UV 165 /* uV */
+#define UFS_VREG_VCCQ2_MAX_UV 195 /* uV */
+
+struct ufs_vreg {
+   struct regulator *reg;
+   const char *name;
+   bool enabled;
+   int min_uV;
+   int max_uV;
+   int min_uA;
+   int max_uA;
+};
+
+struct ufs_vreg_info {
+   struct ufs_vreg *vcc;
+   struct ufs_vreg *vccq;
+   struct ufs_vreg *vccq2;
+};
+
 #endif /* End of Header */
diff --git a/drivers/scsi/ufs/ufshcd-pltfrm.c b/drivers/scsi/ufs/ufshcd-pltfrm.c
index d727b1a..51e47c4 100644
--- a/drivers/scsi/ufs/ufshcd-pltfrm.c
+++ b/drivers/scsi/ufs/ufshcd-pltfrm.c
@@ -53,6 +53,99 @@ static struct ufs_hba_variant_ops *get_variant_ops(struct 
device *dev)
return NULL;
 }
 
+#define MAX_PROP_SIZE 32
+static int ufshcd_populate_vreg(struct device *dev, const char *name,
+   struct ufs_vreg **out_vreg)
+{
+   int ret = 0;
+   char prop_name[MAX_PROP_SIZE];
+   struct ufs_vreg *vreg = NULL;
+   struct device_node *np = dev-of_node;
+
+   if (!np) {
+   dev_err(dev, %s: non DT initialization\n, __func__);
+   goto out;
+   }
+
+   snprintf(prop_name, MAX_PROP_SIZE, %s-supply, name);
+   if (!of_parse_phandle(np, prop_name, 0)) {
+   dev_info(dev, %s: Unable to find %s regulator, assuming 
enabled\n,
+   __func__, prop_name);
+   goto out;
+   }
+
+   vreg = devm_kzalloc(dev, sizeof(*vreg), GFP_KERNEL);
+   if (!vreg) {
+   dev_err(dev, No memory for %s regulator\n, name);
+   goto out;
+   }
+
+   vreg-name = kstrdup(name, GFP_KERNEL);
+
+   snprintf(prop_name, MAX_PROP_SIZE, %s-max-microamp, name);
+   ret = of_property_read_u32(np, prop_name, vreg-max_uA);
+   if (ret) {
+   dev_err(dev, %s: unable to find %s err %d\n,
+   __func__, prop_name, ret);
+   goto out_free

[PATCH/RFC V2 03/16] scsi: ufs: Add clock initialization support

2014-08-14 Thread Dolev Raviv
From: Sujit Reddy Thumma sthu...@codeaurora.org

Add generic clock initialization support for UFSHCD platform
driver. The clock info is read from device tree using standard
clock bindings. A generic max-clock-frequency-hz property is
defined to save information on maximum operating clock frequency
the h/w supports.

Signed-off-by: Sujit Reddy Thumma sthu...@codeaurora.org
Signed-off-by: Dolev Raviv dra...@codeaurora.org

diff --git a/Documentation/devicetree/bindings/ufs/ufshcd-pltfrm.txt 
b/Documentation/devicetree/bindings/ufs/ufshcd-pltfrm.txt
index 65e3117..b0f791a 100644
--- a/Documentation/devicetree/bindings/ufs/ufshcd-pltfrm.txt
+++ b/Documentation/devicetree/bindings/ufs/ufshcd-pltfrm.txt
@@ -21,8 +21,17 @@ Optional properties:
 - vccq-max-microamp : specifies max. load that can be drawn from vccq 
supply
 - vccq2-max-microamp: specifies max. load that can be drawn from vccq2 
supply
 
+- clocks: List of phandle and clock specifier pairs
+- clock-names   : List of clock input name strings sorted in the same
+  order as the clocks property.
+- max-clock-frequency-hz : List of maximum operating frequency stored in the 
same
+   order as the clocks property. If this property is 
not
+  defined or a value in the array is 0 then it is 
assumed
+  that the frequency is set by the parent clock or a
+  fixed rate clock source.
+
 Note: If above properties are not defined it can be assumed that the supply
-regulators are always on.
+regulators or clocks are always on.
 
 Example:
ufshc@0xfc598000 {
@@ -37,4 +46,8 @@ Example:
vcc-max-microamp = 50;
vccq-max-microamp = 20;
vccq2-max-microamp = 20;
+
+   clocks = core 0, ref 0, iface 0;
+   clock-names = core_clk, ref_clk, iface_clk;
+   max-clock-frequency-hz = 1 1920 0;
};
diff --git a/drivers/scsi/ufs/ufshcd-pci.c b/drivers/scsi/ufs/ufshcd-pci.c
index 11a3237..1aac2ef 100644
--- a/drivers/scsi/ufs/ufshcd-pci.c
+++ b/drivers/scsi/ufs/ufshcd-pci.c
@@ -170,6 +170,8 @@ ufshcd_pci_probe(struct pci_dev *pdev, const struct 
pci_device_id *id)
return err;
}
 
+   INIT_LIST_HEAD(hba-clk_list_head);
+
err = ufshcd_init(hba, mmio_base, pdev-irq);
if (err) {
dev_err(pdev-dev, Initialization failed\n);
diff --git a/drivers/scsi/ufs/ufshcd-pltfrm.c b/drivers/scsi/ufs/ufshcd-pltfrm.c
index 51e47c4..642d80f 100644
--- a/drivers/scsi/ufs/ufshcd-pltfrm.c
+++ b/drivers/scsi/ufs/ufshcd-pltfrm.c
@@ -53,6 +53,71 @@ static struct ufs_hba_variant_ops *get_variant_ops(struct 
device *dev)
return NULL;
 }
 
+static int ufshcd_parse_clock_info(struct ufs_hba *hba)
+{
+   int ret = 0;
+   int cnt;
+   int i;
+   struct device *dev = hba-dev;
+   struct device_node *np = dev-of_node;
+   char *name;
+   u32 *clkfreq = NULL;
+   struct ufs_clk_info *clki;
+
+   if (!np)
+   goto out;
+
+   INIT_LIST_HEAD(hba-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,
+   __func__);
+   } else if (cnt  0) {
+   dev_err(dev, %s: count clock strings failed, err %d\n,
+   __func__, cnt);
+   ret = cnt;
+   }
+
+   if (cnt = 0)
+   goto out;
+
+   clkfreq = kzalloc(cnt * sizeof(*clkfreq), GFP_KERNEL);
+   if (!clkfreq) {
+   ret = -ENOMEM;
+   dev_err(dev, %s: memory alloc failed\n, __func__);
+   goto out;
+   }
+
+   ret = of_property_read_u32_array(np,
+   max-clock-frequency-hz, clkfreq, cnt);
+   if (ret  (ret != -EINVAL)) {
+   dev_err(dev, %s: invalid max-clock-frequency-hz property, 
%d\n,
+   __func__, ret);
+   goto out;
+   }
+
+   for (i = 0; i  cnt; i++) {
+   ret = of_property_read_string_index(np,
+   clock-names, i, (const char **)name);
+   if (ret)
+   goto out;
+
+   clki = devm_kzalloc(dev, sizeof(*clki), GFP_KERNEL);
+   if (!clki) {
+   ret = -ENOMEM;
+   goto out;
+   }
+
+   clki-max_freq = clkfreq[i];
+   clki-name = kstrdup(name, GFP_KERNEL);
+   list_add_tail(clki-list, hba-clk_list_head);
+   }
+out:
+   kfree(clkfreq);
+   return ret;
+}
+
 #define MAX_PROP_SIZE 32
 static int ufshcd_populate_vreg(struct device *dev, const char *name,
struct ufs_vreg **out_vreg)
@@ -266,6 +331,12 @@ static int

[PATCH/RFC V2 11/16] scsi: ufs: refactor configuring power mode

2014-08-14 Thread Dolev Raviv
Sometimes, the device shall report its maximum power and speed
capabilities, but we might not wish to configure it to use those
maximum capabilities.
This change adds support for the vendor specific host driver to
implement power change notify callback.

To enable configuring different power modes (number of lanes,
gear number and fast/slow modes) it is necessary to split the
configuration stage from the stage that reads the device max power mode.
In addition, it is not required to read the configuration more than
once, thus the configuration is stored after reading it once.

Signed-off-by: Dolev Raviv dra...@codeaurora.org
Signed-off-by: Yaniv Gardi yga...@codeaurora.org

diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index fac71c9..3a66d0d 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -178,6 +178,8 @@ static int ufshcd_clear_tm_cmd(struct ufs_hba *hba, int 
tag);
 static void ufshcd_hba_exit(struct ufs_hba *hba);
 static int ufshcd_probe_hba(struct ufs_hba *hba);
 static int ufshcd_host_reset_and_restore(struct ufs_hba *hba);
+static int ufshcd_config_pwr_mode(struct ufs_hba *hba,
+   struct ufs_pa_layer_attr *desired_pwr_mode);
 
 static inline void ufshcd_enable_irq(struct ufs_hba *hba)
 {
@@ -1933,65 +1935,129 @@ static int ufshcd_uic_hibern8_exit(struct ufs_hba *hba)
 }
 
 /**
- * ufshcd_config_max_pwr_mode - Set  Change power mode with
- * maximum capability attribute information.
- * @hba: per adapter instance
- *
- * Returns 0 on success, non-zero value on failure
+ * ufshcd_get_max_pwr_mode - reads the max power mode negotiated with device
+ * @hba: per-adapter instance
  */
-static int ufshcd_config_max_pwr_mode(struct ufs_hba *hba)
+static int ufshcd_get_max_pwr_mode(struct ufs_hba *hba)
 {
-   enum {RX = 0, TX = 1};
-   u32 lanes[] = {1, 1};
-   u32 gear[] = {1, 1};
-   u8 pwr[] = {FASTAUTO_MODE, FASTAUTO_MODE};
-   int ret;
+   struct ufs_pa_layer_attr *pwr_info = hba-max_pwr_info.info;
+
+   if (hba-max_pwr_info.is_valid)
+   return 0;
+
+   pwr_info-pwr_tx = FASTAUTO_MODE;
+   pwr_info-pwr_rx = FASTAUTO_MODE;
+   pwr_info-hs_rate = PA_HS_MODE_B;
 
/* Get the connected lane count */
-   ufshcd_dme_get(hba, UIC_ARG_MIB(PA_CONNECTEDRXDATALANES), lanes[RX]);
-   ufshcd_dme_get(hba, UIC_ARG_MIB(PA_CONNECTEDTXDATALANES), lanes[TX]);
+   ufshcd_dme_get(hba, UIC_ARG_MIB(PA_CONNECTEDRXDATALANES),
+   pwr_info-lane_rx);
+   ufshcd_dme_get(hba, UIC_ARG_MIB(PA_CONNECTEDTXDATALANES),
+   pwr_info-lane_tx);
+
+   if (!pwr_info-lane_rx || !pwr_info-lane_tx) {
+   dev_err(hba-dev, %s: invalid connected lanes value. rx=%d, 
tx=%d\n,
+   __func__,
+   pwr_info-lane_rx,
+   pwr_info-lane_tx);
+   return -EINVAL;
+   }
 
/*
 * First, get the maximum gears of HS speed.
 * If a zero value, it means there is no HSGEAR capability.
 * Then, get the maximum gears of PWM speed.
 */
-   ufshcd_dme_get(hba, UIC_ARG_MIB(PA_MAXRXHSGEAR), gear[RX]);
-   if (!gear[RX]) {
-   ufshcd_dme_get(hba, UIC_ARG_MIB(PA_MAXRXPWMGEAR), gear[RX]);
-   pwr[RX] = SLOWAUTO_MODE;
+   ufshcd_dme_get(hba, UIC_ARG_MIB(PA_MAXRXHSGEAR), pwr_info-gear_rx);
+   if (!pwr_info-gear_rx) {
+   ufshcd_dme_get(hba, UIC_ARG_MIB(PA_MAXRXPWMGEAR),
+   pwr_info-gear_rx);
+   if (!pwr_info-gear_rx) {
+   dev_err(hba-dev, %s: invalid max pwm rx gear read = 
%d\n,
+   __func__, pwr_info-gear_rx);
+   return -EINVAL;
+   }
+   pwr_info-pwr_rx = SLOWAUTO_MODE;
}
 
-   ufshcd_dme_peer_get(hba, UIC_ARG_MIB(PA_MAXRXHSGEAR), gear[TX]);
-   if (!gear[TX]) {
+   ufshcd_dme_peer_get(hba, UIC_ARG_MIB(PA_MAXRXHSGEAR),
+   pwr_info-gear_tx);
+   if (!pwr_info-gear_tx) {
ufshcd_dme_peer_get(hba, UIC_ARG_MIB(PA_MAXRXPWMGEAR),
-   gear[TX]);
-   pwr[TX] = SLOWAUTO_MODE;
+   pwr_info-gear_tx);
+   if (!pwr_info-gear_tx) {
+   dev_err(hba-dev, %s: invalid max pwm tx gear read = 
%d\n,
+   __func__, pwr_info-gear_tx);
+   return -EINVAL;
+   }
+   pwr_info-pwr_tx = SLOWAUTO_MODE;
}
 
+   hba-max_pwr_info.is_valid = true;
+   return 0;
+}
+
+/**
+ * ufshcd_config_pwr_mode - configure a new power mode
+ * @hba: per-adapter instance
+ * @desired_pwr_mode: desired power configuration
+ */
+static int ufshcd_config_pwr_mode(struct ufs_hba *hba,
+   struct ufs_pa_layer_attr *desired_pwr_mode)
+{
+   struct

[PATCH/RFC V2 12/16] scsi: ufs: Add support for clock gating

2014-08-14 Thread Dolev Raviv
From: Sahitya Tummala stumm...@codeaurora.org

The UFS controller clocks can be gated after certain period of
inactivity, which is typically less than runtime suspend timeout.
In addition to clocks the link will also be put into Hibern8 mode
to save more power.

The clock gating can be turned on by enabling the capability
UFSHCD_CAP_CLK_GATING. To enable entering into Hibern8 mode as part of
clock gating, set the capability UFSHCD_CAP_HIBERN8_WITH_CLK_GATING.

The tracing events for clock gating can be enabled through debugfs as:
echo 1  /sys/kernel/debug/tracing/events/ufs/ufshcd_clk_gating/enable
cat /sys/kernel/debug/tracing/trace_pipe

Signed-off-by: Sahitya Tummala stumm...@codeaurora.org
Signed-off-by: Dolev Raviv dra...@codeaurora.org

diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index 3a66d0d..1e5219c 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -177,6 +177,11 @@ static int ufshcd_reset_and_restore(struct ufs_hba *hba);
 static int ufshcd_clear_tm_cmd(struct ufs_hba *hba, int tag);
 static void ufshcd_hba_exit(struct ufs_hba *hba);
 static int ufshcd_probe_hba(struct ufs_hba *hba);
+static int __ufshcd_setup_clocks(struct ufs_hba *hba, bool on,
+bool skip_ref_clk);
+static int ufshcd_setup_clocks(struct ufs_hba *hba, bool on);
+static int ufshcd_uic_hibern8_exit(struct ufs_hba *hba);
+static int ufshcd_uic_hibern8_enter(struct ufs_hba *hba);
 static int ufshcd_host_reset_and_restore(struct ufs_hba *hba);
 static int ufshcd_config_pwr_mode(struct ufs_hba *hba,
struct ufs_pa_layer_attr *desired_pwr_mode);
@@ -498,6 +503,231 @@ static inline int ufshcd_is_hba_active(struct ufs_hba 
*hba)
return (ufshcd_readl(hba, REG_CONTROLLER_ENABLE)  0x1) ? 0 : 1;
 }
 
+static void ufshcd_ungate_work(struct work_struct *work)
+{
+   int ret;
+   unsigned long flags;
+   struct ufs_hba *hba = container_of(work, struct ufs_hba,
+   clk_gating.ungate_work);
+
+   cancel_delayed_work_sync(hba-clk_gating.gate_work);
+
+   spin_lock_irqsave(hba-host-host_lock, flags);
+   if (hba-clk_gating.state == CLKS_ON) {
+   spin_unlock_irqrestore(hba-host-host_lock, flags);
+   goto unblock_reqs;
+   }
+
+   spin_unlock_irqrestore(hba-host-host_lock, flags);
+   ufshcd_setup_clocks(hba, true);
+
+   /* Exit from hibern8 */
+   if (ufshcd_can_hibern8_during_gating(hba)) {
+   /* Prevent gating in this path */
+   hba-clk_gating.is_suspended = true;
+   if (ufshcd_is_link_hibern8(hba)) {
+   ret = ufshcd_uic_hibern8_exit(hba);
+   if (ret)
+   dev_err(hba-dev, %s: hibern8 exit failed 
%d\n,
+   __func__, ret);
+   else
+   ufshcd_set_link_active(hba);
+   }
+   hba-clk_gating.is_suspended = false;
+   }
+unblock_reqs:
+   scsi_unblock_requests(hba-host);
+}
+
+/**
+ * ufshcd_hold - Enable clocks that were gated earlier due to ufshcd_release.
+ * Also, exit from hibern8 mode and set the link as active.
+ * @hba: per adapter instance
+ * @async: This indicates whether caller should ungate clocks asynchronously.
+ */
+int ufshcd_hold(struct ufs_hba *hba, bool async)
+{
+   int rc = 0;
+   unsigned long flags;
+
+   if (!ufshcd_is_clkgating_allowed(hba))
+   goto out;
+start:
+   spin_lock_irqsave(hba-host-host_lock, flags);
+   hba-clk_gating.active_reqs++;
+
+   switch (hba-clk_gating.state) {
+   case CLKS_ON:
+   break;
+   case REQ_CLKS_OFF:
+   if (cancel_delayed_work(hba-clk_gating.gate_work)) {
+   hba-clk_gating.state = CLKS_ON;
+   break;
+   }
+   /*
+* If we here, it means gating work is either done or
+* currently running. Hence, fall through to cancel gating
+* work and to enable clocks.
+*/
+   case CLKS_OFF:
+   scsi_block_requests(hba-host);
+   hba-clk_gating.state = REQ_CLKS_ON;
+   schedule_work(hba-clk_gating.ungate_work);
+   /*
+* fall through to check if we should wait for this
+* work to be done or not.
+*/
+   case REQ_CLKS_ON:
+   if (async) {
+   rc = -EAGAIN;
+   hba-clk_gating.active_reqs--;
+   break;
+   } else {
+   spin_unlock_irqrestore(hba-host-host_lock, flags);
+   flush_work(hba-clk_gating.ungate_work);
+   /* Make sure state is CLKS_ON before returning */
+   goto start;
+   }
+   default:
+   dev_err(hba

[PATCH/RFC V2 07/16] scsi: support well known logical units

2014-08-14 Thread Dolev Raviv
From: Subhash Jadavani subha...@codeaurora.org

REPORT LUNS command has SELECT REPORT field which controls what type of
logical units to be reported by device server. According to UFS device
standard, if this field is set to 0, REPORT LUNS would report only report
standard logical units. If it's set to 1 then it would report only well
known logical unit and if it's set to 2 then device would report both
standard and well known logical units.
Some well-known logical units might not have scsi upper-layer drivers. In
such cases, the runtime PM reference count increased during device
enumeration will not be decreased, causing the parent device (host) to
always be on even during idle.

This change allows the SCSI LLD (Low Level Driver) to choose which type
of logical units should be detected.

Signed-off-by: Subhash Jadavani subha...@codeaurora.org
Signed-off-by: Sujit Reddy Thumma sthu...@codeaurora.org
Signed-off-by: Dolev Raviv dra...@codeaurora.org

diff --git a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c
index 4a6e4ba..5a0e164 100644
--- a/drivers/scsi/scsi_scan.c
+++ b/drivers/scsi/scsi_scan.c
@@ -802,6 +802,14 @@ static int scsi_add_lun(struct scsi_device *sdev, unsigned 
char *inq_result,
} else {
sdev-type = (inq_result[0]  0x1f);
sdev-removable = (inq_result[1]  0x80)  7;
+
+   /*
+* some devices may respond with wrong type for
+* well-known logical units. Force well-known type
+* to enumerate them correctly.
+*/
+   if (scsi_is_wlun(sdev-lun)  (sdev-type != TYPE_WLUN))
+   sdev-type = TYPE_WLUN;
}
 
switch (sdev-type) {
@@ -817,6 +825,7 @@ static int scsi_add_lun(struct scsi_device *sdev, unsigned 
char *inq_result,
case TYPE_COMM:
case TYPE_RAID:
case TYPE_OSD:
+   case TYPE_WLUN:
sdev-writeable = 1;
break;
case TYPE_ROM:
@@ -1412,6 +1421,13 @@ static int scsi_report_lun_scan(struct scsi_target 
*starget, int bflags,
 */
memset(scsi_cmd[1], 0, 5);
 
+   if (shost-report_wlus)
+   /*
+* Set SELECT REPORT field to 0x2 which will make device to
+* report well known logical units along with standard LUs.
+*/
+   scsi_cmd[2] = 0x2;
+
/*
 * bytes 6 - 9: length of the command.
 */
diff --git a/drivers/scsi/scsi_sysfs.c b/drivers/scsi/scsi_sysfs.c
index 5f36788..ba9d0f0 100644
--- a/drivers/scsi/scsi_sysfs.c
+++ b/drivers/scsi/scsi_sysfs.c
@@ -1060,6 +1060,13 @@ int scsi_sysfs_add_sdev(struct scsi_device *sdev)
}
}
 
+   /*
+* put runtime pm reference for well-known logical units,
+* drivers are expected to _get_* again during probe.
+*/
+   if (scsi_is_wlun(sdev-lun))
+   scsi_autopm_put_device(sdev);
+
return error;
 }
 
diff --git a/include/scsi/scsi.h b/include/scsi/scsi.h
index 91e2e42..6a9b102 100644
--- a/include/scsi/scsi.h
+++ b/include/scsi/scsi.h
@@ -332,6 +332,7 @@ static inline int scsi_status_is_good(int status)
 #define TYPE_ENCLOSURE  0x0d/* Enclosure Services Device */
 #define TYPE_RBC   0x0e
 #define TYPE_OSD0x11
+#define TYPE_WLUN   0x1e/* well-known logical unit */
 #define TYPE_NO_LUN 0x7f
 
 /* SCSI protocols; these are taken from SPC-3 section 7.5 */
diff --git a/include/scsi/scsi_host.h b/include/scsi/scsi_host.h
index b2bc519..05664c4 100644
--- a/include/scsi/scsi_host.h
+++ b/include/scsi/scsi_host.h
@@ -675,6 +675,11 @@ struct Scsi_Host {
unsigned no_write_same:1;
 
/*
+* Set SELECT REPORT field to allow detection of well known logical
+* units along with standard LUs.
+*/
+   unsigned report_wlus:1;
+   /*
 * Optional work queue to be utilized by the transport
 */
char work_q_name[20];
-- 
1.8.5.2
-- 
QUALCOMM ISRAEL, on behalf of Qualcomm Innovation Center, Inc. is a member
of Code Aurora Forum, hosted by The Linux Foundation

--
To unsubscribe from this list: send the line unsubscribe linux-scsi in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH/RFC V2 08/16] scsi: ufs: introduce well known logical unit in ufs

2014-08-14 Thread Dolev Raviv
From: Subhash Jadavani subha...@codeaurora.org

UFS device may have standard LUs and LUN id could be from 0x00 to 0x7F.
UFS device specification use Peripheral Device Addressing Format
(SCSI SAM-5) for standard LUs.

UFS device may also have the Well Known LUs (also referred as W-LU) which
again could be from 0x00 to 0x7F. For W-LUs, UFS device specification only
allows the Extended Addressing Format (SCSI SAM-5) which means the W-LUNs
would start from 0xC100 onwards.

This means max. LUN number reported from UFS device could be 0xC17F hence
this patch advertise the max_lun as 0xC17F which will allow SCSI mid
layer to detect the W-LUs as well.

But once the W-LUs are detected, UFSHCD driver may get the commands with
SCSI LUN id upto 0xC17F but UPIU LUN id field is only 8-bit wide so it
requires the mapping of SCSI LUN id to UPIU LUN id. This patch also add
support for this mapping.

Signed-off-by: Subhash Jadavani subha...@codeaurora.org
Signed-off-by: Dolev Raviv dra...@codeaurora.org
Signed-off-by: Sujit Reddy Thumma sthu...@codeaurora.org

diff --git a/drivers/scsi/ufs/ufs.h b/drivers/scsi/ufs/ufs.h
index b0e1f62..bcc3a7f 100644
--- a/drivers/scsi/ufs/ufs.h
+++ b/drivers/scsi/ufs/ufs.h
@@ -49,9 +49,28 @@
 #define UPIU_HEADER_DWORD(byte3, byte2, byte1, byte0)\
cpu_to_be32((byte3  24) | (byte2  16) |\
 (byte1  8) | (byte0))
-
+/*
+ * UFS device may have standard LUs and LUN id could be from 0x00 to
+ * 0x7F. Standard LUs use Peripheral Device Addressing Format.
+ * UFS device may also have the Well Known LUs (also referred as W-LU)
+ * which again could be from 0x00 to 0x7F. For W-LUs, device only use
+ * the Extended Addressing Format which means the W-LUNs would be
+ * from 0xc100 (SCSI_W_LUN_BASE) onwards.
+ * This means max. LUN number reported from UFS device could be 0xC17F.
+ */
+#define UFS_UPIU_MAX_UNIT_NUM_ID   0x7F
+#define UFS_MAX_LUNS   (SCSI_W_LUN_BASE + UFS_UPIU_MAX_UNIT_NUM_ID)
+#define UFS_UPIU_WLUN_ID   (1  7)
 #define UFS_UPIU_MAX_GENERAL_LUN   8
 
+/* Well known logical unit id in LUN field of UPIU */
+enum {
+   UFS_UPIU_REPORT_LUNS_WLUN   = 0x81,
+   UFS_UPIU_UFS_DEVICE_WLUN= 0xD0,
+   UFS_UPIU_BOOT_WLUN  = 0xB0,
+   UFS_UPIU_RPMB_WLUN  = 0xC4,
+};
+
 /*
  * UFS Protocol Information Unit related definitions
  */
diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index a851323..876d210 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -100,7 +100,6 @@ static u32 ufs_query_desc_max_size[] = {
 enum {
UFSHCD_MAX_CHANNEL  = 0,
UFSHCD_MAX_ID   = 1,
-   UFSHCD_MAX_LUNS = 8,
UFSHCD_CMD_PER_LUN  = 32,
UFSHCD_CAN_QUEUE= 32,
 };
@@ -902,6 +901,21 @@ static int ufshcd_compose_upiu(struct ufs_hba *hba, struct 
ufshcd_lrb *lrbp)
 }
 
 /**
+ * ufshcd_scsi_to_upiu_lun - maps scsi LUN to UPIU LUN
+ * @scsi_lun: scsi LUN id
+ *
+ * Returns UPIU LUN id
+ */
+static inline u8 ufshcd_scsi_to_upiu_lun(unsigned int scsi_lun)
+{
+   if (scsi_is_wlun(scsi_lun))
+   return (scsi_lun  UFS_UPIU_MAX_UNIT_NUM_ID)
+   | UFS_UPIU_WLUN_ID;
+   else
+   return scsi_lun  UFS_UPIU_MAX_UNIT_NUM_ID;
+}
+
+/**
  * ufshcd_queuecommand - main entry point for SCSI requests
  * @cmd: command from SCSI Midlayer
  * @done: call back function
@@ -959,7 +973,7 @@ static int ufshcd_queuecommand(struct Scsi_Host *host, 
struct scsi_cmnd *cmd)
lrbp-sense_bufflen = SCSI_SENSE_BUFFERSIZE;
lrbp-sense_buffer = cmd-sense_buffer;
lrbp-task_tag = tag;
-   lrbp-lun = cmd-device-lun;
+   lrbp-lun = ufshcd_scsi_to_upiu_lun(cmd-device-lun);
lrbp-intr_cmd = false;
lrbp-command_type = UTP_CMD_TYPE_SCSI;
 
@@ -1513,7 +1527,7 @@ static inline int ufshcd_read_unit_desc_param(struct 
ufs_hba *hba,
 * Unit descriptors are only available for general purpose LUs (LUN id
 * from 0 to 7) and RPMB Well known LU.
 */
-   if (lun = UFS_UPIU_MAX_GENERAL_LUN)
+   if (lun != UFS_UPIU_RPMB_WLUN  (lun = UFS_UPIU_MAX_GENERAL_LUN))
return -EOPNOTSUPP;
 
return ufshcd_read_desc_param(hba, QUERY_DESC_IDN_UNIT, lun,
@@ -2144,6 +2158,44 @@ static int ufshcd_verify_dev_init(struct ufs_hba *hba)
 }
 
 /**
+ * ufshcd_set_queue_depth - set lun queue depth
+ * @sdev: pointer to SCSI device
+ *
+ * Read bLUQueueDepth value and activate scsi tagged command
+ * queueing. For WLUN, queue depth is set to 1. For best-effort
+ * cases (bLUQueueDepth = 0) the queue depth is set to a maximum
+ * value that host can queue.
+ */
+static void ufshcd_set_queue_depth(struct scsi_device *sdev)
+{
+   int ret = 0;
+   u8 lun_qdepth;
+   struct ufs_hba *hba;
+
+   hba = shost_priv(sdev-host);
+
+   lun_qdepth = hba-nutrs;
+   ret = ufshcd_read_unit_desc_param(hba

[PATCH/RFC V2 13/16] scsi: ufs: Add freq-table-hz property for UFS device

2014-08-14 Thread Dolev Raviv
From: Sahitya Tummala stumm...@codeaurora.org

Add freq-table-hz propery for UFS device to keep track of
min max frequencies supported by UFS clocks.

Signed-off-by: Sahitya Tummala stumm...@codeaurora.org
Signed-off-by: Dolev Raviv dra...@codeaurora.org

diff --git a/Documentation/devicetree/bindings/ufs/ufshcd-pltfrm.txt 
b/Documentation/devicetree/bindings/ufs/ufshcd-pltfrm.txt
index b0f791a..e73a619 100644
--- a/Documentation/devicetree/bindings/ufs/ufshcd-pltfrm.txt
+++ b/Documentation/devicetree/bindings/ufs/ufshcd-pltfrm.txt
@@ -24,11 +24,11 @@ Optional properties:
 - clocks: List of phandle and clock specifier pairs
 - clock-names   : List of clock input name strings sorted in the same
   order as the clocks property.
-- max-clock-frequency-hz : List of maximum operating frequency stored in the 
same
-   order as the clocks property. If this property is 
not
-  defined or a value in the array is 0 then it is 
assumed
-  that the frequency is set by the parent clock or a
-  fixed rate clock source.
+- freq-table-hz: Array of min max operating frequencies 
stored in the same
+  order as the clocks property. If this property is not
+ defined or a value in the array is 0 then it is 
assumed
+ that the frequency is set by the parent clock or a
+ fixed rate clock source.
 
 Note: If above properties are not defined it can be assumed that the supply
 regulators or clocks are always on.
@@ -49,5 +49,5 @@ Example:
 
clocks = core 0, ref 0, iface 0;
clock-names = core_clk, ref_clk, iface_clk;
-   max-clock-frequency-hz = 1 1920 0;
+   freq-table-hz = 1 2, 0 0, 0 0;
};
diff --git a/drivers/scsi/ufs/ufshcd-pltfrm.c b/drivers/scsi/ufs/ufshcd-pltfrm.c
index edaccd0..551be95 100644
--- a/drivers/scsi/ufs/ufshcd-pltfrm.c
+++ b/drivers/scsi/ufs/ufshcd-pltfrm.c
@@ -63,6 +63,8 @@ static int ufshcd_parse_clock_info(struct ufs_hba *hba)
char *name;
u32 *clkfreq = NULL;
struct ufs_clk_info *clki;
+   int len = 0;
+   size_t sz = 0;
 
if (!np)
goto out;
@@ -82,39 +84,59 @@ static int ufshcd_parse_clock_info(struct ufs_hba *hba)
if (cnt = 0)
goto out;
 
-   clkfreq = kzalloc(cnt * sizeof(*clkfreq), GFP_KERNEL);
+   if (!of_get_property(np, freq-table-hz, len)) {
+   dev_info(dev, freq-table-hz property not specified\n);
+   goto out;
+   }
+
+   if (len = 0)
+   goto out;
+
+   sz = len / sizeof(*clkfreq);
+   if (sz != 2 * cnt) {
+   dev_err(dev, %s len mismatch\n, freq-table-hz);
+   ret = -EINVAL;
+   goto out;
+   }
+
+   clkfreq = devm_kzalloc(dev, sz * sizeof(*clkfreq),
+   GFP_KERNEL);
if (!clkfreq) {
+   dev_err(dev, %s: no memory\n, freq-table-hz);
ret = -ENOMEM;
-   dev_err(dev, %s: memory alloc failed\n, __func__);
goto out;
}
 
-   ret = of_property_read_u32_array(np,
-   max-clock-frequency-hz, clkfreq, cnt);
+   ret = of_property_read_u32_array(np, freq-table-hz,
+   clkfreq, sz);
if (ret  (ret != -EINVAL)) {
-   dev_err(dev, %s: invalid max-clock-frequency-hz property, 
%d\n,
-   __func__, ret);
-   goto out;
+   dev_err(dev, %s: error reading array %d\n,
+   freq-table-hz, ret);
+   goto free_clkfreq;
}
 
-   for (i = 0; i  cnt; i++) {
+   for (i = 0; i  sz; i += 2) {
ret = of_property_read_string_index(np,
-   clock-names, i, (const char **)name);
+   clock-names, i/2, (const char **)name);
if (ret)
-   goto out;
+   goto free_clkfreq;
 
clki = devm_kzalloc(dev, sizeof(*clki), GFP_KERNEL);
if (!clki) {
ret = -ENOMEM;
-   goto out;
+   goto free_clkfreq;
}
 
-   clki-max_freq = clkfreq[i];
+   clki-min_freq = clkfreq[i];
+   clki-max_freq = clkfreq[i+1];
clki-name = kstrdup(name, GFP_KERNEL);
+   dev_dbg(dev, %s: min %u max %u name %s\n, freq-table-hz,
+   clki-min_freq, clki-max_freq, clki-name);
list_add_tail(clki-list, hba-clk_list_head);
}
-out:
+free_clkfreq:
kfree(clkfreq);
+out:
return ret;
 }
 
diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi

  1   2   3   >