static void sh_mmcif_stop_cmd(struct sh_mmcif_host *host, struct mmc_request *mrq, struct mmc_command *cmd) { long time; if (mrq->cmd->opcode == MMC_READ_MULTIPLE_BLOCK) sh_mmcif_bitset(host, MMCIF_CE_INT_MASK, MASK_MCMD12DRE); else if (mrq->cmd->opcode == MMC_WRITE_MULTIPLE_BLOCK) sh_mmcif_bitset(host, MMCIF_CE_INT_MASK, MASK_MCMD12RBE); else { pr_err(DRIVER_NAME": not support stop cmd\n"); cmd->error = sh_mmcif_error_manage(host); return; } time = wait_event_interruptible_timeout(host->intr_wait, host->wait_int == 1 || host->sd_error == 1, host->timeout); if (host->wait_int != 1 && (time == 0 || host->sd_error != 0)) { cmd->error = sh_mmcif_error_manage(host); return; } sh_mmcif_get_cmd12response(host, cmd); host->wait_int = 0; cmd->error = 0; }
static irqreturn_t sh_mmcif_irqt(int irq, void *dev_id) { struct sh_mmcif_host *host = dev_id; struct mmc_request *mrq; bool wait = false; cancel_delayed_work_sync(&host->timeout_work); mutex_lock(&host->thread_lock); mrq = host->mrq; if (!mrq) { dev_dbg(&host->pd->dev, "IRQ thread state %u, wait %u: NULL mrq!\n", host->state, host->wait_for); mutex_unlock(&host->thread_lock); return IRQ_HANDLED; } /* * All handlers return true, if processing continues, and false, if the * request has to be completed - successfully or not */ switch (host->wait_for) { case MMCIF_WAIT_FOR_REQUEST: /* We're too late, the timeout has already kicked in */ mutex_unlock(&host->thread_lock); return IRQ_HANDLED; case MMCIF_WAIT_FOR_CMD: /* Wait for data? */ wait = sh_mmcif_end_cmd(host); break; case MMCIF_WAIT_FOR_MREAD: /* Wait for more data? */ wait = sh_mmcif_mread_block(host); break; case MMCIF_WAIT_FOR_READ: /* Wait for data end? */ wait = sh_mmcif_read_block(host); break; case MMCIF_WAIT_FOR_MWRITE: /* Wait data to write? */ wait = sh_mmcif_mwrite_block(host); break; case MMCIF_WAIT_FOR_WRITE: /* Wait for data end? */ wait = sh_mmcif_write_block(host); break; case MMCIF_WAIT_FOR_STOP: if (host->sd_error) { mrq->stop->error = sh_mmcif_error_manage(host); dev_dbg(&host->pd->dev, "%s(): %d\n", __func__, mrq->stop->error); break; } sh_mmcif_get_cmd12response(host, mrq->stop); mrq->stop->error = 0; break; case MMCIF_WAIT_FOR_READ_END: case MMCIF_WAIT_FOR_WRITE_END: if (host->sd_error) { mrq->data->error = sh_mmcif_error_manage(host); dev_dbg(&host->pd->dev, "%s(): %d\n", __func__, mrq->data->error); } break; default: BUG(); } if (wait) { schedule_delayed_work(&host->timeout_work, host->timeout); /* Wait for more data */ mutex_unlock(&host->thread_lock); return IRQ_HANDLED; } if (host->wait_for != MMCIF_WAIT_FOR_STOP) { struct mmc_data *data = mrq->data; if (!mrq->cmd->error && data && !data->error) data->bytes_xfered = data->blocks * data->blksz; if (mrq->stop && !mrq->cmd->error && (!data || !data->error)) { sh_mmcif_stop_cmd(host, mrq); if (!mrq->stop->error) { schedule_delayed_work(&host->timeout_work, host->timeout); mutex_unlock(&host->thread_lock); return IRQ_HANDLED; } } } host->wait_for = MMCIF_WAIT_FOR_REQUEST; host->state = STATE_IDLE; host->mrq = NULL; mmc_request_done(host->mmc, mrq); mutex_unlock(&host->thread_lock); return IRQ_HANDLED; }
static int sh_mmcif_start_cmd(struct sh_mmcif_host *host, struct mmc_data *data, struct mmc_cmd *cmd) { long time; int ret = 0, mask = 0; u32 opc = cmd->cmdidx; if (opc == MMC_CMD_STOP_TRANSMISSION) { /* MMCIF sends the STOP command automatically */ if (host->last_cmd == MMC_CMD_READ_MULTIPLE_BLOCK) sh_mmcif_bitset(MASK_MCMD12DRE, &host->regs->ce_int_mask); else sh_mmcif_bitset(MASK_MCMD12RBE, &host->regs->ce_int_mask); time = mmcif_wait_interrupt_flag(host); if (time == 0 || host->sd_error != 0) return sh_mmcif_error_manage(host); sh_mmcif_get_cmd12response(host, cmd); return 0; } if (opc == MMC_CMD_SWITCH) mask = MASK_MRBSYE; else mask = MASK_MCRSPE; mask |= MASK_MCMDVIO | MASK_MBUFVIO | MASK_MWDATERR | MASK_MRDATERR | MASK_MRIDXERR | MASK_MRSPERR | MASK_MCCSTO | MASK_MCRCSTO | MASK_MWDATTO | MASK_MRDATTO | MASK_MRBSYTO | MASK_MRSPTO; if (host->data) { sh_mmcif_write(0, &host->regs->ce_block_set); sh_mmcif_write(data->blocksize, &host->regs->ce_block_set); } opc = sh_mmcif_set_cmd(host, data, cmd); sh_mmcif_write(INT_START_MAGIC, &host->regs->ce_int); sh_mmcif_write(mask, &host->regs->ce_int_mask); debug("CMD%d ARG:%08x\n", cmd->cmdidx, cmd->cmdarg); /* set arg */ sh_mmcif_write(cmd->cmdarg, &host->regs->ce_arg); host->wait_int = 0; /* set cmd */ sh_mmcif_write(opc, &host->regs->ce_cmd_set); time = mmcif_wait_interrupt_flag(host); if (time == 0) return sh_mmcif_error_manage(host); if (host->sd_error) { switch (cmd->cmdidx) { case MMC_CMD_ALL_SEND_CID: case MMC_CMD_SELECT_CARD: case MMC_CMD_APP_CMD: ret = TIMEOUT; break; default: printf(DRIVER_NAME": Cmd(d'%d) err\n", cmd->cmdidx); ret = sh_mmcif_error_manage(host); break; } host->sd_error = 0; host->wait_int = 0; return ret; } /* if no response */ if (!(opc & 0x00C00000)) return 0; if (host->wait_int == 1) { sh_mmcif_get_response(host, cmd); host->wait_int = 0; } if (host->data) ret = sh_mmcif_data_trans(host, data, cmd->cmdidx); host->last_cmd = cmd->cmdidx; return ret; }