@@ -99,7 +99,7 @@
compatible = "st,asc";
status = "disabled";
reg = <0xfe531000 0x2c>;
- interrupts = <0 210 0>;
+ interrupts = <0 210 0>, <0 210 0>;
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_sbc_serial1>;
clocks = <&CLK_SYSIN>;
@@ -140,7 +140,7 @@
v2m_serial0: uart@090000 {
compatible = "arm,pl011", "arm,primecell";
reg = <0x090000 0x1000>;
- interrupts = <5>;
+ interrupts = <5>, <5>;
clocks = <&v2m_oscclk2>, <&smbclk>;
clock-names = "uartclk", "apb_pclk";
};
@@ -41,6 +41,7 @@
#include <linux/interrupt.h>
#include <linux/seq_file.h>
#include <linux/irq.h>
+#include <linux/irqchip/arm-vic.h>
#include <asm/cacheflush.h>
#include <asm/cp15.h>
@@ -130,14 +131,52 @@ void release_fiq(struct fiq_handler *f)
static int fiq_start;
+/* These hacks use backdoors into the interrupt controller to perform FIQ/IRQ
+ * routing. These hacks are nasty and completely incompatible with (working)
+ * multiarch kernels. Additionally these hacks don't count enable/disable
+ * properly...
+ *
+ * This should probably all be replaced with virtual interrupt numbers
+ * that the intc already knows to bind to FIQ.
+ */
+#ifdef CONFIG_ARCH_VERSATILE
+#define USE_VIC_HACK
+#else
+#define USE_GIC_HACK
+#endif
+
void enable_fiq(int fiq)
{
+#ifdef USE_VIC_HACK
+ vic_set_fiq(fiq, true);
+#endif
+#ifdef USE_GIC_HACK
+{
+ struct irq_data *irq_data = irq_get_irq_data(fiq);
+
+ extern void gic_set_group_irq(struct irq_data *d, int group);
+ gic_set_group_irq(irq_data, 0);
+}
+#endif
+
enable_irq(fiq + fiq_start);
}
void disable_fiq(int fiq)
{
disable_irq(fiq + fiq_start);
+
+#ifdef USE_VIC_HACK
+ vic_set_fiq(fiq, false);
+#endif
+#ifdef USE_GIC_HACK
+{
+ struct irq_data *irq_data = irq_get_irq_data(fiq);
+
+ extern void gic_set_group_irq(struct irq_data *d, int group);
+ gic_set_group_irq(irq_data, 1);
+}
+#endif
}
void eoi_fiq(int fiq)
@@ -173,6 +173,33 @@ static void gic_unmask_irq(struct irq_data *d)
raw_spin_unlock(&irq_controller_lock);
}
+/*static*/ void gic_set_group_irq(struct irq_data *d, int group)
+{
+ unsigned long flags;
+ unsigned int reg = gic_irq(d) / 32 * 4;
+ u32 mask = 1 << (gic_irq(d) % 32);
+ u32 val;
+
+ raw_spin_lock_irqsave(&irq_controller_lock, flags);
+ val = readl_relaxed(gic_dist_base(d) + GIC_DIST_IGROUP + reg);
+ if (group)
+ val |= mask;
+ else
+ val &= ~mask;
+ writel_relaxed(val, gic_dist_base(d) + GIC_DIST_IGROUP + reg);
+ raw_spin_unlock_irqrestore(&irq_controller_lock, flags);
+}
+
+/*static*/ int gic_get_group_irq(struct irq_data *d)
+{
+ unsigned int reg = gic_irq(d) / 32 * 4;
+ u32 mask = 1 << (gic_irq(d) % 32);
+ u32 val;
+
+ val = readl_relaxed(gic_dist_base(d) + GIC_DIST_IGROUP + reg);
+ return !!(val & mask);
+}
+
static void gic_eoi_irq(struct irq_data *d)
{
if (gic_arch_extn.irq_eoi) {
This is a hack to make it easy to check that the other interfaces in the patchset make sense. It needs to be replaced by code to get the interrupt controllers to expose FIQs. Unless a better option presents itself I plan to double up each interrupt source (so we get two virqs, one for regular interrupt and one for FIQ). This is what most of the prior art around FIQ in Linux has done in the past. Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org> --- arch/arm/boot/dts/stih416.dtsi | 2 +- arch/arm/boot/dts/vexpress-v2m-rs1.dtsi | 2 +- arch/arm/kernel/fiq.c | 39 +++++++++++++++++++++++++++++++++ drivers/irqchip/irq-gic.c | 27 +++++++++++++++++++++++ 4 files changed, 68 insertions(+), 2 deletions(-)