aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLiviu Dudau <Liviu.Dudau@arm.com>2015-01-20 11:52:59 -0500
committerThomas Gleixner <tglx@linutronix.de>2015-01-26 05:38:23 -0500
commitfb7e7deb7fc348ae131268d30e391c8184285de6 (patch)
treea036b13c9e0bcaeebbe3ce6691042d9f9840d9b6
parentd7eb4f2ecccd71f701bc8873bcf07c2d3b0375f6 (diff)
irqchip: gic: Allow interrupt level to be set for PPIs
During a recent cleanup of the arm64 DTs it has become clear that the handling of PPIs in xxxx_set_type() is incorrect. The ARM TRMs for GICv2 and later allow for "implementation defined" support for setting the edge or level type of the PPI interrupts and don't restrict the activation level of the signal. Current ARM implementations do restrict the PPI level type to IRQ_TYPE_LEVEL_LOW, but licensees of the IP can decide to shoot themselves in the foot at any time. Signed-off-by: Liviu Dudau <Liviu.Dudau@arm.com> Acked-by: Marc Zyngier <Marc.Zyngier@arm.com> Cc: LAKML <linux-arm-kernel@lists.infradead.org> Cc: Russell King <linux@arm.linux.org.uk> Cc: Rob Herring <robh+dt@kernel.org> Cc: Mark Rutland <mark.rutland@arm.com> Cc: Ian Campbell <ijc+devicetree@hellion.org.uk> Cc: Jason Cooper <jason@lakedaemon.net> Cc: Haojian Zhuang <haojian.zhuang@linaro.org> Link: http://lkml.kernel.org/r/1421772779-25764-1-git-send-email-Liviu.Dudau@arm.com Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
-rw-r--r--Documentation/devicetree/bindings/arm/gic.txt8
-rw-r--r--drivers/irqchip/irq-gic-common.c18
-rw-r--r--drivers/irqchip/irq-gic-common.h2
-rw-r--r--drivers/irqchip/irq-gic-v3.c8
-rw-r--r--drivers/irqchip/irq-gic.c9
-rw-r--r--drivers/irqchip/irq-hip04.c9
6 files changed, 35 insertions, 19 deletions
diff --git a/Documentation/devicetree/bindings/arm/gic.txt b/Documentation/devicetree/bindings/arm/gic.txt
index 8112d0c3675a..c97484b73e72 100644
--- a/Documentation/devicetree/bindings/arm/gic.txt
+++ b/Documentation/devicetree/bindings/arm/gic.txt
@@ -32,12 +32,16 @@ Main node required properties:
32 The 3rd cell is the flags, encoded as follows: 32 The 3rd cell is the flags, encoded as follows:
33 bits[3:0] trigger type and level flags. 33 bits[3:0] trigger type and level flags.
34 1 = low-to-high edge triggered 34 1 = low-to-high edge triggered
35 2 = high-to-low edge triggered 35 2 = high-to-low edge triggered (invalid for SPIs)
36 4 = active high level-sensitive 36 4 = active high level-sensitive
37 8 = active low level-sensitive 37 8 = active low level-sensitive (invalid for SPIs).
38 bits[15:8] PPI interrupt cpu mask. Each bit corresponds to each of 38 bits[15:8] PPI interrupt cpu mask. Each bit corresponds to each of
39 the 8 possible cpus attached to the GIC. A bit set to '1' indicated 39 the 8 possible cpus attached to the GIC. A bit set to '1' indicated
40 the interrupt is wired to that CPU. Only valid for PPI interrupts. 40 the interrupt is wired to that CPU. Only valid for PPI interrupts.
41 Also note that the configurability of PPI interrupts is IMPLEMENTATION
42 DEFINED and as such not guaranteed to be present (most SoC available
43 in 2014 seem to ignore the setting of this flag and use the hardware
44 default value).
41 45
42- reg : Specifies base physical address(s) and size of the GIC registers. The 46- reg : Specifies base physical address(s) and size of the GIC registers. The
43 first region is the GIC distributor register base and size. The 2nd region is 47 first region is the GIC distributor register base and size. The 2nd region is
diff --git a/drivers/irqchip/irq-gic-common.c b/drivers/irqchip/irq-gic-common.c
index 61541ff24397..ad96ebb0c7ab 100644
--- a/drivers/irqchip/irq-gic-common.c
+++ b/drivers/irqchip/irq-gic-common.c
@@ -21,7 +21,7 @@
21 21
22#include "irq-gic-common.h" 22#include "irq-gic-common.h"
23 23
24void gic_configure_irq(unsigned int irq, unsigned int type, 24int gic_configure_irq(unsigned int irq, unsigned int type,
25 void __iomem *base, void (*sync_access)(void)) 25 void __iomem *base, void (*sync_access)(void))
26{ 26{
27 u32 enablemask = 1 << (irq % 32); 27 u32 enablemask = 1 << (irq % 32);
@@ -29,16 +29,17 @@ void gic_configure_irq(unsigned int irq, unsigned int type,
29 u32 confmask = 0x2 << ((irq % 16) * 2); 29 u32 confmask = 0x2 << ((irq % 16) * 2);
30 u32 confoff = (irq / 16) * 4; 30 u32 confoff = (irq / 16) * 4;
31 bool enabled = false; 31 bool enabled = false;
32 u32 val; 32 u32 val, oldval;
33 int ret = 0;
33 34
34 /* 35 /*
35 * Read current configuration register, and insert the config 36 * Read current configuration register, and insert the config
36 * for "irq", depending on "type". 37 * for "irq", depending on "type".
37 */ 38 */
38 val = readl_relaxed(base + GIC_DIST_CONFIG + confoff); 39 val = oldval = readl_relaxed(base + GIC_DIST_CONFIG + confoff);
39 if (type == IRQ_TYPE_LEVEL_HIGH) 40 if (type & IRQ_TYPE_LEVEL_MASK)
40 val &= ~confmask; 41 val &= ~confmask;
41 else if (type == IRQ_TYPE_EDGE_RISING) 42 else if (type & IRQ_TYPE_EDGE_BOTH)
42 val |= confmask; 43 val |= confmask;
43 44
44 /* 45 /*
@@ -54,15 +55,20 @@ void gic_configure_irq(unsigned int irq, unsigned int type,
54 55
55 /* 56 /*
56 * Write back the new configuration, and possibly re-enable 57 * Write back the new configuration, and possibly re-enable
57 * the interrupt. 58 * the interrupt. If we tried to write a new configuration and failed,
59 * return an error.
58 */ 60 */
59 writel_relaxed(val, base + GIC_DIST_CONFIG + confoff); 61 writel_relaxed(val, base + GIC_DIST_CONFIG + confoff);
62 if (readl_relaxed(base + GIC_DIST_CONFIG + confoff) != val && val != oldval)
63 ret = -EINVAL;
60 64
61 if (enabled) 65 if (enabled)
62 writel_relaxed(enablemask, base + GIC_DIST_ENABLE_SET + enableoff); 66 writel_relaxed(enablemask, base + GIC_DIST_ENABLE_SET + enableoff);
63 67
64 if (sync_access) 68 if (sync_access)
65 sync_access(); 69 sync_access();
70
71 return ret;
66} 72}
67 73
68void __init gic_dist_config(void __iomem *base, int gic_irqs, 74void __init gic_dist_config(void __iomem *base, int gic_irqs,
diff --git a/drivers/irqchip/irq-gic-common.h b/drivers/irqchip/irq-gic-common.h
index b41f02481c3a..35a9884778bd 100644
--- a/drivers/irqchip/irq-gic-common.h
+++ b/drivers/irqchip/irq-gic-common.h
@@ -20,7 +20,7 @@
20#include <linux/of.h> 20#include <linux/of.h>
21#include <linux/irqdomain.h> 21#include <linux/irqdomain.h>
22 22
23void gic_configure_irq(unsigned int irq, unsigned int type, 23int gic_configure_irq(unsigned int irq, unsigned int type,
24 void __iomem *base, void (*sync_access)(void)); 24 void __iomem *base, void (*sync_access)(void));
25void gic_dist_config(void __iomem *base, int gic_irqs, 25void gic_dist_config(void __iomem *base, int gic_irqs,
26 void (*sync_access)(void)); 26 void (*sync_access)(void));
diff --git a/drivers/irqchip/irq-gic-v3.c b/drivers/irqchip/irq-gic-v3.c
index 1a146ccee701..6e508038f31b 100644
--- a/drivers/irqchip/irq-gic-v3.c
+++ b/drivers/irqchip/irq-gic-v3.c
@@ -238,7 +238,9 @@ static int gic_set_type(struct irq_data *d, unsigned int type)
238 if (irq < 16) 238 if (irq < 16)
239 return -EINVAL; 239 return -EINVAL;
240 240
241 if (type != IRQ_TYPE_LEVEL_HIGH && type != IRQ_TYPE_EDGE_RISING) 241 /* SPIs have restrictions on the supported types */
242 if (irq >= 32 && type != IRQ_TYPE_LEVEL_HIGH &&
243 type != IRQ_TYPE_EDGE_RISING)
242 return -EINVAL; 244 return -EINVAL;
243 245
244 if (gic_irq_in_rdist(d)) { 246 if (gic_irq_in_rdist(d)) {
@@ -249,9 +251,7 @@ static int gic_set_type(struct irq_data *d, unsigned int type)
249 rwp_wait = gic_dist_wait_for_rwp; 251 rwp_wait = gic_dist_wait_for_rwp;
250 } 252 }
251 253
252 gic_configure_irq(irq, type, base, rwp_wait); 254 return gic_configure_irq(irq, type, base, rwp_wait);
253
254 return 0;
255} 255}
256 256
257static u64 gic_mpidr_to_affinity(u64 mpidr) 257static u64 gic_mpidr_to_affinity(u64 mpidr)
diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c
index d617ee5a3d8a..4634cf7d0ec3 100644
--- a/drivers/irqchip/irq-gic.c
+++ b/drivers/irqchip/irq-gic.c
@@ -188,12 +188,15 @@ static int gic_set_type(struct irq_data *d, unsigned int type)
188{ 188{
189 void __iomem *base = gic_dist_base(d); 189 void __iomem *base = gic_dist_base(d);
190 unsigned int gicirq = gic_irq(d); 190 unsigned int gicirq = gic_irq(d);
191 int ret;
191 192
192 /* Interrupt configuration for SGIs can't be changed */ 193 /* Interrupt configuration for SGIs can't be changed */
193 if (gicirq < 16) 194 if (gicirq < 16)
194 return -EINVAL; 195 return -EINVAL;
195 196
196 if (type != IRQ_TYPE_LEVEL_HIGH && type != IRQ_TYPE_EDGE_RISING) 197 /* SPIs have restrictions on the supported types */
198 if (gicirq >= 32 && type != IRQ_TYPE_LEVEL_HIGH &&
199 type != IRQ_TYPE_EDGE_RISING)
197 return -EINVAL; 200 return -EINVAL;
198 201
199 raw_spin_lock(&irq_controller_lock); 202 raw_spin_lock(&irq_controller_lock);
@@ -201,11 +204,11 @@ static int gic_set_type(struct irq_data *d, unsigned int type)
201 if (gic_arch_extn.irq_set_type) 204 if (gic_arch_extn.irq_set_type)
202 gic_arch_extn.irq_set_type(d, type); 205 gic_arch_extn.irq_set_type(d, type);
203 206
204 gic_configure_irq(gicirq, type, base, NULL); 207 ret = gic_configure_irq(gicirq, type, base, NULL);
205 208
206 raw_spin_unlock(&irq_controller_lock); 209 raw_spin_unlock(&irq_controller_lock);
207 210
208 return 0; 211 return ret;
209} 212}
210 213
211static int gic_retrigger(struct irq_data *d) 214static int gic_retrigger(struct irq_data *d)
diff --git a/drivers/irqchip/irq-hip04.c b/drivers/irqchip/irq-hip04.c
index 6bc2deb73d53..7d6ffb5de84f 100644
--- a/drivers/irqchip/irq-hip04.c
+++ b/drivers/irqchip/irq-hip04.c
@@ -120,21 +120,24 @@ static int hip04_irq_set_type(struct irq_data *d, unsigned int type)
120{ 120{
121 void __iomem *base = hip04_dist_base(d); 121 void __iomem *base = hip04_dist_base(d);
122 unsigned int irq = hip04_irq(d); 122 unsigned int irq = hip04_irq(d);
123 int ret;
123 124
124 /* Interrupt configuration for SGIs can't be changed */ 125 /* Interrupt configuration for SGIs can't be changed */
125 if (irq < 16) 126 if (irq < 16)
126 return -EINVAL; 127 return -EINVAL;
127 128
128 if (type != IRQ_TYPE_LEVEL_HIGH && type != IRQ_TYPE_EDGE_RISING) 129 /* SPIs have restrictions on the supported types */
130 if (irq >= 32 && type != IRQ_TYPE_LEVEL_HIGH &&
131 type != IRQ_TYPE_EDGE_RISING)
129 return -EINVAL; 132 return -EINVAL;
130 133
131 raw_spin_lock(&irq_controller_lock); 134 raw_spin_lock(&irq_controller_lock);
132 135
133 gic_configure_irq(irq, type, base, NULL); 136 ret = gic_configure_irq(irq, type, base, NULL);
134 137
135 raw_spin_unlock(&irq_controller_lock); 138 raw_spin_unlock(&irq_controller_lock);
136 139
137 return 0; 140 return ret;
138} 141}
139 142
140#ifdef CONFIG_SMP 143#ifdef CONFIG_SMP