diff options
Diffstat (limited to 'sys/arch/vax/stand/boot/if_ni.c')
-rw-r--r-- | sys/arch/vax/stand/boot/if_ni.c | 534 |
1 files changed, 534 insertions, 0 deletions
diff --git a/sys/arch/vax/stand/boot/if_ni.c b/sys/arch/vax/stand/boot/if_ni.c new file mode 100644 index 00000000000..76f3477eb65 --- /dev/null +++ b/sys/arch/vax/stand/boot/if_ni.c @@ -0,0 +1,534 @@ +/* $OpenBSD: if_ni.c,v 1.1 2002/06/11 09:36:23 hugh Exp $ */ +/* $NetBSD: if_ni.c,v 1.2 2000/07/10 10:40:38 ragge Exp $ */ +/* + * Copyright (c) 2000 Ludd, University of Lule}, Sweden. + * 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 at Ludd, University of + * Lule}, Sweden and its contributors. + * 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. + */ + +/* + * Standalone routine for DEBNA Ethernet controller. + */ + +#include <sys/param.h> +#include <sys/types.h> +#include <sys/queue.h> +#include <sys/socket.h> + +#include <net/if.h> + +#include <netinet/in.h> +#include <netinet/in_systm.h> +#include <netinet/if_ether.h> + +#include <../include/sid.h> +#include <../include/rpb.h> +#include <../include/pte.h> +#include <../include/macros.h> +#include <../include/mtpr.h> +#include <../include/scb.h> + +#include <lib/libkern/libkern.h> + +#include <lib/libsa/netif.h> +#include <lib/libsa/stand.h> +#include <lib/libsa/net.h> + +#include <arch/vax/bi/bireg.h> + +#include "vaxstand.h" + +#undef NIDEBUG +/* + * Tunable buffer parameters. Good idea to have them as power of 8; then + * they will fit into a logical VAX page. + */ +#define NMSGBUF 8 /* Message queue entries */ +#define NTXBUF 16 /* Transmit queue entries */ +#define NTXFRAGS 1 /* Number of transmit buffer fragments */ +#define NRXBUF 24 /* Receive queue entries */ +#define NBDESCS (NTXBUF + NRXBUF) +#define NQUEUES 3 /* RX + TX + MSG */ +#define PKTHDR 18 /* Length of (control) packet header */ +#define RXADD 18 /* Additional length of receive datagram */ +#define TXADD 18 /* "" transmit "" */ +#define MSGADD 134 /* "" message "" */ + +#include <arch/vax/bi/if_nireg.h> + + +#define SPTSIZ 16384 /* 8MB */ +#define roundpg(x) (((int)x + VAX_PGOFSET) & ~VAX_PGOFSET) +#define ALLOC(x) \ + allocbase;xbzero((caddr_t)allocbase,x);allocbase+=roundpg(x); +#define nipqb (&gvppqb->nc_pqb) +#define gvp gvppqb +#define NI_WREG(csr, val) *(volatile long *)(niaddr + (csr)) = (val) +#define NI_RREG(csr) *(volatile long *)(niaddr + (csr)) +#define DELAY(x) {volatile int i = x * 3;while (--i);} +#define WAITREG(csr,val) while (NI_RREG(csr) & val); + +static int ni_get(struct iodesc *, void *, size_t, time_t); +static int ni_put(struct iodesc *, void *, size_t); + +static int *syspte, allocbase, niaddr; +static struct ni_gvppqb *gvppqb; +static struct ni_fqb *fqb; +static struct ni_bbd *bbd; +static char enaddr[6]; +static int beenhere = 0; + +struct netif_driver ni_driver = { + 0, 0, 0, 0, ni_get, ni_put, +}; + +static void +xbzero(char *a, int s) +{ + while (s--) + *a++ = 0; +} + +static int +failtest(int reg, int mask, int test, char *str) +{ + int i = 100; + + do { + DELAY(100000); + } while (((NI_RREG(reg) & mask) != test) && --i); + + if (i == 0) { + printf("ni: %s\n", str); + return 1; + } + return 0; +} + +static int +INSQTI(void *e, void *h) +{ + int ret; + + while ((ret = insqti(e, h)) == ILCK_FAILED) + ; + return ret; +} + +static void * +REMQHI(void *h) +{ + void *ret; + + while ((ret = remqhi(h)) == (void *)ILCK_FAILED) + ; + return ret; +} + +static void +puton(void *pkt, void *q, int args) +{ + INSQTI(pkt, q); + + WAITREG(NI_PCR, PCR_OWN); + NI_WREG(NI_PCR, args); + WAITREG(NI_PCR, PCR_OWN); +} + +static void +remput(void *fq, void *pq, int args) +{ + struct ni_dg *data; + int res; + + while ((data = REMQHI(fq)) == 0) + ; + + res = INSQTI(data, pq); + if (res == Q_EMPTY) { + WAITREG(NI_PCR, PCR_OWN); + NI_WREG(NI_PCR, args); + } +} + +static void +insput(void *elem, void *q, int args) +{ + int res; + + res = INSQTI(elem, q); + if (res == Q_EMPTY) { + WAITREG(NI_PCR, PCR_OWN); + NI_WREG(NI_PCR, args); + } +} + +int +niopen(struct open_file *f, int adapt, int ctlr, int unit, int part) +{ + struct ni_dg *data; + struct ni_msg *msg; + struct ni_ptdb *ptdb; + int i, va, res; + + if (beenhere++ && askname == 0) + return 0; + + niaddr = nexaddr & ~(BI_NODESIZE - 1); + bootrpb.csrphy = niaddr; + if (adapt >= 0) + bootrpb.adpphy = adapt; + /* + * We need a bunch of memory, take it from our load + * address plus 1M. + */ + allocbase = RELOC + 1024 * 1024; + /* + * First create a SPT for the first 8MB of physmem. + */ + syspte = (int *)ALLOC(SPTSIZ*4); + for (i = 0; i < SPTSIZ; i++) + syspte[i] = PG_V|PG_RW|i; + + + gvppqb = (struct ni_gvppqb *)ALLOC(sizeof(struct ni_gvppqb)); + fqb = (struct ni_fqb *)ALLOC(sizeof(struct ni_fqb)); + bbd = (struct ni_bbd *)ALLOC(sizeof(struct ni_bbd) * NBDESCS); + + /* Init the PQB struct */ + nipqb->np_spt = nipqb->np_gpt = (int)syspte; + nipqb->np_sptlen = nipqb->np_gptlen = SPTSIZ; + nipqb->np_vpqb = (u_int32_t)gvp; + nipqb->np_bvplvl = 1; + nipqb->np_vfqb = (u_int32_t)fqb; + nipqb->np_vbdt = (u_int32_t)bbd; + nipqb->np_nbdr = NBDESCS; + + /* Free queue block */ + nipqb->np_freeq = NQUEUES; + fqb->nf_mlen = PKTHDR+MSGADD; + fqb->nf_dlen = PKTHDR+TXADD; + fqb->nf_rlen = PKTHDR+RXADD; +#ifdef NIDEBUG + printf("niopen: syspte %p gvp %p fqb %p bbd %p\n", + syspte, gvppqb, fqb, bbd); +#endif + + NI_WREG(BIREG_VAXBICSR, NI_RREG(BIREG_VAXBICSR) | BICSR_NRST); + DELAY(500000); + i = 20; + while ((NI_RREG(BIREG_VAXBICSR) & BICSR_BROKE) && --i) + DELAY(500000); +#ifdef NIDEBUG + if (i == 0) { + printf("ni: BROKE bit set after reset\n"); + return 1; + } +#endif + /* Check state */ + if (failtest(NI_PSR, PSR_STATE, PSR_UNDEF, "not undefined state")) + return 1; + + /* Clear owner bits */ + NI_WREG(NI_PSR, NI_RREG(NI_PSR) & ~PSR_OWN); + NI_WREG(NI_PCR, NI_RREG(NI_PCR) & ~PCR_OWN); + + /* kick off init */ + NI_WREG(NI_PCR, (int)gvppqb | PCR_INIT | PCR_OWN); + while (NI_RREG(NI_PCR) & PCR_OWN) + DELAY(100000); + + /* Check state */ + if (failtest(NI_PSR, PSR_INITED, PSR_INITED, "failed initialize")) + return 1; + + NI_WREG(NI_PSR, NI_RREG(NI_PSR) & ~PSR_OWN); + WAITREG(NI_PCR, PCR_OWN); + NI_WREG(NI_PCR, PCR_OWN|PCR_ENABLE); + WAITREG(NI_PCR, PCR_OWN); + WAITREG(NI_PSR, PSR_OWN); + + /* Check state */ + if (failtest(NI_PSR, PSR_STATE, PSR_ENABLED, "failed enable")) + return 1; + + NI_WREG(NI_PSR, NI_RREG(NI_PSR) & ~PSR_OWN); + +#ifdef NIDEBUG + printf("Set up message free queue\n"); +#endif + + /* Set up message free queue */ + va = ALLOC(NMSGBUF * 512); + for (i = 0; i < NMSGBUF; i++) { + msg = (void *)(va + i * 512); + + res = INSQTI(msg, &fqb->nf_mforw); + } + WAITREG(NI_PCR, PCR_OWN); + NI_WREG(NI_PCR, PCR_FREEQNE|PCR_MFREEQ|PCR_OWN); + WAITREG(NI_PCR, PCR_OWN); + +#ifdef NIDEBUG + printf("Set up xmit queue\n"); +#endif + + /* Set up xmit queue */ + va = ALLOC(NTXBUF * 512); + for (i = 0; i < NTXBUF; i++) { + struct ni_dg *data; + + data = (void *)(va + i * 512); + data->nd_status = 0; + data->nd_len = TXADD; + data->nd_ptdbidx = 1; + data->nd_opcode = BVP_DGRAM; + data->bufs[0]._offset = 0; + data->bufs[0]._key = 1; + data->nd_cmdref = allocbase; + bbd[i].nb_key = 1; + bbd[i].nb_status = 0; + bbd[i].nb_pte = (int)&syspte[allocbase>>9]; + allocbase += 2048; + data->bufs[0]._index = i; + + res = INSQTI(data, &fqb->nf_dforw); + } + WAITREG(NI_PCR, PCR_OWN); + NI_WREG(NI_PCR, PCR_FREEQNE|PCR_DFREEQ|PCR_OWN); + WAITREG(NI_PCR, PCR_OWN); + +#ifdef NIDEBUG + printf("recv buffers\n"); +#endif + + /* recv buffers */ + va = ALLOC(NRXBUF * 512); + for (i = 0; i < NRXBUF; i++) { + struct ni_dg *data; + struct ni_bbd *bd; + int idx; + + data = (void *)(va + i * 512); + data->nd_cmdref = allocbase; + data->nd_len = RXADD; + data->nd_opcode = BVP_DGRAMRX; + data->nd_ptdbidx = 2; + data->bufs[0]._key = 1; + + idx = NTXBUF + i; + bd = &bbd[idx]; + bd->nb_pte = (int)&syspte[allocbase>>9]; + allocbase += 2048; + bd->nb_len = 2048; + bd->nb_status = NIBD_VALID; + bd->nb_key = 1; + data->bufs[0]._offset = 0; + data->bufs[0]._len = bd->nb_len; + data->bufs[0]._index = idx; + + res = INSQTI(data, &fqb->nf_rforw); + } + WAITREG(NI_PCR, PCR_OWN); + NI_WREG(NI_PCR, PCR_FREEQNE|PCR_RFREEQ|PCR_OWN); + WAITREG(NI_PCR, PCR_OWN); + +#ifdef NIDEBUG + printf("Set initial parameters\n"); +#endif + + /* Set initial parameters */ + msg = REMQHI(&fqb->nf_mforw); + + msg->nm_opcode = BVP_MSG; + msg->nm_status = 0; + msg->nm_len = sizeof(struct ni_param) + 6; + msg->nm_opcode2 = NI_WPARAM; + ((struct ni_param *)&msg->nm_text[0])->np_flags = NP_PAD; + + puton(msg, &gvp->nc_forw0, PCR_CMDQNE|PCR_CMDQ0|PCR_OWN); + + + while ((data = REMQHI(&gvp->nc_forwr)) == 0) + ; + + msg = (struct ni_msg *)data; +#ifdef NIDEBUG + if (msg->nm_opcode2 != NI_WPARAM) { + printf("ni: wrong response code %d\n", msg->nm_opcode2); + insput(data, &fqb->nf_mforw, PCR_FREEQNE|PCR_MFREEQ|PCR_OWN); + } +#endif + bcopy(((struct ni_param *)&msg->nm_text[0])->np_dpa, + enaddr, ETHER_ADDR_LEN); + insput(data, &fqb->nf_mforw, PCR_FREEQNE|PCR_MFREEQ|PCR_OWN); + +#ifdef NIDEBUG + printf("Clear counters\n"); +#endif + + /* Clear counters */ + msg = REMQHI(&fqb->nf_mforw); + msg->nm_opcode = BVP_MSG; + msg->nm_status = 0; + msg->nm_len = sizeof(struct ni_param) + 6; + msg->nm_opcode2 = NI_RCCNTR; + + puton(msg, &gvp->nc_forw0, PCR_CMDQNE|PCR_CMDQ0|PCR_OWN); + remput(&gvp->nc_forwr, &fqb->nf_mforw, PCR_FREEQNE|PCR_MFREEQ|PCR_OWN); + +#ifdef NIDEBUG + printf("Enable transmit logic\n"); +#endif + + /* Enable transmit logic */ + msg = REMQHI(&fqb->nf_mforw); + + msg->nm_opcode = BVP_MSG; + msg->nm_status = 0; + msg->nm_len = 18; + msg->nm_opcode2 = NI_STPTDB; + ptdb = (struct ni_ptdb *)&msg->nm_text[0]; + bzero(ptdb, sizeof(struct ni_ptdb)); + ptdb->np_index = 1; + ptdb->np_fque = 1; + + puton(msg, &gvp->nc_forw0, PCR_CMDQNE|PCR_CMDQ0|PCR_OWN); + remput(&gvp->nc_forwr, &fqb->nf_mforw, PCR_FREEQNE|PCR_MFREEQ|PCR_OWN); + +#ifdef NIDEBUG + printf("ni: hardware address %s\n", ether_sprintf(enaddr)); + printf("Setting receive parameters\n"); +#endif + msg = REMQHI(&fqb->nf_mforw); + ptdb = (struct ni_ptdb *)&msg->nm_text[0]; + bzero(ptdb, sizeof(struct ni_ptdb)); + msg->nm_opcode = BVP_MSG; + msg->nm_len = 18; + ptdb->np_index = 2; + ptdb->np_fque = 2; + msg->nm_opcode2 = NI_STPTDB; + ptdb->np_type = ETHERTYPE_IP; + ptdb->np_flags = PTDB_UNKN|PTDB_BDC; + memset(ptdb->np_mcast[0], 0xff, ETHER_ADDR_LEN); + ptdb->np_adrlen = 1; + msg->nm_len += 8; + insput(msg, &gvp->nc_forw0, PCR_CMDQNE|PCR_CMDQ0|PCR_OWN); + remput(&gvp->nc_forwr, &fqb->nf_mforw, PCR_FREEQNE|PCR_MFREEQ|PCR_OWN); + +#ifdef NIDEBUG + printf("finished\n"); +#endif + + net_devinit(f, &ni_driver, enaddr); + return 0; +} + +int +ni_get(struct iodesc *desc, void *pkt, size_t maxlen, time_t timeout) +{ + struct ni_dg *data; + struct ni_bbd *bd; + int nsec = getsecs() + timeout; + int len, idx; + +loop: while ((data = REMQHI(&gvp->nc_forwr)) == 0 && (nsec > getsecs())) + ; + + if (nsec <= getsecs()) + return 0; + + switch (data->nd_opcode) { + case BVP_DGRAMRX: + idx = data->bufs[0]._index; + bd = &bbd[idx]; + len = data->bufs[0]._len; + if (len > maxlen) + len = maxlen; + bcopy((caddr_t)data->nd_cmdref, pkt, len); + bd->nb_pte = (int)&syspte[data->nd_cmdref>>9]; + data->bufs[0]._len = bd->nb_len = 2048; + data->bufs[0]._offset = 0; + data->bufs[0]._key = 1; + bd->nb_status = NIBD_VALID; + bd->nb_key = 1; + data->nd_len = RXADD; + data->nd_status = 0; + insput(data, &fqb->nf_rforw, + PCR_FREEQNE|PCR_RFREEQ|PCR_OWN); + return len; + + case BVP_DGRAM: + insput(data, &fqb->nf_dforw, PCR_FREEQNE|PCR_DFREEQ|PCR_OWN); + break; + default: + insput(data, &fqb->nf_mforw, PCR_FREEQNE|PCR_MFREEQ|PCR_OWN); + break; + } + + NI_WREG(NI_PSR, NI_RREG(NI_PSR) & ~(PSR_OWN|PSR_RSQ)); + goto loop; +} + +int +ni_put(struct iodesc *desc, void *pkt, size_t len) +{ + struct ni_dg *data; + struct ni_bbd *bdp; + + data = REMQHI(&fqb->nf_dforw); +#ifdef NIDEBUG + if (data == 0) { + printf("ni_put: driver problem, data == 0\n"); + return -1; + } +#endif + bdp = &bbd[(data->bufs[0]._index & 0x7fff)]; + bdp->nb_status = NIBD_VALID; + bdp->nb_len = (len < 64 ? 64 : len); + bcopy(pkt, (caddr_t)data->nd_cmdref, len); + data->bufs[0]._offset = 0; + data->bufs[0]._len = bdp->nb_len; + data->nd_opcode = BVP_DGRAM; + data->nd_pad3 = 1; + data->nd_ptdbidx = 1; + data->nd_len = 18; + insput(data, &gvp->nc_forw0, PCR_CMDQNE|PCR_CMDQ0|PCR_OWN); + return len; +} + +int +niclose(struct open_file *f) +{ + if (beenhere) { + WAITREG(NI_PCR, PCR_OWN); + NI_WREG(NI_PCR, PCR_OWN|PCR_SHUTDOWN); + WAITREG(NI_PCR, PCR_OWN); + } + return 0; +} |