When the driver is encountering EEH errors, which might be caused
by frozen PCI host controller, the driver needn't keep reading on
MMIO until timeout. For the case, 0xFF's should be returned from
hardware. Otherwise, it possibly trigger soft-lockup. The patch
adds more check on that by pci_channel_offline(), thus to avoid
the possible soft-lockup.

Signed-off-by: Gavin Shan <sha...@linux.vnet.ibm.com>
---
 drivers/net/ethernet/broadcom/tg3.c |   36 +++++++++++++++++++++++++++++++++++
 1 files changed, 36 insertions(+), 0 deletions(-)

diff --git a/drivers/net/ethernet/broadcom/tg3.c 
b/drivers/net/ethernet/broadcom/tg3.c
index c777b90..a13463e 100644
--- a/drivers/net/ethernet/broadcom/tg3.c
+++ b/drivers/net/ethernet/broadcom/tg3.c
@@ -744,6 +744,9 @@ static int tg3_ape_lock(struct tg3 *tp, int locknum)
                status = tg3_ape_read32(tp, gnt + off);
                if (status == bit)
                        break;
+               if (pci_channel_offline(tp->pdev))
+                       break;
+
                udelay(10);
        }
 
@@ -1635,6 +1638,9 @@ static void tg3_wait_for_event_ack(struct tg3 *tp)
        for (i = 0; i < delay_cnt; i++) {
                if (!(tr32(GRC_RX_CPU_EVENT) & GRC_RX_CPU_DRIVER_EVENT))
                        break;
+               if (pci_channel_offline(tp->pdev))
+                       break;
+
                udelay(8);
        }
 }
@@ -1813,6 +1819,9 @@ static int tg3_poll_fw(struct tg3 *tp)
                for (i = 0; i < 200; i++) {
                        if (tr32(VCPU_STATUS) & VCPU_STATUS_INIT_DONE)
                                return 0;
+                       if (pci_channel_offline(tp->pdev))
+                               return -ENODEV;
+
                        udelay(100);
                }
                return -ENODEV;
@@ -1823,6 +1832,15 @@ static int tg3_poll_fw(struct tg3 *tp)
                tg3_read_mem(tp, NIC_SRAM_FIRMWARE_MBOX, &val);
                if (val == ~NIC_SRAM_FIRMWARE_MBOX_MAGIC1)
                        break;
+               if (pci_channel_offline(tp->pdev)) {
+                       if (!tg3_flag(tp, NO_FWARE_REPORTED)) {
+                               tg3_flag_set(tp, NO_FWARE_REPORTED);
+                               netdev_info(tp->dev, "No firmware running\n");
+                       }
+
+                       break;
+               }
+
                udelay(10);
        }
 
@@ -3520,6 +3538,8 @@ static int tg3_pause_cpu(struct tg3 *tp, u32 cpu_base)
                tw32(cpu_base + CPU_MODE,  CPU_MODE_HALT);
                if (tr32(cpu_base + CPU_MODE) & CPU_MODE_HALT)
                        break;
+               if (pci_channel_offline(tp->pdev))
+                       return -EBUSY;
        }
 
        return (i == iters) ? -EBUSY : 0;
@@ -8589,6 +8609,14 @@ static int tg3_stop_block(struct tg3 *tp, unsigned long 
ofs, u32 enable_bit, boo
        tw32_f(ofs, val);
 
        for (i = 0; i < MAX_WAIT_CNT; i++) {
+               if (pci_channel_offline(tp->pdev)) {
+                       dev_err(&tp->pdev->dev,
+                               "tg3_stop_block device offline, "
+                               "ofs=%lx enable_bit=%x\n",
+                               ofs, enable_bit);
+                       return -ENODEV;
+               }
+
                udelay(100);
                val = tr32(ofs);
                if ((val & enable_bit) == 0)
@@ -8612,6 +8640,13 @@ static int tg3_abort_hw(struct tg3 *tp, bool silent)
 
        tg3_disable_ints(tp);
 
+       if (pci_channel_offline(tp->pdev)) {
+               tp->rx_mode &= ~(RX_MODE_ENABLE | TX_MODE_ENABLE);
+               tp->mac_mode &= ~MAC_MODE_TDE_ENABLE;
+               err = -ENODEV;
+               goto err_no_dev;
+       }
+
        tp->rx_mode &= ~RX_MODE_ENABLE;
        tw32_f(MAC_RX_MODE, tp->rx_mode);
        udelay(10);
@@ -8660,6 +8695,7 @@ static int tg3_abort_hw(struct tg3 *tp, bool silent)
        err |= tg3_stop_block(tp, BUFMGR_MODE, BUFMGR_MODE_ENABLE, silent);
        err |= tg3_stop_block(tp, MEMARB_MODE, MEMARB_MODE_ENABLE, silent);
 
+err_no_dev:
        for (i = 0; i < tp->irq_cnt; i++) {
                struct tg3_napi *tnapi = &tp->napi[i];
                if (tnapi->hw_status)
-- 
1.7.5.4

_______________________________________________
Linuxppc-dev mailing list
Linuxppc-dev@lists.ozlabs.org
https://lists.ozlabs.org/listinfo/linuxppc-dev

Reply via email to