Skip to contentSkip to conversation

usb: xhci: Add debugfs interface for xHCI driver

PATCH New Lu Baolu 1 participant 1 message Aug 1, 2017

Subsystems (2)
lore
Share & tools
lore

Lu Baolu

author
#0 lore raw

PATCH v2 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]

---
Change log:
v1->v2:
- No need to check return valuse of debugfs interfaces.
- Remove file entries when adding endpoint failed.

 drivers/usb/host/Makefile       |   4 +
 drivers/usb/host/xhci-debugfs.c | 526 ++++++++++++++++++++++++++++++++++++++++
 drivers/usb/host/xhci-debugfs.h | 137 +++++++++++
 drivers/usb/host/xhci-mem.c     |   5 +-
 drivers/usb/host/xhci.c         |  23 +-
 drivers/usb/host/xhci.h         |   9 +
 6 files changed, 700 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 +526 -0

526 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 +2 -3
index 2a82c92..b81a231 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)
 {
@@ -961,6 +960,7 @@ void xhci_free_virt_devices_depth_first(struct xhci_hcd *xhci, int slot_id)
 		}
 	}
 	/* we are now at a leaf device */
+	xhci_debugfs_remove_slot(xhci, slot_id);
 	xhci_free_virt_device(xhci, slot_id);
 }
 
@@ -1496,7 +1496,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 +22 -1
index b2ff1ff..bb7633b 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,
@@ -2772,6 +2782,7 @@ static void xhci_reset_bandwidth(struct usb_hcd *hcd, struct usb_device *udev)
 	/* Free any rings allocated for added endpoints */
 	for (i = 0; i < 31; i++) {
 		if (virt_dev->eps[i].new_ring) {
+			xhci_debugfs_remove_endpoint(xhci, virt_dev, i);
 			xhci_ring_free(xhci, virt_dev->eps[i].new_ring);
 			virt_dev->eps[i].new_ring = NULL;
 		}
@@ -3487,6 +3498,7 @@ static int xhci_discover_or_reset_device(struct usb_hcd *hcd,
 		}
 
 		if (ep->ring) {
+			xhci_debugfs_remove_endpoint(xhci, virt_dev, i);
 			xhci_free_endpoint_ring(xhci, virt_dev, i);
 			last_freed_endpoint = i;
 		}
@@ -3521,6 +3533,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 +3707,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 +5019,8 @@ static int __init xhci_hcd_init(void)
 	if (usb_disabled())
 		return -ENODEV;
 
+	xhci_debugfs_create_root();
+
 	return 0;
 }
 
@@ -5010,7 +5028,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