drm_managed.c 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*
  3. * Copyright (C) 2020 Intel
  4. *
  5. * Based on drivers/base/devres.c
  6. */
  7. #include <drm/drm_managed.h>
  8. #include <linux/export.h>
  9. #include <linux/list.h>
  10. #include <linux/mutex.h>
  11. #include <linux/slab.h>
  12. #include <linux/spinlock.h>
  13. #include <drm/drm_device.h>
  14. #include <drm/drm_print.h>
  15. #include "drm_internal.h"
  16. /**
  17. * DOC: managed resources
  18. *
  19. * Inspired by struct &device managed resources, but tied to the lifetime of
  20. * struct &drm_device, which can outlive the underlying physical device, usually
  21. * when userspace has some open files and other handles to resources still open.
  22. *
  23. * Release actions can be added with drmm_add_action(), memory allocations can
  24. * be done directly with drmm_kmalloc() and the related functions. Everything
  25. * will be released on the final drm_dev_put() in reverse order of how the
  26. * release actions have been added and memory has been allocated since driver
  27. * loading started with devm_drm_dev_alloc().
  28. *
  29. * Note that release actions and managed memory can also be added and removed
  30. * during the lifetime of the driver, all the functions are fully concurrent
  31. * safe. But it is recommended to use managed resources only for resources that
  32. * change rarely, if ever, during the lifetime of the &drm_device instance.
  33. */
  34. struct drmres_node {
  35. struct list_head entry;
  36. drmres_release_t release;
  37. const char *name;
  38. size_t size;
  39. };
  40. struct drmres {
  41. struct drmres_node node;
  42. /*
  43. * Some archs want to perform DMA into kmalloc caches
  44. * and need a guaranteed alignment larger than
  45. * the alignment of a 64-bit integer.
  46. * Thus we use ARCH_DMA_MINALIGN for data[] which will force the same
  47. * alignment for struct drmres when allocated by kmalloc().
  48. */
  49. u8 __aligned(ARCH_DMA_MINALIGN) data[];
  50. };
  51. static void free_dr(struct drmres *dr)
  52. {
  53. kfree_const(dr->node.name);
  54. kfree(dr);
  55. }
  56. void drm_managed_release(struct drm_device *dev)
  57. {
  58. struct drmres *dr, *tmp;
  59. drm_dbg_drmres(dev, "drmres release begin\n");
  60. list_for_each_entry_safe(dr, tmp, &dev->managed.resources, node.entry) {
  61. drm_dbg_drmres(dev, "REL %p %s (%zu bytes)\n",
  62. dr, dr->node.name, dr->node.size);
  63. if (dr->node.release)
  64. dr->node.release(dev, dr->node.size ? *(void **)&dr->data : NULL);
  65. list_del(&dr->node.entry);
  66. free_dr(dr);
  67. }
  68. drm_dbg_drmres(dev, "drmres release end\n");
  69. }
  70. /*
  71. * Always inline so that kmalloc_track_caller tracks the actual interesting
  72. * caller outside of drm_managed.c.
  73. */
  74. static __always_inline struct drmres * alloc_dr(drmres_release_t release,
  75. size_t size, gfp_t gfp, int nid)
  76. {
  77. size_t tot_size;
  78. struct drmres *dr;
  79. /* We must catch any near-SIZE_MAX cases that could overflow. */
  80. if (unlikely(check_add_overflow(sizeof(*dr), size, &tot_size)))
  81. return NULL;
  82. dr = kmalloc_node_track_caller(tot_size, gfp, nid);
  83. if (unlikely(!dr))
  84. return NULL;
  85. memset(dr, 0, offsetof(struct drmres, data));
  86. INIT_LIST_HEAD(&dr->node.entry);
  87. dr->node.release = release;
  88. dr->node.size = size;
  89. return dr;
  90. }
  91. static void del_dr(struct drm_device *dev, struct drmres *dr)
  92. {
  93. list_del_init(&dr->node.entry);
  94. drm_dbg_drmres(dev, "DEL %p %s (%lu bytes)\n",
  95. dr, dr->node.name, (unsigned long) dr->node.size);
  96. }
  97. static void add_dr(struct drm_device *dev, struct drmres *dr)
  98. {
  99. unsigned long flags;
  100. spin_lock_irqsave(&dev->managed.lock, flags);
  101. list_add(&dr->node.entry, &dev->managed.resources);
  102. spin_unlock_irqrestore(&dev->managed.lock, flags);
  103. drm_dbg_drmres(dev, "ADD %p %s (%lu bytes)\n",
  104. dr, dr->node.name, (unsigned long) dr->node.size);
  105. }
  106. void drmm_add_final_kfree(struct drm_device *dev, void *container)
  107. {
  108. WARN_ON(dev->managed.final_kfree);
  109. WARN_ON(dev < (struct drm_device *) container);
  110. WARN_ON(dev + 1 > (struct drm_device *) (container + ksize(container)));
  111. dev->managed.final_kfree = container;
  112. }
  113. int __drmm_add_action(struct drm_device *dev,
  114. drmres_release_t action,
  115. void *data, const char *name)
  116. {
  117. struct drmres *dr;
  118. void **void_ptr;
  119. dr = alloc_dr(action, data ? sizeof(void*) : 0,
  120. GFP_KERNEL | __GFP_ZERO,
  121. dev_to_node(dev->dev));
  122. if (!dr) {
  123. drm_dbg_drmres(dev, "failed to add action %s for %p\n",
  124. name, data);
  125. return -ENOMEM;
  126. }
  127. dr->node.name = kstrdup_const(name, GFP_KERNEL);
  128. if (data) {
  129. void_ptr = (void **)&dr->data;
  130. *void_ptr = data;
  131. }
  132. add_dr(dev, dr);
  133. return 0;
  134. }
  135. EXPORT_SYMBOL(__drmm_add_action);
  136. int __drmm_add_action_or_reset(struct drm_device *dev,
  137. drmres_release_t action,
  138. void *data, const char *name)
  139. {
  140. int ret;
  141. ret = __drmm_add_action(dev, action, data, name);
  142. if (ret)
  143. action(dev, data);
  144. return ret;
  145. }
  146. EXPORT_SYMBOL(__drmm_add_action_or_reset);
  147. /**
  148. * drmm_release_action - release a managed action from a &drm_device
  149. * @dev: DRM device
  150. * @action: function which would be called when @dev is released
  151. * @data: opaque pointer, passed to @action
  152. *
  153. * This function calls the @action previously added by drmm_add_action()
  154. * immediately.
  155. * The @action is removed from the list of cleanup actions for @dev,
  156. * which means that it won't be called in the final drm_dev_put().
  157. */
  158. void drmm_release_action(struct drm_device *dev,
  159. drmres_release_t action,
  160. void *data)
  161. {
  162. struct drmres *dr_match = NULL, *dr;
  163. unsigned long flags;
  164. spin_lock_irqsave(&dev->managed.lock, flags);
  165. list_for_each_entry_reverse(dr, &dev->managed.resources, node.entry) {
  166. if (dr->node.release == action) {
  167. if (!data || *(void **)dr->data == data) {
  168. dr_match = dr;
  169. del_dr(dev, dr_match);
  170. break;
  171. }
  172. }
  173. }
  174. spin_unlock_irqrestore(&dev->managed.lock, flags);
  175. if (WARN_ON(!dr_match))
  176. return;
  177. action(dev, data);
  178. free_dr(dr_match);
  179. }
  180. EXPORT_SYMBOL(drmm_release_action);
  181. /**
  182. * drmm_kmalloc - &drm_device managed kmalloc()
  183. * @dev: DRM device
  184. * @size: size of the memory allocation
  185. * @gfp: GFP allocation flags
  186. *
  187. * This is a &drm_device managed version of kmalloc(). The allocated memory is
  188. * automatically freed on the final drm_dev_put(). Memory can also be freed
  189. * before the final drm_dev_put() by calling drmm_kfree().
  190. */
  191. void *drmm_kmalloc(struct drm_device *dev, size_t size, gfp_t gfp)
  192. {
  193. struct drmres *dr;
  194. dr = alloc_dr(NULL, size, gfp, dev_to_node(dev->dev));
  195. if (!dr) {
  196. drm_dbg_drmres(dev, "failed to allocate %zu bytes, %u flags\n",
  197. size, gfp);
  198. return NULL;
  199. }
  200. dr->node.name = kstrdup_const("kmalloc", gfp);
  201. add_dr(dev, dr);
  202. return dr->data;
  203. }
  204. EXPORT_SYMBOL(drmm_kmalloc);
  205. /**
  206. * drmm_kstrdup - &drm_device managed kstrdup()
  207. * @dev: DRM device
  208. * @s: 0-terminated string to be duplicated
  209. * @gfp: GFP allocation flags
  210. *
  211. * This is a &drm_device managed version of kstrdup(). The allocated memory is
  212. * automatically freed on the final drm_dev_put() and works exactly like a
  213. * memory allocation obtained by drmm_kmalloc().
  214. */
  215. char *drmm_kstrdup(struct drm_device *dev, const char *s, gfp_t gfp)
  216. {
  217. size_t size;
  218. char *buf;
  219. if (!s)
  220. return NULL;
  221. size = strlen(s) + 1;
  222. buf = drmm_kmalloc(dev, size, gfp);
  223. if (buf)
  224. memcpy(buf, s, size);
  225. return buf;
  226. }
  227. EXPORT_SYMBOL_GPL(drmm_kstrdup);
  228. /**
  229. * drmm_kfree - &drm_device managed kfree()
  230. * @dev: DRM device
  231. * @data: memory allocation to be freed
  232. *
  233. * This is a &drm_device managed version of kfree() which can be used to
  234. * release memory allocated through drmm_kmalloc() or any of its related
  235. * functions before the final drm_dev_put() of @dev.
  236. */
  237. void drmm_kfree(struct drm_device *dev, void *data)
  238. {
  239. struct drmres *dr_match = NULL, *dr;
  240. unsigned long flags;
  241. if (!data)
  242. return;
  243. spin_lock_irqsave(&dev->managed.lock, flags);
  244. list_for_each_entry(dr, &dev->managed.resources, node.entry) {
  245. if (dr->data == data) {
  246. dr_match = dr;
  247. del_dr(dev, dr_match);
  248. break;
  249. }
  250. }
  251. spin_unlock_irqrestore(&dev->managed.lock, flags);
  252. if (WARN_ON(!dr_match))
  253. return;
  254. free_dr(dr_match);
  255. }
  256. EXPORT_SYMBOL(drmm_kfree);
  257. void __drmm_mutex_release(struct drm_device *dev, void *res)
  258. {
  259. struct mutex *lock = res;
  260. mutex_destroy(lock);
  261. }
  262. EXPORT_SYMBOL(__drmm_mutex_release);
  263. void __drmm_workqueue_release(struct drm_device *device, void *res)
  264. {
  265. struct workqueue_struct *wq = res;
  266. destroy_workqueue(wq);
  267. }
  268. EXPORT_SYMBOL(__drmm_workqueue_release);