Subject: BVME410 ethernet driver
To: None <port-atari@netbsd.org>
From: maximum entropy <entropy@zippy.bernstein.com>
List: port-atari
Date: 12/02/1998 08:26:09
Here is the driver for the BVME410 lance ethernet card. Yeah, I know
I promised this about a year ago...but I just found and fixed the last
bug that was driving me nuts. So here it is.
The BVME410 comes in three different memory sizes, and with or without
a coax connector (for a total of 6 different models). This code was
developed on the fanciest model (256k, with coax) but with luck it
should work on any model.
The card is manufactured by:
BVM Limited
Hobb Lane
Hedge End
Southampton
SO03 OGH
Tel 0703 270770
I bought mine from:
Bill West Incorporated
887D Main Street
Monroe, CT 06468
Tel 203-261-6027
BWI has a web page with some specs at:
http://bwi.com/58data_3u.html
Mine cost me a little over $1000 US, but I expect the simpler models
are somewhat cheaper. I also bought it about a year ago -- it's
possible that the prices have changed significantly.
I have no affiliation with either BVM or BWI. However, I would like
to give special thanks to Robert Kulawiec (robert@bwi.com). When I
was deciding whether or not I should risk purchasing the card, knowing
that I'd be on my own when writing the driver, Robert faxed me the
programming information from the card's manual without even blinking
an eye. It was a great pleasure to do business with a hardware dealer
who wasn't fazed by the idea that I wouldn't be using his product on a
Windoze box (or even with one of the systems BWI sells that has
drivers for the card).
One more thing...I haven't tested this driver in the presence of
either a PAM or Riebel card (if I had one of them, I wouldn't have
written this driver). If anyone with those cards has trouble, let me
know. I can probably tighten up any loose ends in the match/attach
routines if need be.
Enough BS...here's the data. Merry holidays to all...
--- /sys/dev/ic/lance.c-orig Sat Aug 15 07:13:29 1998
+++ /sys/dev/ic/lance.c Wed Dec 2 03:13:11 1998
@@ -268,6 +268,10 @@
sc->sc_nrbuf = 64;
sc->sc_ntbuf = 16;
break;
+ case 262144:
+ sc->sc_nrbuf = 128;
+ sc->sc_ntbuf = 32;
+ break;
default:
panic("lance_config: weird memory size");
}
--- /sys/arch/atari/vme/if_le_vme.c-orig Wed Jul 22 07:15:35 1998
+++ /sys/arch/atari/vme/if_le_vme.c Wed Dec 2 03:29:09 1998
@@ -75,25 +75,26 @@
#include <atari/vme/vmevar.h>
#include <atari/vme/if_levar.h>
+/*
+ * All cards except BVME410 have 64KB RAM. However.... On the Riebl cards the
+ * area between the offsets 0xee70-0xeec0 is used to store config data.
+ */
struct le_addresses {
u_long reg_addr;
u_long mem_addr;
int irq;
+ int reg_size;
+ int mem_size;
} lestd[] = {
- { 0xfe00fff0, 0xfe010000, IRQUNK }, /* Riebl VME */
- { 0xffcffff0, 0xffcf0000, 5 }, /* PAM VME */
- { 0xfecffff0, 0xfecf0000, 5 } /* Rhotron VME */
+ { 0xfe00fff0, 0xfe010000, IRQUNK, 16, 64*1024 }, /* Riebl */
+ { 0xffcffff0, 0xffcf0000, 5, 16, 64*1024 }, /* PAM */
+ { 0xfecffff0, 0xfecf0000, 5, 16, 64*1024 }, /* Rhotron */
+ { 0xfeff4100, 0xfe000000, 4, 8, VMECF_MEMSIZ_DEFAULT } /*BVME410*/
};
#define NLESTD (sizeof(lestd) / sizeof(lestd[0]))
/*
- * All cards have 64KB RAM. However.... On the Riebl cards the area
- * between the offsets 0xee70-0xeec0 is used to store config data.
- */
-#define MEMSIZE (64*1024)
-
-/*
* Default mac for RIEBL cards without a (working) battery. The first 4 bytes
* are the manufacturer id.
*/
@@ -108,6 +109,10 @@
static int probe_addresses __P((bus_space_tag_t *, bus_space_tag_t *,
bus_space_handle_t *, bus_space_handle_t *));
static void riebl_skip_reserved_area __P((struct lance_softc *));
+static int nm93c06_read __P((bus_space_tag_t, bus_space_handle_t, int));
+static int bvme410_mem_size __P((bus_space_tag_t, u_long));
+static void bvme410_copytobuf __P((struct lance_softc *, void *, int, int));
+static void bvme410_zerobuf __P((struct lance_softc *, int, int));
struct cfattach le_vme_ca = {
sizeof(struct le_softc), le_vme_match, le_vme_attach
@@ -190,24 +195,35 @@
if ((le_ap->irq != IRQUNK) && (va->va_irq != le_ap->irq))
continue;
- if (bus_space_map(iot, le_ap->reg_addr, 16, 0, &ioh)) {
+ if (bus_space_map(iot, le_ap->reg_addr, le_ap->reg_size, 0, &ioh)) {
printf("leprobe: cannot map io-area\n");
return (0);
}
- if (bus_space_map(memt, le_ap->mem_addr, MEMSIZE, 0, &memh)) {
- bus_space_unmap(iot, (caddr_t)le_ap->reg_addr, 16);
+ if (le_ap->mem_size == VMECF_MEMSIZ_DEFAULT) {
+ if (bus_space_peek_2(iot, ioh, BVME410_IVEC)) {
+ bus_space_write_2(iot, ioh, BVME410_BAR, 0x1); /* XXX */
+ le_ap->mem_size = bvme410_mem_size(memt, le_ap->mem_addr);
+ }
+ }
+ if (le_ap->mem_size == VMECF_MEMSIZ_DEFAULT) {
+ bus_space_unmap(iot, (caddr_t)le_ap->reg_addr, le_ap->reg_size);
+ continue;
+ }
+
+ if (bus_space_map(memt, le_ap->mem_addr, le_ap->mem_size, 0, &memh)) {
+ bus_space_unmap(iot, (caddr_t)le_ap->reg_addr, le_ap->reg_size);
printf("leprobe: cannot map memory-area\n");
return (0);
}
found = probe_addresses(&iot, &memt, &ioh, &memh);
- bus_space_unmap(iot, (caddr_t)le_ap->reg_addr, 16);
- bus_space_unmap(memt, (caddr_t)le_ap->mem_addr, 8*NBPG);
+ bus_space_unmap(iot, (caddr_t)le_ap->reg_addr, le_ap->reg_size);
+ bus_space_unmap(memt, (caddr_t)le_ap->mem_addr, le_ap->mem_size);
if (found) {
va->va_iobase = le_ap->reg_addr;
- va->va_iosize = 16;
+ va->va_iosize = le_ap->reg_size;
va->va_maddr = le_ap->mem_addr;
- va->va_msize = MEMSIZE;
+ va->va_msize = le_ap->mem_size;
if (va->va_irq == IRQUNK)
va->va_irq = le_ap->irq;
return 1;
@@ -333,6 +349,10 @@
lesc->sc_type = LE_PAM;
bus_space_read_1(va->va_iot, ioh, LER_MEME);
}
+ else if (bus_space_peek_2(va->va_iot, ioh, BVME410_IVEC)) {
+ printf("BVME410");
+ lesc->sc_type = LE_BVME410;
+ }
else {
printf("Riebl card");
if(bus_space_read_4(va->va_memt, memh, RIEBL_MAGIC_ADDR)
@@ -344,11 +364,22 @@
}
}
- sc->sc_copytodesc = lance_copytobuf_contig;
- sc->sc_copyfromdesc = lance_copyfrombuf_contig;
- sc->sc_copytobuf = lance_copytobuf_contig;
- sc->sc_copyfrombuf = lance_copyfrombuf_contig;
- sc->sc_zerobuf = lance_zerobuf_contig;
+ switch (lesc->sc_type) {
+ case LE_BVME410:
+ sc->sc_copytodesc = bvme410_copytobuf;
+ sc->sc_copyfromdesc = lance_copyfrombuf_contig;
+ sc->sc_copytobuf = bvme410_copytobuf;
+ sc->sc_copyfrombuf = lance_copyfrombuf_contig;
+ sc->sc_zerobuf = bvme410_zerobuf;
+ break;
+ default:
+ sc->sc_copytodesc = lance_copytobuf_contig;
+ sc->sc_copyfromdesc = lance_copyfrombuf_contig;
+ sc->sc_copytobuf = lance_copytobuf_contig;
+ sc->sc_copyfrombuf = lance_copyfrombuf_contig;
+ sc->sc_zerobuf = lance_zerobuf_contig;
+ break;
+ }
sc->sc_rdcsr = lerdcsr;
sc->sc_wrcsr = lewrcsr;
@@ -380,6 +411,15 @@
}
i = bus_space_read_1(va->va_iot, ioh, LER_MEME);
break;
+ case LE_BVME410:
+ for (i = 0; i < (sizeof(sc->sc_enaddr) >> 1); i++) {
+ u_int16_t tmp;
+
+ tmp = nm93c06_read(va->va_iot, ioh, i);
+ sc->sc_enaddr[2 * i] = (tmp >> 8) & 0xff;
+ sc->sc_enaddr[2 * i + 1] = tmp & 0xff;
+ }
+ bus_space_write_2(va->va_iot, ioh, BVME410_BAR, 0x1); /* XXX */
}
am7990_config(&lesc->sc_am7990);
@@ -408,6 +448,9 @@
case LE_PAM:
bus_space_write_1(va->va_iot, ioh, LER_IVEC, 64 + 64);
break;
+ case LE_BVME410:
+ bus_space_write_2(va->va_iot, ioh, BVME410_IVEC, 64 + 64);
+ break;
}
/*
@@ -445,3 +488,102 @@
sc->sc_tbufaddr[i] += offset;
}
}
+
+static int
+nm93c06_read(iot, ioh, nm93c06reg)
+ bus_space_tag_t iot;
+ bus_space_handle_t ioh;
+ int nm93c06reg;
+{
+ int bar;
+ int shift;
+ int bits = 0x180 | (nm93c06reg & 0xf);
+ int data = 0;
+
+ bar = 1<<BVME410_CS_SHIFT;
+ bus_space_write_2(iot, ioh, BVME410_BAR, bar);
+ delay(1); /* tCSS = 1 us */
+ for (shift = 9; shift >= 0; shift--) {
+ if (((bits >> shift) & 1) == 1)
+ bar |= 1<<BVME410_DIN_SHIFT;
+ else
+ bar &= ~(1<<BVME410_DIN_SHIFT);
+ bus_space_write_2(iot, ioh, BVME410_BAR, bar);
+ delay(1); /* tDIS = 0.4 us */
+ bar |= 1<<BVME410_CLK_SHIFT;
+ bus_space_write_2(iot, ioh, BVME410_BAR, bar);
+ delay(2); /* tSKH = 1 us, tSKH + tSKL >= 4 us */
+ bar &= ~(1<<BVME410_CLK_SHIFT);
+ bus_space_write_2(iot, ioh, BVME410_BAR, bar);
+ delay(2); /* tSKL = 1 us, tSKH + tSKL >= 4 us */
+ }
+ bar &= ~(1<<BVME410_DIN_SHIFT);
+ for (shift = 15; shift >= 0; shift--) {
+ delay(1); /* tDIS = 100 ns, BVM manual says 0.4 us */
+ bar |= 1<<BVME410_CLK_SHIFT;
+ bus_space_write_2(iot, ioh, BVME410_BAR, bar);
+ delay(2); /* tSKH = 1 us, tSKH + tSKL >= 4 us */
+ data |= (bus_space_read_2(iot, ioh, BVME410_BAR) & 1) << shift;
+ bar &= ~(1<<BVME410_CLK_SHIFT);
+ bus_space_write_2(iot, ioh, BVME410_BAR, bar);
+ delay(2); /* tSKL = 1 us, tSKH + tSKL >= 4 us */
+ }
+ bar &= ~(1<<BVME410_CS_SHIFT);
+ bus_space_write_2(iot, ioh, BVME410_BAR, bar);
+ delay(1); /* tCS = 1 us */
+ return data;
+}
+
+static int
+bvme410_mem_size(memt, mem_addr)
+ bus_space_tag_t memt;
+ u_long mem_addr;
+{
+ bus_space_handle_t memh;
+ int r;
+
+ if (bus_space_map(memt, mem_addr, 256*1024, 0, &memh))
+ return VMECF_MEMSIZ_DEFAULT;
+ if (!bus_space_peek_1(memt, memh, 0)) {
+ bus_space_unmap(memt, (caddr_t)mem_addr, 256*1024);
+ return VMECF_MEMSIZ_DEFAULT;
+ }
+ bus_space_write_1(memt, memh, 0, 128);
+ bus_space_write_1(memt, memh, 64*1024, 32);
+ bus_space_write_1(memt, memh, 32*1024, 8);
+ r = (int)(bus_space_read_1(memt, memh, 0) * 2048);
+ bus_space_unmap(memt, (caddr_t)mem_addr, 256*1024);
+ return r;
+}
+
+/*
+ * Need to be careful when writing to the bvme410 dual port memory.
+ * Continue writing each byte until it reads back the same.
+ */
+
+static void
+bvme410_copytobuf(sc, from, boff, len)
+ struct lance_softc *sc;
+ void *from;
+ int boff, len;
+{
+ volatile char *buf = (volatile char *) sc->sc_mem;
+ char *f = (char *) from;
+
+ for (buf += boff; len; buf++,f++,len--)
+ while (*buf != *f)
+ *buf = *f;
+}
+
+static void
+bvme410_zerobuf(sc, boff, len)
+ struct lance_softc *sc;
+ int boff, len;
+{
+ volatile char *buf = (volatile char *)sc->sc_mem;
+
+ for (buf += boff; len; buf++,len--)
+ while (*buf != '\0')
+ *buf = '\0';
+}
+
--- /sys/arch/atari/vme/if_levar.h-orig Thu Oct 9 19:25:38 1997
+++ /sys/arch/atari/vme/if_levar.h Tue Dec 1 19:48:43 1998
@@ -42,6 +42,8 @@
*/
#define LER_RDP 0 /* Data port */
#define LER_RAP 2 /* Register select port */
+#define BVME410_IVEC 4 /* Interrupt ID Register */
+#define BVME410_BAR 6 /* BVME410 RAM Base Address Reg */
#define LER_IVEC 7 /* Interrupt vector */
#define LER_EEPROM 13 /* PAM's Eeprom enable port */
#define LER_MEME 15 /* PAM's Mem enable port */
@@ -72,6 +74,7 @@
#define LE_PAM 0
#define LE_OLD_RIEBL 1
#define LE_NEW_RIEBL 2
+#define LE_BVME410 3
/*
* Determine type of RIEBL card by magic
@@ -94,3 +97,12 @@
*/
#define RIEBL_RES_START 0xee70
#define RIEBL_RES_END 0xeec0
+
+/*
+ * Bits in the BVME410 RAM Base Address Register, when node address
+ * serial EEPROM is enabled.
+ */
+#define BVME410_CS_SHIFT 1
+#define BVME410_CLK_SHIFT 2
+#define BVME410_DIN_SHIFT 3
+
--- /sys/arch/atari/conf/GENERIC-orig Wed Dec 2 03:56:31 1998
+++ /sys/arch/atari/conf/GENERIC Wed Dec 2 03:56:57 1998
@@ -184,6 +184,7 @@
avmebus0 at mainbus0 # VME bus
vme0 at avmebus0
le0 at vme0 irq 5 # Lance ethernet (Riebl/PAM).
+le0 at vme0 irq 4 # Lance ethernet (BVME410).
et0 at vme0 # Crazy Dots II
isabus0 at mainbus0 # ISA-bus
--
entropy -- it's not just a good idea, it's the second law.