if_tl.c revision 45155
136270Swpaul/* 236270Swpaul * Copyright (c) 1997, 1998 336270Swpaul * Bill Paul <wpaul@ctr.columbia.edu>. All rights reserved. 436270Swpaul * 536270Swpaul * Redistribution and use in source and binary forms, with or without 636270Swpaul * modification, are permitted provided that the following conditions 736270Swpaul * are met: 836270Swpaul * 1. Redistributions of source code must retain the above copyright 936270Swpaul * notice, this list of conditions and the following disclaimer. 1036270Swpaul * 2. Redistributions in binary form must reproduce the above copyright 1136270Swpaul * notice, this list of conditions and the following disclaimer in the 1236270Swpaul * documentation and/or other materials provided with the distribution. 1336270Swpaul * 3. All advertising materials mentioning features or use of this software 1436270Swpaul * must display the following acknowledgement: 1536270Swpaul * This product includes software developed by Bill Paul. 1636270Swpaul * 4. Neither the name of the author nor the names of any co-contributors 1736270Swpaul * may be used to endorse or promote products derived from this software 1836270Swpaul * without specific prior written permission. 1936270Swpaul * 2036270Swpaul * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND 2136270Swpaul * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2236270Swpaul * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2336270Swpaul * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD 2436270Swpaul * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 2536270Swpaul * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 2636270Swpaul * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 2736270Swpaul * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 2836270Swpaul * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 2936270Swpaul * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 3036270Swpaul * THE POSSIBILITY OF SUCH DAMAGE. 3136270Swpaul * 3245155Swpaul * $Id: if_tl.c,v 1.37 1999/03/30 16:59:06 wpaul Exp $ 3336270Swpaul */ 3436270Swpaul 3536270Swpaul/* 3636270Swpaul * Texas Instruments ThunderLAN driver for FreeBSD 2.2.6 and 3.x. 3736270Swpaul * Supports many Compaq PCI NICs based on the ThunderLAN ethernet controller, 3836270Swpaul * the National Semiconductor DP83840A physical interface and the 3936270Swpaul * Microchip Technology 24Cxx series serial EEPROM. 4036270Swpaul * 4139583Swpaul * Written using the following four documents: 4236270Swpaul * 4336270Swpaul * Texas Instruments ThunderLAN Programmer's Guide (www.ti.com) 4436270Swpaul * National Semiconductor DP83840A data sheet (www.national.com) 4536270Swpaul * Microchip Technology 24C02C data sheet (www.microchip.com) 4639583Swpaul * Micro Linear ML6692 100BaseTX only PHY data sheet (www.microlinear.com) 4736270Swpaul * 4836270Swpaul * Written by Bill Paul <wpaul@ctr.columbia.edu> 4936270Swpaul * Electrical Engineering Department 5036270Swpaul * Columbia University, New York City 5136270Swpaul */ 5236270Swpaul 5336270Swpaul/* 5436270Swpaul * Some notes about the ThunderLAN: 5536270Swpaul * 5636270Swpaul * The ThunderLAN controller is a single chip containing PCI controller 5736270Swpaul * logic, approximately 3K of on-board SRAM, a LAN controller, and media 5839583Swpaul * independent interface (MII) bus. The MII allows the ThunderLAN chip to 5936270Swpaul * control up to 32 different physical interfaces (PHYs). The ThunderLAN 6036270Swpaul * also has a built-in 10baseT PHY, allowing a single ThunderLAN controller 6136270Swpaul * to act as a complete ethernet interface. 6236270Swpaul * 6336270Swpaul * Other PHYs may be attached to the ThunderLAN; the Compaq 10/100 cards 6436270Swpaul * use a National Semiconductor DP83840A PHY that supports 10 or 100Mb/sec 6536270Swpaul * in full or half duplex. Some of the Compaq Deskpro machines use a 6639583Swpaul * Level 1 LXT970 PHY with the same capabilities. Certain Olicom adapters 6739583Swpaul * use a Micro Linear ML6692 100BaseTX only PHY, which can be used in 6839583Swpaul * concert with the ThunderLAN's internal PHY to provide full 10/100 6939583Swpaul * support. This is cheaper than using a standalone external PHY for both 7039583Swpaul * 10/100 modes and letting the ThunderLAN's internal PHY go to waste. 7139583Swpaul * A serial EEPROM is also attached to the ThunderLAN chip to provide 7239583Swpaul * power-up default register settings and for storing the adapter's 7339583Swpaul * station address. Although not supported by this driver, the ThunderLAN 7439583Swpaul * chip can also be connected to token ring PHYs. 7536270Swpaul * 7636270Swpaul * The ThunderLAN has a set of registers which can be used to issue 7739583Swpaul * commands, acknowledge interrupts, and to manipulate other internal 7836270Swpaul * registers on its DIO bus. The primary registers can be accessed 7936270Swpaul * using either programmed I/O (inb/outb) or via PCI memory mapping, 8036270Swpaul * depending on how the card is configured during the PCI probing 8136270Swpaul * phase. It is even possible to have both PIO and memory mapped 8236270Swpaul * access turned on at the same time. 8336270Swpaul * 8436270Swpaul * Frame reception and transmission with the ThunderLAN chip is done 8536270Swpaul * using frame 'lists.' A list structure looks more or less like this: 8636270Swpaul * 8736270Swpaul * struct tl_frag { 8836270Swpaul * u_int32_t fragment_address; 8936270Swpaul * u_int32_t fragment_size; 9036270Swpaul * }; 9136270Swpaul * struct tl_list { 9236270Swpaul * u_int32_t forward_pointer; 9336270Swpaul * u_int16_t cstat; 9436270Swpaul * u_int16_t frame_size; 9536270Swpaul * struct tl_frag fragments[10]; 9636270Swpaul * }; 9736270Swpaul * 9836270Swpaul * The forward pointer in the list header can be either a 0 or the address 9936270Swpaul * of another list, which allows several lists to be linked together. Each 10036270Swpaul * list contains up to 10 fragment descriptors. This means the chip allows 10136270Swpaul * ethernet frames to be broken up into up to 10 chunks for transfer to 10236270Swpaul * and from the SRAM. Note that the forward pointer and fragment buffer 10336270Swpaul * addresses are physical memory addresses, not virtual. Note also that 10436270Swpaul * a single ethernet frame can not span lists: if the host wants to 10536270Swpaul * transmit a frame and the frame data is split up over more than 10 10636270Swpaul * buffers, the frame has to collapsed before it can be transmitted. 10736270Swpaul * 10836270Swpaul * To receive frames, the driver sets up a number of lists and populates 10936270Swpaul * the fragment descriptors, then it sends an RX GO command to the chip. 11036270Swpaul * When a frame is received, the chip will DMA it into the memory regions 11136270Swpaul * specified by the fragment descriptors and then trigger an RX 'end of 11236270Swpaul * frame interrupt' when done. The driver may choose to use only one 11336270Swpaul * fragment per list; this may result is slighltly less efficient use 11436270Swpaul * of memory in exchange for improving performance. 11536270Swpaul * 11636270Swpaul * To transmit frames, the driver again sets up lists and fragment 11736270Swpaul * descriptors, only this time the buffers contain frame data that 11836270Swpaul * is to be DMA'ed into the chip instead of out of it. Once the chip 11936270Swpaul * has transfered the data into its on-board SRAM, it will trigger a 12036270Swpaul * TX 'end of frame' interrupt. It will also generate an 'end of channel' 12136270Swpaul * interrupt when it reaches the end of the list. 12236270Swpaul */ 12336270Swpaul 12436270Swpaul/* 12536270Swpaul * Some notes about this driver: 12636270Swpaul * 12736270Swpaul * The ThunderLAN chip provides a couple of different ways to organize 12836270Swpaul * reception, transmission and interrupt handling. The simplest approach 12936270Swpaul * is to use one list each for transmission and reception. In this mode, 13036270Swpaul * the ThunderLAN will generate two interrupts for every received frame 13136270Swpaul * (one RX EOF and one RX EOC) and two for each transmitted frame (one 13236270Swpaul * TX EOF and one TX EOC). This may make the driver simpler but it hurts 13336270Swpaul * performance to have to handle so many interrupts. 13436270Swpaul * 13536270Swpaul * Initially I wanted to create a circular list of receive buffers so 13636270Swpaul * that the ThunderLAN chip would think there was an infinitely long 13736270Swpaul * receive channel and never deliver an RXEOC interrupt. However this 13836270Swpaul * doesn't work correctly under heavy load: while the manual says the 13936270Swpaul * chip will trigger an RXEOF interrupt each time a frame is copied into 14036270Swpaul * memory, you can't count on the chip waiting around for you to acknowledge 14136270Swpaul * the interrupt before it starts trying to DMA the next frame. The result 14236270Swpaul * is that the chip might traverse the entire circular list and then wrap 14336270Swpaul * around before you have a chance to do anything about it. Consequently, 14436270Swpaul * the receive list is terminated (with a 0 in the forward pointer in the 14536270Swpaul * last element). Each time an RXEOF interrupt arrives, the used list 14636270Swpaul * is shifted to the end of the list. This gives the appearance of an 14736270Swpaul * infinitely large RX chain so long as the driver doesn't fall behind 14836270Swpaul * the chip and allow all of the lists to be filled up. 14936270Swpaul * 15036270Swpaul * If all the lists are filled, the adapter will deliver an RX 'end of 15136270Swpaul * channel' interrupt when it hits the 0 forward pointer at the end of 15236270Swpaul * the chain. The RXEOC handler then cleans out the RX chain and resets 15336270Swpaul * the list head pointer in the ch_parm register and restarts the receiver. 15436270Swpaul * 15536270Swpaul * For frame transmission, it is possible to program the ThunderLAN's 15636270Swpaul * transmit interrupt threshold so that the chip can acknowledge multiple 15736270Swpaul * lists with only a single TX EOF interrupt. This allows the driver to 15836270Swpaul * queue several frames in one shot, and only have to handle a total 15936270Swpaul * two interrupts (one TX EOF and one TX EOC) no matter how many frames 16036270Swpaul * are transmitted. Frame transmission is done directly out of the 16136270Swpaul * mbufs passed to the tl_start() routine via the interface send queue. 16236270Swpaul * The driver simply sets up the fragment descriptors in the transmit 16336270Swpaul * lists to point to the mbuf data regions and sends a TX GO command. 16436270Swpaul * 16536270Swpaul * Note that since the RX and TX lists themselves are always used 16636270Swpaul * only by the driver, the are malloc()ed once at driver initialization 16736270Swpaul * time and never free()ed. 16836270Swpaul * 16936270Swpaul * Also, in order to remain as platform independent as possible, this 17036270Swpaul * driver uses memory mapped register access to manipulate the card 17136270Swpaul * as opposed to programmed I/O. This avoids the use of the inb/outb 17236270Swpaul * (and related) instructions which are specific to the i386 platform. 17336270Swpaul * 17436270Swpaul * Using these techniques, this driver achieves very high performance 17536270Swpaul * by minimizing the amount of interrupts generated during large 17636270Swpaul * transfers and by completely avoiding buffer copies. Frame transfer 17736270Swpaul * to and from the ThunderLAN chip is performed entirely by the chip 17836270Swpaul * itself thereby reducing the load on the host CPU. 17936270Swpaul */ 18036270Swpaul 18136270Swpaul#include "bpfilter.h" 18236270Swpaul 18336270Swpaul#include <sys/param.h> 18436270Swpaul#include <sys/systm.h> 18536270Swpaul#include <sys/sockio.h> 18636270Swpaul#include <sys/mbuf.h> 18736270Swpaul#include <sys/malloc.h> 18836270Swpaul#include <sys/kernel.h> 18936270Swpaul#include <sys/socket.h> 19036270Swpaul 19136270Swpaul#include <net/if.h> 19236270Swpaul#include <net/if_arp.h> 19336270Swpaul#include <net/ethernet.h> 19436270Swpaul#include <net/if_dl.h> 19536270Swpaul#include <net/if_media.h> 19636270Swpaul 19736270Swpaul#if NBPFILTER > 0 19836270Swpaul#include <net/bpf.h> 19936270Swpaul#endif 20036270Swpaul 20136270Swpaul#include <vm/vm.h> /* for vtophys */ 20236270Swpaul#include <vm/pmap.h> /* for vtophys */ 20336270Swpaul#include <machine/clock.h> /* for DELAY */ 20445155Swpaul#include <machine/bus_memio.h> 20545155Swpaul#include <machine/bus_pio.h> 20645155Swpaul#include <machine/bus.h> 20736270Swpaul 20836270Swpaul#include <pci/pcireg.h> 20936270Swpaul#include <pci/pcivar.h> 21036270Swpaul 21139957Swpaul/* 21239957Swpaul * Default to using PIO register access mode to pacify certain 21339957Swpaul * laptop docking stations with built-in ThunderLAN chips that 21439957Swpaul * don't seem to handle memory mapped mode properly. 21539957Swpaul */ 21639957Swpaul#define TL_USEIOSPACE 21739957Swpaul 21839583Swpaul/* #define TL_BACKGROUND_AUTONEG */ 21939583Swpaul 22036270Swpaul#include <pci/if_tlreg.h> 22136270Swpaul 22241591Sarchie#if !defined(lint) 22341591Sarchiestatic const char rcsid[] = 22445155Swpaul "$Id: if_tl.c,v 1.37 1999/03/30 16:59:06 wpaul Exp $"; 22536270Swpaul#endif 22636270Swpaul 22736270Swpaul/* 22836270Swpaul * Various supported device vendors/types and their names. 22936270Swpaul */ 23036270Swpaul 23136270Swpaulstatic struct tl_type tl_devs[] = { 23236270Swpaul { TI_VENDORID, TI_DEVICEID_THUNDERLAN, 23336270Swpaul "Texas Instruments ThunderLAN" }, 23436270Swpaul { COMPAQ_VENDORID, COMPAQ_DEVICEID_NETEL_10, 23536270Swpaul "Compaq Netelligent 10" }, 23636270Swpaul { COMPAQ_VENDORID, COMPAQ_DEVICEID_NETEL_10_100, 23736270Swpaul "Compaq Netelligent 10/100" }, 23836270Swpaul { COMPAQ_VENDORID, COMPAQ_DEVICEID_NETEL_10_100_PROLIANT, 23936270Swpaul "Compaq Netelligent 10/100 Proliant" }, 24036270Swpaul { COMPAQ_VENDORID, COMPAQ_DEVICEID_NETEL_10_100_DUAL, 24136270Swpaul "Compaq Netelligent 10/100 Dual Port" }, 24236270Swpaul { COMPAQ_VENDORID, COMPAQ_DEVICEID_NETFLEX_3P_INTEGRATED, 24336270Swpaul "Compaq NetFlex-3/P Integrated" }, 24436270Swpaul { COMPAQ_VENDORID, COMPAQ_DEVICEID_NETFLEX_3P, 24536270Swpaul "Compaq NetFlex-3/P" }, 24636270Swpaul { COMPAQ_VENDORID, COMPAQ_DEVICEID_NETFLEX_3P_BNC, 24736270Swpaul "Compaq NetFlex 3/P w/ BNC" }, 24837626Swpaul { COMPAQ_VENDORID, COMPAQ_DEVICEID_NETEL_10_100_EMBEDDED, 24937626Swpaul "Compaq Netelligent 10/100 TX Embedded UTP" }, 25037626Swpaul { COMPAQ_VENDORID, COMPAQ_DEVICEID_NETEL_10_T2_UTP_COAX, 25137626Swpaul "Compaq Netelligent 10 T/2 PCI UTP/Coax" }, 25237626Swpaul { COMPAQ_VENDORID, COMPAQ_DEVICEID_NETEL_10_100_TX_UTP, 25337626Swpaul "Compaq Netelligent 10/100 TX UTP" }, 25437626Swpaul { OLICOM_VENDORID, OLICOM_DEVICEID_OC2183, 25537626Swpaul "Olicom OC-2183/2185" }, 25637626Swpaul { OLICOM_VENDORID, OLICOM_DEVICEID_OC2325, 25737626Swpaul "Olicom OC-2325" }, 25837626Swpaul { OLICOM_VENDORID, OLICOM_DEVICEID_OC2326, 25937626Swpaul "Olicom OC-2326 10/100 TX UTP" }, 26036270Swpaul { 0, 0, NULL } 26136270Swpaul}; 26236270Swpaul 26336270Swpaul/* 26436270Swpaul * Various supported PHY vendors/types and their names. Note that 26536270Swpaul * this driver will work with pretty much any MII-compliant PHY, 26636270Swpaul * so failure to positively identify the chip is not a fatal error. 26736270Swpaul */ 26836270Swpaul 26936270Swpaulstatic struct tl_type tl_phys[] = { 27036270Swpaul { TI_PHY_VENDORID, TI_PHY_10BT, "<TI ThunderLAN 10BT (internal)>" }, 27136270Swpaul { TI_PHY_VENDORID, TI_PHY_100VGPMI, "<TI TNETE211 100VG Any-LAN>" }, 27236270Swpaul { NS_PHY_VENDORID, NS_PHY_83840A, "<National Semiconductor DP83840A>"}, 27336270Swpaul { LEVEL1_PHY_VENDORID, LEVEL1_PHY_LXT970, "<Level 1 LXT970>" }, 27436270Swpaul { INTEL_PHY_VENDORID, INTEL_PHY_82555, "<Intel 82555>" }, 27536270Swpaul { SEEQ_PHY_VENDORID, SEEQ_PHY_80220, "<SEEQ 80220>" }, 27636270Swpaul { 0, 0, "<MII-compliant physical interface>" } 27736270Swpaul}; 27836270Swpaul 27936270Swpaulstatic unsigned long tl_count; 28036270Swpaul 28141771Sdillonstatic const char *tl_probe __P((pcici_t, pcidi_t)); 28239583Swpaulstatic void tl_attach __P((pcici_t, int)); 28339583Swpaulstatic int tl_attach_phy __P((struct tl_softc *)); 28436270Swpaulstatic int tl_intvec_rxeoc __P((void *, u_int32_t)); 28536270Swpaulstatic int tl_intvec_txeoc __P((void *, u_int32_t)); 28636270Swpaulstatic int tl_intvec_txeof __P((void *, u_int32_t)); 28736270Swpaulstatic int tl_intvec_rxeof __P((void *, u_int32_t)); 28836270Swpaulstatic int tl_intvec_adchk __P((void *, u_int32_t)); 28936270Swpaulstatic int tl_intvec_netsts __P((void *, u_int32_t)); 29036270Swpaul 29137626Swpaulstatic int tl_newbuf __P((struct tl_softc *, 29237626Swpaul struct tl_chain_onefrag *)); 29336270Swpaulstatic void tl_stats_update __P((void *)); 29436270Swpaulstatic int tl_encap __P((struct tl_softc *, struct tl_chain *, 29536270Swpaul struct mbuf *)); 29636270Swpaul 29736270Swpaulstatic void tl_intr __P((void *)); 29836270Swpaulstatic void tl_start __P((struct ifnet *)); 29936735Sdfrstatic int tl_ioctl __P((struct ifnet *, u_long, caddr_t)); 30036270Swpaulstatic void tl_init __P((void *)); 30136270Swpaulstatic void tl_stop __P((struct tl_softc *)); 30236270Swpaulstatic void tl_watchdog __P((struct ifnet *)); 30336270Swpaulstatic void tl_shutdown __P((int, void *)); 30436270Swpaulstatic int tl_ifmedia_upd __P((struct ifnet *)); 30536270Swpaulstatic void tl_ifmedia_sts __P((struct ifnet *, struct ifmediareq *)); 30636270Swpaul 30741656Swpaulstatic u_int8_t tl_eeprom_putbyte __P((struct tl_softc *, int)); 30839583Swpaulstatic u_int8_t tl_eeprom_getbyte __P((struct tl_softc *, 30941656Swpaul int, u_int8_t *)); 31039583Swpaulstatic int tl_read_eeprom __P((struct tl_softc *, caddr_t, int, int)); 31136270Swpaul 31239583Swpaulstatic void tl_mii_sync __P((struct tl_softc *)); 31339583Swpaulstatic void tl_mii_send __P((struct tl_softc *, u_int32_t, int)); 31439583Swpaulstatic int tl_mii_readreg __P((struct tl_softc *, struct tl_mii_frame *)); 31539583Swpaulstatic int tl_mii_writereg __P((struct tl_softc *, struct tl_mii_frame *)); 31636270Swpaulstatic u_int16_t tl_phy_readreg __P((struct tl_softc *, int)); 31741656Swpaulstatic void tl_phy_writereg __P((struct tl_softc *, int, int)); 31836270Swpaul 31936270Swpaulstatic void tl_autoneg __P((struct tl_softc *, int, int)); 32036270Swpaulstatic void tl_setmode __P((struct tl_softc *, int)); 32141656Swpaulstatic int tl_calchash __P((caddr_t)); 32236270Swpaulstatic void tl_setmulti __P((struct tl_softc *)); 32341656Swpaulstatic void tl_setfilt __P((struct tl_softc *, caddr_t, int)); 32439583Swpaulstatic void tl_softreset __P((struct tl_softc *, int)); 32539583Swpaulstatic void tl_hardreset __P((struct tl_softc *)); 32636270Swpaulstatic int tl_list_rx_init __P((struct tl_softc *)); 32736270Swpaulstatic int tl_list_tx_init __P((struct tl_softc *)); 32836270Swpaul 32941656Swpaulstatic u_int8_t tl_dio_read8 __P((struct tl_softc *, int)); 33041656Swpaulstatic u_int16_t tl_dio_read16 __P((struct tl_softc *, int)); 33141656Swpaulstatic u_int32_t tl_dio_read32 __P((struct tl_softc *, int)); 33241656Swpaulstatic void tl_dio_write8 __P((struct tl_softc *, int, int)); 33341656Swpaulstatic void tl_dio_write16 __P((struct tl_softc *, int, int)); 33441656Swpaulstatic void tl_dio_write32 __P((struct tl_softc *, int, int)); 33541656Swpaulstatic void tl_dio_setbit __P((struct tl_softc *, int, int)); 33641656Swpaulstatic void tl_dio_clrbit __P((struct tl_softc *, int, int)); 33741656Swpaulstatic void tl_dio_setbit16 __P((struct tl_softc *, int, int)); 33841656Swpaulstatic void tl_dio_clrbit16 __P((struct tl_softc *, int, int)); 33939583Swpaul 34039583Swpaulstatic u_int8_t tl_dio_read8(sc, reg) 34141656Swpaul struct tl_softc *sc; 34241656Swpaul int reg; 34339583Swpaul{ 34439583Swpaul CSR_WRITE_2(sc, TL_DIO_ADDR, reg); 34539583Swpaul return(CSR_READ_1(sc, TL_DIO_DATA + (reg & 3))); 34639583Swpaul} 34739583Swpaul 34839583Swpaulstatic u_int16_t tl_dio_read16(sc, reg) 34941656Swpaul struct tl_softc *sc; 35041656Swpaul int reg; 35139583Swpaul{ 35239583Swpaul CSR_WRITE_2(sc, TL_DIO_ADDR, reg); 35339583Swpaul return(CSR_READ_2(sc, TL_DIO_DATA + (reg & 3))); 35439583Swpaul} 35539583Swpaul 35639583Swpaulstatic u_int32_t tl_dio_read32(sc, reg) 35741656Swpaul struct tl_softc *sc; 35841656Swpaul int reg; 35939583Swpaul{ 36039583Swpaul CSR_WRITE_2(sc, TL_DIO_ADDR, reg); 36139583Swpaul return(CSR_READ_4(sc, TL_DIO_DATA + (reg & 3))); 36239583Swpaul} 36339583Swpaul 36439583Swpaulstatic void tl_dio_write8(sc, reg, val) 36541656Swpaul struct tl_softc *sc; 36641656Swpaul int reg; 36741656Swpaul int val; 36839583Swpaul{ 36939583Swpaul CSR_WRITE_2(sc, TL_DIO_ADDR, reg); 37039583Swpaul CSR_WRITE_1(sc, TL_DIO_DATA + (reg & 3), val); 37139583Swpaul return; 37239583Swpaul} 37339583Swpaul 37439583Swpaulstatic void tl_dio_write16(sc, reg, val) 37541656Swpaul struct tl_softc *sc; 37641656Swpaul int reg; 37741656Swpaul int val; 37839583Swpaul{ 37939583Swpaul CSR_WRITE_2(sc, TL_DIO_ADDR, reg); 38039583Swpaul CSR_WRITE_2(sc, TL_DIO_DATA + (reg & 3), val); 38139583Swpaul return; 38239583Swpaul} 38339583Swpaul 38439583Swpaulstatic void tl_dio_write32(sc, reg, val) 38541656Swpaul struct tl_softc *sc; 38641656Swpaul int reg; 38741656Swpaul int val; 38839583Swpaul{ 38939583Swpaul CSR_WRITE_2(sc, TL_DIO_ADDR, reg); 39039583Swpaul CSR_WRITE_4(sc, TL_DIO_DATA + (reg & 3), val); 39139583Swpaul return; 39239583Swpaul} 39339583Swpaul 39439583Swpaulstatic void tl_dio_setbit(sc, reg, bit) 39541656Swpaul struct tl_softc *sc; 39641656Swpaul int reg; 39741656Swpaul int bit; 39839583Swpaul{ 39939583Swpaul u_int8_t f; 40039583Swpaul 40139583Swpaul CSR_WRITE_2(sc, TL_DIO_ADDR, reg); 40239583Swpaul f = CSR_READ_1(sc, TL_DIO_DATA + (reg & 3)); 40339583Swpaul f |= bit; 40439583Swpaul CSR_WRITE_1(sc, TL_DIO_DATA + (reg & 3), f); 40539583Swpaul 40639583Swpaul return; 40739583Swpaul} 40839583Swpaul 40939583Swpaulstatic void tl_dio_clrbit(sc, reg, bit) 41041656Swpaul struct tl_softc *sc; 41141656Swpaul int reg; 41241656Swpaul int bit; 41339583Swpaul{ 41439583Swpaul u_int8_t f; 41539583Swpaul 41639583Swpaul CSR_WRITE_2(sc, TL_DIO_ADDR, reg); 41739583Swpaul f = CSR_READ_1(sc, TL_DIO_DATA + (reg & 3)); 41839583Swpaul f &= ~bit; 41939583Swpaul CSR_WRITE_1(sc, TL_DIO_DATA + (reg & 3), f); 42039583Swpaul 42139583Swpaul return; 42239583Swpaul} 42339583Swpaul 42439583Swpaulstatic void tl_dio_setbit16(sc, reg, bit) 42541656Swpaul struct tl_softc *sc; 42641656Swpaul int reg; 42741656Swpaul int bit; 42839583Swpaul{ 42939583Swpaul u_int16_t f; 43039583Swpaul 43139583Swpaul CSR_WRITE_2(sc, TL_DIO_ADDR, reg); 43239583Swpaul f = CSR_READ_2(sc, TL_DIO_DATA + (reg & 3)); 43339583Swpaul f |= bit; 43439583Swpaul CSR_WRITE_2(sc, TL_DIO_DATA + (reg & 3), f); 43539583Swpaul 43639583Swpaul return; 43739583Swpaul} 43839583Swpaul 43939583Swpaulstatic void tl_dio_clrbit16(sc, reg, bit) 44041656Swpaul struct tl_softc *sc; 44141656Swpaul int reg; 44241656Swpaul int bit; 44339583Swpaul{ 44439583Swpaul u_int16_t f; 44539583Swpaul 44639583Swpaul CSR_WRITE_2(sc, TL_DIO_ADDR, reg); 44739583Swpaul f = CSR_READ_2(sc, TL_DIO_DATA + (reg & 3)); 44839583Swpaul f &= ~bit; 44939583Swpaul CSR_WRITE_2(sc, TL_DIO_DATA + (reg & 3), f); 45039583Swpaul 45139583Swpaul return; 45239583Swpaul} 45339583Swpaul 45436270Swpaul/* 45536270Swpaul * Send an instruction or address to the EEPROM, check for ACK. 45636270Swpaul */ 45739583Swpaulstatic u_int8_t tl_eeprom_putbyte(sc, byte) 45839583Swpaul struct tl_softc *sc; 45941656Swpaul int byte; 46036270Swpaul{ 46136270Swpaul register int i, ack = 0; 46236270Swpaul 46336270Swpaul /* 46436270Swpaul * Make sure we're in TX mode. 46536270Swpaul */ 46639583Swpaul tl_dio_setbit(sc, TL_NETSIO, TL_SIO_ETXEN); 46736270Swpaul 46836270Swpaul /* 46936270Swpaul * Feed in each bit and stobe the clock. 47036270Swpaul */ 47136270Swpaul for (i = 0x80; i; i >>= 1) { 47236270Swpaul if (byte & i) { 47339583Swpaul tl_dio_setbit(sc, TL_NETSIO, TL_SIO_EDATA); 47436270Swpaul } else { 47539583Swpaul tl_dio_clrbit(sc, TL_NETSIO, TL_SIO_EDATA); 47636270Swpaul } 47739583Swpaul DELAY(1); 47839583Swpaul tl_dio_setbit(sc, TL_NETSIO, TL_SIO_ECLOK); 47939583Swpaul DELAY(1); 48039583Swpaul tl_dio_clrbit(sc, TL_NETSIO, TL_SIO_ECLOK); 48136270Swpaul } 48236270Swpaul 48336270Swpaul /* 48436270Swpaul * Turn off TX mode. 48536270Swpaul */ 48639583Swpaul tl_dio_clrbit(sc, TL_NETSIO, TL_SIO_ETXEN); 48736270Swpaul 48836270Swpaul /* 48936270Swpaul * Check for ack. 49036270Swpaul */ 49139583Swpaul tl_dio_setbit(sc, TL_NETSIO, TL_SIO_ECLOK); 49239583Swpaul ack = tl_dio_read8(sc, TL_NETSIO) & TL_SIO_EDATA; 49339583Swpaul tl_dio_clrbit(sc, TL_NETSIO, TL_SIO_ECLOK); 49436270Swpaul 49536270Swpaul return(ack); 49636270Swpaul} 49736270Swpaul 49836270Swpaul/* 49936270Swpaul * Read a byte of data stored in the EEPROM at address 'addr.' 50036270Swpaul */ 50139583Swpaulstatic u_int8_t tl_eeprom_getbyte(sc, addr, dest) 50239583Swpaul struct tl_softc *sc; 50341656Swpaul int addr; 50436270Swpaul u_int8_t *dest; 50536270Swpaul{ 50636270Swpaul register int i; 50736270Swpaul u_int8_t byte = 0; 50836270Swpaul 50939583Swpaul tl_dio_write8(sc, TL_NETSIO, 0); 51039583Swpaul 51136270Swpaul EEPROM_START; 51239583Swpaul 51336270Swpaul /* 51436270Swpaul * Send write control code to EEPROM. 51536270Swpaul */ 51639583Swpaul if (tl_eeprom_putbyte(sc, EEPROM_CTL_WRITE)) { 51739583Swpaul printf("tl%d: failed to send write command, status: %x\n", 51839583Swpaul sc->tl_unit, tl_dio_read8(sc, TL_NETSIO)); 51936270Swpaul return(1); 52039583Swpaul } 52136270Swpaul 52236270Swpaul /* 52336270Swpaul * Send address of byte we want to read. 52436270Swpaul */ 52539583Swpaul if (tl_eeprom_putbyte(sc, addr)) { 52639583Swpaul printf("tl%d: failed to send address, status: %x\n", 52739583Swpaul sc->tl_unit, tl_dio_read8(sc, TL_NETSIO)); 52836270Swpaul return(1); 52939583Swpaul } 53036270Swpaul 53136270Swpaul EEPROM_STOP; 53236270Swpaul EEPROM_START; 53336270Swpaul /* 53436270Swpaul * Send read control code to EEPROM. 53536270Swpaul */ 53639583Swpaul if (tl_eeprom_putbyte(sc, EEPROM_CTL_READ)) { 53739583Swpaul printf("tl%d: failed to send write command, status: %x\n", 53839583Swpaul sc->tl_unit, tl_dio_read8(sc, TL_NETSIO)); 53936270Swpaul return(1); 54039583Swpaul } 54136270Swpaul 54236270Swpaul /* 54336270Swpaul * Start reading bits from EEPROM. 54436270Swpaul */ 54539583Swpaul tl_dio_clrbit(sc, TL_NETSIO, TL_SIO_ETXEN); 54636270Swpaul for (i = 0x80; i; i >>= 1) { 54739583Swpaul tl_dio_setbit(sc, TL_NETSIO, TL_SIO_ECLOK); 54839583Swpaul DELAY(1); 54939583Swpaul if (tl_dio_read8(sc, TL_NETSIO) & TL_SIO_EDATA) 55036270Swpaul byte |= i; 55139583Swpaul tl_dio_clrbit(sc, TL_NETSIO, TL_SIO_ECLOK); 55236501Swpaul DELAY(1); 55336270Swpaul } 55436270Swpaul 55536270Swpaul EEPROM_STOP; 55636270Swpaul 55736270Swpaul /* 55836270Swpaul * No ACK generated for read, so just return byte. 55936270Swpaul */ 56036270Swpaul 56136270Swpaul *dest = byte; 56236270Swpaul 56336270Swpaul return(0); 56436270Swpaul} 56536270Swpaul 56639583Swpaul/* 56739583Swpaul * Read a sequence of bytes from the EEPROM. 56839583Swpaul */ 56939583Swpaulstatic int tl_read_eeprom(sc, dest, off, cnt) 57039583Swpaul struct tl_softc *sc; 57139583Swpaul caddr_t dest; 57239583Swpaul int off; 57339583Swpaul int cnt; 57436270Swpaul{ 57539583Swpaul int err = 0, i; 57639583Swpaul u_int8_t byte = 0; 57739583Swpaul 57839583Swpaul for (i = 0; i < cnt; i++) { 57939583Swpaul err = tl_eeprom_getbyte(sc, off + i, &byte); 58039583Swpaul if (err) 58139583Swpaul break; 58239583Swpaul *(dest + i) = byte; 58339583Swpaul } 58439583Swpaul 58539583Swpaul return(err ? 1 : 0); 58639583Swpaul} 58739583Swpaul 58839583Swpaulstatic void tl_mii_sync(sc) 58939583Swpaul struct tl_softc *sc; 59039583Swpaul{ 59136270Swpaul register int i; 59236270Swpaul 59339583Swpaul tl_dio_clrbit(sc, TL_NETSIO, TL_SIO_MTXEN); 59436270Swpaul 59536270Swpaul for (i = 0; i < 32; i++) { 59639583Swpaul tl_dio_setbit(sc, TL_NETSIO, TL_SIO_MCLK); 59739583Swpaul tl_dio_clrbit(sc, TL_NETSIO, TL_SIO_MCLK); 59836270Swpaul } 59936270Swpaul 60036270Swpaul return; 60136270Swpaul} 60236270Swpaul 60339583Swpaulstatic void tl_mii_send(sc, bits, cnt) 60439583Swpaul struct tl_softc *sc; 60536270Swpaul u_int32_t bits; 60636270Swpaul int cnt; 60736270Swpaul{ 60836270Swpaul int i; 60936270Swpaul 61036270Swpaul for (i = (0x1 << (cnt - 1)); i; i >>= 1) { 61139583Swpaul tl_dio_clrbit(sc, TL_NETSIO, TL_SIO_MCLK); 61236270Swpaul if (bits & i) { 61339583Swpaul tl_dio_setbit(sc, TL_NETSIO, TL_SIO_MDATA); 61436270Swpaul } else { 61539583Swpaul tl_dio_clrbit(sc, TL_NETSIO, TL_SIO_MDATA); 61636270Swpaul } 61739583Swpaul tl_dio_setbit(sc, TL_NETSIO, TL_SIO_MCLK); 61836270Swpaul } 61936270Swpaul} 62036270Swpaul 62139583Swpaulstatic int tl_mii_readreg(sc, frame) 62239583Swpaul struct tl_softc *sc; 62336270Swpaul struct tl_mii_frame *frame; 62436270Swpaul 62536270Swpaul{ 62636270Swpaul int i, ack, s; 62736270Swpaul int minten = 0; 62836270Swpaul 62936270Swpaul s = splimp(); 63036270Swpaul 63139583Swpaul tl_mii_sync(sc); 63236270Swpaul 63336270Swpaul /* 63436270Swpaul * Set up frame for RX. 63536270Swpaul */ 63636270Swpaul frame->mii_stdelim = TL_MII_STARTDELIM; 63736270Swpaul frame->mii_opcode = TL_MII_READOP; 63836270Swpaul frame->mii_turnaround = 0; 63936270Swpaul frame->mii_data = 0; 64036270Swpaul 64136270Swpaul /* 64236270Swpaul * Turn off MII interrupt by forcing MINTEN low. 64336270Swpaul */ 64439583Swpaul minten = tl_dio_read8(sc, TL_NETSIO) & TL_SIO_MINTEN; 64536270Swpaul if (minten) { 64639583Swpaul tl_dio_clrbit(sc, TL_NETSIO, TL_SIO_MINTEN); 64736270Swpaul } 64836270Swpaul 64936270Swpaul /* 65036270Swpaul * Turn on data xmit. 65136270Swpaul */ 65239583Swpaul tl_dio_setbit(sc, TL_NETSIO, TL_SIO_MTXEN); 65336270Swpaul 65436270Swpaul /* 65536270Swpaul * Send command/address info. 65636270Swpaul */ 65739583Swpaul tl_mii_send(sc, frame->mii_stdelim, 2); 65839583Swpaul tl_mii_send(sc, frame->mii_opcode, 2); 65939583Swpaul tl_mii_send(sc, frame->mii_phyaddr, 5); 66039583Swpaul tl_mii_send(sc, frame->mii_regaddr, 5); 66136270Swpaul 66236270Swpaul /* 66336270Swpaul * Turn off xmit. 66436270Swpaul */ 66539583Swpaul tl_dio_clrbit(sc, TL_NETSIO, TL_SIO_MTXEN); 66636270Swpaul 66736270Swpaul /* Idle bit */ 66839583Swpaul tl_dio_clrbit(sc, TL_NETSIO, TL_SIO_MCLK); 66939583Swpaul tl_dio_setbit(sc, TL_NETSIO, TL_SIO_MCLK); 67036270Swpaul 67136270Swpaul /* Check for ack */ 67239583Swpaul tl_dio_clrbit(sc, TL_NETSIO, TL_SIO_MCLK); 67339583Swpaul ack = tl_dio_read8(sc, TL_NETSIO) & TL_SIO_MDATA; 67436270Swpaul 67536270Swpaul /* Complete the cycle */ 67639583Swpaul tl_dio_setbit(sc, TL_NETSIO, TL_SIO_MCLK); 67736270Swpaul 67836270Swpaul /* 67936270Swpaul * Now try reading data bits. If the ack failed, we still 68036270Swpaul * need to clock through 16 cycles to keep the PHYs in sync. 68136270Swpaul */ 68236270Swpaul if (ack) { 68336270Swpaul for(i = 0; i < 16; i++) { 68439583Swpaul tl_dio_clrbit(sc, TL_NETSIO, TL_SIO_MCLK); 68539583Swpaul tl_dio_setbit(sc, TL_NETSIO, TL_SIO_MCLK); 68636270Swpaul } 68736270Swpaul goto fail; 68836270Swpaul } 68936270Swpaul 69036270Swpaul for (i = 0x8000; i; i >>= 1) { 69139583Swpaul tl_dio_clrbit(sc, TL_NETSIO, TL_SIO_MCLK); 69236270Swpaul if (!ack) { 69339583Swpaul if (tl_dio_read8(sc, TL_NETSIO) & TL_SIO_MDATA) 69436270Swpaul frame->mii_data |= i; 69536270Swpaul } 69639583Swpaul tl_dio_setbit(sc, TL_NETSIO, TL_SIO_MCLK); 69736270Swpaul } 69836270Swpaul 69936270Swpaulfail: 70036270Swpaul 70139583Swpaul tl_dio_setbit(sc, TL_NETSIO, TL_SIO_MCLK); 70239583Swpaul tl_dio_clrbit(sc, TL_NETSIO, TL_SIO_MCLK); 70336270Swpaul 70436270Swpaul /* Reenable interrupts */ 70536270Swpaul if (minten) { 70639583Swpaul tl_dio_setbit(sc, TL_NETSIO, TL_SIO_MINTEN); 70736270Swpaul } 70836270Swpaul 70936270Swpaul splx(s); 71036270Swpaul 71136270Swpaul if (ack) 71236270Swpaul return(1); 71336270Swpaul return(0); 71436270Swpaul} 71536270Swpaul 71639583Swpaulstatic int tl_mii_writereg(sc, frame) 71739583Swpaul struct tl_softc *sc; 71836270Swpaul struct tl_mii_frame *frame; 71936270Swpaul 72036270Swpaul{ 72136270Swpaul int s; 72236270Swpaul int minten; 72336270Swpaul 72439583Swpaul tl_mii_sync(sc); 72536270Swpaul 72636270Swpaul s = splimp(); 72736270Swpaul /* 72836270Swpaul * Set up frame for TX. 72936270Swpaul */ 73036270Swpaul 73136270Swpaul frame->mii_stdelim = TL_MII_STARTDELIM; 73236270Swpaul frame->mii_opcode = TL_MII_WRITEOP; 73336270Swpaul frame->mii_turnaround = TL_MII_TURNAROUND; 73436270Swpaul 73536270Swpaul /* 73636270Swpaul * Turn off MII interrupt by forcing MINTEN low. 73736270Swpaul */ 73839583Swpaul minten = tl_dio_read8(sc, TL_NETSIO) & TL_SIO_MINTEN; 73936270Swpaul if (minten) { 74039583Swpaul tl_dio_clrbit(sc, TL_NETSIO, TL_SIO_MINTEN); 74136270Swpaul } 74236270Swpaul 74336270Swpaul /* 74436270Swpaul * Turn on data output. 74536270Swpaul */ 74639583Swpaul tl_dio_setbit(sc, TL_NETSIO, TL_SIO_MTXEN); 74736270Swpaul 74839583Swpaul tl_mii_send(sc, frame->mii_stdelim, 2); 74939583Swpaul tl_mii_send(sc, frame->mii_opcode, 2); 75039583Swpaul tl_mii_send(sc, frame->mii_phyaddr, 5); 75139583Swpaul tl_mii_send(sc, frame->mii_regaddr, 5); 75239583Swpaul tl_mii_send(sc, frame->mii_turnaround, 2); 75339583Swpaul tl_mii_send(sc, frame->mii_data, 16); 75436270Swpaul 75539583Swpaul tl_dio_setbit(sc, TL_NETSIO, TL_SIO_MCLK); 75639583Swpaul tl_dio_clrbit(sc, TL_NETSIO, TL_SIO_MCLK); 75736270Swpaul 75836270Swpaul /* 75936270Swpaul * Turn off xmit. 76036270Swpaul */ 76139583Swpaul tl_dio_clrbit(sc, TL_NETSIO, TL_SIO_MTXEN); 76236270Swpaul 76336270Swpaul /* Reenable interrupts */ 76436270Swpaul if (minten) 76539583Swpaul tl_dio_setbit(sc, TL_NETSIO, TL_SIO_MINTEN); 76636270Swpaul 76736270Swpaul splx(s); 76836270Swpaul 76936270Swpaul return(0); 77036270Swpaul} 77136270Swpaul 77236270Swpaulstatic u_int16_t tl_phy_readreg(sc, reg) 77336270Swpaul struct tl_softc *sc; 77436270Swpaul int reg; 77536270Swpaul{ 77636270Swpaul struct tl_mii_frame frame; 77736270Swpaul 77836270Swpaul bzero((char *)&frame, sizeof(frame)); 77936270Swpaul 78036270Swpaul frame.mii_phyaddr = sc->tl_phy_addr; 78136270Swpaul frame.mii_regaddr = reg; 78239583Swpaul tl_mii_readreg(sc, &frame); 78336270Swpaul 78436270Swpaul /* Reenable MII interrupts, just in case. */ 78539583Swpaul tl_dio_setbit(sc, TL_NETSIO, TL_SIO_MINTEN); 78636270Swpaul 78736270Swpaul return(frame.mii_data); 78836270Swpaul} 78936270Swpaul 79036270Swpaulstatic void tl_phy_writereg(sc, reg, data) 79136270Swpaul struct tl_softc *sc; 79241656Swpaul int reg; 79341656Swpaul int data; 79436270Swpaul{ 79536270Swpaul struct tl_mii_frame frame; 79636270Swpaul 79736270Swpaul bzero((char *)&frame, sizeof(frame)); 79836270Swpaul 79936270Swpaul frame.mii_phyaddr = sc->tl_phy_addr; 80036270Swpaul frame.mii_regaddr = reg; 80136270Swpaul frame.mii_data = data; 80236270Swpaul 80339583Swpaul tl_mii_writereg(sc, &frame); 80436270Swpaul 80536270Swpaul /* Reenable MII interrupts, just in case. */ 80639583Swpaul tl_dio_setbit(sc, TL_NETSIO, TL_SIO_MINTEN); 80736270Swpaul 80836270Swpaul return; 80936270Swpaul} 81036270Swpaul 81136270Swpaul/* 81236270Swpaul * Initiate autonegotiation with a link partner. 81336270Swpaul * 81436270Swpaul * Note that the Texas Instruments ThunderLAN programmer's guide 81536270Swpaul * fails to mention one very important point about autonegotiation. 81636270Swpaul * Autonegotiation is done largely by the PHY, independent of the 81736270Swpaul * ThunderLAN chip itself: the PHY sets the flags in the BMCR 81836270Swpaul * register to indicate what modes were selected and if link status 81936270Swpaul * is good. In fact, the PHY does pretty much all of the work itself, 82036270Swpaul * except for one small detail. 82136270Swpaul * 82236270Swpaul * The PHY may negotiate a full-duplex of half-duplex link, and set 82336270Swpaul * the PHY_BMCR_DUPLEX bit accordingly, but the ThunderLAN's 'NetCommand' 82436270Swpaul * register _also_ has a half-duplex/full-duplex bit, and you MUST ALSO 82536270Swpaul * SET THIS BIT MANUALLY TO CORRESPOND TO THE MODE SELECTED FOR THE PHY! 82636270Swpaul * In other words, both the ThunderLAN chip and the PHY have to be 82736270Swpaul * programmed for full-duplex mode in order for full-duplex to actually 82836270Swpaul * work. So in order for autonegotiation to really work right, we have 82936270Swpaul * to wait for the link to come up, check the BMCR register, then set 83036270Swpaul * the ThunderLAN for full or half-duplex as needed. 83136270Swpaul * 83236270Swpaul * I struggled for two days to figure this out, so I'm making a point 83336270Swpaul * of drawing attention to this fact. I think it's very strange that 83436270Swpaul * the ThunderLAN doesn't automagically track the duplex state of the 83536270Swpaul * PHY, but there you have it. 83636270Swpaul * 83736270Swpaul * Also when, using a National Semiconductor DP83840A PHY, we have to 83836270Swpaul * allow a full three seconds for autonegotiation to complete. So what 83936270Swpaul * we do is flip the autonegotiation restart bit, then set a timeout 84036270Swpaul * to wake us up in three seconds to check the link state. 84139583Swpaul * 84239583Swpaul * Note that there are some versions of the Olicom 2326 that use a 84339583Swpaul * Micro Linear ML6692 100BaseTX PHY. This particular PHY is designed 84439583Swpaul * to provide 100BaseTX support only, but can be used with a controller 84539583Swpaul * that supports an internal 10Mbps PHY to provide a complete 84639583Swpaul * 10/100Mbps solution. However, the ML6692 does not have vendor and 84739583Swpaul * device ID registers, and hence always shows up with a vendor/device 84839583Swpaul * ID of 0. 84939583Swpaul * 85039583Swpaul * We detect this configuration by checking the phy vendor ID in the 85139583Swpaul * softc structure. If it's a zero, and we're negotiating a high-speed 85239583Swpaul * mode, then we turn off the internal PHY. If it's a zero and we've 85339583Swpaul * negotiated a high-speed mode, we turn on the internal PHY. Note 85439583Swpaul * that to make things even more fun, we have to make extra sure that 85539583Swpaul * the loopback bit in the internal PHY's control register is turned 85639583Swpaul * off. 85736270Swpaul */ 85836270Swpaulstatic void tl_autoneg(sc, flag, verbose) 85936270Swpaul struct tl_softc *sc; 86036270Swpaul int flag; 86136270Swpaul int verbose; 86236270Swpaul{ 86338030Swpaul u_int16_t phy_sts = 0, media = 0, advert, ability; 86436270Swpaul struct ifnet *ifp; 86536270Swpaul struct ifmedia *ifm; 86636270Swpaul 86736270Swpaul ifm = &sc->ifmedia; 86836270Swpaul ifp = &sc->arpcom.ac_if; 86936270Swpaul 87036270Swpaul /* 87136270Swpaul * First, see if autoneg is supported. If not, there's 87236270Swpaul * no point in continuing. 87336270Swpaul */ 87436270Swpaul phy_sts = tl_phy_readreg(sc, PHY_BMSR); 87536270Swpaul if (!(phy_sts & PHY_BMSR_CANAUTONEG)) { 87636270Swpaul if (verbose) 87736270Swpaul printf("tl%d: autonegotiation not supported\n", 87836270Swpaul sc->tl_unit); 87936270Swpaul return; 88036270Swpaul } 88136270Swpaul 88236270Swpaul switch (flag) { 88336270Swpaul case TL_FLAG_FORCEDELAY: 88436270Swpaul /* 88536270Swpaul * XXX Never use this option anywhere but in the probe 88636270Swpaul * routine: making the kernel stop dead in its tracks 88736270Swpaul * for three whole seconds after we've gone multi-user 88836270Swpaul * is really bad manners. 88936270Swpaul */ 89038030Swpaul tl_phy_writereg(sc, PHY_BMCR, PHY_BMCR_RESET); 89138030Swpaul DELAY(500); 89236270Swpaul phy_sts = tl_phy_readreg(sc, PHY_BMCR); 89336270Swpaul phy_sts |= PHY_BMCR_AUTONEGENBL|PHY_BMCR_AUTONEGRSTR; 89436270Swpaul tl_phy_writereg(sc, PHY_BMCR, phy_sts); 89539583Swpaul DELAY(5000000); 89636270Swpaul break; 89736270Swpaul case TL_FLAG_SCHEDDELAY: 89837626Swpaul /* 89937626Swpaul * Wait for the transmitter to go idle before starting 90037626Swpaul * an autoneg session, otherwise tl_start() may clobber 90137626Swpaul * our timeout, and we don't want to allow transmission 90237626Swpaul * during an autoneg session since that can screw it up. 90337626Swpaul */ 90437626Swpaul if (!sc->tl_txeoc) { 90537626Swpaul sc->tl_want_auto = 1; 90637626Swpaul return; 90737626Swpaul } 90838030Swpaul tl_phy_writereg(sc, PHY_BMCR, PHY_BMCR_RESET); 90938030Swpaul DELAY(500); 91036270Swpaul phy_sts = tl_phy_readreg(sc, PHY_BMCR); 91136270Swpaul phy_sts |= PHY_BMCR_AUTONEGENBL|PHY_BMCR_AUTONEGRSTR; 91236270Swpaul tl_phy_writereg(sc, PHY_BMCR, phy_sts); 91339583Swpaul ifp->if_timer = 5; 91436270Swpaul sc->tl_autoneg = 1; 91537626Swpaul sc->tl_want_auto = 0; 91636270Swpaul return; 91736270Swpaul case TL_FLAG_DELAYTIMEO: 91836270Swpaul ifp->if_timer = 0; 91936270Swpaul sc->tl_autoneg = 0; 92036270Swpaul break; 92136270Swpaul default: 92239583Swpaul printf("tl%d: invalid autoneg flag: %d\n", sc->tl_unit, flag); 92336270Swpaul return; 92436270Swpaul } 92536270Swpaul 92636270Swpaul /* 92736270Swpaul * Read the BMSR register twice: the LINKSTAT bit is a 92836270Swpaul * latching bit. 92936270Swpaul */ 93036270Swpaul tl_phy_readreg(sc, PHY_BMSR); 93136270Swpaul phy_sts = tl_phy_readreg(sc, PHY_BMSR); 93236270Swpaul if (phy_sts & PHY_BMSR_AUTONEGCOMP) { 93336270Swpaul if (verbose) 93436270Swpaul printf("tl%d: autoneg complete, ", sc->tl_unit); 93536270Swpaul phy_sts = tl_phy_readreg(sc, PHY_BMSR); 93636270Swpaul } else { 93736270Swpaul if (verbose) 93836270Swpaul printf("tl%d: autoneg not complete, ", sc->tl_unit); 93936270Swpaul } 94036270Swpaul 94136270Swpaul /* Link is good. Report modes and set duplex mode. */ 94236270Swpaul if (phy_sts & PHY_BMSR_LINKSTAT) { 94336270Swpaul if (verbose) 94436270Swpaul printf("link status good "); 94538030Swpaul 94638030Swpaul advert = tl_phy_readreg(sc, TL_PHY_ANAR); 94738030Swpaul ability = tl_phy_readreg(sc, TL_PHY_LPAR); 94836270Swpaul media = tl_phy_readreg(sc, PHY_BMCR); 94936270Swpaul 95038030Swpaul /* 95138030Swpaul * Be sure to turn off the ISOLATE and 95238030Swpaul * LOOPBACK bits in the control register, 95338030Swpaul * otherwise we may not be able to communicate. 95438030Swpaul */ 95538030Swpaul media &= ~(PHY_BMCR_LOOPBK|PHY_BMCR_ISOLATE); 95636270Swpaul /* Set the DUPLEX bit in the NetCmd register accordingly. */ 95738030Swpaul if (advert & PHY_ANAR_100BT4 && ability & PHY_ANAR_100BT4) { 95838030Swpaul ifm->ifm_media = IFM_ETHER|IFM_100_T4; 95939583Swpaul media |= PHY_BMCR_SPEEDSEL; 96039583Swpaul media &= ~PHY_BMCR_DUPLEX; 96136270Swpaul if (verbose) 96238030Swpaul printf("(100baseT4)\n"); 96338030Swpaul } else if (advert & PHY_ANAR_100BTXFULL && 96438030Swpaul ability & PHY_ANAR_100BTXFULL) { 96538030Swpaul ifm->ifm_media = IFM_ETHER|IFM_100_TX|IFM_FDX; 96638030Swpaul media |= PHY_BMCR_SPEEDSEL; 96738030Swpaul media |= PHY_BMCR_DUPLEX; 96836270Swpaul if (verbose) 96938030Swpaul printf("(full-duplex, 100Mbps)\n"); 97038030Swpaul } else if (advert & PHY_ANAR_100BTXHALF && 97138030Swpaul ability & PHY_ANAR_100BTXHALF) { 97238030Swpaul ifm->ifm_media = IFM_ETHER|IFM_100_TX|IFM_HDX; 97338030Swpaul media |= PHY_BMCR_SPEEDSEL; 97438030Swpaul media &= ~PHY_BMCR_DUPLEX; 97536270Swpaul if (verbose) 97638030Swpaul printf("(half-duplex, 100Mbps)\n"); 97738030Swpaul } else if (advert & PHY_ANAR_10BTFULL && 97838030Swpaul ability & PHY_ANAR_10BTFULL) { 97938030Swpaul ifm->ifm_media = IFM_ETHER|IFM_10_T|IFM_FDX; 98038030Swpaul media &= ~PHY_BMCR_SPEEDSEL; 98138030Swpaul media |= PHY_BMCR_DUPLEX; 98238030Swpaul if (verbose) 98338030Swpaul printf("(full-duplex, 10Mbps)\n"); 98436270Swpaul } else { 98538030Swpaul ifm->ifm_media = IFM_ETHER|IFM_10_T|IFM_HDX; 98638030Swpaul media &= ~PHY_BMCR_SPEEDSEL; 98738030Swpaul media &= ~PHY_BMCR_DUPLEX; 98836270Swpaul if (verbose) 98938030Swpaul printf("(half-duplex, 10Mbps)\n"); 99036270Swpaul } 99139583Swpaul 99239583Swpaul if (media & PHY_BMCR_DUPLEX) 99339583Swpaul tl_dio_setbit(sc, TL_NETCMD, TL_CMD_DUPLEX); 99439583Swpaul else 99539583Swpaul tl_dio_clrbit(sc, TL_NETCMD, TL_CMD_DUPLEX); 99639583Swpaul 99736270Swpaul media &= ~PHY_BMCR_AUTONEGENBL; 99836270Swpaul tl_phy_writereg(sc, PHY_BMCR, media); 99936270Swpaul } else { 100036270Swpaul if (verbose) 100136270Swpaul printf("no carrier\n"); 100236270Swpaul } 100336270Swpaul 100438030Swpaul tl_init(sc); 100538030Swpaul 100637626Swpaul if (sc->tl_tx_pend) { 100737626Swpaul sc->tl_autoneg = 0; 100837626Swpaul sc->tl_tx_pend = 0; 100937626Swpaul tl_start(ifp); 101037626Swpaul } 101137626Swpaul 101236270Swpaul return; 101336270Swpaul} 101436270Swpaul 101536270Swpaul/* 101636270Swpaul * Set speed and duplex mode. Also program autoneg advertisements 101736270Swpaul * accordingly. 101836270Swpaul */ 101936270Swpaulstatic void tl_setmode(sc, media) 102036270Swpaul struct tl_softc *sc; 102136270Swpaul int media; 102236270Swpaul{ 102339583Swpaul u_int16_t bmcr; 102436270Swpaul 102545155Swpaul if (sc->tl_bitrate) { 102645155Swpaul if (IFM_SUBTYPE(media) == IFM_10_5) 102745155Swpaul tl_dio_setbit(sc, TL_ACOMMIT, TL_AC_MTXD1); 102845155Swpaul if (IFM_SUBTYPE(media) == IFM_10_T) { 102945155Swpaul tl_dio_clrbit(sc, TL_ACOMMIT, TL_AC_MTXD1); 103045155Swpaul if ((media & IFM_GMASK) == IFM_FDX) { 103145155Swpaul tl_dio_clrbit(sc, TL_ACOMMIT, TL_AC_MTXD3); 103245155Swpaul tl_dio_setbit(sc, TL_NETCMD, TL_CMD_DUPLEX); 103345155Swpaul } else { 103445155Swpaul tl_dio_setbit(sc, TL_ACOMMIT, TL_AC_MTXD3); 103545155Swpaul tl_dio_clrbit(sc, TL_NETCMD, TL_CMD_DUPLEX); 103645155Swpaul } 103745155Swpaul } 103845155Swpaul return; 103945155Swpaul } 104045155Swpaul 104136270Swpaul bmcr = tl_phy_readreg(sc, PHY_BMCR); 104236270Swpaul 104336270Swpaul bmcr &= ~(PHY_BMCR_SPEEDSEL|PHY_BMCR_DUPLEX|PHY_BMCR_AUTONEGENBL| 104438030Swpaul PHY_BMCR_LOOPBK|PHY_BMCR_ISOLATE); 104536270Swpaul 104636270Swpaul if (IFM_SUBTYPE(media) == IFM_LOOP) 104736270Swpaul bmcr |= PHY_BMCR_LOOPBK; 104836270Swpaul 104936270Swpaul if (IFM_SUBTYPE(media) == IFM_AUTO) 105036270Swpaul bmcr |= PHY_BMCR_AUTONEGENBL; 105136270Swpaul 105239583Swpaul /* 105339583Swpaul * The ThunderLAN's internal PHY has an AUI transceiver 105439583Swpaul * that can be selected. This is usually attached to a 105539583Swpaul * 10base2/BNC port. In order to activate this port, we 105639583Swpaul * have to set the AUISEL bit in the internal PHY's 105739583Swpaul * special control register. 105839583Swpaul */ 105938030Swpaul if (IFM_SUBTYPE(media) == IFM_10_5) { 106039583Swpaul u_int16_t addr, ctl; 106139583Swpaul addr = sc->tl_phy_addr; 106239583Swpaul sc->tl_phy_addr = TL_PHYADDR_MAX; 106339583Swpaul ctl = tl_phy_readreg(sc, TL_PHY_CTL); 106436270Swpaul ctl |= PHY_CTL_AUISEL; 106538030Swpaul tl_phy_writereg(sc, TL_PHY_CTL, ctl); 106639583Swpaul tl_phy_writereg(sc, PHY_BMCR, bmcr); 106739583Swpaul sc->tl_phy_addr = addr; 106839583Swpaul bmcr |= PHY_BMCR_ISOLATE; 106939583Swpaul } else { 107039583Swpaul u_int16_t addr, ctl; 107139583Swpaul addr = sc->tl_phy_addr; 107239583Swpaul sc->tl_phy_addr = TL_PHYADDR_MAX; 107339583Swpaul ctl = tl_phy_readreg(sc, TL_PHY_CTL); 107439583Swpaul ctl &= ~PHY_CTL_AUISEL; 107539583Swpaul tl_phy_writereg(sc, TL_PHY_CTL, ctl); 107639583Swpaul tl_phy_writereg(sc, PHY_BMCR, PHY_BMCR_ISOLATE); 107739583Swpaul sc->tl_phy_addr = addr; 107839583Swpaul bmcr &= ~PHY_BMCR_ISOLATE; 107938030Swpaul } 108036270Swpaul 108136270Swpaul if (IFM_SUBTYPE(media) == IFM_100_TX) { 108236270Swpaul bmcr |= PHY_BMCR_SPEEDSEL; 108336270Swpaul if ((media & IFM_GMASK) == IFM_FDX) { 108436270Swpaul bmcr |= PHY_BMCR_DUPLEX; 108539583Swpaul tl_dio_setbit(sc, TL_NETCMD, TL_CMD_DUPLEX); 108636270Swpaul } else { 108736270Swpaul bmcr &= ~PHY_BMCR_DUPLEX; 108839583Swpaul tl_dio_clrbit(sc, TL_NETCMD, TL_CMD_DUPLEX); 108936270Swpaul } 109036270Swpaul } 109136270Swpaul 109236270Swpaul if (IFM_SUBTYPE(media) == IFM_10_T) { 109336270Swpaul bmcr &= ~PHY_BMCR_SPEEDSEL; 109436270Swpaul if ((media & IFM_GMASK) == IFM_FDX) { 109536270Swpaul bmcr |= PHY_BMCR_DUPLEX; 109639583Swpaul tl_dio_setbit(sc, TL_NETCMD, TL_CMD_DUPLEX); 109736270Swpaul } else { 109836270Swpaul bmcr &= ~PHY_BMCR_DUPLEX; 109939583Swpaul tl_dio_clrbit(sc, TL_NETCMD, TL_CMD_DUPLEX); 110036270Swpaul } 110136270Swpaul } 110236270Swpaul 110336270Swpaul tl_phy_writereg(sc, PHY_BMCR, bmcr); 110436270Swpaul 110538030Swpaul tl_init(sc); 110638030Swpaul 110736270Swpaul return; 110836270Swpaul} 110936270Swpaul 111036464Swpaul/* 111136464Swpaul * Calculate the hash of a MAC address for programming the multicast hash 111236464Swpaul * table. This hash is simply the address split into 6-bit chunks 111336464Swpaul * XOR'd, e.g. 111436464Swpaul * byte: 000000|00 1111|1111 22|222222|333333|33 4444|4444 55|555555 111536464Swpaul * bit: 765432|10 7654|3210 76|543210|765432|10 7654|3210 76|543210 111636464Swpaul * Bytes 0-2 and 3-5 are symmetrical, so are folded together. Then 111736464Swpaul * the folded 24-bit value is split into 6-bit portions and XOR'd. 111836464Swpaul */ 111936270Swpaulstatic int tl_calchash(addr) 112041656Swpaul caddr_t addr; 112136270Swpaul{ 112237626Swpaul int t; 112336270Swpaul 112436464Swpaul t = (addr[0] ^ addr[3]) << 16 | (addr[1] ^ addr[4]) << 8 | 112536464Swpaul (addr[2] ^ addr[5]); 112636464Swpaul return ((t >> 18) ^ (t >> 12) ^ (t >> 6) ^ t) & 0x3f; 112736270Swpaul} 112836270Swpaul 112939583Swpaul/* 113039583Swpaul * The ThunderLAN has a perfect MAC address filter in addition to 113139583Swpaul * the multicast hash filter. The perfect filter can be programmed 113239583Swpaul * with up to four MAC addresses. The first one is always used to 113339583Swpaul * hold the station address, which leaves us free to use the other 113439583Swpaul * three for multicast addresses. 113539583Swpaul */ 113639583Swpaulstatic void tl_setfilt(sc, addr, slot) 113739583Swpaul struct tl_softc *sc; 113841656Swpaul caddr_t addr; 113939583Swpaul int slot; 114039583Swpaul{ 114139583Swpaul int i; 114239583Swpaul u_int16_t regaddr; 114339583Swpaul 114439583Swpaul regaddr = TL_AREG0_B5 + (slot * ETHER_ADDR_LEN); 114539583Swpaul 114639583Swpaul for (i = 0; i < ETHER_ADDR_LEN; i++) 114739583Swpaul tl_dio_write8(sc, regaddr + i, *(addr + i)); 114839583Swpaul 114939583Swpaul return; 115039583Swpaul} 115139583Swpaul 115239583Swpaul/* 115339583Swpaul * XXX In FreeBSD 3.0, multicast addresses are managed using a doubly 115439583Swpaul * linked list. This is fine, except addresses are added from the head 115539583Swpaul * end of the list. We want to arrange for 224.0.0.1 (the "all hosts") 115639583Swpaul * group to always be in the perfect filter, but as more groups are added, 115739583Swpaul * the 224.0.0.1 entry (which is always added first) gets pushed down 115839583Swpaul * the list and ends up at the tail. So after 3 or 4 multicast groups 115939583Swpaul * are added, the all-hosts entry gets pushed out of the perfect filter 116039583Swpaul * and into the hash table. 116139583Swpaul * 116239583Swpaul * Because the multicast list is a doubly-linked list as opposed to a 116339583Swpaul * circular queue, we don't have the ability to just grab the tail of 116439583Swpaul * the list and traverse it backwards. Instead, we have to traverse 116539583Swpaul * the list once to find the tail, then traverse it again backwards to 116639583Swpaul * update the multicast filter. 116739583Swpaul */ 116836270Swpaulstatic void tl_setmulti(sc) 116936270Swpaul struct tl_softc *sc; 117036270Swpaul{ 117136270Swpaul struct ifnet *ifp; 117236270Swpaul u_int32_t hashes[2] = { 0, 0 }; 117339583Swpaul int h, i; 117436270Swpaul struct ifmultiaddr *ifma; 117539583Swpaul u_int8_t dummy[] = { 0, 0, 0, 0, 0 ,0 }; 117636270Swpaul ifp = &sc->arpcom.ac_if; 117736270Swpaul 117839583Swpaul /* First, zot all the existing filters. */ 117939583Swpaul for (i = 1; i < 4; i++) 118041656Swpaul tl_setfilt(sc, (caddr_t)&dummy, i); 118139583Swpaul tl_dio_write32(sc, TL_HASH1, 0); 118239583Swpaul tl_dio_write32(sc, TL_HASH2, 0); 118339583Swpaul 118439583Swpaul /* Now program new ones. */ 118539583Swpaul if (ifp->if_flags & IFF_ALLMULTI) { 118636270Swpaul hashes[0] = 0xFFFFFFFF; 118736270Swpaul hashes[1] = 0xFFFFFFFF; 118836270Swpaul } else { 118939583Swpaul i = 1; 119039583Swpaul /* First find the tail of the list. */ 119136270Swpaul for (ifma = ifp->if_multiaddrs.lh_first; ifma != NULL; 119236270Swpaul ifma = ifma->ifma_link.le_next) { 119339583Swpaul if (ifma->ifma_link.le_next == NULL) 119439583Swpaul break; 119539583Swpaul } 119639583Swpaul /* Now traverse the list backwards. */ 119739583Swpaul for (; ifma != NULL && ifma != (void *)&ifp->if_multiaddrs; 119839583Swpaul ifma = (struct ifmultiaddr *)ifma->ifma_link.le_prev) { 119936270Swpaul if (ifma->ifma_addr->sa_family != AF_LINK) 120036270Swpaul continue; 120139583Swpaul /* 120239583Swpaul * Program the first three multicast groups 120339583Swpaul * into the perfect filter. For all others, 120439583Swpaul * use the hash table. 120539583Swpaul */ 120639583Swpaul if (i < 4) { 120739583Swpaul tl_setfilt(sc, 120839583Swpaul LLADDR((struct sockaddr_dl *)ifma->ifma_addr), i); 120939583Swpaul i++; 121039583Swpaul continue; 121139583Swpaul } 121239583Swpaul 121336270Swpaul h = tl_calchash( 121436270Swpaul LLADDR((struct sockaddr_dl *)ifma->ifma_addr)); 121536270Swpaul if (h < 32) 121636270Swpaul hashes[0] |= (1 << h); 121736270Swpaul else 121836317Swpaul hashes[1] |= (1 << (h - 32)); 121936270Swpaul } 122036270Swpaul } 122136270Swpaul 122239583Swpaul tl_dio_write32(sc, TL_HASH1, hashes[0]); 122339583Swpaul tl_dio_write32(sc, TL_HASH2, hashes[1]); 122436270Swpaul 122536270Swpaul return; 122636270Swpaul} 122736270Swpaul 122839583Swpaul/* 122939583Swpaul * This routine is recommended by the ThunderLAN manual to insure that 123039583Swpaul * the internal PHY is powered up correctly. It also recommends a one 123139583Swpaul * second pause at the end to 'wait for the clocks to start' but in my 123239583Swpaul * experience this isn't necessary. 123339583Swpaul */ 123439583Swpaulstatic void tl_hardreset(sc) 123539583Swpaul struct tl_softc *sc; 123639583Swpaul{ 123739583Swpaul int i; 123839583Swpaul u_int16_t old_addr, flags; 123939583Swpaul 124039583Swpaul old_addr = sc->tl_phy_addr; 124139583Swpaul 124239583Swpaul for (i = 0; i < TL_PHYADDR_MAX + 1; i++) { 124339583Swpaul sc->tl_phy_addr = i; 124439583Swpaul tl_mii_sync(sc); 124539583Swpaul } 124639583Swpaul 124739583Swpaul flags = PHY_BMCR_LOOPBK|PHY_BMCR_ISOLATE|PHY_BMCR_PWRDOWN; 124839583Swpaul 124939583Swpaul for (i = 0; i < TL_PHYADDR_MAX + 1; i++) { 125039583Swpaul sc->tl_phy_addr = i; 125139583Swpaul tl_phy_writereg(sc, PHY_BMCR, flags); 125239583Swpaul } 125339583Swpaul 125439583Swpaul sc->tl_phy_addr = TL_PHYADDR_MAX; 125539583Swpaul tl_phy_writereg(sc, PHY_BMCR, PHY_BMCR_ISOLATE); 125639583Swpaul 125739583Swpaul DELAY(50000); 125839583Swpaul 125939583Swpaul tl_phy_writereg(sc, PHY_BMCR, PHY_BMCR_LOOPBK|PHY_BMCR_ISOLATE); 126039583Swpaul 126139583Swpaul tl_mii_sync(sc); 126239583Swpaul 126339583Swpaul while(tl_phy_readreg(sc, PHY_BMCR) & PHY_BMCR_RESET); 126439583Swpaul 126539583Swpaul sc->tl_phy_addr = old_addr; 126639583Swpaul 126739583Swpaul return; 126839583Swpaul} 126939583Swpaul 127039583Swpaulstatic void tl_softreset(sc, internal) 127139583Swpaul struct tl_softc *sc; 127236270Swpaul int internal; 127336270Swpaul{ 127439583Swpaul u_int32_t cmd, dummy, i; 127536270Swpaul 127636270Swpaul /* Assert the adapter reset bit. */ 127739583Swpaul CMD_SET(sc, TL_CMD_ADRST); 127836270Swpaul /* Turn off interrupts */ 127939583Swpaul CMD_SET(sc, TL_CMD_INTSOFF); 128036270Swpaul 128136270Swpaul /* First, clear the stats registers. */ 128239583Swpaul for (i = 0; i < 5; i++) 128339583Swpaul dummy = tl_dio_read32(sc, TL_TXGOODFRAMES); 128436270Swpaul 128536270Swpaul /* Clear Areg and Hash registers */ 128639583Swpaul for (i = 0; i < 8; i++) 128739583Swpaul tl_dio_write32(sc, TL_AREG0_B5, 0x00000000); 128836270Swpaul 128936270Swpaul /* 129036270Swpaul * Set up Netconfig register. Enable one channel and 129136270Swpaul * one fragment mode. 129236270Swpaul */ 129339583Swpaul tl_dio_setbit16(sc, TL_NETCONFIG, TL_CFG_ONECHAN|TL_CFG_ONEFRAG); 129445155Swpaul if (internal && !sc->tl_bitrate) { 129539583Swpaul tl_dio_setbit16(sc, TL_NETCONFIG, TL_CFG_PHYEN); 129636270Swpaul } else { 129739583Swpaul tl_dio_clrbit16(sc, TL_NETCONFIG, TL_CFG_PHYEN); 129836270Swpaul } 129936270Swpaul 130045155Swpaul /* Handle cards with bitrate devices. */ 130145155Swpaul if (sc->tl_bitrate) 130245155Swpaul tl_dio_setbit16(sc, TL_NETCONFIG, TL_CFG_BITRATE); 130345155Swpaul 130436270Swpaul /* Set PCI burst size */ 130539583Swpaul tl_dio_write8(sc, TL_BSIZEREG, 0x33); 130636270Swpaul 130736270Swpaul /* 130836270Swpaul * Load adapter irq pacing timer and tx threshold. 130936270Swpaul * We make the transmit threshold 1 initially but we may 131036270Swpaul * change that later. 131136270Swpaul */ 131239583Swpaul cmd = CSR_READ_4(sc, TL_HOSTCMD); 131336270Swpaul cmd |= TL_CMD_NES; 131436270Swpaul cmd &= ~(TL_CMD_RT|TL_CMD_EOC|TL_CMD_ACK_MASK|TL_CMD_CHSEL_MASK); 131539583Swpaul CMD_PUT(sc, cmd | (TL_CMD_LDTHR | TX_THR)); 131639583Swpaul CMD_PUT(sc, cmd | (TL_CMD_LDTMR | 0x00000003)); 131736270Swpaul 131836270Swpaul /* Unreset the MII */ 131939583Swpaul tl_dio_setbit(sc, TL_NETSIO, TL_SIO_NMRST); 132036270Swpaul 132136270Swpaul /* Clear status register */ 132239583Swpaul tl_dio_setbit16(sc, TL_NETSTS, TL_STS_MIRQ); 132339583Swpaul tl_dio_setbit16(sc, TL_NETSTS, TL_STS_HBEAT); 132439583Swpaul tl_dio_setbit16(sc, TL_NETSTS, TL_STS_TXSTOP); 132539583Swpaul tl_dio_setbit16(sc, TL_NETSTS, TL_STS_RXSTOP); 132636270Swpaul 132736270Swpaul /* Enable network status interrupts for everything. */ 132839583Swpaul tl_dio_setbit(sc, TL_NETMASK, TL_MASK_MASK7|TL_MASK_MASK6| 132936270Swpaul TL_MASK_MASK5|TL_MASK_MASK4); 133036270Swpaul 133136270Swpaul /* Take the adapter out of reset */ 133239583Swpaul tl_dio_setbit(sc, TL_NETCMD, TL_CMD_NRESET|TL_CMD_NWRAP); 133336270Swpaul 133436270Swpaul /* Wait for things to settle down a little. */ 133536270Swpaul DELAY(500); 133636270Swpaul 133736270Swpaul return; 133836270Swpaul} 133936270Swpaul 134036270Swpaul/* 134136270Swpaul * Probe for a ThunderLAN chip. Check the PCI vendor and device IDs 134239583Swpaul * against our list and return its name if we find a match. 134336270Swpaul */ 134441771Sdillonstatic const char * 134536270Swpaultl_probe(config_id, device_id) 134636270Swpaul pcici_t config_id; 134736270Swpaul pcidi_t device_id; 134836270Swpaul{ 134936270Swpaul struct tl_type *t; 135036270Swpaul 135136270Swpaul t = tl_devs; 135236270Swpaul 135336270Swpaul while(t->tl_name != NULL) { 135436270Swpaul if ((device_id & 0xFFFF) == t->tl_vid && 135539583Swpaul ((device_id >> 16) & 0xFFFF) == t->tl_did) 135636270Swpaul return(t->tl_name); 135736270Swpaul t++; 135836270Swpaul } 135936270Swpaul 136036270Swpaul return(NULL); 136136270Swpaul} 136236270Swpaul 136336270Swpaul/* 136436270Swpaul * Do the interface setup and attach for a PHY on a particular 136536270Swpaul * ThunderLAN chip. Also also set up interrupt vectors. 136636270Swpaul */ 136739583Swpaulstatic int tl_attach_phy(sc) 136839583Swpaul struct tl_softc *sc; 136936270Swpaul{ 137036270Swpaul int phy_ctl; 137136270Swpaul struct tl_type *p = tl_phys; 137239583Swpaul int media = IFM_ETHER|IFM_100_TX|IFM_FDX; 137339583Swpaul struct ifnet *ifp; 137436270Swpaul 137539583Swpaul ifp = &sc->arpcom.ac_if; 137636270Swpaul 137739583Swpaul sc->tl_phy_did = tl_phy_readreg(sc, TL_PHY_DEVID); 137839583Swpaul sc->tl_phy_vid = tl_phy_readreg(sc, TL_PHY_VENID); 137939583Swpaul sc->tl_phy_sts = tl_phy_readreg(sc, TL_PHY_GENSTS); 138039583Swpaul phy_ctl = tl_phy_readreg(sc, TL_PHY_GENCTL); 138136270Swpaul 138236270Swpaul /* 138336270Swpaul * PHY revision numbers tend to vary a bit. Our algorithm here 138436270Swpaul * is to check everything but the 8 least significant bits. 138536270Swpaul */ 138636270Swpaul while(p->tl_vid) { 138736270Swpaul if (sc->tl_phy_vid == p->tl_vid && 138836270Swpaul (sc->tl_phy_did | 0x000F) == p->tl_did) { 138936270Swpaul sc->tl_pinfo = p; 139036270Swpaul break; 139136270Swpaul } 139236270Swpaul p++; 139336270Swpaul } 139436270Swpaul if (sc->tl_pinfo == NULL) { 139536270Swpaul sc->tl_pinfo = &tl_phys[PHY_UNKNOWN]; 139636270Swpaul } 139736270Swpaul 139836270Swpaul if (sc->tl_phy_sts & PHY_BMSR_100BT4 || 139936270Swpaul sc->tl_phy_sts & PHY_BMSR_100BTXFULL || 140036270Swpaul sc->tl_phy_sts & PHY_BMSR_100BTXHALF) 140136270Swpaul ifp->if_baudrate = 100000000; 140236270Swpaul else 140336270Swpaul ifp->if_baudrate = 10000000; 140436270Swpaul 140539583Swpaul if (bootverbose) { 140639583Swpaul printf("tl%d: phy at mii address %d\n", sc->tl_unit, 140739583Swpaul sc->tl_phy_addr); 140836270Swpaul 140939583Swpaul printf("tl%d: %s ", sc->tl_unit, sc->tl_pinfo->tl_name); 141039583Swpaul } 141136270Swpaul 141236270Swpaul if (sc->tl_phy_sts & PHY_BMSR_100BT4 || 141336270Swpaul sc->tl_phy_sts & PHY_BMSR_100BTXHALF || 141436270Swpaul sc->tl_phy_sts & PHY_BMSR_100BTXHALF) 141539583Swpaul if (bootverbose) 141639583Swpaul printf("10/100Mbps "); 141736270Swpaul else { 141836270Swpaul media &= ~IFM_100_TX; 141936270Swpaul media |= IFM_10_T; 142039583Swpaul if (bootverbose) 142139583Swpaul printf("10Mbps "); 142236270Swpaul } 142336270Swpaul 142436270Swpaul if (sc->tl_phy_sts & PHY_BMSR_100BTXFULL || 142536270Swpaul sc->tl_phy_sts & PHY_BMSR_10BTFULL) 142639583Swpaul if (bootverbose) 142739583Swpaul printf("full duplex "); 142836270Swpaul else { 142939583Swpaul if (bootverbose) 143039583Swpaul printf("half duplex "); 143136270Swpaul media &= ~IFM_FDX; 143236270Swpaul } 143336270Swpaul 143436270Swpaul if (sc->tl_phy_sts & PHY_BMSR_CANAUTONEG) { 143536270Swpaul media = IFM_ETHER|IFM_AUTO; 143639583Swpaul if (bootverbose) 143739583Swpaul printf("autonegotiating\n"); 143836270Swpaul } else 143939583Swpaul if (bootverbose) 144039583Swpaul printf("\n"); 144136270Swpaul 144236270Swpaul /* If this isn't a known PHY, print the PHY indentifier info. */ 144339583Swpaul if (sc->tl_pinfo->tl_vid == 0 && bootverbose) 144436270Swpaul printf("tl%d: vendor id: %04x product id: %04x\n", 144536270Swpaul sc->tl_unit, sc->tl_phy_vid, sc->tl_phy_did); 144636270Swpaul 144736270Swpaul /* Set up ifmedia data and callbacks. */ 144836270Swpaul ifmedia_init(&sc->ifmedia, 0, tl_ifmedia_upd, tl_ifmedia_sts); 144936270Swpaul 145036270Swpaul /* 145136270Swpaul * All ThunderLANs support at least 10baseT half duplex. 145236270Swpaul * They also support AUI selection if used in 10Mb/s modes. 145336270Swpaul */ 145436270Swpaul ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_10_T|IFM_HDX, 0, NULL); 145536270Swpaul ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_10_T, 0, NULL); 145636270Swpaul ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_10_5, 0, NULL); 145736270Swpaul 145836270Swpaul /* Some ThunderLAN PHYs support autonegotiation. */ 145936270Swpaul if (sc->tl_phy_sts & PHY_BMSR_CANAUTONEG) 146036270Swpaul ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_AUTO, 0, NULL); 146136270Swpaul 146236270Swpaul /* Some support 10baseT full duplex. */ 146336270Swpaul if (sc->tl_phy_sts & PHY_BMSR_10BTFULL) 146436270Swpaul ifmedia_add(&sc->ifmedia, 146536270Swpaul IFM_ETHER|IFM_10_T|IFM_FDX, 0, NULL); 146636270Swpaul 146736270Swpaul /* Some support 100BaseTX half duplex. */ 146836270Swpaul if (sc->tl_phy_sts & PHY_BMSR_100BTXHALF) 146936270Swpaul ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_100_TX, 0, NULL); 147036270Swpaul if (sc->tl_phy_sts & PHY_BMSR_100BTXHALF) 147136270Swpaul ifmedia_add(&sc->ifmedia, 147236270Swpaul IFM_ETHER|IFM_100_TX|IFM_HDX, 0, NULL); 147336270Swpaul 147436270Swpaul /* Some support 100BaseTX full duplex. */ 147536270Swpaul if (sc->tl_phy_sts & PHY_BMSR_100BTXFULL) 147636270Swpaul ifmedia_add(&sc->ifmedia, 147736270Swpaul IFM_ETHER|IFM_100_TX|IFM_FDX, 0, NULL); 147836270Swpaul 147936270Swpaul /* Some also support 100BaseT4. */ 148036270Swpaul if (sc->tl_phy_sts & PHY_BMSR_100BT4) 148136270Swpaul ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_100_T4, 0, NULL); 148236270Swpaul 148336270Swpaul /* Set default media. */ 148436270Swpaul ifmedia_set(&sc->ifmedia, media); 148536270Swpaul 148636270Swpaul /* 148736270Swpaul * Kick off an autonegotiation session if this PHY supports it. 148836270Swpaul * This is necessary to make sure the chip's duplex mode matches 148936270Swpaul * the PHY's duplex mode. It may not: once enabled, the PHY may 149036270Swpaul * autonegotiate full-duplex mode with its link partner, but the 149136270Swpaul * ThunderLAN chip defaults to half-duplex and stays there unless 149236270Swpaul * told otherwise. 149336270Swpaul */ 149438030Swpaul if (sc->tl_phy_sts & PHY_BMSR_CANAUTONEG) { 149538030Swpaul tl_init(sc); 149639583Swpaul#ifdef TL_BACKGROUND_AUTONEG 149738030Swpaul tl_autoneg(sc, TL_FLAG_SCHEDDELAY, 1); 149839583Swpaul#else 149939583Swpaul tl_autoneg(sc, TL_FLAG_FORCEDELAY, 1); 150039583Swpaul#endif 150138030Swpaul } 150236270Swpaul 150336270Swpaul return(0); 150436270Swpaul} 150536270Swpaul 150636270Swpaulstatic void 150739583Swpaultl_attach(config_id, unit) 150836270Swpaul pcici_t config_id; 150936270Swpaul int unit; 151036270Swpaul{ 151136270Swpaul int s, i, phys = 0; 151239583Swpaul#ifndef TL_USEIOSPACE 151336270Swpaul vm_offset_t pbase, vbase; 151439583Swpaul#endif 151536270Swpaul u_int32_t command; 151639583Swpaul u_int16_t did, vid; 151739583Swpaul struct tl_type *t; 151839583Swpaul struct ifnet *ifp; 151939583Swpaul struct tl_softc *sc; 152039583Swpaul unsigned int round; 152139583Swpaul caddr_t roundptr; 152236270Swpaul 152336270Swpaul s = splimp(); 152436270Swpaul 152539583Swpaul vid = pci_cfgread(config_id, PCIR_VENDOR, 2); 152639583Swpaul did = pci_cfgread(config_id, PCIR_DEVICE, 2); 152739583Swpaul 152839583Swpaul t = tl_devs; 152939583Swpaul while(t->tl_name != NULL) { 153039583Swpaul if (vid == t->tl_vid && did == t->tl_did) 153136270Swpaul break; 153239583Swpaul t++; 153339583Swpaul } 153436270Swpaul 153539583Swpaul if (t->tl_name == NULL) { 153639583Swpaul printf("tl%d: unknown device!?\n", unit); 153736270Swpaul goto fail; 153836270Swpaul } 153936270Swpaul 154039583Swpaul /* First, allocate memory for the softc struct. */ 154139583Swpaul sc = malloc(sizeof(struct tl_softc), M_DEVBUF, M_NOWAIT); 154239583Swpaul if (sc == NULL) { 154339583Swpaul printf("tl%d: no memory for softc struct!\n", unit); 154439583Swpaul goto fail; 154539583Swpaul } 154639583Swpaul 154739583Swpaul bzero(sc, sizeof(struct tl_softc)); 154839583Swpaul 154936270Swpaul /* 155036270Swpaul * Map control/status registers. 155136270Swpaul */ 155236270Swpaul command = pci_conf_read(config_id, PCI_COMMAND_STATUS_REG); 155339583Swpaul command |= (PCIM_CMD_PORTEN|PCIM_CMD_MEMEN|PCIM_CMD_BUSMASTEREN); 155439583Swpaul pci_conf_write(config_id, PCI_COMMAND_STATUS_REG, command); 155539583Swpaul command = pci_conf_read(config_id, PCI_COMMAND_STATUS_REG); 155636270Swpaul 155739583Swpaul#ifdef TL_USEIOSPACE 155839583Swpaul if (!(command & PCIM_CMD_PORTEN)) { 155939583Swpaul printf("tl%d: failed to enable I/O ports!\n", unit); 156039583Swpaul free(sc, M_DEVBUF); 156139583Swpaul goto fail; 156239583Swpaul } 156339583Swpaul 156445155Swpaul if (!pci_map_port(config_id, TL_PCI_LOIO, 156545155Swpaul (u_short *)&(sc->tl_bhandle))) { 156645155Swpaul if (!pci_map_port(config_id, TL_PCI_LOMEM, 156745155Swpaul (u_short *)&(sc->tl_bhandle))) { 156845155Swpaul printf ("tl%d: couldn't map ports\n", unit); 156945155Swpaul goto fail; 157045155Swpaul } 157145155Swpaul } 157245155Swpaul#ifdef __alpha__ 157345155Swpaul sc->tl_btag = ALPHA_BUS_SPACE_IO; 157445155Swpaul#endif 157545155Swpaul#ifdef __i386__ 157645155Swpaul sc->tl_btag = I386_BUS_SPACE_IO; 157745155Swpaul#endif 157839583Swpaul#else 157936270Swpaul if (!(command & PCIM_CMD_MEMEN)) { 158039583Swpaul printf("tl%d: failed to enable memory mapping!\n", unit); 158136270Swpaul goto fail; 158236270Swpaul } 158336270Swpaul 158436270Swpaul if (!pci_map_mem(config_id, TL_PCI_LOMEM, &vbase, &pbase)) { 158545155Swpaul if (!pci_map_mem(config_id, TL_PCI_LOIO, &vbase, &pbase)) { 158645155Swpaul printf ("tl%d: couldn't map memory\n", unit); 158745155Swpaul goto fail; 158845155Swpaul } 158936270Swpaul } 159036270Swpaul 159145155Swpaul#ifdef __alpha__ 159245155Swpaul sc->tl_btag = ALPHA_BUS_SPACE_MEM; 159339583Swpaul#endif 159445155Swpaul#ifdef __i386__ 159545155Swpaul sc->tl_btag = I386_BUS_SPACE_MEM; 159645155Swpaul#endif 159745155Swpaul sc->tl_bhandle = vbase; 159845155Swpaul#endif 159936270Swpaul 160039583Swpaul#ifdef notdef 160139583Swpaul /* 160239583Swpaul * The ThunderLAN manual suggests jacking the PCI latency 160339583Swpaul * timer all the way up to its maximum value. I'm not sure 160439583Swpaul * if this is really necessary, but what the manual wants, 160539583Swpaul * the manual gets. 160639583Swpaul */ 160739583Swpaul command = pci_conf_read(config_id, TL_PCI_LATENCY_TIMER); 160839583Swpaul command |= 0x0000FF00; 160939583Swpaul pci_conf_write(config_id, TL_PCI_LATENCY_TIMER, command); 161039583Swpaul#endif 161136270Swpaul 161236270Swpaul /* Allocate interrupt */ 161339583Swpaul if (!pci_map_int(config_id, tl_intr, sc, &net_imask)) { 161439583Swpaul printf("tl%d: couldn't map interrupt\n", unit); 161536270Swpaul goto fail; 161636270Swpaul } 161736270Swpaul 161836270Swpaul /* 161939583Swpaul * Now allocate memory for the TX and RX lists. Note that 162039583Swpaul * we actually allocate 8 bytes more than we really need: 162139583Swpaul * this is because we need to adjust the final address to 162239583Swpaul * be aligned on a quadword (64-bit) boundary in order to 162339583Swpaul * make the chip happy. If the list structures aren't properly 162439583Swpaul * aligned, DMA fails and the chip generates an adapter check 162539583Swpaul * interrupt and has to be reset. If you set up the softc struct 162639583Swpaul * just right you can sort of obtain proper alignment 'by chance.' 162739583Swpaul * But I don't want to depend on this, so instead the alignment 162839583Swpaul * is forced here. 162936270Swpaul */ 163039583Swpaul sc->tl_ldata_ptr = malloc(sizeof(struct tl_list_data) + 8, 163139583Swpaul M_DEVBUF, M_NOWAIT); 163239583Swpaul 163339583Swpaul if (sc->tl_ldata_ptr == NULL) { 163439583Swpaul free(sc, M_DEVBUF); 163539583Swpaul printf("tl%d: no memory for list buffers!\n", unit); 163636270Swpaul goto fail; 163736270Swpaul } 163836270Swpaul 163936270Swpaul /* 164039583Swpaul * Convoluted but satisfies my ANSI sensibilities. GCC lets 164139583Swpaul * you do casts on the LHS of an assignment, but ANSI doesn't 164239583Swpaul * allow that. 164338030Swpaul */ 164439583Swpaul sc->tl_ldata = (struct tl_list_data *)sc->tl_ldata_ptr; 164539583Swpaul round = (unsigned int)sc->tl_ldata_ptr & 0xF; 164639583Swpaul roundptr = sc->tl_ldata_ptr; 164739583Swpaul for (i = 0; i < 8; i++) { 164839583Swpaul if (round % 8) { 164939583Swpaul round++; 165039583Swpaul roundptr++; 165139583Swpaul } else 165239583Swpaul break; 165338030Swpaul } 165439583Swpaul sc->tl_ldata = (struct tl_list_data *)roundptr; 165538030Swpaul 165639583Swpaul bzero(sc->tl_ldata, sizeof(struct tl_list_data)); 165739583Swpaul 165839583Swpaul sc->tl_unit = unit; 165939583Swpaul sc->tl_dinfo = t; 166043235Swpaul if (t->tl_vid == COMPAQ_VENDORID || t->tl_vid == TI_VENDORID) 166139583Swpaul sc->tl_eeaddr = TL_EEPROM_EADDR; 166239583Swpaul if (t->tl_vid == OLICOM_VENDORID) 166339583Swpaul sc->tl_eeaddr = TL_EEPROM_EADDR_OC; 166439583Swpaul 166539583Swpaul /* Reset the adapter. */ 166639583Swpaul tl_softreset(sc, 1); 166739583Swpaul tl_hardreset(sc); 166839583Swpaul tl_softreset(sc, 1); 166939583Swpaul 167038030Swpaul /* 167139583Swpaul * Get station address from the EEPROM. 167239583Swpaul */ 167339583Swpaul if (tl_read_eeprom(sc, (caddr_t)&sc->arpcom.ac_enaddr, 167439583Swpaul sc->tl_eeaddr, ETHER_ADDR_LEN)) { 167539583Swpaul printf("tl%d: failed to read station address\n", unit); 167639583Swpaul goto fail; 167739583Swpaul } 167839583Swpaul 167939583Swpaul /* 168039583Swpaul * XXX Olicom, in its desire to be different from the 168139583Swpaul * rest of the world, has done strange things with the 168239583Swpaul * encoding of the station address in the EEPROM. First 168339583Swpaul * of all, they store the address at offset 0xF8 rather 168439583Swpaul * than at 0x83 like the ThunderLAN manual suggests. 168539583Swpaul * Second, they store the address in three 16-bit words in 168639583Swpaul * network byte order, as opposed to storing it sequentially 168739583Swpaul * like all the other ThunderLAN cards. In order to get 168839583Swpaul * the station address in a form that matches what the Olicom 168939583Swpaul * diagnostic utility specifies, we have to byte-swap each 169039583Swpaul * word. To make things even more confusing, neither 00:00:28 169139583Swpaul * nor 00:00:24 appear in the IEEE OUI database. 169239583Swpaul */ 169339583Swpaul if (sc->tl_dinfo->tl_vid == OLICOM_VENDORID) { 169439583Swpaul for (i = 0; i < ETHER_ADDR_LEN; i += 2) { 169539583Swpaul u_int16_t *p; 169639583Swpaul p = (u_int16_t *)&sc->arpcom.ac_enaddr[i]; 169739583Swpaul *p = ntohs(*p); 169839583Swpaul } 169939583Swpaul } 170039583Swpaul 170139583Swpaul /* 170236270Swpaul * A ThunderLAN chip was detected. Inform the world. 170336270Swpaul */ 170439583Swpaul printf("tl%d: Ethernet address: %6D\n", unit, 170539583Swpaul sc->arpcom.ac_enaddr, ":"); 170636270Swpaul 170739583Swpaul ifp = &sc->arpcom.ac_if; 170839583Swpaul ifp->if_softc = sc; 170939583Swpaul ifp->if_unit = sc->tl_unit; 171039583Swpaul ifp->if_name = "tl"; 171139583Swpaul ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 171239583Swpaul ifp->if_ioctl = tl_ioctl; 171339583Swpaul ifp->if_output = ether_output; 171439583Swpaul ifp->if_start = tl_start; 171539583Swpaul ifp->if_watchdog = tl_watchdog; 171639583Swpaul ifp->if_init = tl_init; 171739583Swpaul ifp->if_mtu = ETHERMTU; 171843515Swpaul ifp->if_snd.ifq_maxlen = TL_TX_LIST_CNT - 1; 171939583Swpaul callout_handle_init(&sc->tl_stat_ch); 172039583Swpaul 172139583Swpaul /* Reset the adapter again. */ 172239583Swpaul tl_softreset(sc, 1); 172339583Swpaul tl_hardreset(sc); 172439583Swpaul tl_softreset(sc, 1); 172539583Swpaul 172636270Swpaul /* 172736270Swpaul * Now attach the ThunderLAN's PHYs. There will always 172836270Swpaul * be at least one PHY; if the PHY address is 0x1F, then 172939583Swpaul * it's the internal one. 173036270Swpaul */ 173136270Swpaul 173236270Swpaul for (i = TL_PHYADDR_MIN; i < TL_PHYADDR_MAX + 1; i++) { 173339583Swpaul sc->tl_phy_addr = i; 173439583Swpaul if (bootverbose) 173539583Swpaul printf("tl%d: looking for phy at addr %x\n", unit, i); 173639583Swpaul tl_phy_writereg(sc, PHY_BMCR, PHY_BMCR_RESET); 173736270Swpaul DELAY(500); 173839583Swpaul while(tl_phy_readreg(sc, PHY_BMCR) & PHY_BMCR_RESET); 173939583Swpaul sc->tl_phy_sts = tl_phy_readreg(sc, PHY_BMSR); 174039583Swpaul if (bootverbose) 174139583Swpaul printf("tl%d: status: %x\n", unit, sc->tl_phy_sts); 174239583Swpaul if (!sc->tl_phy_sts) 174336270Swpaul continue; 174439583Swpaul if (tl_attach_phy(sc)) { 174539583Swpaul printf("tl%d: failed to attach a phy %d\n", unit, i); 174636270Swpaul goto fail; 174736270Swpaul } 174836270Swpaul phys++; 174936270Swpaul if (phys && i != TL_PHYADDR_MAX) 175036270Swpaul break; 175136270Swpaul } 175236270Swpaul 175345155Swpaul /* 175445155Swpaul * If no MII-based PHYs were detected, then this is a 175545155Swpaul * TNETE110 device with a bit rate PHY. There's no autoneg 175645155Swpaul * support, so just default to 10baseT mode. 175745155Swpaul */ 175836270Swpaul if (!phys) { 175945155Swpaul struct ifmedia *ifm; 176045155Swpaul sc->tl_bitrate = 1; 176145155Swpaul ifmedia_init(&sc->ifmedia, 0, tl_ifmedia_upd, tl_ifmedia_sts); 176245155Swpaul ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_10_T, 0, NULL); 176345155Swpaul ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_10_T|IFM_HDX, 0, NULL); 176445155Swpaul ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_10_T|IFM_FDX, 0, NULL); 176545155Swpaul ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_10_5, 0, NULL); 176645155Swpaul /* Reset again, this time setting bitrate mode. */ 176745155Swpaul tl_softreset(sc, 1); 176845155Swpaul ifm = &sc->ifmedia; 176945155Swpaul ifm->ifm_media = ifm->ifm_cur->ifm_media; 177045155Swpaul tl_ifmedia_upd(ifp); 177136270Swpaul } 177236270Swpaul 177339627Swpaul tl_intvec_adchk((void *)sc, 0); 177439627Swpaul tl_stop(sc); 177539627Swpaul 177639583Swpaul /* 177739627Swpaul * Attempt to clear any stray interrupts 177839627Swpaul * that may be lurking. 177939627Swpaul */ 178039627Swpaul tl_intr((void *)sc); 178139627Swpaul 178239627Swpaul /* 178339583Swpaul * Call MI attach routines. 178439583Swpaul */ 178539583Swpaul if_attach(ifp); 178639583Swpaul ether_ifattach(ifp); 178738030Swpaul 178839583Swpaul#if NBPFILTER > 0 178939583Swpaul bpfattach(ifp, DLT_EN10MB, sizeof(struct ether_header)); 179039583Swpaul#endif 179139583Swpaul 179239583Swpaul at_shutdown(tl_shutdown, sc, SHUTDOWN_POST_SYNC); 179339583Swpaul 179436270Swpaulfail: 179536270Swpaul splx(s); 179636270Swpaul return; 179736270Swpaul} 179836270Swpaul 179936270Swpaul/* 180036270Swpaul * Initialize the transmit lists. 180136270Swpaul */ 180236270Swpaulstatic int tl_list_tx_init(sc) 180336270Swpaul struct tl_softc *sc; 180436270Swpaul{ 180536270Swpaul struct tl_chain_data *cd; 180636270Swpaul struct tl_list_data *ld; 180736270Swpaul int i; 180836270Swpaul 180936270Swpaul cd = &sc->tl_cdata; 181036270Swpaul ld = sc->tl_ldata; 181136270Swpaul for (i = 0; i < TL_TX_LIST_CNT; i++) { 181236270Swpaul cd->tl_tx_chain[i].tl_ptr = &ld->tl_tx_list[i]; 181336270Swpaul if (i == (TL_TX_LIST_CNT - 1)) 181436270Swpaul cd->tl_tx_chain[i].tl_next = NULL; 181536270Swpaul else 181636270Swpaul cd->tl_tx_chain[i].tl_next = &cd->tl_tx_chain[i + 1]; 181736270Swpaul } 181836270Swpaul 181936270Swpaul cd->tl_tx_free = &cd->tl_tx_chain[0]; 182036270Swpaul cd->tl_tx_tail = cd->tl_tx_head = NULL; 182136270Swpaul sc->tl_txeoc = 1; 182236270Swpaul 182336270Swpaul return(0); 182436270Swpaul} 182536270Swpaul 182636270Swpaul/* 182736270Swpaul * Initialize the RX lists and allocate mbufs for them. 182836270Swpaul */ 182936270Swpaulstatic int tl_list_rx_init(sc) 183036270Swpaul struct tl_softc *sc; 183136270Swpaul{ 183236270Swpaul struct tl_chain_data *cd; 183336270Swpaul struct tl_list_data *ld; 183436270Swpaul int i; 183536270Swpaul 183636270Swpaul cd = &sc->tl_cdata; 183736270Swpaul ld = sc->tl_ldata; 183836270Swpaul 183940795Swpaul for (i = 0; i < TL_RX_LIST_CNT; i++) { 184036270Swpaul cd->tl_rx_chain[i].tl_ptr = 184137626Swpaul (struct tl_list_onefrag *)&ld->tl_rx_list[i]; 184239583Swpaul if (tl_newbuf(sc, &cd->tl_rx_chain[i]) == ENOBUFS) 184339583Swpaul return(ENOBUFS); 184440795Swpaul if (i == (TL_RX_LIST_CNT - 1)) { 184536270Swpaul cd->tl_rx_chain[i].tl_next = NULL; 184636270Swpaul ld->tl_rx_list[i].tlist_fptr = 0; 184736270Swpaul } else { 184836270Swpaul cd->tl_rx_chain[i].tl_next = &cd->tl_rx_chain[i + 1]; 184936270Swpaul ld->tl_rx_list[i].tlist_fptr = 185036270Swpaul vtophys(&ld->tl_rx_list[i + 1]); 185136270Swpaul } 185236270Swpaul } 185336270Swpaul 185436270Swpaul cd->tl_rx_head = &cd->tl_rx_chain[0]; 185536270Swpaul cd->tl_rx_tail = &cd->tl_rx_chain[TL_RX_LIST_CNT - 1]; 185636270Swpaul 185736270Swpaul return(0); 185836270Swpaul} 185936270Swpaul 186036270Swpaulstatic int tl_newbuf(sc, c) 186136270Swpaul struct tl_softc *sc; 186237626Swpaul struct tl_chain_onefrag *c; 186336270Swpaul{ 186436270Swpaul struct mbuf *m_new = NULL; 186536270Swpaul 186636270Swpaul MGETHDR(m_new, M_DONTWAIT, MT_DATA); 186736270Swpaul if (m_new == NULL) { 186839583Swpaul printf("tl%d: no memory for rx list -- packet dropped!", 186936270Swpaul sc->tl_unit); 187036270Swpaul return(ENOBUFS); 187136270Swpaul } 187236270Swpaul 187336270Swpaul MCLGET(m_new, M_DONTWAIT); 187436270Swpaul if (!(m_new->m_flags & M_EXT)) { 187539583Swpaul printf("tl%d: no memory for rx list -- packet dropped!", 187639583Swpaul sc->tl_unit); 187736270Swpaul m_freem(m_new); 187836270Swpaul return(ENOBUFS); 187936270Swpaul } 188036270Swpaul 188145155Swpaul#ifdef __alpha__ 188245155Swpaul m_new->m_data += 2; 188345155Swpaul#endif 188445155Swpaul 188536270Swpaul c->tl_mbuf = m_new; 188636270Swpaul c->tl_next = NULL; 188736270Swpaul c->tl_ptr->tlist_frsize = MCLBYTES; 188836270Swpaul c->tl_ptr->tlist_cstat = TL_CSTAT_READY; 188936270Swpaul c->tl_ptr->tlist_fptr = 0; 189037626Swpaul c->tl_ptr->tl_frag.tlist_dadr = vtophys(mtod(m_new, caddr_t)); 189137626Swpaul c->tl_ptr->tl_frag.tlist_dcnt = MCLBYTES; 189236270Swpaul 189336270Swpaul return(0); 189436270Swpaul} 189536270Swpaul/* 189636270Swpaul * Interrupt handler for RX 'end of frame' condition (EOF). This 189736270Swpaul * tells us that a full ethernet frame has been captured and we need 189836270Swpaul * to handle it. 189936270Swpaul * 190036270Swpaul * Reception is done using 'lists' which consist of a header and a 190136270Swpaul * series of 10 data count/data address pairs that point to buffers. 190236270Swpaul * Initially you're supposed to create a list, populate it with pointers 190336270Swpaul * to buffers, then load the physical address of the list into the 190436270Swpaul * ch_parm register. The adapter is then supposed to DMA the received 190536270Swpaul * frame into the buffers for you. 190636270Swpaul * 190736270Swpaul * To make things as fast as possible, we have the chip DMA directly 190836270Swpaul * into mbufs. This saves us from having to do a buffer copy: we can 190936270Swpaul * just hand the mbufs directly to ether_input(). Once the frame has 191036270Swpaul * been sent on its way, the 'list' structure is assigned a new buffer 191136270Swpaul * and moved to the end of the RX chain. As long we we stay ahead of 191236270Swpaul * the chip, it will always think it has an endless receive channel. 191336270Swpaul * 191436270Swpaul * If we happen to fall behind and the chip manages to fill up all of 191536270Swpaul * the buffers, it will generate an end of channel interrupt and wait 191636270Swpaul * for us to empty the chain and restart the receiver. 191736270Swpaul */ 191836270Swpaulstatic int tl_intvec_rxeof(xsc, type) 191936270Swpaul void *xsc; 192036270Swpaul u_int32_t type; 192136270Swpaul{ 192236270Swpaul struct tl_softc *sc; 192336270Swpaul int r = 0, total_len = 0; 192436270Swpaul struct ether_header *eh; 192536270Swpaul struct mbuf *m; 192636270Swpaul struct ifnet *ifp; 192737626Swpaul struct tl_chain_onefrag *cur_rx; 192836270Swpaul 192936270Swpaul sc = xsc; 193036270Swpaul ifp = &sc->arpcom.ac_if; 193136270Swpaul 193236270Swpaul while(sc->tl_cdata.tl_rx_head->tl_ptr->tlist_cstat & TL_CSTAT_FRAMECMP){ 193336270Swpaul r++; 193436270Swpaul cur_rx = sc->tl_cdata.tl_rx_head; 193536270Swpaul sc->tl_cdata.tl_rx_head = cur_rx->tl_next; 193636270Swpaul m = cur_rx->tl_mbuf; 193736270Swpaul total_len = cur_rx->tl_ptr->tlist_frsize; 193836270Swpaul 193939583Swpaul if (tl_newbuf(sc, cur_rx) == ENOBUFS) { 194039583Swpaul ifp->if_ierrors++; 194139583Swpaul cur_rx->tl_ptr->tlist_frsize = MCLBYTES; 194239583Swpaul cur_rx->tl_ptr->tlist_cstat = TL_CSTAT_READY; 194339583Swpaul cur_rx->tl_ptr->tl_frag.tlist_dcnt = MCLBYTES; 194439583Swpaul continue; 194539583Swpaul } 194636270Swpaul 194736270Swpaul sc->tl_cdata.tl_rx_tail->tl_ptr->tlist_fptr = 194836270Swpaul vtophys(cur_rx->tl_ptr); 194936270Swpaul sc->tl_cdata.tl_rx_tail->tl_next = cur_rx; 195036270Swpaul sc->tl_cdata.tl_rx_tail = cur_rx; 195136270Swpaul 195236270Swpaul eh = mtod(m, struct ether_header *); 195336270Swpaul m->m_pkthdr.rcvif = ifp; 195436270Swpaul 195537626Swpaul /* 195637626Swpaul * Note: when the ThunderLAN chip is in 'capture all 195737626Swpaul * frames' mode, it will receive its own transmissions. 195837626Swpaul * We drop don't need to process our own transmissions, 195937626Swpaul * so we drop them here and continue. 196037626Swpaul */ 196139583Swpaul /*if (ifp->if_flags & IFF_PROMISC && */ 196239583Swpaul if (!bcmp(eh->ether_shost, sc->arpcom.ac_enaddr, 196337626Swpaul ETHER_ADDR_LEN)) { 196437626Swpaul m_freem(m); 196537626Swpaul continue; 196637626Swpaul } 196737626Swpaul 196836270Swpaul#if NBPFILTER > 0 196936270Swpaul /* 197036270Swpaul * Handle BPF listeners. Let the BPF user see the packet, but 197136270Swpaul * don't pass it up to the ether_input() layer unless it's 197236270Swpaul * a broadcast packet, multicast packet, matches our ethernet 197336270Swpaul * address or the interface is in promiscuous mode. If we don't 197436270Swpaul * want the packet, just forget it. We leave the mbuf in place 197536270Swpaul * since it can be used again later. 197636270Swpaul */ 197736270Swpaul if (ifp->if_bpf) { 197836270Swpaul m->m_pkthdr.len = m->m_len = total_len; 197936270Swpaul bpf_mtap(ifp, m); 198036270Swpaul if (ifp->if_flags & IFF_PROMISC && 198136270Swpaul (bcmp(eh->ether_dhost, sc->arpcom.ac_enaddr, 198236270Swpaul ETHER_ADDR_LEN) && 198336270Swpaul (eh->ether_dhost[0] & 1) == 0)) { 198436270Swpaul m_freem(m); 198536270Swpaul continue; 198636270Swpaul } 198736270Swpaul } 198836270Swpaul#endif 198936270Swpaul /* Remove header from mbuf and pass it on. */ 199036270Swpaul m->m_pkthdr.len = m->m_len = 199136270Swpaul total_len - sizeof(struct ether_header); 199236270Swpaul m->m_data += sizeof(struct ether_header); 199336270Swpaul ether_input(ifp, eh, m); 199436270Swpaul } 199536270Swpaul 199636270Swpaul return(r); 199736270Swpaul} 199836270Swpaul 199936270Swpaul/* 200036270Swpaul * The RX-EOC condition hits when the ch_parm address hasn't been 200136270Swpaul * initialized or the adapter reached a list with a forward pointer 200236270Swpaul * of 0 (which indicates the end of the chain). In our case, this means 200336270Swpaul * the card has hit the end of the receive buffer chain and we need to 200436270Swpaul * empty out the buffers and shift the pointer back to the beginning again. 200536270Swpaul */ 200636270Swpaulstatic int tl_intvec_rxeoc(xsc, type) 200736270Swpaul void *xsc; 200836270Swpaul u_int32_t type; 200936270Swpaul{ 201036270Swpaul struct tl_softc *sc; 201136270Swpaul int r; 201236270Swpaul 201336270Swpaul sc = xsc; 201436270Swpaul 201536270Swpaul /* Flush out the receive queue and ack RXEOF interrupts. */ 201636270Swpaul r = tl_intvec_rxeof(xsc, type); 201739583Swpaul CMD_PUT(sc, TL_CMD_ACK | r | (type & ~(0x00100000))); 201836270Swpaul r = 1; 201939583Swpaul CSR_WRITE_4(sc, TL_CH_PARM, vtophys(sc->tl_cdata.tl_rx_head->tl_ptr)); 202036270Swpaul r |= (TL_CMD_GO|TL_CMD_RT); 202136270Swpaul return(r); 202236270Swpaul} 202336270Swpaul 202436270Swpaulstatic int tl_intvec_txeof(xsc, type) 202536270Swpaul void *xsc; 202636270Swpaul u_int32_t type; 202736270Swpaul{ 202836270Swpaul struct tl_softc *sc; 202936270Swpaul int r = 0; 203036270Swpaul struct tl_chain *cur_tx; 203136270Swpaul 203236270Swpaul sc = xsc; 203336270Swpaul 203436270Swpaul /* 203536270Swpaul * Go through our tx list and free mbufs for those 203636270Swpaul * frames that have been sent. 203736270Swpaul */ 203836270Swpaul while (sc->tl_cdata.tl_tx_head != NULL) { 203936270Swpaul cur_tx = sc->tl_cdata.tl_tx_head; 204036270Swpaul if (!(cur_tx->tl_ptr->tlist_cstat & TL_CSTAT_FRAMECMP)) 204136270Swpaul break; 204236270Swpaul sc->tl_cdata.tl_tx_head = cur_tx->tl_next; 204336270Swpaul 204436270Swpaul r++; 204536270Swpaul m_freem(cur_tx->tl_mbuf); 204636270Swpaul cur_tx->tl_mbuf = NULL; 204736270Swpaul 204836270Swpaul cur_tx->tl_next = sc->tl_cdata.tl_tx_free; 204936270Swpaul sc->tl_cdata.tl_tx_free = cur_tx; 205037626Swpaul if (!cur_tx->tl_ptr->tlist_fptr) 205137626Swpaul break; 205236270Swpaul } 205336270Swpaul 205436270Swpaul return(r); 205536270Swpaul} 205636270Swpaul 205736270Swpaul/* 205836270Swpaul * The transmit end of channel interrupt. The adapter triggers this 205936270Swpaul * interrupt to tell us it hit the end of the current transmit list. 206036270Swpaul * 206136270Swpaul * A note about this: it's possible for a condition to arise where 206236270Swpaul * tl_start() may try to send frames between TXEOF and TXEOC interrupts. 206336270Swpaul * You have to avoid this since the chip expects things to go in a 206436270Swpaul * particular order: transmit, acknowledge TXEOF, acknowledge TXEOC. 206536270Swpaul * When the TXEOF handler is called, it will free all of the transmitted 206636270Swpaul * frames and reset the tx_head pointer to NULL. However, a TXEOC 206736270Swpaul * interrupt should be received and acknowledged before any more frames 206836270Swpaul * are queued for transmission. If tl_statrt() is called after TXEOF 206936270Swpaul * resets the tx_head pointer but _before_ the TXEOC interrupt arrives, 207036270Swpaul * it could attempt to issue a transmit command prematurely. 207136270Swpaul * 207236270Swpaul * To guard against this, tl_start() will only issue transmit commands 207336270Swpaul * if the tl_txeoc flag is set, and only the TXEOC interrupt handler 207436270Swpaul * can set this flag once tl_start() has cleared it. 207536270Swpaul */ 207636270Swpaulstatic int tl_intvec_txeoc(xsc, type) 207736270Swpaul void *xsc; 207836270Swpaul u_int32_t type; 207936270Swpaul{ 208036270Swpaul struct tl_softc *sc; 208136270Swpaul struct ifnet *ifp; 208236270Swpaul u_int32_t cmd; 208336270Swpaul 208436270Swpaul sc = xsc; 208536270Swpaul ifp = &sc->arpcom.ac_if; 208636270Swpaul 208736270Swpaul /* Clear the timeout timer. */ 208836270Swpaul ifp->if_timer = 0; 208936270Swpaul 209036270Swpaul if (sc->tl_cdata.tl_tx_head == NULL) { 209136270Swpaul ifp->if_flags &= ~IFF_OACTIVE; 209236270Swpaul sc->tl_cdata.tl_tx_tail = NULL; 209336270Swpaul sc->tl_txeoc = 1; 209437626Swpaul /* 209537626Swpaul * If we just drained the TX queue and 209637626Swpaul * there's an autoneg request waiting, set 209737626Swpaul * it in motion. This will block the transmitter 209837626Swpaul * until the autoneg session completes which will 209937626Swpaul * no doubt piss off any processes waiting to 210037626Swpaul * transmit, but that's the way the ball bounces. 210137626Swpaul */ 210237626Swpaul if (sc->tl_want_auto) 210337626Swpaul tl_autoneg(sc, TL_FLAG_SCHEDDELAY, 1); 210436270Swpaul } else { 210536270Swpaul sc->tl_txeoc = 0; 210636270Swpaul /* First we have to ack the EOC interrupt. */ 210739583Swpaul CMD_PUT(sc, TL_CMD_ACK | 0x00000001 | type); 210836270Swpaul /* Then load the address of the next TX list. */ 210939583Swpaul CSR_WRITE_4(sc, TL_CH_PARM, 211039583Swpaul vtophys(sc->tl_cdata.tl_tx_head->tl_ptr)); 211136270Swpaul /* Restart TX channel. */ 211239583Swpaul cmd = CSR_READ_4(sc, TL_HOSTCMD); 211336270Swpaul cmd &= ~TL_CMD_RT; 211436270Swpaul cmd |= TL_CMD_GO|TL_CMD_INTSON; 211539583Swpaul CMD_PUT(sc, cmd); 211636270Swpaul return(0); 211736270Swpaul } 211836270Swpaul 211936270Swpaul return(1); 212036270Swpaul} 212136270Swpaul 212236270Swpaulstatic int tl_intvec_adchk(xsc, type) 212336270Swpaul void *xsc; 212436270Swpaul u_int32_t type; 212536270Swpaul{ 212636270Swpaul struct tl_softc *sc; 212737626Swpaul u_int16_t bmcr, ctl; 212836270Swpaul 212936270Swpaul sc = xsc; 213036270Swpaul 213139627Swpaul if (type) 213239627Swpaul printf("tl%d: adapter check: %x\n", sc->tl_unit, 213341656Swpaul (unsigned int)CSR_READ_4(sc, TL_CH_PARM)); 213436270Swpaul 213537626Swpaul /* 213637626Swpaul * Before resetting the adapter, try reading the PHY 213737626Swpaul * settings so we can put them back later. This is 213837626Swpaul * necessary to keep the chip operating at the same 213937626Swpaul * speed and duplex settings after the reset completes. 214037626Swpaul */ 214145155Swpaul if (!sc->tl_bitrate) { 214237626Swpaul bmcr = tl_phy_readreg(sc, PHY_BMCR); 214337626Swpaul ctl = tl_phy_readreg(sc, TL_PHY_CTL); 214439583Swpaul tl_softreset(sc, 1); 214537626Swpaul tl_phy_writereg(sc, PHY_BMCR, bmcr); 214637626Swpaul tl_phy_writereg(sc, TL_PHY_CTL, ctl); 214737626Swpaul if (bmcr & PHY_BMCR_DUPLEX) { 214839583Swpaul tl_dio_setbit(sc, TL_NETCMD, TL_CMD_DUPLEX); 214937626Swpaul } else { 215039583Swpaul tl_dio_clrbit(sc, TL_NETCMD, TL_CMD_DUPLEX); 215137626Swpaul } 215245155Swpaul } 215337626Swpaul tl_stop(sc); 215436270Swpaul tl_init(sc); 215539583Swpaul CMD_SET(sc, TL_CMD_INTSON); 215636270Swpaul 215736270Swpaul return(0); 215836270Swpaul} 215936270Swpaul 216036270Swpaulstatic int tl_intvec_netsts(xsc, type) 216136270Swpaul void *xsc; 216236270Swpaul u_int32_t type; 216336270Swpaul{ 216436270Swpaul struct tl_softc *sc; 216536270Swpaul u_int16_t netsts; 216636270Swpaul 216736270Swpaul sc = xsc; 216836270Swpaul 216939583Swpaul netsts = tl_dio_read16(sc, TL_NETSTS); 217039583Swpaul tl_dio_write16(sc, TL_NETSTS, netsts); 217136270Swpaul 217236270Swpaul printf("tl%d: network status: %x\n", sc->tl_unit, netsts); 217336270Swpaul 217436270Swpaul return(1); 217536270Swpaul} 217636270Swpaul 217739583Swpaulstatic void tl_intr(xsc) 217839583Swpaul void *xsc; 217936270Swpaul{ 218036270Swpaul struct tl_softc *sc; 218136270Swpaul struct ifnet *ifp; 218236270Swpaul int r = 0; 218336270Swpaul u_int32_t type = 0; 218436270Swpaul u_int16_t ints = 0; 218536270Swpaul u_int8_t ivec = 0; 218636270Swpaul 218739583Swpaul sc = xsc; 218836270Swpaul 218936270Swpaul /* Disable interrupts */ 219039583Swpaul ints = CSR_READ_2(sc, TL_HOST_INT); 219139583Swpaul CSR_WRITE_2(sc, TL_HOST_INT, ints); 219236270Swpaul type = (ints << 16) & 0xFFFF0000; 219336270Swpaul ivec = (ints & TL_VEC_MASK) >> 5; 219436270Swpaul ints = (ints & TL_INT_MASK) >> 2; 219536270Swpaul 219636270Swpaul ifp = &sc->arpcom.ac_if; 219736270Swpaul 219836270Swpaul switch(ints) { 219936270Swpaul case (TL_INTR_INVALID): 220039583Swpaul#ifdef DIAGNOSTIC 220139583Swpaul printf("tl%d: got an invalid interrupt!\n", sc->tl_unit); 220239583Swpaul#endif 220339583Swpaul /* Re-enable interrupts but don't ack this one. */ 220439583Swpaul CMD_PUT(sc, type); 220539583Swpaul r = 0; 220636270Swpaul break; 220736270Swpaul case (TL_INTR_TXEOF): 220836270Swpaul r = tl_intvec_txeof((void *)sc, type); 220936270Swpaul break; 221036270Swpaul case (TL_INTR_TXEOC): 221136270Swpaul r = tl_intvec_txeoc((void *)sc, type); 221236270Swpaul break; 221336270Swpaul case (TL_INTR_STATOFLOW): 221439583Swpaul tl_stats_update(sc); 221539583Swpaul r = 1; 221636270Swpaul break; 221736270Swpaul case (TL_INTR_RXEOF): 221836270Swpaul r = tl_intvec_rxeof((void *)sc, type); 221936270Swpaul break; 222036270Swpaul case (TL_INTR_DUMMY): 222139583Swpaul printf("tl%d: got a dummy interrupt\n", sc->tl_unit); 222239583Swpaul r = 1; 222336270Swpaul break; 222436270Swpaul case (TL_INTR_ADCHK): 222536270Swpaul if (ivec) 222636270Swpaul r = tl_intvec_adchk((void *)sc, type); 222736270Swpaul else 222836270Swpaul r = tl_intvec_netsts((void *)sc, type); 222936270Swpaul break; 223036270Swpaul case (TL_INTR_RXEOC): 223136270Swpaul r = tl_intvec_rxeoc((void *)sc, type); 223236270Swpaul break; 223336270Swpaul default: 223436270Swpaul printf("tl%d: bogus interrupt type\n", ifp->if_unit); 223536270Swpaul break; 223636270Swpaul } 223736270Swpaul 223836270Swpaul /* Re-enable interrupts */ 223937626Swpaul if (r) { 224039583Swpaul CMD_PUT(sc, TL_CMD_ACK | r | type); 224137626Swpaul } 224236270Swpaul 224337626Swpaul if (ifp->if_snd.ifq_head != NULL) 224437626Swpaul tl_start(ifp); 224537626Swpaul 224636270Swpaul return; 224736270Swpaul} 224836270Swpaul 224936270Swpaulstatic void tl_stats_update(xsc) 225036270Swpaul void *xsc; 225136270Swpaul{ 225236270Swpaul struct tl_softc *sc; 225336270Swpaul struct ifnet *ifp; 225436270Swpaul struct tl_stats tl_stats; 225536270Swpaul u_int32_t *p; 225636270Swpaul 225736270Swpaul bzero((char *)&tl_stats, sizeof(struct tl_stats)); 225836270Swpaul 225936270Swpaul sc = xsc; 226036270Swpaul ifp = &sc->arpcom.ac_if; 226136270Swpaul 226236270Swpaul p = (u_int32_t *)&tl_stats; 226336270Swpaul 226439583Swpaul CSR_WRITE_2(sc, TL_DIO_ADDR, TL_TXGOODFRAMES|TL_DIO_ADDR_INC); 226539583Swpaul *p++ = CSR_READ_4(sc, TL_DIO_DATA); 226639583Swpaul *p++ = CSR_READ_4(sc, TL_DIO_DATA); 226739583Swpaul *p++ = CSR_READ_4(sc, TL_DIO_DATA); 226839583Swpaul *p++ = CSR_READ_4(sc, TL_DIO_DATA); 226939583Swpaul *p++ = CSR_READ_4(sc, TL_DIO_DATA); 227036270Swpaul 227136270Swpaul ifp->if_opackets += tl_tx_goodframes(tl_stats); 227236270Swpaul ifp->if_collisions += tl_stats.tl_tx_single_collision + 227336270Swpaul tl_stats.tl_tx_multi_collision; 227436270Swpaul ifp->if_ipackets += tl_rx_goodframes(tl_stats); 227536270Swpaul ifp->if_ierrors += tl_stats.tl_crc_errors + tl_stats.tl_code_errors + 227636270Swpaul tl_rx_overrun(tl_stats); 227736270Swpaul ifp->if_oerrors += tl_tx_underrun(tl_stats); 227836270Swpaul 227936270Swpaul sc->tl_stat_ch = timeout(tl_stats_update, sc, hz); 228036302Swpaul 228136302Swpaul return; 228236270Swpaul} 228336270Swpaul 228436270Swpaul/* 228536270Swpaul * Encapsulate an mbuf chain in a list by coupling the mbuf data 228636270Swpaul * pointers to the fragment pointers. 228736270Swpaul */ 228836270Swpaulstatic int tl_encap(sc, c, m_head) 228936270Swpaul struct tl_softc *sc; 229036270Swpaul struct tl_chain *c; 229136270Swpaul struct mbuf *m_head; 229236270Swpaul{ 229336270Swpaul int frag = 0; 229436270Swpaul struct tl_frag *f = NULL; 229536270Swpaul int total_len; 229636270Swpaul struct mbuf *m; 229736270Swpaul 229836270Swpaul /* 229936270Swpaul * Start packing the mbufs in this chain into 230036270Swpaul * the fragment pointers. Stop when we run out 230136270Swpaul * of fragments or hit the end of the mbuf chain. 230236270Swpaul */ 230336270Swpaul m = m_head; 230436270Swpaul total_len = 0; 230536270Swpaul 230636270Swpaul for (m = m_head, frag = 0; m != NULL; m = m->m_next) { 230736270Swpaul if (m->m_len != 0) { 230836270Swpaul if (frag == TL_MAXFRAGS) 230936270Swpaul break; 231036270Swpaul total_len+= m->m_len; 231136270Swpaul c->tl_ptr->tl_frag[frag].tlist_dadr = 231236270Swpaul vtophys(mtod(m, vm_offset_t)); 231336270Swpaul c->tl_ptr->tl_frag[frag].tlist_dcnt = m->m_len; 231436270Swpaul frag++; 231536270Swpaul } 231636270Swpaul } 231736270Swpaul 231836270Swpaul /* 231936270Swpaul * Handle special cases. 232036270Swpaul * Special case #1: we used up all 10 fragments, but 232136270Swpaul * we have more mbufs left in the chain. Copy the 232236270Swpaul * data into an mbuf cluster. Note that we don't 232336270Swpaul * bother clearing the values in the other fragment 232436270Swpaul * pointers/counters; it wouldn't gain us anything, 232536270Swpaul * and would waste cycles. 232636270Swpaul */ 232736270Swpaul if (m != NULL) { 232836270Swpaul struct mbuf *m_new = NULL; 232936270Swpaul 233036270Swpaul MGETHDR(m_new, M_DONTWAIT, MT_DATA); 233136270Swpaul if (m_new == NULL) { 233236270Swpaul printf("tl%d: no memory for tx list", sc->tl_unit); 233336270Swpaul return(1); 233436270Swpaul } 233536270Swpaul if (m_head->m_pkthdr.len > MHLEN) { 233636270Swpaul MCLGET(m_new, M_DONTWAIT); 233736270Swpaul if (!(m_new->m_flags & M_EXT)) { 233836270Swpaul m_freem(m_new); 233936270Swpaul printf("tl%d: no memory for tx list", 234036270Swpaul sc->tl_unit); 234136270Swpaul return(1); 234236270Swpaul } 234336270Swpaul } 234436270Swpaul m_copydata(m_head, 0, m_head->m_pkthdr.len, 234536270Swpaul mtod(m_new, caddr_t)); 234636270Swpaul m_new->m_pkthdr.len = m_new->m_len = m_head->m_pkthdr.len; 234736270Swpaul m_freem(m_head); 234836270Swpaul m_head = m_new; 234936270Swpaul f = &c->tl_ptr->tl_frag[0]; 235036270Swpaul f->tlist_dadr = vtophys(mtod(m_new, caddr_t)); 235136270Swpaul f->tlist_dcnt = total_len = m_new->m_len; 235236270Swpaul frag = 1; 235336270Swpaul } 235436270Swpaul 235536270Swpaul /* 235636270Swpaul * Special case #2: the frame is smaller than the minimum 235736270Swpaul * frame size. We have to pad it to make the chip happy. 235836270Swpaul */ 235936270Swpaul if (total_len < TL_MIN_FRAMELEN) { 236036270Swpaul if (frag == TL_MAXFRAGS) 236139583Swpaul printf("tl%d: all frags filled but " 236239583Swpaul "frame still to small!\n", sc->tl_unit); 236336270Swpaul f = &c->tl_ptr->tl_frag[frag]; 236436270Swpaul f->tlist_dcnt = TL_MIN_FRAMELEN - total_len; 236536270Swpaul f->tlist_dadr = vtophys(&sc->tl_ldata->tl_pad); 236636270Swpaul total_len += f->tlist_dcnt; 236736270Swpaul frag++; 236836270Swpaul } 236936270Swpaul 237036270Swpaul c->tl_mbuf = m_head; 237136270Swpaul c->tl_ptr->tl_frag[frag - 1].tlist_dcnt |= TL_LAST_FRAG; 237236270Swpaul c->tl_ptr->tlist_frsize = total_len; 237336270Swpaul c->tl_ptr->tlist_cstat = TL_CSTAT_READY; 237436270Swpaul c->tl_ptr->tlist_fptr = 0; 237536270Swpaul 237636270Swpaul return(0); 237736270Swpaul} 237836270Swpaul 237936270Swpaul/* 238036270Swpaul * Main transmit routine. To avoid having to do mbuf copies, we put pointers 238136270Swpaul * to the mbuf data regions directly in the transmit lists. We also save a 238236270Swpaul * copy of the pointers since the transmit list fragment pointers are 238336270Swpaul * physical addresses. 238436270Swpaul */ 238536270Swpaulstatic void tl_start(ifp) 238636270Swpaul struct ifnet *ifp; 238736270Swpaul{ 238836270Swpaul struct tl_softc *sc; 238936270Swpaul struct mbuf *m_head = NULL; 239036270Swpaul u_int32_t cmd; 239136270Swpaul struct tl_chain *prev = NULL, *cur_tx = NULL, *start_tx; 239236270Swpaul 239336270Swpaul sc = ifp->if_softc; 239436270Swpaul 239537626Swpaul if (sc->tl_autoneg) { 239637626Swpaul sc->tl_tx_pend = 1; 239737626Swpaul return; 239837626Swpaul } 239937626Swpaul 240036270Swpaul /* 240136270Swpaul * Check for an available queue slot. If there are none, 240236270Swpaul * punt. 240336270Swpaul */ 240436270Swpaul if (sc->tl_cdata.tl_tx_free == NULL) { 240536270Swpaul ifp->if_flags |= IFF_OACTIVE; 240636270Swpaul return; 240736270Swpaul } 240836270Swpaul 240936270Swpaul start_tx = sc->tl_cdata.tl_tx_free; 241036270Swpaul 241136270Swpaul while(sc->tl_cdata.tl_tx_free != NULL) { 241236270Swpaul IF_DEQUEUE(&ifp->if_snd, m_head); 241336270Swpaul if (m_head == NULL) 241436270Swpaul break; 241536270Swpaul 241636270Swpaul /* Pick a chain member off the free list. */ 241736270Swpaul cur_tx = sc->tl_cdata.tl_tx_free; 241836270Swpaul sc->tl_cdata.tl_tx_free = cur_tx->tl_next; 241936270Swpaul 242036270Swpaul cur_tx->tl_next = NULL; 242136270Swpaul 242236270Swpaul /* Pack the data into the list. */ 242336270Swpaul tl_encap(sc, cur_tx, m_head); 242436270Swpaul 242536270Swpaul /* Chain it together */ 242636270Swpaul if (prev != NULL) { 242736270Swpaul prev->tl_next = cur_tx; 242836270Swpaul prev->tl_ptr->tlist_fptr = vtophys(cur_tx->tl_ptr); 242936270Swpaul } 243036270Swpaul prev = cur_tx; 243136270Swpaul 243236270Swpaul /* 243336270Swpaul * If there's a BPF listener, bounce a copy of this frame 243436270Swpaul * to him. 243536270Swpaul */ 243636270Swpaul#if NBPFILTER > 0 243736270Swpaul if (ifp->if_bpf) 243836270Swpaul bpf_mtap(ifp, cur_tx->tl_mbuf); 243936270Swpaul#endif 244036270Swpaul } 244136270Swpaul 244236270Swpaul /* 244341526Swpaul * If there are no packets queued, bail. 244441526Swpaul */ 244541526Swpaul if (cur_tx == NULL) 244641526Swpaul return; 244741526Swpaul 244841526Swpaul /* 244936270Swpaul * That's all we can stands, we can't stands no more. 245036270Swpaul * If there are no other transfers pending, then issue the 245136270Swpaul * TX GO command to the adapter to start things moving. 245236270Swpaul * Otherwise, just leave the data in the queue and let 245336270Swpaul * the EOF/EOC interrupt handler send. 245436270Swpaul */ 245536270Swpaul if (sc->tl_cdata.tl_tx_head == NULL) { 245636270Swpaul sc->tl_cdata.tl_tx_head = start_tx; 245736270Swpaul sc->tl_cdata.tl_tx_tail = cur_tx; 245839583Swpaul 245936270Swpaul if (sc->tl_txeoc) { 246036270Swpaul sc->tl_txeoc = 0; 246139583Swpaul CSR_WRITE_4(sc, TL_CH_PARM, vtophys(start_tx->tl_ptr)); 246239583Swpaul cmd = CSR_READ_4(sc, TL_HOSTCMD); 246336270Swpaul cmd &= ~TL_CMD_RT; 246436270Swpaul cmd |= TL_CMD_GO|TL_CMD_INTSON; 246539583Swpaul CMD_PUT(sc, cmd); 246636270Swpaul } 246736270Swpaul } else { 246836270Swpaul sc->tl_cdata.tl_tx_tail->tl_next = start_tx; 246942146Swpaul sc->tl_cdata.tl_tx_tail = cur_tx; 247036270Swpaul } 247136270Swpaul 247236270Swpaul /* 247336270Swpaul * Set a timeout in case the chip goes out to lunch. 247436270Swpaul */ 247536270Swpaul ifp->if_timer = 5; 247636270Swpaul 247736270Swpaul return; 247836270Swpaul} 247936270Swpaul 248036270Swpaulstatic void tl_init(xsc) 248136270Swpaul void *xsc; 248236270Swpaul{ 248336270Swpaul struct tl_softc *sc = xsc; 248436270Swpaul struct ifnet *ifp = &sc->arpcom.ac_if; 248536270Swpaul int s; 248636270Swpaul u_int16_t phy_sts; 248736270Swpaul 248839583Swpaul if (sc->tl_autoneg) 248939583Swpaul return; 249039583Swpaul 249136270Swpaul s = splimp(); 249236270Swpaul 249336270Swpaul ifp = &sc->arpcom.ac_if; 249436270Swpaul 249536270Swpaul /* 249636270Swpaul * Cancel pending I/O. 249736270Swpaul */ 249836270Swpaul tl_stop(sc); 249936270Swpaul 250036270Swpaul /* 250136270Swpaul * Set 'capture all frames' bit for promiscuous mode. 250236270Swpaul */ 250339583Swpaul if (ifp->if_flags & IFF_PROMISC) 250439583Swpaul tl_dio_setbit(sc, TL_NETCMD, TL_CMD_CAF); 250539583Swpaul else 250639583Swpaul tl_dio_clrbit(sc, TL_NETCMD, TL_CMD_CAF); 250736270Swpaul 250836270Swpaul /* 250936270Swpaul * Set capture broadcast bit to capture broadcast frames. 251036270Swpaul */ 251139583Swpaul if (ifp->if_flags & IFF_BROADCAST) 251239583Swpaul tl_dio_clrbit(sc, TL_NETCMD, TL_CMD_NOBRX); 251339583Swpaul else 251439583Swpaul tl_dio_setbit(sc, TL_NETCMD, TL_CMD_NOBRX); 251536270Swpaul 251636270Swpaul /* Init our MAC address */ 251741656Swpaul tl_setfilt(sc, (caddr_t)&sc->arpcom.ac_enaddr, 0); 251836270Swpaul 251939583Swpaul /* Init multicast filter, if needed. */ 252039583Swpaul tl_setmulti(sc); 252139583Swpaul 252236270Swpaul /* Init circular RX list. */ 252339583Swpaul if (tl_list_rx_init(sc) == ENOBUFS) { 252439583Swpaul printf("tl%d: initialization failed: no " 252539583Swpaul "memory for rx buffers\n", sc->tl_unit); 252639583Swpaul tl_stop(sc); 252736270Swpaul return; 252836270Swpaul } 252936270Swpaul 253036270Swpaul /* Init TX pointers. */ 253136270Swpaul tl_list_tx_init(sc); 253236270Swpaul 253336270Swpaul /* 253436270Swpaul * Enable PHY interrupts. 253536270Swpaul */ 253636270Swpaul phy_sts = tl_phy_readreg(sc, TL_PHY_CTL); 253736270Swpaul phy_sts |= PHY_CTL_INTEN; 253836270Swpaul tl_phy_writereg(sc, TL_PHY_CTL, phy_sts); 253936270Swpaul 254036270Swpaul /* Enable MII interrupts. */ 254139583Swpaul tl_dio_setbit(sc, TL_NETSIO, TL_SIO_MINTEN); 254236270Swpaul 254339583Swpaul /* Enable PCI interrupts. */ 254439583Swpaul CMD_SET(sc, TL_CMD_INTSON); 254536270Swpaul 254636270Swpaul /* Load the address of the rx list */ 254739583Swpaul CMD_SET(sc, TL_CMD_RT); 254839583Swpaul CSR_WRITE_4(sc, TL_CH_PARM, vtophys(&sc->tl_ldata->tl_rx_list[0])); 254936270Swpaul 255038030Swpaul /* 255139583Swpaul * XXX This is a kludge to handle adapters with the Micro Linear 255239583Swpaul * ML6692 100BaseTX PHY, which only supports 100Mbps modes and 255339583Swpaul * relies on the controller's internal 10Mbps PHY to provide 255439583Swpaul * 10Mbps modes. The ML6692 always shows up with a vendor/device ID 255539583Swpaul * of 0 (it doesn't actually have vendor/device ID registers) 255639583Swpaul * so we use that property to detect it. In theory there ought to 255739583Swpaul * be a better way to 'spot the looney' but I can't find one. 255839583Swpaul */ 255939583Swpaul if (!sc->tl_phy_vid) { 256039583Swpaul u_int8_t addr = 0; 256139583Swpaul u_int16_t bmcr; 256238030Swpaul 256339583Swpaul bmcr = tl_phy_readreg(sc, PHY_BMCR); 256439583Swpaul addr = sc->tl_phy_addr; 256539583Swpaul sc->tl_phy_addr = TL_PHYADDR_MAX; 256639583Swpaul tl_phy_writereg(sc, PHY_BMCR, PHY_BMCR_RESET); 256739583Swpaul if (bmcr & PHY_BMCR_SPEEDSEL) 256839583Swpaul tl_phy_writereg(sc, PHY_BMCR, PHY_BMCR_ISOLATE); 256939583Swpaul else 257039583Swpaul tl_phy_writereg(sc, PHY_BMCR, bmcr); 257139583Swpaul sc->tl_phy_addr = addr; 257239583Swpaul } 257338030Swpaul 257436270Swpaul /* Send the RX go command */ 257539583Swpaul CMD_SET(sc, TL_CMD_GO|TL_CMD_RT); 257636270Swpaul 257736270Swpaul ifp->if_flags |= IFF_RUNNING; 257836270Swpaul ifp->if_flags &= ~IFF_OACTIVE; 257936270Swpaul 258036270Swpaul (void)splx(s); 258136270Swpaul 258236270Swpaul /* Start the stats update counter */ 258336270Swpaul sc->tl_stat_ch = timeout(tl_stats_update, sc, hz); 258436270Swpaul 258536270Swpaul return; 258636270Swpaul} 258736270Swpaul 258836270Swpaul/* 258936270Swpaul * Set media options. 259036270Swpaul */ 259136270Swpaulstatic int tl_ifmedia_upd(ifp) 259236270Swpaul struct ifnet *ifp; 259336270Swpaul{ 259436270Swpaul struct tl_softc *sc; 259536270Swpaul struct ifmedia *ifm; 259636270Swpaul 259736270Swpaul sc = ifp->if_softc; 259836270Swpaul ifm = &sc->ifmedia; 259936270Swpaul 260036270Swpaul if (IFM_TYPE(ifm->ifm_media) != IFM_ETHER) 260136270Swpaul return(EINVAL); 260236270Swpaul 260336270Swpaul if (IFM_SUBTYPE(ifm->ifm_media) == IFM_AUTO) 260436270Swpaul tl_autoneg(sc, TL_FLAG_SCHEDDELAY, 1); 260536270Swpaul else 260636270Swpaul tl_setmode(sc, ifm->ifm_media); 260736270Swpaul 260836270Swpaul return(0); 260936270Swpaul} 261036270Swpaul 261136270Swpaul/* 261236270Swpaul * Report current media status. 261336270Swpaul */ 261436270Swpaulstatic void tl_ifmedia_sts(ifp, ifmr) 261536270Swpaul struct ifnet *ifp; 261636270Swpaul struct ifmediareq *ifmr; 261736270Swpaul{ 261836270Swpaul u_int16_t phy_ctl; 261936270Swpaul u_int16_t phy_sts; 262036270Swpaul struct tl_softc *sc; 262136270Swpaul 262236270Swpaul sc = ifp->if_softc; 262336270Swpaul 262436270Swpaul ifmr->ifm_active = IFM_ETHER; 262536270Swpaul 262645155Swpaul if (sc->tl_bitrate) { 262745155Swpaul if (tl_dio_read8(sc, TL_ACOMMIT) & TL_AC_MTXD1) 262845155Swpaul ifmr->ifm_active = IFM_ETHER|IFM_10_5; 262945155Swpaul else 263045155Swpaul ifmr->ifm_active = IFM_ETHER|IFM_10_T; 263145155Swpaul if (tl_dio_read8(sc, TL_ACOMMIT) & TL_AC_MTXD3) 263245155Swpaul ifmr->ifm_active |= IFM_HDX; 263345155Swpaul else 263445155Swpaul ifmr->ifm_active |= IFM_FDX; 263545155Swpaul return; 263645155Swpaul } 263745155Swpaul 263836270Swpaul phy_ctl = tl_phy_readreg(sc, PHY_BMCR); 263936270Swpaul phy_sts = tl_phy_readreg(sc, TL_PHY_CTL); 264036270Swpaul 264136270Swpaul if (phy_sts & PHY_CTL_AUISEL) 264239583Swpaul ifmr->ifm_active = IFM_ETHER|IFM_10_5; 264336270Swpaul 264436270Swpaul if (phy_ctl & PHY_BMCR_LOOPBK) 264539583Swpaul ifmr->ifm_active = IFM_ETHER|IFM_LOOP; 264636270Swpaul 264736270Swpaul if (phy_ctl & PHY_BMCR_SPEEDSEL) 264839583Swpaul ifmr->ifm_active = IFM_ETHER|IFM_100_TX; 264936270Swpaul else 265039583Swpaul ifmr->ifm_active = IFM_ETHER|IFM_10_T; 265136270Swpaul 265236270Swpaul if (phy_ctl & PHY_BMCR_DUPLEX) { 265336270Swpaul ifmr->ifm_active |= IFM_FDX; 265436270Swpaul ifmr->ifm_active &= ~IFM_HDX; 265536270Swpaul } else { 265636270Swpaul ifmr->ifm_active &= ~IFM_FDX; 265736270Swpaul ifmr->ifm_active |= IFM_HDX; 265836270Swpaul } 265936270Swpaul 266036270Swpaul return; 266136270Swpaul} 266236270Swpaul 266336270Swpaulstatic int tl_ioctl(ifp, command, data) 266436270Swpaul struct ifnet *ifp; 266536735Sdfr u_long command; 266636270Swpaul caddr_t data; 266736270Swpaul{ 266836270Swpaul struct tl_softc *sc = ifp->if_softc; 266936270Swpaul struct ifreq *ifr = (struct ifreq *) data; 267036270Swpaul int s, error = 0; 267136270Swpaul 267236270Swpaul s = splimp(); 267336270Swpaul 267436270Swpaul switch(command) { 267536270Swpaul case SIOCSIFADDR: 267636270Swpaul case SIOCGIFADDR: 267736270Swpaul case SIOCSIFMTU: 267836270Swpaul error = ether_ioctl(ifp, command, data); 267936270Swpaul break; 268036270Swpaul case SIOCSIFFLAGS: 268136270Swpaul if (ifp->if_flags & IFF_UP) { 268236270Swpaul tl_init(sc); 268336270Swpaul } else { 268436270Swpaul if (ifp->if_flags & IFF_RUNNING) { 268536270Swpaul tl_stop(sc); 268636270Swpaul } 268736270Swpaul } 268836270Swpaul error = 0; 268936270Swpaul break; 269036270Swpaul case SIOCADDMULTI: 269136270Swpaul case SIOCDELMULTI: 269236270Swpaul tl_setmulti(sc); 269336270Swpaul error = 0; 269436270Swpaul break; 269536270Swpaul case SIOCSIFMEDIA: 269636270Swpaul case SIOCGIFMEDIA: 269736270Swpaul error = ifmedia_ioctl(ifp, ifr, &sc->ifmedia, command); 269836270Swpaul break; 269936270Swpaul default: 270036270Swpaul error = EINVAL; 270136270Swpaul break; 270236270Swpaul } 270336270Swpaul 270436270Swpaul (void)splx(s); 270536270Swpaul 270636270Swpaul return(error); 270736270Swpaul} 270836270Swpaul 270936270Swpaulstatic void tl_watchdog(ifp) 271036270Swpaul struct ifnet *ifp; 271136270Swpaul{ 271236270Swpaul struct tl_softc *sc; 271336270Swpaul u_int16_t bmsr; 271436270Swpaul 271536270Swpaul sc = ifp->if_softc; 271636270Swpaul 271736270Swpaul if (sc->tl_autoneg) { 271836270Swpaul tl_autoneg(sc, TL_FLAG_DELAYTIMEO, 1); 271936270Swpaul return; 272036270Swpaul } 272136270Swpaul 272236270Swpaul /* Check that we're still connected. */ 272336270Swpaul tl_phy_readreg(sc, PHY_BMSR); 272436270Swpaul bmsr = tl_phy_readreg(sc, PHY_BMSR); 272536270Swpaul if (!(bmsr & PHY_BMSR_LINKSTAT)) { 272636270Swpaul printf("tl%d: no carrier\n", sc->tl_unit); 272736270Swpaul tl_autoneg(sc, TL_FLAG_SCHEDDELAY, 1); 272836270Swpaul } else 272936270Swpaul printf("tl%d: device timeout\n", sc->tl_unit); 273036270Swpaul 273136270Swpaul ifp->if_oerrors++; 273236270Swpaul 273336270Swpaul tl_init(sc); 273436270Swpaul 273536270Swpaul return; 273636270Swpaul} 273736270Swpaul 273836270Swpaul/* 273936270Swpaul * Stop the adapter and free any mbufs allocated to the 274036270Swpaul * RX and TX lists. 274136270Swpaul */ 274236270Swpaulstatic void tl_stop(sc) 274336270Swpaul struct tl_softc *sc; 274436270Swpaul{ 274536270Swpaul register int i; 274636270Swpaul struct ifnet *ifp; 274736270Swpaul 274836270Swpaul ifp = &sc->arpcom.ac_if; 274936270Swpaul 275036270Swpaul /* Stop the stats updater. */ 275136270Swpaul untimeout(tl_stats_update, sc, sc->tl_stat_ch); 275236270Swpaul 275336270Swpaul /* Stop the transmitter */ 275439583Swpaul CMD_CLR(sc, TL_CMD_RT); 275539583Swpaul CMD_SET(sc, TL_CMD_STOP); 275639583Swpaul CSR_WRITE_4(sc, TL_CH_PARM, 0); 275736270Swpaul 275836270Swpaul /* Stop the receiver */ 275939583Swpaul CMD_SET(sc, TL_CMD_RT); 276039583Swpaul CMD_SET(sc, TL_CMD_STOP); 276139583Swpaul CSR_WRITE_4(sc, TL_CH_PARM, 0); 276236270Swpaul 276336270Swpaul /* 276436270Swpaul * Disable host interrupts. 276536270Swpaul */ 276639583Swpaul CMD_SET(sc, TL_CMD_INTSOFF); 276736270Swpaul 276836270Swpaul /* 276936270Swpaul * Disable MII interrupts. 277036270Swpaul */ 277139583Swpaul tl_dio_clrbit(sc, TL_NETSIO, TL_SIO_MINTEN); 277236270Swpaul 277336270Swpaul /* 277436270Swpaul * Clear list pointer. 277536270Swpaul */ 277639583Swpaul CSR_WRITE_4(sc, TL_CH_PARM, 0); 277736270Swpaul 277836270Swpaul /* 277936270Swpaul * Free the RX lists. 278036270Swpaul */ 278136270Swpaul for (i = 0; i < TL_RX_LIST_CNT; i++) { 278236270Swpaul if (sc->tl_cdata.tl_rx_chain[i].tl_mbuf != NULL) { 278336270Swpaul m_freem(sc->tl_cdata.tl_rx_chain[i].tl_mbuf); 278436270Swpaul sc->tl_cdata.tl_rx_chain[i].tl_mbuf = NULL; 278536270Swpaul } 278636270Swpaul } 278736270Swpaul bzero((char *)&sc->tl_ldata->tl_rx_list, 278836270Swpaul sizeof(sc->tl_ldata->tl_rx_list)); 278936270Swpaul 279036270Swpaul /* 279136270Swpaul * Free the TX list buffers. 279236270Swpaul */ 279336270Swpaul for (i = 0; i < TL_TX_LIST_CNT; i++) { 279436270Swpaul if (sc->tl_cdata.tl_tx_chain[i].tl_mbuf != NULL) { 279536270Swpaul m_freem(sc->tl_cdata.tl_tx_chain[i].tl_mbuf); 279636270Swpaul sc->tl_cdata.tl_tx_chain[i].tl_mbuf = NULL; 279736270Swpaul } 279836270Swpaul } 279936270Swpaul bzero((char *)&sc->tl_ldata->tl_tx_list, 280036270Swpaul sizeof(sc->tl_ldata->tl_tx_list)); 280136270Swpaul 280236270Swpaul ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE); 280336270Swpaul 280436270Swpaul return; 280536270Swpaul} 280636270Swpaul 280736270Swpaul/* 280836270Swpaul * Stop all chip I/O so that the kernel's probe routines don't 280936270Swpaul * get confused by errant DMAs when rebooting. 281036270Swpaul */ 281139583Swpaulstatic void tl_shutdown(howto, xsc) 281236270Swpaul int howto; 281339583Swpaul void *xsc; 281436270Swpaul{ 281539583Swpaul struct tl_softc *sc; 281636270Swpaul 281739583Swpaul sc = xsc; 281836270Swpaul 281939583Swpaul tl_stop(sc); 282036270Swpaul 282136270Swpaul return; 282236270Swpaul} 282336270Swpaul 282436270Swpaul 282539583Swpaulstatic struct pci_device tl_device = { 282639583Swpaul "tl", 282736270Swpaul tl_probe, 282839583Swpaul tl_attach, 282936270Swpaul &tl_count, 283036270Swpaul NULL 283136270Swpaul}; 283239583SwpaulDATA_SET(pcidevice_set, tl_device); 2833