aboutsummaryrefslogtreecommitdiffstats
path: root/target/linux/brcm2708/patches-3.18/0105-dwc_otg-fixup-read-modify-write-in-critical-paths.patch
blob: cac525f80bc0afdb5bb606b98295872ab88d72bb (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
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
From a05cd269cbf2623efe2499459efdd123ee04ab81 Mon Sep 17 00:00:00 2001
From: P33M <P33M@github.com>
Date: Wed, 4 Feb 2015 12:16:50 +0000
Subject: [PATCH 105/114] dwc_otg: fixup read-modify-write in critical paths

Be more careful about read-modify-write on registers that the FIQ
also touches.
---
 drivers/usb/host/dwc_otg/dwc_otg_hcd.c       | 13 +++++++++---
 drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c  | 30 +++++++++++++++++++++++++---
 drivers/usb/host/dwc_otg/dwc_otg_hcd_queue.c | 22 ++++++++++++++++----
 3 files changed, 55 insertions(+), 10 deletions(-)

--- a/drivers/usb/host/dwc_otg/dwc_otg_hcd.c
+++ b/drivers/usb/host/dwc_otg/dwc_otg_hcd.c
@@ -2447,9 +2447,16 @@ void dwc_otg_hcd_queue_transactions(dwc_
 			 */
 			gintmsk_data_t gintmsk = {.d32 = 0 };
 			gintmsk.b.nptxfempty = 1;
-			DWC_MODIFY_REG32(&hcd->core_if->
-					 core_global_regs->gintmsk, gintmsk.d32,
-					 0);
+
+			if (fiq_enable) {
+				local_fiq_disable();
+				fiq_fsm_spin_lock(&hcd->fiq_state->lock);
+				DWC_MODIFY_REG32(&hcd->core_if->core_global_regs->gintmsk, gintmsk.d32, 0);
+				fiq_fsm_spin_unlock(&hcd->fiq_state->lock);
+				local_fiq_enable();
+			} else {
+				DWC_MODIFY_REG32(&hcd->core_if->core_global_regs->gintmsk, gintmsk.d32, 0);
+			}
 		}
 	}
 }
--- a/drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c
+++ b/drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c
@@ -165,7 +165,15 @@ int32_t dwc_otg_hcd_handle_intr(dwc_otg_
 
 			gintmsk_data_t gintmsk = { .b.portintr = 1};
 			retval |= dwc_otg_hcd_handle_port_intr(dwc_otg_hcd);
-			DWC_MODIFY_REG32(&core_if->core_global_regs->gintmsk, 0, gintmsk.d32);
+			if (fiq_enable) {
+				local_fiq_disable();
+				fiq_fsm_spin_lock(&dwc_otg_hcd->fiq_state->lock);
+				DWC_MODIFY_REG32(&dwc_otg_hcd->core_if->core_global_regs->gintmsk, 0, gintmsk.d32);
+				fiq_fsm_spin_unlock(&dwc_otg_hcd->fiq_state->lock);
+				local_fiq_enable();
+			} else {
+				DWC_MODIFY_REG32(&dwc_otg_hcd->core_if->core_global_regs->gintmsk, 0, gintmsk.d32);
+			}
 		}
 		if (gintsts.b.hcintr) {
 			retval |= dwc_otg_hcd_handle_hc_intr(dwc_otg_hcd);
@@ -1069,7 +1077,15 @@ static void halt_channel(dwc_otg_hcd_t *
 			 * be processed.
 			 */
 			gintmsk.b.nptxfempty = 1;
-			DWC_MODIFY_REG32(&global_regs->gintmsk, 0, gintmsk.d32);
+			if (fiq_enable) {
+				local_fiq_disable();
+				fiq_fsm_spin_lock(&hcd->fiq_state->lock);
+				DWC_MODIFY_REG32(&global_regs->gintmsk, 0, gintmsk.d32);
+				fiq_fsm_spin_unlock(&hcd->fiq_state->lock);
+				local_fiq_enable();
+			} else {
+				DWC_MODIFY_REG32(&global_regs->gintmsk, 0, gintmsk.d32);
+			}
 		} else {
 			/*
 			 * Move the QH from the periodic queued schedule to
@@ -1086,7 +1102,15 @@ static void halt_channel(dwc_otg_hcd_t *
 			 * processed.
 			 */
 			gintmsk.b.ptxfempty = 1;
-			DWC_MODIFY_REG32(&global_regs->gintmsk, 0, gintmsk.d32);
+			if (fiq_enable) {
+				local_fiq_disable();
+				fiq_fsm_spin_lock(&hcd->fiq_state->lock);
+				DWC_MODIFY_REG32(&global_regs->gintmsk, 0, gintmsk.d32);
+				fiq_fsm_spin_unlock(&hcd->fiq_state->lock);
+				local_fiq_enable();
+			} else {
+				DWC_MODIFY_REG32(&global_regs->gintmsk, 0, gintmsk.d32);
+			}
 		}
 	}
 }
--- a/drivers/usb/host/dwc_otg/dwc_otg_hcd_queue.c
+++ b/drivers/usb/host/dwc_otg/dwc_otg_hcd_queue.c
@@ -683,8 +683,15 @@ int dwc_otg_hcd_qh_add(dwc_otg_hcd_t * h
 		status = schedule_periodic(hcd, qh);
 		if ( !hcd->periodic_qh_count ) {
 			intr_mask.b.sofintr = 1;
-			DWC_MODIFY_REG32(&hcd->core_if->core_global_regs->gintmsk,
-								intr_mask.d32, intr_mask.d32);
+			if (fiq_enable) {
+				local_fiq_disable();
+				fiq_fsm_spin_lock(&hcd->fiq_state->lock);
+				DWC_MODIFY_REG32(&hcd->core_if->core_global_regs->gintmsk, intr_mask.d32, intr_mask.d32);
+				fiq_fsm_spin_unlock(&hcd->fiq_state->lock);
+				local_fiq_enable();
+			} else {
+				DWC_MODIFY_REG32(&hcd->core_if->core_global_regs->gintmsk, intr_mask.d32, intr_mask.d32);
+			}
 		}
 		hcd->periodic_qh_count++;
 	}
@@ -745,8 +752,15 @@ void dwc_otg_hcd_qh_remove(dwc_otg_hcd_t
 		hcd->periodic_qh_count--;
 		if( !hcd->periodic_qh_count && !fiq_fsm_enable ) {
 			intr_mask.b.sofintr = 1;
-				DWC_MODIFY_REG32(&hcd->core_if->core_global_regs->gintmsk,
-									intr_mask.d32, 0);
+			if (fiq_enable) {
+				local_fiq_disable();
+				fiq_fsm_spin_lock(&hcd->fiq_state->lock);
+				DWC_MODIFY_REG32(&hcd->core_if->core_global_regs->gintmsk, intr_mask.d32, 0);
+				fiq_fsm_spin_unlock(&hcd->fiq_state->lock);
+				local_fiq_enable();
+			} else {
+				DWC_MODIFY_REG32(&hcd->core_if->core_global_regs->gintmsk, intr_mask.d32, 0);
+			}
 		}
 	}
 }