svn commit: r251614 - stable/9/sys/dev/usb/controller
Hans Petter Selasky
hselasky at FreeBSD.org
Tue Jun 11 06:18:52 UTC 2013
Author: hselasky
Date: Tue Jun 11 06:18:51 2013
New Revision: 251614
URL: http://svnweb.freebsd.org/changeset/base/251614
Log:
MFC r251249, r251251, r251252, r2512, r251254 and r251515:
Correct XHCI DMA descriptor programming.
Correct maximum IRQ rate.
Modified:
stable/9/sys/dev/usb/controller/xhci.c
stable/9/sys/dev/usb/controller/xhcireg.h
Directory Properties:
stable/9/sys/ (props changed)
stable/9/sys/dev/ (props changed)
Modified: stable/9/sys/dev/usb/controller/xhci.c
==============================================================================
--- stable/9/sys/dev/usb/controller/xhci.c Tue Jun 11 03:37:29 2013 (r251613)
+++ stable/9/sys/dev/usb/controller/xhci.c Tue Jun 11 06:18:51 2013 (r251614)
@@ -1533,9 +1533,11 @@ xhci_setup_generic_chain_sub(struct xhci
struct xhci_td *td;
struct xhci_td *td_next;
struct xhci_td *td_alt_next;
+ struct xhci_td *td_first;
uint32_t buf_offset;
uint32_t average;
uint32_t len_old;
+ uint32_t npkt_off;
uint32_t dword;
uint8_t shortpkt_old;
uint8_t precompute;
@@ -1545,12 +1547,13 @@ xhci_setup_generic_chain_sub(struct xhci
buf_offset = 0;
shortpkt_old = temp->shortpkt;
len_old = temp->len;
+ npkt_off = 0;
precompute = 1;
restart:
td = temp->td;
- td_next = temp->td_next;
+ td_next = td_first = temp->td_next;
while (1) {
@@ -1651,7 +1654,7 @@ restart:
/* fill out buffer pointers */
if (average == 0) {
- npkt = 1;
+ npkt = 0;
memset(&buf_res, 0, sizeof(buf_res));
} else {
usbd_get_page(temp->pc, temp->offset +
@@ -1665,8 +1668,10 @@ restart:
if (buf_res.length > XHCI_TD_PAGE_SIZE)
buf_res.length = XHCI_TD_PAGE_SIZE;
+ npkt_off += buf_res.length;
+
/* setup npkt */
- npkt = (average + temp->max_packet_size - 1) /
+ npkt = (len_old - npkt_off + temp->max_packet_size - 1) /
temp->max_packet_size;
if (npkt > 31)
@@ -1684,32 +1689,55 @@ restart:
td->td_trb[x].dwTrb2 = htole32(dword);
- dword = XHCI_TRB_3_CHAIN_BIT | XHCI_TRB_3_CYCLE_BIT |
- XHCI_TRB_3_TYPE_SET(temp->trb_type) |
- (temp->do_isoc_sync ?
- XHCI_TRB_3_FRID_SET(temp->isoc_frame / 8) :
- XHCI_TRB_3_ISO_SIA_BIT) |
- XHCI_TRB_3_TBC_SET(temp->tbc) |
- XHCI_TRB_3_TLBPC_SET(temp->tlbpc);
-
- temp->do_isoc_sync = 0;
-
- if (temp->direction == UE_DIR_IN) {
- dword |= XHCI_TRB_3_DIR_IN;
-
- /*
- * NOTE: Only the SETUP stage should
- * use the IDT bit. Else transactions
- * can be sent using the wrong data
- * toggle value.
- */
- if (temp->trb_type !=
- XHCI_TRB_TYPE_SETUP_STAGE &&
- temp->trb_type !=
- XHCI_TRB_TYPE_STATUS_STAGE)
- dword |= XHCI_TRB_3_ISP_BIT;
+ switch (temp->trb_type) {
+ case XHCI_TRB_TYPE_ISOCH:
+ /* 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_TBC_SET(temp->tbc) |
+ XHCI_TRB_3_TLBPC_SET(temp->tlbpc);
+ if (td != td_first) {
+ dword |= XHCI_TRB_3_TYPE_SET(XHCI_TRB_TYPE_NORMAL);
+ } else if (temp->do_isoc_sync != 0) {
+ temp->do_isoc_sync = 0;
+ /* wait until "isoc_frame" */
+ dword |= XHCI_TRB_3_TYPE_SET(XHCI_TRB_TYPE_ISOCH) |
+ XHCI_TRB_3_FRID_SET(temp->isoc_frame / 8);
+ } else {
+ /* start data transfer at next interval */
+ dword |= XHCI_TRB_3_TYPE_SET(XHCI_TRB_TYPE_ISOCH) |
+ XHCI_TRB_3_ISO_SIA_BIT;
+ }
+ if (temp->direction == UE_DIR_IN)
+ dword |= XHCI_TRB_3_DIR_IN | XHCI_TRB_3_ISP_BIT;
+ break;
+ case XHCI_TRB_TYPE_DATA_STAGE:
+ dword = XHCI_TRB_3_CHAIN_BIT | XHCI_TRB_3_CYCLE_BIT |
+ XHCI_TRB_3_TYPE_SET(XHCI_TRB_TYPE_DATA_STAGE) |
+ XHCI_TRB_3_TBC_SET(temp->tbc) |
+ XHCI_TRB_3_TLBPC_SET(temp->tlbpc);
+ if (temp->direction == UE_DIR_IN)
+ dword |= XHCI_TRB_3_DIR_IN | XHCI_TRB_3_ISP_BIT;
+ break;
+ case XHCI_TRB_TYPE_STATUS_STAGE:
+ dword = XHCI_TRB_3_CHAIN_BIT | XHCI_TRB_3_CYCLE_BIT |
+ XHCI_TRB_3_TYPE_SET(XHCI_TRB_TYPE_STATUS_STAGE) |
+ XHCI_TRB_3_TBC_SET(temp->tbc) |
+ XHCI_TRB_3_TLBPC_SET(temp->tlbpc);
+ if (temp->direction == UE_DIR_IN)
+ dword |= XHCI_TRB_3_DIR_IN;
+ break;
+ default: /* XHCI_TRB_TYPE_NORMAL */
+ /* BEI: Interrupts are inhibited until EOT */
+ dword = XHCI_TRB_3_CHAIN_BIT | XHCI_TRB_3_CYCLE_BIT |
+ XHCI_TRB_3_TYPE_SET(XHCI_TRB_TYPE_NORMAL) |
+ XHCI_TRB_3_BEI_BIT |
+ XHCI_TRB_3_TBC_SET(temp->tbc) |
+ XHCI_TRB_3_TLBPC_SET(temp->tlbpc);
+ if (temp->direction == UE_DIR_IN)
+ dword |= XHCI_TRB_3_DIR_IN | XHCI_TRB_3_ISP_BIT;
+ break;
}
-
td->td_trb[x].dwTrb3 = htole32(dword);
average -= buf_res.length;
@@ -1773,9 +1801,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);
+ /*
+ * Remove cycle bit from the first TRB if we are
+ * stepping them:
+ */
+ if (temp->step_td != 0) {
+ td_first->td_trb[0].dwTrb3 &= ~htole32(XHCI_TRB_3_CYCLE_BIT);
+ usb_pc_cpu_flush(td_first->page_cache);
+ }
/* 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));
@@ -2601,6 +2634,7 @@ xhci_transfer_insert(struct usb_xfer *xf
{
struct xhci_td *td_first;
struct xhci_td *td_last;
+ struct xhci_trb *trb_link;
struct xhci_endpoint_ext *pepext;
uint64_t addr;
uint8_t i;
@@ -2666,11 +2700,15 @@ xhci_transfer_insert(struct usb_xfer *xf
/* 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]);
Modified: stable/9/sys/dev/usb/controller/xhcireg.h
==============================================================================
--- stable/9/sys/dev/usb/controller/xhcireg.h Tue Jun 11 03:37:29 2013 (r251613)
+++ stable/9/sys/dev/usb/controller/xhcireg.h Tue Jun 11 06:18:51 2013 (r251614)
@@ -166,7 +166,7 @@
#define XHCI_IMOD_IVAL_SET(x) (((x) & 0xFFFF) << 0) /* 250ns unit */
#define XHCI_IMOD_ICNT_GET(x) (((x) >> 16) & 0xFFFF) /* 250ns unit */
#define XHCI_IMOD_ICNT_SET(x) (((x) & 0xFFFF) << 16) /* 250ns unit */
-#define XHCI_IMOD_DEFAULT 0x000001F4U /* 8000 IRQ/second */
+#define XHCI_IMOD_DEFAULT 0x000003E8U /* 8000 IRQ/second */
#define XHCI_ERSTSZ(n) (0x0028 + (0x20 * (n))) /* XHCI event ring segment table size */
#define XHCI_ERSTS_GET(x) ((x) & 0xFFFF)
#define XHCI_ERSTS_SET(x) ((x) & 0xFFFF)
More information about the svn-src-stable-9
mailing list