Loading drivers/mmc/card/block.c +12 −1 Original line number Diff line number Diff line Loading @@ -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); Loading Loading @@ -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); Loading drivers/mmc/host/cmdq_hci.c +86 −2 Original line number Diff line number Diff line Loading @@ -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" Loading Loading @@ -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); Loading @@ -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); Loading Loading @@ -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 Loading @@ -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); Loading Loading @@ -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; } Loading drivers/mmc/host/cmdq_hci.h +3 −1 Original line number Diff line number Diff line Loading @@ -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 Loading Loading @@ -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 Loading include/linux/mmc/host.h +1 −0 Original line number Diff line number Diff line Loading @@ -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 Loading
drivers/mmc/card/block.c +12 −1 Original line number Diff line number Diff line Loading @@ -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); Loading Loading @@ -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); Loading
drivers/mmc/host/cmdq_hci.c +86 −2 Original line number Diff line number Diff line Loading @@ -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" Loading Loading @@ -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); Loading @@ -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); Loading Loading @@ -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 Loading @@ -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); Loading Loading @@ -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; } Loading
drivers/mmc/host/cmdq_hci.h +3 −1 Original line number Diff line number Diff line Loading @@ -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 Loading Loading @@ -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 Loading
include/linux/mmc/host.h +1 −0 Original line number Diff line number Diff line Loading @@ -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