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