nvdimm 驱动的分析

简介:

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里面的数据写到磁盘。












本文转自存储之厨51CTO博客,原文链接: http://blog.51cto.com/xiamachao/2064402,如需转载请自行联系原作者

相关文章
|
8月前
|
Linux C语言 SoC
嵌入式linux总线设备驱动模型分析
嵌入式linux总线设备驱动模型分析
93 1
CMOS摄像头驱动分析-i2c驱动
CMOS摄像头驱动分析-i2c驱动
201 0
|
芯片 数据格式
16位ADC芯片SGM58031驱动重点
16位ADC芯片SGM58031驱动重点
880 0
|
Linux API
Linux驱动分析之LCD驱动架构
在Linux设备中,LCD显示采用了帧缓冲(framebuffer)技术,所以LCD驱动也叫Framebuffer驱动,所以LCD驱动框架就是围绕帧缓冲展开工作。帧缓冲(framebuffer)是Linux系统为显示设备提供的一个接口,它将显示缓冲区抽象出来,屏蔽图像硬件的底层差异,允许上层应用程序在图形模式下直接对显示缓冲区进行读写操作。对于帧缓冲设备而言,只要在显示缓冲区中与显示点对应的区域写入颜色值,对应的颜色会自动在屏幕上显示。帧缓冲为标准字符设备, 主设备号为29,对应于/dev/fbn。
|
缓存 Linux API
Linux驱动分析之Uart驱动架构
UART设备驱动可以使用tty驱动的框架来实现,但是因为串口之间有共性,所以Linux在tty接口上封装了一层(serial core)。后面我们再拿一篇文章来解释tty驱动,tty其实就是各种终端设备,串口其实也是终端设备。
Linux驱动分析之Uart驱动架构
|
Linux Android开发 芯片
Linux驱动分析之Framebuffer驱动
前面我们了解了LCD的基本架构《Linux驱动分析之LCD驱动架构》,接下来我们拿个具体的实例来分析分析。这样可以了解其大概是如何使用和工作的。
|
Linux API
Linux驱动分析之SPI驱动架构
Linux驱动分析之SPI驱动架构
|
缓存 Linux 芯片
Linux驱动分析之Uart驱动
之前对Uart驱动的整体架构做了介绍,现在来分析具体的驱动程序。我们以NXP 的 IMX6来进行分析。
|
Linux 芯片
Linux驱动分析之RTC驱动
前面《Linux驱动分析之RTC框架》分析了RTC的基本框架,接下来拿个RTC驱动实例来分析一下。

热门文章

最新文章