1 /* $OpenBSD: if_el.c,v 1.18 2003/01/27 19:09:12 jason Exp $ */ 2 /* $NetBSD: if_el.c,v 1.39 1996/05/12 23:52:32 mycroft Exp $ */ 3 4 /* 5 * Copyright (c) 1994, Matthew E. Kimmel. Permission is hereby granted 6 * to use, copy, modify and distribute this software provided that both 7 * the copyright notice and this permission notice appear in all copies 8 * of the software, derivative works or modified versions, and any 9 * portions thereof. 10 */ 11 12 /* 13 * 3COM Etherlink 3C501 device driver 14 */ 15 16 /* 17 * Bugs/possible improvements: 18 * - Does not currently support DMA 19 * - Does not currently support multicasts 20 */ 21 22 #include "bpfilter.h" 23 24 #include <sys/param.h> 25 #include <sys/systm.h> 26 #include <sys/errno.h> 27 #include <sys/ioctl.h> 28 #include <sys/mbuf.h> 29 #include <sys/socket.h> 30 #include <sys/syslog.h> 31 #include <sys/device.h> 32 33 #include <net/if.h> 34 #include <net/if_dl.h> 35 #include <net/if_types.h> 36 37 #ifdef INET 38 #include <netinet/in.h> 39 #include <netinet/in_systm.h> 40 #include <netinet/in_var.h> 41 #include <netinet/ip.h> 42 #include <netinet/if_ether.h> 43 #endif 44 45 #if NBPFILTER > 0 46 #include <net/bpf.h> 47 #include <net/bpfdesc.h> 48 #endif 49 50 #include <machine/cpu.h> 51 #include <machine/intr.h> 52 #include <machine/pio.h> 53 54 #include <dev/isa/isavar.h> 55 #include <dev/isa/if_elreg.h> 56 57 /* for debugging convenience */ 58 #ifdef EL_DEBUG 59 #define dprintf(x) printf x 60 #else 61 #define dprintf(x) 62 #endif 63 64 /* 65 * per-line info and status 66 */ 67 struct el_softc { 68 struct device sc_dev; 69 void *sc_ih; 70 71 struct arpcom sc_arpcom; /* ethernet common */ 72 int sc_iobase; /* base I/O addr */ 73 }; 74 75 /* 76 * prototypes 77 */ 78 int elintr(void *); 79 void elinit(struct el_softc *); 80 int elioctl(struct ifnet *, u_long, caddr_t); 81 void elstart(struct ifnet *); 82 void elwatchdog(struct ifnet *); 83 void elreset(struct el_softc *); 84 void elstop(struct el_softc *); 85 static int el_xmit(struct el_softc *); 86 void elread(struct el_softc *, int); 87 struct mbuf *elget(struct el_softc *sc, int); 88 static inline void el_hardreset(struct el_softc *); 89 90 int elprobe(struct device *, void *, void *); 91 void elattach(struct device *, struct device *, void *); 92 93 struct cfattach el_ca = { 94 sizeof(struct el_softc), elprobe, elattach 95 }; 96 97 struct cfdriver el_cd = { 98 NULL, "el", DV_IFNET 99 }; 100 101 /* 102 * Probe routine. 103 * 104 * See if the card is there and at the right place. 105 * (XXX - cgd -- needs help) 106 */ 107 int 108 elprobe(parent, match, aux) 109 struct device *parent; 110 void *match, *aux; 111 { 112 struct el_softc *sc = match; 113 struct isa_attach_args *ia = aux; 114 int iobase = ia->ia_iobase; 115 u_char station_addr[ETHER_ADDR_LEN]; 116 int i; 117 118 /* First check the base. */ 119 if (iobase < 0x280 || iobase > 0x3f0) 120 return 0; 121 122 /* Grab some info for our structure. */ 123 sc->sc_iobase = iobase; 124 125 /* 126 * Now attempt to grab the station address from the PROM and see if it 127 * contains the 3com vendor code. 128 */ 129 dprintf(("Probing 3c501 at 0x%x...\n", iobase)); 130 131 /* Reset the board. */ 132 dprintf(("Resetting board...\n")); 133 outb(iobase+EL_AC, EL_AC_RESET); 134 delay(5); 135 outb(iobase+EL_AC, 0); 136 137 /* Now read the address. */ 138 dprintf(("Reading station address...\n")); 139 for (i = 0; i < ETHER_ADDR_LEN; i++) { 140 outb(iobase+EL_GPBL, i); 141 station_addr[i] = inb(iobase+EL_EAW); 142 } 143 dprintf(("Address is %s\n", ether_sprintf(station_addr))); 144 145 /* 146 * If the vendor code is ok, return a 1. We'll assume that whoever 147 * configured this system is right about the IRQ. 148 */ 149 if (station_addr[0] != 0x02 || station_addr[1] != 0x60 || 150 station_addr[2] != 0x8c) { 151 dprintf(("Bad vendor code.\n")); 152 return 0; 153 } 154 155 dprintf(("Vendor code ok.\n")); 156 /* Copy the station address into the arpcom structure. */ 157 bcopy(station_addr, sc->sc_arpcom.ac_enaddr, ETHER_ADDR_LEN); 158 159 ia->ia_iosize = 4; /* XXX */ 160 ia->ia_msize = 0; 161 return 1; 162 } 163 164 /* 165 * Attach the interface to the kernel data structures. By the time this is 166 * called, we know that the card exists at the given I/O address. We still 167 * assume that the IRQ given is correct. 168 */ 169 void 170 elattach(parent, self, aux) 171 struct device *parent, *self; 172 void *aux; 173 { 174 struct el_softc *sc = (void *)self; 175 struct isa_attach_args *ia = aux; 176 struct ifnet *ifp = &sc->sc_arpcom.ac_if; 177 178 dprintf(("Attaching %s...\n", sc->sc_dev.dv_xname)); 179 180 /* Stop the board. */ 181 elstop(sc); 182 183 /* Initialize ifnet structure. */ 184 bcopy(sc->sc_dev.dv_xname, ifp->if_xname, IFNAMSIZ); 185 ifp->if_softc = sc; 186 ifp->if_start = elstart; 187 ifp->if_ioctl = elioctl; 188 ifp->if_watchdog = elwatchdog; 189 ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_NOTRAILERS; 190 IFQ_SET_READY(&ifp->if_snd); 191 192 /* Now we can attach the interface. */ 193 dprintf(("Attaching interface...\n")); 194 if_attach(ifp); 195 ether_ifattach(ifp); 196 197 /* Print out some information for the user. */ 198 printf(": address %s\n", ether_sprintf(sc->sc_arpcom.ac_enaddr)); 199 200 sc->sc_ih = isa_intr_establish(ia->ia_ic, ia->ia_irq, IST_EDGE, 201 IPL_NET, elintr, sc, sc->sc_dev.dv_xname); 202 203 dprintf(("elattach() finished.\n")); 204 } 205 206 /* 207 * Reset interface. 208 */ 209 void 210 elreset(sc) 211 struct el_softc *sc; 212 { 213 int s; 214 215 dprintf(("elreset()\n")); 216 s = splnet(); 217 elstop(sc); 218 elinit(sc); 219 splx(s); 220 } 221 222 /* 223 * Stop interface. 224 */ 225 void 226 elstop(sc) 227 struct el_softc *sc; 228 { 229 230 outb(sc->sc_iobase+EL_AC, 0); 231 } 232 233 /* 234 * Do a hardware reset of the board, and upload the ethernet address again in 235 * case the board forgets. 236 */ 237 static inline void 238 el_hardreset(sc) 239 struct el_softc *sc; 240 { 241 int iobase = sc->sc_iobase; 242 int i; 243 244 outb(iobase+EL_AC, EL_AC_RESET); 245 delay(5); 246 outb(iobase+EL_AC, 0); 247 248 for (i = 0; i < ETHER_ADDR_LEN; i++) 249 outb(iobase+i, sc->sc_arpcom.ac_enaddr[i]); 250 } 251 252 /* 253 * Initialize interface. 254 */ 255 void 256 elinit(sc) 257 struct el_softc *sc; 258 { 259 struct ifnet *ifp = &sc->sc_arpcom.ac_if; 260 int iobase = sc->sc_iobase; 261 262 /* First, reset the board. */ 263 el_hardreset(sc); 264 265 /* Configure rx. */ 266 dprintf(("Configuring rx...\n")); 267 if (ifp->if_flags & IFF_PROMISC) 268 outb(iobase+EL_RXC, EL_RXC_AGF | EL_RXC_DSHORT | EL_RXC_DDRIB | EL_RXC_DOFLOW | EL_RXC_PROMISC); 269 else 270 outb(iobase+EL_RXC, EL_RXC_AGF | EL_RXC_DSHORT | EL_RXC_DDRIB | EL_RXC_DOFLOW | EL_RXC_ABROAD); 271 outb(iobase+EL_RBC, 0); 272 273 /* Configure TX. */ 274 dprintf(("Configuring tx...\n")); 275 outb(iobase+EL_TXC, 0); 276 277 /* Start reception. */ 278 dprintf(("Starting reception...\n")); 279 outb(iobase+EL_AC, EL_AC_IRQE | EL_AC_RX); 280 281 /* Set flags appropriately. */ 282 ifp->if_flags |= IFF_RUNNING; 283 ifp->if_flags &= ~IFF_OACTIVE; 284 285 /* And start output. */ 286 elstart(ifp); 287 } 288 289 /* 290 * Start output on interface. Get datagrams from the queue and output them, 291 * giving the receiver a chance between datagrams. Call only from splnet or 292 * interrupt level! 293 */ 294 void 295 elstart(ifp) 296 struct ifnet *ifp; 297 { 298 struct el_softc *sc = ifp->if_softc; 299 int iobase = sc->sc_iobase; 300 struct mbuf *m, *m0; 301 int s, i, off, retries; 302 303 dprintf(("elstart()...\n")); 304 s = splnet(); 305 306 /* Don't do anything if output is active. */ 307 if ((ifp->if_flags & IFF_OACTIVE) != 0) { 308 splx(s); 309 return; 310 } 311 312 ifp->if_flags |= IFF_OACTIVE; 313 314 /* 315 * The main loop. They warned me against endless loops, but would I 316 * listen? NOOO.... 317 */ 318 for (;;) { 319 /* Dequeue the next datagram. */ 320 IFQ_DEQUEUE(&ifp->if_snd, m0); 321 322 /* If there's nothing to send, return. */ 323 if (m0 == 0) 324 break; 325 326 #if NBPFILTER > 0 327 /* Give the packet to the bpf, if any. */ 328 if (ifp->if_bpf) 329 bpf_mtap(ifp->if_bpf, m0); 330 #endif 331 332 /* Disable the receiver. */ 333 outb(iobase+EL_AC, EL_AC_HOST); 334 outb(iobase+EL_RBC, 0); 335 336 /* Transfer datagram to board. */ 337 dprintf(("el: xfr pkt length=%d...\n", m0->m_pkthdr.len)); 338 off = EL_BUFSIZ - max(m0->m_pkthdr.len, ETHER_MIN_LEN); 339 outb(iobase+EL_GPBL, off); 340 outb(iobase+EL_GPBH, off >> 8); 341 342 /* Copy the datagram to the buffer. */ 343 for (m = m0; m != 0; m = m->m_next) 344 outsb(iobase+EL_BUF, mtod(m, caddr_t), m->m_len); 345 for (i = 0; 346 i < ETHER_MIN_LEN - ETHER_CRC_LEN - m0->m_pkthdr.len; i++) 347 outb(iobase+EL_BUF, 0); 348 349 m_freem(m0); 350 351 /* Now transmit the datagram. */ 352 retries = 0; 353 for (;;) { 354 outb(iobase+EL_GPBL, off); 355 outb(iobase+EL_GPBH, off >> 8); 356 if (el_xmit(sc)) { 357 ifp->if_oerrors++; 358 break; 359 } 360 /* Check out status. */ 361 i = inb(iobase+EL_TXS); 362 dprintf(("tx status=0x%x\n", i)); 363 if ((i & EL_TXS_READY) == 0) { 364 dprintf(("el: err txs=%x\n", i)); 365 if (i & (EL_TXS_COLL | EL_TXS_COLL16)) { 366 ifp->if_collisions++; 367 if ((i & EL_TXC_DCOLL16) == 0 && 368 retries < 15) { 369 retries++; 370 outb(iobase+EL_AC, EL_AC_HOST); 371 } 372 } else { 373 ifp->if_oerrors++; 374 break; 375 } 376 } else { 377 ifp->if_opackets++; 378 break; 379 } 380 } 381 382 /* 383 * Now give the card a chance to receive. 384 * Gotta love 3c501s... 385 */ 386 (void)inb(iobase+EL_AS); 387 outb(iobase+EL_AC, EL_AC_IRQE | EL_AC_RX); 388 splx(s); 389 /* Interrupt here. */ 390 s = splnet(); 391 } 392 393 (void)inb(iobase+EL_AS); 394 outb(iobase+EL_AC, EL_AC_IRQE | EL_AC_RX); 395 ifp->if_flags &= ~IFF_OACTIVE; 396 splx(s); 397 } 398 399 /* 400 * This function actually attempts to transmit a datagram downloaded to the 401 * board. Call at splnet or interrupt, after downloading data! Returns 0 on 402 * success, non-0 on failure. 403 */ 404 static int 405 el_xmit(sc) 406 struct el_softc *sc; 407 { 408 int iobase = sc->sc_iobase; 409 int i; 410 411 /* 412 * XXX 413 * This busy-waits for the tx completion. Can we get an interrupt 414 * instead? 415 */ 416 417 dprintf(("el: xmit...")); 418 outb(iobase+EL_AC, EL_AC_TXFRX); 419 i = 20000; 420 while ((inb(iobase+EL_AS) & EL_AS_TXBUSY) && (i > 0)) 421 i--; 422 if (i == 0) { 423 dprintf(("tx not ready\n")); 424 return -1; 425 } 426 dprintf(("%d cycles.\n", 20000 - i)); 427 return 0; 428 } 429 430 /* 431 * Controller interrupt. 432 */ 433 int 434 elintr(arg) 435 void *arg; 436 { 437 register struct el_softc *sc = arg; 438 int iobase = sc->sc_iobase; 439 int rxstat, len; 440 441 dprintf(("elintr: ")); 442 443 /* Check board status. */ 444 if ((inb(iobase+EL_AS) & EL_AS_RXBUSY) != 0) { 445 (void)inb(iobase+EL_RXC); 446 outb(iobase+EL_AC, EL_AC_IRQE | EL_AC_RX); 447 return 0; 448 } 449 450 for (;;) { 451 rxstat = inb(iobase+EL_RXS); 452 if (rxstat & EL_RXS_STALE) 453 break; 454 455 /* If there's an overflow, reinit the board. */ 456 if ((rxstat & EL_RXS_NOFLOW) == 0) { 457 dprintf(("overflow.\n")); 458 el_hardreset(sc); 459 /* Put board back into receive mode. */ 460 if (sc->sc_arpcom.ac_if.if_flags & IFF_PROMISC) 461 outb(iobase+EL_RXC, EL_RXC_AGF | EL_RXC_DSHORT | EL_RXC_DDRIB | EL_RXC_DOFLOW | EL_RXC_PROMISC); 462 else 463 outb(iobase+EL_RXC, EL_RXC_AGF | EL_RXC_DSHORT | EL_RXC_DDRIB | EL_RXC_DOFLOW | EL_RXC_ABROAD); 464 (void)inb(iobase+EL_AS); 465 outb(iobase+EL_RBC, 0); 466 break; 467 } 468 469 /* Incoming packet. */ 470 len = inb(iobase+EL_RBL); 471 len |= inb(iobase+EL_RBH) << 8; 472 dprintf(("receive len=%d rxstat=%x ", len, rxstat)); 473 outb(iobase+EL_AC, EL_AC_HOST); 474 475 /* Pass data up to upper levels. */ 476 elread(sc, len); 477 478 /* Is there another packet? */ 479 if ((inb(iobase+EL_AS) & EL_AS_RXBUSY) != 0) 480 break; 481 482 dprintf(("<rescan> ")); 483 } 484 485 (void)inb(iobase+EL_RXC); 486 outb(iobase+EL_AC, EL_AC_IRQE | EL_AC_RX); 487 return 1; 488 } 489 490 /* 491 * Pass a packet to the higher levels. 492 */ 493 void 494 elread(sc, len) 495 register struct el_softc *sc; 496 int len; 497 { 498 struct ifnet *ifp = &sc->sc_arpcom.ac_if; 499 struct mbuf *m; 500 501 if (len <= sizeof(struct ether_header) || 502 len > ETHER_MAX_LEN) { 503 printf("%s: invalid packet size %d; dropping\n", 504 sc->sc_dev.dv_xname, len); 505 ifp->if_ierrors++; 506 return; 507 } 508 509 /* Pull packet off interface. */ 510 m = elget(sc, len); 511 if (m == 0) { 512 ifp->if_ierrors++; 513 return; 514 } 515 516 ifp->if_ipackets++; 517 518 #if NBPFILTER > 0 519 /* 520 * Check if there's a BPF listener on this interface. 521 * If so, hand off the raw packet to BPF. 522 */ 523 if (ifp->if_bpf) 524 bpf_mtap(ifp->if_bpf, m); 525 #endif 526 527 ether_input_mbuf(ifp, m); 528 } 529 530 /* 531 * Pull read data off a interface. Len is length of data, with local net 532 * header stripped. We copy the data into mbufs. When full cluster sized 533 * units are present we copy into clusters. 534 */ 535 struct mbuf * 536 elget(sc, totlen) 537 struct el_softc *sc; 538 int totlen; 539 { 540 struct ifnet *ifp = &sc->sc_arpcom.ac_if; 541 int iobase = sc->sc_iobase; 542 struct mbuf *top, **mp, *m; 543 int len; 544 545 MGETHDR(m, M_DONTWAIT, MT_DATA); 546 if (m == 0) 547 return 0; 548 m->m_pkthdr.rcvif = ifp; 549 m->m_pkthdr.len = totlen; 550 len = MHLEN; 551 top = 0; 552 mp = ⊤ 553 554 outb(iobase+EL_GPBL, 0); 555 outb(iobase+EL_GPBH, 0); 556 557 while (totlen > 0) { 558 if (top) { 559 MGET(m, M_DONTWAIT, MT_DATA); 560 if (m == 0) { 561 m_freem(top); 562 return 0; 563 } 564 len = MLEN; 565 } 566 if (totlen >= MINCLSIZE) { 567 MCLGET(m, M_DONTWAIT); 568 if (m->m_flags & M_EXT) 569 len = MCLBYTES; 570 } 571 m->m_len = len = min(totlen, len); 572 insb(iobase+EL_BUF, mtod(m, caddr_t), len); 573 totlen -= len; 574 *mp = m; 575 mp = &m->m_next; 576 } 577 578 outb(iobase+EL_RBC, 0); 579 outb(iobase+EL_AC, EL_AC_RX); 580 581 return top; 582 } 583 584 /* 585 * Process an ioctl request. This code needs some work - it looks pretty ugly. 586 */ 587 int 588 elioctl(ifp, cmd, data) 589 register struct ifnet *ifp; 590 u_long cmd; 591 caddr_t data; 592 { 593 struct el_softc *sc = ifp->if_softc; 594 struct ifaddr *ifa = (struct ifaddr *)data; 595 int s, error = 0; 596 597 s = splnet(); 598 599 if ((error = ether_ioctl(ifp, &sc->sc_arpcom, cmd, data)) > 0) { 600 splx(s); 601 return error; 602 } 603 604 switch (cmd) { 605 606 case SIOCSIFADDR: 607 ifp->if_flags |= IFF_UP; 608 609 switch (ifa->ifa_addr->sa_family) { 610 #ifdef INET 611 case AF_INET: 612 elinit(sc); 613 arp_ifinit(&sc->sc_arpcom, ifa); 614 break; 615 #endif 616 default: 617 elinit(sc); 618 break; 619 } 620 break; 621 622 case SIOCSIFFLAGS: 623 if ((ifp->if_flags & IFF_UP) == 0 && 624 (ifp->if_flags & IFF_RUNNING) != 0) { 625 /* 626 * If interface is marked down and it is running, then 627 * stop it. 628 */ 629 elstop(sc); 630 ifp->if_flags &= ~IFF_RUNNING; 631 } else if ((ifp->if_flags & IFF_UP) != 0 && 632 (ifp->if_flags & IFF_RUNNING) == 0) { 633 /* 634 * If interface is marked up and it is stopped, then 635 * start it. 636 */ 637 elinit(sc); 638 } else { 639 /* 640 * Some other important flag might have changed, so 641 * reset. 642 */ 643 elreset(sc); 644 } 645 break; 646 647 default: 648 error = EINVAL; 649 break; 650 } 651 652 splx(s); 653 return error; 654 } 655 656 /* 657 * Device timeout routine. 658 */ 659 void 660 elwatchdog(ifp) 661 struct ifnet *ifp; 662 { 663 struct el_softc *sc = ifp->if_softc; 664 665 log(LOG_ERR, "%s: device timeout\n", sc->sc_dev.dv_xname); 666 sc->sc_arpcom.ac_if.if_oerrors++; 667 668 elreset(sc); 669 } 670