1 /* $NetBSD: lance.c,v 1.12 2000/05/12 16:45:42 thorpej Exp $ */ 2 3 /*- 4 * Copyright (c) 1997, 1998 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Charles M. Hannum and by Jason R. Thorpe of the Numerical Aerospace 9 * Simulation Facility, NASA Ames Research Center. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in the 18 * documentation and/or other materials provided with the distribution. 19 * 3. All advertising materials mentioning features or use of this software 20 * must display the following acknowledgement: 21 * This product includes software developed by the NetBSD 22 * Foundation, Inc. and its contributors. 23 * 4. Neither the name of The NetBSD Foundation nor the names of its 24 * contributors may be used to endorse or promote products derived 25 * from this software without specific prior written permission. 26 * 27 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 28 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 29 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 30 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 31 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 32 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 33 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 34 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 35 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 36 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 37 * POSSIBILITY OF SUCH DAMAGE. 38 */ 39 40 /*- 41 * Copyright (c) 1992, 1993 42 * The Regents of the University of California. All rights reserved. 43 * 44 * This code is derived from software contributed to Berkeley by 45 * Ralph Campbell and Rick Macklem. 46 * 47 * Redistribution and use in source and binary forms, with or without 48 * modification, are permitted provided that the following conditions 49 * are met: 50 * 1. Redistributions of source code must retain the above copyright 51 * notice, this list of conditions and the following disclaimer. 52 * 2. Redistributions in binary form must reproduce the above copyright 53 * notice, this list of conditions and the following disclaimer in the 54 * documentation and/or other materials provided with the distribution. 55 * 3. All advertising materials mentioning features or use of this software 56 * must display the following acknowledgement: 57 * This product includes software developed by the University of 58 * California, Berkeley and its contributors. 59 * 4. Neither the name of the University nor the names of its contributors 60 * may be used to endorse or promote products derived from this software 61 * without specific prior written permission. 62 * 63 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 64 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 65 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 66 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 67 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 68 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 69 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 70 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 71 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 72 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 73 * SUCH DAMAGE. 74 * 75 * @(#)if_le.c 8.2 (Berkeley) 11/16/93 76 */ 77 78 #include "opt_inet.h" 79 #include "opt_ccitt.h" 80 #include "opt_llc.h" 81 #include "opt_ns.h" 82 #include "bpfilter.h" 83 #include "rnd.h" 84 85 #include <sys/param.h> 86 #include <sys/systm.h> 87 #include <sys/mbuf.h> 88 #include <sys/syslog.h> 89 #include <sys/socket.h> 90 #include <sys/device.h> 91 #include <sys/malloc.h> 92 #include <sys/ioctl.h> 93 #include <sys/errno.h> 94 #if NRND > 0 95 #include <sys/rnd.h> 96 #endif 97 98 #include <net/if.h> 99 #include <net/if_dl.h> 100 #include <net/if_ether.h> 101 #include <net/if_media.h> 102 103 #ifdef INET 104 #include <netinet/in.h> 105 #include <netinet/if_inarp.h> 106 #include <netinet/in_systm.h> 107 #include <netinet/in_var.h> 108 #include <netinet/ip.h> 109 #endif 110 111 #ifdef NS 112 #include <netns/ns.h> 113 #include <netns/ns_if.h> 114 #endif 115 116 #if defined(CCITT) && defined(LLC) 117 #include <sys/socketvar.h> 118 #include <netccitt/x25.h> 119 #include <netccitt/pk.h> 120 #include <netccitt/pk_var.h> 121 #include <netccitt/pk_extern.h> 122 #endif 123 124 #if NBPFILTER > 0 125 #include <net/bpf.h> 126 #include <net/bpfdesc.h> 127 #endif 128 129 #include <dev/ic/lancereg.h> 130 #include <dev/ic/lancevar.h> 131 132 #if defined(_KERNEL) && !defined(_LKM) 133 #include "opt_ddb.h" 134 #endif 135 136 #ifdef DDB 137 #define integrate 138 #define hide 139 #else 140 #define integrate static __inline 141 #define hide static 142 #endif 143 144 integrate struct mbuf *lance_get __P((struct lance_softc *, int, int)); 145 146 hide void lance_shutdown __P((void *)); 147 148 int lance_mediachange __P((struct ifnet *)); 149 void lance_mediastatus __P((struct ifnet *, struct ifmediareq *)); 150 151 static inline u_int16_t ether_cmp __P((void *, void *)); 152 153 void lance_stop __P((struct lance_softc *)); 154 int lance_ioctl __P((struct ifnet *, u_long, caddr_t)); 155 void lance_watchdog __P((struct ifnet *)); 156 157 /* 158 * Compare two Ether/802 addresses for equality, inlined and 159 * unrolled for speed. Use this like bcmp(). 160 * 161 * XXX: Add <machine/inlines.h> for stuff like this? 162 * XXX: or maybe add it to libkern.h instead? 163 * 164 * "I'd love to have an inline assembler version of this." 165 * XXX: Who wanted that? mycroft? I wrote one, but this 166 * version in C is as good as hand-coded assembly. -gwr 167 * 168 * Please do NOT tweak this without looking at the actual 169 * assembly code generated before and after your tweaks! 170 */ 171 static inline u_int16_t 172 ether_cmp(one, two) 173 void *one, *two; 174 { 175 u_int16_t *a = (u_short *) one; 176 u_int16_t *b = (u_short *) two; 177 u_int16_t diff; 178 179 #ifdef m68k 180 /* 181 * The post-increment-pointer form produces the best 182 * machine code for m68k. This was carefully tuned 183 * so it compiles to just 8 short (2-byte) op-codes! 184 */ 185 diff = *a++ - *b++; 186 diff |= *a++ - *b++; 187 diff |= *a++ - *b++; 188 #else 189 /* 190 * Most modern CPUs do better with a single expresion. 191 * Note that short-cut evaluation is NOT helpful here, 192 * because it just makes the code longer, not faster! 193 */ 194 diff = (a[0] - b[0]) | (a[1] - b[1]) | (a[2] - b[2]); 195 #endif 196 197 return (diff); 198 } 199 200 #define ETHER_CMP ether_cmp 201 202 #ifdef LANCE_REVC_BUG 203 /* Make sure this is short-aligned, for ether_cmp(). */ 204 static u_int16_t bcast_enaddr[3] = { ~0, ~0, ~0 }; 205 #endif 206 207 #define ifp (&sc->sc_ethercom.ec_if) 208 209 void 210 lance_config(sc) 211 struct lance_softc *sc; 212 { 213 int i; 214 215 /* Make sure the chip is stopped. */ 216 lance_stop(sc); 217 218 /* Initialize ifnet structure. */ 219 bcopy(sc->sc_dev.dv_xname, ifp->if_xname, IFNAMSIZ); 220 ifp->if_softc = sc; 221 ifp->if_start = sc->sc_start; 222 ifp->if_ioctl = lance_ioctl; 223 ifp->if_watchdog = lance_watchdog; 224 ifp->if_flags = 225 IFF_BROADCAST | IFF_SIMPLEX | IFF_NOTRAILERS | IFF_MULTICAST; 226 #ifdef LANCE_REVC_BUG 227 ifp->if_flags &= ~IFF_MULTICAST; 228 #endif 229 230 /* Initialize ifmedia structures. */ 231 ifmedia_init(&sc->sc_media, 0, lance_mediachange, lance_mediastatus); 232 if (sc->sc_supmedia != NULL) { 233 for (i = 0; i < sc->sc_nsupmedia; i++) 234 ifmedia_add(&sc->sc_media, sc->sc_supmedia[i], 235 0, NULL); 236 ifmedia_set(&sc->sc_media, sc->sc_defaultmedia); 237 } else { 238 ifmedia_add(&sc->sc_media, IFM_ETHER|IFM_MANUAL, 0, NULL); 239 ifmedia_set(&sc->sc_media, IFM_ETHER|IFM_MANUAL); 240 } 241 242 switch (sc->sc_memsize) { 243 case 8192: 244 sc->sc_nrbuf = 4; 245 sc->sc_ntbuf = 1; 246 break; 247 case 16384: 248 sc->sc_nrbuf = 8; 249 sc->sc_ntbuf = 2; 250 break; 251 case 32768: 252 sc->sc_nrbuf = 16; 253 sc->sc_ntbuf = 4; 254 break; 255 case 65536: 256 sc->sc_nrbuf = 32; 257 sc->sc_ntbuf = 8; 258 break; 259 case 131072: 260 sc->sc_nrbuf = 64; 261 sc->sc_ntbuf = 16; 262 break; 263 case 262144: 264 sc->sc_nrbuf = 128; 265 sc->sc_ntbuf = 32; 266 break; 267 default: 268 panic("lance_config: weird memory size"); 269 } 270 271 printf(": address %s\n", ether_sprintf(sc->sc_enaddr)); 272 printf("%s: %d receive buffers, %d transmit buffers\n", 273 sc->sc_dev.dv_xname, sc->sc_nrbuf, sc->sc_ntbuf); 274 275 /* Attach the interface. */ 276 if_attach(ifp); 277 ether_ifattach(ifp, sc->sc_enaddr); 278 279 #if NBPFILTER > 0 280 bpfattach(&ifp->if_bpf, ifp, DLT_EN10MB, sizeof(struct ether_header)); 281 #endif 282 283 sc->sc_sh = shutdownhook_establish(lance_shutdown, sc); 284 if (sc->sc_sh == NULL) 285 panic("lance_config: can't establish shutdownhook"); 286 sc->sc_rbufaddr = malloc(sc->sc_nrbuf * sizeof(int), M_DEVBUF, 287 M_WAITOK); 288 sc->sc_tbufaddr = malloc(sc->sc_ntbuf * sizeof(int), M_DEVBUF, 289 M_WAITOK); 290 291 #if NRND > 0 292 rnd_attach_source(&sc->rnd_source, sc->sc_dev.dv_xname, 293 RND_TYPE_NET, 0); 294 #endif 295 } 296 297 void 298 lance_reset(sc) 299 struct lance_softc *sc; 300 { 301 int s; 302 303 s = splnet(); 304 lance_init(sc); 305 splx(s); 306 } 307 308 void 309 lance_stop(sc) 310 struct lance_softc *sc; 311 { 312 313 (*sc->sc_wrcsr)(sc, LE_CSR0, LE_C0_STOP); 314 } 315 316 /* 317 * Initialization of interface; set up initialization block 318 * and transmit/receive descriptor rings. 319 */ 320 void 321 lance_init(sc) 322 struct lance_softc *sc; 323 { 324 int timo; 325 u_long a; 326 327 (*sc->sc_wrcsr)(sc, LE_CSR0, LE_C0_STOP); 328 DELAY(100); 329 330 /* Newer LANCE chips have a reset register */ 331 if (sc->sc_hwreset) 332 (*sc->sc_hwreset)(sc); 333 334 /* Set the correct byte swapping mode, etc. */ 335 (*sc->sc_wrcsr)(sc, LE_CSR3, sc->sc_conf3); 336 337 /* Set up LANCE init block. */ 338 (*sc->sc_meminit)(sc); 339 340 /* Give LANCE the physical address of its init block. */ 341 a = sc->sc_addr + LE_INITADDR(sc); 342 (*sc->sc_wrcsr)(sc, LE_CSR1, a); 343 (*sc->sc_wrcsr)(sc, LE_CSR2, a >> 16); 344 345 /* Try to initialize the LANCE. */ 346 DELAY(100); 347 (*sc->sc_wrcsr)(sc, LE_CSR0, LE_C0_INIT); 348 349 /* Wait for initialization to finish. */ 350 for (timo = 100000; timo; timo--) 351 if ((*sc->sc_rdcsr)(sc, LE_CSR0) & LE_C0_IDON) 352 break; 353 354 if ((*sc->sc_rdcsr)(sc, LE_CSR0) & LE_C0_IDON) { 355 /* Start the LANCE. */ 356 (*sc->sc_wrcsr)(sc, LE_CSR0, LE_C0_INEA | LE_C0_STRT | 357 LE_C0_IDON); 358 ifp->if_flags |= IFF_RUNNING; 359 ifp->if_flags &= ~IFF_OACTIVE; 360 ifp->if_timer = 0; 361 (*sc->sc_start)(ifp); 362 } else 363 printf("%s: controller failed to initialize\n", 364 sc->sc_dev.dv_xname); 365 if (sc->sc_hwinit) 366 (*sc->sc_hwinit)(sc); 367 } 368 369 /* 370 * Routine to copy from mbuf chain to transmit buffer in 371 * network buffer memory. 372 */ 373 int 374 lance_put(sc, boff, m) 375 struct lance_softc *sc; 376 int boff; 377 struct mbuf *m; 378 { 379 struct mbuf *n; 380 int len, tlen = 0; 381 382 for (; m; m = n) { 383 len = m->m_len; 384 if (len == 0) { 385 MFREE(m, n); 386 continue; 387 } 388 (*sc->sc_copytobuf)(sc, mtod(m, caddr_t), boff, len); 389 boff += len; 390 tlen += len; 391 MFREE(m, n); 392 } 393 if (tlen < LEMINSIZE) { 394 (*sc->sc_zerobuf)(sc, boff, LEMINSIZE - tlen); 395 tlen = LEMINSIZE; 396 } 397 return (tlen); 398 } 399 400 /* 401 * Pull data off an interface. 402 * Len is length of data, with local net header stripped. 403 * We copy the data into mbufs. When full cluster sized units are present 404 * we copy into clusters. 405 */ 406 integrate struct mbuf * 407 lance_get(sc, boff, totlen) 408 struct lance_softc *sc; 409 int boff, totlen; 410 { 411 struct mbuf *m, *m0, *newm; 412 int len; 413 414 MGETHDR(m0, M_DONTWAIT, MT_DATA); 415 if (m0 == 0) 416 return (0); 417 m0->m_pkthdr.rcvif = ifp; 418 m0->m_pkthdr.len = totlen; 419 len = MHLEN; 420 m = m0; 421 422 while (totlen > 0) { 423 if (totlen >= MINCLSIZE) { 424 MCLGET(m, M_DONTWAIT); 425 if ((m->m_flags & M_EXT) == 0) 426 goto bad; 427 len = MCLBYTES; 428 } 429 430 if (m == m0) { 431 caddr_t newdata = (caddr_t) 432 ALIGN(m->m_data + sizeof(struct ether_header)) - 433 sizeof(struct ether_header); 434 len -= newdata - m->m_data; 435 m->m_data = newdata; 436 } 437 438 m->m_len = len = min(totlen, len); 439 (*sc->sc_copyfrombuf)(sc, mtod(m, caddr_t), boff, len); 440 boff += len; 441 442 totlen -= len; 443 if (totlen > 0) { 444 MGET(newm, M_DONTWAIT, MT_DATA); 445 if (newm == 0) 446 goto bad; 447 len = MLEN; 448 m = m->m_next = newm; 449 } 450 } 451 452 return (m0); 453 454 bad: 455 m_freem(m0); 456 return (0); 457 } 458 459 /* 460 * Pass a packet to the higher levels. 461 */ 462 void 463 lance_read(sc, boff, len) 464 struct lance_softc *sc; 465 int boff, len; 466 { 467 struct mbuf *m; 468 struct ether_header *eh; 469 470 if (len <= sizeof(struct ether_header) || 471 len > ETHERMTU + sizeof(struct ether_header)) { 472 #ifdef LEDEBUG 473 printf("%s: invalid packet size %d; dropping\n", 474 sc->sc_dev.dv_xname, len); 475 #endif 476 ifp->if_ierrors++; 477 return; 478 } 479 480 /* Pull packet off interface. */ 481 m = lance_get(sc, boff, len); 482 if (m == 0) { 483 ifp->if_ierrors++; 484 return; 485 } 486 487 ifp->if_ipackets++; 488 489 /* We assume that the header fit entirely in one mbuf. */ 490 eh = mtod(m, struct ether_header *); 491 492 #if NBPFILTER > 0 493 /* 494 * Check if there's a BPF listener on this interface. 495 * If so, hand off the raw packet to BPF. 496 */ 497 if (ifp->if_bpf) { 498 bpf_mtap(ifp->if_bpf, m); 499 500 #ifndef LANCE_REVC_BUG 501 /* 502 * Note that the interface cannot be in promiscuous mode if 503 * there are no BPF listeners. And if we are in promiscuous 504 * mode, we have to check if this packet is really ours. 505 */ 506 if ((ifp->if_flags & IFF_PROMISC) != 0 && 507 (eh->ether_dhost[0] & 1) == 0 && /* !mcast and !bcast */ 508 ETHER_CMP(eh->ether_dhost, sc->sc_enaddr)) { 509 m_freem(m); 510 return; 511 } 512 #endif 513 } 514 #endif 515 516 #ifdef LANCE_REVC_BUG 517 /* 518 * The old LANCE (Rev. C) chips have a bug which causes 519 * garbage to be inserted in front of the received packet. 520 * The work-around is to ignore packets with an invalid 521 * destination address (garbage will usually not match). 522 * Of course, this precludes multicast support... 523 */ 524 if (ETHER_CMP(eh->ether_dhost, sc->sc_enaddr) && 525 ETHER_CMP(eh->ether_dhost, bcast_enaddr)) { 526 m_freem(m); 527 return; 528 } 529 #endif 530 531 /* Pass the packet up. */ 532 (*ifp->if_input)(ifp, m); 533 } 534 535 #undef ifp 536 537 void 538 lance_watchdog(ifp) 539 struct ifnet *ifp; 540 { 541 struct lance_softc *sc = ifp->if_softc; 542 543 log(LOG_ERR, "%s: device timeout\n", sc->sc_dev.dv_xname); 544 ++ifp->if_oerrors; 545 546 lance_reset(sc); 547 } 548 549 int 550 lance_mediachange(ifp) 551 struct ifnet *ifp; 552 { 553 struct lance_softc *sc = ifp->if_softc; 554 555 if (sc->sc_mediachange) 556 return ((*sc->sc_mediachange)(sc)); 557 return (0); 558 } 559 560 void 561 lance_mediastatus(ifp, ifmr) 562 struct ifnet *ifp; 563 struct ifmediareq *ifmr; 564 { 565 struct lance_softc *sc = ifp->if_softc; 566 567 if ((ifp->if_flags & IFF_UP) == 0) 568 return; 569 570 ifmr->ifm_status = IFM_AVALID; 571 if (sc->sc_havecarrier) 572 ifmr->ifm_status |= IFM_ACTIVE; 573 574 if (sc->sc_mediastatus) 575 (*sc->sc_mediastatus)(sc, ifmr); 576 } 577 578 /* 579 * Process an ioctl request. 580 */ 581 int 582 lance_ioctl(ifp, cmd, data) 583 struct ifnet *ifp; 584 u_long cmd; 585 caddr_t data; 586 { 587 struct lance_softc *sc = ifp->if_softc; 588 struct ifaddr *ifa = (struct ifaddr *)data; 589 struct ifreq *ifr = (struct ifreq *)data; 590 int s, error = 0; 591 592 s = splnet(); 593 594 switch (cmd) { 595 596 case SIOCSIFADDR: 597 ifp->if_flags |= IFF_UP; 598 599 switch (ifa->ifa_addr->sa_family) { 600 #ifdef INET 601 case AF_INET: 602 lance_init(sc); 603 arp_ifinit(ifp, ifa); 604 break; 605 #endif 606 #ifdef NS 607 case AF_NS: 608 { 609 struct ns_addr *ina = &IA_SNS(ifa)->sns_addr; 610 611 if (ns_nullhost(*ina)) 612 ina->x_host = 613 *(union ns_host *)LLADDR(ifp->if_sadl); 614 else { 615 bcopy(ina->x_host.c_host, 616 LLADDR(ifp->if_sadl), 617 sizeof(sc->sc_enaddr)); 618 } 619 /* Set new address. */ 620 lance_init(sc); 621 break; 622 } 623 #endif 624 default: 625 lance_init(sc); 626 break; 627 } 628 break; 629 630 #if defined(CCITT) && defined(LLC) 631 case SIOCSIFCONF_X25: 632 ifp->if_flags |= IFF_UP; 633 ifa->ifa_rtrequest = cons_rtrequest; /* XXX */ 634 error = x25_llcglue(PRC_IFUP, ifa->ifa_addr); 635 if (error == 0) 636 lance_init(sc); 637 break; 638 #endif /* CCITT && LLC */ 639 640 case SIOCSIFFLAGS: 641 if ((ifp->if_flags & IFF_UP) == 0 && 642 (ifp->if_flags & IFF_RUNNING) != 0) { 643 /* 644 * If interface is marked down and it is running, then 645 * stop it. 646 */ 647 lance_stop(sc); 648 ifp->if_flags &= ~IFF_RUNNING; 649 } else if ((ifp->if_flags & IFF_UP) != 0 && 650 (ifp->if_flags & IFF_RUNNING) == 0) { 651 /* 652 * If interface is marked up and it is stopped, then 653 * start it. 654 */ 655 lance_init(sc); 656 } else if ((ifp->if_flags & IFF_UP) != 0) { 657 /* 658 * Reset the interface to pick up changes in any other 659 * flags that affect hardware registers. 660 */ 661 /*lance_stop(sc);*/ 662 lance_init(sc); 663 } 664 #ifdef LEDEBUG 665 if (ifp->if_flags & IFF_DEBUG) 666 sc->sc_debug = 1; 667 else 668 sc->sc_debug = 0; 669 #endif 670 break; 671 672 case SIOCADDMULTI: 673 case SIOCDELMULTI: 674 error = (cmd == SIOCADDMULTI) ? 675 ether_addmulti(ifr, &sc->sc_ethercom) : 676 ether_delmulti(ifr, &sc->sc_ethercom); 677 678 if (error == ENETRESET) { 679 /* 680 * Multicast list has changed; set the hardware filter 681 * accordingly. 682 */ 683 lance_reset(sc); 684 error = 0; 685 } 686 break; 687 688 case SIOCGIFMEDIA: 689 case SIOCSIFMEDIA: 690 error = ifmedia_ioctl(ifp, ifr, &sc->sc_media, cmd); 691 break; 692 693 default: 694 error = EINVAL; 695 break; 696 } 697 698 splx(s); 699 return (error); 700 } 701 702 hide void 703 lance_shutdown(arg) 704 void *arg; 705 { 706 707 lance_stop((struct lance_softc *)arg); 708 } 709 710 /* 711 * Set up the logical address filter. 712 */ 713 void 714 lance_setladrf(ac, af) 715 struct ethercom *ac; 716 u_int16_t *af; 717 { 718 struct ifnet *ifp = &ac->ec_if; 719 struct ether_multi *enm; 720 u_int32_t crc; 721 struct ether_multistep step; 722 723 /* 724 * Set up multicast address filter by passing all multicast addresses 725 * through a crc generator, and then using the high order 6 bits as an 726 * index into the 64 bit logical address filter. The high order bit 727 * selects the word, while the rest of the bits select the bit within 728 * the word. 729 */ 730 731 if (ifp->if_flags & IFF_PROMISC) 732 goto allmulti; 733 734 af[0] = af[1] = af[2] = af[3] = 0x0000; 735 ETHER_FIRST_MULTI(step, ac, enm); 736 while (enm != NULL) { 737 if (ETHER_CMP(enm->enm_addrlo, enm->enm_addrhi)) { 738 /* 739 * We must listen to a range of multicast addresses. 740 * For now, just accept all multicasts, rather than 741 * trying to set only those filter bits needed to match 742 * the range. (At this time, the only use of address 743 * ranges is for IP multicast routing, for which the 744 * range is big enough to require all bits set.) 745 */ 746 goto allmulti; 747 } 748 749 crc = ether_crc32_le(enm->enm_addrlo, ETHER_ADDR_LEN); 750 751 /* Just want the 6 most significant bits. */ 752 crc >>= 26; 753 754 /* Set the corresponding bit in the filter. */ 755 af[crc >> 4] |= 1 << (crc & 0xf); 756 757 ETHER_NEXT_MULTI(step, enm); 758 } 759 ifp->if_flags &= ~IFF_ALLMULTI; 760 return; 761 762 allmulti: 763 ifp->if_flags |= IFF_ALLMULTI; 764 af[0] = af[1] = af[2] = af[3] = 0xffff; 765 } 766 767 /* 768 * Routines for accessing the transmit and receive buffers. 769 * The various CPU and adapter configurations supported by this 770 * driver require three different access methods for buffers 771 * and descriptors: 772 * (1) contig (contiguous data; no padding), 773 * (2) gap2 (two bytes of data followed by two bytes of padding), 774 * (3) gap16 (16 bytes of data followed by 16 bytes of padding). 775 */ 776 777 /* 778 * contig: contiguous data with no padding. 779 * 780 * Buffers may have any alignment. 781 */ 782 783 void 784 lance_copytobuf_contig(sc, from, boff, len) 785 struct lance_softc *sc; 786 void *from; 787 int boff, len; 788 { 789 volatile caddr_t buf = sc->sc_mem; 790 791 /* 792 * Just call bcopy() to do the work. 793 */ 794 bcopy(from, buf + boff, len); 795 } 796 797 void 798 lance_copyfrombuf_contig(sc, to, boff, len) 799 struct lance_softc *sc; 800 void *to; 801 int boff, len; 802 { 803 volatile caddr_t buf = sc->sc_mem; 804 805 /* 806 * Just call bcopy() to do the work. 807 */ 808 bcopy(buf + boff, to, len); 809 } 810 811 void 812 lance_zerobuf_contig(sc, boff, len) 813 struct lance_softc *sc; 814 int boff, len; 815 { 816 volatile caddr_t buf = sc->sc_mem; 817 818 /* 819 * Just let bzero() do the work 820 */ 821 bzero(buf + boff, len); 822 } 823 824 #if 0 825 /* 826 * Examples only; duplicate these and tweak (if necessary) in 827 * machine-specific front-ends. 828 */ 829 830 /* 831 * gap2: two bytes of data followed by two bytes of pad. 832 * 833 * Buffers must be 4-byte aligned. The code doesn't worry about 834 * doing an extra byte. 835 */ 836 837 void 838 lance_copytobuf_gap2(sc, fromv, boff, len) 839 struct lance_softc *sc; 840 void *fromv; 841 int boff; 842 int len; 843 { 844 volatile caddr_t buf = sc->sc_mem; 845 caddr_t from = fromv; 846 volatile u_int16_t *bptr; 847 848 if (boff & 0x1) { 849 /* handle unaligned first byte */ 850 bptr = ((volatile u_int16_t *)buf) + (boff - 1); 851 *bptr = (*from++ << 8) | (*bptr & 0xff); 852 bptr += 2; 853 len--; 854 } else 855 bptr = ((volatile u_int16_t *)buf) + boff; 856 while (len > 1) { 857 *bptr = (from[1] << 8) | (from[0] & 0xff); 858 bptr += 2; 859 from += 2; 860 len -= 2; 861 } 862 if (len == 1) 863 *bptr = (u_int16_t)*from; 864 } 865 866 void 867 lance_copyfrombuf_gap2(sc, tov, boff, len) 868 struct lance_softc *sc; 869 void *tov; 870 int boff, len; 871 { 872 volatile caddr_t buf = sc->sc_mem; 873 caddr_t to = tov; 874 volatile u_int16_t *bptr; 875 u_int16_t tmp; 876 877 if (boff & 0x1) { 878 /* handle unaligned first byte */ 879 bptr = ((volatile u_int16_t *)buf) + (boff - 1); 880 *to++ = (*bptr >> 8) & 0xff; 881 bptr += 2; 882 len--; 883 } else 884 bptr = ((volatile u_int16_t *)buf) + boff; 885 while (len > 1) { 886 tmp = *bptr; 887 *to++ = tmp & 0xff; 888 *to++ = (tmp >> 8) & 0xff; 889 bptr += 2; 890 len -= 2; 891 } 892 if (len == 1) 893 *to = *bptr & 0xff; 894 } 895 896 void 897 lance_zerobuf_gap2(sc, boff, len) 898 struct lance_softc *sc; 899 int boff, len; 900 { 901 volatile caddr_t buf = sc->sc_mem; 902 volatile u_int16_t *bptr; 903 904 if ((unsigned)boff & 0x1) { 905 bptr = ((volatile u_int16_t *)buf) + (boff - 1); 906 *bptr &= 0xff; 907 bptr += 2; 908 len--; 909 } else 910 bptr = ((volatile u_int16_t *)buf) + boff; 911 while (len > 0) { 912 *bptr = 0; 913 bptr += 2; 914 len -= 2; 915 } 916 } 917 918 /* 919 * gap16: 16 bytes of data followed by 16 bytes of pad. 920 * 921 * Buffers must be 32-byte aligned. 922 */ 923 924 void 925 lance_copytobuf_gap16(sc, fromv, boff, len) 926 struct lance_softc *sc; 927 void *fromv; 928 int boff; 929 int len; 930 { 931 volatile caddr_t buf = sc->sc_mem; 932 caddr_t from = fromv; 933 caddr_t bptr; 934 int xfer; 935 936 bptr = buf + ((boff << 1) & ~0x1f); 937 boff &= 0xf; 938 xfer = min(len, 16 - boff); 939 while (len > 0) { 940 bcopy(from, bptr + boff, xfer); 941 from += xfer; 942 bptr += 32; 943 boff = 0; 944 len -= xfer; 945 xfer = min(len, 16); 946 } 947 } 948 949 void 950 lance_copyfrombuf_gap16(sc, tov, boff, len) 951 struct lance_softc *sc; 952 void *tov; 953 int boff, len; 954 { 955 volatile caddr_t buf = sc->sc_mem; 956 caddr_t to = tov; 957 caddr_t bptr; 958 int xfer; 959 960 bptr = buf + ((boff << 1) & ~0x1f); 961 boff &= 0xf; 962 xfer = min(len, 16 - boff); 963 while (len > 0) { 964 bcopy(bptr + boff, to, xfer); 965 to += xfer; 966 bptr += 32; 967 boff = 0; 968 len -= xfer; 969 xfer = min(len, 16); 970 } 971 } 972 973 void 974 lance_zerobuf_gap16(sc, boff, len) 975 struct lance_softc *sc; 976 int boff, len; 977 { 978 volatile caddr_t buf = sc->sc_mem; 979 caddr_t bptr; 980 int xfer; 981 982 bptr = buf + ((boff << 1) & ~0x1f); 983 boff &= 0xf; 984 xfer = min(len, 16 - boff); 985 while (len > 0) { 986 bzero(bptr + boff, xfer); 987 bptr += 32; 988 boff = 0; 989 len -= xfer; 990 xfer = min(len, 16); 991 } 992 } 993 #endif /* Example only */ 994