Loading...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 | // 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_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; 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"); |