if_ni.c revision 1.9 1 /* $NetBSD: if_ni.c,v 1.9 2011/07/03 08:56:25 mrg 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((void *)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, saseconds_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 u_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 struct ni_param *nip;
198
199 if (beenhere++ && askname == 0)
200 return 0;
201
202 niaddr = nexaddr & ~(BI_NODESIZE - 1);
203 bootrpb.csrphy = niaddr;
204 if (adapt >= 0)
205 bootrpb.adpphy = adapt;
206 /*
207 * We need a bunch of memory, take it from our load
208 * address plus 1M.
209 */
210 allocbase = RELOC + 1024 * 1024;
211 /*
212 * First create a SPT for the first 8MB of physmem.
213 */
214 syspte = (int *)ALLOC(SPTSIZ*4);
215 for (i = 0; i < SPTSIZ; i++)
216 syspte[i] = PG_V|PG_RW|i;
217
218
219 gvppqb = (struct ni_gvppqb *)ALLOC(sizeof(struct ni_gvppqb));
220 fqb = (struct ni_fqb *)ALLOC(sizeof(struct ni_fqb));
221 bbd = (struct ni_bbd *)ALLOC(sizeof(struct ni_bbd) * NBDESCS);
222
223 /* Init the PQB struct */
224 nipqb->np_spt = nipqb->np_gpt = (int)syspte;
225 nipqb->np_sptlen = nipqb->np_gptlen = SPTSIZ;
226 nipqb->np_vpqb = (u_int32_t)gvp;
227 nipqb->np_bvplvl = 1;
228 nipqb->np_vfqb = (u_int32_t)fqb;
229 nipqb->np_vbdt = (u_int32_t)bbd;
230 nipqb->np_nbdr = NBDESCS;
231
232 /* Free queue block */
233 nipqb->np_freeq = NQUEUES;
234 fqb->nf_mlen = PKTHDR+MSGADD;
235 fqb->nf_dlen = PKTHDR+TXADD;
236 fqb->nf_rlen = PKTHDR+RXADD;
237 #ifdef NIDEBUG
238 printf("niopen: syspte %p gvp %p fqb %p bbd %p\n",
239 syspte, gvppqb, fqb, bbd);
240 #endif
241
242 NI_WREG(BIREG_VAXBICSR, NI_RREG(BIREG_VAXBICSR) | BICSR_NRST);
243 DELAY(500000);
244 i = 20;
245 while ((NI_RREG(BIREG_VAXBICSR) & BICSR_BROKE) && --i)
246 DELAY(500000);
247 #ifdef NIDEBUG
248 if (i == 0) {
249 printf("ni: BROKE bit set after reset\n");
250 return 1;
251 }
252 #endif
253 /* Check state */
254 if (failtest(NI_PSR, PSR_STATE, PSR_UNDEF, "not undefined state"))
255 return 1;
256
257 /* Clear owner bits */
258 NI_WREG(NI_PSR, NI_RREG(NI_PSR) & ~PSR_OWN);
259 NI_WREG(NI_PCR, NI_RREG(NI_PCR) & ~PCR_OWN);
260
261 /* kick off init */
262 NI_WREG(NI_PCR, (int)gvppqb | PCR_INIT | PCR_OWN);
263 while (NI_RREG(NI_PCR) & PCR_OWN)
264 DELAY(100000);
265
266 /* Check state */
267 if (failtest(NI_PSR, PSR_INITED, PSR_INITED, "failed initialize"))
268 return 1;
269
270 NI_WREG(NI_PSR, NI_RREG(NI_PSR) & ~PSR_OWN);
271 WAITREG(NI_PCR, PCR_OWN);
272 NI_WREG(NI_PCR, PCR_OWN|PCR_ENABLE);
273 WAITREG(NI_PCR, PCR_OWN);
274 WAITREG(NI_PSR, PSR_OWN);
275
276 /* Check state */
277 if (failtest(NI_PSR, PSR_STATE, PSR_ENABLED, "failed enable"))
278 return 1;
279
280 NI_WREG(NI_PSR, NI_RREG(NI_PSR) & ~PSR_OWN);
281
282 #ifdef NIDEBUG
283 printf("Set up message free queue\n");
284 #endif
285
286 /* Set up message free queue */
287 va = ALLOC(NMSGBUF * 512);
288 for (i = 0; i < NMSGBUF; i++) {
289 msg = (void *)(va + i * 512);
290
291 res = INSQTI(msg, &fqb->nf_mforw);
292 }
293 WAITREG(NI_PCR, PCR_OWN);
294 NI_WREG(NI_PCR, PCR_FREEQNE|PCR_MFREEQ|PCR_OWN);
295 WAITREG(NI_PCR, PCR_OWN);
296
297 #ifdef NIDEBUG
298 printf("Set up xmit queue\n");
299 #endif
300
301 /* Set up xmit queue */
302 va = ALLOC(NTXBUF * 512);
303 for (i = 0; i < NTXBUF; i++) {
304 struct ni_dg *data;
305
306 data = (void *)(va + i * 512);
307 data->nd_status = 0;
308 data->nd_len = TXADD;
309 data->nd_ptdbidx = 1;
310 data->nd_opcode = BVP_DGRAM;
311 data->bufs[0]._offset = 0;
312 data->bufs[0]._key = 1;
313 data->nd_cmdref = allocbase;
314 bbd[i].nb_key = 1;
315 bbd[i].nb_status = 0;
316 bbd[i].nb_pte = (int)&syspte[allocbase>>9];
317 allocbase += 2048;
318 data->bufs[0]._index = i;
319
320 res = INSQTI(data, &fqb->nf_dforw);
321 }
322 WAITREG(NI_PCR, PCR_OWN);
323 NI_WREG(NI_PCR, PCR_FREEQNE|PCR_DFREEQ|PCR_OWN);
324 WAITREG(NI_PCR, PCR_OWN);
325
326 #ifdef NIDEBUG
327 printf("recv buffers\n");
328 #endif
329
330 /* recv buffers */
331 va = ALLOC(NRXBUF * 512);
332 for (i = 0; i < NRXBUF; i++) {
333 struct ni_dg *data;
334 struct ni_bbd *bd;
335 int idx;
336
337 data = (void *)(va + i * 512);
338 data->nd_cmdref = allocbase;
339 data->nd_len = RXADD;
340 data->nd_opcode = BVP_DGRAMRX;
341 data->nd_ptdbidx = 2;
342 data->bufs[0]._key = 1;
343
344 idx = NTXBUF + i;
345 bd = &bbd[idx];
346 bd->nb_pte = (int)&syspte[allocbase>>9];
347 allocbase += 2048;
348 bd->nb_len = 2048;
349 bd->nb_status = NIBD_VALID;
350 bd->nb_key = 1;
351 data->bufs[0]._offset = 0;
352 data->bufs[0]._len = bd->nb_len;
353 data->bufs[0]._index = idx;
354
355 res = INSQTI(data, &fqb->nf_rforw);
356 }
357 WAITREG(NI_PCR, PCR_OWN);
358 NI_WREG(NI_PCR, PCR_FREEQNE|PCR_RFREEQ|PCR_OWN);
359 WAITREG(NI_PCR, PCR_OWN);
360
361 #ifdef NIDEBUG
362 printf("Set initial parameters\n");
363 #endif
364
365 /* Set initial parameters */
366 msg = REMQHI(&fqb->nf_mforw);
367
368 msg->nm_opcode = BVP_MSG;
369 msg->nm_status = 0;
370 msg->nm_len = sizeof(struct ni_param) + 6;
371 msg->nm_opcode2 = NI_WPARAM;
372 nip = (struct ni_param *)&msg->nm_text[0];
373 nip->np_flags = NP_PAD;
374
375 puton(msg, &gvp->nc_forw0, PCR_CMDQNE|PCR_CMDQ0|PCR_OWN);
376
377
378 while ((data = REMQHI(&gvp->nc_forwr)) == 0)
379 ;
380
381 msg = (struct ni_msg *)data;
382 #ifdef NIDEBUG
383 if (msg->nm_opcode2 != NI_WPARAM) {
384 printf("ni: wrong response code %d\n", msg->nm_opcode2);
385 insput(data, &fqb->nf_mforw, PCR_FREEQNE|PCR_MFREEQ|PCR_OWN);
386 }
387 #endif
388 bcopy(nip->np_dpa, enaddr, ETHER_ADDR_LEN);
389 insput(data, &fqb->nf_mforw, PCR_FREEQNE|PCR_MFREEQ|PCR_OWN);
390
391 #ifdef NIDEBUG
392 printf("Clear counters\n");
393 #endif
394
395 /* Clear counters */
396 msg = REMQHI(&fqb->nf_mforw);
397 msg->nm_opcode = BVP_MSG;
398 msg->nm_status = 0;
399 msg->nm_len = sizeof(struct ni_param) + 6;
400 msg->nm_opcode2 = NI_RCCNTR;
401
402 puton(msg, &gvp->nc_forw0, PCR_CMDQNE|PCR_CMDQ0|PCR_OWN);
403 remput(&gvp->nc_forwr, &fqb->nf_mforw, PCR_FREEQNE|PCR_MFREEQ|PCR_OWN);
404
405 #ifdef NIDEBUG
406 printf("Enable transmit logic\n");
407 #endif
408
409 /* Enable transmit logic */
410 msg = REMQHI(&fqb->nf_mforw);
411
412 msg->nm_opcode = BVP_MSG;
413 msg->nm_status = 0;
414 msg->nm_len = 18;
415 msg->nm_opcode2 = NI_STPTDB;
416 ptdb = (struct ni_ptdb *)&msg->nm_text[0];
417 memset(ptdb, 0, sizeof(struct ni_ptdb));
418 ptdb->np_index = 1;
419 ptdb->np_fque = 1;
420
421 puton(msg, &gvp->nc_forw0, PCR_CMDQNE|PCR_CMDQ0|PCR_OWN);
422 remput(&gvp->nc_forwr, &fqb->nf_mforw, PCR_FREEQNE|PCR_MFREEQ|PCR_OWN);
423
424 #ifdef NIDEBUG
425 printf("ni: hardware address %s\n", ether_sprintf(enaddr));
426 printf("Setting receive parameters\n");
427 #endif
428 msg = REMQHI(&fqb->nf_mforw);
429 ptdb = (struct ni_ptdb *)&msg->nm_text[0];
430 memset(ptdb, 0, sizeof(struct ni_ptdb));
431 msg->nm_opcode = BVP_MSG;
432 msg->nm_len = 18;
433 ptdb->np_index = 2;
434 ptdb->np_fque = 2;
435 msg->nm_opcode2 = NI_STPTDB;
436 ptdb->np_type = ETHERTYPE_IP;
437 ptdb->np_flags = PTDB_UNKN|PTDB_BDC;
438 memset(ptdb->np_mcast[0], 0xff, ETHER_ADDR_LEN);
439 ptdb->np_adrlen = 1;
440 msg->nm_len += 8;
441 insput(msg, &gvp->nc_forw0, PCR_CMDQNE|PCR_CMDQ0|PCR_OWN);
442 remput(&gvp->nc_forwr, &fqb->nf_mforw, PCR_FREEQNE|PCR_MFREEQ|PCR_OWN);
443
444 #ifdef NIDEBUG
445 printf("finished\n");
446 #endif
447
448 net_devinit(f, &ni_driver, enaddr);
449 return 0;
450 }
451
452 int
453 ni_get(struct iodesc *desc, void *pkt, size_t maxlen, saseconds_t timeout)
454 {
455 struct ni_dg *data;
456 struct ni_bbd *bd;
457 satime_t nsec = getsecs();
458 int len, idx;
459
460 loop:
461 while ((data = REMQHI(&gvp->nc_forwr)) == 0 &&
462 ((getsecs() - nsec) < timeout))
463 ;
464
465 if ((getsecs() - nsec) >= timeout)
466 return 0;
467
468 switch (data->nd_opcode) {
469 case BVP_DGRAMRX:
470 idx = data->bufs[0]._index;
471 bd = &bbd[idx];
472 len = data->bufs[0]._len;
473 if (len > maxlen)
474 len = maxlen;
475 memcpy(pkt, (void *)data->nd_cmdref, len);
476 bd->nb_pte = (int)&syspte[data->nd_cmdref>>9];
477 data->bufs[0]._len = bd->nb_len = 2048;
478 data->bufs[0]._offset = 0;
479 data->bufs[0]._key = 1;
480 bd->nb_status = NIBD_VALID;
481 bd->nb_key = 1;
482 data->nd_len = RXADD;
483 data->nd_status = 0;
484 insput(data, &fqb->nf_rforw,
485 PCR_FREEQNE|PCR_RFREEQ|PCR_OWN);
486 return len;
487
488 case BVP_DGRAM:
489 insput(data, &fqb->nf_dforw, PCR_FREEQNE|PCR_DFREEQ|PCR_OWN);
490 break;
491 default:
492 insput(data, &fqb->nf_mforw, PCR_FREEQNE|PCR_MFREEQ|PCR_OWN);
493 break;
494 }
495
496 NI_WREG(NI_PSR, NI_RREG(NI_PSR) & ~(PSR_OWN|PSR_RSQ));
497 goto loop;
498 }
499
500 int
501 ni_put(struct iodesc *desc, void *pkt, size_t len)
502 {
503 struct ni_dg *data;
504 struct ni_bbd *bdp;
505
506 data = REMQHI(&fqb->nf_dforw);
507 #ifdef NIDEBUG
508 if (data == 0) {
509 printf("ni_put: driver problem, data == 0\n");
510 return -1;
511 }
512 #endif
513 bdp = &bbd[(data->bufs[0]._index & 0x7fff)];
514 bdp->nb_status = NIBD_VALID;
515 bdp->nb_len = (len < 64 ? 64 : len);
516 memcpy((void *)data->nd_cmdref, pkt, len);
517 data->bufs[0]._offset = 0;
518 data->bufs[0]._len = bdp->nb_len;
519 data->nd_opcode = BVP_DGRAM;
520 data->nd_pad3 = 1;
521 data->nd_ptdbidx = 1;
522 data->nd_len = 18;
523 insput(data, &gvp->nc_forw0, PCR_CMDQNE|PCR_CMDQ0|PCR_OWN);
524 return len;
525 }
526
527 int
528 niclose(struct open_file *f)
529 {
530 if (beenhere) {
531 WAITREG(NI_PCR, PCR_OWN);
532 NI_WREG(NI_PCR, PCR_OWN|PCR_SHUTDOWN);
533 WAITREG(NI_PCR, PCR_OWN);
534 }
535 return 0;
536 }
537