This series cleans up the xhci code (by removing some of the old 16bit assumptions), and rearranges things a little to make the code layout more similar to the other usb controller drivers. This is in preparation for the next USB series which reworks some of the USB timing.
This series (along with the next) is also at: https://github.com/KevinOConnor/seabios/tree/testing
-Kevin
Kevin O'Connor (4): xhci: Remove 16bit code wrappers. xhci: Use high memory instead of low memory for internal storage. xhci: Move root hub and setup code to top of file. xhci: Add xhci_check_ports() and xhci_free_pipes() functions.
src/hw/usb-xhci.c | 924 +++++++++++++++++++++++++++--------------------------- 1 file changed, 462 insertions(+), 462 deletions(-)
The usb-xhci.c file is only compiled in 32bit mode now, so remove all the 16bit macros.
Signed-off-by: Kevin O'Connor kevin@koconnor.net --- src/hw/usb-xhci.c | 118 ++++++++++++++++++++++-------------------------------- 1 file changed, 48 insertions(+), 70 deletions(-)
diff --git a/src/hw/usb-xhci.c b/src/hw/usb-xhci.c index bbf51c2..a3927bc 100644 --- a/src/hw/usb-xhci.c +++ b/src/hw/usb-xhci.c @@ -5,7 +5,6 @@ // // This file may be distributed under the terms of the GNU LGPLv3 license.
-#include "biosvar.h" // GET_LOWFLAT #include "config.h" // CONFIG_* #include "malloc.h" // memalign_low #include "memmap.h" // PAGE_SIZE @@ -13,7 +12,7 @@ #include "pci.h" // pci_bdf_to_bus #include "pci_ids.h" // PCI_CLASS_SERIAL_USB_XHCI #include "pci_regs.h" // PCI_BASE_ADDRESS_0 -#include "string.h" // memcpy_fl +#include "string.h" // memcpy #include "usb.h" // struct usb_s #include "usb-xhci.h" // struct ehci_qh #include "util.h" // timer_calc @@ -304,48 +303,48 @@ static const int eptype_to_xhci_out[] = { };
// -------------------------------------------------------------- -// internal functions, 16bit + 32bit +// internal functions
static void xhci_doorbell(struct usb_xhci_s *xhci, u32 slotid, u32 value) { - struct xhci_db *db = GET_LOWFLAT(xhci->db); + struct xhci_db *db = xhci->db; void *addr = &db[slotid].doorbell; writel(addr, value); }
static void xhci_process_events(struct usb_xhci_s *xhci) { - struct xhci_ring *evts = GET_LOWFLAT(xhci->evts); + struct xhci_ring *evts = xhci->evts;
for (;;) { /* check for event */ - u32 nidx = GET_LOWFLAT(evts->nidx); - u32 cs = GET_LOWFLAT(evts->cs); + u32 nidx = evts->nidx; + u32 cs = evts->cs; struct xhci_trb *etrb = evts->ring + nidx; - u32 control = GET_LOWFLAT(etrb->control); + u32 control = etrb->control; if ((control & TRB_C) != (cs ? 1 : 0)) return;
/* process event */ u32 evt_type = TRB_TYPE(control); - u32 evt_cc = (GET_LOWFLAT(etrb->status) >> 24) & 0xff; + u32 evt_cc = (etrb->status >> 24) & 0xff; switch (evt_type) { case ER_TRANSFER: case ER_COMMAND_COMPLETE: { - struct xhci_trb *rtrb = (void*)GET_LOWFLAT(etrb->ptr_low); + struct xhci_trb *rtrb = (void*)etrb->ptr_low; struct xhci_ring *ring = XHCI_RING(rtrb); struct xhci_trb *evt = &ring->evt; u32 eidx = rtrb - ring->ring + 1; dprintf(5, "%s: ring %p [trb %p, evt %p, type %d, eidx %d, cc %d]\n", __func__, ring, rtrb, evt, evt_type, eidx, evt_cc); - memcpy_fl(evt, etrb, sizeof(*etrb)); - SET_LOWFLAT(ring->eidx, eidx); + memcpy(evt, etrb, sizeof(*etrb)); + ring->eidx = eidx; break; } case ER_PORT_STATUS_CHANGE: { - u32 portid = (GET_LOWFLAT(etrb->ptr_low) >> 24) & 0xff; + u32 portid = (etrb->ptr_low >> 24) & 0xff; dprintf(3, "%s: status change port #%d\n", __func__, portid); break; @@ -361,10 +360,10 @@ static void xhci_process_events(struct usb_xhci_s *xhci) if (nidx == XHCI_RING_ITEMS) { nidx = 0; cs = cs ? 0 : 1; - SET_LOWFLAT(evts->cs, cs); + evts->cs = cs; } - SET_LOWFLAT(evts->nidx, nidx); - struct xhci_ir *ir = GET_LOWFLAT(xhci->ir); + evts->nidx = nidx; + struct xhci_ir *ir = xhci->ir; u32 erdp = (u32)(evts->ring + nidx); writel(&ir->erdp_low, erdp); writel(&ir->erdp_high, 0); @@ -373,8 +372,8 @@ static void xhci_process_events(struct usb_xhci_s *xhci)
static int xhci_ring_busy(struct xhci_ring *ring) { - u32 eidx = GET_LOWFLAT(ring->eidx); - u32 nidx = GET_LOWFLAT(ring->nidx); + u32 eidx = ring->eidx; + u32 nidx = ring->nidx; return (eidx != nidx); }
@@ -387,7 +386,7 @@ static int xhci_event_wait(struct usb_xhci_s *xhci, for (;;) { xhci_process_events(xhci); if (!xhci_ring_busy(ring)) { - u32 status = GET_LOWFLAT(ring->evt.status); + u32 status = ring->evt.status; return (status >> 24) & 0xff; } if (timer_check(end)) { @@ -401,8 +400,8 @@ static int xhci_event_wait(struct usb_xhci_s *xhci, static void xhci_trb_queue(struct xhci_ring *ring, struct xhci_trb *trb) { - u32 nidx = GET_LOWFLAT(ring->nidx); - u32 cs = GET_LOWFLAT(ring->cs); + u32 nidx = ring->nidx; + u32 cs = ring->cs; struct xhci_trb *dst; u32 control;
@@ -411,31 +410,31 @@ static void xhci_trb_queue(struct xhci_ring *ring, control = (TR_LINK << 10); // trb type control |= TRB_LK_TC; control |= (cs ? TRB_C : 0); - SET_LOWFLAT(dst->ptr_low, (u32)&ring[0]); - SET_LOWFLAT(dst->ptr_high, 0); - SET_LOWFLAT(dst->status, 0); - SET_LOWFLAT(dst->control, control); + dst->ptr_low = (u32)&ring[0]; + dst->ptr_high = 0; + dst->status = 0; + dst->control = control; nidx = 0; cs = cs ? 0 : 1; - SET_LOWFLAT(ring->nidx, nidx); - SET_LOWFLAT(ring->cs, cs); + ring->nidx = nidx; + ring->cs = cs;
dprintf(5, "%s: ring %p [linked]\n", __func__, ring); }
dst = ring->ring + nidx; - control = GET_LOWFLAT(trb->control) | (cs ? TRB_C : 0); + control = trb->control | (cs ? TRB_C : 0);
- SET_LOWFLAT(dst->ptr_low, GET_LOWFLAT(trb->ptr_low)); - SET_LOWFLAT(dst->ptr_high, GET_LOWFLAT(trb->ptr_high)); - SET_LOWFLAT(dst->status, GET_LOWFLAT(trb->status)); - SET_LOWFLAT(dst->control, control); + dst->ptr_low = trb->ptr_low; + dst->ptr_high = trb->ptr_high; + dst->status = trb->status; + dst->control = control; nidx++; - SET_LOWFLAT(ring->nidx, nidx); + ring->nidx = nidx;
dprintf(5, "%s: ring %p [nidx %d, len %d]\n", __func__, ring, nidx, - GET_LOWFLAT(trb->status) & 0xffff); + trb->status & 0xffff); }
static void xhci_xfer_queue(struct xhci_pipe *pipe, @@ -447,9 +446,9 @@ static void xhci_xfer_queue(struct xhci_pipe *pipe, static void xhci_xfer_kick(struct xhci_pipe *pipe) { struct usb_xhci_s *xhci = container_of( - GET_LOWFLAT(pipe->pipe.cntl), struct usb_xhci_s, usb); - u32 slotid = GET_LOWFLAT(pipe->slotid); - u32 epid = GET_LOWFLAT(pipe->epid); + 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); @@ -467,16 +466,12 @@ static void xhci_xfer_normal(struct xhci_pipe *pipe, trb.control |= (TR_NORMAL << 10); // trb type trb.control |= TRB_TR_IOC;
- xhci_xfer_queue(pipe, MAKE_FLATPTR(GET_SEG(SS), &trb)); + xhci_xfer_queue(pipe, &trb); xhci_xfer_kick(pipe); }
-// -------------------------------------------------------------- -// internal functions, pure 32bit - static int wait_bit(u32 *reg, u32 mask, int value, u32 timeout) { - ASSERT32FLAT(); u32 end = timer_calc(timeout);
while ((readl(reg) & mask) != value) { @@ -492,7 +487,6 @@ static int wait_bit(u32 *reg, u32 mask, int value, u32 timeout) static int xhci_cmd_submit(struct usb_xhci_s *xhci, struct xhci_trb *cmd) { - ASSERT32FLAT(); int rc;
mutex_lock(&xhci->cmds->lock); @@ -505,7 +499,6 @@ static int xhci_cmd_submit(struct usb_xhci_s *xhci,
static int xhci_cmd_enable_slot(struct usb_xhci_s *xhci) { - ASSERT32FLAT(); struct xhci_trb cmd = { .ptr_low = 0, .ptr_high = 0, @@ -522,7 +515,6 @@ static int xhci_cmd_enable_slot(struct usb_xhci_s *xhci) #if 0 static int xhci_cmd_disable_slot(struct usb_xhci_s *xhci, u32 slotid) { - ASSERT32FLAT(); struct xhci_trb cmd = { .ptr_low = 0, .ptr_high = 0, @@ -537,7 +529,6 @@ static int xhci_cmd_disable_slot(struct usb_xhci_s *xhci, u32 slotid) static int xhci_cmd_address_device(struct usb_xhci_s *xhci, u32 slotid , struct xhci_inctx *inctx) { - ASSERT32FLAT(); struct xhci_trb cmd = { .ptr_low = (u32)inctx, .ptr_high = 0, @@ -551,7 +542,6 @@ static int xhci_cmd_address_device(struct usb_xhci_s *xhci, u32 slotid static int xhci_cmd_configure_endpoint(struct usb_xhci_s *xhci, u32 slotid , struct xhci_inctx *inctx) { - ASSERT32FLAT(); struct xhci_trb cmd = { .ptr_low = (u32)inctx, .ptr_high = 0, @@ -566,7 +556,6 @@ static int xhci_cmd_configure_endpoint(struct usb_xhci_s *xhci, u32 slotid static int xhci_cmd_evaluate_context(struct usb_xhci_s *xhci, u32 slotid , struct xhci_inctx *inctx) { - ASSERT32FLAT(); struct xhci_trb cmd = { .ptr_low = (u32)inctx, .ptr_high = 0, @@ -582,7 +571,6 @@ static void xhci_xfer_setup(struct xhci_pipe *pipe, const struct usb_ctrlrequest *req, int dir, int datalen) { - ASSERT32FLAT(); struct xhci_trb trb;
memset(&trb, 0, sizeof(trb)); @@ -602,7 +590,6 @@ static void xhci_xfer_setup(struct xhci_pipe *pipe, static void xhci_xfer_data(struct xhci_pipe *pipe, int dir, void *data, int datalen) { - ASSERT32FLAT(); struct xhci_trb trb;
memset(&trb, 0, sizeof(trb)); @@ -616,7 +603,6 @@ static void xhci_xfer_data(struct xhci_pipe *pipe,
static void xhci_xfer_status(struct xhci_pipe *pipe, int dir, int datalen) { - ASSERT32FLAT(); struct xhci_trb trb;
memset(&trb, 0, sizeof(trb)); @@ -632,7 +618,6 @@ static void xhci_xfer_status(struct xhci_pipe *pipe, int dir, int datalen) static void configure_xhci(void *data) { - ASSERT32FLAT(); struct usb_xhci_s *xhci = data; u32 reg;
@@ -734,7 +719,6 @@ fail: static void xhci_print_port_state(int loglevel, const char *prefix, u32 port, u32 portsc) { - ASSERT32FLAT(); u32 pls = xhci_get_field(portsc, XHCI_PORTSC_PLS); u32 speed = xhci_get_field(portsc, XHCI_PORTSC_SPEED);
@@ -748,7 +732,6 @@ xhci_print_port_state(int loglevel, const char *prefix, u32 port, u32 portsc) static int xhci_hub_detect(struct usbhub_s *hub, u32 port) { - ASSERT32FLAT(); struct usb_xhci_s *xhci = container_of(hub->cntl, struct usb_xhci_s, usb); u32 portsc = readl(&xhci->pr[port].portsc);
@@ -766,7 +749,6 @@ xhci_hub_detect(struct usbhub_s *hub, u32 port) static int xhci_hub_reset(struct usbhub_s *hub, u32 port) { - ASSERT32FLAT(); struct usb_xhci_s *xhci = container_of(hub->cntl, struct usb_xhci_s, usb); u32 portsc = readl(&xhci->pr[port].portsc); int rc; @@ -796,7 +778,6 @@ xhci_hub_reset(struct usbhub_s *hub, u32 port) static void xhci_hub_disconnect(struct usbhub_s *hub, u32 port) { - ASSERT32FLAT(); // XXX - should turn the port power off. }
@@ -886,7 +867,6 @@ struct usb_pipe * xhci_alloc_pipe(struct usbdevice_s *usbdev , struct usb_endpoint_descriptor *epdesc) { - ASSERT32FLAT(); if (!CONFIG_USB_XHCI) return NULL; u8 eptype = epdesc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK; @@ -991,7 +971,6 @@ struct usb_pipe * xhci_update_pipe(struct usbdevice_s *usbdev, struct usb_pipe *upipe , struct usb_endpoint_descriptor *epdesc) { - ASSERT32FLAT(); if (!CONFIG_USB_XHCI) return NULL; u8 eptype = epdesc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK; @@ -1028,7 +1007,6 @@ int xhci_control(struct usb_pipe *p, int dir, const void *cmd, int cmdsize , void *data, int datalen) { - ASSERT32FLAT(); if (!CONFIG_USB_XHCI) return -1; const struct usb_ctrlrequest *req = cmd; @@ -1054,7 +1032,7 @@ xhci_control(struct usb_pipe *p, int dir, const void *cmd, int cmdsize return 0; }
-int VISIBLE32FLAT +int xhci_send_bulk(struct usb_pipe *p, int dir, void *data, int datalen) { if (!CONFIG_USB_XHCI) @@ -1062,7 +1040,7 @@ xhci_send_bulk(struct usb_pipe *p, int dir, void *data, int datalen)
struct xhci_pipe *pipe = container_of(p, struct xhci_pipe, pipe); struct usb_xhci_s *xhci = container_of( - GET_LOWFLAT(pipe->pipe.cntl), struct usb_xhci_s, usb); + pipe->pipe.cntl, struct usb_xhci_s, usb);
xhci_xfer_normal(pipe, data, datalen); int cc = xhci_event_wait(xhci, &pipe->reqs, usb_xfer_time(p, datalen)); @@ -1081,15 +1059,15 @@ xhci_poll_intr(struct usb_pipe *p, void *data)
struct xhci_pipe *pipe = container_of(p, struct xhci_pipe, pipe); struct usb_xhci_s *xhci = container_of( - GET_LOWFLAT(pipe->pipe.cntl), struct usb_xhci_s, usb); - u32 len = GET_LOWFLAT(pipe->pipe.maxpacket); - void *buf = GET_LOWFLAT(pipe->buf); - int bufused = GET_LOWFLAT(pipe->bufused); + pipe->pipe.cntl, struct usb_xhci_s, usb); + u32 len = pipe->pipe.maxpacket; + void *buf = pipe->buf; + int bufused = pipe->bufused;
if (!bufused) { xhci_xfer_normal(pipe, buf, len); bufused = 1; - SET_LOWFLAT(pipe->bufused, bufused); + pipe->bufused = bufused; return -1; }
@@ -1097,10 +1075,10 @@ xhci_poll_intr(struct usb_pipe *p, void *data) if (xhci_ring_busy(&pipe->reqs)) return -1; dprintf(5, "%s: st %x ct %x [ %p <= %p / %d ]\n", __func__, - GET_LOWFLAT(pipe->reqs.evt.status), - GET_LOWFLAT(pipe->reqs.evt.control), - MAKE_FLATPTR(GET_SEG(SS), data), buf, len); - memcpy_fl(MAKE_FLATPTR(GET_SEG(SS), data), buf, len); + pipe->reqs.evt.status, + pipe->reqs.evt.control, + data, buf, len); + memcpy(data, buf, len); xhci_xfer_normal(pipe, buf, len); return 0; }
Now that the driver runs exclusively in 32bit mode, avoid using the scarce low memory resource.
Signed-off-by: Kevin O'Connor kevin@koconnor.net --- src/hw/usb-xhci.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/src/hw/usb-xhci.c b/src/hw/usb-xhci.c index a3927bc..b36f864 100644 --- a/src/hw/usb-xhci.c +++ b/src/hw/usb-xhci.c @@ -624,7 +624,7 @@ configure_xhci(void *data) xhci->devs = memalign_high(64, sizeof(*xhci->devs) * (xhci->slots + 1)); xhci->eseg = memalign_high(64, sizeof(*xhci->eseg)); xhci->cmds = memalign_high(XHCI_RING_SIZE, sizeof(*xhci->cmds)); - xhci->evts = memalign_low(XHCI_RING_SIZE, sizeof(*xhci->evts)); + xhci->evts = memalign_high(XHCI_RING_SIZE, sizeof(*xhci->evts)); if (!xhci->devs || !xhci->cmds || !xhci->evts || !xhci->eseg) { warn_noalloc(); goto fail; @@ -896,7 +896,7 @@ xhci_alloc_pipe(struct usbdevice_s *usbdev pipe->epid = epid; pipe->reqs.cs = 1; if (eptype == USB_ENDPOINT_XFER_INT) - pipe->buf = malloc_low(pipe->pipe.maxpacket); + pipe->buf = malloc_high(pipe->pipe.maxpacket);
// Allocate input context and initialize endpoint info. struct xhci_inctx *in = xhci_alloc_inctx(usbdev, epid); @@ -1086,7 +1086,7 @@ xhci_poll_intr(struct usb_pipe *p, void *data) static void xhci_controller_setup(struct pci_device *pci) { - struct usb_xhci_s *xhci = malloc_low(sizeof(*xhci)); + struct usb_xhci_s *xhci = malloc_high(sizeof(*xhci)); if (!xhci) { warn_noalloc(); return;
Move the setup code to the top of the file so that like code is together and to make the code layout more similar to the other usb controllers.
This change is purely code movement.
Signed-off-by: Kevin O'Connor kevin@koconnor.net --- src/hw/usb-xhci.c | 787 +++++++++++++++++++++++++++--------------------------- 1 file changed, 396 insertions(+), 391 deletions(-)
diff --git a/src/hw/usb-xhci.c b/src/hw/usb-xhci.c index b36f864..0e22547 100644 --- a/src/hw/usb-xhci.c +++ b/src/hw/usb-xhci.c @@ -302,8 +302,296 @@ static const int eptype_to_xhci_out[] = { [ USB_ENDPOINT_XFER_INT ] = 3, };
-// -------------------------------------------------------------- -// internal functions +static int wait_bit(u32 *reg, u32 mask, int value, u32 timeout) +{ + u32 end = timer_calc(timeout); + + while ((readl(reg) & mask) != value) { + if (timer_check(end)) { + warn_timeout(); + return -1; + } + yield(); + } + return 0; +} + + +/**************************************************************** + * Root hub + ****************************************************************/ + +// Check if device attached to port +static void +xhci_print_port_state(int loglevel, const char *prefix, u32 port, u32 portsc) +{ + u32 pls = xhci_get_field(portsc, XHCI_PORTSC_PLS); + u32 speed = xhci_get_field(portsc, XHCI_PORTSC_SPEED); + + dprintf(loglevel, "%s port #%d: 0x%08x,%s%s pls %d, speed %d [%s]\n", + prefix, port + 1, portsc, + (portsc & XHCI_PORTSC_PP) ? " powered," : "", + (portsc & XHCI_PORTSC_PED) ? " enabled," : "", + pls, speed, speed_name[speed]); +} + +static int +xhci_hub_detect(struct usbhub_s *hub, u32 port) +{ + struct usb_xhci_s *xhci = container_of(hub->cntl, struct usb_xhci_s, usb); + u32 portsc = readl(&xhci->pr[port].portsc); + + xhci_print_port_state(3, __func__, port, portsc); + switch (xhci_get_field(portsc, XHCI_PORTSC_PLS)) { + case PLS_U0: + case PLS_POLLING: + return 0; + default: + return -1; + } +} + +// Reset device on port +static int +xhci_hub_reset(struct usbhub_s *hub, u32 port) +{ + struct usb_xhci_s *xhci = container_of(hub->cntl, struct usb_xhci_s, usb); + u32 portsc = readl(&xhci->pr[port].portsc); + int rc; + + switch (xhci_get_field(portsc, XHCI_PORTSC_PLS)) { + case PLS_U0: + rc = speed_from_xhci[xhci_get_field(portsc, XHCI_PORTSC_SPEED)]; + break; + case PLS_POLLING: + xhci_print_port_state(3, __func__, port, portsc); + portsc |= XHCI_PORTSC_PR; + writel(&xhci->pr[port].portsc, portsc); + if (wait_bit(&xhci->pr[port].portsc, XHCI_PORTSC_PED, XHCI_PORTSC_PED, 100) != 0) + return -1; + portsc = readl(&xhci->pr[port].portsc); + rc = speed_from_xhci[xhci_get_field(portsc, XHCI_PORTSC_SPEED)]; + break; + default: + rc = -1; + break; + } + + xhci_print_port_state(1, "XHCI", port, portsc); + return rc; +} + +static void +xhci_hub_disconnect(struct usbhub_s *hub, u32 port) +{ + // XXX - should turn the port power off. +} + +static struct usbhub_op_s xhci_hub_ops = { + .detect = xhci_hub_detect, + .reset = xhci_hub_reset, + .disconnect = xhci_hub_disconnect, +}; + + +/**************************************************************** + * Setup + ****************************************************************/ + +static void +configure_xhci(void *data) +{ + struct usb_xhci_s *xhci = data; + u32 reg; + + xhci->devs = memalign_high(64, sizeof(*xhci->devs) * (xhci->slots + 1)); + xhci->eseg = memalign_high(64, sizeof(*xhci->eseg)); + xhci->cmds = memalign_high(XHCI_RING_SIZE, sizeof(*xhci->cmds)); + xhci->evts = memalign_high(XHCI_RING_SIZE, sizeof(*xhci->evts)); + if (!xhci->devs || !xhci->cmds || !xhci->evts || !xhci->eseg) { + warn_noalloc(); + goto fail; + } + memset(xhci->devs, 0, sizeof(*xhci->devs) * (xhci->slots + 1)); + memset(xhci->cmds, 0, sizeof(*xhci->cmds)); + memset(xhci->evts, 0, sizeof(*xhci->evts)); + memset(xhci->eseg, 0, sizeof(*xhci->eseg)); + + reg = readl(&xhci->op->usbcmd); + if (reg & XHCI_CMD_RS) { + reg &= ~XHCI_CMD_RS; + writel(&xhci->op->usbcmd, reg); + if (wait_bit(&xhci->op->usbsts, XHCI_STS_HCH, XHCI_STS_HCH, 32) != 0) + goto fail; + } + + dprintf(3, "%s: resetting\n", __func__); + writel(&xhci->op->usbcmd, XHCI_CMD_HCRST); + if (wait_bit(&xhci->op->usbcmd, XHCI_CMD_HCRST, 0, 100) != 0) + goto fail; + if (wait_bit(&xhci->op->usbsts, XHCI_STS_CNR, 0, 100) != 0) + goto fail; + + writel(&xhci->op->config, xhci->slots); + writel(&xhci->op->dcbaap_low, (u32)xhci->devs); + writel(&xhci->op->dcbaap_high, 0); + writel(&xhci->op->crcr_low, (u32)xhci->cmds | 1); + writel(&xhci->op->crcr_high, 0); + xhci->cmds->cs = 1; + + xhci->eseg->ptr_low = (u32)xhci->evts; + xhci->eseg->ptr_high = 0; + xhci->eseg->size = XHCI_RING_ITEMS; + writel(&xhci->ir->erstsz, 1); + writel(&xhci->ir->erdp_low, (u32)xhci->evts); + writel(&xhci->ir->erdp_high, 0); + writel(&xhci->ir->erstba_low, (u32)xhci->eseg); + writel(&xhci->ir->erstba_high, 0); + xhci->evts->cs = 1; + + reg = readl(&xhci->caps->hcsparams2); + u32 spb = reg >> 27; + if (spb) { + dprintf(3, "%s: setup %d scratch pad buffers\n", __func__, spb); + u64 *spba = memalign_high(64, sizeof(*spba) * spb); + void *pad = memalign_high(PAGE_SIZE, PAGE_SIZE * spb); + if (!spba || !pad) { + warn_noalloc(); + free(spba); + free(pad); + goto fail; + } + int i; + for (i = 0; i < spb; i++) + spba[i] = (u32)pad + (i * PAGE_SIZE); + xhci->devs[0].ptr_low = (u32)spba; + xhci->devs[0].ptr_high = 0; + } + + reg = readl(&xhci->op->usbcmd); + reg |= XHCI_CMD_RS; + writel(&xhci->op->usbcmd, reg); + + // FIXME: try find a more elegant way than a fixed delay + msleep(100); + + usb_enumerate(&xhci->hub); + // XXX - should walk list of pipes and free unused pipes. + if (xhci->hub.devcount) + return; + + // No devices found - shutdown and free controller. + dprintf(1, "XHCI no devices found\n"); + reg = readl(&xhci->op->usbcmd); + reg &= ~XHCI_CMD_RS; + writel(&xhci->op->usbcmd, reg); + wait_bit(&xhci->op->usbsts, XHCI_STS_HCH, XHCI_STS_HCH, 32); + +fail: + free(xhci->eseg); + free(xhci->evts); + free(xhci->cmds); + free(xhci->devs); + free(xhci); +} + +static void +xhci_controller_setup(struct pci_device *pci) +{ + struct usb_xhci_s *xhci = malloc_high(sizeof(*xhci)); + if (!xhci) { + warn_noalloc(); + return; + } + memset(xhci, 0, sizeof(*xhci)); + + wait_preempt(); // Avoid pci_config_readl when preempting + xhci->baseaddr = pci_config_readl(pci->bdf, PCI_BASE_ADDRESS_0) + & PCI_BASE_ADDRESS_MEM_MASK; + xhci->caps = (void*)(xhci->baseaddr); + xhci->op = (void*)(xhci->baseaddr + readb(&xhci->caps->caplength)); + xhci->pr = (void*)(xhci->baseaddr + readb(&xhci->caps->caplength) + 0x400); + xhci->db = (void*)(xhci->baseaddr + readl(&xhci->caps->dboff)); + xhci->ir = (void*)(xhci->baseaddr + readl(&xhci->caps->rtsoff) + 0x20); + + u32 hcs1 = readl(&xhci->caps->hcsparams1); + u32 hcc = readl(&xhci->caps->hccparams); + xhci->ports = (hcs1 >> 24) & 0xff; + xhci->slots = hcs1 & 0xff; + xhci->xcap = ((hcc >> 16) & 0xffff) << 2; + xhci->context64 = (hcc & 0x04) ? 1 : 0; + + xhci->usb.pci = pci; + xhci->usb.type = USB_TYPE_XHCI; + xhci->hub.cntl = &xhci->usb; + xhci->hub.portcount = xhci->ports; + xhci->hub.op = &xhci_hub_ops; + + dprintf(1, "XHCI init on dev %02x:%02x.%x: regs @ %p, %d ports, %d slots" + ", %d byte contexts\n" + , pci_bdf_to_bus(pci->bdf), pci_bdf_to_dev(pci->bdf) + , pci_bdf_to_fn(pci->bdf), xhci->caps + , xhci->ports, xhci->slots, xhci->context64 ? 64 : 32); + + if (xhci->xcap) { + u32 off, addr = xhci->baseaddr + xhci->xcap; + do { + struct xhci_xcap *xcap = (void*)addr; + u32 ports, name, cap = readl(&xcap->cap); + switch (cap & 0xff) { + case 0x02: + name = readl(&xcap->data[0]); + ports = readl(&xcap->data[1]); + dprintf(1, "XHCI protocol %c%c%c%c %x.%02x" + ", %d ports (offset %d), def %x\n" + , (name >> 0) & 0xff + , (name >> 8) & 0xff + , (name >> 16) & 0xff + , (name >> 24) & 0xff + , (cap >> 24) & 0xff + , (cap >> 16) & 0xff + , (ports >> 8) & 0xff + , (ports >> 0) & 0xff + , ports >> 16); + break; + default: + dprintf(1, "XHCI extcap 0x%x @ %x\n", cap & 0xff, addr); + break; + } + off = (cap >> 8) & 0xff; + addr += off << 2; + } while (off > 0); + } + + u32 pagesize = readl(&xhci->op->pagesize); + if (PAGE_SIZE != (pagesize<<12)) { + dprintf(1, "XHCI driver does not support page size code %d\n" + , pagesize<<12); + free(xhci); + return; + } + + pci_config_maskw(pci->bdf, PCI_COMMAND, 0, PCI_COMMAND_MASTER); + + run_thread(configure_xhci, xhci); +} + +void +xhci_setup(void) +{ + if (! CONFIG_USB_XHCI) + return; + struct pci_device *pci; + foreachpci(pci) { + if (pci_classprog(pci) == PCI_CLASS_SERIAL_USB_XHCI) + xhci_controller_setup(pci); + } +} + + +/**************************************************************** + * End point communication + ****************************************************************/
static void xhci_doorbell(struct usb_xhci_s *xhci, u32 slotid, u32 value) { @@ -470,326 +758,136 @@ static void xhci_xfer_normal(struct xhci_pipe *pipe, xhci_xfer_kick(pipe); }
-static int wait_bit(u32 *reg, u32 mask, int value, u32 timeout) -{ - u32 end = timer_calc(timeout); - - while ((readl(reg) & mask) != value) { - if (timer_check(end)) { - warn_timeout(); - return -1; - } - yield(); - } - return 0; -} - static int xhci_cmd_submit(struct usb_xhci_s *xhci, struct xhci_trb *cmd) { int rc;
- mutex_lock(&xhci->cmds->lock); - xhci_trb_queue(xhci->cmds, cmd); - xhci_doorbell(xhci, 0, 0); - 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); - if (cc != CC_SUCCESS) - return -1; - return (xhci->cmds->evt.control >> 24) & 0xff; -} - -#if 0 -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); -} -#endif - -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); -} - -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); -} - -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); -} - -static void xhci_xfer_setup(struct xhci_pipe *pipe, - const struct usb_ctrlrequest *req, - int dir, int datalen) -{ - struct xhci_trb trb; - - memset(&trb, 0, sizeof(trb)); - trb.ptr_low |= req->bRequestType; - trb.ptr_low |= (req->bRequest) << 8; - trb.ptr_low |= (req->wValue) << 16; - trb.ptr_high |= req->wIndex; - trb.ptr_high |= (req->wLength) << 16; - trb.status |= 8; // length - trb.control |= (TR_SETUP << 10); // trb type - trb.control |= TRB_TR_IDT; - if (datalen) - trb.control |= (dir ? 3 : 2) << 16; // transfer type - xhci_xfer_queue(pipe, &trb); -} - -static void xhci_xfer_data(struct xhci_pipe *pipe, - int dir, void *data, int datalen) -{ - struct xhci_trb trb; - - memset(&trb, 0, sizeof(trb)); - trb.ptr_low = (u32)data; - trb.status = datalen; - trb.control |= (TR_DATA << 10); // trb type - if (dir) - trb.control |= (1 << 16); - xhci_xfer_queue(pipe, &trb); -} - -static void xhci_xfer_status(struct xhci_pipe *pipe, int dir, int datalen) -{ - struct xhci_trb trb; - - memset(&trb, 0, sizeof(trb)); - trb.control |= (TR_STATUS << 10); // trb type - trb.control |= TRB_TR_IOC; - if (!datalen || !dir) - trb.control |= (1 << 16); - - xhci_xfer_queue(pipe, &trb); - xhci_xfer_kick(pipe); -} - -static void -configure_xhci(void *data) -{ - struct usb_xhci_s *xhci = data; - u32 reg; - - xhci->devs = memalign_high(64, sizeof(*xhci->devs) * (xhci->slots + 1)); - xhci->eseg = memalign_high(64, sizeof(*xhci->eseg)); - xhci->cmds = memalign_high(XHCI_RING_SIZE, sizeof(*xhci->cmds)); - xhci->evts = memalign_high(XHCI_RING_SIZE, sizeof(*xhci->evts)); - if (!xhci->devs || !xhci->cmds || !xhci->evts || !xhci->eseg) { - warn_noalloc(); - goto fail; - } - memset(xhci->devs, 0, sizeof(*xhci->devs) * (xhci->slots + 1)); - memset(xhci->cmds, 0, sizeof(*xhci->cmds)); - memset(xhci->evts, 0, sizeof(*xhci->evts)); - memset(xhci->eseg, 0, sizeof(*xhci->eseg)); - - reg = readl(&xhci->op->usbcmd); - if (reg & XHCI_CMD_RS) { - reg &= ~XHCI_CMD_RS; - writel(&xhci->op->usbcmd, reg); - if (wait_bit(&xhci->op->usbsts, XHCI_STS_HCH, XHCI_STS_HCH, 32) != 0) - goto fail; - } - - dprintf(3, "%s: resetting\n", __func__); - writel(&xhci->op->usbcmd, XHCI_CMD_HCRST); - if (wait_bit(&xhci->op->usbcmd, XHCI_CMD_HCRST, 0, 100) != 0) - goto fail; - if (wait_bit(&xhci->op->usbsts, XHCI_STS_CNR, 0, 100) != 0) - goto fail; - - writel(&xhci->op->config, xhci->slots); - writel(&xhci->op->dcbaap_low, (u32)xhci->devs); - writel(&xhci->op->dcbaap_high, 0); - writel(&xhci->op->crcr_low, (u32)xhci->cmds | 1); - writel(&xhci->op->crcr_high, 0); - xhci->cmds->cs = 1; - - xhci->eseg->ptr_low = (u32)xhci->evts; - xhci->eseg->ptr_high = 0; - xhci->eseg->size = XHCI_RING_ITEMS; - writel(&xhci->ir->erstsz, 1); - writel(&xhci->ir->erdp_low, (u32)xhci->evts); - writel(&xhci->ir->erdp_high, 0); - writel(&xhci->ir->erstba_low, (u32)xhci->eseg); - writel(&xhci->ir->erstba_high, 0); - xhci->evts->cs = 1; - - reg = readl(&xhci->caps->hcsparams2); - u32 spb = reg >> 27; - if (spb) { - dprintf(3, "%s: setup %d scratch pad buffers\n", __func__, spb); - u64 *spba = memalign_high(64, sizeof(*spba) * spb); - void *pad = memalign_high(PAGE_SIZE, PAGE_SIZE * spb); - if (!spba || !pad) { - warn_noalloc(); - free(spba); - free(pad); - goto fail; - } - int i; - for (i = 0; i < spb; i++) - spba[i] = (u32)pad + (i * PAGE_SIZE); - xhci->devs[0].ptr_low = (u32)spba; - xhci->devs[0].ptr_high = 0; - } - - reg = readl(&xhci->op->usbcmd); - reg |= XHCI_CMD_RS; - writel(&xhci->op->usbcmd, reg); - - // FIXME: try find a more elegant way than a fixed delay - msleep(100); - - usb_enumerate(&xhci->hub); - // XXX - should walk list of pipes and free unused pipes. - if (xhci->hub.devcount) - return; - - // No devices found - shutdown and free controller. - dprintf(1, "XHCI no devices found\n"); - reg = readl(&xhci->op->usbcmd); - reg &= ~XHCI_CMD_RS; - writel(&xhci->op->usbcmd, reg); - wait_bit(&xhci->op->usbsts, XHCI_STS_HCH, XHCI_STS_HCH, 32); - -fail: - free(xhci->eseg); - free(xhci->evts); - free(xhci->cmds); - free(xhci->devs); - free(xhci); -} - -// -------------------------------------------------------------- -// xhci root hub + mutex_lock(&xhci->cmds->lock); + xhci_trb_queue(xhci->cmds, cmd); + xhci_doorbell(xhci, 0, 0); + rc = xhci_event_wait(xhci, xhci->cmds, 1000); + mutex_unlock(&xhci->cmds->lock); + return rc; +}
-// Check if device attached to port -static void -xhci_print_port_state(int loglevel, const char *prefix, u32 port, u32 portsc) +static int xhci_cmd_enable_slot(struct usb_xhci_s *xhci) { - u32 pls = xhci_get_field(portsc, XHCI_PORTSC_PLS); - u32 speed = xhci_get_field(portsc, XHCI_PORTSC_SPEED); + 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); + if (cc != CC_SUCCESS) + return -1; + return (xhci->cmds->evt.control >> 24) & 0xff; +}
- dprintf(loglevel, "%s port #%d: 0x%08x,%s%s pls %d, speed %d [%s]\n", - prefix, port + 1, portsc, - (portsc & XHCI_PORTSC_PP) ? " powered," : "", - (portsc & XHCI_PORTSC_PED) ? " enabled," : "", - pls, speed, speed_name[speed]); +#if 0 +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); } +#endif
-static int -xhci_hub_detect(struct usbhub_s *hub, u32 port) +static int xhci_cmd_address_device(struct usb_xhci_s *xhci, u32 slotid + , struct xhci_inctx *inctx) { - struct usb_xhci_s *xhci = container_of(hub->cntl, struct usb_xhci_s, usb); - u32 portsc = readl(&xhci->pr[port].portsc); + 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); +}
- xhci_print_port_state(3, __func__, port, portsc); - switch (xhci_get_field(portsc, XHCI_PORTSC_PLS)) { - case PLS_U0: - case PLS_POLLING: - return 0; - default: - return -1; - } +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); }
-// Reset device on port -static int -xhci_hub_reset(struct usbhub_s *hub, u32 port) +static int xhci_cmd_evaluate_context(struct usb_xhci_s *xhci, u32 slotid + , struct xhci_inctx *inctx) { - struct usb_xhci_s *xhci = container_of(hub->cntl, struct usb_xhci_s, usb); - u32 portsc = readl(&xhci->pr[port].portsc); - int rc; + 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); +}
- switch (xhci_get_field(portsc, XHCI_PORTSC_PLS)) { - case PLS_U0: - rc = speed_from_xhci[xhci_get_field(portsc, XHCI_PORTSC_SPEED)]; - break; - case PLS_POLLING: - xhci_print_port_state(3, __func__, port, portsc); - portsc |= XHCI_PORTSC_PR; - writel(&xhci->pr[port].portsc, portsc); - if (wait_bit(&xhci->pr[port].portsc, XHCI_PORTSC_PED, XHCI_PORTSC_PED, 100) != 0) - return -1; - portsc = readl(&xhci->pr[port].portsc); - rc = speed_from_xhci[xhci_get_field(portsc, XHCI_PORTSC_SPEED)]; - break; - default: - rc = -1; - break; - } +static void xhci_xfer_setup(struct xhci_pipe *pipe, + const struct usb_ctrlrequest *req, + int dir, int datalen) +{ + struct xhci_trb trb;
- xhci_print_port_state(1, "XHCI", port, portsc); - return rc; + memset(&trb, 0, sizeof(trb)); + trb.ptr_low |= req->bRequestType; + trb.ptr_low |= (req->bRequest) << 8; + trb.ptr_low |= (req->wValue) << 16; + trb.ptr_high |= req->wIndex; + trb.ptr_high |= (req->wLength) << 16; + trb.status |= 8; // length + trb.control |= (TR_SETUP << 10); // trb type + trb.control |= TRB_TR_IDT; + if (datalen) + trb.control |= (dir ? 3 : 2) << 16; // transfer type + xhci_xfer_queue(pipe, &trb); }
-static void -xhci_hub_disconnect(struct usbhub_s *hub, u32 port) +static void xhci_xfer_data(struct xhci_pipe *pipe, + int dir, void *data, int datalen) { - // XXX - should turn the port power off. + struct xhci_trb trb; + + memset(&trb, 0, sizeof(trb)); + trb.ptr_low = (u32)data; + trb.status = datalen; + trb.control |= (TR_DATA << 10); // trb type + if (dir) + trb.control |= (1 << 16); + xhci_xfer_queue(pipe, &trb); }
-static struct usbhub_op_s xhci_hub_ops = { - .detect = xhci_hub_detect, - .reset = xhci_hub_reset, - .disconnect = xhci_hub_disconnect, -}; +static void xhci_xfer_status(struct xhci_pipe *pipe, int dir, int datalen) +{ + struct xhci_trb trb;
-// -------------------------------------------------------------- -// external interface + memset(&trb, 0, sizeof(trb)); + trb.control |= (TR_STATUS << 10); // trb type + trb.control |= TRB_TR_IOC; + if (!datalen || !dir) + trb.control |= (1 << 16);
+ xhci_xfer_queue(pipe, &trb); + xhci_xfer_kick(pipe); +}
static struct xhci_inctx * xhci_alloc_inctx(struct usbdevice_s *usbdev, int maxepid) @@ -1082,96 +1180,3 @@ xhci_poll_intr(struct usb_pipe *p, void *data) xhci_xfer_normal(pipe, buf, len); return 0; } - -static void -xhci_controller_setup(struct pci_device *pci) -{ - struct usb_xhci_s *xhci = malloc_high(sizeof(*xhci)); - if (!xhci) { - warn_noalloc(); - return; - } - memset(xhci, 0, sizeof(*xhci)); - - wait_preempt(); // Avoid pci_config_readl when preempting - xhci->baseaddr = pci_config_readl(pci->bdf, PCI_BASE_ADDRESS_0) - & PCI_BASE_ADDRESS_MEM_MASK; - xhci->caps = (void*)(xhci->baseaddr); - xhci->op = (void*)(xhci->baseaddr + readb(&xhci->caps->caplength)); - xhci->pr = (void*)(xhci->baseaddr + readb(&xhci->caps->caplength) + 0x400); - xhci->db = (void*)(xhci->baseaddr + readl(&xhci->caps->dboff)); - xhci->ir = (void*)(xhci->baseaddr + readl(&xhci->caps->rtsoff) + 0x20); - - u32 hcs1 = readl(&xhci->caps->hcsparams1); - u32 hcc = readl(&xhci->caps->hccparams); - xhci->ports = (hcs1 >> 24) & 0xff; - xhci->slots = hcs1 & 0xff; - xhci->xcap = ((hcc >> 16) & 0xffff) << 2; - xhci->context64 = (hcc & 0x04) ? 1 : 0; - - xhci->usb.pci = pci; - xhci->usb.type = USB_TYPE_XHCI; - xhci->hub.cntl = &xhci->usb; - xhci->hub.portcount = xhci->ports; - xhci->hub.op = &xhci_hub_ops; - - dprintf(1, "XHCI init on dev %02x:%02x.%x: regs @ %p, %d ports, %d slots" - ", %d byte contexts\n" - , pci_bdf_to_bus(pci->bdf), pci_bdf_to_dev(pci->bdf) - , pci_bdf_to_fn(pci->bdf), xhci->caps - , xhci->ports, xhci->slots, xhci->context64 ? 64 : 32); - - if (xhci->xcap) { - u32 off, addr = xhci->baseaddr + xhci->xcap; - do { - struct xhci_xcap *xcap = (void*)addr; - u32 ports, name, cap = readl(&xcap->cap); - switch (cap & 0xff) { - case 0x02: - name = readl(&xcap->data[0]); - ports = readl(&xcap->data[1]); - dprintf(1, "XHCI protocol %c%c%c%c %x.%02x" - ", %d ports (offset %d), def %x\n" - , (name >> 0) & 0xff - , (name >> 8) & 0xff - , (name >> 16) & 0xff - , (name >> 24) & 0xff - , (cap >> 24) & 0xff - , (cap >> 16) & 0xff - , (ports >> 8) & 0xff - , (ports >> 0) & 0xff - , ports >> 16); - break; - default: - dprintf(1, "XHCI extcap 0x%x @ %x\n", cap & 0xff, addr); - break; - } - off = (cap >> 8) & 0xff; - addr += off << 2; - } while (off > 0); - } - - u32 pagesize = readl(&xhci->op->pagesize); - if (PAGE_SIZE != (pagesize<<12)) { - dprintf(1, "XHCI driver does not support page size code %d\n" - , pagesize<<12); - free(xhci); - return; - } - - pci_config_maskw(pci->bdf, PCI_COMMAND, 0, PCI_COMMAND_MASTER); - - run_thread(configure_xhci, xhci); -} - -void -xhci_setup(void) -{ - if (! CONFIG_USB_XHCI) - return; - struct pci_device *pci; - foreachpci(pci) { - if (pci_classprog(pci) == PCI_CLASS_SERIAL_USB_XHCI) - xhci_controller_setup(pci); - } -}
Add these two functions so that the xhci code is more similar to the other USB controllers. Also, store the temporary hub structure on the stack instead of in struct usb_xhci_s.
Signed-off-by: Kevin O'Connor kevin@koconnor.net --- src/hw/usb-xhci.c | 37 +++++++++++++++++++++++++++---------- 1 file changed, 27 insertions(+), 10 deletions(-)
diff --git a/src/hw/usb-xhci.c b/src/hw/usb-xhci.c index 0e22547..87e5e64 100644 --- a/src/hw/usb-xhci.c +++ b/src/hw/usb-xhci.c @@ -228,7 +228,6 @@ struct xhci_ring {
struct usb_xhci_s { struct usb_s usb; - struct usbhub_s hub;
/* devinfo */ u32 baseaddr; @@ -393,12 +392,34 @@ static struct usbhub_op_s xhci_hub_ops = { .disconnect = xhci_hub_disconnect, };
+// Find any devices connected to the root hub. +static int +xhci_check_ports(struct usb_xhci_s *xhci) +{ + // FIXME: try find a more elegant way than a fixed delay + msleep(100); + + struct usbhub_s hub; + memset(&hub, 0, sizeof(hub)); + hub.cntl = &xhci->usb; + hub.portcount = xhci->ports; + hub.op = &xhci_hub_ops; + usb_enumerate(&hub); + return hub.devcount; +} +
/**************************************************************** * Setup ****************************************************************/
static void +xhci_free_pipes(struct usb_xhci_s *xhci) +{ + // XXX - should walk list of pipes and free unused pipes. +} + +static void configure_xhci(void *data) { struct usb_xhci_s *xhci = data; @@ -472,12 +493,11 @@ configure_xhci(void *data) reg |= XHCI_CMD_RS; writel(&xhci->op->usbcmd, reg);
- // FIXME: try find a more elegant way than a fixed delay - msleep(100); - - usb_enumerate(&xhci->hub); - // XXX - should walk list of pipes and free unused pipes. - if (xhci->hub.devcount) + // Find devices + int count = xhci_check_ports(xhci); + xhci_free_pipes(xhci); + if (count) + // Success return;
// No devices found - shutdown and free controller. @@ -523,9 +543,6 @@ xhci_controller_setup(struct pci_device *pci)
xhci->usb.pci = pci; xhci->usb.type = USB_TYPE_XHCI; - xhci->hub.cntl = &xhci->usb; - xhci->hub.portcount = xhci->ports; - xhci->hub.op = &xhci_hub_ops;
dprintf(1, "XHCI init on dev %02x:%02x.%x: regs @ %p, %d ports, %d slots" ", %d byte contexts\n"