Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * virtio_pmem.c: Virtio pmem Driver
0004  *
0005  * Discovers persistent memory range information
0006  * from host and registers the virtual pmem device
0007  * with libnvdimm core.
0008  */
0009 #include "virtio_pmem.h"
0010 #include "nd.h"
0011 
0012 static struct virtio_device_id id_table[] = {
0013     { VIRTIO_ID_PMEM, VIRTIO_DEV_ANY_ID },
0014     { 0 },
0015 };
0016 
0017  /* Initialize virt queue */
0018 static int init_vq(struct virtio_pmem *vpmem)
0019 {
0020     /* single vq */
0021     vpmem->req_vq = virtio_find_single_vq(vpmem->vdev,
0022                     virtio_pmem_host_ack, "flush_queue");
0023     if (IS_ERR(vpmem->req_vq))
0024         return PTR_ERR(vpmem->req_vq);
0025 
0026     spin_lock_init(&vpmem->pmem_lock);
0027     INIT_LIST_HEAD(&vpmem->req_list);
0028 
0029     return 0;
0030 };
0031 
0032 static int virtio_pmem_probe(struct virtio_device *vdev)
0033 {
0034     struct nd_region_desc ndr_desc = {};
0035     int nid = dev_to_node(&vdev->dev);
0036     struct nd_region *nd_region;
0037     struct virtio_pmem *vpmem;
0038     struct resource res;
0039     int err = 0;
0040 
0041     if (!vdev->config->get) {
0042         dev_err(&vdev->dev, "%s failure: config access disabled\n",
0043             __func__);
0044         return -EINVAL;
0045     }
0046 
0047     vpmem = devm_kzalloc(&vdev->dev, sizeof(*vpmem), GFP_KERNEL);
0048     if (!vpmem) {
0049         err = -ENOMEM;
0050         goto out_err;
0051     }
0052 
0053     vpmem->vdev = vdev;
0054     vdev->priv = vpmem;
0055     err = init_vq(vpmem);
0056     if (err) {
0057         dev_err(&vdev->dev, "failed to initialize virtio pmem vq's\n");
0058         goto out_err;
0059     }
0060 
0061     virtio_cread_le(vpmem->vdev, struct virtio_pmem_config,
0062             start, &vpmem->start);
0063     virtio_cread_le(vpmem->vdev, struct virtio_pmem_config,
0064             size, &vpmem->size);
0065 
0066     res.start = vpmem->start;
0067     res.end   = vpmem->start + vpmem->size - 1;
0068     vpmem->nd_desc.provider_name = "virtio-pmem";
0069     vpmem->nd_desc.module = THIS_MODULE;
0070 
0071     vpmem->nvdimm_bus = nvdimm_bus_register(&vdev->dev,
0072                         &vpmem->nd_desc);
0073     if (!vpmem->nvdimm_bus) {
0074         dev_err(&vdev->dev, "failed to register device with nvdimm_bus\n");
0075         err = -ENXIO;
0076         goto out_vq;
0077     }
0078 
0079     dev_set_drvdata(&vdev->dev, vpmem->nvdimm_bus);
0080 
0081     ndr_desc.res = &res;
0082     ndr_desc.numa_node = nid;
0083     ndr_desc.flush = async_pmem_flush;
0084     ndr_desc.provider_data = vdev;
0085     set_bit(ND_REGION_PAGEMAP, &ndr_desc.flags);
0086     set_bit(ND_REGION_ASYNC, &ndr_desc.flags);
0087     /*
0088      * The NVDIMM region could be available before the
0089      * virtio_device_ready() that is called by
0090      * virtio_dev_probe(), so we set device ready here.
0091      */
0092     virtio_device_ready(vdev);
0093     nd_region = nvdimm_pmem_region_create(vpmem->nvdimm_bus, &ndr_desc);
0094     if (!nd_region) {
0095         dev_err(&vdev->dev, "failed to create nvdimm region\n");
0096         err = -ENXIO;
0097         goto out_nd;
0098     }
0099     return 0;
0100 out_nd:
0101     virtio_reset_device(vdev);
0102     nvdimm_bus_unregister(vpmem->nvdimm_bus);
0103 out_vq:
0104     vdev->config->del_vqs(vdev);
0105 out_err:
0106     return err;
0107 }
0108 
0109 static void virtio_pmem_remove(struct virtio_device *vdev)
0110 {
0111     struct nvdimm_bus *nvdimm_bus = dev_get_drvdata(&vdev->dev);
0112 
0113     nvdimm_bus_unregister(nvdimm_bus);
0114     vdev->config->del_vqs(vdev);
0115     virtio_reset_device(vdev);
0116 }
0117 
0118 static struct virtio_driver virtio_pmem_driver = {
0119     .driver.name        = KBUILD_MODNAME,
0120     .driver.owner       = THIS_MODULE,
0121     .id_table       = id_table,
0122     .probe          = virtio_pmem_probe,
0123     .remove         = virtio_pmem_remove,
0124 };
0125 
0126 module_virtio_driver(virtio_pmem_driver);
0127 MODULE_DEVICE_TABLE(virtio, id_table);
0128 MODULE_DESCRIPTION("Virtio pmem driver");
0129 MODULE_LICENSE("GPL");