[PATCH 21/23] xhci: Use generic HCD throughput statistics.

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



This patch relies on the functionally added in the patch "Shared USB host
controller throughput statistics."

This converts xHCI to use the generic HCD throughput statistics.  The
statistics measure the time between when ownership of a TD for an urb is
transferred to the hardware to when the host controller submits an event
on the event ring for that TD.  Statistics for each urb are reported
through the tp-stats file in debugfs/xhci/.  The file gives a pair of
values that represent the actual amount of data transferred by the HC and
the time it took to process the TD, send all packets to the device, and
transfer data into the buffer.

Signed-off-by: Sarah Sharp <sarah.a.sharp@xxxxxxxxxxxxxxx>
---
 drivers/usb/host/xhci-dbg.c  |   30 ++++++++++++++++++++++++++++++
 drivers/usb/host/xhci-hcd.c  |    6 ++++++
 drivers/usb/host/xhci-ring.c |   10 ++++++++++
 drivers/usb/host/xhci.h      |   10 ++++++++++
 4 files changed, 56 insertions(+), 0 deletions(-)

diff --git a/drivers/usb/host/xhci-dbg.c b/drivers/usb/host/xhci-dbg.c
index 16ef42a..e8e0d5d 100644
--- a/drivers/usb/host/xhci-dbg.c
+++ b/drivers/usb/host/xhci-dbg.c
@@ -20,6 +20,12 @@
  * Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
+#include <linux/debugfs.h>
+#include <linux/stringify.h>
+
+#ifdef CONFIG_USB_HCD_STAT
+#include "hcd-dbg.h"
+#endif
 #include "xhci.h"
 
 #define XHCI_INIT_VALUE 0x0
@@ -489,3 +495,27 @@ void xhci_dbg_ctx(struct xhci_hcd *xhci, struct xhci_device_control *ctx, dma_ad
 		}
 	}
 }
+
+void xhci_debugfs_remove(struct xhci_hcd *xhci)
+{
+#ifdef CONFIG_USB_HCD_STAT
+	hcd_stat_free(xhci->tp_stat);
+	xhci->tp_stat = NULL;
+#endif
+	debugfs_remove(xhci->dtry_dir);
+}
+
+int xhci_debugfs_add(struct xhci_hcd *xhci)
+{
+	xhci->dtry_dir = debugfs_create_dir("xhci", NULL);
+	if (!xhci->dtry_dir)
+		return -ENOMEM;
+
+#ifdef CONFIG_USB_HCD_STAT
+	xhci->tp_stat = hcd_stat_alloc(xhci->dtry_dir, "tp-stats", GFP_KERNEL);
+	if (!xhci->tp_stat)
+		return -ENOMEM;
+#endif
+
+	return 0;
+}
diff --git a/drivers/usb/host/xhci-hcd.c b/drivers/usb/host/xhci-hcd.c
index e5fbdcd..1be9dfc 100644
--- a/drivers/usb/host/xhci-hcd.c
+++ b/drivers/usb/host/xhci-hcd.c
@@ -211,6 +211,11 @@ int xhci_init(struct usb_hcd *hcd)
 
 	xhci_dbg(xhci, "xhci_init\n");
 	spin_lock_init(&xhci->lock);
+	if (xhci_debugfs_add(xhci) < 0) {
+		xhci_warn(xhci, "Could not create debug files\n");
+		xhci_debugfs_remove(xhci);
+		return -ENOMEM;
+	}
 	retval = xhci_mem_init(xhci, GFP_KERNEL);
 	xhci_dbg(xhci, "Finished xhci_init\n");
 
@@ -482,6 +487,7 @@ void xhci_stop(struct usb_hcd *hcd)
 	xhci_mem_cleanup(xhci);
 	xhci_dbg(xhci, "xhci_stop completed - status = %x\n",
 		    xhci_readl(xhci, &xhci->op_regs->status));
+	xhci_debugfs_remove(xhci);
 }
 
 /*
diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c
index c948288..1027088 100644
--- a/drivers/usb/host/xhci-ring.c
+++ b/drivers/usb/host/xhci-ring.c
@@ -398,6 +398,7 @@ static int handle_tx_event(struct xhci_hcd *xhci,
 	union xhci_trb *event_trb;
 	struct urb *urb;
 	int status = -EINPROGRESS;
+	ktime_t stop_time;
 
 	xdev = xhci->devs[TRB_TO_SLOT_ID(event->flags)];
 	if (!xdev) {
@@ -437,6 +438,7 @@ static int handle_tx_event(struct xhci_hcd *xhci,
 		xhci_err(xhci, "ERROR Transfer event TRB DMA ptr not part of current TD\n");
 		return -ESHUTDOWN;
 	}
+	stop_time = ktime_get();
 	event_trb = &event_seg->trbs[(event_dma - event_seg->dma) / sizeof(*event_trb)];
 	xhci_dbg(xhci, "Event TRB with TRB type ID %u\n",
 			(unsigned int) (event->flags & TRB_TYPE_BITMASK)>>10);
@@ -602,6 +604,11 @@ cleanup:
 
 	/* FIXME for multi-TD URBs (who have buffers bigger than 64MB) */
 	if (urb) {
+#ifdef CONFIG_USB_HCD_STAT
+		hcd_stat_update(xhci->tp_stat, urb->actual_length,
+				ktime_sub(stop_time, td->start_time));
+#endif
+
 		usb_hcd_unlink_urb_from_ep(xhci_to_hcd(xhci), urb);
 		spin_unlock(&xhci->lock);
 		usb_hcd_giveback_urb(xhci_to_hcd(xhci), urb, status);
@@ -832,6 +839,9 @@ void giveback_first_trb(struct xhci_hcd *xhci, int slot_id,
 	wmb();
 	start_trb->field[3] |= start_cycle;
 	field = xhci_readl(xhci, &xhci->dba->doorbell[slot_id]) & DB_MASK;
+#ifdef CONFIG_USB_HCD_STAT
+	td->start_time = ktime_get();
+#endif
 	xhci_writel(xhci, field | EPI_TO_DB(ep_index),
 			&xhci->dba->doorbell[slot_id]);
 	/* Flush PCI posted writes */
diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h
index 06e0761..1b0ab6c 100644
--- a/drivers/usb/host/xhci.h
+++ b/drivers/usb/host/xhci.h
@@ -897,6 +897,9 @@ struct xhci_td {
 	struct list_head	td_list;
 	struct urb		*urb;
 	union xhci_trb		*last_trb;
+#ifdef CONFIG_USB_HCD_STAT
+	ktime_t			start_time;
+#endif
 };
 
 struct xhci_segment {
@@ -1013,6 +1016,11 @@ struct xhci_hcd {
 	int			noops_submitted;
 	int			noops_handled;
 	int			error_bitmask;
+	struct dentry		*dtry_dir;
+#ifdef CONFIG_USB_HCD_STAT
+	/* Throughput statistics - maybe later we'll have one per endpoint */
+	struct hcd_stat	*tp_stat;
+#endif
 };
 
 /* For testing purposes */
@@ -1073,6 +1081,8 @@ void xhci_dbg_erst(struct xhci_hcd *xhci, struct xhci_erst *erst);
 void xhci_dbg_cmd_ptrs(struct xhci_hcd *xhci);
 void xhci_dbg_ring_ptrs(struct xhci_hcd *xhci, struct xhci_ring *ring);
 void xhci_dbg_ctx(struct xhci_hcd *xhci, struct xhci_device_control *ctx, dma_addr_t dma, unsigned int last_ep);
+int xhci_debugfs_add(struct xhci_hcd *xhci);
+void xhci_debugfs_remove(struct xhci_hcd *xhci);
 
 /* xHCI memory managment */
 void xhci_mem_cleanup(struct xhci_hcd *xhci);
-- 
1.5.6.5

--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

[Index of Archives]     [Linux Media]     [Linux Input]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Old Linux USB Devel Archive]

  Powered by Linux