linux 内核 sd卡驱动,(转)Linux内核MTD驱动程序与SD卡驱动程序(三)

(3)MMC卡请求的处理

Linux_kernel_mtd_mmc_sd_driver_01.gif图 函数mmc_init_queue调用层次图

函数mmc_init_queue初始化一个MMC卡请求队列结构,其中参数mq是mmc请求队列,参数card是加在这个队列里的mmc卡,参数lock是队列锁。函数mmc_init_queue调用层次图如上图。

函数mmc_init_queue分析如下(在drivers/mmc/mmc_queue.c中):

int mmc_init_queue(struct mmc_queue *mq, struct mmc_card *card,

spinlock_t *lock)

{

struct mmc_host *host = card->host;

u64 limit = BLK_BOUNCE_HIGH;

int ret;

if (host->dev->dma_mask && *host->dev->dma_mask)

limit = *host->dev->dma_mask;

mq->card = card;

//初始化块层的请求队列,请求合并策略,赋上请求处理函数mmc_request。

mq->queue = blk_init_queue(mmc_request, lock);

if (!mq->queue)

return -ENOMEM;

//初始化请求队列的扇区及片断限制

blk_queue_prep_rq(mq->queue, mmc_prep_request);//赋上准备请求函数

blk_queue_bounce_limit(mq->queue, limit);

blk_queue_max_sectors(mq->queue, host->max_sectors);

blk_queue_max_phys_segments(mq->queue, host->max_phys_segs);

blk_queue_max_hw_segments(mq->queue, host->max_hw_segs);

blk_queue_max_segment_size(mq->queue, host->max_seg_size);

mq->queue->queuedata = mq;

mq->req = NULL;

mq->sg = kmalloc(sizeof(struct scatterlist) * host->max_phys_segs,

GFP_KERNEL);

if (!mq->sg) {

ret = -ENOMEM;

goto cleanup;

}

init_completion(&mq->thread_complete);

init_waitqueue_head(&mq->thread_wq);

init_MUTEX(&mq->thread_sem);

//创建请求队列处理线程mmc_queue_thread

ret = kernel_thread(mmc_queue_thread, mq, CLONE_KERNEL);

if (ret >= 0) {

wait_for_completion(&mq->thread_complete);

init_completion(&mq->thread_complete);

ret = 0;

goto out;

}

cleanup:

kfree(mq->sg);

mq->sg = NULL;

blk_cleanup_queue(mq->queue);

out:

return ret;

}

函数mmc_prep_request 在准备一个MMC请求时做一些状态转移及保护操作,函数列出如下(在drivers/mmc/ mmc_queue.c中):

static int mmc_prep_request(struct request_queue *q, struct request *req)

{

struct mmc_queue *mq = q->queuedata;

int ret = BLKPREP_KILL;

if (req->flags & REQ_SPECIAL) {

//在req->special 中已建立命令块,表示请求已准备好

BUG_ON(!req->special);

ret = BLKPREP_OK;

} else if (req->flags & (REQ_CMD | REQ_BLOCK_PC)) {

//块I/O请求需要按照协议进行翻译

ret = mq->prep_fn(mq, req);

} else {

//无效的请求

blk_dump_rq_flags(req, "MMC bad request");

}

if (ret == BLKPREP_OK)//请求已准备好,不需再准备了

req->flags |= REQ_DONTPREP;

return ret;

}

函数mmc_blk_prep_rq是准备请求时调用的函数,这里仅做了简单的保护处理,列出如下(在drivers/mmc/mmc_block.c中):

static int mmc_blk_prep_rq(struct mmc_queue *mq, struct request *req)

{

struct mmc_blk_data *md = mq->data;

int stat = BLKPREP_OK;

//如果没有设备,没法完成初始化

if (!md || !mq->card) {

printk(KERN_ERR "%s: killing request - no device/host\n",

req->rq_disk->disk_name);

stat = BLKPREP_KILL;

}

return stat;

}

函数mmc_request是通用MMC请求处理函数,它唤醒请求队列处理线程。它在特定的主控制器上被任何请求队列调用。当主控制器不忙时,我们查找在这个主控制器上的任何一个队列中的请求,并且尝试发出这个请求进行处理。

函数mmc_request分析如下(在driver/mmd/mmc_queue.c中):

static void mmc_request(request_queue_t *q)

{

struct mmc_queue *mq = q->queuedata;

if (!mq->req)//如果有请求,唤醒请求队列处理线程

wake_up(&mq->thread_wq);

}

线程函数mmc_queue_thread调用了具体设备的请求处理函数,利用线程机制来处理请求。函数mmc_queue_thread分析如下:

static int mmc_queue_thread(void *d)

{

struct mmc_queue *mq = d;

struct request_queue *q = mq->queue;

DECLARE_WAITQUEUE(wait, current); //声明一个当前进程的等待队列

//设置当前进程状态,来让线程自己来处理挂起

current->flags |= PF_MEMALLOC|PF_NOFREEZE;

//让线程继承init进程,从而不会使用用户进程资源

daemonize("mmcqd");

complete(&mq->thread_complete); //设置线程完成时的回调函数

down(&mq->thread_sem);

add_wait_queue(&mq->thread_wq, &wait); //加线程到等待队列

do {

struct request *req = NULL;

spin_lock_irq(q->queue_lock);

set_current_state(TASK_INTERRUPTIBLE);

if (!blk_queue_plugged(q)) //如果队列是非堵塞状态,得到下一个请求

mq->req = req = elv_next_request(q);

spin_unlock_irq(q->queue_lock);

if (!req) {//如果请求为空

if (mq->flags & MMC_QUEUE_EXIT)

break;

up(&mq->thread_sem);

schedule();

down(&mq->thread_sem);

continue;

}

set_current_state(TASK_RUNNING);

//这里调用了mmc_blk_issue_rq开始处理请求

mq->issue_fn(mq, req);

} while (1);

remove_wait_queue(&mq->thread_wq, &wait);

up(&mq->thread_sem);

//调用请求处理完后的回调函数

complete_and_exit(&mq->thread_complete, 0);

return 0;

}

函数mmc_blk_issue_rq初始化MMC块请求结构后,向卡发出请求命令,并等待请求的完成,函数分析如下:

static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req)

{

struct mmc_blk_data *md = mq->data;

struct mmc_card *card = md->queue.card;

int ret;

//认领控制器,发命令到卡设置card为选中状态

if (mmc_card_claim_host(card))

goto cmd_err;

do {

struct mmc_blk_request brq;

struct mmc_command cmd;

//初始化MMC块请求结构

memset(&brq, 0, sizeof(struct mmc_blk_request));

brq.mrq.cmd = &brq.cmd;

brq.mrq.data = &brq.data;

brq.cmd.arg = req->sector << 9;

brq.cmd.flags = MMC_RSP_R1;

brq.data.timeout_ns = card->csd.tacc_ns * 10;

brq.data.timeout_clks = card->csd.tacc_clks * 10;

brq.data.blksz_bits = md->block_bits;

brq.data.blocks = req->nr_sectors >> (md->block_bits - 9);

brq.stop.opcode = MMC_STOP_TRANSMISSION;

brq.stop.arg = 0;

brq.stop.flags = MMC_RSP_R1B;

if (rq_data_dir(req) == READ) {//读请求

brq.cmd.opcode = brq.data.blocks > 1 ? MMC_READ_MULTIPLE_BLOCK : MMC_READ_SINGLE_BLOCK;

brq.data.flags |= MMC_DATA_READ;

} else {//写

brq.cmd.opcode = MMC_WRITE_BLOCK;

brq.cmd.flags = MMC_RSP_R1B;

brq.data.flags |= MMC_DATA_WRITE;

brq.data.blocks = 1;

}

brq.mrq.stop = brq.data.blocks > 1 ? &brq.stop : NULL;

brq.data.sg = mq->sg;

brq.data.sg_len = blk_rq_map_sg(req->q, req, brq.data.sg);

//等待请求完成

mmc_wait_for_req(card->host, &brq.mrq);

……

do {

int err;

cmd.opcode = MMC_SEND_STATUS;

cmd.arg = card->rca << 16;

cmd.flags = MMC_RSP_R1;

err = mmc_wait_for_cmd(card->host, &cmd, 5);

if (err) {

printk(KERN_ERR "%s: error %d requesting status\n",

req->rq_disk->disk_name, err);

goto cmd_err;

}

} while (!(cmd.resp[0] & R1_READY_FOR_DATA));

//一个块被成功传输

spin_lock_irq(&md->lock);

ret = end_that_request_chunk(req, 1, brq.data.bytes_xfered);

if (!ret) {

//整个请求完全成功完成

add_disk_randomness(req->rq_disk);

blkdev_dequeue_request(req);//从队列中删除请求

end_that_request_last(req);//写一些更新信息

}

spin_unlock_irq(&md->lock);

} while (ret);

mmc_card_release_host(card);

return 1;

cmd_err:

mmc_card_release_host(card);

spin_lock_irq(&md->lock);

do {

//结束请求req上的I/O,操作成功时返回0

ret = end_that_request_chunk(req, 0,

req->current_nr_sectors << 9);

} while (ret);

add_disk_randomness(req->rq_disk);

blkdev_dequeue_request(req);

end_that_request_last(req);

spin_unlock_irq(&md->lock);

return 0;

}

函数mmc_card_claim_host发出命令选择这个卡card,函数列出如下(在 include/linuc/mmc/card.h中):

static inline int mmc_card_claim_host(struct mmc_card *card)

{

return __mmc_claim_host(card->host, card);

}

函数__mmc_claim_host专有地认领一个控制器,参数host是认领的mmc控制器,参数card是去认领控制器的卡。函数__mmc_claim_host为一套操作认领一个控制器,如果card是被传递的一个有效的卡,并且它不是上次被选择的卡,那么在函数返回之前发出命令选择这个卡card。

函数__mmc_claim_host分析如下(在drivers/mmc/mmc.c中):

int __mmc_claim_host(struct mmc_host *host, struct mmc_card *card)

{

DECLARE_WAITQUEUE(wait, current);//给当前进程声明一个等待队列

unsigned long flags;

int err = 0;

add_wait_queue(&host->wq, &wait);//加host->wq到等待队列中

spin_lock_irqsave(&host->lock, flags);

while (1) {

set_current_state(TASK_UNINTERRUPTIBLE);//设置当前进程不可中断状态

if (host->card_busy == NULL) //如果没有忙的卡,跳出循环

break;

spin_unlock_irqrestore(&host->lock, flags);

schedule(); //如果有忙的卡,去调度执行

spin_lock_irqsave(&host->lock, flags);

}

set_current_state(TASK_RUNNING);//设置当前进程为运行状态

host->card_busy = card; //指定当前忙的卡

spin_unlock_irqrestore(&host->lock, flags);

remove_wait_queue(&host->wq, &wait); //从等待队列中移去host->wq

//如果卡不是选择状态,发出命令到卡设置为选择状态

if (card != (void *)-1 && host->card_selected != card) {

struct mmc_command cmd;

host->card_selected = card;

cmd.opcode = MMC_SELECT_CARD;

cmd.arg = card->rca << 16;

cmd.flags = MMC_RSP_R1;

//等待命令完成

err = mmc_wait_for_cmd(host, &cmd, CMD_RETRIES);

}

return err;

}

函数mmc_wait_for_req开始执行一个请求并等待请求完成,函数分析如下(在drivers/mmc/mmc.c中):

int mmc_wait_for_req(struct mmc_host *host, struct mmc_request *mrq)

{

DECLARE_COMPLETION(complete);

mrq->done_data = &complete;

mrq->done = mmc_wait_done;

mmc_start_request(host, mrq);

wait_for_completion(&complete);

return 0;

}

函数mmc_start_request开始排队执行一个在控制器上的命令,参数host是执行命令的控制器,参数mrq是将要开始执行的请求。调用者应持有锁并且关中断。

函数mmc_start_request分析如下(在drivers/mmc/mmc.c中):

void mmc_start_request(struct mmc_host *host, struct mmc_request *mrq)

{

DBG("MMC: starting cmd %02x arg %08x flags %08x\n",

mrq->cmd->opcode, mrq->cmd->arg, mrq->cmd->flags);

WARN_ON(host->card_busy == NULL);

mrq->cmd->error = 0;

mrq->cmd->mrq = mrq;

if (mrq->data) {

mrq->cmd->data = mrq->data;

mrq->data->error = 0;

mrq->data->mrq = mrq;

if (mrq->stop) {

mrq->data->stop = mrq->stop;

mrq->stop->error = 0;

mrq->stop->mrq = mrq;

}

}

//调用请求处理函数,对于amba主控制器来说就是mmci_request函数

host->ops->request(host, mrq);

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值