debug.c 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*
  3. * Wireless Host Controller (WHC) debug.
  4. *
  5. * Copyright (C) 2008 Cambridge Silicon Radio Ltd.
  6. */
  7. #include <linux/slab.h>
  8. #include <linux/kernel.h>
  9. #include <linux/debugfs.h>
  10. #include <linux/seq_file.h>
  11. #include <linux/export.h>
  12. #include "../../wusbcore/wusbhc.h"
  13. #include "whcd.h"
  14. struct whc_dbg {
  15. struct dentry *di_f;
  16. struct dentry *asl_f;
  17. struct dentry *pzl_f;
  18. };
  19. static void qset_print(struct seq_file *s, struct whc_qset *qset)
  20. {
  21. static const char *qh_type[] = {
  22. "ctrl", "isoc", "bulk", "intr", "rsvd", "rsvd", "rsvd", "lpintr", };
  23. struct whc_std *std;
  24. struct urb *urb = NULL;
  25. int i;
  26. seq_printf(s, "qset %08x", (u32)qset->qset_dma);
  27. if (&qset->list_node == qset->whc->async_list.prev) {
  28. seq_printf(s, " (dummy)\n");
  29. } else {
  30. seq_printf(s, " ep%d%s-%s maxpkt: %d\n",
  31. qset->qh.info1 & 0x0f,
  32. (qset->qh.info1 >> 4) & 0x1 ? "in" : "out",
  33. qh_type[(qset->qh.info1 >> 5) & 0x7],
  34. (qset->qh.info1 >> 16) & 0xffff);
  35. }
  36. seq_printf(s, " -> %08x\n", (u32)qset->qh.link);
  37. seq_printf(s, " info: %08x %08x %08x\n",
  38. qset->qh.info1, qset->qh.info2, qset->qh.info3);
  39. seq_printf(s, " sts: %04x errs: %d curwin: %08x\n",
  40. qset->qh.status, qset->qh.err_count, qset->qh.cur_window);
  41. seq_printf(s, " TD: sts: %08x opts: %08x\n",
  42. qset->qh.overlay.qtd.status, qset->qh.overlay.qtd.options);
  43. for (i = 0; i < WHCI_QSET_TD_MAX; i++) {
  44. seq_printf(s, " %c%c TD[%d]: sts: %08x opts: %08x ptr: %08x\n",
  45. i == qset->td_start ? 'S' : ' ',
  46. i == qset->td_end ? 'E' : ' ',
  47. i, qset->qtd[i].status, qset->qtd[i].options,
  48. (u32)qset->qtd[i].page_list_ptr);
  49. }
  50. seq_printf(s, " ntds: %d\n", qset->ntds);
  51. list_for_each_entry(std, &qset->stds, list_node) {
  52. if (urb != std->urb) {
  53. urb = std->urb;
  54. seq_printf(s, " urb %p transferred: %d bytes\n", urb,
  55. urb->actual_length);
  56. }
  57. if (std->qtd)
  58. seq_printf(s, " sTD[%td]: %zu bytes @ %08x\n",
  59. std->qtd - &qset->qtd[0],
  60. std->len, std->num_pointers ?
  61. (u32)(std->pl_virt[0].buf_ptr) : (u32)std->dma_addr);
  62. else
  63. seq_printf(s, " sTD[-]: %zd bytes @ %08x\n",
  64. std->len, std->num_pointers ?
  65. (u32)(std->pl_virt[0].buf_ptr) : (u32)std->dma_addr);
  66. }
  67. }
  68. static int di_show(struct seq_file *s, void *p)
  69. {
  70. struct whc *whc = s->private;
  71. int d;
  72. for (d = 0; d < whc->n_devices; d++) {
  73. struct di_buf_entry *di = &whc->di_buf[d];
  74. seq_printf(s, "DI[%d]\n", d);
  75. seq_printf(s, " availability: %*pb\n",
  76. UWB_NUM_MAS, (unsigned long *)di->availability_info);
  77. seq_printf(s, " %c%c key idx: %d dev addr: %d\n",
  78. (di->addr_sec_info & WHC_DI_SECURE) ? 'S' : ' ',
  79. (di->addr_sec_info & WHC_DI_DISABLE) ? 'D' : ' ',
  80. (di->addr_sec_info & WHC_DI_KEY_IDX_MASK) >> 8,
  81. (di->addr_sec_info & WHC_DI_DEV_ADDR_MASK));
  82. }
  83. return 0;
  84. }
  85. DEFINE_SHOW_ATTRIBUTE(di);
  86. static int asl_show(struct seq_file *s, void *p)
  87. {
  88. struct whc *whc = s->private;
  89. struct whc_qset *qset;
  90. list_for_each_entry(qset, &whc->async_list, list_node) {
  91. qset_print(s, qset);
  92. }
  93. return 0;
  94. }
  95. DEFINE_SHOW_ATTRIBUTE(asl);
  96. static int pzl_show(struct seq_file *s, void *p)
  97. {
  98. struct whc *whc = s->private;
  99. struct whc_qset *qset;
  100. int period;
  101. for (period = 0; period < 5; period++) {
  102. seq_printf(s, "Period %d\n", period);
  103. list_for_each_entry(qset, &whc->periodic_list[period], list_node) {
  104. qset_print(s, qset);
  105. }
  106. }
  107. return 0;
  108. }
  109. DEFINE_SHOW_ATTRIBUTE(pzl);
  110. void whc_dbg_init(struct whc *whc)
  111. {
  112. if (whc->wusbhc.pal.debugfs_dir == NULL)
  113. return;
  114. whc->dbg = kzalloc(sizeof(struct whc_dbg), GFP_KERNEL);
  115. if (whc->dbg == NULL)
  116. return;
  117. whc->dbg->di_f = debugfs_create_file("di", 0444,
  118. whc->wusbhc.pal.debugfs_dir, whc,
  119. &di_fops);
  120. whc->dbg->asl_f = debugfs_create_file("asl", 0444,
  121. whc->wusbhc.pal.debugfs_dir, whc,
  122. &asl_fops);
  123. whc->dbg->pzl_f = debugfs_create_file("pzl", 0444,
  124. whc->wusbhc.pal.debugfs_dir, whc,
  125. &pzl_fops);
  126. }
  127. void whc_dbg_clean_up(struct whc *whc)
  128. {
  129. if (whc->dbg) {
  130. debugfs_remove(whc->dbg->pzl_f);
  131. debugfs_remove(whc->dbg->asl_f);
  132. debugfs_remove(whc->dbg->di_f);
  133. kfree(whc->dbg);
  134. }
  135. }