Merge "mmc: card: block: Add support for completing cmdq requests with error"
This commit is contained in:
commit
ded703d63e
4 changed files with 102 additions and 4 deletions
|
@ -3544,7 +3544,7 @@ void mmc_blk_cmdq_complete_rq(struct request *rq)
|
|||
else if (mrq->data && mrq->data->error)
|
||||
err = mrq->data->error;
|
||||
|
||||
if (err || cmdq_req->resp_err) {
|
||||
if ((err || cmdq_req->resp_err) && !cmdq_req->skip_err_handling) {
|
||||
pr_err("%s: %s: txfr error(%d)/resp_err(%d)\n",
|
||||
mmc_hostname(mrq->host), __func__, err,
|
||||
cmdq_req->resp_err);
|
||||
|
@ -3581,6 +3581,17 @@ void mmc_blk_cmdq_complete_rq(struct request *rq)
|
|||
blk_end_request_all(rq, err);
|
||||
goto out;
|
||||
}
|
||||
/*
|
||||
* In case of error, cmdq_req->data.bytes_xfered is set to 0.
|
||||
* If we call blk_end_request() with nr_bytes as 0 then the request
|
||||
* never gets completed. So in case of error, to complete a request
|
||||
* with error we should use blk_end_request_all().
|
||||
*/
|
||||
if (err && cmdq_req->skip_err_handling) {
|
||||
cmdq_req->skip_err_handling = false;
|
||||
blk_end_request_all(rq, err);
|
||||
goto out;
|
||||
}
|
||||
|
||||
blk_end_request(rq, err, cmdq_req->data.bytes_xfered);
|
||||
|
||||
|
|
|
@ -145,6 +145,29 @@ static void cmdq_clear_set_irqs(struct cmdq_host *cq_host, u32 clear, u32 set)
|
|||
mb();
|
||||
}
|
||||
|
||||
static int cmdq_clear_task_poll(struct cmdq_host *cq_host, unsigned int tag)
|
||||
{
|
||||
int retries = 100;
|
||||
|
||||
cmdq_clear_set_irqs(cq_host, CQIS_TCL, 0);
|
||||
cmdq_writel(cq_host, 1<<tag, CQTCLR);
|
||||
while (retries) {
|
||||
/*
|
||||
* Task Clear register and doorbell,
|
||||
* both should indicate that task is cleared
|
||||
*/
|
||||
if ((cmdq_readl(cq_host, CQTCLR) & 1<<tag) ||
|
||||
(cmdq_readl(cq_host, CQTDBR) & 1<<tag)) {
|
||||
udelay(5);
|
||||
retries--;
|
||||
continue;
|
||||
} else
|
||||
break;
|
||||
}
|
||||
|
||||
cmdq_clear_set_irqs(cq_host, 0, CQIS_TCL);
|
||||
return retries ? 0 : -ETIMEDOUT;
|
||||
}
|
||||
|
||||
#define DRV_NAME "cmdq-host"
|
||||
|
||||
|
@ -857,6 +880,8 @@ irqreturn_t cmdq_irq(struct mmc_host *mmc, int err)
|
|||
struct mmc_request *mrq;
|
||||
int ret;
|
||||
u32 dbr_set = 0;
|
||||
u32 dev_pend_set = 0;
|
||||
int stat_err = 0;
|
||||
|
||||
status = cmdq_readl(cq_host, CQIS);
|
||||
|
||||
|
@ -865,7 +890,9 @@ irqreturn_t cmdq_irq(struct mmc_host *mmc, int err)
|
|||
MMC_TRACE(mmc, "%s: CQIS: 0x%x err: %d\n",
|
||||
__func__, status, err);
|
||||
|
||||
if (err || (status & CQIS_RED)) {
|
||||
stat_err = status & (CQIS_RED | CQIS_GCE | CQIS_ICCE);
|
||||
|
||||
if (err || stat_err) {
|
||||
err_info = cmdq_readl(cq_host, CQTERRI);
|
||||
pr_err("%s: err: %d status: 0x%08x task-err-info (0x%08lx)\n",
|
||||
mmc_hostname(mmc), err, status, err_info);
|
||||
|
@ -968,7 +995,7 @@ skip_cqterri:
|
|||
* CQE detected a reponse error from device
|
||||
* In most cases, this would require a reset.
|
||||
*/
|
||||
if (status & CQIS_RED) {
|
||||
if (stat_err & CQIS_RED) {
|
||||
/*
|
||||
* will check if the RED error is due to a bkops
|
||||
* exception once the queue is empty
|
||||
|
@ -987,6 +1014,62 @@ skip_cqterri:
|
|||
mrq->cmdq_req->resp_arg = cmdq_readl(cq_host, CQCRA);
|
||||
}
|
||||
|
||||
/*
|
||||
* Generic Crypto error detected by CQE.
|
||||
* Its a fatal, would require cmdq reset.
|
||||
*/
|
||||
if (stat_err & CQIS_GCE) {
|
||||
if (mrq->data)
|
||||
mrq->data->error = -EIO;
|
||||
pr_err("%s: Crypto generic error while processing task %lu!",
|
||||
mmc_hostname(mmc), tag);
|
||||
MMC_TRACE(mmc, "%s: GCE error detected with tag %lu\n",
|
||||
__func__, tag);
|
||||
}
|
||||
/*
|
||||
* Invalid crypto config error detected by CQE, clear the task.
|
||||
* Task can be cleared only when CQE is halt state.
|
||||
*/
|
||||
if (stat_err & CQIS_ICCE) {
|
||||
/*
|
||||
* Invalid Crypto Config Error is detected at the
|
||||
* beginning of the transfer before the actual execution
|
||||
* started. So just clear the task in CQE. No need to
|
||||
* clear in device. Only the task which caused ICCE has
|
||||
* to be cleared. Other tasks can be continue processing
|
||||
* The first task which is about to be prepared would
|
||||
* cause ICCE Error.
|
||||
*/
|
||||
dbr_set = cmdq_readl(cq_host, CQTDBR);
|
||||
dev_pend_set = cmdq_readl(cq_host, CQDPT);
|
||||
if (dbr_set ^ dev_pend_set)
|
||||
tag = ffs(dbr_set ^ dev_pend_set) - 1;
|
||||
mrq = get_req_by_tag(cq_host, tag);
|
||||
pr_err("%s: Crypto config error while processing task %lu!",
|
||||
mmc_hostname(mmc), tag);
|
||||
MMC_TRACE(mmc, "%s: ICCE error with tag %lu\n",
|
||||
__func__, tag);
|
||||
if (mrq->data)
|
||||
mrq->data->error = -EIO;
|
||||
else if (mrq->cmd)
|
||||
mrq->cmd->error = -EIO;
|
||||
/*
|
||||
* If CQE is halted and tag is valid then clear the task
|
||||
* then un-halt CQE and set flag to skip error recovery.
|
||||
* If any of the condtions is not met thene it will
|
||||
* enter into default error recovery path.
|
||||
*/
|
||||
if (!ret && (dbr_set ^ dev_pend_set)) {
|
||||
ret = cmdq_clear_task_poll(cq_host, tag);
|
||||
if (ret) {
|
||||
pr_err("%s: %s: task[%lu] clear failed ret=%d\n",
|
||||
mmc_hostname(mmc),
|
||||
__func__, tag, ret);
|
||||
} else if (!cmdq_halt_poll(mmc, false)) {
|
||||
mrq->cmdq_req->skip_err_handling = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
cmdq_finish_data(mmc, tag);
|
||||
} else {
|
||||
cmdq_writel(cq_host, status, CQIS);
|
||||
|
@ -1052,6 +1135,7 @@ static int cmdq_halt_poll(struct mmc_host *mmc, bool halt)
|
|||
cq_host->ops->clear_set_irqs(mmc, true);
|
||||
cmdq_writel(cq_host, cmdq_readl(cq_host, CQCTL) & ~HALT,
|
||||
CQCTL);
|
||||
mmc_host_clr_halt(mmc);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -37,6 +37,8 @@
|
|||
#define CQIS_TCC (1 << 1)
|
||||
#define CQIS_RED (1 << 2)
|
||||
#define CQIS_TCL (1 << 3)
|
||||
#define CQIS_GCE (1 << 4)
|
||||
#define CQIS_ICCE (1 << 5)
|
||||
|
||||
/* interrupt status enable */
|
||||
#define CQISTE 0x14
|
||||
|
@ -112,7 +114,7 @@
|
|||
/* command response argument */
|
||||
#define CQCRA 0x5C
|
||||
|
||||
#define CQ_INT_ALL 0xF
|
||||
#define CQ_INT_ALL 0x3F
|
||||
#define CQIC_DEFAULT_ICCTH 31
|
||||
#define CQIC_DEFAULT_ICTOVAL 1
|
||||
|
||||
|
|
|
@ -208,6 +208,7 @@ struct mmc_cmdq_req {
|
|||
unsigned int resp_arg;
|
||||
unsigned int dev_pend_tasks;
|
||||
bool resp_err;
|
||||
bool skip_err_handling;
|
||||
int tag; /* used for command queuing */
|
||||
u8 ctx_id;
|
||||
};
|
||||
|
|
Loading…
Add table
Reference in a new issue