summaryrefslogtreecommitdiff
path: root/payloads/libpayload
diff options
context:
space:
mode:
Diffstat (limited to 'payloads/libpayload')
-rw-r--r--payloads/libpayload/drivers/usb/dwc2.c17
-rw-r--r--payloads/libpayload/drivers/usb/ehci.c14
-rw-r--r--payloads/libpayload/drivers/usb/ohci.c11
-rw-r--r--payloads/libpayload/drivers/usb/uhci.c8
-rw-r--r--payloads/libpayload/drivers/usb/xhci_events.c14
-rw-r--r--payloads/libpayload/include/usb/usb.h18
6 files changed, 47 insertions, 35 deletions
diff --git a/payloads/libpayload/drivers/usb/dwc2.c b/payloads/libpayload/drivers/usb/dwc2.c
index 34de3bc42b..06c54e1030 100644
--- a/payloads/libpayload/drivers/usb/dwc2.c
+++ b/payloads/libpayload/drivers/usb/dwc2.c
@@ -146,6 +146,8 @@ static int dwc2_disconnected(hci_t *controller)
return !(hprt.prtena && hprt.prtconnsts);
}
+#define DWC2_SLEEP_TIME_US 5
+
/*
* This function returns the actual transfer length when the transfer succeeded
* or an error code if the transfer failed
@@ -157,14 +159,14 @@ wait_for_complete(endpoint_t *ep, uint32_t ch_num)
hcchar_t hcchar;
hctsiz_t hctsiz;
dwc2_reg_t *reg = DWC2_REG(ep->dev->controller);
- int timeout = 600000; /* time out after 600000 * 5us == 3s */
+ int timeout = USB_MAX_PROCESSING_TIME_US / DWC_SLEEP_TIME_US;
/*
* TODO: We should take care of up to three times of transfer error
* retry here, according to the USB 2.0 spec 4.5.2
*/
do {
- udelay(5);
+ udelay(DWC_SLEEP_TIME_US);
hcint.d32 = readl(&reg->host.hchn[ch_num].hcintn);
hctsiz.d32 = readl(&reg->host.hchn[ch_num].hctsizn);
@@ -374,12 +376,15 @@ static int dwc2_need_split(usbdev_t *dev, split_info_t *split)
return 1;
}
+#define USB_FULL_LOW_SPEED_FRAME_US 1000
+
static int
dwc2_transfer(endpoint_t *ep, int size, int pid, ep_dir_t dir, uint32_t ch_num,
u8 *src, uint8_t skip_nak)
{
split_info_t split;
- int ret, short_pkt, transferred = 0, timeout = 3000;
+ int ret, short_pkt, transferred = 0;
+ int timeout = USB_MAX_PROCESSING_TIME_US / USB_FULL_LOW_SPEED_FRAME_US;
ep->toggle = pid;
@@ -393,11 +398,11 @@ nak_retry:
/*
* dwc2_split_transfer() waits for the next FullSpeed
- * frame boundary, so we have one try per millisecond.
- * It's 3s timeout for each split transfer.
+ * frame boundary, so we only need to delay 500 us
+ * here to have one try per millisecond.
*/
if (ret == -HCSTAT_NAK && !skip_nak && --timeout) {
- udelay(500);
+ udelay(USB_FULL_LOW_SPEED_FRAME_US / 2);
goto nak_retry;
}
} else {
diff --git a/payloads/libpayload/drivers/usb/ehci.c b/payloads/libpayload/drivers/usb/ehci.c
index 3d6c077b31..68763402af 100644
--- a/payloads/libpayload/drivers/usb/ehci.c
+++ b/payloads/libpayload/drivers/usb/ehci.c
@@ -247,6 +247,8 @@ static void free_qh_and_tds(ehci_qh_t *qh, qtd_t *cur)
free((void *)qh);
}
+#define EHCI_SLEEP_TIME_US 50
+
static int wait_for_tds(qtd_t *head)
{
/* returns the amount of bytes *not* transmitted, or -1 for error */
@@ -256,18 +258,10 @@ static int wait_for_tds(qtd_t *head)
if (0) dump_td(virt_to_phys(cur));
/* wait for results */
- /* how long to wait?
- * tested with some USB2.0 flash sticks:
- * TUR turn around took
- * about 2.2s for the slowest (13fe:3800)
- * max. 250ms for the others
- * slowest non-TUR turn around took about 1.3s
- * set to 3s to be safe as a failed TUR can be fatal
- */
- int timeout = 60000; /* time out after 60000 * 50us == 3s */
+ int timeout = USB_MAX_PROCESSING_TIME_US / EHCI_SLEEP_TIME_US;
while ((cur->token & QTD_ACTIVE) && !(cur->token & QTD_HALTED)
&& timeout--)
- udelay(50);
+ udelay(EHCI_SLEEP_TIME_US);
if (timeout < 0) {
usb_debug("Error: ehci: queue transfer "
"processing timed out.\n");
diff --git a/payloads/libpayload/drivers/usb/ohci.c b/payloads/libpayload/drivers/usb/ohci.c
index ecd1084005..f1dc081656 100644
--- a/payloads/libpayload/drivers/usb/ohci.c
+++ b/payloads/libpayload/drivers/usb/ohci.c
@@ -292,14 +292,13 @@ ohci_stop (hci_t *controller)
OHCI_INST (controller)->opreg->HcControl &= ~PeriodicListEnable;
}
+#define OHCI_SLEEP_TIME_US 1000
+
static int
wait_for_ed(usbdev_t *dev, ed_t *head, int pages)
{
/* wait for results */
- /* TOTEST: how long to wait?
- * give 2s per TD (2 pages) plus another 2s for now
- */
- int timeout = pages*1000 + 2000;
+ int timeout = USB_MAX_PROCESSING_TIME_US / OHCI_SLEEP_TIME_US;
while (((head->head_pointer & ~3) != head->tail_pointer) &&
!(head->head_pointer & 1) &&
((((td_t*)phys_to_virt(head->head_pointer & ~3))->config
@@ -315,9 +314,9 @@ wait_for_ed(usbdev_t *dev, ed_t *head, int pages)
((td_t*)phys_to_virt(head->head_pointer & ~3))->next_td,
head->tail_pointer,
(((td_t*)phys_to_virt(head->head_pointer & ~3))->config & TD_CC_MASK) >> TD_CC_SHIFT);
- mdelay(1);
+ udelay(OHCI_SLEEP_TIME_US);
}
- if (timeout < 0)
+ if (timeout <= 0)
usb_debug("Error: ohci: endpoint "
"descriptor processing timed out.\n");
/* Clear the done queue. */
diff --git a/payloads/libpayload/drivers/usb/uhci.c b/payloads/libpayload/drivers/usb/uhci.c
index e62fd25a2d..32d40901a0 100644
--- a/payloads/libpayload/drivers/usb/uhci.c
+++ b/payloads/libpayload/drivers/usb/uhci.c
@@ -272,21 +272,23 @@ uhci_stop (hci_t *controller)
uhci_reg_read16(controller, USBCMD) & ~1); // stop work on schedule
}
+#define UHCI_SLEEP_TIME_US 30
+#define UHCI_TIMEOUT (USB_MAX_PROCESSING_TIME_US / UHCI_SLEEP_TIME_US)
#define GET_TD(x) ((void*)(((unsigned int)(x))&~0xf))
static td_t *
wait_for_completed_qh (hci_t *controller, qh_t *qh)
{
- int timeout = 1000; /* max 30 ms. */
+ int timeout = UHCI_TIMEOUT;
void *current = GET_TD (qh->elementlinkptr);
while (((qh->elementlinkptr & FLISTP_TERMINATE) == 0) && (timeout-- > 0)) {
if (current != GET_TD (qh->elementlinkptr)) {
current = GET_TD (qh->elementlinkptr);
- timeout = 1000;
+ timeout = UHCI_TIMEOUT;
}
uhci_reg_write16(controller, USBSTS,
uhci_reg_read16(controller, USBSTS) | 0); // clear resettable registers
- udelay (30);
+ udelay(UHCI_SLEEP_TIME_US);
}
return (GET_TD (qh->elementlinkptr) ==
0) ? 0 : GET_TD (phys_to_virt (qh->elementlinkptr));
diff --git a/payloads/libpayload/drivers/usb/xhci_events.c b/payloads/libpayload/drivers/usb/xhci_events.c
index dacb5d8618..c21797de93 100644
--- a/payloads/libpayload/drivers/usb/xhci_events.c
+++ b/payloads/libpayload/drivers/usb/xhci_events.c
@@ -236,7 +236,7 @@ xhci_wait_for_command_aborted(xhci_t *const xhci, const trb_t *const address)
* we don't get a response after 5s. Still, let the caller decide,
* what to do then.
*/
- unsigned long timeout_us = 5 * 1000 * 1000; /* 5s */
+ unsigned long timeout_us = USB_MAX_PROCESSING_TIME_US; /* 5s */
int cc = TIMEOUT;
/*
* Expects two command completion events:
@@ -280,13 +280,7 @@ xhci_wait_for_command_done(xhci_t *const xhci,
const trb_t *const address,
const int clear_event)
{
- /*
- * The Address Device Command should take most time, as it has to
- * communicate with the USB device. Set address processing shouldn't
- * take longer than 50ms (at the slave). Let's take a timeout of
- * 100ms.
- */
- unsigned long timeout_us = 100 * 1000; /* 100ms */
+ unsigned long timeout_us = USB_MAX_PROCESSING_TIME_US; /* 5s */
int cc = TIMEOUT;
while (xhci_wait_for_event_type(xhci, TRB_EV_CMD_CMPL, &timeout_us)) {
if ((xhci->er.cur->ptr_low == virt_to_phys(address)) &&
@@ -311,8 +305,8 @@ int
xhci_wait_for_transfer(xhci_t *const xhci, const int slot_id, const int ep_id)
{
xhci_spew("Waiting for transfer on ID %d EP %d\n", slot_id, ep_id);
- /* 3s for all types of transfers */ /* TODO: test, wait longer? */
- unsigned long timeout_us = 3 * 1000 * 1000;
+ /* 5s for all types of transfers */
+ unsigned long timeout_us = USB_MAX_PROCESSING_TIME_US;
int ret = TIMEOUT;
while (xhci_wait_for_event_type(xhci, TRB_EV_TRANSFER, &timeout_us)) {
if (TRB_GET(ID, xhci->er.cur) == slot_id &&
diff --git a/payloads/libpayload/include/usb/usb.h b/payloads/libpayload/include/usb/usb.h
index 79c4586c4a..db7ec57d57 100644
--- a/payloads/libpayload/include/usb/usb.h
+++ b/payloads/libpayload/include/usb/usb.h
@@ -71,6 +71,24 @@ typedef enum {
/* SetAddress() recovery interval (USB 2.0 specification 9.2.6.3 */
#define SET_ADDRESS_MDELAY 2
+/*
+ * USB sets an upper limit of 5 seconds for any transfer to be completed.
+ *
+ * Data originally from EHCI driver:
+ * Tested with some USB2.0 flash sticks:
+ * TUR turn around took about 2.2s for the slowest (13fe:3800), maximum
+ * of 250ms for the others.
+ *
+ * SET ADDRESS on xHCI controllers.
+ * The USB specification indicates that devices must complete processing
+ * of a SET ADDRESS request within 50 ms. However, some hubs were found
+ * to take more than 100 ms to complete a SET ADDRESS request on a
+ * downstream port.
+ */
+#define USB_MAX_PROCESSING_TIME_US (5 * 1000 * 1000)
+
+#define USB_FULL_LOW_SPEED_FRAME_US 1000
+
typedef struct {
unsigned char bDescLength;
unsigned char bDescriptorType;