diff options
-rw-r--r-- | drivers/usb/host/xhci-mem.c | 1 | ||||
-rw-r--r-- | drivers/usb/host/xhci-ring.c | 158 | ||||
-rw-r--r-- | drivers/usb/host/xhci.h | 8 |
3 files changed, 117 insertions, 50 deletions
diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c index 6d8f7e32932a..64d036804715 100644 --- a/drivers/usb/host/xhci-mem.c +++ b/drivers/usb/host/xhci-mem.c | |||
@@ -1124,6 +1124,7 @@ int xhci_endpoint_init(struct xhci_hcd *xhci, | |||
1124 | virt_dev->num_rings_cached--; | 1124 | virt_dev->num_rings_cached--; |
1125 | xhci_reinit_cached_ring(xhci, virt_dev->eps[ep_index].new_ring); | 1125 | xhci_reinit_cached_ring(xhci, virt_dev->eps[ep_index].new_ring); |
1126 | } | 1126 | } |
1127 | virt_dev->eps[ep_index].skip = false; | ||
1127 | ep_ring = virt_dev->eps[ep_index].new_ring; | 1128 | ep_ring = virt_dev->eps[ep_index].new_ring; |
1128 | ep_ctx->deq = ep_ring->first_seg->dma | ep_ring->cycle_state; | 1129 | ep_ctx->deq = ep_ring->first_seg->dma | ep_ring->cycle_state; |
1129 | 1130 | ||
diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index 5bb12fed9d2d..4c3501003b8e 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c | |||
@@ -1675,6 +1675,16 @@ static int handle_tx_event(struct xhci_hcd *xhci, | |||
1675 | "still with TDs queued?\n", | 1675 | "still with TDs queued?\n", |
1676 | TRB_TO_SLOT_ID(event->flags), ep_index); | 1676 | TRB_TO_SLOT_ID(event->flags), ep_index); |
1677 | goto cleanup; | 1677 | goto cleanup; |
1678 | case COMP_MISSED_INT: | ||
1679 | /* | ||
1680 | * When encounter missed service error, one or more isoc tds | ||
1681 | * may be missed by xHC. | ||
1682 | * Set skip flag of the ep_ring; Complete the missed tds as | ||
1683 | * short transfer when process the ep_ring next time. | ||
1684 | */ | ||
1685 | ep->skip = true; | ||
1686 | xhci_dbg(xhci, "Miss service interval error, set skip flag\n"); | ||
1687 | goto cleanup; | ||
1678 | default: | 1688 | default: |
1679 | if (xhci_is_vendor_info_code(xhci, trb_comp_code)) { | 1689 | if (xhci_is_vendor_info_code(xhci, trb_comp_code)) { |
1680 | status = 0; | 1690 | status = 0; |
@@ -1685,60 +1695,108 @@ static int handle_tx_event(struct xhci_hcd *xhci, | |||
1685 | goto cleanup; | 1695 | goto cleanup; |
1686 | } | 1696 | } |
1687 | 1697 | ||
1688 | /* This TRB should be in the TD at the head of this ring's TD list */ | 1698 | do { |
1689 | if (list_empty(&ep_ring->td_list)) { | 1699 | /* This TRB should be in the TD at the head of this ring's |
1690 | xhci_warn(xhci, "WARN Event TRB for slot %d ep %d with no TDs queued?\n", | 1700 | * TD list. |
1691 | TRB_TO_SLOT_ID(event->flags), ep_index); | 1701 | */ |
1692 | xhci_dbg(xhci, "Event TRB with TRB type ID %u\n", | 1702 | if (list_empty(&ep_ring->td_list)) { |
1693 | (unsigned int) (event->flags & TRB_TYPE_BITMASK)>>10); | 1703 | xhci_warn(xhci, "WARN Event TRB for slot %d ep %d " |
1694 | xhci_print_trb_offsets(xhci, (union xhci_trb *) event); | 1704 | "with no TDs queued?\n", |
1695 | goto cleanup; | 1705 | TRB_TO_SLOT_ID(event->flags), ep_index); |
1696 | } | 1706 | xhci_dbg(xhci, "Event TRB with TRB type ID %u\n", |
1697 | td = list_entry(ep_ring->td_list.next, struct xhci_td, td_list); | 1707 | (unsigned int) (event->flags & TRB_TYPE_BITMASK)>>10); |
1698 | 1708 | xhci_print_trb_offsets(xhci, (union xhci_trb *) event); | |
1699 | /* Is this a TRB in the currently executing TD? */ | 1709 | if (ep->skip) { |
1700 | event_seg = trb_in_td(ep_ring->deq_seg, ep_ring->dequeue, | 1710 | ep->skip = false; |
1701 | td->last_trb, event_dma); | 1711 | xhci_dbg(xhci, "td_list is empty while skip " |
1702 | if (!event_seg) { | 1712 | "flag set. Clear skip flag.\n"); |
1703 | /* HC is busted, give up! */ | 1713 | } |
1704 | xhci_err(xhci, "ERROR Transfer event TRB DMA ptr not part of current TD\n"); | 1714 | ret = 0; |
1705 | return -ESHUTDOWN; | 1715 | goto cleanup; |
1706 | } | 1716 | } |
1707 | event_trb = &event_seg->trbs[(event_dma - event_seg->dma) / sizeof(*event_trb)]; | ||
1708 | 1717 | ||
1709 | /* Now update the urb's actual_length and give back to the core */ | 1718 | td = list_entry(ep_ring->td_list.next, struct xhci_td, td_list); |
1710 | /* Was this a control transfer? */ | 1719 | /* Is this a TRB in the currently executing TD? */ |
1711 | if (usb_endpoint_xfer_control(&td->urb->ep->desc)) | 1720 | event_seg = trb_in_td(ep_ring->deq_seg, ep_ring->dequeue, |
1712 | ret = process_ctrl_td(xhci, td, event_trb, event, ep, | 1721 | td->last_trb, event_dma); |
1713 | &status); | 1722 | if (event_seg && ep->skip) { |
1714 | else | 1723 | xhci_dbg(xhci, "Found td. Clear skip flag.\n"); |
1715 | ret = process_bulk_intr_td(xhci, td, event_trb, event, ep, | 1724 | ep->skip = false; |
1716 | &status); | 1725 | } |
1726 | if (!event_seg && | ||
1727 | (!ep->skip || !usb_endpoint_xfer_isoc(&td->urb->ep->desc))) { | ||
1728 | /* HC is busted, give up! */ | ||
1729 | xhci_err(xhci, "ERROR Transfer event TRB DMA ptr not " | ||
1730 | "part of current TD\n"); | ||
1731 | return -ESHUTDOWN; | ||
1732 | } | ||
1717 | 1733 | ||
1718 | cleanup: | 1734 | if (event_seg) { |
1719 | inc_deq(xhci, xhci->event_ring, true); | 1735 | event_trb = &event_seg->trbs[(event_dma - |
1720 | xhci_set_hc_event_deq(xhci); | 1736 | event_seg->dma) / sizeof(*event_trb)]; |
1737 | /* | ||
1738 | * No-op TRB should not trigger interrupts. | ||
1739 | * If event_trb is a no-op TRB, it means the | ||
1740 | * corresponding TD has been cancelled. Just ignore | ||
1741 | * the TD. | ||
1742 | */ | ||
1743 | if ((event_trb->generic.field[3] & TRB_TYPE_BITMASK) | ||
1744 | == TRB_TYPE(TRB_TR_NOOP)) { | ||
1745 | xhci_dbg(xhci, "event_trb is a no-op TRB. " | ||
1746 | "Skip it\n"); | ||
1747 | goto cleanup; | ||
1748 | } | ||
1749 | } | ||
1721 | 1750 | ||
1722 | /* FIXME for multi-TD URBs (who have buffers bigger than 64MB) */ | 1751 | /* Now update the urb's actual_length and give back to |
1723 | if (ret) { | 1752 | * the core |
1724 | urb = td->urb; | ||
1725 | /* Leave the TD around for the reset endpoint function to use | ||
1726 | * (but only if it's not a control endpoint, since we already | ||
1727 | * queued the Set TR dequeue pointer command for stalled | ||
1728 | * control endpoints). | ||
1729 | */ | 1753 | */ |
1730 | if (usb_endpoint_xfer_control(&urb->ep->desc) || | 1754 | if (usb_endpoint_xfer_control(&td->urb->ep->desc)) |
1731 | (trb_comp_code != COMP_STALL && | 1755 | ret = process_ctrl_td(xhci, td, event_trb, event, ep, |
1732 | trb_comp_code != COMP_BABBLE)) | 1756 | &status); |
1733 | kfree(td); | 1757 | else |
1734 | 1758 | ret = process_bulk_intr_td(xhci, td, event_trb, event, | |
1735 | usb_hcd_unlink_urb_from_ep(xhci_to_hcd(xhci), urb); | 1759 | ep, &status); |
1736 | xhci_dbg(xhci, "Giveback URB %p, len = %d, status = %d\n", | 1760 | |
1737 | urb, urb->actual_length, status); | 1761 | cleanup: |
1738 | spin_unlock(&xhci->lock); | 1762 | /* |
1739 | usb_hcd_giveback_urb(xhci_to_hcd(xhci), urb, status); | 1763 | * Do not update event ring dequeue pointer if ep->skip is set. |
1740 | spin_lock(&xhci->lock); | 1764 | * Will roll back to continue process missed tds. |
1741 | } | 1765 | */ |
1766 | if (trb_comp_code == COMP_MISSED_INT || !ep->skip) { | ||
1767 | inc_deq(xhci, xhci->event_ring, true); | ||
1768 | xhci_set_hc_event_deq(xhci); | ||
1769 | } | ||
1770 | |||
1771 | if (ret) { | ||
1772 | urb = td->urb; | ||
1773 | /* Leave the TD around for the reset endpoint function | ||
1774 | * to use(but only if it's not a control endpoint, | ||
1775 | * since we already queued the Set TR dequeue pointer | ||
1776 | * command for stalled control endpoints). | ||
1777 | */ | ||
1778 | if (usb_endpoint_xfer_control(&urb->ep->desc) || | ||
1779 | (trb_comp_code != COMP_STALL && | ||
1780 | trb_comp_code != COMP_BABBLE)) | ||
1781 | kfree(td); | ||
1782 | |||
1783 | usb_hcd_unlink_urb_from_ep(xhci_to_hcd(xhci), urb); | ||
1784 | xhci_dbg(xhci, "Giveback URB %p, len = %d, " | ||
1785 | "status = %d\n", | ||
1786 | urb, urb->actual_length, status); | ||
1787 | spin_unlock(&xhci->lock); | ||
1788 | usb_hcd_giveback_urb(xhci_to_hcd(xhci), urb, status); | ||
1789 | spin_lock(&xhci->lock); | ||
1790 | } | ||
1791 | |||
1792 | /* | ||
1793 | * If ep->skip is set, it means there are missed tds on the | ||
1794 | * endpoint ring need to take care of. | ||
1795 | * Process them as short transfer until reach the td pointed by | ||
1796 | * the event. | ||
1797 | */ | ||
1798 | } while (ep->skip && trb_comp_code != COMP_MISSED_INT); | ||
1799 | |||
1742 | return 0; | 1800 | return 0; |
1743 | } | 1801 | } |
1744 | 1802 | ||
diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h index 5bc03d1c2beb..f4dfb26a65aa 100644 --- a/drivers/usb/host/xhci.h +++ b/drivers/usb/host/xhci.h | |||
@@ -720,6 +720,14 @@ struct xhci_virt_ep { | |||
720 | struct timer_list stop_cmd_timer; | 720 | struct timer_list stop_cmd_timer; |
721 | int stop_cmds_pending; | 721 | int stop_cmds_pending; |
722 | struct xhci_hcd *xhci; | 722 | struct xhci_hcd *xhci; |
723 | /* | ||
724 | * Sometimes the xHC can not process isochronous endpoint ring quickly | ||
725 | * enough, and it will miss some isoc tds on the ring and generate | ||
726 | * a Missed Service Error Event. | ||
727 | * Set skip flag when receive a Missed Service Error Event and | ||
728 | * process the missed tds on the endpoint ring. | ||
729 | */ | ||
730 | bool skip; | ||
723 | }; | 731 | }; |
724 | 732 | ||
725 | struct xhci_virt_device { | 733 | struct xhci_virt_device { |