aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSujit Reddy Thumma <sthumma@codeaurora.org>2014-09-25 08:32:26 -0400
committerChristoph Hellwig <hch@lst.de>2014-10-01 07:11:21 -0400
commit1d337ec2f35e69a046dab0cc77e64e68d1cdcd8b (patch)
tree88d672dad6fa282cd02e242d606a3340e42f209f
parentda461cec9a1ff0a074cd1db47598ba36a1686ef4 (diff)
ufs: improve init sequence
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 <sthumma@codeaurora.org> Signed-off-by: Dolev Raviv <draviv@codeaurora.org> Signed-off-by: Christoph Hellwig <hch@lst.de>
-rw-r--r--drivers/scsi/ufs/ufshcd.c101
-rw-r--r--drivers/scsi/ufs/ufshcd.h2
2 files changed, 75 insertions, 28 deletions
diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index 3f2b30db80cc..af29d4c0a416 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -62,6 +62,12 @@
62/* Task management command timeout */ 62/* Task management command timeout */
63#define TM_CMD_TIMEOUT 100 /* msecs */ 63#define TM_CMD_TIMEOUT 100 /* msecs */
64 64
65/* maximum number of link-startup retries */
66#define DME_LINKSTARTUP_RETRIES 3
67
68/* maximum number of reset retries before giving up */
69#define MAX_HOST_RESET_RETRIES 5
70
65/* Expose the flag value from utp_upiu_query.value */ 71/* Expose the flag value from utp_upiu_query.value */
66#define MASK_QUERY_UPIU_FLAG_LOC 0xFF 72#define MASK_QUERY_UPIU_FLAG_LOC 0xFF
67 73
@@ -137,6 +143,8 @@ static void ufshcd_tmc_handler(struct ufs_hba *hba);
137static void ufshcd_async_scan(void *data, async_cookie_t cookie); 143static void ufshcd_async_scan(void *data, async_cookie_t cookie);
138static int ufshcd_reset_and_restore(struct ufs_hba *hba); 144static int ufshcd_reset_and_restore(struct ufs_hba *hba);
139static int ufshcd_clear_tm_cmd(struct ufs_hba *hba, int tag); 145static int ufshcd_clear_tm_cmd(struct ufs_hba *hba, int tag);
146static void ufshcd_hba_exit(struct ufs_hba *hba);
147static int ufshcd_probe_hba(struct ufs_hba *hba);
140 148
141/* 149/*
142 * ufshcd_wait_for_register - wait for register value to change 150 * ufshcd_wait_for_register - wait for register value to change
@@ -2043,6 +2051,9 @@ static int ufshcd_hba_enable(struct ufs_hba *hba)
2043 msleep(5); 2051 msleep(5);
2044 } 2052 }
2045 2053
2054 /* enable UIC related interrupts */
2055 ufshcd_enable_intr(hba, UIC_COMMAND_COMPL);
2056
2046 if (hba->vops && hba->vops->hce_enable_notify) 2057 if (hba->vops && hba->vops->hce_enable_notify)
2047 hba->vops->hce_enable_notify(hba, POST_CHANGE); 2058 hba->vops->hce_enable_notify(hba, POST_CHANGE);
2048 2059
@@ -2058,23 +2069,33 @@ static int ufshcd_hba_enable(struct ufs_hba *hba)
2058static int ufshcd_link_startup(struct ufs_hba *hba) 2069static int ufshcd_link_startup(struct ufs_hba *hba)
2059{ 2070{
2060 int ret; 2071 int ret;
2072 int retries = DME_LINKSTARTUP_RETRIES;
2061 2073
2062 /* enable UIC related interrupts */ 2074 do {
2063 ufshcd_enable_intr(hba, UIC_COMMAND_COMPL); 2075 if (hba->vops && hba->vops->link_startup_notify)
2076 hba->vops->link_startup_notify(hba, PRE_CHANGE);
2064 2077
2065 if (hba->vops && hba->vops->link_startup_notify) 2078 ret = ufshcd_dme_link_startup(hba);
2066 hba->vops->link_startup_notify(hba, PRE_CHANGE);
2067 2079
2068 ret = ufshcd_dme_link_startup(hba); 2080 /* check if device is detected by inter-connect layer */
2069 if (ret) 2081 if (!ret && !ufshcd_is_device_present(hba)) {
2070 goto out; 2082 dev_err(hba->dev, "%s: Device not present\n", __func__);
2083 ret = -ENXIO;
2084 goto out;
2085 }
2071 2086
2072 /* check if device is detected by inter-connect layer */ 2087 /*
2073 if (!ufshcd_is_device_present(hba)) { 2088 * DME link lost indication is only received when link is up,
2074 dev_err(hba->dev, "%s: Device not present\n", __func__); 2089 * but we can't be sure if the link is up until link startup
2075 ret = -ENXIO; 2090 * succeeds. So reset the local Uni-Pro and try again.
2091 */
2092 if (ret && ufshcd_hba_enable(hba))
2093 goto out;
2094 } while (ret && retries--);
2095
2096 if (ret)
2097 /* failed to get the link up... retire */
2076 goto out; 2098 goto out;
2077 }
2078 2099
2079 /* Include any host controller configuration via UIC commands */ 2100 /* Include any host controller configuration via UIC commands */
2080 if (hba->vops && hba->vops->link_startup_notify) { 2101 if (hba->vops && hba->vops->link_startup_notify) {
@@ -3139,7 +3160,6 @@ out:
3139static int ufshcd_host_reset_and_restore(struct ufs_hba *hba) 3160static int ufshcd_host_reset_and_restore(struct ufs_hba *hba)
3140{ 3161{
3141 int err; 3162 int err;
3142 async_cookie_t cookie;
3143 unsigned long flags; 3163 unsigned long flags;
3144 3164
3145 /* Reset the host controller */ 3165 /* Reset the host controller */
@@ -3152,10 +3172,9 @@ static int ufshcd_host_reset_and_restore(struct ufs_hba *hba)
3152 goto out; 3172 goto out;
3153 3173
3154 /* Establish the link again and restore the device */ 3174 /* Establish the link again and restore the device */
3155 cookie = async_schedule(ufshcd_async_scan, hba); 3175 err = ufshcd_probe_hba(hba);
3156 /* wait for async scan to be completed */ 3176
3157 async_synchronize_cookie(++cookie); 3177 if (!err && (hba->ufshcd_state != UFSHCD_STATE_OPERATIONAL))
3158 if (hba->ufshcd_state != UFSHCD_STATE_OPERATIONAL)
3159 err = -EIO; 3178 err = -EIO;
3160out: 3179out:
3161 if (err) 3180 if (err)
@@ -3177,8 +3196,11 @@ static int ufshcd_reset_and_restore(struct ufs_hba *hba)
3177{ 3196{
3178 int err = 0; 3197 int err = 0;
3179 unsigned long flags; 3198 unsigned long flags;
3199 int retries = MAX_HOST_RESET_RETRIES;
3180 3200
3181 err = ufshcd_host_reset_and_restore(hba); 3201 do {
3202 err = ufshcd_host_reset_and_restore(hba);
3203 } while (err && --retries);
3182 3204
3183 /* 3205 /*
3184 * After reset the door-bell might be cleared, complete 3206 * After reset the door-bell might be cleared, complete
@@ -3243,13 +3265,13 @@ static int ufshcd_eh_host_reset_handler(struct scsi_cmnd *cmd)
3243} 3265}
3244 3266
3245/** 3267/**
3246 * ufshcd_async_scan - asynchronous execution for link startup 3268 * ufshcd_probe_hba - probe hba to detect device and initialize
3247 * @data: data pointer to pass to this function 3269 * @hba: per-adapter instance
3248 * @cookie: cookie data 3270 *
3271 * Execute link-startup and verify device initialization
3249 */ 3272 */
3250static void ufshcd_async_scan(void *data, async_cookie_t cookie) 3273static int ufshcd_probe_hba(struct ufs_hba *hba)
3251{ 3274{
3252 struct ufs_hba *hba = (struct ufs_hba *)data;
3253 int ret; 3275 int ret;
3254 3276
3255 ret = ufshcd_link_startup(hba); 3277 ret = ufshcd_link_startup(hba);
@@ -3275,7 +3297,26 @@ static void ufshcd_async_scan(void *data, async_cookie_t cookie)
3275 pm_runtime_put_sync(hba->dev); 3297 pm_runtime_put_sync(hba->dev);
3276 } 3298 }
3277out: 3299out:
3278 return; 3300 /*
3301 * If we failed to initialize the device or the device is not
3302 * present, turn off the power/clocks etc.
3303 */
3304 if (ret && !ufshcd_eh_in_progress(hba))
3305 ufshcd_hba_exit(hba);
3306
3307 return ret;
3308}
3309
3310/**
3311 * ufshcd_async_scan - asynchronous execution for probing hba
3312 * @data: data pointer to pass to this function
3313 * @cookie: cookie data
3314 */
3315static void ufshcd_async_scan(void *data, async_cookie_t cookie)
3316{
3317 struct ufs_hba *hba = (struct ufs_hba *)data;
3318
3319 ufshcd_probe_hba(hba);
3279} 3320}
3280 3321
3281static struct scsi_host_template ufshcd_driver_template = { 3322static struct scsi_host_template ufshcd_driver_template = {
@@ -3631,6 +3672,7 @@ static int ufshcd_hba_init(struct ufs_hba *hba)
3631 if (err) 3672 if (err)
3632 goto out_disable_vreg; 3673 goto out_disable_vreg;
3633 3674
3675 hba->is_powered = true;
3634 goto out; 3676 goto out;
3635 3677
3636out_disable_vreg: 3678out_disable_vreg:
@@ -3645,10 +3687,13 @@ out:
3645 3687
3646static void ufshcd_hba_exit(struct ufs_hba *hba) 3688static void ufshcd_hba_exit(struct ufs_hba *hba)
3647{ 3689{
3648 ufshcd_variant_hba_exit(hba); 3690 if (hba->is_powered) {
3649 ufshcd_setup_vreg(hba, false); 3691 ufshcd_variant_hba_exit(hba);
3650 ufshcd_setup_clocks(hba, false); 3692 ufshcd_setup_vreg(hba, false);
3651 ufshcd_setup_hba_vreg(hba, false); 3693 ufshcd_setup_clocks(hba, false);
3694 ufshcd_setup_hba_vreg(hba, false);
3695 hba->is_powered = false;
3696 }
3652} 3697}
3653 3698
3654/** 3699/**
diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h
index bc0f7ed02605..eddb3f3b4139 100644
--- a/drivers/scsi/ufs/ufshcd.h
+++ b/drivers/scsi/ufs/ufshcd.h
@@ -228,6 +228,7 @@ struct ufs_hba_variant_ops {
228 * @eh_flags: Error handling flags 228 * @eh_flags: Error handling flags
229 * @intr_mask: Interrupt Mask Bits 229 * @intr_mask: Interrupt Mask Bits
230 * @ee_ctrl_mask: Exception event control mask 230 * @ee_ctrl_mask: Exception event control mask
231 * @is_powered: flag to check if HBA is powered
231 * @eh_work: Worker to handle UFS errors that require s/w attention 232 * @eh_work: Worker to handle UFS errors that require s/w attention
232 * @eeh_work: Worker to handle exception events 233 * @eeh_work: Worker to handle exception events
233 * @errors: HBA errors 234 * @errors: HBA errors
@@ -283,6 +284,7 @@ struct ufs_hba {
283 u32 eh_flags; 284 u32 eh_flags;
284 u32 intr_mask; 285 u32 intr_mask;
285 u16 ee_ctrl_mask; 286 u16 ee_ctrl_mask;
287 bool is_powered;
286 288
287 /* Work Queues */ 289 /* Work Queues */
288 struct work_struct eh_work; 290 struct work_struct eh_work;