本文共 35669 字,大约阅读时间需要 118 分钟。
早在SD控制器之初始化篇中,就对SD卡控制器有了一个基本的介绍。其实SD控制器层更过的意义是为core层提供一种操作SD卡硬件的一种方法,当然不同的控制器对硬件控制的方法不尽相同,但是他们最终都能像core层提交一个统一的封装有操作方法的数据结构,那便是即将闪亮登场的struct mmc_host_ops....
依旧是以s3c2440为例,对应的host文件为s3cmci.c。接下来就来揭开与之对应的struct mmc_host_ops结构的神秘面纱....
[host/s3cmci.c]
1355 static struct mmc_host_ops s3cmci_ops = {
1356 .request = s3cmci_request,
1357 .set_ios = s3cmci_set_ios,
1358 .get_ro = s3cmci_get_ro,
1359 .get_cd = s3cmci_card_present,
1360 .enable_sdio_irq = s3cmci_enable_sdio_irq,
1361 };
在讲述每个方法具体的实现之前,先来对struct mmc_host_ops结构中的各个成员有个简单的认识。
request方法:无论是前面所说的单纯的命令传输,还是带有数据的传输过程,无一例外最终都是调用request来实现的,那么如您所想,他也将成为这个舞台万众瞩目的焦点。
set_ios方法:用于设置SD卡控制器,前面我们所见到的设置控制器时钟,数据线宽度等等一系列操作最终就是通过他来实现的。
get_ro方法:获取卡的写保护状态,前面所过,SD卡初始化完成以后,我们进行的一个最后的工作便是检测卡的写保护状态,其实就是调用get_ro方法。
get_cd方法:检测卡是否在卡槽之中,它所对应的函数前面已经在初始化中分析过了,这里不再单独列来。
enable_sdio_irq方法:就是使能SDIO卡的中断,这个是对sdio卡而言的,这里将不做重点分析。
有了一个初步的了解之后,接下来的时间就来各个击破了,本着由浅入深的原则我们先来看看s3cmci_get_ro。
从SD卡结构上来说有个写保护的开关,这就使得判断SD卡是否写保护可以从其机械特征上入手,从而特殊设计的SD卡槽为我们提供了方便。在这里采用的方法正是利用了这种特殊设计的SD卡槽带来的优势,因此只需要读取SD卡槽的SD写保护引脚的状态就能判定卡写保护的情况。实现的代码如下:
[host/s3cmci.c]
1298 static int s3cmci_get_ro(struct mmc_host *mmc)
1299 {
1300 struct s3cmci_host *host = mmc_priv(mmc);
1301 struct s3c24xx_mci_pdata *pdata = host->pdata;
1302 int ret;
1303
1304 if (pdata->no_wprotect)
1305 return 0;
1306
1307 ret = s3c2410_gpio_getpin(pdata->gpio_wprotect);
1308
1309 if (pdata->wprotect_invert)
1310 ret = !ret;
1311
1312 return ret;
1313 }
1307行正是获取SD写保护引脚的值,当然由于硬件设计上的不同可能带来状态上的取反,所以这里有个pdata->wprotect_invert标记决定是否应该反相。对于只读来说应该返回1,否则该方法的返回值为0。
根据我们前面所见到的种种设置,这里的ioset可能会相对烦锁一些,具体的代码如下:
[host/s3cmci.c]
1229 static void s3cmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
1230 {
1231 struct s3cmci_host *host = mmc_priv(mmc);
1232 u32 mci_con;
1233
1234 /* Set the power state */
1235
1236 mci_con = readl(host->base + S3C2410_SDICON);
1237
1238 switch (ios->power_mode) {
1239 case MMC_POWER_ON:
1240 case MMC_POWER_UP:
1241 s3c2410_gpio_cfgpin(S3C2410_GPE(5), S3C2410_GPE5_SDCLK);
1242 s3c2410_gpio_cfgpin(S3C2410_GPE(6), S3C2410_GPE6_SDCMD);
1243 s3c2410_gpio_cfgpin(S3C2410_GPE(7), S3C2410_GPE7_SDDAT0);
1244 s3c2410_gpio_cfgpin(S3C2410_GPE(8), S3C2410_GPE8_SDDAT1);
1245 s3c2410_gpio_cfgpin(S3C2410_GPE(9), S3C2410_GPE9_SDDAT2);
1246 s3c2410_gpio_cfgpin(S3C2410_GPE(10), S3C2410_GPE10_SDDAT3);
1247
1248 if (host->pdata->set_power)
1249 host->pdata->set_power(ios->power_mode, ios->vdd);
1250
1251 if (!host->is2440)
1252 mci_con |= S3C2410_SDICON_FIFORESET;
1253
1254 break;
1255
1256 case MMC_POWER_OFF:
1257 default:
1258 gpio_direction_output(S3C2410_GPE(5), 0);
1259
1260 if (host->is2440)
1261 mci_con |= S3C2440_SDICON_SDRESET;
1262
1263 if (host->pdata->set_power)
1264 host->pdata->set_power(ios->power_mode, ios->vdd);
1265
1266 break;
1267 }
1268
1269 s3cmci_set_clk(host, ios);
1270
1271 /* Set CLOCK_ENABLE */
1272 if (ios->clock)
1273 mci_con |= S3C2410_SDICON_CLOCKTYPE;
1274 else
1275 mci_con &= ~S3C2410_SDICON_CLOCKTYPE;
1276
1277 writel(mci_con, host->base + S3C2410_SDICON);
1278
1279 if ((ios->power_mode == MMC_POWER_ON) ||
1280 (ios->power_mode == MMC_POWER_UP)) {
1281 dbg(host, dbg_conf, "running at %lukHz (requested: %ukHz).\n",
1282 host->real_rate/1000, ios->clock/1000);
1283 } else {
1284 dbg(host, dbg_conf, "powered down.\n");
1285 }
1286
1287 host->bus_width = ios->bus_width;
1288 }
1236行对SD卡控制器的设置最直接的莫过于对寄存器S3C2410_SDICON的访问了,为了保证后面不改变其他无关位的值,这里先读取S3C2410_SDICON中的当前值保存。
1238-1267行是SD控制器工作状态的设定,对ioset来说,swith无疑是他最好的朋友,当MMC_POWER_UP时,SD控制器的相应管脚会得到正确的初始化。其他的如fifo也将被正确复位。
1269-1275行就是对sd控制器时钟的设置,最终一切ioset的成功归功于1277行将重新设置的S3C2410_SDICON状态写入寄存器,从此新的控制器状态生效。
都说前世的五百次回眸,才换来今生的一次擦肩而过。我们苦苦等待的s3cmci_request,在历经千百次的磨难之后也终究在我们面前揭开了她神秘的面纱....
[host/s3cmci.c]
1190 static void s3cmci_request(struct mmc_host *mmc, struct mmc_request *mrq)
1191 {
1192 struct s3cmci_host *host = mmc_priv(mmc);
1193
1194 host->status = "mmc request";
1195 host->cmd_is_stop = 0;
1196 host->mrq = mrq;
1197
1198 if (s3cmci_card_present(mmc) == 0) {
1199 dbg(host, dbg_err, "%s: no medium present\n", __func__);
1200 host->mrq->cmd->error = -ENOMEDIUM;
1201 mmc_request_done(mmc, mrq);
1202 } else
1203 s3cmci_send_request(mmc);
1204 }
1198行判断SD卡是否还在卡槽之中,如果已经拔出,那不客气mmc_request_done将帮您结束这个请求。怎么个解决法还是先看看mmc_request_done的代码:
[core/core.c]
75 void mmc_request_done(struct mmc_host *host, struct mmc_request *mrq)
76 {
77 ): %d, retrying...\n",
87 mmc_hostname(host), cmd->opcode, err);
88
89 cmd->retries--;
90 cmd->error = 0;
91 host->ops->request(host, mrq);
92 } else {
93 led_trigger_event(host->led, LED_OFF);
94
95 pr_debug("%s: req done (CMD%u): %d: %08x %08x %08x %08x\n",
96 mmc_hostname(host), cmd->opcode, err,
97 cmd->resp[0], cmd->resp[1],
98 cmd->resp[2], cmd->resp[3]);
99
100 if (mrq->data) {
101 pr_debug("%s: %d bytes transferred: %d\n",
102 mmc_hostname(host),
103 mrq->data->bytes_xfered, mrq->data->error);
104 }
105
106 if (mrq->stop) {
107 pr_debug("%s: (CMD%u): %d: %08x %08x %08x %08x\n",
108 mmc_hostname(host), mrq->stop->opcode,
109 mrq->stop->error,
110 mrq->stop->resp[0], mrq->stop->resp[1],
111 mrq->stop->resp[2], mrq->stop->resp[3]);
112 }
113
114 if (mrq->done)
115 mrq->done(mrq);
116 }
117 }
80-83行如果是SPI传输出现错误,而且还有重试的机会,那么只要SPI不忽略这个命令,那么就还是给他重试的机会,也就到了85-91行继续调用host->ops->request(host, mrq);提交请求,否则既然是SPI忽略了这个命令,无论重试多少次都不会有结果,那么就干脆一不做二不休cmd->retries = 0;
85-91行就是只要设备有重生的机会就还是继续拯救...
92-115行如果传输无误或者重试次数到了,就会执行。其中多半是调试信息。
114-115行许下的承诺就好比欠下的债,前面我们讨论mmc_wait_for_req的时候有这么两句:
197 mrq->done_data = &complete;
198 mrq->done = mmc_wait_done;
然后我们说N年以后的某一天我们会和mmc_wait_done再聚首,这里115行便是调用的mmc_wait_done。内容如下:
[core/core.c]
179 static void mmc_wait_done(struct mmc_request *mrq)
180 {
181 complete(mrq->done_data);
182 }
还记得mmc_wait_for_req中为了你苦苦等待的那个wait_for_completion(&complete),因为等待,所以她进入了睡眠。现在事情做完了,他重新回来调用complete(mrq->done_data)唤醒这个沉睡的内核精灵。说到这好奇的人难免会问,那要是一直出错又该是谁来唤醒他呢?带着疑问我们继续向前....
回到s3cmci_request如果卡还存在的话1203行s3cmci_send_request将真正开始这个请求的处理。
[host/s3cmci.c]
1125 static void s3cmci_send_request(struct mmc_host *mmc)
1126 {
1127 struct s3cmci_host *host = mmc_priv(mmc);
1128 struct mmc_request *mrq = host->mrq;
1129 struct mmc_command *cmd = host->cmd_is_stop ? mrq->stop : mrq->cmd;
1130
1131 host->ccnt++;
1132 prepare_dbgmsg(host, cmd, host->cmd_is_stop);
1133
1134 /* Clear command, data and fifo status registers
1135 Fifo clear only necessary on 2440, but doesn't hurt on 2410
1136 */
1137 writel(0xFFFFFFFF, host->base + S3C2410_SDICMDSTAT);
1138 writel(0xFFFFFFFF, host->base + S3C2410_SDIDSTA);
1139 writel(0xFFFFFFFF, host->base + S3C2410_SDIFSTA);
1140
1141 if (cmd->data) {
1142 int res = s3cmci_setup_data(host, cmd->data);
1143
1144 host->dcnt++;
1145
1146 if (res) {
1147 dbg(host, dbg_err, "setup data error %d\n", res);
1148 cmd->error = res;
1149 cmd->data->error = res;
1150
1151 mmc_request_done(mmc, mrq);
1152 return;
1153 }
1154
1155 if (s3cmci_host_usedma(host))
1156 res = s3cmci_prepare_dma(host, cmd->data);
1157 else
1158 res = s3cmci_prepare_pio(host, cmd->data);
1159
1160 if (res) {
1161 dbg(host, dbg_err, "data prepare error %d\n", res);
1162 cmd->error = res;
1163 cmd->data->error = res;
1164
1165 mmc_request_done(mmc, mrq);
1166 return;
1167 }
1168 }
1169
1170 /* Send command */
1171 s3cmci_send_command(host, cmd);
1172
1173 /* Enable Interrupt */
1174 s3cmci_enable_irq(host, true);
1175 }
1137-1139行全部写入1,是为了清除之前传输的SDI命令状态寄存器、SDI数据状态寄存器以及SDI FIFO状态寄存器。这是在一次新的传输之前所必须有的初始化工作,否则可能出现未知的状态错误。
1141行cmd->data实际上就是mmc_request->data,前面没少对他进行介绍。与之相类似的还有stop->data。这里我们姑且不说带有数据的传输过程,先来看看SD卡命令的实现。也就是1171行 s3cmci_send_command(host, cmd);
[host/s3cmci.c]
939 static void s3cmci_send_command(struct s3cmci_host *host,
940 struct mmc_command *cmd)
941 {
942 u32 ccon, imsk;
943
944 imsk = S3C2410_SDIIMSK_CRCSTATUS | S3C2410_SDIIMSK_CMDTIMEOUT |
945 S3C2410_SDIIMSK_RESPONSEND |S3C2410_SDIIMSK_CMDSENT |
946 S3C2410_SDIIMSK_RESPONSECRC;
947
948 enable_imask(host, imsk);
949
950 if (cmd->data)
951 host->complete_what = COMPLETION_XFERFINISH_RSPFIN;
952 else if (cmd->flags & MMC_RSP_PRESENT)
953 host->complete_what = COMPLETION_RSPFIN;
954 else
955 host->complete_what = COMPLETION_CMDSENT;
956
957 writel(cmd->arg, host->base + S3C2410_SDICMDARG);
958
959 ccon = cmd->opcode & S3C2410_SDICMDCON_INDEX;
960 ccon|=S3C2410_SDICMDCON_SENDERHOST|S3C2410_SDICMDCON_CMDSTART;
961
962 if (cmd->flags & MMC_RSP_PRESENT)
963 ccon |= S3C2410_SDICMDCON_WAITRSP;
964
965 if (cmd->flags & MMC_RSP_136)
966 ccon |= S3C2410_SDICMDCON_LONGRSP;
967
968 writel(ccon, host->base + S3C2410_SDICMDCON);
969 }
944-948行是使能相应的中断,其中包括CRC校验错误、命令超时、收到命令响应等等。具体的中断屏蔽寄存器的内容可以参考S3C2440用户手册。
950-955行实际上指当前的这个命令结束时候应该所处的状态,中断处理函数将实际硬件的完成情况与这个状态相比较,最终得到这个命令执行的结果。而cmd->flags正是前面提交命令之前根据不同命令的实际情况来设置的,比如具有应答数据的命令可能需要设置cmd->flags |= MMC_RSP_PRESENT。然后对应的结束状态也就应该是COMPLETION_RSPFIN收到应答。前面说过host->complete_what是个枚举类型的变量包含了整个命令过程的各个阶段,内容如下:
11 enum s3cmci_waitfor {
12 COMPLETION_NONE,
13 COMPLETION_FINALIZE,
14 COMPLETION_CMDSENT,
15 COMPLETION_RSPFIN,
16 COMPLETION_XFERFINISH,
17 COMPLETION_XFERFINISH_RSPFIN,
18 };
一般的命令可能无应答阶段,我们默认数据传输正确完成以后即认为命令执行完成也就是955行对应的host->complete_what = COMPLETION_CMDSENT;
957行是对命令命令参数寄存器的设置,cmd->arg是一个32bit的整数,这里如实填写即可。
959行之后的内容就是对控制寄存器的设置了,由于控制寄存器比较重要,这里列出他寄存器位的信息如下:
对照上表应该不难分析函数中所设置的每一位的具体含义,这里就不再一一解释了。SDICmdCon[8]的置位使得SD控制器开始发送命令。回到s3cmci_send_request....
1174行s3cmci_enable_irq(host, true);就是使能SDI控制器的中断。然而s3cmci_send_command中间的944行设置imr|=S3C2410_SDIIMSK_CMDSENT,命中注定命令发出以后产生一个相应的中断,接下来就进入probe阶段所注册的那个SDI中断request_irq(host->irq, s3cmci_irq, 0, DRIVER_NAME, host)。
[host/s3cmci.c]
550 static irqreturn_t s3cmci_irq(int irq, void *dev_id)
551 {
552 struct s3cmci_host *host = dev_id;
553 struct mmc_command *cmd;
554 u32 mci_csta, mci_dsta, mci_fsta, mci_dcnt, mci_imsk;
555 u32 mci_cclear = 0, mci_dclear;
556 unsigned long iflags;
557
558 mci_dsta = readl(host->base + S3C2410_SDIDSTA);
559 mci_imsk = readl(host->base + host->sdiimsk);
560
561 if (mci_dsta & S3C2410_SDIDSTA_SDIOIRQDETECT) {
562 if (mci_imsk & S3C2410_SDIIMSK_SDIOIRQ) {
563 mci_dclear = S3C2410_SDIDSTA_SDIOIRQDETECT;
564 writel(mci_dclear, host->base + S3C2410_SDIDSTA);
565
566 mmc_signal_sdio_irq(host->mmc);
567 return IRQ_HANDLED;
568 }
569 }
570
571 spin_lock_irqsave(&host->complete_lock, iflags);
572
573 mci_csta = readl(host->base + S3C2410_SDICMDSTAT);
574 mci_dcnt = readl(host->base + S3C2410_SDIDCNT);
575 mci_fsta = readl(host->base + S3C2410_SDIFSTA);
576 mci_dclear = 0;
577
578 if ((host->complete_what == COMPLETION_NONE) ||
579 (host->complete_what == COMPLETION_FINALIZE)) {
580 host->status ="nothing to complete";
581 clear_imask(host);
582 goto irq_out;
583 }
584
585 if (!host->mrq) {
586 host->status = "no active mrq";
587 clear_imask(host);
588 goto irq_out;
589 }
590
591 cmd = host->cmd_is_stop ? host->mrq->stop : host->mrq->cmd;
592
593 if (!cmd) {
594 host->status = "no active cmd";
595 clear_imask(host);
596 goto irq_out;
597 }
598
599 if (!s3cmci_host_usedma(host)) {
600 if ((host->pio_active == XFER_WRITE) &&
601 (mci_fsta & S3C2410_SDIFSTA_TFDET)) {
602
603 disable_imask(host, S3C2410_SDIIMSK_TXFIFOHALF);
604 tasklet_schedule(&host->pio_tasklet);
605 host->status = "pio tx";
606 }
607
608 if ((host->pio_active == XFER_READ) &&
609 (mci_fsta & S3C2410_SDIFSTA_RFDET)) {
610
611 disable_imask(host,
612 S3C2410_SDIIMSK_RXFIFOHALF |
613 S3C2410_SDIIMSK_RXFIFOLAST);
614
615 tasklet_schedule(&host->pio_tasklet);
616 host->status = "pio rx";
617 }
618 }
619
620 if (mci_csta & S3C2410_SDICMDSTAT_CMDTIMEOUT) {
621 dbg(host, dbg_err, "CMDSTAT: error CMDTIMEOUT\n");
622 cmd->error = -ETIMEDOUT;
623 host->status = "error: command timeout";
624 goto fail_transfer;
625 }
626
627 if (mci_csta & S3C2410_SDICMDSTAT_CMDSENT) {
628 if (host->complete_what == COMPLETION_CMDSENT) {
629 host->status ="ok: command sent";
630 goto close_transfer;
631 }
632
633 mci_cclear |= S3C2410_SDICMDSTAT_CMDSENT;
634 }
635
636 if (mci_csta & S3C2410_SDICMDSTAT_CRCFAIL) {
637 if (cmd->flags & MMC_RSP_CRC) {
638 if (host->mrq->cmd->flags & MMC_RSP_136) {
639 dbg(host, dbg_irq,
640 "fixup: ignore CRC fail with long rsp\n");
641 } else {
642 /* note, we used to fail the transfer
643 * here, but it seems that this is just
644 * the hardware getting it wrong.
645 *
646 * cmd->error = -EILSEQ;
647 * host->status = "error: bad command crc";
648 * goto fail_transfer;
649 */
650 }
651 }
652
653 mci_cclear |= S3C2410_SDICMDSTAT_CRCFAIL;
654 }
655
656 if (mci_csta & S3C2410_SDICMDSTAT_RSPFIN) {
657 if (host->complete_what == COMPLETION_RSPFIN) {
658 host->status = "ok: command response received";
659 goto close_transfer;
660 }
661
662 if (host->complete_what == COMPLETION_XFERFINISH_RSPFIN)
663 host->complete_what = COMPLETION_XFERFINISH;
664
665 mci_cclear |= S3C2410_SDICMDSTAT_RSPFIN;
666 }
667
668 /* errors handled after this point are only relevant
669 when a data transfer is in progress */
670
671 if (!cmd->data)
672 goto clear_status_bits;
673
674 /* Check for FIFO failure */
675 if (host->is2440) {
676 if (mci_fsta & S3C2440_SDIFSTA_FIFOFAIL) {
677 dbg(host, dbg_err, "FIFO failure\n");
678 host->mrq->data->error = -EILSEQ;
679 host->status = "error: 2440 fifo failure";
680 goto fail_transfer;
681 }
682 } else {
683 if (mci_dsta & S3C2410_SDIDSTA_FIFOFAIL) {
684 dbg(host, dbg_err, "FIFO failure\n");
685 cmd->data->error = -EILSEQ;
686 host->status = "error: fifo failure";
687 goto fail_transfer;
688 }
689 }
690
691 if (mci_dsta & S3C2410_SDIDSTA_RXCRCFAIL) {
692 dbg(host, dbg_err, "bad data crc (outgoing)\n");
693 cmd->data->error = -EILSEQ;
694 host->status = "error: bad data crc (outgoing)";
695 goto fail_transfer;
696 }
697
698 if (mci_dsta & S3C2410_SDIDSTA_CRCFAIL) {
699 dbg(host, dbg_err, "bad data crc (incoming)\n");
700 cmd->data->error = -EILSEQ;
701 host->status = "error: bad data crc (incoming)";
702 goto fail_transfer;
703 }
704
705 if (mci_dsta & S3C2410_SDIDSTA_DATATIMEOUT) {
706 dbg(host, dbg_err, "data timeout\n");
707 cmd->data->error = -ETIMEDOUT;
708 host->status = "error: data timeout";
709 goto fail_transfer;
710 }
711
712 if (mci_dsta & S3C2410_SDIDSTA_XFERFINISH) {
713 if (host->complete_what == COMPLETION_XFERFINISH) {
714 host->status = "ok: data transfer completed";
715 goto close_transfer;
716 }
717
718 if (host->complete_what == COMPLETION_XFERFINISH_RSPFIN)
719 host->complete_what = COMPLETION_RSPFIN;
720
721 mci_dclear |= S3C2410_SDIDSTA_XFERFINISH;
722 }
723
724 clear_status_bits:
725 writel(mci_cclear, host->base + S3C2410_SDICMDSTAT);
726 writel(mci_dclear, host->base + S3C2410_SDIDSTA);
727
728 goto irq_out;
729
730 fail_transfer:
731 host->pio_active = XFER_NONE;
732
733 close_transfer:
734 host->complete_what = COMPLETION_FINALIZE;
735
736 clear_imask(host);
737 tasklet_schedule(&host->pio_tasklet);
738
739 goto irq_out;
740
741 irq_out:
742 dbg(host, dbg_irq,
743 "csta:0x%08x dsta:0x%08x fsta:0x%08x dcnt:0x%08x status:%s.\n",
744 mci_csta, mci_dsta, mci_fsta, mci_dcnt, host->status);
745
746 spin_unlock_irqrestore(&host->complete_lock, iflags);
747 return IRQ_HANDLED;
748
749 }
558-570行是判断SDIO所触发的中断,与我们说说的无关。飘过....
573-576行分别读取命令状态、尚未完成传输的数据大小以及FIFO的状态的值。
578-583行就是之前所分析的host->complete_what,如果设备无欲无求host->complete_what == COMPLETION_NONE,即使连最基本的命令发送也不要求完成的话,那就没什么意义了,直接清除IMASK,返回。
[host/s3cmci.c]
226 static inline void clear_imask(struct s3cmci_host *host)
227 {
228 u32 mask = readl(host->base + host->sdiimsk);
229
230 /* preserve the SDIO IRQ mask state */
231 mask &= S3C2410_SDIIMSK_SDIOIRQ;
232 writel(mask, host->base + host->sdiimsk);
233 }
上面的代码只保留了SDIO IRQ状态,其他的中断都是被屏蔽了的。由此足见其对SDIO设备的偏心程度。
585-589行尽然玩丢了host->mrq,无论是命令还是数据请求,我们都是递交了struct mmc_request结构的,所以驱动很气愤,直接返回。
591行前面我们看到struct mmc_request中包含了两种类型的struct mmc_cmd一个是所谓的cmd另外一个就是stop了,当然选择哪一个也不是他自己说来算了,当然有主机的host->cmd_is_stop来决定了。
599-618行是PIO模式下数据传输的,我们姑且先放着,等说完CMD回头再看。
620-625行命令超时以后就会跳转到fail_transfer,至于fail_transfer又干了些啥好事我们走到那里了再说,继续前进...
627-631行命令发送成功以后所产生的中断,如果host->complete_what也正好只要求传输成功即COMPLETION_CMDSENT,那正好完成工作,goto close_transfer。
636-654行是CRC错误,忽略。
656-660行命令相应接收成功,那么依旧goto close_transfer。
662-665行至今尚未发现一个所谓的COMPLETION_XFERFINISH_RSPFIN最多也就数据传输成功那么修改一下这个脑残host->complete_what = COMPLETION_XFERFINISH;
671-672行如果没有数据传输,那么接下来就可以进行状态清理工作了。
675-722行是检查FIFO信息的,回头说到PIO传输的时候在来分析它。
725-726行意图很明确,显然是毁尸灭迹,清除状态。
最后可以看到无论是先前的fail_transfer:还是后来的close_transfer,最总都会去调用737行的tasklet_schedule(&host->pio_tasklet),是什么赋予这个函数如此强大的魅力,且听下回分解...
是时候该看点实际的数据传输了,前面说过s3cmci_send_request中的if (cmd->data)是区分命令是否有数据阶段的关键标志。如果有数据传输的,那么就到了1142行s3cmci_setup_data。
[host/s3cmci.c]
971 static int s3cmci_setup_data(struct s3cmci_host *host, struct mmc_data *data)
972 {
973 u32 dcon, imsk, stoptries = 3;
974
975 /* write DCON register */
976
977 if (!data) {
978 writel(0, host->base + S3C2410_SDIDCON);
979 return 0;
980 }
981
982 if ((data->blksz & 3) != 0) {
983 /* We cannot deal with unaligned blocks with more than
984 * one block being transfered. */
985
986 if (data->blocks > 1) {
987 pr_warning("%s:can'tdonon-wordsizedblock transfers (blksz %d)\n", __func__, data->blksz);
988 return -EINVAL;
989 }
990 }
991
992 while (readl(host->base + S3C2410_SDIDSTA) &
993 (S3C2410_SDIDSTA_TXDATAON | S3C2410_SDIDSTA_RXDATAON)) {
994
995 dbg(host, dbg_err,
996 "mci_setup_data() transfer stillin progress.\n");
997
998 writel(S3C2410_SDIDCON_STOP, host->base + S3C2410_SDIDCON);
999 s3cmci_reset(host);
1000
1001 if ((stoptries--) == 0) {
1002 dbg_dumpregs(host, "DRF");
1003 return -EINVAL;
1004 }
1005 }
1006
1007 dcon = data->blocks & S3C2410_SDIDCON_BLKNUM_MASK;
1008
1009 if (s3cmci_host_usedma(host))
1010 dcon |= S3C2410_SDIDCON_DMAEN;
1011
1012 if (host->bus_width == MMC_BUS_WIDTH_4)
1013 dcon |= S3C2410_SDIDCON_WIDEBUS;
1014
1015 if (!(data->flags & MMC_DATA_STREAM))
1016 dcon |= S3C2410_SDIDCON_BLOCKMODE;
1017
1018 if (data->flags & MMC_DATA_WRITE) {
1019 dcon |= S3C2410_SDIDCON_TXAFTERRESP;
1020 dcon |= S3C2410_SDIDCON_XFER_TXSTART;
1021 }
1022
1023 if (data->flags & MMC_DATA_READ) {
1024 dcon |= S3C2410_SDIDCON_RXAFTERCMD;
1025 dcon |= S3C2410_SDIDCON_XFER_RXSTART;
1026 }
1027
1028 if (host->is2440) {
1029 dcon |= S3C2440_SDIDCON_DS_WORD;
1030 dcon |= S3C2440_SDIDCON_DATSTART;
1031 }
1032
1033 writel(dcon, host->base + S3C2410_SDIDCON);
1034
1035 /* write BSIZE register */
1036
1037 writel(data->blksz, host->base + S3C2410_SDIBSIZE);
1038
1039 /* add to IMASK register */
1040 imsk = S3C2410_SDIIMSK_FIFOFAIL | S3C2410_SDIIMSK_DATACRC |
1041 S3C2410_SDIIMSK_DATATIMEOUT | S3C2410_SDIIMSK_DATAFINISH;
1042
1043 enable_imask(host, imsk);
1044
1045 /* write TIMER register */
1046
1047 if (host->is2440) {
1048 writel(0x007FFFFF, host->base + S3C2410_SDITIMER);
1049 } else {
1050 writel(0x0000FFFF, host->base + S3C2410_SDITIMER);
1051
1052 /* FIX: set slow clock to prevent timeouts on read */
1053 if (data->flags & MMC_DATA_READ)
1054 writel(0xFF, host->base + S3C2410_SDIPRE);
1055 }
1056
1057 return 0;
1058 }
977-980行如果data不存在,接下来就无事可做了。
982-991行块大小是4字节对齐的,如果data->blksz不满足,那么返回错误。
992-1005行读取数据状态寄存器,如果正在发送或接收数据,则s3cmci_reset(host);复位SD控制器。
[host/s3cmci.c]
1290 static void s3cmci_reset(struct s3cmci_host *host)
1291 {
1292 u32 con = readl(host->base + S3C2410_SDICON);
1293
1294 con |= S3C2440_SDICON_SDRESET;
1295 writel(con, host->base + S3C2410_SDICON);
1296 }
1007-1033行根据数据特征、主机总线宽度等信息设置数据控制寄存器。
1037行设置SD控制器块大小寄存器。这是上层设置下来的值,一般为512。
1040-1043行设置中断屏蔽寄存器,使能数据传输完成中断、超时等。
1047-1054行是关于读写超时的处理。接着返回到s3cmci_send_request....
如果不出什么问题,应该就到了1155行。
s3cmci_prepare_dma(host, cmd->data);是DMA传输的处理,
s3cmci_prepare_pio(host, cmd->data);是PIO方式的处理,下面我们先来关注PIO方式的数据传输。
[host/s3cmci.c]
1062 static int s3cmci_prepare_pio(struct s3cmci_host *host, struct mmc_data *data)
1063 {
1064 int rw = (data->flags & MMC_DATA_WRITE) ? 1 : 0;
1065
1066 BUG_ON((data->flags & BOTH_DIR) == BOTH_DIR);
1067
1068 host->pio_sgptr = 0;
1069 host->pio_bytes = 0;
1070 host->pio_count = 0;
1071 host->pio_active = rw ? XFER_WRITE : XFER_READ;
1072
1073 if (rw) {
1074 do_pio_write(host);
1075 enable_imask(host, S3C2410_SDIIMSK_TXFIFOHALF);
1076 } else {
1077 enable_imask(host, S3C2410_SDIIMSK_RXFIFOHALF
1078 | S3C2410_SDIIMSK_RXFIFOLAST);
1079 }
1080
1081 return 0;
1082 }
Ø PIO写数据
这个函数分两部分来看,首先对于写来说会调用1074行do_pio_write(host);来做写入的前期工作,如果是读SD卡就只需要使能接收FIFO相关的中断即可。那么我们先对写的情况做简单的分析:
[host/s3cmci.c]
443 static void do_pio_write(struct s3cmci_host *host)
444 {
445 void __iomem *to_ptr;
446 int res;
447 u32 fifo;
448 u32 *ptr;
449
450 to_ptr = host->base + host->sdidata;
451
452 while ((fifo = fifo_free(host)) > 3) {
453 if (!host->pio_bytes) {
454 res = get_data_buffer(host, &host->pio_bytes,
455 &host->pio_ptr);
456 if (res) {
457 dbg(host, dbg_pio,
458 "pio_write(): complete (no more data).\n");
459 host->pio_active = XFER_NONE;
460
461 return;
462 }
463
464 dbg(host, dbg_pio,
465 "pio_write(): new source: [%i]@[%p]\n",
466 host->pio_bytes, host->pio_ptr);
467
468 }
469
470 /* If we have reached the end of the block, we have to
471 * write exactly the remaining number of bytes. If we
472 * in the middle of the block, we have to write full
473 * words, so round down to an even multiple of 4. */
474 if (fifo >= host->pio_bytes)
475 fifo = host->pio_bytes;
476 else
477 fifo -= fifo & 3;
478
479 host->pio_bytes -= fifo;
480 host->pio_count += fifo;
481
482 fifo = (fifo + 3) >> 2;
483 ptr = host->pio_ptr;
484 while (fifo--)
485 writel(*ptr++, to_ptr);
486 host->pio_ptr = ptr;
487 }
488
489 enable_imask(host, S3C2410_SDIIMSK_TXFIFOHALF);
490 }
452行是对发送FIFO剩余空间的判断,方法比较简单直接读取FIFO状态寄存器即可获得。
[host/s3cmci.c]
294 static inline u32 fifo_free(struct s3cmci_host *host)
295 {
296 u32 fifostat = readl(host->base + S3C2410_SDIFSTA);
297
298 fifostat &= S3C2410_SDIFSTA_COUNTMASK;
299 return 63 - fifostat;
300 }
当发送FIFO的容量大于三个字节时程序将向FIFO中写入数据,此时while循环得以执行。
454取出要发送的数据地址以及数据长度。get_data_buffer的内容如下:
[host/s3cmci.c]
257 static inline int get_data_buffer(struct s3cmci_host *host,
258 u32 *bytes, u32 **pointer)
259 {
260 struct scatterlist *sg;
261
262 if (host->pio_active == XFER_NONE)
263 return -EINVAL;
264
265 if ((!host->mrq) || (!host->mrq->data))
266 return -EINVAL;
267
268 if (host->pio_sgptr >= host->mrq->data->sg_len) {
269 dbg(host, dbg_debug, "no more buffers (%i/%i)\n",
270 host->pio_sgptr, host->mrq->data->sg_len);
271 return -EBUSY;
272 }
273 sg = &host->mrq->data->sg[host->pio_sgptr];
274
275 *bytes = sg->length;
276 *pointer = sg_virt(sg);
277
278 host->pio_sgptr++;
279
280 dbg(host, dbg_sg, "new buffer (%i/%i)\n",
281 host->pio_sgptr, host->mrq->data->sg_len);
282
283 return 0;
284 }
273行很明显是对每个散列表单独操作的,275行对应当前散列项的长度,276行sg_virt用于获取其所对应的内核虚拟地址,最后host->pio_sgptr++移动指针到下一项。
回到do_pio_write,474-477行就是取出剩余的空间,如果剩余空间大于要发送的长度就直接全部发送,否则留三个字节空闲。
482行4个字节对齐的,也就是说后面实际上传输的字节数应该是(((fifo + 3) >> 2)<<2),那么这个值与host->pio_bytes -= fifo;中的fifo相比是很有可能不相等的。换句话说实际传输的字节说与记录的大小不等,看上去是个bug,其实前面我们说过,所有走到这一步的数据长度都已经是4字节对齐了,所以这里这样处理就不会有问题了。
从s3cmci_prepare_pio返回以后就到了1171行s3cmci_send_command(host, cmd);这里发送的将是写扇区命令,从而开启了真正的PIO数据传输。
对于PIO方式来说,一旦命令写入,数据传输立即就开始了。如果发送FIFO中的数据低于FIFO空闲中断的阈值,将触发控制器产生中断,从而就满足了s3cmci_irq中断处理函数的599-606行的条件。
[s3cmci_irq]
599 if (!s3cmci_host_usedma(host)) {
600 if ((host->pio_active == XFER_WRITE) &&
601 (mci_fsta & S3C2410_SDIFSTA_TFDET)) {
602
603 disable_imask(host, S3C2410_SDIIMSK_TXFIFOHALF);
604 tasklet_schedule(&host->pio_tasklet);
605 host->status = "pio tx";
606 }
于是tasklet_schedule(&host->pio_tasklet)被调用,同时724-728行将帮助清除中断标志。
724 clear_status_bits:
725 writel(mci_cclear, host->base + S3C2410_SDICMDSTAT);
726 writel(mci_dclear, host->base + S3C2410_SDIDSTA);
727
728 goto irq_out;
又见了tasklet_schedule(&host->pio_tasklet),他不是什么天外飞仙,一切因果只因s3cmci.c中的1588 tasklet_init(&host->pio_tasklet, pio_tasklet, (unsigned long) host);
从中断函数返回以后,目光投向pio_tasklet,对应的内容如下:
[host/s3cmci.c]
492 static void pio_tasklet(unsigned long data)
493 {
494 struct s3cmci_host *host = (struct s3cmci_host *) data;
495
496 s3cmci_disable_irq(host, true);
497 udelay(50);
498
499 if (host->pio_active == XFER_WRITE)
500 do_pio_write(host);
501
502 if (host->pio_active == XFER_READ)
503 do_pio_read(host);
504
505 if (host->complete_what == COMPLETION_FINALIZE) {
506 clear_imask(host);
507 if (host->pio_active != XFER_NONE) {
508 dbg(host, dbg_err, "unfinished %s "
509 "- pio_count:[%u] pio_bytes:[%u]\n",
510 (host->pio_active == XFER_READ) ? "read" : "write",
511 host->pio_count, host->pio_bytes);
512
513 if (host->mrq->data)
514 host->mrq->data->error = -EINVAL;
515 }
516
517 s3cmci_enable_irq(host, false);
518 finalize_request(host);
519 } else
520 s3cmci_enable_irq(host, true);
521 }
函数格式比较工整,如果host->pio_active继续保持XFER_WRITE的话,就会再次调用do_pio_write(host)来继续向发送FIFO中填入数据。
505行是传输完成以后设置的,传输完成以后会调用finalize_request(host);结束这次请求。
[host/s3cmci.c]
822 static void finalize_request(struct s3cmci_host *host)
823 {
824 struct mmc_request *mrq = host->mrq;
825 struct mmc_command *cmd = host->cmd_is_stop ? mrq->stop : mrq->cmd;
826 int debug_as_failure = 0;
827
828 if (host->complete_what != COMPLETION_FINALIZE)
829 return;
830
831 if (!mrq)
832 return;
833
834 if (cmd->data && (cmd->error == 0) &&
835 (cmd->data->error == 0)) {
836 if (s3cmci_host_usedma(host) && (!host->dma_complete)) {
837 dbg(host, dbg_dma, "DMA Missing (%d)!\n",
838 host->dma_complete);
839 return;
840 }
841 }
842
843 /* Read response from controller. */
844 cmd->resp[0] = readl(host->base + S3C2410_SDIRSP0);
845 cmd->resp[1] = readl(host->base + S3C2410_SDIRSP1);
846 cmd->resp[2] = readl(host->base + S3C2410_SDIRSP2);
847 cmd->resp[3] = readl(host->base + S3C2410_SDIRSP3);
848
849 writel(host->prescaler, host->base + S3C2410_SDIPRE);
850
851 if (cmd->error)
852 debug_as_failure = 1;
853
854 if (cmd->data && cmd->data->error)
855 debug_as_failure = 1;
856
857 dbg_dumpcmd(host, cmd, debug_as_failure);
858
859 /* Cleanup controller */
860 writel(0, host->base + S3C2410_SDICMDARG);
861 writel(S3C2410_SDIDCON_STOP, host->base + S3C2410_SDIDCON);
862 writel(0, host->base + S3C2410_SDICMDCON);
863 clear_imask(host);
864
865 if (cmd->data && cmd->error)
866 cmd->data->error = cmd->error;
867
868 if (cmd->data && cmd->data->stop && (!host->cmd_is_stop)) {
869 host->cmd_is_stop = 1;
870 s3cmci_send_request(host->mmc);
871 return;
872 }
873
874 /* If we have no data transfer we are finished here */
875 if (!mrq->data)
876 goto request_done;
877
878 /* Calulate the amout of bytes transfer if there was no error */
879 if (mrq->data->error == 0) {
880 mrq->data->bytes_xfered =
881 (mrq->data->blocks * mrq->data->blksz);
882 } else {
883 mrq->data->bytes_xfered = 0;
884 }
885
886 /* If we had an error while transfering data we flush the
887 * DMA channel and the fifo to clear out any garbage. */
888 if (mrq->data->error != 0) {
889 if (s3cmci_host_usedma(host))
890 s3c2410_dma_ctrl(host->dma, S3C2410_DMAOP_FLUSH);
891
892 if (host->is2440) {
893 /* Clear failure register and reset fifo. */
894 writel(S3C2440_SDIFSTA_FIFORESET |
895 S3C2440_SDIFSTA_FIFOFAIL,
896 host->base + S3C2410_SDIFSTA);
897 } else {
898 u32 mci_con;
899
900 /* reset fifo */
901 mci_con = readl(host->base + S3C2410_SDICON);
902 mci_con |= S3C2410_SDICON_FIFORESET;
903
904 writel(mci_con, host->base + S3C2410_SDICON);
905 }
906 }
907
908 request_done:
909 host->complete_what = COMPLETION_NONE;
910 host->mrq = NULL;
911
912 s3cmci_check_sdio_irq(host);
913 mmc_request_done(host->mmc, mrq);
914 }
843-847行是发送读写命令以后SD卡回复的信息,这个信息在block层中将作为请求完成情况的一个依据。
860-863行是完成任务后对控制器做清理工作。
868-872行这个是对于多扇区的读写还应该有一个结束命令,以结束此次操作。在mmc_blk_issue_rq中就已经对这个stop命令设置好了,如下:
[card/block.c]
259 brq.stop.opcode = MMC_STOP_TRANSMISSION;
260 brq.stop.arg = 0;
261 brq.stop.flags = MMC_RSP_SPI_R1B | MMC_RSP_R1B | MMC_CMD_AC;
。。。。。
284 if (!mmc_host_is_spi(card->host)
285 || rq_data_dir(req) == READ)
286 brq.mrq.stop = &brq.stop;
287 readcmd = MMC_READ_MULTIPLE_BLOCK;
288 writecmd = MMC_WRITE_MULTIPLE_BLOCK;
289 } else {
290 brq.mrq.stop = NULL;
291 readcmd = MMC_READ_SINGLE_BLOCK;
292 writecmd = MMC_WRITE_BLOCK;
293 }
259行MMC_STOP_TRANSMISSION就正好是CMD12命令,最终结束命令也就是由s3cmci_send_request发出了。
879-884行如果传输没有发生错误,传输的字节数将被正确记载,否则传输数据长度将为0,暗示此次数据传输失败。
888-904行传输有错误,便要重新刷新DMA控制器或者是复位FIFO。
909-901行host的工作完成以后host内部相应的对象应该复位,以便重新接受请求。
913行mmc_request_done前面分析过,如果出错可能会引发重试,否则调用complete(mrq->done_data);通知等待该请求的进程。
好了,以上说分析的就是PIO写数据部分的情况了,接下来看下PIO读是如何工作的。。。
Ø PIO读数据
依然回到s3cmci_send_request中,还是看s3cmci_prepare_pio的内容。
前面的分析我们知道对于PIO的写数据来说必须先填充其FIFO,否则可能写命令发出以后,主机无法发送数据导致命令失败。然而读数据却只能有中断引发,因此当主机发送读命令之前s3cmci_prepare_pio必须设置好相应的中断使能,enable_imask(host,
S3C2410_SDIIMSK_RXFIFOHALF|S3C2410_SDIIMSK_RXFIFOLAST);当接收FIFO有较多数据时将以中断形式通知主机。同样s3cmci_send_request中的s3cmci_send_command(host, cmd);发送读命令开启了读SD卡数据的新时代。
一旦FIFO中的数据达到接收阈值将触发中断,接下来就进入了s3cmci_irq的608-609行。
608 if ((host->pio_active == XFER_READ) &&
609 (mci_fsta & S3C2410_SDIFSTA_RFDET)) {
610
611 disable_imask(host,
612 S3C2410_SDIIMSK_RXFIFOHALF |
613 S3C2410_SDIIMSK_RXFIFOLAST);
614
615 tasklet_schedule(&host->pio_tasklet);
616 host->status = "pio rx";
617 }
618 }
与写SD相同,读SD卡也将调用tasklet_schedule,然后进入pio_tasklet的502-503行。do_pio_read(host);将读取fifo中的数据。
[host/s3cmci.c]
360 static void do_pio_read(struct s3cmci_host *host)
361 {
362 int res;
363 u32 fifo;
364 u32 *ptr;
365 u32 fifo_words;
366 void __iomem *from_ptr;
367
368 /* write real prescaler to host, it might be set slow to fix */
369 writel(host->prescaler, host->base + S3C2410_SDIPRE);
370
371 from_ptr = host->base + host->sdidata;
372
373 while ((fifo = fifo_count(host))) {
374 if (!host->pio_bytes) {
375 res = get_data_buffer(host, &host->pio_bytes,
376 &host->pio_ptr);
377 if (res) {
378 host->pio_active = XFER_NONE;
379 host->complete_what = COMPLETION_FINALIZE;
380
381 dbg(host, dbg_pio, "pio_read(): "
382 "complete (no more data).\n");
383 return;
384 }
385
386 dbg(host, dbg_pio,
387 "pio_read(): new target: [%i]@[%p]\n",
388 host->pio_bytes, host->pio_ptr);
389 }
390
391 dbg(host, dbg_pio,
392 "pio_read(): fifo:[%02i] buffer:[%03i] dcnt:[%08X]\n",
393 fifo, host->pio_bytes,
394 readl(host->base + S3C2410_SDIDCNT));
395
396 /* If we have reached the end of the block, we can
397 * read a word and get 1 to 3 bytes. If we in the
398 * middle of the block, we have to read full words,
399 * otherwise we will write garbage, so round down to
400 * an even multiple of 4. */
401 if (fifo >= host->pio_bytes)
402 fifo = host->pio_bytes;
403 else
404 fifo -= fifo & 3;
405
406 host->pio_bytes -= fifo;
407 host->pio_count += fifo;
408
409 fifo_words = fifo >> 2;
410 ptr = host->pio_ptr;
411 while (fifo_words--)
412 *ptr++ = readl(from_ptr);
413 host->pio_ptr = ptr;
414
415 if (fifo & 3) {
416 u32 n = fifo & 3;
417 u32 data = readl(from_ptr);
418 u8 *p = (u8 *)host->pio_ptr;
419
420 while (n--) {
421 *p++ = data;
422 data >>= 8;
423 }
424 }
425 }
426
427 if (!host->pio_bytes) {
428 res = get_data_buffer(host, &host->pio_bytes, &host->pio_ptr);
429 if (res) {
430 dbg(host, dbg_pio,
431 "pio_read(): complete (no more buffers).\n");
432 host->pio_active = XFER_NONE;
433 host->complete_what = COMPLETION_FINALIZE;
434
435 return;
436 }
437 }
438
439 enable_imask(host,
440 S3C2410_SDIIMSK_RXFIFOHALF| S3C2410_SDIIMSK_RXFIFOLAST);
441 }
373行读取FIFO中数据的长度。
[host/s3cmci.c]
286 static inline u32 fifo_count(struct s3cmci_host *host)
287 {
288 u32 fifostat = readl(host->base + S3C2410_SDIFSTA);
289
290 fifostat &= S3C2410_SDIFSTA_COUNTMASK;
291 return fifostat;
292 }
375-376行和写操作中的作用是相同的,获取scatterlist表项对应的数据长度及内核虚拟地址。
401-425行整个过程与PIO写的过程是完全相反的,代码比较简单就不再分析了。其他的内容就和写过程是一样的了。
Ø DMA传输
最后还有关于DMA方式下的代码,其中只有s3cmci_prepare_dma和中断处理不一致。对于DMA来说内核为其维护了一个回调函数。这里我们只是简单分析一下,就不深入到S3C2440 DMA的管理机制里面去了。首先还是来看s3cmci_prepare_dma。
[host/s3cmci.c]
1018 static int s3cmci_prepare_dma(struct s3cmci_host *host, struct mmc_data *data)
1019 {
1020 int dma_len, i;
1021 int rw = data->flags & MMC_DATA_WRITE;
1022
1023 BUG_ON((data->flags & BOTH_DIR) == BOTH_DIR);
1024
1025 s3cmci_dma_setup(host, rw ? S3C2410_DMASRC_MEM : S3C2410_DMASRC_HW);
1026 s3c2410_dma_ctrl(host->dma, S3C2410_DMAOP_FLUSH);
1027
1028 dma_len = dma_map_sg(mmc_dev(host->mmc), data->sg, data->sg_len,
1029 rw ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
1030
1031 if (dma_len == 0)
1032 return -ENOMEM;
1033
1034 host->dma_complete = 0;
1035 host->dmatogo = dma_len;
1036
1037 for (i = 0; i < dma_len; i++) {
1038 int res;
1039
1040 dbg(host, dbg_dma, "enqueue %i: %08x@%u\n", i,
1041 sg_dma_address(&data->sg[i]),
1042 sg_dma_len(&data->sg[i]));
1043
1044 res = s3c2410_dma_enqueue(host->dma, host,
1045 sg_dma_address(&data->sg[i]),
1046 sg_dma_len(&data->sg[i]));
1047
1048 if (res) {
1049 s3c2410_dma_ctrl(host->dma, S3C2410_DMAOP_FLUSH);
1050 return -EBUSY;
1051 }
1052 }
1053
1054 s3c2410_dma_ctrl(host->dma, S3C2410_DMAOP_START);
1055
1056 return 0;
1057 }
1025行对申请到的DMA通道进行设置。代码如下:
[host/s3cmci.c]
916 static void s3cmci_dma_setup(struct s3cmci_host *host,
917 enum s3c2410_dmasrc source)
918 {
919 static enum s3c2410_dmasrc last_source = -1;
920 static int setup_ok;
921
922 if (last_source == source)
923 return;
924
925 last_source = source;
926
927 s3c2410_dma_devconfig(host->dma, source,
928 host->mem->start + host->sdidata);
929
930 if (!setup_ok) {
931 s3c2410_dma_config(host->dma, 4);
932 s3c2410_dma_set_buffdone_fn(host->dma,
933 s3cmci_dma_done_callback);
934 s3c2410_dma_setflags(host->dma, S3C2410_DMAF_AUTOSTART);
935 setup_ok = 1;
936 }
937 }
927行配置了DMA的源和目的的硬件地址及类型。
931行配置了DMA传输的单元大小为4字节。
932-933行设置DMA通道对应的回调函数s3cmci_dma_done_callback,这个我们后面再说。回到s3cmci_prepare_dma...
1092行刷新DMA通道,清除状态信息。
1094行映射一个发散/汇聚列表的DMA的映射,对于2440来说DMA不支持散列地址,所以1103-1118行对每段映射进行了处理,将其加入到DMA队列当中。
1120行开启了DMA传输通道,一旦SD控制发送命令以后,DMA通道不断地将数据发送到(或接收从)SD控制器的数据寄存器中,最终完成数据的传输。
一旦DMA数据传输完成,回调函数s3cmci_dma_done_callback将开始工作。
[host/s3cmci.c]
766 static void s3cmci_dma_done_callback(struct s3c2410_dma_chan *dma_ch,
767 void *buf_id, int size,
768 enum s3c2410_dma_buffresult result)
769 {
770 struct s3cmci_host *host = buf_id;
771 unsigned long iflags;
772 u32 mci_csta, mci_dsta, mci_fsta, mci_dcnt;
773
774 mci_csta = readl(host->base + S3C2410_SDICMDSTAT);
775 mci_dsta = readl(host->base + S3C2410_SDIDSTA);
776 mci_fsta = readl(host->base + S3C2410_SDIFSTA);
777 mci_dcnt = readl(host->base + S3C2410_SDIDCNT);
778
779 BUG_ON(!host->mrq);
780 BUG_ON(!host->mrq->data);
781 BUG_ON(!host->dmatogo);
782
783 spin_lock_irqsave(&host->complete_lock, iflags);
784
785 if (result != S3C2410_RES_OK) {
786 dbg(host, dbg_fail, "DMA FAILED: csta=0x%08x dsta=0x%08x "
787 fsta=0x%08x dcnt:0x%08x result:0x%08x toGo:%u\n,
788 mci_csta, mci_dsta, mci_fsta,
789 mci_dcnt, result, host->dmatogo);
790
791 goto fail_request;
792 }
793
794 host->dmatogo--;
795 if (host->dmatogo) {
796 dbg(host, dbg_dma, "DMA DONE Size:%i DSTA:[%08x] "
797 DCNT:[%08x] toGo:%u\n,
798 size, mci_dsta, mci_dcnt, host->dmatogo);
799
800 goto out;
801 }
802
803 dbg(host, dbg_dma, "DMA FINISHED Size:%i DSTA:%08x DCNT:%08x\n",
804 size, mci_dsta, mci_dcnt);
805
806 host->dma_complete = 1;
807 host->complete_what = COMPLETION_FINALIZE;
808
809 out:
810 tasklet_schedule(&host->pio_tasklet);
811 spin_unlock_irqrestore(&host->complete_lock, iflags);
812 return;
813
814 fail_request:
815 host->mrq->data->error = -EINVAL;
816 host->complete_what = COMPLETION_FINALIZE;
817 clear_imask(host);
818
819 goto out;
820 }
实际长上面的函数中我们不难发现DMA完成以后,仍然是调用tasklet_schedule(&host->pio_tasklet);来完成结束工作。
到目前为止,linux2.6.32内核下的SD卡子系统的分析就算基本完成了。回顾整个SD卡子系统所采用的驱动开发的技巧主要有:
Ø 内核线程:用于处理上层块设备的请求;
Ø Completions 机制:用于block层与底层硬件的同步。典型例子为mmc_wait_for_req;
Ø 内核工作队列:用于轮询SD卡是否插入。
Ø 等待队列:在申请SD控制器时,我们使用了工作队列来保证内核的同步。
Ø Tasklets 机制:在底层硬件的中断处理中,Tasklets软中断为中断的相应赢得的足够的时间。
当然上面大多是内核同步和时间处理的策略,在内存管理方面也使用了不少技巧,比如通篇可见的scatterlist散列表等等。
最后,谈到这三个目录的作用及其之间的关系主要有:
card目录:主要完成与块设备层的接口,向core层提供正确可靠的struct mmc_request结构。
core目录:维护了SD卡与host之间的联系,实现了SD,MMC,SDIO等设备初始化的通用代码,并调用host提供的struct mmc_host_ops完成设备相关的初始化操作。
host目录:像core层提供必要的设备操作方法,特别是完成struct mmc_host_ops结构,以及初始化控制等,另外与card相关联的一点是当处理完成时利用Completions唤醒block层
转载地址:http://drdmi.baihongyu.com/