Now that the SPDX tag is in all USB files, that identifies the license in a specific and legally-defined manner. So the extra GPL text wording can be removed as it is no longer needed at all. This is done on a quest to remove the 700+ different ways that files in the kernel describe the GPL license text. And there's unneeded stuff like the address (sometimes incorrect) for the FSF which is never needed. No copyright headers or other non-license-description text was removed. Cc: Felipe Balbi <felipe.balbi@linux.intel.com> Cc: Johan Hovold <johan@kernel.org> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
190 lines
4.8 KiB
C
190 lines
4.8 KiB
C
// 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_print(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;
|
|
}
|
|
|
|
static int asl_print(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;
|
|
}
|
|
|
|
static int pzl_print(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;
|
|
}
|
|
|
|
static int di_open(struct inode *inode, struct file *file)
|
|
{
|
|
return single_open(file, di_print, inode->i_private);
|
|
}
|
|
|
|
static int asl_open(struct inode *inode, struct file *file)
|
|
{
|
|
return single_open(file, asl_print, inode->i_private);
|
|
}
|
|
|
|
static int pzl_open(struct inode *inode, struct file *file)
|
|
{
|
|
return single_open(file, pzl_print, inode->i_private);
|
|
}
|
|
|
|
static const struct file_operations di_fops = {
|
|
.open = di_open,
|
|
.read = seq_read,
|
|
.llseek = seq_lseek,
|
|
.release = single_release,
|
|
.owner = THIS_MODULE,
|
|
};
|
|
|
|
static const struct file_operations asl_fops = {
|
|
.open = asl_open,
|
|
.read = seq_read,
|
|
.llseek = seq_lseek,
|
|
.release = single_release,
|
|
.owner = THIS_MODULE,
|
|
};
|
|
|
|
static const struct file_operations pzl_fops = {
|
|
.open = pzl_open,
|
|
.read = seq_read,
|
|
.llseek = seq_lseek,
|
|
.release = single_release,
|
|
.owner = THIS_MODULE,
|
|
};
|
|
|
|
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);
|
|
}
|
|
}
|