Rost, Martin
2014-05-08 06:33:52 UTC
The mcp2515 sometimes seems to trigger an interrupt with the corresponding register not being set yet.
This makes the driver exit the interrupt because there is obviously nothing to do, but the interrupt line is kept low.
Therefore the driver does not see any more interrupts until the chip is reset (via interface down/up).
This patch changes the IST to first check the IRQ registers, and wait up to 10 ms if an event really occurrs.
If the IRQ register is still empty after 10ms, a kernel message gets issued.
The IST loop is rearranged to evaluate the IRQ register at the last moment before exiting, to not miss a late irq event.
---
diff --git "a/mcp251x.c" "b/mcp251x.c"
index ad58ac6..668ce63 100644
--- "a/mcp251x.c"
+++ "b/mcp251x.c"
@@ -806,15 +806,29 @@ static irqreturn_t mcp251x_can_ist(int irq, void *dev_id)
struct mcp251x_priv *priv = dev_id;
struct spi_device *spi = priv->spi;
struct net_device *net = priv->net;
+ u8 intf, eflag;
+ u8 retrycount = 10;
mutex_lock(&priv->mcp_lock);
- while (!priv->force_quit) {
+
+ do {
+ mcp251x_read_2regs(spi, CANINTF, &intf, &eflag);
+ if (!intf) {
+// printk(KERN_CRIT "MCP251x: IRQ delaying.\r\n");
+ mdelay(1);
+ }
+ } while (!intf && (retrycount--));
+
+ if (!intf)
+ printk(KERN_CRIT "MCP251x: IRQ without a cause.\r\n");
+
+ while ((!priv->force_quit) && (intf)) {
enum can_state new_state;
- u8 intf, eflag;
+// u8 intf, eflag;
u8 clear_intf = 0;
int can_id = 0, data1 = 0;
- mcp251x_read_2regs(spi, CANINTF, &intf, &eflag);
+// mcp251x_read_2regs(spi, CANINTF, &intf, &eflag);
/* mask out flags we don't care about */
intf &= CANINTF_RX | CANINTF_TX | CANINTF_ERR;
@@ -913,8 +927,8 @@ static irqreturn_t mcp251x_can_ist(int irq, void *dev_id)
}
}
- if (intf == 0)
- break;
+// if (intf == 0)
+// break;
if (intf & CANINTF_TX) {
net->stats.tx_packets++;
@@ -926,6 +940,7 @@ static irqreturn_t mcp251x_can_ist(int irq, void *dev_id)
netif_wake_queue(net);
}
+ mcp251x_read_2regs(spi, CANINTF, &intf, &eflag);
}
mutex_unlock(&priv->mcp_lock);
return IRQ_HANDLED;
---
This makes the driver exit the interrupt because there is obviously nothing to do, but the interrupt line is kept low.
Therefore the driver does not see any more interrupts until the chip is reset (via interface down/up).
This patch changes the IST to first check the IRQ registers, and wait up to 10 ms if an event really occurrs.
If the IRQ register is still empty after 10ms, a kernel message gets issued.
The IST loop is rearranged to evaluate the IRQ register at the last moment before exiting, to not miss a late irq event.
---
diff --git "a/mcp251x.c" "b/mcp251x.c"
index ad58ac6..668ce63 100644
--- "a/mcp251x.c"
+++ "b/mcp251x.c"
@@ -806,15 +806,29 @@ static irqreturn_t mcp251x_can_ist(int irq, void *dev_id)
struct mcp251x_priv *priv = dev_id;
struct spi_device *spi = priv->spi;
struct net_device *net = priv->net;
+ u8 intf, eflag;
+ u8 retrycount = 10;
mutex_lock(&priv->mcp_lock);
- while (!priv->force_quit) {
+
+ do {
+ mcp251x_read_2regs(spi, CANINTF, &intf, &eflag);
+ if (!intf) {
+// printk(KERN_CRIT "MCP251x: IRQ delaying.\r\n");
+ mdelay(1);
+ }
+ } while (!intf && (retrycount--));
+
+ if (!intf)
+ printk(KERN_CRIT "MCP251x: IRQ without a cause.\r\n");
+
+ while ((!priv->force_quit) && (intf)) {
enum can_state new_state;
- u8 intf, eflag;
+// u8 intf, eflag;
u8 clear_intf = 0;
int can_id = 0, data1 = 0;
- mcp251x_read_2regs(spi, CANINTF, &intf, &eflag);
+// mcp251x_read_2regs(spi, CANINTF, &intf, &eflag);
/* mask out flags we don't care about */
intf &= CANINTF_RX | CANINTF_TX | CANINTF_ERR;
@@ -913,8 +927,8 @@ static irqreturn_t mcp251x_can_ist(int irq, void *dev_id)
}
}
- if (intf == 0)
- break;
+// if (intf == 0)
+// break;
if (intf & CANINTF_TX) {
net->stats.tx_packets++;
@@ -926,6 +940,7 @@ static irqreturn_t mcp251x_can_ist(int irq, void *dev_id)
netif_wake_queue(net);
}
+ mcp251x_read_2regs(spi, CANINTF, &intf, &eflag);
}
mutex_unlock(&priv->mcp_lock);
return IRQ_HANDLED;
---