xHCI: count free TRBs on transfer ring
In the past, the room_on_ring() check was implemented by walking all over the ring, which is wasteful and complicated. Count the number of free TRBs instead. The free TRBs number should be updated when enqueue/dequeue pointer is updated, or upon the completion of a set dequeue pointer command. Signed-off-by: Andiry Xu <andiry.xu@amd.com> Signed-off-by: Sarah Sharp <sarah.a.sharp@linux.intel.com> Tested-by: Paul Zimmerman <Paul.Zimmerman@synopsys.com>
This commit is contained in:
parent
3fe4fe083d
commit
b008df60c6
|
@ -135,6 +135,12 @@ static void xhci_initialize_ring_info(struct xhci_ring *ring)
|
||||||
/* Not necessary for new rings, but needed for re-initialized rings */
|
/* Not necessary for new rings, but needed for re-initialized rings */
|
||||||
ring->enq_updates = 0;
|
ring->enq_updates = 0;
|
||||||
ring->deq_updates = 0;
|
ring->deq_updates = 0;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -145,10 +145,17 @@ static void next_trb(struct xhci_hcd *xhci,
|
||||||
*/
|
*/
|
||||||
static void inc_deq(struct xhci_hcd *xhci, struct xhci_ring *ring)
|
static void inc_deq(struct xhci_hcd *xhci, struct xhci_ring *ring)
|
||||||
{
|
{
|
||||||
union xhci_trb *next = ++(ring->dequeue);
|
union xhci_trb *next;
|
||||||
unsigned long long addr;
|
unsigned long long addr;
|
||||||
|
|
||||||
ring->deq_updates++;
|
ring->deq_updates++;
|
||||||
|
|
||||||
|
/* If this is not event ring, there is one more usable TRB */
|
||||||
|
if (ring->type != TYPE_EVENT &&
|
||||||
|
!last_trb(xhci, ring, ring->deq_seg, ring->dequeue))
|
||||||
|
ring->num_trbs_free++;
|
||||||
|
next = ++(ring->dequeue);
|
||||||
|
|
||||||
/* Update the dequeue pointer further if that was a link TRB or we're at
|
/* 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)
|
* the end of an event ring segment (which doesn't have link TRBS)
|
||||||
*/
|
*/
|
||||||
|
@ -189,6 +196,10 @@ static void inc_enq(struct xhci_hcd *xhci, struct xhci_ring *ring,
|
||||||
unsigned long long addr;
|
unsigned long long addr;
|
||||||
|
|
||||||
chain = le32_to_cpu(ring->enqueue->generic.field[3]) & TRB_CHAIN;
|
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(xhci, ring, ring->enq_seg, ring->enqueue))
|
||||||
|
ring->num_trbs_free--;
|
||||||
next = ++(ring->enqueue);
|
next = ++(ring->enqueue);
|
||||||
|
|
||||||
ring->enq_updates++;
|
ring->enq_updates++;
|
||||||
|
@ -240,54 +251,14 @@ static void inc_enq(struct xhci_hcd *xhci, struct xhci_ring *ring,
|
||||||
/*
|
/*
|
||||||
* Check to see if there's room to enqueue num_trbs on the ring. See rules
|
* Check to see if there's room to enqueue num_trbs on the ring. See rules
|
||||||
* above.
|
* above.
|
||||||
* FIXME: this would be simpler and faster if we just kept track of the number
|
|
||||||
* of free TRBs in a ring.
|
|
||||||
*/
|
*/
|
||||||
static int room_on_ring(struct xhci_hcd *xhci, struct xhci_ring *ring,
|
static inline int room_on_ring(struct xhci_hcd *xhci, struct xhci_ring *ring,
|
||||||
unsigned int num_trbs)
|
unsigned int num_trbs)
|
||||||
{
|
{
|
||||||
int i;
|
if (ring->num_trbs_free >= num_trbs)
|
||||||
union xhci_trb *enq = ring->enqueue;
|
|
||||||
struct xhci_segment *enq_seg = ring->enq_seg;
|
|
||||||
struct xhci_segment *cur_seg;
|
|
||||||
unsigned int left_on_ring;
|
|
||||||
|
|
||||||
/* If we are currently pointing to a link TRB, advance the
|
|
||||||
* enqueue pointer before checking for space */
|
|
||||||
while (last_trb(xhci, ring, enq_seg, enq)) {
|
|
||||||
enq_seg = enq_seg->next;
|
|
||||||
enq = enq_seg->trbs;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Check if ring is empty */
|
|
||||||
if (enq == ring->dequeue) {
|
|
||||||
/* Can't use link trbs */
|
|
||||||
left_on_ring = TRBS_PER_SEGMENT - 1;
|
|
||||||
for (cur_seg = enq_seg->next; cur_seg != enq_seg;
|
|
||||||
cur_seg = cur_seg->next)
|
|
||||||
left_on_ring += TRBS_PER_SEGMENT - 1;
|
|
||||||
|
|
||||||
/* Always need one TRB free in the ring. */
|
|
||||||
left_on_ring -= 1;
|
|
||||||
if (num_trbs > left_on_ring) {
|
|
||||||
xhci_warn(xhci, "Not enough room on ring; "
|
|
||||||
"need %u TRBs, %u TRBs left\n",
|
|
||||||
num_trbs, left_on_ring);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
|
||||||
/* Make sure there's an extra empty TRB available */
|
return 0;
|
||||||
for (i = 0; i <= num_trbs; ++i) {
|
|
||||||
if (enq == ring->dequeue)
|
|
||||||
return 0;
|
|
||||||
enq++;
|
|
||||||
while (last_trb(xhci, ring, enq_seg, enq)) {
|
|
||||||
enq_seg = enq_seg->next;
|
|
||||||
enq = enq_seg->trbs;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Ring the host controller doorbell after placing a command on the ring */
|
/* Ring the host controller doorbell after placing a command on the ring */
|
||||||
|
@ -893,6 +864,43 @@ void xhci_stop_endpoint_command_watchdog(unsigned long arg)
|
||||||
xhci_dbg(xhci, "xHCI host controller is dead.\n");
|
xhci_dbg(xhci, "xHCI host controller is dead.\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void update_ring_for_set_deq_completion(struct xhci_hcd *xhci,
|
||||||
|
struct xhci_virt_device *dev,
|
||||||
|
struct xhci_ring *ep_ring,
|
||||||
|
unsigned int ep_index)
|
||||||
|
{
|
||||||
|
union xhci_trb *dequeue_temp;
|
||||||
|
int num_trbs_free_temp;
|
||||||
|
bool revert = false;
|
||||||
|
|
||||||
|
num_trbs_free_temp = ep_ring->num_trbs_free;
|
||||||
|
dequeue_temp = ep_ring->dequeue;
|
||||||
|
|
||||||
|
while (ep_ring->dequeue != dev->eps[ep_index].queued_deq_ptr) {
|
||||||
|
/* We have more usable TRBs */
|
||||||
|
ep_ring->num_trbs_free++;
|
||||||
|
ep_ring->dequeue++;
|
||||||
|
if (last_trb(xhci, ep_ring, ep_ring->deq_seg,
|
||||||
|
ep_ring->dequeue)) {
|
||||||
|
if (ep_ring->dequeue ==
|
||||||
|
dev->eps[ep_index].queued_deq_ptr)
|
||||||
|
break;
|
||||||
|
ep_ring->deq_seg = ep_ring->deq_seg->next;
|
||||||
|
ep_ring->dequeue = ep_ring->deq_seg->trbs;
|
||||||
|
}
|
||||||
|
if (ep_ring->dequeue == dequeue_temp) {
|
||||||
|
revert = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (revert) {
|
||||||
|
xhci_dbg(xhci, "Unable to find new dequeue pointer\n");
|
||||||
|
ep_ring->num_trbs_free = num_trbs_free_temp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* When we get a completion for a Set Transfer Ring Dequeue Pointer command,
|
* When we get a completion for a Set Transfer Ring Dequeue Pointer command,
|
||||||
* we need to clear the set deq pending flag in the endpoint ring state, so that
|
* we need to clear the set deq pending flag in the endpoint ring state, so that
|
||||||
|
@ -974,8 +982,8 @@ static void handle_set_deq_completion(struct xhci_hcd *xhci,
|
||||||
/* Update the ring's dequeue segment and dequeue pointer
|
/* Update the ring's dequeue segment and dequeue pointer
|
||||||
* to reflect the new position.
|
* to reflect the new position.
|
||||||
*/
|
*/
|
||||||
ep_ring->deq_seg = dev->eps[ep_index].queued_deq_seg;
|
update_ring_for_set_deq_completion(xhci, dev,
|
||||||
ep_ring->dequeue = dev->eps[ep_index].queued_deq_ptr;
|
ep_ring, ep_index);
|
||||||
} else {
|
} else {
|
||||||
xhci_warn(xhci, "Mismatch between completed Set TR Deq "
|
xhci_warn(xhci, "Mismatch between completed Set TR Deq "
|
||||||
"Ptr command & xHCI internal state.\n");
|
"Ptr command & xHCI internal state.\n");
|
||||||
|
@ -3407,6 +3415,7 @@ cleanup:
|
||||||
ep_ring->enqueue = urb_priv->td[0]->first_trb;
|
ep_ring->enqueue = urb_priv->td[0]->first_trb;
|
||||||
ep_ring->enq_seg = urb_priv->td[0]->start_seg;
|
ep_ring->enq_seg = urb_priv->td[0]->start_seg;
|
||||||
ep_ring->cycle_state = start_cycle;
|
ep_ring->cycle_state = start_cycle;
|
||||||
|
ep_ring->num_trbs_free = ep_ring->num_trbs_free_temp;
|
||||||
usb_hcd_unlink_urb_from_ep(bus_to_hcd(urb->dev->bus), urb);
|
usb_hcd_unlink_urb_from_ep(bus_to_hcd(urb->dev->bus), urb);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -3479,6 +3488,8 @@ int xhci_queue_isoc_tx_prepare(struct xhci_hcd *xhci, gfp_t mem_flags,
|
||||||
urb->dev->speed == USB_SPEED_FULL)
|
urb->dev->speed == USB_SPEED_FULL)
|
||||||
urb->interval /= 8;
|
urb->interval /= 8;
|
||||||
}
|
}
|
||||||
|
ep_ring->num_trbs_free_temp = ep_ring->num_trbs_free;
|
||||||
|
|
||||||
return xhci_queue_isoc_tx(xhci, GFP_ATOMIC, urb, slot_id, ep_index);
|
return xhci_queue_isoc_tx(xhci, GFP_ATOMIC, urb, slot_id, ep_index);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -729,6 +729,7 @@ static void xhci_clear_command_ring(struct xhci_hcd *xhci)
|
||||||
ring->enq_seg = ring->deq_seg;
|
ring->enq_seg = ring->deq_seg;
|
||||||
ring->enqueue = ring->dequeue;
|
ring->enqueue = ring->dequeue;
|
||||||
|
|
||||||
|
ring->num_trbs_free = ring->num_segs * (TRBS_PER_SEGMENT - 1) - 1;
|
||||||
/*
|
/*
|
||||||
* Ring is now zeroed, so the HW should look for change of ownership
|
* Ring is now zeroed, so the HW should look for change of ownership
|
||||||
* when the cycle bit is set to 1.
|
* when the cycle bit is set to 1.
|
||||||
|
|
|
@ -1278,6 +1278,8 @@ struct xhci_ring {
|
||||||
u32 cycle_state;
|
u32 cycle_state;
|
||||||
unsigned int stream_id;
|
unsigned int stream_id;
|
||||||
unsigned int num_segs;
|
unsigned int num_segs;
|
||||||
|
unsigned int num_trbs_free;
|
||||||
|
unsigned int num_trbs_free_temp;
|
||||||
enum xhci_ring_type type;
|
enum xhci_ring_type type;
|
||||||
bool last_td_was_short;
|
bool last_td_was_short;
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in New Issue