Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 5 May 1998 18:43:40 +0700 (NSS)
From:      Ustimenko Semen <semen@iclub.nsu.ru>
To:        Adam McDougall <mcdougall@ameritech.net>
Cc:        Andrew <andrew@iaccess.com.au>, freebsd-current@FreeBSD.ORG, Jaroslav Klaus <J.Klaus@sh.cvut.cz>
Subject:   Re: ethernet card Problems
Message-ID:  <Pine.BSF.3.96.980505183656.13866C-200000@iclub.nsu.ru>
In-Reply-To: <35495353.62F9852D@ameritech.net>

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

[-- Attachment #1 --]
Hello!

On Fri, 1 May 1998, Adam McDougall wrote:

> Andrew wrote:
> 
> > >Hi,
> > >
> > >I'm having some ethernet crad problems.  The card i'm using is a SMC8216
> > >10/100Mbps
> > >I'm running it on 100Mbps.
> > >I'm running ipfilter with transproxy and squid on a 14 Gig cache on
> > >freebsd3.0-current, divertin all packets comin in on port 80 to transproxy.
> > >This is what messages tells me just before the whole thing crashes:
> > >

At last, i have done something, i added some debug output
if any errors occured, fixed epic_stop() to properly stop TX DMA and
changed tx queuing policy a little.

I don't want to commit it to FreeBSD-current, just
would You be so please to try it with EPIC_DEBUG enabled in if_tx.c.
Patch is attached.

Have You used previous versions? What was the best?

Thank you.

[-- Attachment #2 --]
*** if_tx.c.orig	Tue May  5 18:21:38 1998
--- if_tx.c	Tue May  5 18:24:42 1998
***************
*** 51,56 ****
--- 51,64 ----
  #define	TX_FRAG_LIST	1	/* Transmit directly from mbuf enstead */
  				/* of collecting mbuf's frags to one */
  				/* static allocated place */
+ /*#define	EARLY_RX	1*/
+ /*#define	EARLY_TX	1*/
+ 
+ #if defined(EPIC_DEBUG)
+ #define dprintf(a) printf a
+ #else
+ #define dprintf(a)
+ #endif
  
  #include "pci.h"
  #if NPCI > 0
***************
*** 85,91 ****
   * Global variables
   */
  static u_long epic_pci_count;
- static epic_softc_t * epics[EPIC_MAX_DEVICES];
  static struct pci_device txdevice = { 
  	"tx",
  	epic_pci_probe,
--- 93,98 ----
***************
*** 225,231 ****
  		m0 = m;
  
  #if defined(TX_FRAG_LIST)
! 		if( buf->mbuf ) m_freem( buf->mbuf );
  		buf->mbuf = m;
  		flist->numfrags = 0;
  
--- 232,241 ----
  		m0 = m;
  
  #if defined(TX_FRAG_LIST)
! 		if( buf->mbuf ) {
! 			dprintf(("tx%d: mbuf not freed in ifstart\n",sc->unit));
! 			m_freem( buf->mbuf );
! 		}
  		buf->mbuf = m;
  		flist->numfrags = 0;
  
***************
*** 238,243 ****
--- 248,254 ----
  		}
  
  		if( NULL != m0 ){
+ 			dprintf(("tx%d: mbuf too fragmented\n",sc->unit));
  			/* Copy packet to new allocated mbuf */
  			MGETHDR(m0,M_DONTWAIT,MT_DATA);
  			if( NULL == m0 ) {
***************
*** 255,282 ****
  				continue;
  			}
  
! 			for (len = 0; m != 0; m = m->m_next) {
! 				bcopy( mtod(m, caddr_t), mtod(m0, caddr_t) + len, m->m_len);
! 				len += m->m_len;
! 			}
! 			
! 			m_freem(buf->mbuf);
! 			buf->mbuf = m0;
  			flist->numfrags = 1;
  			flist->frag[0].fraglen = len;
  			flist->frag[0].fragaddr = vtophys( mtod(m0, caddr_t) );
  		}
  
  		/* Does not generate TXC unless ring is full more then a half */
! 		desc->control = (sc->pending_txs>TX_RING_SIZE/2)?0x05:0x01;
  #else
! 		for (len = 0; m0 != 0; m0 = m0->m_next) {
! 			bcopy(mtod(m0, caddr_t), buf->data + len, m0->m_len);
! 			len += m0->m_len;
! 		}
  
  		/* Does not generate TXC unless ring is full more then a half */
! 		desc->control = (sc->pending_txs>TX_RING_SIZE/2)?0x14:0x10;
  #endif
  
  		/* Packet should be at least ETHER_MIN_LEN */
--- 266,294 ----
  				continue;
  			}
  
! 			len = m->m_pkthdr.len;
! 			m_copydata( m, 0, len, mtod(m0,caddr_t) );
! 			m0->m_pkthdr.len = len;
! 			m0->m_pkthdr.rcvif = &sc->epic_if;
! 			m0->m_len = len;
! 
! 			m_freem(m);
! 			buf->mbuf = m = m0;
  			flist->numfrags = 1;
  			flist->frag[0].fraglen = len;
  			flist->frag[0].fragaddr = vtophys( mtod(m0, caddr_t) );
  		}
  
  		/* Does not generate TXC unless ring is full more then a half */
! 		/*desc->control = (sc->pending_txs>TX_RING_SIZE/2)?0x05:0x01; */
! 		desc->control = 0x01;
  #else
! 		len = m->m_pkthdr.len;
! 		m_copydata( m, 0, len, buf->data );
  
  		/* Does not generate TXC unless ring is full more then a half */
! 		/*desc->control = (sc->pending_txs>TX_RING_SIZE/2)?0x14:0x10;*/
! 		desc->control = 0x10;
  #endif
  
  		/* Packet should be at least ETHER_MIN_LEN */
***************
*** 285,290 ****
--- 297,305 ----
  		/* Pass ownership to the chip */
  		desc->status = 0x8000;
  
+ 		/* Trigger an immediate transmit demand. */
+ 		CSR_WRITE_4( sc, COMMAND, COMMAND_TXQUEUED );
+ 
  		/* Set watchdog timer */
  		ifp->if_timer = 2;
  
***************
*** 296,303 ****
  		/* We don't need mbuf anyway */
  		m_freem( m );
  #endif
- 		/* Trigger an immediate transmit demand. */
- 		CSR_WRITE_4( sc, COMMAND, COMMAND_TXQUEUED );
  
  		/* Packet queued successful */
  		sc->pending_txs++;
--- 311,316 ----
***************
*** 313,319 ****
  }
  
  /*
!  *  IFWATCHDOG function
   *
   * splimp() invoked here
   */
--- 326,333 ----
  }
  
  /*
!  * Synopsis: This one is called if packets wasn't transmitted
!  * during timeout.
   *
   * splimp() invoked here
   */
***************
*** 330,335 ****
--- 344,357 ----
  	printf("tx%d: device timeout %d packets\n",
  			sc->unit,sc->pending_txs);
  
+ #if defined(EPIC_DEBUG)
+ 	printf("tx%d: dirty_tx: %d, cur_tx: %d\n",sc->unit,sc->dirty_tx,sc->cur_tx);
+ 	printf("tx%d: not transmitted descs: ",sc->unit);
+ 	for(i=0;i<TX_RING_SIZE;i++)
+ 		if( sc->tx_desc[i].status & 0x8000 ) printf("%d ",i);	
+ 	printf("\n");
+ #endif
+ 
  	ifp->if_oerrors+=sc->pending_txs;
  
  	epic_stop(sc);
***************
*** 370,375 ****
--- 392,398 ----
  
  		/* Check for errors */
  		if( !(desc->status & 1) ) {
+ 			dprintf(("tx%d: receive error, status: %x\n",sc->unit,desc->status));
  			sc->epic_if.if_ierrors++;
  			goto rxerror;
  		}
***************
*** 477,483 ****
  	int coll;
  	u_int16_t stt;
  
! 	while( i++ < TX_RING_SIZE ){
  		struct epic_tx_buffer *buf = sc->tx_buffer + sc->dirty_tx;
  		struct epic_tx_desc *desc = sc->tx_desc + sc->dirty_tx;
  #if defined(TX_FRAG_LIST)
--- 500,506 ----
  	int coll;
  	u_int16_t stt;
  
! 	while( sc->pending_txs > 0 ){
  		struct epic_tx_buffer *buf = sc->tx_buffer + sc->dirty_tx;
  		struct epic_tx_desc *desc = sc->tx_desc + sc->dirty_tx;
  #if defined(TX_FRAG_LIST)
***************
*** 566,600 ****
  	epic_softc_t * sc = (epic_softc_t *) arg;
          int status;
  
! 	status = CSR_READ_4( sc, INTSTAT);
  	CSR_WRITE_4( sc, INTSTAT, status & (
! 		INTSTAT_RQE|INTSTAT_HCC|INTSTAT_RCC|
  		INTSTAT_TXC|INTSTAT_TCC|INTSTAT_TQE|
  		INTSTAT_FATAL|INTSTAT_GP2|
  		INTSTAT_CNT|INTSTAT_TXU|INTSTAT_OVW|INTSTAT_RXE ) );
  
! 	if( status & (INTSTAT_RQE|INTSTAT_HCC|INTSTAT_RCC) ) {
  		epic_rx_done( sc );
! 		if( status & INTSTAT_RQE ) 
  			CSR_WRITE_4( sc, COMMAND, COMMAND_RXQUEUED );
  	}
  
  	if( status & (INTSTAT_TXC|INTSTAT_TCC|INTSTAT_TQE) )
  		epic_tx_done( sc );
  
- 	if( (status & INTSTAT_TQE) && !(sc->epic_if.if_flags & IFF_OACTIVE) )
- 		epic_ifstart( &sc->epic_if );
- 
  	if( (status & INTSTAT_GP2) && (QS6612_OUI == sc->phyid) ) {
  		u_int32_t status;
  
  		status = epic_read_phy_register( sc, QS6612_INTSTAT );
  
! 		if( (status & INTSTAT_AN_COMPLETE) && 
! 		    (epic_autoneg(sc) == EPIC_FULL_DUPLEX) ) {
  			status = BMCR_FULL_DUPLEX | epic_read_phy_register( sc, DP83840_BMCR );
! 			CSR_WRITE_4( sc, TXCON,
! 				TXCON_LOOPBACK_MODE_FULL_DUPLEX|TXCON_DEFAULT );
  		} else {
  			status = ~BMCR_FULL_DUPLEX & epic_read_phy_register( sc, DP83840_BMCR );
  			CSR_WRITE_4( sc, TXCON, TXCON_DEFAULT );
--- 589,636 ----
  	epic_softc_t * sc = (epic_softc_t *) arg;
          int status;
  
! intloop:
! 	status = CSR_READ_4( sc, INTSTAT );
! 
! #if defined(EPIC_DEBUG)
! 	if( (status & INTSTAT_TQE) && (sc->epic_if.if_flags & IFF_DEBUG) ){
! 		printf("tx%d: TQE occured, forced epic_stop() - epic_init()\n",sc->unit);
! 		epic_stop( sc );
! 		epic_init( sc );
! 	}
! #endif
! 
  	CSR_WRITE_4( sc, INTSTAT, status & (
! 		INTSTAT_RQE|INTSTAT_RCC|
  		INTSTAT_TXC|INTSTAT_TCC|INTSTAT_TQE|
  		INTSTAT_FATAL|INTSTAT_GP2|
  		INTSTAT_CNT|INTSTAT_TXU|INTSTAT_OVW|INTSTAT_RXE ) );
  
! 	if( status & (INTSTAT_RQE|INTSTAT_RCC|INTSTAT_OVW) ) {
  		epic_rx_done( sc );
! 		if( status & INTSTAT_RQE ) {
! 			dprintf(("tx%d: Rx FIFO overflowed, restarting receiver\n",sc->unit));
  			CSR_WRITE_4( sc, COMMAND, COMMAND_RXQUEUED );
+ 			sc->epic_if.if_ierrors++;
+ 		}
+ 		if( status & INTSTAT_OVW ) {
+ 			dprintf(("tx%d: onchip Rx buffer overflowed, restarting receiver\n",sc->unit));
+ 			CSR_WRITE_4( sc, COMMAND, COMMAND_RXQUEUED );
+ 			sc->epic_if.if_ierrors++;
+ 		}
  	}
  
  	if( status & (INTSTAT_TXC|INTSTAT_TCC|INTSTAT_TQE) )
  		epic_tx_done( sc );
  
  	if( (status & INTSTAT_GP2) && (QS6612_OUI == sc->phyid) ) {
  		u_int32_t status;
  
  		status = epic_read_phy_register( sc, QS6612_INTSTAT );
  
! 		if( (status & INTSTAT_AN_COMPLETE) && (epic_autoneg(sc) == EPIC_FULL_DUPLEX) ) {
  			status = BMCR_FULL_DUPLEX | epic_read_phy_register( sc, DP83840_BMCR );
! 			CSR_WRITE_4( sc, TXCON, TXCON_FULL_DUPLEX | TXCON_DEFAULT );
  		} else {
  			status = ~BMCR_FULL_DUPLEX & epic_read_phy_register( sc, DP83840_BMCR );
  			CSR_WRITE_4( sc, TXCON, TXCON_DEFAULT );
***************
*** 603,617 ****
  		/* There is apparently QS6612 chip bug: */
  		/* BMCR_FULL_DUPLEX flag is not updated by */
  		/* autonegotiation process, so update it by hands */
! 		epic_write_phy_register( sc, DP83840_BMCR, status);
  
  		/* We should clear GP2 int again after we clear it on PHY */
  		CSR_WRITE_4( sc, INTSTAT, INTSTAT_GP2 ); 
  	}
  
  	if( status & (INTSTAT_FATAL|INTSTAT_PMA|INTSTAT_PTA|INTSTAT_APE|INTSTAT_DPE) ){
  		int j;
! 		struct epic_tx_desc *desc;
  
  		printf("tx%d: PCI fatal error occured (%s%s%s%s)\n",
  			sc->unit,
--- 639,656 ----
  		/* There is apparently QS6612 chip bug: */
  		/* BMCR_FULL_DUPLEX flag is not updated by */
  		/* autonegotiation process, so update it by hands */
! 		epic_write_phy_register(sc, DP83840_BMCR, status);
  
  		/* We should clear GP2 int again after we clear it on PHY */
  		CSR_WRITE_4( sc, INTSTAT, INTSTAT_GP2 ); 
  	}
  
  	if( status & (INTSTAT_FATAL|INTSTAT_PMA|INTSTAT_PTA|INTSTAT_APE|INTSTAT_DPE) ){
+ #if defined(EPIC_DEBUG)
  		int j;
! 		struct epic_tx_desc *tdesc;
! 		struct epic_rx_desc *rdesc;
! #endif
  
  		printf("tx%d: PCI fatal error occured (%s%s%s%s)\n",
  			sc->unit,
***************
*** 621,635 ****
  			(status&INTSTAT_DPE)?" DPE":"");
  
  #if defined(EPIC_DEBUG)
! 		printf("tx%d: dumping descriptors\n",sc->unit);
  		for(j=0;j<TX_RING_SIZE;j++){
! 			desc = sc->tx_desc + j;
! 			printf("desc%d: %d %04x, %08x, %04x %d, %08x\n",
  				j,
! 				desc->txlength,desc->status,
! 				desc->bufaddr,
! 				desc->control,desc->buflength,
! 				desc->next
  			);
  		}
  #endif
--- 660,686 ----
  			(status&INTSTAT_DPE)?" DPE":"");
  
  #if defined(EPIC_DEBUG)
! 		printf("tx%d: PRCDAR: 0x%08x, PTCDAR: 0x%08x\n",sc->unit,CSR_READ_4(sc,PRCDAR),CSR_READ_4(sc,PTCDAR));
! 		printf("tx%d: dumping tx descriptors\n",sc->unit);
  		for(j=0;j<TX_RING_SIZE;j++){
! 			tdesc = sc->tx_desc + j;
! 			printf("desc%d: %4d 0x%04x, 0x%08x, 0x%04x %4d, 0x%08x\n",
  				j,
! 				tdesc->txlength,tdesc->status,
! 				tdesc->bufaddr,
! 				tdesc->control,tdesc->buflength,
! 				tdesc->next
! 			);
! 		}
! 		printf("tx%d: dumping rx descriptors\n",sc->unit);
! 		for(j=0;j<RX_RING_SIZE;j++){
! 			rdesc = sc->rx_desc + j;
! 			printf("desc%d: %4d 0x%04x, 0x%08x, %4d, 0x%08x\n",
! 				j,
! 				rdesc->rxlength,rdesc->status,
! 				rdesc->bufaddr,
! 				rdesc->buflength,
! 				rdesc->next
  			);
  		}
  #endif
***************
*** 640,667 ****
  	}
  
          /* UPDATE statistics */
! 	if (status & (INTSTAT_CNT | INTSTAT_TXU | INTSTAT_OVW | INTSTAT_RXE)) {
  
  		/* update dot3 Rx statistics */
! 		sc->dot3stats.dot3StatsMissedFrames += CSR_READ_1( sc, MPCNT);
! 		sc->dot3stats.dot3StatsFrameTooLongs += CSR_READ_1( sc, ALICNT);
! 		sc->dot3stats.dot3StatsFCSErrors += CSR_READ_1( sc, CRCCNT);
  
  		/* Update if Rx statistics */
! 		if (status & (INTSTAT_OVW | INTSTAT_RXE))
  			sc->epic_if.if_ierrors++;
  
  		/* Tx FIFO underflow. */
  		if (status & INTSTAT_TXU) {
  			/* Inc. counters */
  			sc->dot3stats.dot3StatsInternalMacTransmitErrors++;
  			sc->epic_if.if_oerrors++;
  
  			/* Restart the transmit process. */
! 			CSR_WRITE_4(sc, COMMAND, COMMAND_TXUGO);
  		}
  	}
  
  	/* If no packets are pending, thus no timeouts */
  	if( sc->pending_txs == 0 )
  		sc->epic_if.if_timer = 0;
--- 691,723 ----
  	}
  
          /* UPDATE statistics */
! 	if (status & (INTSTAT_CNT | INTSTAT_TXU | INTSTAT_RXE)) {
  
  		/* update dot3 Rx statistics */
! 		sc->dot3stats.dot3StatsMissedFrames += CSR_READ_1(sc, MPCNT);
! 		sc->dot3stats.dot3StatsFrameTooLongs += CSR_READ_1(sc, ALICNT);
! 		sc->dot3stats.dot3StatsFCSErrors += CSR_READ_1(sc, CRCCNT);
  
  		/* Update if Rx statistics */
! 		if (status & INTSTAT_RXE) {
! 			dprintf(("tx%d: CRC/Alignment error\n",sc->unit));
  			sc->epic_if.if_ierrors++;
+ 		}
  
  		/* Tx FIFO underflow. */
  		if (status & INTSTAT_TXU) {
+ 			dprintf(("tx%d: Tx underrun error, restarting tranciever\n",sc->unit));
  			/* Inc. counters */
  			sc->dot3stats.dot3StatsInternalMacTransmitErrors++;
  			sc->epic_if.if_oerrors++;
  
  			/* Restart the transmit process. */
! 			CSR_WRITE_4(sc, COMMAND, COMMAND_TXUGO | COMMAND_TXQUEUED);
  		}
  	}
  
+ 	if( CSR_READ_4( sc, INTSTAT ) & INTSTAT_INT_ACTV ) goto intloop;
+ 
  	/* If no packets are pending, thus no timeouts */
  	if( sc->pending_txs == 0 )
  		sc->epic_if.if_timer = 0;
***************
*** 724,741 ****
  
  	/* Preinitialize softc structure */
      	bzero(sc, sizeof(epic_softc_t));		
- 	epics[ unit ] = sc;
  	sc->unit = unit;
  
  	/* Get iobase or membase */
  #if defined(EPIC_USEIOSPACE)
  	if (!pci_map_port(config_id, PCI_CBIO,(u_short *) &(sc->iobase))) {
  		printf("tx%d: cannot map port\n",unit);
  		return;
  	}
  #else
  	if (!pci_map_mem(config_id, PCI_CBMA,(vm_offset_t *) &(sc->csr),(vm_offset_t *) &pmembase)) {
  		printf("tx%d: cannot map memory\n",unit); 
  		return;
  	}
  #endif
--- 780,798 ----
  
  	/* Preinitialize softc structure */
      	bzero(sc, sizeof(epic_softc_t));		
  	sc->unit = unit;
  
  	/* Get iobase or membase */
  #if defined(EPIC_USEIOSPACE)
  	if (!pci_map_port(config_id, PCI_CBIO,(u_short *) &(sc->iobase))) {
  		printf("tx%d: cannot map port\n",unit);
+ 		free(sc, M_DEVBUF);
  		return;
  	}
  #else
  	if (!pci_map_mem(config_id, PCI_CBMA,(vm_offset_t *) &(sc->csr),(vm_offset_t *) &pmembase)) {
  		printf("tx%d: cannot map memory\n",unit); 
+ 		free(sc, M_DEVBUF);
  		return;
  	}
  #endif
***************
*** 764,776 ****
  		sc->epic_macaddr[0],sc->epic_macaddr[1],sc->epic_macaddr[2],
  		sc->epic_macaddr[3],sc->epic_macaddr[4],sc->epic_macaddr[5]);
  
- 
  	s = splimp();
  
  	/* Map interrupt */
  	if( !pci_map_int(config_id, epic_intr_normal, (void*)sc, &net_imask) ) {
  		printf("tx%d: couldn't map interrupt\n",unit);
- 		epics[ unit ] = NULL;
  		free(sc, M_DEVBUF);
  		return;
  	}
--- 821,831 ----
***************
*** 867,876 ****
--- 922,934 ----
  	/* init ifmedia interface */
  	ifmedia_init(&sc->ifmedia,0,epic_ifmedia_change,epic_ifmedia_status);
  	ifmedia_add(&sc->ifmedia,IFM_ETHER|IFM_10_T,0,NULL);
+ 	ifmedia_add(&sc->ifmedia,IFM_ETHER|IFM_10_T|IFM_LOOP,0,NULL);
  	ifmedia_add(&sc->ifmedia,IFM_ETHER|IFM_10_T|IFM_FDX,0,NULL);
  	ifmedia_add(&sc->ifmedia,IFM_ETHER|IFM_100_TX,0,NULL);
+ 	ifmedia_add(&sc->ifmedia,IFM_ETHER|IFM_100_TX|IFM_LOOP,0,NULL);
  	ifmedia_add(&sc->ifmedia,IFM_ETHER|IFM_100_TX|IFM_FDX,0,NULL);
  	ifmedia_add(&sc->ifmedia,IFM_ETHER|IFM_AUTO,0,NULL);
+ 	ifmedia_add(&sc->ifmedia,IFM_ETHER|IFM_LOOP,0,NULL);
  	ifmedia_set(&sc->ifmedia, media);
  #endif
  
***************
*** 884,892 ****
  	/* Set shut down routine to stop DMA processes on reboot */
  	at_shutdown(epic_shutdown, sc, SHUTDOWN_POST_SYNC);
  
! 	/*
! 	 *  Attach to if manager
! 	 */
  	if_attach(ifp);
  	ether_ifattach(ifp);
  
--- 942,948 ----
  	/* Set shut down routine to stop DMA processes on reboot */
  	at_shutdown(epic_shutdown, sc, SHUTDOWN_POST_SYNC);
  
! 	/*  Attach to if manager */
  	if_attach(ifp);
  	ether_ifattach(ifp);
  
***************
*** 937,947 ****
  	ifmr->ifm_status |= IFM_ACTIVE;
  	ifmr->ifm_active |= (bmcr&BMCR_100MBPS)?IFM_100_TX:IFM_10_T;
  	ifmr->ifm_active |= (bmcr&BMCR_FULL_DUPLEX)?IFM_FDX:0;
  }
  #endif
  
  /*
!  * IFINIT function
   * 
   * splimp() invoked here
   */
--- 993,1004 ----
  	ifmr->ifm_status |= IFM_ACTIVE;
  	ifmr->ifm_active |= (bmcr&BMCR_100MBPS)?IFM_100_TX:IFM_10_T;
  	ifmr->ifm_active |= (bmcr&BMCR_FULL_DUPLEX)?IFM_FDX:0;
+ 	ifmr->ifm_active |= ((CSR_READ_4(sc,TXCON)&TXCON_LOOPBACK_MODE)==TXCON_LOOPBACK_MODE_INT)?IFM_LOOP:0;
  }
  #endif
  
  /*
!  * Reset chip, PHY, allocate rings
   * 
   * splimp() invoked here
   */
***************
*** 979,986 ****
          CSR_WRITE_4( sc, LAN1, ((u_int16_t *)sc->epic_macaddr)[1] );
  	CSR_WRITE_4( sc, LAN2, ((u_int16_t *)sc->epic_macaddr)[2] );
  
  	/* Set transmit threshold */
! 	CSR_WRITE_4( sc, ETXTHR, 0x40 );
  
  	/* Compute and set RXCON. */
  	epic_set_rx_mode( sc );
--- 1036,1045 ----
          CSR_WRITE_4( sc, LAN1, ((u_int16_t *)sc->epic_macaddr)[1] );
  	CSR_WRITE_4( sc, LAN2, ((u_int16_t *)sc->epic_macaddr)[2] );
  
+ #if defined(EARLY_TX)
  	/* Set transmit threshold */
! 	CSR_WRITE_4( sc, ETXTHR, TRANSMIT_THRESHOLD );
! #endif
  
  	/* Compute and set RXCON. */
  	epic_set_rx_mode( sc );
***************
*** 993,1011 ****
  	epic_set_mc_table( sc );
  
  	/* Enable interrupts by setting the interrupt mask. */
! 	if( QS6612_OUI == sc->phyid ) {
! 		CSR_WRITE_4( sc, INTMASK,
! 			INTSTAT_RCC | INTSTAT_RQE | INTSTAT_OVW | INTSTAT_RXE |
! 			INTSTAT_TXC | INTSTAT_TCC | INTSTAT_TQE | INTSTAT_TXU |
! 			INTSTAT_CNT | INTSTAT_GP2 | INTSTAT_FATAL |
! 			INTSTAT_PTA | INTSTAT_PMA | INTSTAT_APE | INTSTAT_DPE );
! 	} else {
! 		CSR_WRITE_4( sc, INTMASK,
! 			INTSTAT_RCC | INTSTAT_RQE | INTSTAT_OVW | INTSTAT_RXE |
! 			INTSTAT_TXC | INTSTAT_TCC | INTSTAT_TQE | INTSTAT_TXU |
! 			INTSTAT_CNT | INTSTAT_FATAL |
! 			INTSTAT_PTA | INTSTAT_PMA | INTSTAT_APE | INTSTAT_DPE );
! 	}
  
  	/* Enable interrupts,  set for PCI read multiple and etc */
  	CSR_WRITE_4( sc, GENCTL,
--- 1052,1062 ----
  	epic_set_mc_table( sc );
  
  	/* Enable interrupts by setting the interrupt mask. */
! 	CSR_WRITE_4( sc, INTMASK,
! 		INTSTAT_RCC | INTSTAT_RQE | INTSTAT_OVW | INTSTAT_RXE |
! 		INTSTAT_TXC | INTSTAT_TCC | INTSTAT_TQE | INTSTAT_TXU |
! 		INTSTAT_CNT | INTSTAT_FATAL |
! 		((QS6612_OUI == sc->phyid)?INTSTAT_GP2:0) );
  
  	/* Enable interrupts,  set for PCI read multiple and etc */
  	CSR_WRITE_4( sc, GENCTL,
***************
*** 1027,1057 ****
  }
  
  /*
!  * This function should set EPIC's registers according IFF_* flags
   */
  static void
  epic_set_rx_mode(
      epic_softc_t * sc)
  {
! 	struct ifnet *ifp = &sc->epic_if;
!         u_int16_t rxcon = 0;
  
! #if NBPFILTER > 0
! 	if( sc->epic_if.if_flags & IFF_PROMISC )
! 		rxcon |= RXCON_PROMISCUOUS_MODE;
! #endif
! 
! 	if( sc->epic_if.if_flags & IFF_BROADCAST )
! 		rxcon |= RXCON_RECEIVE_BROADCAST_FRAMES;
! 
! 	if( sc->epic_if.if_flags & IFF_MULTICAST )
! 		rxcon |= RXCON_RECEIVE_MULTICAST_FRAMES;
  
  	CSR_WRITE_4( sc, RXCON, rxcon );
  
  	return;
  }
  
  static void
  epic_init_phy __P((
      epic_softc_t * sc))
--- 1078,1102 ----
  }
  
  /*
!  * Synopsis: calculate and set Rx mode
   */
  static void
  epic_set_rx_mode(
      epic_softc_t * sc)
  {
! 	u_int32_t flags = sc->epic_if.if_flags;
!         u_int32_t rxcon = RXCON_DEFAULT | RXCON_RECEIVE_MULTICAST_FRAMES | RXCON_RECEIVE_BROADCAST_FRAMES;
  
! 	rxcon |= (flags & IFF_PROMISC)?RXCON_PROMISCUOUS_MODE:0;
  
  	CSR_WRITE_4( sc, RXCON, rxcon );
  
  	return;
  }
  
+ /*
+  * Synopsis: Reset PHY and do PHY-special initialization:
+  */
  static void
  epic_init_phy __P((
      epic_softc_t * sc))
***************
*** 1073,1079 ****
  		CSR_WRITE_4( sc, NVCTL, NVCTL_GP1_OUTPUT_ENABLE );
  		epic_read_phy_register( sc, QS6612_INTSTAT );
  		epic_write_phy_register( sc, QS6612_INTMASK,
! 			INTMASK_THUNDERLAN|INTSTAT_AN_COMPLETE );
  		break;
  	default:
  		break;
--- 1118,1128 ----
  		CSR_WRITE_4( sc, NVCTL, NVCTL_GP1_OUTPUT_ENABLE );
  		epic_read_phy_register( sc, QS6612_INTSTAT );
  		epic_write_phy_register( sc, QS6612_INTMASK,
! 			INTMASK_THUNDERLAN | INTSTAT_AN_COMPLETE );
! 
! 		/* Enable QS6612 extended cable length capabilites */
! 		epic_write_phy_register( sc, QS6612_MCTL, epic_read_phy_register( sc,QS6612_MCTL ) | MCTL_BTEXT );
! 
  		break;
  	default:
  		break;
***************
*** 1081,1087 ****
  }
  
  /*
!  * This function should set MII to mode specified by IFF_LINK* flags or
   * ifmedia structure.
   */
  static void
--- 1130,1136 ----
  }
  
  /*
!  * Synopsis: Set PHY to media type specified by IFF_LINK* flags or
   * ifmedia structure.
   */
  static void
***************
*** 1108,1114 ****
  
  		epic_write_phy_register( sc, DP83840_BMCR, media );
  
! 		CSR_WRITE_4( sc, TXCON,(tgtmedia&IFM_FDX)?TXCON_LOOPBACK_MODE_FULL_DUPLEX|TXCON_DEFAULT:TXCON_DEFAULT );
  	}
  #else
  	if( ifp->if_flags & IFF_LINK0 ) {
--- 1157,1167 ----
  
  		epic_write_phy_register( sc, DP83840_BMCR, media );
  
! 		media = TXCON_DEFAULT;
! 		if( tgtmedia & IFM_FDX ) media |= TXCON_FULL_DUPLEX;
! 		else if( tgtmedia & IFM_LOOP ) media |= TXCON_LOOPBACK_MODE_INT;
! 		
! 		CSR_WRITE_4( sc, TXCON, media );
  	}
  #else
  	if( ifp->if_flags & IFF_LINK0 ) {
***************
*** 1121,1127 ****
  
  		epic_write_phy_register( sc, DP83840_BMCR, media );
  
! 		CSR_WRITE_4( sc, TXCON, (ifp->if_flags & IFF_LINK2) ? TXCON_LOOPBACK_MODE_FULL_DUPLEX|TXCON_DEFAULT : TXCON_DEFAULT );
  	}
  #endif
  	  else {
--- 1174,1183 ----
  
  		epic_write_phy_register( sc, DP83840_BMCR, media );
  
! 		media = TXCON_DEFAULT;
! 		media |= (ifp->if_flags&IFF_LINK2)?TXCON_FULL_DUPLEX:0;
!  
! 		CSR_WRITE_4( sc, TXCON, media );
  	}
  #endif
  	  else {
***************
*** 1142,1149 ****
          		DELAY(3000000);
  			
  			if( epic_autoneg(sc) == EPIC_FULL_DUPLEX )
! 				CSR_WRITE_4( sc, TXCON,
! 					TXCON_LOOPBACK_MODE_FULL_DUPLEX|TXCON_DEFAULT);
  		}
  		/* Else it will be done when GP2 int occured */
  	}
--- 1198,1204 ----
          		DELAY(3000000);
  			
  			if( epic_autoneg(sc) == EPIC_FULL_DUPLEX )
! 				CSR_WRITE_4( sc, TXCON, TXCON_FULL_DUPLEX|TXCON_DEFAULT);
  		}
  		/* Else it will be done when GP2 int occured */
  	}
***************
*** 1258,1264 ****
  }
  
  /*
!  *  This function should completely stop rx and tx processes
   *  
   *  splimp() invoked here
   */
--- 1313,1320 ----
  }
  
  /*
!  *  Synopsis: Completely stop Rx and Tx processes, and deallocate rings. If
!  * TQE is set, additional packet needs to be queued to stop Tx DMA.
   *  
   *  splimp() invoked here
   */
***************
*** 1268,1305 ****
  {
  	int i,s;
  
  	s = splimp();
  	sc->epic_if.if_timer = 0;
  
! 	/* Disable interrupts, stop processes */
  	CSR_WRITE_4( sc, INTMASK, 0 );
  	CSR_WRITE_4( sc, GENCTL, 0 );
- 	CSR_WRITE_4( sc, COMMAND,
- 		COMMAND_STOP_RX | COMMAND_STOP_RDMA | COMMAND_STOP_TDMA );
  
! 	/* Wait RX and TX DMA to stop */
! 	for(i=0;i<0x100000;i++){
! 		if( (CSR_READ_4(sc,INTSTAT)&(INTSTAT_RXIDLE|INTSTAT_TXIDLE)) ==
! 			(INTSTAT_RXIDLE|INTSTAT_TXIDLE) ) break;
! 	}
! 	
! 	if( !(CSR_READ_4(sc,INTSTAT)&INTSTAT_RXIDLE) )
  		printf("tx%d: can't stop RX DMA\n",sc->unit);
  
! 	if( !(CSR_READ_4(sc,INTSTAT)&INTSTAT_TXIDLE) )
! 		printf("tx%d: can't stop TX DMA\n",sc->unit);
  
! 	/* Reset chip and phy */
  	CSR_WRITE_4( sc, GENCTL, GENCTL_SOFT_RESET );
  
  	/* Need to wait for 15 pci ticks to pass before accessing again*/
  	DELAY(1);
  
  	/* Free memory allocated for rings */
  	epic_free_rings( sc );
  
  	splx(s);
  
  }
  
  /*
--- 1324,1392 ----
  {
  	int i,s;
  
+ 	dprintf(("tx%d: epic_stop(): enter\n",sc->unit));
+ 
  	s = splimp();
  	sc->epic_if.if_timer = 0;
  
! 	/* Disable interrupts */
  	CSR_WRITE_4( sc, INTMASK, 0 );
  	CSR_WRITE_4( sc, GENCTL, 0 );
  
! 	/* Stop Tx and Rx DMA */
! 	CSR_WRITE_4( sc, COMMAND, COMMAND_STOP_RX | COMMAND_STOP_RDMA | COMMAND_STOP_TDMA);
! 
! 	dprintf(("tx%d: waiting Rx DMA to stop\n",sc->unit));
! 	/* Wait only Rx DMA */
! 	for(i=0;i<0x100000;i++)
! 		if( (CSR_READ_4(sc,INTSTAT)&INTSTAT_RXIDLE) == INTSTAT_RXIDLE ) break;
! 
! 	if( !(CSR_READ_4(sc,INTSTAT)&INTSTAT_RXIDLE) ) 
  		printf("tx%d: can't stop RX DMA\n",sc->unit);
+ 	else
+ 		dprintf(("tx%d: Rx DMA stoped\n",sc->unit));
+ 
+ 	/* May need to queue one more packet if TQE */
+ 	if( (CSR_READ_4( sc, INTSTAT ) & INTSTAT_TQE) &&
+ 	    !(CSR_READ_4( sc, INTSTAT ) & INTSTAT_TXIDLE) ){
+ 		dprintf(("tx%d: epic_stop(): queue last packet\n",sc->unit));
+ 
+ 		/* Turn it to loopback mode */	
+ 		CSR_WRITE_4( sc, TXCON, TXCON_DEFAULT | TXCON_LOOPBACK_MODE_INT );
+ 
+ 		sc->tx_desc[sc->cur_tx].bufaddr = vtophys( sc );
+ 		sc->tx_desc[sc->cur_tx].buflength = ETHER_MIN_LEN-ETHER_CRC_LEN;
+ 		sc->tx_desc[sc->cur_tx].control = 0x14;
+ 		sc->tx_desc[sc->cur_tx].txlength = ETHER_MIN_LEN-ETHER_CRC_LEN;
+ 		sc->tx_desc[sc->cur_tx].status = 0x8000;
+ 
+ 		CSR_WRITE_4( sc, COMMAND, COMMAND_TXQUEUED );
  
! 		dprintf(("tx%d: waiting Tx DMA to stop\n",sc->unit));
! 		/* Wait TX DMA to stop */
! 		for(i=0;i<0x100000;i++)
! 			if( (CSR_READ_4(sc,INTSTAT)&INTSTAT_TXIDLE) == INTSTAT_TXIDLE ) break;
  
! 		if( !(CSR_READ_4(sc,INTSTAT)&INTSTAT_TXIDLE) )
! 			printf("tx%d: can't stop TX DMA\n",sc->unit);
! 		else
! 			dprintf(("tx%d: Tx DMA stoped\n",sc->unit));
! 	} else
! 		dprintf(("tx%d: Tx DMA stoped\n",sc->unit));
! 
! 	/* Reset chip */
  	CSR_WRITE_4( sc, GENCTL, GENCTL_SOFT_RESET );
  
  	/* Need to wait for 15 pci ticks to pass before accessing again*/
  	DELAY(1);
  
+ 	dprintf(("tx%d: deallocate rings\n",sc->unit));
  	/* Free memory allocated for rings */
  	epic_free_rings( sc );
  
  	splx(s);
  
+ 	dprintf(("tx%d: epic_stop(): done\n",sc->unit));
  }
  
  /*
***************
*** 1312,1317 ****
--- 1399,1406 ----
  epic_free_rings(epic_softc_t * sc){
  	int i;
  
+ 	dprintf(("tx%d: epic_free_rings(): enter\n",sc->unit));
+ 
  	for(i=0;i<RX_RING_SIZE;i++){
  		struct epic_rx_buffer *buf = sc->rx_buffer + i;
  		struct epic_rx_desc *desc = sc->rx_desc + i;
***************
*** 1345,1350 ****
--- 1434,1441 ----
  		buf->data = NULL;
  #endif
  	}
+ 
+ 	dprintf(("tx%d: epic_free_rings(): done\n",sc->unit));
  }
  
  /*
***************
*** 1382,1388 ****
  		if( NULL == (buf->mbuf->m_flags & M_EXT) ) return -1;
  		desc->bufaddr = vtophys( mtod(buf->mbuf,caddr_t) );
  #else
! 		buf->data = malloc(ETHER_MAX_FRAME_LEN, M_DEVBUF, M_NOWAIT);
  		if( buf->data == NULL ) return -1;
  		desc->bufaddr = vtophys( buf->data );
  #endif
--- 1473,1479 ----
  		if( NULL == (buf->mbuf->m_flags & M_EXT) ) return -1;
  		desc->bufaddr = vtophys( mtod(buf->mbuf,caddr_t) );
  #else
! 		buf->data = malloc( ETHER_MAX_FRAME_LEN, M_DEVBUF, M_NOWAIT);
  		if( buf->data == NULL ) return -1;
  		desc->bufaddr = vtophys( buf->data );
  #endif
*** smc83c170.h.orig	Tue May  5 18:21:30 1998
--- smc83c170.h	Tue May  5 18:10:43 1998
***************
*** 180,190 ****
  #define TXCON_LOOPBACK_DISABLE		0x00000000
  #define TXCON_LOOPBACK_MODE_INT		0x00000002
  #define TXCON_LOOPBACK_MODE_PHY		0x00000004
! #define TXCON_LOOPBACK_MODE_FULL_DUPLEX	0x00000006
  #define TXCON_SLOT_TIME			0x00000078
  
! #define TXCON_DEFAULT	(TXCON_SLOT_TIME|TXCON_EARLY_TRANSMIT_ENABLE)
! 
  /*
   * National Semiconductor's DP83840A Registers and bits
   */
--- 180,200 ----
  #define TXCON_LOOPBACK_DISABLE		0x00000000
  #define TXCON_LOOPBACK_MODE_INT		0x00000002
  #define TXCON_LOOPBACK_MODE_PHY		0x00000004
! #define TXCON_LOOPBACK_MODE		0x00000006
! #define TXCON_FULL_DUPLEX		0x00000006
  #define TXCON_SLOT_TIME			0x00000078
  
! #if defined(EARLY_TX)
!  #define TXCON_DEFAULT		(TXCON_SLOT_TIME | TXCON_EARLY_TRANSMIT_ENABLE)
!  #define TRANSMIT_THRESHOLD	0x40
! #else
!  #define TXCON_DEFAULT		(TXCON_SLOT_TIME)
! #endif
! #if defined(EARLY_RX)
!  #define RXCON_DEFAULT		(RXCON_EARLY_RECEIVE_ENABLE | RXCON_SAVE_ERRORED_PACKETS)
! #else
!  #define RXCON_DEFAULT		(0)
! #endif
  /*
   * National Semiconductor's DP83840A Registers and bits
   */
***************
*** 228,236 ****
--- 238,252 ----
   * Quality Semiconductor's QS6612 registers and bits
   */
  #define	QS6612_OUI		0x006051
+ #define	QS6612_MCTL		17
  #define	QS6612_INTSTAT		29
  #define	QS6612_INTMASK		30
  
+ #define	MCTL_T4_PRESENT		0x1000	/* External T4 Enabled, ignored */
+ 					/* if AutoNeg is enabled */
+ #define	MCTL_BTEXT		0x0800	/* Reduces 10baset squelch level */
+ 					/* for extended cable length */
+ 
  #define	INTSTAT_AN_COMPLETE	0x40	/* Autonegotiation complete */
  #define	INTSTAT_RF_DETECTED	0x20	/* Remote Fault detected */
  #define	INTSTAT_LINK_STATUS	0x10	/* Link status changed */

Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?Pine.BSF.3.96.980505183656.13866C-200000>