summaryrefslogtreecommitdiffstats
path: root/sys/dev/usb/controller/xhci.c
diff options
context:
space:
mode:
authorhselasky <hselasky@FreeBSD.org>2013-06-02 11:58:31 +0000
committerhselasky <hselasky@FreeBSD.org>2013-06-02 11:58:31 +0000
commit28fdbc94a368f9f022357cbf6afdd0ef06fa87a8 (patch)
treee659d7124af5d58967875e44743390f8d4299eeb /sys/dev/usb/controller/xhci.c
parent960738a3a8e479435612e39b0fc163f657c4c453 (diff)
downloadFreeBSD-src-28fdbc94a368f9f022357cbf6afdd0ef06fa87a8.zip
FreeBSD-src-28fdbc94a368f9f022357cbf6afdd0ef06fa87a8.tar.gz
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
Diffstat (limited to 'sys/dev/usb/controller/xhci.c')
-rw-r--r--sys/dev/usb/controller/xhci.c33
1 files changed, 24 insertions, 9 deletions
diff --git a/sys/dev/usb/controller/xhci.c b/sys/dev/usb/controller/xhci.c
index 69c873f..6ae40ee 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 @@ restart:
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 @@ restart:
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 @@ restart:
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]);
OpenPOWER on IntegriCloud