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