virtio_pmem.c 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163
  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_validate(struct virtio_device *vdev)
  28. {
  29. struct virtio_shm_region shm_reg;
  30. if (virtio_has_feature(vdev, VIRTIO_PMEM_F_SHMEM_REGION) &&
  31. !virtio_get_shm_region(vdev, &shm_reg, (u8)VIRTIO_PMEM_SHMEM_REGION_ID)
  32. ) {
  33. dev_notice(&vdev->dev, "failed to get shared memory region %d\n",
  34. VIRTIO_PMEM_SHMEM_REGION_ID);
  35. __virtio_clear_bit(vdev, VIRTIO_PMEM_F_SHMEM_REGION);
  36. }
  37. return 0;
  38. }
  39. static int virtio_pmem_probe(struct virtio_device *vdev)
  40. {
  41. struct nd_region_desc ndr_desc = {};
  42. struct nd_region *nd_region;
  43. struct virtio_pmem *vpmem;
  44. struct resource res;
  45. struct virtio_shm_region shm_reg;
  46. int err = 0;
  47. if (!vdev->config->get) {
  48. dev_err(&vdev->dev, "%s failure: config access disabled\n",
  49. __func__);
  50. return -EINVAL;
  51. }
  52. vpmem = devm_kzalloc(&vdev->dev, sizeof(*vpmem), GFP_KERNEL);
  53. if (!vpmem) {
  54. err = -ENOMEM;
  55. goto out_err;
  56. }
  57. vpmem->vdev = vdev;
  58. vdev->priv = vpmem;
  59. err = init_vq(vpmem);
  60. if (err) {
  61. dev_err(&vdev->dev, "failed to initialize virtio pmem vq's\n");
  62. goto out_err;
  63. }
  64. if (virtio_has_feature(vdev, VIRTIO_PMEM_F_SHMEM_REGION)) {
  65. virtio_get_shm_region(vdev, &shm_reg, (u8)VIRTIO_PMEM_SHMEM_REGION_ID);
  66. vpmem->start = shm_reg.addr;
  67. vpmem->size = shm_reg.len;
  68. } else {
  69. virtio_cread_le(vpmem->vdev, struct virtio_pmem_config,
  70. start, &vpmem->start);
  71. virtio_cread_le(vpmem->vdev, struct virtio_pmem_config,
  72. size, &vpmem->size);
  73. }
  74. res.start = vpmem->start;
  75. res.end = vpmem->start + vpmem->size - 1;
  76. vpmem->nd_desc.provider_name = "virtio-pmem";
  77. vpmem->nd_desc.module = THIS_MODULE;
  78. vpmem->nvdimm_bus = nvdimm_bus_register(&vdev->dev,
  79. &vpmem->nd_desc);
  80. if (!vpmem->nvdimm_bus) {
  81. dev_err(&vdev->dev, "failed to register device with nvdimm_bus\n");
  82. err = -ENXIO;
  83. goto out_vq;
  84. }
  85. dev_set_drvdata(&vdev->dev, vpmem->nvdimm_bus);
  86. ndr_desc.res = &res;
  87. ndr_desc.numa_node = memory_add_physaddr_to_nid(res.start);
  88. ndr_desc.target_node = phys_to_target_node(res.start);
  89. if (ndr_desc.target_node == NUMA_NO_NODE) {
  90. ndr_desc.target_node = ndr_desc.numa_node;
  91. dev_dbg(&vdev->dev, "changing target node from %d to %d",
  92. NUMA_NO_NODE, ndr_desc.target_node);
  93. }
  94. ndr_desc.flush = async_pmem_flush;
  95. ndr_desc.provider_data = vdev;
  96. set_bit(ND_REGION_PAGEMAP, &ndr_desc.flags);
  97. set_bit(ND_REGION_ASYNC, &ndr_desc.flags);
  98. /*
  99. * The NVDIMM region could be available before the
  100. * virtio_device_ready() that is called by
  101. * virtio_dev_probe(), so we set device ready here.
  102. */
  103. virtio_device_ready(vdev);
  104. nd_region = nvdimm_pmem_region_create(vpmem->nvdimm_bus, &ndr_desc);
  105. if (!nd_region) {
  106. dev_err(&vdev->dev, "failed to create nvdimm region\n");
  107. err = -ENXIO;
  108. goto out_nd;
  109. }
  110. return 0;
  111. out_nd:
  112. virtio_reset_device(vdev);
  113. nvdimm_bus_unregister(vpmem->nvdimm_bus);
  114. out_vq:
  115. vdev->config->del_vqs(vdev);
  116. out_err:
  117. return err;
  118. }
  119. static void virtio_pmem_remove(struct virtio_device *vdev)
  120. {
  121. struct nvdimm_bus *nvdimm_bus = dev_get_drvdata(&vdev->dev);
  122. nvdimm_bus_unregister(nvdimm_bus);
  123. vdev->config->del_vqs(vdev);
  124. virtio_reset_device(vdev);
  125. }
  126. static unsigned int features[] = {
  127. VIRTIO_PMEM_F_SHMEM_REGION,
  128. };
  129. static struct virtio_driver virtio_pmem_driver = {
  130. .feature_table = features,
  131. .feature_table_size = ARRAY_SIZE(features),
  132. .driver.name = KBUILD_MODNAME,
  133. .id_table = id_table,
  134. .validate = virtio_pmem_validate,
  135. .probe = virtio_pmem_probe,
  136. .remove = virtio_pmem_remove,
  137. };
  138. module_virtio_driver(virtio_pmem_driver);
  139. MODULE_DEVICE_TABLE(virtio, id_table);
  140. MODULE_DESCRIPTION("Virtio pmem driver");
  141. MODULE_LICENSE("GPL");