summaryrefslogtreecommitdiff
path: root/sys/arch/mvme68k/stand/netboot/if_le.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/arch/mvme68k/stand/netboot/if_le.c')
-rw-r--r--sys/arch/mvme68k/stand/netboot/if_le.c431
1 files changed, 431 insertions, 0 deletions
diff --git a/sys/arch/mvme68k/stand/netboot/if_le.c b/sys/arch/mvme68k/stand/netboot/if_le.c
new file mode 100644
index 00000000000..8049b69b9e0
--- /dev/null
+++ b/sys/arch/mvme68k/stand/netboot/if_le.c
@@ -0,0 +1,431 @@
+/* $NetBSD: le_poll.c,v 1.3 1994/10/26 09:11:48 cgd Exp $ */
+
+/*
+ * Copyright (c) 1993 Adam Glass
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Adam Glass.
+ * 4. The name of the Author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Adam Glass ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/param.h>
+#include <sys/types.h>
+
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+
+#include "stand.h"
+#include "netif.h"
+#include "config.h"
+
+#include "if_lereg.h"
+
+int le_debug = 0;
+
+void le_end __P((struct netif *));
+void le_error __P((struct netif *, char *, volatile struct lereg1 *));
+int le_get __P((struct iodesc *, void *, int, time_t));
+void le_init __P((struct iodesc *, void *));
+int le_match __P((struct netif *, void *));
+int le_poll __P((struct iodesc *, void *, int));
+int le_probe __P((struct netif *, void *));
+int le_put __P((struct iodesc *, void *, int));
+void le_reset __P((struct netif *, u_char *));
+
+struct netif_stats le_stats;
+
+struct netif_dif le0_dif = {
+ 0, /* unit */
+ 1, /* nsel */
+ &le_stats,
+ 0,
+ 0,
+};
+
+struct netif_driver le_driver = {
+ "le", /* netif_bname */
+ le_match, /* match */
+ le_probe, /* probe */
+ le_init, /* init */
+ le_get, /* get */
+ le_put, /* put */
+ le_end, /* end */
+ &le0_dif, /* netif_ifs */
+ 1, /* netif_nifs */
+};
+
+struct le_configuration {
+ unsigned int phys_addr;
+ int used;
+} le_config[] = {
+ { LANCE_REG_ADDR, 0 }
+};
+
+int nle_config = sizeof(le_config) / (sizeof(le_config[0]));
+
+struct {
+ struct lereg1 *sc_r1; /* LANCE registers */
+ struct lereg2 *sc_r2; /* RAM */
+ int next_rmd;
+ int next_tmd;
+} le_softc;
+
+int
+le_match(nif, machdep_hint)
+ struct netif *nif;
+ void *machdep_hint;
+{
+ char *name;
+ int i, val = 0;
+ extern int cputyp;
+
+ if (cputyp != CPU_147)
+ return (0);
+ name = machdep_hint;
+ if (name && !bcmp(le_driver.netif_bname, name, 2))
+ val += 10;
+ for (i = 0; i < nle_config; i++) {
+ if (le_config[i].used)
+ continue;
+ if (le_debug)
+ printf("le%d: le_match --> %d\n", i, val + 1);
+ le_config[i].used++;
+ return val + 1;
+ }
+ if (le_debug)
+ printf("le%d: le_match --> 0\n", i);
+ return 0;
+}
+
+int
+le_probe(nif, machdep_hint)
+ struct netif *nif;
+ void *machdep_hint;
+{
+ extern int cputyp;
+
+ /* the set unit is the current unit */
+ if (le_debug)
+ printf("le%d: le_probe called\n", nif->nif_unit);
+
+ if (cputyp == CPU_147)
+ return 0;
+ return 1;
+}
+
+void
+le_error(nif, str, ler1)
+ struct netif *nif;
+ char *str;
+ volatile struct lereg1 *ler1;
+{
+ /* ler1->ler1_rap = LE_CSRO done in caller */
+ if (ler1->ler1_rdp & LE_C0_BABL)
+ panic("le%d: been babbling, found by '%s'\n", nif->nif_unit, str);
+ if (ler1->ler1_rdp & LE_C0_CERR) {
+ le_stats.collision_error++;
+ ler1->ler1_rdp = LE_C0_CERR;
+ }
+ if (ler1->ler1_rdp & LE_C0_MISS) {
+ le_stats.missed++;
+ ler1->ler1_rdp = LE_C0_MISS;
+ }
+ if (ler1->ler1_rdp & LE_C0_MERR) {
+ printf("le%d: memory error in '%s'\n", nif->nif_unit, str);
+ panic("memory error");
+ }
+}
+
+void
+le_reset(nif, myea)
+ struct netif *nif;
+ u_char *myea;
+{
+ struct lereg1 *ler1 = le_softc.sc_r1;
+ struct lereg2 *ler2 = le_softc.sc_r2;
+ unsigned int a;
+ int timo = 100000, stat, i;
+
+ if (le_debug)
+ printf("le%d: le_reset called\n", nif->nif_unit);
+ ler1->ler1_rap = LE_CSR0;
+ ler1->ler1_rdp = LE_C0_STOP; /* do nothing until we are finished */
+
+ bzero(ler2, sizeof(*ler2));
+
+ ler2->ler2_mode = LE_MODE_NORMAL;
+ ler2->ler2_padr[0] = myea[1];
+ ler2->ler2_padr[1] = myea[0];
+ ler2->ler2_padr[2] = myea[3];
+ ler2->ler2_padr[3] = myea[2];
+ ler2->ler2_padr[4] = myea[5];
+ ler2->ler2_padr[5] = myea[4];
+
+
+ ler2->ler2_ladrf0 = 0;
+ ler2->ler2_ladrf1 = 0;
+
+ a = (u_int) ler2->ler2_rmd;
+ ler2->ler2_rlen = LE_RLEN | (a >> 16);
+ ler2->ler2_rdra = a & LE_ADDR_LOW_MASK;
+
+ a = (u_int) ler2->ler2_tmd;
+ ler2->ler2_tlen = LE_TLEN | (a >> 16);
+ ler2->ler2_tdra = a & LE_ADDR_LOW_MASK;
+
+ ler1->ler1_rap = LE_CSR1;
+ a = (u_int) ler2;
+ ler1->ler1_rdp = a & LE_ADDR_LOW_MASK;
+ ler1->ler1_rap = LE_CSR2;
+ ler1->ler1_rdp = a >> 16;
+
+ for (i = 0; i < LERBUF; i++) {
+ a = (u_int) & ler2->ler2_rbuf[i];
+ ler2->ler2_rmd[i].rmd0 = a & LE_ADDR_LOW_MASK;
+ ler2->ler2_rmd[i].rmd1_bits = LE_R1_OWN;
+ ler2->ler2_rmd[i].rmd1_hadr = a >> 16;
+ ler2->ler2_rmd[i].rmd2 = -LEMTU;
+ ler2->ler2_rmd[i].rmd3 = 0;
+ }
+ for (i = 0; i < LETBUF; i++) {
+ a = (u_int) & ler2->ler2_tbuf[i];
+ ler2->ler2_tmd[i].tmd0 = a & LE_ADDR_LOW_MASK;
+ ler2->ler2_tmd[i].tmd1_bits = 0;
+ ler2->ler2_tmd[i].tmd1_hadr = a >> 16;
+ ler2->ler2_tmd[i].tmd2 = 0;
+ ler2->ler2_tmd[i].tmd3 = 0;
+ }
+
+ ler1->ler1_rap = LE_CSR3;
+ ler1->ler1_rdp = LE_C3_BSWP;
+
+ ler1->ler1_rap = LE_CSR0;
+ ler1->ler1_rdp = LE_C0_INIT;
+ do {
+ if (--timo == 0) {
+ printf("le%d: init timeout, stat = 0x%x\n",
+ nif->nif_unit, stat);
+ break;
+ }
+ stat = ler1->ler1_rdp;
+ } while ((stat & LE_C0_IDON) == 0);
+
+ ler1->ler1_rdp = LE_C0_IDON;
+ le_softc.next_rmd = 0;
+ le_softc.next_tmd = 0;
+ ler1->ler1_rap = LE_CSR0;
+ ler1->ler1_rdp = LE_C0_STRT;
+}
+
+int
+le_poll(desc, pkt, len)
+ struct iodesc *desc;
+ void *pkt;
+ int len;
+{
+ struct lereg1 *ler1 = le_softc.sc_r1;
+ struct lereg2 *ler2 = le_softc.sc_r2;
+ unsigned int a;
+ int length;
+ struct lermd *rmd;
+
+
+ ler1->ler1_rap = LE_CSR0;
+ if ((ler1->ler1_rdp & LE_C0_RINT) != 0)
+ ler1->ler1_rdp = LE_C0_RINT;
+ rmd = &ler2->ler2_rmd[le_softc.next_rmd];
+ if (rmd->rmd1_bits & LE_R1_OWN) {
+ return (0);
+ }
+ if (ler1->ler1_rdp & LE_C0_ERR)
+ le_error(desc->io_netif, "le_poll", ler1);
+ if (rmd->rmd1_bits & LE_R1_ERR) {
+ printf("le%d_poll: rmd status 0x%x\n", desc->io_netif->nif_unit,
+ rmd->rmd1_bits);
+ length = 0;
+ goto cleanup;
+ }
+ if ((rmd->rmd1_bits & (LE_R1_STP | LE_R1_ENP)) != (LE_R1_STP | LE_R1_ENP))
+ panic("le_poll: chained packet\n");
+
+ length = rmd->rmd3;
+ if (length >= LEMTU) {
+ length = 0;
+ panic("csr0 when bad things happen: %x\n", ler1->ler1_rdp);
+ goto cleanup;
+ }
+ if (!length)
+ goto cleanup;
+ length -= 4;
+ if (length > 0) {
+
+ /*
+ * if buffer is smaller than the packet truncate it.
+ * (is this wise?)
+ */
+ if (length > len)
+ length = len;
+
+ bcopy(&ler2->ler2_rbuf[le_softc.next_rmd], pkt, length);
+ }
+cleanup:
+ a = (u_int) & ler2->ler2_rbuf[le_softc.next_rmd];
+ rmd->rmd0 = a & LE_ADDR_LOW_MASK;
+ rmd->rmd1_hadr = a >> 16;
+ rmd->rmd2 = -LEMTU;
+ le_softc.next_rmd =
+ (le_softc.next_rmd == (LERBUF - 1)) ? 0 : (le_softc.next_rmd + 1);
+ rmd->rmd1_bits = LE_R1_OWN;
+ return length;
+}
+
+int
+le_put(desc, pkt, len)
+ struct iodesc *desc;
+ void *pkt;
+ int len;
+{
+ volatile struct lereg1 *ler1 = le_softc.sc_r1;
+ volatile struct lereg2 *ler2 = le_softc.sc_r2;
+ volatile struct letmd *tmd;
+ int timo = 100000, stat, i;
+ unsigned int a;
+
+ ler1->ler1_rap = LE_CSR0;
+ if (ler1->ler1_rdp & LE_C0_ERR)
+ le_error(desc->io_netif, "le_put(way before xmit)", ler1);
+ tmd = &ler2->ler2_tmd[le_softc.next_tmd];
+ while (tmd->tmd1_bits & LE_T1_OWN) {
+ printf("le%d: output buffer busy\n", desc->io_netif->nif_unit);
+ }
+ bcopy(pkt, ler2->ler2_tbuf[le_softc.next_tmd], len);
+ if (len < 64)
+ tmd->tmd2 = -64;
+ else
+ tmd->tmd2 = -len;
+ tmd->tmd3 = 0;
+ if (ler1->ler1_rdp & LE_C0_ERR)
+ le_error(desc->io_netif, "le_put(before xmit)", ler1);
+ tmd->tmd1_bits = LE_T1_STP | LE_T1_ENP | LE_T1_OWN;
+ a = (u_int) & ler2->ler2_tbuf[le_softc.next_tmd];
+ tmd->tmd0 = a & LE_ADDR_LOW_MASK;
+ tmd->tmd1_hadr = a >> 16;
+ ler1->ler1_rdp = LE_C0_TDMD;
+ if (ler1->ler1_rdp & LE_C0_ERR)
+ le_error(desc->io_netif, "le_put(after xmit)", ler1);
+ do {
+ if (--timo == 0) {
+ printf("le%d: transmit timeout, stat = 0x%x\n",
+ desc->io_netif->nif_unit, stat);
+ if (ler1->ler1_rdp & LE_C0_ERR)
+ le_error(desc->io_netif, "le_put(timeout)", ler1);
+ break;
+ }
+ stat = ler1->ler1_rdp;
+ } while ((stat & LE_C0_TINT) == 0);
+ ler1->ler1_rdp = LE_C0_TINT;
+ if (ler1->ler1_rdp & LE_C0_ERR) {
+ if ((ler1->ler1_rdp & (LE_C0_BABL | LE_C0_CERR | LE_C0_MISS |
+ LE_C0_MERR)) !=
+ LE_C0_CERR)
+ printf("le_put: xmit error, buf %d\n", le_softc.next_tmd);
+ le_error(desc->io_netif, "le_put(xmit error)", ler1);
+ }
+ le_softc.next_tmd = 0;
+/* (le_softc.next_tmd == (LETBUF - 1)) ? 0 : le_softc.next_tmd + 1;*/
+ if (tmd->tmd1_bits & LE_T1_DEF)
+ le_stats.deferred++;
+ if (tmd->tmd1_bits & LE_T1_ONE)
+ le_stats.collisions++;
+ if (tmd->tmd1_bits & LE_T1_MORE)
+ le_stats.collisions += 2;
+ if (tmd->tmd1_bits & LE_T1_ERR) {
+ printf("le%d: transmit error, error = 0x%x\n", desc->io_netif->nif_unit,
+ tmd->tmd3);
+ return -1;
+ }
+ if (le_debug) {
+ printf("le%d: le_put() successful: sent %d\n",
+ desc->io_netif->nif_unit, len);
+ printf("le%d: le_put(): tmd1_bits: %x tmd3: %x\n",
+ desc->io_netif->nif_unit,
+ (unsigned int) tmd->tmd1_bits,
+ (unsigned int) tmd->tmd3);
+ }
+ return len;
+}
+
+int
+le_get(desc, pkt, len, timeout)
+ struct iodesc *desc;
+ void *pkt;
+ int len;
+ time_t timeout;
+{
+ time_t t;
+ int cc;
+
+ t = getsecs();
+ cc = 0;
+ while (((getsecs() - t) < timeout) && !cc) {
+ cc = le_poll(desc, pkt, len);
+ }
+ return cc;
+}
+/*
+ * init le device. return 0 on failure, 1 if ok.
+ */
+void
+le_init(desc, machdep_hint)
+ struct iodesc *desc;
+ void *machdep_hint;
+{
+ u_long eram = 4*1024*1024;
+ struct netif *nif = desc->io_netif;
+
+ if (le_debug)
+ printf("le%d: le_init called\n", desc->io_netif->nif_unit);
+ machdep_common_ether(desc->myea);
+ bzero(&le_softc, sizeof(le_softc));
+ le_softc.sc_r1 =
+ (struct lereg1 *) le_config[desc->io_netif->nif_unit].phys_addr;
+ le_softc.sc_r2 = (struct lereg2 *) (eram - (1024 * 1024));
+ le_reset(desc->io_netif, desc->myea);
+ printf("device: %s%d attached to %s\n", nif->nif_driver->netif_bname,
+ nif->nif_unit, ether_sprintf(desc->myea));
+}
+
+void
+le_end(nif)
+ struct netif *nif;
+{
+ struct lereg1 *ler1 = le_softc.sc_r1;
+
+ if (le_debug)
+ printf("le%d: le_end called\n", nif->nif_unit);
+ ler1->ler1_rap = LE_CSR0;
+ ler1->ler1_rdp = LE_C0_STOP;
+}