scsi :ufs: verify hba controller hce reg value
Sometimes due to hw issues it takes some time to the host controller register to update. In order to verify the register has updated, a polling is done until its value is set. In addition the functions ufshcd_hba_stop() and ufshcd_wait_for_register() was updated with an additional input parameter, indicating the timeout between reads will be done by sleeping or spinning the cpu. Change-Id: Id79d92a4a0bc05d385eb47c027fe19a765f71851 Signed-off-by: Raviv Shvili <rshvili@codeaurora.org> [subhashj@codeaurora.org: resolved merge conflicts, dropped the changes in drivers/scsi/ufs/ufshcd-pci.c] Signed-off-by: Subhash Jadavani <subhashj@codeaurora.org>
This commit is contained in:
parent
7e9e854fc3
commit
2069520a4c
2 changed files with 27 additions and 24 deletions
|
@ -318,11 +318,12 @@ static void ufshcd_print_tmrs(struct ufs_hba *hba, unsigned long bitmap)
|
||||||
* @val - wait condition
|
* @val - wait condition
|
||||||
* @interval_us - polling interval in microsecs
|
* @interval_us - polling interval in microsecs
|
||||||
* @timeout_ms - timeout in millisecs
|
* @timeout_ms - timeout in millisecs
|
||||||
*
|
* @can_sleep - perform sleep or just spin
|
||||||
* Returns -ETIMEDOUT on error, zero on success
|
* Returns -ETIMEDOUT on error, zero on success
|
||||||
*/
|
*/
|
||||||
static int ufshcd_wait_for_register(struct ufs_hba *hba, u32 reg, u32 mask,
|
int ufshcd_wait_for_register(struct ufs_hba *hba, u32 reg, u32 mask,
|
||||||
u32 val, unsigned long interval_us, unsigned long timeout_ms)
|
u32 val, unsigned long interval_us,
|
||||||
|
unsigned long timeout_ms, bool can_sleep)
|
||||||
{
|
{
|
||||||
int err = 0;
|
int err = 0;
|
||||||
unsigned long timeout = jiffies + msecs_to_jiffies(timeout_ms);
|
unsigned long timeout = jiffies + msecs_to_jiffies(timeout_ms);
|
||||||
|
@ -331,9 +332,10 @@ static int ufshcd_wait_for_register(struct ufs_hba *hba, u32 reg, u32 mask,
|
||||||
val = val & mask;
|
val = val & mask;
|
||||||
|
|
||||||
while ((ufshcd_readl(hba, reg) & mask) != val) {
|
while ((ufshcd_readl(hba, reg) & mask) != val) {
|
||||||
/* wakeup within 50us of expiry */
|
if (can_sleep)
|
||||||
usleep_range(interval_us, interval_us + 50);
|
usleep_range(interval_us, interval_us + 50);
|
||||||
|
else
|
||||||
|
udelay(interval_us);
|
||||||
if (time_after(jiffies, timeout)) {
|
if (time_after(jiffies, timeout)) {
|
||||||
if ((ufshcd_readl(hba, reg) & mask) != val)
|
if ((ufshcd_readl(hba, reg) & mask) != val)
|
||||||
err = -ETIMEDOUT;
|
err = -ETIMEDOUT;
|
||||||
|
@ -1504,7 +1506,7 @@ ufshcd_clear_cmd(struct ufs_hba *hba, int tag)
|
||||||
*/
|
*/
|
||||||
err = ufshcd_wait_for_register(hba,
|
err = ufshcd_wait_for_register(hba,
|
||||||
REG_UTP_TRANSFER_REQ_DOOR_BELL,
|
REG_UTP_TRANSFER_REQ_DOOR_BELL,
|
||||||
mask, ~mask, 1000, 1000);
|
mask, ~mask, 1000, 1000, true);
|
||||||
|
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
@ -2757,18 +2759,9 @@ static int ufshcd_hba_enable(struct ufs_hba *hba)
|
||||||
* development and testing of this driver. msleep can be changed to
|
* development and testing of this driver. msleep can be changed to
|
||||||
* mdelay and retry count can be reduced based on the controller.
|
* mdelay and retry count can be reduced based on the controller.
|
||||||
*/
|
*/
|
||||||
if (!ufshcd_is_hba_active(hba)) {
|
if (!ufshcd_is_hba_active(hba))
|
||||||
|
|
||||||
/* change controller state to "reset state" */
|
/* change controller state to "reset state" */
|
||||||
ufshcd_hba_stop(hba);
|
ufshcd_hba_stop(hba, true);
|
||||||
|
|
||||||
/*
|
|
||||||
* This delay is based on the testing done with UFS host
|
|
||||||
* controller FPGA. The delay can be changed based on the
|
|
||||||
* host controller used.
|
|
||||||
*/
|
|
||||||
msleep(5);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* UniPro link is disabled at this point */
|
/* UniPro link is disabled at this point */
|
||||||
ufshcd_set_link_off(hba);
|
ufshcd_set_link_off(hba);
|
||||||
|
@ -3856,7 +3849,7 @@ static int ufshcd_clear_tm_cmd(struct ufs_hba *hba, int tag)
|
||||||
/* poll for max. 1 sec to clear door bell register by h/w */
|
/* poll for max. 1 sec to clear door bell register by h/w */
|
||||||
err = ufshcd_wait_for_register(hba,
|
err = ufshcd_wait_for_register(hba,
|
||||||
REG_UTP_TASK_REQ_DOOR_BELL,
|
REG_UTP_TASK_REQ_DOOR_BELL,
|
||||||
mask, 0, 1000, 1000);
|
mask, 0, 1000, 1000, true);
|
||||||
out:
|
out:
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
@ -4129,7 +4122,7 @@ static int ufshcd_host_reset_and_restore(struct ufs_hba *hba)
|
||||||
|
|
||||||
/* Reset the host controller */
|
/* Reset the host controller */
|
||||||
spin_lock_irqsave(hba->host->host_lock, flags);
|
spin_lock_irqsave(hba->host->host_lock, flags);
|
||||||
ufshcd_hba_stop(hba);
|
ufshcd_hba_stop(hba, false);
|
||||||
spin_unlock_irqrestore(hba->host->host_lock, flags);
|
spin_unlock_irqrestore(hba->host->host_lock, flags);
|
||||||
|
|
||||||
err = ufshcd_hba_enable(hba);
|
err = ufshcd_hba_enable(hba);
|
||||||
|
@ -5278,7 +5271,7 @@ static int ufshcd_link_state_transition(struct ufs_hba *hba,
|
||||||
* Change controller state to "reset state" which
|
* Change controller state to "reset state" which
|
||||||
* should also put the link in off/reset state
|
* should also put the link in off/reset state
|
||||||
*/
|
*/
|
||||||
ufshcd_hba_stop(hba);
|
ufshcd_hba_stop(hba, true);
|
||||||
/*
|
/*
|
||||||
* TODO: Check if we need any delay to make sure that
|
* TODO: Check if we need any delay to make sure that
|
||||||
* controller is reset
|
* controller is reset
|
||||||
|
@ -5754,7 +5747,7 @@ void ufshcd_remove(struct ufs_hba *hba)
|
||||||
scsi_remove_host(hba->host);
|
scsi_remove_host(hba->host);
|
||||||
/* disable interrupts */
|
/* disable interrupts */
|
||||||
ufshcd_disable_intr(hba, hba->intr_mask);
|
ufshcd_disable_intr(hba, hba->intr_mask);
|
||||||
ufshcd_hba_stop(hba);
|
ufshcd_hba_stop(hba, true);
|
||||||
|
|
||||||
scsi_host_put(hba->host);
|
scsi_host_put(hba->host);
|
||||||
|
|
||||||
|
|
|
@ -633,14 +633,24 @@ int ufshcd_alloc_host(struct device *, struct ufs_hba **);
|
||||||
void ufshcd_dealloc_host(struct ufs_hba *);
|
void ufshcd_dealloc_host(struct ufs_hba *);
|
||||||
int ufshcd_init(struct ufs_hba * , void __iomem * , unsigned int);
|
int ufshcd_init(struct ufs_hba * , void __iomem * , unsigned int);
|
||||||
void ufshcd_remove(struct ufs_hba *);
|
void ufshcd_remove(struct ufs_hba *);
|
||||||
|
int ufshcd_wait_for_register(struct ufs_hba *hba, u32 reg, u32 mask,
|
||||||
|
u32 val, unsigned long interval_us,
|
||||||
|
unsigned long timeout_ms, bool can_sleep);
|
||||||
/**
|
/**
|
||||||
* ufshcd_hba_stop - Send controller to reset state
|
* ufshcd_hba_stop - Send controller to reset state
|
||||||
* @hba: per adapter instance
|
* @hba: per adapter instance
|
||||||
|
* @can_sleep: perform sleep or just spin
|
||||||
*/
|
*/
|
||||||
static inline void ufshcd_hba_stop(struct ufs_hba *hba)
|
static inline void ufshcd_hba_stop(struct ufs_hba *hba, bool can_sleep)
|
||||||
{
|
{
|
||||||
|
int err;
|
||||||
|
|
||||||
ufshcd_writel(hba, CONTROLLER_DISABLE, REG_CONTROLLER_ENABLE);
|
ufshcd_writel(hba, CONTROLLER_DISABLE, REG_CONTROLLER_ENABLE);
|
||||||
|
err = ufshcd_wait_for_register(hba, REG_CONTROLLER_ENABLE,
|
||||||
|
CONTROLLER_ENABLE, CONTROLLER_DISABLE,
|
||||||
|
10, 1, can_sleep);
|
||||||
|
if (err)
|
||||||
|
dev_err(hba->dev, "%s: Controller disable failed\n", __func__);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void check_upiu_size(void)
|
static inline void check_upiu_size(void)
|
||||||
|
|
Loading…
Add table
Reference in a new issue