summaryrefslogtreecommitdiff
path: root/drivers/nvdimm/virtio_pmem.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/nvdimm/virtio_pmem.c')
-rw-r--r--drivers/nvdimm/virtio_pmem.c72
1 files changed, 65 insertions, 7 deletions
diff --git a/drivers/nvdimm/virtio_pmem.c b/drivers/nvdimm/virtio_pmem.c
index 20da455d2ef6..2396d19ce549 100644
--- a/drivers/nvdimm/virtio_pmem.c
+++ b/drivers/nvdimm/virtio_pmem.c
@@ -29,13 +29,27 @@ static int init_vq(struct virtio_pmem *vpmem)
return 0;
};
+static int virtio_pmem_validate(struct virtio_device *vdev)
+{
+ struct virtio_shm_region shm_reg;
+
+ if (virtio_has_feature(vdev, VIRTIO_PMEM_F_SHMEM_REGION) &&
+ !virtio_get_shm_region(vdev, &shm_reg, (u8)VIRTIO_PMEM_SHMEM_REGION_ID)
+ ) {
+ dev_notice(&vdev->dev, "failed to get shared memory region %d\n",
+ VIRTIO_PMEM_SHMEM_REGION_ID);
+ __virtio_clear_bit(vdev, VIRTIO_PMEM_F_SHMEM_REGION);
+ }
+ 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;
+ struct virtio_shm_region shm_reg;
int err = 0;
if (!vdev->config->get) {
@@ -58,10 +72,16 @@ static int virtio_pmem_probe(struct virtio_device *vdev)
goto out_err;
}
- virtio_cread_le(vpmem->vdev, struct virtio_pmem_config,
- start, &vpmem->start);
- virtio_cread_le(vpmem->vdev, struct virtio_pmem_config,
- size, &vpmem->size);
+ if (virtio_has_feature(vdev, VIRTIO_PMEM_F_SHMEM_REGION)) {
+ virtio_get_shm_region(vdev, &shm_reg, (u8)VIRTIO_PMEM_SHMEM_REGION_ID);
+ vpmem->start = shm_reg.addr;
+ vpmem->size = shm_reg.len;
+ } else {
+ virtio_cread_le(vpmem->vdev, struct virtio_pmem_config,
+ start, &vpmem->start);
+ virtio_cread_le(vpmem->vdev, struct virtio_pmem_config,
+ size, &vpmem->size);
+ }
res.start = vpmem->start;
res.end = vpmem->start + vpmem->size - 1;
@@ -79,7 +99,15 @@ static int virtio_pmem_probe(struct virtio_device *vdev)
dev_set_drvdata(&vdev->dev, vpmem->nvdimm_bus);
ndr_desc.res = &res;
- ndr_desc.numa_node = nid;
+
+ ndr_desc.numa_node = memory_add_physaddr_to_nid(res.start);
+ ndr_desc.target_node = phys_to_target_node(res.start);
+ if (ndr_desc.target_node == NUMA_NO_NODE) {
+ ndr_desc.target_node = ndr_desc.numa_node;
+ dev_dbg(&vdev->dev, "changing target node from %d to %d",
+ NUMA_NO_NODE, ndr_desc.target_node);
+ }
+
ndr_desc.flush = async_pmem_flush;
ndr_desc.provider_data = vdev;
set_bit(ND_REGION_PAGEMAP, &ndr_desc.flags);
@@ -115,12 +143,42 @@ static void virtio_pmem_remove(struct virtio_device *vdev)
virtio_reset_device(vdev);
}
+static int virtio_pmem_freeze(struct virtio_device *vdev)
+{
+ vdev->config->del_vqs(vdev);
+ virtio_reset_device(vdev);
+
+ return 0;
+}
+
+static int virtio_pmem_restore(struct virtio_device *vdev)
+{
+ int ret;
+
+ ret = init_vq(vdev->priv);
+ if (ret) {
+ dev_err(&vdev->dev, "failed to initialize virtio pmem's vq\n");
+ return ret;
+ }
+ virtio_device_ready(vdev);
+
+ return 0;
+}
+
+static unsigned int features[] = {
+ VIRTIO_PMEM_F_SHMEM_REGION,
+};
+
static struct virtio_driver virtio_pmem_driver = {
+ .feature_table = features,
+ .feature_table_size = ARRAY_SIZE(features),
.driver.name = KBUILD_MODNAME,
- .driver.owner = THIS_MODULE,
.id_table = id_table,
+ .validate = virtio_pmem_validate,
.probe = virtio_pmem_probe,
.remove = virtio_pmem_remove,
+ .freeze = virtio_pmem_freeze,
+ .restore = virtio_pmem_restore,
};
module_virtio_driver(virtio_pmem_driver);