#include <sys/param.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/queue.h>
#include <net/if.h>
#include <net/if_ether.h>
#include <netinet/in.h>
#include <netinet/in_systm.h>
#include <lib/libsa/netif.h>
#include <lib/libsa/stand.h>
#include <lib/libsa/net.h>
#include "lib/libkern/libkern.h"
#include <dev/ic/sgecreg.h>
#include "arch/vax/include/sid.h"
#include "arch/vax/include/rpb.h"
#include "vaxstand.h"
static int ze_get(struct iodesc *, void *, size_t, saseconds_t);
static int ze_put(struct iodesc *, void *, size_t);
struct netif_driver ze_driver = {
0, 0, 0, 0, ze_get, ze_put,
};
#define NRCV 8
#define NXMT 4
#define SETUP_FRAME_LEN 128
#define OW_ALLOC(x) ((void *)((int)((int)alloc((x) + 15) + 15) & ~15))
static volatile struct zedevice *addr;
struct ze_tdes *ze_tdes_list;
struct ze_rdes *ze_rdes_list;
u_char ze_myaddr[ETHER_ADDR_LEN];
int
zeopen(struct open_file *f, int adapt, int ctlr, int unit, int part)
{
u_long nicsr0_work, *nisa_rom;
struct ze_tdes *ze_setup_tdes_list;
int i;
if (askname == 0)
addr = (struct zedevice *)bootrpb.csrphy;
else
addr = (struct zedevice *)0x20008000;
addr->ze_nicsr6 = ZE_NICSR6_MBO | ZE_NICSR6_RE;
while ((addr->ze_nicsr5 & ZE_NICSR5_ID) == 0)
;
if (addr->ze_nicsr5 & ZE_NICSR5_SF) {
printf("SGEC self-test failed...\n");
return 1;
}
if (vax_boardtype == VAX_BTYP_49) {
nisa_rom = (u_long *)0x27800000;
for (i=0; i<ETHER_ADDR_LEN; i++)
ze_myaddr[i] = nisa_rom[i] & 0377;
} else if (vax_boardtype == VAX_BTYP_VXT) {
nisa_rom = (u_long *)0x200c4000;
for (i=0; i<ETHER_ADDR_LEN; i++)
ze_myaddr[i] = nisa_rom[i] & 0xff;
} else {
nisa_rom = (u_long *)0x20084000;
for (i=0; i<ETHER_ADDR_LEN; i++)
if (vax_boardtype == VAX_BTYP_660)
ze_myaddr[i] = (nisa_rom[i] & 0xff000000) >> 24;
else
ze_myaddr[i] = (nisa_rom[i] & 0x0000ff00) >> 8;
}
printf("SGEC: Ethernet address %s\n", ether_sprintf(ze_myaddr));
nicsr0_work = ZE_NICSR0_IPL14 | ZE_NICSR0_SA | ZE_NICSR0_MBO |
(ZE_NICSR0_IV_MASK & 0x0108);
while (addr->ze_nicsr0 != nicsr0_work)
addr->ze_nicsr0 = nicsr0_work;
if (addr->ze_nicsr5 & ZE_NICSR5_ME)
addr->ze_nicsr5 |= ZE_NICSR5_ME;
ze_rdes_list = OW_ALLOC((NRCV+1) * sizeof(struct ze_rdes));
ze_tdes_list = OW_ALLOC((NXMT+1) * sizeof(struct ze_tdes));
for (i=0; i < NRCV; i++) {
memset(ze_rdes_list+i, 0,sizeof(struct ze_rdes));
ze_rdes_list[i].ze_framelen = ZE_FRAMELEN_OW;
ze_rdes_list[i].ze_bufsize = ETHER_MAX_LEN;
ze_rdes_list[i].ze_bufaddr = alloc(ETHER_MAX_LEN);
}
memset(ze_rdes_list+NRCV, 0,sizeof(struct ze_rdes));
ze_rdes_list[NRCV].ze_framelen = ZE_FRAMELEN_OW;
ze_rdes_list[NRCV].ze_rdes1 = ZE_RDES1_CA;
ze_rdes_list[NRCV].ze_bufaddr = (u_char *)ze_rdes_list;
for (i=0; i < NXMT; i++) {
memset(ze_tdes_list+i, 0,sizeof(struct ze_tdes));
ze_tdes_list[i].ze_tdes1 = ZE_TDES1_FS | ZE_TDES1_LS;
ze_tdes_list[i].ze_bufsize = ETHER_MAX_LEN;
ze_tdes_list[i].ze_bufaddr = alloc(ETHER_MAX_LEN);
}
memset(ze_tdes_list+NXMT, 0,sizeof(struct ze_tdes));
ze_tdes_list[NXMT].ze_tdes1 = ZE_TDES1_CA;
ze_tdes_list[NXMT].ze_tdr = ZE_TDR_OW;
ze_tdes_list[NXMT].ze_bufaddr = (u_char *)ze_tdes_list;
ze_setup_tdes_list = OW_ALLOC(2*sizeof(struct ze_tdes));
memset(ze_setup_tdes_list+0, 0,2*sizeof(struct ze_tdes));
ze_setup_tdes_list[0].ze_tdr = ZE_TDR_OW;
ze_setup_tdes_list[0].ze_tdes1 = ZE_TDES1_DT_SETUP;
ze_setup_tdes_list[0].ze_bufsize = SETUP_FRAME_LEN;
ze_setup_tdes_list[0].ze_bufaddr = alloc(SETUP_FRAME_LEN);
memset(ze_setup_tdes_list[0].ze_bufaddr, 0,SETUP_FRAME_LEN);
for (i=0; i < 16; i++)
memcpy(ze_setup_tdes_list[0].ze_bufaddr+(8*i), ze_myaddr,
ETHER_ADDR_LEN);
ze_setup_tdes_list[1].ze_tdes1 = ZE_TDES1_CA;
ze_setup_tdes_list[1].ze_bufaddr = (u_char *)ze_setup_tdes_list;
addr->ze_nicsr4 = ze_setup_tdes_list;
addr->ze_nicsr6 = ZE_NICSR6_MBO | ZE_NICSR6_SE | ZE_NICSR6_ST |
ZE_NICSR6_DC | ZE_NICSR6_BL_4;
while ((addr->ze_nicsr5 & ZE_NICSR5_TS) != ZE_NICSR5_TS_SUSP)
;
addr->ze_nicsr4 = ze_tdes_list;
addr->ze_nicsr3 = ze_rdes_list;
addr->ze_nicsr6 |= ZE_NICSR6_SR;
net_devinit(f, &ze_driver, ze_myaddr);
return 0;
}
int
ze_get(struct iodesc *desc, void *pkt, size_t maxlen, saseconds_t timeout)
{
int timeout_ctr=100000*timeout, len, rdes;
while (timeout_ctr-- > 0) {
if (!(addr->ze_nicsr5 & ZE_NICSR5_RI))
continue;
for (rdes=0; rdes<NRCV; rdes++) {
if (ze_rdes_list[rdes].ze_framelen & ZE_FRAMELEN_OW)
continue;
if (ze_rdes_list[rdes].ze_rdes0 & ZE_RDES0_ES)
len = 0;
else {
if ((len = (ze_rdes_list[rdes].ze_framelen &
(~ ZE_FRAMELEN_OW))) > maxlen)
len = maxlen;
bcopy((void *)ze_rdes_list[rdes].ze_bufaddr,
pkt,len);
}
ze_rdes_list[rdes].ze_framelen = ZE_FRAMELEN_OW;
if (len > 0) {
addr->ze_nicsr5=ZE_NICSR5_RU | ZE_NICSR5_RI |
ZE_NICSR5_IS;
addr->ze_nicsr2=ZE_NICSR2_RXPD;
return len;
}
}
}
addr->ze_nicsr5=ZE_NICSR5_RU | ZE_NICSR5_RI | ZE_NICSR5_IS;
addr->ze_nicsr2=ZE_NICSR2_RXPD;
return 0;
}
int
ze_put(struct iodesc *desc, void *pkt, size_t len)
{
int timeout=100000;
while ((addr->ze_nicsr5 & ZE_NICSR5_TS) == ZE_NICSR5_TS_RUN)
;
memcpy((void *)ze_tdes_list[0].ze_bufaddr, pkt, len);
ze_tdes_list[0].ze_bufsize = len;
if (len < ETHER_MIN_LEN)
ze_tdes_list[0].ze_bufsize = ETHER_MIN_LEN;
ze_tdes_list[0].ze_tdr = ZE_TDR_OW;
addr->ze_nicsr4 = ze_tdes_list;
addr->ze_nicsr1 = ZE_NICSR1_TXPD;
timeout = 100000;
while (((addr->ze_nicsr5 & ZE_NICSR5_TI) == 0) && (--timeout>0))
;
addr->ze_nicsr5 |= ZE_NICSR5_TI;
if (timeout>0) return len;
return -1;
}
int
zeclose(struct open_file *f)
{
addr->ze_nicsr6 = ZE_NICSR6_RE;
return 0;
}