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