iotlb.c 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /* Copyright (C) 2020 Red Hat, Inc.
  3. * Author: Jason Wang <[email protected]>
  4. *
  5. * IOTLB implementation for vhost.
  6. */
  7. #include <linux/slab.h>
  8. #include <linux/vhost_iotlb.h>
  9. #include <linux/module.h>
  10. #define MOD_VERSION "0.1"
  11. #define MOD_DESC "VHOST IOTLB"
  12. #define MOD_AUTHOR "Jason Wang <[email protected]>"
  13. #define MOD_LICENSE "GPL v2"
  14. #define START(map) ((map)->start)
  15. #define LAST(map) ((map)->last)
  16. INTERVAL_TREE_DEFINE(struct vhost_iotlb_map,
  17. rb, __u64, __subtree_last,
  18. START, LAST, static inline, vhost_iotlb_itree);
  19. /**
  20. * vhost_iotlb_map_free - remove a map node and free it
  21. * @iotlb: the IOTLB
  22. * @map: the map that want to be remove and freed
  23. */
  24. void vhost_iotlb_map_free(struct vhost_iotlb *iotlb,
  25. struct vhost_iotlb_map *map)
  26. {
  27. vhost_iotlb_itree_remove(map, &iotlb->root);
  28. list_del(&map->link);
  29. kfree(map);
  30. iotlb->nmaps--;
  31. }
  32. EXPORT_SYMBOL_GPL(vhost_iotlb_map_free);
  33. /**
  34. * vhost_iotlb_add_range_ctx - add a new range to vhost IOTLB
  35. * @iotlb: the IOTLB
  36. * @start: start of the IOVA range
  37. * @last: last of IOVA range
  38. * @addr: the address that is mapped to @start
  39. * @perm: access permission of this range
  40. * @opaque: the opaque pointer for the new mapping
  41. *
  42. * Returns an error last is smaller than start or memory allocation
  43. * fails
  44. */
  45. int vhost_iotlb_add_range_ctx(struct vhost_iotlb *iotlb,
  46. u64 start, u64 last,
  47. u64 addr, unsigned int perm,
  48. void *opaque)
  49. {
  50. struct vhost_iotlb_map *map;
  51. if (last < start)
  52. return -EFAULT;
  53. /* If the range being mapped is [0, ULONG_MAX], split it into two entries
  54. * otherwise its size would overflow u64.
  55. */
  56. if (start == 0 && last == ULONG_MAX) {
  57. u64 mid = last / 2;
  58. int err = vhost_iotlb_add_range_ctx(iotlb, start, mid, addr,
  59. perm, opaque);
  60. if (err)
  61. return err;
  62. addr += mid + 1;
  63. start = mid + 1;
  64. }
  65. if (iotlb->limit &&
  66. iotlb->nmaps == iotlb->limit &&
  67. iotlb->flags & VHOST_IOTLB_FLAG_RETIRE) {
  68. map = list_first_entry(&iotlb->list, typeof(*map), link);
  69. vhost_iotlb_map_free(iotlb, map);
  70. }
  71. map = kmalloc(sizeof(*map), GFP_ATOMIC);
  72. if (!map)
  73. return -ENOMEM;
  74. map->start = start;
  75. map->size = last - start + 1;
  76. map->last = last;
  77. map->addr = addr;
  78. map->perm = perm;
  79. map->opaque = opaque;
  80. iotlb->nmaps++;
  81. vhost_iotlb_itree_insert(map, &iotlb->root);
  82. INIT_LIST_HEAD(&map->link);
  83. list_add_tail(&map->link, &iotlb->list);
  84. return 0;
  85. }
  86. EXPORT_SYMBOL_GPL(vhost_iotlb_add_range_ctx);
  87. int vhost_iotlb_add_range(struct vhost_iotlb *iotlb,
  88. u64 start, u64 last,
  89. u64 addr, unsigned int perm)
  90. {
  91. return vhost_iotlb_add_range_ctx(iotlb, start, last,
  92. addr, perm, NULL);
  93. }
  94. EXPORT_SYMBOL_GPL(vhost_iotlb_add_range);
  95. /**
  96. * vhost_iotlb_del_range - delete overlapped ranges from vhost IOTLB
  97. * @iotlb: the IOTLB
  98. * @start: start of the IOVA range
  99. * @last: last of IOVA range
  100. */
  101. void vhost_iotlb_del_range(struct vhost_iotlb *iotlb, u64 start, u64 last)
  102. {
  103. struct vhost_iotlb_map *map;
  104. while ((map = vhost_iotlb_itree_iter_first(&iotlb->root,
  105. start, last)))
  106. vhost_iotlb_map_free(iotlb, map);
  107. }
  108. EXPORT_SYMBOL_GPL(vhost_iotlb_del_range);
  109. /**
  110. * vhost_iotlb_init - initialize a vhost IOTLB
  111. * @iotlb: the IOTLB that needs to be initialized
  112. * @limit: maximum number of IOTLB entries
  113. * @flags: VHOST_IOTLB_FLAG_XXX
  114. */
  115. void vhost_iotlb_init(struct vhost_iotlb *iotlb, unsigned int limit,
  116. unsigned int flags)
  117. {
  118. iotlb->root = RB_ROOT_CACHED;
  119. iotlb->limit = limit;
  120. iotlb->nmaps = 0;
  121. iotlb->flags = flags;
  122. INIT_LIST_HEAD(&iotlb->list);
  123. }
  124. EXPORT_SYMBOL_GPL(vhost_iotlb_init);
  125. /**
  126. * vhost_iotlb_alloc - add a new vhost IOTLB
  127. * @limit: maximum number of IOTLB entries
  128. * @flags: VHOST_IOTLB_FLAG_XXX
  129. *
  130. * Returns an error is memory allocation fails
  131. */
  132. struct vhost_iotlb *vhost_iotlb_alloc(unsigned int limit, unsigned int flags)
  133. {
  134. struct vhost_iotlb *iotlb = kzalloc(sizeof(*iotlb), GFP_KERNEL);
  135. if (!iotlb)
  136. return NULL;
  137. vhost_iotlb_init(iotlb, limit, flags);
  138. return iotlb;
  139. }
  140. EXPORT_SYMBOL_GPL(vhost_iotlb_alloc);
  141. /**
  142. * vhost_iotlb_reset - reset vhost IOTLB (free all IOTLB entries)
  143. * @iotlb: the IOTLB to be reset
  144. */
  145. void vhost_iotlb_reset(struct vhost_iotlb *iotlb)
  146. {
  147. vhost_iotlb_del_range(iotlb, 0ULL, 0ULL - 1);
  148. }
  149. EXPORT_SYMBOL_GPL(vhost_iotlb_reset);
  150. /**
  151. * vhost_iotlb_free - reset and free vhost IOTLB
  152. * @iotlb: the IOTLB to be freed
  153. */
  154. void vhost_iotlb_free(struct vhost_iotlb *iotlb)
  155. {
  156. if (iotlb) {
  157. vhost_iotlb_reset(iotlb);
  158. kfree(iotlb);
  159. }
  160. }
  161. EXPORT_SYMBOL_GPL(vhost_iotlb_free);
  162. /**
  163. * vhost_iotlb_itree_first - return the first overlapped range
  164. * @iotlb: the IOTLB
  165. * @start: start of IOVA range
  166. * @last: last byte in IOVA range
  167. */
  168. struct vhost_iotlb_map *
  169. vhost_iotlb_itree_first(struct vhost_iotlb *iotlb, u64 start, u64 last)
  170. {
  171. return vhost_iotlb_itree_iter_first(&iotlb->root, start, last);
  172. }
  173. EXPORT_SYMBOL_GPL(vhost_iotlb_itree_first);
  174. /**
  175. * vhost_iotlb_itree_next - return the next overlapped range
  176. * @map: the starting map node
  177. * @start: start of IOVA range
  178. * @last: last byte IOVA range
  179. */
  180. struct vhost_iotlb_map *
  181. vhost_iotlb_itree_next(struct vhost_iotlb_map *map, u64 start, u64 last)
  182. {
  183. return vhost_iotlb_itree_iter_next(map, start, last);
  184. }
  185. EXPORT_SYMBOL_GPL(vhost_iotlb_itree_next);
  186. MODULE_VERSION(MOD_VERSION);
  187. MODULE_DESCRIPTION(MOD_DESC);
  188. MODULE_AUTHOR(MOD_AUTHOR);
  189. MODULE_LICENSE(MOD_LICENSE);