162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+
262306a36Sopenharmony_ci/* Faraday FOTG210 EHCI-like driver
362306a36Sopenharmony_ci *
462306a36Sopenharmony_ci * Copyright (c) 2013 Faraday Technology Corporation
562306a36Sopenharmony_ci *
662306a36Sopenharmony_ci * Author: Yuan-Hsin Chen <yhchen@faraday-tech.com>
762306a36Sopenharmony_ci *	   Feng-Hsin Chiang <john453@faraday-tech.com>
862306a36Sopenharmony_ci *	   Po-Yu Chuang <ratbert.chuang@gmail.com>
962306a36Sopenharmony_ci *
1062306a36Sopenharmony_ci * Most of code borrowed from the Linux-3.7 EHCI driver
1162306a36Sopenharmony_ci */
1262306a36Sopenharmony_ci#include <linux/module.h>
1362306a36Sopenharmony_ci#include <linux/of.h>
1462306a36Sopenharmony_ci#include <linux/device.h>
1562306a36Sopenharmony_ci#include <linux/dmapool.h>
1662306a36Sopenharmony_ci#include <linux/kernel.h>
1762306a36Sopenharmony_ci#include <linux/delay.h>
1862306a36Sopenharmony_ci#include <linux/ioport.h>
1962306a36Sopenharmony_ci#include <linux/sched.h>
2062306a36Sopenharmony_ci#include <linux/vmalloc.h>
2162306a36Sopenharmony_ci#include <linux/errno.h>
2262306a36Sopenharmony_ci#include <linux/init.h>
2362306a36Sopenharmony_ci#include <linux/hrtimer.h>
2462306a36Sopenharmony_ci#include <linux/list.h>
2562306a36Sopenharmony_ci#include <linux/interrupt.h>
2662306a36Sopenharmony_ci#include <linux/usb.h>
2762306a36Sopenharmony_ci#include <linux/usb/hcd.h>
2862306a36Sopenharmony_ci#include <linux/moduleparam.h>
2962306a36Sopenharmony_ci#include <linux/dma-mapping.h>
3062306a36Sopenharmony_ci#include <linux/debugfs.h>
3162306a36Sopenharmony_ci#include <linux/slab.h>
3262306a36Sopenharmony_ci#include <linux/uaccess.h>
3362306a36Sopenharmony_ci#include <linux/platform_device.h>
3462306a36Sopenharmony_ci#include <linux/io.h>
3562306a36Sopenharmony_ci#include <linux/iopoll.h>
3662306a36Sopenharmony_ci
3762306a36Sopenharmony_ci#include <asm/byteorder.h>
3862306a36Sopenharmony_ci#include <asm/irq.h>
3962306a36Sopenharmony_ci#include <asm/unaligned.h>
4062306a36Sopenharmony_ci
4162306a36Sopenharmony_ci#include "fotg210.h"
4262306a36Sopenharmony_ci
4362306a36Sopenharmony_cistatic const char hcd_name[] = "fotg210_hcd";
4462306a36Sopenharmony_ci
4562306a36Sopenharmony_ci#undef FOTG210_URB_TRACE
4662306a36Sopenharmony_ci#define FOTG210_STATS
4762306a36Sopenharmony_ci
4862306a36Sopenharmony_ci/* magic numbers that can affect system performance */
4962306a36Sopenharmony_ci#define FOTG210_TUNE_CERR	3 /* 0-3 qtd retries; 0 == don't stop */
5062306a36Sopenharmony_ci#define FOTG210_TUNE_RL_HS	4 /* nak throttle; see 4.9 */
5162306a36Sopenharmony_ci#define FOTG210_TUNE_RL_TT	0
5262306a36Sopenharmony_ci#define FOTG210_TUNE_MULT_HS	1 /* 1-3 transactions/uframe; 4.10.3 */
5362306a36Sopenharmony_ci#define FOTG210_TUNE_MULT_TT	1
5462306a36Sopenharmony_ci
5562306a36Sopenharmony_ci/* Some drivers think it's safe to schedule isochronous transfers more than 256
5662306a36Sopenharmony_ci * ms into the future (partly as a result of an old bug in the scheduling
5762306a36Sopenharmony_ci * code).  In an attempt to avoid trouble, we will use a minimum scheduling
5862306a36Sopenharmony_ci * length of 512 frames instead of 256.
5962306a36Sopenharmony_ci */
6062306a36Sopenharmony_ci#define FOTG210_TUNE_FLS 1 /* (medium) 512-frame schedule */
6162306a36Sopenharmony_ci
6262306a36Sopenharmony_ci/* Initial IRQ latency:  faster than hw default */
6362306a36Sopenharmony_cistatic int log2_irq_thresh; /* 0 to 6 */
6462306a36Sopenharmony_cimodule_param(log2_irq_thresh, int, S_IRUGO);
6562306a36Sopenharmony_ciMODULE_PARM_DESC(log2_irq_thresh, "log2 IRQ latency, 1-64 microframes");
6662306a36Sopenharmony_ci
6762306a36Sopenharmony_ci/* initial park setting:  slower than hw default */
6862306a36Sopenharmony_cistatic unsigned park;
6962306a36Sopenharmony_cimodule_param(park, uint, S_IRUGO);
7062306a36Sopenharmony_ciMODULE_PARM_DESC(park, "park setting; 1-3 back-to-back async packets");
7162306a36Sopenharmony_ci
7262306a36Sopenharmony_ci/* for link power management(LPM) feature */
7362306a36Sopenharmony_cistatic unsigned int hird;
7462306a36Sopenharmony_cimodule_param(hird, int, S_IRUGO);
7562306a36Sopenharmony_ciMODULE_PARM_DESC(hird, "host initiated resume duration, +1 for each 75us");
7662306a36Sopenharmony_ci
7762306a36Sopenharmony_ci#define INTR_MASK (STS_IAA | STS_FATAL | STS_PCD | STS_ERR | STS_INT)
7862306a36Sopenharmony_ci
7962306a36Sopenharmony_ci#include "fotg210-hcd.h"
8062306a36Sopenharmony_ci
8162306a36Sopenharmony_ci#define fotg210_dbg(fotg210, fmt, args...) \
8262306a36Sopenharmony_ci	dev_dbg(fotg210_to_hcd(fotg210)->self.controller, fmt, ## args)
8362306a36Sopenharmony_ci#define fotg210_err(fotg210, fmt, args...) \
8462306a36Sopenharmony_ci	dev_err(fotg210_to_hcd(fotg210)->self.controller, fmt, ## args)
8562306a36Sopenharmony_ci#define fotg210_info(fotg210, fmt, args...) \
8662306a36Sopenharmony_ci	dev_info(fotg210_to_hcd(fotg210)->self.controller, fmt, ## args)
8762306a36Sopenharmony_ci#define fotg210_warn(fotg210, fmt, args...) \
8862306a36Sopenharmony_ci	dev_warn(fotg210_to_hcd(fotg210)->self.controller, fmt, ## args)
8962306a36Sopenharmony_ci
9062306a36Sopenharmony_ci/* check the values in the HCSPARAMS register (host controller _Structural_
9162306a36Sopenharmony_ci * parameters) see EHCI spec, Table 2-4 for each value
9262306a36Sopenharmony_ci */
9362306a36Sopenharmony_cistatic void dbg_hcs_params(struct fotg210_hcd *fotg210, char *label)
9462306a36Sopenharmony_ci{
9562306a36Sopenharmony_ci	u32 params = fotg210_readl(fotg210, &fotg210->caps->hcs_params);
9662306a36Sopenharmony_ci
9762306a36Sopenharmony_ci	fotg210_dbg(fotg210, "%s hcs_params 0x%x ports=%d\n", label, params,
9862306a36Sopenharmony_ci			HCS_N_PORTS(params));
9962306a36Sopenharmony_ci}
10062306a36Sopenharmony_ci
10162306a36Sopenharmony_ci/* check the values in the HCCPARAMS register (host controller _Capability_
10262306a36Sopenharmony_ci * parameters) see EHCI Spec, Table 2-5 for each value
10362306a36Sopenharmony_ci */
10462306a36Sopenharmony_cistatic void dbg_hcc_params(struct fotg210_hcd *fotg210, char *label)
10562306a36Sopenharmony_ci{
10662306a36Sopenharmony_ci	u32 params = fotg210_readl(fotg210, &fotg210->caps->hcc_params);
10762306a36Sopenharmony_ci
10862306a36Sopenharmony_ci	fotg210_dbg(fotg210, "%s hcc_params %04x uframes %s%s\n", label,
10962306a36Sopenharmony_ci			params,
11062306a36Sopenharmony_ci			HCC_PGM_FRAMELISTLEN(params) ? "256/512/1024" : "1024",
11162306a36Sopenharmony_ci			HCC_CANPARK(params) ? " park" : "");
11262306a36Sopenharmony_ci}
11362306a36Sopenharmony_ci
11462306a36Sopenharmony_cistatic void __maybe_unused
11562306a36Sopenharmony_cidbg_qtd(const char *label, struct fotg210_hcd *fotg210, struct fotg210_qtd *qtd)
11662306a36Sopenharmony_ci{
11762306a36Sopenharmony_ci	fotg210_dbg(fotg210, "%s td %p n%08x %08x t%08x p0=%08x\n", label, qtd,
11862306a36Sopenharmony_ci			hc32_to_cpup(fotg210, &qtd->hw_next),
11962306a36Sopenharmony_ci			hc32_to_cpup(fotg210, &qtd->hw_alt_next),
12062306a36Sopenharmony_ci			hc32_to_cpup(fotg210, &qtd->hw_token),
12162306a36Sopenharmony_ci			hc32_to_cpup(fotg210, &qtd->hw_buf[0]));
12262306a36Sopenharmony_ci	if (qtd->hw_buf[1])
12362306a36Sopenharmony_ci		fotg210_dbg(fotg210, "  p1=%08x p2=%08x p3=%08x p4=%08x\n",
12462306a36Sopenharmony_ci				hc32_to_cpup(fotg210, &qtd->hw_buf[1]),
12562306a36Sopenharmony_ci				hc32_to_cpup(fotg210, &qtd->hw_buf[2]),
12662306a36Sopenharmony_ci				hc32_to_cpup(fotg210, &qtd->hw_buf[3]),
12762306a36Sopenharmony_ci				hc32_to_cpup(fotg210, &qtd->hw_buf[4]));
12862306a36Sopenharmony_ci}
12962306a36Sopenharmony_ci
13062306a36Sopenharmony_cistatic void __maybe_unused
13162306a36Sopenharmony_cidbg_qh(const char *label, struct fotg210_hcd *fotg210, struct fotg210_qh *qh)
13262306a36Sopenharmony_ci{
13362306a36Sopenharmony_ci	struct fotg210_qh_hw *hw = qh->hw;
13462306a36Sopenharmony_ci
13562306a36Sopenharmony_ci	fotg210_dbg(fotg210, "%s qh %p n%08x info %x %x qtd %x\n", label, qh,
13662306a36Sopenharmony_ci			hw->hw_next, hw->hw_info1, hw->hw_info2,
13762306a36Sopenharmony_ci			hw->hw_current);
13862306a36Sopenharmony_ci
13962306a36Sopenharmony_ci	dbg_qtd("overlay", fotg210, (struct fotg210_qtd *) &hw->hw_qtd_next);
14062306a36Sopenharmony_ci}
14162306a36Sopenharmony_ci
14262306a36Sopenharmony_cistatic void __maybe_unused
14362306a36Sopenharmony_cidbg_itd(const char *label, struct fotg210_hcd *fotg210, struct fotg210_itd *itd)
14462306a36Sopenharmony_ci{
14562306a36Sopenharmony_ci	fotg210_dbg(fotg210, "%s[%d] itd %p, next %08x, urb %p\n", label,
14662306a36Sopenharmony_ci			itd->frame, itd, hc32_to_cpu(fotg210, itd->hw_next),
14762306a36Sopenharmony_ci			itd->urb);
14862306a36Sopenharmony_ci
14962306a36Sopenharmony_ci	fotg210_dbg(fotg210,
15062306a36Sopenharmony_ci			"  trans: %08x %08x %08x %08x %08x %08x %08x %08x\n",
15162306a36Sopenharmony_ci			hc32_to_cpu(fotg210, itd->hw_transaction[0]),
15262306a36Sopenharmony_ci			hc32_to_cpu(fotg210, itd->hw_transaction[1]),
15362306a36Sopenharmony_ci			hc32_to_cpu(fotg210, itd->hw_transaction[2]),
15462306a36Sopenharmony_ci			hc32_to_cpu(fotg210, itd->hw_transaction[3]),
15562306a36Sopenharmony_ci			hc32_to_cpu(fotg210, itd->hw_transaction[4]),
15662306a36Sopenharmony_ci			hc32_to_cpu(fotg210, itd->hw_transaction[5]),
15762306a36Sopenharmony_ci			hc32_to_cpu(fotg210, itd->hw_transaction[6]),
15862306a36Sopenharmony_ci			hc32_to_cpu(fotg210, itd->hw_transaction[7]));
15962306a36Sopenharmony_ci
16062306a36Sopenharmony_ci	fotg210_dbg(fotg210,
16162306a36Sopenharmony_ci			"  buf:   %08x %08x %08x %08x %08x %08x %08x\n",
16262306a36Sopenharmony_ci			hc32_to_cpu(fotg210, itd->hw_bufp[0]),
16362306a36Sopenharmony_ci			hc32_to_cpu(fotg210, itd->hw_bufp[1]),
16462306a36Sopenharmony_ci			hc32_to_cpu(fotg210, itd->hw_bufp[2]),
16562306a36Sopenharmony_ci			hc32_to_cpu(fotg210, itd->hw_bufp[3]),
16662306a36Sopenharmony_ci			hc32_to_cpu(fotg210, itd->hw_bufp[4]),
16762306a36Sopenharmony_ci			hc32_to_cpu(fotg210, itd->hw_bufp[5]),
16862306a36Sopenharmony_ci			hc32_to_cpu(fotg210, itd->hw_bufp[6]));
16962306a36Sopenharmony_ci
17062306a36Sopenharmony_ci	fotg210_dbg(fotg210, "  index: %d %d %d %d %d %d %d %d\n",
17162306a36Sopenharmony_ci			itd->index[0], itd->index[1], itd->index[2],
17262306a36Sopenharmony_ci			itd->index[3], itd->index[4], itd->index[5],
17362306a36Sopenharmony_ci			itd->index[6], itd->index[7]);
17462306a36Sopenharmony_ci}
17562306a36Sopenharmony_ci
17662306a36Sopenharmony_cistatic int __maybe_unused
17762306a36Sopenharmony_cidbg_status_buf(char *buf, unsigned len, const char *label, u32 status)
17862306a36Sopenharmony_ci{
17962306a36Sopenharmony_ci	return scnprintf(buf, len, "%s%sstatus %04x%s%s%s%s%s%s%s%s%s%s",
18062306a36Sopenharmony_ci			label, label[0] ? " " : "", status,
18162306a36Sopenharmony_ci			(status & STS_ASS) ? " Async" : "",
18262306a36Sopenharmony_ci			(status & STS_PSS) ? " Periodic" : "",
18362306a36Sopenharmony_ci			(status & STS_RECL) ? " Recl" : "",
18462306a36Sopenharmony_ci			(status & STS_HALT) ? " Halt" : "",
18562306a36Sopenharmony_ci			(status & STS_IAA) ? " IAA" : "",
18662306a36Sopenharmony_ci			(status & STS_FATAL) ? " FATAL" : "",
18762306a36Sopenharmony_ci			(status & STS_FLR) ? " FLR" : "",
18862306a36Sopenharmony_ci			(status & STS_PCD) ? " PCD" : "",
18962306a36Sopenharmony_ci			(status & STS_ERR) ? " ERR" : "",
19062306a36Sopenharmony_ci			(status & STS_INT) ? " INT" : "");
19162306a36Sopenharmony_ci}
19262306a36Sopenharmony_ci
19362306a36Sopenharmony_cistatic int __maybe_unused
19462306a36Sopenharmony_cidbg_intr_buf(char *buf, unsigned len, const char *label, u32 enable)
19562306a36Sopenharmony_ci{
19662306a36Sopenharmony_ci	return scnprintf(buf, len, "%s%sintrenable %02x%s%s%s%s%s%s",
19762306a36Sopenharmony_ci			label, label[0] ? " " : "", enable,
19862306a36Sopenharmony_ci			(enable & STS_IAA) ? " IAA" : "",
19962306a36Sopenharmony_ci			(enable & STS_FATAL) ? " FATAL" : "",
20062306a36Sopenharmony_ci			(enable & STS_FLR) ? " FLR" : "",
20162306a36Sopenharmony_ci			(enable & STS_PCD) ? " PCD" : "",
20262306a36Sopenharmony_ci			(enable & STS_ERR) ? " ERR" : "",
20362306a36Sopenharmony_ci			(enable & STS_INT) ? " INT" : "");
20462306a36Sopenharmony_ci}
20562306a36Sopenharmony_ci
20662306a36Sopenharmony_cistatic const char *const fls_strings[] = { "1024", "512", "256", "??" };
20762306a36Sopenharmony_ci
20862306a36Sopenharmony_cistatic int dbg_command_buf(char *buf, unsigned len, const char *label,
20962306a36Sopenharmony_ci		u32 command)
21062306a36Sopenharmony_ci{
21162306a36Sopenharmony_ci	return scnprintf(buf, len,
21262306a36Sopenharmony_ci			"%s%scommand %07x %s=%d ithresh=%d%s%s%s period=%s%s %s",
21362306a36Sopenharmony_ci			label, label[0] ? " " : "", command,
21462306a36Sopenharmony_ci			(command & CMD_PARK) ? " park" : "(park)",
21562306a36Sopenharmony_ci			CMD_PARK_CNT(command),
21662306a36Sopenharmony_ci			(command >> 16) & 0x3f,
21762306a36Sopenharmony_ci			(command & CMD_IAAD) ? " IAAD" : "",
21862306a36Sopenharmony_ci			(command & CMD_ASE) ? " Async" : "",
21962306a36Sopenharmony_ci			(command & CMD_PSE) ? " Periodic" : "",
22062306a36Sopenharmony_ci			fls_strings[(command >> 2) & 0x3],
22162306a36Sopenharmony_ci			(command & CMD_RESET) ? " Reset" : "",
22262306a36Sopenharmony_ci			(command & CMD_RUN) ? "RUN" : "HALT");
22362306a36Sopenharmony_ci}
22462306a36Sopenharmony_ci
22562306a36Sopenharmony_cistatic char *dbg_port_buf(char *buf, unsigned len, const char *label, int port,
22662306a36Sopenharmony_ci		u32 status)
22762306a36Sopenharmony_ci{
22862306a36Sopenharmony_ci	char *sig;
22962306a36Sopenharmony_ci
23062306a36Sopenharmony_ci	/* signaling state */
23162306a36Sopenharmony_ci	switch (status & (3 << 10)) {
23262306a36Sopenharmony_ci	case 0 << 10:
23362306a36Sopenharmony_ci		sig = "se0";
23462306a36Sopenharmony_ci		break;
23562306a36Sopenharmony_ci	case 1 << 10:
23662306a36Sopenharmony_ci		sig = "k";
23762306a36Sopenharmony_ci		break; /* low speed */
23862306a36Sopenharmony_ci	case 2 << 10:
23962306a36Sopenharmony_ci		sig = "j";
24062306a36Sopenharmony_ci		break;
24162306a36Sopenharmony_ci	default:
24262306a36Sopenharmony_ci		sig = "?";
24362306a36Sopenharmony_ci		break;
24462306a36Sopenharmony_ci	}
24562306a36Sopenharmony_ci
24662306a36Sopenharmony_ci	scnprintf(buf, len, "%s%sport:%d status %06x %d sig=%s%s%s%s%s%s%s%s",
24762306a36Sopenharmony_ci			label, label[0] ? " " : "", port, status,
24862306a36Sopenharmony_ci			status >> 25, /*device address */
24962306a36Sopenharmony_ci			sig,
25062306a36Sopenharmony_ci			(status & PORT_RESET) ? " RESET" : "",
25162306a36Sopenharmony_ci			(status & PORT_SUSPEND) ? " SUSPEND" : "",
25262306a36Sopenharmony_ci			(status & PORT_RESUME) ? " RESUME" : "",
25362306a36Sopenharmony_ci			(status & PORT_PEC) ? " PEC" : "",
25462306a36Sopenharmony_ci			(status & PORT_PE) ? " PE" : "",
25562306a36Sopenharmony_ci			(status & PORT_CSC) ? " CSC" : "",
25662306a36Sopenharmony_ci			(status & PORT_CONNECT) ? " CONNECT" : "");
25762306a36Sopenharmony_ci
25862306a36Sopenharmony_ci	return buf;
25962306a36Sopenharmony_ci}
26062306a36Sopenharmony_ci
26162306a36Sopenharmony_ci/* functions have the "wrong" filename when they're output... */
26262306a36Sopenharmony_ci#define dbg_status(fotg210, label, status) {			\
26362306a36Sopenharmony_ci	char _buf[80];						\
26462306a36Sopenharmony_ci	dbg_status_buf(_buf, sizeof(_buf), label, status);	\
26562306a36Sopenharmony_ci	fotg210_dbg(fotg210, "%s\n", _buf);			\
26662306a36Sopenharmony_ci}
26762306a36Sopenharmony_ci
26862306a36Sopenharmony_ci#define dbg_cmd(fotg210, label, command) {			\
26962306a36Sopenharmony_ci	char _buf[80];						\
27062306a36Sopenharmony_ci	dbg_command_buf(_buf, sizeof(_buf), label, command);	\
27162306a36Sopenharmony_ci	fotg210_dbg(fotg210, "%s\n", _buf);			\
27262306a36Sopenharmony_ci}
27362306a36Sopenharmony_ci
27462306a36Sopenharmony_ci#define dbg_port(fotg210, label, port, status) {			       \
27562306a36Sopenharmony_ci	char _buf[80];							       \
27662306a36Sopenharmony_ci	fotg210_dbg(fotg210, "%s\n",					       \
27762306a36Sopenharmony_ci			dbg_port_buf(_buf, sizeof(_buf), label, port, status));\
27862306a36Sopenharmony_ci}
27962306a36Sopenharmony_ci
28062306a36Sopenharmony_ci/* troubleshooting help: expose state in debugfs */
28162306a36Sopenharmony_cistatic int debug_async_open(struct inode *, struct file *);
28262306a36Sopenharmony_cistatic int debug_periodic_open(struct inode *, struct file *);
28362306a36Sopenharmony_cistatic int debug_registers_open(struct inode *, struct file *);
28462306a36Sopenharmony_cistatic int debug_async_open(struct inode *, struct file *);
28562306a36Sopenharmony_ci
28662306a36Sopenharmony_cistatic ssize_t debug_output(struct file*, char __user*, size_t, loff_t*);
28762306a36Sopenharmony_cistatic int debug_close(struct inode *, struct file *);
28862306a36Sopenharmony_ci
28962306a36Sopenharmony_cistatic const struct file_operations debug_async_fops = {
29062306a36Sopenharmony_ci	.owner		= THIS_MODULE,
29162306a36Sopenharmony_ci	.open		= debug_async_open,
29262306a36Sopenharmony_ci	.read		= debug_output,
29362306a36Sopenharmony_ci	.release	= debug_close,
29462306a36Sopenharmony_ci	.llseek		= default_llseek,
29562306a36Sopenharmony_ci};
29662306a36Sopenharmony_cistatic const struct file_operations debug_periodic_fops = {
29762306a36Sopenharmony_ci	.owner		= THIS_MODULE,
29862306a36Sopenharmony_ci	.open		= debug_periodic_open,
29962306a36Sopenharmony_ci	.read		= debug_output,
30062306a36Sopenharmony_ci	.release	= debug_close,
30162306a36Sopenharmony_ci	.llseek		= default_llseek,
30262306a36Sopenharmony_ci};
30362306a36Sopenharmony_cistatic const struct file_operations debug_registers_fops = {
30462306a36Sopenharmony_ci	.owner		= THIS_MODULE,
30562306a36Sopenharmony_ci	.open		= debug_registers_open,
30662306a36Sopenharmony_ci	.read		= debug_output,
30762306a36Sopenharmony_ci	.release	= debug_close,
30862306a36Sopenharmony_ci	.llseek		= default_llseek,
30962306a36Sopenharmony_ci};
31062306a36Sopenharmony_ci
31162306a36Sopenharmony_cistatic struct dentry *fotg210_debug_root;
31262306a36Sopenharmony_ci
31362306a36Sopenharmony_cistruct debug_buffer {
31462306a36Sopenharmony_ci	ssize_t (*fill_func)(struct debug_buffer *);	/* fill method */
31562306a36Sopenharmony_ci	struct usb_bus *bus;
31662306a36Sopenharmony_ci	struct mutex mutex;	/* protect filling of buffer */
31762306a36Sopenharmony_ci	size_t count;		/* number of characters filled into buffer */
31862306a36Sopenharmony_ci	char *output_buf;
31962306a36Sopenharmony_ci	size_t alloc_size;
32062306a36Sopenharmony_ci};
32162306a36Sopenharmony_ci
32262306a36Sopenharmony_cistatic inline char speed_char(u32 scratch)
32362306a36Sopenharmony_ci{
32462306a36Sopenharmony_ci	switch (scratch & (3 << 12)) {
32562306a36Sopenharmony_ci	case QH_FULL_SPEED:
32662306a36Sopenharmony_ci		return 'f';
32762306a36Sopenharmony_ci
32862306a36Sopenharmony_ci	case QH_LOW_SPEED:
32962306a36Sopenharmony_ci		return 'l';
33062306a36Sopenharmony_ci
33162306a36Sopenharmony_ci	case QH_HIGH_SPEED:
33262306a36Sopenharmony_ci		return 'h';
33362306a36Sopenharmony_ci
33462306a36Sopenharmony_ci	default:
33562306a36Sopenharmony_ci		return '?';
33662306a36Sopenharmony_ci	}
33762306a36Sopenharmony_ci}
33862306a36Sopenharmony_ci
33962306a36Sopenharmony_cistatic inline char token_mark(struct fotg210_hcd *fotg210, __hc32 token)
34062306a36Sopenharmony_ci{
34162306a36Sopenharmony_ci	__u32 v = hc32_to_cpu(fotg210, token);
34262306a36Sopenharmony_ci
34362306a36Sopenharmony_ci	if (v & QTD_STS_ACTIVE)
34462306a36Sopenharmony_ci		return '*';
34562306a36Sopenharmony_ci	if (v & QTD_STS_HALT)
34662306a36Sopenharmony_ci		return '-';
34762306a36Sopenharmony_ci	if (!IS_SHORT_READ(v))
34862306a36Sopenharmony_ci		return ' ';
34962306a36Sopenharmony_ci	/* tries to advance through hw_alt_next */
35062306a36Sopenharmony_ci	return '/';
35162306a36Sopenharmony_ci}
35262306a36Sopenharmony_ci
35362306a36Sopenharmony_cistatic void qh_lines(struct fotg210_hcd *fotg210, struct fotg210_qh *qh,
35462306a36Sopenharmony_ci		char **nextp, unsigned *sizep)
35562306a36Sopenharmony_ci{
35662306a36Sopenharmony_ci	u32 scratch;
35762306a36Sopenharmony_ci	u32 hw_curr;
35862306a36Sopenharmony_ci	struct fotg210_qtd *td;
35962306a36Sopenharmony_ci	unsigned temp;
36062306a36Sopenharmony_ci	unsigned size = *sizep;
36162306a36Sopenharmony_ci	char *next = *nextp;
36262306a36Sopenharmony_ci	char mark;
36362306a36Sopenharmony_ci	__le32 list_end = FOTG210_LIST_END(fotg210);
36462306a36Sopenharmony_ci	struct fotg210_qh_hw *hw = qh->hw;
36562306a36Sopenharmony_ci
36662306a36Sopenharmony_ci	if (hw->hw_qtd_next == list_end) /* NEC does this */
36762306a36Sopenharmony_ci		mark = '@';
36862306a36Sopenharmony_ci	else
36962306a36Sopenharmony_ci		mark = token_mark(fotg210, hw->hw_token);
37062306a36Sopenharmony_ci	if (mark == '/') { /* qh_alt_next controls qh advance? */
37162306a36Sopenharmony_ci		if ((hw->hw_alt_next & QTD_MASK(fotg210)) ==
37262306a36Sopenharmony_ci		    fotg210->async->hw->hw_alt_next)
37362306a36Sopenharmony_ci			mark = '#'; /* blocked */
37462306a36Sopenharmony_ci		else if (hw->hw_alt_next == list_end)
37562306a36Sopenharmony_ci			mark = '.'; /* use hw_qtd_next */
37662306a36Sopenharmony_ci		/* else alt_next points to some other qtd */
37762306a36Sopenharmony_ci	}
37862306a36Sopenharmony_ci	scratch = hc32_to_cpup(fotg210, &hw->hw_info1);
37962306a36Sopenharmony_ci	hw_curr = (mark == '*') ? hc32_to_cpup(fotg210, &hw->hw_current) : 0;
38062306a36Sopenharmony_ci	temp = scnprintf(next, size,
38162306a36Sopenharmony_ci			"qh/%p dev%d %cs ep%d %08x %08x(%08x%c %s nak%d)",
38262306a36Sopenharmony_ci			qh, scratch & 0x007f,
38362306a36Sopenharmony_ci			speed_char(scratch),
38462306a36Sopenharmony_ci			(scratch >> 8) & 0x000f,
38562306a36Sopenharmony_ci			scratch, hc32_to_cpup(fotg210, &hw->hw_info2),
38662306a36Sopenharmony_ci			hc32_to_cpup(fotg210, &hw->hw_token), mark,
38762306a36Sopenharmony_ci			(cpu_to_hc32(fotg210, QTD_TOGGLE) & hw->hw_token)
38862306a36Sopenharmony_ci				? "data1" : "data0",
38962306a36Sopenharmony_ci			(hc32_to_cpup(fotg210, &hw->hw_alt_next) >> 1) & 0x0f);
39062306a36Sopenharmony_ci	size -= temp;
39162306a36Sopenharmony_ci	next += temp;
39262306a36Sopenharmony_ci
39362306a36Sopenharmony_ci	/* hc may be modifying the list as we read it ... */
39462306a36Sopenharmony_ci	list_for_each_entry(td, &qh->qtd_list, qtd_list) {
39562306a36Sopenharmony_ci		scratch = hc32_to_cpup(fotg210, &td->hw_token);
39662306a36Sopenharmony_ci		mark = ' ';
39762306a36Sopenharmony_ci		if (hw_curr == td->qtd_dma)
39862306a36Sopenharmony_ci			mark = '*';
39962306a36Sopenharmony_ci		else if (hw->hw_qtd_next == cpu_to_hc32(fotg210, td->qtd_dma))
40062306a36Sopenharmony_ci			mark = '+';
40162306a36Sopenharmony_ci		else if (QTD_LENGTH(scratch)) {
40262306a36Sopenharmony_ci			if (td->hw_alt_next == fotg210->async->hw->hw_alt_next)
40362306a36Sopenharmony_ci				mark = '#';
40462306a36Sopenharmony_ci			else if (td->hw_alt_next != list_end)
40562306a36Sopenharmony_ci				mark = '/';
40662306a36Sopenharmony_ci		}
40762306a36Sopenharmony_ci		temp = snprintf(next, size,
40862306a36Sopenharmony_ci				"\n\t%p%c%s len=%d %08x urb %p",
40962306a36Sopenharmony_ci				td, mark, ({ char *tmp;
41062306a36Sopenharmony_ci				switch ((scratch>>8)&0x03) {
41162306a36Sopenharmony_ci				case 0:
41262306a36Sopenharmony_ci					tmp = "out";
41362306a36Sopenharmony_ci					break;
41462306a36Sopenharmony_ci				case 1:
41562306a36Sopenharmony_ci					tmp = "in";
41662306a36Sopenharmony_ci					break;
41762306a36Sopenharmony_ci				case 2:
41862306a36Sopenharmony_ci					tmp = "setup";
41962306a36Sopenharmony_ci					break;
42062306a36Sopenharmony_ci				default:
42162306a36Sopenharmony_ci					tmp = "?";
42262306a36Sopenharmony_ci					break;
42362306a36Sopenharmony_ci				 } tmp; }),
42462306a36Sopenharmony_ci				(scratch >> 16) & 0x7fff,
42562306a36Sopenharmony_ci				scratch,
42662306a36Sopenharmony_ci				td->urb);
42762306a36Sopenharmony_ci		if (size < temp)
42862306a36Sopenharmony_ci			temp = size;
42962306a36Sopenharmony_ci		size -= temp;
43062306a36Sopenharmony_ci		next += temp;
43162306a36Sopenharmony_ci	}
43262306a36Sopenharmony_ci
43362306a36Sopenharmony_ci	temp = snprintf(next, size, "\n");
43462306a36Sopenharmony_ci	if (size < temp)
43562306a36Sopenharmony_ci		temp = size;
43662306a36Sopenharmony_ci
43762306a36Sopenharmony_ci	size -= temp;
43862306a36Sopenharmony_ci	next += temp;
43962306a36Sopenharmony_ci
44062306a36Sopenharmony_ci	*sizep = size;
44162306a36Sopenharmony_ci	*nextp = next;
44262306a36Sopenharmony_ci}
44362306a36Sopenharmony_ci
44462306a36Sopenharmony_cistatic ssize_t fill_async_buffer(struct debug_buffer *buf)
44562306a36Sopenharmony_ci{
44662306a36Sopenharmony_ci	struct usb_hcd *hcd;
44762306a36Sopenharmony_ci	struct fotg210_hcd *fotg210;
44862306a36Sopenharmony_ci	unsigned long flags;
44962306a36Sopenharmony_ci	unsigned temp, size;
45062306a36Sopenharmony_ci	char *next;
45162306a36Sopenharmony_ci	struct fotg210_qh *qh;
45262306a36Sopenharmony_ci
45362306a36Sopenharmony_ci	hcd = bus_to_hcd(buf->bus);
45462306a36Sopenharmony_ci	fotg210 = hcd_to_fotg210(hcd);
45562306a36Sopenharmony_ci	next = buf->output_buf;
45662306a36Sopenharmony_ci	size = buf->alloc_size;
45762306a36Sopenharmony_ci
45862306a36Sopenharmony_ci	*next = 0;
45962306a36Sopenharmony_ci
46062306a36Sopenharmony_ci	/* dumps a snapshot of the async schedule.
46162306a36Sopenharmony_ci	 * usually empty except for long-term bulk reads, or head.
46262306a36Sopenharmony_ci	 * one QH per line, and TDs we know about
46362306a36Sopenharmony_ci	 */
46462306a36Sopenharmony_ci	spin_lock_irqsave(&fotg210->lock, flags);
46562306a36Sopenharmony_ci	for (qh = fotg210->async->qh_next.qh; size > 0 && qh;
46662306a36Sopenharmony_ci			qh = qh->qh_next.qh)
46762306a36Sopenharmony_ci		qh_lines(fotg210, qh, &next, &size);
46862306a36Sopenharmony_ci	if (fotg210->async_unlink && size > 0) {
46962306a36Sopenharmony_ci		temp = scnprintf(next, size, "\nunlink =\n");
47062306a36Sopenharmony_ci		size -= temp;
47162306a36Sopenharmony_ci		next += temp;
47262306a36Sopenharmony_ci
47362306a36Sopenharmony_ci		for (qh = fotg210->async_unlink; size > 0 && qh;
47462306a36Sopenharmony_ci				qh = qh->unlink_next)
47562306a36Sopenharmony_ci			qh_lines(fotg210, qh, &next, &size);
47662306a36Sopenharmony_ci	}
47762306a36Sopenharmony_ci	spin_unlock_irqrestore(&fotg210->lock, flags);
47862306a36Sopenharmony_ci
47962306a36Sopenharmony_ci	return strlen(buf->output_buf);
48062306a36Sopenharmony_ci}
48162306a36Sopenharmony_ci
48262306a36Sopenharmony_ci/* count tds, get ep direction */
48362306a36Sopenharmony_cistatic unsigned output_buf_tds_dir(char *buf, struct fotg210_hcd *fotg210,
48462306a36Sopenharmony_ci		struct fotg210_qh_hw *hw, struct fotg210_qh *qh, unsigned size)
48562306a36Sopenharmony_ci{
48662306a36Sopenharmony_ci	u32 scratch = hc32_to_cpup(fotg210, &hw->hw_info1);
48762306a36Sopenharmony_ci	struct fotg210_qtd *qtd;
48862306a36Sopenharmony_ci	char *type = "";
48962306a36Sopenharmony_ci	unsigned temp = 0;
49062306a36Sopenharmony_ci
49162306a36Sopenharmony_ci	/* count tds, get ep direction */
49262306a36Sopenharmony_ci	list_for_each_entry(qtd, &qh->qtd_list, qtd_list) {
49362306a36Sopenharmony_ci		temp++;
49462306a36Sopenharmony_ci		switch ((hc32_to_cpu(fotg210, qtd->hw_token) >> 8) & 0x03) {
49562306a36Sopenharmony_ci		case 0:
49662306a36Sopenharmony_ci			type = "out";
49762306a36Sopenharmony_ci			continue;
49862306a36Sopenharmony_ci		case 1:
49962306a36Sopenharmony_ci			type = "in";
50062306a36Sopenharmony_ci			continue;
50162306a36Sopenharmony_ci		}
50262306a36Sopenharmony_ci	}
50362306a36Sopenharmony_ci
50462306a36Sopenharmony_ci	return scnprintf(buf, size, "(%c%d ep%d%s [%d/%d] q%d p%d)",
50562306a36Sopenharmony_ci			speed_char(scratch), scratch & 0x007f,
50662306a36Sopenharmony_ci			(scratch >> 8) & 0x000f, type, qh->usecs,
50762306a36Sopenharmony_ci			qh->c_usecs, temp, (scratch >> 16) & 0x7ff);
50862306a36Sopenharmony_ci}
50962306a36Sopenharmony_ci
51062306a36Sopenharmony_ci#define DBG_SCHED_LIMIT 64
51162306a36Sopenharmony_cistatic ssize_t fill_periodic_buffer(struct debug_buffer *buf)
51262306a36Sopenharmony_ci{
51362306a36Sopenharmony_ci	struct usb_hcd *hcd;
51462306a36Sopenharmony_ci	struct fotg210_hcd *fotg210;
51562306a36Sopenharmony_ci	unsigned long flags;
51662306a36Sopenharmony_ci	union fotg210_shadow p, *seen;
51762306a36Sopenharmony_ci	unsigned temp, size, seen_count;
51862306a36Sopenharmony_ci	char *next;
51962306a36Sopenharmony_ci	unsigned i;
52062306a36Sopenharmony_ci	__hc32 tag;
52162306a36Sopenharmony_ci
52262306a36Sopenharmony_ci	seen = kmalloc_array(DBG_SCHED_LIMIT, sizeof(*seen), GFP_ATOMIC);
52362306a36Sopenharmony_ci	if (!seen)
52462306a36Sopenharmony_ci		return 0;
52562306a36Sopenharmony_ci
52662306a36Sopenharmony_ci	seen_count = 0;
52762306a36Sopenharmony_ci
52862306a36Sopenharmony_ci	hcd = bus_to_hcd(buf->bus);
52962306a36Sopenharmony_ci	fotg210 = hcd_to_fotg210(hcd);
53062306a36Sopenharmony_ci	next = buf->output_buf;
53162306a36Sopenharmony_ci	size = buf->alloc_size;
53262306a36Sopenharmony_ci
53362306a36Sopenharmony_ci	temp = scnprintf(next, size, "size = %d\n", fotg210->periodic_size);
53462306a36Sopenharmony_ci	size -= temp;
53562306a36Sopenharmony_ci	next += temp;
53662306a36Sopenharmony_ci
53762306a36Sopenharmony_ci	/* dump a snapshot of the periodic schedule.
53862306a36Sopenharmony_ci	 * iso changes, interrupt usually doesn't.
53962306a36Sopenharmony_ci	 */
54062306a36Sopenharmony_ci	spin_lock_irqsave(&fotg210->lock, flags);
54162306a36Sopenharmony_ci	for (i = 0; i < fotg210->periodic_size; i++) {
54262306a36Sopenharmony_ci		p = fotg210->pshadow[i];
54362306a36Sopenharmony_ci		if (likely(!p.ptr))
54462306a36Sopenharmony_ci			continue;
54562306a36Sopenharmony_ci
54662306a36Sopenharmony_ci		tag = Q_NEXT_TYPE(fotg210, fotg210->periodic[i]);
54762306a36Sopenharmony_ci
54862306a36Sopenharmony_ci		temp = scnprintf(next, size, "%4d: ", i);
54962306a36Sopenharmony_ci		size -= temp;
55062306a36Sopenharmony_ci		next += temp;
55162306a36Sopenharmony_ci
55262306a36Sopenharmony_ci		do {
55362306a36Sopenharmony_ci			struct fotg210_qh_hw *hw;
55462306a36Sopenharmony_ci
55562306a36Sopenharmony_ci			switch (hc32_to_cpu(fotg210, tag)) {
55662306a36Sopenharmony_ci			case Q_TYPE_QH:
55762306a36Sopenharmony_ci				hw = p.qh->hw;
55862306a36Sopenharmony_ci				temp = scnprintf(next, size, " qh%d-%04x/%p",
55962306a36Sopenharmony_ci						p.qh->period,
56062306a36Sopenharmony_ci						hc32_to_cpup(fotg210,
56162306a36Sopenharmony_ci							&hw->hw_info2)
56262306a36Sopenharmony_ci							/* uframe masks */
56362306a36Sopenharmony_ci							& (QH_CMASK | QH_SMASK),
56462306a36Sopenharmony_ci						p.qh);
56562306a36Sopenharmony_ci				size -= temp;
56662306a36Sopenharmony_ci				next += temp;
56762306a36Sopenharmony_ci				/* don't repeat what follows this qh */
56862306a36Sopenharmony_ci				for (temp = 0; temp < seen_count; temp++) {
56962306a36Sopenharmony_ci					if (seen[temp].ptr != p.ptr)
57062306a36Sopenharmony_ci						continue;
57162306a36Sopenharmony_ci					if (p.qh->qh_next.ptr) {
57262306a36Sopenharmony_ci						temp = scnprintf(next, size,
57362306a36Sopenharmony_ci								" ...");
57462306a36Sopenharmony_ci						size -= temp;
57562306a36Sopenharmony_ci						next += temp;
57662306a36Sopenharmony_ci					}
57762306a36Sopenharmony_ci					break;
57862306a36Sopenharmony_ci				}
57962306a36Sopenharmony_ci				/* show more info the first time around */
58062306a36Sopenharmony_ci				if (temp == seen_count) {
58162306a36Sopenharmony_ci					temp = output_buf_tds_dir(next,
58262306a36Sopenharmony_ci							fotg210, hw,
58362306a36Sopenharmony_ci							p.qh, size);
58462306a36Sopenharmony_ci
58562306a36Sopenharmony_ci					if (seen_count < DBG_SCHED_LIMIT)
58662306a36Sopenharmony_ci						seen[seen_count++].qh = p.qh;
58762306a36Sopenharmony_ci				} else
58862306a36Sopenharmony_ci					temp = 0;
58962306a36Sopenharmony_ci				tag = Q_NEXT_TYPE(fotg210, hw->hw_next);
59062306a36Sopenharmony_ci				p = p.qh->qh_next;
59162306a36Sopenharmony_ci				break;
59262306a36Sopenharmony_ci			case Q_TYPE_FSTN:
59362306a36Sopenharmony_ci				temp = scnprintf(next, size,
59462306a36Sopenharmony_ci						" fstn-%8x/%p",
59562306a36Sopenharmony_ci						p.fstn->hw_prev, p.fstn);
59662306a36Sopenharmony_ci				tag = Q_NEXT_TYPE(fotg210, p.fstn->hw_next);
59762306a36Sopenharmony_ci				p = p.fstn->fstn_next;
59862306a36Sopenharmony_ci				break;
59962306a36Sopenharmony_ci			case Q_TYPE_ITD:
60062306a36Sopenharmony_ci				temp = scnprintf(next, size,
60162306a36Sopenharmony_ci						" itd/%p", p.itd);
60262306a36Sopenharmony_ci				tag = Q_NEXT_TYPE(fotg210, p.itd->hw_next);
60362306a36Sopenharmony_ci				p = p.itd->itd_next;
60462306a36Sopenharmony_ci				break;
60562306a36Sopenharmony_ci			}
60662306a36Sopenharmony_ci			size -= temp;
60762306a36Sopenharmony_ci			next += temp;
60862306a36Sopenharmony_ci		} while (p.ptr);
60962306a36Sopenharmony_ci
61062306a36Sopenharmony_ci		temp = scnprintf(next, size, "\n");
61162306a36Sopenharmony_ci		size -= temp;
61262306a36Sopenharmony_ci		next += temp;
61362306a36Sopenharmony_ci	}
61462306a36Sopenharmony_ci	spin_unlock_irqrestore(&fotg210->lock, flags);
61562306a36Sopenharmony_ci	kfree(seen);
61662306a36Sopenharmony_ci
61762306a36Sopenharmony_ci	return buf->alloc_size - size;
61862306a36Sopenharmony_ci}
61962306a36Sopenharmony_ci#undef DBG_SCHED_LIMIT
62062306a36Sopenharmony_ci
62162306a36Sopenharmony_cistatic const char *rh_state_string(struct fotg210_hcd *fotg210)
62262306a36Sopenharmony_ci{
62362306a36Sopenharmony_ci	switch (fotg210->rh_state) {
62462306a36Sopenharmony_ci	case FOTG210_RH_HALTED:
62562306a36Sopenharmony_ci		return "halted";
62662306a36Sopenharmony_ci	case FOTG210_RH_SUSPENDED:
62762306a36Sopenharmony_ci		return "suspended";
62862306a36Sopenharmony_ci	case FOTG210_RH_RUNNING:
62962306a36Sopenharmony_ci		return "running";
63062306a36Sopenharmony_ci	case FOTG210_RH_STOPPING:
63162306a36Sopenharmony_ci		return "stopping";
63262306a36Sopenharmony_ci	}
63362306a36Sopenharmony_ci	return "?";
63462306a36Sopenharmony_ci}
63562306a36Sopenharmony_ci
63662306a36Sopenharmony_cistatic ssize_t fill_registers_buffer(struct debug_buffer *buf)
63762306a36Sopenharmony_ci{
63862306a36Sopenharmony_ci	struct usb_hcd *hcd;
63962306a36Sopenharmony_ci	struct fotg210_hcd *fotg210;
64062306a36Sopenharmony_ci	unsigned long flags;
64162306a36Sopenharmony_ci	unsigned temp, size, i;
64262306a36Sopenharmony_ci	char *next, scratch[80];
64362306a36Sopenharmony_ci	static const char fmt[] = "%*s\n";
64462306a36Sopenharmony_ci	static const char label[] = "";
64562306a36Sopenharmony_ci
64662306a36Sopenharmony_ci	hcd = bus_to_hcd(buf->bus);
64762306a36Sopenharmony_ci	fotg210 = hcd_to_fotg210(hcd);
64862306a36Sopenharmony_ci	next = buf->output_buf;
64962306a36Sopenharmony_ci	size = buf->alloc_size;
65062306a36Sopenharmony_ci
65162306a36Sopenharmony_ci	spin_lock_irqsave(&fotg210->lock, flags);
65262306a36Sopenharmony_ci
65362306a36Sopenharmony_ci	if (!HCD_HW_ACCESSIBLE(hcd)) {
65462306a36Sopenharmony_ci		size = scnprintf(next, size,
65562306a36Sopenharmony_ci				"bus %s, device %s\n"
65662306a36Sopenharmony_ci				"%s\n"
65762306a36Sopenharmony_ci				"SUSPENDED(no register access)\n",
65862306a36Sopenharmony_ci				hcd->self.controller->bus->name,
65962306a36Sopenharmony_ci				dev_name(hcd->self.controller),
66062306a36Sopenharmony_ci				hcd->product_desc);
66162306a36Sopenharmony_ci		goto done;
66262306a36Sopenharmony_ci	}
66362306a36Sopenharmony_ci
66462306a36Sopenharmony_ci	/* Capability Registers */
66562306a36Sopenharmony_ci	i = HC_VERSION(fotg210, fotg210_readl(fotg210,
66662306a36Sopenharmony_ci			&fotg210->caps->hc_capbase));
66762306a36Sopenharmony_ci	temp = scnprintf(next, size,
66862306a36Sopenharmony_ci			"bus %s, device %s\n"
66962306a36Sopenharmony_ci			"%s\n"
67062306a36Sopenharmony_ci			"EHCI %x.%02x, rh state %s\n",
67162306a36Sopenharmony_ci			hcd->self.controller->bus->name,
67262306a36Sopenharmony_ci			dev_name(hcd->self.controller),
67362306a36Sopenharmony_ci			hcd->product_desc,
67462306a36Sopenharmony_ci			i >> 8, i & 0x0ff, rh_state_string(fotg210));
67562306a36Sopenharmony_ci	size -= temp;
67662306a36Sopenharmony_ci	next += temp;
67762306a36Sopenharmony_ci
67862306a36Sopenharmony_ci	/* FIXME interpret both types of params */
67962306a36Sopenharmony_ci	i = fotg210_readl(fotg210, &fotg210->caps->hcs_params);
68062306a36Sopenharmony_ci	temp = scnprintf(next, size, "structural params 0x%08x\n", i);
68162306a36Sopenharmony_ci	size -= temp;
68262306a36Sopenharmony_ci	next += temp;
68362306a36Sopenharmony_ci
68462306a36Sopenharmony_ci	i = fotg210_readl(fotg210, &fotg210->caps->hcc_params);
68562306a36Sopenharmony_ci	temp = scnprintf(next, size, "capability params 0x%08x\n", i);
68662306a36Sopenharmony_ci	size -= temp;
68762306a36Sopenharmony_ci	next += temp;
68862306a36Sopenharmony_ci
68962306a36Sopenharmony_ci	/* Operational Registers */
69062306a36Sopenharmony_ci	temp = dbg_status_buf(scratch, sizeof(scratch), label,
69162306a36Sopenharmony_ci			fotg210_readl(fotg210, &fotg210->regs->status));
69262306a36Sopenharmony_ci	temp = scnprintf(next, size, fmt, temp, scratch);
69362306a36Sopenharmony_ci	size -= temp;
69462306a36Sopenharmony_ci	next += temp;
69562306a36Sopenharmony_ci
69662306a36Sopenharmony_ci	temp = dbg_command_buf(scratch, sizeof(scratch), label,
69762306a36Sopenharmony_ci			fotg210_readl(fotg210, &fotg210->regs->command));
69862306a36Sopenharmony_ci	temp = scnprintf(next, size, fmt, temp, scratch);
69962306a36Sopenharmony_ci	size -= temp;
70062306a36Sopenharmony_ci	next += temp;
70162306a36Sopenharmony_ci
70262306a36Sopenharmony_ci	temp = dbg_intr_buf(scratch, sizeof(scratch), label,
70362306a36Sopenharmony_ci			fotg210_readl(fotg210, &fotg210->regs->intr_enable));
70462306a36Sopenharmony_ci	temp = scnprintf(next, size, fmt, temp, scratch);
70562306a36Sopenharmony_ci	size -= temp;
70662306a36Sopenharmony_ci	next += temp;
70762306a36Sopenharmony_ci
70862306a36Sopenharmony_ci	temp = scnprintf(next, size, "uframe %04x\n",
70962306a36Sopenharmony_ci			fotg210_read_frame_index(fotg210));
71062306a36Sopenharmony_ci	size -= temp;
71162306a36Sopenharmony_ci	next += temp;
71262306a36Sopenharmony_ci
71362306a36Sopenharmony_ci	if (fotg210->async_unlink) {
71462306a36Sopenharmony_ci		temp = scnprintf(next, size, "async unlink qh %p\n",
71562306a36Sopenharmony_ci				fotg210->async_unlink);
71662306a36Sopenharmony_ci		size -= temp;
71762306a36Sopenharmony_ci		next += temp;
71862306a36Sopenharmony_ci	}
71962306a36Sopenharmony_ci
72062306a36Sopenharmony_ci#ifdef FOTG210_STATS
72162306a36Sopenharmony_ci	temp = scnprintf(next, size,
72262306a36Sopenharmony_ci			"irq normal %ld err %ld iaa %ld(lost %ld)\n",
72362306a36Sopenharmony_ci			fotg210->stats.normal, fotg210->stats.error,
72462306a36Sopenharmony_ci			fotg210->stats.iaa, fotg210->stats.lost_iaa);
72562306a36Sopenharmony_ci	size -= temp;
72662306a36Sopenharmony_ci	next += temp;
72762306a36Sopenharmony_ci
72862306a36Sopenharmony_ci	temp = scnprintf(next, size, "complete %ld unlink %ld\n",
72962306a36Sopenharmony_ci			fotg210->stats.complete, fotg210->stats.unlink);
73062306a36Sopenharmony_ci	size -= temp;
73162306a36Sopenharmony_ci	next += temp;
73262306a36Sopenharmony_ci#endif
73362306a36Sopenharmony_ci
73462306a36Sopenharmony_cidone:
73562306a36Sopenharmony_ci	spin_unlock_irqrestore(&fotg210->lock, flags);
73662306a36Sopenharmony_ci
73762306a36Sopenharmony_ci	return buf->alloc_size - size;
73862306a36Sopenharmony_ci}
73962306a36Sopenharmony_ci
74062306a36Sopenharmony_cistatic struct debug_buffer
74162306a36Sopenharmony_ci*alloc_buffer(struct usb_bus *bus, ssize_t (*fill_func)(struct debug_buffer *))
74262306a36Sopenharmony_ci{
74362306a36Sopenharmony_ci	struct debug_buffer *buf;
74462306a36Sopenharmony_ci
74562306a36Sopenharmony_ci	buf = kzalloc(sizeof(struct debug_buffer), GFP_KERNEL);
74662306a36Sopenharmony_ci
74762306a36Sopenharmony_ci	if (buf) {
74862306a36Sopenharmony_ci		buf->bus = bus;
74962306a36Sopenharmony_ci		buf->fill_func = fill_func;
75062306a36Sopenharmony_ci		mutex_init(&buf->mutex);
75162306a36Sopenharmony_ci		buf->alloc_size = PAGE_SIZE;
75262306a36Sopenharmony_ci	}
75362306a36Sopenharmony_ci
75462306a36Sopenharmony_ci	return buf;
75562306a36Sopenharmony_ci}
75662306a36Sopenharmony_ci
75762306a36Sopenharmony_cistatic int fill_buffer(struct debug_buffer *buf)
75862306a36Sopenharmony_ci{
75962306a36Sopenharmony_ci	int ret = 0;
76062306a36Sopenharmony_ci
76162306a36Sopenharmony_ci	if (!buf->output_buf)
76262306a36Sopenharmony_ci		buf->output_buf = vmalloc(buf->alloc_size);
76362306a36Sopenharmony_ci
76462306a36Sopenharmony_ci	if (!buf->output_buf) {
76562306a36Sopenharmony_ci		ret = -ENOMEM;
76662306a36Sopenharmony_ci		goto out;
76762306a36Sopenharmony_ci	}
76862306a36Sopenharmony_ci
76962306a36Sopenharmony_ci	ret = buf->fill_func(buf);
77062306a36Sopenharmony_ci
77162306a36Sopenharmony_ci	if (ret >= 0) {
77262306a36Sopenharmony_ci		buf->count = ret;
77362306a36Sopenharmony_ci		ret = 0;
77462306a36Sopenharmony_ci	}
77562306a36Sopenharmony_ci
77662306a36Sopenharmony_ciout:
77762306a36Sopenharmony_ci	return ret;
77862306a36Sopenharmony_ci}
77962306a36Sopenharmony_ci
78062306a36Sopenharmony_cistatic ssize_t debug_output(struct file *file, char __user *user_buf,
78162306a36Sopenharmony_ci		size_t len, loff_t *offset)
78262306a36Sopenharmony_ci{
78362306a36Sopenharmony_ci	struct debug_buffer *buf = file->private_data;
78462306a36Sopenharmony_ci	int ret = 0;
78562306a36Sopenharmony_ci
78662306a36Sopenharmony_ci	mutex_lock(&buf->mutex);
78762306a36Sopenharmony_ci	if (buf->count == 0) {
78862306a36Sopenharmony_ci		ret = fill_buffer(buf);
78962306a36Sopenharmony_ci		if (ret != 0) {
79062306a36Sopenharmony_ci			mutex_unlock(&buf->mutex);
79162306a36Sopenharmony_ci			goto out;
79262306a36Sopenharmony_ci		}
79362306a36Sopenharmony_ci	}
79462306a36Sopenharmony_ci	mutex_unlock(&buf->mutex);
79562306a36Sopenharmony_ci
79662306a36Sopenharmony_ci	ret = simple_read_from_buffer(user_buf, len, offset,
79762306a36Sopenharmony_ci			buf->output_buf, buf->count);
79862306a36Sopenharmony_ci
79962306a36Sopenharmony_ciout:
80062306a36Sopenharmony_ci	return ret;
80162306a36Sopenharmony_ci
80262306a36Sopenharmony_ci}
80362306a36Sopenharmony_ci
80462306a36Sopenharmony_cistatic int debug_close(struct inode *inode, struct file *file)
80562306a36Sopenharmony_ci{
80662306a36Sopenharmony_ci	struct debug_buffer *buf = file->private_data;
80762306a36Sopenharmony_ci
80862306a36Sopenharmony_ci	if (buf) {
80962306a36Sopenharmony_ci		vfree(buf->output_buf);
81062306a36Sopenharmony_ci		kfree(buf);
81162306a36Sopenharmony_ci	}
81262306a36Sopenharmony_ci
81362306a36Sopenharmony_ci	return 0;
81462306a36Sopenharmony_ci}
81562306a36Sopenharmony_cistatic int debug_async_open(struct inode *inode, struct file *file)
81662306a36Sopenharmony_ci{
81762306a36Sopenharmony_ci	file->private_data = alloc_buffer(inode->i_private, fill_async_buffer);
81862306a36Sopenharmony_ci
81962306a36Sopenharmony_ci	return file->private_data ? 0 : -ENOMEM;
82062306a36Sopenharmony_ci}
82162306a36Sopenharmony_ci
82262306a36Sopenharmony_cistatic int debug_periodic_open(struct inode *inode, struct file *file)
82362306a36Sopenharmony_ci{
82462306a36Sopenharmony_ci	struct debug_buffer *buf;
82562306a36Sopenharmony_ci
82662306a36Sopenharmony_ci	buf = alloc_buffer(inode->i_private, fill_periodic_buffer);
82762306a36Sopenharmony_ci	if (!buf)
82862306a36Sopenharmony_ci		return -ENOMEM;
82962306a36Sopenharmony_ci
83062306a36Sopenharmony_ci	buf->alloc_size = (sizeof(void *) == 4 ? 6 : 8)*PAGE_SIZE;
83162306a36Sopenharmony_ci	file->private_data = buf;
83262306a36Sopenharmony_ci	return 0;
83362306a36Sopenharmony_ci}
83462306a36Sopenharmony_ci
83562306a36Sopenharmony_cistatic int debug_registers_open(struct inode *inode, struct file *file)
83662306a36Sopenharmony_ci{
83762306a36Sopenharmony_ci	file->private_data = alloc_buffer(inode->i_private,
83862306a36Sopenharmony_ci			fill_registers_buffer);
83962306a36Sopenharmony_ci
84062306a36Sopenharmony_ci	return file->private_data ? 0 : -ENOMEM;
84162306a36Sopenharmony_ci}
84262306a36Sopenharmony_ci
84362306a36Sopenharmony_cistatic inline void create_debug_files(struct fotg210_hcd *fotg210)
84462306a36Sopenharmony_ci{
84562306a36Sopenharmony_ci	struct usb_bus *bus = &fotg210_to_hcd(fotg210)->self;
84662306a36Sopenharmony_ci	struct dentry *root;
84762306a36Sopenharmony_ci
84862306a36Sopenharmony_ci	root = debugfs_create_dir(bus->bus_name, fotg210_debug_root);
84962306a36Sopenharmony_ci
85062306a36Sopenharmony_ci	debugfs_create_file("async", S_IRUGO, root, bus, &debug_async_fops);
85162306a36Sopenharmony_ci	debugfs_create_file("periodic", S_IRUGO, root, bus,
85262306a36Sopenharmony_ci			    &debug_periodic_fops);
85362306a36Sopenharmony_ci	debugfs_create_file("registers", S_IRUGO, root, bus,
85462306a36Sopenharmony_ci			    &debug_registers_fops);
85562306a36Sopenharmony_ci}
85662306a36Sopenharmony_ci
85762306a36Sopenharmony_cistatic inline void remove_debug_files(struct fotg210_hcd *fotg210)
85862306a36Sopenharmony_ci{
85962306a36Sopenharmony_ci	struct usb_bus *bus = &fotg210_to_hcd(fotg210)->self;
86062306a36Sopenharmony_ci
86162306a36Sopenharmony_ci	debugfs_lookup_and_remove(bus->bus_name, fotg210_debug_root);
86262306a36Sopenharmony_ci}
86362306a36Sopenharmony_ci
86462306a36Sopenharmony_ci/* handshake - spin reading hc until handshake completes or fails
86562306a36Sopenharmony_ci * @ptr: address of hc register to be read
86662306a36Sopenharmony_ci * @mask: bits to look at in result of read
86762306a36Sopenharmony_ci * @done: value of those bits when handshake succeeds
86862306a36Sopenharmony_ci * @usec: timeout in microseconds
86962306a36Sopenharmony_ci *
87062306a36Sopenharmony_ci * Returns negative errno, or zero on success
87162306a36Sopenharmony_ci *
87262306a36Sopenharmony_ci * Success happens when the "mask" bits have the specified value (hardware
87362306a36Sopenharmony_ci * handshake done).  There are two failure modes:  "usec" have passed (major
87462306a36Sopenharmony_ci * hardware flakeout), or the register reads as all-ones (hardware removed).
87562306a36Sopenharmony_ci *
87662306a36Sopenharmony_ci * That last failure should_only happen in cases like physical cardbus eject
87762306a36Sopenharmony_ci * before driver shutdown. But it also seems to be caused by bugs in cardbus
87862306a36Sopenharmony_ci * bridge shutdown:  shutting down the bridge before the devices using it.
87962306a36Sopenharmony_ci */
88062306a36Sopenharmony_cistatic int handshake(struct fotg210_hcd *fotg210, void __iomem *ptr,
88162306a36Sopenharmony_ci		u32 mask, u32 done, int usec)
88262306a36Sopenharmony_ci{
88362306a36Sopenharmony_ci	u32 result;
88462306a36Sopenharmony_ci	int ret;
88562306a36Sopenharmony_ci
88662306a36Sopenharmony_ci	ret = readl_poll_timeout_atomic(ptr, result,
88762306a36Sopenharmony_ci					((result & mask) == done ||
88862306a36Sopenharmony_ci					 result == U32_MAX), 1, usec);
88962306a36Sopenharmony_ci	if (result == U32_MAX)		/* card removed */
89062306a36Sopenharmony_ci		return -ENODEV;
89162306a36Sopenharmony_ci
89262306a36Sopenharmony_ci	return ret;
89362306a36Sopenharmony_ci}
89462306a36Sopenharmony_ci
89562306a36Sopenharmony_ci/* Force HC to halt state from unknown (EHCI spec section 2.3).
89662306a36Sopenharmony_ci * Must be called with interrupts enabled and the lock not held.
89762306a36Sopenharmony_ci */
89862306a36Sopenharmony_cistatic int fotg210_halt(struct fotg210_hcd *fotg210)
89962306a36Sopenharmony_ci{
90062306a36Sopenharmony_ci	u32 temp;
90162306a36Sopenharmony_ci
90262306a36Sopenharmony_ci	spin_lock_irq(&fotg210->lock);
90362306a36Sopenharmony_ci
90462306a36Sopenharmony_ci	/* disable any irqs left enabled by previous code */
90562306a36Sopenharmony_ci	fotg210_writel(fotg210, 0, &fotg210->regs->intr_enable);
90662306a36Sopenharmony_ci
90762306a36Sopenharmony_ci	/*
90862306a36Sopenharmony_ci	 * This routine gets called during probe before fotg210->command
90962306a36Sopenharmony_ci	 * has been initialized, so we can't rely on its value.
91062306a36Sopenharmony_ci	 */
91162306a36Sopenharmony_ci	fotg210->command &= ~CMD_RUN;
91262306a36Sopenharmony_ci	temp = fotg210_readl(fotg210, &fotg210->regs->command);
91362306a36Sopenharmony_ci	temp &= ~(CMD_RUN | CMD_IAAD);
91462306a36Sopenharmony_ci	fotg210_writel(fotg210, temp, &fotg210->regs->command);
91562306a36Sopenharmony_ci
91662306a36Sopenharmony_ci	spin_unlock_irq(&fotg210->lock);
91762306a36Sopenharmony_ci	synchronize_irq(fotg210_to_hcd(fotg210)->irq);
91862306a36Sopenharmony_ci
91962306a36Sopenharmony_ci	return handshake(fotg210, &fotg210->regs->status,
92062306a36Sopenharmony_ci			STS_HALT, STS_HALT, 16 * 125);
92162306a36Sopenharmony_ci}
92262306a36Sopenharmony_ci
92362306a36Sopenharmony_ci/* Reset a non-running (STS_HALT == 1) controller.
92462306a36Sopenharmony_ci * Must be called with interrupts enabled and the lock not held.
92562306a36Sopenharmony_ci */
92662306a36Sopenharmony_cistatic int fotg210_reset(struct fotg210_hcd *fotg210)
92762306a36Sopenharmony_ci{
92862306a36Sopenharmony_ci	int retval;
92962306a36Sopenharmony_ci	u32 command = fotg210_readl(fotg210, &fotg210->regs->command);
93062306a36Sopenharmony_ci
93162306a36Sopenharmony_ci	/* If the EHCI debug controller is active, special care must be
93262306a36Sopenharmony_ci	 * taken before and after a host controller reset
93362306a36Sopenharmony_ci	 */
93462306a36Sopenharmony_ci	if (fotg210->debug && !dbgp_reset_prep(fotg210_to_hcd(fotg210)))
93562306a36Sopenharmony_ci		fotg210->debug = NULL;
93662306a36Sopenharmony_ci
93762306a36Sopenharmony_ci	command |= CMD_RESET;
93862306a36Sopenharmony_ci	dbg_cmd(fotg210, "reset", command);
93962306a36Sopenharmony_ci	fotg210_writel(fotg210, command, &fotg210->regs->command);
94062306a36Sopenharmony_ci	fotg210->rh_state = FOTG210_RH_HALTED;
94162306a36Sopenharmony_ci	fotg210->next_statechange = jiffies;
94262306a36Sopenharmony_ci	retval = handshake(fotg210, &fotg210->regs->command,
94362306a36Sopenharmony_ci			CMD_RESET, 0, 250 * 1000);
94462306a36Sopenharmony_ci
94562306a36Sopenharmony_ci	if (retval)
94662306a36Sopenharmony_ci		return retval;
94762306a36Sopenharmony_ci
94862306a36Sopenharmony_ci	if (fotg210->debug)
94962306a36Sopenharmony_ci		dbgp_external_startup(fotg210_to_hcd(fotg210));
95062306a36Sopenharmony_ci
95162306a36Sopenharmony_ci	fotg210->port_c_suspend = fotg210->suspended_ports =
95262306a36Sopenharmony_ci			fotg210->resuming_ports = 0;
95362306a36Sopenharmony_ci	return retval;
95462306a36Sopenharmony_ci}
95562306a36Sopenharmony_ci
95662306a36Sopenharmony_ci/* Idle the controller (turn off the schedules).
95762306a36Sopenharmony_ci * Must be called with interrupts enabled and the lock not held.
95862306a36Sopenharmony_ci */
95962306a36Sopenharmony_cistatic void fotg210_quiesce(struct fotg210_hcd *fotg210)
96062306a36Sopenharmony_ci{
96162306a36Sopenharmony_ci	u32 temp;
96262306a36Sopenharmony_ci
96362306a36Sopenharmony_ci	if (fotg210->rh_state != FOTG210_RH_RUNNING)
96462306a36Sopenharmony_ci		return;
96562306a36Sopenharmony_ci
96662306a36Sopenharmony_ci	/* wait for any schedule enables/disables to take effect */
96762306a36Sopenharmony_ci	temp = (fotg210->command << 10) & (STS_ASS | STS_PSS);
96862306a36Sopenharmony_ci	handshake(fotg210, &fotg210->regs->status, STS_ASS | STS_PSS, temp,
96962306a36Sopenharmony_ci			16 * 125);
97062306a36Sopenharmony_ci
97162306a36Sopenharmony_ci	/* then disable anything that's still active */
97262306a36Sopenharmony_ci	spin_lock_irq(&fotg210->lock);
97362306a36Sopenharmony_ci	fotg210->command &= ~(CMD_ASE | CMD_PSE);
97462306a36Sopenharmony_ci	fotg210_writel(fotg210, fotg210->command, &fotg210->regs->command);
97562306a36Sopenharmony_ci	spin_unlock_irq(&fotg210->lock);
97662306a36Sopenharmony_ci
97762306a36Sopenharmony_ci	/* hardware can take 16 microframes to turn off ... */
97862306a36Sopenharmony_ci	handshake(fotg210, &fotg210->regs->status, STS_ASS | STS_PSS, 0,
97962306a36Sopenharmony_ci			16 * 125);
98062306a36Sopenharmony_ci}
98162306a36Sopenharmony_ci
98262306a36Sopenharmony_cistatic void end_unlink_async(struct fotg210_hcd *fotg210);
98362306a36Sopenharmony_cistatic void unlink_empty_async(struct fotg210_hcd *fotg210);
98462306a36Sopenharmony_cistatic void fotg210_work(struct fotg210_hcd *fotg210);
98562306a36Sopenharmony_cistatic void start_unlink_intr(struct fotg210_hcd *fotg210,
98662306a36Sopenharmony_ci			      struct fotg210_qh *qh);
98762306a36Sopenharmony_cistatic void end_unlink_intr(struct fotg210_hcd *fotg210, struct fotg210_qh *qh);
98862306a36Sopenharmony_ci
98962306a36Sopenharmony_ci/* Set a bit in the USBCMD register */
99062306a36Sopenharmony_cistatic void fotg210_set_command_bit(struct fotg210_hcd *fotg210, u32 bit)
99162306a36Sopenharmony_ci{
99262306a36Sopenharmony_ci	fotg210->command |= bit;
99362306a36Sopenharmony_ci	fotg210_writel(fotg210, fotg210->command, &fotg210->regs->command);
99462306a36Sopenharmony_ci
99562306a36Sopenharmony_ci	/* unblock posted write */
99662306a36Sopenharmony_ci	fotg210_readl(fotg210, &fotg210->regs->command);
99762306a36Sopenharmony_ci}
99862306a36Sopenharmony_ci
99962306a36Sopenharmony_ci/* Clear a bit in the USBCMD register */
100062306a36Sopenharmony_cistatic void fotg210_clear_command_bit(struct fotg210_hcd *fotg210, u32 bit)
100162306a36Sopenharmony_ci{
100262306a36Sopenharmony_ci	fotg210->command &= ~bit;
100362306a36Sopenharmony_ci	fotg210_writel(fotg210, fotg210->command, &fotg210->regs->command);
100462306a36Sopenharmony_ci
100562306a36Sopenharmony_ci	/* unblock posted write */
100662306a36Sopenharmony_ci	fotg210_readl(fotg210, &fotg210->regs->command);
100762306a36Sopenharmony_ci}
100862306a36Sopenharmony_ci
100962306a36Sopenharmony_ci/* EHCI timer support...  Now using hrtimers.
101062306a36Sopenharmony_ci *
101162306a36Sopenharmony_ci * Lots of different events are triggered from fotg210->hrtimer.  Whenever
101262306a36Sopenharmony_ci * the timer routine runs, it checks each possible event; events that are
101362306a36Sopenharmony_ci * currently enabled and whose expiration time has passed get handled.
101462306a36Sopenharmony_ci * The set of enabled events is stored as a collection of bitflags in
101562306a36Sopenharmony_ci * fotg210->enabled_hrtimer_events, and they are numbered in order of
101662306a36Sopenharmony_ci * increasing delay values (ranging between 1 ms and 100 ms).
101762306a36Sopenharmony_ci *
101862306a36Sopenharmony_ci * Rather than implementing a sorted list or tree of all pending events,
101962306a36Sopenharmony_ci * we keep track only of the lowest-numbered pending event, in
102062306a36Sopenharmony_ci * fotg210->next_hrtimer_event.  Whenever fotg210->hrtimer gets restarted, its
102162306a36Sopenharmony_ci * expiration time is set to the timeout value for this event.
102262306a36Sopenharmony_ci *
102362306a36Sopenharmony_ci * As a result, events might not get handled right away; the actual delay
102462306a36Sopenharmony_ci * could be anywhere up to twice the requested delay.  This doesn't
102562306a36Sopenharmony_ci * matter, because none of the events are especially time-critical.  The
102662306a36Sopenharmony_ci * ones that matter most all have a delay of 1 ms, so they will be
102762306a36Sopenharmony_ci * handled after 2 ms at most, which is okay.  In addition to this, we
102862306a36Sopenharmony_ci * allow for an expiration range of 1 ms.
102962306a36Sopenharmony_ci */
103062306a36Sopenharmony_ci
103162306a36Sopenharmony_ci/* Delay lengths for the hrtimer event types.
103262306a36Sopenharmony_ci * Keep this list sorted by delay length, in the same order as
103362306a36Sopenharmony_ci * the event types indexed by enum fotg210_hrtimer_event in fotg210.h.
103462306a36Sopenharmony_ci */
103562306a36Sopenharmony_cistatic unsigned event_delays_ns[] = {
103662306a36Sopenharmony_ci	1 * NSEC_PER_MSEC,	/* FOTG210_HRTIMER_POLL_ASS */
103762306a36Sopenharmony_ci	1 * NSEC_PER_MSEC,	/* FOTG210_HRTIMER_POLL_PSS */
103862306a36Sopenharmony_ci	1 * NSEC_PER_MSEC,	/* FOTG210_HRTIMER_POLL_DEAD */
103962306a36Sopenharmony_ci	1125 * NSEC_PER_USEC,	/* FOTG210_HRTIMER_UNLINK_INTR */
104062306a36Sopenharmony_ci	2 * NSEC_PER_MSEC,	/* FOTG210_HRTIMER_FREE_ITDS */
104162306a36Sopenharmony_ci	6 * NSEC_PER_MSEC,	/* FOTG210_HRTIMER_ASYNC_UNLINKS */
104262306a36Sopenharmony_ci	10 * NSEC_PER_MSEC,	/* FOTG210_HRTIMER_IAA_WATCHDOG */
104362306a36Sopenharmony_ci	10 * NSEC_PER_MSEC,	/* FOTG210_HRTIMER_DISABLE_PERIODIC */
104462306a36Sopenharmony_ci	15 * NSEC_PER_MSEC,	/* FOTG210_HRTIMER_DISABLE_ASYNC */
104562306a36Sopenharmony_ci	100 * NSEC_PER_MSEC,	/* FOTG210_HRTIMER_IO_WATCHDOG */
104662306a36Sopenharmony_ci};
104762306a36Sopenharmony_ci
104862306a36Sopenharmony_ci/* Enable a pending hrtimer event */
104962306a36Sopenharmony_cistatic void fotg210_enable_event(struct fotg210_hcd *fotg210, unsigned event,
105062306a36Sopenharmony_ci		bool resched)
105162306a36Sopenharmony_ci{
105262306a36Sopenharmony_ci	ktime_t *timeout = &fotg210->hr_timeouts[event];
105362306a36Sopenharmony_ci
105462306a36Sopenharmony_ci	if (resched)
105562306a36Sopenharmony_ci		*timeout = ktime_add(ktime_get(), event_delays_ns[event]);
105662306a36Sopenharmony_ci	fotg210->enabled_hrtimer_events |= (1 << event);
105762306a36Sopenharmony_ci
105862306a36Sopenharmony_ci	/* Track only the lowest-numbered pending event */
105962306a36Sopenharmony_ci	if (event < fotg210->next_hrtimer_event) {
106062306a36Sopenharmony_ci		fotg210->next_hrtimer_event = event;
106162306a36Sopenharmony_ci		hrtimer_start_range_ns(&fotg210->hrtimer, *timeout,
106262306a36Sopenharmony_ci				NSEC_PER_MSEC, HRTIMER_MODE_ABS);
106362306a36Sopenharmony_ci	}
106462306a36Sopenharmony_ci}
106562306a36Sopenharmony_ci
106662306a36Sopenharmony_ci
106762306a36Sopenharmony_ci/* Poll the STS_ASS status bit; see when it agrees with CMD_ASE */
106862306a36Sopenharmony_cistatic void fotg210_poll_ASS(struct fotg210_hcd *fotg210)
106962306a36Sopenharmony_ci{
107062306a36Sopenharmony_ci	unsigned actual, want;
107162306a36Sopenharmony_ci
107262306a36Sopenharmony_ci	/* Don't enable anything if the controller isn't running (e.g., died) */
107362306a36Sopenharmony_ci	if (fotg210->rh_state != FOTG210_RH_RUNNING)
107462306a36Sopenharmony_ci		return;
107562306a36Sopenharmony_ci
107662306a36Sopenharmony_ci	want = (fotg210->command & CMD_ASE) ? STS_ASS : 0;
107762306a36Sopenharmony_ci	actual = fotg210_readl(fotg210, &fotg210->regs->status) & STS_ASS;
107862306a36Sopenharmony_ci
107962306a36Sopenharmony_ci	if (want != actual) {
108062306a36Sopenharmony_ci
108162306a36Sopenharmony_ci		/* Poll again later, but give up after about 20 ms */
108262306a36Sopenharmony_ci		if (fotg210->ASS_poll_count++ < 20) {
108362306a36Sopenharmony_ci			fotg210_enable_event(fotg210, FOTG210_HRTIMER_POLL_ASS,
108462306a36Sopenharmony_ci					true);
108562306a36Sopenharmony_ci			return;
108662306a36Sopenharmony_ci		}
108762306a36Sopenharmony_ci		fotg210_dbg(fotg210, "Waited too long for the async schedule status (%x/%x), giving up\n",
108862306a36Sopenharmony_ci				want, actual);
108962306a36Sopenharmony_ci	}
109062306a36Sopenharmony_ci	fotg210->ASS_poll_count = 0;
109162306a36Sopenharmony_ci
109262306a36Sopenharmony_ci	/* The status is up-to-date; restart or stop the schedule as needed */
109362306a36Sopenharmony_ci	if (want == 0) {	/* Stopped */
109462306a36Sopenharmony_ci		if (fotg210->async_count > 0)
109562306a36Sopenharmony_ci			fotg210_set_command_bit(fotg210, CMD_ASE);
109662306a36Sopenharmony_ci
109762306a36Sopenharmony_ci	} else {		/* Running */
109862306a36Sopenharmony_ci		if (fotg210->async_count == 0) {
109962306a36Sopenharmony_ci
110062306a36Sopenharmony_ci			/* Turn off the schedule after a while */
110162306a36Sopenharmony_ci			fotg210_enable_event(fotg210,
110262306a36Sopenharmony_ci					FOTG210_HRTIMER_DISABLE_ASYNC,
110362306a36Sopenharmony_ci					true);
110462306a36Sopenharmony_ci		}
110562306a36Sopenharmony_ci	}
110662306a36Sopenharmony_ci}
110762306a36Sopenharmony_ci
110862306a36Sopenharmony_ci/* Turn off the async schedule after a brief delay */
110962306a36Sopenharmony_cistatic void fotg210_disable_ASE(struct fotg210_hcd *fotg210)
111062306a36Sopenharmony_ci{
111162306a36Sopenharmony_ci	fotg210_clear_command_bit(fotg210, CMD_ASE);
111262306a36Sopenharmony_ci}
111362306a36Sopenharmony_ci
111462306a36Sopenharmony_ci
111562306a36Sopenharmony_ci/* Poll the STS_PSS status bit; see when it agrees with CMD_PSE */
111662306a36Sopenharmony_cistatic void fotg210_poll_PSS(struct fotg210_hcd *fotg210)
111762306a36Sopenharmony_ci{
111862306a36Sopenharmony_ci	unsigned actual, want;
111962306a36Sopenharmony_ci
112062306a36Sopenharmony_ci	/* Don't do anything if the controller isn't running (e.g., died) */
112162306a36Sopenharmony_ci	if (fotg210->rh_state != FOTG210_RH_RUNNING)
112262306a36Sopenharmony_ci		return;
112362306a36Sopenharmony_ci
112462306a36Sopenharmony_ci	want = (fotg210->command & CMD_PSE) ? STS_PSS : 0;
112562306a36Sopenharmony_ci	actual = fotg210_readl(fotg210, &fotg210->regs->status) & STS_PSS;
112662306a36Sopenharmony_ci
112762306a36Sopenharmony_ci	if (want != actual) {
112862306a36Sopenharmony_ci
112962306a36Sopenharmony_ci		/* Poll again later, but give up after about 20 ms */
113062306a36Sopenharmony_ci		if (fotg210->PSS_poll_count++ < 20) {
113162306a36Sopenharmony_ci			fotg210_enable_event(fotg210, FOTG210_HRTIMER_POLL_PSS,
113262306a36Sopenharmony_ci					true);
113362306a36Sopenharmony_ci			return;
113462306a36Sopenharmony_ci		}
113562306a36Sopenharmony_ci		fotg210_dbg(fotg210, "Waited too long for the periodic schedule status (%x/%x), giving up\n",
113662306a36Sopenharmony_ci				want, actual);
113762306a36Sopenharmony_ci	}
113862306a36Sopenharmony_ci	fotg210->PSS_poll_count = 0;
113962306a36Sopenharmony_ci
114062306a36Sopenharmony_ci	/* The status is up-to-date; restart or stop the schedule as needed */
114162306a36Sopenharmony_ci	if (want == 0) {	/* Stopped */
114262306a36Sopenharmony_ci		if (fotg210->periodic_count > 0)
114362306a36Sopenharmony_ci			fotg210_set_command_bit(fotg210, CMD_PSE);
114462306a36Sopenharmony_ci
114562306a36Sopenharmony_ci	} else {		/* Running */
114662306a36Sopenharmony_ci		if (fotg210->periodic_count == 0) {
114762306a36Sopenharmony_ci
114862306a36Sopenharmony_ci			/* Turn off the schedule after a while */
114962306a36Sopenharmony_ci			fotg210_enable_event(fotg210,
115062306a36Sopenharmony_ci					FOTG210_HRTIMER_DISABLE_PERIODIC,
115162306a36Sopenharmony_ci					true);
115262306a36Sopenharmony_ci		}
115362306a36Sopenharmony_ci	}
115462306a36Sopenharmony_ci}
115562306a36Sopenharmony_ci
115662306a36Sopenharmony_ci/* Turn off the periodic schedule after a brief delay */
115762306a36Sopenharmony_cistatic void fotg210_disable_PSE(struct fotg210_hcd *fotg210)
115862306a36Sopenharmony_ci{
115962306a36Sopenharmony_ci	fotg210_clear_command_bit(fotg210, CMD_PSE);
116062306a36Sopenharmony_ci}
116162306a36Sopenharmony_ci
116262306a36Sopenharmony_ci
116362306a36Sopenharmony_ci/* Poll the STS_HALT status bit; see when a dead controller stops */
116462306a36Sopenharmony_cistatic void fotg210_handle_controller_death(struct fotg210_hcd *fotg210)
116562306a36Sopenharmony_ci{
116662306a36Sopenharmony_ci	if (!(fotg210_readl(fotg210, &fotg210->regs->status) & STS_HALT)) {
116762306a36Sopenharmony_ci
116862306a36Sopenharmony_ci		/* Give up after a few milliseconds */
116962306a36Sopenharmony_ci		if (fotg210->died_poll_count++ < 5) {
117062306a36Sopenharmony_ci			/* Try again later */
117162306a36Sopenharmony_ci			fotg210_enable_event(fotg210,
117262306a36Sopenharmony_ci					FOTG210_HRTIMER_POLL_DEAD, true);
117362306a36Sopenharmony_ci			return;
117462306a36Sopenharmony_ci		}
117562306a36Sopenharmony_ci		fotg210_warn(fotg210, "Waited too long for the controller to stop, giving up\n");
117662306a36Sopenharmony_ci	}
117762306a36Sopenharmony_ci
117862306a36Sopenharmony_ci	/* Clean up the mess */
117962306a36Sopenharmony_ci	fotg210->rh_state = FOTG210_RH_HALTED;
118062306a36Sopenharmony_ci	fotg210_writel(fotg210, 0, &fotg210->regs->intr_enable);
118162306a36Sopenharmony_ci	fotg210_work(fotg210);
118262306a36Sopenharmony_ci	end_unlink_async(fotg210);
118362306a36Sopenharmony_ci
118462306a36Sopenharmony_ci	/* Not in process context, so don't try to reset the controller */
118562306a36Sopenharmony_ci}
118662306a36Sopenharmony_ci
118762306a36Sopenharmony_ci
118862306a36Sopenharmony_ci/* Handle unlinked interrupt QHs once they are gone from the hardware */
118962306a36Sopenharmony_cistatic void fotg210_handle_intr_unlinks(struct fotg210_hcd *fotg210)
119062306a36Sopenharmony_ci{
119162306a36Sopenharmony_ci	bool stopped = (fotg210->rh_state < FOTG210_RH_RUNNING);
119262306a36Sopenharmony_ci
119362306a36Sopenharmony_ci	/*
119462306a36Sopenharmony_ci	 * Process all the QHs on the intr_unlink list that were added
119562306a36Sopenharmony_ci	 * before the current unlink cycle began.  The list is in
119662306a36Sopenharmony_ci	 * temporal order, so stop when we reach the first entry in the
119762306a36Sopenharmony_ci	 * current cycle.  But if the root hub isn't running then
119862306a36Sopenharmony_ci	 * process all the QHs on the list.
119962306a36Sopenharmony_ci	 */
120062306a36Sopenharmony_ci	fotg210->intr_unlinking = true;
120162306a36Sopenharmony_ci	while (fotg210->intr_unlink) {
120262306a36Sopenharmony_ci		struct fotg210_qh *qh = fotg210->intr_unlink;
120362306a36Sopenharmony_ci
120462306a36Sopenharmony_ci		if (!stopped && qh->unlink_cycle == fotg210->intr_unlink_cycle)
120562306a36Sopenharmony_ci			break;
120662306a36Sopenharmony_ci		fotg210->intr_unlink = qh->unlink_next;
120762306a36Sopenharmony_ci		qh->unlink_next = NULL;
120862306a36Sopenharmony_ci		end_unlink_intr(fotg210, qh);
120962306a36Sopenharmony_ci	}
121062306a36Sopenharmony_ci
121162306a36Sopenharmony_ci	/* Handle remaining entries later */
121262306a36Sopenharmony_ci	if (fotg210->intr_unlink) {
121362306a36Sopenharmony_ci		fotg210_enable_event(fotg210, FOTG210_HRTIMER_UNLINK_INTR,
121462306a36Sopenharmony_ci				true);
121562306a36Sopenharmony_ci		++fotg210->intr_unlink_cycle;
121662306a36Sopenharmony_ci	}
121762306a36Sopenharmony_ci	fotg210->intr_unlinking = false;
121862306a36Sopenharmony_ci}
121962306a36Sopenharmony_ci
122062306a36Sopenharmony_ci
122162306a36Sopenharmony_ci/* Start another free-iTDs/siTDs cycle */
122262306a36Sopenharmony_cistatic void start_free_itds(struct fotg210_hcd *fotg210)
122362306a36Sopenharmony_ci{
122462306a36Sopenharmony_ci	if (!(fotg210->enabled_hrtimer_events &
122562306a36Sopenharmony_ci			BIT(FOTG210_HRTIMER_FREE_ITDS))) {
122662306a36Sopenharmony_ci		fotg210->last_itd_to_free = list_entry(
122762306a36Sopenharmony_ci				fotg210->cached_itd_list.prev,
122862306a36Sopenharmony_ci				struct fotg210_itd, itd_list);
122962306a36Sopenharmony_ci		fotg210_enable_event(fotg210, FOTG210_HRTIMER_FREE_ITDS, true);
123062306a36Sopenharmony_ci	}
123162306a36Sopenharmony_ci}
123262306a36Sopenharmony_ci
123362306a36Sopenharmony_ci/* Wait for controller to stop using old iTDs and siTDs */
123462306a36Sopenharmony_cistatic void end_free_itds(struct fotg210_hcd *fotg210)
123562306a36Sopenharmony_ci{
123662306a36Sopenharmony_ci	struct fotg210_itd *itd, *n;
123762306a36Sopenharmony_ci
123862306a36Sopenharmony_ci	if (fotg210->rh_state < FOTG210_RH_RUNNING)
123962306a36Sopenharmony_ci		fotg210->last_itd_to_free = NULL;
124062306a36Sopenharmony_ci
124162306a36Sopenharmony_ci	list_for_each_entry_safe(itd, n, &fotg210->cached_itd_list, itd_list) {
124262306a36Sopenharmony_ci		list_del(&itd->itd_list);
124362306a36Sopenharmony_ci		dma_pool_free(fotg210->itd_pool, itd, itd->itd_dma);
124462306a36Sopenharmony_ci		if (itd == fotg210->last_itd_to_free)
124562306a36Sopenharmony_ci			break;
124662306a36Sopenharmony_ci	}
124762306a36Sopenharmony_ci
124862306a36Sopenharmony_ci	if (!list_empty(&fotg210->cached_itd_list))
124962306a36Sopenharmony_ci		start_free_itds(fotg210);
125062306a36Sopenharmony_ci}
125162306a36Sopenharmony_ci
125262306a36Sopenharmony_ci
125362306a36Sopenharmony_ci/* Handle lost (or very late) IAA interrupts */
125462306a36Sopenharmony_cistatic void fotg210_iaa_watchdog(struct fotg210_hcd *fotg210)
125562306a36Sopenharmony_ci{
125662306a36Sopenharmony_ci	if (fotg210->rh_state != FOTG210_RH_RUNNING)
125762306a36Sopenharmony_ci		return;
125862306a36Sopenharmony_ci
125962306a36Sopenharmony_ci	/*
126062306a36Sopenharmony_ci	 * Lost IAA irqs wedge things badly; seen first with a vt8235.
126162306a36Sopenharmony_ci	 * So we need this watchdog, but must protect it against both
126262306a36Sopenharmony_ci	 * (a) SMP races against real IAA firing and retriggering, and
126362306a36Sopenharmony_ci	 * (b) clean HC shutdown, when IAA watchdog was pending.
126462306a36Sopenharmony_ci	 */
126562306a36Sopenharmony_ci	if (fotg210->async_iaa) {
126662306a36Sopenharmony_ci		u32 cmd, status;
126762306a36Sopenharmony_ci
126862306a36Sopenharmony_ci		/* If we get here, IAA is *REALLY* late.  It's barely
126962306a36Sopenharmony_ci		 * conceivable that the system is so busy that CMD_IAAD
127062306a36Sopenharmony_ci		 * is still legitimately set, so let's be sure it's
127162306a36Sopenharmony_ci		 * clear before we read STS_IAA.  (The HC should clear
127262306a36Sopenharmony_ci		 * CMD_IAAD when it sets STS_IAA.)
127362306a36Sopenharmony_ci		 */
127462306a36Sopenharmony_ci		cmd = fotg210_readl(fotg210, &fotg210->regs->command);
127562306a36Sopenharmony_ci
127662306a36Sopenharmony_ci		/*
127762306a36Sopenharmony_ci		 * If IAA is set here it either legitimately triggered
127862306a36Sopenharmony_ci		 * after the watchdog timer expired (_way_ late, so we'll
127962306a36Sopenharmony_ci		 * still count it as lost) ... or a silicon erratum:
128062306a36Sopenharmony_ci		 * - VIA seems to set IAA without triggering the IRQ;
128162306a36Sopenharmony_ci		 * - IAAD potentially cleared without setting IAA.
128262306a36Sopenharmony_ci		 */
128362306a36Sopenharmony_ci		status = fotg210_readl(fotg210, &fotg210->regs->status);
128462306a36Sopenharmony_ci		if ((status & STS_IAA) || !(cmd & CMD_IAAD)) {
128562306a36Sopenharmony_ci			INCR(fotg210->stats.lost_iaa);
128662306a36Sopenharmony_ci			fotg210_writel(fotg210, STS_IAA,
128762306a36Sopenharmony_ci					&fotg210->regs->status);
128862306a36Sopenharmony_ci		}
128962306a36Sopenharmony_ci
129062306a36Sopenharmony_ci		fotg210_dbg(fotg210, "IAA watchdog: status %x cmd %x\n",
129162306a36Sopenharmony_ci				status, cmd);
129262306a36Sopenharmony_ci		end_unlink_async(fotg210);
129362306a36Sopenharmony_ci	}
129462306a36Sopenharmony_ci}
129562306a36Sopenharmony_ci
129662306a36Sopenharmony_ci
129762306a36Sopenharmony_ci/* Enable the I/O watchdog, if appropriate */
129862306a36Sopenharmony_cistatic void turn_on_io_watchdog(struct fotg210_hcd *fotg210)
129962306a36Sopenharmony_ci{
130062306a36Sopenharmony_ci	/* Not needed if the controller isn't running or it's already enabled */
130162306a36Sopenharmony_ci	if (fotg210->rh_state != FOTG210_RH_RUNNING ||
130262306a36Sopenharmony_ci			(fotg210->enabled_hrtimer_events &
130362306a36Sopenharmony_ci			BIT(FOTG210_HRTIMER_IO_WATCHDOG)))
130462306a36Sopenharmony_ci		return;
130562306a36Sopenharmony_ci
130662306a36Sopenharmony_ci	/*
130762306a36Sopenharmony_ci	 * Isochronous transfers always need the watchdog.
130862306a36Sopenharmony_ci	 * For other sorts we use it only if the flag is set.
130962306a36Sopenharmony_ci	 */
131062306a36Sopenharmony_ci	if (fotg210->isoc_count > 0 || (fotg210->need_io_watchdog &&
131162306a36Sopenharmony_ci			fotg210->async_count + fotg210->intr_count > 0))
131262306a36Sopenharmony_ci		fotg210_enable_event(fotg210, FOTG210_HRTIMER_IO_WATCHDOG,
131362306a36Sopenharmony_ci				true);
131462306a36Sopenharmony_ci}
131562306a36Sopenharmony_ci
131662306a36Sopenharmony_ci
131762306a36Sopenharmony_ci/* Handler functions for the hrtimer event types.
131862306a36Sopenharmony_ci * Keep this array in the same order as the event types indexed by
131962306a36Sopenharmony_ci * enum fotg210_hrtimer_event in fotg210.h.
132062306a36Sopenharmony_ci */
132162306a36Sopenharmony_cistatic void (*event_handlers[])(struct fotg210_hcd *) = {
132262306a36Sopenharmony_ci	fotg210_poll_ASS,			/* FOTG210_HRTIMER_POLL_ASS */
132362306a36Sopenharmony_ci	fotg210_poll_PSS,			/* FOTG210_HRTIMER_POLL_PSS */
132462306a36Sopenharmony_ci	fotg210_handle_controller_death,	/* FOTG210_HRTIMER_POLL_DEAD */
132562306a36Sopenharmony_ci	fotg210_handle_intr_unlinks,	/* FOTG210_HRTIMER_UNLINK_INTR */
132662306a36Sopenharmony_ci	end_free_itds,			/* FOTG210_HRTIMER_FREE_ITDS */
132762306a36Sopenharmony_ci	unlink_empty_async,		/* FOTG210_HRTIMER_ASYNC_UNLINKS */
132862306a36Sopenharmony_ci	fotg210_iaa_watchdog,		/* FOTG210_HRTIMER_IAA_WATCHDOG */
132962306a36Sopenharmony_ci	fotg210_disable_PSE,		/* FOTG210_HRTIMER_DISABLE_PERIODIC */
133062306a36Sopenharmony_ci	fotg210_disable_ASE,		/* FOTG210_HRTIMER_DISABLE_ASYNC */
133162306a36Sopenharmony_ci	fotg210_work,			/* FOTG210_HRTIMER_IO_WATCHDOG */
133262306a36Sopenharmony_ci};
133362306a36Sopenharmony_ci
133462306a36Sopenharmony_cistatic enum hrtimer_restart fotg210_hrtimer_func(struct hrtimer *t)
133562306a36Sopenharmony_ci{
133662306a36Sopenharmony_ci	struct fotg210_hcd *fotg210 =
133762306a36Sopenharmony_ci			container_of(t, struct fotg210_hcd, hrtimer);
133862306a36Sopenharmony_ci	ktime_t now;
133962306a36Sopenharmony_ci	unsigned long events;
134062306a36Sopenharmony_ci	unsigned long flags;
134162306a36Sopenharmony_ci	unsigned e;
134262306a36Sopenharmony_ci
134362306a36Sopenharmony_ci	spin_lock_irqsave(&fotg210->lock, flags);
134462306a36Sopenharmony_ci
134562306a36Sopenharmony_ci	events = fotg210->enabled_hrtimer_events;
134662306a36Sopenharmony_ci	fotg210->enabled_hrtimer_events = 0;
134762306a36Sopenharmony_ci	fotg210->next_hrtimer_event = FOTG210_HRTIMER_NO_EVENT;
134862306a36Sopenharmony_ci
134962306a36Sopenharmony_ci	/*
135062306a36Sopenharmony_ci	 * Check each pending event.  If its time has expired, handle
135162306a36Sopenharmony_ci	 * the event; otherwise re-enable it.
135262306a36Sopenharmony_ci	 */
135362306a36Sopenharmony_ci	now = ktime_get();
135462306a36Sopenharmony_ci	for_each_set_bit(e, &events, FOTG210_HRTIMER_NUM_EVENTS) {
135562306a36Sopenharmony_ci		if (ktime_compare(now, fotg210->hr_timeouts[e]) >= 0)
135662306a36Sopenharmony_ci			event_handlers[e](fotg210);
135762306a36Sopenharmony_ci		else
135862306a36Sopenharmony_ci			fotg210_enable_event(fotg210, e, false);
135962306a36Sopenharmony_ci	}
136062306a36Sopenharmony_ci
136162306a36Sopenharmony_ci	spin_unlock_irqrestore(&fotg210->lock, flags);
136262306a36Sopenharmony_ci	return HRTIMER_NORESTART;
136362306a36Sopenharmony_ci}
136462306a36Sopenharmony_ci
136562306a36Sopenharmony_ci#define fotg210_bus_suspend NULL
136662306a36Sopenharmony_ci#define fotg210_bus_resume NULL
136762306a36Sopenharmony_ci
136862306a36Sopenharmony_cistatic int check_reset_complete(struct fotg210_hcd *fotg210, int index,
136962306a36Sopenharmony_ci		u32 __iomem *status_reg, int port_status)
137062306a36Sopenharmony_ci{
137162306a36Sopenharmony_ci	if (!(port_status & PORT_CONNECT))
137262306a36Sopenharmony_ci		return port_status;
137362306a36Sopenharmony_ci
137462306a36Sopenharmony_ci	/* if reset finished and it's still not enabled -- handoff */
137562306a36Sopenharmony_ci	if (!(port_status & PORT_PE))
137662306a36Sopenharmony_ci		/* with integrated TT, there's nobody to hand it to! */
137762306a36Sopenharmony_ci		fotg210_dbg(fotg210, "Failed to enable port %d on root hub TT\n",
137862306a36Sopenharmony_ci				index + 1);
137962306a36Sopenharmony_ci	else
138062306a36Sopenharmony_ci		fotg210_dbg(fotg210, "port %d reset complete, port enabled\n",
138162306a36Sopenharmony_ci				index + 1);
138262306a36Sopenharmony_ci
138362306a36Sopenharmony_ci	return port_status;
138462306a36Sopenharmony_ci}
138562306a36Sopenharmony_ci
138662306a36Sopenharmony_ci
138762306a36Sopenharmony_ci/* build "status change" packet (one or two bytes) from HC registers */
138862306a36Sopenharmony_ci
138962306a36Sopenharmony_cistatic int fotg210_hub_status_data(struct usb_hcd *hcd, char *buf)
139062306a36Sopenharmony_ci{
139162306a36Sopenharmony_ci	struct fotg210_hcd *fotg210 = hcd_to_fotg210(hcd);
139262306a36Sopenharmony_ci	u32 temp, status;
139362306a36Sopenharmony_ci	u32 mask;
139462306a36Sopenharmony_ci	int retval = 1;
139562306a36Sopenharmony_ci	unsigned long flags;
139662306a36Sopenharmony_ci
139762306a36Sopenharmony_ci	/* init status to no-changes */
139862306a36Sopenharmony_ci	buf[0] = 0;
139962306a36Sopenharmony_ci
140062306a36Sopenharmony_ci	/* Inform the core about resumes-in-progress by returning
140162306a36Sopenharmony_ci	 * a non-zero value even if there are no status changes.
140262306a36Sopenharmony_ci	 */
140362306a36Sopenharmony_ci	status = fotg210->resuming_ports;
140462306a36Sopenharmony_ci
140562306a36Sopenharmony_ci	mask = PORT_CSC | PORT_PEC;
140662306a36Sopenharmony_ci	/* PORT_RESUME from hardware ~= PORT_STAT_C_SUSPEND */
140762306a36Sopenharmony_ci
140862306a36Sopenharmony_ci	/* no hub change reports (bit 0) for now (power, ...) */
140962306a36Sopenharmony_ci
141062306a36Sopenharmony_ci	/* port N changes (bit N)? */
141162306a36Sopenharmony_ci	spin_lock_irqsave(&fotg210->lock, flags);
141262306a36Sopenharmony_ci
141362306a36Sopenharmony_ci	temp = fotg210_readl(fotg210, &fotg210->regs->port_status);
141462306a36Sopenharmony_ci
141562306a36Sopenharmony_ci	/*
141662306a36Sopenharmony_ci	 * Return status information even for ports with OWNER set.
141762306a36Sopenharmony_ci	 * Otherwise hub_wq wouldn't see the disconnect event when a
141862306a36Sopenharmony_ci	 * high-speed device is switched over to the companion
141962306a36Sopenharmony_ci	 * controller by the user.
142062306a36Sopenharmony_ci	 */
142162306a36Sopenharmony_ci
142262306a36Sopenharmony_ci	if ((temp & mask) != 0 || test_bit(0, &fotg210->port_c_suspend) ||
142362306a36Sopenharmony_ci			(fotg210->reset_done[0] &&
142462306a36Sopenharmony_ci			time_after_eq(jiffies, fotg210->reset_done[0]))) {
142562306a36Sopenharmony_ci		buf[0] |= 1 << 1;
142662306a36Sopenharmony_ci		status = STS_PCD;
142762306a36Sopenharmony_ci	}
142862306a36Sopenharmony_ci	/* FIXME autosuspend idle root hubs */
142962306a36Sopenharmony_ci	spin_unlock_irqrestore(&fotg210->lock, flags);
143062306a36Sopenharmony_ci	return status ? retval : 0;
143162306a36Sopenharmony_ci}
143262306a36Sopenharmony_ci
143362306a36Sopenharmony_cistatic void fotg210_hub_descriptor(struct fotg210_hcd *fotg210,
143462306a36Sopenharmony_ci		struct usb_hub_descriptor *desc)
143562306a36Sopenharmony_ci{
143662306a36Sopenharmony_ci	int ports = HCS_N_PORTS(fotg210->hcs_params);
143762306a36Sopenharmony_ci	u16 temp;
143862306a36Sopenharmony_ci
143962306a36Sopenharmony_ci	desc->bDescriptorType = USB_DT_HUB;
144062306a36Sopenharmony_ci	desc->bPwrOn2PwrGood = 10;	/* fotg210 1.0, 2.3.9 says 20ms max */
144162306a36Sopenharmony_ci	desc->bHubContrCurrent = 0;
144262306a36Sopenharmony_ci
144362306a36Sopenharmony_ci	desc->bNbrPorts = ports;
144462306a36Sopenharmony_ci	temp = 1 + (ports / 8);
144562306a36Sopenharmony_ci	desc->bDescLength = 7 + 2 * temp;
144662306a36Sopenharmony_ci
144762306a36Sopenharmony_ci	/* two bitmaps:  ports removable, and usb 1.0 legacy PortPwrCtrlMask */
144862306a36Sopenharmony_ci	memset(&desc->u.hs.DeviceRemovable[0], 0, temp);
144962306a36Sopenharmony_ci	memset(&desc->u.hs.DeviceRemovable[temp], 0xff, temp);
145062306a36Sopenharmony_ci
145162306a36Sopenharmony_ci	temp = HUB_CHAR_INDV_PORT_OCPM;	/* per-port overcurrent reporting */
145262306a36Sopenharmony_ci	temp |= HUB_CHAR_NO_LPSM;	/* no power switching */
145362306a36Sopenharmony_ci	desc->wHubCharacteristics = cpu_to_le16(temp);
145462306a36Sopenharmony_ci}
145562306a36Sopenharmony_ci
145662306a36Sopenharmony_cistatic int fotg210_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
145762306a36Sopenharmony_ci		u16 wIndex, char *buf, u16 wLength)
145862306a36Sopenharmony_ci{
145962306a36Sopenharmony_ci	struct fotg210_hcd *fotg210 = hcd_to_fotg210(hcd);
146062306a36Sopenharmony_ci	int ports = HCS_N_PORTS(fotg210->hcs_params);
146162306a36Sopenharmony_ci	u32 __iomem *status_reg = &fotg210->regs->port_status;
146262306a36Sopenharmony_ci	u32 temp, temp1, status;
146362306a36Sopenharmony_ci	unsigned long flags;
146462306a36Sopenharmony_ci	int retval = 0;
146562306a36Sopenharmony_ci	unsigned selector;
146662306a36Sopenharmony_ci
146762306a36Sopenharmony_ci	/*
146862306a36Sopenharmony_ci	 * FIXME:  support SetPortFeatures USB_PORT_FEAT_INDICATOR.
146962306a36Sopenharmony_ci	 * HCS_INDICATOR may say we can change LEDs to off/amber/green.
147062306a36Sopenharmony_ci	 * (track current state ourselves) ... blink for diagnostics,
147162306a36Sopenharmony_ci	 * power, "this is the one", etc.  EHCI spec supports this.
147262306a36Sopenharmony_ci	 */
147362306a36Sopenharmony_ci
147462306a36Sopenharmony_ci	spin_lock_irqsave(&fotg210->lock, flags);
147562306a36Sopenharmony_ci	switch (typeReq) {
147662306a36Sopenharmony_ci	case ClearHubFeature:
147762306a36Sopenharmony_ci		switch (wValue) {
147862306a36Sopenharmony_ci		case C_HUB_LOCAL_POWER:
147962306a36Sopenharmony_ci		case C_HUB_OVER_CURRENT:
148062306a36Sopenharmony_ci			/* no hub-wide feature/status flags */
148162306a36Sopenharmony_ci			break;
148262306a36Sopenharmony_ci		default:
148362306a36Sopenharmony_ci			goto error;
148462306a36Sopenharmony_ci		}
148562306a36Sopenharmony_ci		break;
148662306a36Sopenharmony_ci	case ClearPortFeature:
148762306a36Sopenharmony_ci		if (!wIndex || wIndex > ports)
148862306a36Sopenharmony_ci			goto error;
148962306a36Sopenharmony_ci		wIndex--;
149062306a36Sopenharmony_ci		temp = fotg210_readl(fotg210, status_reg);
149162306a36Sopenharmony_ci		temp &= ~PORT_RWC_BITS;
149262306a36Sopenharmony_ci
149362306a36Sopenharmony_ci		/*
149462306a36Sopenharmony_ci		 * Even if OWNER is set, so the port is owned by the
149562306a36Sopenharmony_ci		 * companion controller, hub_wq needs to be able to clear
149662306a36Sopenharmony_ci		 * the port-change status bits (especially
149762306a36Sopenharmony_ci		 * USB_PORT_STAT_C_CONNECTION).
149862306a36Sopenharmony_ci		 */
149962306a36Sopenharmony_ci
150062306a36Sopenharmony_ci		switch (wValue) {
150162306a36Sopenharmony_ci		case USB_PORT_FEAT_ENABLE:
150262306a36Sopenharmony_ci			fotg210_writel(fotg210, temp & ~PORT_PE, status_reg);
150362306a36Sopenharmony_ci			break;
150462306a36Sopenharmony_ci		case USB_PORT_FEAT_C_ENABLE:
150562306a36Sopenharmony_ci			fotg210_writel(fotg210, temp | PORT_PEC, status_reg);
150662306a36Sopenharmony_ci			break;
150762306a36Sopenharmony_ci		case USB_PORT_FEAT_SUSPEND:
150862306a36Sopenharmony_ci			if (temp & PORT_RESET)
150962306a36Sopenharmony_ci				goto error;
151062306a36Sopenharmony_ci			if (!(temp & PORT_SUSPEND))
151162306a36Sopenharmony_ci				break;
151262306a36Sopenharmony_ci			if ((temp & PORT_PE) == 0)
151362306a36Sopenharmony_ci				goto error;
151462306a36Sopenharmony_ci
151562306a36Sopenharmony_ci			/* resume signaling for 20 msec */
151662306a36Sopenharmony_ci			fotg210_writel(fotg210, temp | PORT_RESUME, status_reg);
151762306a36Sopenharmony_ci			fotg210->reset_done[wIndex] = jiffies
151862306a36Sopenharmony_ci					+ msecs_to_jiffies(USB_RESUME_TIMEOUT);
151962306a36Sopenharmony_ci			break;
152062306a36Sopenharmony_ci		case USB_PORT_FEAT_C_SUSPEND:
152162306a36Sopenharmony_ci			clear_bit(wIndex, &fotg210->port_c_suspend);
152262306a36Sopenharmony_ci			break;
152362306a36Sopenharmony_ci		case USB_PORT_FEAT_C_CONNECTION:
152462306a36Sopenharmony_ci			fotg210_writel(fotg210, temp | PORT_CSC, status_reg);
152562306a36Sopenharmony_ci			break;
152662306a36Sopenharmony_ci		case USB_PORT_FEAT_C_OVER_CURRENT:
152762306a36Sopenharmony_ci			fotg210_writel(fotg210, temp | OTGISR_OVC,
152862306a36Sopenharmony_ci					&fotg210->regs->otgisr);
152962306a36Sopenharmony_ci			break;
153062306a36Sopenharmony_ci		case USB_PORT_FEAT_C_RESET:
153162306a36Sopenharmony_ci			/* GetPortStatus clears reset */
153262306a36Sopenharmony_ci			break;
153362306a36Sopenharmony_ci		default:
153462306a36Sopenharmony_ci			goto error;
153562306a36Sopenharmony_ci		}
153662306a36Sopenharmony_ci		fotg210_readl(fotg210, &fotg210->regs->command);
153762306a36Sopenharmony_ci		break;
153862306a36Sopenharmony_ci	case GetHubDescriptor:
153962306a36Sopenharmony_ci		fotg210_hub_descriptor(fotg210, (struct usb_hub_descriptor *)
154062306a36Sopenharmony_ci				buf);
154162306a36Sopenharmony_ci		break;
154262306a36Sopenharmony_ci	case GetHubStatus:
154362306a36Sopenharmony_ci		/* no hub-wide feature/status flags */
154462306a36Sopenharmony_ci		memset(buf, 0, 4);
154562306a36Sopenharmony_ci		/*cpu_to_le32s ((u32 *) buf); */
154662306a36Sopenharmony_ci		break;
154762306a36Sopenharmony_ci	case GetPortStatus:
154862306a36Sopenharmony_ci		if (!wIndex || wIndex > ports)
154962306a36Sopenharmony_ci			goto error;
155062306a36Sopenharmony_ci		wIndex--;
155162306a36Sopenharmony_ci		status = 0;
155262306a36Sopenharmony_ci		temp = fotg210_readl(fotg210, status_reg);
155362306a36Sopenharmony_ci
155462306a36Sopenharmony_ci		/* wPortChange bits */
155562306a36Sopenharmony_ci		if (temp & PORT_CSC)
155662306a36Sopenharmony_ci			status |= USB_PORT_STAT_C_CONNECTION << 16;
155762306a36Sopenharmony_ci		if (temp & PORT_PEC)
155862306a36Sopenharmony_ci			status |= USB_PORT_STAT_C_ENABLE << 16;
155962306a36Sopenharmony_ci
156062306a36Sopenharmony_ci		temp1 = fotg210_readl(fotg210, &fotg210->regs->otgisr);
156162306a36Sopenharmony_ci		if (temp1 & OTGISR_OVC)
156262306a36Sopenharmony_ci			status |= USB_PORT_STAT_C_OVERCURRENT << 16;
156362306a36Sopenharmony_ci
156462306a36Sopenharmony_ci		/* whoever resumes must GetPortStatus to complete it!! */
156562306a36Sopenharmony_ci		if (temp & PORT_RESUME) {
156662306a36Sopenharmony_ci
156762306a36Sopenharmony_ci			/* Remote Wakeup received? */
156862306a36Sopenharmony_ci			if (!fotg210->reset_done[wIndex]) {
156962306a36Sopenharmony_ci				/* resume signaling for 20 msec */
157062306a36Sopenharmony_ci				fotg210->reset_done[wIndex] = jiffies
157162306a36Sopenharmony_ci						+ msecs_to_jiffies(20);
157262306a36Sopenharmony_ci				/* check the port again */
157362306a36Sopenharmony_ci				mod_timer(&fotg210_to_hcd(fotg210)->rh_timer,
157462306a36Sopenharmony_ci						fotg210->reset_done[wIndex]);
157562306a36Sopenharmony_ci			}
157662306a36Sopenharmony_ci
157762306a36Sopenharmony_ci			/* resume completed? */
157862306a36Sopenharmony_ci			else if (time_after_eq(jiffies,
157962306a36Sopenharmony_ci					fotg210->reset_done[wIndex])) {
158062306a36Sopenharmony_ci				clear_bit(wIndex, &fotg210->suspended_ports);
158162306a36Sopenharmony_ci				set_bit(wIndex, &fotg210->port_c_suspend);
158262306a36Sopenharmony_ci				fotg210->reset_done[wIndex] = 0;
158362306a36Sopenharmony_ci
158462306a36Sopenharmony_ci				/* stop resume signaling */
158562306a36Sopenharmony_ci				temp = fotg210_readl(fotg210, status_reg);
158662306a36Sopenharmony_ci				fotg210_writel(fotg210, temp &
158762306a36Sopenharmony_ci						~(PORT_RWC_BITS | PORT_RESUME),
158862306a36Sopenharmony_ci						status_reg);
158962306a36Sopenharmony_ci				clear_bit(wIndex, &fotg210->resuming_ports);
159062306a36Sopenharmony_ci				retval = handshake(fotg210, status_reg,
159162306a36Sopenharmony_ci						PORT_RESUME, 0, 2000);/* 2ms */
159262306a36Sopenharmony_ci				if (retval != 0) {
159362306a36Sopenharmony_ci					fotg210_err(fotg210,
159462306a36Sopenharmony_ci							"port %d resume error %d\n",
159562306a36Sopenharmony_ci							wIndex + 1, retval);
159662306a36Sopenharmony_ci					goto error;
159762306a36Sopenharmony_ci				}
159862306a36Sopenharmony_ci				temp &= ~(PORT_SUSPEND|PORT_RESUME|(3<<10));
159962306a36Sopenharmony_ci			}
160062306a36Sopenharmony_ci		}
160162306a36Sopenharmony_ci
160262306a36Sopenharmony_ci		/* whoever resets must GetPortStatus to complete it!! */
160362306a36Sopenharmony_ci		if ((temp & PORT_RESET) && time_after_eq(jiffies,
160462306a36Sopenharmony_ci				fotg210->reset_done[wIndex])) {
160562306a36Sopenharmony_ci			status |= USB_PORT_STAT_C_RESET << 16;
160662306a36Sopenharmony_ci			fotg210->reset_done[wIndex] = 0;
160762306a36Sopenharmony_ci			clear_bit(wIndex, &fotg210->resuming_ports);
160862306a36Sopenharmony_ci
160962306a36Sopenharmony_ci			/* force reset to complete */
161062306a36Sopenharmony_ci			fotg210_writel(fotg210,
161162306a36Sopenharmony_ci					temp & ~(PORT_RWC_BITS | PORT_RESET),
161262306a36Sopenharmony_ci					status_reg);
161362306a36Sopenharmony_ci			/* REVISIT:  some hardware needs 550+ usec to clear
161462306a36Sopenharmony_ci			 * this bit; seems too long to spin routinely...
161562306a36Sopenharmony_ci			 */
161662306a36Sopenharmony_ci			retval = handshake(fotg210, status_reg,
161762306a36Sopenharmony_ci					PORT_RESET, 0, 1000);
161862306a36Sopenharmony_ci			if (retval != 0) {
161962306a36Sopenharmony_ci				fotg210_err(fotg210, "port %d reset error %d\n",
162062306a36Sopenharmony_ci						wIndex + 1, retval);
162162306a36Sopenharmony_ci				goto error;
162262306a36Sopenharmony_ci			}
162362306a36Sopenharmony_ci
162462306a36Sopenharmony_ci			/* see what we found out */
162562306a36Sopenharmony_ci			temp = check_reset_complete(fotg210, wIndex, status_reg,
162662306a36Sopenharmony_ci					fotg210_readl(fotg210, status_reg));
162762306a36Sopenharmony_ci
162862306a36Sopenharmony_ci			/* restart schedule */
162962306a36Sopenharmony_ci			fotg210->command |= CMD_RUN;
163062306a36Sopenharmony_ci			fotg210_writel(fotg210, fotg210->command, &fotg210->regs->command);
163162306a36Sopenharmony_ci		}
163262306a36Sopenharmony_ci
163362306a36Sopenharmony_ci		if (!(temp & (PORT_RESUME|PORT_RESET))) {
163462306a36Sopenharmony_ci			fotg210->reset_done[wIndex] = 0;
163562306a36Sopenharmony_ci			clear_bit(wIndex, &fotg210->resuming_ports);
163662306a36Sopenharmony_ci		}
163762306a36Sopenharmony_ci
163862306a36Sopenharmony_ci		/* transfer dedicated ports to the companion hc */
163962306a36Sopenharmony_ci		if ((temp & PORT_CONNECT) &&
164062306a36Sopenharmony_ci				test_bit(wIndex, &fotg210->companion_ports)) {
164162306a36Sopenharmony_ci			temp &= ~PORT_RWC_BITS;
164262306a36Sopenharmony_ci			fotg210_writel(fotg210, temp, status_reg);
164362306a36Sopenharmony_ci			fotg210_dbg(fotg210, "port %d --> companion\n",
164462306a36Sopenharmony_ci					wIndex + 1);
164562306a36Sopenharmony_ci			temp = fotg210_readl(fotg210, status_reg);
164662306a36Sopenharmony_ci		}
164762306a36Sopenharmony_ci
164862306a36Sopenharmony_ci		/*
164962306a36Sopenharmony_ci		 * Even if OWNER is set, there's no harm letting hub_wq
165062306a36Sopenharmony_ci		 * see the wPortStatus values (they should all be 0 except
165162306a36Sopenharmony_ci		 * for PORT_POWER anyway).
165262306a36Sopenharmony_ci		 */
165362306a36Sopenharmony_ci
165462306a36Sopenharmony_ci		if (temp & PORT_CONNECT) {
165562306a36Sopenharmony_ci			status |= USB_PORT_STAT_CONNECTION;
165662306a36Sopenharmony_ci			status |= fotg210_port_speed(fotg210, temp);
165762306a36Sopenharmony_ci		}
165862306a36Sopenharmony_ci		if (temp & PORT_PE)
165962306a36Sopenharmony_ci			status |= USB_PORT_STAT_ENABLE;
166062306a36Sopenharmony_ci
166162306a36Sopenharmony_ci		/* maybe the port was unsuspended without our knowledge */
166262306a36Sopenharmony_ci		if (temp & (PORT_SUSPEND|PORT_RESUME)) {
166362306a36Sopenharmony_ci			status |= USB_PORT_STAT_SUSPEND;
166462306a36Sopenharmony_ci		} else if (test_bit(wIndex, &fotg210->suspended_ports)) {
166562306a36Sopenharmony_ci			clear_bit(wIndex, &fotg210->suspended_ports);
166662306a36Sopenharmony_ci			clear_bit(wIndex, &fotg210->resuming_ports);
166762306a36Sopenharmony_ci			fotg210->reset_done[wIndex] = 0;
166862306a36Sopenharmony_ci			if (temp & PORT_PE)
166962306a36Sopenharmony_ci				set_bit(wIndex, &fotg210->port_c_suspend);
167062306a36Sopenharmony_ci		}
167162306a36Sopenharmony_ci
167262306a36Sopenharmony_ci		temp1 = fotg210_readl(fotg210, &fotg210->regs->otgisr);
167362306a36Sopenharmony_ci		if (temp1 & OTGISR_OVC)
167462306a36Sopenharmony_ci			status |= USB_PORT_STAT_OVERCURRENT;
167562306a36Sopenharmony_ci		if (temp & PORT_RESET)
167662306a36Sopenharmony_ci			status |= USB_PORT_STAT_RESET;
167762306a36Sopenharmony_ci		if (test_bit(wIndex, &fotg210->port_c_suspend))
167862306a36Sopenharmony_ci			status |= USB_PORT_STAT_C_SUSPEND << 16;
167962306a36Sopenharmony_ci
168062306a36Sopenharmony_ci		if (status & ~0xffff)	/* only if wPortChange is interesting */
168162306a36Sopenharmony_ci			dbg_port(fotg210, "GetStatus", wIndex + 1, temp);
168262306a36Sopenharmony_ci		put_unaligned_le32(status, buf);
168362306a36Sopenharmony_ci		break;
168462306a36Sopenharmony_ci	case SetHubFeature:
168562306a36Sopenharmony_ci		switch (wValue) {
168662306a36Sopenharmony_ci		case C_HUB_LOCAL_POWER:
168762306a36Sopenharmony_ci		case C_HUB_OVER_CURRENT:
168862306a36Sopenharmony_ci			/* no hub-wide feature/status flags */
168962306a36Sopenharmony_ci			break;
169062306a36Sopenharmony_ci		default:
169162306a36Sopenharmony_ci			goto error;
169262306a36Sopenharmony_ci		}
169362306a36Sopenharmony_ci		break;
169462306a36Sopenharmony_ci	case SetPortFeature:
169562306a36Sopenharmony_ci		selector = wIndex >> 8;
169662306a36Sopenharmony_ci		wIndex &= 0xff;
169762306a36Sopenharmony_ci
169862306a36Sopenharmony_ci		if (!wIndex || wIndex > ports)
169962306a36Sopenharmony_ci			goto error;
170062306a36Sopenharmony_ci		wIndex--;
170162306a36Sopenharmony_ci		temp = fotg210_readl(fotg210, status_reg);
170262306a36Sopenharmony_ci		temp &= ~PORT_RWC_BITS;
170362306a36Sopenharmony_ci		switch (wValue) {
170462306a36Sopenharmony_ci		case USB_PORT_FEAT_SUSPEND:
170562306a36Sopenharmony_ci			if ((temp & PORT_PE) == 0
170662306a36Sopenharmony_ci					|| (temp & PORT_RESET) != 0)
170762306a36Sopenharmony_ci				goto error;
170862306a36Sopenharmony_ci
170962306a36Sopenharmony_ci			/* After above check the port must be connected.
171062306a36Sopenharmony_ci			 * Set appropriate bit thus could put phy into low power
171162306a36Sopenharmony_ci			 * mode if we have hostpc feature
171262306a36Sopenharmony_ci			 */
171362306a36Sopenharmony_ci			fotg210_writel(fotg210, temp | PORT_SUSPEND,
171462306a36Sopenharmony_ci					status_reg);
171562306a36Sopenharmony_ci			set_bit(wIndex, &fotg210->suspended_ports);
171662306a36Sopenharmony_ci			break;
171762306a36Sopenharmony_ci		case USB_PORT_FEAT_RESET:
171862306a36Sopenharmony_ci			if (temp & PORT_RESUME)
171962306a36Sopenharmony_ci				goto error;
172062306a36Sopenharmony_ci			/* line status bits may report this as low speed,
172162306a36Sopenharmony_ci			 * which can be fine if this root hub has a
172262306a36Sopenharmony_ci			 * transaction translator built in.
172362306a36Sopenharmony_ci			 */
172462306a36Sopenharmony_ci			fotg210_dbg(fotg210, "port %d reset\n", wIndex + 1);
172562306a36Sopenharmony_ci			temp |= PORT_RESET;
172662306a36Sopenharmony_ci			temp &= ~PORT_PE;
172762306a36Sopenharmony_ci
172862306a36Sopenharmony_ci			/*
172962306a36Sopenharmony_ci			 * caller must wait, then call GetPortStatus
173062306a36Sopenharmony_ci			 * usb 2.0 spec says 50 ms resets on root
173162306a36Sopenharmony_ci			 */
173262306a36Sopenharmony_ci			fotg210->reset_done[wIndex] = jiffies
173362306a36Sopenharmony_ci					+ msecs_to_jiffies(50);
173462306a36Sopenharmony_ci			fotg210_writel(fotg210, temp, status_reg);
173562306a36Sopenharmony_ci			break;
173662306a36Sopenharmony_ci
173762306a36Sopenharmony_ci		/* For downstream facing ports (these):  one hub port is put
173862306a36Sopenharmony_ci		 * into test mode according to USB2 11.24.2.13, then the hub
173962306a36Sopenharmony_ci		 * must be reset (which for root hub now means rmmod+modprobe,
174062306a36Sopenharmony_ci		 * or else system reboot).  See EHCI 2.3.9 and 4.14 for info
174162306a36Sopenharmony_ci		 * about the EHCI-specific stuff.
174262306a36Sopenharmony_ci		 */
174362306a36Sopenharmony_ci		case USB_PORT_FEAT_TEST:
174462306a36Sopenharmony_ci			if (!selector || selector > 5)
174562306a36Sopenharmony_ci				goto error;
174662306a36Sopenharmony_ci			spin_unlock_irqrestore(&fotg210->lock, flags);
174762306a36Sopenharmony_ci			fotg210_quiesce(fotg210);
174862306a36Sopenharmony_ci			spin_lock_irqsave(&fotg210->lock, flags);
174962306a36Sopenharmony_ci
175062306a36Sopenharmony_ci			/* Put all enabled ports into suspend */
175162306a36Sopenharmony_ci			temp = fotg210_readl(fotg210, status_reg) &
175262306a36Sopenharmony_ci				~PORT_RWC_BITS;
175362306a36Sopenharmony_ci			if (temp & PORT_PE)
175462306a36Sopenharmony_ci				fotg210_writel(fotg210, temp | PORT_SUSPEND,
175562306a36Sopenharmony_ci						status_reg);
175662306a36Sopenharmony_ci
175762306a36Sopenharmony_ci			spin_unlock_irqrestore(&fotg210->lock, flags);
175862306a36Sopenharmony_ci			fotg210_halt(fotg210);
175962306a36Sopenharmony_ci			spin_lock_irqsave(&fotg210->lock, flags);
176062306a36Sopenharmony_ci
176162306a36Sopenharmony_ci			temp = fotg210_readl(fotg210, status_reg);
176262306a36Sopenharmony_ci			temp |= selector << 16;
176362306a36Sopenharmony_ci			fotg210_writel(fotg210, temp, status_reg);
176462306a36Sopenharmony_ci			break;
176562306a36Sopenharmony_ci
176662306a36Sopenharmony_ci		default:
176762306a36Sopenharmony_ci			goto error;
176862306a36Sopenharmony_ci		}
176962306a36Sopenharmony_ci		fotg210_readl(fotg210, &fotg210->regs->command);
177062306a36Sopenharmony_ci		break;
177162306a36Sopenharmony_ci
177262306a36Sopenharmony_ci	default:
177362306a36Sopenharmony_cierror:
177462306a36Sopenharmony_ci		/* "stall" on error */
177562306a36Sopenharmony_ci		retval = -EPIPE;
177662306a36Sopenharmony_ci	}
177762306a36Sopenharmony_ci	spin_unlock_irqrestore(&fotg210->lock, flags);
177862306a36Sopenharmony_ci	return retval;
177962306a36Sopenharmony_ci}
178062306a36Sopenharmony_ci
178162306a36Sopenharmony_cistatic void __maybe_unused fotg210_relinquish_port(struct usb_hcd *hcd,
178262306a36Sopenharmony_ci		int portnum)
178362306a36Sopenharmony_ci{
178462306a36Sopenharmony_ci	return;
178562306a36Sopenharmony_ci}
178662306a36Sopenharmony_ci
178762306a36Sopenharmony_cistatic int __maybe_unused fotg210_port_handed_over(struct usb_hcd *hcd,
178862306a36Sopenharmony_ci		int portnum)
178962306a36Sopenharmony_ci{
179062306a36Sopenharmony_ci	return 0;
179162306a36Sopenharmony_ci}
179262306a36Sopenharmony_ci
179362306a36Sopenharmony_ci/* There's basically three types of memory:
179462306a36Sopenharmony_ci *	- data used only by the HCD ... kmalloc is fine
179562306a36Sopenharmony_ci *	- async and periodic schedules, shared by HC and HCD ... these
179662306a36Sopenharmony_ci *	  need to use dma_pool or dma_alloc_coherent
179762306a36Sopenharmony_ci *	- driver buffers, read/written by HC ... single shot DMA mapped
179862306a36Sopenharmony_ci *
179962306a36Sopenharmony_ci * There's also "register" data (e.g. PCI or SOC), which is memory mapped.
180062306a36Sopenharmony_ci * No memory seen by this driver is pageable.
180162306a36Sopenharmony_ci */
180262306a36Sopenharmony_ci
180362306a36Sopenharmony_ci/* Allocate the key transfer structures from the previously allocated pool */
180462306a36Sopenharmony_cistatic inline void fotg210_qtd_init(struct fotg210_hcd *fotg210,
180562306a36Sopenharmony_ci		struct fotg210_qtd *qtd, dma_addr_t dma)
180662306a36Sopenharmony_ci{
180762306a36Sopenharmony_ci	memset(qtd, 0, sizeof(*qtd));
180862306a36Sopenharmony_ci	qtd->qtd_dma = dma;
180962306a36Sopenharmony_ci	qtd->hw_token = cpu_to_hc32(fotg210, QTD_STS_HALT);
181062306a36Sopenharmony_ci	qtd->hw_next = FOTG210_LIST_END(fotg210);
181162306a36Sopenharmony_ci	qtd->hw_alt_next = FOTG210_LIST_END(fotg210);
181262306a36Sopenharmony_ci	INIT_LIST_HEAD(&qtd->qtd_list);
181362306a36Sopenharmony_ci}
181462306a36Sopenharmony_ci
181562306a36Sopenharmony_cistatic struct fotg210_qtd *fotg210_qtd_alloc(struct fotg210_hcd *fotg210,
181662306a36Sopenharmony_ci		gfp_t flags)
181762306a36Sopenharmony_ci{
181862306a36Sopenharmony_ci	struct fotg210_qtd *qtd;
181962306a36Sopenharmony_ci	dma_addr_t dma;
182062306a36Sopenharmony_ci
182162306a36Sopenharmony_ci	qtd = dma_pool_alloc(fotg210->qtd_pool, flags, &dma);
182262306a36Sopenharmony_ci	if (qtd != NULL)
182362306a36Sopenharmony_ci		fotg210_qtd_init(fotg210, qtd, dma);
182462306a36Sopenharmony_ci
182562306a36Sopenharmony_ci	return qtd;
182662306a36Sopenharmony_ci}
182762306a36Sopenharmony_ci
182862306a36Sopenharmony_cistatic inline void fotg210_qtd_free(struct fotg210_hcd *fotg210,
182962306a36Sopenharmony_ci		struct fotg210_qtd *qtd)
183062306a36Sopenharmony_ci{
183162306a36Sopenharmony_ci	dma_pool_free(fotg210->qtd_pool, qtd, qtd->qtd_dma);
183262306a36Sopenharmony_ci}
183362306a36Sopenharmony_ci
183462306a36Sopenharmony_ci
183562306a36Sopenharmony_cistatic void qh_destroy(struct fotg210_hcd *fotg210, struct fotg210_qh *qh)
183662306a36Sopenharmony_ci{
183762306a36Sopenharmony_ci	/* clean qtds first, and know this is not linked */
183862306a36Sopenharmony_ci	if (!list_empty(&qh->qtd_list) || qh->qh_next.ptr) {
183962306a36Sopenharmony_ci		fotg210_dbg(fotg210, "unused qh not empty!\n");
184062306a36Sopenharmony_ci		BUG();
184162306a36Sopenharmony_ci	}
184262306a36Sopenharmony_ci	if (qh->dummy)
184362306a36Sopenharmony_ci		fotg210_qtd_free(fotg210, qh->dummy);
184462306a36Sopenharmony_ci	dma_pool_free(fotg210->qh_pool, qh->hw, qh->qh_dma);
184562306a36Sopenharmony_ci	kfree(qh);
184662306a36Sopenharmony_ci}
184762306a36Sopenharmony_ci
184862306a36Sopenharmony_cistatic struct fotg210_qh *fotg210_qh_alloc(struct fotg210_hcd *fotg210,
184962306a36Sopenharmony_ci		gfp_t flags)
185062306a36Sopenharmony_ci{
185162306a36Sopenharmony_ci	struct fotg210_qh *qh;
185262306a36Sopenharmony_ci	dma_addr_t dma;
185362306a36Sopenharmony_ci
185462306a36Sopenharmony_ci	qh = kzalloc(sizeof(*qh), GFP_ATOMIC);
185562306a36Sopenharmony_ci	if (!qh)
185662306a36Sopenharmony_ci		goto done;
185762306a36Sopenharmony_ci	qh->hw = (struct fotg210_qh_hw *)
185862306a36Sopenharmony_ci		dma_pool_zalloc(fotg210->qh_pool, flags, &dma);
185962306a36Sopenharmony_ci	if (!qh->hw)
186062306a36Sopenharmony_ci		goto fail;
186162306a36Sopenharmony_ci	qh->qh_dma = dma;
186262306a36Sopenharmony_ci	INIT_LIST_HEAD(&qh->qtd_list);
186362306a36Sopenharmony_ci
186462306a36Sopenharmony_ci	/* dummy td enables safe urb queuing */
186562306a36Sopenharmony_ci	qh->dummy = fotg210_qtd_alloc(fotg210, flags);
186662306a36Sopenharmony_ci	if (qh->dummy == NULL) {
186762306a36Sopenharmony_ci		fotg210_dbg(fotg210, "no dummy td\n");
186862306a36Sopenharmony_ci		goto fail1;
186962306a36Sopenharmony_ci	}
187062306a36Sopenharmony_cidone:
187162306a36Sopenharmony_ci	return qh;
187262306a36Sopenharmony_cifail1:
187362306a36Sopenharmony_ci	dma_pool_free(fotg210->qh_pool, qh->hw, qh->qh_dma);
187462306a36Sopenharmony_cifail:
187562306a36Sopenharmony_ci	kfree(qh);
187662306a36Sopenharmony_ci	return NULL;
187762306a36Sopenharmony_ci}
187862306a36Sopenharmony_ci
187962306a36Sopenharmony_ci/* The queue heads and transfer descriptors are managed from pools tied
188062306a36Sopenharmony_ci * to each of the "per device" structures.
188162306a36Sopenharmony_ci * This is the initialisation and cleanup code.
188262306a36Sopenharmony_ci */
188362306a36Sopenharmony_ci
188462306a36Sopenharmony_cistatic void fotg210_mem_cleanup(struct fotg210_hcd *fotg210)
188562306a36Sopenharmony_ci{
188662306a36Sopenharmony_ci	if (fotg210->async)
188762306a36Sopenharmony_ci		qh_destroy(fotg210, fotg210->async);
188862306a36Sopenharmony_ci	fotg210->async = NULL;
188962306a36Sopenharmony_ci
189062306a36Sopenharmony_ci	if (fotg210->dummy)
189162306a36Sopenharmony_ci		qh_destroy(fotg210, fotg210->dummy);
189262306a36Sopenharmony_ci	fotg210->dummy = NULL;
189362306a36Sopenharmony_ci
189462306a36Sopenharmony_ci	/* DMA consistent memory and pools */
189562306a36Sopenharmony_ci	dma_pool_destroy(fotg210->qtd_pool);
189662306a36Sopenharmony_ci	fotg210->qtd_pool = NULL;
189762306a36Sopenharmony_ci
189862306a36Sopenharmony_ci	dma_pool_destroy(fotg210->qh_pool);
189962306a36Sopenharmony_ci	fotg210->qh_pool = NULL;
190062306a36Sopenharmony_ci
190162306a36Sopenharmony_ci	dma_pool_destroy(fotg210->itd_pool);
190262306a36Sopenharmony_ci	fotg210->itd_pool = NULL;
190362306a36Sopenharmony_ci
190462306a36Sopenharmony_ci	if (fotg210->periodic)
190562306a36Sopenharmony_ci		dma_free_coherent(fotg210_to_hcd(fotg210)->self.controller,
190662306a36Sopenharmony_ci				fotg210->periodic_size * sizeof(u32),
190762306a36Sopenharmony_ci				fotg210->periodic, fotg210->periodic_dma);
190862306a36Sopenharmony_ci	fotg210->periodic = NULL;
190962306a36Sopenharmony_ci
191062306a36Sopenharmony_ci	/* shadow periodic table */
191162306a36Sopenharmony_ci	kfree(fotg210->pshadow);
191262306a36Sopenharmony_ci	fotg210->pshadow = NULL;
191362306a36Sopenharmony_ci}
191462306a36Sopenharmony_ci
191562306a36Sopenharmony_ci/* remember to add cleanup code (above) if you add anything here */
191662306a36Sopenharmony_cistatic int fotg210_mem_init(struct fotg210_hcd *fotg210, gfp_t flags)
191762306a36Sopenharmony_ci{
191862306a36Sopenharmony_ci	int i;
191962306a36Sopenharmony_ci
192062306a36Sopenharmony_ci	/* QTDs for control/bulk/intr transfers */
192162306a36Sopenharmony_ci	fotg210->qtd_pool = dma_pool_create("fotg210_qtd",
192262306a36Sopenharmony_ci			fotg210_to_hcd(fotg210)->self.controller,
192362306a36Sopenharmony_ci			sizeof(struct fotg210_qtd),
192462306a36Sopenharmony_ci			32 /* byte alignment (for hw parts) */,
192562306a36Sopenharmony_ci			4096 /* can't cross 4K */);
192662306a36Sopenharmony_ci	if (!fotg210->qtd_pool)
192762306a36Sopenharmony_ci		goto fail;
192862306a36Sopenharmony_ci
192962306a36Sopenharmony_ci	/* QHs for control/bulk/intr transfers */
193062306a36Sopenharmony_ci	fotg210->qh_pool = dma_pool_create("fotg210_qh",
193162306a36Sopenharmony_ci			fotg210_to_hcd(fotg210)->self.controller,
193262306a36Sopenharmony_ci			sizeof(struct fotg210_qh_hw),
193362306a36Sopenharmony_ci			32 /* byte alignment (for hw parts) */,
193462306a36Sopenharmony_ci			4096 /* can't cross 4K */);
193562306a36Sopenharmony_ci	if (!fotg210->qh_pool)
193662306a36Sopenharmony_ci		goto fail;
193762306a36Sopenharmony_ci
193862306a36Sopenharmony_ci	fotg210->async = fotg210_qh_alloc(fotg210, flags);
193962306a36Sopenharmony_ci	if (!fotg210->async)
194062306a36Sopenharmony_ci		goto fail;
194162306a36Sopenharmony_ci
194262306a36Sopenharmony_ci	/* ITD for high speed ISO transfers */
194362306a36Sopenharmony_ci	fotg210->itd_pool = dma_pool_create("fotg210_itd",
194462306a36Sopenharmony_ci			fotg210_to_hcd(fotg210)->self.controller,
194562306a36Sopenharmony_ci			sizeof(struct fotg210_itd),
194662306a36Sopenharmony_ci			64 /* byte alignment (for hw parts) */,
194762306a36Sopenharmony_ci			4096 /* can't cross 4K */);
194862306a36Sopenharmony_ci	if (!fotg210->itd_pool)
194962306a36Sopenharmony_ci		goto fail;
195062306a36Sopenharmony_ci
195162306a36Sopenharmony_ci	/* Hardware periodic table */
195262306a36Sopenharmony_ci	fotg210->periodic =
195362306a36Sopenharmony_ci		dma_alloc_coherent(fotg210_to_hcd(fotg210)->self.controller,
195462306a36Sopenharmony_ci				fotg210->periodic_size * sizeof(__le32),
195562306a36Sopenharmony_ci				&fotg210->periodic_dma, 0);
195662306a36Sopenharmony_ci	if (fotg210->periodic == NULL)
195762306a36Sopenharmony_ci		goto fail;
195862306a36Sopenharmony_ci
195962306a36Sopenharmony_ci	for (i = 0; i < fotg210->periodic_size; i++)
196062306a36Sopenharmony_ci		fotg210->periodic[i] = FOTG210_LIST_END(fotg210);
196162306a36Sopenharmony_ci
196262306a36Sopenharmony_ci	/* software shadow of hardware table */
196362306a36Sopenharmony_ci	fotg210->pshadow = kcalloc(fotg210->periodic_size, sizeof(void *),
196462306a36Sopenharmony_ci			flags);
196562306a36Sopenharmony_ci	if (fotg210->pshadow != NULL)
196662306a36Sopenharmony_ci		return 0;
196762306a36Sopenharmony_ci
196862306a36Sopenharmony_cifail:
196962306a36Sopenharmony_ci	fotg210_dbg(fotg210, "couldn't init memory\n");
197062306a36Sopenharmony_ci	fotg210_mem_cleanup(fotg210);
197162306a36Sopenharmony_ci	return -ENOMEM;
197262306a36Sopenharmony_ci}
197362306a36Sopenharmony_ci/* EHCI hardware queue manipulation ... the core.  QH/QTD manipulation.
197462306a36Sopenharmony_ci *
197562306a36Sopenharmony_ci * Control, bulk, and interrupt traffic all use "qh" lists.  They list "qtd"
197662306a36Sopenharmony_ci * entries describing USB transactions, max 16-20kB/entry (with 4kB-aligned
197762306a36Sopenharmony_ci * buffers needed for the larger number).  We use one QH per endpoint, queue
197862306a36Sopenharmony_ci * multiple urbs (all three types) per endpoint.  URBs may need several qtds.
197962306a36Sopenharmony_ci *
198062306a36Sopenharmony_ci * ISO traffic uses "ISO TD" (itd) records, and (along with
198162306a36Sopenharmony_ci * interrupts) needs careful scheduling.  Performance improvements can be
198262306a36Sopenharmony_ci * an ongoing challenge.  That's in "ehci-sched.c".
198362306a36Sopenharmony_ci *
198462306a36Sopenharmony_ci * USB 1.1 devices are handled (a) by "companion" OHCI or UHCI root hubs,
198562306a36Sopenharmony_ci * or otherwise through transaction translators (TTs) in USB 2.0 hubs using
198662306a36Sopenharmony_ci * (b) special fields in qh entries or (c) split iso entries.  TTs will
198762306a36Sopenharmony_ci * buffer low/full speed data so the host collects it at high speed.
198862306a36Sopenharmony_ci */
198962306a36Sopenharmony_ci
199062306a36Sopenharmony_ci/* fill a qtd, returning how much of the buffer we were able to queue up */
199162306a36Sopenharmony_cistatic int qtd_fill(struct fotg210_hcd *fotg210, struct fotg210_qtd *qtd,
199262306a36Sopenharmony_ci		dma_addr_t buf, size_t len, int token, int maxpacket)
199362306a36Sopenharmony_ci{
199462306a36Sopenharmony_ci	int i, count;
199562306a36Sopenharmony_ci	u64 addr = buf;
199662306a36Sopenharmony_ci
199762306a36Sopenharmony_ci	/* one buffer entry per 4K ... first might be short or unaligned */
199862306a36Sopenharmony_ci	qtd->hw_buf[0] = cpu_to_hc32(fotg210, (u32)addr);
199962306a36Sopenharmony_ci	qtd->hw_buf_hi[0] = cpu_to_hc32(fotg210, (u32)(addr >> 32));
200062306a36Sopenharmony_ci	count = 0x1000 - (buf & 0x0fff);	/* rest of that page */
200162306a36Sopenharmony_ci	if (likely(len < count))		/* ... iff needed */
200262306a36Sopenharmony_ci		count = len;
200362306a36Sopenharmony_ci	else {
200462306a36Sopenharmony_ci		buf +=  0x1000;
200562306a36Sopenharmony_ci		buf &= ~0x0fff;
200662306a36Sopenharmony_ci
200762306a36Sopenharmony_ci		/* per-qtd limit: from 16K to 20K (best alignment) */
200862306a36Sopenharmony_ci		for (i = 1; count < len && i < 5; i++) {
200962306a36Sopenharmony_ci			addr = buf;
201062306a36Sopenharmony_ci			qtd->hw_buf[i] = cpu_to_hc32(fotg210, (u32)addr);
201162306a36Sopenharmony_ci			qtd->hw_buf_hi[i] = cpu_to_hc32(fotg210,
201262306a36Sopenharmony_ci					(u32)(addr >> 32));
201362306a36Sopenharmony_ci			buf += 0x1000;
201462306a36Sopenharmony_ci			if ((count + 0x1000) < len)
201562306a36Sopenharmony_ci				count += 0x1000;
201662306a36Sopenharmony_ci			else
201762306a36Sopenharmony_ci				count = len;
201862306a36Sopenharmony_ci		}
201962306a36Sopenharmony_ci
202062306a36Sopenharmony_ci		/* short packets may only terminate transfers */
202162306a36Sopenharmony_ci		if (count != len)
202262306a36Sopenharmony_ci			count -= (count % maxpacket);
202362306a36Sopenharmony_ci	}
202462306a36Sopenharmony_ci	qtd->hw_token = cpu_to_hc32(fotg210, (count << 16) | token);
202562306a36Sopenharmony_ci	qtd->length = count;
202662306a36Sopenharmony_ci
202762306a36Sopenharmony_ci	return count;
202862306a36Sopenharmony_ci}
202962306a36Sopenharmony_ci
203062306a36Sopenharmony_cistatic inline void qh_update(struct fotg210_hcd *fotg210,
203162306a36Sopenharmony_ci		struct fotg210_qh *qh, struct fotg210_qtd *qtd)
203262306a36Sopenharmony_ci{
203362306a36Sopenharmony_ci	struct fotg210_qh_hw *hw = qh->hw;
203462306a36Sopenharmony_ci
203562306a36Sopenharmony_ci	/* writes to an active overlay are unsafe */
203662306a36Sopenharmony_ci	BUG_ON(qh->qh_state != QH_STATE_IDLE);
203762306a36Sopenharmony_ci
203862306a36Sopenharmony_ci	hw->hw_qtd_next = QTD_NEXT(fotg210, qtd->qtd_dma);
203962306a36Sopenharmony_ci	hw->hw_alt_next = FOTG210_LIST_END(fotg210);
204062306a36Sopenharmony_ci
204162306a36Sopenharmony_ci	/* Except for control endpoints, we make hardware maintain data
204262306a36Sopenharmony_ci	 * toggle (like OHCI) ... here (re)initialize the toggle in the QH,
204362306a36Sopenharmony_ci	 * and set the pseudo-toggle in udev. Only usb_clear_halt() will
204462306a36Sopenharmony_ci	 * ever clear it.
204562306a36Sopenharmony_ci	 */
204662306a36Sopenharmony_ci	if (!(hw->hw_info1 & cpu_to_hc32(fotg210, QH_TOGGLE_CTL))) {
204762306a36Sopenharmony_ci		unsigned is_out, epnum;
204862306a36Sopenharmony_ci
204962306a36Sopenharmony_ci		is_out = qh->is_out;
205062306a36Sopenharmony_ci		epnum = (hc32_to_cpup(fotg210, &hw->hw_info1) >> 8) & 0x0f;
205162306a36Sopenharmony_ci		if (unlikely(!usb_gettoggle(qh->dev, epnum, is_out))) {
205262306a36Sopenharmony_ci			hw->hw_token &= ~cpu_to_hc32(fotg210, QTD_TOGGLE);
205362306a36Sopenharmony_ci			usb_settoggle(qh->dev, epnum, is_out, 1);
205462306a36Sopenharmony_ci		}
205562306a36Sopenharmony_ci	}
205662306a36Sopenharmony_ci
205762306a36Sopenharmony_ci	hw->hw_token &= cpu_to_hc32(fotg210, QTD_TOGGLE | QTD_STS_PING);
205862306a36Sopenharmony_ci}
205962306a36Sopenharmony_ci
206062306a36Sopenharmony_ci/* if it weren't for a common silicon quirk (writing the dummy into the qh
206162306a36Sopenharmony_ci * overlay, so qh->hw_token wrongly becomes inactive/halted), only fault
206262306a36Sopenharmony_ci * recovery (including urb dequeue) would need software changes to a QH...
206362306a36Sopenharmony_ci */
206462306a36Sopenharmony_cistatic void qh_refresh(struct fotg210_hcd *fotg210, struct fotg210_qh *qh)
206562306a36Sopenharmony_ci{
206662306a36Sopenharmony_ci	struct fotg210_qtd *qtd;
206762306a36Sopenharmony_ci
206862306a36Sopenharmony_ci	if (list_empty(&qh->qtd_list))
206962306a36Sopenharmony_ci		qtd = qh->dummy;
207062306a36Sopenharmony_ci	else {
207162306a36Sopenharmony_ci		qtd = list_entry(qh->qtd_list.next,
207262306a36Sopenharmony_ci				struct fotg210_qtd, qtd_list);
207362306a36Sopenharmony_ci		/*
207462306a36Sopenharmony_ci		 * first qtd may already be partially processed.
207562306a36Sopenharmony_ci		 * If we come here during unlink, the QH overlay region
207662306a36Sopenharmony_ci		 * might have reference to the just unlinked qtd. The
207762306a36Sopenharmony_ci		 * qtd is updated in qh_completions(). Update the QH
207862306a36Sopenharmony_ci		 * overlay here.
207962306a36Sopenharmony_ci		 */
208062306a36Sopenharmony_ci		if (cpu_to_hc32(fotg210, qtd->qtd_dma) == qh->hw->hw_current) {
208162306a36Sopenharmony_ci			qh->hw->hw_qtd_next = qtd->hw_next;
208262306a36Sopenharmony_ci			qtd = NULL;
208362306a36Sopenharmony_ci		}
208462306a36Sopenharmony_ci	}
208562306a36Sopenharmony_ci
208662306a36Sopenharmony_ci	if (qtd)
208762306a36Sopenharmony_ci		qh_update(fotg210, qh, qtd);
208862306a36Sopenharmony_ci}
208962306a36Sopenharmony_ci
209062306a36Sopenharmony_cistatic void qh_link_async(struct fotg210_hcd *fotg210, struct fotg210_qh *qh);
209162306a36Sopenharmony_ci
209262306a36Sopenharmony_cistatic void fotg210_clear_tt_buffer_complete(struct usb_hcd *hcd,
209362306a36Sopenharmony_ci		struct usb_host_endpoint *ep)
209462306a36Sopenharmony_ci{
209562306a36Sopenharmony_ci	struct fotg210_hcd *fotg210 = hcd_to_fotg210(hcd);
209662306a36Sopenharmony_ci	struct fotg210_qh *qh = ep->hcpriv;
209762306a36Sopenharmony_ci	unsigned long flags;
209862306a36Sopenharmony_ci
209962306a36Sopenharmony_ci	spin_lock_irqsave(&fotg210->lock, flags);
210062306a36Sopenharmony_ci	qh->clearing_tt = 0;
210162306a36Sopenharmony_ci	if (qh->qh_state == QH_STATE_IDLE && !list_empty(&qh->qtd_list)
210262306a36Sopenharmony_ci			&& fotg210->rh_state == FOTG210_RH_RUNNING)
210362306a36Sopenharmony_ci		qh_link_async(fotg210, qh);
210462306a36Sopenharmony_ci	spin_unlock_irqrestore(&fotg210->lock, flags);
210562306a36Sopenharmony_ci}
210662306a36Sopenharmony_ci
210762306a36Sopenharmony_cistatic void fotg210_clear_tt_buffer(struct fotg210_hcd *fotg210,
210862306a36Sopenharmony_ci		struct fotg210_qh *qh, struct urb *urb, u32 token)
210962306a36Sopenharmony_ci{
211062306a36Sopenharmony_ci
211162306a36Sopenharmony_ci	/* If an async split transaction gets an error or is unlinked,
211262306a36Sopenharmony_ci	 * the TT buffer may be left in an indeterminate state.  We
211362306a36Sopenharmony_ci	 * have to clear the TT buffer.
211462306a36Sopenharmony_ci	 *
211562306a36Sopenharmony_ci	 * Note: this routine is never called for Isochronous transfers.
211662306a36Sopenharmony_ci	 */
211762306a36Sopenharmony_ci	if (urb->dev->tt && !usb_pipeint(urb->pipe) && !qh->clearing_tt) {
211862306a36Sopenharmony_ci		struct usb_device *tt = urb->dev->tt->hub;
211962306a36Sopenharmony_ci
212062306a36Sopenharmony_ci		dev_dbg(&tt->dev,
212162306a36Sopenharmony_ci				"clear tt buffer port %d, a%d ep%d t%08x\n",
212262306a36Sopenharmony_ci				urb->dev->ttport, urb->dev->devnum,
212362306a36Sopenharmony_ci				usb_pipeendpoint(urb->pipe), token);
212462306a36Sopenharmony_ci
212562306a36Sopenharmony_ci		if (urb->dev->tt->hub !=
212662306a36Sopenharmony_ci				fotg210_to_hcd(fotg210)->self.root_hub) {
212762306a36Sopenharmony_ci			if (usb_hub_clear_tt_buffer(urb) == 0)
212862306a36Sopenharmony_ci				qh->clearing_tt = 1;
212962306a36Sopenharmony_ci		}
213062306a36Sopenharmony_ci	}
213162306a36Sopenharmony_ci}
213262306a36Sopenharmony_ci
213362306a36Sopenharmony_cistatic int qtd_copy_status(struct fotg210_hcd *fotg210, struct urb *urb,
213462306a36Sopenharmony_ci		size_t length, u32 token)
213562306a36Sopenharmony_ci{
213662306a36Sopenharmony_ci	int status = -EINPROGRESS;
213762306a36Sopenharmony_ci
213862306a36Sopenharmony_ci	/* count IN/OUT bytes, not SETUP (even short packets) */
213962306a36Sopenharmony_ci	if (likely(QTD_PID(token) != 2))
214062306a36Sopenharmony_ci		urb->actual_length += length - QTD_LENGTH(token);
214162306a36Sopenharmony_ci
214262306a36Sopenharmony_ci	/* don't modify error codes */
214362306a36Sopenharmony_ci	if (unlikely(urb->unlinked))
214462306a36Sopenharmony_ci		return status;
214562306a36Sopenharmony_ci
214662306a36Sopenharmony_ci	/* force cleanup after short read; not always an error */
214762306a36Sopenharmony_ci	if (unlikely(IS_SHORT_READ(token)))
214862306a36Sopenharmony_ci		status = -EREMOTEIO;
214962306a36Sopenharmony_ci
215062306a36Sopenharmony_ci	/* serious "can't proceed" faults reported by the hardware */
215162306a36Sopenharmony_ci	if (token & QTD_STS_HALT) {
215262306a36Sopenharmony_ci		if (token & QTD_STS_BABBLE) {
215362306a36Sopenharmony_ci			/* FIXME "must" disable babbling device's port too */
215462306a36Sopenharmony_ci			status = -EOVERFLOW;
215562306a36Sopenharmony_ci		/* CERR nonzero + halt --> stall */
215662306a36Sopenharmony_ci		} else if (QTD_CERR(token)) {
215762306a36Sopenharmony_ci			status = -EPIPE;
215862306a36Sopenharmony_ci
215962306a36Sopenharmony_ci		/* In theory, more than one of the following bits can be set
216062306a36Sopenharmony_ci		 * since they are sticky and the transaction is retried.
216162306a36Sopenharmony_ci		 * Which to test first is rather arbitrary.
216262306a36Sopenharmony_ci		 */
216362306a36Sopenharmony_ci		} else if (token & QTD_STS_MMF) {
216462306a36Sopenharmony_ci			/* fs/ls interrupt xfer missed the complete-split */
216562306a36Sopenharmony_ci			status = -EPROTO;
216662306a36Sopenharmony_ci		} else if (token & QTD_STS_DBE) {
216762306a36Sopenharmony_ci			status = (QTD_PID(token) == 1) /* IN ? */
216862306a36Sopenharmony_ci				? -ENOSR  /* hc couldn't read data */
216962306a36Sopenharmony_ci				: -ECOMM; /* hc couldn't write data */
217062306a36Sopenharmony_ci		} else if (token & QTD_STS_XACT) {
217162306a36Sopenharmony_ci			/* timeout, bad CRC, wrong PID, etc */
217262306a36Sopenharmony_ci			fotg210_dbg(fotg210, "devpath %s ep%d%s 3strikes\n",
217362306a36Sopenharmony_ci					urb->dev->devpath,
217462306a36Sopenharmony_ci					usb_pipeendpoint(urb->pipe),
217562306a36Sopenharmony_ci					usb_pipein(urb->pipe) ? "in" : "out");
217662306a36Sopenharmony_ci			status = -EPROTO;
217762306a36Sopenharmony_ci		} else {	/* unknown */
217862306a36Sopenharmony_ci			status = -EPROTO;
217962306a36Sopenharmony_ci		}
218062306a36Sopenharmony_ci
218162306a36Sopenharmony_ci		fotg210_dbg(fotg210,
218262306a36Sopenharmony_ci				"dev%d ep%d%s qtd token %08x --> status %d\n",
218362306a36Sopenharmony_ci				usb_pipedevice(urb->pipe),
218462306a36Sopenharmony_ci				usb_pipeendpoint(urb->pipe),
218562306a36Sopenharmony_ci				usb_pipein(urb->pipe) ? "in" : "out",
218662306a36Sopenharmony_ci				token, status);
218762306a36Sopenharmony_ci	}
218862306a36Sopenharmony_ci
218962306a36Sopenharmony_ci	return status;
219062306a36Sopenharmony_ci}
219162306a36Sopenharmony_ci
219262306a36Sopenharmony_cistatic void fotg210_urb_done(struct fotg210_hcd *fotg210, struct urb *urb,
219362306a36Sopenharmony_ci		int status)
219462306a36Sopenharmony_ci__releases(fotg210->lock)
219562306a36Sopenharmony_ci__acquires(fotg210->lock)
219662306a36Sopenharmony_ci{
219762306a36Sopenharmony_ci	if (likely(urb->hcpriv != NULL)) {
219862306a36Sopenharmony_ci		struct fotg210_qh *qh = (struct fotg210_qh *) urb->hcpriv;
219962306a36Sopenharmony_ci
220062306a36Sopenharmony_ci		/* S-mask in a QH means it's an interrupt urb */
220162306a36Sopenharmony_ci		if ((qh->hw->hw_info2 & cpu_to_hc32(fotg210, QH_SMASK)) != 0) {
220262306a36Sopenharmony_ci
220362306a36Sopenharmony_ci			/* ... update hc-wide periodic stats (for usbfs) */
220462306a36Sopenharmony_ci			fotg210_to_hcd(fotg210)->self.bandwidth_int_reqs--;
220562306a36Sopenharmony_ci		}
220662306a36Sopenharmony_ci	}
220762306a36Sopenharmony_ci
220862306a36Sopenharmony_ci	if (unlikely(urb->unlinked)) {
220962306a36Sopenharmony_ci		INCR(fotg210->stats.unlink);
221062306a36Sopenharmony_ci	} else {
221162306a36Sopenharmony_ci		/* report non-error and short read status as zero */
221262306a36Sopenharmony_ci		if (status == -EINPROGRESS || status == -EREMOTEIO)
221362306a36Sopenharmony_ci			status = 0;
221462306a36Sopenharmony_ci		INCR(fotg210->stats.complete);
221562306a36Sopenharmony_ci	}
221662306a36Sopenharmony_ci
221762306a36Sopenharmony_ci#ifdef FOTG210_URB_TRACE
221862306a36Sopenharmony_ci	fotg210_dbg(fotg210,
221962306a36Sopenharmony_ci			"%s %s urb %p ep%d%s status %d len %d/%d\n",
222062306a36Sopenharmony_ci			__func__, urb->dev->devpath, urb,
222162306a36Sopenharmony_ci			usb_pipeendpoint(urb->pipe),
222262306a36Sopenharmony_ci			usb_pipein(urb->pipe) ? "in" : "out",
222362306a36Sopenharmony_ci			status,
222462306a36Sopenharmony_ci			urb->actual_length, urb->transfer_buffer_length);
222562306a36Sopenharmony_ci#endif
222662306a36Sopenharmony_ci
222762306a36Sopenharmony_ci	/* complete() can reenter this HCD */
222862306a36Sopenharmony_ci	usb_hcd_unlink_urb_from_ep(fotg210_to_hcd(fotg210), urb);
222962306a36Sopenharmony_ci	spin_unlock(&fotg210->lock);
223062306a36Sopenharmony_ci	usb_hcd_giveback_urb(fotg210_to_hcd(fotg210), urb, status);
223162306a36Sopenharmony_ci	spin_lock(&fotg210->lock);
223262306a36Sopenharmony_ci}
223362306a36Sopenharmony_ci
223462306a36Sopenharmony_cistatic int qh_schedule(struct fotg210_hcd *fotg210, struct fotg210_qh *qh);
223562306a36Sopenharmony_ci
223662306a36Sopenharmony_ci/* Process and free completed qtds for a qh, returning URBs to drivers.
223762306a36Sopenharmony_ci * Chases up to qh->hw_current.  Returns number of completions called,
223862306a36Sopenharmony_ci * indicating how much "real" work we did.
223962306a36Sopenharmony_ci */
224062306a36Sopenharmony_cistatic unsigned qh_completions(struct fotg210_hcd *fotg210,
224162306a36Sopenharmony_ci		struct fotg210_qh *qh)
224262306a36Sopenharmony_ci{
224362306a36Sopenharmony_ci	struct fotg210_qtd *last, *end = qh->dummy;
224462306a36Sopenharmony_ci	struct fotg210_qtd *qtd, *tmp;
224562306a36Sopenharmony_ci	int last_status;
224662306a36Sopenharmony_ci	int stopped;
224762306a36Sopenharmony_ci	unsigned count = 0;
224862306a36Sopenharmony_ci	u8 state;
224962306a36Sopenharmony_ci	struct fotg210_qh_hw *hw = qh->hw;
225062306a36Sopenharmony_ci
225162306a36Sopenharmony_ci	if (unlikely(list_empty(&qh->qtd_list)))
225262306a36Sopenharmony_ci		return count;
225362306a36Sopenharmony_ci
225462306a36Sopenharmony_ci	/* completions (or tasks on other cpus) must never clobber HALT
225562306a36Sopenharmony_ci	 * till we've gone through and cleaned everything up, even when
225662306a36Sopenharmony_ci	 * they add urbs to this qh's queue or mark them for unlinking.
225762306a36Sopenharmony_ci	 *
225862306a36Sopenharmony_ci	 * NOTE:  unlinking expects to be done in queue order.
225962306a36Sopenharmony_ci	 *
226062306a36Sopenharmony_ci	 * It's a bug for qh->qh_state to be anything other than
226162306a36Sopenharmony_ci	 * QH_STATE_IDLE, unless our caller is scan_async() or
226262306a36Sopenharmony_ci	 * scan_intr().
226362306a36Sopenharmony_ci	 */
226462306a36Sopenharmony_ci	state = qh->qh_state;
226562306a36Sopenharmony_ci	qh->qh_state = QH_STATE_COMPLETING;
226662306a36Sopenharmony_ci	stopped = (state == QH_STATE_IDLE);
226762306a36Sopenharmony_ci
226862306a36Sopenharmony_cirescan:
226962306a36Sopenharmony_ci	last = NULL;
227062306a36Sopenharmony_ci	last_status = -EINPROGRESS;
227162306a36Sopenharmony_ci	qh->needs_rescan = 0;
227262306a36Sopenharmony_ci
227362306a36Sopenharmony_ci	/* remove de-activated QTDs from front of queue.
227462306a36Sopenharmony_ci	 * after faults (including short reads), cleanup this urb
227562306a36Sopenharmony_ci	 * then let the queue advance.
227662306a36Sopenharmony_ci	 * if queue is stopped, handles unlinks.
227762306a36Sopenharmony_ci	 */
227862306a36Sopenharmony_ci	list_for_each_entry_safe(qtd, tmp, &qh->qtd_list, qtd_list) {
227962306a36Sopenharmony_ci		struct urb *urb;
228062306a36Sopenharmony_ci		u32 token = 0;
228162306a36Sopenharmony_ci
228262306a36Sopenharmony_ci		urb = qtd->urb;
228362306a36Sopenharmony_ci
228462306a36Sopenharmony_ci		/* clean up any state from previous QTD ...*/
228562306a36Sopenharmony_ci		if (last) {
228662306a36Sopenharmony_ci			if (likely(last->urb != urb)) {
228762306a36Sopenharmony_ci				fotg210_urb_done(fotg210, last->urb,
228862306a36Sopenharmony_ci						last_status);
228962306a36Sopenharmony_ci				count++;
229062306a36Sopenharmony_ci				last_status = -EINPROGRESS;
229162306a36Sopenharmony_ci			}
229262306a36Sopenharmony_ci			fotg210_qtd_free(fotg210, last);
229362306a36Sopenharmony_ci			last = NULL;
229462306a36Sopenharmony_ci		}
229562306a36Sopenharmony_ci
229662306a36Sopenharmony_ci		/* ignore urbs submitted during completions we reported */
229762306a36Sopenharmony_ci		if (qtd == end)
229862306a36Sopenharmony_ci			break;
229962306a36Sopenharmony_ci
230062306a36Sopenharmony_ci		/* hardware copies qtd out of qh overlay */
230162306a36Sopenharmony_ci		rmb();
230262306a36Sopenharmony_ci		token = hc32_to_cpu(fotg210, qtd->hw_token);
230362306a36Sopenharmony_ci
230462306a36Sopenharmony_ci		/* always clean up qtds the hc de-activated */
230562306a36Sopenharmony_ciretry_xacterr:
230662306a36Sopenharmony_ci		if ((token & QTD_STS_ACTIVE) == 0) {
230762306a36Sopenharmony_ci
230862306a36Sopenharmony_ci			/* Report Data Buffer Error: non-fatal but useful */
230962306a36Sopenharmony_ci			if (token & QTD_STS_DBE)
231062306a36Sopenharmony_ci				fotg210_dbg(fotg210,
231162306a36Sopenharmony_ci					"detected DataBufferErr for urb %p ep%d%s len %d, qtd %p [qh %p]\n",
231262306a36Sopenharmony_ci					urb, usb_endpoint_num(&urb->ep->desc),
231362306a36Sopenharmony_ci					usb_endpoint_dir_in(&urb->ep->desc)
231462306a36Sopenharmony_ci						? "in" : "out",
231562306a36Sopenharmony_ci					urb->transfer_buffer_length, qtd, qh);
231662306a36Sopenharmony_ci
231762306a36Sopenharmony_ci			/* on STALL, error, and short reads this urb must
231862306a36Sopenharmony_ci			 * complete and all its qtds must be recycled.
231962306a36Sopenharmony_ci			 */
232062306a36Sopenharmony_ci			if ((token & QTD_STS_HALT) != 0) {
232162306a36Sopenharmony_ci
232262306a36Sopenharmony_ci				/* retry transaction errors until we
232362306a36Sopenharmony_ci				 * reach the software xacterr limit
232462306a36Sopenharmony_ci				 */
232562306a36Sopenharmony_ci				if ((token & QTD_STS_XACT) &&
232662306a36Sopenharmony_ci						QTD_CERR(token) == 0 &&
232762306a36Sopenharmony_ci						++qh->xacterrs < QH_XACTERR_MAX &&
232862306a36Sopenharmony_ci						!urb->unlinked) {
232962306a36Sopenharmony_ci					fotg210_dbg(fotg210,
233062306a36Sopenharmony_ci						"detected XactErr len %zu/%zu retry %d\n",
233162306a36Sopenharmony_ci						qtd->length - QTD_LENGTH(token),
233262306a36Sopenharmony_ci						qtd->length,
233362306a36Sopenharmony_ci						qh->xacterrs);
233462306a36Sopenharmony_ci
233562306a36Sopenharmony_ci					/* reset the token in the qtd and the
233662306a36Sopenharmony_ci					 * qh overlay (which still contains
233762306a36Sopenharmony_ci					 * the qtd) so that we pick up from
233862306a36Sopenharmony_ci					 * where we left off
233962306a36Sopenharmony_ci					 */
234062306a36Sopenharmony_ci					token &= ~QTD_STS_HALT;
234162306a36Sopenharmony_ci					token |= QTD_STS_ACTIVE |
234262306a36Sopenharmony_ci						 (FOTG210_TUNE_CERR << 10);
234362306a36Sopenharmony_ci					qtd->hw_token = cpu_to_hc32(fotg210,
234462306a36Sopenharmony_ci							token);
234562306a36Sopenharmony_ci					wmb();
234662306a36Sopenharmony_ci					hw->hw_token = cpu_to_hc32(fotg210,
234762306a36Sopenharmony_ci							token);
234862306a36Sopenharmony_ci					goto retry_xacterr;
234962306a36Sopenharmony_ci				}
235062306a36Sopenharmony_ci				stopped = 1;
235162306a36Sopenharmony_ci
235262306a36Sopenharmony_ci			/* magic dummy for some short reads; qh won't advance.
235362306a36Sopenharmony_ci			 * that silicon quirk can kick in with this dummy too.
235462306a36Sopenharmony_ci			 *
235562306a36Sopenharmony_ci			 * other short reads won't stop the queue, including
235662306a36Sopenharmony_ci			 * control transfers (status stage handles that) or
235762306a36Sopenharmony_ci			 * most other single-qtd reads ... the queue stops if
235862306a36Sopenharmony_ci			 * URB_SHORT_NOT_OK was set so the driver submitting
235962306a36Sopenharmony_ci			 * the urbs could clean it up.
236062306a36Sopenharmony_ci			 */
236162306a36Sopenharmony_ci			} else if (IS_SHORT_READ(token) &&
236262306a36Sopenharmony_ci					!(qtd->hw_alt_next &
236362306a36Sopenharmony_ci					FOTG210_LIST_END(fotg210))) {
236462306a36Sopenharmony_ci				stopped = 1;
236562306a36Sopenharmony_ci			}
236662306a36Sopenharmony_ci
236762306a36Sopenharmony_ci		/* stop scanning when we reach qtds the hc is using */
236862306a36Sopenharmony_ci		} else if (likely(!stopped
236962306a36Sopenharmony_ci				&& fotg210->rh_state >= FOTG210_RH_RUNNING)) {
237062306a36Sopenharmony_ci			break;
237162306a36Sopenharmony_ci
237262306a36Sopenharmony_ci		/* scan the whole queue for unlinks whenever it stops */
237362306a36Sopenharmony_ci		} else {
237462306a36Sopenharmony_ci			stopped = 1;
237562306a36Sopenharmony_ci
237662306a36Sopenharmony_ci			/* cancel everything if we halt, suspend, etc */
237762306a36Sopenharmony_ci			if (fotg210->rh_state < FOTG210_RH_RUNNING)
237862306a36Sopenharmony_ci				last_status = -ESHUTDOWN;
237962306a36Sopenharmony_ci
238062306a36Sopenharmony_ci			/* this qtd is active; skip it unless a previous qtd
238162306a36Sopenharmony_ci			 * for its urb faulted, or its urb was canceled.
238262306a36Sopenharmony_ci			 */
238362306a36Sopenharmony_ci			else if (last_status == -EINPROGRESS && !urb->unlinked)
238462306a36Sopenharmony_ci				continue;
238562306a36Sopenharmony_ci
238662306a36Sopenharmony_ci			/* qh unlinked; token in overlay may be most current */
238762306a36Sopenharmony_ci			if (state == QH_STATE_IDLE &&
238862306a36Sopenharmony_ci					cpu_to_hc32(fotg210, qtd->qtd_dma)
238962306a36Sopenharmony_ci					== hw->hw_current) {
239062306a36Sopenharmony_ci				token = hc32_to_cpu(fotg210, hw->hw_token);
239162306a36Sopenharmony_ci
239262306a36Sopenharmony_ci				/* An unlink may leave an incomplete
239362306a36Sopenharmony_ci				 * async transaction in the TT buffer.
239462306a36Sopenharmony_ci				 * We have to clear it.
239562306a36Sopenharmony_ci				 */
239662306a36Sopenharmony_ci				fotg210_clear_tt_buffer(fotg210, qh, urb,
239762306a36Sopenharmony_ci						token);
239862306a36Sopenharmony_ci			}
239962306a36Sopenharmony_ci		}
240062306a36Sopenharmony_ci
240162306a36Sopenharmony_ci		/* unless we already know the urb's status, collect qtd status
240262306a36Sopenharmony_ci		 * and update count of bytes transferred.  in common short read
240362306a36Sopenharmony_ci		 * cases with only one data qtd (including control transfers),
240462306a36Sopenharmony_ci		 * queue processing won't halt.  but with two or more qtds (for
240562306a36Sopenharmony_ci		 * example, with a 32 KB transfer), when the first qtd gets a
240662306a36Sopenharmony_ci		 * short read the second must be removed by hand.
240762306a36Sopenharmony_ci		 */
240862306a36Sopenharmony_ci		if (last_status == -EINPROGRESS) {
240962306a36Sopenharmony_ci			last_status = qtd_copy_status(fotg210, urb,
241062306a36Sopenharmony_ci					qtd->length, token);
241162306a36Sopenharmony_ci			if (last_status == -EREMOTEIO &&
241262306a36Sopenharmony_ci					(qtd->hw_alt_next &
241362306a36Sopenharmony_ci					FOTG210_LIST_END(fotg210)))
241462306a36Sopenharmony_ci				last_status = -EINPROGRESS;
241562306a36Sopenharmony_ci
241662306a36Sopenharmony_ci			/* As part of low/full-speed endpoint-halt processing
241762306a36Sopenharmony_ci			 * we must clear the TT buffer (11.17.5).
241862306a36Sopenharmony_ci			 */
241962306a36Sopenharmony_ci			if (unlikely(last_status != -EINPROGRESS &&
242062306a36Sopenharmony_ci					last_status != -EREMOTEIO)) {
242162306a36Sopenharmony_ci				/* The TT's in some hubs malfunction when they
242262306a36Sopenharmony_ci				 * receive this request following a STALL (they
242362306a36Sopenharmony_ci				 * stop sending isochronous packets).  Since a
242462306a36Sopenharmony_ci				 * STALL can't leave the TT buffer in a busy
242562306a36Sopenharmony_ci				 * state (if you believe Figures 11-48 - 11-51
242662306a36Sopenharmony_ci				 * in the USB 2.0 spec), we won't clear the TT
242762306a36Sopenharmony_ci				 * buffer in this case.  Strictly speaking this
242862306a36Sopenharmony_ci				 * is a violation of the spec.
242962306a36Sopenharmony_ci				 */
243062306a36Sopenharmony_ci				if (last_status != -EPIPE)
243162306a36Sopenharmony_ci					fotg210_clear_tt_buffer(fotg210, qh,
243262306a36Sopenharmony_ci							urb, token);
243362306a36Sopenharmony_ci			}
243462306a36Sopenharmony_ci		}
243562306a36Sopenharmony_ci
243662306a36Sopenharmony_ci		/* if we're removing something not at the queue head,
243762306a36Sopenharmony_ci		 * patch the hardware queue pointer.
243862306a36Sopenharmony_ci		 */
243962306a36Sopenharmony_ci		if (stopped && qtd->qtd_list.prev != &qh->qtd_list) {
244062306a36Sopenharmony_ci			last = list_entry(qtd->qtd_list.prev,
244162306a36Sopenharmony_ci					struct fotg210_qtd, qtd_list);
244262306a36Sopenharmony_ci			last->hw_next = qtd->hw_next;
244362306a36Sopenharmony_ci		}
244462306a36Sopenharmony_ci
244562306a36Sopenharmony_ci		/* remove qtd; it's recycled after possible urb completion */
244662306a36Sopenharmony_ci		list_del(&qtd->qtd_list);
244762306a36Sopenharmony_ci		last = qtd;
244862306a36Sopenharmony_ci
244962306a36Sopenharmony_ci		/* reinit the xacterr counter for the next qtd */
245062306a36Sopenharmony_ci		qh->xacterrs = 0;
245162306a36Sopenharmony_ci	}
245262306a36Sopenharmony_ci
245362306a36Sopenharmony_ci	/* last urb's completion might still need calling */
245462306a36Sopenharmony_ci	if (likely(last != NULL)) {
245562306a36Sopenharmony_ci		fotg210_urb_done(fotg210, last->urb, last_status);
245662306a36Sopenharmony_ci		count++;
245762306a36Sopenharmony_ci		fotg210_qtd_free(fotg210, last);
245862306a36Sopenharmony_ci	}
245962306a36Sopenharmony_ci
246062306a36Sopenharmony_ci	/* Do we need to rescan for URBs dequeued during a giveback? */
246162306a36Sopenharmony_ci	if (unlikely(qh->needs_rescan)) {
246262306a36Sopenharmony_ci		/* If the QH is already unlinked, do the rescan now. */
246362306a36Sopenharmony_ci		if (state == QH_STATE_IDLE)
246462306a36Sopenharmony_ci			goto rescan;
246562306a36Sopenharmony_ci
246662306a36Sopenharmony_ci		/* Otherwise we have to wait until the QH is fully unlinked.
246762306a36Sopenharmony_ci		 * Our caller will start an unlink if qh->needs_rescan is
246862306a36Sopenharmony_ci		 * set.  But if an unlink has already started, nothing needs
246962306a36Sopenharmony_ci		 * to be done.
247062306a36Sopenharmony_ci		 */
247162306a36Sopenharmony_ci		if (state != QH_STATE_LINKED)
247262306a36Sopenharmony_ci			qh->needs_rescan = 0;
247362306a36Sopenharmony_ci	}
247462306a36Sopenharmony_ci
247562306a36Sopenharmony_ci	/* restore original state; caller must unlink or relink */
247662306a36Sopenharmony_ci	qh->qh_state = state;
247762306a36Sopenharmony_ci
247862306a36Sopenharmony_ci	/* be sure the hardware's done with the qh before refreshing
247962306a36Sopenharmony_ci	 * it after fault cleanup, or recovering from silicon wrongly
248062306a36Sopenharmony_ci	 * overlaying the dummy qtd (which reduces DMA chatter).
248162306a36Sopenharmony_ci	 */
248262306a36Sopenharmony_ci	if (stopped != 0 || hw->hw_qtd_next == FOTG210_LIST_END(fotg210)) {
248362306a36Sopenharmony_ci		switch (state) {
248462306a36Sopenharmony_ci		case QH_STATE_IDLE:
248562306a36Sopenharmony_ci			qh_refresh(fotg210, qh);
248662306a36Sopenharmony_ci			break;
248762306a36Sopenharmony_ci		case QH_STATE_LINKED:
248862306a36Sopenharmony_ci			/* We won't refresh a QH that's linked (after the HC
248962306a36Sopenharmony_ci			 * stopped the queue).  That avoids a race:
249062306a36Sopenharmony_ci			 *  - HC reads first part of QH;
249162306a36Sopenharmony_ci			 *  - CPU updates that first part and the token;
249262306a36Sopenharmony_ci			 *  - HC reads rest of that QH, including token
249362306a36Sopenharmony_ci			 * Result:  HC gets an inconsistent image, and then
249462306a36Sopenharmony_ci			 * DMAs to/from the wrong memory (corrupting it).
249562306a36Sopenharmony_ci			 *
249662306a36Sopenharmony_ci			 * That should be rare for interrupt transfers,
249762306a36Sopenharmony_ci			 * except maybe high bandwidth ...
249862306a36Sopenharmony_ci			 */
249962306a36Sopenharmony_ci
250062306a36Sopenharmony_ci			/* Tell the caller to start an unlink */
250162306a36Sopenharmony_ci			qh->needs_rescan = 1;
250262306a36Sopenharmony_ci			break;
250362306a36Sopenharmony_ci		/* otherwise, unlink already started */
250462306a36Sopenharmony_ci		}
250562306a36Sopenharmony_ci	}
250662306a36Sopenharmony_ci
250762306a36Sopenharmony_ci	return count;
250862306a36Sopenharmony_ci}
250962306a36Sopenharmony_ci
251062306a36Sopenharmony_ci/* reverse of qh_urb_transaction:  free a list of TDs.
251162306a36Sopenharmony_ci * used for cleanup after errors, before HC sees an URB's TDs.
251262306a36Sopenharmony_ci */
251362306a36Sopenharmony_cistatic void qtd_list_free(struct fotg210_hcd *fotg210, struct urb *urb,
251462306a36Sopenharmony_ci		struct list_head *head)
251562306a36Sopenharmony_ci{
251662306a36Sopenharmony_ci	struct fotg210_qtd *qtd, *temp;
251762306a36Sopenharmony_ci
251862306a36Sopenharmony_ci	list_for_each_entry_safe(qtd, temp, head, qtd_list) {
251962306a36Sopenharmony_ci		list_del(&qtd->qtd_list);
252062306a36Sopenharmony_ci		fotg210_qtd_free(fotg210, qtd);
252162306a36Sopenharmony_ci	}
252262306a36Sopenharmony_ci}
252362306a36Sopenharmony_ci
252462306a36Sopenharmony_ci/* create a list of filled qtds for this URB; won't link into qh.
252562306a36Sopenharmony_ci */
252662306a36Sopenharmony_cistatic struct list_head *qh_urb_transaction(struct fotg210_hcd *fotg210,
252762306a36Sopenharmony_ci		struct urb *urb, struct list_head *head, gfp_t flags)
252862306a36Sopenharmony_ci{
252962306a36Sopenharmony_ci	struct fotg210_qtd *qtd, *qtd_prev;
253062306a36Sopenharmony_ci	dma_addr_t buf;
253162306a36Sopenharmony_ci	int len, this_sg_len, maxpacket;
253262306a36Sopenharmony_ci	int is_input;
253362306a36Sopenharmony_ci	u32 token;
253462306a36Sopenharmony_ci	int i;
253562306a36Sopenharmony_ci	struct scatterlist *sg;
253662306a36Sopenharmony_ci
253762306a36Sopenharmony_ci	/*
253862306a36Sopenharmony_ci	 * URBs map to sequences of QTDs:  one logical transaction
253962306a36Sopenharmony_ci	 */
254062306a36Sopenharmony_ci	qtd = fotg210_qtd_alloc(fotg210, flags);
254162306a36Sopenharmony_ci	if (unlikely(!qtd))
254262306a36Sopenharmony_ci		return NULL;
254362306a36Sopenharmony_ci	list_add_tail(&qtd->qtd_list, head);
254462306a36Sopenharmony_ci	qtd->urb = urb;
254562306a36Sopenharmony_ci
254662306a36Sopenharmony_ci	token = QTD_STS_ACTIVE;
254762306a36Sopenharmony_ci	token |= (FOTG210_TUNE_CERR << 10);
254862306a36Sopenharmony_ci	/* for split transactions, SplitXState initialized to zero */
254962306a36Sopenharmony_ci
255062306a36Sopenharmony_ci	len = urb->transfer_buffer_length;
255162306a36Sopenharmony_ci	is_input = usb_pipein(urb->pipe);
255262306a36Sopenharmony_ci	if (usb_pipecontrol(urb->pipe)) {
255362306a36Sopenharmony_ci		/* SETUP pid */
255462306a36Sopenharmony_ci		qtd_fill(fotg210, qtd, urb->setup_dma,
255562306a36Sopenharmony_ci				sizeof(struct usb_ctrlrequest),
255662306a36Sopenharmony_ci				token | (2 /* "setup" */ << 8), 8);
255762306a36Sopenharmony_ci
255862306a36Sopenharmony_ci		/* ... and always at least one more pid */
255962306a36Sopenharmony_ci		token ^= QTD_TOGGLE;
256062306a36Sopenharmony_ci		qtd_prev = qtd;
256162306a36Sopenharmony_ci		qtd = fotg210_qtd_alloc(fotg210, flags);
256262306a36Sopenharmony_ci		if (unlikely(!qtd))
256362306a36Sopenharmony_ci			goto cleanup;
256462306a36Sopenharmony_ci		qtd->urb = urb;
256562306a36Sopenharmony_ci		qtd_prev->hw_next = QTD_NEXT(fotg210, qtd->qtd_dma);
256662306a36Sopenharmony_ci		list_add_tail(&qtd->qtd_list, head);
256762306a36Sopenharmony_ci
256862306a36Sopenharmony_ci		/* for zero length DATA stages, STATUS is always IN */
256962306a36Sopenharmony_ci		if (len == 0)
257062306a36Sopenharmony_ci			token |= (1 /* "in" */ << 8);
257162306a36Sopenharmony_ci	}
257262306a36Sopenharmony_ci
257362306a36Sopenharmony_ci	/*
257462306a36Sopenharmony_ci	 * data transfer stage:  buffer setup
257562306a36Sopenharmony_ci	 */
257662306a36Sopenharmony_ci	i = urb->num_mapped_sgs;
257762306a36Sopenharmony_ci	if (len > 0 && i > 0) {
257862306a36Sopenharmony_ci		sg = urb->sg;
257962306a36Sopenharmony_ci		buf = sg_dma_address(sg);
258062306a36Sopenharmony_ci
258162306a36Sopenharmony_ci		/* urb->transfer_buffer_length may be smaller than the
258262306a36Sopenharmony_ci		 * size of the scatterlist (or vice versa)
258362306a36Sopenharmony_ci		 */
258462306a36Sopenharmony_ci		this_sg_len = min_t(int, sg_dma_len(sg), len);
258562306a36Sopenharmony_ci	} else {
258662306a36Sopenharmony_ci		sg = NULL;
258762306a36Sopenharmony_ci		buf = urb->transfer_dma;
258862306a36Sopenharmony_ci		this_sg_len = len;
258962306a36Sopenharmony_ci	}
259062306a36Sopenharmony_ci
259162306a36Sopenharmony_ci	if (is_input)
259262306a36Sopenharmony_ci		token |= (1 /* "in" */ << 8);
259362306a36Sopenharmony_ci	/* else it's already initted to "out" pid (0 << 8) */
259462306a36Sopenharmony_ci
259562306a36Sopenharmony_ci	maxpacket = usb_maxpacket(urb->dev, urb->pipe);
259662306a36Sopenharmony_ci
259762306a36Sopenharmony_ci	/*
259862306a36Sopenharmony_ci	 * buffer gets wrapped in one or more qtds;
259962306a36Sopenharmony_ci	 * last one may be "short" (including zero len)
260062306a36Sopenharmony_ci	 * and may serve as a control status ack
260162306a36Sopenharmony_ci	 */
260262306a36Sopenharmony_ci	for (;;) {
260362306a36Sopenharmony_ci		int this_qtd_len;
260462306a36Sopenharmony_ci
260562306a36Sopenharmony_ci		this_qtd_len = qtd_fill(fotg210, qtd, buf, this_sg_len, token,
260662306a36Sopenharmony_ci				maxpacket);
260762306a36Sopenharmony_ci		this_sg_len -= this_qtd_len;
260862306a36Sopenharmony_ci		len -= this_qtd_len;
260962306a36Sopenharmony_ci		buf += this_qtd_len;
261062306a36Sopenharmony_ci
261162306a36Sopenharmony_ci		/*
261262306a36Sopenharmony_ci		 * short reads advance to a "magic" dummy instead of the next
261362306a36Sopenharmony_ci		 * qtd ... that forces the queue to stop, for manual cleanup.
261462306a36Sopenharmony_ci		 * (this will usually be overridden later.)
261562306a36Sopenharmony_ci		 */
261662306a36Sopenharmony_ci		if (is_input)
261762306a36Sopenharmony_ci			qtd->hw_alt_next = fotg210->async->hw->hw_alt_next;
261862306a36Sopenharmony_ci
261962306a36Sopenharmony_ci		/* qh makes control packets use qtd toggle; maybe switch it */
262062306a36Sopenharmony_ci		if ((maxpacket & (this_qtd_len + (maxpacket - 1))) == 0)
262162306a36Sopenharmony_ci			token ^= QTD_TOGGLE;
262262306a36Sopenharmony_ci
262362306a36Sopenharmony_ci		if (likely(this_sg_len <= 0)) {
262462306a36Sopenharmony_ci			if (--i <= 0 || len <= 0)
262562306a36Sopenharmony_ci				break;
262662306a36Sopenharmony_ci			sg = sg_next(sg);
262762306a36Sopenharmony_ci			buf = sg_dma_address(sg);
262862306a36Sopenharmony_ci			this_sg_len = min_t(int, sg_dma_len(sg), len);
262962306a36Sopenharmony_ci		}
263062306a36Sopenharmony_ci
263162306a36Sopenharmony_ci		qtd_prev = qtd;
263262306a36Sopenharmony_ci		qtd = fotg210_qtd_alloc(fotg210, flags);
263362306a36Sopenharmony_ci		if (unlikely(!qtd))
263462306a36Sopenharmony_ci			goto cleanup;
263562306a36Sopenharmony_ci		qtd->urb = urb;
263662306a36Sopenharmony_ci		qtd_prev->hw_next = QTD_NEXT(fotg210, qtd->qtd_dma);
263762306a36Sopenharmony_ci		list_add_tail(&qtd->qtd_list, head);
263862306a36Sopenharmony_ci	}
263962306a36Sopenharmony_ci
264062306a36Sopenharmony_ci	/*
264162306a36Sopenharmony_ci	 * unless the caller requires manual cleanup after short reads,
264262306a36Sopenharmony_ci	 * have the alt_next mechanism keep the queue running after the
264362306a36Sopenharmony_ci	 * last data qtd (the only one, for control and most other cases).
264462306a36Sopenharmony_ci	 */
264562306a36Sopenharmony_ci	if (likely((urb->transfer_flags & URB_SHORT_NOT_OK) == 0 ||
264662306a36Sopenharmony_ci			usb_pipecontrol(urb->pipe)))
264762306a36Sopenharmony_ci		qtd->hw_alt_next = FOTG210_LIST_END(fotg210);
264862306a36Sopenharmony_ci
264962306a36Sopenharmony_ci	/*
265062306a36Sopenharmony_ci	 * control requests may need a terminating data "status" ack;
265162306a36Sopenharmony_ci	 * other OUT ones may need a terminating short packet
265262306a36Sopenharmony_ci	 * (zero length).
265362306a36Sopenharmony_ci	 */
265462306a36Sopenharmony_ci	if (likely(urb->transfer_buffer_length != 0)) {
265562306a36Sopenharmony_ci		int one_more = 0;
265662306a36Sopenharmony_ci
265762306a36Sopenharmony_ci		if (usb_pipecontrol(urb->pipe)) {
265862306a36Sopenharmony_ci			one_more = 1;
265962306a36Sopenharmony_ci			token ^= 0x0100;	/* "in" <--> "out"  */
266062306a36Sopenharmony_ci			token |= QTD_TOGGLE;	/* force DATA1 */
266162306a36Sopenharmony_ci		} else if (usb_pipeout(urb->pipe)
266262306a36Sopenharmony_ci				&& (urb->transfer_flags & URB_ZERO_PACKET)
266362306a36Sopenharmony_ci				&& !(urb->transfer_buffer_length % maxpacket)) {
266462306a36Sopenharmony_ci			one_more = 1;
266562306a36Sopenharmony_ci		}
266662306a36Sopenharmony_ci		if (one_more) {
266762306a36Sopenharmony_ci			qtd_prev = qtd;
266862306a36Sopenharmony_ci			qtd = fotg210_qtd_alloc(fotg210, flags);
266962306a36Sopenharmony_ci			if (unlikely(!qtd))
267062306a36Sopenharmony_ci				goto cleanup;
267162306a36Sopenharmony_ci			qtd->urb = urb;
267262306a36Sopenharmony_ci			qtd_prev->hw_next = QTD_NEXT(fotg210, qtd->qtd_dma);
267362306a36Sopenharmony_ci			list_add_tail(&qtd->qtd_list, head);
267462306a36Sopenharmony_ci
267562306a36Sopenharmony_ci			/* never any data in such packets */
267662306a36Sopenharmony_ci			qtd_fill(fotg210, qtd, 0, 0, token, 0);
267762306a36Sopenharmony_ci		}
267862306a36Sopenharmony_ci	}
267962306a36Sopenharmony_ci
268062306a36Sopenharmony_ci	/* by default, enable interrupt on urb completion */
268162306a36Sopenharmony_ci	if (likely(!(urb->transfer_flags & URB_NO_INTERRUPT)))
268262306a36Sopenharmony_ci		qtd->hw_token |= cpu_to_hc32(fotg210, QTD_IOC);
268362306a36Sopenharmony_ci	return head;
268462306a36Sopenharmony_ci
268562306a36Sopenharmony_cicleanup:
268662306a36Sopenharmony_ci	qtd_list_free(fotg210, urb, head);
268762306a36Sopenharmony_ci	return NULL;
268862306a36Sopenharmony_ci}
268962306a36Sopenharmony_ci
269062306a36Sopenharmony_ci/* Would be best to create all qh's from config descriptors,
269162306a36Sopenharmony_ci * when each interface/altsetting is established.  Unlink
269262306a36Sopenharmony_ci * any previous qh and cancel its urbs first; endpoints are
269362306a36Sopenharmony_ci * implicitly reset then (data toggle too).
269462306a36Sopenharmony_ci * That'd mean updating how usbcore talks to HCDs. (2.7?)
269562306a36Sopenharmony_ci */
269662306a36Sopenharmony_ci
269762306a36Sopenharmony_ci
269862306a36Sopenharmony_ci/* Each QH holds a qtd list; a QH is used for everything except iso.
269962306a36Sopenharmony_ci *
270062306a36Sopenharmony_ci * For interrupt urbs, the scheduler must set the microframe scheduling
270162306a36Sopenharmony_ci * mask(s) each time the QH gets scheduled.  For highspeed, that's
270262306a36Sopenharmony_ci * just one microframe in the s-mask.  For split interrupt transactions
270362306a36Sopenharmony_ci * there are additional complications: c-mask, maybe FSTNs.
270462306a36Sopenharmony_ci */
270562306a36Sopenharmony_cistatic struct fotg210_qh *qh_make(struct fotg210_hcd *fotg210, struct urb *urb,
270662306a36Sopenharmony_ci		gfp_t flags)
270762306a36Sopenharmony_ci{
270862306a36Sopenharmony_ci	struct fotg210_qh *qh = fotg210_qh_alloc(fotg210, flags);
270962306a36Sopenharmony_ci	struct usb_host_endpoint *ep;
271062306a36Sopenharmony_ci	u32 info1 = 0, info2 = 0;
271162306a36Sopenharmony_ci	int is_input, type;
271262306a36Sopenharmony_ci	int maxp = 0;
271362306a36Sopenharmony_ci	int mult;
271462306a36Sopenharmony_ci	struct usb_tt *tt = urb->dev->tt;
271562306a36Sopenharmony_ci	struct fotg210_qh_hw *hw;
271662306a36Sopenharmony_ci
271762306a36Sopenharmony_ci	if (!qh)
271862306a36Sopenharmony_ci		return qh;
271962306a36Sopenharmony_ci
272062306a36Sopenharmony_ci	/*
272162306a36Sopenharmony_ci	 * init endpoint/device data for this QH
272262306a36Sopenharmony_ci	 */
272362306a36Sopenharmony_ci	info1 |= usb_pipeendpoint(urb->pipe) << 8;
272462306a36Sopenharmony_ci	info1 |= usb_pipedevice(urb->pipe) << 0;
272562306a36Sopenharmony_ci
272662306a36Sopenharmony_ci	is_input = usb_pipein(urb->pipe);
272762306a36Sopenharmony_ci	type = usb_pipetype(urb->pipe);
272862306a36Sopenharmony_ci	ep = usb_pipe_endpoint(urb->dev, urb->pipe);
272962306a36Sopenharmony_ci	maxp = usb_endpoint_maxp(&ep->desc);
273062306a36Sopenharmony_ci	mult = usb_endpoint_maxp_mult(&ep->desc);
273162306a36Sopenharmony_ci
273262306a36Sopenharmony_ci	/* 1024 byte maxpacket is a hardware ceiling.  High bandwidth
273362306a36Sopenharmony_ci	 * acts like up to 3KB, but is built from smaller packets.
273462306a36Sopenharmony_ci	 */
273562306a36Sopenharmony_ci	if (maxp > 1024) {
273662306a36Sopenharmony_ci		fotg210_dbg(fotg210, "bogus qh maxpacket %d\n", maxp);
273762306a36Sopenharmony_ci		goto done;
273862306a36Sopenharmony_ci	}
273962306a36Sopenharmony_ci
274062306a36Sopenharmony_ci	/* Compute interrupt scheduling parameters just once, and save.
274162306a36Sopenharmony_ci	 * - allowing for high bandwidth, how many nsec/uframe are used?
274262306a36Sopenharmony_ci	 * - split transactions need a second CSPLIT uframe; same question
274362306a36Sopenharmony_ci	 * - splits also need a schedule gap (for full/low speed I/O)
274462306a36Sopenharmony_ci	 * - qh has a polling interval
274562306a36Sopenharmony_ci	 *
274662306a36Sopenharmony_ci	 * For control/bulk requests, the HC or TT handles these.
274762306a36Sopenharmony_ci	 */
274862306a36Sopenharmony_ci	if (type == PIPE_INTERRUPT) {
274962306a36Sopenharmony_ci		qh->usecs = NS_TO_US(usb_calc_bus_time(USB_SPEED_HIGH,
275062306a36Sopenharmony_ci				is_input, 0, mult * maxp));
275162306a36Sopenharmony_ci		qh->start = NO_FRAME;
275262306a36Sopenharmony_ci
275362306a36Sopenharmony_ci		if (urb->dev->speed == USB_SPEED_HIGH) {
275462306a36Sopenharmony_ci			qh->c_usecs = 0;
275562306a36Sopenharmony_ci			qh->gap_uf = 0;
275662306a36Sopenharmony_ci
275762306a36Sopenharmony_ci			qh->period = urb->interval >> 3;
275862306a36Sopenharmony_ci			if (qh->period == 0 && urb->interval != 1) {
275962306a36Sopenharmony_ci				/* NOTE interval 2 or 4 uframes could work.
276062306a36Sopenharmony_ci				 * But interval 1 scheduling is simpler, and
276162306a36Sopenharmony_ci				 * includes high bandwidth.
276262306a36Sopenharmony_ci				 */
276362306a36Sopenharmony_ci				urb->interval = 1;
276462306a36Sopenharmony_ci			} else if (qh->period > fotg210->periodic_size) {
276562306a36Sopenharmony_ci				qh->period = fotg210->periodic_size;
276662306a36Sopenharmony_ci				urb->interval = qh->period << 3;
276762306a36Sopenharmony_ci			}
276862306a36Sopenharmony_ci		} else {
276962306a36Sopenharmony_ci			int think_time;
277062306a36Sopenharmony_ci
277162306a36Sopenharmony_ci			/* gap is f(FS/LS transfer times) */
277262306a36Sopenharmony_ci			qh->gap_uf = 1 + usb_calc_bus_time(urb->dev->speed,
277362306a36Sopenharmony_ci					is_input, 0, maxp) / (125 * 1000);
277462306a36Sopenharmony_ci
277562306a36Sopenharmony_ci			/* FIXME this just approximates SPLIT/CSPLIT times */
277662306a36Sopenharmony_ci			if (is_input) {		/* SPLIT, gap, CSPLIT+DATA */
277762306a36Sopenharmony_ci				qh->c_usecs = qh->usecs + HS_USECS(0);
277862306a36Sopenharmony_ci				qh->usecs = HS_USECS(1);
277962306a36Sopenharmony_ci			} else {		/* SPLIT+DATA, gap, CSPLIT */
278062306a36Sopenharmony_ci				qh->usecs += HS_USECS(1);
278162306a36Sopenharmony_ci				qh->c_usecs = HS_USECS(0);
278262306a36Sopenharmony_ci			}
278362306a36Sopenharmony_ci
278462306a36Sopenharmony_ci			think_time = tt ? tt->think_time : 0;
278562306a36Sopenharmony_ci			qh->tt_usecs = NS_TO_US(think_time +
278662306a36Sopenharmony_ci					usb_calc_bus_time(urb->dev->speed,
278762306a36Sopenharmony_ci					is_input, 0, maxp));
278862306a36Sopenharmony_ci			qh->period = urb->interval;
278962306a36Sopenharmony_ci			if (qh->period > fotg210->periodic_size) {
279062306a36Sopenharmony_ci				qh->period = fotg210->periodic_size;
279162306a36Sopenharmony_ci				urb->interval = qh->period;
279262306a36Sopenharmony_ci			}
279362306a36Sopenharmony_ci		}
279462306a36Sopenharmony_ci	}
279562306a36Sopenharmony_ci
279662306a36Sopenharmony_ci	/* support for tt scheduling, and access to toggles */
279762306a36Sopenharmony_ci	qh->dev = urb->dev;
279862306a36Sopenharmony_ci
279962306a36Sopenharmony_ci	/* using TT? */
280062306a36Sopenharmony_ci	switch (urb->dev->speed) {
280162306a36Sopenharmony_ci	case USB_SPEED_LOW:
280262306a36Sopenharmony_ci		info1 |= QH_LOW_SPEED;
280362306a36Sopenharmony_ci		fallthrough;
280462306a36Sopenharmony_ci
280562306a36Sopenharmony_ci	case USB_SPEED_FULL:
280662306a36Sopenharmony_ci		/* EPS 0 means "full" */
280762306a36Sopenharmony_ci		if (type != PIPE_INTERRUPT)
280862306a36Sopenharmony_ci			info1 |= (FOTG210_TUNE_RL_TT << 28);
280962306a36Sopenharmony_ci		if (type == PIPE_CONTROL) {
281062306a36Sopenharmony_ci			info1 |= QH_CONTROL_EP;		/* for TT */
281162306a36Sopenharmony_ci			info1 |= QH_TOGGLE_CTL;		/* toggle from qtd */
281262306a36Sopenharmony_ci		}
281362306a36Sopenharmony_ci		info1 |= maxp << 16;
281462306a36Sopenharmony_ci
281562306a36Sopenharmony_ci		info2 |= (FOTG210_TUNE_MULT_TT << 30);
281662306a36Sopenharmony_ci
281762306a36Sopenharmony_ci		/* Some Freescale processors have an erratum in which the
281862306a36Sopenharmony_ci		 * port number in the queue head was 0..N-1 instead of 1..N.
281962306a36Sopenharmony_ci		 */
282062306a36Sopenharmony_ci		if (fotg210_has_fsl_portno_bug(fotg210))
282162306a36Sopenharmony_ci			info2 |= (urb->dev->ttport-1) << 23;
282262306a36Sopenharmony_ci		else
282362306a36Sopenharmony_ci			info2 |= urb->dev->ttport << 23;
282462306a36Sopenharmony_ci
282562306a36Sopenharmony_ci		/* set the address of the TT; for TDI's integrated
282662306a36Sopenharmony_ci		 * root hub tt, leave it zeroed.
282762306a36Sopenharmony_ci		 */
282862306a36Sopenharmony_ci		if (tt && tt->hub != fotg210_to_hcd(fotg210)->self.root_hub)
282962306a36Sopenharmony_ci			info2 |= tt->hub->devnum << 16;
283062306a36Sopenharmony_ci
283162306a36Sopenharmony_ci		/* NOTE:  if (PIPE_INTERRUPT) { scheduler sets c-mask } */
283262306a36Sopenharmony_ci
283362306a36Sopenharmony_ci		break;
283462306a36Sopenharmony_ci
283562306a36Sopenharmony_ci	case USB_SPEED_HIGH:		/* no TT involved */
283662306a36Sopenharmony_ci		info1 |= QH_HIGH_SPEED;
283762306a36Sopenharmony_ci		if (type == PIPE_CONTROL) {
283862306a36Sopenharmony_ci			info1 |= (FOTG210_TUNE_RL_HS << 28);
283962306a36Sopenharmony_ci			info1 |= 64 << 16;	/* usb2 fixed maxpacket */
284062306a36Sopenharmony_ci			info1 |= QH_TOGGLE_CTL;	/* toggle from qtd */
284162306a36Sopenharmony_ci			info2 |= (FOTG210_TUNE_MULT_HS << 30);
284262306a36Sopenharmony_ci		} else if (type == PIPE_BULK) {
284362306a36Sopenharmony_ci			info1 |= (FOTG210_TUNE_RL_HS << 28);
284462306a36Sopenharmony_ci			/* The USB spec says that high speed bulk endpoints
284562306a36Sopenharmony_ci			 * always use 512 byte maxpacket.  But some device
284662306a36Sopenharmony_ci			 * vendors decided to ignore that, and MSFT is happy
284762306a36Sopenharmony_ci			 * to help them do so.  So now people expect to use
284862306a36Sopenharmony_ci			 * such nonconformant devices with Linux too; sigh.
284962306a36Sopenharmony_ci			 */
285062306a36Sopenharmony_ci			info1 |= maxp << 16;
285162306a36Sopenharmony_ci			info2 |= (FOTG210_TUNE_MULT_HS << 30);
285262306a36Sopenharmony_ci		} else {		/* PIPE_INTERRUPT */
285362306a36Sopenharmony_ci			info1 |= maxp << 16;
285462306a36Sopenharmony_ci			info2 |= mult << 30;
285562306a36Sopenharmony_ci		}
285662306a36Sopenharmony_ci		break;
285762306a36Sopenharmony_ci	default:
285862306a36Sopenharmony_ci		fotg210_dbg(fotg210, "bogus dev %p speed %d\n", urb->dev,
285962306a36Sopenharmony_ci				urb->dev->speed);
286062306a36Sopenharmony_cidone:
286162306a36Sopenharmony_ci		qh_destroy(fotg210, qh);
286262306a36Sopenharmony_ci		return NULL;
286362306a36Sopenharmony_ci	}
286462306a36Sopenharmony_ci
286562306a36Sopenharmony_ci	/* NOTE:  if (PIPE_INTERRUPT) { scheduler sets s-mask } */
286662306a36Sopenharmony_ci
286762306a36Sopenharmony_ci	/* init as live, toggle clear, advance to dummy */
286862306a36Sopenharmony_ci	qh->qh_state = QH_STATE_IDLE;
286962306a36Sopenharmony_ci	hw = qh->hw;
287062306a36Sopenharmony_ci	hw->hw_info1 = cpu_to_hc32(fotg210, info1);
287162306a36Sopenharmony_ci	hw->hw_info2 = cpu_to_hc32(fotg210, info2);
287262306a36Sopenharmony_ci	qh->is_out = !is_input;
287362306a36Sopenharmony_ci	usb_settoggle(urb->dev, usb_pipeendpoint(urb->pipe), !is_input, 1);
287462306a36Sopenharmony_ci	qh_refresh(fotg210, qh);
287562306a36Sopenharmony_ci	return qh;
287662306a36Sopenharmony_ci}
287762306a36Sopenharmony_ci
287862306a36Sopenharmony_cistatic void enable_async(struct fotg210_hcd *fotg210)
287962306a36Sopenharmony_ci{
288062306a36Sopenharmony_ci	if (fotg210->async_count++)
288162306a36Sopenharmony_ci		return;
288262306a36Sopenharmony_ci
288362306a36Sopenharmony_ci	/* Stop waiting to turn off the async schedule */
288462306a36Sopenharmony_ci	fotg210->enabled_hrtimer_events &= ~BIT(FOTG210_HRTIMER_DISABLE_ASYNC);
288562306a36Sopenharmony_ci
288662306a36Sopenharmony_ci	/* Don't start the schedule until ASS is 0 */
288762306a36Sopenharmony_ci	fotg210_poll_ASS(fotg210);
288862306a36Sopenharmony_ci	turn_on_io_watchdog(fotg210);
288962306a36Sopenharmony_ci}
289062306a36Sopenharmony_ci
289162306a36Sopenharmony_cistatic void disable_async(struct fotg210_hcd *fotg210)
289262306a36Sopenharmony_ci{
289362306a36Sopenharmony_ci	if (--fotg210->async_count)
289462306a36Sopenharmony_ci		return;
289562306a36Sopenharmony_ci
289662306a36Sopenharmony_ci	/* The async schedule and async_unlink list are supposed to be empty */
289762306a36Sopenharmony_ci	WARN_ON(fotg210->async->qh_next.qh || fotg210->async_unlink);
289862306a36Sopenharmony_ci
289962306a36Sopenharmony_ci	/* Don't turn off the schedule until ASS is 1 */
290062306a36Sopenharmony_ci	fotg210_poll_ASS(fotg210);
290162306a36Sopenharmony_ci}
290262306a36Sopenharmony_ci
290362306a36Sopenharmony_ci/* move qh (and its qtds) onto async queue; maybe enable queue.  */
290462306a36Sopenharmony_ci
290562306a36Sopenharmony_cistatic void qh_link_async(struct fotg210_hcd *fotg210, struct fotg210_qh *qh)
290662306a36Sopenharmony_ci{
290762306a36Sopenharmony_ci	__hc32 dma = QH_NEXT(fotg210, qh->qh_dma);
290862306a36Sopenharmony_ci	struct fotg210_qh *head;
290962306a36Sopenharmony_ci
291062306a36Sopenharmony_ci	/* Don't link a QH if there's a Clear-TT-Buffer pending */
291162306a36Sopenharmony_ci	if (unlikely(qh->clearing_tt))
291262306a36Sopenharmony_ci		return;
291362306a36Sopenharmony_ci
291462306a36Sopenharmony_ci	WARN_ON(qh->qh_state != QH_STATE_IDLE);
291562306a36Sopenharmony_ci
291662306a36Sopenharmony_ci	/* clear halt and/or toggle; and maybe recover from silicon quirk */
291762306a36Sopenharmony_ci	qh_refresh(fotg210, qh);
291862306a36Sopenharmony_ci
291962306a36Sopenharmony_ci	/* splice right after start */
292062306a36Sopenharmony_ci	head = fotg210->async;
292162306a36Sopenharmony_ci	qh->qh_next = head->qh_next;
292262306a36Sopenharmony_ci	qh->hw->hw_next = head->hw->hw_next;
292362306a36Sopenharmony_ci	wmb();
292462306a36Sopenharmony_ci
292562306a36Sopenharmony_ci	head->qh_next.qh = qh;
292662306a36Sopenharmony_ci	head->hw->hw_next = dma;
292762306a36Sopenharmony_ci
292862306a36Sopenharmony_ci	qh->xacterrs = 0;
292962306a36Sopenharmony_ci	qh->qh_state = QH_STATE_LINKED;
293062306a36Sopenharmony_ci	/* qtd completions reported later by interrupt */
293162306a36Sopenharmony_ci
293262306a36Sopenharmony_ci	enable_async(fotg210);
293362306a36Sopenharmony_ci}
293462306a36Sopenharmony_ci
293562306a36Sopenharmony_ci/* For control/bulk/interrupt, return QH with these TDs appended.
293662306a36Sopenharmony_ci * Allocates and initializes the QH if necessary.
293762306a36Sopenharmony_ci * Returns null if it can't allocate a QH it needs to.
293862306a36Sopenharmony_ci * If the QH has TDs (urbs) already, that's great.
293962306a36Sopenharmony_ci */
294062306a36Sopenharmony_cistatic struct fotg210_qh *qh_append_tds(struct fotg210_hcd *fotg210,
294162306a36Sopenharmony_ci		struct urb *urb, struct list_head *qtd_list,
294262306a36Sopenharmony_ci		int epnum, void **ptr)
294362306a36Sopenharmony_ci{
294462306a36Sopenharmony_ci	struct fotg210_qh *qh = NULL;
294562306a36Sopenharmony_ci	__hc32 qh_addr_mask = cpu_to_hc32(fotg210, 0x7f);
294662306a36Sopenharmony_ci
294762306a36Sopenharmony_ci	qh = (struct fotg210_qh *) *ptr;
294862306a36Sopenharmony_ci	if (unlikely(qh == NULL)) {
294962306a36Sopenharmony_ci		/* can't sleep here, we have fotg210->lock... */
295062306a36Sopenharmony_ci		qh = qh_make(fotg210, urb, GFP_ATOMIC);
295162306a36Sopenharmony_ci		*ptr = qh;
295262306a36Sopenharmony_ci	}
295362306a36Sopenharmony_ci	if (likely(qh != NULL)) {
295462306a36Sopenharmony_ci		struct fotg210_qtd *qtd;
295562306a36Sopenharmony_ci
295662306a36Sopenharmony_ci		if (unlikely(list_empty(qtd_list)))
295762306a36Sopenharmony_ci			qtd = NULL;
295862306a36Sopenharmony_ci		else
295962306a36Sopenharmony_ci			qtd = list_entry(qtd_list->next, struct fotg210_qtd,
296062306a36Sopenharmony_ci					qtd_list);
296162306a36Sopenharmony_ci
296262306a36Sopenharmony_ci		/* control qh may need patching ... */
296362306a36Sopenharmony_ci		if (unlikely(epnum == 0)) {
296462306a36Sopenharmony_ci			/* usb_reset_device() briefly reverts to address 0 */
296562306a36Sopenharmony_ci			if (usb_pipedevice(urb->pipe) == 0)
296662306a36Sopenharmony_ci				qh->hw->hw_info1 &= ~qh_addr_mask;
296762306a36Sopenharmony_ci		}
296862306a36Sopenharmony_ci
296962306a36Sopenharmony_ci		/* just one way to queue requests: swap with the dummy qtd.
297062306a36Sopenharmony_ci		 * only hc or qh_refresh() ever modify the overlay.
297162306a36Sopenharmony_ci		 */
297262306a36Sopenharmony_ci		if (likely(qtd != NULL)) {
297362306a36Sopenharmony_ci			struct fotg210_qtd *dummy;
297462306a36Sopenharmony_ci			dma_addr_t dma;
297562306a36Sopenharmony_ci			__hc32 token;
297662306a36Sopenharmony_ci
297762306a36Sopenharmony_ci			/* to avoid racing the HC, use the dummy td instead of
297862306a36Sopenharmony_ci			 * the first td of our list (becomes new dummy).  both
297962306a36Sopenharmony_ci			 * tds stay deactivated until we're done, when the
298062306a36Sopenharmony_ci			 * HC is allowed to fetch the old dummy (4.10.2).
298162306a36Sopenharmony_ci			 */
298262306a36Sopenharmony_ci			token = qtd->hw_token;
298362306a36Sopenharmony_ci			qtd->hw_token = HALT_BIT(fotg210);
298462306a36Sopenharmony_ci
298562306a36Sopenharmony_ci			dummy = qh->dummy;
298662306a36Sopenharmony_ci
298762306a36Sopenharmony_ci			dma = dummy->qtd_dma;
298862306a36Sopenharmony_ci			*dummy = *qtd;
298962306a36Sopenharmony_ci			dummy->qtd_dma = dma;
299062306a36Sopenharmony_ci
299162306a36Sopenharmony_ci			list_del(&qtd->qtd_list);
299262306a36Sopenharmony_ci			list_add(&dummy->qtd_list, qtd_list);
299362306a36Sopenharmony_ci			list_splice_tail(qtd_list, &qh->qtd_list);
299462306a36Sopenharmony_ci
299562306a36Sopenharmony_ci			fotg210_qtd_init(fotg210, qtd, qtd->qtd_dma);
299662306a36Sopenharmony_ci			qh->dummy = qtd;
299762306a36Sopenharmony_ci
299862306a36Sopenharmony_ci			/* hc must see the new dummy at list end */
299962306a36Sopenharmony_ci			dma = qtd->qtd_dma;
300062306a36Sopenharmony_ci			qtd = list_entry(qh->qtd_list.prev,
300162306a36Sopenharmony_ci					struct fotg210_qtd, qtd_list);
300262306a36Sopenharmony_ci			qtd->hw_next = QTD_NEXT(fotg210, dma);
300362306a36Sopenharmony_ci
300462306a36Sopenharmony_ci			/* let the hc process these next qtds */
300562306a36Sopenharmony_ci			wmb();
300662306a36Sopenharmony_ci			dummy->hw_token = token;
300762306a36Sopenharmony_ci
300862306a36Sopenharmony_ci			urb->hcpriv = qh;
300962306a36Sopenharmony_ci		}
301062306a36Sopenharmony_ci	}
301162306a36Sopenharmony_ci	return qh;
301262306a36Sopenharmony_ci}
301362306a36Sopenharmony_ci
301462306a36Sopenharmony_cistatic int submit_async(struct fotg210_hcd *fotg210, struct urb *urb,
301562306a36Sopenharmony_ci		struct list_head *qtd_list, gfp_t mem_flags)
301662306a36Sopenharmony_ci{
301762306a36Sopenharmony_ci	int epnum;
301862306a36Sopenharmony_ci	unsigned long flags;
301962306a36Sopenharmony_ci	struct fotg210_qh *qh = NULL;
302062306a36Sopenharmony_ci	int rc;
302162306a36Sopenharmony_ci
302262306a36Sopenharmony_ci	epnum = urb->ep->desc.bEndpointAddress;
302362306a36Sopenharmony_ci
302462306a36Sopenharmony_ci#ifdef FOTG210_URB_TRACE
302562306a36Sopenharmony_ci	{
302662306a36Sopenharmony_ci		struct fotg210_qtd *qtd;
302762306a36Sopenharmony_ci
302862306a36Sopenharmony_ci		qtd = list_entry(qtd_list->next, struct fotg210_qtd, qtd_list);
302962306a36Sopenharmony_ci		fotg210_dbg(fotg210,
303062306a36Sopenharmony_ci				"%s %s urb %p ep%d%s len %d, qtd %p [qh %p]\n",
303162306a36Sopenharmony_ci				__func__, urb->dev->devpath, urb,
303262306a36Sopenharmony_ci				epnum & 0x0f, (epnum & USB_DIR_IN)
303362306a36Sopenharmony_ci					? "in" : "out",
303462306a36Sopenharmony_ci				urb->transfer_buffer_length,
303562306a36Sopenharmony_ci				qtd, urb->ep->hcpriv);
303662306a36Sopenharmony_ci	}
303762306a36Sopenharmony_ci#endif
303862306a36Sopenharmony_ci
303962306a36Sopenharmony_ci	spin_lock_irqsave(&fotg210->lock, flags);
304062306a36Sopenharmony_ci	if (unlikely(!HCD_HW_ACCESSIBLE(fotg210_to_hcd(fotg210)))) {
304162306a36Sopenharmony_ci		rc = -ESHUTDOWN;
304262306a36Sopenharmony_ci		goto done;
304362306a36Sopenharmony_ci	}
304462306a36Sopenharmony_ci	rc = usb_hcd_link_urb_to_ep(fotg210_to_hcd(fotg210), urb);
304562306a36Sopenharmony_ci	if (unlikely(rc))
304662306a36Sopenharmony_ci		goto done;
304762306a36Sopenharmony_ci
304862306a36Sopenharmony_ci	qh = qh_append_tds(fotg210, urb, qtd_list, epnum, &urb->ep->hcpriv);
304962306a36Sopenharmony_ci	if (unlikely(qh == NULL)) {
305062306a36Sopenharmony_ci		usb_hcd_unlink_urb_from_ep(fotg210_to_hcd(fotg210), urb);
305162306a36Sopenharmony_ci		rc = -ENOMEM;
305262306a36Sopenharmony_ci		goto done;
305362306a36Sopenharmony_ci	}
305462306a36Sopenharmony_ci
305562306a36Sopenharmony_ci	/* Control/bulk operations through TTs don't need scheduling,
305662306a36Sopenharmony_ci	 * the HC and TT handle it when the TT has a buffer ready.
305762306a36Sopenharmony_ci	 */
305862306a36Sopenharmony_ci	if (likely(qh->qh_state == QH_STATE_IDLE))
305962306a36Sopenharmony_ci		qh_link_async(fotg210, qh);
306062306a36Sopenharmony_cidone:
306162306a36Sopenharmony_ci	spin_unlock_irqrestore(&fotg210->lock, flags);
306262306a36Sopenharmony_ci	if (unlikely(qh == NULL))
306362306a36Sopenharmony_ci		qtd_list_free(fotg210, urb, qtd_list);
306462306a36Sopenharmony_ci	return rc;
306562306a36Sopenharmony_ci}
306662306a36Sopenharmony_ci
306762306a36Sopenharmony_cistatic void single_unlink_async(struct fotg210_hcd *fotg210,
306862306a36Sopenharmony_ci		struct fotg210_qh *qh)
306962306a36Sopenharmony_ci{
307062306a36Sopenharmony_ci	struct fotg210_qh *prev;
307162306a36Sopenharmony_ci
307262306a36Sopenharmony_ci	/* Add to the end of the list of QHs waiting for the next IAAD */
307362306a36Sopenharmony_ci	qh->qh_state = QH_STATE_UNLINK;
307462306a36Sopenharmony_ci	if (fotg210->async_unlink)
307562306a36Sopenharmony_ci		fotg210->async_unlink_last->unlink_next = qh;
307662306a36Sopenharmony_ci	else
307762306a36Sopenharmony_ci		fotg210->async_unlink = qh;
307862306a36Sopenharmony_ci	fotg210->async_unlink_last = qh;
307962306a36Sopenharmony_ci
308062306a36Sopenharmony_ci	/* Unlink it from the schedule */
308162306a36Sopenharmony_ci	prev = fotg210->async;
308262306a36Sopenharmony_ci	while (prev->qh_next.qh != qh)
308362306a36Sopenharmony_ci		prev = prev->qh_next.qh;
308462306a36Sopenharmony_ci
308562306a36Sopenharmony_ci	prev->hw->hw_next = qh->hw->hw_next;
308662306a36Sopenharmony_ci	prev->qh_next = qh->qh_next;
308762306a36Sopenharmony_ci	if (fotg210->qh_scan_next == qh)
308862306a36Sopenharmony_ci		fotg210->qh_scan_next = qh->qh_next.qh;
308962306a36Sopenharmony_ci}
309062306a36Sopenharmony_ci
309162306a36Sopenharmony_cistatic void start_iaa_cycle(struct fotg210_hcd *fotg210, bool nested)
309262306a36Sopenharmony_ci{
309362306a36Sopenharmony_ci	/*
309462306a36Sopenharmony_ci	 * Do nothing if an IAA cycle is already running or
309562306a36Sopenharmony_ci	 * if one will be started shortly.
309662306a36Sopenharmony_ci	 */
309762306a36Sopenharmony_ci	if (fotg210->async_iaa || fotg210->async_unlinking)
309862306a36Sopenharmony_ci		return;
309962306a36Sopenharmony_ci
310062306a36Sopenharmony_ci	/* Do all the waiting QHs at once */
310162306a36Sopenharmony_ci	fotg210->async_iaa = fotg210->async_unlink;
310262306a36Sopenharmony_ci	fotg210->async_unlink = NULL;
310362306a36Sopenharmony_ci
310462306a36Sopenharmony_ci	/* If the controller isn't running, we don't have to wait for it */
310562306a36Sopenharmony_ci	if (unlikely(fotg210->rh_state < FOTG210_RH_RUNNING)) {
310662306a36Sopenharmony_ci		if (!nested)		/* Avoid recursion */
310762306a36Sopenharmony_ci			end_unlink_async(fotg210);
310862306a36Sopenharmony_ci
310962306a36Sopenharmony_ci	/* Otherwise start a new IAA cycle */
311062306a36Sopenharmony_ci	} else if (likely(fotg210->rh_state == FOTG210_RH_RUNNING)) {
311162306a36Sopenharmony_ci		/* Make sure the unlinks are all visible to the hardware */
311262306a36Sopenharmony_ci		wmb();
311362306a36Sopenharmony_ci
311462306a36Sopenharmony_ci		fotg210_writel(fotg210, fotg210->command | CMD_IAAD,
311562306a36Sopenharmony_ci				&fotg210->regs->command);
311662306a36Sopenharmony_ci		fotg210_readl(fotg210, &fotg210->regs->command);
311762306a36Sopenharmony_ci		fotg210_enable_event(fotg210, FOTG210_HRTIMER_IAA_WATCHDOG,
311862306a36Sopenharmony_ci				true);
311962306a36Sopenharmony_ci	}
312062306a36Sopenharmony_ci}
312162306a36Sopenharmony_ci
312262306a36Sopenharmony_ci/* the async qh for the qtds being unlinked are now gone from the HC */
312362306a36Sopenharmony_ci
312462306a36Sopenharmony_cistatic void end_unlink_async(struct fotg210_hcd *fotg210)
312562306a36Sopenharmony_ci{
312662306a36Sopenharmony_ci	struct fotg210_qh *qh;
312762306a36Sopenharmony_ci
312862306a36Sopenharmony_ci	/* Process the idle QHs */
312962306a36Sopenharmony_cirestart:
313062306a36Sopenharmony_ci	fotg210->async_unlinking = true;
313162306a36Sopenharmony_ci	while (fotg210->async_iaa) {
313262306a36Sopenharmony_ci		qh = fotg210->async_iaa;
313362306a36Sopenharmony_ci		fotg210->async_iaa = qh->unlink_next;
313462306a36Sopenharmony_ci		qh->unlink_next = NULL;
313562306a36Sopenharmony_ci
313662306a36Sopenharmony_ci		qh->qh_state = QH_STATE_IDLE;
313762306a36Sopenharmony_ci		qh->qh_next.qh = NULL;
313862306a36Sopenharmony_ci
313962306a36Sopenharmony_ci		qh_completions(fotg210, qh);
314062306a36Sopenharmony_ci		if (!list_empty(&qh->qtd_list) &&
314162306a36Sopenharmony_ci				fotg210->rh_state == FOTG210_RH_RUNNING)
314262306a36Sopenharmony_ci			qh_link_async(fotg210, qh);
314362306a36Sopenharmony_ci		disable_async(fotg210);
314462306a36Sopenharmony_ci	}
314562306a36Sopenharmony_ci	fotg210->async_unlinking = false;
314662306a36Sopenharmony_ci
314762306a36Sopenharmony_ci	/* Start a new IAA cycle if any QHs are waiting for it */
314862306a36Sopenharmony_ci	if (fotg210->async_unlink) {
314962306a36Sopenharmony_ci		start_iaa_cycle(fotg210, true);
315062306a36Sopenharmony_ci		if (unlikely(fotg210->rh_state < FOTG210_RH_RUNNING))
315162306a36Sopenharmony_ci			goto restart;
315262306a36Sopenharmony_ci	}
315362306a36Sopenharmony_ci}
315462306a36Sopenharmony_ci
315562306a36Sopenharmony_cistatic void unlink_empty_async(struct fotg210_hcd *fotg210)
315662306a36Sopenharmony_ci{
315762306a36Sopenharmony_ci	struct fotg210_qh *qh, *next;
315862306a36Sopenharmony_ci	bool stopped = (fotg210->rh_state < FOTG210_RH_RUNNING);
315962306a36Sopenharmony_ci	bool check_unlinks_later = false;
316062306a36Sopenharmony_ci
316162306a36Sopenharmony_ci	/* Unlink all the async QHs that have been empty for a timer cycle */
316262306a36Sopenharmony_ci	next = fotg210->async->qh_next.qh;
316362306a36Sopenharmony_ci	while (next) {
316462306a36Sopenharmony_ci		qh = next;
316562306a36Sopenharmony_ci		next = qh->qh_next.qh;
316662306a36Sopenharmony_ci
316762306a36Sopenharmony_ci		if (list_empty(&qh->qtd_list) &&
316862306a36Sopenharmony_ci				qh->qh_state == QH_STATE_LINKED) {
316962306a36Sopenharmony_ci			if (!stopped && qh->unlink_cycle ==
317062306a36Sopenharmony_ci					fotg210->async_unlink_cycle)
317162306a36Sopenharmony_ci				check_unlinks_later = true;
317262306a36Sopenharmony_ci			else
317362306a36Sopenharmony_ci				single_unlink_async(fotg210, qh);
317462306a36Sopenharmony_ci		}
317562306a36Sopenharmony_ci	}
317662306a36Sopenharmony_ci
317762306a36Sopenharmony_ci	/* Start a new IAA cycle if any QHs are waiting for it */
317862306a36Sopenharmony_ci	if (fotg210->async_unlink)
317962306a36Sopenharmony_ci		start_iaa_cycle(fotg210, false);
318062306a36Sopenharmony_ci
318162306a36Sopenharmony_ci	/* QHs that haven't been empty for long enough will be handled later */
318262306a36Sopenharmony_ci	if (check_unlinks_later) {
318362306a36Sopenharmony_ci		fotg210_enable_event(fotg210, FOTG210_HRTIMER_ASYNC_UNLINKS,
318462306a36Sopenharmony_ci				true);
318562306a36Sopenharmony_ci		++fotg210->async_unlink_cycle;
318662306a36Sopenharmony_ci	}
318762306a36Sopenharmony_ci}
318862306a36Sopenharmony_ci
318962306a36Sopenharmony_ci/* makes sure the async qh will become idle */
319062306a36Sopenharmony_ci/* caller must own fotg210->lock */
319162306a36Sopenharmony_ci
319262306a36Sopenharmony_cistatic void start_unlink_async(struct fotg210_hcd *fotg210,
319362306a36Sopenharmony_ci		struct fotg210_qh *qh)
319462306a36Sopenharmony_ci{
319562306a36Sopenharmony_ci	/*
319662306a36Sopenharmony_ci	 * If the QH isn't linked then there's nothing we can do
319762306a36Sopenharmony_ci	 * unless we were called during a giveback, in which case
319862306a36Sopenharmony_ci	 * qh_completions() has to deal with it.
319962306a36Sopenharmony_ci	 */
320062306a36Sopenharmony_ci	if (qh->qh_state != QH_STATE_LINKED) {
320162306a36Sopenharmony_ci		if (qh->qh_state == QH_STATE_COMPLETING)
320262306a36Sopenharmony_ci			qh->needs_rescan = 1;
320362306a36Sopenharmony_ci		return;
320462306a36Sopenharmony_ci	}
320562306a36Sopenharmony_ci
320662306a36Sopenharmony_ci	single_unlink_async(fotg210, qh);
320762306a36Sopenharmony_ci	start_iaa_cycle(fotg210, false);
320862306a36Sopenharmony_ci}
320962306a36Sopenharmony_ci
321062306a36Sopenharmony_cistatic void scan_async(struct fotg210_hcd *fotg210)
321162306a36Sopenharmony_ci{
321262306a36Sopenharmony_ci	struct fotg210_qh *qh;
321362306a36Sopenharmony_ci	bool check_unlinks_later = false;
321462306a36Sopenharmony_ci
321562306a36Sopenharmony_ci	fotg210->qh_scan_next = fotg210->async->qh_next.qh;
321662306a36Sopenharmony_ci	while (fotg210->qh_scan_next) {
321762306a36Sopenharmony_ci		qh = fotg210->qh_scan_next;
321862306a36Sopenharmony_ci		fotg210->qh_scan_next = qh->qh_next.qh;
321962306a36Sopenharmony_cirescan:
322062306a36Sopenharmony_ci		/* clean any finished work for this qh */
322162306a36Sopenharmony_ci		if (!list_empty(&qh->qtd_list)) {
322262306a36Sopenharmony_ci			int temp;
322362306a36Sopenharmony_ci
322462306a36Sopenharmony_ci			/*
322562306a36Sopenharmony_ci			 * Unlinks could happen here; completion reporting
322662306a36Sopenharmony_ci			 * drops the lock.  That's why fotg210->qh_scan_next
322762306a36Sopenharmony_ci			 * always holds the next qh to scan; if the next qh
322862306a36Sopenharmony_ci			 * gets unlinked then fotg210->qh_scan_next is adjusted
322962306a36Sopenharmony_ci			 * in single_unlink_async().
323062306a36Sopenharmony_ci			 */
323162306a36Sopenharmony_ci			temp = qh_completions(fotg210, qh);
323262306a36Sopenharmony_ci			if (qh->needs_rescan) {
323362306a36Sopenharmony_ci				start_unlink_async(fotg210, qh);
323462306a36Sopenharmony_ci			} else if (list_empty(&qh->qtd_list)
323562306a36Sopenharmony_ci					&& qh->qh_state == QH_STATE_LINKED) {
323662306a36Sopenharmony_ci				qh->unlink_cycle = fotg210->async_unlink_cycle;
323762306a36Sopenharmony_ci				check_unlinks_later = true;
323862306a36Sopenharmony_ci			} else if (temp != 0)
323962306a36Sopenharmony_ci				goto rescan;
324062306a36Sopenharmony_ci		}
324162306a36Sopenharmony_ci	}
324262306a36Sopenharmony_ci
324362306a36Sopenharmony_ci	/*
324462306a36Sopenharmony_ci	 * Unlink empty entries, reducing DMA usage as well
324562306a36Sopenharmony_ci	 * as HCD schedule-scanning costs.  Delay for any qh
324662306a36Sopenharmony_ci	 * we just scanned, there's a not-unusual case that it
324762306a36Sopenharmony_ci	 * doesn't stay idle for long.
324862306a36Sopenharmony_ci	 */
324962306a36Sopenharmony_ci	if (check_unlinks_later && fotg210->rh_state == FOTG210_RH_RUNNING &&
325062306a36Sopenharmony_ci			!(fotg210->enabled_hrtimer_events &
325162306a36Sopenharmony_ci			BIT(FOTG210_HRTIMER_ASYNC_UNLINKS))) {
325262306a36Sopenharmony_ci		fotg210_enable_event(fotg210,
325362306a36Sopenharmony_ci				FOTG210_HRTIMER_ASYNC_UNLINKS, true);
325462306a36Sopenharmony_ci		++fotg210->async_unlink_cycle;
325562306a36Sopenharmony_ci	}
325662306a36Sopenharmony_ci}
325762306a36Sopenharmony_ci/* EHCI scheduled transaction support:  interrupt, iso, split iso
325862306a36Sopenharmony_ci * These are called "periodic" transactions in the EHCI spec.
325962306a36Sopenharmony_ci *
326062306a36Sopenharmony_ci * Note that for interrupt transfers, the QH/QTD manipulation is shared
326162306a36Sopenharmony_ci * with the "asynchronous" transaction support (control/bulk transfers).
326262306a36Sopenharmony_ci * The only real difference is in how interrupt transfers are scheduled.
326362306a36Sopenharmony_ci *
326462306a36Sopenharmony_ci * For ISO, we make an "iso_stream" head to serve the same role as a QH.
326562306a36Sopenharmony_ci * It keeps track of every ITD (or SITD) that's linked, and holds enough
326662306a36Sopenharmony_ci * pre-calculated schedule data to make appending to the queue be quick.
326762306a36Sopenharmony_ci */
326862306a36Sopenharmony_cistatic int fotg210_get_frame(struct usb_hcd *hcd);
326962306a36Sopenharmony_ci
327062306a36Sopenharmony_ci/* periodic_next_shadow - return "next" pointer on shadow list
327162306a36Sopenharmony_ci * @periodic: host pointer to qh/itd
327262306a36Sopenharmony_ci * @tag: hardware tag for type of this record
327362306a36Sopenharmony_ci */
327462306a36Sopenharmony_cistatic union fotg210_shadow *periodic_next_shadow(struct fotg210_hcd *fotg210,
327562306a36Sopenharmony_ci		union fotg210_shadow *periodic, __hc32 tag)
327662306a36Sopenharmony_ci{
327762306a36Sopenharmony_ci	switch (hc32_to_cpu(fotg210, tag)) {
327862306a36Sopenharmony_ci	case Q_TYPE_QH:
327962306a36Sopenharmony_ci		return &periodic->qh->qh_next;
328062306a36Sopenharmony_ci	case Q_TYPE_FSTN:
328162306a36Sopenharmony_ci		return &periodic->fstn->fstn_next;
328262306a36Sopenharmony_ci	default:
328362306a36Sopenharmony_ci		return &periodic->itd->itd_next;
328462306a36Sopenharmony_ci	}
328562306a36Sopenharmony_ci}
328662306a36Sopenharmony_ci
328762306a36Sopenharmony_cistatic __hc32 *shadow_next_periodic(struct fotg210_hcd *fotg210,
328862306a36Sopenharmony_ci		union fotg210_shadow *periodic, __hc32 tag)
328962306a36Sopenharmony_ci{
329062306a36Sopenharmony_ci	switch (hc32_to_cpu(fotg210, tag)) {
329162306a36Sopenharmony_ci	/* our fotg210_shadow.qh is actually software part */
329262306a36Sopenharmony_ci	case Q_TYPE_QH:
329362306a36Sopenharmony_ci		return &periodic->qh->hw->hw_next;
329462306a36Sopenharmony_ci	/* others are hw parts */
329562306a36Sopenharmony_ci	default:
329662306a36Sopenharmony_ci		return periodic->hw_next;
329762306a36Sopenharmony_ci	}
329862306a36Sopenharmony_ci}
329962306a36Sopenharmony_ci
330062306a36Sopenharmony_ci/* caller must hold fotg210->lock */
330162306a36Sopenharmony_cistatic void periodic_unlink(struct fotg210_hcd *fotg210, unsigned frame,
330262306a36Sopenharmony_ci		void *ptr)
330362306a36Sopenharmony_ci{
330462306a36Sopenharmony_ci	union fotg210_shadow *prev_p = &fotg210->pshadow[frame];
330562306a36Sopenharmony_ci	__hc32 *hw_p = &fotg210->periodic[frame];
330662306a36Sopenharmony_ci	union fotg210_shadow here = *prev_p;
330762306a36Sopenharmony_ci
330862306a36Sopenharmony_ci	/* find predecessor of "ptr"; hw and shadow lists are in sync */
330962306a36Sopenharmony_ci	while (here.ptr && here.ptr != ptr) {
331062306a36Sopenharmony_ci		prev_p = periodic_next_shadow(fotg210, prev_p,
331162306a36Sopenharmony_ci				Q_NEXT_TYPE(fotg210, *hw_p));
331262306a36Sopenharmony_ci		hw_p = shadow_next_periodic(fotg210, &here,
331362306a36Sopenharmony_ci				Q_NEXT_TYPE(fotg210, *hw_p));
331462306a36Sopenharmony_ci		here = *prev_p;
331562306a36Sopenharmony_ci	}
331662306a36Sopenharmony_ci	/* an interrupt entry (at list end) could have been shared */
331762306a36Sopenharmony_ci	if (!here.ptr)
331862306a36Sopenharmony_ci		return;
331962306a36Sopenharmony_ci
332062306a36Sopenharmony_ci	/* update shadow and hardware lists ... the old "next" pointers
332162306a36Sopenharmony_ci	 * from ptr may still be in use, the caller updates them.
332262306a36Sopenharmony_ci	 */
332362306a36Sopenharmony_ci	*prev_p = *periodic_next_shadow(fotg210, &here,
332462306a36Sopenharmony_ci			Q_NEXT_TYPE(fotg210, *hw_p));
332562306a36Sopenharmony_ci
332662306a36Sopenharmony_ci	*hw_p = *shadow_next_periodic(fotg210, &here,
332762306a36Sopenharmony_ci			Q_NEXT_TYPE(fotg210, *hw_p));
332862306a36Sopenharmony_ci}
332962306a36Sopenharmony_ci
333062306a36Sopenharmony_ci/* how many of the uframe's 125 usecs are allocated? */
333162306a36Sopenharmony_cistatic unsigned short periodic_usecs(struct fotg210_hcd *fotg210,
333262306a36Sopenharmony_ci		unsigned frame, unsigned uframe)
333362306a36Sopenharmony_ci{
333462306a36Sopenharmony_ci	__hc32 *hw_p = &fotg210->periodic[frame];
333562306a36Sopenharmony_ci	union fotg210_shadow *q = &fotg210->pshadow[frame];
333662306a36Sopenharmony_ci	unsigned usecs = 0;
333762306a36Sopenharmony_ci	struct fotg210_qh_hw *hw;
333862306a36Sopenharmony_ci
333962306a36Sopenharmony_ci	while (q->ptr) {
334062306a36Sopenharmony_ci		switch (hc32_to_cpu(fotg210, Q_NEXT_TYPE(fotg210, *hw_p))) {
334162306a36Sopenharmony_ci		case Q_TYPE_QH:
334262306a36Sopenharmony_ci			hw = q->qh->hw;
334362306a36Sopenharmony_ci			/* is it in the S-mask? */
334462306a36Sopenharmony_ci			if (hw->hw_info2 & cpu_to_hc32(fotg210, 1 << uframe))
334562306a36Sopenharmony_ci				usecs += q->qh->usecs;
334662306a36Sopenharmony_ci			/* ... or C-mask? */
334762306a36Sopenharmony_ci			if (hw->hw_info2 & cpu_to_hc32(fotg210,
334862306a36Sopenharmony_ci					1 << (8 + uframe)))
334962306a36Sopenharmony_ci				usecs += q->qh->c_usecs;
335062306a36Sopenharmony_ci			hw_p = &hw->hw_next;
335162306a36Sopenharmony_ci			q = &q->qh->qh_next;
335262306a36Sopenharmony_ci			break;
335362306a36Sopenharmony_ci		/* case Q_TYPE_FSTN: */
335462306a36Sopenharmony_ci		default:
335562306a36Sopenharmony_ci			/* for "save place" FSTNs, count the relevant INTR
335662306a36Sopenharmony_ci			 * bandwidth from the previous frame
335762306a36Sopenharmony_ci			 */
335862306a36Sopenharmony_ci			if (q->fstn->hw_prev != FOTG210_LIST_END(fotg210))
335962306a36Sopenharmony_ci				fotg210_dbg(fotg210, "ignoring FSTN cost ...\n");
336062306a36Sopenharmony_ci
336162306a36Sopenharmony_ci			hw_p = &q->fstn->hw_next;
336262306a36Sopenharmony_ci			q = &q->fstn->fstn_next;
336362306a36Sopenharmony_ci			break;
336462306a36Sopenharmony_ci		case Q_TYPE_ITD:
336562306a36Sopenharmony_ci			if (q->itd->hw_transaction[uframe])
336662306a36Sopenharmony_ci				usecs += q->itd->stream->usecs;
336762306a36Sopenharmony_ci			hw_p = &q->itd->hw_next;
336862306a36Sopenharmony_ci			q = &q->itd->itd_next;
336962306a36Sopenharmony_ci			break;
337062306a36Sopenharmony_ci		}
337162306a36Sopenharmony_ci	}
337262306a36Sopenharmony_ci	if (usecs > fotg210->uframe_periodic_max)
337362306a36Sopenharmony_ci		fotg210_err(fotg210, "uframe %d sched overrun: %d usecs\n",
337462306a36Sopenharmony_ci				frame * 8 + uframe, usecs);
337562306a36Sopenharmony_ci	return usecs;
337662306a36Sopenharmony_ci}
337762306a36Sopenharmony_ci
337862306a36Sopenharmony_cistatic int same_tt(struct usb_device *dev1, struct usb_device *dev2)
337962306a36Sopenharmony_ci{
338062306a36Sopenharmony_ci	if (!dev1->tt || !dev2->tt)
338162306a36Sopenharmony_ci		return 0;
338262306a36Sopenharmony_ci	if (dev1->tt != dev2->tt)
338362306a36Sopenharmony_ci		return 0;
338462306a36Sopenharmony_ci	if (dev1->tt->multi)
338562306a36Sopenharmony_ci		return dev1->ttport == dev2->ttport;
338662306a36Sopenharmony_ci	else
338762306a36Sopenharmony_ci		return 1;
338862306a36Sopenharmony_ci}
338962306a36Sopenharmony_ci
339062306a36Sopenharmony_ci/* return true iff the device's transaction translator is available
339162306a36Sopenharmony_ci * for a periodic transfer starting at the specified frame, using
339262306a36Sopenharmony_ci * all the uframes in the mask.
339362306a36Sopenharmony_ci */
339462306a36Sopenharmony_cistatic int tt_no_collision(struct fotg210_hcd *fotg210, unsigned period,
339562306a36Sopenharmony_ci		struct usb_device *dev, unsigned frame, u32 uf_mask)
339662306a36Sopenharmony_ci{
339762306a36Sopenharmony_ci	if (period == 0)	/* error */
339862306a36Sopenharmony_ci		return 0;
339962306a36Sopenharmony_ci
340062306a36Sopenharmony_ci	/* note bandwidth wastage:  split never follows csplit
340162306a36Sopenharmony_ci	 * (different dev or endpoint) until the next uframe.
340262306a36Sopenharmony_ci	 * calling convention doesn't make that distinction.
340362306a36Sopenharmony_ci	 */
340462306a36Sopenharmony_ci	for (; frame < fotg210->periodic_size; frame += period) {
340562306a36Sopenharmony_ci		union fotg210_shadow here;
340662306a36Sopenharmony_ci		__hc32 type;
340762306a36Sopenharmony_ci		struct fotg210_qh_hw *hw;
340862306a36Sopenharmony_ci
340962306a36Sopenharmony_ci		here = fotg210->pshadow[frame];
341062306a36Sopenharmony_ci		type = Q_NEXT_TYPE(fotg210, fotg210->periodic[frame]);
341162306a36Sopenharmony_ci		while (here.ptr) {
341262306a36Sopenharmony_ci			switch (hc32_to_cpu(fotg210, type)) {
341362306a36Sopenharmony_ci			case Q_TYPE_ITD:
341462306a36Sopenharmony_ci				type = Q_NEXT_TYPE(fotg210, here.itd->hw_next);
341562306a36Sopenharmony_ci				here = here.itd->itd_next;
341662306a36Sopenharmony_ci				continue;
341762306a36Sopenharmony_ci			case Q_TYPE_QH:
341862306a36Sopenharmony_ci				hw = here.qh->hw;
341962306a36Sopenharmony_ci				if (same_tt(dev, here.qh->dev)) {
342062306a36Sopenharmony_ci					u32 mask;
342162306a36Sopenharmony_ci
342262306a36Sopenharmony_ci					mask = hc32_to_cpu(fotg210,
342362306a36Sopenharmony_ci							hw->hw_info2);
342462306a36Sopenharmony_ci					/* "knows" no gap is needed */
342562306a36Sopenharmony_ci					mask |= mask >> 8;
342662306a36Sopenharmony_ci					if (mask & uf_mask)
342762306a36Sopenharmony_ci						break;
342862306a36Sopenharmony_ci				}
342962306a36Sopenharmony_ci				type = Q_NEXT_TYPE(fotg210, hw->hw_next);
343062306a36Sopenharmony_ci				here = here.qh->qh_next;
343162306a36Sopenharmony_ci				continue;
343262306a36Sopenharmony_ci			/* case Q_TYPE_FSTN: */
343362306a36Sopenharmony_ci			default:
343462306a36Sopenharmony_ci				fotg210_dbg(fotg210,
343562306a36Sopenharmony_ci						"periodic frame %d bogus type %d\n",
343662306a36Sopenharmony_ci						frame, type);
343762306a36Sopenharmony_ci			}
343862306a36Sopenharmony_ci
343962306a36Sopenharmony_ci			/* collision or error */
344062306a36Sopenharmony_ci			return 0;
344162306a36Sopenharmony_ci		}
344262306a36Sopenharmony_ci	}
344362306a36Sopenharmony_ci
344462306a36Sopenharmony_ci	/* no collision */
344562306a36Sopenharmony_ci	return 1;
344662306a36Sopenharmony_ci}
344762306a36Sopenharmony_ci
344862306a36Sopenharmony_cistatic void enable_periodic(struct fotg210_hcd *fotg210)
344962306a36Sopenharmony_ci{
345062306a36Sopenharmony_ci	if (fotg210->periodic_count++)
345162306a36Sopenharmony_ci		return;
345262306a36Sopenharmony_ci
345362306a36Sopenharmony_ci	/* Stop waiting to turn off the periodic schedule */
345462306a36Sopenharmony_ci	fotg210->enabled_hrtimer_events &=
345562306a36Sopenharmony_ci		~BIT(FOTG210_HRTIMER_DISABLE_PERIODIC);
345662306a36Sopenharmony_ci
345762306a36Sopenharmony_ci	/* Don't start the schedule until PSS is 0 */
345862306a36Sopenharmony_ci	fotg210_poll_PSS(fotg210);
345962306a36Sopenharmony_ci	turn_on_io_watchdog(fotg210);
346062306a36Sopenharmony_ci}
346162306a36Sopenharmony_ci
346262306a36Sopenharmony_cistatic void disable_periodic(struct fotg210_hcd *fotg210)
346362306a36Sopenharmony_ci{
346462306a36Sopenharmony_ci	if (--fotg210->periodic_count)
346562306a36Sopenharmony_ci		return;
346662306a36Sopenharmony_ci
346762306a36Sopenharmony_ci	/* Don't turn off the schedule until PSS is 1 */
346862306a36Sopenharmony_ci	fotg210_poll_PSS(fotg210);
346962306a36Sopenharmony_ci}
347062306a36Sopenharmony_ci
347162306a36Sopenharmony_ci/* periodic schedule slots have iso tds (normal or split) first, then a
347262306a36Sopenharmony_ci * sparse tree for active interrupt transfers.
347362306a36Sopenharmony_ci *
347462306a36Sopenharmony_ci * this just links in a qh; caller guarantees uframe masks are set right.
347562306a36Sopenharmony_ci * no FSTN support (yet; fotg210 0.96+)
347662306a36Sopenharmony_ci */
347762306a36Sopenharmony_cistatic void qh_link_periodic(struct fotg210_hcd *fotg210, struct fotg210_qh *qh)
347862306a36Sopenharmony_ci{
347962306a36Sopenharmony_ci	unsigned i;
348062306a36Sopenharmony_ci	unsigned period = qh->period;
348162306a36Sopenharmony_ci
348262306a36Sopenharmony_ci	dev_dbg(&qh->dev->dev,
348362306a36Sopenharmony_ci			"link qh%d-%04x/%p start %d [%d/%d us]\n", period,
348462306a36Sopenharmony_ci			hc32_to_cpup(fotg210, &qh->hw->hw_info2) &
348562306a36Sopenharmony_ci			(QH_CMASK | QH_SMASK), qh, qh->start, qh->usecs,
348662306a36Sopenharmony_ci			qh->c_usecs);
348762306a36Sopenharmony_ci
348862306a36Sopenharmony_ci	/* high bandwidth, or otherwise every microframe */
348962306a36Sopenharmony_ci	if (period == 0)
349062306a36Sopenharmony_ci		period = 1;
349162306a36Sopenharmony_ci
349262306a36Sopenharmony_ci	for (i = qh->start; i < fotg210->periodic_size; i += period) {
349362306a36Sopenharmony_ci		union fotg210_shadow *prev = &fotg210->pshadow[i];
349462306a36Sopenharmony_ci		__hc32 *hw_p = &fotg210->periodic[i];
349562306a36Sopenharmony_ci		union fotg210_shadow here = *prev;
349662306a36Sopenharmony_ci		__hc32 type = 0;
349762306a36Sopenharmony_ci
349862306a36Sopenharmony_ci		/* skip the iso nodes at list head */
349962306a36Sopenharmony_ci		while (here.ptr) {
350062306a36Sopenharmony_ci			type = Q_NEXT_TYPE(fotg210, *hw_p);
350162306a36Sopenharmony_ci			if (type == cpu_to_hc32(fotg210, Q_TYPE_QH))
350262306a36Sopenharmony_ci				break;
350362306a36Sopenharmony_ci			prev = periodic_next_shadow(fotg210, prev, type);
350462306a36Sopenharmony_ci			hw_p = shadow_next_periodic(fotg210, &here, type);
350562306a36Sopenharmony_ci			here = *prev;
350662306a36Sopenharmony_ci		}
350762306a36Sopenharmony_ci
350862306a36Sopenharmony_ci		/* sorting each branch by period (slow-->fast)
350962306a36Sopenharmony_ci		 * enables sharing interior tree nodes
351062306a36Sopenharmony_ci		 */
351162306a36Sopenharmony_ci		while (here.ptr && qh != here.qh) {
351262306a36Sopenharmony_ci			if (qh->period > here.qh->period)
351362306a36Sopenharmony_ci				break;
351462306a36Sopenharmony_ci			prev = &here.qh->qh_next;
351562306a36Sopenharmony_ci			hw_p = &here.qh->hw->hw_next;
351662306a36Sopenharmony_ci			here = *prev;
351762306a36Sopenharmony_ci		}
351862306a36Sopenharmony_ci		/* link in this qh, unless some earlier pass did that */
351962306a36Sopenharmony_ci		if (qh != here.qh) {
352062306a36Sopenharmony_ci			qh->qh_next = here;
352162306a36Sopenharmony_ci			if (here.qh)
352262306a36Sopenharmony_ci				qh->hw->hw_next = *hw_p;
352362306a36Sopenharmony_ci			wmb();
352462306a36Sopenharmony_ci			prev->qh = qh;
352562306a36Sopenharmony_ci			*hw_p = QH_NEXT(fotg210, qh->qh_dma);
352662306a36Sopenharmony_ci		}
352762306a36Sopenharmony_ci	}
352862306a36Sopenharmony_ci	qh->qh_state = QH_STATE_LINKED;
352962306a36Sopenharmony_ci	qh->xacterrs = 0;
353062306a36Sopenharmony_ci
353162306a36Sopenharmony_ci	/* update per-qh bandwidth for usbfs */
353262306a36Sopenharmony_ci	fotg210_to_hcd(fotg210)->self.bandwidth_allocated += qh->period
353362306a36Sopenharmony_ci		? ((qh->usecs + qh->c_usecs) / qh->period)
353462306a36Sopenharmony_ci		: (qh->usecs * 8);
353562306a36Sopenharmony_ci
353662306a36Sopenharmony_ci	list_add(&qh->intr_node, &fotg210->intr_qh_list);
353762306a36Sopenharmony_ci
353862306a36Sopenharmony_ci	/* maybe enable periodic schedule processing */
353962306a36Sopenharmony_ci	++fotg210->intr_count;
354062306a36Sopenharmony_ci	enable_periodic(fotg210);
354162306a36Sopenharmony_ci}
354262306a36Sopenharmony_ci
354362306a36Sopenharmony_cistatic void qh_unlink_periodic(struct fotg210_hcd *fotg210,
354462306a36Sopenharmony_ci		struct fotg210_qh *qh)
354562306a36Sopenharmony_ci{
354662306a36Sopenharmony_ci	unsigned i;
354762306a36Sopenharmony_ci	unsigned period;
354862306a36Sopenharmony_ci
354962306a36Sopenharmony_ci	/*
355062306a36Sopenharmony_ci	 * If qh is for a low/full-speed device, simply unlinking it
355162306a36Sopenharmony_ci	 * could interfere with an ongoing split transaction.  To unlink
355262306a36Sopenharmony_ci	 * it safely would require setting the QH_INACTIVATE bit and
355362306a36Sopenharmony_ci	 * waiting at least one frame, as described in EHCI 4.12.2.5.
355462306a36Sopenharmony_ci	 *
355562306a36Sopenharmony_ci	 * We won't bother with any of this.  Instead, we assume that the
355662306a36Sopenharmony_ci	 * only reason for unlinking an interrupt QH while the current URB
355762306a36Sopenharmony_ci	 * is still active is to dequeue all the URBs (flush the whole
355862306a36Sopenharmony_ci	 * endpoint queue).
355962306a36Sopenharmony_ci	 *
356062306a36Sopenharmony_ci	 * If rebalancing the periodic schedule is ever implemented, this
356162306a36Sopenharmony_ci	 * approach will no longer be valid.
356262306a36Sopenharmony_ci	 */
356362306a36Sopenharmony_ci
356462306a36Sopenharmony_ci	/* high bandwidth, or otherwise part of every microframe */
356562306a36Sopenharmony_ci	period = qh->period;
356662306a36Sopenharmony_ci	if (!period)
356762306a36Sopenharmony_ci		period = 1;
356862306a36Sopenharmony_ci
356962306a36Sopenharmony_ci	for (i = qh->start; i < fotg210->periodic_size; i += period)
357062306a36Sopenharmony_ci		periodic_unlink(fotg210, i, qh);
357162306a36Sopenharmony_ci
357262306a36Sopenharmony_ci	/* update per-qh bandwidth for usbfs */
357362306a36Sopenharmony_ci	fotg210_to_hcd(fotg210)->self.bandwidth_allocated -= qh->period
357462306a36Sopenharmony_ci		? ((qh->usecs + qh->c_usecs) / qh->period)
357562306a36Sopenharmony_ci		: (qh->usecs * 8);
357662306a36Sopenharmony_ci
357762306a36Sopenharmony_ci	dev_dbg(&qh->dev->dev,
357862306a36Sopenharmony_ci			"unlink qh%d-%04x/%p start %d [%d/%d us]\n",
357962306a36Sopenharmony_ci			qh->period, hc32_to_cpup(fotg210, &qh->hw->hw_info2) &
358062306a36Sopenharmony_ci			(QH_CMASK | QH_SMASK), qh, qh->start, qh->usecs,
358162306a36Sopenharmony_ci			qh->c_usecs);
358262306a36Sopenharmony_ci
358362306a36Sopenharmony_ci	/* qh->qh_next still "live" to HC */
358462306a36Sopenharmony_ci	qh->qh_state = QH_STATE_UNLINK;
358562306a36Sopenharmony_ci	qh->qh_next.ptr = NULL;
358662306a36Sopenharmony_ci
358762306a36Sopenharmony_ci	if (fotg210->qh_scan_next == qh)
358862306a36Sopenharmony_ci		fotg210->qh_scan_next = list_entry(qh->intr_node.next,
358962306a36Sopenharmony_ci				struct fotg210_qh, intr_node);
359062306a36Sopenharmony_ci	list_del(&qh->intr_node);
359162306a36Sopenharmony_ci}
359262306a36Sopenharmony_ci
359362306a36Sopenharmony_cistatic void start_unlink_intr(struct fotg210_hcd *fotg210,
359462306a36Sopenharmony_ci		struct fotg210_qh *qh)
359562306a36Sopenharmony_ci{
359662306a36Sopenharmony_ci	/* If the QH isn't linked then there's nothing we can do
359762306a36Sopenharmony_ci	 * unless we were called during a giveback, in which case
359862306a36Sopenharmony_ci	 * qh_completions() has to deal with it.
359962306a36Sopenharmony_ci	 */
360062306a36Sopenharmony_ci	if (qh->qh_state != QH_STATE_LINKED) {
360162306a36Sopenharmony_ci		if (qh->qh_state == QH_STATE_COMPLETING)
360262306a36Sopenharmony_ci			qh->needs_rescan = 1;
360362306a36Sopenharmony_ci		return;
360462306a36Sopenharmony_ci	}
360562306a36Sopenharmony_ci
360662306a36Sopenharmony_ci	qh_unlink_periodic(fotg210, qh);
360762306a36Sopenharmony_ci
360862306a36Sopenharmony_ci	/* Make sure the unlinks are visible before starting the timer */
360962306a36Sopenharmony_ci	wmb();
361062306a36Sopenharmony_ci
361162306a36Sopenharmony_ci	/*
361262306a36Sopenharmony_ci	 * The EHCI spec doesn't say how long it takes the controller to
361362306a36Sopenharmony_ci	 * stop accessing an unlinked interrupt QH.  The timer delay is
361462306a36Sopenharmony_ci	 * 9 uframes; presumably that will be long enough.
361562306a36Sopenharmony_ci	 */
361662306a36Sopenharmony_ci	qh->unlink_cycle = fotg210->intr_unlink_cycle;
361762306a36Sopenharmony_ci
361862306a36Sopenharmony_ci	/* New entries go at the end of the intr_unlink list */
361962306a36Sopenharmony_ci	if (fotg210->intr_unlink)
362062306a36Sopenharmony_ci		fotg210->intr_unlink_last->unlink_next = qh;
362162306a36Sopenharmony_ci	else
362262306a36Sopenharmony_ci		fotg210->intr_unlink = qh;
362362306a36Sopenharmony_ci	fotg210->intr_unlink_last = qh;
362462306a36Sopenharmony_ci
362562306a36Sopenharmony_ci	if (fotg210->intr_unlinking)
362662306a36Sopenharmony_ci		;	/* Avoid recursive calls */
362762306a36Sopenharmony_ci	else if (fotg210->rh_state < FOTG210_RH_RUNNING)
362862306a36Sopenharmony_ci		fotg210_handle_intr_unlinks(fotg210);
362962306a36Sopenharmony_ci	else if (fotg210->intr_unlink == qh) {
363062306a36Sopenharmony_ci		fotg210_enable_event(fotg210, FOTG210_HRTIMER_UNLINK_INTR,
363162306a36Sopenharmony_ci				true);
363262306a36Sopenharmony_ci		++fotg210->intr_unlink_cycle;
363362306a36Sopenharmony_ci	}
363462306a36Sopenharmony_ci}
363562306a36Sopenharmony_ci
363662306a36Sopenharmony_cistatic void end_unlink_intr(struct fotg210_hcd *fotg210, struct fotg210_qh *qh)
363762306a36Sopenharmony_ci{
363862306a36Sopenharmony_ci	struct fotg210_qh_hw *hw = qh->hw;
363962306a36Sopenharmony_ci	int rc;
364062306a36Sopenharmony_ci
364162306a36Sopenharmony_ci	qh->qh_state = QH_STATE_IDLE;
364262306a36Sopenharmony_ci	hw->hw_next = FOTG210_LIST_END(fotg210);
364362306a36Sopenharmony_ci
364462306a36Sopenharmony_ci	qh_completions(fotg210, qh);
364562306a36Sopenharmony_ci
364662306a36Sopenharmony_ci	/* reschedule QH iff another request is queued */
364762306a36Sopenharmony_ci	if (!list_empty(&qh->qtd_list) &&
364862306a36Sopenharmony_ci			fotg210->rh_state == FOTG210_RH_RUNNING) {
364962306a36Sopenharmony_ci		rc = qh_schedule(fotg210, qh);
365062306a36Sopenharmony_ci
365162306a36Sopenharmony_ci		/* An error here likely indicates handshake failure
365262306a36Sopenharmony_ci		 * or no space left in the schedule.  Neither fault
365362306a36Sopenharmony_ci		 * should happen often ...
365462306a36Sopenharmony_ci		 *
365562306a36Sopenharmony_ci		 * FIXME kill the now-dysfunctional queued urbs
365662306a36Sopenharmony_ci		 */
365762306a36Sopenharmony_ci		if (rc != 0)
365862306a36Sopenharmony_ci			fotg210_err(fotg210, "can't reschedule qh %p, err %d\n",
365962306a36Sopenharmony_ci					qh, rc);
366062306a36Sopenharmony_ci	}
366162306a36Sopenharmony_ci
366262306a36Sopenharmony_ci	/* maybe turn off periodic schedule */
366362306a36Sopenharmony_ci	--fotg210->intr_count;
366462306a36Sopenharmony_ci	disable_periodic(fotg210);
366562306a36Sopenharmony_ci}
366662306a36Sopenharmony_ci
366762306a36Sopenharmony_cistatic int check_period(struct fotg210_hcd *fotg210, unsigned frame,
366862306a36Sopenharmony_ci		unsigned uframe, unsigned period, unsigned usecs)
366962306a36Sopenharmony_ci{
367062306a36Sopenharmony_ci	int claimed;
367162306a36Sopenharmony_ci
367262306a36Sopenharmony_ci	/* complete split running into next frame?
367362306a36Sopenharmony_ci	 * given FSTN support, we could sometimes check...
367462306a36Sopenharmony_ci	 */
367562306a36Sopenharmony_ci	if (uframe >= 8)
367662306a36Sopenharmony_ci		return 0;
367762306a36Sopenharmony_ci
367862306a36Sopenharmony_ci	/* convert "usecs we need" to "max already claimed" */
367962306a36Sopenharmony_ci	usecs = fotg210->uframe_periodic_max - usecs;
368062306a36Sopenharmony_ci
368162306a36Sopenharmony_ci	/* we "know" 2 and 4 uframe intervals were rejected; so
368262306a36Sopenharmony_ci	 * for period 0, check _every_ microframe in the schedule.
368362306a36Sopenharmony_ci	 */
368462306a36Sopenharmony_ci	if (unlikely(period == 0)) {
368562306a36Sopenharmony_ci		do {
368662306a36Sopenharmony_ci			for (uframe = 0; uframe < 7; uframe++) {
368762306a36Sopenharmony_ci				claimed = periodic_usecs(fotg210, frame,
368862306a36Sopenharmony_ci						uframe);
368962306a36Sopenharmony_ci				if (claimed > usecs)
369062306a36Sopenharmony_ci					return 0;
369162306a36Sopenharmony_ci			}
369262306a36Sopenharmony_ci		} while ((frame += 1) < fotg210->periodic_size);
369362306a36Sopenharmony_ci
369462306a36Sopenharmony_ci	/* just check the specified uframe, at that period */
369562306a36Sopenharmony_ci	} else {
369662306a36Sopenharmony_ci		do {
369762306a36Sopenharmony_ci			claimed = periodic_usecs(fotg210, frame, uframe);
369862306a36Sopenharmony_ci			if (claimed > usecs)
369962306a36Sopenharmony_ci				return 0;
370062306a36Sopenharmony_ci		} while ((frame += period) < fotg210->periodic_size);
370162306a36Sopenharmony_ci	}
370262306a36Sopenharmony_ci
370362306a36Sopenharmony_ci	/* success! */
370462306a36Sopenharmony_ci	return 1;
370562306a36Sopenharmony_ci}
370662306a36Sopenharmony_ci
370762306a36Sopenharmony_cistatic int check_intr_schedule(struct fotg210_hcd *fotg210, unsigned frame,
370862306a36Sopenharmony_ci		unsigned uframe, const struct fotg210_qh *qh, __hc32 *c_maskp)
370962306a36Sopenharmony_ci{
371062306a36Sopenharmony_ci	int retval = -ENOSPC;
371162306a36Sopenharmony_ci	u8 mask = 0;
371262306a36Sopenharmony_ci
371362306a36Sopenharmony_ci	if (qh->c_usecs && uframe >= 6)		/* FSTN territory? */
371462306a36Sopenharmony_ci		goto done;
371562306a36Sopenharmony_ci
371662306a36Sopenharmony_ci	if (!check_period(fotg210, frame, uframe, qh->period, qh->usecs))
371762306a36Sopenharmony_ci		goto done;
371862306a36Sopenharmony_ci	if (!qh->c_usecs) {
371962306a36Sopenharmony_ci		retval = 0;
372062306a36Sopenharmony_ci		*c_maskp = 0;
372162306a36Sopenharmony_ci		goto done;
372262306a36Sopenharmony_ci	}
372362306a36Sopenharmony_ci
372462306a36Sopenharmony_ci	/* Make sure this tt's buffer is also available for CSPLITs.
372562306a36Sopenharmony_ci	 * We pessimize a bit; probably the typical full speed case
372662306a36Sopenharmony_ci	 * doesn't need the second CSPLIT.
372762306a36Sopenharmony_ci	 *
372862306a36Sopenharmony_ci	 * NOTE:  both SPLIT and CSPLIT could be checked in just
372962306a36Sopenharmony_ci	 * one smart pass...
373062306a36Sopenharmony_ci	 */
373162306a36Sopenharmony_ci	mask = 0x03 << (uframe + qh->gap_uf);
373262306a36Sopenharmony_ci	*c_maskp = cpu_to_hc32(fotg210, mask << 8);
373362306a36Sopenharmony_ci
373462306a36Sopenharmony_ci	mask |= 1 << uframe;
373562306a36Sopenharmony_ci	if (tt_no_collision(fotg210, qh->period, qh->dev, frame, mask)) {
373662306a36Sopenharmony_ci		if (!check_period(fotg210, frame, uframe + qh->gap_uf + 1,
373762306a36Sopenharmony_ci				qh->period, qh->c_usecs))
373862306a36Sopenharmony_ci			goto done;
373962306a36Sopenharmony_ci		if (!check_period(fotg210, frame, uframe + qh->gap_uf,
374062306a36Sopenharmony_ci				qh->period, qh->c_usecs))
374162306a36Sopenharmony_ci			goto done;
374262306a36Sopenharmony_ci		retval = 0;
374362306a36Sopenharmony_ci	}
374462306a36Sopenharmony_cidone:
374562306a36Sopenharmony_ci	return retval;
374662306a36Sopenharmony_ci}
374762306a36Sopenharmony_ci
374862306a36Sopenharmony_ci/* "first fit" scheduling policy used the first time through,
374962306a36Sopenharmony_ci * or when the previous schedule slot can't be re-used.
375062306a36Sopenharmony_ci */
375162306a36Sopenharmony_cistatic int qh_schedule(struct fotg210_hcd *fotg210, struct fotg210_qh *qh)
375262306a36Sopenharmony_ci{
375362306a36Sopenharmony_ci	int status;
375462306a36Sopenharmony_ci	unsigned uframe;
375562306a36Sopenharmony_ci	__hc32 c_mask;
375662306a36Sopenharmony_ci	unsigned frame;	/* 0..(qh->period - 1), or NO_FRAME */
375762306a36Sopenharmony_ci	struct fotg210_qh_hw *hw = qh->hw;
375862306a36Sopenharmony_ci
375962306a36Sopenharmony_ci	qh_refresh(fotg210, qh);
376062306a36Sopenharmony_ci	hw->hw_next = FOTG210_LIST_END(fotg210);
376162306a36Sopenharmony_ci	frame = qh->start;
376262306a36Sopenharmony_ci
376362306a36Sopenharmony_ci	/* reuse the previous schedule slots, if we can */
376462306a36Sopenharmony_ci	if (frame < qh->period) {
376562306a36Sopenharmony_ci		uframe = ffs(hc32_to_cpup(fotg210, &hw->hw_info2) & QH_SMASK);
376662306a36Sopenharmony_ci		status = check_intr_schedule(fotg210, frame, --uframe,
376762306a36Sopenharmony_ci				qh, &c_mask);
376862306a36Sopenharmony_ci	} else {
376962306a36Sopenharmony_ci		uframe = 0;
377062306a36Sopenharmony_ci		c_mask = 0;
377162306a36Sopenharmony_ci		status = -ENOSPC;
377262306a36Sopenharmony_ci	}
377362306a36Sopenharmony_ci
377462306a36Sopenharmony_ci	/* else scan the schedule to find a group of slots such that all
377562306a36Sopenharmony_ci	 * uframes have enough periodic bandwidth available.
377662306a36Sopenharmony_ci	 */
377762306a36Sopenharmony_ci	if (status) {
377862306a36Sopenharmony_ci		/* "normal" case, uframing flexible except with splits */
377962306a36Sopenharmony_ci		if (qh->period) {
378062306a36Sopenharmony_ci			int i;
378162306a36Sopenharmony_ci
378262306a36Sopenharmony_ci			for (i = qh->period; status && i > 0; --i) {
378362306a36Sopenharmony_ci				frame = ++fotg210->random_frame % qh->period;
378462306a36Sopenharmony_ci				for (uframe = 0; uframe < 8; uframe++) {
378562306a36Sopenharmony_ci					status = check_intr_schedule(fotg210,
378662306a36Sopenharmony_ci							frame, uframe, qh,
378762306a36Sopenharmony_ci							&c_mask);
378862306a36Sopenharmony_ci					if (status == 0)
378962306a36Sopenharmony_ci						break;
379062306a36Sopenharmony_ci				}
379162306a36Sopenharmony_ci			}
379262306a36Sopenharmony_ci
379362306a36Sopenharmony_ci		/* qh->period == 0 means every uframe */
379462306a36Sopenharmony_ci		} else {
379562306a36Sopenharmony_ci			frame = 0;
379662306a36Sopenharmony_ci			status = check_intr_schedule(fotg210, 0, 0, qh,
379762306a36Sopenharmony_ci					&c_mask);
379862306a36Sopenharmony_ci		}
379962306a36Sopenharmony_ci		if (status)
380062306a36Sopenharmony_ci			goto done;
380162306a36Sopenharmony_ci		qh->start = frame;
380262306a36Sopenharmony_ci
380362306a36Sopenharmony_ci		/* reset S-frame and (maybe) C-frame masks */
380462306a36Sopenharmony_ci		hw->hw_info2 &= cpu_to_hc32(fotg210, ~(QH_CMASK | QH_SMASK));
380562306a36Sopenharmony_ci		hw->hw_info2 |= qh->period
380662306a36Sopenharmony_ci			? cpu_to_hc32(fotg210, 1 << uframe)
380762306a36Sopenharmony_ci			: cpu_to_hc32(fotg210, QH_SMASK);
380862306a36Sopenharmony_ci		hw->hw_info2 |= c_mask;
380962306a36Sopenharmony_ci	} else
381062306a36Sopenharmony_ci		fotg210_dbg(fotg210, "reused qh %p schedule\n", qh);
381162306a36Sopenharmony_ci
381262306a36Sopenharmony_ci	/* stuff into the periodic schedule */
381362306a36Sopenharmony_ci	qh_link_periodic(fotg210, qh);
381462306a36Sopenharmony_cidone:
381562306a36Sopenharmony_ci	return status;
381662306a36Sopenharmony_ci}
381762306a36Sopenharmony_ci
381862306a36Sopenharmony_cistatic int intr_submit(struct fotg210_hcd *fotg210, struct urb *urb,
381962306a36Sopenharmony_ci		struct list_head *qtd_list, gfp_t mem_flags)
382062306a36Sopenharmony_ci{
382162306a36Sopenharmony_ci	unsigned epnum;
382262306a36Sopenharmony_ci	unsigned long flags;
382362306a36Sopenharmony_ci	struct fotg210_qh *qh;
382462306a36Sopenharmony_ci	int status;
382562306a36Sopenharmony_ci	struct list_head empty;
382662306a36Sopenharmony_ci
382762306a36Sopenharmony_ci	/* get endpoint and transfer/schedule data */
382862306a36Sopenharmony_ci	epnum = urb->ep->desc.bEndpointAddress;
382962306a36Sopenharmony_ci
383062306a36Sopenharmony_ci	spin_lock_irqsave(&fotg210->lock, flags);
383162306a36Sopenharmony_ci
383262306a36Sopenharmony_ci	if (unlikely(!HCD_HW_ACCESSIBLE(fotg210_to_hcd(fotg210)))) {
383362306a36Sopenharmony_ci		status = -ESHUTDOWN;
383462306a36Sopenharmony_ci		goto done_not_linked;
383562306a36Sopenharmony_ci	}
383662306a36Sopenharmony_ci	status = usb_hcd_link_urb_to_ep(fotg210_to_hcd(fotg210), urb);
383762306a36Sopenharmony_ci	if (unlikely(status))
383862306a36Sopenharmony_ci		goto done_not_linked;
383962306a36Sopenharmony_ci
384062306a36Sopenharmony_ci	/* get qh and force any scheduling errors */
384162306a36Sopenharmony_ci	INIT_LIST_HEAD(&empty);
384262306a36Sopenharmony_ci	qh = qh_append_tds(fotg210, urb, &empty, epnum, &urb->ep->hcpriv);
384362306a36Sopenharmony_ci	if (qh == NULL) {
384462306a36Sopenharmony_ci		status = -ENOMEM;
384562306a36Sopenharmony_ci		goto done;
384662306a36Sopenharmony_ci	}
384762306a36Sopenharmony_ci	if (qh->qh_state == QH_STATE_IDLE) {
384862306a36Sopenharmony_ci		status = qh_schedule(fotg210, qh);
384962306a36Sopenharmony_ci		if (status)
385062306a36Sopenharmony_ci			goto done;
385162306a36Sopenharmony_ci	}
385262306a36Sopenharmony_ci
385362306a36Sopenharmony_ci	/* then queue the urb's tds to the qh */
385462306a36Sopenharmony_ci	qh = qh_append_tds(fotg210, urb, qtd_list, epnum, &urb->ep->hcpriv);
385562306a36Sopenharmony_ci	BUG_ON(qh == NULL);
385662306a36Sopenharmony_ci
385762306a36Sopenharmony_ci	/* ... update usbfs periodic stats */
385862306a36Sopenharmony_ci	fotg210_to_hcd(fotg210)->self.bandwidth_int_reqs++;
385962306a36Sopenharmony_ci
386062306a36Sopenharmony_cidone:
386162306a36Sopenharmony_ci	if (unlikely(status))
386262306a36Sopenharmony_ci		usb_hcd_unlink_urb_from_ep(fotg210_to_hcd(fotg210), urb);
386362306a36Sopenharmony_cidone_not_linked:
386462306a36Sopenharmony_ci	spin_unlock_irqrestore(&fotg210->lock, flags);
386562306a36Sopenharmony_ci	if (status)
386662306a36Sopenharmony_ci		qtd_list_free(fotg210, urb, qtd_list);
386762306a36Sopenharmony_ci
386862306a36Sopenharmony_ci	return status;
386962306a36Sopenharmony_ci}
387062306a36Sopenharmony_ci
387162306a36Sopenharmony_cistatic void scan_intr(struct fotg210_hcd *fotg210)
387262306a36Sopenharmony_ci{
387362306a36Sopenharmony_ci	struct fotg210_qh *qh;
387462306a36Sopenharmony_ci
387562306a36Sopenharmony_ci	list_for_each_entry_safe(qh, fotg210->qh_scan_next,
387662306a36Sopenharmony_ci			&fotg210->intr_qh_list, intr_node) {
387762306a36Sopenharmony_cirescan:
387862306a36Sopenharmony_ci		/* clean any finished work for this qh */
387962306a36Sopenharmony_ci		if (!list_empty(&qh->qtd_list)) {
388062306a36Sopenharmony_ci			int temp;
388162306a36Sopenharmony_ci
388262306a36Sopenharmony_ci			/*
388362306a36Sopenharmony_ci			 * Unlinks could happen here; completion reporting
388462306a36Sopenharmony_ci			 * drops the lock.  That's why fotg210->qh_scan_next
388562306a36Sopenharmony_ci			 * always holds the next qh to scan; if the next qh
388662306a36Sopenharmony_ci			 * gets unlinked then fotg210->qh_scan_next is adjusted
388762306a36Sopenharmony_ci			 * in qh_unlink_periodic().
388862306a36Sopenharmony_ci			 */
388962306a36Sopenharmony_ci			temp = qh_completions(fotg210, qh);
389062306a36Sopenharmony_ci			if (unlikely(qh->needs_rescan ||
389162306a36Sopenharmony_ci					(list_empty(&qh->qtd_list) &&
389262306a36Sopenharmony_ci					qh->qh_state == QH_STATE_LINKED)))
389362306a36Sopenharmony_ci				start_unlink_intr(fotg210, qh);
389462306a36Sopenharmony_ci			else if (temp != 0)
389562306a36Sopenharmony_ci				goto rescan;
389662306a36Sopenharmony_ci		}
389762306a36Sopenharmony_ci	}
389862306a36Sopenharmony_ci}
389962306a36Sopenharmony_ci
390062306a36Sopenharmony_ci/* fotg210_iso_stream ops work with both ITD and SITD */
390162306a36Sopenharmony_ci
390262306a36Sopenharmony_cistatic struct fotg210_iso_stream *iso_stream_alloc(gfp_t mem_flags)
390362306a36Sopenharmony_ci{
390462306a36Sopenharmony_ci	struct fotg210_iso_stream *stream;
390562306a36Sopenharmony_ci
390662306a36Sopenharmony_ci	stream = kzalloc(sizeof(*stream), mem_flags);
390762306a36Sopenharmony_ci	if (likely(stream != NULL)) {
390862306a36Sopenharmony_ci		INIT_LIST_HEAD(&stream->td_list);
390962306a36Sopenharmony_ci		INIT_LIST_HEAD(&stream->free_list);
391062306a36Sopenharmony_ci		stream->next_uframe = -1;
391162306a36Sopenharmony_ci	}
391262306a36Sopenharmony_ci	return stream;
391362306a36Sopenharmony_ci}
391462306a36Sopenharmony_ci
391562306a36Sopenharmony_cistatic void iso_stream_init(struct fotg210_hcd *fotg210,
391662306a36Sopenharmony_ci		struct fotg210_iso_stream *stream, struct usb_device *dev,
391762306a36Sopenharmony_ci		int pipe, unsigned interval)
391862306a36Sopenharmony_ci{
391962306a36Sopenharmony_ci	u32 buf1;
392062306a36Sopenharmony_ci	unsigned epnum, maxp;
392162306a36Sopenharmony_ci	int is_input;
392262306a36Sopenharmony_ci	long bandwidth;
392362306a36Sopenharmony_ci	unsigned multi;
392462306a36Sopenharmony_ci	struct usb_host_endpoint *ep;
392562306a36Sopenharmony_ci
392662306a36Sopenharmony_ci	/*
392762306a36Sopenharmony_ci	 * this might be a "high bandwidth" highspeed endpoint,
392862306a36Sopenharmony_ci	 * as encoded in the ep descriptor's wMaxPacket field
392962306a36Sopenharmony_ci	 */
393062306a36Sopenharmony_ci	epnum = usb_pipeendpoint(pipe);
393162306a36Sopenharmony_ci	is_input = usb_pipein(pipe) ? USB_DIR_IN : 0;
393262306a36Sopenharmony_ci	ep = usb_pipe_endpoint(dev, pipe);
393362306a36Sopenharmony_ci	maxp = usb_endpoint_maxp(&ep->desc);
393462306a36Sopenharmony_ci	if (is_input)
393562306a36Sopenharmony_ci		buf1 = (1 << 11);
393662306a36Sopenharmony_ci	else
393762306a36Sopenharmony_ci		buf1 = 0;
393862306a36Sopenharmony_ci
393962306a36Sopenharmony_ci	multi = usb_endpoint_maxp_mult(&ep->desc);
394062306a36Sopenharmony_ci	buf1 |= maxp;
394162306a36Sopenharmony_ci	maxp *= multi;
394262306a36Sopenharmony_ci
394362306a36Sopenharmony_ci	stream->buf0 = cpu_to_hc32(fotg210, (epnum << 8) | dev->devnum);
394462306a36Sopenharmony_ci	stream->buf1 = cpu_to_hc32(fotg210, buf1);
394562306a36Sopenharmony_ci	stream->buf2 = cpu_to_hc32(fotg210, multi);
394662306a36Sopenharmony_ci
394762306a36Sopenharmony_ci	/* usbfs wants to report the average usecs per frame tied up
394862306a36Sopenharmony_ci	 * when transfers on this endpoint are scheduled ...
394962306a36Sopenharmony_ci	 */
395062306a36Sopenharmony_ci	if (dev->speed == USB_SPEED_FULL) {
395162306a36Sopenharmony_ci		interval <<= 3;
395262306a36Sopenharmony_ci		stream->usecs = NS_TO_US(usb_calc_bus_time(dev->speed,
395362306a36Sopenharmony_ci				is_input, 1, maxp));
395462306a36Sopenharmony_ci		stream->usecs /= 8;
395562306a36Sopenharmony_ci	} else {
395662306a36Sopenharmony_ci		stream->highspeed = 1;
395762306a36Sopenharmony_ci		stream->usecs = HS_USECS_ISO(maxp);
395862306a36Sopenharmony_ci	}
395962306a36Sopenharmony_ci	bandwidth = stream->usecs * 8;
396062306a36Sopenharmony_ci	bandwidth /= interval;
396162306a36Sopenharmony_ci
396262306a36Sopenharmony_ci	stream->bandwidth = bandwidth;
396362306a36Sopenharmony_ci	stream->udev = dev;
396462306a36Sopenharmony_ci	stream->bEndpointAddress = is_input | epnum;
396562306a36Sopenharmony_ci	stream->interval = interval;
396662306a36Sopenharmony_ci	stream->maxp = maxp;
396762306a36Sopenharmony_ci}
396862306a36Sopenharmony_ci
396962306a36Sopenharmony_cistatic struct fotg210_iso_stream *iso_stream_find(struct fotg210_hcd *fotg210,
397062306a36Sopenharmony_ci		struct urb *urb)
397162306a36Sopenharmony_ci{
397262306a36Sopenharmony_ci	unsigned epnum;
397362306a36Sopenharmony_ci	struct fotg210_iso_stream *stream;
397462306a36Sopenharmony_ci	struct usb_host_endpoint *ep;
397562306a36Sopenharmony_ci	unsigned long flags;
397662306a36Sopenharmony_ci
397762306a36Sopenharmony_ci	epnum = usb_pipeendpoint(urb->pipe);
397862306a36Sopenharmony_ci	if (usb_pipein(urb->pipe))
397962306a36Sopenharmony_ci		ep = urb->dev->ep_in[epnum];
398062306a36Sopenharmony_ci	else
398162306a36Sopenharmony_ci		ep = urb->dev->ep_out[epnum];
398262306a36Sopenharmony_ci
398362306a36Sopenharmony_ci	spin_lock_irqsave(&fotg210->lock, flags);
398462306a36Sopenharmony_ci	stream = ep->hcpriv;
398562306a36Sopenharmony_ci
398662306a36Sopenharmony_ci	if (unlikely(stream == NULL)) {
398762306a36Sopenharmony_ci		stream = iso_stream_alloc(GFP_ATOMIC);
398862306a36Sopenharmony_ci		if (likely(stream != NULL)) {
398962306a36Sopenharmony_ci			ep->hcpriv = stream;
399062306a36Sopenharmony_ci			stream->ep = ep;
399162306a36Sopenharmony_ci			iso_stream_init(fotg210, stream, urb->dev, urb->pipe,
399262306a36Sopenharmony_ci					urb->interval);
399362306a36Sopenharmony_ci		}
399462306a36Sopenharmony_ci
399562306a36Sopenharmony_ci	/* if dev->ep[epnum] is a QH, hw is set */
399662306a36Sopenharmony_ci	} else if (unlikely(stream->hw != NULL)) {
399762306a36Sopenharmony_ci		fotg210_dbg(fotg210, "dev %s ep%d%s, not iso??\n",
399862306a36Sopenharmony_ci				urb->dev->devpath, epnum,
399962306a36Sopenharmony_ci				usb_pipein(urb->pipe) ? "in" : "out");
400062306a36Sopenharmony_ci		stream = NULL;
400162306a36Sopenharmony_ci	}
400262306a36Sopenharmony_ci
400362306a36Sopenharmony_ci	spin_unlock_irqrestore(&fotg210->lock, flags);
400462306a36Sopenharmony_ci	return stream;
400562306a36Sopenharmony_ci}
400662306a36Sopenharmony_ci
400762306a36Sopenharmony_ci/* fotg210_iso_sched ops can be ITD-only or SITD-only */
400862306a36Sopenharmony_ci
400962306a36Sopenharmony_cistatic struct fotg210_iso_sched *iso_sched_alloc(unsigned packets,
401062306a36Sopenharmony_ci		gfp_t mem_flags)
401162306a36Sopenharmony_ci{
401262306a36Sopenharmony_ci	struct fotg210_iso_sched *iso_sched;
401362306a36Sopenharmony_ci
401462306a36Sopenharmony_ci	iso_sched = kzalloc(struct_size(iso_sched, packet, packets), mem_flags);
401562306a36Sopenharmony_ci	if (likely(iso_sched != NULL))
401662306a36Sopenharmony_ci		INIT_LIST_HEAD(&iso_sched->td_list);
401762306a36Sopenharmony_ci
401862306a36Sopenharmony_ci	return iso_sched;
401962306a36Sopenharmony_ci}
402062306a36Sopenharmony_ci
402162306a36Sopenharmony_cistatic inline void itd_sched_init(struct fotg210_hcd *fotg210,
402262306a36Sopenharmony_ci		struct fotg210_iso_sched *iso_sched,
402362306a36Sopenharmony_ci		struct fotg210_iso_stream *stream, struct urb *urb)
402462306a36Sopenharmony_ci{
402562306a36Sopenharmony_ci	unsigned i;
402662306a36Sopenharmony_ci	dma_addr_t dma = urb->transfer_dma;
402762306a36Sopenharmony_ci
402862306a36Sopenharmony_ci	/* how many uframes are needed for these transfers */
402962306a36Sopenharmony_ci	iso_sched->span = urb->number_of_packets * stream->interval;
403062306a36Sopenharmony_ci
403162306a36Sopenharmony_ci	/* figure out per-uframe itd fields that we'll need later
403262306a36Sopenharmony_ci	 * when we fit new itds into the schedule.
403362306a36Sopenharmony_ci	 */
403462306a36Sopenharmony_ci	for (i = 0; i < urb->number_of_packets; i++) {
403562306a36Sopenharmony_ci		struct fotg210_iso_packet *uframe = &iso_sched->packet[i];
403662306a36Sopenharmony_ci		unsigned length;
403762306a36Sopenharmony_ci		dma_addr_t buf;
403862306a36Sopenharmony_ci		u32 trans;
403962306a36Sopenharmony_ci
404062306a36Sopenharmony_ci		length = urb->iso_frame_desc[i].length;
404162306a36Sopenharmony_ci		buf = dma + urb->iso_frame_desc[i].offset;
404262306a36Sopenharmony_ci
404362306a36Sopenharmony_ci		trans = FOTG210_ISOC_ACTIVE;
404462306a36Sopenharmony_ci		trans |= buf & 0x0fff;
404562306a36Sopenharmony_ci		if (unlikely(((i + 1) == urb->number_of_packets))
404662306a36Sopenharmony_ci				&& !(urb->transfer_flags & URB_NO_INTERRUPT))
404762306a36Sopenharmony_ci			trans |= FOTG210_ITD_IOC;
404862306a36Sopenharmony_ci		trans |= length << 16;
404962306a36Sopenharmony_ci		uframe->transaction = cpu_to_hc32(fotg210, trans);
405062306a36Sopenharmony_ci
405162306a36Sopenharmony_ci		/* might need to cross a buffer page within a uframe */
405262306a36Sopenharmony_ci		uframe->bufp = (buf & ~(u64)0x0fff);
405362306a36Sopenharmony_ci		buf += length;
405462306a36Sopenharmony_ci		if (unlikely((uframe->bufp != (buf & ~(u64)0x0fff))))
405562306a36Sopenharmony_ci			uframe->cross = 1;
405662306a36Sopenharmony_ci	}
405762306a36Sopenharmony_ci}
405862306a36Sopenharmony_ci
405962306a36Sopenharmony_cistatic void iso_sched_free(struct fotg210_iso_stream *stream,
406062306a36Sopenharmony_ci		struct fotg210_iso_sched *iso_sched)
406162306a36Sopenharmony_ci{
406262306a36Sopenharmony_ci	if (!iso_sched)
406362306a36Sopenharmony_ci		return;
406462306a36Sopenharmony_ci	/* caller must hold fotg210->lock!*/
406562306a36Sopenharmony_ci	list_splice(&iso_sched->td_list, &stream->free_list);
406662306a36Sopenharmony_ci	kfree(iso_sched);
406762306a36Sopenharmony_ci}
406862306a36Sopenharmony_ci
406962306a36Sopenharmony_cistatic int itd_urb_transaction(struct fotg210_iso_stream *stream,
407062306a36Sopenharmony_ci		struct fotg210_hcd *fotg210, struct urb *urb, gfp_t mem_flags)
407162306a36Sopenharmony_ci{
407262306a36Sopenharmony_ci	struct fotg210_itd *itd;
407362306a36Sopenharmony_ci	dma_addr_t itd_dma;
407462306a36Sopenharmony_ci	int i;
407562306a36Sopenharmony_ci	unsigned num_itds;
407662306a36Sopenharmony_ci	struct fotg210_iso_sched *sched;
407762306a36Sopenharmony_ci	unsigned long flags;
407862306a36Sopenharmony_ci
407962306a36Sopenharmony_ci	sched = iso_sched_alloc(urb->number_of_packets, mem_flags);
408062306a36Sopenharmony_ci	if (unlikely(sched == NULL))
408162306a36Sopenharmony_ci		return -ENOMEM;
408262306a36Sopenharmony_ci
408362306a36Sopenharmony_ci	itd_sched_init(fotg210, sched, stream, urb);
408462306a36Sopenharmony_ci
408562306a36Sopenharmony_ci	if (urb->interval < 8)
408662306a36Sopenharmony_ci		num_itds = 1 + (sched->span + 7) / 8;
408762306a36Sopenharmony_ci	else
408862306a36Sopenharmony_ci		num_itds = urb->number_of_packets;
408962306a36Sopenharmony_ci
409062306a36Sopenharmony_ci	/* allocate/init ITDs */
409162306a36Sopenharmony_ci	spin_lock_irqsave(&fotg210->lock, flags);
409262306a36Sopenharmony_ci	for (i = 0; i < num_itds; i++) {
409362306a36Sopenharmony_ci
409462306a36Sopenharmony_ci		/*
409562306a36Sopenharmony_ci		 * Use iTDs from the free list, but not iTDs that may
409662306a36Sopenharmony_ci		 * still be in use by the hardware.
409762306a36Sopenharmony_ci		 */
409862306a36Sopenharmony_ci		if (likely(!list_empty(&stream->free_list))) {
409962306a36Sopenharmony_ci			itd = list_first_entry(&stream->free_list,
410062306a36Sopenharmony_ci					struct fotg210_itd, itd_list);
410162306a36Sopenharmony_ci			if (itd->frame == fotg210->now_frame)
410262306a36Sopenharmony_ci				goto alloc_itd;
410362306a36Sopenharmony_ci			list_del(&itd->itd_list);
410462306a36Sopenharmony_ci			itd_dma = itd->itd_dma;
410562306a36Sopenharmony_ci		} else {
410662306a36Sopenharmony_cialloc_itd:
410762306a36Sopenharmony_ci			spin_unlock_irqrestore(&fotg210->lock, flags);
410862306a36Sopenharmony_ci			itd = dma_pool_alloc(fotg210->itd_pool, mem_flags,
410962306a36Sopenharmony_ci					&itd_dma);
411062306a36Sopenharmony_ci			spin_lock_irqsave(&fotg210->lock, flags);
411162306a36Sopenharmony_ci			if (!itd) {
411262306a36Sopenharmony_ci				iso_sched_free(stream, sched);
411362306a36Sopenharmony_ci				spin_unlock_irqrestore(&fotg210->lock, flags);
411462306a36Sopenharmony_ci				return -ENOMEM;
411562306a36Sopenharmony_ci			}
411662306a36Sopenharmony_ci		}
411762306a36Sopenharmony_ci
411862306a36Sopenharmony_ci		memset(itd, 0, sizeof(*itd));
411962306a36Sopenharmony_ci		itd->itd_dma = itd_dma;
412062306a36Sopenharmony_ci		list_add(&itd->itd_list, &sched->td_list);
412162306a36Sopenharmony_ci	}
412262306a36Sopenharmony_ci	spin_unlock_irqrestore(&fotg210->lock, flags);
412362306a36Sopenharmony_ci
412462306a36Sopenharmony_ci	/* temporarily store schedule info in hcpriv */
412562306a36Sopenharmony_ci	urb->hcpriv = sched;
412662306a36Sopenharmony_ci	urb->error_count = 0;
412762306a36Sopenharmony_ci	return 0;
412862306a36Sopenharmony_ci}
412962306a36Sopenharmony_ci
413062306a36Sopenharmony_cistatic inline int itd_slot_ok(struct fotg210_hcd *fotg210, u32 mod, u32 uframe,
413162306a36Sopenharmony_ci		u8 usecs, u32 period)
413262306a36Sopenharmony_ci{
413362306a36Sopenharmony_ci	uframe %= period;
413462306a36Sopenharmony_ci	do {
413562306a36Sopenharmony_ci		/* can't commit more than uframe_periodic_max usec */
413662306a36Sopenharmony_ci		if (periodic_usecs(fotg210, uframe >> 3, uframe & 0x7)
413762306a36Sopenharmony_ci				> (fotg210->uframe_periodic_max - usecs))
413862306a36Sopenharmony_ci			return 0;
413962306a36Sopenharmony_ci
414062306a36Sopenharmony_ci		/* we know urb->interval is 2^N uframes */
414162306a36Sopenharmony_ci		uframe += period;
414262306a36Sopenharmony_ci	} while (uframe < mod);
414362306a36Sopenharmony_ci	return 1;
414462306a36Sopenharmony_ci}
414562306a36Sopenharmony_ci
414662306a36Sopenharmony_ci/* This scheduler plans almost as far into the future as it has actual
414762306a36Sopenharmony_ci * periodic schedule slots.  (Affected by TUNE_FLS, which defaults to
414862306a36Sopenharmony_ci * "as small as possible" to be cache-friendlier.)  That limits the size
414962306a36Sopenharmony_ci * transfers you can stream reliably; avoid more than 64 msec per urb.
415062306a36Sopenharmony_ci * Also avoid queue depths of less than fotg210's worst irq latency (affected
415162306a36Sopenharmony_ci * by the per-urb URB_NO_INTERRUPT hint, the log2_irq_thresh module parameter,
415262306a36Sopenharmony_ci * and other factors); or more than about 230 msec total (for portability,
415362306a36Sopenharmony_ci * given FOTG210_TUNE_FLS and the slop).  Or, write a smarter scheduler!
415462306a36Sopenharmony_ci */
415562306a36Sopenharmony_ci
415662306a36Sopenharmony_ci#define SCHEDULE_SLOP 80 /* microframes */
415762306a36Sopenharmony_ci
415862306a36Sopenharmony_cistatic int iso_stream_schedule(struct fotg210_hcd *fotg210, struct urb *urb,
415962306a36Sopenharmony_ci		struct fotg210_iso_stream *stream)
416062306a36Sopenharmony_ci{
416162306a36Sopenharmony_ci	u32 now, next, start, period, span;
416262306a36Sopenharmony_ci	int status;
416362306a36Sopenharmony_ci	unsigned mod = fotg210->periodic_size << 3;
416462306a36Sopenharmony_ci	struct fotg210_iso_sched *sched = urb->hcpriv;
416562306a36Sopenharmony_ci
416662306a36Sopenharmony_ci	period = urb->interval;
416762306a36Sopenharmony_ci	span = sched->span;
416862306a36Sopenharmony_ci
416962306a36Sopenharmony_ci	if (span > mod - SCHEDULE_SLOP) {
417062306a36Sopenharmony_ci		fotg210_dbg(fotg210, "iso request %p too long\n", urb);
417162306a36Sopenharmony_ci		status = -EFBIG;
417262306a36Sopenharmony_ci		goto fail;
417362306a36Sopenharmony_ci	}
417462306a36Sopenharmony_ci
417562306a36Sopenharmony_ci	now = fotg210_read_frame_index(fotg210) & (mod - 1);
417662306a36Sopenharmony_ci
417762306a36Sopenharmony_ci	/* Typical case: reuse current schedule, stream is still active.
417862306a36Sopenharmony_ci	 * Hopefully there are no gaps from the host falling behind
417962306a36Sopenharmony_ci	 * (irq delays etc), but if there are we'll take the next
418062306a36Sopenharmony_ci	 * slot in the schedule, implicitly assuming URB_ISO_ASAP.
418162306a36Sopenharmony_ci	 */
418262306a36Sopenharmony_ci	if (likely(!list_empty(&stream->td_list))) {
418362306a36Sopenharmony_ci		u32 excess;
418462306a36Sopenharmony_ci
418562306a36Sopenharmony_ci		/* For high speed devices, allow scheduling within the
418662306a36Sopenharmony_ci		 * isochronous scheduling threshold.  For full speed devices
418762306a36Sopenharmony_ci		 * and Intel PCI-based controllers, don't (work around for
418862306a36Sopenharmony_ci		 * Intel ICH9 bug).
418962306a36Sopenharmony_ci		 */
419062306a36Sopenharmony_ci		if (!stream->highspeed && fotg210->fs_i_thresh)
419162306a36Sopenharmony_ci			next = now + fotg210->i_thresh;
419262306a36Sopenharmony_ci		else
419362306a36Sopenharmony_ci			next = now;
419462306a36Sopenharmony_ci
419562306a36Sopenharmony_ci		/* Fell behind (by up to twice the slop amount)?
419662306a36Sopenharmony_ci		 * We decide based on the time of the last currently-scheduled
419762306a36Sopenharmony_ci		 * slot, not the time of the next available slot.
419862306a36Sopenharmony_ci		 */
419962306a36Sopenharmony_ci		excess = (stream->next_uframe - period - next) & (mod - 1);
420062306a36Sopenharmony_ci		if (excess >= mod - 2 * SCHEDULE_SLOP)
420162306a36Sopenharmony_ci			start = next + excess - mod + period *
420262306a36Sopenharmony_ci					DIV_ROUND_UP(mod - excess, period);
420362306a36Sopenharmony_ci		else
420462306a36Sopenharmony_ci			start = next + excess + period;
420562306a36Sopenharmony_ci		if (start - now >= mod) {
420662306a36Sopenharmony_ci			fotg210_dbg(fotg210, "request %p would overflow (%d+%d >= %d)\n",
420762306a36Sopenharmony_ci					urb, start - now - period, period,
420862306a36Sopenharmony_ci					mod);
420962306a36Sopenharmony_ci			status = -EFBIG;
421062306a36Sopenharmony_ci			goto fail;
421162306a36Sopenharmony_ci		}
421262306a36Sopenharmony_ci	}
421362306a36Sopenharmony_ci
421462306a36Sopenharmony_ci	/* need to schedule; when's the next (u)frame we could start?
421562306a36Sopenharmony_ci	 * this is bigger than fotg210->i_thresh allows; scheduling itself
421662306a36Sopenharmony_ci	 * isn't free, the slop should handle reasonably slow cpus.  it
421762306a36Sopenharmony_ci	 * can also help high bandwidth if the dma and irq loads don't
421862306a36Sopenharmony_ci	 * jump until after the queue is primed.
421962306a36Sopenharmony_ci	 */
422062306a36Sopenharmony_ci	else {
422162306a36Sopenharmony_ci		int done = 0;
422262306a36Sopenharmony_ci
422362306a36Sopenharmony_ci		start = SCHEDULE_SLOP + (now & ~0x07);
422462306a36Sopenharmony_ci
422562306a36Sopenharmony_ci		/* NOTE:  assumes URB_ISO_ASAP, to limit complexity/bugs */
422662306a36Sopenharmony_ci
422762306a36Sopenharmony_ci		/* find a uframe slot with enough bandwidth.
422862306a36Sopenharmony_ci		 * Early uframes are more precious because full-speed
422962306a36Sopenharmony_ci		 * iso IN transfers can't use late uframes,
423062306a36Sopenharmony_ci		 * and therefore they should be allocated last.
423162306a36Sopenharmony_ci		 */
423262306a36Sopenharmony_ci		next = start;
423362306a36Sopenharmony_ci		start += period;
423462306a36Sopenharmony_ci		do {
423562306a36Sopenharmony_ci			start--;
423662306a36Sopenharmony_ci			/* check schedule: enough space? */
423762306a36Sopenharmony_ci			if (itd_slot_ok(fotg210, mod, start,
423862306a36Sopenharmony_ci					stream->usecs, period))
423962306a36Sopenharmony_ci				done = 1;
424062306a36Sopenharmony_ci		} while (start > next && !done);
424162306a36Sopenharmony_ci
424262306a36Sopenharmony_ci		/* no room in the schedule */
424362306a36Sopenharmony_ci		if (!done) {
424462306a36Sopenharmony_ci			fotg210_dbg(fotg210, "iso resched full %p (now %d max %d)\n",
424562306a36Sopenharmony_ci					urb, now, now + mod);
424662306a36Sopenharmony_ci			status = -ENOSPC;
424762306a36Sopenharmony_ci			goto fail;
424862306a36Sopenharmony_ci		}
424962306a36Sopenharmony_ci	}
425062306a36Sopenharmony_ci
425162306a36Sopenharmony_ci	/* Tried to schedule too far into the future? */
425262306a36Sopenharmony_ci	if (unlikely(start - now + span - period >=
425362306a36Sopenharmony_ci			mod - 2 * SCHEDULE_SLOP)) {
425462306a36Sopenharmony_ci		fotg210_dbg(fotg210, "request %p would overflow (%d+%d >= %d)\n",
425562306a36Sopenharmony_ci				urb, start - now, span - period,
425662306a36Sopenharmony_ci				mod - 2 * SCHEDULE_SLOP);
425762306a36Sopenharmony_ci		status = -EFBIG;
425862306a36Sopenharmony_ci		goto fail;
425962306a36Sopenharmony_ci	}
426062306a36Sopenharmony_ci
426162306a36Sopenharmony_ci	stream->next_uframe = start & (mod - 1);
426262306a36Sopenharmony_ci
426362306a36Sopenharmony_ci	/* report high speed start in uframes; full speed, in frames */
426462306a36Sopenharmony_ci	urb->start_frame = stream->next_uframe;
426562306a36Sopenharmony_ci	if (!stream->highspeed)
426662306a36Sopenharmony_ci		urb->start_frame >>= 3;
426762306a36Sopenharmony_ci
426862306a36Sopenharmony_ci	/* Make sure scan_isoc() sees these */
426962306a36Sopenharmony_ci	if (fotg210->isoc_count == 0)
427062306a36Sopenharmony_ci		fotg210->next_frame = now >> 3;
427162306a36Sopenharmony_ci	return 0;
427262306a36Sopenharmony_ci
427362306a36Sopenharmony_cifail:
427462306a36Sopenharmony_ci	iso_sched_free(stream, sched);
427562306a36Sopenharmony_ci	urb->hcpriv = NULL;
427662306a36Sopenharmony_ci	return status;
427762306a36Sopenharmony_ci}
427862306a36Sopenharmony_ci
427962306a36Sopenharmony_cistatic inline void itd_init(struct fotg210_hcd *fotg210,
428062306a36Sopenharmony_ci		struct fotg210_iso_stream *stream, struct fotg210_itd *itd)
428162306a36Sopenharmony_ci{
428262306a36Sopenharmony_ci	int i;
428362306a36Sopenharmony_ci
428462306a36Sopenharmony_ci	/* it's been recently zeroed */
428562306a36Sopenharmony_ci	itd->hw_next = FOTG210_LIST_END(fotg210);
428662306a36Sopenharmony_ci	itd->hw_bufp[0] = stream->buf0;
428762306a36Sopenharmony_ci	itd->hw_bufp[1] = stream->buf1;
428862306a36Sopenharmony_ci	itd->hw_bufp[2] = stream->buf2;
428962306a36Sopenharmony_ci
429062306a36Sopenharmony_ci	for (i = 0; i < 8; i++)
429162306a36Sopenharmony_ci		itd->index[i] = -1;
429262306a36Sopenharmony_ci
429362306a36Sopenharmony_ci	/* All other fields are filled when scheduling */
429462306a36Sopenharmony_ci}
429562306a36Sopenharmony_ci
429662306a36Sopenharmony_cistatic inline void itd_patch(struct fotg210_hcd *fotg210,
429762306a36Sopenharmony_ci		struct fotg210_itd *itd, struct fotg210_iso_sched *iso_sched,
429862306a36Sopenharmony_ci		unsigned index, u16 uframe)
429962306a36Sopenharmony_ci{
430062306a36Sopenharmony_ci	struct fotg210_iso_packet *uf = &iso_sched->packet[index];
430162306a36Sopenharmony_ci	unsigned pg = itd->pg;
430262306a36Sopenharmony_ci
430362306a36Sopenharmony_ci	uframe &= 0x07;
430462306a36Sopenharmony_ci	itd->index[uframe] = index;
430562306a36Sopenharmony_ci
430662306a36Sopenharmony_ci	itd->hw_transaction[uframe] = uf->transaction;
430762306a36Sopenharmony_ci	itd->hw_transaction[uframe] |= cpu_to_hc32(fotg210, pg << 12);
430862306a36Sopenharmony_ci	itd->hw_bufp[pg] |= cpu_to_hc32(fotg210, uf->bufp & ~(u32)0);
430962306a36Sopenharmony_ci	itd->hw_bufp_hi[pg] |= cpu_to_hc32(fotg210, (u32)(uf->bufp >> 32));
431062306a36Sopenharmony_ci
431162306a36Sopenharmony_ci	/* iso_frame_desc[].offset must be strictly increasing */
431262306a36Sopenharmony_ci	if (unlikely(uf->cross)) {
431362306a36Sopenharmony_ci		u64 bufp = uf->bufp + 4096;
431462306a36Sopenharmony_ci
431562306a36Sopenharmony_ci		itd->pg = ++pg;
431662306a36Sopenharmony_ci		itd->hw_bufp[pg] |= cpu_to_hc32(fotg210, bufp & ~(u32)0);
431762306a36Sopenharmony_ci		itd->hw_bufp_hi[pg] |= cpu_to_hc32(fotg210, (u32)(bufp >> 32));
431862306a36Sopenharmony_ci	}
431962306a36Sopenharmony_ci}
432062306a36Sopenharmony_ci
432162306a36Sopenharmony_cistatic inline void itd_link(struct fotg210_hcd *fotg210, unsigned frame,
432262306a36Sopenharmony_ci		struct fotg210_itd *itd)
432362306a36Sopenharmony_ci{
432462306a36Sopenharmony_ci	union fotg210_shadow *prev = &fotg210->pshadow[frame];
432562306a36Sopenharmony_ci	__hc32 *hw_p = &fotg210->periodic[frame];
432662306a36Sopenharmony_ci	union fotg210_shadow here = *prev;
432762306a36Sopenharmony_ci	__hc32 type = 0;
432862306a36Sopenharmony_ci
432962306a36Sopenharmony_ci	/* skip any iso nodes which might belong to previous microframes */
433062306a36Sopenharmony_ci	while (here.ptr) {
433162306a36Sopenharmony_ci		type = Q_NEXT_TYPE(fotg210, *hw_p);
433262306a36Sopenharmony_ci		if (type == cpu_to_hc32(fotg210, Q_TYPE_QH))
433362306a36Sopenharmony_ci			break;
433462306a36Sopenharmony_ci		prev = periodic_next_shadow(fotg210, prev, type);
433562306a36Sopenharmony_ci		hw_p = shadow_next_periodic(fotg210, &here, type);
433662306a36Sopenharmony_ci		here = *prev;
433762306a36Sopenharmony_ci	}
433862306a36Sopenharmony_ci
433962306a36Sopenharmony_ci	itd->itd_next = here;
434062306a36Sopenharmony_ci	itd->hw_next = *hw_p;
434162306a36Sopenharmony_ci	prev->itd = itd;
434262306a36Sopenharmony_ci	itd->frame = frame;
434362306a36Sopenharmony_ci	wmb();
434462306a36Sopenharmony_ci	*hw_p = cpu_to_hc32(fotg210, itd->itd_dma | Q_TYPE_ITD);
434562306a36Sopenharmony_ci}
434662306a36Sopenharmony_ci
434762306a36Sopenharmony_ci/* fit urb's itds into the selected schedule slot; activate as needed */
434862306a36Sopenharmony_cistatic void itd_link_urb(struct fotg210_hcd *fotg210, struct urb *urb,
434962306a36Sopenharmony_ci		unsigned mod, struct fotg210_iso_stream *stream)
435062306a36Sopenharmony_ci{
435162306a36Sopenharmony_ci	int packet;
435262306a36Sopenharmony_ci	unsigned next_uframe, uframe, frame;
435362306a36Sopenharmony_ci	struct fotg210_iso_sched *iso_sched = urb->hcpriv;
435462306a36Sopenharmony_ci	struct fotg210_itd *itd;
435562306a36Sopenharmony_ci
435662306a36Sopenharmony_ci	next_uframe = stream->next_uframe & (mod - 1);
435762306a36Sopenharmony_ci
435862306a36Sopenharmony_ci	if (unlikely(list_empty(&stream->td_list))) {
435962306a36Sopenharmony_ci		fotg210_to_hcd(fotg210)->self.bandwidth_allocated
436062306a36Sopenharmony_ci				+= stream->bandwidth;
436162306a36Sopenharmony_ci		fotg210_dbg(fotg210,
436262306a36Sopenharmony_ci			"schedule devp %s ep%d%s-iso period %d start %d.%d\n",
436362306a36Sopenharmony_ci			urb->dev->devpath, stream->bEndpointAddress & 0x0f,
436462306a36Sopenharmony_ci			(stream->bEndpointAddress & USB_DIR_IN) ? "in" : "out",
436562306a36Sopenharmony_ci			urb->interval,
436662306a36Sopenharmony_ci			next_uframe >> 3, next_uframe & 0x7);
436762306a36Sopenharmony_ci	}
436862306a36Sopenharmony_ci
436962306a36Sopenharmony_ci	/* fill iTDs uframe by uframe */
437062306a36Sopenharmony_ci	for (packet = 0, itd = NULL; packet < urb->number_of_packets;) {
437162306a36Sopenharmony_ci		if (itd == NULL) {
437262306a36Sopenharmony_ci			/* ASSERT:  we have all necessary itds */
437362306a36Sopenharmony_ci
437462306a36Sopenharmony_ci			/* ASSERT:  no itds for this endpoint in this uframe */
437562306a36Sopenharmony_ci
437662306a36Sopenharmony_ci			itd = list_entry(iso_sched->td_list.next,
437762306a36Sopenharmony_ci					struct fotg210_itd, itd_list);
437862306a36Sopenharmony_ci			list_move_tail(&itd->itd_list, &stream->td_list);
437962306a36Sopenharmony_ci			itd->stream = stream;
438062306a36Sopenharmony_ci			itd->urb = urb;
438162306a36Sopenharmony_ci			itd_init(fotg210, stream, itd);
438262306a36Sopenharmony_ci		}
438362306a36Sopenharmony_ci
438462306a36Sopenharmony_ci		uframe = next_uframe & 0x07;
438562306a36Sopenharmony_ci		frame = next_uframe >> 3;
438662306a36Sopenharmony_ci
438762306a36Sopenharmony_ci		itd_patch(fotg210, itd, iso_sched, packet, uframe);
438862306a36Sopenharmony_ci
438962306a36Sopenharmony_ci		next_uframe += stream->interval;
439062306a36Sopenharmony_ci		next_uframe &= mod - 1;
439162306a36Sopenharmony_ci		packet++;
439262306a36Sopenharmony_ci
439362306a36Sopenharmony_ci		/* link completed itds into the schedule */
439462306a36Sopenharmony_ci		if (((next_uframe >> 3) != frame)
439562306a36Sopenharmony_ci				|| packet == urb->number_of_packets) {
439662306a36Sopenharmony_ci			itd_link(fotg210, frame & (fotg210->periodic_size - 1),
439762306a36Sopenharmony_ci					itd);
439862306a36Sopenharmony_ci			itd = NULL;
439962306a36Sopenharmony_ci		}
440062306a36Sopenharmony_ci	}
440162306a36Sopenharmony_ci	stream->next_uframe = next_uframe;
440262306a36Sopenharmony_ci
440362306a36Sopenharmony_ci	/* don't need that schedule data any more */
440462306a36Sopenharmony_ci	iso_sched_free(stream, iso_sched);
440562306a36Sopenharmony_ci	urb->hcpriv = NULL;
440662306a36Sopenharmony_ci
440762306a36Sopenharmony_ci	++fotg210->isoc_count;
440862306a36Sopenharmony_ci	enable_periodic(fotg210);
440962306a36Sopenharmony_ci}
441062306a36Sopenharmony_ci
441162306a36Sopenharmony_ci#define ISO_ERRS (FOTG210_ISOC_BUF_ERR | FOTG210_ISOC_BABBLE |\
441262306a36Sopenharmony_ci		FOTG210_ISOC_XACTERR)
441362306a36Sopenharmony_ci
441462306a36Sopenharmony_ci/* Process and recycle a completed ITD.  Return true iff its urb completed,
441562306a36Sopenharmony_ci * and hence its completion callback probably added things to the hardware
441662306a36Sopenharmony_ci * schedule.
441762306a36Sopenharmony_ci *
441862306a36Sopenharmony_ci * Note that we carefully avoid recycling this descriptor until after any
441962306a36Sopenharmony_ci * completion callback runs, so that it won't be reused quickly.  That is,
442062306a36Sopenharmony_ci * assuming (a) no more than two urbs per frame on this endpoint, and also
442162306a36Sopenharmony_ci * (b) only this endpoint's completions submit URBs.  It seems some silicon
442262306a36Sopenharmony_ci * corrupts things if you reuse completed descriptors very quickly...
442362306a36Sopenharmony_ci */
442462306a36Sopenharmony_cistatic bool itd_complete(struct fotg210_hcd *fotg210, struct fotg210_itd *itd)
442562306a36Sopenharmony_ci{
442662306a36Sopenharmony_ci	struct urb *urb = itd->urb;
442762306a36Sopenharmony_ci	struct usb_iso_packet_descriptor *desc;
442862306a36Sopenharmony_ci	u32 t;
442962306a36Sopenharmony_ci	unsigned uframe;
443062306a36Sopenharmony_ci	int urb_index = -1;
443162306a36Sopenharmony_ci	struct fotg210_iso_stream *stream = itd->stream;
443262306a36Sopenharmony_ci	struct usb_device *dev;
443362306a36Sopenharmony_ci	bool retval = false;
443462306a36Sopenharmony_ci
443562306a36Sopenharmony_ci	/* for each uframe with a packet */
443662306a36Sopenharmony_ci	for (uframe = 0; uframe < 8; uframe++) {
443762306a36Sopenharmony_ci		if (likely(itd->index[uframe] == -1))
443862306a36Sopenharmony_ci			continue;
443962306a36Sopenharmony_ci		urb_index = itd->index[uframe];
444062306a36Sopenharmony_ci		desc = &urb->iso_frame_desc[urb_index];
444162306a36Sopenharmony_ci
444262306a36Sopenharmony_ci		t = hc32_to_cpup(fotg210, &itd->hw_transaction[uframe]);
444362306a36Sopenharmony_ci		itd->hw_transaction[uframe] = 0;
444462306a36Sopenharmony_ci
444562306a36Sopenharmony_ci		/* report transfer status */
444662306a36Sopenharmony_ci		if (unlikely(t & ISO_ERRS)) {
444762306a36Sopenharmony_ci			urb->error_count++;
444862306a36Sopenharmony_ci			if (t & FOTG210_ISOC_BUF_ERR)
444962306a36Sopenharmony_ci				desc->status = usb_pipein(urb->pipe)
445062306a36Sopenharmony_ci					? -ENOSR  /* hc couldn't read */
445162306a36Sopenharmony_ci					: -ECOMM; /* hc couldn't write */
445262306a36Sopenharmony_ci			else if (t & FOTG210_ISOC_BABBLE)
445362306a36Sopenharmony_ci				desc->status = -EOVERFLOW;
445462306a36Sopenharmony_ci			else /* (t & FOTG210_ISOC_XACTERR) */
445562306a36Sopenharmony_ci				desc->status = -EPROTO;
445662306a36Sopenharmony_ci
445762306a36Sopenharmony_ci			/* HC need not update length with this error */
445862306a36Sopenharmony_ci			if (!(t & FOTG210_ISOC_BABBLE)) {
445962306a36Sopenharmony_ci				desc->actual_length = FOTG210_ITD_LENGTH(t);
446062306a36Sopenharmony_ci				urb->actual_length += desc->actual_length;
446162306a36Sopenharmony_ci			}
446262306a36Sopenharmony_ci		} else if (likely((t & FOTG210_ISOC_ACTIVE) == 0)) {
446362306a36Sopenharmony_ci			desc->status = 0;
446462306a36Sopenharmony_ci			desc->actual_length = FOTG210_ITD_LENGTH(t);
446562306a36Sopenharmony_ci			urb->actual_length += desc->actual_length;
446662306a36Sopenharmony_ci		} else {
446762306a36Sopenharmony_ci			/* URB was too late */
446862306a36Sopenharmony_ci			desc->status = -EXDEV;
446962306a36Sopenharmony_ci		}
447062306a36Sopenharmony_ci	}
447162306a36Sopenharmony_ci
447262306a36Sopenharmony_ci	/* handle completion now? */
447362306a36Sopenharmony_ci	if (likely((urb_index + 1) != urb->number_of_packets))
447462306a36Sopenharmony_ci		goto done;
447562306a36Sopenharmony_ci
447662306a36Sopenharmony_ci	/* ASSERT: it's really the last itd for this urb
447762306a36Sopenharmony_ci	 * list_for_each_entry (itd, &stream->td_list, itd_list)
447862306a36Sopenharmony_ci	 *	BUG_ON (itd->urb == urb);
447962306a36Sopenharmony_ci	 */
448062306a36Sopenharmony_ci
448162306a36Sopenharmony_ci	/* give urb back to the driver; completion often (re)submits */
448262306a36Sopenharmony_ci	dev = urb->dev;
448362306a36Sopenharmony_ci	fotg210_urb_done(fotg210, urb, 0);
448462306a36Sopenharmony_ci	retval = true;
448562306a36Sopenharmony_ci	urb = NULL;
448662306a36Sopenharmony_ci
448762306a36Sopenharmony_ci	--fotg210->isoc_count;
448862306a36Sopenharmony_ci	disable_periodic(fotg210);
448962306a36Sopenharmony_ci
449062306a36Sopenharmony_ci	if (unlikely(list_is_singular(&stream->td_list))) {
449162306a36Sopenharmony_ci		fotg210_to_hcd(fotg210)->self.bandwidth_allocated
449262306a36Sopenharmony_ci				-= stream->bandwidth;
449362306a36Sopenharmony_ci		fotg210_dbg(fotg210,
449462306a36Sopenharmony_ci			"deschedule devp %s ep%d%s-iso\n",
449562306a36Sopenharmony_ci			dev->devpath, stream->bEndpointAddress & 0x0f,
449662306a36Sopenharmony_ci			(stream->bEndpointAddress & USB_DIR_IN) ? "in" : "out");
449762306a36Sopenharmony_ci	}
449862306a36Sopenharmony_ci
449962306a36Sopenharmony_cidone:
450062306a36Sopenharmony_ci	itd->urb = NULL;
450162306a36Sopenharmony_ci
450262306a36Sopenharmony_ci	/* Add to the end of the free list for later reuse */
450362306a36Sopenharmony_ci	list_move_tail(&itd->itd_list, &stream->free_list);
450462306a36Sopenharmony_ci
450562306a36Sopenharmony_ci	/* Recycle the iTDs when the pipeline is empty (ep no longer in use) */
450662306a36Sopenharmony_ci	if (list_empty(&stream->td_list)) {
450762306a36Sopenharmony_ci		list_splice_tail_init(&stream->free_list,
450862306a36Sopenharmony_ci				&fotg210->cached_itd_list);
450962306a36Sopenharmony_ci		start_free_itds(fotg210);
451062306a36Sopenharmony_ci	}
451162306a36Sopenharmony_ci
451262306a36Sopenharmony_ci	return retval;
451362306a36Sopenharmony_ci}
451462306a36Sopenharmony_ci
451562306a36Sopenharmony_cistatic int itd_submit(struct fotg210_hcd *fotg210, struct urb *urb,
451662306a36Sopenharmony_ci		gfp_t mem_flags)
451762306a36Sopenharmony_ci{
451862306a36Sopenharmony_ci	int status = -EINVAL;
451962306a36Sopenharmony_ci	unsigned long flags;
452062306a36Sopenharmony_ci	struct fotg210_iso_stream *stream;
452162306a36Sopenharmony_ci
452262306a36Sopenharmony_ci	/* Get iso_stream head */
452362306a36Sopenharmony_ci	stream = iso_stream_find(fotg210, urb);
452462306a36Sopenharmony_ci	if (unlikely(stream == NULL)) {
452562306a36Sopenharmony_ci		fotg210_dbg(fotg210, "can't get iso stream\n");
452662306a36Sopenharmony_ci		return -ENOMEM;
452762306a36Sopenharmony_ci	}
452862306a36Sopenharmony_ci	if (unlikely(urb->interval != stream->interval &&
452962306a36Sopenharmony_ci			fotg210_port_speed(fotg210, 0) ==
453062306a36Sopenharmony_ci			USB_PORT_STAT_HIGH_SPEED)) {
453162306a36Sopenharmony_ci		fotg210_dbg(fotg210, "can't change iso interval %d --> %d\n",
453262306a36Sopenharmony_ci				stream->interval, urb->interval);
453362306a36Sopenharmony_ci		goto done;
453462306a36Sopenharmony_ci	}
453562306a36Sopenharmony_ci
453662306a36Sopenharmony_ci#ifdef FOTG210_URB_TRACE
453762306a36Sopenharmony_ci	fotg210_dbg(fotg210,
453862306a36Sopenharmony_ci			"%s %s urb %p ep%d%s len %d, %d pkts %d uframes[%p]\n",
453962306a36Sopenharmony_ci			__func__, urb->dev->devpath, urb,
454062306a36Sopenharmony_ci			usb_pipeendpoint(urb->pipe),
454162306a36Sopenharmony_ci			usb_pipein(urb->pipe) ? "in" : "out",
454262306a36Sopenharmony_ci			urb->transfer_buffer_length,
454362306a36Sopenharmony_ci			urb->number_of_packets, urb->interval,
454462306a36Sopenharmony_ci			stream);
454562306a36Sopenharmony_ci#endif
454662306a36Sopenharmony_ci
454762306a36Sopenharmony_ci	/* allocate ITDs w/o locking anything */
454862306a36Sopenharmony_ci	status = itd_urb_transaction(stream, fotg210, urb, mem_flags);
454962306a36Sopenharmony_ci	if (unlikely(status < 0)) {
455062306a36Sopenharmony_ci		fotg210_dbg(fotg210, "can't init itds\n");
455162306a36Sopenharmony_ci		goto done;
455262306a36Sopenharmony_ci	}
455362306a36Sopenharmony_ci
455462306a36Sopenharmony_ci	/* schedule ... need to lock */
455562306a36Sopenharmony_ci	spin_lock_irqsave(&fotg210->lock, flags);
455662306a36Sopenharmony_ci	if (unlikely(!HCD_HW_ACCESSIBLE(fotg210_to_hcd(fotg210)))) {
455762306a36Sopenharmony_ci		status = -ESHUTDOWN;
455862306a36Sopenharmony_ci		goto done_not_linked;
455962306a36Sopenharmony_ci	}
456062306a36Sopenharmony_ci	status = usb_hcd_link_urb_to_ep(fotg210_to_hcd(fotg210), urb);
456162306a36Sopenharmony_ci	if (unlikely(status))
456262306a36Sopenharmony_ci		goto done_not_linked;
456362306a36Sopenharmony_ci	status = iso_stream_schedule(fotg210, urb, stream);
456462306a36Sopenharmony_ci	if (likely(status == 0))
456562306a36Sopenharmony_ci		itd_link_urb(fotg210, urb, fotg210->periodic_size << 3, stream);
456662306a36Sopenharmony_ci	else
456762306a36Sopenharmony_ci		usb_hcd_unlink_urb_from_ep(fotg210_to_hcd(fotg210), urb);
456862306a36Sopenharmony_cidone_not_linked:
456962306a36Sopenharmony_ci	spin_unlock_irqrestore(&fotg210->lock, flags);
457062306a36Sopenharmony_cidone:
457162306a36Sopenharmony_ci	return status;
457262306a36Sopenharmony_ci}
457362306a36Sopenharmony_ci
457462306a36Sopenharmony_cistatic inline int scan_frame_queue(struct fotg210_hcd *fotg210, unsigned frame,
457562306a36Sopenharmony_ci		unsigned now_frame, bool live)
457662306a36Sopenharmony_ci{
457762306a36Sopenharmony_ci	unsigned uf;
457862306a36Sopenharmony_ci	bool modified;
457962306a36Sopenharmony_ci	union fotg210_shadow q, *q_p;
458062306a36Sopenharmony_ci	__hc32 type, *hw_p;
458162306a36Sopenharmony_ci
458262306a36Sopenharmony_ci	/* scan each element in frame's queue for completions */
458362306a36Sopenharmony_ci	q_p = &fotg210->pshadow[frame];
458462306a36Sopenharmony_ci	hw_p = &fotg210->periodic[frame];
458562306a36Sopenharmony_ci	q.ptr = q_p->ptr;
458662306a36Sopenharmony_ci	type = Q_NEXT_TYPE(fotg210, *hw_p);
458762306a36Sopenharmony_ci	modified = false;
458862306a36Sopenharmony_ci
458962306a36Sopenharmony_ci	while (q.ptr) {
459062306a36Sopenharmony_ci		switch (hc32_to_cpu(fotg210, type)) {
459162306a36Sopenharmony_ci		case Q_TYPE_ITD:
459262306a36Sopenharmony_ci			/* If this ITD is still active, leave it for
459362306a36Sopenharmony_ci			 * later processing ... check the next entry.
459462306a36Sopenharmony_ci			 * No need to check for activity unless the
459562306a36Sopenharmony_ci			 * frame is current.
459662306a36Sopenharmony_ci			 */
459762306a36Sopenharmony_ci			if (frame == now_frame && live) {
459862306a36Sopenharmony_ci				rmb();
459962306a36Sopenharmony_ci				for (uf = 0; uf < 8; uf++) {
460062306a36Sopenharmony_ci					if (q.itd->hw_transaction[uf] &
460162306a36Sopenharmony_ci							ITD_ACTIVE(fotg210))
460262306a36Sopenharmony_ci						break;
460362306a36Sopenharmony_ci				}
460462306a36Sopenharmony_ci				if (uf < 8) {
460562306a36Sopenharmony_ci					q_p = &q.itd->itd_next;
460662306a36Sopenharmony_ci					hw_p = &q.itd->hw_next;
460762306a36Sopenharmony_ci					type = Q_NEXT_TYPE(fotg210,
460862306a36Sopenharmony_ci							q.itd->hw_next);
460962306a36Sopenharmony_ci					q = *q_p;
461062306a36Sopenharmony_ci					break;
461162306a36Sopenharmony_ci				}
461262306a36Sopenharmony_ci			}
461362306a36Sopenharmony_ci
461462306a36Sopenharmony_ci			/* Take finished ITDs out of the schedule
461562306a36Sopenharmony_ci			 * and process them:  recycle, maybe report
461662306a36Sopenharmony_ci			 * URB completion.  HC won't cache the
461762306a36Sopenharmony_ci			 * pointer for much longer, if at all.
461862306a36Sopenharmony_ci			 */
461962306a36Sopenharmony_ci			*q_p = q.itd->itd_next;
462062306a36Sopenharmony_ci			*hw_p = q.itd->hw_next;
462162306a36Sopenharmony_ci			type = Q_NEXT_TYPE(fotg210, q.itd->hw_next);
462262306a36Sopenharmony_ci			wmb();
462362306a36Sopenharmony_ci			modified = itd_complete(fotg210, q.itd);
462462306a36Sopenharmony_ci			q = *q_p;
462562306a36Sopenharmony_ci			break;
462662306a36Sopenharmony_ci		default:
462762306a36Sopenharmony_ci			fotg210_dbg(fotg210, "corrupt type %d frame %d shadow %p\n",
462862306a36Sopenharmony_ci					type, frame, q.ptr);
462962306a36Sopenharmony_ci			fallthrough;
463062306a36Sopenharmony_ci		case Q_TYPE_QH:
463162306a36Sopenharmony_ci		case Q_TYPE_FSTN:
463262306a36Sopenharmony_ci			/* End of the iTDs and siTDs */
463362306a36Sopenharmony_ci			q.ptr = NULL;
463462306a36Sopenharmony_ci			break;
463562306a36Sopenharmony_ci		}
463662306a36Sopenharmony_ci
463762306a36Sopenharmony_ci		/* assume completion callbacks modify the queue */
463862306a36Sopenharmony_ci		if (unlikely(modified && fotg210->isoc_count > 0))
463962306a36Sopenharmony_ci			return -EINVAL;
464062306a36Sopenharmony_ci	}
464162306a36Sopenharmony_ci	return 0;
464262306a36Sopenharmony_ci}
464362306a36Sopenharmony_ci
464462306a36Sopenharmony_cistatic void scan_isoc(struct fotg210_hcd *fotg210)
464562306a36Sopenharmony_ci{
464662306a36Sopenharmony_ci	unsigned uf, now_frame, frame, ret;
464762306a36Sopenharmony_ci	unsigned fmask = fotg210->periodic_size - 1;
464862306a36Sopenharmony_ci	bool live;
464962306a36Sopenharmony_ci
465062306a36Sopenharmony_ci	/*
465162306a36Sopenharmony_ci	 * When running, scan from last scan point up to "now"
465262306a36Sopenharmony_ci	 * else clean up by scanning everything that's left.
465362306a36Sopenharmony_ci	 * Touches as few pages as possible:  cache-friendly.
465462306a36Sopenharmony_ci	 */
465562306a36Sopenharmony_ci	if (fotg210->rh_state >= FOTG210_RH_RUNNING) {
465662306a36Sopenharmony_ci		uf = fotg210_read_frame_index(fotg210);
465762306a36Sopenharmony_ci		now_frame = (uf >> 3) & fmask;
465862306a36Sopenharmony_ci		live = true;
465962306a36Sopenharmony_ci	} else  {
466062306a36Sopenharmony_ci		now_frame = (fotg210->next_frame - 1) & fmask;
466162306a36Sopenharmony_ci		live = false;
466262306a36Sopenharmony_ci	}
466362306a36Sopenharmony_ci	fotg210->now_frame = now_frame;
466462306a36Sopenharmony_ci
466562306a36Sopenharmony_ci	frame = fotg210->next_frame;
466662306a36Sopenharmony_ci	for (;;) {
466762306a36Sopenharmony_ci		ret = 1;
466862306a36Sopenharmony_ci		while (ret != 0)
466962306a36Sopenharmony_ci			ret = scan_frame_queue(fotg210, frame,
467062306a36Sopenharmony_ci					now_frame, live);
467162306a36Sopenharmony_ci
467262306a36Sopenharmony_ci		/* Stop when we have reached the current frame */
467362306a36Sopenharmony_ci		if (frame == now_frame)
467462306a36Sopenharmony_ci			break;
467562306a36Sopenharmony_ci		frame = (frame + 1) & fmask;
467662306a36Sopenharmony_ci	}
467762306a36Sopenharmony_ci	fotg210->next_frame = now_frame;
467862306a36Sopenharmony_ci}
467962306a36Sopenharmony_ci
468062306a36Sopenharmony_ci/* Display / Set uframe_periodic_max
468162306a36Sopenharmony_ci */
468262306a36Sopenharmony_cistatic ssize_t uframe_periodic_max_show(struct device *dev,
468362306a36Sopenharmony_ci		struct device_attribute *attr, char *buf)
468462306a36Sopenharmony_ci{
468562306a36Sopenharmony_ci	struct fotg210_hcd *fotg210;
468662306a36Sopenharmony_ci
468762306a36Sopenharmony_ci	fotg210 = hcd_to_fotg210(bus_to_hcd(dev_get_drvdata(dev)));
468862306a36Sopenharmony_ci	return sysfs_emit(buf, "%d\n", fotg210->uframe_periodic_max);
468962306a36Sopenharmony_ci}
469062306a36Sopenharmony_ci
469162306a36Sopenharmony_cistatic ssize_t uframe_periodic_max_store(struct device *dev,
469262306a36Sopenharmony_ci		struct device_attribute *attr, const char *buf, size_t count)
469362306a36Sopenharmony_ci{
469462306a36Sopenharmony_ci	struct fotg210_hcd *fotg210;
469562306a36Sopenharmony_ci	unsigned uframe_periodic_max;
469662306a36Sopenharmony_ci	unsigned frame, uframe;
469762306a36Sopenharmony_ci	unsigned short allocated_max;
469862306a36Sopenharmony_ci	unsigned long flags;
469962306a36Sopenharmony_ci	ssize_t ret;
470062306a36Sopenharmony_ci
470162306a36Sopenharmony_ci	fotg210 = hcd_to_fotg210(bus_to_hcd(dev_get_drvdata(dev)));
470262306a36Sopenharmony_ci
470362306a36Sopenharmony_ci	ret = kstrtouint(buf, 0, &uframe_periodic_max);
470462306a36Sopenharmony_ci	if (ret)
470562306a36Sopenharmony_ci		return ret;
470662306a36Sopenharmony_ci
470762306a36Sopenharmony_ci	if (uframe_periodic_max < 100 || uframe_periodic_max >= 125) {
470862306a36Sopenharmony_ci		fotg210_info(fotg210, "rejecting invalid request for uframe_periodic_max=%u\n",
470962306a36Sopenharmony_ci				uframe_periodic_max);
471062306a36Sopenharmony_ci		return -EINVAL;
471162306a36Sopenharmony_ci	}
471262306a36Sopenharmony_ci
471362306a36Sopenharmony_ci	ret = -EINVAL;
471462306a36Sopenharmony_ci
471562306a36Sopenharmony_ci	/*
471662306a36Sopenharmony_ci	 * lock, so that our checking does not race with possible periodic
471762306a36Sopenharmony_ci	 * bandwidth allocation through submitting new urbs.
471862306a36Sopenharmony_ci	 */
471962306a36Sopenharmony_ci	spin_lock_irqsave(&fotg210->lock, flags);
472062306a36Sopenharmony_ci
472162306a36Sopenharmony_ci	/*
472262306a36Sopenharmony_ci	 * for request to decrease max periodic bandwidth, we have to check
472362306a36Sopenharmony_ci	 * every microframe in the schedule to see whether the decrease is
472462306a36Sopenharmony_ci	 * possible.
472562306a36Sopenharmony_ci	 */
472662306a36Sopenharmony_ci	if (uframe_periodic_max < fotg210->uframe_periodic_max) {
472762306a36Sopenharmony_ci		allocated_max = 0;
472862306a36Sopenharmony_ci
472962306a36Sopenharmony_ci		for (frame = 0; frame < fotg210->periodic_size; ++frame)
473062306a36Sopenharmony_ci			for (uframe = 0; uframe < 7; ++uframe)
473162306a36Sopenharmony_ci				allocated_max = max(allocated_max,
473262306a36Sopenharmony_ci						periodic_usecs(fotg210, frame,
473362306a36Sopenharmony_ci						uframe));
473462306a36Sopenharmony_ci
473562306a36Sopenharmony_ci		if (allocated_max > uframe_periodic_max) {
473662306a36Sopenharmony_ci			fotg210_info(fotg210,
473762306a36Sopenharmony_ci					"cannot decrease uframe_periodic_max because periodic bandwidth is already allocated (%u > %u)\n",
473862306a36Sopenharmony_ci					allocated_max, uframe_periodic_max);
473962306a36Sopenharmony_ci			goto out_unlock;
474062306a36Sopenharmony_ci		}
474162306a36Sopenharmony_ci	}
474262306a36Sopenharmony_ci
474362306a36Sopenharmony_ci	/* increasing is always ok */
474462306a36Sopenharmony_ci
474562306a36Sopenharmony_ci	fotg210_info(fotg210,
474662306a36Sopenharmony_ci			"setting max periodic bandwidth to %u%% (== %u usec/uframe)\n",
474762306a36Sopenharmony_ci			100 * uframe_periodic_max/125, uframe_periodic_max);
474862306a36Sopenharmony_ci
474962306a36Sopenharmony_ci	if (uframe_periodic_max != 100)
475062306a36Sopenharmony_ci		fotg210_warn(fotg210, "max periodic bandwidth set is non-standard\n");
475162306a36Sopenharmony_ci
475262306a36Sopenharmony_ci	fotg210->uframe_periodic_max = uframe_periodic_max;
475362306a36Sopenharmony_ci	ret = count;
475462306a36Sopenharmony_ci
475562306a36Sopenharmony_ciout_unlock:
475662306a36Sopenharmony_ci	spin_unlock_irqrestore(&fotg210->lock, flags);
475762306a36Sopenharmony_ci	return ret;
475862306a36Sopenharmony_ci}
475962306a36Sopenharmony_ci
476062306a36Sopenharmony_cistatic DEVICE_ATTR_RW(uframe_periodic_max);
476162306a36Sopenharmony_ci
476262306a36Sopenharmony_cistatic inline int create_sysfs_files(struct fotg210_hcd *fotg210)
476362306a36Sopenharmony_ci{
476462306a36Sopenharmony_ci	struct device *controller = fotg210_to_hcd(fotg210)->self.controller;
476562306a36Sopenharmony_ci
476662306a36Sopenharmony_ci	return device_create_file(controller, &dev_attr_uframe_periodic_max);
476762306a36Sopenharmony_ci}
476862306a36Sopenharmony_ci
476962306a36Sopenharmony_cistatic inline void remove_sysfs_files(struct fotg210_hcd *fotg210)
477062306a36Sopenharmony_ci{
477162306a36Sopenharmony_ci	struct device *controller = fotg210_to_hcd(fotg210)->self.controller;
477262306a36Sopenharmony_ci
477362306a36Sopenharmony_ci	device_remove_file(controller, &dev_attr_uframe_periodic_max);
477462306a36Sopenharmony_ci}
477562306a36Sopenharmony_ci/* On some systems, leaving remote wakeup enabled prevents system shutdown.
477662306a36Sopenharmony_ci * The firmware seems to think that powering off is a wakeup event!
477762306a36Sopenharmony_ci * This routine turns off remote wakeup and everything else, on all ports.
477862306a36Sopenharmony_ci */
477962306a36Sopenharmony_cistatic void fotg210_turn_off_all_ports(struct fotg210_hcd *fotg210)
478062306a36Sopenharmony_ci{
478162306a36Sopenharmony_ci	u32 __iomem *status_reg = &fotg210->regs->port_status;
478262306a36Sopenharmony_ci
478362306a36Sopenharmony_ci	fotg210_writel(fotg210, PORT_RWC_BITS, status_reg);
478462306a36Sopenharmony_ci}
478562306a36Sopenharmony_ci
478662306a36Sopenharmony_ci/* Halt HC, turn off all ports, and let the BIOS use the companion controllers.
478762306a36Sopenharmony_ci * Must be called with interrupts enabled and the lock not held.
478862306a36Sopenharmony_ci */
478962306a36Sopenharmony_cistatic void fotg210_silence_controller(struct fotg210_hcd *fotg210)
479062306a36Sopenharmony_ci{
479162306a36Sopenharmony_ci	fotg210_halt(fotg210);
479262306a36Sopenharmony_ci
479362306a36Sopenharmony_ci	spin_lock_irq(&fotg210->lock);
479462306a36Sopenharmony_ci	fotg210->rh_state = FOTG210_RH_HALTED;
479562306a36Sopenharmony_ci	fotg210_turn_off_all_ports(fotg210);
479662306a36Sopenharmony_ci	spin_unlock_irq(&fotg210->lock);
479762306a36Sopenharmony_ci}
479862306a36Sopenharmony_ci
479962306a36Sopenharmony_ci/* fotg210_shutdown kick in for silicon on any bus (not just pci, etc).
480062306a36Sopenharmony_ci * This forcibly disables dma and IRQs, helping kexec and other cases
480162306a36Sopenharmony_ci * where the next system software may expect clean state.
480262306a36Sopenharmony_ci */
480362306a36Sopenharmony_cistatic void fotg210_shutdown(struct usb_hcd *hcd)
480462306a36Sopenharmony_ci{
480562306a36Sopenharmony_ci	struct fotg210_hcd *fotg210 = hcd_to_fotg210(hcd);
480662306a36Sopenharmony_ci
480762306a36Sopenharmony_ci	spin_lock_irq(&fotg210->lock);
480862306a36Sopenharmony_ci	fotg210->shutdown = true;
480962306a36Sopenharmony_ci	fotg210->rh_state = FOTG210_RH_STOPPING;
481062306a36Sopenharmony_ci	fotg210->enabled_hrtimer_events = 0;
481162306a36Sopenharmony_ci	spin_unlock_irq(&fotg210->lock);
481262306a36Sopenharmony_ci
481362306a36Sopenharmony_ci	fotg210_silence_controller(fotg210);
481462306a36Sopenharmony_ci
481562306a36Sopenharmony_ci	hrtimer_cancel(&fotg210->hrtimer);
481662306a36Sopenharmony_ci}
481762306a36Sopenharmony_ci
481862306a36Sopenharmony_ci/* fotg210_work is called from some interrupts, timers, and so on.
481962306a36Sopenharmony_ci * it calls driver completion functions, after dropping fotg210->lock.
482062306a36Sopenharmony_ci */
482162306a36Sopenharmony_cistatic void fotg210_work(struct fotg210_hcd *fotg210)
482262306a36Sopenharmony_ci{
482362306a36Sopenharmony_ci	/* another CPU may drop fotg210->lock during a schedule scan while
482462306a36Sopenharmony_ci	 * it reports urb completions.  this flag guards against bogus
482562306a36Sopenharmony_ci	 * attempts at re-entrant schedule scanning.
482662306a36Sopenharmony_ci	 */
482762306a36Sopenharmony_ci	if (fotg210->scanning) {
482862306a36Sopenharmony_ci		fotg210->need_rescan = true;
482962306a36Sopenharmony_ci		return;
483062306a36Sopenharmony_ci	}
483162306a36Sopenharmony_ci	fotg210->scanning = true;
483262306a36Sopenharmony_ci
483362306a36Sopenharmony_cirescan:
483462306a36Sopenharmony_ci	fotg210->need_rescan = false;
483562306a36Sopenharmony_ci	if (fotg210->async_count)
483662306a36Sopenharmony_ci		scan_async(fotg210);
483762306a36Sopenharmony_ci	if (fotg210->intr_count > 0)
483862306a36Sopenharmony_ci		scan_intr(fotg210);
483962306a36Sopenharmony_ci	if (fotg210->isoc_count > 0)
484062306a36Sopenharmony_ci		scan_isoc(fotg210);
484162306a36Sopenharmony_ci	if (fotg210->need_rescan)
484262306a36Sopenharmony_ci		goto rescan;
484362306a36Sopenharmony_ci	fotg210->scanning = false;
484462306a36Sopenharmony_ci
484562306a36Sopenharmony_ci	/* the IO watchdog guards against hardware or driver bugs that
484662306a36Sopenharmony_ci	 * misplace IRQs, and should let us run completely without IRQs.
484762306a36Sopenharmony_ci	 * such lossage has been observed on both VT6202 and VT8235.
484862306a36Sopenharmony_ci	 */
484962306a36Sopenharmony_ci	turn_on_io_watchdog(fotg210);
485062306a36Sopenharmony_ci}
485162306a36Sopenharmony_ci
485262306a36Sopenharmony_ci/* Called when the fotg210_hcd module is removed.
485362306a36Sopenharmony_ci */
485462306a36Sopenharmony_cistatic void fotg210_stop(struct usb_hcd *hcd)
485562306a36Sopenharmony_ci{
485662306a36Sopenharmony_ci	struct fotg210_hcd *fotg210 = hcd_to_fotg210(hcd);
485762306a36Sopenharmony_ci
485862306a36Sopenharmony_ci	fotg210_dbg(fotg210, "stop\n");
485962306a36Sopenharmony_ci
486062306a36Sopenharmony_ci	/* no more interrupts ... */
486162306a36Sopenharmony_ci
486262306a36Sopenharmony_ci	spin_lock_irq(&fotg210->lock);
486362306a36Sopenharmony_ci	fotg210->enabled_hrtimer_events = 0;
486462306a36Sopenharmony_ci	spin_unlock_irq(&fotg210->lock);
486562306a36Sopenharmony_ci
486662306a36Sopenharmony_ci	fotg210_quiesce(fotg210);
486762306a36Sopenharmony_ci	fotg210_silence_controller(fotg210);
486862306a36Sopenharmony_ci	fotg210_reset(fotg210);
486962306a36Sopenharmony_ci
487062306a36Sopenharmony_ci	hrtimer_cancel(&fotg210->hrtimer);
487162306a36Sopenharmony_ci	remove_sysfs_files(fotg210);
487262306a36Sopenharmony_ci	remove_debug_files(fotg210);
487362306a36Sopenharmony_ci
487462306a36Sopenharmony_ci	/* root hub is shut down separately (first, when possible) */
487562306a36Sopenharmony_ci	spin_lock_irq(&fotg210->lock);
487662306a36Sopenharmony_ci	end_free_itds(fotg210);
487762306a36Sopenharmony_ci	spin_unlock_irq(&fotg210->lock);
487862306a36Sopenharmony_ci	fotg210_mem_cleanup(fotg210);
487962306a36Sopenharmony_ci
488062306a36Sopenharmony_ci#ifdef FOTG210_STATS
488162306a36Sopenharmony_ci	fotg210_dbg(fotg210, "irq normal %ld err %ld iaa %ld (lost %ld)\n",
488262306a36Sopenharmony_ci			fotg210->stats.normal, fotg210->stats.error,
488362306a36Sopenharmony_ci			fotg210->stats.iaa, fotg210->stats.lost_iaa);
488462306a36Sopenharmony_ci	fotg210_dbg(fotg210, "complete %ld unlink %ld\n",
488562306a36Sopenharmony_ci			fotg210->stats.complete, fotg210->stats.unlink);
488662306a36Sopenharmony_ci#endif
488762306a36Sopenharmony_ci
488862306a36Sopenharmony_ci	dbg_status(fotg210, "fotg210_stop completed",
488962306a36Sopenharmony_ci			fotg210_readl(fotg210, &fotg210->regs->status));
489062306a36Sopenharmony_ci}
489162306a36Sopenharmony_ci
489262306a36Sopenharmony_ci/* one-time init, only for memory state */
489362306a36Sopenharmony_cistatic int hcd_fotg210_init(struct usb_hcd *hcd)
489462306a36Sopenharmony_ci{
489562306a36Sopenharmony_ci	struct fotg210_hcd *fotg210 = hcd_to_fotg210(hcd);
489662306a36Sopenharmony_ci	u32 temp;
489762306a36Sopenharmony_ci	int retval;
489862306a36Sopenharmony_ci	u32 hcc_params;
489962306a36Sopenharmony_ci	struct fotg210_qh_hw *hw;
490062306a36Sopenharmony_ci
490162306a36Sopenharmony_ci	spin_lock_init(&fotg210->lock);
490262306a36Sopenharmony_ci
490362306a36Sopenharmony_ci	/*
490462306a36Sopenharmony_ci	 * keep io watchdog by default, those good HCDs could turn off it later
490562306a36Sopenharmony_ci	 */
490662306a36Sopenharmony_ci	fotg210->need_io_watchdog = 1;
490762306a36Sopenharmony_ci
490862306a36Sopenharmony_ci	hrtimer_init(&fotg210->hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS);
490962306a36Sopenharmony_ci	fotg210->hrtimer.function = fotg210_hrtimer_func;
491062306a36Sopenharmony_ci	fotg210->next_hrtimer_event = FOTG210_HRTIMER_NO_EVENT;
491162306a36Sopenharmony_ci
491262306a36Sopenharmony_ci	hcc_params = fotg210_readl(fotg210, &fotg210->caps->hcc_params);
491362306a36Sopenharmony_ci
491462306a36Sopenharmony_ci	/*
491562306a36Sopenharmony_ci	 * by default set standard 80% (== 100 usec/uframe) max periodic
491662306a36Sopenharmony_ci	 * bandwidth as required by USB 2.0
491762306a36Sopenharmony_ci	 */
491862306a36Sopenharmony_ci	fotg210->uframe_periodic_max = 100;
491962306a36Sopenharmony_ci
492062306a36Sopenharmony_ci	/*
492162306a36Sopenharmony_ci	 * hw default: 1K periodic list heads, one per frame.
492262306a36Sopenharmony_ci	 * periodic_size can shrink by USBCMD update if hcc_params allows.
492362306a36Sopenharmony_ci	 */
492462306a36Sopenharmony_ci	fotg210->periodic_size = DEFAULT_I_TDPS;
492562306a36Sopenharmony_ci	INIT_LIST_HEAD(&fotg210->intr_qh_list);
492662306a36Sopenharmony_ci	INIT_LIST_HEAD(&fotg210->cached_itd_list);
492762306a36Sopenharmony_ci
492862306a36Sopenharmony_ci	if (HCC_PGM_FRAMELISTLEN(hcc_params)) {
492962306a36Sopenharmony_ci		/* periodic schedule size can be smaller than default */
493062306a36Sopenharmony_ci		switch (FOTG210_TUNE_FLS) {
493162306a36Sopenharmony_ci		case 0:
493262306a36Sopenharmony_ci			fotg210->periodic_size = 1024;
493362306a36Sopenharmony_ci			break;
493462306a36Sopenharmony_ci		case 1:
493562306a36Sopenharmony_ci			fotg210->periodic_size = 512;
493662306a36Sopenharmony_ci			break;
493762306a36Sopenharmony_ci		case 2:
493862306a36Sopenharmony_ci			fotg210->periodic_size = 256;
493962306a36Sopenharmony_ci			break;
494062306a36Sopenharmony_ci		default:
494162306a36Sopenharmony_ci			BUG();
494262306a36Sopenharmony_ci		}
494362306a36Sopenharmony_ci	}
494462306a36Sopenharmony_ci	retval = fotg210_mem_init(fotg210, GFP_KERNEL);
494562306a36Sopenharmony_ci	if (retval < 0)
494662306a36Sopenharmony_ci		return retval;
494762306a36Sopenharmony_ci
494862306a36Sopenharmony_ci	/* controllers may cache some of the periodic schedule ... */
494962306a36Sopenharmony_ci	fotg210->i_thresh = 2;
495062306a36Sopenharmony_ci
495162306a36Sopenharmony_ci	/*
495262306a36Sopenharmony_ci	 * dedicate a qh for the async ring head, since we couldn't unlink
495362306a36Sopenharmony_ci	 * a 'real' qh without stopping the async schedule [4.8].  use it
495462306a36Sopenharmony_ci	 * as the 'reclamation list head' too.
495562306a36Sopenharmony_ci	 * its dummy is used in hw_alt_next of many tds, to prevent the qh
495662306a36Sopenharmony_ci	 * from automatically advancing to the next td after short reads.
495762306a36Sopenharmony_ci	 */
495862306a36Sopenharmony_ci	fotg210->async->qh_next.qh = NULL;
495962306a36Sopenharmony_ci	hw = fotg210->async->hw;
496062306a36Sopenharmony_ci	hw->hw_next = QH_NEXT(fotg210, fotg210->async->qh_dma);
496162306a36Sopenharmony_ci	hw->hw_info1 = cpu_to_hc32(fotg210, QH_HEAD);
496262306a36Sopenharmony_ci	hw->hw_token = cpu_to_hc32(fotg210, QTD_STS_HALT);
496362306a36Sopenharmony_ci	hw->hw_qtd_next = FOTG210_LIST_END(fotg210);
496462306a36Sopenharmony_ci	fotg210->async->qh_state = QH_STATE_LINKED;
496562306a36Sopenharmony_ci	hw->hw_alt_next = QTD_NEXT(fotg210, fotg210->async->dummy->qtd_dma);
496662306a36Sopenharmony_ci
496762306a36Sopenharmony_ci	/* clear interrupt enables, set irq latency */
496862306a36Sopenharmony_ci	if (log2_irq_thresh < 0 || log2_irq_thresh > 6)
496962306a36Sopenharmony_ci		log2_irq_thresh = 0;
497062306a36Sopenharmony_ci	temp = 1 << (16 + log2_irq_thresh);
497162306a36Sopenharmony_ci	if (HCC_CANPARK(hcc_params)) {
497262306a36Sopenharmony_ci		/* HW default park == 3, on hardware that supports it (like
497362306a36Sopenharmony_ci		 * NVidia and ALI silicon), maximizes throughput on the async
497462306a36Sopenharmony_ci		 * schedule by avoiding QH fetches between transfers.
497562306a36Sopenharmony_ci		 *
497662306a36Sopenharmony_ci		 * With fast usb storage devices and NForce2, "park" seems to
497762306a36Sopenharmony_ci		 * make problems:  throughput reduction (!), data errors...
497862306a36Sopenharmony_ci		 */
497962306a36Sopenharmony_ci		if (park) {
498062306a36Sopenharmony_ci			park = min_t(unsigned, park, 3);
498162306a36Sopenharmony_ci			temp |= CMD_PARK;
498262306a36Sopenharmony_ci			temp |= park << 8;
498362306a36Sopenharmony_ci		}
498462306a36Sopenharmony_ci		fotg210_dbg(fotg210, "park %d\n", park);
498562306a36Sopenharmony_ci	}
498662306a36Sopenharmony_ci	if (HCC_PGM_FRAMELISTLEN(hcc_params)) {
498762306a36Sopenharmony_ci		/* periodic schedule size can be smaller than default */
498862306a36Sopenharmony_ci		temp &= ~(3 << 2);
498962306a36Sopenharmony_ci		temp |= (FOTG210_TUNE_FLS << 2);
499062306a36Sopenharmony_ci	}
499162306a36Sopenharmony_ci	fotg210->command = temp;
499262306a36Sopenharmony_ci
499362306a36Sopenharmony_ci	/* Accept arbitrarily long scatter-gather lists */
499462306a36Sopenharmony_ci	if (!hcd->localmem_pool)
499562306a36Sopenharmony_ci		hcd->self.sg_tablesize = ~0;
499662306a36Sopenharmony_ci	return 0;
499762306a36Sopenharmony_ci}
499862306a36Sopenharmony_ci
499962306a36Sopenharmony_ci/* start HC running; it's halted, hcd_fotg210_init() has been run (once) */
500062306a36Sopenharmony_cistatic int fotg210_run(struct usb_hcd *hcd)
500162306a36Sopenharmony_ci{
500262306a36Sopenharmony_ci	struct fotg210_hcd *fotg210 = hcd_to_fotg210(hcd);
500362306a36Sopenharmony_ci	u32 temp;
500462306a36Sopenharmony_ci
500562306a36Sopenharmony_ci	hcd->uses_new_polling = 1;
500662306a36Sopenharmony_ci
500762306a36Sopenharmony_ci	/* EHCI spec section 4.1 */
500862306a36Sopenharmony_ci
500962306a36Sopenharmony_ci	fotg210_writel(fotg210, fotg210->periodic_dma,
501062306a36Sopenharmony_ci			&fotg210->regs->frame_list);
501162306a36Sopenharmony_ci	fotg210_writel(fotg210, (u32)fotg210->async->qh_dma,
501262306a36Sopenharmony_ci			&fotg210->regs->async_next);
501362306a36Sopenharmony_ci
501462306a36Sopenharmony_ci	/*
501562306a36Sopenharmony_ci	 * hcc_params controls whether fotg210->regs->segment must (!!!)
501662306a36Sopenharmony_ci	 * be used; it constrains QH/ITD/SITD and QTD locations.
501762306a36Sopenharmony_ci	 * dma_pool consistent memory always uses segment zero.
501862306a36Sopenharmony_ci	 * streaming mappings for I/O buffers, like dma_map_single(),
501962306a36Sopenharmony_ci	 * can return segments above 4GB, if the device allows.
502062306a36Sopenharmony_ci	 *
502162306a36Sopenharmony_ci	 * NOTE:  the dma mask is visible through dev->dma_mask, so
502262306a36Sopenharmony_ci	 * drivers can pass this info along ... like NETIF_F_HIGHDMA,
502362306a36Sopenharmony_ci	 * Scsi_Host.highmem_io, and so forth.  It's readonly to all
502462306a36Sopenharmony_ci	 * host side drivers though.
502562306a36Sopenharmony_ci	 */
502662306a36Sopenharmony_ci	fotg210_readl(fotg210, &fotg210->caps->hcc_params);
502762306a36Sopenharmony_ci
502862306a36Sopenharmony_ci	/*
502962306a36Sopenharmony_ci	 * Philips, Intel, and maybe others need CMD_RUN before the
503062306a36Sopenharmony_ci	 * root hub will detect new devices (why?); NEC doesn't
503162306a36Sopenharmony_ci	 */
503262306a36Sopenharmony_ci	fotg210->command &= ~(CMD_IAAD|CMD_PSE|CMD_ASE|CMD_RESET);
503362306a36Sopenharmony_ci	fotg210->command |= CMD_RUN;
503462306a36Sopenharmony_ci	fotg210_writel(fotg210, fotg210->command, &fotg210->regs->command);
503562306a36Sopenharmony_ci	dbg_cmd(fotg210, "init", fotg210->command);
503662306a36Sopenharmony_ci
503762306a36Sopenharmony_ci	/*
503862306a36Sopenharmony_ci	 * Start, enabling full USB 2.0 functionality ... usb 1.1 devices
503962306a36Sopenharmony_ci	 * are explicitly handed to companion controller(s), so no TT is
504062306a36Sopenharmony_ci	 * involved with the root hub.  (Except where one is integrated,
504162306a36Sopenharmony_ci	 * and there's no companion controller unless maybe for USB OTG.)
504262306a36Sopenharmony_ci	 *
504362306a36Sopenharmony_ci	 * Turning on the CF flag will transfer ownership of all ports
504462306a36Sopenharmony_ci	 * from the companions to the EHCI controller.  If any of the
504562306a36Sopenharmony_ci	 * companions are in the middle of a port reset at the time, it
504662306a36Sopenharmony_ci	 * could cause trouble.  Write-locking ehci_cf_port_reset_rwsem
504762306a36Sopenharmony_ci	 * guarantees that no resets are in progress.  After we set CF,
504862306a36Sopenharmony_ci	 * a short delay lets the hardware catch up; new resets shouldn't
504962306a36Sopenharmony_ci	 * be started before the port switching actions could complete.
505062306a36Sopenharmony_ci	 */
505162306a36Sopenharmony_ci	down_write(&ehci_cf_port_reset_rwsem);
505262306a36Sopenharmony_ci	fotg210->rh_state = FOTG210_RH_RUNNING;
505362306a36Sopenharmony_ci	/* unblock posted writes */
505462306a36Sopenharmony_ci	fotg210_readl(fotg210, &fotg210->regs->command);
505562306a36Sopenharmony_ci	usleep_range(5000, 10000);
505662306a36Sopenharmony_ci	up_write(&ehci_cf_port_reset_rwsem);
505762306a36Sopenharmony_ci	fotg210->last_periodic_enable = ktime_get_real();
505862306a36Sopenharmony_ci
505962306a36Sopenharmony_ci	temp = HC_VERSION(fotg210,
506062306a36Sopenharmony_ci			fotg210_readl(fotg210, &fotg210->caps->hc_capbase));
506162306a36Sopenharmony_ci	fotg210_info(fotg210,
506262306a36Sopenharmony_ci			"USB %x.%x started, EHCI %x.%02x\n",
506362306a36Sopenharmony_ci			((fotg210->sbrn & 0xf0) >> 4), (fotg210->sbrn & 0x0f),
506462306a36Sopenharmony_ci			temp >> 8, temp & 0xff);
506562306a36Sopenharmony_ci
506662306a36Sopenharmony_ci	fotg210_writel(fotg210, INTR_MASK,
506762306a36Sopenharmony_ci			&fotg210->regs->intr_enable); /* Turn On Interrupts */
506862306a36Sopenharmony_ci
506962306a36Sopenharmony_ci	/* GRR this is run-once init(), being done every time the HC starts.
507062306a36Sopenharmony_ci	 * So long as they're part of class devices, we can't do it init()
507162306a36Sopenharmony_ci	 * since the class device isn't created that early.
507262306a36Sopenharmony_ci	 */
507362306a36Sopenharmony_ci	create_debug_files(fotg210);
507462306a36Sopenharmony_ci	create_sysfs_files(fotg210);
507562306a36Sopenharmony_ci
507662306a36Sopenharmony_ci	return 0;
507762306a36Sopenharmony_ci}
507862306a36Sopenharmony_ci
507962306a36Sopenharmony_cistatic int fotg210_setup(struct usb_hcd *hcd)
508062306a36Sopenharmony_ci{
508162306a36Sopenharmony_ci	struct fotg210_hcd *fotg210 = hcd_to_fotg210(hcd);
508262306a36Sopenharmony_ci	int retval;
508362306a36Sopenharmony_ci
508462306a36Sopenharmony_ci	fotg210->regs = (void __iomem *)fotg210->caps +
508562306a36Sopenharmony_ci			HC_LENGTH(fotg210,
508662306a36Sopenharmony_ci			fotg210_readl(fotg210, &fotg210->caps->hc_capbase));
508762306a36Sopenharmony_ci	dbg_hcs_params(fotg210, "reset");
508862306a36Sopenharmony_ci	dbg_hcc_params(fotg210, "reset");
508962306a36Sopenharmony_ci
509062306a36Sopenharmony_ci	/* cache this readonly data; minimize chip reads */
509162306a36Sopenharmony_ci	fotg210->hcs_params = fotg210_readl(fotg210,
509262306a36Sopenharmony_ci			&fotg210->caps->hcs_params);
509362306a36Sopenharmony_ci
509462306a36Sopenharmony_ci	fotg210->sbrn = HCD_USB2;
509562306a36Sopenharmony_ci
509662306a36Sopenharmony_ci	/* data structure init */
509762306a36Sopenharmony_ci	retval = hcd_fotg210_init(hcd);
509862306a36Sopenharmony_ci	if (retval)
509962306a36Sopenharmony_ci		return retval;
510062306a36Sopenharmony_ci
510162306a36Sopenharmony_ci	retval = fotg210_halt(fotg210);
510262306a36Sopenharmony_ci	if (retval)
510362306a36Sopenharmony_ci		return retval;
510462306a36Sopenharmony_ci
510562306a36Sopenharmony_ci	fotg210_reset(fotg210);
510662306a36Sopenharmony_ci
510762306a36Sopenharmony_ci	return 0;
510862306a36Sopenharmony_ci}
510962306a36Sopenharmony_ci
511062306a36Sopenharmony_cistatic irqreturn_t fotg210_irq(struct usb_hcd *hcd)
511162306a36Sopenharmony_ci{
511262306a36Sopenharmony_ci	struct fotg210_hcd *fotg210 = hcd_to_fotg210(hcd);
511362306a36Sopenharmony_ci	u32 status, masked_status, pcd_status = 0, cmd;
511462306a36Sopenharmony_ci	int bh;
511562306a36Sopenharmony_ci
511662306a36Sopenharmony_ci	spin_lock(&fotg210->lock);
511762306a36Sopenharmony_ci
511862306a36Sopenharmony_ci	status = fotg210_readl(fotg210, &fotg210->regs->status);
511962306a36Sopenharmony_ci
512062306a36Sopenharmony_ci	/* e.g. cardbus physical eject */
512162306a36Sopenharmony_ci	if (status == ~(u32) 0) {
512262306a36Sopenharmony_ci		fotg210_dbg(fotg210, "device removed\n");
512362306a36Sopenharmony_ci		goto dead;
512462306a36Sopenharmony_ci	}
512562306a36Sopenharmony_ci
512662306a36Sopenharmony_ci	/*
512762306a36Sopenharmony_ci	 * We don't use STS_FLR, but some controllers don't like it to
512862306a36Sopenharmony_ci	 * remain on, so mask it out along with the other status bits.
512962306a36Sopenharmony_ci	 */
513062306a36Sopenharmony_ci	masked_status = status & (INTR_MASK | STS_FLR);
513162306a36Sopenharmony_ci
513262306a36Sopenharmony_ci	/* Shared IRQ? */
513362306a36Sopenharmony_ci	if (!masked_status ||
513462306a36Sopenharmony_ci			unlikely(fotg210->rh_state == FOTG210_RH_HALTED)) {
513562306a36Sopenharmony_ci		spin_unlock(&fotg210->lock);
513662306a36Sopenharmony_ci		return IRQ_NONE;
513762306a36Sopenharmony_ci	}
513862306a36Sopenharmony_ci
513962306a36Sopenharmony_ci	/* clear (just) interrupts */
514062306a36Sopenharmony_ci	fotg210_writel(fotg210, masked_status, &fotg210->regs->status);
514162306a36Sopenharmony_ci	cmd = fotg210_readl(fotg210, &fotg210->regs->command);
514262306a36Sopenharmony_ci	bh = 0;
514362306a36Sopenharmony_ci
514462306a36Sopenharmony_ci	/* unrequested/ignored: Frame List Rollover */
514562306a36Sopenharmony_ci	dbg_status(fotg210, "irq", status);
514662306a36Sopenharmony_ci
514762306a36Sopenharmony_ci	/* INT, ERR, and IAA interrupt rates can be throttled */
514862306a36Sopenharmony_ci
514962306a36Sopenharmony_ci	/* normal [4.15.1.2] or error [4.15.1.1] completion */
515062306a36Sopenharmony_ci	if (likely((status & (STS_INT|STS_ERR)) != 0)) {
515162306a36Sopenharmony_ci		if (likely((status & STS_ERR) == 0))
515262306a36Sopenharmony_ci			INCR(fotg210->stats.normal);
515362306a36Sopenharmony_ci		else
515462306a36Sopenharmony_ci			INCR(fotg210->stats.error);
515562306a36Sopenharmony_ci		bh = 1;
515662306a36Sopenharmony_ci	}
515762306a36Sopenharmony_ci
515862306a36Sopenharmony_ci	/* complete the unlinking of some qh [4.15.2.3] */
515962306a36Sopenharmony_ci	if (status & STS_IAA) {
516062306a36Sopenharmony_ci
516162306a36Sopenharmony_ci		/* Turn off the IAA watchdog */
516262306a36Sopenharmony_ci		fotg210->enabled_hrtimer_events &=
516362306a36Sopenharmony_ci			~BIT(FOTG210_HRTIMER_IAA_WATCHDOG);
516462306a36Sopenharmony_ci
516562306a36Sopenharmony_ci		/*
516662306a36Sopenharmony_ci		 * Mild optimization: Allow another IAAD to reset the
516762306a36Sopenharmony_ci		 * hrtimer, if one occurs before the next expiration.
516862306a36Sopenharmony_ci		 * In theory we could always cancel the hrtimer, but
516962306a36Sopenharmony_ci		 * tests show that about half the time it will be reset
517062306a36Sopenharmony_ci		 * for some other event anyway.
517162306a36Sopenharmony_ci		 */
517262306a36Sopenharmony_ci		if (fotg210->next_hrtimer_event == FOTG210_HRTIMER_IAA_WATCHDOG)
517362306a36Sopenharmony_ci			++fotg210->next_hrtimer_event;
517462306a36Sopenharmony_ci
517562306a36Sopenharmony_ci		/* guard against (alleged) silicon errata */
517662306a36Sopenharmony_ci		if (cmd & CMD_IAAD)
517762306a36Sopenharmony_ci			fotg210_dbg(fotg210, "IAA with IAAD still set?\n");
517862306a36Sopenharmony_ci		if (fotg210->async_iaa) {
517962306a36Sopenharmony_ci			INCR(fotg210->stats.iaa);
518062306a36Sopenharmony_ci			end_unlink_async(fotg210);
518162306a36Sopenharmony_ci		} else
518262306a36Sopenharmony_ci			fotg210_dbg(fotg210, "IAA with nothing unlinked?\n");
518362306a36Sopenharmony_ci	}
518462306a36Sopenharmony_ci
518562306a36Sopenharmony_ci	/* remote wakeup [4.3.1] */
518662306a36Sopenharmony_ci	if (status & STS_PCD) {
518762306a36Sopenharmony_ci		int pstatus;
518862306a36Sopenharmony_ci		u32 __iomem *status_reg = &fotg210->regs->port_status;
518962306a36Sopenharmony_ci
519062306a36Sopenharmony_ci		/* kick root hub later */
519162306a36Sopenharmony_ci		pcd_status = status;
519262306a36Sopenharmony_ci
519362306a36Sopenharmony_ci		/* resume root hub? */
519462306a36Sopenharmony_ci		if (fotg210->rh_state == FOTG210_RH_SUSPENDED)
519562306a36Sopenharmony_ci			usb_hcd_resume_root_hub(hcd);
519662306a36Sopenharmony_ci
519762306a36Sopenharmony_ci		pstatus = fotg210_readl(fotg210, status_reg);
519862306a36Sopenharmony_ci
519962306a36Sopenharmony_ci		if (test_bit(0, &fotg210->suspended_ports) &&
520062306a36Sopenharmony_ci				((pstatus & PORT_RESUME) ||
520162306a36Sopenharmony_ci				!(pstatus & PORT_SUSPEND)) &&
520262306a36Sopenharmony_ci				(pstatus & PORT_PE) &&
520362306a36Sopenharmony_ci				fotg210->reset_done[0] == 0) {
520462306a36Sopenharmony_ci
520562306a36Sopenharmony_ci			/* start 20 msec resume signaling from this port,
520662306a36Sopenharmony_ci			 * and make hub_wq collect PORT_STAT_C_SUSPEND to
520762306a36Sopenharmony_ci			 * stop that signaling.  Use 5 ms extra for safety,
520862306a36Sopenharmony_ci			 * like usb_port_resume() does.
520962306a36Sopenharmony_ci			 */
521062306a36Sopenharmony_ci			fotg210->reset_done[0] = jiffies + msecs_to_jiffies(25);
521162306a36Sopenharmony_ci			set_bit(0, &fotg210->resuming_ports);
521262306a36Sopenharmony_ci			fotg210_dbg(fotg210, "port 1 remote wakeup\n");
521362306a36Sopenharmony_ci			mod_timer(&hcd->rh_timer, fotg210->reset_done[0]);
521462306a36Sopenharmony_ci		}
521562306a36Sopenharmony_ci	}
521662306a36Sopenharmony_ci
521762306a36Sopenharmony_ci	/* PCI errors [4.15.2.4] */
521862306a36Sopenharmony_ci	if (unlikely((status & STS_FATAL) != 0)) {
521962306a36Sopenharmony_ci		fotg210_err(fotg210, "fatal error\n");
522062306a36Sopenharmony_ci		dbg_cmd(fotg210, "fatal", cmd);
522162306a36Sopenharmony_ci		dbg_status(fotg210, "fatal", status);
522262306a36Sopenharmony_cidead:
522362306a36Sopenharmony_ci		usb_hc_died(hcd);
522462306a36Sopenharmony_ci
522562306a36Sopenharmony_ci		/* Don't let the controller do anything more */
522662306a36Sopenharmony_ci		fotg210->shutdown = true;
522762306a36Sopenharmony_ci		fotg210->rh_state = FOTG210_RH_STOPPING;
522862306a36Sopenharmony_ci		fotg210->command &= ~(CMD_RUN | CMD_ASE | CMD_PSE);
522962306a36Sopenharmony_ci		fotg210_writel(fotg210, fotg210->command,
523062306a36Sopenharmony_ci				&fotg210->regs->command);
523162306a36Sopenharmony_ci		fotg210_writel(fotg210, 0, &fotg210->regs->intr_enable);
523262306a36Sopenharmony_ci		fotg210_handle_controller_death(fotg210);
523362306a36Sopenharmony_ci
523462306a36Sopenharmony_ci		/* Handle completions when the controller stops */
523562306a36Sopenharmony_ci		bh = 0;
523662306a36Sopenharmony_ci	}
523762306a36Sopenharmony_ci
523862306a36Sopenharmony_ci	if (bh)
523962306a36Sopenharmony_ci		fotg210_work(fotg210);
524062306a36Sopenharmony_ci	spin_unlock(&fotg210->lock);
524162306a36Sopenharmony_ci	if (pcd_status)
524262306a36Sopenharmony_ci		usb_hcd_poll_rh_status(hcd);
524362306a36Sopenharmony_ci	return IRQ_HANDLED;
524462306a36Sopenharmony_ci}
524562306a36Sopenharmony_ci
524662306a36Sopenharmony_ci/* non-error returns are a promise to giveback() the urb later
524762306a36Sopenharmony_ci * we drop ownership so next owner (or urb unlink) can get it
524862306a36Sopenharmony_ci *
524962306a36Sopenharmony_ci * urb + dev is in hcd.self.controller.urb_list
525062306a36Sopenharmony_ci * we're queueing TDs onto software and hardware lists
525162306a36Sopenharmony_ci *
525262306a36Sopenharmony_ci * hcd-specific init for hcpriv hasn't been done yet
525362306a36Sopenharmony_ci *
525462306a36Sopenharmony_ci * NOTE:  control, bulk, and interrupt share the same code to append TDs
525562306a36Sopenharmony_ci * to a (possibly active) QH, and the same QH scanning code.
525662306a36Sopenharmony_ci */
525762306a36Sopenharmony_cistatic int fotg210_urb_enqueue(struct usb_hcd *hcd, struct urb *urb,
525862306a36Sopenharmony_ci		gfp_t mem_flags)
525962306a36Sopenharmony_ci{
526062306a36Sopenharmony_ci	struct fotg210_hcd *fotg210 = hcd_to_fotg210(hcd);
526162306a36Sopenharmony_ci	struct list_head qtd_list;
526262306a36Sopenharmony_ci
526362306a36Sopenharmony_ci	INIT_LIST_HEAD(&qtd_list);
526462306a36Sopenharmony_ci
526562306a36Sopenharmony_ci	switch (usb_pipetype(urb->pipe)) {
526662306a36Sopenharmony_ci	case PIPE_CONTROL:
526762306a36Sopenharmony_ci		/* qh_completions() code doesn't handle all the fault cases
526862306a36Sopenharmony_ci		 * in multi-TD control transfers.  Even 1KB is rare anyway.
526962306a36Sopenharmony_ci		 */
527062306a36Sopenharmony_ci		if (urb->transfer_buffer_length > (16 * 1024))
527162306a36Sopenharmony_ci			return -EMSGSIZE;
527262306a36Sopenharmony_ci		fallthrough;
527362306a36Sopenharmony_ci	/* case PIPE_BULK: */
527462306a36Sopenharmony_ci	default:
527562306a36Sopenharmony_ci		if (!qh_urb_transaction(fotg210, urb, &qtd_list, mem_flags))
527662306a36Sopenharmony_ci			return -ENOMEM;
527762306a36Sopenharmony_ci		return submit_async(fotg210, urb, &qtd_list, mem_flags);
527862306a36Sopenharmony_ci
527962306a36Sopenharmony_ci	case PIPE_INTERRUPT:
528062306a36Sopenharmony_ci		if (!qh_urb_transaction(fotg210, urb, &qtd_list, mem_flags))
528162306a36Sopenharmony_ci			return -ENOMEM;
528262306a36Sopenharmony_ci		return intr_submit(fotg210, urb, &qtd_list, mem_flags);
528362306a36Sopenharmony_ci
528462306a36Sopenharmony_ci	case PIPE_ISOCHRONOUS:
528562306a36Sopenharmony_ci		return itd_submit(fotg210, urb, mem_flags);
528662306a36Sopenharmony_ci	}
528762306a36Sopenharmony_ci}
528862306a36Sopenharmony_ci
528962306a36Sopenharmony_ci/* remove from hardware lists
529062306a36Sopenharmony_ci * completions normally happen asynchronously
529162306a36Sopenharmony_ci */
529262306a36Sopenharmony_ci
529362306a36Sopenharmony_cistatic int fotg210_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
529462306a36Sopenharmony_ci{
529562306a36Sopenharmony_ci	struct fotg210_hcd *fotg210 = hcd_to_fotg210(hcd);
529662306a36Sopenharmony_ci	struct fotg210_qh *qh;
529762306a36Sopenharmony_ci	unsigned long flags;
529862306a36Sopenharmony_ci	int rc;
529962306a36Sopenharmony_ci
530062306a36Sopenharmony_ci	spin_lock_irqsave(&fotg210->lock, flags);
530162306a36Sopenharmony_ci	rc = usb_hcd_check_unlink_urb(hcd, urb, status);
530262306a36Sopenharmony_ci	if (rc)
530362306a36Sopenharmony_ci		goto done;
530462306a36Sopenharmony_ci
530562306a36Sopenharmony_ci	switch (usb_pipetype(urb->pipe)) {
530662306a36Sopenharmony_ci	/* case PIPE_CONTROL: */
530762306a36Sopenharmony_ci	/* case PIPE_BULK:*/
530862306a36Sopenharmony_ci	default:
530962306a36Sopenharmony_ci		qh = (struct fotg210_qh *) urb->hcpriv;
531062306a36Sopenharmony_ci		if (!qh)
531162306a36Sopenharmony_ci			break;
531262306a36Sopenharmony_ci		switch (qh->qh_state) {
531362306a36Sopenharmony_ci		case QH_STATE_LINKED:
531462306a36Sopenharmony_ci		case QH_STATE_COMPLETING:
531562306a36Sopenharmony_ci			start_unlink_async(fotg210, qh);
531662306a36Sopenharmony_ci			break;
531762306a36Sopenharmony_ci		case QH_STATE_UNLINK:
531862306a36Sopenharmony_ci		case QH_STATE_UNLINK_WAIT:
531962306a36Sopenharmony_ci			/* already started */
532062306a36Sopenharmony_ci			break;
532162306a36Sopenharmony_ci		case QH_STATE_IDLE:
532262306a36Sopenharmony_ci			/* QH might be waiting for a Clear-TT-Buffer */
532362306a36Sopenharmony_ci			qh_completions(fotg210, qh);
532462306a36Sopenharmony_ci			break;
532562306a36Sopenharmony_ci		}
532662306a36Sopenharmony_ci		break;
532762306a36Sopenharmony_ci
532862306a36Sopenharmony_ci	case PIPE_INTERRUPT:
532962306a36Sopenharmony_ci		qh = (struct fotg210_qh *) urb->hcpriv;
533062306a36Sopenharmony_ci		if (!qh)
533162306a36Sopenharmony_ci			break;
533262306a36Sopenharmony_ci		switch (qh->qh_state) {
533362306a36Sopenharmony_ci		case QH_STATE_LINKED:
533462306a36Sopenharmony_ci		case QH_STATE_COMPLETING:
533562306a36Sopenharmony_ci			start_unlink_intr(fotg210, qh);
533662306a36Sopenharmony_ci			break;
533762306a36Sopenharmony_ci		case QH_STATE_IDLE:
533862306a36Sopenharmony_ci			qh_completions(fotg210, qh);
533962306a36Sopenharmony_ci			break;
534062306a36Sopenharmony_ci		default:
534162306a36Sopenharmony_ci			fotg210_dbg(fotg210, "bogus qh %p state %d\n",
534262306a36Sopenharmony_ci					qh, qh->qh_state);
534362306a36Sopenharmony_ci			goto done;
534462306a36Sopenharmony_ci		}
534562306a36Sopenharmony_ci		break;
534662306a36Sopenharmony_ci
534762306a36Sopenharmony_ci	case PIPE_ISOCHRONOUS:
534862306a36Sopenharmony_ci		/* itd... */
534962306a36Sopenharmony_ci
535062306a36Sopenharmony_ci		/* wait till next completion, do it then. */
535162306a36Sopenharmony_ci		/* completion irqs can wait up to 1024 msec, */
535262306a36Sopenharmony_ci		break;
535362306a36Sopenharmony_ci	}
535462306a36Sopenharmony_cidone:
535562306a36Sopenharmony_ci	spin_unlock_irqrestore(&fotg210->lock, flags);
535662306a36Sopenharmony_ci	return rc;
535762306a36Sopenharmony_ci}
535862306a36Sopenharmony_ci
535962306a36Sopenharmony_ci/* bulk qh holds the data toggle */
536062306a36Sopenharmony_ci
536162306a36Sopenharmony_cistatic void fotg210_endpoint_disable(struct usb_hcd *hcd,
536262306a36Sopenharmony_ci		struct usb_host_endpoint *ep)
536362306a36Sopenharmony_ci{
536462306a36Sopenharmony_ci	struct fotg210_hcd *fotg210 = hcd_to_fotg210(hcd);
536562306a36Sopenharmony_ci	unsigned long flags;
536662306a36Sopenharmony_ci	struct fotg210_qh *qh, *tmp;
536762306a36Sopenharmony_ci
536862306a36Sopenharmony_ci	/* ASSERT:  any requests/urbs are being unlinked */
536962306a36Sopenharmony_ci	/* ASSERT:  nobody can be submitting urbs for this any more */
537062306a36Sopenharmony_ci
537162306a36Sopenharmony_cirescan:
537262306a36Sopenharmony_ci	spin_lock_irqsave(&fotg210->lock, flags);
537362306a36Sopenharmony_ci	qh = ep->hcpriv;
537462306a36Sopenharmony_ci	if (!qh)
537562306a36Sopenharmony_ci		goto done;
537662306a36Sopenharmony_ci
537762306a36Sopenharmony_ci	/* endpoints can be iso streams.  for now, we don't
537862306a36Sopenharmony_ci	 * accelerate iso completions ... so spin a while.
537962306a36Sopenharmony_ci	 */
538062306a36Sopenharmony_ci	if (qh->hw == NULL) {
538162306a36Sopenharmony_ci		struct fotg210_iso_stream *stream = ep->hcpriv;
538262306a36Sopenharmony_ci
538362306a36Sopenharmony_ci		if (!list_empty(&stream->td_list))
538462306a36Sopenharmony_ci			goto idle_timeout;
538562306a36Sopenharmony_ci
538662306a36Sopenharmony_ci		/* BUG_ON(!list_empty(&stream->free_list)); */
538762306a36Sopenharmony_ci		kfree(stream);
538862306a36Sopenharmony_ci		goto done;
538962306a36Sopenharmony_ci	}
539062306a36Sopenharmony_ci
539162306a36Sopenharmony_ci	if (fotg210->rh_state < FOTG210_RH_RUNNING)
539262306a36Sopenharmony_ci		qh->qh_state = QH_STATE_IDLE;
539362306a36Sopenharmony_ci	switch (qh->qh_state) {
539462306a36Sopenharmony_ci	case QH_STATE_LINKED:
539562306a36Sopenharmony_ci	case QH_STATE_COMPLETING:
539662306a36Sopenharmony_ci		for (tmp = fotg210->async->qh_next.qh;
539762306a36Sopenharmony_ci				tmp && tmp != qh;
539862306a36Sopenharmony_ci				tmp = tmp->qh_next.qh)
539962306a36Sopenharmony_ci			continue;
540062306a36Sopenharmony_ci		/* periodic qh self-unlinks on empty, and a COMPLETING qh
540162306a36Sopenharmony_ci		 * may already be unlinked.
540262306a36Sopenharmony_ci		 */
540362306a36Sopenharmony_ci		if (tmp)
540462306a36Sopenharmony_ci			start_unlink_async(fotg210, qh);
540562306a36Sopenharmony_ci		fallthrough;
540662306a36Sopenharmony_ci	case QH_STATE_UNLINK:		/* wait for hw to finish? */
540762306a36Sopenharmony_ci	case QH_STATE_UNLINK_WAIT:
540862306a36Sopenharmony_ciidle_timeout:
540962306a36Sopenharmony_ci		spin_unlock_irqrestore(&fotg210->lock, flags);
541062306a36Sopenharmony_ci		schedule_timeout_uninterruptible(1);
541162306a36Sopenharmony_ci		goto rescan;
541262306a36Sopenharmony_ci	case QH_STATE_IDLE:		/* fully unlinked */
541362306a36Sopenharmony_ci		if (qh->clearing_tt)
541462306a36Sopenharmony_ci			goto idle_timeout;
541562306a36Sopenharmony_ci		if (list_empty(&qh->qtd_list)) {
541662306a36Sopenharmony_ci			qh_destroy(fotg210, qh);
541762306a36Sopenharmony_ci			break;
541862306a36Sopenharmony_ci		}
541962306a36Sopenharmony_ci		fallthrough;
542062306a36Sopenharmony_ci	default:
542162306a36Sopenharmony_ci		/* caller was supposed to have unlinked any requests;
542262306a36Sopenharmony_ci		 * that's not our job.  just leak this memory.
542362306a36Sopenharmony_ci		 */
542462306a36Sopenharmony_ci		fotg210_err(fotg210, "qh %p (#%02x) state %d%s\n",
542562306a36Sopenharmony_ci				qh, ep->desc.bEndpointAddress, qh->qh_state,
542662306a36Sopenharmony_ci				list_empty(&qh->qtd_list) ? "" : "(has tds)");
542762306a36Sopenharmony_ci		break;
542862306a36Sopenharmony_ci	}
542962306a36Sopenharmony_cidone:
543062306a36Sopenharmony_ci	ep->hcpriv = NULL;
543162306a36Sopenharmony_ci	spin_unlock_irqrestore(&fotg210->lock, flags);
543262306a36Sopenharmony_ci}
543362306a36Sopenharmony_ci
543462306a36Sopenharmony_cistatic void fotg210_endpoint_reset(struct usb_hcd *hcd,
543562306a36Sopenharmony_ci		struct usb_host_endpoint *ep)
543662306a36Sopenharmony_ci{
543762306a36Sopenharmony_ci	struct fotg210_hcd *fotg210 = hcd_to_fotg210(hcd);
543862306a36Sopenharmony_ci	struct fotg210_qh *qh;
543962306a36Sopenharmony_ci	int eptype = usb_endpoint_type(&ep->desc);
544062306a36Sopenharmony_ci	int epnum = usb_endpoint_num(&ep->desc);
544162306a36Sopenharmony_ci	int is_out = usb_endpoint_dir_out(&ep->desc);
544262306a36Sopenharmony_ci	unsigned long flags;
544362306a36Sopenharmony_ci
544462306a36Sopenharmony_ci	if (eptype != USB_ENDPOINT_XFER_BULK && eptype != USB_ENDPOINT_XFER_INT)
544562306a36Sopenharmony_ci		return;
544662306a36Sopenharmony_ci
544762306a36Sopenharmony_ci	spin_lock_irqsave(&fotg210->lock, flags);
544862306a36Sopenharmony_ci	qh = ep->hcpriv;
544962306a36Sopenharmony_ci
545062306a36Sopenharmony_ci	/* For Bulk and Interrupt endpoints we maintain the toggle state
545162306a36Sopenharmony_ci	 * in the hardware; the toggle bits in udev aren't used at all.
545262306a36Sopenharmony_ci	 * When an endpoint is reset by usb_clear_halt() we must reset
545362306a36Sopenharmony_ci	 * the toggle bit in the QH.
545462306a36Sopenharmony_ci	 */
545562306a36Sopenharmony_ci	if (qh) {
545662306a36Sopenharmony_ci		usb_settoggle(qh->dev, epnum, is_out, 0);
545762306a36Sopenharmony_ci		if (!list_empty(&qh->qtd_list)) {
545862306a36Sopenharmony_ci			WARN_ONCE(1, "clear_halt for a busy endpoint\n");
545962306a36Sopenharmony_ci		} else if (qh->qh_state == QH_STATE_LINKED ||
546062306a36Sopenharmony_ci				qh->qh_state == QH_STATE_COMPLETING) {
546162306a36Sopenharmony_ci
546262306a36Sopenharmony_ci			/* The toggle value in the QH can't be updated
546362306a36Sopenharmony_ci			 * while the QH is active.  Unlink it now;
546462306a36Sopenharmony_ci			 * re-linking will call qh_refresh().
546562306a36Sopenharmony_ci			 */
546662306a36Sopenharmony_ci			if (eptype == USB_ENDPOINT_XFER_BULK)
546762306a36Sopenharmony_ci				start_unlink_async(fotg210, qh);
546862306a36Sopenharmony_ci			else
546962306a36Sopenharmony_ci				start_unlink_intr(fotg210, qh);
547062306a36Sopenharmony_ci		}
547162306a36Sopenharmony_ci	}
547262306a36Sopenharmony_ci	spin_unlock_irqrestore(&fotg210->lock, flags);
547362306a36Sopenharmony_ci}
547462306a36Sopenharmony_ci
547562306a36Sopenharmony_cistatic int fotg210_get_frame(struct usb_hcd *hcd)
547662306a36Sopenharmony_ci{
547762306a36Sopenharmony_ci	struct fotg210_hcd *fotg210 = hcd_to_fotg210(hcd);
547862306a36Sopenharmony_ci
547962306a36Sopenharmony_ci	return (fotg210_read_frame_index(fotg210) >> 3) %
548062306a36Sopenharmony_ci		fotg210->periodic_size;
548162306a36Sopenharmony_ci}
548262306a36Sopenharmony_ci
548362306a36Sopenharmony_ci/* The EHCI in ChipIdea HDRC cannot be a separate module or device,
548462306a36Sopenharmony_ci * because its registers (and irq) are shared between host/gadget/otg
548562306a36Sopenharmony_ci * functions  and in order to facilitate role switching we cannot
548662306a36Sopenharmony_ci * give the fotg210 driver exclusive access to those.
548762306a36Sopenharmony_ci */
548862306a36Sopenharmony_ci
548962306a36Sopenharmony_cistatic const struct hc_driver fotg210_fotg210_hc_driver = {
549062306a36Sopenharmony_ci	.description		= hcd_name,
549162306a36Sopenharmony_ci	.product_desc		= "Faraday USB2.0 Host Controller",
549262306a36Sopenharmony_ci	.hcd_priv_size		= sizeof(struct fotg210_hcd),
549362306a36Sopenharmony_ci
549462306a36Sopenharmony_ci	/*
549562306a36Sopenharmony_ci	 * generic hardware linkage
549662306a36Sopenharmony_ci	 */
549762306a36Sopenharmony_ci	.irq			= fotg210_irq,
549862306a36Sopenharmony_ci	.flags			= HCD_MEMORY | HCD_DMA | HCD_USB2,
549962306a36Sopenharmony_ci
550062306a36Sopenharmony_ci	/*
550162306a36Sopenharmony_ci	 * basic lifecycle operations
550262306a36Sopenharmony_ci	 */
550362306a36Sopenharmony_ci	.reset			= hcd_fotg210_init,
550462306a36Sopenharmony_ci	.start			= fotg210_run,
550562306a36Sopenharmony_ci	.stop			= fotg210_stop,
550662306a36Sopenharmony_ci	.shutdown		= fotg210_shutdown,
550762306a36Sopenharmony_ci
550862306a36Sopenharmony_ci	/*
550962306a36Sopenharmony_ci	 * managing i/o requests and associated device resources
551062306a36Sopenharmony_ci	 */
551162306a36Sopenharmony_ci	.urb_enqueue		= fotg210_urb_enqueue,
551262306a36Sopenharmony_ci	.urb_dequeue		= fotg210_urb_dequeue,
551362306a36Sopenharmony_ci	.endpoint_disable	= fotg210_endpoint_disable,
551462306a36Sopenharmony_ci	.endpoint_reset		= fotg210_endpoint_reset,
551562306a36Sopenharmony_ci
551662306a36Sopenharmony_ci	/*
551762306a36Sopenharmony_ci	 * scheduling support
551862306a36Sopenharmony_ci	 */
551962306a36Sopenharmony_ci	.get_frame_number	= fotg210_get_frame,
552062306a36Sopenharmony_ci
552162306a36Sopenharmony_ci	/*
552262306a36Sopenharmony_ci	 * root hub support
552362306a36Sopenharmony_ci	 */
552462306a36Sopenharmony_ci	.hub_status_data	= fotg210_hub_status_data,
552562306a36Sopenharmony_ci	.hub_control		= fotg210_hub_control,
552662306a36Sopenharmony_ci	.bus_suspend		= fotg210_bus_suspend,
552762306a36Sopenharmony_ci	.bus_resume		= fotg210_bus_resume,
552862306a36Sopenharmony_ci
552962306a36Sopenharmony_ci	.relinquish_port	= fotg210_relinquish_port,
553062306a36Sopenharmony_ci	.port_handed_over	= fotg210_port_handed_over,
553162306a36Sopenharmony_ci
553262306a36Sopenharmony_ci	.clear_tt_buffer_complete = fotg210_clear_tt_buffer_complete,
553362306a36Sopenharmony_ci};
553462306a36Sopenharmony_ci
553562306a36Sopenharmony_cistatic void fotg210_init(struct fotg210_hcd *fotg210)
553662306a36Sopenharmony_ci{
553762306a36Sopenharmony_ci	u32 value;
553862306a36Sopenharmony_ci
553962306a36Sopenharmony_ci	iowrite32(GMIR_MDEV_INT | GMIR_MOTG_INT | GMIR_INT_POLARITY,
554062306a36Sopenharmony_ci			&fotg210->regs->gmir);
554162306a36Sopenharmony_ci
554262306a36Sopenharmony_ci	value = ioread32(&fotg210->regs->otgcsr);
554362306a36Sopenharmony_ci	value &= ~OTGCSR_A_BUS_DROP;
554462306a36Sopenharmony_ci	value |= OTGCSR_A_BUS_REQ;
554562306a36Sopenharmony_ci	iowrite32(value, &fotg210->regs->otgcsr);
554662306a36Sopenharmony_ci}
554762306a36Sopenharmony_ci
554862306a36Sopenharmony_ci/*
554962306a36Sopenharmony_ci * fotg210_hcd_probe - initialize faraday FOTG210 HCDs
555062306a36Sopenharmony_ci *
555162306a36Sopenharmony_ci * Allocates basic resources for this USB host controller, and
555262306a36Sopenharmony_ci * then invokes the start() method for the HCD associated with it
555362306a36Sopenharmony_ci * through the hotplug entry's driver_data.
555462306a36Sopenharmony_ci */
555562306a36Sopenharmony_ciint fotg210_hcd_probe(struct platform_device *pdev, struct fotg210 *fotg)
555662306a36Sopenharmony_ci{
555762306a36Sopenharmony_ci	struct device *dev = &pdev->dev;
555862306a36Sopenharmony_ci	struct usb_hcd *hcd;
555962306a36Sopenharmony_ci	int irq;
556062306a36Sopenharmony_ci	int retval;
556162306a36Sopenharmony_ci	struct fotg210_hcd *fotg210;
556262306a36Sopenharmony_ci
556362306a36Sopenharmony_ci	if (usb_disabled())
556462306a36Sopenharmony_ci		return -ENODEV;
556562306a36Sopenharmony_ci
556662306a36Sopenharmony_ci	pdev->dev.power.power_state = PMSG_ON;
556762306a36Sopenharmony_ci
556862306a36Sopenharmony_ci	irq = platform_get_irq(pdev, 0);
556962306a36Sopenharmony_ci	if (irq < 0)
557062306a36Sopenharmony_ci		return irq;
557162306a36Sopenharmony_ci
557262306a36Sopenharmony_ci	hcd = usb_create_hcd(&fotg210_fotg210_hc_driver, dev,
557362306a36Sopenharmony_ci			dev_name(dev));
557462306a36Sopenharmony_ci	if (!hcd) {
557562306a36Sopenharmony_ci		retval = dev_err_probe(dev, -ENOMEM, "failed to create hcd\n");
557662306a36Sopenharmony_ci		goto fail_create_hcd;
557762306a36Sopenharmony_ci	}
557862306a36Sopenharmony_ci
557962306a36Sopenharmony_ci	hcd->has_tt = 1;
558062306a36Sopenharmony_ci
558162306a36Sopenharmony_ci	hcd->regs = fotg->base;
558262306a36Sopenharmony_ci
558362306a36Sopenharmony_ci	hcd->rsrc_start = fotg->res->start;
558462306a36Sopenharmony_ci	hcd->rsrc_len = resource_size(fotg->res);
558562306a36Sopenharmony_ci
558662306a36Sopenharmony_ci	fotg210 = hcd_to_fotg210(hcd);
558762306a36Sopenharmony_ci
558862306a36Sopenharmony_ci	fotg210->fotg = fotg;
558962306a36Sopenharmony_ci	fotg210->caps = hcd->regs;
559062306a36Sopenharmony_ci
559162306a36Sopenharmony_ci	retval = fotg210_setup(hcd);
559262306a36Sopenharmony_ci	if (retval)
559362306a36Sopenharmony_ci		goto failed_put_hcd;
559462306a36Sopenharmony_ci
559562306a36Sopenharmony_ci	fotg210_init(fotg210);
559662306a36Sopenharmony_ci
559762306a36Sopenharmony_ci	retval = usb_add_hcd(hcd, irq, IRQF_SHARED);
559862306a36Sopenharmony_ci	if (retval) {
559962306a36Sopenharmony_ci		dev_err_probe(dev, retval, "failed to add hcd\n");
560062306a36Sopenharmony_ci		goto failed_put_hcd;
560162306a36Sopenharmony_ci	}
560262306a36Sopenharmony_ci	device_wakeup_enable(hcd->self.controller);
560362306a36Sopenharmony_ci	platform_set_drvdata(pdev, hcd);
560462306a36Sopenharmony_ci
560562306a36Sopenharmony_ci	return retval;
560662306a36Sopenharmony_ci
560762306a36Sopenharmony_cifailed_put_hcd:
560862306a36Sopenharmony_ci	usb_put_hcd(hcd);
560962306a36Sopenharmony_cifail_create_hcd:
561062306a36Sopenharmony_ci	return dev_err_probe(dev, retval, "init %s fail\n", dev_name(dev));
561162306a36Sopenharmony_ci}
561262306a36Sopenharmony_ci
561362306a36Sopenharmony_ci/*
561462306a36Sopenharmony_ci * fotg210_hcd_remove - shutdown processing for EHCI HCDs
561562306a36Sopenharmony_ci * @dev: USB Host Controller being removed
561662306a36Sopenharmony_ci *
561762306a36Sopenharmony_ci */
561862306a36Sopenharmony_ciint fotg210_hcd_remove(struct platform_device *pdev)
561962306a36Sopenharmony_ci{
562062306a36Sopenharmony_ci	struct usb_hcd *hcd = platform_get_drvdata(pdev);
562162306a36Sopenharmony_ci
562262306a36Sopenharmony_ci	usb_remove_hcd(hcd);
562362306a36Sopenharmony_ci	usb_put_hcd(hcd);
562462306a36Sopenharmony_ci
562562306a36Sopenharmony_ci	return 0;
562662306a36Sopenharmony_ci}
562762306a36Sopenharmony_ci
562862306a36Sopenharmony_ciint __init fotg210_hcd_init(void)
562962306a36Sopenharmony_ci{
563062306a36Sopenharmony_ci	if (usb_disabled())
563162306a36Sopenharmony_ci		return -ENODEV;
563262306a36Sopenharmony_ci
563362306a36Sopenharmony_ci	set_bit(USB_EHCI_LOADED, &usb_hcds_loaded);
563462306a36Sopenharmony_ci	if (test_bit(USB_UHCI_LOADED, &usb_hcds_loaded) ||
563562306a36Sopenharmony_ci			test_bit(USB_OHCI_LOADED, &usb_hcds_loaded))
563662306a36Sopenharmony_ci		pr_warn("Warning! fotg210_hcd should always be loaded before uhci_hcd and ohci_hcd, not after\n");
563762306a36Sopenharmony_ci
563862306a36Sopenharmony_ci	pr_debug("%s: block sizes: qh %zd qtd %zd itd %zd\n",
563962306a36Sopenharmony_ci			hcd_name, sizeof(struct fotg210_qh),
564062306a36Sopenharmony_ci			sizeof(struct fotg210_qtd),
564162306a36Sopenharmony_ci			sizeof(struct fotg210_itd));
564262306a36Sopenharmony_ci
564362306a36Sopenharmony_ci	fotg210_debug_root = debugfs_create_dir("fotg210", usb_debug_root);
564462306a36Sopenharmony_ci
564562306a36Sopenharmony_ci	return 0;
564662306a36Sopenharmony_ci}
564762306a36Sopenharmony_ci
564862306a36Sopenharmony_civoid __exit fotg210_hcd_cleanup(void)
564962306a36Sopenharmony_ci{
565062306a36Sopenharmony_ci	debugfs_remove(fotg210_debug_root);
565162306a36Sopenharmony_ci	clear_bit(USB_EHCI_LOADED, &usb_hcds_loaded);
565262306a36Sopenharmony_ci}
5653