From 28fdbc94a368f9f022357cbf6afdd0ef06fa87a8 Mon Sep 17 00:00:00 2001 From: hselasky Date: Sun, 2 Jun 2013 11:58:31 +0000 Subject: [PATCH] Block event interrupts when we don't need it as soon as possible. Typically this feature is used for isochronous transfers. This reduces the amount of XHCI interrupting. MFC after: 1 week --- sys/dev/usb/controller/xhci.c | 33 ++++++++++++++++++++++++--------- 1 file changed, 24 insertions(+), 9 deletions(-) diff --git a/sys/dev/usb/controller/xhci.c b/sys/dev/usb/controller/xhci.c index 69c873fed3cc..6ae40ee37522 100644 --- a/sys/dev/usb/controller/xhci.c +++ b/sys/dev/usb/controller/xhci.c @@ -1545,6 +1545,7 @@ xhci_setup_generic_chain_sub(struct xhci_std_temp *temp) { struct usb_page_search buf_res; struct xhci_td *td; + struct xhci_td *td_first; struct xhci_td *td_next; struct xhci_td *td_alt_next; uint32_t buf_offset; @@ -1564,7 +1565,7 @@ xhci_setup_generic_chain_sub(struct xhci_std_temp *temp) restart: td = temp->td; - td_next = temp->td_next; + td_next = td_first = temp->td_next; while (1) { @@ -1698,7 +1699,9 @@ xhci_setup_generic_chain_sub(struct xhci_std_temp *temp) td->td_trb[x].dwTrb2 = htole32(dword); + /* BEI: Interrupts are inhibited until EOT */ dword = XHCI_TRB_3_CHAIN_BIT | XHCI_TRB_3_CYCLE_BIT | + XHCI_TRB_3_BEI_BIT | XHCI_TRB_3_TYPE_SET(temp->trb_type) | XHCI_TRB_3_TBC_SET(temp->tbc) | XHCI_TRB_3_TLBPC_SET(temp->tlbpc); @@ -1761,8 +1764,10 @@ xhci_setup_generic_chain_sub(struct xhci_std_temp *temp) td->td_trb[x].dwTrb2 = htole32(dword); + /* BEI: interrupts are inhibited until EOT */ dword = XHCI_TRB_3_TYPE_SET(XHCI_TRB_TYPE_LINK) | - XHCI_TRB_3_CYCLE_BIT | XHCI_TRB_3_IOC_BIT; + XHCI_TRB_3_CYCLE_BIT | XHCI_TRB_3_IOC_BIT | + XHCI_TRB_3_BEI_BIT; td->td_trb[x].dwTrb3 = htole32(dword); @@ -1790,9 +1795,14 @@ xhci_setup_generic_chain_sub(struct xhci_std_temp *temp) goto restart; } - /* remove cycle bit from first if we are stepping the TRBs */ - if (temp->step_td) - td->td_trb[0].dwTrb3 &= ~htole32(XHCI_TRB_3_CYCLE_BIT); + /* need to force an interrupt if we are stepping the TRBs */ + if ((temp->direction & UE_DIR_IN) != 0 && temp->multishort == 0) { + /* remove cycle bit from first TRB if we are stepping them */ + if (temp->step_td) + td_first->td_trb[0].dwTrb3 &= ~htole32(XHCI_TRB_3_CYCLE_BIT); + /* make sure the last LINK event generates an interrupt */ + td->td_trb[td->ntrb].dwTrb3 &= ~htole32(XHCI_TRB_3_BEI_BIT); + } /* remove chain bit because this is the last TRB in the chain */ td->td_trb[td->ntrb - 1].dwTrb2 &= ~htole32(XHCI_TRB_2_TDSZ_SET(15)); @@ -2655,6 +2665,7 @@ xhci_transfer_insert(struct usb_xfer *xfer) { struct xhci_td *td_first; struct xhci_td *td_last; + struct xhci_trb *trb_link; struct xhci_endpoint_ext *pepext; uint64_t addr; usb_stream_t id; @@ -2730,11 +2741,15 @@ xhci_transfer_insert(struct usb_xfer *xfer) /* compute terminating return address */ addr += (inext * sizeof(struct xhci_trb)); + /* compute link TRB pointer */ + trb_link = td_last->td_trb + td_last->ntrb; + /* update next pointer of last link TRB */ - td_last->td_trb[td_last->ntrb].qwTrb0 = htole64(addr); - td_last->td_trb[td_last->ntrb].dwTrb2 = htole32(XHCI_TRB_2_IRQ_SET(0)); - td_last->td_trb[td_last->ntrb].dwTrb3 = htole32(XHCI_TRB_3_IOC_BIT | - XHCI_TRB_3_CYCLE_BIT | XHCI_TRB_3_TYPE_SET(XHCI_TRB_TYPE_LINK)); + trb_link->qwTrb0 = htole64(addr); + trb_link->dwTrb2 = htole32(XHCI_TRB_2_IRQ_SET(0)); + trb_link->dwTrb3 = htole32(XHCI_TRB_3_IOC_BIT | + XHCI_TRB_3_CYCLE_BIT | + XHCI_TRB_3_TYPE_SET(XHCI_TRB_TYPE_LINK)); #ifdef USB_DEBUG xhci_dump_trb(&td_last->td_trb[td_last->ntrb]);