xref: /netbsd/sys/arch/vax/boot/boot/if_ni.c (revision 2d5d8524)
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
xbzero(char * a,int s)104 xbzero(char *a, int s)
105 {
106 	while (s--)
107 		*a++ = 0;
108 }
109 
110 static int
failtest(int reg,int mask,int test,char * str)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
INSQTI(void * e,void * h)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 *
REMQHI(void * h)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
puton(void * pkt,void * q,int args)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
remput(void * fq,void * pq,int args)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
insput(void * elem,void * q,int args)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
niopen(struct open_file * f,int adapt,int ctlr,int unit,int part)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
ni_get(struct iodesc * desc,void * pkt,size_t maxlen,saseconds_t timeout)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
ni_put(struct iodesc * desc,void * pkt,size_t len)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
niclose(struct open_file * f)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