1246122Shselasky/* $FreeBSD: releng/10.2/sys/dev/usb/controller/xhci.c 279648 2015-03-05 10:18:03Z hselasky $ */ 2213379Shselasky/*- 3213379Shselasky * Copyright (c) 2010 Hans Petter Selasky. All rights reserved. 4213379Shselasky * 5213379Shselasky * Redistribution and use in source and binary forms, with or without 6213379Shselasky * modification, are permitted provided that the following conditions 7213379Shselasky * are met: 8213379Shselasky * 1. Redistributions of source code must retain the above copyright 9213379Shselasky * notice, this list of conditions and the following disclaimer. 10213379Shselasky * 2. Redistributions in binary form must reproduce the above copyright 11213379Shselasky * notice, this list of conditions and the following disclaimer in the 12213379Shselasky * documentation and/or other materials provided with the distribution. 13213379Shselasky * 14213379Shselasky * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15213379Shselasky * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16213379Shselasky * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17213379Shselasky * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18213379Shselasky * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19213379Shselasky * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20213379Shselasky * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21213379Shselasky * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22213379Shselasky * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23213379Shselasky * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24213379Shselasky * SUCH DAMAGE. 25213379Shselasky */ 26213379Shselasky 27213379Shselasky/* 28213379Shselasky * USB eXtensible Host Controller Interface, a.k.a. USB 3.0 controller. 29213379Shselasky * 30213379Shselasky * The XHCI 1.0 spec can be found at 31213379Shselasky * http://www.intel.com/technology/usb/download/xHCI_Specification_for_USB.pdf 32213379Shselasky * and the USB 3.0 spec at 33213379Shselasky * http://www.usb.org/developers/docs/usb_30_spec_060910.zip 34213379Shselasky */ 35213379Shselasky 36213379Shselasky/* 37213379Shselasky * A few words about the design implementation: This driver emulates 38213379Shselasky * the concept about TDs which is found in EHCI specification. This 39248554Shselasky * way we achieve that the USB controller drivers look similar to 40248554Shselasky * eachother which makes it easier to understand the code. 41213379Shselasky */ 42213379Shselasky 43246122Shselasky#ifdef USB_GLOBAL_INCLUDE_FILE 44246122Shselasky#include USB_GLOBAL_INCLUDE_FILE 45246122Shselasky#else 46213379Shselasky#include <sys/stdint.h> 47213379Shselasky#include <sys/stddef.h> 48213379Shselasky#include <sys/param.h> 49213379Shselasky#include <sys/queue.h> 50213379Shselasky#include <sys/types.h> 51213379Shselasky#include <sys/systm.h> 52213379Shselasky#include <sys/kernel.h> 53213379Shselasky#include <sys/bus.h> 54213379Shselasky#include <sys/module.h> 55213379Shselasky#include <sys/lock.h> 56213379Shselasky#include <sys/mutex.h> 57213379Shselasky#include <sys/condvar.h> 58213379Shselasky#include <sys/sysctl.h> 59213379Shselasky#include <sys/sx.h> 60213379Shselasky#include <sys/unistd.h> 61213379Shselasky#include <sys/callout.h> 62213379Shselasky#include <sys/malloc.h> 63213379Shselasky#include <sys/priv.h> 64213379Shselasky 65213379Shselasky#include <dev/usb/usb.h> 66213379Shselasky#include <dev/usb/usbdi.h> 67213379Shselasky 68213379Shselasky#define USB_DEBUG_VAR xhcidebug 69213379Shselasky 70213379Shselasky#include <dev/usb/usb_core.h> 71213379Shselasky#include <dev/usb/usb_debug.h> 72213379Shselasky#include <dev/usb/usb_busdma.h> 73213379Shselasky#include <dev/usb/usb_process.h> 74213379Shselasky#include <dev/usb/usb_transfer.h> 75213379Shselasky#include <dev/usb/usb_device.h> 76213379Shselasky#include <dev/usb/usb_hub.h> 77213379Shselasky#include <dev/usb/usb_util.h> 78213379Shselasky 79213379Shselasky#include <dev/usb/usb_controller.h> 80213379Shselasky#include <dev/usb/usb_bus.h> 81246122Shselasky#endif /* USB_GLOBAL_INCLUDE_FILE */ 82246122Shselasky 83213379Shselasky#include <dev/usb/controller/xhci.h> 84213379Shselasky#include <dev/usb/controller/xhcireg.h> 85213379Shselasky 86213379Shselasky#define XHCI_BUS2SC(bus) \ 87213379Shselasky ((struct xhci_softc *)(((uint8_t *)(bus)) - \ 88213379Shselasky ((uint8_t *)&(((struct xhci_softc *)0)->sc_bus)))) 89213379Shselasky 90255347Shselaskystatic SYSCTL_NODE(_hw_usb, OID_AUTO, xhci, CTLFLAG_RW, 0, "USB XHCI"); 91255347Shselasky 92255347Shselaskystatic int xhcistreams; 93255347ShselaskySYSCTL_INT(_hw_usb_xhci, OID_AUTO, streams, CTLFLAG_RW | CTLFLAG_TUN, 94255347Shselasky &xhcistreams, 0, "Set to enable streams mode support"); 95255347ShselaskyTUNABLE_INT("hw.usb.xhci.streams", &xhcistreams); 96255347Shselasky 97213379Shselasky#ifdef USB_DEBUG 98239617Shselaskystatic int xhcidebug; 99239617Shselaskystatic int xhciroute; 100251499Shselaskystatic int xhcipolling; 101279648Shselaskystatic int xhcidma32; 102213379Shselasky 103242126ShselaskySYSCTL_INT(_hw_usb_xhci, OID_AUTO, debug, CTLFLAG_RW | CTLFLAG_TUN, 104213379Shselasky &xhcidebug, 0, "Debug level"); 105242126ShselaskyTUNABLE_INT("hw.usb.xhci.debug", &xhcidebug); 106242126ShselaskySYSCTL_INT(_hw_usb_xhci, OID_AUTO, xhci_port_route, CTLFLAG_RW | CTLFLAG_TUN, 107279648Shselasky &xhciroute, 0, "Routing bitmap for switching EHCI ports to the XHCI controller"); 108239617ShselaskyTUNABLE_INT("hw.usb.xhci.xhci_port_route", &xhciroute); 109251499ShselaskySYSCTL_INT(_hw_usb_xhci, OID_AUTO, use_polling, CTLFLAG_RW | CTLFLAG_TUN, 110279648Shselasky &xhcipolling, 0, "Set to enable software interrupt polling for the XHCI controller"); 111251499ShselaskyTUNABLE_INT("hw.usb.xhci.use_polling", &xhcipolling); 112279648ShselaskySYSCTL_INT(_hw_usb_xhci, OID_AUTO, dma32, CTLFLAG_RWTUN, 113279648Shselasky &xhcidma32, 0, "Set to only use 32-bit DMA for the XHCI controller"); 114279648ShselaskyTUNABLE_INT("hw.usb.xhci.dma32", &xhcidma32); 115255768Shselasky#else 116255768Shselasky#define xhciroute 0 117279648Shselasky#define xhcidma32 0 118213379Shselasky#endif 119213379Shselasky 120213379Shselasky#define XHCI_INTR_ENDPT 1 121213379Shselasky 122213379Shselaskystruct xhci_std_temp { 123213379Shselasky struct xhci_softc *sc; 124213379Shselasky struct usb_page_cache *pc; 125213379Shselasky struct xhci_td *td; 126213379Shselasky struct xhci_td *td_next; 127213379Shselasky uint32_t len; 128213379Shselasky uint32_t offset; 129213379Shselasky uint32_t max_packet_size; 130213379Shselasky uint32_t average; 131213379Shselasky uint16_t isoc_delta; 132213379Shselasky uint16_t isoc_frame; 133213379Shselasky uint8_t shortpkt; 134213379Shselasky uint8_t multishort; 135213379Shselasky uint8_t last_frame; 136213379Shselasky uint8_t trb_type; 137213379Shselasky uint8_t direction; 138213379Shselasky uint8_t tbc; 139213379Shselasky uint8_t tlbpc; 140213379Shselasky uint8_t step_td; 141234803Shselasky uint8_t do_isoc_sync; 142213379Shselasky}; 143213379Shselasky 144213379Shselaskystatic void xhci_do_poll(struct usb_bus *); 145213379Shselaskystatic void xhci_device_done(struct usb_xfer *, usb_error_t); 146213379Shselaskystatic void xhci_root_intr(struct xhci_softc *); 147213379Shselaskystatic void xhci_free_device_ext(struct usb_device *); 148213379Shselaskystatic struct xhci_endpoint_ext *xhci_get_endpoint_ext(struct usb_device *, 149213379Shselasky struct usb_endpoint_descriptor *); 150213379Shselaskystatic usb_proc_callback_t xhci_configure_msg; 151213379Shselaskystatic usb_error_t xhci_configure_device(struct usb_device *); 152213379Shselaskystatic usb_error_t xhci_configure_endpoint(struct usb_device *, 153251247Shselasky struct usb_endpoint_descriptor *, struct xhci_endpoint_ext *, 154251247Shselasky uint16_t, uint8_t, uint8_t, uint8_t, uint16_t, uint16_t, 155251247Shselasky uint8_t); 156213379Shselaskystatic usb_error_t xhci_configure_mask(struct usb_device *, 157213379Shselasky uint32_t, uint8_t); 158213379Shselaskystatic usb_error_t xhci_cmd_evaluate_ctx(struct xhci_softc *, 159213379Shselasky uint64_t, uint8_t); 160213379Shselaskystatic void xhci_endpoint_doorbell(struct usb_xfer *); 161217374Shselaskystatic void xhci_ctx_set_le32(struct xhci_softc *sc, volatile uint32_t *ptr, uint32_t val); 162217374Shselaskystatic uint32_t xhci_ctx_get_le32(struct xhci_softc *sc, volatile uint32_t *ptr); 163217374Shselaskystatic void xhci_ctx_set_le64(struct xhci_softc *sc, volatile uint64_t *ptr, uint64_t val); 164217374Shselasky#ifdef USB_DEBUG 165217374Shselaskystatic uint64_t xhci_ctx_get_le64(struct xhci_softc *sc, volatile uint64_t *ptr); 166217374Shselasky#endif 167213379Shselasky 168213379Shselaskyextern struct usb_bus_methods xhci_bus_methods; 169213379Shselasky 170213379Shselasky#ifdef USB_DEBUG 171213379Shselaskystatic void 172213379Shselaskyxhci_dump_trb(struct xhci_trb *trb) 173213379Shselasky{ 174213379Shselasky DPRINTFN(5, "trb = %p\n", trb); 175213379Shselasky DPRINTFN(5, "qwTrb0 = 0x%016llx\n", (long long)le64toh(trb->qwTrb0)); 176213379Shselasky DPRINTFN(5, "dwTrb2 = 0x%08x\n", le32toh(trb->dwTrb2)); 177213379Shselasky DPRINTFN(5, "dwTrb3 = 0x%08x\n", le32toh(trb->dwTrb3)); 178213379Shselasky} 179213379Shselasky 180213379Shselaskystatic void 181217374Shselaskyxhci_dump_endpoint(struct xhci_softc *sc, struct xhci_endp_ctx *pep) 182213379Shselasky{ 183213379Shselasky DPRINTFN(5, "pep = %p\n", pep); 184217374Shselasky DPRINTFN(5, "dwEpCtx0=0x%08x\n", xhci_ctx_get_le32(sc, &pep->dwEpCtx0)); 185217374Shselasky DPRINTFN(5, "dwEpCtx1=0x%08x\n", xhci_ctx_get_le32(sc, &pep->dwEpCtx1)); 186217374Shselasky DPRINTFN(5, "qwEpCtx2=0x%016llx\n", (long long)xhci_ctx_get_le64(sc, &pep->qwEpCtx2)); 187217374Shselasky DPRINTFN(5, "dwEpCtx4=0x%08x\n", xhci_ctx_get_le32(sc, &pep->dwEpCtx4)); 188217374Shselasky DPRINTFN(5, "dwEpCtx5=0x%08x\n", xhci_ctx_get_le32(sc, &pep->dwEpCtx5)); 189217374Shselasky DPRINTFN(5, "dwEpCtx6=0x%08x\n", xhci_ctx_get_le32(sc, &pep->dwEpCtx6)); 190217374Shselasky DPRINTFN(5, "dwEpCtx7=0x%08x\n", xhci_ctx_get_le32(sc, &pep->dwEpCtx7)); 191213379Shselasky} 192213379Shselasky 193213379Shselaskystatic void 194217374Shselaskyxhci_dump_device(struct xhci_softc *sc, struct xhci_slot_ctx *psl) 195213379Shselasky{ 196213379Shselasky DPRINTFN(5, "psl = %p\n", psl); 197217374Shselasky DPRINTFN(5, "dwSctx0=0x%08x\n", xhci_ctx_get_le32(sc, &psl->dwSctx0)); 198217374Shselasky DPRINTFN(5, "dwSctx1=0x%08x\n", xhci_ctx_get_le32(sc, &psl->dwSctx1)); 199217374Shselasky DPRINTFN(5, "dwSctx2=0x%08x\n", xhci_ctx_get_le32(sc, &psl->dwSctx2)); 200217374Shselasky DPRINTFN(5, "dwSctx3=0x%08x\n", xhci_ctx_get_le32(sc, &psl->dwSctx3)); 201213379Shselasky} 202213379Shselasky#endif 203213379Shselasky 204251499Shselaskyuint8_t 205251499Shselaskyxhci_use_polling(void) 206251499Shselasky{ 207251499Shselasky#ifdef USB_DEBUG 208251499Shselasky return (xhcipolling != 0); 209251499Shselasky#else 210251499Shselasky return (0); 211251499Shselasky#endif 212251499Shselasky} 213251499Shselasky 214213379Shselaskystatic void 215213379Shselaskyxhci_iterate_hw_softc(struct usb_bus *bus, usb_bus_mem_sub_cb_t *cb) 216213379Shselasky{ 217213379Shselasky struct xhci_softc *sc = XHCI_BUS2SC(bus); 218213379Shselasky uint8_t i; 219213379Shselasky 220213379Shselasky cb(bus, &sc->sc_hw.root_pc, &sc->sc_hw.root_pg, 221213379Shselasky sizeof(struct xhci_hw_root), XHCI_PAGE_SIZE); 222213379Shselasky 223213379Shselasky cb(bus, &sc->sc_hw.ctx_pc, &sc->sc_hw.ctx_pg, 224213379Shselasky sizeof(struct xhci_dev_ctx_addr), XHCI_PAGE_SIZE); 225213379Shselasky 226213379Shselasky for (i = 0; i != XHCI_MAX_SCRATCHPADS; i++) { 227213379Shselasky cb(bus, &sc->sc_hw.scratch_pc[i], &sc->sc_hw.scratch_pg[i], 228213379Shselasky XHCI_PAGE_SIZE, XHCI_PAGE_SIZE); 229213379Shselasky } 230213379Shselasky} 231213379Shselasky 232217374Shselaskystatic void 233217374Shselaskyxhci_ctx_set_le32(struct xhci_softc *sc, volatile uint32_t *ptr, uint32_t val) 234217374Shselasky{ 235217374Shselasky if (sc->sc_ctx_is_64_byte) { 236217374Shselasky uint32_t offset; 237217374Shselasky /* exploit the fact that our structures are XHCI_PAGE_SIZE aligned */ 238217374Shselasky /* all contexts are initially 32-bytes */ 239217374Shselasky offset = ((uintptr_t)ptr) & ((XHCI_PAGE_SIZE - 1) & ~(31U)); 240217374Shselasky ptr = (volatile uint32_t *)(((volatile uint8_t *)ptr) + offset); 241217374Shselasky } 242217374Shselasky *ptr = htole32(val); 243217374Shselasky} 244217374Shselasky 245217374Shselaskystatic uint32_t 246217374Shselaskyxhci_ctx_get_le32(struct xhci_softc *sc, volatile uint32_t *ptr) 247217374Shselasky{ 248217374Shselasky if (sc->sc_ctx_is_64_byte) { 249217374Shselasky uint32_t offset; 250217374Shselasky /* exploit the fact that our structures are XHCI_PAGE_SIZE aligned */ 251217374Shselasky /* all contexts are initially 32-bytes */ 252217374Shselasky offset = ((uintptr_t)ptr) & ((XHCI_PAGE_SIZE - 1) & ~(31U)); 253217374Shselasky ptr = (volatile uint32_t *)(((volatile uint8_t *)ptr) + offset); 254217374Shselasky } 255217374Shselasky return (le32toh(*ptr)); 256217374Shselasky} 257217374Shselasky 258217374Shselaskystatic void 259217374Shselaskyxhci_ctx_set_le64(struct xhci_softc *sc, volatile uint64_t *ptr, uint64_t val) 260217374Shselasky{ 261217374Shselasky if (sc->sc_ctx_is_64_byte) { 262217374Shselasky uint32_t offset; 263217374Shselasky /* exploit the fact that our structures are XHCI_PAGE_SIZE aligned */ 264217374Shselasky /* all contexts are initially 32-bytes */ 265217374Shselasky offset = ((uintptr_t)ptr) & ((XHCI_PAGE_SIZE - 1) & ~(31U)); 266217374Shselasky ptr = (volatile uint64_t *)(((volatile uint8_t *)ptr) + offset); 267217374Shselasky } 268217374Shselasky *ptr = htole64(val); 269217374Shselasky} 270217374Shselasky 271217374Shselasky#ifdef USB_DEBUG 272217374Shselaskystatic uint64_t 273217374Shselaskyxhci_ctx_get_le64(struct xhci_softc *sc, volatile uint64_t *ptr) 274217374Shselasky{ 275217374Shselasky if (sc->sc_ctx_is_64_byte) { 276217374Shselasky uint32_t offset; 277217374Shselasky /* exploit the fact that our structures are XHCI_PAGE_SIZE aligned */ 278217374Shselasky /* all contexts are initially 32-bytes */ 279217374Shselasky offset = ((uintptr_t)ptr) & ((XHCI_PAGE_SIZE - 1) & ~(31U)); 280217374Shselasky ptr = (volatile uint64_t *)(((volatile uint8_t *)ptr) + offset); 281217374Shselasky } 282217374Shselasky return (le64toh(*ptr)); 283217374Shselasky} 284217374Shselasky#endif 285217374Shselasky 286259603Shselaskystatic int 287259603Shselaskyxhci_reset_command_queue_locked(struct xhci_softc *sc) 288259603Shselasky{ 289259603Shselasky struct usb_page_search buf_res; 290259603Shselasky struct xhci_hw_root *phwr; 291259603Shselasky uint64_t addr; 292259603Shselasky uint32_t temp; 293259603Shselasky 294259603Shselasky DPRINTF("\n"); 295259603Shselasky 296259603Shselasky temp = XREAD4(sc, oper, XHCI_CRCR_LO); 297259603Shselasky if (temp & XHCI_CRCR_LO_CRR) { 298259603Shselasky DPRINTF("Command ring running\n"); 299259603Shselasky temp &= ~(XHCI_CRCR_LO_CS | XHCI_CRCR_LO_CA); 300259603Shselasky 301259603Shselasky /* 302259603Shselasky * Try to abort the last command as per section 303259603Shselasky * 4.6.1.2 "Aborting a Command" of the XHCI 304259603Shselasky * specification: 305259603Shselasky */ 306259603Shselasky 307259603Shselasky /* stop and cancel */ 308259603Shselasky XWRITE4(sc, oper, XHCI_CRCR_LO, temp | XHCI_CRCR_LO_CS); 309259603Shselasky XWRITE4(sc, oper, XHCI_CRCR_HI, 0); 310259603Shselasky 311259603Shselasky XWRITE4(sc, oper, XHCI_CRCR_LO, temp | XHCI_CRCR_LO_CA); 312259603Shselasky XWRITE4(sc, oper, XHCI_CRCR_HI, 0); 313259603Shselasky 314259603Shselasky /* wait 250ms */ 315259603Shselasky usb_pause_mtx(&sc->sc_bus.bus_mtx, hz / 4); 316259603Shselasky 317259603Shselasky /* check if command ring is still running */ 318259603Shselasky temp = XREAD4(sc, oper, XHCI_CRCR_LO); 319259603Shselasky if (temp & XHCI_CRCR_LO_CRR) { 320259603Shselasky DPRINTF("Comand ring still running\n"); 321259603Shselasky return (USB_ERR_IOERROR); 322259603Shselasky } 323259603Shselasky } 324259603Shselasky 325259603Shselasky /* reset command ring */ 326259603Shselasky sc->sc_command_ccs = 1; 327259603Shselasky sc->sc_command_idx = 0; 328259603Shselasky 329259603Shselasky usbd_get_page(&sc->sc_hw.root_pc, 0, &buf_res); 330259603Shselasky 331278278Shselasky /* set up command ring control base address */ 332259603Shselasky addr = buf_res.physaddr; 333259603Shselasky phwr = buf_res.buffer; 334259603Shselasky addr += (uintptr_t)&((struct xhci_hw_root *)0)->hwr_commands[0]; 335259603Shselasky 336259603Shselasky DPRINTF("CRCR=0x%016llx\n", (unsigned long long)addr); 337259603Shselasky 338259603Shselasky memset(phwr->hwr_commands, 0, sizeof(phwr->hwr_commands)); 339259603Shselasky phwr->hwr_commands[XHCI_MAX_COMMANDS - 1].qwTrb0 = htole64(addr); 340259603Shselasky 341259603Shselasky usb_pc_cpu_flush(&sc->sc_hw.root_pc); 342259603Shselasky 343259603Shselasky XWRITE4(sc, oper, XHCI_CRCR_LO, ((uint32_t)addr) | XHCI_CRCR_LO_RCS); 344259603Shselasky XWRITE4(sc, oper, XHCI_CRCR_HI, (uint32_t)(addr >> 32)); 345259603Shselasky 346259603Shselasky return (0); 347259603Shselasky} 348259603Shselasky 349213379Shselaskyusb_error_t 350213379Shselaskyxhci_start_controller(struct xhci_softc *sc) 351213379Shselasky{ 352213379Shselasky struct usb_page_search buf_res; 353213379Shselasky struct xhci_hw_root *phwr; 354213379Shselasky struct xhci_dev_ctx_addr *pdctxa; 355213379Shselasky uint64_t addr; 356213379Shselasky uint32_t temp; 357213379Shselasky uint16_t i; 358213379Shselasky 359213379Shselasky DPRINTF("\n"); 360213379Shselasky 361213379Shselasky sc->sc_event_ccs = 1; 362213379Shselasky sc->sc_event_idx = 0; 363213379Shselasky sc->sc_command_ccs = 1; 364213379Shselasky sc->sc_command_idx = 0; 365213379Shselasky 366213379Shselasky /* Reset controller */ 367213379Shselasky XWRITE4(sc, oper, XHCI_USBCMD, XHCI_CMD_HCRST); 368213379Shselasky 369213379Shselasky for (i = 0; i != 100; i++) { 370227541Shselasky usb_pause_mtx(NULL, hz / 100); 371260537Shselasky temp = (XREAD4(sc, oper, XHCI_USBCMD) & XHCI_CMD_HCRST) | 372260537Shselasky (XREAD4(sc, oper, XHCI_USBSTS) & XHCI_STS_CNR); 373213379Shselasky if (!temp) 374213379Shselasky break; 375213379Shselasky } 376213379Shselasky 377213379Shselasky if (temp) { 378213379Shselasky device_printf(sc->sc_bus.parent, "Controller " 379213379Shselasky "reset timeout.\n"); 380213379Shselasky return (USB_ERR_IOERROR); 381213379Shselasky } 382213379Shselasky 383213379Shselasky if (!(XREAD4(sc, oper, XHCI_PAGESIZE) & XHCI_PAGESIZE_4K)) { 384213379Shselasky device_printf(sc->sc_bus.parent, "Controller does " 385213379Shselasky "not support 4K page size.\n"); 386213379Shselasky return (USB_ERR_IOERROR); 387213379Shselasky } 388213379Shselasky 389213379Shselasky temp = XREAD4(sc, capa, XHCI_HCSPARAMS1); 390213379Shselasky 391213379Shselasky i = XHCI_HCS1_N_PORTS(temp); 392213379Shselasky 393213379Shselasky if (i == 0) { 394213379Shselasky device_printf(sc->sc_bus.parent, "Invalid number " 395213379Shselasky "of ports: %u\n", i); 396213379Shselasky return (USB_ERR_IOERROR); 397213379Shselasky } 398213379Shselasky 399213379Shselasky sc->sc_noport = i; 400213379Shselasky sc->sc_noslot = XHCI_HCS1_DEVSLOT_MAX(temp); 401213379Shselasky 402213379Shselasky if (sc->sc_noslot > XHCI_MAX_DEVICES) 403213379Shselasky sc->sc_noslot = XHCI_MAX_DEVICES; 404213379Shselasky 405278278Shselasky /* set up number of device slots */ 406213379Shselasky 407213379Shselasky DPRINTF("CONFIG=0x%08x -> 0x%08x\n", 408213379Shselasky XREAD4(sc, oper, XHCI_CONFIG), sc->sc_noslot); 409213379Shselasky 410213379Shselasky XWRITE4(sc, oper, XHCI_CONFIG, sc->sc_noslot); 411213379Shselasky 412213379Shselasky DPRINTF("Max slots: %u\n", sc->sc_noslot); 413213379Shselasky 414213379Shselasky temp = XREAD4(sc, capa, XHCI_HCSPARAMS2); 415213379Shselasky 416213379Shselasky sc->sc_noscratch = XHCI_HCS2_SPB_MAX(temp); 417213379Shselasky 418213379Shselasky if (sc->sc_noscratch > XHCI_MAX_SCRATCHPADS) { 419213379Shselasky device_printf(sc->sc_bus.parent, "XHCI request " 420213379Shselasky "too many scratchpads\n"); 421213379Shselasky return (USB_ERR_NOMEM); 422213379Shselasky } 423213379Shselasky 424213379Shselasky DPRINTF("Max scratch: %u\n", sc->sc_noscratch); 425213379Shselasky 426213379Shselasky temp = XREAD4(sc, capa, XHCI_HCSPARAMS3); 427213379Shselasky 428213379Shselasky sc->sc_exit_lat_max = XHCI_HCS3_U1_DEL(temp) + 429213379Shselasky XHCI_HCS3_U2_DEL(temp) + 250 /* us */; 430213379Shselasky 431213379Shselasky temp = XREAD4(sc, oper, XHCI_USBSTS); 432213379Shselasky 433213379Shselasky /* clear interrupts */ 434213379Shselasky XWRITE4(sc, oper, XHCI_USBSTS, temp); 435213379Shselasky /* disable all device notifications */ 436213379Shselasky XWRITE4(sc, oper, XHCI_DNCTRL, 0); 437213379Shselasky 438278278Shselasky /* set up device context base address */ 439213379Shselasky usbd_get_page(&sc->sc_hw.ctx_pc, 0, &buf_res); 440213379Shselasky pdctxa = buf_res.buffer; 441213379Shselasky memset(pdctxa, 0, sizeof(*pdctxa)); 442213379Shselasky 443213379Shselasky addr = buf_res.physaddr; 444213379Shselasky addr += (uintptr_t)&((struct xhci_dev_ctx_addr *)0)->qwSpBufPtr[0]; 445213379Shselasky 446213379Shselasky /* slot 0 points to the table of scratchpad pointers */ 447213379Shselasky pdctxa->qwBaaDevCtxAddr[0] = htole64(addr); 448213379Shselasky 449213379Shselasky for (i = 0; i != sc->sc_noscratch; i++) { 450213379Shselasky struct usb_page_search buf_scp; 451213379Shselasky usbd_get_page(&sc->sc_hw.scratch_pc[i], 0, &buf_scp); 452213379Shselasky pdctxa->qwSpBufPtr[i] = htole64((uint64_t)buf_scp.physaddr); 453213379Shselasky } 454213379Shselasky 455213379Shselasky addr = buf_res.physaddr; 456213379Shselasky 457213379Shselasky XWRITE4(sc, oper, XHCI_DCBAAP_LO, (uint32_t)addr); 458213379Shselasky XWRITE4(sc, oper, XHCI_DCBAAP_HI, (uint32_t)(addr >> 32)); 459213379Shselasky XWRITE4(sc, oper, XHCI_DCBAAP_LO, (uint32_t)addr); 460213379Shselasky XWRITE4(sc, oper, XHCI_DCBAAP_HI, (uint32_t)(addr >> 32)); 461213379Shselasky 462213379Shselasky /* Setup event table size */ 463213379Shselasky 464213379Shselasky temp = XREAD4(sc, capa, XHCI_HCSPARAMS2); 465213379Shselasky 466213379Shselasky DPRINTF("HCS2=0x%08x\n", temp); 467213379Shselasky 468213379Shselasky temp = XHCI_HCS2_ERST_MAX(temp); 469213379Shselasky temp = 1U << temp; 470213379Shselasky if (temp > XHCI_MAX_RSEG) 471213379Shselasky temp = XHCI_MAX_RSEG; 472213379Shselasky 473213379Shselasky sc->sc_erst_max = temp; 474213379Shselasky 475213379Shselasky DPRINTF("ERSTSZ=0x%08x -> 0x%08x\n", 476213379Shselasky XREAD4(sc, runt, XHCI_ERSTSZ(0)), temp); 477213379Shselasky 478213379Shselasky XWRITE4(sc, runt, XHCI_ERSTSZ(0), XHCI_ERSTS_SET(temp)); 479213379Shselasky 480265078Shselasky /* Check if we should use the default IMOD value */ 481265078Shselasky if (sc->sc_imod_default == 0) 482265078Shselasky sc->sc_imod_default = XHCI_IMOD_DEFAULT; 483265078Shselasky 484213379Shselasky /* Setup interrupt rate */ 485265078Shselasky XWRITE4(sc, runt, XHCI_IMOD(0), sc->sc_imod_default); 486213379Shselasky 487213379Shselasky usbd_get_page(&sc->sc_hw.root_pc, 0, &buf_res); 488213379Shselasky 489213379Shselasky phwr = buf_res.buffer; 490213379Shselasky addr = buf_res.physaddr; 491213379Shselasky addr += (uintptr_t)&((struct xhci_hw_root *)0)->hwr_events[0]; 492213379Shselasky 493213379Shselasky /* reset hardware root structure */ 494213379Shselasky memset(phwr, 0, sizeof(*phwr)); 495213379Shselasky 496213379Shselasky phwr->hwr_ring_seg[0].qwEvrsTablePtr = htole64(addr); 497213379Shselasky phwr->hwr_ring_seg[0].dwEvrsTableSize = htole32(XHCI_MAX_EVENTS); 498213379Shselasky 499213379Shselasky DPRINTF("ERDP(0)=0x%016llx\n", (unsigned long long)addr); 500213379Shselasky 501213379Shselasky XWRITE4(sc, runt, XHCI_ERDP_LO(0), (uint32_t)addr); 502213379Shselasky XWRITE4(sc, runt, XHCI_ERDP_HI(0), (uint32_t)(addr >> 32)); 503213379Shselasky 504278662Shselasky addr = buf_res.physaddr; 505213379Shselasky 506213379Shselasky DPRINTF("ERSTBA(0)=0x%016llx\n", (unsigned long long)addr); 507213379Shselasky 508213379Shselasky XWRITE4(sc, runt, XHCI_ERSTBA_LO(0), (uint32_t)addr); 509213379Shselasky XWRITE4(sc, runt, XHCI_ERSTBA_HI(0), (uint32_t)(addr >> 32)); 510213379Shselasky 511213379Shselasky /* Setup interrupter registers */ 512213379Shselasky 513213379Shselasky temp = XREAD4(sc, runt, XHCI_IMAN(0)); 514213379Shselasky temp |= XHCI_IMAN_INTR_ENA; 515213379Shselasky XWRITE4(sc, runt, XHCI_IMAN(0), temp); 516213379Shselasky 517278278Shselasky /* set up command ring control base address */ 518213379Shselasky addr = buf_res.physaddr; 519213379Shselasky addr += (uintptr_t)&((struct xhci_hw_root *)0)->hwr_commands[0]; 520213379Shselasky 521213379Shselasky DPRINTF("CRCR=0x%016llx\n", (unsigned long long)addr); 522213379Shselasky 523213379Shselasky XWRITE4(sc, oper, XHCI_CRCR_LO, ((uint32_t)addr) | XHCI_CRCR_LO_RCS); 524213379Shselasky XWRITE4(sc, oper, XHCI_CRCR_HI, (uint32_t)(addr >> 32)); 525213379Shselasky 526213379Shselasky phwr->hwr_commands[XHCI_MAX_COMMANDS - 1].qwTrb0 = htole64(addr); 527213379Shselasky 528213379Shselasky usb_bus_mem_flush_all(&sc->sc_bus, &xhci_iterate_hw_softc); 529213379Shselasky 530213379Shselasky /* Go! */ 531213379Shselasky XWRITE4(sc, oper, XHCI_USBCMD, XHCI_CMD_RS | 532213379Shselasky XHCI_CMD_INTE | XHCI_CMD_HSEE); 533213379Shselasky 534213379Shselasky for (i = 0; i != 100; i++) { 535227541Shselasky usb_pause_mtx(NULL, hz / 100); 536213379Shselasky temp = XREAD4(sc, oper, XHCI_USBSTS) & XHCI_STS_HCH; 537213379Shselasky if (!temp) 538213379Shselasky break; 539213379Shselasky } 540213379Shselasky if (temp) { 541213379Shselasky XWRITE4(sc, oper, XHCI_USBCMD, 0); 542213379Shselasky device_printf(sc->sc_bus.parent, "Run timeout.\n"); 543213379Shselasky return (USB_ERR_IOERROR); 544213379Shselasky } 545213379Shselasky 546213379Shselasky /* catch any lost interrupts */ 547213379Shselasky xhci_do_poll(&sc->sc_bus); 548213379Shselasky 549255768Shselasky if (sc->sc_port_route != NULL) { 550255768Shselasky /* Route all ports to the XHCI by default */ 551255768Shselasky sc->sc_port_route(sc->sc_bus.parent, 552255768Shselasky ~xhciroute, xhciroute); 553255768Shselasky } 554213379Shselasky return (0); 555213379Shselasky} 556213379Shselasky 557213379Shselaskyusb_error_t 558213379Shselaskyxhci_halt_controller(struct xhci_softc *sc) 559213379Shselasky{ 560213379Shselasky uint32_t temp; 561213379Shselasky uint16_t i; 562213379Shselasky 563213379Shselasky DPRINTF("\n"); 564213379Shselasky 565213379Shselasky sc->sc_capa_off = 0; 566213379Shselasky sc->sc_oper_off = XREAD1(sc, capa, XHCI_CAPLENGTH); 567213379Shselasky sc->sc_runt_off = XREAD4(sc, capa, XHCI_RTSOFF) & ~0xF; 568213379Shselasky sc->sc_door_off = XREAD4(sc, capa, XHCI_DBOFF) & ~0x3; 569213379Shselasky 570213379Shselasky /* Halt controller */ 571213379Shselasky XWRITE4(sc, oper, XHCI_USBCMD, 0); 572213379Shselasky 573213379Shselasky for (i = 0; i != 100; i++) { 574227541Shselasky usb_pause_mtx(NULL, hz / 100); 575213379Shselasky temp = XREAD4(sc, oper, XHCI_USBSTS) & XHCI_STS_HCH; 576213379Shselasky if (temp) 577213379Shselasky break; 578213379Shselasky } 579213379Shselasky 580213379Shselasky if (!temp) { 581213379Shselasky device_printf(sc->sc_bus.parent, "Controller halt timeout.\n"); 582213379Shselasky return (USB_ERR_IOERROR); 583213379Shselasky } 584213379Shselasky return (0); 585213379Shselasky} 586213379Shselasky 587213379Shselaskyusb_error_t 588279648Shselaskyxhci_init(struct xhci_softc *sc, device_t self, uint8_t dma32) 589213379Shselasky{ 590278278Shselasky uint32_t temp; 591278278Shselasky 592278278Shselasky DPRINTF("\n"); 593278278Shselasky 594278278Shselasky /* initialize some bus fields */ 595213379Shselasky sc->sc_bus.parent = self; 596213379Shselasky 597213379Shselasky /* set the bus revision */ 598213379Shselasky sc->sc_bus.usbrev = USB_REV_3_0; 599213379Shselasky 600213379Shselasky /* set up the bus struct */ 601213379Shselasky sc->sc_bus.methods = &xhci_bus_methods; 602213379Shselasky 603278278Shselasky /* set up devices array */ 604213379Shselasky sc->sc_bus.devices = sc->sc_devices; 605213379Shselasky sc->sc_bus.devices_max = XHCI_MAX_DEVICES; 606213379Shselasky 607272589Shselasky /* set default cycle state in case of early interrupts */ 608272589Shselasky sc->sc_event_ccs = 1; 609272589Shselasky sc->sc_command_ccs = 1; 610272589Shselasky 611278278Shselasky /* set up bus space offsets */ 612278278Shselasky sc->sc_capa_off = 0; 613278278Shselasky sc->sc_oper_off = XREAD1(sc, capa, XHCI_CAPLENGTH); 614278278Shselasky sc->sc_runt_off = XREAD4(sc, capa, XHCI_RTSOFF) & ~0x1F; 615278278Shselasky sc->sc_door_off = XREAD4(sc, capa, XHCI_DBOFF) & ~0x3; 616213379Shselasky 617278278Shselasky DPRINTF("CAPLENGTH=0x%x\n", sc->sc_oper_off); 618278278Shselasky DPRINTF("RUNTIMEOFFSET=0x%x\n", sc->sc_runt_off); 619278278Shselasky DPRINTF("DOOROFFSET=0x%x\n", sc->sc_door_off); 620278278Shselasky 621278278Shselasky DPRINTF("xHCI version = 0x%04x\n", XREAD2(sc, capa, XHCI_HCIVERSION)); 622278278Shselasky 623278278Shselasky temp = XREAD4(sc, capa, XHCI_HCSPARAMS0); 624278278Shselasky 625278278Shselasky DPRINTF("HCS0 = 0x%08x\n", temp); 626278278Shselasky 627278278Shselasky /* set up context size */ 628278278Shselasky if (XHCI_HCS0_CSZ(temp)) { 629278278Shselasky sc->sc_ctx_is_64_byte = 1; 630278278Shselasky } else { 631278278Shselasky sc->sc_ctx_is_64_byte = 0; 632278278Shselasky } 633278278Shselasky 634278278Shselasky /* get DMA bits */ 635279648Shselasky sc->sc_bus.dma_bits = (XHCI_HCS0_AC64(temp) && 636279648Shselasky xhcidma32 == 0 && dma32 == 0) ? 64 : 32; 637278278Shselasky 638278278Shselasky device_printf(self, "%d bytes context size, %d-bit DMA\n", 639278278Shselasky sc->sc_ctx_is_64_byte ? 64 : 32, (int)sc->sc_bus.dma_bits); 640278278Shselasky 641213379Shselasky /* get all DMA memory */ 642213379Shselasky if (usb_bus_mem_alloc_all(&sc->sc_bus, 643213379Shselasky USB_GET_DMA_TAG(self), &xhci_iterate_hw_softc)) { 644213379Shselasky return (ENOMEM); 645213379Shselasky } 646213379Shselasky 647278278Shselasky /* set up command queue mutex and condition varible */ 648278278Shselasky cv_init(&sc->sc_cmd_cv, "CMDQ"); 649278278Shselasky sx_init(&sc->sc_cmd_sx, "CMDQ lock"); 650213379Shselasky 651278278Shselasky sc->sc_config_msg[0].hdr.pm_callback = &xhci_configure_msg; 652278278Shselasky sc->sc_config_msg[0].bus = &sc->sc_bus; 653278278Shselasky sc->sc_config_msg[1].hdr.pm_callback = &xhci_configure_msg; 654278278Shselasky sc->sc_config_msg[1].bus = &sc->sc_bus; 655278278Shselasky 656213379Shselasky return (0); 657213379Shselasky} 658213379Shselasky 659213379Shselaskyvoid 660213379Shselaskyxhci_uninit(struct xhci_softc *sc) 661213379Shselasky{ 662249786Shselasky /* 663249786Shselasky * NOTE: At this point the control transfer process is gone 664249786Shselasky * and "xhci_configure_msg" is no longer called. Consequently 665249786Shselasky * waiting for the configuration messages to complete is not 666249786Shselasky * needed. 667249786Shselasky */ 668213379Shselasky usb_bus_mem_free_all(&sc->sc_bus, &xhci_iterate_hw_softc); 669213379Shselasky 670213379Shselasky cv_destroy(&sc->sc_cmd_cv); 671213379Shselasky sx_destroy(&sc->sc_cmd_sx); 672213379Shselasky} 673213379Shselasky 674229086Shselaskystatic void 675229086Shselaskyxhci_set_hw_power_sleep(struct usb_bus *bus, uint32_t state) 676213379Shselasky{ 677229086Shselasky struct xhci_softc *sc = XHCI_BUS2SC(bus); 678213379Shselasky 679229086Shselasky switch (state) { 680229086Shselasky case USB_HW_POWER_SUSPEND: 681229086Shselasky DPRINTF("Stopping the XHCI\n"); 682229086Shselasky xhci_halt_controller(sc); 683229086Shselasky break; 684229086Shselasky case USB_HW_POWER_SHUTDOWN: 685229086Shselasky DPRINTF("Stopping the XHCI\n"); 686229086Shselasky xhci_halt_controller(sc); 687229086Shselasky break; 688229086Shselasky case USB_HW_POWER_RESUME: 689229086Shselasky DPRINTF("Starting the XHCI\n"); 690229086Shselasky xhci_start_controller(sc); 691229086Shselasky break; 692229086Shselasky default: 693229086Shselasky break; 694229086Shselasky } 695213379Shselasky} 696213379Shselasky 697213379Shselaskystatic usb_error_t 698213379Shselaskyxhci_generic_done_sub(struct usb_xfer *xfer) 699213379Shselasky{ 700213379Shselasky struct xhci_td *td; 701213379Shselasky struct xhci_td *td_alt_next; 702213379Shselasky uint32_t len; 703213379Shselasky uint8_t status; 704213379Shselasky 705213379Shselasky td = xfer->td_transfer_cache; 706213379Shselasky td_alt_next = td->alt_next; 707213379Shselasky 708213379Shselasky if (xfer->aframes != xfer->nframes) 709213379Shselasky usbd_xfer_set_frame_len(xfer, xfer->aframes, 0); 710213379Shselasky 711213379Shselasky while (1) { 712213379Shselasky 713213379Shselasky usb_pc_cpu_invalidate(td->page_cache); 714213379Shselasky 715213379Shselasky status = td->status; 716213379Shselasky len = td->remainder; 717213379Shselasky 718213379Shselasky DPRINTFN(4, "xfer=%p[%u/%u] rem=%u/%u status=%u\n", 719213379Shselasky xfer, (unsigned int)xfer->aframes, 720213379Shselasky (unsigned int)xfer->nframes, 721213379Shselasky (unsigned int)len, (unsigned int)td->len, 722213379Shselasky (unsigned int)status); 723213379Shselasky 724213379Shselasky /* 725213379Shselasky * Verify the status length and 726213379Shselasky * add the length to "frlengths[]": 727213379Shselasky */ 728213379Shselasky if (len > td->len) { 729213379Shselasky /* should not happen */ 730213379Shselasky DPRINTF("Invalid status length, " 731213379Shselasky "0x%04x/0x%04x bytes\n", len, td->len); 732213379Shselasky status = XHCI_TRB_ERROR_LENGTH; 733213379Shselasky } else if (xfer->aframes != xfer->nframes) { 734213379Shselasky xfer->frlengths[xfer->aframes] += td->len - len; 735213379Shselasky } 736213379Shselasky /* Check for last transfer */ 737213379Shselasky if (((void *)td) == xfer->td_transfer_last) { 738213379Shselasky td = NULL; 739213379Shselasky break; 740213379Shselasky } 741213379Shselasky /* Check for transfer error */ 742213379Shselasky if (status != XHCI_TRB_ERROR_SHORT_PKT && 743213379Shselasky status != XHCI_TRB_ERROR_SUCCESS) { 744213379Shselasky /* the transfer is finished */ 745213379Shselasky td = NULL; 746213379Shselasky break; 747213379Shselasky } 748213379Shselasky /* Check for short transfer */ 749213379Shselasky if (len > 0) { 750213379Shselasky if (xfer->flags_int.short_frames_ok || 751213379Shselasky xfer->flags_int.isochronous_xfr || 752213379Shselasky xfer->flags_int.control_xfr) { 753213379Shselasky /* follow alt next */ 754213379Shselasky td = td->alt_next; 755213379Shselasky } else { 756213379Shselasky /* the transfer is finished */ 757213379Shselasky td = NULL; 758213379Shselasky } 759213379Shselasky break; 760213379Shselasky } 761213379Shselasky td = td->obj_next; 762213379Shselasky 763213379Shselasky if (td->alt_next != td_alt_next) { 764213379Shselasky /* this USB frame is complete */ 765213379Shselasky break; 766213379Shselasky } 767213379Shselasky } 768213379Shselasky 769213379Shselasky /* update transfer cache */ 770213379Shselasky 771213379Shselasky xfer->td_transfer_cache = td; 772213379Shselasky 773213379Shselasky return ((status == XHCI_TRB_ERROR_STALL) ? USB_ERR_STALLED : 774213379Shselasky (status != XHCI_TRB_ERROR_SHORT_PKT && 775213379Shselasky status != XHCI_TRB_ERROR_SUCCESS) ? USB_ERR_IOERROR : 776213379Shselasky USB_ERR_NORMAL_COMPLETION); 777213379Shselasky} 778213379Shselasky 779213379Shselaskystatic void 780213379Shselaskyxhci_generic_done(struct usb_xfer *xfer) 781213379Shselasky{ 782213379Shselasky usb_error_t err = 0; 783213379Shselasky 784213379Shselasky DPRINTFN(13, "xfer=%p endpoint=%p transfer done\n", 785213379Shselasky xfer, xfer->endpoint); 786213379Shselasky 787213379Shselasky /* reset scanner */ 788213379Shselasky 789213379Shselasky xfer->td_transfer_cache = xfer->td_transfer_first; 790213379Shselasky 791213379Shselasky if (xfer->flags_int.control_xfr) { 792213379Shselasky 793213379Shselasky if (xfer->flags_int.control_hdr) 794213379Shselasky err = xhci_generic_done_sub(xfer); 795213379Shselasky 796213379Shselasky xfer->aframes = 1; 797213379Shselasky 798213379Shselasky if (xfer->td_transfer_cache == NULL) 799213379Shselasky goto done; 800213379Shselasky } 801213379Shselasky 802213379Shselasky while (xfer->aframes != xfer->nframes) { 803213379Shselasky 804213379Shselasky err = xhci_generic_done_sub(xfer); 805213379Shselasky xfer->aframes++; 806213379Shselasky 807213379Shselasky if (xfer->td_transfer_cache == NULL) 808213379Shselasky goto done; 809213379Shselasky } 810213379Shselasky 811213379Shselasky if (xfer->flags_int.control_xfr && 812213379Shselasky !xfer->flags_int.control_act) 813213379Shselasky err = xhci_generic_done_sub(xfer); 814213379Shselaskydone: 815213379Shselasky /* transfer is complete */ 816213379Shselasky xhci_device_done(xfer, err); 817213379Shselasky} 818213379Shselasky 819213379Shselaskystatic void 820213379Shselaskyxhci_activate_transfer(struct usb_xfer *xfer) 821213379Shselasky{ 822213379Shselasky struct xhci_td *td; 823213379Shselasky 824213379Shselasky td = xfer->td_transfer_cache; 825213379Shselasky 826213379Shselasky usb_pc_cpu_invalidate(td->page_cache); 827213379Shselasky 828213379Shselasky if (!(td->td_trb[0].dwTrb3 & htole32(XHCI_TRB_3_CYCLE_BIT))) { 829213379Shselasky 830213379Shselasky /* activate the transfer */ 831213379Shselasky 832213379Shselasky td->td_trb[0].dwTrb3 |= htole32(XHCI_TRB_3_CYCLE_BIT); 833213379Shselasky usb_pc_cpu_flush(td->page_cache); 834213379Shselasky 835213379Shselasky xhci_endpoint_doorbell(xfer); 836213379Shselasky } 837213379Shselasky} 838213379Shselasky 839213379Shselaskystatic void 840213379Shselaskyxhci_skip_transfer(struct usb_xfer *xfer) 841213379Shselasky{ 842213379Shselasky struct xhci_td *td; 843213379Shselasky struct xhci_td *td_last; 844213379Shselasky 845213379Shselasky td = xfer->td_transfer_cache; 846213379Shselasky td_last = xfer->td_transfer_last; 847213379Shselasky 848213379Shselasky td = td->alt_next; 849213379Shselasky 850213379Shselasky usb_pc_cpu_invalidate(td->page_cache); 851213379Shselasky 852213379Shselasky if (!(td->td_trb[0].dwTrb3 & htole32(XHCI_TRB_3_CYCLE_BIT))) { 853213379Shselasky 854213379Shselasky usb_pc_cpu_invalidate(td_last->page_cache); 855213379Shselasky 856213379Shselasky /* copy LINK TRB to current waiting location */ 857213379Shselasky 858213379Shselasky td->td_trb[0].qwTrb0 = td_last->td_trb[td_last->ntrb].qwTrb0; 859213379Shselasky td->td_trb[0].dwTrb2 = td_last->td_trb[td_last->ntrb].dwTrb2; 860213379Shselasky usb_pc_cpu_flush(td->page_cache); 861213379Shselasky 862213379Shselasky td->td_trb[0].dwTrb3 = td_last->td_trb[td_last->ntrb].dwTrb3; 863213379Shselasky usb_pc_cpu_flush(td->page_cache); 864213379Shselasky 865213379Shselasky xhci_endpoint_doorbell(xfer); 866213379Shselasky } 867213379Shselasky} 868213379Shselasky 869213379Shselasky/*------------------------------------------------------------------------* 870213379Shselasky * xhci_check_transfer 871213379Shselasky *------------------------------------------------------------------------*/ 872213379Shselaskystatic void 873213379Shselaskyxhci_check_transfer(struct xhci_softc *sc, struct xhci_trb *trb) 874213379Shselasky{ 875251247Shselasky struct xhci_endpoint_ext *pepext; 876213379Shselasky int64_t offset; 877213379Shselasky uint64_t td_event; 878213379Shselasky uint32_t temp; 879213379Shselasky uint32_t remainder; 880251247Shselasky uint16_t stream_id; 881251247Shselasky uint16_t i; 882213379Shselasky uint8_t status; 883213379Shselasky uint8_t halted; 884213379Shselasky uint8_t epno; 885213379Shselasky uint8_t index; 886213379Shselasky 887213379Shselasky /* decode TRB */ 888213379Shselasky td_event = le64toh(trb->qwTrb0); 889213379Shselasky temp = le32toh(trb->dwTrb2); 890213379Shselasky 891213379Shselasky remainder = XHCI_TRB_2_REM_GET(temp); 892213379Shselasky status = XHCI_TRB_2_ERROR_GET(temp); 893251247Shselasky stream_id = XHCI_TRB_2_STREAM_GET(temp); 894213379Shselasky 895213379Shselasky temp = le32toh(trb->dwTrb3); 896213379Shselasky epno = XHCI_TRB_3_EP_GET(temp); 897213379Shselasky index = XHCI_TRB_3_SLOT_GET(temp); 898213379Shselasky 899213379Shselasky /* check if error means halted */ 900213379Shselasky halted = (status != XHCI_TRB_ERROR_SHORT_PKT && 901213379Shselasky status != XHCI_TRB_ERROR_SUCCESS); 902213379Shselasky 903251247Shselasky DPRINTF("slot=%u epno=%u stream=%u remainder=%u status=%u\n", 904251247Shselasky index, epno, stream_id, remainder, status); 905213379Shselasky 906213379Shselasky if (index > sc->sc_noslot) { 907213379Shselasky DPRINTF("Invalid slot.\n"); 908213379Shselasky return; 909213379Shselasky } 910213379Shselasky 911213379Shselasky if ((epno == 0) || (epno >= XHCI_MAX_ENDPOINTS)) { 912213379Shselasky DPRINTF("Invalid endpoint.\n"); 913213379Shselasky return; 914213379Shselasky } 915213379Shselasky 916251247Shselasky pepext = &sc->sc_hw.devs[index].endp[epno]; 917251247Shselasky 918251247Shselasky if (pepext->trb_ep_mode != USB_EP_MODE_STREAMS) { 919251247Shselasky stream_id = 0; 920251247Shselasky DPRINTF("stream_id=0\n"); 921251247Shselasky } else if (stream_id >= XHCI_MAX_STREAMS) { 922251247Shselasky DPRINTF("Invalid stream ID.\n"); 923251247Shselasky return; 924251247Shselasky } 925251247Shselasky 926213379Shselasky /* try to find the USB transfer that generated the event */ 927213379Shselasky for (i = 0; i != (XHCI_MAX_TRANSFERS - 1); i++) { 928213379Shselasky struct usb_xfer *xfer; 929213379Shselasky struct xhci_td *td; 930213379Shselasky 931251247Shselasky xfer = pepext->xfer[i + (XHCI_MAX_TRANSFERS * stream_id)]; 932213379Shselasky if (xfer == NULL) 933213379Shselasky continue; 934213379Shselasky 935213379Shselasky td = xfer->td_transfer_cache; 936213379Shselasky 937213379Shselasky DPRINTFN(5, "Checking if 0x%016llx == (0x%016llx .. 0x%016llx)\n", 938213379Shselasky (long long)td_event, 939213379Shselasky (long long)td->td_self, 940213379Shselasky (long long)td->td_self + sizeof(td->td_trb)); 941213379Shselasky 942213379Shselasky /* 943213379Shselasky * NOTE: Some XHCI implementations might not trigger 944213379Shselasky * an event on the last LINK TRB so we need to 945213379Shselasky * consider both the last and second last event 946213379Shselasky * address as conditions for a successful transfer. 947213379Shselasky * 948213379Shselasky * NOTE: We assume that the XHCI will only trigger one 949213379Shselasky * event per chain of TRBs. 950213379Shselasky */ 951213379Shselasky 952213379Shselasky offset = td_event - td->td_self; 953213379Shselasky 954213379Shselasky if (offset >= 0 && 955233774Shselasky offset < (int64_t)sizeof(td->td_trb)) { 956213379Shselasky 957213379Shselasky usb_pc_cpu_invalidate(td->page_cache); 958213379Shselasky 959213379Shselasky /* compute rest of remainder, if any */ 960213379Shselasky for (i = (offset / 16) + 1; i < td->ntrb; i++) { 961213379Shselasky temp = le32toh(td->td_trb[i].dwTrb2); 962213379Shselasky remainder += XHCI_TRB_2_BYTES_GET(temp); 963213379Shselasky } 964213379Shselasky 965213379Shselasky DPRINTFN(5, "New remainder: %u\n", remainder); 966213379Shselasky 967213379Shselasky /* clear isochronous transfer errors */ 968213379Shselasky if (xfer->flags_int.isochronous_xfr) { 969213379Shselasky if (halted) { 970213379Shselasky halted = 0; 971213379Shselasky status = XHCI_TRB_ERROR_SUCCESS; 972213379Shselasky remainder = td->len; 973213379Shselasky } 974213379Shselasky } 975213379Shselasky 976213379Shselasky /* "td->remainder" is verified later */ 977213379Shselasky td->remainder = remainder; 978213379Shselasky td->status = status; 979213379Shselasky 980213379Shselasky usb_pc_cpu_flush(td->page_cache); 981213379Shselasky 982213379Shselasky /* 983213379Shselasky * 1) Last transfer descriptor makes the 984213379Shselasky * transfer done 985213379Shselasky */ 986213379Shselasky if (((void *)td) == xfer->td_transfer_last) { 987213379Shselasky DPRINTF("TD is last\n"); 988213379Shselasky xhci_generic_done(xfer); 989213379Shselasky break; 990213379Shselasky } 991213379Shselasky 992213379Shselasky /* 993213379Shselasky * 2) Any kind of error makes the transfer 994213379Shselasky * done 995213379Shselasky */ 996213379Shselasky if (halted) { 997213379Shselasky DPRINTF("TD has I/O error\n"); 998213379Shselasky xhci_generic_done(xfer); 999213379Shselasky break; 1000213379Shselasky } 1001213379Shselasky 1002213379Shselasky /* 1003213379Shselasky * 3) If there is no alternate next transfer, 1004213379Shselasky * a short packet also makes the transfer done 1005213379Shselasky */ 1006213379Shselasky if (td->remainder > 0) { 1007246113Shselasky if (td->alt_next == NULL) { 1008246126Shselasky DPRINTF( 1009246126Shselasky "short TD has no alternate next\n"); 1010246113Shselasky xhci_generic_done(xfer); 1011246113Shselasky break; 1012246113Shselasky } 1013213379Shselasky DPRINTF("TD has short pkt\n"); 1014213379Shselasky if (xfer->flags_int.short_frames_ok || 1015213379Shselasky xfer->flags_int.isochronous_xfr || 1016213379Shselasky xfer->flags_int.control_xfr) { 1017213379Shselasky /* follow the alt next */ 1018213379Shselasky xfer->td_transfer_cache = td->alt_next; 1019213379Shselasky xhci_activate_transfer(xfer); 1020213379Shselasky break; 1021213379Shselasky } 1022213379Shselasky xhci_skip_transfer(xfer); 1023213379Shselasky xhci_generic_done(xfer); 1024213379Shselasky break; 1025213379Shselasky } 1026213379Shselasky 1027213379Shselasky /* 1028213379Shselasky * 4) Transfer complete - go to next TD 1029213379Shselasky */ 1030213379Shselasky DPRINTF("Following next TD\n"); 1031213379Shselasky xfer->td_transfer_cache = td->obj_next; 1032213379Shselasky xhci_activate_transfer(xfer); 1033213379Shselasky break; /* there should only be one match */ 1034213379Shselasky } 1035213379Shselasky } 1036213379Shselasky} 1037213379Shselasky 1038255768Shselaskystatic int 1039213379Shselaskyxhci_check_command(struct xhci_softc *sc, struct xhci_trb *trb) 1040213379Shselasky{ 1041213379Shselasky if (sc->sc_cmd_addr == trb->qwTrb0) { 1042213379Shselasky DPRINTF("Received command event\n"); 1043213379Shselasky sc->sc_cmd_result[0] = trb->dwTrb2; 1044213379Shselasky sc->sc_cmd_result[1] = trb->dwTrb3; 1045213379Shselasky cv_signal(&sc->sc_cmd_cv); 1046255768Shselasky return (1); /* command match */ 1047213379Shselasky } 1048255768Shselasky return (0); 1049213379Shselasky} 1050213379Shselasky 1051255768Shselaskystatic int 1052213379Shselaskyxhci_interrupt_poll(struct xhci_softc *sc) 1053213379Shselasky{ 1054213379Shselasky struct usb_page_search buf_res; 1055213379Shselasky struct xhci_hw_root *phwr; 1056213379Shselasky uint64_t addr; 1057213379Shselasky uint32_t temp; 1058255768Shselasky int retval = 0; 1059213379Shselasky uint16_t i; 1060213379Shselasky uint8_t event; 1061213379Shselasky uint8_t j; 1062213379Shselasky uint8_t k; 1063213379Shselasky uint8_t t; 1064213379Shselasky 1065213379Shselasky usbd_get_page(&sc->sc_hw.root_pc, 0, &buf_res); 1066213379Shselasky 1067213379Shselasky phwr = buf_res.buffer; 1068213379Shselasky 1069213379Shselasky /* Receive any events */ 1070213379Shselasky 1071213379Shselasky usb_pc_cpu_invalidate(&sc->sc_hw.root_pc); 1072213379Shselasky 1073213379Shselasky i = sc->sc_event_idx; 1074213379Shselasky j = sc->sc_event_ccs; 1075213379Shselasky t = 2; 1076213379Shselasky 1077213379Shselasky while (1) { 1078213379Shselasky 1079213379Shselasky temp = le32toh(phwr->hwr_events[i].dwTrb3); 1080213379Shselasky 1081213379Shselasky k = (temp & XHCI_TRB_3_CYCLE_BIT) ? 1 : 0; 1082213379Shselasky 1083213379Shselasky if (j != k) 1084213379Shselasky break; 1085213379Shselasky 1086213379Shselasky event = XHCI_TRB_3_TYPE_GET(temp); 1087213379Shselasky 1088213379Shselasky DPRINTFN(10, "event[%u] = %u (0x%016llx 0x%08lx 0x%08lx)\n", 1089213379Shselasky i, event, (long long)le64toh(phwr->hwr_events[i].qwTrb0), 1090213379Shselasky (long)le32toh(phwr->hwr_events[i].dwTrb2), 1091213379Shselasky (long)le32toh(phwr->hwr_events[i].dwTrb3)); 1092213379Shselasky 1093213379Shselasky switch (event) { 1094213379Shselasky case XHCI_TRB_EVENT_TRANSFER: 1095213379Shselasky xhci_check_transfer(sc, &phwr->hwr_events[i]); 1096213379Shselasky break; 1097213379Shselasky case XHCI_TRB_EVENT_CMD_COMPLETE: 1098255768Shselasky retval |= xhci_check_command(sc, &phwr->hwr_events[i]); 1099213379Shselasky break; 1100213379Shselasky default: 1101213379Shselasky DPRINTF("Unhandled event = %u\n", event); 1102213379Shselasky break; 1103213379Shselasky } 1104213379Shselasky 1105213379Shselasky i++; 1106213379Shselasky 1107213379Shselasky if (i == XHCI_MAX_EVENTS) { 1108213379Shselasky i = 0; 1109213379Shselasky j ^= 1; 1110213379Shselasky 1111213379Shselasky /* check for timeout */ 1112213379Shselasky if (!--t) 1113213379Shselasky break; 1114213379Shselasky } 1115213379Shselasky } 1116213379Shselasky 1117213379Shselasky sc->sc_event_idx = i; 1118213379Shselasky sc->sc_event_ccs = j; 1119213379Shselasky 1120213379Shselasky /* 1121213379Shselasky * NOTE: The Event Ring Dequeue Pointer Register is 64-bit 1122213379Shselasky * latched. That means to activate the register we need to 1123213379Shselasky * write both the low and high double word of the 64-bit 1124213379Shselasky * register. 1125213379Shselasky */ 1126213379Shselasky 1127278662Shselasky addr = buf_res.physaddr; 1128213379Shselasky addr += (uintptr_t)&((struct xhci_hw_root *)0)->hwr_events[i]; 1129213379Shselasky 1130213379Shselasky /* try to clear busy bit */ 1131213379Shselasky addr |= XHCI_ERDP_LO_BUSY; 1132213379Shselasky 1133213379Shselasky XWRITE4(sc, runt, XHCI_ERDP_LO(0), (uint32_t)addr); 1134213379Shselasky XWRITE4(sc, runt, XHCI_ERDP_HI(0), (uint32_t)(addr >> 32)); 1135255768Shselasky 1136255768Shselasky return (retval); 1137213379Shselasky} 1138213379Shselasky 1139213379Shselaskystatic usb_error_t 1140213379Shselaskyxhci_do_command(struct xhci_softc *sc, struct xhci_trb *trb, 1141213379Shselasky uint16_t timeout_ms) 1142213379Shselasky{ 1143213379Shselasky struct usb_page_search buf_res; 1144213379Shselasky struct xhci_hw_root *phwr; 1145213379Shselasky uint64_t addr; 1146213379Shselasky uint32_t temp; 1147213379Shselasky uint8_t i; 1148213379Shselasky uint8_t j; 1149259603Shselasky uint8_t timeout = 0; 1150213379Shselasky int err; 1151213379Shselasky 1152213379Shselasky XHCI_CMD_ASSERT_LOCKED(sc); 1153213379Shselasky 1154213379Shselasky /* get hardware root structure */ 1155213379Shselasky 1156213379Shselasky usbd_get_page(&sc->sc_hw.root_pc, 0, &buf_res); 1157213379Shselasky 1158213379Shselasky phwr = buf_res.buffer; 1159213379Shselasky 1160213379Shselasky /* Queue command */ 1161213379Shselasky 1162213379Shselasky USB_BUS_LOCK(&sc->sc_bus); 1163259603Shselaskyretry: 1164213379Shselasky i = sc->sc_command_idx; 1165213379Shselasky j = sc->sc_command_ccs; 1166213379Shselasky 1167213379Shselasky DPRINTFN(10, "command[%u] = %u (0x%016llx, 0x%08lx, 0x%08lx)\n", 1168213379Shselasky i, XHCI_TRB_3_TYPE_GET(le32toh(trb->dwTrb3)), 1169213379Shselasky (long long)le64toh(trb->qwTrb0), 1170213379Shselasky (long)le32toh(trb->dwTrb2), 1171213379Shselasky (long)le32toh(trb->dwTrb3)); 1172213379Shselasky 1173213379Shselasky phwr->hwr_commands[i].qwTrb0 = trb->qwTrb0; 1174213379Shselasky phwr->hwr_commands[i].dwTrb2 = trb->dwTrb2; 1175213379Shselasky 1176213379Shselasky usb_pc_cpu_flush(&sc->sc_hw.root_pc); 1177213379Shselasky 1178213379Shselasky temp = trb->dwTrb3; 1179213379Shselasky 1180213379Shselasky if (j) 1181213379Shselasky temp |= htole32(XHCI_TRB_3_CYCLE_BIT); 1182213379Shselasky else 1183213379Shselasky temp &= ~htole32(XHCI_TRB_3_CYCLE_BIT); 1184213379Shselasky 1185213379Shselasky temp &= ~htole32(XHCI_TRB_3_TC_BIT); 1186213379Shselasky 1187213379Shselasky phwr->hwr_commands[i].dwTrb3 = temp; 1188213379Shselasky 1189213379Shselasky usb_pc_cpu_flush(&sc->sc_hw.root_pc); 1190213379Shselasky 1191213379Shselasky addr = buf_res.physaddr; 1192213379Shselasky addr += (uintptr_t)&((struct xhci_hw_root *)0)->hwr_commands[i]; 1193213379Shselasky 1194213379Shselasky sc->sc_cmd_addr = htole64(addr); 1195213379Shselasky 1196213379Shselasky i++; 1197213379Shselasky 1198213379Shselasky if (i == (XHCI_MAX_COMMANDS - 1)) { 1199213379Shselasky 1200213379Shselasky if (j) { 1201213379Shselasky temp = htole32(XHCI_TRB_3_TC_BIT | 1202213379Shselasky XHCI_TRB_3_TYPE_SET(XHCI_TRB_TYPE_LINK) | 1203213379Shselasky XHCI_TRB_3_CYCLE_BIT); 1204213379Shselasky } else { 1205213379Shselasky temp = htole32(XHCI_TRB_3_TC_BIT | 1206213379Shselasky XHCI_TRB_3_TYPE_SET(XHCI_TRB_TYPE_LINK)); 1207213379Shselasky } 1208213379Shselasky 1209213379Shselasky phwr->hwr_commands[i].dwTrb3 = temp; 1210213379Shselasky 1211213379Shselasky usb_pc_cpu_flush(&sc->sc_hw.root_pc); 1212213379Shselasky 1213213379Shselasky i = 0; 1214213379Shselasky j ^= 1; 1215213379Shselasky } 1216213379Shselasky 1217213379Shselasky sc->sc_command_idx = i; 1218213379Shselasky sc->sc_command_ccs = j; 1219213379Shselasky 1220213379Shselasky XWRITE4(sc, door, XHCI_DOORBELL(0), 0); 1221213379Shselasky 1222213379Shselasky err = cv_timedwait(&sc->sc_cmd_cv, &sc->sc_bus.bus_mtx, 1223213379Shselasky USB_MS_TO_TICKS(timeout_ms)); 1224213379Shselasky 1225255768Shselasky /* 1226255768Shselasky * In some error cases event interrupts are not generated. 1227255768Shselasky * Poll one time to see if the command has completed. 1228255768Shselasky */ 1229255768Shselasky if (err != 0 && xhci_interrupt_poll(sc) != 0) { 1230255768Shselasky DPRINTF("Command was completed when polling\n"); 1231255768Shselasky err = 0; 1232255768Shselasky } 1233255768Shselasky if (err != 0) { 1234259603Shselasky DPRINTF("Command timeout!\n"); 1235257110Shselasky /* 1236259603Shselasky * After some weeks of continuous operation, it has 1237259603Shselasky * been observed that the ASMedia Technology, ASM1042 1238259603Shselasky * SuperSpeed USB Host Controller can suddenly stop 1239259603Shselasky * accepting commands via the command queue. Try to 1240259603Shselasky * first reset the command queue. If that fails do a 1241259603Shselasky * host controller reset. 1242257110Shselasky */ 1243259603Shselasky if (timeout == 0 && 1244259603Shselasky xhci_reset_command_queue_locked(sc) == 0) { 1245264336Shselasky temp = le32toh(trb->dwTrb3); 1246264336Shselasky 1247264336Shselasky /* 1248264336Shselasky * Avoid infinite XHCI reset loops if the set 1249264336Shselasky * address command fails to respond due to a 1250264336Shselasky * non-enumerating device: 1251264336Shselasky */ 1252264336Shselasky if (XHCI_TRB_3_TYPE_GET(temp) == XHCI_TRB_TYPE_ADDRESS_DEVICE && 1253264336Shselasky (temp & XHCI_TRB_3_BSR_BIT) == 0) { 1254264336Shselasky DPRINTF("Set address timeout\n"); 1255264336Shselasky } else { 1256264336Shselasky timeout = 1; 1257264336Shselasky goto retry; 1258264336Shselasky } 1259259603Shselasky } else { 1260259603Shselasky DPRINTF("Controller reset!\n"); 1261259603Shselasky usb_bus_reset_async_locked(&sc->sc_bus); 1262257110Shselasky } 1263213379Shselasky err = USB_ERR_TIMEOUT; 1264213379Shselasky trb->dwTrb2 = 0; 1265213379Shselasky trb->dwTrb3 = 0; 1266213379Shselasky } else { 1267213379Shselasky temp = le32toh(sc->sc_cmd_result[0]); 1268213379Shselasky if (XHCI_TRB_2_ERROR_GET(temp) != XHCI_TRB_ERROR_SUCCESS) 1269213379Shselasky err = USB_ERR_IOERROR; 1270213379Shselasky 1271213379Shselasky trb->dwTrb2 = sc->sc_cmd_result[0]; 1272213379Shselasky trb->dwTrb3 = sc->sc_cmd_result[1]; 1273213379Shselasky } 1274213379Shselasky 1275213379Shselasky USB_BUS_UNLOCK(&sc->sc_bus); 1276213379Shselasky 1277213379Shselasky return (err); 1278213379Shselasky} 1279213379Shselasky 1280213379Shselasky#if 0 1281213379Shselaskystatic usb_error_t 1282213379Shselaskyxhci_cmd_nop(struct xhci_softc *sc) 1283213379Shselasky{ 1284213379Shselasky struct xhci_trb trb; 1285213379Shselasky uint32_t temp; 1286213379Shselasky 1287213379Shselasky DPRINTF("\n"); 1288213379Shselasky 1289213379Shselasky trb.qwTrb0 = 0; 1290213379Shselasky trb.dwTrb2 = 0; 1291213379Shselasky temp = XHCI_TRB_3_TYPE_SET(XHCI_TRB_TYPE_NOOP); 1292213379Shselasky 1293213379Shselasky trb.dwTrb3 = htole32(temp); 1294213379Shselasky 1295227654Shselasky return (xhci_do_command(sc, &trb, 100 /* ms */)); 1296213379Shselasky} 1297213379Shselasky#endif 1298213379Shselasky 1299213379Shselaskystatic usb_error_t 1300213379Shselaskyxhci_cmd_enable_slot(struct xhci_softc *sc, uint8_t *pslot) 1301213379Shselasky{ 1302213379Shselasky struct xhci_trb trb; 1303213379Shselasky uint32_t temp; 1304213379Shselasky usb_error_t err; 1305213379Shselasky 1306213379Shselasky DPRINTF("\n"); 1307213379Shselasky 1308213379Shselasky trb.qwTrb0 = 0; 1309213379Shselasky trb.dwTrb2 = 0; 1310213379Shselasky trb.dwTrb3 = htole32(XHCI_TRB_3_TYPE_SET(XHCI_TRB_TYPE_ENABLE_SLOT)); 1311213379Shselasky 1312227654Shselasky err = xhci_do_command(sc, &trb, 100 /* ms */); 1313213379Shselasky if (err) 1314213379Shselasky goto done; 1315213379Shselasky 1316213379Shselasky temp = le32toh(trb.dwTrb3); 1317213379Shselasky 1318213379Shselasky *pslot = XHCI_TRB_3_SLOT_GET(temp); 1319213379Shselasky 1320213379Shselaskydone: 1321213379Shselasky return (err); 1322213379Shselasky} 1323213379Shselasky 1324213379Shselaskystatic usb_error_t 1325213379Shselaskyxhci_cmd_disable_slot(struct xhci_softc *sc, uint8_t slot_id) 1326213379Shselasky{ 1327213379Shselasky struct xhci_trb trb; 1328213379Shselasky uint32_t temp; 1329213379Shselasky 1330213379Shselasky DPRINTF("\n"); 1331213379Shselasky 1332213379Shselasky trb.qwTrb0 = 0; 1333213379Shselasky trb.dwTrb2 = 0; 1334213379Shselasky temp = XHCI_TRB_3_TYPE_SET(XHCI_TRB_TYPE_DISABLE_SLOT) | 1335213379Shselasky XHCI_TRB_3_SLOT_SET(slot_id); 1336213379Shselasky 1337213379Shselasky trb.dwTrb3 = htole32(temp); 1338213379Shselasky 1339227654Shselasky return (xhci_do_command(sc, &trb, 100 /* ms */)); 1340213379Shselasky} 1341213379Shselasky 1342213379Shselaskystatic usb_error_t 1343213379Shselaskyxhci_cmd_set_address(struct xhci_softc *sc, uint64_t input_ctx, 1344213379Shselasky uint8_t bsr, uint8_t slot_id) 1345213379Shselasky{ 1346213379Shselasky struct xhci_trb trb; 1347213379Shselasky uint32_t temp; 1348213379Shselasky 1349213379Shselasky DPRINTF("\n"); 1350213379Shselasky 1351213379Shselasky trb.qwTrb0 = htole64(input_ctx); 1352213379Shselasky trb.dwTrb2 = 0; 1353213379Shselasky temp = XHCI_TRB_3_TYPE_SET(XHCI_TRB_TYPE_ADDRESS_DEVICE) | 1354213379Shselasky XHCI_TRB_3_SLOT_SET(slot_id); 1355213379Shselasky 1356213379Shselasky if (bsr) 1357213379Shselasky temp |= XHCI_TRB_3_BSR_BIT; 1358213379Shselasky 1359213379Shselasky trb.dwTrb3 = htole32(temp); 1360213379Shselasky 1361213379Shselasky return (xhci_do_command(sc, &trb, 500 /* ms */)); 1362213379Shselasky} 1363213379Shselasky 1364213379Shselaskystatic usb_error_t 1365213379Shselaskyxhci_set_address(struct usb_device *udev, struct mtx *mtx, uint16_t address) 1366213379Shselasky{ 1367213379Shselasky struct usb_page_search buf_inp; 1368213379Shselasky struct usb_page_search buf_dev; 1369213379Shselasky struct xhci_softc *sc = XHCI_BUS2SC(udev->bus); 1370213379Shselasky struct xhci_hw_dev *hdev; 1371213379Shselasky struct xhci_dev_ctx *pdev; 1372213379Shselasky struct xhci_endpoint_ext *pepext; 1373217374Shselasky uint32_t temp; 1374213379Shselasky uint16_t mps; 1375213379Shselasky usb_error_t err; 1376213379Shselasky uint8_t index; 1377213379Shselasky 1378213379Shselasky /* the root HUB case is not handled here */ 1379213379Shselasky if (udev->parent_hub == NULL) 1380213379Shselasky return (USB_ERR_INVAL); 1381213379Shselasky 1382213379Shselasky index = udev->controller_slot_id; 1383213379Shselasky 1384213379Shselasky hdev = &sc->sc_hw.devs[index]; 1385213379Shselasky 1386213379Shselasky if (mtx != NULL) 1387213379Shselasky mtx_unlock(mtx); 1388213379Shselasky 1389213379Shselasky XHCI_CMD_LOCK(sc); 1390213379Shselasky 1391213379Shselasky switch (hdev->state) { 1392213379Shselasky case XHCI_ST_DEFAULT: 1393213379Shselasky case XHCI_ST_ENABLED: 1394213379Shselasky 1395213379Shselasky hdev->state = XHCI_ST_ENABLED; 1396213379Shselasky 1397213379Shselasky /* set configure mask to slot and EP0 */ 1398213379Shselasky xhci_configure_mask(udev, 3, 0); 1399213379Shselasky 1400213379Shselasky /* configure input slot context structure */ 1401213379Shselasky err = xhci_configure_device(udev); 1402213379Shselasky 1403213379Shselasky if (err != 0) { 1404213379Shselasky DPRINTF("Could not configure device\n"); 1405213379Shselasky break; 1406213379Shselasky } 1407213379Shselasky 1408213379Shselasky /* configure input endpoint context structure */ 1409213379Shselasky switch (udev->speed) { 1410213379Shselasky case USB_SPEED_LOW: 1411213379Shselasky case USB_SPEED_FULL: 1412213379Shselasky mps = 8; 1413213379Shselasky break; 1414213379Shselasky case USB_SPEED_HIGH: 1415213379Shselasky mps = 64; 1416213379Shselasky break; 1417213379Shselasky default: 1418213379Shselasky mps = 512; 1419213379Shselasky break; 1420213379Shselasky } 1421213379Shselasky 1422213379Shselasky pepext = xhci_get_endpoint_ext(udev, 1423213379Shselasky &udev->ctrl_ep_desc); 1424279353Shselasky 1425279353Shselasky /* ensure the control endpoint is setup again */ 1426279353Shselasky USB_BUS_LOCK(udev->bus); 1427279353Shselasky pepext->trb_halted = 1; 1428279353Shselasky pepext->trb_running = 0; 1429279353Shselasky USB_BUS_UNLOCK(udev->bus); 1430279353Shselasky 1431213379Shselasky err = xhci_configure_endpoint(udev, 1432251247Shselasky &udev->ctrl_ep_desc, pepext, 1433239214Shselasky 0, 1, 1, 0, mps, mps, USB_EP_MODE_DEFAULT); 1434213379Shselasky 1435213379Shselasky if (err != 0) { 1436213379Shselasky DPRINTF("Could not configure default endpoint\n"); 1437213379Shselasky break; 1438213379Shselasky } 1439213379Shselasky 1440213379Shselasky /* execute set address command */ 1441213379Shselasky usbd_get_page(&hdev->input_pc, 0, &buf_inp); 1442213379Shselasky 1443213379Shselasky err = xhci_cmd_set_address(sc, buf_inp.physaddr, 1444213379Shselasky (address == 0), index); 1445213379Shselasky 1446213379Shselasky if (err != 0) { 1447255768Shselasky temp = le32toh(sc->sc_cmd_result[0]); 1448255768Shselasky if (address == 0 && sc->sc_port_route != NULL && 1449255768Shselasky XHCI_TRB_2_ERROR_GET(temp) == 1450255768Shselasky XHCI_TRB_ERROR_PARAMETER) { 1451255768Shselasky /* LynxPoint XHCI - ports are not switchable */ 1452255768Shselasky /* Un-route all ports from the XHCI */ 1453255768Shselasky sc->sc_port_route(sc->sc_bus.parent, 0, ~0); 1454255768Shselasky } 1455213379Shselasky DPRINTF("Could not set address " 1456213379Shselasky "for slot %u.\n", index); 1457213379Shselasky if (address != 0) 1458213379Shselasky break; 1459213379Shselasky } 1460213379Shselasky 1461213379Shselasky /* update device address to new value */ 1462213379Shselasky 1463213379Shselasky usbd_get_page(&hdev->device_pc, 0, &buf_dev); 1464213379Shselasky pdev = buf_dev.buffer; 1465213379Shselasky usb_pc_cpu_invalidate(&hdev->device_pc); 1466213379Shselasky 1467217374Shselasky temp = xhci_ctx_get_le32(sc, &pdev->ctx_slot.dwSctx3); 1468217374Shselasky udev->address = XHCI_SCTX_3_DEV_ADDR_GET(temp); 1469217374Shselasky 1470213379Shselasky /* update device state to new value */ 1471213379Shselasky 1472213379Shselasky if (address != 0) 1473213379Shselasky hdev->state = XHCI_ST_ADDRESSED; 1474213379Shselasky else 1475213379Shselasky hdev->state = XHCI_ST_DEFAULT; 1476213379Shselasky break; 1477213379Shselasky 1478213379Shselasky default: 1479213379Shselasky DPRINTF("Wrong state for set address.\n"); 1480213379Shselasky err = USB_ERR_IOERROR; 1481213379Shselasky break; 1482213379Shselasky } 1483213379Shselasky XHCI_CMD_UNLOCK(sc); 1484213379Shselasky 1485213379Shselasky if (mtx != NULL) 1486213379Shselasky mtx_lock(mtx); 1487213379Shselasky 1488213379Shselasky return (err); 1489213379Shselasky} 1490213379Shselasky 1491213379Shselaskystatic usb_error_t 1492213379Shselaskyxhci_cmd_configure_ep(struct xhci_softc *sc, uint64_t input_ctx, 1493213379Shselasky uint8_t deconfigure, uint8_t slot_id) 1494213379Shselasky{ 1495213379Shselasky struct xhci_trb trb; 1496213379Shselasky uint32_t temp; 1497213379Shselasky 1498213379Shselasky DPRINTF("\n"); 1499213379Shselasky 1500213379Shselasky trb.qwTrb0 = htole64(input_ctx); 1501213379Shselasky trb.dwTrb2 = 0; 1502213379Shselasky temp = XHCI_TRB_3_TYPE_SET(XHCI_TRB_TYPE_CONFIGURE_EP) | 1503213379Shselasky XHCI_TRB_3_SLOT_SET(slot_id); 1504213379Shselasky 1505213379Shselasky if (deconfigure) 1506213379Shselasky temp |= XHCI_TRB_3_DCEP_BIT; 1507213379Shselasky 1508213379Shselasky trb.dwTrb3 = htole32(temp); 1509213379Shselasky 1510227654Shselasky return (xhci_do_command(sc, &trb, 100 /* ms */)); 1511213379Shselasky} 1512213379Shselasky 1513213379Shselaskystatic usb_error_t 1514213379Shselaskyxhci_cmd_evaluate_ctx(struct xhci_softc *sc, uint64_t input_ctx, 1515213379Shselasky uint8_t slot_id) 1516213379Shselasky{ 1517213379Shselasky struct xhci_trb trb; 1518213379Shselasky uint32_t temp; 1519213379Shselasky 1520213379Shselasky DPRINTF("\n"); 1521213379Shselasky 1522213379Shselasky trb.qwTrb0 = htole64(input_ctx); 1523213379Shselasky trb.dwTrb2 = 0; 1524213379Shselasky temp = XHCI_TRB_3_TYPE_SET(XHCI_TRB_TYPE_EVALUATE_CTX) | 1525213379Shselasky XHCI_TRB_3_SLOT_SET(slot_id); 1526213379Shselasky trb.dwTrb3 = htole32(temp); 1527213379Shselasky 1528227654Shselasky return (xhci_do_command(sc, &trb, 100 /* ms */)); 1529213379Shselasky} 1530213379Shselasky 1531213379Shselaskystatic usb_error_t 1532213379Shselaskyxhci_cmd_reset_ep(struct xhci_softc *sc, uint8_t preserve, 1533213379Shselasky uint8_t ep_id, uint8_t slot_id) 1534213379Shselasky{ 1535213379Shselasky struct xhci_trb trb; 1536213379Shselasky uint32_t temp; 1537213379Shselasky 1538213379Shselasky DPRINTF("\n"); 1539213379Shselasky 1540213379Shselasky trb.qwTrb0 = 0; 1541213379Shselasky trb.dwTrb2 = 0; 1542213379Shselasky temp = XHCI_TRB_3_TYPE_SET(XHCI_TRB_TYPE_RESET_EP) | 1543213379Shselasky XHCI_TRB_3_SLOT_SET(slot_id) | 1544213379Shselasky XHCI_TRB_3_EP_SET(ep_id); 1545213379Shselasky 1546213379Shselasky if (preserve) 1547213379Shselasky temp |= XHCI_TRB_3_PRSV_BIT; 1548213379Shselasky 1549213379Shselasky trb.dwTrb3 = htole32(temp); 1550213379Shselasky 1551227654Shselasky return (xhci_do_command(sc, &trb, 100 /* ms */)); 1552213379Shselasky} 1553213379Shselasky 1554213379Shselaskystatic usb_error_t 1555213379Shselaskyxhci_cmd_set_tr_dequeue_ptr(struct xhci_softc *sc, uint64_t dequeue_ptr, 1556213379Shselasky uint16_t stream_id, uint8_t ep_id, uint8_t slot_id) 1557213379Shselasky{ 1558213379Shselasky struct xhci_trb trb; 1559213379Shselasky uint32_t temp; 1560213379Shselasky 1561213379Shselasky DPRINTF("\n"); 1562213379Shselasky 1563213379Shselasky trb.qwTrb0 = htole64(dequeue_ptr); 1564213379Shselasky 1565213379Shselasky temp = XHCI_TRB_2_STREAM_SET(stream_id); 1566213379Shselasky trb.dwTrb2 = htole32(temp); 1567213379Shselasky 1568213379Shselasky temp = XHCI_TRB_3_TYPE_SET(XHCI_TRB_TYPE_SET_TR_DEQUEUE) | 1569213379Shselasky XHCI_TRB_3_SLOT_SET(slot_id) | 1570213379Shselasky XHCI_TRB_3_EP_SET(ep_id); 1571213379Shselasky trb.dwTrb3 = htole32(temp); 1572213379Shselasky 1573227654Shselasky return (xhci_do_command(sc, &trb, 100 /* ms */)); 1574213379Shselasky} 1575213379Shselasky 1576213379Shselaskystatic usb_error_t 1577213379Shselaskyxhci_cmd_stop_ep(struct xhci_softc *sc, uint8_t suspend, 1578213379Shselasky uint8_t ep_id, uint8_t slot_id) 1579213379Shselasky{ 1580213379Shselasky struct xhci_trb trb; 1581213379Shselasky uint32_t temp; 1582213379Shselasky 1583213379Shselasky DPRINTF("\n"); 1584213379Shselasky 1585213379Shselasky trb.qwTrb0 = 0; 1586213379Shselasky trb.dwTrb2 = 0; 1587213379Shselasky temp = XHCI_TRB_3_TYPE_SET(XHCI_TRB_TYPE_STOP_EP) | 1588213379Shselasky XHCI_TRB_3_SLOT_SET(slot_id) | 1589213379Shselasky XHCI_TRB_3_EP_SET(ep_id); 1590213379Shselasky 1591213379Shselasky if (suspend) 1592213379Shselasky temp |= XHCI_TRB_3_SUSP_EP_BIT; 1593213379Shselasky 1594213379Shselasky trb.dwTrb3 = htole32(temp); 1595213379Shselasky 1596227654Shselasky return (xhci_do_command(sc, &trb, 100 /* ms */)); 1597213379Shselasky} 1598213379Shselasky 1599213379Shselaskystatic usb_error_t 1600213379Shselaskyxhci_cmd_reset_dev(struct xhci_softc *sc, uint8_t slot_id) 1601213379Shselasky{ 1602213379Shselasky struct xhci_trb trb; 1603213379Shselasky uint32_t temp; 1604213379Shselasky 1605213379Shselasky DPRINTF("\n"); 1606213379Shselasky 1607213379Shselasky trb.qwTrb0 = 0; 1608213379Shselasky trb.dwTrb2 = 0; 1609213379Shselasky temp = XHCI_TRB_3_TYPE_SET(XHCI_TRB_TYPE_RESET_DEVICE) | 1610213379Shselasky XHCI_TRB_3_SLOT_SET(slot_id); 1611213379Shselasky 1612213379Shselasky trb.dwTrb3 = htole32(temp); 1613213379Shselasky 1614227654Shselasky return (xhci_do_command(sc, &trb, 100 /* ms */)); 1615213379Shselasky} 1616213379Shselasky 1617213379Shselasky/*------------------------------------------------------------------------* 1618213379Shselasky * xhci_interrupt - XHCI interrupt handler 1619213379Shselasky *------------------------------------------------------------------------*/ 1620213379Shselaskyvoid 1621213379Shselaskyxhci_interrupt(struct xhci_softc *sc) 1622213379Shselasky{ 1623213379Shselasky uint32_t status; 1624261096Shselasky uint32_t temp; 1625213379Shselasky 1626213379Shselasky USB_BUS_LOCK(&sc->sc_bus); 1627213379Shselasky 1628213379Shselasky status = XREAD4(sc, oper, XHCI_USBSTS); 1629213379Shselasky 1630261096Shselasky /* acknowledge interrupts, if any */ 1631261096Shselasky if (status != 0) { 1632261096Shselasky XWRITE4(sc, oper, XHCI_USBSTS, status); 1633261096Shselasky DPRINTFN(16, "real interrupt (status=0x%08x)\n", status); 1634261096Shselasky } 1635213379Shselasky 1636261096Shselasky temp = XREAD4(sc, runt, XHCI_IMAN(0)); 1637213379Shselasky 1638261096Shselasky /* force clearing of pending interrupts */ 1639261096Shselasky if (temp & XHCI_IMAN_INTR_PEND) 1640261096Shselasky XWRITE4(sc, runt, XHCI_IMAN(0), temp); 1641245175Shselasky 1642261096Shselasky /* check for event(s) */ 1643261096Shselasky xhci_interrupt_poll(sc); 1644213379Shselasky 1645245132Shselasky if (status & (XHCI_STS_PCD | XHCI_STS_HCH | 1646245132Shselasky XHCI_STS_HSE | XHCI_STS_HCE)) { 1647245132Shselasky 1648213379Shselasky if (status & XHCI_STS_PCD) { 1649213379Shselasky xhci_root_intr(sc); 1650213379Shselasky } 1651213379Shselasky 1652213379Shselasky if (status & XHCI_STS_HCH) { 1653213379Shselasky printf("%s: host controller halted\n", 1654213379Shselasky __FUNCTION__); 1655213379Shselasky } 1656213379Shselasky 1657213379Shselasky if (status & XHCI_STS_HSE) { 1658213379Shselasky printf("%s: host system error\n", 1659213379Shselasky __FUNCTION__); 1660213379Shselasky } 1661213379Shselasky 1662213379Shselasky if (status & XHCI_STS_HCE) { 1663213379Shselasky printf("%s: host controller error\n", 1664213379Shselasky __FUNCTION__); 1665213379Shselasky } 1666213379Shselasky } 1667213379Shselasky USB_BUS_UNLOCK(&sc->sc_bus); 1668213379Shselasky} 1669213379Shselasky 1670213379Shselasky/*------------------------------------------------------------------------* 1671213379Shselasky * xhci_timeout - XHCI timeout handler 1672213379Shselasky *------------------------------------------------------------------------*/ 1673213379Shselaskystatic void 1674213379Shselaskyxhci_timeout(void *arg) 1675213379Shselasky{ 1676213379Shselasky struct usb_xfer *xfer = arg; 1677213379Shselasky 1678213379Shselasky DPRINTF("xfer=%p\n", xfer); 1679213379Shselasky 1680213379Shselasky USB_BUS_LOCK_ASSERT(xfer->xroot->bus, MA_OWNED); 1681213379Shselasky 1682213379Shselasky /* transfer is transferred */ 1683213379Shselasky xhci_device_done(xfer, USB_ERR_TIMEOUT); 1684213379Shselasky} 1685213379Shselasky 1686213379Shselaskystatic void 1687213379Shselaskyxhci_do_poll(struct usb_bus *bus) 1688213379Shselasky{ 1689213379Shselasky struct xhci_softc *sc = XHCI_BUS2SC(bus); 1690213379Shselasky 1691213379Shselasky USB_BUS_LOCK(&sc->sc_bus); 1692213379Shselasky xhci_interrupt_poll(sc); 1693213379Shselasky USB_BUS_UNLOCK(&sc->sc_bus); 1694213379Shselasky} 1695213379Shselasky 1696213379Shselaskystatic void 1697213379Shselaskyxhci_setup_generic_chain_sub(struct xhci_std_temp *temp) 1698213379Shselasky{ 1699213379Shselasky struct usb_page_search buf_res; 1700213379Shselasky struct xhci_td *td; 1701213379Shselasky struct xhci_td *td_next; 1702213379Shselasky struct xhci_td *td_alt_next; 1703251515Shselasky struct xhci_td *td_first; 1704213379Shselasky uint32_t buf_offset; 1705213379Shselasky uint32_t average; 1706213379Shselasky uint32_t len_old; 1707251254Shselasky uint32_t npkt_off; 1708213379Shselasky uint32_t dword; 1709213379Shselasky uint8_t shortpkt_old; 1710213379Shselasky uint8_t precompute; 1711213379Shselasky uint8_t x; 1712213379Shselasky 1713213379Shselasky td_alt_next = NULL; 1714213379Shselasky buf_offset = 0; 1715213379Shselasky shortpkt_old = temp->shortpkt; 1716213379Shselasky len_old = temp->len; 1717251254Shselasky npkt_off = 0; 1718213379Shselasky precompute = 1; 1719213379Shselasky 1720213379Shselaskyrestart: 1721213379Shselasky 1722213379Shselasky td = temp->td; 1723251515Shselasky td_next = td_first = temp->td_next; 1724213379Shselasky 1725213379Shselasky while (1) { 1726213379Shselasky 1727213379Shselasky if (temp->len == 0) { 1728213379Shselasky 1729213379Shselasky if (temp->shortpkt) 1730213379Shselasky break; 1731213379Shselasky 1732213379Shselasky /* send a Zero Length Packet, ZLP, last */ 1733213379Shselasky 1734213379Shselasky temp->shortpkt = 1; 1735213379Shselasky average = 0; 1736213379Shselasky 1737213379Shselasky } else { 1738213379Shselasky 1739213379Shselasky average = temp->average; 1740213379Shselasky 1741213379Shselasky if (temp->len < average) { 1742213379Shselasky if (temp->len % temp->max_packet_size) { 1743213379Shselasky temp->shortpkt = 1; 1744213379Shselasky } 1745213379Shselasky average = temp->len; 1746213379Shselasky } 1747213379Shselasky } 1748213379Shselasky 1749213379Shselasky if (td_next == NULL) 1750213379Shselasky panic("%s: out of XHCI transfer descriptors!", __FUNCTION__); 1751213379Shselasky 1752213379Shselasky /* get next TD */ 1753213379Shselasky 1754213379Shselasky td = td_next; 1755213379Shselasky td_next = td->obj_next; 1756213379Shselasky 1757213379Shselasky /* check if we are pre-computing */ 1758213379Shselasky 1759213379Shselasky if (precompute) { 1760213379Shselasky 1761213379Shselasky /* update remaining length */ 1762213379Shselasky 1763213379Shselasky temp->len -= average; 1764213379Shselasky 1765213379Shselasky continue; 1766213379Shselasky } 1767213379Shselasky /* fill out current TD */ 1768213379Shselasky 1769213379Shselasky td->len = average; 1770213379Shselasky td->remainder = 0; 1771213379Shselasky td->status = 0; 1772213379Shselasky 1773213379Shselasky /* update remaining length */ 1774213379Shselasky 1775213379Shselasky temp->len -= average; 1776213379Shselasky 1777213379Shselasky /* reset TRB index */ 1778213379Shselasky 1779213379Shselasky x = 0; 1780213379Shselasky 1781213379Shselasky if (temp->trb_type == XHCI_TRB_TYPE_SETUP_STAGE) { 1782213379Shselasky /* immediate data */ 1783213379Shselasky 1784213379Shselasky if (average > 8) 1785213379Shselasky average = 8; 1786213379Shselasky 1787213379Shselasky td->td_trb[0].qwTrb0 = 0; 1788213379Shselasky 1789213379Shselasky usbd_copy_out(temp->pc, temp->offset + buf_offset, 1790213379Shselasky (uint8_t *)(uintptr_t)&td->td_trb[0].qwTrb0, 1791213379Shselasky average); 1792213379Shselasky 1793213379Shselasky dword = XHCI_TRB_2_BYTES_SET(8) | 1794213379Shselasky XHCI_TRB_2_TDSZ_SET(0) | 1795213379Shselasky XHCI_TRB_2_IRQ_SET(0); 1796213379Shselasky 1797213379Shselasky td->td_trb[0].dwTrb2 = htole32(dword); 1798213379Shselasky 1799213379Shselasky dword = XHCI_TRB_3_TYPE_SET(XHCI_TRB_TYPE_SETUP_STAGE) | 1800213379Shselasky XHCI_TRB_3_IDT_BIT | XHCI_TRB_3_CYCLE_BIT; 1801213379Shselasky 1802213379Shselasky /* check wLength */ 1803213379Shselasky if (td->td_trb[0].qwTrb0 & 1804213379Shselasky htole64(XHCI_TRB_0_WLENGTH_MASK)) { 1805262370Shselasky if (td->td_trb[0].qwTrb0 & 1806262370Shselasky htole64(XHCI_TRB_0_DIR_IN_MASK)) 1807213379Shselasky dword |= XHCI_TRB_3_TRT_IN; 1808213379Shselasky else 1809213379Shselasky dword |= XHCI_TRB_3_TRT_OUT; 1810213379Shselasky } 1811213379Shselasky 1812213379Shselasky td->td_trb[0].dwTrb3 = htole32(dword); 1813213379Shselasky#ifdef USB_DEBUG 1814213379Shselasky xhci_dump_trb(&td->td_trb[x]); 1815213379Shselasky#endif 1816213379Shselasky x++; 1817213379Shselasky 1818213379Shselasky } else do { 1819213379Shselasky 1820213379Shselasky uint32_t npkt; 1821213379Shselasky 1822213379Shselasky /* fill out buffer pointers */ 1823213379Shselasky 1824213379Shselasky if (average == 0) { 1825213379Shselasky memset(&buf_res, 0, sizeof(buf_res)); 1826213379Shselasky } else { 1827213379Shselasky usbd_get_page(temp->pc, temp->offset + 1828213379Shselasky buf_offset, &buf_res); 1829213379Shselasky 1830213379Shselasky /* get length to end of page */ 1831213379Shselasky if (buf_res.length > average) 1832213379Shselasky buf_res.length = average; 1833213379Shselasky 1834213379Shselasky /* check for maximum length */ 1835213379Shselasky if (buf_res.length > XHCI_TD_PAGE_SIZE) 1836213379Shselasky buf_res.length = XHCI_TD_PAGE_SIZE; 1837213379Shselasky 1838251254Shselasky npkt_off += buf_res.length; 1839253532Shselasky } 1840251254Shselasky 1841278278Shselasky /* set up npkt */ 1842253532Shselasky npkt = (len_old - npkt_off + temp->max_packet_size - 1) / 1843253532Shselasky temp->max_packet_size; 1844213379Shselasky 1845253532Shselasky if (npkt == 0) 1846253532Shselasky npkt = 1; 1847253532Shselasky else if (npkt > 31) 1848253532Shselasky npkt = 31; 1849213379Shselasky 1850213379Shselasky /* fill out TRB's */ 1851213379Shselasky td->td_trb[x].qwTrb0 = 1852213379Shselasky htole64((uint64_t)buf_res.physaddr); 1853213379Shselasky 1854213379Shselasky dword = 1855213379Shselasky XHCI_TRB_2_BYTES_SET(buf_res.length) | 1856213379Shselasky XHCI_TRB_2_TDSZ_SET(npkt) | 1857213379Shselasky XHCI_TRB_2_IRQ_SET(0); 1858213379Shselasky 1859213379Shselasky td->td_trb[x].dwTrb2 = htole32(dword); 1860213379Shselasky 1861251515Shselasky switch (temp->trb_type) { 1862251515Shselasky case XHCI_TRB_TYPE_ISOCH: 1863251515Shselasky dword = XHCI_TRB_3_CHAIN_BIT | XHCI_TRB_3_CYCLE_BIT | 1864251515Shselasky XHCI_TRB_3_TBC_SET(temp->tbc) | 1865251515Shselasky XHCI_TRB_3_TLBPC_SET(temp->tlbpc); 1866251515Shselasky if (td != td_first) { 1867251515Shselasky dword |= XHCI_TRB_3_TYPE_SET(XHCI_TRB_TYPE_NORMAL); 1868251515Shselasky } else if (temp->do_isoc_sync != 0) { 1869251249Shselasky temp->do_isoc_sync = 0; 1870251515Shselasky /* wait until "isoc_frame" */ 1871251515Shselasky dword |= XHCI_TRB_3_TYPE_SET(XHCI_TRB_TYPE_ISOCH) | 1872251515Shselasky XHCI_TRB_3_FRID_SET(temp->isoc_frame / 8); 1873251249Shselasky } else { 1874251515Shselasky /* start data transfer at next interval */ 1875251515Shselasky dword |= XHCI_TRB_3_TYPE_SET(XHCI_TRB_TYPE_ISOCH) | 1876251515Shselasky XHCI_TRB_3_ISO_SIA_BIT; 1877251249Shselasky } 1878251515Shselasky if (temp->direction == UE_DIR_IN) 1879266669Shselasky dword |= XHCI_TRB_3_ISP_BIT; 1880251515Shselasky break; 1881251515Shselasky case XHCI_TRB_TYPE_DATA_STAGE: 1882251515Shselasky dword = XHCI_TRB_3_CHAIN_BIT | XHCI_TRB_3_CYCLE_BIT | 1883266669Shselasky XHCI_TRB_3_TYPE_SET(XHCI_TRB_TYPE_DATA_STAGE); 1884251515Shselasky if (temp->direction == UE_DIR_IN) 1885251515Shselasky dword |= XHCI_TRB_3_DIR_IN | XHCI_TRB_3_ISP_BIT; 1886278507Shselasky /* 1887278507Shselasky * Section 3.2.9 in the XHCI 1888278507Shselasky * specification about control 1889278507Shselasky * transfers says that we should use a 1890278507Shselasky * normal-TRB if there are more TRBs 1891278507Shselasky * extending the data-stage 1892278507Shselasky * TRB. Update the "trb_type". 1893278507Shselasky */ 1894278507Shselasky temp->trb_type = XHCI_TRB_TYPE_NORMAL; 1895251515Shselasky break; 1896251515Shselasky case XHCI_TRB_TYPE_STATUS_STAGE: 1897251515Shselasky dword = XHCI_TRB_3_CHAIN_BIT | XHCI_TRB_3_CYCLE_BIT | 1898266669Shselasky XHCI_TRB_3_TYPE_SET(XHCI_TRB_TYPE_STATUS_STAGE); 1899251515Shselasky if (temp->direction == UE_DIR_IN) 1900251515Shselasky dword |= XHCI_TRB_3_DIR_IN; 1901251515Shselasky break; 1902251515Shselasky default: /* XHCI_TRB_TYPE_NORMAL */ 1903251515Shselasky dword = XHCI_TRB_3_CHAIN_BIT | XHCI_TRB_3_CYCLE_BIT | 1904266669Shselasky XHCI_TRB_3_TYPE_SET(XHCI_TRB_TYPE_NORMAL); 1905251515Shselasky if (temp->direction == UE_DIR_IN) 1906266669Shselasky dword |= XHCI_TRB_3_ISP_BIT; 1907251515Shselasky break; 1908251249Shselasky } 1909213379Shselasky td->td_trb[x].dwTrb3 = htole32(dword); 1910213379Shselasky 1911213379Shselasky average -= buf_res.length; 1912213379Shselasky buf_offset += buf_res.length; 1913213379Shselasky#ifdef USB_DEBUG 1914213379Shselasky xhci_dump_trb(&td->td_trb[x]); 1915213379Shselasky#endif 1916213379Shselasky x++; 1917213379Shselasky 1918213379Shselasky } while (average != 0); 1919213379Shselasky 1920213379Shselasky td->td_trb[x-1].dwTrb3 |= htole32(XHCI_TRB_3_IOC_BIT); 1921213379Shselasky 1922213379Shselasky /* store number of data TRB's */ 1923213379Shselasky 1924213379Shselasky td->ntrb = x; 1925213379Shselasky 1926213379Shselasky DPRINTF("NTRB=%u\n", x); 1927213379Shselasky 1928213379Shselasky /* fill out link TRB */ 1929213379Shselasky 1930213379Shselasky if (td_next != NULL) { 1931213379Shselasky /* link the current TD with the next one */ 1932213379Shselasky td->td_trb[x].qwTrb0 = htole64((uint64_t)td_next->td_self); 1933213379Shselasky DPRINTF("LINK=0x%08llx\n", (long long)td_next->td_self); 1934213379Shselasky } else { 1935213379Shselasky /* this field will get updated later */ 1936213379Shselasky DPRINTF("NOLINK\n"); 1937213379Shselasky } 1938213379Shselasky 1939213379Shselasky dword = XHCI_TRB_2_IRQ_SET(0); 1940213379Shselasky 1941213379Shselasky td->td_trb[x].dwTrb2 = htole32(dword); 1942213379Shselasky 1943213379Shselasky dword = XHCI_TRB_3_TYPE_SET(XHCI_TRB_TYPE_LINK) | 1944259607Shselasky XHCI_TRB_3_CYCLE_BIT | XHCI_TRB_3_IOC_BIT | 1945259607Shselasky /* 1946259607Shselasky * CHAIN-BIT: Ensure that a multi-TRB IN-endpoint 1947259607Shselasky * frame only receives a single short packet event 1948259607Shselasky * by setting the CHAIN bit in the LINK field. In 1949259607Shselasky * addition some XHCI controllers have problems 1950259607Shselasky * sending a ZLP unless the CHAIN-BIT is set in 1951259607Shselasky * the LINK TRB. 1952259607Shselasky */ 1953259607Shselasky XHCI_TRB_3_CHAIN_BIT; 1954213379Shselasky 1955213379Shselasky td->td_trb[x].dwTrb3 = htole32(dword); 1956213379Shselasky 1957213379Shselasky td->alt_next = td_alt_next; 1958213379Shselasky#ifdef USB_DEBUG 1959213379Shselasky xhci_dump_trb(&td->td_trb[x]); 1960213379Shselasky#endif 1961213379Shselasky usb_pc_cpu_flush(td->page_cache); 1962213379Shselasky } 1963213379Shselasky 1964213379Shselasky if (precompute) { 1965213379Shselasky precompute = 0; 1966213379Shselasky 1967278278Shselasky /* set up alt next pointer, if any */ 1968213379Shselasky if (temp->last_frame) { 1969213379Shselasky td_alt_next = NULL; 1970213379Shselasky } else { 1971213379Shselasky /* we use this field internally */ 1972213379Shselasky td_alt_next = td_next; 1973213379Shselasky } 1974213379Shselasky 1975213379Shselasky /* restore */ 1976213379Shselasky temp->shortpkt = shortpkt_old; 1977213379Shselasky temp->len = len_old; 1978213379Shselasky goto restart; 1979213379Shselasky } 1980213379Shselasky 1981251515Shselasky /* 1982251515Shselasky * Remove cycle bit from the first TRB if we are 1983251515Shselasky * stepping them: 1984251515Shselasky */ 1985251515Shselasky if (temp->step_td != 0) { 1986251515Shselasky td_first->td_trb[0].dwTrb3 &= ~htole32(XHCI_TRB_3_CYCLE_BIT); 1987251515Shselasky usb_pc_cpu_flush(td_first->page_cache); 1988251251Shselasky } 1989213379Shselasky 1990253532Shselasky /* clear TD SIZE to zero, hence this is the last TRB */ 1991259607Shselasky /* remove chain bit because this is the last data TRB in the chain */ 1992213379Shselasky td->td_trb[td->ntrb - 1].dwTrb2 &= ~htole32(XHCI_TRB_2_TDSZ_SET(15)); 1993213379Shselasky td->td_trb[td->ntrb - 1].dwTrb3 &= ~htole32(XHCI_TRB_3_CHAIN_BIT); 1994259607Shselasky /* remove CHAIN-BIT from last LINK TRB */ 1995259607Shselasky td->td_trb[td->ntrb].dwTrb3 &= ~htole32(XHCI_TRB_3_CHAIN_BIT); 1996213379Shselasky 1997213379Shselasky usb_pc_cpu_flush(td->page_cache); 1998213379Shselasky 1999213379Shselasky temp->td = td; 2000213379Shselasky temp->td_next = td_next; 2001213379Shselasky} 2002213379Shselasky 2003213379Shselaskystatic void 2004213379Shselaskyxhci_setup_generic_chain(struct usb_xfer *xfer) 2005213379Shselasky{ 2006213379Shselasky struct xhci_std_temp temp; 2007213379Shselasky struct xhci_td *td; 2008213379Shselasky uint32_t x; 2009213379Shselasky uint32_t y; 2010213379Shselasky uint8_t mult; 2011213379Shselasky 2012234803Shselasky temp.do_isoc_sync = 0; 2013213379Shselasky temp.step_td = 0; 2014213379Shselasky temp.tbc = 0; 2015213379Shselasky temp.tlbpc = 0; 2016213379Shselasky temp.average = xfer->max_hc_frame_size; 2017213379Shselasky temp.max_packet_size = xfer->max_packet_size; 2018213379Shselasky temp.sc = XHCI_BUS2SC(xfer->xroot->bus); 2019213379Shselasky temp.pc = NULL; 2020213379Shselasky temp.last_frame = 0; 2021213379Shselasky temp.offset = 0; 2022213379Shselasky temp.multishort = xfer->flags_int.isochronous_xfr || 2023213379Shselasky xfer->flags_int.control_xfr || 2024213379Shselasky xfer->flags_int.short_frames_ok; 2025213379Shselasky 2026213379Shselasky /* toggle the DMA set we are using */ 2027213379Shselasky xfer->flags_int.curr_dma_set ^= 1; 2028213379Shselasky 2029213379Shselasky /* get next DMA set */ 2030213379Shselasky td = xfer->td_start[xfer->flags_int.curr_dma_set]; 2031213379Shselasky 2032213379Shselasky temp.td = NULL; 2033213379Shselasky temp.td_next = td; 2034213379Shselasky 2035213379Shselasky xfer->td_transfer_first = td; 2036213379Shselasky xfer->td_transfer_cache = td; 2037213379Shselasky 2038213379Shselasky if (xfer->flags_int.isochronous_xfr) { 2039213379Shselasky uint8_t shift; 2040213379Shselasky 2041213379Shselasky /* compute multiplier for ISOCHRONOUS transfers */ 2042213379Shselasky mult = xfer->endpoint->ecomp ? 2043239214Shselasky UE_GET_SS_ISO_MULT(xfer->endpoint->ecomp->bmAttributes) 2044239214Shselasky : 0; 2045213379Shselasky /* check for USB 2.0 multiplier */ 2046213379Shselasky if (mult == 0) { 2047213379Shselasky mult = (xfer->endpoint->edesc-> 2048213379Shselasky wMaxPacketSize[1] >> 3) & 3; 2049213379Shselasky } 2050213379Shselasky /* range check */ 2051213379Shselasky if (mult > 2) 2052213379Shselasky mult = 3; 2053213379Shselasky else 2054213379Shselasky mult++; 2055213379Shselasky 2056213379Shselasky x = XREAD4(temp.sc, runt, XHCI_MFINDEX); 2057213379Shselasky 2058213379Shselasky DPRINTF("MFINDEX=0x%08x\n", x); 2059213379Shselasky 2060213379Shselasky switch (usbd_get_speed(xfer->xroot->udev)) { 2061213379Shselasky case USB_SPEED_FULL: 2062213379Shselasky shift = 3; 2063213379Shselasky temp.isoc_delta = 8; /* 1ms */ 2064213379Shselasky x += temp.isoc_delta - 1; 2065213379Shselasky x &= ~(temp.isoc_delta - 1); 2066213379Shselasky break; 2067213379Shselasky default: 2068213379Shselasky shift = usbd_xfer_get_fps_shift(xfer); 2069213379Shselasky temp.isoc_delta = 1U << shift; 2070213379Shselasky x += temp.isoc_delta - 1; 2071213379Shselasky x &= ~(temp.isoc_delta - 1); 2072213379Shselasky /* simple frame load balancing */ 2073213379Shselasky x += xfer->endpoint->usb_uframe; 2074213379Shselasky break; 2075213379Shselasky } 2076213379Shselasky 2077213379Shselasky y = XHCI_MFINDEX_GET(x - xfer->endpoint->isoc_next); 2078213379Shselasky 2079213379Shselasky if ((xfer->endpoint->is_synced == 0) || 2080213379Shselasky (y < (xfer->nframes << shift)) || 2081213379Shselasky (XHCI_MFINDEX_GET(-y) >= (128 * 8))) { 2082213379Shselasky /* 2083213379Shselasky * If there is data underflow or the pipe 2084213379Shselasky * queue is empty we schedule the transfer a 2085213379Shselasky * few frames ahead of the current frame 2086213379Shselasky * position. Else two isochronous transfers 2087213379Shselasky * might overlap. 2088213379Shselasky */ 2089213379Shselasky xfer->endpoint->isoc_next = XHCI_MFINDEX_GET(x + (3 * 8)); 2090213379Shselasky xfer->endpoint->is_synced = 1; 2091234803Shselasky temp.do_isoc_sync = 1; 2092234803Shselasky 2093213379Shselasky DPRINTFN(3, "start next=%d\n", xfer->endpoint->isoc_next); 2094213379Shselasky } 2095213379Shselasky 2096213379Shselasky /* compute isochronous completion time */ 2097213379Shselasky 2098213379Shselasky y = XHCI_MFINDEX_GET(xfer->endpoint->isoc_next - (x & ~7)); 2099213379Shselasky 2100213379Shselasky xfer->isoc_time_complete = 2101213379Shselasky usb_isoc_time_expand(&temp.sc->sc_bus, x / 8) + 2102213379Shselasky (y / 8) + (((xfer->nframes << shift) + 7) / 8); 2103213379Shselasky 2104213379Shselasky x = 0; 2105213379Shselasky temp.isoc_frame = xfer->endpoint->isoc_next; 2106213379Shselasky temp.trb_type = XHCI_TRB_TYPE_ISOCH; 2107213379Shselasky 2108213379Shselasky xfer->endpoint->isoc_next += xfer->nframes << shift; 2109213379Shselasky 2110213379Shselasky } else if (xfer->flags_int.control_xfr) { 2111213379Shselasky 2112213379Shselasky /* check if we should prepend a setup message */ 2113213379Shselasky 2114213379Shselasky if (xfer->flags_int.control_hdr) { 2115213379Shselasky 2116213379Shselasky temp.len = xfer->frlengths[0]; 2117213379Shselasky temp.pc = xfer->frbuffers + 0; 2118213379Shselasky temp.shortpkt = temp.len ? 1 : 0; 2119213379Shselasky temp.trb_type = XHCI_TRB_TYPE_SETUP_STAGE; 2120213379Shselasky temp.direction = 0; 2121213379Shselasky 2122213379Shselasky /* check for last frame */ 2123213379Shselasky if (xfer->nframes == 1) { 2124213379Shselasky /* no STATUS stage yet, SETUP is last */ 2125213379Shselasky if (xfer->flags_int.control_act) 2126213379Shselasky temp.last_frame = 1; 2127213379Shselasky } 2128213379Shselasky 2129213379Shselasky xhci_setup_generic_chain_sub(&temp); 2130213379Shselasky } 2131213379Shselasky x = 1; 2132213379Shselasky mult = 1; 2133213379Shselasky temp.isoc_delta = 0; 2134213379Shselasky temp.isoc_frame = 0; 2135278507Shselasky temp.trb_type = xfer->flags_int.control_did_data ? 2136278507Shselasky XHCI_TRB_TYPE_NORMAL : XHCI_TRB_TYPE_DATA_STAGE; 2137213379Shselasky } else { 2138213379Shselasky x = 0; 2139213379Shselasky mult = 1; 2140213379Shselasky temp.isoc_delta = 0; 2141213379Shselasky temp.isoc_frame = 0; 2142213379Shselasky temp.trb_type = XHCI_TRB_TYPE_NORMAL; 2143213379Shselasky } 2144213379Shselasky 2145213379Shselasky if (x != xfer->nframes) { 2146278278Shselasky /* set up page_cache pointer */ 2147213379Shselasky temp.pc = xfer->frbuffers + x; 2148213379Shselasky /* set endpoint direction */ 2149213379Shselasky temp.direction = UE_GET_DIR(xfer->endpointno); 2150213379Shselasky } 2151213379Shselasky 2152213379Shselasky while (x != xfer->nframes) { 2153213379Shselasky 2154213379Shselasky /* DATA0 / DATA1 message */ 2155213379Shselasky 2156213379Shselasky temp.len = xfer->frlengths[x]; 2157213379Shselasky temp.step_td = ((xfer->endpointno & UE_DIR_IN) && 2158213379Shselasky x != 0 && temp.multishort == 0); 2159213379Shselasky 2160213379Shselasky x++; 2161213379Shselasky 2162213379Shselasky if (x == xfer->nframes) { 2163213379Shselasky if (xfer->flags_int.control_xfr) { 2164213379Shselasky /* no STATUS stage yet, DATA is last */ 2165213379Shselasky if (xfer->flags_int.control_act) 2166213379Shselasky temp.last_frame = 1; 2167213379Shselasky } else { 2168213379Shselasky temp.last_frame = 1; 2169213379Shselasky } 2170213379Shselasky } 2171213379Shselasky if (temp.len == 0) { 2172213379Shselasky 2173213379Shselasky /* make sure that we send an USB packet */ 2174213379Shselasky 2175213379Shselasky temp.shortpkt = 0; 2176213379Shselasky 2177213379Shselasky temp.tbc = 0; 2178213379Shselasky temp.tlbpc = mult - 1; 2179213379Shselasky 2180213379Shselasky } else if (xfer->flags_int.isochronous_xfr) { 2181213379Shselasky 2182213379Shselasky uint8_t tdpc; 2183213379Shselasky 2184234803Shselasky /* 2185234803Shselasky * Isochronous transfers don't have short 2186234803Shselasky * packet termination: 2187234803Shselasky */ 2188213379Shselasky 2189213379Shselasky temp.shortpkt = 1; 2190213379Shselasky 2191213379Shselasky /* isochronous transfers have a transfer limit */ 2192213379Shselasky 2193213379Shselasky if (temp.len > xfer->max_frame_size) 2194213379Shselasky temp.len = xfer->max_frame_size; 2195213379Shselasky 2196213379Shselasky /* compute TD packet count */ 2197213379Shselasky tdpc = (temp.len + xfer->max_packet_size - 1) / 2198213379Shselasky xfer->max_packet_size; 2199213379Shselasky 2200213379Shselasky temp.tbc = ((tdpc + mult - 1) / mult) - 1; 2201213379Shselasky temp.tlbpc = (tdpc % mult); 2202213379Shselasky 2203213379Shselasky if (temp.tlbpc == 0) 2204213379Shselasky temp.tlbpc = mult - 1; 2205213379Shselasky else 2206213379Shselasky temp.tlbpc--; 2207213379Shselasky } else { 2208213379Shselasky 2209213379Shselasky /* regular data transfer */ 2210213379Shselasky 2211213379Shselasky temp.shortpkt = xfer->flags.force_short_xfer ? 0 : 1; 2212213379Shselasky } 2213213379Shselasky 2214213379Shselasky xhci_setup_generic_chain_sub(&temp); 2215213379Shselasky 2216213379Shselasky if (xfer->flags_int.isochronous_xfr) { 2217213379Shselasky temp.offset += xfer->frlengths[x - 1]; 2218213379Shselasky temp.isoc_frame += temp.isoc_delta; 2219213379Shselasky } else { 2220213379Shselasky /* get next Page Cache pointer */ 2221213379Shselasky temp.pc = xfer->frbuffers + x; 2222213379Shselasky } 2223213379Shselasky } 2224213379Shselasky 2225213379Shselasky /* check if we should append a status stage */ 2226213379Shselasky 2227213379Shselasky if (xfer->flags_int.control_xfr && 2228213379Shselasky !xfer->flags_int.control_act) { 2229213379Shselasky 2230213379Shselasky /* 2231213379Shselasky * Send a DATA1 message and invert the current 2232213379Shselasky * endpoint direction. 2233213379Shselasky */ 2234213379Shselasky temp.step_td = (xfer->nframes != 0); 2235213379Shselasky temp.direction = UE_GET_DIR(xfer->endpointno) ^ UE_DIR_IN; 2236213379Shselasky temp.len = 0; 2237213379Shselasky temp.pc = NULL; 2238213379Shselasky temp.shortpkt = 0; 2239213379Shselasky temp.last_frame = 1; 2240213379Shselasky temp.trb_type = XHCI_TRB_TYPE_STATUS_STAGE; 2241213379Shselasky 2242213379Shselasky xhci_setup_generic_chain_sub(&temp); 2243213379Shselasky } 2244213379Shselasky 2245213379Shselasky td = temp.td; 2246213379Shselasky 2247213379Shselasky /* must have at least one frame! */ 2248213379Shselasky 2249213379Shselasky xfer->td_transfer_last = td; 2250213379Shselasky 2251213379Shselasky DPRINTF("first=%p last=%p\n", xfer->td_transfer_first, td); 2252213379Shselasky} 2253213379Shselasky 2254213379Shselaskystatic void 2255213379Shselaskyxhci_set_slot_pointer(struct xhci_softc *sc, uint8_t index, uint64_t dev_addr) 2256213379Shselasky{ 2257213379Shselasky struct usb_page_search buf_res; 2258213379Shselasky struct xhci_dev_ctx_addr *pdctxa; 2259213379Shselasky 2260213379Shselasky usbd_get_page(&sc->sc_hw.ctx_pc, 0, &buf_res); 2261213379Shselasky 2262213379Shselasky pdctxa = buf_res.buffer; 2263213379Shselasky 2264213379Shselasky DPRINTF("addr[%u]=0x%016llx\n", index, (long long)dev_addr); 2265213379Shselasky 2266213379Shselasky pdctxa->qwBaaDevCtxAddr[index] = htole64(dev_addr); 2267213379Shselasky 2268213379Shselasky usb_pc_cpu_flush(&sc->sc_hw.ctx_pc); 2269213379Shselasky} 2270213379Shselasky 2271213379Shselaskystatic usb_error_t 2272213379Shselaskyxhci_configure_mask(struct usb_device *udev, uint32_t mask, uint8_t drop) 2273213379Shselasky{ 2274213379Shselasky struct xhci_softc *sc = XHCI_BUS2SC(udev->bus); 2275213379Shselasky struct usb_page_search buf_inp; 2276213379Shselasky struct xhci_input_dev_ctx *pinp; 2277243780Shselasky uint32_t temp; 2278213379Shselasky uint8_t index; 2279243780Shselasky uint8_t x; 2280213379Shselasky 2281213379Shselasky index = udev->controller_slot_id; 2282213379Shselasky 2283213379Shselasky usbd_get_page(&sc->sc_hw.devs[index].input_pc, 0, &buf_inp); 2284213379Shselasky 2285213379Shselasky pinp = buf_inp.buffer; 2286213379Shselasky 2287213379Shselasky if (drop) { 2288213379Shselasky mask &= XHCI_INCTX_NON_CTRL_MASK; 2289217374Shselasky xhci_ctx_set_le32(sc, &pinp->ctx_input.dwInCtx0, mask); 2290217374Shselasky xhci_ctx_set_le32(sc, &pinp->ctx_input.dwInCtx1, 0); 2291213379Shselasky } else { 2292272097Shselasky /* 2293272097Shselasky * Some hardware requires that we drop the endpoint 2294272097Shselasky * context before adding it again: 2295272097Shselasky */ 2296272097Shselasky xhci_ctx_set_le32(sc, &pinp->ctx_input.dwInCtx0, 2297272097Shselasky mask & XHCI_INCTX_NON_CTRL_MASK); 2298272097Shselasky 2299272097Shselasky /* Add new endpoint context */ 2300217374Shselasky xhci_ctx_set_le32(sc, &pinp->ctx_input.dwInCtx1, mask); 2301243780Shselasky 2302243780Shselasky /* find most significant set bit */ 2303243780Shselasky for (x = 31; x != 1; x--) { 2304243780Shselasky if (mask & (1 << x)) 2305243780Shselasky break; 2306243780Shselasky } 2307243780Shselasky 2308243780Shselasky /* adjust */ 2309243780Shselasky x--; 2310243780Shselasky 2311272589Shselasky /* figure out the maximum number of contexts */ 2312272589Shselasky if (x > sc->sc_hw.devs[index].context_num) 2313243780Shselasky sc->sc_hw.devs[index].context_num = x; 2314272589Shselasky else 2315272589Shselasky x = sc->sc_hw.devs[index].context_num; 2316272589Shselasky 2317272589Shselasky /* update number of contexts */ 2318272589Shselasky temp = xhci_ctx_get_le32(sc, &pinp->ctx_slot.dwSctx0); 2319272589Shselasky temp &= ~XHCI_SCTX_0_CTX_NUM_SET(31); 2320272589Shselasky temp |= XHCI_SCTX_0_CTX_NUM_SET(x + 1); 2321272589Shselasky xhci_ctx_set_le32(sc, &pinp->ctx_slot.dwSctx0, temp); 2322213379Shselasky } 2323276965Shselasky usb_pc_cpu_flush(&sc->sc_hw.devs[index].input_pc); 2324213379Shselasky return (0); 2325213379Shselasky} 2326213379Shselasky 2327213379Shselaskystatic usb_error_t 2328213379Shselaskyxhci_configure_endpoint(struct usb_device *udev, 2329251247Shselasky struct usb_endpoint_descriptor *edesc, struct xhci_endpoint_ext *pepext, 2330251247Shselasky uint16_t interval, uint8_t max_packet_count, 2331251247Shselasky uint8_t mult, uint8_t fps_shift, uint16_t max_packet_size, 2332239214Shselasky uint16_t max_frame_size, uint8_t ep_mode) 2333213379Shselasky{ 2334213379Shselasky struct usb_page_search buf_inp; 2335213379Shselasky struct xhci_softc *sc = XHCI_BUS2SC(udev->bus); 2336213379Shselasky struct xhci_input_dev_ctx *pinp; 2337251247Shselasky uint64_t ring_addr = pepext->physaddr; 2338213379Shselasky uint32_t temp; 2339213379Shselasky uint8_t index; 2340213379Shselasky uint8_t epno; 2341213379Shselasky uint8_t type; 2342213379Shselasky 2343213379Shselasky index = udev->controller_slot_id; 2344213379Shselasky 2345213379Shselasky usbd_get_page(&sc->sc_hw.devs[index].input_pc, 0, &buf_inp); 2346213379Shselasky 2347213379Shselasky pinp = buf_inp.buffer; 2348213379Shselasky 2349213379Shselasky epno = edesc->bEndpointAddress; 2350213379Shselasky type = edesc->bmAttributes & UE_XFERTYPE; 2351213379Shselasky 2352213379Shselasky if (type == UE_CONTROL) 2353213379Shselasky epno |= UE_DIR_IN; 2354213379Shselasky 2355213379Shselasky epno = XHCI_EPNO2EPID(epno); 2356213379Shselasky 2357213379Shselasky if (epno == 0) 2358213379Shselasky return (USB_ERR_NO_PIPE); /* invalid */ 2359213379Shselasky 2360213379Shselasky if (max_packet_count == 0) 2361213379Shselasky return (USB_ERR_BAD_BUFSIZE); 2362213379Shselasky 2363213379Shselasky max_packet_count--; 2364213379Shselasky 2365213379Shselasky if (mult == 0) 2366213379Shselasky return (USB_ERR_BAD_BUFSIZE); 2367213379Shselasky 2368251247Shselasky /* store endpoint mode */ 2369251247Shselasky pepext->trb_ep_mode = ep_mode; 2370251247Shselasky usb_pc_cpu_flush(pepext->page_cache); 2371251247Shselasky 2372239214Shselasky if (ep_mode == USB_EP_MODE_STREAMS) { 2373239214Shselasky temp = XHCI_EPCTX_0_EPSTATE_SET(0) | 2374239214Shselasky XHCI_EPCTX_0_MAXP_STREAMS_SET(XHCI_MAX_STREAMS_LOG - 1) | 2375239214Shselasky XHCI_EPCTX_0_LSA_SET(1); 2376213379Shselasky 2377239214Shselasky ring_addr += sizeof(struct xhci_trb) * 2378239214Shselasky XHCI_MAX_TRANSFERS * XHCI_MAX_STREAMS; 2379239214Shselasky } else { 2380239214Shselasky temp = XHCI_EPCTX_0_EPSTATE_SET(0) | 2381239214Shselasky XHCI_EPCTX_0_MAXP_STREAMS_SET(0) | 2382239214Shselasky XHCI_EPCTX_0_LSA_SET(0); 2383239214Shselasky 2384239214Shselasky ring_addr |= XHCI_EPCTX_2_DCS_SET(1); 2385239214Shselasky } 2386239214Shselasky 2387213379Shselasky switch (udev->speed) { 2388213379Shselasky case USB_SPEED_FULL: 2389213379Shselasky case USB_SPEED_LOW: 2390213379Shselasky /* 1ms -> 125us */ 2391213379Shselasky fps_shift += 3; 2392213379Shselasky break; 2393213379Shselasky default: 2394213379Shselasky break; 2395213379Shselasky } 2396213379Shselasky 2397213379Shselasky switch (type) { 2398213379Shselasky case UE_INTERRUPT: 2399213379Shselasky if (fps_shift > 3) 2400213379Shselasky fps_shift--; 2401213379Shselasky temp |= XHCI_EPCTX_0_IVAL_SET(fps_shift); 2402213379Shselasky break; 2403213379Shselasky case UE_ISOCHRONOUS: 2404213379Shselasky temp |= XHCI_EPCTX_0_IVAL_SET(fps_shift); 2405213379Shselasky 2406213379Shselasky switch (udev->speed) { 2407213379Shselasky case USB_SPEED_SUPER: 2408213379Shselasky if (mult > 3) 2409213379Shselasky mult = 3; 2410213379Shselasky temp |= XHCI_EPCTX_0_MULT_SET(mult - 1); 2411213379Shselasky max_packet_count /= mult; 2412213379Shselasky break; 2413213379Shselasky default: 2414213379Shselasky break; 2415213379Shselasky } 2416213379Shselasky break; 2417213379Shselasky default: 2418213379Shselasky break; 2419213379Shselasky } 2420213379Shselasky 2421217374Shselasky xhci_ctx_set_le32(sc, &pinp->ctx_ep[epno - 1].dwEpCtx0, temp); 2422213379Shselasky 2423213379Shselasky temp = 2424213379Shselasky XHCI_EPCTX_1_HID_SET(0) | 2425213379Shselasky XHCI_EPCTX_1_MAXB_SET(max_packet_count) | 2426213379Shselasky XHCI_EPCTX_1_MAXP_SIZE_SET(max_packet_size); 2427213379Shselasky 2428276965Shselasky /* 2429276965Shselasky * Always enable the "three strikes and you are gone" feature 2430276965Shselasky * except for ISOCHRONOUS endpoints. This is suggested by 2431276965Shselasky * section 4.3.3 in the XHCI specification about device slot 2432276965Shselasky * initialisation. 2433276965Shselasky */ 2434276965Shselasky if (type != UE_ISOCHRONOUS) 2435276965Shselasky temp |= XHCI_EPCTX_1_CERR_SET(3); 2436213379Shselasky 2437213379Shselasky switch (type) { 2438213379Shselasky case UE_CONTROL: 2439213379Shselasky temp |= XHCI_EPCTX_1_EPTYPE_SET(4); 2440213379Shselasky break; 2441213379Shselasky case UE_ISOCHRONOUS: 2442213379Shselasky temp |= XHCI_EPCTX_1_EPTYPE_SET(1); 2443213379Shselasky break; 2444213379Shselasky case UE_BULK: 2445213379Shselasky temp |= XHCI_EPCTX_1_EPTYPE_SET(2); 2446213379Shselasky break; 2447213379Shselasky default: 2448213379Shselasky temp |= XHCI_EPCTX_1_EPTYPE_SET(3); 2449213379Shselasky break; 2450213379Shselasky } 2451213379Shselasky 2452213379Shselasky /* check for IN direction */ 2453213379Shselasky if (epno & 1) 2454213379Shselasky temp |= XHCI_EPCTX_1_EPTYPE_SET(4); 2455213379Shselasky 2456217374Shselasky xhci_ctx_set_le32(sc, &pinp->ctx_ep[epno - 1].dwEpCtx1, temp); 2457217374Shselasky xhci_ctx_set_le64(sc, &pinp->ctx_ep[epno - 1].qwEpCtx2, ring_addr); 2458213379Shselasky 2459213379Shselasky switch (edesc->bmAttributes & UE_XFERTYPE) { 2460213379Shselasky case UE_INTERRUPT: 2461213379Shselasky case UE_ISOCHRONOUS: 2462213379Shselasky temp = XHCI_EPCTX_4_MAX_ESIT_PAYLOAD_SET(max_frame_size) | 2463213379Shselasky XHCI_EPCTX_4_AVG_TRB_LEN_SET(MIN(XHCI_PAGE_SIZE, 2464213379Shselasky max_frame_size)); 2465213379Shselasky break; 2466213379Shselasky case UE_CONTROL: 2467213379Shselasky temp = XHCI_EPCTX_4_AVG_TRB_LEN_SET(8); 2468213379Shselasky break; 2469213379Shselasky default: 2470213379Shselasky temp = XHCI_EPCTX_4_AVG_TRB_LEN_SET(XHCI_PAGE_SIZE); 2471213379Shselasky break; 2472213379Shselasky } 2473213379Shselasky 2474217374Shselasky xhci_ctx_set_le32(sc, &pinp->ctx_ep[epno - 1].dwEpCtx4, temp); 2475213379Shselasky 2476213379Shselasky#ifdef USB_DEBUG 2477217374Shselasky xhci_dump_endpoint(sc, &pinp->ctx_ep[epno - 1]); 2478213379Shselasky#endif 2479213379Shselasky usb_pc_cpu_flush(&sc->sc_hw.devs[index].input_pc); 2480213379Shselasky 2481213379Shselasky return (0); /* success */ 2482213379Shselasky} 2483213379Shselasky 2484213379Shselaskystatic usb_error_t 2485213379Shselaskyxhci_configure_endpoint_by_xfer(struct usb_xfer *xfer) 2486213379Shselasky{ 2487213379Shselasky struct xhci_endpoint_ext *pepext; 2488213379Shselasky struct usb_endpoint_ss_comp_descriptor *ecomp; 2489239214Shselasky usb_stream_t x; 2490213379Shselasky 2491213379Shselasky pepext = xhci_get_endpoint_ext(xfer->xroot->udev, 2492213379Shselasky xfer->endpoint->edesc); 2493213379Shselasky 2494213379Shselasky ecomp = xfer->endpoint->ecomp; 2495213379Shselasky 2496239214Shselasky for (x = 0; x != XHCI_MAX_STREAMS; x++) { 2497239214Shselasky uint64_t temp; 2498239214Shselasky 2499239214Shselasky /* halt any transfers */ 2500239214Shselasky pepext->trb[x * XHCI_MAX_TRANSFERS].dwTrb3 = 0; 2501239214Shselasky 2502239214Shselasky /* compute start of TRB ring for stream "x" */ 2503239214Shselasky temp = pepext->physaddr + 2504239214Shselasky (x * XHCI_MAX_TRANSFERS * sizeof(struct xhci_trb)) + 2505239214Shselasky XHCI_SCTX_0_SCT_SEC_TR_RING; 2506239214Shselasky 2507239214Shselasky /* make tree structure */ 2508239214Shselasky pepext->trb[(XHCI_MAX_TRANSFERS * 2509239214Shselasky XHCI_MAX_STREAMS) + x].qwTrb0 = htole64(temp); 2510239214Shselasky 2511239214Shselasky /* reserved fields */ 2512239214Shselasky pepext->trb[(XHCI_MAX_TRANSFERS * 2513239214Shselasky XHCI_MAX_STREAMS) + x].dwTrb2 = 0; 2514239214Shselasky pepext->trb[(XHCI_MAX_TRANSFERS * 2515239214Shselasky XHCI_MAX_STREAMS) + x].dwTrb3 = 0; 2516239214Shselasky } 2517213379Shselasky usb_pc_cpu_flush(pepext->page_cache); 2518213379Shselasky 2519213379Shselasky return (xhci_configure_endpoint(xfer->xroot->udev, 2520251247Shselasky xfer->endpoint->edesc, pepext, 2521213379Shselasky xfer->interval, xfer->max_packet_count, 2522239214Shselasky (ecomp != NULL) ? UE_GET_SS_ISO_MULT(ecomp->bmAttributes) + 1 : 1, 2523213379Shselasky usbd_xfer_get_fps_shift(xfer), xfer->max_packet_size, 2524239214Shselasky xfer->max_frame_size, xfer->endpoint->ep_mode)); 2525213379Shselasky} 2526213379Shselasky 2527213379Shselaskystatic usb_error_t 2528213379Shselaskyxhci_configure_device(struct usb_device *udev) 2529213379Shselasky{ 2530213379Shselasky struct xhci_softc *sc = XHCI_BUS2SC(udev->bus); 2531213379Shselasky struct usb_page_search buf_inp; 2532213379Shselasky struct usb_page_cache *pcinp; 2533213379Shselasky struct xhci_input_dev_ctx *pinp; 2534213379Shselasky struct usb_device *hubdev; 2535213379Shselasky uint32_t temp; 2536213379Shselasky uint32_t route; 2537230032Shselasky uint32_t rh_port; 2538213379Shselasky uint8_t is_hub; 2539213379Shselasky uint8_t index; 2540230032Shselasky uint8_t depth; 2541213379Shselasky 2542213379Shselasky index = udev->controller_slot_id; 2543213379Shselasky 2544213379Shselasky DPRINTF("index=%u\n", index); 2545213379Shselasky 2546213379Shselasky pcinp = &sc->sc_hw.devs[index].input_pc; 2547213379Shselasky 2548213379Shselasky usbd_get_page(pcinp, 0, &buf_inp); 2549213379Shselasky 2550213379Shselasky pinp = buf_inp.buffer; 2551213379Shselasky 2552213379Shselasky rh_port = 0; 2553213379Shselasky route = 0; 2554213379Shselasky 2555213379Shselasky /* figure out route string and root HUB port number */ 2556213379Shselasky 2557213379Shselasky for (hubdev = udev; hubdev != NULL; hubdev = hubdev->parent_hub) { 2558213379Shselasky 2559213379Shselasky if (hubdev->parent_hub == NULL) 2560213379Shselasky break; 2561213379Shselasky 2562230032Shselasky depth = hubdev->parent_hub->depth; 2563230032Shselasky 2564213379Shselasky /* 2565213379Shselasky * NOTE: HS/FS/LS devices and the SS root HUB can have 2566213379Shselasky * more than 15 ports 2567213379Shselasky */ 2568213379Shselasky 2569213379Shselasky rh_port = hubdev->port_no; 2570213379Shselasky 2571230032Shselasky if (depth == 0) 2572213379Shselasky break; 2573213379Shselasky 2574230032Shselasky if (rh_port > 15) 2575230032Shselasky rh_port = 15; 2576213379Shselasky 2577230032Shselasky if (depth < 6) 2578230032Shselasky route |= rh_port << (4 * (depth - 1)); 2579213379Shselasky } 2580213379Shselasky 2581230032Shselasky DPRINTF("Route=0x%08x\n", route); 2582230032Shselasky 2583243780Shselasky temp = XHCI_SCTX_0_ROUTE_SET(route) | 2584243780Shselasky XHCI_SCTX_0_CTX_NUM_SET( 2585243780Shselasky sc->sc_hw.devs[index].context_num + 1); 2586213379Shselasky 2587213379Shselasky switch (udev->speed) { 2588213379Shselasky case USB_SPEED_LOW: 2589213379Shselasky temp |= XHCI_SCTX_0_SPEED_SET(2); 2590234803Shselasky if (udev->parent_hs_hub != NULL && 2591234803Shselasky udev->parent_hs_hub->ddesc.bDeviceProtocol == 2592234803Shselasky UDPROTO_HSHUBMTT) { 2593234803Shselasky DPRINTF("Device inherits MTT\n"); 2594234803Shselasky temp |= XHCI_SCTX_0_MTT_SET(1); 2595234803Shselasky } 2596213379Shselasky break; 2597213379Shselasky case USB_SPEED_HIGH: 2598213379Shselasky temp |= XHCI_SCTX_0_SPEED_SET(3); 2599234803Shselasky if (sc->sc_hw.devs[index].nports != 0 && 2600234803Shselasky udev->ddesc.bDeviceProtocol == UDPROTO_HSHUBMTT) { 2601234803Shselasky DPRINTF("HUB supports MTT\n"); 2602234803Shselasky temp |= XHCI_SCTX_0_MTT_SET(1); 2603234803Shselasky } 2604213379Shselasky break; 2605213379Shselasky case USB_SPEED_FULL: 2606213379Shselasky temp |= XHCI_SCTX_0_SPEED_SET(1); 2607234803Shselasky if (udev->parent_hs_hub != NULL && 2608234803Shselasky udev->parent_hs_hub->ddesc.bDeviceProtocol == 2609234803Shselasky UDPROTO_HSHUBMTT) { 2610234803Shselasky DPRINTF("Device inherits MTT\n"); 2611234803Shselasky temp |= XHCI_SCTX_0_MTT_SET(1); 2612234803Shselasky } 2613213379Shselasky break; 2614213379Shselasky default: 2615213379Shselasky temp |= XHCI_SCTX_0_SPEED_SET(4); 2616213379Shselasky break; 2617213379Shselasky } 2618213379Shselasky 2619213379Shselasky is_hub = sc->sc_hw.devs[index].nports != 0 && 2620213379Shselasky (udev->speed == USB_SPEED_SUPER || 2621213379Shselasky udev->speed == USB_SPEED_HIGH); 2622213379Shselasky 2623234803Shselasky if (is_hub) 2624213379Shselasky temp |= XHCI_SCTX_0_HUB_SET(1); 2625213379Shselasky 2626217374Shselasky xhci_ctx_set_le32(sc, &pinp->ctx_slot.dwSctx0, temp); 2627213379Shselasky 2628213379Shselasky temp = XHCI_SCTX_1_RH_PORT_SET(rh_port); 2629213379Shselasky 2630213379Shselasky if (is_hub) { 2631213379Shselasky temp |= XHCI_SCTX_1_NUM_PORTS_SET( 2632213379Shselasky sc->sc_hw.devs[index].nports); 2633213379Shselasky } 2634213379Shselasky 2635213379Shselasky switch (udev->speed) { 2636213379Shselasky case USB_SPEED_SUPER: 2637213379Shselasky switch (sc->sc_hw.devs[index].state) { 2638213379Shselasky case XHCI_ST_ADDRESSED: 2639213379Shselasky case XHCI_ST_CONFIGURED: 2640213379Shselasky /* enable power save */ 2641213379Shselasky temp |= XHCI_SCTX_1_MAX_EL_SET(sc->sc_exit_lat_max); 2642213379Shselasky break; 2643213379Shselasky default: 2644213379Shselasky /* disable power save */ 2645213379Shselasky break; 2646213379Shselasky } 2647213379Shselasky break; 2648213379Shselasky default: 2649213379Shselasky break; 2650213379Shselasky } 2651213379Shselasky 2652217374Shselasky xhci_ctx_set_le32(sc, &pinp->ctx_slot.dwSctx1, temp); 2653213379Shselasky 2654213379Shselasky temp = XHCI_SCTX_2_IRQ_TARGET_SET(0); 2655213379Shselasky 2656234803Shselasky if (is_hub) { 2657234803Shselasky temp |= XHCI_SCTX_2_TT_THINK_TIME_SET( 2658234803Shselasky sc->sc_hw.devs[index].tt); 2659234803Shselasky } 2660213379Shselasky 2661213379Shselasky hubdev = udev->parent_hs_hub; 2662213379Shselasky 2663213379Shselasky /* check if we should activate the transaction translator */ 2664213379Shselasky switch (udev->speed) { 2665213379Shselasky case USB_SPEED_FULL: 2666213379Shselasky case USB_SPEED_LOW: 2667213379Shselasky if (hubdev != NULL) { 2668213379Shselasky temp |= XHCI_SCTX_2_TT_HUB_SID_SET( 2669213379Shselasky hubdev->controller_slot_id); 2670213379Shselasky temp |= XHCI_SCTX_2_TT_PORT_NUM_SET( 2671213379Shselasky udev->hs_port_no); 2672213379Shselasky } 2673213379Shselasky break; 2674213379Shselasky default: 2675213379Shselasky break; 2676213379Shselasky } 2677213379Shselasky 2678217374Shselasky xhci_ctx_set_le32(sc, &pinp->ctx_slot.dwSctx2, temp); 2679213379Shselasky 2680261111Shselasky /* 2681261111Shselasky * These fields should be initialized to zero, according to 2682261111Shselasky * XHCI section 6.2.2 - slot context: 2683261111Shselasky */ 2684261111Shselasky temp = XHCI_SCTX_3_DEV_ADDR_SET(0) | 2685213379Shselasky XHCI_SCTX_3_SLOT_STATE_SET(0); 2686213379Shselasky 2687217374Shselasky xhci_ctx_set_le32(sc, &pinp->ctx_slot.dwSctx3, temp); 2688213379Shselasky 2689213379Shselasky#ifdef USB_DEBUG 2690217374Shselasky xhci_dump_device(sc, &pinp->ctx_slot); 2691213379Shselasky#endif 2692213379Shselasky usb_pc_cpu_flush(pcinp); 2693213379Shselasky 2694213379Shselasky return (0); /* success */ 2695213379Shselasky} 2696213379Shselasky 2697213379Shselaskystatic usb_error_t 2698213379Shselaskyxhci_alloc_device_ext(struct usb_device *udev) 2699213379Shselasky{ 2700213379Shselasky struct xhci_softc *sc = XHCI_BUS2SC(udev->bus); 2701213379Shselasky struct usb_page_search buf_dev; 2702213379Shselasky struct usb_page_search buf_ep; 2703213379Shselasky struct xhci_trb *trb; 2704213379Shselasky struct usb_page_cache *pc; 2705213379Shselasky struct usb_page *pg; 2706213379Shselasky uint64_t addr; 2707213379Shselasky uint8_t index; 2708213379Shselasky uint8_t i; 2709213379Shselasky 2710213379Shselasky index = udev->controller_slot_id; 2711213379Shselasky 2712213379Shselasky pc = &sc->sc_hw.devs[index].device_pc; 2713213379Shselasky pg = &sc->sc_hw.devs[index].device_pg; 2714213379Shselasky 2715213379Shselasky /* need to initialize the page cache */ 2716213379Shselasky pc->tag_parent = sc->sc_bus.dma_parent_tag; 2717213379Shselasky 2718217374Shselasky if (usb_pc_alloc_mem(pc, pg, sc->sc_ctx_is_64_byte ? 2719217374Shselasky (2 * sizeof(struct xhci_dev_ctx)) : 2720217374Shselasky sizeof(struct xhci_dev_ctx), XHCI_PAGE_SIZE)) 2721213379Shselasky goto error; 2722213379Shselasky 2723213379Shselasky usbd_get_page(pc, 0, &buf_dev); 2724213379Shselasky 2725213379Shselasky pc = &sc->sc_hw.devs[index].input_pc; 2726213379Shselasky pg = &sc->sc_hw.devs[index].input_pg; 2727213379Shselasky 2728213379Shselasky /* need to initialize the page cache */ 2729213379Shselasky pc->tag_parent = sc->sc_bus.dma_parent_tag; 2730213379Shselasky 2731217374Shselasky if (usb_pc_alloc_mem(pc, pg, sc->sc_ctx_is_64_byte ? 2732217374Shselasky (2 * sizeof(struct xhci_input_dev_ctx)) : 2733243780Shselasky sizeof(struct xhci_input_dev_ctx), XHCI_PAGE_SIZE)) { 2734213379Shselasky goto error; 2735243780Shselasky } 2736213379Shselasky 2737278278Shselasky /* initialize all endpoint LINK TRBs */ 2738213379Shselasky 2739269447Shselasky for (i = 0; i != XHCI_MAX_ENDPOINTS; i++) { 2740213379Shselasky 2741269447Shselasky pc = &sc->sc_hw.devs[index].endpoint_pc[i]; 2742269447Shselasky pg = &sc->sc_hw.devs[index].endpoint_pg[i]; 2743213379Shselasky 2744269447Shselasky /* need to initialize the page cache */ 2745269447Shselasky pc->tag_parent = sc->sc_bus.dma_parent_tag; 2746213379Shselasky 2747269447Shselasky if (usb_pc_alloc_mem(pc, pg, 2748269447Shselasky sizeof(struct xhci_dev_endpoint_trbs), XHCI_TRB_ALIGN)) { 2749269447Shselasky goto error; 2750269447Shselasky } 2751213379Shselasky 2752213379Shselasky /* lookup endpoint TRB ring */ 2753269447Shselasky usbd_get_page(pc, 0, &buf_ep); 2754213379Shselasky 2755213379Shselasky /* get TRB pointer */ 2756213379Shselasky trb = buf_ep.buffer; 2757213379Shselasky trb += XHCI_MAX_TRANSFERS - 1; 2758213379Shselasky 2759213379Shselasky /* get TRB start address */ 2760213379Shselasky addr = buf_ep.physaddr; 2761213379Shselasky 2762213379Shselasky /* create LINK TRB */ 2763213379Shselasky trb->qwTrb0 = htole64(addr); 2764213379Shselasky trb->dwTrb2 = htole32(XHCI_TRB_2_IRQ_SET(0)); 2765213379Shselasky trb->dwTrb3 = htole32(XHCI_TRB_3_CYCLE_BIT | 2766213379Shselasky XHCI_TRB_3_TYPE_SET(XHCI_TRB_TYPE_LINK)); 2767269447Shselasky 2768269447Shselasky usb_pc_cpu_flush(pc); 2769213379Shselasky } 2770213379Shselasky 2771213379Shselasky xhci_set_slot_pointer(sc, index, buf_dev.physaddr); 2772213379Shselasky 2773213379Shselasky return (0); 2774213379Shselasky 2775213379Shselaskyerror: 2776213379Shselasky xhci_free_device_ext(udev); 2777213379Shselasky 2778213379Shselasky return (USB_ERR_NOMEM); 2779213379Shselasky} 2780213379Shselasky 2781213379Shselaskystatic void 2782213379Shselaskyxhci_free_device_ext(struct usb_device *udev) 2783213379Shselasky{ 2784213379Shselasky struct xhci_softc *sc = XHCI_BUS2SC(udev->bus); 2785213379Shselasky uint8_t index; 2786269447Shselasky uint8_t i; 2787213379Shselasky 2788213379Shselasky index = udev->controller_slot_id; 2789213379Shselasky xhci_set_slot_pointer(sc, index, 0); 2790213379Shselasky 2791213379Shselasky usb_pc_free_mem(&sc->sc_hw.devs[index].device_pc); 2792213379Shselasky usb_pc_free_mem(&sc->sc_hw.devs[index].input_pc); 2793269447Shselasky for (i = 0; i != XHCI_MAX_ENDPOINTS; i++) 2794269447Shselasky usb_pc_free_mem(&sc->sc_hw.devs[index].endpoint_pc[i]); 2795213379Shselasky} 2796213379Shselasky 2797213379Shselaskystatic struct xhci_endpoint_ext * 2798213379Shselaskyxhci_get_endpoint_ext(struct usb_device *udev, struct usb_endpoint_descriptor *edesc) 2799213379Shselasky{ 2800213379Shselasky struct xhci_softc *sc = XHCI_BUS2SC(udev->bus); 2801213379Shselasky struct xhci_endpoint_ext *pepext; 2802213379Shselasky struct usb_page_cache *pc; 2803213379Shselasky struct usb_page_search buf_ep; 2804213379Shselasky uint8_t epno; 2805213379Shselasky uint8_t index; 2806213379Shselasky 2807213379Shselasky epno = edesc->bEndpointAddress; 2808213379Shselasky if ((edesc->bmAttributes & UE_XFERTYPE) == UE_CONTROL) 2809213379Shselasky epno |= UE_DIR_IN; 2810213379Shselasky 2811213379Shselasky epno = XHCI_EPNO2EPID(epno); 2812213379Shselasky 2813213379Shselasky index = udev->controller_slot_id; 2814213379Shselasky 2815269447Shselasky pc = &sc->sc_hw.devs[index].endpoint_pc[epno]; 2816213379Shselasky 2817269447Shselasky usbd_get_page(pc, 0, &buf_ep); 2818213379Shselasky 2819213379Shselasky pepext = &sc->sc_hw.devs[index].endp[epno]; 2820213379Shselasky pepext->page_cache = pc; 2821213379Shselasky pepext->trb = buf_ep.buffer; 2822213379Shselasky pepext->physaddr = buf_ep.physaddr; 2823213379Shselasky 2824213379Shselasky return (pepext); 2825213379Shselasky} 2826213379Shselasky 2827213379Shselaskystatic void 2828213379Shselaskyxhci_endpoint_doorbell(struct usb_xfer *xfer) 2829213379Shselasky{ 2830213379Shselasky struct xhci_softc *sc = XHCI_BUS2SC(xfer->xroot->bus); 2831213379Shselasky uint8_t epno; 2832213379Shselasky uint8_t index; 2833213379Shselasky 2834213379Shselasky epno = xfer->endpointno; 2835213379Shselasky if (xfer->flags_int.control_xfr) 2836213379Shselasky epno |= UE_DIR_IN; 2837213379Shselasky 2838213379Shselasky epno = XHCI_EPNO2EPID(epno); 2839213379Shselasky index = xfer->xroot->udev->controller_slot_id; 2840213379Shselasky 2841243780Shselasky if (xfer->xroot->udev->flags.self_suspended == 0) { 2842243780Shselasky XWRITE4(sc, door, XHCI_DOORBELL(index), 2843243780Shselasky epno | XHCI_DB_SID_SET(xfer->stream_id)); 2844243780Shselasky } 2845213379Shselasky} 2846213379Shselasky 2847213379Shselaskystatic void 2848213379Shselaskyxhci_transfer_remove(struct usb_xfer *xfer, usb_error_t error) 2849213379Shselasky{ 2850213379Shselasky struct xhci_endpoint_ext *pepext; 2851213379Shselasky 2852213379Shselasky if (xfer->flags_int.bandwidth_reclaimed) { 2853213379Shselasky xfer->flags_int.bandwidth_reclaimed = 0; 2854213379Shselasky 2855213379Shselasky pepext = xhci_get_endpoint_ext(xfer->xroot->udev, 2856213379Shselasky xfer->endpoint->edesc); 2857213379Shselasky 2858239214Shselasky pepext->trb_used[xfer->stream_id]--; 2859213379Shselasky 2860213379Shselasky pepext->xfer[xfer->qh_pos] = NULL; 2861213379Shselasky 2862213379Shselasky if (error && pepext->trb_running != 0) { 2863213379Shselasky pepext->trb_halted = 1; 2864213379Shselasky pepext->trb_running = 0; 2865213379Shselasky } 2866213379Shselasky } 2867213379Shselasky} 2868213379Shselasky 2869213379Shselaskystatic usb_error_t 2870213379Shselaskyxhci_transfer_insert(struct usb_xfer *xfer) 2871213379Shselasky{ 2872213379Shselasky struct xhci_td *td_first; 2873213379Shselasky struct xhci_td *td_last; 2874251251Shselasky struct xhci_trb *trb_link; 2875213379Shselasky struct xhci_endpoint_ext *pepext; 2876213379Shselasky uint64_t addr; 2877239214Shselasky usb_stream_t id; 2878213379Shselasky uint8_t i; 2879213379Shselasky uint8_t inext; 2880213379Shselasky uint8_t trb_limit; 2881213379Shselasky 2882213379Shselasky DPRINTFN(8, "\n"); 2883213379Shselasky 2884239214Shselasky id = xfer->stream_id; 2885239214Shselasky 2886213379Shselasky /* check if already inserted */ 2887213379Shselasky if (xfer->flags_int.bandwidth_reclaimed) { 2888213379Shselasky DPRINTFN(8, "Already in schedule\n"); 2889213379Shselasky return (0); 2890213379Shselasky } 2891213379Shselasky 2892213379Shselasky pepext = xhci_get_endpoint_ext(xfer->xroot->udev, 2893213379Shselasky xfer->endpoint->edesc); 2894213379Shselasky 2895213379Shselasky td_first = xfer->td_transfer_first; 2896213379Shselasky td_last = xfer->td_transfer_last; 2897213379Shselasky addr = pepext->physaddr; 2898213379Shselasky 2899213379Shselasky switch (xfer->endpoint->edesc->bmAttributes & UE_XFERTYPE) { 2900213379Shselasky case UE_CONTROL: 2901213379Shselasky case UE_INTERRUPT: 2902213379Shselasky /* single buffered */ 2903213379Shselasky trb_limit = 1; 2904213379Shselasky break; 2905213379Shselasky default: 2906213379Shselasky /* multi buffered */ 2907213379Shselasky trb_limit = (XHCI_MAX_TRANSFERS - 2); 2908213379Shselasky break; 2909213379Shselasky } 2910213379Shselasky 2911239214Shselasky if (pepext->trb_used[id] >= trb_limit) { 2912213379Shselasky DPRINTFN(8, "Too many TDs queued.\n"); 2913213379Shselasky return (USB_ERR_NOMEM); 2914213379Shselasky } 2915213379Shselasky 2916213379Shselasky /* check for stopped condition, after putting transfer on interrupt queue */ 2917213379Shselasky if (pepext->trb_running == 0) { 2918213379Shselasky struct xhci_softc *sc = XHCI_BUS2SC(xfer->xroot->bus); 2919213379Shselasky 2920213379Shselasky DPRINTFN(8, "Not running\n"); 2921213379Shselasky 2922213379Shselasky /* start configuration */ 2923246363Shselasky (void)usb_proc_msignal(USB_BUS_CONTROL_XFER_PROC(&sc->sc_bus), 2924213379Shselasky &sc->sc_config_msg[0], &sc->sc_config_msg[1]); 2925213379Shselasky return (0); 2926213379Shselasky } 2927213379Shselasky 2928239214Shselasky pepext->trb_used[id]++; 2929213379Shselasky 2930213379Shselasky /* get current TRB index */ 2931239214Shselasky i = pepext->trb_index[id]; 2932213379Shselasky 2933213379Shselasky /* get next TRB index */ 2934213379Shselasky inext = (i + 1); 2935213379Shselasky 2936213379Shselasky /* the last entry of the ring is a hardcoded link TRB */ 2937213379Shselasky if (inext >= (XHCI_MAX_TRANSFERS - 1)) 2938213379Shselasky inext = 0; 2939213379Shselasky 2940251247Shselasky /* store next TRB index, before stream ID offset is added */ 2941251247Shselasky pepext->trb_index[id] = inext; 2942251247Shselasky 2943239214Shselasky /* offset for stream */ 2944239214Shselasky i += id * XHCI_MAX_TRANSFERS; 2945239214Shselasky inext += id * XHCI_MAX_TRANSFERS; 2946239214Shselasky 2947213379Shselasky /* compute terminating return address */ 2948239214Shselasky addr += (inext * sizeof(struct xhci_trb)); 2949213379Shselasky 2950251251Shselasky /* compute link TRB pointer */ 2951251251Shselasky trb_link = td_last->td_trb + td_last->ntrb; 2952251251Shselasky 2953213379Shselasky /* update next pointer of last link TRB */ 2954251251Shselasky trb_link->qwTrb0 = htole64(addr); 2955251251Shselasky trb_link->dwTrb2 = htole32(XHCI_TRB_2_IRQ_SET(0)); 2956251251Shselasky trb_link->dwTrb3 = htole32(XHCI_TRB_3_IOC_BIT | 2957251251Shselasky XHCI_TRB_3_CYCLE_BIT | 2958251251Shselasky XHCI_TRB_3_TYPE_SET(XHCI_TRB_TYPE_LINK)); 2959213379Shselasky 2960213379Shselasky#ifdef USB_DEBUG 2961213379Shselasky xhci_dump_trb(&td_last->td_trb[td_last->ntrb]); 2962213379Shselasky#endif 2963213379Shselasky usb_pc_cpu_flush(td_last->page_cache); 2964213379Shselasky 2965213379Shselasky /* write ahead chain end marker */ 2966213379Shselasky 2967213379Shselasky pepext->trb[inext].qwTrb0 = 0; 2968213379Shselasky pepext->trb[inext].dwTrb2 = 0; 2969213379Shselasky pepext->trb[inext].dwTrb3 = 0; 2970213379Shselasky 2971213379Shselasky /* update next pointer of link TRB */ 2972213379Shselasky 2973213379Shselasky pepext->trb[i].qwTrb0 = htole64((uint64_t)td_first->td_self); 2974213379Shselasky pepext->trb[i].dwTrb2 = htole32(XHCI_TRB_2_IRQ_SET(0)); 2975213379Shselasky 2976213379Shselasky#ifdef USB_DEBUG 2977213379Shselasky xhci_dump_trb(&pepext->trb[i]); 2978213379Shselasky#endif 2979213379Shselasky usb_pc_cpu_flush(pepext->page_cache); 2980213379Shselasky 2981213379Shselasky /* toggle cycle bit which activates the transfer chain */ 2982213379Shselasky 2983213379Shselasky pepext->trb[i].dwTrb3 = htole32(XHCI_TRB_3_CYCLE_BIT | 2984213379Shselasky XHCI_TRB_3_TYPE_SET(XHCI_TRB_TYPE_LINK)); 2985213379Shselasky 2986213379Shselasky usb_pc_cpu_flush(pepext->page_cache); 2987213379Shselasky 2988213379Shselasky DPRINTF("qh_pos = %u\n", i); 2989213379Shselasky 2990213379Shselasky pepext->xfer[i] = xfer; 2991213379Shselasky 2992213379Shselasky xfer->qh_pos = i; 2993213379Shselasky 2994213379Shselasky xfer->flags_int.bandwidth_reclaimed = 1; 2995213379Shselasky 2996213379Shselasky xhci_endpoint_doorbell(xfer); 2997213379Shselasky 2998213379Shselasky return (0); 2999213379Shselasky} 3000213379Shselasky 3001213379Shselaskystatic void 3002213379Shselaskyxhci_root_intr(struct xhci_softc *sc) 3003213379Shselasky{ 3004213379Shselasky uint16_t i; 3005213379Shselasky 3006213379Shselasky USB_BUS_LOCK_ASSERT(&sc->sc_bus, MA_OWNED); 3007213379Shselasky 3008213379Shselasky /* clear any old interrupt data */ 3009213379Shselasky memset(sc->sc_hub_idata, 0, sizeof(sc->sc_hub_idata)); 3010213379Shselasky 3011213379Shselasky for (i = 1; i <= sc->sc_noport; i++) { 3012213379Shselasky /* pick out CHANGE bits from the status register */ 3013213379Shselasky if (XREAD4(sc, oper, XHCI_PORTSC(i)) & ( 3014213379Shselasky XHCI_PS_CSC | XHCI_PS_PEC | 3015213379Shselasky XHCI_PS_OCC | XHCI_PS_WRC | 3016213379Shselasky XHCI_PS_PRC | XHCI_PS_PLC | 3017213379Shselasky XHCI_PS_CEC)) { 3018213379Shselasky sc->sc_hub_idata[i / 8] |= 1 << (i % 8); 3019213379Shselasky DPRINTF("port %d changed\n", i); 3020213379Shselasky } 3021213379Shselasky } 3022213379Shselasky uhub_root_intr(&sc->sc_bus, sc->sc_hub_idata, 3023213379Shselasky sizeof(sc->sc_hub_idata)); 3024213379Shselasky} 3025213379Shselasky 3026213379Shselasky/*------------------------------------------------------------------------* 3027213379Shselasky * xhci_device_done - XHCI done handler 3028213379Shselasky * 3029213379Shselasky * NOTE: This function can be called two times in a row on 3030213379Shselasky * the same USB transfer. From close and from interrupt. 3031213379Shselasky *------------------------------------------------------------------------*/ 3032213379Shselaskystatic void 3033213379Shselaskyxhci_device_done(struct usb_xfer *xfer, usb_error_t error) 3034213379Shselasky{ 3035213379Shselasky DPRINTFN(2, "xfer=%p, endpoint=%p, error=%d\n", 3036213379Shselasky xfer, xfer->endpoint, error); 3037213379Shselasky 3038213379Shselasky /* remove transfer from HW queue */ 3039213379Shselasky xhci_transfer_remove(xfer, error); 3040213379Shselasky 3041213379Shselasky /* dequeue transfer and start next transfer */ 3042213379Shselasky usbd_transfer_done(xfer, error); 3043213379Shselasky} 3044213379Shselasky 3045213379Shselasky/*------------------------------------------------------------------------* 3046213379Shselasky * XHCI data transfer support (generic type) 3047213379Shselasky *------------------------------------------------------------------------*/ 3048213379Shselaskystatic void 3049213379Shselaskyxhci_device_generic_open(struct usb_xfer *xfer) 3050213379Shselasky{ 3051213379Shselasky if (xfer->flags_int.isochronous_xfr) { 3052213379Shselasky switch (xfer->xroot->udev->speed) { 3053213379Shselasky case USB_SPEED_FULL: 3054213379Shselasky break; 3055213379Shselasky default: 3056213379Shselasky usb_hs_bandwidth_alloc(xfer); 3057213379Shselasky break; 3058213379Shselasky } 3059213379Shselasky } 3060213379Shselasky} 3061213379Shselasky 3062213379Shselaskystatic void 3063213379Shselaskyxhci_device_generic_close(struct usb_xfer *xfer) 3064213379Shselasky{ 3065213379Shselasky DPRINTF("\n"); 3066213379Shselasky 3067213379Shselasky xhci_device_done(xfer, USB_ERR_CANCELLED); 3068213379Shselasky 3069213379Shselasky if (xfer->flags_int.isochronous_xfr) { 3070213379Shselasky switch (xfer->xroot->udev->speed) { 3071213379Shselasky case USB_SPEED_FULL: 3072213379Shselasky break; 3073213379Shselasky default: 3074213379Shselasky usb_hs_bandwidth_free(xfer); 3075213379Shselasky break; 3076213379Shselasky } 3077213379Shselasky } 3078213379Shselasky} 3079213379Shselasky 3080213379Shselaskystatic void 3081213379Shselaskyxhci_device_generic_multi_enter(struct usb_endpoint *ep, 3082239214Shselasky usb_stream_t stream_id, struct usb_xfer *enter_xfer) 3083213379Shselasky{ 3084213379Shselasky struct usb_xfer *xfer; 3085213379Shselasky 3086213379Shselasky /* check if there is a current transfer */ 3087239214Shselasky xfer = ep->endpoint_q[stream_id].curr; 3088213379Shselasky if (xfer == NULL) 3089213379Shselasky return; 3090213379Shselasky 3091213379Shselasky /* 3092213379Shselasky * Check if the current transfer is started and then pickup 3093213379Shselasky * the next one, if any. Else wait for next start event due to 3094213379Shselasky * block on failure feature. 3095213379Shselasky */ 3096213379Shselasky if (!xfer->flags_int.bandwidth_reclaimed) 3097213379Shselasky return; 3098213379Shselasky 3099239214Shselasky xfer = TAILQ_FIRST(&ep->endpoint_q[stream_id].head); 3100213379Shselasky if (xfer == NULL) { 3101213379Shselasky /* 3102213379Shselasky * In case of enter we have to consider that the 3103213379Shselasky * transfer is queued by the USB core after the enter 3104213379Shselasky * method is called. 3105213379Shselasky */ 3106213379Shselasky xfer = enter_xfer; 3107213379Shselasky 3108213379Shselasky if (xfer == NULL) 3109213379Shselasky return; 3110213379Shselasky } 3111213379Shselasky 3112213379Shselasky /* try to multi buffer */ 3113213379Shselasky xhci_transfer_insert(xfer); 3114213379Shselasky} 3115213379Shselasky 3116213379Shselaskystatic void 3117213379Shselaskyxhci_device_generic_enter(struct usb_xfer *xfer) 3118213379Shselasky{ 3119213379Shselasky DPRINTF("\n"); 3120213379Shselasky 3121278278Shselasky /* set up TD's and QH */ 3122213379Shselasky xhci_setup_generic_chain(xfer); 3123213379Shselasky 3124239214Shselasky xhci_device_generic_multi_enter(xfer->endpoint, 3125239214Shselasky xfer->stream_id, xfer); 3126213379Shselasky} 3127213379Shselasky 3128213379Shselaskystatic void 3129213379Shselaskyxhci_device_generic_start(struct usb_xfer *xfer) 3130213379Shselasky{ 3131213379Shselasky DPRINTF("\n"); 3132213379Shselasky 3133213379Shselasky /* try to insert xfer on HW queue */ 3134213379Shselasky xhci_transfer_insert(xfer); 3135213379Shselasky 3136213379Shselasky /* try to multi buffer */ 3137239214Shselasky xhci_device_generic_multi_enter(xfer->endpoint, 3138239214Shselasky xfer->stream_id, NULL); 3139213379Shselasky 3140213379Shselasky /* add transfer last on interrupt queue */ 3141213379Shselasky usbd_transfer_enqueue(&xfer->xroot->bus->intr_q, xfer); 3142213379Shselasky 3143213379Shselasky /* start timeout, if any */ 3144213379Shselasky if (xfer->timeout != 0) 3145213379Shselasky usbd_transfer_timeout_ms(xfer, &xhci_timeout, xfer->timeout); 3146213379Shselasky} 3147213379Shselasky 3148213379Shselaskystruct usb_pipe_methods xhci_device_generic_methods = 3149213379Shselasky{ 3150213379Shselasky .open = xhci_device_generic_open, 3151213379Shselasky .close = xhci_device_generic_close, 3152213379Shselasky .enter = xhci_device_generic_enter, 3153213379Shselasky .start = xhci_device_generic_start, 3154213379Shselasky}; 3155213379Shselasky 3156213379Shselasky/*------------------------------------------------------------------------* 3157213379Shselasky * xhci root HUB support 3158213379Shselasky *------------------------------------------------------------------------* 3159213379Shselasky * Simulate a hardware HUB by handling all the necessary requests. 3160213379Shselasky *------------------------------------------------------------------------*/ 3161213379Shselasky 3162233774Shselasky#define HSETW(ptr, val) ptr = { (uint8_t)(val), (uint8_t)((val) >> 8) } 3163213379Shselasky 3164213379Shselaskystatic const 3165213379Shselaskystruct usb_device_descriptor xhci_devd = 3166213379Shselasky{ 3167213379Shselasky .bLength = sizeof(xhci_devd), 3168213379Shselasky .bDescriptorType = UDESC_DEVICE, /* type */ 3169213379Shselasky HSETW(.bcdUSB, 0x0300), /* USB version */ 3170213379Shselasky .bDeviceClass = UDCLASS_HUB, /* class */ 3171213379Shselasky .bDeviceSubClass = UDSUBCLASS_HUB, /* subclass */ 3172213379Shselasky .bDeviceProtocol = UDPROTO_SSHUB, /* protocol */ 3173213379Shselasky .bMaxPacketSize = 9, /* max packet size */ 3174213379Shselasky HSETW(.idVendor, 0x0000), /* vendor */ 3175213379Shselasky HSETW(.idProduct, 0x0000), /* product */ 3176213379Shselasky HSETW(.bcdDevice, 0x0100), /* device version */ 3177213379Shselasky .iManufacturer = 1, 3178213379Shselasky .iProduct = 2, 3179213379Shselasky .iSerialNumber = 0, 3180213379Shselasky .bNumConfigurations = 1, /* # of configurations */ 3181213379Shselasky}; 3182213379Shselasky 3183213379Shselaskystatic const 3184213379Shselaskystruct xhci_bos_desc xhci_bosd = { 3185213379Shselasky .bosd = { 3186213379Shselasky .bLength = sizeof(xhci_bosd.bosd), 3187213379Shselasky .bDescriptorType = UDESC_BOS, 3188213379Shselasky HSETW(.wTotalLength, sizeof(xhci_bosd)), 3189213379Shselasky .bNumDeviceCaps = 3, 3190213379Shselasky }, 3191213379Shselasky .usb2extd = { 3192213379Shselasky .bLength = sizeof(xhci_bosd.usb2extd), 3193213379Shselasky .bDescriptorType = 1, 3194213379Shselasky .bDevCapabilityType = 2, 3195227401Shselasky .bmAttributes[0] = 2, 3196213379Shselasky }, 3197213379Shselasky .usbdcd = { 3198213379Shselasky .bLength = sizeof(xhci_bosd.usbdcd), 3199213379Shselasky .bDescriptorType = UDESC_DEVICE_CAPABILITY, 3200213379Shselasky .bDevCapabilityType = 3, 3201213379Shselasky .bmAttributes = 0, /* XXX */ 3202213379Shselasky HSETW(.wSpeedsSupported, 0x000C), 3203213379Shselasky .bFunctionalitySupport = 8, 3204213379Shselasky .bU1DevExitLat = 255, /* dummy - not used */ 3205233774Shselasky .wU2DevExitLat = { 0x00, 0x08 }, 3206213379Shselasky }, 3207213379Shselasky .cidd = { 3208213379Shselasky .bLength = sizeof(xhci_bosd.cidd), 3209213379Shselasky .bDescriptorType = 1, 3210213379Shselasky .bDevCapabilityType = 4, 3211213379Shselasky .bReserved = 0, 3212213379Shselasky .bContainerID = 0, /* XXX */ 3213213379Shselasky }, 3214213379Shselasky}; 3215213379Shselasky 3216213379Shselaskystatic const 3217213379Shselaskystruct xhci_config_desc xhci_confd = { 3218213379Shselasky .confd = { 3219213379Shselasky .bLength = sizeof(xhci_confd.confd), 3220213379Shselasky .bDescriptorType = UDESC_CONFIG, 3221213379Shselasky .wTotalLength[0] = sizeof(xhci_confd), 3222213379Shselasky .bNumInterface = 1, 3223213379Shselasky .bConfigurationValue = 1, 3224213379Shselasky .iConfiguration = 0, 3225213379Shselasky .bmAttributes = UC_SELF_POWERED, 3226213379Shselasky .bMaxPower = 0 /* max power */ 3227213379Shselasky }, 3228213379Shselasky .ifcd = { 3229213379Shselasky .bLength = sizeof(xhci_confd.ifcd), 3230213379Shselasky .bDescriptorType = UDESC_INTERFACE, 3231213379Shselasky .bNumEndpoints = 1, 3232213379Shselasky .bInterfaceClass = UICLASS_HUB, 3233213379Shselasky .bInterfaceSubClass = UISUBCLASS_HUB, 3234213379Shselasky .bInterfaceProtocol = 0, 3235213379Shselasky }, 3236213379Shselasky .endpd = { 3237213379Shselasky .bLength = sizeof(xhci_confd.endpd), 3238213379Shselasky .bDescriptorType = UDESC_ENDPOINT, 3239213379Shselasky .bEndpointAddress = UE_DIR_IN | XHCI_INTR_ENDPT, 3240213379Shselasky .bmAttributes = UE_INTERRUPT, 3241213379Shselasky .wMaxPacketSize[0] = 2, /* max 15 ports */ 3242213379Shselasky .bInterval = 255, 3243213379Shselasky }, 3244213379Shselasky .endpcd = { 3245213379Shselasky .bLength = sizeof(xhci_confd.endpcd), 3246213379Shselasky .bDescriptorType = UDESC_ENDPOINT_SS_COMP, 3247213379Shselasky .bMaxBurst = 0, 3248213379Shselasky .bmAttributes = 0, 3249213379Shselasky }, 3250213379Shselasky}; 3251213379Shselasky 3252213379Shselaskystatic const 3253213379Shselaskystruct usb_hub_ss_descriptor xhci_hubd = { 3254213379Shselasky .bLength = sizeof(xhci_hubd), 3255213379Shselasky .bDescriptorType = UDESC_SS_HUB, 3256213379Shselasky}; 3257213379Shselasky 3258213379Shselaskystatic usb_error_t 3259213379Shselaskyxhci_roothub_exec(struct usb_device *udev, 3260213379Shselasky struct usb_device_request *req, const void **pptr, uint16_t *plength) 3261213379Shselasky{ 3262213379Shselasky struct xhci_softc *sc = XHCI_BUS2SC(udev->bus); 3263213379Shselasky const char *str_ptr; 3264213379Shselasky const void *ptr; 3265213379Shselasky uint32_t port; 3266213379Shselasky uint32_t v; 3267213379Shselasky uint16_t len; 3268213379Shselasky uint16_t i; 3269213379Shselasky uint16_t value; 3270213379Shselasky uint16_t index; 3271213379Shselasky uint8_t j; 3272213379Shselasky usb_error_t err; 3273213379Shselasky 3274213379Shselasky USB_BUS_LOCK_ASSERT(&sc->sc_bus, MA_OWNED); 3275213379Shselasky 3276213379Shselasky /* buffer reset */ 3277213379Shselasky ptr = (const void *)&sc->sc_hub_desc; 3278213379Shselasky len = 0; 3279213379Shselasky err = 0; 3280213379Shselasky 3281213379Shselasky value = UGETW(req->wValue); 3282213379Shselasky index = UGETW(req->wIndex); 3283213379Shselasky 3284213379Shselasky DPRINTFN(3, "type=0x%02x request=0x%02x wLen=0x%04x " 3285213379Shselasky "wValue=0x%04x wIndex=0x%04x\n", 3286213379Shselasky req->bmRequestType, req->bRequest, 3287213379Shselasky UGETW(req->wLength), value, index); 3288213379Shselasky 3289213379Shselasky#define C(x,y) ((x) | ((y) << 8)) 3290213379Shselasky switch (C(req->bRequest, req->bmRequestType)) { 3291213379Shselasky case C(UR_CLEAR_FEATURE, UT_WRITE_DEVICE): 3292213379Shselasky case C(UR_CLEAR_FEATURE, UT_WRITE_INTERFACE): 3293213379Shselasky case C(UR_CLEAR_FEATURE, UT_WRITE_ENDPOINT): 3294213379Shselasky /* 3295213379Shselasky * DEVICE_REMOTE_WAKEUP and ENDPOINT_HALT are no-ops 3296213379Shselasky * for the integrated root hub. 3297213379Shselasky */ 3298213379Shselasky break; 3299213379Shselasky case C(UR_GET_CONFIG, UT_READ_DEVICE): 3300213379Shselasky len = 1; 3301213379Shselasky sc->sc_hub_desc.temp[0] = sc->sc_conf; 3302213379Shselasky break; 3303213379Shselasky case C(UR_GET_DESCRIPTOR, UT_READ_DEVICE): 3304213379Shselasky switch (value >> 8) { 3305213379Shselasky case UDESC_DEVICE: 3306213379Shselasky if ((value & 0xff) != 0) { 3307213379Shselasky err = USB_ERR_IOERROR; 3308213379Shselasky goto done; 3309213379Shselasky } 3310213379Shselasky len = sizeof(xhci_devd); 3311213379Shselasky ptr = (const void *)&xhci_devd; 3312213379Shselasky break; 3313213379Shselasky 3314213379Shselasky case UDESC_BOS: 3315213379Shselasky if ((value & 0xff) != 0) { 3316213379Shselasky err = USB_ERR_IOERROR; 3317213379Shselasky goto done; 3318213379Shselasky } 3319213379Shselasky len = sizeof(xhci_bosd); 3320213379Shselasky ptr = (const void *)&xhci_bosd; 3321213379Shselasky break; 3322213379Shselasky 3323213379Shselasky case UDESC_CONFIG: 3324213379Shselasky if ((value & 0xff) != 0) { 3325213379Shselasky err = USB_ERR_IOERROR; 3326213379Shselasky goto done; 3327213379Shselasky } 3328213379Shselasky len = sizeof(xhci_confd); 3329213379Shselasky ptr = (const void *)&xhci_confd; 3330213379Shselasky break; 3331213379Shselasky 3332213379Shselasky case UDESC_STRING: 3333213379Shselasky switch (value & 0xff) { 3334213379Shselasky case 0: /* Language table */ 3335213379Shselasky str_ptr = "\001"; 3336213379Shselasky break; 3337213379Shselasky 3338213379Shselasky case 1: /* Vendor */ 3339213379Shselasky str_ptr = sc->sc_vendor; 3340213379Shselasky break; 3341213379Shselasky 3342213379Shselasky case 2: /* Product */ 3343213379Shselasky str_ptr = "XHCI root HUB"; 3344213379Shselasky break; 3345213379Shselasky 3346213379Shselasky default: 3347213379Shselasky str_ptr = ""; 3348213379Shselasky break; 3349213379Shselasky } 3350213379Shselasky 3351213379Shselasky len = usb_make_str_desc( 3352213379Shselasky sc->sc_hub_desc.temp, 3353213379Shselasky sizeof(sc->sc_hub_desc.temp), 3354213379Shselasky str_ptr); 3355213379Shselasky break; 3356213379Shselasky 3357213379Shselasky default: 3358213379Shselasky err = USB_ERR_IOERROR; 3359213379Shselasky goto done; 3360213379Shselasky } 3361213379Shselasky break; 3362213379Shselasky case C(UR_GET_INTERFACE, UT_READ_INTERFACE): 3363213379Shselasky len = 1; 3364213379Shselasky sc->sc_hub_desc.temp[0] = 0; 3365213379Shselasky break; 3366213379Shselasky case C(UR_GET_STATUS, UT_READ_DEVICE): 3367213379Shselasky len = 2; 3368213379Shselasky USETW(sc->sc_hub_desc.stat.wStatus, UDS_SELF_POWERED); 3369213379Shselasky break; 3370213379Shselasky case C(UR_GET_STATUS, UT_READ_INTERFACE): 3371213379Shselasky case C(UR_GET_STATUS, UT_READ_ENDPOINT): 3372213379Shselasky len = 2; 3373213379Shselasky USETW(sc->sc_hub_desc.stat.wStatus, 0); 3374213379Shselasky break; 3375213379Shselasky case C(UR_SET_ADDRESS, UT_WRITE_DEVICE): 3376213379Shselasky if (value >= XHCI_MAX_DEVICES) { 3377213379Shselasky err = USB_ERR_IOERROR; 3378213379Shselasky goto done; 3379213379Shselasky } 3380213379Shselasky break; 3381213379Shselasky case C(UR_SET_CONFIG, UT_WRITE_DEVICE): 3382213379Shselasky if (value != 0 && value != 1) { 3383213379Shselasky err = USB_ERR_IOERROR; 3384213379Shselasky goto done; 3385213379Shselasky } 3386213379Shselasky sc->sc_conf = value; 3387213379Shselasky break; 3388213379Shselasky case C(UR_SET_DESCRIPTOR, UT_WRITE_DEVICE): 3389213379Shselasky break; 3390213379Shselasky case C(UR_SET_FEATURE, UT_WRITE_DEVICE): 3391213379Shselasky case C(UR_SET_FEATURE, UT_WRITE_INTERFACE): 3392213379Shselasky case C(UR_SET_FEATURE, UT_WRITE_ENDPOINT): 3393213379Shselasky err = USB_ERR_IOERROR; 3394213379Shselasky goto done; 3395213379Shselasky case C(UR_SET_INTERFACE, UT_WRITE_INTERFACE): 3396213379Shselasky break; 3397213379Shselasky case C(UR_SYNCH_FRAME, UT_WRITE_ENDPOINT): 3398213379Shselasky break; 3399213379Shselasky /* Hub requests */ 3400213379Shselasky case C(UR_CLEAR_FEATURE, UT_WRITE_CLASS_DEVICE): 3401213379Shselasky break; 3402213379Shselasky case C(UR_CLEAR_FEATURE, UT_WRITE_CLASS_OTHER): 3403213379Shselasky DPRINTFN(9, "UR_CLEAR_PORT_FEATURE\n"); 3404213379Shselasky 3405213379Shselasky if ((index < 1) || 3406213379Shselasky (index > sc->sc_noport)) { 3407213379Shselasky err = USB_ERR_IOERROR; 3408213379Shselasky goto done; 3409213379Shselasky } 3410213379Shselasky port = XHCI_PORTSC(index); 3411213379Shselasky 3412226803Shselasky v = XREAD4(sc, oper, port); 3413226803Shselasky i = XHCI_PS_PLS_GET(v); 3414226803Shselasky v &= ~XHCI_PS_CLEAR; 3415213379Shselasky 3416213379Shselasky switch (value) { 3417213379Shselasky case UHF_C_BH_PORT_RESET: 3418213379Shselasky XWRITE4(sc, oper, port, v | XHCI_PS_WRC); 3419213379Shselasky break; 3420213379Shselasky case UHF_C_PORT_CONFIG_ERROR: 3421213379Shselasky XWRITE4(sc, oper, port, v | XHCI_PS_CEC); 3422213379Shselasky break; 3423230032Shselasky case UHF_C_PORT_SUSPEND: 3424213379Shselasky case UHF_C_PORT_LINK_STATE: 3425213379Shselasky XWRITE4(sc, oper, port, v | XHCI_PS_PLC); 3426213379Shselasky break; 3427213379Shselasky case UHF_C_PORT_CONNECTION: 3428213379Shselasky XWRITE4(sc, oper, port, v | XHCI_PS_CSC); 3429213379Shselasky break; 3430213379Shselasky case UHF_C_PORT_ENABLE: 3431213379Shselasky XWRITE4(sc, oper, port, v | XHCI_PS_PEC); 3432213379Shselasky break; 3433213379Shselasky case UHF_C_PORT_OVER_CURRENT: 3434213379Shselasky XWRITE4(sc, oper, port, v | XHCI_PS_OCC); 3435213379Shselasky break; 3436213379Shselasky case UHF_C_PORT_RESET: 3437213379Shselasky XWRITE4(sc, oper, port, v | XHCI_PS_PRC); 3438213379Shselasky break; 3439213379Shselasky case UHF_PORT_ENABLE: 3440213379Shselasky XWRITE4(sc, oper, port, v | XHCI_PS_PED); 3441213379Shselasky break; 3442213379Shselasky case UHF_PORT_POWER: 3443213379Shselasky XWRITE4(sc, oper, port, v & ~XHCI_PS_PP); 3444213379Shselasky break; 3445213379Shselasky case UHF_PORT_INDICATOR: 3446213379Shselasky XWRITE4(sc, oper, port, v & ~XHCI_PS_PIC_SET(3)); 3447213379Shselasky break; 3448213379Shselasky case UHF_PORT_SUSPEND: 3449226803Shselasky 3450226803Shselasky /* U3 -> U15 */ 3451226803Shselasky if (i == 3) { 3452226803Shselasky XWRITE4(sc, oper, port, v | 3453226803Shselasky XHCI_PS_PLS_SET(0xF) | XHCI_PS_LWS); 3454226803Shselasky } 3455226803Shselasky 3456226803Shselasky /* wait 20ms for resume sequence to complete */ 3457226803Shselasky usb_pause_mtx(&sc->sc_bus.bus_mtx, hz / 50); 3458226803Shselasky 3459226803Shselasky /* U0 */ 3460213379Shselasky XWRITE4(sc, oper, port, v | 3461213379Shselasky XHCI_PS_PLS_SET(0) | XHCI_PS_LWS); 3462213379Shselasky break; 3463213379Shselasky default: 3464213379Shselasky err = USB_ERR_IOERROR; 3465213379Shselasky goto done; 3466213379Shselasky } 3467213379Shselasky break; 3468213379Shselasky 3469213379Shselasky case C(UR_GET_DESCRIPTOR, UT_READ_CLASS_DEVICE): 3470213379Shselasky if ((value & 0xff) != 0) { 3471213379Shselasky err = USB_ERR_IOERROR; 3472213379Shselasky goto done; 3473213379Shselasky } 3474213379Shselasky 3475213379Shselasky v = XREAD4(sc, capa, XHCI_HCSPARAMS0); 3476213379Shselasky 3477213379Shselasky sc->sc_hub_desc.hubd = xhci_hubd; 3478213379Shselasky 3479213379Shselasky sc->sc_hub_desc.hubd.bNbrPorts = sc->sc_noport; 3480213379Shselasky 3481213379Shselasky if (XHCI_HCS0_PPC(v)) 3482213379Shselasky i = UHD_PWR_INDIVIDUAL; 3483213379Shselasky else 3484213379Shselasky i = UHD_PWR_GANGED; 3485213379Shselasky 3486213379Shselasky if (XHCI_HCS0_PIND(v)) 3487213379Shselasky i |= UHD_PORT_IND; 3488213379Shselasky 3489213379Shselasky i |= UHD_OC_INDIVIDUAL; 3490213379Shselasky 3491213379Shselasky USETW(sc->sc_hub_desc.hubd.wHubCharacteristics, i); 3492213379Shselasky 3493213379Shselasky /* see XHCI section 5.4.9: */ 3494213379Shselasky sc->sc_hub_desc.hubd.bPwrOn2PwrGood = 10; 3495213379Shselasky 3496213379Shselasky for (j = 1; j <= sc->sc_noport; j++) { 3497213379Shselasky 3498213379Shselasky v = XREAD4(sc, oper, XHCI_PORTSC(j)); 3499213379Shselasky if (v & XHCI_PS_DR) { 3500213379Shselasky sc->sc_hub_desc.hubd. 3501213379Shselasky DeviceRemovable[j / 8] |= 1U << (j % 8); 3502213379Shselasky } 3503213379Shselasky } 3504213379Shselasky len = sc->sc_hub_desc.hubd.bLength; 3505213379Shselasky break; 3506213379Shselasky 3507213379Shselasky case C(UR_GET_STATUS, UT_READ_CLASS_DEVICE): 3508213379Shselasky len = 16; 3509213379Shselasky memset(sc->sc_hub_desc.temp, 0, 16); 3510213379Shselasky break; 3511213379Shselasky 3512213379Shselasky case C(UR_GET_STATUS, UT_READ_CLASS_OTHER): 3513213379Shselasky DPRINTFN(9, "UR_GET_STATUS i=%d\n", index); 3514213379Shselasky 3515213379Shselasky if ((index < 1) || 3516213379Shselasky (index > sc->sc_noport)) { 3517213379Shselasky err = USB_ERR_IOERROR; 3518213379Shselasky goto done; 3519213379Shselasky } 3520213379Shselasky 3521213379Shselasky v = XREAD4(sc, oper, XHCI_PORTSC(index)); 3522213379Shselasky 3523213379Shselasky DPRINTFN(9, "port status=0x%08x\n", v); 3524213379Shselasky 3525213379Shselasky i = UPS_PORT_LINK_STATE_SET(XHCI_PS_PLS_GET(v)); 3526213379Shselasky 3527213379Shselasky switch (XHCI_PS_SPEED_GET(v)) { 3528213379Shselasky case 3: 3529213379Shselasky i |= UPS_HIGH_SPEED; 3530213379Shselasky break; 3531213379Shselasky case 2: 3532213379Shselasky i |= UPS_LOW_SPEED; 3533213379Shselasky break; 3534213379Shselasky case 1: 3535213379Shselasky /* FULL speed */ 3536213379Shselasky break; 3537213379Shselasky default: 3538213379Shselasky i |= UPS_OTHER_SPEED; 3539213379Shselasky break; 3540213379Shselasky } 3541213379Shselasky 3542213379Shselasky if (v & XHCI_PS_CCS) 3543213379Shselasky i |= UPS_CURRENT_CONNECT_STATUS; 3544213379Shselasky if (v & XHCI_PS_PED) 3545213379Shselasky i |= UPS_PORT_ENABLED; 3546213379Shselasky if (v & XHCI_PS_OCA) 3547213379Shselasky i |= UPS_OVERCURRENT_INDICATOR; 3548213379Shselasky if (v & XHCI_PS_PR) 3549213379Shselasky i |= UPS_RESET; 3550230050Shselasky if (v & XHCI_PS_PP) { 3551230050Shselasky /* 3552230050Shselasky * The USB 3.0 RH is using the 3553230050Shselasky * USB 2.0's power bit 3554230050Shselasky */ 3555230050Shselasky i |= UPS_PORT_POWER; 3556230050Shselasky } 3557213379Shselasky USETW(sc->sc_hub_desc.ps.wPortStatus, i); 3558213379Shselasky 3559213379Shselasky i = 0; 3560213379Shselasky if (v & XHCI_PS_CSC) 3561213379Shselasky i |= UPS_C_CONNECT_STATUS; 3562213379Shselasky if (v & XHCI_PS_PEC) 3563213379Shselasky i |= UPS_C_PORT_ENABLED; 3564213379Shselasky if (v & XHCI_PS_OCC) 3565213379Shselasky i |= UPS_C_OVERCURRENT_INDICATOR; 3566213379Shselasky if (v & XHCI_PS_WRC) 3567213379Shselasky i |= UPS_C_BH_PORT_RESET; 3568213379Shselasky if (v & XHCI_PS_PRC) 3569213379Shselasky i |= UPS_C_PORT_RESET; 3570213379Shselasky if (v & XHCI_PS_PLC) 3571213379Shselasky i |= UPS_C_PORT_LINK_STATE; 3572213379Shselasky if (v & XHCI_PS_CEC) 3573213379Shselasky i |= UPS_C_PORT_CONFIG_ERROR; 3574213379Shselasky 3575213379Shselasky USETW(sc->sc_hub_desc.ps.wPortChange, i); 3576213379Shselasky len = sizeof(sc->sc_hub_desc.ps); 3577213379Shselasky break; 3578213379Shselasky 3579213379Shselasky case C(UR_SET_DESCRIPTOR, UT_WRITE_CLASS_DEVICE): 3580213379Shselasky err = USB_ERR_IOERROR; 3581213379Shselasky goto done; 3582213379Shselasky 3583213379Shselasky case C(UR_SET_FEATURE, UT_WRITE_CLASS_DEVICE): 3584213379Shselasky break; 3585213379Shselasky 3586213379Shselasky case C(UR_SET_FEATURE, UT_WRITE_CLASS_OTHER): 3587213379Shselasky 3588213379Shselasky i = index >> 8; 3589213379Shselasky index &= 0x00FF; 3590213379Shselasky 3591213379Shselasky if ((index < 1) || 3592213379Shselasky (index > sc->sc_noport)) { 3593213379Shselasky err = USB_ERR_IOERROR; 3594213379Shselasky goto done; 3595213379Shselasky } 3596213379Shselasky 3597213379Shselasky port = XHCI_PORTSC(index); 3598213379Shselasky v = XREAD4(sc, oper, port) & ~XHCI_PS_CLEAR; 3599213379Shselasky 3600213379Shselasky switch (value) { 3601213379Shselasky case UHF_PORT_U1_TIMEOUT: 3602213379Shselasky if (XHCI_PS_SPEED_GET(v) != 4) { 3603213379Shselasky err = USB_ERR_IOERROR; 3604213379Shselasky goto done; 3605213379Shselasky } 3606213379Shselasky port = XHCI_PORTPMSC(index); 3607213379Shselasky v = XREAD4(sc, oper, port); 3608213379Shselasky v &= ~XHCI_PM3_U1TO_SET(0xFF); 3609213379Shselasky v |= XHCI_PM3_U1TO_SET(i); 3610213379Shselasky XWRITE4(sc, oper, port, v); 3611213379Shselasky break; 3612213379Shselasky case UHF_PORT_U2_TIMEOUT: 3613213379Shselasky if (XHCI_PS_SPEED_GET(v) != 4) { 3614213379Shselasky err = USB_ERR_IOERROR; 3615213379Shselasky goto done; 3616213379Shselasky } 3617213379Shselasky port = XHCI_PORTPMSC(index); 3618213379Shselasky v = XREAD4(sc, oper, port); 3619213379Shselasky v &= ~XHCI_PM3_U2TO_SET(0xFF); 3620213379Shselasky v |= XHCI_PM3_U2TO_SET(i); 3621213379Shselasky XWRITE4(sc, oper, port, v); 3622213379Shselasky break; 3623213379Shselasky case UHF_BH_PORT_RESET: 3624213379Shselasky XWRITE4(sc, oper, port, v | XHCI_PS_WPR); 3625213379Shselasky break; 3626213379Shselasky case UHF_PORT_LINK_STATE: 3627213379Shselasky XWRITE4(sc, oper, port, v | 3628213379Shselasky XHCI_PS_PLS_SET(i) | XHCI_PS_LWS); 3629213379Shselasky /* 4ms settle time */ 3630213379Shselasky usb_pause_mtx(&sc->sc_bus.bus_mtx, hz / 250); 3631213379Shselasky break; 3632213379Shselasky case UHF_PORT_ENABLE: 3633213379Shselasky DPRINTFN(3, "set port enable %d\n", index); 3634213379Shselasky break; 3635213379Shselasky case UHF_PORT_SUSPEND: 3636213379Shselasky DPRINTFN(6, "suspend port %u (LPM=%u)\n", index, i); 3637213379Shselasky j = XHCI_PS_SPEED_GET(v); 3638213379Shselasky if ((j < 1) || (j > 3)) { 3639213379Shselasky /* non-supported speed */ 3640213379Shselasky err = USB_ERR_IOERROR; 3641213379Shselasky goto done; 3642213379Shselasky } 3643213379Shselasky XWRITE4(sc, oper, port, v | 3644213379Shselasky XHCI_PS_PLS_SET(i ? 2 /* LPM */ : 3) | XHCI_PS_LWS); 3645213379Shselasky break; 3646213379Shselasky case UHF_PORT_RESET: 3647213379Shselasky DPRINTFN(6, "reset port %d\n", index); 3648213379Shselasky XWRITE4(sc, oper, port, v | XHCI_PS_PR); 3649213379Shselasky break; 3650213379Shselasky case UHF_PORT_POWER: 3651213379Shselasky DPRINTFN(3, "set port power %d\n", index); 3652213379Shselasky XWRITE4(sc, oper, port, v | XHCI_PS_PP); 3653213379Shselasky break; 3654213379Shselasky case UHF_PORT_TEST: 3655213379Shselasky DPRINTFN(3, "set port test %d\n", index); 3656213379Shselasky break; 3657213379Shselasky case UHF_PORT_INDICATOR: 3658213379Shselasky DPRINTFN(3, "set port indicator %d\n", index); 3659213379Shselasky 3660213379Shselasky v &= ~XHCI_PS_PIC_SET(3); 3661213379Shselasky v |= XHCI_PS_PIC_SET(1); 3662213379Shselasky 3663213379Shselasky XWRITE4(sc, oper, port, v); 3664213379Shselasky break; 3665213379Shselasky default: 3666213379Shselasky err = USB_ERR_IOERROR; 3667213379Shselasky goto done; 3668213379Shselasky } 3669213379Shselasky break; 3670213379Shselasky 3671213379Shselasky case C(UR_CLEAR_TT_BUFFER, UT_WRITE_CLASS_OTHER): 3672213379Shselasky case C(UR_RESET_TT, UT_WRITE_CLASS_OTHER): 3673213379Shselasky case C(UR_GET_TT_STATE, UT_READ_CLASS_OTHER): 3674213379Shselasky case C(UR_STOP_TT, UT_WRITE_CLASS_OTHER): 3675213379Shselasky break; 3676213379Shselasky default: 3677213379Shselasky err = USB_ERR_IOERROR; 3678213379Shselasky goto done; 3679213379Shselasky } 3680213379Shselaskydone: 3681213379Shselasky *plength = len; 3682213379Shselasky *pptr = ptr; 3683213379Shselasky return (err); 3684213379Shselasky} 3685213379Shselasky 3686213379Shselaskystatic void 3687213379Shselaskyxhci_xfer_setup(struct usb_setup_params *parm) 3688213379Shselasky{ 3689213379Shselasky struct usb_page_search page_info; 3690213379Shselasky struct usb_page_cache *pc; 3691213379Shselasky struct xhci_softc *sc; 3692213379Shselasky struct usb_xfer *xfer; 3693213379Shselasky void *last_obj; 3694213379Shselasky uint32_t ntd; 3695213379Shselasky uint32_t n; 3696213379Shselasky 3697213379Shselasky sc = XHCI_BUS2SC(parm->udev->bus); 3698213379Shselasky xfer = parm->curr_xfer; 3699213379Shselasky 3700213379Shselasky /* 3701213379Shselasky * The proof for the "ntd" formula is illustrated like this: 3702213379Shselasky * 3703213379Shselasky * +------------------------------------+ 3704213379Shselasky * | | 3705213379Shselasky * | |remainder -> | 3706213379Shselasky * | +-----+---+ | 3707213379Shselasky * | | xxx | x | frm 0 | 3708213379Shselasky * | +-----+---++ | 3709213379Shselasky * | | xxx | xx | frm 1 | 3710213379Shselasky * | +-----+----+ | 3711213379Shselasky * | ... | 3712213379Shselasky * +------------------------------------+ 3713213379Shselasky * 3714213379Shselasky * "xxx" means a completely full USB transfer descriptor 3715213379Shselasky * 3716213379Shselasky * "x" and "xx" means a short USB packet 3717213379Shselasky * 3718213379Shselasky * For the remainder of an USB transfer modulo 3719213379Shselasky * "max_data_length" we need two USB transfer descriptors. 3720213379Shselasky * One to transfer the remaining data and one to finalise with 3721213379Shselasky * a zero length packet in case the "force_short_xfer" flag is 3722213379Shselasky * set. We only need two USB transfer descriptors in the case 3723213379Shselasky * where the transfer length of the first one is a factor of 3724213379Shselasky * "max_frame_size". The rest of the needed USB transfer 3725213379Shselasky * descriptors is given by the buffer size divided by the 3726213379Shselasky * maximum data payload. 3727213379Shselasky */ 3728213379Shselasky parm->hc_max_packet_size = 0x400; 3729213379Shselasky parm->hc_max_packet_count = 16 * 3; 3730213379Shselasky parm->hc_max_frame_size = XHCI_TD_PAYLOAD_MAX; 3731213379Shselasky 3732213379Shselasky xfer->flags_int.bdma_enable = 1; 3733213379Shselasky 3734213379Shselasky usbd_transfer_setup_sub(parm); 3735213379Shselasky 3736213379Shselasky if (xfer->flags_int.isochronous_xfr) { 3737213379Shselasky ntd = ((1 * xfer->nframes) 3738213379Shselasky + (xfer->max_data_length / xfer->max_hc_frame_size)); 3739213379Shselasky } else if (xfer->flags_int.control_xfr) { 3740213379Shselasky ntd = ((2 * xfer->nframes) + 1 /* STATUS */ 3741213379Shselasky + (xfer->max_data_length / xfer->max_hc_frame_size)); 3742213379Shselasky } else { 3743213379Shselasky ntd = ((2 * xfer->nframes) 3744213379Shselasky + (xfer->max_data_length / xfer->max_hc_frame_size)); 3745213379Shselasky } 3746213379Shselasky 3747213379Shselaskyalloc_dma_set: 3748213379Shselasky 3749213379Shselasky if (parm->err) 3750213379Shselasky return; 3751213379Shselasky 3752213379Shselasky /* 3753213379Shselasky * Allocate queue heads and transfer descriptors 3754213379Shselasky */ 3755213379Shselasky last_obj = NULL; 3756213379Shselasky 3757213379Shselasky if (usbd_transfer_setup_sub_malloc( 3758213379Shselasky parm, &pc, sizeof(struct xhci_td), 3759213379Shselasky XHCI_TD_ALIGN, ntd)) { 3760213379Shselasky parm->err = USB_ERR_NOMEM; 3761213379Shselasky return; 3762213379Shselasky } 3763213379Shselasky if (parm->buf) { 3764213379Shselasky for (n = 0; n != ntd; n++) { 3765213379Shselasky struct xhci_td *td; 3766213379Shselasky 3767213379Shselasky usbd_get_page(pc + n, 0, &page_info); 3768213379Shselasky 3769213379Shselasky td = page_info.buffer; 3770213379Shselasky 3771213379Shselasky /* init TD */ 3772213379Shselasky td->td_self = page_info.physaddr; 3773213379Shselasky td->obj_next = last_obj; 3774213379Shselasky td->page_cache = pc + n; 3775213379Shselasky 3776213379Shselasky last_obj = td; 3777213379Shselasky 3778213379Shselasky usb_pc_cpu_flush(pc + n); 3779213379Shselasky } 3780213379Shselasky } 3781213379Shselasky xfer->td_start[xfer->flags_int.curr_dma_set] = last_obj; 3782213379Shselasky 3783213379Shselasky if (!xfer->flags_int.curr_dma_set) { 3784213379Shselasky xfer->flags_int.curr_dma_set = 1; 3785213379Shselasky goto alloc_dma_set; 3786213379Shselasky } 3787213379Shselasky} 3788213379Shselasky 3789213379Shselaskystatic usb_error_t 3790213379Shselaskyxhci_configure_reset_endpoint(struct usb_xfer *xfer) 3791213379Shselasky{ 3792213379Shselasky struct xhci_softc *sc = XHCI_BUS2SC(xfer->xroot->bus); 3793213379Shselasky struct usb_page_search buf_inp; 3794213379Shselasky struct usb_device *udev; 3795213379Shselasky struct xhci_endpoint_ext *pepext; 3796213379Shselasky struct usb_endpoint_descriptor *edesc; 3797213379Shselasky struct usb_page_cache *pcinp; 3798213379Shselasky usb_error_t err; 3799239214Shselasky usb_stream_t stream_id; 3800213379Shselasky uint8_t index; 3801213379Shselasky uint8_t epno; 3802213379Shselasky 3803213379Shselasky pepext = xhci_get_endpoint_ext(xfer->xroot->udev, 3804213379Shselasky xfer->endpoint->edesc); 3805213379Shselasky 3806213379Shselasky udev = xfer->xroot->udev; 3807213379Shselasky index = udev->controller_slot_id; 3808213379Shselasky 3809213379Shselasky pcinp = &sc->sc_hw.devs[index].input_pc; 3810213379Shselasky 3811213379Shselasky usbd_get_page(pcinp, 0, &buf_inp); 3812213379Shselasky 3813213379Shselasky edesc = xfer->endpoint->edesc; 3814213379Shselasky 3815213379Shselasky epno = edesc->bEndpointAddress; 3816239214Shselasky stream_id = xfer->stream_id; 3817213379Shselasky 3818213379Shselasky if ((edesc->bmAttributes & UE_XFERTYPE) == UE_CONTROL) 3819213379Shselasky epno |= UE_DIR_IN; 3820213379Shselasky 3821213379Shselasky epno = XHCI_EPNO2EPID(epno); 3822213379Shselasky 3823213379Shselasky if (epno == 0) 3824213379Shselasky return (USB_ERR_NO_PIPE); /* invalid */ 3825213379Shselasky 3826213379Shselasky XHCI_CMD_LOCK(sc); 3827213379Shselasky 3828213379Shselasky /* configure endpoint */ 3829213379Shselasky 3830213379Shselasky err = xhci_configure_endpoint_by_xfer(xfer); 3831213379Shselasky 3832213379Shselasky if (err != 0) { 3833213379Shselasky XHCI_CMD_UNLOCK(sc); 3834213379Shselasky return (err); 3835213379Shselasky } 3836213379Shselasky 3837213379Shselasky /* 3838213379Shselasky * Get the endpoint into the stopped state according to the 3839213379Shselasky * endpoint context state diagram in the XHCI specification: 3840213379Shselasky */ 3841213379Shselasky 3842213379Shselasky err = xhci_cmd_stop_ep(sc, 0, epno, index); 3843213379Shselasky 3844213379Shselasky if (err != 0) 3845213379Shselasky DPRINTF("Could not stop endpoint %u\n", epno); 3846213379Shselasky 3847213379Shselasky err = xhci_cmd_reset_ep(sc, 0, epno, index); 3848213379Shselasky 3849213379Shselasky if (err != 0) 3850213379Shselasky DPRINTF("Could not reset endpoint %u\n", epno); 3851213379Shselasky 3852239214Shselasky err = xhci_cmd_set_tr_dequeue_ptr(sc, 3853239214Shselasky (pepext->physaddr + (stream_id * sizeof(struct xhci_trb) * 3854239214Shselasky XHCI_MAX_TRANSFERS)) | XHCI_EPCTX_2_DCS_SET(1), 3855239214Shselasky stream_id, epno, index); 3856213379Shselasky 3857213379Shselasky if (err != 0) 3858213379Shselasky DPRINTF("Could not set dequeue ptr for endpoint %u\n", epno); 3859213379Shselasky 3860213379Shselasky /* 3861213379Shselasky * Get the endpoint into the running state according to the 3862213379Shselasky * endpoint context state diagram in the XHCI specification: 3863213379Shselasky */ 3864213379Shselasky 3865243780Shselasky xhci_configure_mask(udev, (1U << epno) | 1U, 0); 3866213379Shselasky 3867213379Shselasky err = xhci_cmd_evaluate_ctx(sc, buf_inp.physaddr, index); 3868213379Shselasky 3869213379Shselasky if (err != 0) 3870213379Shselasky DPRINTF("Could not configure endpoint %u\n", epno); 3871213379Shselasky 3872213379Shselasky err = xhci_cmd_configure_ep(sc, buf_inp.physaddr, 0, index); 3873213379Shselasky 3874213379Shselasky if (err != 0) 3875213379Shselasky DPRINTF("Could not configure endpoint %u\n", epno); 3876213379Shselasky 3877213379Shselasky XHCI_CMD_UNLOCK(sc); 3878213379Shselasky 3879213379Shselasky return (0); 3880213379Shselasky} 3881213379Shselasky 3882213379Shselaskystatic void 3883213379Shselaskyxhci_xfer_unsetup(struct usb_xfer *xfer) 3884213379Shselasky{ 3885213379Shselasky return; 3886213379Shselasky} 3887213379Shselasky 3888213379Shselaskystatic void 3889213379Shselaskyxhci_start_dma_delay(struct usb_xfer *xfer) 3890213379Shselasky{ 3891213379Shselasky struct xhci_softc *sc = XHCI_BUS2SC(xfer->xroot->bus); 3892213379Shselasky 3893213379Shselasky /* put transfer on interrupt queue (again) */ 3894213379Shselasky usbd_transfer_enqueue(&sc->sc_bus.intr_q, xfer); 3895213379Shselasky 3896246363Shselasky (void)usb_proc_msignal(USB_BUS_CONTROL_XFER_PROC(&sc->sc_bus), 3897213379Shselasky &sc->sc_config_msg[0], &sc->sc_config_msg[1]); 3898213379Shselasky} 3899213379Shselasky 3900213379Shselaskystatic void 3901213379Shselaskyxhci_configure_msg(struct usb_proc_msg *pm) 3902213379Shselasky{ 3903213379Shselasky struct xhci_softc *sc; 3904213379Shselasky struct xhci_endpoint_ext *pepext; 3905213379Shselasky struct usb_xfer *xfer; 3906213379Shselasky 3907213379Shselasky sc = XHCI_BUS2SC(((struct usb_bus_msg *)pm)->bus); 3908213379Shselasky 3909213379Shselaskyrestart: 3910213379Shselasky TAILQ_FOREACH(xfer, &sc->sc_bus.intr_q.head, wait_entry) { 3911213379Shselasky 3912213379Shselasky pepext = xhci_get_endpoint_ext(xfer->xroot->udev, 3913213379Shselasky xfer->endpoint->edesc); 3914213379Shselasky 3915213379Shselasky if ((pepext->trb_halted != 0) || 3916213379Shselasky (pepext->trb_running == 0)) { 3917213379Shselasky 3918251247Shselasky uint16_t i; 3919213379Shselasky 3920213379Shselasky /* clear halted and running */ 3921213379Shselasky pepext->trb_halted = 0; 3922213379Shselasky pepext->trb_running = 0; 3923213379Shselasky 3924213379Shselasky /* nuke remaining buffered transfers */ 3925213379Shselasky 3926251247Shselasky for (i = 0; i != (XHCI_MAX_TRANSFERS * 3927251247Shselasky XHCI_MAX_STREAMS); i++) { 3928213379Shselasky /* 3929213379Shselasky * NOTE: We need to use the timeout 3930213379Shselasky * error code here else existing 3931213379Shselasky * isochronous clients can get 3932213379Shselasky * confused: 3933213379Shselasky */ 3934213379Shselasky if (pepext->xfer[i] != NULL) { 3935213379Shselasky xhci_device_done(pepext->xfer[i], 3936213379Shselasky USB_ERR_TIMEOUT); 3937213379Shselasky } 3938213379Shselasky } 3939213379Shselasky 3940213379Shselasky /* 3941213379Shselasky * NOTE: The USB transfer cannot vanish in 3942213379Shselasky * this state! 3943213379Shselasky */ 3944213379Shselasky 3945213379Shselasky USB_BUS_UNLOCK(&sc->sc_bus); 3946213379Shselasky 3947213379Shselasky xhci_configure_reset_endpoint(xfer); 3948213379Shselasky 3949213379Shselasky USB_BUS_LOCK(&sc->sc_bus); 3950213379Shselasky 3951213379Shselasky /* check if halted is still cleared */ 3952213379Shselasky if (pepext->trb_halted == 0) { 3953213379Shselasky pepext->trb_running = 1; 3954239214Shselasky memset(pepext->trb_index, 0, 3955239214Shselasky sizeof(pepext->trb_index)); 3956213379Shselasky } 3957213379Shselasky goto restart; 3958213379Shselasky } 3959213379Shselasky 3960213379Shselasky if (xfer->flags_int.did_dma_delay) { 3961213379Shselasky 3962213379Shselasky /* remove transfer from interrupt queue (again) */ 3963213379Shselasky usbd_transfer_dequeue(xfer); 3964213379Shselasky 3965213379Shselasky /* we are finally done */ 3966213379Shselasky usb_dma_delay_done_cb(xfer); 3967213379Shselasky 3968213379Shselasky /* queue changed - restart */ 3969213379Shselasky goto restart; 3970213379Shselasky } 3971213379Shselasky } 3972213379Shselasky 3973213379Shselasky TAILQ_FOREACH(xfer, &sc->sc_bus.intr_q.head, wait_entry) { 3974213379Shselasky 3975213379Shselasky /* try to insert xfer on HW queue */ 3976213379Shselasky xhci_transfer_insert(xfer); 3977213379Shselasky 3978213379Shselasky /* try to multi buffer */ 3979239214Shselasky xhci_device_generic_multi_enter(xfer->endpoint, 3980239214Shselasky xfer->stream_id, NULL); 3981213379Shselasky } 3982213379Shselasky} 3983213379Shselasky 3984213379Shselaskystatic void 3985213379Shselaskyxhci_ep_init(struct usb_device *udev, struct usb_endpoint_descriptor *edesc, 3986213379Shselasky struct usb_endpoint *ep) 3987213379Shselasky{ 3988213379Shselasky struct xhci_endpoint_ext *pepext; 3989213379Shselasky 3990213379Shselasky DPRINTFN(2, "endpoint=%p, addr=%d, endpt=%d, mode=%d\n", 3991213379Shselasky ep, udev->address, edesc->bEndpointAddress, udev->flags.usb_mode); 3992213379Shselasky 3993213379Shselasky if (udev->parent_hub == NULL) { 3994213379Shselasky /* root HUB has special endpoint handling */ 3995213379Shselasky return; 3996213379Shselasky } 3997213379Shselasky 3998213379Shselasky ep->methods = &xhci_device_generic_methods; 3999213379Shselasky 4000213379Shselasky pepext = xhci_get_endpoint_ext(udev, edesc); 4001213379Shselasky 4002213379Shselasky USB_BUS_LOCK(udev->bus); 4003213379Shselasky pepext->trb_halted = 1; 4004213379Shselasky pepext->trb_running = 0; 4005213379Shselasky USB_BUS_UNLOCK(udev->bus); 4006213379Shselasky} 4007213379Shselasky 4008213379Shselaskystatic void 4009213379Shselaskyxhci_ep_uninit(struct usb_device *udev, struct usb_endpoint *ep) 4010213379Shselasky{ 4011213379Shselasky 4012213379Shselasky} 4013213379Shselasky 4014213379Shselaskystatic void 4015213379Shselaskyxhci_ep_clear_stall(struct usb_device *udev, struct usb_endpoint *ep) 4016213379Shselasky{ 4017213379Shselasky struct xhci_endpoint_ext *pepext; 4018213379Shselasky 4019213379Shselasky DPRINTF("\n"); 4020213379Shselasky 4021213379Shselasky if (udev->flags.usb_mode != USB_MODE_HOST) { 4022213379Shselasky /* not supported */ 4023213379Shselasky return; 4024213379Shselasky } 4025213379Shselasky if (udev->parent_hub == NULL) { 4026213379Shselasky /* root HUB has special endpoint handling */ 4027213379Shselasky return; 4028213379Shselasky } 4029213379Shselasky 4030213379Shselasky pepext = xhci_get_endpoint_ext(udev, ep->edesc); 4031213379Shselasky 4032213379Shselasky USB_BUS_LOCK(udev->bus); 4033213379Shselasky pepext->trb_halted = 1; 4034213379Shselasky pepext->trb_running = 0; 4035213379Shselasky USB_BUS_UNLOCK(udev->bus); 4036213379Shselasky} 4037213379Shselasky 4038213379Shselaskystatic usb_error_t 4039213379Shselaskyxhci_device_init(struct usb_device *udev) 4040213379Shselasky{ 4041213379Shselasky struct xhci_softc *sc = XHCI_BUS2SC(udev->bus); 4042213379Shselasky usb_error_t err; 4043213379Shselasky uint8_t temp; 4044213379Shselasky 4045213379Shselasky /* no init for root HUB */ 4046213379Shselasky if (udev->parent_hub == NULL) 4047213379Shselasky return (0); 4048213379Shselasky 4049213379Shselasky XHCI_CMD_LOCK(sc); 4050213379Shselasky 4051213379Shselasky /* set invalid default */ 4052213379Shselasky 4053213379Shselasky udev->controller_slot_id = sc->sc_noslot + 1; 4054213379Shselasky 4055213379Shselasky /* try to get a new slot ID from the XHCI */ 4056213379Shselasky 4057213379Shselasky err = xhci_cmd_enable_slot(sc, &temp); 4058213379Shselasky 4059213379Shselasky if (err) { 4060213379Shselasky XHCI_CMD_UNLOCK(sc); 4061213379Shselasky return (err); 4062213379Shselasky } 4063213379Shselasky 4064213379Shselasky if (temp > sc->sc_noslot) { 4065213379Shselasky XHCI_CMD_UNLOCK(sc); 4066213379Shselasky return (USB_ERR_BAD_ADDRESS); 4067213379Shselasky } 4068213379Shselasky 4069213379Shselasky if (sc->sc_hw.devs[temp].state != XHCI_ST_DISABLED) { 4070213379Shselasky DPRINTF("slot %u already allocated.\n", temp); 4071213379Shselasky XHCI_CMD_UNLOCK(sc); 4072213379Shselasky return (USB_ERR_BAD_ADDRESS); 4073213379Shselasky } 4074213379Shselasky 4075213379Shselasky /* store slot ID for later reference */ 4076213379Shselasky 4077213379Shselasky udev->controller_slot_id = temp; 4078213379Shselasky 4079213379Shselasky /* reset data structure */ 4080213379Shselasky 4081213379Shselasky memset(&sc->sc_hw.devs[temp], 0, sizeof(sc->sc_hw.devs[0])); 4082213379Shselasky 4083213379Shselasky /* set mark slot allocated */ 4084213379Shselasky 4085213379Shselasky sc->sc_hw.devs[temp].state = XHCI_ST_ENABLED; 4086213379Shselasky 4087213379Shselasky err = xhci_alloc_device_ext(udev); 4088213379Shselasky 4089213379Shselasky XHCI_CMD_UNLOCK(sc); 4090213379Shselasky 4091213379Shselasky /* get device into default state */ 4092213379Shselasky 4093213379Shselasky if (err == 0) 4094213379Shselasky err = xhci_set_address(udev, NULL, 0); 4095213379Shselasky 4096213379Shselasky return (err); 4097213379Shselasky} 4098213379Shselasky 4099213379Shselaskystatic void 4100213379Shselaskyxhci_device_uninit(struct usb_device *udev) 4101213379Shselasky{ 4102213379Shselasky struct xhci_softc *sc = XHCI_BUS2SC(udev->bus); 4103213379Shselasky uint8_t index; 4104213379Shselasky 4105213379Shselasky /* no init for root HUB */ 4106213379Shselasky if (udev->parent_hub == NULL) 4107213379Shselasky return; 4108213379Shselasky 4109213379Shselasky XHCI_CMD_LOCK(sc); 4110213379Shselasky 4111213379Shselasky index = udev->controller_slot_id; 4112213379Shselasky 4113213379Shselasky if (index <= sc->sc_noslot) { 4114213379Shselasky xhci_cmd_disable_slot(sc, index); 4115213379Shselasky sc->sc_hw.devs[index].state = XHCI_ST_DISABLED; 4116213379Shselasky 4117213379Shselasky /* free device extension */ 4118213379Shselasky xhci_free_device_ext(udev); 4119213379Shselasky } 4120213379Shselasky 4121213379Shselasky XHCI_CMD_UNLOCK(sc); 4122213379Shselasky} 4123213379Shselasky 4124213379Shselaskystatic void 4125213379Shselaskyxhci_get_dma_delay(struct usb_device *udev, uint32_t *pus) 4126213379Shselasky{ 4127213379Shselasky /* 4128213379Shselasky * Wait until the hardware has finished any possible use of 4129213379Shselasky * the transfer descriptor(s) 4130213379Shselasky */ 4131213379Shselasky *pus = 2048; /* microseconds */ 4132213379Shselasky} 4133213379Shselasky 4134213379Shselaskystatic void 4135213379Shselaskyxhci_device_resume(struct usb_device *udev) 4136213379Shselasky{ 4137213379Shselasky struct xhci_softc *sc = XHCI_BUS2SC(udev->bus); 4138213379Shselasky uint8_t index; 4139213379Shselasky uint8_t n; 4140243780Shselasky uint8_t p; 4141213379Shselasky 4142213379Shselasky DPRINTF("\n"); 4143213379Shselasky 4144213379Shselasky /* check for root HUB */ 4145213379Shselasky if (udev->parent_hub == NULL) 4146213379Shselasky return; 4147213379Shselasky 4148213379Shselasky index = udev->controller_slot_id; 4149213379Shselasky 4150213379Shselasky XHCI_CMD_LOCK(sc); 4151213379Shselasky 4152213379Shselasky /* blindly resume all endpoints */ 4153213379Shselasky 4154213379Shselasky USB_BUS_LOCK(udev->bus); 4155213379Shselasky 4156243780Shselasky for (n = 1; n != XHCI_MAX_ENDPOINTS; n++) { 4157243780Shselasky for (p = 0; p != XHCI_MAX_STREAMS; p++) { 4158243780Shselasky XWRITE4(sc, door, XHCI_DOORBELL(index), 4159243780Shselasky n | XHCI_DB_SID_SET(p)); 4160243780Shselasky } 4161243780Shselasky } 4162213379Shselasky 4163213379Shselasky USB_BUS_UNLOCK(udev->bus); 4164213379Shselasky 4165213379Shselasky XHCI_CMD_UNLOCK(sc); 4166213379Shselasky} 4167213379Shselasky 4168213379Shselaskystatic void 4169213379Shselaskyxhci_device_suspend(struct usb_device *udev) 4170213379Shselasky{ 4171213379Shselasky struct xhci_softc *sc = XHCI_BUS2SC(udev->bus); 4172213379Shselasky uint8_t index; 4173213379Shselasky uint8_t n; 4174213379Shselasky usb_error_t err; 4175213379Shselasky 4176213379Shselasky DPRINTF("\n"); 4177213379Shselasky 4178213379Shselasky /* check for root HUB */ 4179213379Shselasky if (udev->parent_hub == NULL) 4180213379Shselasky return; 4181213379Shselasky 4182213379Shselasky index = udev->controller_slot_id; 4183213379Shselasky 4184213379Shselasky XHCI_CMD_LOCK(sc); 4185213379Shselasky 4186213379Shselasky /* blindly suspend all endpoints */ 4187213379Shselasky 4188213379Shselasky for (n = 1; n != XHCI_MAX_ENDPOINTS; n++) { 4189213379Shselasky err = xhci_cmd_stop_ep(sc, 1, n, index); 4190213379Shselasky if (err != 0) { 4191213379Shselasky DPRINTF("Failed to suspend endpoint " 4192213379Shselasky "%u on slot %u (ignored).\n", n, index); 4193213379Shselasky } 4194213379Shselasky } 4195213379Shselasky 4196213379Shselasky XHCI_CMD_UNLOCK(sc); 4197213379Shselasky} 4198213379Shselasky 4199213379Shselaskystatic void 4200213379Shselaskyxhci_set_hw_power(struct usb_bus *bus) 4201213379Shselasky{ 4202213379Shselasky DPRINTF("\n"); 4203213379Shselasky} 4204213379Shselasky 4205213379Shselaskystatic void 4206213379Shselaskyxhci_device_state_change(struct usb_device *udev) 4207213379Shselasky{ 4208213379Shselasky struct xhci_softc *sc = XHCI_BUS2SC(udev->bus); 4209213379Shselasky struct usb_page_search buf_inp; 4210213379Shselasky usb_error_t err; 4211213379Shselasky uint8_t index; 4212213379Shselasky 4213213379Shselasky /* check for root HUB */ 4214213379Shselasky if (udev->parent_hub == NULL) 4215213379Shselasky return; 4216213379Shselasky 4217213379Shselasky index = udev->controller_slot_id; 4218213379Shselasky 4219213379Shselasky DPRINTF("\n"); 4220213379Shselasky 4221213379Shselasky if (usb_get_device_state(udev) == USB_STATE_CONFIGURED) { 4222213379Shselasky err = uhub_query_info(udev, &sc->sc_hw.devs[index].nports, 4223213379Shselasky &sc->sc_hw.devs[index].tt); 4224213379Shselasky if (err != 0) 4225213379Shselasky sc->sc_hw.devs[index].nports = 0; 4226213379Shselasky } 4227213379Shselasky 4228213379Shselasky XHCI_CMD_LOCK(sc); 4229213379Shselasky 4230213379Shselasky switch (usb_get_device_state(udev)) { 4231213379Shselasky case USB_STATE_POWERED: 4232213379Shselasky if (sc->sc_hw.devs[index].state == XHCI_ST_DEFAULT) 4233213379Shselasky break; 4234213379Shselasky 4235243780Shselasky /* set default state */ 4236213379Shselasky sc->sc_hw.devs[index].state = XHCI_ST_DEFAULT; 4237213379Shselasky 4238243780Shselasky /* reset number of contexts */ 4239243780Shselasky sc->sc_hw.devs[index].context_num = 0; 4240243780Shselasky 4241213379Shselasky err = xhci_cmd_reset_dev(sc, index); 4242213379Shselasky 4243213379Shselasky if (err != 0) { 4244213379Shselasky DPRINTF("Device reset failed " 4245213379Shselasky "for slot %u.\n", index); 4246213379Shselasky } 4247213379Shselasky break; 4248213379Shselasky 4249213379Shselasky case USB_STATE_ADDRESSED: 4250213379Shselasky if (sc->sc_hw.devs[index].state == XHCI_ST_ADDRESSED) 4251213379Shselasky break; 4252213379Shselasky 4253213379Shselasky sc->sc_hw.devs[index].state = XHCI_ST_ADDRESSED; 4254213379Shselasky 4255213379Shselasky err = xhci_cmd_configure_ep(sc, 0, 1, index); 4256213379Shselasky 4257213379Shselasky if (err) { 4258213379Shselasky DPRINTF("Failed to deconfigure " 4259213379Shselasky "slot %u.\n", index); 4260213379Shselasky } 4261213379Shselasky break; 4262213379Shselasky 4263213379Shselasky case USB_STATE_CONFIGURED: 4264213379Shselasky if (sc->sc_hw.devs[index].state == XHCI_ST_CONFIGURED) 4265213379Shselasky break; 4266213379Shselasky 4267243780Shselasky /* set configured state */ 4268213379Shselasky sc->sc_hw.devs[index].state = XHCI_ST_CONFIGURED; 4269213379Shselasky 4270243780Shselasky /* reset number of contexts */ 4271243780Shselasky sc->sc_hw.devs[index].context_num = 0; 4272243780Shselasky 4273213379Shselasky usbd_get_page(&sc->sc_hw.devs[index].input_pc, 0, &buf_inp); 4274213379Shselasky 4275243780Shselasky xhci_configure_mask(udev, 3, 0); 4276213379Shselasky 4277213379Shselasky err = xhci_configure_device(udev); 4278213379Shselasky if (err != 0) { 4279213379Shselasky DPRINTF("Could not configure device " 4280213379Shselasky "at slot %u.\n", index); 4281213379Shselasky } 4282213379Shselasky 4283213379Shselasky err = xhci_cmd_evaluate_ctx(sc, buf_inp.physaddr, index); 4284213379Shselasky if (err != 0) { 4285213379Shselasky DPRINTF("Could not evaluate device " 4286213379Shselasky "context at slot %u.\n", index); 4287213379Shselasky } 4288213379Shselasky break; 4289213379Shselasky 4290213379Shselasky default: 4291213379Shselasky break; 4292213379Shselasky } 4293213379Shselasky XHCI_CMD_UNLOCK(sc); 4294213379Shselasky} 4295213379Shselasky 4296239214Shselaskystatic usb_error_t 4297239214Shselaskyxhci_set_endpoint_mode(struct usb_device *udev, struct usb_endpoint *ep, 4298239214Shselasky uint8_t ep_mode) 4299239214Shselasky{ 4300239214Shselasky switch (ep_mode) { 4301239214Shselasky case USB_EP_MODE_DEFAULT: 4302239214Shselasky return (0); 4303239214Shselasky case USB_EP_MODE_STREAMS: 4304255347Shselasky if (xhcistreams == 0 || 4305255347Shselasky (ep->edesc->bmAttributes & UE_XFERTYPE) != UE_BULK || 4306239214Shselasky udev->speed != USB_SPEED_SUPER) 4307239214Shselasky return (USB_ERR_INVAL); 4308239214Shselasky return (0); 4309239214Shselasky default: 4310239214Shselasky return (USB_ERR_INVAL); 4311239214Shselasky } 4312239214Shselasky} 4313239214Shselasky 4314213379Shselaskystruct usb_bus_methods xhci_bus_methods = { 4315213379Shselasky .endpoint_init = xhci_ep_init, 4316213379Shselasky .endpoint_uninit = xhci_ep_uninit, 4317213379Shselasky .xfer_setup = xhci_xfer_setup, 4318213379Shselasky .xfer_unsetup = xhci_xfer_unsetup, 4319213379Shselasky .get_dma_delay = xhci_get_dma_delay, 4320213379Shselasky .device_init = xhci_device_init, 4321213379Shselasky .device_uninit = xhci_device_uninit, 4322213379Shselasky .device_resume = xhci_device_resume, 4323213379Shselasky .device_suspend = xhci_device_suspend, 4324213379Shselasky .set_hw_power = xhci_set_hw_power, 4325213379Shselasky .roothub_exec = xhci_roothub_exec, 4326213379Shselasky .xfer_poll = xhci_do_poll, 4327213379Shselasky .start_dma_delay = xhci_start_dma_delay, 4328213379Shselasky .set_address = xhci_set_address, 4329213379Shselasky .clear_stall = xhci_ep_clear_stall, 4330213379Shselasky .device_state_change = xhci_device_state_change, 4331229086Shselasky .set_hw_power_sleep = xhci_set_hw_power_sleep, 4332239214Shselasky .set_endpoint_mode = xhci_set_endpoint_mode, 4333213379Shselasky}; 4334