Commit df3e6548 authored by Michael Chan's avatar Michael Chan Committed by David S. Miller
Browse files

[TG3]: Add recovery logic when MMIOs are re-ordered

Add recovery logic when we suspect that the system is re-ordering
MMIOs. Re-ordered MMIOs to the send mailbox can cause bogus tx
completions and hit BUG_ON() in the tx completion path.

tg3 already has logic to handle re-ordered MMIOs by flushing the MMIOs
that must be strictly ordered (such as the send mailbox).  Determining
when to enable the flush is currently a manual process of adding known
chipsets to a list.

The new code replaces the BUG_ON() in the tx completion path with the
call to tg3_tx_recover(). It will set the TG3_FLAG_MBOX_WRITE_REORDER
flag and reset the chip later in the workqueue to recover and start
flushing MMIOs to the mailbox.

A message to report the problem will be printed. We will then decide
whether or not to add the host bridge to the list of chipsets that do

We may add some additional code later to print the host bridge's ID so
that the user can report it more easily.

The assumption that re-ordering can only happen on x86 systems is also
Signed-off-by: default avatarMichael Chan <>
Signed-off-by: default avatarDavid S. Miller <>
parent 30b6c28d
......@@ -2967,6 +2967,29 @@ static int tg3_setup_phy(struct tg3 *tp, int force_reset)
return err;
/* This is called whenever we suspect that the system chipset is re-
* ordering the sequence of MMIO to the tx send mailbox. The symptom
* is bogus tx completions. We try to recover by setting the
* TG3_FLAG_MBOX_WRITE_REORDER flag and resetting the chip later
* in the workqueue.
static void tg3_tx_recover(struct tg3 *tp)
BUG_ON((tp->tg3_flags & TG3_FLAG_MBOX_WRITE_REORDER) ||
tp->write32_tx_mbox == tg3_write_indirect_mbox);
printk(KERN_WARNING PFX "%s: The system may be re-ordering memory-"
"mapped I/O cycles to the network device, attempting to "
"recover. Please report the problem to the driver maintainer "
"and include system chipset information.\n", tp->dev->name);
tp->tg3_flags |= TG3_FLAG_TX_RECOVERY_PENDING;
/* Tigon3 never reports partial packet sends. So we do not
* need special logic to handle SKBs that have not had all
* of their frags sent yet, like SunGEM does.
......@@ -2979,9 +3002,13 @@ static void tg3_tx(struct tg3 *tp)
while (sw_idx != hw_idx) {
struct tx_ring_info *ri = &tp->tx_buffers[sw_idx];
struct sk_buff *skb = ri->skb;
int i;
int i, tx_bug = 0;
if (unlikely(skb == NULL)) {
BUG_ON(skb == NULL);
pci_unmap_addr(ri, mapping),
......@@ -2992,10 +3019,9 @@ static void tg3_tx(struct tg3 *tp)
sw_idx = NEXT_TX(sw_idx);
for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
BUG_ON(sw_idx == hw_idx);
ri = &tp->tx_buffers[sw_idx];
BUG_ON(ri->skb != NULL);
if (unlikely(ri->skb != NULL || sw_idx == hw_idx))
tx_bug = 1;
pci_unmap_addr(ri, mapping),
......@@ -3006,6 +3032,11 @@ static void tg3_tx(struct tg3 *tp)
if (unlikely(tx_bug)) {
tp->tx_cons = sw_idx;
......@@ -3333,6 +3364,11 @@ static int tg3_poll(struct net_device *netdev, int *budget)
/* run TX completion thread */
if (sblk->idx[0].tx_consumer != tp->tx_cons) {
if (unlikely(tp->tg3_flags & TG3_FLAG_TX_RECOVERY_PENDING)) {
return 0;
/* run RX thread, within the bounds set by NAPI.
......@@ -3581,6 +3617,13 @@ static void tg3_reset_task(void *_data)
restart_timer = tp->tg3_flags2 & TG3_FLG2_RESTART_TIMER;
tp->tg3_flags2 &= ~TG3_FLG2_RESTART_TIMER;
if (tp->tg3_flags & TG3_FLAG_TX_RECOVERY_PENDING) {
tp->write32_tx_mbox = tg3_write32_tx_mbox;
tp->write32_rx_mbox = tg3_write_flush_reg32;
tp->tg3_flags |= TG3_FLAG_MBOX_WRITE_REORDER;
tp->tg3_flags &= ~TG3_FLAG_TX_RECOVERY_PENDING;
tg3_halt(tp, RESET_KIND_SHUTDOWN, 0);
tg3_init_hw(tp, 1);
......@@ -2155,11 +2155,7 @@ struct tg3 {
#define TG3_FLAG_ENABLE_ASF 0x00000020
#define TG3_FLAG_5701_REG_WRITE_BUG 0x00000040
#define TG3_FLAG_POLL_SERDES 0x00000080
#if defined(CONFIG_X86)
#define TG3_FLAG_MBOX_WRITE_REORDER 0x00000100
#define TG3_FLAG_MBOX_WRITE_REORDER 0 /* disables code too */
#define TG3_FLAG_PCIX_TARGET_HWBUG 0x00000200
#define TG3_FLAG_WOL_SPEED_100MB 0x00000400
#define TG3_FLAG_WOL_ENABLE 0x00000800
......@@ -2172,6 +2168,7 @@ struct tg3 {
#define TG3_FLAG_PCI_HIGH_SPEED 0x00040000
#define TG3_FLAG_PCI_32BIT 0x00080000
#define TG3_FLAG_SRAM_USE_CONFIG 0x00100000
#define TG3_FLAG_TX_RECOVERY_PENDING 0x00200000
#define TG3_FLAG_SERDES_WOL_CAP 0x00400000
#define TG3_FLAG_JUMBO_RING_ENABLE 0x00800000
#define TG3_FLAG_10_100_ONLY 0x01000000
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment