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