813 lines · 22.0 KB · C
RawDownload
// SPDX-License-Identifier: GPL-2.0/* * debugfs.c - Designware USB2 DRD controller debugfs * * Copyright (C) 2015 Intel Corporation * Mian Yousaf Kaukab <yousaf.kaukab@intel.com> */ #include <linux/spinlock.h>#include <linux/debugfs.h>#include <linux/seq_file.h>#include <linux/uaccess.h> #include "core.h"#include "debug.h" #if IS_ENABLED(CONFIG_USB_DWC2_PERIPHERAL) || \	IS_ENABLED(CONFIG_USB_DWC2_DUAL_ROLE) /** * testmode_write() - change usb test mode state. * @file: The  file to write to. * @ubuf: The buffer where user wrote. * @count: The ubuf size. * @ppos: Unused parameter. */static ssize_t testmode_write(struct file *file, const char __user *ubuf, size_t		count, loff_t *ppos){	struct seq_file		*s = file->private_data;	struct dwc2_hsotg	*hsotg = s->private;	unsigned long		flags;	u32			testmode = 0;	char			buf[32]; 	if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count)))		return -EFAULT; 	if (!strncmp(buf, "test_j", 6))		testmode = USB_TEST_J;	else if (!strncmp(buf, "test_k", 6))		testmode = USB_TEST_K;	else if (!strncmp(buf, "test_se0_nak", 12))		testmode = USB_TEST_SE0_NAK;	else if (!strncmp(buf, "test_packet", 11))		testmode = USB_TEST_PACKET;	else if (!strncmp(buf, "test_force_enable", 17))		testmode = USB_TEST_FORCE_ENABLE;	else		testmode = 0; 	spin_lock_irqsave(&hsotg->lock, flags);	dwc2_hsotg_set_test_mode(hsotg, testmode);	spin_unlock_irqrestore(&hsotg->lock, flags);	return count;} /** * testmode_show() - debugfs: show usb test mode state * @s: The seq file to write to. * @unused: Unused parameter. * * This debugfs entry shows which usb test mode is currently enabled. */static int testmode_show(struct seq_file *s, void *unused){	struct dwc2_hsotg *hsotg = s->private;	unsigned long flags;	int dctl; 	spin_lock_irqsave(&hsotg->lock, flags);	dctl = dwc2_readl(hsotg, DCTL);	dctl &= DCTL_TSTCTL_MASK;	dctl >>= DCTL_TSTCTL_SHIFT;	spin_unlock_irqrestore(&hsotg->lock, flags); 	switch (dctl) {	case 0:		seq_puts(s, "no test\n");		break;	case USB_TEST_J:		seq_puts(s, "test_j\n");		break;	case USB_TEST_K:		seq_puts(s, "test_k\n");		break;	case USB_TEST_SE0_NAK:		seq_puts(s, "test_se0_nak\n");		break;	case USB_TEST_PACKET:		seq_puts(s, "test_packet\n");		break;	case USB_TEST_FORCE_ENABLE:		seq_puts(s, "test_force_enable\n");		break;	default:		seq_printf(s, "UNKNOWN %d\n", dctl);	} 	return 0;} static int testmode_open(struct inode *inode, struct file *file){	return single_open(file, testmode_show, inode->i_private);} static const struct file_operations testmode_fops = {	.owner		= THIS_MODULE,	.open		= testmode_open,	.write		= testmode_write,	.read		= seq_read,	.llseek		= seq_lseek,	.release	= single_release,}; /** * state_show - debugfs: show overall driver and device state. * @seq: The seq file to write to. * @v: Unused parameter. * * This debugfs entry shows the overall state of the hardware and * some general information about each of the endpoints available * to the system. */static int state_show(struct seq_file *seq, void *v){	struct dwc2_hsotg *hsotg = seq->private;	int idx; 	seq_printf(seq, "DCFG=0x%08x, DCTL=0x%08x, DSTS=0x%08x\n",		   dwc2_readl(hsotg, DCFG),		 dwc2_readl(hsotg, DCTL),		 dwc2_readl(hsotg, DSTS)); 	seq_printf(seq, "DIEPMSK=0x%08x, DOEPMASK=0x%08x\n",		   dwc2_readl(hsotg, DIEPMSK), dwc2_readl(hsotg, DOEPMSK)); 	seq_printf(seq, "GINTMSK=0x%08x, GINTSTS=0x%08x\n",		   dwc2_readl(hsotg, GINTMSK),		   dwc2_readl(hsotg, GINTSTS)); 	seq_printf(seq, "DAINTMSK=0x%08x, DAINT=0x%08x\n",		   dwc2_readl(hsotg, DAINTMSK),		   dwc2_readl(hsotg, DAINT)); 	seq_printf(seq, "GNPTXSTS=0x%08x, GRXSTSR=%08x\n",		   dwc2_readl(hsotg, GNPTXSTS),		   dwc2_readl(hsotg, GRXSTSR)); 	seq_puts(seq, "\nEndpoint status:\n"); 	for (idx = 0; idx < hsotg->num_of_eps; idx++) {		u32 in, out; 		in = dwc2_readl(hsotg, DIEPCTL(idx));		out = dwc2_readl(hsotg, DOEPCTL(idx)); 		seq_printf(seq, "ep%d: DIEPCTL=0x%08x, DOEPCTL=0x%08x",			   idx, in, out); 		in = dwc2_readl(hsotg, DIEPTSIZ(idx));		out = dwc2_readl(hsotg, DOEPTSIZ(idx)); 		seq_printf(seq, ", DIEPTSIZ=0x%08x, DOEPTSIZ=0x%08x",			   in, out); 		seq_puts(seq, "\n");	} 	return 0;}DEFINE_SHOW_ATTRIBUTE(state); /** * fifo_show - debugfs: show the fifo information * @seq: The seq_file to write data to. * @v: Unused parameter. * * Show the FIFO information for the overall fifo and all the * periodic transmission FIFOs. */static int fifo_show(struct seq_file *seq, void *v){	struct dwc2_hsotg *hsotg = seq->private;	int fifo_count = dwc2_hsotg_tx_fifo_count(hsotg);	u32 val;	int idx; 	seq_puts(seq, "Non-periodic FIFOs:\n");	seq_printf(seq, "RXFIFO: Size %d\n", dwc2_readl(hsotg, GRXFSIZ)); 	val = dwc2_readl(hsotg, GNPTXFSIZ);	seq_printf(seq, "NPTXFIFO: Size %d, Start 0x%08x\n",		   val >> FIFOSIZE_DEPTH_SHIFT,		   val & FIFOSIZE_STARTADDR_MASK); 	seq_puts(seq, "\nPeriodic TXFIFOs:\n"); 	for (idx = 1; idx <= fifo_count; idx++) {		val = dwc2_readl(hsotg, DPTXFSIZN(idx)); 		seq_printf(seq, "\tDPTXFIFO%2d: Size %d, Start 0x%08x\n", idx,			   val >> FIFOSIZE_DEPTH_SHIFT,			   val & FIFOSIZE_STARTADDR_MASK);	} 	return 0;}DEFINE_SHOW_ATTRIBUTE(fifo); static const char *decode_direction(int is_in){	return is_in ? "in" : "out";} /** * ep_show - debugfs: show the state of an endpoint. * @seq: The seq_file to write data to. * @v: Unused parameter. * * This debugfs entry shows the state of the given endpoint (one is * registered for each available). */static int ep_show(struct seq_file *seq, void *v){	struct dwc2_hsotg_ep *ep = seq->private;	struct dwc2_hsotg *hsotg = ep->parent;	struct dwc2_hsotg_req *req;	int index = ep->index;	int show_limit = 15;	unsigned long flags; 	seq_printf(seq, "Endpoint index %d, named %s,  dir %s:\n",		   ep->index, ep->ep.name, decode_direction(ep->dir_in)); 	/* first show the register state */ 	seq_printf(seq, "\tDIEPCTL=0x%08x, DOEPCTL=0x%08x\n",		   dwc2_readl(hsotg, DIEPCTL(index)),		   dwc2_readl(hsotg, DOEPCTL(index))); 	seq_printf(seq, "\tDIEPDMA=0x%08x, DOEPDMA=0x%08x\n",		   dwc2_readl(hsotg, DIEPDMA(index)),		   dwc2_readl(hsotg, DOEPDMA(index))); 	seq_printf(seq, "\tDIEPINT=0x%08x, DOEPINT=0x%08x\n",		   dwc2_readl(hsotg, DIEPINT(index)),		   dwc2_readl(hsotg, DOEPINT(index))); 	seq_printf(seq, "\tDIEPTSIZ=0x%08x, DOEPTSIZ=0x%08x\n",		   dwc2_readl(hsotg, DIEPTSIZ(index)),		   dwc2_readl(hsotg, DOEPTSIZ(index))); 	seq_puts(seq, "\n");	seq_printf(seq, "mps %d\n", ep->ep.maxpacket);	seq_printf(seq, "total_data=%ld\n", ep->total_data); 	seq_printf(seq, "request list (%p,%p):\n",		   ep->queue.next, ep->queue.prev); 	spin_lock_irqsave(&hsotg->lock, flags); 	list_for_each_entry(req, &ep->queue, queue) {		if (--show_limit < 0) {			seq_puts(seq, "not showing more requests...\n");			break;		} 		seq_printf(seq, "%c req %p: %d bytes @%p, ",			   req == ep->req ? '*' : ' ',			   req, req->req.length, req->req.buf);		seq_printf(seq, "%d done, res %d\n",			   req->req.actual, req->req.status);	} 	spin_unlock_irqrestore(&hsotg->lock, flags); 	return 0;}DEFINE_SHOW_ATTRIBUTE(ep); /** * dwc2_hsotg_create_debug - create debugfs directory and files * @hsotg: The driver state * * Create the debugfs files to allow the user to get information * about the state of the system. The directory name is created * with the same name as the device itself, in case we end up * with multiple blocks in future systems. */static void dwc2_hsotg_create_debug(struct dwc2_hsotg *hsotg){	struct dentry *root;	unsigned int epidx; 	root = hsotg->debug_root; 	/* create general state file */	debugfs_create_file("state", 0444, root, hsotg, &state_fops);	debugfs_create_file("testmode", 0644, root, hsotg, &testmode_fops);	debugfs_create_file("fifo", 0444, root, hsotg, &fifo_fops); 	/* Create one file for each out endpoint */	for (epidx = 0; epidx < hsotg->num_of_eps; epidx++) {		struct dwc2_hsotg_ep *ep; 		ep = hsotg->eps_out[epidx];		if (ep)			debugfs_create_file(ep->name, 0444, root, ep, &ep_fops);	}	/* Create one file for each in endpoint. EP0 is handled with out eps */	for (epidx = 1; epidx < hsotg->num_of_eps; epidx++) {		struct dwc2_hsotg_ep *ep; 		ep = hsotg->eps_in[epidx];		if (ep)			debugfs_create_file(ep->name, 0444, root, ep, &ep_fops);	}}#elsestatic inline void dwc2_hsotg_create_debug(struct dwc2_hsotg *hsotg) {}#endif /* dwc2_hsotg_delete_debug is removed as cleanup in done in dwc2_debugfs_exit */ #define dump_register(nm)	\{				\	.name	= #nm,		\	.offset	= nm,		\} static const struct debugfs_reg32 dwc2_regs[] = {	/*	 * Accessing registers like this can trigger mode mismatch interrupt.	 * However, according to dwc2 databook, the register access, in this	 * case, is completed on the processor bus but is ignored by the core	 * and does not affect its operation.	 */	dump_register(GOTGCTL),	dump_register(GOTGINT),	dump_register(GAHBCFG),	dump_register(GUSBCFG),	dump_register(GRSTCTL),	dump_register(GINTSTS),	dump_register(GINTMSK),	dump_register(GRXSTSR),	/* Omit GRXSTSP */	dump_register(GRXFSIZ),	dump_register(GNPTXFSIZ),	dump_register(GNPTXSTS),	dump_register(GI2CCTL),	dump_register(GPVNDCTL),	dump_register(GGPIO),	dump_register(GUID),	dump_register(GSNPSID),	dump_register(GHWCFG1),	dump_register(GHWCFG2),	dump_register(GHWCFG3),	dump_register(GHWCFG4),	dump_register(GLPMCFG),	dump_register(GPWRDN),	dump_register(GDFIFOCFG),	dump_register(ADPCTL),	dump_register(HPTXFSIZ),	dump_register(DPTXFSIZN(1)),	dump_register(DPTXFSIZN(2)),	dump_register(DPTXFSIZN(3)),	dump_register(DPTXFSIZN(4)),	dump_register(DPTXFSIZN(5)),	dump_register(DPTXFSIZN(6)),	dump_register(DPTXFSIZN(7)),	dump_register(DPTXFSIZN(8)),	dump_register(DPTXFSIZN(9)),	dump_register(DPTXFSIZN(10)),	dump_register(DPTXFSIZN(11)),	dump_register(DPTXFSIZN(12)),	dump_register(DPTXFSIZN(13)),	dump_register(DPTXFSIZN(14)),	dump_register(DPTXFSIZN(15)),	dump_register(DCFG),	dump_register(DCTL),	dump_register(DSTS),	dump_register(DIEPMSK),	dump_register(DOEPMSK),	dump_register(DAINT),	dump_register(DAINTMSK),	dump_register(DTKNQR1),	dump_register(DTKNQR2),	dump_register(DTKNQR3),	dump_register(DTKNQR4),	dump_register(DVBUSDIS),	dump_register(DVBUSPULSE),	dump_register(DIEPCTL(0)),	dump_register(DIEPCTL(1)),	dump_register(DIEPCTL(2)),	dump_register(DIEPCTL(3)),	dump_register(DIEPCTL(4)),	dump_register(DIEPCTL(5)),	dump_register(DIEPCTL(6)),	dump_register(DIEPCTL(7)),	dump_register(DIEPCTL(8)),	dump_register(DIEPCTL(9)),	dump_register(DIEPCTL(10)),	dump_register(DIEPCTL(11)),	dump_register(DIEPCTL(12)),	dump_register(DIEPCTL(13)),	dump_register(DIEPCTL(14)),	dump_register(DIEPCTL(15)),	dump_register(DOEPCTL(0)),	dump_register(DOEPCTL(1)),	dump_register(DOEPCTL(2)),	dump_register(DOEPCTL(3)),	dump_register(DOEPCTL(4)),	dump_register(DOEPCTL(5)),	dump_register(DOEPCTL(6)),	dump_register(DOEPCTL(7)),	dump_register(DOEPCTL(8)),	dump_register(DOEPCTL(9)),	dump_register(DOEPCTL(10)),	dump_register(DOEPCTL(11)),	dump_register(DOEPCTL(12)),	dump_register(DOEPCTL(13)),	dump_register(DOEPCTL(14)),	dump_register(DOEPCTL(15)),	dump_register(DIEPINT(0)),	dump_register(DIEPINT(1)),	dump_register(DIEPINT(2)),	dump_register(DIEPINT(3)),	dump_register(DIEPINT(4)),	dump_register(DIEPINT(5)),	dump_register(DIEPINT(6)),	dump_register(DIEPINT(7)),	dump_register(DIEPINT(8)),	dump_register(DIEPINT(9)),	dump_register(DIEPINT(10)),	dump_register(DIEPINT(11)),	dump_register(DIEPINT(12)),	dump_register(DIEPINT(13)),	dump_register(DIEPINT(14)),	dump_register(DIEPINT(15)),	dump_register(DOEPINT(0)),	dump_register(DOEPINT(1)),	dump_register(DOEPINT(2)),	dump_register(DOEPINT(3)),	dump_register(DOEPINT(4)),	dump_register(DOEPINT(5)),	dump_register(DOEPINT(6)),	dump_register(DOEPINT(7)),	dump_register(DOEPINT(8)),	dump_register(DOEPINT(9)),	dump_register(DOEPINT(10)),	dump_register(DOEPINT(11)),	dump_register(DOEPINT(12)),	dump_register(DOEPINT(13)),	dump_register(DOEPINT(14)),	dump_register(DOEPINT(15)),	dump_register(DIEPTSIZ(0)),	dump_register(DIEPTSIZ(1)),	dump_register(DIEPTSIZ(2)),	dump_register(DIEPTSIZ(3)),	dump_register(DIEPTSIZ(4)),	dump_register(DIEPTSIZ(5)),	dump_register(DIEPTSIZ(6)),	dump_register(DIEPTSIZ(7)),	dump_register(DIEPTSIZ(8)),	dump_register(DIEPTSIZ(9)),	dump_register(DIEPTSIZ(10)),	dump_register(DIEPTSIZ(11)),	dump_register(DIEPTSIZ(12)),	dump_register(DIEPTSIZ(13)),	dump_register(DIEPTSIZ(14)),	dump_register(DIEPTSIZ(15)),	dump_register(DOEPTSIZ(0)),	dump_register(DOEPTSIZ(1)),	dump_register(DOEPTSIZ(2)),	dump_register(DOEPTSIZ(3)),	dump_register(DOEPTSIZ(4)),	dump_register(DOEPTSIZ(5)),	dump_register(DOEPTSIZ(6)),	dump_register(DOEPTSIZ(7)),	dump_register(DOEPTSIZ(8)),	dump_register(DOEPTSIZ(9)),	dump_register(DOEPTSIZ(10)),	dump_register(DOEPTSIZ(11)),	dump_register(DOEPTSIZ(12)),	dump_register(DOEPTSIZ(13)),	dump_register(DOEPTSIZ(14)),	dump_register(DOEPTSIZ(15)),	dump_register(DIEPDMA(0)),	dump_register(DIEPDMA(1)),	dump_register(DIEPDMA(2)),	dump_register(DIEPDMA(3)),	dump_register(DIEPDMA(4)),	dump_register(DIEPDMA(5)),	dump_register(DIEPDMA(6)),	dump_register(DIEPDMA(7)),	dump_register(DIEPDMA(8)),	dump_register(DIEPDMA(9)),	dump_register(DIEPDMA(10)),

Lines 1–500 of 813.