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); }
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