[SeaBIOS] [PATCH 03/19] Batch free USB pipes on EHCI controllers.

Kevin O'Connor kevin at koconnor.net
Sun Mar 11 03:42:25 CET 2012


Instead of unregistering each control "endpoint descriptor" after it
is used, keep them around for later users.  Free all unused
descriptors in one batch at the end of initialization.  This should
slightly optimize boot time, and it requires less overall interaction
with the controller.

This also merges the code that allocates the control and bulk pipes,
as they were quite similar before.

Signed-off-by: Kevin O'Connor <kevin at koconnor.net>
---
 src/usb-ehci.c |  224 ++++++++++++++++++++++++++++++--------------------------
 1 files changed, 119 insertions(+), 105 deletions(-)

diff --git a/src/usb-ehci.c b/src/usb-ehci.c
index 9bdd638..2978072 100644
--- a/src/usb-ehci.c
+++ b/src/usb-ehci.c
@@ -26,6 +26,14 @@ struct usb_ehci_s {
     int legacycount;
 };
 
+struct ehci_pipe {
+    struct ehci_qh qh;
+    struct ehci_qtd *next_td, *tds;
+    void *data;
+    struct usb_pipe pipe;
+    u8 iscontrol;
+};
+
 
 /****************************************************************
  * Root hub
@@ -169,6 +177,76 @@ check_ehci_ports(struct usb_ehci_s *cntl)
  * Setup
  ****************************************************************/
 
+// Wait for next USB async frame to start - for ensuring safe memory release.
+static void
+ehci_waittick(struct usb_ehci_s *cntl)
+{
+    if (MODE16) {
+        msleep(10);
+        return;
+    }
+    // Wait for access to "doorbell"
+    barrier();
+    u32 cmd, sts;
+    u64 end = calc_future_tsc(100);
+    for (;;) {
+        sts = readl(&cntl->regs->usbsts);
+        if (!(sts & STS_IAA)) {
+            cmd = readl(&cntl->regs->usbcmd);
+            if (!(cmd & CMD_IAAD))
+                break;
+        }
+        if (check_tsc(end)) {
+            warn_timeout();
+            return;
+        }
+        yield();
+    }
+    // Ring "doorbell"
+    writel(&cntl->regs->usbcmd, cmd | CMD_IAAD);
+    // Wait for completion
+    for (;;) {
+        sts = readl(&cntl->regs->usbsts);
+        if (sts & STS_IAA)
+            break;
+        if (check_tsc(end)) {
+            warn_timeout();
+            return;
+        }
+        yield();
+    }
+    // Ack completion
+    writel(&cntl->regs->usbsts, STS_IAA);
+}
+
+static void
+ehci_free_pipes(struct usb_ehci_s *cntl)
+{
+    dprintf(7, "ehci_free_pipes %p\n", cntl);
+
+    struct ehci_qh *start = cntl->async_qh;
+    struct ehci_qh *pos = start;
+    for (;;) {
+        struct ehci_qh *next = (void*)(pos->next & ~EHCI_PTR_BITS);
+        if (next == start)
+            break;
+        struct ehci_pipe *pipe = container_of(next, struct ehci_pipe, qh);
+        if (pipe->pipe.cntl != &cntl->usb)
+            pos->next = next->next;
+        else
+            pos = next;
+    }
+    ehci_waittick(cntl);
+    for (;;) {
+        struct usb_pipe *usbpipe = cntl->usb.freelist;
+        if (!usbpipe)
+            break;
+        cntl->usb.freelist = usbpipe->freenext;
+        struct ehci_pipe *pipe = container_of(usbpipe, struct ehci_pipe, pipe);
+        free(pipe);
+    }
+}
+
 static void
 configure_ehci(void *data)
 {
@@ -233,6 +311,7 @@ configure_ehci(void *data)
     // Find devices
     int count = check_ehci_ports(cntl);
     free_pipe(cntl->usb.defaultpipe);
+    ehci_free_pipes(cntl);
     if (count)
         // Success
         return;
@@ -303,55 +382,6 @@ ehci_init(struct pci_device *pci, int busid, struct pci_device *comppci)
  * End point communication
  ****************************************************************/
 
-struct ehci_pipe {
-    struct ehci_qh qh;
-    struct ehci_qtd *next_td, *tds;
-    void *data;
-    struct usb_pipe pipe;
-};
-
-// Wait for next USB async frame to start - for ensuring safe memory release.
-static void
-ehci_waittick(struct usb_ehci_s *cntl)
-{
-    if (MODE16) {
-        msleep(10);
-        return;
-    }
-    // Wait for access to "doorbell"
-    barrier();
-    u32 cmd, sts;
-    u64 end = calc_future_tsc(100);
-    for (;;) {
-        sts = readl(&cntl->regs->usbsts);
-        if (!(sts & STS_IAA)) {
-            cmd = readl(&cntl->regs->usbcmd);
-            if (!(cmd & CMD_IAAD))
-                break;
-        }
-        if (check_tsc(end)) {
-            warn_timeout();
-            return;
-        }
-        yield();
-    }
-    // Ring "doorbell"
-    writel(&cntl->regs->usbcmd, cmd | CMD_IAAD);
-    // Wait for completion
-    for (;;) {
-        sts = readl(&cntl->regs->usbsts);
-        if (sts & STS_IAA)
-            break;
-        if (check_tsc(end)) {
-            warn_timeout();
-            return;
-        }
-        yield();
-    }
-    // Ack completion
-    writel(&cntl->regs->usbsts, STS_IAA);
-}
-
 static void
 ehci_reset_pipe(struct ehci_pipe *pipe)
 {
@@ -394,45 +424,44 @@ ehci_wait_td(struct ehci_pipe *pipe, struct ehci_qtd *td, int timeout)
 }
 
 void
-ehci_free_pipe(struct usb_pipe *p)
+ehci_free_pipe(struct usb_pipe *pipe)
 {
     if (! CONFIG_USB_EHCI)
         return;
-    dprintf(7, "ehci_free_pipe %p\n", p);
-    struct ehci_pipe *pipe = container_of(p, struct ehci_pipe, pipe);
-    struct usb_ehci_s *cntl = container_of(
-        pipe->pipe.cntl, struct usb_ehci_s, usb);
-
-    struct ehci_qh *start = cntl->async_qh;
-    struct ehci_qh *pos = start;
-    for (;;) {
-        struct ehci_qh *next = (void*)(pos->next & ~EHCI_PTR_BITS);
-        if (next == start) {
-            // Not found?!  Exit without freeing.
-            warn_internalerror();
-            return;
-        }
-        if (next == &pipe->qh) {
-            pos->next = next->next;
-            ehci_waittick(cntl);
-            free(pipe);
-            return;
-        }
-        pos = next;
-    }
+    // Add to controller's free list.
+    struct usb_s *cntl = pipe->cntl;
+    pipe->freenext = cntl->freelist;
+    cntl->freelist = pipe;
 }
 
-struct usb_pipe *
-ehci_alloc_control_pipe(struct usb_pipe *dummy)
+static struct usb_pipe *
+ehci_alloc_pipe(struct usb_pipe *dummy, int iscontrol)
 {
     if (! CONFIG_USB_EHCI)
         return NULL;
     struct usb_ehci_s *cntl = container_of(
         dummy->cntl, struct usb_ehci_s, usb);
-    dprintf(7, "ehci_alloc_control_pipe %p\n", &cntl->usb);
+    dprintf(7, "ehci_alloc_pipe %p %d\n", &cntl->usb, iscontrol);
+
+    struct usb_pipe *freepipe = cntl->usb.freelist;
+    while (freepipe) {
+        struct ehci_pipe *pipe = container_of(cntl->usb.freelist
+                                              , struct ehci_pipe, pipe);
+        if (pipe->iscontrol == iscontrol) {
+            // Use previously allocated queue head.
+            cntl->usb.freelist = pipe->pipe.freenext;
+            memcpy(&pipe->pipe, dummy, sizeof(pipe->pipe));
+            return &pipe->pipe;
+        }
+        freepipe = freepipe->freenext;
+    }
 
-    // Allocate a queue head.
-    struct ehci_pipe *pipe = memalign_tmphigh(EHCI_QH_ALIGN, sizeof(*pipe));
+    // Allocate a new queue head.
+    struct ehci_pipe *pipe;
+    if (iscontrol)
+        pipe = memalign_tmphigh(EHCI_QH_ALIGN, sizeof(*pipe));
+    else
+        pipe = memalign_low(EHCI_QH_ALIGN, sizeof(*pipe));
     if (!pipe) {
         warn_noalloc();
         return NULL;
@@ -440,6 +469,7 @@ ehci_alloc_control_pipe(struct usb_pipe *dummy)
     memset(pipe, 0, sizeof(*pipe));
     memcpy(&pipe->pipe, dummy, sizeof(pipe->pipe));
     pipe->qh.qtd_next = pipe->qh.alt_next = EHCI_PTR_TERM;
+    pipe->iscontrol = iscontrol;
 
     // Add queue head to controller list.
     struct ehci_qh *async_qh = cntl->async_qh;
@@ -449,6 +479,18 @@ ehci_alloc_control_pipe(struct usb_pipe *dummy)
     return &pipe->pipe;
 }
 
+struct usb_pipe *
+ehci_alloc_control_pipe(struct usb_pipe *dummy)
+{
+    return ehci_alloc_pipe(dummy, 1);
+}
+
+struct usb_pipe *
+ehci_alloc_bulk_pipe(struct usb_pipe *dummy)
+{
+    return ehci_alloc_pipe(dummy, 0);
+}
+
 static int
 fillTDbuffer(struct ehci_qtd *td, u16 maxpacket, const void *buf, int bytes)
 {
@@ -546,34 +588,6 @@ ehci_control(struct usb_pipe *p, int dir, const void *cmd, int cmdsize
     return ret;
 }
 
-struct usb_pipe *
-ehci_alloc_bulk_pipe(struct usb_pipe *dummy)
-{
-    // XXX - this func is same as alloc_control except for malloc_low
-    if (! CONFIG_USB_EHCI)
-        return NULL;
-    struct usb_ehci_s *cntl = container_of(
-        dummy->cntl, struct usb_ehci_s, usb);
-    dprintf(7, "ehci_alloc_bulk_pipe %p\n", &cntl->usb);
-
-    // Allocate a queue head.
-    struct ehci_pipe *pipe = memalign_low(EHCI_QH_ALIGN, sizeof(*pipe));
-    if (!pipe) {
-        warn_noalloc();
-        return NULL;
-    }
-    memset(pipe, 0, sizeof(*pipe));
-    memcpy(&pipe->pipe, dummy, sizeof(pipe->pipe));
-    pipe->qh.qtd_next = pipe->qh.alt_next = EHCI_PTR_TERM;
-
-    // Add queue head to controller list.
-    struct ehci_qh *async_qh = cntl->async_qh;
-    pipe->qh.next = async_qh->next;
-    barrier();
-    async_qh->next = (u32)&pipe->qh | EHCI_PTR_QH;
-    return &pipe->pipe;
-}
-
 #define STACKQTDS 4
 
 int
-- 
1.7.6.5




More information about the SeaBIOS mailing list