summaryrefslogtreecommitdiff
path: root/target/linux/brcm2708/patches-3.10/0060-dwc_otg-fix-NAK-holdoff-and-allow-on-split-transacti.patch
blob: ae5bfe9b26981b65867be3b16a2d9cc3e4d57fad (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
From 370cbdb4a5ec521d9312b02bbaf269ed520b1451 Mon Sep 17 00:00:00 2001
From: P33M <P33M@github.com>
Date: Mon, 22 Apr 2013 00:08:36 +0100
Subject: [PATCH 060/174] dwc_otg: fix NAK holdoff and allow on split
 transactions only

This corrects a bug where if a single active non-periodic endpoint
had at least one transaction in its qh, on frnum == MAX_FRNUM the qh
would get skipped and never get queued again. This would result in
a silent device until error detection (automatic or otherwise) would
either reset the device or flush and requeue the URBs.

Additionally the NAK holdoff was enabled for all transactions - this
would potentially stall a HS endpoint for 1ms if a previous error state
enabled this interrupt and the next response was a NAK. Fix so that
only split transactions get held off.
---
 drivers/usb/host/dwc_otg/dwc_otg_hcd.c | 28 ++++++++++++++++++----------
 1 file changed, 18 insertions(+), 10 deletions(-)

--- a/drivers/usb/host/dwc_otg/dwc_otg_hcd.c
+++ b/drivers/usb/host/dwc_otg/dwc_otg_hcd.c
@@ -46,7 +46,7 @@
 #include "dwc_otg_hcd.h"
 #include "dwc_otg_regs.h"
 
-extern bool microframe_schedule;
+extern bool microframe_schedule, nak_holdoff_enable;
 
 //#define DEBUG_HOST_CHANNELS
 #ifdef DEBUG_HOST_CHANNELS
@@ -1349,18 +1349,26 @@ dwc_otg_transaction_type_e dwc_otg_hcd_s
 
 		/*
 		 * Check to see if this is a NAK'd retransmit, in which case ignore for retransmission
-		 * we hold off on bulk retransmissions to reduce NAK interrupt overhead for
+		 * we hold off on bulk retransmissions to reduce NAK interrupt overhead for full-speed
 		 * cheeky devices that just hold off using NAKs
 		 */
-		if (dwc_full_frame_num(qh->nak_frame) == dwc_full_frame_num(dwc_otg_hcd_get_frame_number(hcd))) {
-			// Make fiq interrupt run on next frame (i.e. 8 uframes)
-			g_next_sched_frame = ((qh->nak_frame + 8) & ~7) & DWC_HFNUM_MAX_FRNUM;
-			qh_ptr = DWC_LIST_NEXT(qh_ptr);
-			continue;
+		if (nak_holdoff_enable && qh->do_split) {
+			if (qh->nak_frame != 0xffff &&
+				dwc_full_frame_num(qh->nak_frame) ==
+				dwc_full_frame_num(dwc_otg_hcd_get_frame_number(hcd))) {
+				/*
+				 * Revisit: Need to avoid trampling on periodic scheduling.
+				 * Currently we are safe because g_np_count != g_np_sent whenever we hit this,
+				 * but if this behaviour is changed then periodic endpoints will get a slower
+				 * polling rate.
+				 */
+				g_next_sched_frame = ((qh->nak_frame + 8) & ~7) & DWC_HFNUM_MAX_FRNUM;
+				qh_ptr = DWC_LIST_NEXT(qh_ptr);
+				continue;
+			} else {
+				qh->nak_frame = 0xffff;
+			}
 		}
-		else
-			qh->nak_frame = 0xffff;
-
 		if (microframe_schedule) {
 				DWC_SPINLOCK_IRQSAVE(channel_lock, &flags);
 				if (hcd->available_host_channels < 1) {