From 11527dad9862ba7e53654943fdacc3ffdad00ae2 Mon Sep 17 00:00:00 2001 From: Jonathan Bell Date: Mon, 13 Dec 2021 15:05:56 +0000 Subject: [PATCH] xhci: refactor out TRBS_PER_SEGMENT define in runtime code In anticipation of adjusting the number of utilised TRBs in a ring segment, add trbs_per_seg to struct xhci_ring and use this instead of a compile-time define. Signed-off-by: Jonathan Bell --- drivers/usb/host/xhci-mem.c | 48 +++++++++++++++++++----------------- drivers/usb/host/xhci-ring.c | 20 +++++++++------ drivers/usb/host/xhci.c | 6 ++--- drivers/usb/host/xhci.h | 1 + 4 files changed, 42 insertions(+), 33 deletions(-) --- a/drivers/usb/host/xhci-mem.c +++ b/drivers/usb/host/xhci-mem.c @@ -98,6 +98,7 @@ static void xhci_free_segments_for_ring( */ static void xhci_link_segments(struct xhci_segment *prev, struct xhci_segment *next, + unsigned int trbs_per_seg, enum xhci_ring_type type, bool chain_links) { u32 val; @@ -106,16 +107,16 @@ static void xhci_link_segments(struct xh return; prev->next = next; if (type != TYPE_EVENT) { - prev->trbs[TRBS_PER_SEGMENT-1].link.segment_ptr = + prev->trbs[trbs_per_seg - 1].link.segment_ptr = cpu_to_le64(next->dma); /* Set the last TRB in the segment to have a TRB type ID of Link TRB */ - val = le32_to_cpu(prev->trbs[TRBS_PER_SEGMENT-1].link.control); + val = le32_to_cpu(prev->trbs[trbs_per_seg - 1].link.control); val &= ~TRB_TYPE_BITMASK; val |= TRB_TYPE(TRB_LINK); if (chain_links) val |= TRB_CHAIN; - prev->trbs[TRBS_PER_SEGMENT-1].link.control = cpu_to_le32(val); + prev->trbs[trbs_per_seg - 1].link.control = cpu_to_le32(val); } } @@ -139,15 +140,17 @@ static void xhci_link_rings(struct xhci_ (xhci->quirks & XHCI_AMD_0x96_HOST))); next = ring->enq_seg->next; - xhci_link_segments(ring->enq_seg, first, ring->type, chain_links); - xhci_link_segments(last, next, ring->type, chain_links); + xhci_link_segments(ring->enq_seg, first, ring->trbs_per_seg, + ring->type, chain_links); + xhci_link_segments(last, next, ring->trbs_per_seg, + ring->type, chain_links); ring->num_segs += num_segs; - ring->num_trbs_free += (TRBS_PER_SEGMENT - 1) * num_segs; + ring->num_trbs_free += (ring->trbs_per_seg - 1) * num_segs; if (ring->type != TYPE_EVENT && ring->enq_seg == ring->last_seg) { - ring->last_seg->trbs[TRBS_PER_SEGMENT-1].link.control + ring->last_seg->trbs[ring->trbs_per_seg - 1].link.control &= ~cpu_to_le32(LINK_TOGGLE); - last->trbs[TRBS_PER_SEGMENT-1].link.control + last->trbs[ring->trbs_per_seg - 1].link.control |= cpu_to_le32(LINK_TOGGLE); ring->last_seg = last; } @@ -314,14 +317,15 @@ void xhci_initialize_ring_info(struct xh * Each segment has a link TRB, and leave an extra TRB for SW * accounting purpose */ - ring->num_trbs_free = ring->num_segs * (TRBS_PER_SEGMENT - 1) - 1; + ring->num_trbs_free = ring->num_segs * (ring->trbs_per_seg - 1) - 1; } /* Allocate segments and link them for a ring */ static int xhci_alloc_segments_for_ring(struct xhci_hcd *xhci, struct xhci_segment **first, struct xhci_segment **last, - unsigned int num_segs, unsigned int cycle_state, - enum xhci_ring_type type, unsigned int max_packet, gfp_t flags) + unsigned int num_segs, unsigned int trbs_per_seg, + unsigned int cycle_state, enum xhci_ring_type type, + unsigned int max_packet, gfp_t flags) { struct xhci_segment *prev; bool chain_links; @@ -350,12 +354,12 @@ static int xhci_alloc_segments_for_ring( } return -ENOMEM; } - xhci_link_segments(prev, next, type, chain_links); + xhci_link_segments(prev, next, trbs_per_seg, type, chain_links); prev = next; num_segs--; } - xhci_link_segments(prev, *first, type, chain_links); + xhci_link_segments(prev, *first, trbs_per_seg, type, chain_links); *last = prev; return 0; @@ -387,16 +391,17 @@ struct xhci_ring *xhci_ring_alloc(struct if (num_segs == 0) return ring; + ring->trbs_per_seg = TRBS_PER_SEGMENT; ret = xhci_alloc_segments_for_ring(xhci, &ring->first_seg, - &ring->last_seg, num_segs, cycle_state, type, - max_packet, flags); + &ring->last_seg, num_segs, ring->trbs_per_seg, + cycle_state, type, max_packet, flags); if (ret) goto fail; /* Only event ring does not use link TRB */ if (type != TYPE_EVENT) { /* See section 4.9.2.1 and 6.4.4.1 */ - ring->last_seg->trbs[TRBS_PER_SEGMENT - 1].link.control |= + ring->last_seg->trbs[ring->trbs_per_seg - 1].link.control |= cpu_to_le32(LINK_TOGGLE); } xhci_initialize_ring_info(ring, cycle_state); @@ -429,15 +434,14 @@ int xhci_ring_expansion(struct xhci_hcd unsigned int num_segs_needed; int ret; - num_segs_needed = (num_trbs + (TRBS_PER_SEGMENT - 1) - 1) / - (TRBS_PER_SEGMENT - 1); - + num_segs_needed = (num_trbs + (ring->trbs_per_seg - 1) - 1) / + (ring->trbs_per_seg - 1); /* Allocate number of segments we needed, or double the ring size */ num_segs = max(ring->num_segs, num_segs_needed); ret = xhci_alloc_segments_for_ring(xhci, &first, &last, - num_segs, ring->cycle_state, ring->type, - ring->bounce_buf_len, flags); + num_segs, ring->trbs_per_seg, ring->cycle_state, + ring->type, ring->bounce_buf_len, flags); if (ret) return -ENOMEM; @@ -1811,7 +1815,7 @@ int xhci_alloc_erst(struct xhci_hcd *xhc for (val = 0; val < evt_ring->num_segs; val++) { entry = &erst->entries[val]; entry->seg_addr = cpu_to_le64(seg->dma); - entry->seg_size = cpu_to_le32(TRBS_PER_SEGMENT); + entry->seg_size = cpu_to_le32(evt_ring->trbs_per_seg); entry->rsvd = 0; seg = seg->next; } --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -90,15 +90,16 @@ static bool trb_is_link(union xhci_trb * return TRB_TYPE_LINK_LE32(trb->link.control); } -static bool last_trb_on_seg(struct xhci_segment *seg, union xhci_trb *trb) +static bool last_trb_on_seg(struct xhci_segment *seg, + unsigned int trbs_per_seg, union xhci_trb *trb) { - return trb == &seg->trbs[TRBS_PER_SEGMENT - 1]; + return trb == &seg->trbs[trbs_per_seg - 1]; } static bool last_trb_on_ring(struct xhci_ring *ring, struct xhci_segment *seg, union xhci_trb *trb) { - return last_trb_on_seg(seg, trb) && (seg->next == ring->first_seg); + return last_trb_on_seg(seg, ring->trbs_per_seg, trb) && (seg->next == ring->first_seg); } static bool link_trb_toggles_cycle(union xhci_trb *trb) @@ -161,7 +162,8 @@ void inc_deq(struct xhci_hcd *xhci, stru /* event ring doesn't have link trbs, check for last trb */ if (ring->type == TYPE_EVENT) { - if (!last_trb_on_seg(ring->deq_seg, ring->dequeue)) { + if (!last_trb_on_seg(ring->deq_seg, ring->trbs_per_seg, + ring->dequeue)) { ring->dequeue++; goto out; } @@ -174,7 +176,8 @@ void inc_deq(struct xhci_hcd *xhci, stru /* All other rings have link trbs */ if (!trb_is_link(ring->dequeue)) { - if (last_trb_on_seg(ring->deq_seg, ring->dequeue)) { + if (last_trb_on_seg(ring->deq_seg, ring->trbs_per_seg, + ring->dequeue)) { xhci_warn(xhci, "Missing link TRB at end of segment\n"); } else { ring->dequeue++; @@ -225,7 +228,7 @@ static void inc_enq(struct xhci_hcd *xhc if (!trb_is_link(ring->enqueue)) ring->num_trbs_free--; - if (last_trb_on_seg(ring->enq_seg, ring->enqueue)) { + if (last_trb_on_seg(ring->enq_seg, ring->trbs_per_seg, ring->enqueue)) { xhci_err(xhci, "Tried to move enqueue past ring segment\n"); return; } @@ -3100,7 +3103,7 @@ irqreturn_t xhci_irq(struct usb_hcd *hcd * that clears the EHB. */ while (xhci_handle_event(xhci) > 0) { - if (event_loop++ < TRBS_PER_SEGMENT / 2) + if (event_loop++ < xhci->event_ring->trbs_per_seg / 2) continue; xhci_update_erst_dequeue(xhci, event_ring_deq); event_ring_deq = xhci->event_ring->dequeue; @@ -3242,7 +3245,8 @@ static int prepare_ring(struct xhci_hcd } } - if (last_trb_on_seg(ep_ring->enq_seg, ep_ring->enqueue)) { + if (last_trb_on_seg(ep_ring->enq_seg, ep_ring->trbs_per_seg, + ep_ring->enqueue)) { xhci_warn(xhci, "Missing link TRB at end of ring segment\n"); return -EINVAL; } --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -895,8 +895,8 @@ static void xhci_clear_command_ring(stru seg = ring->deq_seg; do { memset(seg->trbs, 0, - sizeof(union xhci_trb) * (TRBS_PER_SEGMENT - 1)); - seg->trbs[TRBS_PER_SEGMENT - 1].link.control &= + sizeof(union xhci_trb) * (ring->trbs_per_seg - 1)); + seg->trbs[ring->trbs_per_seg - 1].link.control &= cpu_to_le32(~TRB_CYCLE); seg = seg->next; } while (seg != ring->deq_seg); @@ -907,7 +907,7 @@ static void xhci_clear_command_ring(stru ring->enq_seg = ring->deq_seg; ring->enqueue = ring->dequeue; - ring->num_trbs_free = ring->num_segs * (TRBS_PER_SEGMENT - 1) - 1; + ring->num_trbs_free = ring->num_segs * (ring->trbs_per_seg - 1) - 1; /* * Ring is now zeroed, so the HW should look for change of ownership * when the cycle bit is set to 1. --- a/drivers/usb/host/xhci.h +++ b/drivers/usb/host/xhci.h @@ -1633,6 +1633,7 @@ struct xhci_ring { unsigned int num_trbs_free; unsigned int num_trbs_free_temp; unsigned int bounce_buf_len; + unsigned int trbs_per_seg; enum xhci_ring_type type; bool last_td_was_short; struct radix_tree_root *trb_address_map;