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