aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorAndiry Xu <andiry.xu@amd.com>2010-07-22 18:23:25 -0400
committerGreg Kroah-Hartman <gregkh@suse.de>2010-08-10 17:35:41 -0400
commitd18240db797ed749b511b8dc910c5dcf08be46d6 (patch)
treefe358df8e823593a144597252e72c32b6434abd2 /drivers
parent986a92d44810cad915279fdc942e2fd2c2857499 (diff)
USB: xHCI: Missed Service Error Event process
This patch adds mechanism to process Missed Service Error Event. Sometimes the xHC is unable to process the isoc TDs in time, it will generate Missed Service Error Event. In this case some TDs on the ring are not processed and missed. When encounter a Missed Servce Error Event, set the skip flag of the ep, and process the missed TDs until reach the next processed TD, then clear the skip flag. Signed-off-by: Andiry Xu <andiry.xu@amd.com> Signed-off-by: Sarah Sharp <sarah.a.sharp@linux.intel.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/usb/host/xhci-mem.c1
-rw-r--r--drivers/usb/host/xhci-ring.c158
-rw-r--r--drivers/usb/host/xhci.h8
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
1718cleanup: 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); 1761cleanup:
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
725struct xhci_virt_device { 733struct xhci_virt_device {