Skip to content

Commit 1d337ec

Browse files
Sujit Reddy ThummaChristoph Hellwig
authored andcommitted
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 <[email protected]> Signed-off-by: Dolev Raviv <[email protected]> Signed-off-by: Christoph Hellwig <[email protected]>
1 parent da461ce commit 1d337ec

File tree

2 files changed

+75
-28
lines changed

2 files changed

+75
-28
lines changed

drivers/scsi/ufs/ufshcd.c

Lines changed: 73 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,12 @@
6262
/* Task management command timeout */
6363
#define TM_CMD_TIMEOUT 100 /* msecs */
6464

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+
6571
/* Expose the flag value from utp_upiu_query.value */
6672
#define MASK_QUERY_UPIU_FLAG_LOC 0xFF
6773

@@ -137,6 +143,8 @@ static void ufshcd_tmc_handler(struct ufs_hba *hba);
137143
static void ufshcd_async_scan(void *data, async_cookie_t cookie);
138144
static int ufshcd_reset_and_restore(struct ufs_hba *hba);
139145
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);
140148

141149
/*
142150
* ufshcd_wait_for_register - wait for register value to change
@@ -2043,6 +2051,9 @@ static int ufshcd_hba_enable(struct ufs_hba *hba)
20432051
msleep(5);
20442052
}
20452053

2054+
/* enable UIC related interrupts */
2055+
ufshcd_enable_intr(hba, UIC_COMMAND_COMPL);
2056+
20462057
if (hba->vops && hba->vops->hce_enable_notify)
20472058
hba->vops->hce_enable_notify(hba, POST_CHANGE);
20482059

@@ -2058,23 +2069,33 @@ static int ufshcd_hba_enable(struct ufs_hba *hba)
20582069
static int ufshcd_link_startup(struct ufs_hba *hba)
20592070
{
20602071
int ret;
2072+
int retries = DME_LINKSTARTUP_RETRIES;
20612073

2062-
/* enable UIC related interrupts */
2063-
ufshcd_enable_intr(hba, UIC_COMMAND_COMPL);
2074+
do {
2075+
if (hba->vops && hba->vops->link_startup_notify)
2076+
hba->vops->link_startup_notify(hba, PRE_CHANGE);
20642077

2065-
if (hba->vops && hba->vops->link_startup_notify)
2066-
hba->vops->link_startup_notify(hba, PRE_CHANGE);
2078+
ret = ufshcd_dme_link_startup(hba);
20672079

2068-
ret = ufshcd_dme_link_startup(hba);
2069-
if (ret)
2070-
goto out;
2080+
/* check if device is detected by inter-connect layer */
2081+
if (!ret && !ufshcd_is_device_present(hba)) {
2082+
dev_err(hba->dev, "%s: Device not present\n", __func__);
2083+
ret = -ENXIO;
2084+
goto out;
2085+
}
20712086

2072-
/* check if device is detected by inter-connect layer */
2073-
if (!ufshcd_is_device_present(hba)) {
2074-
dev_err(hba->dev, "%s: Device not present\n", __func__);
2075-
ret = -ENXIO;
2087+
/*
2088+
* DME link lost indication is only received when link is up,
2089+
* but we can't be sure if the link is up until link startup
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 */
20762098
goto out;
2077-
}
20782099

20792100
/* Include any host controller configuration via UIC commands */
20802101
if (hba->vops && hba->vops->link_startup_notify) {
@@ -3139,7 +3160,6 @@ static int ufshcd_abort(struct scsi_cmnd *cmd)
31393160
static int ufshcd_host_reset_and_restore(struct ufs_hba *hba)
31403161
{
31413162
int err;
3142-
async_cookie_t cookie;
31433163
unsigned long flags;
31443164

31453165
/* Reset the host controller */
@@ -3152,10 +3172,9 @@ static int ufshcd_host_reset_and_restore(struct ufs_hba *hba)
31523172
goto out;
31533173

31543174
/* Establish the link again and restore the device */
3155-
cookie = async_schedule(ufshcd_async_scan, hba);
3156-
/* wait for async scan to be completed */
3157-
async_synchronize_cookie(++cookie);
3158-
if (hba->ufshcd_state != UFSHCD_STATE_OPERATIONAL)
3175+
err = ufshcd_probe_hba(hba);
3176+
3177+
if (!err && (hba->ufshcd_state != UFSHCD_STATE_OPERATIONAL))
31593178
err = -EIO;
31603179
out:
31613180
if (err)
@@ -3177,8 +3196,11 @@ static int ufshcd_reset_and_restore(struct ufs_hba *hba)
31773196
{
31783197
int err = 0;
31793198
unsigned long flags;
3199+
int retries = MAX_HOST_RESET_RETRIES;
31803200

3181-
err = ufshcd_host_reset_and_restore(hba);
3201+
do {
3202+
err = ufshcd_host_reset_and_restore(hba);
3203+
} while (err && --retries);
31823204

31833205
/*
31843206
* After reset the door-bell might be cleared, complete
@@ -3243,13 +3265,13 @@ static int ufshcd_eh_host_reset_handler(struct scsi_cmnd *cmd)
32433265
}
32443266

32453267
/**
3246-
* ufshcd_async_scan - asynchronous execution for link startup
3247-
* @data: data pointer to pass to this function
3248-
* @cookie: cookie data
3268+
* ufshcd_probe_hba - probe hba to detect device and initialize
3269+
* @hba: per-adapter instance
3270+
*
3271+
* Execute link-startup and verify device initialization
32493272
*/
3250-
static void ufshcd_async_scan(void *data, async_cookie_t cookie)
3273+
static int ufshcd_probe_hba(struct ufs_hba *hba)
32513274
{
3252-
struct ufs_hba *hba = (struct ufs_hba *)data;
32533275
int ret;
32543276

32553277
ret = ufshcd_link_startup(hba);
@@ -3275,7 +3297,26 @@ static void ufshcd_async_scan(void *data, async_cookie_t cookie)
32753297
pm_runtime_put_sync(hba->dev);
32763298
}
32773299
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);
32793320
}
32803321

32813322
static struct scsi_host_template ufshcd_driver_template = {
@@ -3631,6 +3672,7 @@ static int ufshcd_hba_init(struct ufs_hba *hba)
36313672
if (err)
36323673
goto out_disable_vreg;
36333674

3675+
hba->is_powered = true;
36343676
goto out;
36353677

36363678
out_disable_vreg:
@@ -3645,10 +3687,13 @@ static int ufshcd_hba_init(struct ufs_hba *hba)
36453687

36463688
static void ufshcd_hba_exit(struct ufs_hba *hba)
36473689
{
3648-
ufshcd_variant_hba_exit(hba);
3649-
ufshcd_setup_vreg(hba, false);
3650-
ufshcd_setup_clocks(hba, false);
3651-
ufshcd_setup_hba_vreg(hba, false);
3690+
if (hba->is_powered) {
3691+
ufshcd_variant_hba_exit(hba);
3692+
ufshcd_setup_vreg(hba, false);
3693+
ufshcd_setup_clocks(hba, false);
3694+
ufshcd_setup_hba_vreg(hba, false);
3695+
hba->is_powered = false;
3696+
}
36523697
}
36533698

36543699
/**

drivers/scsi/ufs/ufshcd.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -228,6 +228,7 @@ struct ufs_hba_variant_ops {
228228
* @eh_flags: Error handling flags
229229
* @intr_mask: Interrupt Mask Bits
230230
* @ee_ctrl_mask: Exception event control mask
231+
* @is_powered: flag to check if HBA is powered
231232
* @eh_work: Worker to handle UFS errors that require s/w attention
232233
* @eeh_work: Worker to handle exception events
233234
* @errors: HBA errors
@@ -283,6 +284,7 @@ struct ufs_hba {
283284
u32 eh_flags;
284285
u32 intr_mask;
285286
u16 ee_ctrl_mask;
287+
bool is_powered;
286288

287289
/* Work Queues */
288290
struct work_struct eh_work;

0 commit comments

Comments
 (0)