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