Skip to contentSkip to conversation

usb: xhci: Add debugfs interface for xHCI driver

PATCH Superseded Lu Baolu 2 participants 3 messages Jul 29, 2017 – Jul 30, 2017

Subsystems (2)

v1 of 2 Superseded Latest is v2 →

lore
Share & tools
lore

Lu Baolu

author
#0 lore raw

PATCH 1/1 usb: xhci: Add debugfs interface for xHCI driver

This adds debugfs consumer for xHCI driver. The debugfs entries read all host registers, device/endpoint contexts, command ring, event ring and various endpoint rings. With these entries, users can check the registers and memory spaces used by a host during run time, or save all the information with a simple 'cp -r' for post-mortem programs.

The file hierarchy looks like this.

[root of debugfs]

|__usb
|____[e,u,o]hci                 <---------[root for other HCIs]
|____xhci                       <---------------[root for xHCI]
|______0000:00:14.0             <--------------[xHCI host name]
|________reg-cap                <--------[capability registers]
|________reg-op                 <-------[operational registers]
|________reg-runtime            <-----------[runtime registers]
|________reg-ext-#cap_name      <----[extended capability regs]
|________command-ring           <-------[root for command ring]
|__________cycle                <------------------[ring cycle]
|__________dequeue              <--------[ring dequeue pointer]
|__________enqueue              <--------[ring enqueue pointer]
|__________trbs                 <-------------------[ring trbs]
|________event-ring             <---------[root for event ring]
|__________cycle                <------------------[ring cycle]
|__________dequeue              <--------[ring dequeue pointer]
|__________enqueue              <--------[ring enqueue pointer]
|__________trbs                 <-------------------[ring trbs]
|________devices                <------------[root for devices]
|__________#slot_id             <-----------[root for a device]
|____________name               <-----------------[device name]
|____________slot-context       <----------------[slot context]
|____________ep-context         <-----------[endpoint contexts]
|____________ep#ep_index        <--------[root for an endpoint]
|______________cycle            <------------------[ring cycle]
|______________dequeue          <--------[ring dequeue pointer]
|______________enqueue          <--------[ring enqueue pointer]
|______________trbs             <-------------------[ring trbs]
---
 drivers/usb/host/Makefile       |   4 +
 drivers/usb/host/xhci-debugfs.c | 552 ++++++++++++++++++++++++++++++++++++++++
 drivers/usb/host/xhci-debugfs.h | 137 ++++++++++
 drivers/usb/host/xhci-mem.c     |   4 +-
 drivers/usb/host/xhci.c         |  21 +-
 drivers/usb/host/xhci.h         |   9 +
 6 files changed, 723 insertions(+), 4 deletions(-)
 create mode 100644 drivers/usb/host/xhci-debugfs.c
 create mode 100644 drivers/usb/host/xhci-debugfs.h
drivers/usb/host/Makefile +4 -0
index cf2691f..b2a7f05 100644
@@ -25,6 +25,10 @@ ifneq ($(CONFIG_USB_XHCI_RCAR), )
 	xhci-plat-hcd-y		+= xhci-rcar.o
 endif
 
+ifneq ($(CONFIG_DEBUG_FS),)
+	xhci-hcd-y		+= xhci-debugfs.o
+endif
+
 obj-$(CONFIG_USB_WHCI_HCD)	+= whci/
 
 obj-$(CONFIG_USB_PCI)	+= pci-quirks.o
drivers/usb/host/xhci-debugfs.c new file +552 -0

552 lines not on this page · raw message

drivers/usb/host/xhci-debugfs.h new file +137 -0

137 lines not on this page · raw message

drivers/usb/host/xhci-mem.c +1 -3
index 2a82c92..62fd109 100644
@@ -28,6 +28,7 @@
 
 #include "xhci.h"
 #include "xhci-trace.h"
+#include "xhci-debugfs.h"
 
 /*
  * Allocates a generic ring segment from the ring pool, sets the dma address,
@@ -465,8 +466,6 @@ int xhci_ring_expansion(struct xhci_hcd *xhci, struct xhci_ring *ring,
 	return 0;
 }
 
-#define CTX_SIZE(_hcc) (HCC_64BYTE_CONTEXT(_hcc) ? 64 : 32)
-
 static struct xhci_container_ctx *xhci_alloc_container_ctx(struct xhci_hcd *xhci,
 						    int type, gfp_t flags)
 {
@@ -1496,7 +1495,6 @@ int xhci_endpoint_init(struct xhci_hcd *xhci,
 	ep_ctx->tx_info = cpu_to_le32(EP_MAX_ESIT_PAYLOAD_LO(max_esit_payload) |
 				      EP_AVG_TRB_LENGTH(avg_trb_len));
 
-	/* FIXME Debug endpoint context */
 	return 0;
 }
 
drivers/usb/host/xhci.c +20 -1
index b2ff1ff..ea08c2a 100644
@@ -32,6 +32,7 @@
 #include "xhci.h"
 #include "xhci-trace.h"
 #include "xhci-mtk.h"
+#include "xhci-debugfs.h"
 
 #define DRIVER_AUTHOR "Sarah Sharp"
 #define DRIVER_DESC "'eXtensible' Host Controller (xHC) Driver"
@@ -632,6 +633,9 @@ int xhci_run(struct usb_hcd *hcd)
 	}
 	xhci_dbg_trace(xhci, trace_xhci_dbg_init,
 			"Finished xhci_run for USB2 roothub");
+
+	xhci_debugfs_init(xhci);
+
 	return 0;
 }
 EXPORT_SYMBOL_GPL(xhci_run);
@@ -650,6 +654,8 @@ static void xhci_stop(struct usb_hcd *hcd)
 	u32 temp;
 	struct xhci_hcd *xhci = hcd_to_xhci(hcd);
 
+	xhci_debugfs_exit(xhci);
+
 	mutex_lock(&xhci->mutex);
 
 	/* Only halt host and free memory after both hcds are removed */
@@ -1600,6 +1606,8 @@ static int xhci_drop_endpoint(struct usb_hcd *hcd, struct usb_device *udev,
 	ctrl_ctx->add_flags &= cpu_to_le32(~drop_flag);
 	new_add_flags = le32_to_cpu(ctrl_ctx->add_flags);
 
+	xhci_debugfs_remove_endpoint(xhci, xhci->devs[udev->slot_id], ep_index);
+
 	xhci_endpoint_zero(xhci, xhci->devs[udev->slot_id], ep);
 
 	if (xhci->quirks & XHCI_MTK_HOST)
@@ -1722,6 +1730,8 @@ static int xhci_add_endpoint(struct usb_hcd *hcd, struct usb_device *udev,
 	/* Store the usb_device pointer for later use */
 	ep->hcpriv = udev;
 
+	xhci_debugfs_create_endpoint(xhci, virt_dev, ep_index);
+
 	xhci_dbg(xhci, "add ep 0x%x, slot id %d, new drop flags = %#x, new add flags = %#x\n",
 			(unsigned int) ep->desc.bEndpointAddress,
 			udev->slot_id,
@@ -3521,6 +3531,8 @@ static void xhci_free_dev(struct usb_hcd *hcd, struct usb_device *udev)
 	int i, ret;
 	struct xhci_command *command;
 
+	xhci_debugfs_remove_slot(xhci, udev->slot_id);
+
 	command = xhci_alloc_command(xhci, false, false, GFP_KERNEL);
 	if (!command)
 		return;
@@ -3693,6 +3705,8 @@ int xhci_alloc_dev(struct usb_hcd *hcd, struct usb_device *udev)
 
 	udev->slot_id = slot_id;
 
+	xhci_debugfs_create_slot(xhci, slot_id);
+
 #ifndef CONFIG_USB_DEFAULT_PERSIST
 	/*
 	 * If resetting upon resume, we can't put the controller into runtime
@@ -5003,6 +5017,8 @@ static int __init xhci_hcd_init(void)
 	if (usb_disabled())
 		return -ENODEV;
 
+	xhci_debugfs_create_root();
+
 	return 0;
 }
 
@@ -5010,7 +5026,10 @@ static int __init xhci_hcd_init(void)
  * If an init function is provided, an exit function must also be provided
  * to allow module unload.
  */
-static void __exit xhci_hcd_fini(void) { }
+static void __exit xhci_hcd_fini(void)
+{
+	xhci_debugfs_remove_root();
+}
 
 module_init(xhci_hcd_init);
 module_exit(xhci_hcd_fini);
drivers/usb/host/xhci.h +9 -0
index e3e9352..e27a161 100644
@@ -131,6 +131,8 @@ struct xhci_cap_regs {
 /* Extended Capabilities pointer from PCI base - section 5.3.6 */
 #define HCC_EXT_CAPS(p)		XHCI_HCC_EXT_CAPS(p)
 
+#define CTX_SIZE(_hcc)		(HCC_64BYTE_CONTEXT(_hcc) ? 64 : 32)
+
 /* db_off bitmask - bits 0:1 reserved */
 #define	DBOFF_MASK	(~0x3)
 
@@ -998,6 +1000,8 @@ struct xhci_virt_device {
 	struct xhci_tt_bw_info		*tt_info;
 	/* The current max exit latency for the enabled USB3 link states. */
 	u16				current_mel;
+	/* Used for the debugfs interfaces. */
+	void				*debugfs_private;
 };
 
 /*
@@ -1850,6 +1854,10 @@ struct xhci_hcd {
 /* Compliance Mode Timer Triggered every 2 seconds */
 #define COMP_MODE_RCVRY_MSECS 2000
 
+	struct dentry		*debugfs_root;
+	struct dentry		*debugfs_slots;
+	struct list_head	regset_list;
+
 	/* platform-specific data -- must come last */
 	unsigned long		priv[0] __aligned(sizeof(s64));
 };
@@ -2098,6 +2106,7 @@ struct xhci_ep_ctx *xhci_get_ep_ctx(struct xhci_hcd *xhci, struct xhci_container
 struct xhci_ring *xhci_triad_to_transfer_ring(struct xhci_hcd *xhci,
 		unsigned int slot_id, unsigned int ep_index,
 		unsigned int stream_id);
+
 static inline struct xhci_ring *xhci_urb_to_transfer_ring(struct xhci_hcd *xhci,
 								struct urb *urb)
 {
Signature · 1 line
2.7.4
#1 lore raw
Quoted 4 lines · Lu Baolu
drivers/usb/host/xhci-debugfs.c new file +4 -0
+static void xhci_debugfs_create_files(struct xhci_hcd *xhci,
+				      struct xhci_file_map *files,
+				      size_t nentries, void *data,
+				      struct dentry *parent,

drivers/usb/host/xhci-debugfs.c line 358

Quoted 10 lines
drivers/usb/host/xhci-debugfs.c new file +10 -0
+				      const struct file_operations *fops)
+{
+	int			i;
+	struct dentry		*file;
+
+	for (i = 0; i < nentries; i++) {
+		file = debugfs_create_file(files[i].name, 0444,
+					   parent, data, fops);
+		if (IS_ERR_OR_NULL(file))
+			break;

There's no need to ever check the return value of a debugfs_ function, there's nothing you can do here, just keep calling it :)

And you will not get an error, you will only get NULL if there is an error, as the only error you would get is if debugfs was not enabled.

drivers/usb/host/xhci-debugfs.c line 371

Quoted 10 lines
drivers/usb/host/xhci-debugfs.c new file +10 -0
+static struct dentry *xhci_debugfs_create_ring_dir(struct xhci_hcd *xhci,
+						   struct xhci_ring *ring,
+						   const char *name,
+						   struct dentry *parent)
+{
+	struct dentry		*dir;
+
+	dir = debugfs_create_dir(name, parent);
+	if (IS_ERR_OR_NULL(dir))
+		return NULL;

Same here. Just keep going, you don't care about the return value, but you can use it safely no matter what.

Same for other places in this patch as well.

thanks,

greg k-h

author
#2 lore raw

Hi Greg,

Quoted 35 lines · Greg KH
Quoted 4 lines · Lu Baolu
drivers/usb/host/xhci-debugfs.c new file +4 -0
+static void xhci_debugfs_create_files(struct xhci_hcd *xhci,
+				      struct xhci_file_map *files,
+				      size_t nentries, void *data,
+				      struct dentry *parent,

drivers/usb/host/xhci-debugfs.c line 358

Quoted 10 lines
drivers/usb/host/xhci-debugfs.c new file +10 -0
+				      const struct file_operations *fops)
+{
+	int			i;
+	struct dentry		*file;
+
+	for (i = 0; i < nentries; i++) {
+		file = debugfs_create_file(files[i].name, 0444,
+					   parent, data, fops);
+		if (IS_ERR_OR_NULL(file))
+			break;

There's no need to ever check the return value of a debugfs_ function, there's nothing you can do here, just keep calling it :)

And you will not get an error, you will only get NULL if there is an error, as the only error you would get is if debugfs was not enabled.

drivers/usb/host/xhci-debugfs.c line 371

Quoted 10 lines
drivers/usb/host/xhci-debugfs.c new file +10 -0
+static struct dentry *xhci_debugfs_create_ring_dir(struct xhci_hcd *xhci,
+						   struct xhci_ring *ring,
+						   const char *name,
+						   struct dentry *parent)
+{
+	struct dentry		*dir;
+
+	dir = debugfs_create_dir(name, parent);
+	if (IS_ERR_OR_NULL(dir))
+		return NULL;

Same here. Just keep going, you don't care about the return value, but you can use it safely no matter what.

Quoted 1 line

Same for other places in this patch as well.

Thanks for review. I will correct them in a v2 patch.

Best regards,
Lu Baolu