diff options
-rw-r--r-- | drivers/scsi/ufs/ufshcd.c | 101 | ||||
-rw-r--r-- | drivers/scsi/ufs/ufshcd.h | 2 |
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); | |||
137 | static void ufshcd_async_scan(void *data, async_cookie_t cookie); | 143 | static void ufshcd_async_scan(void *data, async_cookie_t cookie); |
138 | static int ufshcd_reset_and_restore(struct ufs_hba *hba); | 144 | static int ufshcd_reset_and_restore(struct ufs_hba *hba); |
139 | static int ufshcd_clear_tm_cmd(struct ufs_hba *hba, int tag); | 145 | static int ufshcd_clear_tm_cmd(struct ufs_hba *hba, int tag); |
146 | static void ufshcd_hba_exit(struct ufs_hba *hba); | ||
147 | static 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) | |||
2058 | static int ufshcd_link_startup(struct ufs_hba *hba) | 2069 | static 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: | |||
3139 | static int ufshcd_host_reset_and_restore(struct ufs_hba *hba) | 3160 | static 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; |
3160 | out: | 3179 | out: |
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 | */ |
3250 | static void ufshcd_async_scan(void *data, async_cookie_t cookie) | 3273 | static 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 | } |
3277 | out: | 3299 | out: |
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 | */ | ||
3315 | static 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 | ||
3281 | static struct scsi_host_template ufshcd_driver_template = { | 3322 | static 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 | ||
3636 | out_disable_vreg: | 3678 | out_disable_vreg: |
@@ -3645,10 +3687,13 @@ out: | |||
3645 | 3687 | ||
3646 | static void ufshcd_hba_exit(struct ufs_hba *hba) | 3688 | static 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; |