Annotation of sys/dev/pci/if_tl.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: if_tl.c,v 1.43 2007/05/08 21:19:13 deraadt Exp $ */
! 2:
! 3: /*
! 4: * Copyright (c) 1997, 1998
! 5: * Bill Paul <wpaul@ctr.columbia.edu>. 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. Redistributions in binary form must reproduce the above copyright
! 13: * notice, this list of conditions and the following disclaimer in the
! 14: * documentation and/or other materials provided with the distribution.
! 15: * 3. All advertising materials mentioning features or use of this software
! 16: * must display the following acknowledgement:
! 17: * This product includes software developed by Bill Paul.
! 18: * 4. Neither the name of the author nor the names of any co-contributors
! 19: * may be used to endorse or promote products derived from this software
! 20: * without specific prior written permission.
! 21: *
! 22: * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND
! 23: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
! 24: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
! 25: * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD
! 26: * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
! 27: * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
! 28: * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
! 29: * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
! 30: * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
! 31: * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
! 32: * THE POSSIBILITY OF SUCH DAMAGE.
! 33: *
! 34: * $FreeBSD: src/sys/pci/if_tl.c,v 1.64 2001/02/06 10:11:48 phk Exp $
! 35: */
! 36:
! 37: /*
! 38: * Texas Instruments ThunderLAN driver for FreeBSD 2.2.6 and 3.x.
! 39: * Supports many Compaq PCI NICs based on the ThunderLAN ethernet controller,
! 40: * the National Semiconductor DP83840A physical interface and the
! 41: * Microchip Technology 24Cxx series serial EEPROM.
! 42: *
! 43: * Written using the following four documents:
! 44: *
! 45: * Texas Instruments ThunderLAN Programmer's Guide (www.ti.com)
! 46: * National Semiconductor DP83840A data sheet (www.national.com)
! 47: * Microchip Technology 24C02C data sheet (www.microchip.com)
! 48: * Micro Linear ML6692 100BaseTX only PHY data sheet (www.microlinear.com)
! 49: *
! 50: * Written by Bill Paul <wpaul@ctr.columbia.edu>
! 51: * Electrical Engineering Department
! 52: * Columbia University, New York City
! 53: */
! 54:
! 55: /*
! 56: * Some notes about the ThunderLAN:
! 57: *
! 58: * The ThunderLAN controller is a single chip containing PCI controller
! 59: * logic, approximately 3K of on-board SRAM, a LAN controller, and media
! 60: * independent interface (MII) bus. The MII allows the ThunderLAN chip to
! 61: * control up to 32 different physical interfaces (PHYs). The ThunderLAN
! 62: * also has a built-in 10baseT PHY, allowing a single ThunderLAN controller
! 63: * to act as a complete ethernet interface.
! 64: *
! 65: * Other PHYs may be attached to the ThunderLAN; the Compaq 10/100 cards
! 66: * use a National Semiconductor DP83840A PHY that supports 10 or 100Mb/sec
! 67: * in full or half duplex. Some of the Compaq Deskpro machines use a
! 68: * Level 1 LXT970 PHY with the same capabilities. Certain Olicom adapters
! 69: * use a Micro Linear ML6692 100BaseTX only PHY, which can be used in
! 70: * concert with the ThunderLAN's internal PHY to provide full 10/100
! 71: * support. This is cheaper than using a standalone external PHY for both
! 72: * 10/100 modes and letting the ThunderLAN's internal PHY go to waste.
! 73: * A serial EEPROM is also attached to the ThunderLAN chip to provide
! 74: * power-up default register settings and for storing the adapter's
! 75: * station address. Although not supported by this driver, the ThunderLAN
! 76: * chip can also be connected to token ring PHYs.
! 77: *
! 78: * The ThunderLAN has a set of registers which can be used to issue
! 79: * commands, acknowledge interrupts, and to manipulate other internal
! 80: * registers on its DIO bus. The primary registers can be accessed
! 81: * using either programmed I/O (inb/outb) or via PCI memory mapping,
! 82: * depending on how the card is configured during the PCI probing
! 83: * phase. It is even possible to have both PIO and memory mapped
! 84: * access turned on at the same time.
! 85: *
! 86: * Frame reception and transmission with the ThunderLAN chip is done
! 87: * using frame 'lists.' A list structure looks more or less like this:
! 88: *
! 89: * struct tl_frag {
! 90: * u_int32_t fragment_address;
! 91: * u_int32_t fragment_size;
! 92: * };
! 93: * struct tl_list {
! 94: * u_int32_t forward_pointer;
! 95: * u_int16_t cstat;
! 96: * u_int16_t frame_size;
! 97: * struct tl_frag fragments[10];
! 98: * };
! 99: *
! 100: * The forward pointer in the list header can be either a 0 or the address
! 101: * of another list, which allows several lists to be linked together. Each
! 102: * list contains up to 10 fragment descriptors. This means the chip allows
! 103: * ethernet frames to be broken up into up to 10 chunks for transfer to
! 104: * and from the SRAM. Note that the forward pointer and fragment buffer
! 105: * addresses are physical memory addresses, not virtual. Note also that
! 106: * a single ethernet frame can not span lists: if the host wants to
! 107: * transmit a frame and the frame data is split up over more than 10
! 108: * buffers, the frame has to collapsed before it can be transmitted.
! 109: *
! 110: * To receive frames, the driver sets up a number of lists and populates
! 111: * the fragment descriptors, then it sends an RX GO command to the chip.
! 112: * When a frame is received, the chip will DMA it into the memory regions
! 113: * specified by the fragment descriptors and then trigger an RX 'end of
! 114: * frame interrupt' when done. The driver may choose to use only one
! 115: * fragment per list; this may result is slighltly less efficient use
! 116: * of memory in exchange for improving performance.
! 117: *
! 118: * To transmit frames, the driver again sets up lists and fragment
! 119: * descriptors, only this time the buffers contain frame data that
! 120: * is to be DMA'ed into the chip instead of out of it. Once the chip
! 121: * has transferred the data into its on-board SRAM, it will trigger a
! 122: * TX 'end of frame' interrupt. It will also generate an 'end of channel'
! 123: * interrupt when it reaches the end of the list.
! 124: */
! 125:
! 126: /*
! 127: * Some notes about this driver:
! 128: *
! 129: * The ThunderLAN chip provides a couple of different ways to organize
! 130: * reception, transmission and interrupt handling. The simplest approach
! 131: * is to use one list each for transmission and reception. In this mode,
! 132: * the ThunderLAN will generate two interrupts for every received frame
! 133: * (one RX EOF and one RX EOC) and two for each transmitted frame (one
! 134: * TX EOF and one TX EOC). This may make the driver simpler but it hurts
! 135: * performance to have to handle so many interrupts.
! 136: *
! 137: * Initially I wanted to create a circular list of receive buffers so
! 138: * that the ThunderLAN chip would think there was an infinitely long
! 139: * receive channel and never deliver an RXEOC interrupt. However this
! 140: * doesn't work correctly under heavy load: while the manual says the
! 141: * chip will trigger an RXEOF interrupt each time a frame is copied into
! 142: * memory, you can't count on the chip waiting around for you to acknowledge
! 143: * the interrupt before it starts trying to DMA the next frame. The result
! 144: * is that the chip might traverse the entire circular list and then wrap
! 145: * around before you have a chance to do anything about it. Consequently,
! 146: * the receive list is terminated (with a 0 in the forward pointer in the
! 147: * last element). Each time an RXEOF interrupt arrives, the used list
! 148: * is shifted to the end of the list. This gives the appearance of an
! 149: * infinitely large RX chain so long as the driver doesn't fall behind
! 150: * the chip and allow all of the lists to be filled up.
! 151: *
! 152: * If all the lists are filled, the adapter will deliver an RX 'end of
! 153: * channel' interrupt when it hits the 0 forward pointer at the end of
! 154: * the chain. The RXEOC handler then cleans out the RX chain and resets
! 155: * the list head pointer in the ch_parm register and restarts the receiver.
! 156: *
! 157: * For frame transmission, it is possible to program the ThunderLAN's
! 158: * transmit interrupt threshold so that the chip can acknowledge multiple
! 159: * lists with only a single TX EOF interrupt. This allows the driver to
! 160: * queue several frames in one shot, and only have to handle a total
! 161: * two interrupts (one TX EOF and one TX EOC) no matter how many frames
! 162: * are transmitted. Frame transmission is done directly out of the
! 163: * mbufs passed to the tl_start() routine via the interface send queue.
! 164: * The driver simply sets up the fragment descriptors in the transmit
! 165: * lists to point to the mbuf data regions and sends a TX GO command.
! 166: *
! 167: * Note that since the RX and TX lists themselves are always used
! 168: * only by the driver, the are malloc()ed once at driver initialization
! 169: * time and never free()ed.
! 170: *
! 171: * Also, in order to remain as platform independent as possible, this
! 172: * driver uses memory mapped register access to manipulate the card
! 173: * as opposed to programmed I/O. This avoids the use of the inb/outb
! 174: * (and related) instructions which are specific to the i386 platform.
! 175: *
! 176: * Using these techniques, this driver achieves very high performance
! 177: * by minimizing the amount of interrupts generated during large
! 178: * transfers and by completely avoiding buffer copies. Frame transfer
! 179: * to and from the ThunderLAN chip is performed entirely by the chip
! 180: * itself thereby reducing the load on the host CPU.
! 181: */
! 182:
! 183: #include "bpfilter.h"
! 184:
! 185: #include <sys/param.h>
! 186: #include <sys/systm.h>
! 187: #include <sys/sockio.h>
! 188: #include <sys/mbuf.h>
! 189: #include <sys/malloc.h>
! 190: #include <sys/kernel.h>
! 191: #include <sys/socket.h>
! 192: #include <sys/device.h>
! 193: #include <sys/timeout.h>
! 194:
! 195: #include <net/if.h>
! 196:
! 197: #ifdef INET
! 198: #include <netinet/in.h>
! 199: #include <netinet/in_systm.h>
! 200: #include <netinet/in_var.h>
! 201: #include <netinet/ip.h>
! 202: #include <netinet/if_ether.h>
! 203: #endif
! 204:
! 205: #include <net/if_dl.h>
! 206: #include <net/if_media.h>
! 207:
! 208: #if NBPFILTER > 0
! 209: #include <net/bpf.h>
! 210: #endif
! 211:
! 212: #include <uvm/uvm_extern.h> /* for vtophys */
! 213: #define VTOPHYS(v) vtophys((vaddr_t)(v))
! 214:
! 215: #include <dev/mii/mii.h>
! 216: #include <dev/mii/miivar.h>
! 217:
! 218: #include <dev/pci/pcireg.h>
! 219: #include <dev/pci/pcivar.h>
! 220: #include <dev/pci/pcidevs.h>
! 221:
! 222: /*
! 223: * Default to using PIO register access mode to pacify certain
! 224: * laptop docking stations with built-in ThunderLAN chips that
! 225: * don't seem to handle memory mapped mode properly.
! 226: */
! 227: #define TL_USEIOSPACE
! 228:
! 229: #include <dev/pci/if_tlreg.h>
! 230: #include <dev/mii/tlphyvar.h>
! 231:
! 232: const struct tl_products tl_prods[] = {
! 233: { PCI_VENDOR_COMPAQ, PCI_PRODUCT_COMPAQ_N100TX, TLPHY_MEDIA_NO_10_T },
! 234: { PCI_VENDOR_COMPAQ, PCI_PRODUCT_COMPAQ_N10T, TLPHY_MEDIA_10_5 },
! 235: { PCI_VENDOR_COMPAQ, PCI_PRODUCT_COMPAQ_IntNF3P, TLPHY_MEDIA_10_2 },
! 236: { PCI_VENDOR_COMPAQ, PCI_PRODUCT_COMPAQ_IntPL100TX, TLPHY_MEDIA_10_5|TLPHY_MEDIA_NO_10_T },
! 237: { PCI_VENDOR_COMPAQ, PCI_PRODUCT_COMPAQ_DPNet100TX, TLPHY_MEDIA_10_5|TLPHY_MEDIA_NO_10_T },
! 238: { PCI_VENDOR_COMPAQ, PCI_PRODUCT_COMPAQ_DP4000, TLPHY_MEDIA_10_5|TLPHY_MEDIA_NO_10_T },
! 239: { PCI_VENDOR_COMPAQ, PCI_PRODUCT_COMPAQ_NF3P_BNC, TLPHY_MEDIA_10_2 },
! 240: { PCI_VENDOR_COMPAQ, PCI_PRODUCT_COMPAQ_NF3P, TLPHY_MEDIA_10_5 },
! 241: { PCI_VENDOR_TI, PCI_PRODUCT_TI_TLAN, 0 },
! 242: { 0, 0, 0 }
! 243: };
! 244:
! 245: int tl_probe(struct device *, void *, void *);
! 246: void tl_attach(struct device *, struct device *, void *);
! 247: void tl_wait_up(void *);
! 248: int tl_intvec_rxeoc(void *, u_int32_t);
! 249: int tl_intvec_txeoc(void *, u_int32_t);
! 250: int tl_intvec_txeof(void *, u_int32_t);
! 251: int tl_intvec_rxeof(void *, u_int32_t);
! 252: int tl_intvec_adchk(void *, u_int32_t);
! 253: int tl_intvec_netsts(void *, u_int32_t);
! 254:
! 255: int tl_newbuf(struct tl_softc *,
! 256: struct tl_chain_onefrag *);
! 257: void tl_stats_update(void *);
! 258: int tl_encap(struct tl_softc *, struct tl_chain *,
! 259: struct mbuf *);
! 260:
! 261: int tl_intr(void *);
! 262: void tl_start(struct ifnet *);
! 263: int tl_ioctl(struct ifnet *, u_long, caddr_t);
! 264: void tl_init(void *);
! 265: void tl_stop(struct tl_softc *);
! 266: void tl_watchdog(struct ifnet *);
! 267: void tl_shutdown(void *);
! 268: int tl_ifmedia_upd(struct ifnet *);
! 269: void tl_ifmedia_sts(struct ifnet *, struct ifmediareq *);
! 270:
! 271: u_int8_t tl_eeprom_putbyte(struct tl_softc *, int);
! 272: u_int8_t tl_eeprom_getbyte(struct tl_softc *,
! 273: int, u_int8_t *);
! 274: int tl_read_eeprom(struct tl_softc *, caddr_t, int, int);
! 275:
! 276: void tl_mii_sync(struct tl_softc *);
! 277: void tl_mii_send(struct tl_softc *, u_int32_t, int);
! 278: int tl_mii_readreg(struct tl_softc *, struct tl_mii_frame *);
! 279: int tl_mii_writereg(struct tl_softc *, struct tl_mii_frame *);
! 280: int tl_miibus_readreg(struct device *, int, int);
! 281: void tl_miibus_writereg(struct device *, int, int, int);
! 282: void tl_miibus_statchg(struct device *);
! 283:
! 284: void tl_setmode(struct tl_softc *, int);
! 285: #if 0
! 286: int tl_calchash(caddr_t);
! 287: #endif
! 288: void tl_setmulti(struct tl_softc *);
! 289: void tl_setfilt(struct tl_softc *, caddr_t, int);
! 290: void tl_softreset(struct tl_softc *, int);
! 291: void tl_hardreset(struct device *);
! 292: int tl_list_rx_init(struct tl_softc *);
! 293: int tl_list_tx_init(struct tl_softc *);
! 294:
! 295: u_int8_t tl_dio_read8(struct tl_softc *, int);
! 296: u_int16_t tl_dio_read16(struct tl_softc *, int);
! 297: u_int32_t tl_dio_read32(struct tl_softc *, int);
! 298: void tl_dio_write8(struct tl_softc *, int, int);
! 299: void tl_dio_write16(struct tl_softc *, int, int);
! 300: void tl_dio_write32(struct tl_softc *, int, int);
! 301: void tl_dio_setbit(struct tl_softc *, int, int);
! 302: void tl_dio_clrbit(struct tl_softc *, int, int);
! 303: void tl_dio_setbit16(struct tl_softc *, int, int);
! 304: void tl_dio_clrbit16(struct tl_softc *, int, int);
! 305:
! 306: u_int8_t tl_dio_read8(sc, reg)
! 307: struct tl_softc *sc;
! 308: int reg;
! 309: {
! 310: CSR_WRITE_2(sc, TL_DIO_ADDR, reg);
! 311: return(CSR_READ_1(sc, TL_DIO_DATA + (reg & 3)));
! 312: }
! 313:
! 314: u_int16_t tl_dio_read16(sc, reg)
! 315: struct tl_softc *sc;
! 316: int reg;
! 317: {
! 318: CSR_WRITE_2(sc, TL_DIO_ADDR, reg);
! 319: return(CSR_READ_2(sc, TL_DIO_DATA + (reg & 3)));
! 320: }
! 321:
! 322: u_int32_t tl_dio_read32(sc, reg)
! 323: struct tl_softc *sc;
! 324: int reg;
! 325: {
! 326: CSR_WRITE_2(sc, TL_DIO_ADDR, reg);
! 327: return(CSR_READ_4(sc, TL_DIO_DATA + (reg & 3)));
! 328: }
! 329:
! 330: void tl_dio_write8(sc, reg, val)
! 331: struct tl_softc *sc;
! 332: int reg;
! 333: int val;
! 334: {
! 335: CSR_WRITE_2(sc, TL_DIO_ADDR, reg);
! 336: CSR_WRITE_1(sc, TL_DIO_DATA + (reg & 3), val);
! 337: return;
! 338: }
! 339:
! 340: void tl_dio_write16(sc, reg, val)
! 341: struct tl_softc *sc;
! 342: int reg;
! 343: int val;
! 344: {
! 345: CSR_WRITE_2(sc, TL_DIO_ADDR, reg);
! 346: CSR_WRITE_2(sc, TL_DIO_DATA + (reg & 3), val);
! 347: return;
! 348: }
! 349:
! 350: void tl_dio_write32(sc, reg, val)
! 351: struct tl_softc *sc;
! 352: int reg;
! 353: int val;
! 354: {
! 355: CSR_WRITE_2(sc, TL_DIO_ADDR, reg);
! 356: CSR_WRITE_4(sc, TL_DIO_DATA + (reg & 3), val);
! 357: return;
! 358: }
! 359:
! 360: void tl_dio_setbit(sc, reg, bit)
! 361: struct tl_softc *sc;
! 362: int reg;
! 363: int bit;
! 364: {
! 365: u_int8_t f;
! 366:
! 367: CSR_WRITE_2(sc, TL_DIO_ADDR, reg);
! 368: f = CSR_READ_1(sc, TL_DIO_DATA + (reg & 3));
! 369: f |= bit;
! 370: CSR_WRITE_1(sc, TL_DIO_DATA + (reg & 3), f);
! 371:
! 372: return;
! 373: }
! 374:
! 375: void tl_dio_clrbit(sc, reg, bit)
! 376: struct tl_softc *sc;
! 377: int reg;
! 378: int bit;
! 379: {
! 380: u_int8_t f;
! 381:
! 382: CSR_WRITE_2(sc, TL_DIO_ADDR, reg);
! 383: f = CSR_READ_1(sc, TL_DIO_DATA + (reg & 3));
! 384: f &= ~bit;
! 385: CSR_WRITE_1(sc, TL_DIO_DATA + (reg & 3), f);
! 386:
! 387: return;
! 388: }
! 389:
! 390: void tl_dio_setbit16(sc, reg, bit)
! 391: struct tl_softc *sc;
! 392: int reg;
! 393: int bit;
! 394: {
! 395: u_int16_t f;
! 396:
! 397: CSR_WRITE_2(sc, TL_DIO_ADDR, reg);
! 398: f = CSR_READ_2(sc, TL_DIO_DATA + (reg & 3));
! 399: f |= bit;
! 400: CSR_WRITE_2(sc, TL_DIO_DATA + (reg & 3), f);
! 401:
! 402: return;
! 403: }
! 404:
! 405: void tl_dio_clrbit16(sc, reg, bit)
! 406: struct tl_softc *sc;
! 407: int reg;
! 408: int bit;
! 409: {
! 410: u_int16_t f;
! 411:
! 412: CSR_WRITE_2(sc, TL_DIO_ADDR, reg);
! 413: f = CSR_READ_2(sc, TL_DIO_DATA + (reg & 3));
! 414: f &= ~bit;
! 415: CSR_WRITE_2(sc, TL_DIO_DATA + (reg & 3), f);
! 416:
! 417: return;
! 418: }
! 419:
! 420: /*
! 421: * Send an instruction or address to the EEPROM, check for ACK.
! 422: */
! 423: u_int8_t tl_eeprom_putbyte(sc, byte)
! 424: struct tl_softc *sc;
! 425: int byte;
! 426: {
! 427: int i, ack = 0;
! 428:
! 429: /*
! 430: * Make sure we're in TX mode.
! 431: */
! 432: tl_dio_setbit(sc, TL_NETSIO, TL_SIO_ETXEN);
! 433:
! 434: /*
! 435: * Feed in each bit and strobe the clock.
! 436: */
! 437: for (i = 0x80; i; i >>= 1) {
! 438: if (byte & i) {
! 439: tl_dio_setbit(sc, TL_NETSIO, TL_SIO_EDATA);
! 440: } else {
! 441: tl_dio_clrbit(sc, TL_NETSIO, TL_SIO_EDATA);
! 442: }
! 443: DELAY(1);
! 444: tl_dio_setbit(sc, TL_NETSIO, TL_SIO_ECLOK);
! 445: DELAY(1);
! 446: tl_dio_clrbit(sc, TL_NETSIO, TL_SIO_ECLOK);
! 447: }
! 448:
! 449: /*
! 450: * Turn off TX mode.
! 451: */
! 452: tl_dio_clrbit(sc, TL_NETSIO, TL_SIO_ETXEN);
! 453:
! 454: /*
! 455: * Check for ack.
! 456: */
! 457: tl_dio_setbit(sc, TL_NETSIO, TL_SIO_ECLOK);
! 458: ack = tl_dio_read8(sc, TL_NETSIO) & TL_SIO_EDATA;
! 459: tl_dio_clrbit(sc, TL_NETSIO, TL_SIO_ECLOK);
! 460:
! 461: return(ack);
! 462: }
! 463:
! 464: /*
! 465: * Read a byte of data stored in the EEPROM at address 'addr.'
! 466: */
! 467: u_int8_t tl_eeprom_getbyte(sc, addr, dest)
! 468: struct tl_softc *sc;
! 469: int addr;
! 470: u_int8_t *dest;
! 471: {
! 472: int i;
! 473: u_int8_t byte = 0;
! 474:
! 475: tl_dio_write8(sc, TL_NETSIO, 0);
! 476:
! 477: EEPROM_START;
! 478:
! 479: /*
! 480: * Send write control code to EEPROM.
! 481: */
! 482: if (tl_eeprom_putbyte(sc, EEPROM_CTL_WRITE)) {
! 483: printf("%s: failed to send write command, status: %x\n",
! 484: sc->sc_dev.dv_xname, tl_dio_read8(sc, TL_NETSIO));
! 485: return(1);
! 486: }
! 487:
! 488: /*
! 489: * Send address of byte we want to read.
! 490: */
! 491: if (tl_eeprom_putbyte(sc, addr)) {
! 492: printf("%s: failed to send address, status: %x\n",
! 493: sc->sc_dev.dv_xname, tl_dio_read8(sc, TL_NETSIO));
! 494: return(1);
! 495: }
! 496:
! 497: EEPROM_STOP;
! 498: EEPROM_START;
! 499: /*
! 500: * Send read control code to EEPROM.
! 501: */
! 502: if (tl_eeprom_putbyte(sc, EEPROM_CTL_READ)) {
! 503: printf("%s: failed to send write command, status: %x\n",
! 504: sc->sc_dev.dv_xname, tl_dio_read8(sc, TL_NETSIO));
! 505: return(1);
! 506: }
! 507:
! 508: /*
! 509: * Start reading bits from EEPROM.
! 510: */
! 511: tl_dio_clrbit(sc, TL_NETSIO, TL_SIO_ETXEN);
! 512: for (i = 0x80; i; i >>= 1) {
! 513: tl_dio_setbit(sc, TL_NETSIO, TL_SIO_ECLOK);
! 514: DELAY(1);
! 515: if (tl_dio_read8(sc, TL_NETSIO) & TL_SIO_EDATA)
! 516: byte |= i;
! 517: tl_dio_clrbit(sc, TL_NETSIO, TL_SIO_ECLOK);
! 518: DELAY(1);
! 519: }
! 520:
! 521: EEPROM_STOP;
! 522:
! 523: /*
! 524: * No ACK generated for read, so just return byte.
! 525: */
! 526:
! 527: *dest = byte;
! 528:
! 529: return(0);
! 530: }
! 531:
! 532: /*
! 533: * Read a sequence of bytes from the EEPROM.
! 534: */
! 535: int tl_read_eeprom(sc, dest, off, cnt)
! 536: struct tl_softc *sc;
! 537: caddr_t dest;
! 538: int off;
! 539: int cnt;
! 540: {
! 541: int err = 0, i;
! 542: u_int8_t byte = 0;
! 543:
! 544: for (i = 0; i < cnt; i++) {
! 545: err = tl_eeprom_getbyte(sc, off + i, &byte);
! 546: if (err)
! 547: break;
! 548: *(dest + i) = byte;
! 549: }
! 550:
! 551: return(err ? 1 : 0);
! 552: }
! 553:
! 554: void tl_mii_sync(sc)
! 555: struct tl_softc *sc;
! 556: {
! 557: int i;
! 558:
! 559: tl_dio_clrbit(sc, TL_NETSIO, TL_SIO_MTXEN);
! 560:
! 561: for (i = 0; i < 32; i++) {
! 562: tl_dio_setbit(sc, TL_NETSIO, TL_SIO_MCLK);
! 563: tl_dio_clrbit(sc, TL_NETSIO, TL_SIO_MCLK);
! 564: }
! 565:
! 566: return;
! 567: }
! 568:
! 569: void tl_mii_send(sc, bits, cnt)
! 570: struct tl_softc *sc;
! 571: u_int32_t bits;
! 572: int cnt;
! 573: {
! 574: int i;
! 575:
! 576: for (i = (0x1 << (cnt - 1)); i; i >>= 1) {
! 577: tl_dio_clrbit(sc, TL_NETSIO, TL_SIO_MCLK);
! 578: if (bits & i) {
! 579: tl_dio_setbit(sc, TL_NETSIO, TL_SIO_MDATA);
! 580: } else {
! 581: tl_dio_clrbit(sc, TL_NETSIO, TL_SIO_MDATA);
! 582: }
! 583: tl_dio_setbit(sc, TL_NETSIO, TL_SIO_MCLK);
! 584: }
! 585: }
! 586:
! 587: int tl_mii_readreg(sc, frame)
! 588: struct tl_softc *sc;
! 589: struct tl_mii_frame *frame;
! 590:
! 591: {
! 592: int i, ack, s;
! 593: int minten = 0;
! 594:
! 595: s = splnet();
! 596:
! 597: tl_mii_sync(sc);
! 598:
! 599: /*
! 600: * Set up frame for RX.
! 601: */
! 602: frame->mii_stdelim = TL_MII_STARTDELIM;
! 603: frame->mii_opcode = TL_MII_READOP;
! 604: frame->mii_turnaround = 0;
! 605: frame->mii_data = 0;
! 606:
! 607: /*
! 608: * Turn off MII interrupt by forcing MINTEN low.
! 609: */
! 610: minten = tl_dio_read8(sc, TL_NETSIO) & TL_SIO_MINTEN;
! 611: if (minten) {
! 612: tl_dio_clrbit(sc, TL_NETSIO, TL_SIO_MINTEN);
! 613: }
! 614:
! 615: /*
! 616: * Turn on data xmit.
! 617: */
! 618: tl_dio_setbit(sc, TL_NETSIO, TL_SIO_MTXEN);
! 619:
! 620: /*
! 621: * Send command/address info.
! 622: */
! 623: tl_mii_send(sc, frame->mii_stdelim, 2);
! 624: tl_mii_send(sc, frame->mii_opcode, 2);
! 625: tl_mii_send(sc, frame->mii_phyaddr, 5);
! 626: tl_mii_send(sc, frame->mii_regaddr, 5);
! 627:
! 628: /*
! 629: * Turn off xmit.
! 630: */
! 631: tl_dio_clrbit(sc, TL_NETSIO, TL_SIO_MTXEN);
! 632:
! 633: /* Idle bit */
! 634: tl_dio_clrbit(sc, TL_NETSIO, TL_SIO_MCLK);
! 635: tl_dio_setbit(sc, TL_NETSIO, TL_SIO_MCLK);
! 636:
! 637: /* Check for ack */
! 638: tl_dio_clrbit(sc, TL_NETSIO, TL_SIO_MCLK);
! 639: ack = tl_dio_read8(sc, TL_NETSIO) & TL_SIO_MDATA;
! 640:
! 641: /* Complete the cycle */
! 642: tl_dio_setbit(sc, TL_NETSIO, TL_SIO_MCLK);
! 643:
! 644: /*
! 645: * Now try reading data bits. If the ack failed, we still
! 646: * need to clock through 16 cycles to keep the PHYs in sync.
! 647: */
! 648: if (ack) {
! 649: for(i = 0; i < 16; i++) {
! 650: tl_dio_clrbit(sc, TL_NETSIO, TL_SIO_MCLK);
! 651: tl_dio_setbit(sc, TL_NETSIO, TL_SIO_MCLK);
! 652: }
! 653: goto fail;
! 654: }
! 655:
! 656: for (i = 0x8000; i; i >>= 1) {
! 657: tl_dio_clrbit(sc, TL_NETSIO, TL_SIO_MCLK);
! 658: if (!ack) {
! 659: if (tl_dio_read8(sc, TL_NETSIO) & TL_SIO_MDATA)
! 660: frame->mii_data |= i;
! 661: }
! 662: tl_dio_setbit(sc, TL_NETSIO, TL_SIO_MCLK);
! 663: }
! 664:
! 665: fail:
! 666:
! 667: tl_dio_setbit(sc, TL_NETSIO, TL_SIO_MCLK);
! 668: tl_dio_clrbit(sc, TL_NETSIO, TL_SIO_MCLK);
! 669:
! 670: /* Reenable interrupts */
! 671: if (minten) {
! 672: tl_dio_setbit(sc, TL_NETSIO, TL_SIO_MINTEN);
! 673: }
! 674:
! 675: splx(s);
! 676:
! 677: if (ack)
! 678: return(1);
! 679: return(0);
! 680: }
! 681:
! 682: int tl_mii_writereg(sc, frame)
! 683: struct tl_softc *sc;
! 684: struct tl_mii_frame *frame;
! 685:
! 686: {
! 687: int s;
! 688: int minten;
! 689:
! 690: tl_mii_sync(sc);
! 691:
! 692: s = splnet();
! 693: /*
! 694: * Set up frame for TX.
! 695: */
! 696:
! 697: frame->mii_stdelim = TL_MII_STARTDELIM;
! 698: frame->mii_opcode = TL_MII_WRITEOP;
! 699: frame->mii_turnaround = TL_MII_TURNAROUND;
! 700:
! 701: /*
! 702: * Turn off MII interrupt by forcing MINTEN low.
! 703: */
! 704: minten = tl_dio_read8(sc, TL_NETSIO) & TL_SIO_MINTEN;
! 705: if (minten) {
! 706: tl_dio_clrbit(sc, TL_NETSIO, TL_SIO_MINTEN);
! 707: }
! 708:
! 709: /*
! 710: * Turn on data output.
! 711: */
! 712: tl_dio_setbit(sc, TL_NETSIO, TL_SIO_MTXEN);
! 713:
! 714: tl_mii_send(sc, frame->mii_stdelim, 2);
! 715: tl_mii_send(sc, frame->mii_opcode, 2);
! 716: tl_mii_send(sc, frame->mii_phyaddr, 5);
! 717: tl_mii_send(sc, frame->mii_regaddr, 5);
! 718: tl_mii_send(sc, frame->mii_turnaround, 2);
! 719: tl_mii_send(sc, frame->mii_data, 16);
! 720:
! 721: tl_dio_setbit(sc, TL_NETSIO, TL_SIO_MCLK);
! 722: tl_dio_clrbit(sc, TL_NETSIO, TL_SIO_MCLK);
! 723:
! 724: /*
! 725: * Turn off xmit.
! 726: */
! 727: tl_dio_clrbit(sc, TL_NETSIO, TL_SIO_MTXEN);
! 728:
! 729: /* Reenable interrupts */
! 730: if (minten)
! 731: tl_dio_setbit(sc, TL_NETSIO, TL_SIO_MINTEN);
! 732:
! 733: splx(s);
! 734:
! 735: return(0);
! 736: }
! 737:
! 738: int tl_miibus_readreg(dev, phy, reg)
! 739: struct device *dev;
! 740: int phy, reg;
! 741: {
! 742: struct tl_softc *sc = (struct tl_softc *)dev;
! 743: struct tl_mii_frame frame;
! 744:
! 745: bzero((char *)&frame, sizeof(frame));
! 746:
! 747: frame.mii_phyaddr = phy;
! 748: frame.mii_regaddr = reg;
! 749: tl_mii_readreg(sc, &frame);
! 750:
! 751: return(frame.mii_data);
! 752: }
! 753:
! 754: void tl_miibus_writereg(dev, phy, reg, data)
! 755: struct device *dev;
! 756: int phy, reg, data;
! 757: {
! 758: struct tl_softc *sc = (struct tl_softc *)dev;
! 759: struct tl_mii_frame frame;
! 760:
! 761: bzero((char *)&frame, sizeof(frame));
! 762:
! 763: frame.mii_phyaddr = phy;
! 764: frame.mii_regaddr = reg;
! 765: frame.mii_data = data;
! 766:
! 767: tl_mii_writereg(sc, &frame);
! 768: }
! 769:
! 770: void tl_miibus_statchg(dev)
! 771: struct device *dev;
! 772: {
! 773: struct tl_softc *sc = (struct tl_softc *)dev;
! 774:
! 775: if ((sc->sc_mii.mii_media_active & IFM_GMASK) == IFM_FDX) {
! 776: tl_dio_setbit(sc, TL_NETCMD, TL_CMD_DUPLEX);
! 777: } else {
! 778: tl_dio_clrbit(sc, TL_NETCMD, TL_CMD_DUPLEX);
! 779: }
! 780: }
! 781:
! 782: /*
! 783: * Set modes for bitrate devices.
! 784: */
! 785: void tl_setmode(sc, media)
! 786: struct tl_softc *sc;
! 787: int media;
! 788: {
! 789: if (IFM_SUBTYPE(media) == IFM_10_5)
! 790: tl_dio_setbit(sc, TL_ACOMMIT, TL_AC_MTXD1);
! 791: if (IFM_SUBTYPE(media) == IFM_10_T) {
! 792: tl_dio_clrbit(sc, TL_ACOMMIT, TL_AC_MTXD1);
! 793: if ((media & IFM_GMASK) == IFM_FDX) {
! 794: tl_dio_clrbit(sc, TL_ACOMMIT, TL_AC_MTXD3);
! 795: tl_dio_setbit(sc, TL_NETCMD, TL_CMD_DUPLEX);
! 796: } else {
! 797: tl_dio_setbit(sc, TL_ACOMMIT, TL_AC_MTXD3);
! 798: tl_dio_clrbit(sc, TL_NETCMD, TL_CMD_DUPLEX);
! 799: }
! 800: }
! 801: }
! 802:
! 803: #if 0
! 804: /*
! 805: * Calculate the hash of a MAC address for programming the multicast hash
! 806: * table. This hash is simply the address split into 6-bit chunks
! 807: * XOR'd, e.g.
! 808: * byte: 000000|00 1111|1111 22|222222|333333|33 4444|4444 55|555555
! 809: * bit: 765432|10 7654|3210 76|543210|765432|10 7654|3210 76|543210
! 810: * Bytes 0-2 and 3-5 are symmetrical, so are folded together. Then
! 811: * the folded 24-bit value is split into 6-bit portions and XOR'd.
! 812: */
! 813: int tl_calchash(addr)
! 814: caddr_t addr;
! 815: {
! 816: int t;
! 817:
! 818: t = (addr[0] ^ addr[3]) << 16 | (addr[1] ^ addr[4]) << 8 |
! 819: (addr[2] ^ addr[5]);
! 820: return ((t >> 18) ^ (t >> 12) ^ (t >> 6) ^ t) & 0x3f;
! 821: }
! 822: #endif
! 823:
! 824: /*
! 825: * The ThunderLAN has a perfect MAC address filter in addition to
! 826: * the multicast hash filter. The perfect filter can be programmed
! 827: * with up to four MAC addresses. The first one is always used to
! 828: * hold the station address, which leaves us free to use the other
! 829: * three for multicast addresses.
! 830: */
! 831: void tl_setfilt(sc, addr, slot)
! 832: struct tl_softc *sc;
! 833: caddr_t addr;
! 834: int slot;
! 835: {
! 836: int i;
! 837: u_int16_t regaddr;
! 838:
! 839: regaddr = TL_AREG0_B5 + (slot * ETHER_ADDR_LEN);
! 840:
! 841: for (i = 0; i < ETHER_ADDR_LEN; i++)
! 842: tl_dio_write8(sc, regaddr + i, *(addr + i));
! 843:
! 844: return;
! 845: }
! 846:
! 847: /*
! 848: * XXX In FreeBSD 3.0, multicast addresses are managed using a doubly
! 849: * linked list. This is fine, except addresses are added from the head
! 850: * end of the list. We want to arrange for 224.0.0.1 (the "all hosts")
! 851: * group to always be in the perfect filter, but as more groups are added,
! 852: * the 224.0.0.1 entry (which is always added first) gets pushed down
! 853: * the list and ends up at the tail. So after 3 or 4 multicast groups
! 854: * are added, the all-hosts entry gets pushed out of the perfect filter
! 855: * and into the hash table.
! 856: *
! 857: * Because the multicast list is a doubly-linked list as opposed to a
! 858: * circular queue, we don't have the ability to just grab the tail of
! 859: * the list and traverse it backwards. Instead, we have to traverse
! 860: * the list once to find the tail, then traverse it again backwards to
! 861: * update the multicast filter.
! 862: */
! 863: void tl_setmulti(sc)
! 864: struct tl_softc *sc;
! 865: {
! 866: struct ifnet *ifp;
! 867: u_int32_t hashes[2] = { 0, 0 };
! 868: int h;
! 869: struct arpcom *ac = &sc->arpcom;
! 870: struct ether_multistep step;
! 871: struct ether_multi *enm;
! 872: ifp = &sc->arpcom.ac_if;
! 873:
! 874: tl_dio_write32(sc, TL_HASH1, 0);
! 875: tl_dio_write32(sc, TL_HASH2, 0);
! 876:
! 877: ifp->if_flags &= ~IFF_ALLMULTI;
! 878: #if 0
! 879: ETHER_FIRST_MULTI(step, ac, enm);
! 880: while (enm != NULL) {
! 881: if (memcmp(enm->enm_addrlo, enm->enm_addrhi, 6) == 0) {
! 882: h = tl_calchash(enm->enm_addrlo);
! 883: hashes[h/32] |= (1 << (h % 32));
! 884: } else {
! 885: hashes[0] = hashes[1] = 0xffffffff;
! 886: ifp->if_flags |= IFF_ALLMULTI;
! 887: break;
! 888: }
! 889: ETHER_NEXT_MULTI(step, enm);
! 890: }
! 891: #else
! 892: ETHER_FIRST_MULTI(step, ac, enm);
! 893: h = 0;
! 894: while (enm != NULL) {
! 895: h++;
! 896: ETHER_NEXT_MULTI(step, enm);
! 897: }
! 898: if (h) {
! 899: hashes[0] = hashes[1] = 0xffffffff;
! 900: ifp->if_flags |= IFF_ALLMULTI;
! 901: } else {
! 902: hashes[0] = hashes[1] = 0x00000000;
! 903: }
! 904: #endif
! 905:
! 906: tl_dio_write32(sc, TL_HASH1, hashes[0]);
! 907: tl_dio_write32(sc, TL_HASH2, hashes[1]);
! 908:
! 909: return;
! 910: }
! 911:
! 912: /*
! 913: * This routine is recommended by the ThunderLAN manual to insure that
! 914: * the internal PHY is powered up correctly. It also recommends a one
! 915: * second pause at the end to 'wait for the clocks to start' but in my
! 916: * experience this isn't necessary.
! 917: */
! 918: void tl_hardreset(dev)
! 919: struct device *dev;
! 920: {
! 921: struct tl_softc *sc = (struct tl_softc *)dev;
! 922: int i;
! 923: u_int16_t flags;
! 924:
! 925: flags = BMCR_LOOP|BMCR_ISO|BMCR_PDOWN;
! 926:
! 927: for (i =0 ; i < MII_NPHY; i++)
! 928: tl_miibus_writereg(dev, i, MII_BMCR, flags);
! 929:
! 930: tl_miibus_writereg(dev, 31, MII_BMCR, BMCR_ISO);
! 931: tl_mii_sync(sc);
! 932: while(tl_miibus_readreg(dev, 31, MII_BMCR) & BMCR_RESET);
! 933:
! 934: DELAY(5000);
! 935: return;
! 936: }
! 937:
! 938: void tl_softreset(sc, internal)
! 939: struct tl_softc *sc;
! 940: int internal;
! 941: {
! 942: u_int32_t cmd, dummy, i;
! 943:
! 944: /* Assert the adapter reset bit. */
! 945: CMD_SET(sc, TL_CMD_ADRST);
! 946: /* Turn off interrupts */
! 947: CMD_SET(sc, TL_CMD_INTSOFF);
! 948:
! 949: /* First, clear the stats registers. */
! 950: for (i = 0; i < 5; i++)
! 951: dummy = tl_dio_read32(sc, TL_TXGOODFRAMES);
! 952:
! 953: /* Clear Areg and Hash registers */
! 954: for (i = 0; i < 8; i++)
! 955: tl_dio_write32(sc, TL_AREG0_B5, 0x00000000);
! 956:
! 957: /*
! 958: * Set up Netconfig register. Enable one channel and
! 959: * one fragment mode.
! 960: */
! 961: tl_dio_setbit16(sc, TL_NETCONFIG, TL_CFG_ONECHAN|TL_CFG_ONEFRAG);
! 962: if (internal && !sc->tl_bitrate) {
! 963: tl_dio_setbit16(sc, TL_NETCONFIG, TL_CFG_PHYEN);
! 964: } else {
! 965: tl_dio_clrbit16(sc, TL_NETCONFIG, TL_CFG_PHYEN);
! 966: }
! 967:
! 968: /* Handle cards with bitrate devices. */
! 969: if (sc->tl_bitrate)
! 970: tl_dio_setbit16(sc, TL_NETCONFIG, TL_CFG_BITRATE);
! 971:
! 972: /*
! 973: * Load adapter irq pacing timer and tx threshold.
! 974: * We make the transmit threshold 1 initially but we may
! 975: * change that later.
! 976: */
! 977: cmd = CSR_READ_4(sc, TL_HOSTCMD);
! 978: cmd |= TL_CMD_NES;
! 979: cmd &= ~(TL_CMD_RT|TL_CMD_EOC|TL_CMD_ACK_MASK|TL_CMD_CHSEL_MASK);
! 980: CMD_PUT(sc, cmd | (TL_CMD_LDTHR | TX_THR));
! 981: CMD_PUT(sc, cmd | (TL_CMD_LDTMR | 0x00000003));
! 982:
! 983: /* Unreset the MII */
! 984: tl_dio_setbit(sc, TL_NETSIO, TL_SIO_NMRST);
! 985:
! 986: /* Take the adapter out of reset */
! 987: tl_dio_setbit(sc, TL_NETCMD, TL_CMD_NRESET|TL_CMD_NWRAP);
! 988:
! 989: /* Wait for things to settle down a little. */
! 990: DELAY(500);
! 991:
! 992: return;
! 993: }
! 994:
! 995: /*
! 996: * Initialize the transmit lists.
! 997: */
! 998: int tl_list_tx_init(sc)
! 999: struct tl_softc *sc;
! 1000: {
! 1001: struct tl_chain_data *cd;
! 1002: struct tl_list_data *ld;
! 1003: int i;
! 1004:
! 1005: cd = &sc->tl_cdata;
! 1006: ld = sc->tl_ldata;
! 1007: for (i = 0; i < TL_TX_LIST_CNT; i++) {
! 1008: cd->tl_tx_chain[i].tl_ptr = &ld->tl_tx_list[i];
! 1009: if (i == (TL_TX_LIST_CNT - 1))
! 1010: cd->tl_tx_chain[i].tl_next = NULL;
! 1011: else
! 1012: cd->tl_tx_chain[i].tl_next = &cd->tl_tx_chain[i + 1];
! 1013: }
! 1014:
! 1015: cd->tl_tx_free = &cd->tl_tx_chain[0];
! 1016: cd->tl_tx_tail = cd->tl_tx_head = NULL;
! 1017: sc->tl_txeoc = 1;
! 1018:
! 1019: return(0);
! 1020: }
! 1021:
! 1022: /*
! 1023: * Initialize the RX lists and allocate mbufs for them.
! 1024: */
! 1025: int tl_list_rx_init(sc)
! 1026: struct tl_softc *sc;
! 1027: {
! 1028: struct tl_chain_data *cd;
! 1029: struct tl_list_data *ld;
! 1030: int i;
! 1031:
! 1032: cd = &sc->tl_cdata;
! 1033: ld = sc->tl_ldata;
! 1034:
! 1035: for (i = 0; i < TL_RX_LIST_CNT; i++) {
! 1036: cd->tl_rx_chain[i].tl_ptr =
! 1037: (struct tl_list_onefrag *)&ld->tl_rx_list[i];
! 1038: if (tl_newbuf(sc, &cd->tl_rx_chain[i]) == ENOBUFS)
! 1039: return(ENOBUFS);
! 1040: if (i == (TL_RX_LIST_CNT - 1)) {
! 1041: cd->tl_rx_chain[i].tl_next = NULL;
! 1042: ld->tl_rx_list[i].tlist_fptr = 0;
! 1043: } else {
! 1044: cd->tl_rx_chain[i].tl_next = &cd->tl_rx_chain[i + 1];
! 1045: ld->tl_rx_list[i].tlist_fptr =
! 1046: VTOPHYS(&ld->tl_rx_list[i + 1]);
! 1047: }
! 1048: }
! 1049:
! 1050: cd->tl_rx_head = &cd->tl_rx_chain[0];
! 1051: cd->tl_rx_tail = &cd->tl_rx_chain[TL_RX_LIST_CNT - 1];
! 1052:
! 1053: return(0);
! 1054: }
! 1055:
! 1056: int tl_newbuf(sc, c)
! 1057: struct tl_softc *sc;
! 1058: struct tl_chain_onefrag *c;
! 1059: {
! 1060: struct mbuf *m_new = NULL;
! 1061:
! 1062: MGETHDR(m_new, M_DONTWAIT, MT_DATA);
! 1063: if (m_new == NULL) {
! 1064: return(ENOBUFS);
! 1065: }
! 1066:
! 1067: MCLGET(m_new, M_DONTWAIT);
! 1068: if (!(m_new->m_flags & M_EXT)) {
! 1069: m_freem(m_new);
! 1070: return(ENOBUFS);
! 1071: }
! 1072:
! 1073: #ifdef __alpha__
! 1074: m_new->m_data += 2;
! 1075: #endif
! 1076:
! 1077: c->tl_mbuf = m_new;
! 1078: c->tl_next = NULL;
! 1079: c->tl_ptr->tlist_frsize = MCLBYTES;
! 1080: c->tl_ptr->tlist_fptr = 0;
! 1081: c->tl_ptr->tl_frag.tlist_dadr = VTOPHYS(mtod(m_new, caddr_t));
! 1082: c->tl_ptr->tl_frag.tlist_dcnt = MCLBYTES;
! 1083: c->tl_ptr->tlist_cstat = TL_CSTAT_READY;
! 1084:
! 1085: return(0);
! 1086: }
! 1087: /*
! 1088: * Interrupt handler for RX 'end of frame' condition (EOF). This
! 1089: * tells us that a full ethernet frame has been captured and we need
! 1090: * to handle it.
! 1091: *
! 1092: * Reception is done using 'lists' which consist of a header and a
! 1093: * series of 10 data count/data address pairs that point to buffers.
! 1094: * Initially you're supposed to create a list, populate it with pointers
! 1095: * to buffers, then load the physical address of the list into the
! 1096: * ch_parm register. The adapter is then supposed to DMA the received
! 1097: * frame into the buffers for you.
! 1098: *
! 1099: * To make things as fast as possible, we have the chip DMA directly
! 1100: * into mbufs. This saves us from having to do a buffer copy: we can
! 1101: * just hand the mbufs directly to ether_input(). Once the frame has
! 1102: * been sent on its way, the 'list' structure is assigned a new buffer
! 1103: * and moved to the end of the RX chain. As long we we stay ahead of
! 1104: * the chip, it will always think it has an endless receive channel.
! 1105: *
! 1106: * If we happen to fall behind and the chip manages to fill up all of
! 1107: * the buffers, it will generate an end of channel interrupt and wait
! 1108: * for us to empty the chain and restart the receiver.
! 1109: */
! 1110: int tl_intvec_rxeof(xsc, type)
! 1111: void *xsc;
! 1112: u_int32_t type;
! 1113: {
! 1114: struct tl_softc *sc;
! 1115: int r = 0, total_len = 0;
! 1116: struct ether_header *eh;
! 1117: struct mbuf *m;
! 1118: struct ifnet *ifp;
! 1119: struct tl_chain_onefrag *cur_rx;
! 1120:
! 1121: sc = xsc;
! 1122: ifp = &sc->arpcom.ac_if;
! 1123:
! 1124: while(sc->tl_cdata.tl_rx_head != NULL) {
! 1125: cur_rx = sc->tl_cdata.tl_rx_head;
! 1126: if (!(cur_rx->tl_ptr->tlist_cstat & TL_CSTAT_FRAMECMP))
! 1127: break;
! 1128: r++;
! 1129: sc->tl_cdata.tl_rx_head = cur_rx->tl_next;
! 1130: m = cur_rx->tl_mbuf;
! 1131: total_len = cur_rx->tl_ptr->tlist_frsize;
! 1132:
! 1133: if (tl_newbuf(sc, cur_rx) == ENOBUFS) {
! 1134: ifp->if_ierrors++;
! 1135: cur_rx->tl_ptr->tlist_frsize = MCLBYTES;
! 1136: cur_rx->tl_ptr->tlist_cstat = TL_CSTAT_READY;
! 1137: cur_rx->tl_ptr->tl_frag.tlist_dcnt = MCLBYTES;
! 1138: continue;
! 1139: }
! 1140:
! 1141: sc->tl_cdata.tl_rx_tail->tl_ptr->tlist_fptr =
! 1142: VTOPHYS(cur_rx->tl_ptr);
! 1143: sc->tl_cdata.tl_rx_tail->tl_next = cur_rx;
! 1144: sc->tl_cdata.tl_rx_tail = cur_rx;
! 1145:
! 1146: eh = mtod(m, struct ether_header *);
! 1147: m->m_pkthdr.rcvif = ifp;
! 1148:
! 1149: /*
! 1150: * Note: when the ThunderLAN chip is in 'capture all
! 1151: * frames' mode, it will receive its own transmissions.
! 1152: * We drop don't need to process our own transmissions,
! 1153: * so we drop them here and continue.
! 1154: */
! 1155: /*if (ifp->if_flags & IFF_PROMISC && */
! 1156: if (!bcmp(eh->ether_shost, sc->arpcom.ac_enaddr,
! 1157: ETHER_ADDR_LEN)) {
! 1158: m_freem(m);
! 1159: continue;
! 1160: }
! 1161:
! 1162: m->m_pkthdr.len = m->m_len = total_len;
! 1163: #if NBPFILTER > 0
! 1164: /*
! 1165: * Handle BPF listeners. Let the BPF user see the packet, but
! 1166: * don't pass it up to the ether_input() layer unless it's
! 1167: * a broadcast packet, multicast packet, matches our ethernet
! 1168: * address or the interface is in promiscuous mode. If we don't
! 1169: * want the packet, just forget it. We leave the mbuf in place
! 1170: * since it can be used again later.
! 1171: */
! 1172: if (ifp->if_bpf) {
! 1173: bpf_mtap(ifp->if_bpf, m, BPF_DIRECTION_IN);
! 1174: }
! 1175: #endif
! 1176: /* pass it on. */
! 1177: ether_input_mbuf(ifp, m);
! 1178: }
! 1179:
! 1180: return(r);
! 1181: }
! 1182:
! 1183: /*
! 1184: * The RX-EOC condition hits when the ch_parm address hasn't been
! 1185: * initialized or the adapter reached a list with a forward pointer
! 1186: * of 0 (which indicates the end of the chain). In our case, this means
! 1187: * the card has hit the end of the receive buffer chain and we need to
! 1188: * empty out the buffers and shift the pointer back to the beginning again.
! 1189: */
! 1190: int tl_intvec_rxeoc(xsc, type)
! 1191: void *xsc;
! 1192: u_int32_t type;
! 1193: {
! 1194: struct tl_softc *sc;
! 1195: int r;
! 1196: struct tl_chain_data *cd;
! 1197:
! 1198: sc = xsc;
! 1199: cd = &sc->tl_cdata;
! 1200:
! 1201: /* Flush out the receive queue and ack RXEOF interrupts. */
! 1202: r = tl_intvec_rxeof(xsc, type);
! 1203: CMD_PUT(sc, TL_CMD_ACK | r | (type & ~(0x00100000)));
! 1204: r = 1;
! 1205: cd->tl_rx_head = &cd->tl_rx_chain[0];
! 1206: cd->tl_rx_tail = &cd->tl_rx_chain[TL_RX_LIST_CNT - 1];
! 1207: CSR_WRITE_4(sc, TL_CH_PARM, VTOPHYS(sc->tl_cdata.tl_rx_head->tl_ptr));
! 1208: r |= (TL_CMD_GO|TL_CMD_RT);
! 1209: return(r);
! 1210: }
! 1211:
! 1212: int tl_intvec_txeof(xsc, type)
! 1213: void *xsc;
! 1214: u_int32_t type;
! 1215: {
! 1216: struct tl_softc *sc;
! 1217: int r = 0;
! 1218: struct tl_chain *cur_tx;
! 1219:
! 1220: sc = xsc;
! 1221:
! 1222: /*
! 1223: * Go through our tx list and free mbufs for those
! 1224: * frames that have been sent.
! 1225: */
! 1226: while (sc->tl_cdata.tl_tx_head != NULL) {
! 1227: cur_tx = sc->tl_cdata.tl_tx_head;
! 1228: if (!(cur_tx->tl_ptr->tlist_cstat & TL_CSTAT_FRAMECMP))
! 1229: break;
! 1230: sc->tl_cdata.tl_tx_head = cur_tx->tl_next;
! 1231:
! 1232: r++;
! 1233: m_freem(cur_tx->tl_mbuf);
! 1234: cur_tx->tl_mbuf = NULL;
! 1235:
! 1236: cur_tx->tl_next = sc->tl_cdata.tl_tx_free;
! 1237: sc->tl_cdata.tl_tx_free = cur_tx;
! 1238: if (!cur_tx->tl_ptr->tlist_fptr)
! 1239: break;
! 1240: }
! 1241:
! 1242: return(r);
! 1243: }
! 1244:
! 1245: /*
! 1246: * The transmit end of channel interrupt. The adapter triggers this
! 1247: * interrupt to tell us it hit the end of the current transmit list.
! 1248: *
! 1249: * A note about this: it's possible for a condition to arise where
! 1250: * tl_start() may try to send frames between TXEOF and TXEOC interrupts.
! 1251: * You have to avoid this since the chip expects things to go in a
! 1252: * particular order: transmit, acknowledge TXEOF, acknowledge TXEOC.
! 1253: * When the TXEOF handler is called, it will free all of the transmitted
! 1254: * frames and reset the tx_head pointer to NULL. However, a TXEOC
! 1255: * interrupt should be received and acknowledged before any more frames
! 1256: * are queued for transmission. If tl_statrt() is called after TXEOF
! 1257: * resets the tx_head pointer but _before_ the TXEOC interrupt arrives,
! 1258: * it could attempt to issue a transmit command prematurely.
! 1259: *
! 1260: * To guard against this, tl_start() will only issue transmit commands
! 1261: * if the tl_txeoc flag is set, and only the TXEOC interrupt handler
! 1262: * can set this flag once tl_start() has cleared it.
! 1263: */
! 1264: int tl_intvec_txeoc(xsc, type)
! 1265: void *xsc;
! 1266: u_int32_t type;
! 1267: {
! 1268: struct tl_softc *sc;
! 1269: struct ifnet *ifp;
! 1270: u_int32_t cmd;
! 1271:
! 1272: sc = xsc;
! 1273: ifp = &sc->arpcom.ac_if;
! 1274:
! 1275: /* Clear the timeout timer. */
! 1276: ifp->if_timer = 0;
! 1277:
! 1278: if (sc->tl_cdata.tl_tx_head == NULL) {
! 1279: ifp->if_flags &= ~IFF_OACTIVE;
! 1280: sc->tl_cdata.tl_tx_tail = NULL;
! 1281: sc->tl_txeoc = 1;
! 1282: } else {
! 1283: sc->tl_txeoc = 0;
! 1284: /* First we have to ack the EOC interrupt. */
! 1285: CMD_PUT(sc, TL_CMD_ACK | 0x00000001 | type);
! 1286: /* Then load the address of the next TX list. */
! 1287: CSR_WRITE_4(sc, TL_CH_PARM,
! 1288: VTOPHYS(sc->tl_cdata.tl_tx_head->tl_ptr));
! 1289: /* Restart TX channel. */
! 1290: cmd = CSR_READ_4(sc, TL_HOSTCMD);
! 1291: cmd &= ~TL_CMD_RT;
! 1292: cmd |= TL_CMD_GO|TL_CMD_INTSON;
! 1293: CMD_PUT(sc, cmd);
! 1294: return(0);
! 1295: }
! 1296:
! 1297: return(1);
! 1298: }
! 1299:
! 1300: int tl_intvec_adchk(xsc, type)
! 1301: void *xsc;
! 1302: u_int32_t type;
! 1303: {
! 1304: struct tl_softc *sc;
! 1305:
! 1306: sc = xsc;
! 1307:
! 1308: if (type)
! 1309: printf("%s: adapter check: %x\n", sc->sc_dev.dv_xname,
! 1310: (unsigned int)CSR_READ_4(sc, TL_CH_PARM));
! 1311:
! 1312: tl_softreset(sc, 1);
! 1313: tl_stop(sc);
! 1314: tl_init(sc);
! 1315: CMD_SET(sc, TL_CMD_INTSON);
! 1316:
! 1317: return(0);
! 1318: }
! 1319:
! 1320: int tl_intvec_netsts(xsc, type)
! 1321: void *xsc;
! 1322: u_int32_t type;
! 1323: {
! 1324: struct tl_softc *sc;
! 1325: u_int16_t netsts;
! 1326:
! 1327: sc = xsc;
! 1328:
! 1329: netsts = tl_dio_read16(sc, TL_NETSTS);
! 1330: tl_dio_write16(sc, TL_NETSTS, netsts);
! 1331:
! 1332: printf("%s: network status: %x\n", sc->sc_dev.dv_xname, netsts);
! 1333:
! 1334: return(1);
! 1335: }
! 1336:
! 1337: int tl_intr(xsc)
! 1338: void *xsc;
! 1339: {
! 1340: struct tl_softc *sc;
! 1341: struct ifnet *ifp;
! 1342: int r = 0;
! 1343: u_int32_t type = 0;
! 1344: u_int16_t ints = 0;
! 1345: u_int8_t ivec = 0;
! 1346:
! 1347: sc = xsc;
! 1348:
! 1349: /* Disable interrupts */
! 1350: ints = CSR_READ_2(sc, TL_HOST_INT);
! 1351: CSR_WRITE_2(sc, TL_HOST_INT, ints);
! 1352: type = (ints << 16) & 0xFFFF0000;
! 1353: ivec = (ints & TL_VEC_MASK) >> 5;
! 1354: ints = (ints & TL_INT_MASK) >> 2;
! 1355:
! 1356: ifp = &sc->arpcom.ac_if;
! 1357:
! 1358: switch(ints) {
! 1359: case (TL_INTR_INVALID):
! 1360: /* Re-enable interrupts but don't ack this one. */
! 1361: CMD_PUT(sc, type);
! 1362: r = 0;
! 1363: break;
! 1364: case (TL_INTR_TXEOF):
! 1365: r = tl_intvec_txeof((void *)sc, type);
! 1366: break;
! 1367: case (TL_INTR_TXEOC):
! 1368: r = tl_intvec_txeoc((void *)sc, type);
! 1369: break;
! 1370: case (TL_INTR_STATOFLOW):
! 1371: tl_stats_update(sc);
! 1372: r = 1;
! 1373: break;
! 1374: case (TL_INTR_RXEOF):
! 1375: r = tl_intvec_rxeof((void *)sc, type);
! 1376: break;
! 1377: case (TL_INTR_DUMMY):
! 1378: printf("%s: got a dummy interrupt\n", sc->sc_dev.dv_xname);
! 1379: r = 1;
! 1380: break;
! 1381: case (TL_INTR_ADCHK):
! 1382: if (ivec)
! 1383: r = tl_intvec_adchk((void *)sc, type);
! 1384: else
! 1385: r = tl_intvec_netsts((void *)sc, type);
! 1386: break;
! 1387: case (TL_INTR_RXEOC):
! 1388: r = tl_intvec_rxeoc((void *)sc, type);
! 1389: break;
! 1390: default:
! 1391: printf("%s: bogus interrupt type\n", sc->sc_dev.dv_xname);
! 1392: break;
! 1393: }
! 1394:
! 1395: /* Re-enable interrupts */
! 1396: if (r) {
! 1397: CMD_PUT(sc, TL_CMD_ACK | r | type);
! 1398: }
! 1399:
! 1400: if (!IFQ_IS_EMPTY(&ifp->if_snd))
! 1401: tl_start(ifp);
! 1402:
! 1403: return r;
! 1404: }
! 1405:
! 1406: void tl_stats_update(xsc)
! 1407: void *xsc;
! 1408: {
! 1409: struct tl_softc *sc;
! 1410: struct ifnet *ifp;
! 1411: struct tl_stats tl_stats;
! 1412: u_int32_t *p;
! 1413: int s;
! 1414:
! 1415: s = splnet();
! 1416:
! 1417: bzero((char *)&tl_stats, sizeof(struct tl_stats));
! 1418:
! 1419: sc = xsc;
! 1420: ifp = &sc->arpcom.ac_if;
! 1421:
! 1422: p = (u_int32_t *)&tl_stats;
! 1423:
! 1424: CSR_WRITE_2(sc, TL_DIO_ADDR, TL_TXGOODFRAMES|TL_DIO_ADDR_INC);
! 1425: *p++ = CSR_READ_4(sc, TL_DIO_DATA);
! 1426: *p++ = CSR_READ_4(sc, TL_DIO_DATA);
! 1427: *p++ = CSR_READ_4(sc, TL_DIO_DATA);
! 1428: *p++ = CSR_READ_4(sc, TL_DIO_DATA);
! 1429: *p++ = CSR_READ_4(sc, TL_DIO_DATA);
! 1430:
! 1431: ifp->if_opackets += tl_tx_goodframes(tl_stats);
! 1432: ifp->if_collisions += tl_stats.tl_tx_single_collision +
! 1433: tl_stats.tl_tx_multi_collision;
! 1434: ifp->if_ipackets += tl_rx_goodframes(tl_stats);
! 1435: ifp->if_ierrors += tl_stats.tl_crc_errors + tl_stats.tl_code_errors +
! 1436: tl_rx_overrun(tl_stats);
! 1437: ifp->if_oerrors += tl_tx_underrun(tl_stats);
! 1438:
! 1439: if (tl_tx_underrun(tl_stats)) {
! 1440: u_int8_t tx_thresh;
! 1441: tx_thresh = tl_dio_read8(sc, TL_ACOMMIT) & TL_AC_TXTHRESH;
! 1442: if (tx_thresh != TL_AC_TXTHRESH_WHOLEPKT) {
! 1443: tx_thresh >>= 4;
! 1444: tx_thresh++;
! 1445: tl_dio_clrbit(sc, TL_ACOMMIT, TL_AC_TXTHRESH);
! 1446: tl_dio_setbit(sc, TL_ACOMMIT, tx_thresh << 4);
! 1447: }
! 1448: }
! 1449:
! 1450: timeout_add(&sc->tl_stats_tmo, hz);
! 1451:
! 1452: if (!sc->tl_bitrate)
! 1453: mii_tick(&sc->sc_mii);
! 1454:
! 1455: splx(s);
! 1456: return;
! 1457: }
! 1458:
! 1459: /*
! 1460: * Encapsulate an mbuf chain in a list by coupling the mbuf data
! 1461: * pointers to the fragment pointers.
! 1462: */
! 1463: int tl_encap(sc, c, m_head)
! 1464: struct tl_softc *sc;
! 1465: struct tl_chain *c;
! 1466: struct mbuf *m_head;
! 1467: {
! 1468: int frag = 0;
! 1469: struct tl_frag *f = NULL;
! 1470: int total_len;
! 1471: struct mbuf *m;
! 1472:
! 1473: /*
! 1474: * Start packing the mbufs in this chain into
! 1475: * the fragment pointers. Stop when we run out
! 1476: * of fragments or hit the end of the mbuf chain.
! 1477: */
! 1478: m = m_head;
! 1479: total_len = 0;
! 1480:
! 1481: for (m = m_head, frag = 0; m != NULL; m = m->m_next) {
! 1482: if (m->m_len != 0) {
! 1483: if (frag == TL_MAXFRAGS)
! 1484: break;
! 1485: total_len+= m->m_len;
! 1486: c->tl_ptr->tl_frag[frag].tlist_dadr =
! 1487: VTOPHYS(mtod(m, vaddr_t));
! 1488: c->tl_ptr->tl_frag[frag].tlist_dcnt = m->m_len;
! 1489: frag++;
! 1490: }
! 1491: }
! 1492:
! 1493: /*
! 1494: * Handle special cases.
! 1495: * Special case #1: we used up all 10 fragments, but
! 1496: * we have more mbufs left in the chain. Copy the
! 1497: * data into an mbuf cluster. Note that we don't
! 1498: * bother clearing the values in the other fragment
! 1499: * pointers/counters; it wouldn't gain us anything,
! 1500: * and would waste cycles.
! 1501: */
! 1502: if (m != NULL) {
! 1503: struct mbuf *m_new = NULL;
! 1504:
! 1505: MGETHDR(m_new, M_DONTWAIT, MT_DATA);
! 1506: if (m_new == NULL) {
! 1507: return(1);
! 1508: }
! 1509: if (m_head->m_pkthdr.len > MHLEN) {
! 1510: MCLGET(m_new, M_DONTWAIT);
! 1511: if (!(m_new->m_flags & M_EXT)) {
! 1512: m_freem(m_new);
! 1513: return(1);
! 1514: }
! 1515: }
! 1516: m_copydata(m_head, 0, m_head->m_pkthdr.len,
! 1517: mtod(m_new, caddr_t));
! 1518: m_new->m_pkthdr.len = m_new->m_len = m_head->m_pkthdr.len;
! 1519: m_freem(m_head);
! 1520: m_head = m_new;
! 1521: f = &c->tl_ptr->tl_frag[0];
! 1522: f->tlist_dadr = VTOPHYS(mtod(m_new, caddr_t));
! 1523: f->tlist_dcnt = total_len = m_new->m_len;
! 1524: frag = 1;
! 1525: }
! 1526:
! 1527: /*
! 1528: * Special case #2: the frame is smaller than the minimum
! 1529: * frame size. We have to pad it to make the chip happy.
! 1530: */
! 1531: if (total_len < TL_MIN_FRAMELEN) {
! 1532: f = &c->tl_ptr->tl_frag[frag];
! 1533: f->tlist_dcnt = TL_MIN_FRAMELEN - total_len;
! 1534: f->tlist_dadr = VTOPHYS(&sc->tl_ldata->tl_pad);
! 1535: total_len += f->tlist_dcnt;
! 1536: frag++;
! 1537: }
! 1538:
! 1539: c->tl_mbuf = m_head;
! 1540: c->tl_ptr->tl_frag[frag - 1].tlist_dcnt |= TL_LAST_FRAG;
! 1541: c->tl_ptr->tlist_frsize = total_len;
! 1542: c->tl_ptr->tlist_cstat = TL_CSTAT_READY;
! 1543: c->tl_ptr->tlist_fptr = 0;
! 1544:
! 1545: return(0);
! 1546: }
! 1547:
! 1548: /*
! 1549: * Main transmit routine. To avoid having to do mbuf copies, we put pointers
! 1550: * to the mbuf data regions directly in the transmit lists. We also save a
! 1551: * copy of the pointers since the transmit list fragment pointers are
! 1552: * physical addresses.
! 1553: */
! 1554: void tl_start(ifp)
! 1555: struct ifnet *ifp;
! 1556: {
! 1557: struct tl_softc *sc;
! 1558: struct mbuf *m_head = NULL;
! 1559: u_int32_t cmd;
! 1560: struct tl_chain *prev = NULL, *cur_tx = NULL, *start_tx;
! 1561:
! 1562: sc = ifp->if_softc;
! 1563:
! 1564: /*
! 1565: * Check for an available queue slot. If there are none,
! 1566: * punt.
! 1567: */
! 1568: if (sc->tl_cdata.tl_tx_free == NULL) {
! 1569: ifp->if_flags |= IFF_OACTIVE;
! 1570: return;
! 1571: }
! 1572:
! 1573: start_tx = sc->tl_cdata.tl_tx_free;
! 1574:
! 1575: while(sc->tl_cdata.tl_tx_free != NULL) {
! 1576: IFQ_DEQUEUE(&ifp->if_snd, m_head);
! 1577: if (m_head == NULL)
! 1578: break;
! 1579:
! 1580: /* Pick a chain member off the free list. */
! 1581: cur_tx = sc->tl_cdata.tl_tx_free;
! 1582: sc->tl_cdata.tl_tx_free = cur_tx->tl_next;
! 1583:
! 1584: cur_tx->tl_next = NULL;
! 1585:
! 1586: /* Pack the data into the list. */
! 1587: tl_encap(sc, cur_tx, m_head);
! 1588:
! 1589: /* Chain it together */
! 1590: if (prev != NULL) {
! 1591: prev->tl_next = cur_tx;
! 1592: prev->tl_ptr->tlist_fptr = VTOPHYS(cur_tx->tl_ptr);
! 1593: }
! 1594: prev = cur_tx;
! 1595:
! 1596: /*
! 1597: * If there's a BPF listener, bounce a copy of this frame
! 1598: * to him.
! 1599: */
! 1600: #if NBPFILTER > 0
! 1601: if (ifp->if_bpf)
! 1602: bpf_mtap(ifp->if_bpf, cur_tx->tl_mbuf,
! 1603: BPF_DIRECTION_OUT);
! 1604: #endif
! 1605: }
! 1606:
! 1607: /*
! 1608: * If there are no packets queued, bail.
! 1609: */
! 1610: if (cur_tx == NULL)
! 1611: return;
! 1612:
! 1613: /*
! 1614: * That's all we can stands, we can't stands no more.
! 1615: * If there are no other transfers pending, then issue the
! 1616: * TX GO command to the adapter to start things moving.
! 1617: * Otherwise, just leave the data in the queue and let
! 1618: * the EOF/EOC interrupt handler send.
! 1619: */
! 1620: if (sc->tl_cdata.tl_tx_head == NULL) {
! 1621: sc->tl_cdata.tl_tx_head = start_tx;
! 1622: sc->tl_cdata.tl_tx_tail = cur_tx;
! 1623:
! 1624: if (sc->tl_txeoc) {
! 1625: sc->tl_txeoc = 0;
! 1626: CSR_WRITE_4(sc, TL_CH_PARM, VTOPHYS(start_tx->tl_ptr));
! 1627: cmd = CSR_READ_4(sc, TL_HOSTCMD);
! 1628: cmd &= ~TL_CMD_RT;
! 1629: cmd |= TL_CMD_GO|TL_CMD_INTSON;
! 1630: CMD_PUT(sc, cmd);
! 1631: }
! 1632: } else {
! 1633: sc->tl_cdata.tl_tx_tail->tl_next = start_tx;
! 1634: sc->tl_cdata.tl_tx_tail = cur_tx;
! 1635: }
! 1636:
! 1637: /*
! 1638: * Set a timeout in case the chip goes out to lunch.
! 1639: */
! 1640: ifp->if_timer = 10;
! 1641:
! 1642: return;
! 1643: }
! 1644:
! 1645: void tl_init(xsc)
! 1646: void *xsc;
! 1647: {
! 1648: struct tl_softc *sc = xsc;
! 1649: struct ifnet *ifp = &sc->arpcom.ac_if;
! 1650: int s;
! 1651:
! 1652: s = splnet();
! 1653:
! 1654: /*
! 1655: * Cancel pending I/O.
! 1656: */
! 1657: tl_stop(sc);
! 1658:
! 1659: /* Initialize TX FIFO threshold */
! 1660: tl_dio_clrbit(sc, TL_ACOMMIT, TL_AC_TXTHRESH);
! 1661: tl_dio_setbit(sc, TL_ACOMMIT, TL_AC_TXTHRESH_16LONG);
! 1662:
! 1663: /* Set PCI burst size */
! 1664: tl_dio_write8(sc, TL_BSIZEREG, TL_RXBURST_16LONG|TL_TXBURST_16LONG);
! 1665:
! 1666: /*
! 1667: * Set 'capture all frames' bit for promiscuous mode.
! 1668: */
! 1669: if (ifp->if_flags & IFF_PROMISC)
! 1670: tl_dio_setbit(sc, TL_NETCMD, TL_CMD_CAF);
! 1671: else
! 1672: tl_dio_clrbit(sc, TL_NETCMD, TL_CMD_CAF);
! 1673:
! 1674: /*
! 1675: * Set capture broadcast bit to capture broadcast frames.
! 1676: */
! 1677: if (ifp->if_flags & IFF_BROADCAST)
! 1678: tl_dio_clrbit(sc, TL_NETCMD, TL_CMD_NOBRX);
! 1679: else
! 1680: tl_dio_setbit(sc, TL_NETCMD, TL_CMD_NOBRX);
! 1681:
! 1682: tl_dio_write16(sc, TL_MAXRX, MCLBYTES);
! 1683:
! 1684: /* Init our MAC address */
! 1685: tl_setfilt(sc, (caddr_t)&sc->arpcom.ac_enaddr, 0);
! 1686:
! 1687: /* Init multicast filter, if needed. */
! 1688: tl_setmulti(sc);
! 1689:
! 1690: /* Init circular RX list. */
! 1691: if (tl_list_rx_init(sc) == ENOBUFS) {
! 1692: printf("%s: initialization failed: no memory for rx buffers\n",
! 1693: sc->sc_dev.dv_xname);
! 1694: tl_stop(sc);
! 1695: splx(s);
! 1696: return;
! 1697: }
! 1698:
! 1699: /* Init TX pointers. */
! 1700: tl_list_tx_init(sc);
! 1701:
! 1702: /* Enable PCI interrupts. */
! 1703: CMD_SET(sc, TL_CMD_INTSON);
! 1704:
! 1705: /* Load the address of the rx list */
! 1706: CMD_SET(sc, TL_CMD_RT);
! 1707: CSR_WRITE_4(sc, TL_CH_PARM, VTOPHYS(&sc->tl_ldata->tl_rx_list[0]));
! 1708:
! 1709: if (!sc->tl_bitrate) {
! 1710: mii_mediachg(&sc->sc_mii);
! 1711: } else {
! 1712: tl_ifmedia_upd(ifp);
! 1713: }
! 1714:
! 1715: /* Send the RX go command */
! 1716: CMD_SET(sc, TL_CMD_GO|TL_CMD_NES|TL_CMD_RT);
! 1717:
! 1718: splx(s);
! 1719:
! 1720: /* Start the stats update counter */
! 1721: timeout_set(&sc->tl_stats_tmo, tl_stats_update, sc);
! 1722: timeout_add(&sc->tl_stats_tmo, hz);
! 1723: timeout_set(&sc->tl_wait_tmo, tl_wait_up, sc);
! 1724: timeout_add(&sc->tl_wait_tmo, 2 * hz);
! 1725:
! 1726: return;
! 1727: }
! 1728:
! 1729: /*
! 1730: * Set media options.
! 1731: */
! 1732: int
! 1733: tl_ifmedia_upd(ifp)
! 1734: struct ifnet *ifp;
! 1735: {
! 1736: struct tl_softc *sc = ifp->if_softc;
! 1737:
! 1738: if (sc->tl_bitrate)
! 1739: tl_setmode(sc, sc->ifmedia.ifm_media);
! 1740: else
! 1741: mii_mediachg(&sc->sc_mii);
! 1742:
! 1743: return(0);
! 1744: }
! 1745:
! 1746: /*
! 1747: * Report current media status.
! 1748: */
! 1749: void tl_ifmedia_sts(ifp, ifmr)
! 1750: struct ifnet *ifp;
! 1751: struct ifmediareq *ifmr;
! 1752: {
! 1753: struct tl_softc *sc;
! 1754: struct mii_data *mii;
! 1755:
! 1756: sc = ifp->if_softc;
! 1757: mii = &sc->sc_mii;
! 1758:
! 1759: ifmr->ifm_active = IFM_ETHER;
! 1760: if (sc->tl_bitrate) {
! 1761: if (tl_dio_read8(sc, TL_ACOMMIT) & TL_AC_MTXD1)
! 1762: ifmr->ifm_active = IFM_ETHER|IFM_10_5;
! 1763: else
! 1764: ifmr->ifm_active = IFM_ETHER|IFM_10_T;
! 1765: if (tl_dio_read8(sc, TL_ACOMMIT) & TL_AC_MTXD3)
! 1766: ifmr->ifm_active |= IFM_HDX;
! 1767: else
! 1768: ifmr->ifm_active |= IFM_FDX;
! 1769: return;
! 1770: } else {
! 1771: mii_pollstat(mii);
! 1772: ifmr->ifm_active = mii->mii_media_active;
! 1773: ifmr->ifm_status = mii->mii_media_status;
! 1774: }
! 1775:
! 1776: return;
! 1777: }
! 1778:
! 1779: int tl_ioctl(ifp, command, data)
! 1780: struct ifnet *ifp;
! 1781: u_long command;
! 1782: caddr_t data;
! 1783: {
! 1784: struct tl_softc *sc = ifp->if_softc;
! 1785: struct ifreq *ifr = (struct ifreq *) data;
! 1786: struct ifaddr *ifa = (struct ifaddr *)data;
! 1787: int s, error = 0;
! 1788:
! 1789: s = splnet();
! 1790:
! 1791: if ((error = ether_ioctl(ifp, &sc->arpcom, command, data)) > 0) {
! 1792: splx(s);
! 1793: return error;
! 1794: }
! 1795:
! 1796: switch(command) {
! 1797: case SIOCSIFADDR:
! 1798: ifp->if_flags |= IFF_UP;
! 1799: switch (ifa->ifa_addr->sa_family) {
! 1800: #ifdef INET
! 1801: case AF_INET:
! 1802: tl_init(sc);
! 1803: arp_ifinit(&sc->arpcom, ifa);
! 1804: break;
! 1805: #endif /* INET */
! 1806: default:
! 1807: tl_init(sc);
! 1808: break;
! 1809: }
! 1810: break;
! 1811: case SIOCSIFFLAGS:
! 1812: if (ifp->if_flags & IFF_UP) {
! 1813: if (ifp->if_flags & IFF_RUNNING &&
! 1814: ifp->if_flags & IFF_PROMISC &&
! 1815: !(sc->tl_if_flags & IFF_PROMISC)) {
! 1816: tl_dio_setbit(sc, TL_NETCMD, TL_CMD_CAF);
! 1817: tl_setmulti(sc);
! 1818: } else if (ifp->if_flags & IFF_RUNNING &&
! 1819: !(ifp->if_flags & IFF_PROMISC) &&
! 1820: sc->tl_if_flags & IFF_PROMISC) {
! 1821: tl_dio_clrbit(sc, TL_NETCMD, TL_CMD_CAF);
! 1822: tl_setmulti(sc);
! 1823: } else
! 1824: tl_init(sc);
! 1825: } else {
! 1826: if (ifp->if_flags & IFF_RUNNING) {
! 1827: tl_stop(sc);
! 1828: }
! 1829: }
! 1830: sc->tl_if_flags = ifp->if_flags;
! 1831: error = 0;
! 1832: break;
! 1833: case SIOCADDMULTI:
! 1834: case SIOCDELMULTI:
! 1835: error = (command == SIOCADDMULTI) ?
! 1836: ether_addmulti(ifr, &sc->arpcom) :
! 1837: ether_delmulti(ifr, &sc->arpcom);
! 1838:
! 1839: if (error == ENETRESET) {
! 1840: /*
! 1841: * Multicast list has changed; set the hardware
! 1842: * filter accordingly.
! 1843: */
! 1844: tl_setmulti(sc);
! 1845: error = 0;
! 1846: }
! 1847: break;
! 1848: case SIOCSIFMEDIA:
! 1849: case SIOCGIFMEDIA:
! 1850: if (sc->tl_bitrate)
! 1851: error = ifmedia_ioctl(ifp, ifr, &sc->ifmedia, command);
! 1852: else
! 1853: error = ifmedia_ioctl(ifp, ifr,
! 1854: &sc->sc_mii.mii_media, command);
! 1855: break;
! 1856: default:
! 1857: error = ENOTTY;
! 1858: break;
! 1859: }
! 1860:
! 1861: splx(s);
! 1862:
! 1863: return(error);
! 1864: }
! 1865:
! 1866: void tl_watchdog(ifp)
! 1867: struct ifnet *ifp;
! 1868: {
! 1869: struct tl_softc *sc;
! 1870:
! 1871: sc = ifp->if_softc;
! 1872:
! 1873: printf("%s: device timeout\n", sc->sc_dev.dv_xname);
! 1874:
! 1875: ifp->if_oerrors++;
! 1876:
! 1877: tl_softreset(sc, 1);
! 1878: tl_init(sc);
! 1879:
! 1880: return;
! 1881: }
! 1882:
! 1883: /*
! 1884: * Stop the adapter and free any mbufs allocated to the
! 1885: * RX and TX lists.
! 1886: */
! 1887: void tl_stop(sc)
! 1888: struct tl_softc *sc;
! 1889: {
! 1890: int i;
! 1891: struct ifnet *ifp;
! 1892:
! 1893: ifp = &sc->arpcom.ac_if;
! 1894:
! 1895: /* Stop the stats updater. */
! 1896: timeout_del(&sc->tl_stats_tmo);
! 1897: timeout_del(&sc->tl_wait_tmo);
! 1898:
! 1899: /* Stop the transmitter */
! 1900: CMD_CLR(sc, TL_CMD_RT);
! 1901: CMD_SET(sc, TL_CMD_STOP);
! 1902: CSR_WRITE_4(sc, TL_CH_PARM, 0);
! 1903:
! 1904: /* Stop the receiver */
! 1905: CMD_SET(sc, TL_CMD_RT);
! 1906: CMD_SET(sc, TL_CMD_STOP);
! 1907: CSR_WRITE_4(sc, TL_CH_PARM, 0);
! 1908:
! 1909: /*
! 1910: * Disable host interrupts.
! 1911: */
! 1912: CMD_SET(sc, TL_CMD_INTSOFF);
! 1913:
! 1914: /*
! 1915: * Clear list pointer.
! 1916: */
! 1917: CSR_WRITE_4(sc, TL_CH_PARM, 0);
! 1918:
! 1919: /*
! 1920: * Free the RX lists.
! 1921: */
! 1922: for (i = 0; i < TL_RX_LIST_CNT; i++) {
! 1923: if (sc->tl_cdata.tl_rx_chain[i].tl_mbuf != NULL) {
! 1924: m_freem(sc->tl_cdata.tl_rx_chain[i].tl_mbuf);
! 1925: sc->tl_cdata.tl_rx_chain[i].tl_mbuf = NULL;
! 1926: }
! 1927: }
! 1928: bzero((char *)&sc->tl_ldata->tl_rx_list,
! 1929: sizeof(sc->tl_ldata->tl_rx_list));
! 1930:
! 1931: /*
! 1932: * Free the TX list buffers.
! 1933: */
! 1934: for (i = 0; i < TL_TX_LIST_CNT; i++) {
! 1935: if (sc->tl_cdata.tl_tx_chain[i].tl_mbuf != NULL) {
! 1936: m_freem(sc->tl_cdata.tl_tx_chain[i].tl_mbuf);
! 1937: sc->tl_cdata.tl_tx_chain[i].tl_mbuf = NULL;
! 1938: }
! 1939: }
! 1940: bzero((char *)&sc->tl_ldata->tl_tx_list,
! 1941: sizeof(sc->tl_ldata->tl_tx_list));
! 1942:
! 1943: ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE);
! 1944:
! 1945: return;
! 1946: }
! 1947:
! 1948: int
! 1949: tl_probe(parent, match, aux)
! 1950: struct device *parent;
! 1951: void *match;
! 1952: void *aux;
! 1953: {
! 1954: struct pci_attach_args *pa = (struct pci_attach_args *) aux;
! 1955:
! 1956: if (PCI_VENDOR(pa->pa_id) == PCI_VENDOR_TI) {
! 1957: if (PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_TI_TLAN)
! 1958: return 1;
! 1959: return 0;
! 1960: }
! 1961:
! 1962: if (PCI_VENDOR(pa->pa_id) == PCI_VENDOR_COMPAQ) {
! 1963: switch (PCI_PRODUCT(pa->pa_id)) {
! 1964: case PCI_PRODUCT_COMPAQ_N100TX:
! 1965: case PCI_PRODUCT_COMPAQ_N10T:
! 1966: case PCI_PRODUCT_COMPAQ_IntNF3P:
! 1967: case PCI_PRODUCT_COMPAQ_DPNet100TX:
! 1968: case PCI_PRODUCT_COMPAQ_IntPL100TX:
! 1969: case PCI_PRODUCT_COMPAQ_DP4000:
! 1970: case PCI_PRODUCT_COMPAQ_N10T2:
! 1971: case PCI_PRODUCT_COMPAQ_N10_TX_UTP:
! 1972: case PCI_PRODUCT_COMPAQ_NF3P:
! 1973: case PCI_PRODUCT_COMPAQ_NF3P_BNC:
! 1974: return 1;
! 1975: }
! 1976: return 0;
! 1977: }
! 1978:
! 1979: if (PCI_VENDOR(pa->pa_id) == PCI_VENDOR_OLICOM) {
! 1980: switch (PCI_PRODUCT(pa->pa_id)) {
! 1981: case PCI_PRODUCT_OLICOM_OC2183:
! 1982: case PCI_PRODUCT_OLICOM_OC2325:
! 1983: case PCI_PRODUCT_OLICOM_OC2326:
! 1984: return 1;
! 1985: }
! 1986: return 0;
! 1987: }
! 1988:
! 1989: return 0;
! 1990: }
! 1991:
! 1992: void
! 1993: tl_attach(parent, self, aux)
! 1994: struct device *parent, *self;
! 1995: void *aux;
! 1996: {
! 1997: struct tl_softc *sc = (struct tl_softc *)self;
! 1998: struct pci_attach_args *pa = aux;
! 1999: pci_chipset_tag_t pc = pa->pa_pc;
! 2000: pci_intr_handle_t ih;
! 2001: const char *intrstr = NULL;
! 2002: struct ifnet *ifp = &sc->arpcom.ac_if;
! 2003: bus_size_t iosize;
! 2004: u_int32_t command;
! 2005: int i, rseg;
! 2006: bus_dma_segment_t seg;
! 2007: bus_dmamap_t dmamap;
! 2008: caddr_t kva;
! 2009:
! 2010: /*
! 2011: * Map control/status registers.
! 2012: */
! 2013:
! 2014: #ifdef TL_USEIOSPACE
! 2015: if (pci_mapreg_map(pa, TL_PCI_LOIO, PCI_MAPREG_TYPE_IO, 0,
! 2016: &sc->tl_btag, &sc->tl_bhandle, NULL, &iosize, 0)) {
! 2017: if (pci_mapreg_map(pa, TL_PCI_LOMEM, PCI_MAPREG_TYPE_IO, 0,
! 2018: &sc->tl_btag, &sc->tl_bhandle, NULL, &iosize, 0)) {
! 2019: printf(": failed to map i/o space\n");
! 2020: return;
! 2021: }
! 2022: }
! 2023: #else
! 2024: if (pci_mapreg_map(pa, TL_PCI_LOMEM, PCI_MAPREG_TYPE_MEM, 0,
! 2025: &sc->tl_btag, &sc->tl_bhandle, NULL, &iosize, 0)){
! 2026: if (pci_mapreg_map(pa, TL_PCI_LOIO, PCI_MAPREG_TYPE_MEM, 0,
! 2027: &sc->tl_btag, &sc->tl_bhandle, NULL, &iosize, 0)){
! 2028: printf(": failed to map memory space\n");
! 2029: return;
! 2030: }
! 2031: }
! 2032: #endif
! 2033:
! 2034: /*
! 2035: * Manual wants the PCI latency timer jacked up to 0xff
! 2036: */
! 2037: command = pci_conf_read(pa->pa_pc, pa->pa_tag, TL_PCI_LATENCY_TIMER);
! 2038: command |= 0x0000ff00;
! 2039: pci_conf_write(pa->pa_pc, pa->pa_tag, TL_PCI_LATENCY_TIMER, command);
! 2040:
! 2041: /*
! 2042: * Allocate our interrupt.
! 2043: */
! 2044: if (pci_intr_map(pa, &ih)) {
! 2045: printf(": couldn't map interrupt\n");
! 2046: bus_space_unmap(sc->tl_btag, sc->tl_bhandle, iosize);
! 2047: return;
! 2048: }
! 2049: intrstr = pci_intr_string(pc, ih);
! 2050: sc->sc_ih = pci_intr_establish(pc, ih, IPL_NET, tl_intr, sc,
! 2051: self->dv_xname);
! 2052: if (sc->sc_ih == NULL) {
! 2053: printf(": could not establish interrupt");
! 2054: if (intrstr != NULL)
! 2055: printf(" at %s", intrstr);
! 2056: printf("\n");
! 2057: bus_space_unmap(sc->tl_btag, sc->tl_bhandle, iosize);
! 2058: return;
! 2059: }
! 2060: printf(": %s", intrstr);
! 2061:
! 2062: sc->sc_dmat = pa->pa_dmat;
! 2063: if (bus_dmamem_alloc(sc->sc_dmat, sizeof(struct tl_list_data),
! 2064: PAGE_SIZE, 0, &seg, 1, &rseg, BUS_DMA_NOWAIT)) {
! 2065: printf("%s: can't alloc list\n", sc->sc_dev.dv_xname);
! 2066: bus_space_unmap(sc->tl_btag, sc->tl_bhandle, iosize);
! 2067: return;
! 2068: }
! 2069: if (bus_dmamem_map(sc->sc_dmat, &seg, rseg, sizeof(struct tl_list_data),
! 2070: &kva, BUS_DMA_NOWAIT)) {
! 2071: printf("%s: can't map dma buffers (%d bytes)\n",
! 2072: sc->sc_dev.dv_xname, sizeof(struct tl_list_data));
! 2073: bus_dmamem_free(sc->sc_dmat, &seg, rseg);
! 2074: return;
! 2075: }
! 2076: if (bus_dmamap_create(sc->sc_dmat, sizeof(struct tl_list_data), 1,
! 2077: sizeof(struct tl_list_data), 0, BUS_DMA_NOWAIT, &dmamap)) {
! 2078: printf("%s: can't create dma map\n", sc->sc_dev.dv_xname);
! 2079: bus_dmamem_unmap(sc->sc_dmat, kva, sizeof(struct tl_list_data));
! 2080: bus_dmamem_free(sc->sc_dmat, &seg, rseg);
! 2081: bus_space_unmap(sc->tl_btag, sc->tl_bhandle, iosize);
! 2082: return;
! 2083: }
! 2084: if (bus_dmamap_load(sc->sc_dmat, dmamap, kva,
! 2085: sizeof(struct tl_list_data), NULL, BUS_DMA_NOWAIT)) {
! 2086: printf("%s: can't load dma map\n", sc->sc_dev.dv_xname);
! 2087: bus_dmamap_destroy(sc->sc_dmat, dmamap);
! 2088: bus_dmamem_unmap(sc->sc_dmat, kva, sizeof(struct tl_list_data));
! 2089: bus_dmamem_free(sc->sc_dmat, &seg, rseg);
! 2090: bus_space_unmap(sc->tl_btag, sc->tl_bhandle, iosize);
! 2091: return;
! 2092: }
! 2093: sc->tl_ldata = (struct tl_list_data *)kva;
! 2094: bzero(sc->tl_ldata, sizeof(struct tl_list_data));
! 2095:
! 2096: for (sc->tl_product = tl_prods; sc->tl_product->tp_vend;
! 2097: sc->tl_product++) {
! 2098: if (sc->tl_product->tp_vend == PCI_VENDOR(pa->pa_id) &&
! 2099: sc->tl_product->tp_prod == PCI_PRODUCT(pa->pa_id))
! 2100: break;
! 2101: }
! 2102:
! 2103: if (PCI_VENDOR(pa->pa_id) == PCI_VENDOR_COMPAQ ||
! 2104: PCI_VENDOR(pa->pa_id) == PCI_VENDOR_TI)
! 2105: sc->tl_eeaddr = TL_EEPROM_EADDR;
! 2106: if (PCI_VENDOR(pa->pa_id) == PCI_VENDOR_OLICOM)
! 2107: sc->tl_eeaddr = TL_EEPROM_EADDR_OC;
! 2108:
! 2109: /*
! 2110: * Reset adapter.
! 2111: */
! 2112: tl_softreset(sc, 1);
! 2113: tl_hardreset(self);
! 2114: DELAY(1000000);
! 2115: tl_softreset(sc, 1);
! 2116:
! 2117: /*
! 2118: * Get station address from the EEPROM.
! 2119: */
! 2120: if (tl_read_eeprom(sc, (caddr_t)&sc->arpcom.ac_enaddr,
! 2121: sc->tl_eeaddr, ETHER_ADDR_LEN)) {
! 2122: printf("\n%s: failed to read station address\n",
! 2123: sc->sc_dev.dv_xname);
! 2124: bus_space_unmap(sc->tl_btag, sc->tl_bhandle, iosize);
! 2125: return;
! 2126: }
! 2127:
! 2128: if (PCI_VENDOR(pa->pa_id) == PCI_VENDOR_OLICOM) {
! 2129: for (i = 0; i < ETHER_ADDR_LEN; i += 2) {
! 2130: u_int16_t *p;
! 2131:
! 2132: p = (u_int16_t *)&sc->arpcom.ac_enaddr[i];
! 2133: *p = ntohs(*p);
! 2134: }
! 2135: }
! 2136:
! 2137: printf(" address %s\n", ether_sprintf(sc->arpcom.ac_enaddr));
! 2138:
! 2139: ifp = &sc->arpcom.ac_if;
! 2140: ifp->if_softc = sc;
! 2141: ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
! 2142: ifp->if_ioctl = tl_ioctl;
! 2143: ifp->if_start = tl_start;
! 2144: ifp->if_watchdog = tl_watchdog;
! 2145: ifp->if_baudrate = 10000000;
! 2146: IFQ_SET_MAXLEN(&ifp->if_snd, TL_TX_LIST_CNT - 1);
! 2147: IFQ_SET_READY(&ifp->if_snd);
! 2148: bcopy(sc->sc_dev.dv_xname, ifp->if_xname, IFNAMSIZ);
! 2149:
! 2150: /*
! 2151: * Reset adapter (again).
! 2152: */
! 2153: tl_softreset(sc, 1);
! 2154: tl_hardreset(self);
! 2155: DELAY(1000000);
! 2156: tl_softreset(sc, 1);
! 2157:
! 2158: /*
! 2159: * Do MII setup. If no PHYs are found, then this is a
! 2160: * bitrate ThunderLAN chip that only supports 10baseT
! 2161: * and AUI/BNC.
! 2162: */
! 2163: sc->sc_mii.mii_ifp = ifp;
! 2164: sc->sc_mii.mii_readreg = tl_miibus_readreg;
! 2165: sc->sc_mii.mii_writereg = tl_miibus_writereg;
! 2166: sc->sc_mii.mii_statchg = tl_miibus_statchg;
! 2167: ifmedia_init(&sc->sc_mii.mii_media, 0, tl_ifmedia_upd, tl_ifmedia_sts);
! 2168: mii_attach(self, &sc->sc_mii, 0xffffffff, MII_PHY_ANY, MII_OFFSET_ANY,
! 2169: 0);
! 2170: if (LIST_FIRST(&sc->sc_mii.mii_phys) == NULL) {
! 2171: struct ifmedia *ifm;
! 2172: sc->tl_bitrate = 1;
! 2173: ifmedia_init(&sc->ifmedia, 0, tl_ifmedia_upd, tl_ifmedia_sts);
! 2174: ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_10_T, 0, NULL);
! 2175: ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_10_T|IFM_HDX, 0, NULL);
! 2176: ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_10_T|IFM_FDX, 0, NULL);
! 2177: ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_10_5, 0, NULL);
! 2178: ifmedia_set(&sc->ifmedia, IFM_ETHER|IFM_10_T);
! 2179: /* Reset again, this time setting bitrate mode. */
! 2180: tl_softreset(sc, 1);
! 2181: ifm = &sc->ifmedia;
! 2182: ifm->ifm_media = ifm->ifm_cur->ifm_media;
! 2183: tl_ifmedia_upd(ifp);
! 2184: } else
! 2185: ifmedia_set(&sc->sc_mii.mii_media, IFM_ETHER|IFM_AUTO);
! 2186:
! 2187: /*
! 2188: * Attach us everywhere.
! 2189: */
! 2190: if_attach(ifp);
! 2191: ether_ifattach(ifp);
! 2192:
! 2193: shutdownhook_establish(tl_shutdown, sc);
! 2194: }
! 2195:
! 2196: void
! 2197: tl_wait_up(xsc)
! 2198: void *xsc;
! 2199: {
! 2200: struct tl_softc *sc = xsc;
! 2201: struct ifnet *ifp = &sc->arpcom.ac_if;
! 2202:
! 2203: ifp->if_flags |= IFF_RUNNING;
! 2204: ifp->if_flags &= ~IFF_OACTIVE;
! 2205: }
! 2206:
! 2207: void
! 2208: tl_shutdown(xsc)
! 2209: void *xsc;
! 2210: {
! 2211: struct tl_softc *sc = xsc;
! 2212:
! 2213: tl_stop(sc);
! 2214: }
! 2215:
! 2216: struct cfattach tl_ca = {
! 2217: sizeof(struct tl_softc), tl_probe, tl_attach
! 2218: };
! 2219:
! 2220: struct cfdriver tl_cd = {
! 2221: 0, "tl", DV_IFNET
! 2222: };
CVSweb