18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * hcd_queue.c - DesignWare HS OTG Controller host queuing routines
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Copyright (C) 2004-2013 Synopsys, Inc.
68c2ecf20Sopenharmony_ci *
78c2ecf20Sopenharmony_ci * Redistribution and use in source and binary forms, with or without
88c2ecf20Sopenharmony_ci * modification, are permitted provided that the following conditions
98c2ecf20Sopenharmony_ci * are met:
108c2ecf20Sopenharmony_ci * 1. Redistributions of source code must retain the above copyright
118c2ecf20Sopenharmony_ci *    notice, this list of conditions, and the following disclaimer,
128c2ecf20Sopenharmony_ci *    without modification.
138c2ecf20Sopenharmony_ci * 2. Redistributions in binary form must reproduce the above copyright
148c2ecf20Sopenharmony_ci *    notice, this list of conditions and the following disclaimer in the
158c2ecf20Sopenharmony_ci *    documentation and/or other materials provided with the distribution.
168c2ecf20Sopenharmony_ci * 3. The names of the above-listed copyright holders may not be used
178c2ecf20Sopenharmony_ci *    to endorse or promote products derived from this software without
188c2ecf20Sopenharmony_ci *    specific prior written permission.
198c2ecf20Sopenharmony_ci *
208c2ecf20Sopenharmony_ci * ALTERNATIVELY, this software may be distributed under the terms of the
218c2ecf20Sopenharmony_ci * GNU General Public License ("GPL") as published by the Free Software
228c2ecf20Sopenharmony_ci * Foundation; either version 2 of the License, or (at your option) any
238c2ecf20Sopenharmony_ci * later version.
248c2ecf20Sopenharmony_ci *
258c2ecf20Sopenharmony_ci * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
268c2ecf20Sopenharmony_ci * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
278c2ecf20Sopenharmony_ci * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
288c2ecf20Sopenharmony_ci * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
298c2ecf20Sopenharmony_ci * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
308c2ecf20Sopenharmony_ci * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
318c2ecf20Sopenharmony_ci * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
328c2ecf20Sopenharmony_ci * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
338c2ecf20Sopenharmony_ci * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
348c2ecf20Sopenharmony_ci * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
358c2ecf20Sopenharmony_ci * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
368c2ecf20Sopenharmony_ci */
378c2ecf20Sopenharmony_ci
388c2ecf20Sopenharmony_ci/*
398c2ecf20Sopenharmony_ci * This file contains the functions to manage Queue Heads and Queue
408c2ecf20Sopenharmony_ci * Transfer Descriptors for Host mode
418c2ecf20Sopenharmony_ci */
428c2ecf20Sopenharmony_ci#include <linux/gcd.h>
438c2ecf20Sopenharmony_ci#include <linux/kernel.h>
448c2ecf20Sopenharmony_ci#include <linux/module.h>
458c2ecf20Sopenharmony_ci#include <linux/spinlock.h>
468c2ecf20Sopenharmony_ci#include <linux/interrupt.h>
478c2ecf20Sopenharmony_ci#include <linux/dma-mapping.h>
488c2ecf20Sopenharmony_ci#include <linux/io.h>
498c2ecf20Sopenharmony_ci#include <linux/slab.h>
508c2ecf20Sopenharmony_ci#include <linux/usb.h>
518c2ecf20Sopenharmony_ci
528c2ecf20Sopenharmony_ci#include <linux/usb/hcd.h>
538c2ecf20Sopenharmony_ci#include <linux/usb/ch11.h>
548c2ecf20Sopenharmony_ci
558c2ecf20Sopenharmony_ci#include "core.h"
568c2ecf20Sopenharmony_ci#include "hcd.h"
578c2ecf20Sopenharmony_ci
588c2ecf20Sopenharmony_ci/* Wait this long before releasing periodic reservation */
598c2ecf20Sopenharmony_ci#define DWC2_UNRESERVE_DELAY (msecs_to_jiffies(5))
608c2ecf20Sopenharmony_ci
618c2ecf20Sopenharmony_ci/* If we get a NAK, wait this long before retrying */
628c2ecf20Sopenharmony_ci#define DWC2_RETRY_WAIT_DELAY (1 * NSEC_PER_MSEC)
638c2ecf20Sopenharmony_ci
648c2ecf20Sopenharmony_ci/**
658c2ecf20Sopenharmony_ci * dwc2_periodic_channel_available() - Checks that a channel is available for a
668c2ecf20Sopenharmony_ci * periodic transfer
678c2ecf20Sopenharmony_ci *
688c2ecf20Sopenharmony_ci * @hsotg: The HCD state structure for the DWC OTG controller
698c2ecf20Sopenharmony_ci *
708c2ecf20Sopenharmony_ci * Return: 0 if successful, negative error code otherwise
718c2ecf20Sopenharmony_ci */
728c2ecf20Sopenharmony_cistatic int dwc2_periodic_channel_available(struct dwc2_hsotg *hsotg)
738c2ecf20Sopenharmony_ci{
748c2ecf20Sopenharmony_ci	/*
758c2ecf20Sopenharmony_ci	 * Currently assuming that there is a dedicated host channel for
768c2ecf20Sopenharmony_ci	 * each periodic transaction plus at least one host channel for
778c2ecf20Sopenharmony_ci	 * non-periodic transactions
788c2ecf20Sopenharmony_ci	 */
798c2ecf20Sopenharmony_ci	int status;
808c2ecf20Sopenharmony_ci	int num_channels;
818c2ecf20Sopenharmony_ci
828c2ecf20Sopenharmony_ci	num_channels = hsotg->params.host_channels;
838c2ecf20Sopenharmony_ci	if ((hsotg->periodic_channels + hsotg->non_periodic_channels <
848c2ecf20Sopenharmony_ci	     num_channels) && (hsotg->periodic_channels < num_channels - 1)) {
858c2ecf20Sopenharmony_ci		status = 0;
868c2ecf20Sopenharmony_ci	} else {
878c2ecf20Sopenharmony_ci		dev_dbg(hsotg->dev,
888c2ecf20Sopenharmony_ci			"%s: Total channels: %d, Periodic: %d, Non-periodic: %d\n",
898c2ecf20Sopenharmony_ci			__func__, num_channels,
908c2ecf20Sopenharmony_ci			hsotg->periodic_channels, hsotg->non_periodic_channels);
918c2ecf20Sopenharmony_ci		status = -ENOSPC;
928c2ecf20Sopenharmony_ci	}
938c2ecf20Sopenharmony_ci
948c2ecf20Sopenharmony_ci	return status;
958c2ecf20Sopenharmony_ci}
968c2ecf20Sopenharmony_ci
978c2ecf20Sopenharmony_ci/**
988c2ecf20Sopenharmony_ci * dwc2_check_periodic_bandwidth() - Checks that there is sufficient bandwidth
998c2ecf20Sopenharmony_ci * for the specified QH in the periodic schedule
1008c2ecf20Sopenharmony_ci *
1018c2ecf20Sopenharmony_ci * @hsotg: The HCD state structure for the DWC OTG controller
1028c2ecf20Sopenharmony_ci * @qh:    QH containing periodic bandwidth required
1038c2ecf20Sopenharmony_ci *
1048c2ecf20Sopenharmony_ci * Return: 0 if successful, negative error code otherwise
1058c2ecf20Sopenharmony_ci *
1068c2ecf20Sopenharmony_ci * For simplicity, this calculation assumes that all the transfers in the
1078c2ecf20Sopenharmony_ci * periodic schedule may occur in the same (micro)frame
1088c2ecf20Sopenharmony_ci */
1098c2ecf20Sopenharmony_cistatic int dwc2_check_periodic_bandwidth(struct dwc2_hsotg *hsotg,
1108c2ecf20Sopenharmony_ci					 struct dwc2_qh *qh)
1118c2ecf20Sopenharmony_ci{
1128c2ecf20Sopenharmony_ci	int status;
1138c2ecf20Sopenharmony_ci	s16 max_claimed_usecs;
1148c2ecf20Sopenharmony_ci
1158c2ecf20Sopenharmony_ci	status = 0;
1168c2ecf20Sopenharmony_ci
1178c2ecf20Sopenharmony_ci	if (qh->dev_speed == USB_SPEED_HIGH || qh->do_split) {
1188c2ecf20Sopenharmony_ci		/*
1198c2ecf20Sopenharmony_ci		 * High speed mode
1208c2ecf20Sopenharmony_ci		 * Max periodic usecs is 80% x 125 usec = 100 usec
1218c2ecf20Sopenharmony_ci		 */
1228c2ecf20Sopenharmony_ci		max_claimed_usecs = 100 - qh->host_us;
1238c2ecf20Sopenharmony_ci	} else {
1248c2ecf20Sopenharmony_ci		/*
1258c2ecf20Sopenharmony_ci		 * Full speed mode
1268c2ecf20Sopenharmony_ci		 * Max periodic usecs is 90% x 1000 usec = 900 usec
1278c2ecf20Sopenharmony_ci		 */
1288c2ecf20Sopenharmony_ci		max_claimed_usecs = 900 - qh->host_us;
1298c2ecf20Sopenharmony_ci	}
1308c2ecf20Sopenharmony_ci
1318c2ecf20Sopenharmony_ci	if (hsotg->periodic_usecs > max_claimed_usecs) {
1328c2ecf20Sopenharmony_ci		dev_err(hsotg->dev,
1338c2ecf20Sopenharmony_ci			"%s: already claimed usecs %d, required usecs %d\n",
1348c2ecf20Sopenharmony_ci			__func__, hsotg->periodic_usecs, qh->host_us);
1358c2ecf20Sopenharmony_ci		status = -ENOSPC;
1368c2ecf20Sopenharmony_ci	}
1378c2ecf20Sopenharmony_ci
1388c2ecf20Sopenharmony_ci	return status;
1398c2ecf20Sopenharmony_ci}
1408c2ecf20Sopenharmony_ci
1418c2ecf20Sopenharmony_ci/**
1428c2ecf20Sopenharmony_ci * pmap_schedule() - Schedule time in a periodic bitmap (pmap).
1438c2ecf20Sopenharmony_ci *
1448c2ecf20Sopenharmony_ci * @map:             The bitmap representing the schedule; will be updated
1458c2ecf20Sopenharmony_ci *                   upon success.
1468c2ecf20Sopenharmony_ci * @bits_per_period: The schedule represents several periods.  This is how many
1478c2ecf20Sopenharmony_ci *                   bits are in each period.  It's assumed that the beginning
1488c2ecf20Sopenharmony_ci *                   of the schedule will repeat after its end.
1498c2ecf20Sopenharmony_ci * @periods_in_map:  The number of periods in the schedule.
1508c2ecf20Sopenharmony_ci * @num_bits:        The number of bits we need per period we want to reserve
1518c2ecf20Sopenharmony_ci *                   in this function call.
1528c2ecf20Sopenharmony_ci * @interval:        How often we need to be scheduled for the reservation this
1538c2ecf20Sopenharmony_ci *                   time.  1 means every period.  2 means every other period.
1548c2ecf20Sopenharmony_ci *                   ...you get the picture?
1558c2ecf20Sopenharmony_ci * @start:           The bit number to start at.  Normally 0.  Must be within
1568c2ecf20Sopenharmony_ci *                   the interval or we return failure right away.
1578c2ecf20Sopenharmony_ci * @only_one_period: Normally we'll allow picking a start anywhere within the
1588c2ecf20Sopenharmony_ci *                   first interval, since we can still make all repetition
1598c2ecf20Sopenharmony_ci *                   requirements by doing that.  However, if you pass true
1608c2ecf20Sopenharmony_ci *                   here then we'll return failure if we can't fit within
1618c2ecf20Sopenharmony_ci *                   the period that "start" is in.
1628c2ecf20Sopenharmony_ci *
1638c2ecf20Sopenharmony_ci * The idea here is that we want to schedule time for repeating events that all
1648c2ecf20Sopenharmony_ci * want the same resource.  The resource is divided into fixed-sized periods
1658c2ecf20Sopenharmony_ci * and the events want to repeat every "interval" periods.  The schedule
1668c2ecf20Sopenharmony_ci * granularity is one bit.
1678c2ecf20Sopenharmony_ci *
1688c2ecf20Sopenharmony_ci * To keep things "simple", we'll represent our schedule with a bitmap that
1698c2ecf20Sopenharmony_ci * contains a fixed number of periods.  This gets rid of a lot of complexity
1708c2ecf20Sopenharmony_ci * but does mean that we need to handle things specially (and non-ideally) if
1718c2ecf20Sopenharmony_ci * the number of the periods in the schedule doesn't match well with the
1728c2ecf20Sopenharmony_ci * intervals that we're trying to schedule.
1738c2ecf20Sopenharmony_ci *
1748c2ecf20Sopenharmony_ci * Here's an explanation of the scheme we'll implement, assuming 8 periods.
1758c2ecf20Sopenharmony_ci * - If interval is 1, we need to take up space in each of the 8
1768c2ecf20Sopenharmony_ci *   periods we're scheduling.  Easy.
1778c2ecf20Sopenharmony_ci * - If interval is 2, we need to take up space in half of the
1788c2ecf20Sopenharmony_ci *   periods.  Again, easy.
1798c2ecf20Sopenharmony_ci * - If interval is 3, we actually need to fall back to interval 1.
1808c2ecf20Sopenharmony_ci *   Why?  Because we might need time in any period.  AKA for the
1818c2ecf20Sopenharmony_ci *   first 8 periods, we'll be in slot 0, 3, 6.  Then we'll be
1828c2ecf20Sopenharmony_ci *   in slot 1, 4, 7.  Then we'll be in 2, 5.  Then we'll be back to
1838c2ecf20Sopenharmony_ci *   0, 3, and 6.  Since we could be in any frame we need to reserve
1848c2ecf20Sopenharmony_ci *   for all of them.  Sucks, but that's what you gotta do.  Note that
1858c2ecf20Sopenharmony_ci *   if we were instead scheduling 8 * 3 = 24 we'd do much better, but
1868c2ecf20Sopenharmony_ci *   then we need more memory and time to do scheduling.
1878c2ecf20Sopenharmony_ci * - If interval is 4, easy.
1888c2ecf20Sopenharmony_ci * - If interval is 5, we again need interval 1.  The schedule will be
1898c2ecf20Sopenharmony_ci *   0, 5, 2, 7, 4, 1, 6, 3, 0
1908c2ecf20Sopenharmony_ci * - If interval is 6, we need interval 2.  0, 6, 4, 2.
1918c2ecf20Sopenharmony_ci * - If interval is 7, we need interval 1.
1928c2ecf20Sopenharmony_ci * - If interval is 8, we need interval 8.
1938c2ecf20Sopenharmony_ci *
1948c2ecf20Sopenharmony_ci * If you do the math, you'll see that we need to pretend that interval is
1958c2ecf20Sopenharmony_ci * equal to the greatest_common_divisor(interval, periods_in_map).
1968c2ecf20Sopenharmony_ci *
1978c2ecf20Sopenharmony_ci * Note that at the moment this function tends to front-pack the schedule.
1988c2ecf20Sopenharmony_ci * In some cases that's really non-ideal (it's hard to schedule things that
1998c2ecf20Sopenharmony_ci * need to repeat every period).  In other cases it's perfect (you can easily
2008c2ecf20Sopenharmony_ci * schedule bigger, less often repeating things).
2018c2ecf20Sopenharmony_ci *
2028c2ecf20Sopenharmony_ci * Here's the algorithm in action (8 periods, 5 bits per period):
2038c2ecf20Sopenharmony_ci *  |**   |     |**   |     |**   |     |**   |     |   OK 2 bits, intv 2 at 0
2048c2ecf20Sopenharmony_ci *  |*****|  ***|*****|  ***|*****|  ***|*****|  ***|   OK 3 bits, intv 3 at 2
2058c2ecf20Sopenharmony_ci *  |*****|* ***|*****|  ***|*****|* ***|*****|  ***|   OK 1 bits, intv 4 at 5
2068c2ecf20Sopenharmony_ci *  |**   |*    |**   |     |**   |*    |**   |     | Remv 3 bits, intv 3 at 2
2078c2ecf20Sopenharmony_ci *  |***  |*    |***  |     |***  |*    |***  |     |   OK 1 bits, intv 6 at 2
2088c2ecf20Sopenharmony_ci *  |**** |*  * |**** |   * |**** |*  * |**** |   * |   OK 1 bits, intv 1 at 3
2098c2ecf20Sopenharmony_ci *  |**** |**** |**** | *** |**** |**** |**** | *** |   OK 2 bits, intv 2 at 6
2108c2ecf20Sopenharmony_ci *  |*****|*****|*****| ****|*****|*****|*****| ****|   OK 1 bits, intv 1 at 4
2118c2ecf20Sopenharmony_ci *  |*****|*****|*****| ****|*****|*****|*****| ****| FAIL 1 bits, intv 1
2128c2ecf20Sopenharmony_ci *  |  ***|*****|  ***| ****|  ***|*****|  ***| ****| Remv 2 bits, intv 2 at 0
2138c2ecf20Sopenharmony_ci *  |  ***| ****|  ***| ****|  ***| ****|  ***| ****| Remv 1 bits, intv 4 at 5
2148c2ecf20Sopenharmony_ci *  |   **| ****|   **| ****|   **| ****|   **| ****| Remv 1 bits, intv 6 at 2
2158c2ecf20Sopenharmony_ci *  |    *| ** *|    *| ** *|    *| ** *|    *| ** *| Remv 1 bits, intv 1 at 3
2168c2ecf20Sopenharmony_ci *  |    *|    *|    *|    *|    *|    *|    *|    *| Remv 2 bits, intv 2 at 6
2178c2ecf20Sopenharmony_ci *  |     |     |     |     |     |     |     |     | Remv 1 bits, intv 1 at 4
2188c2ecf20Sopenharmony_ci *  |**   |     |**   |     |**   |     |**   |     |   OK 2 bits, intv 2 at 0
2198c2ecf20Sopenharmony_ci *  |***  |     |**   |     |***  |     |**   |     |   OK 1 bits, intv 4 at 2
2208c2ecf20Sopenharmony_ci *  |*****|     |** **|     |*****|     |** **|     |   OK 2 bits, intv 2 at 3
2218c2ecf20Sopenharmony_ci *  |*****|*    |** **|     |*****|*    |** **|     |   OK 1 bits, intv 4 at 5
2228c2ecf20Sopenharmony_ci *  |*****|***  |** **| **  |*****|***  |** **| **  |   OK 2 bits, intv 2 at 6
2238c2ecf20Sopenharmony_ci *  |*****|*****|** **| ****|*****|*****|** **| ****|   OK 2 bits, intv 2 at 8
2248c2ecf20Sopenharmony_ci *  |*****|*****|*****| ****|*****|*****|*****| ****|   OK 1 bits, intv 4 at 12
2258c2ecf20Sopenharmony_ci *
2268c2ecf20Sopenharmony_ci * This function is pretty generic and could be easily abstracted if anything
2278c2ecf20Sopenharmony_ci * needed similar scheduling.
2288c2ecf20Sopenharmony_ci *
2298c2ecf20Sopenharmony_ci * Returns either -ENOSPC or a >= 0 start bit which should be passed to the
2308c2ecf20Sopenharmony_ci * unschedule routine.  The map bitmap will be updated on a non-error result.
2318c2ecf20Sopenharmony_ci */
2328c2ecf20Sopenharmony_cistatic int pmap_schedule(unsigned long *map, int bits_per_period,
2338c2ecf20Sopenharmony_ci			 int periods_in_map, int num_bits,
2348c2ecf20Sopenharmony_ci			 int interval, int start, bool only_one_period)
2358c2ecf20Sopenharmony_ci{
2368c2ecf20Sopenharmony_ci	int interval_bits;
2378c2ecf20Sopenharmony_ci	int to_reserve;
2388c2ecf20Sopenharmony_ci	int first_end;
2398c2ecf20Sopenharmony_ci	int i;
2408c2ecf20Sopenharmony_ci
2418c2ecf20Sopenharmony_ci	if (num_bits > bits_per_period)
2428c2ecf20Sopenharmony_ci		return -ENOSPC;
2438c2ecf20Sopenharmony_ci
2448c2ecf20Sopenharmony_ci	/* Adjust interval as per description */
2458c2ecf20Sopenharmony_ci	interval = gcd(interval, periods_in_map);
2468c2ecf20Sopenharmony_ci
2478c2ecf20Sopenharmony_ci	interval_bits = bits_per_period * interval;
2488c2ecf20Sopenharmony_ci	to_reserve = periods_in_map / interval;
2498c2ecf20Sopenharmony_ci
2508c2ecf20Sopenharmony_ci	/* If start has gotten us past interval then we can't schedule */
2518c2ecf20Sopenharmony_ci	if (start >= interval_bits)
2528c2ecf20Sopenharmony_ci		return -ENOSPC;
2538c2ecf20Sopenharmony_ci
2548c2ecf20Sopenharmony_ci	if (only_one_period)
2558c2ecf20Sopenharmony_ci		/* Must fit within same period as start; end at begin of next */
2568c2ecf20Sopenharmony_ci		first_end = (start / bits_per_period + 1) * bits_per_period;
2578c2ecf20Sopenharmony_ci	else
2588c2ecf20Sopenharmony_ci		/* Can fit anywhere in the first interval */
2598c2ecf20Sopenharmony_ci		first_end = interval_bits;
2608c2ecf20Sopenharmony_ci
2618c2ecf20Sopenharmony_ci	/*
2628c2ecf20Sopenharmony_ci	 * We'll try to pick the first repetition, then see if that time
2638c2ecf20Sopenharmony_ci	 * is free for each of the subsequent repetitions.  If it's not
2648c2ecf20Sopenharmony_ci	 * we'll adjust the start time for the next search of the first
2658c2ecf20Sopenharmony_ci	 * repetition.
2668c2ecf20Sopenharmony_ci	 */
2678c2ecf20Sopenharmony_ci	while (start + num_bits <= first_end) {
2688c2ecf20Sopenharmony_ci		int end;
2698c2ecf20Sopenharmony_ci
2708c2ecf20Sopenharmony_ci		/* Need to stay within this period */
2718c2ecf20Sopenharmony_ci		end = (start / bits_per_period + 1) * bits_per_period;
2728c2ecf20Sopenharmony_ci
2738c2ecf20Sopenharmony_ci		/* Look for num_bits us in this microframe starting at start */
2748c2ecf20Sopenharmony_ci		start = bitmap_find_next_zero_area(map, end, start, num_bits,
2758c2ecf20Sopenharmony_ci						   0);
2768c2ecf20Sopenharmony_ci
2778c2ecf20Sopenharmony_ci		/*
2788c2ecf20Sopenharmony_ci		 * We should get start >= end if we fail.  We might be
2798c2ecf20Sopenharmony_ci		 * able to check the next microframe depending on the
2808c2ecf20Sopenharmony_ci		 * interval, so continue on (start already updated).
2818c2ecf20Sopenharmony_ci		 */
2828c2ecf20Sopenharmony_ci		if (start >= end) {
2838c2ecf20Sopenharmony_ci			start = end;
2848c2ecf20Sopenharmony_ci			continue;
2858c2ecf20Sopenharmony_ci		}
2868c2ecf20Sopenharmony_ci
2878c2ecf20Sopenharmony_ci		/* At this point we have a valid point for first one */
2888c2ecf20Sopenharmony_ci		for (i = 1; i < to_reserve; i++) {
2898c2ecf20Sopenharmony_ci			int ith_start = start + interval_bits * i;
2908c2ecf20Sopenharmony_ci			int ith_end = end + interval_bits * i;
2918c2ecf20Sopenharmony_ci			int ret;
2928c2ecf20Sopenharmony_ci
2938c2ecf20Sopenharmony_ci			/* Use this as a dumb "check if bits are 0" */
2948c2ecf20Sopenharmony_ci			ret = bitmap_find_next_zero_area(
2958c2ecf20Sopenharmony_ci				map, ith_start + num_bits, ith_start, num_bits,
2968c2ecf20Sopenharmony_ci				0);
2978c2ecf20Sopenharmony_ci
2988c2ecf20Sopenharmony_ci			/* We got the right place, continue checking */
2998c2ecf20Sopenharmony_ci			if (ret == ith_start)
3008c2ecf20Sopenharmony_ci				continue;
3018c2ecf20Sopenharmony_ci
3028c2ecf20Sopenharmony_ci			/* Move start up for next time and exit for loop */
3038c2ecf20Sopenharmony_ci			ith_start = bitmap_find_next_zero_area(
3048c2ecf20Sopenharmony_ci				map, ith_end, ith_start, num_bits, 0);
3058c2ecf20Sopenharmony_ci			if (ith_start >= ith_end)
3068c2ecf20Sopenharmony_ci				/* Need a while new period next time */
3078c2ecf20Sopenharmony_ci				start = end;
3088c2ecf20Sopenharmony_ci			else
3098c2ecf20Sopenharmony_ci				start = ith_start - interval_bits * i;
3108c2ecf20Sopenharmony_ci			break;
3118c2ecf20Sopenharmony_ci		}
3128c2ecf20Sopenharmony_ci
3138c2ecf20Sopenharmony_ci		/* If didn't exit the for loop with a break, we have success */
3148c2ecf20Sopenharmony_ci		if (i == to_reserve)
3158c2ecf20Sopenharmony_ci			break;
3168c2ecf20Sopenharmony_ci	}
3178c2ecf20Sopenharmony_ci
3188c2ecf20Sopenharmony_ci	if (start + num_bits > first_end)
3198c2ecf20Sopenharmony_ci		return -ENOSPC;
3208c2ecf20Sopenharmony_ci
3218c2ecf20Sopenharmony_ci	for (i = 0; i < to_reserve; i++) {
3228c2ecf20Sopenharmony_ci		int ith_start = start + interval_bits * i;
3238c2ecf20Sopenharmony_ci
3248c2ecf20Sopenharmony_ci		bitmap_set(map, ith_start, num_bits);
3258c2ecf20Sopenharmony_ci	}
3268c2ecf20Sopenharmony_ci
3278c2ecf20Sopenharmony_ci	return start;
3288c2ecf20Sopenharmony_ci}
3298c2ecf20Sopenharmony_ci
3308c2ecf20Sopenharmony_ci/**
3318c2ecf20Sopenharmony_ci * pmap_unschedule() - Undo work done by pmap_schedule()
3328c2ecf20Sopenharmony_ci *
3338c2ecf20Sopenharmony_ci * @map:             See pmap_schedule().
3348c2ecf20Sopenharmony_ci * @bits_per_period: See pmap_schedule().
3358c2ecf20Sopenharmony_ci * @periods_in_map:  See pmap_schedule().
3368c2ecf20Sopenharmony_ci * @num_bits:        The number of bits that was passed to schedule.
3378c2ecf20Sopenharmony_ci * @interval:        The interval that was passed to schedule.
3388c2ecf20Sopenharmony_ci * @start:           The return value from pmap_schedule().
3398c2ecf20Sopenharmony_ci */
3408c2ecf20Sopenharmony_cistatic void pmap_unschedule(unsigned long *map, int bits_per_period,
3418c2ecf20Sopenharmony_ci			    int periods_in_map, int num_bits,
3428c2ecf20Sopenharmony_ci			    int interval, int start)
3438c2ecf20Sopenharmony_ci{
3448c2ecf20Sopenharmony_ci	int interval_bits;
3458c2ecf20Sopenharmony_ci	int to_release;
3468c2ecf20Sopenharmony_ci	int i;
3478c2ecf20Sopenharmony_ci
3488c2ecf20Sopenharmony_ci	/* Adjust interval as per description in pmap_schedule() */
3498c2ecf20Sopenharmony_ci	interval = gcd(interval, periods_in_map);
3508c2ecf20Sopenharmony_ci
3518c2ecf20Sopenharmony_ci	interval_bits = bits_per_period * interval;
3528c2ecf20Sopenharmony_ci	to_release = periods_in_map / interval;
3538c2ecf20Sopenharmony_ci
3548c2ecf20Sopenharmony_ci	for (i = 0; i < to_release; i++) {
3558c2ecf20Sopenharmony_ci		int ith_start = start + interval_bits * i;
3568c2ecf20Sopenharmony_ci
3578c2ecf20Sopenharmony_ci		bitmap_clear(map, ith_start, num_bits);
3588c2ecf20Sopenharmony_ci	}
3598c2ecf20Sopenharmony_ci}
3608c2ecf20Sopenharmony_ci
3618c2ecf20Sopenharmony_ci/**
3628c2ecf20Sopenharmony_ci * dwc2_get_ls_map() - Get the map used for the given qh
3638c2ecf20Sopenharmony_ci *
3648c2ecf20Sopenharmony_ci * @hsotg: The HCD state structure for the DWC OTG controller.
3658c2ecf20Sopenharmony_ci * @qh:    QH for the periodic transfer.
3668c2ecf20Sopenharmony_ci *
3678c2ecf20Sopenharmony_ci * We'll always get the periodic map out of our TT.  Note that even if we're
3688c2ecf20Sopenharmony_ci * running the host straight in low speed / full speed mode it appears as if
3698c2ecf20Sopenharmony_ci * a TT is allocated for us, so we'll use it.  If that ever changes we can
3708c2ecf20Sopenharmony_ci * add logic here to get a map out of "hsotg" if !qh->do_split.
3718c2ecf20Sopenharmony_ci *
3728c2ecf20Sopenharmony_ci * Returns: the map or NULL if a map couldn't be found.
3738c2ecf20Sopenharmony_ci */
3748c2ecf20Sopenharmony_cistatic unsigned long *dwc2_get_ls_map(struct dwc2_hsotg *hsotg,
3758c2ecf20Sopenharmony_ci				      struct dwc2_qh *qh)
3768c2ecf20Sopenharmony_ci{
3778c2ecf20Sopenharmony_ci	unsigned long *map;
3788c2ecf20Sopenharmony_ci
3798c2ecf20Sopenharmony_ci	/* Don't expect to be missing a TT and be doing low speed scheduling */
3808c2ecf20Sopenharmony_ci	if (WARN_ON(!qh->dwc_tt))
3818c2ecf20Sopenharmony_ci		return NULL;
3828c2ecf20Sopenharmony_ci
3838c2ecf20Sopenharmony_ci	/* Get the map and adjust if this is a multi_tt hub */
3848c2ecf20Sopenharmony_ci	map = qh->dwc_tt->periodic_bitmaps;
3858c2ecf20Sopenharmony_ci	if (qh->dwc_tt->usb_tt->multi)
3868c2ecf20Sopenharmony_ci		map += DWC2_ELEMENTS_PER_LS_BITMAP * (qh->ttport - 1);
3878c2ecf20Sopenharmony_ci
3888c2ecf20Sopenharmony_ci	return map;
3898c2ecf20Sopenharmony_ci}
3908c2ecf20Sopenharmony_ci
3918c2ecf20Sopenharmony_ci#ifdef DWC2_PRINT_SCHEDULE
3928c2ecf20Sopenharmony_ci/*
3938c2ecf20Sopenharmony_ci * cat_printf() - A printf() + strcat() helper
3948c2ecf20Sopenharmony_ci *
3958c2ecf20Sopenharmony_ci * This is useful for concatenating a bunch of strings where each string is
3968c2ecf20Sopenharmony_ci * constructed using printf.
3978c2ecf20Sopenharmony_ci *
3988c2ecf20Sopenharmony_ci * @buf:   The destination buffer; will be updated to point after the printed
3998c2ecf20Sopenharmony_ci *         data.
4008c2ecf20Sopenharmony_ci * @size:  The number of bytes in the buffer (includes space for '\0').
4018c2ecf20Sopenharmony_ci * @fmt:   The format for printf.
4028c2ecf20Sopenharmony_ci * @...:   The args for printf.
4038c2ecf20Sopenharmony_ci */
4048c2ecf20Sopenharmony_cistatic __printf(3, 4)
4058c2ecf20Sopenharmony_civoid cat_printf(char **buf, size_t *size, const char *fmt, ...)
4068c2ecf20Sopenharmony_ci{
4078c2ecf20Sopenharmony_ci	va_list args;
4088c2ecf20Sopenharmony_ci	int i;
4098c2ecf20Sopenharmony_ci
4108c2ecf20Sopenharmony_ci	if (*size == 0)
4118c2ecf20Sopenharmony_ci		return;
4128c2ecf20Sopenharmony_ci
4138c2ecf20Sopenharmony_ci	va_start(args, fmt);
4148c2ecf20Sopenharmony_ci	i = vsnprintf(*buf, *size, fmt, args);
4158c2ecf20Sopenharmony_ci	va_end(args);
4168c2ecf20Sopenharmony_ci
4178c2ecf20Sopenharmony_ci	if (i >= *size) {
4188c2ecf20Sopenharmony_ci		(*buf)[*size - 1] = '\0';
4198c2ecf20Sopenharmony_ci		*buf += *size;
4208c2ecf20Sopenharmony_ci		*size = 0;
4218c2ecf20Sopenharmony_ci	} else {
4228c2ecf20Sopenharmony_ci		*buf += i;
4238c2ecf20Sopenharmony_ci		*size -= i;
4248c2ecf20Sopenharmony_ci	}
4258c2ecf20Sopenharmony_ci}
4268c2ecf20Sopenharmony_ci
4278c2ecf20Sopenharmony_ci/*
4288c2ecf20Sopenharmony_ci * pmap_print() - Print the given periodic map
4298c2ecf20Sopenharmony_ci *
4308c2ecf20Sopenharmony_ci * Will attempt to print out the periodic schedule.
4318c2ecf20Sopenharmony_ci *
4328c2ecf20Sopenharmony_ci * @map:             See pmap_schedule().
4338c2ecf20Sopenharmony_ci * @bits_per_period: See pmap_schedule().
4348c2ecf20Sopenharmony_ci * @periods_in_map:  See pmap_schedule().
4358c2ecf20Sopenharmony_ci * @period_name:     The name of 1 period, like "uFrame"
4368c2ecf20Sopenharmony_ci * @units:           The name of the units, like "us".
4378c2ecf20Sopenharmony_ci * @print_fn:        The function to call for printing.
4388c2ecf20Sopenharmony_ci * @print_data:      Opaque data to pass to the print function.
4398c2ecf20Sopenharmony_ci */
4408c2ecf20Sopenharmony_cistatic void pmap_print(unsigned long *map, int bits_per_period,
4418c2ecf20Sopenharmony_ci		       int periods_in_map, const char *period_name,
4428c2ecf20Sopenharmony_ci		       const char *units,
4438c2ecf20Sopenharmony_ci		       void (*print_fn)(const char *str, void *data),
4448c2ecf20Sopenharmony_ci		       void *print_data)
4458c2ecf20Sopenharmony_ci{
4468c2ecf20Sopenharmony_ci	int period;
4478c2ecf20Sopenharmony_ci
4488c2ecf20Sopenharmony_ci	for (period = 0; period < periods_in_map; period++) {
4498c2ecf20Sopenharmony_ci		char tmp[64];
4508c2ecf20Sopenharmony_ci		char *buf = tmp;
4518c2ecf20Sopenharmony_ci		size_t buf_size = sizeof(tmp);
4528c2ecf20Sopenharmony_ci		int period_start = period * bits_per_period;
4538c2ecf20Sopenharmony_ci		int period_end = period_start + bits_per_period;
4548c2ecf20Sopenharmony_ci		int start = 0;
4558c2ecf20Sopenharmony_ci		int count = 0;
4568c2ecf20Sopenharmony_ci		bool printed = false;
4578c2ecf20Sopenharmony_ci		int i;
4588c2ecf20Sopenharmony_ci
4598c2ecf20Sopenharmony_ci		for (i = period_start; i < period_end + 1; i++) {
4608c2ecf20Sopenharmony_ci			/* Handle case when ith bit is set */
4618c2ecf20Sopenharmony_ci			if (i < period_end &&
4628c2ecf20Sopenharmony_ci			    bitmap_find_next_zero_area(map, i + 1,
4638c2ecf20Sopenharmony_ci						       i, 1, 0) != i) {
4648c2ecf20Sopenharmony_ci				if (count == 0)
4658c2ecf20Sopenharmony_ci					start = i - period_start;
4668c2ecf20Sopenharmony_ci				count++;
4678c2ecf20Sopenharmony_ci				continue;
4688c2ecf20Sopenharmony_ci			}
4698c2ecf20Sopenharmony_ci
4708c2ecf20Sopenharmony_ci			/* ith bit isn't set; don't care if count == 0 */
4718c2ecf20Sopenharmony_ci			if (count == 0)
4728c2ecf20Sopenharmony_ci				continue;
4738c2ecf20Sopenharmony_ci
4748c2ecf20Sopenharmony_ci			if (!printed)
4758c2ecf20Sopenharmony_ci				cat_printf(&buf, &buf_size, "%s %d: ",
4768c2ecf20Sopenharmony_ci					   period_name, period);
4778c2ecf20Sopenharmony_ci			else
4788c2ecf20Sopenharmony_ci				cat_printf(&buf, &buf_size, ", ");
4798c2ecf20Sopenharmony_ci			printed = true;
4808c2ecf20Sopenharmony_ci
4818c2ecf20Sopenharmony_ci			cat_printf(&buf, &buf_size, "%d %s -%3d %s", start,
4828c2ecf20Sopenharmony_ci				   units, start + count - 1, units);
4838c2ecf20Sopenharmony_ci			count = 0;
4848c2ecf20Sopenharmony_ci		}
4858c2ecf20Sopenharmony_ci
4868c2ecf20Sopenharmony_ci		if (printed)
4878c2ecf20Sopenharmony_ci			print_fn(tmp, print_data);
4888c2ecf20Sopenharmony_ci	}
4898c2ecf20Sopenharmony_ci}
4908c2ecf20Sopenharmony_ci
4918c2ecf20Sopenharmony_cistruct dwc2_qh_print_data {
4928c2ecf20Sopenharmony_ci	struct dwc2_hsotg *hsotg;
4938c2ecf20Sopenharmony_ci	struct dwc2_qh *qh;
4948c2ecf20Sopenharmony_ci};
4958c2ecf20Sopenharmony_ci
4968c2ecf20Sopenharmony_ci/**
4978c2ecf20Sopenharmony_ci * dwc2_qh_print() - Helper function for dwc2_qh_schedule_print()
4988c2ecf20Sopenharmony_ci *
4998c2ecf20Sopenharmony_ci * @str:  The string to print
5008c2ecf20Sopenharmony_ci * @data: A pointer to a struct dwc2_qh_print_data
5018c2ecf20Sopenharmony_ci */
5028c2ecf20Sopenharmony_cistatic void dwc2_qh_print(const char *str, void *data)
5038c2ecf20Sopenharmony_ci{
5048c2ecf20Sopenharmony_ci	struct dwc2_qh_print_data *print_data = data;
5058c2ecf20Sopenharmony_ci
5068c2ecf20Sopenharmony_ci	dwc2_sch_dbg(print_data->hsotg, "QH=%p ...%s\n", print_data->qh, str);
5078c2ecf20Sopenharmony_ci}
5088c2ecf20Sopenharmony_ci
5098c2ecf20Sopenharmony_ci/**
5108c2ecf20Sopenharmony_ci * dwc2_qh_schedule_print() - Print the periodic schedule
5118c2ecf20Sopenharmony_ci *
5128c2ecf20Sopenharmony_ci * @hsotg: The HCD state structure for the DWC OTG controller.
5138c2ecf20Sopenharmony_ci * @qh:    QH to print.
5148c2ecf20Sopenharmony_ci */
5158c2ecf20Sopenharmony_cistatic void dwc2_qh_schedule_print(struct dwc2_hsotg *hsotg,
5168c2ecf20Sopenharmony_ci				   struct dwc2_qh *qh)
5178c2ecf20Sopenharmony_ci{
5188c2ecf20Sopenharmony_ci	struct dwc2_qh_print_data print_data = { hsotg, qh };
5198c2ecf20Sopenharmony_ci	int i;
5208c2ecf20Sopenharmony_ci
5218c2ecf20Sopenharmony_ci	/*
5228c2ecf20Sopenharmony_ci	 * The printing functions are quite slow and inefficient.
5238c2ecf20Sopenharmony_ci	 * If we don't have tracing turned on, don't run unless the special
5248c2ecf20Sopenharmony_ci	 * define is turned on.
5258c2ecf20Sopenharmony_ci	 */
5268c2ecf20Sopenharmony_ci
5278c2ecf20Sopenharmony_ci	if (qh->schedule_low_speed) {
5288c2ecf20Sopenharmony_ci		unsigned long *map = dwc2_get_ls_map(hsotg, qh);
5298c2ecf20Sopenharmony_ci
5308c2ecf20Sopenharmony_ci		dwc2_sch_dbg(hsotg, "QH=%p LS/FS trans: %d=>%d us @ %d us",
5318c2ecf20Sopenharmony_ci			     qh, qh->device_us,
5328c2ecf20Sopenharmony_ci			     DWC2_ROUND_US_TO_SLICE(qh->device_us),
5338c2ecf20Sopenharmony_ci			     DWC2_US_PER_SLICE * qh->ls_start_schedule_slice);
5348c2ecf20Sopenharmony_ci
5358c2ecf20Sopenharmony_ci		if (map) {
5368c2ecf20Sopenharmony_ci			dwc2_sch_dbg(hsotg,
5378c2ecf20Sopenharmony_ci				     "QH=%p Whole low/full speed map %p now:\n",
5388c2ecf20Sopenharmony_ci				     qh, map);
5398c2ecf20Sopenharmony_ci			pmap_print(map, DWC2_LS_PERIODIC_SLICES_PER_FRAME,
5408c2ecf20Sopenharmony_ci				   DWC2_LS_SCHEDULE_FRAMES, "Frame ", "slices",
5418c2ecf20Sopenharmony_ci				   dwc2_qh_print, &print_data);
5428c2ecf20Sopenharmony_ci		}
5438c2ecf20Sopenharmony_ci	}
5448c2ecf20Sopenharmony_ci
5458c2ecf20Sopenharmony_ci	for (i = 0; i < qh->num_hs_transfers; i++) {
5468c2ecf20Sopenharmony_ci		struct dwc2_hs_transfer_time *trans_time = qh->hs_transfers + i;
5478c2ecf20Sopenharmony_ci		int uframe = trans_time->start_schedule_us /
5488c2ecf20Sopenharmony_ci			     DWC2_HS_PERIODIC_US_PER_UFRAME;
5498c2ecf20Sopenharmony_ci		int rel_us = trans_time->start_schedule_us %
5508c2ecf20Sopenharmony_ci			     DWC2_HS_PERIODIC_US_PER_UFRAME;
5518c2ecf20Sopenharmony_ci
5528c2ecf20Sopenharmony_ci		dwc2_sch_dbg(hsotg,
5538c2ecf20Sopenharmony_ci			     "QH=%p HS trans #%d: %d us @ uFrame %d + %d us\n",
5548c2ecf20Sopenharmony_ci			     qh, i, trans_time->duration_us, uframe, rel_us);
5558c2ecf20Sopenharmony_ci	}
5568c2ecf20Sopenharmony_ci	if (qh->num_hs_transfers) {
5578c2ecf20Sopenharmony_ci		dwc2_sch_dbg(hsotg, "QH=%p Whole high speed map now:\n", qh);
5588c2ecf20Sopenharmony_ci		pmap_print(hsotg->hs_periodic_bitmap,
5598c2ecf20Sopenharmony_ci			   DWC2_HS_PERIODIC_US_PER_UFRAME,
5608c2ecf20Sopenharmony_ci			   DWC2_HS_SCHEDULE_UFRAMES, "uFrame", "us",
5618c2ecf20Sopenharmony_ci			   dwc2_qh_print, &print_data);
5628c2ecf20Sopenharmony_ci	}
5638c2ecf20Sopenharmony_ci}
5648c2ecf20Sopenharmony_ci#else
5658c2ecf20Sopenharmony_cistatic inline void dwc2_qh_schedule_print(struct dwc2_hsotg *hsotg,
5668c2ecf20Sopenharmony_ci					  struct dwc2_qh *qh) {};
5678c2ecf20Sopenharmony_ci#endif
5688c2ecf20Sopenharmony_ci
5698c2ecf20Sopenharmony_ci/**
5708c2ecf20Sopenharmony_ci * dwc2_ls_pmap_schedule() - Schedule a low speed QH
5718c2ecf20Sopenharmony_ci *
5728c2ecf20Sopenharmony_ci * @hsotg:        The HCD state structure for the DWC OTG controller.
5738c2ecf20Sopenharmony_ci * @qh:           QH for the periodic transfer.
5748c2ecf20Sopenharmony_ci * @search_slice: We'll start trying to schedule at the passed slice.
5758c2ecf20Sopenharmony_ci *                Remember that slices are the units of the low speed
5768c2ecf20Sopenharmony_ci *                schedule (think 25us or so).
5778c2ecf20Sopenharmony_ci *
5788c2ecf20Sopenharmony_ci * Wraps pmap_schedule() with the right parameters for low speed scheduling.
5798c2ecf20Sopenharmony_ci *
5808c2ecf20Sopenharmony_ci * Normally we schedule low speed devices on the map associated with the TT.
5818c2ecf20Sopenharmony_ci *
5828c2ecf20Sopenharmony_ci * Returns: 0 for success or an error code.
5838c2ecf20Sopenharmony_ci */
5848c2ecf20Sopenharmony_cistatic int dwc2_ls_pmap_schedule(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh,
5858c2ecf20Sopenharmony_ci				 int search_slice)
5868c2ecf20Sopenharmony_ci{
5878c2ecf20Sopenharmony_ci	int slices = DIV_ROUND_UP(qh->device_us, DWC2_US_PER_SLICE);
5888c2ecf20Sopenharmony_ci	unsigned long *map = dwc2_get_ls_map(hsotg, qh);
5898c2ecf20Sopenharmony_ci	int slice;
5908c2ecf20Sopenharmony_ci
5918c2ecf20Sopenharmony_ci	if (!map)
5928c2ecf20Sopenharmony_ci		return -EINVAL;
5938c2ecf20Sopenharmony_ci
5948c2ecf20Sopenharmony_ci	/*
5958c2ecf20Sopenharmony_ci	 * Schedule on the proper low speed map with our low speed scheduling
5968c2ecf20Sopenharmony_ci	 * parameters.  Note that we use the "device_interval" here since
5978c2ecf20Sopenharmony_ci	 * we want the low speed interval and the only way we'd be in this
5988c2ecf20Sopenharmony_ci	 * function is if the device is low speed.
5998c2ecf20Sopenharmony_ci	 *
6008c2ecf20Sopenharmony_ci	 * If we happen to be doing low speed and high speed scheduling for the
6018c2ecf20Sopenharmony_ci	 * same transaction (AKA we have a split) we always do low speed first.
6028c2ecf20Sopenharmony_ci	 * That means we can always pass "false" for only_one_period (that
6038c2ecf20Sopenharmony_ci	 * parameters is only useful when we're trying to get one schedule to
6048c2ecf20Sopenharmony_ci	 * match what we already planned in the other schedule).
6058c2ecf20Sopenharmony_ci	 */
6068c2ecf20Sopenharmony_ci	slice = pmap_schedule(map, DWC2_LS_PERIODIC_SLICES_PER_FRAME,
6078c2ecf20Sopenharmony_ci			      DWC2_LS_SCHEDULE_FRAMES, slices,
6088c2ecf20Sopenharmony_ci			      qh->device_interval, search_slice, false);
6098c2ecf20Sopenharmony_ci
6108c2ecf20Sopenharmony_ci	if (slice < 0)
6118c2ecf20Sopenharmony_ci		return slice;
6128c2ecf20Sopenharmony_ci
6138c2ecf20Sopenharmony_ci	qh->ls_start_schedule_slice = slice;
6148c2ecf20Sopenharmony_ci	return 0;
6158c2ecf20Sopenharmony_ci}
6168c2ecf20Sopenharmony_ci
6178c2ecf20Sopenharmony_ci/**
6188c2ecf20Sopenharmony_ci * dwc2_ls_pmap_unschedule() - Undo work done by dwc2_ls_pmap_schedule()
6198c2ecf20Sopenharmony_ci *
6208c2ecf20Sopenharmony_ci * @hsotg:       The HCD state structure for the DWC OTG controller.
6218c2ecf20Sopenharmony_ci * @qh:          QH for the periodic transfer.
6228c2ecf20Sopenharmony_ci */
6238c2ecf20Sopenharmony_cistatic void dwc2_ls_pmap_unschedule(struct dwc2_hsotg *hsotg,
6248c2ecf20Sopenharmony_ci				    struct dwc2_qh *qh)
6258c2ecf20Sopenharmony_ci{
6268c2ecf20Sopenharmony_ci	int slices = DIV_ROUND_UP(qh->device_us, DWC2_US_PER_SLICE);
6278c2ecf20Sopenharmony_ci	unsigned long *map = dwc2_get_ls_map(hsotg, qh);
6288c2ecf20Sopenharmony_ci
6298c2ecf20Sopenharmony_ci	/* Schedule should have failed, so no worries about no error code */
6308c2ecf20Sopenharmony_ci	if (!map)
6318c2ecf20Sopenharmony_ci		return;
6328c2ecf20Sopenharmony_ci
6338c2ecf20Sopenharmony_ci	pmap_unschedule(map, DWC2_LS_PERIODIC_SLICES_PER_FRAME,
6348c2ecf20Sopenharmony_ci			DWC2_LS_SCHEDULE_FRAMES, slices, qh->device_interval,
6358c2ecf20Sopenharmony_ci			qh->ls_start_schedule_slice);
6368c2ecf20Sopenharmony_ci}
6378c2ecf20Sopenharmony_ci
6388c2ecf20Sopenharmony_ci/**
6398c2ecf20Sopenharmony_ci * dwc2_hs_pmap_schedule - Schedule in the main high speed schedule
6408c2ecf20Sopenharmony_ci *
6418c2ecf20Sopenharmony_ci * This will schedule something on the main dwc2 schedule.
6428c2ecf20Sopenharmony_ci *
6438c2ecf20Sopenharmony_ci * We'll start looking in qh->hs_transfers[index].start_schedule_us.  We'll
6448c2ecf20Sopenharmony_ci * update this with the result upon success.  We also use the duration from
6458c2ecf20Sopenharmony_ci * the same structure.
6468c2ecf20Sopenharmony_ci *
6478c2ecf20Sopenharmony_ci * @hsotg:           The HCD state structure for the DWC OTG controller.
6488c2ecf20Sopenharmony_ci * @qh:              QH for the periodic transfer.
6498c2ecf20Sopenharmony_ci * @only_one_period: If true we will limit ourselves to just looking at
6508c2ecf20Sopenharmony_ci *                   one period (aka one 100us chunk).  This is used if we have
6518c2ecf20Sopenharmony_ci *                   already scheduled something on the low speed schedule and
6528c2ecf20Sopenharmony_ci *                   need to find something that matches on the high speed one.
6538c2ecf20Sopenharmony_ci * @index:           The index into qh->hs_transfers that we're working with.
6548c2ecf20Sopenharmony_ci *
6558c2ecf20Sopenharmony_ci * Returns: 0 for success or an error code.  Upon success the
6568c2ecf20Sopenharmony_ci *          dwc2_hs_transfer_time specified by "index" will be updated.
6578c2ecf20Sopenharmony_ci */
6588c2ecf20Sopenharmony_cistatic int dwc2_hs_pmap_schedule(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh,
6598c2ecf20Sopenharmony_ci				 bool only_one_period, int index)
6608c2ecf20Sopenharmony_ci{
6618c2ecf20Sopenharmony_ci	struct dwc2_hs_transfer_time *trans_time = qh->hs_transfers + index;
6628c2ecf20Sopenharmony_ci	int us;
6638c2ecf20Sopenharmony_ci
6648c2ecf20Sopenharmony_ci	us = pmap_schedule(hsotg->hs_periodic_bitmap,
6658c2ecf20Sopenharmony_ci			   DWC2_HS_PERIODIC_US_PER_UFRAME,
6668c2ecf20Sopenharmony_ci			   DWC2_HS_SCHEDULE_UFRAMES, trans_time->duration_us,
6678c2ecf20Sopenharmony_ci			   qh->host_interval, trans_time->start_schedule_us,
6688c2ecf20Sopenharmony_ci			   only_one_period);
6698c2ecf20Sopenharmony_ci
6708c2ecf20Sopenharmony_ci	if (us < 0)
6718c2ecf20Sopenharmony_ci		return us;
6728c2ecf20Sopenharmony_ci
6738c2ecf20Sopenharmony_ci	trans_time->start_schedule_us = us;
6748c2ecf20Sopenharmony_ci	return 0;
6758c2ecf20Sopenharmony_ci}
6768c2ecf20Sopenharmony_ci
6778c2ecf20Sopenharmony_ci/**
6788c2ecf20Sopenharmony_ci * dwc2_ls_pmap_unschedule() - Undo work done by dwc2_hs_pmap_schedule()
6798c2ecf20Sopenharmony_ci *
6808c2ecf20Sopenharmony_ci * @hsotg:       The HCD state structure for the DWC OTG controller.
6818c2ecf20Sopenharmony_ci * @qh:          QH for the periodic transfer.
6828c2ecf20Sopenharmony_ci * @index:       Transfer index
6838c2ecf20Sopenharmony_ci */
6848c2ecf20Sopenharmony_cistatic void dwc2_hs_pmap_unschedule(struct dwc2_hsotg *hsotg,
6858c2ecf20Sopenharmony_ci				    struct dwc2_qh *qh, int index)
6868c2ecf20Sopenharmony_ci{
6878c2ecf20Sopenharmony_ci	struct dwc2_hs_transfer_time *trans_time = qh->hs_transfers + index;
6888c2ecf20Sopenharmony_ci
6898c2ecf20Sopenharmony_ci	pmap_unschedule(hsotg->hs_periodic_bitmap,
6908c2ecf20Sopenharmony_ci			DWC2_HS_PERIODIC_US_PER_UFRAME,
6918c2ecf20Sopenharmony_ci			DWC2_HS_SCHEDULE_UFRAMES, trans_time->duration_us,
6928c2ecf20Sopenharmony_ci			qh->host_interval, trans_time->start_schedule_us);
6938c2ecf20Sopenharmony_ci}
6948c2ecf20Sopenharmony_ci
6958c2ecf20Sopenharmony_ci/**
6968c2ecf20Sopenharmony_ci * dwc2_uframe_schedule_split - Schedule a QH for a periodic split xfer.
6978c2ecf20Sopenharmony_ci *
6988c2ecf20Sopenharmony_ci * This is the most complicated thing in USB.  We have to find matching time
6998c2ecf20Sopenharmony_ci * in both the global high speed schedule for the port and the low speed
7008c2ecf20Sopenharmony_ci * schedule for the TT associated with the given device.
7018c2ecf20Sopenharmony_ci *
7028c2ecf20Sopenharmony_ci * Being here means that the host must be running in high speed mode and the
7038c2ecf20Sopenharmony_ci * device is in low or full speed mode (and behind a hub).
7048c2ecf20Sopenharmony_ci *
7058c2ecf20Sopenharmony_ci * @hsotg:       The HCD state structure for the DWC OTG controller.
7068c2ecf20Sopenharmony_ci * @qh:          QH for the periodic transfer.
7078c2ecf20Sopenharmony_ci */
7088c2ecf20Sopenharmony_cistatic int dwc2_uframe_schedule_split(struct dwc2_hsotg *hsotg,
7098c2ecf20Sopenharmony_ci				      struct dwc2_qh *qh)
7108c2ecf20Sopenharmony_ci{
7118c2ecf20Sopenharmony_ci	int bytecount = qh->maxp_mult * qh->maxp;
7128c2ecf20Sopenharmony_ci	int ls_search_slice;
7138c2ecf20Sopenharmony_ci	int err = 0;
7148c2ecf20Sopenharmony_ci	int host_interval_in_sched;
7158c2ecf20Sopenharmony_ci
7168c2ecf20Sopenharmony_ci	/*
7178c2ecf20Sopenharmony_ci	 * The interval (how often to repeat) in the actual host schedule.
7188c2ecf20Sopenharmony_ci	 * See pmap_schedule() for gcd() explanation.
7198c2ecf20Sopenharmony_ci	 */
7208c2ecf20Sopenharmony_ci	host_interval_in_sched = gcd(qh->host_interval,
7218c2ecf20Sopenharmony_ci				     DWC2_HS_SCHEDULE_UFRAMES);
7228c2ecf20Sopenharmony_ci
7238c2ecf20Sopenharmony_ci	/*
7248c2ecf20Sopenharmony_ci	 * We always try to find space in the low speed schedule first, then
7258c2ecf20Sopenharmony_ci	 * try to find high speed time that matches.  If we don't, we'll bump
7268c2ecf20Sopenharmony_ci	 * up the place we start searching in the low speed schedule and try
7278c2ecf20Sopenharmony_ci	 * again.  To start we'll look right at the beginning of the low speed
7288c2ecf20Sopenharmony_ci	 * schedule.
7298c2ecf20Sopenharmony_ci	 *
7308c2ecf20Sopenharmony_ci	 * Note that this will tend to front-load the high speed schedule.
7318c2ecf20Sopenharmony_ci	 * We may eventually want to try to avoid this by either considering
7328c2ecf20Sopenharmony_ci	 * both schedules together or doing some sort of round robin.
7338c2ecf20Sopenharmony_ci	 */
7348c2ecf20Sopenharmony_ci	ls_search_slice = 0;
7358c2ecf20Sopenharmony_ci
7368c2ecf20Sopenharmony_ci	while (ls_search_slice < DWC2_LS_SCHEDULE_SLICES) {
7378c2ecf20Sopenharmony_ci		int start_s_uframe;
7388c2ecf20Sopenharmony_ci		int ssplit_s_uframe;
7398c2ecf20Sopenharmony_ci		int second_s_uframe;
7408c2ecf20Sopenharmony_ci		int rel_uframe;
7418c2ecf20Sopenharmony_ci		int first_count;
7428c2ecf20Sopenharmony_ci		int middle_count;
7438c2ecf20Sopenharmony_ci		int end_count;
7448c2ecf20Sopenharmony_ci		int first_data_bytes;
7458c2ecf20Sopenharmony_ci		int other_data_bytes;
7468c2ecf20Sopenharmony_ci		int i;
7478c2ecf20Sopenharmony_ci
7488c2ecf20Sopenharmony_ci		if (qh->schedule_low_speed) {
7498c2ecf20Sopenharmony_ci			err = dwc2_ls_pmap_schedule(hsotg, qh, ls_search_slice);
7508c2ecf20Sopenharmony_ci
7518c2ecf20Sopenharmony_ci			/*
7528c2ecf20Sopenharmony_ci			 * If we got an error here there's no other magic we
7538c2ecf20Sopenharmony_ci			 * can do, so bail.  All the looping above is only
7548c2ecf20Sopenharmony_ci			 * helpful to redo things if we got a low speed slot
7558c2ecf20Sopenharmony_ci			 * and then couldn't find a matching high speed slot.
7568c2ecf20Sopenharmony_ci			 */
7578c2ecf20Sopenharmony_ci			if (err)
7588c2ecf20Sopenharmony_ci				return err;
7598c2ecf20Sopenharmony_ci		} else {
7608c2ecf20Sopenharmony_ci			/* Must be missing the tt structure?  Why? */
7618c2ecf20Sopenharmony_ci			WARN_ON_ONCE(1);
7628c2ecf20Sopenharmony_ci		}
7638c2ecf20Sopenharmony_ci
7648c2ecf20Sopenharmony_ci		/*
7658c2ecf20Sopenharmony_ci		 * This will give us a number 0 - 7 if
7668c2ecf20Sopenharmony_ci		 * DWC2_LS_SCHEDULE_FRAMES == 1, or 0 - 15 if == 2, or ...
7678c2ecf20Sopenharmony_ci		 */
7688c2ecf20Sopenharmony_ci		start_s_uframe = qh->ls_start_schedule_slice /
7698c2ecf20Sopenharmony_ci				 DWC2_SLICES_PER_UFRAME;
7708c2ecf20Sopenharmony_ci
7718c2ecf20Sopenharmony_ci		/* Get a number that's always 0 - 7 */
7728c2ecf20Sopenharmony_ci		rel_uframe = (start_s_uframe % 8);
7738c2ecf20Sopenharmony_ci
7748c2ecf20Sopenharmony_ci		/*
7758c2ecf20Sopenharmony_ci		 * If we were going to start in uframe 7 then we would need to
7768c2ecf20Sopenharmony_ci		 * issue a start split in uframe 6, which spec says is not OK.
7778c2ecf20Sopenharmony_ci		 * Move on to the next full frame (assuming there is one).
7788c2ecf20Sopenharmony_ci		 *
7798c2ecf20Sopenharmony_ci		 * See 11.18.4 Host Split Transaction Scheduling Requirements
7808c2ecf20Sopenharmony_ci		 * bullet 1.
7818c2ecf20Sopenharmony_ci		 */
7828c2ecf20Sopenharmony_ci		if (rel_uframe == 7) {
7838c2ecf20Sopenharmony_ci			if (qh->schedule_low_speed)
7848c2ecf20Sopenharmony_ci				dwc2_ls_pmap_unschedule(hsotg, qh);
7858c2ecf20Sopenharmony_ci			ls_search_slice =
7868c2ecf20Sopenharmony_ci				(qh->ls_start_schedule_slice /
7878c2ecf20Sopenharmony_ci				 DWC2_LS_PERIODIC_SLICES_PER_FRAME + 1) *
7888c2ecf20Sopenharmony_ci				DWC2_LS_PERIODIC_SLICES_PER_FRAME;
7898c2ecf20Sopenharmony_ci			continue;
7908c2ecf20Sopenharmony_ci		}
7918c2ecf20Sopenharmony_ci
7928c2ecf20Sopenharmony_ci		/*
7938c2ecf20Sopenharmony_ci		 * For ISOC in:
7948c2ecf20Sopenharmony_ci		 * - start split            (frame -1)
7958c2ecf20Sopenharmony_ci		 * - complete split w/ data (frame +1)
7968c2ecf20Sopenharmony_ci		 * - complete split w/ data (frame +2)
7978c2ecf20Sopenharmony_ci		 * - ...
7988c2ecf20Sopenharmony_ci		 * - complete split w/ data (frame +num_data_packets)
7998c2ecf20Sopenharmony_ci		 * - complete split w/ data (frame +num_data_packets+1)
8008c2ecf20Sopenharmony_ci		 * - complete split w/ data (frame +num_data_packets+2, max 8)
8018c2ecf20Sopenharmony_ci		 *   ...though if frame was "0" then max is 7...
8028c2ecf20Sopenharmony_ci		 *
8038c2ecf20Sopenharmony_ci		 * For ISOC out we might need to do:
8048c2ecf20Sopenharmony_ci		 * - start split w/ data    (frame -1)
8058c2ecf20Sopenharmony_ci		 * - start split w/ data    (frame +0)
8068c2ecf20Sopenharmony_ci		 * - ...
8078c2ecf20Sopenharmony_ci		 * - start split w/ data    (frame +num_data_packets-2)
8088c2ecf20Sopenharmony_ci		 *
8098c2ecf20Sopenharmony_ci		 * For INTERRUPT in we might need to do:
8108c2ecf20Sopenharmony_ci		 * - start split            (frame -1)
8118c2ecf20Sopenharmony_ci		 * - complete split w/ data (frame +1)
8128c2ecf20Sopenharmony_ci		 * - complete split w/ data (frame +2)
8138c2ecf20Sopenharmony_ci		 * - complete split w/ data (frame +3, max 8)
8148c2ecf20Sopenharmony_ci		 *
8158c2ecf20Sopenharmony_ci		 * For INTERRUPT out we might need to do:
8168c2ecf20Sopenharmony_ci		 * - start split w/ data    (frame -1)
8178c2ecf20Sopenharmony_ci		 * - complete split         (frame +1)
8188c2ecf20Sopenharmony_ci		 * - complete split         (frame +2)
8198c2ecf20Sopenharmony_ci		 * - complete split         (frame +3, max 8)
8208c2ecf20Sopenharmony_ci		 *
8218c2ecf20Sopenharmony_ci		 * Start adjusting!
8228c2ecf20Sopenharmony_ci		 */
8238c2ecf20Sopenharmony_ci		ssplit_s_uframe = (start_s_uframe +
8248c2ecf20Sopenharmony_ci				   host_interval_in_sched - 1) %
8258c2ecf20Sopenharmony_ci				  host_interval_in_sched;
8268c2ecf20Sopenharmony_ci		if (qh->ep_type == USB_ENDPOINT_XFER_ISOC && !qh->ep_is_in)
8278c2ecf20Sopenharmony_ci			second_s_uframe = start_s_uframe;
8288c2ecf20Sopenharmony_ci		else
8298c2ecf20Sopenharmony_ci			second_s_uframe = start_s_uframe + 1;
8308c2ecf20Sopenharmony_ci
8318c2ecf20Sopenharmony_ci		/* First data transfer might not be all 188 bytes. */
8328c2ecf20Sopenharmony_ci		first_data_bytes = 188 -
8338c2ecf20Sopenharmony_ci			DIV_ROUND_UP(188 * (qh->ls_start_schedule_slice %
8348c2ecf20Sopenharmony_ci					    DWC2_SLICES_PER_UFRAME),
8358c2ecf20Sopenharmony_ci				     DWC2_SLICES_PER_UFRAME);
8368c2ecf20Sopenharmony_ci		if (first_data_bytes > bytecount)
8378c2ecf20Sopenharmony_ci			first_data_bytes = bytecount;
8388c2ecf20Sopenharmony_ci		other_data_bytes = bytecount - first_data_bytes;
8398c2ecf20Sopenharmony_ci
8408c2ecf20Sopenharmony_ci		/*
8418c2ecf20Sopenharmony_ci		 * For now, skip OUT xfers where first xfer is partial
8428c2ecf20Sopenharmony_ci		 *
8438c2ecf20Sopenharmony_ci		 * Main dwc2 code assumes:
8448c2ecf20Sopenharmony_ci		 * - INT transfers never get split in two.
8458c2ecf20Sopenharmony_ci		 * - ISOC transfers can always transfer 188 bytes the first
8468c2ecf20Sopenharmony_ci		 *   time.
8478c2ecf20Sopenharmony_ci		 *
8488c2ecf20Sopenharmony_ci		 * Until that code is fixed, try again if the first transfer
8498c2ecf20Sopenharmony_ci		 * couldn't transfer everything.
8508c2ecf20Sopenharmony_ci		 *
8518c2ecf20Sopenharmony_ci		 * This code can be removed if/when the rest of dwc2 handles
8528c2ecf20Sopenharmony_ci		 * the above cases.  Until it's fixed we just won't be able
8538c2ecf20Sopenharmony_ci		 * to schedule quite as tightly.
8548c2ecf20Sopenharmony_ci		 */
8558c2ecf20Sopenharmony_ci		if (!qh->ep_is_in &&
8568c2ecf20Sopenharmony_ci		    (first_data_bytes != min_t(int, 188, bytecount))) {
8578c2ecf20Sopenharmony_ci			dwc2_sch_dbg(hsotg,
8588c2ecf20Sopenharmony_ci				     "QH=%p avoiding broken 1st xfer (%d, %d)\n",
8598c2ecf20Sopenharmony_ci				     qh, first_data_bytes, bytecount);
8608c2ecf20Sopenharmony_ci			if (qh->schedule_low_speed)
8618c2ecf20Sopenharmony_ci				dwc2_ls_pmap_unschedule(hsotg, qh);
8628c2ecf20Sopenharmony_ci			ls_search_slice = (start_s_uframe + 1) *
8638c2ecf20Sopenharmony_ci				DWC2_SLICES_PER_UFRAME;
8648c2ecf20Sopenharmony_ci			continue;
8658c2ecf20Sopenharmony_ci		}
8668c2ecf20Sopenharmony_ci
8678c2ecf20Sopenharmony_ci		/* Start by assuming transfers for the bytes */
8688c2ecf20Sopenharmony_ci		qh->num_hs_transfers = 1 + DIV_ROUND_UP(other_data_bytes, 188);
8698c2ecf20Sopenharmony_ci
8708c2ecf20Sopenharmony_ci		/*
8718c2ecf20Sopenharmony_ci		 * Everything except ISOC OUT has extra transfers.  Rules are
8728c2ecf20Sopenharmony_ci		 * complicated.  See 11.18.4 Host Split Transaction Scheduling
8738c2ecf20Sopenharmony_ci		 * Requirements bullet 3.
8748c2ecf20Sopenharmony_ci		 */
8758c2ecf20Sopenharmony_ci		if (qh->ep_type == USB_ENDPOINT_XFER_INT) {
8768c2ecf20Sopenharmony_ci			if (rel_uframe == 6)
8778c2ecf20Sopenharmony_ci				qh->num_hs_transfers += 2;
8788c2ecf20Sopenharmony_ci			else
8798c2ecf20Sopenharmony_ci				qh->num_hs_transfers += 3;
8808c2ecf20Sopenharmony_ci
8818c2ecf20Sopenharmony_ci			if (qh->ep_is_in) {
8828c2ecf20Sopenharmony_ci				/*
8838c2ecf20Sopenharmony_ci				 * First is start split, middle/end is data.
8848c2ecf20Sopenharmony_ci				 * Allocate full data bytes for all data.
8858c2ecf20Sopenharmony_ci				 */
8868c2ecf20Sopenharmony_ci				first_count = 4;
8878c2ecf20Sopenharmony_ci				middle_count = bytecount;
8888c2ecf20Sopenharmony_ci				end_count = bytecount;
8898c2ecf20Sopenharmony_ci			} else {
8908c2ecf20Sopenharmony_ci				/*
8918c2ecf20Sopenharmony_ci				 * First is data, middle/end is complete.
8928c2ecf20Sopenharmony_ci				 * First transfer and second can have data.
8938c2ecf20Sopenharmony_ci				 * Rest should just have complete split.
8948c2ecf20Sopenharmony_ci				 */
8958c2ecf20Sopenharmony_ci				first_count = first_data_bytes;
8968c2ecf20Sopenharmony_ci				middle_count = max_t(int, 4, other_data_bytes);
8978c2ecf20Sopenharmony_ci				end_count = 4;
8988c2ecf20Sopenharmony_ci			}
8998c2ecf20Sopenharmony_ci		} else {
9008c2ecf20Sopenharmony_ci			if (qh->ep_is_in) {
9018c2ecf20Sopenharmony_ci				int last;
9028c2ecf20Sopenharmony_ci
9038c2ecf20Sopenharmony_ci				/* Account for the start split */
9048c2ecf20Sopenharmony_ci				qh->num_hs_transfers++;
9058c2ecf20Sopenharmony_ci
9068c2ecf20Sopenharmony_ci				/* Calculate "L" value from spec */
9078c2ecf20Sopenharmony_ci				last = rel_uframe + qh->num_hs_transfers + 1;
9088c2ecf20Sopenharmony_ci
9098c2ecf20Sopenharmony_ci				/* Start with basic case */
9108c2ecf20Sopenharmony_ci				if (last <= 6)
9118c2ecf20Sopenharmony_ci					qh->num_hs_transfers += 2;
9128c2ecf20Sopenharmony_ci				else
9138c2ecf20Sopenharmony_ci					qh->num_hs_transfers += 1;
9148c2ecf20Sopenharmony_ci
9158c2ecf20Sopenharmony_ci				/* Adjust downwards */
9168c2ecf20Sopenharmony_ci				if (last >= 6 && rel_uframe == 0)
9178c2ecf20Sopenharmony_ci					qh->num_hs_transfers--;
9188c2ecf20Sopenharmony_ci
9198c2ecf20Sopenharmony_ci				/* 1st = start; rest can contain data */
9208c2ecf20Sopenharmony_ci				first_count = 4;
9218c2ecf20Sopenharmony_ci				middle_count = min_t(int, 188, bytecount);
9228c2ecf20Sopenharmony_ci				end_count = middle_count;
9238c2ecf20Sopenharmony_ci			} else {
9248c2ecf20Sopenharmony_ci				/* All contain data, last might be smaller */
9258c2ecf20Sopenharmony_ci				first_count = first_data_bytes;
9268c2ecf20Sopenharmony_ci				middle_count = min_t(int, 188,
9278c2ecf20Sopenharmony_ci						     other_data_bytes);
9288c2ecf20Sopenharmony_ci				end_count = other_data_bytes % 188;
9298c2ecf20Sopenharmony_ci			}
9308c2ecf20Sopenharmony_ci		}
9318c2ecf20Sopenharmony_ci
9328c2ecf20Sopenharmony_ci		/* Assign durations per uFrame */
9338c2ecf20Sopenharmony_ci		qh->hs_transfers[0].duration_us = HS_USECS_ISO(first_count);
9348c2ecf20Sopenharmony_ci		for (i = 1; i < qh->num_hs_transfers - 1; i++)
9358c2ecf20Sopenharmony_ci			qh->hs_transfers[i].duration_us =
9368c2ecf20Sopenharmony_ci				HS_USECS_ISO(middle_count);
9378c2ecf20Sopenharmony_ci		if (qh->num_hs_transfers > 1)
9388c2ecf20Sopenharmony_ci			qh->hs_transfers[qh->num_hs_transfers - 1].duration_us =
9398c2ecf20Sopenharmony_ci				HS_USECS_ISO(end_count);
9408c2ecf20Sopenharmony_ci
9418c2ecf20Sopenharmony_ci		/*
9428c2ecf20Sopenharmony_ci		 * Assign start us.  The call below to dwc2_hs_pmap_schedule()
9438c2ecf20Sopenharmony_ci		 * will start with these numbers but may adjust within the same
9448c2ecf20Sopenharmony_ci		 * microframe.
9458c2ecf20Sopenharmony_ci		 */
9468c2ecf20Sopenharmony_ci		qh->hs_transfers[0].start_schedule_us =
9478c2ecf20Sopenharmony_ci			ssplit_s_uframe * DWC2_HS_PERIODIC_US_PER_UFRAME;
9488c2ecf20Sopenharmony_ci		for (i = 1; i < qh->num_hs_transfers; i++)
9498c2ecf20Sopenharmony_ci			qh->hs_transfers[i].start_schedule_us =
9508c2ecf20Sopenharmony_ci				((second_s_uframe + i - 1) %
9518c2ecf20Sopenharmony_ci				 DWC2_HS_SCHEDULE_UFRAMES) *
9528c2ecf20Sopenharmony_ci				DWC2_HS_PERIODIC_US_PER_UFRAME;
9538c2ecf20Sopenharmony_ci
9548c2ecf20Sopenharmony_ci		/* Try to schedule with filled in hs_transfers above */
9558c2ecf20Sopenharmony_ci		for (i = 0; i < qh->num_hs_transfers; i++) {
9568c2ecf20Sopenharmony_ci			err = dwc2_hs_pmap_schedule(hsotg, qh, true, i);
9578c2ecf20Sopenharmony_ci			if (err)
9588c2ecf20Sopenharmony_ci				break;
9598c2ecf20Sopenharmony_ci		}
9608c2ecf20Sopenharmony_ci
9618c2ecf20Sopenharmony_ci		/* If we scheduled all w/out breaking out then we're all good */
9628c2ecf20Sopenharmony_ci		if (i == qh->num_hs_transfers)
9638c2ecf20Sopenharmony_ci			break;
9648c2ecf20Sopenharmony_ci
9658c2ecf20Sopenharmony_ci		for (; i >= 0; i--)
9668c2ecf20Sopenharmony_ci			dwc2_hs_pmap_unschedule(hsotg, qh, i);
9678c2ecf20Sopenharmony_ci
9688c2ecf20Sopenharmony_ci		if (qh->schedule_low_speed)
9698c2ecf20Sopenharmony_ci			dwc2_ls_pmap_unschedule(hsotg, qh);
9708c2ecf20Sopenharmony_ci
9718c2ecf20Sopenharmony_ci		/* Try again starting in the next microframe */
9728c2ecf20Sopenharmony_ci		ls_search_slice = (start_s_uframe + 1) * DWC2_SLICES_PER_UFRAME;
9738c2ecf20Sopenharmony_ci	}
9748c2ecf20Sopenharmony_ci
9758c2ecf20Sopenharmony_ci	if (ls_search_slice >= DWC2_LS_SCHEDULE_SLICES)
9768c2ecf20Sopenharmony_ci		return -ENOSPC;
9778c2ecf20Sopenharmony_ci
9788c2ecf20Sopenharmony_ci	return 0;
9798c2ecf20Sopenharmony_ci}
9808c2ecf20Sopenharmony_ci
9818c2ecf20Sopenharmony_ci/**
9828c2ecf20Sopenharmony_ci * dwc2_uframe_schedule_hs - Schedule a QH for a periodic high speed xfer.
9838c2ecf20Sopenharmony_ci *
9848c2ecf20Sopenharmony_ci * Basically this just wraps dwc2_hs_pmap_schedule() to provide a clean
9858c2ecf20Sopenharmony_ci * interface.
9868c2ecf20Sopenharmony_ci *
9878c2ecf20Sopenharmony_ci * @hsotg:       The HCD state structure for the DWC OTG controller.
9888c2ecf20Sopenharmony_ci * @qh:          QH for the periodic transfer.
9898c2ecf20Sopenharmony_ci */
9908c2ecf20Sopenharmony_cistatic int dwc2_uframe_schedule_hs(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh)
9918c2ecf20Sopenharmony_ci{
9928c2ecf20Sopenharmony_ci	/* In non-split host and device time are the same */
9938c2ecf20Sopenharmony_ci	WARN_ON(qh->host_us != qh->device_us);
9948c2ecf20Sopenharmony_ci	WARN_ON(qh->host_interval != qh->device_interval);
9958c2ecf20Sopenharmony_ci	WARN_ON(qh->num_hs_transfers != 1);
9968c2ecf20Sopenharmony_ci
9978c2ecf20Sopenharmony_ci	/* We'll have one transfer; init start to 0 before calling scheduler */
9988c2ecf20Sopenharmony_ci	qh->hs_transfers[0].start_schedule_us = 0;
9998c2ecf20Sopenharmony_ci	qh->hs_transfers[0].duration_us = qh->host_us;
10008c2ecf20Sopenharmony_ci
10018c2ecf20Sopenharmony_ci	return dwc2_hs_pmap_schedule(hsotg, qh, false, 0);
10028c2ecf20Sopenharmony_ci}
10038c2ecf20Sopenharmony_ci
10048c2ecf20Sopenharmony_ci/**
10058c2ecf20Sopenharmony_ci * dwc2_uframe_schedule_ls - Schedule a QH for a periodic low/full speed xfer.
10068c2ecf20Sopenharmony_ci *
10078c2ecf20Sopenharmony_ci * Basically this just wraps dwc2_ls_pmap_schedule() to provide a clean
10088c2ecf20Sopenharmony_ci * interface.
10098c2ecf20Sopenharmony_ci *
10108c2ecf20Sopenharmony_ci * @hsotg:       The HCD state structure for the DWC OTG controller.
10118c2ecf20Sopenharmony_ci * @qh:          QH for the periodic transfer.
10128c2ecf20Sopenharmony_ci */
10138c2ecf20Sopenharmony_cistatic int dwc2_uframe_schedule_ls(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh)
10148c2ecf20Sopenharmony_ci{
10158c2ecf20Sopenharmony_ci	/* In non-split host and device time are the same */
10168c2ecf20Sopenharmony_ci	WARN_ON(qh->host_us != qh->device_us);
10178c2ecf20Sopenharmony_ci	WARN_ON(qh->host_interval != qh->device_interval);
10188c2ecf20Sopenharmony_ci	WARN_ON(!qh->schedule_low_speed);
10198c2ecf20Sopenharmony_ci
10208c2ecf20Sopenharmony_ci	/* Run on the main low speed schedule (no split = no hub = no TT) */
10218c2ecf20Sopenharmony_ci	return dwc2_ls_pmap_schedule(hsotg, qh, 0);
10228c2ecf20Sopenharmony_ci}
10238c2ecf20Sopenharmony_ci
10248c2ecf20Sopenharmony_ci/**
10258c2ecf20Sopenharmony_ci * dwc2_uframe_schedule - Schedule a QH for a periodic xfer.
10268c2ecf20Sopenharmony_ci *
10278c2ecf20Sopenharmony_ci * Calls one of the 3 sub-function depending on what type of transfer this QH
10288c2ecf20Sopenharmony_ci * is for.  Also adds some printing.
10298c2ecf20Sopenharmony_ci *
10308c2ecf20Sopenharmony_ci * @hsotg:       The HCD state structure for the DWC OTG controller.
10318c2ecf20Sopenharmony_ci * @qh:          QH for the periodic transfer.
10328c2ecf20Sopenharmony_ci */
10338c2ecf20Sopenharmony_cistatic int dwc2_uframe_schedule(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh)
10348c2ecf20Sopenharmony_ci{
10358c2ecf20Sopenharmony_ci	int ret;
10368c2ecf20Sopenharmony_ci
10378c2ecf20Sopenharmony_ci	if (qh->dev_speed == USB_SPEED_HIGH)
10388c2ecf20Sopenharmony_ci		ret = dwc2_uframe_schedule_hs(hsotg, qh);
10398c2ecf20Sopenharmony_ci	else if (!qh->do_split)
10408c2ecf20Sopenharmony_ci		ret = dwc2_uframe_schedule_ls(hsotg, qh);
10418c2ecf20Sopenharmony_ci	else
10428c2ecf20Sopenharmony_ci		ret = dwc2_uframe_schedule_split(hsotg, qh);
10438c2ecf20Sopenharmony_ci
10448c2ecf20Sopenharmony_ci	if (ret)
10458c2ecf20Sopenharmony_ci		dwc2_sch_dbg(hsotg, "QH=%p Failed to schedule %d\n", qh, ret);
10468c2ecf20Sopenharmony_ci	else
10478c2ecf20Sopenharmony_ci		dwc2_qh_schedule_print(hsotg, qh);
10488c2ecf20Sopenharmony_ci
10498c2ecf20Sopenharmony_ci	return ret;
10508c2ecf20Sopenharmony_ci}
10518c2ecf20Sopenharmony_ci
10528c2ecf20Sopenharmony_ci/**
10538c2ecf20Sopenharmony_ci * dwc2_uframe_unschedule - Undoes dwc2_uframe_schedule().
10548c2ecf20Sopenharmony_ci *
10558c2ecf20Sopenharmony_ci * @hsotg:       The HCD state structure for the DWC OTG controller.
10568c2ecf20Sopenharmony_ci * @qh:          QH for the periodic transfer.
10578c2ecf20Sopenharmony_ci */
10588c2ecf20Sopenharmony_cistatic void dwc2_uframe_unschedule(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh)
10598c2ecf20Sopenharmony_ci{
10608c2ecf20Sopenharmony_ci	int i;
10618c2ecf20Sopenharmony_ci
10628c2ecf20Sopenharmony_ci	for (i = 0; i < qh->num_hs_transfers; i++)
10638c2ecf20Sopenharmony_ci		dwc2_hs_pmap_unschedule(hsotg, qh, i);
10648c2ecf20Sopenharmony_ci
10658c2ecf20Sopenharmony_ci	if (qh->schedule_low_speed)
10668c2ecf20Sopenharmony_ci		dwc2_ls_pmap_unschedule(hsotg, qh);
10678c2ecf20Sopenharmony_ci
10688c2ecf20Sopenharmony_ci	dwc2_sch_dbg(hsotg, "QH=%p Unscheduled\n", qh);
10698c2ecf20Sopenharmony_ci}
10708c2ecf20Sopenharmony_ci
10718c2ecf20Sopenharmony_ci/**
10728c2ecf20Sopenharmony_ci * dwc2_pick_first_frame() - Choose 1st frame for qh that's already scheduled
10738c2ecf20Sopenharmony_ci *
10748c2ecf20Sopenharmony_ci * Takes a qh that has already been scheduled (which means we know we have the
10758c2ecf20Sopenharmony_ci * bandwdith reserved for us) and set the next_active_frame and the
10768c2ecf20Sopenharmony_ci * start_active_frame.
10778c2ecf20Sopenharmony_ci *
10788c2ecf20Sopenharmony_ci * This is expected to be called on qh's that weren't previously actively
10798c2ecf20Sopenharmony_ci * running.  It just picks the next frame that we can fit into without any
10808c2ecf20Sopenharmony_ci * thought about the past.
10818c2ecf20Sopenharmony_ci *
10828c2ecf20Sopenharmony_ci * @hsotg: The HCD state structure for the DWC OTG controller
10838c2ecf20Sopenharmony_ci * @qh:    QH for a periodic endpoint
10848c2ecf20Sopenharmony_ci *
10858c2ecf20Sopenharmony_ci */
10868c2ecf20Sopenharmony_cistatic void dwc2_pick_first_frame(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh)
10878c2ecf20Sopenharmony_ci{
10888c2ecf20Sopenharmony_ci	u16 frame_number;
10898c2ecf20Sopenharmony_ci	u16 earliest_frame;
10908c2ecf20Sopenharmony_ci	u16 next_active_frame;
10918c2ecf20Sopenharmony_ci	u16 relative_frame;
10928c2ecf20Sopenharmony_ci	u16 interval;
10938c2ecf20Sopenharmony_ci
10948c2ecf20Sopenharmony_ci	/*
10958c2ecf20Sopenharmony_ci	 * Use the real frame number rather than the cached value as of the
10968c2ecf20Sopenharmony_ci	 * last SOF to give us a little extra slop.
10978c2ecf20Sopenharmony_ci	 */
10988c2ecf20Sopenharmony_ci	frame_number = dwc2_hcd_get_frame_number(hsotg);
10998c2ecf20Sopenharmony_ci
11008c2ecf20Sopenharmony_ci	/*
11018c2ecf20Sopenharmony_ci	 * We wouldn't want to start any earlier than the next frame just in
11028c2ecf20Sopenharmony_ci	 * case the frame number ticks as we're doing this calculation.
11038c2ecf20Sopenharmony_ci	 *
11048c2ecf20Sopenharmony_ci	 * NOTE: if we could quantify how long till we actually get scheduled
11058c2ecf20Sopenharmony_ci	 * we might be able to avoid the "+ 1" by looking at the upper part of
11068c2ecf20Sopenharmony_ci	 * HFNUM (the FRREM field).  For now we'll just use the + 1 though.
11078c2ecf20Sopenharmony_ci	 */
11088c2ecf20Sopenharmony_ci	earliest_frame = dwc2_frame_num_inc(frame_number, 1);
11098c2ecf20Sopenharmony_ci	next_active_frame = earliest_frame;
11108c2ecf20Sopenharmony_ci
11118c2ecf20Sopenharmony_ci	/* Get the "no microframe schduler" out of the way... */
11128c2ecf20Sopenharmony_ci	if (!hsotg->params.uframe_sched) {
11138c2ecf20Sopenharmony_ci		if (qh->do_split)
11148c2ecf20Sopenharmony_ci			/* Splits are active at microframe 0 minus 1 */
11158c2ecf20Sopenharmony_ci			next_active_frame |= 0x7;
11168c2ecf20Sopenharmony_ci		goto exit;
11178c2ecf20Sopenharmony_ci	}
11188c2ecf20Sopenharmony_ci
11198c2ecf20Sopenharmony_ci	if (qh->dev_speed == USB_SPEED_HIGH || qh->do_split) {
11208c2ecf20Sopenharmony_ci		/*
11218c2ecf20Sopenharmony_ci		 * We're either at high speed or we're doing a split (which
11228c2ecf20Sopenharmony_ci		 * means we're talking high speed to a hub).  In any case
11238c2ecf20Sopenharmony_ci		 * the first frame should be based on when the first scheduled
11248c2ecf20Sopenharmony_ci		 * event is.
11258c2ecf20Sopenharmony_ci		 */
11268c2ecf20Sopenharmony_ci		WARN_ON(qh->num_hs_transfers < 1);
11278c2ecf20Sopenharmony_ci
11288c2ecf20Sopenharmony_ci		relative_frame = qh->hs_transfers[0].start_schedule_us /
11298c2ecf20Sopenharmony_ci				 DWC2_HS_PERIODIC_US_PER_UFRAME;
11308c2ecf20Sopenharmony_ci
11318c2ecf20Sopenharmony_ci		/* Adjust interval as per high speed schedule */
11328c2ecf20Sopenharmony_ci		interval = gcd(qh->host_interval, DWC2_HS_SCHEDULE_UFRAMES);
11338c2ecf20Sopenharmony_ci
11348c2ecf20Sopenharmony_ci	} else {
11358c2ecf20Sopenharmony_ci		/*
11368c2ecf20Sopenharmony_ci		 * Low or full speed directly on dwc2.  Just about the same
11378c2ecf20Sopenharmony_ci		 * as high speed but on a different schedule and with slightly
11388c2ecf20Sopenharmony_ci		 * different adjustments.  Note that this works because when
11398c2ecf20Sopenharmony_ci		 * the host and device are both low speed then frames in the
11408c2ecf20Sopenharmony_ci		 * controller tick at low speed.
11418c2ecf20Sopenharmony_ci		 */
11428c2ecf20Sopenharmony_ci		relative_frame = qh->ls_start_schedule_slice /
11438c2ecf20Sopenharmony_ci				 DWC2_LS_PERIODIC_SLICES_PER_FRAME;
11448c2ecf20Sopenharmony_ci		interval = gcd(qh->host_interval, DWC2_LS_SCHEDULE_FRAMES);
11458c2ecf20Sopenharmony_ci	}
11468c2ecf20Sopenharmony_ci
11478c2ecf20Sopenharmony_ci	/* Scheduler messed up if frame is past interval */
11488c2ecf20Sopenharmony_ci	WARN_ON(relative_frame >= interval);
11498c2ecf20Sopenharmony_ci
11508c2ecf20Sopenharmony_ci	/*
11518c2ecf20Sopenharmony_ci	 * We know interval must divide (HFNUM_MAX_FRNUM + 1) now that we've
11528c2ecf20Sopenharmony_ci	 * done the gcd(), so it's safe to move to the beginning of the current
11538c2ecf20Sopenharmony_ci	 * interval like this.
11548c2ecf20Sopenharmony_ci	 *
11558c2ecf20Sopenharmony_ci	 * After this we might be before earliest_frame, but don't worry,
11568c2ecf20Sopenharmony_ci	 * we'll fix it...
11578c2ecf20Sopenharmony_ci	 */
11588c2ecf20Sopenharmony_ci	next_active_frame = (next_active_frame / interval) * interval;
11598c2ecf20Sopenharmony_ci
11608c2ecf20Sopenharmony_ci	/*
11618c2ecf20Sopenharmony_ci	 * Actually choose to start at the frame number we've been
11628c2ecf20Sopenharmony_ci	 * scheduled for.
11638c2ecf20Sopenharmony_ci	 */
11648c2ecf20Sopenharmony_ci	next_active_frame = dwc2_frame_num_inc(next_active_frame,
11658c2ecf20Sopenharmony_ci					       relative_frame);
11668c2ecf20Sopenharmony_ci
11678c2ecf20Sopenharmony_ci	/*
11688c2ecf20Sopenharmony_ci	 * We actually need 1 frame before since the next_active_frame is
11698c2ecf20Sopenharmony_ci	 * the frame number we'll be put on the ready list and we won't be on
11708c2ecf20Sopenharmony_ci	 * the bus until 1 frame later.
11718c2ecf20Sopenharmony_ci	 */
11728c2ecf20Sopenharmony_ci	next_active_frame = dwc2_frame_num_dec(next_active_frame, 1);
11738c2ecf20Sopenharmony_ci
11748c2ecf20Sopenharmony_ci	/*
11758c2ecf20Sopenharmony_ci	 * By now we might actually be before the earliest_frame.  Let's move
11768c2ecf20Sopenharmony_ci	 * up intervals until we're not.
11778c2ecf20Sopenharmony_ci	 */
11788c2ecf20Sopenharmony_ci	while (dwc2_frame_num_gt(earliest_frame, next_active_frame))
11798c2ecf20Sopenharmony_ci		next_active_frame = dwc2_frame_num_inc(next_active_frame,
11808c2ecf20Sopenharmony_ci						       interval);
11818c2ecf20Sopenharmony_ci
11828c2ecf20Sopenharmony_ciexit:
11838c2ecf20Sopenharmony_ci	qh->next_active_frame = next_active_frame;
11848c2ecf20Sopenharmony_ci	qh->start_active_frame = next_active_frame;
11858c2ecf20Sopenharmony_ci
11868c2ecf20Sopenharmony_ci	dwc2_sch_vdbg(hsotg, "QH=%p First fn=%04x nxt=%04x\n",
11878c2ecf20Sopenharmony_ci		      qh, frame_number, qh->next_active_frame);
11888c2ecf20Sopenharmony_ci}
11898c2ecf20Sopenharmony_ci
11908c2ecf20Sopenharmony_ci/**
11918c2ecf20Sopenharmony_ci * dwc2_do_reserve() - Make a periodic reservation
11928c2ecf20Sopenharmony_ci *
11938c2ecf20Sopenharmony_ci * Try to allocate space in the periodic schedule.  Depending on parameters
11948c2ecf20Sopenharmony_ci * this might use the microframe scheduler or the dumb scheduler.
11958c2ecf20Sopenharmony_ci *
11968c2ecf20Sopenharmony_ci * @hsotg: The HCD state structure for the DWC OTG controller
11978c2ecf20Sopenharmony_ci * @qh:    QH for the periodic transfer.
11988c2ecf20Sopenharmony_ci *
11998c2ecf20Sopenharmony_ci * Returns: 0 upon success; error upon failure.
12008c2ecf20Sopenharmony_ci */
12018c2ecf20Sopenharmony_cistatic int dwc2_do_reserve(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh)
12028c2ecf20Sopenharmony_ci{
12038c2ecf20Sopenharmony_ci	int status;
12048c2ecf20Sopenharmony_ci
12058c2ecf20Sopenharmony_ci	if (hsotg->params.uframe_sched) {
12068c2ecf20Sopenharmony_ci		status = dwc2_uframe_schedule(hsotg, qh);
12078c2ecf20Sopenharmony_ci	} else {
12088c2ecf20Sopenharmony_ci		status = dwc2_periodic_channel_available(hsotg);
12098c2ecf20Sopenharmony_ci		if (status) {
12108c2ecf20Sopenharmony_ci			dev_info(hsotg->dev,
12118c2ecf20Sopenharmony_ci				 "%s: No host channel available for periodic transfer\n",
12128c2ecf20Sopenharmony_ci				 __func__);
12138c2ecf20Sopenharmony_ci			return status;
12148c2ecf20Sopenharmony_ci		}
12158c2ecf20Sopenharmony_ci
12168c2ecf20Sopenharmony_ci		status = dwc2_check_periodic_bandwidth(hsotg, qh);
12178c2ecf20Sopenharmony_ci	}
12188c2ecf20Sopenharmony_ci
12198c2ecf20Sopenharmony_ci	if (status) {
12208c2ecf20Sopenharmony_ci		dev_dbg(hsotg->dev,
12218c2ecf20Sopenharmony_ci			"%s: Insufficient periodic bandwidth for periodic transfer\n",
12228c2ecf20Sopenharmony_ci			__func__);
12238c2ecf20Sopenharmony_ci		return status;
12248c2ecf20Sopenharmony_ci	}
12258c2ecf20Sopenharmony_ci
12268c2ecf20Sopenharmony_ci	if (!hsotg->params.uframe_sched)
12278c2ecf20Sopenharmony_ci		/* Reserve periodic channel */
12288c2ecf20Sopenharmony_ci		hsotg->periodic_channels++;
12298c2ecf20Sopenharmony_ci
12308c2ecf20Sopenharmony_ci	/* Update claimed usecs per (micro)frame */
12318c2ecf20Sopenharmony_ci	hsotg->periodic_usecs += qh->host_us;
12328c2ecf20Sopenharmony_ci
12338c2ecf20Sopenharmony_ci	dwc2_pick_first_frame(hsotg, qh);
12348c2ecf20Sopenharmony_ci
12358c2ecf20Sopenharmony_ci	return 0;
12368c2ecf20Sopenharmony_ci}
12378c2ecf20Sopenharmony_ci
12388c2ecf20Sopenharmony_ci/**
12398c2ecf20Sopenharmony_ci * dwc2_do_unreserve() - Actually release the periodic reservation
12408c2ecf20Sopenharmony_ci *
12418c2ecf20Sopenharmony_ci * This function actually releases the periodic bandwidth that was reserved
12428c2ecf20Sopenharmony_ci * by the given qh.
12438c2ecf20Sopenharmony_ci *
12448c2ecf20Sopenharmony_ci * @hsotg: The HCD state structure for the DWC OTG controller
12458c2ecf20Sopenharmony_ci * @qh:    QH for the periodic transfer.
12468c2ecf20Sopenharmony_ci */
12478c2ecf20Sopenharmony_cistatic void dwc2_do_unreserve(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh)
12488c2ecf20Sopenharmony_ci{
12498c2ecf20Sopenharmony_ci	assert_spin_locked(&hsotg->lock);
12508c2ecf20Sopenharmony_ci
12518c2ecf20Sopenharmony_ci	WARN_ON(!qh->unreserve_pending);
12528c2ecf20Sopenharmony_ci
12538c2ecf20Sopenharmony_ci	/* No more unreserve pending--we're doing it */
12548c2ecf20Sopenharmony_ci	qh->unreserve_pending = false;
12558c2ecf20Sopenharmony_ci
12568c2ecf20Sopenharmony_ci	if (WARN_ON(!list_empty(&qh->qh_list_entry)))
12578c2ecf20Sopenharmony_ci		list_del_init(&qh->qh_list_entry);
12588c2ecf20Sopenharmony_ci
12598c2ecf20Sopenharmony_ci	/* Update claimed usecs per (micro)frame */
12608c2ecf20Sopenharmony_ci	hsotg->periodic_usecs -= qh->host_us;
12618c2ecf20Sopenharmony_ci
12628c2ecf20Sopenharmony_ci	if (hsotg->params.uframe_sched) {
12638c2ecf20Sopenharmony_ci		dwc2_uframe_unschedule(hsotg, qh);
12648c2ecf20Sopenharmony_ci	} else {
12658c2ecf20Sopenharmony_ci		/* Release periodic channel reservation */
12668c2ecf20Sopenharmony_ci		hsotg->periodic_channels--;
12678c2ecf20Sopenharmony_ci	}
12688c2ecf20Sopenharmony_ci}
12698c2ecf20Sopenharmony_ci
12708c2ecf20Sopenharmony_ci/**
12718c2ecf20Sopenharmony_ci * dwc2_unreserve_timer_fn() - Timer function to release periodic reservation
12728c2ecf20Sopenharmony_ci *
12738c2ecf20Sopenharmony_ci * According to the kernel doc for usb_submit_urb() (specifically the part about
12748c2ecf20Sopenharmony_ci * "Reserved Bandwidth Transfers"), we need to keep a reservation active as
12758c2ecf20Sopenharmony_ci * long as a device driver keeps submitting.  Since we're using HCD_BH to give
12768c2ecf20Sopenharmony_ci * back the URB we need to give the driver a little bit of time before we
12778c2ecf20Sopenharmony_ci * release the reservation.  This worker is called after the appropriate
12788c2ecf20Sopenharmony_ci * delay.
12798c2ecf20Sopenharmony_ci *
12808c2ecf20Sopenharmony_ci * @t: Address to a qh unreserve_work.
12818c2ecf20Sopenharmony_ci */
12828c2ecf20Sopenharmony_cistatic void dwc2_unreserve_timer_fn(struct timer_list *t)
12838c2ecf20Sopenharmony_ci{
12848c2ecf20Sopenharmony_ci	struct dwc2_qh *qh = from_timer(qh, t, unreserve_timer);
12858c2ecf20Sopenharmony_ci	struct dwc2_hsotg *hsotg = qh->hsotg;
12868c2ecf20Sopenharmony_ci	unsigned long flags;
12878c2ecf20Sopenharmony_ci
12888c2ecf20Sopenharmony_ci	/*
12898c2ecf20Sopenharmony_ci	 * Wait for the lock, or for us to be scheduled again.  We
12908c2ecf20Sopenharmony_ci	 * could be scheduled again if:
12918c2ecf20Sopenharmony_ci	 * - We started executing but didn't get the lock yet.
12928c2ecf20Sopenharmony_ci	 * - A new reservation came in, but cancel didn't take effect
12938c2ecf20Sopenharmony_ci	 *   because we already started executing.
12948c2ecf20Sopenharmony_ci	 * - The timer has been kicked again.
12958c2ecf20Sopenharmony_ci	 * In that case cancel and wait for the next call.
12968c2ecf20Sopenharmony_ci	 */
12978c2ecf20Sopenharmony_ci	while (!spin_trylock_irqsave(&hsotg->lock, flags)) {
12988c2ecf20Sopenharmony_ci		if (timer_pending(&qh->unreserve_timer))
12998c2ecf20Sopenharmony_ci			return;
13008c2ecf20Sopenharmony_ci	}
13018c2ecf20Sopenharmony_ci
13028c2ecf20Sopenharmony_ci	/*
13038c2ecf20Sopenharmony_ci	 * Might be no more unreserve pending if:
13048c2ecf20Sopenharmony_ci	 * - We started executing but didn't get the lock yet.
13058c2ecf20Sopenharmony_ci	 * - A new reservation came in, but cancel didn't take effect
13068c2ecf20Sopenharmony_ci	 *   because we already started executing.
13078c2ecf20Sopenharmony_ci	 *
13088c2ecf20Sopenharmony_ci	 * We can't put this in the loop above because unreserve_pending needs
13098c2ecf20Sopenharmony_ci	 * to be accessed under lock, so we can only check it once we got the
13108c2ecf20Sopenharmony_ci	 * lock.
13118c2ecf20Sopenharmony_ci	 */
13128c2ecf20Sopenharmony_ci	if (qh->unreserve_pending)
13138c2ecf20Sopenharmony_ci		dwc2_do_unreserve(hsotg, qh);
13148c2ecf20Sopenharmony_ci
13158c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&hsotg->lock, flags);
13168c2ecf20Sopenharmony_ci}
13178c2ecf20Sopenharmony_ci
13188c2ecf20Sopenharmony_ci/**
13198c2ecf20Sopenharmony_ci * dwc2_check_max_xfer_size() - Checks that the max transfer size allowed in a
13208c2ecf20Sopenharmony_ci * host channel is large enough to handle the maximum data transfer in a single
13218c2ecf20Sopenharmony_ci * (micro)frame for a periodic transfer
13228c2ecf20Sopenharmony_ci *
13238c2ecf20Sopenharmony_ci * @hsotg: The HCD state structure for the DWC OTG controller
13248c2ecf20Sopenharmony_ci * @qh:    QH for a periodic endpoint
13258c2ecf20Sopenharmony_ci *
13268c2ecf20Sopenharmony_ci * Return: 0 if successful, negative error code otherwise
13278c2ecf20Sopenharmony_ci */
13288c2ecf20Sopenharmony_cistatic int dwc2_check_max_xfer_size(struct dwc2_hsotg *hsotg,
13298c2ecf20Sopenharmony_ci				    struct dwc2_qh *qh)
13308c2ecf20Sopenharmony_ci{
13318c2ecf20Sopenharmony_ci	u32 max_xfer_size;
13328c2ecf20Sopenharmony_ci	u32 max_channel_xfer_size;
13338c2ecf20Sopenharmony_ci	int status = 0;
13348c2ecf20Sopenharmony_ci
13358c2ecf20Sopenharmony_ci	max_xfer_size = qh->maxp * qh->maxp_mult;
13368c2ecf20Sopenharmony_ci	max_channel_xfer_size = hsotg->params.max_transfer_size;
13378c2ecf20Sopenharmony_ci
13388c2ecf20Sopenharmony_ci	if (max_xfer_size > max_channel_xfer_size) {
13398c2ecf20Sopenharmony_ci		dev_err(hsotg->dev,
13408c2ecf20Sopenharmony_ci			"%s: Periodic xfer length %d > max xfer length for channel %d\n",
13418c2ecf20Sopenharmony_ci			__func__, max_xfer_size, max_channel_xfer_size);
13428c2ecf20Sopenharmony_ci		status = -ENOSPC;
13438c2ecf20Sopenharmony_ci	}
13448c2ecf20Sopenharmony_ci
13458c2ecf20Sopenharmony_ci	return status;
13468c2ecf20Sopenharmony_ci}
13478c2ecf20Sopenharmony_ci
13488c2ecf20Sopenharmony_ci/**
13498c2ecf20Sopenharmony_ci * dwc2_schedule_periodic() - Schedules an interrupt or isochronous transfer in
13508c2ecf20Sopenharmony_ci * the periodic schedule
13518c2ecf20Sopenharmony_ci *
13528c2ecf20Sopenharmony_ci * @hsotg: The HCD state structure for the DWC OTG controller
13538c2ecf20Sopenharmony_ci * @qh:    QH for the periodic transfer. The QH should already contain the
13548c2ecf20Sopenharmony_ci *         scheduling information.
13558c2ecf20Sopenharmony_ci *
13568c2ecf20Sopenharmony_ci * Return: 0 if successful, negative error code otherwise
13578c2ecf20Sopenharmony_ci */
13588c2ecf20Sopenharmony_cistatic int dwc2_schedule_periodic(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh)
13598c2ecf20Sopenharmony_ci{
13608c2ecf20Sopenharmony_ci	int status;
13618c2ecf20Sopenharmony_ci
13628c2ecf20Sopenharmony_ci	status = dwc2_check_max_xfer_size(hsotg, qh);
13638c2ecf20Sopenharmony_ci	if (status) {
13648c2ecf20Sopenharmony_ci		dev_dbg(hsotg->dev,
13658c2ecf20Sopenharmony_ci			"%s: Channel max transfer size too small for periodic transfer\n",
13668c2ecf20Sopenharmony_ci			__func__);
13678c2ecf20Sopenharmony_ci		return status;
13688c2ecf20Sopenharmony_ci	}
13698c2ecf20Sopenharmony_ci
13708c2ecf20Sopenharmony_ci	/* Cancel pending unreserve; if canceled OK, unreserve was pending */
13718c2ecf20Sopenharmony_ci	if (del_timer(&qh->unreserve_timer))
13728c2ecf20Sopenharmony_ci		WARN_ON(!qh->unreserve_pending);
13738c2ecf20Sopenharmony_ci
13748c2ecf20Sopenharmony_ci	/*
13758c2ecf20Sopenharmony_ci	 * Only need to reserve if there's not an unreserve pending, since if an
13768c2ecf20Sopenharmony_ci	 * unreserve is pending then by definition our old reservation is still
13778c2ecf20Sopenharmony_ci	 * valid.  Unreserve might still be pending even if we didn't cancel if
13788c2ecf20Sopenharmony_ci	 * dwc2_unreserve_timer_fn() already started.  Code in the timer handles
13798c2ecf20Sopenharmony_ci	 * that case.
13808c2ecf20Sopenharmony_ci	 */
13818c2ecf20Sopenharmony_ci	if (!qh->unreserve_pending) {
13828c2ecf20Sopenharmony_ci		status = dwc2_do_reserve(hsotg, qh);
13838c2ecf20Sopenharmony_ci		if (status)
13848c2ecf20Sopenharmony_ci			return status;
13858c2ecf20Sopenharmony_ci	} else {
13868c2ecf20Sopenharmony_ci		/*
13878c2ecf20Sopenharmony_ci		 * It might have been a while, so make sure that frame_number
13888c2ecf20Sopenharmony_ci		 * is still good.  Note: we could also try to use the similar
13898c2ecf20Sopenharmony_ci		 * dwc2_next_periodic_start() but that schedules much more
13908c2ecf20Sopenharmony_ci		 * tightly and we might need to hurry and queue things up.
13918c2ecf20Sopenharmony_ci		 */
13928c2ecf20Sopenharmony_ci		if (dwc2_frame_num_le(qh->next_active_frame,
13938c2ecf20Sopenharmony_ci				      hsotg->frame_number))
13948c2ecf20Sopenharmony_ci			dwc2_pick_first_frame(hsotg, qh);
13958c2ecf20Sopenharmony_ci	}
13968c2ecf20Sopenharmony_ci
13978c2ecf20Sopenharmony_ci	qh->unreserve_pending = 0;
13988c2ecf20Sopenharmony_ci
13998c2ecf20Sopenharmony_ci	if (hsotg->params.dma_desc_enable)
14008c2ecf20Sopenharmony_ci		/* Don't rely on SOF and start in ready schedule */
14018c2ecf20Sopenharmony_ci		list_add_tail(&qh->qh_list_entry, &hsotg->periodic_sched_ready);
14028c2ecf20Sopenharmony_ci	else
14038c2ecf20Sopenharmony_ci		/* Always start in inactive schedule */
14048c2ecf20Sopenharmony_ci		list_add_tail(&qh->qh_list_entry,
14058c2ecf20Sopenharmony_ci			      &hsotg->periodic_sched_inactive);
14068c2ecf20Sopenharmony_ci
14078c2ecf20Sopenharmony_ci	return 0;
14088c2ecf20Sopenharmony_ci}
14098c2ecf20Sopenharmony_ci
14108c2ecf20Sopenharmony_ci/**
14118c2ecf20Sopenharmony_ci * dwc2_deschedule_periodic() - Removes an interrupt or isochronous transfer
14128c2ecf20Sopenharmony_ci * from the periodic schedule
14138c2ecf20Sopenharmony_ci *
14148c2ecf20Sopenharmony_ci * @hsotg: The HCD state structure for the DWC OTG controller
14158c2ecf20Sopenharmony_ci * @qh:	   QH for the periodic transfer
14168c2ecf20Sopenharmony_ci */
14178c2ecf20Sopenharmony_cistatic void dwc2_deschedule_periodic(struct dwc2_hsotg *hsotg,
14188c2ecf20Sopenharmony_ci				     struct dwc2_qh *qh)
14198c2ecf20Sopenharmony_ci{
14208c2ecf20Sopenharmony_ci	bool did_modify;
14218c2ecf20Sopenharmony_ci
14228c2ecf20Sopenharmony_ci	assert_spin_locked(&hsotg->lock);
14238c2ecf20Sopenharmony_ci
14248c2ecf20Sopenharmony_ci	/*
14258c2ecf20Sopenharmony_ci	 * Schedule the unreserve to happen in a little bit.  Cases here:
14268c2ecf20Sopenharmony_ci	 * - Unreserve worker might be sitting there waiting to grab the lock.
14278c2ecf20Sopenharmony_ci	 *   In this case it will notice it's been schedule again and will
14288c2ecf20Sopenharmony_ci	 *   quit.
14298c2ecf20Sopenharmony_ci	 * - Unreserve worker might not be scheduled.
14308c2ecf20Sopenharmony_ci	 *
14318c2ecf20Sopenharmony_ci	 * We should never already be scheduled since dwc2_schedule_periodic()
14328c2ecf20Sopenharmony_ci	 * should have canceled the scheduled unreserve timer (hence the
14338c2ecf20Sopenharmony_ci	 * warning on did_modify).
14348c2ecf20Sopenharmony_ci	 *
14358c2ecf20Sopenharmony_ci	 * We add + 1 to the timer to guarantee that at least 1 jiffy has
14368c2ecf20Sopenharmony_ci	 * passed (otherwise if the jiffy counter might tick right after we
14378c2ecf20Sopenharmony_ci	 * read it and we'll get no delay).
14388c2ecf20Sopenharmony_ci	 */
14398c2ecf20Sopenharmony_ci	did_modify = mod_timer(&qh->unreserve_timer,
14408c2ecf20Sopenharmony_ci			       jiffies + DWC2_UNRESERVE_DELAY + 1);
14418c2ecf20Sopenharmony_ci	WARN_ON(did_modify);
14428c2ecf20Sopenharmony_ci	qh->unreserve_pending = 1;
14438c2ecf20Sopenharmony_ci
14448c2ecf20Sopenharmony_ci	list_del_init(&qh->qh_list_entry);
14458c2ecf20Sopenharmony_ci}
14468c2ecf20Sopenharmony_ci
14478c2ecf20Sopenharmony_ci/**
14488c2ecf20Sopenharmony_ci * dwc2_wait_timer_fn() - Timer function to re-queue after waiting
14498c2ecf20Sopenharmony_ci *
14508c2ecf20Sopenharmony_ci * As per the spec, a NAK indicates that "a function is temporarily unable to
14518c2ecf20Sopenharmony_ci * transmit or receive data, but will eventually be able to do so without need
14528c2ecf20Sopenharmony_ci * of host intervention".
14538c2ecf20Sopenharmony_ci *
14548c2ecf20Sopenharmony_ci * That means that when we encounter a NAK we're supposed to retry.
14558c2ecf20Sopenharmony_ci *
14568c2ecf20Sopenharmony_ci * ...but if we retry right away (from the interrupt handler that saw the NAK)
14578c2ecf20Sopenharmony_ci * then we can end up with an interrupt storm (if the other side keeps NAKing
14588c2ecf20Sopenharmony_ci * us) because on slow enough CPUs it could take us longer to get out of the
14598c2ecf20Sopenharmony_ci * interrupt routine than it takes for the device to send another NAK.  That
14608c2ecf20Sopenharmony_ci * leads to a constant stream of NAK interrupts and the CPU locks.
14618c2ecf20Sopenharmony_ci *
14628c2ecf20Sopenharmony_ci * ...so instead of retrying right away in the case of a NAK we'll set a timer
14638c2ecf20Sopenharmony_ci * to retry some time later.  This function handles that timer and moves the
14648c2ecf20Sopenharmony_ci * qh back to the "inactive" list, then queues transactions.
14658c2ecf20Sopenharmony_ci *
14668c2ecf20Sopenharmony_ci * @t: Pointer to wait_timer in a qh.
14678c2ecf20Sopenharmony_ci *
14688c2ecf20Sopenharmony_ci * Return: HRTIMER_NORESTART to not automatically restart this timer.
14698c2ecf20Sopenharmony_ci */
14708c2ecf20Sopenharmony_cistatic enum hrtimer_restart dwc2_wait_timer_fn(struct hrtimer *t)
14718c2ecf20Sopenharmony_ci{
14728c2ecf20Sopenharmony_ci	struct dwc2_qh *qh = container_of(t, struct dwc2_qh, wait_timer);
14738c2ecf20Sopenharmony_ci	struct dwc2_hsotg *hsotg = qh->hsotg;
14748c2ecf20Sopenharmony_ci	unsigned long flags;
14758c2ecf20Sopenharmony_ci
14768c2ecf20Sopenharmony_ci	spin_lock_irqsave(&hsotg->lock, flags);
14778c2ecf20Sopenharmony_ci
14788c2ecf20Sopenharmony_ci	/*
14798c2ecf20Sopenharmony_ci	 * We'll set wait_timer_cancel to true if we want to cancel this
14808c2ecf20Sopenharmony_ci	 * operation in dwc2_hcd_qh_unlink().
14818c2ecf20Sopenharmony_ci	 */
14828c2ecf20Sopenharmony_ci	if (!qh->wait_timer_cancel) {
14838c2ecf20Sopenharmony_ci		enum dwc2_transaction_type tr_type;
14848c2ecf20Sopenharmony_ci
14858c2ecf20Sopenharmony_ci		qh->want_wait = false;
14868c2ecf20Sopenharmony_ci
14878c2ecf20Sopenharmony_ci		list_move(&qh->qh_list_entry,
14888c2ecf20Sopenharmony_ci			  &hsotg->non_periodic_sched_inactive);
14898c2ecf20Sopenharmony_ci
14908c2ecf20Sopenharmony_ci		tr_type = dwc2_hcd_select_transactions(hsotg);
14918c2ecf20Sopenharmony_ci		if (tr_type != DWC2_TRANSACTION_NONE)
14928c2ecf20Sopenharmony_ci			dwc2_hcd_queue_transactions(hsotg, tr_type);
14938c2ecf20Sopenharmony_ci	}
14948c2ecf20Sopenharmony_ci
14958c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&hsotg->lock, flags);
14968c2ecf20Sopenharmony_ci	return HRTIMER_NORESTART;
14978c2ecf20Sopenharmony_ci}
14988c2ecf20Sopenharmony_ci
14998c2ecf20Sopenharmony_ci/**
15008c2ecf20Sopenharmony_ci * dwc2_qh_init() - Initializes a QH structure
15018c2ecf20Sopenharmony_ci *
15028c2ecf20Sopenharmony_ci * @hsotg: The HCD state structure for the DWC OTG controller
15038c2ecf20Sopenharmony_ci * @qh:    The QH to init
15048c2ecf20Sopenharmony_ci * @urb:   Holds the information about the device/endpoint needed to initialize
15058c2ecf20Sopenharmony_ci *         the QH
15068c2ecf20Sopenharmony_ci * @mem_flags: Flags for allocating memory.
15078c2ecf20Sopenharmony_ci */
15088c2ecf20Sopenharmony_cistatic void dwc2_qh_init(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh,
15098c2ecf20Sopenharmony_ci			 struct dwc2_hcd_urb *urb, gfp_t mem_flags)
15108c2ecf20Sopenharmony_ci{
15118c2ecf20Sopenharmony_ci	int dev_speed = dwc2_host_get_speed(hsotg, urb->priv);
15128c2ecf20Sopenharmony_ci	u8 ep_type = dwc2_hcd_get_pipe_type(&urb->pipe_info);
15138c2ecf20Sopenharmony_ci	bool ep_is_in = !!dwc2_hcd_is_pipe_in(&urb->pipe_info);
15148c2ecf20Sopenharmony_ci	bool ep_is_isoc = (ep_type == USB_ENDPOINT_XFER_ISOC);
15158c2ecf20Sopenharmony_ci	bool ep_is_int = (ep_type == USB_ENDPOINT_XFER_INT);
15168c2ecf20Sopenharmony_ci	u32 hprt = dwc2_readl(hsotg, HPRT0);
15178c2ecf20Sopenharmony_ci	u32 prtspd = (hprt & HPRT0_SPD_MASK) >> HPRT0_SPD_SHIFT;
15188c2ecf20Sopenharmony_ci	bool do_split = (prtspd == HPRT0_SPD_HIGH_SPEED &&
15198c2ecf20Sopenharmony_ci			 dev_speed != USB_SPEED_HIGH);
15208c2ecf20Sopenharmony_ci	int maxp = dwc2_hcd_get_maxp(&urb->pipe_info);
15218c2ecf20Sopenharmony_ci	int maxp_mult = dwc2_hcd_get_maxp_mult(&urb->pipe_info);
15228c2ecf20Sopenharmony_ci	int bytecount = maxp_mult * maxp;
15238c2ecf20Sopenharmony_ci	char *speed, *type;
15248c2ecf20Sopenharmony_ci
15258c2ecf20Sopenharmony_ci	/* Initialize QH */
15268c2ecf20Sopenharmony_ci	qh->hsotg = hsotg;
15278c2ecf20Sopenharmony_ci	timer_setup(&qh->unreserve_timer, dwc2_unreserve_timer_fn, 0);
15288c2ecf20Sopenharmony_ci	hrtimer_init(&qh->wait_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
15298c2ecf20Sopenharmony_ci	qh->wait_timer.function = &dwc2_wait_timer_fn;
15308c2ecf20Sopenharmony_ci	qh->ep_type = ep_type;
15318c2ecf20Sopenharmony_ci	qh->ep_is_in = ep_is_in;
15328c2ecf20Sopenharmony_ci
15338c2ecf20Sopenharmony_ci	qh->data_toggle = DWC2_HC_PID_DATA0;
15348c2ecf20Sopenharmony_ci	qh->maxp = maxp;
15358c2ecf20Sopenharmony_ci	qh->maxp_mult = maxp_mult;
15368c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&qh->qtd_list);
15378c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&qh->qh_list_entry);
15388c2ecf20Sopenharmony_ci
15398c2ecf20Sopenharmony_ci	qh->do_split = do_split;
15408c2ecf20Sopenharmony_ci	qh->dev_speed = dev_speed;
15418c2ecf20Sopenharmony_ci
15428c2ecf20Sopenharmony_ci	if (ep_is_int || ep_is_isoc) {
15438c2ecf20Sopenharmony_ci		/* Compute scheduling parameters once and save them */
15448c2ecf20Sopenharmony_ci		int host_speed = do_split ? USB_SPEED_HIGH : dev_speed;
15458c2ecf20Sopenharmony_ci		struct dwc2_tt *dwc_tt = dwc2_host_get_tt_info(hsotg, urb->priv,
15468c2ecf20Sopenharmony_ci							       mem_flags,
15478c2ecf20Sopenharmony_ci							       &qh->ttport);
15488c2ecf20Sopenharmony_ci		int device_ns;
15498c2ecf20Sopenharmony_ci
15508c2ecf20Sopenharmony_ci		qh->dwc_tt = dwc_tt;
15518c2ecf20Sopenharmony_ci
15528c2ecf20Sopenharmony_ci		qh->host_us = NS_TO_US(usb_calc_bus_time(host_speed, ep_is_in,
15538c2ecf20Sopenharmony_ci				       ep_is_isoc, bytecount));
15548c2ecf20Sopenharmony_ci		device_ns = usb_calc_bus_time(dev_speed, ep_is_in,
15558c2ecf20Sopenharmony_ci					      ep_is_isoc, bytecount);
15568c2ecf20Sopenharmony_ci
15578c2ecf20Sopenharmony_ci		if (do_split && dwc_tt)
15588c2ecf20Sopenharmony_ci			device_ns += dwc_tt->usb_tt->think_time;
15598c2ecf20Sopenharmony_ci		qh->device_us = NS_TO_US(device_ns);
15608c2ecf20Sopenharmony_ci
15618c2ecf20Sopenharmony_ci		qh->device_interval = urb->interval;
15628c2ecf20Sopenharmony_ci		qh->host_interval = urb->interval * (do_split ? 8 : 1);
15638c2ecf20Sopenharmony_ci
15648c2ecf20Sopenharmony_ci		/*
15658c2ecf20Sopenharmony_ci		 * Schedule low speed if we're running the host in low or
15668c2ecf20Sopenharmony_ci		 * full speed OR if we've got a "TT" to deal with to access this
15678c2ecf20Sopenharmony_ci		 * device.
15688c2ecf20Sopenharmony_ci		 */
15698c2ecf20Sopenharmony_ci		qh->schedule_low_speed = prtspd != HPRT0_SPD_HIGH_SPEED ||
15708c2ecf20Sopenharmony_ci					 dwc_tt;
15718c2ecf20Sopenharmony_ci
15728c2ecf20Sopenharmony_ci		if (do_split) {
15738c2ecf20Sopenharmony_ci			/* We won't know num transfers until we schedule */
15748c2ecf20Sopenharmony_ci			qh->num_hs_transfers = -1;
15758c2ecf20Sopenharmony_ci		} else if (dev_speed == USB_SPEED_HIGH) {
15768c2ecf20Sopenharmony_ci			qh->num_hs_transfers = 1;
15778c2ecf20Sopenharmony_ci		} else {
15788c2ecf20Sopenharmony_ci			qh->num_hs_transfers = 0;
15798c2ecf20Sopenharmony_ci		}
15808c2ecf20Sopenharmony_ci
15818c2ecf20Sopenharmony_ci		/* We'll schedule later when we have something to do */
15828c2ecf20Sopenharmony_ci	}
15838c2ecf20Sopenharmony_ci
15848c2ecf20Sopenharmony_ci	switch (dev_speed) {
15858c2ecf20Sopenharmony_ci	case USB_SPEED_LOW:
15868c2ecf20Sopenharmony_ci		speed = "low";
15878c2ecf20Sopenharmony_ci		break;
15888c2ecf20Sopenharmony_ci	case USB_SPEED_FULL:
15898c2ecf20Sopenharmony_ci		speed = "full";
15908c2ecf20Sopenharmony_ci		break;
15918c2ecf20Sopenharmony_ci	case USB_SPEED_HIGH:
15928c2ecf20Sopenharmony_ci		speed = "high";
15938c2ecf20Sopenharmony_ci		break;
15948c2ecf20Sopenharmony_ci	default:
15958c2ecf20Sopenharmony_ci		speed = "?";
15968c2ecf20Sopenharmony_ci		break;
15978c2ecf20Sopenharmony_ci	}
15988c2ecf20Sopenharmony_ci
15998c2ecf20Sopenharmony_ci	switch (qh->ep_type) {
16008c2ecf20Sopenharmony_ci	case USB_ENDPOINT_XFER_ISOC:
16018c2ecf20Sopenharmony_ci		type = "isochronous";
16028c2ecf20Sopenharmony_ci		break;
16038c2ecf20Sopenharmony_ci	case USB_ENDPOINT_XFER_INT:
16048c2ecf20Sopenharmony_ci		type = "interrupt";
16058c2ecf20Sopenharmony_ci		break;
16068c2ecf20Sopenharmony_ci	case USB_ENDPOINT_XFER_CONTROL:
16078c2ecf20Sopenharmony_ci		type = "control";
16088c2ecf20Sopenharmony_ci		break;
16098c2ecf20Sopenharmony_ci	case USB_ENDPOINT_XFER_BULK:
16108c2ecf20Sopenharmony_ci		type = "bulk";
16118c2ecf20Sopenharmony_ci		break;
16128c2ecf20Sopenharmony_ci	default:
16138c2ecf20Sopenharmony_ci		type = "?";
16148c2ecf20Sopenharmony_ci		break;
16158c2ecf20Sopenharmony_ci	}
16168c2ecf20Sopenharmony_ci
16178c2ecf20Sopenharmony_ci	dwc2_sch_dbg(hsotg, "QH=%p Init %s, %s speed, %d bytes:\n", qh, type,
16188c2ecf20Sopenharmony_ci		     speed, bytecount);
16198c2ecf20Sopenharmony_ci	dwc2_sch_dbg(hsotg, "QH=%p ...addr=%d, ep=%d, %s\n", qh,
16208c2ecf20Sopenharmony_ci		     dwc2_hcd_get_dev_addr(&urb->pipe_info),
16218c2ecf20Sopenharmony_ci		     dwc2_hcd_get_ep_num(&urb->pipe_info),
16228c2ecf20Sopenharmony_ci		     ep_is_in ? "IN" : "OUT");
16238c2ecf20Sopenharmony_ci	if (ep_is_int || ep_is_isoc) {
16248c2ecf20Sopenharmony_ci		dwc2_sch_dbg(hsotg,
16258c2ecf20Sopenharmony_ci			     "QH=%p ...duration: host=%d us, device=%d us\n",
16268c2ecf20Sopenharmony_ci			     qh, qh->host_us, qh->device_us);
16278c2ecf20Sopenharmony_ci		dwc2_sch_dbg(hsotg, "QH=%p ...interval: host=%d, device=%d\n",
16288c2ecf20Sopenharmony_ci			     qh, qh->host_interval, qh->device_interval);
16298c2ecf20Sopenharmony_ci		if (qh->schedule_low_speed)
16308c2ecf20Sopenharmony_ci			dwc2_sch_dbg(hsotg, "QH=%p ...low speed schedule=%p\n",
16318c2ecf20Sopenharmony_ci				     qh, dwc2_get_ls_map(hsotg, qh));
16328c2ecf20Sopenharmony_ci	}
16338c2ecf20Sopenharmony_ci}
16348c2ecf20Sopenharmony_ci
16358c2ecf20Sopenharmony_ci/**
16368c2ecf20Sopenharmony_ci * dwc2_hcd_qh_create() - Allocates and initializes a QH
16378c2ecf20Sopenharmony_ci *
16388c2ecf20Sopenharmony_ci * @hsotg:        The HCD state structure for the DWC OTG controller
16398c2ecf20Sopenharmony_ci * @urb:          Holds the information about the device/endpoint needed
16408c2ecf20Sopenharmony_ci *                to initialize the QH
16418c2ecf20Sopenharmony_ci * @mem_flags:   Flags for allocating memory.
16428c2ecf20Sopenharmony_ci *
16438c2ecf20Sopenharmony_ci * Return: Pointer to the newly allocated QH, or NULL on error
16448c2ecf20Sopenharmony_ci */
16458c2ecf20Sopenharmony_cistruct dwc2_qh *dwc2_hcd_qh_create(struct dwc2_hsotg *hsotg,
16468c2ecf20Sopenharmony_ci				   struct dwc2_hcd_urb *urb,
16478c2ecf20Sopenharmony_ci					  gfp_t mem_flags)
16488c2ecf20Sopenharmony_ci{
16498c2ecf20Sopenharmony_ci	struct dwc2_qh *qh;
16508c2ecf20Sopenharmony_ci
16518c2ecf20Sopenharmony_ci	if (!urb->priv)
16528c2ecf20Sopenharmony_ci		return NULL;
16538c2ecf20Sopenharmony_ci
16548c2ecf20Sopenharmony_ci	/* Allocate memory */
16558c2ecf20Sopenharmony_ci	qh = kzalloc(sizeof(*qh), mem_flags);
16568c2ecf20Sopenharmony_ci	if (!qh)
16578c2ecf20Sopenharmony_ci		return NULL;
16588c2ecf20Sopenharmony_ci
16598c2ecf20Sopenharmony_ci	dwc2_qh_init(hsotg, qh, urb, mem_flags);
16608c2ecf20Sopenharmony_ci
16618c2ecf20Sopenharmony_ci	if (hsotg->params.dma_desc_enable &&
16628c2ecf20Sopenharmony_ci	    dwc2_hcd_qh_init_ddma(hsotg, qh, mem_flags) < 0) {
16638c2ecf20Sopenharmony_ci		dwc2_hcd_qh_free(hsotg, qh);
16648c2ecf20Sopenharmony_ci		return NULL;
16658c2ecf20Sopenharmony_ci	}
16668c2ecf20Sopenharmony_ci
16678c2ecf20Sopenharmony_ci	return qh;
16688c2ecf20Sopenharmony_ci}
16698c2ecf20Sopenharmony_ci
16708c2ecf20Sopenharmony_ci/**
16718c2ecf20Sopenharmony_ci * dwc2_hcd_qh_free() - Frees the QH
16728c2ecf20Sopenharmony_ci *
16738c2ecf20Sopenharmony_ci * @hsotg: HCD instance
16748c2ecf20Sopenharmony_ci * @qh:    The QH to free
16758c2ecf20Sopenharmony_ci *
16768c2ecf20Sopenharmony_ci * QH should already be removed from the list. QTD list should already be empty
16778c2ecf20Sopenharmony_ci * if called from URB Dequeue.
16788c2ecf20Sopenharmony_ci *
16798c2ecf20Sopenharmony_ci * Must NOT be called with interrupt disabled or spinlock held
16808c2ecf20Sopenharmony_ci */
16818c2ecf20Sopenharmony_civoid dwc2_hcd_qh_free(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh)
16828c2ecf20Sopenharmony_ci{
16838c2ecf20Sopenharmony_ci	/* Make sure any unreserve work is finished. */
16848c2ecf20Sopenharmony_ci	if (del_timer_sync(&qh->unreserve_timer)) {
16858c2ecf20Sopenharmony_ci		unsigned long flags;
16868c2ecf20Sopenharmony_ci
16878c2ecf20Sopenharmony_ci		spin_lock_irqsave(&hsotg->lock, flags);
16888c2ecf20Sopenharmony_ci		dwc2_do_unreserve(hsotg, qh);
16898c2ecf20Sopenharmony_ci		spin_unlock_irqrestore(&hsotg->lock, flags);
16908c2ecf20Sopenharmony_ci	}
16918c2ecf20Sopenharmony_ci
16928c2ecf20Sopenharmony_ci	/*
16938c2ecf20Sopenharmony_ci	 * We don't have the lock so we can safely wait until the wait timer
16948c2ecf20Sopenharmony_ci	 * finishes.  Of course, at this point in time we'd better have set
16958c2ecf20Sopenharmony_ci	 * wait_timer_active to false so if this timer was still pending it
16968c2ecf20Sopenharmony_ci	 * won't do anything anyway, but we want it to finish before we free
16978c2ecf20Sopenharmony_ci	 * memory.
16988c2ecf20Sopenharmony_ci	 */
16998c2ecf20Sopenharmony_ci	hrtimer_cancel(&qh->wait_timer);
17008c2ecf20Sopenharmony_ci
17018c2ecf20Sopenharmony_ci	dwc2_host_put_tt_info(hsotg, qh->dwc_tt);
17028c2ecf20Sopenharmony_ci
17038c2ecf20Sopenharmony_ci	if (qh->desc_list)
17048c2ecf20Sopenharmony_ci		dwc2_hcd_qh_free_ddma(hsotg, qh);
17058c2ecf20Sopenharmony_ci	else if (hsotg->unaligned_cache && qh->dw_align_buf)
17068c2ecf20Sopenharmony_ci		kmem_cache_free(hsotg->unaligned_cache, qh->dw_align_buf);
17078c2ecf20Sopenharmony_ci
17088c2ecf20Sopenharmony_ci	kfree(qh);
17098c2ecf20Sopenharmony_ci}
17108c2ecf20Sopenharmony_ci
17118c2ecf20Sopenharmony_ci/**
17128c2ecf20Sopenharmony_ci * dwc2_hcd_qh_add() - Adds a QH to either the non periodic or periodic
17138c2ecf20Sopenharmony_ci * schedule if it is not already in the schedule. If the QH is already in
17148c2ecf20Sopenharmony_ci * the schedule, no action is taken.
17158c2ecf20Sopenharmony_ci *
17168c2ecf20Sopenharmony_ci * @hsotg: The HCD state structure for the DWC OTG controller
17178c2ecf20Sopenharmony_ci * @qh:    The QH to add
17188c2ecf20Sopenharmony_ci *
17198c2ecf20Sopenharmony_ci * Return: 0 if successful, negative error code otherwise
17208c2ecf20Sopenharmony_ci */
17218c2ecf20Sopenharmony_ciint dwc2_hcd_qh_add(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh)
17228c2ecf20Sopenharmony_ci{
17238c2ecf20Sopenharmony_ci	int status;
17248c2ecf20Sopenharmony_ci	u32 intr_mask;
17258c2ecf20Sopenharmony_ci	ktime_t delay;
17268c2ecf20Sopenharmony_ci
17278c2ecf20Sopenharmony_ci	if (dbg_qh(qh))
17288c2ecf20Sopenharmony_ci		dev_vdbg(hsotg->dev, "%s()\n", __func__);
17298c2ecf20Sopenharmony_ci
17308c2ecf20Sopenharmony_ci	if (!list_empty(&qh->qh_list_entry))
17318c2ecf20Sopenharmony_ci		/* QH already in a schedule */
17328c2ecf20Sopenharmony_ci		return 0;
17338c2ecf20Sopenharmony_ci
17348c2ecf20Sopenharmony_ci	/* Add the new QH to the appropriate schedule */
17358c2ecf20Sopenharmony_ci	if (dwc2_qh_is_non_per(qh)) {
17368c2ecf20Sopenharmony_ci		/* Schedule right away */
17378c2ecf20Sopenharmony_ci		qh->start_active_frame = hsotg->frame_number;
17388c2ecf20Sopenharmony_ci		qh->next_active_frame = qh->start_active_frame;
17398c2ecf20Sopenharmony_ci
17408c2ecf20Sopenharmony_ci		if (qh->want_wait) {
17418c2ecf20Sopenharmony_ci			list_add_tail(&qh->qh_list_entry,
17428c2ecf20Sopenharmony_ci				      &hsotg->non_periodic_sched_waiting);
17438c2ecf20Sopenharmony_ci			qh->wait_timer_cancel = false;
17448c2ecf20Sopenharmony_ci			delay = ktime_set(0, DWC2_RETRY_WAIT_DELAY);
17458c2ecf20Sopenharmony_ci			hrtimer_start(&qh->wait_timer, delay, HRTIMER_MODE_REL);
17468c2ecf20Sopenharmony_ci		} else {
17478c2ecf20Sopenharmony_ci			list_add_tail(&qh->qh_list_entry,
17488c2ecf20Sopenharmony_ci				      &hsotg->non_periodic_sched_inactive);
17498c2ecf20Sopenharmony_ci		}
17508c2ecf20Sopenharmony_ci		return 0;
17518c2ecf20Sopenharmony_ci	}
17528c2ecf20Sopenharmony_ci
17538c2ecf20Sopenharmony_ci	status = dwc2_schedule_periodic(hsotg, qh);
17548c2ecf20Sopenharmony_ci	if (status)
17558c2ecf20Sopenharmony_ci		return status;
17568c2ecf20Sopenharmony_ci	if (!hsotg->periodic_qh_count) {
17578c2ecf20Sopenharmony_ci		intr_mask = dwc2_readl(hsotg, GINTMSK);
17588c2ecf20Sopenharmony_ci		intr_mask |= GINTSTS_SOF;
17598c2ecf20Sopenharmony_ci		dwc2_writel(hsotg, intr_mask, GINTMSK);
17608c2ecf20Sopenharmony_ci	}
17618c2ecf20Sopenharmony_ci	hsotg->periodic_qh_count++;
17628c2ecf20Sopenharmony_ci
17638c2ecf20Sopenharmony_ci	return 0;
17648c2ecf20Sopenharmony_ci}
17658c2ecf20Sopenharmony_ci
17668c2ecf20Sopenharmony_ci/**
17678c2ecf20Sopenharmony_ci * dwc2_hcd_qh_unlink() - Removes a QH from either the non-periodic or periodic
17688c2ecf20Sopenharmony_ci * schedule. Memory is not freed.
17698c2ecf20Sopenharmony_ci *
17708c2ecf20Sopenharmony_ci * @hsotg: The HCD state structure
17718c2ecf20Sopenharmony_ci * @qh:    QH to remove from schedule
17728c2ecf20Sopenharmony_ci */
17738c2ecf20Sopenharmony_civoid dwc2_hcd_qh_unlink(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh)
17748c2ecf20Sopenharmony_ci{
17758c2ecf20Sopenharmony_ci	u32 intr_mask;
17768c2ecf20Sopenharmony_ci
17778c2ecf20Sopenharmony_ci	dev_vdbg(hsotg->dev, "%s()\n", __func__);
17788c2ecf20Sopenharmony_ci
17798c2ecf20Sopenharmony_ci	/* If the wait_timer is pending, this will stop it from acting */
17808c2ecf20Sopenharmony_ci	qh->wait_timer_cancel = true;
17818c2ecf20Sopenharmony_ci
17828c2ecf20Sopenharmony_ci	if (list_empty(&qh->qh_list_entry))
17838c2ecf20Sopenharmony_ci		/* QH is not in a schedule */
17848c2ecf20Sopenharmony_ci		return;
17858c2ecf20Sopenharmony_ci
17868c2ecf20Sopenharmony_ci	if (dwc2_qh_is_non_per(qh)) {
17878c2ecf20Sopenharmony_ci		if (hsotg->non_periodic_qh_ptr == &qh->qh_list_entry)
17888c2ecf20Sopenharmony_ci			hsotg->non_periodic_qh_ptr =
17898c2ecf20Sopenharmony_ci					hsotg->non_periodic_qh_ptr->next;
17908c2ecf20Sopenharmony_ci		list_del_init(&qh->qh_list_entry);
17918c2ecf20Sopenharmony_ci		return;
17928c2ecf20Sopenharmony_ci	}
17938c2ecf20Sopenharmony_ci
17948c2ecf20Sopenharmony_ci	dwc2_deschedule_periodic(hsotg, qh);
17958c2ecf20Sopenharmony_ci	hsotg->periodic_qh_count--;
17968c2ecf20Sopenharmony_ci	if (!hsotg->periodic_qh_count &&
17978c2ecf20Sopenharmony_ci	    !hsotg->params.dma_desc_enable) {
17988c2ecf20Sopenharmony_ci		intr_mask = dwc2_readl(hsotg, GINTMSK);
17998c2ecf20Sopenharmony_ci		intr_mask &= ~GINTSTS_SOF;
18008c2ecf20Sopenharmony_ci		dwc2_writel(hsotg, intr_mask, GINTMSK);
18018c2ecf20Sopenharmony_ci	}
18028c2ecf20Sopenharmony_ci}
18038c2ecf20Sopenharmony_ci
18048c2ecf20Sopenharmony_ci/**
18058c2ecf20Sopenharmony_ci * dwc2_next_for_periodic_split() - Set next_active_frame midway thru a split.
18068c2ecf20Sopenharmony_ci *
18078c2ecf20Sopenharmony_ci * This is called for setting next_active_frame for periodic splits for all but
18088c2ecf20Sopenharmony_ci * the first packet of the split.  Confusing?  I thought so...
18098c2ecf20Sopenharmony_ci *
18108c2ecf20Sopenharmony_ci * Periodic splits are single low/full speed transfers that we end up splitting
18118c2ecf20Sopenharmony_ci * up into several high speed transfers.  They always fit into one full (1 ms)
18128c2ecf20Sopenharmony_ci * frame but might be split over several microframes (125 us each).  We to put
18138c2ecf20Sopenharmony_ci * each of the parts on a very specific high speed frame.
18148c2ecf20Sopenharmony_ci *
18158c2ecf20Sopenharmony_ci * This function figures out where the next active uFrame needs to be.
18168c2ecf20Sopenharmony_ci *
18178c2ecf20Sopenharmony_ci * @hsotg:        The HCD state structure
18188c2ecf20Sopenharmony_ci * @qh:           QH for the periodic transfer.
18198c2ecf20Sopenharmony_ci * @frame_number: The current frame number.
18208c2ecf20Sopenharmony_ci *
18218c2ecf20Sopenharmony_ci * Return: number missed by (or 0 if we didn't miss).
18228c2ecf20Sopenharmony_ci */
18238c2ecf20Sopenharmony_cistatic int dwc2_next_for_periodic_split(struct dwc2_hsotg *hsotg,
18248c2ecf20Sopenharmony_ci					struct dwc2_qh *qh, u16 frame_number)
18258c2ecf20Sopenharmony_ci{
18268c2ecf20Sopenharmony_ci	u16 old_frame = qh->next_active_frame;
18278c2ecf20Sopenharmony_ci	u16 prev_frame_number = dwc2_frame_num_dec(frame_number, 1);
18288c2ecf20Sopenharmony_ci	int missed = 0;
18298c2ecf20Sopenharmony_ci	u16 incr;
18308c2ecf20Sopenharmony_ci
18318c2ecf20Sopenharmony_ci	/*
18328c2ecf20Sopenharmony_ci	 * See dwc2_uframe_schedule_split() for split scheduling.
18338c2ecf20Sopenharmony_ci	 *
18348c2ecf20Sopenharmony_ci	 * Basically: increment 1 normally, but 2 right after the start split
18358c2ecf20Sopenharmony_ci	 * (except for ISOC out).
18368c2ecf20Sopenharmony_ci	 */
18378c2ecf20Sopenharmony_ci	if (old_frame == qh->start_active_frame &&
18388c2ecf20Sopenharmony_ci	    !(qh->ep_type == USB_ENDPOINT_XFER_ISOC && !qh->ep_is_in))
18398c2ecf20Sopenharmony_ci		incr = 2;
18408c2ecf20Sopenharmony_ci	else
18418c2ecf20Sopenharmony_ci		incr = 1;
18428c2ecf20Sopenharmony_ci
18438c2ecf20Sopenharmony_ci	qh->next_active_frame = dwc2_frame_num_inc(old_frame, incr);
18448c2ecf20Sopenharmony_ci
18458c2ecf20Sopenharmony_ci	/*
18468c2ecf20Sopenharmony_ci	 * Note that it's OK for frame_number to be 1 frame past
18478c2ecf20Sopenharmony_ci	 * next_active_frame.  Remember that next_active_frame is supposed to
18488c2ecf20Sopenharmony_ci	 * be 1 frame _before_ when we want to be scheduled.  If we're 1 frame
18498c2ecf20Sopenharmony_ci	 * past it just means schedule ASAP.
18508c2ecf20Sopenharmony_ci	 *
18518c2ecf20Sopenharmony_ci	 * It's _not_ OK, however, if we're more than one frame past.
18528c2ecf20Sopenharmony_ci	 */
18538c2ecf20Sopenharmony_ci	if (dwc2_frame_num_gt(prev_frame_number, qh->next_active_frame)) {
18548c2ecf20Sopenharmony_ci		/*
18558c2ecf20Sopenharmony_ci		 * OOPS, we missed.  That's actually pretty bad since
18568c2ecf20Sopenharmony_ci		 * the hub will be unhappy; try ASAP I guess.
18578c2ecf20Sopenharmony_ci		 */
18588c2ecf20Sopenharmony_ci		missed = dwc2_frame_num_dec(prev_frame_number,
18598c2ecf20Sopenharmony_ci					    qh->next_active_frame);
18608c2ecf20Sopenharmony_ci		qh->next_active_frame = frame_number;
18618c2ecf20Sopenharmony_ci	}
18628c2ecf20Sopenharmony_ci
18638c2ecf20Sopenharmony_ci	return missed;
18648c2ecf20Sopenharmony_ci}
18658c2ecf20Sopenharmony_ci
18668c2ecf20Sopenharmony_ci/**
18678c2ecf20Sopenharmony_ci * dwc2_next_periodic_start() - Set next_active_frame for next transfer start
18688c2ecf20Sopenharmony_ci *
18698c2ecf20Sopenharmony_ci * This is called for setting next_active_frame for a periodic transfer for
18708c2ecf20Sopenharmony_ci * all cases other than midway through a periodic split.  This will also update
18718c2ecf20Sopenharmony_ci * start_active_frame.
18728c2ecf20Sopenharmony_ci *
18738c2ecf20Sopenharmony_ci * Since we _always_ keep start_active_frame as the start of the previous
18748c2ecf20Sopenharmony_ci * transfer this is normally pretty easy: we just add our interval to
18758c2ecf20Sopenharmony_ci * start_active_frame and we've got our answer.
18768c2ecf20Sopenharmony_ci *
18778c2ecf20Sopenharmony_ci * The tricks come into play if we miss.  In that case we'll look for the next
18788c2ecf20Sopenharmony_ci * slot we can fit into.
18798c2ecf20Sopenharmony_ci *
18808c2ecf20Sopenharmony_ci * @hsotg:        The HCD state structure
18818c2ecf20Sopenharmony_ci * @qh:           QH for the periodic transfer.
18828c2ecf20Sopenharmony_ci * @frame_number: The current frame number.
18838c2ecf20Sopenharmony_ci *
18848c2ecf20Sopenharmony_ci * Return: number missed by (or 0 if we didn't miss).
18858c2ecf20Sopenharmony_ci */
18868c2ecf20Sopenharmony_cistatic int dwc2_next_periodic_start(struct dwc2_hsotg *hsotg,
18878c2ecf20Sopenharmony_ci				    struct dwc2_qh *qh, u16 frame_number)
18888c2ecf20Sopenharmony_ci{
18898c2ecf20Sopenharmony_ci	int missed = 0;
18908c2ecf20Sopenharmony_ci	u16 interval = qh->host_interval;
18918c2ecf20Sopenharmony_ci	u16 prev_frame_number = dwc2_frame_num_dec(frame_number, 1);
18928c2ecf20Sopenharmony_ci
18938c2ecf20Sopenharmony_ci	qh->start_active_frame = dwc2_frame_num_inc(qh->start_active_frame,
18948c2ecf20Sopenharmony_ci						    interval);
18958c2ecf20Sopenharmony_ci
18968c2ecf20Sopenharmony_ci	/*
18978c2ecf20Sopenharmony_ci	 * The dwc2_frame_num_gt() function used below won't work terribly well
18988c2ecf20Sopenharmony_ci	 * with if we just incremented by a really large intervals since the
18998c2ecf20Sopenharmony_ci	 * frame counter only goes to 0x3fff.  It's terribly unlikely that we
19008c2ecf20Sopenharmony_ci	 * will have missed in this case anyway.  Just go to exit.  If we want
19018c2ecf20Sopenharmony_ci	 * to try to do better we'll need to keep track of a bigger counter
19028c2ecf20Sopenharmony_ci	 * somewhere in the driver and handle overflows.
19038c2ecf20Sopenharmony_ci	 */
19048c2ecf20Sopenharmony_ci	if (interval >= 0x1000)
19058c2ecf20Sopenharmony_ci		goto exit;
19068c2ecf20Sopenharmony_ci
19078c2ecf20Sopenharmony_ci	/*
19088c2ecf20Sopenharmony_ci	 * Test for misses, which is when it's too late to schedule.
19098c2ecf20Sopenharmony_ci	 *
19108c2ecf20Sopenharmony_ci	 * A few things to note:
19118c2ecf20Sopenharmony_ci	 * - We compare against prev_frame_number since start_active_frame
19128c2ecf20Sopenharmony_ci	 *   and next_active_frame are always 1 frame before we want things
19138c2ecf20Sopenharmony_ci	 *   to be active and we assume we can still get scheduled in the
19148c2ecf20Sopenharmony_ci	 *   current frame number.
19158c2ecf20Sopenharmony_ci	 * - It's possible for start_active_frame (now incremented) to be
19168c2ecf20Sopenharmony_ci	 *   next_active_frame if we got an EO MISS (even_odd miss) which
19178c2ecf20Sopenharmony_ci	 *   basically means that we detected there wasn't enough time for
19188c2ecf20Sopenharmony_ci	 *   the last packet and dwc2_hc_set_even_odd_frame() rescheduled us
19198c2ecf20Sopenharmony_ci	 *   at the last second.  We want to make sure we don't schedule
19208c2ecf20Sopenharmony_ci	 *   another transfer for the same frame.  My test webcam doesn't seem
19218c2ecf20Sopenharmony_ci	 *   terribly upset by missing a transfer but really doesn't like when
19228c2ecf20Sopenharmony_ci	 *   we do two transfers in the same frame.
19238c2ecf20Sopenharmony_ci	 * - Some misses are expected.  Specifically, in order to work
19248c2ecf20Sopenharmony_ci	 *   perfectly dwc2 really needs quite spectacular interrupt latency
19258c2ecf20Sopenharmony_ci	 *   requirements.  It needs to be able to handle its interrupts
19268c2ecf20Sopenharmony_ci	 *   completely within 125 us of them being asserted. That not only
19278c2ecf20Sopenharmony_ci	 *   means that the dwc2 interrupt handler needs to be fast but it
19288c2ecf20Sopenharmony_ci	 *   means that nothing else in the system has to block dwc2 for a long
19298c2ecf20Sopenharmony_ci	 *   time.  We can help with the dwc2 parts of this, but it's hard to
19308c2ecf20Sopenharmony_ci	 *   guarantee that a system will have interrupt latency < 125 us, so
19318c2ecf20Sopenharmony_ci	 *   we have to be robust to some misses.
19328c2ecf20Sopenharmony_ci	 */
19338c2ecf20Sopenharmony_ci	if (qh->start_active_frame == qh->next_active_frame ||
19348c2ecf20Sopenharmony_ci	    dwc2_frame_num_gt(prev_frame_number, qh->start_active_frame)) {
19358c2ecf20Sopenharmony_ci		u16 ideal_start = qh->start_active_frame;
19368c2ecf20Sopenharmony_ci		int periods_in_map;
19378c2ecf20Sopenharmony_ci
19388c2ecf20Sopenharmony_ci		/*
19398c2ecf20Sopenharmony_ci		 * Adjust interval as per gcd with map size.
19408c2ecf20Sopenharmony_ci		 * See pmap_schedule() for more details here.
19418c2ecf20Sopenharmony_ci		 */
19428c2ecf20Sopenharmony_ci		if (qh->do_split || qh->dev_speed == USB_SPEED_HIGH)
19438c2ecf20Sopenharmony_ci			periods_in_map = DWC2_HS_SCHEDULE_UFRAMES;
19448c2ecf20Sopenharmony_ci		else
19458c2ecf20Sopenharmony_ci			periods_in_map = DWC2_LS_SCHEDULE_FRAMES;
19468c2ecf20Sopenharmony_ci		interval = gcd(interval, periods_in_map);
19478c2ecf20Sopenharmony_ci
19488c2ecf20Sopenharmony_ci		do {
19498c2ecf20Sopenharmony_ci			qh->start_active_frame = dwc2_frame_num_inc(
19508c2ecf20Sopenharmony_ci				qh->start_active_frame, interval);
19518c2ecf20Sopenharmony_ci		} while (dwc2_frame_num_gt(prev_frame_number,
19528c2ecf20Sopenharmony_ci					   qh->start_active_frame));
19538c2ecf20Sopenharmony_ci
19548c2ecf20Sopenharmony_ci		missed = dwc2_frame_num_dec(qh->start_active_frame,
19558c2ecf20Sopenharmony_ci					    ideal_start);
19568c2ecf20Sopenharmony_ci	}
19578c2ecf20Sopenharmony_ci
19588c2ecf20Sopenharmony_ciexit:
19598c2ecf20Sopenharmony_ci	qh->next_active_frame = qh->start_active_frame;
19608c2ecf20Sopenharmony_ci
19618c2ecf20Sopenharmony_ci	return missed;
19628c2ecf20Sopenharmony_ci}
19638c2ecf20Sopenharmony_ci
19648c2ecf20Sopenharmony_ci/*
19658c2ecf20Sopenharmony_ci * Deactivates a QH. For non-periodic QHs, removes the QH from the active
19668c2ecf20Sopenharmony_ci * non-periodic schedule. The QH is added to the inactive non-periodic
19678c2ecf20Sopenharmony_ci * schedule if any QTDs are still attached to the QH.
19688c2ecf20Sopenharmony_ci *
19698c2ecf20Sopenharmony_ci * For periodic QHs, the QH is removed from the periodic queued schedule. If
19708c2ecf20Sopenharmony_ci * there are any QTDs still attached to the QH, the QH is added to either the
19718c2ecf20Sopenharmony_ci * periodic inactive schedule or the periodic ready schedule and its next
19728c2ecf20Sopenharmony_ci * scheduled frame is calculated. The QH is placed in the ready schedule if
19738c2ecf20Sopenharmony_ci * the scheduled frame has been reached already. Otherwise it's placed in the
19748c2ecf20Sopenharmony_ci * inactive schedule. If there are no QTDs attached to the QH, the QH is
19758c2ecf20Sopenharmony_ci * completely removed from the periodic schedule.
19768c2ecf20Sopenharmony_ci */
19778c2ecf20Sopenharmony_civoid dwc2_hcd_qh_deactivate(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh,
19788c2ecf20Sopenharmony_ci			    int sched_next_periodic_split)
19798c2ecf20Sopenharmony_ci{
19808c2ecf20Sopenharmony_ci	u16 old_frame = qh->next_active_frame;
19818c2ecf20Sopenharmony_ci	u16 frame_number;
19828c2ecf20Sopenharmony_ci	int missed;
19838c2ecf20Sopenharmony_ci
19848c2ecf20Sopenharmony_ci	if (dbg_qh(qh))
19858c2ecf20Sopenharmony_ci		dev_vdbg(hsotg->dev, "%s()\n", __func__);
19868c2ecf20Sopenharmony_ci
19878c2ecf20Sopenharmony_ci	if (dwc2_qh_is_non_per(qh)) {
19888c2ecf20Sopenharmony_ci		dwc2_hcd_qh_unlink(hsotg, qh);
19898c2ecf20Sopenharmony_ci		if (!list_empty(&qh->qtd_list))
19908c2ecf20Sopenharmony_ci			/* Add back to inactive/waiting non-periodic schedule */
19918c2ecf20Sopenharmony_ci			dwc2_hcd_qh_add(hsotg, qh);
19928c2ecf20Sopenharmony_ci		return;
19938c2ecf20Sopenharmony_ci	}
19948c2ecf20Sopenharmony_ci
19958c2ecf20Sopenharmony_ci	/*
19968c2ecf20Sopenharmony_ci	 * Use the real frame number rather than the cached value as of the
19978c2ecf20Sopenharmony_ci	 * last SOF just to get us a little closer to reality.  Note that
19988c2ecf20Sopenharmony_ci	 * means we don't actually know if we've already handled the SOF
19998c2ecf20Sopenharmony_ci	 * interrupt for this frame.
20008c2ecf20Sopenharmony_ci	 */
20018c2ecf20Sopenharmony_ci	frame_number = dwc2_hcd_get_frame_number(hsotg);
20028c2ecf20Sopenharmony_ci
20038c2ecf20Sopenharmony_ci	if (sched_next_periodic_split)
20048c2ecf20Sopenharmony_ci		missed = dwc2_next_for_periodic_split(hsotg, qh, frame_number);
20058c2ecf20Sopenharmony_ci	else
20068c2ecf20Sopenharmony_ci		missed = dwc2_next_periodic_start(hsotg, qh, frame_number);
20078c2ecf20Sopenharmony_ci
20088c2ecf20Sopenharmony_ci	dwc2_sch_vdbg(hsotg,
20098c2ecf20Sopenharmony_ci		      "QH=%p next(%d) fn=%04x, sch=%04x=>%04x (%+d) miss=%d %s\n",
20108c2ecf20Sopenharmony_ci		     qh, sched_next_periodic_split, frame_number, old_frame,
20118c2ecf20Sopenharmony_ci		     qh->next_active_frame,
20128c2ecf20Sopenharmony_ci		     dwc2_frame_num_dec(qh->next_active_frame, old_frame),
20138c2ecf20Sopenharmony_ci		missed, missed ? "MISS" : "");
20148c2ecf20Sopenharmony_ci
20158c2ecf20Sopenharmony_ci	if (list_empty(&qh->qtd_list)) {
20168c2ecf20Sopenharmony_ci		dwc2_hcd_qh_unlink(hsotg, qh);
20178c2ecf20Sopenharmony_ci		return;
20188c2ecf20Sopenharmony_ci	}
20198c2ecf20Sopenharmony_ci
20208c2ecf20Sopenharmony_ci	/*
20218c2ecf20Sopenharmony_ci	 * Remove from periodic_sched_queued and move to
20228c2ecf20Sopenharmony_ci	 * appropriate queue
20238c2ecf20Sopenharmony_ci	 *
20248c2ecf20Sopenharmony_ci	 * Note: we purposely use the frame_number from the "hsotg" structure
20258c2ecf20Sopenharmony_ci	 * since we know SOF interrupt will handle future frames.
20268c2ecf20Sopenharmony_ci	 */
20278c2ecf20Sopenharmony_ci	if (dwc2_frame_num_le(qh->next_active_frame, hsotg->frame_number))
20288c2ecf20Sopenharmony_ci		list_move_tail(&qh->qh_list_entry,
20298c2ecf20Sopenharmony_ci			       &hsotg->periodic_sched_ready);
20308c2ecf20Sopenharmony_ci	else
20318c2ecf20Sopenharmony_ci		list_move_tail(&qh->qh_list_entry,
20328c2ecf20Sopenharmony_ci			       &hsotg->periodic_sched_inactive);
20338c2ecf20Sopenharmony_ci}
20348c2ecf20Sopenharmony_ci
20358c2ecf20Sopenharmony_ci/**
20368c2ecf20Sopenharmony_ci * dwc2_hcd_qtd_init() - Initializes a QTD structure
20378c2ecf20Sopenharmony_ci *
20388c2ecf20Sopenharmony_ci * @qtd: The QTD to initialize
20398c2ecf20Sopenharmony_ci * @urb: The associated URB
20408c2ecf20Sopenharmony_ci */
20418c2ecf20Sopenharmony_civoid dwc2_hcd_qtd_init(struct dwc2_qtd *qtd, struct dwc2_hcd_urb *urb)
20428c2ecf20Sopenharmony_ci{
20438c2ecf20Sopenharmony_ci	qtd->urb = urb;
20448c2ecf20Sopenharmony_ci	if (dwc2_hcd_get_pipe_type(&urb->pipe_info) ==
20458c2ecf20Sopenharmony_ci			USB_ENDPOINT_XFER_CONTROL) {
20468c2ecf20Sopenharmony_ci		/*
20478c2ecf20Sopenharmony_ci		 * The only time the QTD data toggle is used is on the data
20488c2ecf20Sopenharmony_ci		 * phase of control transfers. This phase always starts with
20498c2ecf20Sopenharmony_ci		 * DATA1.
20508c2ecf20Sopenharmony_ci		 */
20518c2ecf20Sopenharmony_ci		qtd->data_toggle = DWC2_HC_PID_DATA1;
20528c2ecf20Sopenharmony_ci		qtd->control_phase = DWC2_CONTROL_SETUP;
20538c2ecf20Sopenharmony_ci	}
20548c2ecf20Sopenharmony_ci
20558c2ecf20Sopenharmony_ci	/* Start split */
20568c2ecf20Sopenharmony_ci	qtd->complete_split = 0;
20578c2ecf20Sopenharmony_ci	qtd->isoc_split_pos = DWC2_HCSPLT_XACTPOS_ALL;
20588c2ecf20Sopenharmony_ci	qtd->isoc_split_offset = 0;
20598c2ecf20Sopenharmony_ci	qtd->in_process = 0;
20608c2ecf20Sopenharmony_ci
20618c2ecf20Sopenharmony_ci	/* Store the qtd ptr in the urb to reference the QTD */
20628c2ecf20Sopenharmony_ci	urb->qtd = qtd;
20638c2ecf20Sopenharmony_ci}
20648c2ecf20Sopenharmony_ci
20658c2ecf20Sopenharmony_ci/**
20668c2ecf20Sopenharmony_ci * dwc2_hcd_qtd_add() - Adds a QTD to the QTD-list of a QH
20678c2ecf20Sopenharmony_ci *			Caller must hold driver lock.
20688c2ecf20Sopenharmony_ci *
20698c2ecf20Sopenharmony_ci * @hsotg:        The DWC HCD structure
20708c2ecf20Sopenharmony_ci * @qtd:          The QTD to add
20718c2ecf20Sopenharmony_ci * @qh:           Queue head to add qtd to
20728c2ecf20Sopenharmony_ci *
20738c2ecf20Sopenharmony_ci * Return: 0 if successful, negative error code otherwise
20748c2ecf20Sopenharmony_ci *
20758c2ecf20Sopenharmony_ci * If the QH to which the QTD is added is not currently scheduled, it is placed
20768c2ecf20Sopenharmony_ci * into the proper schedule based on its EP type.
20778c2ecf20Sopenharmony_ci */
20788c2ecf20Sopenharmony_ciint dwc2_hcd_qtd_add(struct dwc2_hsotg *hsotg, struct dwc2_qtd *qtd,
20798c2ecf20Sopenharmony_ci		     struct dwc2_qh *qh)
20808c2ecf20Sopenharmony_ci{
20818c2ecf20Sopenharmony_ci	int retval;
20828c2ecf20Sopenharmony_ci
20838c2ecf20Sopenharmony_ci	if (unlikely(!qh)) {
20848c2ecf20Sopenharmony_ci		dev_err(hsotg->dev, "%s: Invalid QH\n", __func__);
20858c2ecf20Sopenharmony_ci		retval = -EINVAL;
20868c2ecf20Sopenharmony_ci		goto fail;
20878c2ecf20Sopenharmony_ci	}
20888c2ecf20Sopenharmony_ci
20898c2ecf20Sopenharmony_ci	retval = dwc2_hcd_qh_add(hsotg, qh);
20908c2ecf20Sopenharmony_ci	if (retval)
20918c2ecf20Sopenharmony_ci		goto fail;
20928c2ecf20Sopenharmony_ci
20938c2ecf20Sopenharmony_ci	qtd->qh = qh;
20948c2ecf20Sopenharmony_ci	list_add_tail(&qtd->qtd_list_entry, &qh->qtd_list);
20958c2ecf20Sopenharmony_ci
20968c2ecf20Sopenharmony_ci	return 0;
20978c2ecf20Sopenharmony_cifail:
20988c2ecf20Sopenharmony_ci	return retval;
20998c2ecf20Sopenharmony_ci}
2100