tcm-sita.c 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /*
  3. * SImple Tiler Allocator (SiTA): 2D and 1D allocation(reservation) algorithm
  4. *
  5. * Authors: Ravi Ramachandra <[email protected]>,
  6. * Lajos Molnar <[email protected]>
  7. * Andy Gross <[email protected]>
  8. *
  9. * Copyright (C) 2012 Texas Instruments Incorporated - https://www.ti.com/
  10. */
  11. #include <linux/init.h>
  12. #include <linux/module.h>
  13. #include <linux/errno.h>
  14. #include <linux/sched.h>
  15. #include <linux/wait.h>
  16. #include <linux/bitmap.h>
  17. #include <linux/slab.h>
  18. #include "tcm.h"
  19. static unsigned long mask[8];
  20. /*
  21. * pos position in bitmap
  22. * w width in slots
  23. * h height in slots
  24. * map ptr to bitmap
  25. * stride slots in a row
  26. */
  27. static void free_slots(unsigned long pos, u16 w, u16 h,
  28. unsigned long *map, u16 stride)
  29. {
  30. int i;
  31. for (i = 0; i < h; i++, pos += stride)
  32. bitmap_clear(map, pos, w);
  33. }
  34. /*
  35. * w width in slots
  36. * pos ptr to position
  37. * map ptr to bitmap
  38. * num_bits number of bits in bitmap
  39. */
  40. static int r2l_b2t_1d(u16 w, unsigned long *pos, unsigned long *map,
  41. size_t num_bits)
  42. {
  43. unsigned long search_count = 0;
  44. unsigned long bit;
  45. bool area_found = false;
  46. *pos = num_bits - w;
  47. while (search_count < num_bits) {
  48. bit = find_next_bit(map, num_bits, *pos);
  49. if (bit - *pos >= w) {
  50. /* found a long enough free area */
  51. bitmap_set(map, *pos, w);
  52. area_found = true;
  53. break;
  54. }
  55. search_count = num_bits - bit + w;
  56. *pos = bit - w;
  57. }
  58. return (area_found) ? 0 : -ENOMEM;
  59. }
  60. /*
  61. * w = width in slots
  62. * h = height in slots
  63. * a = align in slots (mask, 2^n-1, 0 is unaligned)
  64. * offset = offset in bytes from 4KiB
  65. * pos = position in bitmap for buffer
  66. * map = bitmap ptr
  67. * num_bits = size of bitmap
  68. * stride = bits in one row of container
  69. */
  70. static int l2r_t2b(u16 w, u16 h, u16 a, s16 offset,
  71. unsigned long *pos, unsigned long slot_bytes,
  72. unsigned long *map, size_t num_bits, size_t slot_stride)
  73. {
  74. int i;
  75. unsigned long index;
  76. bool area_free = false;
  77. unsigned long slots_per_band = PAGE_SIZE / slot_bytes;
  78. unsigned long bit_offset = (offset > 0) ? offset / slot_bytes : 0;
  79. unsigned long curr_bit = bit_offset;
  80. /* reset alignment to 1 if we are matching a specific offset */
  81. /* adjust alignment - 1 to get to the format expected in bitmaps */
  82. a = (offset > 0) ? 0 : a - 1;
  83. /* FIXME Return error if slots_per_band > stride */
  84. while (curr_bit < num_bits) {
  85. *pos = bitmap_find_next_zero_area(map, num_bits, curr_bit, w,
  86. a);
  87. /* skip forward if we are not at right offset */
  88. if (bit_offset > 0 && (*pos % slots_per_band != bit_offset)) {
  89. curr_bit = ALIGN(*pos, slots_per_band) + bit_offset;
  90. continue;
  91. }
  92. /* skip forward to next row if we overlap end of row */
  93. if ((*pos % slot_stride) + w > slot_stride) {
  94. curr_bit = ALIGN(*pos, slot_stride) + bit_offset;
  95. continue;
  96. }
  97. /* TODO: Handle overlapping 4K boundaries */
  98. /* break out of look if we will go past end of container */
  99. if ((*pos + slot_stride * h) > num_bits)
  100. break;
  101. /* generate mask that represents out matching pattern */
  102. bitmap_clear(mask, 0, slot_stride);
  103. bitmap_set(mask, (*pos % BITS_PER_LONG), w);
  104. /* assume the area is free until we find an overlap */
  105. area_free = true;
  106. /* check subsequent rows to see if complete area is free */
  107. for (i = 1; i < h; i++) {
  108. index = *pos / BITS_PER_LONG + i * 8;
  109. if (bitmap_intersects(&map[index], mask,
  110. (*pos % BITS_PER_LONG) + w)) {
  111. area_free = false;
  112. break;
  113. }
  114. }
  115. if (area_free)
  116. break;
  117. /* go forward past this match */
  118. if (bit_offset > 0)
  119. curr_bit = ALIGN(*pos, slots_per_band) + bit_offset;
  120. else
  121. curr_bit = *pos + a + 1;
  122. }
  123. if (area_free) {
  124. /* set area as in-use. iterate over rows */
  125. for (i = 0, index = *pos; i < h; i++, index += slot_stride)
  126. bitmap_set(map, index, w);
  127. }
  128. return (area_free) ? 0 : -ENOMEM;
  129. }
  130. static s32 sita_reserve_1d(struct tcm *tcm, u32 num_slots,
  131. struct tcm_area *area)
  132. {
  133. unsigned long pos;
  134. int ret;
  135. spin_lock(&(tcm->lock));
  136. ret = r2l_b2t_1d(num_slots, &pos, tcm->bitmap, tcm->map_size);
  137. if (!ret) {
  138. area->p0.x = pos % tcm->width;
  139. area->p0.y = pos / tcm->width;
  140. area->p1.x = (pos + num_slots - 1) % tcm->width;
  141. area->p1.y = (pos + num_slots - 1) / tcm->width;
  142. }
  143. spin_unlock(&(tcm->lock));
  144. return ret;
  145. }
  146. static s32 sita_reserve_2d(struct tcm *tcm, u16 h, u16 w, u16 align,
  147. s16 offset, u16 slot_bytes,
  148. struct tcm_area *area)
  149. {
  150. unsigned long pos;
  151. int ret;
  152. spin_lock(&(tcm->lock));
  153. ret = l2r_t2b(w, h, align, offset, &pos, slot_bytes, tcm->bitmap,
  154. tcm->map_size, tcm->width);
  155. if (!ret) {
  156. area->p0.x = pos % tcm->width;
  157. area->p0.y = pos / tcm->width;
  158. area->p1.x = area->p0.x + w - 1;
  159. area->p1.y = area->p0.y + h - 1;
  160. }
  161. spin_unlock(&(tcm->lock));
  162. return ret;
  163. }
  164. static void sita_deinit(struct tcm *tcm)
  165. {
  166. kfree(tcm);
  167. }
  168. static s32 sita_free(struct tcm *tcm, struct tcm_area *area)
  169. {
  170. unsigned long pos;
  171. u16 w, h;
  172. pos = area->p0.x + area->p0.y * tcm->width;
  173. if (area->is2d) {
  174. w = area->p1.x - area->p0.x + 1;
  175. h = area->p1.y - area->p0.y + 1;
  176. } else {
  177. w = area->p1.x + area->p1.y * tcm->width - pos + 1;
  178. h = 1;
  179. }
  180. spin_lock(&(tcm->lock));
  181. free_slots(pos, w, h, tcm->bitmap, tcm->width);
  182. spin_unlock(&(tcm->lock));
  183. return 0;
  184. }
  185. struct tcm *sita_init(u16 width, u16 height)
  186. {
  187. struct tcm *tcm;
  188. size_t map_size = BITS_TO_LONGS(width*height) * sizeof(unsigned long);
  189. if (width == 0 || height == 0)
  190. return NULL;
  191. tcm = kzalloc(sizeof(*tcm) + map_size, GFP_KERNEL);
  192. if (!tcm)
  193. goto error;
  194. /* Updating the pointers to SiTA implementation APIs */
  195. tcm->height = height;
  196. tcm->width = width;
  197. tcm->reserve_2d = sita_reserve_2d;
  198. tcm->reserve_1d = sita_reserve_1d;
  199. tcm->free = sita_free;
  200. tcm->deinit = sita_deinit;
  201. spin_lock_init(&tcm->lock);
  202. tcm->bitmap = (unsigned long *)(tcm + 1);
  203. bitmap_clear(tcm->bitmap, 0, width*height);
  204. tcm->map_size = width*height;
  205. return tcm;
  206. error:
  207. return NULL;
  208. }