[SeaBIOS] [PATCH] xhci: Build TRBs directly in xhci_trb_queue()

Kevin O'Connor posted 1 patch 6 years, 6 months ago
Patches applied successfully (tree, apply log)
git fetch https://github.com/patchew-project/seabios tags/patchew/20171003174157.32379-1-kevin@koconnor.net
src/hw/usb-xhci.c | 162 +++++++++++++++++++-----------------------------------
1 file changed, 57 insertions(+), 105 deletions(-)
[SeaBIOS] [PATCH] xhci: Build TRBs directly in xhci_trb_queue()
Posted by Kevin O'Connor 6 years, 6 months ago
Use the logic for building a 'struct xhci_trb' that was in
xhci_xfer_queue() up so that command and ring TRBs can also use that
functionality.  This eliminates the need to manually generate the
xhci_trb struct from those code paths.

Signed-off-by: Kevin O'Connor <kevin@koconnor.net>
---
 src/hw/usb-xhci.c | 162 +++++++++++++++++++-----------------------------------
 1 file changed, 57 insertions(+), 105 deletions(-)

diff --git a/src/hw/usb-xhci.c b/src/hw/usb-xhci.c
index 50b3b86..a92a162 100644
--- a/src/hw/usb-xhci.c
+++ b/src/hw/usb-xhci.c
@@ -641,13 +641,16 @@ xhci_setup(void)
  * End point communication
  ****************************************************************/
 
+// Signal the hardware to process events on a TRB ring
 static void xhci_doorbell(struct usb_xhci_s *xhci, u32 slotid, u32 value)
 {
+    dprintf(5, "%s: slotid %d, epid %d\n", __func__, slotid, value);
     struct xhci_db *db = xhci->db;
     void *addr = &db[slotid].doorbell;
     writel(addr, value);
 }
 
+// Dequeue events on the XHCI command ring generated by the hardware
 static void xhci_process_events(struct usb_xhci_s *xhci)
 {
     struct xhci_ring *evts = xhci->evts;
@@ -712,6 +715,7 @@ static void xhci_process_events(struct usb_xhci_s *xhci)
     }
 }
 
+// Check if a ring has any pending TRBs
 static int xhci_ring_busy(struct xhci_ring *ring)
 {
     u32 eidx = ring->eidx;
@@ -719,6 +723,7 @@ static int xhci_ring_busy(struct xhci_ring *ring)
     return (eidx != nidx);
 }
 
+// Wait for a ring to empty (all TRBs processed by hardware)
 static int xhci_event_wait(struct usb_xhci_s *xhci,
                            struct xhci_ring *ring,
                            u32 timeout)
@@ -739,69 +744,54 @@ static int xhci_event_wait(struct usb_xhci_s *xhci,
     }
 }
 
-static void xhci_trb_queue(struct xhci_ring *ring,
-                           struct xhci_trb *trb)
+// Add a TRB to the given ring
+static void xhci_trb_fill(struct xhci_ring *ring
+                          , void *data, u32 xferlen, u32 flags)
 {
-    u32 nidx = ring->nidx;
-    u32 cs   = ring->cs;
-    struct xhci_trb *dst;
-    u32 control;
-
-    if (nidx == XHCI_RING_ITEMS-1) {
-        dst = ring->ring + nidx;
-        control  = (TR_LINK << 10); // trb type
-        control |= TRB_LK_TC;
-        control |= (cs ? TRB_C : 0);
-        dst->ptr_low = (u32)&ring[0];
+    struct xhci_trb *dst = &ring->ring[ring->nidx];
+    if (flags & TRB_TR_IDT) {
+        memcpy(&dst->ptr_low, data, xferlen);
+    } else {
+        dst->ptr_low = (u32)data;
         dst->ptr_high = 0;
-        dst->status = 0;
-        dst->control = control;
-        nidx = 0;
-        cs = cs ? 0 : 1;
-        ring->nidx = nidx;
-        ring->cs = cs;
+    }
+    dst->status = xferlen;
+    dst->control = flags | (ring->cs ? TRB_C : 0);
+}
 
+// Queue a TRB onto a ring, wrapping ring as needed
+static void xhci_trb_queue(struct xhci_ring *ring,
+                           void *data, u32 xferlen, u32 flags)
+{
+    if (ring->nidx >= ARRAY_SIZE(ring->ring) - 1) {
+        xhci_trb_fill(ring, ring->ring, 0, (TR_LINK << 10) | TRB_LK_TC);
+        ring->nidx = 0;
+        ring->cs ^= 1;
         dprintf(5, "%s: ring %p [linked]\n", __func__, ring);
     }
 
-    dst = ring->ring + nidx;
-    control = trb->control | (cs ? TRB_C : 0);
-
-    dst->ptr_low =  trb->ptr_low;
-    dst->ptr_high = trb->ptr_high;
-    dst->status =   trb->status;
-    dst->control =  control;
-    nidx++;
-    ring->nidx = nidx;
-
+    xhci_trb_fill(ring, data, xferlen, flags);
+    ring->nidx++;
     dprintf(5, "%s: ring %p [nidx %d, len %d]\n",
-            __func__, ring, nidx,
-            trb->status & 0xffff);
+            __func__, ring, ring->nidx, xferlen);
 }
 
-static int xhci_cmd_submit(struct usb_xhci_s *xhci,
-                           struct xhci_trb *cmd)
+// Submit a command to the xhci controller ring
+static int xhci_cmd_submit(struct usb_xhci_s *xhci, struct xhci_inctx *inctx
+                           , u32 flags)
 {
-    int rc;
-
     mutex_lock(&xhci->cmds->lock);
-    xhci_trb_queue(xhci->cmds, cmd);
+    xhci_trb_queue(xhci->cmds, inctx, 0, flags);
     xhci_doorbell(xhci, 0, 0);
-    rc = xhci_event_wait(xhci, xhci->cmds, 1000);
+    int rc = xhci_event_wait(xhci, xhci->cmds, 1000);
     mutex_unlock(&xhci->cmds->lock);
     return rc;
 }
 
 static int xhci_cmd_enable_slot(struct usb_xhci_s *xhci)
 {
-    struct xhci_trb cmd = {
-        .ptr_low  = 0,
-        .ptr_high = 0,
-        .status   = 0,
-        .control  = (CR_ENABLE_SLOT << 10)
-    };
     dprintf(3, "%s:\n", __func__);
-    int cc = xhci_cmd_submit(xhci, &cmd);
+    int cc = xhci_cmd_submit(xhci, NULL, CR_ENABLE_SLOT << 10);
     if (cc != CC_SUCCESS)
         return -1;
     return (xhci->cmds->evt.control >> 24) & 0xff;
@@ -809,55 +799,34 @@ static int xhci_cmd_enable_slot(struct usb_xhci_s *xhci)
 
 static int xhci_cmd_disable_slot(struct usb_xhci_s *xhci, u32 slotid)
 {
-    struct xhci_trb cmd = {
-        .ptr_low  = 0,
-        .ptr_high = 0,
-        .status   = 0,
-        .control  = (slotid << 24) | (CR_DISABLE_SLOT << 10)
-    };
     dprintf(3, "%s: slotid %d\n", __func__, slotid);
-    return xhci_cmd_submit(xhci, &cmd);
+    return xhci_cmd_submit(xhci, NULL, (CR_DISABLE_SLOT << 10) | (slotid << 24));
 }
 
 static int xhci_cmd_address_device(struct usb_xhci_s *xhci, u32 slotid
                                    , struct xhci_inctx *inctx)
 {
-    struct xhci_trb cmd = {
-        .ptr_low  = (u32)inctx,
-        .ptr_high = 0,
-        .status   = 0,
-        .control  = (slotid << 24) | (CR_ADDRESS_DEVICE << 10)
-    };
     dprintf(3, "%s: slotid %d\n", __func__, slotid);
-    return xhci_cmd_submit(xhci, &cmd);
+    return xhci_cmd_submit(xhci, inctx
+                           , (CR_ADDRESS_DEVICE << 10) | (slotid << 24));
 }
 
 static int xhci_cmd_configure_endpoint(struct usb_xhci_s *xhci, u32 slotid
                                        , struct xhci_inctx *inctx)
 {
-    struct xhci_trb cmd = {
-        .ptr_low  = (u32)inctx,
-        .ptr_high = 0,
-        .status   = 0,
-        .control  = (slotid << 24) | (CR_CONFIGURE_ENDPOINT << 10)
-    };
     dprintf(3, "%s: slotid %d, add 0x%x, del 0x%x\n", __func__,
             slotid, inctx->add, inctx->del);
-    return xhci_cmd_submit(xhci, &cmd);
+    return xhci_cmd_submit(xhci, inctx
+                           , (CR_CONFIGURE_ENDPOINT << 10) | (slotid << 24));
 }
 
 static int xhci_cmd_evaluate_context(struct usb_xhci_s *xhci, u32 slotid
                                      , struct xhci_inctx *inctx)
 {
-    struct xhci_trb cmd = {
-        .ptr_low  = (u32)inctx,
-        .ptr_high = 0,
-        .status   = 0,
-        .control  = (slotid << 24) | (CR_EVALUATE_CONTEXT << 10)
-    };
     dprintf(3, "%s: slotid %d, add 0x%x, del 0x%x\n", __func__,
             slotid, inctx->add, inctx->del);
-    return xhci_cmd_submit(xhci, &cmd);
+    return xhci_cmd_submit(xhci, inctx
+                           , (CR_EVALUATE_CONTEXT << 10) | (slotid << 24));
 }
 
 static struct xhci_inctx *
@@ -1092,37 +1061,29 @@ xhci_realloc_pipe(struct usbdevice_s *usbdev, struct usb_pipe *upipe
     return upipe;
 }
 
-static void xhci_xfer_queue(struct xhci_pipe *pipe,
-                            void *data, int datalen, u32 flags)
-{
-    struct xhci_trb trb;
-    memset(&trb, 0, sizeof(trb));
-    if (flags & TRB_TR_IDT)
-        memcpy(&trb.ptr_low, data, datalen);
-    else
-        trb.ptr_low  = (u32)data;
-    trb.status = datalen;
-    trb.control = flags;
-    xhci_trb_queue(&pipe->reqs, &trb);
-}
-
-static void xhci_xfer_kick(struct xhci_pipe *pipe)
+static void xhci_xfer_setup(struct xhci_pipe *pipe, int dir, void *cmd
+                            , void *data, int datalen)
 {
     struct usb_xhci_s *xhci = container_of(
         pipe->pipe.cntl, struct usb_xhci_s, usb);
-    u32 slotid = pipe->slotid;
-    u32 epid = pipe->epid;
-
-    dprintf(5, "%s: ring %p, slotid %d, epid %d\n",
-            __func__, &pipe->reqs, slotid, epid);
-    xhci_doorbell(xhci, slotid, epid);
+    xhci_trb_queue(&pipe->reqs, cmd, USB_CONTROL_SETUP_SIZE
+                   , (TR_SETUP << 10) | TRB_TR_IDT
+                   | ((datalen ? (dir ? 3 : 2) : 0) << 16));
+    if (datalen)
+        xhci_trb_queue(&pipe->reqs, data, datalen, (TR_DATA << 10)
+                       | ((dir ? 1 : 0) << 16));
+    xhci_trb_queue(&pipe->reqs, NULL, 0, (TR_STATUS << 10) | TRB_TR_IOC
+                   | ((dir ? 0 : 1) << 16));
+    xhci_doorbell(xhci, pipe->slotid, pipe->epid);
 }
 
 static void xhci_xfer_normal(struct xhci_pipe *pipe,
                              void *data, int datalen)
 {
-    xhci_xfer_queue(pipe, data, datalen, (TR_NORMAL << 10) | TRB_TR_IOC);
-    xhci_xfer_kick(pipe);
+    struct usb_xhci_s *xhci = container_of(
+        pipe->pipe.cntl, struct usb_xhci_s, usb);
+    xhci_trb_queue(&pipe->reqs, data, datalen, (TR_NORMAL << 10) | TRB_TR_IOC);
+    xhci_doorbell(xhci, pipe->slotid, pipe->epid);
 }
 
 int
@@ -1140,16 +1101,7 @@ xhci_send_pipe(struct usb_pipe *p, int dir, const void *cmd
         if (req->bRequest == USB_REQ_SET_ADDRESS)
             // Set address command sent during xhci_alloc_pipe.
             return 0;
-
-        xhci_xfer_queue(pipe, (void*)req, USB_CONTROL_SETUP_SIZE
-                        , (TR_SETUP << 10) | TRB_TR_IDT
-                        | ((datalen ? (dir ? 3 : 2) : 0) << 16));
-        if (datalen)
-            xhci_xfer_queue(pipe, data, datalen, (TR_DATA << 10)
-                            | ((dir ? 1 : 0) << 16));
-        xhci_xfer_queue(pipe, NULL, 0, (TR_STATUS << 10) | TRB_TR_IOC
-                        | ((dir ? 0 : 1) << 16));
-        xhci_xfer_kick(pipe);
+        xhci_xfer_setup(pipe, dir, (void*)req, data, datalen);
     } else {
         xhci_xfer_normal(pipe, data, datalen);
     }
-- 
2.9.5


_______________________________________________
SeaBIOS mailing list
SeaBIOS@seabios.org
https://mail.coreboot.org/mailman/listinfo/seabios
Re: [SeaBIOS] [PATCH] xhci: Build TRBs directly in xhci_trb_queue()
Posted by Kevin O'Connor 6 years, 6 months ago
On Tue, Oct 03, 2017 at 01:41:57PM -0400, Kevin O'Connor wrote:
> Use the logic for building a 'struct xhci_trb' that was in
> xhci_xfer_queue() up so that command and ring TRBs can also use that
> functionality.  This eliminates the need to manually generate the
> xhci_trb struct from those code paths.

FYI, I committed this change.

-Kevin

_______________________________________________
SeaBIOS mailing list
SeaBIOS@seabios.org
https://mail.coreboot.org/mailman/listinfo/seabios