aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arc/kernel/irq.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arc/kernel/irq.c')
-rw-r--r--arch/arc/kernel/irq.c53
1 files changed, 41 insertions, 12 deletions
diff --git a/arch/arc/kernel/irq.c b/arch/arc/kernel/irq.c
index 7d653c0d0773..620ec2fe32a9 100644
--- a/arch/arc/kernel/irq.c
+++ b/arch/arc/kernel/irq.c
@@ -19,21 +19,16 @@
/*
* Early Hardware specific Interrupt setup
+ * -Platform independent, needed for each CPU (not foldable into init_IRQ)
* -Called very early (start_kernel -> setup_arch -> setup_processor)
- * -Platform Independent (must for any ARC700)
- * -Needed for each CPU (hence not foldable into init_IRQ)
*
* what it does ?
- * -Disable all IRQs (on CPU side)
* -Optionally, setup the High priority Interrupts as Level 2 IRQs
*/
void arc_init_IRQ(void)
{
int level_mask = 0;
- /* Disable all IRQs: enable them as devices request */
- write_aux_reg(AUX_IENABLE, 0);
-
/* setup any high priority Interrupts (Level2 in ARCompact jargon) */
level_mask |= IS_ENABLED(CONFIG_ARC_IRQ3_LV2) << 3;
level_mask |= IS_ENABLED(CONFIG_ARC_IRQ5_LV2) << 5;
@@ -60,20 +55,28 @@ void arc_init_IRQ(void)
* below, per IRQ.
*/
-static void arc_mask_irq(struct irq_data *data)
+static void arc_irq_mask(struct irq_data *data)
{
- arch_mask_irq(data->irq);
+ unsigned int ienb;
+
+ ienb = read_aux_reg(AUX_IENABLE);
+ ienb &= ~(1 << data->irq);
+ write_aux_reg(AUX_IENABLE, ienb);
}
-static void arc_unmask_irq(struct irq_data *data)
+static void arc_irq_unmask(struct irq_data *data)
{
- arch_unmask_irq(data->irq);
+ unsigned int ienb;
+
+ ienb = read_aux_reg(AUX_IENABLE);
+ ienb |= (1 << data->irq);
+ write_aux_reg(AUX_IENABLE, ienb);
}
static struct irq_chip onchip_intc = {
.name = "ARC In-core Intc",
- .irq_mask = arc_mask_irq,
- .irq_unmask = arc_unmask_irq,
+ .irq_mask = arc_irq_mask,
+ .irq_unmask = arc_irq_unmask,
};
static int arc_intc_domain_map(struct irq_domain *d, unsigned int irq,
@@ -150,6 +153,32 @@ void arch_do_IRQ(unsigned int irq, struct pt_regs *regs)
set_irq_regs(old_regs);
}
+void arc_request_percpu_irq(int irq, int cpu,
+ irqreturn_t (*isr)(int irq, void *dev),
+ const char *irq_nm,
+ void *percpu_dev)
+{
+ /* Boot cpu calls request, all call enable */
+ if (!cpu) {
+ int rc;
+
+ /*
+ * These 2 calls are essential to making percpu IRQ APIs work
+ * Ideally these details could be hidden in irq chip map function
+ * but the issue is IPIs IRQs being static (non-DT) and platform
+ * specific, so we can't identify them there.
+ */
+ irq_set_percpu_devid(irq);
+ irq_modify_status(irq, IRQ_NOAUTOEN, 0); /* @irq, @clr, @set */
+
+ rc = request_percpu_irq(irq, isr, irq_nm, percpu_dev);
+ if (rc)
+ panic("Percpu IRQ request failed for %d\n", irq);
+ }
+
+ enable_percpu_irq(irq, 0);
+}
+
/*
* arch_local_irq_enable - Enable interrupts.
*