aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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;