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>
This commit is contained in:
Andiry Xu 2010-12-20 15:09:34 +08:00 коммит произвёл Sarah Sharp
Родитель e1eab2e000
Коммит 50f7b52a83
1 изменённых файлов: 21 добавлений и 7 удалений

Просмотреть файл

@ -2421,7 +2421,10 @@ static void giveback_first_trb(struct xhci_hcd *xhci, int slot_id,
* isn't reordered. * isn't reordered.
*/ */
wmb(); wmb();
start_trb->field[3] |= start_cycle; if (start_cycle)
start_trb->field[3] |= start_cycle;
else
start_trb->field[3] &= ~0x1;
xhci_ring_ep_doorbell(xhci, slot_id, ep_index, stream_id); xhci_ring_ep_doorbell(xhci, slot_id, ep_index, stream_id);
} }
@ -2551,9 +2554,11 @@ static int queue_bulk_sg_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
u32 remainder = 0; u32 remainder = 0;
/* Don't change the cycle bit of the first TRB until later */ /* Don't change the cycle bit of the first TRB until later */
if (first_trb) if (first_trb) {
first_trb = false; first_trb = false;
else if (start_cycle == 0)
field |= 0x1;
} else
field |= ep_ring->cycle_state; field |= ep_ring->cycle_state;
/* Chain all the TRBs together; clear the chain bit in the last /* 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,
field = 0; field = 0;
/* Don't change the cycle bit of the first TRB until later */ /* Don't change the cycle bit of the first TRB until later */
if (first_trb) if (first_trb) {
first_trb = false; first_trb = false;
else if (start_cycle == 0)
field |= 0x1;
} else
field |= ep_ring->cycle_state; field |= ep_ring->cycle_state;
/* Chain all the TRBs together; clear the chain bit in the last /* 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,
/* Queue setup TRB - see section 6.4.1.2.1 */ /* Queue setup TRB - see section 6.4.1.2.1 */
/* FIXME better way to translate setup_packet into two u32 fields? */ /* FIXME better way to translate setup_packet into two u32 fields? */
setup = (struct usb_ctrlrequest *) urb->setup_packet; setup = (struct usb_ctrlrequest *) urb->setup_packet;
field = 0;
field |= TRB_IDT | TRB_TYPE(TRB_SETUP);
if (start_cycle == 0)
field |= 0x1;
queue_trb(xhci, ep_ring, false, true, queue_trb(xhci, ep_ring, false, true,
/* FIXME endianness is probably going to bite my ass here. */ /* FIXME endianness is probably going to bite my ass here. */
setup->bRequestType | setup->bRequest << 8 | setup->wValue << 16, setup->bRequestType | setup->bRequest << 8 | setup->wValue << 16,
setup->wIndex | setup->wLength << 16, setup->wIndex | setup->wLength << 16,
TRB_LEN(8) | TRB_INTR_TARGET(0), TRB_LEN(8) | TRB_INTR_TARGET(0),
/* Immediate data in pointer */ /* Immediate data in pointer */
TRB_IDT | TRB_TYPE(TRB_SETUP)); field);
/* If there's data, queue data TRBs */ /* If there's data, queue data TRBs */
field = 0; field = 0;
@ -2951,7 +2962,10 @@ static int xhci_queue_isoc_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
field |= TRB_TYPE(TRB_ISOC); field |= TRB_TYPE(TRB_ISOC);
/* Assume URB_ISO_ASAP is set */ /* Assume URB_ISO_ASAP is set */
field |= TRB_SIA; field |= TRB_SIA;
if (i > 0) if (i == 0) {
if (start_cycle == 0)
field |= 0x1;
} else
field |= ep_ring->cycle_state; field |= ep_ring->cycle_state;
first_trb = false; first_trb = false;
} else { } else {