162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Copyright (c) 2008 Rodolfo Giometti <giometti@linux.it>
462306a36Sopenharmony_ci * Copyright (c) 2008 Eurotech S.p.A. <info@eurtech.it>
562306a36Sopenharmony_ci *
662306a36Sopenharmony_ci * This code is *strongly* based on EHCI-HCD code by David Brownell since
762306a36Sopenharmony_ci * the chip is a quasi-EHCI compatible.
862306a36Sopenharmony_ci */
962306a36Sopenharmony_ci
1062306a36Sopenharmony_ci#include <linux/module.h>
1162306a36Sopenharmony_ci#include <linux/pci.h>
1262306a36Sopenharmony_ci#include <linux/dmapool.h>
1362306a36Sopenharmony_ci#include <linux/kernel.h>
1462306a36Sopenharmony_ci#include <linux/delay.h>
1562306a36Sopenharmony_ci#include <linux/ioport.h>
1662306a36Sopenharmony_ci#include <linux/sched.h>
1762306a36Sopenharmony_ci#include <linux/slab.h>
1862306a36Sopenharmony_ci#include <linux/errno.h>
1962306a36Sopenharmony_ci#include <linux/timer.h>
2062306a36Sopenharmony_ci#include <linux/list.h>
2162306a36Sopenharmony_ci#include <linux/interrupt.h>
2262306a36Sopenharmony_ci#include <linux/usb.h>
2362306a36Sopenharmony_ci#include <linux/usb/hcd.h>
2462306a36Sopenharmony_ci#include <linux/moduleparam.h>
2562306a36Sopenharmony_ci#include <linux/dma-mapping.h>
2662306a36Sopenharmony_ci#include <linux/io.h>
2762306a36Sopenharmony_ci#include <linux/iopoll.h>
2862306a36Sopenharmony_ci
2962306a36Sopenharmony_ci#include <asm/irq.h>
3062306a36Sopenharmony_ci#include <asm/unaligned.h>
3162306a36Sopenharmony_ci
3262306a36Sopenharmony_ci#include <linux/irq.h>
3362306a36Sopenharmony_ci#include <linux/platform_device.h>
3462306a36Sopenharmony_ci
3562306a36Sopenharmony_ci#define DRIVER_VERSION "0.0.50"
3662306a36Sopenharmony_ci
3762306a36Sopenharmony_ci#define OXU_DEVICEID			0x00
3862306a36Sopenharmony_ci	#define OXU_REV_MASK		0xffff0000
3962306a36Sopenharmony_ci	#define OXU_REV_SHIFT		16
4062306a36Sopenharmony_ci	#define OXU_REV_2100		0x2100
4162306a36Sopenharmony_ci	#define OXU_BO_SHIFT		8
4262306a36Sopenharmony_ci	#define OXU_BO_MASK		(0x3 << OXU_BO_SHIFT)
4362306a36Sopenharmony_ci	#define OXU_MAJ_REV_SHIFT	4
4462306a36Sopenharmony_ci	#define OXU_MAJ_REV_MASK	(0xf << OXU_MAJ_REV_SHIFT)
4562306a36Sopenharmony_ci	#define OXU_MIN_REV_SHIFT	0
4662306a36Sopenharmony_ci	#define OXU_MIN_REV_MASK	(0xf << OXU_MIN_REV_SHIFT)
4762306a36Sopenharmony_ci#define OXU_HOSTIFCONFIG		0x04
4862306a36Sopenharmony_ci#define OXU_SOFTRESET			0x08
4962306a36Sopenharmony_ci	#define OXU_SRESET		(1 << 0)
5062306a36Sopenharmony_ci
5162306a36Sopenharmony_ci#define OXU_PIOBURSTREADCTRL		0x0C
5262306a36Sopenharmony_ci
5362306a36Sopenharmony_ci#define OXU_CHIPIRQSTATUS		0x10
5462306a36Sopenharmony_ci#define OXU_CHIPIRQEN_SET		0x14
5562306a36Sopenharmony_ci#define OXU_CHIPIRQEN_CLR		0x18
5662306a36Sopenharmony_ci	#define OXU_USBSPHLPWUI		0x00000080
5762306a36Sopenharmony_ci	#define OXU_USBOTGLPWUI		0x00000040
5862306a36Sopenharmony_ci	#define OXU_USBSPHI		0x00000002
5962306a36Sopenharmony_ci	#define OXU_USBOTGI		0x00000001
6062306a36Sopenharmony_ci
6162306a36Sopenharmony_ci#define OXU_CLKCTRL_SET			0x1C
6262306a36Sopenharmony_ci	#define OXU_SYSCLKEN		0x00000008
6362306a36Sopenharmony_ci	#define OXU_USBSPHCLKEN		0x00000002
6462306a36Sopenharmony_ci	#define OXU_USBOTGCLKEN		0x00000001
6562306a36Sopenharmony_ci
6662306a36Sopenharmony_ci#define OXU_ASO				0x68
6762306a36Sopenharmony_ci	#define OXU_SPHPOEN		0x00000100
6862306a36Sopenharmony_ci	#define OXU_OVRCCURPUPDEN	0x00000800
6962306a36Sopenharmony_ci	#define OXU_ASO_OP		(1 << 10)
7062306a36Sopenharmony_ci	#define OXU_COMPARATOR		0x000004000
7162306a36Sopenharmony_ci
7262306a36Sopenharmony_ci#define OXU_USBMODE			0x1A8
7362306a36Sopenharmony_ci	#define OXU_VBPS		0x00000020
7462306a36Sopenharmony_ci	#define OXU_ES_LITTLE		0x00000000
7562306a36Sopenharmony_ci	#define OXU_CM_HOST_ONLY	0x00000003
7662306a36Sopenharmony_ci
7762306a36Sopenharmony_ci/*
7862306a36Sopenharmony_ci * Proper EHCI structs & defines
7962306a36Sopenharmony_ci */
8062306a36Sopenharmony_ci
8162306a36Sopenharmony_ci/* Magic numbers that can affect system performance */
8262306a36Sopenharmony_ci#define EHCI_TUNE_CERR		3	/* 0-3 qtd retries; 0 == don't stop */
8362306a36Sopenharmony_ci#define EHCI_TUNE_RL_HS		4	/* nak throttle; see 4.9 */
8462306a36Sopenharmony_ci#define EHCI_TUNE_RL_TT		0
8562306a36Sopenharmony_ci#define EHCI_TUNE_MULT_HS	1	/* 1-3 transactions/uframe; 4.10.3 */
8662306a36Sopenharmony_ci#define EHCI_TUNE_MULT_TT	1
8762306a36Sopenharmony_ci#define EHCI_TUNE_FLS		2	/* (small) 256 frame schedule */
8862306a36Sopenharmony_ci
8962306a36Sopenharmony_cistruct oxu_hcd;
9062306a36Sopenharmony_ci
9162306a36Sopenharmony_ci/* EHCI register interface, corresponds to EHCI Revision 0.95 specification */
9262306a36Sopenharmony_ci
9362306a36Sopenharmony_ci/* Section 2.2 Host Controller Capability Registers */
9462306a36Sopenharmony_cistruct ehci_caps {
9562306a36Sopenharmony_ci	/* these fields are specified as 8 and 16 bit registers,
9662306a36Sopenharmony_ci	 * but some hosts can't perform 8 or 16 bit PCI accesses.
9762306a36Sopenharmony_ci	 */
9862306a36Sopenharmony_ci	u32		hc_capbase;
9962306a36Sopenharmony_ci#define HC_LENGTH(p)		(((p)>>00)&0x00ff)	/* bits 7:0 */
10062306a36Sopenharmony_ci#define HC_VERSION(p)		(((p)>>16)&0xffff)	/* bits 31:16 */
10162306a36Sopenharmony_ci	u32		hcs_params;     /* HCSPARAMS - offset 0x4 */
10262306a36Sopenharmony_ci#define HCS_DEBUG_PORT(p)	(((p)>>20)&0xf)	/* bits 23:20, debug port? */
10362306a36Sopenharmony_ci#define HCS_INDICATOR(p)	((p)&(1 << 16))	/* true: has port indicators */
10462306a36Sopenharmony_ci#define HCS_N_CC(p)		(((p)>>12)&0xf)	/* bits 15:12, #companion HCs */
10562306a36Sopenharmony_ci#define HCS_N_PCC(p)		(((p)>>8)&0xf)	/* bits 11:8, ports per CC */
10662306a36Sopenharmony_ci#define HCS_PORTROUTED(p)	((p)&(1 << 7))	/* true: port routing */
10762306a36Sopenharmony_ci#define HCS_PPC(p)		((p)&(1 << 4))	/* true: port power control */
10862306a36Sopenharmony_ci#define HCS_N_PORTS(p)		(((p)>>0)&0xf)	/* bits 3:0, ports on HC */
10962306a36Sopenharmony_ci
11062306a36Sopenharmony_ci	u32		hcc_params;      /* HCCPARAMS - offset 0x8 */
11162306a36Sopenharmony_ci#define HCC_EXT_CAPS(p)		(((p)>>8)&0xff)	/* for pci extended caps */
11262306a36Sopenharmony_ci#define HCC_ISOC_CACHE(p)       ((p)&(1 << 7))  /* true: can cache isoc frame */
11362306a36Sopenharmony_ci#define HCC_ISOC_THRES(p)       (((p)>>4)&0x7)  /* bits 6:4, uframes cached */
11462306a36Sopenharmony_ci#define HCC_CANPARK(p)		((p)&(1 << 2))  /* true: can park on async qh */
11562306a36Sopenharmony_ci#define HCC_PGM_FRAMELISTLEN(p) ((p)&(1 << 1))  /* true: periodic_size changes*/
11662306a36Sopenharmony_ci#define HCC_64BIT_ADDR(p)       ((p)&(1))       /* true: can use 64-bit addr */
11762306a36Sopenharmony_ci	u8		portroute[8];	 /* nibbles for routing - offset 0xC */
11862306a36Sopenharmony_ci} __packed;
11962306a36Sopenharmony_ci
12062306a36Sopenharmony_ci
12162306a36Sopenharmony_ci/* Section 2.3 Host Controller Operational Registers */
12262306a36Sopenharmony_cistruct ehci_regs {
12362306a36Sopenharmony_ci	/* USBCMD: offset 0x00 */
12462306a36Sopenharmony_ci	u32		command;
12562306a36Sopenharmony_ci/* 23:16 is r/w intr rate, in microframes; default "8" == 1/msec */
12662306a36Sopenharmony_ci#define CMD_PARK	(1<<11)		/* enable "park" on async qh */
12762306a36Sopenharmony_ci#define CMD_PARK_CNT(c)	(((c)>>8)&3)	/* how many transfers to park for */
12862306a36Sopenharmony_ci#define CMD_LRESET	(1<<7)		/* partial reset (no ports, etc) */
12962306a36Sopenharmony_ci#define CMD_IAAD	(1<<6)		/* "doorbell" interrupt async advance */
13062306a36Sopenharmony_ci#define CMD_ASE		(1<<5)		/* async schedule enable */
13162306a36Sopenharmony_ci#define CMD_PSE		(1<<4)		/* periodic schedule enable */
13262306a36Sopenharmony_ci/* 3:2 is periodic frame list size */
13362306a36Sopenharmony_ci#define CMD_RESET	(1<<1)		/* reset HC not bus */
13462306a36Sopenharmony_ci#define CMD_RUN		(1<<0)		/* start/stop HC */
13562306a36Sopenharmony_ci
13662306a36Sopenharmony_ci	/* USBSTS: offset 0x04 */
13762306a36Sopenharmony_ci	u32		status;
13862306a36Sopenharmony_ci#define STS_ASS		(1<<15)		/* Async Schedule Status */
13962306a36Sopenharmony_ci#define STS_PSS		(1<<14)		/* Periodic Schedule Status */
14062306a36Sopenharmony_ci#define STS_RECL	(1<<13)		/* Reclamation */
14162306a36Sopenharmony_ci#define STS_HALT	(1<<12)		/* Not running (any reason) */
14262306a36Sopenharmony_ci/* some bits reserved */
14362306a36Sopenharmony_ci	/* these STS_* flags are also intr_enable bits (USBINTR) */
14462306a36Sopenharmony_ci#define STS_IAA		(1<<5)		/* Interrupted on async advance */
14562306a36Sopenharmony_ci#define STS_FATAL	(1<<4)		/* such as some PCI access errors */
14662306a36Sopenharmony_ci#define STS_FLR		(1<<3)		/* frame list rolled over */
14762306a36Sopenharmony_ci#define STS_PCD		(1<<2)		/* port change detect */
14862306a36Sopenharmony_ci#define STS_ERR		(1<<1)		/* "error" completion (overflow, ...) */
14962306a36Sopenharmony_ci#define STS_INT		(1<<0)		/* "normal" completion (short, ...) */
15062306a36Sopenharmony_ci
15162306a36Sopenharmony_ci#define INTR_MASK (STS_IAA | STS_FATAL | STS_PCD | STS_ERR | STS_INT)
15262306a36Sopenharmony_ci
15362306a36Sopenharmony_ci	/* USBINTR: offset 0x08 */
15462306a36Sopenharmony_ci	u32		intr_enable;
15562306a36Sopenharmony_ci
15662306a36Sopenharmony_ci	/* FRINDEX: offset 0x0C */
15762306a36Sopenharmony_ci	u32		frame_index;	/* current microframe number */
15862306a36Sopenharmony_ci	/* CTRLDSSEGMENT: offset 0x10 */
15962306a36Sopenharmony_ci	u32		segment;	/* address bits 63:32 if needed */
16062306a36Sopenharmony_ci	/* PERIODICLISTBASE: offset 0x14 */
16162306a36Sopenharmony_ci	u32		frame_list;	/* points to periodic list */
16262306a36Sopenharmony_ci	/* ASYNCLISTADDR: offset 0x18 */
16362306a36Sopenharmony_ci	u32		async_next;	/* address of next async queue head */
16462306a36Sopenharmony_ci
16562306a36Sopenharmony_ci	u32		reserved[9];
16662306a36Sopenharmony_ci
16762306a36Sopenharmony_ci	/* CONFIGFLAG: offset 0x40 */
16862306a36Sopenharmony_ci	u32		configured_flag;
16962306a36Sopenharmony_ci#define FLAG_CF		(1<<0)		/* true: we'll support "high speed" */
17062306a36Sopenharmony_ci
17162306a36Sopenharmony_ci	/* PORTSC: offset 0x44 */
17262306a36Sopenharmony_ci	u32		port_status[];	/* up to N_PORTS */
17362306a36Sopenharmony_ci/* 31:23 reserved */
17462306a36Sopenharmony_ci#define PORT_WKOC_E	(1<<22)		/* wake on overcurrent (enable) */
17562306a36Sopenharmony_ci#define PORT_WKDISC_E	(1<<21)		/* wake on disconnect (enable) */
17662306a36Sopenharmony_ci#define PORT_WKCONN_E	(1<<20)		/* wake on connect (enable) */
17762306a36Sopenharmony_ci/* 19:16 for port testing */
17862306a36Sopenharmony_ci#define PORT_LED_OFF	(0<<14)
17962306a36Sopenharmony_ci#define PORT_LED_AMBER	(1<<14)
18062306a36Sopenharmony_ci#define PORT_LED_GREEN	(2<<14)
18162306a36Sopenharmony_ci#define PORT_LED_MASK	(3<<14)
18262306a36Sopenharmony_ci#define PORT_OWNER	(1<<13)		/* true: companion hc owns this port */
18362306a36Sopenharmony_ci#define PORT_POWER	(1<<12)		/* true: has power (see PPC) */
18462306a36Sopenharmony_ci#define PORT_USB11(x) (((x)&(3<<10)) == (1<<10))	/* USB 1.1 device */
18562306a36Sopenharmony_ci/* 11:10 for detecting lowspeed devices (reset vs release ownership) */
18662306a36Sopenharmony_ci/* 9 reserved */
18762306a36Sopenharmony_ci#define PORT_RESET	(1<<8)		/* reset port */
18862306a36Sopenharmony_ci#define PORT_SUSPEND	(1<<7)		/* suspend port */
18962306a36Sopenharmony_ci#define PORT_RESUME	(1<<6)		/* resume it */
19062306a36Sopenharmony_ci#define PORT_OCC	(1<<5)		/* over current change */
19162306a36Sopenharmony_ci#define PORT_OC		(1<<4)		/* over current active */
19262306a36Sopenharmony_ci#define PORT_PEC	(1<<3)		/* port enable change */
19362306a36Sopenharmony_ci#define PORT_PE		(1<<2)		/* port enable */
19462306a36Sopenharmony_ci#define PORT_CSC	(1<<1)		/* connect status change */
19562306a36Sopenharmony_ci#define PORT_CONNECT	(1<<0)		/* device connected */
19662306a36Sopenharmony_ci#define PORT_RWC_BITS   (PORT_CSC | PORT_PEC | PORT_OCC)
19762306a36Sopenharmony_ci} __packed;
19862306a36Sopenharmony_ci
19962306a36Sopenharmony_ci/* Appendix C, Debug port ... intended for use with special "debug devices"
20062306a36Sopenharmony_ci * that can help if there's no serial console.  (nonstandard enumeration.)
20162306a36Sopenharmony_ci */
20262306a36Sopenharmony_cistruct ehci_dbg_port {
20362306a36Sopenharmony_ci	u32	control;
20462306a36Sopenharmony_ci#define DBGP_OWNER	(1<<30)
20562306a36Sopenharmony_ci#define DBGP_ENABLED	(1<<28)
20662306a36Sopenharmony_ci#define DBGP_DONE	(1<<16)
20762306a36Sopenharmony_ci#define DBGP_INUSE	(1<<10)
20862306a36Sopenharmony_ci#define DBGP_ERRCODE(x)	(((x)>>7)&0x07)
20962306a36Sopenharmony_ci#	define DBGP_ERR_BAD	1
21062306a36Sopenharmony_ci#	define DBGP_ERR_SIGNAL	2
21162306a36Sopenharmony_ci#define DBGP_ERROR	(1<<6)
21262306a36Sopenharmony_ci#define DBGP_GO		(1<<5)
21362306a36Sopenharmony_ci#define DBGP_OUT	(1<<4)
21462306a36Sopenharmony_ci#define DBGP_LEN(x)	(((x)>>0)&0x0f)
21562306a36Sopenharmony_ci	u32	pids;
21662306a36Sopenharmony_ci#define DBGP_PID_GET(x)		(((x)>>16)&0xff)
21762306a36Sopenharmony_ci#define DBGP_PID_SET(data, tok)	(((data)<<8)|(tok))
21862306a36Sopenharmony_ci	u32	data03;
21962306a36Sopenharmony_ci	u32	data47;
22062306a36Sopenharmony_ci	u32	address;
22162306a36Sopenharmony_ci#define DBGP_EPADDR(dev, ep)	(((dev)<<8)|(ep))
22262306a36Sopenharmony_ci} __packed;
22362306a36Sopenharmony_ci
22462306a36Sopenharmony_ci#define	QTD_NEXT(dma)	cpu_to_le32((u32)dma)
22562306a36Sopenharmony_ci
22662306a36Sopenharmony_ci/*
22762306a36Sopenharmony_ci * EHCI Specification 0.95 Section 3.5
22862306a36Sopenharmony_ci * QTD: describe data transfer components (buffer, direction, ...)
22962306a36Sopenharmony_ci * See Fig 3-6 "Queue Element Transfer Descriptor Block Diagram".
23062306a36Sopenharmony_ci *
23162306a36Sopenharmony_ci * These are associated only with "QH" (Queue Head) structures,
23262306a36Sopenharmony_ci * used with control, bulk, and interrupt transfers.
23362306a36Sopenharmony_ci */
23462306a36Sopenharmony_cistruct ehci_qtd {
23562306a36Sopenharmony_ci	/* first part defined by EHCI spec */
23662306a36Sopenharmony_ci	__le32			hw_next;		/* see EHCI 3.5.1 */
23762306a36Sopenharmony_ci	__le32			hw_alt_next;		/* see EHCI 3.5.2 */
23862306a36Sopenharmony_ci	__le32			hw_token;		/* see EHCI 3.5.3 */
23962306a36Sopenharmony_ci#define	QTD_TOGGLE	(1 << 31)	/* data toggle */
24062306a36Sopenharmony_ci#define	QTD_LENGTH(tok)	(((tok)>>16) & 0x7fff)
24162306a36Sopenharmony_ci#define	QTD_IOC		(1 << 15)	/* interrupt on complete */
24262306a36Sopenharmony_ci#define	QTD_CERR(tok)	(((tok)>>10) & 0x3)
24362306a36Sopenharmony_ci#define	QTD_PID(tok)	(((tok)>>8) & 0x3)
24462306a36Sopenharmony_ci#define	QTD_STS_ACTIVE	(1 << 7)	/* HC may execute this */
24562306a36Sopenharmony_ci#define	QTD_STS_HALT	(1 << 6)	/* halted on error */
24662306a36Sopenharmony_ci#define	QTD_STS_DBE	(1 << 5)	/* data buffer error (in HC) */
24762306a36Sopenharmony_ci#define	QTD_STS_BABBLE	(1 << 4)	/* device was babbling (qtd halted) */
24862306a36Sopenharmony_ci#define	QTD_STS_XACT	(1 << 3)	/* device gave illegal response */
24962306a36Sopenharmony_ci#define	QTD_STS_MMF	(1 << 2)	/* incomplete split transaction */
25062306a36Sopenharmony_ci#define	QTD_STS_STS	(1 << 1)	/* split transaction state */
25162306a36Sopenharmony_ci#define	QTD_STS_PING	(1 << 0)	/* issue PING? */
25262306a36Sopenharmony_ci	__le32			hw_buf[5];		/* see EHCI 3.5.4 */
25362306a36Sopenharmony_ci	__le32			hw_buf_hi[5];		/* Appendix B */
25462306a36Sopenharmony_ci
25562306a36Sopenharmony_ci	/* the rest is HCD-private */
25662306a36Sopenharmony_ci	dma_addr_t		qtd_dma;		/* qtd address */
25762306a36Sopenharmony_ci	struct list_head	qtd_list;		/* sw qtd list */
25862306a36Sopenharmony_ci	struct urb		*urb;			/* qtd's urb */
25962306a36Sopenharmony_ci	size_t			length;			/* length of buffer */
26062306a36Sopenharmony_ci
26162306a36Sopenharmony_ci	u32			qtd_buffer_len;
26262306a36Sopenharmony_ci	void			*buffer;
26362306a36Sopenharmony_ci	dma_addr_t		buffer_dma;
26462306a36Sopenharmony_ci	void			*transfer_buffer;
26562306a36Sopenharmony_ci	void			*transfer_dma;
26662306a36Sopenharmony_ci} __aligned(32);
26762306a36Sopenharmony_ci
26862306a36Sopenharmony_ci/* mask NakCnt+T in qh->hw_alt_next */
26962306a36Sopenharmony_ci#define QTD_MASK cpu_to_le32 (~0x1f)
27062306a36Sopenharmony_ci
27162306a36Sopenharmony_ci#define IS_SHORT_READ(token) (QTD_LENGTH(token) != 0 && QTD_PID(token) == 1)
27262306a36Sopenharmony_ci
27362306a36Sopenharmony_ci/* Type tag from {qh, itd, sitd, fstn}->hw_next */
27462306a36Sopenharmony_ci#define Q_NEXT_TYPE(dma) ((dma) & cpu_to_le32 (3 << 1))
27562306a36Sopenharmony_ci
27662306a36Sopenharmony_ci/* values for that type tag */
27762306a36Sopenharmony_ci#define Q_TYPE_QH	cpu_to_le32 (1 << 1)
27862306a36Sopenharmony_ci
27962306a36Sopenharmony_ci/* next async queue entry, or pointer to interrupt/periodic QH */
28062306a36Sopenharmony_ci#define	QH_NEXT(dma)	(cpu_to_le32(((u32)dma)&~0x01f)|Q_TYPE_QH)
28162306a36Sopenharmony_ci
28262306a36Sopenharmony_ci/* for periodic/async schedules and qtd lists, mark end of list */
28362306a36Sopenharmony_ci#define	EHCI_LIST_END	cpu_to_le32(1) /* "null pointer" to hw */
28462306a36Sopenharmony_ci
28562306a36Sopenharmony_ci/*
28662306a36Sopenharmony_ci * Entries in periodic shadow table are pointers to one of four kinds
28762306a36Sopenharmony_ci * of data structure.  That's dictated by the hardware; a type tag is
28862306a36Sopenharmony_ci * encoded in the low bits of the hardware's periodic schedule.  Use
28962306a36Sopenharmony_ci * Q_NEXT_TYPE to get the tag.
29062306a36Sopenharmony_ci *
29162306a36Sopenharmony_ci * For entries in the async schedule, the type tag always says "qh".
29262306a36Sopenharmony_ci */
29362306a36Sopenharmony_ciunion ehci_shadow {
29462306a36Sopenharmony_ci	struct ehci_qh		*qh;		/* Q_TYPE_QH */
29562306a36Sopenharmony_ci	__le32			*hw_next;	/* (all types) */
29662306a36Sopenharmony_ci	void			*ptr;
29762306a36Sopenharmony_ci};
29862306a36Sopenharmony_ci
29962306a36Sopenharmony_ci/*
30062306a36Sopenharmony_ci * EHCI Specification 0.95 Section 3.6
30162306a36Sopenharmony_ci * QH: describes control/bulk/interrupt endpoints
30262306a36Sopenharmony_ci * See Fig 3-7 "Queue Head Structure Layout".
30362306a36Sopenharmony_ci *
30462306a36Sopenharmony_ci * These appear in both the async and (for interrupt) periodic schedules.
30562306a36Sopenharmony_ci */
30662306a36Sopenharmony_ci
30762306a36Sopenharmony_cistruct ehci_qh {
30862306a36Sopenharmony_ci	/* first part defined by EHCI spec */
30962306a36Sopenharmony_ci	__le32			hw_next;	 /* see EHCI 3.6.1 */
31062306a36Sopenharmony_ci	__le32			hw_info1;	/* see EHCI 3.6.2 */
31162306a36Sopenharmony_ci#define	QH_HEAD		0x00008000
31262306a36Sopenharmony_ci	__le32			hw_info2;	/* see EHCI 3.6.2 */
31362306a36Sopenharmony_ci#define	QH_SMASK	0x000000ff
31462306a36Sopenharmony_ci#define	QH_CMASK	0x0000ff00
31562306a36Sopenharmony_ci#define	QH_HUBADDR	0x007f0000
31662306a36Sopenharmony_ci#define	QH_HUBPORT	0x3f800000
31762306a36Sopenharmony_ci#define	QH_MULT		0xc0000000
31862306a36Sopenharmony_ci	__le32			hw_current;	 /* qtd list - see EHCI 3.6.4 */
31962306a36Sopenharmony_ci
32062306a36Sopenharmony_ci	/* qtd overlay (hardware parts of a struct ehci_qtd) */
32162306a36Sopenharmony_ci	__le32			hw_qtd_next;
32262306a36Sopenharmony_ci	__le32			hw_alt_next;
32362306a36Sopenharmony_ci	__le32			hw_token;
32462306a36Sopenharmony_ci	__le32			hw_buf[5];
32562306a36Sopenharmony_ci	__le32			hw_buf_hi[5];
32662306a36Sopenharmony_ci
32762306a36Sopenharmony_ci	/* the rest is HCD-private */
32862306a36Sopenharmony_ci	dma_addr_t		qh_dma;		/* address of qh */
32962306a36Sopenharmony_ci	union ehci_shadow	qh_next;	/* ptr to qh; or periodic */
33062306a36Sopenharmony_ci	struct list_head	qtd_list;	/* sw qtd list */
33162306a36Sopenharmony_ci	struct ehci_qtd		*dummy;
33262306a36Sopenharmony_ci	struct ehci_qh		*reclaim;	/* next to reclaim */
33362306a36Sopenharmony_ci
33462306a36Sopenharmony_ci	struct oxu_hcd		*oxu;
33562306a36Sopenharmony_ci	struct kref		kref;
33662306a36Sopenharmony_ci	unsigned int		stamp;
33762306a36Sopenharmony_ci
33862306a36Sopenharmony_ci	u8			qh_state;
33962306a36Sopenharmony_ci#define	QH_STATE_LINKED		1		/* HC sees this */
34062306a36Sopenharmony_ci#define	QH_STATE_UNLINK		2		/* HC may still see this */
34162306a36Sopenharmony_ci#define	QH_STATE_IDLE		3		/* HC doesn't see this */
34262306a36Sopenharmony_ci#define	QH_STATE_UNLINK_WAIT	4		/* LINKED and on reclaim q */
34362306a36Sopenharmony_ci#define	QH_STATE_COMPLETING	5		/* don't touch token.HALT */
34462306a36Sopenharmony_ci
34562306a36Sopenharmony_ci	/* periodic schedule info */
34662306a36Sopenharmony_ci	u8			usecs;		/* intr bandwidth */
34762306a36Sopenharmony_ci	u8			gap_uf;		/* uframes split/csplit gap */
34862306a36Sopenharmony_ci	u8			c_usecs;	/* ... split completion bw */
34962306a36Sopenharmony_ci	u16			tt_usecs;	/* tt downstream bandwidth */
35062306a36Sopenharmony_ci	unsigned short		period;		/* polling interval */
35162306a36Sopenharmony_ci	unsigned short		start;		/* where polling starts */
35262306a36Sopenharmony_ci#define NO_FRAME ((unsigned short)~0)			/* pick new start */
35362306a36Sopenharmony_ci	struct usb_device	*dev;		/* access to TT */
35462306a36Sopenharmony_ci} __aligned(32);
35562306a36Sopenharmony_ci
35662306a36Sopenharmony_ci/*
35762306a36Sopenharmony_ci * Proper OXU210HP structs
35862306a36Sopenharmony_ci */
35962306a36Sopenharmony_ci
36062306a36Sopenharmony_ci#define OXU_OTG_CORE_OFFSET	0x00400
36162306a36Sopenharmony_ci#define OXU_OTG_CAP_OFFSET	(OXU_OTG_CORE_OFFSET + 0x100)
36262306a36Sopenharmony_ci#define OXU_SPH_CORE_OFFSET	0x00800
36362306a36Sopenharmony_ci#define OXU_SPH_CAP_OFFSET	(OXU_SPH_CORE_OFFSET + 0x100)
36462306a36Sopenharmony_ci
36562306a36Sopenharmony_ci#define OXU_OTG_MEM		0xE000
36662306a36Sopenharmony_ci#define OXU_SPH_MEM		0x16000
36762306a36Sopenharmony_ci
36862306a36Sopenharmony_ci/* Only how many elements & element structure are specifies here. */
36962306a36Sopenharmony_ci/* 2 host controllers are enabled - total size <= 28 kbytes */
37062306a36Sopenharmony_ci#define	DEFAULT_I_TDPS		1024
37162306a36Sopenharmony_ci#define QHEAD_NUM		16
37262306a36Sopenharmony_ci#define QTD_NUM			32
37362306a36Sopenharmony_ci#define SITD_NUM		8
37462306a36Sopenharmony_ci#define MURB_NUM		8
37562306a36Sopenharmony_ci
37662306a36Sopenharmony_ci#define BUFFER_NUM		8
37762306a36Sopenharmony_ci#define BUFFER_SIZE		512
37862306a36Sopenharmony_ci
37962306a36Sopenharmony_cistruct oxu_info {
38062306a36Sopenharmony_ci	struct usb_hcd *hcd[2];
38162306a36Sopenharmony_ci};
38262306a36Sopenharmony_ci
38362306a36Sopenharmony_cistruct oxu_buf {
38462306a36Sopenharmony_ci	u8			buffer[BUFFER_SIZE];
38562306a36Sopenharmony_ci} __aligned(BUFFER_SIZE);
38662306a36Sopenharmony_ci
38762306a36Sopenharmony_cistruct oxu_onchip_mem {
38862306a36Sopenharmony_ci	struct oxu_buf		db_pool[BUFFER_NUM];
38962306a36Sopenharmony_ci
39062306a36Sopenharmony_ci	u32			frame_list[DEFAULT_I_TDPS];
39162306a36Sopenharmony_ci	struct ehci_qh		qh_pool[QHEAD_NUM];
39262306a36Sopenharmony_ci	struct ehci_qtd		qtd_pool[QTD_NUM];
39362306a36Sopenharmony_ci} __aligned(4 << 10);
39462306a36Sopenharmony_ci
39562306a36Sopenharmony_ci#define	EHCI_MAX_ROOT_PORTS	15		/* see HCS_N_PORTS */
39662306a36Sopenharmony_ci
39762306a36Sopenharmony_cistruct oxu_murb {
39862306a36Sopenharmony_ci	struct urb		urb;
39962306a36Sopenharmony_ci	struct urb		*main;
40062306a36Sopenharmony_ci	u8			last;
40162306a36Sopenharmony_ci};
40262306a36Sopenharmony_ci
40362306a36Sopenharmony_cistruct oxu_hcd {				/* one per controller */
40462306a36Sopenharmony_ci	unsigned int		is_otg:1;
40562306a36Sopenharmony_ci
40662306a36Sopenharmony_ci	u8			qh_used[QHEAD_NUM];
40762306a36Sopenharmony_ci	u8			qtd_used[QTD_NUM];
40862306a36Sopenharmony_ci	u8			db_used[BUFFER_NUM];
40962306a36Sopenharmony_ci	u8			murb_used[MURB_NUM];
41062306a36Sopenharmony_ci
41162306a36Sopenharmony_ci	struct oxu_onchip_mem	__iomem *mem;
41262306a36Sopenharmony_ci	spinlock_t		mem_lock;
41362306a36Sopenharmony_ci
41462306a36Sopenharmony_ci	struct timer_list	urb_timer;
41562306a36Sopenharmony_ci
41662306a36Sopenharmony_ci	struct ehci_caps __iomem *caps;
41762306a36Sopenharmony_ci	struct ehci_regs __iomem *regs;
41862306a36Sopenharmony_ci
41962306a36Sopenharmony_ci	u32			hcs_params;	/* cached register copy */
42062306a36Sopenharmony_ci	spinlock_t		lock;
42162306a36Sopenharmony_ci
42262306a36Sopenharmony_ci	/* async schedule support */
42362306a36Sopenharmony_ci	struct ehci_qh		*async;
42462306a36Sopenharmony_ci	struct ehci_qh		*reclaim;
42562306a36Sopenharmony_ci	unsigned int		reclaim_ready:1;
42662306a36Sopenharmony_ci	unsigned int		scanning:1;
42762306a36Sopenharmony_ci
42862306a36Sopenharmony_ci	/* periodic schedule support */
42962306a36Sopenharmony_ci	unsigned int		periodic_size;
43062306a36Sopenharmony_ci	__le32			*periodic;	/* hw periodic table */
43162306a36Sopenharmony_ci	dma_addr_t		periodic_dma;
43262306a36Sopenharmony_ci	unsigned int		i_thresh;	/* uframes HC might cache */
43362306a36Sopenharmony_ci
43462306a36Sopenharmony_ci	union ehci_shadow	*pshadow;	/* mirror hw periodic table */
43562306a36Sopenharmony_ci	int			next_uframe;	/* scan periodic, start here */
43662306a36Sopenharmony_ci	unsigned int		periodic_sched;	/* periodic activity count */
43762306a36Sopenharmony_ci
43862306a36Sopenharmony_ci	/* per root hub port */
43962306a36Sopenharmony_ci	unsigned long		reset_done[EHCI_MAX_ROOT_PORTS];
44062306a36Sopenharmony_ci	/* bit vectors (one bit per port) */
44162306a36Sopenharmony_ci	unsigned long		bus_suspended;	/* which ports were
44262306a36Sopenharmony_ci						 * already suspended at the
44362306a36Sopenharmony_ci						 * start of a bus suspend
44462306a36Sopenharmony_ci						 */
44562306a36Sopenharmony_ci	unsigned long		companion_ports;/* which ports are dedicated
44662306a36Sopenharmony_ci						 * to the companion controller
44762306a36Sopenharmony_ci						 */
44862306a36Sopenharmony_ci
44962306a36Sopenharmony_ci	struct timer_list	watchdog;
45062306a36Sopenharmony_ci	unsigned long		actions;
45162306a36Sopenharmony_ci	unsigned int		stamp;
45262306a36Sopenharmony_ci	unsigned long		next_statechange;
45362306a36Sopenharmony_ci	u32			command;
45462306a36Sopenharmony_ci
45562306a36Sopenharmony_ci	/* SILICON QUIRKS */
45662306a36Sopenharmony_ci	struct list_head	urb_list;	/* this is the head to urb
45762306a36Sopenharmony_ci						 * queue that didn't get enough
45862306a36Sopenharmony_ci						 * resources
45962306a36Sopenharmony_ci						 */
46062306a36Sopenharmony_ci	struct oxu_murb		*murb_pool;	/* murb per split big urb */
46162306a36Sopenharmony_ci	unsigned int		urb_len;
46262306a36Sopenharmony_ci
46362306a36Sopenharmony_ci	u8			sbrn;		/* packed release number */
46462306a36Sopenharmony_ci};
46562306a36Sopenharmony_ci
46662306a36Sopenharmony_ci#define EHCI_IAA_JIFFIES	(HZ/100)	/* arbitrary; ~10 msec */
46762306a36Sopenharmony_ci#define EHCI_IO_JIFFIES		(HZ/10)		/* io watchdog > irq_thresh */
46862306a36Sopenharmony_ci#define EHCI_ASYNC_JIFFIES      (HZ/20)		/* async idle timeout */
46962306a36Sopenharmony_ci#define EHCI_SHRINK_JIFFIES     (HZ/200)	/* async qh unlink delay */
47062306a36Sopenharmony_ci
47162306a36Sopenharmony_cienum ehci_timer_action {
47262306a36Sopenharmony_ci	TIMER_IO_WATCHDOG,
47362306a36Sopenharmony_ci	TIMER_IAA_WATCHDOG,
47462306a36Sopenharmony_ci	TIMER_ASYNC_SHRINK,
47562306a36Sopenharmony_ci	TIMER_ASYNC_OFF,
47662306a36Sopenharmony_ci};
47762306a36Sopenharmony_ci
47862306a36Sopenharmony_ci/*
47962306a36Sopenharmony_ci * Main defines
48062306a36Sopenharmony_ci */
48162306a36Sopenharmony_ci
48262306a36Sopenharmony_ci#define oxu_dbg(oxu, fmt, args...) \
48362306a36Sopenharmony_ci		dev_dbg(oxu_to_hcd(oxu)->self.controller , fmt , ## args)
48462306a36Sopenharmony_ci#define oxu_err(oxu, fmt, args...) \
48562306a36Sopenharmony_ci		dev_err(oxu_to_hcd(oxu)->self.controller , fmt , ## args)
48662306a36Sopenharmony_ci#define oxu_info(oxu, fmt, args...) \
48762306a36Sopenharmony_ci		dev_info(oxu_to_hcd(oxu)->self.controller , fmt , ## args)
48862306a36Sopenharmony_ci
48962306a36Sopenharmony_ci#ifdef CONFIG_DYNAMIC_DEBUG
49062306a36Sopenharmony_ci#define DEBUG
49162306a36Sopenharmony_ci#endif
49262306a36Sopenharmony_ci
49362306a36Sopenharmony_cistatic inline struct usb_hcd *oxu_to_hcd(struct oxu_hcd *oxu)
49462306a36Sopenharmony_ci{
49562306a36Sopenharmony_ci	return container_of((void *) oxu, struct usb_hcd, hcd_priv);
49662306a36Sopenharmony_ci}
49762306a36Sopenharmony_ci
49862306a36Sopenharmony_cistatic inline struct oxu_hcd *hcd_to_oxu(struct usb_hcd *hcd)
49962306a36Sopenharmony_ci{
50062306a36Sopenharmony_ci	return (struct oxu_hcd *) (hcd->hcd_priv);
50162306a36Sopenharmony_ci}
50262306a36Sopenharmony_ci
50362306a36Sopenharmony_ci/*
50462306a36Sopenharmony_ci * Debug stuff
50562306a36Sopenharmony_ci */
50662306a36Sopenharmony_ci
50762306a36Sopenharmony_ci#undef OXU_URB_TRACE
50862306a36Sopenharmony_ci#undef OXU_VERBOSE_DEBUG
50962306a36Sopenharmony_ci
51062306a36Sopenharmony_ci#ifdef OXU_VERBOSE_DEBUG
51162306a36Sopenharmony_ci#define oxu_vdbg			oxu_dbg
51262306a36Sopenharmony_ci#else
51362306a36Sopenharmony_ci#define oxu_vdbg(oxu, fmt, args...)	/* Nop */
51462306a36Sopenharmony_ci#endif
51562306a36Sopenharmony_ci
51662306a36Sopenharmony_ci#ifdef DEBUG
51762306a36Sopenharmony_ci
51862306a36Sopenharmony_cistatic int __attribute__((__unused__))
51962306a36Sopenharmony_cidbg_status_buf(char *buf, unsigned len, const char *label, u32 status)
52062306a36Sopenharmony_ci{
52162306a36Sopenharmony_ci	return scnprintf(buf, len, "%s%sstatus %04x%s%s%s%s%s%s%s%s%s%s",
52262306a36Sopenharmony_ci		label, label[0] ? " " : "", status,
52362306a36Sopenharmony_ci		(status & STS_ASS) ? " Async" : "",
52462306a36Sopenharmony_ci		(status & STS_PSS) ? " Periodic" : "",
52562306a36Sopenharmony_ci		(status & STS_RECL) ? " Recl" : "",
52662306a36Sopenharmony_ci		(status & STS_HALT) ? " Halt" : "",
52762306a36Sopenharmony_ci		(status & STS_IAA) ? " IAA" : "",
52862306a36Sopenharmony_ci		(status & STS_FATAL) ? " FATAL" : "",
52962306a36Sopenharmony_ci		(status & STS_FLR) ? " FLR" : "",
53062306a36Sopenharmony_ci		(status & STS_PCD) ? " PCD" : "",
53162306a36Sopenharmony_ci		(status & STS_ERR) ? " ERR" : "",
53262306a36Sopenharmony_ci		(status & STS_INT) ? " INT" : ""
53362306a36Sopenharmony_ci		);
53462306a36Sopenharmony_ci}
53562306a36Sopenharmony_ci
53662306a36Sopenharmony_cistatic int __attribute__((__unused__))
53762306a36Sopenharmony_cidbg_intr_buf(char *buf, unsigned len, const char *label, u32 enable)
53862306a36Sopenharmony_ci{
53962306a36Sopenharmony_ci	return scnprintf(buf, len, "%s%sintrenable %02x%s%s%s%s%s%s",
54062306a36Sopenharmony_ci		label, label[0] ? " " : "", enable,
54162306a36Sopenharmony_ci		(enable & STS_IAA) ? " IAA" : "",
54262306a36Sopenharmony_ci		(enable & STS_FATAL) ? " FATAL" : "",
54362306a36Sopenharmony_ci		(enable & STS_FLR) ? " FLR" : "",
54462306a36Sopenharmony_ci		(enable & STS_PCD) ? " PCD" : "",
54562306a36Sopenharmony_ci		(enable & STS_ERR) ? " ERR" : "",
54662306a36Sopenharmony_ci		(enable & STS_INT) ? " INT" : ""
54762306a36Sopenharmony_ci		);
54862306a36Sopenharmony_ci}
54962306a36Sopenharmony_ci
55062306a36Sopenharmony_cistatic const char *const fls_strings[] =
55162306a36Sopenharmony_ci    { "1024", "512", "256", "??" };
55262306a36Sopenharmony_ci
55362306a36Sopenharmony_cistatic int dbg_command_buf(char *buf, unsigned len,
55462306a36Sopenharmony_ci				const char *label, u32 command)
55562306a36Sopenharmony_ci{
55662306a36Sopenharmony_ci	return scnprintf(buf, len,
55762306a36Sopenharmony_ci		"%s%scommand %06x %s=%d ithresh=%d%s%s%s%s period=%s%s %s",
55862306a36Sopenharmony_ci		label, label[0] ? " " : "", command,
55962306a36Sopenharmony_ci		(command & CMD_PARK) ? "park" : "(park)",
56062306a36Sopenharmony_ci		CMD_PARK_CNT(command),
56162306a36Sopenharmony_ci		(command >> 16) & 0x3f,
56262306a36Sopenharmony_ci		(command & CMD_LRESET) ? " LReset" : "",
56362306a36Sopenharmony_ci		(command & CMD_IAAD) ? " IAAD" : "",
56462306a36Sopenharmony_ci		(command & CMD_ASE) ? " Async" : "",
56562306a36Sopenharmony_ci		(command & CMD_PSE) ? " Periodic" : "",
56662306a36Sopenharmony_ci		fls_strings[(command >> 2) & 0x3],
56762306a36Sopenharmony_ci		(command & CMD_RESET) ? " Reset" : "",
56862306a36Sopenharmony_ci		(command & CMD_RUN) ? "RUN" : "HALT"
56962306a36Sopenharmony_ci		);
57062306a36Sopenharmony_ci}
57162306a36Sopenharmony_ci
57262306a36Sopenharmony_cistatic int dbg_port_buf(char *buf, unsigned len, const char *label,
57362306a36Sopenharmony_ci				int port, u32 status)
57462306a36Sopenharmony_ci{
57562306a36Sopenharmony_ci	char	*sig;
57662306a36Sopenharmony_ci
57762306a36Sopenharmony_ci	/* signaling state */
57862306a36Sopenharmony_ci	switch (status & (3 << 10)) {
57962306a36Sopenharmony_ci	case 0 << 10:
58062306a36Sopenharmony_ci		sig = "se0";
58162306a36Sopenharmony_ci		break;
58262306a36Sopenharmony_ci	case 1 << 10:
58362306a36Sopenharmony_ci		sig = "k";	/* low speed */
58462306a36Sopenharmony_ci		break;
58562306a36Sopenharmony_ci	case 2 << 10:
58662306a36Sopenharmony_ci		sig = "j";
58762306a36Sopenharmony_ci		break;
58862306a36Sopenharmony_ci	default:
58962306a36Sopenharmony_ci		sig = "?";
59062306a36Sopenharmony_ci		break;
59162306a36Sopenharmony_ci	}
59262306a36Sopenharmony_ci
59362306a36Sopenharmony_ci	return scnprintf(buf, len,
59462306a36Sopenharmony_ci		"%s%sport %d status %06x%s%s sig=%s%s%s%s%s%s%s%s%s%s",
59562306a36Sopenharmony_ci		label, label[0] ? " " : "", port, status,
59662306a36Sopenharmony_ci		(status & PORT_POWER) ? " POWER" : "",
59762306a36Sopenharmony_ci		(status & PORT_OWNER) ? " OWNER" : "",
59862306a36Sopenharmony_ci		sig,
59962306a36Sopenharmony_ci		(status & PORT_RESET) ? " RESET" : "",
60062306a36Sopenharmony_ci		(status & PORT_SUSPEND) ? " SUSPEND" : "",
60162306a36Sopenharmony_ci		(status & PORT_RESUME) ? " RESUME" : "",
60262306a36Sopenharmony_ci		(status & PORT_OCC) ? " OCC" : "",
60362306a36Sopenharmony_ci		(status & PORT_OC) ? " OC" : "",
60462306a36Sopenharmony_ci		(status & PORT_PEC) ? " PEC" : "",
60562306a36Sopenharmony_ci		(status & PORT_PE) ? " PE" : "",
60662306a36Sopenharmony_ci		(status & PORT_CSC) ? " CSC" : "",
60762306a36Sopenharmony_ci		(status & PORT_CONNECT) ? " CONNECT" : ""
60862306a36Sopenharmony_ci	    );
60962306a36Sopenharmony_ci}
61062306a36Sopenharmony_ci
61162306a36Sopenharmony_ci#else
61262306a36Sopenharmony_ci
61362306a36Sopenharmony_cistatic inline int __attribute__((__unused__))
61462306a36Sopenharmony_cidbg_status_buf(char *buf, unsigned len, const char *label, u32 status)
61562306a36Sopenharmony_ci{ return 0; }
61662306a36Sopenharmony_ci
61762306a36Sopenharmony_cistatic inline int __attribute__((__unused__))
61862306a36Sopenharmony_cidbg_command_buf(char *buf, unsigned len, const char *label, u32 command)
61962306a36Sopenharmony_ci{ return 0; }
62062306a36Sopenharmony_ci
62162306a36Sopenharmony_cistatic inline int __attribute__((__unused__))
62262306a36Sopenharmony_cidbg_intr_buf(char *buf, unsigned len, const char *label, u32 enable)
62362306a36Sopenharmony_ci{ return 0; }
62462306a36Sopenharmony_ci
62562306a36Sopenharmony_cistatic inline int __attribute__((__unused__))
62662306a36Sopenharmony_cidbg_port_buf(char *buf, unsigned len, const char *label, int port, u32 status)
62762306a36Sopenharmony_ci{ return 0; }
62862306a36Sopenharmony_ci
62962306a36Sopenharmony_ci#endif /* DEBUG */
63062306a36Sopenharmony_ci
63162306a36Sopenharmony_ci/* functions have the "wrong" filename when they're output... */
63262306a36Sopenharmony_ci#define dbg_status(oxu, label, status) { \
63362306a36Sopenharmony_ci	char _buf[80]; \
63462306a36Sopenharmony_ci	dbg_status_buf(_buf, sizeof _buf, label, status); \
63562306a36Sopenharmony_ci	oxu_dbg(oxu, "%s\n", _buf); \
63662306a36Sopenharmony_ci}
63762306a36Sopenharmony_ci
63862306a36Sopenharmony_ci#define dbg_cmd(oxu, label, command) { \
63962306a36Sopenharmony_ci	char _buf[80]; \
64062306a36Sopenharmony_ci	dbg_command_buf(_buf, sizeof _buf, label, command); \
64162306a36Sopenharmony_ci	oxu_dbg(oxu, "%s\n", _buf); \
64262306a36Sopenharmony_ci}
64362306a36Sopenharmony_ci
64462306a36Sopenharmony_ci#define dbg_port(oxu, label, port, status) { \
64562306a36Sopenharmony_ci	char _buf[80]; \
64662306a36Sopenharmony_ci	dbg_port_buf(_buf, sizeof _buf, label, port, status); \
64762306a36Sopenharmony_ci	oxu_dbg(oxu, "%s\n", _buf); \
64862306a36Sopenharmony_ci}
64962306a36Sopenharmony_ci
65062306a36Sopenharmony_ci/*
65162306a36Sopenharmony_ci * Module parameters
65262306a36Sopenharmony_ci */
65362306a36Sopenharmony_ci
65462306a36Sopenharmony_ci/* Initial IRQ latency: faster than hw default */
65562306a36Sopenharmony_cistatic int log2_irq_thresh;			/* 0 to 6 */
65662306a36Sopenharmony_cimodule_param(log2_irq_thresh, int, S_IRUGO);
65762306a36Sopenharmony_ciMODULE_PARM_DESC(log2_irq_thresh, "log2 IRQ latency, 1-64 microframes");
65862306a36Sopenharmony_ci
65962306a36Sopenharmony_ci/* Initial park setting: slower than hw default */
66062306a36Sopenharmony_cistatic unsigned park;
66162306a36Sopenharmony_cimodule_param(park, uint, S_IRUGO);
66262306a36Sopenharmony_ciMODULE_PARM_DESC(park, "park setting; 1-3 back-to-back async packets");
66362306a36Sopenharmony_ci
66462306a36Sopenharmony_ci/* For flakey hardware, ignore overcurrent indicators */
66562306a36Sopenharmony_cistatic bool ignore_oc;
66662306a36Sopenharmony_cimodule_param(ignore_oc, bool, S_IRUGO);
66762306a36Sopenharmony_ciMODULE_PARM_DESC(ignore_oc, "ignore bogus hardware overcurrent indications");
66862306a36Sopenharmony_ci
66962306a36Sopenharmony_ci
67062306a36Sopenharmony_cistatic void ehci_work(struct oxu_hcd *oxu);
67162306a36Sopenharmony_cistatic int oxu_hub_control(struct usb_hcd *hcd,
67262306a36Sopenharmony_ci				u16 typeReq, u16 wValue, u16 wIndex,
67362306a36Sopenharmony_ci				char *buf, u16 wLength);
67462306a36Sopenharmony_ci
67562306a36Sopenharmony_ci/*
67662306a36Sopenharmony_ci * Local functions
67762306a36Sopenharmony_ci */
67862306a36Sopenharmony_ci
67962306a36Sopenharmony_ci/* Low level read/write registers functions */
68062306a36Sopenharmony_cistatic inline u32 oxu_readl(void __iomem *base, u32 reg)
68162306a36Sopenharmony_ci{
68262306a36Sopenharmony_ci	return readl(base + reg);
68362306a36Sopenharmony_ci}
68462306a36Sopenharmony_ci
68562306a36Sopenharmony_cistatic inline void oxu_writel(void __iomem *base, u32 reg, u32 val)
68662306a36Sopenharmony_ci{
68762306a36Sopenharmony_ci	writel(val, base + reg);
68862306a36Sopenharmony_ci}
68962306a36Sopenharmony_ci
69062306a36Sopenharmony_cistatic inline void timer_action_done(struct oxu_hcd *oxu,
69162306a36Sopenharmony_ci					enum ehci_timer_action action)
69262306a36Sopenharmony_ci{
69362306a36Sopenharmony_ci	clear_bit(action, &oxu->actions);
69462306a36Sopenharmony_ci}
69562306a36Sopenharmony_ci
69662306a36Sopenharmony_cistatic inline void timer_action(struct oxu_hcd *oxu,
69762306a36Sopenharmony_ci					enum ehci_timer_action action)
69862306a36Sopenharmony_ci{
69962306a36Sopenharmony_ci	if (!test_and_set_bit(action, &oxu->actions)) {
70062306a36Sopenharmony_ci		unsigned long t;
70162306a36Sopenharmony_ci
70262306a36Sopenharmony_ci		switch (action) {
70362306a36Sopenharmony_ci		case TIMER_IAA_WATCHDOG:
70462306a36Sopenharmony_ci			t = EHCI_IAA_JIFFIES;
70562306a36Sopenharmony_ci			break;
70662306a36Sopenharmony_ci		case TIMER_IO_WATCHDOG:
70762306a36Sopenharmony_ci			t = EHCI_IO_JIFFIES;
70862306a36Sopenharmony_ci			break;
70962306a36Sopenharmony_ci		case TIMER_ASYNC_OFF:
71062306a36Sopenharmony_ci			t = EHCI_ASYNC_JIFFIES;
71162306a36Sopenharmony_ci			break;
71262306a36Sopenharmony_ci		case TIMER_ASYNC_SHRINK:
71362306a36Sopenharmony_ci		default:
71462306a36Sopenharmony_ci			t = EHCI_SHRINK_JIFFIES;
71562306a36Sopenharmony_ci			break;
71662306a36Sopenharmony_ci		}
71762306a36Sopenharmony_ci		t += jiffies;
71862306a36Sopenharmony_ci		/* all timings except IAA watchdog can be overridden.
71962306a36Sopenharmony_ci		 * async queue SHRINK often precedes IAA.  while it's ready
72062306a36Sopenharmony_ci		 * to go OFF neither can matter, and afterwards the IO
72162306a36Sopenharmony_ci		 * watchdog stops unless there's still periodic traffic.
72262306a36Sopenharmony_ci		 */
72362306a36Sopenharmony_ci		if (action != TIMER_IAA_WATCHDOG
72462306a36Sopenharmony_ci				&& t > oxu->watchdog.expires
72562306a36Sopenharmony_ci				&& timer_pending(&oxu->watchdog))
72662306a36Sopenharmony_ci			return;
72762306a36Sopenharmony_ci		mod_timer(&oxu->watchdog, t);
72862306a36Sopenharmony_ci	}
72962306a36Sopenharmony_ci}
73062306a36Sopenharmony_ci
73162306a36Sopenharmony_ci/*
73262306a36Sopenharmony_ci * handshake - spin reading hc until handshake completes or fails
73362306a36Sopenharmony_ci * @ptr: address of hc register to be read
73462306a36Sopenharmony_ci * @mask: bits to look at in result of read
73562306a36Sopenharmony_ci * @done: value of those bits when handshake succeeds
73662306a36Sopenharmony_ci * @usec: timeout in microseconds
73762306a36Sopenharmony_ci *
73862306a36Sopenharmony_ci * Returns negative errno, or zero on success
73962306a36Sopenharmony_ci *
74062306a36Sopenharmony_ci * Success happens when the "mask" bits have the specified value (hardware
74162306a36Sopenharmony_ci * handshake done).  There are two failure modes:  "usec" have passed (major
74262306a36Sopenharmony_ci * hardware flakeout), or the register reads as all-ones (hardware removed).
74362306a36Sopenharmony_ci *
74462306a36Sopenharmony_ci * That last failure should_only happen in cases like physical cardbus eject
74562306a36Sopenharmony_ci * before driver shutdown. But it also seems to be caused by bugs in cardbus
74662306a36Sopenharmony_ci * bridge shutdown:  shutting down the bridge before the devices using it.
74762306a36Sopenharmony_ci */
74862306a36Sopenharmony_cistatic int handshake(struct oxu_hcd *oxu, void __iomem *ptr,
74962306a36Sopenharmony_ci					u32 mask, u32 done, int usec)
75062306a36Sopenharmony_ci{
75162306a36Sopenharmony_ci	u32 result;
75262306a36Sopenharmony_ci	int ret;
75362306a36Sopenharmony_ci
75462306a36Sopenharmony_ci	ret = readl_poll_timeout_atomic(ptr, result,
75562306a36Sopenharmony_ci					((result & mask) == done ||
75662306a36Sopenharmony_ci					 result == U32_MAX),
75762306a36Sopenharmony_ci					1, usec);
75862306a36Sopenharmony_ci	if (result == U32_MAX)		/* card removed */
75962306a36Sopenharmony_ci		return -ENODEV;
76062306a36Sopenharmony_ci
76162306a36Sopenharmony_ci	return ret;
76262306a36Sopenharmony_ci}
76362306a36Sopenharmony_ci
76462306a36Sopenharmony_ci/* Force HC to halt state from unknown (EHCI spec section 2.3) */
76562306a36Sopenharmony_cistatic int ehci_halt(struct oxu_hcd *oxu)
76662306a36Sopenharmony_ci{
76762306a36Sopenharmony_ci	u32	temp = readl(&oxu->regs->status);
76862306a36Sopenharmony_ci
76962306a36Sopenharmony_ci	/* disable any irqs left enabled by previous code */
77062306a36Sopenharmony_ci	writel(0, &oxu->regs->intr_enable);
77162306a36Sopenharmony_ci
77262306a36Sopenharmony_ci	if ((temp & STS_HALT) != 0)
77362306a36Sopenharmony_ci		return 0;
77462306a36Sopenharmony_ci
77562306a36Sopenharmony_ci	temp = readl(&oxu->regs->command);
77662306a36Sopenharmony_ci	temp &= ~CMD_RUN;
77762306a36Sopenharmony_ci	writel(temp, &oxu->regs->command);
77862306a36Sopenharmony_ci	return handshake(oxu, &oxu->regs->status,
77962306a36Sopenharmony_ci			  STS_HALT, STS_HALT, 16 * 125);
78062306a36Sopenharmony_ci}
78162306a36Sopenharmony_ci
78262306a36Sopenharmony_ci/* Put TDI/ARC silicon into EHCI mode */
78362306a36Sopenharmony_cistatic void tdi_reset(struct oxu_hcd *oxu)
78462306a36Sopenharmony_ci{
78562306a36Sopenharmony_ci	u32 __iomem *reg_ptr;
78662306a36Sopenharmony_ci	u32 tmp;
78762306a36Sopenharmony_ci
78862306a36Sopenharmony_ci	reg_ptr = (u32 __iomem *)(((u8 __iomem *)oxu->regs) + 0x68);
78962306a36Sopenharmony_ci	tmp = readl(reg_ptr);
79062306a36Sopenharmony_ci	tmp |= 0x3;
79162306a36Sopenharmony_ci	writel(tmp, reg_ptr);
79262306a36Sopenharmony_ci}
79362306a36Sopenharmony_ci
79462306a36Sopenharmony_ci/* Reset a non-running (STS_HALT == 1) controller */
79562306a36Sopenharmony_cistatic int ehci_reset(struct oxu_hcd *oxu)
79662306a36Sopenharmony_ci{
79762306a36Sopenharmony_ci	int	retval;
79862306a36Sopenharmony_ci	u32	command = readl(&oxu->regs->command);
79962306a36Sopenharmony_ci
80062306a36Sopenharmony_ci	command |= CMD_RESET;
80162306a36Sopenharmony_ci	dbg_cmd(oxu, "reset", command);
80262306a36Sopenharmony_ci	writel(command, &oxu->regs->command);
80362306a36Sopenharmony_ci	oxu_to_hcd(oxu)->state = HC_STATE_HALT;
80462306a36Sopenharmony_ci	oxu->next_statechange = jiffies;
80562306a36Sopenharmony_ci	retval = handshake(oxu, &oxu->regs->command,
80662306a36Sopenharmony_ci			    CMD_RESET, 0, 250 * 1000);
80762306a36Sopenharmony_ci
80862306a36Sopenharmony_ci	if (retval)
80962306a36Sopenharmony_ci		return retval;
81062306a36Sopenharmony_ci
81162306a36Sopenharmony_ci	tdi_reset(oxu);
81262306a36Sopenharmony_ci
81362306a36Sopenharmony_ci	return retval;
81462306a36Sopenharmony_ci}
81562306a36Sopenharmony_ci
81662306a36Sopenharmony_ci/* Idle the controller (from running) */
81762306a36Sopenharmony_cistatic void ehci_quiesce(struct oxu_hcd *oxu)
81862306a36Sopenharmony_ci{
81962306a36Sopenharmony_ci	u32	temp;
82062306a36Sopenharmony_ci
82162306a36Sopenharmony_ci#ifdef DEBUG
82262306a36Sopenharmony_ci	BUG_ON(!HC_IS_RUNNING(oxu_to_hcd(oxu)->state));
82362306a36Sopenharmony_ci#endif
82462306a36Sopenharmony_ci
82562306a36Sopenharmony_ci	/* wait for any schedule enables/disables to take effect */
82662306a36Sopenharmony_ci	temp = readl(&oxu->regs->command) << 10;
82762306a36Sopenharmony_ci	temp &= STS_ASS | STS_PSS;
82862306a36Sopenharmony_ci	if (handshake(oxu, &oxu->regs->status, STS_ASS | STS_PSS,
82962306a36Sopenharmony_ci				temp, 16 * 125) != 0) {
83062306a36Sopenharmony_ci		oxu_to_hcd(oxu)->state = HC_STATE_HALT;
83162306a36Sopenharmony_ci		return;
83262306a36Sopenharmony_ci	}
83362306a36Sopenharmony_ci
83462306a36Sopenharmony_ci	/* then disable anything that's still active */
83562306a36Sopenharmony_ci	temp = readl(&oxu->regs->command);
83662306a36Sopenharmony_ci	temp &= ~(CMD_ASE | CMD_IAAD | CMD_PSE);
83762306a36Sopenharmony_ci	writel(temp, &oxu->regs->command);
83862306a36Sopenharmony_ci
83962306a36Sopenharmony_ci	/* hardware can take 16 microframes to turn off ... */
84062306a36Sopenharmony_ci	if (handshake(oxu, &oxu->regs->status, STS_ASS | STS_PSS,
84162306a36Sopenharmony_ci				0, 16 * 125) != 0) {
84262306a36Sopenharmony_ci		oxu_to_hcd(oxu)->state = HC_STATE_HALT;
84362306a36Sopenharmony_ci		return;
84462306a36Sopenharmony_ci	}
84562306a36Sopenharmony_ci}
84662306a36Sopenharmony_ci
84762306a36Sopenharmony_cistatic int check_reset_complete(struct oxu_hcd *oxu, int index,
84862306a36Sopenharmony_ci				u32 __iomem *status_reg, int port_status)
84962306a36Sopenharmony_ci{
85062306a36Sopenharmony_ci	if (!(port_status & PORT_CONNECT)) {
85162306a36Sopenharmony_ci		oxu->reset_done[index] = 0;
85262306a36Sopenharmony_ci		return port_status;
85362306a36Sopenharmony_ci	}
85462306a36Sopenharmony_ci
85562306a36Sopenharmony_ci	/* if reset finished and it's still not enabled -- handoff */
85662306a36Sopenharmony_ci	if (!(port_status & PORT_PE)) {
85762306a36Sopenharmony_ci		oxu_dbg(oxu, "Failed to enable port %d on root hub TT\n",
85862306a36Sopenharmony_ci				index+1);
85962306a36Sopenharmony_ci		return port_status;
86062306a36Sopenharmony_ci	} else
86162306a36Sopenharmony_ci		oxu_dbg(oxu, "port %d high speed\n", index + 1);
86262306a36Sopenharmony_ci
86362306a36Sopenharmony_ci	return port_status;
86462306a36Sopenharmony_ci}
86562306a36Sopenharmony_ci
86662306a36Sopenharmony_cistatic void ehci_hub_descriptor(struct oxu_hcd *oxu,
86762306a36Sopenharmony_ci				struct usb_hub_descriptor *desc)
86862306a36Sopenharmony_ci{
86962306a36Sopenharmony_ci	int ports = HCS_N_PORTS(oxu->hcs_params);
87062306a36Sopenharmony_ci	u16 temp;
87162306a36Sopenharmony_ci
87262306a36Sopenharmony_ci	desc->bDescriptorType = USB_DT_HUB;
87362306a36Sopenharmony_ci	desc->bPwrOn2PwrGood = 10;	/* oxu 1.0, 2.3.9 says 20ms max */
87462306a36Sopenharmony_ci	desc->bHubContrCurrent = 0;
87562306a36Sopenharmony_ci
87662306a36Sopenharmony_ci	desc->bNbrPorts = ports;
87762306a36Sopenharmony_ci	temp = 1 + (ports / 8);
87862306a36Sopenharmony_ci	desc->bDescLength = 7 + 2 * temp;
87962306a36Sopenharmony_ci
88062306a36Sopenharmony_ci	/* ports removable, and usb 1.0 legacy PortPwrCtrlMask */
88162306a36Sopenharmony_ci	memset(&desc->u.hs.DeviceRemovable[0], 0, temp);
88262306a36Sopenharmony_ci	memset(&desc->u.hs.DeviceRemovable[temp], 0xff, temp);
88362306a36Sopenharmony_ci
88462306a36Sopenharmony_ci	temp = HUB_CHAR_INDV_PORT_OCPM;	/* per-port overcurrent reporting */
88562306a36Sopenharmony_ci	if (HCS_PPC(oxu->hcs_params))
88662306a36Sopenharmony_ci		temp |= HUB_CHAR_INDV_PORT_LPSM; /* per-port power control */
88762306a36Sopenharmony_ci	else
88862306a36Sopenharmony_ci		temp |= HUB_CHAR_NO_LPSM; /* no power switching */
88962306a36Sopenharmony_ci	desc->wHubCharacteristics = (__force __u16)cpu_to_le16(temp);
89062306a36Sopenharmony_ci}
89162306a36Sopenharmony_ci
89262306a36Sopenharmony_ci
89362306a36Sopenharmony_ci/* Allocate an OXU210HP on-chip memory data buffer
89462306a36Sopenharmony_ci *
89562306a36Sopenharmony_ci * An on-chip memory data buffer is required for each OXU210HP USB transfer.
89662306a36Sopenharmony_ci * Each transfer descriptor has one or more on-chip memory data buffers.
89762306a36Sopenharmony_ci *
89862306a36Sopenharmony_ci * Data buffers are allocated from a fix sized pool of data blocks.
89962306a36Sopenharmony_ci * To minimise fragmentation and give reasonable memory utlisation,
90062306a36Sopenharmony_ci * data buffers are allocated with sizes the power of 2 multiples of
90162306a36Sopenharmony_ci * the block size, starting on an address a multiple of the allocated size.
90262306a36Sopenharmony_ci *
90362306a36Sopenharmony_ci * FIXME: callers of this function require a buffer to be allocated for
90462306a36Sopenharmony_ci * len=0. This is a waste of on-chip memory and should be fix. Then this
90562306a36Sopenharmony_ci * function should be changed to not allocate a buffer for len=0.
90662306a36Sopenharmony_ci */
90762306a36Sopenharmony_cistatic int oxu_buf_alloc(struct oxu_hcd *oxu, struct ehci_qtd *qtd, int len)
90862306a36Sopenharmony_ci{
90962306a36Sopenharmony_ci	int n_blocks;	/* minium blocks needed to hold len */
91062306a36Sopenharmony_ci	int a_blocks;	/* blocks allocated */
91162306a36Sopenharmony_ci	int i, j;
91262306a36Sopenharmony_ci
91362306a36Sopenharmony_ci	/* Don't allocte bigger than supported */
91462306a36Sopenharmony_ci	if (len > BUFFER_SIZE * BUFFER_NUM) {
91562306a36Sopenharmony_ci		oxu_err(oxu, "buffer too big (%d)\n", len);
91662306a36Sopenharmony_ci		return -ENOMEM;
91762306a36Sopenharmony_ci	}
91862306a36Sopenharmony_ci
91962306a36Sopenharmony_ci	spin_lock(&oxu->mem_lock);
92062306a36Sopenharmony_ci
92162306a36Sopenharmony_ci	/* Number of blocks needed to hold len */
92262306a36Sopenharmony_ci	n_blocks = (len + BUFFER_SIZE - 1) / BUFFER_SIZE;
92362306a36Sopenharmony_ci
92462306a36Sopenharmony_ci	/* Round the number of blocks up to the power of 2 */
92562306a36Sopenharmony_ci	for (a_blocks = 1; a_blocks < n_blocks; a_blocks <<= 1)
92662306a36Sopenharmony_ci		;
92762306a36Sopenharmony_ci
92862306a36Sopenharmony_ci	/* Find a suitable available data buffer */
92962306a36Sopenharmony_ci	for (i = 0; i < BUFFER_NUM;
93062306a36Sopenharmony_ci			i += max(a_blocks, (int)oxu->db_used[i])) {
93162306a36Sopenharmony_ci
93262306a36Sopenharmony_ci		/* Check all the required blocks are available */
93362306a36Sopenharmony_ci		for (j = 0; j < a_blocks; j++)
93462306a36Sopenharmony_ci			if (oxu->db_used[i + j])
93562306a36Sopenharmony_ci				break;
93662306a36Sopenharmony_ci
93762306a36Sopenharmony_ci		if (j != a_blocks)
93862306a36Sopenharmony_ci			continue;
93962306a36Sopenharmony_ci
94062306a36Sopenharmony_ci		/* Allocate blocks found! */
94162306a36Sopenharmony_ci		qtd->buffer = (void *) &oxu->mem->db_pool[i];
94262306a36Sopenharmony_ci		qtd->buffer_dma = virt_to_phys(qtd->buffer);
94362306a36Sopenharmony_ci
94462306a36Sopenharmony_ci		qtd->qtd_buffer_len = BUFFER_SIZE * a_blocks;
94562306a36Sopenharmony_ci		oxu->db_used[i] = a_blocks;
94662306a36Sopenharmony_ci
94762306a36Sopenharmony_ci		spin_unlock(&oxu->mem_lock);
94862306a36Sopenharmony_ci
94962306a36Sopenharmony_ci		return 0;
95062306a36Sopenharmony_ci	}
95162306a36Sopenharmony_ci
95262306a36Sopenharmony_ci	/* Failed */
95362306a36Sopenharmony_ci
95462306a36Sopenharmony_ci	spin_unlock(&oxu->mem_lock);
95562306a36Sopenharmony_ci
95662306a36Sopenharmony_ci	return -ENOMEM;
95762306a36Sopenharmony_ci}
95862306a36Sopenharmony_ci
95962306a36Sopenharmony_cistatic void oxu_buf_free(struct oxu_hcd *oxu, struct ehci_qtd *qtd)
96062306a36Sopenharmony_ci{
96162306a36Sopenharmony_ci	int index;
96262306a36Sopenharmony_ci
96362306a36Sopenharmony_ci	spin_lock(&oxu->mem_lock);
96462306a36Sopenharmony_ci
96562306a36Sopenharmony_ci	index = (qtd->buffer - (void *) &oxu->mem->db_pool[0])
96662306a36Sopenharmony_ci							 / BUFFER_SIZE;
96762306a36Sopenharmony_ci	oxu->db_used[index] = 0;
96862306a36Sopenharmony_ci	qtd->qtd_buffer_len = 0;
96962306a36Sopenharmony_ci	qtd->buffer_dma = 0;
97062306a36Sopenharmony_ci	qtd->buffer = NULL;
97162306a36Sopenharmony_ci
97262306a36Sopenharmony_ci	spin_unlock(&oxu->mem_lock);
97362306a36Sopenharmony_ci}
97462306a36Sopenharmony_ci
97562306a36Sopenharmony_cistatic inline void ehci_qtd_init(struct ehci_qtd *qtd, dma_addr_t dma)
97662306a36Sopenharmony_ci{
97762306a36Sopenharmony_ci	memset(qtd, 0, sizeof *qtd);
97862306a36Sopenharmony_ci	qtd->qtd_dma = dma;
97962306a36Sopenharmony_ci	qtd->hw_token = cpu_to_le32(QTD_STS_HALT);
98062306a36Sopenharmony_ci	qtd->hw_next = EHCI_LIST_END;
98162306a36Sopenharmony_ci	qtd->hw_alt_next = EHCI_LIST_END;
98262306a36Sopenharmony_ci	INIT_LIST_HEAD(&qtd->qtd_list);
98362306a36Sopenharmony_ci}
98462306a36Sopenharmony_ci
98562306a36Sopenharmony_cistatic inline void oxu_qtd_free(struct oxu_hcd *oxu, struct ehci_qtd *qtd)
98662306a36Sopenharmony_ci{
98762306a36Sopenharmony_ci	int index;
98862306a36Sopenharmony_ci
98962306a36Sopenharmony_ci	if (qtd->buffer)
99062306a36Sopenharmony_ci		oxu_buf_free(oxu, qtd);
99162306a36Sopenharmony_ci
99262306a36Sopenharmony_ci	spin_lock(&oxu->mem_lock);
99362306a36Sopenharmony_ci
99462306a36Sopenharmony_ci	index = qtd - &oxu->mem->qtd_pool[0];
99562306a36Sopenharmony_ci	oxu->qtd_used[index] = 0;
99662306a36Sopenharmony_ci
99762306a36Sopenharmony_ci	spin_unlock(&oxu->mem_lock);
99862306a36Sopenharmony_ci}
99962306a36Sopenharmony_ci
100062306a36Sopenharmony_cistatic struct ehci_qtd *ehci_qtd_alloc(struct oxu_hcd *oxu)
100162306a36Sopenharmony_ci{
100262306a36Sopenharmony_ci	int i;
100362306a36Sopenharmony_ci	struct ehci_qtd *qtd = NULL;
100462306a36Sopenharmony_ci
100562306a36Sopenharmony_ci	spin_lock(&oxu->mem_lock);
100662306a36Sopenharmony_ci
100762306a36Sopenharmony_ci	for (i = 0; i < QTD_NUM; i++)
100862306a36Sopenharmony_ci		if (!oxu->qtd_used[i])
100962306a36Sopenharmony_ci			break;
101062306a36Sopenharmony_ci
101162306a36Sopenharmony_ci	if (i < QTD_NUM) {
101262306a36Sopenharmony_ci		qtd = (struct ehci_qtd *) &oxu->mem->qtd_pool[i];
101362306a36Sopenharmony_ci		memset(qtd, 0, sizeof *qtd);
101462306a36Sopenharmony_ci
101562306a36Sopenharmony_ci		qtd->hw_token = cpu_to_le32(QTD_STS_HALT);
101662306a36Sopenharmony_ci		qtd->hw_next = EHCI_LIST_END;
101762306a36Sopenharmony_ci		qtd->hw_alt_next = EHCI_LIST_END;
101862306a36Sopenharmony_ci		INIT_LIST_HEAD(&qtd->qtd_list);
101962306a36Sopenharmony_ci
102062306a36Sopenharmony_ci		qtd->qtd_dma = virt_to_phys(qtd);
102162306a36Sopenharmony_ci
102262306a36Sopenharmony_ci		oxu->qtd_used[i] = 1;
102362306a36Sopenharmony_ci	}
102462306a36Sopenharmony_ci
102562306a36Sopenharmony_ci	spin_unlock(&oxu->mem_lock);
102662306a36Sopenharmony_ci
102762306a36Sopenharmony_ci	return qtd;
102862306a36Sopenharmony_ci}
102962306a36Sopenharmony_ci
103062306a36Sopenharmony_cistatic void oxu_qh_free(struct oxu_hcd *oxu, struct ehci_qh *qh)
103162306a36Sopenharmony_ci{
103262306a36Sopenharmony_ci	int index;
103362306a36Sopenharmony_ci
103462306a36Sopenharmony_ci	spin_lock(&oxu->mem_lock);
103562306a36Sopenharmony_ci
103662306a36Sopenharmony_ci	index = qh - &oxu->mem->qh_pool[0];
103762306a36Sopenharmony_ci	oxu->qh_used[index] = 0;
103862306a36Sopenharmony_ci
103962306a36Sopenharmony_ci	spin_unlock(&oxu->mem_lock);
104062306a36Sopenharmony_ci}
104162306a36Sopenharmony_ci
104262306a36Sopenharmony_cistatic void qh_destroy(struct kref *kref)
104362306a36Sopenharmony_ci{
104462306a36Sopenharmony_ci	struct ehci_qh *qh = container_of(kref, struct ehci_qh, kref);
104562306a36Sopenharmony_ci	struct oxu_hcd *oxu = qh->oxu;
104662306a36Sopenharmony_ci
104762306a36Sopenharmony_ci	/* clean qtds first, and know this is not linked */
104862306a36Sopenharmony_ci	if (!list_empty(&qh->qtd_list) || qh->qh_next.ptr) {
104962306a36Sopenharmony_ci		oxu_dbg(oxu, "unused qh not empty!\n");
105062306a36Sopenharmony_ci		BUG();
105162306a36Sopenharmony_ci	}
105262306a36Sopenharmony_ci	if (qh->dummy)
105362306a36Sopenharmony_ci		oxu_qtd_free(oxu, qh->dummy);
105462306a36Sopenharmony_ci	oxu_qh_free(oxu, qh);
105562306a36Sopenharmony_ci}
105662306a36Sopenharmony_ci
105762306a36Sopenharmony_cistatic struct ehci_qh *oxu_qh_alloc(struct oxu_hcd *oxu)
105862306a36Sopenharmony_ci{
105962306a36Sopenharmony_ci	int i;
106062306a36Sopenharmony_ci	struct ehci_qh *qh = NULL;
106162306a36Sopenharmony_ci
106262306a36Sopenharmony_ci	spin_lock(&oxu->mem_lock);
106362306a36Sopenharmony_ci
106462306a36Sopenharmony_ci	for (i = 0; i < QHEAD_NUM; i++)
106562306a36Sopenharmony_ci		if (!oxu->qh_used[i])
106662306a36Sopenharmony_ci			break;
106762306a36Sopenharmony_ci
106862306a36Sopenharmony_ci	if (i < QHEAD_NUM) {
106962306a36Sopenharmony_ci		qh = (struct ehci_qh *) &oxu->mem->qh_pool[i];
107062306a36Sopenharmony_ci		memset(qh, 0, sizeof *qh);
107162306a36Sopenharmony_ci
107262306a36Sopenharmony_ci		kref_init(&qh->kref);
107362306a36Sopenharmony_ci		qh->oxu = oxu;
107462306a36Sopenharmony_ci		qh->qh_dma = virt_to_phys(qh);
107562306a36Sopenharmony_ci		INIT_LIST_HEAD(&qh->qtd_list);
107662306a36Sopenharmony_ci
107762306a36Sopenharmony_ci		/* dummy td enables safe urb queuing */
107862306a36Sopenharmony_ci		qh->dummy = ehci_qtd_alloc(oxu);
107962306a36Sopenharmony_ci		if (qh->dummy == NULL) {
108062306a36Sopenharmony_ci			oxu_dbg(oxu, "no dummy td\n");
108162306a36Sopenharmony_ci			oxu->qh_used[i] = 0;
108262306a36Sopenharmony_ci			qh = NULL;
108362306a36Sopenharmony_ci			goto unlock;
108462306a36Sopenharmony_ci		}
108562306a36Sopenharmony_ci
108662306a36Sopenharmony_ci		oxu->qh_used[i] = 1;
108762306a36Sopenharmony_ci	}
108862306a36Sopenharmony_ciunlock:
108962306a36Sopenharmony_ci	spin_unlock(&oxu->mem_lock);
109062306a36Sopenharmony_ci
109162306a36Sopenharmony_ci	return qh;
109262306a36Sopenharmony_ci}
109362306a36Sopenharmony_ci
109462306a36Sopenharmony_ci/* to share a qh (cpu threads, or hc) */
109562306a36Sopenharmony_cistatic inline struct ehci_qh *qh_get(struct ehci_qh *qh)
109662306a36Sopenharmony_ci{
109762306a36Sopenharmony_ci	kref_get(&qh->kref);
109862306a36Sopenharmony_ci	return qh;
109962306a36Sopenharmony_ci}
110062306a36Sopenharmony_ci
110162306a36Sopenharmony_cistatic inline void qh_put(struct ehci_qh *qh)
110262306a36Sopenharmony_ci{
110362306a36Sopenharmony_ci	kref_put(&qh->kref, qh_destroy);
110462306a36Sopenharmony_ci}
110562306a36Sopenharmony_ci
110662306a36Sopenharmony_cistatic void oxu_murb_free(struct oxu_hcd *oxu, struct oxu_murb *murb)
110762306a36Sopenharmony_ci{
110862306a36Sopenharmony_ci	int index;
110962306a36Sopenharmony_ci
111062306a36Sopenharmony_ci	spin_lock(&oxu->mem_lock);
111162306a36Sopenharmony_ci
111262306a36Sopenharmony_ci	index = murb - &oxu->murb_pool[0];
111362306a36Sopenharmony_ci	oxu->murb_used[index] = 0;
111462306a36Sopenharmony_ci
111562306a36Sopenharmony_ci	spin_unlock(&oxu->mem_lock);
111662306a36Sopenharmony_ci}
111762306a36Sopenharmony_ci
111862306a36Sopenharmony_cistatic struct oxu_murb *oxu_murb_alloc(struct oxu_hcd *oxu)
111962306a36Sopenharmony_ci
112062306a36Sopenharmony_ci{
112162306a36Sopenharmony_ci	int i;
112262306a36Sopenharmony_ci	struct oxu_murb *murb = NULL;
112362306a36Sopenharmony_ci
112462306a36Sopenharmony_ci	spin_lock(&oxu->mem_lock);
112562306a36Sopenharmony_ci
112662306a36Sopenharmony_ci	for (i = 0; i < MURB_NUM; i++)
112762306a36Sopenharmony_ci		if (!oxu->murb_used[i])
112862306a36Sopenharmony_ci			break;
112962306a36Sopenharmony_ci
113062306a36Sopenharmony_ci	if (i < MURB_NUM) {
113162306a36Sopenharmony_ci		murb = &(oxu->murb_pool)[i];
113262306a36Sopenharmony_ci
113362306a36Sopenharmony_ci		oxu->murb_used[i] = 1;
113462306a36Sopenharmony_ci	}
113562306a36Sopenharmony_ci
113662306a36Sopenharmony_ci	spin_unlock(&oxu->mem_lock);
113762306a36Sopenharmony_ci
113862306a36Sopenharmony_ci	return murb;
113962306a36Sopenharmony_ci}
114062306a36Sopenharmony_ci
114162306a36Sopenharmony_ci/* The queue heads and transfer descriptors are managed from pools tied
114262306a36Sopenharmony_ci * to each of the "per device" structures.
114362306a36Sopenharmony_ci * This is the initialisation and cleanup code.
114462306a36Sopenharmony_ci */
114562306a36Sopenharmony_cistatic void ehci_mem_cleanup(struct oxu_hcd *oxu)
114662306a36Sopenharmony_ci{
114762306a36Sopenharmony_ci	kfree(oxu->murb_pool);
114862306a36Sopenharmony_ci	oxu->murb_pool = NULL;
114962306a36Sopenharmony_ci
115062306a36Sopenharmony_ci	if (oxu->async)
115162306a36Sopenharmony_ci		qh_put(oxu->async);
115262306a36Sopenharmony_ci	oxu->async = NULL;
115362306a36Sopenharmony_ci
115462306a36Sopenharmony_ci	del_timer(&oxu->urb_timer);
115562306a36Sopenharmony_ci
115662306a36Sopenharmony_ci	oxu->periodic = NULL;
115762306a36Sopenharmony_ci
115862306a36Sopenharmony_ci	/* shadow periodic table */
115962306a36Sopenharmony_ci	kfree(oxu->pshadow);
116062306a36Sopenharmony_ci	oxu->pshadow = NULL;
116162306a36Sopenharmony_ci}
116262306a36Sopenharmony_ci
116362306a36Sopenharmony_ci/* Remember to add cleanup code (above) if you add anything here.
116462306a36Sopenharmony_ci */
116562306a36Sopenharmony_cistatic int ehci_mem_init(struct oxu_hcd *oxu, gfp_t flags)
116662306a36Sopenharmony_ci{
116762306a36Sopenharmony_ci	int i;
116862306a36Sopenharmony_ci
116962306a36Sopenharmony_ci	for (i = 0; i < oxu->periodic_size; i++)
117062306a36Sopenharmony_ci		oxu->mem->frame_list[i] = EHCI_LIST_END;
117162306a36Sopenharmony_ci	for (i = 0; i < QHEAD_NUM; i++)
117262306a36Sopenharmony_ci		oxu->qh_used[i] = 0;
117362306a36Sopenharmony_ci	for (i = 0; i < QTD_NUM; i++)
117462306a36Sopenharmony_ci		oxu->qtd_used[i] = 0;
117562306a36Sopenharmony_ci
117662306a36Sopenharmony_ci	oxu->murb_pool = kcalloc(MURB_NUM, sizeof(struct oxu_murb), flags);
117762306a36Sopenharmony_ci	if (!oxu->murb_pool)
117862306a36Sopenharmony_ci		goto fail;
117962306a36Sopenharmony_ci
118062306a36Sopenharmony_ci	for (i = 0; i < MURB_NUM; i++)
118162306a36Sopenharmony_ci		oxu->murb_used[i] = 0;
118262306a36Sopenharmony_ci
118362306a36Sopenharmony_ci	oxu->async = oxu_qh_alloc(oxu);
118462306a36Sopenharmony_ci	if (!oxu->async)
118562306a36Sopenharmony_ci		goto fail;
118662306a36Sopenharmony_ci
118762306a36Sopenharmony_ci	oxu->periodic = (__le32 *) &oxu->mem->frame_list;
118862306a36Sopenharmony_ci	oxu->periodic_dma = virt_to_phys(oxu->periodic);
118962306a36Sopenharmony_ci
119062306a36Sopenharmony_ci	for (i = 0; i < oxu->periodic_size; i++)
119162306a36Sopenharmony_ci		oxu->periodic[i] = EHCI_LIST_END;
119262306a36Sopenharmony_ci
119362306a36Sopenharmony_ci	/* software shadow of hardware table */
119462306a36Sopenharmony_ci	oxu->pshadow = kcalloc(oxu->periodic_size, sizeof(void *), flags);
119562306a36Sopenharmony_ci	if (oxu->pshadow != NULL)
119662306a36Sopenharmony_ci		return 0;
119762306a36Sopenharmony_ci
119862306a36Sopenharmony_cifail:
119962306a36Sopenharmony_ci	oxu_dbg(oxu, "couldn't init memory\n");
120062306a36Sopenharmony_ci	ehci_mem_cleanup(oxu);
120162306a36Sopenharmony_ci	return -ENOMEM;
120262306a36Sopenharmony_ci}
120362306a36Sopenharmony_ci
120462306a36Sopenharmony_ci/* Fill a qtd, returning how much of the buffer we were able to queue up.
120562306a36Sopenharmony_ci */
120662306a36Sopenharmony_cistatic int qtd_fill(struct ehci_qtd *qtd, dma_addr_t buf, size_t len,
120762306a36Sopenharmony_ci				int token, int maxpacket)
120862306a36Sopenharmony_ci{
120962306a36Sopenharmony_ci	int i, count;
121062306a36Sopenharmony_ci	u64 addr = buf;
121162306a36Sopenharmony_ci
121262306a36Sopenharmony_ci	/* one buffer entry per 4K ... first might be short or unaligned */
121362306a36Sopenharmony_ci	qtd->hw_buf[0] = cpu_to_le32((u32)addr);
121462306a36Sopenharmony_ci	qtd->hw_buf_hi[0] = cpu_to_le32((u32)(addr >> 32));
121562306a36Sopenharmony_ci	count = 0x1000 - (buf & 0x0fff);	/* rest of that page */
121662306a36Sopenharmony_ci	if (likely(len < count))		/* ... iff needed */
121762306a36Sopenharmony_ci		count = len;
121862306a36Sopenharmony_ci	else {
121962306a36Sopenharmony_ci		buf +=  0x1000;
122062306a36Sopenharmony_ci		buf &= ~0x0fff;
122162306a36Sopenharmony_ci
122262306a36Sopenharmony_ci		/* per-qtd limit: from 16K to 20K (best alignment) */
122362306a36Sopenharmony_ci		for (i = 1; count < len && i < 5; i++) {
122462306a36Sopenharmony_ci			addr = buf;
122562306a36Sopenharmony_ci			qtd->hw_buf[i] = cpu_to_le32((u32)addr);
122662306a36Sopenharmony_ci			qtd->hw_buf_hi[i] = cpu_to_le32((u32)(addr >> 32));
122762306a36Sopenharmony_ci			buf += 0x1000;
122862306a36Sopenharmony_ci			if ((count + 0x1000) < len)
122962306a36Sopenharmony_ci				count += 0x1000;
123062306a36Sopenharmony_ci			else
123162306a36Sopenharmony_ci				count = len;
123262306a36Sopenharmony_ci		}
123362306a36Sopenharmony_ci
123462306a36Sopenharmony_ci		/* short packets may only terminate transfers */
123562306a36Sopenharmony_ci		if (count != len)
123662306a36Sopenharmony_ci			count -= (count % maxpacket);
123762306a36Sopenharmony_ci	}
123862306a36Sopenharmony_ci	qtd->hw_token = cpu_to_le32((count << 16) | token);
123962306a36Sopenharmony_ci	qtd->length = count;
124062306a36Sopenharmony_ci
124162306a36Sopenharmony_ci	return count;
124262306a36Sopenharmony_ci}
124362306a36Sopenharmony_ci
124462306a36Sopenharmony_cistatic inline void qh_update(struct oxu_hcd *oxu,
124562306a36Sopenharmony_ci				struct ehci_qh *qh, struct ehci_qtd *qtd)
124662306a36Sopenharmony_ci{
124762306a36Sopenharmony_ci	/* writes to an active overlay are unsafe */
124862306a36Sopenharmony_ci	BUG_ON(qh->qh_state != QH_STATE_IDLE);
124962306a36Sopenharmony_ci
125062306a36Sopenharmony_ci	qh->hw_qtd_next = QTD_NEXT(qtd->qtd_dma);
125162306a36Sopenharmony_ci	qh->hw_alt_next = EHCI_LIST_END;
125262306a36Sopenharmony_ci
125362306a36Sopenharmony_ci	/* Except for control endpoints, we make hardware maintain data
125462306a36Sopenharmony_ci	 * toggle (like OHCI) ... here (re)initialize the toggle in the QH,
125562306a36Sopenharmony_ci	 * and set the pseudo-toggle in udev. Only usb_clear_halt() will
125662306a36Sopenharmony_ci	 * ever clear it.
125762306a36Sopenharmony_ci	 */
125862306a36Sopenharmony_ci	if (!(qh->hw_info1 & cpu_to_le32(1 << 14))) {
125962306a36Sopenharmony_ci		unsigned	is_out, epnum;
126062306a36Sopenharmony_ci
126162306a36Sopenharmony_ci		is_out = !(qtd->hw_token & cpu_to_le32(1 << 8));
126262306a36Sopenharmony_ci		epnum = (le32_to_cpup(&qh->hw_info1) >> 8) & 0x0f;
126362306a36Sopenharmony_ci		if (unlikely(!usb_gettoggle(qh->dev, epnum, is_out))) {
126462306a36Sopenharmony_ci			qh->hw_token &= ~cpu_to_le32(QTD_TOGGLE);
126562306a36Sopenharmony_ci			usb_settoggle(qh->dev, epnum, is_out, 1);
126662306a36Sopenharmony_ci		}
126762306a36Sopenharmony_ci	}
126862306a36Sopenharmony_ci
126962306a36Sopenharmony_ci	/* HC must see latest qtd and qh data before we clear ACTIVE+HALT */
127062306a36Sopenharmony_ci	wmb();
127162306a36Sopenharmony_ci	qh->hw_token &= cpu_to_le32(QTD_TOGGLE | QTD_STS_PING);
127262306a36Sopenharmony_ci}
127362306a36Sopenharmony_ci
127462306a36Sopenharmony_ci/* If it weren't for a common silicon quirk (writing the dummy into the qh
127562306a36Sopenharmony_ci * overlay, so qh->hw_token wrongly becomes inactive/halted), only fault
127662306a36Sopenharmony_ci * recovery (including urb dequeue) would need software changes to a QH...
127762306a36Sopenharmony_ci */
127862306a36Sopenharmony_cistatic void qh_refresh(struct oxu_hcd *oxu, struct ehci_qh *qh)
127962306a36Sopenharmony_ci{
128062306a36Sopenharmony_ci	struct ehci_qtd *qtd;
128162306a36Sopenharmony_ci
128262306a36Sopenharmony_ci	if (list_empty(&qh->qtd_list))
128362306a36Sopenharmony_ci		qtd = qh->dummy;
128462306a36Sopenharmony_ci	else {
128562306a36Sopenharmony_ci		qtd = list_entry(qh->qtd_list.next,
128662306a36Sopenharmony_ci				struct ehci_qtd, qtd_list);
128762306a36Sopenharmony_ci		/* first qtd may already be partially processed */
128862306a36Sopenharmony_ci		if (cpu_to_le32(qtd->qtd_dma) == qh->hw_current)
128962306a36Sopenharmony_ci			qtd = NULL;
129062306a36Sopenharmony_ci	}
129162306a36Sopenharmony_ci
129262306a36Sopenharmony_ci	if (qtd)
129362306a36Sopenharmony_ci		qh_update(oxu, qh, qtd);
129462306a36Sopenharmony_ci}
129562306a36Sopenharmony_ci
129662306a36Sopenharmony_cistatic void qtd_copy_status(struct oxu_hcd *oxu, struct urb *urb,
129762306a36Sopenharmony_ci				size_t length, u32 token)
129862306a36Sopenharmony_ci{
129962306a36Sopenharmony_ci	/* count IN/OUT bytes, not SETUP (even short packets) */
130062306a36Sopenharmony_ci	if (likely(QTD_PID(token) != 2))
130162306a36Sopenharmony_ci		urb->actual_length += length - QTD_LENGTH(token);
130262306a36Sopenharmony_ci
130362306a36Sopenharmony_ci	/* don't modify error codes */
130462306a36Sopenharmony_ci	if (unlikely(urb->status != -EINPROGRESS))
130562306a36Sopenharmony_ci		return;
130662306a36Sopenharmony_ci
130762306a36Sopenharmony_ci	/* force cleanup after short read; not always an error */
130862306a36Sopenharmony_ci	if (unlikely(IS_SHORT_READ(token)))
130962306a36Sopenharmony_ci		urb->status = -EREMOTEIO;
131062306a36Sopenharmony_ci
131162306a36Sopenharmony_ci	/* serious "can't proceed" faults reported by the hardware */
131262306a36Sopenharmony_ci	if (token & QTD_STS_HALT) {
131362306a36Sopenharmony_ci		if (token & QTD_STS_BABBLE) {
131462306a36Sopenharmony_ci			/* FIXME "must" disable babbling device's port too */
131562306a36Sopenharmony_ci			urb->status = -EOVERFLOW;
131662306a36Sopenharmony_ci		} else if (token & QTD_STS_MMF) {
131762306a36Sopenharmony_ci			/* fs/ls interrupt xfer missed the complete-split */
131862306a36Sopenharmony_ci			urb->status = -EPROTO;
131962306a36Sopenharmony_ci		} else if (token & QTD_STS_DBE) {
132062306a36Sopenharmony_ci			urb->status = (QTD_PID(token) == 1) /* IN ? */
132162306a36Sopenharmony_ci				? -ENOSR  /* hc couldn't read data */
132262306a36Sopenharmony_ci				: -ECOMM; /* hc couldn't write data */
132362306a36Sopenharmony_ci		} else if (token & QTD_STS_XACT) {
132462306a36Sopenharmony_ci			/* timeout, bad crc, wrong PID, etc; retried */
132562306a36Sopenharmony_ci			if (QTD_CERR(token))
132662306a36Sopenharmony_ci				urb->status = -EPIPE;
132762306a36Sopenharmony_ci			else {
132862306a36Sopenharmony_ci				oxu_dbg(oxu, "devpath %s ep%d%s 3strikes\n",
132962306a36Sopenharmony_ci					urb->dev->devpath,
133062306a36Sopenharmony_ci					usb_pipeendpoint(urb->pipe),
133162306a36Sopenharmony_ci					usb_pipein(urb->pipe) ? "in" : "out");
133262306a36Sopenharmony_ci				urb->status = -EPROTO;
133362306a36Sopenharmony_ci			}
133462306a36Sopenharmony_ci		/* CERR nonzero + no errors + halt --> stall */
133562306a36Sopenharmony_ci		} else if (QTD_CERR(token))
133662306a36Sopenharmony_ci			urb->status = -EPIPE;
133762306a36Sopenharmony_ci		else	/* unknown */
133862306a36Sopenharmony_ci			urb->status = -EPROTO;
133962306a36Sopenharmony_ci
134062306a36Sopenharmony_ci		oxu_vdbg(oxu, "dev%d ep%d%s qtd token %08x --> status %d\n",
134162306a36Sopenharmony_ci			usb_pipedevice(urb->pipe),
134262306a36Sopenharmony_ci			usb_pipeendpoint(urb->pipe),
134362306a36Sopenharmony_ci			usb_pipein(urb->pipe) ? "in" : "out",
134462306a36Sopenharmony_ci			token, urb->status);
134562306a36Sopenharmony_ci	}
134662306a36Sopenharmony_ci}
134762306a36Sopenharmony_ci
134862306a36Sopenharmony_cistatic void ehci_urb_done(struct oxu_hcd *oxu, struct urb *urb)
134962306a36Sopenharmony_ci__releases(oxu->lock)
135062306a36Sopenharmony_ci__acquires(oxu->lock)
135162306a36Sopenharmony_ci{
135262306a36Sopenharmony_ci	if (likely(urb->hcpriv != NULL)) {
135362306a36Sopenharmony_ci		struct ehci_qh	*qh = (struct ehci_qh *) urb->hcpriv;
135462306a36Sopenharmony_ci
135562306a36Sopenharmony_ci		/* S-mask in a QH means it's an interrupt urb */
135662306a36Sopenharmony_ci		if ((qh->hw_info2 & cpu_to_le32(QH_SMASK)) != 0) {
135762306a36Sopenharmony_ci
135862306a36Sopenharmony_ci			/* ... update hc-wide periodic stats (for usbfs) */
135962306a36Sopenharmony_ci			oxu_to_hcd(oxu)->self.bandwidth_int_reqs--;
136062306a36Sopenharmony_ci		}
136162306a36Sopenharmony_ci		qh_put(qh);
136262306a36Sopenharmony_ci	}
136362306a36Sopenharmony_ci
136462306a36Sopenharmony_ci	urb->hcpriv = NULL;
136562306a36Sopenharmony_ci	switch (urb->status) {
136662306a36Sopenharmony_ci	case -EINPROGRESS:		/* success */
136762306a36Sopenharmony_ci		urb->status = 0;
136862306a36Sopenharmony_ci		break;
136962306a36Sopenharmony_ci	default:			/* fault */
137062306a36Sopenharmony_ci		break;
137162306a36Sopenharmony_ci	case -EREMOTEIO:		/* fault or normal */
137262306a36Sopenharmony_ci		if (!(urb->transfer_flags & URB_SHORT_NOT_OK))
137362306a36Sopenharmony_ci			urb->status = 0;
137462306a36Sopenharmony_ci		break;
137562306a36Sopenharmony_ci	case -ECONNRESET:		/* canceled */
137662306a36Sopenharmony_ci	case -ENOENT:
137762306a36Sopenharmony_ci		break;
137862306a36Sopenharmony_ci	}
137962306a36Sopenharmony_ci
138062306a36Sopenharmony_ci#ifdef OXU_URB_TRACE
138162306a36Sopenharmony_ci	oxu_dbg(oxu, "%s %s urb %p ep%d%s status %d len %d/%d\n",
138262306a36Sopenharmony_ci		__func__, urb->dev->devpath, urb,
138362306a36Sopenharmony_ci		usb_pipeendpoint(urb->pipe),
138462306a36Sopenharmony_ci		usb_pipein(urb->pipe) ? "in" : "out",
138562306a36Sopenharmony_ci		urb->status,
138662306a36Sopenharmony_ci		urb->actual_length, urb->transfer_buffer_length);
138762306a36Sopenharmony_ci#endif
138862306a36Sopenharmony_ci
138962306a36Sopenharmony_ci	/* complete() can reenter this HCD */
139062306a36Sopenharmony_ci	spin_unlock(&oxu->lock);
139162306a36Sopenharmony_ci	usb_hcd_giveback_urb(oxu_to_hcd(oxu), urb, urb->status);
139262306a36Sopenharmony_ci	spin_lock(&oxu->lock);
139362306a36Sopenharmony_ci}
139462306a36Sopenharmony_ci
139562306a36Sopenharmony_cistatic void start_unlink_async(struct oxu_hcd *oxu, struct ehci_qh *qh);
139662306a36Sopenharmony_cistatic void unlink_async(struct oxu_hcd *oxu, struct ehci_qh *qh);
139762306a36Sopenharmony_ci
139862306a36Sopenharmony_cistatic void intr_deschedule(struct oxu_hcd *oxu, struct ehci_qh *qh);
139962306a36Sopenharmony_cistatic int qh_schedule(struct oxu_hcd *oxu, struct ehci_qh *qh);
140062306a36Sopenharmony_ci
140162306a36Sopenharmony_ci#define HALT_BIT cpu_to_le32(QTD_STS_HALT)
140262306a36Sopenharmony_ci
140362306a36Sopenharmony_ci/* Process and free completed qtds for a qh, returning URBs to drivers.
140462306a36Sopenharmony_ci * Chases up to qh->hw_current.  Returns number of completions called,
140562306a36Sopenharmony_ci * indicating how much "real" work we did.
140662306a36Sopenharmony_ci */
140762306a36Sopenharmony_cistatic unsigned qh_completions(struct oxu_hcd *oxu, struct ehci_qh *qh)
140862306a36Sopenharmony_ci{
140962306a36Sopenharmony_ci	struct ehci_qtd *last = NULL, *end = qh->dummy;
141062306a36Sopenharmony_ci	struct ehci_qtd	*qtd, *tmp;
141162306a36Sopenharmony_ci	int stopped;
141262306a36Sopenharmony_ci	unsigned count = 0;
141362306a36Sopenharmony_ci	int do_status = 0;
141462306a36Sopenharmony_ci	u8 state;
141562306a36Sopenharmony_ci	struct oxu_murb *murb = NULL;
141662306a36Sopenharmony_ci
141762306a36Sopenharmony_ci	if (unlikely(list_empty(&qh->qtd_list)))
141862306a36Sopenharmony_ci		return count;
141962306a36Sopenharmony_ci
142062306a36Sopenharmony_ci	/* completions (or tasks on other cpus) must never clobber HALT
142162306a36Sopenharmony_ci	 * till we've gone through and cleaned everything up, even when
142262306a36Sopenharmony_ci	 * they add urbs to this qh's queue or mark them for unlinking.
142362306a36Sopenharmony_ci	 *
142462306a36Sopenharmony_ci	 * NOTE:  unlinking expects to be done in queue order.
142562306a36Sopenharmony_ci	 */
142662306a36Sopenharmony_ci	state = qh->qh_state;
142762306a36Sopenharmony_ci	qh->qh_state = QH_STATE_COMPLETING;
142862306a36Sopenharmony_ci	stopped = (state == QH_STATE_IDLE);
142962306a36Sopenharmony_ci
143062306a36Sopenharmony_ci	/* remove de-activated QTDs from front of queue.
143162306a36Sopenharmony_ci	 * after faults (including short reads), cleanup this urb
143262306a36Sopenharmony_ci	 * then let the queue advance.
143362306a36Sopenharmony_ci	 * if queue is stopped, handles unlinks.
143462306a36Sopenharmony_ci	 */
143562306a36Sopenharmony_ci	list_for_each_entry_safe(qtd, tmp, &qh->qtd_list, qtd_list) {
143662306a36Sopenharmony_ci		struct urb *urb;
143762306a36Sopenharmony_ci		u32 token = 0;
143862306a36Sopenharmony_ci
143962306a36Sopenharmony_ci		urb = qtd->urb;
144062306a36Sopenharmony_ci
144162306a36Sopenharmony_ci		/* Clean up any state from previous QTD ...*/
144262306a36Sopenharmony_ci		if (last) {
144362306a36Sopenharmony_ci			if (likely(last->urb != urb)) {
144462306a36Sopenharmony_ci				if (last->urb->complete == NULL) {
144562306a36Sopenharmony_ci					murb = (struct oxu_murb *) last->urb;
144662306a36Sopenharmony_ci					last->urb = murb->main;
144762306a36Sopenharmony_ci					if (murb->last) {
144862306a36Sopenharmony_ci						ehci_urb_done(oxu, last->urb);
144962306a36Sopenharmony_ci						count++;
145062306a36Sopenharmony_ci					}
145162306a36Sopenharmony_ci					oxu_murb_free(oxu, murb);
145262306a36Sopenharmony_ci				} else {
145362306a36Sopenharmony_ci					ehci_urb_done(oxu, last->urb);
145462306a36Sopenharmony_ci					count++;
145562306a36Sopenharmony_ci				}
145662306a36Sopenharmony_ci			}
145762306a36Sopenharmony_ci			oxu_qtd_free(oxu, last);
145862306a36Sopenharmony_ci			last = NULL;
145962306a36Sopenharmony_ci		}
146062306a36Sopenharmony_ci
146162306a36Sopenharmony_ci		/* ignore urbs submitted during completions we reported */
146262306a36Sopenharmony_ci		if (qtd == end)
146362306a36Sopenharmony_ci			break;
146462306a36Sopenharmony_ci
146562306a36Sopenharmony_ci		/* hardware copies qtd out of qh overlay */
146662306a36Sopenharmony_ci		rmb();
146762306a36Sopenharmony_ci		token = le32_to_cpu(qtd->hw_token);
146862306a36Sopenharmony_ci
146962306a36Sopenharmony_ci		/* always clean up qtds the hc de-activated */
147062306a36Sopenharmony_ci		if ((token & QTD_STS_ACTIVE) == 0) {
147162306a36Sopenharmony_ci
147262306a36Sopenharmony_ci			if ((token & QTD_STS_HALT) != 0) {
147362306a36Sopenharmony_ci				stopped = 1;
147462306a36Sopenharmony_ci
147562306a36Sopenharmony_ci			/* magic dummy for some short reads; qh won't advance.
147662306a36Sopenharmony_ci			 * that silicon quirk can kick in with this dummy too.
147762306a36Sopenharmony_ci			 */
147862306a36Sopenharmony_ci			} else if (IS_SHORT_READ(token) &&
147962306a36Sopenharmony_ci					!(qtd->hw_alt_next & EHCI_LIST_END)) {
148062306a36Sopenharmony_ci				stopped = 1;
148162306a36Sopenharmony_ci				goto halt;
148262306a36Sopenharmony_ci			}
148362306a36Sopenharmony_ci
148462306a36Sopenharmony_ci		/* stop scanning when we reach qtds the hc is using */
148562306a36Sopenharmony_ci		} else if (likely(!stopped &&
148662306a36Sopenharmony_ci				HC_IS_RUNNING(oxu_to_hcd(oxu)->state))) {
148762306a36Sopenharmony_ci			break;
148862306a36Sopenharmony_ci
148962306a36Sopenharmony_ci		} else {
149062306a36Sopenharmony_ci			stopped = 1;
149162306a36Sopenharmony_ci
149262306a36Sopenharmony_ci			if (unlikely(!HC_IS_RUNNING(oxu_to_hcd(oxu)->state)))
149362306a36Sopenharmony_ci				urb->status = -ESHUTDOWN;
149462306a36Sopenharmony_ci
149562306a36Sopenharmony_ci			/* ignore active urbs unless some previous qtd
149662306a36Sopenharmony_ci			 * for the urb faulted (including short read) or
149762306a36Sopenharmony_ci			 * its urb was canceled.  we may patch qh or qtds.
149862306a36Sopenharmony_ci			 */
149962306a36Sopenharmony_ci			if (likely(urb->status == -EINPROGRESS))
150062306a36Sopenharmony_ci				continue;
150162306a36Sopenharmony_ci
150262306a36Sopenharmony_ci			/* issue status after short control reads */
150362306a36Sopenharmony_ci			if (unlikely(do_status != 0)
150462306a36Sopenharmony_ci					&& QTD_PID(token) == 0 /* OUT */) {
150562306a36Sopenharmony_ci				do_status = 0;
150662306a36Sopenharmony_ci				continue;
150762306a36Sopenharmony_ci			}
150862306a36Sopenharmony_ci
150962306a36Sopenharmony_ci			/* token in overlay may be most current */
151062306a36Sopenharmony_ci			if (state == QH_STATE_IDLE
151162306a36Sopenharmony_ci					&& cpu_to_le32(qtd->qtd_dma)
151262306a36Sopenharmony_ci						== qh->hw_current)
151362306a36Sopenharmony_ci				token = le32_to_cpu(qh->hw_token);
151462306a36Sopenharmony_ci
151562306a36Sopenharmony_ci			/* force halt for unlinked or blocked qh, so we'll
151662306a36Sopenharmony_ci			 * patch the qh later and so that completions can't
151762306a36Sopenharmony_ci			 * activate it while we "know" it's stopped.
151862306a36Sopenharmony_ci			 */
151962306a36Sopenharmony_ci			if ((HALT_BIT & qh->hw_token) == 0) {
152062306a36Sopenharmony_cihalt:
152162306a36Sopenharmony_ci				qh->hw_token |= HALT_BIT;
152262306a36Sopenharmony_ci				wmb();
152362306a36Sopenharmony_ci			}
152462306a36Sopenharmony_ci		}
152562306a36Sopenharmony_ci
152662306a36Sopenharmony_ci		/* Remove it from the queue */
152762306a36Sopenharmony_ci		qtd_copy_status(oxu, urb->complete ?
152862306a36Sopenharmony_ci					urb : ((struct oxu_murb *) urb)->main,
152962306a36Sopenharmony_ci				qtd->length, token);
153062306a36Sopenharmony_ci		if ((usb_pipein(qtd->urb->pipe)) &&
153162306a36Sopenharmony_ci				(NULL != qtd->transfer_buffer))
153262306a36Sopenharmony_ci			memcpy(qtd->transfer_buffer, qtd->buffer, qtd->length);
153362306a36Sopenharmony_ci		do_status = (urb->status == -EREMOTEIO)
153462306a36Sopenharmony_ci				&& usb_pipecontrol(urb->pipe);
153562306a36Sopenharmony_ci
153662306a36Sopenharmony_ci		if (stopped && qtd->qtd_list.prev != &qh->qtd_list) {
153762306a36Sopenharmony_ci			last = list_entry(qtd->qtd_list.prev,
153862306a36Sopenharmony_ci					struct ehci_qtd, qtd_list);
153962306a36Sopenharmony_ci			last->hw_next = qtd->hw_next;
154062306a36Sopenharmony_ci		}
154162306a36Sopenharmony_ci		list_del(&qtd->qtd_list);
154262306a36Sopenharmony_ci		last = qtd;
154362306a36Sopenharmony_ci	}
154462306a36Sopenharmony_ci
154562306a36Sopenharmony_ci	/* last urb's completion might still need calling */
154662306a36Sopenharmony_ci	if (likely(last != NULL)) {
154762306a36Sopenharmony_ci		if (last->urb->complete == NULL) {
154862306a36Sopenharmony_ci			murb = (struct oxu_murb *) last->urb;
154962306a36Sopenharmony_ci			last->urb = murb->main;
155062306a36Sopenharmony_ci			if (murb->last) {
155162306a36Sopenharmony_ci				ehci_urb_done(oxu, last->urb);
155262306a36Sopenharmony_ci				count++;
155362306a36Sopenharmony_ci			}
155462306a36Sopenharmony_ci			oxu_murb_free(oxu, murb);
155562306a36Sopenharmony_ci		} else {
155662306a36Sopenharmony_ci			ehci_urb_done(oxu, last->urb);
155762306a36Sopenharmony_ci			count++;
155862306a36Sopenharmony_ci		}
155962306a36Sopenharmony_ci		oxu_qtd_free(oxu, last);
156062306a36Sopenharmony_ci	}
156162306a36Sopenharmony_ci
156262306a36Sopenharmony_ci	/* restore original state; caller must unlink or relink */
156362306a36Sopenharmony_ci	qh->qh_state = state;
156462306a36Sopenharmony_ci
156562306a36Sopenharmony_ci	/* be sure the hardware's done with the qh before refreshing
156662306a36Sopenharmony_ci	 * it after fault cleanup, or recovering from silicon wrongly
156762306a36Sopenharmony_ci	 * overlaying the dummy qtd (which reduces DMA chatter).
156862306a36Sopenharmony_ci	 */
156962306a36Sopenharmony_ci	if (stopped != 0 || qh->hw_qtd_next == EHCI_LIST_END) {
157062306a36Sopenharmony_ci		switch (state) {
157162306a36Sopenharmony_ci		case QH_STATE_IDLE:
157262306a36Sopenharmony_ci			qh_refresh(oxu, qh);
157362306a36Sopenharmony_ci			break;
157462306a36Sopenharmony_ci		case QH_STATE_LINKED:
157562306a36Sopenharmony_ci			/* should be rare for periodic transfers,
157662306a36Sopenharmony_ci			 * except maybe high bandwidth ...
157762306a36Sopenharmony_ci			 */
157862306a36Sopenharmony_ci			if ((cpu_to_le32(QH_SMASK)
157962306a36Sopenharmony_ci					& qh->hw_info2) != 0) {
158062306a36Sopenharmony_ci				intr_deschedule(oxu, qh);
158162306a36Sopenharmony_ci				(void) qh_schedule(oxu, qh);
158262306a36Sopenharmony_ci			} else
158362306a36Sopenharmony_ci				unlink_async(oxu, qh);
158462306a36Sopenharmony_ci			break;
158562306a36Sopenharmony_ci		/* otherwise, unlink already started */
158662306a36Sopenharmony_ci		}
158762306a36Sopenharmony_ci	}
158862306a36Sopenharmony_ci
158962306a36Sopenharmony_ci	return count;
159062306a36Sopenharmony_ci}
159162306a36Sopenharmony_ci
159262306a36Sopenharmony_ci/* High bandwidth multiplier, as encoded in highspeed endpoint descriptors */
159362306a36Sopenharmony_ci#define hb_mult(wMaxPacketSize)		(1 + (((wMaxPacketSize) >> 11) & 0x03))
159462306a36Sopenharmony_ci/* ... and packet size, for any kind of endpoint descriptor */
159562306a36Sopenharmony_ci#define max_packet(wMaxPacketSize)	((wMaxPacketSize) & 0x07ff)
159662306a36Sopenharmony_ci
159762306a36Sopenharmony_ci/* Reverse of qh_urb_transaction: free a list of TDs.
159862306a36Sopenharmony_ci * used for cleanup after errors, before HC sees an URB's TDs.
159962306a36Sopenharmony_ci */
160062306a36Sopenharmony_cistatic void qtd_list_free(struct oxu_hcd *oxu,
160162306a36Sopenharmony_ci				struct urb *urb, struct list_head *head)
160262306a36Sopenharmony_ci{
160362306a36Sopenharmony_ci	struct ehci_qtd	*qtd, *temp;
160462306a36Sopenharmony_ci
160562306a36Sopenharmony_ci	list_for_each_entry_safe(qtd, temp, head, qtd_list) {
160662306a36Sopenharmony_ci		list_del(&qtd->qtd_list);
160762306a36Sopenharmony_ci		oxu_qtd_free(oxu, qtd);
160862306a36Sopenharmony_ci	}
160962306a36Sopenharmony_ci}
161062306a36Sopenharmony_ci
161162306a36Sopenharmony_ci/* Create a list of filled qtds for this URB; won't link into qh.
161262306a36Sopenharmony_ci */
161362306a36Sopenharmony_cistatic struct list_head *qh_urb_transaction(struct oxu_hcd *oxu,
161462306a36Sopenharmony_ci						struct urb *urb,
161562306a36Sopenharmony_ci						struct list_head *head,
161662306a36Sopenharmony_ci						gfp_t flags)
161762306a36Sopenharmony_ci{
161862306a36Sopenharmony_ci	struct ehci_qtd	*qtd, *qtd_prev;
161962306a36Sopenharmony_ci	dma_addr_t buf;
162062306a36Sopenharmony_ci	int len, maxpacket;
162162306a36Sopenharmony_ci	int is_input;
162262306a36Sopenharmony_ci	u32 token;
162362306a36Sopenharmony_ci	void *transfer_buf = NULL;
162462306a36Sopenharmony_ci	int ret;
162562306a36Sopenharmony_ci
162662306a36Sopenharmony_ci	/*
162762306a36Sopenharmony_ci	 * URBs map to sequences of QTDs: one logical transaction
162862306a36Sopenharmony_ci	 */
162962306a36Sopenharmony_ci	qtd = ehci_qtd_alloc(oxu);
163062306a36Sopenharmony_ci	if (unlikely(!qtd))
163162306a36Sopenharmony_ci		return NULL;
163262306a36Sopenharmony_ci	list_add_tail(&qtd->qtd_list, head);
163362306a36Sopenharmony_ci	qtd->urb = urb;
163462306a36Sopenharmony_ci
163562306a36Sopenharmony_ci	token = QTD_STS_ACTIVE;
163662306a36Sopenharmony_ci	token |= (EHCI_TUNE_CERR << 10);
163762306a36Sopenharmony_ci	/* for split transactions, SplitXState initialized to zero */
163862306a36Sopenharmony_ci
163962306a36Sopenharmony_ci	len = urb->transfer_buffer_length;
164062306a36Sopenharmony_ci	is_input = usb_pipein(urb->pipe);
164162306a36Sopenharmony_ci	if (!urb->transfer_buffer && urb->transfer_buffer_length && is_input)
164262306a36Sopenharmony_ci		urb->transfer_buffer = phys_to_virt(urb->transfer_dma);
164362306a36Sopenharmony_ci
164462306a36Sopenharmony_ci	if (usb_pipecontrol(urb->pipe)) {
164562306a36Sopenharmony_ci		/* SETUP pid */
164662306a36Sopenharmony_ci		ret = oxu_buf_alloc(oxu, qtd, sizeof(struct usb_ctrlrequest));
164762306a36Sopenharmony_ci		if (ret)
164862306a36Sopenharmony_ci			goto cleanup;
164962306a36Sopenharmony_ci
165062306a36Sopenharmony_ci		qtd_fill(qtd, qtd->buffer_dma, sizeof(struct usb_ctrlrequest),
165162306a36Sopenharmony_ci				token | (2 /* "setup" */ << 8), 8);
165262306a36Sopenharmony_ci		memcpy(qtd->buffer, qtd->urb->setup_packet,
165362306a36Sopenharmony_ci				sizeof(struct usb_ctrlrequest));
165462306a36Sopenharmony_ci
165562306a36Sopenharmony_ci		/* ... and always at least one more pid */
165662306a36Sopenharmony_ci		token ^= QTD_TOGGLE;
165762306a36Sopenharmony_ci		qtd_prev = qtd;
165862306a36Sopenharmony_ci		qtd = ehci_qtd_alloc(oxu);
165962306a36Sopenharmony_ci		if (unlikely(!qtd))
166062306a36Sopenharmony_ci			goto cleanup;
166162306a36Sopenharmony_ci		qtd->urb = urb;
166262306a36Sopenharmony_ci		qtd_prev->hw_next = QTD_NEXT(qtd->qtd_dma);
166362306a36Sopenharmony_ci		list_add_tail(&qtd->qtd_list, head);
166462306a36Sopenharmony_ci
166562306a36Sopenharmony_ci		/* for zero length DATA stages, STATUS is always IN */
166662306a36Sopenharmony_ci		if (len == 0)
166762306a36Sopenharmony_ci			token |= (1 /* "in" */ << 8);
166862306a36Sopenharmony_ci	}
166962306a36Sopenharmony_ci
167062306a36Sopenharmony_ci	/*
167162306a36Sopenharmony_ci	 * Data transfer stage: buffer setup
167262306a36Sopenharmony_ci	 */
167362306a36Sopenharmony_ci
167462306a36Sopenharmony_ci	ret = oxu_buf_alloc(oxu, qtd, len);
167562306a36Sopenharmony_ci	if (ret)
167662306a36Sopenharmony_ci		goto cleanup;
167762306a36Sopenharmony_ci
167862306a36Sopenharmony_ci	buf = qtd->buffer_dma;
167962306a36Sopenharmony_ci	transfer_buf = urb->transfer_buffer;
168062306a36Sopenharmony_ci
168162306a36Sopenharmony_ci	if (!is_input)
168262306a36Sopenharmony_ci		memcpy(qtd->buffer, qtd->urb->transfer_buffer, len);
168362306a36Sopenharmony_ci
168462306a36Sopenharmony_ci	if (is_input)
168562306a36Sopenharmony_ci		token |= (1 /* "in" */ << 8);
168662306a36Sopenharmony_ci	/* else it's already initted to "out" pid (0 << 8) */
168762306a36Sopenharmony_ci
168862306a36Sopenharmony_ci	maxpacket = usb_maxpacket(urb->dev, urb->pipe);
168962306a36Sopenharmony_ci
169062306a36Sopenharmony_ci	/*
169162306a36Sopenharmony_ci	 * buffer gets wrapped in one or more qtds;
169262306a36Sopenharmony_ci	 * last one may be "short" (including zero len)
169362306a36Sopenharmony_ci	 * and may serve as a control status ack
169462306a36Sopenharmony_ci	 */
169562306a36Sopenharmony_ci	for (;;) {
169662306a36Sopenharmony_ci		int this_qtd_len;
169762306a36Sopenharmony_ci
169862306a36Sopenharmony_ci		this_qtd_len = qtd_fill(qtd, buf, len, token, maxpacket);
169962306a36Sopenharmony_ci		qtd->transfer_buffer = transfer_buf;
170062306a36Sopenharmony_ci		len -= this_qtd_len;
170162306a36Sopenharmony_ci		buf += this_qtd_len;
170262306a36Sopenharmony_ci		transfer_buf += this_qtd_len;
170362306a36Sopenharmony_ci		if (is_input)
170462306a36Sopenharmony_ci			qtd->hw_alt_next = oxu->async->hw_alt_next;
170562306a36Sopenharmony_ci
170662306a36Sopenharmony_ci		/* qh makes control packets use qtd toggle; maybe switch it */
170762306a36Sopenharmony_ci		if ((maxpacket & (this_qtd_len + (maxpacket - 1))) == 0)
170862306a36Sopenharmony_ci			token ^= QTD_TOGGLE;
170962306a36Sopenharmony_ci
171062306a36Sopenharmony_ci		if (likely(len <= 0))
171162306a36Sopenharmony_ci			break;
171262306a36Sopenharmony_ci
171362306a36Sopenharmony_ci		qtd_prev = qtd;
171462306a36Sopenharmony_ci		qtd = ehci_qtd_alloc(oxu);
171562306a36Sopenharmony_ci		if (unlikely(!qtd))
171662306a36Sopenharmony_ci			goto cleanup;
171762306a36Sopenharmony_ci		if (likely(len > 0)) {
171862306a36Sopenharmony_ci			ret = oxu_buf_alloc(oxu, qtd, len);
171962306a36Sopenharmony_ci			if (ret)
172062306a36Sopenharmony_ci				goto cleanup;
172162306a36Sopenharmony_ci		}
172262306a36Sopenharmony_ci		qtd->urb = urb;
172362306a36Sopenharmony_ci		qtd_prev->hw_next = QTD_NEXT(qtd->qtd_dma);
172462306a36Sopenharmony_ci		list_add_tail(&qtd->qtd_list, head);
172562306a36Sopenharmony_ci	}
172662306a36Sopenharmony_ci
172762306a36Sopenharmony_ci	/* unless the bulk/interrupt caller wants a chance to clean
172862306a36Sopenharmony_ci	 * up after short reads, hc should advance qh past this urb
172962306a36Sopenharmony_ci	 */
173062306a36Sopenharmony_ci	if (likely((urb->transfer_flags & URB_SHORT_NOT_OK) == 0
173162306a36Sopenharmony_ci				|| usb_pipecontrol(urb->pipe)))
173262306a36Sopenharmony_ci		qtd->hw_alt_next = EHCI_LIST_END;
173362306a36Sopenharmony_ci
173462306a36Sopenharmony_ci	/*
173562306a36Sopenharmony_ci	 * control requests may need a terminating data "status" ack;
173662306a36Sopenharmony_ci	 * bulk ones may need a terminating short packet (zero length).
173762306a36Sopenharmony_ci	 */
173862306a36Sopenharmony_ci	if (likely(urb->transfer_buffer_length != 0)) {
173962306a36Sopenharmony_ci		int	one_more = 0;
174062306a36Sopenharmony_ci
174162306a36Sopenharmony_ci		if (usb_pipecontrol(urb->pipe)) {
174262306a36Sopenharmony_ci			one_more = 1;
174362306a36Sopenharmony_ci			token ^= 0x0100;	/* "in" <--> "out"  */
174462306a36Sopenharmony_ci			token |= QTD_TOGGLE;	/* force DATA1 */
174562306a36Sopenharmony_ci		} else if (usb_pipebulk(urb->pipe)
174662306a36Sopenharmony_ci				&& (urb->transfer_flags & URB_ZERO_PACKET)
174762306a36Sopenharmony_ci				&& !(urb->transfer_buffer_length % maxpacket)) {
174862306a36Sopenharmony_ci			one_more = 1;
174962306a36Sopenharmony_ci		}
175062306a36Sopenharmony_ci		if (one_more) {
175162306a36Sopenharmony_ci			qtd_prev = qtd;
175262306a36Sopenharmony_ci			qtd = ehci_qtd_alloc(oxu);
175362306a36Sopenharmony_ci			if (unlikely(!qtd))
175462306a36Sopenharmony_ci				goto cleanup;
175562306a36Sopenharmony_ci			qtd->urb = urb;
175662306a36Sopenharmony_ci			qtd_prev->hw_next = QTD_NEXT(qtd->qtd_dma);
175762306a36Sopenharmony_ci			list_add_tail(&qtd->qtd_list, head);
175862306a36Sopenharmony_ci
175962306a36Sopenharmony_ci			/* never any data in such packets */
176062306a36Sopenharmony_ci			qtd_fill(qtd, 0, 0, token, 0);
176162306a36Sopenharmony_ci		}
176262306a36Sopenharmony_ci	}
176362306a36Sopenharmony_ci
176462306a36Sopenharmony_ci	/* by default, enable interrupt on urb completion */
176562306a36Sopenharmony_ci	qtd->hw_token |= cpu_to_le32(QTD_IOC);
176662306a36Sopenharmony_ci	return head;
176762306a36Sopenharmony_ci
176862306a36Sopenharmony_cicleanup:
176962306a36Sopenharmony_ci	qtd_list_free(oxu, urb, head);
177062306a36Sopenharmony_ci	return NULL;
177162306a36Sopenharmony_ci}
177262306a36Sopenharmony_ci
177362306a36Sopenharmony_ci/* Each QH holds a qtd list; a QH is used for everything except iso.
177462306a36Sopenharmony_ci *
177562306a36Sopenharmony_ci * For interrupt urbs, the scheduler must set the microframe scheduling
177662306a36Sopenharmony_ci * mask(s) each time the QH gets scheduled.  For highspeed, that's
177762306a36Sopenharmony_ci * just one microframe in the s-mask.  For split interrupt transactions
177862306a36Sopenharmony_ci * there are additional complications: c-mask, maybe FSTNs.
177962306a36Sopenharmony_ci */
178062306a36Sopenharmony_cistatic struct ehci_qh *qh_make(struct oxu_hcd *oxu,
178162306a36Sopenharmony_ci				struct urb *urb, gfp_t flags)
178262306a36Sopenharmony_ci{
178362306a36Sopenharmony_ci	struct ehci_qh *qh = oxu_qh_alloc(oxu);
178462306a36Sopenharmony_ci	u32 info1 = 0, info2 = 0;
178562306a36Sopenharmony_ci	int is_input, type;
178662306a36Sopenharmony_ci	int maxp = 0;
178762306a36Sopenharmony_ci
178862306a36Sopenharmony_ci	if (!qh)
178962306a36Sopenharmony_ci		return qh;
179062306a36Sopenharmony_ci
179162306a36Sopenharmony_ci	/*
179262306a36Sopenharmony_ci	 * init endpoint/device data for this QH
179362306a36Sopenharmony_ci	 */
179462306a36Sopenharmony_ci	info1 |= usb_pipeendpoint(urb->pipe) << 8;
179562306a36Sopenharmony_ci	info1 |= usb_pipedevice(urb->pipe) << 0;
179662306a36Sopenharmony_ci
179762306a36Sopenharmony_ci	is_input = usb_pipein(urb->pipe);
179862306a36Sopenharmony_ci	type = usb_pipetype(urb->pipe);
179962306a36Sopenharmony_ci	maxp = usb_maxpacket(urb->dev, urb->pipe);
180062306a36Sopenharmony_ci
180162306a36Sopenharmony_ci	/* Compute interrupt scheduling parameters just once, and save.
180262306a36Sopenharmony_ci	 * - allowing for high bandwidth, how many nsec/uframe are used?
180362306a36Sopenharmony_ci	 * - split transactions need a second CSPLIT uframe; same question
180462306a36Sopenharmony_ci	 * - splits also need a schedule gap (for full/low speed I/O)
180562306a36Sopenharmony_ci	 * - qh has a polling interval
180662306a36Sopenharmony_ci	 *
180762306a36Sopenharmony_ci	 * For control/bulk requests, the HC or TT handles these.
180862306a36Sopenharmony_ci	 */
180962306a36Sopenharmony_ci	if (type == PIPE_INTERRUPT) {
181062306a36Sopenharmony_ci		qh->usecs = NS_TO_US(usb_calc_bus_time(USB_SPEED_HIGH,
181162306a36Sopenharmony_ci								is_input, 0,
181262306a36Sopenharmony_ci				hb_mult(maxp) * max_packet(maxp)));
181362306a36Sopenharmony_ci		qh->start = NO_FRAME;
181462306a36Sopenharmony_ci
181562306a36Sopenharmony_ci		if (urb->dev->speed == USB_SPEED_HIGH) {
181662306a36Sopenharmony_ci			qh->c_usecs = 0;
181762306a36Sopenharmony_ci			qh->gap_uf = 0;
181862306a36Sopenharmony_ci
181962306a36Sopenharmony_ci			qh->period = urb->interval >> 3;
182062306a36Sopenharmony_ci			if (qh->period == 0 && urb->interval != 1) {
182162306a36Sopenharmony_ci				/* NOTE interval 2 or 4 uframes could work.
182262306a36Sopenharmony_ci				 * But interval 1 scheduling is simpler, and
182362306a36Sopenharmony_ci				 * includes high bandwidth.
182462306a36Sopenharmony_ci				 */
182562306a36Sopenharmony_ci				oxu_dbg(oxu, "intr period %d uframes, NYET!\n",
182662306a36Sopenharmony_ci					urb->interval);
182762306a36Sopenharmony_ci				goto done;
182862306a36Sopenharmony_ci			}
182962306a36Sopenharmony_ci		} else {
183062306a36Sopenharmony_ci			struct usb_tt	*tt = urb->dev->tt;
183162306a36Sopenharmony_ci			int		think_time;
183262306a36Sopenharmony_ci
183362306a36Sopenharmony_ci			/* gap is f(FS/LS transfer times) */
183462306a36Sopenharmony_ci			qh->gap_uf = 1 + usb_calc_bus_time(urb->dev->speed,
183562306a36Sopenharmony_ci					is_input, 0, maxp) / (125 * 1000);
183662306a36Sopenharmony_ci
183762306a36Sopenharmony_ci			/* FIXME this just approximates SPLIT/CSPLIT times */
183862306a36Sopenharmony_ci			if (is_input) {		/* SPLIT, gap, CSPLIT+DATA */
183962306a36Sopenharmony_ci				qh->c_usecs = qh->usecs + HS_USECS(0);
184062306a36Sopenharmony_ci				qh->usecs = HS_USECS(1);
184162306a36Sopenharmony_ci			} else {		/* SPLIT+DATA, gap, CSPLIT */
184262306a36Sopenharmony_ci				qh->usecs += HS_USECS(1);
184362306a36Sopenharmony_ci				qh->c_usecs = HS_USECS(0);
184462306a36Sopenharmony_ci			}
184562306a36Sopenharmony_ci
184662306a36Sopenharmony_ci			think_time = tt ? tt->think_time : 0;
184762306a36Sopenharmony_ci			qh->tt_usecs = NS_TO_US(think_time +
184862306a36Sopenharmony_ci					usb_calc_bus_time(urb->dev->speed,
184962306a36Sopenharmony_ci					is_input, 0, max_packet(maxp)));
185062306a36Sopenharmony_ci			qh->period = urb->interval;
185162306a36Sopenharmony_ci		}
185262306a36Sopenharmony_ci	}
185362306a36Sopenharmony_ci
185462306a36Sopenharmony_ci	/* support for tt scheduling, and access to toggles */
185562306a36Sopenharmony_ci	qh->dev = urb->dev;
185662306a36Sopenharmony_ci
185762306a36Sopenharmony_ci	/* using TT? */
185862306a36Sopenharmony_ci	switch (urb->dev->speed) {
185962306a36Sopenharmony_ci	case USB_SPEED_LOW:
186062306a36Sopenharmony_ci		info1 |= (1 << 12);	/* EPS "low" */
186162306a36Sopenharmony_ci		fallthrough;
186262306a36Sopenharmony_ci
186362306a36Sopenharmony_ci	case USB_SPEED_FULL:
186462306a36Sopenharmony_ci		/* EPS 0 means "full" */
186562306a36Sopenharmony_ci		if (type != PIPE_INTERRUPT)
186662306a36Sopenharmony_ci			info1 |= (EHCI_TUNE_RL_TT << 28);
186762306a36Sopenharmony_ci		if (type == PIPE_CONTROL) {
186862306a36Sopenharmony_ci			info1 |= (1 << 27);	/* for TT */
186962306a36Sopenharmony_ci			info1 |= 1 << 14;	/* toggle from qtd */
187062306a36Sopenharmony_ci		}
187162306a36Sopenharmony_ci		info1 |= maxp << 16;
187262306a36Sopenharmony_ci
187362306a36Sopenharmony_ci		info2 |= (EHCI_TUNE_MULT_TT << 30);
187462306a36Sopenharmony_ci		info2 |= urb->dev->ttport << 23;
187562306a36Sopenharmony_ci
187662306a36Sopenharmony_ci		/* NOTE:  if (PIPE_INTERRUPT) { scheduler sets c-mask } */
187762306a36Sopenharmony_ci
187862306a36Sopenharmony_ci		break;
187962306a36Sopenharmony_ci
188062306a36Sopenharmony_ci	case USB_SPEED_HIGH:		/* no TT involved */
188162306a36Sopenharmony_ci		info1 |= (2 << 12);	/* EPS "high" */
188262306a36Sopenharmony_ci		if (type == PIPE_CONTROL) {
188362306a36Sopenharmony_ci			info1 |= (EHCI_TUNE_RL_HS << 28);
188462306a36Sopenharmony_ci			info1 |= 64 << 16;	/* usb2 fixed maxpacket */
188562306a36Sopenharmony_ci			info1 |= 1 << 14;	/* toggle from qtd */
188662306a36Sopenharmony_ci			info2 |= (EHCI_TUNE_MULT_HS << 30);
188762306a36Sopenharmony_ci		} else if (type == PIPE_BULK) {
188862306a36Sopenharmony_ci			info1 |= (EHCI_TUNE_RL_HS << 28);
188962306a36Sopenharmony_ci			info1 |= 512 << 16;	/* usb2 fixed maxpacket */
189062306a36Sopenharmony_ci			info2 |= (EHCI_TUNE_MULT_HS << 30);
189162306a36Sopenharmony_ci		} else {		/* PIPE_INTERRUPT */
189262306a36Sopenharmony_ci			info1 |= max_packet(maxp) << 16;
189362306a36Sopenharmony_ci			info2 |= hb_mult(maxp) << 30;
189462306a36Sopenharmony_ci		}
189562306a36Sopenharmony_ci		break;
189662306a36Sopenharmony_ci	default:
189762306a36Sopenharmony_ci		oxu_dbg(oxu, "bogus dev %p speed %d\n", urb->dev, urb->dev->speed);
189862306a36Sopenharmony_cidone:
189962306a36Sopenharmony_ci		qh_put(qh);
190062306a36Sopenharmony_ci		return NULL;
190162306a36Sopenharmony_ci	}
190262306a36Sopenharmony_ci
190362306a36Sopenharmony_ci	/* NOTE:  if (PIPE_INTERRUPT) { scheduler sets s-mask } */
190462306a36Sopenharmony_ci
190562306a36Sopenharmony_ci	/* init as live, toggle clear, advance to dummy */
190662306a36Sopenharmony_ci	qh->qh_state = QH_STATE_IDLE;
190762306a36Sopenharmony_ci	qh->hw_info1 = cpu_to_le32(info1);
190862306a36Sopenharmony_ci	qh->hw_info2 = cpu_to_le32(info2);
190962306a36Sopenharmony_ci	usb_settoggle(urb->dev, usb_pipeendpoint(urb->pipe), !is_input, 1);
191062306a36Sopenharmony_ci	qh_refresh(oxu, qh);
191162306a36Sopenharmony_ci	return qh;
191262306a36Sopenharmony_ci}
191362306a36Sopenharmony_ci
191462306a36Sopenharmony_ci/* Move qh (and its qtds) onto async queue; maybe enable queue.
191562306a36Sopenharmony_ci */
191662306a36Sopenharmony_cistatic void qh_link_async(struct oxu_hcd *oxu, struct ehci_qh *qh)
191762306a36Sopenharmony_ci{
191862306a36Sopenharmony_ci	__le32 dma = QH_NEXT(qh->qh_dma);
191962306a36Sopenharmony_ci	struct ehci_qh *head;
192062306a36Sopenharmony_ci
192162306a36Sopenharmony_ci	/* (re)start the async schedule? */
192262306a36Sopenharmony_ci	head = oxu->async;
192362306a36Sopenharmony_ci	timer_action_done(oxu, TIMER_ASYNC_OFF);
192462306a36Sopenharmony_ci	if (!head->qh_next.qh) {
192562306a36Sopenharmony_ci		u32	cmd = readl(&oxu->regs->command);
192662306a36Sopenharmony_ci
192762306a36Sopenharmony_ci		if (!(cmd & CMD_ASE)) {
192862306a36Sopenharmony_ci			/* in case a clear of CMD_ASE didn't take yet */
192962306a36Sopenharmony_ci			(void)handshake(oxu, &oxu->regs->status,
193062306a36Sopenharmony_ci					STS_ASS, 0, 150);
193162306a36Sopenharmony_ci			cmd |= CMD_ASE | CMD_RUN;
193262306a36Sopenharmony_ci			writel(cmd, &oxu->regs->command);
193362306a36Sopenharmony_ci			oxu_to_hcd(oxu)->state = HC_STATE_RUNNING;
193462306a36Sopenharmony_ci			/* posted write need not be known to HC yet ... */
193562306a36Sopenharmony_ci		}
193662306a36Sopenharmony_ci	}
193762306a36Sopenharmony_ci
193862306a36Sopenharmony_ci	/* clear halt and/or toggle; and maybe recover from silicon quirk */
193962306a36Sopenharmony_ci	if (qh->qh_state == QH_STATE_IDLE)
194062306a36Sopenharmony_ci		qh_refresh(oxu, qh);
194162306a36Sopenharmony_ci
194262306a36Sopenharmony_ci	/* splice right after start */
194362306a36Sopenharmony_ci	qh->qh_next = head->qh_next;
194462306a36Sopenharmony_ci	qh->hw_next = head->hw_next;
194562306a36Sopenharmony_ci	wmb();
194662306a36Sopenharmony_ci
194762306a36Sopenharmony_ci	head->qh_next.qh = qh;
194862306a36Sopenharmony_ci	head->hw_next = dma;
194962306a36Sopenharmony_ci
195062306a36Sopenharmony_ci	qh->qh_state = QH_STATE_LINKED;
195162306a36Sopenharmony_ci	/* qtd completions reported later by interrupt */
195262306a36Sopenharmony_ci}
195362306a36Sopenharmony_ci
195462306a36Sopenharmony_ci#define	QH_ADDR_MASK	cpu_to_le32(0x7f)
195562306a36Sopenharmony_ci
195662306a36Sopenharmony_ci/*
195762306a36Sopenharmony_ci * For control/bulk/interrupt, return QH with these TDs appended.
195862306a36Sopenharmony_ci * Allocates and initializes the QH if necessary.
195962306a36Sopenharmony_ci * Returns null if it can't allocate a QH it needs to.
196062306a36Sopenharmony_ci * If the QH has TDs (urbs) already, that's great.
196162306a36Sopenharmony_ci */
196262306a36Sopenharmony_cistatic struct ehci_qh *qh_append_tds(struct oxu_hcd *oxu,
196362306a36Sopenharmony_ci				struct urb *urb, struct list_head *qtd_list,
196462306a36Sopenharmony_ci				int epnum, void	**ptr)
196562306a36Sopenharmony_ci{
196662306a36Sopenharmony_ci	struct ehci_qh *qh = NULL;
196762306a36Sopenharmony_ci
196862306a36Sopenharmony_ci	qh = (struct ehci_qh *) *ptr;
196962306a36Sopenharmony_ci	if (unlikely(qh == NULL)) {
197062306a36Sopenharmony_ci		/* can't sleep here, we have oxu->lock... */
197162306a36Sopenharmony_ci		qh = qh_make(oxu, urb, GFP_ATOMIC);
197262306a36Sopenharmony_ci		*ptr = qh;
197362306a36Sopenharmony_ci	}
197462306a36Sopenharmony_ci	if (likely(qh != NULL)) {
197562306a36Sopenharmony_ci		struct ehci_qtd	*qtd;
197662306a36Sopenharmony_ci
197762306a36Sopenharmony_ci		if (unlikely(list_empty(qtd_list)))
197862306a36Sopenharmony_ci			qtd = NULL;
197962306a36Sopenharmony_ci		else
198062306a36Sopenharmony_ci			qtd = list_entry(qtd_list->next, struct ehci_qtd,
198162306a36Sopenharmony_ci					qtd_list);
198262306a36Sopenharmony_ci
198362306a36Sopenharmony_ci		/* control qh may need patching ... */
198462306a36Sopenharmony_ci		if (unlikely(epnum == 0)) {
198562306a36Sopenharmony_ci
198662306a36Sopenharmony_ci			/* usb_reset_device() briefly reverts to address 0 */
198762306a36Sopenharmony_ci			if (usb_pipedevice(urb->pipe) == 0)
198862306a36Sopenharmony_ci				qh->hw_info1 &= ~QH_ADDR_MASK;
198962306a36Sopenharmony_ci		}
199062306a36Sopenharmony_ci
199162306a36Sopenharmony_ci		/* just one way to queue requests: swap with the dummy qtd.
199262306a36Sopenharmony_ci		 * only hc or qh_refresh() ever modify the overlay.
199362306a36Sopenharmony_ci		 */
199462306a36Sopenharmony_ci		if (likely(qtd != NULL)) {
199562306a36Sopenharmony_ci			struct ehci_qtd	*dummy;
199662306a36Sopenharmony_ci			dma_addr_t dma;
199762306a36Sopenharmony_ci			__le32 token;
199862306a36Sopenharmony_ci
199962306a36Sopenharmony_ci			/* to avoid racing the HC, use the dummy td instead of
200062306a36Sopenharmony_ci			 * the first td of our list (becomes new dummy).  both
200162306a36Sopenharmony_ci			 * tds stay deactivated until we're done, when the
200262306a36Sopenharmony_ci			 * HC is allowed to fetch the old dummy (4.10.2).
200362306a36Sopenharmony_ci			 */
200462306a36Sopenharmony_ci			token = qtd->hw_token;
200562306a36Sopenharmony_ci			qtd->hw_token = HALT_BIT;
200662306a36Sopenharmony_ci			wmb();
200762306a36Sopenharmony_ci			dummy = qh->dummy;
200862306a36Sopenharmony_ci
200962306a36Sopenharmony_ci			dma = dummy->qtd_dma;
201062306a36Sopenharmony_ci			*dummy = *qtd;
201162306a36Sopenharmony_ci			dummy->qtd_dma = dma;
201262306a36Sopenharmony_ci
201362306a36Sopenharmony_ci			list_del(&qtd->qtd_list);
201462306a36Sopenharmony_ci			list_add(&dummy->qtd_list, qtd_list);
201562306a36Sopenharmony_ci			list_splice(qtd_list, qh->qtd_list.prev);
201662306a36Sopenharmony_ci
201762306a36Sopenharmony_ci			ehci_qtd_init(qtd, qtd->qtd_dma);
201862306a36Sopenharmony_ci			qh->dummy = qtd;
201962306a36Sopenharmony_ci
202062306a36Sopenharmony_ci			/* hc must see the new dummy at list end */
202162306a36Sopenharmony_ci			dma = qtd->qtd_dma;
202262306a36Sopenharmony_ci			qtd = list_entry(qh->qtd_list.prev,
202362306a36Sopenharmony_ci					struct ehci_qtd, qtd_list);
202462306a36Sopenharmony_ci			qtd->hw_next = QTD_NEXT(dma);
202562306a36Sopenharmony_ci
202662306a36Sopenharmony_ci			/* let the hc process these next qtds */
202762306a36Sopenharmony_ci			dummy->hw_token = (token & ~(0x80));
202862306a36Sopenharmony_ci			wmb();
202962306a36Sopenharmony_ci			dummy->hw_token = token;
203062306a36Sopenharmony_ci
203162306a36Sopenharmony_ci			urb->hcpriv = qh_get(qh);
203262306a36Sopenharmony_ci		}
203362306a36Sopenharmony_ci	}
203462306a36Sopenharmony_ci	return qh;
203562306a36Sopenharmony_ci}
203662306a36Sopenharmony_ci
203762306a36Sopenharmony_cistatic int submit_async(struct oxu_hcd	*oxu, struct urb *urb,
203862306a36Sopenharmony_ci			struct list_head *qtd_list, gfp_t mem_flags)
203962306a36Sopenharmony_ci{
204062306a36Sopenharmony_ci	int epnum = urb->ep->desc.bEndpointAddress;
204162306a36Sopenharmony_ci	unsigned long flags;
204262306a36Sopenharmony_ci	struct ehci_qh *qh = NULL;
204362306a36Sopenharmony_ci	int rc = 0;
204462306a36Sopenharmony_ci#ifdef OXU_URB_TRACE
204562306a36Sopenharmony_ci	struct ehci_qtd	*qtd;
204662306a36Sopenharmony_ci
204762306a36Sopenharmony_ci	qtd = list_entry(qtd_list->next, struct ehci_qtd, qtd_list);
204862306a36Sopenharmony_ci
204962306a36Sopenharmony_ci	oxu_dbg(oxu, "%s %s urb %p ep%d%s len %d, qtd %p [qh %p]\n",
205062306a36Sopenharmony_ci		__func__, urb->dev->devpath, urb,
205162306a36Sopenharmony_ci		epnum & 0x0f, (epnum & USB_DIR_IN) ? "in" : "out",
205262306a36Sopenharmony_ci		urb->transfer_buffer_length,
205362306a36Sopenharmony_ci		qtd, urb->ep->hcpriv);
205462306a36Sopenharmony_ci#endif
205562306a36Sopenharmony_ci
205662306a36Sopenharmony_ci	spin_lock_irqsave(&oxu->lock, flags);
205762306a36Sopenharmony_ci	if (unlikely(!HCD_HW_ACCESSIBLE(oxu_to_hcd(oxu)))) {
205862306a36Sopenharmony_ci		rc = -ESHUTDOWN;
205962306a36Sopenharmony_ci		goto done;
206062306a36Sopenharmony_ci	}
206162306a36Sopenharmony_ci
206262306a36Sopenharmony_ci	qh = qh_append_tds(oxu, urb, qtd_list, epnum, &urb->ep->hcpriv);
206362306a36Sopenharmony_ci	if (unlikely(qh == NULL)) {
206462306a36Sopenharmony_ci		rc = -ENOMEM;
206562306a36Sopenharmony_ci		goto done;
206662306a36Sopenharmony_ci	}
206762306a36Sopenharmony_ci
206862306a36Sopenharmony_ci	/* Control/bulk operations through TTs don't need scheduling,
206962306a36Sopenharmony_ci	 * the HC and TT handle it when the TT has a buffer ready.
207062306a36Sopenharmony_ci	 */
207162306a36Sopenharmony_ci	if (likely(qh->qh_state == QH_STATE_IDLE))
207262306a36Sopenharmony_ci		qh_link_async(oxu, qh_get(qh));
207362306a36Sopenharmony_cidone:
207462306a36Sopenharmony_ci	spin_unlock_irqrestore(&oxu->lock, flags);
207562306a36Sopenharmony_ci	if (unlikely(qh == NULL))
207662306a36Sopenharmony_ci		qtd_list_free(oxu, urb, qtd_list);
207762306a36Sopenharmony_ci	return rc;
207862306a36Sopenharmony_ci}
207962306a36Sopenharmony_ci
208062306a36Sopenharmony_ci/* The async qh for the qtds being reclaimed are now unlinked from the HC */
208162306a36Sopenharmony_ci
208262306a36Sopenharmony_cistatic void end_unlink_async(struct oxu_hcd *oxu)
208362306a36Sopenharmony_ci{
208462306a36Sopenharmony_ci	struct ehci_qh *qh = oxu->reclaim;
208562306a36Sopenharmony_ci	struct ehci_qh *next;
208662306a36Sopenharmony_ci
208762306a36Sopenharmony_ci	timer_action_done(oxu, TIMER_IAA_WATCHDOG);
208862306a36Sopenharmony_ci
208962306a36Sopenharmony_ci	qh->qh_state = QH_STATE_IDLE;
209062306a36Sopenharmony_ci	qh->qh_next.qh = NULL;
209162306a36Sopenharmony_ci	qh_put(qh);			/* refcount from reclaim */
209262306a36Sopenharmony_ci
209362306a36Sopenharmony_ci	/* other unlink(s) may be pending (in QH_STATE_UNLINK_WAIT) */
209462306a36Sopenharmony_ci	next = qh->reclaim;
209562306a36Sopenharmony_ci	oxu->reclaim = next;
209662306a36Sopenharmony_ci	oxu->reclaim_ready = 0;
209762306a36Sopenharmony_ci	qh->reclaim = NULL;
209862306a36Sopenharmony_ci
209962306a36Sopenharmony_ci	qh_completions(oxu, qh);
210062306a36Sopenharmony_ci
210162306a36Sopenharmony_ci	if (!list_empty(&qh->qtd_list)
210262306a36Sopenharmony_ci			&& HC_IS_RUNNING(oxu_to_hcd(oxu)->state))
210362306a36Sopenharmony_ci		qh_link_async(oxu, qh);
210462306a36Sopenharmony_ci	else {
210562306a36Sopenharmony_ci		qh_put(qh);		/* refcount from async list */
210662306a36Sopenharmony_ci
210762306a36Sopenharmony_ci		/* it's not free to turn the async schedule on/off; leave it
210862306a36Sopenharmony_ci		 * active but idle for a while once it empties.
210962306a36Sopenharmony_ci		 */
211062306a36Sopenharmony_ci		if (HC_IS_RUNNING(oxu_to_hcd(oxu)->state)
211162306a36Sopenharmony_ci				&& oxu->async->qh_next.qh == NULL)
211262306a36Sopenharmony_ci			timer_action(oxu, TIMER_ASYNC_OFF);
211362306a36Sopenharmony_ci	}
211462306a36Sopenharmony_ci
211562306a36Sopenharmony_ci	if (next) {
211662306a36Sopenharmony_ci		oxu->reclaim = NULL;
211762306a36Sopenharmony_ci		start_unlink_async(oxu, next);
211862306a36Sopenharmony_ci	}
211962306a36Sopenharmony_ci}
212062306a36Sopenharmony_ci
212162306a36Sopenharmony_ci/* makes sure the async qh will become idle */
212262306a36Sopenharmony_ci/* caller must own oxu->lock */
212362306a36Sopenharmony_ci
212462306a36Sopenharmony_cistatic void start_unlink_async(struct oxu_hcd *oxu, struct ehci_qh *qh)
212562306a36Sopenharmony_ci{
212662306a36Sopenharmony_ci	int cmd = readl(&oxu->regs->command);
212762306a36Sopenharmony_ci	struct ehci_qh *prev;
212862306a36Sopenharmony_ci
212962306a36Sopenharmony_ci#ifdef DEBUG
213062306a36Sopenharmony_ci	assert_spin_locked(&oxu->lock);
213162306a36Sopenharmony_ci	BUG_ON(oxu->reclaim || (qh->qh_state != QH_STATE_LINKED
213262306a36Sopenharmony_ci				&& qh->qh_state != QH_STATE_UNLINK_WAIT));
213362306a36Sopenharmony_ci#endif
213462306a36Sopenharmony_ci
213562306a36Sopenharmony_ci	/* stop async schedule right now? */
213662306a36Sopenharmony_ci	if (unlikely(qh == oxu->async)) {
213762306a36Sopenharmony_ci		/* can't get here without STS_ASS set */
213862306a36Sopenharmony_ci		if (oxu_to_hcd(oxu)->state != HC_STATE_HALT
213962306a36Sopenharmony_ci				&& !oxu->reclaim) {
214062306a36Sopenharmony_ci			/* ... and CMD_IAAD clear */
214162306a36Sopenharmony_ci			writel(cmd & ~CMD_ASE, &oxu->regs->command);
214262306a36Sopenharmony_ci			wmb();
214362306a36Sopenharmony_ci			/* handshake later, if we need to */
214462306a36Sopenharmony_ci			timer_action_done(oxu, TIMER_ASYNC_OFF);
214562306a36Sopenharmony_ci		}
214662306a36Sopenharmony_ci		return;
214762306a36Sopenharmony_ci	}
214862306a36Sopenharmony_ci
214962306a36Sopenharmony_ci	qh->qh_state = QH_STATE_UNLINK;
215062306a36Sopenharmony_ci	oxu->reclaim = qh = qh_get(qh);
215162306a36Sopenharmony_ci
215262306a36Sopenharmony_ci	prev = oxu->async;
215362306a36Sopenharmony_ci	while (prev->qh_next.qh != qh)
215462306a36Sopenharmony_ci		prev = prev->qh_next.qh;
215562306a36Sopenharmony_ci
215662306a36Sopenharmony_ci	prev->hw_next = qh->hw_next;
215762306a36Sopenharmony_ci	prev->qh_next = qh->qh_next;
215862306a36Sopenharmony_ci	wmb();
215962306a36Sopenharmony_ci
216062306a36Sopenharmony_ci	if (unlikely(oxu_to_hcd(oxu)->state == HC_STATE_HALT)) {
216162306a36Sopenharmony_ci		/* if (unlikely(qh->reclaim != 0))
216262306a36Sopenharmony_ci		 *	this will recurse, probably not much
216362306a36Sopenharmony_ci		 */
216462306a36Sopenharmony_ci		end_unlink_async(oxu);
216562306a36Sopenharmony_ci		return;
216662306a36Sopenharmony_ci	}
216762306a36Sopenharmony_ci
216862306a36Sopenharmony_ci	oxu->reclaim_ready = 0;
216962306a36Sopenharmony_ci	cmd |= CMD_IAAD;
217062306a36Sopenharmony_ci	writel(cmd, &oxu->regs->command);
217162306a36Sopenharmony_ci	(void) readl(&oxu->regs->command);
217262306a36Sopenharmony_ci	timer_action(oxu, TIMER_IAA_WATCHDOG);
217362306a36Sopenharmony_ci}
217462306a36Sopenharmony_ci
217562306a36Sopenharmony_cistatic void scan_async(struct oxu_hcd *oxu)
217662306a36Sopenharmony_ci{
217762306a36Sopenharmony_ci	struct ehci_qh *qh;
217862306a36Sopenharmony_ci	enum ehci_timer_action action = TIMER_IO_WATCHDOG;
217962306a36Sopenharmony_ci
218062306a36Sopenharmony_ci	if (!++(oxu->stamp))
218162306a36Sopenharmony_ci		oxu->stamp++;
218262306a36Sopenharmony_ci	timer_action_done(oxu, TIMER_ASYNC_SHRINK);
218362306a36Sopenharmony_cirescan:
218462306a36Sopenharmony_ci	qh = oxu->async->qh_next.qh;
218562306a36Sopenharmony_ci	if (likely(qh != NULL)) {
218662306a36Sopenharmony_ci		do {
218762306a36Sopenharmony_ci			/* clean any finished work for this qh */
218862306a36Sopenharmony_ci			if (!list_empty(&qh->qtd_list)
218962306a36Sopenharmony_ci					&& qh->stamp != oxu->stamp) {
219062306a36Sopenharmony_ci				int temp;
219162306a36Sopenharmony_ci
219262306a36Sopenharmony_ci				/* unlinks could happen here; completion
219362306a36Sopenharmony_ci				 * reporting drops the lock.  rescan using
219462306a36Sopenharmony_ci				 * the latest schedule, but don't rescan
219562306a36Sopenharmony_ci				 * qhs we already finished (no looping).
219662306a36Sopenharmony_ci				 */
219762306a36Sopenharmony_ci				qh = qh_get(qh);
219862306a36Sopenharmony_ci				qh->stamp = oxu->stamp;
219962306a36Sopenharmony_ci				temp = qh_completions(oxu, qh);
220062306a36Sopenharmony_ci				qh_put(qh);
220162306a36Sopenharmony_ci				if (temp != 0)
220262306a36Sopenharmony_ci					goto rescan;
220362306a36Sopenharmony_ci			}
220462306a36Sopenharmony_ci
220562306a36Sopenharmony_ci			/* unlink idle entries, reducing HC PCI usage as well
220662306a36Sopenharmony_ci			 * as HCD schedule-scanning costs.  delay for any qh
220762306a36Sopenharmony_ci			 * we just scanned, there's a not-unusual case that it
220862306a36Sopenharmony_ci			 * doesn't stay idle for long.
220962306a36Sopenharmony_ci			 * (plus, avoids some kind of re-activation race.)
221062306a36Sopenharmony_ci			 */
221162306a36Sopenharmony_ci			if (list_empty(&qh->qtd_list)) {
221262306a36Sopenharmony_ci				if (qh->stamp == oxu->stamp)
221362306a36Sopenharmony_ci					action = TIMER_ASYNC_SHRINK;
221462306a36Sopenharmony_ci				else if (!oxu->reclaim
221562306a36Sopenharmony_ci					    && qh->qh_state == QH_STATE_LINKED)
221662306a36Sopenharmony_ci					start_unlink_async(oxu, qh);
221762306a36Sopenharmony_ci			}
221862306a36Sopenharmony_ci
221962306a36Sopenharmony_ci			qh = qh->qh_next.qh;
222062306a36Sopenharmony_ci		} while (qh);
222162306a36Sopenharmony_ci	}
222262306a36Sopenharmony_ci	if (action == TIMER_ASYNC_SHRINK)
222362306a36Sopenharmony_ci		timer_action(oxu, TIMER_ASYNC_SHRINK);
222462306a36Sopenharmony_ci}
222562306a36Sopenharmony_ci
222662306a36Sopenharmony_ci/*
222762306a36Sopenharmony_ci * periodic_next_shadow - return "next" pointer on shadow list
222862306a36Sopenharmony_ci * @periodic: host pointer to qh/itd/sitd
222962306a36Sopenharmony_ci * @tag: hardware tag for type of this record
223062306a36Sopenharmony_ci */
223162306a36Sopenharmony_cistatic union ehci_shadow *periodic_next_shadow(union ehci_shadow *periodic,
223262306a36Sopenharmony_ci						__le32 tag)
223362306a36Sopenharmony_ci{
223462306a36Sopenharmony_ci	switch (tag) {
223562306a36Sopenharmony_ci	default:
223662306a36Sopenharmony_ci	case Q_TYPE_QH:
223762306a36Sopenharmony_ci		return &periodic->qh->qh_next;
223862306a36Sopenharmony_ci	}
223962306a36Sopenharmony_ci}
224062306a36Sopenharmony_ci
224162306a36Sopenharmony_ci/* caller must hold oxu->lock */
224262306a36Sopenharmony_cistatic void periodic_unlink(struct oxu_hcd *oxu, unsigned frame, void *ptr)
224362306a36Sopenharmony_ci{
224462306a36Sopenharmony_ci	union ehci_shadow *prev_p = &oxu->pshadow[frame];
224562306a36Sopenharmony_ci	__le32 *hw_p = &oxu->periodic[frame];
224662306a36Sopenharmony_ci	union ehci_shadow here = *prev_p;
224762306a36Sopenharmony_ci
224862306a36Sopenharmony_ci	/* find predecessor of "ptr"; hw and shadow lists are in sync */
224962306a36Sopenharmony_ci	while (here.ptr && here.ptr != ptr) {
225062306a36Sopenharmony_ci		prev_p = periodic_next_shadow(prev_p, Q_NEXT_TYPE(*hw_p));
225162306a36Sopenharmony_ci		hw_p = here.hw_next;
225262306a36Sopenharmony_ci		here = *prev_p;
225362306a36Sopenharmony_ci	}
225462306a36Sopenharmony_ci	/* an interrupt entry (at list end) could have been shared */
225562306a36Sopenharmony_ci	if (!here.ptr)
225662306a36Sopenharmony_ci		return;
225762306a36Sopenharmony_ci
225862306a36Sopenharmony_ci	/* update shadow and hardware lists ... the old "next" pointers
225962306a36Sopenharmony_ci	 * from ptr may still be in use, the caller updates them.
226062306a36Sopenharmony_ci	 */
226162306a36Sopenharmony_ci	*prev_p = *periodic_next_shadow(&here, Q_NEXT_TYPE(*hw_p));
226262306a36Sopenharmony_ci	*hw_p = *here.hw_next;
226362306a36Sopenharmony_ci}
226462306a36Sopenharmony_ci
226562306a36Sopenharmony_ci/* how many of the uframe's 125 usecs are allocated? */
226662306a36Sopenharmony_cistatic unsigned short periodic_usecs(struct oxu_hcd *oxu,
226762306a36Sopenharmony_ci					unsigned frame, unsigned uframe)
226862306a36Sopenharmony_ci{
226962306a36Sopenharmony_ci	__le32 *hw_p = &oxu->periodic[frame];
227062306a36Sopenharmony_ci	union ehci_shadow *q = &oxu->pshadow[frame];
227162306a36Sopenharmony_ci	unsigned usecs = 0;
227262306a36Sopenharmony_ci
227362306a36Sopenharmony_ci	while (q->ptr) {
227462306a36Sopenharmony_ci		switch (Q_NEXT_TYPE(*hw_p)) {
227562306a36Sopenharmony_ci		case Q_TYPE_QH:
227662306a36Sopenharmony_ci		default:
227762306a36Sopenharmony_ci			/* is it in the S-mask? */
227862306a36Sopenharmony_ci			if (q->qh->hw_info2 & cpu_to_le32(1 << uframe))
227962306a36Sopenharmony_ci				usecs += q->qh->usecs;
228062306a36Sopenharmony_ci			/* ... or C-mask? */
228162306a36Sopenharmony_ci			if (q->qh->hw_info2 & cpu_to_le32(1 << (8 + uframe)))
228262306a36Sopenharmony_ci				usecs += q->qh->c_usecs;
228362306a36Sopenharmony_ci			hw_p = &q->qh->hw_next;
228462306a36Sopenharmony_ci			q = &q->qh->qh_next;
228562306a36Sopenharmony_ci			break;
228662306a36Sopenharmony_ci		}
228762306a36Sopenharmony_ci	}
228862306a36Sopenharmony_ci#ifdef DEBUG
228962306a36Sopenharmony_ci	if (usecs > 100)
229062306a36Sopenharmony_ci		oxu_err(oxu, "uframe %d sched overrun: %d usecs\n",
229162306a36Sopenharmony_ci						frame * 8 + uframe, usecs);
229262306a36Sopenharmony_ci#endif
229362306a36Sopenharmony_ci	return usecs;
229462306a36Sopenharmony_ci}
229562306a36Sopenharmony_ci
229662306a36Sopenharmony_cistatic int enable_periodic(struct oxu_hcd *oxu)
229762306a36Sopenharmony_ci{
229862306a36Sopenharmony_ci	u32 cmd;
229962306a36Sopenharmony_ci	int status;
230062306a36Sopenharmony_ci
230162306a36Sopenharmony_ci	/* did clearing PSE did take effect yet?
230262306a36Sopenharmony_ci	 * takes effect only at frame boundaries...
230362306a36Sopenharmony_ci	 */
230462306a36Sopenharmony_ci	status = handshake(oxu, &oxu->regs->status, STS_PSS, 0, 9 * 125);
230562306a36Sopenharmony_ci	if (status != 0) {
230662306a36Sopenharmony_ci		oxu_to_hcd(oxu)->state = HC_STATE_HALT;
230762306a36Sopenharmony_ci		usb_hc_died(oxu_to_hcd(oxu));
230862306a36Sopenharmony_ci		return status;
230962306a36Sopenharmony_ci	}
231062306a36Sopenharmony_ci
231162306a36Sopenharmony_ci	cmd = readl(&oxu->regs->command) | CMD_PSE;
231262306a36Sopenharmony_ci	writel(cmd, &oxu->regs->command);
231362306a36Sopenharmony_ci	/* posted write ... PSS happens later */
231462306a36Sopenharmony_ci	oxu_to_hcd(oxu)->state = HC_STATE_RUNNING;
231562306a36Sopenharmony_ci
231662306a36Sopenharmony_ci	/* make sure ehci_work scans these */
231762306a36Sopenharmony_ci	oxu->next_uframe = readl(&oxu->regs->frame_index)
231862306a36Sopenharmony_ci		% (oxu->periodic_size << 3);
231962306a36Sopenharmony_ci	return 0;
232062306a36Sopenharmony_ci}
232162306a36Sopenharmony_ci
232262306a36Sopenharmony_cistatic int disable_periodic(struct oxu_hcd *oxu)
232362306a36Sopenharmony_ci{
232462306a36Sopenharmony_ci	u32 cmd;
232562306a36Sopenharmony_ci	int status;
232662306a36Sopenharmony_ci
232762306a36Sopenharmony_ci	/* did setting PSE not take effect yet?
232862306a36Sopenharmony_ci	 * takes effect only at frame boundaries...
232962306a36Sopenharmony_ci	 */
233062306a36Sopenharmony_ci	status = handshake(oxu, &oxu->regs->status, STS_PSS, STS_PSS, 9 * 125);
233162306a36Sopenharmony_ci	if (status != 0) {
233262306a36Sopenharmony_ci		oxu_to_hcd(oxu)->state = HC_STATE_HALT;
233362306a36Sopenharmony_ci		usb_hc_died(oxu_to_hcd(oxu));
233462306a36Sopenharmony_ci		return status;
233562306a36Sopenharmony_ci	}
233662306a36Sopenharmony_ci
233762306a36Sopenharmony_ci	cmd = readl(&oxu->regs->command) & ~CMD_PSE;
233862306a36Sopenharmony_ci	writel(cmd, &oxu->regs->command);
233962306a36Sopenharmony_ci	/* posted write ... */
234062306a36Sopenharmony_ci
234162306a36Sopenharmony_ci	oxu->next_uframe = -1;
234262306a36Sopenharmony_ci	return 0;
234362306a36Sopenharmony_ci}
234462306a36Sopenharmony_ci
234562306a36Sopenharmony_ci/* periodic schedule slots have iso tds (normal or split) first, then a
234662306a36Sopenharmony_ci * sparse tree for active interrupt transfers.
234762306a36Sopenharmony_ci *
234862306a36Sopenharmony_ci * this just links in a qh; caller guarantees uframe masks are set right.
234962306a36Sopenharmony_ci * no FSTN support (yet; oxu 0.96+)
235062306a36Sopenharmony_ci */
235162306a36Sopenharmony_cistatic int qh_link_periodic(struct oxu_hcd *oxu, struct ehci_qh *qh)
235262306a36Sopenharmony_ci{
235362306a36Sopenharmony_ci	unsigned i;
235462306a36Sopenharmony_ci	unsigned period = qh->period;
235562306a36Sopenharmony_ci
235662306a36Sopenharmony_ci	dev_dbg(&qh->dev->dev,
235762306a36Sopenharmony_ci		"link qh%d-%04x/%p start %d [%d/%d us]\n",
235862306a36Sopenharmony_ci		period, le32_to_cpup(&qh->hw_info2) & (QH_CMASK | QH_SMASK),
235962306a36Sopenharmony_ci		qh, qh->start, qh->usecs, qh->c_usecs);
236062306a36Sopenharmony_ci
236162306a36Sopenharmony_ci	/* high bandwidth, or otherwise every microframe */
236262306a36Sopenharmony_ci	if (period == 0)
236362306a36Sopenharmony_ci		period = 1;
236462306a36Sopenharmony_ci
236562306a36Sopenharmony_ci	for (i = qh->start; i < oxu->periodic_size; i += period) {
236662306a36Sopenharmony_ci		union ehci_shadow	*prev = &oxu->pshadow[i];
236762306a36Sopenharmony_ci		__le32			*hw_p = &oxu->periodic[i];
236862306a36Sopenharmony_ci		union ehci_shadow	here = *prev;
236962306a36Sopenharmony_ci		__le32			type = 0;
237062306a36Sopenharmony_ci
237162306a36Sopenharmony_ci		/* skip the iso nodes at list head */
237262306a36Sopenharmony_ci		while (here.ptr) {
237362306a36Sopenharmony_ci			type = Q_NEXT_TYPE(*hw_p);
237462306a36Sopenharmony_ci			if (type == Q_TYPE_QH)
237562306a36Sopenharmony_ci				break;
237662306a36Sopenharmony_ci			prev = periodic_next_shadow(prev, type);
237762306a36Sopenharmony_ci			hw_p = &here.qh->hw_next;
237862306a36Sopenharmony_ci			here = *prev;
237962306a36Sopenharmony_ci		}
238062306a36Sopenharmony_ci
238162306a36Sopenharmony_ci		/* sorting each branch by period (slow-->fast)
238262306a36Sopenharmony_ci		 * enables sharing interior tree nodes
238362306a36Sopenharmony_ci		 */
238462306a36Sopenharmony_ci		while (here.ptr && qh != here.qh) {
238562306a36Sopenharmony_ci			if (qh->period > here.qh->period)
238662306a36Sopenharmony_ci				break;
238762306a36Sopenharmony_ci			prev = &here.qh->qh_next;
238862306a36Sopenharmony_ci			hw_p = &here.qh->hw_next;
238962306a36Sopenharmony_ci			here = *prev;
239062306a36Sopenharmony_ci		}
239162306a36Sopenharmony_ci		/* link in this qh, unless some earlier pass did that */
239262306a36Sopenharmony_ci		if (qh != here.qh) {
239362306a36Sopenharmony_ci			qh->qh_next = here;
239462306a36Sopenharmony_ci			if (here.qh)
239562306a36Sopenharmony_ci				qh->hw_next = *hw_p;
239662306a36Sopenharmony_ci			wmb();
239762306a36Sopenharmony_ci			prev->qh = qh;
239862306a36Sopenharmony_ci			*hw_p = QH_NEXT(qh->qh_dma);
239962306a36Sopenharmony_ci		}
240062306a36Sopenharmony_ci	}
240162306a36Sopenharmony_ci	qh->qh_state = QH_STATE_LINKED;
240262306a36Sopenharmony_ci	qh_get(qh);
240362306a36Sopenharmony_ci
240462306a36Sopenharmony_ci	/* update per-qh bandwidth for usbfs */
240562306a36Sopenharmony_ci	oxu_to_hcd(oxu)->self.bandwidth_allocated += qh->period
240662306a36Sopenharmony_ci		? ((qh->usecs + qh->c_usecs) / qh->period)
240762306a36Sopenharmony_ci		: (qh->usecs * 8);
240862306a36Sopenharmony_ci
240962306a36Sopenharmony_ci	/* maybe enable periodic schedule processing */
241062306a36Sopenharmony_ci	if (!oxu->periodic_sched++)
241162306a36Sopenharmony_ci		return enable_periodic(oxu);
241262306a36Sopenharmony_ci
241362306a36Sopenharmony_ci	return 0;
241462306a36Sopenharmony_ci}
241562306a36Sopenharmony_ci
241662306a36Sopenharmony_cistatic void qh_unlink_periodic(struct oxu_hcd *oxu, struct ehci_qh *qh)
241762306a36Sopenharmony_ci{
241862306a36Sopenharmony_ci	unsigned i;
241962306a36Sopenharmony_ci	unsigned period;
242062306a36Sopenharmony_ci
242162306a36Sopenharmony_ci	/* FIXME:
242262306a36Sopenharmony_ci	 *   IF this isn't high speed
242362306a36Sopenharmony_ci	 *   and this qh is active in the current uframe
242462306a36Sopenharmony_ci	 *   (and overlay token SplitXstate is false?)
242562306a36Sopenharmony_ci	 * THEN
242662306a36Sopenharmony_ci	 *   qh->hw_info1 |= cpu_to_le32(1 << 7 "ignore");
242762306a36Sopenharmony_ci	 */
242862306a36Sopenharmony_ci
242962306a36Sopenharmony_ci	/* high bandwidth, or otherwise part of every microframe */
243062306a36Sopenharmony_ci	period = qh->period;
243162306a36Sopenharmony_ci	if (period == 0)
243262306a36Sopenharmony_ci		period = 1;
243362306a36Sopenharmony_ci
243462306a36Sopenharmony_ci	for (i = qh->start; i < oxu->periodic_size; i += period)
243562306a36Sopenharmony_ci		periodic_unlink(oxu, i, qh);
243662306a36Sopenharmony_ci
243762306a36Sopenharmony_ci	/* update per-qh bandwidth for usbfs */
243862306a36Sopenharmony_ci	oxu_to_hcd(oxu)->self.bandwidth_allocated -= qh->period
243962306a36Sopenharmony_ci		? ((qh->usecs + qh->c_usecs) / qh->period)
244062306a36Sopenharmony_ci		: (qh->usecs * 8);
244162306a36Sopenharmony_ci
244262306a36Sopenharmony_ci	dev_dbg(&qh->dev->dev,
244362306a36Sopenharmony_ci		"unlink qh%d-%04x/%p start %d [%d/%d us]\n",
244462306a36Sopenharmony_ci		qh->period,
244562306a36Sopenharmony_ci		le32_to_cpup(&qh->hw_info2) & (QH_CMASK | QH_SMASK),
244662306a36Sopenharmony_ci		qh, qh->start, qh->usecs, qh->c_usecs);
244762306a36Sopenharmony_ci
244862306a36Sopenharmony_ci	/* qh->qh_next still "live" to HC */
244962306a36Sopenharmony_ci	qh->qh_state = QH_STATE_UNLINK;
245062306a36Sopenharmony_ci	qh->qh_next.ptr = NULL;
245162306a36Sopenharmony_ci	qh_put(qh);
245262306a36Sopenharmony_ci
245362306a36Sopenharmony_ci	/* maybe turn off periodic schedule */
245462306a36Sopenharmony_ci	oxu->periodic_sched--;
245562306a36Sopenharmony_ci	if (!oxu->periodic_sched)
245662306a36Sopenharmony_ci		(void) disable_periodic(oxu);
245762306a36Sopenharmony_ci}
245862306a36Sopenharmony_ci
245962306a36Sopenharmony_cistatic void intr_deschedule(struct oxu_hcd *oxu, struct ehci_qh *qh)
246062306a36Sopenharmony_ci{
246162306a36Sopenharmony_ci	unsigned wait;
246262306a36Sopenharmony_ci
246362306a36Sopenharmony_ci	qh_unlink_periodic(oxu, qh);
246462306a36Sopenharmony_ci
246562306a36Sopenharmony_ci	/* simple/paranoid:  always delay, expecting the HC needs to read
246662306a36Sopenharmony_ci	 * qh->hw_next or finish a writeback after SPLIT/CSPLIT ... and
246762306a36Sopenharmony_ci	 * expect hub_wq to clean up after any CSPLITs we won't issue.
246862306a36Sopenharmony_ci	 * active high speed queues may need bigger delays...
246962306a36Sopenharmony_ci	 */
247062306a36Sopenharmony_ci	if (list_empty(&qh->qtd_list)
247162306a36Sopenharmony_ci		|| (cpu_to_le32(QH_CMASK) & qh->hw_info2) != 0)
247262306a36Sopenharmony_ci		wait = 2;
247362306a36Sopenharmony_ci	else
247462306a36Sopenharmony_ci		wait = 55;	/* worst case: 3 * 1024 */
247562306a36Sopenharmony_ci
247662306a36Sopenharmony_ci	udelay(wait);
247762306a36Sopenharmony_ci	qh->qh_state = QH_STATE_IDLE;
247862306a36Sopenharmony_ci	qh->hw_next = EHCI_LIST_END;
247962306a36Sopenharmony_ci	wmb();
248062306a36Sopenharmony_ci}
248162306a36Sopenharmony_ci
248262306a36Sopenharmony_cistatic int check_period(struct oxu_hcd *oxu,
248362306a36Sopenharmony_ci			unsigned frame, unsigned uframe,
248462306a36Sopenharmony_ci			unsigned period, unsigned usecs)
248562306a36Sopenharmony_ci{
248662306a36Sopenharmony_ci	int claimed;
248762306a36Sopenharmony_ci
248862306a36Sopenharmony_ci	/* complete split running into next frame?
248962306a36Sopenharmony_ci	 * given FSTN support, we could sometimes check...
249062306a36Sopenharmony_ci	 */
249162306a36Sopenharmony_ci	if (uframe >= 8)
249262306a36Sopenharmony_ci		return 0;
249362306a36Sopenharmony_ci
249462306a36Sopenharmony_ci	/*
249562306a36Sopenharmony_ci	 * 80% periodic == 100 usec/uframe available
249662306a36Sopenharmony_ci	 * convert "usecs we need" to "max already claimed"
249762306a36Sopenharmony_ci	 */
249862306a36Sopenharmony_ci	usecs = 100 - usecs;
249962306a36Sopenharmony_ci
250062306a36Sopenharmony_ci	/* we "know" 2 and 4 uframe intervals were rejected; so
250162306a36Sopenharmony_ci	 * for period 0, check _every_ microframe in the schedule.
250262306a36Sopenharmony_ci	 */
250362306a36Sopenharmony_ci	if (unlikely(period == 0)) {
250462306a36Sopenharmony_ci		do {
250562306a36Sopenharmony_ci			for (uframe = 0; uframe < 7; uframe++) {
250662306a36Sopenharmony_ci				claimed = periodic_usecs(oxu, frame, uframe);
250762306a36Sopenharmony_ci				if (claimed > usecs)
250862306a36Sopenharmony_ci					return 0;
250962306a36Sopenharmony_ci			}
251062306a36Sopenharmony_ci		} while ((frame += 1) < oxu->periodic_size);
251162306a36Sopenharmony_ci
251262306a36Sopenharmony_ci	/* just check the specified uframe, at that period */
251362306a36Sopenharmony_ci	} else {
251462306a36Sopenharmony_ci		do {
251562306a36Sopenharmony_ci			claimed = periodic_usecs(oxu, frame, uframe);
251662306a36Sopenharmony_ci			if (claimed > usecs)
251762306a36Sopenharmony_ci				return 0;
251862306a36Sopenharmony_ci		} while ((frame += period) < oxu->periodic_size);
251962306a36Sopenharmony_ci	}
252062306a36Sopenharmony_ci
252162306a36Sopenharmony_ci	return 1;
252262306a36Sopenharmony_ci}
252362306a36Sopenharmony_ci
252462306a36Sopenharmony_cistatic int check_intr_schedule(struct oxu_hcd	*oxu,
252562306a36Sopenharmony_ci				unsigned frame, unsigned uframe,
252662306a36Sopenharmony_ci				const struct ehci_qh *qh, __le32 *c_maskp)
252762306a36Sopenharmony_ci{
252862306a36Sopenharmony_ci	int retval = -ENOSPC;
252962306a36Sopenharmony_ci
253062306a36Sopenharmony_ci	if (qh->c_usecs && uframe >= 6)		/* FSTN territory? */
253162306a36Sopenharmony_ci		goto done;
253262306a36Sopenharmony_ci
253362306a36Sopenharmony_ci	if (!check_period(oxu, frame, uframe, qh->period, qh->usecs))
253462306a36Sopenharmony_ci		goto done;
253562306a36Sopenharmony_ci	if (!qh->c_usecs) {
253662306a36Sopenharmony_ci		retval = 0;
253762306a36Sopenharmony_ci		*c_maskp = 0;
253862306a36Sopenharmony_ci		goto done;
253962306a36Sopenharmony_ci	}
254062306a36Sopenharmony_ci
254162306a36Sopenharmony_cidone:
254262306a36Sopenharmony_ci	return retval;
254362306a36Sopenharmony_ci}
254462306a36Sopenharmony_ci
254562306a36Sopenharmony_ci/* "first fit" scheduling policy used the first time through,
254662306a36Sopenharmony_ci * or when the previous schedule slot can't be re-used.
254762306a36Sopenharmony_ci */
254862306a36Sopenharmony_cistatic int qh_schedule(struct oxu_hcd *oxu, struct ehci_qh *qh)
254962306a36Sopenharmony_ci{
255062306a36Sopenharmony_ci	int		status;
255162306a36Sopenharmony_ci	unsigned	uframe;
255262306a36Sopenharmony_ci	__le32		c_mask;
255362306a36Sopenharmony_ci	unsigned	frame;		/* 0..(qh->period - 1), or NO_FRAME */
255462306a36Sopenharmony_ci
255562306a36Sopenharmony_ci	qh_refresh(oxu, qh);
255662306a36Sopenharmony_ci	qh->hw_next = EHCI_LIST_END;
255762306a36Sopenharmony_ci	frame = qh->start;
255862306a36Sopenharmony_ci
255962306a36Sopenharmony_ci	/* reuse the previous schedule slots, if we can */
256062306a36Sopenharmony_ci	if (frame < qh->period) {
256162306a36Sopenharmony_ci		uframe = ffs(le32_to_cpup(&qh->hw_info2) & QH_SMASK);
256262306a36Sopenharmony_ci		status = check_intr_schedule(oxu, frame, --uframe,
256362306a36Sopenharmony_ci				qh, &c_mask);
256462306a36Sopenharmony_ci	} else {
256562306a36Sopenharmony_ci		uframe = 0;
256662306a36Sopenharmony_ci		c_mask = 0;
256762306a36Sopenharmony_ci		status = -ENOSPC;
256862306a36Sopenharmony_ci	}
256962306a36Sopenharmony_ci
257062306a36Sopenharmony_ci	/* else scan the schedule to find a group of slots such that all
257162306a36Sopenharmony_ci	 * uframes have enough periodic bandwidth available.
257262306a36Sopenharmony_ci	 */
257362306a36Sopenharmony_ci	if (status) {
257462306a36Sopenharmony_ci		/* "normal" case, uframing flexible except with splits */
257562306a36Sopenharmony_ci		if (qh->period) {
257662306a36Sopenharmony_ci			frame = qh->period - 1;
257762306a36Sopenharmony_ci			do {
257862306a36Sopenharmony_ci				for (uframe = 0; uframe < 8; uframe++) {
257962306a36Sopenharmony_ci					status = check_intr_schedule(oxu,
258062306a36Sopenharmony_ci							frame, uframe, qh,
258162306a36Sopenharmony_ci							&c_mask);
258262306a36Sopenharmony_ci					if (status == 0)
258362306a36Sopenharmony_ci						break;
258462306a36Sopenharmony_ci				}
258562306a36Sopenharmony_ci			} while (status && frame--);
258662306a36Sopenharmony_ci
258762306a36Sopenharmony_ci		/* qh->period == 0 means every uframe */
258862306a36Sopenharmony_ci		} else {
258962306a36Sopenharmony_ci			frame = 0;
259062306a36Sopenharmony_ci			status = check_intr_schedule(oxu, 0, 0, qh, &c_mask);
259162306a36Sopenharmony_ci		}
259262306a36Sopenharmony_ci		if (status)
259362306a36Sopenharmony_ci			goto done;
259462306a36Sopenharmony_ci		qh->start = frame;
259562306a36Sopenharmony_ci
259662306a36Sopenharmony_ci		/* reset S-frame and (maybe) C-frame masks */
259762306a36Sopenharmony_ci		qh->hw_info2 &= cpu_to_le32(~(QH_CMASK | QH_SMASK));
259862306a36Sopenharmony_ci		qh->hw_info2 |= qh->period
259962306a36Sopenharmony_ci			? cpu_to_le32(1 << uframe)
260062306a36Sopenharmony_ci			: cpu_to_le32(QH_SMASK);
260162306a36Sopenharmony_ci		qh->hw_info2 |= c_mask;
260262306a36Sopenharmony_ci	} else
260362306a36Sopenharmony_ci		oxu_dbg(oxu, "reused qh %p schedule\n", qh);
260462306a36Sopenharmony_ci
260562306a36Sopenharmony_ci	/* stuff into the periodic schedule */
260662306a36Sopenharmony_ci	status = qh_link_periodic(oxu, qh);
260762306a36Sopenharmony_cidone:
260862306a36Sopenharmony_ci	return status;
260962306a36Sopenharmony_ci}
261062306a36Sopenharmony_ci
261162306a36Sopenharmony_cistatic int intr_submit(struct oxu_hcd *oxu, struct urb *urb,
261262306a36Sopenharmony_ci			struct list_head *qtd_list, gfp_t mem_flags)
261362306a36Sopenharmony_ci{
261462306a36Sopenharmony_ci	unsigned epnum;
261562306a36Sopenharmony_ci	unsigned long flags;
261662306a36Sopenharmony_ci	struct ehci_qh *qh;
261762306a36Sopenharmony_ci	int status = 0;
261862306a36Sopenharmony_ci	struct list_head	empty;
261962306a36Sopenharmony_ci
262062306a36Sopenharmony_ci	/* get endpoint and transfer/schedule data */
262162306a36Sopenharmony_ci	epnum = urb->ep->desc.bEndpointAddress;
262262306a36Sopenharmony_ci
262362306a36Sopenharmony_ci	spin_lock_irqsave(&oxu->lock, flags);
262462306a36Sopenharmony_ci
262562306a36Sopenharmony_ci	if (unlikely(!HCD_HW_ACCESSIBLE(oxu_to_hcd(oxu)))) {
262662306a36Sopenharmony_ci		status = -ESHUTDOWN;
262762306a36Sopenharmony_ci		goto done;
262862306a36Sopenharmony_ci	}
262962306a36Sopenharmony_ci
263062306a36Sopenharmony_ci	/* get qh and force any scheduling errors */
263162306a36Sopenharmony_ci	INIT_LIST_HEAD(&empty);
263262306a36Sopenharmony_ci	qh = qh_append_tds(oxu, urb, &empty, epnum, &urb->ep->hcpriv);
263362306a36Sopenharmony_ci	if (qh == NULL) {
263462306a36Sopenharmony_ci		status = -ENOMEM;
263562306a36Sopenharmony_ci		goto done;
263662306a36Sopenharmony_ci	}
263762306a36Sopenharmony_ci	if (qh->qh_state == QH_STATE_IDLE) {
263862306a36Sopenharmony_ci		status = qh_schedule(oxu, qh);
263962306a36Sopenharmony_ci		if (status != 0)
264062306a36Sopenharmony_ci			goto done;
264162306a36Sopenharmony_ci	}
264262306a36Sopenharmony_ci
264362306a36Sopenharmony_ci	/* then queue the urb's tds to the qh */
264462306a36Sopenharmony_ci	qh = qh_append_tds(oxu, urb, qtd_list, epnum, &urb->ep->hcpriv);
264562306a36Sopenharmony_ci	BUG_ON(qh == NULL);
264662306a36Sopenharmony_ci
264762306a36Sopenharmony_ci	/* ... update usbfs periodic stats */
264862306a36Sopenharmony_ci	oxu_to_hcd(oxu)->self.bandwidth_int_reqs++;
264962306a36Sopenharmony_ci
265062306a36Sopenharmony_cidone:
265162306a36Sopenharmony_ci	spin_unlock_irqrestore(&oxu->lock, flags);
265262306a36Sopenharmony_ci	if (status)
265362306a36Sopenharmony_ci		qtd_list_free(oxu, urb, qtd_list);
265462306a36Sopenharmony_ci
265562306a36Sopenharmony_ci	return status;
265662306a36Sopenharmony_ci}
265762306a36Sopenharmony_ci
265862306a36Sopenharmony_cistatic inline int itd_submit(struct oxu_hcd *oxu, struct urb *urb,
265962306a36Sopenharmony_ci						gfp_t mem_flags)
266062306a36Sopenharmony_ci{
266162306a36Sopenharmony_ci	oxu_dbg(oxu, "iso support is missing!\n");
266262306a36Sopenharmony_ci	return -ENOSYS;
266362306a36Sopenharmony_ci}
266462306a36Sopenharmony_ci
266562306a36Sopenharmony_cistatic inline int sitd_submit(struct oxu_hcd *oxu, struct urb *urb,
266662306a36Sopenharmony_ci						gfp_t mem_flags)
266762306a36Sopenharmony_ci{
266862306a36Sopenharmony_ci	oxu_dbg(oxu, "split iso support is missing!\n");
266962306a36Sopenharmony_ci	return -ENOSYS;
267062306a36Sopenharmony_ci}
267162306a36Sopenharmony_ci
267262306a36Sopenharmony_cistatic void scan_periodic(struct oxu_hcd *oxu)
267362306a36Sopenharmony_ci{
267462306a36Sopenharmony_ci	unsigned frame, clock, now_uframe, mod;
267562306a36Sopenharmony_ci	unsigned modified;
267662306a36Sopenharmony_ci
267762306a36Sopenharmony_ci	mod = oxu->periodic_size << 3;
267862306a36Sopenharmony_ci
267962306a36Sopenharmony_ci	/*
268062306a36Sopenharmony_ci	 * When running, scan from last scan point up to "now"
268162306a36Sopenharmony_ci	 * else clean up by scanning everything that's left.
268262306a36Sopenharmony_ci	 * Touches as few pages as possible:  cache-friendly.
268362306a36Sopenharmony_ci	 */
268462306a36Sopenharmony_ci	now_uframe = oxu->next_uframe;
268562306a36Sopenharmony_ci	if (HC_IS_RUNNING(oxu_to_hcd(oxu)->state))
268662306a36Sopenharmony_ci		clock = readl(&oxu->regs->frame_index);
268762306a36Sopenharmony_ci	else
268862306a36Sopenharmony_ci		clock = now_uframe + mod - 1;
268962306a36Sopenharmony_ci	clock %= mod;
269062306a36Sopenharmony_ci
269162306a36Sopenharmony_ci	for (;;) {
269262306a36Sopenharmony_ci		union ehci_shadow	q, *q_p;
269362306a36Sopenharmony_ci		__le32			type, *hw_p;
269462306a36Sopenharmony_ci
269562306a36Sopenharmony_ci		/* don't scan past the live uframe */
269662306a36Sopenharmony_ci		frame = now_uframe >> 3;
269762306a36Sopenharmony_ci		if (frame != (clock >> 3)) {
269862306a36Sopenharmony_ci			/* safe to scan the whole frame at once */
269962306a36Sopenharmony_ci			now_uframe |= 0x07;
270062306a36Sopenharmony_ci		}
270162306a36Sopenharmony_ci
270262306a36Sopenharmony_cirestart:
270362306a36Sopenharmony_ci		/* scan each element in frame's queue for completions */
270462306a36Sopenharmony_ci		q_p = &oxu->pshadow[frame];
270562306a36Sopenharmony_ci		hw_p = &oxu->periodic[frame];
270662306a36Sopenharmony_ci		q.ptr = q_p->ptr;
270762306a36Sopenharmony_ci		type = Q_NEXT_TYPE(*hw_p);
270862306a36Sopenharmony_ci		modified = 0;
270962306a36Sopenharmony_ci
271062306a36Sopenharmony_ci		while (q.ptr != NULL) {
271162306a36Sopenharmony_ci			union ehci_shadow temp;
271262306a36Sopenharmony_ci
271362306a36Sopenharmony_ci			switch (type) {
271462306a36Sopenharmony_ci			case Q_TYPE_QH:
271562306a36Sopenharmony_ci				/* handle any completions */
271662306a36Sopenharmony_ci				temp.qh = qh_get(q.qh);
271762306a36Sopenharmony_ci				type = Q_NEXT_TYPE(q.qh->hw_next);
271862306a36Sopenharmony_ci				q = q.qh->qh_next;
271962306a36Sopenharmony_ci				modified = qh_completions(oxu, temp.qh);
272062306a36Sopenharmony_ci				if (unlikely(list_empty(&temp.qh->qtd_list)))
272162306a36Sopenharmony_ci					intr_deschedule(oxu, temp.qh);
272262306a36Sopenharmony_ci				qh_put(temp.qh);
272362306a36Sopenharmony_ci				break;
272462306a36Sopenharmony_ci			default:
272562306a36Sopenharmony_ci				oxu_dbg(oxu, "corrupt type %d frame %d shadow %p\n",
272662306a36Sopenharmony_ci					type, frame, q.ptr);
272762306a36Sopenharmony_ci				q.ptr = NULL;
272862306a36Sopenharmony_ci			}
272962306a36Sopenharmony_ci
273062306a36Sopenharmony_ci			/* assume completion callbacks modify the queue */
273162306a36Sopenharmony_ci			if (unlikely(modified))
273262306a36Sopenharmony_ci				goto restart;
273362306a36Sopenharmony_ci		}
273462306a36Sopenharmony_ci
273562306a36Sopenharmony_ci		/* Stop when we catch up to the HC */
273662306a36Sopenharmony_ci
273762306a36Sopenharmony_ci		/* FIXME:  this assumes we won't get lapped when
273862306a36Sopenharmony_ci		 * latencies climb; that should be rare, but...
273962306a36Sopenharmony_ci		 * detect it, and just go all the way around.
274062306a36Sopenharmony_ci		 * FLR might help detect this case, so long as latencies
274162306a36Sopenharmony_ci		 * don't exceed periodic_size msec (default 1.024 sec).
274262306a36Sopenharmony_ci		 */
274362306a36Sopenharmony_ci
274462306a36Sopenharmony_ci		/* FIXME: likewise assumes HC doesn't halt mid-scan */
274562306a36Sopenharmony_ci
274662306a36Sopenharmony_ci		if (now_uframe == clock) {
274762306a36Sopenharmony_ci			unsigned	now;
274862306a36Sopenharmony_ci
274962306a36Sopenharmony_ci			if (!HC_IS_RUNNING(oxu_to_hcd(oxu)->state))
275062306a36Sopenharmony_ci				break;
275162306a36Sopenharmony_ci			oxu->next_uframe = now_uframe;
275262306a36Sopenharmony_ci			now = readl(&oxu->regs->frame_index) % mod;
275362306a36Sopenharmony_ci			if (now_uframe == now)
275462306a36Sopenharmony_ci				break;
275562306a36Sopenharmony_ci
275662306a36Sopenharmony_ci			/* rescan the rest of this frame, then ... */
275762306a36Sopenharmony_ci			clock = now;
275862306a36Sopenharmony_ci		} else {
275962306a36Sopenharmony_ci			now_uframe++;
276062306a36Sopenharmony_ci			now_uframe %= mod;
276162306a36Sopenharmony_ci		}
276262306a36Sopenharmony_ci	}
276362306a36Sopenharmony_ci}
276462306a36Sopenharmony_ci
276562306a36Sopenharmony_ci/* On some systems, leaving remote wakeup enabled prevents system shutdown.
276662306a36Sopenharmony_ci * The firmware seems to think that powering off is a wakeup event!
276762306a36Sopenharmony_ci * This routine turns off remote wakeup and everything else, on all ports.
276862306a36Sopenharmony_ci */
276962306a36Sopenharmony_cistatic void ehci_turn_off_all_ports(struct oxu_hcd *oxu)
277062306a36Sopenharmony_ci{
277162306a36Sopenharmony_ci	int port = HCS_N_PORTS(oxu->hcs_params);
277262306a36Sopenharmony_ci
277362306a36Sopenharmony_ci	while (port--)
277462306a36Sopenharmony_ci		writel(PORT_RWC_BITS, &oxu->regs->port_status[port]);
277562306a36Sopenharmony_ci}
277662306a36Sopenharmony_ci
277762306a36Sopenharmony_cistatic void ehci_port_power(struct oxu_hcd *oxu, int is_on)
277862306a36Sopenharmony_ci{
277962306a36Sopenharmony_ci	unsigned port;
278062306a36Sopenharmony_ci
278162306a36Sopenharmony_ci	if (!HCS_PPC(oxu->hcs_params))
278262306a36Sopenharmony_ci		return;
278362306a36Sopenharmony_ci
278462306a36Sopenharmony_ci	oxu_dbg(oxu, "...power%s ports...\n", is_on ? "up" : "down");
278562306a36Sopenharmony_ci	for (port = HCS_N_PORTS(oxu->hcs_params); port > 0; ) {
278662306a36Sopenharmony_ci		if (is_on)
278762306a36Sopenharmony_ci			oxu_hub_control(oxu_to_hcd(oxu), SetPortFeature,
278862306a36Sopenharmony_ci				USB_PORT_FEAT_POWER, port--, NULL, 0);
278962306a36Sopenharmony_ci		else
279062306a36Sopenharmony_ci			oxu_hub_control(oxu_to_hcd(oxu), ClearPortFeature,
279162306a36Sopenharmony_ci				USB_PORT_FEAT_POWER, port--, NULL, 0);
279262306a36Sopenharmony_ci	}
279362306a36Sopenharmony_ci
279462306a36Sopenharmony_ci	msleep(20);
279562306a36Sopenharmony_ci}
279662306a36Sopenharmony_ci
279762306a36Sopenharmony_ci/* Called from some interrupts, timers, and so on.
279862306a36Sopenharmony_ci * It calls driver completion functions, after dropping oxu->lock.
279962306a36Sopenharmony_ci */
280062306a36Sopenharmony_cistatic void ehci_work(struct oxu_hcd *oxu)
280162306a36Sopenharmony_ci{
280262306a36Sopenharmony_ci	timer_action_done(oxu, TIMER_IO_WATCHDOG);
280362306a36Sopenharmony_ci	if (oxu->reclaim_ready)
280462306a36Sopenharmony_ci		end_unlink_async(oxu);
280562306a36Sopenharmony_ci
280662306a36Sopenharmony_ci	/* another CPU may drop oxu->lock during a schedule scan while
280762306a36Sopenharmony_ci	 * it reports urb completions.  this flag guards against bogus
280862306a36Sopenharmony_ci	 * attempts at re-entrant schedule scanning.
280962306a36Sopenharmony_ci	 */
281062306a36Sopenharmony_ci	if (oxu->scanning)
281162306a36Sopenharmony_ci		return;
281262306a36Sopenharmony_ci	oxu->scanning = 1;
281362306a36Sopenharmony_ci	scan_async(oxu);
281462306a36Sopenharmony_ci	if (oxu->next_uframe != -1)
281562306a36Sopenharmony_ci		scan_periodic(oxu);
281662306a36Sopenharmony_ci	oxu->scanning = 0;
281762306a36Sopenharmony_ci
281862306a36Sopenharmony_ci	/* the IO watchdog guards against hardware or driver bugs that
281962306a36Sopenharmony_ci	 * misplace IRQs, and should let us run completely without IRQs.
282062306a36Sopenharmony_ci	 * such lossage has been observed on both VT6202 and VT8235.
282162306a36Sopenharmony_ci	 */
282262306a36Sopenharmony_ci	if (HC_IS_RUNNING(oxu_to_hcd(oxu)->state) &&
282362306a36Sopenharmony_ci			(oxu->async->qh_next.ptr != NULL ||
282462306a36Sopenharmony_ci			 oxu->periodic_sched != 0))
282562306a36Sopenharmony_ci		timer_action(oxu, TIMER_IO_WATCHDOG);
282662306a36Sopenharmony_ci}
282762306a36Sopenharmony_ci
282862306a36Sopenharmony_cistatic void unlink_async(struct oxu_hcd *oxu, struct ehci_qh *qh)
282962306a36Sopenharmony_ci{
283062306a36Sopenharmony_ci	/* if we need to use IAA and it's busy, defer */
283162306a36Sopenharmony_ci	if (qh->qh_state == QH_STATE_LINKED
283262306a36Sopenharmony_ci			&& oxu->reclaim
283362306a36Sopenharmony_ci			&& HC_IS_RUNNING(oxu_to_hcd(oxu)->state)) {
283462306a36Sopenharmony_ci		struct ehci_qh		*last;
283562306a36Sopenharmony_ci
283662306a36Sopenharmony_ci		for (last = oxu->reclaim;
283762306a36Sopenharmony_ci				last->reclaim;
283862306a36Sopenharmony_ci				last = last->reclaim)
283962306a36Sopenharmony_ci			continue;
284062306a36Sopenharmony_ci		qh->qh_state = QH_STATE_UNLINK_WAIT;
284162306a36Sopenharmony_ci		last->reclaim = qh;
284262306a36Sopenharmony_ci
284362306a36Sopenharmony_ci	/* bypass IAA if the hc can't care */
284462306a36Sopenharmony_ci	} else if (!HC_IS_RUNNING(oxu_to_hcd(oxu)->state) && oxu->reclaim)
284562306a36Sopenharmony_ci		end_unlink_async(oxu);
284662306a36Sopenharmony_ci
284762306a36Sopenharmony_ci	/* something else might have unlinked the qh by now */
284862306a36Sopenharmony_ci	if (qh->qh_state == QH_STATE_LINKED)
284962306a36Sopenharmony_ci		start_unlink_async(oxu, qh);
285062306a36Sopenharmony_ci}
285162306a36Sopenharmony_ci
285262306a36Sopenharmony_ci/*
285362306a36Sopenharmony_ci * USB host controller methods
285462306a36Sopenharmony_ci */
285562306a36Sopenharmony_ci
285662306a36Sopenharmony_cistatic irqreturn_t oxu210_hcd_irq(struct usb_hcd *hcd)
285762306a36Sopenharmony_ci{
285862306a36Sopenharmony_ci	struct oxu_hcd *oxu = hcd_to_oxu(hcd);
285962306a36Sopenharmony_ci	u32 status, pcd_status = 0;
286062306a36Sopenharmony_ci	int bh;
286162306a36Sopenharmony_ci
286262306a36Sopenharmony_ci	spin_lock(&oxu->lock);
286362306a36Sopenharmony_ci
286462306a36Sopenharmony_ci	status = readl(&oxu->regs->status);
286562306a36Sopenharmony_ci
286662306a36Sopenharmony_ci	/* e.g. cardbus physical eject */
286762306a36Sopenharmony_ci	if (status == ~(u32) 0) {
286862306a36Sopenharmony_ci		oxu_dbg(oxu, "device removed\n");
286962306a36Sopenharmony_ci		goto dead;
287062306a36Sopenharmony_ci	}
287162306a36Sopenharmony_ci
287262306a36Sopenharmony_ci	/* Shared IRQ? */
287362306a36Sopenharmony_ci	status &= INTR_MASK;
287462306a36Sopenharmony_ci	if (!status || unlikely(hcd->state == HC_STATE_HALT)) {
287562306a36Sopenharmony_ci		spin_unlock(&oxu->lock);
287662306a36Sopenharmony_ci		return IRQ_NONE;
287762306a36Sopenharmony_ci	}
287862306a36Sopenharmony_ci
287962306a36Sopenharmony_ci	/* clear (just) interrupts */
288062306a36Sopenharmony_ci	writel(status, &oxu->regs->status);
288162306a36Sopenharmony_ci	readl(&oxu->regs->command);	/* unblock posted write */
288262306a36Sopenharmony_ci	bh = 0;
288362306a36Sopenharmony_ci
288462306a36Sopenharmony_ci#ifdef OXU_VERBOSE_DEBUG
288562306a36Sopenharmony_ci	/* unrequested/ignored: Frame List Rollover */
288662306a36Sopenharmony_ci	dbg_status(oxu, "irq", status);
288762306a36Sopenharmony_ci#endif
288862306a36Sopenharmony_ci
288962306a36Sopenharmony_ci	/* INT, ERR, and IAA interrupt rates can be throttled */
289062306a36Sopenharmony_ci
289162306a36Sopenharmony_ci	/* normal [4.15.1.2] or error [4.15.1.1] completion */
289262306a36Sopenharmony_ci	if (likely((status & (STS_INT|STS_ERR)) != 0))
289362306a36Sopenharmony_ci		bh = 1;
289462306a36Sopenharmony_ci
289562306a36Sopenharmony_ci	/* complete the unlinking of some qh [4.15.2.3] */
289662306a36Sopenharmony_ci	if (status & STS_IAA) {
289762306a36Sopenharmony_ci		oxu->reclaim_ready = 1;
289862306a36Sopenharmony_ci		bh = 1;
289962306a36Sopenharmony_ci	}
290062306a36Sopenharmony_ci
290162306a36Sopenharmony_ci	/* remote wakeup [4.3.1] */
290262306a36Sopenharmony_ci	if (status & STS_PCD) {
290362306a36Sopenharmony_ci		unsigned i = HCS_N_PORTS(oxu->hcs_params);
290462306a36Sopenharmony_ci		pcd_status = status;
290562306a36Sopenharmony_ci
290662306a36Sopenharmony_ci		/* resume root hub? */
290762306a36Sopenharmony_ci		if (!(readl(&oxu->regs->command) & CMD_RUN))
290862306a36Sopenharmony_ci			usb_hcd_resume_root_hub(hcd);
290962306a36Sopenharmony_ci
291062306a36Sopenharmony_ci		while (i--) {
291162306a36Sopenharmony_ci			int pstatus = readl(&oxu->regs->port_status[i]);
291262306a36Sopenharmony_ci
291362306a36Sopenharmony_ci			if (pstatus & PORT_OWNER)
291462306a36Sopenharmony_ci				continue;
291562306a36Sopenharmony_ci			if (!(pstatus & PORT_RESUME)
291662306a36Sopenharmony_ci					|| oxu->reset_done[i] != 0)
291762306a36Sopenharmony_ci				continue;
291862306a36Sopenharmony_ci
291962306a36Sopenharmony_ci			/* start USB_RESUME_TIMEOUT resume signaling from this
292062306a36Sopenharmony_ci			 * port, and make hub_wq collect PORT_STAT_C_SUSPEND to
292162306a36Sopenharmony_ci			 * stop that signaling.
292262306a36Sopenharmony_ci			 */
292362306a36Sopenharmony_ci			oxu->reset_done[i] = jiffies +
292462306a36Sopenharmony_ci				msecs_to_jiffies(USB_RESUME_TIMEOUT);
292562306a36Sopenharmony_ci			oxu_dbg(oxu, "port %d remote wakeup\n", i + 1);
292662306a36Sopenharmony_ci			mod_timer(&hcd->rh_timer, oxu->reset_done[i]);
292762306a36Sopenharmony_ci		}
292862306a36Sopenharmony_ci	}
292962306a36Sopenharmony_ci
293062306a36Sopenharmony_ci	/* PCI errors [4.15.2.4] */
293162306a36Sopenharmony_ci	if (unlikely((status & STS_FATAL) != 0)) {
293262306a36Sopenharmony_ci		/* bogus "fatal" IRQs appear on some chips... why?  */
293362306a36Sopenharmony_ci		status = readl(&oxu->regs->status);
293462306a36Sopenharmony_ci		dbg_cmd(oxu, "fatal", readl(&oxu->regs->command));
293562306a36Sopenharmony_ci		dbg_status(oxu, "fatal", status);
293662306a36Sopenharmony_ci		if (status & STS_HALT) {
293762306a36Sopenharmony_ci			oxu_err(oxu, "fatal error\n");
293862306a36Sopenharmony_cidead:
293962306a36Sopenharmony_ci			ehci_reset(oxu);
294062306a36Sopenharmony_ci			writel(0, &oxu->regs->configured_flag);
294162306a36Sopenharmony_ci			usb_hc_died(hcd);
294262306a36Sopenharmony_ci			/* generic layer kills/unlinks all urbs, then
294362306a36Sopenharmony_ci			 * uses oxu_stop to clean up the rest
294462306a36Sopenharmony_ci			 */
294562306a36Sopenharmony_ci			bh = 1;
294662306a36Sopenharmony_ci		}
294762306a36Sopenharmony_ci	}
294862306a36Sopenharmony_ci
294962306a36Sopenharmony_ci	if (bh)
295062306a36Sopenharmony_ci		ehci_work(oxu);
295162306a36Sopenharmony_ci	spin_unlock(&oxu->lock);
295262306a36Sopenharmony_ci	if (pcd_status & STS_PCD)
295362306a36Sopenharmony_ci		usb_hcd_poll_rh_status(hcd);
295462306a36Sopenharmony_ci	return IRQ_HANDLED;
295562306a36Sopenharmony_ci}
295662306a36Sopenharmony_ci
295762306a36Sopenharmony_cistatic irqreturn_t oxu_irq(struct usb_hcd *hcd)
295862306a36Sopenharmony_ci{
295962306a36Sopenharmony_ci	struct oxu_hcd *oxu = hcd_to_oxu(hcd);
296062306a36Sopenharmony_ci	int ret = IRQ_HANDLED;
296162306a36Sopenharmony_ci
296262306a36Sopenharmony_ci	u32 status = oxu_readl(hcd->regs, OXU_CHIPIRQSTATUS);
296362306a36Sopenharmony_ci	u32 enable = oxu_readl(hcd->regs, OXU_CHIPIRQEN_SET);
296462306a36Sopenharmony_ci
296562306a36Sopenharmony_ci	/* Disable all interrupt */
296662306a36Sopenharmony_ci	oxu_writel(hcd->regs, OXU_CHIPIRQEN_CLR, enable);
296762306a36Sopenharmony_ci
296862306a36Sopenharmony_ci	if ((oxu->is_otg && (status & OXU_USBOTGI)) ||
296962306a36Sopenharmony_ci		(!oxu->is_otg && (status & OXU_USBSPHI)))
297062306a36Sopenharmony_ci		oxu210_hcd_irq(hcd);
297162306a36Sopenharmony_ci	else
297262306a36Sopenharmony_ci		ret = IRQ_NONE;
297362306a36Sopenharmony_ci
297462306a36Sopenharmony_ci	/* Enable all interrupt back */
297562306a36Sopenharmony_ci	oxu_writel(hcd->regs, OXU_CHIPIRQEN_SET, enable);
297662306a36Sopenharmony_ci
297762306a36Sopenharmony_ci	return ret;
297862306a36Sopenharmony_ci}
297962306a36Sopenharmony_ci
298062306a36Sopenharmony_cistatic void oxu_watchdog(struct timer_list *t)
298162306a36Sopenharmony_ci{
298262306a36Sopenharmony_ci	struct oxu_hcd	*oxu = from_timer(oxu, t, watchdog);
298362306a36Sopenharmony_ci	unsigned long flags;
298462306a36Sopenharmony_ci
298562306a36Sopenharmony_ci	spin_lock_irqsave(&oxu->lock, flags);
298662306a36Sopenharmony_ci
298762306a36Sopenharmony_ci	/* lost IAA irqs wedge things badly; seen with a vt8235 */
298862306a36Sopenharmony_ci	if (oxu->reclaim) {
298962306a36Sopenharmony_ci		u32 status = readl(&oxu->regs->status);
299062306a36Sopenharmony_ci		if (status & STS_IAA) {
299162306a36Sopenharmony_ci			oxu_vdbg(oxu, "lost IAA\n");
299262306a36Sopenharmony_ci			writel(STS_IAA, &oxu->regs->status);
299362306a36Sopenharmony_ci			oxu->reclaim_ready = 1;
299462306a36Sopenharmony_ci		}
299562306a36Sopenharmony_ci	}
299662306a36Sopenharmony_ci
299762306a36Sopenharmony_ci	/* stop async processing after it's idled a bit */
299862306a36Sopenharmony_ci	if (test_bit(TIMER_ASYNC_OFF, &oxu->actions))
299962306a36Sopenharmony_ci		start_unlink_async(oxu, oxu->async);
300062306a36Sopenharmony_ci
300162306a36Sopenharmony_ci	/* oxu could run by timer, without IRQs ... */
300262306a36Sopenharmony_ci	ehci_work(oxu);
300362306a36Sopenharmony_ci
300462306a36Sopenharmony_ci	spin_unlock_irqrestore(&oxu->lock, flags);
300562306a36Sopenharmony_ci}
300662306a36Sopenharmony_ci
300762306a36Sopenharmony_ci/* One-time init, only for memory state.
300862306a36Sopenharmony_ci */
300962306a36Sopenharmony_cistatic int oxu_hcd_init(struct usb_hcd *hcd)
301062306a36Sopenharmony_ci{
301162306a36Sopenharmony_ci	struct oxu_hcd *oxu = hcd_to_oxu(hcd);
301262306a36Sopenharmony_ci	u32 temp;
301362306a36Sopenharmony_ci	int retval;
301462306a36Sopenharmony_ci	u32 hcc_params;
301562306a36Sopenharmony_ci
301662306a36Sopenharmony_ci	spin_lock_init(&oxu->lock);
301762306a36Sopenharmony_ci
301862306a36Sopenharmony_ci	timer_setup(&oxu->watchdog, oxu_watchdog, 0);
301962306a36Sopenharmony_ci
302062306a36Sopenharmony_ci	/*
302162306a36Sopenharmony_ci	 * hw default: 1K periodic list heads, one per frame.
302262306a36Sopenharmony_ci	 * periodic_size can shrink by USBCMD update if hcc_params allows.
302362306a36Sopenharmony_ci	 */
302462306a36Sopenharmony_ci	oxu->periodic_size = DEFAULT_I_TDPS;
302562306a36Sopenharmony_ci	retval = ehci_mem_init(oxu, GFP_KERNEL);
302662306a36Sopenharmony_ci	if (retval < 0)
302762306a36Sopenharmony_ci		return retval;
302862306a36Sopenharmony_ci
302962306a36Sopenharmony_ci	/* controllers may cache some of the periodic schedule ... */
303062306a36Sopenharmony_ci	hcc_params = readl(&oxu->caps->hcc_params);
303162306a36Sopenharmony_ci	if (HCC_ISOC_CACHE(hcc_params))		/* full frame cache */
303262306a36Sopenharmony_ci		oxu->i_thresh = 8;
303362306a36Sopenharmony_ci	else					/* N microframes cached */
303462306a36Sopenharmony_ci		oxu->i_thresh = 2 + HCC_ISOC_THRES(hcc_params);
303562306a36Sopenharmony_ci
303662306a36Sopenharmony_ci	oxu->reclaim = NULL;
303762306a36Sopenharmony_ci	oxu->reclaim_ready = 0;
303862306a36Sopenharmony_ci	oxu->next_uframe = -1;
303962306a36Sopenharmony_ci
304062306a36Sopenharmony_ci	/*
304162306a36Sopenharmony_ci	 * dedicate a qh for the async ring head, since we couldn't unlink
304262306a36Sopenharmony_ci	 * a 'real' qh without stopping the async schedule [4.8].  use it
304362306a36Sopenharmony_ci	 * as the 'reclamation list head' too.
304462306a36Sopenharmony_ci	 * its dummy is used in hw_alt_next of many tds, to prevent the qh
304562306a36Sopenharmony_ci	 * from automatically advancing to the next td after short reads.
304662306a36Sopenharmony_ci	 */
304762306a36Sopenharmony_ci	oxu->async->qh_next.qh = NULL;
304862306a36Sopenharmony_ci	oxu->async->hw_next = QH_NEXT(oxu->async->qh_dma);
304962306a36Sopenharmony_ci	oxu->async->hw_info1 = cpu_to_le32(QH_HEAD);
305062306a36Sopenharmony_ci	oxu->async->hw_token = cpu_to_le32(QTD_STS_HALT);
305162306a36Sopenharmony_ci	oxu->async->hw_qtd_next = EHCI_LIST_END;
305262306a36Sopenharmony_ci	oxu->async->qh_state = QH_STATE_LINKED;
305362306a36Sopenharmony_ci	oxu->async->hw_alt_next = QTD_NEXT(oxu->async->dummy->qtd_dma);
305462306a36Sopenharmony_ci
305562306a36Sopenharmony_ci	/* clear interrupt enables, set irq latency */
305662306a36Sopenharmony_ci	if (log2_irq_thresh < 0 || log2_irq_thresh > 6)
305762306a36Sopenharmony_ci		log2_irq_thresh = 0;
305862306a36Sopenharmony_ci	temp = 1 << (16 + log2_irq_thresh);
305962306a36Sopenharmony_ci	if (HCC_CANPARK(hcc_params)) {
306062306a36Sopenharmony_ci		/* HW default park == 3, on hardware that supports it (like
306162306a36Sopenharmony_ci		 * NVidia and ALI silicon), maximizes throughput on the async
306262306a36Sopenharmony_ci		 * schedule by avoiding QH fetches between transfers.
306362306a36Sopenharmony_ci		 *
306462306a36Sopenharmony_ci		 * With fast usb storage devices and NForce2, "park" seems to
306562306a36Sopenharmony_ci		 * make problems:  throughput reduction (!), data errors...
306662306a36Sopenharmony_ci		 */
306762306a36Sopenharmony_ci		if (park) {
306862306a36Sopenharmony_ci			park = min(park, (unsigned) 3);
306962306a36Sopenharmony_ci			temp |= CMD_PARK;
307062306a36Sopenharmony_ci			temp |= park << 8;
307162306a36Sopenharmony_ci		}
307262306a36Sopenharmony_ci		oxu_dbg(oxu, "park %d\n", park);
307362306a36Sopenharmony_ci	}
307462306a36Sopenharmony_ci	if (HCC_PGM_FRAMELISTLEN(hcc_params)) {
307562306a36Sopenharmony_ci		/* periodic schedule size can be smaller than default */
307662306a36Sopenharmony_ci		temp &= ~(3 << 2);
307762306a36Sopenharmony_ci		temp |= (EHCI_TUNE_FLS << 2);
307862306a36Sopenharmony_ci	}
307962306a36Sopenharmony_ci	oxu->command = temp;
308062306a36Sopenharmony_ci
308162306a36Sopenharmony_ci	return 0;
308262306a36Sopenharmony_ci}
308362306a36Sopenharmony_ci
308462306a36Sopenharmony_ci/* Called during probe() after chip reset completes.
308562306a36Sopenharmony_ci */
308662306a36Sopenharmony_cistatic int oxu_reset(struct usb_hcd *hcd)
308762306a36Sopenharmony_ci{
308862306a36Sopenharmony_ci	struct oxu_hcd *oxu = hcd_to_oxu(hcd);
308962306a36Sopenharmony_ci
309062306a36Sopenharmony_ci	spin_lock_init(&oxu->mem_lock);
309162306a36Sopenharmony_ci	INIT_LIST_HEAD(&oxu->urb_list);
309262306a36Sopenharmony_ci	oxu->urb_len = 0;
309362306a36Sopenharmony_ci
309462306a36Sopenharmony_ci	if (oxu->is_otg) {
309562306a36Sopenharmony_ci		oxu->caps = hcd->regs + OXU_OTG_CAP_OFFSET;
309662306a36Sopenharmony_ci		oxu->regs = hcd->regs + OXU_OTG_CAP_OFFSET + \
309762306a36Sopenharmony_ci			HC_LENGTH(readl(&oxu->caps->hc_capbase));
309862306a36Sopenharmony_ci
309962306a36Sopenharmony_ci		oxu->mem = hcd->regs + OXU_SPH_MEM;
310062306a36Sopenharmony_ci	} else {
310162306a36Sopenharmony_ci		oxu->caps = hcd->regs + OXU_SPH_CAP_OFFSET;
310262306a36Sopenharmony_ci		oxu->regs = hcd->regs + OXU_SPH_CAP_OFFSET + \
310362306a36Sopenharmony_ci			HC_LENGTH(readl(&oxu->caps->hc_capbase));
310462306a36Sopenharmony_ci
310562306a36Sopenharmony_ci		oxu->mem = hcd->regs + OXU_OTG_MEM;
310662306a36Sopenharmony_ci	}
310762306a36Sopenharmony_ci
310862306a36Sopenharmony_ci	oxu->hcs_params = readl(&oxu->caps->hcs_params);
310962306a36Sopenharmony_ci	oxu->sbrn = 0x20;
311062306a36Sopenharmony_ci
311162306a36Sopenharmony_ci	return oxu_hcd_init(hcd);
311262306a36Sopenharmony_ci}
311362306a36Sopenharmony_ci
311462306a36Sopenharmony_cistatic int oxu_run(struct usb_hcd *hcd)
311562306a36Sopenharmony_ci{
311662306a36Sopenharmony_ci	struct oxu_hcd *oxu = hcd_to_oxu(hcd);
311762306a36Sopenharmony_ci	int retval;
311862306a36Sopenharmony_ci	u32 temp, hcc_params;
311962306a36Sopenharmony_ci
312062306a36Sopenharmony_ci	hcd->uses_new_polling = 1;
312162306a36Sopenharmony_ci
312262306a36Sopenharmony_ci	/* EHCI spec section 4.1 */
312362306a36Sopenharmony_ci	retval = ehci_reset(oxu);
312462306a36Sopenharmony_ci	if (retval != 0) {
312562306a36Sopenharmony_ci		ehci_mem_cleanup(oxu);
312662306a36Sopenharmony_ci		return retval;
312762306a36Sopenharmony_ci	}
312862306a36Sopenharmony_ci	writel(oxu->periodic_dma, &oxu->regs->frame_list);
312962306a36Sopenharmony_ci	writel((u32) oxu->async->qh_dma, &oxu->regs->async_next);
313062306a36Sopenharmony_ci
313162306a36Sopenharmony_ci	/* hcc_params controls whether oxu->regs->segment must (!!!)
313262306a36Sopenharmony_ci	 * be used; it constrains QH/ITD/SITD and QTD locations.
313362306a36Sopenharmony_ci	 * dma_pool consistent memory always uses segment zero.
313462306a36Sopenharmony_ci	 * streaming mappings for I/O buffers, like dma_map_single(),
313562306a36Sopenharmony_ci	 * can return segments above 4GB, if the device allows.
313662306a36Sopenharmony_ci	 *
313762306a36Sopenharmony_ci	 * NOTE:  the dma mask is visible through dev->dma_mask, so
313862306a36Sopenharmony_ci	 * drivers can pass this info along ... like NETIF_F_HIGHDMA,
313962306a36Sopenharmony_ci	 * Scsi_Host.highmem_io, and so forth.  It's readonly to all
314062306a36Sopenharmony_ci	 * host side drivers though.
314162306a36Sopenharmony_ci	 */
314262306a36Sopenharmony_ci	hcc_params = readl(&oxu->caps->hcc_params);
314362306a36Sopenharmony_ci	if (HCC_64BIT_ADDR(hcc_params))
314462306a36Sopenharmony_ci		writel(0, &oxu->regs->segment);
314562306a36Sopenharmony_ci
314662306a36Sopenharmony_ci	oxu->command &= ~(CMD_LRESET | CMD_IAAD | CMD_PSE |
314762306a36Sopenharmony_ci				CMD_ASE | CMD_RESET);
314862306a36Sopenharmony_ci	oxu->command |= CMD_RUN;
314962306a36Sopenharmony_ci	writel(oxu->command, &oxu->regs->command);
315062306a36Sopenharmony_ci	dbg_cmd(oxu, "init", oxu->command);
315162306a36Sopenharmony_ci
315262306a36Sopenharmony_ci	/*
315362306a36Sopenharmony_ci	 * Start, enabling full USB 2.0 functionality ... usb 1.1 devices
315462306a36Sopenharmony_ci	 * are explicitly handed to companion controller(s), so no TT is
315562306a36Sopenharmony_ci	 * involved with the root hub.  (Except where one is integrated,
315662306a36Sopenharmony_ci	 * and there's no companion controller unless maybe for USB OTG.)
315762306a36Sopenharmony_ci	 */
315862306a36Sopenharmony_ci	hcd->state = HC_STATE_RUNNING;
315962306a36Sopenharmony_ci	writel(FLAG_CF, &oxu->regs->configured_flag);
316062306a36Sopenharmony_ci	readl(&oxu->regs->command);	/* unblock posted writes */
316162306a36Sopenharmony_ci
316262306a36Sopenharmony_ci	temp = HC_VERSION(readl(&oxu->caps->hc_capbase));
316362306a36Sopenharmony_ci	oxu_info(oxu, "USB %x.%x started, quasi-EHCI %x.%02x, driver %s%s\n",
316462306a36Sopenharmony_ci		((oxu->sbrn & 0xf0)>>4), (oxu->sbrn & 0x0f),
316562306a36Sopenharmony_ci		temp >> 8, temp & 0xff, DRIVER_VERSION,
316662306a36Sopenharmony_ci		ignore_oc ? ", overcurrent ignored" : "");
316762306a36Sopenharmony_ci
316862306a36Sopenharmony_ci	writel(INTR_MASK, &oxu->regs->intr_enable); /* Turn On Interrupts */
316962306a36Sopenharmony_ci
317062306a36Sopenharmony_ci	return 0;
317162306a36Sopenharmony_ci}
317262306a36Sopenharmony_ci
317362306a36Sopenharmony_cistatic void oxu_stop(struct usb_hcd *hcd)
317462306a36Sopenharmony_ci{
317562306a36Sopenharmony_ci	struct oxu_hcd *oxu = hcd_to_oxu(hcd);
317662306a36Sopenharmony_ci
317762306a36Sopenharmony_ci	/* Turn off port power on all root hub ports. */
317862306a36Sopenharmony_ci	ehci_port_power(oxu, 0);
317962306a36Sopenharmony_ci
318062306a36Sopenharmony_ci	/* no more interrupts ... */
318162306a36Sopenharmony_ci	del_timer_sync(&oxu->watchdog);
318262306a36Sopenharmony_ci
318362306a36Sopenharmony_ci	spin_lock_irq(&oxu->lock);
318462306a36Sopenharmony_ci	if (HC_IS_RUNNING(hcd->state))
318562306a36Sopenharmony_ci		ehci_quiesce(oxu);
318662306a36Sopenharmony_ci
318762306a36Sopenharmony_ci	ehci_reset(oxu);
318862306a36Sopenharmony_ci	writel(0, &oxu->regs->intr_enable);
318962306a36Sopenharmony_ci	spin_unlock_irq(&oxu->lock);
319062306a36Sopenharmony_ci
319162306a36Sopenharmony_ci	/* let companion controllers work when we aren't */
319262306a36Sopenharmony_ci	writel(0, &oxu->regs->configured_flag);
319362306a36Sopenharmony_ci
319462306a36Sopenharmony_ci	/* root hub is shut down separately (first, when possible) */
319562306a36Sopenharmony_ci	spin_lock_irq(&oxu->lock);
319662306a36Sopenharmony_ci	if (oxu->async)
319762306a36Sopenharmony_ci		ehci_work(oxu);
319862306a36Sopenharmony_ci	spin_unlock_irq(&oxu->lock);
319962306a36Sopenharmony_ci	ehci_mem_cleanup(oxu);
320062306a36Sopenharmony_ci
320162306a36Sopenharmony_ci	dbg_status(oxu, "oxu_stop completed", readl(&oxu->regs->status));
320262306a36Sopenharmony_ci}
320362306a36Sopenharmony_ci
320462306a36Sopenharmony_ci/* Kick in for silicon on any bus (not just pci, etc).
320562306a36Sopenharmony_ci * This forcibly disables dma and IRQs, helping kexec and other cases
320662306a36Sopenharmony_ci * where the next system software may expect clean state.
320762306a36Sopenharmony_ci */
320862306a36Sopenharmony_cistatic void oxu_shutdown(struct usb_hcd *hcd)
320962306a36Sopenharmony_ci{
321062306a36Sopenharmony_ci	struct oxu_hcd *oxu = hcd_to_oxu(hcd);
321162306a36Sopenharmony_ci
321262306a36Sopenharmony_ci	(void) ehci_halt(oxu);
321362306a36Sopenharmony_ci	ehci_turn_off_all_ports(oxu);
321462306a36Sopenharmony_ci
321562306a36Sopenharmony_ci	/* make BIOS/etc use companion controller during reboot */
321662306a36Sopenharmony_ci	writel(0, &oxu->regs->configured_flag);
321762306a36Sopenharmony_ci
321862306a36Sopenharmony_ci	/* unblock posted writes */
321962306a36Sopenharmony_ci	readl(&oxu->regs->configured_flag);
322062306a36Sopenharmony_ci}
322162306a36Sopenharmony_ci
322262306a36Sopenharmony_ci/* Non-error returns are a promise to giveback() the urb later
322362306a36Sopenharmony_ci * we drop ownership so next owner (or urb unlink) can get it
322462306a36Sopenharmony_ci *
322562306a36Sopenharmony_ci * urb + dev is in hcd.self.controller.urb_list
322662306a36Sopenharmony_ci * we're queueing TDs onto software and hardware lists
322762306a36Sopenharmony_ci *
322862306a36Sopenharmony_ci * hcd-specific init for hcpriv hasn't been done yet
322962306a36Sopenharmony_ci *
323062306a36Sopenharmony_ci * NOTE:  control, bulk, and interrupt share the same code to append TDs
323162306a36Sopenharmony_ci * to a (possibly active) QH, and the same QH scanning code.
323262306a36Sopenharmony_ci */
323362306a36Sopenharmony_cistatic int __oxu_urb_enqueue(struct usb_hcd *hcd, struct urb *urb,
323462306a36Sopenharmony_ci				gfp_t mem_flags)
323562306a36Sopenharmony_ci{
323662306a36Sopenharmony_ci	struct oxu_hcd *oxu = hcd_to_oxu(hcd);
323762306a36Sopenharmony_ci	struct list_head qtd_list;
323862306a36Sopenharmony_ci
323962306a36Sopenharmony_ci	INIT_LIST_HEAD(&qtd_list);
324062306a36Sopenharmony_ci
324162306a36Sopenharmony_ci	switch (usb_pipetype(urb->pipe)) {
324262306a36Sopenharmony_ci	case PIPE_CONTROL:
324362306a36Sopenharmony_ci	case PIPE_BULK:
324462306a36Sopenharmony_ci	default:
324562306a36Sopenharmony_ci		if (!qh_urb_transaction(oxu, urb, &qtd_list, mem_flags))
324662306a36Sopenharmony_ci			return -ENOMEM;
324762306a36Sopenharmony_ci		return submit_async(oxu, urb, &qtd_list, mem_flags);
324862306a36Sopenharmony_ci
324962306a36Sopenharmony_ci	case PIPE_INTERRUPT:
325062306a36Sopenharmony_ci		if (!qh_urb_transaction(oxu, urb, &qtd_list, mem_flags))
325162306a36Sopenharmony_ci			return -ENOMEM;
325262306a36Sopenharmony_ci		return intr_submit(oxu, urb, &qtd_list, mem_flags);
325362306a36Sopenharmony_ci
325462306a36Sopenharmony_ci	case PIPE_ISOCHRONOUS:
325562306a36Sopenharmony_ci		if (urb->dev->speed == USB_SPEED_HIGH)
325662306a36Sopenharmony_ci			return itd_submit(oxu, urb, mem_flags);
325762306a36Sopenharmony_ci		else
325862306a36Sopenharmony_ci			return sitd_submit(oxu, urb, mem_flags);
325962306a36Sopenharmony_ci	}
326062306a36Sopenharmony_ci}
326162306a36Sopenharmony_ci
326262306a36Sopenharmony_ci/* This function is responsible for breaking URBs with big data size
326362306a36Sopenharmony_ci * into smaller size and processing small urbs in sequence.
326462306a36Sopenharmony_ci */
326562306a36Sopenharmony_cistatic int oxu_urb_enqueue(struct usb_hcd *hcd, struct urb *urb,
326662306a36Sopenharmony_ci				gfp_t mem_flags)
326762306a36Sopenharmony_ci{
326862306a36Sopenharmony_ci	struct oxu_hcd *oxu = hcd_to_oxu(hcd);
326962306a36Sopenharmony_ci	int num, rem;
327062306a36Sopenharmony_ci	void *transfer_buffer;
327162306a36Sopenharmony_ci	struct urb *murb;
327262306a36Sopenharmony_ci	int i, ret;
327362306a36Sopenharmony_ci
327462306a36Sopenharmony_ci	/* If not bulk pipe just enqueue the URB */
327562306a36Sopenharmony_ci	if (!usb_pipebulk(urb->pipe))
327662306a36Sopenharmony_ci		return __oxu_urb_enqueue(hcd, urb, mem_flags);
327762306a36Sopenharmony_ci
327862306a36Sopenharmony_ci	/* Otherwise we should verify the USB transfer buffer size! */
327962306a36Sopenharmony_ci	transfer_buffer = urb->transfer_buffer;
328062306a36Sopenharmony_ci
328162306a36Sopenharmony_ci	num = urb->transfer_buffer_length / 4096;
328262306a36Sopenharmony_ci	rem = urb->transfer_buffer_length % 4096;
328362306a36Sopenharmony_ci	if (rem != 0)
328462306a36Sopenharmony_ci		num++;
328562306a36Sopenharmony_ci
328662306a36Sopenharmony_ci	/* If URB is smaller than 4096 bytes just enqueue it! */
328762306a36Sopenharmony_ci	if (num == 1)
328862306a36Sopenharmony_ci		return __oxu_urb_enqueue(hcd, urb, mem_flags);
328962306a36Sopenharmony_ci
329062306a36Sopenharmony_ci	/* Ok, we have more job to do! :) */
329162306a36Sopenharmony_ci
329262306a36Sopenharmony_ci	for (i = 0; i < num - 1; i++) {
329362306a36Sopenharmony_ci		/* Get free micro URB poll till a free urb is received */
329462306a36Sopenharmony_ci
329562306a36Sopenharmony_ci		do {
329662306a36Sopenharmony_ci			murb = (struct urb *) oxu_murb_alloc(oxu);
329762306a36Sopenharmony_ci			if (!murb)
329862306a36Sopenharmony_ci				schedule();
329962306a36Sopenharmony_ci		} while (!murb);
330062306a36Sopenharmony_ci
330162306a36Sopenharmony_ci		/* Coping the urb */
330262306a36Sopenharmony_ci		memcpy(murb, urb, sizeof(struct urb));
330362306a36Sopenharmony_ci
330462306a36Sopenharmony_ci		murb->transfer_buffer_length = 4096;
330562306a36Sopenharmony_ci		murb->transfer_buffer = transfer_buffer + i * 4096;
330662306a36Sopenharmony_ci
330762306a36Sopenharmony_ci		/* Null pointer for the encodes that this is a micro urb */
330862306a36Sopenharmony_ci		murb->complete = NULL;
330962306a36Sopenharmony_ci
331062306a36Sopenharmony_ci		((struct oxu_murb *) murb)->main = urb;
331162306a36Sopenharmony_ci		((struct oxu_murb *) murb)->last = 0;
331262306a36Sopenharmony_ci
331362306a36Sopenharmony_ci		/* This loop is to guarantee urb to be processed when there's
331462306a36Sopenharmony_ci		 * not enough resources at a particular time by retrying.
331562306a36Sopenharmony_ci		 */
331662306a36Sopenharmony_ci		do {
331762306a36Sopenharmony_ci			ret  = __oxu_urb_enqueue(hcd, murb, mem_flags);
331862306a36Sopenharmony_ci			if (ret)
331962306a36Sopenharmony_ci				schedule();
332062306a36Sopenharmony_ci		} while (ret);
332162306a36Sopenharmony_ci	}
332262306a36Sopenharmony_ci
332362306a36Sopenharmony_ci	/* Last urb requires special handling  */
332462306a36Sopenharmony_ci
332562306a36Sopenharmony_ci	/* Get free micro URB poll till a free urb is received */
332662306a36Sopenharmony_ci	do {
332762306a36Sopenharmony_ci		murb = (struct urb *) oxu_murb_alloc(oxu);
332862306a36Sopenharmony_ci		if (!murb)
332962306a36Sopenharmony_ci			schedule();
333062306a36Sopenharmony_ci	} while (!murb);
333162306a36Sopenharmony_ci
333262306a36Sopenharmony_ci	/* Coping the urb */
333362306a36Sopenharmony_ci	memcpy(murb, urb, sizeof(struct urb));
333462306a36Sopenharmony_ci
333562306a36Sopenharmony_ci	murb->transfer_buffer_length = rem > 0 ? rem : 4096;
333662306a36Sopenharmony_ci	murb->transfer_buffer = transfer_buffer + (num - 1) * 4096;
333762306a36Sopenharmony_ci
333862306a36Sopenharmony_ci	/* Null pointer for the encodes that this is a micro urb */
333962306a36Sopenharmony_ci	murb->complete = NULL;
334062306a36Sopenharmony_ci
334162306a36Sopenharmony_ci	((struct oxu_murb *) murb)->main = urb;
334262306a36Sopenharmony_ci	((struct oxu_murb *) murb)->last = 1;
334362306a36Sopenharmony_ci
334462306a36Sopenharmony_ci	do {
334562306a36Sopenharmony_ci		ret = __oxu_urb_enqueue(hcd, murb, mem_flags);
334662306a36Sopenharmony_ci		if (ret)
334762306a36Sopenharmony_ci			schedule();
334862306a36Sopenharmony_ci	} while (ret);
334962306a36Sopenharmony_ci
335062306a36Sopenharmony_ci	return ret;
335162306a36Sopenharmony_ci}
335262306a36Sopenharmony_ci
335362306a36Sopenharmony_ci/* Remove from hardware lists.
335462306a36Sopenharmony_ci * Completions normally happen asynchronously
335562306a36Sopenharmony_ci */
335662306a36Sopenharmony_cistatic int oxu_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
335762306a36Sopenharmony_ci{
335862306a36Sopenharmony_ci	struct oxu_hcd *oxu = hcd_to_oxu(hcd);
335962306a36Sopenharmony_ci	struct ehci_qh *qh;
336062306a36Sopenharmony_ci	unsigned long flags;
336162306a36Sopenharmony_ci
336262306a36Sopenharmony_ci	spin_lock_irqsave(&oxu->lock, flags);
336362306a36Sopenharmony_ci	switch (usb_pipetype(urb->pipe)) {
336462306a36Sopenharmony_ci	case PIPE_CONTROL:
336562306a36Sopenharmony_ci	case PIPE_BULK:
336662306a36Sopenharmony_ci	default:
336762306a36Sopenharmony_ci		qh = (struct ehci_qh *) urb->hcpriv;
336862306a36Sopenharmony_ci		if (!qh)
336962306a36Sopenharmony_ci			break;
337062306a36Sopenharmony_ci		unlink_async(oxu, qh);
337162306a36Sopenharmony_ci		break;
337262306a36Sopenharmony_ci
337362306a36Sopenharmony_ci	case PIPE_INTERRUPT:
337462306a36Sopenharmony_ci		qh = (struct ehci_qh *) urb->hcpriv;
337562306a36Sopenharmony_ci		if (!qh)
337662306a36Sopenharmony_ci			break;
337762306a36Sopenharmony_ci		switch (qh->qh_state) {
337862306a36Sopenharmony_ci		case QH_STATE_LINKED:
337962306a36Sopenharmony_ci			intr_deschedule(oxu, qh);
338062306a36Sopenharmony_ci			fallthrough;
338162306a36Sopenharmony_ci		case QH_STATE_IDLE:
338262306a36Sopenharmony_ci			qh_completions(oxu, qh);
338362306a36Sopenharmony_ci			break;
338462306a36Sopenharmony_ci		default:
338562306a36Sopenharmony_ci			oxu_dbg(oxu, "bogus qh %p state %d\n",
338662306a36Sopenharmony_ci					qh, qh->qh_state);
338762306a36Sopenharmony_ci			goto done;
338862306a36Sopenharmony_ci		}
338962306a36Sopenharmony_ci
339062306a36Sopenharmony_ci		/* reschedule QH iff another request is queued */
339162306a36Sopenharmony_ci		if (!list_empty(&qh->qtd_list)
339262306a36Sopenharmony_ci				&& HC_IS_RUNNING(hcd->state)) {
339362306a36Sopenharmony_ci			int status;
339462306a36Sopenharmony_ci
339562306a36Sopenharmony_ci			status = qh_schedule(oxu, qh);
339662306a36Sopenharmony_ci			spin_unlock_irqrestore(&oxu->lock, flags);
339762306a36Sopenharmony_ci
339862306a36Sopenharmony_ci			if (status != 0) {
339962306a36Sopenharmony_ci				/* shouldn't happen often, but ...
340062306a36Sopenharmony_ci				 * FIXME kill those tds' urbs
340162306a36Sopenharmony_ci				 */
340262306a36Sopenharmony_ci				dev_err(hcd->self.controller,
340362306a36Sopenharmony_ci					"can't reschedule qh %p, err %d\n", qh,
340462306a36Sopenharmony_ci					status);
340562306a36Sopenharmony_ci			}
340662306a36Sopenharmony_ci			return status;
340762306a36Sopenharmony_ci		}
340862306a36Sopenharmony_ci		break;
340962306a36Sopenharmony_ci	}
341062306a36Sopenharmony_cidone:
341162306a36Sopenharmony_ci	spin_unlock_irqrestore(&oxu->lock, flags);
341262306a36Sopenharmony_ci	return 0;
341362306a36Sopenharmony_ci}
341462306a36Sopenharmony_ci
341562306a36Sopenharmony_ci/* Bulk qh holds the data toggle */
341662306a36Sopenharmony_cistatic void oxu_endpoint_disable(struct usb_hcd *hcd,
341762306a36Sopenharmony_ci					struct usb_host_endpoint *ep)
341862306a36Sopenharmony_ci{
341962306a36Sopenharmony_ci	struct oxu_hcd *oxu = hcd_to_oxu(hcd);
342062306a36Sopenharmony_ci	unsigned long		flags;
342162306a36Sopenharmony_ci	struct ehci_qh		*qh, *tmp;
342262306a36Sopenharmony_ci
342362306a36Sopenharmony_ci	/* ASSERT:  any requests/urbs are being unlinked */
342462306a36Sopenharmony_ci	/* ASSERT:  nobody can be submitting urbs for this any more */
342562306a36Sopenharmony_ci
342662306a36Sopenharmony_cirescan:
342762306a36Sopenharmony_ci	spin_lock_irqsave(&oxu->lock, flags);
342862306a36Sopenharmony_ci	qh = ep->hcpriv;
342962306a36Sopenharmony_ci	if (!qh)
343062306a36Sopenharmony_ci		goto done;
343162306a36Sopenharmony_ci
343262306a36Sopenharmony_ci	/* endpoints can be iso streams.  for now, we don't
343362306a36Sopenharmony_ci	 * accelerate iso completions ... so spin a while.
343462306a36Sopenharmony_ci	 */
343562306a36Sopenharmony_ci	if (qh->hw_info1 == 0) {
343662306a36Sopenharmony_ci		oxu_vdbg(oxu, "iso delay\n");
343762306a36Sopenharmony_ci		goto idle_timeout;
343862306a36Sopenharmony_ci	}
343962306a36Sopenharmony_ci
344062306a36Sopenharmony_ci	if (!HC_IS_RUNNING(hcd->state))
344162306a36Sopenharmony_ci		qh->qh_state = QH_STATE_IDLE;
344262306a36Sopenharmony_ci	switch (qh->qh_state) {
344362306a36Sopenharmony_ci	case QH_STATE_LINKED:
344462306a36Sopenharmony_ci		for (tmp = oxu->async->qh_next.qh;
344562306a36Sopenharmony_ci				tmp && tmp != qh;
344662306a36Sopenharmony_ci				tmp = tmp->qh_next.qh)
344762306a36Sopenharmony_ci			continue;
344862306a36Sopenharmony_ci		/* periodic qh self-unlinks on empty */
344962306a36Sopenharmony_ci		if (!tmp)
345062306a36Sopenharmony_ci			goto nogood;
345162306a36Sopenharmony_ci		unlink_async(oxu, qh);
345262306a36Sopenharmony_ci		fallthrough;
345362306a36Sopenharmony_ci	case QH_STATE_UNLINK:		/* wait for hw to finish? */
345462306a36Sopenharmony_ciidle_timeout:
345562306a36Sopenharmony_ci		spin_unlock_irqrestore(&oxu->lock, flags);
345662306a36Sopenharmony_ci		schedule_timeout_uninterruptible(1);
345762306a36Sopenharmony_ci		goto rescan;
345862306a36Sopenharmony_ci	case QH_STATE_IDLE:		/* fully unlinked */
345962306a36Sopenharmony_ci		if (list_empty(&qh->qtd_list)) {
346062306a36Sopenharmony_ci			qh_put(qh);
346162306a36Sopenharmony_ci			break;
346262306a36Sopenharmony_ci		}
346362306a36Sopenharmony_ci		fallthrough;
346462306a36Sopenharmony_ci	default:
346562306a36Sopenharmony_cinogood:
346662306a36Sopenharmony_ci		/* caller was supposed to have unlinked any requests;
346762306a36Sopenharmony_ci		 * that's not our job.  just leak this memory.
346862306a36Sopenharmony_ci		 */
346962306a36Sopenharmony_ci		oxu_err(oxu, "qh %p (#%02x) state %d%s\n",
347062306a36Sopenharmony_ci			qh, ep->desc.bEndpointAddress, qh->qh_state,
347162306a36Sopenharmony_ci			list_empty(&qh->qtd_list) ? "" : "(has tds)");
347262306a36Sopenharmony_ci		break;
347362306a36Sopenharmony_ci	}
347462306a36Sopenharmony_ci	ep->hcpriv = NULL;
347562306a36Sopenharmony_cidone:
347662306a36Sopenharmony_ci	spin_unlock_irqrestore(&oxu->lock, flags);
347762306a36Sopenharmony_ci}
347862306a36Sopenharmony_ci
347962306a36Sopenharmony_cistatic int oxu_get_frame(struct usb_hcd *hcd)
348062306a36Sopenharmony_ci{
348162306a36Sopenharmony_ci	struct oxu_hcd *oxu = hcd_to_oxu(hcd);
348262306a36Sopenharmony_ci
348362306a36Sopenharmony_ci	return (readl(&oxu->regs->frame_index) >> 3) %
348462306a36Sopenharmony_ci		oxu->periodic_size;
348562306a36Sopenharmony_ci}
348662306a36Sopenharmony_ci
348762306a36Sopenharmony_ci/* Build "status change" packet (one or two bytes) from HC registers */
348862306a36Sopenharmony_cistatic int oxu_hub_status_data(struct usb_hcd *hcd, char *buf)
348962306a36Sopenharmony_ci{
349062306a36Sopenharmony_ci	struct oxu_hcd *oxu = hcd_to_oxu(hcd);
349162306a36Sopenharmony_ci	u32 temp, mask, status = 0;
349262306a36Sopenharmony_ci	int ports, i, retval = 1;
349362306a36Sopenharmony_ci	unsigned long flags;
349462306a36Sopenharmony_ci
349562306a36Sopenharmony_ci	/* if !PM, root hub timers won't get shut down ... */
349662306a36Sopenharmony_ci	if (!HC_IS_RUNNING(hcd->state))
349762306a36Sopenharmony_ci		return 0;
349862306a36Sopenharmony_ci
349962306a36Sopenharmony_ci	/* init status to no-changes */
350062306a36Sopenharmony_ci	buf[0] = 0;
350162306a36Sopenharmony_ci	ports = HCS_N_PORTS(oxu->hcs_params);
350262306a36Sopenharmony_ci	if (ports > 7) {
350362306a36Sopenharmony_ci		buf[1] = 0;
350462306a36Sopenharmony_ci		retval++;
350562306a36Sopenharmony_ci	}
350662306a36Sopenharmony_ci
350762306a36Sopenharmony_ci	/* Some boards (mostly VIA?) report bogus overcurrent indications,
350862306a36Sopenharmony_ci	 * causing massive log spam unless we completely ignore them.  It
350962306a36Sopenharmony_ci	 * may be relevant that VIA VT8235 controllers, where PORT_POWER is
351062306a36Sopenharmony_ci	 * always set, seem to clear PORT_OCC and PORT_CSC when writing to
351162306a36Sopenharmony_ci	 * PORT_POWER; that's surprising, but maybe within-spec.
351262306a36Sopenharmony_ci	 */
351362306a36Sopenharmony_ci	if (!ignore_oc)
351462306a36Sopenharmony_ci		mask = PORT_CSC | PORT_PEC | PORT_OCC;
351562306a36Sopenharmony_ci	else
351662306a36Sopenharmony_ci		mask = PORT_CSC | PORT_PEC;
351762306a36Sopenharmony_ci
351862306a36Sopenharmony_ci	/* no hub change reports (bit 0) for now (power, ...) */
351962306a36Sopenharmony_ci
352062306a36Sopenharmony_ci	/* port N changes (bit N)? */
352162306a36Sopenharmony_ci	spin_lock_irqsave(&oxu->lock, flags);
352262306a36Sopenharmony_ci	for (i = 0; i < ports; i++) {
352362306a36Sopenharmony_ci		temp = readl(&oxu->regs->port_status[i]);
352462306a36Sopenharmony_ci
352562306a36Sopenharmony_ci		/*
352662306a36Sopenharmony_ci		 * Return status information even for ports with OWNER set.
352762306a36Sopenharmony_ci		 * Otherwise hub_wq wouldn't see the disconnect event when a
352862306a36Sopenharmony_ci		 * high-speed device is switched over to the companion
352962306a36Sopenharmony_ci		 * controller by the user.
353062306a36Sopenharmony_ci		 */
353162306a36Sopenharmony_ci
353262306a36Sopenharmony_ci		if (!(temp & PORT_CONNECT))
353362306a36Sopenharmony_ci			oxu->reset_done[i] = 0;
353462306a36Sopenharmony_ci		if ((temp & mask) != 0 || ((temp & PORT_RESUME) != 0 &&
353562306a36Sopenharmony_ci				time_after_eq(jiffies, oxu->reset_done[i]))) {
353662306a36Sopenharmony_ci			if (i < 7)
353762306a36Sopenharmony_ci				buf[0] |= 1 << (i + 1);
353862306a36Sopenharmony_ci			else
353962306a36Sopenharmony_ci				buf[1] |= 1 << (i - 7);
354062306a36Sopenharmony_ci			status = STS_PCD;
354162306a36Sopenharmony_ci		}
354262306a36Sopenharmony_ci	}
354362306a36Sopenharmony_ci	/* FIXME autosuspend idle root hubs */
354462306a36Sopenharmony_ci	spin_unlock_irqrestore(&oxu->lock, flags);
354562306a36Sopenharmony_ci	return status ? retval : 0;
354662306a36Sopenharmony_ci}
354762306a36Sopenharmony_ci
354862306a36Sopenharmony_ci/* Returns the speed of a device attached to a port on the root hub. */
354962306a36Sopenharmony_cistatic inline unsigned int oxu_port_speed(struct oxu_hcd *oxu,
355062306a36Sopenharmony_ci						unsigned int portsc)
355162306a36Sopenharmony_ci{
355262306a36Sopenharmony_ci	switch ((portsc >> 26) & 3) {
355362306a36Sopenharmony_ci	case 0:
355462306a36Sopenharmony_ci		return 0;
355562306a36Sopenharmony_ci	case 1:
355662306a36Sopenharmony_ci		return USB_PORT_STAT_LOW_SPEED;
355762306a36Sopenharmony_ci	case 2:
355862306a36Sopenharmony_ci	default:
355962306a36Sopenharmony_ci		return USB_PORT_STAT_HIGH_SPEED;
356062306a36Sopenharmony_ci	}
356162306a36Sopenharmony_ci}
356262306a36Sopenharmony_ci
356362306a36Sopenharmony_ci#define	PORT_WAKE_BITS	(PORT_WKOC_E|PORT_WKDISC_E|PORT_WKCONN_E)
356462306a36Sopenharmony_cistatic int oxu_hub_control(struct usb_hcd *hcd, u16 typeReq,
356562306a36Sopenharmony_ci				u16 wValue, u16 wIndex, char *buf, u16 wLength)
356662306a36Sopenharmony_ci{
356762306a36Sopenharmony_ci	struct oxu_hcd *oxu = hcd_to_oxu(hcd);
356862306a36Sopenharmony_ci	int ports = HCS_N_PORTS(oxu->hcs_params);
356962306a36Sopenharmony_ci	u32 __iomem *status_reg = &oxu->regs->port_status[wIndex - 1];
357062306a36Sopenharmony_ci	u32 temp, status;
357162306a36Sopenharmony_ci	unsigned long	flags;
357262306a36Sopenharmony_ci	int retval = 0;
357362306a36Sopenharmony_ci	unsigned selector;
357462306a36Sopenharmony_ci
357562306a36Sopenharmony_ci	/*
357662306a36Sopenharmony_ci	 * FIXME:  support SetPortFeatures USB_PORT_FEAT_INDICATOR.
357762306a36Sopenharmony_ci	 * HCS_INDICATOR may say we can change LEDs to off/amber/green.
357862306a36Sopenharmony_ci	 * (track current state ourselves) ... blink for diagnostics,
357962306a36Sopenharmony_ci	 * power, "this is the one", etc.  EHCI spec supports this.
358062306a36Sopenharmony_ci	 */
358162306a36Sopenharmony_ci
358262306a36Sopenharmony_ci	spin_lock_irqsave(&oxu->lock, flags);
358362306a36Sopenharmony_ci	switch (typeReq) {
358462306a36Sopenharmony_ci	case ClearHubFeature:
358562306a36Sopenharmony_ci		switch (wValue) {
358662306a36Sopenharmony_ci		case C_HUB_LOCAL_POWER:
358762306a36Sopenharmony_ci		case C_HUB_OVER_CURRENT:
358862306a36Sopenharmony_ci			/* no hub-wide feature/status flags */
358962306a36Sopenharmony_ci			break;
359062306a36Sopenharmony_ci		default:
359162306a36Sopenharmony_ci			goto error;
359262306a36Sopenharmony_ci		}
359362306a36Sopenharmony_ci		break;
359462306a36Sopenharmony_ci	case ClearPortFeature:
359562306a36Sopenharmony_ci		if (!wIndex || wIndex > ports)
359662306a36Sopenharmony_ci			goto error;
359762306a36Sopenharmony_ci		wIndex--;
359862306a36Sopenharmony_ci		temp = readl(status_reg);
359962306a36Sopenharmony_ci
360062306a36Sopenharmony_ci		/*
360162306a36Sopenharmony_ci		 * Even if OWNER is set, so the port is owned by the
360262306a36Sopenharmony_ci		 * companion controller, hub_wq needs to be able to clear
360362306a36Sopenharmony_ci		 * the port-change status bits (especially
360462306a36Sopenharmony_ci		 * USB_PORT_STAT_C_CONNECTION).
360562306a36Sopenharmony_ci		 */
360662306a36Sopenharmony_ci
360762306a36Sopenharmony_ci		switch (wValue) {
360862306a36Sopenharmony_ci		case USB_PORT_FEAT_ENABLE:
360962306a36Sopenharmony_ci			writel(temp & ~PORT_PE, status_reg);
361062306a36Sopenharmony_ci			break;
361162306a36Sopenharmony_ci		case USB_PORT_FEAT_C_ENABLE:
361262306a36Sopenharmony_ci			writel((temp & ~PORT_RWC_BITS) | PORT_PEC, status_reg);
361362306a36Sopenharmony_ci			break;
361462306a36Sopenharmony_ci		case USB_PORT_FEAT_SUSPEND:
361562306a36Sopenharmony_ci			if (temp & PORT_RESET)
361662306a36Sopenharmony_ci				goto error;
361762306a36Sopenharmony_ci			if (temp & PORT_SUSPEND) {
361862306a36Sopenharmony_ci				if ((temp & PORT_PE) == 0)
361962306a36Sopenharmony_ci					goto error;
362062306a36Sopenharmony_ci				/* resume signaling for 20 msec */
362162306a36Sopenharmony_ci				temp &= ~(PORT_RWC_BITS | PORT_WAKE_BITS);
362262306a36Sopenharmony_ci				writel(temp | PORT_RESUME, status_reg);
362362306a36Sopenharmony_ci				oxu->reset_done[wIndex] = jiffies
362462306a36Sopenharmony_ci						+ msecs_to_jiffies(20);
362562306a36Sopenharmony_ci			}
362662306a36Sopenharmony_ci			break;
362762306a36Sopenharmony_ci		case USB_PORT_FEAT_C_SUSPEND:
362862306a36Sopenharmony_ci			/* we auto-clear this feature */
362962306a36Sopenharmony_ci			break;
363062306a36Sopenharmony_ci		case USB_PORT_FEAT_POWER:
363162306a36Sopenharmony_ci			if (HCS_PPC(oxu->hcs_params))
363262306a36Sopenharmony_ci				writel(temp & ~(PORT_RWC_BITS | PORT_POWER),
363362306a36Sopenharmony_ci					  status_reg);
363462306a36Sopenharmony_ci			break;
363562306a36Sopenharmony_ci		case USB_PORT_FEAT_C_CONNECTION:
363662306a36Sopenharmony_ci			writel((temp & ~PORT_RWC_BITS) | PORT_CSC, status_reg);
363762306a36Sopenharmony_ci			break;
363862306a36Sopenharmony_ci		case USB_PORT_FEAT_C_OVER_CURRENT:
363962306a36Sopenharmony_ci			writel((temp & ~PORT_RWC_BITS) | PORT_OCC, status_reg);
364062306a36Sopenharmony_ci			break;
364162306a36Sopenharmony_ci		case USB_PORT_FEAT_C_RESET:
364262306a36Sopenharmony_ci			/* GetPortStatus clears reset */
364362306a36Sopenharmony_ci			break;
364462306a36Sopenharmony_ci		default:
364562306a36Sopenharmony_ci			goto error;
364662306a36Sopenharmony_ci		}
364762306a36Sopenharmony_ci		readl(&oxu->regs->command);	/* unblock posted write */
364862306a36Sopenharmony_ci		break;
364962306a36Sopenharmony_ci	case GetHubDescriptor:
365062306a36Sopenharmony_ci		ehci_hub_descriptor(oxu, (struct usb_hub_descriptor *)
365162306a36Sopenharmony_ci			buf);
365262306a36Sopenharmony_ci		break;
365362306a36Sopenharmony_ci	case GetHubStatus:
365462306a36Sopenharmony_ci		/* no hub-wide feature/status flags */
365562306a36Sopenharmony_ci		memset(buf, 0, 4);
365662306a36Sopenharmony_ci		break;
365762306a36Sopenharmony_ci	case GetPortStatus:
365862306a36Sopenharmony_ci		if (!wIndex || wIndex > ports)
365962306a36Sopenharmony_ci			goto error;
366062306a36Sopenharmony_ci		wIndex--;
366162306a36Sopenharmony_ci		status = 0;
366262306a36Sopenharmony_ci		temp = readl(status_reg);
366362306a36Sopenharmony_ci
366462306a36Sopenharmony_ci		/* wPortChange bits */
366562306a36Sopenharmony_ci		if (temp & PORT_CSC)
366662306a36Sopenharmony_ci			status |= USB_PORT_STAT_C_CONNECTION << 16;
366762306a36Sopenharmony_ci		if (temp & PORT_PEC)
366862306a36Sopenharmony_ci			status |= USB_PORT_STAT_C_ENABLE << 16;
366962306a36Sopenharmony_ci		if ((temp & PORT_OCC) && !ignore_oc)
367062306a36Sopenharmony_ci			status |= USB_PORT_STAT_C_OVERCURRENT << 16;
367162306a36Sopenharmony_ci
367262306a36Sopenharmony_ci		/* whoever resumes must GetPortStatus to complete it!! */
367362306a36Sopenharmony_ci		if (temp & PORT_RESUME) {
367462306a36Sopenharmony_ci
367562306a36Sopenharmony_ci			/* Remote Wakeup received? */
367662306a36Sopenharmony_ci			if (!oxu->reset_done[wIndex]) {
367762306a36Sopenharmony_ci				/* resume signaling for 20 msec */
367862306a36Sopenharmony_ci				oxu->reset_done[wIndex] = jiffies
367962306a36Sopenharmony_ci						+ msecs_to_jiffies(20);
368062306a36Sopenharmony_ci				/* check the port again */
368162306a36Sopenharmony_ci				mod_timer(&oxu_to_hcd(oxu)->rh_timer,
368262306a36Sopenharmony_ci						oxu->reset_done[wIndex]);
368362306a36Sopenharmony_ci			}
368462306a36Sopenharmony_ci
368562306a36Sopenharmony_ci			/* resume completed? */
368662306a36Sopenharmony_ci			else if (time_after_eq(jiffies,
368762306a36Sopenharmony_ci					oxu->reset_done[wIndex])) {
368862306a36Sopenharmony_ci				status |= USB_PORT_STAT_C_SUSPEND << 16;
368962306a36Sopenharmony_ci				oxu->reset_done[wIndex] = 0;
369062306a36Sopenharmony_ci
369162306a36Sopenharmony_ci				/* stop resume signaling */
369262306a36Sopenharmony_ci				temp = readl(status_reg);
369362306a36Sopenharmony_ci				writel(temp & ~(PORT_RWC_BITS | PORT_RESUME),
369462306a36Sopenharmony_ci					status_reg);
369562306a36Sopenharmony_ci				retval = handshake(oxu, status_reg,
369662306a36Sopenharmony_ci					   PORT_RESUME, 0, 2000 /* 2msec */);
369762306a36Sopenharmony_ci				if (retval != 0) {
369862306a36Sopenharmony_ci					oxu_err(oxu,
369962306a36Sopenharmony_ci						"port %d resume error %d\n",
370062306a36Sopenharmony_ci						wIndex + 1, retval);
370162306a36Sopenharmony_ci					goto error;
370262306a36Sopenharmony_ci				}
370362306a36Sopenharmony_ci				temp &= ~(PORT_SUSPEND|PORT_RESUME|(3<<10));
370462306a36Sopenharmony_ci			}
370562306a36Sopenharmony_ci		}
370662306a36Sopenharmony_ci
370762306a36Sopenharmony_ci		/* whoever resets must GetPortStatus to complete it!! */
370862306a36Sopenharmony_ci		if ((temp & PORT_RESET)
370962306a36Sopenharmony_ci				&& time_after_eq(jiffies,
371062306a36Sopenharmony_ci					oxu->reset_done[wIndex])) {
371162306a36Sopenharmony_ci			status |= USB_PORT_STAT_C_RESET << 16;
371262306a36Sopenharmony_ci			oxu->reset_done[wIndex] = 0;
371362306a36Sopenharmony_ci
371462306a36Sopenharmony_ci			/* force reset to complete */
371562306a36Sopenharmony_ci			writel(temp & ~(PORT_RWC_BITS | PORT_RESET),
371662306a36Sopenharmony_ci					status_reg);
371762306a36Sopenharmony_ci			/* REVISIT:  some hardware needs 550+ usec to clear
371862306a36Sopenharmony_ci			 * this bit; seems too long to spin routinely...
371962306a36Sopenharmony_ci			 */
372062306a36Sopenharmony_ci			retval = handshake(oxu, status_reg,
372162306a36Sopenharmony_ci					PORT_RESET, 0, 750);
372262306a36Sopenharmony_ci			if (retval != 0) {
372362306a36Sopenharmony_ci				oxu_err(oxu, "port %d reset error %d\n",
372462306a36Sopenharmony_ci					wIndex + 1, retval);
372562306a36Sopenharmony_ci				goto error;
372662306a36Sopenharmony_ci			}
372762306a36Sopenharmony_ci
372862306a36Sopenharmony_ci			/* see what we found out */
372962306a36Sopenharmony_ci			temp = check_reset_complete(oxu, wIndex, status_reg,
373062306a36Sopenharmony_ci					readl(status_reg));
373162306a36Sopenharmony_ci		}
373262306a36Sopenharmony_ci
373362306a36Sopenharmony_ci		/* transfer dedicated ports to the companion hc */
373462306a36Sopenharmony_ci		if ((temp & PORT_CONNECT) &&
373562306a36Sopenharmony_ci				test_bit(wIndex, &oxu->companion_ports)) {
373662306a36Sopenharmony_ci			temp &= ~PORT_RWC_BITS;
373762306a36Sopenharmony_ci			temp |= PORT_OWNER;
373862306a36Sopenharmony_ci			writel(temp, status_reg);
373962306a36Sopenharmony_ci			oxu_dbg(oxu, "port %d --> companion\n", wIndex + 1);
374062306a36Sopenharmony_ci			temp = readl(status_reg);
374162306a36Sopenharmony_ci		}
374262306a36Sopenharmony_ci
374362306a36Sopenharmony_ci		/*
374462306a36Sopenharmony_ci		 * Even if OWNER is set, there's no harm letting hub_wq
374562306a36Sopenharmony_ci		 * see the wPortStatus values (they should all be 0 except
374662306a36Sopenharmony_ci		 * for PORT_POWER anyway).
374762306a36Sopenharmony_ci		 */
374862306a36Sopenharmony_ci
374962306a36Sopenharmony_ci		if (temp & PORT_CONNECT) {
375062306a36Sopenharmony_ci			status |= USB_PORT_STAT_CONNECTION;
375162306a36Sopenharmony_ci			/* status may be from integrated TT */
375262306a36Sopenharmony_ci			status |= oxu_port_speed(oxu, temp);
375362306a36Sopenharmony_ci		}
375462306a36Sopenharmony_ci		if (temp & PORT_PE)
375562306a36Sopenharmony_ci			status |= USB_PORT_STAT_ENABLE;
375662306a36Sopenharmony_ci		if (temp & (PORT_SUSPEND|PORT_RESUME))
375762306a36Sopenharmony_ci			status |= USB_PORT_STAT_SUSPEND;
375862306a36Sopenharmony_ci		if (temp & PORT_OC)
375962306a36Sopenharmony_ci			status |= USB_PORT_STAT_OVERCURRENT;
376062306a36Sopenharmony_ci		if (temp & PORT_RESET)
376162306a36Sopenharmony_ci			status |= USB_PORT_STAT_RESET;
376262306a36Sopenharmony_ci		if (temp & PORT_POWER)
376362306a36Sopenharmony_ci			status |= USB_PORT_STAT_POWER;
376462306a36Sopenharmony_ci
376562306a36Sopenharmony_ci#ifndef	OXU_VERBOSE_DEBUG
376662306a36Sopenharmony_ci	if (status & ~0xffff)	/* only if wPortChange is interesting */
376762306a36Sopenharmony_ci#endif
376862306a36Sopenharmony_ci		dbg_port(oxu, "GetStatus", wIndex + 1, temp);
376962306a36Sopenharmony_ci		put_unaligned(cpu_to_le32(status), (__le32 *) buf);
377062306a36Sopenharmony_ci		break;
377162306a36Sopenharmony_ci	case SetHubFeature:
377262306a36Sopenharmony_ci		switch (wValue) {
377362306a36Sopenharmony_ci		case C_HUB_LOCAL_POWER:
377462306a36Sopenharmony_ci		case C_HUB_OVER_CURRENT:
377562306a36Sopenharmony_ci			/* no hub-wide feature/status flags */
377662306a36Sopenharmony_ci			break;
377762306a36Sopenharmony_ci		default:
377862306a36Sopenharmony_ci			goto error;
377962306a36Sopenharmony_ci		}
378062306a36Sopenharmony_ci		break;
378162306a36Sopenharmony_ci	case SetPortFeature:
378262306a36Sopenharmony_ci		selector = wIndex >> 8;
378362306a36Sopenharmony_ci		wIndex &= 0xff;
378462306a36Sopenharmony_ci		if (!wIndex || wIndex > ports)
378562306a36Sopenharmony_ci			goto error;
378662306a36Sopenharmony_ci		wIndex--;
378762306a36Sopenharmony_ci		temp = readl(status_reg);
378862306a36Sopenharmony_ci		if (temp & PORT_OWNER)
378962306a36Sopenharmony_ci			break;
379062306a36Sopenharmony_ci
379162306a36Sopenharmony_ci		temp &= ~PORT_RWC_BITS;
379262306a36Sopenharmony_ci		switch (wValue) {
379362306a36Sopenharmony_ci		case USB_PORT_FEAT_SUSPEND:
379462306a36Sopenharmony_ci			if ((temp & PORT_PE) == 0
379562306a36Sopenharmony_ci					|| (temp & PORT_RESET) != 0)
379662306a36Sopenharmony_ci				goto error;
379762306a36Sopenharmony_ci			if (device_may_wakeup(&hcd->self.root_hub->dev))
379862306a36Sopenharmony_ci				temp |= PORT_WAKE_BITS;
379962306a36Sopenharmony_ci			writel(temp | PORT_SUSPEND, status_reg);
380062306a36Sopenharmony_ci			break;
380162306a36Sopenharmony_ci		case USB_PORT_FEAT_POWER:
380262306a36Sopenharmony_ci			if (HCS_PPC(oxu->hcs_params))
380362306a36Sopenharmony_ci				writel(temp | PORT_POWER, status_reg);
380462306a36Sopenharmony_ci			break;
380562306a36Sopenharmony_ci		case USB_PORT_FEAT_RESET:
380662306a36Sopenharmony_ci			if (temp & PORT_RESUME)
380762306a36Sopenharmony_ci				goto error;
380862306a36Sopenharmony_ci			/* line status bits may report this as low speed,
380962306a36Sopenharmony_ci			 * which can be fine if this root hub has a
381062306a36Sopenharmony_ci			 * transaction translator built in.
381162306a36Sopenharmony_ci			 */
381262306a36Sopenharmony_ci			oxu_vdbg(oxu, "port %d reset\n", wIndex + 1);
381362306a36Sopenharmony_ci			temp |= PORT_RESET;
381462306a36Sopenharmony_ci			temp &= ~PORT_PE;
381562306a36Sopenharmony_ci
381662306a36Sopenharmony_ci			/*
381762306a36Sopenharmony_ci			 * caller must wait, then call GetPortStatus
381862306a36Sopenharmony_ci			 * usb 2.0 spec says 50 ms resets on root
381962306a36Sopenharmony_ci			 */
382062306a36Sopenharmony_ci			oxu->reset_done[wIndex] = jiffies
382162306a36Sopenharmony_ci					+ msecs_to_jiffies(50);
382262306a36Sopenharmony_ci			writel(temp, status_reg);
382362306a36Sopenharmony_ci			break;
382462306a36Sopenharmony_ci
382562306a36Sopenharmony_ci		/* For downstream facing ports (these):  one hub port is put
382662306a36Sopenharmony_ci		 * into test mode according to USB2 11.24.2.13, then the hub
382762306a36Sopenharmony_ci		 * must be reset (which for root hub now means rmmod+modprobe,
382862306a36Sopenharmony_ci		 * or else system reboot).  See EHCI 2.3.9 and 4.14 for info
382962306a36Sopenharmony_ci		 * about the EHCI-specific stuff.
383062306a36Sopenharmony_ci		 */
383162306a36Sopenharmony_ci		case USB_PORT_FEAT_TEST:
383262306a36Sopenharmony_ci			if (!selector || selector > 5)
383362306a36Sopenharmony_ci				goto error;
383462306a36Sopenharmony_ci			ehci_quiesce(oxu);
383562306a36Sopenharmony_ci			ehci_halt(oxu);
383662306a36Sopenharmony_ci			temp |= selector << 16;
383762306a36Sopenharmony_ci			writel(temp, status_reg);
383862306a36Sopenharmony_ci			break;
383962306a36Sopenharmony_ci
384062306a36Sopenharmony_ci		default:
384162306a36Sopenharmony_ci			goto error;
384262306a36Sopenharmony_ci		}
384362306a36Sopenharmony_ci		readl(&oxu->regs->command);	/* unblock posted writes */
384462306a36Sopenharmony_ci		break;
384562306a36Sopenharmony_ci
384662306a36Sopenharmony_ci	default:
384762306a36Sopenharmony_cierror:
384862306a36Sopenharmony_ci		/* "stall" on error */
384962306a36Sopenharmony_ci		retval = -EPIPE;
385062306a36Sopenharmony_ci	}
385162306a36Sopenharmony_ci	spin_unlock_irqrestore(&oxu->lock, flags);
385262306a36Sopenharmony_ci	return retval;
385362306a36Sopenharmony_ci}
385462306a36Sopenharmony_ci
385562306a36Sopenharmony_ci#ifdef CONFIG_PM
385662306a36Sopenharmony_ci
385762306a36Sopenharmony_cistatic int oxu_bus_suspend(struct usb_hcd *hcd)
385862306a36Sopenharmony_ci{
385962306a36Sopenharmony_ci	struct oxu_hcd *oxu = hcd_to_oxu(hcd);
386062306a36Sopenharmony_ci	int port;
386162306a36Sopenharmony_ci	int mask;
386262306a36Sopenharmony_ci
386362306a36Sopenharmony_ci	oxu_dbg(oxu, "suspend root hub\n");
386462306a36Sopenharmony_ci
386562306a36Sopenharmony_ci	if (time_before(jiffies, oxu->next_statechange))
386662306a36Sopenharmony_ci		msleep(5);
386762306a36Sopenharmony_ci
386862306a36Sopenharmony_ci	port = HCS_N_PORTS(oxu->hcs_params);
386962306a36Sopenharmony_ci	spin_lock_irq(&oxu->lock);
387062306a36Sopenharmony_ci
387162306a36Sopenharmony_ci	/* stop schedules, clean any completed work */
387262306a36Sopenharmony_ci	if (HC_IS_RUNNING(hcd->state)) {
387362306a36Sopenharmony_ci		ehci_quiesce(oxu);
387462306a36Sopenharmony_ci		hcd->state = HC_STATE_QUIESCING;
387562306a36Sopenharmony_ci	}
387662306a36Sopenharmony_ci	oxu->command = readl(&oxu->regs->command);
387762306a36Sopenharmony_ci	if (oxu->reclaim)
387862306a36Sopenharmony_ci		oxu->reclaim_ready = 1;
387962306a36Sopenharmony_ci	ehci_work(oxu);
388062306a36Sopenharmony_ci
388162306a36Sopenharmony_ci	/* Unlike other USB host controller types, EHCI doesn't have
388262306a36Sopenharmony_ci	 * any notion of "global" or bus-wide suspend.  The driver has
388362306a36Sopenharmony_ci	 * to manually suspend all the active unsuspended ports, and
388462306a36Sopenharmony_ci	 * then manually resume them in the bus_resume() routine.
388562306a36Sopenharmony_ci	 */
388662306a36Sopenharmony_ci	oxu->bus_suspended = 0;
388762306a36Sopenharmony_ci	while (port--) {
388862306a36Sopenharmony_ci		u32 __iomem *reg = &oxu->regs->port_status[port];
388962306a36Sopenharmony_ci		u32 t1 = readl(reg) & ~PORT_RWC_BITS;
389062306a36Sopenharmony_ci		u32 t2 = t1;
389162306a36Sopenharmony_ci
389262306a36Sopenharmony_ci		/* keep track of which ports we suspend */
389362306a36Sopenharmony_ci		if ((t1 & PORT_PE) && !(t1 & PORT_OWNER) &&
389462306a36Sopenharmony_ci				!(t1 & PORT_SUSPEND)) {
389562306a36Sopenharmony_ci			t2 |= PORT_SUSPEND;
389662306a36Sopenharmony_ci			set_bit(port, &oxu->bus_suspended);
389762306a36Sopenharmony_ci		}
389862306a36Sopenharmony_ci
389962306a36Sopenharmony_ci		/* enable remote wakeup on all ports */
390062306a36Sopenharmony_ci		if (device_may_wakeup(&hcd->self.root_hub->dev))
390162306a36Sopenharmony_ci			t2 |= PORT_WKOC_E|PORT_WKDISC_E|PORT_WKCONN_E;
390262306a36Sopenharmony_ci		else
390362306a36Sopenharmony_ci			t2 &= ~(PORT_WKOC_E|PORT_WKDISC_E|PORT_WKCONN_E);
390462306a36Sopenharmony_ci
390562306a36Sopenharmony_ci		if (t1 != t2) {
390662306a36Sopenharmony_ci			oxu_vdbg(oxu, "port %d, %08x -> %08x\n",
390762306a36Sopenharmony_ci				port + 1, t1, t2);
390862306a36Sopenharmony_ci			writel(t2, reg);
390962306a36Sopenharmony_ci		}
391062306a36Sopenharmony_ci	}
391162306a36Sopenharmony_ci
391262306a36Sopenharmony_ci	spin_unlock_irq(&oxu->lock);
391362306a36Sopenharmony_ci	/* turn off now-idle HC */
391462306a36Sopenharmony_ci	del_timer_sync(&oxu->watchdog);
391562306a36Sopenharmony_ci	spin_lock_irq(&oxu->lock);
391662306a36Sopenharmony_ci	ehci_halt(oxu);
391762306a36Sopenharmony_ci	hcd->state = HC_STATE_SUSPENDED;
391862306a36Sopenharmony_ci
391962306a36Sopenharmony_ci	/* allow remote wakeup */
392062306a36Sopenharmony_ci	mask = INTR_MASK;
392162306a36Sopenharmony_ci	if (!device_may_wakeup(&hcd->self.root_hub->dev))
392262306a36Sopenharmony_ci		mask &= ~STS_PCD;
392362306a36Sopenharmony_ci	writel(mask, &oxu->regs->intr_enable);
392462306a36Sopenharmony_ci	readl(&oxu->regs->intr_enable);
392562306a36Sopenharmony_ci
392662306a36Sopenharmony_ci	oxu->next_statechange = jiffies + msecs_to_jiffies(10);
392762306a36Sopenharmony_ci	spin_unlock_irq(&oxu->lock);
392862306a36Sopenharmony_ci	return 0;
392962306a36Sopenharmony_ci}
393062306a36Sopenharmony_ci
393162306a36Sopenharmony_ci/* Caller has locked the root hub, and should reset/reinit on error */
393262306a36Sopenharmony_cistatic int oxu_bus_resume(struct usb_hcd *hcd)
393362306a36Sopenharmony_ci{
393462306a36Sopenharmony_ci	struct oxu_hcd *oxu = hcd_to_oxu(hcd);
393562306a36Sopenharmony_ci	u32 temp;
393662306a36Sopenharmony_ci	int i;
393762306a36Sopenharmony_ci
393862306a36Sopenharmony_ci	if (time_before(jiffies, oxu->next_statechange))
393962306a36Sopenharmony_ci		msleep(5);
394062306a36Sopenharmony_ci	spin_lock_irq(&oxu->lock);
394162306a36Sopenharmony_ci
394262306a36Sopenharmony_ci	/* Ideally and we've got a real resume here, and no port's power
394362306a36Sopenharmony_ci	 * was lost.  (For PCI, that means Vaux was maintained.)  But we
394462306a36Sopenharmony_ci	 * could instead be restoring a swsusp snapshot -- so that BIOS was
394562306a36Sopenharmony_ci	 * the last user of the controller, not reset/pm hardware keeping
394662306a36Sopenharmony_ci	 * state we gave to it.
394762306a36Sopenharmony_ci	 */
394862306a36Sopenharmony_ci	temp = readl(&oxu->regs->intr_enable);
394962306a36Sopenharmony_ci	oxu_dbg(oxu, "resume root hub%s\n", temp ? "" : " after power loss");
395062306a36Sopenharmony_ci
395162306a36Sopenharmony_ci	/* at least some APM implementations will try to deliver
395262306a36Sopenharmony_ci	 * IRQs right away, so delay them until we're ready.
395362306a36Sopenharmony_ci	 */
395462306a36Sopenharmony_ci	writel(0, &oxu->regs->intr_enable);
395562306a36Sopenharmony_ci
395662306a36Sopenharmony_ci	/* re-init operational registers */
395762306a36Sopenharmony_ci	writel(0, &oxu->regs->segment);
395862306a36Sopenharmony_ci	writel(oxu->periodic_dma, &oxu->regs->frame_list);
395962306a36Sopenharmony_ci	writel((u32) oxu->async->qh_dma, &oxu->regs->async_next);
396062306a36Sopenharmony_ci
396162306a36Sopenharmony_ci	/* restore CMD_RUN, framelist size, and irq threshold */
396262306a36Sopenharmony_ci	writel(oxu->command, &oxu->regs->command);
396362306a36Sopenharmony_ci
396462306a36Sopenharmony_ci	/* Some controller/firmware combinations need a delay during which
396562306a36Sopenharmony_ci	 * they set up the port statuses.  See Bugzilla #8190. */
396662306a36Sopenharmony_ci	mdelay(8);
396762306a36Sopenharmony_ci
396862306a36Sopenharmony_ci	/* manually resume the ports we suspended during bus_suspend() */
396962306a36Sopenharmony_ci	i = HCS_N_PORTS(oxu->hcs_params);
397062306a36Sopenharmony_ci	while (i--) {
397162306a36Sopenharmony_ci		temp = readl(&oxu->regs->port_status[i]);
397262306a36Sopenharmony_ci		temp &= ~(PORT_RWC_BITS
397362306a36Sopenharmony_ci			| PORT_WKOC_E | PORT_WKDISC_E | PORT_WKCONN_E);
397462306a36Sopenharmony_ci		if (test_bit(i, &oxu->bus_suspended) && (temp & PORT_SUSPEND)) {
397562306a36Sopenharmony_ci			oxu->reset_done[i] = jiffies + msecs_to_jiffies(20);
397662306a36Sopenharmony_ci			temp |= PORT_RESUME;
397762306a36Sopenharmony_ci		}
397862306a36Sopenharmony_ci		writel(temp, &oxu->regs->port_status[i]);
397962306a36Sopenharmony_ci	}
398062306a36Sopenharmony_ci	i = HCS_N_PORTS(oxu->hcs_params);
398162306a36Sopenharmony_ci	mdelay(20);
398262306a36Sopenharmony_ci	while (i--) {
398362306a36Sopenharmony_ci		temp = readl(&oxu->regs->port_status[i]);
398462306a36Sopenharmony_ci		if (test_bit(i, &oxu->bus_suspended) && (temp & PORT_SUSPEND)) {
398562306a36Sopenharmony_ci			temp &= ~(PORT_RWC_BITS | PORT_RESUME);
398662306a36Sopenharmony_ci			writel(temp, &oxu->regs->port_status[i]);
398762306a36Sopenharmony_ci			oxu_vdbg(oxu, "resumed port %d\n", i + 1);
398862306a36Sopenharmony_ci		}
398962306a36Sopenharmony_ci	}
399062306a36Sopenharmony_ci	(void) readl(&oxu->regs->command);
399162306a36Sopenharmony_ci
399262306a36Sopenharmony_ci	/* maybe re-activate the schedule(s) */
399362306a36Sopenharmony_ci	temp = 0;
399462306a36Sopenharmony_ci	if (oxu->async->qh_next.qh)
399562306a36Sopenharmony_ci		temp |= CMD_ASE;
399662306a36Sopenharmony_ci	if (oxu->periodic_sched)
399762306a36Sopenharmony_ci		temp |= CMD_PSE;
399862306a36Sopenharmony_ci	if (temp) {
399962306a36Sopenharmony_ci		oxu->command |= temp;
400062306a36Sopenharmony_ci		writel(oxu->command, &oxu->regs->command);
400162306a36Sopenharmony_ci	}
400262306a36Sopenharmony_ci
400362306a36Sopenharmony_ci	oxu->next_statechange = jiffies + msecs_to_jiffies(5);
400462306a36Sopenharmony_ci	hcd->state = HC_STATE_RUNNING;
400562306a36Sopenharmony_ci
400662306a36Sopenharmony_ci	/* Now we can safely re-enable irqs */
400762306a36Sopenharmony_ci	writel(INTR_MASK, &oxu->regs->intr_enable);
400862306a36Sopenharmony_ci
400962306a36Sopenharmony_ci	spin_unlock_irq(&oxu->lock);
401062306a36Sopenharmony_ci	return 0;
401162306a36Sopenharmony_ci}
401262306a36Sopenharmony_ci
401362306a36Sopenharmony_ci#else
401462306a36Sopenharmony_ci
401562306a36Sopenharmony_cistatic int oxu_bus_suspend(struct usb_hcd *hcd)
401662306a36Sopenharmony_ci{
401762306a36Sopenharmony_ci	return 0;
401862306a36Sopenharmony_ci}
401962306a36Sopenharmony_ci
402062306a36Sopenharmony_cistatic int oxu_bus_resume(struct usb_hcd *hcd)
402162306a36Sopenharmony_ci{
402262306a36Sopenharmony_ci	return 0;
402362306a36Sopenharmony_ci}
402462306a36Sopenharmony_ci
402562306a36Sopenharmony_ci#endif	/* CONFIG_PM */
402662306a36Sopenharmony_ci
402762306a36Sopenharmony_cistatic const struct hc_driver oxu_hc_driver = {
402862306a36Sopenharmony_ci	.description =		"oxu210hp_hcd",
402962306a36Sopenharmony_ci	.product_desc =		"oxu210hp HCD",
403062306a36Sopenharmony_ci	.hcd_priv_size =	sizeof(struct oxu_hcd),
403162306a36Sopenharmony_ci
403262306a36Sopenharmony_ci	/*
403362306a36Sopenharmony_ci	 * Generic hardware linkage
403462306a36Sopenharmony_ci	 */
403562306a36Sopenharmony_ci	.irq =			oxu_irq,
403662306a36Sopenharmony_ci	.flags =		HCD_MEMORY | HCD_USB2,
403762306a36Sopenharmony_ci
403862306a36Sopenharmony_ci	/*
403962306a36Sopenharmony_ci	 * Basic lifecycle operations
404062306a36Sopenharmony_ci	 */
404162306a36Sopenharmony_ci	.reset =		oxu_reset,
404262306a36Sopenharmony_ci	.start =		oxu_run,
404362306a36Sopenharmony_ci	.stop =			oxu_stop,
404462306a36Sopenharmony_ci	.shutdown =		oxu_shutdown,
404562306a36Sopenharmony_ci
404662306a36Sopenharmony_ci	/*
404762306a36Sopenharmony_ci	 * Managing i/o requests and associated device resources
404862306a36Sopenharmony_ci	 */
404962306a36Sopenharmony_ci	.urb_enqueue =		oxu_urb_enqueue,
405062306a36Sopenharmony_ci	.urb_dequeue =		oxu_urb_dequeue,
405162306a36Sopenharmony_ci	.endpoint_disable =	oxu_endpoint_disable,
405262306a36Sopenharmony_ci
405362306a36Sopenharmony_ci	/*
405462306a36Sopenharmony_ci	 * Scheduling support
405562306a36Sopenharmony_ci	 */
405662306a36Sopenharmony_ci	.get_frame_number =	oxu_get_frame,
405762306a36Sopenharmony_ci
405862306a36Sopenharmony_ci	/*
405962306a36Sopenharmony_ci	 * Root hub support
406062306a36Sopenharmony_ci	 */
406162306a36Sopenharmony_ci	.hub_status_data =	oxu_hub_status_data,
406262306a36Sopenharmony_ci	.hub_control =		oxu_hub_control,
406362306a36Sopenharmony_ci	.bus_suspend =		oxu_bus_suspend,
406462306a36Sopenharmony_ci	.bus_resume =		oxu_bus_resume,
406562306a36Sopenharmony_ci};
406662306a36Sopenharmony_ci
406762306a36Sopenharmony_ci/*
406862306a36Sopenharmony_ci * Module stuff
406962306a36Sopenharmony_ci */
407062306a36Sopenharmony_ci
407162306a36Sopenharmony_cistatic void oxu_configuration(struct platform_device *pdev, void __iomem *base)
407262306a36Sopenharmony_ci{
407362306a36Sopenharmony_ci	u32 tmp;
407462306a36Sopenharmony_ci
407562306a36Sopenharmony_ci	/* Initialize top level registers.
407662306a36Sopenharmony_ci	 * First write ever
407762306a36Sopenharmony_ci	 */
407862306a36Sopenharmony_ci	oxu_writel(base, OXU_HOSTIFCONFIG, 0x0000037D);
407962306a36Sopenharmony_ci	oxu_writel(base, OXU_SOFTRESET, OXU_SRESET);
408062306a36Sopenharmony_ci	oxu_writel(base, OXU_HOSTIFCONFIG, 0x0000037D);
408162306a36Sopenharmony_ci
408262306a36Sopenharmony_ci	tmp = oxu_readl(base, OXU_PIOBURSTREADCTRL);
408362306a36Sopenharmony_ci	oxu_writel(base, OXU_PIOBURSTREADCTRL, tmp | 0x0040);
408462306a36Sopenharmony_ci
408562306a36Sopenharmony_ci	oxu_writel(base, OXU_ASO, OXU_SPHPOEN | OXU_OVRCCURPUPDEN |
408662306a36Sopenharmony_ci					OXU_COMPARATOR | OXU_ASO_OP);
408762306a36Sopenharmony_ci
408862306a36Sopenharmony_ci	tmp = oxu_readl(base, OXU_CLKCTRL_SET);
408962306a36Sopenharmony_ci	oxu_writel(base, OXU_CLKCTRL_SET, tmp | OXU_SYSCLKEN | OXU_USBOTGCLKEN);
409062306a36Sopenharmony_ci
409162306a36Sopenharmony_ci	/* Clear all top interrupt enable */
409262306a36Sopenharmony_ci	oxu_writel(base, OXU_CHIPIRQEN_CLR, 0xff);
409362306a36Sopenharmony_ci
409462306a36Sopenharmony_ci	/* Clear all top interrupt status */
409562306a36Sopenharmony_ci	oxu_writel(base, OXU_CHIPIRQSTATUS, 0xff);
409662306a36Sopenharmony_ci
409762306a36Sopenharmony_ci	/* Enable all needed top interrupt except OTG SPH core */
409862306a36Sopenharmony_ci	oxu_writel(base, OXU_CHIPIRQEN_SET, OXU_USBSPHLPWUI | OXU_USBOTGLPWUI);
409962306a36Sopenharmony_ci}
410062306a36Sopenharmony_ci
410162306a36Sopenharmony_cistatic int oxu_verify_id(struct platform_device *pdev, void __iomem *base)
410262306a36Sopenharmony_ci{
410362306a36Sopenharmony_ci	u32 id;
410462306a36Sopenharmony_ci	static const char * const bo[] = {
410562306a36Sopenharmony_ci		"reserved",
410662306a36Sopenharmony_ci		"128-pin LQFP",
410762306a36Sopenharmony_ci		"84-pin TFBGA",
410862306a36Sopenharmony_ci		"reserved",
410962306a36Sopenharmony_ci	};
411062306a36Sopenharmony_ci
411162306a36Sopenharmony_ci	/* Read controller signature register to find a match */
411262306a36Sopenharmony_ci	id = oxu_readl(base, OXU_DEVICEID);
411362306a36Sopenharmony_ci	dev_info(&pdev->dev, "device ID %x\n", id);
411462306a36Sopenharmony_ci	if ((id & OXU_REV_MASK) != (OXU_REV_2100 << OXU_REV_SHIFT))
411562306a36Sopenharmony_ci		return -1;
411662306a36Sopenharmony_ci
411762306a36Sopenharmony_ci	dev_info(&pdev->dev, "found device %x %s (%04x:%04x)\n",
411862306a36Sopenharmony_ci		id >> OXU_REV_SHIFT,
411962306a36Sopenharmony_ci		bo[(id & OXU_BO_MASK) >> OXU_BO_SHIFT],
412062306a36Sopenharmony_ci		(id & OXU_MAJ_REV_MASK) >> OXU_MAJ_REV_SHIFT,
412162306a36Sopenharmony_ci		(id & OXU_MIN_REV_MASK) >> OXU_MIN_REV_SHIFT);
412262306a36Sopenharmony_ci
412362306a36Sopenharmony_ci	return 0;
412462306a36Sopenharmony_ci}
412562306a36Sopenharmony_ci
412662306a36Sopenharmony_cistatic const struct hc_driver oxu_hc_driver;
412762306a36Sopenharmony_cistatic struct usb_hcd *oxu_create(struct platform_device *pdev,
412862306a36Sopenharmony_ci				unsigned long memstart, unsigned long memlen,
412962306a36Sopenharmony_ci				void __iomem *base, int irq, int otg)
413062306a36Sopenharmony_ci{
413162306a36Sopenharmony_ci	struct device *dev = &pdev->dev;
413262306a36Sopenharmony_ci
413362306a36Sopenharmony_ci	struct usb_hcd *hcd;
413462306a36Sopenharmony_ci	struct oxu_hcd *oxu;
413562306a36Sopenharmony_ci	int ret;
413662306a36Sopenharmony_ci
413762306a36Sopenharmony_ci	/* Set endian mode and host mode */
413862306a36Sopenharmony_ci	oxu_writel(base + (otg ? OXU_OTG_CORE_OFFSET : OXU_SPH_CORE_OFFSET),
413962306a36Sopenharmony_ci				OXU_USBMODE,
414062306a36Sopenharmony_ci				OXU_CM_HOST_ONLY | OXU_ES_LITTLE | OXU_VBPS);
414162306a36Sopenharmony_ci
414262306a36Sopenharmony_ci	hcd = usb_create_hcd(&oxu_hc_driver, dev,
414362306a36Sopenharmony_ci				otg ? "oxu210hp_otg" : "oxu210hp_sph");
414462306a36Sopenharmony_ci	if (!hcd)
414562306a36Sopenharmony_ci		return ERR_PTR(-ENOMEM);
414662306a36Sopenharmony_ci
414762306a36Sopenharmony_ci	hcd->rsrc_start = memstart;
414862306a36Sopenharmony_ci	hcd->rsrc_len = memlen;
414962306a36Sopenharmony_ci	hcd->regs = base;
415062306a36Sopenharmony_ci	hcd->irq = irq;
415162306a36Sopenharmony_ci	hcd->state = HC_STATE_HALT;
415262306a36Sopenharmony_ci
415362306a36Sopenharmony_ci	oxu = hcd_to_oxu(hcd);
415462306a36Sopenharmony_ci	oxu->is_otg = otg;
415562306a36Sopenharmony_ci
415662306a36Sopenharmony_ci	ret = usb_add_hcd(hcd, irq, IRQF_SHARED);
415762306a36Sopenharmony_ci	if (ret < 0) {
415862306a36Sopenharmony_ci		usb_put_hcd(hcd);
415962306a36Sopenharmony_ci		return ERR_PTR(ret);
416062306a36Sopenharmony_ci	}
416162306a36Sopenharmony_ci
416262306a36Sopenharmony_ci	device_wakeup_enable(hcd->self.controller);
416362306a36Sopenharmony_ci	return hcd;
416462306a36Sopenharmony_ci}
416562306a36Sopenharmony_ci
416662306a36Sopenharmony_cistatic int oxu_init(struct platform_device *pdev,
416762306a36Sopenharmony_ci				unsigned long memstart, unsigned long memlen,
416862306a36Sopenharmony_ci				void __iomem *base, int irq)
416962306a36Sopenharmony_ci{
417062306a36Sopenharmony_ci	struct oxu_info *info = platform_get_drvdata(pdev);
417162306a36Sopenharmony_ci	struct usb_hcd *hcd;
417262306a36Sopenharmony_ci	int ret;
417362306a36Sopenharmony_ci
417462306a36Sopenharmony_ci	/* First time configuration at start up */
417562306a36Sopenharmony_ci	oxu_configuration(pdev, base);
417662306a36Sopenharmony_ci
417762306a36Sopenharmony_ci	ret = oxu_verify_id(pdev, base);
417862306a36Sopenharmony_ci	if (ret) {
417962306a36Sopenharmony_ci		dev_err(&pdev->dev, "no devices found!\n");
418062306a36Sopenharmony_ci		return -ENODEV;
418162306a36Sopenharmony_ci	}
418262306a36Sopenharmony_ci
418362306a36Sopenharmony_ci	/* Create the OTG controller */
418462306a36Sopenharmony_ci	hcd = oxu_create(pdev, memstart, memlen, base, irq, 1);
418562306a36Sopenharmony_ci	if (IS_ERR(hcd)) {
418662306a36Sopenharmony_ci		dev_err(&pdev->dev, "cannot create OTG controller!\n");
418762306a36Sopenharmony_ci		ret = PTR_ERR(hcd);
418862306a36Sopenharmony_ci		goto error_create_otg;
418962306a36Sopenharmony_ci	}
419062306a36Sopenharmony_ci	info->hcd[0] = hcd;
419162306a36Sopenharmony_ci
419262306a36Sopenharmony_ci	/* Create the SPH host controller */
419362306a36Sopenharmony_ci	hcd = oxu_create(pdev, memstart, memlen, base, irq, 0);
419462306a36Sopenharmony_ci	if (IS_ERR(hcd)) {
419562306a36Sopenharmony_ci		dev_err(&pdev->dev, "cannot create SPH controller!\n");
419662306a36Sopenharmony_ci		ret = PTR_ERR(hcd);
419762306a36Sopenharmony_ci		goto error_create_sph;
419862306a36Sopenharmony_ci	}
419962306a36Sopenharmony_ci	info->hcd[1] = hcd;
420062306a36Sopenharmony_ci
420162306a36Sopenharmony_ci	oxu_writel(base, OXU_CHIPIRQEN_SET,
420262306a36Sopenharmony_ci		oxu_readl(base, OXU_CHIPIRQEN_SET) | 3);
420362306a36Sopenharmony_ci
420462306a36Sopenharmony_ci	return 0;
420562306a36Sopenharmony_ci
420662306a36Sopenharmony_cierror_create_sph:
420762306a36Sopenharmony_ci	usb_remove_hcd(info->hcd[0]);
420862306a36Sopenharmony_ci	usb_put_hcd(info->hcd[0]);
420962306a36Sopenharmony_ci
421062306a36Sopenharmony_cierror_create_otg:
421162306a36Sopenharmony_ci	return ret;
421262306a36Sopenharmony_ci}
421362306a36Sopenharmony_ci
421462306a36Sopenharmony_cistatic int oxu_drv_probe(struct platform_device *pdev)
421562306a36Sopenharmony_ci{
421662306a36Sopenharmony_ci	struct resource *res;
421762306a36Sopenharmony_ci	void __iomem *base;
421862306a36Sopenharmony_ci	unsigned long memstart, memlen;
421962306a36Sopenharmony_ci	int irq, ret;
422062306a36Sopenharmony_ci	struct oxu_info *info;
422162306a36Sopenharmony_ci
422262306a36Sopenharmony_ci	if (usb_disabled())
422362306a36Sopenharmony_ci		return -ENODEV;
422462306a36Sopenharmony_ci
422562306a36Sopenharmony_ci	/*
422662306a36Sopenharmony_ci	 * Get the platform resources
422762306a36Sopenharmony_ci	 */
422862306a36Sopenharmony_ci	irq = platform_get_irq(pdev, 0);
422962306a36Sopenharmony_ci	if (irq < 0)
423062306a36Sopenharmony_ci		return irq;
423162306a36Sopenharmony_ci	dev_dbg(&pdev->dev, "IRQ resource %d\n", irq);
423262306a36Sopenharmony_ci
423362306a36Sopenharmony_ci	base = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
423462306a36Sopenharmony_ci	if (IS_ERR(base)) {
423562306a36Sopenharmony_ci		ret = PTR_ERR(base);
423662306a36Sopenharmony_ci		goto error;
423762306a36Sopenharmony_ci	}
423862306a36Sopenharmony_ci	memstart = res->start;
423962306a36Sopenharmony_ci	memlen = resource_size(res);
424062306a36Sopenharmony_ci
424162306a36Sopenharmony_ci	ret = irq_set_irq_type(irq, IRQF_TRIGGER_FALLING);
424262306a36Sopenharmony_ci	if (ret) {
424362306a36Sopenharmony_ci		dev_err(&pdev->dev, "error setting irq type\n");
424462306a36Sopenharmony_ci		ret = -EFAULT;
424562306a36Sopenharmony_ci		goto error;
424662306a36Sopenharmony_ci	}
424762306a36Sopenharmony_ci
424862306a36Sopenharmony_ci	/* Allocate a driver data struct to hold useful info for both
424962306a36Sopenharmony_ci	 * SPH & OTG devices
425062306a36Sopenharmony_ci	 */
425162306a36Sopenharmony_ci	info = devm_kzalloc(&pdev->dev, sizeof(struct oxu_info), GFP_KERNEL);
425262306a36Sopenharmony_ci	if (!info) {
425362306a36Sopenharmony_ci		ret = -EFAULT;
425462306a36Sopenharmony_ci		goto error;
425562306a36Sopenharmony_ci	}
425662306a36Sopenharmony_ci	platform_set_drvdata(pdev, info);
425762306a36Sopenharmony_ci
425862306a36Sopenharmony_ci	ret = oxu_init(pdev, memstart, memlen, base, irq);
425962306a36Sopenharmony_ci	if (ret < 0) {
426062306a36Sopenharmony_ci		dev_dbg(&pdev->dev, "cannot init USB devices\n");
426162306a36Sopenharmony_ci		goto error;
426262306a36Sopenharmony_ci	}
426362306a36Sopenharmony_ci
426462306a36Sopenharmony_ci	dev_info(&pdev->dev, "devices enabled and running\n");
426562306a36Sopenharmony_ci	platform_set_drvdata(pdev, info);
426662306a36Sopenharmony_ci
426762306a36Sopenharmony_ci	return 0;
426862306a36Sopenharmony_ci
426962306a36Sopenharmony_cierror:
427062306a36Sopenharmony_ci	dev_err(&pdev->dev, "init %s fail, %d\n", dev_name(&pdev->dev), ret);
427162306a36Sopenharmony_ci	return ret;
427262306a36Sopenharmony_ci}
427362306a36Sopenharmony_ci
427462306a36Sopenharmony_cistatic void oxu_remove(struct platform_device *pdev, struct usb_hcd *hcd)
427562306a36Sopenharmony_ci{
427662306a36Sopenharmony_ci	usb_remove_hcd(hcd);
427762306a36Sopenharmony_ci	usb_put_hcd(hcd);
427862306a36Sopenharmony_ci}
427962306a36Sopenharmony_ci
428062306a36Sopenharmony_cistatic void oxu_drv_remove(struct platform_device *pdev)
428162306a36Sopenharmony_ci{
428262306a36Sopenharmony_ci	struct oxu_info *info = platform_get_drvdata(pdev);
428362306a36Sopenharmony_ci
428462306a36Sopenharmony_ci	oxu_remove(pdev, info->hcd[0]);
428562306a36Sopenharmony_ci	oxu_remove(pdev, info->hcd[1]);
428662306a36Sopenharmony_ci}
428762306a36Sopenharmony_ci
428862306a36Sopenharmony_cistatic void oxu_drv_shutdown(struct platform_device *pdev)
428962306a36Sopenharmony_ci{
429062306a36Sopenharmony_ci	oxu_drv_remove(pdev);
429162306a36Sopenharmony_ci}
429262306a36Sopenharmony_ci
429362306a36Sopenharmony_ci#if 0
429462306a36Sopenharmony_ci/* FIXME: TODO */
429562306a36Sopenharmony_cistatic int oxu_drv_suspend(struct device *dev)
429662306a36Sopenharmony_ci{
429762306a36Sopenharmony_ci	struct platform_device *pdev = to_platform_device(dev);
429862306a36Sopenharmony_ci	struct usb_hcd *hcd = dev_get_drvdata(dev);
429962306a36Sopenharmony_ci
430062306a36Sopenharmony_ci	return 0;
430162306a36Sopenharmony_ci}
430262306a36Sopenharmony_ci
430362306a36Sopenharmony_cistatic int oxu_drv_resume(struct device *dev)
430462306a36Sopenharmony_ci{
430562306a36Sopenharmony_ci	struct platform_device *pdev = to_platform_device(dev);
430662306a36Sopenharmony_ci	struct usb_hcd *hcd = dev_get_drvdata(dev);
430762306a36Sopenharmony_ci
430862306a36Sopenharmony_ci	return 0;
430962306a36Sopenharmony_ci}
431062306a36Sopenharmony_ci#else
431162306a36Sopenharmony_ci#define oxu_drv_suspend	NULL
431262306a36Sopenharmony_ci#define oxu_drv_resume	NULL
431362306a36Sopenharmony_ci#endif
431462306a36Sopenharmony_ci
431562306a36Sopenharmony_cistatic struct platform_driver oxu_driver = {
431662306a36Sopenharmony_ci	.probe		= oxu_drv_probe,
431762306a36Sopenharmony_ci	.remove_new	= oxu_drv_remove,
431862306a36Sopenharmony_ci	.shutdown	= oxu_drv_shutdown,
431962306a36Sopenharmony_ci	.suspend	= oxu_drv_suspend,
432062306a36Sopenharmony_ci	.resume		= oxu_drv_resume,
432162306a36Sopenharmony_ci	.driver = {
432262306a36Sopenharmony_ci		.name = "oxu210hp-hcd",
432362306a36Sopenharmony_ci		.bus = &platform_bus_type
432462306a36Sopenharmony_ci	}
432562306a36Sopenharmony_ci};
432662306a36Sopenharmony_ci
432762306a36Sopenharmony_cimodule_platform_driver(oxu_driver);
432862306a36Sopenharmony_ci
432962306a36Sopenharmony_ciMODULE_DESCRIPTION("Oxford OXU210HP HCD driver - ver. " DRIVER_VERSION);
433062306a36Sopenharmony_ciMODULE_AUTHOR("Rodolfo Giometti <giometti@linux.it>");
433162306a36Sopenharmony_ciMODULE_LICENSE("GPL");
4332