xref: /netbsd/sys/arch/vax/boot/boot/if_ni.c (revision bf9ec67e)
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