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