mvebu: backport mainline patches from kernel 3.12
[openwrt.git] / target / linux / mvebu / patches-3.10 / 0086-irqchip-armada-370-xp-fix-MSI-race-condition.patch
1 From ddda6fa410b6e50ee67d4a628187e76b4a6c9b28 Mon Sep 17 00:00:00 2001
2 From: Lior Amsalem <alior@marvell.com>
3 Date: Mon, 25 Nov 2013 17:26:45 +0100
4 Subject: [PATCH 086/203] irqchip: armada-370-xp: fix MSI race condition
5
6 In the Armada 370/XP driver, when we receive an IRQ 1, we read the
7 list of doorbells that caused the interrupt from register
8 ARMADA_370_XP_IN_DRBEL_CAUSE_OFFS. This gives the list of MSIs that
9 were generated. However, instead of acknowledging only the MSIs that
10 were generated, we acknowledge *all* the MSIs, by writing
11 ~MSI_DOORBELL_MASK in the ARMADA_370_XP_IN_DRBEL_CAUSE_OFFS register.
12
13 This creates a race condition: if a new MSI that isn't part of the
14 ones read into the temporary "msimask" variable is fired before we
15 acknowledge all MSIs, then we will simply loose it.
16
17 It is important to mention that this ARMADA_370_XP_IN_DRBEL_CAUSE_OFFS
18 register has the following behavior: "A CPU write of 0 clears the bits
19 in this field. A CPU write of 1 has no effect". This is what allows us
20 to simply write ~msimask to acknoledge the handled MSIs.
21
22 Notice that the same problem is present in the IPI implementation, but
23 it is fixed as a separate patch, so that this IPI fix can be pushed to
24 older stable versions as appropriate (all the way to 3.8), while the
25 MSI code only appeared in 3.13.
26
27 Signed-off-by: Lior Amsalem <alior@marvell.com>
28 Signed-off-by: Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
29 Cc: Thomas Gleixner <tglx@linutronix.de>
30 ---
31  drivers/irqchip/irq-armada-370-xp.c | 2 +-
32  1 file changed, 1 insertion(+), 1 deletion(-)
33
34 --- a/drivers/irqchip/irq-armada-370-xp.c
35 +++ b/drivers/irqchip/irq-armada-370-xp.c
36 @@ -381,7 +381,7 @@ armada_370_xp_handle_irq(struct pt_regs
37                                                 ARMADA_370_XP_IN_DRBEL_CAUSE_OFFS)
38                                 & PCI_MSI_DOORBELL_MASK;
39  
40 -                       writel(~PCI_MSI_DOORBELL_MASK, per_cpu_int_base +
41 +                       writel(~msimask, per_cpu_int_base +
42                                ARMADA_370_XP_IN_DRBEL_CAUSE_OFFS);
43  
44                         for (msinr = PCI_MSI_DOORBELL_START;