Browse Source

Add error recovery for async schedule errors & halted pipes

main
PaulStoffregen 7 years ago
parent
commit
e345c0360d
2 changed files with 113 additions and 23 deletions
  1. +22
    -20
      USBHost_t36.h
  2. +91
    -3
      ehci.cpp

+ 22
- 20
USBHost_t36.h View File

static bool allocate_interrupt_pipe_bandwidth(Pipe_t *pipe, static bool allocate_interrupt_pipe_bandwidth(Pipe_t *pipe,
uint32_t maxlen, uint32_t interval); uint32_t maxlen, uint32_t interval);
static void add_qh_to_periodic_schedule(Pipe_t *pipe); static void add_qh_to_periodic_schedule(Pipe_t *pipe);
static bool followup_Transfer(Transfer_t *transfer);
static void followup_Error(void);
protected: protected:
#ifdef USBHOST_PRINT_DEBUG #ifdef USBHOST_PRINT_DEBUG
static void print(const Transfer_t *transfer); static void print(const Transfer_t *transfer);
static void println() { Serial.println(); } static void println() { Serial.println(); }
static void print(uint32_t n, uint8_t b) { Serial.print(n, b); } static void print(uint32_t n, uint8_t b) { Serial.print(n, b); }
static void println(uint32_t n, uint8_t b) { Serial.println(n, b); } static void println(uint32_t n, uint8_t b) { Serial.println(n, b); }
static void println(const char *s, int n) {
Serial.print(s); Serial.println(n); }
static void println(const char *s, unsigned int n) {
Serial.print(s); Serial.println(n); }
static void println(const char *s, long n) {
Serial.print(s); Serial.println(n); }
static void println(const char *s, unsigned long n) {
Serial.print(s); Serial.println(n); }
static void println(const char *s, int n, uint8_t b) {
static void print(const char *s, int n, uint8_t b = DEC) {
Serial.print(s); Serial.print(n, b); }
static void print(const char *s, unsigned int n, uint8_t b = DEC) {
Serial.print(s); Serial.print(n, b); }
static void print(const char *s, long n, uint8_t b = DEC) {
Serial.print(s); Serial.print(n, b); }
static void print(const char *s, unsigned long n, uint8_t b = DEC) {
Serial.print(s); Serial.print(n, b); }
static void println(const char *s, int n, uint8_t b = DEC) {
Serial.print(s); Serial.println(n, b); } Serial.print(s); Serial.println(n, b); }
static void println(const char *s, unsigned int n, uint8_t b) {
static void println(const char *s, unsigned int n, uint8_t b = DEC) {
Serial.print(s); Serial.println(n, b); } Serial.print(s); Serial.println(n, b); }
static void println(const char *s, long n, uint8_t b) {
static void println(const char *s, long n, uint8_t b = DEC) {
Serial.print(s); Serial.println(n, b); } Serial.print(s); Serial.println(n, b); }
static void println(const char *s, unsigned long n, uint8_t b) {
static void println(const char *s, unsigned long n, uint8_t b = DEC) {
Serial.print(s); Serial.println(n, b); } Serial.print(s); Serial.println(n, b); }
#else #else
static void print(const Transfer_t *transfer) {} static void print(const Transfer_t *transfer) {}
static void println() {} static void println() {}
static void print(uint32_t n, uint8_t b) {} static void print(uint32_t n, uint8_t b) {}
static void println(uint32_t n, uint8_t b) {} static void println(uint32_t n, uint8_t b) {}
static void println(const char *s, int n) {}
static void println(const char *s, unsigned int n) {}
static void println(const char *s, long n) {}
static void println(const char *s, unsigned long n) {}
static void println(const char *s, int n, uint8_t b) {}
static void println(const char *s, unsigned int n, uint8_t b) {}
static void println(const char *s, long n, uint8_t b) {}
static void println(const char *s, unsigned long n, uint8_t b) {}
static void print(const char *s, int n, uint8_t b = DEC) {}
static void print(const char *s, unsigned int n, uint8_t b = DEC) {}
static void print(const char *s, long n, uint8_t b = DEC) {}
static void print(const char *s, unsigned long n, uint8_t b = DEC) {}
static void println(const char *s, int n, uint8_t b = DEC) {}
static void println(const char *s, unsigned int n, uint8_t b = DEC) {}
static void println(const char *s, long n, uint8_t b = DEC) {}
static void println(const char *s, unsigned long n, uint8_t b = DEC) {}
#endif #endif
static void mk_setup(setup_t &s, uint32_t bmRequestType, uint32_t bRequest, static void mk_setup(setup_t &s, uint32_t bmRequestType, uint32_t bRequest,
uint32_t wValue, uint32_t wIndex, uint32_t wLength) { uint32_t wValue, uint32_t wIndex, uint32_t wLength) {

+ 91
- 3
ehci.cpp View File



static void init_qTD(volatile Transfer_t *t, void *buf, uint32_t len, static void init_qTD(volatile Transfer_t *t, void *buf, uint32_t len,
uint32_t pid, uint32_t data01, bool irq); uint32_t pid, uint32_t data01, bool irq);
static bool followup_Transfer(Transfer_t *transfer);
static void add_to_async_followup_list(Transfer_t *first, Transfer_t *last); static void add_to_async_followup_list(Transfer_t *first, Transfer_t *last);
static void remove_from_async_followup_list(Transfer_t *transfer); static void remove_from_async_followup_list(Transfer_t *transfer);
static void add_to_periodic_followup_list(Transfer_t *first, Transfer_t *last); static void add_to_periodic_followup_list(Transfer_t *first, Transfer_t *last);
} }
} }
} }
if (stat & USBHS_USBSTS_UEI) {
followup_Error();
}


if (stat & USBHS_USBSTS_PCI) { // port change detected if (stat & USBHS_USBSTS_PCI) { // port change detected
const uint32_t portstat = USBHS_PORTSC1; const uint32_t portstat = USBHS_PORTSC1;
return true; return true;
} }


static bool followup_Transfer(Transfer_t *transfer)
bool USBHost::followup_Transfer(Transfer_t *transfer)
{ {
//println(" Followup ", (uint32_t)transfer, HEX);
print(" Followup ", (uint32_t)transfer, HEX);
println(" token=", transfer->qtd.token, HEX);


if (!(transfer->qtd.token & 0x80)) { if (!(transfer->qtd.token & 0x80)) {
// TODO: check error status // TODO: check error status
return false; return false;
} }


void USBHost::followup_Error(void)
{
println("ERROR Followup");
Transfer_t *p = async_followup_first;
while (p) {
if (followup_Transfer(p)) {
// transfer completed
Transfer_t *next = p->next_followup;
remove_from_async_followup_list(p);
println(" remove from followup list");
if (p->qtd.token & 0x40) {
Pipe_t *haltedpipe = p->pipe;
free_Transfer(p);
// traverse the rest of the list for unfinished work
// from this halted pipe. Remove from the followup
// list and put onto our own temporary list
Transfer_t *first = NULL;
Transfer_t *last = NULL;
p = next;
while (p) {
Transfer_t *next2 = p->next_followup;
if (p->pipe == haltedpipe) {
println(" stray halted ", (uint32_t)p, HEX);
remove_from_async_followup_list(p);
if (first == NULL) {
first = p;
last = p;
} else {
last->next_followup = p;
}
p->next_followup = NULL;
if (next == p) next = next2;
}
p = next2;
}
// halted pipe (probably) still has unfinished transfers
// find the halted pipe's dummy halt transfer
p = (Transfer_t *)(haltedpipe->qh.next & ~0x1F);
while (p && ((p->qtd.token & 0x40) == 0)) {
print(" qtd: ", (uint32_t)p, HEX);
print(", token=", (uint32_t)p->qtd.token, HEX);
println(", next=", (uint32_t)p->qtd.next, HEX);
p = (Transfer_t *)(p->qtd.next & ~0x1F);
}
if (p) {
// unhalt the pipe, "forget" unfinished transfers
// hopefully they're all on the list we made!
println(" dummy halt: ", (uint32_t)p, HEX);
haltedpipe->qh.next = (uint32_t)p;
haltedpipe->qh.current = 0;
haltedpipe->qh.token = 0;
} else {
println(" no dummy halt found, yikes!");
// TODO: this should never happen, but what if it does?
}

// Do any driver callbacks belonging to the unfinished
// transfers. This is done last, after retoring the
// pipe to a working state (if possible) so the driver
// callback can use the pipe.
p = first;
while (p) {
uint32_t token = p->qtd.token;
if (token & 0x8000 && haltedpipe->callback_function) {
// driver expects a callback
p->qtd.token = token | 0x40;
(*(p->pipe->callback_function))(p);
}
Transfer_t *next2 = p->next_followup;
free_Transfer(p);
p = next2;
}
} else {
free_Transfer(p);
}
p = next;
} else {
// transfer still pending
println(" remain on followup list");
p = p->next_followup;
}
}
// TODO: handle errors from periodic schedule!
}

static void add_to_async_followup_list(Transfer_t *first, Transfer_t *last) static void add_to_async_followup_list(Transfer_t *first, Transfer_t *last)
{ {
last->next_followup = NULL; // always add to end of list last->next_followup = NULL; // always add to end of list

Loading…
Cancel
Save