Linux Audio

Check our new training course

Loading...
Note: File does not exist in v4.17.
  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
 12static struct virtio_device_id id_table[] = {
 13	{ VIRTIO_ID_PMEM, VIRTIO_DEV_ANY_ID },
 14	{ 0 },
 15};
 16
 17 /* Initialize virt queue */
 18static int init_vq(struct virtio_pmem *vpmem)
 19{
 20	/* single vq */
 21	vpmem->req_vq = virtio_find_single_vq(vpmem->vdev,
 22					virtio_pmem_host_ack, "flush_queue");
 23	if (IS_ERR(vpmem->req_vq))
 24		return PTR_ERR(vpmem->req_vq);
 25
 26	spin_lock_init(&vpmem->pmem_lock);
 27	INIT_LIST_HEAD(&vpmem->req_list);
 28
 29	return 0;
 30};
 31
 32static int virtio_pmem_validate(struct virtio_device *vdev)
 33{
 34	struct virtio_shm_region shm_reg;
 35
 36	if (virtio_has_feature(vdev, VIRTIO_PMEM_F_SHMEM_REGION) &&
 37		!virtio_get_shm_region(vdev, &shm_reg, (u8)VIRTIO_PMEM_SHMEM_REGION_ID)
 38	) {
 39		dev_notice(&vdev->dev, "failed to get shared memory region %d\n",
 40				VIRTIO_PMEM_SHMEM_REGION_ID);
 41		__virtio_clear_bit(vdev, VIRTIO_PMEM_F_SHMEM_REGION);
 42	}
 43	return 0;
 44}
 45
 46static int virtio_pmem_probe(struct virtio_device *vdev)
 47{
 48	struct nd_region_desc ndr_desc = {};
 49	struct nd_region *nd_region;
 50	struct virtio_pmem *vpmem;
 51	struct resource res;
 52	struct virtio_shm_region shm_reg;
 53	int err = 0;
 54
 55	if (!vdev->config->get) {
 56		dev_err(&vdev->dev, "%s failure: config access disabled\n",
 57			__func__);
 58		return -EINVAL;
 59	}
 60
 61	vpmem = devm_kzalloc(&vdev->dev, sizeof(*vpmem), GFP_KERNEL);
 62	if (!vpmem) {
 63		err = -ENOMEM;
 64		goto out_err;
 65	}
 66
 67	vpmem->vdev = vdev;
 68	vdev->priv = vpmem;
 69	err = init_vq(vpmem);
 70	if (err) {
 71		dev_err(&vdev->dev, "failed to initialize virtio pmem vq's\n");
 72		goto out_err;
 73	}
 74
 75	if (virtio_has_feature(vdev, VIRTIO_PMEM_F_SHMEM_REGION)) {
 76		virtio_get_shm_region(vdev, &shm_reg, (u8)VIRTIO_PMEM_SHMEM_REGION_ID);
 77		vpmem->start = shm_reg.addr;
 78		vpmem->size = shm_reg.len;
 79	} else {
 80		virtio_cread_le(vpmem->vdev, struct virtio_pmem_config,
 81				start, &vpmem->start);
 82		virtio_cread_le(vpmem->vdev, struct virtio_pmem_config,
 83				size, &vpmem->size);
 84	}
 85
 86	res.start = vpmem->start;
 87	res.end   = vpmem->start + vpmem->size - 1;
 88	vpmem->nd_desc.provider_name = "virtio-pmem";
 89	vpmem->nd_desc.module = THIS_MODULE;
 90
 91	vpmem->nvdimm_bus = nvdimm_bus_register(&vdev->dev,
 92						&vpmem->nd_desc);
 93	if (!vpmem->nvdimm_bus) {
 94		dev_err(&vdev->dev, "failed to register device with nvdimm_bus\n");
 95		err = -ENXIO;
 96		goto out_vq;
 97	}
 98
 99	dev_set_drvdata(&vdev->dev, vpmem->nvdimm_bus);
100
101	ndr_desc.res = &res;
102
103	ndr_desc.numa_node = memory_add_physaddr_to_nid(res.start);
104	ndr_desc.target_node = phys_to_target_node(res.start);
105	if (ndr_desc.target_node == NUMA_NO_NODE) {
106		ndr_desc.target_node = ndr_desc.numa_node;
107		dev_dbg(&vdev->dev, "changing target node from %d to %d",
108			NUMA_NO_NODE, ndr_desc.target_node);
109	}
110
111	ndr_desc.flush = async_pmem_flush;
112	ndr_desc.provider_data = vdev;
113	set_bit(ND_REGION_PAGEMAP, &ndr_desc.flags);
114	set_bit(ND_REGION_ASYNC, &ndr_desc.flags);
115	/*
116	 * The NVDIMM region could be available before the
117	 * virtio_device_ready() that is called by
118	 * virtio_dev_probe(), so we set device ready here.
119	 */
120	virtio_device_ready(vdev);
121	nd_region = nvdimm_pmem_region_create(vpmem->nvdimm_bus, &ndr_desc);
122	if (!nd_region) {
123		dev_err(&vdev->dev, "failed to create nvdimm region\n");
124		err = -ENXIO;
125		goto out_nd;
126	}
127	return 0;
128out_nd:
129	virtio_reset_device(vdev);
130	nvdimm_bus_unregister(vpmem->nvdimm_bus);
131out_vq:
132	vdev->config->del_vqs(vdev);
133out_err:
134	return err;
135}
136
137static void virtio_pmem_remove(struct virtio_device *vdev)
138{
139	struct nvdimm_bus *nvdimm_bus = dev_get_drvdata(&vdev->dev);
140
141	nvdimm_bus_unregister(nvdimm_bus);
142	vdev->config->del_vqs(vdev);
143	virtio_reset_device(vdev);
144}
145
146static int virtio_pmem_freeze(struct virtio_device *vdev)
147{
148	vdev->config->del_vqs(vdev);
149	virtio_reset_device(vdev);
150
151	return 0;
152}
153
154static int virtio_pmem_restore(struct virtio_device *vdev)
155{
156	int ret;
157
158	ret = init_vq(vdev->priv);
159	if (ret) {
160		dev_err(&vdev->dev, "failed to initialize virtio pmem's vq\n");
161		return ret;
162	}
163	virtio_device_ready(vdev);
164
165	return 0;
166}
167
168static unsigned int features[] = {
169	VIRTIO_PMEM_F_SHMEM_REGION,
170};
171
172static struct virtio_driver virtio_pmem_driver = {
173	.feature_table		= features,
174	.feature_table_size	= ARRAY_SIZE(features),
175	.driver.name		= KBUILD_MODNAME,
176	.id_table		= id_table,
177	.validate		= virtio_pmem_validate,
178	.probe			= virtio_pmem_probe,
179	.remove			= virtio_pmem_remove,
180	.freeze			= virtio_pmem_freeze,
181	.restore		= virtio_pmem_restore,
182};
183
184module_virtio_driver(virtio_pmem_driver);
185MODULE_DEVICE_TABLE(virtio, id_table);
186MODULE_DESCRIPTION("Virtio pmem driver");
187MODULE_LICENSE("GPL");