linux 3.13版本nvme驱动阅读记录四

这里记录下在nvme_probe函数调用misc_register函数的总结。

static int nvme_probe(struct pci_dev *pdev, const struct pci_device_id *id)
{//...
create_cdev://利用miscdev结构体提供一些字符设备的操作(回调函数),用户空间可以下发一些nvme的命令等scnprintf(dev->name, sizeof(dev->name), "nvme%d", dev->instance);dev->miscdev.minor = MISC_DYNAMIC_MINOR;dev->miscdev.parent = &pdev->dev;dev->miscdev.name = dev->name;dev->miscdev.fops = &nvme_dev_fops;result = misc_register(&dev->miscdev); //将字符设备那一堆函数在汇总在一起if (result)goto remove;kref_init(&dev->kref);//设备引用计数初始化,值为1return 0;//...
}

nvme_dev_fops

static int nvme_dev_open(struct inode *inode, struct file *f)
{struct nvme_dev *dev = container_of(f->private_data, struct nvme_dev, miscdev);kref_get(&dev->kref);f->private_data = dev;return 0;
}static int nvme_dev_release(struct inode *inode, struct file *f)
{struct nvme_dev *dev = f->private_data;kref_put(&dev->kref, nvme_free_dev);return 0;
}static long nvme_dev_ioctl(struct file *f, unsigned int cmd, unsigned long arg)
{struct nvme_dev *dev = f->private_data;switch (cmd) {case NVME_IOCTL_ADMIN_CMD:return nvme_user_admin_cmd(dev, (void __user *)arg);default:return -ENOTTY;}
}static const struct file_operations nvme_dev_fops = {.owner		= THIS_MODULE,.open		= nvme_dev_open,.release	= nvme_dev_release,.unlocked_ioctl	= nvme_dev_ioctl,
};

nvme_user_admin_cmd

static int nvme_user_admin_cmd(struct nvme_dev *dev, struct nvme_admin_cmd __user *ucmd)
{struct nvme_admin_cmd cmd;struct nvme_command c;int status, length;struct nvme_iod *uninitialized_var(iod);unsigned timeout;if (!capable(CAP_SYS_ADMIN))//sudoreturn -EACCES;if (copy_from_user(&cmd, ucmd, sizeof(cmd)))return -EFAULT;memset(&c, 0, sizeof(c));c.common.opcode = cmd.opcode;c.common.flags = cmd.flags;c.common.nsid = cpu_to_le32(cmd.nsid);c.common.cdw2[0] = cpu_to_le32(cmd.cdw2);c.common.cdw2[1] = cpu_to_le32(cmd.cdw3);c.common.cdw10[0] = cpu_to_le32(cmd.cdw10);c.common.cdw10[1] = cpu_to_le32(cmd.cdw11);c.common.cdw10[2] = cpu_to_le32(cmd.cdw12);c.common.cdw10[3] = cpu_to_le32(cmd.cdw13);c.common.cdw10[4] = cpu_to_le32(cmd.cdw14);c.common.cdw10[5] = cpu_to_le32(cmd.cdw15);length = cmd.data_len;if (cmd.data_len) {/*将用户态传下来的地址,转成page结构体*/iod = nvme_map_user_pages(dev, cmd.opcode & 1, cmd.addr, length);if (IS_ERR(iod))return PTR_ERR(iod);length = nvme_setup_prps(dev, &c.common, iod, length, GFP_KERNEL);}/*timeout:发命令的超时时间msecs_to_jiffies:ms转jiffies*/timeout = cmd.timeout_ms ? msecs_to_jiffies(cmd.timeout_ms) : ADMIN_TIMEOUT;if (length != cmd.data_len)status = -ENOMEM;elsestatus = nvme_submit_sync_cmd(dev->queues[0], &c, &cmd.result, timeout);/*解除映射*/if (cmd.data_len) {nvme_unmap_user_pages(dev, cmd.opcode & 1, iod);nvme_free_iod(dev, iod);}/*将命令的执行结果返回给用户态*/if ((status >= 0) && copy_to_user(&ucmd->result, &cmd.result, sizeof(cmd.result)))status = -EFAULT;return status;
}

nvme_map_user_pages和nvme_unmap_user_pages

struct nvme_iod *nvme_map_user_pages(struct nvme_dev *dev, int write, unsigned long addr, unsigned length)
{int i, err, count, nents, offset;struct scatterlist *sg;struct page **pages;struct nvme_iod *iod;if (addr & 3) //地址是4字节对齐。因为struct scatterlist结构体的page_link的低两位有其它用途了return ERR_PTR(-EINVAL);if (!length || length > INT_MAX - PAGE_SIZE)return ERR_PTR(-EINVAL);offset = offset_in_page(addr);//0x12345678 -> 0x678 = 1656, 假设length=3000//计算需要几个page, offset(起始处)是struct page的起始处,所以是offset+length计算的需要几个pagecount = DIV_ROUND_UP(offset + length, PAGE_SIZE); //((offset + length) / PAGE_SIZE) + 1//申请内存pages = kcalloc(count, sizeof(*pages), GFP_KERNEL);if (!pages)return ERR_PTR(-ENOMEM);/*addr可能不是4k对齐的,后续可能需要offset*/err = get_user_pages_fast(addr, count, 1, pages);//pin 用户态虚拟地址,返回对应的struct page结构if (err < count) {count = err;err = -EFAULT;goto put_pages;}iod = nvme_alloc_iod(count, length, GFP_KERNEL);sg = iod->sg;sg_init_table(sg, count);for (i = 0; i < count; i++) {/*page->|-------||		||		|offset->|------ ||-------|*///len offset第一次 len = 2440, offset=1656,第二次 len=560,offset=0 刚好符合length=3000sg_set_page(&sg[i], pages[i], min_t(unsigned, length, PAGE_SIZE - offset), offset);length -= (PAGE_SIZE - offset);offset = 0;}sg_mark_end(&sg[i - 1]);iod->nents = count;err = -ENOMEM;//将struct scatterlist记录的每一个sge内核态虚拟地址映射为dma地址nents = dma_map_sg(&dev->pci_dev->dev, sg, count, write ? DMA_TO_DEVICE : DMA_FROM_DEVICE);if (!nents)goto free_iod;kfree(pages);return iod;
free_iod:kfree(iod);
put_pages:for (i = 0; i < count; i++)put_page(pages[i]);//addr对应的struct pagekfree(pages);return ERR_PTR(err);
}void nvme_unmap_user_pages(struct nvme_dev *dev, int write, struct nvme_iod *iod)
{int i;dma_unmap_sg(&dev->pci_dev->dev, iod->sg, iod->nents, write ? DMA_TO_DEVICE : DMA_FROM_DEVICE);for (i = 0; i < iod->nents; i++)put_page(sg_page(&iod->sg[i]));
}

调用完以后在dev目录下也可以看到相关的设备节点了。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/138157.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

医学影像系统源码(MRI、CT三维重建)

一、MRI概述 核磁共振成像&#xff08;英语&#xff1a;Nuclear Magnetic Resonance Imaging&#xff0c;简称NMRI&#xff09;&#xff0c;又称自旋成像&#xff08;英语&#xff1a;spin imaging&#xff09;&#xff0c;也称磁共振成像&#xff08;Magnetic Resonance Imag…

Labview利用声卡捕获波形

一般的计算机上自带的声卡&#xff0c;均既有A/D功能&#xff0c;又有D/A功能&#xff0c;就是一款具备基本配置的数据采集卡&#xff0c;并且技术成熟&#xff0c;性能稳定。 后台如下&#xff1a;

【Word自定义配置,超简单,图文并茂】自定义Word中的默认配置,比如标题大小与颜色(参考科研作图配色),正文字体等

▚ 01 自定义样式Styles中的默认标题模板 &#x1f4e2;自定义标题的显示效果&#xff0c;如下图所示&#xff1a; 1.1 自定义标题的模板Normal.dotm 1.1.1 选择所需修改的标题 新建一个空白Word文档&#xff0c;依次选择菜单栏的开始Home&#xff0c;样式Styles&#xff0c;…

低代码信创开发核心技术(三):MDA模型驱动架构及元数据系统设计

前言 写最后一篇文章的时候&#xff0c;我本人其实犹豫了半年&#xff0c;在想是否发布出这篇文章&#xff0c;因为可能会动了很多人的利益。所以这篇文章既是整个低代码信创开发的高度总结&#xff0c;也是最为精华的一部分&#xff0c;它点明了低代码中最为核心的技术。虽然…

光刻掩膜版怎么制作的?

光掩膜版基本上是 IC 设计的“主模板”。掩模版有不同的尺寸。常见尺寸为 6 x 6 英寸一般的掩膜版由石英或玻璃基板组成。光掩膜版涂有不透明薄膜。更复杂的掩模版使用其他材料。 一般来说&#xff0c;术语“photo mask”用于描述与 1X 步进机或光刻系统一起使用的“主模板”。…

Ubuntu 安装常见问题

1. 安装oh my zsh 搜狗输入法不能用 vim /etc/environmentexport XIM_PROGRAMfcitx export XIMfcitx export GTK_IM_MODULEfcitx export QT_IM_MODULEfcitx export XMODIFIERS“imfcitx” export LANG“zh_CN.UTF-8”配置完后重启&#xff0c;稍等一会&#xff0c;右上角会有个…

Windows下Python及Anaconda的安装与设置之保姆指南

学习Python编程需要安装基本的开发环境。 &#xff08;1&#xff09;python ——编译器&#xff1b;这个是任何语言都需要的&#xff1b;必需&#xff01; &#xff08;2&#xff09;Anaconda ——主要的辅助工具&#xff0c;号称是 Python‘OS&#xff1b;必需&#xff01; …

python机器学习——随机森林

随机森林 随机森林&#xff08;Random Forest&#xff09;是一种集成学习方法&#xff0c;它通过构建多个决策树并结合它们的预测结果来进行分类或回归。 算法原理&#xff1a; 决策树&#xff08;Decision Tree&#xff09;: 随机森林由多个决策树组成。决策树是一种基于树…

如何在PPT中去除编辑密码?

&#xff1a;忘记PPT幻灯片密码&#xff1f;最简单的办法在这里&#xff01; 【摘要】&#xff1a;具体步骤如下&#xff1a;第一步百度搜索【密码帝官网】&#xff0c;第二步点击“立即开始”&#xff0c;在用户中心上传文件即可。不用下载软件&#xff0c;手机电脑都可以用。…

Pytorch实战教程(一)-神经网络与模型训练

0. 前言 人工神经网络 (Artificial Neural Network, ANN) 是一种监督学习算法,其灵感来自人类大脑的运作方式。类似于人脑中神经元连接和激活的方式,神经网络接受输入,通过某些函数在网络中进行传递,导致某些后续神经元被激活,从而产生输出。函数越复杂,网络对于输入的数…

云架构师学习------腾讯云通识-存储与数据库

云架构师学习------腾讯云通识-存储与数据库 云架构师学习------腾讯云通识-存储与数据库存储基础存储服务对象存储-COS产品概述功能概览产品优势 云硬盘-CBS产品概述产品功能产品优势云硬盘类型 文件存储-CFS产品概述产品功能产品优势文件存储类型及性能规格存储类型性能与规格…

图论09-桥和割点

文章目录 1 寻找桥的算法2 桥的代码实现3 寻找割点的算法4 割点的代码实现 1 寻找桥的算法 2 桥的代码实现 package Chapt06_Bridge;import java.util.ArrayList;public class FindBridges {private Graph G;private boolean[] visited;//ord数组记录访问的顺序private int or…

51单片机PCF8591数字电压表数码管显示设计( proteus仿真+程序+设计报告+讲解视频)

PCF8591数字电压表数码管显示 1.主要功能&#xff1a;讲解视频&#xff1a;2.仿真3. 程序代码4. 设计报告5. 设计资料内容清单&&下载链接资料下载链接&#xff08;可点击&#xff09;&#xff1a; 51单片机PCF8591数字电压表数码管设计( proteus仿真程序设计报告讲解视…

计蒜客详解合集(2)期

目录 T1126——单词倒排 T1617——地瓜烧 T1612——蒜头君的数字游戏 T1488——旋转单词 T1461——校验信用卡号码 T1437——最大值和次大值 T1126——单词倒排 超级水的一道题&#xff0c;和T1122类似但更简单&#xff0c;分割后逆序输出即可~ 编写程序&#xff0c;读入…

Linux系統下查看处理器信息

在 Linux 系统中&#xff0c;可以使用 lscpu 命令来查看处理器的信息。该命令会显示有关 CPU 架构、核心数、线程数、缓存等级和大小等详细信息。 要使用 lscpu 命令&#xff0c;只需在终端中输入以下命令并按下回车键&#xff1a; lscpu执行后&#xff0c;将显示处理器的相关…

2023最新版本 从零基础入门C++与QT(学习笔记) -2- 命名空间的使用

&#x1f38f;在不同的命名空间变量名可相同 创建(如下方代码块) &#x1f384;分析一下构成 &#x1f388;-1- namespace 关键字命名空间 &#x1f388;-2- wm9 空间名称 &#x1f388;-3-括号里边正常定义变量即可 namespace wm9 {int a 99;char b A;float c 9.99;char…

Harbor(V2.8+) 登录时报错 net/http: TLS handshake timeout

问题描述 最近将harbor从v1.8 升级到v2.8后&#xff0c;客户端在登录时出现了以下问题&#xff1a; net/http: TLS handshake timeout解决方案 由于V2.8版本的nginx代理中只有配置TLSv1.2协议&#xff0c;没有TLSv1.1协议的支持&#xff0c;导致了部分客户端无法的登录。 在…

Django——orm模块创建表关系

django orm中如何创建表关系 1. 表关系分析 表与表之间的关系: 一对多 多对多 一对一 没有关系 判断表关系的方法: 换位思考用4张表举例: 图书表 出版社表 作者表 作者详情表图书和出版社是一对多的关系 外键字段建在多的那一方图书和作者是多对多的关系 需要创建第三张表来…

振南技术干货集:研发版本乱到“妈不认”? Git!(1)

注解目录 1、关于 Git 1.1Git 今生 (Git 和 Linux 的生父都是 Linus&#xff0c;振南给你讲讲当初关于 Git 的爱恨情愁&#xff0c;其背后其实是开源与闭源两左阵营的明争暗斗。) 1.2Git的爆发 (Git 超越时代的分布式思想。振南再给你讲讲旧金山三个年轻人创办 GitHub&…

Java设计模式之访问者模式

目录 定义 结构 案例 优点 缺点 使用场景 扩展 分派 案例实现须知 动态分派 静态分派 双分派 定义 封装一些作用于某种数据结构中的各元素的操作&#xff0c;它可以在不改变这个数据结构的前提下定义作用于这些元素的新的操作。 结构 访问者模式包含以下主要角色…