1 /* 2 * Copyright (c) 1988 Regents of the University of California. 3 * All rights reserved. 4 * 5 * This code is derived from software contributed to Berkeley by 6 * Computer Consoles Inc. 7 * 8 * Redistribution and use in source and binary forms are permitted 9 * provided that the above copyright notice and this paragraph are 10 * duplicated in all such forms and that any documentation, 11 * advertising materials, and other materials related to such 12 * distribution and use acknowledge that the software was developed 13 * by the University of California, Berkeley. The name of the 14 * University may not be used to endorse or promote products derived 15 * from this software without specific prior written permission. 16 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 17 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 18 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 19 * 20 * @(#)if_ace.c 7.3 (Berkeley) 08/27/88 21 */ 22 23 /* 24 * ACC VERSAbus Ethernet controller 25 */ 26 #include "ace.h" 27 #if NACE > 0 28 29 #include "param.h" 30 #include "systm.h" 31 #include "malloc.h" 32 #include "mbuf.h" 33 #include "buf.h" 34 #include "protosw.h" 35 #include "socket.h" 36 #include "vmmac.h" 37 #include "ioctl.h" 38 #include "errno.h" 39 #include "vmparam.h" 40 #include "syslog.h" 41 42 #include "../net/if.h" 43 #include "../net/netisr.h" 44 #include "../net/route.h" 45 #ifdef INET 46 #include "../netinet/in.h" 47 #include "../netinet/in_systm.h" 48 #include "../netinet/in_var.h" 49 #include "../netinet/ip.h" 50 #include "../netinet/ip_var.h" 51 #include "../netinet/if_ether.h" 52 #endif 53 #ifdef NS 54 #include "../netns/ns.h" 55 #include "../netns/ns_if.h" 56 #endif 57 58 #include "../machine/cpu.h" 59 #include "../machine/pte.h" 60 61 #include "../tahoe/mtpr.h" 62 #include "../tahoeif/if_acereg.h" 63 #include "../tahoevba/vbavar.h" 64 65 int aceprobe(), aceattach(), acerint(), acecint(), acestart(); 66 struct vba_device *aceinfo[NACE]; 67 long acestd[] = { 0 }; 68 struct vba_driver acedriver = 69 { aceprobe, 0, aceattach, 0, acestd, "ace", aceinfo, "v/eiu", 0 }; 70 71 int aceinit(), aceoutput(), aceioctl(), acereset(); 72 struct mbuf *aceget(); 73 74 /* 75 * Ethernet software status per interface. 76 * 77 * Each interface is referenced by a network interface structure, 78 * is_if, which the routing code uses to locate the interface. 79 * This structure contains the output queue for the interface, its address, ... 80 */ 81 struct ace_softc { 82 struct arpcom is_ac; /* Ethernet common part */ 83 #define is_if is_ac.ac_if /* network-visible interface */ 84 #define is_addr is_ac.ac_enaddr /* hardware Ethernet address */ 85 short is_flags; 86 #define ACEF_OACTIVE 0x1 /* output is active */ 87 #define ACEF_RCVPENDING 0x2 /* start rcv in acecint */ 88 short is_promiscuous; /* true is enabled */ 89 short is_segboundry; /* first TX Seg in dpm */ 90 short is_eictr; /* Rx segment tracking ctr */ 91 short is_eoctr; /* Tx segment tracking ctr */ 92 short is_txnext; /* Next available Tx segment */ 93 short is_currnd; /* current random backoff */ 94 struct ace_stats is_stats; /* holds board statistics */ 95 short is_xcnt; /* count xmitted segments to be acked 96 by the controller */ 97 long is_ivec; /* autoconfig interrupt vector base */ 98 struct pte *is_map; /* pte map for dual ported memory */ 99 caddr_t is_dpm; /* address of mapped memory */ 100 } ace_softc[NACE]; 101 extern struct ifnet loif; 102 103 aceprobe(reg, vi) 104 caddr_t reg; 105 struct vba_device *vi; 106 { 107 register br, cvec; /* must be r12, r11 */ 108 struct acedevice *ap = (struct acedevice *)reg; 109 struct ace_softc *is = &ace_softc[vi->ui_unit]; 110 111 #ifdef lint 112 br = 0; cvec = br; br = cvec; 113 acerint(0); acecint(0); 114 #endif 115 if (badaddr(reg, 2)) 116 return (0); 117 movow(&ap->csr, CSR_RESET); 118 DELAY(10000); 119 #ifdef notdef 120 /* 121 * Select two spaces for the interrupts aligned to an 122 * eight vector boundary and fitting in 8 bits (as 123 * required by the controller) -- YECH. The controller 124 * will be notified later at initialization time. 125 */ 126 if ((vi->ui_hd->vh_lastiv -= 2) > 0xff) 127 vi->ui_hd->vh_lastiv = 0x200; 128 is->is_ivec = vi->ui_hd->vh_lastiv = vi->ui_hd->vh_lastiv &~ 0x7; 129 #else 130 is->is_ivec = 0x90+vi->ui_unit*8; 131 #endif 132 br = 0x14, cvec = is->is_ivec; /* XXX */ 133 return (sizeof (*ap)); 134 } 135 136 /* 137 * Interface exists: make available by filling in network interface 138 * record. System will initialize the interface when it is ready 139 * to accept packets. 140 */ 141 aceattach(ui) 142 struct vba_device *ui; 143 { 144 register short unit = ui->ui_unit; 145 register struct ace_softc *is = &ace_softc[unit]; 146 register struct ifnet *ifp = &is->is_if; 147 register struct acedevice *addr = (struct acedevice *)ui->ui_addr; 148 register short *wp, i; 149 extern enoutput(); 150 151 ifp->if_unit = unit; 152 ifp->if_name = "ace"; 153 ifp->if_mtu = ETHERMTU; 154 /* 155 * Get station's addresses and set multicast hash table. 156 */ 157 for (wp = (short *)addr->station, i = 0; i < 6; i++) 158 is->is_addr[i] = ~*wp++; 159 printf("ace%d: hardware address %s\n", unit, 160 ether_sprintf(is->is_addr)); 161 is->is_promiscuous = 0; 162 for (wp = (short *)addr->hash, i = 0; i < 8; i++) 163 movow(wp++, ~0xf); 164 movow(&addr->bcastena[0], ~0xffff); 165 movow(&addr->bcastena[1], ~0xffff); 166 /* 167 * Allocate and map dual ported VERSAbus memory. 168 */ 169 if (vbmemalloc(32, (caddr_t)ui->ui_flags, 170 &is->is_map, &is->is_dpm) == 0) { 171 printf("ace%d: can't allocate VERSAbus memory map\n", unit); 172 return; 173 } 174 175 ifp->if_init = aceinit; 176 ifp->if_output = enoutput; 177 ifp->if_start = acestart; 178 ifp->if_ioctl = aceioctl; 179 ifp->if_reset = acereset; 180 ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX; 181 if_attach(ifp); 182 } 183 184 /* 185 * Reset of interface after "system" reset. 186 */ 187 acereset(unit, vban) 188 int unit, vban; 189 { 190 register struct vba_device *ui; 191 192 if (unit >= NACE || (ui = aceinfo[unit]) == 0 || ui->ui_alive == 0 || 193 ui->ui_vbanum != vban) 194 return; 195 printf(" ace%d", unit); 196 aceinit(unit); 197 } 198 199 /* 200 * Initialization of interface; clear recorded pending operations 201 */ 202 aceinit(unit) 203 int unit; 204 { 205 register struct ace_softc *is = &ace_softc[unit]; 206 register struct vba_device *ui = aceinfo[unit]; 207 register struct acedevice *addr; 208 register short Csr; 209 register int s; 210 211 if (is->is_if.if_addrlist == (struct ifaddr *)0) 212 return; 213 if ((is->is_if.if_flags & IFF_RUNNING) == 0) { 214 /* 215 * Reset the controller, initialize the recieve buffers, 216 * and turn the controller on again and set board online. 217 */ 218 addr = (struct acedevice *)ui->ui_addr; 219 s = splimp(); 220 movow(&addr->csr, CSR_RESET); 221 DELAY(10000); 222 223 /* 224 * Clean up dpm since the controller might 225 * jumble dpm after reset. 226 */ 227 acesetup(unit); 228 movow(&addr->csr, CSR_GO); 229 Csr = addr->csr; 230 if (Csr & CSR_ACTIVE) { 231 movow(&addr->ivct, is->is_ivec); 232 Csr |= CSR_IENA | is->is_promiscuous; 233 movow(&addr->csr, Csr); 234 is->is_flags = 0; 235 is->is_xcnt = 0; 236 is->is_if.if_flags |= IFF_RUNNING; 237 } 238 splx(s); 239 } 240 if (is->is_if.if_snd.ifq_head) 241 acestart(&is->is_if); 242 } 243 244 /* 245 * Start output on interface. 246 * Get another datagram to send off of the interface queue, 247 * and map it to the interface before starting the output. 248 */ 249 acestart(ifp) 250 register struct ifnet *ifp; 251 { 252 register struct tx_segment *txs; 253 register long len; 254 register int s; 255 struct mbuf *m; 256 short retries; 257 #define is ((struct ace_softc *)ifp) 258 259 again: 260 txs = (struct tx_segment*)(is->is_dpm + (is->is_txnext << 11)); 261 if (txs->tx_csr & TCS_TBFULL) { 262 is->is_stats.tx_busy++; 263 ifp->if_flags |= IFF_OACTIVE; 264 return (0); 265 } 266 s = splimp(); 267 IF_DEQUEUE(&ifp->if_snd, m); 268 splx(s); 269 if (m == 0) { 270 ifp->if_flags &= ~IFF_OACTIVE; 271 return (0); 272 } 273 len = aceput(txs->tx_data, m); 274 retries = txs->tx_csr & TCS_RTC; 275 if (retries > 0) 276 acebakoff(is, txs, retries); 277 278 /* 279 * Ensure minimum packet length. 280 * This makes the safe assumtion that there are no virtual holes 281 * after the data. 282 * For security, it might be wise to zero out the added bytes, 283 * but we're mainly interested in speed at the moment. 284 */ 285 if (len - sizeof (struct ether_header) < ETHERMIN) 286 len = ETHERMIN + sizeof (struct ether_header); 287 if (++is->is_txnext > SEG_MAX) 288 is->is_txnext = is->is_segboundry; 289 ifp->if_opackets++; 290 is->is_xcnt++; 291 len = (len & 0x7fff) | TCS_TBFULL; 292 movow(txs, len); 293 goto again; 294 #undef is 295 } 296 297 /* 298 * Transmit done interrupt. 299 */ 300 acecint(unit) 301 int unit; 302 { 303 register struct ace_softc *is = &ace_softc[unit]; 304 register struct tx_segment *txseg; 305 short eostat; 306 307 if (is->is_xcnt <= 0) { 308 log(LOG_ERR, "ace%d: stray xmit interrupt, xcnt %d\n", 309 unit, is->is_xcnt); 310 is->is_xcnt = 0; 311 if (is->is_if.if_snd.ifq_head) 312 acestart(&is->is_if); 313 return; 314 } 315 is->is_xcnt--; 316 txseg = (struct tx_segment *)((is->is_eoctr << 11) + is->is_dpm); 317 eostat = txseg->tx_csr; 318 if ((eostat & TCS_TBFULL) == 0) { 319 is->is_stats.tx_retries += eostat & TCS_RTC; 320 if (eostat & TCS_RTFAIL) { 321 is->is_stats.tx_discarded++; 322 is->is_if.if_oerrors++; 323 } else 324 is->is_stats.tx_datagrams++; 325 if (++is->is_eoctr >= 16) 326 is->is_eoctr = is->is_segboundry; 327 } 328 if (is->is_if.if_snd.ifq_head) 329 acestart(&is->is_if); 330 } 331 332 /* 333 * Ethernet interface receiver interrupt. 334 * If input error just drop packet. 335 * Otherwise purge input buffered data path and examine 336 * packet to determine type. If can't determine length 337 * from type, then have to drop packet. Othewise decapsulate 338 * packet based on type and pass to type specific higher-level 339 * input routine. 340 */ 341 acerint(unit) 342 int unit; 343 { 344 register struct ace_softc *is = &ace_softc[unit]; 345 register struct ifqueue *inq; 346 register struct ether_header *ace; 347 register struct rx_segment *rxseg; 348 int len, s, off, resid; 349 struct mbuf *m; 350 short eistat; 351 352 if ((is->is_if.if_flags&IFF_RUNNING) == 0) 353 return; 354 again: 355 rxseg = (struct rx_segment *)((is->is_eictr << 11) + is->is_dpm); 356 eistat = rxseg->rx_csr; 357 if ((eistat & RCS_RBFULL) == 0) 358 return; 359 is->is_if.if_ipackets++; 360 if (++is->is_eictr >= is->is_segboundry) 361 is->is_eictr = 0; 362 len = eistat & RCS_RBC; 363 if ((eistat & (RCS_ROVRN | RCS_RCRC | RCS_RODD)) || 364 len < ET_MINLEN || len > ET_MAXLEN+CRC_SIZE) { 365 if (eistat & RCS_ROVRN) 366 is->is_stats.rx_overruns++; 367 if (eistat & RCS_RCRC) 368 is->is_stats.rx_crc_errors++; 369 if (eistat & RCS_RODD) 370 is->is_stats.rx_align_errors++; 371 if (len < ET_MINLEN) 372 is->is_stats.rx_underruns++; 373 if (len > ET_MAXLEN+CRC_SIZE) 374 is->is_stats.rx_overruns++; 375 is->is_if.if_ierrors++; 376 rxseg->rx_csr = 0; 377 return; 378 } else 379 is->is_stats.rx_datagrams++; 380 ace = (struct ether_header *)rxseg->rx_data; 381 len -= sizeof (struct ether_header); 382 /* 383 * Deal with trailer protocol: if type is trailer 384 * get true type from first 16-bit word past data. 385 * Remember that type was trailer by setting off. 386 */ 387 ace->ether_type = ntohs((u_short)ace->ether_type); 388 #define acedataaddr(ace, off, type) \ 389 ((type)(((caddr_t)(((char *)ace)+sizeof (struct ether_header))+(off)))) 390 if (ace->ether_type >= ETHERTYPE_TRAIL && 391 ace->ether_type < ETHERTYPE_TRAIL+ETHERTYPE_NTRAILER) { 392 off = (ace->ether_type - ETHERTYPE_TRAIL) * 512; 393 if (off >= ETHERMTU) 394 goto setup; /* sanity */ 395 ace->ether_type = ntohs(*acedataaddr(ace, off, u_short *)); 396 resid = ntohs(*(acedataaddr(ace, off+2, u_short *))); 397 if (off + resid > len) 398 goto setup; /* sanity */ 399 len = off + resid; 400 } else 401 off = 0; 402 if (len == 0) 403 goto setup; 404 405 /* 406 * Pull packet off interface. Off is nonzero if packet 407 * has trailing header; aceget will then force this header 408 * information to be at the front. 409 */ 410 m = aceget((u_char *)rxseg->rx_data, len, off, &is->is_if); 411 if (m == 0) 412 goto setup; 413 switch (ace->ether_type) { 414 415 #ifdef INET 416 case ETHERTYPE_IP: 417 schednetisr(NETISR_IP); 418 inq = &ipintrq; 419 break; 420 #endif 421 422 case ETHERTYPE_ARP: 423 arpinput(&is->is_ac, m); 424 goto setup; 425 #ifdef NS 426 case ETHERTYPE_NS: 427 schednetisr(NETISR_NS); 428 inq = &nsintrq; 429 break; 430 431 #endif 432 default: 433 m_freem(m); 434 goto setup; 435 } 436 if (IF_QFULL(inq)) { 437 IF_DROP(inq); 438 m_freem(m); 439 goto setup; 440 } 441 s = splimp(); 442 IF_ENQUEUE(inq, m); 443 splx(s); 444 setup: 445 rxseg->rx_csr = 0; 446 goto again; 447 } 448 449 /* 450 * Routine to copy from mbuf chain to transmit buffer on the VERSAbus 451 * If packet size is less than the minimum legal size, 452 * the buffer is expanded. We probably should zero out the extra 453 * bytes for security, but that would slow things down. 454 */ 455 aceput(txbuf, m) 456 char *txbuf; 457 struct mbuf *m; 458 { 459 register u_char *bp, *mcp; 460 register short *s1, *s2; 461 register u_int len; 462 register struct mbuf *mp; 463 int total; 464 465 total = mp->m_pkthdr.len; 466 bp = (u_char *)txbuf; 467 for (mp = m; (mp); mp = mp->m_next) { 468 len = mp->m_len; 469 if (len == 0) 470 continue; 471 mcp = mtod(mp, u_char *); 472 if (((int)mcp & 01) && ((int)bp & 01)) { 473 /* source & destination at odd addresses */ 474 movob(bp++, *mcp++); 475 --len; 476 } 477 if (len > 1 && (((int)mcp & 01)==0) && (((int)bp & 01)==0)) { 478 int l = len; 479 480 s1 = (short *)bp; 481 s2 = (short *)mcp; 482 len >>= 1; /* count # of shorts */ 483 while (len-- != 0) 484 movow(s1++, *s2++); 485 len = l & 1; /* # remaining bytes */ 486 bp = (u_char *)s1; 487 mcp = (u_char *)s2; 488 } 489 while (len-- != 0) 490 movob(bp++, *mcp++); 491 } 492 m_freem(m); 493 return (total); 494 } 495 496 /* 497 * Routine to copy from VERSAbus memory into mbufs. 498 * 499 * Warning: This makes the fairly safe assumption that 500 * mbufs have even lengths. 501 */ 502 /*ARGSUSED*/ 503 struct mbuf * 504 aceget(rxbuf, totlen, off, ifp) 505 u_char *rxbuf; 506 int totlen, off; 507 struct ifnet *ifp; 508 { 509 register u_char *cp, *mcp; 510 register struct mbuf *m; 511 register int tlen; 512 struct mbuf *top = 0, **mp = ⊤ 513 int len; 514 u_char *packet_end; 515 516 rxbuf += sizeof (struct ether_header); 517 cp = rxbuf; 518 packet_end = cp + totlen; 519 if (off) { 520 off += 2 * sizeof(u_short); 521 totlen -= 2 *sizeof(u_short); 522 cp = rxbuf + off; 523 } 524 525 MGETHDR(m, M_DONTWAIT, MT_DATA); 526 if (m == 0) 527 return (0); 528 m->m_pkthdr.rcvif = ifp; 529 m->m_pkthdr.len = totlen; 530 m->m_len = MHLEN; 531 532 while (totlen > 0) { 533 if (top) { 534 MGET(m, M_DONTWAIT, MT_DATA); 535 if (m == 0) { 536 m_freem(top); 537 return (0); 538 } 539 m->m_len = MLEN; 540 } 541 len = min(totlen, (packet_end - cp)); 542 if (len >= MINCLSIZE) { 543 MCLGET(m, M_DONTWAIT); 544 if (m->m_flags & M_EXT) 545 m->m_len = len = min(len, MCLBYTES); 546 else 547 len = m->m_len; 548 } else { 549 /* 550 * Place initial small packet/header at end of mbuf. 551 */ 552 if (len < m->m_len) { 553 if (top == 0 && len + max_linkhdr <= m->m_len) 554 m->m_data += max_linkhdr; 555 m->m_len = len; 556 } else 557 len = m->m_len; 558 } 559 mcp = mtod(m, u_char *); 560 /*bcopy((caddr_t)cp, (caddr_t)mcp, len);*/ 561 /*cp += len; mcp += len;*/ 562 tlen = len; 563 if (((int)mcp & 01) && ((int)cp & 01)) { 564 /* source & destination at odd addresses */ 565 *mcp++ = *cp++; 566 --tlen; 567 } 568 if (tlen > 1 && (((int)mcp&01) == 0) && (((int)cp&01) == 0)) { 569 register short *s1, *s2; 570 register int l; 571 572 s1 = (short *)mcp; 573 s2 = (short *)cp; 574 l = tlen >> 1; /* count # of shorts */ 575 while (l-- > 0) /* copy shorts */ 576 *s1++ = *s2++; 577 tlen &= 1; /* # remaining bytes */ 578 mcp = (u_char *)s1; 579 cp = (u_char *)s2; 580 } 581 while (tlen-- > 0) 582 *mcp++ = *cp++; 583 *mp = m; 584 mp = &m->m_next; 585 totlen -= len; 586 if (cp == packet_end) 587 cp = rxbuf; 588 } 589 return (top); 590 } 591 592 /* backoff table masks */ 593 short random_mask_tbl[16] = { 594 0x0040, 0x00c0, 0x01c0, 0x03c0, 0x07c0, 0x0fc0, 0x1fc0, 0x3fc0, 595 0x7fc0, 0xffc0, 0xffc0, 0xffc0, 0xffc0, 0xffc0, 0xffc0, 0xffc0 596 }; 597 598 acebakoff(is, txseg, retries) 599 struct ace_softc *is; 600 struct tx_segment *txseg; 601 register int retries; 602 { 603 register short *pBakNum, random_num; 604 short *pMask; 605 606 pMask = &random_mask_tbl[0]; 607 pBakNum = &txseg->tx_backoff[0]; 608 while (--retries >= 0) { 609 random_num = (is->is_currnd = (is->is_currnd * 18741)-13849); 610 random_num &= *pMask++; 611 *pBakNum++ = random_num ^ (short)(0xff00 | 0x00fc); 612 } 613 } 614 615 /* 616 * Process an ioctl request. 617 */ 618 aceioctl(ifp, cmd, data) 619 register struct ifnet *ifp; 620 int cmd; 621 caddr_t data; 622 { 623 register struct ifaddr *ifa = (struct ifaddr *)data; 624 struct acedevice *addr; 625 int s = splimp(), error = 0; 626 627 switch (cmd) { 628 629 case SIOCSIFADDR: 630 ifp->if_flags |= IFF_UP; 631 switch (ifa->ifa_addr.sa_family) { 632 #ifdef INET 633 case AF_INET: 634 aceinit(ifp->if_unit); /* before arpwhohas */ 635 ((struct arpcom *)ifp)->ac_ipaddr = 636 IA_SIN(ifa)->sin_addr; 637 arpwhohas((struct arpcom *)ifp, &IA_SIN(ifa)->sin_addr); 638 break; 639 #endif 640 #ifdef NS 641 case AF_NS: { 642 struct ns_addr *ina = &IA_SNS(ifa)->sns_addr; 643 struct ace_softc *is = &ace_softc[ifp->if_unit]; 644 645 if (!ns_nullhost(*ina)) { 646 ifp->if_flags &= ~IFF_RUNNING; 647 addr = (struct acedevice *) 648 aceinfo[ifp->if_unit]->ui_addr; 649 movow(&addr->csr, CSR_RESET); 650 DELAY(10000); 651 /* set station address & copy addr to arp */ 652 acesetaddr(ifp->if_unit, addr, 653 ina->x_host.c_host); 654 } else 655 ina->x_host = *(union ns_host *)is->is_addr; 656 aceinit(ifp->if_unit); 657 break; 658 } 659 #endif 660 default: 661 aceinit(ifp->if_unit); 662 break; 663 } 664 break; 665 666 case SIOCSIFFLAGS: 667 if ((ifp->if_flags&IFF_UP) == 0 && ifp->if_flags&IFF_RUNNING) { 668 addr = (struct acedevice *) 669 (aceinfo[ifp->if_unit]->ui_addr); 670 movow(&addr->csr, CSR_RESET); 671 ifp->if_flags &= ~IFF_RUNNING; 672 } else if (ifp->if_flags&IFF_UP && 673 (ifp->if_flags&IFF_RUNNING) == 0) 674 aceinit(ifp->if_unit); 675 break; 676 677 default: 678 error = EINVAL; 679 } 680 splx(s); 681 return (error); 682 } 683 684 /* 685 * Set the on-board station address, then read it back 686 * to initialize the address used by ARP (among others). 687 */ 688 acesetaddr(unit, addr, station) 689 short unit; 690 struct acedevice *addr; 691 u_char *station; 692 { 693 struct ace_softc *is = &ace_softc[unit]; 694 register short *wp, i; 695 696 for (wp = (short *)addr->station, i = 0; i < 6; i++) 697 movow(wp++, ~*station++); 698 for (wp = (short *)addr->station, i = 0; i < 6; i++) 699 is->is_addr[i] = ~*wp++; 700 printf("ace%d: hardware address %s\n", unit, 701 ether_sprintf(is->is_addr)); 702 } 703 704 /* 705 * Setup the device for use. Initialize dual-ported memory, 706 * backoff parameters, and various other software state. 707 */ 708 acesetup(unit) 709 int unit; 710 { 711 register struct ace_softc *is = &ace_softc[unit]; 712 register char *pData1; 713 register short i; 714 struct acedevice *addr; 715 716 bzero(is->is_dpm, 16384*2); 717 is->is_currnd = 49123; 718 addr = (struct acedevice *)aceinfo[unit]->ui_addr; 719 is->is_segboundry = (addr->segb >> 11) & 0xf; 720 pData1 = is->is_dpm + (is->is_segboundry << 11); 721 for (i = SEG_MAX + 1 - is->is_segboundry; --i >= 0;) { 722 acebakoff(is, (struct tx_segment *)pData1, 15); 723 pData1 += sizeof (struct tx_segment); 724 } 725 is->is_eictr = 0; 726 is->is_eoctr = is->is_txnext = is->is_segboundry; 727 bzero((char *)&is->is_stats, sizeof (is->is_stats)); 728 } 729 #endif 730