tcm-sita.c 6.2 KB

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