File Index
Files and directories
Sign in
FILE

virtio_pmem.c

File preview with syntax highlighting.

linux-6.19.14/drivers/nvdimm/virtio_pmem.c C
  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	mutex_init(&vpmem->flush_lock);
 68	vpmem->vdev = vdev;
 69	vdev->priv = vpmem;
 70	err = init_vq(vpmem);
 71	if (err) {
 72		dev_err(&vdev->dev, "failed to initialize virtio pmem vq's\n");
 73		goto out_err;
 74	}
 75
 76	if (virtio_has_feature(vdev, VIRTIO_PMEM_F_SHMEM_REGION)) {
 77		virtio_get_shm_region(vdev, &shm_reg, (u8)VIRTIO_PMEM_SHMEM_REGION_ID);
 78		vpmem->start = shm_reg.addr;
 79		vpmem->size = shm_reg.len;
 80	} else {
 81		virtio_cread_le(vpmem->vdev, struct virtio_pmem_config,
 82				start, &vpmem->start);
 83		virtio_cread_le(vpmem->vdev, struct virtio_pmem_config,
 84				size, &vpmem->size);
 85	}
 86
 87	res.start = vpmem->start;
 88	res.end   = vpmem->start + vpmem->size - 1;
 89	vpmem->nd_desc.provider_name = "virtio-pmem";
 90	vpmem->nd_desc.module = THIS_MODULE;
 91
 92	vpmem->nvdimm_bus = nvdimm_bus_register(&vdev->dev,
 93						&vpmem->nd_desc);
 94	if (!vpmem->nvdimm_bus) {
 95		dev_err(&vdev->dev, "failed to register device with nvdimm_bus\n");
 96		err = -ENXIO;
 97		goto out_vq;
 98	}
 99
100	dev_set_drvdata(&vdev->dev, vpmem->nvdimm_bus);
101
102	ndr_desc.res = &res;
103
104	ndr_desc.numa_node = memory_add_physaddr_to_nid(res.start);
105	ndr_desc.target_node = phys_to_target_node(res.start);
106	if (ndr_desc.target_node == NUMA_NO_NODE) {
107		ndr_desc.target_node = ndr_desc.numa_node;
108		dev_dbg(&vdev->dev, "changing target node from %d to %d",
109			NUMA_NO_NODE, ndr_desc.target_node);
110	}
111
112	ndr_desc.flush = async_pmem_flush;
113	ndr_desc.provider_data = vdev;
114	set_bit(ND_REGION_PAGEMAP, &ndr_desc.flags);
115	set_bit(ND_REGION_ASYNC, &ndr_desc.flags);
116	/*
117	 * The NVDIMM region could be available before the
118	 * virtio_device_ready() that is called by
119	 * virtio_dev_probe(), so we set device ready here.
120	 */
121	virtio_device_ready(vdev);
122	nd_region = nvdimm_pmem_region_create(vpmem->nvdimm_bus, &ndr_desc);
123	if (!nd_region) {
124		dev_err(&vdev->dev, "failed to create nvdimm region\n");
125		err = -ENXIO;
126		goto out_nd;
127	}
128	return 0;
129out_nd:
130	virtio_reset_device(vdev);
131	nvdimm_bus_unregister(vpmem->nvdimm_bus);
132out_vq:
133	vdev->config->del_vqs(vdev);
134out_err:
135	return err;
136}
137
138static void virtio_pmem_remove(struct virtio_device *vdev)
139{
140	struct nvdimm_bus *nvdimm_bus = dev_get_drvdata(&vdev->dev);
141
142	nvdimm_bus_unregister(nvdimm_bus);
143	vdev->config->del_vqs(vdev);
144	virtio_reset_device(vdev);
145}
146
147static int virtio_pmem_freeze(struct virtio_device *vdev)
148{
149	vdev->config->del_vqs(vdev);
150	virtio_reset_device(vdev);
151
152	return 0;
153}
154
155static int virtio_pmem_restore(struct virtio_device *vdev)
156{
157	int ret;
158
159	ret = init_vq(vdev->priv);
160	if (ret) {
161		dev_err(&vdev->dev, "failed to initialize virtio pmem's vq\n");
162		return ret;
163	}
164	virtio_device_ready(vdev);
165
166	return 0;
167}
168
169static unsigned int features[] = {
170	VIRTIO_PMEM_F_SHMEM_REGION,
171};
172
173static struct virtio_driver virtio_pmem_driver = {
174	.feature_table		= features,
175	.feature_table_size	= ARRAY_SIZE(features),
176	.driver.name		= KBUILD_MODNAME,
177	.id_table		= id_table,
178	.validate		= virtio_pmem_validate,
179	.probe			= virtio_pmem_probe,
180	.remove			= virtio_pmem_remove,
181	.freeze			= virtio_pmem_freeze,
182	.restore		= virtio_pmem_restore,
183};
184
185module_virtio_driver(virtio_pmem_driver);
186MODULE_DEVICE_TABLE(virtio, id_table);
187MODULE_DESCRIPTION("Virtio pmem driver");
188MODULE_LICENSE("GPL");
~/ Read-only file preview.