Home | History | Annotate | Line # | Download | only in boot
if_ni.c revision 1.2
      1 /*	$NetBSD: if_ni.c,v 1.2 2000/07/10 10:40:38 ragge Exp $ */
      2 /*
      3  * Copyright (c) 2000 Ludd, University of Lule}, Sweden.
      4  * All rights reserved.
      5  *
      6  * Redistribution and use in source and binary forms, with or without
      7  * modification, are permitted provided that the following conditions
      8  * are met:
      9  * 1. Redistributions of source code must retain the above copyright
     10  *    notice, this list of conditions and the following disclaimer.
     11  * 2. Redistributions in binary form must reproduce the above copyright
     12  *    notice, this list of conditions and the following disclaimer in the
     13  *    documentation and/or other materials provided with the distribution.
     14  * 3. All advertising materials mentioning features or use of this software
     15  *    must display the following acknowledgement:
     16  *	This product includes software developed at Ludd, University of
     17  *	Lule}, Sweden and its contributors.
     18  * 4. The name of the author may not be used to endorse or promote products
     19  *    derived from this software without specific prior written permission
     20  *
     21  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
     22  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     23  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
     24  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
     25  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
     26  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     27  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     28  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     29  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
     30  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     31  */
     32 
     33 /*
     34  * Standalone routine for DEBNA Ethernet controller.
     35  */
     36 
     37 #include <sys/param.h>
     38 #include <sys/types.h>
     39 #include <sys/queue.h>
     40 #include <sys/socket.h>
     41 
     42 #include <net/if.h>
     43 #include <net/if_ether.h>
     44 
     45 #include <netinet/in.h>
     46 #include <netinet/in_systm.h>
     47 
     48 #include <../include/sid.h>
     49 #include <../include/rpb.h>
     50 #include <../include/pte.h>
     51 #include <../include/macros.h>
     52 #include <../include/mtpr.h>
     53 #include <../include/scb.h>
     54 
     55 #include <lib/libkern/libkern.h>
     56 
     57 #include <lib/libsa/netif.h>
     58 #include <lib/libsa/stand.h>
     59 #include <lib/libsa/net.h>
     60 
     61 #include <dev/bi/bireg.h>
     62 
     63 #include "vaxstand.h"
     64 
     65 #undef NIDEBUG
     66 /*
     67  * Tunable buffer parameters. Good idea to have them as power of 8; then
     68  * they will fit into a logical VAX page.
     69  */
     70 #define NMSGBUF		8	/* Message queue entries */
     71 #define NTXBUF		16	/* Transmit queue entries */
     72 #define NTXFRAGS	1	/* Number of transmit buffer fragments */
     73 #define NRXBUF		24	/* Receive queue entries */
     74 #define NBDESCS		(NTXBUF + NRXBUF)
     75 #define NQUEUES		3	/* RX + TX + MSG */
     76 #define PKTHDR		18	/* Length of (control) packet header */
     77 #define RXADD		18	/* Additional length of receive datagram */
     78 #define TXADD		18	/*	""	transmit   ""	 */
     79 #define MSGADD		134	/*	""	message	   ""	 */
     80 
     81 #include <dev/bi/if_nireg.h>
     82 
     83 
     84 #define SPTSIZ	16384	/* 8MB */
     85 #define roundpg(x)	(((int)x + VAX_PGOFSET) & ~VAX_PGOFSET)
     86 #define ALLOC(x) \
     87 	allocbase;xbzero((caddr_t)allocbase,x);allocbase+=roundpg(x);
     88 #define nipqb	(&gvppqb->nc_pqb)
     89 #define gvp	gvppqb
     90 #define NI_WREG(csr, val) *(volatile long *)(niaddr + (csr)) = (val)
     91 #define NI_RREG(csr)	*(volatile long *)(niaddr + (csr))
     92 #define DELAY(x)	{volatile int i = x * 3;while (--i);}
     93 #define WAITREG(csr,val) while (NI_RREG(csr) & val);
     94 
     95 static int ni_get(struct iodesc *, void *, size_t, time_t);
     96 static int ni_put(struct iodesc *, void *, size_t);
     97 
     98 static int *syspte, allocbase, niaddr;
     99 static struct ni_gvppqb *gvppqb;
    100 static struct ni_fqb *fqb;
    101 static struct ni_bbd *bbd;
    102 static char enaddr[6];
    103 static int beenhere = 0;
    104 
    105 struct netif_driver ni_driver = {
    106 	0, 0, 0, 0, ni_get, ni_put,
    107 };
    108 
    109 static void
    110 xbzero(char *a, int s)
    111 {
    112 	while (s--)
    113 		*a++ = 0;
    114 }
    115 
    116 static int
    117 failtest(int reg, int mask, int test, char *str)
    118 {
    119 	int i = 100;
    120 
    121 	do {
    122 		DELAY(100000);
    123 	} while (((NI_RREG(reg) & mask) != test) && --i);
    124 
    125 	if (i == 0) {
    126 		printf("ni: %s\n", str);
    127 		return 1;
    128 	}
    129 	return 0;
    130 }
    131 
    132 static int
    133 INSQTI(void *e, void *h)
    134 {
    135 	int ret;
    136 
    137 	while ((ret = insqti(e, h)) == ILCK_FAILED)
    138 		;
    139 	return ret;
    140 }
    141 
    142 static void *
    143 REMQHI(void *h)
    144 {
    145 	void *ret;
    146 
    147 	while ((ret = remqhi(h)) == (void *)ILCK_FAILED)
    148 		;
    149 	return ret;
    150 }
    151 
    152 static void
    153 puton(void *pkt, void *q, int args)
    154 {
    155 	INSQTI(pkt, q);
    156 
    157 	WAITREG(NI_PCR, PCR_OWN);
    158 	NI_WREG(NI_PCR, args);
    159 	WAITREG(NI_PCR, PCR_OWN);
    160 }
    161 
    162 static void
    163 remput(void *fq, void *pq, int args)
    164 {
    165 	struct ni_dg *data;
    166 	int res;
    167 
    168 	while ((data = REMQHI(fq)) == 0)
    169 		;
    170 
    171 	res = INSQTI(data, pq);
    172 	if (res == Q_EMPTY) {
    173 		WAITREG(NI_PCR, PCR_OWN);
    174 		NI_WREG(NI_PCR, args);
    175 	}
    176 }
    177 
    178 static void
    179 insput(void *elem, void *q, int args)
    180 {
    181 	int res;
    182 
    183 	res = INSQTI(elem, q);
    184 	if (res == Q_EMPTY) {
    185 		WAITREG(NI_PCR, PCR_OWN);
    186 		NI_WREG(NI_PCR, args);
    187 	}
    188 }
    189 
    190 int
    191 niopen(struct open_file *f, int adapt, int ctlr, int unit, int part)
    192 {
    193 	struct ni_dg *data;
    194 	struct ni_msg *msg;
    195 	struct ni_ptdb *ptdb;
    196 	int i, va, res;
    197 
    198 	if (beenhere++ && askname == 0)
    199 		return 0;
    200 
    201 	niaddr = nexaddr & ~(BI_NODESIZE - 1);
    202 	bootrpb.csrphy = niaddr;
    203 	if (adapt >= 0)
    204 		bootrpb.adpphy = adapt;
    205 	/*
    206 	 * We need a bunch of memory, take it from our load
    207 	 * address plus 1M.
    208 	 */
    209 	allocbase = RELOC + 1024 * 1024;
    210 	/*
    211 	 * First create a SPT for the first 8MB of physmem.
    212 	 */
    213 	syspte = (int *)ALLOC(SPTSIZ*4);
    214 	for (i = 0; i < SPTSIZ; i++)
    215 		syspte[i] = PG_V|PG_RW|i;
    216 
    217 
    218 	gvppqb = (struct ni_gvppqb *)ALLOC(sizeof(struct ni_gvppqb));
    219 	fqb = (struct ni_fqb *)ALLOC(sizeof(struct ni_fqb));
    220 	bbd = (struct ni_bbd *)ALLOC(sizeof(struct ni_bbd) * NBDESCS);
    221 
    222 	/* Init the PQB struct */
    223 	nipqb->np_spt = nipqb->np_gpt = (int)syspte;
    224 	nipqb->np_sptlen = nipqb->np_gptlen = SPTSIZ;
    225 	nipqb->np_vpqb = (u_int32_t)gvp;
    226 	nipqb->np_bvplvl = 1;
    227 	nipqb->np_vfqb = (u_int32_t)fqb;
    228 	nipqb->np_vbdt = (u_int32_t)bbd;
    229 	nipqb->np_nbdr = NBDESCS;
    230 
    231 	/* Free queue block */
    232 	nipqb->np_freeq = NQUEUES;
    233 	fqb->nf_mlen = PKTHDR+MSGADD;
    234 	fqb->nf_dlen = PKTHDR+TXADD;
    235 	fqb->nf_rlen = PKTHDR+RXADD;
    236 #ifdef NIDEBUG
    237 	printf("niopen: syspte %p gvp %p fqb %p bbd %p\n",
    238 	    syspte, gvppqb, fqb, bbd);
    239 #endif
    240 
    241 	NI_WREG(BIREG_VAXBICSR, NI_RREG(BIREG_VAXBICSR) | BICSR_NRST);
    242 	DELAY(500000);
    243 	i = 20;
    244 	while ((NI_RREG(BIREG_VAXBICSR) & BICSR_BROKE) && --i)
    245 		DELAY(500000);
    246 #ifdef NIDEBUG
    247 	if (i == 0) {
    248 		printf("ni: BROKE bit set after reset\n");
    249 		return 1;
    250 	}
    251 #endif
    252 	/* Check state */
    253 	if (failtest(NI_PSR, PSR_STATE, PSR_UNDEF, "not undefined state"))
    254 		return 1;
    255 
    256 	/* Clear owner bits */
    257 	NI_WREG(NI_PSR, NI_RREG(NI_PSR) & ~PSR_OWN);
    258 	NI_WREG(NI_PCR, NI_RREG(NI_PCR) & ~PCR_OWN);
    259 
    260 	/* kick off init */
    261 	NI_WREG(NI_PCR, (int)gvppqb | PCR_INIT | PCR_OWN);
    262 	while (NI_RREG(NI_PCR) & PCR_OWN)
    263 		DELAY(100000);
    264 
    265 	/* Check state */
    266 	if (failtest(NI_PSR, PSR_INITED, PSR_INITED, "failed initialize"))
    267 		return 1;
    268 
    269 	NI_WREG(NI_PSR, NI_RREG(NI_PSR) & ~PSR_OWN);
    270 	WAITREG(NI_PCR, PCR_OWN);
    271 	NI_WREG(NI_PCR, PCR_OWN|PCR_ENABLE);
    272 	WAITREG(NI_PCR, PCR_OWN);
    273 	WAITREG(NI_PSR, PSR_OWN);
    274 
    275 	/* Check state */
    276 	if (failtest(NI_PSR, PSR_STATE, PSR_ENABLED, "failed enable"))
    277 		return 1;
    278 
    279 	NI_WREG(NI_PSR, NI_RREG(NI_PSR) & ~PSR_OWN);
    280 
    281 #ifdef NIDEBUG
    282 	printf("Set up message free queue\n");
    283 #endif
    284 
    285 	/* Set up message free queue */
    286 	va = ALLOC(NMSGBUF * 512);
    287 	for (i = 0; i < NMSGBUF; i++) {
    288 		msg = (void *)(va + i * 512);
    289 
    290 		res = INSQTI(msg, &fqb->nf_mforw);
    291 	}
    292 	WAITREG(NI_PCR, PCR_OWN);
    293 	NI_WREG(NI_PCR, PCR_FREEQNE|PCR_MFREEQ|PCR_OWN);
    294 	WAITREG(NI_PCR, PCR_OWN);
    295 
    296 #ifdef NIDEBUG
    297 	printf("Set up xmit queue\n");
    298 #endif
    299 
    300 	/* Set up xmit queue */
    301 	va = ALLOC(NTXBUF * 512);
    302 	for (i = 0; i < NTXBUF; i++) {
    303 		struct ni_dg *data;
    304 
    305 		data = (void *)(va + i * 512);
    306 		data->nd_status = 0;
    307 		data->nd_len = TXADD;
    308 		data->nd_ptdbidx = 1;
    309 		data->nd_opcode = BVP_DGRAM;
    310 		data->bufs[0]._offset = 0;
    311 		data->bufs[0]._key = 1;
    312 		data->nd_cmdref = allocbase;
    313 		bbd[i].nb_key = 1;
    314 		bbd[i].nb_status = 0;
    315 		bbd[i].nb_pte = (int)&syspte[allocbase>>9];
    316 		allocbase += 2048;
    317 		data->bufs[0]._index = i;
    318 
    319 		res = INSQTI(data, &fqb->nf_dforw);
    320 	}
    321 	WAITREG(NI_PCR, PCR_OWN);
    322 	NI_WREG(NI_PCR, PCR_FREEQNE|PCR_DFREEQ|PCR_OWN);
    323 	WAITREG(NI_PCR, PCR_OWN);
    324 
    325 #ifdef NIDEBUG
    326 	printf("recv buffers\n");
    327 #endif
    328 
    329 	/* recv buffers */
    330 	va = ALLOC(NRXBUF * 512);
    331 	for (i = 0; i < NRXBUF; i++) {
    332 		struct ni_dg *data;
    333 		struct ni_bbd *bd;
    334 		int idx;
    335 
    336 		data = (void *)(va + i * 512);
    337 		data->nd_cmdref = allocbase;
    338 		data->nd_len = RXADD;
    339 		data->nd_opcode = BVP_DGRAMRX;
    340 		data->nd_ptdbidx = 2;
    341 		data->bufs[0]._key = 1;
    342 
    343 		idx = NTXBUF + i;
    344 		bd = &bbd[idx];
    345 		bd->nb_pte = (int)&syspte[allocbase>>9];
    346 		allocbase += 2048;
    347 		bd->nb_len = 2048;
    348 		bd->nb_status = NIBD_VALID;
    349 		bd->nb_key = 1;
    350 		data->bufs[0]._offset = 0;
    351 		data->bufs[0]._len = bd->nb_len;
    352 		data->bufs[0]._index = idx;
    353 
    354 		res = INSQTI(data, &fqb->nf_rforw);
    355 	}
    356 	WAITREG(NI_PCR, PCR_OWN);
    357 	NI_WREG(NI_PCR, PCR_FREEQNE|PCR_RFREEQ|PCR_OWN);
    358 	WAITREG(NI_PCR, PCR_OWN);
    359 
    360 #ifdef NIDEBUG
    361 	printf("Set initial parameters\n");
    362 #endif
    363 
    364 	/* Set initial parameters */
    365 	msg = REMQHI(&fqb->nf_mforw);
    366 
    367 	msg->nm_opcode = BVP_MSG;
    368 	msg->nm_status = 0;
    369 	msg->nm_len = sizeof(struct ni_param) + 6;
    370 	msg->nm_opcode2 = NI_WPARAM;
    371 	((struct ni_param *)&msg->nm_text[0])->np_flags = NP_PAD;
    372 
    373 	puton(msg, &gvp->nc_forw0, PCR_CMDQNE|PCR_CMDQ0|PCR_OWN);
    374 
    375 
    376 	while ((data = REMQHI(&gvp->nc_forwr)) == 0)
    377 		;
    378 
    379 	msg = (struct ni_msg *)data;
    380 #ifdef NIDEBUG
    381 	if (msg->nm_opcode2 != NI_WPARAM) {
    382 		printf("ni: wrong response code %d\n", msg->nm_opcode2);
    383 		insput(data, &fqb->nf_mforw, PCR_FREEQNE|PCR_MFREEQ|PCR_OWN);
    384 	}
    385 #endif
    386 	bcopy(((struct ni_param *)&msg->nm_text[0])->np_dpa,
    387 	    enaddr, ETHER_ADDR_LEN);
    388 	insput(data, &fqb->nf_mforw, PCR_FREEQNE|PCR_MFREEQ|PCR_OWN);
    389 
    390 #ifdef NIDEBUG
    391 	printf("Clear counters\n");
    392 #endif
    393 
    394 	/* Clear counters */
    395 	msg = REMQHI(&fqb->nf_mforw);
    396 	msg->nm_opcode = BVP_MSG;
    397 	msg->nm_status = 0;
    398 	msg->nm_len = sizeof(struct ni_param) + 6;
    399 	msg->nm_opcode2 = NI_RCCNTR;
    400 
    401 	puton(msg, &gvp->nc_forw0, PCR_CMDQNE|PCR_CMDQ0|PCR_OWN);
    402 	remput(&gvp->nc_forwr, &fqb->nf_mforw, PCR_FREEQNE|PCR_MFREEQ|PCR_OWN);
    403 
    404 #ifdef NIDEBUG
    405 	printf("Enable transmit logic\n");
    406 #endif
    407 
    408 	/* Enable transmit logic */
    409 	msg = REMQHI(&fqb->nf_mforw);
    410 
    411 	msg->nm_opcode = BVP_MSG;
    412 	msg->nm_status = 0;
    413 	msg->nm_len = 18;
    414 	msg->nm_opcode2 = NI_STPTDB;
    415 	ptdb = (struct ni_ptdb *)&msg->nm_text[0];
    416 	bzero(ptdb, sizeof(struct ni_ptdb));
    417 	ptdb->np_index = 1;
    418 	ptdb->np_fque = 1;
    419 
    420 	puton(msg, &gvp->nc_forw0, PCR_CMDQNE|PCR_CMDQ0|PCR_OWN);
    421 	remput(&gvp->nc_forwr, &fqb->nf_mforw, PCR_FREEQNE|PCR_MFREEQ|PCR_OWN);
    422 
    423 #ifdef NIDEBUG
    424 	printf("ni: hardware address %s\n", ether_sprintf(enaddr));
    425 	printf("Setting receive parameters\n");
    426 #endif
    427 	msg = REMQHI(&fqb->nf_mforw);
    428 	ptdb = (struct ni_ptdb *)&msg->nm_text[0];
    429 	bzero(ptdb, sizeof(struct ni_ptdb));
    430 	msg->nm_opcode = BVP_MSG;
    431 	msg->nm_len = 18;
    432 	ptdb->np_index = 2;
    433 	ptdb->np_fque = 2;
    434 	msg->nm_opcode2 = NI_STPTDB;
    435 	ptdb->np_type = ETHERTYPE_IP;
    436 	ptdb->np_flags = PTDB_UNKN|PTDB_BDC;
    437 	memset(ptdb->np_mcast[0], 0xff, ETHER_ADDR_LEN);
    438 	ptdb->np_adrlen = 1;
    439 	msg->nm_len += 8;
    440 	insput(msg, &gvp->nc_forw0, PCR_CMDQNE|PCR_CMDQ0|PCR_OWN);
    441 	remput(&gvp->nc_forwr, &fqb->nf_mforw, PCR_FREEQNE|PCR_MFREEQ|PCR_OWN);
    442 
    443 #ifdef NIDEBUG
    444 	printf("finished\n");
    445 #endif
    446 
    447 	net_devinit(f, &ni_driver, enaddr);
    448 	return 0;
    449 }
    450 
    451 int
    452 ni_get(struct iodesc *desc, void *pkt, size_t maxlen, time_t timeout)
    453 {
    454 	struct ni_dg *data;
    455 	struct ni_bbd *bd;
    456 	int nsec = getsecs() + timeout;
    457 	int len, idx;
    458 
    459 loop:	while ((data = REMQHI(&gvp->nc_forwr)) == 0 && (nsec > getsecs()))
    460 		;
    461 
    462 	if (nsec <= getsecs())
    463 		return 0;
    464 
    465 	switch (data->nd_opcode) {
    466 	case BVP_DGRAMRX:
    467 		idx = data->bufs[0]._index;
    468 		bd = &bbd[idx];
    469 		len = data->bufs[0]._len;
    470 		if (len > maxlen)
    471 			len = maxlen;
    472 		bcopy((caddr_t)data->nd_cmdref, pkt, len);
    473 		bd->nb_pte = (int)&syspte[data->nd_cmdref>>9];
    474 		data->bufs[0]._len = bd->nb_len = 2048;
    475 		data->bufs[0]._offset = 0;
    476 		data->bufs[0]._key = 1;
    477 		bd->nb_status = NIBD_VALID;
    478 		bd->nb_key = 1;
    479 		data->nd_len = RXADD;
    480 		data->nd_status = 0;
    481 		insput(data, &fqb->nf_rforw,
    482 		    PCR_FREEQNE|PCR_RFREEQ|PCR_OWN);
    483 		return len;
    484 
    485 	case BVP_DGRAM:
    486 		insput(data, &fqb->nf_dforw, PCR_FREEQNE|PCR_DFREEQ|PCR_OWN);
    487 		break;
    488 	default:
    489 		insput(data, &fqb->nf_mforw, PCR_FREEQNE|PCR_MFREEQ|PCR_OWN);
    490 		break;
    491 	}
    492 
    493 	NI_WREG(NI_PSR, NI_RREG(NI_PSR) & ~(PSR_OWN|PSR_RSQ));
    494 	goto loop;
    495 }
    496 
    497 int
    498 ni_put(struct iodesc *desc, void *pkt, size_t len)
    499 {
    500 	struct ni_dg *data;
    501 	struct ni_bbd *bdp;
    502 
    503 	data = REMQHI(&fqb->nf_dforw);
    504 #ifdef NIDEBUG
    505 	if (data == 0) {
    506 		printf("ni_put: driver problem, data == 0\n");
    507 		return -1;
    508 	}
    509 #endif
    510 	bdp = &bbd[(data->bufs[0]._index & 0x7fff)];
    511 	bdp->nb_status = NIBD_VALID;
    512 	bdp->nb_len = (len < 64 ? 64 : len);
    513 	bcopy(pkt, (caddr_t)data->nd_cmdref, len);
    514 	data->bufs[0]._offset = 0;
    515 	data->bufs[0]._len = bdp->nb_len;
    516 	data->nd_opcode = BVP_DGRAM;
    517 	data->nd_pad3 = 1;
    518 	data->nd_ptdbidx = 1;
    519 	data->nd_len = 18;
    520 	insput(data, &gvp->nc_forw0, PCR_CMDQNE|PCR_CMDQ0|PCR_OWN);
    521 	return len;
    522 }
    523 
    524 int
    525 niclose(struct open_file *f)
    526 {
    527 	if (beenhere) {
    528 		WAITREG(NI_PCR, PCR_OWN);
    529 		NI_WREG(NI_PCR, PCR_OWN|PCR_SHUTDOWN);
    530 		WAITREG(NI_PCR, PCR_OWN);
    531 	}
    532 	return 0;
    533 }
    534