Browse Source

Merge "feat(ufs): adds timeout and error handling" into integration

pull/1995/head
Madhukar Pappireddy 2 years ago
committed by TrustedFirmware Code Review
parent
commit
2519ee5ffe
  1. 195
      drivers/ufs/ufs.c
  2. 20
      include/drivers/ufs.h

195
drivers/ufs/ufs.c

@ -30,9 +30,138 @@
static ufs_params_t ufs_params;
static int nutrs; /* Number of UTP Transfer Request Slots */
/*
* ufs_uic_error_handler - UIC error interrupts handler
* @ignore_linereset: set to ignore PA_LAYER_GEN_ERR (UIC error)
*
* Returns
* 0 - ignore error
* -EIO - fatal error, needs re-init
* -EAGAIN - non-fatal error, retries are sufficient
*/
static int ufs_uic_error_handler(bool ignore_linereset)
{
uint32_t data;
int result = 0;
data = mmio_read_32(ufs_params.reg_base + UECPA);
if (data & UFS_UIC_PA_ERROR_MASK) {
if (data & PA_LAYER_GEN_ERR) {
if (!ignore_linereset) {
return -EIO;
}
} else {
result = -EAGAIN;
}
}
data = mmio_read_32(ufs_params.reg_base + UECDL);
if (data & UFS_UIC_DL_ERROR_MASK) {
if (data & PA_INIT_ERR) {
return -EIO;
}
result = -EAGAIN;
}
/* NL/TL/DME error requires retries */
data = mmio_read_32(ufs_params.reg_base + UECN);
if (data & UFS_UIC_NL_ERROR_MASK) {
result = -EAGAIN;
}
data = mmio_read_32(ufs_params.reg_base + UECT);
if (data & UFS_UIC_TL_ERROR_MASK) {
result = -EAGAIN;
}
data = mmio_read_32(ufs_params.reg_base + UECDME);
if (data & UFS_UIC_DME_ERROR_MASK) {
result = -EAGAIN;
}
return result;
}
/*
* ufs_error_handler - error interrupts handler
* @status: interrupt status
* @ignore_linereset: set to ignore PA_LAYER_GEN_ERR (UIC error)
*
* Returns
* 0 - ignore error
* -EIO - fatal error, needs re-init
* -EAGAIN - non-fatal error, retries are sufficient
*/
static int ufs_error_handler(uint32_t status, bool ignore_linereset)
{
int result;
if (status & UFS_INT_UE) {
result = ufs_uic_error_handler(ignore_linereset);
if (result != 0) {
return result;
}
}
/* Return I/O error on fatal error, it is upto the caller to re-init UFS */
if (status & UFS_INT_FATAL) {
return -EIO;
}
/* retry for non-fatal errors */
return -EAGAIN;
}
/*
* ufs_wait_for_int_status - wait for expected interrupt status
* @expected: expected interrupt status bit
* @timeout_ms: timeout in milliseconds to poll for
* @ignore_linereset: set to ignore PA_LAYER_GEN_ERR (UIC error)
*
* Returns
* 0 - received expected interrupt and cleared it
* -EIO - fatal error, needs re-init
* -EAGAIN - non-fatal error, caller can retry
* -ETIMEDOUT - timed out waiting for interrupt status
*/
static int ufs_wait_for_int_status(const uint32_t expected_status,
unsigned int timeout_ms,
bool ignore_linereset)
{
uint32_t interrupt_status, interrupts_enabled;
int result = 0;
interrupts_enabled = mmio_read_32(ufs_params.reg_base + IE);
do {
interrupt_status = mmio_read_32(ufs_params.reg_base + IS) & interrupts_enabled;
if (interrupt_status & UFS_INT_ERR) {
mmio_write_32(ufs_params.reg_base + IS, interrupt_status & UFS_INT_ERR);
result = ufs_error_handler(interrupt_status, ignore_linereset);
if (result != 0) {
return result;
}
}
if (interrupt_status & expected_status) {
break;
}
mdelay(1);
} while (timeout_ms-- > 0);
if (!(interrupt_status & expected_status)) {
return -ETIMEDOUT;
}
mmio_write_32(ufs_params.reg_base + IS, expected_status);
return result;
}
int ufshc_send_uic_cmd(uintptr_t base, uic_cmd_t *cmd)
{
unsigned int data;
int result;
if (base == 0 || cmd == NULL)
return -EINVAL;
@ -46,10 +175,12 @@ int ufshc_send_uic_cmd(uintptr_t base, uic_cmd_t *cmd)
mmio_write_32(base + UCMDARG3, cmd->arg3);
mmio_write_32(base + UICCMD, cmd->op);
do {
data = mmio_read_32(base + IS);
} while ((data & UFS_INT_UCCS) == 0);
mmio_write_32(base + IS, UFS_INT_UCCS);
result = ufs_wait_for_int_status(UFS_INT_UCCS, UIC_CMD_TIMEOUT_MS,
cmd->op == DME_SET);
if (result != 0) {
return result;
}
return mmio_read_32(base + UCMDARG2) & CONFIG_RESULT_CODE_MASK;
}
@ -83,9 +214,10 @@ int ufshc_dme_get(unsigned int attr, unsigned int idx, unsigned int *val)
result = ufshc_send_uic_cmd(base, &cmd);
if (result == 0)
break;
data = mmio_read_32(base + IS);
if (data & UFS_INT_UE)
return -EINVAL;
/* -EIO requires UFS re-init */
if (result == -EIO) {
return result;
}
}
if (retries >= UFS_UIC_COMMAND_RETRIES)
return -EIO;
@ -97,7 +229,6 @@ int ufshc_dme_get(unsigned int attr, unsigned int idx, unsigned int *val)
int ufshc_dme_set(unsigned int attr, unsigned int idx, unsigned int val)
{
uintptr_t base;
unsigned int data;
int result, retries;
uic_cmd_t cmd;
@ -113,9 +244,10 @@ int ufshc_dme_set(unsigned int attr, unsigned int idx, unsigned int val)
result = ufshc_send_uic_cmd(base, &cmd);
if (result == 0)
break;
data = mmio_read_32(base + IS);
if (data & UFS_INT_UE)
return -EINVAL;
/* -EIO requires UFS re-init */
if (result == -EIO) {
return result;
}
}
if (retries >= UFS_UIC_COMMAND_RETRIES)
return -EIO;
@ -193,9 +325,10 @@ static int ufshc_reset(uintptr_t base)
return -EIO;
}
/* Enable Interrupts */
data = UFS_INT_UCCS | UFS_INT_ULSS | UFS_INT_UE | UFS_INT_UTPES |
UFS_INT_DFES | UFS_INT_HCFES | UFS_INT_SBFES;
/* Enable UIC Interrupts alone. We can ignore other interrupts until
* link is up as there might be spurious error interrupts during link-up
*/
data = UFS_INT_UCCS | UFS_INT_UHES | UFS_INT_UHXS | UFS_INT_UPMS;
mmio_write_32(base + IE, data);
return 0;
@ -229,6 +362,13 @@ static int ufshc_link_startup(uintptr_t base)
data = mmio_read_32(base + IS);
if (data & UFS_INT_ULSS)
mmio_write_32(base + IS, UFS_INT_ULSS);
/* clear UE set due to line-reset */
if (data & UFS_INT_UE) {
mmio_write_32(base + IS, UFS_INT_UE);
}
/* clearing line-reset, UECPA is cleared on read */
mmio_read_32(base + UECPA);
return 0;
}
return -EIO;
@ -472,21 +612,22 @@ static void ufs_send_request(int task_tag)
mmio_setbits_32(ufs_params.reg_base + UTRLDBR, 1 << slot);
}
static int ufs_check_resp(utp_utrd_t *utrd, int trans_type)
static int ufs_check_resp(utp_utrd_t *utrd, int trans_type, unsigned int timeout_ms)
{
utrd_header_t *hd;
resp_upiu_t *resp;
sense_data_t *sense;
unsigned int data;
int slot;
int slot, result;
hd = (utrd_header_t *)utrd->header;
resp = (resp_upiu_t *)utrd->resp_upiu;
do {
data = mmio_read_32(ufs_params.reg_base + IS);
if ((data & ~(UFS_INT_UCCS | UFS_INT_UTRCS)) != 0)
return -EIO;
} while ((data & UFS_INT_UTRCS) == 0);
result = ufs_wait_for_int_status(UFS_INT_UTRCS, timeout_ms, false);
if (result != 0) {
return result;
}
slot = utrd->task_tag - 1;
data = mmio_read_32(ufs_params.reg_base + UTRLDBR);
@ -510,6 +651,7 @@ static int ufs_check_resp(utp_utrd_t *utrd, int trans_type)
(void)resp;
(void)slot;
(void)data;
return 0;
}
@ -523,7 +665,7 @@ static void ufs_send_cmd(utp_utrd_t *utrd, uint8_t cmd_op, uint8_t lun, int lba,
result = ufs_prepare_cmd(utrd, cmd_op, lun, lba, buf, length);
assert(result == 0);
ufs_send_request(utrd->task_tag);
result = ufs_check_resp(utrd, RESPONSE_UPIU);
result = ufs_check_resp(utrd, RESPONSE_UPIU, CMD_TIMEOUT_MS);
if (result == 0 || result == -EIO) {
break;
}
@ -574,7 +716,7 @@ static void ufs_verify_init(void)
get_utrd(&utrd);
ufs_prepare_nop_out(&utrd);
ufs_send_request(utrd.task_tag);
result = ufs_check_resp(&utrd, NOP_IN_UPIU);
result = ufs_check_resp(&utrd, NOP_IN_UPIU, NOP_OUT_TIMEOUT_MS);
assert(result == 0);
(void)result;
}
@ -607,7 +749,7 @@ static void ufs_query(uint8_t op, uint8_t idn, uint8_t index, uint8_t sel,
get_utrd(&utrd);
ufs_prepare_query(&utrd, op, idn, index, sel, buf, size);
ufs_send_request(utrd.task_tag);
result = ufs_check_resp(&utrd, QUERY_RESPONSE_UPIU);
result = ufs_check_resp(&utrd, QUERY_RESPONSE_UPIU, QUERY_REQ_TIMEOUT_MS);
assert(result == 0);
resp = (query_resp_upiu_t *)utrd.resp_upiu;
#ifdef UFS_RESP_DEBUG
@ -895,6 +1037,11 @@ int ufs_init(const ufs_ops_t *ops, ufs_params_t *params)
result = ufshc_link_startup(ufs_params.reg_base);
assert(result == 0);
/* enable all interrupts */
data = UFS_INT_UCCS | UFS_INT_UHES | UFS_INT_UHXS | UFS_INT_UPMS;
data |= UFS_INT_UTRCS | UFS_INT_ERR;
mmio_write_32(ufs_params.reg_base + IE, data);
ufs_enum();
ufs_get_device_info(&card);

20
include/drivers/ufs.h

@ -57,6 +57,21 @@
/* UTP Transfer Request Completion Status */
#define UFS_INT_UTRCS (1 << 0)
#define UFS_INT_FATAL (UFS_INT_DFES |\
UFS_INT_HCFES |\
UFS_INT_SBFES)
#define UFS_INT_ERR (UFS_INT_FATAL |\
UFS_INT_UE)
#define UFS_UIC_PA_ERROR_MASK 0x8000001F
#define UFS_UIC_DL_ERROR_MASK 0x8000FFFF
#define UFS_UIC_NL_ERROR_MASK 0x80000007
#define UFS_UIC_TL_ERROR_MASK 0x8000007F
#define UFS_UIC_DME_ERROR_MASK 0x80000001
#define PA_INIT_ERR (1 << 13)
#define PA_LAYER_GEN_ERR (1 << 4)
/* Host Controller Status */
#define HCS 0x30
#define HCS_UPMCRS_MASK (7 << 8)
@ -275,6 +290,11 @@
#define FDEVICEINIT_TIMEOUT_MS 1500
#define UIC_CMD_TIMEOUT_MS 500
#define QUERY_REQ_TIMEOUT_MS 1500
#define NOP_OUT_TIMEOUT_MS 50
#define CMD_TIMEOUT_MS 5000
/**
* ufs_dev_desc - ufs device details from the device descriptor
* @wmanufacturerid: card details

Loading…
Cancel
Save