[tulip-bug] [PATCH] check_duplex bug causes HD operation, carrier errors

Bhavesh P. Davda bhavesh@avaya.com
Wed Jul 10 11:35:01 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;
 >> }
 >>
 >>
 >
 >