NVME Driver分析之nvme_submit_sync_cmd
来源:互联网 发布:nginx 默认403页面 编辑:程序博客网 时间:2024/06/05 02:49
前面在分支创建 I/O Completion Queue 命令时我们提到了,Admin command的提交,使用了nvme_submit_admin_cmd函数,该函数其实是调用了nvme_submit_sync_cmd(dev, 0, cmd, result, ADMIN_TIMEOUT),即提交了一个同步的命令。
static int nvme_submit_sync_cmd(struct nvme_dev *dev, int q_idx, struct nvme_command *cmd, u32 *result, unsigned timeout){ int cmdid, ret; struct sync_cmd_info cmdinfo; struct nvme_queue *nvmeq; nvmeq = lock_nvmeq(dev, q_idx); if (!nvmeq) return -ENODEV; cmdinfo.task = current; cmdinfo.status = -EINTR; cmdid = alloc_cmdid(nvmeq, &cmdinfo, sync_completion, timeout); //给cmd分配一个cmd id,通过在一个bitmap(还记得第一节分析init时提到的cmdid_data吗,它就是这个bitmap)中从头向后找,找到第一个非0的位置,就将这个位置号作为cmd id分配给这个cmd。。在alloc_cmdid的时候还会把completion的回调函数(sync_completion)以及回调函数的(cmdinfo)放入nvmeq->cmdinfo中,当controller处理完命令以后,host在被唤醒或者检测到这个命令处理完以后,就会执行这个回调函数,处理completion queue。 if (cmdid < 0) { unlock_nvmeq(nvmeq); return cmdid; } cmd->common.command_id = cmdid; //把获取的cmd id赋值要提交的cmd的command_id set_current_state(TASK_KILLABLE); ret = nvme_submit_cmd(nvmeq, cmd); //把command拷贝到queue中去同时按一下doorbell寄存器门铃,nvmeq->q_db = &dev->dbs[qid * 2 * dev->db_stride] if (ret) {//如果提交失败 free_cmdid(nvmeq, cmdid, NULL);//把cmdid清理掉 unlock_nvmeq(nvmeq); set_current_state(TASK_RUNNING); return ret;//返回error code } unlock_nvmeq(nvmeq); schedule_timeout(timeout);//等待controller执行完,执行一次cpu调度 if (cmdinfo.status == -EINTR) nvmeq = lock_nvmeq(dev, q_idx); if (nvmeq) {//如果queue还存在,则说明timeout超时了 nvme_abort_command(nvmeq, cmdid);//aborted掉这个cmd unlock_nvmeq(nvmeq); } return -EINTR; } if (result) *result = cmdinfo.result; return cmdinfo.status;}
static int nvme_submit_cmd(struct nvme_queue *nvmeq, struct nvme_command *cmd){ unsigned long flags; u16 tail; spin_lock_irqsave(&nvmeq->q_lock, flags); if (nvmeq->q_suspended) { //如果是suspend状态,说明这个queue没有init OK,所以要返回error信息 spin_unlock_irqrestore(&nvmeq->q_lock, flags); return -EBUSY; } tail = nvmeq->sq_tail; //找到submission queue的队尾 memcpy(&nvmeq->sq_cmds[tail], cmd, sizeof(*cmd)); //把要提交的命令拷贝到循环队列的队尾中去 if (++tail == nvmeq->q_depth) //如果循环队列到头了,则队尾重新归0 tail = 0; writel(tail, nvmeq->q_db); //按门铃!!! nvmeq->sq_tail = tail; //更新队尾的位置 spin_unlock_irqrestore(&nvmeq->q_lock, flags); return 0;}
static void *free_cmdid(struct nvme_queue *nvmeq, int cmdid, nvme_completion_fn *fn){ void *ctx; struct nvme_cmd_info *info = nvme_cmd_info(nvmeq); if (cmdid >= nvmeq->q_depth || !info[cmdid].fn) { if (fn) *fn = special_completion; return CMD_CTX_INVALID; } if (fn) *fn = info[cmdid].fn; ctx = info[cmdid].ctx; info[cmdid].fn = special_completion; info[cmdid].ctx = CMD_CTX_COMPLETED; clear_bit(cmdid, nvmeq->cmdid_data); //将该cmdid对应的bitmap位清零 wake_up(&nvmeq->sq_full); //唤醒等待获取cmdid的进程,同时唤醒process_cq的处理进程 return ctx;}
0 0
- NVME Driver分析之nvme_submit_sync_cmd
- NVME driver分析之nvme_dev_start函数分析
- NVME Driver分析之nvme_dev_add函数分析
- NVME Driver解析之init与probe
- NVME Driver 解析之Create I/O Completion Queue command
- NVME Drive分析之 Detailed IO Process
- nvme的__nvme_revalidate_disk分析
- NVMe之命令
- NVMe之热拔插事件
- NVMe
- nvme 驱动详解 之1
- 独家发布 | Linux NVMe Driver学习笔记大合集
- 从PCIe trace中分析NVMe
- Linux display driver 分析之 fb_find_mode函数
- linux内核组件分析之---设备驱动模型之driver
- linux内核组件分析之---设备驱动模型之driver
- linux里的nvme驱动代码分析(加载初始化)
- linux设备模型之bus,device,driver分析一
- vim中taglist无法显示问题
- mysql 存储过程学习
- XMPP介绍
- nryktulyupiyp
- js实现图片上传及预览---------------------->>兼容ie6-8 火狐以及谷歌
- NVME Driver分析之nvme_submit_sync_cmd
- CSS之页面布局之二(冻结布局)
- 基于Yii的PDO工具类以及Yii的常用操作
- 异常检测
- The Wavelet Tutorial Part IV
- Android 四大组件之Activity生命周期
- iOS 判断网络类型2G、3G、4G等等等
- 用ListBox作滚屏显示的一种方法 .
- COCOS2DX引擎深入一————调度原理