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 104 xbzero(char *a, int s) 105 { 106 while (s--) 107 *a++ = 0; 108 } 109 110 static int 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 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 * 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 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 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 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 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 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 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 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