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