xref: /linux/drivers/nvdimm/virtio_pmem.c (revision 7f063b2f17eaba2a35e251aa53627f2a70d536e2)
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * virtio_pmem.c: Virtio pmem Driver
4  *
5  * Discovers persistent memory range information
6  * from host and registers the virtual pmem device
7  * with libnvdimm core.
8  */
9 #include "virtio_pmem.h"
10 #include "nd.h"
11 
12 static struct virtio_device_id id_table[] = {
13 	{ VIRTIO_ID_PMEM, VIRTIO_DEV_ANY_ID },
14 	{ 0 },
15 };
16 
17  /* Initialize virt queue */
init_vq(struct virtio_pmem * vpmem)18 static int init_vq(struct virtio_pmem *vpmem)
19 {
20 	int err;
21 
22 	/* single vq */
23 	vpmem->req_vq = virtio_find_single_vq(vpmem->vdev,
24 					virtio_pmem_host_ack, "flush_queue");
25 	if (IS_ERR(vpmem->req_vq)) {
26 		err = PTR_ERR(vpmem->req_vq);
27 		vpmem->req_vq = NULL;
28 		return err;
29 	}
30 
31 	spin_lock_init(&vpmem->pmem_lock);
32 	INIT_LIST_HEAD(&vpmem->req_list);
33 	vpmem->req_inflight = NULL;
34 	WRITE_ONCE(vpmem->broken, false);
35 
36 	return 0;
37 };
38 
virtio_pmem_del_vqs(struct virtio_pmem * vpmem)39 static void virtio_pmem_del_vqs(struct virtio_pmem *vpmem)
40 {
41 	if (!vpmem->req_vq)
42 		return;
43 
44 	vpmem->vdev->config->del_vqs(vpmem->vdev);
45 	vpmem->req_vq = NULL;
46 }
47 
virtio_pmem_validate(struct virtio_device * vdev)48 static int virtio_pmem_validate(struct virtio_device *vdev)
49 {
50 	struct virtio_shm_region shm_reg;
51 
52 	if (virtio_has_feature(vdev, VIRTIO_PMEM_F_SHMEM_REGION) &&
53 		!virtio_get_shm_region(vdev, &shm_reg, (u8)VIRTIO_PMEM_SHMEM_REGION_ID)
54 	) {
55 		dev_notice(&vdev->dev, "failed to get shared memory region %d\n",
56 				VIRTIO_PMEM_SHMEM_REGION_ID);
57 		__virtio_clear_bit(vdev, VIRTIO_PMEM_F_SHMEM_REGION);
58 	}
59 	return 0;
60 }
61 
virtio_pmem_probe(struct virtio_device * vdev)62 static int virtio_pmem_probe(struct virtio_device *vdev)
63 {
64 	struct nd_region_desc ndr_desc = {};
65 	struct nd_region *nd_region;
66 	struct virtio_pmem *vpmem;
67 	struct resource res;
68 	struct virtio_shm_region shm_reg;
69 	int err = 0;
70 
71 	if (!vdev->config->get) {
72 		dev_err(&vdev->dev, "%s failure: config access disabled\n",
73 			__func__);
74 		return -EINVAL;
75 	}
76 
77 	vpmem = devm_kzalloc(&vdev->dev, sizeof(*vpmem), GFP_KERNEL);
78 	if (!vpmem) {
79 		err = -ENOMEM;
80 		goto out_err;
81 	}
82 
83 	mutex_init(&vpmem->flush_lock);
84 	vpmem->vdev = vdev;
85 	vdev->priv = vpmem;
86 	vpmem->flush_wq = alloc_ordered_workqueue("virtio-pmem-flush",
87 						  WQ_MEM_RECLAIM);
88 	if (!vpmem->flush_wq) {
89 		err = -ENOMEM;
90 		goto out_err;
91 	}
92 
93 	err = init_vq(vpmem);
94 	if (err) {
95 		dev_err(&vdev->dev, "failed to initialize virtio pmem vq's\n");
96 		goto out_wq;
97 	}
98 
99 	if (virtio_has_feature(vdev, VIRTIO_PMEM_F_SHMEM_REGION)) {
100 		virtio_get_shm_region(vdev, &shm_reg, (u8)VIRTIO_PMEM_SHMEM_REGION_ID);
101 		vpmem->start = shm_reg.addr;
102 		vpmem->size = shm_reg.len;
103 	} else {
104 		virtio_cread_le(vpmem->vdev, struct virtio_pmem_config,
105 				start, &vpmem->start);
106 		virtio_cread_le(vpmem->vdev, struct virtio_pmem_config,
107 				size, &vpmem->size);
108 	}
109 
110 	res.start = vpmem->start;
111 	res.end   = vpmem->start + vpmem->size - 1;
112 	vpmem->nd_desc.provider_name = "virtio-pmem";
113 	vpmem->nd_desc.module = THIS_MODULE;
114 
115 	vpmem->nvdimm_bus = nvdimm_bus_register(&vdev->dev,
116 						&vpmem->nd_desc);
117 	if (!vpmem->nvdimm_bus) {
118 		dev_err(&vdev->dev, "failed to register device with nvdimm_bus\n");
119 		err = -ENXIO;
120 		goto out_vq;
121 	}
122 
123 	dev_set_drvdata(&vdev->dev, vpmem->nvdimm_bus);
124 
125 	ndr_desc.res = &res;
126 
127 	ndr_desc.numa_node = memory_add_physaddr_to_nid(res.start);
128 	ndr_desc.target_node = phys_to_target_node(res.start);
129 	if (ndr_desc.target_node == NUMA_NO_NODE) {
130 		ndr_desc.target_node = ndr_desc.numa_node;
131 		dev_dbg(&vdev->dev, "changing target node from %d to %d",
132 			NUMA_NO_NODE, ndr_desc.target_node);
133 	}
134 
135 	ndr_desc.flush = async_pmem_flush;
136 	ndr_desc.provider_data = vdev;
137 	set_bit(ND_REGION_PAGEMAP, &ndr_desc.flags);
138 	set_bit(ND_REGION_ASYNC, &ndr_desc.flags);
139 	/*
140 	 * The NVDIMM region could be available before the
141 	 * virtio_device_ready() that is called by
142 	 * virtio_dev_probe(), so we set device ready here.
143 	 */
144 	virtio_device_ready(vdev);
145 	nd_region = nvdimm_pmem_region_create(vpmem->nvdimm_bus, &ndr_desc);
146 	if (!nd_region) {
147 		dev_err(&vdev->dev, "failed to create nvdimm region\n");
148 		err = -ENXIO;
149 		goto out_nd;
150 	}
151 	return 0;
152 out_nd:
153 	virtio_reset_device(vdev);
154 	nvdimm_bus_unregister(vpmem->nvdimm_bus);
155 out_vq:
156 	virtio_pmem_del_vqs(vpmem);
157 out_wq:
158 	destroy_workqueue(vpmem->flush_wq);
159 out_err:
160 	return err;
161 }
162 
virtio_pmem_remove(struct virtio_device * vdev)163 static void virtio_pmem_remove(struct virtio_device *vdev)
164 {
165 	struct nvdimm_bus *nvdimm_bus = dev_get_drvdata(&vdev->dev);
166 	struct virtio_pmem *vpmem = vdev->priv;
167 	unsigned long flags;
168 
169 	spin_lock_irqsave(&vpmem->pmem_lock, flags);
170 	virtio_pmem_mark_broken(vpmem);
171 	spin_unlock_irqrestore(&vpmem->pmem_lock, flags);
172 
173 	drain_workqueue(vpmem->flush_wq);
174 	virtio_reset_device(vdev);
175 
176 	spin_lock_irqsave(&vpmem->pmem_lock, flags);
177 	virtio_pmem_drain(vpmem);
178 	spin_unlock_irqrestore(&vpmem->pmem_lock, flags);
179 
180 	nvdimm_bus_unregister(nvdimm_bus);
181 	virtio_pmem_del_vqs(vpmem);
182 	destroy_workqueue(vpmem->flush_wq);
183 }
184 
virtio_pmem_freeze(struct virtio_device * vdev)185 static int virtio_pmem_freeze(struct virtio_device *vdev)
186 {
187 	struct virtio_pmem *vpmem = vdev->priv;
188 	unsigned long flags;
189 
190 	spin_lock_irqsave(&vpmem->pmem_lock, flags);
191 	virtio_pmem_mark_broken(vpmem);
192 	spin_unlock_irqrestore(&vpmem->pmem_lock, flags);
193 
194 	drain_workqueue(vpmem->flush_wq);
195 	virtio_reset_device(vdev);
196 
197 	spin_lock_irqsave(&vpmem->pmem_lock, flags);
198 	virtio_pmem_drain(vpmem);
199 	spin_unlock_irqrestore(&vpmem->pmem_lock, flags);
200 
201 	virtio_pmem_del_vqs(vpmem);
202 
203 	return 0;
204 }
205 
virtio_pmem_restore(struct virtio_device * vdev)206 static int virtio_pmem_restore(struct virtio_device *vdev)
207 {
208 	int ret;
209 
210 	ret = init_vq(vdev->priv);
211 	if (ret) {
212 		dev_err(&vdev->dev, "failed to initialize virtio pmem's vq\n");
213 		return ret;
214 	}
215 	virtio_device_ready(vdev);
216 
217 	return 0;
218 }
219 
220 static unsigned int features[] = {
221 	VIRTIO_PMEM_F_SHMEM_REGION,
222 };
223 
224 static struct virtio_driver virtio_pmem_driver = {
225 	.feature_table		= features,
226 	.feature_table_size	= ARRAY_SIZE(features),
227 	.driver.name		= KBUILD_MODNAME,
228 	.id_table		= id_table,
229 	.validate		= virtio_pmem_validate,
230 	.probe			= virtio_pmem_probe,
231 	.remove			= virtio_pmem_remove,
232 	.freeze			= virtio_pmem_freeze,
233 	.restore		= virtio_pmem_restore,
234 };
235 
236 module_virtio_driver(virtio_pmem_driver);
237 MODULE_DEVICE_TABLE(virtio, id_table);
238 MODULE_DESCRIPTION("Virtio pmem driver");
239 MODULE_LICENSE("GPL");
240