aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb
diff options
context:
space:
mode:
authorDmitry Torokhov <dtor@vmware.com>2011-03-23 23:47:05 -0400
committerSarah Sharp <sarah.a.sharp@linux.intel.com>2011-04-13 19:19:48 -0400
commit926008c9386dde09b015753b6681c502177baa30 (patch)
treeac2f5d77acd5cb70ed9fb823123d791a34315823 /drivers/usb
parent575688e1e5f462c44ddd608ce3ec9f38b64c3c0d (diff)
USB: xhci: simplify logic of skipping missed isoc TDs
The logic of the handling Missed Service Error Events was pretty confusing as we were checking the same condition several times. In addition, it caused compiler warning since the compiler could not figure out that event_trb is actually unused in case we are skipping current TD. Fix that by rearranging "skip" condition checks, and factor out skip_isoc_td() so that it is called explicitly. Signed-off-by: Dmitry Torokhov <dtor@vmware.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.c172
1 files changed, 94 insertions, 78 deletions
diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c
index 0161eb053225..b69a0a136e66 100644
--- a/drivers/usb/host/xhci-ring.c
+++ b/drivers/usb/host/xhci-ring.c
@@ -1675,71 +1675,52 @@ static int process_isoc_td(struct xhci_hcd *xhci, struct xhci_td *td,
1675 struct urb_priv *urb_priv; 1675 struct urb_priv *urb_priv;
1676 int idx; 1676 int idx;
1677 int len = 0; 1677 int len = 0;
1678 int skip_td = 0;
1679 union xhci_trb *cur_trb; 1678 union xhci_trb *cur_trb;
1680 struct xhci_segment *cur_seg; 1679 struct xhci_segment *cur_seg;
1680 struct usb_iso_packet_descriptor *frame;
1681 u32 trb_comp_code; 1681 u32 trb_comp_code;
1682 bool skip_td = false;
1682 1683
1683 ep_ring = xhci_dma_to_transfer_ring(ep, event->buffer); 1684 ep_ring = xhci_dma_to_transfer_ring(ep, event->buffer);
1684 trb_comp_code = GET_COMP_CODE(event->transfer_len); 1685 trb_comp_code = GET_COMP_CODE(event->transfer_len);
1685 urb_priv = td->urb->hcpriv; 1686 urb_priv = td->urb->hcpriv;
1686 idx = urb_priv->td_cnt; 1687 idx = urb_priv->td_cnt;
1688 frame = &td->urb->iso_frame_desc[idx];
1687 1689
1688 if (ep->skip) { 1690 /* handle completion code */
1689 /* The transfer is partly done */ 1691 switch (trb_comp_code) {
1690 *status = -EXDEV; 1692 case COMP_SUCCESS:
1691 td->urb->iso_frame_desc[idx].status = -EXDEV; 1693 frame->status = 0;
1692 } else { 1694 xhci_dbg(xhci, "Successful isoc transfer!\n");
1693 /* handle completion code */ 1695 break;
1694 switch (trb_comp_code) { 1696 case COMP_SHORT_TX:
1695 case COMP_SUCCESS: 1697 frame->status = td->urb->transfer_flags & URB_SHORT_NOT_OK ?
1696 td->urb->iso_frame_desc[idx].status = 0; 1698 -EREMOTEIO : 0;
1697 xhci_dbg(xhci, "Successful isoc transfer!\n"); 1699 break;
1698 break; 1700 case COMP_BW_OVER:
1699 case COMP_SHORT_TX: 1701 frame->status = -ECOMM;
1700 if (td->urb->transfer_flags & URB_SHORT_NOT_OK) 1702 skip_td = true;
1701 td->urb->iso_frame_desc[idx].status = 1703 break;
1702 -EREMOTEIO; 1704 case COMP_BUFF_OVER:
1703 else 1705 case COMP_BABBLE:
1704 td->urb->iso_frame_desc[idx].status = 0; 1706 frame->status = -EOVERFLOW;
1705 break; 1707 skip_td = true;
1706 case COMP_BW_OVER: 1708 break;
1707 td->urb->iso_frame_desc[idx].status = -ECOMM; 1709 case COMP_STALL:
1708 skip_td = 1; 1710 frame->status = -EPROTO;
1709 break; 1711 skip_td = true;
1710 case COMP_BUFF_OVER: 1712 break;
1711 case COMP_BABBLE: 1713 case COMP_STOP:
1712 td->urb->iso_frame_desc[idx].status = -EOVERFLOW; 1714 case COMP_STOP_INVAL:
1713 skip_td = 1; 1715 break;
1714 break; 1716 default:
1715 case COMP_STALL: 1717 frame->status = -1;
1716 td->urb->iso_frame_desc[idx].status = -EPROTO; 1718 break;
1717 skip_td = 1;
1718 break;
1719 case COMP_STOP:
1720 case COMP_STOP_INVAL:
1721 break;
1722 default:
1723 td->urb->iso_frame_desc[idx].status = -1;
1724 break;
1725 }
1726 }
1727
1728 /* calc actual length */
1729 if (ep->skip) {
1730 td->urb->iso_frame_desc[idx].actual_length = 0;
1731 /* Update ring dequeue pointer */
1732 while (ep_ring->dequeue != td->last_trb)
1733 inc_deq(xhci, ep_ring, false);
1734 inc_deq(xhci, ep_ring, false);
1735 return finish_td(xhci, td, event_trb, event, ep, status, true);
1736 } 1719 }
1737 1720
1738 if (trb_comp_code == COMP_SUCCESS || skip_td == 1) { 1721 if (trb_comp_code == COMP_SUCCESS || skip_td) {
1739 td->urb->iso_frame_desc[idx].actual_length = 1722 frame->actual_length = frame->length;
1740 td->urb->iso_frame_desc[idx].length; 1723 td->urb->actual_length += frame->length;
1741 td->urb->actual_length +=
1742 td->urb->iso_frame_desc[idx].length;
1743 } else { 1724 } else {
1744 for (cur_trb = ep_ring->dequeue, 1725 for (cur_trb = ep_ring->dequeue,
1745 cur_seg = ep_ring->deq_seg; cur_trb != event_trb; 1726 cur_seg = ep_ring->deq_seg; cur_trb != event_trb;
@@ -1755,7 +1736,7 @@ static int process_isoc_td(struct xhci_hcd *xhci, struct xhci_td *td,
1755 TRB_LEN(event->transfer_len); 1736 TRB_LEN(event->transfer_len);
1756 1737
1757 if (trb_comp_code != COMP_STOP_INVAL) { 1738 if (trb_comp_code != COMP_STOP_INVAL) {
1758 td->urb->iso_frame_desc[idx].actual_length = len; 1739 frame->actual_length = len;
1759 td->urb->actual_length += len; 1740 td->urb->actual_length += len;
1760 } 1741 }
1761 } 1742 }
@@ -1766,6 +1747,35 @@ static int process_isoc_td(struct xhci_hcd *xhci, struct xhci_td *td,
1766 return finish_td(xhci, td, event_trb, event, ep, status, false); 1747 return finish_td(xhci, td, event_trb, event, ep, status, false);
1767} 1748}
1768 1749
1750static int skip_isoc_td(struct xhci_hcd *xhci, struct xhci_td *td,
1751 struct xhci_transfer_event *event,
1752 struct xhci_virt_ep *ep, int *status)
1753{
1754 struct xhci_ring *ep_ring;
1755 struct urb_priv *urb_priv;
1756 struct usb_iso_packet_descriptor *frame;
1757 int idx;
1758
1759 ep_ring = xhci_dma_to_transfer_ring(ep, event->buffer);
1760 urb_priv = td->urb->hcpriv;
1761 idx = urb_priv->td_cnt;
1762 frame = &td->urb->iso_frame_desc[idx];
1763
1764 /* The transfer is partly done */
1765 *status = -EXDEV;
1766 frame->status = -EXDEV;
1767
1768 /* calc actual length */
1769 frame->actual_length = 0;
1770
1771 /* Update ring dequeue pointer */
1772 while (ep_ring->dequeue != td->last_trb)
1773 inc_deq(xhci, ep_ring, false);
1774 inc_deq(xhci, ep_ring, false);
1775
1776 return finish_td(xhci, td, NULL, event, ep, status, true);
1777}
1778
1769/* 1779/*
1770 * Process bulk and interrupt tds, update urb status and actual_length. 1780 * Process bulk and interrupt tds, update urb status and actual_length.
1771 */ 1781 */
@@ -2024,36 +2034,42 @@ static int handle_tx_event(struct xhci_hcd *xhci,
2024 } 2034 }
2025 2035
2026 td = list_entry(ep_ring->td_list.next, struct xhci_td, td_list); 2036 td = list_entry(ep_ring->td_list.next, struct xhci_td, td_list);
2037
2027 /* Is this a TRB in the currently executing TD? */ 2038 /* Is this a TRB in the currently executing TD? */
2028 event_seg = trb_in_td(ep_ring->deq_seg, ep_ring->dequeue, 2039 event_seg = trb_in_td(ep_ring->deq_seg, ep_ring->dequeue,
2029 td->last_trb, event_dma); 2040 td->last_trb, event_dma);
2030 if (event_seg && ep->skip) { 2041 if (!event_seg) {
2042 if (!ep->skip ||
2043 !usb_endpoint_xfer_isoc(&td->urb->ep->desc)) {
2044 /* HC is busted, give up! */
2045 xhci_err(xhci,
2046 "ERROR Transfer event TRB DMA ptr not "
2047 "part of current TD\n");
2048 return -ESHUTDOWN;
2049 }
2050
2051 ret = skip_isoc_td(xhci, td, event, ep, &status);
2052 goto cleanup;
2053 }
2054
2055 if (ep->skip) {
2031 xhci_dbg(xhci, "Found td. Clear skip flag.\n"); 2056 xhci_dbg(xhci, "Found td. Clear skip flag.\n");
2032 ep->skip = false; 2057 ep->skip = false;
2033 } 2058 }
2034 if (!event_seg &&
2035 (!ep->skip || !usb_endpoint_xfer_isoc(&td->urb->ep->desc))) {
2036 /* HC is busted, give up! */
2037 xhci_err(xhci, "ERROR Transfer event TRB DMA ptr not "
2038 "part of current TD\n");
2039 return -ESHUTDOWN;
2040 }
2041 2059
2042 if (event_seg) { 2060 event_trb = &event_seg->trbs[(event_dma - event_seg->dma) /
2043 event_trb = &event_seg->trbs[(event_dma - 2061 sizeof(*event_trb)];
2044 event_seg->dma) / sizeof(*event_trb)]; 2062 /*
2045 /* 2063 * No-op TRB should not trigger interrupts.
2046 * No-op TRB should not trigger interrupts. 2064 * If event_trb is a no-op TRB, it means the
2047 * If event_trb is a no-op TRB, it means the 2065 * corresponding TD has been cancelled. Just ignore
2048 * corresponding TD has been cancelled. Just ignore 2066 * the TD.
2049 * the TD. 2067 */
2050 */ 2068 if ((event_trb->generic.field[3] & TRB_TYPE_BITMASK)
2051 if ((event_trb->generic.field[3] & TRB_TYPE_BITMASK) 2069 == TRB_TYPE(TRB_TR_NOOP)) {
2052 == TRB_TYPE(TRB_TR_NOOP)) { 2070 xhci_dbg(xhci,
2053 xhci_dbg(xhci, "event_trb is a no-op TRB. " 2071 "event_trb is a no-op TRB. Skip it\n");
2054 "Skip it\n"); 2072 goto cleanup;
2055 goto cleanup;
2056 }
2057 } 2073 }
2058 2074
2059 /* Now update the urb's actual_length and give back to 2075 /* Now update the urb's actual_length and give back to