hc
2025-02-14 bbb9540dc49f70f6b703d1c8d1b85fa5f602d86e
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
// SPDX-License-Identifier: GPL-2.0
/*
 * virtio_pmem.c: Virtio pmem Driver
 *
 * Discovers persistent memory range information
 * from host and registers the virtual pmem device
 * with libnvdimm core.
 */
#include "virtio_pmem.h"
#include "nd.h"
 
static struct virtio_device_id id_table[] = {
   { VIRTIO_ID_PMEM, VIRTIO_DEV_ANY_ID },
   { 0 },
};
 
 /* Initialize virt queue */
static int init_vq(struct virtio_pmem *vpmem)
{
   /* single vq */
   vpmem->req_vq = virtio_find_single_vq(vpmem->vdev,
                   virtio_pmem_host_ack, "flush_queue");
   if (IS_ERR(vpmem->req_vq))
       return PTR_ERR(vpmem->req_vq);
 
   spin_lock_init(&vpmem->pmem_lock);
   INIT_LIST_HEAD(&vpmem->req_list);
 
   return 0;
};
 
static int virtio_pmem_probe(struct virtio_device *vdev)
{
   struct nd_region_desc ndr_desc = {};
   int nid = dev_to_node(&vdev->dev);
   struct nd_region *nd_region;
   struct virtio_pmem *vpmem;
   struct resource res;
   int err = 0;
 
   if (!vdev->config->get) {
       dev_err(&vdev->dev, "%s failure: config access disabled\n",
           __func__);
       return -EINVAL;
   }
 
   vpmem = devm_kzalloc(&vdev->dev, sizeof(*vpmem), GFP_KERNEL);
   if (!vpmem) {
       err = -ENOMEM;
       goto out_err;
   }
 
   vpmem->vdev = vdev;
   vdev->priv = vpmem;
   err = init_vq(vpmem);
   if (err) {
       dev_err(&vdev->dev, "failed to initialize virtio pmem vq's\n");
       goto out_err;
   }
 
   virtio_cread_le(vpmem->vdev, struct virtio_pmem_config,
           start, &vpmem->start);
   virtio_cread_le(vpmem->vdev, struct virtio_pmem_config,
           size, &vpmem->size);
 
   res.start = vpmem->start;
   res.end   = vpmem->start + vpmem->size - 1;
   vpmem->nd_desc.provider_name = "virtio-pmem";
   vpmem->nd_desc.module = THIS_MODULE;
 
   vpmem->nvdimm_bus = nvdimm_bus_register(&vdev->dev,
                       &vpmem->nd_desc);
   if (!vpmem->nvdimm_bus) {
       dev_err(&vdev->dev, "failed to register device with nvdimm_bus\n");
       err = -ENXIO;
       goto out_vq;
   }
 
   dev_set_drvdata(&vdev->dev, vpmem->nvdimm_bus);
 
   ndr_desc.res = &res;
   ndr_desc.numa_node = nid;
   ndr_desc.flush = async_pmem_flush;
   set_bit(ND_REGION_PAGEMAP, &ndr_desc.flags);
   set_bit(ND_REGION_ASYNC, &ndr_desc.flags);
   nd_region = nvdimm_pmem_region_create(vpmem->nvdimm_bus, &ndr_desc);
   if (!nd_region) {
       dev_err(&vdev->dev, "failed to create nvdimm region\n");
       err = -ENXIO;
       goto out_nd;
   }
   nd_region->provider_data = dev_to_virtio(nd_region->dev.parent->parent);
   return 0;
out_nd:
   nvdimm_bus_unregister(vpmem->nvdimm_bus);
out_vq:
   vdev->config->del_vqs(vdev);
out_err:
   return err;
}
 
static void virtio_pmem_remove(struct virtio_device *vdev)
{
   struct nvdimm_bus *nvdimm_bus = dev_get_drvdata(&vdev->dev);
 
   nvdimm_bus_unregister(nvdimm_bus);
   vdev->config->del_vqs(vdev);
   vdev->config->reset(vdev);
}
 
static struct virtio_driver virtio_pmem_driver = {
   .driver.name        = KBUILD_MODNAME,
   .driver.owner        = THIS_MODULE,
   .id_table        = id_table,
   .probe            = virtio_pmem_probe,
   .remove            = virtio_pmem_remove,
};
 
module_virtio_driver(virtio_pmem_driver);
MODULE_DEVICE_TABLE(virtio, id_table);
MODULE_DESCRIPTION("Virtio pmem driver");
MODULE_LICENSE("GPL");