allocator.c 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385
  1. /*
  2. * UWB reservation management.
  3. *
  4. * Copyright (C) 2008 Cambridge Silicon Radio Ltd.
  5. *
  6. * This program is free software; you can redistribute it and/or
  7. * modify it under the terms of the GNU General Public License version
  8. * 2 as published by the Free Software Foundation.
  9. *
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU General Public License
  16. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  17. */
  18. #include <linux/kernel.h>
  19. #include <linux/uwb.h>
  20. #include "uwb-internal.h"
  21. static void uwb_rsv_fill_column_alloc(struct uwb_rsv_alloc_info *ai)
  22. {
  23. int col, mas, safe_mas, unsafe_mas;
  24. unsigned char *bm = ai->bm;
  25. struct uwb_rsv_col_info *ci = ai->ci;
  26. unsigned char c;
  27. for (col = ci->csi.start_col; col < UWB_NUM_ZONES; col += ci->csi.interval) {
  28. safe_mas = ci->csi.safe_mas_per_col;
  29. unsafe_mas = ci->csi.unsafe_mas_per_col;
  30. for (mas = 0; mas < UWB_MAS_PER_ZONE; mas++ ) {
  31. if (bm[col * UWB_MAS_PER_ZONE + mas] == 0) {
  32. if (safe_mas > 0) {
  33. safe_mas--;
  34. c = UWB_RSV_MAS_SAFE;
  35. } else if (unsafe_mas > 0) {
  36. unsafe_mas--;
  37. c = UWB_RSV_MAS_UNSAFE;
  38. } else {
  39. break;
  40. }
  41. bm[col * UWB_MAS_PER_ZONE + mas] = c;
  42. }
  43. }
  44. }
  45. }
  46. static void uwb_rsv_fill_row_alloc(struct uwb_rsv_alloc_info *ai)
  47. {
  48. int mas, col, rows;
  49. unsigned char *bm = ai->bm;
  50. struct uwb_rsv_row_info *ri = &ai->ri;
  51. unsigned char c;
  52. rows = 1;
  53. c = UWB_RSV_MAS_SAFE;
  54. for (mas = UWB_MAS_PER_ZONE - 1; mas >= 0; mas--) {
  55. if (ri->avail[mas] == 1) {
  56. if (rows > ri->used_rows) {
  57. break;
  58. } else if (rows > 7) {
  59. c = UWB_RSV_MAS_UNSAFE;
  60. }
  61. for (col = 0; col < UWB_NUM_ZONES; col++) {
  62. if (bm[col * UWB_NUM_ZONES + mas] != UWB_RSV_MAS_NOT_AVAIL) {
  63. bm[col * UWB_NUM_ZONES + mas] = c;
  64. if(c == UWB_RSV_MAS_SAFE)
  65. ai->safe_allocated_mases++;
  66. else
  67. ai->unsafe_allocated_mases++;
  68. }
  69. }
  70. rows++;
  71. }
  72. }
  73. ai->total_allocated_mases = ai->safe_allocated_mases + ai->unsafe_allocated_mases;
  74. }
  75. /*
  76. * Find the best column set for a given availability, interval, num safe mas and
  77. * num unsafe mas.
  78. *
  79. * The different sets are tried in order as shown below, depending on the interval.
  80. *
  81. * interval = 16
  82. * deep = 0
  83. * set 1 -> { 8 }
  84. * deep = 1
  85. * set 1 -> { 4 }
  86. * set 2 -> { 12 }
  87. * deep = 2
  88. * set 1 -> { 2 }
  89. * set 2 -> { 6 }
  90. * set 3 -> { 10 }
  91. * set 4 -> { 14 }
  92. * deep = 3
  93. * set 1 -> { 1 }
  94. * set 2 -> { 3 }
  95. * set 3 -> { 5 }
  96. * set 4 -> { 7 }
  97. * set 5 -> { 9 }
  98. * set 6 -> { 11 }
  99. * set 7 -> { 13 }
  100. * set 8 -> { 15 }
  101. *
  102. * interval = 8
  103. * deep = 0
  104. * set 1 -> { 4 12 }
  105. * deep = 1
  106. * set 1 -> { 2 10 }
  107. * set 2 -> { 6 14 }
  108. * deep = 2
  109. * set 1 -> { 1 9 }
  110. * set 2 -> { 3 11 }
  111. * set 3 -> { 5 13 }
  112. * set 4 -> { 7 15 }
  113. *
  114. * interval = 4
  115. * deep = 0
  116. * set 1 -> { 2 6 10 14 }
  117. * deep = 1
  118. * set 1 -> { 1 5 9 13 }
  119. * set 2 -> { 3 7 11 15 }
  120. *
  121. * interval = 2
  122. * deep = 0
  123. * set 1 -> { 1 3 5 7 9 11 13 15 }
  124. */
  125. static int uwb_rsv_find_best_column_set(struct uwb_rsv_alloc_info *ai, int interval,
  126. int num_safe_mas, int num_unsafe_mas)
  127. {
  128. struct uwb_rsv_col_info *ci = ai->ci;
  129. struct uwb_rsv_col_set_info *csi = &ci->csi;
  130. struct uwb_rsv_col_set_info tmp_csi;
  131. int deep, set, col, start_col_deep, col_start_set;
  132. int start_col, max_mas_in_set, lowest_max_mas_in_deep;
  133. int n_mas;
  134. int found = UWB_RSV_ALLOC_NOT_FOUND;
  135. tmp_csi.start_col = 0;
  136. start_col_deep = interval;
  137. n_mas = num_unsafe_mas + num_safe_mas;
  138. for (deep = 0; ((interval >> deep) & 0x1) == 0; deep++) {
  139. start_col_deep /= 2;
  140. col_start_set = 0;
  141. lowest_max_mas_in_deep = UWB_MAS_PER_ZONE;
  142. for (set = 1; set <= (1 << deep); set++) {
  143. max_mas_in_set = 0;
  144. start_col = start_col_deep + col_start_set;
  145. for (col = start_col; col < UWB_NUM_ZONES; col += interval) {
  146. if (ci[col].max_avail_safe >= num_safe_mas &&
  147. ci[col].max_avail_unsafe >= n_mas) {
  148. if (ci[col].highest_mas[n_mas] > max_mas_in_set)
  149. max_mas_in_set = ci[col].highest_mas[n_mas];
  150. } else {
  151. max_mas_in_set = 0;
  152. break;
  153. }
  154. }
  155. if ((lowest_max_mas_in_deep > max_mas_in_set) && max_mas_in_set) {
  156. lowest_max_mas_in_deep = max_mas_in_set;
  157. tmp_csi.start_col = start_col;
  158. }
  159. col_start_set += (interval >> deep);
  160. }
  161. if (lowest_max_mas_in_deep < 8) {
  162. csi->start_col = tmp_csi.start_col;
  163. found = UWB_RSV_ALLOC_FOUND;
  164. break;
  165. } else if ((lowest_max_mas_in_deep > 8) &&
  166. (lowest_max_mas_in_deep != UWB_MAS_PER_ZONE) &&
  167. (found == UWB_RSV_ALLOC_NOT_FOUND)) {
  168. csi->start_col = tmp_csi.start_col;
  169. found = UWB_RSV_ALLOC_FOUND;
  170. }
  171. }
  172. if (found == UWB_RSV_ALLOC_FOUND) {
  173. csi->interval = interval;
  174. csi->safe_mas_per_col = num_safe_mas;
  175. csi->unsafe_mas_per_col = num_unsafe_mas;
  176. ai->safe_allocated_mases = (UWB_NUM_ZONES / interval) * num_safe_mas;
  177. ai->unsafe_allocated_mases = (UWB_NUM_ZONES / interval) * num_unsafe_mas;
  178. ai->total_allocated_mases = ai->safe_allocated_mases + ai->unsafe_allocated_mases;
  179. ai->interval = interval;
  180. }
  181. return found;
  182. }
  183. static void get_row_descriptors(struct uwb_rsv_alloc_info *ai)
  184. {
  185. unsigned char *bm = ai->bm;
  186. struct uwb_rsv_row_info *ri = &ai->ri;
  187. int col, mas;
  188. ri->free_rows = 16;
  189. for (mas = 0; mas < UWB_MAS_PER_ZONE; mas ++) {
  190. ri->avail[mas] = 1;
  191. for (col = 1; col < UWB_NUM_ZONES; col++) {
  192. if (bm[col * UWB_NUM_ZONES + mas] == UWB_RSV_MAS_NOT_AVAIL) {
  193. ri->free_rows--;
  194. ri->avail[mas]=0;
  195. break;
  196. }
  197. }
  198. }
  199. }
  200. static void uwb_rsv_fill_column_info(unsigned char *bm, int column, struct uwb_rsv_col_info *rci)
  201. {
  202. int mas;
  203. int block_count = 0, start_block = 0;
  204. int previous_avail = 0;
  205. int available = 0;
  206. int safe_mas_in_row[UWB_MAS_PER_ZONE] = {
  207. 8, 7, 6, 5, 4, 4, 4, 4, 4, 4, 4, 4, 4, 3, 2, 1,
  208. };
  209. rci->max_avail_safe = 0;
  210. for (mas = 0; mas < UWB_MAS_PER_ZONE; mas ++) {
  211. if (!bm[column * UWB_NUM_ZONES + mas]) {
  212. available++;
  213. rci->max_avail_unsafe = available;
  214. rci->highest_mas[available] = mas;
  215. if (previous_avail) {
  216. block_count++;
  217. if ((block_count > safe_mas_in_row[start_block]) &&
  218. (!rci->max_avail_safe))
  219. rci->max_avail_safe = available - 1;
  220. } else {
  221. previous_avail = 1;
  222. start_block = mas;
  223. block_count = 1;
  224. }
  225. } else {
  226. previous_avail = 0;
  227. }
  228. }
  229. if (!rci->max_avail_safe)
  230. rci->max_avail_safe = rci->max_avail_unsafe;
  231. }
  232. static void get_column_descriptors(struct uwb_rsv_alloc_info *ai)
  233. {
  234. unsigned char *bm = ai->bm;
  235. struct uwb_rsv_col_info *ci = ai->ci;
  236. int col;
  237. for (col = 1; col < UWB_NUM_ZONES; col++) {
  238. uwb_rsv_fill_column_info(bm, col, &ci[col]);
  239. }
  240. }
  241. static int uwb_rsv_find_best_row_alloc(struct uwb_rsv_alloc_info *ai)
  242. {
  243. int n_rows;
  244. int max_rows = ai->max_mas / UWB_USABLE_MAS_PER_ROW;
  245. int min_rows = ai->min_mas / UWB_USABLE_MAS_PER_ROW;
  246. if (ai->min_mas % UWB_USABLE_MAS_PER_ROW)
  247. min_rows++;
  248. for (n_rows = max_rows; n_rows >= min_rows; n_rows--) {
  249. if (n_rows <= ai->ri.free_rows) {
  250. ai->ri.used_rows = n_rows;
  251. ai->interval = 1; /* row reservation */
  252. uwb_rsv_fill_row_alloc(ai);
  253. return UWB_RSV_ALLOC_FOUND;
  254. }
  255. }
  256. return UWB_RSV_ALLOC_NOT_FOUND;
  257. }
  258. static int uwb_rsv_find_best_col_alloc(struct uwb_rsv_alloc_info *ai, int interval)
  259. {
  260. int n_safe, n_unsafe, n_mas;
  261. int n_column = UWB_NUM_ZONES / interval;
  262. int max_per_zone = ai->max_mas / n_column;
  263. int min_per_zone = ai->min_mas / n_column;
  264. if (ai->min_mas % n_column)
  265. min_per_zone++;
  266. if (min_per_zone > UWB_MAS_PER_ZONE) {
  267. return UWB_RSV_ALLOC_NOT_FOUND;
  268. }
  269. if (max_per_zone > UWB_MAS_PER_ZONE) {
  270. max_per_zone = UWB_MAS_PER_ZONE;
  271. }
  272. for (n_mas = max_per_zone; n_mas >= min_per_zone; n_mas--) {
  273. if (uwb_rsv_find_best_column_set(ai, interval, 0, n_mas) == UWB_RSV_ALLOC_NOT_FOUND)
  274. continue;
  275. for (n_safe = n_mas; n_safe >= 0; n_safe--) {
  276. n_unsafe = n_mas - n_safe;
  277. if (uwb_rsv_find_best_column_set(ai, interval, n_safe, n_unsafe) == UWB_RSV_ALLOC_FOUND) {
  278. uwb_rsv_fill_column_alloc(ai);
  279. return UWB_RSV_ALLOC_FOUND;
  280. }
  281. }
  282. }
  283. return UWB_RSV_ALLOC_NOT_FOUND;
  284. }
  285. int uwb_rsv_find_best_allocation(struct uwb_rsv *rsv, struct uwb_mas_bm *available,
  286. struct uwb_mas_bm *result)
  287. {
  288. struct uwb_rsv_alloc_info *ai;
  289. int interval;
  290. int bit_index;
  291. ai = kzalloc(sizeof(struct uwb_rsv_alloc_info), GFP_KERNEL);
  292. ai->min_mas = rsv->min_mas;
  293. ai->max_mas = rsv->max_mas;
  294. ai->max_interval = rsv->max_interval;
  295. /* fill the not available vector from the available bm */
  296. for (bit_index = 0; bit_index < UWB_NUM_MAS; bit_index++) {
  297. if (!test_bit(bit_index, available->bm))
  298. ai->bm[bit_index] = UWB_RSV_MAS_NOT_AVAIL;
  299. }
  300. if (ai->max_interval == 1) {
  301. get_row_descriptors(ai);
  302. if (uwb_rsv_find_best_row_alloc(ai) == UWB_RSV_ALLOC_FOUND)
  303. goto alloc_found;
  304. else
  305. goto alloc_not_found;
  306. }
  307. get_column_descriptors(ai);
  308. for (interval = 16; interval >= 2; interval>>=1) {
  309. if (interval > ai->max_interval)
  310. continue;
  311. if (uwb_rsv_find_best_col_alloc(ai, interval) == UWB_RSV_ALLOC_FOUND)
  312. goto alloc_found;
  313. }
  314. /* try row reservation if no column is found */
  315. get_row_descriptors(ai);
  316. if (uwb_rsv_find_best_row_alloc(ai) == UWB_RSV_ALLOC_FOUND)
  317. goto alloc_found;
  318. else
  319. goto alloc_not_found;
  320. alloc_found:
  321. bitmap_zero(result->bm, UWB_NUM_MAS);
  322. bitmap_zero(result->unsafe_bm, UWB_NUM_MAS);
  323. /* fill the safe and unsafe bitmaps */
  324. for (bit_index = 0; bit_index < UWB_NUM_MAS; bit_index++) {
  325. if (ai->bm[bit_index] == UWB_RSV_MAS_SAFE)
  326. set_bit(bit_index, result->bm);
  327. else if (ai->bm[bit_index] == UWB_RSV_MAS_UNSAFE)
  328. set_bit(bit_index, result->unsafe_bm);
  329. }
  330. bitmap_or(result->bm, result->bm, result->unsafe_bm, UWB_NUM_MAS);
  331. result->safe = ai->safe_allocated_mases;
  332. result->unsafe = ai->unsafe_allocated_mases;
  333. kfree(ai);
  334. return UWB_RSV_ALLOC_FOUND;
  335. alloc_not_found:
  336. kfree(ai);
  337. return UWB_RSV_ALLOC_NOT_FOUND;
  338. }