brcm2708: update 3.10 patches with raspberrypi/rpi-3.10.y of 27 Apr. 2014
[openwrt/svn-archive/archive.git] / target / linux / brcm2708 / patches-3.10 / 0079-dwc_otg-fiq-prevent-FIQ-thrash-and-incorrect-state-p.patch
1 From 6a276a4e4878b5b3e92c8975a87eb641d57669c4 Mon Sep 17 00:00:00 2001
2 From: P33M <P33M@github.com>
3 Date: Sat, 13 Jul 2013 21:48:41 +0100
4 Subject: [PATCH 079/196] dwc_otg: fiq: prevent FIQ thrash and incorrect state
5 passing to IRQ
6
7 In the case of a transaction to a device that had previously aborted
8 due to an error, several interrupts are enabled to reset the error
9 count when a device responds. This has the side-effect of making the
10 FIQ thrash because the hardware will generate multiple instances of
11 a NAK on an IN bulk/interrupt endpoint and multiple instances of ACK
12 on an OUT bulk/interrupt endpoint. Make the FIQ mask and clear the
13 associated interrupts.
14
15 Additionally, on non-split transactions make sure that only unmasked
16 interrupts are cleared. This caused a hard-to-trigger but serious
17 race condition when you had the combination of an endpoint awaiting
18 error recovery and a transaction completed on an endpoint - due to
19 the sequencing and timing of interrupts generated by the dwc_otg core,
20 it was possible to confuse the IRQ handler.
21 ---
22 drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c | 21 +++++++++++++++++++++
23 1 file changed, 21 insertions(+)
24
25 diff --git a/drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c b/drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c
26 index 27b673f..d655363 100644
27 --- a/drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c
28 +++ b/drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c
29 @@ -324,6 +324,27 @@ int fiq_hcintr_handle(int channel, hfnum_data_t hfnum)
30 }
31 }
32 }
33 + else
34 + {
35 + /*
36 + * If we have any of NAK, ACK, Datatlgerr active on a
37 + * non-split channel, the sole reason is to reset error
38 + * counts for a previously broken transaction. The FIQ
39 + * will thrash on NAK IN and ACK OUT in particular so
40 + * handle it "once" and allow the IRQ to do the rest.
41 + */
42 + hcint.d32 &= hcintmsk.d32;
43 + if(hcint.b.nak)
44 + {
45 + hcintmsk.b.nak = 0;
46 + FIQ_WRITE((dwc_regs_base + 0x500 + (channel * 0x20) + 0xc), hcintmsk.d32);
47 + }
48 + if (hcint.b.ack)
49 + {
50 + hcintmsk.b.ack = 0;
51 + FIQ_WRITE((dwc_regs_base + 0x500 + (channel * 0x20) + 0xc), hcintmsk.d32);
52 + }
53 + }
54
55 // Clear the interrupt, this will also clear the HAINT bit
56 FIQ_WRITE((dwc_regs_base + 0x500 + (channel * 0x20) + 0x8), hcint.d32);
57 --
58 1.9.1
59