linux/drivers/nvdimm/virtio_pmem.c
<<
>>
Prefs
   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        int nid = dev_to_node(&vdev->dev);
  36        struct nd_region *nd_region;
  37        struct virtio_pmem *vpmem;
  38        struct resource res;
  39        int err = 0;
  40
  41        if (!vdev->config->get) {
  42                dev_err(&vdev->dev, "%s failure: config access disabled\n",
  43                        __func__);
  44                return -EINVAL;
  45        }
  46
  47        vpmem = devm_kzalloc(&vdev->dev, sizeof(*vpmem), GFP_KERNEL);
  48        if (!vpmem) {
  49                err = -ENOMEM;
  50                goto out_err;
  51        }
  52
  53        vpmem->vdev = vdev;
  54        vdev->priv = vpmem;
  55        err = init_vq(vpmem);
  56        if (err) {
  57                dev_err(&vdev->dev, "failed to initialize virtio pmem vq's\n");
  58                goto out_err;
  59        }
  60
  61        virtio_cread_le(vpmem->vdev, struct virtio_pmem_config,
  62                        start, &vpmem->start);
  63        virtio_cread_le(vpmem->vdev, struct virtio_pmem_config,
  64                        size, &vpmem->size);
  65
  66        res.start = vpmem->start;
  67        res.end   = vpmem->start + vpmem->size - 1;
  68        vpmem->nd_desc.provider_name = "virtio-pmem";
  69        vpmem->nd_desc.module = THIS_MODULE;
  70
  71        vpmem->nvdimm_bus = nvdimm_bus_register(&vdev->dev,
  72                                                &vpmem->nd_desc);
  73        if (!vpmem->nvdimm_bus) {
  74                dev_err(&vdev->dev, "failed to register device with nvdimm_bus\n");
  75                err = -ENXIO;
  76                goto out_vq;
  77        }
  78
  79        dev_set_drvdata(&vdev->dev, vpmem->nvdimm_bus);
  80
  81        ndr_desc.res = &res;
  82        ndr_desc.numa_node = nid;
  83        ndr_desc.flush = async_pmem_flush;
  84        set_bit(ND_REGION_PAGEMAP, &ndr_desc.flags);
  85        set_bit(ND_REGION_ASYNC, &ndr_desc.flags);
  86        nd_region = nvdimm_pmem_region_create(vpmem->nvdimm_bus, &ndr_desc);
  87        if (!nd_region) {
  88                dev_err(&vdev->dev, "failed to create nvdimm region\n");
  89                err = -ENXIO;
  90                goto out_nd;
  91        }
  92        nd_region->provider_data = dev_to_virtio(nd_region->dev.parent->parent);
  93        return 0;
  94out_nd:
  95        nvdimm_bus_unregister(vpmem->nvdimm_bus);
  96out_vq:
  97        vdev->config->del_vqs(vdev);
  98out_err:
  99        return err;
 100}
 101
 102static void virtio_pmem_remove(struct virtio_device *vdev)
 103{
 104        struct nvdimm_bus *nvdimm_bus = dev_get_drvdata(&vdev->dev);
 105
 106        nvdimm_bus_unregister(nvdimm_bus);
 107        vdev->config->del_vqs(vdev);
 108        vdev->config->reset(vdev);
 109}
 110
 111static struct virtio_driver virtio_pmem_driver = {
 112        .driver.name            = KBUILD_MODNAME,
 113        .driver.owner           = THIS_MODULE,
 114        .id_table               = id_table,
 115        .probe                  = virtio_pmem_probe,
 116        .remove                 = virtio_pmem_remove,
 117};
 118
 119module_virtio_driver(virtio_pmem_driver);
 120MODULE_DEVICE_TABLE(virtio, id_table);
 121MODULE_DESCRIPTION("Virtio pmem driver");
 122MODULE_LICENSE("GPL");
 123