PERFORCE change 182197 for review
Hans Petter Selasky
hselasky at skunkworks.freebsd.org
Wed Aug 11 18:26:18 UTC 2010
http://p4web.freebsd.org/@@182197?ac=10
Change 182197 by hselasky at hselasky_laptop001 on 2010/08/10 16:19:57
USB controller (XHCI):
- correctly compute multiplier and burst bits for
isoc. transfers.
- isochronous transfers should not fail on
data errors and always report success to the
client unless there is a complete stop in
the isochronous schedule.
- use timeout error code instead of I/O error
code due to the way applications handle this
kind of error.
Affected files ...
.. //depot/projects/usb/src/sys/dev/usb/controller/xhci.c#25 edit
.. //depot/projects/usb/src/sys/dev/usb/controller/xhci.h#21 edit
Differences ...
==== //depot/projects/usb/src/sys/dev/usb/controller/xhci.c#25 (text+ko) ====
@@ -113,6 +113,8 @@
uint8_t last_frame;
uint8_t trb_type;
uint8_t direction;
+ uint8_t tbc;
+ uint8_t tlbpc;
};
static void xhci_do_poll(struct usb_bus *);
@@ -722,6 +724,7 @@
if (xfer->flags_int.isochronous_xfr) {
if (halted) {
halted = 0;
+ status = XHCI_TRB_ERROR_SUCCESS;
remainder = td->len;
}
}
@@ -1537,7 +1540,9 @@
dword = XHCI_TRB_3_CHAIN_BIT | XHCI_TRB_3_CYCLE_BIT |
XHCI_TRB_3_TYPE_SET(temp->trb_type) |
- XHCI_TRB_3_FRID_SET(temp->isoc_frame);
+ XHCI_TRB_3_FRID_SET(temp->isoc_frame) |
+ 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;
@@ -1637,7 +1642,10 @@
struct xhci_td *td;
uint32_t x;
uint32_t y;
+ uint8_t mult;
+ temp.tbc = 0;
+ temp.tlbpc = 0;
temp.average = xfer->max_hc_frame_size;
temp.max_packet_size = xfer->max_packet_size;
temp.sc = XHCI_BUS2SC(xfer->xroot->bus);
@@ -1663,6 +1671,20 @@
if (xfer->flags_int.isochronous_xfr) {
uint8_t shift;
+ /* compute multiplier for ISOCHRONOUS transfers */
+ mult = xfer->endpoint->ecomp ?
+ (xfer->endpoint->ecomp->bmAttributes & 3) : 0;
+ /* check for USB 2.0 multiplier */
+ if (mult == 0) {
+ mult = (xfer->endpoint->edesc->
+ wMaxPacketSize[1] >> 3) & 3;
+ }
+ /* range check */
+ if (mult > 2)
+ mult = 3;
+ else
+ mult++;
+
x = XREAD4(temp.sc, runt, XHCI_MFINDEX);
DPRINTF("MFINDEX=0x%08x\n", x);
@@ -1737,11 +1759,13 @@
xhci_setup_generic_chain_sub(&temp);
}
x = 1;
+ mult = 1;
temp.isoc_delta = 0;
temp.isoc_frame = 0;
temp.trb_type = XHCI_TRB_TYPE_DATA_STAGE;
} else {
x = 0;
+ mult = 1;
temp.isoc_delta = 0;
temp.isoc_frame = 0;
temp.trb_type = XHCI_TRB_TYPE_NORMAL;
@@ -1777,8 +1801,13 @@
temp.shortpkt = 0;
+ temp.tbc = 0;
+ temp.tlbpc = mult - 1;
+
} else if (xfer->flags_int.isochronous_xfr) {
+ uint8_t tdpc;
+
/* isochronous transfers don't have short packet termination */
temp.shortpkt = 1;
@@ -1787,6 +1816,18 @@
if (temp.len > xfer->max_frame_size)
temp.len = xfer->max_frame_size;
+
+ /* compute TD packet count */
+ tdpc = (temp.len + xfer->max_packet_size - 1) /
+ xfer->max_packet_size;
+
+ temp.tbc = ((tdpc + mult - 1) / mult) - 1;
+ temp.tlbpc = (tdpc % mult);
+
+ if (temp.tlbpc == 0)
+ temp.tlbpc = mult - 1;
+ else
+ temp.tlbpc--;
} else {
/* regular data transfer */
@@ -2000,14 +2041,14 @@
switch (edesc->bmAttributes & UE_XFERTYPE) {
case UE_INTERRUPT:
case UE_ISOCHRONOUS:
- temp = XHCI_EPCTX_4_MAX_ESIT_PAYLOAD_SET(max_frame_size);
- temp = XHCI_EPCTX_4_AVG_TRB_LEN_SET(XHCI_TD_PAYLOAD_MAX);
+ temp = XHCI_EPCTX_4_MAX_ESIT_PAYLOAD_SET(max_frame_size) |
+ XHCI_EPCTX_4_AVG_TRB_LEN_SET(XHCI_PAGE_SIZE);
break;
case UE_CONTROL:
temp = XHCI_EPCTX_4_AVG_TRB_LEN_SET(8);
break;
default:
- temp = XHCI_EPCTX_4_AVG_TRB_LEN_SET(XHCI_TD_PAYLOAD_MAX);
+ temp = XHCI_EPCTX_4_AVG_TRB_LEN_SET(XHCI_PAGE_SIZE);
break;
}
@@ -3395,11 +3436,22 @@
/* nuke remaining buffered transfers */
for (i = 0; i != (XHCI_MAX_TRANSFERS - 1); i++) {
- if (pepext->xfer[i] != NULL)
- xhci_device_done(pepext->xfer[i], USB_ERR_IOERROR);
+ /*
+ * NOTE: We need to use the timeout
+ * error code here else existing
+ * isochronous clients can get
+ * confused:
+ */
+ if (pepext->xfer[i] != NULL) {
+ xhci_device_done(pepext->xfer[i],
+ USB_ERR_TIMEOUT);
+ }
}
- /* NOTE: The USB transfer cannot vanish in this state! */
+ /*
+ * NOTE: The USB transfer cannot vanish in
+ * this state!
+ */
USB_BUS_UNLOCK(&sc->sc_bus);
==== //depot/projects/usb/src/sys/dev/usb/controller/xhci.h#21 (text+ko) ====
@@ -205,6 +205,8 @@
#define XHCI_TRB_3_CHAIN_BIT (1U << 4)
#define XHCI_TRB_3_IOC_BIT (1U << 5)
#define XHCI_TRB_3_IDT_BIT (1U << 6)
+#define XHCI_TRB_3_TBC_GET(x) (((x) >> 7) & 3)
+#define XHCI_TRB_3_TBC_SET(x) (((x) & 3) << 7)
#define XHCI_TRB_3_BEI_BIT (1U << 9)
#define XHCI_TRB_3_DCEP_BIT (1U << 9)
#define XHCI_TRB_3_PRSV_BIT (1U << 9)
More information about the p4-projects
mailing list