mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-08-26 19:00:25 +00:00
mmc: dw_mmc: rework the code related to cmd/data completion
Main change corresponds to dw_mci_command_complete(). And EBE is divided into read and write. Some minor changes for code readability. Signed-off-by: Seungwon Jeon <tgih.jun@samsung.com> Tested-by: Alim Akhtar <alim.akhtar@samsung.com> Signed-off-by: Chris Ball <cjb@laptop.org>
This commit is contained in:
parent
90c2143a8f
commit
e352c81311
1 changed files with 84 additions and 63 deletions
|
@ -845,7 +845,9 @@ static void __dw_mci_start_request(struct dw_mci *host,
|
|||
|
||||
host->pending_events = 0;
|
||||
host->completed_events = 0;
|
||||
host->cmd_status = 0;
|
||||
host->data_status = 0;
|
||||
host->dir_status = 0;
|
||||
|
||||
data = cmd->data;
|
||||
if (data) {
|
||||
|
@ -1157,7 +1159,7 @@ static void dw_mci_request_end(struct dw_mci *host, struct mmc_request *mrq)
|
|||
spin_lock(&host->lock);
|
||||
}
|
||||
|
||||
static void dw_mci_command_complete(struct dw_mci *host, struct mmc_command *cmd)
|
||||
static int dw_mci_command_complete(struct dw_mci *host, struct mmc_command *cmd)
|
||||
{
|
||||
u32 status = host->cmd_status;
|
||||
|
||||
|
@ -1192,6 +1194,57 @@ static void dw_mci_command_complete(struct dw_mci *host, struct mmc_command *cmd
|
|||
if (host->quirks & DW_MCI_QUIRK_RETRY_DELAY)
|
||||
mdelay(20);
|
||||
}
|
||||
|
||||
return cmd->error;
|
||||
}
|
||||
|
||||
static int dw_mci_data_complete(struct dw_mci *host, struct mmc_data *data)
|
||||
{
|
||||
u32 status = host->data_status, ctrl;
|
||||
|
||||
if (status & DW_MCI_DATA_ERROR_FLAGS) {
|
||||
if (status & SDMMC_INT_DRTO) {
|
||||
data->error = -ETIMEDOUT;
|
||||
} else if (status & SDMMC_INT_DCRC) {
|
||||
data->error = -EILSEQ;
|
||||
} else if (status & SDMMC_INT_EBE) {
|
||||
if (host->dir_status ==
|
||||
DW_MCI_SEND_STATUS) {
|
||||
/*
|
||||
* No data CRC status was returned.
|
||||
* The number of bytes transferred
|
||||
* will be exaggerated in PIO mode.
|
||||
*/
|
||||
data->bytes_xfered = 0;
|
||||
data->error = -ETIMEDOUT;
|
||||
} else if (host->dir_status ==
|
||||
DW_MCI_RECV_STATUS) {
|
||||
data->error = -EIO;
|
||||
}
|
||||
} else {
|
||||
/* SDMMC_INT_SBE is included */
|
||||
data->error = -EIO;
|
||||
}
|
||||
|
||||
dev_err(host->dev, "data error, status 0x%08x\n", status);
|
||||
|
||||
/*
|
||||
* After an error, there may be data lingering
|
||||
* in the FIFO, so reset it - doing so
|
||||
* generates a block interrupt, hence setting
|
||||
* the scatter-gather pointer to NULL.
|
||||
*/
|
||||
sg_miter_stop(&host->sg_miter);
|
||||
host->sg = NULL;
|
||||
ctrl = mci_readl(host, CTRL);
|
||||
ctrl |= SDMMC_CTRL_FIFO_RESET;
|
||||
mci_writel(host, CTRL, ctrl);
|
||||
} else {
|
||||
data->bytes_xfered = data->blocks * data->blksz;
|
||||
data->error = 0;
|
||||
}
|
||||
|
||||
return data->error;
|
||||
}
|
||||
|
||||
static void dw_mci_tasklet_func(unsigned long priv)
|
||||
|
@ -1199,14 +1252,17 @@ static void dw_mci_tasklet_func(unsigned long priv)
|
|||
struct dw_mci *host = (struct dw_mci *)priv;
|
||||
struct mmc_data *data;
|
||||
struct mmc_command *cmd;
|
||||
struct mmc_request *mrq;
|
||||
enum dw_mci_state state;
|
||||
enum dw_mci_state prev_state;
|
||||
u32 status, ctrl;
|
||||
u32 ctrl;
|
||||
unsigned int err;
|
||||
|
||||
spin_lock(&host->lock);
|
||||
|
||||
state = host->state;
|
||||
data = host->data;
|
||||
mrq = host->mrq;
|
||||
|
||||
do {
|
||||
prev_state = state;
|
||||
|
@ -1223,23 +1279,23 @@ static void dw_mci_tasklet_func(unsigned long priv)
|
|||
cmd = host->cmd;
|
||||
host->cmd = NULL;
|
||||
set_bit(EVENT_CMD_COMPLETE, &host->completed_events);
|
||||
dw_mci_command_complete(host, cmd);
|
||||
if (cmd == host->mrq->sbc && !cmd->error) {
|
||||
err = dw_mci_command_complete(host, cmd);
|
||||
if (cmd == mrq->sbc && !err) {
|
||||
prev_state = state = STATE_SENDING_CMD;
|
||||
__dw_mci_start_request(host, host->cur_slot,
|
||||
host->mrq->cmd);
|
||||
mrq->cmd);
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
if (cmd->data && cmd->error) {
|
||||
if (cmd->data && err) {
|
||||
dw_mci_stop_dma(host);
|
||||
send_stop_abort(host, data);
|
||||
state = STATE_SENDING_STOP;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!host->mrq->data || cmd->error) {
|
||||
dw_mci_request_end(host, host->mrq);
|
||||
if (!cmd->data || err) {
|
||||
dw_mci_request_end(host, mrq);
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
|
@ -1270,62 +1326,27 @@ static void dw_mci_tasklet_func(unsigned long priv)
|
|||
|
||||
host->data = NULL;
|
||||
set_bit(EVENT_DATA_COMPLETE, &host->completed_events);
|
||||
status = host->data_status;
|
||||
err = dw_mci_data_complete(host, data);
|
||||
|
||||
if (status & DW_MCI_DATA_ERROR_FLAGS) {
|
||||
if (status & SDMMC_INT_DRTO) {
|
||||
data->error = -ETIMEDOUT;
|
||||
} else if (status & SDMMC_INT_DCRC) {
|
||||
data->error = -EILSEQ;
|
||||
} else if (status & SDMMC_INT_EBE &&
|
||||
host->dir_status ==
|
||||
DW_MCI_SEND_STATUS) {
|
||||
/*
|
||||
* No data CRC status was returned.
|
||||
* The number of bytes transferred will
|
||||
* be exaggerated in PIO mode.
|
||||
*/
|
||||
data->bytes_xfered = 0;
|
||||
data->error = -ETIMEDOUT;
|
||||
} else {
|
||||
dev_err(host->dev,
|
||||
"data FIFO error "
|
||||
"(status=%08x)\n",
|
||||
status);
|
||||
data->error = -EIO;
|
||||
if (!err) {
|
||||
if (!data->stop || mrq->sbc) {
|
||||
if (mrq->sbc)
|
||||
data->stop->error = 0;
|
||||
dw_mci_request_end(host, mrq);
|
||||
goto unlock;
|
||||
}
|
||||
/*
|
||||
* After an error, there may be data lingering
|
||||
* in the FIFO, so reset it - doing so
|
||||
* generates a block interrupt, hence setting
|
||||
* the scatter-gather pointer to NULL.
|
||||
*/
|
||||
sg_miter_stop(&host->sg_miter);
|
||||
host->sg = NULL;
|
||||
ctrl = mci_readl(host, CTRL);
|
||||
ctrl |= SDMMC_CTRL_FIFO_RESET;
|
||||
mci_writel(host, CTRL, ctrl);
|
||||
} else {
|
||||
data->bytes_xfered = data->blocks * data->blksz;
|
||||
data->error = 0;
|
||||
}
|
||||
|
||||
if (!data->stop && !data->error) {
|
||||
dw_mci_request_end(host, host->mrq);
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
if (host->mrq->sbc && !data->error) {
|
||||
data->stop->error = 0;
|
||||
dw_mci_request_end(host, host->mrq);
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
prev_state = state = STATE_SENDING_STOP;
|
||||
if (data->stop && !data->error) {
|
||||
/* stop command for open-ended transfer*/
|
||||
send_stop_abort(host, data);
|
||||
if (data->stop)
|
||||
send_stop_abort(host, data);
|
||||
}
|
||||
|
||||
/*
|
||||
* If err has non-zero,
|
||||
* stop-abort command has been already issued.
|
||||
*/
|
||||
prev_state = state = STATE_SENDING_STOP;
|
||||
|
||||
/* fall through */
|
||||
|
||||
case STATE_SENDING_STOP:
|
||||
|
@ -1334,7 +1355,7 @@ static void dw_mci_tasklet_func(unsigned long priv)
|
|||
break;
|
||||
|
||||
/* CMD error in data command */
|
||||
if (host->mrq->cmd->error && host->mrq->data) {
|
||||
if (mrq->cmd->error && mrq->data) {
|
||||
sg_miter_stop(&host->sg_miter);
|
||||
host->sg = NULL;
|
||||
ctrl = mci_readl(host, CTRL);
|
||||
|
@ -1345,12 +1366,12 @@ static void dw_mci_tasklet_func(unsigned long priv)
|
|||
host->cmd = NULL;
|
||||
host->data = NULL;
|
||||
|
||||
if (host->mrq->stop)
|
||||
dw_mci_command_complete(host, host->mrq->stop);
|
||||
if (mrq->stop)
|
||||
dw_mci_command_complete(host, mrq->stop);
|
||||
else
|
||||
host->cmd_status = 0;
|
||||
|
||||
dw_mci_request_end(host, host->mrq);
|
||||
dw_mci_request_end(host, mrq);
|
||||
goto unlock;
|
||||
|
||||
case STATE_DATA_ERROR:
|
||||
|
|
Loading…
Reference in a new issue