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