5544c1b
From 82b29b635d26ad0f5e14fabdf0956e9b8e7dbbfb Mon Sep 17 00:00:00 2001
c8dfc65
From: Gerd Hoffmann <kraxel@redhat.com>
c8dfc65
Date: Fri, 31 Aug 2012 10:44:21 +0200
5544c1b
Subject: [PATCH] ehci: trace guest bugs
c8dfc65
c8dfc65
make qemu_queue_{cancel,reset} return the number of packets released,
c8dfc65
so the caller can figure whenever there have been active packets even
c8dfc65
though there shouldn't have been any.  Add tracepoint to log this.
c8dfc65
c8dfc65
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
5544c1b
(cherry picked from commit 5c514681abbb3ae2f61f517c1aa3197f2f3ca93c)
5544c1b
5544c1b
Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
c8dfc65
---
c8dfc65
 hw/usb/hcd-ehci.c | 26 ++++++++++++++++++++------
c8dfc65
 trace-events      |  1 +
c8dfc65
 2 files changed, 21 insertions(+), 6 deletions(-)
c8dfc65
c8dfc65
diff --git a/hw/usb/hcd-ehci.c b/hw/usb/hcd-ehci.c
c8dfc65
index 23221d0..4564615 100644
c8dfc65
--- a/hw/usb/hcd-ehci.c
c8dfc65
+++ b/hw/usb/hcd-ehci.c
c8dfc65
@@ -716,6 +716,12 @@ static void ehci_trace_sitd(EHCIState *s, target_phys_addr_t addr,
c8dfc65
                         (bool)(sitd->results & SITD_RESULTS_ACTIVE));
c8dfc65
 }
c8dfc65
 
c8dfc65
+static void ehci_trace_guest_bug(EHCIState *s, const char *message)
c8dfc65
+{
c8dfc65
+    trace_usb_ehci_guest_bug(message);
c8dfc65
+    fprintf(stderr, "ehci warning: %s\n", message);
c8dfc65
+}
c8dfc65
+
c8dfc65
 static inline bool ehci_enabled(EHCIState *s)
c8dfc65
 {
c8dfc65
     return s->usbcmd & USBCMD_RUNSTOP;
c8dfc65
@@ -785,27 +791,33 @@ static EHCIQueue *ehci_alloc_queue(EHCIState *ehci, uint32_t addr, int async)
c8dfc65
     return q;
c8dfc65
 }
c8dfc65
 
c8dfc65
-static void ehci_cancel_queue(EHCIQueue *q)
c8dfc65
+static int ehci_cancel_queue(EHCIQueue *q)
c8dfc65
 {
c8dfc65
     EHCIPacket *p;
c8dfc65
+    int packets = 0;
c8dfc65
 
c8dfc65
     p = QTAILQ_FIRST(&q->packets);
c8dfc65
     if (p == NULL) {
c8dfc65
-        return;
c8dfc65
+        return 0;
c8dfc65
     }
c8dfc65
 
c8dfc65
     trace_usb_ehci_queue_action(q, "cancel");
c8dfc65
     do {
c8dfc65
         ehci_free_packet(p);
c8dfc65
+        packets++;
c8dfc65
     } while ((p = QTAILQ_FIRST(&q->packets)) != NULL);
c8dfc65
+    return packets;
c8dfc65
 }
c8dfc65
 
c8dfc65
-static void ehci_reset_queue(EHCIQueue *q)
c8dfc65
+static int ehci_reset_queue(EHCIQueue *q)
c8dfc65
 {
c8dfc65
+    int packets;
c8dfc65
+
c8dfc65
     trace_usb_ehci_queue_action(q, "reset");
c8dfc65
-    ehci_cancel_queue(q);
c8dfc65
+    packets = ehci_cancel_queue(q);
c8dfc65
     q->dev = NULL;
c8dfc65
     q->qtdaddr = 0;
c8dfc65
+    return packets;
c8dfc65
 }
c8dfc65
 
c8dfc65
 static void ehci_free_queue(EHCIQueue *q)
c8dfc65
@@ -1817,7 +1829,9 @@ static EHCIQueue *ehci_state_fetchqh(EHCIState *ehci, int async)
c8dfc65
         (memcmp(&qh.current_qtd, &q->qh.current_qtd,
c8dfc65
                                  9 * sizeof(uint32_t)) != 0) ||
c8dfc65
         (q->dev != NULL && q->dev->addr != devaddr)) {
c8dfc65
-        ehci_reset_queue(q);
c8dfc65
+        if (ehci_reset_queue(q) > 0) {
c8dfc65
+            ehci_trace_guest_bug(ehci, "guest updated active QH");
c8dfc65
+        }
c8dfc65
         p = NULL;
c8dfc65
     }
c8dfc65
     q->qh = qh;
c8dfc65
@@ -1979,8 +1993,8 @@ static int ehci_state_fetchqtd(EHCIQueue *q)
c8dfc65
             (!NLPTR_TBIT(p->qtd.next) && (p->qtd.next != qtd.next)) ||
c8dfc65
             (!NLPTR_TBIT(p->qtd.altnext) && (p->qtd.altnext != qtd.altnext)) ||
c8dfc65
             p->qtd.bufptr[0] != qtd.bufptr[0]) {
c8dfc65
-            /* guest bug: guest updated active QH or qTD underneath us */
c8dfc65
             ehci_cancel_queue(q);
c8dfc65
+            ehci_trace_guest_bug(q->ehci, "guest updated active QH or qTD");
c8dfc65
             p = NULL;
c8dfc65
         } else {
c8dfc65
             p->qtd = qtd;
c8dfc65
diff --git a/trace-events b/trace-events
c8dfc65
index 8fcbc50..5112a47 100644
c8dfc65
--- a/trace-events
c8dfc65
+++ b/trace-events
c8dfc65
@@ -263,6 +263,7 @@ usb_ehci_data(int rw, uint32_t cpage, uint32_t offset, uint32_t addr, uint32_t l
c8dfc65
 usb_ehci_queue_action(void *q, const char *action) "q %p: %s"
c8dfc65
 usb_ehci_packet_action(void *q, void *p, const char *action) "q %p p %p: %s"
c8dfc65
 usb_ehci_irq(uint32_t level, uint32_t frindex, uint32_t sts, uint32_t mask) "level %d, frindex 0x%04x, sts 0x%x, mask 0x%x"
c8dfc65
+usb_ehci_guest_bug(const char *reason) "%s"
c8dfc65
 
c8dfc65
 # hw/usb/hcd-uhci.c
c8dfc65
 usb_uhci_reset(void) "=== RESET ==="