NetBSD/sys/arch/mvme68k/stand/netboot/if_ie.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

501 lines
12 KiB
C

/* $NetBSD: if_ie.c,v 1.5 2000/07/24 18:39:51 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.
*/
#include <sys/param.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/in_systm.h>
#include <net/if.h>
#include <net/if_ether.h>
#include <lib/libkern/libkern.h>
#include <lib/libsa/stand.h>
#include <lib/libsa/net.h>
#define NTXBUF 1
#define NRXBUF 16
#define IE_RBUF_SIZE ETHER_MAX_LEN
#include <machine/prom.h>
#include "libsa.h"
#include "netif.h"
#include "config.h"
#include "dev_net.h"
#include "i82586.h"
#include "if_iereg.h"
int ie_debug = 0;
void ie_stop __P((struct netif *));
void ie_end __P((struct netif *));
void ie_error __P((struct netif *, char *, volatile struct iereg *));
int ie_get __P((struct iodesc *, void *, size_t, time_t));
void ie_init __P((struct iodesc *, void *));
int ie_match __P((struct netif *, void *));
int ie_poll __P((struct iodesc *, void *, int));
int ie_probe __P((struct netif *, void *));
int ie_put __P((struct iodesc *, void *, size_t));
void ie_reset __P((struct netif *, u_char *));
void ieack __P((volatile struct iereg *, struct iemem *));
struct netif_stats ie_stats;
struct netif_dif ie0_dif = {
0, /* unit */
1, /* nsel */
&ie_stats,
0,
0,
};
struct netif_driver ie_driver = {
"ie", /* netif_bname */
ie_match, /* match */
ie_probe, /* probe */
ie_init, /* init */
ie_get, /* get */
ie_put, /* put */
ie_end, /* end */
&ie0_dif, /* netif_ifs */
1, /* netif_nifs */
};
struct ie_configuration {
u_int phys_addr;
int used;
} ie_config[] = {
{ INTEL_REG_ADDR, 0 }
};
int nie_config = sizeof(ie_config) / (sizeof(ie_config[0]));
struct {
struct iereg *sc_reg; /* IE registers */
struct iemem *sc_mem; /* RAM */
} ie_softc;
int
ie_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(ie_driver.netif_bname, name, 2))
val += 10;
for (i = 0; i < nie_config; i++) {
if (ie_config[i].used)
continue;
if (ie_debug)
printf("ie%d: ie_match --> %d\n", i, val + 1);
ie_config[i].used++;
return (val + 1);
}
if (ie_debug)
printf("ie%d: ie_match --> 0\n", i);
return (0);
}
int
ie_probe(nif, machdep_hint)
struct netif *nif;
void *machdep_hint;
{
/* the set unit is the current unit */
if (ie_debug)
printf("ie%d: ie_probe called\n", nif->nif_unit);
if (bugargs.cputyp != CPU_147)
return (0);
return (1);
}
void
ie_error(nif, str, ier)
struct netif *nif;
char *str;
volatile struct iereg *ier;
{
panic("ie%d: unknown error\n", nif->nif_unit);
}
void
ieack(ier, iem)
volatile struct iereg *ier;
struct iemem *iem;
{
/* ack the `interrupt' */
iem->im_scb.ie_command = iem->im_scb.ie_status & IE_ST_WHENCE;
ier->ie_attention = 1; /* chan attention! */
while (iem->im_scb.ie_command)
;
}
void
ie_reset(nif, myea)
struct netif *nif;
u_char *myea;
{
volatile struct iereg *ier = ie_softc.sc_reg;
struct iemem *iem = ie_softc.sc_mem;
int timo = 10000, i;
volatile int t;
u_int a;
if (ie_debug)
printf("ie%d: ie_reset called\n", nif->nif_unit);
/*printf("ier %x iem %x\n", ier, iem);*/
*(u_char *)0xfff4202a = 0x40;
bzero(iem, sizeof(*iem));
iem->im_scp.scp_sysbus = 0;
iem->im_scp.scp_iscp_low = (int) &iem->im_iscp & 0xffff;
iem->im_scp.scp_iscp_high = (int) &iem->im_iscp >> 16;
iem->im_iscp.iscp_scboffset = (int) &iem->im_scb - (int) iem;
iem->im_iscp.iscp_busy = 1;
iem->im_iscp.iscp_base_low = (int) iem & 0xffff;
iem->im_iscp.iscp_base_high = (int) iem >> 16;
/*
* completely and utterly unlike what i expected, the
* "write" order is:
* 1st: d15-d0 -> high address
* 2nd: d31-d16 -> low address
*/
/* reset chip */
a = IE_PORT_RESET;
ier->ie_porthigh = a & 0xffff;
t = 0;
t = 1;
ier->ie_portlow = a >> 16;
for (t = timo; t--;)
;
/* set new SCP pointer */
a = (int) &iem->im_scp | IE_PORT_NEWSCP;
ier->ie_porthigh = a & 0xffff;
t = 0;
t = 1;
ier->ie_portlow = a >> 16;
for (t = timo; t--;)
;
ier->ie_attention = 1; /* chan attention! */
for (t = timo * 10; t--;)
;
/* send CONFIGURE command */
iem->im_scb.ie_command = IE_CU_START;
iem->im_scb.ie_command_list = (int) &iem->im_cc - (int) iem;
iem->im_cc.com.ie_cmd_status = 0;
iem->im_cc.com.ie_cmd_cmd = IE_CMD_CONFIG | IE_CMD_LAST;
iem->im_cc.com.ie_cmd_link = 0xffff;
iem->im_cc.ie_config_count = 0x0c;
iem->im_cc.ie_fifo = 8;
iem->im_cc.ie_save_bad = 0x40;
iem->im_cc.ie_addr_len = 0x2e;
iem->im_cc.ie_priority = 0;
iem->im_cc.ie_ifs = 0x60;
iem->im_cc.ie_slot_low = 0;
iem->im_cc.ie_slot_high = 0xf2;
iem->im_cc.ie_promisc = 0;
iem->im_cc.ie_crs_cdt = 0;
iem->im_cc.ie_min_len = 64;
iem->im_cc.ie_junk = 0xff;
ier->ie_attention = 1; /* chan attention! */
for (t = timo * 10; t--;)
;
ieack(ier, iem);
/*printf("ic %x\n", &iem->im_ic);*/
/* send IASETUP command */
iem->im_scb.ie_command = IE_CU_START;
iem->im_scb.ie_command_list = (int) &iem->im_ic - (int) iem;
iem->im_ic.com.ie_cmd_status = 0;
iem->im_ic.com.ie_cmd_cmd = IE_CMD_IASETUP | IE_CMD_LAST;
iem->im_ic.com.ie_cmd_link = 0xffff;
bcopy(myea, (void *)&iem->im_ic.ie_address, sizeof iem->im_ic.ie_address);
ier->ie_attention = 1; /* chan attention! */
for (t = timo * 10; t--;)
;
ieack(ier, iem);
/* setup buffers */
for (i = 0; i < NRXBUF; i++) {
iem->im_rfd[i].ie_fd_next = (int) &iem->im_rfd[(i+1) % NRXBUF] -
(int) iem;
iem->im_rbd[i].ie_rbd_next = (int) &iem->im_rbd[(i+1) % NRXBUF] -
(int) iem;
a = (int) &iem->im_rxbuf[i * IE_RBUF_SIZE];
iem->im_rbd[i].ie_rbd_buffer_low = a & 0xffff;
iem->im_rbd[i].ie_rbd_buffer_high = a >> 16;
iem->im_rbd[i].ie_rbd_length = IE_RBUF_SIZE;
}
iem->im_rfd[NRXBUF-1].ie_fd_last |= IE_FD_LAST;
iem->im_rbd[NRXBUF-1].ie_rbd_length |= IE_RBD_LAST;
iem->im_rfd[0].ie_fd_buf_desc = (int) &iem->im_rbd[0] - (int) iem;
/*printf("rfd[0] %x rbd[0] %x buf[0] %x\n", &iem->im_rfd, &iem->im_rbd,
&iem->im_rxbuf);*/
/* send receiver start command */
iem->im_scb.ie_command = IE_RU_START;
iem->im_scb.ie_command_list = 0;
iem->im_scb.ie_recv_list = (int) &iem->im_rfd[0] - (int) iem;
ier->ie_attention = 1; /* chan attention! */
while (iem->im_scb.ie_command)
;
ieack(ier, iem);
}
int
ie_poll(desc, pkt, len)
struct iodesc *desc;
void *pkt;
int len;
{
volatile struct iereg *ier = ie_softc.sc_reg;
struct iemem *iem = ie_softc.sc_mem;
static int slot;
int length = 0;
u_short status;
asm(".word 0xf518\n");
status = iem->im_rfd[slot].ie_fd_status;
if (status & IE_FD_BUSY)
return (0);
/* printf("slot %d: %x\n", slot, status); */
if ((status & (IE_FD_COMPLETE | IE_FD_OK)) == (IE_FD_COMPLETE | IE_FD_OK)) {
if (status & IE_FD_OK) {
length = iem->im_rbd[slot].ie_rbd_actual & 0x3fff;
if (length > len)
length = len;
bcopy((void *)&iem->im_rxbuf[slot * IE_RBUF_SIZE],
pkt, length);
iem->im_rfd[slot].ie_fd_status = 0;
iem->im_rfd[slot].ie_fd_last |= IE_FD_LAST;
iem->im_rfd[(slot+NRXBUF-1)%NRXBUF].ie_fd_last &=
~IE_FD_LAST;
iem->im_rbd[slot].ie_rbd_actual = 0;
iem->im_rbd[slot].ie_rbd_length |= IE_RBD_LAST;
iem->im_rbd[(slot+NRXBUF-1)%NRXBUF].ie_rbd_length &=
~IE_RBD_LAST;
/*printf("S%d\n", slot);*/
} else {
printf("shit\n");
}
slot++;
/* should move descriptor onto end of queue... */
}
if ((iem->im_scb.ie_status & IE_RU_READY) == 0) {
printf("RR\n");
for (slot = 0; slot < NRXBUF; slot++) {
iem->im_rbd[slot].ie_rbd_length &= ~IE_RBD_LAST;
iem->im_rfd[slot].ie_fd_last &= ~IE_FD_LAST;
}
iem->im_rbd[NRXBUF-1].ie_rbd_length |= IE_RBD_LAST;
iem->im_rfd[NRXBUF-1].ie_fd_last |= IE_FD_LAST;
iem->im_rfd[0].ie_fd_buf_desc = (int)&iem->im_rbd[0] - (int)iem;
iem->im_scb.ie_command = IE_RU_START;
iem->im_scb.ie_command_list = 0;
iem->im_scb.ie_recv_list = (int)&iem->im_rfd[0] - (int)iem;
ier->ie_attention = 1; /* chan attention! */
while (iem->im_scb.ie_command)
;
slot = 0;
}
slot = slot % NRXBUF;
return (length);
}
int
ie_put(desc, pkt, len)
struct iodesc *desc;
void *pkt;
size_t len;
{
volatile struct iereg *ier = ie_softc.sc_reg;
struct iemem *iem = ie_softc.sc_mem;
u_char *p = pkt;
u_int a;
int xx = 0;
/* send transmit command */
while (iem->im_scb.ie_command)
;
/* copy data */
bcopy(p, (void *)&iem->im_txbuf[xx], len);
len = MAX(len, ETHER_MIN_LEN);
/* build transmit descriptor */
iem->im_xd[xx].ie_xmit_flags = len | IE_XMIT_LAST;
iem->im_xd[xx].ie_xmit_next = 0xffff;
a = (int) &iem->im_txbuf[xx];
iem->im_xd[xx].ie_xmit_buf_low = a & 0xffff;
iem->im_xd[xx].ie_xmit_buf_high = a >> 16;
/* transmit command */
iem->im_xc[xx].com.ie_cmd_status = 0;
iem->im_xc[xx].com.ie_cmd_cmd = IE_CMD_XMIT | IE_CMD_LAST;
iem->im_xc[xx].com.ie_cmd_link = 0xffff;
iem->im_xc[xx].ie_xmit_desc = (int) &iem->im_xd[xx] - (int) iem;
iem->im_xc[xx].ie_xmit_length = len;
bcopy(p, (void *)&iem->im_xc[xx].ie_xmit_addr,
sizeof iem->im_xc[xx].ie_xmit_addr);
iem->im_scb.ie_command = IE_CU_START;
iem->im_scb.ie_command_list = (int) &iem->im_xc[xx] - (int) iem;
ier->ie_attention = 1; /* chan attention! */
if (ie_debug) {
printf("ie%d: send %d to %x:%x:%x:%x:%x:%x\n",
desc->io_netif->nif_unit, len,
p[0], p[1], p[2], p[3], p[4], p[5]);
}
return (len);
}
int
ie_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 = ie_poll(desc, pkt, len);
}
return (cc);
}
/*
* init ie device. return 0 on failure, 1 if ok.
*/
void
ie_init(desc, machdep_hint)
struct iodesc *desc;
void *machdep_hint;
{
struct netif *nif = desc->io_netif;
if (ie_debug)
printf("ie%d: ie_init called\n", desc->io_netif->nif_unit);
machdep_common_ether(desc->myea);
bzero(&ie_softc, sizeof(ie_softc));
ie_softc.sc_reg =
(struct iereg *) ie_config[desc->io_netif->nif_unit].phys_addr;
ie_softc.sc_mem = (struct iemem *) 0x3e0000;
ie_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
ie_stop(nif)
struct netif *nif;
{
volatile struct iereg *ier = ie_softc.sc_reg;
struct iemem *iem = ie_softc.sc_mem;
int timo = 10000;
volatile int t;
u_int a;
iem->im_iscp.iscp_busy = 1;
/* reset chip */
a = IE_PORT_RESET;
ier->ie_porthigh = a & 0xffff;
t = 0;
t = 1;
ier->ie_portlow = a >> 16;
for (t = timo; t--;)
;
/* reset chip again */
a = IE_PORT_RESET;
ier->ie_porthigh = a & 0xffff;
t = 0;
t = 1;
ier->ie_portlow = a >> 16;
for (t = timo; t--;)
;
/*printf("status %x busy %x\n", iem->im_scb.ie_status,
iem->im_iscp.iscp_busy);*/
}
void
ie_end(nif)
struct netif *nif;
{
if (ie_debug)
printf("ie%d: ie_end called\n", nif->nif_unit);
ie_stop(nif);
/* *(u_char *) 0xfff42002 = 0; */
}