diff options
author | Kevin O'Connor <kevin@koconnor.net> | 2017-10-03 10:45:24 -0400 |
---|---|---|
committer | Kevin O'Connor <kevin@koconnor.net> | 2017-10-03 13:58:12 -0400 |
commit | 4b48839999c696b732ee6b2a03b18a47d9d324c2 (patch) | |
tree | a29a7bb4b90d93f43dff31c0cbe3317153867545 | |
parent | f3d2a156448f006e5d83eb60cb1da2dea6c997bf (diff) | |
download | seabios-4b48839999c696b732ee6b2a03b18a47d9d324c2.tar.gz |
xhci: Build TRBs directly in xhci_trb_queue()
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>
-rw-r--r-- | src/hw/usb-xhci.c | 164 |
1 files changed, 59 insertions, 105 deletions
diff --git a/src/hw/usb-xhci.c b/src/hw/usb-xhci.c index 50b3b86d..0f717c6c 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,31 @@ 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) +// Submit a USB "setup" message request to the pipe's ring +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); } +// Submit a USB transfer request to the pipe's ring 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 +1103,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); } |