[tulip] Re: [tulip-bug] [PATCH] check_duplex bug causes HD operation, carrier
errors
Bhavesh P. Davda
bhavesh@avaya.com
Wed Jul 10 11:35:51 2002
Just a "ping" to verify you saw this...
Thanks
- Bhavesh
--
Bhavesh P. Davda
Avaya Inc
bhavesh@avaya.com
-------- Original Message --------
Subject: Re: [tulip-bug] [PATCH] check_duplex bug causes HD operation,
carrier errors
Date: Fri, 28 Jun 2002 13:40:45 -0600
From: "Bhavesh P. Davda" <bhavesh@avaya.com>
Organization: Avaya, Inc.
To: Donald Becker <becker@scyld.com>
CC: tulip-bug@scyld.com
References: <Pine.LNX.4.33.0206281213070.1095-100000@presario>
I disagree. Yeah, though this patch restarts the transmitter every
minute, atleast it selects the right duplex setting.
The problem was: if 'tp->full_duplex' is initially set, and if the
negotiated 'duplex' is also set in check_duplex, then the code doesn't
set the FullDuplex bit in CSR6. In that case, like in the case of a
tulip_open(), CSR6 gets set to half-duplex (default setting through
init_media())
I verified this with tulip-diag, and also by setting tulip_debug=3.
As an alternative, an additional parameter could be passed to
check_duplex() to say that this is called from tulip_open(), so set the
FullDuplex bit in CSR6 if necessary, even if tp->full_duplex == duplex
Here is that alternative patch:
diff -Naur orig/tulip.c new/tulip.c
--- orig/tulip.c Thu Jun 27 15:37:41 2002
+++ new/tulip.c Fri Jun 28 13:36:15 2002
@@ -623,7 +623,7 @@
static void mdio_write(struct net_device *dev, int phy_id, int
location, int value);
static int tulip_open(struct net_device *dev);
/* Chip-specific media selection (timer functions prototyped above). */
-static int check_duplex(struct net_device *dev);
+static int check_duplex(struct net_device *dev, int startup);
static void select_media(struct net_device *dev, int startup);
static void init_media(struct net_device *dev);
static void nway_lnk_change(struct net_device *dev, int csr5);
@@ -1516,7 +1516,7 @@
tp->full_duplex = 0;
init_media(dev);
if (media_cap[dev->if_port] & MediaIsMII)
-
check_duplex(dev);
+
check_duplex(dev, 1);
set_rx_mode(dev);
/* Start the Tx to process setup frame. */
@@ -1887,7 +1887,7 @@
Return 0 if everything is OK.
Return < 0 if the transceiver is missing or has no link beat.
*/
-static int check_duplex(struct net_device *dev)
+static int check_duplex(struct net_device *dev, int startup)
{
long ioaddr = dev->base_addr;
struct tulip_private *tp = (struct tulip_private *)dev->priv;
@@ -1916,7 +1916,7 @@
duplex = ((negotiated & 0x0300) == 0x0100
|| (negotiated & 0x00C0) == 0x0040);
/* 100baseTx-FD or 10T-FD, but not 100-HD */
-
if (tp->full_duplex != duplex) {
+
if ((startup) || (tp->full_duplex != duplex)) {
tp->full_duplex = duplex;
if (negotiated & 0x0380) /* 100mbps. */
tp->csr6 &= ~0x00400000;
@@ -2079,7 +2079,7 @@
}
case 1: case 3: /* 21140, 21142 MII */
actually_mii:
-
check_duplex(dev);
+
check_duplex(dev, 0);
next_tick = 60*HZ;
break;
case 2: /* 21142 serial block has no link beat. */
@@ -2109,7 +2109,7 @@
printk(KERN_INFO"%s: N-Way autonegotiation status %8.8x, %s.\n",
dev->name, csr12, medianame[dev->if_port]);
if (media_cap[dev->if_port] & MediaIsMII) {
-
check_duplex(dev);
+
check_duplex(dev, 0);
} else if (tp->nwayset) {
/* Do not screw up a negotiated session! */
if (tp->msg_level & NETIF_MSG_TIMER)
@@ -2407,7 +2407,7 @@
int next_tick = 60*HZ;
if (media_cap[dev->if_port] & MediaIsMII) {
-
if (check_duplex(dev) > 0)
+
if (check_duplex(dev, 0) > 0)
next_tick = 3*HZ;
} else {
int csr12 = inl(ioaddr + CSR12);
@@ -2475,7 +2475,7 @@
"%4.4x.\n",
dev->name, mdio_read(dev, tp->phys[0], 1),
mdio_read(dev, tp->phys[0], 5));
-
check_duplex(dev);
+
check_duplex(dev, 0);
tp->timer.expires = jiffies + next_tick;
add_timer(&tp->timer);
}
--
Bhavesh P. Davda
Avaya Inc
bhavesh@avaya.com
Donald Becker wrote:
> On Thu, 27 Jun 2002, Bhavesh P. Davda wrote:
>
>
>>Subject: [tulip-bug] [PATCH] check_duplex bug causes HD operation,
>> carrier errors
>>
>>Finally was able to track this bug down to a fairly simple set of
>>operations:
>
>
> Errrmm, this patch stops the transmitter to change the duplex every
> timer tick.
>
> I'm not seeing the bug that this fixes.
> It appears to fix a problem where the 'tp->full_duplex' variable is
> initially set, but the chip has not been put in full duplex mode. Since
> the driver thinks the duplex setting is fine, it is never updated.
>
> This mismatch should be pretty clearly shown with tulip-diag.
>
>
>>diff -Naur orig/tulip.c new/tulip.c
>>--- orig/tulip.c Thu Jun 27 15:37:41 2002
>>+++ new/tulip.c Thu Jun 27 15:39:05 2002
>>@@ -1916,21 +1916,18 @@
>> duplex = ((negotiated & 0x0300) == 0x0100
>> || (negotiated & 0x00C0) == 0x0040);
>> /* 100baseTx-FD or 10T-FD, but not 100-HD */
>>- if (tp->full_duplex != duplex) {
>>-
tp->full_duplex = duplex;
>>-
if (negotiated & 0x0380) /* 100mbps. */
>>-
tp->csr6 &= ~0x00400000;
>>-
if (tp->full_duplex) tp->csr6 |= FullDuplex;
>>-
else tp->csr6 &= ~FullDuplex;
>>-
outl(tp->csr6 | RxOn, ioaddr + CSR6);
>>-
outl(tp->csr6 | TxOn | RxOn, ioaddr + CSR6);
>>-
if (tp->msg_level & NETIF_MSG_LINK)
>>-
printk(KERN_INFO "%s: Setting %s-duplex based on MII "
>>-
"#%d link partner capability of %4.4x.\n",
>>-
dev->name, tp->full_duplex ? "full" : "half",
>>-
tp->phys[0], mii_reg5);
>>-
return 1;
>>- }
>>+ tp->full_duplex = duplex;
>>+ if (negotiated & 0x0380) /* 100mbps. */
>>+
tp->csr6 &= ~0x00400000;
>>+ if (tp->full_duplex) tp->csr6 |= FullDuplex;
>>+ else
tp->csr6 &= ~FullDuplex;
>>+ outl(tp->csr6 | RxOn, ioaddr + CSR6);
>>+ outl(tp->csr6 | TxOn | RxOn, ioaddr + CSR6);
>>+ if (tp->msg_level & NETIF_MSG_LINK)
>>+
printk(KERN_INFO "%s: Setting %s-duplex based on MII "
>>+
"#%d link partner capability of %4.4x.\n",
>>+
dev->name, tp->full_duplex ? "full" : "half",
>>+
tp->phys[0], mii_reg5);
>> return 0;
>> }
>>
>>
>
>