Commit 021bff91 authored by Sarah Sharp's avatar Sarah Sharp Committed by Greg Kroah-Hartman

USB: xhci: Performance - move functions that find ep ring.

I've been using perf to measure the top symbols while transferring 1GB of data
on a USB 3.0 drive with dd.  This is using the raw disk with /dev/sdb, with a
block size of 1K.

During performance testing, the top symbol was xhci_triad_to_transfer_ring(), a
function that should return immediately if streams are not enabled for an
endpoint.  It turned out that the functions to find the endpoint ring was
defined in xhci-mem.c and used in xhci-ring.c and xhci-hcd.c.  I moved a copy of
xhci_triad_to_transfer_ring() and xhci_urb_to_transfer_ring() into xhci-ring.c
and declared them static.  I also made a static version of
xhci_urb_to_transfer_ring() in xhci.c.

This improved throughput on a 1GB read of the raw disk with dd from
186MB/s to 195MB/s, and perf reported sampling the xhci_triad_to_transfer_ring()
0.06% of the time, rather than 9.26% of the time.
Signed-off-by: default avatarSarah Sharp <sarah.a.sharp@linux.intel.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@suse.de>
parent c6ba1c2a
...@@ -391,49 +391,6 @@ struct xhci_ring *xhci_stream_id_to_ring( ...@@ -391,49 +391,6 @@ struct xhci_ring *xhci_stream_id_to_ring(
return ep->stream_info->stream_rings[stream_id]; return ep->stream_info->stream_rings[stream_id];
} }
struct xhci_ring *xhci_triad_to_transfer_ring(struct xhci_hcd *xhci,
unsigned int slot_id, unsigned int ep_index,
unsigned int stream_id)
{
struct xhci_virt_ep *ep;
ep = &xhci->devs[slot_id]->eps[ep_index];
/* Common case: no streams */
if (!(ep->ep_state & EP_HAS_STREAMS))
return ep->ring;
if (stream_id == 0) {
xhci_warn(xhci,
"WARN: Slot ID %u, ep index %u has streams, "
"but URB has no stream ID.\n",
slot_id, ep_index);
return NULL;
}
if (stream_id < ep->stream_info->num_streams)
return ep->stream_info->stream_rings[stream_id];
xhci_warn(xhci,
"WARN: Slot ID %u, ep index %u has "
"stream IDs 1 to %u allocated, "
"but stream ID %u is requested.\n",
slot_id, ep_index,
ep->stream_info->num_streams - 1,
stream_id);
return NULL;
}
/* Get the right ring for the given URB.
* If the endpoint supports streams, boundary check the URB's stream ID.
* If the endpoint doesn't support streams, return the singular endpoint ring.
*/
struct xhci_ring *xhci_urb_to_transfer_ring(struct xhci_hcd *xhci,
struct urb *urb)
{
return xhci_triad_to_transfer_ring(xhci, urb->dev->slot_id,
xhci_get_endpoint_index(&urb->ep->desc), urb->stream_id);
}
#ifdef CONFIG_USB_XHCI_HCD_DEBUGGING #ifdef CONFIG_USB_XHCI_HCD_DEBUGGING
static int xhci_test_radix_tree(struct xhci_hcd *xhci, static int xhci_test_radix_tree(struct xhci_hcd *xhci,
unsigned int num_streams, unsigned int num_streams,
......
...@@ -419,6 +419,50 @@ static struct xhci_segment *find_trb_seg( ...@@ -419,6 +419,50 @@ static struct xhci_segment *find_trb_seg(
return cur_seg; return cur_seg;
} }
static struct xhci_ring *xhci_triad_to_transfer_ring(struct xhci_hcd *xhci,
unsigned int slot_id, unsigned int ep_index,
unsigned int stream_id)
{
struct xhci_virt_ep *ep;
ep = &xhci->devs[slot_id]->eps[ep_index];
/* Common case: no streams */
if (!(ep->ep_state & EP_HAS_STREAMS))
return ep->ring;
if (stream_id == 0) {
xhci_warn(xhci,
"WARN: Slot ID %u, ep index %u has streams, "
"but URB has no stream ID.\n",
slot_id, ep_index);
return NULL;
}
if (stream_id < ep->stream_info->num_streams)
return ep->stream_info->stream_rings[stream_id];
xhci_warn(xhci,
"WARN: Slot ID %u, ep index %u has "
"stream IDs 1 to %u allocated, "
"but stream ID %u is requested.\n",
slot_id, ep_index,
ep->stream_info->num_streams - 1,
stream_id);
return NULL;
}
/* Get the right ring for the given URB.
* If the endpoint supports streams, boundary check the URB's stream ID.
* If the endpoint doesn't support streams, return the singular endpoint ring.
*/
static struct xhci_ring *xhci_urb_to_transfer_ring(struct xhci_hcd *xhci,
struct urb *urb)
{
return xhci_triad_to_transfer_ring(xhci, urb->dev->slot_id,
xhci_get_endpoint_index(&urb->ep->desc), urb->stream_id);
}
/* /*
* Move the xHC's endpoint ring dequeue pointer past cur_td. * Move the xHC's endpoint ring dequeue pointer past cur_td.
* Record the new state of the xHC's endpoint ring dequeue segment, * Record the new state of the xHC's endpoint ring dequeue segment,
......
...@@ -916,6 +916,47 @@ int xhci_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, gfp_t mem_flags) ...@@ -916,6 +916,47 @@ int xhci_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, gfp_t mem_flags)
return -ESHUTDOWN; return -ESHUTDOWN;
} }
/* Get the right ring for the given URB.
* If the endpoint supports streams, boundary check the URB's stream ID.
* If the endpoint doesn't support streams, return the singular endpoint ring.
*/
static struct xhci_ring *xhci_urb_to_transfer_ring(struct xhci_hcd *xhci,
struct urb *urb)
{
unsigned int slot_id;
unsigned int ep_index;
unsigned int stream_id;
struct xhci_virt_ep *ep;
slot_id = urb->dev->slot_id;
ep_index = xhci_get_endpoint_index(&urb->ep->desc);
stream_id = urb->stream_id;
ep = &xhci->devs[slot_id]->eps[ep_index];
/* Common case: no streams */
if (!(ep->ep_state & EP_HAS_STREAMS))
return ep->ring;
if (stream_id == 0) {
xhci_warn(xhci,
"WARN: Slot ID %u, ep index %u has streams, "
"but URB has no stream ID.\n",
slot_id, ep_index);
return NULL;
}
if (stream_id < ep->stream_info->num_streams)
return ep->stream_info->stream_rings[stream_id];
xhci_warn(xhci,
"WARN: Slot ID %u, ep index %u has "
"stream IDs 1 to %u allocated, "
"but stream ID %u is requested.\n",
slot_id, ep_index,
ep->stream_info->num_streams - 1,
stream_id);
return NULL;
}
/* /*
* Remove the URB's TD from the endpoint ring. This may cause the HC to stop * Remove the URB's TD from the endpoint ring. This may cause the HC to stop
* USB transfers, potentially stopping in the middle of a TRB buffer. The HC * USB transfers, potentially stopping in the middle of a TRB buffer. The HC
......
...@@ -1344,11 +1344,6 @@ void xhci_setup_no_streams_ep_input_ctx(struct xhci_hcd *xhci, ...@@ -1344,11 +1344,6 @@ void xhci_setup_no_streams_ep_input_ctx(struct xhci_hcd *xhci,
struct xhci_ring *xhci_dma_to_transfer_ring( struct xhci_ring *xhci_dma_to_transfer_ring(
struct xhci_virt_ep *ep, struct xhci_virt_ep *ep,
u64 address); u64 address);
struct xhci_ring *xhci_urb_to_transfer_ring(struct xhci_hcd *xhci,
struct urb *urb);
struct xhci_ring *xhci_triad_to_transfer_ring(struct xhci_hcd *xhci,
unsigned int slot_id, unsigned int ep_index,
unsigned int stream_id);
struct xhci_ring *xhci_stream_id_to_ring( struct xhci_ring *xhci_stream_id_to_ring(
struct xhci_virt_device *dev, struct xhci_virt_device *dev,
unsigned int ep_index, unsigned int ep_index,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment