xref: /utopia/UTPA2-700.0.x/modules/usb/drv/usb_ecos/newhost/drvEHCI_SCHD.cxx (revision 53ee8cc121a030b8d368113ac3e966b4705770ef)
1*53ee8cc1Swenshuai.xi //<MStar Software>
2*53ee8cc1Swenshuai.xi //******************************************************************************
3*53ee8cc1Swenshuai.xi // MStar Software
4*53ee8cc1Swenshuai.xi // Copyright (c) 2010 - 2012 MStar Semiconductor, Inc. All rights reserved.
5*53ee8cc1Swenshuai.xi // All software, firmware and related documentation herein ("MStar Software") are
6*53ee8cc1Swenshuai.xi // intellectual property of MStar Semiconductor, Inc. ("MStar") and protected by
7*53ee8cc1Swenshuai.xi // law, including, but not limited to, copyright law and international treaties.
8*53ee8cc1Swenshuai.xi // Any use, modification, reproduction, retransmission, or republication of all
9*53ee8cc1Swenshuai.xi // or part of MStar Software is expressly prohibited, unless prior written
10*53ee8cc1Swenshuai.xi // permission has been granted by MStar.
11*53ee8cc1Swenshuai.xi //
12*53ee8cc1Swenshuai.xi // By accessing, browsing and/or using MStar Software, you acknowledge that you
13*53ee8cc1Swenshuai.xi // have read, understood, and agree, to be bound by below terms ("Terms") and to
14*53ee8cc1Swenshuai.xi // comply with all applicable laws and regulations:
15*53ee8cc1Swenshuai.xi //
16*53ee8cc1Swenshuai.xi // 1. MStar shall retain any and all right, ownership and interest to MStar
17*53ee8cc1Swenshuai.xi //    Software and any modification/derivatives thereof.
18*53ee8cc1Swenshuai.xi //    No right, ownership, or interest to MStar Software and any
19*53ee8cc1Swenshuai.xi //    modification/derivatives thereof is transferred to you under Terms.
20*53ee8cc1Swenshuai.xi //
21*53ee8cc1Swenshuai.xi // 2. You understand that MStar Software might include, incorporate or be
22*53ee8cc1Swenshuai.xi //    supplied together with third party`s software and the use of MStar
23*53ee8cc1Swenshuai.xi //    Software may require additional licenses from third parties.
24*53ee8cc1Swenshuai.xi //    Therefore, you hereby agree it is your sole responsibility to separately
25*53ee8cc1Swenshuai.xi //    obtain any and all third party right and license necessary for your use of
26*53ee8cc1Swenshuai.xi //    such third party`s software.
27*53ee8cc1Swenshuai.xi //
28*53ee8cc1Swenshuai.xi // 3. MStar Software and any modification/derivatives thereof shall be deemed as
29*53ee8cc1Swenshuai.xi //    MStar`s confidential information and you agree to keep MStar`s
30*53ee8cc1Swenshuai.xi //    confidential information in strictest confidence and not disclose to any
31*53ee8cc1Swenshuai.xi //    third party.
32*53ee8cc1Swenshuai.xi //
33*53ee8cc1Swenshuai.xi // 4. MStar Software is provided on an "AS IS" basis without warranties of any
34*53ee8cc1Swenshuai.xi //    kind. Any warranties are hereby expressly disclaimed by MStar, including
35*53ee8cc1Swenshuai.xi //    without limitation, any warranties of merchantability, non-infringement of
36*53ee8cc1Swenshuai.xi //    intellectual property rights, fitness for a particular purpose, error free
37*53ee8cc1Swenshuai.xi //    and in conformity with any international standard.  You agree to waive any
38*53ee8cc1Swenshuai.xi //    claim against MStar for any loss, damage, cost or expense that you may
39*53ee8cc1Swenshuai.xi //    incur related to your use of MStar Software.
40*53ee8cc1Swenshuai.xi //    In no event shall MStar be liable for any direct, indirect, incidental or
41*53ee8cc1Swenshuai.xi //    consequential damages, including without limitation, lost of profit or
42*53ee8cc1Swenshuai.xi //    revenues, lost or damage of data, and unauthorized system use.
43*53ee8cc1Swenshuai.xi //    You agree that this Section 4 shall still apply without being affected
44*53ee8cc1Swenshuai.xi //    even if MStar Software has been modified by MStar in accordance with your
45*53ee8cc1Swenshuai.xi //    request or instruction for your use, except otherwise agreed by both
46*53ee8cc1Swenshuai.xi //    parties in writing.
47*53ee8cc1Swenshuai.xi //
48*53ee8cc1Swenshuai.xi // 5. If requested, MStar may from time to time provide technical supports or
49*53ee8cc1Swenshuai.xi //    services in relation with MStar Software to you for your use of
50*53ee8cc1Swenshuai.xi //    MStar Software in conjunction with your or your customer`s product
51*53ee8cc1Swenshuai.xi //    ("Services").
52*53ee8cc1Swenshuai.xi //    You understand and agree that, except otherwise agreed by both parties in
53*53ee8cc1Swenshuai.xi //    writing, Services are provided on an "AS IS" basis and the warranty
54*53ee8cc1Swenshuai.xi //    disclaimer set forth in Section 4 above shall apply.
55*53ee8cc1Swenshuai.xi //
56*53ee8cc1Swenshuai.xi // 6. Nothing contained herein shall be construed as by implication, estoppels
57*53ee8cc1Swenshuai.xi //    or otherwise:
58*53ee8cc1Swenshuai.xi //    (a) conferring any license or right to use MStar name, trademark, service
59*53ee8cc1Swenshuai.xi //        mark, symbol or any other identification;
60*53ee8cc1Swenshuai.xi //    (b) obligating MStar or any of its affiliates to furnish any person,
61*53ee8cc1Swenshuai.xi //        including without limitation, you and your customers, any assistance
62*53ee8cc1Swenshuai.xi //        of any kind whatsoever, or any information; or
63*53ee8cc1Swenshuai.xi //    (c) conferring any license or right under any intellectual property right.
64*53ee8cc1Swenshuai.xi //
65*53ee8cc1Swenshuai.xi // 7. These terms shall be governed by and construed in accordance with the laws
66*53ee8cc1Swenshuai.xi //    of Taiwan, R.O.C., excluding its conflict of law rules.
67*53ee8cc1Swenshuai.xi //    Any and all dispute arising out hereof or related hereto shall be finally
68*53ee8cc1Swenshuai.xi //    settled by arbitration referred to the Chinese Arbitration Association,
69*53ee8cc1Swenshuai.xi //    Taipei in accordance with the ROC Arbitration Law and the Arbitration
70*53ee8cc1Swenshuai.xi //    Rules of the Association by three (3) arbitrators appointed in accordance
71*53ee8cc1Swenshuai.xi //    with the said Rules.
72*53ee8cc1Swenshuai.xi //    The place of arbitration shall be in Taipei, Taiwan and the language shall
73*53ee8cc1Swenshuai.xi //    be English.
74*53ee8cc1Swenshuai.xi //    The arbitration award shall be final and binding to both parties.
75*53ee8cc1Swenshuai.xi //
76*53ee8cc1Swenshuai.xi //******************************************************************************
77*53ee8cc1Swenshuai.xi //<MStar Software>
78*53ee8cc1Swenshuai.xi int ms_ehci_get_frame_idx (struct usb_hcd *hcd);
79*53ee8cc1Swenshuai.xi 
80*53ee8cc1Swenshuai.xi /*-------------------------------------------------------------------------*/
ms_periodic_unlink(struct ehci_hcd * pEhci,U32 u32Frame,void * ptr)81*53ee8cc1Swenshuai.xi static void ms_periodic_unlink (struct ehci_hcd *pEhci, U32 u32Frame, void *ptr)
82*53ee8cc1Swenshuai.xi {
83*53ee8cc1Swenshuai.xi 	union ehci_qh_shadow  *prev_p = &pEhci->pshadow [u32Frame];
84*53ee8cc1Swenshuai.xi 	U32   *hw_p = &pEhci->pPeriodic [u32Frame];
85*53ee8cc1Swenshuai.xi 	union ehci_qh_shadow  here = *prev_p;
86*53ee8cc1Swenshuai.xi 	union ehci_qh_shadow  *next_p1;
87*53ee8cc1Swenshuai.xi 
88*53ee8cc1Swenshuai.xi 	while (here.ptr && here.ptr != ptr)
89*53ee8cc1Swenshuai.xi 	{
90*53ee8cc1Swenshuai.xi 		prev_p = (Q_NEXT_TYPE (*hw_p) == QH_TYPE)
91*53ee8cc1Swenshuai.xi 			? (union ehci_qh_shadow *)(&prev_p->qh->qh_next)
92*53ee8cc1Swenshuai.xi 			: NULL;
93*53ee8cc1Swenshuai.xi 		//hw_p = &here.qh->hw_next_qh;
94*53ee8cc1Swenshuai.xi 		hw_p = here.hw_next;
95*53ee8cc1Swenshuai.xi 		here = *prev_p;
96*53ee8cc1Swenshuai.xi 	}
97*53ee8cc1Swenshuai.xi 	if (!here.ptr)
98*53ee8cc1Swenshuai.xi 	{
99*53ee8cc1Swenshuai.xi 		ms_debug_msg ("[periodic_unlink] entry %p no longer on u32Frame [%d]\n", ptr, (int)u32Frame);
100*53ee8cc1Swenshuai.xi 		return;
101*53ee8cc1Swenshuai.xi 	}
102*53ee8cc1Swenshuai.xi 
103*53ee8cc1Swenshuai.xi 	next_p1 = (Q_NEXT_TYPE (*hw_p) == QH_TYPE)
104*53ee8cc1Swenshuai.xi 		? (union ehci_qh_shadow *)(&here.qh->qh_next)
105*53ee8cc1Swenshuai.xi 		: NULL;
106*53ee8cc1Swenshuai.xi 	//*hw_p = here.qh->hw_next_qh;
107*53ee8cc1Swenshuai.xi 	*hw_p = *here.hw_next;
108*53ee8cc1Swenshuai.xi 	*prev_p = *next_p1;
109*53ee8cc1Swenshuai.xi 	//next_p1->ptr = 0; // no meaning code
110*53ee8cc1Swenshuai.xi }
111*53ee8cc1Swenshuai.xi 
ms_periodic_usecs(struct ehci_hcd * pEhci,U32 u32Frame,U32 u32uFrame)112*53ee8cc1Swenshuai.xi static U16 ms_periodic_usecs (struct ehci_hcd *pEhci, U32 u32Frame, U32 u32uFrame)
113*53ee8cc1Swenshuai.xi {
114*53ee8cc1Swenshuai.xi 	U32      *phw_p = &pEhci->pPeriodic [u32Frame];
115*53ee8cc1Swenshuai.xi 	union ehci_qh_shadow  *pQh = &pEhci->pshadow [u32Frame];
116*53ee8cc1Swenshuai.xi 	U32    u32uSecs = 0;
117*53ee8cc1Swenshuai.xi 
118*53ee8cc1Swenshuai.xi 	while (pQh->ptr)
119*53ee8cc1Swenshuai.xi 	{
120*53ee8cc1Swenshuai.xi 		if (Q_NEXT_TYPE (*phw_p) == QH_TYPE)
121*53ee8cc1Swenshuai.xi 		{
122*53ee8cc1Swenshuai.xi 			if (pQh->qh->hw_ep_state2 & (1 << u32uFrame))
123*53ee8cc1Swenshuai.xi 				u32uSecs += pQh->qh->u8Usecs;
124*53ee8cc1Swenshuai.xi 			if (pQh->qh->hw_ep_state2 & (1 << (8 + u32uFrame)))
125*53ee8cc1Swenshuai.xi 				u32uSecs += pQh->qh->c_usecs;
126*53ee8cc1Swenshuai.xi 			phw_p = &pQh->qh->hw_next_qh; // patch from Linux, move hardware pointer too
127*53ee8cc1Swenshuai.xi 			pQh = &pQh->qh->qh_next;
128*53ee8cc1Swenshuai.xi 		}
129*53ee8cc1Swenshuai.xi 		else
130*53ee8cc1Swenshuai.xi 			USB_ASSERT (0, "Next list type not qH type!\n");
131*53ee8cc1Swenshuai.xi 	}
132*53ee8cc1Swenshuai.xi #ifdef  DEBUG
133*53ee8cc1Swenshuai.xi 	/*
134*53ee8cc1Swenshuai.xi 	 * set standard 80% (== 100 usec/uframe) periodic
135*53ee8cc1Swenshuai.xi 	 * bandwidth as required by USB 2.0 by default, (100/125)
136*53ee8cc1Swenshuai.xi 	 */
137*53ee8cc1Swenshuai.xi 	if (u32uSecs > 100)
138*53ee8cc1Swenshuai.xi 	ms_debug_err("overallocated u32uFrame %d, periodic is %d u32uSecs",
139*53ee8cc1Swenshuai.xi 		u32Frame * 8 + u32uFrame, u32uSecs);
140*53ee8cc1Swenshuai.xi #endif
141*53ee8cc1Swenshuai.xi 	return u32uSecs;
142*53ee8cc1Swenshuai.xi }
143*53ee8cc1Swenshuai.xi 
144*53ee8cc1Swenshuai.xi /*-------------------------------------------------------------------------*/
ms_enable_periodic(struct ehci_hcd * pEhci)145*53ee8cc1Swenshuai.xi static int ms_enable_periodic (struct ehci_hcd *pEhci)
146*53ee8cc1Swenshuai.xi {
147*53ee8cc1Swenshuai.xi 	U32  u32Cmd;
148*53ee8cc1Swenshuai.xi 	int  iStatus;
149*53ee8cc1Swenshuai.xi 
150*53ee8cc1Swenshuai.xi 	if (pEhci->u32PeriodicSched++) // patch from Linux
151*53ee8cc1Swenshuai.xi 		return 0;
152*53ee8cc1Swenshuai.xi 
153*53ee8cc1Swenshuai.xi 	ms_debug_func("<%s> ++\n", __FUNCTION__);
154*53ee8cc1Swenshuai.xi 	iStatus = ms_check_status (&pEhci->op_regs->usbsts, USBSTS_PSS, 0, 9 * 125);
155*53ee8cc1Swenshuai.xi 	if (iStatus != 0)
156*53ee8cc1Swenshuai.xi 	{
157*53ee8cc1Swenshuai.xi 		pEhci->hcd.state = HCD_STATE_HALT;
158*53ee8cc1Swenshuai.xi 		ms_debug_err("enable periodic schedule time out!!!!\n");
159*53ee8cc1Swenshuai.xi 		return iStatus;
160*53ee8cc1Swenshuai.xi 	}
161*53ee8cc1Swenshuai.xi 
162*53ee8cc1Swenshuai.xi 	u32Cmd = hcd_reg_readl ((U32)&pEhci->op_regs->usbcmd) | USBCMD_PSE;
163*53ee8cc1Swenshuai.xi 	hcd_reg_writel (u32Cmd, (U32)&pEhci->op_regs->usbcmd);
164*53ee8cc1Swenshuai.xi 	pEhci->hcd.state = HCD_STATE_RUNNING;
165*53ee8cc1Swenshuai.xi 	pEhci->iNextUframe = hcd_reg_readl ((U32)&pEhci->op_regs->frindex)
166*53ee8cc1Swenshuai.xi 		% (pEhci->u32PeriodicSize << 3);
167*53ee8cc1Swenshuai.xi 	return 0;
168*53ee8cc1Swenshuai.xi }
169*53ee8cc1Swenshuai.xi 
ms_disable_periodic(struct ehci_hcd * pEhci)170*53ee8cc1Swenshuai.xi static int ms_disable_periodic (struct ehci_hcd *pEhci)
171*53ee8cc1Swenshuai.xi {
172*53ee8cc1Swenshuai.xi 	U32  u32Cmd;
173*53ee8cc1Swenshuai.xi 	int  iStatus;
174*53ee8cc1Swenshuai.xi 
175*53ee8cc1Swenshuai.xi 	if (--pEhci->u32PeriodicSched) // patch from Linux
176*53ee8cc1Swenshuai.xi 		return 0;
177*53ee8cc1Swenshuai.xi 
178*53ee8cc1Swenshuai.xi 	ms_debug_func("<%s> ++\n", __FUNCTION__);
179*53ee8cc1Swenshuai.xi 	iStatus = ms_check_status (&pEhci->op_regs->usbsts, USBSTS_PSS, USBSTS_PSS, 9 * 125);
180*53ee8cc1Swenshuai.xi 	if (iStatus != 0)
181*53ee8cc1Swenshuai.xi 	{
182*53ee8cc1Swenshuai.xi 		ms_debug_err("disable periodic schedule time out!!!!\n");
183*53ee8cc1Swenshuai.xi 		return iStatus;
184*53ee8cc1Swenshuai.xi 	}
185*53ee8cc1Swenshuai.xi 
186*53ee8cc1Swenshuai.xi 	u32Cmd = hcd_reg_readl ((U32)&pEhci->op_regs->usbcmd) & ~USBCMD_PSE;
187*53ee8cc1Swenshuai.xi 	hcd_reg_writel (u32Cmd, (U32)&pEhci->op_regs->usbcmd);
188*53ee8cc1Swenshuai.xi 	pEhci->iNextUframe = -1;
189*53ee8cc1Swenshuai.xi 	return 0;
190*53ee8cc1Swenshuai.xi }
191*53ee8cc1Swenshuai.xi 
192*53ee8cc1Swenshuai.xi /*-------------------------------------------------------------------------*/
193*53ee8cc1Swenshuai.xi static int ms_qh_schedule (struct ehci_hcd *pEhci, struct ehci_qh *pQh);
ms_intr_deschedule(struct ehci_hcd * pEhci,struct ehci_qh * pQh1)194*53ee8cc1Swenshuai.xi static void ms_intr_deschedule (
195*53ee8cc1Swenshuai.xi 	struct ehci_hcd  *pEhci,
196*53ee8cc1Swenshuai.xi 	struct ehci_qh  *pQh1
197*53ee8cc1Swenshuai.xi 	)
198*53ee8cc1Swenshuai.xi {
199*53ee8cc1Swenshuai.xi 	U32  u32Frame = pQh1->u16Start;
200*53ee8cc1Swenshuai.xi 	U32  iWait;
201*53ee8cc1Swenshuai.xi 	U32  period;
202*53ee8cc1Swenshuai.xi 	//int			rc;
203*53ee8cc1Swenshuai.xi 
204*53ee8cc1Swenshuai.xi 	ms_debug_func("<%s> ++\n", __FUNCTION__);
205*53ee8cc1Swenshuai.xi 
206*53ee8cc1Swenshuai.xi 	/*** qh_unlink_periodic statement ***/
207*53ee8cc1Swenshuai.xi 	if ((period = pQh1->u16Period) == 0)
208*53ee8cc1Swenshuai.xi 		period = 1;
209*53ee8cc1Swenshuai.xi 
210*53ee8cc1Swenshuai.xi 	/*** qh_unlink_periodic statement ***/
211*53ee8cc1Swenshuai.xi 	do
212*53ee8cc1Swenshuai.xi 	{
213*53ee8cc1Swenshuai.xi 		ms_periodic_unlink (pEhci, u32Frame, pQh1);
214*53ee8cc1Swenshuai.xi 		//ms_qh_put (pEhci, pQh1); // moved
215*53ee8cc1Swenshuai.xi 		u32Frame += period;
216*53ee8cc1Swenshuai.xi 	} while (u32Frame < pEhci->u32PeriodicSize);
217*53ee8cc1Swenshuai.xi 
218*53ee8cc1Swenshuai.xi 	// TODO: update bandwidth per ep if required
219*53ee8cc1Swenshuai.xi 	pQh1->qh_status = QH_STS_UNLINK;
220*53ee8cc1Swenshuai.xi 	pQh1->qh_next.ptr = 0;
221*53ee8cc1Swenshuai.xi 	ms_qh_put (pEhci, pQh1); // patch from Linux here
222*53ee8cc1Swenshuai.xi 
223*53ee8cc1Swenshuai.xi 	#if 1
224*53ee8cc1Swenshuai.xi 	ms_disable_periodic(pEhci);
225*53ee8cc1Swenshuai.xi 	#else
226*53ee8cc1Swenshuai.xi 	pEhci->u32PeriodicSched--;
227*53ee8cc1Swenshuai.xi 	if (!pEhci->u32PeriodicSched)
228*53ee8cc1Swenshuai.xi 		ms_disable_periodic (pEhci);
229*53ee8cc1Swenshuai.xi 	else
230*53ee8cc1Swenshuai.xi 	{
231*53ee8cc1Swenshuai.xi 		ms_debug_msg ("periodic schedule still enabled\n");
232*53ee8cc1Swenshuai.xi 	}
233*53ee8cc1Swenshuai.xi 	#endif
234*53ee8cc1Swenshuai.xi 	/*** end of qh_unlink_periodic statement ***/
235*53ee8cc1Swenshuai.xi 	wmb(); // make sure hardware visible (hint from linux 3.10.40)
236*53ee8cc1Swenshuai.xi 
237*53ee8cc1Swenshuai.xi 	/* patch from Linux 2.6.28 */
238*53ee8cc1Swenshuai.xi 	if (list_empty (&pQh1->qtd_list) || (QH_CMASK & pQh1->hw_ep_state2) != 0)
239*53ee8cc1Swenshuai.xi 		iWait = 2;
240*53ee8cc1Swenshuai.xi 	else
241*53ee8cc1Swenshuai.xi 		iWait = 55;
242*53ee8cc1Swenshuai.xi 
243*53ee8cc1Swenshuai.xi 	udelay (iWait);
244*53ee8cc1Swenshuai.xi 	#if 0
245*53ee8cc1Swenshuai.xi 	if (((ms_ehci_get_frame_idx (&pEhci->hcd) - u32Frame) % pQh1->u16Period) == 0)
246*53ee8cc1Swenshuai.xi 	{
247*53ee8cc1Swenshuai.xi 		if (iWait)
248*53ee8cc1Swenshuai.xi 		{
249*53ee8cc1Swenshuai.xi 			udelay (125);
250*53ee8cc1Swenshuai.xi 			pQh1->hw_next_qh = EHCI_LIST_END;
251*53ee8cc1Swenshuai.xi 		}
252*53ee8cc1Swenshuai.xi 		else
253*53ee8cc1Swenshuai.xi 		{
254*53ee8cc1Swenshuai.xi 			ms_debug_msg ("ms_intr_deschedule...\n");
255*53ee8cc1Swenshuai.xi 		}
256*53ee8cc1Swenshuai.xi 	}
257*53ee8cc1Swenshuai.xi 	else
258*53ee8cc1Swenshuai.xi 		pQh1->hw_next_qh = EHCI_LIST_END;
259*53ee8cc1Swenshuai.xi 	#endif
260*53ee8cc1Swenshuai.xi 
261*53ee8cc1Swenshuai.xi 	pQh1->qh_status = QH_STS_IDLE;
262*53ee8cc1Swenshuai.xi 
263*53ee8cc1Swenshuai.xi 	ms_debug_debug ("descheduled qh %p, period = %d u32Frame = %d count = %d, u32PeriodicSched = %d\n",
264*53ee8cc1Swenshuai.xi 		pQh1, pQh1->u16Period, (int)u32Frame,
265*53ee8cc1Swenshuai.xi 		osapi_atomic_read(&pQh1->tRefCnt), (int)pEhci->u32PeriodicSched);
266*53ee8cc1Swenshuai.xi 
267*53ee8cc1Swenshuai.xi 	#if 1 // patch from Linux
268*53ee8cc1Swenshuai.xi 	pQh1->hw_next_qh = EHCI_LIST_END;
269*53ee8cc1Swenshuai.xi 	wmb ();
270*53ee8cc1Swenshuai.xi 	#endif
271*53ee8cc1Swenshuai.xi 
272*53ee8cc1Swenshuai.xi 	#if 0
273*53ee8cc1Swenshuai.xi 	ms_qh_completions(pEhci, pQh1, NULL);
274*53ee8cc1Swenshuai.xi 
275*53ee8cc1Swenshuai.xi 	if (!list_empty(&pQh1->qtd_list) && HCD_IS_RUNNING(pEhci->hcd.state))
276*53ee8cc1Swenshuai.xi 	{
277*53ee8cc1Swenshuai.xi 		rc = ms_qh_schedule(pEhci, pQh1); // reschedule
278*53ee8cc1Swenshuai.xi 
279*53ee8cc1Swenshuai.xi 		if (rc != 0)
280*53ee8cc1Swenshuai.xi 			ms_debug_err("can't reschedule qh %p, err %d\n", pQh1, rc);
281*53ee8cc1Swenshuai.xi 	}
282*53ee8cc1Swenshuai.xi 	#endif
283*53ee8cc1Swenshuai.xi }
284*53ee8cc1Swenshuai.xi 
ms_check_period(struct ehci_hcd * pEhci,U32 u32Frame,U32 u32uFrame,U32 u32Period,U32 u32Usecs)285*53ee8cc1Swenshuai.xi static int ms_check_period (
286*53ee8cc1Swenshuai.xi 	struct ehci_hcd *pEhci,
287*53ee8cc1Swenshuai.xi 	U32  u32Frame,
288*53ee8cc1Swenshuai.xi 	U32  u32uFrame,
289*53ee8cc1Swenshuai.xi 	U32  u32Period,
290*53ee8cc1Swenshuai.xi 	U32  u32Usecs
291*53ee8cc1Swenshuai.xi 	)
292*53ee8cc1Swenshuai.xi {
293*53ee8cc1Swenshuai.xi 	int  claimed;
294*53ee8cc1Swenshuai.xi 
295*53ee8cc1Swenshuai.xi 	if (u32uFrame >= 8)
296*53ee8cc1Swenshuai.xi 		return 0;
297*53ee8cc1Swenshuai.xi 
298*53ee8cc1Swenshuai.xi 	u32Usecs = 100 - u32Usecs; // high speed case
299*53ee8cc1Swenshuai.xi #if 0
300*53ee8cc1Swenshuai.xi 	if ( pEhci->hcd.eSpeed == USB_HIGH_SPEED )
301*53ee8cc1Swenshuai.xi 		u32Usecs = 100 - u32Usecs;
302*53ee8cc1Swenshuai.xi 	else
303*53ee8cc1Swenshuai.xi 		u32Usecs = 900 - u32Usecs;
304*53ee8cc1Swenshuai.xi #endif
305*53ee8cc1Swenshuai.xi 
306*53ee8cc1Swenshuai.xi 	/* period=0, check every micro-frame, uframe==7??? */
307*53ee8cc1Swenshuai.xi 	if (u32Period == 0) {
308*53ee8cc1Swenshuai.xi 		do {
309*53ee8cc1Swenshuai.xi 			for (u32uFrame = 0; u32uFrame < 7; u32uFrame++) {
310*53ee8cc1Swenshuai.xi 				claimed = ms_periodic_usecs (pEhci, u32Frame, u32uFrame);
311*53ee8cc1Swenshuai.xi 				if (claimed > u32Usecs)
312*53ee8cc1Swenshuai.xi 					return 0;
313*53ee8cc1Swenshuai.xi 			}
314*53ee8cc1Swenshuai.xi 		} while ((u32Frame += 1) < pEhci->u32PeriodicSize);
315*53ee8cc1Swenshuai.xi 
316*53ee8cc1Swenshuai.xi 	/* just check the specified uframe, at that period */
317*53ee8cc1Swenshuai.xi 	} else {
318*53ee8cc1Swenshuai.xi 		do
319*53ee8cc1Swenshuai.xi 		{
320*53ee8cc1Swenshuai.xi 			/* un-patch base on linux code */
321*53ee8cc1Swenshuai.xi 			//if (pEhci->pshadow [u32Frame].ptr)
322*53ee8cc1Swenshuai.xi 			//	return 0;
323*53ee8cc1Swenshuai.xi 
324*53ee8cc1Swenshuai.xi 			claimed = ms_periodic_usecs (pEhci, u32Frame, u32uFrame);
325*53ee8cc1Swenshuai.xi 			if ((U32)claimed > u32Usecs)
326*53ee8cc1Swenshuai.xi 				return 0;
327*53ee8cc1Swenshuai.xi 
328*53ee8cc1Swenshuai.xi 		} while ((u32Frame += u32Period) < pEhci->u32PeriodicSize);
329*53ee8cc1Swenshuai.xi 	}
330*53ee8cc1Swenshuai.xi 
331*53ee8cc1Swenshuai.xi 	/* pass all check! */
332*53ee8cc1Swenshuai.xi 	return 1;
333*53ee8cc1Swenshuai.xi }
334*53ee8cc1Swenshuai.xi 
ms_same_tt(struct usb_device * dev1,struct usb_device * dev2)335*53ee8cc1Swenshuai.xi static int ms_same_tt (struct usb_device *dev1, struct usb_device *dev2)
336*53ee8cc1Swenshuai.xi {
337*53ee8cc1Swenshuai.xi 	if (!dev1->tt || !dev2->tt)
338*53ee8cc1Swenshuai.xi 		return 0;
339*53ee8cc1Swenshuai.xi 	if (dev1->tt != dev2->tt)
340*53ee8cc1Swenshuai.xi 		return 0;
341*53ee8cc1Swenshuai.xi 	if (dev1->tt->multi)
342*53ee8cc1Swenshuai.xi 		return dev1->u32TTPort == dev2->u32TTPort;
343*53ee8cc1Swenshuai.xi 	else
344*53ee8cc1Swenshuai.xi 		return 1;
345*53ee8cc1Swenshuai.xi }
346*53ee8cc1Swenshuai.xi 
ms_tt_no_collision(struct ehci_hcd * pEhci,U32 u32Period,struct usb_device * dev,U32 frame,U32 uf_mask)347*53ee8cc1Swenshuai.xi static int ms_tt_no_collision (
348*53ee8cc1Swenshuai.xi 	struct ehci_hcd		*pEhci,
349*53ee8cc1Swenshuai.xi 	U32     		u32Period,
350*53ee8cc1Swenshuai.xi 	struct usb_device	*dev,
351*53ee8cc1Swenshuai.xi 	U32     		frame,
352*53ee8cc1Swenshuai.xi 	U32			uf_mask
353*53ee8cc1Swenshuai.xi )
354*53ee8cc1Swenshuai.xi {
355*53ee8cc1Swenshuai.xi 	if (u32Period == 0)	/* error */
356*53ee8cc1Swenshuai.xi 		return 0;
357*53ee8cc1Swenshuai.xi 
358*53ee8cc1Swenshuai.xi 	for (; frame < pEhci->u32PeriodicSize; frame += u32Period) {
359*53ee8cc1Swenshuai.xi 		union ehci_qh_shadow	here;
360*53ee8cc1Swenshuai.xi 		U32			type;
361*53ee8cc1Swenshuai.xi 
362*53ee8cc1Swenshuai.xi 		here = pEhci->pshadow [frame];
363*53ee8cc1Swenshuai.xi 		type = Q_NEXT_TYPE(pEhci->pPeriodic [frame]);
364*53ee8cc1Swenshuai.xi 		while (here.ptr) {
365*53ee8cc1Swenshuai.xi 			switch (type) {
366*53ee8cc1Swenshuai.xi 			case QH_TYPE:
367*53ee8cc1Swenshuai.xi 				if (ms_same_tt (dev, here.qh->dev)) {
368*53ee8cc1Swenshuai.xi 					U32		mask;
369*53ee8cc1Swenshuai.xi 
370*53ee8cc1Swenshuai.xi 					mask = here.qh->hw_ep_state2;
371*53ee8cc1Swenshuai.xi 					/* "knows" no gap is needed */
372*53ee8cc1Swenshuai.xi 					mask |= mask >> 8;
373*53ee8cc1Swenshuai.xi 					if (mask & uf_mask)
374*53ee8cc1Swenshuai.xi 						break;
375*53ee8cc1Swenshuai.xi 				}
376*53ee8cc1Swenshuai.xi 				type = Q_NEXT_TYPE(here.qh->hw_next_qh);
377*53ee8cc1Swenshuai.xi 				here = here.qh->qh_next;
378*53ee8cc1Swenshuai.xi 				continue;
379*53ee8cc1Swenshuai.xi 			default:
380*53ee8cc1Swenshuai.xi 				ms_debug_err ("periodic frame %d bogus type %d\n",
381*53ee8cc1Swenshuai.xi 					frame, type);
382*53ee8cc1Swenshuai.xi 			}
383*53ee8cc1Swenshuai.xi 
384*53ee8cc1Swenshuai.xi 			/* collision or error */
385*53ee8cc1Swenshuai.xi 			return 0;
386*53ee8cc1Swenshuai.xi 		}
387*53ee8cc1Swenshuai.xi 	}
388*53ee8cc1Swenshuai.xi 
389*53ee8cc1Swenshuai.xi 	/* no collision */
390*53ee8cc1Swenshuai.xi 	return 1;
391*53ee8cc1Swenshuai.xi }
392*53ee8cc1Swenshuai.xi 
ms_check_intr_schedule(struct ehci_hcd * pEhci,U32 u32Frame,U32 u32uFrame,const struct ehci_qh * pQh,U32 * c_maskp)393*53ee8cc1Swenshuai.xi static int ms_check_intr_schedule (
394*53ee8cc1Swenshuai.xi 	struct ehci_hcd    *pEhci,
395*53ee8cc1Swenshuai.xi 	U32    u32Frame,
396*53ee8cc1Swenshuai.xi 	U32    u32uFrame,
397*53ee8cc1Swenshuai.xi 	const struct ehci_qh  *pQh,
398*53ee8cc1Swenshuai.xi 	U32      *c_maskp
399*53ee8cc1Swenshuai.xi 	)
400*53ee8cc1Swenshuai.xi {
401*53ee8cc1Swenshuai.xi 	int    iRetVal = -ENOSPC;
402*53ee8cc1Swenshuai.xi 	U8		mask = 0;
403*53ee8cc1Swenshuai.xi 
404*53ee8cc1Swenshuai.xi 	/* patch from linux */
405*53ee8cc1Swenshuai.xi 	if (pQh->c_usecs && u32uFrame >= 6)		/* may be FSTN */
406*53ee8cc1Swenshuai.xi 		goto done;
407*53ee8cc1Swenshuai.xi 
408*53ee8cc1Swenshuai.xi 	if (!ms_check_period (pEhci, u32Frame, u32uFrame, pQh->u16Period, pQh->u8Usecs))
409*53ee8cc1Swenshuai.xi 		goto done;
410*53ee8cc1Swenshuai.xi 	if (!pQh->c_usecs)
411*53ee8cc1Swenshuai.xi 	{
412*53ee8cc1Swenshuai.xi 		iRetVal = 0;
413*53ee8cc1Swenshuai.xi 		*c_maskp = 0;
414*53ee8cc1Swenshuai.xi 		goto done;
415*53ee8cc1Swenshuai.xi 	}
416*53ee8cc1Swenshuai.xi 
417*53ee8cc1Swenshuai.xi #if 1 // adding tt collision check
418*53ee8cc1Swenshuai.xi 	mask = 0x03 << (u32uFrame + pQh->u8Gap_uf);
419*53ee8cc1Swenshuai.xi 	//*c_maskp = cpu_to_hc32(ehci, mask << 8);
420*53ee8cc1Swenshuai.xi 	*c_maskp = (0x03 << (8 + u32uFrame + pQh->u8Gap_uf));
421*53ee8cc1Swenshuai.xi 
422*53ee8cc1Swenshuai.xi 	mask |= 1 << u32uFrame;
423*53ee8cc1Swenshuai.xi 	if (ms_tt_no_collision (pEhci, pQh->u16Period, pQh->dev, u32Frame, mask)) {
424*53ee8cc1Swenshuai.xi 		if (!ms_check_period (pEhci, u32Frame, u32uFrame + pQh->u8Gap_uf + 1,
425*53ee8cc1Swenshuai.xi 					pQh->u16Period, pQh->c_usecs))
426*53ee8cc1Swenshuai.xi 			goto done;
427*53ee8cc1Swenshuai.xi 		if (!ms_check_period (pEhci, u32Frame, u32uFrame + pQh->u8Gap_uf,
428*53ee8cc1Swenshuai.xi 					pQh->u16Period, pQh->c_usecs))
429*53ee8cc1Swenshuai.xi 			goto done;
430*53ee8cc1Swenshuai.xi 		iRetVal = 0; // pass all periodic check
431*53ee8cc1Swenshuai.xi 	}
432*53ee8cc1Swenshuai.xi 
433*53ee8cc1Swenshuai.xi #else
434*53ee8cc1Swenshuai.xi 	if (!ms_check_period (pEhci, u32Frame, u32uFrame + pQh->u8Gap_uf + 1,
435*53ee8cc1Swenshuai.xi 		pQh->u16Period, pQh->c_usecs))
436*53ee8cc1Swenshuai.xi 		goto done;
437*53ee8cc1Swenshuai.xi 	if (!ms_check_period (pEhci, u32Frame, u32uFrame + pQh->u8Gap_uf,
438*53ee8cc1Swenshuai.xi 		pQh->u16Period, pQh->c_usecs))
439*53ee8cc1Swenshuai.xi 	    goto done;
440*53ee8cc1Swenshuai.xi 
441*53ee8cc1Swenshuai.xi 	*c_maskp = (0x03 << (8 + u32uFrame + pQh->u8Gap_uf));
442*53ee8cc1Swenshuai.xi 	iRetVal = 0;
443*53ee8cc1Swenshuai.xi #endif
444*53ee8cc1Swenshuai.xi done:
445*53ee8cc1Swenshuai.xi 	return iRetVal;
446*53ee8cc1Swenshuai.xi }
447*53ee8cc1Swenshuai.xi 
ms_qh_link_periodic(struct ehci_hcd * ehci,struct ehci_qh * qh)448*53ee8cc1Swenshuai.xi static int ms_qh_link_periodic (struct ehci_hcd *ehci, struct ehci_qh *qh)
449*53ee8cc1Swenshuai.xi {
450*53ee8cc1Swenshuai.xi 	unsigned	i;
451*53ee8cc1Swenshuai.xi 	unsigned	period = qh->u16Period;
452*53ee8cc1Swenshuai.xi 
453*53ee8cc1Swenshuai.xi 	ms_debug_debug ("link qh%d-%04x/%p start %d [%d/%d us]\n",
454*53ee8cc1Swenshuai.xi 		period, qh->hw_ep_state2 & (QH_CMASK | QH_SMASK),
455*53ee8cc1Swenshuai.xi 		qh, qh->u16Start, qh->u8Usecs, qh->c_usecs);
456*53ee8cc1Swenshuai.xi 
457*53ee8cc1Swenshuai.xi 	/* high bandwidth, or otherwise every microframe */
458*53ee8cc1Swenshuai.xi 	if (period == 0)
459*53ee8cc1Swenshuai.xi 		period = 1;
460*53ee8cc1Swenshuai.xi 
461*53ee8cc1Swenshuai.xi 	for (i = qh->u16Start; i < ehci->u32PeriodicSize; i += period) {
462*53ee8cc1Swenshuai.xi 		union ehci_qh_shadow	*prev = &ehci->pshadow[i];
463*53ee8cc1Swenshuai.xi 		U32			*hw_p = &ehci->pPeriodic[i];
464*53ee8cc1Swenshuai.xi 		union ehci_qh_shadow	here = *prev;
465*53ee8cc1Swenshuai.xi 		//U32			type = 0;
466*53ee8cc1Swenshuai.xi 
467*53ee8cc1Swenshuai.xi 		/* skip the iso nodes at list head */
468*53ee8cc1Swenshuai.xi 		#if 0
469*53ee8cc1Swenshuai.xi 		while (here.ptr) {
470*53ee8cc1Swenshuai.xi 			type = Q_NEXT_TYPE(*hw_p);
471*53ee8cc1Swenshuai.xi 			if (type == QH_TYPE)
472*53ee8cc1Swenshuai.xi 				break;
473*53ee8cc1Swenshuai.xi 			prev = periodic_next_shadow(ehci, prev, type);
474*53ee8cc1Swenshuai.xi 			hw_p = shadow_next_periodic(ehci, &here, type);
475*53ee8cc1Swenshuai.xi 			here = *prev;
476*53ee8cc1Swenshuai.xi 		}
477*53ee8cc1Swenshuai.xi 		#endif
478*53ee8cc1Swenshuai.xi 
479*53ee8cc1Swenshuai.xi 		/* sorting each branch by period (slow-->fast)
480*53ee8cc1Swenshuai.xi 		 * enables sharing interior tree nodes
481*53ee8cc1Swenshuai.xi 		 */
482*53ee8cc1Swenshuai.xi 		while (here.ptr && qh != here.qh) {
483*53ee8cc1Swenshuai.xi 			if (qh->u16Period > here.qh->u16Period)
484*53ee8cc1Swenshuai.xi 				break;
485*53ee8cc1Swenshuai.xi 			prev = &here.qh->qh_next;
486*53ee8cc1Swenshuai.xi 			hw_p = &here.qh->hw_next_qh;
487*53ee8cc1Swenshuai.xi 			here = *prev;
488*53ee8cc1Swenshuai.xi 		}
489*53ee8cc1Swenshuai.xi 		/* link in this qh, unless some earlier pass did that */
490*53ee8cc1Swenshuai.xi 		if (qh != here.qh) {
491*53ee8cc1Swenshuai.xi 			qh->qh_next = here;
492*53ee8cc1Swenshuai.xi 			if (here.qh)
493*53ee8cc1Swenshuai.xi 				qh->hw_next_qh = *hw_p;
494*53ee8cc1Swenshuai.xi 			wmb ();
495*53ee8cc1Swenshuai.xi 			prev->qh = qh;
496*53ee8cc1Swenshuai.xi 			*hw_p = QH_NEXT (qh->qh_dma_addr);
497*53ee8cc1Swenshuai.xi 		}
498*53ee8cc1Swenshuai.xi 	}
499*53ee8cc1Swenshuai.xi 	qh->qh_status = QH_STS_LINKED;
500*53ee8cc1Swenshuai.xi 	qh->xacterrs = 0;
501*53ee8cc1Swenshuai.xi 	ms_qh_get (qh);
502*53ee8cc1Swenshuai.xi 
503*53ee8cc1Swenshuai.xi 	// TODO: update bandwidth per ep if required
504*53ee8cc1Swenshuai.xi 
505*53ee8cc1Swenshuai.xi 	/* maybe enable periodic schedule processing */
506*53ee8cc1Swenshuai.xi 	return ms_enable_periodic(ehci);
507*53ee8cc1Swenshuai.xi }
508*53ee8cc1Swenshuai.xi 
ms_qh_schedule(struct ehci_hcd * pEhci,struct ehci_qh * pQh)509*53ee8cc1Swenshuai.xi static int ms_qh_schedule (struct ehci_hcd *pEhci, struct ehci_qh *pQh)
510*53ee8cc1Swenshuai.xi {
511*53ee8cc1Swenshuai.xi 	int  iStatus;
512*53ee8cc1Swenshuai.xi 	U32  u32uFrame1;
513*53ee8cc1Swenshuai.xi 	U32  u32_C_mask1;
514*53ee8cc1Swenshuai.xi 	U32  u32Frame1;
515*53ee8cc1Swenshuai.xi 
516*53ee8cc1Swenshuai.xi 	pQh->hw_next_qh = EHCI_LIST_END;
517*53ee8cc1Swenshuai.xi 	u32Frame1 = pQh->u16Start;
518*53ee8cc1Swenshuai.xi 
519*53ee8cc1Swenshuai.xi 	if (u32Frame1 < pQh->u16Period)
520*53ee8cc1Swenshuai.xi 	{
521*53ee8cc1Swenshuai.xi 		u32uFrame1 = ms_find_1st_set (pQh->hw_ep_state2 & 0x00ff);
522*53ee8cc1Swenshuai.xi 		iStatus = ms_check_intr_schedule (pEhci, u32Frame1, --u32uFrame1,
523*53ee8cc1Swenshuai.xi 			pQh, &u32_C_mask1);
524*53ee8cc1Swenshuai.xi 	}
525*53ee8cc1Swenshuai.xi 	else
526*53ee8cc1Swenshuai.xi 	{
527*53ee8cc1Swenshuai.xi 		u32uFrame1 = 0;
528*53ee8cc1Swenshuai.xi 		u32_C_mask1 = 0;
529*53ee8cc1Swenshuai.xi 		iStatus = -ENOSPC;
530*53ee8cc1Swenshuai.xi 		/* the 1st path, pQh->u16Start is initialed as NOFRAME(65535) */
531*53ee8cc1Swenshuai.xi 	}
532*53ee8cc1Swenshuai.xi 
533*53ee8cc1Swenshuai.xi 	if (iStatus)
534*53ee8cc1Swenshuai.xi 	{
535*53ee8cc1Swenshuai.xi 		if (pQh->u16Period) {
536*53ee8cc1Swenshuai.xi 			//u32Frame1 = pQh->u16Period - 1;
537*53ee8cc1Swenshuai.xi 			//do
538*53ee8cc1Swenshuai.xi 			//{
539*53ee8cc1Swenshuai.xi 			int i;
540*53ee8cc1Swenshuai.xi 
541*53ee8cc1Swenshuai.xi 			for (i = pQh->u16Period; iStatus && i > 0; --i) {
542*53ee8cc1Swenshuai.xi 				/* patch from linux, to generate relative random start frame */
543*53ee8cc1Swenshuai.xi 				u32Frame1 = ++pEhci->u32random_frm % pQh->u16Period;
544*53ee8cc1Swenshuai.xi 				for (u32uFrame1 = 0; u32uFrame1 < 8; u32uFrame1++)
545*53ee8cc1Swenshuai.xi 				{
546*53ee8cc1Swenshuai.xi 					iStatus = ms_check_intr_schedule (pEhci, u32Frame1, u32uFrame1, pQh, &u32_C_mask1);
547*53ee8cc1Swenshuai.xi 					if (iStatus == 0) // first fit @ uframe
548*53ee8cc1Swenshuai.xi 					{
549*53ee8cc1Swenshuai.xi 						ms_debug_msg("[USB] first fit (frame,uframe)=(%d,%d)\n", u32Frame1, u32uFrame1);
550*53ee8cc1Swenshuai.xi 						break;
551*53ee8cc1Swenshuai.xi 					}
552*53ee8cc1Swenshuai.xi 				}
553*53ee8cc1Swenshuai.xi 			//} while (iStatus && u32Frame1--);
554*53ee8cc1Swenshuai.xi 			}
555*53ee8cc1Swenshuai.xi 		/* pQh->u16Period == 0 means every uframe */
556*53ee8cc1Swenshuai.xi 		} else {
557*53ee8cc1Swenshuai.xi 			u32Frame1 = 0;
558*53ee8cc1Swenshuai.xi 			iStatus = ms_check_intr_schedule (pEhci, 0, 0, pQh, &u32_C_mask1);
559*53ee8cc1Swenshuai.xi 		}
560*53ee8cc1Swenshuai.xi 		if (iStatus) // no time slot fit
561*53ee8cc1Swenshuai.xi 		{
562*53ee8cc1Swenshuai.xi 			ms_debug_msg("[USB] no time slot fit\n");
563*53ee8cc1Swenshuai.xi 			goto done;
564*53ee8cc1Swenshuai.xi 		}
565*53ee8cc1Swenshuai.xi 		pQh->u16Start = u32Frame1;
566*53ee8cc1Swenshuai.xi 
567*53ee8cc1Swenshuai.xi 		pQh->hw_ep_state2 &= ~0xffff; // clear QH_CMASK and QH_SMASK
568*53ee8cc1Swenshuai.xi 		pQh->hw_ep_state2 |= (pQh->u16Period ? (1 << u32uFrame1) : QH_SMASK) | u32_C_mask1;
569*53ee8cc1Swenshuai.xi 	}
570*53ee8cc1Swenshuai.xi 	else
571*53ee8cc1Swenshuai.xi 		ms_debug_msg ("reused previous pQh %p schedule", pQh);
572*53ee8cc1Swenshuai.xi 
573*53ee8cc1Swenshuai.xi 	/* ms_qh_link_periodic() moved, patch as linux 3.10.x */
574*53ee8cc1Swenshuai.xi 	//iStatus = ms_qh_link_periodic (pEhci, pQh);
575*53ee8cc1Swenshuai.xi 
576*53ee8cc1Swenshuai.xi 	ms_debug_msg ("[ms_qh_schedule] qh->hw_info2:%x ,usecs %d/%d, period %d.0 starting %d.%d (gap %d)\n",
577*53ee8cc1Swenshuai.xi 		pQh->hw_ep_state2 & (QH_CMASK | QH_SMASK), pQh->u8Usecs, pQh->c_usecs, pQh->u16Period, (int)u32Frame1, (int)u32uFrame1, pQh->u8Gap_uf);
578*53ee8cc1Swenshuai.xi 	#if 0
579*53ee8cc1Swenshuai.xi 	pQh->qh_status = QH_STS_LINKED;
580*53ee8cc1Swenshuai.xi 	ms_debug_msg ("[ms_qh_schedule] scheduled pQh %p usecs %d/%d period %d.0 starting %d.%d (gap %d)\n",
581*53ee8cc1Swenshuai.xi 		pQh, pQh->u8Usecs, pQh->c_usecs, pQh->u16Period, (int)u32Frame1, (int)u32uFrame1, pQh->u8Gap_uf);
582*53ee8cc1Swenshuai.xi 	do
583*53ee8cc1Swenshuai.xi 	{
584*53ee8cc1Swenshuai.xi 		if (pEhci->pshadow [u32Frame1].ptr != 0)
585*53ee8cc1Swenshuai.xi 		{
586*53ee8cc1Swenshuai.xi 			USB_ASSERT (0, "pEhci->pshadow [u32Frame1].ptr != 0\n");
587*53ee8cc1Swenshuai.xi 		}
588*53ee8cc1Swenshuai.xi 		else
589*53ee8cc1Swenshuai.xi 		{
590*53ee8cc1Swenshuai.xi 			pEhci->pshadow [u32Frame1].qh = ms_qh_get (pQh);
591*53ee8cc1Swenshuai.xi 			pEhci->pPeriodic [u32Frame1] = QH_NEXT (pQh->qh_dma_addr);
592*53ee8cc1Swenshuai.xi 		}
593*53ee8cc1Swenshuai.xi 		wmb ();
594*53ee8cc1Swenshuai.xi 		u32Frame1 += pQh->u16Period;
595*53ee8cc1Swenshuai.xi 	} while (u32Frame1 < pEhci->u32PeriodicSize);
596*53ee8cc1Swenshuai.xi 
597*53ee8cc1Swenshuai.xi 	if (!pEhci->u32PeriodicSched++)
598*53ee8cc1Swenshuai.xi 		iStatus = ms_enable_periodic (pEhci);
599*53ee8cc1Swenshuai.xi 	#endif
600*53ee8cc1Swenshuai.xi done:
601*53ee8cc1Swenshuai.xi 	return iStatus;
602*53ee8cc1Swenshuai.xi }
603*53ee8cc1Swenshuai.xi 
ms_intr_submit(struct ehci_hcd * pEhci,struct urb * pUrb,struct list_head * qtd_list)604*53ee8cc1Swenshuai.xi static int ms_intr_submit (
605*53ee8cc1Swenshuai.xi 	struct ehci_hcd    *pEhci,
606*53ee8cc1Swenshuai.xi 	struct urb    *pUrb,
607*53ee8cc1Swenshuai.xi 	struct list_head  *qtd_list
608*53ee8cc1Swenshuai.xi 	)
609*53ee8cc1Swenshuai.xi {
610*53ee8cc1Swenshuai.xi 	U32    epnum1;
611*53ee8cc1Swenshuai.xi 	U32    u32Flags;
612*53ee8cc1Swenshuai.xi 	struct ehci_qh    *pQh1;
613*53ee8cc1Swenshuai.xi 	struct s_hcd_dev    *dev;
614*53ee8cc1Swenshuai.xi 	int      is_input;
615*53ee8cc1Swenshuai.xi 	int      status = 0;
616*53ee8cc1Swenshuai.xi 	struct list_head  stEmpty;
617*53ee8cc1Swenshuai.xi 
618*53ee8cc1Swenshuai.xi 	epnum1 = usb_pipeendpoint (pUrb->u32Pipe);
619*53ee8cc1Swenshuai.xi 	is_input = usb_pipein (pUrb->u32Pipe);
620*53ee8cc1Swenshuai.xi 	if (is_input && !usb_pipecontrol(pUrb->u32Pipe))
621*53ee8cc1Swenshuai.xi 		epnum1 |= 0x10;
622*53ee8cc1Swenshuai.xi 
623*53ee8cc1Swenshuai.xi 	osapi_spin_lock_irqsave (&pEhci->tHcdLock, u32Flags);
624*53ee8cc1Swenshuai.xi 	dev = (struct s_hcd_dev *)pUrb->dev->hcpriv;
625*53ee8cc1Swenshuai.xi 
626*53ee8cc1Swenshuai.xi 	// TODO: HC accessible decision, if not jump to done
627*53ee8cc1Swenshuai.xi 
628*53ee8cc1Swenshuai.xi 	ms_list_init (&stEmpty);
629*53ee8cc1Swenshuai.xi 	pQh1 = ms_qh_append_tds (pEhci, pUrb, &stEmpty, epnum1, &dev->ep [epnum1]);
630*53ee8cc1Swenshuai.xi 	if (pQh1 == 0)
631*53ee8cc1Swenshuai.xi 	{
632*53ee8cc1Swenshuai.xi 		status = -ENOMEM;
633*53ee8cc1Swenshuai.xi 		goto done;
634*53ee8cc1Swenshuai.xi 	}
635*53ee8cc1Swenshuai.xi 	if (pQh1->qh_status == QH_STS_IDLE)
636*53ee8cc1Swenshuai.xi 	{
637*53ee8cc1Swenshuai.xi 		if ((status = ms_qh_schedule (pEhci, pQh1)) != 0)
638*53ee8cc1Swenshuai.xi 			goto done;
639*53ee8cc1Swenshuai.xi 	}
640*53ee8cc1Swenshuai.xi 
641*53ee8cc1Swenshuai.xi 	pQh1 = ms_qh_append_tds (pEhci, pUrb, qtd_list, epnum1, &dev->ep [epnum1]);
642*53ee8cc1Swenshuai.xi 	USB_ASSERT(pQh1!=0, "BUG_ON()!!!! pQh1==NULL\n");
643*53ee8cc1Swenshuai.xi 
644*53ee8cc1Swenshuai.xi 	/* patch from linux code from 3.10.x */
645*53ee8cc1Swenshuai.xi #if 1
646*53ee8cc1Swenshuai.xi 	/* stuff into the periodic schedule */
647*53ee8cc1Swenshuai.xi 	if (pQh1->qh_status == QH_STS_IDLE) {
648*53ee8cc1Swenshuai.xi 		ms_qh_refresh(pEhci, pQh1);
649*53ee8cc1Swenshuai.xi 		ms_qh_link_periodic(pEhci, pQh1);
650*53ee8cc1Swenshuai.xi 	}
651*53ee8cc1Swenshuai.xi #endif
652*53ee8cc1Swenshuai.xi 	Chip_Flush_Memory();
653*53ee8cc1Swenshuai.xi 
654*53ee8cc1Swenshuai.xi done:
655*53ee8cc1Swenshuai.xi 	osapi_spin_unlock_irqrestore (&pEhci->tHcdLock, u32Flags);
656*53ee8cc1Swenshuai.xi 	if (status)
657*53ee8cc1Swenshuai.xi 		ms_qtd_register_free (pEhci, qtd_list);
658*53ee8cc1Swenshuai.xi 
659*53ee8cc1Swenshuai.xi 	return status;
660*53ee8cc1Swenshuai.xi }
661*53ee8cc1Swenshuai.xi 
ms_intr_complete(struct ehci_hcd * pEhci,struct ehci_qh * pQh,struct stPtRegs * pRegs)662*53ee8cc1Swenshuai.xi static U32 ms_intr_complete (
663*53ee8cc1Swenshuai.xi 	struct ehci_hcd  *pEhci,
664*53ee8cc1Swenshuai.xi 	struct ehci_qh  *pQh,
665*53ee8cc1Swenshuai.xi 	struct stPtRegs  *pRegs
666*53ee8cc1Swenshuai.xi 	)
667*53ee8cc1Swenshuai.xi {
668*53ee8cc1Swenshuai.xi 	U32  u32Count;
669*53ee8cc1Swenshuai.xi 	if ((pQh->hw_token & QTD_STS_ACT) != 0)
670*53ee8cc1Swenshuai.xi 		return 0;
671*53ee8cc1Swenshuai.xi 
672*53ee8cc1Swenshuai.xi 	if (ms_is_empty_list (&pQh->qtd_list))
673*53ee8cc1Swenshuai.xi 	{
674*53ee8cc1Swenshuai.xi 		ms_debug_msg ("[intr qh] %p no TDs?", pQh);
675*53ee8cc1Swenshuai.xi 		return 0;
676*53ee8cc1Swenshuai.xi 	}
677*53ee8cc1Swenshuai.xi 
678*53ee8cc1Swenshuai.xi 	u32Count = ms_qh_completions (pEhci, pQh, pRegs);
679*53ee8cc1Swenshuai.xi 	if (ms_is_empty_list (&pQh->qtd_list))
680*53ee8cc1Swenshuai.xi 		ms_intr_deschedule (pEhci, pQh);
681*53ee8cc1Swenshuai.xi 	return u32Count;
682*53ee8cc1Swenshuai.xi }
683*53ee8cc1Swenshuai.xi 
684*53ee8cc1Swenshuai.xi /*-------------------------------------------------------------------------*/
685*53ee8cc1Swenshuai.xi 
ms_scan_periodic(struct ehci_hcd * pEhci,struct stPtRegs * pRegs)686*53ee8cc1Swenshuai.xi static void ms_scan_periodic (struct ehci_hcd *pEhci, struct stPtRegs *pRegs)
687*53ee8cc1Swenshuai.xi {
688*53ee8cc1Swenshuai.xi 	U32  u32Frame, u32Clock, u32clock_uframe, u32Mod;
689*53ee8cc1Swenshuai.xi 	U32  u32Count = 0;
690*53ee8cc1Swenshuai.xi 
691*53ee8cc1Swenshuai.xi 	u32Mod = pEhci->u32PeriodicSize << 3;
692*53ee8cc1Swenshuai.xi 	u32Frame = pEhci->iNextUframe >> 3;
693*53ee8cc1Swenshuai.xi 	if (HCD_IS_RUNNING (pEhci->hcd.state))
694*53ee8cc1Swenshuai.xi 		u32clock_uframe = hcd_reg_readl ((U32)&pEhci->op_regs->frindex);
695*53ee8cc1Swenshuai.xi 	else
696*53ee8cc1Swenshuai.xi 		//u32clock_uframe = (u32Frame << 3) - 1;
697*53ee8cc1Swenshuai.xi 		u32clock_uframe = pEhci->iNextUframe + u32Mod - 1;
698*53ee8cc1Swenshuai.xi 	u32clock_uframe %= u32Mod;
699*53ee8cc1Swenshuai.xi 	u32Clock = u32clock_uframe >> 3;
700*53ee8cc1Swenshuai.xi 
701*53ee8cc1Swenshuai.xi 	for (;;)
702*53ee8cc1Swenshuai.xi 	{
703*53ee8cc1Swenshuai.xi 		union ehci_qh_shadow  q, *q_p;
704*53ee8cc1Swenshuai.xi 		U32      u32Type, *hw_p;
705*53ee8cc1Swenshuai.xi 
706*53ee8cc1Swenshuai.xi restart:
707*53ee8cc1Swenshuai.xi 		q_p = &pEhci->pshadow [u32Frame];
708*53ee8cc1Swenshuai.xi 		hw_p = &pEhci->pPeriodic [u32Frame];
709*53ee8cc1Swenshuai.xi 		q.ptr = q_p->ptr;
710*53ee8cc1Swenshuai.xi 		u32Type = Q_NEXT_TYPE (*hw_p);
711*53ee8cc1Swenshuai.xi 		u32Count = 0;
712*53ee8cc1Swenshuai.xi 
713*53ee8cc1Swenshuai.xi 		while (q.ptr != 0)
714*53ee8cc1Swenshuai.xi 		{
715*53ee8cc1Swenshuai.xi 			int      last;
716*53ee8cc1Swenshuai.xi 			union ehci_qh_shadow  temp;
717*53ee8cc1Swenshuai.xi 
718*53ee8cc1Swenshuai.xi 			if (u32Type == QH_TYPE)
719*53ee8cc1Swenshuai.xi 			{
720*53ee8cc1Swenshuai.xi 				last = (q.qh->hw_next_qh == EHCI_LIST_END);
721*53ee8cc1Swenshuai.xi 				temp = q.qh->qh_next;
722*53ee8cc1Swenshuai.xi 				u32Type = Q_NEXT_TYPE (q.qh->hw_next_qh);
723*53ee8cc1Swenshuai.xi 				u32Count = ms_intr_complete (pEhci, ms_qh_get (q.qh), pRegs);
724*53ee8cc1Swenshuai.xi 				ms_qh_put (pEhci, q.qh);
725*53ee8cc1Swenshuai.xi 				q = temp;
726*53ee8cc1Swenshuai.xi 			}
727*53ee8cc1Swenshuai.xi 			else
728*53ee8cc1Swenshuai.xi 			{
729*53ee8cc1Swenshuai.xi 				ms_debug_msg ("corrupt u32Type %d u32Frame %d shadow %p",
730*53ee8cc1Swenshuai.xi 					(int)u32Type, (int)u32Frame, q.ptr);
731*53ee8cc1Swenshuai.xi 				// BUG ();
732*53ee8cc1Swenshuai.xi 				last = 1;
733*53ee8cc1Swenshuai.xi 				q.ptr = 0;
734*53ee8cc1Swenshuai.xi 			}
735*53ee8cc1Swenshuai.xi 
736*53ee8cc1Swenshuai.xi 			if (q.ptr == 0 && !last)
737*53ee8cc1Swenshuai.xi 				goto restart;
738*53ee8cc1Swenshuai.xi 			if (u32Count) {
739*53ee8cc1Swenshuai.xi 				if (pEhci->u32PeriodicSched > 0)
740*53ee8cc1Swenshuai.xi 					goto restart;
741*53ee8cc1Swenshuai.xi 				u32Frame = u32Clock;
742*53ee8cc1Swenshuai.xi 				break;
743*53ee8cc1Swenshuai.xi 			}
744*53ee8cc1Swenshuai.xi 		}
745*53ee8cc1Swenshuai.xi 
746*53ee8cc1Swenshuai.xi 		if (u32Frame == u32Clock)
747*53ee8cc1Swenshuai.xi 		{
748*53ee8cc1Swenshuai.xi 			U32  now;
749*53ee8cc1Swenshuai.xi 
750*53ee8cc1Swenshuai.xi 			if (!HCD_IS_RUNNING (pEhci->hcd.state) || pEhci->u32PeriodicSched == 0)
751*53ee8cc1Swenshuai.xi 				break;
752*53ee8cc1Swenshuai.xi 
753*53ee8cc1Swenshuai.xi 			pEhci->iNextUframe = u32clock_uframe;
754*53ee8cc1Swenshuai.xi 			now = hcd_reg_readl ((U32)&pEhci->op_regs->frindex) % u32Mod;
755*53ee8cc1Swenshuai.xi 			if (u32clock_uframe == now)
756*53ee8cc1Swenshuai.xi 				break;
757*53ee8cc1Swenshuai.xi 
758*53ee8cc1Swenshuai.xi 			u32clock_uframe = now;
759*53ee8cc1Swenshuai.xi 			u32Clock = u32clock_uframe >> 3;
760*53ee8cc1Swenshuai.xi 		}
761*53ee8cc1Swenshuai.xi 		else
762*53ee8cc1Swenshuai.xi 			u32Frame = (u32Frame + 1) % pEhci->u32PeriodicSize;
763*53ee8cc1Swenshuai.xi 	}
764*53ee8cc1Swenshuai.xi }
765*53ee8cc1Swenshuai.xi 
766