android_kernel_xiaomi_sm7250/drivers/nvdimm/virtio_pmem.c
Pankaj Gupta 748a437c5c UPSTREAM: virtio-pmem: Add virtio pmem driver
This patch adds virtio-pmem driver for KVM guest.

Guest reads the persistent memory range information from
Qemu over VIRTIO and registers it on nvdimm_bus. It also
creates a nd_region object with the persistent memory
range information so that existing 'nvdimm/pmem' driver
can reserve this into system memory map. This way
'virtio-pmem' driver uses existing functionality of pmem
driver to register persistent memory compatible for DAX
capable filesystems.

This also provides function to perform guest flush over
VIRTIO from 'pmem' driver when userspace performs flush
on DAX memory range.

Signed-off-by: Pankaj Gupta <pagupta@redhat.com>
Reviewed-by: Yuval Shaia <yuval.shaia@oracle.com>
Acked-by: Michael S. Tsirkin <mst@redhat.com>
Acked-by: Jakub Staron <jstaron@google.com>
Tested-by: Jakub Staron <jstaron@google.com>
Reviewed-by: Cornelia Huck <cohuck@redhat.com>
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
(cherry picked from commit 6e84200c0a2994b991259d19450eee561029bf70)
Bug: 146400078
Bug: 148297388
Change-Id: Ie3457fe184f29984d181bc0afa9267e2567a2caf
Signed-off-by: Alistair Delva <adelva@google.com>
2020-01-26 19:04:57 +00:00

123 lines
3.0 KiB
C

// 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(vpmem->vdev, struct virtio_pmem_config,
start, &vpmem->start);
virtio_cread(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");