brcm2708: remove CMA_DEBUG
[openwrt.git] / target / linux / brcm2708 / patches-3.18 / 0092-dwc_otg-introduce-fiq_fsm_spin-un-lock.patch
1 From 424f79f35a94611f73182f19a7711174b756b052 Mon Sep 17 00:00:00 2001
2 From: P33M <P33M@github.com>
3 Date: Fri, 26 Sep 2014 11:32:09 +0100
4 Subject: [PATCH 092/114] dwc_otg: introduce fiq_fsm_spin(un|)lock()
5
6 SMP safety for the FIQ relies on register read-modify write cycles being
7 completed in the correct order. Several places in the DWC code modify
8 registers also touched by the FIQ. Protect these by a bare-bones lock
9 mechanism.
10
11 This also makes it possible to run the FIQ and IRQ handlers on different
12 cores.
13 ---
14  .../usb/host/dwc_common_port/dwc_common_linux.c    |  6 ---
15  drivers/usb/host/dwc_otg/dwc_otg_cil.c             | 10 -----
16  drivers/usb/host/dwc_otg/dwc_otg_fiq_fsm.c         | 46 +++++++++++++++++++++-
17  drivers/usb/host/dwc_otg/dwc_otg_fiq_fsm.h         | 16 +++++++-
18  drivers/usb/host/dwc_otg/dwc_otg_hcd.c             | 23 ++++++++++-
19  drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c        |  9 ++++-
20  6 files changed, 88 insertions(+), 22 deletions(-)
21
22 diff --git a/drivers/usb/host/dwc_common_port/dwc_common_linux.c b/drivers/usb/host/dwc_common_port/dwc_common_linux.c
23 index 5c50a8b..b802042 100644
24 --- a/drivers/usb/host/dwc_common_port/dwc_common_linux.c
25 +++ b/drivers/usb/host/dwc_common_port/dwc_common_linux.c
26 @@ -580,13 +580,7 @@ void DWC_WRITE_REG64(uint64_t volatile *reg, uint64_t value)
27  
28  void DWC_MODIFY_REG32(uint32_t volatile *reg, uint32_t clear_mask, uint32_t set_mask)
29  {
30 -       unsigned long flags;
31 -
32 -       local_irq_save(flags);
33 -       local_fiq_disable();
34         writel((readl(reg) & ~clear_mask) | set_mask, reg);
35 -       local_fiq_enable();
36 -       local_irq_restore(flags);
37  }
38  
39  #if 0
40 diff --git a/drivers/usb/host/dwc_otg/dwc_otg_cil.c b/drivers/usb/host/dwc_otg/dwc_otg_cil.c
41 index 6a32c5c..e40060f 100644
42 --- a/drivers/usb/host/dwc_otg/dwc_otg_cil.c
43 +++ b/drivers/usb/host/dwc_otg/dwc_otg_cil.c
44 @@ -2244,9 +2244,7 @@ void dwc_otg_core_host_init(dwc_otg_core_if_t * core_if)
45   */
46  void dwc_otg_hc_init(dwc_otg_core_if_t * core_if, dwc_hc_t * hc)
47  {
48 -       uint32_t intr_enable;
49         hcintmsk_data_t hc_intr_mask;
50 -       gintmsk_data_t gintmsk = {.d32 = 0 };
51         hcchar_data_t hcchar;
52         hcsplt_data_t hcsplt;
53  
54 @@ -2348,14 +2346,6 @@ void dwc_otg_hc_init(dwc_otg_core_if_t * core_if, dwc_hc_t * hc)
55         }
56         DWC_WRITE_REG32(&hc_regs->hcintmsk, hc_intr_mask.d32);
57  
58 -       /* Enable the top level host channel interrupt. */
59 -       intr_enable = (1 << hc_num);
60 -       DWC_MODIFY_REG32(&host_if->host_global_regs->haintmsk, 0, intr_enable);
61 -
62 -       /* Make sure host channel interrupts are enabled. */
63 -       gintmsk.b.hcintr = 1;
64 -       DWC_MODIFY_REG32(&core_if->core_global_regs->gintmsk, 0, gintmsk.d32);
65 -
66         /*
67          * Program the HCCHARn register with the endpoint characteristics for
68          * the current transfer.
69 diff --git a/drivers/usb/host/dwc_otg/dwc_otg_fiq_fsm.c b/drivers/usb/host/dwc_otg/dwc_otg_fiq_fsm.c
70 index 284f902..84618a5 100644
71 --- a/drivers/usb/host/dwc_otg/dwc_otg_fiq_fsm.c
72 +++ b/drivers/usb/host/dwc_otg/dwc_otg_fiq_fsm.c
73 @@ -75,6 +75,46 @@ void notrace _fiq_print(enum fiq_debug_level dbg_lvl, volatile struct fiq_state
74  }
75  
76  /**
77 + * fiq_fsm_spin_lock() - ARMv6+ bare bones spinlock
78 + * Must be called with local interrupts and FIQ disabled.
79 + */
80 +inline void fiq_fsm_spin_lock(fiq_lock_t *lock)
81 +{
82 +       unsigned long tmp;
83 +       uint32_t newval;
84 +       fiq_lock_t lockval;
85 +       smp_mb__before_spinlock();
86 +       /* Nested locking, yay. If we are on the same CPU as the fiq, then the disable
87 +        * will be sufficient. If we are on a different CPU, then the lock protects us. */
88 +       prefetchw(&lock->slock);
89 +       asm volatile (
90 +       "1:     ldrex   %0, [%3]\n"
91 +       "       add     %1, %0, %4\n"
92 +       "       strex   %2, %1, [%3]\n"
93 +       "       teq     %2, #0\n"
94 +       "       bne     1b"
95 +       : "=&r" (lockval), "=&r" (newval), "=&r" (tmp)
96 +       : "r" (&lock->slock), "I" (1 << 16)
97 +       : "cc");
98 +
99 +       while (lockval.tickets.next != lockval.tickets.owner) {
100 +               wfe();
101 +               lockval.tickets.owner = ACCESS_ONCE(lock->tickets.owner);
102 +       }
103 +       smp_mb();
104 +}
105 +
106 +/**
107 + * fiq_fsm_spin_unlock() - ARMv6+ bare bones spinunlock
108 + */
109 +inline void fiq_fsm_spin_unlock(fiq_lock_t *lock)
110 +{
111 +       smp_mb();
112 +       lock->tickets.owner++;
113 +       dsb_sev();
114 +}
115 +
116 +/**
117   * fiq_fsm_restart_channel() - Poke channel enable bit for a split transaction
118   * @channel: channel to re-enable
119   */
120 @@ -1142,6 +1182,7 @@ void notrace dwc_otg_fiq_fsm(struct fiq_state *state, int num_channels)
121         gintsts_handled.d32 = 0;
122         haint_handled.d32 = 0;
123  
124 +       fiq_fsm_spin_lock(&state->lock);
125         gintsts.d32 = FIQ_READ(state->dwc_regs_base + GINTSTS);
126         gintmsk.d32 = FIQ_READ(state->dwc_regs_base + GINTMSK);
127         gintsts.d32 &= gintmsk.d32;
128 @@ -1231,7 +1272,7 @@ void notrace dwc_otg_fiq_fsm(struct fiq_state *state, int num_channels)
129  
130         }
131         state->fiq_done++;
132 -       mb();
133 +       fiq_fsm_spin_unlock(&state->lock);
134  }
135  
136  
137 @@ -1253,6 +1294,7 @@ void notrace dwc_otg_fiq_nop(struct fiq_state *state)
138         gintmsk_data_t gintmsk;
139         hfnum_data_t hfnum;
140  
141 +       fiq_fsm_spin_lock(&state->lock);
142         hfnum.d32 = FIQ_READ(state->dwc_regs_base + HFNUM);
143         gintsts.d32 = FIQ_READ(state->dwc_regs_base + GINTSTS);
144         gintmsk.d32 = FIQ_READ(state->dwc_regs_base + GINTMSK);
145 @@ -1290,5 +1332,5 @@ void notrace dwc_otg_fiq_nop(struct fiq_state *state)
146  
147         }
148         state->fiq_done++;
149 -       mb();
150 +       fiq_fsm_spin_unlock(&state->lock);
151  }
152 diff --git a/drivers/usb/host/dwc_otg/dwc_otg_fiq_fsm.h b/drivers/usb/host/dwc_otg/dwc_otg_fiq_fsm.h
153 index 5c7707f..8455324 100644
154 --- a/drivers/usb/host/dwc_otg/dwc_otg_fiq_fsm.h
155 +++ b/drivers/usb/host/dwc_otg/dwc_otg_fiq_fsm.h
156 @@ -120,7 +120,6 @@ typedef struct {
157         volatile void* intstat;
158  } mphi_regs_t;
159  
160 -
161  enum fiq_debug_level {
162         FIQDBG_SCHED = (1 << 0),
163         FIQDBG_INT   = (1 << 1),
164 @@ -128,6 +127,16 @@ enum fiq_debug_level {
165         FIQDBG_PORTHUB = (1 << 3),
166  };
167  
168 +typedef struct {
169 +       union {
170 +               uint32_t slock;
171 +               struct _tickets {
172 +                       uint16_t owner;
173 +                       uint16_t next;
174 +               } tickets;
175 +       };
176 +} fiq_lock_t;
177 +
178  struct fiq_state;
179  
180  extern void _fiq_print (enum fiq_debug_level dbg_lvl, volatile struct fiq_state *state, char *fmt, ...);
181 @@ -324,6 +333,7 @@ struct fiq_channel_state {
182   * It contains top-level state information.
183   */
184  struct fiq_state {
185 +       fiq_lock_t lock;
186         mphi_regs_t mphi_regs;
187         void *dwc_regs_base;
188         dma_addr_t dma_base;
189 @@ -342,6 +352,10 @@ struct fiq_state {
190         struct fiq_channel_state channel[0];
191  };
192  
193 +extern void fiq_fsm_spin_lock(fiq_lock_t *lock);
194 +
195 +extern void fiq_fsm_spin_unlock(fiq_lock_t *lock);
196 +
197  extern int fiq_fsm_too_late(struct fiq_state *st, int n);
198  
199  extern int fiq_fsm_tt_in_use(struct fiq_state *st, int num_channels, int n);
200 diff --git a/drivers/usb/host/dwc_otg/dwc_otg_hcd.c b/drivers/usb/host/dwc_otg/dwc_otg_hcd.c
201 index 68d4f3b..124ac16 100644
202 --- a/drivers/usb/host/dwc_otg/dwc_otg_hcd.c
203 +++ b/drivers/usb/host/dwc_otg/dwc_otg_hcd.c
204 @@ -1184,6 +1184,9 @@ static void assign_and_init_hc(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh)
205         dwc_otg_qtd_t *qtd;
206         dwc_otg_hcd_urb_t *urb;
207         void* ptr = NULL;
208 +       uint32_t intr_enable;
209 +       unsigned long flags;
210 +       gintmsk_data_t gintmsk = { .d32 = 0, };
211  
212         qtd = DWC_CIRCLEQ_FIRST(&qh->qtd_list);
213  
214 @@ -1409,6 +1412,20 @@ static void assign_and_init_hc(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh)
215                 hc->desc_list_addr = qh->desc_list_dma;
216  
217         dwc_otg_hc_init(hcd->core_if, hc);
218 +
219 +       local_irq_save(flags);
220 +       local_fiq_disable();
221 +       fiq_fsm_spin_lock(&hcd->fiq_state->lock);
222 +       /* Enable the top level host channel interrupt. */
223 +       intr_enable = (1 << hc->hc_num);
224 +       DWC_MODIFY_REG32(&hcd->core_if->host_if->host_global_regs->haintmsk, 0, intr_enable);
225 +
226 +       /* Make sure host channel interrupts are enabled. */
227 +       gintmsk.b.hcintr = 1;
228 +       DWC_MODIFY_REG32(&hcd->core_if->core_global_regs->gintmsk, 0, gintmsk.d32);
229 +       fiq_fsm_spin_unlock(&hcd->fiq_state->lock);
230 +       local_fiq_enable();
231 +       local_irq_restore(flags);
232         hc->qh = qh;
233  }
234  
235 @@ -1659,6 +1676,7 @@ int fiq_fsm_queue_isoc_transaction(dwc_otg_hcd_t *hcd, dwc_otg_qh_t *qh)
236         fiq_print(FIQDBG_INT, hcd->fiq_state, "%08x", st->hcdma_copy.d32);
237         hfnum.d32 = DWC_READ_REG32(&hcd->core_if->host_if->host_global_regs->hfnum);
238         local_fiq_disable();
239 +       fiq_fsm_spin_lock(&hcd->fiq_state->lock);
240         DWC_WRITE_REG32(&hc_regs->hctsiz, st->hctsiz_copy.d32);
241         DWC_WRITE_REG32(&hc_regs->hcsplt, st->hcsplt_copy.d32);
242         DWC_WRITE_REG32(&hc_regs->hcdma, st->hcdma_copy.d32);
243 @@ -1676,6 +1694,7 @@ int fiq_fsm_queue_isoc_transaction(dwc_otg_hcd_t *hcd, dwc_otg_qh_t *qh)
244         }
245         mb();
246         st->hcchar_copy.b.chen = 0;
247 +       fiq_fsm_spin_unlock(&hcd->fiq_state->lock);
248         local_fiq_enable();
249         return 0;
250  }
251 @@ -1811,7 +1830,7 @@ int fiq_fsm_queue_split_transaction(dwc_otg_hcd_t *hcd, dwc_otg_qh_t *qh)
252         DWC_WRITE_REG32(&hc_regs->hcintmsk, st->hcintmsk_copy.d32);
253  
254         local_fiq_disable();
255 -       mb();
256 +       fiq_fsm_spin_lock(&hcd->fiq_state->lock);
257  
258         if (hc->ep_type & 0x1) {
259                 hfnum.d32 = DWC_READ_REG32(&hcd->core_if->host_if->host_global_regs->hfnum);
260 @@ -1909,7 +1928,7 @@ int fiq_fsm_queue_split_transaction(dwc_otg_hcd_t *hcd, dwc_otg_qh_t *qh)
261                 st->hcchar_copy.b.chen = 1;
262                 DWC_WRITE_REG32(&hc_regs->hcchar, st->hcchar_copy.d32);
263         }
264 -       mb();
265 +       fiq_fsm_spin_unlock(&hcd->fiq_state->lock);
266         local_fiq_enable();
267         return 0;
268  }
269 diff --git a/drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c b/drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c
270 index a5566bc..ee35196 100644
271 --- a/drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c
272 +++ b/drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c
273 @@ -101,6 +101,7 @@ int32_t dwc_otg_hcd_handle_intr(dwc_otg_hcd_t * dwc_otg_hcd)
274         if (dwc_otg_is_host_mode(core_if)) {
275                 if (fiq_enable) {
276                         local_fiq_disable();
277 +                       fiq_fsm_spin_lock(&dwc_otg_hcd->fiq_state->lock);
278                         /* Pull in from the FIQ's disabled mask */
279                         gintmsk.d32 = gintmsk.d32 | ~(dwc_otg_hcd->fiq_state->gintmsk_saved.d32);
280                         dwc_otg_hcd->fiq_state->gintmsk_saved.d32 = ~0;
281 @@ -116,8 +117,10 @@ int32_t dwc_otg_hcd_handle_intr(dwc_otg_hcd_t * dwc_otg_hcd)
282                 }
283                 gintsts.d32 &= gintmsk.d32;
284  
285 -               if (fiq_enable)
286 +               if (fiq_enable) {
287 +                       fiq_fsm_spin_unlock(&dwc_otg_hcd->fiq_state->lock);
288                         local_fiq_enable();
289 +               }
290  
291                 if (!gintsts.d32) {
292                         goto exit_handler_routine;
293 @@ -200,6 +203,7 @@ exit_handler_routine:
294                 gintmsk_data_t gintmsk_new;
295                 haintmsk_data_t haintmsk_new;
296                 local_fiq_disable();
297 +               fiq_fsm_spin_lock(&dwc_otg_hcd->fiq_state->lock);
298                 gintmsk_new.d32 = *(volatile uint32_t *)&dwc_otg_hcd->fiq_state->gintmsk_saved.d32;
299                 if(fiq_fsm_enable)
300                         haintmsk_new.d32 = *(volatile uint32_t *)&dwc_otg_hcd->fiq_state->haintmsk_saved.d32;
301 @@ -222,6 +226,7 @@ exit_handler_routine:
302                 haintmsk.d32 = DWC_READ_REG32(&core_if->host_if->host_global_regs->haintmsk);
303                 /* Re-enable interrupts that the FIQ masked (first time round) */
304                 FIQ_WRITE(dwc_otg_hcd->fiq_state->dwc_regs_base + GINTMSK, gintmsk.d32);
305 +               fiq_fsm_spin_unlock(&dwc_otg_hcd->fiq_state->lock);
306                 local_fiq_enable();
307  
308                 if ((jiffies / HZ) > last_time) {
309 @@ -633,8 +638,10 @@ int32_t dwc_otg_hcd_handle_hc_intr(dwc_otg_hcd_t * dwc_otg_hcd)
310         {
311                 /* check the mask? */
312                 local_fiq_disable();
313 +               fiq_fsm_spin_lock(&dwc_otg_hcd->fiq_state->lock);
314                 haint.b2.chint |= ~(dwc_otg_hcd->fiq_state->haintmsk_saved.b2.chint);
315                 dwc_otg_hcd->fiq_state->haintmsk_saved.b2.chint = ~0;
316 +               fiq_fsm_spin_unlock(&dwc_otg_hcd->fiq_state->lock);
317                 local_fiq_enable();
318         }
319  
320 -- 
321 1.8.3.2
322