//MMC/SD卡中断服务程序 static irqreturn_t s3cmci_irq(int irq, void *dev_id) { //dev_id参数是申请中断的时候传递过来的s3cmci_host结构体,void类型的指针可以存放任何的数据类型 struct s3cmci_host *host = dev_id; struct mmc_command *cmd; u32 mci_csta, mci_dsta, mci_fsta, mci_dcnt, mci_imsk; u32 mci_cclear, mci_dclear; unsigned long iflags;
//关中断并保持状态字 spin_lock_irqsave(&host->complete_lock, iflags);
//分别读命令状态、数据状态、数据保留计数器、FIFO状态、中断屏蔽寄存器的值 mci_csta = readl(host->base + S3C2410_SDICMDSTAT); mci_dsta = readl(host->base + S3C2410_SDIDSTA); mci_dcnt = readl(host->base + S3C2410_SDIDCNT); mci_fsta = readl(host->base + S3C2410_SDIFSTA); mci_imsk = readl(host->base + host->sdiimsk); mci_cclear = 0; mci_dclear = 0;
//如果当前没有请求状态或者请求已经完成了,则恢复中断什么都不做 if ((host->complete_what == COMPLETION_NONE) || (host->complete_what == COMPLETION_FINALIZE)) { host->status = "nothing to complete"; clear_imask(host); goto irq_out; }
//如果核心层无MMC/SD请求,则恢复中断什么都不做 if (!host->mrq) { host->status = "no active mrq"; clear_imask(host); goto irq_out; }
//获取当前发送命令有无完成 cmd = host->cmd_is_stop ? host->mrq->stop : host->mrq->cmd;
//如果发送命令完成了,则恢复中断什么都不做 if (!cmd) { host->status = "no active cmd"; clear_imask(host); goto irq_out; }
//判断在数据传输状态时使用的传输方式 if (!host->dodma) { //不是DMA传输。如果是FIFO写,则切换到底半部去进行FIFO的写操作 if ((host->pio_active == XFER_WRITE) && (mci_fsta & S3C2410_SDIFSTA_TFDET)) { disable_imask(host, S3C2410_SDIIMSK_TXFIFOHALF); tasklet_schedule(&host->pio_tasklet); host->status = "pio tx"; }
//如果是FIFO读,则切换到底半部去进行FIFO的读操作 if ((host->pio_active == XFER_READ) && (mci_fsta & S3C2410_SDIFSTA_RFDET)) { disable_imask(host, S3C2410_SDIIMSK_RXFIFOHALF | S3C2410_SDIIMSK_RXFIFOLAST); tasklet_schedule(&host->pio_tasklet); host->status = "pio rx"; } }
//命令响应超时 if (mci_csta & S3C2410_SDICMDSTAT_CMDTIMEOUT) { dbg(host, dbg_err, "CMDSTAT: error CMDTIMEOUT\n"); cmd->error = -ETIMEDOUT; host->status = "error: command timeout"; goto fail_transfer; }
//命令发送结束 if (mci_csta & S3C2410_SDICMDSTAT_CMDSENT) { if (host->complete_what == COMPLETION_CMDSENT) { host->status = "ok: command sent"; goto close_transfer; }
mci_cclear |= S3C2410_SDICMDSTAT_CMDSENT; }
//收到命令响应,CRC校验失败 if (mci_csta & S3C2410_SDICMDSTAT_CRCFAIL) { if (cmd->flags & MMC_RSP_CRC) { if (host->mrq->cmd->flags & MMC_RSP_136) { dbg(host, dbg_irq, "fixup: ignore CRC fail with long rsp\n"); } else { /* note, we used to fail the transfer * here, but it seems that this is just * the hardware getting it wrong. * * cmd->error = -EILSEQ; * host->status = "error: bad command crc"; * goto fail_transfer; */ } }
mci_cclear |= S3C2410_SDICMDSTAT_CRCFAIL; }
//收到命令响应,响应结束 if (mci_csta & S3C2410_SDICMDSTAT_RSPFIN) { //如果当前任务是完成,接收命令响应 if (host->complete_what == COMPLETION_RSPFIN) { host->status = "ok: command response received"; goto close_transfer;//停止传输
} //当前任务是完成数据传输和接收命令响应 if (host->complete_what == COMPLETION_XFERFINISH_RSPFIN) //标记当前任务为完成数据传输 host->complete_what = COMPLETION_XFERFINISH;
//清除收到命令响应标志 mci_cclear |= S3C2410_SDICMDSTAT_RSPFIN; }
if (!cmd->data) goto clear_status_bits;
//FIFO失败 if (mci_fsta & S3C2440_SDIFSTA_FIFOFAIL) { dbg(host, dbg_err, "FIFO failure\n"); host->mrq->data->error = -EILSEQ; host->status = "error: 2440 fifo failure"; goto fail_transfer; }
//接收CRC错误 if (mci_dsta & S3C2410_SDIDSTA_RXCRCFAIL) { dbg(host, dbg_err, "bad data crc (outgoing)\n"); cmd->data->error = -EILSEQ; host->status = "error: bad data crc (outgoing)"; goto fail_transfer; }
//发送数据后,CRC状态错误 if (mci_dsta & S3C2410_SDIDSTA_CRCFAIL) { dbg(host, dbg_err, "bad data crc (incoming)\n"); cmd->data->error = -EILSEQ; host->status = "error: bad data crc (incoming)"; goto fail_transfer; }
//数据/忙接收超时 if (mci_dsta & S3C2410_SDIDSTA_DATATIMEOUT) { dbg(host, dbg_err, "data timeout\n"); cmd->data->error = -ETIMEDOUT; host->status = "error: data timeout"; goto fail_transfer; }
//数据计数器为0,和本次请求的全部数据传输结束 if (mci_dsta & S3C2410_SDIDSTA_XFERFINISH) { //如果当前任务是完成数据传输则结束数据传输 if (host->complete_what == COMPLETION_XFERFINISH) { host->status = "ok: data transfer completed"; goto close_transfer; }
//如果当前任务是完成数据传输和接收命令响应 if (host->complete_what == COMPLETION_XFERFINISH_RSPFIN) //标记当前任务为完成 接收命令响应 host->complete_what = COMPLETION_RSPFIN;
//清除数据传输完标志 mci_dclear |= S3C2410_SDIDSTA_XFERFINISH; }
//清除状态字 clear_status_bits: writel(mci_cclear, host->base + S3C2410_SDICMDSTAT); writel(mci_dclear, host->base + S3C2410_SDIDSTA);
goto irq_out;
//传输失败 fail_transfer: host->pio_active = XFER_NONE;
//传输结束 close_transfer: host->complete_what = COMPLETION_FINALIZE;
clear_imask(host); tasklet_schedule(&host->pio_tasklet);
goto irq_out;
irq_out: dbg(host, dbg_irq, "csta:0x%08x dsta:0x%08x fsta:0x%08x dcnt:0x%08x status:%s.\n", mci_csta, mci_dsta, mci_fsta, mci_dcnt, host->status);
//开中断并恢复状态字 spin_unlock_irqrestore(&host->complete_lock, iflags); return IRQ_HANDLED; }
//MMC/SD卡中断底半部程序 static void pio_tasklet(unsigned long data) { //data参数是在s3cmci_probe中的tasklet_init的时候传递过来的 struct s3cmci_host *host = (struct s3cmci_host *) data;
//在执行底半部程序的时候屏蔽中断 disable_irq(host->irq);
//判断如果当前存在FIFO的写状态,则进行FIFO的写操作 if (host->pio_active == XFER_WRITE) do_pio_write(host);
//判断如果当前存在FIFO的读状态,则进行FIFO的读操作 if (host->pio_active == XFER_READ) do_pio_read(host);
//判断如果当前的请求状态为完成状态,则准备进行完成请求处理 if (host->complete_what == COMPLETION_FINALIZE) { //清空中断屏蔽寄存器 clear_imask(host); //FIFO状态验证 if (host->pio_active != XFER_NONE) { if (host->mrq->data) host->mrq->data->error = -EINVAL; }
//完成请求处理 finalize_request(host); } else //当前请求状态为其他,则使能中断继续请求处理 enable_irq(host->irq); }
//完成请求处理 static void finalize_request(struct s3cmci_host *host) { struct mmc_request *mrq = host->mrq; struct mmc_command *cmd = host->cmd_is_stop ? mrq->stop : mrq->cmd; int debug_as_failure = 0;
//如果当前请求状态不为完成状态,则为错误 if (host->complete_what != COMPLETION_FINALIZE) return;
if (!mrq) return;
if (cmd->data && (cmd->error == 0) && (cmd->data->error == 0)) { if (host->dodma && (!host->dma_complete)) { dbg(host, dbg_dma, "DMA Missing!\n"); return; } }
//读响应寄存器 cmd->resp[0] = readl(host->base + S3C2410_SDIRSP0); cmd->resp[1] = readl(host->base + S3C2410_SDIRSP1); cmd->resp[2] = readl(host->base + S3C2410_SDIRSP2); cmd->resp[3] = readl(host->base + S3C2410_SDIRSP3);
writel(host->prescaler, host->base + S3C2410_SDIPRE);
if (cmd->error) debug_as_failure = 1;
if (cmd->data && cmd->data->error) debug_as_failure = 1;
dbg_dumpcmd(host, cmd, debug_as_failure);
//清空命令参数、数据配置、命令配置、中断屏蔽寄存器 writel(0, host->base + S3C2410_SDICMDARG); writel(S3C2410_SDIDCON_STOP, host->base + S3C2410_SDIDCON); writel(0, host->base + S3C2410_SDICMDCON); writel(0, host->base + host->sdiimsk);
if (cmd->data && cmd->error) cmd->data->error = cmd->error;
//有数据请求,有传输停止命令,数据传输命令已发送 if (cmd->data && cmd->data->stop && (!host->cmd_is_stop)) { host->cmd_is_stop = 1; s3cmci_send_request(host->mmc);//传输停止命令
return; }
if (!mrq->data) goto request_done;
//计算已传输的数据量 if (mrq->data->error == 0) { mrq->data->bytes_xfered = (mrq->data->blocks * mrq->data->blksz); } else { mrq->data->bytes_xfered = 0; }
if (mrq->data->error != 0) { if (host->dodma) s3c2410_dma_ctrl(host->dma, S3C2410_DMAOP_FLUSH);
//清除和复位FIFO状态寄存器 writel(S3C2440_SDIFSTA_FIFORESET | S3C2440_SDIFSTA_FIFOFAIL, host->base + S3C2410_SDIFSTA); }
//完成请求 request_done: host->complete_what = COMPLETION_NONE; host->mrq = NULL; mmc_request_done(host->mmc, mrq); }
|