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