Skip to content

Commit

Permalink
net/tg3: Avoid delay during MMIO access
Browse files Browse the repository at this point in the history
When the EEH error is the result of a fenced host bridge, MMIO accesses
can be very slow (milliseconds) to timeout and return all 1's,
thus causing the driver various timeout loops to take way too long and
trigger soft-lockup warnings (in addition to taking minutes to recover).

It might be worthwhile to check if for any of these cases, ffffffff is
a valid possible value, and if not, bail early since that means the HW
is either gone or isolated. In the meantime, checking that the PCI channel
is offline would be workaround of the problem.

Cc: <stable@vger.kernel.org> # v3.0+
Signed-off-by: Gavin Shan <shangw@linux.vnet.ibm.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
Gavin Shan authored and David S. Miller committed Jun 26, 2013
1 parent dc84829 commit 6d446ec
Showing 1 changed file with 36 additions and 0 deletions.
36 changes: 36 additions & 0 deletions drivers/net/ethernet/broadcom/tg3.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}

Expand Down Expand Up @@ -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);
}
}
Expand Down Expand Up @@ -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;
Expand All @@ -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);
}

Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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)
Expand All @@ -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);
Expand Down Expand Up @@ -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)
Expand Down

0 comments on commit 6d446ec

Please sign in to comment.