Patchwork [07/12] uhci: Add support for input queuing

login
register
mail settings
Submitter Hans de Goede
Date Oct. 8, 2012, 7:51 a.m.
Message ID <1349682696-3046-8-git-send-email-hdegoede@redhat.com>
Download mbox | patch
Permalink /patch/189943/
State New
Headers show

Comments

Hans de Goede - Oct. 8, 2012, 7:51 a.m.
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
---
 hw/usb/hcd-uhci.c | 31 +++++++++++++++++++++++++------
 1 file changed, 25 insertions(+), 6 deletions(-)

Patch

diff --git a/hw/usb/hcd-uhci.c b/hw/usb/hcd-uhci.c
index 124d43a..63f2161 100644
--- a/hw/usb/hcd-uhci.c
+++ b/hw/usb/hcd-uhci.c
@@ -678,6 +678,13 @@  static void uhci_wakeup(USBPort *port1)
     }
 }
 
+static void uhci_remove_from_queue(USBPort *port, USBPacket *p)
+{
+    UHCIAsync *async = DO_UPCAST(UHCIAsync, packet, p);
+    uhci_async_unlink(async);
+    uhci_async_cancel(async);
+}
+
 static USBDevice *uhci_find_device(UHCIState *s, uint8_t addr)
 {
     USBDevice *dev;
@@ -818,7 +825,8 @@  out:
 }
 
 static int uhci_handle_td(UHCIState *s, uint32_t addr, UHCI_TD *td,
-                          uint32_t *int_mask, bool queuing)
+                          uint32_t *int_mask, bool queuing,
+                          struct USBEndpoint **ep_ret)
 {
     UHCIAsync *async;
     int len = 0, max_len;
@@ -862,6 +870,9 @@  static int uhci_handle_td(UHCIState *s, uint32_t addr, UHCI_TD *td,
 
     dev = uhci_find_device(s, (td->token >> 8) & 0x7f);
     ep = usb_ep_get(dev, pid, (td->token >> 15) & 0xf);
+    if (ep_ret) {
+        *ep_ret = ep;
+    }
     usb_packet_setup(&async->packet, pid, ep, addr);
     qemu_sglist_add(&async->sgl, td->buffer, max_len);
     usb_packet_map(&async->packet, &async->sgl);
@@ -875,6 +886,8 @@  static int uhci_handle_td(UHCIState *s, uint32_t addr, UHCI_TD *td,
         break;
 
     case USB_TOKEN_IN:
+        async->packet.short_not_ok = ((td->ctrl & TD_CTRL_SPD) != 0);
+        async->packet.int_req = ((td->ctrl & TD_CTRL_IOC) != 0);
         len = usb_handle_packet(dev, &async->packet);
         break;
 
@@ -975,7 +988,7 @@  static int qhdb_insert(QhDb *db, uint32_t addr)
     return 0;
 }
 
-static void uhci_fill_queue(UHCIState *s, UHCI_TD *td)
+static void uhci_fill_queue(UHCIState *s, UHCI_TD *td, struct USBEndpoint *ep)
 {
     uint32_t int_mask = 0;
     uint32_t plink = td->link;
@@ -984,7 +997,8 @@  static void uhci_fill_queue(UHCIState *s, UHCI_TD *td)
     int ret;
 
     ptd.ctrl = td->ctrl;
-    while (is_valid(plink) && !(ptd.ctrl & TD_CTRL_SPD)) {
+    while (is_valid(plink) &&
+            (usb_ep_input_pipeline(ep) || !(ptd.ctrl & TD_CTRL_SPD))) {
         pci_dma_read(&s->dev, plink & ~0xf, &ptd, sizeof(ptd));
         le32_to_cpus(&ptd.link);
         le32_to_cpus(&ptd.ctrl);
@@ -997,7 +1011,7 @@  static void uhci_fill_queue(UHCIState *s, UHCI_TD *td)
             break;
         }
         trace_usb_uhci_td_queue(plink & ~0xf, ptd.ctrl, ptd.token);
-        ret = uhci_handle_td(s, plink, &ptd, &int_mask, true);
+        ret = uhci_handle_td(s, plink, &ptd, &int_mask, true, NULL);
         if (ret == TD_RESULT_ASYNC_CONT) {
             break;
         }
@@ -1005,12 +1019,14 @@  static void uhci_fill_queue(UHCIState *s, UHCI_TD *td)
         assert(int_mask == 0);
         plink = ptd.link;
     }
+    usb_ep_process_queue(ep);
 }
 
 static void uhci_process_frame(UHCIState *s)
 {
     uint32_t frame_addr, link, old_td_ctrl, val, int_mask;
     uint32_t curr_qh, td_count = 0;
+    struct USBEndpoint *curr_ep;
     int cnt, ret;
     UHCI_TD td;
     UHCI_QH qh;
@@ -1081,7 +1097,7 @@  static void uhci_process_frame(UHCIState *s)
         trace_usb_uhci_td_load(curr_qh & ~0xf, link & ~0xf, td.ctrl, td.token);
 
         old_td_ctrl = td.ctrl;
-        ret = uhci_handle_td(s, link, &td, &int_mask, false);
+        ret = uhci_handle_td(s, link, &td, &int_mask, false, &curr_ep);
         if (old_td_ctrl != td.ctrl) {
             /* update the status bits of the TD */
             val = cpu_to_le32(td.ctrl);
@@ -1100,7 +1116,7 @@  static void uhci_process_frame(UHCIState *s)
 
         case TD_RESULT_ASYNC_START:
             trace_usb_uhci_td_async(curr_qh & ~0xf, link & ~0xf);
-            uhci_fill_queue(s, &td);
+            uhci_fill_queue(s, &td, curr_ep);
             link = curr_qh ? qh.link : td.link;
             continue;
 
@@ -1202,6 +1218,7 @@  static USBPortOps uhci_port_ops = {
     .child_detach = uhci_child_detach,
     .wakeup = uhci_wakeup,
     .complete = uhci_async_complete,
+    .remove_from_queue = uhci_remove_from_queue,
 };
 
 static USBBusOps uhci_bus_ops = {
@@ -1238,6 +1255,7 @@  static int usb_uhci_common_initfn(PCIDevice *dev)
         USBPort *ports[NB_PORTS];
         for(i = 0; i < NB_PORTS; i++) {
             ports[i] = &s->ports[i].port;
+            ports[i]->supports_queuing = true;
         }
         if (usb_register_companion(s->masterbus, ports, NB_PORTS,
                 s->firstport, s, &uhci_port_ops,
@@ -1247,6 +1265,7 @@  static int usb_uhci_common_initfn(PCIDevice *dev)
     } else {
         usb_bus_new(&s->bus, &uhci_bus_ops, &s->dev.qdev);
         for (i = 0; i < NB_PORTS; i++) {
+            s->ports[i].port.supports_queuing = true;
             usb_register_port(&s->bus, &s->ports[i].port, s, i, &uhci_port_ops,
                               USB_SPEED_MASK_LOW | USB_SPEED_MASK_FULL);
         }