Modify

Opened 2 years ago

Last modified 22 months ago

#21613 new defect

brcm63xx: external IRQs broken

Reported by: dgcbueu@… Owned by: developers
Priority: high Milestone: Designated Driver (Trunk)
Component: kernel Version: Trunk
Keywords: Cc:

Description

Since Chaos Calmer version, external IRQs are broken in brcm63xx.

Previous versions of Openwrt worked quite fine

  • Attitude Adjustment: OK
  • Barrier Breaker: OK
  • Chaos Calmer: FAIL
  • trunk: FAIL

This is the snippet code I used for testing

#include <linux/kernel.h>
#include <linux/err.h>
#include <linux/module.h>
#include <linux/spinlock.h>
#include <linux/interrupt.h>
 
#include <bcm63xx_cpu.h>
#include <bcm63xx_io.h>
#include <bcm63xx_regs.h>
#include <bcm63xx_irq.h>
 
static irqreturn_t gpio_interrupt(int irq, void *dev_id)
{
	printk("my IRQ triggered!!!!\n");
	return IRQ_HANDLED;
}
 
int bcm63xx_button_init(void)
{
	int ret, irq;
 
	printk("TEST IRQ (GPIO-button)\n");
	irq = IRQ_EXT_1;
	ret = request_irq(irq, gpio_interrupt, 0, "bcm63xx_extIRQ", NULL);
	if (ret) {
		printk(KERN_ERR "bcm63xx-extIRQ: failed to register irq %d\n",irq);
		return ret;
	}
	printk("Mapped IRQ %d\n", irq );
 
	return 0;
}
 
arch_initcall(bcm63xx_button_init);

These external IRQs are commonly wired externally to some physical button on the casing, so it was very easy to test it.

I also succesfully tested a more complex driver like an Infrarred receiver:
https://github.com/danitool/openwrt-pkgs/blob/bb/lirc-bcm63xx/src/lirc_bcm63xx.c

And worked totally fine in AA and BB, but failed on CC and trunk.

In CC a new driver was introduced to manage IRQs in brcm63xx, probably this driver itself is the culprit.

The IRQ driver irq-bcm6345.ext: http://pastebin.com/DuWFq3fn

Attachments (0)

Change History (5)

comment:1 Changed 2 years ago by anonymous

In BCM6358 the situation is even worse. If I try to use external the range:

 0 <= IRQ_EXT <= 3

the board hangs at boot time. However with IRQ_EXT 4 and 5 is able to boot without problems, but they still don't work.

Maybe the IRQs are incorrectly mapped?

comment:2 Changed 2 years ago by Likharevdmitriy@…

I fixed it like this:

--- ./irq-bcm6345-ext.c	2016-03-03 02:41:57.312097733 +0500
+++ ./irq-bcm6345-ext-patched.c	2016-03-03 02:23:10.538692292 +0500
@@ -16,6 +16,7 @@
 #include <linux/of_address.h>
 #include <linux/slab.h>
 #include <linux/spinlock.h>
+#include <bcm63xx_io.h>
 
 #include "irqchip.h"
 
@@ -71,9 +72,9 @@ static void bcm6345_ext_intc_irq_ack(str
 	u32 reg;
 
 	raw_spin_lock(&priv->lock);
-	reg = __raw_readl(priv->reg);
-	reg |= hwirq << (EXTIRQ_CFG_CLEAR * priv->shift);
-	__raw_writel(reg, priv->reg);
+	reg = bcm_readl(priv->reg);
+	reg |= 1 << (hwirq + EXTIRQ_CFG_CLEAR * priv->shift);
+	bcm_writel(reg, priv->reg);
 	raw_spin_unlock(&priv->lock);
 }
 
@@ -84,9 +85,9 @@ static void bcm6345_ext_intc_irq_mask(st
 	u32 reg;
 
 	raw_spin_lock(&priv->lock);
-	reg = __raw_readl(priv->reg);
-	reg &= ~(hwirq << (EXTIRQ_CFG_MASK * priv->shift));
-	__raw_writel(reg, priv->reg);
+	reg = bcm_readl(priv->reg);
+	reg &= ~(1 << (hwirq + EXTIRQ_CFG_MASK * priv->shift));
+	bcm_writel(reg, priv->reg);
 	raw_spin_unlock(&priv->lock);
 }
 
@@ -97,9 +98,9 @@ static void bcm6345_ext_intc_irq_unmask(
 	u32 reg;
 
 	raw_spin_lock(&priv->lock);
-	reg = __raw_readl(priv->reg);
-	reg |= hwirq << (EXTIRQ_CFG_MASK * priv->shift);
-	__raw_writel(reg, priv->reg);
+	reg = bcm_readl(priv->reg);
+	reg |= 1 << (hwirq + EXTIRQ_CFG_MASK * priv->shift);
+	bcm_writel(reg, priv->reg);
 	raw_spin_unlock(&priv->lock);
 }
 
@@ -143,22 +144,22 @@ static int bcm6345_ext_intc_set_type(str
 	}
 
 	raw_spin_lock(&priv->lock);
-	reg = __raw_readl(priv->reg);
+	reg = bcm_readl(priv->reg);
 
 	if (levelsense)
-		reg |= hwirq << (EXTIRQ_CFG_LEVELSENSE * priv->shift);
+		reg |= 1 << (hwirq + EXTIRQ_CFG_LEVELSENSE * priv->shift);
 	else
-		reg &= ~(hwirq << (EXTIRQ_CFG_LEVELSENSE * priv->shift));
+		reg &= ~(1 << (hwirq + EXTIRQ_CFG_LEVELSENSE * priv->shift));
 	if (sense)
-		reg |= hwirq << (EXTIRQ_CFG_SENSE * priv->shift);
+		reg |= 1 << (hwirq + EXTIRQ_CFG_SENSE * priv->shift);
 	else
-		reg &= ~(hwirq << (EXTIRQ_CFG_SENSE * priv->shift));
+		reg &= ~(1 << (hwirq + EXTIRQ_CFG_SENSE * priv->shift));
 	if (bothedge)
-		reg |= hwirq << (EXTIRQ_CFG_BOTHEDGE * priv->shift);
+		reg |= 1 << (hwirq + EXTIRQ_CFG_BOTHEDGE * priv->shift);
 	else
-		reg &= ~(hwirq << (EXTIRQ_CFG_BOTHEDGE * priv->shift));
+		reg &= ~(1 << (hwirq + EXTIRQ_CFG_BOTHEDGE * priv->shift));
 
-	__raw_writel(reg, priv->reg);
+	bcm_writel(reg, priv->reg);
 	raw_spin_unlock(&priv->lock);
 
 	irqd_set_trigger_type(data, flow_type);
@@ -208,6 +209,7 @@ static int __init __bcm6345_ext_intc_ini
 
 	data->reg = reg;
 
+	data->shift = shift;
 	data->chip.name = "bcm6345-ext-intc";
 	data->chip.irq_ack = bcm6345_ext_intc_irq_ack;
 	data->chip.irq_mask = bcm6345_ext_intc_irq_mask;

tested on bcm6328

comment:3 Changed 2 years ago by likharevdmitriy@…

upd: for some reason works in Chaos Calmer but fail in trunk

comment:4 Changed 23 months ago by dgcbueu@…

Hi likharevdmitriy, I tested your patch in a BCM6348 based board and it works like a charm.

I made the dumb test printing something on the console, and also tested the LIRC driver. Both working ok in Chaos Calmer.

I didn't make any test in trunk. But it's great to have this fix at least in Chaos calmer.

Thanks very much.
Regards.

comment:5 Changed 22 months ago by dgcbueu@…

For Openwrt trunk last revision I've tested this variation of the patch in BCM6348 with success:

--- a/drivers/irqchip/irq-bcm6345-ext.c
+++ b/drivers/irqchip/irq-bcm6345-ext.c
@@ -72,7 +72,7 @@
 
 	raw_spin_lock(&priv->lock);
 	reg = __raw_readl(priv->reg);
-	reg |= hwirq << (EXTIRQ_CFG_CLEAR * priv->shift);
+	reg |= 1 << (hwirq + EXTIRQ_CFG_CLEAR * priv->shift);
 	__raw_writel(reg, priv->reg);
 	raw_spin_unlock(&priv->lock);
 }
@@ -85,7 +85,7 @@
 
 	raw_spin_lock(&priv->lock);
 	reg = __raw_readl(priv->reg);
-	reg &= ~(hwirq << (EXTIRQ_CFG_MASK * priv->shift));
+	reg &= ~(1 << (hwirq + EXTIRQ_CFG_MASK * priv->shift));
 	__raw_writel(reg, priv->reg);
 	raw_spin_unlock(&priv->lock);
 }
@@ -98,7 +98,7 @@
 
 	raw_spin_lock(&priv->lock);
 	reg = __raw_readl(priv->reg);
-	reg |= hwirq << (EXTIRQ_CFG_MASK * priv->shift);
+	reg |= 1 << (hwirq + EXTIRQ_CFG_MASK * priv->shift);
 	__raw_writel(reg, priv->reg);
 	raw_spin_unlock(&priv->lock);
 }
@@ -146,17 +146,17 @@
 	reg = __raw_readl(priv->reg);
 
 	if (levelsense)
-		reg |= hwirq << (EXTIRQ_CFG_LEVELSENSE * priv->shift);
+		reg |= 1 << (hwirq + EXTIRQ_CFG_LEVELSENSE * priv->shift);
 	else
-		reg &= ~(hwirq << (EXTIRQ_CFG_LEVELSENSE * priv->shift));
+		reg &= ~(1 << (hwirq + EXTIRQ_CFG_LEVELSENSE * priv->shift));
 	if (sense)
-		reg |= hwirq << (EXTIRQ_CFG_SENSE * priv->shift);
+		reg |= 1 << (hwirq + EXTIRQ_CFG_SENSE * priv->shift);
 	else
-		reg &= ~(hwirq << (EXTIRQ_CFG_SENSE * priv->shift));
+		reg &= ~(1 << (hwirq + EXTIRQ_CFG_SENSE * priv->shift));
 	if (bothedge)
-		reg |= hwirq << (EXTIRQ_CFG_BOTHEDGE * priv->shift);
+		reg |= 1 << (hwirq + EXTIRQ_CFG_BOTHEDGE * priv->shift);
 	else
-		reg &= ~(hwirq << (EXTIRQ_CFG_BOTHEDGE * priv->shift));
+		reg &= ~(1 << (hwirq + EXTIRQ_CFG_BOTHEDGE * priv->shift));
 
 	__raw_writel(reg, priv->reg);
 	raw_spin_unlock(&priv->lock);

Add Comment

Modify Ticket

Action
as new .
Author


E-mail address and user name can be saved in the Preferences.

 
Note: See TracTickets for help on using tickets.