diff options
author | Andiry Xu <andiry.xu@amd.com> | 2010-12-20 02:09:34 -0500 |
---|---|---|
committer | Sarah Sharp <sarah.a.sharp@linux.intel.com> | 2011-01-14 18:51:55 -0500 |
commit | 50f7b52a83a893929edf87a89ebc081ff26a7b91 (patch) | |
tree | 8cf753001566c0b925bee66c9458a30d96b94b49 /drivers/usb | |
parent | e1eab2e00015bfe48388920ff287efdbefb6af24 (diff) |
xHCI: fix cycle bit set in giveback_first_trb()
giveback_first_trb() controls the cycle bit set of the start_trb, to ensure
that the start_trb is written last and the host controller will receive a
whole td at a time.
However, if the ring is wrapped and cycle bit is toggled to zero, then
giveback_first_trb() will be of no effect. In this case, set the cycle bit of
start_trb to 1 at the beginning and clear it in giveback_first_trb().
Signed-off-by: Andiry Xu <andiry.xu@amd.com>
Signed-off-by: Sarah Sharp <sarah.a.sharp@linux.intel.com>
Diffstat (limited to 'drivers/usb')
-rw-r--r-- | drivers/usb/host/xhci-ring.c | 28 |
1 files changed, 21 insertions, 7 deletions
diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index 59f81b560483..1ee6de92193a 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c | |||
@@ -2421,7 +2421,10 @@ static void giveback_first_trb(struct xhci_hcd *xhci, int slot_id, | |||
2421 | * isn't reordered. | 2421 | * isn't reordered. |
2422 | */ | 2422 | */ |
2423 | wmb(); | 2423 | wmb(); |
2424 | start_trb->field[3] |= start_cycle; | 2424 | if (start_cycle) |
2425 | start_trb->field[3] |= start_cycle; | ||
2426 | else | ||
2427 | start_trb->field[3] &= ~0x1; | ||
2425 | xhci_ring_ep_doorbell(xhci, slot_id, ep_index, stream_id); | 2428 | xhci_ring_ep_doorbell(xhci, slot_id, ep_index, stream_id); |
2426 | } | 2429 | } |
2427 | 2430 | ||
@@ -2551,9 +2554,11 @@ static int queue_bulk_sg_tx(struct xhci_hcd *xhci, gfp_t mem_flags, | |||
2551 | u32 remainder = 0; | 2554 | u32 remainder = 0; |
2552 | 2555 | ||
2553 | /* Don't change the cycle bit of the first TRB until later */ | 2556 | /* Don't change the cycle bit of the first TRB until later */ |
2554 | if (first_trb) | 2557 | if (first_trb) { |
2555 | first_trb = false; | 2558 | first_trb = false; |
2556 | else | 2559 | if (start_cycle == 0) |
2560 | field |= 0x1; | ||
2561 | } else | ||
2557 | field |= ep_ring->cycle_state; | 2562 | field |= ep_ring->cycle_state; |
2558 | 2563 | ||
2559 | /* Chain all the TRBs together; clear the chain bit in the last | 2564 | /* Chain all the TRBs together; clear the chain bit in the last |
@@ -2711,9 +2716,11 @@ int xhci_queue_bulk_tx(struct xhci_hcd *xhci, gfp_t mem_flags, | |||
2711 | field = 0; | 2716 | field = 0; |
2712 | 2717 | ||
2713 | /* Don't change the cycle bit of the first TRB until later */ | 2718 | /* Don't change the cycle bit of the first TRB until later */ |
2714 | if (first_trb) | 2719 | if (first_trb) { |
2715 | first_trb = false; | 2720 | first_trb = false; |
2716 | else | 2721 | if (start_cycle == 0) |
2722 | field |= 0x1; | ||
2723 | } else | ||
2717 | field |= ep_ring->cycle_state; | 2724 | field |= ep_ring->cycle_state; |
2718 | 2725 | ||
2719 | /* Chain all the TRBs together; clear the chain bit in the last | 2726 | /* Chain all the TRBs together; clear the chain bit in the last |
@@ -2818,13 +2825,17 @@ int xhci_queue_ctrl_tx(struct xhci_hcd *xhci, gfp_t mem_flags, | |||
2818 | /* Queue setup TRB - see section 6.4.1.2.1 */ | 2825 | /* Queue setup TRB - see section 6.4.1.2.1 */ |
2819 | /* FIXME better way to translate setup_packet into two u32 fields? */ | 2826 | /* FIXME better way to translate setup_packet into two u32 fields? */ |
2820 | setup = (struct usb_ctrlrequest *) urb->setup_packet; | 2827 | setup = (struct usb_ctrlrequest *) urb->setup_packet; |
2828 | field = 0; | ||
2829 | field |= TRB_IDT | TRB_TYPE(TRB_SETUP); | ||
2830 | if (start_cycle == 0) | ||
2831 | field |= 0x1; | ||
2821 | queue_trb(xhci, ep_ring, false, true, | 2832 | queue_trb(xhci, ep_ring, false, true, |
2822 | /* FIXME endianness is probably going to bite my ass here. */ | 2833 | /* FIXME endianness is probably going to bite my ass here. */ |
2823 | setup->bRequestType | setup->bRequest << 8 | setup->wValue << 16, | 2834 | setup->bRequestType | setup->bRequest << 8 | setup->wValue << 16, |
2824 | setup->wIndex | setup->wLength << 16, | 2835 | setup->wIndex | setup->wLength << 16, |
2825 | TRB_LEN(8) | TRB_INTR_TARGET(0), | 2836 | TRB_LEN(8) | TRB_INTR_TARGET(0), |
2826 | /* Immediate data in pointer */ | 2837 | /* Immediate data in pointer */ |
2827 | TRB_IDT | TRB_TYPE(TRB_SETUP)); | 2838 | field); |
2828 | 2839 | ||
2829 | /* If there's data, queue data TRBs */ | 2840 | /* If there's data, queue data TRBs */ |
2830 | field = 0; | 2841 | field = 0; |
@@ -2951,7 +2962,10 @@ static int xhci_queue_isoc_tx(struct xhci_hcd *xhci, gfp_t mem_flags, | |||
2951 | field |= TRB_TYPE(TRB_ISOC); | 2962 | field |= TRB_TYPE(TRB_ISOC); |
2952 | /* Assume URB_ISO_ASAP is set */ | 2963 | /* Assume URB_ISO_ASAP is set */ |
2953 | field |= TRB_SIA; | 2964 | field |= TRB_SIA; |
2954 | if (i > 0) | 2965 | if (i == 0) { |
2966 | if (start_cycle == 0) | ||
2967 | field |= 0x1; | ||
2968 | } else | ||
2955 | field |= ep_ring->cycle_state; | 2969 | field |= ep_ring->cycle_state; |
2956 | first_trb = false; | 2970 | first_trb = false; |
2957 | } else { | 2971 | } else { |