Fixed performance problems caused by the ring buffer becoming flodded when

multiple packets were being received due to not flushing newly received
packets from the ring buffer between receiving an interupt and pulling
in the packets.
This commit is contained in:
mark 1996-02-15 21:48:59 +00:00
parent 5ef42fccf7
commit f134e05316
1 changed files with 113 additions and 70 deletions

View File

@ -1,3 +1,5 @@
/* $NetBSD: if_eh.c,v 1.2 1996/02/15 21:48:59 mark Exp $ */
/* /*
* Copyright (c) 1995 Melvin Tang-Richardson. * Copyright (c) 1995 Melvin Tang-Richardson.
* All rights reserved. * All rights reserved.
@ -7,6 +9,7 @@
* - Testing * - Testing
* - 16-bit dma's * - 16-bit dma's
* - Buffer overflow handling (This must be done a certain way) [Nuts] * - Buffer overflow handling (This must be done a certain way) [Nuts]
* - Enabling card interrupts (Need i cubed info)
* *
* Other things to do * Other things to do
* - Pipelined transmitts * - Pipelined transmitts
@ -44,6 +47,8 @@
* *
* Ether H driver. * Ether H driver.
* *
* $Id: if_eh.c,v 1.2 1996/02/15 21:48:59 mark Exp $
*
*/ */
/* Some system includes *****************************************************/ /* Some system includes *****************************************************/
@ -100,10 +105,10 @@
#define MY_PODULE (0xec) #define MY_PODULE (0xec)
#define TXBUF_SIZE (1522) #define TXBUF_SIZE (1522)
#define NTXBUF (2) #define NTXBUF (1)
#define RXBUF_SIZE (256) #define RXBUF_SIZE (256)
#define NRXBUF (20) #define NRXBUF (26)
#define ETHER_MIN_LEN (64) #define ETHER_MIN_LEN (64)
#define ETHER_MAX_LEN (1522) #define ETHER_MAX_LEN (1522)
@ -194,7 +199,11 @@ void eh_shutdown __P(( void *arg ));
/* Bus attachment code ******************************************************/ /* Bus attachment code ******************************************************/
/****************************************************************************/ /****************************************************************************/
int ehprobe ( struct device *parent, void *match, void *aux ) int
ehprobe(parent, match, aux)
struct device *parent;
void *match;
void *aux;
{ {
struct eh_softc *sc = (void *) match; struct eh_softc *sc = (void *) match;
struct podule_attach_args *pa = (void *) aux; struct podule_attach_args *pa = (void *) aux;
@ -338,7 +347,11 @@ int ehprobe ( struct device *parent, void *match, void *aux )
return 1; return 1;
} }
void ehattach ( struct device *parent, struct device *self, void *aux ) void
ehattach(parent, self, aux)
struct device *parent;
struct device *self;
void *aux;
{ {
struct eh_softc *sc = (void *) self; struct eh_softc *sc = (void *) self;
struct podule_attach_args *pa = (void *)aux; struct podule_attach_args *pa = (void *)aux;
@ -424,7 +437,9 @@ void ehattach ( struct device *parent, struct device *self, void *aux )
#define NEXT_TXBUF (((sc->sc_txcur+1)>=NTXBUF) ? 0 : (sc->sc_txcur+1)) #define NEXT_TXBUF (((sc->sc_txcur+1)>=NTXBUF) ? 0 : (sc->sc_txcur+1))
void ehstart ( struct ifnet *ifp ) void
ehstart(ifp)
struct ifnet *ifp;
{ {
struct eh_softc *sc = ehcd.cd_devs[ifp->if_unit]; struct eh_softc *sc = ehcd.cd_devs[ifp->if_unit];
int cur; int cur;
@ -434,6 +449,8 @@ void ehstart ( struct ifnet *ifp )
char txbuf[TXBUF_SIZE]; char txbuf[TXBUF_SIZE];
int len = 0; int len = 0;
PAGE(0);
if ((ifp->if_flags & IFF_OACTIVE) != 0 ) if ((ifp->if_flags & IFF_OACTIVE) != 0 )
return; return;
@ -502,7 +519,11 @@ void ehstart ( struct ifnet *ifp )
#define DOSET(a,b) (a->if_flags|=b) #define DOSET(a,b) (a->if_flags|=b)
#define DOCLR(a,b) (a->if_flags&=~b) #define DOCLR(a,b) (a->if_flags&=~b)
int ehioctl ( struct ifnet *ifp, u_long cmd, caddr_t data ) int
ehioctl(ifp, cmd, data)
struct ifnet *ifp;
u_long cmd;
caddr_t data;
{ {
struct eh_softc *sc = ehcd.cd_devs[ifp->if_unit]; struct eh_softc *sc = ehcd.cd_devs[ifp->if_unit];
struct ifaddr *ifa = (struct ifaddr *)data; struct ifaddr *ifa = (struct ifaddr *)data;
@ -555,7 +576,9 @@ int ehioctl ( struct ifnet *ifp, u_long cmd, caddr_t data )
return error; return error;
} }
void ehwatchdog ( int unit ) void
ehwatchdog(unit)
int unit;
{ {
struct eh_softc *sc = ehcd.cd_devs[unit]; struct eh_softc *sc = ehcd.cd_devs[unit];
@ -573,7 +596,9 @@ void ehwatchdog ( int unit )
* continue to completion before entering the reset state. * continue to completion before entering the reset state.
*/ */
void eh_stop_controller ( struct eh_softc *sc ) void
eh_stop_controller(sc)
struct eh_softc *sc;
{ {
SetReg ( EH_COMMAND, ((GetReg(EH_COMMAND)&0xfc)|1) ); SetReg ( EH_COMMAND, ((GetReg(EH_COMMAND)&0xfc)|1) );
delay ( 10000 ); /* Change this to wait on the ISR bit */ delay ( 10000 ); /* Change this to wait on the ISR bit */
@ -586,13 +611,17 @@ void eh_stop_controller ( struct eh_softc *sc )
* been placed in a reset mode by eh_stop_controller or an error. * been placed in a reset mode by eh_stop_controller or an error.
*/ */
void eh_start_controller ( struct eh_softc *sc ) void
eh_start_controller(sc)
struct eh_softc *sc;
{ {
int temp = GetReg(EH_COMMAND); int temp = GetReg(EH_COMMAND);
SetReg ( EH_COMMAND, ( (temp&0xfc)|2) ); SetReg ( EH_COMMAND, ( (temp&0xfc)|2) );
} }
void eh_transmit_command ( struct eh_softc *sc ) void
eh_transmit_command(sc)
struct eh_softc *sc;
{ {
/* Explicit set here. There is no other reasonable combination */ /* Explicit set here. There is no other reasonable combination */
SetReg ( EH_COMMAND, COM_ABORT|COM_STA|COM_TXP); SetReg ( EH_COMMAND, COM_ABORT|COM_STA|COM_TXP);
@ -606,7 +635,9 @@ void eh_transmit_command ( struct eh_softc *sc )
/* We musn't fail */ /* We musn't fail */
inline void eh_ensure_dma_ok ( struct eh_softc *sc ) inline void
eh_ensure_dma_ok(sc)
struct eh_softc *sc;
{ {
register int isr = GetReg ( EH_ISR ); register int isr = GetReg ( EH_ISR );
register int status = GetReg ( EH_COMMAND ); register int status = GetReg ( EH_COMMAND );
@ -627,7 +658,10 @@ inline void eh_ensure_dma_ok ( struct eh_softc *sc )
SetReg ( EH_COMMAND, 0x22 ); SetReg ( EH_COMMAND, 0x22 );
} }
inline int eh_ensure_dma_competed ( struct eh_softc *sc, int type ) inline int
eh_ensure_dma_competed(sc, type)
struct eh_softc *sc;
int type;
{ {
register int status = GetReg ( EH_COMMAND ); register int status = GetReg ( EH_COMMAND );
@ -653,7 +687,12 @@ inline int eh_ensure_dma_competed ( struct eh_softc *sc, int type )
/* Do an eh_copyin, but take into consideration ring wrap */ /* Do an eh_copyin, but take into consideration ring wrap */
int eh_copyring ( struct eh_softc *sc, int src, char *dest, int len ) int
eh_copyring(sc, src, dest, len)
struct eh_softc *sc;
int src;
char *dest;
int len;
{ {
if ( (src+len)>sc->sc_rbd ) if ( (src+len)>sc->sc_rbd )
{ {
@ -680,7 +719,12 @@ int eh_copyring ( struct eh_softc *sc, int src, char *dest, int len )
return len; return len;
} }
int eh_copyin ( struct eh_softc *sc, int src, char *dest, int len ) int
eh_copyin(sc, src, dest, len)
struct eh_softc *sc;
int src;
char *dest;
int len;
{ {
int counter; int counter;
int s; int s;
@ -727,7 +771,12 @@ int eh_copyin ( struct eh_softc *sc, int src, char *dest, int len )
return len; return len;
} }
int eh_copyout ( struct eh_softc *sc, char *src, int dest, int len ) int
eh_copyout(sc, src, dest, len)
struct eh_softc *sc;
char *src;
int dest;
int len;
{ {
int counter; int counter;
int s; int s;
@ -778,7 +827,9 @@ int eh_copyout ( struct eh_softc *sc, char *src, int dest, int len )
#define ALLOCBLK(v,s) (v)=card_freestart; \ #define ALLOCBLK(v,s) (v)=card_freestart; \
card_freestart+=((s)+0xff)&(~0xff) card_freestart+=((s)+0xff)&(~0xff)
void ehinit ( struct eh_softc *sc ) void
ehinit(sc)
struct eh_softc *sc;
{ {
int card_freestart; int card_freestart;
int counter; int counter;
@ -792,7 +843,7 @@ void ehinit ( struct eh_softc *sc )
ALLOCBLK ( sc->sc_rbs, (RXBUF_SIZE*NRXBUF) ); ALLOCBLK ( sc->sc_rbs, (RXBUF_SIZE*NRXBUF) );
sc->sc_rbd = card_freestart; sc->sc_rbd = card_freestart;
sc->sc_nxtpkt = sc->sc_rbs; sc->sc_nxtpkt = sc->sc_rbs + 0x100;
/* Allocate transmit buffers */ /* Allocate transmit buffers */
for ( counter=0; counter<NTXBUF; counter++ ) for ( counter=0; counter<NTXBUF; counter++ )
@ -861,11 +912,11 @@ void ehinit ( struct eh_softc *sc )
PAGE(1); PAGE(1);
SetReg ( EH_CURR, sc->sc_nxtpkt >> 8 );
for ( counter=0; counter<6; counter++ ) for ( counter=0; counter<6; counter++ )
SetReg ( ((counter+1)<<2), sc->sc_arpcom.ac_enaddr[counter] ); SetReg ( ((counter+1)<<2), sc->sc_arpcom.ac_enaddr[counter] );
SetReg ( EH_CURR, sc->sc_rbs >> 8 );
/* Put controller into start mode COM = 0x22 */ /* Put controller into start mode COM = 0x22 */
SetReg ( EH_COMMAND, 0x22 ); SetReg ( EH_COMMAND, 0x22 );
@ -882,7 +933,9 @@ void ehinit ( struct eh_softc *sc )
ehstart(&sc->sc_arpcom.ac_if); ehstart(&sc->sc_arpcom.ac_if);
} }
int ehstop ( struct eh_softc *sc ) int
ehstop(sc)
struct eh_softc *sc;
{ {
int s = splimp (); int s = splimp ();
eh_stop_controller (sc); eh_stop_controller (sc);
@ -897,7 +950,9 @@ int ehstop ( struct eh_softc *sc )
#undef MYTEST #undef MYTEST
void eh_rint ( struct eh_softc *sc ) void
eh_rint(sc)
struct eh_softc *sc;
{ {
struct ifnet *ifp = &sc->sc_arpcom.ac_if; struct ifnet *ifp = &sc->sc_arpcom.ac_if;
struct mbuf *top, **mp, *m; struct mbuf *top, **mp, *m;
@ -941,33 +996,8 @@ void eh_rint ( struct eh_softc *sc )
} }
rxstatus = hdr.rx_status; rxstatus = hdr.rx_status;
/* Apparently, older NE2000 clones read the MSB of len wrong */
/* This code recalculates it. It seems as if the DP83905 */
/* does not get it wrong */
#ifdef MYTEST
old=hdr.rx_rbc1;
totlen = hdr.rx_rbc0;
if ( (hdr.rx_nxtpkt<<8) > ptr )
hdr.rx_rbc1 = (hdr.rx_nxtpkt<<8)-ptr;
else
hdr.rx_rbc1 = (hdr.rx_nxtpkt<<8)+(sc->sc_rbd-sc->sc_rbs)-ptr;
hdr.rx_rbc1=(hdr.rx_rbc1>>8)-1;
if ( ((totlen&255)+4)>256 )
hdr.rx_rbc1--;
#endif
totlen = (hdr.rx_rbc1<<8) + hdr.rx_rbc0; totlen = (hdr.rx_rbc1<<8) + hdr.rx_rbc0;
#ifdef MYTEST
if (old!=hdr.rx_rbc1)
printf ( "CODE CAUGHT CHIP Actual %02x%02x CALC%02x%02x",
old, (int)hdr.rx_rbc0, (int)hdr.rx_rbc1, (int)hdr.rx_rbc0 );
#endif
ptr+=4; ptr+=4;
/* Check the packet's status */ /* Check the packet's status */
@ -986,7 +1016,9 @@ if (old!=hdr.rx_rbc1)
return; return;
} }
sc->sc_nxtpkt = hdr.rx_nxtpkt << 8;
if (0)
printf ( "pulling packet at %08x, next at %08x\n", thispacket, sc->sc_nxtpkt );
if ( totlen>ETHER_MAX_LEN ) if ( totlen>ETHER_MAX_LEN )
{ {
@ -1020,7 +1052,7 @@ if (old!=hdr.rx_rbc1)
MGET(m, M_DONTWAIT, MT_DATA); MGET(m, M_DONTWAIT, MT_DATA);
if ( m==0 ) { if ( m==0 ) {
m_freem(top); m_freem(top);
return; goto skip;
} }
len = MLEN; len = MLEN;
} }
@ -1040,23 +1072,32 @@ if (old!=hdr.rx_rbc1)
mp = &m->m_next; mp = &m->m_next;
} }
m = top;
ifp->if_ipackets++;
ether_input(ifp, &eh, m );
skip:
/* Ok, I'm done with this packet */ /* Ok, I'm done with this packet */
sc->sc_nxtpkt = hdr.rx_nxtpkt << 8;
/* Set the boundary pointer on the ring buffer */ /* Set the boundary pointer on the ring buffer */
bnry = (sc->sc_nxtpkt>>8)-1; bnry = (sc->sc_nxtpkt>>8)-1;
if ( bnry < sc->sc_rbs ) if ( bnry < (sc->sc_rbs>>8) )
bnry = sc->sc_rbd-1; bnry = (sc->sc_rbd>>8)-1;
SetReg ( EH_BNRY, bnry ); SetReg ( EH_BNRY, bnry );
m = top; PAGE(1);
ifp->if_ipackets++; rbend = GetReg ( EH_CURR ) << 8;
ether_input(ifp, &eh, m ); PAGE(0);
} }
} }
} }
int ehintr ( void *arg ) int
ehintr(arg)
void *arg;
{ {
struct eh_softc *sc = arg; struct eh_softc *sc = arg;
register int isr = GetReg ( EH_ISR ); /* Is char of int faster ? */ register int isr = GetReg ( EH_ISR ); /* Is char of int faster ? */
@ -1169,7 +1210,9 @@ int ehintr ( void *arg )
/* Auxilary routines ********************************************************/ /* Auxilary routines ********************************************************/
/****************************************************************************/ /****************************************************************************/
void eh_shutdown ( void *arg ) void
eh_shutdown(arg)
void *arg;
{ {
struct eh_softc *sc = (struct eh_softc *)arg; struct eh_softc *sc = (struct eh_softc *)arg;