162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * c67x00-sched.c: Cypress C67X00 USB Host Controller Driver - TD scheduling
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright (C) 2006-2008 Barco N.V.
662306a36Sopenharmony_ci *    Derived from the Cypress cy7c67200/300 ezusb linux driver and
762306a36Sopenharmony_ci *    based on multiple host controller drivers inside the linux kernel.
862306a36Sopenharmony_ci */
962306a36Sopenharmony_ci
1062306a36Sopenharmony_ci#include <linux/kthread.h>
1162306a36Sopenharmony_ci#include <linux/slab.h>
1262306a36Sopenharmony_ci
1362306a36Sopenharmony_ci#include "c67x00.h"
1462306a36Sopenharmony_ci#include "c67x00-hcd.h"
1562306a36Sopenharmony_ci
1662306a36Sopenharmony_ci/*
1762306a36Sopenharmony_ci * These are the stages for a control urb, they are kept
1862306a36Sopenharmony_ci * in both urb->interval and td->privdata.
1962306a36Sopenharmony_ci */
2062306a36Sopenharmony_ci#define SETUP_STAGE		0
2162306a36Sopenharmony_ci#define DATA_STAGE		1
2262306a36Sopenharmony_ci#define STATUS_STAGE		2
2362306a36Sopenharmony_ci
2462306a36Sopenharmony_ci/* -------------------------------------------------------------------------- */
2562306a36Sopenharmony_ci
2662306a36Sopenharmony_ci/*
2762306a36Sopenharmony_ci * struct c67x00_ep_data: Host endpoint data structure
2862306a36Sopenharmony_ci */
2962306a36Sopenharmony_cistruct c67x00_ep_data {
3062306a36Sopenharmony_ci	struct list_head queue;
3162306a36Sopenharmony_ci	struct list_head node;
3262306a36Sopenharmony_ci	struct usb_host_endpoint *hep;
3362306a36Sopenharmony_ci	struct usb_device *dev;
3462306a36Sopenharmony_ci	u16 next_frame;		/* For int/isoc transactions */
3562306a36Sopenharmony_ci};
3662306a36Sopenharmony_ci
3762306a36Sopenharmony_ci/*
3862306a36Sopenharmony_ci * struct c67x00_td
3962306a36Sopenharmony_ci *
4062306a36Sopenharmony_ci * Hardware parts are little endiannes, SW in CPU endianess.
4162306a36Sopenharmony_ci */
4262306a36Sopenharmony_cistruct c67x00_td {
4362306a36Sopenharmony_ci	/* HW specific part */
4462306a36Sopenharmony_ci	__le16 ly_base_addr;	/* Bytes 0-1 */
4562306a36Sopenharmony_ci	__le16 port_length;	/* Bytes 2-3 */
4662306a36Sopenharmony_ci	u8 pid_ep;		/* Byte 4 */
4762306a36Sopenharmony_ci	u8 dev_addr;		/* Byte 5 */
4862306a36Sopenharmony_ci	u8 ctrl_reg;		/* Byte 6 */
4962306a36Sopenharmony_ci	u8 status;		/* Byte 7 */
5062306a36Sopenharmony_ci	u8 retry_cnt;		/* Byte 8 */
5162306a36Sopenharmony_ci#define TT_OFFSET		2
5262306a36Sopenharmony_ci#define TT_CONTROL		0
5362306a36Sopenharmony_ci#define TT_ISOCHRONOUS		1
5462306a36Sopenharmony_ci#define TT_BULK			2
5562306a36Sopenharmony_ci#define TT_INTERRUPT		3
5662306a36Sopenharmony_ci	u8 residue;		/* Byte 9 */
5762306a36Sopenharmony_ci	__le16 next_td_addr;	/* Bytes 10-11 */
5862306a36Sopenharmony_ci	/* SW part */
5962306a36Sopenharmony_ci	struct list_head td_list;
6062306a36Sopenharmony_ci	u16 td_addr;
6162306a36Sopenharmony_ci	void *data;
6262306a36Sopenharmony_ci	struct urb *urb;
6362306a36Sopenharmony_ci	unsigned long privdata;
6462306a36Sopenharmony_ci
6562306a36Sopenharmony_ci	/* These are needed for handling the toggle bits:
6662306a36Sopenharmony_ci	 * an urb can be dequeued while a td is in progress
6762306a36Sopenharmony_ci	 * after checking the td, the toggle bit might need to
6862306a36Sopenharmony_ci	 * be fixed */
6962306a36Sopenharmony_ci	struct c67x00_ep_data *ep_data;
7062306a36Sopenharmony_ci	unsigned int pipe;
7162306a36Sopenharmony_ci};
7262306a36Sopenharmony_ci
7362306a36Sopenharmony_cistruct c67x00_urb_priv {
7462306a36Sopenharmony_ci	struct list_head hep_node;
7562306a36Sopenharmony_ci	struct urb *urb;
7662306a36Sopenharmony_ci	int port;
7762306a36Sopenharmony_ci	int cnt;		/* packet number for isoc */
7862306a36Sopenharmony_ci	int status;
7962306a36Sopenharmony_ci	struct c67x00_ep_data *ep_data;
8062306a36Sopenharmony_ci};
8162306a36Sopenharmony_ci
8262306a36Sopenharmony_ci#define td_udev(td)	((td)->ep_data->dev)
8362306a36Sopenharmony_ci
8462306a36Sopenharmony_ci#define CY_TD_SIZE		12
8562306a36Sopenharmony_ci
8662306a36Sopenharmony_ci#define TD_PIDEP_OFFSET		0x04
8762306a36Sopenharmony_ci#define TD_PIDEPMASK_PID	0xF0
8862306a36Sopenharmony_ci#define TD_PIDEPMASK_EP		0x0F
8962306a36Sopenharmony_ci#define TD_PORTLENMASK_DL	0x03FF
9062306a36Sopenharmony_ci#define TD_PORTLENMASK_PN	0xC000
9162306a36Sopenharmony_ci
9262306a36Sopenharmony_ci#define TD_STATUS_OFFSET	0x07
9362306a36Sopenharmony_ci#define TD_STATUSMASK_ACK	0x01
9462306a36Sopenharmony_ci#define TD_STATUSMASK_ERR	0x02
9562306a36Sopenharmony_ci#define TD_STATUSMASK_TMOUT	0x04
9662306a36Sopenharmony_ci#define TD_STATUSMASK_SEQ	0x08
9762306a36Sopenharmony_ci#define TD_STATUSMASK_SETUP	0x10
9862306a36Sopenharmony_ci#define TD_STATUSMASK_OVF	0x20
9962306a36Sopenharmony_ci#define TD_STATUSMASK_NAK	0x40
10062306a36Sopenharmony_ci#define TD_STATUSMASK_STALL	0x80
10162306a36Sopenharmony_ci
10262306a36Sopenharmony_ci#define TD_ERROR_MASK		(TD_STATUSMASK_ERR | TD_STATUSMASK_TMOUT | \
10362306a36Sopenharmony_ci				 TD_STATUSMASK_STALL)
10462306a36Sopenharmony_ci
10562306a36Sopenharmony_ci#define TD_RETRYCNT_OFFSET	0x08
10662306a36Sopenharmony_ci#define TD_RETRYCNTMASK_ACT_FLG	0x10
10762306a36Sopenharmony_ci#define TD_RETRYCNTMASK_TX_TYPE	0x0C
10862306a36Sopenharmony_ci#define TD_RETRYCNTMASK_RTY_CNT	0x03
10962306a36Sopenharmony_ci
11062306a36Sopenharmony_ci#define TD_RESIDUE_OVERFLOW	0x80
11162306a36Sopenharmony_ci
11262306a36Sopenharmony_ci#define TD_PID_IN		0x90
11362306a36Sopenharmony_ci
11462306a36Sopenharmony_ci/* Residue: signed 8bits, neg -> OVERFLOW, pos -> UNDERFLOW */
11562306a36Sopenharmony_ci#define td_residue(td)		((__s8)(td->residue))
11662306a36Sopenharmony_ci#define td_ly_base_addr(td)	(__le16_to_cpu((td)->ly_base_addr))
11762306a36Sopenharmony_ci#define td_port_length(td)	(__le16_to_cpu((td)->port_length))
11862306a36Sopenharmony_ci#define td_next_td_addr(td)	(__le16_to_cpu((td)->next_td_addr))
11962306a36Sopenharmony_ci
12062306a36Sopenharmony_ci#define td_active(td)		((td)->retry_cnt & TD_RETRYCNTMASK_ACT_FLG)
12162306a36Sopenharmony_ci#define td_length(td)		(td_port_length(td) & TD_PORTLENMASK_DL)
12262306a36Sopenharmony_ci
12362306a36Sopenharmony_ci#define td_sequence_ok(td)	(!td->status || \
12462306a36Sopenharmony_ci				 (!(td->status & TD_STATUSMASK_SEQ) ==	\
12562306a36Sopenharmony_ci				  !(td->ctrl_reg & SEQ_SEL)))
12662306a36Sopenharmony_ci
12762306a36Sopenharmony_ci#define td_acked(td)		(!td->status || \
12862306a36Sopenharmony_ci				 (td->status & TD_STATUSMASK_ACK))
12962306a36Sopenharmony_ci#define td_actual_bytes(td)	(td_length(td) - td_residue(td))
13062306a36Sopenharmony_ci
13162306a36Sopenharmony_ci/* -------------------------------------------------------------------------- */
13262306a36Sopenharmony_ci
13362306a36Sopenharmony_ci/*
13462306a36Sopenharmony_ci * dbg_td - Dump the contents of the TD
13562306a36Sopenharmony_ci */
13662306a36Sopenharmony_cistatic void dbg_td(struct c67x00_hcd *c67x00, struct c67x00_td *td, char *msg)
13762306a36Sopenharmony_ci{
13862306a36Sopenharmony_ci	struct device *dev = c67x00_hcd_dev(c67x00);
13962306a36Sopenharmony_ci
14062306a36Sopenharmony_ci	dev_dbg(dev, "### %s at 0x%04x\n", msg, td->td_addr);
14162306a36Sopenharmony_ci	dev_dbg(dev, "urb:      0x%p\n", td->urb);
14262306a36Sopenharmony_ci	dev_dbg(dev, "endpoint:   %4d\n", usb_pipeendpoint(td->pipe));
14362306a36Sopenharmony_ci	dev_dbg(dev, "pipeout:    %4d\n", usb_pipeout(td->pipe));
14462306a36Sopenharmony_ci	dev_dbg(dev, "ly_base_addr: 0x%04x\n", td_ly_base_addr(td));
14562306a36Sopenharmony_ci	dev_dbg(dev, "port_length:  0x%04x\n", td_port_length(td));
14662306a36Sopenharmony_ci	dev_dbg(dev, "pid_ep:         0x%02x\n", td->pid_ep);
14762306a36Sopenharmony_ci	dev_dbg(dev, "dev_addr:       0x%02x\n", td->dev_addr);
14862306a36Sopenharmony_ci	dev_dbg(dev, "ctrl_reg:       0x%02x\n", td->ctrl_reg);
14962306a36Sopenharmony_ci	dev_dbg(dev, "status:         0x%02x\n", td->status);
15062306a36Sopenharmony_ci	dev_dbg(dev, "retry_cnt:      0x%02x\n", td->retry_cnt);
15162306a36Sopenharmony_ci	dev_dbg(dev, "residue:        0x%02x\n", td->residue);
15262306a36Sopenharmony_ci	dev_dbg(dev, "next_td_addr: 0x%04x\n", td_next_td_addr(td));
15362306a36Sopenharmony_ci	dev_dbg(dev, "data: %*ph\n", td_length(td), td->data);
15462306a36Sopenharmony_ci}
15562306a36Sopenharmony_ci
15662306a36Sopenharmony_ci/* -------------------------------------------------------------------------- */
15762306a36Sopenharmony_ci/* Helper functions */
15862306a36Sopenharmony_ci
15962306a36Sopenharmony_cistatic inline u16 c67x00_get_current_frame_number(struct c67x00_hcd *c67x00)
16062306a36Sopenharmony_ci{
16162306a36Sopenharmony_ci	return c67x00_ll_husb_get_frame(c67x00->sie) & HOST_FRAME_MASK;
16262306a36Sopenharmony_ci}
16362306a36Sopenharmony_ci
16462306a36Sopenharmony_ci/*
16562306a36Sopenharmony_ci * frame_add
16662306a36Sopenharmony_ci * Software wraparound for framenumbers.
16762306a36Sopenharmony_ci */
16862306a36Sopenharmony_cistatic inline u16 frame_add(u16 a, u16 b)
16962306a36Sopenharmony_ci{
17062306a36Sopenharmony_ci	return (a + b) & HOST_FRAME_MASK;
17162306a36Sopenharmony_ci}
17262306a36Sopenharmony_ci
17362306a36Sopenharmony_ci/*
17462306a36Sopenharmony_ci * frame_after - is frame a after frame b
17562306a36Sopenharmony_ci */
17662306a36Sopenharmony_cistatic inline int frame_after(u16 a, u16 b)
17762306a36Sopenharmony_ci{
17862306a36Sopenharmony_ci	return ((HOST_FRAME_MASK + a - b) & HOST_FRAME_MASK) <
17962306a36Sopenharmony_ci	    (HOST_FRAME_MASK / 2);
18062306a36Sopenharmony_ci}
18162306a36Sopenharmony_ci
18262306a36Sopenharmony_ci/*
18362306a36Sopenharmony_ci * frame_after_eq - is frame a after or equal to frame b
18462306a36Sopenharmony_ci */
18562306a36Sopenharmony_cistatic inline int frame_after_eq(u16 a, u16 b)
18662306a36Sopenharmony_ci{
18762306a36Sopenharmony_ci	return ((HOST_FRAME_MASK + 1 + a - b) & HOST_FRAME_MASK) <
18862306a36Sopenharmony_ci	    (HOST_FRAME_MASK / 2);
18962306a36Sopenharmony_ci}
19062306a36Sopenharmony_ci
19162306a36Sopenharmony_ci/* -------------------------------------------------------------------------- */
19262306a36Sopenharmony_ci
19362306a36Sopenharmony_ci/*
19462306a36Sopenharmony_ci * c67x00_release_urb - remove link from all tds to this urb
19562306a36Sopenharmony_ci * Disconnects the urb from it's tds, so that it can be given back.
19662306a36Sopenharmony_ci * pre: urb->hcpriv != NULL
19762306a36Sopenharmony_ci */
19862306a36Sopenharmony_cistatic void c67x00_release_urb(struct c67x00_hcd *c67x00, struct urb *urb)
19962306a36Sopenharmony_ci{
20062306a36Sopenharmony_ci	struct c67x00_td *td;
20162306a36Sopenharmony_ci	struct c67x00_urb_priv *urbp;
20262306a36Sopenharmony_ci
20362306a36Sopenharmony_ci	BUG_ON(!urb);
20462306a36Sopenharmony_ci
20562306a36Sopenharmony_ci	c67x00->urb_count--;
20662306a36Sopenharmony_ci
20762306a36Sopenharmony_ci	if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) {
20862306a36Sopenharmony_ci		c67x00->urb_iso_count--;
20962306a36Sopenharmony_ci		if (c67x00->urb_iso_count == 0)
21062306a36Sopenharmony_ci			c67x00->max_frame_bw = MAX_FRAME_BW_STD;
21162306a36Sopenharmony_ci	}
21262306a36Sopenharmony_ci
21362306a36Sopenharmony_ci	/* TODO this might be not so efficient when we've got many urbs!
21462306a36Sopenharmony_ci	 * Alternatives:
21562306a36Sopenharmony_ci	 *   * only clear when needed
21662306a36Sopenharmony_ci	 *   * keep a list of tds with each urbp
21762306a36Sopenharmony_ci	 */
21862306a36Sopenharmony_ci	list_for_each_entry(td, &c67x00->td_list, td_list)
21962306a36Sopenharmony_ci		if (urb == td->urb)
22062306a36Sopenharmony_ci			td->urb = NULL;
22162306a36Sopenharmony_ci
22262306a36Sopenharmony_ci	urbp = urb->hcpriv;
22362306a36Sopenharmony_ci	urb->hcpriv = NULL;
22462306a36Sopenharmony_ci	list_del(&urbp->hep_node);
22562306a36Sopenharmony_ci	kfree(urbp);
22662306a36Sopenharmony_ci}
22762306a36Sopenharmony_ci
22862306a36Sopenharmony_ci/* -------------------------------------------------------------------------- */
22962306a36Sopenharmony_ci
23062306a36Sopenharmony_cistatic struct c67x00_ep_data *
23162306a36Sopenharmony_cic67x00_ep_data_alloc(struct c67x00_hcd *c67x00, struct urb *urb)
23262306a36Sopenharmony_ci{
23362306a36Sopenharmony_ci	struct usb_host_endpoint *hep = urb->ep;
23462306a36Sopenharmony_ci	struct c67x00_ep_data *ep_data;
23562306a36Sopenharmony_ci	int type;
23662306a36Sopenharmony_ci
23762306a36Sopenharmony_ci	c67x00->current_frame = c67x00_get_current_frame_number(c67x00);
23862306a36Sopenharmony_ci
23962306a36Sopenharmony_ci	/* Check if endpoint already has a c67x00_ep_data struct allocated */
24062306a36Sopenharmony_ci	if (hep->hcpriv) {
24162306a36Sopenharmony_ci		ep_data = hep->hcpriv;
24262306a36Sopenharmony_ci		if (frame_after(c67x00->current_frame, ep_data->next_frame))
24362306a36Sopenharmony_ci			ep_data->next_frame =
24462306a36Sopenharmony_ci			    frame_add(c67x00->current_frame, 1);
24562306a36Sopenharmony_ci		return hep->hcpriv;
24662306a36Sopenharmony_ci	}
24762306a36Sopenharmony_ci
24862306a36Sopenharmony_ci	/* Allocate and initialize a new c67x00 endpoint data structure */
24962306a36Sopenharmony_ci	ep_data = kzalloc(sizeof(*ep_data), GFP_ATOMIC);
25062306a36Sopenharmony_ci	if (!ep_data)
25162306a36Sopenharmony_ci		return NULL;
25262306a36Sopenharmony_ci
25362306a36Sopenharmony_ci	INIT_LIST_HEAD(&ep_data->queue);
25462306a36Sopenharmony_ci	INIT_LIST_HEAD(&ep_data->node);
25562306a36Sopenharmony_ci	ep_data->hep = hep;
25662306a36Sopenharmony_ci
25762306a36Sopenharmony_ci	/* hold a reference to udev as long as this endpoint lives,
25862306a36Sopenharmony_ci	 * this is needed to possibly fix the data toggle */
25962306a36Sopenharmony_ci	ep_data->dev = usb_get_dev(urb->dev);
26062306a36Sopenharmony_ci	hep->hcpriv = ep_data;
26162306a36Sopenharmony_ci
26262306a36Sopenharmony_ci	/* For ISOC and INT endpoints, start ASAP: */
26362306a36Sopenharmony_ci	ep_data->next_frame = frame_add(c67x00->current_frame, 1);
26462306a36Sopenharmony_ci
26562306a36Sopenharmony_ci	/* Add the endpoint data to one of the pipe lists; must be added
26662306a36Sopenharmony_ci	   in order of endpoint address */
26762306a36Sopenharmony_ci	type = usb_pipetype(urb->pipe);
26862306a36Sopenharmony_ci	if (list_empty(&ep_data->node)) {
26962306a36Sopenharmony_ci		list_add(&ep_data->node, &c67x00->list[type]);
27062306a36Sopenharmony_ci	} else {
27162306a36Sopenharmony_ci		struct c67x00_ep_data *prev;
27262306a36Sopenharmony_ci
27362306a36Sopenharmony_ci		list_for_each_entry(prev, &c67x00->list[type], node) {
27462306a36Sopenharmony_ci			if (prev->hep->desc.bEndpointAddress >
27562306a36Sopenharmony_ci			    hep->desc.bEndpointAddress) {
27662306a36Sopenharmony_ci				list_add(&ep_data->node, prev->node.prev);
27762306a36Sopenharmony_ci				break;
27862306a36Sopenharmony_ci			}
27962306a36Sopenharmony_ci		}
28062306a36Sopenharmony_ci	}
28162306a36Sopenharmony_ci
28262306a36Sopenharmony_ci	return ep_data;
28362306a36Sopenharmony_ci}
28462306a36Sopenharmony_ci
28562306a36Sopenharmony_cistatic int c67x00_ep_data_free(struct usb_host_endpoint *hep)
28662306a36Sopenharmony_ci{
28762306a36Sopenharmony_ci	struct c67x00_ep_data *ep_data = hep->hcpriv;
28862306a36Sopenharmony_ci
28962306a36Sopenharmony_ci	if (!ep_data)
29062306a36Sopenharmony_ci		return 0;
29162306a36Sopenharmony_ci
29262306a36Sopenharmony_ci	if (!list_empty(&ep_data->queue))
29362306a36Sopenharmony_ci		return -EBUSY;
29462306a36Sopenharmony_ci
29562306a36Sopenharmony_ci	usb_put_dev(ep_data->dev);
29662306a36Sopenharmony_ci	list_del(&ep_data->queue);
29762306a36Sopenharmony_ci	list_del(&ep_data->node);
29862306a36Sopenharmony_ci
29962306a36Sopenharmony_ci	kfree(ep_data);
30062306a36Sopenharmony_ci	hep->hcpriv = NULL;
30162306a36Sopenharmony_ci
30262306a36Sopenharmony_ci	return 0;
30362306a36Sopenharmony_ci}
30462306a36Sopenharmony_ci
30562306a36Sopenharmony_civoid c67x00_endpoint_disable(struct usb_hcd *hcd, struct usb_host_endpoint *ep)
30662306a36Sopenharmony_ci{
30762306a36Sopenharmony_ci	struct c67x00_hcd *c67x00 = hcd_to_c67x00_hcd(hcd);
30862306a36Sopenharmony_ci	unsigned long flags;
30962306a36Sopenharmony_ci
31062306a36Sopenharmony_ci	if (!list_empty(&ep->urb_list))
31162306a36Sopenharmony_ci		dev_warn(c67x00_hcd_dev(c67x00), "error: urb list not empty\n");
31262306a36Sopenharmony_ci
31362306a36Sopenharmony_ci	spin_lock_irqsave(&c67x00->lock, flags);
31462306a36Sopenharmony_ci
31562306a36Sopenharmony_ci	/* loop waiting for all transfers in the endpoint queue to complete */
31662306a36Sopenharmony_ci	while (c67x00_ep_data_free(ep)) {
31762306a36Sopenharmony_ci		/* Drop the lock so we can sleep waiting for the hardware */
31862306a36Sopenharmony_ci		spin_unlock_irqrestore(&c67x00->lock, flags);
31962306a36Sopenharmony_ci
32062306a36Sopenharmony_ci		/* it could happen that we reinitialize this completion, while
32162306a36Sopenharmony_ci		 * somebody was waiting for that completion.  The timeout and
32262306a36Sopenharmony_ci		 * while loop handle such cases, but this might be improved */
32362306a36Sopenharmony_ci		reinit_completion(&c67x00->endpoint_disable);
32462306a36Sopenharmony_ci		c67x00_sched_kick(c67x00);
32562306a36Sopenharmony_ci		wait_for_completion_timeout(&c67x00->endpoint_disable, 1 * HZ);
32662306a36Sopenharmony_ci
32762306a36Sopenharmony_ci		spin_lock_irqsave(&c67x00->lock, flags);
32862306a36Sopenharmony_ci	}
32962306a36Sopenharmony_ci
33062306a36Sopenharmony_ci	spin_unlock_irqrestore(&c67x00->lock, flags);
33162306a36Sopenharmony_ci}
33262306a36Sopenharmony_ci
33362306a36Sopenharmony_ci/* -------------------------------------------------------------------------- */
33462306a36Sopenharmony_ci
33562306a36Sopenharmony_cistatic inline int get_root_port(struct usb_device *dev)
33662306a36Sopenharmony_ci{
33762306a36Sopenharmony_ci	while (dev->parent->parent)
33862306a36Sopenharmony_ci		dev = dev->parent;
33962306a36Sopenharmony_ci	return dev->portnum;
34062306a36Sopenharmony_ci}
34162306a36Sopenharmony_ci
34262306a36Sopenharmony_ciint c67x00_urb_enqueue(struct usb_hcd *hcd,
34362306a36Sopenharmony_ci		       struct urb *urb, gfp_t mem_flags)
34462306a36Sopenharmony_ci{
34562306a36Sopenharmony_ci	int ret;
34662306a36Sopenharmony_ci	unsigned long flags;
34762306a36Sopenharmony_ci	struct c67x00_urb_priv *urbp;
34862306a36Sopenharmony_ci	struct c67x00_hcd *c67x00 = hcd_to_c67x00_hcd(hcd);
34962306a36Sopenharmony_ci	int port = get_root_port(urb->dev)-1;
35062306a36Sopenharmony_ci
35162306a36Sopenharmony_ci	/* Allocate and initialize urb private data */
35262306a36Sopenharmony_ci	urbp = kzalloc(sizeof(*urbp), mem_flags);
35362306a36Sopenharmony_ci	if (!urbp) {
35462306a36Sopenharmony_ci		ret = -ENOMEM;
35562306a36Sopenharmony_ci		goto err_urbp;
35662306a36Sopenharmony_ci	}
35762306a36Sopenharmony_ci
35862306a36Sopenharmony_ci	spin_lock_irqsave(&c67x00->lock, flags);
35962306a36Sopenharmony_ci
36062306a36Sopenharmony_ci	/* Make sure host controller is running */
36162306a36Sopenharmony_ci	if (!HC_IS_RUNNING(hcd->state)) {
36262306a36Sopenharmony_ci		ret = -ENODEV;
36362306a36Sopenharmony_ci		goto err_not_linked;
36462306a36Sopenharmony_ci	}
36562306a36Sopenharmony_ci
36662306a36Sopenharmony_ci	ret = usb_hcd_link_urb_to_ep(hcd, urb);
36762306a36Sopenharmony_ci	if (ret)
36862306a36Sopenharmony_ci		goto err_not_linked;
36962306a36Sopenharmony_ci
37062306a36Sopenharmony_ci	INIT_LIST_HEAD(&urbp->hep_node);
37162306a36Sopenharmony_ci	urbp->urb = urb;
37262306a36Sopenharmony_ci	urbp->port = port;
37362306a36Sopenharmony_ci
37462306a36Sopenharmony_ci	urbp->ep_data = c67x00_ep_data_alloc(c67x00, urb);
37562306a36Sopenharmony_ci
37662306a36Sopenharmony_ci	if (!urbp->ep_data) {
37762306a36Sopenharmony_ci		ret = -ENOMEM;
37862306a36Sopenharmony_ci		goto err_epdata;
37962306a36Sopenharmony_ci	}
38062306a36Sopenharmony_ci
38162306a36Sopenharmony_ci	/* TODO claim bandwidth with usb_claim_bandwidth?
38262306a36Sopenharmony_ci	 * also release it somewhere! */
38362306a36Sopenharmony_ci
38462306a36Sopenharmony_ci	urb->hcpriv = urbp;
38562306a36Sopenharmony_ci
38662306a36Sopenharmony_ci	urb->actual_length = 0;	/* Nothing received/transmitted yet */
38762306a36Sopenharmony_ci
38862306a36Sopenharmony_ci	switch (usb_pipetype(urb->pipe)) {
38962306a36Sopenharmony_ci	case PIPE_CONTROL:
39062306a36Sopenharmony_ci		urb->interval = SETUP_STAGE;
39162306a36Sopenharmony_ci		break;
39262306a36Sopenharmony_ci	case PIPE_INTERRUPT:
39362306a36Sopenharmony_ci		break;
39462306a36Sopenharmony_ci	case PIPE_BULK:
39562306a36Sopenharmony_ci		break;
39662306a36Sopenharmony_ci	case PIPE_ISOCHRONOUS:
39762306a36Sopenharmony_ci		if (c67x00->urb_iso_count == 0)
39862306a36Sopenharmony_ci			c67x00->max_frame_bw = MAX_FRAME_BW_ISO;
39962306a36Sopenharmony_ci		c67x00->urb_iso_count++;
40062306a36Sopenharmony_ci		/* Assume always URB_ISO_ASAP, FIXME */
40162306a36Sopenharmony_ci		if (list_empty(&urbp->ep_data->queue))
40262306a36Sopenharmony_ci			urb->start_frame = urbp->ep_data->next_frame;
40362306a36Sopenharmony_ci		else {
40462306a36Sopenharmony_ci			/* Go right after the last one */
40562306a36Sopenharmony_ci			struct urb *last_urb;
40662306a36Sopenharmony_ci
40762306a36Sopenharmony_ci			last_urb = list_entry(urbp->ep_data->queue.prev,
40862306a36Sopenharmony_ci					      struct c67x00_urb_priv,
40962306a36Sopenharmony_ci					      hep_node)->urb;
41062306a36Sopenharmony_ci			urb->start_frame =
41162306a36Sopenharmony_ci			    frame_add(last_urb->start_frame,
41262306a36Sopenharmony_ci				      last_urb->number_of_packets *
41362306a36Sopenharmony_ci				      last_urb->interval);
41462306a36Sopenharmony_ci		}
41562306a36Sopenharmony_ci		urbp->cnt = 0;
41662306a36Sopenharmony_ci		break;
41762306a36Sopenharmony_ci	}
41862306a36Sopenharmony_ci
41962306a36Sopenharmony_ci	/* Add the URB to the endpoint queue */
42062306a36Sopenharmony_ci	list_add_tail(&urbp->hep_node, &urbp->ep_data->queue);
42162306a36Sopenharmony_ci
42262306a36Sopenharmony_ci	/* If this is the only URB, kick start the controller */
42362306a36Sopenharmony_ci	if (!c67x00->urb_count++)
42462306a36Sopenharmony_ci		c67x00_ll_hpi_enable_sofeop(c67x00->sie);
42562306a36Sopenharmony_ci
42662306a36Sopenharmony_ci	c67x00_sched_kick(c67x00);
42762306a36Sopenharmony_ci	spin_unlock_irqrestore(&c67x00->lock, flags);
42862306a36Sopenharmony_ci
42962306a36Sopenharmony_ci	return 0;
43062306a36Sopenharmony_ci
43162306a36Sopenharmony_cierr_epdata:
43262306a36Sopenharmony_ci	usb_hcd_unlink_urb_from_ep(hcd, urb);
43362306a36Sopenharmony_cierr_not_linked:
43462306a36Sopenharmony_ci	spin_unlock_irqrestore(&c67x00->lock, flags);
43562306a36Sopenharmony_ci	kfree(urbp);
43662306a36Sopenharmony_cierr_urbp:
43762306a36Sopenharmony_ci
43862306a36Sopenharmony_ci	return ret;
43962306a36Sopenharmony_ci}
44062306a36Sopenharmony_ci
44162306a36Sopenharmony_ciint c67x00_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
44262306a36Sopenharmony_ci{
44362306a36Sopenharmony_ci	struct c67x00_hcd *c67x00 = hcd_to_c67x00_hcd(hcd);
44462306a36Sopenharmony_ci	unsigned long flags;
44562306a36Sopenharmony_ci	int rc;
44662306a36Sopenharmony_ci
44762306a36Sopenharmony_ci	spin_lock_irqsave(&c67x00->lock, flags);
44862306a36Sopenharmony_ci	rc = usb_hcd_check_unlink_urb(hcd, urb, status);
44962306a36Sopenharmony_ci	if (rc)
45062306a36Sopenharmony_ci		goto done;
45162306a36Sopenharmony_ci
45262306a36Sopenharmony_ci	c67x00_release_urb(c67x00, urb);
45362306a36Sopenharmony_ci	usb_hcd_unlink_urb_from_ep(hcd, urb);
45462306a36Sopenharmony_ci
45562306a36Sopenharmony_ci	spin_unlock(&c67x00->lock);
45662306a36Sopenharmony_ci	usb_hcd_giveback_urb(hcd, urb, status);
45762306a36Sopenharmony_ci	spin_lock(&c67x00->lock);
45862306a36Sopenharmony_ci
45962306a36Sopenharmony_ci	spin_unlock_irqrestore(&c67x00->lock, flags);
46062306a36Sopenharmony_ci
46162306a36Sopenharmony_ci	return 0;
46262306a36Sopenharmony_ci
46362306a36Sopenharmony_ci done:
46462306a36Sopenharmony_ci	spin_unlock_irqrestore(&c67x00->lock, flags);
46562306a36Sopenharmony_ci	return rc;
46662306a36Sopenharmony_ci}
46762306a36Sopenharmony_ci
46862306a36Sopenharmony_ci/* -------------------------------------------------------------------------- */
46962306a36Sopenharmony_ci
47062306a36Sopenharmony_ci/*
47162306a36Sopenharmony_ci * pre: c67x00 locked, urb unlocked
47262306a36Sopenharmony_ci */
47362306a36Sopenharmony_cistatic void
47462306a36Sopenharmony_cic67x00_giveback_urb(struct c67x00_hcd *c67x00, struct urb *urb, int status)
47562306a36Sopenharmony_ci{
47662306a36Sopenharmony_ci	struct c67x00_urb_priv *urbp;
47762306a36Sopenharmony_ci
47862306a36Sopenharmony_ci	if (!urb)
47962306a36Sopenharmony_ci		return;
48062306a36Sopenharmony_ci
48162306a36Sopenharmony_ci	urbp = urb->hcpriv;
48262306a36Sopenharmony_ci	urbp->status = status;
48362306a36Sopenharmony_ci
48462306a36Sopenharmony_ci	list_del_init(&urbp->hep_node);
48562306a36Sopenharmony_ci
48662306a36Sopenharmony_ci	c67x00_release_urb(c67x00, urb);
48762306a36Sopenharmony_ci	usb_hcd_unlink_urb_from_ep(c67x00_hcd_to_hcd(c67x00), urb);
48862306a36Sopenharmony_ci	spin_unlock(&c67x00->lock);
48962306a36Sopenharmony_ci	usb_hcd_giveback_urb(c67x00_hcd_to_hcd(c67x00), urb, status);
49062306a36Sopenharmony_ci	spin_lock(&c67x00->lock);
49162306a36Sopenharmony_ci}
49262306a36Sopenharmony_ci
49362306a36Sopenharmony_ci/* -------------------------------------------------------------------------- */
49462306a36Sopenharmony_ci
49562306a36Sopenharmony_cistatic int c67x00_claim_frame_bw(struct c67x00_hcd *c67x00, struct urb *urb,
49662306a36Sopenharmony_ci				 int len, int periodic)
49762306a36Sopenharmony_ci{
49862306a36Sopenharmony_ci	struct c67x00_urb_priv *urbp = urb->hcpriv;
49962306a36Sopenharmony_ci	int bit_time;
50062306a36Sopenharmony_ci
50162306a36Sopenharmony_ci	/* According to the C67x00 BIOS user manual, page 3-18,19, the
50262306a36Sopenharmony_ci	 * following calculations provide the full speed bit times for
50362306a36Sopenharmony_ci	 * a transaction.
50462306a36Sopenharmony_ci	 *
50562306a36Sopenharmony_ci	 * FS(in)	= 112.5 +  9.36*BC + HOST_DELAY
50662306a36Sopenharmony_ci	 * FS(in,iso)	=  90.5 +  9.36*BC + HOST_DELAY
50762306a36Sopenharmony_ci	 * FS(out)	= 112.5 +  9.36*BC + HOST_DELAY
50862306a36Sopenharmony_ci	 * FS(out,iso)	=  78.4 +  9.36*BC + HOST_DELAY
50962306a36Sopenharmony_ci	 * LS(in)	= 802.4 + 75.78*BC + HOST_DELAY
51062306a36Sopenharmony_ci	 * LS(out)	= 802.6 + 74.67*BC + HOST_DELAY
51162306a36Sopenharmony_ci	 *
51262306a36Sopenharmony_ci	 * HOST_DELAY == 106 for the c67200 and c67300.
51362306a36Sopenharmony_ci	 */
51462306a36Sopenharmony_ci
51562306a36Sopenharmony_ci	/* make calculations in 1/100 bit times to maintain resolution */
51662306a36Sopenharmony_ci	if (urbp->ep_data->dev->speed == USB_SPEED_LOW) {
51762306a36Sopenharmony_ci		/* Low speed pipe */
51862306a36Sopenharmony_ci		if (usb_pipein(urb->pipe))
51962306a36Sopenharmony_ci			bit_time = 80240 + 7578*len;
52062306a36Sopenharmony_ci		else
52162306a36Sopenharmony_ci			bit_time = 80260 + 7467*len;
52262306a36Sopenharmony_ci	} else {
52362306a36Sopenharmony_ci		/* FS pipes */
52462306a36Sopenharmony_ci		if (usb_pipeisoc(urb->pipe))
52562306a36Sopenharmony_ci			bit_time = usb_pipein(urb->pipe) ? 9050 : 7840;
52662306a36Sopenharmony_ci		else
52762306a36Sopenharmony_ci			bit_time = 11250;
52862306a36Sopenharmony_ci		bit_time += 936*len;
52962306a36Sopenharmony_ci	}
53062306a36Sopenharmony_ci
53162306a36Sopenharmony_ci	/* Scale back down to integer bit times.  Use a host delay of 106.
53262306a36Sopenharmony_ci	 * (this is the only place it is used) */
53362306a36Sopenharmony_ci	bit_time = ((bit_time+50) / 100) + 106;
53462306a36Sopenharmony_ci
53562306a36Sopenharmony_ci	if (unlikely(bit_time + c67x00->bandwidth_allocated >=
53662306a36Sopenharmony_ci		     c67x00->max_frame_bw))
53762306a36Sopenharmony_ci		return -EMSGSIZE;
53862306a36Sopenharmony_ci
53962306a36Sopenharmony_ci	if (unlikely(c67x00->next_td_addr + CY_TD_SIZE >=
54062306a36Sopenharmony_ci		     c67x00->td_base_addr + SIE_TD_SIZE))
54162306a36Sopenharmony_ci		return -EMSGSIZE;
54262306a36Sopenharmony_ci
54362306a36Sopenharmony_ci	if (unlikely(c67x00->next_buf_addr + len >=
54462306a36Sopenharmony_ci		     c67x00->buf_base_addr + SIE_TD_BUF_SIZE))
54562306a36Sopenharmony_ci		return -EMSGSIZE;
54662306a36Sopenharmony_ci
54762306a36Sopenharmony_ci	if (periodic) {
54862306a36Sopenharmony_ci		if (unlikely(bit_time + c67x00->periodic_bw_allocated >=
54962306a36Sopenharmony_ci			     MAX_PERIODIC_BW(c67x00->max_frame_bw)))
55062306a36Sopenharmony_ci			return -EMSGSIZE;
55162306a36Sopenharmony_ci		c67x00->periodic_bw_allocated += bit_time;
55262306a36Sopenharmony_ci	}
55362306a36Sopenharmony_ci
55462306a36Sopenharmony_ci	c67x00->bandwidth_allocated += bit_time;
55562306a36Sopenharmony_ci	return 0;
55662306a36Sopenharmony_ci}
55762306a36Sopenharmony_ci
55862306a36Sopenharmony_ci/* -------------------------------------------------------------------------- */
55962306a36Sopenharmony_ci
56062306a36Sopenharmony_ci/*
56162306a36Sopenharmony_ci * td_addr and buf_addr must be word aligned
56262306a36Sopenharmony_ci */
56362306a36Sopenharmony_cistatic int c67x00_create_td(struct c67x00_hcd *c67x00, struct urb *urb,
56462306a36Sopenharmony_ci			    void *data, int len, int pid, int toggle,
56562306a36Sopenharmony_ci			    unsigned long privdata)
56662306a36Sopenharmony_ci{
56762306a36Sopenharmony_ci	struct c67x00_td *td;
56862306a36Sopenharmony_ci	struct c67x00_urb_priv *urbp = urb->hcpriv;
56962306a36Sopenharmony_ci	const __u8 active_flag = 1, retry_cnt = 3;
57062306a36Sopenharmony_ci	__u8 cmd = 0;
57162306a36Sopenharmony_ci	int tt = 0;
57262306a36Sopenharmony_ci
57362306a36Sopenharmony_ci	if (c67x00_claim_frame_bw(c67x00, urb, len, usb_pipeisoc(urb->pipe)
57462306a36Sopenharmony_ci				  || usb_pipeint(urb->pipe)))
57562306a36Sopenharmony_ci		return -EMSGSIZE;	/* Not really an error, but expected */
57662306a36Sopenharmony_ci
57762306a36Sopenharmony_ci	td = kzalloc(sizeof(*td), GFP_ATOMIC);
57862306a36Sopenharmony_ci	if (!td)
57962306a36Sopenharmony_ci		return -ENOMEM;
58062306a36Sopenharmony_ci
58162306a36Sopenharmony_ci	td->pipe = urb->pipe;
58262306a36Sopenharmony_ci	td->ep_data = urbp->ep_data;
58362306a36Sopenharmony_ci
58462306a36Sopenharmony_ci	if ((td_udev(td)->speed == USB_SPEED_LOW) &&
58562306a36Sopenharmony_ci	    !(c67x00->low_speed_ports & (1 << urbp->port)))
58662306a36Sopenharmony_ci		cmd |= PREAMBLE_EN;
58762306a36Sopenharmony_ci
58862306a36Sopenharmony_ci	switch (usb_pipetype(td->pipe)) {
58962306a36Sopenharmony_ci	case PIPE_ISOCHRONOUS:
59062306a36Sopenharmony_ci		tt = TT_ISOCHRONOUS;
59162306a36Sopenharmony_ci		cmd |= ISO_EN;
59262306a36Sopenharmony_ci		break;
59362306a36Sopenharmony_ci	case PIPE_CONTROL:
59462306a36Sopenharmony_ci		tt = TT_CONTROL;
59562306a36Sopenharmony_ci		break;
59662306a36Sopenharmony_ci	case PIPE_BULK:
59762306a36Sopenharmony_ci		tt = TT_BULK;
59862306a36Sopenharmony_ci		break;
59962306a36Sopenharmony_ci	case PIPE_INTERRUPT:
60062306a36Sopenharmony_ci		tt = TT_INTERRUPT;
60162306a36Sopenharmony_ci		break;
60262306a36Sopenharmony_ci	}
60362306a36Sopenharmony_ci
60462306a36Sopenharmony_ci	if (toggle)
60562306a36Sopenharmony_ci		cmd |= SEQ_SEL;
60662306a36Sopenharmony_ci
60762306a36Sopenharmony_ci	cmd |= ARM_EN;
60862306a36Sopenharmony_ci
60962306a36Sopenharmony_ci	/* SW part */
61062306a36Sopenharmony_ci	td->td_addr = c67x00->next_td_addr;
61162306a36Sopenharmony_ci	c67x00->next_td_addr = c67x00->next_td_addr + CY_TD_SIZE;
61262306a36Sopenharmony_ci
61362306a36Sopenharmony_ci	/* HW part */
61462306a36Sopenharmony_ci	td->ly_base_addr = __cpu_to_le16(c67x00->next_buf_addr);
61562306a36Sopenharmony_ci	td->port_length = __cpu_to_le16((c67x00->sie->sie_num << 15) |
61662306a36Sopenharmony_ci					(urbp->port << 14) | (len & 0x3FF));
61762306a36Sopenharmony_ci	td->pid_ep = ((pid & 0xF) << TD_PIDEP_OFFSET) |
61862306a36Sopenharmony_ci	    (usb_pipeendpoint(td->pipe) & 0xF);
61962306a36Sopenharmony_ci	td->dev_addr = usb_pipedevice(td->pipe) & 0x7F;
62062306a36Sopenharmony_ci	td->ctrl_reg = cmd;
62162306a36Sopenharmony_ci	td->status = 0;
62262306a36Sopenharmony_ci	td->retry_cnt = (tt << TT_OFFSET) | (active_flag << 4) | retry_cnt;
62362306a36Sopenharmony_ci	td->residue = 0;
62462306a36Sopenharmony_ci	td->next_td_addr = __cpu_to_le16(c67x00->next_td_addr);
62562306a36Sopenharmony_ci
62662306a36Sopenharmony_ci	/* SW part */
62762306a36Sopenharmony_ci	td->data = data;
62862306a36Sopenharmony_ci	td->urb = urb;
62962306a36Sopenharmony_ci	td->privdata = privdata;
63062306a36Sopenharmony_ci
63162306a36Sopenharmony_ci	c67x00->next_buf_addr += (len + 1) & ~0x01;	/* properly align */
63262306a36Sopenharmony_ci
63362306a36Sopenharmony_ci	list_add_tail(&td->td_list, &c67x00->td_list);
63462306a36Sopenharmony_ci	return 0;
63562306a36Sopenharmony_ci}
63662306a36Sopenharmony_ci
63762306a36Sopenharmony_cistatic inline void c67x00_release_td(struct c67x00_td *td)
63862306a36Sopenharmony_ci{
63962306a36Sopenharmony_ci	list_del_init(&td->td_list);
64062306a36Sopenharmony_ci	kfree(td);
64162306a36Sopenharmony_ci}
64262306a36Sopenharmony_ci
64362306a36Sopenharmony_ci/* -------------------------------------------------------------------------- */
64462306a36Sopenharmony_ci
64562306a36Sopenharmony_cistatic int c67x00_add_data_urb(struct c67x00_hcd *c67x00, struct urb *urb)
64662306a36Sopenharmony_ci{
64762306a36Sopenharmony_ci	int remaining;
64862306a36Sopenharmony_ci	int toggle;
64962306a36Sopenharmony_ci	int pid;
65062306a36Sopenharmony_ci	int ret = 0;
65162306a36Sopenharmony_ci	int maxps;
65262306a36Sopenharmony_ci	int need_empty;
65362306a36Sopenharmony_ci
65462306a36Sopenharmony_ci	toggle = usb_gettoggle(urb->dev, usb_pipeendpoint(urb->pipe),
65562306a36Sopenharmony_ci			       usb_pipeout(urb->pipe));
65662306a36Sopenharmony_ci	remaining = urb->transfer_buffer_length - urb->actual_length;
65762306a36Sopenharmony_ci
65862306a36Sopenharmony_ci	maxps = usb_maxpacket(urb->dev, urb->pipe);
65962306a36Sopenharmony_ci
66062306a36Sopenharmony_ci	need_empty = (urb->transfer_flags & URB_ZERO_PACKET) &&
66162306a36Sopenharmony_ci	    usb_pipeout(urb->pipe) && !(remaining % maxps);
66262306a36Sopenharmony_ci
66362306a36Sopenharmony_ci	while (remaining || need_empty) {
66462306a36Sopenharmony_ci		int len;
66562306a36Sopenharmony_ci		char *td_buf;
66662306a36Sopenharmony_ci
66762306a36Sopenharmony_ci		len = (remaining > maxps) ? maxps : remaining;
66862306a36Sopenharmony_ci		if (!len)
66962306a36Sopenharmony_ci			need_empty = 0;
67062306a36Sopenharmony_ci
67162306a36Sopenharmony_ci		pid = usb_pipeout(urb->pipe) ? USB_PID_OUT : USB_PID_IN;
67262306a36Sopenharmony_ci		td_buf = urb->transfer_buffer + urb->transfer_buffer_length -
67362306a36Sopenharmony_ci		    remaining;
67462306a36Sopenharmony_ci		ret = c67x00_create_td(c67x00, urb, td_buf, len, pid, toggle,
67562306a36Sopenharmony_ci				       DATA_STAGE);
67662306a36Sopenharmony_ci		if (ret)
67762306a36Sopenharmony_ci			return ret;	/* td wasn't created */
67862306a36Sopenharmony_ci
67962306a36Sopenharmony_ci		toggle ^= 1;
68062306a36Sopenharmony_ci		remaining -= len;
68162306a36Sopenharmony_ci		if (usb_pipecontrol(urb->pipe))
68262306a36Sopenharmony_ci			break;
68362306a36Sopenharmony_ci	}
68462306a36Sopenharmony_ci
68562306a36Sopenharmony_ci	return 0;
68662306a36Sopenharmony_ci}
68762306a36Sopenharmony_ci
68862306a36Sopenharmony_ci/*
68962306a36Sopenharmony_ci * return 0 in case more bandwidth is available, else errorcode
69062306a36Sopenharmony_ci */
69162306a36Sopenharmony_cistatic int c67x00_add_ctrl_urb(struct c67x00_hcd *c67x00, struct urb *urb)
69262306a36Sopenharmony_ci{
69362306a36Sopenharmony_ci	int ret;
69462306a36Sopenharmony_ci	int pid;
69562306a36Sopenharmony_ci
69662306a36Sopenharmony_ci	switch (urb->interval) {
69762306a36Sopenharmony_ci	default:
69862306a36Sopenharmony_ci	case SETUP_STAGE:
69962306a36Sopenharmony_ci		ret = c67x00_create_td(c67x00, urb, urb->setup_packet,
70062306a36Sopenharmony_ci				       8, USB_PID_SETUP, 0, SETUP_STAGE);
70162306a36Sopenharmony_ci		if (ret)
70262306a36Sopenharmony_ci			return ret;
70362306a36Sopenharmony_ci		urb->interval = SETUP_STAGE;
70462306a36Sopenharmony_ci		usb_settoggle(urb->dev, usb_pipeendpoint(urb->pipe),
70562306a36Sopenharmony_ci			      usb_pipeout(urb->pipe), 1);
70662306a36Sopenharmony_ci		break;
70762306a36Sopenharmony_ci	case DATA_STAGE:
70862306a36Sopenharmony_ci		if (urb->transfer_buffer_length) {
70962306a36Sopenharmony_ci			ret = c67x00_add_data_urb(c67x00, urb);
71062306a36Sopenharmony_ci			if (ret)
71162306a36Sopenharmony_ci				return ret;
71262306a36Sopenharmony_ci			break;
71362306a36Sopenharmony_ci		}
71462306a36Sopenharmony_ci		fallthrough;
71562306a36Sopenharmony_ci	case STATUS_STAGE:
71662306a36Sopenharmony_ci		pid = !usb_pipeout(urb->pipe) ? USB_PID_OUT : USB_PID_IN;
71762306a36Sopenharmony_ci		ret = c67x00_create_td(c67x00, urb, NULL, 0, pid, 1,
71862306a36Sopenharmony_ci				       STATUS_STAGE);
71962306a36Sopenharmony_ci		if (ret)
72062306a36Sopenharmony_ci			return ret;
72162306a36Sopenharmony_ci		break;
72262306a36Sopenharmony_ci	}
72362306a36Sopenharmony_ci
72462306a36Sopenharmony_ci	return 0;
72562306a36Sopenharmony_ci}
72662306a36Sopenharmony_ci
72762306a36Sopenharmony_ci/*
72862306a36Sopenharmony_ci * return 0 in case more bandwidth is available, else errorcode
72962306a36Sopenharmony_ci */
73062306a36Sopenharmony_cistatic int c67x00_add_int_urb(struct c67x00_hcd *c67x00, struct urb *urb)
73162306a36Sopenharmony_ci{
73262306a36Sopenharmony_ci	struct c67x00_urb_priv *urbp = urb->hcpriv;
73362306a36Sopenharmony_ci
73462306a36Sopenharmony_ci	if (frame_after_eq(c67x00->current_frame, urbp->ep_data->next_frame)) {
73562306a36Sopenharmony_ci		urbp->ep_data->next_frame =
73662306a36Sopenharmony_ci		    frame_add(urbp->ep_data->next_frame, urb->interval);
73762306a36Sopenharmony_ci		return c67x00_add_data_urb(c67x00, urb);
73862306a36Sopenharmony_ci	}
73962306a36Sopenharmony_ci	return 0;
74062306a36Sopenharmony_ci}
74162306a36Sopenharmony_ci
74262306a36Sopenharmony_cistatic int c67x00_add_iso_urb(struct c67x00_hcd *c67x00, struct urb *urb)
74362306a36Sopenharmony_ci{
74462306a36Sopenharmony_ci	struct c67x00_urb_priv *urbp = urb->hcpriv;
74562306a36Sopenharmony_ci
74662306a36Sopenharmony_ci	if (frame_after_eq(c67x00->current_frame, urbp->ep_data->next_frame)) {
74762306a36Sopenharmony_ci		char *td_buf;
74862306a36Sopenharmony_ci		int len, pid, ret;
74962306a36Sopenharmony_ci
75062306a36Sopenharmony_ci		BUG_ON(urbp->cnt >= urb->number_of_packets);
75162306a36Sopenharmony_ci
75262306a36Sopenharmony_ci		td_buf = urb->transfer_buffer +
75362306a36Sopenharmony_ci		    urb->iso_frame_desc[urbp->cnt].offset;
75462306a36Sopenharmony_ci		len = urb->iso_frame_desc[urbp->cnt].length;
75562306a36Sopenharmony_ci		pid = usb_pipeout(urb->pipe) ? USB_PID_OUT : USB_PID_IN;
75662306a36Sopenharmony_ci
75762306a36Sopenharmony_ci		ret = c67x00_create_td(c67x00, urb, td_buf, len, pid, 0,
75862306a36Sopenharmony_ci				       urbp->cnt);
75962306a36Sopenharmony_ci		if (ret) {
76062306a36Sopenharmony_ci			dev_dbg(c67x00_hcd_dev(c67x00), "create failed: %d\n",
76162306a36Sopenharmony_ci				ret);
76262306a36Sopenharmony_ci			urb->iso_frame_desc[urbp->cnt].actual_length = 0;
76362306a36Sopenharmony_ci			urb->iso_frame_desc[urbp->cnt].status = ret;
76462306a36Sopenharmony_ci			if (urbp->cnt + 1 == urb->number_of_packets)
76562306a36Sopenharmony_ci				c67x00_giveback_urb(c67x00, urb, 0);
76662306a36Sopenharmony_ci		}
76762306a36Sopenharmony_ci
76862306a36Sopenharmony_ci		urbp->ep_data->next_frame =
76962306a36Sopenharmony_ci		    frame_add(urbp->ep_data->next_frame, urb->interval);
77062306a36Sopenharmony_ci		urbp->cnt++;
77162306a36Sopenharmony_ci	}
77262306a36Sopenharmony_ci	return 0;
77362306a36Sopenharmony_ci}
77462306a36Sopenharmony_ci
77562306a36Sopenharmony_ci/* -------------------------------------------------------------------------- */
77662306a36Sopenharmony_ci
77762306a36Sopenharmony_cistatic void c67x00_fill_from_list(struct c67x00_hcd *c67x00, int type,
77862306a36Sopenharmony_ci				  int (*add)(struct c67x00_hcd *, struct urb *))
77962306a36Sopenharmony_ci{
78062306a36Sopenharmony_ci	struct c67x00_ep_data *ep_data;
78162306a36Sopenharmony_ci	struct urb *urb;
78262306a36Sopenharmony_ci
78362306a36Sopenharmony_ci	/* traverse every endpoint on the list */
78462306a36Sopenharmony_ci	list_for_each_entry(ep_data, &c67x00->list[type], node) {
78562306a36Sopenharmony_ci		if (!list_empty(&ep_data->queue)) {
78662306a36Sopenharmony_ci			/* and add the first urb */
78762306a36Sopenharmony_ci			/* isochronous transfer rely on this */
78862306a36Sopenharmony_ci			urb = list_entry(ep_data->queue.next,
78962306a36Sopenharmony_ci					 struct c67x00_urb_priv,
79062306a36Sopenharmony_ci					 hep_node)->urb;
79162306a36Sopenharmony_ci			add(c67x00, urb);
79262306a36Sopenharmony_ci		}
79362306a36Sopenharmony_ci	}
79462306a36Sopenharmony_ci}
79562306a36Sopenharmony_ci
79662306a36Sopenharmony_cistatic void c67x00_fill_frame(struct c67x00_hcd *c67x00)
79762306a36Sopenharmony_ci{
79862306a36Sopenharmony_ci	struct c67x00_td *td, *ttd;
79962306a36Sopenharmony_ci
80062306a36Sopenharmony_ci	/* Check if we can proceed */
80162306a36Sopenharmony_ci	if (!list_empty(&c67x00->td_list)) {
80262306a36Sopenharmony_ci		dev_warn(c67x00_hcd_dev(c67x00),
80362306a36Sopenharmony_ci			 "TD list not empty! This should not happen!\n");
80462306a36Sopenharmony_ci		list_for_each_entry_safe(td, ttd, &c67x00->td_list, td_list) {
80562306a36Sopenharmony_ci			dbg_td(c67x00, td, "Unprocessed td");
80662306a36Sopenharmony_ci			c67x00_release_td(td);
80762306a36Sopenharmony_ci		}
80862306a36Sopenharmony_ci	}
80962306a36Sopenharmony_ci
81062306a36Sopenharmony_ci	/* Reinitialize variables */
81162306a36Sopenharmony_ci	c67x00->bandwidth_allocated = 0;
81262306a36Sopenharmony_ci	c67x00->periodic_bw_allocated = 0;
81362306a36Sopenharmony_ci
81462306a36Sopenharmony_ci	c67x00->next_td_addr = c67x00->td_base_addr;
81562306a36Sopenharmony_ci	c67x00->next_buf_addr = c67x00->buf_base_addr;
81662306a36Sopenharmony_ci
81762306a36Sopenharmony_ci	/* Fill the list */
81862306a36Sopenharmony_ci	c67x00_fill_from_list(c67x00, PIPE_ISOCHRONOUS, c67x00_add_iso_urb);
81962306a36Sopenharmony_ci	c67x00_fill_from_list(c67x00, PIPE_INTERRUPT, c67x00_add_int_urb);
82062306a36Sopenharmony_ci	c67x00_fill_from_list(c67x00, PIPE_CONTROL, c67x00_add_ctrl_urb);
82162306a36Sopenharmony_ci	c67x00_fill_from_list(c67x00, PIPE_BULK, c67x00_add_data_urb);
82262306a36Sopenharmony_ci}
82362306a36Sopenharmony_ci
82462306a36Sopenharmony_ci/* -------------------------------------------------------------------------- */
82562306a36Sopenharmony_ci
82662306a36Sopenharmony_ci/*
82762306a36Sopenharmony_ci * Get TD from C67X00
82862306a36Sopenharmony_ci */
82962306a36Sopenharmony_cistatic inline void
83062306a36Sopenharmony_cic67x00_parse_td(struct c67x00_hcd *c67x00, struct c67x00_td *td)
83162306a36Sopenharmony_ci{
83262306a36Sopenharmony_ci	c67x00_ll_read_mem_le16(c67x00->sie->dev,
83362306a36Sopenharmony_ci				td->td_addr, td, CY_TD_SIZE);
83462306a36Sopenharmony_ci
83562306a36Sopenharmony_ci	if (usb_pipein(td->pipe) && td_actual_bytes(td))
83662306a36Sopenharmony_ci		c67x00_ll_read_mem_le16(c67x00->sie->dev, td_ly_base_addr(td),
83762306a36Sopenharmony_ci					td->data, td_actual_bytes(td));
83862306a36Sopenharmony_ci}
83962306a36Sopenharmony_ci
84062306a36Sopenharmony_cistatic int c67x00_td_to_error(struct c67x00_hcd *c67x00, struct c67x00_td *td)
84162306a36Sopenharmony_ci{
84262306a36Sopenharmony_ci	if (td->status & TD_STATUSMASK_ERR) {
84362306a36Sopenharmony_ci		dbg_td(c67x00, td, "ERROR_FLAG");
84462306a36Sopenharmony_ci		return -EILSEQ;
84562306a36Sopenharmony_ci	}
84662306a36Sopenharmony_ci	if (td->status & TD_STATUSMASK_STALL) {
84762306a36Sopenharmony_ci		/* dbg_td(c67x00, td, "STALL"); */
84862306a36Sopenharmony_ci		return -EPIPE;
84962306a36Sopenharmony_ci	}
85062306a36Sopenharmony_ci	if (td->status & TD_STATUSMASK_TMOUT) {
85162306a36Sopenharmony_ci		dbg_td(c67x00, td, "TIMEOUT");
85262306a36Sopenharmony_ci		return -ETIMEDOUT;
85362306a36Sopenharmony_ci	}
85462306a36Sopenharmony_ci
85562306a36Sopenharmony_ci	return 0;
85662306a36Sopenharmony_ci}
85762306a36Sopenharmony_ci
85862306a36Sopenharmony_cistatic inline int c67x00_end_of_data(struct c67x00_td *td)
85962306a36Sopenharmony_ci{
86062306a36Sopenharmony_ci	int maxps, need_empty, remaining;
86162306a36Sopenharmony_ci	struct urb *urb = td->urb;
86262306a36Sopenharmony_ci	int act_bytes;
86362306a36Sopenharmony_ci
86462306a36Sopenharmony_ci	act_bytes = td_actual_bytes(td);
86562306a36Sopenharmony_ci
86662306a36Sopenharmony_ci	if (unlikely(!act_bytes))
86762306a36Sopenharmony_ci		return 1;	/* This was an empty packet */
86862306a36Sopenharmony_ci
86962306a36Sopenharmony_ci	maxps = usb_maxpacket(td_udev(td), td->pipe);
87062306a36Sopenharmony_ci
87162306a36Sopenharmony_ci	if (unlikely(act_bytes < maxps))
87262306a36Sopenharmony_ci		return 1;	/* Smaller then full packet */
87362306a36Sopenharmony_ci
87462306a36Sopenharmony_ci	remaining = urb->transfer_buffer_length - urb->actual_length;
87562306a36Sopenharmony_ci	need_empty = (urb->transfer_flags & URB_ZERO_PACKET) &&
87662306a36Sopenharmony_ci	    usb_pipeout(urb->pipe) && !(remaining % maxps);
87762306a36Sopenharmony_ci
87862306a36Sopenharmony_ci	if (unlikely(!remaining && !need_empty))
87962306a36Sopenharmony_ci		return 1;
88062306a36Sopenharmony_ci
88162306a36Sopenharmony_ci	return 0;
88262306a36Sopenharmony_ci}
88362306a36Sopenharmony_ci
88462306a36Sopenharmony_ci/* -------------------------------------------------------------------------- */
88562306a36Sopenharmony_ci
88662306a36Sopenharmony_ci/* Remove all td's from the list which come
88762306a36Sopenharmony_ci * after last_td and are meant for the same pipe.
88862306a36Sopenharmony_ci * This is used when a short packet has occurred */
88962306a36Sopenharmony_cistatic inline void c67x00_clear_pipe(struct c67x00_hcd *c67x00,
89062306a36Sopenharmony_ci				     struct c67x00_td *last_td)
89162306a36Sopenharmony_ci{
89262306a36Sopenharmony_ci	struct c67x00_td *td, *tmp;
89362306a36Sopenharmony_ci	td = last_td;
89462306a36Sopenharmony_ci	tmp = last_td;
89562306a36Sopenharmony_ci	while (td->td_list.next != &c67x00->td_list) {
89662306a36Sopenharmony_ci		td = list_entry(td->td_list.next, struct c67x00_td, td_list);
89762306a36Sopenharmony_ci		if (td->pipe == last_td->pipe) {
89862306a36Sopenharmony_ci			c67x00_release_td(td);
89962306a36Sopenharmony_ci			td = tmp;
90062306a36Sopenharmony_ci		}
90162306a36Sopenharmony_ci		tmp = td;
90262306a36Sopenharmony_ci	}
90362306a36Sopenharmony_ci}
90462306a36Sopenharmony_ci
90562306a36Sopenharmony_ci/* -------------------------------------------------------------------------- */
90662306a36Sopenharmony_ci
90762306a36Sopenharmony_cistatic void c67x00_handle_successful_td(struct c67x00_hcd *c67x00,
90862306a36Sopenharmony_ci					struct c67x00_td *td)
90962306a36Sopenharmony_ci{
91062306a36Sopenharmony_ci	struct urb *urb = td->urb;
91162306a36Sopenharmony_ci
91262306a36Sopenharmony_ci	if (!urb)
91362306a36Sopenharmony_ci		return;
91462306a36Sopenharmony_ci
91562306a36Sopenharmony_ci	urb->actual_length += td_actual_bytes(td);
91662306a36Sopenharmony_ci
91762306a36Sopenharmony_ci	switch (usb_pipetype(td->pipe)) {
91862306a36Sopenharmony_ci		/* isochronous tds are handled separately */
91962306a36Sopenharmony_ci	case PIPE_CONTROL:
92062306a36Sopenharmony_ci		switch (td->privdata) {
92162306a36Sopenharmony_ci		case SETUP_STAGE:
92262306a36Sopenharmony_ci			urb->interval =
92362306a36Sopenharmony_ci			    urb->transfer_buffer_length ?
92462306a36Sopenharmony_ci			    DATA_STAGE : STATUS_STAGE;
92562306a36Sopenharmony_ci			/* Don't count setup_packet with normal data: */
92662306a36Sopenharmony_ci			urb->actual_length = 0;
92762306a36Sopenharmony_ci			break;
92862306a36Sopenharmony_ci
92962306a36Sopenharmony_ci		case DATA_STAGE:
93062306a36Sopenharmony_ci			if (c67x00_end_of_data(td)) {
93162306a36Sopenharmony_ci				urb->interval = STATUS_STAGE;
93262306a36Sopenharmony_ci				c67x00_clear_pipe(c67x00, td);
93362306a36Sopenharmony_ci			}
93462306a36Sopenharmony_ci			break;
93562306a36Sopenharmony_ci
93662306a36Sopenharmony_ci		case STATUS_STAGE:
93762306a36Sopenharmony_ci			urb->interval = 0;
93862306a36Sopenharmony_ci			c67x00_giveback_urb(c67x00, urb, 0);
93962306a36Sopenharmony_ci			break;
94062306a36Sopenharmony_ci		}
94162306a36Sopenharmony_ci		break;
94262306a36Sopenharmony_ci
94362306a36Sopenharmony_ci	case PIPE_INTERRUPT:
94462306a36Sopenharmony_ci	case PIPE_BULK:
94562306a36Sopenharmony_ci		if (unlikely(c67x00_end_of_data(td))) {
94662306a36Sopenharmony_ci			c67x00_clear_pipe(c67x00, td);
94762306a36Sopenharmony_ci			c67x00_giveback_urb(c67x00, urb, 0);
94862306a36Sopenharmony_ci		}
94962306a36Sopenharmony_ci		break;
95062306a36Sopenharmony_ci	}
95162306a36Sopenharmony_ci}
95262306a36Sopenharmony_ci
95362306a36Sopenharmony_cistatic void c67x00_handle_isoc(struct c67x00_hcd *c67x00, struct c67x00_td *td)
95462306a36Sopenharmony_ci{
95562306a36Sopenharmony_ci	struct urb *urb = td->urb;
95662306a36Sopenharmony_ci	int cnt;
95762306a36Sopenharmony_ci
95862306a36Sopenharmony_ci	if (!urb)
95962306a36Sopenharmony_ci		return;
96062306a36Sopenharmony_ci
96162306a36Sopenharmony_ci	cnt = td->privdata;
96262306a36Sopenharmony_ci
96362306a36Sopenharmony_ci	if (td->status & TD_ERROR_MASK)
96462306a36Sopenharmony_ci		urb->error_count++;
96562306a36Sopenharmony_ci
96662306a36Sopenharmony_ci	urb->iso_frame_desc[cnt].actual_length = td_actual_bytes(td);
96762306a36Sopenharmony_ci	urb->iso_frame_desc[cnt].status = c67x00_td_to_error(c67x00, td);
96862306a36Sopenharmony_ci	if (cnt + 1 == urb->number_of_packets)	/* Last packet */
96962306a36Sopenharmony_ci		c67x00_giveback_urb(c67x00, urb, 0);
97062306a36Sopenharmony_ci}
97162306a36Sopenharmony_ci
97262306a36Sopenharmony_ci/* -------------------------------------------------------------------------- */
97362306a36Sopenharmony_ci
97462306a36Sopenharmony_ci/*
97562306a36Sopenharmony_ci * c67x00_check_td_list - handle tds which have been processed by the c67x00
97662306a36Sopenharmony_ci * pre: current_td == 0
97762306a36Sopenharmony_ci */
97862306a36Sopenharmony_cistatic inline void c67x00_check_td_list(struct c67x00_hcd *c67x00)
97962306a36Sopenharmony_ci{
98062306a36Sopenharmony_ci	struct c67x00_td *td, *tmp;
98162306a36Sopenharmony_ci	struct urb *urb;
98262306a36Sopenharmony_ci	int ack_ok;
98362306a36Sopenharmony_ci	int clear_endpoint;
98462306a36Sopenharmony_ci
98562306a36Sopenharmony_ci	list_for_each_entry_safe(td, tmp, &c67x00->td_list, td_list) {
98662306a36Sopenharmony_ci		/* get the TD */
98762306a36Sopenharmony_ci		c67x00_parse_td(c67x00, td);
98862306a36Sopenharmony_ci		urb = td->urb;	/* urb can be NULL! */
98962306a36Sopenharmony_ci		ack_ok = 0;
99062306a36Sopenharmony_ci		clear_endpoint = 1;
99162306a36Sopenharmony_ci
99262306a36Sopenharmony_ci		/* Handle isochronous transfers separately */
99362306a36Sopenharmony_ci		if (usb_pipeisoc(td->pipe)) {
99462306a36Sopenharmony_ci			clear_endpoint = 0;
99562306a36Sopenharmony_ci			c67x00_handle_isoc(c67x00, td);
99662306a36Sopenharmony_ci			goto cont;
99762306a36Sopenharmony_ci		}
99862306a36Sopenharmony_ci
99962306a36Sopenharmony_ci		/* When an error occurs, all td's for that pipe go into an
100062306a36Sopenharmony_ci		 * inactive state. This state matches successful transfers so
100162306a36Sopenharmony_ci		 * we must make sure not to service them. */
100262306a36Sopenharmony_ci		if (td->status & TD_ERROR_MASK) {
100362306a36Sopenharmony_ci			c67x00_giveback_urb(c67x00, urb,
100462306a36Sopenharmony_ci					    c67x00_td_to_error(c67x00, td));
100562306a36Sopenharmony_ci			goto cont;
100662306a36Sopenharmony_ci		}
100762306a36Sopenharmony_ci
100862306a36Sopenharmony_ci		if ((td->status & TD_STATUSMASK_NAK) || !td_sequence_ok(td) ||
100962306a36Sopenharmony_ci		    !td_acked(td))
101062306a36Sopenharmony_ci			goto cont;
101162306a36Sopenharmony_ci
101262306a36Sopenharmony_ci		/* Sequence ok and acked, don't need to fix toggle */
101362306a36Sopenharmony_ci		ack_ok = 1;
101462306a36Sopenharmony_ci
101562306a36Sopenharmony_ci		if (unlikely(td->status & TD_STATUSMASK_OVF)) {
101662306a36Sopenharmony_ci			if (td_residue(td) & TD_RESIDUE_OVERFLOW) {
101762306a36Sopenharmony_ci				/* Overflow */
101862306a36Sopenharmony_ci				c67x00_giveback_urb(c67x00, urb, -EOVERFLOW);
101962306a36Sopenharmony_ci				goto cont;
102062306a36Sopenharmony_ci			}
102162306a36Sopenharmony_ci		}
102262306a36Sopenharmony_ci
102362306a36Sopenharmony_ci		clear_endpoint = 0;
102462306a36Sopenharmony_ci		c67x00_handle_successful_td(c67x00, td);
102562306a36Sopenharmony_ci
102662306a36Sopenharmony_cicont:
102762306a36Sopenharmony_ci		if (clear_endpoint)
102862306a36Sopenharmony_ci			c67x00_clear_pipe(c67x00, td);
102962306a36Sopenharmony_ci		if (ack_ok)
103062306a36Sopenharmony_ci			usb_settoggle(td_udev(td), usb_pipeendpoint(td->pipe),
103162306a36Sopenharmony_ci				      usb_pipeout(td->pipe),
103262306a36Sopenharmony_ci				      !(td->ctrl_reg & SEQ_SEL));
103362306a36Sopenharmony_ci		/* next in list could have been removed, due to clear_pipe! */
103462306a36Sopenharmony_ci		tmp = list_entry(td->td_list.next, typeof(*td), td_list);
103562306a36Sopenharmony_ci		c67x00_release_td(td);
103662306a36Sopenharmony_ci	}
103762306a36Sopenharmony_ci}
103862306a36Sopenharmony_ci
103962306a36Sopenharmony_ci/* -------------------------------------------------------------------------- */
104062306a36Sopenharmony_ci
104162306a36Sopenharmony_cistatic inline int c67x00_all_tds_processed(struct c67x00_hcd *c67x00)
104262306a36Sopenharmony_ci{
104362306a36Sopenharmony_ci	/* If all tds are processed, we can check the previous frame (if
104462306a36Sopenharmony_ci	 * there was any) and start our next frame.
104562306a36Sopenharmony_ci	 */
104662306a36Sopenharmony_ci	return !c67x00_ll_husb_get_current_td(c67x00->sie);
104762306a36Sopenharmony_ci}
104862306a36Sopenharmony_ci
104962306a36Sopenharmony_ci/*
105062306a36Sopenharmony_ci * Send td to C67X00
105162306a36Sopenharmony_ci */
105262306a36Sopenharmony_cistatic void c67x00_send_td(struct c67x00_hcd *c67x00, struct c67x00_td *td)
105362306a36Sopenharmony_ci{
105462306a36Sopenharmony_ci	int len = td_length(td);
105562306a36Sopenharmony_ci
105662306a36Sopenharmony_ci	if (len && ((td->pid_ep & TD_PIDEPMASK_PID) != TD_PID_IN))
105762306a36Sopenharmony_ci		c67x00_ll_write_mem_le16(c67x00->sie->dev, td_ly_base_addr(td),
105862306a36Sopenharmony_ci					 td->data, len);
105962306a36Sopenharmony_ci
106062306a36Sopenharmony_ci	c67x00_ll_write_mem_le16(c67x00->sie->dev,
106162306a36Sopenharmony_ci				 td->td_addr, td, CY_TD_SIZE);
106262306a36Sopenharmony_ci}
106362306a36Sopenharmony_ci
106462306a36Sopenharmony_cistatic void c67x00_send_frame(struct c67x00_hcd *c67x00)
106562306a36Sopenharmony_ci{
106662306a36Sopenharmony_ci	struct c67x00_td *td;
106762306a36Sopenharmony_ci
106862306a36Sopenharmony_ci	if (list_empty(&c67x00->td_list))
106962306a36Sopenharmony_ci		dev_warn(c67x00_hcd_dev(c67x00),
107062306a36Sopenharmony_ci			 "%s: td list should not be empty here!\n",
107162306a36Sopenharmony_ci			 __func__);
107262306a36Sopenharmony_ci
107362306a36Sopenharmony_ci	list_for_each_entry(td, &c67x00->td_list, td_list) {
107462306a36Sopenharmony_ci		if (td->td_list.next == &c67x00->td_list)
107562306a36Sopenharmony_ci			td->next_td_addr = 0;	/* Last td in list */
107662306a36Sopenharmony_ci
107762306a36Sopenharmony_ci		c67x00_send_td(c67x00, td);
107862306a36Sopenharmony_ci	}
107962306a36Sopenharmony_ci
108062306a36Sopenharmony_ci	c67x00_ll_husb_set_current_td(c67x00->sie, c67x00->td_base_addr);
108162306a36Sopenharmony_ci}
108262306a36Sopenharmony_ci
108362306a36Sopenharmony_ci/* -------------------------------------------------------------------------- */
108462306a36Sopenharmony_ci
108562306a36Sopenharmony_ci/*
108662306a36Sopenharmony_ci * c67x00_do_work - Schedulers state machine
108762306a36Sopenharmony_ci */
108862306a36Sopenharmony_cistatic void c67x00_do_work(struct c67x00_hcd *c67x00)
108962306a36Sopenharmony_ci{
109062306a36Sopenharmony_ci	spin_lock(&c67x00->lock);
109162306a36Sopenharmony_ci	/* Make sure all tds are processed */
109262306a36Sopenharmony_ci	if (!c67x00_all_tds_processed(c67x00))
109362306a36Sopenharmony_ci		goto out;
109462306a36Sopenharmony_ci
109562306a36Sopenharmony_ci	c67x00_check_td_list(c67x00);
109662306a36Sopenharmony_ci
109762306a36Sopenharmony_ci	/* no td's are being processed (current == 0)
109862306a36Sopenharmony_ci	 * and all have been "checked" */
109962306a36Sopenharmony_ci	complete(&c67x00->endpoint_disable);
110062306a36Sopenharmony_ci
110162306a36Sopenharmony_ci	if (!list_empty(&c67x00->td_list))
110262306a36Sopenharmony_ci		goto out;
110362306a36Sopenharmony_ci
110462306a36Sopenharmony_ci	c67x00->current_frame = c67x00_get_current_frame_number(c67x00);
110562306a36Sopenharmony_ci	if (c67x00->current_frame == c67x00->last_frame)
110662306a36Sopenharmony_ci		goto out;	/* Don't send tds in same frame */
110762306a36Sopenharmony_ci	c67x00->last_frame = c67x00->current_frame;
110862306a36Sopenharmony_ci
110962306a36Sopenharmony_ci	/* If no urbs are scheduled, our work is done */
111062306a36Sopenharmony_ci	if (!c67x00->urb_count) {
111162306a36Sopenharmony_ci		c67x00_ll_hpi_disable_sofeop(c67x00->sie);
111262306a36Sopenharmony_ci		goto out;
111362306a36Sopenharmony_ci	}
111462306a36Sopenharmony_ci
111562306a36Sopenharmony_ci	c67x00_fill_frame(c67x00);
111662306a36Sopenharmony_ci	if (!list_empty(&c67x00->td_list))
111762306a36Sopenharmony_ci		/* TD's have been added to the frame */
111862306a36Sopenharmony_ci		c67x00_send_frame(c67x00);
111962306a36Sopenharmony_ci
112062306a36Sopenharmony_ci out:
112162306a36Sopenharmony_ci	spin_unlock(&c67x00->lock);
112262306a36Sopenharmony_ci}
112362306a36Sopenharmony_ci
112462306a36Sopenharmony_ci/* -------------------------------------------------------------------------- */
112562306a36Sopenharmony_ci
112662306a36Sopenharmony_cistatic void c67x00_sched_work(struct work_struct *work)
112762306a36Sopenharmony_ci{
112862306a36Sopenharmony_ci	struct c67x00_hcd *c67x00;
112962306a36Sopenharmony_ci
113062306a36Sopenharmony_ci	c67x00 = container_of(work, struct c67x00_hcd, work);
113162306a36Sopenharmony_ci	c67x00_do_work(c67x00);
113262306a36Sopenharmony_ci}
113362306a36Sopenharmony_ci
113462306a36Sopenharmony_civoid c67x00_sched_kick(struct c67x00_hcd *c67x00)
113562306a36Sopenharmony_ci{
113662306a36Sopenharmony_ci	queue_work(system_highpri_wq, &c67x00->work);
113762306a36Sopenharmony_ci}
113862306a36Sopenharmony_ci
113962306a36Sopenharmony_ciint c67x00_sched_start_scheduler(struct c67x00_hcd *c67x00)
114062306a36Sopenharmony_ci{
114162306a36Sopenharmony_ci	INIT_WORK(&c67x00->work, c67x00_sched_work);
114262306a36Sopenharmony_ci	return 0;
114362306a36Sopenharmony_ci}
114462306a36Sopenharmony_ci
114562306a36Sopenharmony_civoid c67x00_sched_stop_scheduler(struct c67x00_hcd *c67x00)
114662306a36Sopenharmony_ci{
114762306a36Sopenharmony_ci	cancel_work_sync(&c67x00->work);
114862306a36Sopenharmony_ci}
1149