The TX timeout handling has been observed to trigger RX IRQ storms. And
since cp_interrupt() just keeps saying that it handled the interrupt,
the machine then dies. Fix the return value from cp_interrupt(), and
the offending IRQ gets disabled and the machine survives.

Signed-off-by: David Woodhouse <david.woodho...@intel.com>
---
... and I have to make fewer trips to the cupboard under the stairs.
There follows a fix to prevent the IRQ storm from happening at all.

 drivers/net/ethernet/realtek/8139cp.c | 25 ++++++++++++++++---------
 1 file changed, 16 insertions(+), 9 deletions(-)

diff --git a/drivers/net/ethernet/realtek/8139cp.c 
b/drivers/net/ethernet/realtek/8139cp.c
index ba3dab7..f1054ad 100644
--- a/drivers/net/ethernet/realtek/8139cp.c
+++ b/drivers/net/ethernet/realtek/8139cp.c
@@ -371,7 +371,7 @@ struct cp_private {
 
 
 static void __cp_set_rx_mode (struct net_device *dev);
-static void cp_tx (struct cp_private *cp);
+static int cp_tx (struct cp_private *cp);
 static void cp_clean_rings (struct cp_private *cp);
 #ifdef CONFIG_NET_POLL_CONTROLLER
 static void cp_poll_controller(struct net_device *dev);
@@ -587,8 +587,6 @@ static irqreturn_t cp_interrupt (int irq, void 
*dev_instance)
        if (!status || (status == 0xFFFF))
                goto out_unlock;
 
-       handled = 1;
-
        netif_dbg(cp, intr, dev, "intr, status %04x cmd %02x cpcmd %04x\n",
                  status, cpr8(Cmd), cpr16(CpCmd));
 
@@ -596,25 +594,30 @@ static irqreturn_t cp_interrupt (int irq, void 
*dev_instance)
 
        /* close possible race's with dev_close */
        if (unlikely(!netif_running(dev))) {
+               handled = 1;
                cpw16(IntrMask, 0);
                goto out_unlock;
        }
 
-       if (status & (RxOK | RxErr | RxEmpty | RxFIFOOvr))
+       if (status & (RxOK | RxErr | RxEmpty | RxFIFOOvr)) {
                if (napi_schedule_prep(&cp->napi)) {
+                       handled = 1;
                        cpw16_f(IntrMask, cp_norx_intr_mask);
                        __napi_schedule(&cp->napi);
                }
-
+       }
        if (status & (TxOK | TxErr | TxEmpty | SWInt))
-               cp_tx(cp);
-       if (status & LinkChg)
-               mii_check_media(&cp->mii_if, netif_msg_link(cp), false);
+               handled |= cp_tx(cp);
 
+       if (status & LinkChg) {
+               handled = 1;
+               mii_check_media(&cp->mii_if, netif_msg_link(cp), false);
+       }
 
        if (status & PciErr) {
                u16 pci_status;
 
+               handled = 1;
                pci_read_config_word(cp->pdev, PCI_STATUS, &pci_status);
                pci_write_config_word(cp->pdev, PCI_STATUS, pci_status);
                netdev_err(dev, "PCI bus error, status=%04x, PCI status=%04x\n",
@@ -645,11 +648,12 @@ static void cp_poll_controller(struct net_device *dev)
 }
 #endif
 
-static void cp_tx (struct cp_private *cp)
+static int cp_tx (struct cp_private *cp)
 {
        unsigned tx_head = cp->tx_head;
        unsigned tx_tail = cp->tx_tail;
        unsigned bytes_compl = 0, pkts_compl = 0;
+       int handled = 0;
 
        while (tx_tail != tx_head) {
                struct cp_desc *txd = cp->tx_ring + tx_tail;
@@ -661,6 +665,7 @@ static void cp_tx (struct cp_private *cp)
                if (status & DescOwn)
                        break;
 
+               handled = 1;
                skb = cp->tx_skb[tx_tail];
                BUG_ON(!skb);
 
@@ -704,6 +709,8 @@ static void cp_tx (struct cp_private *cp)
        netdev_completed_queue(cp->dev, pkts_compl, bytes_compl);
        if (TX_BUFFS_AVAIL(cp) > (MAX_SKB_FRAGS + 1))
                netif_wake_queue(cp->dev);
+
+       return handled;
 }
 
 static inline u32 cp_tx_vlan_tag(struct sk_buff *skb)
-- 
2.4.3

-- 
David Woodhouse                            Open Source Technology Centre
david.woodho...@intel.com                              Intel Corporation

Attachment: smime.p7s
Description: S/MIME cryptographic signature

Reply via email to