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_probe(struct virtio_device *vdev)
33{
34	struct nd_region_desc ndr_desc = {};
35	struct nd_region *nd_region;
36	struct virtio_pmem *vpmem;
37	struct resource res;
38	int err = 0;
39
40	if (!vdev->config->get) {
41		dev_err(&vdev->dev, "%s failure: config access disabled\n",
42			__func__);
43		return -EINVAL;
44	}
45
46	vpmem = devm_kzalloc(&vdev->dev, sizeof(*vpmem), GFP_KERNEL);
47	if (!vpmem) {
48		err = -ENOMEM;
49		goto out_err;
50	}
51
52	vpmem->vdev = vdev;
53	vdev->priv = vpmem;
54	err = init_vq(vpmem);
55	if (err) {
56		dev_err(&vdev->dev, "failed to initialize virtio pmem vq's\n");
57		goto out_err;
58	}
59
60	virtio_cread_le(vpmem->vdev, struct virtio_pmem_config,
61			start, &vpmem->start);
62	virtio_cread_le(vpmem->vdev, struct virtio_pmem_config,
63			size, &vpmem->size);
64
65	res.start = vpmem->start;
66	res.end   = vpmem->start + vpmem->size - 1;
67	vpmem->nd_desc.provider_name = "virtio-pmem";
68	vpmem->nd_desc.module = THIS_MODULE;
69
70	vpmem->nvdimm_bus = nvdimm_bus_register(&vdev->dev,
71						&vpmem->nd_desc);
72	if (!vpmem->nvdimm_bus) {
73		dev_err(&vdev->dev, "failed to register device with nvdimm_bus\n");
74		err = -ENXIO;
75		goto out_vq;
76	}
77
78	dev_set_drvdata(&vdev->dev, vpmem->nvdimm_bus);
79
80	ndr_desc.res = &res;
81
82	ndr_desc.numa_node = memory_add_physaddr_to_nid(res.start);
83	ndr_desc.target_node = phys_to_target_node(res.start);
84	if (ndr_desc.target_node == NUMA_NO_NODE) {
85		ndr_desc.target_node = ndr_desc.numa_node;
86		dev_dbg(&vdev->dev, "changing target node from %d to %d",
87			NUMA_NO_NODE, ndr_desc.target_node);
88	}
89
90	ndr_desc.flush = async_pmem_flush;
91	ndr_desc.provider_data = vdev;
92	set_bit(ND_REGION_PAGEMAP, &ndr_desc.flags);
93	set_bit(ND_REGION_ASYNC, &ndr_desc.flags);
94	/*
95	 * The NVDIMM region could be available before the
96	 * virtio_device_ready() that is called by
97	 * virtio_dev_probe(), so we set device ready here.
98	 */
99	virtio_device_ready(vdev);
100	nd_region = nvdimm_pmem_region_create(vpmem->nvdimm_bus, &ndr_desc);
101	if (!nd_region) {
102		dev_err(&vdev->dev, "failed to create nvdimm region\n");
103		err = -ENXIO;
104		goto out_nd;
105	}
106	return 0;
107out_nd:
108	virtio_reset_device(vdev);
109	nvdimm_bus_unregister(vpmem->nvdimm_bus);
110out_vq:
111	vdev->config->del_vqs(vdev);
112out_err:
113	return err;
114}
115
116static void virtio_pmem_remove(struct virtio_device *vdev)
117{
118	struct nvdimm_bus *nvdimm_bus = dev_get_drvdata(&vdev->dev);
119
120	nvdimm_bus_unregister(nvdimm_bus);
121	vdev->config->del_vqs(vdev);
122	virtio_reset_device(vdev);
123}
124
125static struct virtio_driver virtio_pmem_driver = {
126	.driver.name		= KBUILD_MODNAME,
127	.driver.owner		= THIS_MODULE,
128	.id_table		= id_table,
129	.probe			= virtio_pmem_probe,
130	.remove			= virtio_pmem_remove,
131};
132
133module_virtio_driver(virtio_pmem_driver);
134MODULE_DEVICE_TABLE(virtio, id_table);
135MODULE_DESCRIPTION("Virtio pmem driver");
136MODULE_LICENSE("GPL");
137