drm_buddy.h 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159
  1. /* SPDX-License-Identifier: MIT */
  2. /*
  3. * Copyright © 2021 Intel Corporation
  4. */
  5. #ifndef __DRM_BUDDY_H__
  6. #define __DRM_BUDDY_H__
  7. #include <linux/bitops.h>
  8. #include <linux/list.h>
  9. #include <linux/slab.h>
  10. #include <linux/sched.h>
  11. #include <drm/drm_print.h>
  12. #define range_overflows(start, size, max) ({ \
  13. typeof(start) start__ = (start); \
  14. typeof(size) size__ = (size); \
  15. typeof(max) max__ = (max); \
  16. (void)(&start__ == &size__); \
  17. (void)(&start__ == &max__); \
  18. start__ >= max__ || size__ > max__ - start__; \
  19. })
  20. #define DRM_BUDDY_RANGE_ALLOCATION (1 << 0)
  21. #define DRM_BUDDY_TOPDOWN_ALLOCATION (1 << 1)
  22. struct drm_buddy_block {
  23. #define DRM_BUDDY_HEADER_OFFSET GENMASK_ULL(63, 12)
  24. #define DRM_BUDDY_HEADER_STATE GENMASK_ULL(11, 10)
  25. #define DRM_BUDDY_ALLOCATED (1 << 10)
  26. #define DRM_BUDDY_FREE (2 << 10)
  27. #define DRM_BUDDY_SPLIT (3 << 10)
  28. /* Free to be used, if needed in the future */
  29. #define DRM_BUDDY_HEADER_UNUSED GENMASK_ULL(9, 6)
  30. #define DRM_BUDDY_HEADER_ORDER GENMASK_ULL(5, 0)
  31. u64 header;
  32. struct drm_buddy_block *left;
  33. struct drm_buddy_block *right;
  34. struct drm_buddy_block *parent;
  35. void *private; /* owned by creator */
  36. /*
  37. * While the block is allocated by the user through drm_buddy_alloc*,
  38. * the user has ownership of the link, for example to maintain within
  39. * a list, if so desired. As soon as the block is freed with
  40. * drm_buddy_free* ownership is given back to the mm.
  41. */
  42. struct list_head link;
  43. struct list_head tmp_link;
  44. };
  45. /* Order-zero must be at least PAGE_SIZE */
  46. #define DRM_BUDDY_MAX_ORDER (63 - PAGE_SHIFT)
  47. /*
  48. * Binary Buddy System.
  49. *
  50. * Locking should be handled by the user, a simple mutex around
  51. * drm_buddy_alloc* and drm_buddy_free* should suffice.
  52. */
  53. struct drm_buddy {
  54. /* Maintain a free list for each order. */
  55. struct list_head *free_list;
  56. /*
  57. * Maintain explicit binary tree(s) to track the allocation of the
  58. * address space. This gives us a simple way of finding a buddy block
  59. * and performing the potentially recursive merge step when freeing a
  60. * block. Nodes are either allocated or free, in which case they will
  61. * also exist on the respective free list.
  62. */
  63. struct drm_buddy_block **roots;
  64. /*
  65. * Anything from here is public, and remains static for the lifetime of
  66. * the mm. Everything above is considered do-not-touch.
  67. */
  68. unsigned int n_roots;
  69. unsigned int max_order;
  70. /* Must be at least PAGE_SIZE */
  71. u64 chunk_size;
  72. u64 size;
  73. u64 avail;
  74. };
  75. static inline u64
  76. drm_buddy_block_offset(struct drm_buddy_block *block)
  77. {
  78. return block->header & DRM_BUDDY_HEADER_OFFSET;
  79. }
  80. static inline unsigned int
  81. drm_buddy_block_order(struct drm_buddy_block *block)
  82. {
  83. return block->header & DRM_BUDDY_HEADER_ORDER;
  84. }
  85. static inline unsigned int
  86. drm_buddy_block_state(struct drm_buddy_block *block)
  87. {
  88. return block->header & DRM_BUDDY_HEADER_STATE;
  89. }
  90. static inline bool
  91. drm_buddy_block_is_allocated(struct drm_buddy_block *block)
  92. {
  93. return drm_buddy_block_state(block) == DRM_BUDDY_ALLOCATED;
  94. }
  95. static inline bool
  96. drm_buddy_block_is_free(struct drm_buddy_block *block)
  97. {
  98. return drm_buddy_block_state(block) == DRM_BUDDY_FREE;
  99. }
  100. static inline bool
  101. drm_buddy_block_is_split(struct drm_buddy_block *block)
  102. {
  103. return drm_buddy_block_state(block) == DRM_BUDDY_SPLIT;
  104. }
  105. static inline u64
  106. drm_buddy_block_size(struct drm_buddy *mm,
  107. struct drm_buddy_block *block)
  108. {
  109. return mm->chunk_size << drm_buddy_block_order(block);
  110. }
  111. int drm_buddy_init(struct drm_buddy *mm, u64 size, u64 chunk_size);
  112. void drm_buddy_fini(struct drm_buddy *mm);
  113. struct drm_buddy_block *
  114. drm_get_buddy(struct drm_buddy_block *block);
  115. int drm_buddy_alloc_blocks(struct drm_buddy *mm,
  116. u64 start, u64 end, u64 size,
  117. u64 min_page_size,
  118. struct list_head *blocks,
  119. unsigned long flags);
  120. int drm_buddy_block_trim(struct drm_buddy *mm,
  121. u64 new_size,
  122. struct list_head *blocks);
  123. void drm_buddy_free_block(struct drm_buddy *mm, struct drm_buddy_block *block);
  124. void drm_buddy_free_list(struct drm_buddy *mm, struct list_head *objects);
  125. void drm_buddy_print(struct drm_buddy *mm, struct drm_printer *p);
  126. void drm_buddy_block_print(struct drm_buddy *mm,
  127. struct drm_buddy_block *block,
  128. struct drm_printer *p);
  129. #endif