mirror of
https://github.com/freebsd/freebsd-src
synced 2024-10-06 00:20:29 +00:00
Patches from driver author in PR#2010.
Submitter requests that this patch be merged into 2.2. Submitted by: seki@sysrap.cs.fujitsu.co.jp
This commit is contained in:
parent
f283fbcac1
commit
d4e29514fc
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=19781
|
@ -21,7 +21,7 @@
|
|||
*/
|
||||
|
||||
/*
|
||||
* $Id: if_fe.c,v 1.19 1996/09/08 10:44:11 phk Exp $
|
||||
* $Id: if_fe.c,v 1.20 1996/10/07 17:50:00 wollman Exp $
|
||||
*
|
||||
* Device driver for Fujitsu MB86960A/MB86965A based Ethernet cards.
|
||||
* To be used with FreeBSD 2.x
|
||||
|
@ -70,7 +70,9 @@
|
|||
* o To test IPX codes.
|
||||
*/
|
||||
|
||||
#include "isa.h"
|
||||
#include "fe.h"
|
||||
#include "crd.h"
|
||||
#include "bpfilter.h"
|
||||
|
||||
#include <sys/param.h>
|
||||
|
@ -121,11 +123,11 @@
|
|||
|
||||
#include <machine/clock.h>
|
||||
|
||||
#include <i386/isa/isa.h>
|
||||
#include <i386/isa/isa_device.h>
|
||||
#include <i386/isa/icu.h>
|
||||
|
||||
/* PCCARD suport */
|
||||
#include "crd.h"
|
||||
#if NCRD > 0
|
||||
#include <sys/select.h>
|
||||
#include <pccard/card.h>
|
||||
|
@ -179,7 +181,7 @@
|
|||
#define FE_FLAGS_OVERRIDE_DLCR6 0x0080
|
||||
|
||||
/* Shouldn't these be defined somewhere else such as isa_device.h? */
|
||||
#define NO_IOADDR 0xFFFFFFFF
|
||||
#define NO_IOADDR (-1)
|
||||
#define NO_IRQ 0
|
||||
|
||||
/*
|
||||
|
@ -226,6 +228,9 @@ static struct fe_softc {
|
|||
u_char txb_count; /* number of packets in TX buffer */
|
||||
u_char txb_sched; /* number of scheduled packets */
|
||||
|
||||
/* Excessive collision counter (see fe_tint() for details. */
|
||||
u_char tx_excolls; /* # of excessive collisions. */
|
||||
|
||||
/* Multicast address filter management. */
|
||||
u_char filter_change; /* MARs must be changed ASAP. */
|
||||
struct fe_filter filter;/* new filter value. */
|
||||
|
@ -248,13 +253,19 @@ static void fe_watchdog ( struct ifnet * );
|
|||
/* Local functions. Order of declaration is confused. FIXME. */
|
||||
static int fe_probe_fmv ( DEVICE *, struct fe_softc * );
|
||||
static int fe_probe_ati ( DEVICE *, struct fe_softc * );
|
||||
static void fe_init_ati ( struct fe_softc * );
|
||||
static int fe_probe_gwy ( DEVICE *, struct fe_softc * );
|
||||
#if NCRD > 0
|
||||
static int fe_probe_mbh ( DEVICE *, struct fe_softc * );
|
||||
static void fe_init_mbh ( struct fe_softc * );
|
||||
static int fe_probe_tdk ( DEVICE *, struct fe_softc * );
|
||||
#endif
|
||||
static int fe_get_packet ( struct fe_softc *, u_short );
|
||||
static void fe_stop ( int );
|
||||
static void fe_tint ( struct fe_softc *, u_char );
|
||||
static void fe_rint ( struct fe_softc *, u_char );
|
||||
static void fe_xmit ( struct fe_softc * );
|
||||
static void fe_emptybuffer ( struct fe_softc * );
|
||||
static void fe_write_mbufs ( struct fe_softc *, struct mbuf * );
|
||||
static struct fe_filter
|
||||
fe_mcaf ( struct fe_softc * );
|
||||
|
@ -358,6 +369,7 @@ static int
|
|||
feinit(struct pccard_dev *dp, int first)
|
||||
{
|
||||
/* validate unit number. */
|
||||
struct fe_softc *sc;
|
||||
if (first) {
|
||||
if (dp->isahd.id_unit >= NFE)
|
||||
return (ENODEV);
|
||||
|
@ -368,6 +380,8 @@ feinit(struct pccard_dev *dp, int first)
|
|||
#if FE_DEBUG >= 2
|
||||
printf("Start Probe\n");
|
||||
#endif
|
||||
sc = &fe_softc[dp->isahd.id_unit];
|
||||
memcpy( sc->sc_enaddr, dp->misc, ETHER_ADDR_LEN );
|
||||
if (fe_probe(&dp->isahd) == 0)
|
||||
return (ENXIO);
|
||||
#if FE_DEBUG >= 2
|
||||
|
@ -398,6 +412,7 @@ feinit(struct pccard_dev *dp, int first)
|
|||
static void
|
||||
feunload(struct pccard_dev *dp)
|
||||
{
|
||||
struct fe_softc *sc = &fe_softc[dp->isahd.id_unit];
|
||||
printf("fe%d: unload\n", dp->isahd.id_unit);
|
||||
fe_stop(dp->isahd.id_unit);
|
||||
}
|
||||
|
@ -436,7 +451,10 @@ static struct fe_probe_list const fe_probe_list [] =
|
|||
{
|
||||
{ fe_probe_fmv, fe_fmv_addr },
|
||||
{ fe_probe_ati, fe_ati_addr },
|
||||
#if NCRD > 0
|
||||
{ fe_probe_mbh, NULL }, /* PCMCIAs cannot be auto-detected. */
|
||||
{ fe_probe_tdk, NULL },
|
||||
#endif
|
||||
{ NULL, NULL }
|
||||
};
|
||||
|
||||
|
@ -733,7 +751,15 @@ fe_probe_fmv ( DEVICE * dev, struct fe_softc * sc )
|
|||
/* Check if our I/O address matches config info. on EEPROM. */
|
||||
n = ( inb( sc->ioaddr[ FE_FMV2 ] ) & FE_FMV2_IOS )
|
||||
>> FE_FMV2_IOS_SHIFT;
|
||||
if ( baseaddr[ n ] != sc->iobase ) return 0;
|
||||
if ( baseaddr[ n ] != sc->iobase ) {
|
||||
#if 0
|
||||
/* May not work on some revisions of the cards... FIXME. */
|
||||
return 0;
|
||||
#else
|
||||
/* Just log the fact and see what happens... FIXME. */
|
||||
log( LOG_WARNING, "fe%d: strange I/O config?n", sc->sc_unit );
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Find the "hardware revision." */
|
||||
revision = inb( sc->ioaddr[ FE_FMV1 ] ) & FE_FMV1_REV;
|
||||
|
@ -749,6 +775,9 @@ fe_probe_fmv ( DEVICE * dev, struct fe_softc * sc )
|
|||
case 8:
|
||||
sc->typestr = "FMV-183";
|
||||
break;
|
||||
case 12:
|
||||
sc->typestr = "FMV-183 (on-board)";
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case FE_FMV0_MEDIUM_T | FE_FMV0_MEDIUM_5:
|
||||
|
@ -1068,6 +1097,9 @@ fe_probe_ati ( DEVICE * dev, struct fe_softc * sc )
|
|||
fe_dump( LOG_INFO, sc, "ATI found" );
|
||||
#endif
|
||||
|
||||
/* Setup hooks. This may solves a nasty bug. FIXME. */
|
||||
sc->init = fe_init_ati;
|
||||
|
||||
/* Initialize 86965. */
|
||||
DELAY( 200 );
|
||||
outb( sc->ioaddr[ FE_DLCR6 ], sc->proto_dlcr6 | FE_D6_DLC_DISABLE );
|
||||
|
@ -1100,36 +1132,132 @@ fe_probe_ati ( DEVICE * dev, struct fe_softc * sc )
|
|||
return ( 0 );
|
||||
}
|
||||
|
||||
/* ATI specific initialization routine. */
|
||||
static void
|
||||
fe_init_ati ( struct fe_softc * sc )
|
||||
{
|
||||
/*
|
||||
* Probe and initialization for Fujitsu MBH10302 PCMCIA Ethernet interface.
|
||||
* I've told that the following operation "Resets" the chip.
|
||||
* Hope this solve a bug which hangs up the driver under
|
||||
* heavy load... FIXME.
|
||||
*/
|
||||
|
||||
/* Minimal initialization of 86965. */
|
||||
DELAY( 200 );
|
||||
outb( sc->ioaddr[ FE_DLCR6 ], sc->proto_dlcr6 | FE_D6_DLC_DISABLE );
|
||||
DELAY( 200 );
|
||||
|
||||
/* "Reset" by wrting into an undocument register location. */
|
||||
outb( sc->ioaddr[ 0x1F ], 0 );
|
||||
|
||||
/* How long do we have to wait after the reset? FIXME. */
|
||||
DELAY( 300 );
|
||||
}
|
||||
|
||||
/*
|
||||
* Probe and initialization for Gateway Communications' old cards.
|
||||
*/
|
||||
static int
|
||||
fe_probe_mbh ( DEVICE * dev, struct fe_softc * sc )
|
||||
fe_probe_gwy ( DEVICE * dev, struct fe_softc * sc )
|
||||
{
|
||||
int i;
|
||||
int i,type;
|
||||
|
||||
static struct fe_simple_probe_struct probe_table [] = {
|
||||
{ FE_DLCR2, 0x70, 0x00 },
|
||||
{ FE_DLCR4, 0x08, 0x00 },
|
||||
/* { FE_DLCR5, 0x80, 0x00 }, Does not work well. */
|
||||
#if 0
|
||||
{ FE_DLCR7, 0xC0, 0x00 },
|
||||
/*
|
||||
* Test *vendor* part of the address for Fujitsu.
|
||||
* The test will gain reliability of probe process, but
|
||||
* it rejects clones by other vendors, or OEM product
|
||||
* supplied by retailer other than Fujitsu.
|
||||
* Test *vendor* part of the address for Gateway.
|
||||
* This test is essential to identify Gateway's cards.
|
||||
* We shuld define some symbolic names for the
|
||||
* following offsets. FIXME.
|
||||
*/
|
||||
{ 0x18, 0xFF, 0x00 },
|
||||
{ 0x19, 0xFF, 0x00 },
|
||||
{ 0x1A, 0xFF, 0x61 },
|
||||
{ 0 }
|
||||
};
|
||||
|
||||
/*
|
||||
* We need explicit IRQ and supported address.
|
||||
* I'm not sure which address and IRQ is possible for Gateway
|
||||
* Ethernet family. The following accepts everything. FIXME.
|
||||
*/
|
||||
{ FE_MBH10, 0xFF, 0x00 },
|
||||
{ FE_MBH11, 0xFF, 0x00 },
|
||||
{ FE_MBH12, 0xFF, 0x0E },
|
||||
#else
|
||||
if ( dev->id_irq == NO_IRQ || ( sc->iobase & ~0x3E0 ) != 0 ) {
|
||||
return ( 0 );
|
||||
}
|
||||
|
||||
#if FE_DEBUG >= 3
|
||||
fe_dump( LOG_INFO, sc, "top of probe" );
|
||||
#endif
|
||||
|
||||
/* Setup an I/O address mapping table. */
|
||||
for ( i = 0; i < MAXREGISTERS; i++ ) {
|
||||
sc->ioaddr[ i ] = sc->iobase + i;
|
||||
}
|
||||
|
||||
/* See if the card is on its address. */
|
||||
if ( !fe_simple_probe( sc, probe_table ) ) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Determine the card type. */
|
||||
sc->typestr = "Gateway Ethernet w/ Fujitsu chipset";
|
||||
|
||||
/* Get our station address from EEPROM. */
|
||||
inblk( sc, 0x18, sc->sc_enaddr, ETHER_ADDR_LEN );
|
||||
|
||||
/*
|
||||
* Program the 86960 as follows:
|
||||
* SRAM: 16KB, 100ns, byte-wide access.
|
||||
* Transmission buffer: 2KB x 2.
|
||||
* System bus interface: 16 bits.
|
||||
* Make sure to clear out ID bits in DLCR7
|
||||
* (They actually are Encoder/Decoder control in NICE.)
|
||||
*/
|
||||
sc->proto_dlcr4 = FE_D4_LBC_DISABLE | FE_D4_CNTRL;
|
||||
sc->proto_dlcr5 = 0;
|
||||
sc->proto_dlcr6 = FE_D6_BUFSIZ_16KB | FE_D6_TXBSIZ_2x2KB
|
||||
| FE_D6_BBW_BYTE | FE_D6_SBW_WORD | FE_D6_SRAM_100ns;
|
||||
sc->proto_dlcr7 = FE_D7_BYTSWP_LH;
|
||||
sc->proto_bmpr13 = 0;
|
||||
|
||||
/* Minimal initialization of 86960. */
|
||||
DELAY( 200 );
|
||||
outb( sc->ioaddr[ FE_DLCR6 ], sc->proto_dlcr6 | FE_D6_DLC_DISABLE );
|
||||
DELAY( 200 );
|
||||
|
||||
/* Disable all interrupts. */
|
||||
outb( sc->ioaddr[ FE_DLCR2 ], 0 );
|
||||
outb( sc->ioaddr[ FE_DLCR3 ], 0 );
|
||||
|
||||
/* That's all. The card occupies 32 I/O addresses, as always. */
|
||||
return 32;
|
||||
}
|
||||
|
||||
#if NCRD > 0
|
||||
/*
|
||||
* Probe and initialization for Fujitsu MBH10302 PCMCIA Ethernet interface.
|
||||
* Note that this is for 10302 only; MBH10304 is handled by fe_probe_tdk().
|
||||
*/
|
||||
static int
|
||||
fe_probe_mbh ( DEVICE * dev, struct fe_softc * sc )
|
||||
{
|
||||
int i,type;
|
||||
|
||||
static struct fe_simple_probe_struct probe_table [] = {
|
||||
{ FE_DLCR0, 0x09, 0x00 },
|
||||
{ FE_DLCR2, 0x79, 0x00 },
|
||||
{ FE_DLCR4, 0x08, 0x00 },
|
||||
{ FE_DLCR6, 0xFF, 0xB6 },
|
||||
/*
|
||||
* The following location has the first byte of the card's
|
||||
* Ethernet (MAC) address.
|
||||
* We can always verify the *first* 2 bits (in Ethernet
|
||||
* bit order) are "global" and "unicast" even for
|
||||
* unknown vendors.
|
||||
* bit order) are "global" and "unicast" for any vendors'.
|
||||
*/
|
||||
{ FE_MBH10, 0x03, 0x00 },
|
||||
#endif
|
||||
|
||||
/* Just a gap? Seems reliable, anyway. */
|
||||
{ 0x12, 0xFF, 0x00 },
|
||||
{ 0x13, 0xFF, 0x00 },
|
||||
|
@ -1140,7 +1268,7 @@ fe_probe_mbh ( DEVICE * dev, struct fe_softc * sc )
|
|||
#if 0
|
||||
{ 0x18, 0xFF, 0xFF },
|
||||
{ 0x19, 0xFF, 0xFF },
|
||||
#endif /* 0 */
|
||||
#endif
|
||||
|
||||
{ 0 }
|
||||
};
|
||||
|
@ -1178,10 +1306,9 @@ fe_probe_mbh ( DEVICE * dev, struct fe_softc * sc )
|
|||
inblk( sc, FE_MBH10, sc->sc_enaddr, ETHER_ADDR_LEN );
|
||||
|
||||
/* Make sure we got a valid station address. */
|
||||
if ( ( sc->sc_enaddr[ 0 ] & 0x03 ) != 0x00
|
||||
|| ( sc->sc_enaddr[ 0 ] == 0x00
|
||||
if ( sc->sc_enaddr[ 0 ] == 0x00
|
||||
&& sc->sc_enaddr[ 1 ] == 0x00
|
||||
&& sc->sc_enaddr[ 2 ] == 0x00 ) ) return 0;
|
||||
&& sc->sc_enaddr[ 2 ] == 0x00 ) return 0;
|
||||
|
||||
/*
|
||||
* Program the 86960 as follows:
|
||||
|
@ -1240,6 +1367,92 @@ fe_init_mbh ( struct fe_softc * sc )
|
|||
outb( sc->ioaddr[ FE_MBH0 ], FE_MBH0_MAGIC | FE_MBH0_INTR_ENABLE );
|
||||
}
|
||||
|
||||
#endif /* NCRD > 0 */
|
||||
|
||||
#if NCRD > 0
|
||||
/*
|
||||
* Probe and initialization for TDK/CONTEC PCMCIA Ethernet interface.
|
||||
* by MASUI Kenji <masui@cs.titech.ac.jp>
|
||||
*
|
||||
* (Contec uses TDK Ethenet chip -- hosokawa)
|
||||
*
|
||||
* This version of fe_probe_tdk has been rewrote to handle
|
||||
* *generic* PC card implementation of Fujitsu MB8696x family. The
|
||||
* name _tdk is just for a historical reason. :-)
|
||||
*/
|
||||
static int
|
||||
fe_probe_tdk ( DEVICE * dev, struct fe_softc * sc )
|
||||
{
|
||||
int i;
|
||||
|
||||
static struct fe_simple_probe_struct probe_table [] = {
|
||||
{ FE_DLCR2, 0x70, 0x00 },
|
||||
{ FE_DLCR4, 0x08, 0x00 },
|
||||
/* { FE_DLCR5, 0x80, 0x00 }, Does not work well. */
|
||||
{ 0 }
|
||||
};
|
||||
|
||||
if ( dev->id_irq == NO_IRQ ) {
|
||||
return ( 0 );
|
||||
}
|
||||
|
||||
/* Setup an I/O address mapping table. */
|
||||
for ( i = 0; i < MAXREGISTERS; i++ ) {
|
||||
sc->ioaddr[ i ] = sc->iobase + i;
|
||||
}
|
||||
|
||||
/*
|
||||
* See if C-NET(PC)C is on its address.
|
||||
*/
|
||||
|
||||
if ( !fe_simple_probe( sc, probe_table ) ) return 0;
|
||||
|
||||
/* Determine the card type. */
|
||||
sc->typestr = "Generic MB8696x Ethernet (PCMCIA)";
|
||||
|
||||
/*
|
||||
* Initialize constants in the per-line structure.
|
||||
*/
|
||||
|
||||
/* The station address *must*be* already in sc_enaddr;
|
||||
Make sure we got a valid station address. */
|
||||
if ( ( sc->sc_enaddr[ 0 ] & 0x03 ) != 0x00
|
||||
|| ( sc->sc_enaddr[ 0 ] == 0x00
|
||||
&& sc->sc_enaddr[ 1 ] == 0x00
|
||||
&& sc->sc_enaddr[ 2 ] == 0x00 ) ) return 0;
|
||||
|
||||
/*
|
||||
* Program the 86965 as follows:
|
||||
* SRAM: 32KB, 100ns, byte-wide access.
|
||||
* Transmission buffer: 4KB x 2.
|
||||
* System bus interface: 16 bits.
|
||||
* XXX: Should we remove IDENT_NICE from DLCR7? Or,
|
||||
* even add IDENT_EC instead? FIXME.
|
||||
*/
|
||||
sc->proto_dlcr4 = FE_D4_LBC_DISABLE | FE_D4_CNTRL;
|
||||
sc->proto_dlcr5 = 0;
|
||||
sc->proto_dlcr6 = FE_D6_BUFSIZ_32KB | FE_D6_TXBSIZ_2x4KB
|
||||
| FE_D6_BBW_BYTE | FE_D6_SBW_WORD | FE_D6_SRAM_100ns;
|
||||
sc->proto_dlcr7 = FE_D7_BYTSWP_LH | FE_D7_IDENT_NICE;
|
||||
sc->proto_bmpr13 = FE_B13_TPTYPE_UTP | FE_B13_PORT_AUTO;
|
||||
|
||||
/* Minimul initialization of 86960. */
|
||||
DELAY( 200 );
|
||||
outb( sc->ioaddr[ FE_DLCR6 ], sc->proto_dlcr6 | FE_D6_DLC_DISABLE );
|
||||
DELAY( 200 );
|
||||
|
||||
/* Disable all interrupts. */
|
||||
outb( sc->ioaddr[ FE_DLCR2 ], 0 );
|
||||
outb( sc->ioaddr[ FE_DLCR3 ], 0 );
|
||||
|
||||
/*
|
||||
* That's all. C-NET(PC)C occupies 16 I/O addresses.
|
||||
* XXX: Are there any card with 32 I/O addresses? FIXME.
|
||||
*/
|
||||
return 16;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Install interface into kernel networking data structures
|
||||
*/
|
||||
|
@ -1453,13 +1666,11 @@ fe_watchdog ( struct ifnet *ifp )
|
|||
log( LOG_ERR, "fe%d: transmission timeout (%d+%d)%s\n",
|
||||
ifp->if_unit, sc->txb_sched, sc->txb_count,
|
||||
( ifp->if_flags & IFF_UP ) ? "" : " when down" );
|
||||
#endif
|
||||
|
||||
/* Suggest users a possible cause. */
|
||||
if ( ifp->if_oerrors > 0 ) {
|
||||
log( LOG_WARNING, "fe%d: wrong IRQ setting in config?",
|
||||
if ( sc->sc_if.if_opackets == 0 && sc->sc_if.if_ipackets == 0 ) {
|
||||
log( LOG_WARNING, "fe%d: wrong IRQ setting in config?\n",
|
||||
ifp->if_unit );
|
||||
}
|
||||
#endif
|
||||
|
||||
#if FE_DEBUG >= 3
|
||||
fe_dump( LOG_INFO, sc, NULL );
|
||||
|
@ -1581,11 +1792,12 @@ fe_init ( int unit )
|
|||
#if FE_DEBUG >= 3
|
||||
fe_dump( LOG_INFO, sc, "just after enabling DLC" );
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Make sure to empty the receive buffer.
|
||||
*
|
||||
* This may be redundant, but *if* the receive buffer were full
|
||||
* at this point, the driver would hang. I have experienced
|
||||
* at this point, then the driver would hang. I have experienced
|
||||
* some strange hang-up just after UP. I hope the following
|
||||
* code solve the problem.
|
||||
*
|
||||
|
@ -1593,29 +1805,24 @@ fe_init ( int unit )
|
|||
* I think the receive buffer cannot have any packets at this
|
||||
* point in this version. The following code *must* be
|
||||
* redundant now. FIXME.
|
||||
*
|
||||
* I've heard a rumore that on some PC card implementation of
|
||||
* 8696x, the receive buffer can have some data at this point.
|
||||
* The following message helps discovering the fact. FIXME.
|
||||
*/
|
||||
for ( i = 0; i < FE_MAX_RECV_COUNT; i++ ) {
|
||||
if ( inb( sc->ioaddr[ FE_DLCR5 ] ) & FE_D5_BUFEMP ) break;
|
||||
outb( sc->ioaddr[ FE_BMPR14 ], FE_B14_SKIP );
|
||||
}
|
||||
#if FE_DEBUG >= 1
|
||||
if ( i >= FE_MAX_RECV_COUNT ) {
|
||||
log( LOG_ERR, "fe%d: cannot empty receive buffer\n",
|
||||
if ( !( inb( sc->ioaddr[ FE_DLCR5 ] ) & FE_D5_BUFEMP ) ) {
|
||||
log( LOG_WARNING,
|
||||
"fe%d: receive buffer has some data after reset\n",
|
||||
sc->sc_unit );
|
||||
|
||||
fe_emptybuffer( sc );
|
||||
}
|
||||
#endif
|
||||
#if FE_DEBUG >= 3
|
||||
if ( i < FE_MAX_RECV_COUNT ) {
|
||||
log( LOG_INFO, "fe%d: receive buffer emptied (%d)\n",
|
||||
sc->sc_unit, i );
|
||||
}
|
||||
#endif
|
||||
|
||||
#if FE_DEBUG >= 3
|
||||
fe_dump( LOG_INFO, sc, "after ERB loop" );
|
||||
#endif
|
||||
|
||||
/* Do we need this here? FIXME. */
|
||||
/* Do we need this here? Actually, no. I must be paranoia. */
|
||||
outb( sc->ioaddr[ FE_DLCR0 ], 0xFF ); /* Clear all bits. */
|
||||
outb( sc->ioaddr[ FE_DLCR1 ], 0xFF ); /* ditto. */
|
||||
|
||||
|
@ -1665,6 +1872,7 @@ fe_xmit ( struct fe_softc * sc )
|
|||
sc->txb_sched = sc->txb_count;
|
||||
sc->txb_count = 0;
|
||||
sc->txb_free = sc->txb_size;
|
||||
sc->tx_excolls = 0;
|
||||
|
||||
/* Start transmitter, passing packets in TX buffer. */
|
||||
outb( sc->ioaddr[ FE_BMPR10 ], sc->txb_sched | FE_B10_START );
|
||||
|
@ -1762,7 +1970,8 @@ fe_start ( struct ifnet *ifp )
|
|||
* (i.e., minimum packet sized) packets rapidly. An 8KB
|
||||
* buffer can hold 130 blocks of 62 bytes long...
|
||||
*/
|
||||
if ( sc->txb_free < ETHER_MAX_LEN - ETHER_CRC_LEN + FE_DATA_LEN_LEN ) {
|
||||
if ( sc->txb_free
|
||||
< ETHER_MAX_LEN - ETHER_CRC_LEN + FE_DATA_LEN_LEN ) {
|
||||
/* No room. */
|
||||
goto indicate_active;
|
||||
}
|
||||
|
@ -1790,7 +1999,9 @@ fe_start ( struct ifnet *ifp )
|
|||
fe_write_mbufs( sc, m );
|
||||
|
||||
/* Start transmitter if it's idle. */
|
||||
if ( sc->txb_sched == 0 ) fe_xmit( sc );
|
||||
if ( ( sc->txb_count > 0 ) && ( sc->txb_sched == 0 ) ) {
|
||||
fe_xmit( sc );
|
||||
}
|
||||
|
||||
/*
|
||||
* Tap off here if there is a bpf listener,
|
||||
|
@ -1835,9 +2046,69 @@ fe_start ( struct ifnet *ifp )
|
|||
* Drop (skip) a packet from receive buffer in 86960 memory.
|
||||
*/
|
||||
static void
|
||||
fe_droppacket ( struct fe_softc * sc )
|
||||
fe_droppacket ( struct fe_softc * sc, int len )
|
||||
{
|
||||
int i;
|
||||
|
||||
/*
|
||||
* 86960 manual says that we have to read 8 bytes from the buffer
|
||||
* before skip the packets and that there must be more than 8 bytes
|
||||
* remaining in the buffer when issue a skip command.
|
||||
* Remember, we have already read 4 bytes before come here.
|
||||
*/
|
||||
if ( len > 12 ) {
|
||||
/* Read 4 more bytes, and skip the rest of the packet. */
|
||||
( void )inw( sc->ioaddr[ FE_BMPR8 ] );
|
||||
( void )inw( sc->ioaddr[ FE_BMPR8 ] );
|
||||
outb( sc->ioaddr[ FE_BMPR14 ], FE_B14_SKIP );
|
||||
} else {
|
||||
/* We should not come here unless receiving RUNTs. */
|
||||
for ( i = 0; i < len; i += 2 ) {
|
||||
( void )inw( sc->ioaddr[ FE_BMPR8 ] );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Empty receiving buffer.
|
||||
*/
|
||||
static void
|
||||
fe_emptybuffer ( struct fe_softc * sc )
|
||||
{
|
||||
int i;
|
||||
u_char saved_dlcr5;
|
||||
|
||||
#if FE_DEBUG >= 1
|
||||
log( LOG_WARNING, "fe%d: emptying receive buffer", sc->sc_unit );
|
||||
#endif
|
||||
/*
|
||||
* Stop receiving packets, temporarily.
|
||||
*/
|
||||
saved_dlcr5 = inb( sc->ioaddr[ FE_DLCR5 ] );
|
||||
outb( sc->ioaddr[ FE_DLCR5 ], sc->proto_dlcr5 );
|
||||
|
||||
/*
|
||||
* When we come here, the receive buffer management should
|
||||
* have been broken. So, we cannot use skip operation.
|
||||
*/
|
||||
for ( i = 0; i < sc->txb_size; i += 2 ) {
|
||||
if ( inb( sc->ioaddr[ FE_DLCR5 ] ) & FE_D5_BUFEMP ) break;
|
||||
( void )inw( sc->ioaddr[ FE_BMPR8 ] );
|
||||
}
|
||||
|
||||
/*
|
||||
* Double check.
|
||||
*/
|
||||
if ( inb( sc->ioaddr[ FE_DLCR5 ] ) & FE_D5_BUFEMP ) {
|
||||
log( LOG_ERR, "fe%d: could not empty receive buffer\n",
|
||||
sc->sc_unit );
|
||||
/* Hmm. What should I do if this happens? FIXME. */
|
||||
}
|
||||
|
||||
/*
|
||||
* Restart receiving packets.
|
||||
*/
|
||||
outb( sc->ioaddr[ FE_DLCR5 ], saved_dlcr5 );
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -1870,15 +2141,8 @@ fe_tint ( struct fe_softc * sc, u_char tstat )
|
|||
#endif
|
||||
|
||||
/*
|
||||
* Update statistics.
|
||||
*/
|
||||
sc->sc_if.if_collisions += 16;
|
||||
sc->sc_if.if_oerrors++;
|
||||
sc->sc_if.if_opackets += sc->txb_sched - left;
|
||||
|
||||
/*
|
||||
* Collision statistics has been updated.
|
||||
* Clear the collision flag on 86960 now to avoid confusion.
|
||||
* Clear the collision flag (in 86960) here
|
||||
* to avoid confusing statistics.
|
||||
*/
|
||||
outb( sc->ioaddr[ FE_DLCR0 ], FE_D0_COLLID );
|
||||
|
||||
|
@ -1897,7 +2161,9 @@ fe_tint ( struct fe_softc * sc, u_char tstat )
|
|||
*/
|
||||
outb( sc->ioaddr[ FE_BMPR11 ],
|
||||
FE_B11_CTRL_SKIP | FE_B11_MODE1 );
|
||||
sc->txb_sched = left - 1;
|
||||
|
||||
/* Update statistics. */
|
||||
sc->tx_excolls++;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -1953,10 +2219,12 @@ fe_tint ( struct fe_softc * sc, u_char tstat )
|
|||
}
|
||||
|
||||
/*
|
||||
* Update total number of successfully
|
||||
* transmitted packets.
|
||||
* Update transmission statistics.
|
||||
* Be sure to reflect number of excessive collisions.
|
||||
*/
|
||||
sc->sc_if.if_opackets += sc->txb_sched;
|
||||
sc->sc_if.if_opackets += sc->txb_sched - sc->tx_excolls;
|
||||
sc->sc_if.if_oerrors += sc->tx_excolls;
|
||||
sc->sc_if.if_collisions += sc->tx_excolls * 16;
|
||||
sc->txb_sched = 0;
|
||||
|
||||
/*
|
||||
|
@ -2031,19 +2299,6 @@ fe_rint ( struct fe_softc * sc, u_char rstat )
|
|||
sc->sc_unit, status );
|
||||
#endif
|
||||
|
||||
/*
|
||||
* If there was an error, update statistics and drop
|
||||
* the packet, unless the interface is in promiscuous
|
||||
* mode.
|
||||
*/
|
||||
if ( ( status & 0xF0 ) != 0x20 ) {
|
||||
if ( !( sc->sc_if.if_flags & IFF_PROMISC ) ) {
|
||||
sc->sc_if.if_ierrors++;
|
||||
fe_droppacket(sc);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Extract the packet length.
|
||||
* It is a sum of a header (14 bytes) and a payload.
|
||||
|
@ -2052,42 +2307,44 @@ fe_rint ( struct fe_softc * sc, u_char rstat )
|
|||
len = inw( sc->ioaddr[ FE_BMPR8 ] );
|
||||
|
||||
/*
|
||||
* MB86965 checks the packet length and drop big packet
|
||||
* If there was an error, update statistics and drop
|
||||
* the packet, unless the interface is in promiscuous
|
||||
* mode.
|
||||
*/
|
||||
if ( ( status & 0xF0 ) != 0x20 ) {
|
||||
if ( !( sc->sc_if.if_flags & IFF_PROMISC ) ) {
|
||||
sc->sc_if.if_ierrors++;
|
||||
fe_droppacket( sc, len );
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* MB86960 checks the packet length and drop big packet
|
||||
* before passing it to us. There are no chance we can
|
||||
* get big packets through it, even if they are actually
|
||||
* sent over a line. Hence, if the length exceeds
|
||||
* the specified limit, it means some serious failure,
|
||||
* such as out-of-sync on receive buffer management.
|
||||
*
|
||||
* Is this statement true? FIXME.
|
||||
* Same for short packets, since we have programmed
|
||||
* 86960 to drop short packets.
|
||||
*/
|
||||
if ( len > ETHER_MAX_LEN - ETHER_CRC_LEN || len < ETHER_MIN_LEN- ETHER_CRC_LEN ) {
|
||||
#if FE_DEBUG >= 2
|
||||
if ( len > ETHER_MAX_LEN - ETHER_CRC_LEN
|
||||
|| len < ETHER_MIN_LEN - ETHER_CRC_LEN ) {
|
||||
#if FE_DEBUG >= 1
|
||||
log( LOG_WARNING,
|
||||
"fe%d: received a %s packet? (%u bytes)\n",
|
||||
sc->sc_unit,
|
||||
len < ETHER_MIN_SIZE- ETHER_CRC_SIZE ? "partial" : "big",
|
||||
len < ETHER_MIN_LEN - ETHER_CRC_LEN
|
||||
? "partial" : "big",
|
||||
len );
|
||||
#endif
|
||||
sc->sc_if.if_ierrors++;
|
||||
fe_droppacket( sc );
|
||||
fe_emptybuffer( sc );
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check for a short (RUNT) packet. We *do* check
|
||||
* but do nothing other than print a message.
|
||||
* Short packets are illegal, but does nothing bad
|
||||
* if it carries data for upper layer.
|
||||
*/
|
||||
#if FE_DEBUG >= 2
|
||||
if ( len < ETHER_MIN_LEN - ETHER_CRC_LEN) {
|
||||
log( LOG_WARNING,
|
||||
"fe%d: received a short packet? (%u bytes)\n",
|
||||
sc->sc_unit, len );
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Go get a packet.
|
||||
*/
|
||||
|
@ -2099,7 +2356,7 @@ fe_rint ( struct fe_softc * sc, u_char rstat )
|
|||
sc->sc_unit, len );
|
||||
#endif
|
||||
sc->sc_if.if_ierrors++;
|
||||
fe_droppacket( sc );
|
||||
fe_droppacket( sc, len );
|
||||
|
||||
/*
|
||||
* We stop receiving packets, even if there are
|
||||
|
@ -2588,7 +2845,8 @@ fe_write_mbufs ( struct fe_softc *sc, struct mbuf *m )
|
|||
* it should be a bug of upper layer. We just ignore it.
|
||||
* ... Partial (too short) packets, neither.
|
||||
*/
|
||||
if ( ! ETHER_IS_VALID_LEN(length + ETHER_CRC_LEN)) {
|
||||
if ( length < ETHER_HDR_LEN
|
||||
|| length > ETHER_MAX_LEN - ETHER_CRC_LEN ) {
|
||||
log( LOG_ERR,
|
||||
"fe%d: got an out-of-spec packet (%u bytes) to send\n",
|
||||
sc->sc_unit, length );
|
||||
|
|
|
@ -21,7 +21,7 @@
|
|||
*/
|
||||
|
||||
/*
|
||||
* $Id: if_fe.c,v 1.19 1996/09/08 10:44:11 phk Exp $
|
||||
* $Id: if_fe.c,v 1.20 1996/10/07 17:50:00 wollman Exp $
|
||||
*
|
||||
* Device driver for Fujitsu MB86960A/MB86965A based Ethernet cards.
|
||||
* To be used with FreeBSD 2.x
|
||||
|
@ -70,7 +70,9 @@
|
|||
* o To test IPX codes.
|
||||
*/
|
||||
|
||||
#include "isa.h"
|
||||
#include "fe.h"
|
||||
#include "crd.h"
|
||||
#include "bpfilter.h"
|
||||
|
||||
#include <sys/param.h>
|
||||
|
@ -121,11 +123,11 @@
|
|||
|
||||
#include <machine/clock.h>
|
||||
|
||||
#include <i386/isa/isa.h>
|
||||
#include <i386/isa/isa_device.h>
|
||||
#include <i386/isa/icu.h>
|
||||
|
||||
/* PCCARD suport */
|
||||
#include "crd.h"
|
||||
#if NCRD > 0
|
||||
#include <sys/select.h>
|
||||
#include <pccard/card.h>
|
||||
|
@ -179,7 +181,7 @@
|
|||
#define FE_FLAGS_OVERRIDE_DLCR6 0x0080
|
||||
|
||||
/* Shouldn't these be defined somewhere else such as isa_device.h? */
|
||||
#define NO_IOADDR 0xFFFFFFFF
|
||||
#define NO_IOADDR (-1)
|
||||
#define NO_IRQ 0
|
||||
|
||||
/*
|
||||
|
@ -226,6 +228,9 @@ static struct fe_softc {
|
|||
u_char txb_count; /* number of packets in TX buffer */
|
||||
u_char txb_sched; /* number of scheduled packets */
|
||||
|
||||
/* Excessive collision counter (see fe_tint() for details. */
|
||||
u_char tx_excolls; /* # of excessive collisions. */
|
||||
|
||||
/* Multicast address filter management. */
|
||||
u_char filter_change; /* MARs must be changed ASAP. */
|
||||
struct fe_filter filter;/* new filter value. */
|
||||
|
@ -248,13 +253,19 @@ static void fe_watchdog ( struct ifnet * );
|
|||
/* Local functions. Order of declaration is confused. FIXME. */
|
||||
static int fe_probe_fmv ( DEVICE *, struct fe_softc * );
|
||||
static int fe_probe_ati ( DEVICE *, struct fe_softc * );
|
||||
static void fe_init_ati ( struct fe_softc * );
|
||||
static int fe_probe_gwy ( DEVICE *, struct fe_softc * );
|
||||
#if NCRD > 0
|
||||
static int fe_probe_mbh ( DEVICE *, struct fe_softc * );
|
||||
static void fe_init_mbh ( struct fe_softc * );
|
||||
static int fe_probe_tdk ( DEVICE *, struct fe_softc * );
|
||||
#endif
|
||||
static int fe_get_packet ( struct fe_softc *, u_short );
|
||||
static void fe_stop ( int );
|
||||
static void fe_tint ( struct fe_softc *, u_char );
|
||||
static void fe_rint ( struct fe_softc *, u_char );
|
||||
static void fe_xmit ( struct fe_softc * );
|
||||
static void fe_emptybuffer ( struct fe_softc * );
|
||||
static void fe_write_mbufs ( struct fe_softc *, struct mbuf * );
|
||||
static struct fe_filter
|
||||
fe_mcaf ( struct fe_softc * );
|
||||
|
@ -358,6 +369,7 @@ static int
|
|||
feinit(struct pccard_dev *dp, int first)
|
||||
{
|
||||
/* validate unit number. */
|
||||
struct fe_softc *sc;
|
||||
if (first) {
|
||||
if (dp->isahd.id_unit >= NFE)
|
||||
return (ENODEV);
|
||||
|
@ -368,6 +380,8 @@ feinit(struct pccard_dev *dp, int first)
|
|||
#if FE_DEBUG >= 2
|
||||
printf("Start Probe\n");
|
||||
#endif
|
||||
sc = &fe_softc[dp->isahd.id_unit];
|
||||
memcpy( sc->sc_enaddr, dp->misc, ETHER_ADDR_LEN );
|
||||
if (fe_probe(&dp->isahd) == 0)
|
||||
return (ENXIO);
|
||||
#if FE_DEBUG >= 2
|
||||
|
@ -398,6 +412,7 @@ feinit(struct pccard_dev *dp, int first)
|
|||
static void
|
||||
feunload(struct pccard_dev *dp)
|
||||
{
|
||||
struct fe_softc *sc = &fe_softc[dp->isahd.id_unit];
|
||||
printf("fe%d: unload\n", dp->isahd.id_unit);
|
||||
fe_stop(dp->isahd.id_unit);
|
||||
}
|
||||
|
@ -436,7 +451,10 @@ static struct fe_probe_list const fe_probe_list [] =
|
|||
{
|
||||
{ fe_probe_fmv, fe_fmv_addr },
|
||||
{ fe_probe_ati, fe_ati_addr },
|
||||
#if NCRD > 0
|
||||
{ fe_probe_mbh, NULL }, /* PCMCIAs cannot be auto-detected. */
|
||||
{ fe_probe_tdk, NULL },
|
||||
#endif
|
||||
{ NULL, NULL }
|
||||
};
|
||||
|
||||
|
@ -733,7 +751,15 @@ fe_probe_fmv ( DEVICE * dev, struct fe_softc * sc )
|
|||
/* Check if our I/O address matches config info. on EEPROM. */
|
||||
n = ( inb( sc->ioaddr[ FE_FMV2 ] ) & FE_FMV2_IOS )
|
||||
>> FE_FMV2_IOS_SHIFT;
|
||||
if ( baseaddr[ n ] != sc->iobase ) return 0;
|
||||
if ( baseaddr[ n ] != sc->iobase ) {
|
||||
#if 0
|
||||
/* May not work on some revisions of the cards... FIXME. */
|
||||
return 0;
|
||||
#else
|
||||
/* Just log the fact and see what happens... FIXME. */
|
||||
log( LOG_WARNING, "fe%d: strange I/O config?n", sc->sc_unit );
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Find the "hardware revision." */
|
||||
revision = inb( sc->ioaddr[ FE_FMV1 ] ) & FE_FMV1_REV;
|
||||
|
@ -749,6 +775,9 @@ fe_probe_fmv ( DEVICE * dev, struct fe_softc * sc )
|
|||
case 8:
|
||||
sc->typestr = "FMV-183";
|
||||
break;
|
||||
case 12:
|
||||
sc->typestr = "FMV-183 (on-board)";
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case FE_FMV0_MEDIUM_T | FE_FMV0_MEDIUM_5:
|
||||
|
@ -1068,6 +1097,9 @@ fe_probe_ati ( DEVICE * dev, struct fe_softc * sc )
|
|||
fe_dump( LOG_INFO, sc, "ATI found" );
|
||||
#endif
|
||||
|
||||
/* Setup hooks. This may solves a nasty bug. FIXME. */
|
||||
sc->init = fe_init_ati;
|
||||
|
||||
/* Initialize 86965. */
|
||||
DELAY( 200 );
|
||||
outb( sc->ioaddr[ FE_DLCR6 ], sc->proto_dlcr6 | FE_D6_DLC_DISABLE );
|
||||
|
@ -1100,36 +1132,132 @@ fe_probe_ati ( DEVICE * dev, struct fe_softc * sc )
|
|||
return ( 0 );
|
||||
}
|
||||
|
||||
/* ATI specific initialization routine. */
|
||||
static void
|
||||
fe_init_ati ( struct fe_softc * sc )
|
||||
{
|
||||
/*
|
||||
* Probe and initialization for Fujitsu MBH10302 PCMCIA Ethernet interface.
|
||||
* I've told that the following operation "Resets" the chip.
|
||||
* Hope this solve a bug which hangs up the driver under
|
||||
* heavy load... FIXME.
|
||||
*/
|
||||
|
||||
/* Minimal initialization of 86965. */
|
||||
DELAY( 200 );
|
||||
outb( sc->ioaddr[ FE_DLCR6 ], sc->proto_dlcr6 | FE_D6_DLC_DISABLE );
|
||||
DELAY( 200 );
|
||||
|
||||
/* "Reset" by wrting into an undocument register location. */
|
||||
outb( sc->ioaddr[ 0x1F ], 0 );
|
||||
|
||||
/* How long do we have to wait after the reset? FIXME. */
|
||||
DELAY( 300 );
|
||||
}
|
||||
|
||||
/*
|
||||
* Probe and initialization for Gateway Communications' old cards.
|
||||
*/
|
||||
static int
|
||||
fe_probe_mbh ( DEVICE * dev, struct fe_softc * sc )
|
||||
fe_probe_gwy ( DEVICE * dev, struct fe_softc * sc )
|
||||
{
|
||||
int i;
|
||||
int i,type;
|
||||
|
||||
static struct fe_simple_probe_struct probe_table [] = {
|
||||
{ FE_DLCR2, 0x70, 0x00 },
|
||||
{ FE_DLCR4, 0x08, 0x00 },
|
||||
/* { FE_DLCR5, 0x80, 0x00 }, Does not work well. */
|
||||
#if 0
|
||||
{ FE_DLCR7, 0xC0, 0x00 },
|
||||
/*
|
||||
* Test *vendor* part of the address for Fujitsu.
|
||||
* The test will gain reliability of probe process, but
|
||||
* it rejects clones by other vendors, or OEM product
|
||||
* supplied by retailer other than Fujitsu.
|
||||
* Test *vendor* part of the address for Gateway.
|
||||
* This test is essential to identify Gateway's cards.
|
||||
* We shuld define some symbolic names for the
|
||||
* following offsets. FIXME.
|
||||
*/
|
||||
{ 0x18, 0xFF, 0x00 },
|
||||
{ 0x19, 0xFF, 0x00 },
|
||||
{ 0x1A, 0xFF, 0x61 },
|
||||
{ 0 }
|
||||
};
|
||||
|
||||
/*
|
||||
* We need explicit IRQ and supported address.
|
||||
* I'm not sure which address and IRQ is possible for Gateway
|
||||
* Ethernet family. The following accepts everything. FIXME.
|
||||
*/
|
||||
{ FE_MBH10, 0xFF, 0x00 },
|
||||
{ FE_MBH11, 0xFF, 0x00 },
|
||||
{ FE_MBH12, 0xFF, 0x0E },
|
||||
#else
|
||||
if ( dev->id_irq == NO_IRQ || ( sc->iobase & ~0x3E0 ) != 0 ) {
|
||||
return ( 0 );
|
||||
}
|
||||
|
||||
#if FE_DEBUG >= 3
|
||||
fe_dump( LOG_INFO, sc, "top of probe" );
|
||||
#endif
|
||||
|
||||
/* Setup an I/O address mapping table. */
|
||||
for ( i = 0; i < MAXREGISTERS; i++ ) {
|
||||
sc->ioaddr[ i ] = sc->iobase + i;
|
||||
}
|
||||
|
||||
/* See if the card is on its address. */
|
||||
if ( !fe_simple_probe( sc, probe_table ) ) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Determine the card type. */
|
||||
sc->typestr = "Gateway Ethernet w/ Fujitsu chipset";
|
||||
|
||||
/* Get our station address from EEPROM. */
|
||||
inblk( sc, 0x18, sc->sc_enaddr, ETHER_ADDR_LEN );
|
||||
|
||||
/*
|
||||
* Program the 86960 as follows:
|
||||
* SRAM: 16KB, 100ns, byte-wide access.
|
||||
* Transmission buffer: 2KB x 2.
|
||||
* System bus interface: 16 bits.
|
||||
* Make sure to clear out ID bits in DLCR7
|
||||
* (They actually are Encoder/Decoder control in NICE.)
|
||||
*/
|
||||
sc->proto_dlcr4 = FE_D4_LBC_DISABLE | FE_D4_CNTRL;
|
||||
sc->proto_dlcr5 = 0;
|
||||
sc->proto_dlcr6 = FE_D6_BUFSIZ_16KB | FE_D6_TXBSIZ_2x2KB
|
||||
| FE_D6_BBW_BYTE | FE_D6_SBW_WORD | FE_D6_SRAM_100ns;
|
||||
sc->proto_dlcr7 = FE_D7_BYTSWP_LH;
|
||||
sc->proto_bmpr13 = 0;
|
||||
|
||||
/* Minimal initialization of 86960. */
|
||||
DELAY( 200 );
|
||||
outb( sc->ioaddr[ FE_DLCR6 ], sc->proto_dlcr6 | FE_D6_DLC_DISABLE );
|
||||
DELAY( 200 );
|
||||
|
||||
/* Disable all interrupts. */
|
||||
outb( sc->ioaddr[ FE_DLCR2 ], 0 );
|
||||
outb( sc->ioaddr[ FE_DLCR3 ], 0 );
|
||||
|
||||
/* That's all. The card occupies 32 I/O addresses, as always. */
|
||||
return 32;
|
||||
}
|
||||
|
||||
#if NCRD > 0
|
||||
/*
|
||||
* Probe and initialization for Fujitsu MBH10302 PCMCIA Ethernet interface.
|
||||
* Note that this is for 10302 only; MBH10304 is handled by fe_probe_tdk().
|
||||
*/
|
||||
static int
|
||||
fe_probe_mbh ( DEVICE * dev, struct fe_softc * sc )
|
||||
{
|
||||
int i,type;
|
||||
|
||||
static struct fe_simple_probe_struct probe_table [] = {
|
||||
{ FE_DLCR0, 0x09, 0x00 },
|
||||
{ FE_DLCR2, 0x79, 0x00 },
|
||||
{ FE_DLCR4, 0x08, 0x00 },
|
||||
{ FE_DLCR6, 0xFF, 0xB6 },
|
||||
/*
|
||||
* The following location has the first byte of the card's
|
||||
* Ethernet (MAC) address.
|
||||
* We can always verify the *first* 2 bits (in Ethernet
|
||||
* bit order) are "global" and "unicast" even for
|
||||
* unknown vendors.
|
||||
* bit order) are "global" and "unicast" for any vendors'.
|
||||
*/
|
||||
{ FE_MBH10, 0x03, 0x00 },
|
||||
#endif
|
||||
|
||||
/* Just a gap? Seems reliable, anyway. */
|
||||
{ 0x12, 0xFF, 0x00 },
|
||||
{ 0x13, 0xFF, 0x00 },
|
||||
|
@ -1140,7 +1268,7 @@ fe_probe_mbh ( DEVICE * dev, struct fe_softc * sc )
|
|||
#if 0
|
||||
{ 0x18, 0xFF, 0xFF },
|
||||
{ 0x19, 0xFF, 0xFF },
|
||||
#endif /* 0 */
|
||||
#endif
|
||||
|
||||
{ 0 }
|
||||
};
|
||||
|
@ -1178,10 +1306,9 @@ fe_probe_mbh ( DEVICE * dev, struct fe_softc * sc )
|
|||
inblk( sc, FE_MBH10, sc->sc_enaddr, ETHER_ADDR_LEN );
|
||||
|
||||
/* Make sure we got a valid station address. */
|
||||
if ( ( sc->sc_enaddr[ 0 ] & 0x03 ) != 0x00
|
||||
|| ( sc->sc_enaddr[ 0 ] == 0x00
|
||||
if ( sc->sc_enaddr[ 0 ] == 0x00
|
||||
&& sc->sc_enaddr[ 1 ] == 0x00
|
||||
&& sc->sc_enaddr[ 2 ] == 0x00 ) ) return 0;
|
||||
&& sc->sc_enaddr[ 2 ] == 0x00 ) return 0;
|
||||
|
||||
/*
|
||||
* Program the 86960 as follows:
|
||||
|
@ -1240,6 +1367,92 @@ fe_init_mbh ( struct fe_softc * sc )
|
|||
outb( sc->ioaddr[ FE_MBH0 ], FE_MBH0_MAGIC | FE_MBH0_INTR_ENABLE );
|
||||
}
|
||||
|
||||
#endif /* NCRD > 0 */
|
||||
|
||||
#if NCRD > 0
|
||||
/*
|
||||
* Probe and initialization for TDK/CONTEC PCMCIA Ethernet interface.
|
||||
* by MASUI Kenji <masui@cs.titech.ac.jp>
|
||||
*
|
||||
* (Contec uses TDK Ethenet chip -- hosokawa)
|
||||
*
|
||||
* This version of fe_probe_tdk has been rewrote to handle
|
||||
* *generic* PC card implementation of Fujitsu MB8696x family. The
|
||||
* name _tdk is just for a historical reason. :-)
|
||||
*/
|
||||
static int
|
||||
fe_probe_tdk ( DEVICE * dev, struct fe_softc * sc )
|
||||
{
|
||||
int i;
|
||||
|
||||
static struct fe_simple_probe_struct probe_table [] = {
|
||||
{ FE_DLCR2, 0x70, 0x00 },
|
||||
{ FE_DLCR4, 0x08, 0x00 },
|
||||
/* { FE_DLCR5, 0x80, 0x00 }, Does not work well. */
|
||||
{ 0 }
|
||||
};
|
||||
|
||||
if ( dev->id_irq == NO_IRQ ) {
|
||||
return ( 0 );
|
||||
}
|
||||
|
||||
/* Setup an I/O address mapping table. */
|
||||
for ( i = 0; i < MAXREGISTERS; i++ ) {
|
||||
sc->ioaddr[ i ] = sc->iobase + i;
|
||||
}
|
||||
|
||||
/*
|
||||
* See if C-NET(PC)C is on its address.
|
||||
*/
|
||||
|
||||
if ( !fe_simple_probe( sc, probe_table ) ) return 0;
|
||||
|
||||
/* Determine the card type. */
|
||||
sc->typestr = "Generic MB8696x Ethernet (PCMCIA)";
|
||||
|
||||
/*
|
||||
* Initialize constants in the per-line structure.
|
||||
*/
|
||||
|
||||
/* The station address *must*be* already in sc_enaddr;
|
||||
Make sure we got a valid station address. */
|
||||
if ( ( sc->sc_enaddr[ 0 ] & 0x03 ) != 0x00
|
||||
|| ( sc->sc_enaddr[ 0 ] == 0x00
|
||||
&& sc->sc_enaddr[ 1 ] == 0x00
|
||||
&& sc->sc_enaddr[ 2 ] == 0x00 ) ) return 0;
|
||||
|
||||
/*
|
||||
* Program the 86965 as follows:
|
||||
* SRAM: 32KB, 100ns, byte-wide access.
|
||||
* Transmission buffer: 4KB x 2.
|
||||
* System bus interface: 16 bits.
|
||||
* XXX: Should we remove IDENT_NICE from DLCR7? Or,
|
||||
* even add IDENT_EC instead? FIXME.
|
||||
*/
|
||||
sc->proto_dlcr4 = FE_D4_LBC_DISABLE | FE_D4_CNTRL;
|
||||
sc->proto_dlcr5 = 0;
|
||||
sc->proto_dlcr6 = FE_D6_BUFSIZ_32KB | FE_D6_TXBSIZ_2x4KB
|
||||
| FE_D6_BBW_BYTE | FE_D6_SBW_WORD | FE_D6_SRAM_100ns;
|
||||
sc->proto_dlcr7 = FE_D7_BYTSWP_LH | FE_D7_IDENT_NICE;
|
||||
sc->proto_bmpr13 = FE_B13_TPTYPE_UTP | FE_B13_PORT_AUTO;
|
||||
|
||||
/* Minimul initialization of 86960. */
|
||||
DELAY( 200 );
|
||||
outb( sc->ioaddr[ FE_DLCR6 ], sc->proto_dlcr6 | FE_D6_DLC_DISABLE );
|
||||
DELAY( 200 );
|
||||
|
||||
/* Disable all interrupts. */
|
||||
outb( sc->ioaddr[ FE_DLCR2 ], 0 );
|
||||
outb( sc->ioaddr[ FE_DLCR3 ], 0 );
|
||||
|
||||
/*
|
||||
* That's all. C-NET(PC)C occupies 16 I/O addresses.
|
||||
* XXX: Are there any card with 32 I/O addresses? FIXME.
|
||||
*/
|
||||
return 16;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Install interface into kernel networking data structures
|
||||
*/
|
||||
|
@ -1453,13 +1666,11 @@ fe_watchdog ( struct ifnet *ifp )
|
|||
log( LOG_ERR, "fe%d: transmission timeout (%d+%d)%s\n",
|
||||
ifp->if_unit, sc->txb_sched, sc->txb_count,
|
||||
( ifp->if_flags & IFF_UP ) ? "" : " when down" );
|
||||
#endif
|
||||
|
||||
/* Suggest users a possible cause. */
|
||||
if ( ifp->if_oerrors > 0 ) {
|
||||
log( LOG_WARNING, "fe%d: wrong IRQ setting in config?",
|
||||
if ( sc->sc_if.if_opackets == 0 && sc->sc_if.if_ipackets == 0 ) {
|
||||
log( LOG_WARNING, "fe%d: wrong IRQ setting in config?\n",
|
||||
ifp->if_unit );
|
||||
}
|
||||
#endif
|
||||
|
||||
#if FE_DEBUG >= 3
|
||||
fe_dump( LOG_INFO, sc, NULL );
|
||||
|
@ -1581,11 +1792,12 @@ fe_init ( int unit )
|
|||
#if FE_DEBUG >= 3
|
||||
fe_dump( LOG_INFO, sc, "just after enabling DLC" );
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Make sure to empty the receive buffer.
|
||||
*
|
||||
* This may be redundant, but *if* the receive buffer were full
|
||||
* at this point, the driver would hang. I have experienced
|
||||
* at this point, then the driver would hang. I have experienced
|
||||
* some strange hang-up just after UP. I hope the following
|
||||
* code solve the problem.
|
||||
*
|
||||
|
@ -1593,29 +1805,24 @@ fe_init ( int unit )
|
|||
* I think the receive buffer cannot have any packets at this
|
||||
* point in this version. The following code *must* be
|
||||
* redundant now. FIXME.
|
||||
*
|
||||
* I've heard a rumore that on some PC card implementation of
|
||||
* 8696x, the receive buffer can have some data at this point.
|
||||
* The following message helps discovering the fact. FIXME.
|
||||
*/
|
||||
for ( i = 0; i < FE_MAX_RECV_COUNT; i++ ) {
|
||||
if ( inb( sc->ioaddr[ FE_DLCR5 ] ) & FE_D5_BUFEMP ) break;
|
||||
outb( sc->ioaddr[ FE_BMPR14 ], FE_B14_SKIP );
|
||||
}
|
||||
#if FE_DEBUG >= 1
|
||||
if ( i >= FE_MAX_RECV_COUNT ) {
|
||||
log( LOG_ERR, "fe%d: cannot empty receive buffer\n",
|
||||
if ( !( inb( sc->ioaddr[ FE_DLCR5 ] ) & FE_D5_BUFEMP ) ) {
|
||||
log( LOG_WARNING,
|
||||
"fe%d: receive buffer has some data after reset\n",
|
||||
sc->sc_unit );
|
||||
|
||||
fe_emptybuffer( sc );
|
||||
}
|
||||
#endif
|
||||
#if FE_DEBUG >= 3
|
||||
if ( i < FE_MAX_RECV_COUNT ) {
|
||||
log( LOG_INFO, "fe%d: receive buffer emptied (%d)\n",
|
||||
sc->sc_unit, i );
|
||||
}
|
||||
#endif
|
||||
|
||||
#if FE_DEBUG >= 3
|
||||
fe_dump( LOG_INFO, sc, "after ERB loop" );
|
||||
#endif
|
||||
|
||||
/* Do we need this here? FIXME. */
|
||||
/* Do we need this here? Actually, no. I must be paranoia. */
|
||||
outb( sc->ioaddr[ FE_DLCR0 ], 0xFF ); /* Clear all bits. */
|
||||
outb( sc->ioaddr[ FE_DLCR1 ], 0xFF ); /* ditto. */
|
||||
|
||||
|
@ -1665,6 +1872,7 @@ fe_xmit ( struct fe_softc * sc )
|
|||
sc->txb_sched = sc->txb_count;
|
||||
sc->txb_count = 0;
|
||||
sc->txb_free = sc->txb_size;
|
||||
sc->tx_excolls = 0;
|
||||
|
||||
/* Start transmitter, passing packets in TX buffer. */
|
||||
outb( sc->ioaddr[ FE_BMPR10 ], sc->txb_sched | FE_B10_START );
|
||||
|
@ -1762,7 +1970,8 @@ fe_start ( struct ifnet *ifp )
|
|||
* (i.e., minimum packet sized) packets rapidly. An 8KB
|
||||
* buffer can hold 130 blocks of 62 bytes long...
|
||||
*/
|
||||
if ( sc->txb_free < ETHER_MAX_LEN - ETHER_CRC_LEN + FE_DATA_LEN_LEN ) {
|
||||
if ( sc->txb_free
|
||||
< ETHER_MAX_LEN - ETHER_CRC_LEN + FE_DATA_LEN_LEN ) {
|
||||
/* No room. */
|
||||
goto indicate_active;
|
||||
}
|
||||
|
@ -1790,7 +1999,9 @@ fe_start ( struct ifnet *ifp )
|
|||
fe_write_mbufs( sc, m );
|
||||
|
||||
/* Start transmitter if it's idle. */
|
||||
if ( sc->txb_sched == 0 ) fe_xmit( sc );
|
||||
if ( ( sc->txb_count > 0 ) && ( sc->txb_sched == 0 ) ) {
|
||||
fe_xmit( sc );
|
||||
}
|
||||
|
||||
/*
|
||||
* Tap off here if there is a bpf listener,
|
||||
|
@ -1835,9 +2046,69 @@ fe_start ( struct ifnet *ifp )
|
|||
* Drop (skip) a packet from receive buffer in 86960 memory.
|
||||
*/
|
||||
static void
|
||||
fe_droppacket ( struct fe_softc * sc )
|
||||
fe_droppacket ( struct fe_softc * sc, int len )
|
||||
{
|
||||
int i;
|
||||
|
||||
/*
|
||||
* 86960 manual says that we have to read 8 bytes from the buffer
|
||||
* before skip the packets and that there must be more than 8 bytes
|
||||
* remaining in the buffer when issue a skip command.
|
||||
* Remember, we have already read 4 bytes before come here.
|
||||
*/
|
||||
if ( len > 12 ) {
|
||||
/* Read 4 more bytes, and skip the rest of the packet. */
|
||||
( void )inw( sc->ioaddr[ FE_BMPR8 ] );
|
||||
( void )inw( sc->ioaddr[ FE_BMPR8 ] );
|
||||
outb( sc->ioaddr[ FE_BMPR14 ], FE_B14_SKIP );
|
||||
} else {
|
||||
/* We should not come here unless receiving RUNTs. */
|
||||
for ( i = 0; i < len; i += 2 ) {
|
||||
( void )inw( sc->ioaddr[ FE_BMPR8 ] );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Empty receiving buffer.
|
||||
*/
|
||||
static void
|
||||
fe_emptybuffer ( struct fe_softc * sc )
|
||||
{
|
||||
int i;
|
||||
u_char saved_dlcr5;
|
||||
|
||||
#if FE_DEBUG >= 1
|
||||
log( LOG_WARNING, "fe%d: emptying receive buffer", sc->sc_unit );
|
||||
#endif
|
||||
/*
|
||||
* Stop receiving packets, temporarily.
|
||||
*/
|
||||
saved_dlcr5 = inb( sc->ioaddr[ FE_DLCR5 ] );
|
||||
outb( sc->ioaddr[ FE_DLCR5 ], sc->proto_dlcr5 );
|
||||
|
||||
/*
|
||||
* When we come here, the receive buffer management should
|
||||
* have been broken. So, we cannot use skip operation.
|
||||
*/
|
||||
for ( i = 0; i < sc->txb_size; i += 2 ) {
|
||||
if ( inb( sc->ioaddr[ FE_DLCR5 ] ) & FE_D5_BUFEMP ) break;
|
||||
( void )inw( sc->ioaddr[ FE_BMPR8 ] );
|
||||
}
|
||||
|
||||
/*
|
||||
* Double check.
|
||||
*/
|
||||
if ( inb( sc->ioaddr[ FE_DLCR5 ] ) & FE_D5_BUFEMP ) {
|
||||
log( LOG_ERR, "fe%d: could not empty receive buffer\n",
|
||||
sc->sc_unit );
|
||||
/* Hmm. What should I do if this happens? FIXME. */
|
||||
}
|
||||
|
||||
/*
|
||||
* Restart receiving packets.
|
||||
*/
|
||||
outb( sc->ioaddr[ FE_DLCR5 ], saved_dlcr5 );
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -1870,15 +2141,8 @@ fe_tint ( struct fe_softc * sc, u_char tstat )
|
|||
#endif
|
||||
|
||||
/*
|
||||
* Update statistics.
|
||||
*/
|
||||
sc->sc_if.if_collisions += 16;
|
||||
sc->sc_if.if_oerrors++;
|
||||
sc->sc_if.if_opackets += sc->txb_sched - left;
|
||||
|
||||
/*
|
||||
* Collision statistics has been updated.
|
||||
* Clear the collision flag on 86960 now to avoid confusion.
|
||||
* Clear the collision flag (in 86960) here
|
||||
* to avoid confusing statistics.
|
||||
*/
|
||||
outb( sc->ioaddr[ FE_DLCR0 ], FE_D0_COLLID );
|
||||
|
||||
|
@ -1897,7 +2161,9 @@ fe_tint ( struct fe_softc * sc, u_char tstat )
|
|||
*/
|
||||
outb( sc->ioaddr[ FE_BMPR11 ],
|
||||
FE_B11_CTRL_SKIP | FE_B11_MODE1 );
|
||||
sc->txb_sched = left - 1;
|
||||
|
||||
/* Update statistics. */
|
||||
sc->tx_excolls++;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -1953,10 +2219,12 @@ fe_tint ( struct fe_softc * sc, u_char tstat )
|
|||
}
|
||||
|
||||
/*
|
||||
* Update total number of successfully
|
||||
* transmitted packets.
|
||||
* Update transmission statistics.
|
||||
* Be sure to reflect number of excessive collisions.
|
||||
*/
|
||||
sc->sc_if.if_opackets += sc->txb_sched;
|
||||
sc->sc_if.if_opackets += sc->txb_sched - sc->tx_excolls;
|
||||
sc->sc_if.if_oerrors += sc->tx_excolls;
|
||||
sc->sc_if.if_collisions += sc->tx_excolls * 16;
|
||||
sc->txb_sched = 0;
|
||||
|
||||
/*
|
||||
|
@ -2031,19 +2299,6 @@ fe_rint ( struct fe_softc * sc, u_char rstat )
|
|||
sc->sc_unit, status );
|
||||
#endif
|
||||
|
||||
/*
|
||||
* If there was an error, update statistics and drop
|
||||
* the packet, unless the interface is in promiscuous
|
||||
* mode.
|
||||
*/
|
||||
if ( ( status & 0xF0 ) != 0x20 ) {
|
||||
if ( !( sc->sc_if.if_flags & IFF_PROMISC ) ) {
|
||||
sc->sc_if.if_ierrors++;
|
||||
fe_droppacket(sc);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Extract the packet length.
|
||||
* It is a sum of a header (14 bytes) and a payload.
|
||||
|
@ -2052,42 +2307,44 @@ fe_rint ( struct fe_softc * sc, u_char rstat )
|
|||
len = inw( sc->ioaddr[ FE_BMPR8 ] );
|
||||
|
||||
/*
|
||||
* MB86965 checks the packet length and drop big packet
|
||||
* If there was an error, update statistics and drop
|
||||
* the packet, unless the interface is in promiscuous
|
||||
* mode.
|
||||
*/
|
||||
if ( ( status & 0xF0 ) != 0x20 ) {
|
||||
if ( !( sc->sc_if.if_flags & IFF_PROMISC ) ) {
|
||||
sc->sc_if.if_ierrors++;
|
||||
fe_droppacket( sc, len );
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* MB86960 checks the packet length and drop big packet
|
||||
* before passing it to us. There are no chance we can
|
||||
* get big packets through it, even if they are actually
|
||||
* sent over a line. Hence, if the length exceeds
|
||||
* the specified limit, it means some serious failure,
|
||||
* such as out-of-sync on receive buffer management.
|
||||
*
|
||||
* Is this statement true? FIXME.
|
||||
* Same for short packets, since we have programmed
|
||||
* 86960 to drop short packets.
|
||||
*/
|
||||
if ( len > ETHER_MAX_LEN - ETHER_CRC_LEN || len < ETHER_MIN_LEN- ETHER_CRC_LEN ) {
|
||||
#if FE_DEBUG >= 2
|
||||
if ( len > ETHER_MAX_LEN - ETHER_CRC_LEN
|
||||
|| len < ETHER_MIN_LEN - ETHER_CRC_LEN ) {
|
||||
#if FE_DEBUG >= 1
|
||||
log( LOG_WARNING,
|
||||
"fe%d: received a %s packet? (%u bytes)\n",
|
||||
sc->sc_unit,
|
||||
len < ETHER_MIN_SIZE- ETHER_CRC_SIZE ? "partial" : "big",
|
||||
len < ETHER_MIN_LEN - ETHER_CRC_LEN
|
||||
? "partial" : "big",
|
||||
len );
|
||||
#endif
|
||||
sc->sc_if.if_ierrors++;
|
||||
fe_droppacket( sc );
|
||||
fe_emptybuffer( sc );
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check for a short (RUNT) packet. We *do* check
|
||||
* but do nothing other than print a message.
|
||||
* Short packets are illegal, but does nothing bad
|
||||
* if it carries data for upper layer.
|
||||
*/
|
||||
#if FE_DEBUG >= 2
|
||||
if ( len < ETHER_MIN_LEN - ETHER_CRC_LEN) {
|
||||
log( LOG_WARNING,
|
||||
"fe%d: received a short packet? (%u bytes)\n",
|
||||
sc->sc_unit, len );
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Go get a packet.
|
||||
*/
|
||||
|
@ -2099,7 +2356,7 @@ fe_rint ( struct fe_softc * sc, u_char rstat )
|
|||
sc->sc_unit, len );
|
||||
#endif
|
||||
sc->sc_if.if_ierrors++;
|
||||
fe_droppacket( sc );
|
||||
fe_droppacket( sc, len );
|
||||
|
||||
/*
|
||||
* We stop receiving packets, even if there are
|
||||
|
@ -2588,7 +2845,8 @@ fe_write_mbufs ( struct fe_softc *sc, struct mbuf *m )
|
|||
* it should be a bug of upper layer. We just ignore it.
|
||||
* ... Partial (too short) packets, neither.
|
||||
*/
|
||||
if ( ! ETHER_IS_VALID_LEN(length + ETHER_CRC_LEN)) {
|
||||
if ( length < ETHER_HDR_LEN
|
||||
|| length > ETHER_MAX_LEN - ETHER_CRC_LEN ) {
|
||||
log( LOG_ERR,
|
||||
"fe%d: got an out-of-spec packet (%u bytes) to send\n",
|
||||
sc->sc_unit, length );
|
||||
|
|
Loading…
Reference in a new issue