There are two locations where we advance the enqueue pointer through a chain of link trbs, in inc_enq() and prepare_ring(). Factor that into a common advance_enq(). Also, in preparation for per-ring operations factor out the differences between the event-rings, chain-quirk-rings and normal endpoint rings into event_ring_inc_enq() and common_inc_enq(). Unfortunately this isn't a net win in the diffstat, but it does eliminate the liability of failing to update one of the instances especially in preparation for overhauling TD-fragment handling for xhci1.0+ hosts. Signed-off-by: Dan Williams <dan.j.williams@xxxxxxxxx> --- drivers/usb/host/xhci-ring.c | 164 ++++++++++++++++++++++-------------------- 1 files changed, 86 insertions(+), 78 deletions(-) diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index bee5c18b0509..d8c9a8211ace 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -171,9 +171,39 @@ static void inc_deq(struct xhci_ring *ring) } /* - * See Cycle bit rules. SW is the consumer for the event ring only. - * Don't make a ring full of link TRBs. That would be dumb and this would loop. - * + * Don't make a ring full of link TRBs. That would be dumb and this + * would loop. + */ +static void advance_enq(struct xhci_ring *ring, u32 chain, bool do_carry_chain) +{ + union xhci_trb *next = ring->enqueue; + + /* + * Update the enqueue pointer further if we're now pointing to a + * link TRB + */ + while (last_trb(ring, ring->enq_seg, next)) { + if (do_carry_chain) { + next->link.control &= cpu_to_le32(~TRB_CHAIN); + next->link.control |= cpu_to_le32(chain); + } else { + next->link.control |= cpu_to_le32(TRB_CHAIN); + } + + /* Give this link TRB to the hardware */ + wmb(); + next->link.control ^= cpu_to_le32(TRB_CYCLE); + + /* Toggle the cycle bit after the last ring segment. */ + if (last_trb_on_last_seg(ring, ring->enq_seg, next)) + ring->cycle_state ^= 1; + ring->enq_seg = xhci_segment_next(ring, ring->enq_seg); + ring->enqueue = ring->enq_seg->trbs; + next = ring->enqueue; + } +} + +/* * If we've just enqueued a TRB that is in the middle of a TD (meaning the * chain bit is set), then set the chain bit in all the following link TRBs. * If we've enqueued the last TRB in a TD, make sure the following link TRBs @@ -187,63 +217,68 @@ static void inc_deq(struct xhci_ring *ring) * @more_trbs_coming: Will you enqueue more TRBs before calling * prepare_transfer()? */ -static void inc_enq(struct xhci_hcd *xhci, struct xhci_ring *ring, - bool more_trbs_coming) +static void common_inc_enq(struct xhci_ring *ring, bool more_trbs_coming, + bool do_carry_chain) { - u32 chain; - union xhci_trb *next; - - chain = le32_to_cpu(ring->enqueue->generic.field[3]) & TRB_CHAIN; - /* If this is not event ring, there is one less usable TRB */ - if (ring->type != TYPE_EVENT && - !last_trb(ring, ring->enq_seg, ring->enqueue)) - ring->num_trbs_free--; - next = ++(ring->enqueue); + u32 chain = le32_to_cpu(ring->enqueue->generic.field[3]) & TRB_CHAIN; + ring->num_trbs_free--; + (ring->enqueue)++; ring->enq_updates++; - /* Update the dequeue pointer further if that was a link TRB or we're at - * the end of an event ring segment (which doesn't have link TRBS) + + /* + * If the caller doesn't plan on enqueueing more TDs before + * ringing the doorbell, then we don't want to give the link TRB + * to the hardware just yet. We'll give the link TRB back in + * prepare_ring() just before we enqueue the TD at the top of + * the ring. */ - while (last_trb(ring, ring->enq_seg, next)) { - if (ring->type != TYPE_EVENT) { - /* - * If the caller doesn't plan on enqueueing more - * TDs before ringing the doorbell, then we - * don't want to give the link TRB to the - * hardware just yet. We'll give the link TRB - * back in prepare_ring() just before we enqueue - * the TD at the top of the ring. - */ - if (!chain && !more_trbs_coming) - break; + if (!chain && !more_trbs_coming) + return; + advance_enq(ring, chain, do_carry_chain); +} - /* If we're not dealing with 0.95 hardware or - * isoc rings on AMD 0.96 host, - * carry over the chain bit of the previous TRB - * (which may mean the chain bit is cleared). - */ - if (!(ring->type == TYPE_ISOC && - (xhci->quirks & XHCI_AMD_0x96_HOST)) - && !xhci_link_trb_quirk(xhci)) { - next->link.control &= - cpu_to_le32(~TRB_CHAIN); - next->link.control |= - cpu_to_le32(chain); - } - /* Give this link TRB to the hardware */ - wmb(); - next->link.control ^= cpu_to_le32(TRB_CYCLE); +/* + * See Cycle bit rules. SW is the consumer for the event ring only. + */ +static void event_inc_enq(struct xhci_ring *ring) +{ + union xhci_trb *next; - /* Toggle the cycle bit after the last ring segment. */ - if (last_trb_on_last_seg(ring, ring->enq_seg, next)) - ring->cycle_state ^= 1; - } + next = ++(ring->enqueue); + ring->enq_updates++; + + /* + * Fix up the enqueue pointer if we're at the end of an event + * ring segment (which doesn't have link TRBS) + */ + if (last_trb(ring, ring->enq_seg, next)) { ring->enq_seg = xhci_segment_next(ring, ring->enq_seg); ring->enqueue = ring->enq_seg->trbs; - next = ring->enqueue; } } +static bool do_carry_chain(struct xhci_hcd *xhci, struct xhci_ring *ring) +{ + /* + * With 0.95 hardware or isoc rings on AMD 0.96 host, don't + * carry over the chain bit of the previous TRB (which may mean + * the chain bit is cleared). + */ + return !(xhci_link_trb_quirk(xhci) || (ring->type == TYPE_ISOC + && (xhci->quirks & XHCI_AMD_0x96_HOST))); +} + +static void inc_enq(struct xhci_hcd *xhci, struct xhci_ring *ring, + bool more_trbs_coming) +{ + if (ring->type == TYPE_EVENT) + event_inc_enq(ring); + else + common_inc_enq(ring, more_trbs_coming, + do_carry_chain(xhci, ring)); +} + /* * Check to see if there's room to enqueue num_trbs on the ring and make sure * enqueue pointer will not advance into dequeue segment. See rules above. @@ -2849,35 +2884,8 @@ static int prepare_ring(struct xhci_hcd *xhci, struct xhci_ring *ep_ring, } } - if (enqueue_is_link_trb(ep_ring)) { - struct xhci_ring *ring = ep_ring; - union xhci_trb *next; - - next = ring->enqueue; - - while (last_trb(ring, ring->enq_seg, next)) { - /* If we're not dealing with 0.95 hardware or isoc rings - * on AMD 0.96 host, clear the chain bit. - */ - if (!xhci_link_trb_quirk(xhci) && - !(ring->type == TYPE_ISOC && - (xhci->quirks & XHCI_AMD_0x96_HOST))) - next->link.control &= cpu_to_le32(~TRB_CHAIN); - else - next->link.control |= cpu_to_le32(TRB_CHAIN); - - wmb(); - next->link.control ^= cpu_to_le32(TRB_CYCLE); - - /* Toggle the cycle bit after the last ring segment. */ - if (last_trb_on_last_seg(ring, ring->enq_seg, next)) - ring->cycle_state ^= 1; - ring->enq_seg = xhci_segment_next(ring, ring->enq_seg); - ring->enqueue = ring->enq_seg->trbs; - next = ring->enqueue; - } - } - + if (enqueue_is_link_trb(ep_ring)) + advance_enq(ep_ring, 0, do_carry_chain(xhci, ep_ring)); return 0; } -- 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