diff options
author | John Youn <John.Youn@synopsys.com> | 2010-05-10 18:33:00 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2010-05-20 16:21:44 -0400 |
commit | 6c12db90f19727c76990e7f4801c67a148b30111 (patch) | |
tree | ae2454143dac5970376cfeb10af008fa03eef7d7 /drivers/usb | |
parent | b0608690c2deafbca32b45196672bfd74006cf61 (diff) |
USB: xhci: Transfer ring link TRB activation change.
Change transfer ring behavior to not follow/activate link TRBs
until active TRBs are queued after it. This change affects
the behavior when a TD ends just before a link TRB.
Signed-off-by: John Youn <johnyoun@synopsys.com>
Signed-off-by: Sarah Sharp <sarah.a.sharp@linux.intel.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/usb')
-rw-r--r-- | drivers/usb/host/xhci-ring.c | 71 |
1 files changed, 58 insertions, 13 deletions
diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index 15f02e88f329..803f6810e996 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c | |||
@@ -112,6 +112,12 @@ static inline int last_trb(struct xhci_hcd *xhci, struct xhci_ring *ring, | |||
112 | return (trb->link.control & TRB_TYPE_BITMASK) == TRB_TYPE(TRB_LINK); | 112 | return (trb->link.control & TRB_TYPE_BITMASK) == TRB_TYPE(TRB_LINK); |
113 | } | 113 | } |
114 | 114 | ||
115 | static inline int enqueue_is_link_trb(struct xhci_ring *ring) | ||
116 | { | ||
117 | struct xhci_link_trb *link = &ring->enqueue->link; | ||
118 | return ((link->control & TRB_TYPE_BITMASK) == TRB_TYPE(TRB_LINK)); | ||
119 | } | ||
120 | |||
115 | /* Updates trb to point to the next TRB in the ring, and updates seg if the next | 121 | /* Updates trb to point to the next TRB in the ring, and updates seg if the next |
116 | * TRB is in a new segment. This does not skip over link TRBs, and it does not | 122 | * TRB is in a new segment. This does not skip over link TRBs, and it does not |
117 | * effect the ring dequeue or enqueue pointers. | 123 | * effect the ring dequeue or enqueue pointers. |
@@ -193,20 +199,15 @@ static void inc_enq(struct xhci_hcd *xhci, struct xhci_ring *ring, bool consumer | |||
193 | while (last_trb(xhci, ring, ring->enq_seg, next)) { | 199 | while (last_trb(xhci, ring, ring->enq_seg, next)) { |
194 | if (!consumer) { | 200 | if (!consumer) { |
195 | if (ring != xhci->event_ring) { | 201 | if (ring != xhci->event_ring) { |
196 | /* If we're not dealing with 0.95 hardware, | 202 | if (chain) { |
197 | * carry over the chain bit of the previous TRB | 203 | next->link.control |= TRB_CHAIN; |
198 | * (which may mean the chain bit is cleared). | 204 | |
199 | */ | 205 | /* Give this link TRB to the hardware */ |
200 | if (!xhci_link_trb_quirk(xhci)) { | 206 | wmb(); |
201 | next->link.control &= ~TRB_CHAIN; | 207 | next->link.control ^= TRB_CYCLE; |
202 | next->link.control |= chain; | 208 | } else { |
209 | break; | ||
203 | } | 210 | } |
204 | /* Give this link TRB to the hardware */ | ||
205 | wmb(); | ||
206 | if (next->link.control & TRB_CYCLE) | ||
207 | next->link.control &= (u32) ~TRB_CYCLE; | ||
208 | else | ||
209 | next->link.control |= (u32) TRB_CYCLE; | ||
210 | } | 211 | } |
211 | /* Toggle the cycle bit after the last ring segment. */ | 212 | /* Toggle the cycle bit after the last ring segment. */ |
212 | if (last_trb_on_last_seg(xhci, ring, ring->enq_seg, next)) { | 213 | if (last_trb_on_last_seg(xhci, ring, ring->enq_seg, next)) { |
@@ -245,6 +246,13 @@ static int room_on_ring(struct xhci_hcd *xhci, struct xhci_ring *ring, | |||
245 | struct xhci_segment *cur_seg; | 246 | struct xhci_segment *cur_seg; |
246 | unsigned int left_on_ring; | 247 | unsigned int left_on_ring; |
247 | 248 | ||
249 | /* If we are currently pointing to a link TRB, advance the | ||
250 | * enqueue pointer before checking for space */ | ||
251 | while (last_trb(xhci, ring, enq_seg, enq)) { | ||
252 | enq_seg = enq_seg->next; | ||
253 | enq = enq_seg->trbs; | ||
254 | } | ||
255 | |||
248 | /* Check if ring is empty */ | 256 | /* Check if ring is empty */ |
249 | if (enq == ring->dequeue) { | 257 | if (enq == ring->dequeue) { |
250 | /* Can't use link trbs */ | 258 | /* Can't use link trbs */ |
@@ -1728,6 +1736,43 @@ static int prepare_ring(struct xhci_hcd *xhci, struct xhci_ring *ep_ring, | |||
1728 | xhci_err(xhci, "ERROR no room on ep ring\n"); | 1736 | xhci_err(xhci, "ERROR no room on ep ring\n"); |
1729 | return -ENOMEM; | 1737 | return -ENOMEM; |
1730 | } | 1738 | } |
1739 | |||
1740 | if (enqueue_is_link_trb(ep_ring)) { | ||
1741 | struct xhci_ring *ring = ep_ring; | ||
1742 | union xhci_trb *next; | ||
1743 | unsigned long long addr; | ||
1744 | |||
1745 | xhci_dbg(xhci, "prepare_ring: pointing to link trb\n"); | ||
1746 | next = ring->enqueue; | ||
1747 | |||
1748 | while (last_trb(xhci, ring, ring->enq_seg, next)) { | ||
1749 | |||
1750 | /* If we're not dealing with 0.95 hardware, | ||
1751 | * clear the chain bit. | ||
1752 | */ | ||
1753 | if (!xhci_link_trb_quirk(xhci)) | ||
1754 | next->link.control &= ~TRB_CHAIN; | ||
1755 | else | ||
1756 | next->link.control |= TRB_CHAIN; | ||
1757 | |||
1758 | wmb(); | ||
1759 | next->link.control ^= (u32) TRB_CYCLE; | ||
1760 | |||
1761 | /* Toggle the cycle bit after the last ring segment. */ | ||
1762 | if (last_trb_on_last_seg(xhci, ring, ring->enq_seg, next)) { | ||
1763 | ring->cycle_state = (ring->cycle_state ? 0 : 1); | ||
1764 | if (!in_interrupt()) { | ||
1765 | xhci_dbg(xhci, "queue_trb: Toggle cycle " | ||
1766 | "state for ring %p = %i\n", | ||
1767 | ring, (unsigned int)ring->cycle_state); | ||
1768 | } | ||
1769 | } | ||
1770 | ring->enq_seg = ring->enq_seg->next; | ||
1771 | ring->enqueue = ring->enq_seg->trbs; | ||
1772 | next = ring->enqueue; | ||
1773 | } | ||
1774 | } | ||
1775 | |||
1731 | return 0; | 1776 | return 0; |
1732 | } | 1777 | } |
1733 | 1778 | ||