Date: Sat, 31 Jul 2010 14:54:59 GMT From: Hans Petter Selasky <hselasky@FreeBSD.org> To: Perforce Change Reviews <perforce@FreeBSD.org> Subject: PERFORCE change 181646 for review Message-ID: <201007311454.o6VEsxL3078511@repoman.freebsd.org>
next in thread | raw e-mail | index | archive | help
http://p4web.freebsd.org/@@181646?ac=10 Change 181646 by hselasky@hselasky_laptop001 on 2010/07/31 14:53:59 USB controller (XHCI): - add more initialisation logic and register definitions Affected files ... .. //depot/projects/usb/src/sys/dev/usb/controller/xhci.c#3 edit .. //depot/projects/usb/src/sys/dev/usb/controller/xhci.h#5 edit .. //depot/projects/usb/src/sys/dev/usb/controller/xhcireg.h#6 edit Differences ... ==== //depot/projects/usb/src/sys/dev/usb/controller/xhci.c#3 (text+ko) ==== @@ -112,29 +112,187 @@ void xhci_iterate_hw_softc(struct usb_bus *bus, usb_bus_mem_sub_cb_t *cb) { + struct xhci_softc *sc = XHCI_BUS2SC(bus); + cb(bus, &sc->sc_hw.root_pc, &sc->sc_hw.root_pg, + sizeof(struct xhci_hw_root), XHCI_PAGE_SIZE); + cb(bus, &sc->sc_ctx.root_pc, &sc->sc_ctx.root_pg, + sizeof(struct xhci_ctx_root), XHCI_PAGE_SIZE); } -usb_error_t -xhci_reset(struct xhci_softc *sc) +static usb_error_t +xhci_start_controller(struct xhci_softc *sc) { + struct usb_page_search buf_res; + struct xhci_hw_root *phwr; + struct xhci_ctx_root *pctxr; + uint64_t addr; + uint32_t temp; + uint16_t i; + + DPRINTF("\n"); + + sc->sc_capa_off = 0; + sc->sc_oper_off = XREAD4(sc, capa, XHCI_CAPLENGTH); + sc->sc_runt_off = XREAD4(sc, capa, XHCI_RTSOFF) & ~0xF; + sc->sc_door_off = XREAD4(sc, capa, XHCI_DBOFF) & ~0x3; + + DPRINTF("xHCI version = 0x%04x\n", XREAD2(sc, capa, XHCI_HCIVERSION)); + + /* Reset controller */ + XWRITE4(sc, oper, XHCI_USBCMD, XHCI_CMD_HCRST); + + for (i = 0; i != 100; i++) { + usb_pause_mtx(NULL, hz / 1000); + temp = XREAD4(sc, XHCI_USBCMD) & XHCI_CMD_HCRST; + if (!temp) + break; + } + + if (temp) { + device_printf(sc->sc_bus.bdev, "Controller reset timeout.\n"); + return (USB_ERR_IOERROR); + } + + if (!(XREAD4(sc, oper, XHCI_PAGESIZE) & XHCI_PAGESIZE_4K)) { + device_printf(sc->sc_bus.bdev, "Controller does not support 4K page size.\n"); + return (USB_ERR_IOERROR); + } + + temp = XREAD4(sc, oper, XHCI_USBSTS); + + /* clear interrupts */ + XWRITE4(sc, oper, XHCI_USBSTS, status); + + /* disable all device notifications */ + XWRITE4(sc, oper, XHCI_DNCTRL, 0); + + /* setup device context base address */ + + usbd_get_page(&sc->sc_hw.ctx_pc, 0, &buf_res); + + addr = buf_res.physaddr; + pctxr = buf_res.ptr; + + memset(pctxr, 0, sizeof(*pctxr)); + + XWRITE4(sc, oper, XHCI_DCBAAP_LO, (uint32_t)addr); + XWRITE4(sc, oper, XHCI_DCBAAP_HI, (uint32_t)(addr >> 32)); + + /* setup number of device slots */ + + XWRITE4(sc, oper, XHCI_CONFIG, XHCI_MAX_DEVICES); + + /* Setup interrupter registers */ + + temp = XREAD4(sc, runt, XHCI_IMAN(0)); + temp |= XHCI_IMAN_IE_BIT | XHCI_IMAN_IP_BIT; + XWRITE4(sc, runt, XHCI_IMAN(0)); + + /* Setup interrupt rate */ + + XWRITE4(sc, runt, XHCI_IMOD, XHCI_IMOD_DEFAULT); + + usbd_get_page(&sc->sc_hw.root_pc, 0, &buf_res); + + phwr = buf_res.ptr; + addr = (uint64_t)buf_res.physaddr + (uintptr_t)&((struct xhci_hw_root *)0)->hwr_events[0]; + + /* reset hardware root structure */ + + memset(phwr, 0, sizeof(*phwr)); + + phwr->hwr_ring_seg[0].qwEvrsTablePtr = htole64(addr); + phwr->hwr_ring_seg[0].dwEvrsTableSize = htole32(XHCI_MAX_EVENTS); + + /* Setup event table size */ + + temp = XREAD4(sc, capa, XHCI_HCSPARAMS2); + + DPRINTF("hcsparams2=0x%08x\n", temp); + + temp = XHCI_HCS2_ERST_MAX(temp); + temp = 1U << temp; + if (temp > XHCI_MAX_RSEG) + temp = XHCI_MAX_RSEG; + + sc->sc_erst_max = temp; + + XWRITE4(sc, runt, XHCI_ERSTSZ(0), temp); + + XWRITE4(sc, oper, XHCI_ERDP_LO(0), (uint32_t)addr); + XWRITE4(sc, oper, XHCI_ERDP_HI(0), (uint32_t)(addr >> 32)); + + addr = (uint64_t)buf_res.physaddr; + + XWRITE4(sc, oper, XHCI_ERSTBA_LO(0), (uint32_t)addr); + XWRITE4(sc, oper, XHCI_ERSTBA_HI(0), (uint32_t)(addr >> 32)); + + /* setup command ring control base address */ + + addr = (uint64_t)buf_res.physaddr + (uintptr_t)&((struct xhci_hw_root *)0)->hwr_commands[0]; + + XWRITE4(sc, oper, XHCI_CRCR_LO, (uint32_t)addr); + XWRITE4(sc, oper, XHCI_CRCR_HI, (uint32_t)(addr >> 32)); + + usb_bus_mem_flush_all(&sc->sc_bus, &ehci_iterate_hw_softc); + + /* Go! */ + XWRITE4(sc, oper, XHCI_USBCMD, XHCI_CMD_RS | XHCI_CMD_INTE | XHCI_CMD_HSEE); + + for (i = 0; i != 100; i++) { + usb_pause_mtx(NULL, hz / 1000); + temp = XREAD4(sc, oper, XHCI_USBSTS) & XHCI_STS_HCH; + if (!temp) + break; + } + if (temp) { + device_printf(sc->sc_bus.bdev, "Run timeout.\n"); + return (USB_ERR_IOERROR); + } + /* catch any lost interrupts */ + xhci_do_poll(&sc->sc_bus); + return (0); } static usb_error_t -xhci_hcreset(struct xhci_softc *sc) +xhci_halt_controller(struct xhci_softc *sc) { + uint32_t temp; + uint16_t i; + + DPRINTF("\n"); + /* Halt controller */ + XWRITE4(sc, oper, XHCI_USBCMD, 0); + + for (i = 0; i != 100; i++) { + usb_pause_mtx(NULL, hz / 1000); + temp = XREAD4(sc, oper, XHCI_USBSTS) & XHCI_STS_HCH; + if (temp) + break; + } + if (!temp) { + device_printf(sc->sc_bus.bdev, "Controller halt timeout.\n"); + return (USB_ERR_IOERROR); + } + return (0); } usb_error_t xhci_init(struct xhci_softc *sc) { + /* set the bus revision */ + sc->sc_bus.usbrev = USB_REV_3_0; + /* set up the bus struct */ + sc->sc_bus.methods = &ehci_bus_methods; + return (0); } void @@ -165,17 +323,6 @@ } -static void -xhci_transfer_intr_enqueue(struct usb_xfer *xfer) -{ - /* check for early completion */ - if (xhci_check_transfer(xfer)) - return; - - /* put transfer on interrupt queue */ - usbd_transfer_enqueue(&xfer->xroot->bus->intr_q, xfer); -} - static usb_error_t xhci_generic_done_sub(struct usb_xfer *xfer) { @@ -377,12 +524,6 @@ } static void -xhci_pcd_enable(struct xhci_softc *sc) -{ - -} - -static void xhci_interrupt_poll(struct xhci_softc *sc) { struct usb_xfer *xfer; @@ -405,8 +546,40 @@ void xhci_interrupt(struct xhci_softc *sc) { + uint32_t status; + + USB_BUS_LOCK(&sc->sc_bus); + + DPRINTFN(16, "real interrupt\n"); + + status = XREAD4(sc, oper, XHCI_USBSTS); + + if (status & XHCI_STS_PCD) { + xhci_root_intr(sc); + } + + if (status & XHCI_STS_HCH) { + printf("%s: host controller halted\n", + __FUNCTION__); + } + if (status & XHCI_STS_HSE) { + printf("%s: host system error\n", + __FUNCTION__); + } + if (status & XHCI_STS_HCE) { + printf("%s: host controller error\n", + __FUNCTION__); + } + + /* acknowledge interrupts */ + + XWRITE4(sc, oper, XHCI_USBSTS, status); + + xhci_interrupt_poll(sc); + + USB_BUS_UNLOCK(&sc->sc_bus); } /*------------------------------------------------------------------------* @@ -873,7 +1046,26 @@ static void xhci_root_intr(struct xhci_softc *sc) { + uint16_t i; + + USB_BUS_LOCK_ASSERT(&sc->sc_bus, MA_OWNED); + /* clear any old interrupt data */ + memset(sc->sc_hub_idata, 0, sizeof(sc->sc_hub_idata)); + + for (i = 1; i <= sc->sc_noport; i++) { + /* pick out CHANGE bits from the status register */ + if (XREAD4(sc, oper, XHCI_PORTSC(i)) & ( + XHCI_PS_CSC | XHCI_PS_PEC | + XHCI_PS_OCC | XHCI_PS_WRC | + XHCI_PS_PRC | XHCI_PS_PLC | + XHCI_PS_CEC)) { + sc->sc_hub_idata[i / 8] |= 1 << (i % 8); + DPRINTF("port %d changed\n", i); + } + } + uhub_root_intr(&sc->sc_bus, sc->sc_hub_idata, + sizeof(sc->sc_hub_idata)); } /*------------------------------------------------------------------------* @@ -918,7 +1110,7 @@ xhci_setup_generic_chain(xfer); /* put transfer on interrupt queue */ - xhci_transfer_intr_enqueue(xfer); + usbd_transfer_enqueue(&xfer->xroot->bus->intr_q, xfer); } static void @@ -986,8 +1178,8 @@ .bmAttributes = XXX, HSETW(.wSpeedsSupported, 0x000C), .bFunctionalitySupport = 8, - .bU1DevExitLat = 128, /* dummy - not used */ - .bU2DevExitLat = 128, /* dummy - not used */ + .bU1DevExitLat = 255, /* dummy - not used */ + .bU2DevExitLat = 255, /* dummy - not used */ }, .cidd = { .bLength = sizeof(xhci_bosd.cidd), ==== //depot/projects/usb/src/sys/dev/usb/controller/xhci.h#5 (text+ko) ==== @@ -31,6 +31,7 @@ #define XHCI_MAX_SCRATCHPADS 32 #define XHCI_MAX_EVENTS (16 * 7) #define XHCI_MAX_COMMANDS (16 * 7) +#define XHCI_MAX_RSEG 1 #define XHCI_DEV_CTX_ADDR_ALIGN 64 /* bytes */ #define XHCI_DEV_CTX_ALIGN 64 /* bytes */ @@ -46,6 +47,7 @@ #define XHCI_TRB_ALIGN 16 /* bytes */ #define XHCI_QH_ALIGN 16 /* bytes */ #define XHCI_TD_ALIGN 16 /* bytes */ +#define XHCI_PAGE_SIZE 4096 /* bytes */ struct xhci_dev_ctx_addr { volatile uint64_t qwBaaDevCtxAddr; @@ -318,11 +320,16 @@ }; struct xhci_hw_root { - struct xhci_event_ring_seg hwr_ring_seg[4]; + struct xhci_event_ring_seg hwr_ring_seg[XHCI_MAX_RSEG]; + volatile uint64_t hwr_padding[2]; struct xhci_trb hwr_events[XHCI_MAX_EVENTS]; struct xhci_trb hwr_commands[XHCI_MAX_COMMANDS]; }; +struct xhci_ctx_root { + volatile uint64_t ctxr_ptr[XHCI_MAX_DEVICES]; +}; + struct xhci_endpoint_ext { TAILQ_HEAD(, xhci_qh) head; @@ -335,16 +342,24 @@ uint8_t pstreams; }; +struct xhci_hw_dev { + struct usb_page_cache device_pc; + struct usb_page_cache input_pc; + struct usb_page_cache scratch_pc[XHCI_MAX_SCRATCHPADS]; + + struct usb_page device_pg; + struct usb_page input_pg; + struct usb_page scratch_pg[XHCI_MAX_SCRATCHPADS]; +}; + struct xhci_hw_softc { struct usb_page_cache root_pc; - struct usb_page_cache device_pc[XHCI_MAX_DEVICES]; - struct usb_page_cache device_input_pc[XHCI_MAX_DEVICES]; - struct usb_page_cache device_sp_pc[XHCI_MAX_DEVICES][XHCI_MAX_SCRATCHPADS]; + struct usb_page_cache ctx_pc; struct usb_page root_pg; - struct usb_page device_pg[XHCI_MAX_DEVICES]; - struct usb_page device_input_pg[XHCI_MAX_DEVICES]; - struct usb_page device_sp_pg[XHCI_MAX_DEVICES][XHCI_MAX_SCRATCHPADS]; + sturct usb_page ctx_pg; + + struct xhci_hw_dev devs[XHCI_MAX_DEVICES]; }; struct xhci_config_desc { @@ -383,17 +398,15 @@ bus_space_tag_t sc_io_tag; bus_space_handle_t sc_io_hdl; - uint32_t sc_eintrs; - uint32_t sc_cmd; /* shadow of cmd register during - * suspend */ + uint32_t sc_cmd; /* copy of cmd register */ + + uint32_t sc_oper_off; /* offset to operational registers */ + uint32_t sc_capa_off; /* offset to capability registers */ + uint32_t sc_runt_off; /* offset to runtime registers */ + uint32_t sc_door_off; /* offset to doorbell registers */ uint16_t sc_flags; /* chip specific flags */ - - uint16_t sc_pcib_off; /* offset to PCI registers */ - uint16_t sc_oper_off; /* offset to operational registers */ - uint16_t sc_capa_off; /* offset to capability registers */ - uint16_t sc_runt_off; /* offset to runtime registers */ - uint16_t sc_door_off; /* offset to doorbell registers */ + uint16_t sc_erst_max; uint8_t sc_noport; /* number of ports on root HUB */ uint8_t sc_addr; /* root HUB device address */ ==== //depot/projects/usb/src/sys/dev/usb/controller/xhcireg.h#6 (text+ko) ==== @@ -64,9 +64,7 @@ #define XHCI_HCS0_PSA_SZ_MAX(x) (((x) >> 12) & 0xF) /* max pri. stream array size */ #define XHCI_HCS0_XECP(x) (((x) >> 16) & 0xFFFF) /* extended capabilities pointer */ #define XHCI_DBOFF 0x14 /* RO doorbell offset */ -#define XHCI_DBOFF_GET(x) (((x) >> 2) & 0x3FFFFFFF) #define XHCI_RTSOFF 0x18 /* RO runtime register space offset */ -#define XHCI_RTSOFF_GET(x) (((x) >> 5) & 0x7FFFFFF) /* XHCI operational registers. Offset given by XHCI_CAPLENGTH register */ #define XHCI_USBCMD 0x00 /* XHCI command */
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201007311454.o6VEsxL3078511>