summaryrefslogtreecommitdiff
path: root/drivers/usb/host/xhci-mem.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb/host/xhci-mem.c')
-rw-r--r--drivers/usb/host/xhci-mem.c37
1 files changed, 23 insertions, 14 deletions
diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c
index 9764122c9cdf..696fad50b478 100644
--- a/drivers/usb/host/xhci-mem.c
+++ b/drivers/usb/host/xhci-mem.c
@@ -96,8 +96,9 @@ static void xhci_free_segments_for_ring(struct xhci_hcd *xhci,
* DMA address of the next segment. The caller needs to set any Link TRB
* related flags, such as End TRB, Toggle Cycle, and no snoop.
*/
-static void xhci_link_segments(struct xhci_hcd *xhci, struct xhci_segment *prev,
- struct xhci_segment *next, enum xhci_ring_type type)
+static void xhci_link_segments(struct xhci_segment *prev,
+ struct xhci_segment *next,
+ enum xhci_ring_type type, bool chain_links)
{
u32 val;
@@ -112,11 +113,7 @@ static void xhci_link_segments(struct xhci_hcd *xhci, struct xhci_segment *prev,
val = le32_to_cpu(prev->trbs[TRBS_PER_SEGMENT-1].link.control);
val &= ~TRB_TYPE_BITMASK;
val |= TRB_TYPE(TRB_LINK);
- /* Always set the chain bit with 0.95 hardware */
- /* Set chain bit for isoc rings on AMD 0.96 host */
- if (xhci_link_trb_quirk(xhci) ||
- (type == TYPE_ISOC &&
- (xhci->quirks & XHCI_AMD_0x96_HOST)))
+ if (chain_links)
val |= TRB_CHAIN;
prev->trbs[TRBS_PER_SEGMENT-1].link.control = cpu_to_le32(val);
}
@@ -131,13 +128,19 @@ static void xhci_link_rings(struct xhci_hcd *xhci, struct xhci_ring *ring,
unsigned int num_segs)
{
struct xhci_segment *next;
+ bool chain_links;
if (!ring || !first || !last)
return;
+ /* Set chain bit for 0.95 hosts, and for isoc rings on AMD 0.96 host */
+ chain_links = !!(xhci_link_trb_quirk(xhci) ||
+ (ring->type == TYPE_ISOC &&
+ (xhci->quirks & XHCI_AMD_0x96_HOST)));
+
next = ring->enq_seg->next;
- xhci_link_segments(xhci, ring->enq_seg, first, ring->type);
- xhci_link_segments(xhci, last, next, ring->type);
+ xhci_link_segments(ring->enq_seg, first, ring->type, chain_links);
+ xhci_link_segments(last, next, ring->type, chain_links);
ring->num_segs += num_segs;
ring->num_trbs_free += (TRBS_PER_SEGMENT - 1) * num_segs;
@@ -290,8 +293,8 @@ void xhci_ring_free(struct xhci_hcd *xhci, struct xhci_ring *ring)
kfree(ring);
}
-static void xhci_initialize_ring_info(struct xhci_ring *ring,
- unsigned int cycle_state)
+void xhci_initialize_ring_info(struct xhci_ring *ring,
+ unsigned int cycle_state)
{
/* The ring is empty, so the enqueue pointer == dequeue pointer */
ring->enqueue = ring->first_seg->trbs;
@@ -321,6 +324,12 @@ static int xhci_alloc_segments_for_ring(struct xhci_hcd *xhci,
enum xhci_ring_type type, unsigned int max_packet, gfp_t flags)
{
struct xhci_segment *prev;
+ bool chain_links;
+
+ /* Set chain bit for 0.95 hosts, and for isoc rings on AMD 0.96 host */
+ chain_links = !!(xhci_link_trb_quirk(xhci) ||
+ (type == TYPE_ISOC &&
+ (xhci->quirks & XHCI_AMD_0x96_HOST)));
prev = xhci_segment_alloc(xhci, cycle_state, max_packet, flags);
if (!prev)
@@ -341,18 +350,18 @@ static int xhci_alloc_segments_for_ring(struct xhci_hcd *xhci,
}
return -ENOMEM;
}
- xhci_link_segments(xhci, prev, next, type);
+ xhci_link_segments(prev, next, type, chain_links);
prev = next;
num_segs--;
}
- xhci_link_segments(xhci, prev, *first, type);
+ xhci_link_segments(prev, *first, type, chain_links);
*last = prev;
return 0;
}
-/**
+/*
* Create a new ring with zero or more segments.
*
* Link each segment together into a ring.