xref: /netbsd-src/sys/external/bsd/dwc2/dist/dwc2_hcdqueue.c (revision b378d10e650f70b3025ff0907354b9dad86d7ddb)
1*b378d10eSskrll /*	$NetBSD: dwc2_hcdqueue.c,v 1.16 2021/12/21 09:51:22 skrll Exp $	*/
2244c883eSskrll 
3970b0700Sskrll /*
4970b0700Sskrll  * hcd_queue.c - DesignWare HS OTG Controller host queuing routines
5970b0700Sskrll  *
6970b0700Sskrll  * Copyright (C) 2004-2013 Synopsys, Inc.
7970b0700Sskrll  *
8970b0700Sskrll  * Redistribution and use in source and binary forms, with or without
9970b0700Sskrll  * modification, are permitted provided that the following conditions
10970b0700Sskrll  * are met:
11970b0700Sskrll  * 1. Redistributions of source code must retain the above copyright
12970b0700Sskrll  *    notice, this list of conditions, and the following disclaimer,
13970b0700Sskrll  *    without modification.
14970b0700Sskrll  * 2. Redistributions in binary form must reproduce the above copyright
15970b0700Sskrll  *    notice, this list of conditions and the following disclaimer in the
16970b0700Sskrll  *    documentation and/or other materials provided with the distribution.
17970b0700Sskrll  * 3. The names of the above-listed copyright holders may not be used
18970b0700Sskrll  *    to endorse or promote products derived from this software without
19970b0700Sskrll  *    specific prior written permission.
20970b0700Sskrll  *
21970b0700Sskrll  * ALTERNATIVELY, this software may be distributed under the terms of the
22970b0700Sskrll  * GNU General Public License ("GPL") as published by the Free Software
23970b0700Sskrll  * Foundation; either version 2 of the License, or (at your option) any
24970b0700Sskrll  * later version.
25970b0700Sskrll  *
26970b0700Sskrll  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
27970b0700Sskrll  * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
28970b0700Sskrll  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29970b0700Sskrll  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
30970b0700Sskrll  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
31970b0700Sskrll  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
32970b0700Sskrll  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
33970b0700Sskrll  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
34970b0700Sskrll  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
35970b0700Sskrll  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
36970b0700Sskrll  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
37970b0700Sskrll  */
38970b0700Sskrll 
39970b0700Sskrll /*
40970b0700Sskrll  * This file contains the functions to manage Queue Heads and Queue
41970b0700Sskrll  * Transfer Descriptors for Host mode
42970b0700Sskrll  */
43c8117e49Sskrll 
44c8117e49Sskrll #include <sys/cdefs.h>
45*b378d10eSskrll __KERNEL_RCSID(0, "$NetBSD: dwc2_hcdqueue.c,v 1.16 2021/12/21 09:51:22 skrll Exp $");
46c8117e49Sskrll 
47c8117e49Sskrll #include <sys/types.h>
48c8117e49Sskrll #include <sys/kmem.h>
49c8117e49Sskrll #include <sys/pool.h>
50c8117e49Sskrll 
51c8117e49Sskrll #include <dev/usb/usb.h>
52c8117e49Sskrll #include <dev/usb/usbdi.h>
53c8117e49Sskrll #include <dev/usb/usbdivar.h>
54c8117e49Sskrll #include <dev/usb/usb_mem.h>
55c8117e49Sskrll 
56c8117e49Sskrll #include <machine/param.h>
57c8117e49Sskrll 
58970b0700Sskrll #include <linux/kernel.h>
59970b0700Sskrll 
60c8117e49Sskrll #include <dwc2/dwc2.h>
61c8117e49Sskrll #include <dwc2/dwc2var.h>
62970b0700Sskrll 
63c8117e49Sskrll #include "dwc2_core.h"
64c8117e49Sskrll #include "dwc2_hcd.h"
65c8117e49Sskrll 
66c8117e49Sskrll static u32 dwc2_calc_bus_time(struct dwc2_hsotg *, int, int, int, int);
6746b04be8Ssimonb static void dwc2_wait_timer_fn(void *);
6846b04be8Ssimonb 
6946b04be8Ssimonb /* If we get a NAK, wait this long before retrying */
7046b04be8Ssimonb #define DWC2_RETRY_WAIT_DELAY 1	/* msec */
71970b0700Sskrll 
72970b0700Sskrll /**
73970b0700Sskrll  * dwc2_qh_init() - Initializes a QH structure
74970b0700Sskrll  *
75970b0700Sskrll  * @hsotg: The HCD state structure for the DWC OTG controller
76970b0700Sskrll  * @qh:    The QH to init
77970b0700Sskrll  * @urb:   Holds the information about the device/endpoint needed to initialize
78970b0700Sskrll  *         the QH
79970b0700Sskrll  */
80970b0700Sskrll #define SCHEDULE_SLOP 10
dwc2_qh_init(struct dwc2_hsotg * hsotg,struct dwc2_qh * qh,struct dwc2_hcd_urb * urb)81970b0700Sskrll static void dwc2_qh_init(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh,
82970b0700Sskrll 			 struct dwc2_hcd_urb *urb)
83970b0700Sskrll {
84970b0700Sskrll 	int dev_speed, hub_addr, hub_port;
85970b0700Sskrll 
86970b0700Sskrll 	dev_vdbg(hsotg->dev, "%s()\n", __func__);
87970b0700Sskrll 
88970b0700Sskrll 	/* Initialize QH */
8946b04be8Ssimonb 	qh->hsotg = hsotg;
9046b04be8Ssimonb 	/* XXX timer_setup(&qh->wait_timer, dwc2_wait_timer_fn, 0); */
9146b04be8Ssimonb 	callout_init(&qh->wait_timer, 0);
9246b04be8Ssimonb 	callout_setfunc(&qh->wait_timer, dwc2_wait_timer_fn, qh);
93970b0700Sskrll 	qh->ep_type = dwc2_hcd_get_pipe_type(&urb->pipe_info);
94970b0700Sskrll 	qh->ep_is_in = dwc2_hcd_is_pipe_in(&urb->pipe_info) ? 1 : 0;
95970b0700Sskrll 
96970b0700Sskrll 	qh->data_toggle = DWC2_HC_PID_DATA0;
97970b0700Sskrll 	qh->maxp = dwc2_hcd_get_mps(&urb->pipe_info);
98970b0700Sskrll 	INIT_LIST_HEAD(&qh->qtd_list);
99970b0700Sskrll 	INIT_LIST_HEAD(&qh->qh_list_entry);
100970b0700Sskrll 
101970b0700Sskrll 	/* FS/LS Endpoint on HS Hub, NOT virtual root hub */
102970b0700Sskrll 	dev_speed = dwc2_host_get_speed(hsotg, urb->priv);
103970b0700Sskrll 
104970b0700Sskrll 	dwc2_host_hub_info(hsotg, urb->priv, &hub_addr, &hub_port);
105df4a329dSskrll 	qh->nak_frame = 0xffff;
106970b0700Sskrll 
107970b0700Sskrll 	if ((dev_speed == USB_SPEED_LOW || dev_speed == USB_SPEED_FULL) &&
108970b0700Sskrll 	    hub_addr != 0 && hub_addr != 1) {
109970b0700Sskrll 		dev_vdbg(hsotg->dev,
110970b0700Sskrll 			 "QH init: EP %d: TT found at hub addr %d, for port %d\n",
111970b0700Sskrll 			 dwc2_hcd_get_ep_num(&urb->pipe_info), hub_addr,
112970b0700Sskrll 			 hub_port);
113970b0700Sskrll 		qh->do_split = 1;
114970b0700Sskrll 	}
115970b0700Sskrll 
116970b0700Sskrll 	if (qh->ep_type == USB_ENDPOINT_XFER_INT ||
117970b0700Sskrll 	    qh->ep_type == USB_ENDPOINT_XFER_ISOC) {
118970b0700Sskrll 		/* Compute scheduling parameters once and save them */
119970b0700Sskrll 		u32 hprt, prtspd;
120970b0700Sskrll 
121970b0700Sskrll 		/* Todo: Account for split transfers in the bus time */
122970b0700Sskrll 		int bytecount =
123970b0700Sskrll 			dwc2_hb_mult(qh->maxp) * dwc2_max_packet(qh->maxp);
124970b0700Sskrll 
125c8117e49Sskrll 		qh->usecs = dwc2_calc_bus_time(hsotg, qh->do_split ?
126970b0700Sskrll 				USB_SPEED_HIGH : dev_speed, qh->ep_is_in,
127970b0700Sskrll 				qh->ep_type == USB_ENDPOINT_XFER_ISOC,
128c8117e49Sskrll 				bytecount);
1295064f7beSskrll 
1305064f7beSskrll 		/* Ensure frame_number corresponds to the reality */
1315064f7beSskrll 		hsotg->frame_number = dwc2_hcd_get_frame_number(hsotg);
132970b0700Sskrll 		/* Start in a slightly future (micro)frame */
133970b0700Sskrll 		qh->sched_frame = dwc2_frame_num_inc(hsotg->frame_number,
134970b0700Sskrll 						     SCHEDULE_SLOP);
135970b0700Sskrll 		qh->interval = urb->interval;
136970b0700Sskrll #if 0
137970b0700Sskrll 		/* Increase interrupt polling rate for debugging */
138970b0700Sskrll 		if (qh->ep_type == USB_ENDPOINT_XFER_INT)
139970b0700Sskrll 			qh->interval = 8;
140970b0700Sskrll #endif
141c8117e49Sskrll 		hprt = DWC2_READ_4(hsotg, HPRT0);
142cb22e524Sskrll 		prtspd = (hprt & HPRT0_SPD_MASK) >> HPRT0_SPD_SHIFT;
143970b0700Sskrll 		if (prtspd == HPRT0_SPD_HIGH_SPEED &&
144970b0700Sskrll 		    (dev_speed == USB_SPEED_LOW ||
145970b0700Sskrll 		     dev_speed == USB_SPEED_FULL)) {
146970b0700Sskrll 			qh->interval *= 8;
147970b0700Sskrll 			qh->sched_frame |= 0x7;
148970b0700Sskrll 			qh->start_split_frame = qh->sched_frame;
149970b0700Sskrll 		}
150970b0700Sskrll 		dev_dbg(hsotg->dev, "interval=%d\n", qh->interval);
151970b0700Sskrll 	}
152970b0700Sskrll 
153970b0700Sskrll 	dev_vdbg(hsotg->dev, "DWC OTG HCD QH Initialized\n");
154970b0700Sskrll 	dev_vdbg(hsotg->dev, "DWC OTG HCD QH - qh = %p\n", qh);
155970b0700Sskrll 	dev_vdbg(hsotg->dev, "DWC OTG HCD QH - Device Address = %d\n",
156970b0700Sskrll 		 dwc2_hcd_get_dev_addr(&urb->pipe_info));
157970b0700Sskrll 	dev_vdbg(hsotg->dev, "DWC OTG HCD QH - Endpoint %d, %s\n",
158970b0700Sskrll 		 dwc2_hcd_get_ep_num(&urb->pipe_info),
159970b0700Sskrll 		 dwc2_hcd_is_pipe_in(&urb->pipe_info) ? "IN" : "OUT");
160970b0700Sskrll 
161970b0700Sskrll 	qh->dev_speed = dev_speed;
162970b0700Sskrll 
163e4c22c37Sskrll #ifdef DWC2_DEBUG
164e4c22c37Sskrll 	const char *speed, *type;
165970b0700Sskrll 	switch (dev_speed) {
166970b0700Sskrll 	case USB_SPEED_LOW:
167970b0700Sskrll 		speed = "low";
168970b0700Sskrll 		break;
169970b0700Sskrll 	case USB_SPEED_FULL:
170970b0700Sskrll 		speed = "full";
171970b0700Sskrll 		break;
172970b0700Sskrll 	case USB_SPEED_HIGH:
173970b0700Sskrll 		speed = "high";
174970b0700Sskrll 		break;
175970b0700Sskrll 	default:
176970b0700Sskrll 		speed = "?";
177970b0700Sskrll 		break;
178970b0700Sskrll 	}
179970b0700Sskrll 	dev_vdbg(hsotg->dev, "DWC OTG HCD QH - Speed = %s\n", speed);
180970b0700Sskrll 
181970b0700Sskrll 	switch (qh->ep_type) {
182970b0700Sskrll 	case USB_ENDPOINT_XFER_ISOC:
183970b0700Sskrll 		type = "isochronous";
184970b0700Sskrll 		break;
185970b0700Sskrll 	case USB_ENDPOINT_XFER_INT:
186970b0700Sskrll 		type = "interrupt";
187970b0700Sskrll 		break;
188970b0700Sskrll 	case USB_ENDPOINT_XFER_CONTROL:
189970b0700Sskrll 		type = "control";
190970b0700Sskrll 		break;
191970b0700Sskrll 	case USB_ENDPOINT_XFER_BULK:
192970b0700Sskrll 		type = "bulk";
193970b0700Sskrll 		break;
194970b0700Sskrll 	default:
195970b0700Sskrll 		type = "?";
196970b0700Sskrll 		break;
197970b0700Sskrll 	}
198970b0700Sskrll 
199970b0700Sskrll 	dev_vdbg(hsotg->dev, "DWC OTG HCD QH - Type = %s\n", type);
200e4c22c37Sskrll #endif
201970b0700Sskrll 
202970b0700Sskrll 	if (qh->ep_type == USB_ENDPOINT_XFER_INT) {
203970b0700Sskrll 		dev_vdbg(hsotg->dev, "DWC OTG HCD QH - usecs = %d\n",
204970b0700Sskrll 			 qh->usecs);
205970b0700Sskrll 		dev_vdbg(hsotg->dev, "DWC OTG HCD QH - interval = %d\n",
206970b0700Sskrll 			 qh->interval);
207970b0700Sskrll 	}
208970b0700Sskrll }
209970b0700Sskrll 
210970b0700Sskrll /**
211970b0700Sskrll  * dwc2_hcd_qh_create() - Allocates and initializes a QH
212970b0700Sskrll  *
213970b0700Sskrll  * @hsotg:     The HCD state structure for the DWC OTG controller
214970b0700Sskrll  * @urb:       Holds the information about the device/endpoint needed
215970b0700Sskrll  *             to initialize the QH
216cb22e524Sskrll  * @mem_flags: Flag to do atomic allocation if needed
217970b0700Sskrll  *
218970b0700Sskrll  * Return: Pointer to the newly allocated QH, or NULL on error
219970b0700Sskrll  */
dwc2_hcd_qh_create(struct dwc2_hsotg * hsotg,struct dwc2_hcd_urb * urb,gfp_t mem_flags)2209c7e1469Sskrll struct dwc2_qh *dwc2_hcd_qh_create(struct dwc2_hsotg *hsotg,
221970b0700Sskrll 					  struct dwc2_hcd_urb *urb,
222970b0700Sskrll 					  gfp_t mem_flags)
223970b0700Sskrll {
224c8117e49Sskrll 	struct dwc2_softc *sc = hsotg->hsotg_sc;
225970b0700Sskrll 	struct dwc2_qh *qh;
226970b0700Sskrll 
227970b0700Sskrll 	if (!urb->priv)
228970b0700Sskrll 		return NULL;
229970b0700Sskrll 
230970b0700Sskrll 	/* Allocate memory */
231c8117e49Sskrll 	qh = pool_cache_get(sc->sc_qhpool, PR_NOWAIT);
232970b0700Sskrll 	if (!qh)
233970b0700Sskrll 		return NULL;
234970b0700Sskrll 
235c8117e49Sskrll 	memset(qh, 0, sizeof(*qh));
236970b0700Sskrll 	dwc2_qh_init(hsotg, qh, urb);
237970b0700Sskrll 
238970b0700Sskrll 	if (hsotg->core_params->dma_desc_enable > 0 &&
239970b0700Sskrll 	    dwc2_hcd_qh_init_ddma(hsotg, qh, mem_flags) < 0) {
240970b0700Sskrll 		dwc2_hcd_qh_free(hsotg, qh);
241970b0700Sskrll 		return NULL;
242970b0700Sskrll 	}
243970b0700Sskrll 
244970b0700Sskrll 	return qh;
245970b0700Sskrll }
246970b0700Sskrll 
247970b0700Sskrll /**
248970b0700Sskrll  * dwc2_hcd_qh_free() - Frees the QH
249970b0700Sskrll  *
250970b0700Sskrll  * @hsotg: HCD instance
251970b0700Sskrll  * @qh:    The QH to free
252970b0700Sskrll  *
253970b0700Sskrll  * QH should already be removed from the list. QTD list should already be empty
254970b0700Sskrll  * if called from URB Dequeue.
255970b0700Sskrll  *
256970b0700Sskrll  * Must NOT be called with interrupt disabled or spinlock held
257970b0700Sskrll  */
dwc2_hcd_qh_free(struct dwc2_hsotg * hsotg,struct dwc2_qh * qh)258970b0700Sskrll void dwc2_hcd_qh_free(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh)
259970b0700Sskrll {
260c8117e49Sskrll 	struct dwc2_softc *sc = hsotg->hsotg_sc;
26146b04be8Ssimonb 
26246b04be8Ssimonb 	/*
26346b04be8Ssimonb 	 * We don't have the lock so we can safely wait until the wait timer
26446b04be8Ssimonb 	 * finishes.  Of course, at this point in time we'd better have set
26546b04be8Ssimonb 	 * wait_timer_active to false so if this timer was still pending it
26646b04be8Ssimonb 	 * won't do anything anyway, but we want it to finish before we free
26746b04be8Ssimonb 	 * memory.
26846b04be8Ssimonb 	 */
26946b04be8Ssimonb 	/* XXX del_timer_sync(&qh->wait_timer); */
27046b04be8Ssimonb 	callout_destroy(&qh->wait_timer);	/* XXX need to callout_halt() first? */
27146b04be8Ssimonb 
2725064f7beSskrll 	if (qh->desc_list) {
273970b0700Sskrll 		dwc2_hcd_qh_free_ddma(hsotg, qh);
274970b0700Sskrll 	} else if (qh->dw_align_buf) {
275*b378d10eSskrll 		usb_freemem(&qh->dw_align_buf_usbdma);
2769c7e1469Sskrll  		qh->dw_align_buf_dma = (dma_addr_t)0;
277970b0700Sskrll 	}
278970b0700Sskrll 
279c8117e49Sskrll 	pool_cache_put(sc->sc_qhpool, qh);
280970b0700Sskrll }
281970b0700Sskrll 
282970b0700Sskrll /**
283970b0700Sskrll  * dwc2_periodic_channel_available() - Checks that a channel is available for a
284970b0700Sskrll  * periodic transfer
285970b0700Sskrll  *
286970b0700Sskrll  * @hsotg: The HCD state structure for the DWC OTG controller
287970b0700Sskrll  *
288cb22e524Sskrll  * Return: 0 if successful, negative error code otherwise
289970b0700Sskrll  */
dwc2_periodic_channel_available(struct dwc2_hsotg * hsotg)290970b0700Sskrll static int dwc2_periodic_channel_available(struct dwc2_hsotg *hsotg)
291970b0700Sskrll {
292970b0700Sskrll 	/*
293cb22e524Sskrll 	 * Currently assuming that there is a dedicated host channel for
294970b0700Sskrll 	 * each periodic transaction plus at least one host channel for
295970b0700Sskrll 	 * non-periodic transactions
296970b0700Sskrll 	 */
297970b0700Sskrll 	int status;
298970b0700Sskrll 	int num_channels;
299970b0700Sskrll 
300970b0700Sskrll 	num_channels = hsotg->core_params->host_channels;
301970b0700Sskrll 	if (hsotg->periodic_channels + hsotg->non_periodic_channels <
302970b0700Sskrll 								num_channels
303970b0700Sskrll 	    && hsotg->periodic_channels < num_channels - 1) {
304970b0700Sskrll 		status = 0;
305970b0700Sskrll 	} else {
306970b0700Sskrll 		dev_dbg(hsotg->dev,
307970b0700Sskrll 			"%s: Total channels: %d, Periodic: %d, "
308970b0700Sskrll 			"Non-periodic: %d\n", __func__, num_channels,
309970b0700Sskrll 			hsotg->periodic_channels, hsotg->non_periodic_channels);
310970b0700Sskrll 		status = -ENOSPC;
311970b0700Sskrll 	}
312970b0700Sskrll 
313970b0700Sskrll 	return status;
314970b0700Sskrll }
315970b0700Sskrll 
316970b0700Sskrll /**
317970b0700Sskrll  * dwc2_check_periodic_bandwidth() - Checks that there is sufficient bandwidth
318970b0700Sskrll  * for the specified QH in the periodic schedule
319970b0700Sskrll  *
320970b0700Sskrll  * @hsotg: The HCD state structure for the DWC OTG controller
321970b0700Sskrll  * @qh:    QH containing periodic bandwidth required
322970b0700Sskrll  *
323970b0700Sskrll  * Return: 0 if successful, negative error code otherwise
324970b0700Sskrll  *
325970b0700Sskrll  * For simplicity, this calculation assumes that all the transfers in the
326970b0700Sskrll  * periodic schedule may occur in the same (micro)frame
327970b0700Sskrll  */
dwc2_check_periodic_bandwidth(struct dwc2_hsotg * hsotg,struct dwc2_qh * qh)328970b0700Sskrll static int dwc2_check_periodic_bandwidth(struct dwc2_hsotg *hsotg,
329970b0700Sskrll 					 struct dwc2_qh *qh)
330970b0700Sskrll {
331970b0700Sskrll 	int status;
332970b0700Sskrll 	s16 max_claimed_usecs;
333970b0700Sskrll 
334970b0700Sskrll 	status = 0;
335970b0700Sskrll 
336970b0700Sskrll 	if (qh->dev_speed == USB_SPEED_HIGH || qh->do_split) {
337970b0700Sskrll 		/*
338970b0700Sskrll 		 * High speed mode
339970b0700Sskrll 		 * Max periodic usecs is 80% x 125 usec = 100 usec
340970b0700Sskrll 		 */
341970b0700Sskrll 		max_claimed_usecs = 100 - qh->usecs;
342970b0700Sskrll 	} else {
343970b0700Sskrll 		/*
344970b0700Sskrll 		 * Full speed mode
345970b0700Sskrll 		 * Max periodic usecs is 90% x 1000 usec = 900 usec
346970b0700Sskrll 		 */
347970b0700Sskrll 		max_claimed_usecs = 900 - qh->usecs;
348970b0700Sskrll 	}
349970b0700Sskrll 
350970b0700Sskrll 	if (hsotg->periodic_usecs > max_claimed_usecs) {
351970b0700Sskrll 		dev_err(hsotg->dev,
352970b0700Sskrll 			"%s: already claimed usecs %d, required usecs %d\n",
353970b0700Sskrll 			__func__, hsotg->periodic_usecs, qh->usecs);
354970b0700Sskrll 		status = -ENOSPC;
355970b0700Sskrll 	}
356970b0700Sskrll 
357970b0700Sskrll 	return status;
358970b0700Sskrll }
359970b0700Sskrll 
360970b0700Sskrll /**
361970b0700Sskrll  * Microframe scheduler
362970b0700Sskrll  * track the total use in hsotg->frame_usecs
363970b0700Sskrll  * keep each qh use in qh->frame_usecs
364970b0700Sskrll  * when surrendering the qh then donate the time back
365970b0700Sskrll  */
366970b0700Sskrll static const unsigned short max_uframe_usecs[] = {
367970b0700Sskrll 	100, 100, 100, 100, 100, 100, 30, 0
368970b0700Sskrll };
369970b0700Sskrll 
dwc2_hcd_init_usecs(struct dwc2_hsotg * hsotg)370970b0700Sskrll void dwc2_hcd_init_usecs(struct dwc2_hsotg *hsotg)
371970b0700Sskrll {
372970b0700Sskrll 	int i;
373970b0700Sskrll 
374970b0700Sskrll 	for (i = 0; i < 8; i++)
375970b0700Sskrll 		hsotg->frame_usecs[i] = max_uframe_usecs[i];
376970b0700Sskrll }
377970b0700Sskrll 
dwc2_find_single_uframe(struct dwc2_hsotg * hsotg,struct dwc2_qh * qh)378970b0700Sskrll static int dwc2_find_single_uframe(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh)
379970b0700Sskrll {
380970b0700Sskrll 	unsigned short utime = qh->usecs;
381661a0168Sskrll 	int i;
382970b0700Sskrll 
383661a0168Sskrll 	for (i = 0; i < 8; i++) {
384970b0700Sskrll 		/* At the start hsotg->frame_usecs[i] = max_uframe_usecs[i] */
385970b0700Sskrll 		if (utime <= hsotg->frame_usecs[i]) {
386970b0700Sskrll 			hsotg->frame_usecs[i] -= utime;
387970b0700Sskrll 			qh->frame_usecs[i] += utime;
388661a0168Sskrll 			return i;
389970b0700Sskrll 		}
390970b0700Sskrll 	}
391f913003cSskrll 	return -ENOSPC;
392970b0700Sskrll }
393970b0700Sskrll 
394970b0700Sskrll /*
395970b0700Sskrll  * use this for FS apps that can span multiple uframes
396970b0700Sskrll  */
dwc2_find_multi_uframe(struct dwc2_hsotg * hsotg,struct dwc2_qh * qh)397970b0700Sskrll static int dwc2_find_multi_uframe(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh)
398970b0700Sskrll {
399970b0700Sskrll 	unsigned short utime = qh->usecs;
400970b0700Sskrll 	unsigned short xtime;
401661a0168Sskrll 	int t_left;
402661a0168Sskrll 	int i;
403970b0700Sskrll 	int j;
404661a0168Sskrll 	int k;
405970b0700Sskrll 
406661a0168Sskrll 	for (i = 0; i < 8; i++) {
407661a0168Sskrll 		if (hsotg->frame_usecs[i] <= 0)
408970b0700Sskrll 			continue;
409970b0700Sskrll 
410970b0700Sskrll 		/*
411970b0700Sskrll 		 * we need n consecutive slots so use j as a start slot
412970b0700Sskrll 		 * j plus j+1 must be enough time (for now)
413970b0700Sskrll 		 */
414970b0700Sskrll 		xtime = hsotg->frame_usecs[i];
415970b0700Sskrll 		for (j = i + 1; j < 8; j++) {
416970b0700Sskrll 			/*
417970b0700Sskrll 			 * if we add this frame remaining time to xtime we may
418970b0700Sskrll 			 * be OK, if not we need to test j for a complete frame
419970b0700Sskrll 			 */
420970b0700Sskrll 			if (xtime + hsotg->frame_usecs[j] < utime) {
421970b0700Sskrll 				if (hsotg->frame_usecs[j] <
422661a0168Sskrll 							max_uframe_usecs[j])
423661a0168Sskrll 					continue;
424970b0700Sskrll 			}
425970b0700Sskrll 			if (xtime >= utime) {
426661a0168Sskrll 				t_left = utime;
427661a0168Sskrll 				for (k = i; k < 8; k++) {
428661a0168Sskrll 					t_left -= hsotg->frame_usecs[k];
429661a0168Sskrll 					if (t_left <= 0) {
430661a0168Sskrll 						qh->frame_usecs[k] +=
431661a0168Sskrll 							hsotg->frame_usecs[k]
432661a0168Sskrll 								+ t_left;
433661a0168Sskrll 						hsotg->frame_usecs[k] = -t_left;
434661a0168Sskrll 						return i;
435661a0168Sskrll 					} else {
436661a0168Sskrll 						qh->frame_usecs[k] +=
437661a0168Sskrll 							hsotg->frame_usecs[k];
438661a0168Sskrll 						hsotg->frame_usecs[k] = 0;
439661a0168Sskrll 					}
440661a0168Sskrll 				}
441970b0700Sskrll 			}
442970b0700Sskrll 			/* add the frame time to x time */
443970b0700Sskrll 			xtime += hsotg->frame_usecs[j];
444970b0700Sskrll 			/* we must have a fully available next frame or break */
445970b0700Sskrll 			if (xtime < utime &&
446661a0168Sskrll 			   hsotg->frame_usecs[j] == max_uframe_usecs[j])
447661a0168Sskrll 				continue;
448970b0700Sskrll 		}
449970b0700Sskrll 	}
450f913003cSskrll 	return -ENOSPC;
451970b0700Sskrll }
452970b0700Sskrll 
dwc2_find_uframe(struct dwc2_hsotg * hsotg,struct dwc2_qh * qh)453970b0700Sskrll static int dwc2_find_uframe(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh)
454970b0700Sskrll {
455970b0700Sskrll 	int ret;
456970b0700Sskrll 
457970b0700Sskrll 	if (qh->dev_speed == USB_SPEED_HIGH) {
458970b0700Sskrll 		/* if this is a hs transaction we need a full frame */
459970b0700Sskrll 		ret = dwc2_find_single_uframe(hsotg, qh);
460970b0700Sskrll 	} else {
461970b0700Sskrll 		/*
462970b0700Sskrll 		 * if this is a fs transaction we may need a sequence
463970b0700Sskrll 		 * of frames
464970b0700Sskrll 		 */
465970b0700Sskrll 		ret = dwc2_find_multi_uframe(hsotg, qh);
466970b0700Sskrll 	}
467970b0700Sskrll 	return ret;
468970b0700Sskrll }
469970b0700Sskrll 
470970b0700Sskrll /**
471970b0700Sskrll  * dwc2_check_max_xfer_size() - Checks that the max transfer size allowed in a
472970b0700Sskrll  * host channel is large enough to handle the maximum data transfer in a single
473970b0700Sskrll  * (micro)frame for a periodic transfer
474970b0700Sskrll  *
475970b0700Sskrll  * @hsotg: The HCD state structure for the DWC OTG controller
476970b0700Sskrll  * @qh:    QH for a periodic endpoint
477970b0700Sskrll  *
478970b0700Sskrll  * Return: 0 if successful, negative error code otherwise
479970b0700Sskrll  */
dwc2_check_max_xfer_size(struct dwc2_hsotg * hsotg,struct dwc2_qh * qh)480970b0700Sskrll static int dwc2_check_max_xfer_size(struct dwc2_hsotg *hsotg,
481970b0700Sskrll 				    struct dwc2_qh *qh)
482970b0700Sskrll {
483970b0700Sskrll 	u32 max_xfer_size;
484970b0700Sskrll 	u32 max_channel_xfer_size;
485970b0700Sskrll 	int status = 0;
486970b0700Sskrll 
487970b0700Sskrll 	max_xfer_size = dwc2_max_packet(qh->maxp) * dwc2_hb_mult(qh->maxp);
488970b0700Sskrll 	max_channel_xfer_size = hsotg->core_params->max_transfer_size;
489970b0700Sskrll 
490970b0700Sskrll 	if (max_xfer_size > max_channel_xfer_size) {
491970b0700Sskrll 		dev_err(hsotg->dev,
492970b0700Sskrll 			"%s: Periodic xfer length %d > max xfer length for channel %d\n",
493970b0700Sskrll 			__func__, max_xfer_size, max_channel_xfer_size);
494970b0700Sskrll 		status = -ENOSPC;
495970b0700Sskrll 	}
496970b0700Sskrll 
497970b0700Sskrll 	return status;
498970b0700Sskrll }
499970b0700Sskrll 
500970b0700Sskrll /**
501970b0700Sskrll  * dwc2_schedule_periodic() - Schedules an interrupt or isochronous transfer in
502970b0700Sskrll  * the periodic schedule
503970b0700Sskrll  *
504970b0700Sskrll  * @hsotg: The HCD state structure for the DWC OTG controller
505970b0700Sskrll  * @qh:    QH for the periodic transfer. The QH should already contain the
506970b0700Sskrll  *         scheduling information.
507970b0700Sskrll  *
508970b0700Sskrll  * Return: 0 if successful, negative error code otherwise
509970b0700Sskrll  */
dwc2_schedule_periodic(struct dwc2_hsotg * hsotg,struct dwc2_qh * qh)510970b0700Sskrll static int dwc2_schedule_periodic(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh)
511970b0700Sskrll {
512970b0700Sskrll 	int status;
513970b0700Sskrll 
514970b0700Sskrll 	if (hsotg->core_params->uframe_sched > 0) {
515970b0700Sskrll 		int frame = -1;
516970b0700Sskrll 
517970b0700Sskrll 		status = dwc2_find_uframe(hsotg, qh);
518970b0700Sskrll 		if (status == 0)
519970b0700Sskrll 			frame = 7;
520970b0700Sskrll 		else if (status > 0)
521970b0700Sskrll 			frame = status - 1;
522970b0700Sskrll 
523970b0700Sskrll 		/* Set the new frame up */
524f913003cSskrll 		if (frame >= 0) {
525970b0700Sskrll 			qh->sched_frame &= ~0x7;
526970b0700Sskrll 			qh->sched_frame |= (frame & 7);
527970b0700Sskrll 		}
528970b0700Sskrll 
529f913003cSskrll 		if (status > 0)
530970b0700Sskrll 			status = 0;
531970b0700Sskrll 	} else {
532970b0700Sskrll 		status = dwc2_periodic_channel_available(hsotg);
533970b0700Sskrll 		if (status) {
534970b0700Sskrll 			dev_info(hsotg->dev,
535970b0700Sskrll 				 "%s: No host channel available for periodic transfer\n",
536970b0700Sskrll 				 __func__);
537970b0700Sskrll 			return status;
538970b0700Sskrll 		}
539970b0700Sskrll 
540970b0700Sskrll 		status = dwc2_check_periodic_bandwidth(hsotg, qh);
541970b0700Sskrll 	}
542970b0700Sskrll 
543970b0700Sskrll 	if (status) {
544970b0700Sskrll 		dev_dbg(hsotg->dev,
545970b0700Sskrll 			"%s: Insufficient periodic bandwidth for periodic transfer\n",
546970b0700Sskrll 			__func__);
547970b0700Sskrll 		return status;
548970b0700Sskrll 	}
549970b0700Sskrll 
550970b0700Sskrll 	status = dwc2_check_max_xfer_size(hsotg, qh);
551970b0700Sskrll 	if (status) {
552970b0700Sskrll 		dev_dbg(hsotg->dev,
553970b0700Sskrll 			"%s: Channel max transfer size too small for periodic transfer\n",
554970b0700Sskrll 			__func__);
555970b0700Sskrll 		return status;
556970b0700Sskrll 	}
557970b0700Sskrll 
558cb22e524Sskrll 	if (hsotg->core_params->dma_desc_enable > 0)
559970b0700Sskrll 		/* Don't rely on SOF and start in ready schedule */
560970b0700Sskrll 		list_add_tail(&qh->qh_list_entry, &hsotg->periodic_sched_ready);
561cb22e524Sskrll 	else
562970b0700Sskrll 		/* Always start in inactive schedule */
563970b0700Sskrll 		list_add_tail(&qh->qh_list_entry,
564970b0700Sskrll 			      &hsotg->periodic_sched_inactive);
565970b0700Sskrll 
566970b0700Sskrll 	if (hsotg->core_params->uframe_sched <= 0)
567970b0700Sskrll 		/* Reserve periodic channel */
568970b0700Sskrll 		hsotg->periodic_channels++;
569970b0700Sskrll 
570970b0700Sskrll 	/* Update claimed usecs per (micro)frame */
571970b0700Sskrll 	hsotg->periodic_usecs += qh->usecs;
572970b0700Sskrll 
573970b0700Sskrll 	return status;
574970b0700Sskrll }
575970b0700Sskrll 
576970b0700Sskrll /**
577970b0700Sskrll  * dwc2_deschedule_periodic() - Removes an interrupt or isochronous transfer
578970b0700Sskrll  * from the periodic schedule
579970b0700Sskrll  *
580970b0700Sskrll  * @hsotg: The HCD state structure for the DWC OTG controller
581970b0700Sskrll  * @qh:	   QH for the periodic transfer
582970b0700Sskrll  */
dwc2_deschedule_periodic(struct dwc2_hsotg * hsotg,struct dwc2_qh * qh)583970b0700Sskrll static void dwc2_deschedule_periodic(struct dwc2_hsotg *hsotg,
584970b0700Sskrll 				     struct dwc2_qh *qh)
585970b0700Sskrll {
586970b0700Sskrll 	int i;
587970b0700Sskrll 
588970b0700Sskrll 	list_del_init(&qh->qh_list_entry);
589970b0700Sskrll 
590970b0700Sskrll 	/* Update claimed usecs per (micro)frame */
591970b0700Sskrll 	hsotg->periodic_usecs -= qh->usecs;
592970b0700Sskrll 
593970b0700Sskrll 	if (hsotg->core_params->uframe_sched > 0) {
594970b0700Sskrll 		for (i = 0; i < 8; i++) {
595970b0700Sskrll 			hsotg->frame_usecs[i] += qh->frame_usecs[i];
596970b0700Sskrll 			qh->frame_usecs[i] = 0;
597970b0700Sskrll 		}
598970b0700Sskrll 	} else {
599970b0700Sskrll 		/* Release periodic channel reservation */
600970b0700Sskrll 		hsotg->periodic_channels--;
601970b0700Sskrll 	}
602970b0700Sskrll }
603970b0700Sskrll 
604970b0700Sskrll /**
60546b04be8Ssimonb  * dwc2_wait_timer_fn() - Timer function to re-queue after waiting
60646b04be8Ssimonb  *
60746b04be8Ssimonb  * As per the spec, a NAK indicates that "a function is temporarily unable to
60846b04be8Ssimonb  * transmit or receive data, but will eventually be able to do so without need
60946b04be8Ssimonb  * of host intervention".
61046b04be8Ssimonb  *
61146b04be8Ssimonb  * That means that when we encounter a NAK we're supposed to retry.
61246b04be8Ssimonb  *
61346b04be8Ssimonb  * ...but if we retry right away (from the interrupt handler that saw the NAK)
61446b04be8Ssimonb  * then we can end up with an interrupt storm (if the other side keeps NAKing
61546b04be8Ssimonb  * us) because on slow enough CPUs it could take us longer to get out of the
61646b04be8Ssimonb  * interrupt routine than it takes for the device to send another NAK.  That
61746b04be8Ssimonb  * leads to a constant stream of NAK interrupts and the CPU locks.
61846b04be8Ssimonb  *
61946b04be8Ssimonb  * ...so instead of retrying right away in the case of a NAK we'll set a timer
62046b04be8Ssimonb  * to retry some time later.  This function handles that timer and moves the
62146b04be8Ssimonb  * qh back to the "inactive" list, then queues transactions.
62246b04be8Ssimonb  *
62346b04be8Ssimonb  * @t: Pointer to wait_timer in a qh.
62446b04be8Ssimonb  */
dwc2_wait_timer_fn(void * arg)62546b04be8Ssimonb static void dwc2_wait_timer_fn(void *arg)
62646b04be8Ssimonb {
62746b04be8Ssimonb 	struct dwc2_qh *qh = arg;
62846b04be8Ssimonb 	struct dwc2_hsotg *hsotg = qh->hsotg;
62946b04be8Ssimonb 	unsigned long flags;
63046b04be8Ssimonb 
63146b04be8Ssimonb 	spin_lock_irqsave(&hsotg->lock, flags);
63246b04be8Ssimonb 
63346b04be8Ssimonb 	/*
63446b04be8Ssimonb 	 * We'll set wait_timer_cancel to true if we want to cancel this
63546b04be8Ssimonb 	 * operation in dwc2_hcd_qh_unlink().
63646b04be8Ssimonb 	 */
63746b04be8Ssimonb 	if (!qh->wait_timer_cancel) {
63846b04be8Ssimonb 		enum dwc2_transaction_type tr_type;
63946b04be8Ssimonb 
64046b04be8Ssimonb 		qh->want_wait = false;
64146b04be8Ssimonb 
64246b04be8Ssimonb 		list_move(&qh->qh_list_entry,
64346b04be8Ssimonb 			  &hsotg->non_periodic_sched_inactive);
64446b04be8Ssimonb 
64546b04be8Ssimonb 		tr_type = dwc2_hcd_select_transactions(hsotg);
64646b04be8Ssimonb 		if (tr_type != DWC2_TRANSACTION_NONE)
64746b04be8Ssimonb 			dwc2_hcd_queue_transactions(hsotg, tr_type);
64846b04be8Ssimonb 	}
64946b04be8Ssimonb 
65046b04be8Ssimonb 	spin_unlock_irqrestore(&hsotg->lock, flags);
65146b04be8Ssimonb }
65246b04be8Ssimonb 
65346b04be8Ssimonb /**
654970b0700Sskrll  * dwc2_hcd_qh_add() - Adds a QH to either the non periodic or periodic
655970b0700Sskrll  * schedule if it is not already in the schedule. If the QH is already in
656970b0700Sskrll  * the schedule, no action is taken.
657970b0700Sskrll  *
658970b0700Sskrll  * @hsotg: The HCD state structure for the DWC OTG controller
659970b0700Sskrll  * @qh:    The QH to add
660970b0700Sskrll  *
661970b0700Sskrll  * Return: 0 if successful, negative error code otherwise
662970b0700Sskrll  */
dwc2_hcd_qh_add(struct dwc2_hsotg * hsotg,struct dwc2_qh * qh)663970b0700Sskrll int dwc2_hcd_qh_add(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh)
664970b0700Sskrll {
665f913003cSskrll 	int status;
666970b0700Sskrll 	u32 intr_mask;
667970b0700Sskrll 
668970b0700Sskrll 	if (dbg_qh(qh))
669970b0700Sskrll 		dev_vdbg(hsotg->dev, "%s()\n", __func__);
670970b0700Sskrll 
671970b0700Sskrll 	if (!list_empty(&qh->qh_list_entry))
672970b0700Sskrll 		/* QH already in a schedule */
673f913003cSskrll 		return 0;
674970b0700Sskrll 
6755064f7beSskrll 	if (!dwc2_frame_num_le(qh->sched_frame, hsotg->frame_number) &&
6765064f7beSskrll 			!hsotg->frame_number) {
6775064f7beSskrll 		dev_dbg(hsotg->dev,
6785064f7beSskrll 				"reset frame number counter\n");
6795064f7beSskrll 		qh->sched_frame = dwc2_frame_num_inc(hsotg->frame_number,
6805064f7beSskrll 				SCHEDULE_SLOP);
6815064f7beSskrll 	}
6825064f7beSskrll 
683970b0700Sskrll 	/* Add the new QH to the appropriate schedule */
684970b0700Sskrll 	if (dwc2_qh_is_non_per(qh)) {
68546b04be8Ssimonb 		if (qh->want_wait) {
68646b04be8Ssimonb 			list_add_tail(&qh->qh_list_entry,
68746b04be8Ssimonb 				      &hsotg->non_periodic_sched_waiting);
68846b04be8Ssimonb 			qh->wait_timer_cancel = false;
68946b04be8Ssimonb 			/* XXX mod_timer(&qh->wait_timer,
69046b04be8Ssimonb 				  jiffies + DWC2_RETRY_WAIT_DELAY + 1); */
69146b04be8Ssimonb 			callout_schedule(&qh->wait_timer,
69246b04be8Ssimonb 			    mstohz(DWC2_RETRY_WAIT_DELAY));
69346b04be8Ssimonb 		} else {
694970b0700Sskrll 			list_add_tail(&qh->qh_list_entry,
695970b0700Sskrll 				      &hsotg->non_periodic_sched_inactive);
69646b04be8Ssimonb 		}
697f913003cSskrll 		return 0;
698f913003cSskrll 	}
6999c7e1469Sskrll 
700970b0700Sskrll 	status = dwc2_schedule_periodic(hsotg, qh);
701f913003cSskrll 	if (status)
702f913003cSskrll 		return status;
703970b0700Sskrll 	if (!hsotg->periodic_qh_count) {
704c8117e49Sskrll 		intr_mask = DWC2_READ_4(hsotg, GINTMSK);
705970b0700Sskrll 		intr_mask |= GINTSTS_SOF;
706c8117e49Sskrll 		DWC2_WRITE_4(hsotg, GINTMSK, intr_mask);
707970b0700Sskrll 	}
708970b0700Sskrll 	hsotg->periodic_qh_count++;
709970b0700Sskrll 
710f913003cSskrll 	return 0;
711970b0700Sskrll }
712970b0700Sskrll 
713970b0700Sskrll /**
714970b0700Sskrll  * dwc2_hcd_qh_unlink() - Removes a QH from either the non-periodic or periodic
715970b0700Sskrll  * schedule. Memory is not freed.
716970b0700Sskrll  *
717970b0700Sskrll  * @hsotg: The HCD state structure
718970b0700Sskrll  * @qh:    QH to remove from schedule
719970b0700Sskrll  */
dwc2_hcd_qh_unlink(struct dwc2_hsotg * hsotg,struct dwc2_qh * qh)720970b0700Sskrll void dwc2_hcd_qh_unlink(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh)
721970b0700Sskrll {
722970b0700Sskrll 	u32 intr_mask;
723970b0700Sskrll 
724970b0700Sskrll 	dev_vdbg(hsotg->dev, "%s()\n", __func__);
725970b0700Sskrll 
72646b04be8Ssimonb 	/* If the wait_timer is pending, this will stop it from acting */
72746b04be8Ssimonb 	qh->wait_timer_cancel = true;
72846b04be8Ssimonb 
729970b0700Sskrll 	if (list_empty(&qh->qh_list_entry))
730970b0700Sskrll 		/* QH is not in a schedule */
731970b0700Sskrll 		return;
732970b0700Sskrll 
733970b0700Sskrll 	if (dwc2_qh_is_non_per(qh)) {
734970b0700Sskrll 		if (hsotg->non_periodic_qh_ptr == &qh->qh_list_entry)
735970b0700Sskrll 			hsotg->non_periodic_qh_ptr =
736970b0700Sskrll 					hsotg->non_periodic_qh_ptr->next;
737970b0700Sskrll 		list_del_init(&qh->qh_list_entry);
738f913003cSskrll 		return;
739f913003cSskrll 	}
7409c7e1469Sskrll 
741970b0700Sskrll 	dwc2_deschedule_periodic(hsotg, qh);
742970b0700Sskrll 	hsotg->periodic_qh_count--;
743970b0700Sskrll 	if (!hsotg->periodic_qh_count) {
744c8117e49Sskrll 		intr_mask = DWC2_READ_4(hsotg, GINTMSK);
745970b0700Sskrll 		intr_mask &= ~GINTSTS_SOF;
746c8117e49Sskrll 		DWC2_WRITE_4(hsotg, GINTMSK, intr_mask);
747970b0700Sskrll 	}
748970b0700Sskrll }
749970b0700Sskrll 
750970b0700Sskrll /*
751970b0700Sskrll  * Schedule the next continuing periodic split transfer
752970b0700Sskrll  */
dwc2_sched_periodic_split(struct dwc2_hsotg * hsotg,struct dwc2_qh * qh,u16 frame_number,int sched_next_periodic_split)753970b0700Sskrll static void dwc2_sched_periodic_split(struct dwc2_hsotg *hsotg,
754970b0700Sskrll 				      struct dwc2_qh *qh, u16 frame_number,
755970b0700Sskrll 				      int sched_next_periodic_split)
756970b0700Sskrll {
757970b0700Sskrll 	u16 incr;
758970b0700Sskrll 
759970b0700Sskrll 	if (sched_next_periodic_split) {
760970b0700Sskrll 		qh->sched_frame = frame_number;
761970b0700Sskrll 		incr = dwc2_frame_num_inc(qh->start_split_frame, 1);
762970b0700Sskrll 		if (dwc2_frame_num_le(frame_number, incr)) {
763970b0700Sskrll 			/*
764970b0700Sskrll 			 * Allow one frame to elapse after start split
765970b0700Sskrll 			 * microframe before scheduling complete split, but
766970b0700Sskrll 			 * DON'T if we are doing the next start split in the
767970b0700Sskrll 			 * same frame for an ISOC out
768970b0700Sskrll 			 */
769970b0700Sskrll 			if (qh->ep_type != USB_ENDPOINT_XFER_ISOC ||
770970b0700Sskrll 			    qh->ep_is_in != 0) {
771970b0700Sskrll 				qh->sched_frame =
772970b0700Sskrll 					dwc2_frame_num_inc(qh->sched_frame, 1);
773970b0700Sskrll 			}
774970b0700Sskrll 		}
775970b0700Sskrll 	} else {
776970b0700Sskrll 		qh->sched_frame = dwc2_frame_num_inc(qh->start_split_frame,
777970b0700Sskrll 						     qh->interval);
778970b0700Sskrll 		if (dwc2_frame_num_le(qh->sched_frame, frame_number))
779970b0700Sskrll 			qh->sched_frame = frame_number;
780970b0700Sskrll 		qh->sched_frame |= 0x7;
781970b0700Sskrll 		qh->start_split_frame = qh->sched_frame;
782970b0700Sskrll 	}
783970b0700Sskrll }
784970b0700Sskrll 
785970b0700Sskrll /*
786970b0700Sskrll  * Deactivates a QH. For non-periodic QHs, removes the QH from the active
787970b0700Sskrll  * non-periodic schedule. The QH is added to the inactive non-periodic
788970b0700Sskrll  * schedule if any QTDs are still attached to the QH.
789970b0700Sskrll  *
790970b0700Sskrll  * For periodic QHs, the QH is removed from the periodic queued schedule. If
791970b0700Sskrll  * there are any QTDs still attached to the QH, the QH is added to either the
792970b0700Sskrll  * periodic inactive schedule or the periodic ready schedule and its next
793970b0700Sskrll  * scheduled frame is calculated. The QH is placed in the ready schedule if
794970b0700Sskrll  * the scheduled frame has been reached already. Otherwise it's placed in the
795970b0700Sskrll  * inactive schedule. If there are no QTDs attached to the QH, the QH is
796970b0700Sskrll  * completely removed from the periodic schedule.
797970b0700Sskrll  */
dwc2_hcd_qh_deactivate(struct dwc2_hsotg * hsotg,struct dwc2_qh * qh,int sched_next_periodic_split)798970b0700Sskrll void dwc2_hcd_qh_deactivate(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh,
799970b0700Sskrll 			    int sched_next_periodic_split)
800970b0700Sskrll {
801f913003cSskrll 	u16 frame_number;
802f913003cSskrll 
803970b0700Sskrll 	if (dbg_qh(qh))
804970b0700Sskrll 		dev_vdbg(hsotg->dev, "%s()\n", __func__);
805970b0700Sskrll 
806970b0700Sskrll 	if (dwc2_qh_is_non_per(qh)) {
807970b0700Sskrll 		dwc2_hcd_qh_unlink(hsotg, qh);
808970b0700Sskrll 		if (!list_empty(&qh->qtd_list))
80946b04be8Ssimonb 			/* Add back to inactive/waiting non-periodic schedule */
810970b0700Sskrll 			dwc2_hcd_qh_add(hsotg, qh);
811f913003cSskrll 		return;
812f913003cSskrll 	}
813f913003cSskrll 
814f913003cSskrll 	frame_number = dwc2_hcd_get_frame_number(hsotg);
815970b0700Sskrll 
816970b0700Sskrll 	if (qh->do_split) {
817970b0700Sskrll 		dwc2_sched_periodic_split(hsotg, qh, frame_number,
818970b0700Sskrll 					  sched_next_periodic_split);
819970b0700Sskrll 	} else {
820970b0700Sskrll 		qh->sched_frame = dwc2_frame_num_inc(qh->sched_frame,
821970b0700Sskrll 						     qh->interval);
822970b0700Sskrll 		if (dwc2_frame_num_le(qh->sched_frame, frame_number))
823970b0700Sskrll 			qh->sched_frame = frame_number;
824970b0700Sskrll 	}
825970b0700Sskrll 
826970b0700Sskrll 	if (list_empty(&qh->qtd_list)) {
827970b0700Sskrll 		dwc2_hcd_qh_unlink(hsotg, qh);
828f913003cSskrll 		return;
829f913003cSskrll 	}
830970b0700Sskrll 	/*
831970b0700Sskrll 	 * Remove from periodic_sched_queued and move to
832970b0700Sskrll 	 * appropriate queue
833970b0700Sskrll 	 */
834970b0700Sskrll 	if ((hsotg->core_params->uframe_sched > 0 &&
835f913003cSskrll 	     dwc2_frame_num_le(qh->sched_frame, frame_number)) ||
836f913003cSskrll 	    (hsotg->core_params->uframe_sched <= 0 &&
837cb22e524Sskrll 	     qh->sched_frame == frame_number))
838f913003cSskrll 		list_move(&qh->qh_list_entry, &hsotg->periodic_sched_ready);
839cb22e524Sskrll 	else
840f913003cSskrll 		list_move(&qh->qh_list_entry, &hsotg->periodic_sched_inactive);
841970b0700Sskrll }
842970b0700Sskrll 
843970b0700Sskrll /**
844970b0700Sskrll  * dwc2_hcd_qtd_init() - Initializes a QTD structure
845970b0700Sskrll  *
846970b0700Sskrll  * @qtd: The QTD to initialize
847970b0700Sskrll  * @urb: The associated URB
848970b0700Sskrll  */
dwc2_hcd_qtd_init(struct dwc2_qtd * qtd,struct dwc2_hcd_urb * urb)849970b0700Sskrll void dwc2_hcd_qtd_init(struct dwc2_qtd *qtd, struct dwc2_hcd_urb *urb)
850970b0700Sskrll {
851970b0700Sskrll 	qtd->urb = urb;
852970b0700Sskrll 	if (dwc2_hcd_get_pipe_type(&urb->pipe_info) ==
853970b0700Sskrll 			USB_ENDPOINT_XFER_CONTROL) {
854970b0700Sskrll 		/*
855970b0700Sskrll 		 * The only time the QTD data toggle is used is on the data
856970b0700Sskrll 		 * phase of control transfers. This phase always starts with
857970b0700Sskrll 		 * DATA1.
858970b0700Sskrll 		 */
859970b0700Sskrll 		qtd->data_toggle = DWC2_HC_PID_DATA1;
860970b0700Sskrll 		qtd->control_phase = DWC2_CONTROL_SETUP;
861970b0700Sskrll 	}
862970b0700Sskrll 
863970b0700Sskrll 	/* Start split */
864970b0700Sskrll 	qtd->complete_split = 0;
865970b0700Sskrll 	qtd->isoc_split_pos = DWC2_HCSPLT_XACTPOS_ALL;
866970b0700Sskrll 	qtd->isoc_split_offset = 0;
867970b0700Sskrll 	qtd->in_process = 0;
868970b0700Sskrll 
869970b0700Sskrll 	/* Store the qtd ptr in the urb to reference the QTD */
870970b0700Sskrll 	urb->qtd = qtd;
871970b0700Sskrll }
872970b0700Sskrll 
873970b0700Sskrll /**
874970b0700Sskrll  * dwc2_hcd_qtd_add() - Adds a QTD to the QTD-list of a QH
8759c7e1469Sskrll  *			Caller must hold driver lock.
876970b0700Sskrll  *
877970b0700Sskrll  * @hsotg:        The DWC HCD structure
878970b0700Sskrll  * @qtd:          The QTD to add
8799c7e1469Sskrll  * @qh:           Queue head to add qtd to
880970b0700Sskrll  *
881970b0700Sskrll  * Return: 0 if successful, negative error code otherwise
882970b0700Sskrll  *
8839c7e1469Sskrll  * If the QH to which the QTD is added is not currently scheduled, it is placed
8849c7e1469Sskrll  * into the proper schedule based on its EP type.
885970b0700Sskrll  */
dwc2_hcd_qtd_add(struct dwc2_hsotg * hsotg,struct dwc2_qtd * qtd,struct dwc2_qh * qh)886970b0700Sskrll int dwc2_hcd_qtd_add(struct dwc2_hsotg *hsotg, struct dwc2_qtd *qtd,
8879c7e1469Sskrll 		     struct dwc2_qh *qh)
888970b0700Sskrll {
8899c7e1469Sskrll 
890e58cc73eSuebayasi 	KASSERT(mutex_owned(&hsotg->lock));
891970b0700Sskrll 	int retval;
892970b0700Sskrll 
8939c7e1469Sskrll 	if (unlikely(!qh)) {
8949c7e1469Sskrll 		dev_err(hsotg->dev, "%s: Invalid QH\n", __func__);
8959c7e1469Sskrll 		retval = -EINVAL;
8969c7e1469Sskrll 		goto fail;
897970b0700Sskrll 	}
898970b0700Sskrll 
8999c7e1469Sskrll 	retval = dwc2_hcd_qh_add(hsotg, qh);
900970b0700Sskrll 	if (retval)
901970b0700Sskrll 		goto fail;
902970b0700Sskrll 
9039c7e1469Sskrll 	qtd->qh = qh;
9049c7e1469Sskrll 	list_add_tail(&qtd->qtd_list_entry, &qh->qtd_list);
905970b0700Sskrll 
906970b0700Sskrll 	return 0;
907970b0700Sskrll fail:
908970b0700Sskrll 	return retval;
909970b0700Sskrll }
910c8117e49Sskrll 
dwc2_hcd_qtd_unlink_and_free(struct dwc2_hsotg * hsotg,struct dwc2_qtd * qtd,struct dwc2_qh * qh)911c8117e49Sskrll void dwc2_hcd_qtd_unlink_and_free(struct dwc2_hsotg *hsotg,
912c8117e49Sskrll 				  struct dwc2_qtd *qtd,
913c8117e49Sskrll 				  struct dwc2_qh *qh)
914c8117e49Sskrll {
915c8117e49Sskrll 	struct dwc2_softc *sc = hsotg->hsotg_sc;
916c8117e49Sskrll 
917c8117e49Sskrll 	list_del_init(&qtd->qtd_list_entry);
918c8117e49Sskrll  	pool_cache_put(sc->sc_qtdpool, qtd);
919c8117e49Sskrll }
920c8117e49Sskrll 
921c8117e49Sskrll #define BITSTUFFTIME(bytecount)	((8 * 7 * (bytecount)) / 6)
922c8117e49Sskrll #define HS_HOST_DELAY		5	/* nanoseconds */
923c8117e49Sskrll #define FS_LS_HOST_DELAY	1000	/* nanoseconds */
924c8117e49Sskrll #define HUB_LS_SETUP		333	/* nanoseconds */
925c8117e49Sskrll 
dwc2_calc_bus_time(struct dwc2_hsotg * hsotg,int speed,int is_in,int is_isoc,int bytecount)926c8117e49Sskrll static u32 dwc2_calc_bus_time(struct dwc2_hsotg *hsotg, int speed, int is_in,
927c8117e49Sskrll 			      int is_isoc, int bytecount)
928c8117e49Sskrll {
929c8117e49Sskrll 	unsigned long retval;
930c8117e49Sskrll 
931c8117e49Sskrll 	switch (speed) {
932c8117e49Sskrll 	case USB_SPEED_HIGH:
933c8117e49Sskrll 		if (is_isoc)
934c8117e49Sskrll 			retval =
935c8117e49Sskrll 			    ((38 * 8 * 2083) +
936c8117e49Sskrll 			     (2083 * (3 + BITSTUFFTIME(bytecount)))) / 1000 +
937c8117e49Sskrll 			    HS_HOST_DELAY;
938c8117e49Sskrll 		else
939c8117e49Sskrll 			retval =
940c8117e49Sskrll 			    ((55 * 8 * 2083) +
941c8117e49Sskrll 			     (2083 * (3 + BITSTUFFTIME(bytecount)))) / 1000 +
942c8117e49Sskrll 			    HS_HOST_DELAY;
943c8117e49Sskrll 		break;
944c8117e49Sskrll 	case USB_SPEED_FULL:
945c8117e49Sskrll 		if (is_isoc) {
946c8117e49Sskrll 			retval =
947c8117e49Sskrll 			    (8354 * (31 + 10 * BITSTUFFTIME(bytecount))) / 1000;
948c8117e49Sskrll 			if (is_in)
949c8117e49Sskrll 				retval = 7268 + FS_LS_HOST_DELAY + retval;
950c8117e49Sskrll 			else
951c8117e49Sskrll 				retval = 6265 + FS_LS_HOST_DELAY + retval;
952c8117e49Sskrll 		} else {
953c8117e49Sskrll 			retval =
954c8117e49Sskrll 			    (8354 * (31 + 10 * BITSTUFFTIME(bytecount))) / 1000;
955c8117e49Sskrll 			retval = 9107 + FS_LS_HOST_DELAY + retval;
956c8117e49Sskrll 		}
957c8117e49Sskrll 		break;
958c8117e49Sskrll 	case USB_SPEED_LOW:
959c8117e49Sskrll 		if (is_in) {
960c8117e49Sskrll 			retval =
961c8117e49Sskrll 			    (67667 * (31 + 10 * BITSTUFFTIME(bytecount))) /
962c8117e49Sskrll 			    1000;
963c8117e49Sskrll 			retval =
964c8117e49Sskrll 			    64060 + (2 * HUB_LS_SETUP) + FS_LS_HOST_DELAY +
965c8117e49Sskrll 			    retval;
966c8117e49Sskrll 		} else {
967c8117e49Sskrll 			retval =
968c8117e49Sskrll 			    (66700 * (31 + 10 * BITSTUFFTIME(bytecount))) /
969c8117e49Sskrll 			    1000;
970c8117e49Sskrll 			retval =
971c8117e49Sskrll 			    64107 + (2 * HUB_LS_SETUP) + FS_LS_HOST_DELAY +
972c8117e49Sskrll 			    retval;
973c8117e49Sskrll 		}
974c8117e49Sskrll 		break;
975c8117e49Sskrll 	default:
976c8117e49Sskrll 		dev_warn(hsotg->dev, "Unknown device speed\n");
977c8117e49Sskrll 		retval = -1;
978c8117e49Sskrll 	}
979c8117e49Sskrll 
980c8117e49Sskrll 	return NS_TO_US(retval);
981c8117e49Sskrll }
982