virtio_pmem.c 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122
  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. static struct virtio_device_id id_table[] = {
  12. { VIRTIO_ID_PMEM, VIRTIO_DEV_ANY_ID },
  13. { 0 },
  14. };
  15. /* Initialize virt queue */
  16. static int init_vq(struct virtio_pmem *vpmem)
  17. {
  18. /* single vq */
  19. vpmem->req_vq = virtio_find_single_vq(vpmem->vdev,
  20. virtio_pmem_host_ack, "flush_queue");
  21. if (IS_ERR(vpmem->req_vq))
  22. return PTR_ERR(vpmem->req_vq);
  23. spin_lock_init(&vpmem->pmem_lock);
  24. INIT_LIST_HEAD(&vpmem->req_list);
  25. return 0;
  26. };
  27. static int virtio_pmem_probe(struct virtio_device *vdev)
  28. {
  29. struct nd_region_desc ndr_desc = {};
  30. int nid = dev_to_node(&vdev->dev);
  31. struct nd_region *nd_region;
  32. struct virtio_pmem *vpmem;
  33. struct resource res;
  34. int err = 0;
  35. if (!vdev->config->get) {
  36. dev_err(&vdev->dev, "%s failure: config access disabled\n",
  37. __func__);
  38. return -EINVAL;
  39. }
  40. vpmem = devm_kzalloc(&vdev->dev, sizeof(*vpmem), GFP_KERNEL);
  41. if (!vpmem) {
  42. err = -ENOMEM;
  43. goto out_err;
  44. }
  45. vpmem->vdev = vdev;
  46. vdev->priv = vpmem;
  47. err = init_vq(vpmem);
  48. if (err) {
  49. dev_err(&vdev->dev, "failed to initialize virtio pmem vq's\n");
  50. goto out_err;
  51. }
  52. virtio_cread_le(vpmem->vdev, struct virtio_pmem_config,
  53. start, &vpmem->start);
  54. virtio_cread_le(vpmem->vdev, struct virtio_pmem_config,
  55. size, &vpmem->size);
  56. res.start = vpmem->start;
  57. res.end = vpmem->start + vpmem->size - 1;
  58. vpmem->nd_desc.provider_name = "virtio-pmem";
  59. vpmem->nd_desc.module = THIS_MODULE;
  60. vpmem->nvdimm_bus = nvdimm_bus_register(&vdev->dev,
  61. &vpmem->nd_desc);
  62. if (!vpmem->nvdimm_bus) {
  63. dev_err(&vdev->dev, "failed to register device with nvdimm_bus\n");
  64. err = -ENXIO;
  65. goto out_vq;
  66. }
  67. dev_set_drvdata(&vdev->dev, vpmem->nvdimm_bus);
  68. ndr_desc.res = &res;
  69. ndr_desc.numa_node = nid;
  70. ndr_desc.flush = async_pmem_flush;
  71. set_bit(ND_REGION_PAGEMAP, &ndr_desc.flags);
  72. set_bit(ND_REGION_ASYNC, &ndr_desc.flags);
  73. nd_region = nvdimm_pmem_region_create(vpmem->nvdimm_bus, &ndr_desc);
  74. if (!nd_region) {
  75. dev_err(&vdev->dev, "failed to create nvdimm region\n");
  76. err = -ENXIO;
  77. goto out_nd;
  78. }
  79. nd_region->provider_data = dev_to_virtio(nd_region->dev.parent->parent);
  80. return 0;
  81. out_nd:
  82. nvdimm_bus_unregister(vpmem->nvdimm_bus);
  83. out_vq:
  84. vdev->config->del_vqs(vdev);
  85. out_err:
  86. return err;
  87. }
  88. static void virtio_pmem_remove(struct virtio_device *vdev)
  89. {
  90. struct nvdimm_bus *nvdimm_bus = dev_get_drvdata(&vdev->dev);
  91. nvdimm_bus_unregister(nvdimm_bus);
  92. vdev->config->del_vqs(vdev);
  93. vdev->config->reset(vdev);
  94. }
  95. static struct virtio_driver virtio_pmem_driver = {
  96. .driver.name = KBUILD_MODNAME,
  97. .driver.owner = THIS_MODULE,
  98. .id_table = id_table,
  99. .probe = virtio_pmem_probe,
  100. .remove = virtio_pmem_remove,
  101. };
  102. module_virtio_driver(virtio_pmem_driver);
  103. MODULE_DEVICE_TABLE(virtio, id_table);
  104. MODULE_DESCRIPTION("Virtio pmem driver");
  105. MODULE_LICENSE("GPL");