aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--hw/usb-ehci.c307
-rw-r--r--trace-events4
2 files changed, 174 insertions, 137 deletions
diff --git a/hw/usb-ehci.c b/hw/usb-ehci.c
index 16fbca6b9d..40a447bc80 100644
--- a/hw/usb-ehci.c
+++ b/hw/usb-ehci.c
@@ -33,20 +33,13 @@
#include "trace.h"
#define EHCI_DEBUG 0
-#define STATE_DEBUG 0 /* state transitions */
-#if EHCI_DEBUG || STATE_DEBUG
+#if EHCI_DEBUG
#define DPRINTF printf
#else
#define DPRINTF(...)
#endif
-#if STATE_DEBUG
-#define DPRINTF_ST DPRINTF
-#else
-#define DPRINTF_ST(...)
-#endif
-
/* internal processing - reset HC to try and recover */
#define USB_RET_PROCERR (-99)
@@ -417,33 +410,59 @@ typedef struct {
*data = val; \
} while(0)
+static const char *ehci_state_names[] = {
+ [ EST_INACTIVE ] = "INACTIVE",
+ [ EST_ACTIVE ] = "ACTIVE",
+ [ EST_EXECUTING ] = "EXECUTING",
+ [ EST_SLEEPING ] = "SLEEPING",
+ [ EST_WAITLISTHEAD ] = "WAITLISTHEAD",
+ [ EST_FETCHENTRY ] = "FETCH ENTRY",
+ [ EST_FETCHQH ] = "FETCH QH",
+ [ EST_FETCHITD ] = "FETCH ITD",
+ [ EST_ADVANCEQUEUE ] = "ADVANCEQUEUE",
+ [ EST_FETCHQTD ] = "FETCH QTD",
+ [ EST_EXECUTE ] = "EXECUTE",
+ [ EST_WRITEBACK ] = "WRITEBACK",
+ [ EST_HORIZONTALQH ] = "HORIZONTALQH",
+};
+
+static const char *ehci_mmio_names[] = {
+ [ CAPLENGTH ] = "CAPLENGTH",
+ [ HCIVERSION ] = "HCIVERSION",
+ [ HCSPARAMS ] = "HCSPARAMS",
+ [ HCCPARAMS ] = "HCCPARAMS",
+ [ USBCMD ] = "USBCMD",
+ [ USBSTS ] = "USBSTS",
+ [ USBINTR ] = "USBINTR",
+ [ FRINDEX ] = "FRINDEX",
+ [ PERIODICLISTBASE ] = "P-LIST BASE",
+ [ ASYNCLISTADDR ] = "A-LIST ADDR",
+ [ PORTSC_BEGIN ] = "PORTSC #0",
+ [ PORTSC_BEGIN + 4] = "PORTSC #1",
+ [ PORTSC_BEGIN + 8] = "PORTSC #2",
+ [ PORTSC_BEGIN + 12] = "PORTSC #3",
+ [ CONFIGFLAG ] = "CONFIGFLAG",
+};
-static const char *addr2str(target_phys_addr_t addr)
+static const char *nr2str(const char **n, size_t len, uint32_t nr)
{
- const char *r = "unknown";
- const char *n[] = {
- [ CAPLENGTH ] = "CAPLENGTH",
- [ HCIVERSION ] = "HCIVERSION",
- [ HCSPARAMS ] = "HCSPARAMS",
- [ HCCPARAMS ] = "HCCPARAMS",
- [ USBCMD ] = "USBCMD",
- [ USBSTS ] = "USBSTS",
- [ USBINTR ] = "USBINTR",
- [ FRINDEX ] = "FRINDEX",
- [ PERIODICLISTBASE ] = "P-LIST BASE",
- [ ASYNCLISTADDR ] = "A-LIST ADDR",
- [ PORTSC_BEGIN ...
- PORTSC_END ] = "PORTSC",
- [ CONFIGFLAG ] = "CONFIGFLAG",
- };
-
- if (addr < ARRAY_SIZE(n) && n[addr] != NULL) {
- return n[addr];
+ if (nr < len && n[nr] != NULL) {
+ return n[nr];
} else {
- return r;
+ return "unknown";
}
}
+static const char *state2str(uint32_t state)
+{
+ return nr2str(ehci_state_names, ARRAY_SIZE(ehci_state_names), state);
+}
+
+static const char *addr2str(target_phys_addr_t addr)
+{
+ return nr2str(ehci_mmio_names, ARRAY_SIZE(ehci_mmio_names), addr);
+}
+
static void ehci_trace_usbsts(uint32_t mask, int state)
{
/* interrupts */
@@ -528,6 +547,56 @@ static inline void ehci_commit_interrupt(EHCIState *s)
s->usbsts_pending = 0;
}
+static void ehci_set_state(EHCIState *s, int async, int state)
+{
+ if (async) {
+ trace_usb_ehci_state("async", state2str(state));
+ s->astate = state;
+ } else {
+ trace_usb_ehci_state("periodic", state2str(state));
+ s->pstate = state;
+ }
+}
+
+static int ehci_get_state(EHCIState *s, int async)
+{
+ return async ? s->astate : s->pstate;
+}
+
+static void ehci_trace_qh(EHCIState *s, target_phys_addr_t addr, EHCIqh *qh)
+{
+ trace_usb_ehci_qh(addr, qh->next,
+ qh->current_qtd, qh->next_qtd, qh->altnext_qtd,
+ get_field(qh->epchar, QH_EPCHAR_RL),
+ get_field(qh->epchar, QH_EPCHAR_MPLEN),
+ get_field(qh->epchar, QH_EPCHAR_EPS),
+ get_field(qh->epchar, QH_EPCHAR_EP),
+ get_field(qh->epchar, QH_EPCHAR_DEVADDR),
+ (bool)(qh->epchar & QH_EPCHAR_C),
+ (bool)(qh->epchar & QH_EPCHAR_H),
+ (bool)(qh->epchar & QH_EPCHAR_DTC),
+ (bool)(qh->epchar & QH_EPCHAR_I));
+}
+
+static void ehci_trace_qtd(EHCIState *s, target_phys_addr_t addr, EHCIqtd *qtd)
+{
+ trace_usb_ehci_qtd(addr, qtd->next, qtd->altnext,
+ get_field(qtd->token, QTD_TOKEN_TBYTES),
+ get_field(qtd->token, QTD_TOKEN_CPAGE),
+ get_field(qtd->token, QTD_TOKEN_CERR),
+ get_field(qtd->token, QTD_TOKEN_PID),
+ (bool)(qtd->token & QTD_TOKEN_IOC),
+ (bool)(qtd->token & QTD_TOKEN_ACTIVE),
+ (bool)(qtd->token & QTD_TOKEN_HALT),
+ (bool)(qtd->token & QTD_TOKEN_BABBLE),
+ (bool)(qtd->token & QTD_TOKEN_XACTERR));
+}
+
+static void ehci_trace_itd(EHCIState *s, target_phys_addr_t addr, EHCIitd *itd)
+{
+ trace_usb_ehci_itd(addr, itd->next);
+}
+
/* Attach or detach a device on root hub */
static void ehci_attach(USBPort *port)
@@ -1230,7 +1299,7 @@ static int ehci_process_itd(EHCIState *ehci,
/* This state is the entry point for asynchronous schedule
* processing. Entry here consitutes a EHCI start event state (4.8.5)
*/
-static int ehci_state_waitlisthead(EHCIState *ehci, int async, int *state)
+static int ehci_state_waitlisthead(EHCIState *ehci, int async)
{
EHCIqh *qh = &ehci->qh;
int i = 0;
@@ -1245,32 +1314,28 @@ static int ehci_state_waitlisthead(EHCIState *ehci, int async, int *state)
/* Find the head of the list (4.9.1.1) */
for(i = 0; i < MAX_QH; i++) {
get_dwords(NLPTR_GET(entry), (uint32_t *) qh, sizeof(EHCIqh) >> 2);
+ ehci_trace_qh(ehci, NLPTR_GET(entry), qh);
if (qh->epchar & QH_EPCHAR_H) {
- DPRINTF_ST("WAITLISTHEAD: QH %08X is the HEAD of the list\n",
- entry);
if (async) {
entry |= (NLPTR_TYPE_QH << 1);
}
ehci->fetch_addr = entry;
- *state = EST_FETCHENTRY;
+ ehci_set_state(ehci, async, EST_FETCHENTRY);
again = 1;
goto out;
}
- DPRINTF_ST("WAITLISTHEAD: QH %08X is NOT the HEAD of the list\n",
- entry);
entry = qh->next;
if (entry == ehci->asynclistaddr) {
- DPRINTF("WAITLISTHEAD: reached beginning of QH list\n");
break;
}
}
/* no head found for list. */
- *state = EST_ACTIVE;
+ ehci_set_state(ehci, async, EST_ACTIVE);
out:
return again;
@@ -1280,7 +1345,7 @@ out:
/* This state is the entry point for periodic schedule processing as
* well as being a continuation state for async processing.
*/
-static int ehci_state_fetchentry(EHCIState *ehci, int async, int *state)
+static int ehci_state_fetchentry(EHCIState *ehci, int async)
{
int again = 0;
uint32_t entry = ehci->fetch_addr;
@@ -1298,7 +1363,7 @@ static int ehci_state_fetchentry(EHCIState *ehci, int async, int *state)
#endif
if (entry < 0x1000) {
DPRINTF("fetchentry: entry invalid (0x%08x)\n", entry);
- *state = EST_ACTIVE;
+ ehci_set_state(ehci, async, EST_ACTIVE);
goto out;
}
@@ -1310,15 +1375,13 @@ static int ehci_state_fetchentry(EHCIState *ehci, int async, int *state)
switch (NLPTR_TYPE_GET(entry)) {
case NLPTR_TYPE_QH:
- DPRINTF_ST("FETCHENTRY: entry %X is a Queue Head\n", entry);
- *state = EST_FETCHQH;
+ ehci_set_state(ehci, async, EST_FETCHQH);
ehci->qhaddr = entry;
again = 1;
break;
case NLPTR_TYPE_ITD:
- DPRINTF_ST("FETCHENTRY: entry %X is an ITD\n", entry);
- *state = EST_FETCHITD;
+ ehci_set_state(ehci, async, EST_FETCHITD);
ehci->itdaddr = entry;
again = 1;
break;
@@ -1334,13 +1397,14 @@ out:
return again;
}
-static int ehci_state_fetchqh(EHCIState *ehci, int async, int *state)
+static int ehci_state_fetchqh(EHCIState *ehci, int async)
{
EHCIqh *qh = &ehci->qh;
int reload;
int again = 0;
get_dwords(NLPTR_GET(ehci->qhaddr), (uint32_t *) qh, sizeof(EHCIqh) >> 2);
+ ehci_trace_qh(ehci, NLPTR_GET(ehci->qhaddr), qh);
if (async && (qh->epchar & QH_EPCHAR_H)) {
@@ -1350,7 +1414,7 @@ static int ehci_state_fetchqh(EHCIState *ehci, int async, int *state)
} else {
DPRINTF("FETCHQH: QH 0x%08x. H-bit set, reclamation status reset"
" - done processing\n", ehci->qhaddr);
- *state = EST_ACTIVE;
+ ehci_set_state(ehci, async, EST_ACTIVE);
goto out;
}
}
@@ -1368,25 +1432,21 @@ static int ehci_state_fetchqh(EHCIState *ehci, int async, int *state)
reload = get_field(qh->epchar, QH_EPCHAR_RL);
if (reload) {
- DPRINTF_ST("FETCHQH: reloading nakcnt to %d\n", reload);
set_field(&qh->altnext_qtd, reload, QH_ALTNEXT_NAKCNT);
}
if (qh->token & QTD_TOKEN_HALT) {
- DPRINTF_ST("FETCHQH: QH Halted, go horizontal\n");
- *state = EST_HORIZONTALQH;
+ ehci_set_state(ehci, async, EST_HORIZONTALQH);
again = 1;
} else if ((qh->token & QTD_TOKEN_ACTIVE) && (qh->current_qtd > 0x1000)) {
- DPRINTF_ST("FETCHQH: Active, !Halt, execute - fetch qTD\n");
ehci->qtdaddr = qh->current_qtd;
- *state = EST_FETCHQTD;
+ ehci_set_state(ehci, async, EST_FETCHQTD);
again = 1;
} else {
/* EHCI spec version 1.0 Section 4.10.2 */
- DPRINTF_ST("FETCHQH: !Active, !Halt, advance queue\n");
- *state = EST_ADVANCEQUEUE;
+ ehci_set_state(ehci, async, EST_ADVANCEQUEUE);
again = 1;
}
@@ -1394,14 +1454,13 @@ out:
return again;
}
-static int ehci_state_fetchitd(EHCIState *ehci, int async, int *state)
+static int ehci_state_fetchitd(EHCIState *ehci, int async)
{
EHCIitd itd;
get_dwords(NLPTR_GET(ehci->itdaddr),(uint32_t *) &itd,
sizeof(EHCIitd) >> 2);
- DPRINTF_ST("FETCHITD: Fetched ITD at address %08X " "(next is %08X)\n",
- ehci->itdaddr, itd.next);
+ ehci_trace_itd(ehci, ehci->itdaddr, &itd);
if (ehci_process_itd(ehci, &itd) != 0) {
return -1;
@@ -1410,13 +1469,13 @@ static int ehci_state_fetchitd(EHCIState *ehci, int async, int *state)
put_dwords(NLPTR_GET(ehci->itdaddr), (uint32_t *) &itd,
sizeof(EHCIitd) >> 2);
ehci->fetch_addr = itd.next;
- *state = EST_FETCHENTRY;
+ ehci_set_state(ehci, async, EST_FETCHENTRY);
return 1;
}
/* Section 4.10.2 - paragraph 3 */
-static int ehci_state_advqueue(EHCIState *ehci, int async, int *state)
+static int ehci_state_advqueue(EHCIState *ehci, int async)
{
#if 0
/* TO-DO: 4.10.2 - paragraph 2
@@ -1424,7 +1483,7 @@ static int ehci_state_advqueue(EHCIState *ehci, int async, int *state)
* go to horizontal QH
*/
if (I-bit set) {
- *state = EST_HORIZONTALQH;
+ ehci_set_state(ehci, async, EST_HORIZONTALQH);
goto out;
}
#endif
@@ -1435,71 +1494,63 @@ static int ehci_state_advqueue(EHCIState *ehci, int async, int *state)
if (((ehci->qh.token & QTD_TOKEN_TBYTES_MASK) != 0) &&
(ehci->qh.altnext_qtd > 0x1000) &&
(NLPTR_TBIT(ehci->qh.altnext_qtd) == 0)) {
- DPRINTF_ST("ADVQUEUE: goto alt next qTD. "
- "curr 0x%08x next 0x%08x alt 0x%08x (next qh %x)\n",
- ehci->qh.current_qtd, ehci->qh.altnext_qtd,
- ehci->qh.next_qtd, ehci->qh.next);
ehci->qtdaddr = ehci->qh.altnext_qtd;
- *state = EST_FETCHQTD;
+ ehci_set_state(ehci, async, EST_FETCHQTD);
/*
* next qTD is valid
*/
} else if ((ehci->qh.next_qtd > 0x1000) &&
(NLPTR_TBIT(ehci->qh.next_qtd) == 0)) {
- DPRINTF_ST("ADVQUEUE: next qTD. "
- "curr 0x%08x next 0x%08x alt 0x%08x (next qh %x)\n",
- ehci->qh.current_qtd, ehci->qh.altnext_qtd,
- ehci->qh.next_qtd, ehci->qh.next);
ehci->qtdaddr = ehci->qh.next_qtd;
- *state = EST_FETCHQTD;
+ ehci_set_state(ehci, async, EST_FETCHQTD);
/*
* no valid qTD, try next QH
*/
} else {
- DPRINTF_ST("ADVQUEUE: go to horizontal QH\n");
- *state = EST_HORIZONTALQH;
+ ehci_set_state(ehci, async, EST_HORIZONTALQH);
}
return 1;
}
/* Section 4.10.2 - paragraph 4 */
-static int ehci_state_fetchqtd(EHCIState *ehci, int async, int *state)
+static int ehci_state_fetchqtd(EHCIState *ehci, int async)
{
EHCIqtd *qtd = &ehci->qtd;
int again = 0;
get_dwords(NLPTR_GET(ehci->qtdaddr),(uint32_t *) qtd, sizeof(EHCIqtd) >> 2);
+ ehci_trace_qtd(ehci, NLPTR_GET(ehci->qtdaddr), qtd);
if (qtd->token & QTD_TOKEN_ACTIVE) {
- *state = EST_EXECUTE;
+ ehci_set_state(ehci, async, EST_EXECUTE);
again = 1;
} else {
- *state = EST_HORIZONTALQH;
+ ehci_set_state(ehci, async, EST_HORIZONTALQH);
again = 1;
}
return again;
}
-static int ehci_state_horizqh(EHCIState *ehci, int async, int *state)
+static int ehci_state_horizqh(EHCIState *ehci, int async)
{
int again = 0;
if (ehci->fetch_addr != ehci->qh.next) {
ehci->fetch_addr = ehci->qh.next;
- *state = EST_FETCHENTRY;
+ ehci_set_state(ehci, async, EST_FETCHENTRY);
again = 1;
} else {
- *state = EST_ACTIVE;
+ ehci_set_state(ehci, async, EST_ACTIVE);
}
return again;
}
-static int ehci_state_execute(EHCIState *ehci, int async, int *state)
+static int ehci_state_execute(EHCIState *ehci, int async)
{
EHCIqh *qh = &ehci->qh;
EHCIqtd *qtd = &ehci->qtd;
@@ -1507,13 +1558,6 @@ static int ehci_state_execute(EHCIState *ehci, int async, int *state)
int reload, nakcnt;
int smask;
- if (async) {
- DPRINTF_ST(">>>>> ASYNC STATE MACHINE execute QH 0x%08x, QTD 0x%08x\n",
- ehci->qhaddr, ehci->qtdaddr);
- } else {
- DPRINTF_ST(">>>>> PERIODIC STATE MACHINE execute\n");
- }
-
if (ehci_qh_do_overlay(ehci, qh, qtd) != 0) {
return -1;
}
@@ -1524,8 +1568,7 @@ static int ehci_state_execute(EHCIState *ehci, int async, int *state)
reload = get_field(qh->epchar, QH_EPCHAR_RL);
nakcnt = get_field(qh->altnext_qtd, QH_ALTNEXT_NAKCNT);
if (reload && !nakcnt) {
- DPRINTF_ST("EXECUTE: RL != 0 but NakCnt == 0 -- no execute\n");
- *state = EST_HORIZONTALQH;
+ ehci_set_state(ehci, async, EST_HORIZONTALQH);
again = 1;
goto out;
}
@@ -1538,8 +1581,7 @@ static int ehci_state_execute(EHCIState *ehci, int async, int *state)
if (!async) {
int transactCtr = get_field(qh->epcap, QH_EPCAP_MULT);
if (!transactCtr) {
- DPRINTF("ZERO transactctr for int qh, go HORIZ\n");
- *state = EST_HORIZONTALQH;
+ ehci_set_state(ehci, async, EST_HORIZONTALQH);
again = 1;
goto out;
}
@@ -1554,7 +1596,7 @@ static int ehci_state_execute(EHCIState *ehci, int async, int *state)
again = -1;
goto out;
}
- *state = EST_EXECUTING;
+ ehci_set_state(ehci, async, EST_EXECUTING);
if (ehci->exec_status != USB_RET_ASYNC) {
again = 1;
@@ -1564,7 +1606,7 @@ out:
return again;
}
-static int ehci_state_executing(EHCIState *ehci, int async, int *state)
+static int ehci_state_executing(EHCIState *ehci, int async)
{
EHCIqh *qh = &ehci->qh;
int again = 0;
@@ -1596,12 +1638,8 @@ static int ehci_state_executing(EHCIState *ehci, int async, int *state)
if (nakcnt) {
nakcnt--;
}
- DPRINTF_ST("EXECUTING: Nak occured and RL != 0, dec NakCnt to %d\n",
- nakcnt);
} else {
nakcnt = reload;
- DPRINTF_ST("EXECUTING: Nak didn't occur, reloading to %d\n",
- nakcnt);
}
set_field(&qh->altnext_qtd, nakcnt, QH_ALTNEXT_NAKCNT);
}
@@ -1611,16 +1649,13 @@ static int ehci_state_executing(EHCIState *ehci, int async, int *state)
* in the EHCI spec but we need to do it since we don't share
* physical memory with our guest VM.
*/
-
- DPRINTF("EXECUTING: write QH to VM memory: qhaddr 0x%x, next 0x%x\n",
- ehci->qhaddr, qh->next);
put_dwords(NLPTR_GET(ehci->qhaddr), (uint32_t *) qh, sizeof(EHCIqh) >> 2);
/* 4.10.5 */
if ((ehci->exec_status == USB_RET_NAK) || (qh->token & QTD_TOKEN_ACTIVE)) {
- *state = EST_HORIZONTALQH;
+ ehci_set_state(ehci, async, EST_HORIZONTALQH);
} else {
- *state = EST_WRITEBACK;
+ ehci_set_state(ehci, async, EST_WRITEBACK);
}
again = 1;
@@ -1630,13 +1665,13 @@ out:
}
-static int ehci_state_writeback(EHCIState *ehci, int async, int *state)
+static int ehci_state_writeback(EHCIState *ehci, int async)
{
EHCIqh *qh = &ehci->qh;
int again = 0;
/* Write back the QTD from the QH area */
- DPRINTF_ST("WRITEBACK: write QTD to VM memory\n");
+ ehci_trace_qtd(ehci, NLPTR_GET(ehci->qtdaddr), (EHCIqtd*) &qh->next_qtd);
put_dwords(NLPTR_GET(ehci->qtdaddr),(uint32_t *) &qh->next_qtd,
sizeof(EHCIqtd) >> 2);
@@ -1644,10 +1679,10 @@ static int ehci_state_writeback(EHCIState *ehci, int async, int *state)
* but stop after one qtd if periodic
*/
//if (async) {
- *state = EST_ADVANCEQUEUE;
+ ehci_set_state(ehci, async, EST_ADVANCEQUEUE);
again = 1;
//} else {
- // *state = EST_ACTIVE;
+ // ehci_set_state(ehci, async, EST_ACTIVE);
//}
return again;
}
@@ -1656,15 +1691,14 @@ static int ehci_state_writeback(EHCIState *ehci, int async, int *state)
* This is the state machine that is common to both async and periodic
*/
-static int ehci_advance_state(EHCIState *ehci,
- int async,
- int state)
+static void ehci_advance_state(EHCIState *ehci,
+ int async)
{
int again;
int iter = 0;
do {
- if (state == EST_FETCHQH) {
+ if (ehci_get_state(ehci, async) == EST_FETCHQH) {
iter++;
/* if we are roaming a lot of QH without executing a qTD
* something is wrong with the linked list. TO-DO: why is
@@ -1672,50 +1706,50 @@ static int ehci_advance_state(EHCIState *ehci,
*/
if (iter > MAX_ITERATIONS) {
DPRINTF("\n*** advance_state: bailing on MAX ITERATIONS***\n");
- state = EST_ACTIVE;
+ ehci_set_state(ehci, async, EST_ACTIVE);
break;
}
}
- switch(state) {
+ switch(ehci_get_state(ehci, async)) {
case EST_WAITLISTHEAD:
- again = ehci_state_waitlisthead(ehci, async, &state);
+ again = ehci_state_waitlisthead(ehci, async);
break;
case EST_FETCHENTRY:
- again = ehci_state_fetchentry(ehci, async, &state);
+ again = ehci_state_fetchentry(ehci, async);
break;
case EST_FETCHQH:
- again = ehci_state_fetchqh(ehci, async, &state);
+ again = ehci_state_fetchqh(ehci, async);
break;
case EST_FETCHITD:
- again = ehci_state_fetchitd(ehci, async, &state);
+ again = ehci_state_fetchitd(ehci, async);
break;
case EST_ADVANCEQUEUE:
- again = ehci_state_advqueue(ehci, async, &state);
+ again = ehci_state_advqueue(ehci, async);
break;
case EST_FETCHQTD:
- again = ehci_state_fetchqtd(ehci, async, &state);
+ again = ehci_state_fetchqtd(ehci, async);
break;
case EST_HORIZONTALQH:
- again = ehci_state_horizqh(ehci, async, &state);
+ again = ehci_state_horizqh(ehci, async);
break;
case EST_EXECUTE:
iter = 0;
- again = ehci_state_execute(ehci, async, &state);
+ again = ehci_state_execute(ehci, async);
break;
case EST_EXECUTING:
- again = ehci_state_executing(ehci, async, &state);
+ again = ehci_state_executing(ehci, async);
break;
case EST_WRITEBACK:
- again = ehci_state_writeback(ehci, async, &state);
+ again = ehci_state_writeback(ehci, async);
break;
default:
@@ -1733,27 +1767,26 @@ static int ehci_advance_state(EHCIState *ehci,
while (again);
ehci_commit_interrupt(ehci);
- return state;
}
static void ehci_advance_async_state(EHCIState *ehci)
{
EHCIqh qh;
- int state = ehci->astate;
+ int async = 1;
- switch(state) {
+ switch(ehci_get_state(ehci, async)) {
case EST_INACTIVE:
if (!(ehci->usbcmd & USBCMD_ASE)) {
break;
}
ehci_set_usbsts(ehci, USBSTS_ASS);
- ehci->astate = EST_ACTIVE;
+ ehci_set_state(ehci, async, EST_ACTIVE);
// No break, fall through to ACTIVE
case EST_ACTIVE:
if ( !(ehci->usbcmd & USBCMD_ASE)) {
ehci_clear_usbsts(ehci, USBSTS_ASS);
- ehci->astate = EST_INACTIVE;
+ ehci_set_state(ehci, async, EST_INACTIVE);
break;
}
@@ -1775,14 +1808,12 @@ static void ehci_advance_async_state(EHCIState *ehci)
break;
}
- DPRINTF_ST("ASYNC: waiting for listhead, starting at %08x\n",
- ehci->asynclistaddr);
/* check that address register has been set */
if (ehci->asynclistaddr == 0) {
break;
}
- state = EST_WAITLISTHEAD;
+ ehci_set_state(ehci, async, EST_WAITLISTHEAD);
/* fall through */
case EST_FETCHENTRY:
@@ -1791,14 +1822,14 @@ static void ehci_advance_async_state(EHCIState *ehci)
case EST_EXECUTING:
get_dwords(NLPTR_GET(ehci->qhaddr), (uint32_t *) &qh,
sizeof(EHCIqh) >> 2);
- ehci->astate = ehci_advance_state(ehci, 1, state);
+ ehci_advance_state(ehci, async);
break;
default:
/* this should only be due to a developer mistake */
fprintf(stderr, "ehci: Bad asynchronous state %d. "
"Resetting to active\n", ehci->astate);
- ehci->astate = EST_ACTIVE;
+ ehci_set_state(ehci, async, EST_ACTIVE);
}
}
@@ -1806,14 +1837,15 @@ static void ehci_advance_periodic_state(EHCIState *ehci)
{
uint32_t entry;
uint32_t list;
+ int async = 0;
// 4.6
- switch(ehci->pstate) {
+ switch(ehci_get_state(ehci, async)) {
case EST_INACTIVE:
if ( !(ehci->frindex & 7) && (ehci->usbcmd & USBCMD_PSE)) {
ehci_set_usbsts(ehci, USBSTS_PSS);
- ehci->pstate = EST_ACTIVE;
+ ehci_set_state(ehci, async, EST_ACTIVE);
// No break, fall through to ACTIVE
} else
break;
@@ -1821,7 +1853,7 @@ static void ehci_advance_periodic_state(EHCIState *ehci)
case EST_ACTIVE:
if ( !(ehci->frindex & 7) && !(ehci->usbcmd & USBCMD_PSE)) {
ehci_clear_usbsts(ehci, USBSTS_PSS);
- ehci->pstate = EST_INACTIVE;
+ ehci_set_state(ehci, async, EST_INACTIVE);
break;
}
@@ -1838,19 +1870,20 @@ static void ehci_advance_periodic_state(EHCIState *ehci)
DPRINTF("PERIODIC state adv fr=%d. [%08X] -> %08X\n",
ehci->frindex / 8, list, entry);
ehci->fetch_addr = entry;
- ehci->pstate = ehci_advance_state(ehci, 0, EST_FETCHENTRY);
+ ehci_set_state(ehci, async, EST_FETCHENTRY);
+ ehci_advance_state(ehci, async);
break;
case EST_EXECUTING:
DPRINTF("PERIODIC state adv for executing\n");
- ehci->pstate = ehci_advance_state(ehci, 0, EST_EXECUTING);
+ ehci_advance_state(ehci, async);
break;
default:
/* this should only be due to a developer mistake */
fprintf(stderr, "ehci: Bad periodic state %d. "
"Resetting to active\n", ehci->pstate);
- ehci->pstate = EST_ACTIVE;
+ ehci_set_state(ehci, async, EST_ACTIVE);
}
}
@@ -1896,7 +1929,7 @@ static void ehci_frame_timer(void *opaque)
} else {
// TODO could this cause periodic frames to get skipped if async
// active?
- if (ehci->astate != EST_EXECUTING) {
+ if (ehci_get_state(ehci, 1) != EST_EXECUTING) {
ehci_advance_periodic_state(ehci);
}
}
@@ -1913,7 +1946,7 @@ static void ehci_frame_timer(void *opaque)
/* Async is not inside loop since it executes everything it can once
* called
*/
- if (ehci->pstate != EST_EXECUTING) {
+ if (ehci_get_state(ehci, 0) != EST_EXECUTING) {
ehci_advance_async_state(ehci);
}
diff --git a/trace-events b/trace-events
index c87a86ef35..2b89d0fad4 100644
--- a/trace-events
+++ b/trace-events
@@ -199,6 +199,10 @@ disable usb_ehci_reset(void) "=== RESET ==="
disable usb_ehci_mmio_readl(uint32_t addr, const char *str, uint32_t val) "rd mmio %04x [%s] = %x"
disable usb_ehci_mmio_writel(uint32_t addr, const char *str, uint32_t val, uint32_t oldval) "wr mmio %04x [%s] = %x (old: %x)"
disable usb_ehci_usbsts(const char *sts, int state) "usbsts %s %d"
+disable usb_ehci_state(const char *schedule, const char *state) "%s schedule %s"
+disable usb_ehci_qh(uint32_t addr, uint32_t next, uint32_t c_qtd, uint32_t n_qtd, uint32_t a_qtd, int rl, int mplen, int eps, int ep, int devaddr, int c, int h, int dtc, int i) "QH @ %08x: next %08x qtds %08x,%08x,%08x - rl %d, mplen %d, eps %d, ep %d, dev %d, c %d, h %d, dtc %d, i %d"
+disable usb_ehci_qtd(uint32_t addr, uint32_t next, uint32_t altnext, int tbytes, int cpage, int cerr, int pid, int ioc, int active, int halt, int babble, int xacterr) "QH @ %08x: next %08x altnext %08x - tbytes %d, cpage %d, cerr %d, pid %d, ioc %d, active %d, halt %d, babble %d, xacterr %d"
+disable usb_ehci_itd(uint32_t addr, uint32_t next) "ITD @ %08x: next %08x"
# hw/usb-desc.c
disable usb_desc_device(int addr, int len, int ret) "dev %d query device, len %d, ret %d"