NetBSD/sys/arch/mvme68k/stand/netboot/if_le.c
jdolecek 921705c3eb cleanup Makefiles, put common stuff to Makefile.booters, ditch unnecessary
stuff
make this all compile with -Wall -Wno-main -Wmissing-prototypes
	-Wstrict-prototypes -Werror , also compilable on 1.4.1
label itself as NetBSD/mvme68k instead of "BSD" in bootblock message
move bugcrt.c to libbug, remove bugcrt directory (bugcrt is still built
	and used separately to rest of libbug)
convert sboot to use ordinary mvme68 libsa, instead of copying needed
	stuff in libc_sa.c
convert to use version info generated by sys/conf/newvers_stand.sh
	instead of previous version.c files, add necessary 'version' files
put chiptotime() to separate libsa file (used also by sboot/clock.c)

Thanks to Steve Woodford for help with this. Note that -current build
might be hosed by this change, will be addressed by Steve shortly.
2000-07-24 18:39:01 +00:00

466 lines
13 KiB
C

/* $NetBSD: if_le.c,v 1.2 2000/07/24 18:39:52 jdolecek Exp $ */
/*
* Copyright (c) 1995 Theo de Raadt
*
* 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 under OpenBSD by
* Theo de Raadt for Willowglen Singapore.
* 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 THE AUTHOR ``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 AUTHOR 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.
*
* 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 <machine/prom.h>
#include <lib/libkern/libkern.h>
#include <lib/libsa/stand.h>
#include <lib/libsa/net.h>
#include "libsa.h"
#include "netif.h"
#include "config.h"
#include "dev_net.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 *, size_t, 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 *, size_t));
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;
if (bugargs.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;
{
/* the set unit is the current unit */
if (le_debug)
printf("le%d: le_probe called\n", nif->nif_unit);
if (bugargs.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((void *)&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;
size_t 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;
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, (void *)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;
size_t 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;
}