summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStephen Hemminger <shemminger@osdl.org>2006-03-20 23:48:22 (GMT)
committerJeff Garzik <jeff@garzik.org>2006-03-21 21:00:53 (GMT)
commitd257924e85a81561a956f1791fa5a226e3a32ce1 (patch)
tree4632372160838e2a878f9f1edf0d34b0da06d49c
parent8f24664da64f8db094cd9d379b16fc1d8776d1df (diff)
downloadlinux-d257924e85a81561a956f1791fa5a226e3a32ce1.tar.xz
[PATCH] sky2: handle all error irqs
The hardware has additional error trap interrupt bits. I have never seen them trigger, but if they do, it looks like this might be useful. Signed-off-by: Stephen Hemminger <shemminger@osdl.rog> Signed-off-by: Jeff Garzik <jeff@garzik.org>
-rw-r--r--drivers/net/sky2.c55
-rw-r--r--drivers/net/sky2.h6
2 files changed, 49 insertions, 12 deletions
diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c
index ab36a74..380bb59 100644
--- a/drivers/net/sky2.c
+++ b/drivers/net/sky2.c
@@ -2066,6 +2066,27 @@ static void sky2_mac_intr(struct sky2_hw *hw, unsigned port)
}
}
+/* This should never happen it is a fatal situation */
+static void sky2_descriptor_error(struct sky2_hw *hw, unsigned port,
+ const char *rxtx, u32 mask)
+{
+ struct net_device *dev = hw->dev[port];
+ struct sky2_port *sky2 = netdev_priv(dev);
+ u32 imask;
+
+ printk(KERN_ERR PFX "%s: %s descriptor error (hardware problem)\n",
+ dev ? dev->name : "<not registered>", rxtx);
+
+ imask = sky2_read32(hw, B0_IMSK);
+ imask &= ~mask;
+ sky2_write32(hw, B0_IMSK, imask);
+
+ if (dev) {
+ spin_lock(&sky2->phy_lock);
+ sky2_link_down(sky2);
+ spin_unlock(&sky2->phy_lock);
+ }
+}
static int sky2_poll(struct net_device *dev0, int *budget)
{
@@ -2074,20 +2095,34 @@ static int sky2_poll(struct net_device *dev0, int *budget)
int work_done = 0;
u32 status = sky2_read32(hw, B0_Y2_SP_EISR);
- if (status & Y2_IS_HW_ERR)
- sky2_hw_intr(hw);
+ if (unlikely(status & ~Y2_IS_STAT_BMU)) {
+ if (status & Y2_IS_HW_ERR)
+ sky2_hw_intr(hw);
+
+ if (status & Y2_IS_IRQ_PHY1)
+ sky2_phy_intr(hw, 0);
- if (status & Y2_IS_IRQ_PHY1)
- sky2_phy_intr(hw, 0);
+ if (status & Y2_IS_IRQ_PHY2)
+ sky2_phy_intr(hw, 1);
- if (status & Y2_IS_IRQ_PHY2)
- sky2_phy_intr(hw, 1);
+ if (status & Y2_IS_IRQ_MAC1)
+ sky2_mac_intr(hw, 0);
- if (status & Y2_IS_IRQ_MAC1)
- sky2_mac_intr(hw, 0);
+ if (status & Y2_IS_IRQ_MAC2)
+ sky2_mac_intr(hw, 1);
- if (status & Y2_IS_IRQ_MAC2)
- sky2_mac_intr(hw, 1);
+ if (status & Y2_IS_CHK_RX1)
+ sky2_descriptor_error(hw, 0, "receive", Y2_IS_CHK_RX1);
+
+ if (status & Y2_IS_CHK_RX2)
+ sky2_descriptor_error(hw, 1, "receive", Y2_IS_CHK_RX2);
+
+ if (status & Y2_IS_CHK_TXA1)
+ sky2_descriptor_error(hw, 0, "transmit", Y2_IS_CHK_TXA1);
+
+ if (status & Y2_IS_CHK_TXA2)
+ sky2_descriptor_error(hw, 1, "transmit", Y2_IS_CHK_TXA2);
+ }
if (status & Y2_IS_STAT_BMU) {
work_done = sky2_status_intr(hw, work_limit);
diff --git a/drivers/net/sky2.h b/drivers/net/sky2.h
index 50e9f7d..d63cd5a 100644
--- a/drivers/net/sky2.h
+++ b/drivers/net/sky2.h
@@ -279,8 +279,10 @@ enum {
Y2_IS_CHK_TXA1 = 1<<0, /* Descriptor error TXA 1 */
Y2_IS_BASE = Y2_IS_HW_ERR | Y2_IS_STAT_BMU,
- Y2_IS_PORT_1 = Y2_IS_IRQ_PHY1 | Y2_IS_IRQ_MAC1,
- Y2_IS_PORT_2 = Y2_IS_IRQ_PHY2 | Y2_IS_IRQ_MAC2,
+ Y2_IS_PORT_1 = Y2_IS_IRQ_PHY1 | Y2_IS_IRQ_MAC1
+ | Y2_IS_CHK_TXA1 | Y2_IS_CHK_RX1,
+ Y2_IS_PORT_2 = Y2_IS_IRQ_PHY2 | Y2_IS_IRQ_MAC2
+ | Y2_IS_CHK_TXA2 | Y2_IS_CHK_RX2,
};
/* B2_IRQM_HWE_MSK 32 bit IRQ Moderation HW Error Mask */