imx21-dbg.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440
  1. // SPDX-License-Identifier: GPL-2.0+
  2. /*
  3. * Copyright (c) 2009 by Martin Fuzzey
  4. */
  5. /* this file is part of imx21-hcd.c */
  6. #ifdef CONFIG_DYNAMIC_DEBUG
  7. #define DEBUG
  8. #endif
  9. #ifndef DEBUG
  10. static inline void create_debug_files(struct imx21 *imx21) { }
  11. static inline void remove_debug_files(struct imx21 *imx21) { }
  12. static inline void debug_urb_submitted(struct imx21 *imx21, struct urb *urb) {}
  13. static inline void debug_urb_completed(struct imx21 *imx21, struct urb *urb,
  14. int status) {}
  15. static inline void debug_urb_unlinked(struct imx21 *imx21, struct urb *urb) {}
  16. static inline void debug_urb_queued_for_etd(struct imx21 *imx21,
  17. struct urb *urb) {}
  18. static inline void debug_urb_queued_for_dmem(struct imx21 *imx21,
  19. struct urb *urb) {}
  20. static inline void debug_etd_allocated(struct imx21 *imx21) {}
  21. static inline void debug_etd_freed(struct imx21 *imx21) {}
  22. static inline void debug_dmem_allocated(struct imx21 *imx21, int size) {}
  23. static inline void debug_dmem_freed(struct imx21 *imx21, int size) {}
  24. static inline void debug_isoc_submitted(struct imx21 *imx21,
  25. int frame, struct td *td) {}
  26. static inline void debug_isoc_completed(struct imx21 *imx21,
  27. int frame, struct td *td, int cc, int len) {}
  28. #else
  29. #include <linux/debugfs.h>
  30. #include <linux/seq_file.h>
  31. static const char *dir_labels[] = {
  32. "TD 0",
  33. "OUT",
  34. "IN",
  35. "TD 1"
  36. };
  37. static const char *speed_labels[] = {
  38. "Full",
  39. "Low"
  40. };
  41. static const char *format_labels[] = {
  42. "Control",
  43. "ISO",
  44. "Bulk",
  45. "Interrupt"
  46. };
  47. static inline struct debug_stats *stats_for_urb(struct imx21 *imx21,
  48. struct urb *urb)
  49. {
  50. return usb_pipeisoc(urb->pipe) ?
  51. &imx21->isoc_stats : &imx21->nonisoc_stats;
  52. }
  53. static void debug_urb_submitted(struct imx21 *imx21, struct urb *urb)
  54. {
  55. stats_for_urb(imx21, urb)->submitted++;
  56. }
  57. static void debug_urb_completed(struct imx21 *imx21, struct urb *urb, int st)
  58. {
  59. if (st)
  60. stats_for_urb(imx21, urb)->completed_failed++;
  61. else
  62. stats_for_urb(imx21, urb)->completed_ok++;
  63. }
  64. static void debug_urb_unlinked(struct imx21 *imx21, struct urb *urb)
  65. {
  66. stats_for_urb(imx21, urb)->unlinked++;
  67. }
  68. static void debug_urb_queued_for_etd(struct imx21 *imx21, struct urb *urb)
  69. {
  70. stats_for_urb(imx21, urb)->queue_etd++;
  71. }
  72. static void debug_urb_queued_for_dmem(struct imx21 *imx21, struct urb *urb)
  73. {
  74. stats_for_urb(imx21, urb)->queue_dmem++;
  75. }
  76. static inline void debug_etd_allocated(struct imx21 *imx21)
  77. {
  78. imx21->etd_usage.maximum = max(
  79. ++(imx21->etd_usage.value),
  80. imx21->etd_usage.maximum);
  81. }
  82. static inline void debug_etd_freed(struct imx21 *imx21)
  83. {
  84. imx21->etd_usage.value--;
  85. }
  86. static inline void debug_dmem_allocated(struct imx21 *imx21, int size)
  87. {
  88. imx21->dmem_usage.value += size;
  89. imx21->dmem_usage.maximum = max(
  90. imx21->dmem_usage.value,
  91. imx21->dmem_usage.maximum);
  92. }
  93. static inline void debug_dmem_freed(struct imx21 *imx21, int size)
  94. {
  95. imx21->dmem_usage.value -= size;
  96. }
  97. static void debug_isoc_submitted(struct imx21 *imx21,
  98. int frame, struct td *td)
  99. {
  100. struct debug_isoc_trace *trace = &imx21->isoc_trace[
  101. imx21->isoc_trace_index++];
  102. imx21->isoc_trace_index %= ARRAY_SIZE(imx21->isoc_trace);
  103. trace->schedule_frame = td->frame;
  104. trace->submit_frame = frame;
  105. trace->request_len = td->len;
  106. trace->td = td;
  107. }
  108. static inline void debug_isoc_completed(struct imx21 *imx21,
  109. int frame, struct td *td, int cc, int len)
  110. {
  111. struct debug_isoc_trace *trace, *trace_failed;
  112. int i;
  113. int found = 0;
  114. trace = imx21->isoc_trace;
  115. for (i = 0; i < ARRAY_SIZE(imx21->isoc_trace); i++, trace++) {
  116. if (trace->td == td) {
  117. trace->done_frame = frame;
  118. trace->done_len = len;
  119. trace->cc = cc;
  120. trace->td = NULL;
  121. found = 1;
  122. break;
  123. }
  124. }
  125. if (found && cc) {
  126. trace_failed = &imx21->isoc_trace_failed[
  127. imx21->isoc_trace_index_failed++];
  128. imx21->isoc_trace_index_failed %= ARRAY_SIZE(
  129. imx21->isoc_trace_failed);
  130. *trace_failed = *trace;
  131. }
  132. }
  133. static char *format_ep(struct usb_host_endpoint *ep, char *buf, int bufsize)
  134. {
  135. if (ep)
  136. snprintf(buf, bufsize, "ep_%02x (type:%02X kaddr:%p)",
  137. ep->desc.bEndpointAddress,
  138. usb_endpoint_type(&ep->desc),
  139. ep);
  140. else
  141. snprintf(buf, bufsize, "none");
  142. return buf;
  143. }
  144. static char *format_etd_dword0(u32 value, char *buf, int bufsize)
  145. {
  146. snprintf(buf, bufsize,
  147. "addr=%d ep=%d dir=%s speed=%s format=%s halted=%d",
  148. value & 0x7F,
  149. (value >> DW0_ENDPNT) & 0x0F,
  150. dir_labels[(value >> DW0_DIRECT) & 0x03],
  151. speed_labels[(value >> DW0_SPEED) & 0x01],
  152. format_labels[(value >> DW0_FORMAT) & 0x03],
  153. (value >> DW0_HALTED) & 0x01);
  154. return buf;
  155. }
  156. static int debug_status_show(struct seq_file *s, void *v)
  157. {
  158. struct imx21 *imx21 = s->private;
  159. int etds_allocated = 0;
  160. int etds_sw_busy = 0;
  161. int etds_hw_busy = 0;
  162. int dmem_blocks = 0;
  163. int queued_for_etd = 0;
  164. int queued_for_dmem = 0;
  165. unsigned int dmem_bytes = 0;
  166. int i;
  167. struct etd_priv *etd;
  168. u32 etd_enable_mask;
  169. unsigned long flags;
  170. struct imx21_dmem_area *dmem;
  171. struct ep_priv *ep_priv;
  172. spin_lock_irqsave(&imx21->lock, flags);
  173. etd_enable_mask = readl(imx21->regs + USBH_ETDENSET);
  174. for (i = 0, etd = imx21->etd; i < USB_NUM_ETD; i++, etd++) {
  175. if (etd->alloc)
  176. etds_allocated++;
  177. if (etd->urb)
  178. etds_sw_busy++;
  179. if (etd_enable_mask & (1<<i))
  180. etds_hw_busy++;
  181. }
  182. list_for_each_entry(dmem, &imx21->dmem_list, list) {
  183. dmem_bytes += dmem->size;
  184. dmem_blocks++;
  185. }
  186. list_for_each_entry(ep_priv, &imx21->queue_for_etd, queue)
  187. queued_for_etd++;
  188. list_for_each_entry(etd, &imx21->queue_for_dmem, queue)
  189. queued_for_dmem++;
  190. spin_unlock_irqrestore(&imx21->lock, flags);
  191. seq_printf(s,
  192. "Frame: %d\n"
  193. "ETDs allocated: %d/%d (max=%d)\n"
  194. "ETDs in use sw: %d\n"
  195. "ETDs in use hw: %d\n"
  196. "DMEM allocated: %d/%d (max=%d)\n"
  197. "DMEM blocks: %d\n"
  198. "Queued waiting for ETD: %d\n"
  199. "Queued waiting for DMEM: %d\n",
  200. readl(imx21->regs + USBH_FRMNUB) & 0xFFFF,
  201. etds_allocated, USB_NUM_ETD, imx21->etd_usage.maximum,
  202. etds_sw_busy,
  203. etds_hw_busy,
  204. dmem_bytes, DMEM_SIZE, imx21->dmem_usage.maximum,
  205. dmem_blocks,
  206. queued_for_etd,
  207. queued_for_dmem);
  208. return 0;
  209. }
  210. DEFINE_SHOW_ATTRIBUTE(debug_status);
  211. static int debug_dmem_show(struct seq_file *s, void *v)
  212. {
  213. struct imx21 *imx21 = s->private;
  214. struct imx21_dmem_area *dmem;
  215. unsigned long flags;
  216. char ep_text[40];
  217. spin_lock_irqsave(&imx21->lock, flags);
  218. list_for_each_entry(dmem, &imx21->dmem_list, list)
  219. seq_printf(s,
  220. "%04X: size=0x%X "
  221. "ep=%s\n",
  222. dmem->offset, dmem->size,
  223. format_ep(dmem->ep, ep_text, sizeof(ep_text)));
  224. spin_unlock_irqrestore(&imx21->lock, flags);
  225. return 0;
  226. }
  227. DEFINE_SHOW_ATTRIBUTE(debug_dmem);
  228. static int debug_etd_show(struct seq_file *s, void *v)
  229. {
  230. struct imx21 *imx21 = s->private;
  231. struct etd_priv *etd;
  232. char buf[60];
  233. u32 dword;
  234. int i, j;
  235. unsigned long flags;
  236. spin_lock_irqsave(&imx21->lock, flags);
  237. for (i = 0, etd = imx21->etd; i < USB_NUM_ETD; i++, etd++) {
  238. int state = -1;
  239. struct urb_priv *urb_priv;
  240. if (etd->urb) {
  241. urb_priv = etd->urb->hcpriv;
  242. if (urb_priv)
  243. state = urb_priv->state;
  244. }
  245. seq_printf(s,
  246. "etd_num: %d\n"
  247. "ep: %s\n"
  248. "alloc: %d\n"
  249. "len: %d\n"
  250. "busy sw: %d\n"
  251. "busy hw: %d\n"
  252. "urb state: %d\n"
  253. "current urb: %p\n",
  254. i,
  255. format_ep(etd->ep, buf, sizeof(buf)),
  256. etd->alloc,
  257. etd->len,
  258. etd->urb != NULL,
  259. (readl(imx21->regs + USBH_ETDENSET) & (1 << i)) > 0,
  260. state,
  261. etd->urb);
  262. for (j = 0; j < 4; j++) {
  263. dword = etd_readl(imx21, i, j);
  264. switch (j) {
  265. case 0:
  266. format_etd_dword0(dword, buf, sizeof(buf));
  267. break;
  268. case 2:
  269. snprintf(buf, sizeof(buf),
  270. "cc=0X%02X", dword >> DW2_COMPCODE);
  271. break;
  272. default:
  273. *buf = 0;
  274. break;
  275. }
  276. seq_printf(s,
  277. "dword %d: submitted=%08X cur=%08X [%s]\n",
  278. j,
  279. etd->submitted_dwords[j],
  280. dword,
  281. buf);
  282. }
  283. seq_printf(s, "\n");
  284. }
  285. spin_unlock_irqrestore(&imx21->lock, flags);
  286. return 0;
  287. }
  288. DEFINE_SHOW_ATTRIBUTE(debug_etd);
  289. static void debug_statistics_show_one(struct seq_file *s,
  290. const char *name, struct debug_stats *stats)
  291. {
  292. seq_printf(s, "%s:\n"
  293. "submitted URBs: %lu\n"
  294. "completed OK: %lu\n"
  295. "completed failed: %lu\n"
  296. "unlinked: %lu\n"
  297. "queued for ETD: %lu\n"
  298. "queued for DMEM: %lu\n\n",
  299. name,
  300. stats->submitted,
  301. stats->completed_ok,
  302. stats->completed_failed,
  303. stats->unlinked,
  304. stats->queue_etd,
  305. stats->queue_dmem);
  306. }
  307. static int debug_statistics_show(struct seq_file *s, void *v)
  308. {
  309. struct imx21 *imx21 = s->private;
  310. unsigned long flags;
  311. spin_lock_irqsave(&imx21->lock, flags);
  312. debug_statistics_show_one(s, "nonisoc", &imx21->nonisoc_stats);
  313. debug_statistics_show_one(s, "isoc", &imx21->isoc_stats);
  314. seq_printf(s, "unblock kludge triggers: %lu\n", imx21->debug_unblocks);
  315. spin_unlock_irqrestore(&imx21->lock, flags);
  316. return 0;
  317. }
  318. DEFINE_SHOW_ATTRIBUTE(debug_statistics);
  319. static void debug_isoc_show_one(struct seq_file *s,
  320. const char *name, int index, struct debug_isoc_trace *trace)
  321. {
  322. seq_printf(s, "%s %d:\n"
  323. "cc=0X%02X\n"
  324. "scheduled frame %d (%d)\n"
  325. "submitted frame %d (%d)\n"
  326. "completed frame %d (%d)\n"
  327. "requested length=%d\n"
  328. "completed length=%d\n\n",
  329. name, index,
  330. trace->cc,
  331. trace->schedule_frame, trace->schedule_frame & 0xFFFF,
  332. trace->submit_frame, trace->submit_frame & 0xFFFF,
  333. trace->done_frame, trace->done_frame & 0xFFFF,
  334. trace->request_len,
  335. trace->done_len);
  336. }
  337. static int debug_isoc_show(struct seq_file *s, void *v)
  338. {
  339. struct imx21 *imx21 = s->private;
  340. struct debug_isoc_trace *trace;
  341. unsigned long flags;
  342. int i;
  343. spin_lock_irqsave(&imx21->lock, flags);
  344. trace = imx21->isoc_trace_failed;
  345. for (i = 0; i < ARRAY_SIZE(imx21->isoc_trace_failed); i++, trace++)
  346. debug_isoc_show_one(s, "isoc failed", i, trace);
  347. trace = imx21->isoc_trace;
  348. for (i = 0; i < ARRAY_SIZE(imx21->isoc_trace); i++, trace++)
  349. debug_isoc_show_one(s, "isoc", i, trace);
  350. spin_unlock_irqrestore(&imx21->lock, flags);
  351. return 0;
  352. }
  353. DEFINE_SHOW_ATTRIBUTE(debug_isoc);
  354. static void create_debug_files(struct imx21 *imx21)
  355. {
  356. struct dentry *root;
  357. root = debugfs_create_dir(dev_name(imx21->dev), NULL);
  358. imx21->debug_root = root;
  359. debugfs_create_file("status", S_IRUGO, root, imx21, &debug_status_fops);
  360. debugfs_create_file("dmem", S_IRUGO, root, imx21, &debug_dmem_fops);
  361. debugfs_create_file("etd", S_IRUGO, root, imx21, &debug_etd_fops);
  362. debugfs_create_file("statistics", S_IRUGO, root, imx21,
  363. &debug_statistics_fops);
  364. debugfs_create_file("isoc", S_IRUGO, root, imx21, &debug_isoc_fops);
  365. }
  366. static void remove_debug_files(struct imx21 *imx21)
  367. {
  368. debugfs_remove_recursive(imx21->debug_root);
  369. }
  370. #endif