> For the complete documentation index, see [llms.txt](https://richardweiyang-2.gitbook.io/kernel-exploring/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://richardweiyang-2.gitbook.io/kernel-exploring/00-brief_navigation/03-nvdimm.md).

# nvdimm

创建了nvdimm\_bus，读取了nfit中的信息后，接下来驱动就根据这些信息创建nvdimm这个数据结构了。

这个数据结构就对应着一个物理的dimm，这可能也是为什么使用memmap=内核参数时没有这个设备的原因。

## 构造nvdimm的函数

这个过程由acpi\_nfit\_register\_dimms()函数完成，大致的流程如下：

```
list_for_each_entry(nfit_mem, &acpi_desc->dimms, list) {
    __nvdimm_create();
}
```

从这个片段能看出nvdimm结构体是从acpi\_desc->dimms的信息构建的。

## 相应的数据结构

看了函数调用，现在来看看对应的数据结构的样子。虽然看了有时候也还是不懂。

```
    acpi_nfit_desc
    +-----------------------------------------------+
    |dimms                                          |  a list of nfit_mem
    |    (struct list_head)                         |  parsed from above spa & memdevs
    |    +------------------------------------------+
    |    |nvdimm                                    |  *
    |    |     (struct nvdimm*)                     |
    |    |     +------------------------------------+
    |    |     |dev                                 |
    |    |     |   (struct device)                  |
    |    |     |   +--------------------------------+
    |    |     |   |name                            |  = "nmem%d"
    |    |     |   |groups                          |  = acpi_nfit_dimm_attribute_groups
    |    |     |   |                                |
    |    |     |   |driver_data                     |  = struct nvdimm_drvdata
    |    |     |   |   (void*)                      |
    |    |     |   |  +-----------------------------+
    |    |     |   |  |dev                          |
    |    |     |   |  |   (struct device*)          |
    |    |     |   |  |ns_current, ns_next          |
    |    |     |   |  |nslabel_size                 |  = 128
    |    |     |   |  |   (int)                     |
    |    |     |   |  |nsarea                       |
    |    |     |   |  |     (nd_cmd_get_config_size)|
    |    |     |   |  |data                         |  config data
    |    |     |   |  |   (void*)                   |  namespace index + namespace label
    |    |     |   |  |dpa                          |  created from namespace label
    |    |     |   |  |   (struct resource)         |  from nvdimm_drvdata->data
    |    |     |   |  +-----------------------------+
    |    |     |   |                                |
    |    |     |   +--------------------------------+
    |    |     |provider_data                       |  = nfit_mem
    |    |     |   (void*)                          |
    |    |     |flush_wpq                           |
    |    |     |   (struct resource*)               |
    |    |     |dwork                               |
    |    |     |   (struct delayed_work)            |
    |    |     |sec.ops                             |
    |    |     |                                    |
    |    |     |                                    |
    |    +-----+------------------------------------+
    |    |memdev_dcr                                |
    |    |memdev_pmem                               |
    |    |memdev_bdw                                |
    |    |     (struct acpi_nfit_memory_map)        |
    |    |                                          |
    |    +------------------------------------------+
    |                                               |
    +-----------------------------------------------+
```

在这个数据结构的部分截取中可以看到，acpi\_nfit\_desc中包含了一个类型为nfit\_mem的链表。而函数acpi\_nfit\_register\_dimms就是根据这个链表来构造硬件相对无关的nvdimm数据。

## nvdimm\_driver

nvdimm对应的是一个物理的dimm，这个设备生成之后就需要去检查并初始化。这个工作由它的驱动nvdimm\_driver来完成。

驱动做的关键工作就是根据硬件信息设置这个数据结构中的dev->driver\_data。

这个结构是一个nvdimm\_drvdata类型，其具体的成员也已经在图中显示。主要解释其中两个内容：

* data: 驱动将硬件上的namespace index和namespace label\_size读取到这段内存
* dpa: 驱动根据上面的data信息，将dimm对应的dpa信息转换成res树

我猜这些信息会留着后续使用，那就等着看吧。
