Revision 66f092d2 hw/usb/hcd-ehci.c
b/hw/usb/hcd-ehci.c | ||
---|---|---|
365 | 365 |
uint32_t seen; |
366 | 366 |
uint64_t ts; |
367 | 367 |
int async; |
368 |
int revalidate; |
|
369 | 368 |
|
370 | 369 |
/* cached data from guest - needs to be flushed |
371 | 370 |
* when guest removes an entry (doorbell, handshake sequence) |
... | ... | |
805 | 804 |
return NULL; |
806 | 805 |
} |
807 | 806 |
|
808 |
static void ehci_queues_tag_unused_async(EHCIState *ehci) |
|
809 |
{ |
|
810 |
EHCIQueue *q; |
|
811 |
|
|
812 |
QTAILQ_FOREACH(q, &ehci->aqueues, next) { |
|
813 |
if (!q->seen) { |
|
814 |
q->revalidate = 1; |
|
815 |
} |
|
816 |
} |
|
817 |
} |
|
818 |
|
|
819 |
static void ehci_queues_rip_unused(EHCIState *ehci, int async) |
|
807 |
static void ehci_queues_rip_unused(EHCIState *ehci, int async, int flush) |
|
820 | 808 |
{ |
821 | 809 |
EHCIQueueHead *head = async ? &ehci->aqueues : &ehci->pqueues; |
822 | 810 |
uint64_t maxage = FRAME_TIMER_NS * ehci->maxframes * 4; |
... | ... | |
828 | 816 |
q->ts = ehci->last_run_ns; |
829 | 817 |
continue; |
830 | 818 |
} |
831 |
if (ehci->last_run_ns < q->ts + maxage) { |
|
819 |
if (!flush && ehci->last_run_ns < q->ts + maxage) {
|
|
832 | 820 |
continue; |
833 | 821 |
} |
834 | 822 |
ehci_free_queue(q); |
... | ... | |
1684 | 1672 |
ehci_set_usbsts(ehci, USBSTS_REC); |
1685 | 1673 |
} |
1686 | 1674 |
|
1687 |
ehci_queues_rip_unused(ehci, async); |
|
1675 |
ehci_queues_rip_unused(ehci, async, 0);
|
|
1688 | 1676 |
|
1689 | 1677 |
/* Find the head of the list (4.9.1.1) */ |
1690 | 1678 |
for(i = 0; i < MAX_QH; i++) { |
... | ... | |
1769 | 1757 |
EHCIPacket *p; |
1770 | 1758 |
uint32_t entry, devaddr; |
1771 | 1759 |
EHCIQueue *q; |
1772 |
EHCIqh qh; |
|
1773 | 1760 |
|
1774 | 1761 |
entry = ehci_get_fetch_addr(ehci, async); |
1775 | 1762 |
q = ehci_find_queue_by_qh(ehci, entry, async); |
... | ... | |
1787 | 1774 |
} |
1788 | 1775 |
|
1789 | 1776 |
get_dwords(ehci, NLPTR_GET(q->qhaddr), |
1790 |
(uint32_t *) &qh, sizeof(EHCIqh) >> 2); |
|
1791 |
if (q->revalidate && (q->qh.epchar != qh.epchar || |
|
1792 |
q->qh.epcap != qh.epcap || |
|
1793 |
q->qh.current_qtd != qh.current_qtd)) { |
|
1794 |
ehci_free_queue(q); |
|
1795 |
q = ehci_alloc_queue(ehci, entry, async); |
|
1796 |
q->seen++; |
|
1797 |
p = NULL; |
|
1798 |
} |
|
1799 |
q->qh = qh; |
|
1800 |
q->revalidate = 0; |
|
1777 |
(uint32_t *) &q->qh, sizeof(EHCIqh) >> 2); |
|
1801 | 1778 |
ehci_trace_qh(q, NLPTR_GET(q->qhaddr), &q->qh); |
1802 | 1779 |
|
1803 | 1780 |
devaddr = get_field(q->qh.epchar, QH_EPCHAR_DEVADDR); |
... | ... | |
2306 | 2283 |
*/ |
2307 | 2284 |
if (ehci->usbcmd & USBCMD_IAAD) { |
2308 | 2285 |
/* Remove all unseen qhs from the async qhs queue */ |
2309 |
ehci_queues_tag_unused_async(ehci);
|
|
2286 |
ehci_queues_rip_unused(ehci, async, 1);
|
|
2310 | 2287 |
DPRINTF("ASYNC: doorbell request acknowledged\n"); |
2311 | 2288 |
ehci->usbcmd &= ~USBCMD_IAAD; |
2312 | 2289 |
ehci_raise_irq(ehci, USBSTS_IAA); |
... | ... | |
2359 | 2336 |
ehci_set_fetch_addr(ehci, async,entry); |
2360 | 2337 |
ehci_set_state(ehci, async, EST_FETCHENTRY); |
2361 | 2338 |
ehci_advance_state(ehci, async); |
2362 |
ehci_queues_rip_unused(ehci, async); |
|
2339 |
ehci_queues_rip_unused(ehci, async, 0);
|
|
2363 | 2340 |
break; |
2364 | 2341 |
|
2365 | 2342 |
default: |
Also available in: Unified diff