Skip site navigation (1)Skip section navigation (2)
Date:      Sun, 1 Feb 1998 23:37:34 -0700 (MST)
From:      Steve Bauer <sbauer@hardrock.sdsmt.edu>
To:        FreeBSD-gnats-submit@FreeBSD.ORG
Subject:   kern/5625: SMC9432 device driver update
Message-ID:  <199802020637.XAA00771@hardrock.sdsmt.edu>

next in thread | raw e-mail | index | archive | help

>Number:         5625
>Category:       kern
>Synopsis:       Added support for full Auto-negotiation & fixed netcard lockups
>Confidential:   no
>Severity:       serious
>Priority:       high
>Responsible:    freebsd-bugs
>State:          open
>Quarter:
>Keywords:
>Date-Required:
>Class:          sw-bug
>Submitter-Id:   current-users
>Arrival-Date:   Sun Feb  1 22:40:00 PST 1998
>Last-Modified:
>Originator:     Steve Bauer
>Organization:
South Dakota School of Mines and Technology
>Release:        FreeBSD 3.0-CURRENT i386
>Environment:

		The machine is running FreeBSD 3.0-CURRENT that was cvsuped
	at 8:30pm MST.

>Description:

 	1) The driver for the SMC9432 does not support auto-negotiation of
the duplex that the netcard ran at.  It, the netcard, would lock up every
once in a while.
	2) Changing states of the card would cause the auto-negotiation code
to be re run when the card was already transmitting.
	3) FIFO could overflow if the pci bus was not able to respond to a
request fast enough.

>How-To-Repeat:

	1) It would not auto-negotiate Full-duplex connections.

	2) Starting mrouted was cause a change in the flags and thus
	the driver would re negotiated the connection twice. 

	3) The default for the smc83c170 chip is for the FIFO to be half
full, 64, not the full 128.
	

	
>Fix:
	
	Below are the patches to if_tx.c and smc83c170.h to fix the above 
problems and full auto-negotiation support to the driver.  
	The majority of the patches below are to add the auto-negotiation
support to the driver.  The deletions of the calls to epic_set_rx_mode and
 epic_set_media_speed at lines 139+ of if_tx.c fix the problem of the smc9432  
locking up.  The reason these lines caused the problem was that the card 
was already receiving & transmitting data -- one is not allowed to change 
those parameters while the card is transmitting & receiving data.


*** if_tx.c.orig	Sun Feb  1 20:32:09 1998
--- if_tx.c	Sun Feb  1 23:18:08 1998
***************
*** 79,84 ****
--- 79,85 ----
  #include <netinet/if_ether.h>
  #include <vm/vm.h>
  #include <vm/pmap.h>
+ #include <machine/clock.h>
  
  #include <pci/pcivar.h>
  #include <pci/smc83c170.h>
***************
*** 135,146 ****
  			}
  		}
  
- 		/* Update RXCON register */
- 		epic_set_rx_mode( sc );
- 
- 		/* Update SPEED */
- 		epic_set_media_speed( sc );
- 
  		break;
  
  	case SIOCADDMULTI:
--- 136,141 ----
***************
*** 750,756 ****
  	/* Enable interrupts,  set for PCI read multiple and etc */
  	outl( iobase + GENCTL,
  		GENCTL_ENABLE_INTERRUPT | GENCTL_MEMORY_READ_MULTIPLE |
! 		GENCTL_ONECOPY | GENCTL_RECEIVE_FIFO_THRESHOLD128 );
  
  	/* Set transmit threshold */
  	outl( iobase + ETXTHR, 0x40 );
--- 745,751 ----
  	/* Enable interrupts,  set for PCI read multiple and etc */
  	outl( iobase + GENCTL,
  		GENCTL_ENABLE_INTERRUPT | GENCTL_MEMORY_READ_MULTIPLE |
! 		GENCTL_ONECOPY | GENCTL_RECEIVE_FIFO_THRESHOLD64 );
  
  	/* Set transmit threshold */
  	outl( iobase + ETXTHR, 0x40 );
***************
*** 850,871 ****
  
  		outl( sc->iobase + TXCON, TXCON_DEFAULT );
  
! 		/* Does not allow to autoneg fullduplex modes */
! 		media = epic_read_phy_register( sc->iobase, DP83840_ANAR );
! 		media &= ~(ANAR_100|ANAR_100_FD|ANAR_10_FD|ANAR_10);
! 		media |= ANAR_100|ANAR_10;
! 		epic_write_phy_register( sc->iobase, DP83840_ANAR, media );
  
! 		/* Set and restart autoneg */
! 		epic_write_phy_register( sc->iobase, DP83840_BMCR,
! 			BMCR_AUTONEGOTIATION | BMCR_RESTART_AUTONEG );
  
  #if defined(EPIC_DEBUG)
! 		printf("tx%d: Autonegotiation\n",sc->unit);
! #endif
  	}
  
  	return;
  }
  
  /*
--- 845,960 ----
  
  		outl( sc->iobase + TXCON, TXCON_DEFAULT );
  
! #if defined(EPIC_DEBUG)
! 		printf("tx%d: Autonegotiation\n",sc->unit);
! #endif*/
  
! 		/*Did it autoneg full duplex?*/
! 		if (epic_autoneg(sc) == EPIC_FULL_DUPLEX){
! 			outl( sc->iobase + TXCON,TXCON_LOOPBACK_MODE_FULL_DUPLEX|TXCON_DEFAULT);
  
  #if defined(EPIC_DEBUG)
! 		printf("tx%d: Autonegotiation of Full-Duplex\n",sc->unit);
! #endif/
! 		}
  	}
  
  	return;
+ }
+ 
+ /*
+  * This functions controls the autoneg processes of the phy
+  * It implements the workaround that is described in section 7.2 & 7.3 of the 
+  * DP83840A data sheet
+  * http://www.national.com/ds/DP/DP83840A.pdf
+  */
+ static int 
+ epic_autoneg(
+     epic_softc_t * sc)
+ {
+ 	struct ifnet *ifp = &sc->epic_if;
+ 	u_int16_t media;
+ 	u_int16_t i;
+ 
+ 	media = epic_read_phy_register( sc->iobase, DP83840_ANAR );
+ 	media |= ANAR_100|ANAR_100_FD|ANAR_10|ANAR_10_FD;
+ 	epic_write_phy_register( sc->iobase, DP83840_ANAR, media );
+ 
+ 	/* Set and restart autoneg */
+ 	epic_write_phy_register( sc->iobase, DP83840_BMCR,
+ 		BMCR_AUTONEGOTIATION | BMCR_RESTART_AUTONEG );
+ 
+         /*Wait 3 seconds for the autoneg to finish
+ 	 * This is the recommended time from the DP83840A data sheet
+ 	 * Section 7.1
+          */
+         DELAY(3000000);
+ 
+ 	epic_read_phy_register( sc->iobase, DP83840_BMSR);
+ 
+         /* BMSR must be read twice to update the link status bit/
+ 	 * since that bit is a latch bit
+          */
+ 	i = epic_read_phy_register( sc->iobase, DP83840_BMSR);
+         
+         if ((i & BMSR_LINK_STATUS) && ( i & BMSR_AUTONEG_COMPLETE)){
+ 		i = epic_read_phy_register( sc->iobase, DP83840_PAR);
+ 
+ 		if ( i & PAR_FULL_DUPLEX )
+ 			return 	EPIC_FULL_DUPLEX;
+ 		else
+ 			return EPIC_HALF_DUPLEX;
+         } 
+ 	else {   /*Auto-negotiation or link status is not 1
+ 		   Thus the auto-negotiation failed and one
+ 		   must take other means to fix it.
+ 		  */
+ 
+ 		/* ANER must be read twice to get the correct reading for the 
+ 		 * Multiple link fault bit -- it is a latched bit
+ 	 	 */
+  		epic_read_phy_register (sc->iobase, DP83840_ANER);
+ 
+ 		i = epic_read_phy_register (sc->iobase, DP83840_ANER);
+ 	
+ 		if ( i & ANER_MULTIPLE_LINK_FAULT ) {
+ 			/*it can be forced to 100Mb/s Half-Duplex*/
+ 	 		media = epic_read_phy_register (sc->iobase, DP83840_BMCR);
+ 			media &= !(BMCR_AUTONEGOTIATION | BMCR_FULL_DUPLEX);
+ 			media |= BMCR_100MBPS;
+ 			epic_write_phy_register(sc->iobase, DP83840_BMCR, media);
+ 		
+ 			/*read BMSR again to determine link status*/
+ 			epic_read_phy_register(sc->iobase, DP83840_BMSR);
+ 			i=epic_read_phy_register( sc->iobase, DP83840_BMSR);
+ 		
+ 			if (i & BMSR_LINK_STATUS){
+ 				/*port is linked to the non Auto-Negotiation
+ 				 * 100Mbs partner.
+ 			 	 */
+ 				return EPIC_HALF_DUPLEX;
+ 			}
+ 			else {
+ 				media = epic_read_phy_register (sc->iobase, DP83840_BMCR);
+ 				media &= !(BMCR_AUTONEGOTIATION | BMCR_FULL_DUPLEX | BMCR_100MBPS);
+ 				epic_write_phy_register(sc->iobase, DP83840_BMCR, media);
+ 				epic_read_phy_register(sc->iobase, DP83840_BMSR);
+ 				i=epic_read_phy_register( sc->iobase, DP83840_BMSR);
+ 
+ 				if (i & BMSR_LINK_STATUS) {
+ 					/*port is linked to the non
+ 					 * Auto-Negotiation10Mbs partner
+ 			 	 	 */
+ 					return EPIC_HALF_DUPLEX;
+ 				}
+ 			}
+ 		}
+ 		/* If we get here we are most likely not connected
+ 		 * so lets default it to half duplex
+ 		 */
+ 		return EPIC_HALF_DUPLEX;
+ 	}
+ 	
  }
  
  /*


*** smc83c170.h.orig	Sun Feb  1 20:53:35 1998
--- smc83c170.h	Sun Feb  1 23:18:52 1998
***************
*** 39,44 ****
--- 39,46 ----
  /*#define	EPIC_DEBUG	1*/
  #define TX_RING_SIZE	16
  #define RX_RING_SIZE	16
+ #define EPIC_FULL_DUPLEX	1
+ #define EPIC_HALF_DUPLEX	0
  
  #define ETHER_MAX_FRAME_LEN	(ETHER_MAX_LEN + ETHER_CRC_LEN)
  
***************
*** 185,190 ****
--- 187,194 ----
  #define DP83840_BMCR	0x00	/* Control register */
  #define DP83840_BMSR	0x01	/* Status rgister */
  #define	DP83840_ANAR	0x04	/* Autonegotiation advertising register */
+ #define DP83840_ANER	0x06	/* Auto-Negotiation Expansion Register */
+ #define DP83840_PAR	0x19	/* PHY Address Register */
  #define	DP83840_PHYIDR1	0x02
  #define	DP83840_PHYIDR2	0x03
  
***************
*** 203,208 ****
--- 207,216 ----
  #define BMSR_AUTONEG_ABLE	0x0008
  #define	BMSR_LINK_STATUS	0x0004
  
+ #define PAR_FULL_DUPLEX		0x0400
+ 
+ #define ANER_MULTIPLE_LINK_FAULT	0x10
+ 
  #define	ANAR_10			0x0020
  #define	ANAR_10_FD		0x0040
  #define	ANAR_100		0x0080
***************
*** 282,287 ****
--- 290,296 ----
  static void epic_set_rx_mode(epic_softc_t *);
  static void epic_set_mc_table(epic_softc_t *);
  static void epic_set_media_speed(epic_softc_t *);
+ static int epic_autoneg(epic_softc_t *);
  
  static int epic_read_eeprom(u_int16_t,u_int16_t);
  static void epic_output_eepromw(u_int16_t, u_int16_t);
>Audit-Trail:
>Unformatted:



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?199802020637.XAA00771>