drm_buddy.c 30 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331
  1. // SPDX-License-Identifier: MIT
  2. /*
  3. * Copyright © 2021 Intel Corporation
  4. */
  5. #include <kunit/test-bug.h>
  6. #include <linux/export.h>
  7. #include <linux/kmemleak.h>
  8. #include <linux/module.h>
  9. #include <linux/sizes.h>
  10. #include <drm/drm_buddy.h>
  11. #include <drm/drm_print.h>
  12. enum drm_buddy_free_tree {
  13. DRM_BUDDY_CLEAR_TREE = 0,
  14. DRM_BUDDY_DIRTY_TREE,
  15. DRM_BUDDY_MAX_FREE_TREES,
  16. };
  17. static struct kmem_cache *slab_blocks;
  18. #define for_each_free_tree(tree) \
  19. for ((tree) = 0; (tree) < DRM_BUDDY_MAX_FREE_TREES; (tree)++)
  20. static struct drm_buddy_block *drm_block_alloc(struct drm_buddy *mm,
  21. struct drm_buddy_block *parent,
  22. unsigned int order,
  23. u64 offset)
  24. {
  25. struct drm_buddy_block *block;
  26. BUG_ON(order > DRM_BUDDY_MAX_ORDER);
  27. block = kmem_cache_zalloc(slab_blocks, GFP_KERNEL);
  28. if (!block)
  29. return NULL;
  30. block->header = offset;
  31. block->header |= order;
  32. block->parent = parent;
  33. RB_CLEAR_NODE(&block->rb);
  34. BUG_ON(block->header & DRM_BUDDY_HEADER_UNUSED);
  35. return block;
  36. }
  37. static void drm_block_free(struct drm_buddy *mm,
  38. struct drm_buddy_block *block)
  39. {
  40. kmem_cache_free(slab_blocks, block);
  41. }
  42. static enum drm_buddy_free_tree
  43. get_block_tree(struct drm_buddy_block *block)
  44. {
  45. return drm_buddy_block_is_clear(block) ?
  46. DRM_BUDDY_CLEAR_TREE : DRM_BUDDY_DIRTY_TREE;
  47. }
  48. static struct drm_buddy_block *
  49. rbtree_get_free_block(const struct rb_node *node)
  50. {
  51. return node ? rb_entry(node, struct drm_buddy_block, rb) : NULL;
  52. }
  53. static struct drm_buddy_block *
  54. rbtree_last_free_block(struct rb_root *root)
  55. {
  56. return rbtree_get_free_block(rb_last(root));
  57. }
  58. static bool rbtree_is_empty(struct rb_root *root)
  59. {
  60. return RB_EMPTY_ROOT(root);
  61. }
  62. static bool drm_buddy_block_offset_less(const struct drm_buddy_block *block,
  63. const struct drm_buddy_block *node)
  64. {
  65. return drm_buddy_block_offset(block) < drm_buddy_block_offset(node);
  66. }
  67. static bool rbtree_block_offset_less(struct rb_node *block,
  68. const struct rb_node *node)
  69. {
  70. return drm_buddy_block_offset_less(rbtree_get_free_block(block),
  71. rbtree_get_free_block(node));
  72. }
  73. static void rbtree_insert(struct drm_buddy *mm,
  74. struct drm_buddy_block *block,
  75. enum drm_buddy_free_tree tree)
  76. {
  77. rb_add(&block->rb,
  78. &mm->free_trees[tree][drm_buddy_block_order(block)],
  79. rbtree_block_offset_less);
  80. }
  81. static void rbtree_remove(struct drm_buddy *mm,
  82. struct drm_buddy_block *block)
  83. {
  84. unsigned int order = drm_buddy_block_order(block);
  85. enum drm_buddy_free_tree tree;
  86. struct rb_root *root;
  87. tree = get_block_tree(block);
  88. root = &mm->free_trees[tree][order];
  89. rb_erase(&block->rb, root);
  90. RB_CLEAR_NODE(&block->rb);
  91. }
  92. static void clear_reset(struct drm_buddy_block *block)
  93. {
  94. block->header &= ~DRM_BUDDY_HEADER_CLEAR;
  95. }
  96. static void mark_cleared(struct drm_buddy_block *block)
  97. {
  98. block->header |= DRM_BUDDY_HEADER_CLEAR;
  99. }
  100. static void mark_allocated(struct drm_buddy *mm,
  101. struct drm_buddy_block *block)
  102. {
  103. block->header &= ~DRM_BUDDY_HEADER_STATE;
  104. block->header |= DRM_BUDDY_ALLOCATED;
  105. rbtree_remove(mm, block);
  106. }
  107. static void mark_free(struct drm_buddy *mm,
  108. struct drm_buddy_block *block)
  109. {
  110. enum drm_buddy_free_tree tree;
  111. block->header &= ~DRM_BUDDY_HEADER_STATE;
  112. block->header |= DRM_BUDDY_FREE;
  113. tree = get_block_tree(block);
  114. rbtree_insert(mm, block, tree);
  115. }
  116. static void mark_split(struct drm_buddy *mm,
  117. struct drm_buddy_block *block)
  118. {
  119. block->header &= ~DRM_BUDDY_HEADER_STATE;
  120. block->header |= DRM_BUDDY_SPLIT;
  121. rbtree_remove(mm, block);
  122. }
  123. static inline bool overlaps(u64 s1, u64 e1, u64 s2, u64 e2)
  124. {
  125. return s1 <= e2 && e1 >= s2;
  126. }
  127. static inline bool contains(u64 s1, u64 e1, u64 s2, u64 e2)
  128. {
  129. return s1 <= s2 && e1 >= e2;
  130. }
  131. static struct drm_buddy_block *
  132. __get_buddy(struct drm_buddy_block *block)
  133. {
  134. struct drm_buddy_block *parent;
  135. parent = block->parent;
  136. if (!parent)
  137. return NULL;
  138. if (parent->left == block)
  139. return parent->right;
  140. return parent->left;
  141. }
  142. static unsigned int __drm_buddy_free(struct drm_buddy *mm,
  143. struct drm_buddy_block *block,
  144. bool force_merge)
  145. {
  146. struct drm_buddy_block *parent;
  147. unsigned int order;
  148. while ((parent = block->parent)) {
  149. struct drm_buddy_block *buddy;
  150. buddy = __get_buddy(block);
  151. if (!drm_buddy_block_is_free(buddy))
  152. break;
  153. if (!force_merge) {
  154. /*
  155. * Check the block and its buddy clear state and exit
  156. * the loop if they both have the dissimilar state.
  157. */
  158. if (drm_buddy_block_is_clear(block) !=
  159. drm_buddy_block_is_clear(buddy))
  160. break;
  161. if (drm_buddy_block_is_clear(block))
  162. mark_cleared(parent);
  163. }
  164. rbtree_remove(mm, buddy);
  165. if (force_merge && drm_buddy_block_is_clear(buddy))
  166. mm->clear_avail -= drm_buddy_block_size(mm, buddy);
  167. drm_block_free(mm, block);
  168. drm_block_free(mm, buddy);
  169. block = parent;
  170. }
  171. order = drm_buddy_block_order(block);
  172. mark_free(mm, block);
  173. return order;
  174. }
  175. static int __force_merge(struct drm_buddy *mm,
  176. u64 start,
  177. u64 end,
  178. unsigned int min_order)
  179. {
  180. unsigned int tree, order;
  181. int i;
  182. if (!min_order)
  183. return -ENOMEM;
  184. if (min_order > mm->max_order)
  185. return -EINVAL;
  186. for_each_free_tree(tree) {
  187. for (i = min_order - 1; i >= 0; i--) {
  188. struct rb_node *iter = rb_last(&mm->free_trees[tree][i]);
  189. while (iter) {
  190. struct drm_buddy_block *block, *buddy;
  191. u64 block_start, block_end;
  192. block = rbtree_get_free_block(iter);
  193. iter = rb_prev(iter);
  194. if (!block || !block->parent)
  195. continue;
  196. block_start = drm_buddy_block_offset(block);
  197. block_end = block_start + drm_buddy_block_size(mm, block) - 1;
  198. if (!contains(start, end, block_start, block_end))
  199. continue;
  200. buddy = __get_buddy(block);
  201. if (!drm_buddy_block_is_free(buddy))
  202. continue;
  203. WARN_ON(drm_buddy_block_is_clear(block) ==
  204. drm_buddy_block_is_clear(buddy));
  205. /*
  206. * Advance to the next node when the current node is the buddy,
  207. * as freeing the block will also remove its buddy from the tree.
  208. */
  209. if (iter == &buddy->rb)
  210. iter = rb_prev(iter);
  211. rbtree_remove(mm, block);
  212. if (drm_buddy_block_is_clear(block))
  213. mm->clear_avail -= drm_buddy_block_size(mm, block);
  214. order = __drm_buddy_free(mm, block, true);
  215. if (order >= min_order)
  216. return 0;
  217. }
  218. }
  219. }
  220. return -ENOMEM;
  221. }
  222. /**
  223. * drm_buddy_init - init memory manager
  224. *
  225. * @mm: DRM buddy manager to initialize
  226. * @size: size in bytes to manage
  227. * @chunk_size: minimum page size in bytes for our allocations
  228. *
  229. * Initializes the memory manager and its resources.
  230. *
  231. * Returns:
  232. * 0 on success, error code on failure.
  233. */
  234. int drm_buddy_init(struct drm_buddy *mm, u64 size, u64 chunk_size)
  235. {
  236. unsigned int i, j, root_count = 0;
  237. u64 offset = 0;
  238. if (size < chunk_size)
  239. return -EINVAL;
  240. if (chunk_size < SZ_4K)
  241. return -EINVAL;
  242. if (!is_power_of_2(chunk_size))
  243. return -EINVAL;
  244. size = round_down(size, chunk_size);
  245. mm->size = size;
  246. mm->avail = size;
  247. mm->clear_avail = 0;
  248. mm->chunk_size = chunk_size;
  249. mm->max_order = ilog2(size) - ilog2(chunk_size);
  250. BUG_ON(mm->max_order > DRM_BUDDY_MAX_ORDER);
  251. mm->free_trees = kmalloc_objs(*mm->free_trees, DRM_BUDDY_MAX_FREE_TREES);
  252. if (!mm->free_trees)
  253. return -ENOMEM;
  254. for_each_free_tree(i) {
  255. mm->free_trees[i] = kmalloc_objs(struct rb_root,
  256. mm->max_order + 1);
  257. if (!mm->free_trees[i])
  258. goto out_free_tree;
  259. for (j = 0; j <= mm->max_order; ++j)
  260. mm->free_trees[i][j] = RB_ROOT;
  261. }
  262. mm->n_roots = hweight64(size);
  263. mm->roots = kmalloc_objs(struct drm_buddy_block *, mm->n_roots);
  264. if (!mm->roots)
  265. goto out_free_tree;
  266. /*
  267. * Split into power-of-two blocks, in case we are given a size that is
  268. * not itself a power-of-two.
  269. */
  270. do {
  271. struct drm_buddy_block *root;
  272. unsigned int order;
  273. u64 root_size;
  274. order = ilog2(size) - ilog2(chunk_size);
  275. root_size = chunk_size << order;
  276. root = drm_block_alloc(mm, NULL, order, offset);
  277. if (!root)
  278. goto out_free_roots;
  279. mark_free(mm, root);
  280. BUG_ON(root_count > mm->max_order);
  281. BUG_ON(drm_buddy_block_size(mm, root) < chunk_size);
  282. mm->roots[root_count] = root;
  283. offset += root_size;
  284. size -= root_size;
  285. root_count++;
  286. } while (size);
  287. return 0;
  288. out_free_roots:
  289. while (root_count--)
  290. drm_block_free(mm, mm->roots[root_count]);
  291. kfree(mm->roots);
  292. out_free_tree:
  293. while (i--)
  294. kfree(mm->free_trees[i]);
  295. kfree(mm->free_trees);
  296. return -ENOMEM;
  297. }
  298. EXPORT_SYMBOL(drm_buddy_init);
  299. /**
  300. * drm_buddy_fini - tear down the memory manager
  301. *
  302. * @mm: DRM buddy manager to free
  303. *
  304. * Cleanup memory manager resources and the freetree
  305. */
  306. void drm_buddy_fini(struct drm_buddy *mm)
  307. {
  308. u64 root_size, size, start;
  309. unsigned int order;
  310. int i;
  311. size = mm->size;
  312. for (i = 0; i < mm->n_roots; ++i) {
  313. order = ilog2(size) - ilog2(mm->chunk_size);
  314. start = drm_buddy_block_offset(mm->roots[i]);
  315. __force_merge(mm, start, start + size, order);
  316. if (WARN_ON(!drm_buddy_block_is_free(mm->roots[i])))
  317. kunit_fail_current_test("buddy_fini() root");
  318. drm_block_free(mm, mm->roots[i]);
  319. root_size = mm->chunk_size << order;
  320. size -= root_size;
  321. }
  322. WARN_ON(mm->avail != mm->size);
  323. for_each_free_tree(i)
  324. kfree(mm->free_trees[i]);
  325. kfree(mm->free_trees);
  326. kfree(mm->roots);
  327. }
  328. EXPORT_SYMBOL(drm_buddy_fini);
  329. static int split_block(struct drm_buddy *mm,
  330. struct drm_buddy_block *block)
  331. {
  332. unsigned int block_order = drm_buddy_block_order(block) - 1;
  333. u64 offset = drm_buddy_block_offset(block);
  334. BUG_ON(!drm_buddy_block_is_free(block));
  335. BUG_ON(!drm_buddy_block_order(block));
  336. block->left = drm_block_alloc(mm, block, block_order, offset);
  337. if (!block->left)
  338. return -ENOMEM;
  339. block->right = drm_block_alloc(mm, block, block_order,
  340. offset + (mm->chunk_size << block_order));
  341. if (!block->right) {
  342. drm_block_free(mm, block->left);
  343. return -ENOMEM;
  344. }
  345. mark_split(mm, block);
  346. if (drm_buddy_block_is_clear(block)) {
  347. mark_cleared(block->left);
  348. mark_cleared(block->right);
  349. clear_reset(block);
  350. }
  351. mark_free(mm, block->left);
  352. mark_free(mm, block->right);
  353. return 0;
  354. }
  355. /**
  356. * drm_get_buddy - get buddy address
  357. *
  358. * @block: DRM buddy block
  359. *
  360. * Returns the corresponding buddy block for @block, or NULL
  361. * if this is a root block and can't be merged further.
  362. * Requires some kind of locking to protect against
  363. * any concurrent allocate and free operations.
  364. */
  365. struct drm_buddy_block *
  366. drm_get_buddy(struct drm_buddy_block *block)
  367. {
  368. return __get_buddy(block);
  369. }
  370. EXPORT_SYMBOL(drm_get_buddy);
  371. /**
  372. * drm_buddy_reset_clear - reset blocks clear state
  373. *
  374. * @mm: DRM buddy manager
  375. * @is_clear: blocks clear state
  376. *
  377. * Reset the clear state based on @is_clear value for each block
  378. * in the freetree.
  379. */
  380. void drm_buddy_reset_clear(struct drm_buddy *mm, bool is_clear)
  381. {
  382. enum drm_buddy_free_tree src_tree, dst_tree;
  383. u64 root_size, size, start;
  384. unsigned int order;
  385. int i;
  386. size = mm->size;
  387. for (i = 0; i < mm->n_roots; ++i) {
  388. order = ilog2(size) - ilog2(mm->chunk_size);
  389. start = drm_buddy_block_offset(mm->roots[i]);
  390. __force_merge(mm, start, start + size, order);
  391. root_size = mm->chunk_size << order;
  392. size -= root_size;
  393. }
  394. src_tree = is_clear ? DRM_BUDDY_DIRTY_TREE : DRM_BUDDY_CLEAR_TREE;
  395. dst_tree = is_clear ? DRM_BUDDY_CLEAR_TREE : DRM_BUDDY_DIRTY_TREE;
  396. for (i = 0; i <= mm->max_order; ++i) {
  397. struct rb_root *root = &mm->free_trees[src_tree][i];
  398. struct drm_buddy_block *block, *tmp;
  399. rbtree_postorder_for_each_entry_safe(block, tmp, root, rb) {
  400. rbtree_remove(mm, block);
  401. if (is_clear) {
  402. mark_cleared(block);
  403. mm->clear_avail += drm_buddy_block_size(mm, block);
  404. } else {
  405. clear_reset(block);
  406. mm->clear_avail -= drm_buddy_block_size(mm, block);
  407. }
  408. rbtree_insert(mm, block, dst_tree);
  409. }
  410. }
  411. }
  412. EXPORT_SYMBOL(drm_buddy_reset_clear);
  413. /**
  414. * drm_buddy_free_block - free a block
  415. *
  416. * @mm: DRM buddy manager
  417. * @block: block to be freed
  418. */
  419. void drm_buddy_free_block(struct drm_buddy *mm,
  420. struct drm_buddy_block *block)
  421. {
  422. BUG_ON(!drm_buddy_block_is_allocated(block));
  423. mm->avail += drm_buddy_block_size(mm, block);
  424. if (drm_buddy_block_is_clear(block))
  425. mm->clear_avail += drm_buddy_block_size(mm, block);
  426. __drm_buddy_free(mm, block, false);
  427. }
  428. EXPORT_SYMBOL(drm_buddy_free_block);
  429. static void __drm_buddy_free_list(struct drm_buddy *mm,
  430. struct list_head *objects,
  431. bool mark_clear,
  432. bool mark_dirty)
  433. {
  434. struct drm_buddy_block *block, *on;
  435. WARN_ON(mark_dirty && mark_clear);
  436. list_for_each_entry_safe(block, on, objects, link) {
  437. if (mark_clear)
  438. mark_cleared(block);
  439. else if (mark_dirty)
  440. clear_reset(block);
  441. drm_buddy_free_block(mm, block);
  442. cond_resched();
  443. }
  444. INIT_LIST_HEAD(objects);
  445. }
  446. static void drm_buddy_free_list_internal(struct drm_buddy *mm,
  447. struct list_head *objects)
  448. {
  449. /*
  450. * Don't touch the clear/dirty bit, since allocation is still internal
  451. * at this point. For example we might have just failed part of the
  452. * allocation.
  453. */
  454. __drm_buddy_free_list(mm, objects, false, false);
  455. }
  456. /**
  457. * drm_buddy_free_list - free blocks
  458. *
  459. * @mm: DRM buddy manager
  460. * @objects: input list head to free blocks
  461. * @flags: optional flags like DRM_BUDDY_CLEARED
  462. */
  463. void drm_buddy_free_list(struct drm_buddy *mm,
  464. struct list_head *objects,
  465. unsigned int flags)
  466. {
  467. bool mark_clear = flags & DRM_BUDDY_CLEARED;
  468. __drm_buddy_free_list(mm, objects, mark_clear, !mark_clear);
  469. }
  470. EXPORT_SYMBOL(drm_buddy_free_list);
  471. static bool block_incompatible(struct drm_buddy_block *block, unsigned int flags)
  472. {
  473. bool needs_clear = flags & DRM_BUDDY_CLEAR_ALLOCATION;
  474. return needs_clear != drm_buddy_block_is_clear(block);
  475. }
  476. static struct drm_buddy_block *
  477. __alloc_range_bias(struct drm_buddy *mm,
  478. u64 start, u64 end,
  479. unsigned int order,
  480. unsigned long flags,
  481. bool fallback)
  482. {
  483. u64 req_size = mm->chunk_size << order;
  484. struct drm_buddy_block *block;
  485. struct drm_buddy_block *buddy;
  486. LIST_HEAD(dfs);
  487. int err;
  488. int i;
  489. end = end - 1;
  490. for (i = 0; i < mm->n_roots; ++i)
  491. list_add_tail(&mm->roots[i]->tmp_link, &dfs);
  492. do {
  493. u64 block_start;
  494. u64 block_end;
  495. block = list_first_entry_or_null(&dfs,
  496. struct drm_buddy_block,
  497. tmp_link);
  498. if (!block)
  499. break;
  500. list_del(&block->tmp_link);
  501. if (drm_buddy_block_order(block) < order)
  502. continue;
  503. block_start = drm_buddy_block_offset(block);
  504. block_end = block_start + drm_buddy_block_size(mm, block) - 1;
  505. if (!overlaps(start, end, block_start, block_end))
  506. continue;
  507. if (drm_buddy_block_is_allocated(block))
  508. continue;
  509. if (block_start < start || block_end > end) {
  510. u64 adjusted_start = max(block_start, start);
  511. u64 adjusted_end = min(block_end, end);
  512. if (round_down(adjusted_end + 1, req_size) <=
  513. round_up(adjusted_start, req_size))
  514. continue;
  515. }
  516. if (!fallback && block_incompatible(block, flags))
  517. continue;
  518. if (contains(start, end, block_start, block_end) &&
  519. order == drm_buddy_block_order(block)) {
  520. /*
  521. * Find the free block within the range.
  522. */
  523. if (drm_buddy_block_is_free(block))
  524. return block;
  525. continue;
  526. }
  527. if (!drm_buddy_block_is_split(block)) {
  528. err = split_block(mm, block);
  529. if (unlikely(err))
  530. goto err_undo;
  531. }
  532. list_add(&block->right->tmp_link, &dfs);
  533. list_add(&block->left->tmp_link, &dfs);
  534. } while (1);
  535. return ERR_PTR(-ENOSPC);
  536. err_undo:
  537. /*
  538. * We really don't want to leave around a bunch of split blocks, since
  539. * bigger is better, so make sure we merge everything back before we
  540. * free the allocated blocks.
  541. */
  542. buddy = __get_buddy(block);
  543. if (buddy &&
  544. (drm_buddy_block_is_free(block) &&
  545. drm_buddy_block_is_free(buddy)))
  546. __drm_buddy_free(mm, block, false);
  547. return ERR_PTR(err);
  548. }
  549. static struct drm_buddy_block *
  550. __drm_buddy_alloc_range_bias(struct drm_buddy *mm,
  551. u64 start, u64 end,
  552. unsigned int order,
  553. unsigned long flags)
  554. {
  555. struct drm_buddy_block *block;
  556. bool fallback = false;
  557. block = __alloc_range_bias(mm, start, end, order,
  558. flags, fallback);
  559. if (IS_ERR(block))
  560. return __alloc_range_bias(mm, start, end, order,
  561. flags, !fallback);
  562. return block;
  563. }
  564. static struct drm_buddy_block *
  565. get_maxblock(struct drm_buddy *mm,
  566. unsigned int order,
  567. enum drm_buddy_free_tree tree)
  568. {
  569. struct drm_buddy_block *max_block = NULL, *block = NULL;
  570. struct rb_root *root;
  571. unsigned int i;
  572. for (i = order; i <= mm->max_order; ++i) {
  573. root = &mm->free_trees[tree][i];
  574. block = rbtree_last_free_block(root);
  575. if (!block)
  576. continue;
  577. if (!max_block) {
  578. max_block = block;
  579. continue;
  580. }
  581. if (drm_buddy_block_offset(block) >
  582. drm_buddy_block_offset(max_block)) {
  583. max_block = block;
  584. }
  585. }
  586. return max_block;
  587. }
  588. static struct drm_buddy_block *
  589. alloc_from_freetree(struct drm_buddy *mm,
  590. unsigned int order,
  591. unsigned long flags)
  592. {
  593. struct drm_buddy_block *block = NULL;
  594. struct rb_root *root;
  595. enum drm_buddy_free_tree tree;
  596. unsigned int tmp;
  597. int err;
  598. tree = (flags & DRM_BUDDY_CLEAR_ALLOCATION) ?
  599. DRM_BUDDY_CLEAR_TREE : DRM_BUDDY_DIRTY_TREE;
  600. if (flags & DRM_BUDDY_TOPDOWN_ALLOCATION) {
  601. block = get_maxblock(mm, order, tree);
  602. if (block)
  603. /* Store the obtained block order */
  604. tmp = drm_buddy_block_order(block);
  605. } else {
  606. for (tmp = order; tmp <= mm->max_order; ++tmp) {
  607. /* Get RB tree root for this order and tree */
  608. root = &mm->free_trees[tree][tmp];
  609. block = rbtree_last_free_block(root);
  610. if (block)
  611. break;
  612. }
  613. }
  614. if (!block) {
  615. /* Try allocating from the other tree */
  616. tree = (tree == DRM_BUDDY_CLEAR_TREE) ?
  617. DRM_BUDDY_DIRTY_TREE : DRM_BUDDY_CLEAR_TREE;
  618. for (tmp = order; tmp <= mm->max_order; ++tmp) {
  619. root = &mm->free_trees[tree][tmp];
  620. block = rbtree_last_free_block(root);
  621. if (block)
  622. break;
  623. }
  624. if (!block)
  625. return ERR_PTR(-ENOSPC);
  626. }
  627. BUG_ON(!drm_buddy_block_is_free(block));
  628. while (tmp != order) {
  629. err = split_block(mm, block);
  630. if (unlikely(err))
  631. goto err_undo;
  632. block = block->right;
  633. tmp--;
  634. }
  635. return block;
  636. err_undo:
  637. if (tmp != order)
  638. __drm_buddy_free(mm, block, false);
  639. return ERR_PTR(err);
  640. }
  641. static int __alloc_range(struct drm_buddy *mm,
  642. struct list_head *dfs,
  643. u64 start, u64 size,
  644. struct list_head *blocks,
  645. u64 *total_allocated_on_err)
  646. {
  647. struct drm_buddy_block *block;
  648. struct drm_buddy_block *buddy;
  649. u64 total_allocated = 0;
  650. LIST_HEAD(allocated);
  651. u64 end;
  652. int err;
  653. end = start + size - 1;
  654. do {
  655. u64 block_start;
  656. u64 block_end;
  657. block = list_first_entry_or_null(dfs,
  658. struct drm_buddy_block,
  659. tmp_link);
  660. if (!block)
  661. break;
  662. list_del(&block->tmp_link);
  663. block_start = drm_buddy_block_offset(block);
  664. block_end = block_start + drm_buddy_block_size(mm, block) - 1;
  665. if (!overlaps(start, end, block_start, block_end))
  666. continue;
  667. if (drm_buddy_block_is_allocated(block)) {
  668. err = -ENOSPC;
  669. goto err_free;
  670. }
  671. if (contains(start, end, block_start, block_end)) {
  672. if (drm_buddy_block_is_free(block)) {
  673. mark_allocated(mm, block);
  674. total_allocated += drm_buddy_block_size(mm, block);
  675. mm->avail -= drm_buddy_block_size(mm, block);
  676. if (drm_buddy_block_is_clear(block))
  677. mm->clear_avail -= drm_buddy_block_size(mm, block);
  678. list_add_tail(&block->link, &allocated);
  679. continue;
  680. } else if (!mm->clear_avail) {
  681. err = -ENOSPC;
  682. goto err_free;
  683. }
  684. }
  685. if (!drm_buddy_block_is_split(block)) {
  686. err = split_block(mm, block);
  687. if (unlikely(err))
  688. goto err_undo;
  689. }
  690. list_add(&block->right->tmp_link, dfs);
  691. list_add(&block->left->tmp_link, dfs);
  692. } while (1);
  693. if (total_allocated < size) {
  694. err = -ENOSPC;
  695. goto err_free;
  696. }
  697. list_splice_tail(&allocated, blocks);
  698. return 0;
  699. err_undo:
  700. /*
  701. * We really don't want to leave around a bunch of split blocks, since
  702. * bigger is better, so make sure we merge everything back before we
  703. * free the allocated blocks.
  704. */
  705. buddy = __get_buddy(block);
  706. if (buddy &&
  707. (drm_buddy_block_is_free(block) &&
  708. drm_buddy_block_is_free(buddy)))
  709. __drm_buddy_free(mm, block, false);
  710. err_free:
  711. if (err == -ENOSPC && total_allocated_on_err) {
  712. list_splice_tail(&allocated, blocks);
  713. *total_allocated_on_err = total_allocated;
  714. } else {
  715. drm_buddy_free_list_internal(mm, &allocated);
  716. }
  717. return err;
  718. }
  719. static int __drm_buddy_alloc_range(struct drm_buddy *mm,
  720. u64 start,
  721. u64 size,
  722. u64 *total_allocated_on_err,
  723. struct list_head *blocks)
  724. {
  725. LIST_HEAD(dfs);
  726. int i;
  727. for (i = 0; i < mm->n_roots; ++i)
  728. list_add_tail(&mm->roots[i]->tmp_link, &dfs);
  729. return __alloc_range(mm, &dfs, start, size,
  730. blocks, total_allocated_on_err);
  731. }
  732. static int __alloc_contig_try_harder(struct drm_buddy *mm,
  733. u64 size,
  734. u64 min_block_size,
  735. struct list_head *blocks)
  736. {
  737. u64 rhs_offset, lhs_offset, lhs_size, filled;
  738. struct drm_buddy_block *block;
  739. unsigned int tree, order;
  740. LIST_HEAD(blocks_lhs);
  741. unsigned long pages;
  742. u64 modify_size;
  743. int err;
  744. modify_size = rounddown_pow_of_two(size);
  745. pages = modify_size >> ilog2(mm->chunk_size);
  746. order = fls(pages) - 1;
  747. if (order == 0)
  748. return -ENOSPC;
  749. for_each_free_tree(tree) {
  750. struct rb_root *root;
  751. struct rb_node *iter;
  752. root = &mm->free_trees[tree][order];
  753. if (rbtree_is_empty(root))
  754. continue;
  755. iter = rb_last(root);
  756. while (iter) {
  757. block = rbtree_get_free_block(iter);
  758. /* Allocate blocks traversing RHS */
  759. rhs_offset = drm_buddy_block_offset(block);
  760. err = __drm_buddy_alloc_range(mm, rhs_offset, size,
  761. &filled, blocks);
  762. if (!err || err != -ENOSPC)
  763. return err;
  764. lhs_size = max((size - filled), min_block_size);
  765. if (!IS_ALIGNED(lhs_size, min_block_size))
  766. lhs_size = round_up(lhs_size, min_block_size);
  767. /* Allocate blocks traversing LHS */
  768. lhs_offset = drm_buddy_block_offset(block) - lhs_size;
  769. err = __drm_buddy_alloc_range(mm, lhs_offset, lhs_size,
  770. NULL, &blocks_lhs);
  771. if (!err) {
  772. list_splice(&blocks_lhs, blocks);
  773. return 0;
  774. } else if (err != -ENOSPC) {
  775. drm_buddy_free_list_internal(mm, blocks);
  776. return err;
  777. }
  778. /* Free blocks for the next iteration */
  779. drm_buddy_free_list_internal(mm, blocks);
  780. iter = rb_prev(iter);
  781. }
  782. }
  783. return -ENOSPC;
  784. }
  785. /**
  786. * drm_buddy_block_trim - free unused pages
  787. *
  788. * @mm: DRM buddy manager
  789. * @start: start address to begin the trimming.
  790. * @new_size: original size requested
  791. * @blocks: Input and output list of allocated blocks.
  792. * MUST contain single block as input to be trimmed.
  793. * On success will contain the newly allocated blocks
  794. * making up the @new_size. Blocks always appear in
  795. * ascending order
  796. *
  797. * For contiguous allocation, we round up the size to the nearest
  798. * power of two value, drivers consume *actual* size, so remaining
  799. * portions are unused and can be optionally freed with this function
  800. *
  801. * Returns:
  802. * 0 on success, error code on failure.
  803. */
  804. int drm_buddy_block_trim(struct drm_buddy *mm,
  805. u64 *start,
  806. u64 new_size,
  807. struct list_head *blocks)
  808. {
  809. struct drm_buddy_block *parent;
  810. struct drm_buddy_block *block;
  811. u64 block_start, block_end;
  812. LIST_HEAD(dfs);
  813. u64 new_start;
  814. int err;
  815. if (!list_is_singular(blocks))
  816. return -EINVAL;
  817. block = list_first_entry(blocks,
  818. struct drm_buddy_block,
  819. link);
  820. block_start = drm_buddy_block_offset(block);
  821. block_end = block_start + drm_buddy_block_size(mm, block);
  822. if (WARN_ON(!drm_buddy_block_is_allocated(block)))
  823. return -EINVAL;
  824. if (new_size > drm_buddy_block_size(mm, block))
  825. return -EINVAL;
  826. if (!new_size || !IS_ALIGNED(new_size, mm->chunk_size))
  827. return -EINVAL;
  828. if (new_size == drm_buddy_block_size(mm, block))
  829. return 0;
  830. new_start = block_start;
  831. if (start) {
  832. new_start = *start;
  833. if (new_start < block_start)
  834. return -EINVAL;
  835. if (!IS_ALIGNED(new_start, mm->chunk_size))
  836. return -EINVAL;
  837. if (range_overflows(new_start, new_size, block_end))
  838. return -EINVAL;
  839. }
  840. list_del(&block->link);
  841. mark_free(mm, block);
  842. mm->avail += drm_buddy_block_size(mm, block);
  843. if (drm_buddy_block_is_clear(block))
  844. mm->clear_avail += drm_buddy_block_size(mm, block);
  845. /* Prevent recursively freeing this node */
  846. parent = block->parent;
  847. block->parent = NULL;
  848. list_add(&block->tmp_link, &dfs);
  849. err = __alloc_range(mm, &dfs, new_start, new_size, blocks, NULL);
  850. if (err) {
  851. mark_allocated(mm, block);
  852. mm->avail -= drm_buddy_block_size(mm, block);
  853. if (drm_buddy_block_is_clear(block))
  854. mm->clear_avail -= drm_buddy_block_size(mm, block);
  855. list_add(&block->link, blocks);
  856. }
  857. block->parent = parent;
  858. return err;
  859. }
  860. EXPORT_SYMBOL(drm_buddy_block_trim);
  861. static struct drm_buddy_block *
  862. __drm_buddy_alloc_blocks(struct drm_buddy *mm,
  863. u64 start, u64 end,
  864. unsigned int order,
  865. unsigned long flags)
  866. {
  867. if (flags & DRM_BUDDY_RANGE_ALLOCATION)
  868. /* Allocate traversing within the range */
  869. return __drm_buddy_alloc_range_bias(mm, start, end,
  870. order, flags);
  871. else
  872. /* Allocate from freetree */
  873. return alloc_from_freetree(mm, order, flags);
  874. }
  875. /**
  876. * drm_buddy_alloc_blocks - allocate power-of-two blocks
  877. *
  878. * @mm: DRM buddy manager to allocate from
  879. * @start: start of the allowed range for this block
  880. * @end: end of the allowed range for this block
  881. * @size: size of the allocation in bytes
  882. * @min_block_size: alignment of the allocation
  883. * @blocks: output list head to add allocated blocks
  884. * @flags: DRM_BUDDY_*_ALLOCATION flags
  885. *
  886. * alloc_range_bias() called on range limitations, which traverses
  887. * the tree and returns the desired block.
  888. *
  889. * alloc_from_freetree() called when *no* range restrictions
  890. * are enforced, which picks the block from the freetree.
  891. *
  892. * Returns:
  893. * 0 on success, error code on failure.
  894. */
  895. int drm_buddy_alloc_blocks(struct drm_buddy *mm,
  896. u64 start, u64 end, u64 size,
  897. u64 min_block_size,
  898. struct list_head *blocks,
  899. unsigned long flags)
  900. {
  901. struct drm_buddy_block *block = NULL;
  902. u64 original_size, original_min_size;
  903. unsigned int min_order, order;
  904. LIST_HEAD(allocated);
  905. unsigned long pages;
  906. int err;
  907. if (size < mm->chunk_size)
  908. return -EINVAL;
  909. if (min_block_size < mm->chunk_size)
  910. return -EINVAL;
  911. if (!is_power_of_2(min_block_size))
  912. return -EINVAL;
  913. if (!IS_ALIGNED(start | end | size, mm->chunk_size))
  914. return -EINVAL;
  915. if (end > mm->size)
  916. return -EINVAL;
  917. if (range_overflows(start, size, mm->size))
  918. return -EINVAL;
  919. /* Actual range allocation */
  920. if (start + size == end) {
  921. if (!IS_ALIGNED(start | end, min_block_size))
  922. return -EINVAL;
  923. return __drm_buddy_alloc_range(mm, start, size, NULL, blocks);
  924. }
  925. original_size = size;
  926. original_min_size = min_block_size;
  927. /* Roundup the size to power of 2 */
  928. if (flags & DRM_BUDDY_CONTIGUOUS_ALLOCATION) {
  929. size = roundup_pow_of_two(size);
  930. min_block_size = size;
  931. /* Align size value to min_block_size */
  932. } else if (!IS_ALIGNED(size, min_block_size)) {
  933. size = round_up(size, min_block_size);
  934. }
  935. pages = size >> ilog2(mm->chunk_size);
  936. order = fls(pages) - 1;
  937. min_order = ilog2(min_block_size) - ilog2(mm->chunk_size);
  938. if (order > mm->max_order || size > mm->size) {
  939. if ((flags & DRM_BUDDY_CONTIGUOUS_ALLOCATION) &&
  940. !(flags & DRM_BUDDY_RANGE_ALLOCATION))
  941. return __alloc_contig_try_harder(mm, original_size,
  942. original_min_size, blocks);
  943. return -EINVAL;
  944. }
  945. do {
  946. order = min(order, (unsigned int)fls(pages) - 1);
  947. BUG_ON(order > mm->max_order);
  948. BUG_ON(order < min_order);
  949. do {
  950. block = __drm_buddy_alloc_blocks(mm, start,
  951. end,
  952. order,
  953. flags);
  954. if (!IS_ERR(block))
  955. break;
  956. if (order-- == min_order) {
  957. /* Try allocation through force merge method */
  958. if (mm->clear_avail &&
  959. !__force_merge(mm, start, end, min_order)) {
  960. block = __drm_buddy_alloc_blocks(mm, start,
  961. end,
  962. min_order,
  963. flags);
  964. if (!IS_ERR(block)) {
  965. order = min_order;
  966. break;
  967. }
  968. }
  969. /*
  970. * Try contiguous block allocation through
  971. * try harder method.
  972. */
  973. if (flags & DRM_BUDDY_CONTIGUOUS_ALLOCATION &&
  974. !(flags & DRM_BUDDY_RANGE_ALLOCATION))
  975. return __alloc_contig_try_harder(mm,
  976. original_size,
  977. original_min_size,
  978. blocks);
  979. err = -ENOSPC;
  980. goto err_free;
  981. }
  982. } while (1);
  983. mark_allocated(mm, block);
  984. mm->avail -= drm_buddy_block_size(mm, block);
  985. if (drm_buddy_block_is_clear(block))
  986. mm->clear_avail -= drm_buddy_block_size(mm, block);
  987. kmemleak_update_trace(block);
  988. list_add_tail(&block->link, &allocated);
  989. pages -= BIT(order);
  990. if (!pages)
  991. break;
  992. } while (1);
  993. /* Trim the allocated block to the required size */
  994. if (!(flags & DRM_BUDDY_TRIM_DISABLE) &&
  995. original_size != size) {
  996. struct list_head *trim_list;
  997. LIST_HEAD(temp);
  998. u64 trim_size;
  999. trim_list = &allocated;
  1000. trim_size = original_size;
  1001. if (!list_is_singular(&allocated)) {
  1002. block = list_last_entry(&allocated, typeof(*block), link);
  1003. list_move(&block->link, &temp);
  1004. trim_list = &temp;
  1005. trim_size = drm_buddy_block_size(mm, block) -
  1006. (size - original_size);
  1007. }
  1008. drm_buddy_block_trim(mm,
  1009. NULL,
  1010. trim_size,
  1011. trim_list);
  1012. if (!list_empty(&temp))
  1013. list_splice_tail(trim_list, &allocated);
  1014. }
  1015. list_splice_tail(&allocated, blocks);
  1016. return 0;
  1017. err_free:
  1018. drm_buddy_free_list_internal(mm, &allocated);
  1019. return err;
  1020. }
  1021. EXPORT_SYMBOL(drm_buddy_alloc_blocks);
  1022. /**
  1023. * drm_buddy_block_print - print block information
  1024. *
  1025. * @mm: DRM buddy manager
  1026. * @block: DRM buddy block
  1027. * @p: DRM printer to use
  1028. */
  1029. void drm_buddy_block_print(struct drm_buddy *mm,
  1030. struct drm_buddy_block *block,
  1031. struct drm_printer *p)
  1032. {
  1033. u64 start = drm_buddy_block_offset(block);
  1034. u64 size = drm_buddy_block_size(mm, block);
  1035. drm_printf(p, "%#018llx-%#018llx: %llu\n", start, start + size, size);
  1036. }
  1037. EXPORT_SYMBOL(drm_buddy_block_print);
  1038. /**
  1039. * drm_buddy_print - print allocator state
  1040. *
  1041. * @mm: DRM buddy manager
  1042. * @p: DRM printer to use
  1043. */
  1044. void drm_buddy_print(struct drm_buddy *mm, struct drm_printer *p)
  1045. {
  1046. int order;
  1047. drm_printf(p, "chunk_size: %lluKiB, total: %lluMiB, free: %lluMiB, clear_free: %lluMiB\n",
  1048. mm->chunk_size >> 10, mm->size >> 20, mm->avail >> 20, mm->clear_avail >> 20);
  1049. for (order = mm->max_order; order >= 0; order--) {
  1050. struct drm_buddy_block *block, *tmp;
  1051. struct rb_root *root;
  1052. u64 count = 0, free;
  1053. unsigned int tree;
  1054. for_each_free_tree(tree) {
  1055. root = &mm->free_trees[tree][order];
  1056. rbtree_postorder_for_each_entry_safe(block, tmp, root, rb) {
  1057. BUG_ON(!drm_buddy_block_is_free(block));
  1058. count++;
  1059. }
  1060. }
  1061. drm_printf(p, "order-%2d ", order);
  1062. free = count * (mm->chunk_size << order);
  1063. if (free < SZ_1M)
  1064. drm_printf(p, "free: %8llu KiB", free >> 10);
  1065. else
  1066. drm_printf(p, "free: %8llu MiB", free >> 20);
  1067. drm_printf(p, ", blocks: %llu\n", count);
  1068. }
  1069. }
  1070. EXPORT_SYMBOL(drm_buddy_print);
  1071. static void drm_buddy_module_exit(void)
  1072. {
  1073. kmem_cache_destroy(slab_blocks);
  1074. }
  1075. static int __init drm_buddy_module_init(void)
  1076. {
  1077. slab_blocks = KMEM_CACHE(drm_buddy_block, 0);
  1078. if (!slab_blocks)
  1079. return -ENOMEM;
  1080. return 0;
  1081. }
  1082. module_init(drm_buddy_module_init);
  1083. module_exit(drm_buddy_module_exit);
  1084. MODULE_DESCRIPTION("DRM Buddy Allocator");
  1085. MODULE_LICENSE("Dual MIT/GPL");