dump.c 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300
  1. // SPDX-License-Identifier: GPL-2.0+
  2. /*
  3. * Copyright (c) 2015 Google, Inc
  4. */
  5. #include <common.h>
  6. #include <dm.h>
  7. #include <malloc.h>
  8. #include <mapmem.h>
  9. #include <sort.h>
  10. #include <dm/root.h>
  11. #include <dm/util.h>
  12. #include <dm/uclass-internal.h>
  13. /**
  14. * struct sort_info - information used for sorting
  15. *
  16. * @dev: List of devices
  17. * @alloced: Maximum number of devices in @dev
  18. */
  19. struct sort_info {
  20. struct udevice **dev;
  21. int size;
  22. };
  23. static int h_cmp_uclass_id(const void *d1, const void *d2)
  24. {
  25. const struct udevice *const *dev1 = d1;
  26. const struct udevice *const *dev2 = d2;
  27. return device_get_uclass_id(*dev1) - device_get_uclass_id(*dev2);
  28. }
  29. static void show_devices(struct udevice *dev, int depth, int last_flag,
  30. struct udevice **devs)
  31. {
  32. int i, is_last;
  33. struct udevice *child;
  34. u32 flags = dev_get_flags(dev);
  35. /* print the first 20 characters to not break the tree-format. */
  36. printf(CONFIG_IS_ENABLED(USE_TINY_PRINTF) ? " %s %d [ %c ] %s " :
  37. " %-10.10s %3d [ %c ] %-20.20s ", dev->uclass->uc_drv->name,
  38. dev_get_uclass_index(dev, NULL),
  39. flags & DM_FLAG_ACTIVATED ? '+' : ' ', dev->driver->name);
  40. for (i = depth; i >= 0; i--) {
  41. is_last = (last_flag >> i) & 1;
  42. if (i) {
  43. if (is_last)
  44. printf(" ");
  45. else
  46. printf("| ");
  47. } else {
  48. if (is_last)
  49. printf("`-- ");
  50. else
  51. printf("|-- ");
  52. }
  53. }
  54. printf("%s\n", dev->name);
  55. if (devs) {
  56. int count;
  57. int i;
  58. count = 0;
  59. device_foreach_child(child, dev)
  60. devs[count++] = child;
  61. qsort(devs, count, sizeof(struct udevice *), h_cmp_uclass_id);
  62. for (i = 0; i < count; i++) {
  63. show_devices(devs[i], depth + 1,
  64. (last_flag << 1) | (i == count - 1),
  65. devs + count);
  66. }
  67. } else {
  68. device_foreach_child(child, dev) {
  69. is_last = list_is_last(&child->sibling_node,
  70. &dev->child_head);
  71. show_devices(child, depth + 1,
  72. (last_flag << 1) | is_last, NULL);
  73. }
  74. }
  75. }
  76. void dm_dump_tree(bool sort)
  77. {
  78. struct udevice *root;
  79. root = dm_root();
  80. if (root) {
  81. int dev_count, uclasses;
  82. struct udevice **devs = NULL;
  83. dm_get_stats(&dev_count, &uclasses);
  84. printf(" Class Index Probed Driver Name\n");
  85. printf("-----------------------------------------------------------\n");
  86. if (sort) {
  87. devs = calloc(dev_count, sizeof(struct udevice *));
  88. if (!devs) {
  89. printf("(out of memory)\n");
  90. return;
  91. }
  92. }
  93. show_devices(root, -1, 0, devs);
  94. free(devs);
  95. }
  96. }
  97. /**
  98. * dm_display_line() - Display information about a single device
  99. *
  100. * Displays a single line of information with an option prefix
  101. *
  102. * @dev: Device to display
  103. */
  104. static void dm_display_line(struct udevice *dev, int index)
  105. {
  106. printf("%-3i %c %s @ %08lx", index,
  107. dev_get_flags(dev) & DM_FLAG_ACTIVATED ? '*' : ' ',
  108. dev->name, (ulong)map_to_sysmem(dev));
  109. if (dev->seq_ != -1)
  110. printf(", seq %d", dev_seq(dev));
  111. puts("\n");
  112. }
  113. void dm_dump_uclass(void)
  114. {
  115. struct uclass *uc;
  116. int ret;
  117. int id;
  118. for (id = 0; id < UCLASS_COUNT; id++) {
  119. struct udevice *dev;
  120. int i = 0;
  121. ret = uclass_get(id, &uc);
  122. if (ret)
  123. continue;
  124. printf("uclass %d: %s\n", id, uc->uc_drv->name);
  125. uclass_foreach_dev(dev, uc) {
  126. dm_display_line(dev, i);
  127. i++;
  128. }
  129. puts("\n");
  130. }
  131. }
  132. void dm_dump_driver_compat(void)
  133. {
  134. struct driver *d = ll_entry_start(struct driver, driver);
  135. const int n_ents = ll_entry_count(struct driver, driver);
  136. struct driver *entry;
  137. const struct udevice_id *match;
  138. puts("Driver Compatible\n");
  139. puts("--------------------------------\n");
  140. for (entry = d; entry < d + n_ents; entry++) {
  141. match = entry->of_match;
  142. printf("%-20.20s", entry->name);
  143. if (match) {
  144. printf(" %s", match->compatible);
  145. match++;
  146. }
  147. printf("\n");
  148. for (; match && match->compatible; match++)
  149. printf("%-20.20s %s\n", "", match->compatible);
  150. }
  151. }
  152. void dm_dump_drivers(void)
  153. {
  154. struct driver *d = ll_entry_start(struct driver, driver);
  155. const int n_ents = ll_entry_count(struct driver, driver);
  156. struct driver *entry;
  157. struct udevice *udev;
  158. struct uclass *uc;
  159. int ret;
  160. int i;
  161. puts("Driver uid uclass Devices\n");
  162. puts("----------------------------------------------------------\n");
  163. for (entry = d; entry < d + n_ents; entry++) {
  164. ret = uclass_get(entry->id, &uc);
  165. printf("%-25.25s %-3.3d %-20.20s ", entry->name, entry->id,
  166. !ret ? uc->uc_drv->name : "<no uclass>");
  167. if (ret) {
  168. puts("\n");
  169. continue;
  170. }
  171. i = 0;
  172. uclass_foreach_dev(udev, uc) {
  173. if (udev->driver != entry)
  174. continue;
  175. if (i)
  176. printf("%-51.51s", "");
  177. printf("%-25.25s\n", udev->name);
  178. i++;
  179. }
  180. if (!i)
  181. puts("<none>\n");
  182. }
  183. }
  184. void dm_dump_static_driver_info(void)
  185. {
  186. struct driver_info *drv = ll_entry_start(struct driver_info,
  187. driver_info);
  188. const int n_ents = ll_entry_count(struct driver_info, driver_info);
  189. struct driver_info *entry;
  190. puts("Driver Address\n");
  191. puts("---------------------------------\n");
  192. for (entry = drv; entry != drv + n_ents; entry++)
  193. printf("%-25.25s %p\n", entry->name, entry->plat);
  194. }
  195. void dm_dump_mem(struct dm_stats *stats)
  196. {
  197. int total, total_delta;
  198. int i;
  199. /* Support SPL printf() */
  200. printf("Struct sizes: udevice %x, driver %x, uclass %x, uc_driver %x\n",
  201. (int)sizeof(struct udevice), (int)sizeof(struct driver),
  202. (int)sizeof(struct uclass), (int)sizeof(struct uclass_driver));
  203. printf("Memory: device %x:%x, device names %x, uclass %x:%x\n",
  204. stats->dev_count, stats->dev_size, stats->dev_name_size,
  205. stats->uc_count, stats->uc_size);
  206. printf("\n");
  207. printf("%-15s %5s %5s %5s %5s %5s\n", "Attached type", "Count",
  208. "Size", "Cur", "Tags", "Save");
  209. printf("%-15s %5s %5s %5s %5s %5s\n", "---------------", "-----",
  210. "-----", "-----", "-----", "-----");
  211. total_delta = 0;
  212. for (i = 0; i < DM_TAG_ATTACH_COUNT; i++) {
  213. int cur_size, new_size, delta;
  214. cur_size = stats->dev_count * sizeof(struct udevice);
  215. new_size = stats->dev_count * (sizeof(struct udevice) -
  216. sizeof(void *));
  217. /*
  218. * Let's assume we can fit each dmtag_node into 32 bits. We can
  219. * limit the 'tiny tags' feature to SPL with
  220. * CONFIG_SPL_SYS_MALLOC_F_LEN <= 64KB, so needing 14 bits to
  221. * point to anything in that region (with 4-byte alignment).
  222. * So:
  223. * 4 bits for tag
  224. * 14 bits for offset of dev
  225. * 14 bits for offset of data
  226. */
  227. new_size += stats->attach_count[i] * sizeof(u32);
  228. delta = cur_size - new_size;
  229. total_delta += delta;
  230. printf("%-16s %5x %6x %6x %6x %6x (%d)\n", tag_get_name(i),
  231. stats->attach_count[i], stats->attach_size[i],
  232. cur_size, new_size, delta > 0 ? delta : 0, delta);
  233. }
  234. printf("%-16s %5x %6x\n", "uclass", stats->uc_attach_count,
  235. stats->uc_attach_size);
  236. printf("%-16s %5x %6x %5s %5s %6x (%d)\n", "Attached total",
  237. stats->attach_count_total + stats->uc_attach_count,
  238. stats->attach_size_total + stats->uc_attach_size, "", "",
  239. total_delta > 0 ? total_delta : 0, total_delta);
  240. printf("%-16s %5x %6x\n", "tags", stats->tag_count, stats->tag_size);
  241. printf("\n");
  242. printf("Total size: %x (%d)\n", stats->total_size, stats->total_size);
  243. printf("\n");
  244. total = stats->total_size;
  245. total -= total_delta;
  246. printf("With tags: %x (%d)\n", total, total);
  247. /* Use singly linked lists in struct udevice (3 nodes in each) */
  248. total -= sizeof(void *) * 3 * stats->dev_count;
  249. printf("- singly-linked: %x (%d)\n", total, total);
  250. /* Use an index into the struct_driver list instead of a pointer */
  251. total = total + stats->dev_count * (1 - sizeof(void *));
  252. printf("- driver index: %x (%d)\n", total, total);
  253. /* Same with the uclass */
  254. total = total + stats->dev_count * (1 - sizeof(void *));
  255. printf("- uclass index: %x (%d)\n", total, total);
  256. /* Drop the device name */
  257. printf("Drop device name (not SRAM): %x (%d)\n", stats->dev_name_size,
  258. stats->dev_name_size);
  259. }