diff options
author | Andiry Xu <andiry.xu@amd.com> | 2012-03-05 04:49:34 -0500 |
---|---|---|
committer | Sarah Sharp <sarah.a.sharp@linux.intel.com> | 2012-03-13 12:29:55 -0400 |
commit | b008df60c6369ba0290fa7daa177375407a12e07 (patch) | |
tree | 05a59c4a4d8d624b18ad0844949841f36b241c17 | |
parent | 3fe4fe083d3355537565b2b0a678807513dfa013 (diff) |
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>
-rw-r--r-- | drivers/usb/host/xhci-mem.c | 6 | ||||
-rw-r--r-- | drivers/usb/host/xhci-ring.c | 105 | ||||
-rw-r--r-- | drivers/usb/host/xhci.c | 1 | ||||
-rw-r--r-- | drivers/usb/host/xhci.h | 2 |
4 files changed, 67 insertions, 47 deletions
diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c index bdea4de867b4..212012c97df3 100644 --- a/drivers/usb/host/xhci-mem.c +++ b/drivers/usb/host/xhci-mem.c | |||
@@ -135,6 +135,12 @@ static void xhci_initialize_ring_info(struct xhci_ring *ring) | |||
135 | /* Not necessary for new rings, but needed for re-initialized rings */ | 135 | /* Not necessary for new rings, but needed for re-initialized rings */ |
136 | ring->enq_updates = 0; | 136 | ring->enq_updates = 0; |
137 | ring->deq_updates = 0; | 137 | ring->deq_updates = 0; |
138 | |||
139 | /* | ||
140 | * Each segment has a link TRB, and leave an extra TRB for SW | ||
141 | * accounting purpose | ||
142 | */ | ||
143 | ring->num_trbs_free = ring->num_segs * (TRBS_PER_SEGMENT - 1) - 1; | ||
138 | } | 144 | } |
139 | 145 | ||
140 | /** | 146 | /** |
diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index ad68a28d8fe6..f9b6fa364f22 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c | |||
@@ -145,10 +145,17 @@ static void next_trb(struct xhci_hcd *xhci, | |||
145 | */ | 145 | */ |
146 | static void inc_deq(struct xhci_hcd *xhci, struct xhci_ring *ring) | 146 | static void inc_deq(struct xhci_hcd *xhci, struct xhci_ring *ring) |
147 | { | 147 | { |
148 | union xhci_trb *next = ++(ring->dequeue); | 148 | union xhci_trb *next; |
149 | unsigned long long addr; | 149 | unsigned long long addr; |
150 | 150 | ||
151 | ring->deq_updates++; | 151 | ring->deq_updates++; |
152 | |||
153 | /* If this is not event ring, there is one more usable TRB */ | ||
154 | if (ring->type != TYPE_EVENT && | ||
155 | !last_trb(xhci, ring, ring->deq_seg, ring->dequeue)) | ||
156 | ring->num_trbs_free++; | ||
157 | next = ++(ring->dequeue); | ||
158 | |||
152 | /* Update the dequeue pointer further if that was a link TRB or we're at | 159 | /* Update the dequeue pointer further if that was a link TRB or we're at |
153 | * the end of an event ring segment (which doesn't have link TRBS) | 160 | * the end of an event ring segment (which doesn't have link TRBS) |
154 | */ | 161 | */ |
@@ -189,6 +196,10 @@ static void inc_enq(struct xhci_hcd *xhci, struct xhci_ring *ring, | |||
189 | unsigned long long addr; | 196 | unsigned long long addr; |
190 | 197 | ||
191 | chain = le32_to_cpu(ring->enqueue->generic.field[3]) & TRB_CHAIN; | 198 | chain = le32_to_cpu(ring->enqueue->generic.field[3]) & TRB_CHAIN; |
199 | /* If this is not event ring, there is one less usable TRB */ | ||
200 | if (ring->type != TYPE_EVENT && | ||
201 | !last_trb(xhci, ring, ring->enq_seg, ring->enqueue)) | ||
202 | ring->num_trbs_free--; | ||
192 | next = ++(ring->enqueue); | 203 | next = ++(ring->enqueue); |
193 | 204 | ||
194 | ring->enq_updates++; | 205 | ring->enq_updates++; |
@@ -240,54 +251,14 @@ static void inc_enq(struct xhci_hcd *xhci, struct xhci_ring *ring, | |||
240 | /* | 251 | /* |
241 | * Check to see if there's room to enqueue num_trbs on the ring. See rules | 252 | * Check to see if there's room to enqueue num_trbs on the ring. See rules |
242 | * above. | 253 | * above. |
243 | * FIXME: this would be simpler and faster if we just kept track of the number | ||
244 | * of free TRBs in a ring. | ||
245 | */ | 254 | */ |
246 | static int room_on_ring(struct xhci_hcd *xhci, struct xhci_ring *ring, | 255 | static inline int room_on_ring(struct xhci_hcd *xhci, struct xhci_ring *ring, |
247 | unsigned int num_trbs) | 256 | unsigned int num_trbs) |
248 | { | 257 | { |
249 | int i; | 258 | if (ring->num_trbs_free >= num_trbs) |
250 | union xhci_trb *enq = ring->enqueue; | ||
251 | struct xhci_segment *enq_seg = ring->enq_seg; | ||
252 | struct xhci_segment *cur_seg; | ||
253 | unsigned int left_on_ring; | ||
254 | |||
255 | /* If we are currently pointing to a link TRB, advance the | ||
256 | * enqueue pointer before checking for space */ | ||
257 | while (last_trb(xhci, ring, enq_seg, enq)) { | ||
258 | enq_seg = enq_seg->next; | ||
259 | enq = enq_seg->trbs; | ||
260 | } | ||
261 | |||
262 | /* Check if ring is empty */ | ||
263 | if (enq == ring->dequeue) { | ||
264 | /* Can't use link trbs */ | ||
265 | left_on_ring = TRBS_PER_SEGMENT - 1; | ||
266 | for (cur_seg = enq_seg->next; cur_seg != enq_seg; | ||
267 | cur_seg = cur_seg->next) | ||
268 | left_on_ring += TRBS_PER_SEGMENT - 1; | ||
269 | |||
270 | /* Always need one TRB free in the ring. */ | ||
271 | left_on_ring -= 1; | ||
272 | if (num_trbs > left_on_ring) { | ||
273 | xhci_warn(xhci, "Not enough room on ring; " | ||
274 | "need %u TRBs, %u TRBs left\n", | ||
275 | num_trbs, left_on_ring); | ||
276 | return 0; | ||
277 | } | ||
278 | return 1; | 259 | return 1; |
279 | } | 260 | |
280 | /* Make sure there's an extra empty TRB available */ | 261 | return 0; |
281 | for (i = 0; i <= num_trbs; ++i) { | ||
282 | if (enq == ring->dequeue) | ||
283 | return 0; | ||
284 | enq++; | ||
285 | while (last_trb(xhci, ring, enq_seg, enq)) { | ||
286 | enq_seg = enq_seg->next; | ||
287 | enq = enq_seg->trbs; | ||
288 | } | ||
289 | } | ||
290 | return 1; | ||
291 | } | 262 | } |
292 | 263 | ||
293 | /* Ring the host controller doorbell after placing a command on the ring */ | 264 | /* 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) | |||
893 | xhci_dbg(xhci, "xHCI host controller is dead.\n"); | 864 | xhci_dbg(xhci, "xHCI host controller is dead.\n"); |
894 | } | 865 | } |
895 | 866 | ||
867 | |||
868 | static void update_ring_for_set_deq_completion(struct xhci_hcd *xhci, | ||
869 | struct xhci_virt_device *dev, | ||
870 | struct xhci_ring *ep_ring, | ||
871 | unsigned int ep_index) | ||
872 | { | ||
873 | union xhci_trb *dequeue_temp; | ||
874 | int num_trbs_free_temp; | ||
875 | bool revert = false; | ||
876 | |||
877 | num_trbs_free_temp = ep_ring->num_trbs_free; | ||
878 | dequeue_temp = ep_ring->dequeue; | ||
879 | |||
880 | while (ep_ring->dequeue != dev->eps[ep_index].queued_deq_ptr) { | ||
881 | /* We have more usable TRBs */ | ||
882 | ep_ring->num_trbs_free++; | ||
883 | ep_ring->dequeue++; | ||
884 | if (last_trb(xhci, ep_ring, ep_ring->deq_seg, | ||
885 | ep_ring->dequeue)) { | ||
886 | if (ep_ring->dequeue == | ||
887 | dev->eps[ep_index].queued_deq_ptr) | ||
888 | break; | ||
889 | ep_ring->deq_seg = ep_ring->deq_seg->next; | ||
890 | ep_ring->dequeue = ep_ring->deq_seg->trbs; | ||
891 | } | ||
892 | if (ep_ring->dequeue == dequeue_temp) { | ||
893 | revert = true; | ||
894 | break; | ||
895 | } | ||
896 | } | ||
897 | |||
898 | if (revert) { | ||
899 | xhci_dbg(xhci, "Unable to find new dequeue pointer\n"); | ||
900 | ep_ring->num_trbs_free = num_trbs_free_temp; | ||
901 | } | ||
902 | } | ||
903 | |||
896 | /* | 904 | /* |
897 | * When we get a completion for a Set Transfer Ring Dequeue Pointer command, | 905 | * When we get a completion for a Set Transfer Ring Dequeue Pointer command, |
898 | * we need to clear the set deq pending flag in the endpoint ring state, so that | 906 | * 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, | |||
974 | /* Update the ring's dequeue segment and dequeue pointer | 982 | /* Update the ring's dequeue segment and dequeue pointer |
975 | * to reflect the new position. | 983 | * to reflect the new position. |
976 | */ | 984 | */ |
977 | ep_ring->deq_seg = dev->eps[ep_index].queued_deq_seg; | 985 | update_ring_for_set_deq_completion(xhci, dev, |
978 | ep_ring->dequeue = dev->eps[ep_index].queued_deq_ptr; | 986 | ep_ring, ep_index); |
979 | } else { | 987 | } else { |
980 | xhci_warn(xhci, "Mismatch between completed Set TR Deq " | 988 | xhci_warn(xhci, "Mismatch between completed Set TR Deq " |
981 | "Ptr command & xHCI internal state.\n"); | 989 | "Ptr command & xHCI internal state.\n"); |
@@ -3407,6 +3415,7 @@ cleanup: | |||
3407 | ep_ring->enqueue = urb_priv->td[0]->first_trb; | 3415 | ep_ring->enqueue = urb_priv->td[0]->first_trb; |
3408 | ep_ring->enq_seg = urb_priv->td[0]->start_seg; | 3416 | ep_ring->enq_seg = urb_priv->td[0]->start_seg; |
3409 | ep_ring->cycle_state = start_cycle; | 3417 | ep_ring->cycle_state = start_cycle; |
3418 | ep_ring->num_trbs_free = ep_ring->num_trbs_free_temp; | ||
3410 | usb_hcd_unlink_urb_from_ep(bus_to_hcd(urb->dev->bus), urb); | 3419 | usb_hcd_unlink_urb_from_ep(bus_to_hcd(urb->dev->bus), urb); |
3411 | return ret; | 3420 | return ret; |
3412 | } | 3421 | } |
@@ -3479,6 +3488,8 @@ int xhci_queue_isoc_tx_prepare(struct xhci_hcd *xhci, gfp_t mem_flags, | |||
3479 | urb->dev->speed == USB_SPEED_FULL) | 3488 | urb->dev->speed == USB_SPEED_FULL) |
3480 | urb->interval /= 8; | 3489 | urb->interval /= 8; |
3481 | } | 3490 | } |
3491 | ep_ring->num_trbs_free_temp = ep_ring->num_trbs_free; | ||
3492 | |||
3482 | return xhci_queue_isoc_tx(xhci, GFP_ATOMIC, urb, slot_id, ep_index); | 3493 | return xhci_queue_isoc_tx(xhci, GFP_ATOMIC, urb, slot_id, ep_index); |
3483 | } | 3494 | } |
3484 | 3495 | ||
diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index 262400c10075..dec5b2dc298c 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c | |||
@@ -729,6 +729,7 @@ static void xhci_clear_command_ring(struct xhci_hcd *xhci) | |||
729 | ring->enq_seg = ring->deq_seg; | 729 | ring->enq_seg = ring->deq_seg; |
730 | ring->enqueue = ring->dequeue; | 730 | ring->enqueue = ring->dequeue; |
731 | 731 | ||
732 | ring->num_trbs_free = ring->num_segs * (TRBS_PER_SEGMENT - 1) - 1; | ||
732 | /* | 733 | /* |
733 | * Ring is now zeroed, so the HW should look for change of ownership | 734 | * Ring is now zeroed, so the HW should look for change of ownership |
734 | * when the cycle bit is set to 1. | 735 | * when the cycle bit is set to 1. |
diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h index 2337a8e80b60..ea8fc237d158 100644 --- a/drivers/usb/host/xhci.h +++ b/drivers/usb/host/xhci.h | |||
@@ -1278,6 +1278,8 @@ struct xhci_ring { | |||
1278 | u32 cycle_state; | 1278 | u32 cycle_state; |
1279 | unsigned int stream_id; | 1279 | unsigned int stream_id; |
1280 | unsigned int num_segs; | 1280 | unsigned int num_segs; |
1281 | unsigned int num_trbs_free; | ||
1282 | unsigned int num_trbs_free_temp; | ||
1281 | enum xhci_ring_type type; | 1283 | enum xhci_ring_type type; |
1282 | bool last_td_was_short; | 1284 | bool last_td_was_short; |
1283 | }; | 1285 | }; |