Annotation of sys/dev/pci/if_lmc.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: if_lmc.c,v 1.23 2006/05/13 19:10:02 brad Exp $ */
! 2: /* $NetBSD: if_lmc.c,v 1.1 1999/03/25 03:32:43 explorer Exp $ */
! 3:
! 4: /*-
! 5: * Copyright (c) 1997-1999 LAN Media Corporation (LMC)
! 6: * All rights reserved. www.lanmedia.com
! 7: *
! 8: * This code is written by Michael Graff <graff@vix.com> for LMC.
! 9: * The code is derived from permitted modifications to software created
! 10: * by Matt Thomas (matt@3am-software.com).
! 11: *
! 12: * Redistribution and use in source and binary forms, with or without
! 13: * modification, are permitted provided that the following conditions
! 14: * are met:
! 15: * 1. Redistributions of source code must retain the above copyright
! 16: * notice, this list of conditions and the following disclaimer.
! 17: * 2. Redistributions in binary form must reproduce the above
! 18: * copyright notice, this list of conditions and the following disclaimer
! 19: * in the documentation and/or other materials provided with the
! 20: * distribution.
! 21: * 3. All marketing or advertising materials mentioning features or
! 22: * use of this software must display the following acknowledgement:
! 23: * This product includes software developed by LAN Media Corporation
! 24: * and its contributors.
! 25: * 4. Neither the name of LAN Media Corporation nor the names of its
! 26: * contributors may be used to endorse or promote products derived
! 27: * from this software without specific prior written permission.
! 28: *
! 29: * THIS SOFTWARE IS PROVIDED BY LAN MEDIA CORPORATION AND CONTRIBUTORS
! 30: * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
! 31: * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
! 32: * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
! 33: * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
! 34: * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
! 35: * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
! 36: * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
! 37: * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
! 38: * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
! 39: * THE POSSIBILITY OF SUCH DAMAGE.
! 40: */
! 41:
! 42: /*-
! 43: * Copyright (c) 1994-1997 Matt Thomas (matt@3am-software.com)
! 44: * All rights reserved.
! 45: *
! 46: * Redistribution and use in source and binary forms, with or without
! 47: * modification, are permitted provided that the following conditions
! 48: * are met:
! 49: * 1. Redistributions of source code must retain the above copyright
! 50: * notice, this list of conditions and the following disclaimer.
! 51: * 2. The name of the author may not be used to endorse or promote products
! 52: * derived from this software without specific prior written permission
! 53: *
! 54: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
! 55: * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
! 56: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
! 57: * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
! 58: * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
! 59: * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
! 60: * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
! 61: * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
! 62: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
! 63: * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
! 64: */
! 65:
! 66: /*
! 67: * LMC1200 (DS1) & LMC5245 (DS3) LED definitions
! 68: * led0 yellow = far-end link is in Red alarm condition
! 69: * led1 blue = received an Alarm Indication signal (upstream failure)
! 70: * led2 Green = power to adapter, Gate Array loaded & driver attached
! 71: * led3 red = Loss of Signal (LOS) or out of frame (OOF) conditions
! 72: * detected on T3 receive signal
! 73: *
! 74: * LMC1000 (SSI) & LMC5200 (HSSI) LED definitions
! 75: * led0 Green = power to adapter, Gate Array loaded & driver attached
! 76: * led1 Green = DSR and DTR and RTS and CTS are set (CA, TA for LMC5200)
! 77: * led2 Green = Cable detected (Green indicates non-loopback mode for LMC5200)
! 78: * led3 red = No timing is available from the cable or the on-board
! 79: * frequency generator. (ST not available for LMC5200)
! 80: */
! 81:
! 82: #include "bpfilter.h"
! 83:
! 84: #include <sys/param.h>
! 85: #include <sys/systm.h>
! 86: #include <sys/mbuf.h>
! 87: #include <sys/socket.h>
! 88: #include <sys/ioctl.h>
! 89: #include <sys/errno.h>
! 90: #include <sys/malloc.h>
! 91: #include <sys/kernel.h>
! 92: #include <sys/proc.h>
! 93: #include <sys/device.h>
! 94:
! 95: #include <dev/pci/pcidevs.h>
! 96:
! 97: #include <net/if.h>
! 98: #include <net/if_types.h>
! 99: #include <net/if_dl.h>
! 100: #include <net/netisr.h>
! 101:
! 102: #if NBPFILTER > 0
! 103: #include <net/bpf.h>
! 104: #endif
! 105:
! 106: #include <net/if_sppp.h>
! 107:
! 108: #include <machine/bus.h>
! 109:
! 110: #include <dev/pci/pcireg.h>
! 111: #include <dev/pci/pcivar.h>
! 112: #include <dev/ic/dc21040reg.h>
! 113:
! 114: #include <dev/pci/if_lmc_types.h>
! 115: #include <dev/pci/if_lmcioctl.h>
! 116: #include <dev/pci/if_lmcvar.h>
! 117:
! 118: /*
! 119: * This module supports
! 120: * the DEC 21140A pass 2.2 PCI Fast Ethernet Controller.
! 121: */
! 122: static ifnet_ret_t lmc_ifstart_one(struct ifnet *ifp);
! 123: static ifnet_ret_t lmc_ifstart(struct ifnet *ifp);
! 124: static struct mbuf *lmc_txput(lmc_softc_t * const sc, struct mbuf *m);
! 125: static void lmc_rx_intr(lmc_softc_t * const sc);
! 126:
! 127: static void lmc_watchdog(struct ifnet *ifp);
! 128: static void lmc_ifup(lmc_softc_t * const sc);
! 129: static void lmc_ifdown(lmc_softc_t * const sc);
! 130:
! 131: /*
! 132: * Code the read the SROM and MII bit streams (I2C)
! 133: */
! 134: static inline void
! 135: lmc_delay_300ns(lmc_softc_t * const sc)
! 136: {
! 137: int idx;
! 138: for (idx = (300 / 33) + 1; idx > 0; idx--)
! 139: (void)LMC_CSR_READ(sc, csr_busmode);
! 140: }
! 141:
! 142: #define EMIT \
! 143: do { \
! 144: LMC_CSR_WRITE(sc, csr_srom_mii, csr); \
! 145: lmc_delay_300ns(sc); \
! 146: } while (0)
! 147:
! 148: static inline void
! 149: lmc_srom_idle(lmc_softc_t * const sc)
! 150: {
! 151: unsigned bit, csr;
! 152:
! 153: csr = SROMSEL ; EMIT;
! 154: csr = SROMSEL | SROMRD; EMIT;
! 155: csr ^= SROMCS; EMIT;
! 156: csr ^= SROMCLKON; EMIT;
! 157:
! 158: /*
! 159: * Write 25 cycles of 0 which will force the SROM to be idle.
! 160: */
! 161: for (bit = 3 + SROM_BITWIDTH + 16; bit > 0; bit--) {
! 162: csr ^= SROMCLKOFF; EMIT; /* clock low; data not valid */
! 163: csr ^= SROMCLKON; EMIT; /* clock high; data valid */
! 164: }
! 165: csr ^= SROMCLKOFF; EMIT;
! 166: csr ^= SROMCS; EMIT;
! 167: csr = 0; EMIT;
! 168: }
! 169:
! 170:
! 171: static void
! 172: lmc_srom_read(lmc_softc_t * const sc)
! 173: {
! 174: unsigned idx;
! 175: const unsigned bitwidth = SROM_BITWIDTH;
! 176: const unsigned cmdmask = (SROMCMD_RD << bitwidth);
! 177: const unsigned msb = 1 << (bitwidth + 3 - 1);
! 178: unsigned lastidx = (1 << bitwidth) - 1;
! 179:
! 180: lmc_srom_idle(sc);
! 181:
! 182: for (idx = 0; idx <= lastidx; idx++) {
! 183: unsigned lastbit, data, bits, bit, csr;
! 184: csr = SROMSEL ; EMIT;
! 185: csr = SROMSEL | SROMRD; EMIT;
! 186: csr ^= SROMCSON; EMIT;
! 187: csr ^= SROMCLKON; EMIT;
! 188:
! 189: lastbit = 0;
! 190: for (bits = idx|cmdmask, bit = bitwidth + 3
! 191: ; bit > 0
! 192: ; bit--, bits <<= 1) {
! 193: const unsigned thisbit = bits & msb;
! 194: csr ^= SROMCLKOFF; EMIT; /* clock L data invalid */
! 195: if (thisbit != lastbit) {
! 196: csr ^= SROMDOUT; EMIT;/* clock L invert data */
! 197: } else {
! 198: EMIT;
! 199: }
! 200: csr ^= SROMCLKON; EMIT; /* clock H data valid */
! 201: lastbit = thisbit;
! 202: }
! 203: csr ^= SROMCLKOFF; EMIT;
! 204:
! 205: for (data = 0, bits = 0; bits < 16; bits++) {
! 206: data <<= 1;
! 207: csr ^= SROMCLKON; EMIT; /* clock H data valid */
! 208: data |= LMC_CSR_READ(sc, csr_srom_mii) & SROMDIN ? 1 : 0;
! 209: csr ^= SROMCLKOFF; EMIT; /* clock L data invalid */
! 210: }
! 211: sc->lmc_rombuf[idx*2] = data & 0xFF;
! 212: sc->lmc_rombuf[idx*2+1] = data >> 8;
! 213: csr = SROMSEL | SROMRD; EMIT;
! 214: csr = 0; EMIT;
! 215: }
! 216: lmc_srom_idle(sc);
! 217: }
! 218:
! 219: #define MII_EMIT do { LMC_CSR_WRITE(sc, csr_srom_mii, csr); lmc_delay_300ns(sc); } while (0)
! 220:
! 221: static inline void
! 222: lmc_mii_writebits(lmc_softc_t * const sc, unsigned data, unsigned bits)
! 223: {
! 224: unsigned msb = 1 << (bits - 1);
! 225: unsigned csr = LMC_CSR_READ(sc, csr_srom_mii) & (MII_RD|MII_DOUT|MII_CLK);
! 226: unsigned lastbit = (csr & MII_DOUT) ? msb : 0;
! 227:
! 228: csr |= MII_WR; MII_EMIT; /* clock low; assert write */
! 229:
! 230: for (; bits > 0; bits--, data <<= 1) {
! 231: const unsigned thisbit = data & msb;
! 232: if (thisbit != lastbit) {
! 233: csr ^= MII_DOUT; MII_EMIT; /* clock low; invert data */
! 234: }
! 235: csr ^= MII_CLKON; MII_EMIT; /* clock high; data valid */
! 236: lastbit = thisbit;
! 237: csr ^= MII_CLKOFF; MII_EMIT; /* clock low; data not valid */
! 238: }
! 239: }
! 240:
! 241: static void
! 242: lmc_mii_turnaround(lmc_softc_t * const sc, u_int32_t cmd)
! 243: {
! 244: u_int32_t csr;
! 245:
! 246: csr = LMC_CSR_READ(sc, csr_srom_mii) & (MII_RD|MII_DOUT|MII_CLK);
! 247: if (cmd == MII_WRCMD) {
! 248: csr |= MII_DOUT; MII_EMIT; /* clock low; change data */
! 249: csr ^= MII_CLKON; MII_EMIT; /* clock high; data valid */
! 250: csr ^= MII_CLKOFF; MII_EMIT; /* clock low; data not valid */
! 251: csr ^= MII_DOUT; MII_EMIT; /* clock low; change data */
! 252: } else {
! 253: csr |= MII_RD; MII_EMIT; /* clock low; switch to read */
! 254: }
! 255: csr ^= MII_CLKON; MII_EMIT; /* clock high; data valid */
! 256: csr ^= MII_CLKOFF; MII_EMIT; /* clock low; data not valid */
! 257: }
! 258:
! 259: static u_int32_t
! 260: lmc_mii_readbits(lmc_softc_t * const sc)
! 261: {
! 262: u_int32_t data;
! 263: u_int32_t csr = LMC_CSR_READ(sc, csr_srom_mii) & (MII_RD|MII_DOUT|MII_CLK);
! 264: int idx;
! 265:
! 266: for (idx = 0, data = 0; idx < 16; idx++) {
! 267: data <<= 1; /* this is NOOP on the first pass through */
! 268: csr ^= MII_CLKON; MII_EMIT; /* clock high; data valid */
! 269: if (LMC_CSR_READ(sc, csr_srom_mii) & MII_DIN)
! 270: data |= 1;
! 271: csr ^= MII_CLKOFF; MII_EMIT; /* clock low; data not valid */
! 272: }
! 273: csr ^= MII_RD; MII_EMIT; /* clock low; turn off read */
! 274:
! 275: return data;
! 276: }
! 277:
! 278: u_int32_t
! 279: lmc_mii_readreg(lmc_softc_t * const sc, u_int32_t devaddr, u_int32_t regno)
! 280: {
! 281: u_int32_t csr = LMC_CSR_READ(sc, csr_srom_mii) & (MII_RD|MII_DOUT|MII_CLK);
! 282: u_int32_t data;
! 283:
! 284: csr &= ~(MII_RD|MII_CLK); MII_EMIT;
! 285: lmc_mii_writebits(sc, MII_PREAMBLE, 32);
! 286: lmc_mii_writebits(sc, MII_RDCMD, 8);
! 287: lmc_mii_writebits(sc, devaddr, 5);
! 288: lmc_mii_writebits(sc, regno, 5);
! 289: lmc_mii_turnaround(sc, MII_RDCMD);
! 290:
! 291: data = lmc_mii_readbits(sc);
! 292: return (data);
! 293: }
! 294:
! 295: void
! 296: lmc_mii_writereg(lmc_softc_t * const sc, u_int32_t devaddr,
! 297: u_int32_t regno, u_int32_t data)
! 298: {
! 299: u_int32_t csr;
! 300:
! 301: csr = LMC_CSR_READ(sc, csr_srom_mii) & (MII_RD|MII_DOUT|MII_CLK);
! 302: csr &= ~(MII_RD|MII_CLK); MII_EMIT;
! 303: lmc_mii_writebits(sc, MII_PREAMBLE, 32);
! 304: lmc_mii_writebits(sc, MII_WRCMD, 8);
! 305: lmc_mii_writebits(sc, devaddr, 5);
! 306: lmc_mii_writebits(sc, regno, 5);
! 307: lmc_mii_turnaround(sc, MII_WRCMD);
! 308: lmc_mii_writebits(sc, data, 16);
! 309: }
! 310:
! 311: int
! 312: lmc_read_macaddr(lmc_softc_t * const sc)
! 313: {
! 314: lmc_srom_read(sc);
! 315:
! 316: bcopy(sc->lmc_rombuf + 20, sc->lmc_enaddr, 6);
! 317:
! 318: return 0;
! 319: }
! 320:
! 321: /*
! 322: * Check to make certain there is a signal from the modem, and flicker
! 323: * lights as needed.
! 324: */
! 325: static void
! 326: lmc_watchdog(struct ifnet *ifp)
! 327: {
! 328: lmc_softc_t * const sc = LMC_IFP_TO_SOFTC(ifp);
! 329: int state;
! 330: u_int32_t ostatus;
! 331: u_int32_t link_status;
! 332: u_int32_t ticks;
! 333:
! 334: state = 0;
! 335:
! 336: /*
! 337: * Make sure the tx jabber and rx watchdog are off,
! 338: * and the transmit and receive processes are running.
! 339: */
! 340: LMC_CSR_WRITE (sc, csr_15, 0x00000011);
! 341: sc->lmc_cmdmode |= TULIP_CMD_TXRUN | TULIP_CMD_RXRUN;
! 342: LMC_CSR_WRITE (sc, csr_command, sc->lmc_cmdmode);
! 343:
! 344: /* Is the transmit clock still available? */
! 345: ticks = LMC_CSR_READ (sc, csr_gp_timer);
! 346: ticks = 0x0000ffff - (ticks & 0x0000ffff);
! 347: if (ticks == 0)
! 348: {
! 349: /* no clock found ? */
! 350: if (sc->tx_clockState != 0)
! 351: {
! 352: sc->tx_clockState = 0;
! 353: if (sc->lmc_cardtype == LMC_CARDTYPE_SSI)
! 354: lmc_led_on (sc, LMC_MII16_LED3); /* ON red */
! 355: }
! 356: else
! 357: if (sc->tx_clockState == 0)
! 358: {
! 359: sc->tx_clockState = 1;
! 360: if (sc->lmc_cardtype == LMC_CARDTYPE_SSI)
! 361: lmc_led_off (sc, LMC_MII16_LED3); /* OFF red */
! 362: }
! 363: }
! 364:
! 365: link_status = sc->lmc_media->get_link_status(sc);
! 366: ostatus = ((sc->lmc_flags & LMC_MODEMOK) == LMC_MODEMOK);
! 367:
! 368: /*
! 369: * hardware level link lost, but the interface is marked as up.
! 370: * Mark it as down.
! 371: */
! 372: if (link_status == LMC_LINK_DOWN && ostatus) {
! 373: printf(LMC_PRINTF_FMT ": physical link down\n",
! 374: LMC_PRINTF_ARGS);
! 375: sc->lmc_flags &= ~LMC_MODEMOK;
! 376: if (sc->lmc_cardtype == LMC_CARDTYPE_DS3 ||
! 377: sc->lmc_cardtype == LMC_CARDTYPE_T1)
! 378: lmc_led_on (sc, LMC_DS3_LED3 | LMC_DS3_LED2);
! 379: /* turn on red LED */
! 380: else {
! 381: lmc_led_off (sc, LMC_MII16_LED1);
! 382: lmc_led_on (sc, LMC_MII16_LED0);
! 383: if (sc->lmc_timing == LMC_CTL_CLOCK_SOURCE_EXT)
! 384: lmc_led_on (sc, LMC_MII16_LED3);
! 385: }
! 386:
! 387: }
! 388:
! 389: /*
! 390: * hardware link is up, but the interface is marked as down.
! 391: * Bring it back up again.
! 392: */
! 393: if (link_status != LMC_LINK_DOWN && !ostatus) {
! 394: printf(LMC_PRINTF_FMT ": physical link up\n",
! 395: LMC_PRINTF_ARGS);
! 396: if (sc->lmc_flags & LMC_IFUP)
! 397: lmc_ifup(sc);
! 398: sc->lmc_flags |= LMC_MODEMOK;
! 399: if (sc->lmc_cardtype == LMC_CARDTYPE_DS3 ||
! 400: sc->lmc_cardtype == LMC_CARDTYPE_T1)
! 401: {
! 402: sc->lmc_miireg16 |= LMC_DS3_LED3;
! 403: lmc_led_off (sc, LMC_DS3_LED3);
! 404: /* turn off red LED */
! 405: lmc_led_on (sc, LMC_DS3_LED2);
! 406: } else {
! 407: lmc_led_on (sc, LMC_MII16_LED0 | LMC_MII16_LED1
! 408: | LMC_MII16_LED2);
! 409: if (sc->lmc_timing != LMC_CTL_CLOCK_SOURCE_EXT)
! 410: lmc_led_off (sc, LMC_MII16_LED3);
! 411: }
! 412:
! 413: return;
! 414: }
! 415:
! 416: /* Call media specific watchdog functions */
! 417: sc->lmc_media->watchdog(sc);
! 418:
! 419: /*
! 420: * remember the timer value
! 421: */
! 422: ticks = LMC_CSR_READ(sc, csr_gp_timer);
! 423: LMC_CSR_WRITE(sc, csr_gp_timer, 0xffffffffUL);
! 424: sc->ictl.ticks = 0x0000ffff - (ticks & 0x0000ffff);
! 425:
! 426: ifp->if_timer = 1;
! 427: }
! 428:
! 429: /*
! 430: * Mark the interface as "up" and enable TX/RX and TX/RX interrupts.
! 431: * This also does a full software reset.
! 432: */
! 433: static void
! 434: lmc_ifup(lmc_softc_t * const sc)
! 435: {
! 436: sc->lmc_if.if_timer = 0;
! 437:
! 438: lmc_dec_reset(sc);
! 439: lmc_reset(sc);
! 440:
! 441: sc->lmc_media->set_link_status(sc, LMC_LINK_UP);
! 442: sc->lmc_media->set_status(sc, NULL);
! 443:
! 444: sc->lmc_flags |= LMC_IFUP;
! 445:
! 446: /*
! 447: * for DS3 & DS1 adapters light the green light, led2
! 448: */
! 449: if (sc->lmc_cardtype == LMC_CARDTYPE_DS3 ||
! 450: sc->lmc_cardtype == LMC_CARDTYPE_T1)
! 451: lmc_led_on (sc, LMC_MII16_LED2);
! 452: else
! 453: lmc_led_on (sc, LMC_MII16_LED0 | LMC_MII16_LED2);
! 454:
! 455: /*
! 456: * select what interrupts we want to get
! 457: */
! 458: sc->lmc_intrmask |= (TULIP_STS_NORMALINTR
! 459: | TULIP_STS_RXINTR
! 460: | TULIP_STS_RXNOBUF
! 461: | TULIP_STS_TXINTR
! 462: | TULIP_STS_ABNRMLINTR
! 463: | TULIP_STS_SYSERROR
! 464: | TULIP_STS_TXSTOPPED
! 465: | TULIP_STS_TXUNDERFLOW
! 466: | TULIP_STS_RXSTOPPED
! 467: );
! 468: LMC_CSR_WRITE(sc, csr_intr, sc->lmc_intrmask);
! 469:
! 470: sc->lmc_cmdmode |= TULIP_CMD_TXRUN;
! 471: sc->lmc_cmdmode |= TULIP_CMD_RXRUN;
! 472: LMC_CSR_WRITE(sc, csr_command, sc->lmc_cmdmode);
! 473:
! 474: sc->lmc_if.if_timer = 1;
! 475: }
! 476:
! 477: /*
! 478: * Mark the interface as "down" and disable TX/RX and TX/RX interrupts.
! 479: * This is done by performing a full reset on the interface.
! 480: */
! 481: static void
! 482: lmc_ifdown(lmc_softc_t * const sc)
! 483: {
! 484: sc->lmc_if.if_timer = 0;
! 485: sc->lmc_flags &= ~LMC_IFUP;
! 486:
! 487: sc->lmc_media->set_link_status(sc, LMC_LINK_DOWN);
! 488: lmc_led_off(sc, LMC_MII16_LED_ALL);
! 489:
! 490: lmc_dec_reset(sc);
! 491: lmc_reset(sc);
! 492: sc->lmc_media->set_status(sc, NULL);
! 493: }
! 494:
! 495: static void
! 496: lmc_rx_intr(lmc_softc_t * const sc)
! 497: {
! 498: lmc_ringinfo_t * const ri = &sc->lmc_rxinfo;
! 499: struct ifnet * const ifp = &sc->lmc_if;
! 500: u_int32_t status;
! 501: int fillok = 1;
! 502:
! 503: sc->lmc_rxtick++;
! 504:
! 505: for (;;) {
! 506: lmc_desc_t *eop = ri->ri_nextin;
! 507: int total_len = 0, last_offset = 0;
! 508: struct mbuf *ms = NULL, *me = NULL;
! 509: int accept = 0;
! 510: bus_dmamap_t map;
! 511: int error;
! 512:
! 513: if (fillok && sc->lmc_rxq.ifq_len < LMC_RXQ_TARGET)
! 514: goto queue_mbuf;
! 515:
! 516: /*
! 517: * If the TULIP has no descriptors, there can't be any receive
! 518: * descriptors to process.
! 519: */
! 520: if (eop == ri->ri_nextout)
! 521: break;
! 522:
! 523: /*
! 524: * 90% of the packets will fit in one descriptor. So we
! 525: * optimize for that case.
! 526: */
! 527: LMC_RXDESC_POSTSYNC(sc, eop, sizeof(*eop));
! 528: status = letoh32(((volatile lmc_desc_t *) eop)->d_status);
! 529: if ((status &
! 530: (TULIP_DSTS_OWNER|TULIP_DSTS_RxFIRSTDESC|TULIP_DSTS_RxLASTDESC)) ==
! 531: (TULIP_DSTS_RxFIRSTDESC|TULIP_DSTS_RxLASTDESC)) {
! 532: IF_DEQUEUE(&sc->lmc_rxq, ms);
! 533: me = ms;
! 534: } else {
! 535: /*
! 536: * If still owned by the TULIP, don't touch it.
! 537: */
! 538: if (status & TULIP_DSTS_OWNER)
! 539: break;
! 540:
! 541: /*
! 542: * It is possible (though improbable unless the
! 543: * BIG_PACKET support is enabled or MCLBYTES < 1518)
! 544: * for a received packet to cross more than one
! 545: * receive descriptor.
! 546: */
! 547: while ((status & TULIP_DSTS_RxLASTDESC) == 0) {
! 548: if (++eop == ri->ri_last)
! 549: eop = ri->ri_first;
! 550: LMC_RXDESC_POSTSYNC(sc, eop, sizeof(*eop));
! 551: status = letoh32(((volatile lmc_desc_t *)
! 552: eop)->d_status);
! 553: if (eop == ri->ri_nextout ||
! 554: (status & TULIP_DSTS_OWNER)) {
! 555: return;
! 556: }
! 557: total_len++;
! 558: }
! 559:
! 560: /*
! 561: * Dequeue the first buffer for the start of the
! 562: * packet. Hopefully this will be the only one we
! 563: * need to dequeue. However, if the packet consumed
! 564: * multiple descriptors, then we need to dequeue
! 565: * those buffers and chain to the starting mbuf.
! 566: * All buffers but the last buffer have the same
! 567: * length so we can set that now. (we add to
! 568: * last_offset instead of multiplying since we
! 569: * normally won't go into the loop and thereby
! 570: * saving a ourselves from doing a multiplication
! 571: * by 0 in the normal case).
! 572: */
! 573: IF_DEQUEUE(&sc->lmc_rxq, ms);
! 574: for (me = ms; total_len > 0; total_len--) {
! 575: map = LMC_GETCTX(me, bus_dmamap_t);
! 576: LMC_RXMAP_POSTSYNC(sc, map);
! 577: bus_dmamap_unload(sc->lmc_dmatag, map);
! 578: sc->lmc_rxmaps[sc->lmc_rxmaps_free++] = map;
! 579: #if defined(DIAGNOSTIC)
! 580: LMC_SETCTX(me, NULL);
! 581: #endif
! 582: me->m_len = LMC_RX_BUFLEN;
! 583: last_offset += LMC_RX_BUFLEN;
! 584: IF_DEQUEUE(&sc->lmc_rxq, me->m_next);
! 585: me = me->m_next;
! 586: }
! 587: }
! 588:
! 589: /*
! 590: * Now get the size of received packet (minus the CRC).
! 591: */
! 592: total_len = ((status >> 16) & 0x7FFF);
! 593: if (sc->ictl.crc_length == 16)
! 594: total_len -= 2;
! 595: else
! 596: total_len -= 4;
! 597:
! 598: if ((sc->lmc_flags & LMC_RXIGNORE) == 0
! 599: && ((status & LMC_DSTS_ERRSUM) == 0
! 600: #ifdef BIG_PACKET
! 601: || (total_len <= sc->lmc_if.if_mtu + PPP_HEADER_LEN
! 602: && (status & TULIP_DSTS_RxOVERFLOW) == 0)
! 603: #endif
! 604: )) {
! 605:
! 606: map = LMC_GETCTX(me, bus_dmamap_t);
! 607: bus_dmamap_sync(sc->lmc_dmatag, map, 0, me->m_len,
! 608: BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE);
! 609: bus_dmamap_unload(sc->lmc_dmatag, map);
! 610: sc->lmc_rxmaps[sc->lmc_rxmaps_free++] = map;
! 611: #if defined(DIAGNOSTIC)
! 612: LMC_SETCTX(me, NULL);
! 613: #endif
! 614:
! 615: me->m_len = total_len - last_offset;
! 616: #if NBPFILTER > 0
! 617: if (sc->lmc_bpf != NULL) {
! 618: if (me == ms)
! 619: LMC_BPF_TAP(sc, mtod(ms, caddr_t),
! 620: total_len, BPF_DIRECTION_IN);
! 621: else
! 622: LMC_BPF_MTAP(sc, ms, BPF_DIRECTION_IN);
! 623: }
! 624: #endif
! 625: sc->lmc_flags |= LMC_RXACT;
! 626: accept = 1;
! 627: } else {
! 628: ifp->if_ierrors++;
! 629: if (status & TULIP_DSTS_RxOVERFLOW) {
! 630: sc->lmc_dot3stats.dot3StatsInternalMacReceiveErrors++;
! 631: }
! 632: map = LMC_GETCTX(me, bus_dmamap_t);
! 633: bus_dmamap_unload(sc->lmc_dmatag, map);
! 634: sc->lmc_rxmaps[sc->lmc_rxmaps_free++] = map;
! 635: #if defined(DIAGNOSTIC)
! 636: LMC_SETCTX(me, NULL);
! 637: #endif
! 638: }
! 639:
! 640: ifp->if_ipackets++;
! 641: if (++eop == ri->ri_last)
! 642: eop = ri->ri_first;
! 643: ri->ri_nextin = eop;
! 644:
! 645: queue_mbuf:
! 646: /*
! 647: * Either we are priming the TULIP with mbufs (m == NULL)
! 648: * or we are about to accept an mbuf for the upper layers
! 649: * so we need to allocate an mbuf to replace it. If we
! 650: * can't replace it, send up it anyways. This may cause
! 651: * us to drop packets in the future but that's better than
! 652: * being caught in livelock.
! 653: *
! 654: * Note that if this packet crossed multiple descriptors
! 655: * we don't even try to reallocate all the mbufs here.
! 656: * Instead we rely on the test of the beginning of
! 657: * the loop to refill for the extra consumed mbufs.
! 658: */
! 659: if (accept || ms == NULL) {
! 660: struct mbuf *m0;
! 661: MGETHDR(m0, M_DONTWAIT, MT_DATA);
! 662: if (m0 != NULL) {
! 663: MCLGET(m0, M_DONTWAIT);
! 664: if ((m0->m_flags & M_EXT) == 0) {
! 665: m_freem(m0);
! 666: m0 = NULL;
! 667: }
! 668: }
! 669: if (accept) {
! 670: ms->m_pkthdr.len = total_len;
! 671: ms->m_pkthdr.rcvif = ifp;
! 672: sppp_input(ifp, ms);
! 673: }
! 674: ms = m0;
! 675: }
! 676: if (ms == NULL) {
! 677: /*
! 678: * Couldn't allocate a new buffer. Don't bother
! 679: * trying to replenish the receive queue.
! 680: */
! 681: fillok = 0;
! 682: sc->lmc_flags |= LMC_RXBUFSLOW;
! 683: continue;
! 684: }
! 685: /*
! 686: * Now give the buffer(s) to the TULIP and save in our
! 687: * receive queue.
! 688: */
! 689: do {
! 690: u_int32_t ctl;
! 691: lmc_desc_t * const nextout = ri->ri_nextout;
! 692:
! 693: if (sc->lmc_rxmaps_free > 0) {
! 694: map = sc->lmc_rxmaps[--sc->lmc_rxmaps_free];
! 695: } else {
! 696: m_freem(ms);
! 697: sc->lmc_flags |= LMC_RXBUFSLOW;
! 698: #if defined(LMC_DEBUG)
! 699: sc->lmc_dbg.dbg_rxlowbufs++;
! 700: #endif
! 701: break;
! 702: }
! 703: LMC_SETCTX(ms, map);
! 704: error = bus_dmamap_load(sc->lmc_dmatag, map,
! 705: mtod(ms, void *), LMC_RX_BUFLEN,
! 706: NULL, BUS_DMA_NOWAIT);
! 707: if (error) {
! 708: printf(LMC_PRINTF_FMT
! 709: ": unable to load rx map, "
! 710: "error = %d\n",
! 711: LMC_PRINTF_ARGS, error);
! 712: panic("lmc_rx_intr"); /* XXX */
! 713: }
! 714:
! 715: ctl = letoh32(nextout->d_ctl);
! 716: /* For some weird reason we lose TULIP_DFLAG_ENDRING */
! 717: if ((nextout+1) == ri->ri_last)
! 718: ctl = LMC_CTL(LMC_CTL_FLGS(ctl)|
! 719: TULIP_DFLAG_ENDRING, 0, 0);
! 720: nextout->d_addr1 = htole32(map->dm_segs[0].ds_addr);
! 721: if (map->dm_nsegs == 2) {
! 722: nextout->d_addr2 = htole32(map->dm_segs[1].ds_addr);
! 723: nextout->d_ctl =
! 724: htole32(LMC_CTL(LMC_CTL_FLGS(ctl),
! 725: map->dm_segs[0].ds_len,
! 726: map->dm_segs[1].ds_len));
! 727: } else {
! 728: nextout->d_addr2 = 0;
! 729: nextout->d_ctl =
! 730: htole32(LMC_CTL(LMC_CTL_FLGS(ctl),
! 731: map->dm_segs[0].ds_len, 0));
! 732: }
! 733: LMC_RXDESC_POSTSYNC(sc, nextout, sizeof(*nextout));
! 734: ri->ri_nextout->d_status = htole32(TULIP_DSTS_OWNER);
! 735: LMC_RXDESC_POSTSYNC(sc, nextout, sizeof(u_int32_t));
! 736: if (++ri->ri_nextout == ri->ri_last)
! 737: ri->ri_nextout = ri->ri_first;
! 738: me = ms->m_next;
! 739: ms->m_next = NULL;
! 740: IF_ENQUEUE(&sc->lmc_rxq, ms);
! 741: } while ((ms = me) != NULL);
! 742:
! 743: if (sc->lmc_rxq.ifq_len >= LMC_RXQ_TARGET)
! 744: sc->lmc_flags &= ~LMC_RXBUFSLOW;
! 745: }
! 746: }
! 747:
! 748: static int
! 749: lmc_tx_intr(lmc_softc_t * const sc)
! 750: {
! 751: lmc_ringinfo_t * const ri = &sc->lmc_txinfo;
! 752: struct mbuf *m;
! 753: int xmits = 0;
! 754: int descs = 0;
! 755: u_int32_t d_status;
! 756:
! 757: sc->lmc_txtick++;
! 758:
! 759: while (ri->ri_free < ri->ri_max) {
! 760: u_int32_t flag;
! 761:
! 762: LMC_TXDESC_POSTSYNC(sc, ri->ri_nextin, sizeof(*ri->ri_nextin));
! 763: d_status = letoh32(((volatile lmc_desc_t *) ri->ri_nextin)->d_status);
! 764: if (d_status & TULIP_DSTS_OWNER)
! 765: break;
! 766:
! 767: flag = LMC_CTL_FLGS(letoh32(ri->ri_nextin->d_ctl));
! 768: if (flag & TULIP_DFLAG_TxLASTSEG) {
! 769: IF_DEQUEUE(&sc->lmc_txq, m);
! 770: if (m != NULL) {
! 771: bus_dmamap_t map = LMC_GETCTX(m, bus_dmamap_t);
! 772: LMC_TXMAP_POSTSYNC(sc, map);
! 773: sc->lmc_txmaps[sc->lmc_txmaps_free++] = map;
! 774: #if NBPFILTER > 0
! 775: if (sc->lmc_bpf != NULL)
! 776: LMC_BPF_MTAP(sc, m, BPF_DIRECTION_OUT);
! 777: #endif
! 778: m_freem(m);
! 779: #if defined(LMC_DEBUG)
! 780: } else {
! 781: printf(LMC_PRINTF_FMT ": tx_intr: failed to dequeue mbuf?!?\n", LMC_PRINTF_ARGS);
! 782: #endif
! 783: }
! 784: xmits++;
! 785: if (d_status & LMC_DSTS_ERRSUM) {
! 786: sc->lmc_if.if_oerrors++;
! 787: if (d_status & TULIP_DSTS_TxUNDERFLOW) {
! 788: sc->lmc_dot3stats.dot3StatsInternalTransmitUnderflows++;
! 789: }
! 790: } else {
! 791: if (d_status & TULIP_DSTS_TxDEFERRED) {
! 792: sc->lmc_dot3stats.dot3StatsDeferredTransmissions++;
! 793: }
! 794: }
! 795: }
! 796:
! 797: if (++ri->ri_nextin == ri->ri_last)
! 798: ri->ri_nextin = ri->ri_first;
! 799:
! 800: ri->ri_free++;
! 801: descs++;
! 802: sc->lmc_if.if_flags &= ~IFF_OACTIVE;
! 803: }
! 804: /*
! 805: * If nothing left to transmit, disable the timer.
! 806: * Else if progress, reset the timer back to 2 ticks.
! 807: */
! 808: sc->lmc_if.if_opackets += xmits;
! 809:
! 810: return descs;
! 811: }
! 812:
! 813: static void
! 814: lmc_print_abnormal_interrupt (lmc_softc_t * const sc, u_int32_t csr)
! 815: {
! 816: printf(LMC_PRINTF_FMT ": Abnormal interrupt\n", LMC_PRINTF_ARGS);
! 817: }
! 818:
! 819: static const char * const lmc_system_errors[] = {
! 820: "parity error",
! 821: "master abort",
! 822: "target abort",
! 823: "reserved #3",
! 824: "reserved #4",
! 825: "reserved #5",
! 826: "reserved #6",
! 827: "reserved #7",
! 828: };
! 829:
! 830: static void
! 831: lmc_intr_handler(lmc_softc_t * const sc, int *progress_p)
! 832: {
! 833: u_int32_t csr;
! 834:
! 835: while ((csr = LMC_CSR_READ(sc, csr_status)) & sc->lmc_intrmask) {
! 836:
! 837: *progress_p = 1;
! 838: LMC_CSR_WRITE(sc, csr_status, csr);
! 839:
! 840: if (csr & TULIP_STS_SYSERROR) {
! 841: sc->lmc_last_system_error = (csr & TULIP_STS_ERRORMASK) >> TULIP_STS_ERR_SHIFT;
! 842: if (sc->lmc_flags & LMC_NOMESSAGES) {
! 843: sc->lmc_flags |= LMC_SYSTEMERROR;
! 844: } else {
! 845: printf(LMC_PRINTF_FMT ": system error: %s\n",
! 846: LMC_PRINTF_ARGS,
! 847: lmc_system_errors[sc->lmc_last_system_error]);
! 848: }
! 849: sc->lmc_flags |= LMC_NEEDRESET;
! 850: sc->lmc_system_errors++;
! 851: break;
! 852: }
! 853: if (csr & (TULIP_STS_RXINTR | TULIP_STS_RXNOBUF)) {
! 854: u_int32_t misses = LMC_CSR_READ(sc, csr_missed_frames);
! 855: if (csr & TULIP_STS_RXNOBUF)
! 856: sc->lmc_dot3stats.dot3StatsMissedFrames += misses & 0xFFFF;
! 857: /*
! 858: * Pass 2.[012] of the 21140A-A[CDE] may hang and/or corrupt data
! 859: * on receive overflows.
! 860: */
! 861: if ((misses & 0x0FFE0000) && (sc->lmc_features & LMC_HAVE_RXBADOVRFLW)) {
! 862: sc->lmc_dot3stats.dot3StatsInternalMacReceiveErrors++;
! 863: /*
! 864: * Stop the receiver process and spin until it's stopped.
! 865: * Tell rx_intr to drop the packets it dequeues.
! 866: */
! 867: LMC_CSR_WRITE(sc, csr_command, sc->lmc_cmdmode & ~TULIP_CMD_RXRUN);
! 868: while ((LMC_CSR_READ(sc, csr_status) & TULIP_STS_RXSTOPPED) == 0)
! 869: ;
! 870: LMC_CSR_WRITE(sc, csr_status, TULIP_STS_RXSTOPPED);
! 871: sc->lmc_flags |= LMC_RXIGNORE;
! 872: }
! 873: lmc_rx_intr(sc);
! 874: if (sc->lmc_flags & LMC_RXIGNORE) {
! 875: /*
! 876: * Restart the receiver.
! 877: */
! 878: sc->lmc_flags &= ~LMC_RXIGNORE;
! 879: LMC_CSR_WRITE(sc, csr_command, sc->lmc_cmdmode);
! 880: }
! 881: }
! 882: if (csr & TULIP_STS_ABNRMLINTR) {
! 883: u_int32_t tmp = csr & sc->lmc_intrmask
! 884: & ~(TULIP_STS_NORMALINTR|TULIP_STS_ABNRMLINTR);
! 885: if (csr & TULIP_STS_TXUNDERFLOW) {
! 886: if ((sc->lmc_cmdmode & TULIP_CMD_THRESHOLDCTL) != TULIP_CMD_THRSHLD160) {
! 887: sc->lmc_cmdmode += TULIP_CMD_THRSHLD96;
! 888: sc->lmc_flags |= LMC_NEWTXTHRESH;
! 889: } else if (sc->lmc_features & LMC_HAVE_STOREFWD) {
! 890: sc->lmc_cmdmode |= TULIP_CMD_STOREFWD;
! 891: sc->lmc_flags |= LMC_NEWTXTHRESH;
! 892: }
! 893: }
! 894: if (sc->lmc_flags & LMC_NOMESSAGES) {
! 895: sc->lmc_statusbits |= tmp;
! 896: } else {
! 897: lmc_print_abnormal_interrupt(sc, tmp);
! 898: sc->lmc_flags |= LMC_NOMESSAGES;
! 899: }
! 900: LMC_CSR_WRITE(sc, csr_command, sc->lmc_cmdmode);
! 901: }
! 902:
! 903: if (csr & TULIP_STS_TXINTR)
! 904: lmc_tx_intr(sc);
! 905:
! 906: if (sc->lmc_flags & LMC_WANTTXSTART)
! 907: lmc_ifstart(&sc->lmc_if);
! 908: }
! 909: }
! 910:
! 911: lmc_intrfunc_t
! 912: lmc_intr_normal(void *arg)
! 913: {
! 914: lmc_softc_t * sc = (lmc_softc_t *) arg;
! 915: int progress = 0;
! 916:
! 917: lmc_intr_handler(sc, &progress);
! 918:
! 919: #if !defined(LMC_VOID_INTRFUNC)
! 920: return progress;
! 921: #endif
! 922: }
! 923:
! 924: static struct mbuf *
! 925: lmc_mbuf_compress(struct mbuf *m)
! 926: {
! 927: struct mbuf *m0;
! 928: #if MCLBYTES >= LMC_MTU + PPP_HEADER_LEN && !defined(BIG_PACKET)
! 929: MGETHDR(m0, M_DONTWAIT, MT_DATA);
! 930: if (m0 != NULL) {
! 931: if (m->m_pkthdr.len > MHLEN) {
! 932: MCLGET(m0, M_DONTWAIT);
! 933: if ((m0->m_flags & M_EXT) == 0) {
! 934: m_freem(m);
! 935: m_freem(m0);
! 936: return NULL;
! 937: }
! 938: }
! 939: m_copydata(m, 0, m->m_pkthdr.len, mtod(m0, caddr_t));
! 940: m0->m_pkthdr.len = m0->m_len = m->m_pkthdr.len;
! 941: }
! 942: #else
! 943: int mlen = MHLEN;
! 944: int len = m->m_pkthdr.len;
! 945: struct mbuf **mp = &m0;
! 946:
! 947: while (len > 0) {
! 948: if (mlen == MHLEN) {
! 949: MGETHDR(*mp, M_DONTWAIT, MT_DATA);
! 950: } else {
! 951: MGET(*mp, M_DONTWAIT, MT_DATA);
! 952: }
! 953: if (*mp == NULL) {
! 954: m_freem(m0);
! 955: m0 = NULL;
! 956: break;
! 957: }
! 958: if (len > MLEN) {
! 959: MCLGET(*mp, M_DONTWAIT);
! 960: if (((*mp)->m_flags & M_EXT) == 0) {
! 961: m_freem(m0);
! 962: m0 = NULL;
! 963: break;
! 964: }
! 965: (*mp)->m_len = (len <= MCLBYTES ? len : MCLBYTES);
! 966: } else {
! 967: (*mp)->m_len = (len <= mlen ? len : mlen);
! 968: }
! 969: m_copydata(m, m->m_pkthdr.len - len,
! 970: (*mp)->m_len, mtod((*mp), caddr_t));
! 971: len -= (*mp)->m_len;
! 972: mp = &(*mp)->m_next;
! 973: mlen = MLEN;
! 974: }
! 975: #endif
! 976: m_freem(m);
! 977: return m0;
! 978: }
! 979:
! 980: /*
! 981: * queue the mbuf handed to us for the interface. If we cannot
! 982: * queue it, return the mbuf. Return NULL if the mbuf was queued.
! 983: */
! 984: static struct mbuf *
! 985: lmc_txput(lmc_softc_t * const sc, struct mbuf *m)
! 986: {
! 987: lmc_ringinfo_t * const ri = &sc->lmc_txinfo;
! 988: lmc_desc_t *eop, *nextout;
! 989: int segcnt, free;
! 990: u_int32_t d_status, ctl;
! 991: bus_dmamap_t map;
! 992: int error;
! 993:
! 994: #if defined(LMC_DEBUG)
! 995: if ((sc->lmc_cmdmode & TULIP_CMD_TXRUN) == 0) {
! 996: printf(LMC_PRINTF_FMT ": txput: tx not running\n",
! 997: LMC_PRINTF_ARGS);
! 998: sc->lmc_flags |= LMC_WANTTXSTART;
! 999: goto finish;
! 1000: }
! 1001: #endif
! 1002:
! 1003: /*
! 1004: * Now we try to fill in our transmit descriptors. This is
! 1005: * a bit reminiscent of going on the Ark two by two
! 1006: * since each descriptor for the TULIP can describe
! 1007: * two buffers. So we advance through packet filling
! 1008: * each of the two entries at a time to fill each
! 1009: * descriptor. Clear the first and last segment bits
! 1010: * in each descriptor (actually just clear everything
! 1011: * but the end-of-ring or chain bits) to make sure
! 1012: * we don't get messed up by previously sent packets.
! 1013: *
! 1014: * We may fail to put the entire packet on the ring if
! 1015: * there is either not enough ring entries free or if the
! 1016: * packet has more than MAX_TXSEG segments. In the former
! 1017: * case we will just wait for the ring to empty. In the
! 1018: * latter case we have to recopy.
! 1019: */
! 1020: d_status = 0;
! 1021: eop = nextout = ri->ri_nextout;
! 1022: segcnt = 0;
! 1023: free = ri->ri_free;
! 1024: /*
! 1025: * Reclaim some DMA maps from if we are out.
! 1026: */
! 1027: if (sc->lmc_txmaps_free == 0) {
! 1028: #if defined(LMC_DEBUG)
! 1029: sc->lmc_dbg.dbg_no_txmaps++;
! 1030: #endif
! 1031: free += lmc_tx_intr(sc);
! 1032: }
! 1033: if (sc->lmc_txmaps_free > 0) {
! 1034: map = sc->lmc_txmaps[sc->lmc_txmaps_free-1];
! 1035: } else {
! 1036: sc->lmc_flags |= LMC_WANTTXSTART;
! 1037: #if defined(LMC_DEBUG)
! 1038: sc->lmc_dbg.dbg_txput_finishes[1]++;
! 1039: #endif
! 1040: goto finish;
! 1041: }
! 1042: error = bus_dmamap_load_mbuf(sc->lmc_dmatag, map, m, BUS_DMA_NOWAIT);
! 1043: if (error != 0) {
! 1044: if (error == EFBIG) {
! 1045: /*
! 1046: * The packet exceeds the number of transmit buffer
! 1047: * entries that we can use for one packet, so we have
! 1048: * to recopy it into one mbuf and then try again.
! 1049: */
! 1050: m = lmc_mbuf_compress(m);
! 1051: if (m == NULL) {
! 1052: #if defined(LMC_DEBUG)
! 1053: sc->lmc_dbg.dbg_txput_finishes[2]++;
! 1054: #endif
! 1055: goto finish;
! 1056: }
! 1057: error = bus_dmamap_load_mbuf(sc->lmc_dmatag, map, m,
! 1058: BUS_DMA_NOWAIT);
! 1059: }
! 1060: if (error != 0) {
! 1061: printf(LMC_PRINTF_FMT ": unable to load tx map, "
! 1062: "error = %d\n", LMC_PRINTF_ARGS, error);
! 1063: #if defined(LMC_DEBUG)
! 1064: sc->lmc_dbg.dbg_txput_finishes[3]++;
! 1065: #endif
! 1066: goto finish;
! 1067: }
! 1068: }
! 1069: if ((free -= (map->dm_nsegs + 1) / 2) <= 0
! 1070: /*
! 1071: * See if there's any unclaimed space in the transmit ring.
! 1072: */
! 1073: && (free += lmc_tx_intr(sc)) <= 0) {
! 1074: /*
! 1075: * There's no more room but since nothing
! 1076: * has been committed at this point, just
! 1077: * show output is active, put back the
! 1078: * mbuf and return.
! 1079: */
! 1080: sc->lmc_flags |= LMC_WANTTXSTART;
! 1081: #if defined(LMC_DEBUG)
! 1082: sc->lmc_dbg.dbg_txput_finishes[4]++;
! 1083: #endif
! 1084: bus_dmamap_unload(sc->lmc_dmatag, map);
! 1085: goto finish;
! 1086: }
! 1087: for (; map->dm_nsegs - segcnt > 1; segcnt += 2) {
! 1088: int flg;
! 1089:
! 1090: eop = nextout;
! 1091: flg = LMC_CTL_FLGS(letoh32(eop->d_ctl));
! 1092: flg &= TULIP_DFLAG_ENDRING;
! 1093: flg |= TULIP_DFLAG_TxNOPADDING;
! 1094: if (sc->ictl.crc_length == 16)
! 1095: flg |= TULIP_DFLAG_TxHASCRC;
! 1096: eop->d_status = htole32(d_status);
! 1097: eop->d_addr1 = htole32(map->dm_segs[segcnt].ds_addr);
! 1098: eop->d_addr2 = htole32(map->dm_segs[segcnt+1].ds_addr);
! 1099: eop->d_ctl = htole32(LMC_CTL(flg,
! 1100: map->dm_segs[segcnt].ds_len,
! 1101: map->dm_segs[segcnt+1].ds_len));
! 1102: d_status = TULIP_DSTS_OWNER;
! 1103: if (++nextout == ri->ri_last)
! 1104: nextout = ri->ri_first;
! 1105: }
! 1106: if (segcnt < map->dm_nsegs) {
! 1107: int flg;
! 1108:
! 1109: eop = nextout;
! 1110: flg = LMC_CTL_FLGS(letoh32(eop->d_ctl));
! 1111: flg &= TULIP_DFLAG_ENDRING;
! 1112: flg |= TULIP_DFLAG_TxNOPADDING;
! 1113: if (sc->ictl.crc_length == 16)
! 1114: flg |= TULIP_DFLAG_TxHASCRC;
! 1115: eop->d_status = htole32(d_status);
! 1116: eop->d_addr1 = htole32(map->dm_segs[segcnt].ds_addr);
! 1117: eop->d_addr2 = 0;
! 1118: eop->d_ctl = htole32(LMC_CTL(flg,
! 1119: map->dm_segs[segcnt].ds_len, 0));
! 1120: if (++nextout == ri->ri_last)
! 1121: nextout = ri->ri_first;
! 1122: }
! 1123: LMC_TXMAP_PRESYNC(sc, map);
! 1124: LMC_SETCTX(m, map);
! 1125: map = NULL;
! 1126: --sc->lmc_txmaps_free; /* commit to using the dmamap */
! 1127:
! 1128: /*
! 1129: * The descriptors have been filled in. Now get ready
! 1130: * to transmit.
! 1131: */
! 1132: IF_ENQUEUE(&sc->lmc_txq, m);
! 1133: m = NULL;
! 1134:
! 1135: /*
! 1136: * Make sure the next descriptor after this packet is owned
! 1137: * by us since it may have been set up above if we ran out
! 1138: * of room in the ring.
! 1139: */
! 1140: nextout->d_status = 0;
! 1141: LMC_TXDESC_PRESYNC(sc, nextout, sizeof(u_int32_t));
! 1142:
! 1143: /*
! 1144: * Mark the last and first segments, indicate we want a transmit
! 1145: * complete interrupt, and tell it to transmit!
! 1146: */
! 1147: ctl = letoh32(eop->d_ctl);
! 1148: eop->d_ctl = htole32(LMC_CTL(
! 1149: LMC_CTL_FLGS(ctl)|TULIP_DFLAG_TxLASTSEG|TULIP_DFLAG_TxWANTINTR,
! 1150: LMC_CTL_LEN1(ctl),
! 1151: LMC_CTL_LEN2(ctl)));
! 1152:
! 1153: /*
! 1154: * Note that ri->ri_nextout is still the start of the packet
! 1155: * and until we set the OWNER bit, we can still back out of
! 1156: * everything we have done.
! 1157: */
! 1158: ctl = letoh32(ri->ri_nextout->d_ctl);
! 1159: ri->ri_nextout->d_ctl = htole32(LMC_CTL(
! 1160: LMC_CTL_FLGS(ctl)|TULIP_DFLAG_TxFIRSTSEG,
! 1161: LMC_CTL_LEN1(ctl),
! 1162: LMC_CTL_LEN2(ctl)));
! 1163: if (eop < ri->ri_nextout) {
! 1164: LMC_TXDESC_PRESYNC(sc, ri->ri_nextout,
! 1165: (caddr_t) ri->ri_last - (caddr_t) ri->ri_nextout);
! 1166: LMC_TXDESC_PRESYNC(sc, ri->ri_first,
! 1167: (caddr_t) (eop + 1) - (caddr_t) ri->ri_first);
! 1168: } else {
! 1169: LMC_TXDESC_PRESYNC(sc, ri->ri_nextout,
! 1170: (caddr_t) (eop + 1) - (caddr_t) ri->ri_nextout);
! 1171: }
! 1172: ri->ri_nextout->d_status = htole32(TULIP_DSTS_OWNER);
! 1173: LMC_TXDESC_PRESYNC(sc, ri->ri_nextout, sizeof(u_int32_t));
! 1174:
! 1175: LMC_CSR_WRITE(sc, csr_txpoll, 1);
! 1176:
! 1177: /*
! 1178: * This advances the ring for us.
! 1179: */
! 1180: ri->ri_nextout = nextout;
! 1181: ri->ri_free = free;
! 1182:
! 1183: /*
! 1184: * switch back to the single queueing ifstart.
! 1185: */
! 1186: sc->lmc_flags &= ~LMC_WANTTXSTART;
! 1187: sc->lmc_if.if_start = lmc_ifstart_one;
! 1188:
! 1189: /*
! 1190: * If we want a txstart, there must be not enough space in the
! 1191: * transmit ring. So we want to enable transmit done interrupts
! 1192: * so we can immediately reclaim some space. When the transmit
! 1193: * interrupt is posted, the interrupt handler will call tx_intr
! 1194: * to reclaim space and then txstart (since WANTTXSTART is set).
! 1195: * txstart will move the packet into the transmit ring and clear
! 1196: * WANTTXSTART thereby causing TXINTR to be cleared.
! 1197: */
! 1198: finish:
! 1199: if (sc->lmc_flags & LMC_WANTTXSTART) {
! 1200: sc->lmc_if.if_flags |= IFF_OACTIVE;
! 1201: sc->lmc_if.if_start = lmc_ifstart;
! 1202: }
! 1203:
! 1204: return m;
! 1205: }
! 1206:
! 1207:
! 1208: /*
! 1209: * This routine is entered at splnet()
! 1210: */
! 1211: static int
! 1212: lmc_ifioctl(struct ifnet * ifp, ioctl_cmd_t cmd, caddr_t data)
! 1213: {
! 1214: lmc_softc_t * const sc = LMC_IFP_TO_SOFTC(ifp);
! 1215: int s;
! 1216: struct proc *p = curproc;
! 1217: int error = 0;
! 1218: struct ifreq *ifr = (struct ifreq *)data;
! 1219: u_int32_t new_state;
! 1220: u_int32_t old_state;
! 1221: lmc_ctl_t ctl;
! 1222:
! 1223: s = LMC_RAISESPL();
! 1224:
! 1225: switch (cmd) {
! 1226: case LMCIOCGINFO:
! 1227: error = copyout(&sc->ictl, ifr->ifr_data, sizeof(lmc_ctl_t));
! 1228:
! 1229: goto out;
! 1230: break;
! 1231:
! 1232: case LMCIOCSINFO:
! 1233: error = suser(p, 0);
! 1234: if (error)
! 1235: goto out;
! 1236:
! 1237: error = copyin(ifr->ifr_data, &ctl, sizeof(lmc_ctl_t));
! 1238: if (error != 0)
! 1239: goto out;
! 1240:
! 1241: sc->lmc_media->set_status(sc, &ctl);
! 1242:
! 1243: goto out;
! 1244: break;
! 1245:
! 1246: case SIOCSIFMTU:
! 1247: /*
! 1248: * Don't allow the MTU to get larger than we can handle
! 1249: */
! 1250: if (ifr->ifr_mtu > LMC_MTU) {
! 1251: error = EINVAL;
! 1252: goto out;
! 1253: } else {
! 1254: ifp->if_mtu = ifr->ifr_mtu;
! 1255: }
! 1256: break;
! 1257: }
! 1258:
! 1259: /*
! 1260: * call the sppp ioctl layer
! 1261: */
! 1262: error = sppp_ioctl(ifp, cmd, data);
! 1263: if (error != 0)
! 1264: goto out;
! 1265:
! 1266: /*
! 1267: * If we are transitioning from up to down or down to up, call
! 1268: * our init routine.
! 1269: */
! 1270: new_state = ifp->if_flags & IFF_UP;
! 1271: old_state = sc->lmc_flags & LMC_IFUP;
! 1272:
! 1273: if (new_state && !old_state)
! 1274: lmc_ifup(sc);
! 1275: else if (!new_state && old_state)
! 1276: lmc_ifdown(sc);
! 1277:
! 1278: out:
! 1279: LMC_RESTORESPL(s);
! 1280:
! 1281: return error;
! 1282: }
! 1283:
! 1284: /*
! 1285: * These routines gets called at device spl (from sppp_output).
! 1286: */
! 1287:
! 1288: static ifnet_ret_t
! 1289: lmc_ifstart(struct ifnet * const ifp)
! 1290: {
! 1291: lmc_softc_t * const sc = LMC_IFP_TO_SOFTC(ifp);
! 1292: struct mbuf *m, *m0;
! 1293:
! 1294: if (sc->lmc_flags & LMC_IFUP) {
! 1295: while (sppp_isempty(ifp) == 0) {
! 1296: m = sppp_pick(ifp);
! 1297: if (m == NULL)
! 1298: break;
! 1299: if ((m = lmc_txput(sc, m)) != NULL)
! 1300: break;
! 1301: m0 = sppp_dequeue(ifp);
! 1302: #if defined(LMC_DEBUG)
! 1303: if (m0 != m)
! 1304: printf("lmc_ifstart: mbuf mismatch!\n");
! 1305: #endif
! 1306: }
! 1307: LMC_CSR_WRITE(sc, csr_txpoll, 1);
! 1308: }
! 1309: }
! 1310:
! 1311: static ifnet_ret_t
! 1312: lmc_ifstart_one(struct ifnet * const ifp)
! 1313: {
! 1314: lmc_softc_t * const sc = LMC_IFP_TO_SOFTC(ifp);
! 1315: struct mbuf *m, *m0;
! 1316:
! 1317: if ((sc->lmc_flags & LMC_IFUP) && (sppp_isempty(ifp) == 0)) {
! 1318: m = sppp_pick(ifp);
! 1319: if ((m = lmc_txput(sc, m)) != NULL)
! 1320: return;
! 1321: m0 = sppp_dequeue(ifp);
! 1322: #if defined(LMC_DEBUG)
! 1323: if (m0 != m)
! 1324: printf("lmc_ifstart: mbuf mismatch!\n");
! 1325: #endif
! 1326: LMC_CSR_WRITE(sc, csr_txpoll, 1);
! 1327: }
! 1328: }
! 1329:
! 1330: /*
! 1331: * Set up the OS interface magic and attach to the operating system
! 1332: * network services.
! 1333: */
! 1334: void
! 1335: lmc_attach(lmc_softc_t * const sc)
! 1336: {
! 1337: struct ifnet * const ifp = &sc->lmc_if;
! 1338:
! 1339: ifp->if_flags = IFF_POINTOPOINT | IFF_MULTICAST;
! 1340: ifp->if_ioctl = lmc_ifioctl;
! 1341: ifp->if_start = lmc_ifstart;
! 1342: ifp->if_watchdog = lmc_watchdog;
! 1343: ifp->if_timer = 1;
! 1344: ifp->if_mtu = LMC_MTU;
! 1345: IFQ_SET_MAXLEN(&ifp->if_snd, IFQ_MAXLEN);
! 1346: IFQ_SET_READY(&ifp->if_snd);
! 1347:
! 1348: if_attach(ifp);
! 1349: if_alloc_sadl(ifp);
! 1350:
! 1351: sppp_attach((struct ifnet *)&sc->lmc_sppp);
! 1352: sc->lmc_sppp.pp_flags = PP_CISCO | PP_KEEPALIVE;
! 1353: sc->lmc_sppp.pp_framebytes = 3;
! 1354:
! 1355: #if NBPFILTER > 0
! 1356: LMC_BPF_ATTACH(sc);
! 1357: #endif
! 1358:
! 1359: /*
! 1360: * turn off those LEDs...
! 1361: */
! 1362: sc->lmc_miireg16 |= LMC_MII16_LED_ALL;
! 1363: /*
! 1364: * for DS3 & DS1 adapters light the green light, led2
! 1365: */
! 1366: if (sc->lmc_cardtype == LMC_CARDTYPE_DS3 ||
! 1367: sc->lmc_cardtype == LMC_CARDTYPE_T1)
! 1368: lmc_led_on (sc, LMC_MII16_LED2);
! 1369: else
! 1370: lmc_led_on (sc, LMC_MII16_LED0 | LMC_MII16_LED2);
! 1371: }
! 1372:
! 1373: void
! 1374: lmc_initring(lmc_softc_t * const sc, lmc_ringinfo_t * const ri,
! 1375: lmc_desc_t *descs, int ndescs)
! 1376: {
! 1377: ri->ri_max = ndescs;
! 1378: ri->ri_first = descs;
! 1379: ri->ri_last = ri->ri_first + ri->ri_max;
! 1380: bzero((caddr_t) ri->ri_first, sizeof(ri->ri_first[0]) * ri->ri_max);
! 1381: ri->ri_last[-1].d_ctl = htole32(LMC_CTL(TULIP_DFLAG_ENDRING, 0, 0));
! 1382: }
CVSweb