diff options
author | Michael Chan <mchan@broadcom.com> | 2006-05-26 20:48:07 -0400 |
---|---|---|
committer | David S. Miller <davem@sunset.davemloft.net> | 2006-06-18 00:26:26 -0400 |
commit | df3e6548186f0baa727cd6d3a492891854bd31f2 (patch) | |
tree | 525617b51451b730b0723d57258c6a8bf7f53d09 /drivers/net/tg3.c | |
parent | 30b6c28d2aca4669f2e609ad5d77ea2a6cf0dd3a (diff) |
[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
re-ordering.
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
removed.
Signed-off-by: Michael Chan <mchan@broadcom.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/tg3.c')
-rw-r--r-- | drivers/net/tg3.c | 53 |
1 files changed, 48 insertions, 5 deletions
diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index cb0ebf83c843..9e61df607413 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c | |||
@@ -2967,6 +2967,29 @@ static int tg3_setup_phy(struct tg3 *tp, int force_reset) | |||
2967 | return err; | 2967 | return err; |
2968 | } | 2968 | } |
2969 | 2969 | ||
2970 | /* This is called whenever we suspect that the system chipset is re- | ||
2971 | * ordering the sequence of MMIO to the tx send mailbox. The symptom | ||
2972 | * is bogus tx completions. We try to recover by setting the | ||
2973 | * TG3_FLAG_MBOX_WRITE_REORDER flag and resetting the chip later | ||
2974 | * in the workqueue. | ||
2975 | */ | ||
2976 | static void tg3_tx_recover(struct tg3 *tp) | ||
2977 | { | ||
2978 | BUG_ON((tp->tg3_flags & TG3_FLAG_MBOX_WRITE_REORDER) || | ||
2979 | tp->write32_tx_mbox == tg3_write_indirect_mbox); | ||
2980 | |||
2981 | printk(KERN_WARNING PFX "%s: The system may be re-ordering memory-" | ||
2982 | "mapped I/O cycles to the network device, attempting to " | ||
2983 | "recover. Please report the problem to the driver maintainer " | ||
2984 | "and include system chipset information.\n", tp->dev->name); | ||
2985 | |||
2986 | spin_lock(&tp->lock); | ||
2987 | spin_lock(&tp->tx_lock); | ||
2988 | tp->tg3_flags |= TG3_FLAG_TX_RECOVERY_PENDING; | ||
2989 | spin_unlock(&tp->tx_lock); | ||
2990 | spin_unlock(&tp->lock); | ||
2991 | } | ||
2992 | |||
2970 | /* Tigon3 never reports partial packet sends. So we do not | 2993 | /* Tigon3 never reports partial packet sends. So we do not |
2971 | * need special logic to handle SKBs that have not had all | 2994 | * need special logic to handle SKBs that have not had all |
2972 | * of their frags sent yet, like SunGEM does. | 2995 | * of their frags sent yet, like SunGEM does. |
@@ -2979,9 +3002,13 @@ static void tg3_tx(struct tg3 *tp) | |||
2979 | while (sw_idx != hw_idx) { | 3002 | while (sw_idx != hw_idx) { |
2980 | struct tx_ring_info *ri = &tp->tx_buffers[sw_idx]; | 3003 | struct tx_ring_info *ri = &tp->tx_buffers[sw_idx]; |
2981 | struct sk_buff *skb = ri->skb; | 3004 | struct sk_buff *skb = ri->skb; |
2982 | int i; | 3005 | int i, tx_bug = 0; |
3006 | |||
3007 | if (unlikely(skb == NULL)) { | ||
3008 | tg3_tx_recover(tp); | ||
3009 | return; | ||
3010 | } | ||
2983 | 3011 | ||
2984 | BUG_ON(skb == NULL); | ||
2985 | pci_unmap_single(tp->pdev, | 3012 | pci_unmap_single(tp->pdev, |
2986 | pci_unmap_addr(ri, mapping), | 3013 | pci_unmap_addr(ri, mapping), |
2987 | skb_headlen(skb), | 3014 | skb_headlen(skb), |
@@ -2992,10 +3019,9 @@ static void tg3_tx(struct tg3 *tp) | |||
2992 | sw_idx = NEXT_TX(sw_idx); | 3019 | sw_idx = NEXT_TX(sw_idx); |
2993 | 3020 | ||
2994 | for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) { | 3021 | for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) { |
2995 | BUG_ON(sw_idx == hw_idx); | ||
2996 | |||
2997 | ri = &tp->tx_buffers[sw_idx]; | 3022 | ri = &tp->tx_buffers[sw_idx]; |
2998 | BUG_ON(ri->skb != NULL); | 3023 | if (unlikely(ri->skb != NULL || sw_idx == hw_idx)) |
3024 | tx_bug = 1; | ||
2999 | 3025 | ||
3000 | pci_unmap_page(tp->pdev, | 3026 | pci_unmap_page(tp->pdev, |
3001 | pci_unmap_addr(ri, mapping), | 3027 | pci_unmap_addr(ri, mapping), |
@@ -3006,6 +3032,11 @@ static void tg3_tx(struct tg3 *tp) | |||
3006 | } | 3032 | } |
3007 | 3033 | ||
3008 | dev_kfree_skb(skb); | 3034 | dev_kfree_skb(skb); |
3035 | |||
3036 | if (unlikely(tx_bug)) { | ||
3037 | tg3_tx_recover(tp); | ||
3038 | return; | ||
3039 | } | ||
3009 | } | 3040 | } |
3010 | 3041 | ||
3011 | tp->tx_cons = sw_idx; | 3042 | tp->tx_cons = sw_idx; |
@@ -3333,6 +3364,11 @@ static int tg3_poll(struct net_device *netdev, int *budget) | |||
3333 | /* run TX completion thread */ | 3364 | /* run TX completion thread */ |
3334 | if (sblk->idx[0].tx_consumer != tp->tx_cons) { | 3365 | if (sblk->idx[0].tx_consumer != tp->tx_cons) { |
3335 | tg3_tx(tp); | 3366 | tg3_tx(tp); |
3367 | if (unlikely(tp->tg3_flags & TG3_FLAG_TX_RECOVERY_PENDING)) { | ||
3368 | netif_rx_complete(netdev); | ||
3369 | schedule_work(&tp->reset_task); | ||
3370 | return 0; | ||
3371 | } | ||
3336 | } | 3372 | } |
3337 | 3373 | ||
3338 | /* run RX thread, within the bounds set by NAPI. | 3374 | /* run RX thread, within the bounds set by NAPI. |
@@ -3581,6 +3617,13 @@ static void tg3_reset_task(void *_data) | |||
3581 | restart_timer = tp->tg3_flags2 & TG3_FLG2_RESTART_TIMER; | 3617 | restart_timer = tp->tg3_flags2 & TG3_FLG2_RESTART_TIMER; |
3582 | tp->tg3_flags2 &= ~TG3_FLG2_RESTART_TIMER; | 3618 | tp->tg3_flags2 &= ~TG3_FLG2_RESTART_TIMER; |
3583 | 3619 | ||
3620 | if (tp->tg3_flags & TG3_FLAG_TX_RECOVERY_PENDING) { | ||
3621 | tp->write32_tx_mbox = tg3_write32_tx_mbox; | ||
3622 | tp->write32_rx_mbox = tg3_write_flush_reg32; | ||
3623 | tp->tg3_flags |= TG3_FLAG_MBOX_WRITE_REORDER; | ||
3624 | tp->tg3_flags &= ~TG3_FLAG_TX_RECOVERY_PENDING; | ||
3625 | } | ||
3626 | |||
3584 | tg3_halt(tp, RESET_KIND_SHUTDOWN, 0); | 3627 | tg3_halt(tp, RESET_KIND_SHUTDOWN, 0); |
3585 | tg3_init_hw(tp, 1); | 3628 | tg3_init_hw(tp, 1); |
3586 | 3629 | ||