On Sun, 2006-12-17 at 02:50 -0800, Andrew Morton wrote:
> 
> Begin forwarded message:
> 
> Date: Sun, 17 Dec 2006 02:20:59 -0800
> From: [EMAIL PROTECTED]
> To: [EMAIL PROTECTED]
> Subject: [Bugme-new] [Bug 7696] New: b44 driver doesn't work under heavy load
> 
> 
> http://bugzilla.kernel.org/show_bug.cgi?id=7696
> 
>            Summary: b44 driver doesn't work under heavy load
>     Kernel Version: 2.6.20_rc1
>             Status: NEW
>           Severity: normal
>              Owner: [EMAIL PROTECTED]
>          Submitter: [EMAIL PROTECTED]
>                 CC: [EMAIL PROTECTED]
> 
> 
> First reported as a Gentoo bug[1] I also experience this problem. Under heavy
> load (ie, downloading tarballs etc as opposed to browsing or irc) dmesg fills 
> up
> with these messages:
> 
> b44: eth0: Link is down.
> b44: eth0: Link is up at 100 Mbps, full duplex.
> b44: eth0: Flow control is off for TX and off for RX.
> 

The following patch should address the problem:

[PATCH]b44: Fix frequent link changes.

This fixes the issue of frequent link changes under heavy traffic
reported below:

http://bugzilla.kernel.org/show_bug.cgi?id=7696
https://bugzilla.redhat.com/bugzilla/show_bug.cgi?id=216338

The b44 chip occasionally needs to be reset when ISTAT_ERRORS are
encountered.  The reset sequence includes a PHY reset that will
take many seconds to complete and cause the link to go down and
up.  By skipping the PHY reset, it will greatly reduce the
interruption when ISTAT_ERRORS are encountered.

Change the full_reset parameter to reset_kind parameter in
b44_init_hw().  This will allow PHY reset to be skipped when
ISTAT_ERRORS are encountered.

Signed-off-by: Michael Chan <[EMAIL PROTECTED]>

diff --git a/drivers/net/b44.c b/drivers/net/b44.c
index 474a4e3..b67963b 100644
--- a/drivers/net/b44.c
+++ b/drivers/net/b44.c
@@ -110,6 +110,11 @@ MODULE_DEVICE_TABLE(pci, b44_pci_tbl);
 
 static void b44_halt(struct b44 *);
 static void b44_init_rings(struct b44 *);
+
+#define B44_FULL_RESET         1
+#define B44_FULL_RESET_SKIP_PHY        2
+#define B44_PARTIAL_RESET      3
+
 static void b44_init_hw(struct b44 *, int);
 
 static int dma_desc_align_mask;
@@ -882,7 +887,7 @@ static int b44_poll(struct net_device *n
                spin_lock_irq(&bp->lock);
                b44_halt(bp);
                b44_init_rings(bp);
-               b44_init_hw(bp, 1);
+               b44_init_hw(bp, B44_FULL_RESET_SKIP_PHY);
                netif_wake_queue(bp->dev);
                spin_unlock_irq(&bp->lock);
                done = 1;
@@ -952,7 +957,7 @@ static void b44_tx_timeout(struct net_de
 
        b44_halt(bp);
        b44_init_rings(bp);
-       b44_init_hw(bp, 1);
+       b44_init_hw(bp, B44_FULL_RESET);
 
        spin_unlock_irq(&bp->lock);
 
@@ -1069,7 +1074,7 @@ static int b44_change_mtu(struct net_dev
        b44_halt(bp);
        dev->mtu = new_mtu;
        b44_init_rings(bp);
-       b44_init_hw(bp, 1);
+       b44_init_hw(bp, B44_FULL_RESET);
        spin_unlock_irq(&bp->lock);
 
        b44_enable_ints(bp);
@@ -1366,12 +1371,12 @@ static int b44_set_mac_addr(struct net_d
  * packet processing.  Invoked with bp->lock held.
  */
 static void __b44_set_rx_mode(struct net_device *);
-static void b44_init_hw(struct b44 *bp, int full_reset)
+static void b44_init_hw(struct b44 *bp, int reset_kind)
 {
        u32 val;
 
        b44_chip_reset(bp);
-       if (full_reset) {
+       if (reset_kind == B44_FULL_RESET) {
                b44_phy_reset(bp);
                b44_setup_phy(bp);
        }
@@ -1388,7 +1393,10 @@ static void b44_init_hw(struct b44 *bp,
        bw32(bp, B44_TXMAXLEN, bp->dev->mtu + ETH_HLEN + 8 + RX_HEADER_LEN);
 
        bw32(bp, B44_TX_WMARK, 56); /* XXX magic */
-       if (full_reset) {
+       if (reset_kind == B44_PARTIAL_RESET) {
+               bw32(bp, B44_DMARX_CTRL, (DMARX_CTRL_ENABLE |
+                                     (bp->rx_offset << DMARX_CTRL_ROSHIFT)));
+       } else {
                bw32(bp, B44_DMATX_CTRL, DMATX_CTRL_ENABLE);
                bw32(bp, B44_DMATX_ADDR, bp->tx_ring_dma + bp->dma_offset);
                bw32(bp, B44_DMARX_CTRL, (DMARX_CTRL_ENABLE |
@@ -1399,9 +1407,6 @@ static void b44_init_hw(struct b44 *bp,
                bp->rx_prod = bp->rx_pending;
 
                bw32(bp, B44_MIB_CTRL, MIB_CTRL_CLR_ON_READ);
-       } else {
-               bw32(bp, B44_DMARX_CTRL, (DMARX_CTRL_ENABLE |
-                                     (bp->rx_offset << DMARX_CTRL_ROSHIFT)));
        }
 
        val = br32(bp, B44_ENET_CTRL);
@@ -1418,7 +1423,7 @@ static int b44_open(struct net_device *d
                goto out;
 
        b44_init_rings(bp);
-       b44_init_hw(bp, 1);
+       b44_init_hw(bp, B44_FULL_RESET);
 
        b44_check_phy(bp);
 
@@ -1627,7 +1632,7 @@ static int b44_close(struct net_device *
        netif_poll_enable(dev);
 
        if (bp->flags & B44_FLAG_WOL_ENABLE) {
-               b44_init_hw(bp, 0);
+               b44_init_hw(bp, B44_PARTIAL_RESET);
                b44_setup_wol(bp);
        }
 
@@ -1903,7 +1908,7 @@ static int b44_set_ringparam(struct net_
 
        b44_halt(bp);
        b44_init_rings(bp);
-       b44_init_hw(bp, 1);
+       b44_init_hw(bp, B44_FULL_RESET);
        netif_wake_queue(bp->dev);
        spin_unlock_irq(&bp->lock);
 
@@ -1946,7 +1951,7 @@ static int b44_set_pauseparam(struct net
        if (bp->flags & B44_FLAG_PAUSE_AUTO) {
                b44_halt(bp);
                b44_init_rings(bp);
-               b44_init_hw(bp, 1);
+               b44_init_hw(bp, B44_FULL_RESET);
        } else {
                __b44_set_flow_ctrl(bp, bp->flags);
        }
@@ -2302,7 +2307,7 @@ static int b44_suspend(struct pci_dev *p
 
        free_irq(dev->irq, dev);
        if (bp->flags & B44_FLAG_WOL_ENABLE) {
-               b44_init_hw(bp, 0);
+               b44_init_hw(bp, B44_PARTIAL_RESET);
                b44_setup_wol(bp);
        }
        pci_disable_device(pdev);
@@ -2327,7 +2332,7 @@ static int b44_resume(struct pci_dev *pd
        spin_lock_irq(&bp->lock);
 
        b44_init_rings(bp);
-       b44_init_hw(bp, 1);
+       b44_init_hw(bp, B44_FULL_RESET);
        netif_device_attach(bp->dev);
        spin_unlock_irq(&bp->lock);
 


-
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to