|
@@ -364,32 +364,6 @@ static void ring_doorbell_for_active_rings(struct xhci_hcd *xhci,
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
-/*
|
|
|
|
- * Find the segment that trb is in. Start searching in start_seg.
|
|
|
|
- * If we must move past a segment that has a link TRB with a toggle cycle state
|
|
|
|
- * bit set, then we will toggle the value pointed at by cycle_state.
|
|
|
|
- */
|
|
|
|
-static struct xhci_segment *find_trb_seg(
|
|
|
|
- struct xhci_segment *start_seg,
|
|
|
|
- union xhci_trb *trb, int *cycle_state)
|
|
|
|
-{
|
|
|
|
- struct xhci_segment *cur_seg = start_seg;
|
|
|
|
- struct xhci_generic_trb *generic_trb;
|
|
|
|
-
|
|
|
|
- while (cur_seg->trbs > trb ||
|
|
|
|
- &cur_seg->trbs[TRBS_PER_SEGMENT - 1] < trb) {
|
|
|
|
- generic_trb = &cur_seg->trbs[TRBS_PER_SEGMENT - 1].generic;
|
|
|
|
- if (generic_trb->field[3] & cpu_to_le32(LINK_TOGGLE))
|
|
|
|
- *cycle_state ^= 0x1;
|
|
|
|
- cur_seg = cur_seg->next;
|
|
|
|
- if (cur_seg == start_seg)
|
|
|
|
- /* Looped over the entire list. Oops! */
|
|
|
|
- return NULL;
|
|
|
|
- }
|
|
|
|
- return cur_seg;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-
|
|
|
|
static struct xhci_ring *xhci_triad_to_transfer_ring(struct xhci_hcd *xhci,
|
|
static struct xhci_ring *xhci_triad_to_transfer_ring(struct xhci_hcd *xhci,
|
|
unsigned int slot_id, unsigned int ep_index,
|
|
unsigned int slot_id, unsigned int ep_index,
|
|
unsigned int stream_id)
|
|
unsigned int stream_id)
|
|
@@ -459,9 +433,12 @@ void xhci_find_new_dequeue_state(struct xhci_hcd *xhci,
|
|
struct xhci_virt_device *dev = xhci->devs[slot_id];
|
|
struct xhci_virt_device *dev = xhci->devs[slot_id];
|
|
struct xhci_virt_ep *ep = &dev->eps[ep_index];
|
|
struct xhci_virt_ep *ep = &dev->eps[ep_index];
|
|
struct xhci_ring *ep_ring;
|
|
struct xhci_ring *ep_ring;
|
|
- struct xhci_generic_trb *trb;
|
|
|
|
|
|
+ struct xhci_segment *new_seg;
|
|
|
|
+ union xhci_trb *new_deq;
|
|
dma_addr_t addr;
|
|
dma_addr_t addr;
|
|
u64 hw_dequeue;
|
|
u64 hw_dequeue;
|
|
|
|
+ bool cycle_found = false;
|
|
|
|
+ bool td_last_trb_found = false;
|
|
|
|
|
|
ep_ring = xhci_triad_to_transfer_ring(xhci, slot_id,
|
|
ep_ring = xhci_triad_to_transfer_ring(xhci, slot_id,
|
|
ep_index, stream_id);
|
|
ep_index, stream_id);
|
|
@@ -486,45 +463,45 @@ void xhci_find_new_dequeue_state(struct xhci_hcd *xhci,
|
|
hw_dequeue = le64_to_cpu(ep_ctx->deq);
|
|
hw_dequeue = le64_to_cpu(ep_ctx->deq);
|
|
}
|
|
}
|
|
|
|
|
|
- /* Find virtual address and segment of hardware dequeue pointer */
|
|
|
|
- state->new_deq_seg = ep_ring->deq_seg;
|
|
|
|
- state->new_deq_ptr = ep_ring->dequeue;
|
|
|
|
- while (xhci_trb_virt_to_dma(state->new_deq_seg, state->new_deq_ptr)
|
|
|
|
- != (dma_addr_t)(hw_dequeue & ~0xf)) {
|
|
|
|
- next_trb(xhci, ep_ring, &state->new_deq_seg,
|
|
|
|
- &state->new_deq_ptr);
|
|
|
|
- if (state->new_deq_ptr == ep_ring->dequeue) {
|
|
|
|
- WARN_ON(1);
|
|
|
|
- return;
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
|
|
+ new_seg = ep_ring->deq_seg;
|
|
|
|
+ new_deq = ep_ring->dequeue;
|
|
|
|
+ state->new_cycle_state = hw_dequeue & 0x1;
|
|
|
|
+
|
|
/*
|
|
/*
|
|
- * Find cycle state for last_trb, starting at old cycle state of
|
|
|
|
- * hw_dequeue. If there is only one segment ring, find_trb_seg() will
|
|
|
|
- * return immediately and cannot toggle the cycle state if this search
|
|
|
|
- * wraps around, so add one more toggle manually in that case.
|
|
|
|
|
|
+ * We want to find the pointer, segment and cycle state of the new trb
|
|
|
|
+ * (the one after current TD's last_trb). We know the cycle state at
|
|
|
|
+ * hw_dequeue, so walk the ring until both hw_dequeue and last_trb are
|
|
|
|
+ * found.
|
|
*/
|
|
*/
|
|
- state->new_cycle_state = hw_dequeue & 0x1;
|
|
|
|
- if (ep_ring->first_seg == ep_ring->first_seg->next &&
|
|
|
|
- cur_td->last_trb < state->new_deq_ptr)
|
|
|
|
- state->new_cycle_state ^= 0x1;
|
|
|
|
|
|
+ do {
|
|
|
|
+ if (!cycle_found && xhci_trb_virt_to_dma(new_seg, new_deq)
|
|
|
|
+ == (dma_addr_t)(hw_dequeue & ~0xf)) {
|
|
|
|
+ cycle_found = true;
|
|
|
|
+ if (td_last_trb_found)
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+ if (new_deq == cur_td->last_trb)
|
|
|
|
+ td_last_trb_found = true;
|
|
|
|
|
|
- state->new_deq_ptr = cur_td->last_trb;
|
|
|
|
- xhci_dbg_trace(xhci, trace_xhci_dbg_cancel_urb,
|
|
|
|
- "Finding segment containing last TRB in TD.");
|
|
|
|
- state->new_deq_seg = find_trb_seg(state->new_deq_seg,
|
|
|
|
- state->new_deq_ptr, &state->new_cycle_state);
|
|
|
|
- if (!state->new_deq_seg) {
|
|
|
|
- WARN_ON(1);
|
|
|
|
- return;
|
|
|
|
- }
|
|
|
|
|
|
+ if (cycle_found &&
|
|
|
|
+ TRB_TYPE_LINK_LE32(new_deq->generic.field[3]) &&
|
|
|
|
+ new_deq->generic.field[3] & cpu_to_le32(LINK_TOGGLE))
|
|
|
|
+ state->new_cycle_state ^= 0x1;
|
|
|
|
+
|
|
|
|
+ next_trb(xhci, ep_ring, &new_seg, &new_deq);
|
|
|
|
+
|
|
|
|
+ /* Search wrapped around, bail out */
|
|
|
|
+ if (new_deq == ep->ring->dequeue) {
|
|
|
|
+ xhci_err(xhci, "Error: Failed finding new dequeue state\n");
|
|
|
|
+ state->new_deq_seg = NULL;
|
|
|
|
+ state->new_deq_ptr = NULL;
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ } while (!cycle_found || !td_last_trb_found);
|
|
|
|
|
|
- /* Increment to find next TRB after last_trb. Cycle if appropriate. */
|
|
|
|
- trb = &state->new_deq_ptr->generic;
|
|
|
|
- if (TRB_TYPE_LINK_LE32(trb->field[3]) &&
|
|
|
|
- (trb->field[3] & cpu_to_le32(LINK_TOGGLE)))
|
|
|
|
- state->new_cycle_state ^= 0x1;
|
|
|
|
- next_trb(xhci, ep_ring, &state->new_deq_seg, &state->new_deq_ptr);
|
|
|
|
|
|
+ state->new_deq_seg = new_seg;
|
|
|
|
+ state->new_deq_ptr = new_deq;
|
|
|
|
|
|
/* Don't update the ring cycle state for the producer (us). */
|
|
/* Don't update the ring cycle state for the producer (us). */
|
|
xhci_dbg_trace(xhci, trace_xhci_dbg_cancel_urb,
|
|
xhci_dbg_trace(xhci, trace_xhci_dbg_cancel_urb,
|