1 /* $NetBSD: lemac.c,v 1.26 2004/10/30 18:08:37 thorpej Exp $ */ 2 3 /*- 4 * Copyright (c) 1994, 1995, 1997 Matt Thomas <matt@3am-software.com> 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. The name of the author may not be used to endorse or promote products 13 * derived from this software without specific prior written permission 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 */ 26 27 /* 28 * DEC EtherWORKS 3 Ethernet Controllers 29 * 30 * Written by Matt Thomas 31 * BPF support code stolen directly from if_ec.c 32 * 33 * This driver supports the LEMAC DE203/204/205 cards. 34 */ 35 36 #include <sys/cdefs.h> 37 __KERNEL_RCSID(0, "$NetBSD: lemac.c,v 1.26 2004/10/30 18:08:37 thorpej Exp $"); 38 39 #include "opt_inet.h" 40 #include "opt_ns.h" 41 #include "rnd.h" 42 43 #include <sys/param.h> 44 #include <sys/systm.h> 45 #include <sys/mbuf.h> 46 #include <sys/protosw.h> 47 #include <sys/socket.h> 48 #include <sys/sockio.h> 49 #include <sys/errno.h> 50 #include <sys/malloc.h> 51 #include <sys/device.h> 52 #if NRND > 0 53 #include <sys/rnd.h> 54 #endif 55 56 #include <net/if.h> 57 #include <net/if_types.h> 58 #include <net/if_dl.h> 59 #include <net/route.h> 60 #include <net/if_ether.h> 61 #include <net/if_media.h> 62 63 #ifdef INET 64 #include <netinet/in.h> 65 #include <netinet/in_systm.h> 66 #include <netinet/in_var.h> 67 #include <netinet/ip.h> 68 #include <netinet/if_inarp.h> 69 #endif 70 71 #ifdef NS 72 #include <netns/ns.h> 73 #include <netns/ns_if.h> 74 #endif 75 76 #include <machine/bus.h> 77 78 #include <dev/ic/lemacreg.h> 79 #include <dev/ic/lemacvar.h> 80 #if 0 81 #include <i386/isa/decether.h> 82 #endif 83 84 #include <uvm/uvm_extern.h> 85 86 #include "bpfilter.h" 87 #if NBPFILTER > 0 88 #include <net/bpf.h> 89 #endif 90 91 static void lemac_init(lemac_softc_t *sc); 92 static void lemac_ifstart(struct ifnet *ifp); 93 static void lemac_reset(lemac_softc_t *sc); 94 static void lemac_rne_intr(lemac_softc_t *sc); 95 static void lemac_tne_intr(lemac_softc_t *sc); 96 static void lemac_txd_intr(lemac_softc_t *sc, unsigned cs_value); 97 static void lemac_rxd_intr(lemac_softc_t *sc, unsigned cs_value); 98 static int lemac_read_eeprom(lemac_softc_t *sc); 99 static void lemac_init_adapmem(lemac_softc_t *sc); 100 101 static const u_int16_t lemac_allmulti_mctbl[LEMAC_MCTBL_SIZE/sizeof(u_int16_t)] = { 102 0xFFFFU, 0xFFFFU, 0xFFFFU, 0xFFFFU, 103 0xFFFFU, 0xFFFFU, 0xFFFFU, 0xFFFFU, 104 0xFFFFU, 0xFFFFU, 0xFFFFU, 0xFFFFU, 105 0xFFFFU, 0xFFFFU, 0xFFFFU, 0xFFFFU, 106 0xFFFFU, 0xFFFFU, 0xFFFFU, 0xFFFFU, 107 0xFFFFU, 0xFFFFU, 0xFFFFU, 0xFFFFU, 108 0xFFFFU, 0xFFFFU, 0xFFFFU, 0xFFFFU, 109 0xFFFFU, 0xFFFFU, 0xFFFFU, 0xFFFFU, 110 }; 111 112 /* 113 * Some tuning/monitoring variables. 114 */ 115 unsigned lemac_txmax = 16; 116 117 static void 118 lemac_rxd_intr( 119 lemac_softc_t *sc, 120 unsigned cs_value) 121 { 122 /* 123 * Handle CS_RXD (Receiver disabled) here. 124 * 125 * Check Free Memory Queue Count. If not equal to zero 126 * then just turn Receiver back on. If it is equal to 127 * zero then check to see if transmitter is disabled. 128 * Process transmit TXD loop once more. If all else 129 * fails then do software init (0xC0 to EEPROM Init) 130 * and rebuild Free Memory Queue. 131 */ 132 133 sc->sc_cntrs.cntr_rxd_intrs++; 134 135 /* 136 * Re-enable Receiver. 137 */ 138 139 cs_value &= ~LEMAC_CS_RXD; 140 LEMAC_OUTB(sc, LEMAC_REG_CS, cs_value); 141 142 if (LEMAC_INB(sc, LEMAC_REG_FMC) > 0) 143 return; 144 145 if (cs_value & LEMAC_CS_TXD) 146 lemac_txd_intr(sc, cs_value); 147 148 if ((LEMAC_INB(sc, LEMAC_REG_CS) & LEMAC_CS_RXD) == 0) 149 return; 150 151 printf("%s: fatal RXD error, attempting recovery\n", sc->sc_if.if_xname); 152 153 lemac_reset(sc); 154 if (sc->sc_if.if_flags & IFF_UP) { 155 lemac_init(sc); 156 return; 157 } 158 159 /* 160 * Error during initialization. Mark card as disabled. 161 */ 162 printf("%s: recovery failed -- board disabled\n", sc->sc_if.if_xname); 163 } 164 165 static void 166 lemac_tne_intr( 167 lemac_softc_t *sc) 168 { 169 unsigned txcount = LEMAC_INB(sc, LEMAC_REG_TDC); 170 171 sc->sc_cntrs.cntr_tne_intrs++; 172 while (txcount-- > 0) { 173 unsigned txsts = LEMAC_INB(sc, LEMAC_REG_TDQ); 174 sc->sc_if.if_opackets++; /* another one done */ 175 if ((txsts & (LEMAC_TDQ_LCL|LEMAC_TDQ_NCL)) 176 || (txsts & LEMAC_TDQ_COL) == LEMAC_TDQ_EXCCOL) { 177 if (txsts & LEMAC_TDQ_NCL) 178 sc->sc_flags &= ~LEMAC_LINKUP; 179 sc->sc_if.if_oerrors++; 180 } else { 181 sc->sc_flags |= LEMAC_LINKUP; 182 if ((txsts & LEMAC_TDQ_COL) != LEMAC_TDQ_NOCOL) 183 sc->sc_if.if_collisions++; 184 } 185 } 186 sc->sc_if.if_flags &= ~IFF_OACTIVE; 187 lemac_ifstart(&sc->sc_if); 188 } 189 190 static void 191 lemac_txd_intr( 192 lemac_softc_t *sc, 193 unsigned cs_value) 194 { 195 /* 196 * Read transmit status, remove transmit buffer from 197 * transmit queue and place on free memory queue, 198 * then reset transmitter. 199 * Increment appropriate counters. 200 */ 201 202 sc->sc_cntrs.cntr_txd_intrs++; 203 if (sc->sc_txctl & LEMAC_TX_STP) { 204 sc->sc_if.if_oerrors++; 205 /* return page to free queue */ 206 LEMAC_OUTB(sc, LEMAC_REG_FMQ, LEMAC_INB(sc, LEMAC_REG_TDQ)); 207 } 208 209 /* Turn back on transmitter if disabled */ 210 LEMAC_OUTB(sc, LEMAC_REG_CS, cs_value & ~LEMAC_CS_TXD); 211 sc->sc_if.if_flags &= ~IFF_OACTIVE; 212 } 213 214 static int 215 lemac_read_eeprom( 216 lemac_softc_t *sc) 217 { 218 int word_off, cksum; 219 220 u_char *ep; 221 222 cksum = 0; 223 ep = sc->sc_eeprom; 224 for (word_off = 0; word_off < LEMAC_EEP_SIZE / 2; word_off++) { 225 LEMAC_OUTB(sc, LEMAC_REG_PI1, word_off); 226 LEMAC_OUTB(sc, LEMAC_REG_IOP, LEMAC_IOP_EEREAD); 227 228 DELAY(LEMAC_EEP_DELAY); 229 230 *ep = LEMAC_INB(sc, LEMAC_REG_EE1); cksum += *ep++; 231 *ep = LEMAC_INB(sc, LEMAC_REG_EE2); cksum += *ep++; 232 } 233 234 /* 235 * Set up Transmit Control Byte for use later during transmit. 236 */ 237 238 sc->sc_txctl |= LEMAC_TX_FLAGS; 239 240 if ((sc->sc_eeprom[LEMAC_EEP_SWFLAGS] & LEMAC_EEP_SW_SQE) == 0) 241 sc->sc_txctl &= ~LEMAC_TX_SQE; 242 243 if (sc->sc_eeprom[LEMAC_EEP_SWFLAGS] & LEMAC_EEP_SW_LAB) 244 sc->sc_txctl |= LEMAC_TX_LAB; 245 246 memcpy(sc->sc_prodname, &sc->sc_eeprom[LEMAC_EEP_PRDNM], LEMAC_EEP_PRDNMSZ); 247 sc->sc_prodname[LEMAC_EEP_PRDNMSZ] = '\0'; 248 249 return cksum % 256; 250 } 251 252 static void 253 lemac_init_adapmem( 254 lemac_softc_t *sc) 255 { 256 int pg, conf; 257 258 conf = LEMAC_INB(sc, LEMAC_REG_CNF); 259 260 if ((sc->sc_eeprom[LEMAC_EEP_SETUP] & LEMAC_EEP_ST_DRAM) == 0) { 261 sc->sc_lastpage = 63; 262 conf &= ~LEMAC_CNF_DRAM; 263 } else { 264 sc->sc_lastpage = 127; 265 conf |= LEMAC_CNF_DRAM; 266 } 267 268 LEMAC_OUTB(sc, LEMAC_REG_CNF, conf); 269 270 for (pg = 1; pg <= sc->sc_lastpage; pg++) 271 LEMAC_OUTB(sc, LEMAC_REG_FMQ, pg); 272 } 273 274 static void 275 lemac_input( 276 lemac_softc_t *sc, 277 bus_addr_t offset, 278 size_t length) 279 { 280 struct ether_header eh; 281 struct mbuf *m; 282 283 if (length - sizeof(eh) > ETHERMTU 284 || length - sizeof(eh) < ETHERMIN) { 285 sc->sc_if.if_ierrors++; 286 return; 287 } 288 if (LEMAC_USE_PIO_MODE(sc)) { 289 LEMAC_INSB(sc, LEMAC_REG_DAT, sizeof(eh), (void *) &eh); 290 } else { 291 LEMAC_GETBUF16(sc, offset, sizeof(eh) / 2, (void *) &eh); 292 } 293 294 MGETHDR(m, M_DONTWAIT, MT_DATA); 295 if (m == NULL) { 296 sc->sc_if.if_ierrors++; 297 return; 298 } 299 if (length + 2 > MHLEN) { 300 MCLGET(m, M_DONTWAIT); 301 if ((m->m_flags & M_EXT) == 0) { 302 m_free(m); 303 sc->sc_if.if_ierrors++; 304 return; 305 } 306 } 307 m->m_data += 2; 308 memcpy(m->m_data, (caddr_t)&eh, sizeof(eh)); 309 if (LEMAC_USE_PIO_MODE(sc)) { 310 LEMAC_INSB(sc, LEMAC_REG_DAT, length - sizeof(eh), 311 mtod(m, caddr_t) + sizeof(eh)); 312 } else { 313 LEMAC_GETBUF16(sc, offset + sizeof(eh), (length - sizeof(eh)) / 2, 314 (void *) (mtod(m, caddr_t) + sizeof(eh))); 315 if (length & 1) 316 m->m_data[length - 1] = LEMAC_GET8(sc, offset + length - 1); 317 } 318 #if NBPFILTER > 0 319 if (sc->sc_if.if_bpf != NULL) { 320 m->m_pkthdr.len = m->m_len = length; 321 bpf_mtap(sc->sc_if.if_bpf, m); 322 } 323 /* 324 * If this is single cast but not to us 325 * drop it! 326 */ 327 if ((eh.ether_dhost[0] & 1) == 0 328 && !LEMAC_ADDREQUAL(eh.ether_dhost, sc->sc_enaddr)) { 329 m_freem(m); 330 return; 331 } 332 #endif 333 m->m_pkthdr.len = m->m_len = length; 334 m->m_pkthdr.rcvif = &sc->sc_if; 335 (*sc->sc_if.if_input)(&sc->sc_if, m); 336 } 337 338 static void 339 lemac_rne_intr( 340 lemac_softc_t *sc) 341 { 342 int rxcount; 343 344 sc->sc_cntrs.cntr_rne_intrs++; 345 rxcount = LEMAC_INB(sc, LEMAC_REG_RQC); 346 while (rxcount--) { 347 unsigned rxpg = LEMAC_INB(sc, LEMAC_REG_RQ); 348 u_int32_t rxlen; 349 350 sc->sc_if.if_ipackets++; 351 if (LEMAC_USE_PIO_MODE(sc)) { 352 LEMAC_OUTB(sc, LEMAC_REG_IOP, rxpg); 353 LEMAC_OUTB(sc, LEMAC_REG_PI1, 0); 354 LEMAC_OUTB(sc, LEMAC_REG_PI2, 0); 355 LEMAC_INSB(sc, LEMAC_REG_DAT, sizeof(rxlen), (void *) &rxlen); 356 } else { 357 LEMAC_OUTB(sc, LEMAC_REG_MPN, rxpg); 358 rxlen = LEMAC_GET32(sc, 0); 359 } 360 if (rxlen & LEMAC_RX_OK) { 361 sc->sc_flags |= LEMAC_LINKUP; 362 /* 363 * Get receive length - subtract out checksum. 364 */ 365 rxlen = ((rxlen >> 8) & 0x7FF) - 4; 366 lemac_input(sc, sizeof(rxlen), rxlen); 367 } else { 368 sc->sc_if.if_ierrors++; 369 } 370 LEMAC_OUTB(sc, LEMAC_REG_FMQ, rxpg); /* Return this page to Free Memory Queue */ 371 } /* end while (recv_count--) */ 372 373 return; 374 } 375 376 /* 377 * This is the standard method of reading the DEC Address ROMS. 378 * I don't understand it but it does work. 379 */ 380 static int 381 lemac_read_macaddr( 382 unsigned char *hwaddr, 383 const bus_space_tag_t iot, 384 const bus_space_handle_t ioh, 385 const bus_addr_t ioreg, 386 int skippat) 387 { 388 int cksum, rom_cksum; 389 unsigned char addrbuf[6]; 390 391 if (!skippat) { 392 int idx, idx2, found, octet; 393 static u_char testpat[] = { 0xFF, 0, 0x55, 0xAA, 0xFF, 0, 0x55, 0xAA }; 394 idx2 = found = 0; 395 396 for (idx = 0; idx < 32; idx++) { 397 octet = bus_space_read_1(iot, ioh, ioreg); 398 399 if (octet == testpat[idx2]) { 400 if (++idx2 == sizeof(testpat)) { 401 ++found; 402 break; 403 } 404 } else { 405 idx2 = 0; 406 } 407 } 408 409 if (!found) 410 return -1; 411 } 412 413 if (hwaddr == NULL) 414 hwaddr = addrbuf; 415 416 cksum = 0; 417 hwaddr[0] = bus_space_read_1(iot, ioh, ioreg); 418 hwaddr[1] = bus_space_read_1(iot, ioh, ioreg); 419 420 /* hardware address can't be multicast */ 421 if (hwaddr[0] & 1) 422 return -1; 423 424 cksum = *(u_short *) &hwaddr[0]; 425 426 hwaddr[2] = bus_space_read_1(iot, ioh, ioreg); 427 hwaddr[3] = bus_space_read_1(iot, ioh, ioreg); 428 cksum *= 2; 429 if (cksum > 65535) cksum -= 65535; 430 cksum += *(u_short *) &hwaddr[2]; 431 if (cksum > 65535) cksum -= 65535; 432 433 hwaddr[4] = bus_space_read_1(iot, ioh, ioreg); 434 hwaddr[5] = bus_space_read_1(iot, ioh, ioreg); 435 cksum *= 2; 436 if (cksum > 65535) cksum -= 65535; 437 cksum += *(u_short *) &hwaddr[4]; 438 if (cksum >= 65535) cksum -= 65535; 439 440 /* 00-00-00 is an illegal OUI */ 441 if (hwaddr[0] == 0 && hwaddr[1] == 0 && hwaddr[2] == 0) 442 return -1; 443 444 rom_cksum = bus_space_read_1(iot, ioh, ioreg); 445 rom_cksum |= bus_space_read_1(iot, ioh, ioreg) << 8; 446 447 if (cksum != rom_cksum) 448 return -1; 449 return 0; 450 } 451 452 static void 453 lemac_multicast_op( 454 u_int16_t *mctbl, 455 const u_char *mca, 456 int enable) 457 { 458 u_int idx, bit, crc; 459 460 crc = ether_crc32_le(mca, ETHER_ADDR_LEN); 461 462 /* 463 * The following two lines convert the N bit index into a longword index 464 * and a longword mask. 465 */ 466 #if LEMAC_MCTBL_BITS < 0 467 crc >>= (32 + LEMAC_MCTBL_BITS); 468 crc &= (1 << -LEMAC_MCTBL_BITS) - 1; 469 #else 470 crc &= (1 << LEMAC_MCTBL_BITS) - 1; 471 #endif 472 bit = 1 << (crc & 0x0F); 473 idx = crc >> 4; 474 475 /* 476 * Set or clear hash filter bit in our table. 477 */ 478 if (enable) { 479 mctbl[idx] |= bit; /* Set Bit */ 480 } else { 481 mctbl[idx] &= ~bit; /* Clear Bit */ 482 } 483 } 484 485 static void 486 lemac_multicast_filter( 487 lemac_softc_t *sc) 488 { 489 struct ether_multistep step; 490 struct ether_multi *enm; 491 492 memset(sc->sc_mctbl, 0, LEMAC_MCTBL_BITS / 8); 493 494 lemac_multicast_op(sc->sc_mctbl, etherbroadcastaddr, TRUE); 495 496 ETHER_FIRST_MULTI(step, &sc->sc_ec, enm); 497 while (enm != NULL) { 498 if (!LEMAC_ADDREQUAL(enm->enm_addrlo, enm->enm_addrhi)) { 499 sc->sc_flags |= LEMAC_ALLMULTI; 500 sc->sc_if.if_flags |= IFF_ALLMULTI; 501 return; 502 } 503 lemac_multicast_op(sc->sc_mctbl, enm->enm_addrlo, TRUE); 504 ETHER_NEXT_MULTI(step, enm); 505 } 506 sc->sc_flags &= ~LEMAC_ALLMULTI; 507 sc->sc_if.if_flags &= ~IFF_ALLMULTI; 508 } 509 510 /* 511 * Do a hard reset of the board; 512 */ 513 static void 514 lemac_reset( 515 lemac_softc_t * const sc) 516 { 517 unsigned data; 518 519 /* 520 * Initialize board.. 521 */ 522 sc->sc_flags &= ~LEMAC_LINKUP; 523 sc->sc_if.if_flags &= ~IFF_OACTIVE; 524 LEMAC_INTR_DISABLE(sc); 525 526 LEMAC_OUTB(sc, LEMAC_REG_IOP, LEMAC_IOP_EEINIT); 527 DELAY(LEMAC_EEP_DELAY); 528 529 /* 530 * Read EEPROM information. NOTE - the placement of this function 531 * is important because functions hereafter may rely on information 532 * read from the EEPROM. 533 */ 534 if ((data = lemac_read_eeprom(sc)) != LEMAC_EEP_CKSUM) { 535 printf("%s: reset: EEPROM checksum failed (0x%x)\n", 536 sc->sc_if.if_xname, data); 537 return; 538 } 539 540 /* 541 * Update the control register to reflect the media choice 542 */ 543 data = LEMAC_INB(sc, LEMAC_REG_CTL); 544 if ((data & (LEMAC_CTL_APD|LEMAC_CTL_PSL)) != sc->sc_ctlmode) { 545 data &= ~(LEMAC_CTL_APD|LEMAC_CTL_PSL); 546 data |= sc->sc_ctlmode; 547 LEMAC_OUTB(sc, LEMAC_REG_CTL, data); 548 } 549 550 /* 551 * Force to 2K mode if not already configured. 552 */ 553 554 data = LEMAC_INB(sc, LEMAC_REG_MBR); 555 if (LEMAC_IS_2K_MODE(data)) { 556 sc->sc_flags |= LEMAC_2K_MODE; 557 } else if (LEMAC_IS_64K_MODE(data)) { 558 data = (((data * 2) & 0xF) << 4); 559 sc->sc_flags |= LEMAC_WAS_64K_MODE; 560 LEMAC_OUTB(sc, LEMAC_REG_MBR, data); 561 } else if (LEMAC_IS_32K_MODE(data)) { 562 data = ((data & 0xF) << 4); 563 sc->sc_flags |= LEMAC_WAS_32K_MODE; 564 LEMAC_OUTB(sc, LEMAC_REG_MBR, data); 565 } else { 566 sc->sc_flags |= LEMAC_PIO_MODE; 567 /* PIO mode */ 568 } 569 570 /* 571 * Initialize Free Memory Queue, Init mcast table with broadcast. 572 */ 573 574 lemac_init_adapmem(sc); 575 sc->sc_flags |= LEMAC_ALIVE; 576 } 577 578 static void 579 lemac_init( 580 lemac_softc_t * const sc) 581 { 582 if ((sc->sc_flags & LEMAC_ALIVE) == 0) 583 return; 584 585 /* 586 * If the interface has the up flag 587 */ 588 if (sc->sc_if.if_flags & IFF_UP) { 589 int saved_cs = LEMAC_INB(sc, LEMAC_REG_CS); 590 LEMAC_OUTB(sc, LEMAC_REG_CS, saved_cs | (LEMAC_CS_TXD | LEMAC_CS_RXD)); 591 LEMAC_OUTB(sc, LEMAC_REG_PA0, sc->sc_enaddr[0]); 592 LEMAC_OUTB(sc, LEMAC_REG_PA1, sc->sc_enaddr[1]); 593 LEMAC_OUTB(sc, LEMAC_REG_PA2, sc->sc_enaddr[2]); 594 LEMAC_OUTB(sc, LEMAC_REG_PA3, sc->sc_enaddr[3]); 595 LEMAC_OUTB(sc, LEMAC_REG_PA4, sc->sc_enaddr[4]); 596 LEMAC_OUTB(sc, LEMAC_REG_PA5, sc->sc_enaddr[5]); 597 598 LEMAC_OUTB(sc, LEMAC_REG_IC, LEMAC_INB(sc, LEMAC_REG_IC) | LEMAC_IC_IE); 599 600 if (sc->sc_if.if_flags & IFF_PROMISC) { 601 LEMAC_OUTB(sc, LEMAC_REG_CS, LEMAC_CS_MCE | LEMAC_CS_PME); 602 } else { 603 LEMAC_INTR_DISABLE(sc); 604 lemac_multicast_filter(sc); 605 if (sc->sc_flags & LEMAC_ALLMULTI) 606 memcpy(sc->sc_mctbl, lemac_allmulti_mctbl, 607 sizeof(sc->sc_mctbl)); 608 if (LEMAC_USE_PIO_MODE(sc)) { 609 LEMAC_OUTB(sc, LEMAC_REG_IOP, 0); 610 LEMAC_OUTB(sc, LEMAC_REG_PI1, LEMAC_MCTBL_OFF & 0xFF); 611 LEMAC_OUTB(sc, LEMAC_REG_PI2, LEMAC_MCTBL_OFF >> 8); 612 LEMAC_OUTSB(sc, LEMAC_REG_DAT, sizeof(sc->sc_mctbl), (void *) sc->sc_mctbl); 613 } else { 614 LEMAC_OUTB(sc, LEMAC_REG_MPN, 0); 615 LEMAC_PUTBUF8(sc, LEMAC_MCTBL_OFF, sizeof(sc->sc_mctbl), (void *) sc->sc_mctbl); 616 } 617 618 LEMAC_OUTB(sc, LEMAC_REG_CS, LEMAC_CS_MCE); 619 } 620 621 LEMAC_OUTB(sc, LEMAC_REG_CTL, LEMAC_INB(sc, LEMAC_REG_CTL) ^ LEMAC_CTL_LED); 622 623 LEMAC_INTR_ENABLE(sc); 624 sc->sc_if.if_flags |= IFF_RUNNING; 625 lemac_ifstart(&sc->sc_if); 626 } else { 627 LEMAC_OUTB(sc, LEMAC_REG_CS, LEMAC_CS_RXD|LEMAC_CS_TXD); 628 629 LEMAC_INTR_DISABLE(sc); 630 sc->sc_if.if_flags &= ~IFF_RUNNING; 631 } 632 } 633 634 static void 635 lemac_ifstart( 636 struct ifnet *ifp) 637 { 638 lemac_softc_t * const sc = LEMAC_IFP_TO_SOFTC(ifp); 639 640 if ((ifp->if_flags & IFF_RUNNING) == 0) 641 return; 642 643 LEMAC_INTR_DISABLE(sc); 644 645 for (;;) { 646 struct mbuf *m; 647 struct mbuf *m0; 648 int tx_pg; 649 650 IFQ_POLL(&ifp->if_snd, m); 651 if (m == NULL) 652 break; 653 654 if ((sc->sc_csr.csr_tqc = LEMAC_INB(sc, LEMAC_REG_TQC)) >= lemac_txmax) { 655 sc->sc_cntrs.cntr_txfull++; 656 ifp->if_flags |= IFF_OACTIVE; 657 break; 658 } 659 660 /* 661 * get free memory page 662 */ 663 tx_pg = sc->sc_csr.csr_fmq = LEMAC_INB(sc, LEMAC_REG_FMQ); 664 /* 665 * Check for good transmit page. 666 */ 667 if (tx_pg == 0 || tx_pg > sc->sc_lastpage) { 668 sc->sc_cntrs.cntr_txnospc++; 669 ifp->if_flags |= IFF_OACTIVE; 670 break; 671 } 672 673 IFQ_DEQUEUE(&ifp->if_snd, m); 674 675 /* 676 * The first four bytes of each transmit buffer are for 677 * control information. The first byte is the control 678 * byte, then the length (why not word aligned?), then 679 * the offset to the buffer. 680 */ 681 682 if (LEMAC_USE_PIO_MODE(sc)) { 683 LEMAC_OUTB(sc, LEMAC_REG_IOP, tx_pg); /* Shift 2K window. */ 684 LEMAC_OUTB(sc, LEMAC_REG_PI1, 0); 685 LEMAC_OUTB(sc, LEMAC_REG_PI2, 0); 686 LEMAC_OUTB(sc, LEMAC_REG_DAT, sc->sc_txctl); 687 LEMAC_OUTB(sc, LEMAC_REG_DAT, (m->m_pkthdr.len >> 0) & 0xFF); 688 LEMAC_OUTB(sc, LEMAC_REG_DAT, (m->m_pkthdr.len >> 8) & 0xFF); 689 LEMAC_OUTB(sc, LEMAC_REG_DAT, LEMAC_TX_HDRSZ); 690 for (m0 = m; m0 != NULL; m0 = m0->m_next) 691 LEMAC_OUTSB(sc, LEMAC_REG_DAT, m0->m_len, m0->m_data); 692 } else { 693 bus_size_t txoff = /* (mtod(m, u_int32_t) & (sizeof(u_int32_t) - 1)) + */ LEMAC_TX_HDRSZ; 694 LEMAC_OUTB(sc, LEMAC_REG_MPN, tx_pg); /* Shift 2K window. */ 695 LEMAC_PUT8(sc, 0, sc->sc_txctl); 696 LEMAC_PUT8(sc, 1, (m->m_pkthdr.len >> 0) & 0xFF); 697 LEMAC_PUT8(sc, 2, (m->m_pkthdr.len >> 8) & 0xFF); 698 LEMAC_PUT8(sc, 3, txoff); 699 700 /* 701 * Copy the packet to the board 702 */ 703 for (m0 = m; m0 != NULL; m0 = m0->m_next) { 704 #if 0 705 LEMAC_PUTBUF8(sc, txoff, m0->m_len, m0->m_data); 706 txoff += m0->m_len; 707 #else 708 const u_int8_t *cp = m0->m_data; 709 int len = m0->m_len; 710 #if 0 711 if ((txoff & 3) == (((long)cp) & 3) && len >= 4) { 712 if (txoff & 3) { 713 int alen = (~txoff & 3); 714 LEMAC_PUTBUF8(sc, txoff, alen, cp); 715 cp += alen; txoff += alen; len -= alen; 716 } 717 if (len >= 4) { 718 LEMAC_PUTBUF32(sc, txoff, len / 4, cp); 719 cp += len & ~3; txoff += len & ~3; len &= 3; 720 } 721 } 722 #endif 723 if ((txoff & 1) == (((long)cp) & 1) && len >= 2) { 724 if (txoff & 1) { 725 int alen = (~txoff & 1); 726 LEMAC_PUTBUF8(sc, txoff, alen, cp); 727 cp += alen; txoff += alen; len -= alen; 728 } 729 if (len >= 2) { 730 LEMAC_PUTBUF16(sc, txoff, len / 2, (void *) cp); 731 cp += len & ~1; txoff += len & ~1; len &= 1; 732 } 733 } 734 if (len > 0) { 735 LEMAC_PUTBUF8(sc, txoff, len, cp); 736 txoff += len; 737 } 738 #endif 739 } 740 } 741 742 LEMAC_OUTB(sc, LEMAC_REG_TQ, tx_pg); /* tell chip to transmit this packet */ 743 #if NBPFILTER > 0 744 if (sc->sc_if.if_bpf != NULL) 745 bpf_mtap(sc->sc_if.if_bpf, m); 746 #endif 747 m_freem(m); /* free the mbuf */ 748 } 749 LEMAC_INTR_ENABLE(sc); 750 } 751 752 static int 753 lemac_ifioctl( 754 struct ifnet *ifp, 755 u_long cmd, 756 caddr_t data) 757 { 758 lemac_softc_t * const sc = LEMAC_IFP_TO_SOFTC(ifp); 759 int s; 760 int error = 0; 761 762 s = splnet(); 763 764 switch (cmd) { 765 case SIOCSIFADDR: { 766 struct ifaddr *ifa = (struct ifaddr *)data; 767 768 ifp->if_flags |= IFF_UP; 769 lemac_init(sc); 770 switch (ifa->ifa_addr->sa_family) { 771 #ifdef INET 772 case AF_INET: { 773 arp_ifinit(&sc->sc_if, ifa); 774 break; 775 } 776 #endif /* INET */ 777 778 #ifdef NS 779 /* This magic copied from if_is.c; I don't use XNS, 780 * so I have no way of telling if this actually 781 * works or not. 782 */ 783 case AF_NS: { 784 struct ns_addr *ina = &(IA_SNS(ifa)->sns_addr); 785 if (ns_nullhost(*ina)) { 786 ina->x_host = *(union ns_host *)sc->sc_enaddr; 787 } else { 788 memcpy(sc->sc_enaddr, (caddr_t)ina->x_host.c_host, 789 ifp->if_addrlen); 790 } 791 break; 792 } 793 #endif /* NS */ 794 795 default: { 796 break; 797 } 798 } 799 break; 800 } 801 802 case SIOCSIFFLAGS: { 803 lemac_init(sc); 804 break; 805 } 806 807 case SIOCADDMULTI: 808 case SIOCDELMULTI: { 809 /* 810 * Update multicast listeners 811 */ 812 if (cmd == SIOCADDMULTI) 813 error = ether_addmulti((struct ifreq *)data, &sc->sc_ec); 814 else 815 error = ether_delmulti((struct ifreq *)data, &sc->sc_ec); 816 817 if (error == ENETRESET) { 818 /* reset multicast filtering */ 819 if (ifp->if_flags & IFF_RUNNING) 820 lemac_init(sc); 821 error = 0; 822 } 823 break; 824 } 825 826 case SIOCSIFMEDIA: 827 case SIOCGIFMEDIA: { 828 error = ifmedia_ioctl(ifp, (struct ifreq *)data, 829 &sc->sc_ifmedia, cmd); 830 break; 831 } 832 833 default: { 834 error = EINVAL; 835 break; 836 } 837 } 838 839 splx(s); 840 return error; 841 } 842 843 static int 844 lemac_ifmedia_change( 845 struct ifnet * const ifp) 846 { 847 lemac_softc_t * const sc = LEMAC_IFP_TO_SOFTC(ifp); 848 unsigned new_ctl; 849 850 switch (IFM_SUBTYPE(sc->sc_ifmedia.ifm_media)) { 851 case IFM_10_T: new_ctl = LEMAC_CTL_APD; break; 852 case IFM_10_2: 853 case IFM_10_5: new_ctl = LEMAC_CTL_APD|LEMAC_CTL_PSL; break; 854 case IFM_AUTO: new_ctl = 0; break; 855 default: return EINVAL; 856 } 857 if (sc->sc_ctlmode != new_ctl) { 858 sc->sc_ctlmode = new_ctl; 859 lemac_reset(sc); 860 if (sc->sc_if.if_flags & IFF_UP) 861 lemac_init(sc); 862 } 863 return 0; 864 } 865 866 /* 867 * Media status callback 868 */ 869 static void 870 lemac_ifmedia_status( 871 struct ifnet * const ifp, 872 struct ifmediareq *req) 873 { 874 lemac_softc_t *sc = LEMAC_IFP_TO_SOFTC(ifp); 875 unsigned data = LEMAC_INB(sc, LEMAC_REG_CNF); 876 877 req->ifm_status = IFM_AVALID; 878 if (sc->sc_flags & LEMAC_LINKUP) 879 req->ifm_status |= IFM_ACTIVE; 880 881 if (sc->sc_ctlmode & LEMAC_CTL_APD) { 882 if (sc->sc_ctlmode & LEMAC_CTL_PSL) { 883 req->ifm_active = IFM_10_5; 884 } else { 885 req->ifm_active = IFM_10_T; 886 } 887 } else { 888 /* 889 * The link bit of the configuration register reflects the 890 * current media choice when auto-port is enabled. 891 */ 892 if (data & LEMAC_CNF_NOLINK) { 893 req->ifm_active = IFM_10_5; 894 } else { 895 req->ifm_active = IFM_10_T; 896 } 897 } 898 899 req->ifm_active |= IFM_ETHER; 900 } 901 902 int 903 lemac_port_check( 904 const bus_space_tag_t iot, 905 const bus_space_handle_t ioh) 906 { 907 unsigned char hwaddr[6]; 908 909 if (lemac_read_macaddr(hwaddr, iot, ioh, LEMAC_REG_APD, 0) == 0) 910 return 1; 911 if (lemac_read_macaddr(hwaddr, iot, ioh, LEMAC_REG_APD, 1) == 0) 912 return 1; 913 return 0; 914 } 915 916 void 917 lemac_info_get( 918 const bus_space_tag_t iot, 919 const bus_space_handle_t ioh, 920 bus_addr_t *maddr_p, 921 bus_size_t *msize_p, 922 int *irq_p) 923 { 924 unsigned data; 925 926 *irq_p = LEMAC_DECODEIRQ(bus_space_read_1(iot, ioh, LEMAC_REG_IC) & LEMAC_IC_IRQMSK); 927 928 data = bus_space_read_1(iot, ioh, LEMAC_REG_MBR); 929 if (LEMAC_IS_2K_MODE(data)) { 930 *maddr_p = data * (2 * 1024) + (512 * 1024); 931 *msize_p = 2 * 1024; 932 } else if (LEMAC_IS_64K_MODE(data)) { 933 *maddr_p = data * 64 * 1024; 934 *msize_p = 64 * 1024; 935 } else if (LEMAC_IS_32K_MODE(data)) { 936 *maddr_p = data * 32 * 1024; 937 *msize_p = 32* 1024; 938 } else { 939 *maddr_p = 0; 940 *msize_p = 0; 941 } 942 } 943 944 /* 945 * What to do upon receipt of an interrupt. 946 */ 947 int 948 lemac_intr( 949 void *arg) 950 { 951 lemac_softc_t * const sc = arg; 952 int cs_value; 953 954 LEMAC_INTR_DISABLE(sc); /* Mask interrupts */ 955 956 /* 957 * Determine cause of interrupt. Receive events take 958 * priority over Transmit. 959 */ 960 961 cs_value = LEMAC_INB(sc, LEMAC_REG_CS); 962 963 /* 964 * Check for Receive Queue not being empty. 965 * Check for Transmit Done Queue not being empty. 966 */ 967 968 if (cs_value & LEMAC_CS_RNE) 969 lemac_rne_intr(sc); 970 if (cs_value & LEMAC_CS_TNE) 971 lemac_tne_intr(sc); 972 973 /* 974 * Check for Transmitter Disabled. 975 * Check for Receiver Disabled. 976 */ 977 978 if (cs_value & LEMAC_CS_TXD) 979 lemac_txd_intr(sc, cs_value); 980 if (cs_value & LEMAC_CS_RXD) 981 lemac_rxd_intr(sc, cs_value); 982 983 /* 984 * Toggle LED and unmask interrupts. 985 */ 986 987 sc->sc_csr.csr_cs = LEMAC_INB(sc, LEMAC_REG_CS); 988 989 LEMAC_OUTB(sc, LEMAC_REG_CTL, LEMAC_INB(sc, LEMAC_REG_CTL) ^ LEMAC_CTL_LED); 990 LEMAC_INTR_ENABLE(sc); /* Unmask interrupts */ 991 992 #if NRND > 0 993 if (cs_value) 994 rnd_add_uint32(&sc->rnd_source, cs_value); 995 #endif 996 997 return 1; 998 } 999 1000 void 1001 lemac_shutdown( 1002 void *arg) 1003 { 1004 lemac_reset((lemac_softc_t *) arg); 1005 } 1006 1007 static const char * const lemac_modes[4] = { 1008 "PIO mode (internal 2KB window)", 1009 "2KB window", 1010 "changed 32KB window to 2KB", 1011 "changed 64KB window to 2KB", 1012 }; 1013 1014 void 1015 lemac_ifattach( 1016 lemac_softc_t *sc) 1017 { 1018 struct ifnet * const ifp = &sc->sc_if; 1019 1020 strcpy(ifp->if_xname, sc->sc_dv.dv_xname); 1021 1022 lemac_reset(sc); 1023 1024 (void) lemac_read_macaddr(sc->sc_enaddr, sc->sc_iot, sc->sc_ioh, 1025 LEMAC_REG_APD, 0); 1026 1027 printf(": %s\n", sc->sc_prodname); 1028 1029 printf("%s: address %s, %dKB RAM, %s\n", 1030 ifp->if_xname, 1031 ether_sprintf(sc->sc_enaddr), 1032 sc->sc_lastpage * 2 + 2, 1033 lemac_modes[sc->sc_flags & LEMAC_MODE_MASK]); 1034 1035 ifp->if_softc = (void *) sc; 1036 ifp->if_start = lemac_ifstart; 1037 ifp->if_ioctl = lemac_ifioctl; 1038 1039 ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX 1040 #ifdef IFF_NOTRAILERS 1041 | IFF_NOTRAILERS 1042 #endif 1043 | IFF_MULTICAST; 1044 1045 if (sc->sc_flags & LEMAC_ALIVE) { 1046 int media; 1047 1048 IFQ_SET_READY(&ifp->if_snd); 1049 1050 if_attach(ifp); 1051 ether_ifattach(ifp, sc->sc_enaddr); 1052 1053 #if NRND > 0 1054 rnd_attach_source(&sc->rnd_source, sc->sc_dv.dv_xname, 1055 RND_TYPE_NET, 0); 1056 #endif 1057 1058 ifmedia_init(&sc->sc_ifmedia, 0, 1059 lemac_ifmedia_change, 1060 lemac_ifmedia_status); 1061 if (sc->sc_prodname[4] == '5') /* DE205 is UTP/AUI */ 1062 ifmedia_add(&sc->sc_ifmedia, IFM_ETHER | IFM_AUTO, 0, 0); 1063 if (sc->sc_prodname[4] != '3') /* DE204 & 205 have UTP */ 1064 ifmedia_add(&sc->sc_ifmedia, IFM_ETHER | IFM_10_T, 0, 0); 1065 if (sc->sc_prodname[4] != '4') /* DE203 & 205 have BNC */ 1066 ifmedia_add(&sc->sc_ifmedia, IFM_ETHER | IFM_10_5, 0, 0); 1067 switch (sc->sc_prodname[4]) { 1068 case '3': media = IFM_10_5; break; 1069 case '4': media = IFM_10_T; break; 1070 default: media = IFM_AUTO; break; 1071 } 1072 ifmedia_set(&sc->sc_ifmedia, IFM_ETHER | media); 1073 } else { 1074 printf("%s: disabled due to error\n", ifp->if_xname); 1075 } 1076 } 1077