devres.c 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293
  1. // SPDX-License-Identifier: GPL-2.0+
  2. /*
  3. * Copyright (C) 2015 Masahiro Yamada <yamada.masahiro@socionext.com>
  4. *
  5. * Based on the original work in Linux by
  6. * Copyright (c) 2006 SUSE Linux Products GmbH
  7. * Copyright (c) 2006 Tejun Heo <teheo@suse.de>
  8. */
  9. #define LOG_CATEGORY LOGC_DEVRES
  10. #include <common.h>
  11. #include <malloc.h>
  12. #include <linux/compat.h>
  13. #include <linux/kernel.h>
  14. #include <linux/list.h>
  15. #include <dm/device.h>
  16. #include <dm/devres.h>
  17. #include <dm/root.h>
  18. #include <dm/util.h>
  19. /** enum devres_phase - Shows where resource was allocated
  20. *
  21. * DEVRES_PHASE_BIND: In the bind() method
  22. * DEVRES_PHASE_OFDATA: In the ofdata_to_platdata() method
  23. * DEVRES_PHASE_PROBE: In the probe() method
  24. */
  25. enum devres_phase {
  26. DEVRES_PHASE_BIND,
  27. DEVRES_PHASE_OFDATA,
  28. DEVRES_PHASE_PROBE,
  29. };
  30. /**
  31. * struct devres - Bookkeeping info for managed device resource
  32. * @entry: List to associate this structure with a device
  33. * @release: Callback invoked when this resource is released
  34. * @probe: Show where this resource was allocated
  35. * @name: Name of release function
  36. * @size: Size of resource data
  37. * @data: Resource data
  38. */
  39. struct devres {
  40. struct list_head entry;
  41. dr_release_t release;
  42. enum devres_phase phase;
  43. #ifdef CONFIG_DEBUG_DEVRES
  44. const char *name;
  45. size_t size;
  46. #endif
  47. unsigned long long data[];
  48. };
  49. #ifdef CONFIG_DEBUG_DEVRES
  50. static void set_node_dbginfo(struct devres *dr, const char *name, size_t size)
  51. {
  52. dr->name = name;
  53. dr->size = size;
  54. }
  55. static void devres_log(struct udevice *dev, struct devres *dr,
  56. const char *op)
  57. {
  58. log_debug("%s: DEVRES %3s %p %s (%lu bytes)\n", dev->name, op, dr,
  59. dr->name, (unsigned long)dr->size);
  60. }
  61. #else /* CONFIG_DEBUG_DEVRES */
  62. #define set_node_dbginfo(dr, n, s) do {} while (0)
  63. #define devres_log(dev, dr, op) do {} while (0)
  64. #endif
  65. #if CONFIG_DEBUG_DEVRES
  66. void *__devres_alloc(dr_release_t release, size_t size, gfp_t gfp,
  67. const char *name)
  68. #else
  69. void *_devres_alloc(dr_release_t release, size_t size, gfp_t gfp)
  70. #endif
  71. {
  72. size_t tot_size = sizeof(struct devres) + size;
  73. struct devres *dr;
  74. dr = kmalloc(tot_size, gfp);
  75. if (unlikely(!dr))
  76. return NULL;
  77. INIT_LIST_HEAD(&dr->entry);
  78. dr->release = release;
  79. set_node_dbginfo(dr, name, size);
  80. return dr->data;
  81. }
  82. void devres_free(void *res)
  83. {
  84. if (res) {
  85. struct devres *dr = container_of(res, struct devres, data);
  86. assert_noisy(list_empty(&dr->entry));
  87. kfree(dr);
  88. }
  89. }
  90. void devres_add(struct udevice *dev, void *res)
  91. {
  92. struct devres *dr = container_of(res, struct devres, data);
  93. devres_log(dev, dr, "ADD");
  94. assert_noisy(list_empty(&dr->entry));
  95. if (dev->flags & DM_FLAG_PLATDATA_VALID)
  96. dr->phase = DEVRES_PHASE_PROBE;
  97. else if (dev->flags & DM_FLAG_BOUND)
  98. dr->phase = DEVRES_PHASE_OFDATA;
  99. else
  100. dr->phase = DEVRES_PHASE_BIND;
  101. list_add_tail(&dr->entry, &dev->devres_head);
  102. }
  103. void *devres_find(struct udevice *dev, dr_release_t release,
  104. dr_match_t match, void *match_data)
  105. {
  106. struct devres *dr;
  107. list_for_each_entry_reverse(dr, &dev->devres_head, entry) {
  108. if (dr->release != release)
  109. continue;
  110. if (match && !match(dev, dr->data, match_data))
  111. continue;
  112. return dr->data;
  113. }
  114. return NULL;
  115. }
  116. void *devres_get(struct udevice *dev, void *new_res,
  117. dr_match_t match, void *match_data)
  118. {
  119. struct devres *new_dr = container_of(new_res, struct devres, data);
  120. void *res;
  121. res = devres_find(dev, new_dr->release, match, match_data);
  122. if (!res) {
  123. devres_add(dev, new_res);
  124. res = new_res;
  125. new_res = NULL;
  126. }
  127. devres_free(new_res);
  128. return res;
  129. }
  130. void *devres_remove(struct udevice *dev, dr_release_t release,
  131. dr_match_t match, void *match_data)
  132. {
  133. void *res;
  134. res = devres_find(dev, release, match, match_data);
  135. if (res) {
  136. struct devres *dr = container_of(res, struct devres, data);
  137. list_del_init(&dr->entry);
  138. devres_log(dev, dr, "REM");
  139. }
  140. return res;
  141. }
  142. int devres_destroy(struct udevice *dev, dr_release_t release,
  143. dr_match_t match, void *match_data)
  144. {
  145. void *res;
  146. res = devres_remove(dev, release, match, match_data);
  147. if (unlikely(!res))
  148. return -ENOENT;
  149. devres_free(res);
  150. return 0;
  151. }
  152. int devres_release(struct udevice *dev, dr_release_t release,
  153. dr_match_t match, void *match_data)
  154. {
  155. void *res;
  156. res = devres_remove(dev, release, match, match_data);
  157. if (unlikely(!res))
  158. return -ENOENT;
  159. (*release)(dev, res);
  160. devres_free(res);
  161. return 0;
  162. }
  163. static void release_nodes(struct udevice *dev, struct list_head *head,
  164. bool probe_and_ofdata_only)
  165. {
  166. struct devres *dr, *tmp;
  167. list_for_each_entry_safe_reverse(dr, tmp, head, entry) {
  168. if (probe_and_ofdata_only && dr->phase == DEVRES_PHASE_BIND)
  169. break;
  170. devres_log(dev, dr, "REL");
  171. dr->release(dev, dr->data);
  172. list_del(&dr->entry);
  173. kfree(dr);
  174. }
  175. }
  176. void devres_release_probe(struct udevice *dev)
  177. {
  178. release_nodes(dev, &dev->devres_head, true);
  179. }
  180. void devres_release_all(struct udevice *dev)
  181. {
  182. release_nodes(dev, &dev->devres_head, false);
  183. }
  184. #ifdef CONFIG_DEBUG_DEVRES
  185. static char *const devres_phase_name[] = {"BIND", "OFDATA", "PROBE"};
  186. static void dump_resources(struct udevice *dev, int depth)
  187. {
  188. struct devres *dr;
  189. struct udevice *child;
  190. printf("- %s\n", dev->name);
  191. list_for_each_entry(dr, &dev->devres_head, entry)
  192. printf(" %p (%lu byte) %s %s\n", dr,
  193. (unsigned long)dr->size, dr->name,
  194. devres_phase_name[dr->phase]);
  195. list_for_each_entry(child, &dev->child_head, sibling_node)
  196. dump_resources(child, depth + 1);
  197. }
  198. void dm_dump_devres(void)
  199. {
  200. struct udevice *root;
  201. root = dm_root();
  202. if (root)
  203. dump_resources(root, 0);
  204. }
  205. void devres_get_stats(const struct udevice *dev, struct devres_stats *stats)
  206. {
  207. struct devres *dr;
  208. stats->allocs = 0;
  209. stats->total_size = 0;
  210. list_for_each_entry(dr, &dev->devres_head, entry) {
  211. stats->allocs++;
  212. stats->total_size += dr->size;
  213. }
  214. }
  215. #endif
  216. /*
  217. * Managed kmalloc/kfree
  218. */
  219. static void devm_kmalloc_release(struct udevice *dev, void *res)
  220. {
  221. /* noop */
  222. }
  223. static int devm_kmalloc_match(struct udevice *dev, void *res, void *data)
  224. {
  225. return res == data;
  226. }
  227. void *devm_kmalloc(struct udevice *dev, size_t size, gfp_t gfp)
  228. {
  229. void *data;
  230. data = _devres_alloc(devm_kmalloc_release, size, gfp);
  231. if (unlikely(!data))
  232. return NULL;
  233. devres_add(dev, data);
  234. return data;
  235. }
  236. void devm_kfree(struct udevice *dev, void *p)
  237. {
  238. int rc;
  239. rc = devres_destroy(dev, devm_kmalloc_release, devm_kmalloc_match, p);
  240. assert_noisy(!rc);
  241. }