From owner-freebsd-bugs Sun Feb 1 22:40:04 1998 Return-Path: Received: (from majordom@localhost) by hub.freebsd.org (8.8.8/8.8.8) id WAA11897 for freebsd-bugs-outgoing; Sun, 1 Feb 1998 22:40:04 -0800 (PST) (envelope-from owner-freebsd-bugs@FreeBSD.ORG) Received: (from gnats@localhost) by hub.freebsd.org (8.8.8/8.8.8) id WAA11889; Sun, 1 Feb 1998 22:40:02 -0800 (PST) (envelope-from gnats) Received: from hardrock.sdsmt.edu (cisco097.sdsmt.edu [151.159.97.254]) by hub.freebsd.org (8.8.8/8.8.8) with ESMTP id WAA11637 for ; Sun, 1 Feb 1998 22:37:36 -0800 (PST) (envelope-from sbauer@hardrock.sdsmt.edu) Received: (from sbauer@localhost) by hardrock.sdsmt.edu (8.8.8/8.8.8) id XAA00771; Sun, 1 Feb 1998 23:37:34 -0700 (MST) (envelope-from sbauer) Message-Id: <199802020637.XAA00771@hardrock.sdsmt.edu> Date: Sun, 1 Feb 1998 23:37:34 -0700 (MST) From: Steve Bauer Reply-To: sbauer@hardrock.sdsmt.edu To: FreeBSD-gnats-submit@FreeBSD.ORG X-Send-Pr-Version: 3.2 Subject: kern/5625: SMC9432 device driver update Sender: owner-freebsd-bugs@FreeBSD.ORG Precedence: bulk X-Loop: FreeBSD.org X-To-Unsubscribe: mail to majordomo@FreeBSD.org "unsubscribe freebsd-bugs" >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 #include #include + #include #include #include *************** *** 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: