As of this revision, all known bugs have been fixed. Some of the fixes include:

1) fixed 3c503 lock-up if the thinwire cable was disconnected at boot time
2) 8013EBT boards now work (quite well!) in 16bit/16k mode
3) ED_NO_DOUBLE_BUFFERING flag now works
4) slightly higer performance (about 3%) with 16bit WD/SMC boards
5) support for WD8013WC (10BaseT) boards

   Additionally, the probe code has been reorganized to be much cleaner. This
revision of the driver is 1.25. The release notes have been updated as well.
This commit is contained in:
David Greenman 1993-09-09 07:01:23 +00:00
parent 5c8830eef2
commit 1df5695c0a
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=426
4 changed files with 284 additions and 318 deletions

View File

@ -17,76 +17,39 @@
* Modification history
*
* $Log: if_ed.c,v $
* Revision 1.25 93/09/08 23:04:25 davidg
* fixed problem where 3c503 boards lock up if the cable is
* disconnected at boot time. Added printing of irq number if
* the kernel config and board don't match
*
* Revision 1.24 93/09/07 12:08:36 davidg
* ED_FLAGS_NO_DOUBLE_BUFFERING was being checked against wrong variable
*
* Revision 1.23 93/09/07 10:32:53 davidg
* split wd and 3Com probe code into seperate routines
*
* Revision 1.22 93/09/06 20:28:22 davidg
* change references to LAAR to use shadow/prototype rather than the
* real thing because 8013EBT asic regs are write-only.
*
* Revision 1.21 93/08/25 20:38:02 davidg
* added recognition for WD8013WC (10BaseT) card type
*
* Revision 1.20 93/08/14 20:07:35 davidg
* one more stab at getting the 8013EBT working
*
* Revision 1.19 93/08/02 02:57:53 davidg
* Fixed problem where some rev 8013EBT boards want the DCR_LS flag
* set in order to work in 16bit mode.
*
* Revision 1.18 93/07/27 03:41:36 davidg
* removed unnecessary variable assignment in ed_reset()
*
* Revision 1.17 93/07/26 18:40:57 davidg
* Added include of systm.h to pick up inlined min/max/bcmp if you have
* them in cpufunc.h. Modified wait loop in reset to look a little better.
* Added read for talley counters to prevent an infinite loop on old
* 8003E's if they (the counters) overflow.
*
* Revision 1.16 93/07/25 14:27:12 davidg
* added parans to the previous fix so that it can cope with outb
* being a macro.
*
* Revision 1.15 93/07/25 14:07:56 davidg
* fixed logic problem where a 3c503 register was being written
* even if the board wasn't a 3Com. Wolfgang Solfrank pointed this
* out.
*
* Revision 1.14 93/07/20 15:24:25 davidg
* ommision for force 16bit case fixed from last patch
*
* Revision 1.13 93/07/20 15:13:55 davidg
* Added config file override for memsize by using 'iosiz'. Also added
* config flags overrides to force 8/16bit mode and disable the use of
* double xmit buffers.
* set in order to work in 16bit mode. Also improves performance on
* all types of boards.
*
*...(part of log nuked for brevity)
*
* Revision 1.12 93/07/07 06:27:44 davidg
* moved call to bpfattach to after this drivers attach printf -
* improves readability of startup messages.
*
* Revision 1.11 93/06/27 03:07:01 davidg
* fixed bugs in the 3Com part of the probe routine that were uncovered by
* the previous fix.
*
* Revision 1.10 93/06/25 19:23:19 davidg
* fixed bug that caused erroneous 'Invalid irq configuration' message when
* no board is present (during autoconfiguration).
*
* Revision 1.9 93/06/23 03:48:14 davidg
* fixed minor typo introduced when cleaning up probe routine
*
* Revision 1.8 93/06/23 03:37:19 davidg
* cleaned up/added some comments. Also improved readability of a part of
* the probe routine.
*
* Revision 1.7 93/06/22 04:45:01 davidg
* (no additional changes) Second beta release
*
* Revision 1.6 93/06/22 04:40:35 davidg
* minor definition fix to ed_reset()
*
* Revision 1.5 93/06/22 04:37:39 davidg
* fixed some comments
*
* Revision 1.4 93/06/22 04:34:34 davidg
* added support to use the LLC0 'link-level control' flag
* to disable the tranceiver for AUI operation on 3Com boards.
* The default for this flag can be set in the kernel config
* file - 'flags 0x01' sets the flag (disables the tranceiver).
*
* Revision 1.3 93/06/17 03:57:28 davidg
* fixed some printf's
*
* Revision 1.2 93/06/17 03:26:49 davidg
* fixed 3c503 code to determine 8/16bit board
* changed attach printf to work with Interim-0.1.5 and NetBSD
*...(part of log nuked for brevity)
*
* Revision 1.1 93/06/14 22:21:24 davidg
* Beta release of device driver for SMC/WD80x3 and 3C503 ethernet boards.
@ -136,6 +99,10 @@
#include "i386/include/pio.h"
/* For backwards compatibility */
#ifndef IFF_ALTPHYS
#define IFF_ALTPHYS IFF_LLC0
#endif
/*
* ed_softc: per line info and status
@ -169,6 +136,11 @@ struct ed_softc {
u_char rec_page_start; /* first page of RX ring-buffer */
u_char rec_page_stop; /* last page of RX ring-buffer */
u_char next_packet; /* pointer to next unread RX packet */
/*
* The following 'proto' variable is part of a work-around for 8013EBT asics
* being write-only. It's sort of a prototype/shadow of the real thing.
*/
u_char wd_laar_proto;
} ed_softc[NED];
int ed_attach(), ed_init(), edintr(), ed_ioctl(), ed_probe(),
@ -221,9 +193,8 @@ ed_probe(isa_dev)
struct isa_device *isa_dev;
{
struct ed_softc *sc = &ed_softc[isa_dev->id_unit];
int i, x;
u_int memsize;
u_char iptr, memwidth, sum, tmp;
int i;
u_char sum;
/*
* Setup initial i/o address for ASIC and NIC
@ -245,19 +216,27 @@ ed_probe(isa_dev)
}
if (sum == ED_WD_ROM_CHECKSUM_TOTAL) {
goto type_WD80x3;
return (ed_probe_WD80x3(isa_dev));
} else {
/*
* Do additional checking to make sure its a 3Com and
* not a broken WD clone
* XXX - Should do additional checking to make sure its a 3Com
* and not a broken WD clone
*/
goto type_3Com;
return (ed_probe_3Com(isa_dev));
}
}
type_WD80x3:
/*
* Looks like a WD/SMC board
*/
/*
* Probe and vendor-specific initialization routine for SMC/WD80x3 boards
*/
int
ed_probe_WD80x3(isa_dev)
struct isa_device *isa_dev;
{
struct ed_softc *sc = &ed_softc[isa_dev->id_unit];
int i;
u_int memsize;
u_char iptr, memwidth, sum, tmp;
sc->vendor = ED_VENDOR_WD_SMC;
sc->type = inb(sc->asic_addr + ED_WD_CARD_ID);
@ -290,18 +269,23 @@ ed_probe(isa_dev)
memsize = 16384;
memwidth = 16;
break;
case ED_TYPE_WD8013EB: /* also WD8003EP */
case ED_TYPE_WD8013EP: /* also WD8003EP */
if (inb(sc->asic_addr + ED_WD_ICR)
& ED_WD_ICR_16BIT) {
memwidth = 16;
memsize = 16384;
sc->type_str = "WD8013EB";
sc->type_str = "WD8013EP";
} else {
sc->type_str = "WD8003EP";
memsize = 8192;
memwidth = 8;
}
break;
case ED_TYPE_WD8013WC:
sc->type_str = "WD8013WC";
memsize = 16384;
memwidth = 16;
break;
case ED_TYPE_WD8013EBP:
sc->type_str = "WD8013EBP";
memsize = 16384;
@ -322,14 +306,16 @@ ed_probe(isa_dev)
* Make some adjustments to initial values depending on what is
* found in the ICR.
*/
if ((memwidth==16)
if ((memwidth == 16) && (sc->type != ED_TYPE_WD8013EBT)
&& ((inb(sc->asic_addr + ED_WD_ICR) & ED_WD_ICR_16BIT) == 0)) {
memwidth = 8;
memsize = 8192;
}
#if 0 /* This has caused more problems than it's worth */
if (inb(sc->asic_addr + ED_WD_ICR) & ED_WD_ICR_MSZ) {
memsize = 32768;
}
#endif
#if ED_DEBUG
printf("type=%s memwidth=%d memsize=%d id_msize=%d\n",
@ -367,8 +353,8 @@ ed_probe(isa_dev)
* Translate it using translation table, and check for correctness.
*/
if (ed_intr_mask[iptr] != isa_dev->id_irq) {
printf("ed%d: kernel configured irq doesn't match board configured irq\n",
isa_dev->id_unit);
printf("ed%d: kernel configured irq %d doesn't match board configured irq %d\n",
isa_dev->id_unit, ffs(isa_dev->id_irq) - 1, ffs(ed_intr_mask[iptr]) - 1);
return(0);
}
/*
@ -382,7 +368,7 @@ ed_probe(isa_dev)
/*
* allocate one xmit buffer if < 16k, two buffers otherwise
*/
if ((memsize < 16384) || (isa_dev->id_msize & ED_FLAGS_NO_DOUBLE_BUFFERING)) {
if ((memsize < 16384) || (isa_dev->id_flags & ED_FLAGS_NO_DOUBLE_BUFFERING)) {
sc->smem_ring = sc->smem_start + (ED_PAGE_SIZE * ED_TXBUF_SIZE);
sc->txb_cnt = 1;
sc->rec_page_start = ED_TXBUF_SIZE;
@ -411,14 +397,14 @@ ed_probe(isa_dev)
/*
* Set upper address bits and 8/16 bit access to shared memory
*/
if (sc->type & ED_WD_SOFTCONFIG) {
if ((sc->type & ED_WD_SOFTCONFIG) || (sc->type == ED_TYPE_WD8013EBT)) {
if (memwidth == 8) {
outb(sc->asic_addr + ED_WD_LAAR,
((kvtop(sc->smem_start) >> 19) & ED_WD_LAAR_ADDRHI));
outb(sc->asic_addr + ED_WD_LAAR, (sc->wd_laar_proto =
((kvtop(sc->smem_start) >> 19) & ED_WD_LAAR_ADDRHI)));
} else {
outb(sc->asic_addr + ED_WD_LAAR,
outb(sc->asic_addr + ED_WD_LAAR, (sc->wd_laar_proto =
ED_WD_LAAR_L16EN | ED_WD_LAAR_M16EN |
((kvtop(sc->smem_start) >> 19) & ED_WD_LAAR_ADDRHI));
((kvtop(sc->smem_start) >> 19) & ED_WD_LAAR_ADDRHI)));
}
}
@ -436,9 +422,8 @@ ed_probe(isa_dev)
* Disable 16 bit access to shared memory
*/
if (memwidth == 16)
outb(sc->asic_addr + ED_WD_LAAR,
inb(sc->asic_addr + ED_WD_LAAR)
& ~ED_WD_LAAR_M16EN);
outb(sc->asic_addr + ED_WD_LAAR, (sc->wd_laar_proto &=
~ED_WD_LAAR_M16EN));
return(0);
}
@ -452,16 +437,23 @@ ed_probe(isa_dev)
* memory can be used in this 128k region, too.
*/
if (memwidth == 16)
outb(sc->asic_addr + ED_WD_LAAR, inb(sc->asic_addr + ED_WD_LAAR)
& ~ED_WD_LAAR_M16EN);
outb(sc->asic_addr + ED_WD_LAAR, (sc->wd_laar_proto &=
~ED_WD_LAAR_M16EN));
isa_dev->id_msize = memsize;
return (ED_WD_IO_PORTS);
}
type_3Com:
/*
* Looks like a 3Com board
*/
/*
* Probe and vendor-specific initialization routine for 3Com 3c503 boards
*/
ed_probe_3Com(isa_dev)
struct isa_device *isa_dev;
{
struct ed_softc *sc = &ed_softc[isa_dev->id_unit];
int i;
u_int memsize;
u_char memwidth, sum;
sc->vendor = ED_VENDOR_3COM;
sc->asic_addr = isa_dev->id_iobase + ED_3COM_ASIC_OFFSET;
@ -538,27 +530,46 @@ ed_probe(isa_dev)
}
/*
* Reset NIC and ASIC
* Reset NIC and ASIC. Enable on-board transceiver through reset sequence
* because it'll lock up if the cable isn't connected if we don't.
*/
outb(sc->asic_addr + ED_3COM_CR, ED_3COM_CR_RST);
outb(sc->asic_addr + ED_3COM_CR, ED_3COM_CR_RST | ED_3COM_CR_XSEL);
/*
* Wait for a while, then un-reset it
*/
DELAY(5000);
outb(sc->asic_addr + ED_3COM_CR, 0);
DELAY(50);
/*
* The 3Com ASIC defaults to rather strange settings for the CR after
* a reset - it's important to set it again after the following
* outb (this is done when we map the PROM below).
*/
outb(sc->asic_addr + ED_3COM_CR, ED_3COM_CR_XSEL);
/*
* Wait a bit for the NIC to recover from the reset
*/
DELAY(5000);
DELAY(50);
/*
* The 3Com ASIC defaults to rather strange settings for the CR after
* a reset - it's important to set it so that the NIC I/O
* registers are mapped. The above setting of it to '0' only
* resets the reset condition - the CR is *not* set to zeros.
* Get station address from on-board ROM
*/
outb(sc->asic_addr + ED_3COM_CR, 0);
/*
* First, map ethernet address PROM over the top of where the NIC
* registers normally appear.
*/
outb(sc->asic_addr + ED_3COM_CR, ED_3COM_CR_EALO | ED_3COM_CR_XSEL);
for (i = 0; i < ETHER_ADDR_LEN; ++i)
sc->arpcom.ac_enaddr[i] = inb(sc->nic_addr + i);
/*
* Unmap PROM - select NIC registers. The proper setting of the
* tranceiver is set in ed_init so that the attach code
* is given a chance to set the default based on a compile-time
* config option
*/
outb(sc->asic_addr + ED_3COM_CR, ED_3COM_CR_XSEL);
/*
* Determine if this is an 8bit or 16bit board
@ -629,7 +640,8 @@ ed_probe(isa_dev)
outb(sc->asic_addr + ED_3COM_IDCFR, ED_3COM_IDCFR_IRQ5);
break;
default:
printf("ed%d: Invalid irq configuration\n", isa_dev->id_unit);
printf("ed%d: Invalid irq configuration (%d) must be 2-5 for 3c503\n",
isa_dev->id_unit, ffs(isa_dev->id_irq) - 1);
return(0);
}
@ -649,44 +661,6 @@ ed_probe(isa_dev)
outb(sc->asic_addr + ED_3COM_VPTR1, 0xff);
outb(sc->asic_addr + ED_3COM_VPTR0, 0x00);
/*
* Get station address from on-board ROM
*/
/*
* First, map ethernet address PROM over the top of where the NIC
* registers normally appear.
*/
outb(sc->asic_addr + ED_3COM_CR, ED_3COM_CR_EALO);
for (i = 0; i < ETHER_ADDR_LEN; ++i)
sc->arpcom.ac_enaddr[i] = inb(sc->nic_addr + i);
/*
* Unmap PROM - select NIC registers. Tranceiver remains disabled at
* this point. It's enabled in ed_init so that the attach code
* is given a chance to set the default based on a compile-time
* config option
*/
outb(sc->asic_addr + ED_3COM_CR, 0);
#if 0
printf("Starting write\n");
for (i = 0; i < 8192; ++i)
bzero(sc->smem_start, 8192);
printf("Done.\n");
#endif
#if 0
{ char test_buf[1024];
printf("starting write\n");
for (i = 0; i < 8*8192; ++i)
bcopy(test_buf, sc->smem_start, 1024);
printf("starting read\n");
for (i = 0; i < 8*8192; ++i)
bcopy(sc->smem_start, test_buf, 1024);
printf("done.\n");
}
#endif
/*
* Zero memory and verify that it is clear
*/
@ -734,12 +708,12 @@ ed_attach(isa_dev)
ifp->if_watchdog = ed_watchdog;
/*
* Set default state for LLC0 flag (used to disable the tranceiver
* Set default state for ALTPHYS flag (used to disable the tranceiver
* for AUI operation), based on compile-time config option.
*/
if (isa_dev->id_flags & ED_FLAGS_DISABLE_TRANCEIVER)
ifp->if_flags = (IFF_BROADCAST | IFF_SIMPLEX | IFF_NOTRAILERS
| IFF_LLC0);
| IFF_ALTPHYS);
else
ifp->if_flags = (IFF_BROADCAST | IFF_SIMPLEX | IFF_NOTRAILERS);
@ -777,7 +751,7 @@ ed_attach(isa_dev)
printf("ed%d: address %s, type %s (%dbit) %s\n", isa_dev->id_unit,
ether_sprintf(sc->arpcom.ac_enaddr), sc->type_str,
sc->memwidth, ((sc->vendor == ED_VENDOR_3COM) &&
(ifp->if_flags & IFF_LLC0)) ? "tranceiver disabled" : "");
(ifp->if_flags & IFF_ALTPHYS)) ? "tranceiver disabled" : "");
/*
* If BPF is in the kernel, call the attach for it
@ -979,7 +953,7 @@ ed_init(unit)
* (there is no settable hardware default).
*/
if (sc->vendor == ED_VENDOR_3COM) {
if (ifp->if_flags & IFF_LLC0) {
if (ifp->if_flags & IFF_ALTPHYS) {
outb(sc->asic_addr + ED_3COM_CR, 0);
} else {
outb(sc->asic_addr + ED_3COM_CR, ED_3COM_CR_XSEL);
@ -1065,7 +1039,6 @@ ed_start(ifp)
struct mbuf *m0, *m;
caddr_t buffer;
int len;
u_char laar_tmp;
outloop:
/*
@ -1112,11 +1085,14 @@ ed_start(ifp)
*/
/*
* Enable 16bit access to shared memory on WD/SMC boards
* Don't update wd_laar_proto because we want to restore the
* previous state (because an arp reply in the input code
* may cause a call-back to ed_start)
*/
if (sc->memwidth == 16)
if (sc->vendor == ED_VENDOR_WD_SMC) {
laar_tmp = inb(sc->asic_addr + ED_WD_LAAR);
outb(sc->asic_addr + ED_WD_LAAR, laar_tmp | ED_WD_LAAR_M16EN);
outb(sc->asic_addr + ED_WD_LAAR,
(sc->wd_laar_proto | ED_WD_LAAR_M16EN));
}
buffer = sc->smem_start + (sc->txb_next * ED_TXBUF_SIZE * ED_PAGE_SIZE);
@ -1124,7 +1100,7 @@ ed_start(ifp)
for (m0 = m; m != 0; m = m->m_next) {
bcopy(mtod(m, caddr_t), buffer, m->m_len);
buffer += m->m_len;
len += m->m_len;
len += m->m_len;
}
/*
@ -1132,7 +1108,7 @@ ed_start(ifp)
*/
if (sc->memwidth == 16)
if (sc->vendor == ED_VENDOR_WD_SMC) {
outb(sc->asic_addr + ED_WD_LAAR, laar_tmp);
outb(sc->asic_addr + ED_WD_LAAR, sc->wd_laar_proto);
}
sc->txb_next_len = MAX(len, ETHER_MIN_LEN);
@ -1457,8 +1433,8 @@ edintr(unit)
if (sc->memwidth == 16)
if (sc->vendor == ED_VENDOR_WD_SMC) {
outb(sc->asic_addr + ED_WD_LAAR,
inb(sc->asic_addr + ED_WD_LAAR)
| ED_WD_LAAR_M16EN);
(sc->wd_laar_proto |=
ED_WD_LAAR_M16EN));
}
ed_rint (unit);
@ -1469,8 +1445,8 @@ edintr(unit)
if (sc->memwidth == 16)
if (sc->vendor == ED_VENDOR_WD_SMC) {
outb(sc->asic_addr + ED_WD_LAAR,
inb(sc->asic_addr + ED_WD_LAAR)
& ~ED_WD_LAAR_M16EN);
(sc->wd_laar_proto &=
~ED_WD_LAAR_M16EN));
}
}
@ -1614,11 +1590,11 @@ ed_ioctl(ifp, command, data)
#endif
/*
* An unfortunate hack to provide the (required) software control
* of the tranceiver for 3Com boards. The LLC0 flag disables
* of the tranceiver for 3Com boards. The ALTPHYS flag disables
* the tranceiver if set.
*/
if (sc->vendor == ED_VENDOR_3COM) {
if (ifp->if_flags & IFF_LLC0) {
if (ifp->if_flags & IFF_ALTPHYS) {
outb(sc->asic_addr + ED_3COM_CR, 0);
} else {
outb(sc->asic_addr + ED_3COM_CR, ED_3COM_CR_XSEL);

View File

@ -2,6 +2,12 @@
* National Semiconductor DS8390 NIC register definitions
*
* $Log: if_edreg.h,v $
* Revision 1.5 93/08/25 20:38:34 davidg
* added define for card type WD8013WC (10BaseT)
*
* Revision 1.4 93/08/14 20:07:55 davidg
* fix board type definition for 8013EP
*
* Revision 1.3 93/07/20 15:25:25 davidg
* added config flags for forcing 8/16bit mode and disabling double
* xmit buffers.
@ -662,7 +668,8 @@ struct ed_ring {
#define ED_TYPE_WD8003S 0x02
#define ED_TYPE_WD8003E 0x03
#define ED_TYPE_WD8013EBT 0x05
#define ED_TYPE_WD8013EB 0x27
#define ED_TYPE_WD8013EP 0x27
#define ED_TYPE_WD8013WC 0x28
#define ED_TYPE_WD8013EBP 0x2c
#define ED_TYPE_WD8013EPC 0x29

View File

@ -17,76 +17,39 @@
* Modification history
*
* $Log: if_ed.c,v $
* Revision 1.25 93/09/08 23:04:25 davidg
* fixed problem where 3c503 boards lock up if the cable is
* disconnected at boot time. Added printing of irq number if
* the kernel config and board don't match
*
* Revision 1.24 93/09/07 12:08:36 davidg
* ED_FLAGS_NO_DOUBLE_BUFFERING was being checked against wrong variable
*
* Revision 1.23 93/09/07 10:32:53 davidg
* split wd and 3Com probe code into seperate routines
*
* Revision 1.22 93/09/06 20:28:22 davidg
* change references to LAAR to use shadow/prototype rather than the
* real thing because 8013EBT asic regs are write-only.
*
* Revision 1.21 93/08/25 20:38:02 davidg
* added recognition for WD8013WC (10BaseT) card type
*
* Revision 1.20 93/08/14 20:07:35 davidg
* one more stab at getting the 8013EBT working
*
* Revision 1.19 93/08/02 02:57:53 davidg
* Fixed problem where some rev 8013EBT boards want the DCR_LS flag
* set in order to work in 16bit mode.
*
* Revision 1.18 93/07/27 03:41:36 davidg
* removed unnecessary variable assignment in ed_reset()
*
* Revision 1.17 93/07/26 18:40:57 davidg
* Added include of systm.h to pick up inlined min/max/bcmp if you have
* them in cpufunc.h. Modified wait loop in reset to look a little better.
* Added read for talley counters to prevent an infinite loop on old
* 8003E's if they (the counters) overflow.
*
* Revision 1.16 93/07/25 14:27:12 davidg
* added parans to the previous fix so that it can cope with outb
* being a macro.
*
* Revision 1.15 93/07/25 14:07:56 davidg
* fixed logic problem where a 3c503 register was being written
* even if the board wasn't a 3Com. Wolfgang Solfrank pointed this
* out.
*
* Revision 1.14 93/07/20 15:24:25 davidg
* ommision for force 16bit case fixed from last patch
*
* Revision 1.13 93/07/20 15:13:55 davidg
* Added config file override for memsize by using 'iosiz'. Also added
* config flags overrides to force 8/16bit mode and disable the use of
* double xmit buffers.
* set in order to work in 16bit mode. Also improves performance on
* all types of boards.
*
*...(part of log nuked for brevity)
*
* Revision 1.12 93/07/07 06:27:44 davidg
* moved call to bpfattach to after this drivers attach printf -
* improves readability of startup messages.
*
* Revision 1.11 93/06/27 03:07:01 davidg
* fixed bugs in the 3Com part of the probe routine that were uncovered by
* the previous fix.
*
* Revision 1.10 93/06/25 19:23:19 davidg
* fixed bug that caused erroneous 'Invalid irq configuration' message when
* no board is present (during autoconfiguration).
*
* Revision 1.9 93/06/23 03:48:14 davidg
* fixed minor typo introduced when cleaning up probe routine
*
* Revision 1.8 93/06/23 03:37:19 davidg
* cleaned up/added some comments. Also improved readability of a part of
* the probe routine.
*
* Revision 1.7 93/06/22 04:45:01 davidg
* (no additional changes) Second beta release
*
* Revision 1.6 93/06/22 04:40:35 davidg
* minor definition fix to ed_reset()
*
* Revision 1.5 93/06/22 04:37:39 davidg
* fixed some comments
*
* Revision 1.4 93/06/22 04:34:34 davidg
* added support to use the LLC0 'link-level control' flag
* to disable the tranceiver for AUI operation on 3Com boards.
* The default for this flag can be set in the kernel config
* file - 'flags 0x01' sets the flag (disables the tranceiver).
*
* Revision 1.3 93/06/17 03:57:28 davidg
* fixed some printf's
*
* Revision 1.2 93/06/17 03:26:49 davidg
* fixed 3c503 code to determine 8/16bit board
* changed attach printf to work with Interim-0.1.5 and NetBSD
*...(part of log nuked for brevity)
*
* Revision 1.1 93/06/14 22:21:24 davidg
* Beta release of device driver for SMC/WD80x3 and 3C503 ethernet boards.
@ -136,6 +99,10 @@
#include "i386/include/pio.h"
/* For backwards compatibility */
#ifndef IFF_ALTPHYS
#define IFF_ALTPHYS IFF_LLC0
#endif
/*
* ed_softc: per line info and status
@ -169,6 +136,11 @@ struct ed_softc {
u_char rec_page_start; /* first page of RX ring-buffer */
u_char rec_page_stop; /* last page of RX ring-buffer */
u_char next_packet; /* pointer to next unread RX packet */
/*
* The following 'proto' variable is part of a work-around for 8013EBT asics
* being write-only. It's sort of a prototype/shadow of the real thing.
*/
u_char wd_laar_proto;
} ed_softc[NED];
int ed_attach(), ed_init(), edintr(), ed_ioctl(), ed_probe(),
@ -221,9 +193,8 @@ ed_probe(isa_dev)
struct isa_device *isa_dev;
{
struct ed_softc *sc = &ed_softc[isa_dev->id_unit];
int i, x;
u_int memsize;
u_char iptr, memwidth, sum, tmp;
int i;
u_char sum;
/*
* Setup initial i/o address for ASIC and NIC
@ -245,19 +216,27 @@ ed_probe(isa_dev)
}
if (sum == ED_WD_ROM_CHECKSUM_TOTAL) {
goto type_WD80x3;
return (ed_probe_WD80x3(isa_dev));
} else {
/*
* Do additional checking to make sure its a 3Com and
* not a broken WD clone
* XXX - Should do additional checking to make sure its a 3Com
* and not a broken WD clone
*/
goto type_3Com;
return (ed_probe_3Com(isa_dev));
}
}
type_WD80x3:
/*
* Looks like a WD/SMC board
*/
/*
* Probe and vendor-specific initialization routine for SMC/WD80x3 boards
*/
int
ed_probe_WD80x3(isa_dev)
struct isa_device *isa_dev;
{
struct ed_softc *sc = &ed_softc[isa_dev->id_unit];
int i;
u_int memsize;
u_char iptr, memwidth, sum, tmp;
sc->vendor = ED_VENDOR_WD_SMC;
sc->type = inb(sc->asic_addr + ED_WD_CARD_ID);
@ -290,18 +269,23 @@ ed_probe(isa_dev)
memsize = 16384;
memwidth = 16;
break;
case ED_TYPE_WD8013EB: /* also WD8003EP */
case ED_TYPE_WD8013EP: /* also WD8003EP */
if (inb(sc->asic_addr + ED_WD_ICR)
& ED_WD_ICR_16BIT) {
memwidth = 16;
memsize = 16384;
sc->type_str = "WD8013EB";
sc->type_str = "WD8013EP";
} else {
sc->type_str = "WD8003EP";
memsize = 8192;
memwidth = 8;
}
break;
case ED_TYPE_WD8013WC:
sc->type_str = "WD8013WC";
memsize = 16384;
memwidth = 16;
break;
case ED_TYPE_WD8013EBP:
sc->type_str = "WD8013EBP";
memsize = 16384;
@ -322,14 +306,16 @@ ed_probe(isa_dev)
* Make some adjustments to initial values depending on what is
* found in the ICR.
*/
if ((memwidth==16)
if ((memwidth == 16) && (sc->type != ED_TYPE_WD8013EBT)
&& ((inb(sc->asic_addr + ED_WD_ICR) & ED_WD_ICR_16BIT) == 0)) {
memwidth = 8;
memsize = 8192;
}
#if 0 /* This has caused more problems than it's worth */
if (inb(sc->asic_addr + ED_WD_ICR) & ED_WD_ICR_MSZ) {
memsize = 32768;
}
#endif
#if ED_DEBUG
printf("type=%s memwidth=%d memsize=%d id_msize=%d\n",
@ -367,8 +353,8 @@ ed_probe(isa_dev)
* Translate it using translation table, and check for correctness.
*/
if (ed_intr_mask[iptr] != isa_dev->id_irq) {
printf("ed%d: kernel configured irq doesn't match board configured irq\n",
isa_dev->id_unit);
printf("ed%d: kernel configured irq %d doesn't match board configured irq %d\n",
isa_dev->id_unit, ffs(isa_dev->id_irq) - 1, ffs(ed_intr_mask[iptr]) - 1);
return(0);
}
/*
@ -382,7 +368,7 @@ ed_probe(isa_dev)
/*
* allocate one xmit buffer if < 16k, two buffers otherwise
*/
if ((memsize < 16384) || (isa_dev->id_msize & ED_FLAGS_NO_DOUBLE_BUFFERING)) {
if ((memsize < 16384) || (isa_dev->id_flags & ED_FLAGS_NO_DOUBLE_BUFFERING)) {
sc->smem_ring = sc->smem_start + (ED_PAGE_SIZE * ED_TXBUF_SIZE);
sc->txb_cnt = 1;
sc->rec_page_start = ED_TXBUF_SIZE;
@ -411,14 +397,14 @@ ed_probe(isa_dev)
/*
* Set upper address bits and 8/16 bit access to shared memory
*/
if (sc->type & ED_WD_SOFTCONFIG) {
if ((sc->type & ED_WD_SOFTCONFIG) || (sc->type == ED_TYPE_WD8013EBT)) {
if (memwidth == 8) {
outb(sc->asic_addr + ED_WD_LAAR,
((kvtop(sc->smem_start) >> 19) & ED_WD_LAAR_ADDRHI));
outb(sc->asic_addr + ED_WD_LAAR, (sc->wd_laar_proto =
((kvtop(sc->smem_start) >> 19) & ED_WD_LAAR_ADDRHI)));
} else {
outb(sc->asic_addr + ED_WD_LAAR,
outb(sc->asic_addr + ED_WD_LAAR, (sc->wd_laar_proto =
ED_WD_LAAR_L16EN | ED_WD_LAAR_M16EN |
((kvtop(sc->smem_start) >> 19) & ED_WD_LAAR_ADDRHI));
((kvtop(sc->smem_start) >> 19) & ED_WD_LAAR_ADDRHI)));
}
}
@ -436,9 +422,8 @@ ed_probe(isa_dev)
* Disable 16 bit access to shared memory
*/
if (memwidth == 16)
outb(sc->asic_addr + ED_WD_LAAR,
inb(sc->asic_addr + ED_WD_LAAR)
& ~ED_WD_LAAR_M16EN);
outb(sc->asic_addr + ED_WD_LAAR, (sc->wd_laar_proto &=
~ED_WD_LAAR_M16EN));
return(0);
}
@ -452,16 +437,23 @@ ed_probe(isa_dev)
* memory can be used in this 128k region, too.
*/
if (memwidth == 16)
outb(sc->asic_addr + ED_WD_LAAR, inb(sc->asic_addr + ED_WD_LAAR)
& ~ED_WD_LAAR_M16EN);
outb(sc->asic_addr + ED_WD_LAAR, (sc->wd_laar_proto &=
~ED_WD_LAAR_M16EN));
isa_dev->id_msize = memsize;
return (ED_WD_IO_PORTS);
}
type_3Com:
/*
* Looks like a 3Com board
*/
/*
* Probe and vendor-specific initialization routine for 3Com 3c503 boards
*/
ed_probe_3Com(isa_dev)
struct isa_device *isa_dev;
{
struct ed_softc *sc = &ed_softc[isa_dev->id_unit];
int i;
u_int memsize;
u_char memwidth, sum;
sc->vendor = ED_VENDOR_3COM;
sc->asic_addr = isa_dev->id_iobase + ED_3COM_ASIC_OFFSET;
@ -538,27 +530,46 @@ ed_probe(isa_dev)
}
/*
* Reset NIC and ASIC
* Reset NIC and ASIC. Enable on-board transceiver through reset sequence
* because it'll lock up if the cable isn't connected if we don't.
*/
outb(sc->asic_addr + ED_3COM_CR, ED_3COM_CR_RST);
outb(sc->asic_addr + ED_3COM_CR, ED_3COM_CR_RST | ED_3COM_CR_XSEL);
/*
* Wait for a while, then un-reset it
*/
DELAY(5000);
outb(sc->asic_addr + ED_3COM_CR, 0);
DELAY(50);
/*
* The 3Com ASIC defaults to rather strange settings for the CR after
* a reset - it's important to set it again after the following
* outb (this is done when we map the PROM below).
*/
outb(sc->asic_addr + ED_3COM_CR, ED_3COM_CR_XSEL);
/*
* Wait a bit for the NIC to recover from the reset
*/
DELAY(5000);
DELAY(50);
/*
* The 3Com ASIC defaults to rather strange settings for the CR after
* a reset - it's important to set it so that the NIC I/O
* registers are mapped. The above setting of it to '0' only
* resets the reset condition - the CR is *not* set to zeros.
* Get station address from on-board ROM
*/
outb(sc->asic_addr + ED_3COM_CR, 0);
/*
* First, map ethernet address PROM over the top of where the NIC
* registers normally appear.
*/
outb(sc->asic_addr + ED_3COM_CR, ED_3COM_CR_EALO | ED_3COM_CR_XSEL);
for (i = 0; i < ETHER_ADDR_LEN; ++i)
sc->arpcom.ac_enaddr[i] = inb(sc->nic_addr + i);
/*
* Unmap PROM - select NIC registers. The proper setting of the
* tranceiver is set in ed_init so that the attach code
* is given a chance to set the default based on a compile-time
* config option
*/
outb(sc->asic_addr + ED_3COM_CR, ED_3COM_CR_XSEL);
/*
* Determine if this is an 8bit or 16bit board
@ -629,7 +640,8 @@ ed_probe(isa_dev)
outb(sc->asic_addr + ED_3COM_IDCFR, ED_3COM_IDCFR_IRQ5);
break;
default:
printf("ed%d: Invalid irq configuration\n", isa_dev->id_unit);
printf("ed%d: Invalid irq configuration (%d) must be 2-5 for 3c503\n",
isa_dev->id_unit, ffs(isa_dev->id_irq) - 1);
return(0);
}
@ -649,44 +661,6 @@ ed_probe(isa_dev)
outb(sc->asic_addr + ED_3COM_VPTR1, 0xff);
outb(sc->asic_addr + ED_3COM_VPTR0, 0x00);
/*
* Get station address from on-board ROM
*/
/*
* First, map ethernet address PROM over the top of where the NIC
* registers normally appear.
*/
outb(sc->asic_addr + ED_3COM_CR, ED_3COM_CR_EALO);
for (i = 0; i < ETHER_ADDR_LEN; ++i)
sc->arpcom.ac_enaddr[i] = inb(sc->nic_addr + i);
/*
* Unmap PROM - select NIC registers. Tranceiver remains disabled at
* this point. It's enabled in ed_init so that the attach code
* is given a chance to set the default based on a compile-time
* config option
*/
outb(sc->asic_addr + ED_3COM_CR, 0);
#if 0
printf("Starting write\n");
for (i = 0; i < 8192; ++i)
bzero(sc->smem_start, 8192);
printf("Done.\n");
#endif
#if 0
{ char test_buf[1024];
printf("starting write\n");
for (i = 0; i < 8*8192; ++i)
bcopy(test_buf, sc->smem_start, 1024);
printf("starting read\n");
for (i = 0; i < 8*8192; ++i)
bcopy(sc->smem_start, test_buf, 1024);
printf("done.\n");
}
#endif
/*
* Zero memory and verify that it is clear
*/
@ -734,12 +708,12 @@ ed_attach(isa_dev)
ifp->if_watchdog = ed_watchdog;
/*
* Set default state for LLC0 flag (used to disable the tranceiver
* Set default state for ALTPHYS flag (used to disable the tranceiver
* for AUI operation), based on compile-time config option.
*/
if (isa_dev->id_flags & ED_FLAGS_DISABLE_TRANCEIVER)
ifp->if_flags = (IFF_BROADCAST | IFF_SIMPLEX | IFF_NOTRAILERS
| IFF_LLC0);
| IFF_ALTPHYS);
else
ifp->if_flags = (IFF_BROADCAST | IFF_SIMPLEX | IFF_NOTRAILERS);
@ -777,7 +751,7 @@ ed_attach(isa_dev)
printf("ed%d: address %s, type %s (%dbit) %s\n", isa_dev->id_unit,
ether_sprintf(sc->arpcom.ac_enaddr), sc->type_str,
sc->memwidth, ((sc->vendor == ED_VENDOR_3COM) &&
(ifp->if_flags & IFF_LLC0)) ? "tranceiver disabled" : "");
(ifp->if_flags & IFF_ALTPHYS)) ? "tranceiver disabled" : "");
/*
* If BPF is in the kernel, call the attach for it
@ -979,7 +953,7 @@ ed_init(unit)
* (there is no settable hardware default).
*/
if (sc->vendor == ED_VENDOR_3COM) {
if (ifp->if_flags & IFF_LLC0) {
if (ifp->if_flags & IFF_ALTPHYS) {
outb(sc->asic_addr + ED_3COM_CR, 0);
} else {
outb(sc->asic_addr + ED_3COM_CR, ED_3COM_CR_XSEL);
@ -1065,7 +1039,6 @@ ed_start(ifp)
struct mbuf *m0, *m;
caddr_t buffer;
int len;
u_char laar_tmp;
outloop:
/*
@ -1112,11 +1085,14 @@ ed_start(ifp)
*/
/*
* Enable 16bit access to shared memory on WD/SMC boards
* Don't update wd_laar_proto because we want to restore the
* previous state (because an arp reply in the input code
* may cause a call-back to ed_start)
*/
if (sc->memwidth == 16)
if (sc->vendor == ED_VENDOR_WD_SMC) {
laar_tmp = inb(sc->asic_addr + ED_WD_LAAR);
outb(sc->asic_addr + ED_WD_LAAR, laar_tmp | ED_WD_LAAR_M16EN);
outb(sc->asic_addr + ED_WD_LAAR,
(sc->wd_laar_proto | ED_WD_LAAR_M16EN));
}
buffer = sc->smem_start + (sc->txb_next * ED_TXBUF_SIZE * ED_PAGE_SIZE);
@ -1124,7 +1100,7 @@ ed_start(ifp)
for (m0 = m; m != 0; m = m->m_next) {
bcopy(mtod(m, caddr_t), buffer, m->m_len);
buffer += m->m_len;
len += m->m_len;
len += m->m_len;
}
/*
@ -1132,7 +1108,7 @@ ed_start(ifp)
*/
if (sc->memwidth == 16)
if (sc->vendor == ED_VENDOR_WD_SMC) {
outb(sc->asic_addr + ED_WD_LAAR, laar_tmp);
outb(sc->asic_addr + ED_WD_LAAR, sc->wd_laar_proto);
}
sc->txb_next_len = MAX(len, ETHER_MIN_LEN);
@ -1457,8 +1433,8 @@ edintr(unit)
if (sc->memwidth == 16)
if (sc->vendor == ED_VENDOR_WD_SMC) {
outb(sc->asic_addr + ED_WD_LAAR,
inb(sc->asic_addr + ED_WD_LAAR)
| ED_WD_LAAR_M16EN);
(sc->wd_laar_proto |=
ED_WD_LAAR_M16EN));
}
ed_rint (unit);
@ -1469,8 +1445,8 @@ edintr(unit)
if (sc->memwidth == 16)
if (sc->vendor == ED_VENDOR_WD_SMC) {
outb(sc->asic_addr + ED_WD_LAAR,
inb(sc->asic_addr + ED_WD_LAAR)
& ~ED_WD_LAAR_M16EN);
(sc->wd_laar_proto &=
~ED_WD_LAAR_M16EN));
}
}
@ -1614,11 +1590,11 @@ ed_ioctl(ifp, command, data)
#endif
/*
* An unfortunate hack to provide the (required) software control
* of the tranceiver for 3Com boards. The LLC0 flag disables
* of the tranceiver for 3Com boards. The ALTPHYS flag disables
* the tranceiver if set.
*/
if (sc->vendor == ED_VENDOR_3COM) {
if (ifp->if_flags & IFF_LLC0) {
if (ifp->if_flags & IFF_ALTPHYS) {
outb(sc->asic_addr + ED_3COM_CR, 0);
} else {
outb(sc->asic_addr + ED_3COM_CR, ED_3COM_CR_XSEL);

View File

@ -2,6 +2,12 @@
* National Semiconductor DS8390 NIC register definitions
*
* $Log: if_edreg.h,v $
* Revision 1.5 93/08/25 20:38:34 davidg
* added define for card type WD8013WC (10BaseT)
*
* Revision 1.4 93/08/14 20:07:55 davidg
* fix board type definition for 8013EP
*
* Revision 1.3 93/07/20 15:25:25 davidg
* added config flags for forcing 8/16bit mode and disabling double
* xmit buffers.
@ -662,7 +668,8 @@ struct ed_ring {
#define ED_TYPE_WD8003S 0x02
#define ED_TYPE_WD8003E 0x03
#define ED_TYPE_WD8013EBT 0x05
#define ED_TYPE_WD8013EB 0x27
#define ED_TYPE_WD8013EP 0x27
#define ED_TYPE_WD8013WC 0x28
#define ED_TYPE_WD8013EBP 0x2c
#define ED_TYPE_WD8013EPC 0x29