diff options
Diffstat (limited to 'drivers/usb/host/xhci-ring.c')
-rw-r--r-- | drivers/usb/host/xhci-ring.c | 172 |
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 | ||
1750 | static 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 |