nvdimm 驱动的分析
2018-01-23 21:57
176 查看
nvdimm 驱动的分析
1.驱动的简介
nvdimm在内核中的驱动,是基于一个典型的字符类型的设备驱动模型去实现的。因此,同样需要实现设备驱动的几个典型操作:open/release/mmap/ioctl。 在open阶段通过efi或者e820 table探测到nvdimm的起始物理地址和长度,通过set_mtrr()设置nvdimm对应程序空间的cache属性,通过io_remmap()把物理地址映射到内核虚拟地址;在release阶段,释放上面的资源。在内核实现mmap,为用户实现用户态mmap()提供支持;定义各种命令,进而在ioctl()中实现,进而为用户和内核态的驱动提供交互接口。最后通过register_chrdev()注册这个设备。2.主要的数据结构
作为一个驱动,主要的函数当然是file_operations. nvdimm也不例外:static const struct file_operations nvdimm_fops = { .owner = THIS_MODULE, .open = nvdimm_open, .release = nvdimm_close, .mmap = nvdimm_mmap, .unlocked_ioctl = nvdimm_ioctl, };
3. 主要的函数
3.0 Init和Deinit
nvdimmInit()主要功能如下:{探测设备得到物理地址,set_mtrr、ioramp()为物理地址分配内核空间,注册字符驱动,启动监控nvdimm电容、温度、电量、健康状态的内核线程,注册关机保存数据的服务}
nvdimmDeInit()主要功能:执行和上面的相反的操作
3.1 nvdimm_ioctl()
读取nvdimm状态,设置寄存器的接口,读取eeprom,更新eeprom,dump 寄存器等。 注意这里多次用到copy_to_usr() copy_from_usr() 来同步数据,3.2 nvdimm_mmap()
为了支持用户态mmap()3.3 nvdimm_remap();
映射nvdimm物理地址到虚拟内核地址。4. 和用户态的接口
需要包含公共函数接口,使用举例如下:fd = open("/dev/Agiga"); ioctl(fd, cmd); // mmap(fd, ....); // close(fd);
5. 难点
5.1 支持不同级别的数据一致性
在nvimm_ioremap()中实现,通过调用set_mtrr()实现,然后call相应的ioremap/iormap_wc/iormap_catch。注意由于它只在初始化的时候执行一次,这就意味着一旦驱动加载,它的cache 模式就固定了,不能运行时动态修改。
5.2 在write back模式的时候需要flush Dcache.
具体执行是通过flush_Dcache(),注意这里是需要考虑多多核的架构,得让每一个perCPU都去做:void dcache_flush(void)
{
if (nvdimm_cache == MEM_WRITE_BACK) {
if (on_each_cpu(do_wbinvd, NULL, 1) != 0)
printf("Timed out waiting for cache flush.\n");
}
}
然后通过ioctl的一个命令和flush_Dcache相关联,这样用户态就可以刷nvdimm对应的Dcache了。而且,通过上面的代码,可以看到,只在cache 模式为write-back 时才真正的刷Dcache.
5.3 如何实现panci或者关机时保存数据
nvdimm的核心特性是掉电、异常关机或者重启时会触发ADR(新的机制会这样做),此后硬件会把nvdimm里DRAM上的数据自动写到它的SSD上去。如果此时需要设置某些寄存器,就需要把设置寄存器的动作注册到panic_notifier_list里去。这样,内核关机或者panic依次执行这个 &panic_notifier_list这个函数链,最终就可以完成设置那些寄存器的操作。示例如下:
5.3.1 驱动里实现 panic_task_backup() 函数
mypanic_task(struct notifier_block *this, unsigned long event, void *ptr)
{
UINT32 rc = SUCCESS;
struct nvdimm_device *nvdimm;
................
dcache_flush(); for (index = 0; index < total; index++) { timeOut = 60 * 5; /* step 0: Enable NVDIMM BACKUP function */ smb_cmd.dev_index = index; smb_cmd.rw = SMB_BYTE_WRITE; // byte write ....... /* return status of operation */ if (rc == SUCCESS) { printk(KERN_CRIT "SUCCESS to enable backup mode 0x%c of NVDIMM%d during panic!\n", backup_type, index); } ....... }
5.3.2 声明一个notifier
static struct notifier_block mybackup = {.notifier_call = mypanic_task, };
5.3.2 注册mybackup到panic 通知链条
atomic_notifier_chain_register(&panic_notifier_list, &mybackup);
参考上面的命令就可以把它注册成功,这样在backup_bloc()里触发备份数据,把DRAM里面的数据写到磁盘。
相关文章推荐
- LCD驱动分析(三): framebuffer驱动的注册
- LCD驱动调试中部分常见问题的分析及解决办法
- 我的存储第一战:PM8001驱动分析(一)
- USB驱动框架分析3
- 【Linux高级驱动】I2C驱动框架分析
- wince5.0中es1371声卡单层驱动源码分析
- uboot移植与源码分析总结(3)-Serial驱动分析
- pl330 dmac驱动分析2----关键函数
- 学习笔记 --- LINNUX 使用异步通讯机制实现按键驱动代码分析
- NAND驱动分析--(三)
- 三极管的电平转换及驱动电路分析
- 【转载】RTC驱动分析
- 触摸屏驱动分析
- 【嵌入式Linux学习七步曲之第五篇 Linux内核及驱动编程】Linux内核模块LKM的动态加载技术分析
- 分析几个驱动
- virtio驱动分析之libvirt层的参数配置
- platform驱动开发套路、DM9000的一些分析
- Linux驱动修炼之道-看门狗框架源码分析
- Linux内核中SPI总线驱动分析
- LINUX驱动分析之RTC(四)