aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGerd Hoffmann <kraxel@redhat.com>2012-05-10 12:18:45 +0200
committerGerd Hoffmann <kraxel@redhat.com>2012-06-07 10:02:22 +0200
commite59928b3d148f97658e804fa724cdaa75dc8935a (patch)
treeb7e3f0875c0db96f0358394a54edf9ee2f3da857
parent4224558f87371f87929df1064ddb733104fe5f15 (diff)
ehci: cache USBDevice in EHCIQueue
Keep a USBDevice pointer in EHCIQueue so we don't have to lookup the device on each usb packet submission. Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
-rw-r--r--hw/usb/hcd-ehci.c31
1 files changed, 19 insertions, 12 deletions
diff --git a/hw/usb/hcd-ehci.c b/hw/usb/hcd-ehci.c
index a7cf2820af..d7131bd4d1 100644
--- a/hw/usb/hcd-ehci.c
+++ b/hw/usb/hcd-ehci.c
@@ -371,6 +371,7 @@ struct EHCIQueue {
EHCIqh qh; /* copy of current QH (being worked on) */
uint32_t qhaddr; /* address QH read from */
uint32_t qtdaddr; /* address QTD read from */
+ USBDevice *dev;
QTAILQ_HEAD(, EHCIPacket) packets;
};
@@ -758,11 +759,9 @@ static void ehci_queues_rip_device(EHCIState *ehci, USBDevice *dev, int async)
{
EHCIQueueHead *head = async ? &ehci->aqueues : &ehci->pqueues;
EHCIQueue *q, *tmp;
- int addr;
QTAILQ_FOREACH_SAFE(q, head, next, tmp) {
- addr = get_field(q->qh.epchar, QH_EPCHAR_DEVADDR);
- if (addr != dev->addr) {
+ if (q->dev != dev) {
continue;
}
ehci_free_queue(q, async);
@@ -1397,11 +1396,9 @@ static void ehci_execute_complete(EHCIQueue *q)
static int ehci_execute(EHCIPacket *p)
{
- USBDevice *dev;
USBEndpoint *ep;
int ret;
int endp;
- int devadr;
if (!(p->qtd.token & QTD_TOKEN_ACTIVE)) {
fprintf(stderr, "Attempting to execute inactive qtd\n");
@@ -1435,16 +1432,12 @@ static int ehci_execute(EHCIPacket *p)
}
endp = get_field(p->queue->qh.epchar, QH_EPCHAR_EP);
- devadr = get_field(p->queue->qh.epchar, QH_EPCHAR_DEVADDR);
-
- /* TODO: associating device with ehci port */
- dev = ehci_find_device(p->queue->ehci, devadr);
- ep = usb_ep_get(dev, p->pid, endp);
+ ep = usb_ep_get(p->queue->dev, p->pid, endp);
usb_packet_setup(&p->packet, p->pid, ep);
usb_packet_map(&p->packet, &p->sgl);
- ret = usb_handle_packet(dev, &p->packet);
+ ret = usb_handle_packet(p->queue->dev, &p->packet);
DPRINTF("submit: qh %x next %x qtd %x pid %x len %zd "
"(total %d) endp %x ret %d\n",
q->qhaddr, q->qh.next, q->qtdaddr, q->pid,
@@ -1658,7 +1651,7 @@ out:
static EHCIQueue *ehci_state_fetchqh(EHCIState *ehci, int async)
{
EHCIPacket *p;
- uint32_t entry;
+ uint32_t entry, devaddr;
EHCIQueue *q;
entry = ehci_get_fetch_addr(ehci, async);
@@ -1681,6 +1674,20 @@ static EHCIQueue *ehci_state_fetchqh(EHCIState *ehci, int async)
(uint32_t *) &q->qh, sizeof(EHCIqh) >> 2);
ehci_trace_qh(q, NLPTR_GET(q->qhaddr), &q->qh);
+ devaddr = get_field(q->qh.epchar, QH_EPCHAR_DEVADDR);
+ if (q->dev != NULL && q->dev->addr != devaddr) {
+ if (!QTAILQ_EMPTY(&q->packets)) {
+ /* should not happen (guest bug) */
+ while ((p = QTAILQ_FIRST(&q->packets)) != NULL) {
+ ehci_free_packet(p);
+ }
+ }
+ q->dev = NULL;
+ }
+ if (q->dev == NULL) {
+ q->dev = ehci_find_device(q->ehci, devaddr);
+ }
+
if (p && p->async == EHCI_ASYNC_INFLIGHT) {
/* I/O still in progress -- skip queue */
ehci_set_state(ehci, async, EST_HORIZONTALQH);