aboutsummaryrefslogtreecommitdiffstats
path: root/arch/mips/bcm63xx
diff options
context:
space:
mode:
authorJonas Gorski <jogo@openwrt.org>2014-07-12 06:49:39 -0400
committerRalf Baechle <ralf@linux-mips.org>2014-07-30 09:29:23 -0400
commit74b8ca3f3160b062207be6ee88785409c0a777ea (patch)
tree0908fb60dbbd573ab17c67d8caa3dc4325a3e786 /arch/mips/bcm63xx
parent7a9fd14d4c4796d3b0d4aec9c91183560d201b4d (diff)
MIPS: BCM63xx: Protect irq register accesses
Since we will have the chance of accessing the registers concurrently, protect any accesses through a spinlock. Signed-off-by: Jonas Gorski <jogo@openwrt.org> Cc: linux-mips@linux-mips.org Cc: John Crispin <blogic@openwrt.org> Cc: Maxime Bizon <mbizon@freebox.fr> Cc: Florian Fainelli <florian@openwrt.org> Cc: Kevin Cernekee <cernekee@gmail.com> Cc: Gregory Fong <gregory.0xf0@gmail.com> Patchwork: https://patchwork.linux-mips.org/patch/7321/ Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
Diffstat (limited to 'arch/mips/bcm63xx')
-rw-r--r--arch/mips/bcm63xx/irq.c26
1 files changed, 26 insertions, 0 deletions
diff --git a/arch/mips/bcm63xx/irq.c b/arch/mips/bcm63xx/irq.c
index 53be291c3d94..2f1939122bc3 100644
--- a/arch/mips/bcm63xx/irq.c
+++ b/arch/mips/bcm63xx/irq.c
@@ -12,6 +12,7 @@
12#include <linux/interrupt.h> 12#include <linux/interrupt.h>
13#include <linux/module.h> 13#include <linux/module.h>
14#include <linux/irq.h> 14#include <linux/irq.h>
15#include <linux/spinlock.h>
15#include <asm/irq_cpu.h> 16#include <asm/irq_cpu.h>
16#include <asm/mipsregs.h> 17#include <asm/mipsregs.h>
17#include <bcm63xx_cpu.h> 18#include <bcm63xx_cpu.h>
@@ -20,6 +21,9 @@
20#include <bcm63xx_irq.h> 21#include <bcm63xx_irq.h>
21 22
22 23
24static DEFINE_SPINLOCK(ipic_lock);
25static DEFINE_SPINLOCK(epic_lock);
26
23static u32 irq_stat_addr[2]; 27static u32 irq_stat_addr[2];
24static u32 irq_mask_addr[2]; 28static u32 irq_mask_addr[2];
25static void (*dispatch_internal)(int cpu); 29static void (*dispatch_internal)(int cpu);
@@ -62,8 +66,10 @@ void __dispatch_internal_##width(int cpu) \
62 bool irqs_pending = false; \ 66 bool irqs_pending = false; \
63 static unsigned int i[2]; \ 67 static unsigned int i[2]; \
64 unsigned int *next = &i[cpu]; \ 68 unsigned int *next = &i[cpu]; \
69 unsigned long flags; \
65 \ 70 \
66 /* read registers in reverse order */ \ 71 /* read registers in reverse order */ \
72 spin_lock_irqsave(&ipic_lock, flags); \
67 for (src = 0, tgt = (width / 32); src < (width / 32); src++) { \ 73 for (src = 0, tgt = (width / 32); src < (width / 32); src++) { \
68 u32 val; \ 74 u32 val; \
69 \ 75 \
@@ -74,6 +80,7 @@ void __dispatch_internal_##width(int cpu) \
74 if (val) \ 80 if (val) \
75 irqs_pending = true; \ 81 irqs_pending = true; \
76 } \ 82 } \
83 spin_unlock_irqrestore(&ipic_lock, flags); \
77 \ 84 \
78 if (!irqs_pending) \ 85 if (!irqs_pending) \
79 return; \ 86 return; \
@@ -94,10 +101,13 @@ static void __internal_irq_mask_##width(unsigned int irq) \
94 u32 val; \ 101 u32 val; \
95 unsigned reg = (irq / 32) ^ (width/32 - 1); \ 102 unsigned reg = (irq / 32) ^ (width/32 - 1); \
96 unsigned bit = irq & 0x1f; \ 103 unsigned bit = irq & 0x1f; \
104 unsigned long flags; \
97 \ 105 \
106 spin_lock_irqsave(&ipic_lock, flags); \
98 val = bcm_readl(irq_mask_addr[0] + reg * sizeof(u32)); \ 107 val = bcm_readl(irq_mask_addr[0] + reg * sizeof(u32)); \
99 val &= ~(1 << bit); \ 108 val &= ~(1 << bit); \
100 bcm_writel(val, irq_mask_addr[0] + reg * sizeof(u32)); \ 109 bcm_writel(val, irq_mask_addr[0] + reg * sizeof(u32)); \
110 spin_unlock_irqrestore(&ipic_lock, flags); \
101} \ 111} \
102 \ 112 \
103static void __internal_irq_unmask_##width(unsigned int irq) \ 113static void __internal_irq_unmask_##width(unsigned int irq) \
@@ -105,10 +115,13 @@ static void __internal_irq_unmask_##width(unsigned int irq) \
105 u32 val; \ 115 u32 val; \
106 unsigned reg = (irq / 32) ^ (width/32 - 1); \ 116 unsigned reg = (irq / 32) ^ (width/32 - 1); \
107 unsigned bit = irq & 0x1f; \ 117 unsigned bit = irq & 0x1f; \
118 unsigned long flags; \
108 \ 119 \
120 spin_lock_irqsave(&ipic_lock, flags); \
109 val = bcm_readl(irq_mask_addr[0] + reg * sizeof(u32)); \ 121 val = bcm_readl(irq_mask_addr[0] + reg * sizeof(u32)); \
110 val |= (1 << bit); \ 122 val |= (1 << bit); \
111 bcm_writel(val, irq_mask_addr[0] + reg * sizeof(u32)); \ 123 bcm_writel(val, irq_mask_addr[0] + reg * sizeof(u32)); \
124 spin_unlock_irqrestore(&ipic_lock, flags); \
112} 125}
113 126
114BUILD_IPIC_INTERNAL(32); 127BUILD_IPIC_INTERNAL(32);
@@ -167,8 +180,10 @@ static void bcm63xx_external_irq_mask(struct irq_data *d)
167{ 180{
168 unsigned int irq = d->irq - IRQ_EXTERNAL_BASE; 181 unsigned int irq = d->irq - IRQ_EXTERNAL_BASE;
169 u32 reg, regaddr; 182 u32 reg, regaddr;
183 unsigned long flags;
170 184
171 regaddr = get_ext_irq_perf_reg(irq); 185 regaddr = get_ext_irq_perf_reg(irq);
186 spin_lock_irqsave(&epic_lock, flags);
172 reg = bcm_perf_readl(regaddr); 187 reg = bcm_perf_readl(regaddr);
173 188
174 if (BCMCPU_IS_6348()) 189 if (BCMCPU_IS_6348())
@@ -177,6 +192,8 @@ static void bcm63xx_external_irq_mask(struct irq_data *d)
177 reg &= ~EXTIRQ_CFG_MASK(irq % 4); 192 reg &= ~EXTIRQ_CFG_MASK(irq % 4);
178 193
179 bcm_perf_writel(reg, regaddr); 194 bcm_perf_writel(reg, regaddr);
195 spin_unlock_irqrestore(&epic_lock, flags);
196
180 if (is_ext_irq_cascaded) 197 if (is_ext_irq_cascaded)
181 internal_irq_mask(irq + ext_irq_start); 198 internal_irq_mask(irq + ext_irq_start);
182} 199}
@@ -185,8 +202,10 @@ static void bcm63xx_external_irq_unmask(struct irq_data *d)
185{ 202{
186 unsigned int irq = d->irq - IRQ_EXTERNAL_BASE; 203 unsigned int irq = d->irq - IRQ_EXTERNAL_BASE;
187 u32 reg, regaddr; 204 u32 reg, regaddr;
205 unsigned long flags;
188 206
189 regaddr = get_ext_irq_perf_reg(irq); 207 regaddr = get_ext_irq_perf_reg(irq);
208 spin_lock_irqsave(&epic_lock, flags);
190 reg = bcm_perf_readl(regaddr); 209 reg = bcm_perf_readl(regaddr);
191 210
192 if (BCMCPU_IS_6348()) 211 if (BCMCPU_IS_6348())
@@ -195,6 +214,7 @@ static void bcm63xx_external_irq_unmask(struct irq_data *d)
195 reg |= EXTIRQ_CFG_MASK(irq % 4); 214 reg |= EXTIRQ_CFG_MASK(irq % 4);
196 215
197 bcm_perf_writel(reg, regaddr); 216 bcm_perf_writel(reg, regaddr);
217 spin_unlock_irqrestore(&epic_lock, flags);
198 218
199 if (is_ext_irq_cascaded) 219 if (is_ext_irq_cascaded)
200 internal_irq_unmask(irq + ext_irq_start); 220 internal_irq_unmask(irq + ext_irq_start);
@@ -204,8 +224,10 @@ static void bcm63xx_external_irq_clear(struct irq_data *d)
204{ 224{
205 unsigned int irq = d->irq - IRQ_EXTERNAL_BASE; 225 unsigned int irq = d->irq - IRQ_EXTERNAL_BASE;
206 u32 reg, regaddr; 226 u32 reg, regaddr;
227 unsigned long flags;
207 228
208 regaddr = get_ext_irq_perf_reg(irq); 229 regaddr = get_ext_irq_perf_reg(irq);
230 spin_lock_irqsave(&epic_lock, flags);
209 reg = bcm_perf_readl(regaddr); 231 reg = bcm_perf_readl(regaddr);
210 232
211 if (BCMCPU_IS_6348()) 233 if (BCMCPU_IS_6348())
@@ -214,6 +236,7 @@ static void bcm63xx_external_irq_clear(struct irq_data *d)
214 reg |= EXTIRQ_CFG_CLEAR(irq % 4); 236 reg |= EXTIRQ_CFG_CLEAR(irq % 4);
215 237
216 bcm_perf_writel(reg, regaddr); 238 bcm_perf_writel(reg, regaddr);
239 spin_unlock_irqrestore(&epic_lock, flags);
217} 240}
218 241
219static int bcm63xx_external_irq_set_type(struct irq_data *d, 242static int bcm63xx_external_irq_set_type(struct irq_data *d,
@@ -222,6 +245,7 @@ static int bcm63xx_external_irq_set_type(struct irq_data *d,
222 unsigned int irq = d->irq - IRQ_EXTERNAL_BASE; 245 unsigned int irq = d->irq - IRQ_EXTERNAL_BASE;
223 u32 reg, regaddr; 246 u32 reg, regaddr;
224 int levelsense, sense, bothedge; 247 int levelsense, sense, bothedge;
248 unsigned long flags;
225 249
226 flow_type &= IRQ_TYPE_SENSE_MASK; 250 flow_type &= IRQ_TYPE_SENSE_MASK;
227 251
@@ -256,6 +280,7 @@ static int bcm63xx_external_irq_set_type(struct irq_data *d,
256 } 280 }
257 281
258 regaddr = get_ext_irq_perf_reg(irq); 282 regaddr = get_ext_irq_perf_reg(irq);
283 spin_lock_irqsave(&epic_lock, flags);
259 reg = bcm_perf_readl(regaddr); 284 reg = bcm_perf_readl(regaddr);
260 irq %= 4; 285 irq %= 4;
261 286
@@ -300,6 +325,7 @@ static int bcm63xx_external_irq_set_type(struct irq_data *d,
300 } 325 }
301 326
302 bcm_perf_writel(reg, regaddr); 327 bcm_perf_writel(reg, regaddr);
328 spin_unlock_irqrestore(&epic_lock, flags);
303 329
304 irqd_set_trigger_type(d, flow_type); 330 irqd_set_trigger_type(d, flow_type);
305 if (flow_type & (IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_LEVEL_HIGH)) 331 if (flow_type & (IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_LEVEL_HIGH))