1993e3fafSRobert Mustacchi /*
2993e3fafSRobert Mustacchi  * This file and its contents are supplied under the terms of the
3993e3fafSRobert Mustacchi  * Common Development and Distribution License ("CDDL"), version 1.0.
4993e3fafSRobert Mustacchi  * You may only use this file in accordance with the terms of version
5993e3fafSRobert Mustacchi  * 1.0 of the CDDL.
6993e3fafSRobert Mustacchi  *
7993e3fafSRobert Mustacchi  * A full copy of the text of the CDDL should have accompanied this
8993e3fafSRobert Mustacchi  * source.  A copy of the CDDL is also available via the Internet at
9993e3fafSRobert Mustacchi  * http://www.illumos.org/license/CDDL.
10993e3fafSRobert Mustacchi  */
11993e3fafSRobert Mustacchi 
12993e3fafSRobert Mustacchi /*
132aba3acdSRobert Mustacchi  * Copyright (c) 2018, Joyent, Inc.
14ec82ef79SMatthias Scheler  * Copyright (c) 2019 by Western Digital Corporation
15*0ae0ab6fSJoshua M. Clulow  * Copyright 2022 Oxide Computer Company
16993e3fafSRobert Mustacchi  */
17993e3fafSRobert Mustacchi 
18993e3fafSRobert Mustacchi /*
19993e3fafSRobert Mustacchi  * xHCI Endpoint Initialization and Management
20993e3fafSRobert Mustacchi  *
21993e3fafSRobert Mustacchi  * Please see the big theory statement in xhci.c for more information.
22993e3fafSRobert Mustacchi  */
23993e3fafSRobert Mustacchi 
24993e3fafSRobert Mustacchi #include <sys/usb/hcd/xhci/xhci.h>
25993e3fafSRobert Mustacchi #include <sys/sdt.h>
26993e3fafSRobert Mustacchi 
27993e3fafSRobert Mustacchi boolean_t
xhci_endpoint_is_periodic_in(xhci_endpoint_t * xep)28993e3fafSRobert Mustacchi xhci_endpoint_is_periodic_in(xhci_endpoint_t *xep)
29993e3fafSRobert Mustacchi {
30993e3fafSRobert Mustacchi 	usba_pipe_handle_data_t *ph;
31993e3fafSRobert Mustacchi 
32993e3fafSRobert Mustacchi 	ASSERT(xep != NULL);
33993e3fafSRobert Mustacchi 	ph = xep->xep_pipe;
34993e3fafSRobert Mustacchi 	ASSERT(ph != NULL);
35993e3fafSRobert Mustacchi 
36993e3fafSRobert Mustacchi 	return ((xep->xep_type == USB_EP_ATTR_INTR ||
37993e3fafSRobert Mustacchi 	    xep->xep_type == USB_EP_ATTR_ISOCH) &&
38993e3fafSRobert Mustacchi 	    (ph->p_ep.bEndpointAddress & USB_EP_DIR_MASK) == USB_EP_DIR_IN);
39993e3fafSRobert Mustacchi }
40993e3fafSRobert Mustacchi 
41993e3fafSRobert Mustacchi /*
42993e3fafSRobert Mustacchi  * Endpoints are a bit weirdly numbered. Endpoint zero is the default control
43993e3fafSRobert Mustacchi  * endpoint, so the direction doesn't matter. For all the others, they're
44993e3fafSRobert Mustacchi  * arranged as ep 1 out, ep 1 in, ep 2 out, ep 2 in. This is based on the layout
45993e3fafSRobert Mustacchi  * of the Device Context Structure in xHCI 1.1 / 6.2.1. Therefore to go from the
46993e3fafSRobert Mustacchi  * endpoint and direction, we know that endpoint n starts at 2n - 1.  e.g.
47993e3fafSRobert Mustacchi  * endpoint 1 starts at entry 1, endpoint 2 at entry 3, etc. Finally, the OUT
48993e3fafSRobert Mustacchi  * direction comes first, followed by the IN direction. So if we're getting the
49993e3fafSRobert Mustacchi  * endpoint for one of those, then we have to deal with that.
50993e3fafSRobert Mustacchi  */
51993e3fafSRobert Mustacchi uint_t
xhci_endpoint_pipe_to_epid(usba_pipe_handle_data_t * ph)52993e3fafSRobert Mustacchi xhci_endpoint_pipe_to_epid(usba_pipe_handle_data_t *ph)
53993e3fafSRobert Mustacchi {
54993e3fafSRobert Mustacchi 	int ep;
55993e3fafSRobert Mustacchi 
56993e3fafSRobert Mustacchi 	ep = ph->p_ep.bEndpointAddress & USB_EP_NUM_MASK;
57993e3fafSRobert Mustacchi 	if (ep == 0)
58993e3fafSRobert Mustacchi 		return (ep);
59993e3fafSRobert Mustacchi 	ep = ep * 2 - 1;
60993e3fafSRobert Mustacchi 	if ((ph->p_ep.bEndpointAddress & USB_EP_DIR_MASK) == USB_EP_DIR_IN)
61993e3fafSRobert Mustacchi 		ep++;
62993e3fafSRobert Mustacchi 
63993e3fafSRobert Mustacchi 	VERIFY(ep < XHCI_NUM_ENDPOINTS);
64993e3fafSRobert Mustacchi 	return (ep);
65993e3fafSRobert Mustacchi }
66993e3fafSRobert Mustacchi 
67*0ae0ab6fSJoshua M. Clulow void
xhci_endpoint_timeout_cancel(xhci_t * xhcip,xhci_endpoint_t * xep)68*0ae0ab6fSJoshua M. Clulow xhci_endpoint_timeout_cancel(xhci_t *xhcip, xhci_endpoint_t *xep)
69*0ae0ab6fSJoshua M. Clulow {
70*0ae0ab6fSJoshua M. Clulow 	xep->xep_state |= XHCI_ENDPOINT_TEARDOWN;
71*0ae0ab6fSJoshua M. Clulow 	if (xep->xep_timeout != 0) {
72*0ae0ab6fSJoshua M. Clulow 		mutex_exit(&xhcip->xhci_lock);
73*0ae0ab6fSJoshua M. Clulow 		(void) untimeout(xep->xep_timeout);
74*0ae0ab6fSJoshua M. Clulow 		mutex_enter(&xhcip->xhci_lock);
75*0ae0ab6fSJoshua M. Clulow 		xep->xep_timeout = 0;
76*0ae0ab6fSJoshua M. Clulow 	}
77*0ae0ab6fSJoshua M. Clulow }
78*0ae0ab6fSJoshua M. Clulow 
79*0ae0ab6fSJoshua M. Clulow void
xhci_endpoint_release(xhci_t * xhcip,xhci_endpoint_t * xep)80*0ae0ab6fSJoshua M. Clulow xhci_endpoint_release(xhci_t *xhcip, xhci_endpoint_t *xep)
81*0ae0ab6fSJoshua M. Clulow {
82*0ae0ab6fSJoshua M. Clulow 	VERIFY(MUTEX_HELD(&xhcip->xhci_lock));
83*0ae0ab6fSJoshua M. Clulow 	VERIFY3U(xep->xep_num, !=, XHCI_DEFAULT_ENDPOINT);
84*0ae0ab6fSJoshua M. Clulow 	VERIFY(list_is_empty(&xep->xep_transfers));
85*0ae0ab6fSJoshua M. Clulow 
86*0ae0ab6fSJoshua M. Clulow 	VERIFY(xep->xep_pipe != NULL);
87*0ae0ab6fSJoshua M. Clulow 	xep->xep_pipe = NULL;
88*0ae0ab6fSJoshua M. Clulow 
89*0ae0ab6fSJoshua M. Clulow 	VERIFY(xep->xep_state & XHCI_ENDPOINT_OPEN);
90*0ae0ab6fSJoshua M. Clulow 	xep->xep_state &= ~XHCI_ENDPOINT_OPEN;
91*0ae0ab6fSJoshua M. Clulow 
92*0ae0ab6fSJoshua M. Clulow 	xhci_endpoint_timeout_cancel(xhcip, xep);
93*0ae0ab6fSJoshua M. Clulow }
94*0ae0ab6fSJoshua M. Clulow 
95993e3fafSRobert Mustacchi /*
96993e3fafSRobert Mustacchi  * The assumption is that someone calling this owns this endpoint / device and
97993e3fafSRobert Mustacchi  * that it's in a state where it's safe to zero out that information.
98993e3fafSRobert Mustacchi  */
99993e3fafSRobert Mustacchi void
xhci_endpoint_fini(xhci_device_t * xd,int endpoint)100993e3fafSRobert Mustacchi xhci_endpoint_fini(xhci_device_t *xd, int endpoint)
101993e3fafSRobert Mustacchi {
102993e3fafSRobert Mustacchi 	xhci_endpoint_t *xep = xd->xd_endpoints[endpoint];
103993e3fafSRobert Mustacchi 
104993e3fafSRobert Mustacchi 	VERIFY(xep != NULL);
105993e3fafSRobert Mustacchi 	xd->xd_endpoints[endpoint] = NULL;
106993e3fafSRobert Mustacchi 
107*0ae0ab6fSJoshua M. Clulow 	if (endpoint != XHCI_DEFAULT_ENDPOINT) {
108*0ae0ab6fSJoshua M. Clulow 		VERIFY(!(xep->xep_state & XHCI_ENDPOINT_OPEN));
109*0ae0ab6fSJoshua M. Clulow 	}
110*0ae0ab6fSJoshua M. Clulow 
111993e3fafSRobert Mustacchi 	xhci_ring_free(&xep->xep_ring);
112993e3fafSRobert Mustacchi 	cv_destroy(&xep->xep_state_cv);
113993e3fafSRobert Mustacchi 	list_destroy(&xep->xep_transfers);
114993e3fafSRobert Mustacchi 	kmem_free(xep, sizeof (xhci_endpoint_t));
115993e3fafSRobert Mustacchi }
116993e3fafSRobert Mustacchi 
117993e3fafSRobert Mustacchi /*
118993e3fafSRobert Mustacchi  * Set up the default control endpoint input context. This needs to be done
119993e3fafSRobert Mustacchi  * before we address the device. Note, we separate out the default endpoint from
120993e3fafSRobert Mustacchi  * others, as we must set this up before we have a pipe handle.
121993e3fafSRobert Mustacchi  */
122993e3fafSRobert Mustacchi int
xhci_endpoint_setup_default_context(xhci_t * xhcip,xhci_device_t * xd,xhci_endpoint_t * xep)123993e3fafSRobert Mustacchi xhci_endpoint_setup_default_context(xhci_t *xhcip, xhci_device_t *xd,
124993e3fafSRobert Mustacchi     xhci_endpoint_t *xep)
125993e3fafSRobert Mustacchi {
126993e3fafSRobert Mustacchi 	uint_t mps;
127993e3fafSRobert Mustacchi 	xhci_endpoint_context_t *ectx;
128993e3fafSRobert Mustacchi 	uint64_t deq;
129993e3fafSRobert Mustacchi 
130993e3fafSRobert Mustacchi 	ectx = xd->xd_endin[xep->xep_num];
131993e3fafSRobert Mustacchi 	VERIFY(ectx != NULL);
132993e3fafSRobert Mustacchi 
133993e3fafSRobert Mustacchi 	/*
134993e3fafSRobert Mustacchi 	 * We may or may not have a device descriptor. This should match the
135993e3fafSRobert Mustacchi 	 * same initial sizes that are done in hubd_create_child().
136993e3fafSRobert Mustacchi 	 *
137993e3fafSRobert Mustacchi 	 * Note, since we don't necessarily have an endpoint descriptor yet to
138993e3fafSRobert Mustacchi 	 * base this on we instead use the device's defaults if available. This
139993e3fafSRobert Mustacchi 	 * is different from normal endpoints for which there's always a
140993e3fafSRobert Mustacchi 	 * specific descriptor.
141993e3fafSRobert Mustacchi 	 */
142993e3fafSRobert Mustacchi 	switch (xd->xd_usbdev->usb_port_status) {
143993e3fafSRobert Mustacchi 	case USBA_LOW_SPEED_DEV:
144993e3fafSRobert Mustacchi 		if (xd->xd_usbdev->usb_dev_descr != NULL) {
145993e3fafSRobert Mustacchi 			mps = xd->xd_usbdev->usb_dev_descr->bMaxPacketSize0;
146993e3fafSRobert Mustacchi 		} else {
147993e3fafSRobert Mustacchi 			mps = 8;
148993e3fafSRobert Mustacchi 		}
149993e3fafSRobert Mustacchi 		break;
150993e3fafSRobert Mustacchi 	case USBA_FULL_SPEED_DEV:
151993e3fafSRobert Mustacchi 	case USBA_HIGH_SPEED_DEV:
152993e3fafSRobert Mustacchi 		if (xd->xd_usbdev->usb_dev_descr != NULL) {
153993e3fafSRobert Mustacchi 			mps = xd->xd_usbdev->usb_dev_descr->bMaxPacketSize0;
154993e3fafSRobert Mustacchi 		} else {
155993e3fafSRobert Mustacchi 			mps = 64;
156993e3fafSRobert Mustacchi 		}
157993e3fafSRobert Mustacchi 		break;
158993e3fafSRobert Mustacchi 	case USBA_SUPER_SPEED_DEV:
159993e3fafSRobert Mustacchi 	default:
160993e3fafSRobert Mustacchi 		if (xd->xd_usbdev->usb_dev_descr != NULL) {
161993e3fafSRobert Mustacchi 			mps = xd->xd_usbdev->usb_dev_descr->bMaxPacketSize0;
162993e3fafSRobert Mustacchi 			mps = 1 << mps;
163993e3fafSRobert Mustacchi 		} else {
164993e3fafSRobert Mustacchi 			mps = 512;
165993e3fafSRobert Mustacchi 		}
166993e3fafSRobert Mustacchi 		break;
167993e3fafSRobert Mustacchi 	}
168993e3fafSRobert Mustacchi 
169993e3fafSRobert Mustacchi 	bzero(ectx, sizeof (xhci_endpoint_context_t));
170993e3fafSRobert Mustacchi 	ectx->xec_info = LE_32(0);
171993e3fafSRobert Mustacchi 	ectx->xec_info2 = LE_32(XHCI_EPCTX_SET_CERR(3) |
172993e3fafSRobert Mustacchi 	    XHCI_EPCTX_SET_EPTYPE(XHCI_EPCTX_TYPE_CTRL) |
173993e3fafSRobert Mustacchi 	    XHCI_EPCTX_SET_MAXB(0) | XHCI_EPCTX_SET_MPS(mps));
174993e3fafSRobert Mustacchi 	deq = xhci_dma_pa(&xep->xep_ring.xr_dma) + sizeof (xhci_trb_t) *
175993e3fafSRobert Mustacchi 	    xep->xep_ring.xr_tail;
176993e3fafSRobert Mustacchi 	ectx->xec_dequeue = LE_64(deq | xep->xep_ring.xr_cycle);
177993e3fafSRobert Mustacchi 	ectx->xec_txinfo = LE_32(XHCI_EPCTX_MAX_ESIT_PAYLOAD(0) |
178993e3fafSRobert Mustacchi 	    XHCI_EPCTX_AVG_TRB_LEN(XHCI_CONTEXT_DEF_CTRL_ATL));
179993e3fafSRobert Mustacchi 
180993e3fafSRobert Mustacchi 	XHCI_DMA_SYNC(xd->xd_ictx, DDI_DMA_SYNC_FORDEV);
181993e3fafSRobert Mustacchi 	if (xhci_check_dma_handle(xhcip, &xd->xd_ictx) != DDI_FM_OK) {
182993e3fafSRobert Mustacchi 		xhci_error(xhcip, "failed to initialize default device input "
183993e3fafSRobert Mustacchi 		    "context on slot %d and port %d for endpoint %u:  "
184993e3fafSRobert Mustacchi 		    "encountered fatal FM error synchronizing input context "
185993e3fafSRobert Mustacchi 		    "DMA memory", xd->xd_slot, xd->xd_port, xep->xep_num);
186993e3fafSRobert Mustacchi 		xhci_fm_runtime_reset(xhcip);
187993e3fafSRobert Mustacchi 		return (EIO);
188993e3fafSRobert Mustacchi 	}
189993e3fafSRobert Mustacchi 
190993e3fafSRobert Mustacchi 	return (0);
191993e3fafSRobert Mustacchi }
192993e3fafSRobert Mustacchi 
193993e3fafSRobert Mustacchi /*
194993e3fafSRobert Mustacchi  * Determine if we need to update the maximum packet size of the default
195993e3fafSRobert Mustacchi  * control endpoint. This may happen because we start with the default size
196993e3fafSRobert Mustacchi  * before we have a descriptor and then it may change. For example, with
197993e3fafSRobert Mustacchi  * full-speed devices that may have either an 8 or 64 byte maximum packet size.
198993e3fafSRobert Mustacchi  */
199993e3fafSRobert Mustacchi int
xhci_endpoint_update_default(xhci_t * xhcip,xhci_device_t * xd,xhci_endpoint_t * xep)200993e3fafSRobert Mustacchi xhci_endpoint_update_default(xhci_t *xhcip, xhci_device_t *xd,
201993e3fafSRobert Mustacchi     xhci_endpoint_t *xep)
202993e3fafSRobert Mustacchi {
203993e3fafSRobert Mustacchi 	int mps, desc, info, ret;
204993e3fafSRobert Mustacchi 	ASSERT(xd->xd_usbdev != NULL);
205993e3fafSRobert Mustacchi 
206993e3fafSRobert Mustacchi 	mps = XHCI_EPCTX_GET_MPS(xd->xd_endout[xep->xep_num]->xec_info2);
207993e3fafSRobert Mustacchi 	desc = xd->xd_usbdev->usb_dev_descr->bMaxPacketSize0;
208993e3fafSRobert Mustacchi 	if (xd->xd_usbdev->usb_port_status >= USBA_SUPER_SPEED_DEV) {
209993e3fafSRobert Mustacchi 		desc = 1 << desc;
210993e3fafSRobert Mustacchi 	}
211993e3fafSRobert Mustacchi 
212993e3fafSRobert Mustacchi 	if (mps == desc)
213993e3fafSRobert Mustacchi 		return (USB_SUCCESS);
214993e3fafSRobert Mustacchi 
215993e3fafSRobert Mustacchi 	/*
216993e3fafSRobert Mustacchi 	 * Update only the context for the default control endpoint.
217993e3fafSRobert Mustacchi 	 */
218993e3fafSRobert Mustacchi 	mutex_enter(&xd->xd_imtx);
219993e3fafSRobert Mustacchi 	info = LE_32(xd->xd_endout[xep->xep_num]->xec_info2);
220993e3fafSRobert Mustacchi 	info &= ~XHCI_EPCTX_SET_MPS(mps);
221993e3fafSRobert Mustacchi 	info |= XHCI_EPCTX_SET_MPS(desc);
222993e3fafSRobert Mustacchi 	xd->xd_endin[xep->xep_num]->xec_info2 = LE_32(info);
223993e3fafSRobert Mustacchi 	xd->xd_input->xic_drop_flags = LE_32(0);
224993e3fafSRobert Mustacchi 	xd->xd_input->xic_add_flags = LE_32(XHCI_INCTX_MASK_DCI(1));
225993e3fafSRobert Mustacchi 
226993e3fafSRobert Mustacchi 	ret = xhci_command_evaluate_context(xhcip, xd);
227993e3fafSRobert Mustacchi 	mutex_exit(&xd->xd_imtx);
228993e3fafSRobert Mustacchi 
229993e3fafSRobert Mustacchi 	return (ret);
230993e3fafSRobert Mustacchi }
231993e3fafSRobert Mustacchi 
232993e3fafSRobert Mustacchi static uint_t
xhci_endpoint_epdesc_to_type(usb_ep_descr_t * ep)233993e3fafSRobert Mustacchi xhci_endpoint_epdesc_to_type(usb_ep_descr_t *ep)
234993e3fafSRobert Mustacchi {
235993e3fafSRobert Mustacchi 	int type = ep->bmAttributes & USB_EP_ATTR_MASK;
236993e3fafSRobert Mustacchi 	boolean_t in = (ep->bEndpointAddress & USB_EP_DIR_MASK) ==
237993e3fafSRobert Mustacchi 	    USB_EP_DIR_IN;
238993e3fafSRobert Mustacchi 
239993e3fafSRobert Mustacchi 	switch (type) {
240993e3fafSRobert Mustacchi 	case USB_EP_ATTR_CONTROL:
241993e3fafSRobert Mustacchi 		return (XHCI_EPCTX_TYPE_CTRL);
242993e3fafSRobert Mustacchi 	case USB_EP_ATTR_ISOCH:
243993e3fafSRobert Mustacchi 		if (in == B_TRUE)
244993e3fafSRobert Mustacchi 			return (XHCI_EPCTX_TYPE_ISOCH_IN);
245993e3fafSRobert Mustacchi 		return (XHCI_EPCTX_TYPE_ISOCH_OUT);
246993e3fafSRobert Mustacchi 	case USB_EP_ATTR_BULK:
247993e3fafSRobert Mustacchi 		if (in == B_TRUE)
248993e3fafSRobert Mustacchi 			return (XHCI_EPCTX_TYPE_BULK_IN);
249993e3fafSRobert Mustacchi 		return (XHCI_EPCTX_TYPE_BULK_OUT);
250993e3fafSRobert Mustacchi 	case USB_EP_ATTR_INTR:
251993e3fafSRobert Mustacchi 		if (in == B_TRUE)
252993e3fafSRobert Mustacchi 			return (XHCI_EPCTX_TYPE_INTR_IN);
253993e3fafSRobert Mustacchi 		return (XHCI_EPCTX_TYPE_INTR_OUT);
254993e3fafSRobert Mustacchi 	default:
255993e3fafSRobert Mustacchi 		panic("bad USB attribute type: %d", type);
256993e3fafSRobert Mustacchi 	}
257993e3fafSRobert Mustacchi 
258993e3fafSRobert Mustacchi 	/* LINTED: E_FUNC_NO_RET_VAL */
259993e3fafSRobert Mustacchi }
260993e3fafSRobert Mustacchi 
261993e3fafSRobert Mustacchi static uint_t
xhci_endpoint_determine_burst(xhci_device_t * xd,xhci_endpoint_t * xep)262993e3fafSRobert Mustacchi xhci_endpoint_determine_burst(xhci_device_t *xd, xhci_endpoint_t *xep)
263993e3fafSRobert Mustacchi {
264993e3fafSRobert Mustacchi 	switch (xd->xd_usbdev->usb_port_status) {
265993e3fafSRobert Mustacchi 	case USBA_LOW_SPEED_DEV:
266993e3fafSRobert Mustacchi 	case USBA_FULL_SPEED_DEV:
267993e3fafSRobert Mustacchi 		/*
268993e3fafSRobert Mustacchi 		 * Per xHCI 1.1 / 6.2.3.4, burst is always zero for these
269993e3fafSRobert Mustacchi 		 * devices.
270993e3fafSRobert Mustacchi 		 */
271993e3fafSRobert Mustacchi 		return (0);
272993e3fafSRobert Mustacchi 	case USBA_HIGH_SPEED_DEV:
273993e3fafSRobert Mustacchi 		if (xep->xep_type == USB_EP_ATTR_CONTROL ||
274993e3fafSRobert Mustacchi 		    xep->xep_type == USB_EP_ATTR_BULK)
275993e3fafSRobert Mustacchi 			return (0);
276993e3fafSRobert Mustacchi 		return ((xep->xep_pipe->p_xep.uex_ep.wMaxPacketSize &
277993e3fafSRobert Mustacchi 		    XHCI_CONTEXT_BURST_MASK) >> XHCI_CONTEXT_BURST_SHIFT);
278993e3fafSRobert Mustacchi 	default:
279993e3fafSRobert Mustacchi 		/*
280993e3fafSRobert Mustacchi 		 * For these USB >= 3.0, this comes from the companion
281993e3fafSRobert Mustacchi 		 * descriptor.
282993e3fafSRobert Mustacchi 		 */
283993e3fafSRobert Mustacchi 		ASSERT(xep->xep_pipe->p_xep.uex_flags & USB_EP_XFLAGS_SS_COMP);
284993e3fafSRobert Mustacchi 		return (xep->xep_pipe->p_xep.uex_ep_ss.bMaxBurst);
285993e3fafSRobert Mustacchi 	}
286993e3fafSRobert Mustacchi }
287993e3fafSRobert Mustacchi 
288993e3fafSRobert Mustacchi /*
289993e3fafSRobert Mustacchi  * Convert a linear mapping of values that are in in the range of 1-255 into a
290993e3fafSRobert Mustacchi  * 2^x value. Because we're supposed to round down for these calculations (see
291993e3fafSRobert Mustacchi  * the note in xHCI 1.1 / 6.2.3.6) we can do this simply with a fls() and
292993e3fafSRobert Mustacchi  * subtracting one.
293993e3fafSRobert Mustacchi  */
294993e3fafSRobert Mustacchi static uint_t
xhci_endpoint_linear_interval(usb_ep_descr_t * ep)295993e3fafSRobert Mustacchi xhci_endpoint_linear_interval(usb_ep_descr_t *ep)
296993e3fafSRobert Mustacchi {
297993e3fafSRobert Mustacchi 	int exp;
298993e3fafSRobert Mustacchi 	int ival = ep->bInterval;
299993e3fafSRobert Mustacchi 	if (ival < 1)
300993e3fafSRobert Mustacchi 		ival = 1;
301993e3fafSRobert Mustacchi 	if (ival > 255)
302993e3fafSRobert Mustacchi 		ival = 255;
303993e3fafSRobert Mustacchi 	exp = ddi_fls(ival) - 1;
304993e3fafSRobert Mustacchi 	ASSERT(exp >= 0 && exp <= 7);
305993e3fafSRobert Mustacchi 	return (exp);
306993e3fafSRobert Mustacchi }
307993e3fafSRobert Mustacchi 
308993e3fafSRobert Mustacchi /*
309993e3fafSRobert Mustacchi  * Convert the set of values that use a 2^(x-1) value for interval into a 2^x
310993e3fafSRobert Mustacchi  * range. Note the valid input range is 1-16, so we clamp values based on this.
311993e3fafSRobert Mustacchi  * See xHCI 1.1 / 6.2.3.6 for more information.
312993e3fafSRobert Mustacchi  */
313993e3fafSRobert Mustacchi static uint_t
xhci_endpoint_exponential_interval(usb_ep_descr_t * ep)314993e3fafSRobert Mustacchi xhci_endpoint_exponential_interval(usb_ep_descr_t *ep)
315993e3fafSRobert Mustacchi {
316993e3fafSRobert Mustacchi 	int ival;
317993e3fafSRobert Mustacchi 
318993e3fafSRobert Mustacchi 	ival = ep->bInterval;
319993e3fafSRobert Mustacchi 	if (ival < 1)
320993e3fafSRobert Mustacchi 		ival = 1;
321993e3fafSRobert Mustacchi 	if (ival > 16)
322993e3fafSRobert Mustacchi 		ival = 16;
323993e3fafSRobert Mustacchi 	ival--;
324993e3fafSRobert Mustacchi 	ASSERT(ival >= 0 && ival <= 15);
325993e3fafSRobert Mustacchi 	return (ival);
326993e3fafSRobert Mustacchi }
327993e3fafSRobert Mustacchi 
328993e3fafSRobert Mustacchi 
329993e3fafSRobert Mustacchi /*
330993e3fafSRobert Mustacchi  * Determining the interval is unfortunately somewhat complicated as there are
331993e3fafSRobert Mustacchi  * many differnet forms that things can take. This is all summarized in a
332993e3fafSRobert Mustacchi  * somewhat helpful table, number 65, in xHCI 1.1 / 6.2.3.6. But here's
333993e3fafSRobert Mustacchi  * basically the six different cases we have to consider:
334993e3fafSRobert Mustacchi  *
335993e3fafSRobert Mustacchi  * Case 1: Non-High Speed Bulk and Control Endpoints
3362aba3acdSRobert Mustacchi  *	Always return 0.
337993e3fafSRobert Mustacchi  *
338993e3fafSRobert Mustacchi  * Case 2: Super Speed and High Speed Isoch and Intr endpoints
3392aba3acdSRobert Mustacchi  *	Convert from a 2^(x-1) range to a 2^x range.
340993e3fafSRobert Mustacchi  *
341993e3fafSRobert Mustacchi  * Case 3: Full Speed Isochronous Endpoints
3422aba3acdSRobert Mustacchi  *	As case 2, but add 3 as its values are in frames and we need to convert
3432aba3acdSRobert Mustacchi  *	to microframes. Adding three to the result is the same as multiplying
3442aba3acdSRobert Mustacchi  *	the initial value by 8.
345993e3fafSRobert Mustacchi  *
346993e3fafSRobert Mustacchi  * Case 4: Full speed and Low Speed Interrupt Endpoints
3472aba3acdSRobert Mustacchi  *	These have a 1-255 ms range that we need to convert to a 2^x * 128 us
3482aba3acdSRobert Mustacchi  *	range. We use the linear conversion and then add 3 to account for the
3492aba3acdSRobert Mustacchi  *	multiplying by 8 conversion from frames to microframes.
350993e3fafSRobert Mustacchi  *
351993e3fafSRobert Mustacchi  * Case 5: High Speed Interrupt and Bulk Output
3522aba3acdSRobert Mustacchi  *	These are a bit of a weird case. The spec and other implementations make
3532aba3acdSRobert Mustacchi  *	it seem that it's similar to case 4, but without the fixed addition as
3542aba3acdSRobert Mustacchi  *	its interpreted differently due to NAKs.
355993e3fafSRobert Mustacchi  *
356993e3fafSRobert Mustacchi  * Case 6: Low Speed Isochronous Endpoints
3572aba3acdSRobert Mustacchi  *	These are not actually defined; however, like other implementations we
3582aba3acdSRobert Mustacchi  *	treat them like case 4.
359993e3fafSRobert Mustacchi  */
360993e3fafSRobert Mustacchi static uint_t
xhci_endpoint_interval(xhci_device_t * xd,usb_ep_descr_t * ep)361993e3fafSRobert Mustacchi xhci_endpoint_interval(xhci_device_t *xd, usb_ep_descr_t *ep)
362993e3fafSRobert Mustacchi {
363993e3fafSRobert Mustacchi 	int type = ep->bmAttributes & USB_EP_ATTR_MASK;
364993e3fafSRobert Mustacchi 	int speed = xd->xd_usbdev->usb_port_status;
365993e3fafSRobert Mustacchi 
366993e3fafSRobert Mustacchi 	/*
367993e3fafSRobert Mustacchi 	 * Handle Cases 1 and 5 first.
368993e3fafSRobert Mustacchi 	 */
369993e3fafSRobert Mustacchi 	if (type == USB_EP_ATTR_CONTROL || type == USB_EP_ATTR_BULK) {
370993e3fafSRobert Mustacchi 		if (speed != USBA_HIGH_SPEED_DEV)
371993e3fafSRobert Mustacchi 			return (0);
372993e3fafSRobert Mustacchi 		return (xhci_endpoint_linear_interval(ep));
373993e3fafSRobert Mustacchi 	}
374993e3fafSRobert Mustacchi 
375993e3fafSRobert Mustacchi 	/*
376993e3fafSRobert Mustacchi 	 * Handle Isoch and Intr cases next.
377993e3fafSRobert Mustacchi 	 */
378993e3fafSRobert Mustacchi 	switch (speed) {
379993e3fafSRobert Mustacchi 	case USBA_LOW_SPEED_DEV:
380993e3fafSRobert Mustacchi 		/*
381993e3fafSRobert Mustacchi 		 * Interrupt endpoints at low speed are the same as full speed,
382993e3fafSRobert Mustacchi 		 * hence the fall through.
383993e3fafSRobert Mustacchi 		 */
384993e3fafSRobert Mustacchi 		if (type == USB_EP_ATTR_ISOCH) {
385993e3fafSRobert Mustacchi 			return (xhci_endpoint_exponential_interval(ep) + 3);
386993e3fafSRobert Mustacchi 		}
387993e3fafSRobert Mustacchi 		/* FALLTHROUGH */
388993e3fafSRobert Mustacchi 	case USBA_FULL_SPEED_DEV:
389993e3fafSRobert Mustacchi 		return (xhci_endpoint_linear_interval(ep) + 3);
390993e3fafSRobert Mustacchi 	case USBA_HIGH_SPEED_DEV:
391993e3fafSRobert Mustacchi 	case USBA_SUPER_SPEED_DEV:
392993e3fafSRobert Mustacchi 	default:
393993e3fafSRobert Mustacchi 		/*
394993e3fafSRobert Mustacchi 		 * Case 2. Treat any newer and faster speeds as Super Speed by
395993e3fafSRobert Mustacchi 		 * default as USB 3.1 is effectively treated the same here.
396993e3fafSRobert Mustacchi 		 */
397993e3fafSRobert Mustacchi 		return (xhci_endpoint_exponential_interval(ep));
398993e3fafSRobert Mustacchi 	}
399993e3fafSRobert Mustacchi }
400993e3fafSRobert Mustacchi 
401993e3fafSRobert Mustacchi /*
402993e3fafSRobert Mustacchi  * The way to calculate the Maximum ESIT is described in xHCI 1.1 / 4.14.2.
403993e3fafSRobert Mustacchi  * First off, this only applies to Interrupt and Isochronous descriptors. For
404993e3fafSRobert Mustacchi  * Super Speed and newer things, it comes out of a descriptor. Otherwise we
405993e3fafSRobert Mustacchi  * calculate it by doing 'Max Packet Size' * ('Max Burst' + 1).
406993e3fafSRobert Mustacchi  */
407993e3fafSRobert Mustacchi static uint_t
xhci_endpoint_max_esit(xhci_device_t * xd,xhci_endpoint_t * xep,uint_t mps,uint_t burst)408993e3fafSRobert Mustacchi xhci_endpoint_max_esit(xhci_device_t *xd, xhci_endpoint_t *xep, uint_t mps,
409993e3fafSRobert Mustacchi     uint_t burst)
410993e3fafSRobert Mustacchi {
411993e3fafSRobert Mustacchi 	if (xep->xep_type == USB_EP_ATTR_CONTROL ||
412993e3fafSRobert Mustacchi 	    xep->xep_type == USB_EP_ATTR_BULK) {
413993e3fafSRobert Mustacchi 		return (0);
414993e3fafSRobert Mustacchi 	}
415993e3fafSRobert Mustacchi 
416993e3fafSRobert Mustacchi 	/*
417993e3fafSRobert Mustacchi 	 * Note that this will need to be updated for SuperSpeedPlus ISOC
418993e3fafSRobert Mustacchi 	 * devices to pull from the secondary companion descriptor they use.
419993e3fafSRobert Mustacchi 	 */
420993e3fafSRobert Mustacchi 	if (xd->xd_usbdev->usb_port_status >= USBA_SUPER_SPEED_DEV) {
421993e3fafSRobert Mustacchi 		usb_ep_xdescr_t *ep_xdesc = &xep->xep_pipe->p_xep;
422993e3fafSRobert Mustacchi 		ASSERT(xep->xep_pipe->p_xep.uex_flags & USB_EP_XFLAGS_SS_COMP);
423993e3fafSRobert Mustacchi 		return (ep_xdesc->uex_ep_ss.wBytesPerInterval);
424993e3fafSRobert Mustacchi 	}
425993e3fafSRobert Mustacchi 
426993e3fafSRobert Mustacchi 	return (mps * (burst + 1));
427993e3fafSRobert Mustacchi }
428993e3fafSRobert Mustacchi 
429993e3fafSRobert Mustacchi /*
430993e3fafSRobert Mustacchi  * We've been asked to calculate and tell the xHCI controller an average TRB
431993e3fafSRobert Mustacchi  * data length. This is talked about in an implementation note in xHCI 1.1 /
432993e3fafSRobert Mustacchi  * 4.14.1.1. So, the reality is that it's hard to actually calculate this, as
433993e3fafSRobert Mustacchi  * we're supposed to take into account all of the TRBs that we use on that ring.
434993e3fafSRobert Mustacchi  *
435993e3fafSRobert Mustacchi  * Surveying other xHCI drivers, they all agree on using the default of 8 for
436993e3fafSRobert Mustacchi  * control endpoints; however, from there things get a little more fluid. For
437993e3fafSRobert Mustacchi  * interrupt and isochronous endpoints, many device use the minimum of the max
438993e3fafSRobert Mustacchi  * packet size and the device's pagesize. For bulk endpoints some folks punt and
439993e3fafSRobert Mustacchi  * don't set anything and others try and set it to the pagesize. The xHCI
440993e3fafSRobert Mustacchi  * implementation note suggests a 3k size here initially. For now, we'll just
441993e3fafSRobert Mustacchi  * guess for bulk endpoints and use our page size as a determining factor for
442993e3fafSRobert Mustacchi  * this and use the BSD style for others. Note Linux here only sets this value
443993e3fafSRobert Mustacchi  * for control devices.
444993e3fafSRobert Mustacchi  */
445993e3fafSRobert Mustacchi static uint_t
xhci_endpoint_avg_trb(xhci_t * xhcip,usb_ep_descr_t * ep,int mps)446993e3fafSRobert Mustacchi xhci_endpoint_avg_trb(xhci_t *xhcip, usb_ep_descr_t *ep, int mps)
447993e3fafSRobert Mustacchi {
448993e3fafSRobert Mustacchi 	int type = ep->bmAttributes & USB_EP_ATTR_MASK;
449993e3fafSRobert Mustacchi 
450993e3fafSRobert Mustacchi 	switch (type) {
451993e3fafSRobert Mustacchi 	case USB_EP_ATTR_ISOCH:
452993e3fafSRobert Mustacchi 	case USB_EP_ATTR_INTR:
453993e3fafSRobert Mustacchi 		return (MIN(xhcip->xhci_caps.xcap_pagesize, mps));
454993e3fafSRobert Mustacchi 	case USB_EP_ATTR_CONTROL:
455993e3fafSRobert Mustacchi 		return (XHCI_CONTEXT_DEF_CTRL_ATL);
456993e3fafSRobert Mustacchi 	case USB_EP_ATTR_BULK:
457993e3fafSRobert Mustacchi 		return (xhcip->xhci_caps.xcap_pagesize);
458993e3fafSRobert Mustacchi 	default:
459993e3fafSRobert Mustacchi 		panic("bad USB endpoint type: %d", type);
460993e3fafSRobert Mustacchi 	}
461993e3fafSRobert Mustacchi 
462993e3fafSRobert Mustacchi 	/* LINTED: E_FUNC_NO_RET_VAL */
463993e3fafSRobert Mustacchi }
464993e3fafSRobert Mustacchi 
465*0ae0ab6fSJoshua M. Clulow /*
466*0ae0ab6fSJoshua M. Clulow  * Set up the input context for this endpoint.  If this endpoint is already
467*0ae0ab6fSJoshua M. Clulow  * open, just confirm that the current parameters and the originally programmed
468*0ae0ab6fSJoshua M. Clulow  * parameters match.
469*0ae0ab6fSJoshua M. Clulow  */
470993e3fafSRobert Mustacchi int
xhci_endpoint_setup_context(xhci_t * xhcip,xhci_device_t * xd,xhci_endpoint_t * xep)471993e3fafSRobert Mustacchi xhci_endpoint_setup_context(xhci_t *xhcip, xhci_device_t *xd,
472993e3fafSRobert Mustacchi     xhci_endpoint_t *xep)
473993e3fafSRobert Mustacchi {
474*0ae0ab6fSJoshua M. Clulow 	xhci_endpoint_params_t new_xepp;
475993e3fafSRobert Mustacchi 	xhci_endpoint_context_t *ectx;
476993e3fafSRobert Mustacchi 	uint64_t deq;
477993e3fafSRobert Mustacchi 
478*0ae0ab6fSJoshua M. Clulow 	/*
479*0ae0ab6fSJoshua M. Clulow 	 * Explicitly zero this entire struct to start so that we can compare
480*0ae0ab6fSJoshua M. Clulow 	 * it with bcmp().
481*0ae0ab6fSJoshua M. Clulow 	 */
482*0ae0ab6fSJoshua M. Clulow 	bzero(&new_xepp, sizeof (new_xepp));
483*0ae0ab6fSJoshua M. Clulow 	new_xepp.xepp_configured = B_TRUE;
484*0ae0ab6fSJoshua M. Clulow 
485993e3fafSRobert Mustacchi 	/*
486993e3fafSRobert Mustacchi 	 * For a USB >=3.0 device we should always have its companion descriptor
487993e3fafSRobert Mustacchi 	 * provided for us by USBA. If it's not here, complain loudly and fail.
488993e3fafSRobert Mustacchi 	 */
489993e3fafSRobert Mustacchi 	if (xd->xd_usbdev->usb_port_status >= USBA_SUPER_SPEED_DEV &&
490993e3fafSRobert Mustacchi 	    (xep->xep_pipe->p_xep.uex_flags & USB_EP_XFLAGS_SS_COMP) == 0) {
491993e3fafSRobert Mustacchi 		const char *prod, *mfg;
492993e3fafSRobert Mustacchi 
493993e3fafSRobert Mustacchi 		prod = xd->xd_usbdev->usb_product_str;
494993e3fafSRobert Mustacchi 		if (prod == NULL)
495993e3fafSRobert Mustacchi 			prod = "Unknown Device";
496993e3fafSRobert Mustacchi 		mfg = xd->xd_usbdev->usb_mfg_str;
497993e3fafSRobert Mustacchi 		if (mfg == NULL)
498993e3fafSRobert Mustacchi 			mfg = "Unknown Manufacturer";
499993e3fafSRobert Mustacchi 
500993e3fafSRobert Mustacchi 		xhci_log(xhcip, "Encountered USB >=3.0 device without endpoint "
501993e3fafSRobert Mustacchi 		    "companion descriptor. Ensure driver %s is properly using "
502993e3fafSRobert Mustacchi 		    "usb_pipe_xopen() for device %s %s",
503993e3fafSRobert Mustacchi 		    ddi_driver_name(xd->xd_usbdev->usb_dip), prod, mfg);
504993e3fafSRobert Mustacchi 		return (EINVAL);
505993e3fafSRobert Mustacchi 	}
506993e3fafSRobert Mustacchi 
507993e3fafSRobert Mustacchi 	ectx = xd->xd_endin[xep->xep_num];
508993e3fafSRobert Mustacchi 	VERIFY(ectx != NULL);
509993e3fafSRobert Mustacchi 	VERIFY(xd->xd_usbdev->usb_dev_descr != NULL);
510993e3fafSRobert Mustacchi 	VERIFY(xep->xep_pipe != NULL);
511993e3fafSRobert Mustacchi 
512*0ae0ab6fSJoshua M. Clulow 	new_xepp.xepp_mps =
513*0ae0ab6fSJoshua M. Clulow 	    xep->xep_pipe->p_ep.wMaxPacketSize & XHCI_CONTEXT_MPS_MASK;
514*0ae0ab6fSJoshua M. Clulow 	new_xepp.xepp_mult = XHCI_CONTEXT_DEF_MULT;
515*0ae0ab6fSJoshua M. Clulow 	new_xepp.xepp_cerr = XHCI_CONTEXT_DEF_CERR;
516993e3fafSRobert Mustacchi 
517993e3fafSRobert Mustacchi 	switch (xep->xep_type) {
518993e3fafSRobert Mustacchi 	case USB_EP_ATTR_ISOCH:
519993e3fafSRobert Mustacchi 		/*
520993e3fafSRobert Mustacchi 		 * When we have support for USB 3.1 SuperSpeedPlus devices,
521993e3fafSRobert Mustacchi 		 * we'll need to make sure that we also check for its secondary
522993e3fafSRobert Mustacchi 		 * endpoint companion descriptor here.
523993e3fafSRobert Mustacchi 		 */
524993e3fafSRobert Mustacchi 		/*
525993e3fafSRobert Mustacchi 		 * Super Speed devices nominally have these xHCI super speed
526993e3fafSRobert Mustacchi 		 * companion descriptors. We know that we're not properly
527993e3fafSRobert Mustacchi 		 * grabbing them right now, so until we do, we should basically
528993e3fafSRobert Mustacchi 		 * error about it.
529993e3fafSRobert Mustacchi 		 */
530993e3fafSRobert Mustacchi 		if (xd->xd_usbdev->usb_port_status >= USBA_SUPER_SPEED_DEV) {
531993e3fafSRobert Mustacchi 			ASSERT(xep->xep_pipe->p_xep.uex_flags &
532993e3fafSRobert Mustacchi 			    USB_EP_XFLAGS_SS_COMP);
533*0ae0ab6fSJoshua M. Clulow 			new_xepp.xepp_mult =
534*0ae0ab6fSJoshua M. Clulow 			    xep->xep_pipe->p_xep.uex_ep_ss.bmAttributes &
535993e3fafSRobert Mustacchi 			    USB_EP_SS_COMP_ISOC_MULT_MASK;
536993e3fafSRobert Mustacchi 		}
537993e3fafSRobert Mustacchi 
538*0ae0ab6fSJoshua M. Clulow 		new_xepp.xepp_mps &= XHCI_CONTEXT_MPS_MASK;
539*0ae0ab6fSJoshua M. Clulow 		new_xepp.xepp_cerr = XHCI_CONTEXT_ISOCH_CERR;
540993e3fafSRobert Mustacchi 		break;
541993e3fafSRobert Mustacchi 	default:
542993e3fafSRobert Mustacchi 		/*
543993e3fafSRobert Mustacchi 		 * No explicit changes needed for CONTROL, INTR, and BULK
544993e3fafSRobert Mustacchi 		 * endpoints. They've been handled already and don't have any
545993e3fafSRobert Mustacchi 		 * differences.
546993e3fafSRobert Mustacchi 		 */
547993e3fafSRobert Mustacchi 		break;
548993e3fafSRobert Mustacchi 	}
549993e3fafSRobert Mustacchi 
550*0ae0ab6fSJoshua M. Clulow 	new_xepp.xepp_eptype = xhci_endpoint_epdesc_to_type(
551*0ae0ab6fSJoshua M. Clulow 	    &xep->xep_pipe->p_xep.uex_ep);
552*0ae0ab6fSJoshua M. Clulow 	new_xepp.xepp_burst = xhci_endpoint_determine_burst(xd, xep);
553*0ae0ab6fSJoshua M. Clulow 	new_xepp.xepp_ival = xhci_endpoint_interval(xd,
554*0ae0ab6fSJoshua M. Clulow 	    &xep->xep_pipe->p_xep.uex_ep);
555*0ae0ab6fSJoshua M. Clulow 	new_xepp.xepp_max_esit = xhci_endpoint_max_esit(xd, xep,
556*0ae0ab6fSJoshua M. Clulow 	    new_xepp.xepp_mps, new_xepp.xepp_burst);
557*0ae0ab6fSJoshua M. Clulow 	new_xepp.xepp_avgtrb = xhci_endpoint_avg_trb(xhcip,
558*0ae0ab6fSJoshua M. Clulow 	    &xep->xep_pipe->p_xep.uex_ep, new_xepp.xepp_mps);
559993e3fafSRobert Mustacchi 
560993e3fafSRobert Mustacchi 	/*
561993e3fafSRobert Mustacchi 	 * The multi field may be reserved as zero if the LEC feature flag is
562993e3fafSRobert Mustacchi 	 * set. See the description of mult in xHCI 1.1 / 6.2.3.
563993e3fafSRobert Mustacchi 	 */
564993e3fafSRobert Mustacchi 	if (xhcip->xhci_caps.xcap_flags2 & XCAP2_LEC)
565*0ae0ab6fSJoshua M. Clulow 		new_xepp.xepp_mult = 0;
566*0ae0ab6fSJoshua M. Clulow 
567*0ae0ab6fSJoshua M. Clulow 	if (xep->xep_params.xepp_configured) {
568*0ae0ab6fSJoshua M. Clulow 		/*
569*0ae0ab6fSJoshua M. Clulow 		 * The endpoint context has been configured already.  We are
570*0ae0ab6fSJoshua M. Clulow 		 * reopening the pipe, so just confirm that the parameters are
571*0ae0ab6fSJoshua M. Clulow 		 * the same.
572*0ae0ab6fSJoshua M. Clulow 		 */
573*0ae0ab6fSJoshua M. Clulow 		if (bcmp(&xep->xep_params, &new_xepp, sizeof (new_xepp)) == 0) {
574*0ae0ab6fSJoshua M. Clulow 			/*
575*0ae0ab6fSJoshua M. Clulow 			 * Everything matches up.
576*0ae0ab6fSJoshua M. Clulow 			 */
577*0ae0ab6fSJoshua M. Clulow 			return (0);
578*0ae0ab6fSJoshua M. Clulow 		}
579*0ae0ab6fSJoshua M. Clulow 
580*0ae0ab6fSJoshua M. Clulow 		DTRACE_PROBE3(xhci__context__mismatch,
581*0ae0ab6fSJoshua M. Clulow 		    xhci_t *, xhcip,
582*0ae0ab6fSJoshua M. Clulow 		    xhci_endpoint_t *, xep,
583*0ae0ab6fSJoshua M. Clulow 		    xhci_endpoint_params_t *, &new_xepp);
584*0ae0ab6fSJoshua M. Clulow 
585*0ae0ab6fSJoshua M. Clulow 		xhci_error(xhcip, "device input context on slot %d and "
586*0ae0ab6fSJoshua M. Clulow 		    "port %d for endpoint %u was already initialized but "
587*0ae0ab6fSJoshua M. Clulow 		    "with incompatible parameters",
588*0ae0ab6fSJoshua M. Clulow 		    xd->xd_slot, xd->xd_port, xep->xep_num);
589*0ae0ab6fSJoshua M. Clulow 		return (EINVAL);
590*0ae0ab6fSJoshua M. Clulow 	}
591993e3fafSRobert Mustacchi 
592993e3fafSRobert Mustacchi 	bzero(ectx, sizeof (xhci_endpoint_context_t));
593993e3fafSRobert Mustacchi 
594*0ae0ab6fSJoshua M. Clulow 	ectx->xec_info = LE_32(XHCI_EPCTX_SET_MULT(new_xepp.xepp_mult) |
595*0ae0ab6fSJoshua M. Clulow 	    XHCI_EPCTX_SET_IVAL(new_xepp.xepp_ival));
596*0ae0ab6fSJoshua M. Clulow 	if (xhcip->xhci_caps.xcap_flags2 & XCAP2_LEC) {
597*0ae0ab6fSJoshua M. Clulow 		ectx->xec_info |=
598*0ae0ab6fSJoshua M. Clulow 		    LE_32(XHCI_EPCTX_SET_MAX_ESIT_HI(new_xepp.xepp_max_esit));
599*0ae0ab6fSJoshua M. Clulow 	}
600993e3fafSRobert Mustacchi 
601*0ae0ab6fSJoshua M. Clulow 	ectx->xec_info2 = LE_32(XHCI_EPCTX_SET_CERR(new_xepp.xepp_cerr) |
602*0ae0ab6fSJoshua M. Clulow 	    XHCI_EPCTX_SET_EPTYPE(new_xepp.xepp_eptype) |
603*0ae0ab6fSJoshua M. Clulow 	    XHCI_EPCTX_SET_MAXB(new_xepp.xepp_burst) |
604*0ae0ab6fSJoshua M. Clulow 	    XHCI_EPCTX_SET_MPS(new_xepp.xepp_mps));
605993e3fafSRobert Mustacchi 
606993e3fafSRobert Mustacchi 	deq = xhci_dma_pa(&xep->xep_ring.xr_dma) + sizeof (xhci_trb_t) *
607993e3fafSRobert Mustacchi 	    xep->xep_ring.xr_tail;
608993e3fafSRobert Mustacchi 	ectx->xec_dequeue = LE_64(deq | xep->xep_ring.xr_cycle);
609993e3fafSRobert Mustacchi 
610*0ae0ab6fSJoshua M. Clulow 	ectx->xec_txinfo = LE_32(
611*0ae0ab6fSJoshua M. Clulow 	    XHCI_EPCTX_MAX_ESIT_PAYLOAD(new_xepp.xepp_max_esit) |
612*0ae0ab6fSJoshua M. Clulow 	    XHCI_EPCTX_AVG_TRB_LEN(new_xepp.xepp_avgtrb));
613993e3fafSRobert Mustacchi 
614993e3fafSRobert Mustacchi 	XHCI_DMA_SYNC(xd->xd_ictx, DDI_DMA_SYNC_FORDEV);
615993e3fafSRobert Mustacchi 	if (xhci_check_dma_handle(xhcip, &xd->xd_ictx) != DDI_FM_OK) {
616993e3fafSRobert Mustacchi 		xhci_error(xhcip, "failed to initialize device input "
617993e3fafSRobert Mustacchi 		    "context on slot %d and port %d for endpoint %u:  "
618993e3fafSRobert Mustacchi 		    "encountered fatal FM error synchronizing input context "
619993e3fafSRobert Mustacchi 		    "DMA memory", xd->xd_slot, xd->xd_port, xep->xep_num);
620993e3fafSRobert Mustacchi 		xhci_fm_runtime_reset(xhcip);
621993e3fafSRobert Mustacchi 		return (EIO);
622993e3fafSRobert Mustacchi 	}
623993e3fafSRobert Mustacchi 
624*0ae0ab6fSJoshua M. Clulow 	bcopy(&new_xepp, &xep->xep_params, sizeof (new_xepp));
625*0ae0ab6fSJoshua M. Clulow 	VERIFY(xep->xep_params.xepp_configured);
626993e3fafSRobert Mustacchi 	return (0);
627993e3fafSRobert Mustacchi }
628993e3fafSRobert Mustacchi 
629993e3fafSRobert Mustacchi /*
630993e3fafSRobert Mustacchi  * Initialize the endpoint and its input context for a given device. This is
631993e3fafSRobert Mustacchi  * called from two different contexts:
632993e3fafSRobert Mustacchi  *
633993e3fafSRobert Mustacchi  *   1. Initializing a device
634993e3fafSRobert Mustacchi  *   2. Opening a USB pipe
635993e3fafSRobert Mustacchi  *
636993e3fafSRobert Mustacchi  * In the second case, we need to worry about locking around the device. We
637993e3fafSRobert Mustacchi  * don't need to worry about the locking in the first case because the USBA
638993e3fafSRobert Mustacchi  * doesn't know about it yet.
639993e3fafSRobert Mustacchi  */
640993e3fafSRobert Mustacchi int
xhci_endpoint_init(xhci_t * xhcip,xhci_device_t * xd,usba_pipe_handle_data_t * ph)641993e3fafSRobert Mustacchi xhci_endpoint_init(xhci_t *xhcip, xhci_device_t *xd,
642993e3fafSRobert Mustacchi     usba_pipe_handle_data_t *ph)
643993e3fafSRobert Mustacchi {
644993e3fafSRobert Mustacchi 	int ret;
645993e3fafSRobert Mustacchi 	uint_t epid;
646993e3fafSRobert Mustacchi 	xhci_endpoint_t *xep;
647993e3fafSRobert Mustacchi 
648993e3fafSRobert Mustacchi 	if (ph == NULL) {
649993e3fafSRobert Mustacchi 		epid = XHCI_DEFAULT_ENDPOINT;
650993e3fafSRobert Mustacchi 	} else {
651993e3fafSRobert Mustacchi 		ASSERT(MUTEX_HELD(&xhcip->xhci_lock));
652993e3fafSRobert Mustacchi 		epid = xhci_endpoint_pipe_to_epid(ph);
653993e3fafSRobert Mustacchi 	}
654993e3fafSRobert Mustacchi 	VERIFY(xd->xd_endpoints[epid] == NULL);
655993e3fafSRobert Mustacchi 
656993e3fafSRobert Mustacchi 	xep = kmem_zalloc(sizeof (xhci_endpoint_t), KM_SLEEP);
657993e3fafSRobert Mustacchi 	list_create(&xep->xep_transfers, sizeof (xhci_transfer_t),
658993e3fafSRobert Mustacchi 	    offsetof(xhci_transfer_t, xt_link));
659993e3fafSRobert Mustacchi 	cv_init(&xep->xep_state_cv, NULL, CV_DRIVER, NULL);
660993e3fafSRobert Mustacchi 	xep->xep_xd = xd;
661993e3fafSRobert Mustacchi 	xep->xep_xhci = xhcip;
662993e3fafSRobert Mustacchi 	xep->xep_num = epid;
663993e3fafSRobert Mustacchi 	if (ph == NULL) {
664993e3fafSRobert Mustacchi 		xep->xep_pipe = NULL;
665993e3fafSRobert Mustacchi 		xep->xep_type = USB_EP_ATTR_CONTROL;
666993e3fafSRobert Mustacchi 	} else {
667993e3fafSRobert Mustacchi 		xep->xep_pipe = ph;
668993e3fafSRobert Mustacchi 		xep->xep_type = ph->p_ep.bmAttributes & USB_EP_ATTR_MASK;
669993e3fafSRobert Mustacchi 	}
670993e3fafSRobert Mustacchi 
671993e3fafSRobert Mustacchi 	if ((ret = xhci_ring_alloc(xhcip, &xep->xep_ring)) != 0) {
672993e3fafSRobert Mustacchi 		cv_destroy(&xep->xep_state_cv);
673993e3fafSRobert Mustacchi 		list_destroy(&xep->xep_transfers);
674993e3fafSRobert Mustacchi 		kmem_free(xep, sizeof (xhci_endpoint_t));
675993e3fafSRobert Mustacchi 		return (ret);
676993e3fafSRobert Mustacchi 	}
677993e3fafSRobert Mustacchi 
678993e3fafSRobert Mustacchi 	if ((ret = xhci_ring_reset(xhcip, &xep->xep_ring)) != 0) {
679993e3fafSRobert Mustacchi 		xhci_ring_free(&xep->xep_ring);
680993e3fafSRobert Mustacchi 		cv_destroy(&xep->xep_state_cv);
681993e3fafSRobert Mustacchi 		list_destroy(&xep->xep_transfers);
682993e3fafSRobert Mustacchi 		kmem_free(xep, sizeof (xhci_endpoint_t));
683993e3fafSRobert Mustacchi 		return (ret);
684993e3fafSRobert Mustacchi 	}
685993e3fafSRobert Mustacchi 
686993e3fafSRobert Mustacchi 	xd->xd_endpoints[epid] = xep;
687993e3fafSRobert Mustacchi 	if (ph == NULL) {
688993e3fafSRobert Mustacchi 		ret = xhci_endpoint_setup_default_context(xhcip, xd, xep);
689993e3fafSRobert Mustacchi 	} else {
690993e3fafSRobert Mustacchi 		ret = xhci_endpoint_setup_context(xhcip, xd, xep);
691993e3fafSRobert Mustacchi 	}
692993e3fafSRobert Mustacchi 	if (ret != 0) {
693993e3fafSRobert Mustacchi 		xhci_endpoint_fini(xd, xep->xep_num);
694993e3fafSRobert Mustacchi 		return (ret);
695993e3fafSRobert Mustacchi 	}
696993e3fafSRobert Mustacchi 
697*0ae0ab6fSJoshua M. Clulow 	xep->xep_state |= XHCI_ENDPOINT_OPEN;
698993e3fafSRobert Mustacchi 	return (0);
699993e3fafSRobert Mustacchi }
700993e3fafSRobert Mustacchi 
701*0ae0ab6fSJoshua M. Clulow int
xhci_endpoint_reinit(xhci_t * xhcip,xhci_device_t * xd,xhci_endpoint_t * xep,usba_pipe_handle_data_t * ph)702*0ae0ab6fSJoshua M. Clulow xhci_endpoint_reinit(xhci_t *xhcip, xhci_device_t *xd, xhci_endpoint_t *xep,
703*0ae0ab6fSJoshua M. Clulow     usba_pipe_handle_data_t *ph)
704*0ae0ab6fSJoshua M. Clulow {
705*0ae0ab6fSJoshua M. Clulow 	VERIFY(MUTEX_HELD(&xhcip->xhci_lock));
706*0ae0ab6fSJoshua M. Clulow 	VERIFY(ph != NULL);
707*0ae0ab6fSJoshua M. Clulow 	VERIFY3U(xhci_endpoint_pipe_to_epid(ph), ==, xep->xep_num);
708*0ae0ab6fSJoshua M. Clulow 	VERIFY3U(xep->xep_num, !=, XHCI_DEFAULT_ENDPOINT);
709*0ae0ab6fSJoshua M. Clulow 
710*0ae0ab6fSJoshua M. Clulow 	if (xep->xep_type != (ph->p_ep.bmAttributes & USB_EP_ATTR_MASK)) {
711*0ae0ab6fSJoshua M. Clulow 		/*
712*0ae0ab6fSJoshua M. Clulow 		 * The endpoint type should not change unless the device has
713*0ae0ab6fSJoshua M. Clulow 		 * been torn down and recreated by the framework.
714*0ae0ab6fSJoshua M. Clulow 		 */
715*0ae0ab6fSJoshua M. Clulow 		return (EINVAL);
716*0ae0ab6fSJoshua M. Clulow 	}
717*0ae0ab6fSJoshua M. Clulow 
718*0ae0ab6fSJoshua M. Clulow 	if (xep->xep_state & XHCI_ENDPOINT_OPEN) {
719*0ae0ab6fSJoshua M. Clulow 		return (EBUSY);
720*0ae0ab6fSJoshua M. Clulow 	}
721*0ae0ab6fSJoshua M. Clulow 
722*0ae0ab6fSJoshua M. Clulow 	VERIFY(xep->xep_state & XHCI_ENDPOINT_TEARDOWN);
723*0ae0ab6fSJoshua M. Clulow 	xep->xep_state &= ~XHCI_ENDPOINT_TEARDOWN;
724*0ae0ab6fSJoshua M. Clulow 
725*0ae0ab6fSJoshua M. Clulow 	VERIFY3U(xep->xep_timeout, ==, 0);
726*0ae0ab6fSJoshua M. Clulow 	VERIFY(list_is_empty(&xep->xep_transfers));
727*0ae0ab6fSJoshua M. Clulow 
728*0ae0ab6fSJoshua M. Clulow 	VERIFY3P(xep->xep_pipe, ==, NULL);
729*0ae0ab6fSJoshua M. Clulow 	xep->xep_pipe = ph;
730*0ae0ab6fSJoshua M. Clulow 
731*0ae0ab6fSJoshua M. Clulow 	/*
732*0ae0ab6fSJoshua M. Clulow 	 * Verify that the endpoint context parameters have not changed in a
733*0ae0ab6fSJoshua M. Clulow 	 * way that requires us to tell the controller about it.
734*0ae0ab6fSJoshua M. Clulow 	 */
735*0ae0ab6fSJoshua M. Clulow 	int ret;
736*0ae0ab6fSJoshua M. Clulow 	if ((ret = xhci_endpoint_setup_context(xhcip, xd, xep)) != 0) {
737*0ae0ab6fSJoshua M. Clulow 		xep->xep_pipe = NULL;
738*0ae0ab6fSJoshua M. Clulow 		xhci_endpoint_timeout_cancel(xhcip, xep);
739*0ae0ab6fSJoshua M. Clulow 		return (ret);
740*0ae0ab6fSJoshua M. Clulow 	}
741*0ae0ab6fSJoshua M. Clulow 
742*0ae0ab6fSJoshua M. Clulow 	xep->xep_state |= XHCI_ENDPOINT_OPEN;
743*0ae0ab6fSJoshua M. Clulow 	return (0);
744*0ae0ab6fSJoshua M. Clulow }
745*0ae0ab6fSJoshua M. Clulow 
746*0ae0ab6fSJoshua M. Clulow /*
747*0ae0ab6fSJoshua M. Clulow  * Wait until any ongoing resets or time outs are completed.
748*0ae0ab6fSJoshua M. Clulow  */
749*0ae0ab6fSJoshua M. Clulow void
xhci_endpoint_serialize(xhci_t * xhcip,xhci_endpoint_t * xep)750*0ae0ab6fSJoshua M. Clulow xhci_endpoint_serialize(xhci_t *xhcip, xhci_endpoint_t *xep)
751*0ae0ab6fSJoshua M. Clulow {
752*0ae0ab6fSJoshua M. Clulow 	VERIFY(MUTEX_HELD(&xhcip->xhci_lock));
753*0ae0ab6fSJoshua M. Clulow 
754*0ae0ab6fSJoshua M. Clulow 	while ((xep->xep_state & XHCI_ENDPOINT_SERIALIZE) != 0) {
755*0ae0ab6fSJoshua M. Clulow 		cv_wait(&xep->xep_state_cv, &xhcip->xhci_lock);
756*0ae0ab6fSJoshua M. Clulow 	}
757*0ae0ab6fSJoshua M. Clulow }
758*0ae0ab6fSJoshua M. Clulow 
759993e3fafSRobert Mustacchi /*
760993e3fafSRobert Mustacchi  * Attempt to quiesce an endpoint. Depending on the state of the endpoint, we
761993e3fafSRobert Mustacchi  * may need to simply stop it. Alternatively, we may need to explicitly reset
762993e3fafSRobert Mustacchi  * the endpoint. Once done, this endpoint should be stopped and can be
763993e3fafSRobert Mustacchi  * manipulated.
764993e3fafSRobert Mustacchi  */
765993e3fafSRobert Mustacchi int
xhci_endpoint_quiesce(xhci_t * xhcip,xhci_device_t * xd,xhci_endpoint_t * xep)766993e3fafSRobert Mustacchi xhci_endpoint_quiesce(xhci_t *xhcip, xhci_device_t *xd, xhci_endpoint_t *xep)
767993e3fafSRobert Mustacchi {
768993e3fafSRobert Mustacchi 	int ret = USB_SUCCESS;
769993e3fafSRobert Mustacchi 	xhci_endpoint_context_t *epctx = xd->xd_endout[xep->xep_num];
770993e3fafSRobert Mustacchi 
771993e3fafSRobert Mustacchi 	ASSERT(MUTEX_HELD(&xhcip->xhci_lock));
772993e3fafSRobert Mustacchi 	ASSERT(xep->xep_state & XHCI_ENDPOINT_QUIESCE);
773993e3fafSRobert Mustacchi 
774993e3fafSRobert Mustacchi 	/*
775993e3fafSRobert Mustacchi 	 * First attempt to stop the endpoint, unless it's halted. We don't
776993e3fafSRobert Mustacchi 	 * really care what state it is in. Note that because other activity
777993e3fafSRobert Mustacchi 	 * could be going on, the state may change on us; however, if it's
778993e3fafSRobert Mustacchi 	 * running, it will always transition to a stopped state and none of the
779993e3fafSRobert Mustacchi 	 * other valid states will allow transitions without us taking an active
780993e3fafSRobert Mustacchi 	 * action.
781993e3fafSRobert Mustacchi 	 */
782993e3fafSRobert Mustacchi 	if (!(xep->xep_state & XHCI_ENDPOINT_HALTED)) {
783993e3fafSRobert Mustacchi 		mutex_exit(&xhcip->xhci_lock);
784993e3fafSRobert Mustacchi 		ret = xhci_command_stop_endpoint(xhcip, xd, xep);
785993e3fafSRobert Mustacchi 		mutex_enter(&xhcip->xhci_lock);
786993e3fafSRobert Mustacchi 
787993e3fafSRobert Mustacchi 		if (ret == USB_INVALID_CONTEXT) {
788993e3fafSRobert Mustacchi 			XHCI_DMA_SYNC(xd->xd_octx, DDI_DMA_SYNC_FORKERNEL);
789993e3fafSRobert Mustacchi 		}
790993e3fafSRobert Mustacchi 	}
791993e3fafSRobert Mustacchi 
792993e3fafSRobert Mustacchi 	/*
793993e3fafSRobert Mustacchi 	 * Now, if we had the HALTED flag set or we failed to stop it due to a
794993e3fafSRobert Mustacchi 	 * context error and we're in the HALTED state now, reset the end point.
795993e3fafSRobert Mustacchi 	 */
796993e3fafSRobert Mustacchi 	if ((xep->xep_state & XHCI_ENDPOINT_HALTED) ||
797993e3fafSRobert Mustacchi 	    (ret == USB_INVALID_CONTEXT &&
798993e3fafSRobert Mustacchi 	    XHCI_EPCTX_STATE(LE_32(epctx->xec_info)) == XHCI_EP_HALTED)) {
799993e3fafSRobert Mustacchi 		mutex_exit(&xhcip->xhci_lock);
800993e3fafSRobert Mustacchi 		ret = xhci_command_reset_endpoint(xhcip, xd, xep);
801993e3fafSRobert Mustacchi 		mutex_enter(&xhcip->xhci_lock);
802993e3fafSRobert Mustacchi 	}
803993e3fafSRobert Mustacchi 
804993e3fafSRobert Mustacchi 	/*
805993e3fafSRobert Mustacchi 	 * Ideally, one of the two commands should have worked; however, we
806993e3fafSRobert Mustacchi 	 * could have had a context error due to being in the wrong state.
807993e3fafSRobert Mustacchi 	 * Verify that we're either in the ERROR or STOPPED state and treat both
808993e3fafSRobert Mustacchi 	 * as success. All callers are assumed to be doing this so they can
809993e3fafSRobert Mustacchi 	 * change the dequeue pointer.
810993e3fafSRobert Mustacchi 	 */
811993e3fafSRobert Mustacchi 	if (ret != USB_SUCCESS && ret != USB_INVALID_CONTEXT) {
812993e3fafSRobert Mustacchi 		return (ret);
813993e3fafSRobert Mustacchi 	}
814993e3fafSRobert Mustacchi 
815993e3fafSRobert Mustacchi 	if (ret == USB_INVALID_CONTEXT) {
816993e3fafSRobert Mustacchi 		XHCI_DMA_SYNC(xd->xd_octx, DDI_DMA_SYNC_FORKERNEL);
817993e3fafSRobert Mustacchi 
818993e3fafSRobert Mustacchi 		switch (XHCI_EPCTX_STATE(LE_32(epctx->xec_info))) {
819993e3fafSRobert Mustacchi 		case XHCI_EP_STOPPED:
820993e3fafSRobert Mustacchi 		case XHCI_EP_ERROR:
821993e3fafSRobert Mustacchi 			/*
822993e3fafSRobert Mustacchi 			 * This is where we wanted to go, so let's just take it.
823993e3fafSRobert Mustacchi 			 */
824993e3fafSRobert Mustacchi 			ret = USB_SUCCESS;
825993e3fafSRobert Mustacchi 			break;
826993e3fafSRobert Mustacchi 		case XHCI_EP_DISABLED:
827993e3fafSRobert Mustacchi 		case XHCI_EP_RUNNING:
828993e3fafSRobert Mustacchi 		case XHCI_EP_HALTED:
829993e3fafSRobert Mustacchi 		default:
830993e3fafSRobert Mustacchi 			/*
831993e3fafSRobert Mustacchi 			 * If we're in any of these, something really weird has
832993e3fafSRobert Mustacchi 			 * happened and it's not worth trying to recover at this
833993e3fafSRobert Mustacchi 			 * point.
834993e3fafSRobert Mustacchi 			 */
835993e3fafSRobert Mustacchi 			xhci_error(xhcip, "!asked to stop endpoint %u on slot "
836993e3fafSRobert Mustacchi 			    "%d and port %d: ended up in unexpected state %d",
837993e3fafSRobert Mustacchi 			    xep->xep_num, xd->xd_slot, xd->xd_port,
838993e3fafSRobert Mustacchi 			    XHCI_EPCTX_STATE(LE_32(epctx->xec_info)));
839993e3fafSRobert Mustacchi 			return (ret);
840993e3fafSRobert Mustacchi 		}
841993e3fafSRobert Mustacchi 	}
842993e3fafSRobert Mustacchi 
843993e3fafSRobert Mustacchi 	/*
844993e3fafSRobert Mustacchi 	 * Now that we're successful, we can clear any possible halted state
845993e3fafSRobert Mustacchi 	 * tracking that we might have had.
846993e3fafSRobert Mustacchi 	 */
847993e3fafSRobert Mustacchi 	if (ret == USB_SUCCESS) {
848993e3fafSRobert Mustacchi 		xep->xep_state &= ~XHCI_ENDPOINT_HALTED;
849993e3fafSRobert Mustacchi 	}
850993e3fafSRobert Mustacchi 
851993e3fafSRobert Mustacchi 	return (ret);
852993e3fafSRobert Mustacchi }
853993e3fafSRobert Mustacchi 
854993e3fafSRobert Mustacchi int
xhci_endpoint_ring(xhci_t * xhcip,xhci_device_t * xd,xhci_endpoint_t * xep)855993e3fafSRobert Mustacchi xhci_endpoint_ring(xhci_t *xhcip, xhci_device_t *xd, xhci_endpoint_t *xep)
856993e3fafSRobert Mustacchi {
857993e3fafSRobert Mustacchi 	/*
858993e3fafSRobert Mustacchi 	 * The doorbell ID's are offset by one from the endpoint numbers that we
859993e3fafSRobert Mustacchi 	 * keep.
860993e3fafSRobert Mustacchi 	 */
861993e3fafSRobert Mustacchi 	xhci_put32(xhcip, XHCI_R_DOOR, XHCI_DOORBELL(xd->xd_slot),
862993e3fafSRobert Mustacchi 	    xep->xep_num + 1);
863993e3fafSRobert Mustacchi 	if (xhci_check_regs_acc(xhcip) != DDI_FM_OK) {
864993e3fafSRobert Mustacchi 		xhci_error(xhcip, "failed to ring doorbell for slot %d and "
865993e3fafSRobert Mustacchi 		    "endpoint %u: encountered fatal FM register access error",
866993e3fafSRobert Mustacchi 		    xd->xd_slot, xep->xep_num);
867993e3fafSRobert Mustacchi 		xhci_fm_runtime_reset(xhcip);
868993e3fafSRobert Mustacchi 		return (USB_HC_HARDWARE_ERROR);
869993e3fafSRobert Mustacchi 	}
870993e3fafSRobert Mustacchi 
871993e3fafSRobert Mustacchi 	DTRACE_PROBE3(xhci__doorbell__ring, xhci_t *, xhcip, uint32_t,
872993e3fafSRobert Mustacchi 	    XHCI_DOORBELL(xd->xd_slot), uint32_t, xep->xep_num + 1);
873993e3fafSRobert Mustacchi 
874993e3fafSRobert Mustacchi 	return (USB_SUCCESS);
875993e3fafSRobert Mustacchi }
876993e3fafSRobert Mustacchi 
877993e3fafSRobert Mustacchi static void
xhci_endpoint_tick(void * arg)878993e3fafSRobert Mustacchi xhci_endpoint_tick(void *arg)
879993e3fafSRobert Mustacchi {
880993e3fafSRobert Mustacchi 	int ret;
881993e3fafSRobert Mustacchi 	xhci_transfer_t *xt;
882993e3fafSRobert Mustacchi 	xhci_endpoint_t *xep = arg;
883993e3fafSRobert Mustacchi 	xhci_device_t *xd = xep->xep_xd;
884993e3fafSRobert Mustacchi 	xhci_t *xhcip = xep->xep_xhci;
885993e3fafSRobert Mustacchi 
886993e3fafSRobert Mustacchi 	mutex_enter(&xhcip->xhci_lock);
887993e3fafSRobert Mustacchi 
888993e3fafSRobert Mustacchi 	/*
889993e3fafSRobert Mustacchi 	 * If we have the teardown flag set, then this is going away, don't try
890993e3fafSRobert Mustacchi 	 * to do anything. Also, if somehow a periodic endpoint has something
891993e3fafSRobert Mustacchi 	 * scheduled, just quit now and don't bother.
892993e3fafSRobert Mustacchi 	 */
893993e3fafSRobert Mustacchi 	if (xep->xep_state & (XHCI_ENDPOINT_TEARDOWN |
894993e3fafSRobert Mustacchi 	    XHCI_ENDPOINT_PERIODIC)) {
895993e3fafSRobert Mustacchi 		xep->xep_timeout = 0;
896993e3fafSRobert Mustacchi 		mutex_exit(&xhcip->xhci_lock);
897993e3fafSRobert Mustacchi 		return;
898993e3fafSRobert Mustacchi 	}
899993e3fafSRobert Mustacchi 
900993e3fafSRobert Mustacchi 	/*
901993e3fafSRobert Mustacchi 	 * If something else has already kicked off, something potentially
902993e3fafSRobert Mustacchi 	 * dangerous, just don't bother waiting for it and reschedule.
903993e3fafSRobert Mustacchi 	 */
904993e3fafSRobert Mustacchi 	if (xep->xep_state & XHCI_ENDPOINT_DONT_SCHEDULE) {
905993e3fafSRobert Mustacchi 		xep->xep_timeout = timeout(xhci_endpoint_tick, xep,
906993e3fafSRobert Mustacchi 		    drv_usectohz(XHCI_TICK_TIMEOUT_US));
907993e3fafSRobert Mustacchi 		mutex_exit(&xhcip->xhci_lock);
908993e3fafSRobert Mustacchi 		return;
909993e3fafSRobert Mustacchi 	}
910993e3fafSRobert Mustacchi 
911993e3fafSRobert Mustacchi 	/*
912993e3fafSRobert Mustacchi 	 * At this point, we have an endpoint that we need to consider. See if
913993e3fafSRobert Mustacchi 	 * there are any transfers on it, if none, we're done. If so, check if
914993e3fafSRobert Mustacchi 	 * we have exceeded the timeout. If we have, then we have some work to
915993e3fafSRobert Mustacchi 	 * do.
916993e3fafSRobert Mustacchi 	 */
917993e3fafSRobert Mustacchi 	xt = list_head(&xep->xep_transfers);
918993e3fafSRobert Mustacchi 	if (xt == NULL) {
919993e3fafSRobert Mustacchi 		xep->xep_timeout = 0;
920993e3fafSRobert Mustacchi 		mutex_exit(&xhcip->xhci_lock);
921993e3fafSRobert Mustacchi 		return;
922993e3fafSRobert Mustacchi 	}
923993e3fafSRobert Mustacchi 
924993e3fafSRobert Mustacchi 	if (xt->xt_timeout > 0) {
925993e3fafSRobert Mustacchi 		xt->xt_timeout--;
926993e3fafSRobert Mustacchi 		xep->xep_timeout = timeout(xhci_endpoint_tick, xep,
927993e3fafSRobert Mustacchi 		    drv_usectohz(XHCI_TICK_TIMEOUT_US));
928993e3fafSRobert Mustacchi 		mutex_exit(&xhcip->xhci_lock);
929993e3fafSRobert Mustacchi 		return;
930993e3fafSRobert Mustacchi 	}
931993e3fafSRobert Mustacchi 
932993e3fafSRobert Mustacchi 	/*
933993e3fafSRobert Mustacchi 	 * This item has timed out. We need to stop the ring and take action.
934993e3fafSRobert Mustacchi 	 */
935993e3fafSRobert Mustacchi 	xep->xep_state |= XHCI_ENDPOINT_TIMED_OUT | XHCI_ENDPOINT_QUIESCE;
936993e3fafSRobert Mustacchi 	ret = xhci_endpoint_quiesce(xhcip, xd, xep);
937993e3fafSRobert Mustacchi 	if (ret != USB_SUCCESS) {
938993e3fafSRobert Mustacchi 		/*
939993e3fafSRobert Mustacchi 		 * If we fail to quiesce during the timeout, then remove the
940993e3fafSRobert Mustacchi 		 * state flags and hopefully we'll be able to the next time
941993e3fafSRobert Mustacchi 		 * around or if a reset or polling stop comes in, maybe it can
942993e3fafSRobert Mustacchi 		 * deal with it.
943993e3fafSRobert Mustacchi 		 */
944993e3fafSRobert Mustacchi 		xep->xep_state &= ~(XHCI_ENDPOINT_QUIESCE |
945993e3fafSRobert Mustacchi 		    XHCI_ENDPOINT_TIMED_OUT);
946993e3fafSRobert Mustacchi 		xep->xep_timeout = timeout(xhci_endpoint_tick, xep,
947993e3fafSRobert Mustacchi 		    drv_usectohz(XHCI_TICK_TIMEOUT_US));
948993e3fafSRobert Mustacchi 		mutex_exit(&xhcip->xhci_lock);
949993e3fafSRobert Mustacchi 		cv_broadcast(&xep->xep_state_cv);
950993e3fafSRobert Mustacchi 		xhci_error(xhcip, "failed to successfully quiesce timed out "
951993e3fafSRobert Mustacchi 		    "endpoint %u of device on slot %d and port %d: device "
952993e3fafSRobert Mustacchi 		    "remains timed out", xep->xep_num, xd->xd_slot,
953993e3fafSRobert Mustacchi 		    xd->xd_port);
954993e3fafSRobert Mustacchi 		return;
955993e3fafSRobert Mustacchi 	}
956993e3fafSRobert Mustacchi 
957993e3fafSRobert Mustacchi 	xhci_ring_skip_transfer(&xep->xep_ring, xt);
958993e3fafSRobert Mustacchi 	(void) list_remove_head(&xep->xep_transfers);
959993e3fafSRobert Mustacchi 	mutex_exit(&xhcip->xhci_lock);
960993e3fafSRobert Mustacchi 
961993e3fafSRobert Mustacchi 	/*
962993e3fafSRobert Mustacchi 	 * At this point, we try and set the ring's dequeue pointer. If this
963993e3fafSRobert Mustacchi 	 * fails, we're left in an awkward state. We've already adjusted the
964993e3fafSRobert Mustacchi 	 * ring and removed the transfer. All we can really do is go through and
965993e3fafSRobert Mustacchi 	 * return the transfer and hope that they perhaps attempt to reset the
966993e3fafSRobert Mustacchi 	 * ring and that will succeed at this point. Based on everything we've
967993e3fafSRobert Mustacchi 	 * done to set things up, it'd be odd if this did fail.
968993e3fafSRobert Mustacchi 	 */
969993e3fafSRobert Mustacchi 	ret = xhci_command_set_tr_dequeue(xhcip, xd, xep);
970993e3fafSRobert Mustacchi 	mutex_enter(&xhcip->xhci_lock);
971993e3fafSRobert Mustacchi 	xep->xep_state &= ~XHCI_ENDPOINT_QUIESCE;
972993e3fafSRobert Mustacchi 	if (ret == USB_SUCCESS) {
973993e3fafSRobert Mustacchi 		xep->xep_state &= ~XHCI_ENDPOINT_TIMED_OUT;
974993e3fafSRobert Mustacchi 	} else {
975993e3fafSRobert Mustacchi 		xhci_error(xhcip, "failed to successfully set transfer ring "
976993e3fafSRobert Mustacchi 		    "dequeue pointer of timed out endpoint %u of "
977993e3fafSRobert Mustacchi 		    "device on slot %d and port %d: device remains timed out, "
978993e3fafSRobert Mustacchi 		    "please use cfgadm to recover", xep->xep_num, xd->xd_slot,
979993e3fafSRobert Mustacchi 		    xd->xd_port);
980993e3fafSRobert Mustacchi 	}
981993e3fafSRobert Mustacchi 	xep->xep_timeout = timeout(xhci_endpoint_tick, xep,
982993e3fafSRobert Mustacchi 	    drv_usectohz(XHCI_TICK_TIMEOUT_US));
983993e3fafSRobert Mustacchi 	mutex_exit(&xhcip->xhci_lock);
984993e3fafSRobert Mustacchi 	cv_broadcast(&xep->xep_state_cv);
985993e3fafSRobert Mustacchi 
986993e3fafSRobert Mustacchi 	/*
987993e3fafSRobert Mustacchi 	 * Because we never time out periodic related activity, we will always
988993e3fafSRobert Mustacchi 	 * have the request on the transfer.
989993e3fafSRobert Mustacchi 	 */
990993e3fafSRobert Mustacchi 	ASSERT(xt->xt_usba_req != NULL);
991993e3fafSRobert Mustacchi 	usba_hcdi_cb(xep->xep_pipe, xt->xt_usba_req, USB_CR_TIMEOUT);
992993e3fafSRobert Mustacchi 	xhci_transfer_free(xhcip, xt);
993993e3fafSRobert Mustacchi }
994993e3fafSRobert Mustacchi 
995993e3fafSRobert Mustacchi /*
996993e3fafSRobert Mustacchi  * We've been asked to schedule a series of frames onto the specified endpoint.
997993e3fafSRobert Mustacchi  * We need to make sure that there is enough room, at which point we can queue
998993e3fafSRobert Mustacchi  * it and then ring the door bell. Note that we queue in reverse order to make
999993e3fafSRobert Mustacchi  * sure that if the ring moves on, it won't see the correct cycle bit.
1000993e3fafSRobert Mustacchi  */
1001993e3fafSRobert Mustacchi int
xhci_endpoint_schedule(xhci_t * xhcip,xhci_device_t * xd,xhci_endpoint_t * xep,xhci_transfer_t * xt,boolean_t ring)1002993e3fafSRobert Mustacchi xhci_endpoint_schedule(xhci_t *xhcip, xhci_device_t *xd, xhci_endpoint_t *xep,
1003993e3fafSRobert Mustacchi     xhci_transfer_t *xt, boolean_t ring)
1004993e3fafSRobert Mustacchi {
1005993e3fafSRobert Mustacchi 	int i;
1006993e3fafSRobert Mustacchi 	xhci_ring_t *rp = &xep->xep_ring;
1007993e3fafSRobert Mustacchi 
1008993e3fafSRobert Mustacchi 	ASSERT(MUTEX_HELD(&xhcip->xhci_lock));
1009993e3fafSRobert Mustacchi 	ASSERT(xt->xt_ntrbs > 0);
1010993e3fafSRobert Mustacchi 	ASSERT(xt->xt_trbs != NULL);
1011993e3fafSRobert Mustacchi 
1012993e3fafSRobert Mustacchi 	if ((xep->xep_state & XHCI_ENDPOINT_DONT_SCHEDULE) != 0)
1013993e3fafSRobert Mustacchi 		return (USB_FAILURE);
1014993e3fafSRobert Mustacchi 
1015993e3fafSRobert Mustacchi 	if (xhci_ring_trb_space(rp, xt->xt_ntrbs) == B_FALSE)
1016993e3fafSRobert Mustacchi 		return (USB_NO_RESOURCES);
1017993e3fafSRobert Mustacchi 
1018993e3fafSRobert Mustacchi 	for (i = xt->xt_ntrbs - 1; i > 0; i--) {
10192aba3acdSRobert Mustacchi 		xhci_ring_trb_fill(rp, i, &xt->xt_trbs[i], &xt->xt_trbs_pa[i],
10202aba3acdSRobert Mustacchi 		    B_TRUE);
1021993e3fafSRobert Mustacchi 	}
10222aba3acdSRobert Mustacchi 	xhci_ring_trb_fill(rp, 0U, &xt->xt_trbs[0], &xt->xt_trbs_pa[0],
10232aba3acdSRobert Mustacchi 	    B_FALSE);
1024993e3fafSRobert Mustacchi 
1025993e3fafSRobert Mustacchi 	XHCI_DMA_SYNC(rp->xr_dma, DDI_DMA_SYNC_FORDEV);
1026993e3fafSRobert Mustacchi 	xhci_ring_trb_produce(rp, xt->xt_ntrbs);
1027993e3fafSRobert Mustacchi 	list_insert_tail(&xep->xep_transfers, xt);
1028993e3fafSRobert Mustacchi 
1029993e3fafSRobert Mustacchi 	XHCI_DMA_SYNC(rp->xr_dma, DDI_DMA_SYNC_FORDEV);
1030993e3fafSRobert Mustacchi 	if (xhci_check_dma_handle(xhcip, &rp->xr_dma) != DDI_FM_OK) {
1031993e3fafSRobert Mustacchi 		xhci_error(xhcip, "failed to write out TRB for device on slot "
1032993e3fafSRobert Mustacchi 		    "%d, port %d, and endpoint %u: encountered fatal FM error "
1033993e3fafSRobert Mustacchi 		    "synchronizing ring DMA memory", xd->xd_slot, xd->xd_port,
1034993e3fafSRobert Mustacchi 		    xep->xep_num);
1035993e3fafSRobert Mustacchi 		xhci_fm_runtime_reset(xhcip);
1036993e3fafSRobert Mustacchi 		return (USB_HC_HARDWARE_ERROR);
1037993e3fafSRobert Mustacchi 	}
1038993e3fafSRobert Mustacchi 
1039993e3fafSRobert Mustacchi 	if (xep->xep_timeout == 0 &&
1040993e3fafSRobert Mustacchi 	    !(xep->xep_state & XHCI_ENDPOINT_PERIODIC)) {
1041993e3fafSRobert Mustacchi 		xep->xep_timeout = timeout(xhci_endpoint_tick, xep,
1042993e3fafSRobert Mustacchi 		    drv_usectohz(XHCI_TICK_TIMEOUT_US));
1043993e3fafSRobert Mustacchi 	}
1044993e3fafSRobert Mustacchi 
1045993e3fafSRobert Mustacchi 	xt->xt_sched_time = gethrtime();
1046993e3fafSRobert Mustacchi 
1047993e3fafSRobert Mustacchi 	if (ring == B_FALSE)
1048993e3fafSRobert Mustacchi 		return (USB_SUCCESS);
1049993e3fafSRobert Mustacchi 
1050993e3fafSRobert Mustacchi 	return (xhci_endpoint_ring(xhcip, xd, xep));
1051993e3fafSRobert Mustacchi }
1052993e3fafSRobert Mustacchi 
1053ec82ef79SMatthias Scheler xhci_transfer_t *
xhci_endpoint_determine_transfer(xhci_t * xhcip,xhci_endpoint_t * xep,xhci_trb_t * trb,uint_t * offp)1054993e3fafSRobert Mustacchi xhci_endpoint_determine_transfer(xhci_t *xhcip, xhci_endpoint_t *xep,
10552aba3acdSRobert Mustacchi     xhci_trb_t *trb, uint_t *offp)
1056993e3fafSRobert Mustacchi {
10572aba3acdSRobert Mustacchi 	uint_t i;
10582aba3acdSRobert Mustacchi 	uint64_t addr;
1059993e3fafSRobert Mustacchi 	xhci_transfer_t *xt;
1060993e3fafSRobert Mustacchi 
1061993e3fafSRobert Mustacchi 	ASSERT(xhcip != NULL);
1062993e3fafSRobert Mustacchi 	ASSERT(offp != NULL);
1063993e3fafSRobert Mustacchi 	ASSERT(xep != NULL);
1064993e3fafSRobert Mustacchi 	ASSERT(trb != NULL);
1065993e3fafSRobert Mustacchi 	ASSERT(MUTEX_HELD(&xhcip->xhci_lock));
1066993e3fafSRobert Mustacchi 
1067993e3fafSRobert Mustacchi 	if ((xt = list_head(&xep->xep_transfers)) == NULL)
1068993e3fafSRobert Mustacchi 		return (NULL);
1069993e3fafSRobert Mustacchi 
10702aba3acdSRobert Mustacchi 	addr = LE_64(trb->trb_addr);
10712aba3acdSRobert Mustacchi 
10722aba3acdSRobert Mustacchi 	/*
10732aba3acdSRobert Mustacchi 	 * Check if this is the simple case of an event data. If it is, then all
10742aba3acdSRobert Mustacchi 	 * we need to do is look and see its data matches the address of the
10752aba3acdSRobert Mustacchi 	 * transfer.
10762aba3acdSRobert Mustacchi 	 */
10772aba3acdSRobert Mustacchi 	if (XHCI_TRB_GET_ED(LE_32(trb->trb_flags)) != 0) {
10782aba3acdSRobert Mustacchi 		if (LE_64(trb->trb_addr) != (uintptr_t)xt)
10792aba3acdSRobert Mustacchi 			return (NULL);
10802aba3acdSRobert Mustacchi 
10812aba3acdSRobert Mustacchi 		*offp = xt->xt_ntrbs - 1;
10822aba3acdSRobert Mustacchi 		return (xt);
10832aba3acdSRobert Mustacchi 	}
10842aba3acdSRobert Mustacchi 
10852aba3acdSRobert Mustacchi 	/*
10862aba3acdSRobert Mustacchi 	 * This represents an error that has occurred. We need to check two
10872aba3acdSRobert Mustacchi 	 * different things. The first is that the TRB PA maps to one of the
10882aba3acdSRobert Mustacchi 	 * TRBs in the transfer. Secondly, we need to make sure that it makes
10892aba3acdSRobert Mustacchi 	 * sense in the context of the ring and our notion of where the tail is.
10902aba3acdSRobert Mustacchi 	 */
10912aba3acdSRobert Mustacchi 	for (i = 0; i < xt->xt_ntrbs; i++) {
10922aba3acdSRobert Mustacchi 		if (xt->xt_trbs_pa[i] == addr)
10932aba3acdSRobert Mustacchi 			break;
10942aba3acdSRobert Mustacchi 	}
10952aba3acdSRobert Mustacchi 
10962aba3acdSRobert Mustacchi 	if (i == xt->xt_ntrbs)
10972aba3acdSRobert Mustacchi 		return (NULL);
10982aba3acdSRobert Mustacchi 
10992aba3acdSRobert Mustacchi 	if (xhci_ring_trb_valid_range(&xep->xep_ring, LE_64(trb->trb_addr),
11002aba3acdSRobert Mustacchi 	    xt->xt_ntrbs) == -1)
1101993e3fafSRobert Mustacchi 		return (NULL);
11022aba3acdSRobert Mustacchi 
11032aba3acdSRobert Mustacchi 	*offp = i;
1104993e3fafSRobert Mustacchi 	return (xt);
1105993e3fafSRobert Mustacchi }
1106993e3fafSRobert Mustacchi 
1107993e3fafSRobert Mustacchi static void
xhci_endpoint_reschedule_periodic(xhci_t * xhcip,xhci_device_t * xd,xhci_endpoint_t * xep,xhci_transfer_t * xt)1108993e3fafSRobert Mustacchi xhci_endpoint_reschedule_periodic(xhci_t *xhcip, xhci_device_t *xd,
1109993e3fafSRobert Mustacchi     xhci_endpoint_t *xep, xhci_transfer_t *xt)
1110993e3fafSRobert Mustacchi {
1111993e3fafSRobert Mustacchi 	int ret;
1112993e3fafSRobert Mustacchi 	xhci_pipe_t *xp = (xhci_pipe_t *)xep->xep_pipe->p_hcd_private;
1113993e3fafSRobert Mustacchi 	xhci_periodic_pipe_t *xpp = &xp->xp_periodic;
1114993e3fafSRobert Mustacchi 
1115993e3fafSRobert Mustacchi 	ASSERT3U(xpp->xpp_tsize, >, 0);
1116993e3fafSRobert Mustacchi 
1117993e3fafSRobert Mustacchi 	xt->xt_short = 0;
1118993e3fafSRobert Mustacchi 	xt->xt_cr = USB_CR_OK;
1119993e3fafSRobert Mustacchi 
1120993e3fafSRobert Mustacchi 	mutex_enter(&xhcip->xhci_lock);
1121993e3fafSRobert Mustacchi 
1122993e3fafSRobert Mustacchi 	/*
1123993e3fafSRobert Mustacchi 	 * If we don't have an active poll, then we shouldn't bother trying to
1124993e3fafSRobert Mustacchi 	 * reschedule it. This means that we're trying to stop or we ran out of
1125993e3fafSRobert Mustacchi 	 * memory.
1126993e3fafSRobert Mustacchi 	 */
1127993e3fafSRobert Mustacchi 	if (xpp->xpp_poll_state != XHCI_PERIODIC_POLL_ACTIVE) {
1128993e3fafSRobert Mustacchi 		mutex_exit(&xhcip->xhci_lock);
1129993e3fafSRobert Mustacchi 		return;
1130993e3fafSRobert Mustacchi 	}
1131993e3fafSRobert Mustacchi 
1132993e3fafSRobert Mustacchi 	if (xep->xep_type == USB_EP_ATTR_ISOCH) {
1133993e3fafSRobert Mustacchi 		int i;
1134993e3fafSRobert Mustacchi 		for (i = 0; i < xt->xt_ntrbs; i++) {
1135993e3fafSRobert Mustacchi 			xt->xt_isoc[i].isoc_pkt_actual_length =
1136993e3fafSRobert Mustacchi 			    xt->xt_isoc[i].isoc_pkt_length;
1137993e3fafSRobert Mustacchi 			xt->xt_isoc[i].isoc_pkt_status = USB_CR_OK;
1138993e3fafSRobert Mustacchi 		}
1139993e3fafSRobert Mustacchi 	}
1140993e3fafSRobert Mustacchi 
1141993e3fafSRobert Mustacchi 	/*
1142993e3fafSRobert Mustacchi 	 * In general, there should always be space on the ring for this. The
1143993e3fafSRobert Mustacchi 	 * only reason that rescheduling an existing transfer for a periodic
1144993e3fafSRobert Mustacchi 	 * endpoint wouldn't work is because we have a hardware error, at which
1145993e3fafSRobert Mustacchi 	 * point we're going to be going down hard anyways. We log and bump a
1146993e3fafSRobert Mustacchi 	 * stat here to make this case discoverable in case our assumptions our
1147993e3fafSRobert Mustacchi 	 * wrong.
1148993e3fafSRobert Mustacchi 	 */
1149993e3fafSRobert Mustacchi 	ret = xhci_endpoint_schedule(xhcip, xd, xep, xt, B_TRUE);
1150993e3fafSRobert Mustacchi 	if (ret != 0) {
1151993e3fafSRobert Mustacchi 		xhci_log(xhcip, "!failed to reschedule periodic endpoint %u "
1152993e3fafSRobert Mustacchi 		    "(type %u) on slot %d: %d\n", xep->xep_num, xep->xep_type,
1153993e3fafSRobert Mustacchi 		    xd->xd_slot, ret);
1154993e3fafSRobert Mustacchi 	}
1155993e3fafSRobert Mustacchi 	mutex_exit(&xhcip->xhci_lock);
1156993e3fafSRobert Mustacchi }
1157993e3fafSRobert Mustacchi 
1158993e3fafSRobert Mustacchi /*
1159993e3fafSRobert Mustacchi  * We're dealing with a message on a control endpoint. This may be a default
1160993e3fafSRobert Mustacchi  * endpoint or otherwise. These usually come in groups of 3+ TRBs where you have
1161993e3fafSRobert Mustacchi  * a setup stage, data stage (which may have one or more other TRBs) and then a
1162993e3fafSRobert Mustacchi  * final status stage.
1163993e3fafSRobert Mustacchi  *
1164993e3fafSRobert Mustacchi  * We generally set ourselves up such that we get interrupted and notified only
1165993e3fafSRobert Mustacchi  * on the status stage and for short transfers in the data stage. If we
1166993e3fafSRobert Mustacchi  * encounter a short transfer in the data stage, then we need to go through and
1167993e3fafSRobert Mustacchi  * check whether or not the short transfer is allowed. If it is, then there's
1168993e3fafSRobert Mustacchi  * nothing to do. We'll update everything and call back the framework once we
1169993e3fafSRobert Mustacchi  * get the status stage.
1170993e3fafSRobert Mustacchi  */
1171993e3fafSRobert Mustacchi static boolean_t
xhci_endpoint_control_callback(xhci_t * xhcip,xhci_device_t * xd,xhci_endpoint_t * xep,xhci_transfer_t * xt,uint_t off,xhci_trb_t * trb)1172993e3fafSRobert Mustacchi xhci_endpoint_control_callback(xhci_t *xhcip, xhci_device_t *xd,
11732aba3acdSRobert Mustacchi     xhci_endpoint_t *xep, xhci_transfer_t *xt, uint_t off, xhci_trb_t *trb)
1174993e3fafSRobert Mustacchi {
1175993e3fafSRobert Mustacchi 	int code;
1176993e3fafSRobert Mustacchi 	usb_ctrl_req_t *ucrp;
1177993e3fafSRobert Mustacchi 	xhci_transfer_t *rem;
1178993e3fafSRobert Mustacchi 
1179993e3fafSRobert Mustacchi 	ASSERT(MUTEX_HELD(&xhcip->xhci_lock));
1180993e3fafSRobert Mustacchi 
1181993e3fafSRobert Mustacchi 	code = XHCI_TRB_GET_CODE(LE_32(trb->trb_status));
1182993e3fafSRobert Mustacchi 	ucrp = (usb_ctrl_req_t *)xt->xt_usba_req;
1183993e3fafSRobert Mustacchi 
1184993e3fafSRobert Mustacchi 	/*
1185993e3fafSRobert Mustacchi 	 * Now that we know what this TRB is for, was it for a data/normal stage
1186993e3fafSRobert Mustacchi 	 * or is it the status stage. We cheat by looking at the last entry. If
11872aba3acdSRobert Mustacchi 	 * it's a data stage, then we must have gotten a short write. We record
11882aba3acdSRobert Mustacchi 	 * this fact and whether we should consider the transfer fatal for the
11892aba3acdSRobert Mustacchi 	 * subsequent status stage.
1190993e3fafSRobert Mustacchi 	 */
1191993e3fafSRobert Mustacchi 	if (off != xt->xt_ntrbs - 1) {
1192993e3fafSRobert Mustacchi 		uint_t remain;
1193993e3fafSRobert Mustacchi 		usb_ctrl_req_t *ucrp = (usb_ctrl_req_t *)xt->xt_usba_req;
1194993e3fafSRobert Mustacchi 
1195993e3fafSRobert Mustacchi 		/*
1196993e3fafSRobert Mustacchi 		 * This is a data stage TRB. The only reason we should have
1197993e3fafSRobert Mustacchi 		 * gotten something for this is beacuse it was short. Make sure
1198993e3fafSRobert Mustacchi 		 * it's okay before we continue.
1199993e3fafSRobert Mustacchi 		 */
1200993e3fafSRobert Mustacchi 		VERIFY3S(code, ==, XHCI_CODE_SHORT_XFER);
1201993e3fafSRobert Mustacchi 		if (!(ucrp->ctrl_attributes & USB_ATTRS_SHORT_XFER_OK)) {
1202993e3fafSRobert Mustacchi 			xt->xt_cr = USB_CR_DATA_UNDERRUN;
1203993e3fafSRobert Mustacchi 			mutex_exit(&xhcip->xhci_lock);
1204993e3fafSRobert Mustacchi 			return (B_TRUE);
1205993e3fafSRobert Mustacchi 		}
1206993e3fafSRobert Mustacchi 
1207993e3fafSRobert Mustacchi 		/*
1208993e3fafSRobert Mustacchi 		 * The value in the resulting trb is how much data remained to
1209993e3fafSRobert Mustacchi 		 * be transferred. Normalize that against the original buffer
1210993e3fafSRobert Mustacchi 		 * size.
1211993e3fafSRobert Mustacchi 		 */
1212993e3fafSRobert Mustacchi 		remain = XHCI_TRB_REMAIN(LE_32(trb->trb_status));
1213993e3fafSRobert Mustacchi 		xt->xt_short = xt->xt_buffer.xdb_len - remain;
1214993e3fafSRobert Mustacchi 		mutex_exit(&xhcip->xhci_lock);
1215993e3fafSRobert Mustacchi 		return (B_TRUE);
1216993e3fafSRobert Mustacchi 	}
1217993e3fafSRobert Mustacchi 
1218993e3fafSRobert Mustacchi 	/*
1219993e3fafSRobert Mustacchi 	 * Okay, this is a status stage trb that's in good health. We should
1220993e3fafSRobert Mustacchi 	 * finally go ahead, sync data and try and finally do the callback. If
1221993e3fafSRobert Mustacchi 	 * we have short data, then xt->xt_short will be non-zero.
1222993e3fafSRobert Mustacchi 	 */
1223993e3fafSRobert Mustacchi 	if (xt->xt_data_tohost == B_TRUE) {
1224993e3fafSRobert Mustacchi 		size_t len;
1225993e3fafSRobert Mustacchi 		if (xt->xt_short != 0) {
1226993e3fafSRobert Mustacchi 			len = xt->xt_short;
1227993e3fafSRobert Mustacchi 		} else {
1228993e3fafSRobert Mustacchi 			len = xt->xt_buffer.xdb_len;
1229993e3fafSRobert Mustacchi 		}
1230993e3fafSRobert Mustacchi 
1231993e3fafSRobert Mustacchi 		if (xhci_transfer_sync(xhcip, xt, DDI_DMA_SYNC_FORCPU) !=
1232993e3fafSRobert Mustacchi 		    DDI_FM_OK) {
1233993e3fafSRobert Mustacchi 			xhci_error(xhcip, "failed to process control transfer "
1234993e3fafSRobert Mustacchi 			    "callback for endpoint %u of device on slot %d and "
1235993e3fafSRobert Mustacchi 			    "port %d: encountered fatal FM error synchronizing "
1236993e3fafSRobert Mustacchi 			    "DMA memory, resetting device", xep->xep_num,
1237993e3fafSRobert Mustacchi 			    xd->xd_slot, xd->xd_port);
1238993e3fafSRobert Mustacchi 			xhci_fm_runtime_reset(xhcip);
1239993e3fafSRobert Mustacchi 			mutex_exit(&xhcip->xhci_lock);
1240993e3fafSRobert Mustacchi 			return (B_FALSE);
1241993e3fafSRobert Mustacchi 		}
1242993e3fafSRobert Mustacchi 
1243993e3fafSRobert Mustacchi 		xhci_transfer_copy(xt, ucrp->ctrl_data->b_rptr, len, B_TRUE);
1244993e3fafSRobert Mustacchi 		ucrp->ctrl_data->b_wptr += len;
1245993e3fafSRobert Mustacchi 	}
1246993e3fafSRobert Mustacchi 
1247993e3fafSRobert Mustacchi 	/*
1248993e3fafSRobert Mustacchi 	 * Now we're done. We can go ahead and bump the ring. Free the transfer
1249993e3fafSRobert Mustacchi 	 * outside of the lock and call back into the framework.
1250993e3fafSRobert Mustacchi 	 */
1251993e3fafSRobert Mustacchi 	VERIFY(xhci_ring_trb_consumed(&xep->xep_ring, LE_64(trb->trb_addr)));
1252993e3fafSRobert Mustacchi 	rem = list_remove_head(&xep->xep_transfers);
1253993e3fafSRobert Mustacchi 	VERIFY3P(rem, ==, xt);
1254993e3fafSRobert Mustacchi 	mutex_exit(&xhcip->xhci_lock);
1255993e3fafSRobert Mustacchi 
1256993e3fafSRobert Mustacchi 	usba_hcdi_cb(xep->xep_pipe, (usb_opaque_t)ucrp, xt->xt_cr);
1257993e3fafSRobert Mustacchi 	xhci_transfer_free(xhcip, xt);
1258993e3fafSRobert Mustacchi 
1259993e3fafSRobert Mustacchi 	return (B_TRUE);
1260993e3fafSRobert Mustacchi }
1261993e3fafSRobert Mustacchi 
1262993e3fafSRobert Mustacchi /*
1263993e3fafSRobert Mustacchi  * Cons up a new usb request for the periodic data transfer if we can. If there
1264993e3fafSRobert Mustacchi  * isn't one available, change the return code to NO_RESOURCES and stop polling
1265993e3fafSRobert Mustacchi  * on this endpoint, thus using and consuming the original request.
1266993e3fafSRobert Mustacchi  */
1267993e3fafSRobert Mustacchi static usb_opaque_t
xhci_endpoint_dup_periodic(xhci_endpoint_t * xep,xhci_transfer_t * xt,usb_cr_t * cr)1268993e3fafSRobert Mustacchi xhci_endpoint_dup_periodic(xhci_endpoint_t *xep, xhci_transfer_t *xt,
1269993e3fafSRobert Mustacchi     usb_cr_t *cr)
1270993e3fafSRobert Mustacchi {
1271993e3fafSRobert Mustacchi 	usb_opaque_t urp;
1272993e3fafSRobert Mustacchi 
1273993e3fafSRobert Mustacchi 	xhci_pipe_t *xp = (xhci_pipe_t *)xep->xep_pipe->p_hcd_private;
1274993e3fafSRobert Mustacchi 	xhci_periodic_pipe_t *xpp = &xp->xp_periodic;
1275993e3fafSRobert Mustacchi 
1276993e3fafSRobert Mustacchi 	/*
1277993e3fafSRobert Mustacchi 	 * In general, transfers shouldn't have a usb request. However, oneshot
1278993e3fafSRobert Mustacchi 	 * Interrupt IN ones will, so we use this as a way to shortcut out of
1279993e3fafSRobert Mustacchi 	 * here.
1280993e3fafSRobert Mustacchi 	 */
1281993e3fafSRobert Mustacchi 	if (xt->xt_usba_req != NULL)
1282993e3fafSRobert Mustacchi 		return (xt->xt_usba_req);
1283993e3fafSRobert Mustacchi 
1284993e3fafSRobert Mustacchi 	if (xep->xep_type == USB_EP_ATTR_INTR) {
1285993e3fafSRobert Mustacchi 		urp = (usb_opaque_t)usba_hcdi_dup_intr_req(xep->xep_pipe->p_dip,
1286993e3fafSRobert Mustacchi 		    (usb_intr_req_t *)xpp->xpp_usb_req, xpp->xpp_tsize, 0);
1287993e3fafSRobert Mustacchi 	} else {
1288993e3fafSRobert Mustacchi 		urp = (usb_opaque_t)usba_hcdi_dup_isoc_req(xep->xep_pipe->p_dip,
1289993e3fafSRobert Mustacchi 		    (usb_isoc_req_t *)xpp->xpp_usb_req, 0);
1290993e3fafSRobert Mustacchi 	}
1291993e3fafSRobert Mustacchi 	if (urp == NULL) {
1292993e3fafSRobert Mustacchi 		xpp->xpp_poll_state = XHCI_PERIODIC_POLL_NOMEM;
1293993e3fafSRobert Mustacchi 		urp = xpp->xpp_usb_req;
1294993e3fafSRobert Mustacchi 		xpp->xpp_usb_req = NULL;
1295993e3fafSRobert Mustacchi 		*cr = USB_CR_NO_RESOURCES;
1296993e3fafSRobert Mustacchi 	} else {
1297993e3fafSRobert Mustacchi 		mutex_enter(&xep->xep_pipe->p_mutex);
1298993e3fafSRobert Mustacchi 		xep->xep_pipe->p_req_count++;
1299993e3fafSRobert Mustacchi 		mutex_exit(&xep->xep_pipe->p_mutex);
1300993e3fafSRobert Mustacchi 	}
1301993e3fafSRobert Mustacchi 
1302993e3fafSRobert Mustacchi 	return (urp);
1303993e3fafSRobert Mustacchi }
1304993e3fafSRobert Mustacchi 
1305ec82ef79SMatthias Scheler xhci_device_t *
xhci_device_lookup_by_slot(xhci_t * xhcip,int slot)1306993e3fafSRobert Mustacchi xhci_device_lookup_by_slot(xhci_t *xhcip, int slot)
1307993e3fafSRobert Mustacchi {
1308993e3fafSRobert Mustacchi 	xhci_device_t *xd;
1309993e3fafSRobert Mustacchi 
1310993e3fafSRobert Mustacchi 	ASSERT(MUTEX_HELD(&xhcip->xhci_lock));
1311993e3fafSRobert Mustacchi 
1312993e3fafSRobert Mustacchi 	for (xd = list_head(&xhcip->xhci_usba.xa_devices); xd != NULL;
1313993e3fafSRobert Mustacchi 	    xd = list_next(&xhcip->xhci_usba.xa_devices, xd)) {
1314993e3fafSRobert Mustacchi 		if (xd->xd_slot == slot)
1315993e3fafSRobert Mustacchi 			return (xd);
1316993e3fafSRobert Mustacchi 	}
1317993e3fafSRobert Mustacchi 
1318993e3fafSRobert Mustacchi 	return (NULL);
1319993e3fafSRobert Mustacchi }
1320993e3fafSRobert Mustacchi 
1321993e3fafSRobert Mustacchi /*
1322993e3fafSRobert Mustacchi  * Handle things which consist solely of normal tranfers, in other words, bulk
1323993e3fafSRobert Mustacchi  * and interrupt transfers.
1324993e3fafSRobert Mustacchi  */
1325993e3fafSRobert Mustacchi static boolean_t
xhci_endpoint_norm_callback(xhci_t * xhcip,xhci_device_t * xd,xhci_endpoint_t * xep,xhci_transfer_t * xt,uint_t off,xhci_trb_t * trb)1326993e3fafSRobert Mustacchi xhci_endpoint_norm_callback(xhci_t *xhcip, xhci_device_t *xd,
13272aba3acdSRobert Mustacchi     xhci_endpoint_t *xep, xhci_transfer_t *xt, uint_t off, xhci_trb_t *trb)
1328993e3fafSRobert Mustacchi {
1329993e3fafSRobert Mustacchi 	int code;
1330993e3fafSRobert Mustacchi 	usb_cr_t cr;
1331993e3fafSRobert Mustacchi 	xhci_transfer_t *rem;
1332993e3fafSRobert Mustacchi 	int attrs;
1333993e3fafSRobert Mustacchi 	mblk_t *mp;
1334993e3fafSRobert Mustacchi 	boolean_t periodic = B_FALSE;
1335993e3fafSRobert Mustacchi 	usb_opaque_t urp;
1336993e3fafSRobert Mustacchi 
1337993e3fafSRobert Mustacchi 	ASSERT(MUTEX_HELD(&xhcip->xhci_lock));
1338993e3fafSRobert Mustacchi 	ASSERT(xep->xep_type == USB_EP_ATTR_BULK ||
1339993e3fafSRobert Mustacchi 	    xep->xep_type == USB_EP_ATTR_INTR);
1340993e3fafSRobert Mustacchi 
1341993e3fafSRobert Mustacchi 	code = XHCI_TRB_GET_CODE(LE_32(trb->trb_status));
1342993e3fafSRobert Mustacchi 
1343993e3fafSRobert Mustacchi 	if (code == XHCI_CODE_SHORT_XFER) {
13442aba3acdSRobert Mustacchi 		uint_t residue;
1345993e3fafSRobert Mustacchi 		residue = XHCI_TRB_REMAIN(LE_32(trb->trb_status));
13462aba3acdSRobert Mustacchi 
13472aba3acdSRobert Mustacchi 		if (xep->xep_type == USB_EP_ATTR_BULK) {
13482aba3acdSRobert Mustacchi 			VERIFY3U(XHCI_TRB_GET_ED(LE_32(trb->trb_flags)), !=, 0);
13492aba3acdSRobert Mustacchi 			xt->xt_short = residue;
13502aba3acdSRobert Mustacchi 		} else {
13512aba3acdSRobert Mustacchi 			xt->xt_short = xt->xt_buffer.xdb_len - residue;
13522aba3acdSRobert Mustacchi 		}
1353993e3fafSRobert Mustacchi 	}
1354993e3fafSRobert Mustacchi 
1355993e3fafSRobert Mustacchi 	/*
1356993e3fafSRobert Mustacchi 	 * If we have an interrupt from something that's not the last entry,
1357993e3fafSRobert Mustacchi 	 * that must mean we had a short transfer, so there's nothing more for
1358993e3fafSRobert Mustacchi 	 * us to do at the moment. We won't call back until everything's
1359993e3fafSRobert Mustacchi 	 * finished for the general transfer.
1360993e3fafSRobert Mustacchi 	 */
1361993e3fafSRobert Mustacchi 	if (off < xt->xt_ntrbs - 1) {
1362993e3fafSRobert Mustacchi 		mutex_exit(&xhcip->xhci_lock);
1363993e3fafSRobert Mustacchi 		return (B_TRUE);
1364993e3fafSRobert Mustacchi 	}
1365993e3fafSRobert Mustacchi 
1366993e3fafSRobert Mustacchi 	urp = xt->xt_usba_req;
1367993e3fafSRobert Mustacchi 	if (xep->xep_type == USB_EP_ATTR_BULK) {
1368993e3fafSRobert Mustacchi 		usb_bulk_req_t *ubrp = (usb_bulk_req_t *)xt->xt_usba_req;
1369993e3fafSRobert Mustacchi 		attrs = ubrp->bulk_attributes;
1370993e3fafSRobert Mustacchi 		mp = ubrp->bulk_data;
1371993e3fafSRobert Mustacchi 	} else {
1372993e3fafSRobert Mustacchi 		usb_intr_req_t *uirp = (usb_intr_req_t *)xt->xt_usba_req;
1373993e3fafSRobert Mustacchi 
1374993e3fafSRobert Mustacchi 		if (uirp == NULL) {
1375993e3fafSRobert Mustacchi 			periodic = B_TRUE;
1376993e3fafSRobert Mustacchi 			urp = xhci_endpoint_dup_periodic(xep, xt, &cr);
1377993e3fafSRobert Mustacchi 			uirp = (usb_intr_req_t *)urp;
1378993e3fafSRobert Mustacchi 
1379993e3fafSRobert Mustacchi 			/*
1380993e3fafSRobert Mustacchi 			 * If we weren't able to duplicate the interrupt, then
1381993e3fafSRobert Mustacchi 			 * we can't put any data in it.
1382993e3fafSRobert Mustacchi 			 */
1383993e3fafSRobert Mustacchi 			if (cr == USB_CR_NO_RESOURCES)
1384993e3fafSRobert Mustacchi 				goto out;
1385993e3fafSRobert Mustacchi 		}
1386993e3fafSRobert Mustacchi 
1387993e3fafSRobert Mustacchi 		attrs = uirp->intr_attributes;
1388993e3fafSRobert Mustacchi 		mp = uirp->intr_data;
1389993e3fafSRobert Mustacchi 	}
1390993e3fafSRobert Mustacchi 
1391993e3fafSRobert Mustacchi 	if (xt->xt_data_tohost == B_TRUE) {
1392993e3fafSRobert Mustacchi 		size_t len;
1393993e3fafSRobert Mustacchi 		if (xt->xt_short != 0) {
1394993e3fafSRobert Mustacchi 			if (!(attrs & USB_ATTRS_SHORT_XFER_OK)) {
1395993e3fafSRobert Mustacchi 				cr = USB_CR_DATA_UNDERRUN;
1396993e3fafSRobert Mustacchi 				goto out;
1397993e3fafSRobert Mustacchi 			}
1398993e3fafSRobert Mustacchi 			len = xt->xt_short;
1399993e3fafSRobert Mustacchi 		} else {
1400993e3fafSRobert Mustacchi 			len = xt->xt_buffer.xdb_len;
1401993e3fafSRobert Mustacchi 		}
1402993e3fafSRobert Mustacchi 
1403993e3fafSRobert Mustacchi 		if (xhci_transfer_sync(xhcip, xt, DDI_DMA_SYNC_FORCPU) !=
1404993e3fafSRobert Mustacchi 		    DDI_FM_OK) {
1405993e3fafSRobert Mustacchi 			xhci_error(xhcip, "failed to process normal transfer "
1406993e3fafSRobert Mustacchi 			    "callback for endpoint %u of device on slot %d and "
1407993e3fafSRobert Mustacchi 			    "port %d: encountered fatal FM error synchronizing "
1408993e3fafSRobert Mustacchi 			    "DMA memory, resetting device", xep->xep_num,
1409993e3fafSRobert Mustacchi 			    xd->xd_slot, xd->xd_port);
1410993e3fafSRobert Mustacchi 			xhci_fm_runtime_reset(xhcip);
1411993e3fafSRobert Mustacchi 			mutex_exit(&xhcip->xhci_lock);
1412993e3fafSRobert Mustacchi 			return (B_FALSE);
1413993e3fafSRobert Mustacchi 		}
1414993e3fafSRobert Mustacchi 
1415993e3fafSRobert Mustacchi 		xhci_transfer_copy(xt, mp->b_rptr, len, B_TRUE);
1416993e3fafSRobert Mustacchi 		mp->b_wptr += len;
1417993e3fafSRobert Mustacchi 	}
1418993e3fafSRobert Mustacchi 	cr = USB_CR_OK;
1419993e3fafSRobert Mustacchi 
1420993e3fafSRobert Mustacchi out:
14212aba3acdSRobert Mustacchi 	/*
14222aba3acdSRobert Mustacchi 	 * Don't use the address from the TRB here. When we're dealing with
14232aba3acdSRobert Mustacchi 	 * event data that will be entirely wrong.
14242aba3acdSRobert Mustacchi 	 */
14252aba3acdSRobert Mustacchi 	VERIFY(xhci_ring_trb_consumed(&xep->xep_ring, xt->xt_trbs_pa[off]));
1426993e3fafSRobert Mustacchi 	rem = list_remove_head(&xep->xep_transfers);
1427993e3fafSRobert Mustacchi 	VERIFY3P(rem, ==, xt);
1428993e3fafSRobert Mustacchi 	mutex_exit(&xhcip->xhci_lock);
1429993e3fafSRobert Mustacchi 
1430993e3fafSRobert Mustacchi 	usba_hcdi_cb(xep->xep_pipe, urp, cr);
1431993e3fafSRobert Mustacchi 	if (periodic == B_TRUE) {
1432993e3fafSRobert Mustacchi 		xhci_endpoint_reschedule_periodic(xhcip, xd, xep, xt);
1433993e3fafSRobert Mustacchi 	} else {
1434993e3fafSRobert Mustacchi 		xhci_transfer_free(xhcip, xt);
1435993e3fafSRobert Mustacchi 	}
1436993e3fafSRobert Mustacchi 
1437993e3fafSRobert Mustacchi 	return (B_TRUE);
1438993e3fafSRobert Mustacchi }
1439993e3fafSRobert Mustacchi 
1440993e3fafSRobert Mustacchi static boolean_t
xhci_endpoint_isoch_callback(xhci_t * xhcip,xhci_device_t * xd,xhci_endpoint_t * xep,xhci_transfer_t * xt,uint_t off,xhci_trb_t * trb)1441993e3fafSRobert Mustacchi xhci_endpoint_isoch_callback(xhci_t *xhcip, xhci_device_t *xd,
14422aba3acdSRobert Mustacchi     xhci_endpoint_t *xep, xhci_transfer_t *xt, uint_t off, xhci_trb_t *trb)
1443993e3fafSRobert Mustacchi {
1444993e3fafSRobert Mustacchi 	int code;
1445993e3fafSRobert Mustacchi 	usb_cr_t cr;
1446993e3fafSRobert Mustacchi 	xhci_transfer_t *rem;
1447993e3fafSRobert Mustacchi 	usb_isoc_pkt_descr_t *desc;
1448993e3fafSRobert Mustacchi 	usb_isoc_req_t *usrp;
1449993e3fafSRobert Mustacchi 
1450993e3fafSRobert Mustacchi 	ASSERT(MUTEX_HELD(&xhcip->xhci_lock));
1451993e3fafSRobert Mustacchi 	ASSERT3S(xep->xep_type, ==, USB_EP_ATTR_ISOCH);
1452993e3fafSRobert Mustacchi 
1453993e3fafSRobert Mustacchi 	code = XHCI_TRB_GET_CODE(LE_32(trb->trb_status));
1454993e3fafSRobert Mustacchi 
1455993e3fafSRobert Mustacchi 	/*
1456993e3fafSRobert Mustacchi 	 * The descriptors that we copy the data from are set up to assume that
1457993e3fafSRobert Mustacchi 	 * everything was OK and we transferred all the requested data.
1458993e3fafSRobert Mustacchi 	 */
1459993e3fafSRobert Mustacchi 	desc = &xt->xt_isoc[off];
1460993e3fafSRobert Mustacchi 	if (code == XHCI_CODE_SHORT_XFER) {
1461993e3fafSRobert Mustacchi 		int residue = XHCI_TRB_REMAIN(LE_32(trb->trb_status));
1462993e3fafSRobert Mustacchi 		desc->isoc_pkt_actual_length -= residue;
1463993e3fafSRobert Mustacchi 	}
1464993e3fafSRobert Mustacchi 
1465993e3fafSRobert Mustacchi 	/*
1466993e3fafSRobert Mustacchi 	 * We don't perform the callback until the very last TRB is returned
1467993e3fafSRobert Mustacchi 	 * here. If we have a TRB report on something else, that means that we
1468993e3fafSRobert Mustacchi 	 * had a short transfer.
1469993e3fafSRobert Mustacchi 	 */
1470993e3fafSRobert Mustacchi 	if (off < xt->xt_ntrbs - 1) {
1471993e3fafSRobert Mustacchi 		mutex_exit(&xhcip->xhci_lock);
1472993e3fafSRobert Mustacchi 		return (B_TRUE);
1473993e3fafSRobert Mustacchi 	}
1474993e3fafSRobert Mustacchi 
1475993e3fafSRobert Mustacchi 	VERIFY(xhci_ring_trb_consumed(&xep->xep_ring, LE_64(trb->trb_addr)));
1476993e3fafSRobert Mustacchi 	rem = list_remove_head(&xep->xep_transfers);
1477993e3fafSRobert Mustacchi 	VERIFY3P(rem, ==, xt);
1478993e3fafSRobert Mustacchi 	mutex_exit(&xhcip->xhci_lock);
1479993e3fafSRobert Mustacchi 
1480993e3fafSRobert Mustacchi 	cr = USB_CR_OK;
1481993e3fafSRobert Mustacchi 
1482993e3fafSRobert Mustacchi 	if (xt->xt_data_tohost == B_TRUE) {
1483993e3fafSRobert Mustacchi 		usb_opaque_t urp;
1484993e3fafSRobert Mustacchi 		urp = xhci_endpoint_dup_periodic(xep, xt, &cr);
1485993e3fafSRobert Mustacchi 		usrp = (usb_isoc_req_t *)urp;
1486993e3fafSRobert Mustacchi 
1487993e3fafSRobert Mustacchi 		if (cr == USB_CR_OK) {
1488993e3fafSRobert Mustacchi 			mblk_t *mp;
1489993e3fafSRobert Mustacchi 			size_t len;
1490993e3fafSRobert Mustacchi 			if (xhci_transfer_sync(xhcip, xt,
1491993e3fafSRobert Mustacchi 			    DDI_DMA_SYNC_FORCPU) != DDI_FM_OK) {
1492993e3fafSRobert Mustacchi 				xhci_error(xhcip, "failed to process "
1493993e3fafSRobert Mustacchi 				    "isochronous transfer callback for "
1494993e3fafSRobert Mustacchi 				    "endpoint %u of device on slot %d and port "
1495993e3fafSRobert Mustacchi 				    "%d: encountered fatal FM error "
1496993e3fafSRobert Mustacchi 				    "synchronizing DMA memory, resetting "
1497993e3fafSRobert Mustacchi 				    "device",
1498993e3fafSRobert Mustacchi 				    xep->xep_num, xd->xd_slot, xd->xd_port);
1499993e3fafSRobert Mustacchi 				xhci_fm_runtime_reset(xhcip);
1500993e3fafSRobert Mustacchi 				mutex_exit(&xhcip->xhci_lock);
1501993e3fafSRobert Mustacchi 				return (B_FALSE);
1502993e3fafSRobert Mustacchi 			}
1503993e3fafSRobert Mustacchi 
1504993e3fafSRobert Mustacchi 			mp = usrp->isoc_data;
1505993e3fafSRobert Mustacchi 			len = xt->xt_buffer.xdb_len;
1506993e3fafSRobert Mustacchi 			xhci_transfer_copy(xt, mp->b_rptr, len, B_TRUE);
1507993e3fafSRobert Mustacchi 			mp->b_wptr += len;
1508993e3fafSRobert Mustacchi 		}
1509993e3fafSRobert Mustacchi 	} else {
1510993e3fafSRobert Mustacchi 		usrp = (usb_isoc_req_t *)xt->xt_usba_req;
1511993e3fafSRobert Mustacchi 	}
1512993e3fafSRobert Mustacchi 
1513993e3fafSRobert Mustacchi 	if (cr == USB_CR_OK) {
1514993e3fafSRobert Mustacchi 		bcopy(xt->xt_isoc, usrp->isoc_pkt_descr,
1515993e3fafSRobert Mustacchi 		    sizeof (usb_isoc_pkt_descr_t) * usrp->isoc_pkts_count);
1516993e3fafSRobert Mustacchi 	}
1517993e3fafSRobert Mustacchi 
1518993e3fafSRobert Mustacchi 	usba_hcdi_cb(xep->xep_pipe, (usb_opaque_t)usrp, cr);
1519993e3fafSRobert Mustacchi 	if (xt->xt_data_tohost == B_TRUE) {
1520993e3fafSRobert Mustacchi 		xhci_endpoint_reschedule_periodic(xhcip, xd, xep, xt);
1521993e3fafSRobert Mustacchi 	} else {
1522993e3fafSRobert Mustacchi 		xhci_transfer_free(xhcip, xt);
1523993e3fafSRobert Mustacchi 	}
1524993e3fafSRobert Mustacchi 
1525993e3fafSRobert Mustacchi 	return (B_TRUE);
1526993e3fafSRobert Mustacchi }
1527993e3fafSRobert Mustacchi 
1528993e3fafSRobert Mustacchi boolean_t
xhci_endpoint_transfer_callback(xhci_t * xhcip,xhci_trb_t * trb)1529993e3fafSRobert Mustacchi xhci_endpoint_transfer_callback(xhci_t *xhcip, xhci_trb_t *trb)
1530993e3fafSRobert Mustacchi {
1531993e3fafSRobert Mustacchi 	boolean_t ret;
15322aba3acdSRobert Mustacchi 	int slot, endpoint, code;
15332aba3acdSRobert Mustacchi 	uint_t off;
1534993e3fafSRobert Mustacchi 	xhci_device_t *xd;
1535993e3fafSRobert Mustacchi 	xhci_endpoint_t *xep;
1536993e3fafSRobert Mustacchi 	xhci_transfer_t *xt;
1537993e3fafSRobert Mustacchi 	boolean_t transfer_done;
1538993e3fafSRobert Mustacchi 
1539993e3fafSRobert Mustacchi 	endpoint = XHCI_TRB_GET_EP(LE_32(trb->trb_flags));
1540993e3fafSRobert Mustacchi 	slot = XHCI_TRB_GET_SLOT(LE_32(trb->trb_flags));
1541993e3fafSRobert Mustacchi 	code = XHCI_TRB_GET_CODE(LE_32(trb->trb_status));
1542993e3fafSRobert Mustacchi 
15432aba3acdSRobert Mustacchi 	switch (code) {
15442aba3acdSRobert Mustacchi 	case XHCI_CODE_RING_UNDERRUN:
15452aba3acdSRobert Mustacchi 	case XHCI_CODE_RING_OVERRUN:
15462aba3acdSRobert Mustacchi 		/*
15472aba3acdSRobert Mustacchi 		 * If we have an ISOC overrun or underrun then there will be no
15482aba3acdSRobert Mustacchi 		 * valid data pointer in the TRB associated with it. Just drive
15492aba3acdSRobert Mustacchi 		 * on.
15502aba3acdSRobert Mustacchi 		 */
15512aba3acdSRobert Mustacchi 		return (B_TRUE);
15522aba3acdSRobert Mustacchi 	case XHCI_CODE_UNDEFINED:
15532aba3acdSRobert Mustacchi 		xhci_error(xhcip, "received transfer trb with undefined fatal "
15542aba3acdSRobert Mustacchi 		    "error: resetting device");
15552aba3acdSRobert Mustacchi 		xhci_fm_runtime_reset(xhcip);
15562aba3acdSRobert Mustacchi 		return (B_FALSE);
15572aba3acdSRobert Mustacchi 	case XHCI_CODE_XFER_STOPPED:
15582aba3acdSRobert Mustacchi 	case XHCI_CODE_XFER_STOPINV:
15592aba3acdSRobert Mustacchi 	case XHCI_CODE_XFER_STOPSHORT:
15602aba3acdSRobert Mustacchi 		/*
15612aba3acdSRobert Mustacchi 		 * This causes us to transition the endpoint to a stopped state.
15622aba3acdSRobert Mustacchi 		 * Each of these indicate a different possible state that we
15632aba3acdSRobert Mustacchi 		 * have to deal with. Effectively we're going to drop it and
15642aba3acdSRobert Mustacchi 		 * leave it up to the consumers to figure out what to do. For
15652aba3acdSRobert Mustacchi 		 * the moment, that's generally okay because stops are only used
15662aba3acdSRobert Mustacchi 		 * in cases where we're cleaning up outstanding reqs, etc.
15672aba3acdSRobert Mustacchi 		 *
15682aba3acdSRobert Mustacchi 		 * We do this before we check for the corresponding transfer as
15692aba3acdSRobert Mustacchi 		 * this will generally be generated by a command issued that's
15702aba3acdSRobert Mustacchi 		 * stopping the ring.
15712aba3acdSRobert Mustacchi 		 */
15722aba3acdSRobert Mustacchi 		return (B_TRUE);
15732aba3acdSRobert Mustacchi 	default:
15742aba3acdSRobert Mustacchi 		break;
15752aba3acdSRobert Mustacchi 	}
15762aba3acdSRobert Mustacchi 
1577993e3fafSRobert Mustacchi 	mutex_enter(&xhcip->xhci_lock);
1578993e3fafSRobert Mustacchi 	xd = xhci_device_lookup_by_slot(xhcip, slot);
1579993e3fafSRobert Mustacchi 	if (xd == NULL) {
1580993e3fafSRobert Mustacchi 		xhci_error(xhcip, "received transfer trb with code %d for "
1581993e3fafSRobert Mustacchi 		    "unknown slot %d and endpoint %d: resetting device", code,
1582993e3fafSRobert Mustacchi 		    slot, endpoint);
1583993e3fafSRobert Mustacchi 		mutex_exit(&xhcip->xhci_lock);
1584993e3fafSRobert Mustacchi 		xhci_fm_runtime_reset(xhcip);
1585993e3fafSRobert Mustacchi 		return (B_FALSE);
1586993e3fafSRobert Mustacchi 	}
1587993e3fafSRobert Mustacchi 
1588993e3fafSRobert Mustacchi 	/*
1589993e3fafSRobert Mustacchi 	 * Endpoint IDs are indexed based on their Device Context Index, which
1590993e3fafSRobert Mustacchi 	 * means that we need to subtract one to get the actual ID that we use.
1591993e3fafSRobert Mustacchi 	 */
1592993e3fafSRobert Mustacchi 	xep = xd->xd_endpoints[endpoint - 1];
1593993e3fafSRobert Mustacchi 	if (xep == NULL) {
1594993e3fafSRobert Mustacchi 		xhci_error(xhcip, "received transfer trb with code %d, slot "
1595993e3fafSRobert Mustacchi 		    "%d, and unknown endpoint %d: resetting device", code,
1596993e3fafSRobert Mustacchi 		    slot, endpoint);
1597993e3fafSRobert Mustacchi 		mutex_exit(&xhcip->xhci_lock);
1598993e3fafSRobert Mustacchi 		xhci_fm_runtime_reset(xhcip);
1599993e3fafSRobert Mustacchi 		return (B_FALSE);
1600993e3fafSRobert Mustacchi 	}
1601993e3fafSRobert Mustacchi 
1602993e3fafSRobert Mustacchi 	/*
16032aba3acdSRobert Mustacchi 	 * The TRB that we recieved may be an event data TRB for a bulk
16042aba3acdSRobert Mustacchi 	 * endpoint, a normal or short completion for any other endpoint or an
16052aba3acdSRobert Mustacchi 	 * error. In all cases, we need to figure out what transfer this
16062aba3acdSRobert Mustacchi 	 * corresponds to. If this is an error, then we need to make sure that
16072aba3acdSRobert Mustacchi 	 * the generating ring has been cleaned up.
16082aba3acdSRobert Mustacchi 	 *
16092aba3acdSRobert Mustacchi 	 * TRBs should be delivered in order, based on the ring. If for some
16102aba3acdSRobert Mustacchi 	 * reason we find something that doesn't add up here, then we need to
16112aba3acdSRobert Mustacchi 	 * assume that something has gone horribly wrong in the system and issue
16122aba3acdSRobert Mustacchi 	 * a runtime reset. We issue the runtime reset rather than just trying
16132aba3acdSRobert Mustacchi 	 * to stop and flush the ring, because it's unclear if we could stop
16142aba3acdSRobert Mustacchi 	 * the ring in time.
1615993e3fafSRobert Mustacchi 	 */
1616993e3fafSRobert Mustacchi 	if ((xt = xhci_endpoint_determine_transfer(xhcip, xep, trb, &off)) ==
1617993e3fafSRobert Mustacchi 	    NULL) {
16182aba3acdSRobert Mustacchi 		xhci_error(xhcip, "received transfer trb with code %d, slot "
16192aba3acdSRobert Mustacchi 		    "%d, and endpoint %d, but does not match current transfer "
16202aba3acdSRobert Mustacchi 		    "for endpoint: resetting device", code, slot, endpoint);
1621993e3fafSRobert Mustacchi 		mutex_exit(&xhcip->xhci_lock);
16222aba3acdSRobert Mustacchi 		xhci_fm_runtime_reset(xhcip);
16232aba3acdSRobert Mustacchi 		return (B_FALSE);
1624993e3fafSRobert Mustacchi 	}
1625993e3fafSRobert Mustacchi 
1626993e3fafSRobert Mustacchi 	transfer_done = B_FALSE;
1627993e3fafSRobert Mustacchi 
1628993e3fafSRobert Mustacchi 	switch (code) {
1629993e3fafSRobert Mustacchi 	case XHCI_CODE_SUCCESS:
1630993e3fafSRobert Mustacchi 	case XHCI_CODE_SHORT_XFER:
1631993e3fafSRobert Mustacchi 		/* Handled by endpoint logic */
1632993e3fafSRobert Mustacchi 		break;
1633993e3fafSRobert Mustacchi 	case XHCI_CODE_STALL:
1634993e3fafSRobert Mustacchi 		/*
1635993e3fafSRobert Mustacchi 		 * This causes us to transition to the halted state;
1636993e3fafSRobert Mustacchi 		 * however, downstream clients are able to handle this just
1637993e3fafSRobert Mustacchi 		 * fine.
1638993e3fafSRobert Mustacchi 		 */
1639993e3fafSRobert Mustacchi 		xep->xep_state |= XHCI_ENDPOINT_HALTED;
1640993e3fafSRobert Mustacchi 		xt->xt_cr = USB_CR_STALL;
1641993e3fafSRobert Mustacchi 		transfer_done = B_TRUE;
1642993e3fafSRobert Mustacchi 		break;
1643993e3fafSRobert Mustacchi 	case XHCI_CODE_BABBLE:
1644993e3fafSRobert Mustacchi 		transfer_done = B_TRUE;
1645993e3fafSRobert Mustacchi 		xt->xt_cr = USB_CR_DATA_OVERRUN;
1646993e3fafSRobert Mustacchi 		xep->xep_state |= XHCI_ENDPOINT_HALTED;
1647993e3fafSRobert Mustacchi 		break;
1648993e3fafSRobert Mustacchi 	case XHCI_CODE_TXERR:
1649993e3fafSRobert Mustacchi 	case XHCI_CODE_SPLITERR:
1650993e3fafSRobert Mustacchi 		transfer_done = B_TRUE;
1651993e3fafSRobert Mustacchi 		xt->xt_cr = USB_CR_DEV_NOT_RESP;
1652993e3fafSRobert Mustacchi 		xep->xep_state |= XHCI_ENDPOINT_HALTED;
1653993e3fafSRobert Mustacchi 		break;
16542aba3acdSRobert Mustacchi 	case XHCI_CODE_BW_OVERRUN:
16552aba3acdSRobert Mustacchi 		transfer_done = B_TRUE;
16562aba3acdSRobert Mustacchi 		xt->xt_cr = USB_CR_DATA_OVERRUN;
16572aba3acdSRobert Mustacchi 		break;
16582aba3acdSRobert Mustacchi 	case XHCI_CODE_DATA_BUF:
16592aba3acdSRobert Mustacchi 		transfer_done = B_TRUE;
16602aba3acdSRobert Mustacchi 		if (xt->xt_data_tohost)
16612aba3acdSRobert Mustacchi 			xt->xt_cr = USB_CR_DATA_OVERRUN;
16622aba3acdSRobert Mustacchi 		else
16632aba3acdSRobert Mustacchi 			xt->xt_cr = USB_CR_DATA_UNDERRUN;
16642aba3acdSRobert Mustacchi 		break;
1665993e3fafSRobert Mustacchi 	default:
1666993e3fafSRobert Mustacchi 		/*
1667993e3fafSRobert Mustacchi 		 * Treat these as general unspecified errors that don't cause a
1668993e3fafSRobert Mustacchi 		 * stop of the ring. Even if it does, a subsequent timeout
1669993e3fafSRobert Mustacchi 		 * should occur which causes us to end up dropping a pipe reset
1670993e3fafSRobert Mustacchi 		 * or at least issuing a reset of the device as part of
1671993e3fafSRobert Mustacchi 		 * quiescing.
1672993e3fafSRobert Mustacchi 		 */
1673993e3fafSRobert Mustacchi 		transfer_done = B_TRUE;
16742aba3acdSRobert Mustacchi 		xt->xt_cr = USB_CR_HC_HARDWARE_ERR;
1675993e3fafSRobert Mustacchi 		break;
1676993e3fafSRobert Mustacchi 	}
1677993e3fafSRobert Mustacchi 
1678993e3fafSRobert Mustacchi 	if (transfer_done == B_TRUE) {
1679993e3fafSRobert Mustacchi 		xhci_transfer_t *alt;
1680993e3fafSRobert Mustacchi 
1681993e3fafSRobert Mustacchi 		alt = list_remove_head(&xep->xep_transfers);
1682993e3fafSRobert Mustacchi 		VERIFY3P(alt, ==, xt);
1683993e3fafSRobert Mustacchi 		mutex_exit(&xhcip->xhci_lock);
1684993e3fafSRobert Mustacchi 		if (xt->xt_usba_req == NULL) {
1685993e3fafSRobert Mustacchi 			usb_opaque_t urp;
1686993e3fafSRobert Mustacchi 
1687993e3fafSRobert Mustacchi 			urp = xhci_endpoint_dup_periodic(xep, xt, &xt->xt_cr);
1688993e3fafSRobert Mustacchi 			usba_hcdi_cb(xep->xep_pipe, urp, xt->xt_cr);
1689993e3fafSRobert Mustacchi 		} else {
1690993e3fafSRobert Mustacchi 			usba_hcdi_cb(xep->xep_pipe,
1691993e3fafSRobert Mustacchi 			    (usb_opaque_t)xt->xt_usba_req, xt->xt_cr);
1692993e3fafSRobert Mustacchi 			xhci_transfer_free(xhcip, xt);
1693993e3fafSRobert Mustacchi 		}
1694993e3fafSRobert Mustacchi 		return (B_TRUE);
1695993e3fafSRobert Mustacchi 	}
1696993e3fafSRobert Mustacchi 
1697993e3fafSRobert Mustacchi 	/*
1698993e3fafSRobert Mustacchi 	 * Process the transfer callback based on the type of endpoint. Each of
1699993e3fafSRobert Mustacchi 	 * these callback functions will end up calling back into USBA via
1700993e3fafSRobert Mustacchi 	 * usba_hcdi_cb() to return transfer information (whether successful or
1701993e3fafSRobert Mustacchi 	 * not). Because we can't hold any locks across a call to that function,
1702993e3fafSRobert Mustacchi 	 * all of these callbacks will drop the xhci_t`xhci_lock by the time
1703993e3fafSRobert Mustacchi 	 * they return. This is why there's no mutex_exit() call before we
1704993e3fafSRobert Mustacchi 	 * return.
1705993e3fafSRobert Mustacchi 	 */
1706993e3fafSRobert Mustacchi 	switch (xep->xep_type) {
1707993e3fafSRobert Mustacchi 	case USB_EP_ATTR_CONTROL:
1708993e3fafSRobert Mustacchi 		ret = xhci_endpoint_control_callback(xhcip, xd, xep, xt, off,
1709993e3fafSRobert Mustacchi 		    trb);
1710993e3fafSRobert Mustacchi 		break;
1711993e3fafSRobert Mustacchi 	case USB_EP_ATTR_BULK:
1712993e3fafSRobert Mustacchi 		ret = xhci_endpoint_norm_callback(xhcip, xd, xep, xt, off, trb);
1713993e3fafSRobert Mustacchi 		break;
1714993e3fafSRobert Mustacchi 	case USB_EP_ATTR_INTR:
1715993e3fafSRobert Mustacchi 		ret = xhci_endpoint_norm_callback(xhcip, xd, xep, xt, off,
1716993e3fafSRobert Mustacchi 		    trb);
1717993e3fafSRobert Mustacchi 		break;
1718993e3fafSRobert Mustacchi 	case USB_EP_ATTR_ISOCH:
1719993e3fafSRobert Mustacchi 		ret = xhci_endpoint_isoch_callback(xhcip, xd, xep, xt, off,
1720993e3fafSRobert Mustacchi 		    trb);
1721993e3fafSRobert Mustacchi 		break;
1722993e3fafSRobert Mustacchi 	default:
1723993e3fafSRobert Mustacchi 		panic("bad endpoint type: %u", xep->xep_type);
1724993e3fafSRobert Mustacchi 	}
1725993e3fafSRobert Mustacchi 
1726993e3fafSRobert Mustacchi 	return (ret);
1727993e3fafSRobert Mustacchi }
1728