dfl-afu-region.c 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*
  3. * Driver for FPGA Accelerated Function Unit (AFU) MMIO Region Management
  4. *
  5. * Copyright (C) 2017-2018 Intel Corporation, Inc.
  6. *
  7. * Authors:
  8. * Wu Hao <hao.wu@intel.com>
  9. * Xiao Guangrong <guangrong.xiao@linux.intel.com>
  10. */
  11. #include "dfl-afu.h"
  12. /**
  13. * afu_mmio_region_init - init function for afu mmio region support
  14. * @fdata: afu feature dev data
  15. */
  16. void afu_mmio_region_init(struct dfl_feature_dev_data *fdata)
  17. {
  18. struct dfl_afu *afu = dfl_fpga_fdata_get_private(fdata);
  19. INIT_LIST_HEAD(&afu->regions);
  20. }
  21. #define for_each_region(region, afu) \
  22. list_for_each_entry((region), &(afu)->regions, node)
  23. static struct dfl_afu_mmio_region *get_region_by_index(struct dfl_afu *afu,
  24. u32 region_index)
  25. {
  26. struct dfl_afu_mmio_region *region;
  27. for_each_region(region, afu)
  28. if (region->index == region_index)
  29. return region;
  30. return NULL;
  31. }
  32. /**
  33. * afu_mmio_region_add - add a mmio region to given feature dev.
  34. *
  35. * @fdata: afu feature dev data
  36. * @region_index: region index.
  37. * @region_size: region size.
  38. * @phys: region's physical address of this region.
  39. * @flags: region flags (access permission).
  40. *
  41. * Return: 0 on success, negative error code otherwise.
  42. */
  43. int afu_mmio_region_add(struct dfl_feature_dev_data *fdata,
  44. u32 region_index, u64 region_size, u64 phys, u32 flags)
  45. {
  46. struct device *dev = &fdata->dev->dev;
  47. struct dfl_afu_mmio_region *region;
  48. struct dfl_afu *afu;
  49. int ret = 0;
  50. region = devm_kzalloc(dev, sizeof(*region), GFP_KERNEL);
  51. if (!region)
  52. return -ENOMEM;
  53. region->index = region_index;
  54. region->size = region_size;
  55. region->phys = phys;
  56. region->flags = flags;
  57. mutex_lock(&fdata->lock);
  58. afu = dfl_fpga_fdata_get_private(fdata);
  59. /* check if @index already exists */
  60. if (get_region_by_index(afu, region_index)) {
  61. mutex_unlock(&fdata->lock);
  62. ret = -EEXIST;
  63. goto exit;
  64. }
  65. region_size = PAGE_ALIGN(region_size);
  66. region->offset = afu->region_cur_offset;
  67. list_add(&region->node, &afu->regions);
  68. afu->region_cur_offset += region_size;
  69. afu->num_regions++;
  70. mutex_unlock(&fdata->lock);
  71. return 0;
  72. exit:
  73. devm_kfree(dev, region);
  74. return ret;
  75. }
  76. /**
  77. * afu_mmio_region_destroy - destroy all mmio regions under given feature dev.
  78. * @fdata: afu feature dev data
  79. */
  80. void afu_mmio_region_destroy(struct dfl_feature_dev_data *fdata)
  81. {
  82. struct dfl_afu *afu = dfl_fpga_fdata_get_private(fdata);
  83. struct dfl_afu_mmio_region *tmp, *region;
  84. list_for_each_entry_safe(region, tmp, &afu->regions, node)
  85. devm_kfree(&fdata->dev->dev, region);
  86. }
  87. /**
  88. * afu_mmio_region_get_by_index - find an afu region by index.
  89. * @fdata: afu feature dev data
  90. * @region_index: region index.
  91. * @pregion: ptr to region for result.
  92. *
  93. * Return: 0 on success, negative error code otherwise.
  94. */
  95. int afu_mmio_region_get_by_index(struct dfl_feature_dev_data *fdata,
  96. u32 region_index,
  97. struct dfl_afu_mmio_region *pregion)
  98. {
  99. struct dfl_afu_mmio_region *region;
  100. struct dfl_afu *afu;
  101. int ret = 0;
  102. mutex_lock(&fdata->lock);
  103. afu = dfl_fpga_fdata_get_private(fdata);
  104. region = get_region_by_index(afu, region_index);
  105. if (!region) {
  106. ret = -EINVAL;
  107. goto exit;
  108. }
  109. *pregion = *region;
  110. exit:
  111. mutex_unlock(&fdata->lock);
  112. return ret;
  113. }
  114. /**
  115. * afu_mmio_region_get_by_offset - find an afu mmio region by offset and size
  116. *
  117. * @fdata: afu feature dev data
  118. * @offset: region offset from start of the device fd.
  119. * @size: region size.
  120. * @pregion: ptr to region for result.
  121. *
  122. * Find the region which fully contains the region described by input
  123. * parameters (offset and size) from the feature dev's region linked list.
  124. *
  125. * Return: 0 on success, negative error code otherwise.
  126. */
  127. int afu_mmio_region_get_by_offset(struct dfl_feature_dev_data *fdata,
  128. u64 offset, u64 size,
  129. struct dfl_afu_mmio_region *pregion)
  130. {
  131. struct dfl_afu_mmio_region *region;
  132. struct dfl_afu *afu;
  133. int ret = 0;
  134. mutex_lock(&fdata->lock);
  135. afu = dfl_fpga_fdata_get_private(fdata);
  136. for_each_region(region, afu)
  137. if (region->offset <= offset &&
  138. region->offset + region->size >= offset + size) {
  139. *pregion = *region;
  140. goto exit;
  141. }
  142. ret = -EINVAL;
  143. exit:
  144. mutex_unlock(&fdata->lock);
  145. return ret;
  146. }