MIPS: BCM63XX: Prepare irq code to handle different external irq hardware implementation.
External irq only works for 6348, change code to prepare support of
other CPUs.
Signed-off-by: Maxime Bizon <mbizon@freebox.fr>
Cc: linux-mips@linux-mips.org
Patchwork: https://patchwork.linux-mips.org/patch/2895/
Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
diff --git a/arch/mips/bcm63xx/irq.c b/arch/mips/bcm63xx/irq.c
index a81cd82..cdf352b 100644
--- a/arch/mips/bcm63xx/irq.c
+++ b/arch/mips/bcm63xx/irq.c
@@ -25,18 +25,32 @@
#ifdef CONFIG_BCM63XX_CPU_6338
#define irq_stat_reg PERF_IRQSTAT_6338_REG
#define irq_mask_reg PERF_IRQMASK_6338_REG
+#define is_ext_irq_cascaded 0
+#define ext_irq_start 0
+#define ext_irq_end 0
#endif
#ifdef CONFIG_BCM63XX_CPU_6345
#define irq_stat_reg PERF_IRQSTAT_6345_REG
#define irq_mask_reg PERF_IRQMASK_6345_REG
+#define is_ext_irq_cascaded 0
+#define ext_irq_start 0
+#define ext_irq_end 0
#endif
#ifdef CONFIG_BCM63XX_CPU_6348
#define irq_stat_reg PERF_IRQSTAT_6348_REG
#define irq_mask_reg PERF_IRQMASK_6348_REG
+#define dispatch_internal __dispatch_internal
+#define is_ext_irq_cascaded 0
+#define ext_irq_start 0
+#define ext_irq_end 0
#endif
#ifdef CONFIG_BCM63XX_CPU_6358
#define irq_stat_reg PERF_IRQSTAT_6358_REG
#define irq_mask_reg PERF_IRQMASK_6358_REG
+#define dispatch_internal __dispatch_internal
+#define is_ext_irq_cascaded 1
+#define ext_irq_start (BCM_6358_EXT_IRQ0 - IRQ_INTERNAL_BASE)
+#define ext_irq_end (BCM_6358_EXT_IRQ3 - IRQ_INTERNAL_BASE)
#endif
#define dispatch_internal __dispatch_internal
@@ -51,6 +65,8 @@
static u32 irq_stat_addr, irq_mask_addr;
static void (*dispatch_internal)(void);
+static int is_ext_irq_cascaded;
+static unsigned int ext_irq_start, ext_irq_end;
static void bcm63xx_init_irq(void)
{
@@ -73,6 +89,9 @@
case BCM6358_CPU_ID:
irq_stat_addr += PERF_IRQSTAT_6358_REG;
irq_mask_addr += PERF_IRQMASK_6358_REG;
+ is_ext_irq_cascaded = 1;
+ ext_irq_start = BCM_6358_EXT_IRQ0 - IRQ_INTERNAL_BASE;
+ ext_irq_end = BCM_6358_EXT_IRQ3 - IRQ_INTERNAL_BASE;
break;
default:
BUG();
@@ -84,7 +103,11 @@
static inline void handle_internal(int intbit)
{
- do_IRQ(intbit + IRQ_INTERNAL_BASE);
+ if (is_ext_irq_cascaded &&
+ intbit >= ext_irq_start && intbit <= ext_irq_end)
+ do_IRQ(intbit - ext_irq_start + IRQ_EXTERNAL_BASE);
+ else
+ do_IRQ(intbit + IRQ_INTERNAL_BASE);
}
/*
@@ -128,14 +151,16 @@
do_IRQ(7);
if (cause & CAUSEF_IP2)
dispatch_internal();
- if (cause & CAUSEF_IP3)
- do_IRQ(IRQ_EXT_0);
- if (cause & CAUSEF_IP4)
- do_IRQ(IRQ_EXT_1);
- if (cause & CAUSEF_IP5)
- do_IRQ(IRQ_EXT_2);
- if (cause & CAUSEF_IP6)
- do_IRQ(IRQ_EXT_3);
+ if (!is_ext_irq_cascaded) {
+ if (cause & CAUSEF_IP3)
+ do_IRQ(IRQ_EXT_0);
+ if (cause & CAUSEF_IP4)
+ do_IRQ(IRQ_EXT_1);
+ if (cause & CAUSEF_IP5)
+ do_IRQ(IRQ_EXT_2);
+ if (cause & CAUSEF_IP6)
+ do_IRQ(IRQ_EXT_3);
+ }
} while (1);
}
@@ -143,9 +168,8 @@
* internal IRQs operations: only mask/unmask on PERF irq mask
* register.
*/
-static inline void bcm63xx_internal_irq_mask(struct irq_data *d)
+static void internal_irq_mask(unsigned int irq)
{
- unsigned int irq = d->irq - IRQ_INTERNAL_BASE;
u32 mask;
mask = bcm_readl(irq_mask_addr);
@@ -153,9 +177,8 @@
bcm_writel(mask, irq_mask_addr);
}
-static void bcm63xx_internal_irq_unmask(struct irq_data *d)
+static void internal_irq_unmask(unsigned int irq)
{
- unsigned int irq = d->irq - IRQ_INTERNAL_BASE;
u32 mask;
mask = bcm_readl(irq_mask_addr);
@@ -163,33 +186,47 @@
bcm_writel(mask, irq_mask_addr);
}
+static void bcm63xx_internal_irq_mask(struct irq_data *d)
+{
+ internal_irq_mask(d->irq - IRQ_INTERNAL_BASE);
+}
+
+static void bcm63xx_internal_irq_unmask(struct irq_data *d)
+{
+ internal_irq_unmask(d->irq - IRQ_INTERNAL_BASE);
+}
+
/*
* external IRQs operations: mask/unmask and clear on PERF external
* irq control register.
*/
static void bcm63xx_external_irq_mask(struct irq_data *d)
{
- unsigned int irq = d->irq - IRQ_EXT_BASE;
+ unsigned int irq = d->irq - IRQ_EXTERNAL_BASE;
u32 reg;
reg = bcm_perf_readl(PERF_EXTIRQ_CFG_REG);
reg &= ~EXTIRQ_CFG_MASK(irq);
bcm_perf_writel(reg, PERF_EXTIRQ_CFG_REG);
+ if (is_ext_irq_cascaded)
+ internal_irq_mask(irq + ext_irq_start);
}
static void bcm63xx_external_irq_unmask(struct irq_data *d)
{
- unsigned int irq = d->irq - IRQ_EXT_BASE;
+ unsigned int irq = d->irq - IRQ_EXTERNAL_BASE;
u32 reg;
reg = bcm_perf_readl(PERF_EXTIRQ_CFG_REG);
reg |= EXTIRQ_CFG_MASK(irq);
bcm_perf_writel(reg, PERF_EXTIRQ_CFG_REG);
+ if (is_ext_irq_cascaded)
+ internal_irq_unmask(irq + ext_irq_start);
}
static void bcm63xx_external_irq_clear(struct irq_data *d)
{
- unsigned int irq = d->irq - IRQ_EXT_BASE;
+ unsigned int irq = d->irq - IRQ_EXTERNAL_BASE;
u32 reg;
reg = bcm_perf_readl(PERF_EXTIRQ_CFG_REG);
@@ -197,25 +234,10 @@
bcm_perf_writel(reg, PERF_EXTIRQ_CFG_REG);
}
-static unsigned int bcm63xx_external_irq_startup(struct irq_data *d)
-{
- set_c0_status(0x100 << (d->irq - IRQ_MIPS_BASE));
- irq_enable_hazard();
- bcm63xx_external_irq_unmask(d);
- return 0;
-}
-
-static void bcm63xx_external_irq_shutdown(struct irq_data *d)
-{
- bcm63xx_external_irq_mask(d);
- clear_c0_status(0x100 << (d->irq - IRQ_MIPS_BASE));
- irq_disable_hazard();
-}
-
static int bcm63xx_external_irq_set_type(struct irq_data *d,
unsigned int flow_type)
{
- unsigned int irq = d->irq - IRQ_EXT_BASE;
+ unsigned int irq = d->irq - IRQ_EXTERNAL_BASE;
u32 reg;
flow_type &= IRQ_TYPE_SENSE_MASK;
@@ -275,9 +297,6 @@
static struct irq_chip bcm63xx_external_irq_chip = {
.name = "bcm63xx_epic",
- .irq_startup = bcm63xx_external_irq_startup,
- .irq_shutdown = bcm63xx_external_irq_shutdown,
-
.irq_ack = bcm63xx_external_irq_clear,
.irq_mask = bcm63xx_external_irq_mask,
@@ -292,6 +311,12 @@
.flags = IRQF_NO_THREAD,
};
+static struct irqaction cpu_ext_cascade_action = {
+ .handler = no_action,
+ .name = "cascade_extirq",
+ .flags = IRQF_NO_THREAD,
+};
+
void __init arch_init_irq(void)
{
int i;
@@ -302,9 +327,14 @@
irq_set_chip_and_handler(i, &bcm63xx_internal_irq_chip,
handle_level_irq);
- for (i = IRQ_EXT_BASE; i < IRQ_EXT_BASE + 4; ++i)
+ for (i = IRQ_EXTERNAL_BASE; i < IRQ_EXTERNAL_BASE + 4; ++i)
irq_set_chip_and_handler(i, &bcm63xx_external_irq_chip,
handle_edge_irq);
- setup_irq(IRQ_MIPS_BASE + 2, &cpu_ip2_cascade_action);
+ if (!is_ext_irq_cascaded) {
+ for (i = 3; i < 7; ++i)
+ setup_irq(MIPS_CPU_IRQ_BASE + i, &cpu_ext_cascade_action);
+ }
+
+ setup_irq(MIPS_CPU_IRQ_BASE + 2, &cpu_ip2_cascade_action);
}