if_tl.c revision 36270
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 * 3236270Swpaul * $Id: if_tl.c,v 1.37 1998/05/20 20:08:00 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 * 4136270Swpaul * Written using the following three 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) 4636270Swpaul * 4736270Swpaul * Written by Bill Paul <wpaul@ctr.columbia.edu> 4836270Swpaul * Electrical Engineering Department 4936270Swpaul * Columbia University, New York City 5036270Swpaul */ 5136270Swpaul 5236270Swpaul/* 5336270Swpaul * Some notes about the ThunderLAN: 5436270Swpaul * 5536270Swpaul * The ThunderLAN controller is a single chip containing PCI controller 5636270Swpaul * logic, approximately 3K of on-board SRAM, a LAN controller, and media 5736270Swpaul * independent interface (MII). The MII allows the ThunderLAN chip to 5836270Swpaul * control up to 32 different physical interfaces (PHYs). The ThunderLAN 5936270Swpaul * also has a built-in 10baseT PHY, allowing a single ThunderLAN controller 6036270Swpaul * to act as a complete ethernet interface. 6136270Swpaul * 6236270Swpaul * Other PHYs may be attached to the ThunderLAN; the Compaq 10/100 cards 6336270Swpaul * use a National Semiconductor DP83840A PHY that supports 10 or 100Mb/sec 6436270Swpaul * in full or half duplex. Some of the Compaq Deskpro machines use a 6536270Swpaul * Level 1 LXT970 PHY with the same capabilities. A serial EEPROM is also 6636270Swpaul * attached to the ThunderLAN chip to provide power-up default register 6736270Swpaul * settings and for storing the adapter's stattion address. Although not 6836270Swpaul * supported by this driver, the ThunderLAN chip can also be connected 6936270Swpaul * to token ring PHYs. 7036270Swpaul * 7136270Swpaul * It is important to note that while it is possible to have multiple 7236270Swpaul * PHYs attached to the ThunderLAN's MII, only one PHY may be active at 7336270Swpaul * any time. (This makes me wonder exactly how the dual port Compaq 7436270Swpaul * adapter is supposed to work.) This driver attempts to compensate for 7536270Swpaul * this in the following way: 7636270Swpaul * 7736270Swpaul * When the ThunderLAN chip is probed, the probe routine attempts to 7836270Swpaul * locate all attached PHYs by checking all 32 possible PHY addresses 7936270Swpaul * (0x00 to 0x1F). Each PHY is attached as a separate logical interface. 8036270Swpaul * The driver allows any one interface to be brought up at any given 8136270Swpaul * time: if an attempt is made to bring up a second PHY while another 8236270Swpaul * PHY is already enabled, the driver will return an error. 8336270Swpaul * 8436270Swpaul * The ThunderLAN has a set of registers which can be used to issue 8536270Swpaul * command, acknowledge interrupts, and to manipulate other internal 8636270Swpaul * registers on its DIO bus. The primary registers can be accessed 8736270Swpaul * using either programmed I/O (inb/outb) or via PCI memory mapping, 8836270Swpaul * depending on how the card is configured during the PCI probing 8936270Swpaul * phase. It is even possible to have both PIO and memory mapped 9036270Swpaul * access turned on at the same time. 9136270Swpaul * 9236270Swpaul * Frame reception and transmission with the ThunderLAN chip is done 9336270Swpaul * using frame 'lists.' A list structure looks more or less like this: 9436270Swpaul * 9536270Swpaul * struct tl_frag { 9636270Swpaul * u_int32_t fragment_address; 9736270Swpaul * u_int32_t fragment_size; 9836270Swpaul * }; 9936270Swpaul * struct tl_list { 10036270Swpaul * u_int32_t forward_pointer; 10136270Swpaul * u_int16_t cstat; 10236270Swpaul * u_int16_t frame_size; 10336270Swpaul * struct tl_frag fragments[10]; 10436270Swpaul * }; 10536270Swpaul * 10636270Swpaul * The forward pointer in the list header can be either a 0 or the address 10736270Swpaul * of another list, which allows several lists to be linked together. Each 10836270Swpaul * list contains up to 10 fragment descriptors. This means the chip allows 10936270Swpaul * ethernet frames to be broken up into up to 10 chunks for transfer to 11036270Swpaul * and from the SRAM. Note that the forward pointer and fragment buffer 11136270Swpaul * addresses are physical memory addresses, not virtual. Note also that 11236270Swpaul * a single ethernet frame can not span lists: if the host wants to 11336270Swpaul * transmit a frame and the frame data is split up over more than 10 11436270Swpaul * buffers, the frame has to collapsed before it can be transmitted. 11536270Swpaul * 11636270Swpaul * To receive frames, the driver sets up a number of lists and populates 11736270Swpaul * the fragment descriptors, then it sends an RX GO command to the chip. 11836270Swpaul * When a frame is received, the chip will DMA it into the memory regions 11936270Swpaul * specified by the fragment descriptors and then trigger an RX 'end of 12036270Swpaul * frame interrupt' when done. The driver may choose to use only one 12136270Swpaul * fragment per list; this may result is slighltly less efficient use 12236270Swpaul * of memory in exchange for improving performance. 12336270Swpaul * 12436270Swpaul * To transmit frames, the driver again sets up lists and fragment 12536270Swpaul * descriptors, only this time the buffers contain frame data that 12636270Swpaul * is to be DMA'ed into the chip instead of out of it. Once the chip 12736270Swpaul * has transfered the data into its on-board SRAM, it will trigger a 12836270Swpaul * TX 'end of frame' interrupt. It will also generate an 'end of channel' 12936270Swpaul * interrupt when it reaches the end of the list. 13036270Swpaul */ 13136270Swpaul 13236270Swpaul/* 13336270Swpaul * Some notes about this driver: 13436270Swpaul * 13536270Swpaul * The ThunderLAN chip provides a couple of different ways to organize 13636270Swpaul * reception, transmission and interrupt handling. The simplest approach 13736270Swpaul * is to use one list each for transmission and reception. In this mode, 13836270Swpaul * the ThunderLAN will generate two interrupts for every received frame 13936270Swpaul * (one RX EOF and one RX EOC) and two for each transmitted frame (one 14036270Swpaul * TX EOF and one TX EOC). This may make the driver simpler but it hurts 14136270Swpaul * performance to have to handle so many interrupts. 14236270Swpaul * 14336270Swpaul * Initially I wanted to create a circular list of receive buffers so 14436270Swpaul * that the ThunderLAN chip would think there was an infinitely long 14536270Swpaul * receive channel and never deliver an RXEOC interrupt. However this 14636270Swpaul * doesn't work correctly under heavy load: while the manual says the 14736270Swpaul * chip will trigger an RXEOF interrupt each time a frame is copied into 14836270Swpaul * memory, you can't count on the chip waiting around for you to acknowledge 14936270Swpaul * the interrupt before it starts trying to DMA the next frame. The result 15036270Swpaul * is that the chip might traverse the entire circular list and then wrap 15136270Swpaul * around before you have a chance to do anything about it. Consequently, 15236270Swpaul * the receive list is terminated (with a 0 in the forward pointer in the 15336270Swpaul * last element). Each time an RXEOF interrupt arrives, the used list 15436270Swpaul * is shifted to the end of the list. This gives the appearance of an 15536270Swpaul * infinitely large RX chain so long as the driver doesn't fall behind 15636270Swpaul * the chip and allow all of the lists to be filled up. 15736270Swpaul * 15836270Swpaul * If all the lists are filled, the adapter will deliver an RX 'end of 15936270Swpaul * channel' interrupt when it hits the 0 forward pointer at the end of 16036270Swpaul * the chain. The RXEOC handler then cleans out the RX chain and resets 16136270Swpaul * the list head pointer in the ch_parm register and restarts the receiver. 16236270Swpaul * 16336270Swpaul * For frame transmission, it is possible to program the ThunderLAN's 16436270Swpaul * transmit interrupt threshold so that the chip can acknowledge multiple 16536270Swpaul * lists with only a single TX EOF interrupt. This allows the driver to 16636270Swpaul * queue several frames in one shot, and only have to handle a total 16736270Swpaul * two interrupts (one TX EOF and one TX EOC) no matter how many frames 16836270Swpaul * are transmitted. Frame transmission is done directly out of the 16936270Swpaul * mbufs passed to the tl_start() routine via the interface send queue. 17036270Swpaul * The driver simply sets up the fragment descriptors in the transmit 17136270Swpaul * lists to point to the mbuf data regions and sends a TX GO command. 17236270Swpaul * 17336270Swpaul * Note that since the RX and TX lists themselves are always used 17436270Swpaul * only by the driver, the are malloc()ed once at driver initialization 17536270Swpaul * time and never free()ed. 17636270Swpaul * 17736270Swpaul * Also, in order to remain as platform independent as possible, this 17836270Swpaul * driver uses memory mapped register access to manipulate the card 17936270Swpaul * as opposed to programmed I/O. This avoids the use of the inb/outb 18036270Swpaul * (and related) instructions which are specific to the i386 platform. 18136270Swpaul * 18236270Swpaul * Using these techniques, this driver achieves very high performance 18336270Swpaul * by minimizing the amount of interrupts generated during large 18436270Swpaul * transfers and by completely avoiding buffer copies. Frame transfer 18536270Swpaul * to and from the ThunderLAN chip is performed entirely by the chip 18636270Swpaul * itself thereby reducing the load on the host CPU. 18736270Swpaul */ 18836270Swpaul 18936270Swpaul#include "bpfilter.h" 19036270Swpaul 19136270Swpaul#include <sys/param.h> 19236270Swpaul#include <sys/systm.h> 19336270Swpaul#include <sys/sockio.h> 19436270Swpaul#include <sys/mbuf.h> 19536270Swpaul#include <sys/malloc.h> 19636270Swpaul#include <sys/kernel.h> 19736270Swpaul#include <sys/socket.h> 19836270Swpaul#include <sys/syslog.h> 19936270Swpaul 20036270Swpaul#include <net/if.h> 20136270Swpaul#include <net/if_arp.h> 20236270Swpaul#include <net/ethernet.h> 20336270Swpaul#include <net/if_dl.h> 20436270Swpaul#include <net/if_mib.h> 20536270Swpaul#include <net/if_media.h> 20636270Swpaul#include <net/if_types.h> 20736270Swpaul 20836270Swpaul#ifdef INET 20936270Swpaul#include <netinet/in.h> 21036270Swpaul#include <netinet/in_systm.h> 21136270Swpaul#include <netinet/in_var.h> 21236270Swpaul#include <netinet/ip.h> 21336270Swpaul#include <netinet/if_ether.h> 21436270Swpaul#endif 21536270Swpaul 21636270Swpaul#ifdef IPX 21736270Swpaul#include <netipx/ipx.h> 21836270Swpaul#include <netipx/ipx_if.h> 21936270Swpaul#endif 22036270Swpaul 22136270Swpaul#ifdef NS 22236270Swpaul#include <netns/ns.h> 22336270Swpaul#include <netns/ns_if.h> 22436270Swpaul#endif 22536270Swpaul 22636270Swpaul#if NBPFILTER > 0 22736270Swpaul#include <net/bpf.h> 22836270Swpaul#include <net/bpfdesc.h> 22936270Swpaul#endif 23036270Swpaul 23136270Swpaul#include <vm/vm.h> /* for vtophys */ 23236270Swpaul#include <vm/vm_param.h> /* for vtophys */ 23336270Swpaul#include <vm/pmap.h> /* for vtophys */ 23436270Swpaul#include <machine/clock.h> /* for DELAY */ 23536270Swpaul 23636270Swpaul#include <pci/pcireg.h> 23736270Swpaul#include <pci/pcivar.h> 23836270Swpaul 23936270Swpaul#include <osreldate.h> 24036270Swpaul 24136270Swpaul#include <pci/if_tlreg.h> 24236270Swpaul 24336270Swpaul#ifndef lint 24436270Swpaulstatic char rcsid[] = 24536270Swpaul "$Id: if_tl.c,v 1.37 1998/05/20 20:08:00 wpaul Exp $"; 24636270Swpaul#endif 24736270Swpaul 24836270Swpaul/* 24936270Swpaul * Various supported device vendors/types and their names. 25036270Swpaul */ 25136270Swpaul 25236270Swpaulstatic struct tl_type tl_devs[] = { 25336270Swpaul { TI_VENDORID, TI_DEVICEID_THUNDERLAN, 25436270Swpaul "Texas Instruments ThunderLAN" }, 25536270Swpaul { COMPAQ_VENDORID, COMPAQ_DEVICEID_NETEL_10, 25636270Swpaul "Compaq Netelligent 10" }, 25736270Swpaul { COMPAQ_VENDORID, COMPAQ_DEVICEID_NETEL_10_100, 25836270Swpaul "Compaq Netelligent 10/100" }, 25936270Swpaul { COMPAQ_VENDORID, COMPAQ_DEVICEID_NETEL_10_100_PROLIANT, 26036270Swpaul "Compaq Netelligent 10/100 Proliant" }, 26136270Swpaul { COMPAQ_VENDORID, COMPAQ_DEVICEID_NETEL_10_100_DUAL, 26236270Swpaul "Compaq Netelligent 10/100 Dual Port" }, 26336270Swpaul { COMPAQ_VENDORID, COMPAQ_DEVICEID_NETFLEX_3P_INTEGRATED, 26436270Swpaul "Compaq NetFlex-3/P Integrated" }, 26536270Swpaul { COMPAQ_VENDORID, COMPAQ_DEVICEID_NETFLEX_3P, 26636270Swpaul "Compaq NetFlex-3/P" }, 26736270Swpaul { COMPAQ_VENDORID, COMPAQ_DEVICEID_NETFLEX_3P_BNC, 26836270Swpaul "Compaq NetFlex 3/P w/ BNC" }, 26936270Swpaul { COMPAQ_VENDORID, COMPAQ_DEVICEID_DESKPRO_4000_5233MMX, 27036270Swpaul "Compaq Deskpro 4000 5233MMX" }, 27136270Swpaul { 0, 0, NULL } 27236270Swpaul}; 27336270Swpaul 27436270Swpaul/* 27536270Swpaul * Various supported PHY vendors/types and their names. Note that 27636270Swpaul * this driver will work with pretty much any MII-compliant PHY, 27736270Swpaul * so failure to positively identify the chip is not a fatal error. 27836270Swpaul */ 27936270Swpaul 28036270Swpaulstatic struct tl_type tl_phys[] = { 28136270Swpaul { TI_PHY_VENDORID, TI_PHY_10BT, "<TI ThunderLAN 10BT (internal)>" }, 28236270Swpaul { TI_PHY_VENDORID, TI_PHY_100VGPMI, "<TI TNETE211 100VG Any-LAN>" }, 28336270Swpaul { NS_PHY_VENDORID, NS_PHY_83840A, "<National Semiconductor DP83840A>"}, 28436270Swpaul { LEVEL1_PHY_VENDORID, LEVEL1_PHY_LXT970, "<Level 1 LXT970>" }, 28536270Swpaul { INTEL_PHY_VENDORID, INTEL_PHY_82555, "<Intel 82555>" }, 28636270Swpaul { SEEQ_PHY_VENDORID, SEEQ_PHY_80220, "<SEEQ 80220>" }, 28736270Swpaul { 0, 0, "<MII-compliant physical interface>" } 28836270Swpaul}; 28936270Swpaul 29036270Swpaulstatic struct tl_iflist *tl_iflist = NULL; 29136270Swpaulstatic unsigned long tl_count; 29236270Swpaul 29336270Swpaulstatic char *tl_probe __P((pcici_t, pcidi_t)); 29436270Swpaulstatic void tl_attach_ctlr __P((pcici_t, int)); 29536270Swpaulstatic int tl_attach_phy __P((struct tl_csr *, int, char *, 29636270Swpaul int, struct tl_iflist *)); 29736270Swpaulstatic int tl_intvec_invalid __P((void *, u_int32_t)); 29836270Swpaulstatic int tl_intvec_dummy __P((void *, u_int32_t)); 29936270Swpaulstatic int tl_intvec_rxeoc __P((void *, u_int32_t)); 30036270Swpaulstatic int tl_intvec_txeoc __P((void *, u_int32_t)); 30136270Swpaulstatic int tl_intvec_txeof __P((void *, u_int32_t)); 30236270Swpaulstatic int tl_intvec_rxeof __P((void *, u_int32_t)); 30336270Swpaulstatic int tl_intvec_adchk __P((void *, u_int32_t)); 30436270Swpaulstatic int tl_intvec_netsts __P((void *, u_int32_t)); 30536270Swpaulstatic int tl_intvec_statoflow __P((void *, u_int32_t)); 30636270Swpaul 30736270Swpaulstatic int tl_newbuf __P((struct tl_softc *, struct tl_chain *)); 30836270Swpaulstatic void tl_stats_update __P((void *)); 30936270Swpaulstatic int tl_encap __P((struct tl_softc *, struct tl_chain *, 31036270Swpaul struct mbuf *)); 31136270Swpaul 31236270Swpaulstatic void tl_intr __P((void *)); 31336270Swpaulstatic void tl_start __P((struct ifnet *)); 31436270Swpaulstatic int tl_ioctl __P((struct ifnet *, int, caddr_t)); 31536270Swpaulstatic void tl_init __P((void *)); 31636270Swpaulstatic void tl_stop __P((struct tl_softc *)); 31736270Swpaulstatic void tl_watchdog __P((struct ifnet *)); 31836270Swpaulstatic void tl_shutdown __P((int, void *)); 31936270Swpaulstatic int tl_ifmedia_upd __P((struct ifnet *)); 32036270Swpaulstatic void tl_ifmedia_sts __P((struct ifnet *, struct ifmediareq *)); 32136270Swpaul 32236270Swpaulstatic u_int8_t tl_eeprom_putbyte __P((struct tl_csr *, u_int8_t)); 32336270Swpaulstatic u_int8_t tl_eeprom_getbyte __P((struct tl_csr *, u_int8_t , 32436270Swpaul u_int8_t * )); 32536270Swpaulstatic int tl_read_eeprom __P((struct tl_csr *, caddr_t, int, int)); 32636270Swpaul 32736270Swpaulstatic void tl_mii_sync __P((struct tl_csr *)); 32836270Swpaulstatic void tl_mii_send __P((struct tl_csr *, u_int32_t, int)); 32936270Swpaulstatic int tl_mii_readreg __P((struct tl_csr *, struct tl_mii_frame *)); 33036270Swpaulstatic int tl_mii_writereg __P((struct tl_csr *, struct tl_mii_frame *)); 33136270Swpaulstatic u_int16_t tl_phy_readreg __P((struct tl_softc *, int)); 33236270Swpaulstatic void tl_phy_writereg __P((struct tl_softc *, u_int16_t, u_int16_t)); 33336270Swpaul 33436270Swpaulstatic void tl_autoneg __P((struct tl_softc *, int, int)); 33536270Swpaulstatic void tl_setmode __P((struct tl_softc *, int)); 33636270Swpaulstatic int tl_calchash __P((char *)); 33736270Swpaulstatic void tl_setmulti __P((struct tl_softc *)); 33836270Swpaulstatic void tl_softreset __P((struct tl_csr *, int)); 33936270Swpaulstatic int tl_list_rx_init __P((struct tl_softc *)); 34036270Swpaulstatic int tl_list_tx_init __P((struct tl_softc *)); 34136270Swpaul 34236270Swpaul/* 34336270Swpaul * ThunderLAN adapters typically have a serial EEPROM containing 34436270Swpaul * configuration information. The main reason we're interested in 34536270Swpaul * it is because it also contains the adapters's station address. 34636270Swpaul * 34736270Swpaul * Access to the EEPROM is a bit goofy since it is a serial device: 34836270Swpaul * you have to do reads and writes one bit at a time. The state of 34936270Swpaul * the DATA bit can only change while the CLOCK line is held low. 35036270Swpaul * Transactions work basically like this: 35136270Swpaul * 35236270Swpaul * 1) Send the EEPROM_START sequence to prepare the EEPROM for 35336270Swpaul * accepting commands. This pulls the clock high, sets 35436270Swpaul * the data bit to 0, enables transmission to the EEPROM, 35536270Swpaul * pulls the data bit up to 1, then pulls the clock low. 35636270Swpaul * The idea is to do a 0 to 1 transition of the data bit 35736270Swpaul * while the clock pin is held high. 35836270Swpaul * 35936270Swpaul * 2) To write a bit to the EEPROM, set the TXENABLE bit, then 36036270Swpaul * set the EDATA bit to send a 1 or clear it to send a 0. 36136270Swpaul * Finally, set and then clear ECLOK. Strobing the clock 36236270Swpaul * transmits the bit. After 8 bits have been written, the 36336270Swpaul * EEPROM should respond with an ACK, which should be read. 36436270Swpaul * 36536270Swpaul * 3) To read a bit from the EEPROM, clear the TXENABLE bit, 36636270Swpaul * then set ECLOK. The bit can then be read by reading EDATA. 36736270Swpaul * ECLOCK should then be cleared again. This can be repeated 36836270Swpaul * 8 times to read a whole byte, after which the 36936270Swpaul * 37036270Swpaul * 4) We need to send the address byte to the EEPROM. For this 37136270Swpaul * we have to send the write control byte to the EEPROM to 37236270Swpaul * tell it to accept data. The byte is 0xA0. The EEPROM should 37336270Swpaul * ack this. The address byte can be send after that. 37436270Swpaul * 37536270Swpaul * 5) Now we have to tell the EEPROM to send us data. For that we 37636270Swpaul * have to transmit the read control byte, which is 0xA1. This 37736270Swpaul * byte should also be acked. We can then read the data bits 37836270Swpaul * from the EEPROM. 37936270Swpaul * 38036270Swpaul * 6) When we're all finished, send the EEPROM_STOP sequence. 38136270Swpaul * 38236270Swpaul * Note that we use the ThunderLAN's NetSio register to access the 38336270Swpaul * EEPROM, however there is an alternate method. There is a PCI NVRAM 38436270Swpaul * register at PCI offset 0xB4 which can also be used with minor changes. 38536270Swpaul * The difference is that access to PCI registers via pci_conf_read() 38636270Swpaul * and pci_conf_write() is done using programmed I/O, which we want to 38736270Swpaul * avoid. 38836270Swpaul */ 38936270Swpaul 39036270Swpaul/* 39136270Swpaul * Note that EEPROM_START leaves transmission enabled. 39236270Swpaul */ 39336270Swpaul#define EEPROM_START \ 39436270Swpaul DIO_SEL(TL_NETSIO); \ 39536270Swpaul DIO_BYTE1_SET(TL_SIO_ECLOK); /* Pull clock pin high */ \ 39636270Swpaul DIO_BYTE1_SET(TL_SIO_EDATA); /* Set DATA bit to 1 */ \ 39736270Swpaul DIO_BYTE1_SET(TL_SIO_ETXEN); /* Enable xmit to write bit */ \ 39836270Swpaul DIO_BYTE1_CLR(TL_SIO_EDATA); /* Pull DATA bit to 0 again */ \ 39936270Swpaul DIO_BYTE1_CLR(TL_SIO_ECLOK); /* Pull clock low again */ 40036270Swpaul 40136270Swpaul/* 40236270Swpaul * EEPROM_STOP ends access to the EEPROM and clears the ETXEN bit so 40336270Swpaul * that no further data can be written to the EEPROM I/O pin. 40436270Swpaul */ 40536270Swpaul#define EEPROM_STOP \ 40636270Swpaul DIO_SEL(TL_NETSIO); \ 40736270Swpaul DIO_BYTE1_CLR(TL_SIO_ETXEN); /* Disable xmit */ \ 40836270Swpaul DIO_BYTE1_CLR(TL_SIO_EDATA); /* Pull DATA to 0 */ \ 40936270Swpaul DIO_BYTE1_SET(TL_SIO_ECLOK); /* Pull clock high */ \ 41036270Swpaul DIO_BYTE1_SET(TL_SIO_ETXEN); /* Enable xmit */ \ 41136270Swpaul DIO_BYTE1_SET(TL_SIO_EDATA); /* Toggle DATA to 1 */ \ 41236270Swpaul DIO_BYTE1_CLR(TL_SIO_ETXEN); /* Disable xmit. */ \ 41336270Swpaul DIO_BYTE1_CLR(TL_SIO_ECLOK); /* Pull clock low again */ 41436270Swpaul 41536270Swpaul/* 41636270Swpaul * Send an instruction or address to the EEPROM, check for ACK. 41736270Swpaul */ 41836270Swpaulstatic u_int8_t tl_eeprom_putbyte(csr, byte) 41936270Swpaul struct tl_csr *csr; 42036270Swpaul u_int8_t byte; 42136270Swpaul{ 42236270Swpaul register int i, ack = 0; 42336270Swpaul 42436270Swpaul /* 42536270Swpaul * Make sure we're in TX mode. 42636270Swpaul */ 42736270Swpaul DIO_SEL(TL_NETSIO); 42836270Swpaul DIO_BYTE1_SET(TL_SIO_ETXEN); 42936270Swpaul 43036270Swpaul /* 43136270Swpaul * Feed in each bit and stobe the clock. 43236270Swpaul */ 43336270Swpaul for (i = 0x80; i; i >>= 1) { 43436270Swpaul DIO_SEL(TL_NETSIO); 43536270Swpaul if (byte & i) { 43636270Swpaul DIO_BYTE1_SET(TL_SIO_EDATA); 43736270Swpaul } else { 43836270Swpaul DIO_BYTE1_CLR(TL_SIO_EDATA); 43936270Swpaul } 44036270Swpaul DIO_BYTE1_SET(TL_SIO_ECLOK); 44136270Swpaul DIO_BYTE1_CLR(TL_SIO_ECLOK); 44236270Swpaul } 44336270Swpaul 44436270Swpaul /* 44536270Swpaul * Turn off TX mode. 44636270Swpaul */ 44736270Swpaul DIO_BYTE1_CLR(TL_SIO_ETXEN); 44836270Swpaul 44936270Swpaul /* 45036270Swpaul * Check for ack. 45136270Swpaul */ 45236270Swpaul DIO_BYTE1_SET(TL_SIO_ECLOK); 45336270Swpaul ack = DIO_BYTE1_GET(TL_SIO_EDATA); 45436270Swpaul DIO_BYTE1_CLR(TL_SIO_ECLOK); 45536270Swpaul 45636270Swpaul return(ack); 45736270Swpaul} 45836270Swpaul 45936270Swpaul/* 46036270Swpaul * Read a byte of data stored in the EEPROM at address 'addr.' 46136270Swpaul */ 46236270Swpaulstatic u_int8_t tl_eeprom_getbyte(csr, addr, dest) 46336270Swpaul struct tl_csr *csr; 46436270Swpaul u_int8_t addr; 46536270Swpaul u_int8_t *dest; 46636270Swpaul{ 46736270Swpaul register int i; 46836270Swpaul u_int8_t byte = 0; 46936270Swpaul 47036270Swpaul EEPROM_START; 47136270Swpaul /* 47236270Swpaul * Send write control code to EEPROM. 47336270Swpaul */ 47436270Swpaul if (tl_eeprom_putbyte(csr, EEPROM_CTL_WRITE)) 47536270Swpaul return(1); 47636270Swpaul 47736270Swpaul /* 47836270Swpaul * Send address of byte we want to read. 47936270Swpaul */ 48036270Swpaul if (tl_eeprom_putbyte(csr, addr)) 48136270Swpaul return(1); 48236270Swpaul 48336270Swpaul EEPROM_STOP; 48436270Swpaul EEPROM_START; 48536270Swpaul /* 48636270Swpaul * Send read control code to EEPROM. 48736270Swpaul */ 48836270Swpaul if (tl_eeprom_putbyte(csr, EEPROM_CTL_READ)) 48936270Swpaul return(1); 49036270Swpaul 49136270Swpaul /* 49236270Swpaul * Start reading bits from EEPROM. 49336270Swpaul */ 49436270Swpaul DIO_SEL(TL_NETSIO); 49536270Swpaul DIO_BYTE1_CLR(TL_SIO_ETXEN); 49636270Swpaul for (i = 0x80; i; i >>= 1) { 49736270Swpaul DIO_SEL(TL_NETSIO); 49836270Swpaul DIO_BYTE1_SET(TL_SIO_ECLOK); 49936270Swpaul if (DIO_BYTE1_GET(TL_SIO_EDATA)) 50036270Swpaul byte |= i; 50136270Swpaul DIO_BYTE1_CLR(TL_SIO_ECLOK); 50236270Swpaul } 50336270Swpaul 50436270Swpaul EEPROM_STOP; 50536270Swpaul 50636270Swpaul /* 50736270Swpaul * No ACK generated for read, so just return byte. 50836270Swpaul */ 50936270Swpaul 51036270Swpaul *dest = byte; 51136270Swpaul 51236270Swpaul return(0); 51336270Swpaul} 51436270Swpaul 51536270Swpaulstatic void tl_mii_sync(csr) 51636270Swpaul struct tl_csr *csr; 51736270Swpaul{ 51836270Swpaul register int i; 51936270Swpaul 52036270Swpaul DIO_SEL(TL_NETSIO); 52136270Swpaul DIO_BYTE1_CLR(TL_SIO_MTXEN); 52236270Swpaul 52336270Swpaul for (i = 0; i < 32; i++) { 52436270Swpaul DIO_BYTE1_SET(TL_SIO_MCLK); 52536270Swpaul DIO_BYTE1_CLR(TL_SIO_MCLK); 52636270Swpaul } 52736270Swpaul 52836270Swpaul return; 52936270Swpaul} 53036270Swpaul 53136270Swpaulstatic void tl_mii_send(csr, bits, cnt) 53236270Swpaul struct tl_csr *csr; 53336270Swpaul u_int32_t bits; 53436270Swpaul int cnt; 53536270Swpaul{ 53636270Swpaul int i; 53736270Swpaul 53836270Swpaul for (i = (0x1 << (cnt - 1)); i; i >>= 1) { 53936270Swpaul DIO_BYTE1_CLR(TL_SIO_MCLK); 54036270Swpaul if (bits & i) { 54136270Swpaul DIO_BYTE1_SET(TL_SIO_MDATA); 54236270Swpaul } else { 54336270Swpaul DIO_BYTE1_CLR(TL_SIO_MDATA); 54436270Swpaul } 54536270Swpaul DIO_BYTE1_SET(TL_SIO_MCLK); 54636270Swpaul } 54736270Swpaul} 54836270Swpaul 54936270Swpaulstatic int tl_mii_readreg(csr, frame) 55036270Swpaul struct tl_csr *csr; 55136270Swpaul struct tl_mii_frame *frame; 55236270Swpaul 55336270Swpaul{ 55436270Swpaul int i, ack, s; 55536270Swpaul int minten = 0; 55636270Swpaul 55736270Swpaul s = splimp(); 55836270Swpaul 55936270Swpaul tl_mii_sync(csr); 56036270Swpaul 56136270Swpaul /* 56236270Swpaul * Set up frame for RX. 56336270Swpaul */ 56436270Swpaul frame->mii_stdelim = TL_MII_STARTDELIM; 56536270Swpaul frame->mii_opcode = TL_MII_READOP; 56636270Swpaul frame->mii_turnaround = 0; 56736270Swpaul frame->mii_data = 0; 56836270Swpaul 56936270Swpaul /* 57036270Swpaul * Select the NETSIO register. We will be using it 57136270Swpaul * to communicate indirectly with the MII. 57236270Swpaul */ 57336270Swpaul 57436270Swpaul DIO_SEL(TL_NETSIO); 57536270Swpaul 57636270Swpaul /* 57736270Swpaul * Turn off MII interrupt by forcing MINTEN low. 57836270Swpaul */ 57936270Swpaul minten = DIO_BYTE1_GET(TL_SIO_MINTEN); 58036270Swpaul if (minten) { 58136270Swpaul DIO_BYTE1_CLR(TL_SIO_MINTEN); 58236270Swpaul } 58336270Swpaul 58436270Swpaul /* 58536270Swpaul * Turn on data xmit. 58636270Swpaul */ 58736270Swpaul DIO_BYTE1_SET(TL_SIO_MTXEN); 58836270Swpaul 58936270Swpaul /* 59036270Swpaul * Send command/address info. 59136270Swpaul */ 59236270Swpaul tl_mii_send(csr, frame->mii_stdelim, 2); 59336270Swpaul tl_mii_send(csr, frame->mii_opcode, 2); 59436270Swpaul tl_mii_send(csr, frame->mii_phyaddr, 5); 59536270Swpaul tl_mii_send(csr, frame->mii_regaddr, 5); 59636270Swpaul 59736270Swpaul /* 59836270Swpaul * Turn off xmit. 59936270Swpaul */ 60036270Swpaul DIO_BYTE1_CLR(TL_SIO_MTXEN); 60136270Swpaul 60236270Swpaul /* Idle bit */ 60336270Swpaul DIO_BYTE1_CLR(TL_SIO_MCLK); 60436270Swpaul DIO_BYTE1_SET(TL_SIO_MCLK); 60536270Swpaul 60636270Swpaul /* Check for ack */ 60736270Swpaul DIO_BYTE1_CLR(TL_SIO_MCLK); 60836270Swpaul ack = DIO_BYTE1_GET(TL_SIO_MDATA); 60936270Swpaul 61036270Swpaul /* Complete the cycle */ 61136270Swpaul DIO_BYTE1_SET(TL_SIO_MCLK); 61236270Swpaul 61336270Swpaul /* 61436270Swpaul * Now try reading data bits. If the ack failed, we still 61536270Swpaul * need to clock through 16 cycles to keep the PHYs in sync. 61636270Swpaul */ 61736270Swpaul if (ack) { 61836270Swpaul for(i = 0; i < 16; i++) { 61936270Swpaul DIO_BYTE1_CLR(TL_SIO_MCLK); 62036270Swpaul DIO_BYTE1_SET(TL_SIO_MCLK); 62136270Swpaul } 62236270Swpaul goto fail; 62336270Swpaul } 62436270Swpaul 62536270Swpaul for (i = 0x8000; i; i >>= 1) { 62636270Swpaul DIO_BYTE1_CLR(TL_SIO_MCLK); 62736270Swpaul if (!ack) { 62836270Swpaul if (DIO_BYTE1_GET(TL_SIO_MDATA)) 62936270Swpaul frame->mii_data |= i; 63036270Swpaul } 63136270Swpaul DIO_BYTE1_SET(TL_SIO_MCLK); 63236270Swpaul } 63336270Swpaul 63436270Swpaulfail: 63536270Swpaul 63636270Swpaul DIO_BYTE1_CLR(TL_SIO_MCLK); 63736270Swpaul DIO_BYTE1_SET(TL_SIO_MCLK); 63836270Swpaul 63936270Swpaul /* Reenable interrupts */ 64036270Swpaul if (minten) { 64136270Swpaul DIO_BYTE1_SET(TL_SIO_MINTEN); 64236270Swpaul } 64336270Swpaul 64436270Swpaul splx(s); 64536270Swpaul 64636270Swpaul if (ack) 64736270Swpaul return(1); 64836270Swpaul return(0); 64936270Swpaul} 65036270Swpaul 65136270Swpaulstatic int tl_mii_writereg(csr, frame) 65236270Swpaul struct tl_csr *csr; 65336270Swpaul struct tl_mii_frame *frame; 65436270Swpaul 65536270Swpaul{ 65636270Swpaul int s; 65736270Swpaul int minten; 65836270Swpaul 65936270Swpaul tl_mii_sync(csr); 66036270Swpaul 66136270Swpaul s = splimp(); 66236270Swpaul /* 66336270Swpaul * Set up frame for TX. 66436270Swpaul */ 66536270Swpaul 66636270Swpaul frame->mii_stdelim = TL_MII_STARTDELIM; 66736270Swpaul frame->mii_opcode = TL_MII_WRITEOP; 66836270Swpaul frame->mii_turnaround = TL_MII_TURNAROUND; 66936270Swpaul 67036270Swpaul /* 67136270Swpaul * Select the NETSIO register. We will be using it 67236270Swpaul * to communicate indirectly with the MII. 67336270Swpaul */ 67436270Swpaul 67536270Swpaul DIO_SEL(TL_NETSIO); 67636270Swpaul 67736270Swpaul /* 67836270Swpaul * Turn off MII interrupt by forcing MINTEN low. 67936270Swpaul */ 68036270Swpaul minten = DIO_BYTE1_GET(TL_SIO_MINTEN); 68136270Swpaul if (minten) { 68236270Swpaul DIO_BYTE1_CLR(TL_SIO_MINTEN); 68336270Swpaul } 68436270Swpaul 68536270Swpaul /* 68636270Swpaul * Turn on data output. 68736270Swpaul */ 68836270Swpaul DIO_BYTE1_SET(TL_SIO_MTXEN); 68936270Swpaul 69036270Swpaul tl_mii_send(csr, frame->mii_stdelim, 2); 69136270Swpaul tl_mii_send(csr, frame->mii_opcode, 2); 69236270Swpaul tl_mii_send(csr, frame->mii_phyaddr, 5); 69336270Swpaul tl_mii_send(csr, frame->mii_regaddr, 5); 69436270Swpaul tl_mii_send(csr, frame->mii_turnaround, 2); 69536270Swpaul tl_mii_send(csr, frame->mii_data, 16); 69636270Swpaul 69736270Swpaul DIO_BYTE1_SET(TL_SIO_MCLK); 69836270Swpaul DIO_BYTE1_CLR(TL_SIO_MCLK); 69936270Swpaul 70036270Swpaul /* 70136270Swpaul * Turn off xmit. 70236270Swpaul */ 70336270Swpaul DIO_BYTE1_CLR(TL_SIO_MTXEN); 70436270Swpaul 70536270Swpaul /* Reenable interrupts */ 70636270Swpaul if (minten) 70736270Swpaul DIO_BYTE1_SET(TL_SIO_MINTEN); 70836270Swpaul 70936270Swpaul splx(s); 71036270Swpaul 71136270Swpaul return(0); 71236270Swpaul} 71336270Swpaul 71436270Swpaulstatic u_int16_t tl_phy_readreg(sc, reg) 71536270Swpaul struct tl_softc *sc; 71636270Swpaul int reg; 71736270Swpaul{ 71836270Swpaul struct tl_mii_frame frame; 71936270Swpaul struct tl_csr *csr; 72036270Swpaul 72136270Swpaul bzero((char *)&frame, sizeof(frame)); 72236270Swpaul 72336270Swpaul csr = sc->csr; 72436270Swpaul 72536270Swpaul frame.mii_phyaddr = sc->tl_phy_addr; 72636270Swpaul frame.mii_regaddr = reg; 72736270Swpaul tl_mii_readreg(sc->csr, &frame); 72836270Swpaul 72936270Swpaul /* Reenable MII interrupts, just in case. */ 73036270Swpaul DIO_SEL(TL_NETSIO); 73136270Swpaul DIO_BYTE1_SET(TL_SIO_MINTEN); 73236270Swpaul 73336270Swpaul return(frame.mii_data); 73436270Swpaul} 73536270Swpaul 73636270Swpaulstatic void tl_phy_writereg(sc, reg, data) 73736270Swpaul struct tl_softc *sc; 73836270Swpaul u_int16_t reg; 73936270Swpaul u_int16_t data; 74036270Swpaul{ 74136270Swpaul struct tl_mii_frame frame; 74236270Swpaul struct tl_csr *csr; 74336270Swpaul 74436270Swpaul bzero((char *)&frame, sizeof(frame)); 74536270Swpaul 74636270Swpaul csr = sc->csr; 74736270Swpaul frame.mii_phyaddr = sc->tl_phy_addr; 74836270Swpaul frame.mii_regaddr = reg; 74936270Swpaul frame.mii_data = data; 75036270Swpaul 75136270Swpaul tl_mii_writereg(sc->csr, &frame); 75236270Swpaul 75336270Swpaul /* Reenable MII interrupts, just in case. */ 75436270Swpaul DIO_SEL(TL_NETSIO); 75536270Swpaul DIO_BYTE1_SET(TL_SIO_MINTEN); 75636270Swpaul 75736270Swpaul return; 75836270Swpaul} 75936270Swpaul 76036270Swpaul/* 76136270Swpaul * Read a sequence of bytes from the EEPROM. 76236270Swpaul */ 76336270Swpaulstatic int tl_read_eeprom(csr, dest, off, cnt) 76436270Swpaul struct tl_csr *csr; 76536270Swpaul caddr_t dest; 76636270Swpaul int off; 76736270Swpaul int cnt; 76836270Swpaul{ 76936270Swpaul int err = 0, i; 77036270Swpaul u_int8_t byte = 0; 77136270Swpaul 77236270Swpaul for (i = 0; i < cnt; i++) { 77336270Swpaul err = tl_eeprom_getbyte(csr, off + i, &byte); 77436270Swpaul if (err) 77536270Swpaul break; 77636270Swpaul *(dest + i) = byte; 77736270Swpaul } 77836270Swpaul 77936270Swpaul return(err ? 1 : 0); 78036270Swpaul} 78136270Swpaul 78236270Swpaul/* 78336270Swpaul * Initiate autonegotiation with a link partner. 78436270Swpaul * 78536270Swpaul * Note that the Texas Instruments ThunderLAN programmer's guide 78636270Swpaul * fails to mention one very important point about autonegotiation. 78736270Swpaul * Autonegotiation is done largely by the PHY, independent of the 78836270Swpaul * ThunderLAN chip itself: the PHY sets the flags in the BMCR 78936270Swpaul * register to indicate what modes were selected and if link status 79036270Swpaul * is good. In fact, the PHY does pretty much all of the work itself, 79136270Swpaul * except for one small detail. 79236270Swpaul * 79336270Swpaul * The PHY may negotiate a full-duplex of half-duplex link, and set 79436270Swpaul * the PHY_BMCR_DUPLEX bit accordingly, but the ThunderLAN's 'NetCommand' 79536270Swpaul * register _also_ has a half-duplex/full-duplex bit, and you MUST ALSO 79636270Swpaul * SET THIS BIT MANUALLY TO CORRESPOND TO THE MODE SELECTED FOR THE PHY! 79736270Swpaul * In other words, both the ThunderLAN chip and the PHY have to be 79836270Swpaul * programmed for full-duplex mode in order for full-duplex to actually 79936270Swpaul * work. So in order for autonegotiation to really work right, we have 80036270Swpaul * to wait for the link to come up, check the BMCR register, then set 80136270Swpaul * the ThunderLAN for full or half-duplex as needed. 80236270Swpaul * 80336270Swpaul * I struggled for two days to figure this out, so I'm making a point 80436270Swpaul * of drawing attention to this fact. I think it's very strange that 80536270Swpaul * the ThunderLAN doesn't automagically track the duplex state of the 80636270Swpaul * PHY, but there you have it. 80736270Swpaul * 80836270Swpaul * Also when, using a National Semiconductor DP83840A PHY, we have to 80936270Swpaul * allow a full three seconds for autonegotiation to complete. So what 81036270Swpaul * we do is flip the autonegotiation restart bit, then set a timeout 81136270Swpaul * to wake us up in three seconds to check the link state. 81236270Swpaul */ 81336270Swpaulstatic void tl_autoneg(sc, flag, verbose) 81436270Swpaul struct tl_softc *sc; 81536270Swpaul int flag; 81636270Swpaul int verbose; 81736270Swpaul{ 81836270Swpaul u_int16_t phy_sts = 0, media = 0; 81936270Swpaul struct ifnet *ifp; 82036270Swpaul struct ifmedia *ifm; 82136270Swpaul struct tl_csr *csr; 82236270Swpaul 82336270Swpaul ifm = &sc->ifmedia; 82436270Swpaul ifp = &sc->arpcom.ac_if; 82536270Swpaul csr = sc->csr; 82636270Swpaul 82736270Swpaul /* 82836270Swpaul * First, see if autoneg is supported. If not, there's 82936270Swpaul * no point in continuing. 83036270Swpaul */ 83136270Swpaul phy_sts = tl_phy_readreg(sc, PHY_BMSR); 83236270Swpaul if (!(phy_sts & PHY_BMSR_CANAUTONEG)) { 83336270Swpaul if (verbose) 83436270Swpaul printf("tl%d: autonegotiation not supported\n", 83536270Swpaul sc->tl_unit); 83636270Swpaul return; 83736270Swpaul } 83836270Swpaul 83936270Swpaul switch (flag) { 84036270Swpaul case TL_FLAG_FORCEDELAY: 84136270Swpaul /* 84236270Swpaul * XXX Never use this option anywhere but in the probe 84336270Swpaul * routine: making the kernel stop dead in its tracks 84436270Swpaul * for three whole seconds after we've gone multi-user 84536270Swpaul * is really bad manners. 84636270Swpaul */ 84736270Swpaul phy_sts = tl_phy_readreg(sc, PHY_BMCR); 84836270Swpaul phy_sts |= PHY_BMCR_AUTONEGENBL|PHY_BMCR_AUTONEGRSTR; 84936270Swpaul tl_phy_writereg(sc, PHY_BMCR, phy_sts); 85036270Swpaul DELAY(3000000); 85136270Swpaul break; 85236270Swpaul case TL_FLAG_SCHEDDELAY: 85336270Swpaul phy_sts = tl_phy_readreg(sc, PHY_BMCR); 85436270Swpaul phy_sts |= PHY_BMCR_AUTONEGENBL|PHY_BMCR_AUTONEGRSTR; 85536270Swpaul tl_phy_writereg(sc, PHY_BMCR, phy_sts); 85636270Swpaul ifp->if_timer = 3; 85736270Swpaul sc->tl_autoneg = 1; 85836270Swpaul return; 85936270Swpaul case TL_FLAG_DELAYTIMEO: 86036270Swpaul ifp->if_timer = 0; 86136270Swpaul sc->tl_autoneg = 0; 86236270Swpaul break; 86336270Swpaul default: 86436270Swpaul printf("tl%d: invalid autoneg flag: %d\n", flag, sc->tl_unit); 86536270Swpaul return; 86636270Swpaul } 86736270Swpaul 86836270Swpaul /* 86936270Swpaul * Read the BMSR register twice: the LINKSTAT bit is a 87036270Swpaul * latching bit. 87136270Swpaul */ 87236270Swpaul tl_phy_readreg(sc, PHY_BMSR); 87336270Swpaul phy_sts = tl_phy_readreg(sc, PHY_BMSR); 87436270Swpaul if (phy_sts & PHY_BMSR_AUTONEGCOMP) { 87536270Swpaul if (verbose) 87636270Swpaul printf("tl%d: autoneg complete, ", sc->tl_unit); 87736270Swpaul phy_sts = tl_phy_readreg(sc, PHY_BMSR); 87836270Swpaul } else { 87936270Swpaul if (verbose) 88036270Swpaul printf("tl%d: autoneg not complete, ", sc->tl_unit); 88136270Swpaul } 88236270Swpaul 88336270Swpaul /* Link is good. Report modes and set duplex mode. */ 88436270Swpaul if (phy_sts & PHY_BMSR_LINKSTAT) { 88536270Swpaul if (verbose) 88636270Swpaul printf("link status good "); 88736270Swpaul media = tl_phy_readreg(sc, PHY_BMCR); 88836270Swpaul 88936270Swpaul /* Set the DUPLEX bit in the NetCmd register accordingly. */ 89036270Swpaul if (media & PHY_BMCR_DUPLEX) { 89136270Swpaul if (verbose) 89236270Swpaul printf("(full-duplex, "); 89336270Swpaul ifm->ifm_media |= IFM_FDX; 89436270Swpaul ifm->ifm_media &= ~IFM_HDX; 89536270Swpaul DIO_SEL(TL_NETCMD); 89636270Swpaul DIO_BYTE0_SET(TL_CMD_DUPLEX); 89736270Swpaul } else { 89836270Swpaul if (verbose) 89936270Swpaul printf("(half-duplex, "); 90036270Swpaul ifm->ifm_media &= ~IFM_FDX; 90136270Swpaul ifm->ifm_media |= IFM_HDX; 90236270Swpaul DIO_SEL(TL_NETCMD); 90336270Swpaul DIO_BYTE0_CLR(TL_CMD_DUPLEX); 90436270Swpaul } 90536270Swpaul 90636270Swpaul if (media & PHY_BMCR_SPEEDSEL) { 90736270Swpaul if (verbose) 90836270Swpaul printf("100Mb/s)\n"); 90936270Swpaul ifm->ifm_media |= IFM_100_TX; 91036270Swpaul ifm->ifm_media &= ~IFM_10_T; 91136270Swpaul } else { 91236270Swpaul if (verbose) 91336270Swpaul printf("10Mb/s)\n"); 91436270Swpaul ifm->ifm_media &= ~IFM_100_TX; 91536270Swpaul ifm->ifm_media |= IFM_10_T; 91636270Swpaul } 91736270Swpaul 91836270Swpaul /* Turn off autoneg */ 91936270Swpaul media &= ~PHY_BMCR_AUTONEGENBL; 92036270Swpaul tl_phy_writereg(sc, PHY_BMCR, media); 92136270Swpaul } else { 92236270Swpaul if (verbose) 92336270Swpaul printf("no carrier\n"); 92436270Swpaul } 92536270Swpaul 92636270Swpaul return; 92736270Swpaul} 92836270Swpaul 92936270Swpaul/* 93036270Swpaul * Set speed and duplex mode. Also program autoneg advertisements 93136270Swpaul * accordingly. 93236270Swpaul */ 93336270Swpaulstatic void tl_setmode(sc, media) 93436270Swpaul struct tl_softc *sc; 93536270Swpaul int media; 93636270Swpaul{ 93736270Swpaul u_int16_t bmcr, anar, ctl; 93836270Swpaul struct tl_csr *csr; 93936270Swpaul 94036270Swpaul csr = sc->csr; 94136270Swpaul bmcr = tl_phy_readreg(sc, PHY_BMCR); 94236270Swpaul anar = tl_phy_readreg(sc, PHY_ANAR); 94336270Swpaul ctl = tl_phy_readreg(sc, TL_PHY_CTL); 94436270Swpaul DIO_SEL(TL_NETCMD); 94536270Swpaul 94636270Swpaul bmcr &= ~(PHY_BMCR_SPEEDSEL|PHY_BMCR_DUPLEX|PHY_BMCR_AUTONEGENBL| 94736270Swpaul PHY_BMCR_LOOPBK); 94836270Swpaul anar &= ~(PHY_ANAR_100BT4|PHY_ANAR_100BTXFULL|PHY_ANAR_100BTXHALF| 94936270Swpaul PHY_ANAR_10BTFULL|PHY_ANAR_10BTHALF); 95036270Swpaul 95136270Swpaul ctl &= ~PHY_CTL_AUISEL; 95236270Swpaul 95336270Swpaul if (IFM_SUBTYPE(media) == IFM_LOOP) 95436270Swpaul bmcr |= PHY_BMCR_LOOPBK; 95536270Swpaul 95636270Swpaul if (IFM_SUBTYPE(media) == IFM_AUTO) 95736270Swpaul bmcr |= PHY_BMCR_AUTONEGENBL; 95836270Swpaul 95936270Swpaul if (IFM_SUBTYPE(media) == IFM_10_5) 96036270Swpaul ctl |= PHY_CTL_AUISEL; 96136270Swpaul 96236270Swpaul if (IFM_SUBTYPE(media) == IFM_100_TX) { 96336270Swpaul bmcr |= PHY_BMCR_SPEEDSEL; 96436270Swpaul if ((media & IFM_GMASK) == IFM_FDX) { 96536270Swpaul bmcr |= PHY_BMCR_DUPLEX; 96636270Swpaul anar |= PHY_ANAR_100BTXFULL; 96736270Swpaul DIO_BYTE0_SET(TL_CMD_DUPLEX); 96836270Swpaul } else if ((media & IFM_GMASK) == IFM_HDX) { 96936270Swpaul bmcr &= ~PHY_BMCR_DUPLEX; 97036270Swpaul anar |= PHY_ANAR_100BTXHALF; 97136270Swpaul DIO_BYTE0_CLR(TL_CMD_DUPLEX); 97236270Swpaul } else { 97336270Swpaul bmcr &= ~PHY_BMCR_DUPLEX; 97436270Swpaul anar |= PHY_ANAR_100BTXHALF; 97536270Swpaul DIO_BYTE0_CLR(TL_CMD_DUPLEX); 97636270Swpaul } 97736270Swpaul } 97836270Swpaul 97936270Swpaul if (IFM_SUBTYPE(media) == IFM_10_T) { 98036270Swpaul bmcr &= ~PHY_BMCR_SPEEDSEL; 98136270Swpaul if ((media & IFM_GMASK) == IFM_FDX) { 98236270Swpaul bmcr |= PHY_BMCR_DUPLEX; 98336270Swpaul anar |= PHY_ANAR_10BTFULL; 98436270Swpaul DIO_BYTE0_SET(TL_CMD_DUPLEX); 98536270Swpaul } else if ((media & IFM_GMASK) == IFM_HDX) { 98636270Swpaul bmcr &= ~PHY_BMCR_DUPLEX; 98736270Swpaul anar |= PHY_ANAR_10BTHALF; 98836270Swpaul DIO_BYTE0_CLR(TL_CMD_DUPLEX); 98936270Swpaul } else { 99036270Swpaul bmcr &= ~PHY_BMCR_DUPLEX; 99136270Swpaul anar |= PHY_ANAR_10BTHALF; 99236270Swpaul DIO_BYTE0_CLR(TL_CMD_DUPLEX); 99336270Swpaul } 99436270Swpaul } 99536270Swpaul 99636270Swpaul tl_phy_writereg(sc, PHY_BMCR, bmcr); 99736270Swpaul tl_phy_writereg(sc, PHY_ANAR, anar); 99836270Swpaul tl_phy_writereg(sc, TL_PHY_CTL, ctl); 99936270Swpaul 100036270Swpaul return; 100136270Swpaul} 100236270Swpaul 100336270Swpaul#define XOR(a, b) ((a && !b) || (!a && b)) 100436270Swpaul#define DA(addr, offset) (addr[offset / 8] & (1 << (offset % 8))) 100536270Swpaul 100636270Swpaulstatic int tl_calchash(addr) 100736270Swpaul char *addr; 100836270Swpaul{ 100936270Swpaul int h; 101036270Swpaul 101136270Swpaul h = XOR(DA(addr, 0), XOR(DA(addr, 6), XOR(DA(addr, 12), 101236270Swpaul XOR(DA(addr, 18), XOR(DA(addr, 24), XOR(DA(addr, 30), 101336270Swpaul XOR(DA(addr, 36), DA(addr, 42)))))))); 101436270Swpaul 101536270Swpaul h |= XOR(DA(addr, 1), XOR(DA(addr, 7), XOR(DA(addr, 13), 101636270Swpaul XOR(DA(addr, 19), XOR(DA(addr, 25), XOR(DA(addr, 31), 101736270Swpaul XOR(DA(addr, 37), DA(addr, 43)))))))) << 1; 101836270Swpaul 101936270Swpaul h |= XOR(DA(addr, 2), XOR(DA(addr, 8), XOR(DA(addr, 14), 102036270Swpaul XOR(DA(addr, 20), XOR(DA(addr, 26), XOR(DA(addr, 32), 102136270Swpaul XOR(DA(addr, 38), DA(addr, 44)))))))) << 2; 102236270Swpaul 102336270Swpaul h |= XOR(DA(addr, 3), XOR(DA(addr, 9), XOR(DA(addr, 15), 102436270Swpaul XOR(DA(addr, 21), XOR(DA(addr, 27), XOR(DA(addr, 33), 102536270Swpaul XOR(DA(addr, 39), DA(addr, 45)))))))) << 3; 102636270Swpaul 102736270Swpaul h |= XOR(DA(addr, 4), XOR(DA(addr, 10), XOR(DA(addr, 16), 102836270Swpaul XOR(DA(addr, 22), XOR(DA(addr, 28), XOR(DA(addr, 34), 102936270Swpaul XOR(DA(addr, 40), DA(addr, 46)))))))) << 4; 103036270Swpaul 103136270Swpaul h |= XOR(DA(addr, 5), XOR(DA(addr, 11), XOR(DA(addr, 17), 103236270Swpaul XOR(DA(addr, 23), XOR(DA(addr, 29), XOR(DA(addr, 35), 103336270Swpaul XOR(DA(addr, 41), DA(addr, 47)))))))) << 5; 103436270Swpaul 103536270Swpaul return(h); 103636270Swpaul} 103736270Swpaul 103836270Swpaulstatic void tl_setmulti(sc) 103936270Swpaul struct tl_softc *sc; 104036270Swpaul{ 104136270Swpaul struct ifnet *ifp; 104236270Swpaul struct tl_csr *csr; 104336270Swpaul u_int32_t hashes[2] = { 0, 0 }; 104436270Swpaul int h; 104536270Swpaul#if __FreeBSD_version >= 300000 104636270Swpaul struct ifmultiaddr *ifma; 104736270Swpaul#else 104836270Swpaul struct ether_multi *enm; 104936270Swpaul struct ether_multistep step; 105036270Swpaul#endif 105136270Swpaul 105236270Swpaul csr = sc->csr; 105336270Swpaul ifp = &sc->arpcom.ac_if; 105436270Swpaul 105536270Swpaul if (sc->arpcom.ac_multicnt > 64 || ifp->if_flags & IFF_ALLMULTI) { 105636270Swpaul hashes[0] = 0xFFFFFFFF; 105736270Swpaul hashes[1] = 0xFFFFFFFF; 105836270Swpaul } else { 105936270Swpaul#if __FreeBSD_version >= 300000 106036270Swpaul for (ifma = ifp->if_multiaddrs.lh_first; ifma != NULL; 106136270Swpaul ifma = ifma->ifma_link.le_next) { 106236270Swpaul if (ifma->ifma_addr->sa_family != AF_LINK) 106336270Swpaul continue; 106436270Swpaul h = tl_calchash( 106536270Swpaul LLADDR((struct sockaddr_dl *)ifma->ifma_addr)); 106636270Swpaul if (h < 32) 106736270Swpaul hashes[0] |= (1 << h); 106836270Swpaul else 106936270Swpaul hashes[1] |= (1 << (h - 31)); 107036270Swpaul } 107136270Swpaul#else 107236270Swpaul ETHER_FIRST_MULTI(step, &sc->arpcom, enm); 107336270Swpaul while(enm != NULL) { 107436270Swpaul if (bcmp(enm->enm_addrlo, enm->enm_addrhi, 107536270Swpaul ETHER_ADDR_LEN)) { 107636270Swpaul hashes[0] = 0xFFFFFFFF; 107736270Swpaul hashes[1] = 0xFFFFFFFF; 107836270Swpaul break; 107936270Swpaul } else { 108036270Swpaul h = tl_calchash(enm->enm_addrlo); 108136270Swpaul if (h < 32) 108236270Swpaul hashes[0] |= (1 << h); 108336270Swpaul else 108436270Swpaul hashes[1] |= (1 << (h - 31)); 108536270Swpaul } 108636270Swpaul ETHER_NEXT_MULTI(step, enm); 108736270Swpaul } 108836270Swpaul#endif 108936270Swpaul } 109036270Swpaul 109136270Swpaul DIO_SEL(TL_HASH1); 109236270Swpaul DIO_LONG_PUT(hashes[0]); 109336270Swpaul DIO_SEL(TL_HASH2); 109436270Swpaul DIO_LONG_PUT(hashes[1]); 109536270Swpaul 109636270Swpaul return; 109736270Swpaul} 109836270Swpaul 109936270Swpaulstatic void tl_softreset(csr, internal) 110036270Swpaul struct tl_csr *csr; 110136270Swpaul int internal; 110236270Swpaul{ 110336270Swpaul u_int32_t cmd, dummy; 110436270Swpaul 110536270Swpaul /* Assert the adapter reset bit. */ 110636270Swpaul csr->tl_host_cmd |= TL_CMD_ADRST; 110736270Swpaul /* Turn off interrupts */ 110836270Swpaul csr->tl_host_cmd |= TL_CMD_INTSOFF; 110936270Swpaul 111036270Swpaul /* First, clear the stats registers. */ 111136270Swpaul DIO_SEL(TL_TXGOODFRAMES|TL_DIO_ADDR_INC); 111236270Swpaul DIO_LONG_GET(dummy); 111336270Swpaul DIO_LONG_GET(dummy); 111436270Swpaul DIO_LONG_GET(dummy); 111536270Swpaul DIO_LONG_GET(dummy); 111636270Swpaul DIO_LONG_GET(dummy); 111736270Swpaul 111836270Swpaul /* Clear Areg and Hash registers */ 111936270Swpaul DIO_SEL(TL_AREG0_B5|TL_DIO_ADDR_INC); 112036270Swpaul DIO_LONG_PUT(0x00000000); 112136270Swpaul DIO_LONG_PUT(0x00000000); 112236270Swpaul DIO_LONG_PUT(0x00000000); 112336270Swpaul DIO_LONG_PUT(0x00000000); 112436270Swpaul DIO_LONG_PUT(0x00000000); 112536270Swpaul DIO_LONG_PUT(0x00000000); 112636270Swpaul DIO_LONG_PUT(0x00000000); 112736270Swpaul DIO_LONG_PUT(0x00000000); 112836270Swpaul 112936270Swpaul /* 113036270Swpaul * Set up Netconfig register. Enable one channel and 113136270Swpaul * one fragment mode. 113236270Swpaul */ 113336270Swpaul DIO_SEL(TL_NETCONFIG); 113436270Swpaul DIO_WORD0_SET(TL_CFG_ONECHAN|TL_CFG_ONEFRAG); 113536270Swpaul if (internal) { 113636270Swpaul DIO_SEL(TL_NETCONFIG); 113736270Swpaul DIO_WORD0_SET(TL_CFG_PHYEN); 113836270Swpaul } else { 113936270Swpaul DIO_SEL(TL_NETCONFIG); 114036270Swpaul DIO_WORD0_CLR(TL_CFG_PHYEN); 114136270Swpaul } 114236270Swpaul 114336270Swpaul /* Set PCI burst size */ 114436270Swpaul DIO_SEL(TL_BSIZEREG); 114536270Swpaul DIO_BYTE1_SET(0x33); 114636270Swpaul 114736270Swpaul /* 114836270Swpaul * Load adapter irq pacing timer and tx threshold. 114936270Swpaul * We make the transmit threshold 1 initially but we may 115036270Swpaul * change that later. 115136270Swpaul */ 115236270Swpaul cmd = csr->tl_host_cmd; 115336270Swpaul cmd |= TL_CMD_NES; 115436270Swpaul cmd &= ~(TL_CMD_RT|TL_CMD_EOC|TL_CMD_ACK_MASK|TL_CMD_CHSEL_MASK); 115536270Swpaul csr->tl_host_cmd = cmd | (TL_CMD_LDTHR | TX_THR); 115636270Swpaul csr->tl_host_cmd = cmd | (TL_CMD_LDTMR | 0x00000003); 115736270Swpaul 115836270Swpaul /* Unreset the MII */ 115936270Swpaul DIO_SEL(TL_NETSIO); 116036270Swpaul DIO_BYTE1_SET(TL_SIO_NMRST); 116136270Swpaul 116236270Swpaul /* Clear status register */ 116336270Swpaul DIO_SEL(TL_NETSTS); 116436270Swpaul DIO_BYTE2_SET(TL_STS_MIRQ); 116536270Swpaul DIO_BYTE2_SET(TL_STS_HBEAT); 116636270Swpaul DIO_BYTE2_SET(TL_STS_TXSTOP); 116736270Swpaul DIO_BYTE2_SET(TL_STS_RXSTOP); 116836270Swpaul 116936270Swpaul /* Enable network status interrupts for everything. */ 117036270Swpaul DIO_SEL(TL_NETMASK); 117136270Swpaul DIO_BYTE3_SET(TL_MASK_MASK7|TL_MASK_MASK6| 117236270Swpaul TL_MASK_MASK5|TL_MASK_MASK4); 117336270Swpaul 117436270Swpaul /* Take the adapter out of reset */ 117536270Swpaul DIO_SEL(TL_NETCMD); 117636270Swpaul DIO_BYTE0_SET(TL_CMD_NRESET|TL_CMD_NWRAP); 117736270Swpaul 117836270Swpaul /* Wait for things to settle down a little. */ 117936270Swpaul DELAY(500); 118036270Swpaul 118136270Swpaul return; 118236270Swpaul} 118336270Swpaul 118436270Swpaul/* 118536270Swpaul * Probe for a ThunderLAN chip. Check the PCI vendor and device IDs 118636270Swpaul * against our list and return its name if we find a match. Note that 118736270Swpaul * we also save a pointer to the tl_type struct for this card since we 118836270Swpaul * will need it for the softc struct and attach routine later. 118936270Swpaul */ 119036270Swpaulstatic char * 119136270Swpaultl_probe(config_id, device_id) 119236270Swpaul pcici_t config_id; 119336270Swpaul pcidi_t device_id; 119436270Swpaul{ 119536270Swpaul struct tl_type *t; 119636270Swpaul struct tl_iflist *new; 119736270Swpaul 119836270Swpaul t = tl_devs; 119936270Swpaul 120036270Swpaul while(t->tl_name != NULL) { 120136270Swpaul if ((device_id & 0xFFFF) == t->tl_vid && 120236270Swpaul ((device_id >> 16) & 0xFFFF) == t->tl_did) { 120336270Swpaul new = malloc(sizeof(struct tl_iflist), 120436270Swpaul M_DEVBUF, M_NOWAIT); 120536270Swpaul if (new == NULL) { 120636270Swpaul printf("no memory for controller struct!\n"); 120736270Swpaul break; 120836270Swpaul } 120936270Swpaul bzero(new, sizeof(struct tl_iflist)); 121036270Swpaul new->tl_config_id = config_id; 121136270Swpaul new->tl_dinfo = t; 121236270Swpaul new->tl_next = tl_iflist; 121336270Swpaul tl_iflist = new; 121436270Swpaul return(t->tl_name); 121536270Swpaul } 121636270Swpaul t++; 121736270Swpaul } 121836270Swpaul 121936270Swpaul return(NULL); 122036270Swpaul} 122136270Swpaul 122236270Swpaul/* 122336270Swpaul * The ThunderLAN controller can support multiple PHYs. Logically, 122436270Swpaul * this means we have to be able to deal with each PHY as a separate 122536270Swpaul * interface. We therefore consider ThunderLAN devices as follows: 122636270Swpaul * 122736270Swpaul * o Each ThunderLAN controller device is assigned the name tlcX where 122836270Swpaul * X is the controller's unit number. Each ThunderLAN device found 122936270Swpaul * is assigned a different number. 123036270Swpaul * 123136270Swpaul * o Each PHY on each controller is assigned the name tlX. X starts at 123236270Swpaul * 0 and is incremented each time an additional PHY is found. 123336270Swpaul * 123436270Swpaul * So, if you had two dual-channel ThunderLAN cards, you'd have 123536270Swpaul * tlc0 and tlc1 (the controllers) and tl0, tl1, tl2, tl3 (the logical 123636270Swpaul * interfaces). I think. I'm still not sure how dual chanel controllers 123736270Swpaul * work as I've yet to see one. 123836270Swpaul */ 123936270Swpaul 124036270Swpaul/* 124136270Swpaul * Do the interface setup and attach for a PHY on a particular 124236270Swpaul * ThunderLAN chip. Also also set up interrupt vectors. 124336270Swpaul */ 124436270Swpaulstatic int tl_attach_phy(csr, tl_unit, eaddr, tl_phy, ilist) 124536270Swpaul struct tl_csr *csr; 124636270Swpaul int tl_unit; 124736270Swpaul char *eaddr; 124836270Swpaul int tl_phy; 124936270Swpaul struct tl_iflist *ilist; 125036270Swpaul{ 125136270Swpaul struct tl_softc *sc; 125236270Swpaul struct ifnet *ifp; 125336270Swpaul int phy_ctl; 125436270Swpaul struct tl_type *p = tl_phys; 125536270Swpaul struct tl_mii_frame frame; 125636270Swpaul int i, media = IFM_ETHER|IFM_100_TX|IFM_FDX; 125736270Swpaul unsigned int round; 125836270Swpaul caddr_t roundptr; 125936270Swpaul 126036270Swpaul if (tl_phy != TL_PHYADDR_MAX) 126136270Swpaul tl_softreset(csr, 0); 126236270Swpaul 126336270Swpaul /* Reset the PHY again, just in case. */ 126436270Swpaul bzero((char *)&frame, sizeof(frame)); 126536270Swpaul frame.mii_phyaddr = tl_phy; 126636270Swpaul frame.mii_regaddr = TL_PHY_GENCTL; 126736270Swpaul frame.mii_data = PHY_BMCR_RESET; 126836270Swpaul tl_mii_writereg(csr, &frame); 126936270Swpaul DELAY(500); 127036270Swpaul frame.mii_data = 0; 127136270Swpaul 127236270Swpaul /* First, allocate memory for the softc struct. */ 127336270Swpaul sc = malloc(sizeof(struct tl_softc), M_DEVBUF, M_NOWAIT); 127436270Swpaul if (sc == NULL) { 127536270Swpaul printf("tlc%d: no memory for softc struct!\n", ilist->tlc_unit); 127636270Swpaul return(1); 127736270Swpaul } 127836270Swpaul 127936270Swpaul bzero(sc, sizeof(struct tl_softc)); 128036270Swpaul 128136270Swpaul /* 128236270Swpaul * Now allocate memory for the TX and RX lists. Note that 128336270Swpaul * we actually allocate 8 bytes more than we really need: 128436270Swpaul * this is because we need to adjust the final address to 128536270Swpaul * be aligned on a quadword (64-bit) boundary in order to 128636270Swpaul * make the chip happy. If the list structures aren't properly 128736270Swpaul * aligned, DMA fails and the chip generates an adapter check 128836270Swpaul * interrupt and has to be reset. If you set up the softc struct 128936270Swpaul * just right you can sort of obtain proper alignment 'by chance.' 129036270Swpaul * But I don't want to depend on this, so instead the alignment 129136270Swpaul * is forced here. 129236270Swpaul */ 129336270Swpaul sc->tl_ldata_ptr = malloc(sizeof(struct tl_list_data) + 8, 129436270Swpaul M_DEVBUF, M_NOWAIT); 129536270Swpaul 129636270Swpaul if (sc->tl_ldata_ptr == NULL) { 129736270Swpaul free(sc, M_DEVBUF); 129836270Swpaul printf("tlc%d: no memory for list buffers!\n", ilist->tlc_unit); 129936270Swpaul return(1); 130036270Swpaul } 130136270Swpaul 130236270Swpaul /* 130336270Swpaul * Convoluted but satisfies my ANSI sensibilities. GCC lets 130436270Swpaul * you do casts on the LHS of an assignment, but ANSI doesn't 130536270Swpaul * allow that. 130636270Swpaul */ 130736270Swpaul sc->tl_ldata = (struct tl_list_data *)sc->tl_ldata_ptr; 130836270Swpaul round = (unsigned int)sc->tl_ldata_ptr & 0xF; 130936270Swpaul roundptr = sc->tl_ldata_ptr; 131036270Swpaul for (i = 0; i < 8; i++) { 131136270Swpaul if (round % 8) { 131236270Swpaul round++; 131336270Swpaul roundptr++; 131436270Swpaul } else 131536270Swpaul break; 131636270Swpaul } 131736270Swpaul sc->tl_ldata = (struct tl_list_data *)roundptr; 131836270Swpaul 131936270Swpaul bzero(sc->tl_ldata, sizeof(struct tl_list_data)); 132036270Swpaul 132136270Swpaul sc->csr = csr; 132236270Swpaul sc->tl_dinfo = ilist->tl_dinfo; 132336270Swpaul sc->tl_ctlr = ilist->tlc_unit; 132436270Swpaul sc->tl_unit = tl_unit; 132536270Swpaul sc->tl_phy_addr = tl_phy; 132636270Swpaul sc->tl_iflist = ilist; 132736270Swpaul#if __FreeBSD_version >= 300000 132836270Swpaul callout_handle_init(&sc->tl_stat_ch); 132936270Swpaul#endif 133036270Swpaul 133136270Swpaul frame.mii_regaddr = TL_PHY_VENID; 133236270Swpaul tl_mii_readreg(csr, &frame); 133336270Swpaul sc->tl_phy_vid = frame.mii_data; 133436270Swpaul 133536270Swpaul frame.mii_regaddr = TL_PHY_DEVID; 133636270Swpaul tl_mii_readreg(csr, &frame); 133736270Swpaul sc->tl_phy_did = frame.mii_data; 133836270Swpaul 133936270Swpaul frame.mii_regaddr = TL_PHY_GENSTS; 134036270Swpaul tl_mii_readreg(csr, &frame); 134136270Swpaul sc->tl_phy_sts = frame.mii_data; 134236270Swpaul 134336270Swpaul frame.mii_regaddr = TL_PHY_GENCTL; 134436270Swpaul tl_mii_readreg(csr, &frame); 134536270Swpaul phy_ctl = frame.mii_data; 134636270Swpaul 134736270Swpaul /* 134836270Swpaul * PHY revision numbers tend to vary a bit. Our algorithm here 134936270Swpaul * is to check everything but the 8 least significant bits. 135036270Swpaul */ 135136270Swpaul while(p->tl_vid) { 135236270Swpaul if (sc->tl_phy_vid == p->tl_vid && 135336270Swpaul (sc->tl_phy_did | 0x000F) == p->tl_did) { 135436270Swpaul sc->tl_pinfo = p; 135536270Swpaul break; 135636270Swpaul } 135736270Swpaul p++; 135836270Swpaul } 135936270Swpaul if (sc->tl_pinfo == NULL) { 136036270Swpaul sc->tl_pinfo = &tl_phys[PHY_UNKNOWN]; 136136270Swpaul } 136236270Swpaul 136336270Swpaul bcopy(eaddr, (char *)&sc->arpcom.ac_enaddr, ETHER_ADDR_LEN); 136436270Swpaul ifp = &sc->arpcom.ac_if; 136536270Swpaul ifp->if_softc = sc; 136636270Swpaul ifp->if_unit = tl_unit; 136736270Swpaul ifp->if_name = "tl"; 136836270Swpaul ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 136936270Swpaul ifp->if_ioctl = tl_ioctl; 137036270Swpaul ifp->if_output = ether_output; 137136270Swpaul ifp->if_start = tl_start; 137236270Swpaul ifp->if_watchdog = tl_watchdog; 137336270Swpaul ifp->if_init = tl_init; 137436270Swpaul 137536270Swpaul if (sc->tl_phy_sts & PHY_BMSR_100BT4 || 137636270Swpaul sc->tl_phy_sts & PHY_BMSR_100BTXFULL || 137736270Swpaul sc->tl_phy_sts & PHY_BMSR_100BTXHALF) 137836270Swpaul ifp->if_baudrate = 100000000; 137936270Swpaul else 138036270Swpaul ifp->if_baudrate = 10000000; 138136270Swpaul 138236270Swpaul ilist->tl_sc[tl_phy] = sc; 138336270Swpaul 138436270Swpaul printf("tl%d at tlc%d physical interface %d\n", ifp->if_unit, 138536270Swpaul sc->tl_ctlr, 138636270Swpaul sc->tl_phy_addr); 138736270Swpaul 138836270Swpaul printf("tl%d: %s ", ifp->if_unit, sc->tl_pinfo->tl_name); 138936270Swpaul 139036270Swpaul if (sc->tl_phy_sts & PHY_BMSR_100BT4 || 139136270Swpaul sc->tl_phy_sts & PHY_BMSR_100BTXHALF || 139236270Swpaul sc->tl_phy_sts & PHY_BMSR_100BTXHALF) 139336270Swpaul printf("10/100Mbps "); 139436270Swpaul else { 139536270Swpaul media &= ~IFM_100_TX; 139636270Swpaul media |= IFM_10_T; 139736270Swpaul printf("10Mbps "); 139836270Swpaul } 139936270Swpaul 140036270Swpaul if (sc->tl_phy_sts & PHY_BMSR_100BTXFULL || 140136270Swpaul sc->tl_phy_sts & PHY_BMSR_10BTFULL) 140236270Swpaul printf("full duplex "); 140336270Swpaul else { 140436270Swpaul printf("half duplex "); 140536270Swpaul media &= ~IFM_FDX; 140636270Swpaul } 140736270Swpaul 140836270Swpaul if (sc->tl_phy_sts & PHY_BMSR_CANAUTONEG) { 140936270Swpaul media = IFM_ETHER|IFM_AUTO; 141036270Swpaul printf("autonegotiating\n"); 141136270Swpaul } else 141236270Swpaul printf("\n"); 141336270Swpaul 141436270Swpaul /* If this isn't a known PHY, print the PHY indentifier info. */ 141536270Swpaul if (sc->tl_pinfo->tl_vid == 0) 141636270Swpaul printf("tl%d: vendor id: %04x product id: %04x\n", 141736270Swpaul sc->tl_unit, sc->tl_phy_vid, sc->tl_phy_did); 141836270Swpaul 141936270Swpaul /* Set up ifmedia data and callbacks. */ 142036270Swpaul ifmedia_init(&sc->ifmedia, 0, tl_ifmedia_upd, tl_ifmedia_sts); 142136270Swpaul 142236270Swpaul /* 142336270Swpaul * All ThunderLANs support at least 10baseT half duplex. 142436270Swpaul * They also support AUI selection if used in 10Mb/s modes. 142536270Swpaul * They all also support a loopback mode. 142636270Swpaul */ 142736270Swpaul ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_10_T|IFM_HDX, 0, NULL); 142836270Swpaul ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_10_T, 0, NULL); 142936270Swpaul ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_10_5, 0, NULL); 143036270Swpaul ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_LOOP, 0, NULL); 143136270Swpaul 143236270Swpaul /* Some ThunderLAN PHYs support autonegotiation. */ 143336270Swpaul if (sc->tl_phy_sts & PHY_BMSR_CANAUTONEG) 143436270Swpaul ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_AUTO, 0, NULL); 143536270Swpaul 143636270Swpaul /* Some support 10baseT full duplex. */ 143736270Swpaul if (sc->tl_phy_sts & PHY_BMSR_10BTFULL) 143836270Swpaul ifmedia_add(&sc->ifmedia, 143936270Swpaul IFM_ETHER|IFM_10_T|IFM_FDX, 0, NULL); 144036270Swpaul 144136270Swpaul /* Some support 100BaseTX half duplex. */ 144236270Swpaul if (sc->tl_phy_sts & PHY_BMSR_100BTXHALF) 144336270Swpaul ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_100_TX, 0, NULL); 144436270Swpaul if (sc->tl_phy_sts & PHY_BMSR_100BTXHALF) 144536270Swpaul ifmedia_add(&sc->ifmedia, 144636270Swpaul IFM_ETHER|IFM_100_TX|IFM_HDX, 0, NULL); 144736270Swpaul 144836270Swpaul /* Some support 100BaseTX full duplex. */ 144936270Swpaul if (sc->tl_phy_sts & PHY_BMSR_100BTXFULL) 145036270Swpaul ifmedia_add(&sc->ifmedia, 145136270Swpaul IFM_ETHER|IFM_100_TX|IFM_FDX, 0, NULL); 145236270Swpaul 145336270Swpaul /* Some also support 100BaseT4. */ 145436270Swpaul if (sc->tl_phy_sts & PHY_BMSR_100BT4) 145536270Swpaul ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_100_T4, 0, NULL); 145636270Swpaul 145736270Swpaul /* Set default media. */ 145836270Swpaul ifmedia_set(&sc->ifmedia, media); 145936270Swpaul 146036270Swpaul /* 146136270Swpaul * Kick off an autonegotiation session if this PHY supports it. 146236270Swpaul * This is necessary to make sure the chip's duplex mode matches 146336270Swpaul * the PHY's duplex mode. It may not: once enabled, the PHY may 146436270Swpaul * autonegotiate full-duplex mode with its link partner, but the 146536270Swpaul * ThunderLAN chip defaults to half-duplex and stays there unless 146636270Swpaul * told otherwise. 146736270Swpaul */ 146836270Swpaul if (sc->tl_phy_sts & PHY_BMSR_CANAUTONEG) 146936270Swpaul tl_autoneg(sc, TL_FLAG_FORCEDELAY, 0); 147036270Swpaul 147136270Swpaul /* 147236270Swpaul * Call MI attach routines. 147336270Swpaul */ 147436270Swpaul if_attach(ifp); 147536270Swpaul ether_ifattach(ifp); 147636270Swpaul 147736270Swpaul#if NBPFILTER > 0 147836270Swpaul bpfattach(ifp, DLT_EN10MB, sizeof(struct ether_header)); 147936270Swpaul#endif 148036270Swpaul 148136270Swpaul return(0); 148236270Swpaul} 148336270Swpaul 148436270Swpaulstatic void 148536270Swpaultl_attach_ctlr(config_id, unit) 148636270Swpaul pcici_t config_id; 148736270Swpaul int unit; 148836270Swpaul{ 148936270Swpaul int s, i, phys = 0; 149036270Swpaul vm_offset_t pbase, vbase; 149136270Swpaul struct tl_csr *csr; 149236270Swpaul char eaddr[ETHER_ADDR_LEN]; 149336270Swpaul struct tl_mii_frame frame; 149436270Swpaul u_int32_t command; 149536270Swpaul struct tl_iflist *ilist; 149636270Swpaul 149736270Swpaul s = splimp(); 149836270Swpaul 149936270Swpaul for (ilist = tl_iflist; ilist != NULL; ilist = ilist->tl_next) 150036270Swpaul#if __FreeBSD_version >= 300000 150136270Swpaul if (ilist->tl_config_id == config_id) 150236270Swpaul#else 150336270Swpaul if (sametag(ilist->tl_config_id, config_id)) 150436270Swpaul#endif 150536270Swpaul break; 150636270Swpaul 150736270Swpaul if (ilist == NULL) { 150836270Swpaul printf("couldn't match config id with controller struct\n"); 150936270Swpaul goto fail; 151036270Swpaul } 151136270Swpaul 151236270Swpaul /* 151336270Swpaul * Map control/status registers. 151436270Swpaul */ 151536270Swpaul#if __FreeBSD_version >= 300000 151636270Swpaul pci_conf_write(config_id, PCI_COMMAND_STATUS_REG, 151736270Swpaul PCIM_CMD_MEMEN|PCIM_CMD_BUSMASTEREN); 151836270Swpaul 151936270Swpaul command = pci_conf_read(config_id, PCI_COMMAND_STATUS_REG); 152036270Swpaul 152136270Swpaul if (!(command & PCIM_CMD_MEMEN)) { 152236270Swpaul printf("tlc%d: failed to enable memory mapping!\n", unit); 152336270Swpaul goto fail; 152436270Swpaul } 152536270Swpaul#else 152636270Swpaul pci_conf_write(config_id, PCI_COMMAND_STATUS_REG, 152736270Swpaul PCI_COMMAND_MEM_ENABLE| 152836270Swpaul PCI_COMMAND_MASTER_ENABLE); 152936270Swpaul 153036270Swpaul command = pci_conf_read(config_id, PCI_COMMAND_STATUS_REG); 153136270Swpaul 153236270Swpaul if (!(command & PCI_COMMAND_MEM_ENABLE)) { 153336270Swpaul printf("tlc%d: failed to enable memory mapping!\n", unit); 153436270Swpaul goto fail; 153536270Swpaul } 153636270Swpaul#endif 153736270Swpaul 153836270Swpaul if (!pci_map_mem(config_id, TL_PCI_LOMEM, &vbase, &pbase)) { 153936270Swpaul printf ("tlc%d: couldn't map memory\n", unit); 154036270Swpaul goto fail; 154136270Swpaul } 154236270Swpaul 154336270Swpaul csr = (struct tl_csr *)vbase; 154436270Swpaul 154536270Swpaul ilist->csr = csr; 154636270Swpaul ilist->tl_active_phy = TL_PHYS_IDLE; 154736270Swpaul ilist->tlc_unit = unit; 154836270Swpaul 154936270Swpaul /* Allocate interrupt */ 155036270Swpaul if (!pci_map_int(config_id, tl_intr, ilist, &net_imask)) { 155136270Swpaul printf("tlc%d: couldn't map interrupt\n", unit); 155236270Swpaul goto fail; 155336270Swpaul } 155436270Swpaul 155536270Swpaul /* Reset the adapter. */ 155636270Swpaul tl_softreset(csr, 1); 155736270Swpaul 155836270Swpaul /* 155936270Swpaul * Get station address from the EEPROM. 156036270Swpaul */ 156136270Swpaul if (tl_read_eeprom(csr, (caddr_t)&eaddr, 156236270Swpaul TL_EEPROM_EADDR, ETHER_ADDR_LEN)) { 156336270Swpaul printf("tlc%d: failed to read station address\n", unit); 156436270Swpaul goto fail; 156536270Swpaul } 156636270Swpaul 156736270Swpaul /* 156836270Swpaul * A ThunderLAN chip was detected. Inform the world. 156936270Swpaul */ 157036270Swpaul printf("tlc%d: Ethernet address: %6D\n", unit, eaddr, ":"); 157136270Swpaul 157236270Swpaul /* 157336270Swpaul * Now attach the ThunderLAN's PHYs. There will always 157436270Swpaul * be at least one PHY; if the PHY address is 0x1F, then 157536270Swpaul * it's the internal one. If we encounter a lower numbered 157636270Swpaul * PHY, we ignore the internal once since enabling the 157736270Swpaul * internal PHY disables the external one. 157836270Swpaul */ 157936270Swpaul 158036270Swpaul bzero((char *)&frame, sizeof(frame)); 158136270Swpaul 158236270Swpaul for (i = TL_PHYADDR_MIN; i < TL_PHYADDR_MAX + 1; i++) { 158336270Swpaul frame.mii_phyaddr = i; 158436270Swpaul frame.mii_regaddr = TL_PHY_GENCTL; 158536270Swpaul frame.mii_data = PHY_BMCR_RESET; 158636270Swpaul tl_mii_writereg(csr, &frame); 158736270Swpaul DELAY(500); 158836270Swpaul while(frame.mii_data & PHY_BMCR_RESET) 158936270Swpaul tl_mii_readreg(csr, &frame); 159036270Swpaul frame.mii_regaddr = TL_PHY_VENID; 159136270Swpaul frame.mii_data = 0; 159236270Swpaul tl_mii_readreg(csr, &frame); 159336270Swpaul if (!frame.mii_data) 159436270Swpaul continue; 159536270Swpaul if (tl_attach_phy(csr, phys, eaddr, i, ilist)) { 159636270Swpaul printf("tlc%d: failed to attach interface %d\n", 159736270Swpaul unit, i); 159836270Swpaul goto fail; 159936270Swpaul } 160036270Swpaul phys++; 160136270Swpaul if (phys && i != TL_PHYADDR_MAX) 160236270Swpaul break; 160336270Swpaul } 160436270Swpaul 160536270Swpaul if (!phys) { 160636270Swpaul printf("tlc%d: no physical interfaces attached!\n", unit); 160736270Swpaul goto fail; 160836270Swpaul } 160936270Swpaul 161036270Swpaul at_shutdown(tl_shutdown, ilist, SHUTDOWN_POST_SYNC); 161136270Swpaul 161236270Swpaulfail: 161336270Swpaul splx(s); 161436270Swpaul return; 161536270Swpaul} 161636270Swpaul 161736270Swpaul/* 161836270Swpaul * Initialize the transmit lists. 161936270Swpaul */ 162036270Swpaulstatic int tl_list_tx_init(sc) 162136270Swpaul struct tl_softc *sc; 162236270Swpaul{ 162336270Swpaul struct tl_chain_data *cd; 162436270Swpaul struct tl_list_data *ld; 162536270Swpaul int i; 162636270Swpaul 162736270Swpaul cd = &sc->tl_cdata; 162836270Swpaul ld = sc->tl_ldata; 162936270Swpaul for (i = 0; i < TL_TX_LIST_CNT; i++) { 163036270Swpaul cd->tl_tx_chain[i].tl_ptr = &ld->tl_tx_list[i]; 163136270Swpaul if (i == (TL_TX_LIST_CNT - 1)) 163236270Swpaul cd->tl_tx_chain[i].tl_next = NULL; 163336270Swpaul else 163436270Swpaul cd->tl_tx_chain[i].tl_next = &cd->tl_tx_chain[i + 1]; 163536270Swpaul } 163636270Swpaul 163736270Swpaul cd->tl_tx_free = &cd->tl_tx_chain[0]; 163836270Swpaul cd->tl_tx_tail = cd->tl_tx_head = NULL; 163936270Swpaul sc->tl_txeoc = 1; 164036270Swpaul 164136270Swpaul return(0); 164236270Swpaul} 164336270Swpaul 164436270Swpaul/* 164536270Swpaul * Initialize the RX lists and allocate mbufs for them. 164636270Swpaul */ 164736270Swpaulstatic int tl_list_rx_init(sc) 164836270Swpaul struct tl_softc *sc; 164936270Swpaul{ 165036270Swpaul struct tl_chain_data *cd; 165136270Swpaul struct tl_list_data *ld; 165236270Swpaul int i; 165336270Swpaul 165436270Swpaul cd = &sc->tl_cdata; 165536270Swpaul ld = sc->tl_ldata; 165636270Swpaul 165736270Swpaul for (i = 0; i < TL_TX_LIST_CNT; i++) { 165836270Swpaul cd->tl_rx_chain[i].tl_ptr = 165936270Swpaul (struct tl_list *)&ld->tl_rx_list[i]; 166036270Swpaul tl_newbuf(sc, &cd->tl_rx_chain[i]); 166136270Swpaul if (i == (TL_TX_LIST_CNT - 1)) { 166236270Swpaul cd->tl_rx_chain[i].tl_next = NULL; 166336270Swpaul ld->tl_rx_list[i].tlist_fptr = 0; 166436270Swpaul } else { 166536270Swpaul cd->tl_rx_chain[i].tl_next = &cd->tl_rx_chain[i + 1]; 166636270Swpaul ld->tl_rx_list[i].tlist_fptr = 166736270Swpaul vtophys(&ld->tl_rx_list[i + 1]); 166836270Swpaul } 166936270Swpaul } 167036270Swpaul 167136270Swpaul cd->tl_rx_head = &cd->tl_rx_chain[0]; 167236270Swpaul cd->tl_rx_tail = &cd->tl_rx_chain[TL_RX_LIST_CNT - 1]; 167336270Swpaul 167436270Swpaul return(0); 167536270Swpaul} 167636270Swpaul 167736270Swpaulstatic int tl_newbuf(sc, c) 167836270Swpaul struct tl_softc *sc; 167936270Swpaul struct tl_chain *c; 168036270Swpaul{ 168136270Swpaul struct mbuf *m_new = NULL; 168236270Swpaul 168336270Swpaul MGETHDR(m_new, M_DONTWAIT, MT_DATA); 168436270Swpaul if (m_new == NULL) { 168536270Swpaul printf("tl%d: no memory for rx list", 168636270Swpaul sc->tl_unit); 168736270Swpaul return(ENOBUFS); 168836270Swpaul } 168936270Swpaul 169036270Swpaul MCLGET(m_new, M_DONTWAIT); 169136270Swpaul if (!(m_new->m_flags & M_EXT)) { 169236270Swpaul printf("tl%d: no memory for rx list", sc->tl_unit); 169336270Swpaul m_freem(m_new); 169436270Swpaul return(ENOBUFS); 169536270Swpaul } 169636270Swpaul 169736270Swpaul c->tl_mbuf = m_new; 169836270Swpaul c->tl_next = NULL; 169936270Swpaul c->tl_ptr->tlist_frsize = MCLBYTES; 170036270Swpaul c->tl_ptr->tlist_cstat = TL_CSTAT_READY; 170136270Swpaul c->tl_ptr->tlist_fptr = 0; 170236270Swpaul c->tl_ptr->tl_frag[0].tlist_dadr = vtophys(mtod(m_new, caddr_t)); 170336270Swpaul c->tl_ptr->tl_frag[0].tlist_dcnt = MCLBYTES; 170436270Swpaul 170536270Swpaul return(0); 170636270Swpaul} 170736270Swpaul/* 170836270Swpaul * Interrupt handler for RX 'end of frame' condition (EOF). This 170936270Swpaul * tells us that a full ethernet frame has been captured and we need 171036270Swpaul * to handle it. 171136270Swpaul * 171236270Swpaul * Reception is done using 'lists' which consist of a header and a 171336270Swpaul * series of 10 data count/data address pairs that point to buffers. 171436270Swpaul * Initially you're supposed to create a list, populate it with pointers 171536270Swpaul * to buffers, then load the physical address of the list into the 171636270Swpaul * ch_parm register. The adapter is then supposed to DMA the received 171736270Swpaul * frame into the buffers for you. 171836270Swpaul * 171936270Swpaul * To make things as fast as possible, we have the chip DMA directly 172036270Swpaul * into mbufs. This saves us from having to do a buffer copy: we can 172136270Swpaul * just hand the mbufs directly to ether_input(). Once the frame has 172236270Swpaul * been sent on its way, the 'list' structure is assigned a new buffer 172336270Swpaul * and moved to the end of the RX chain. As long we we stay ahead of 172436270Swpaul * the chip, it will always think it has an endless receive channel. 172536270Swpaul * 172636270Swpaul * If we happen to fall behind and the chip manages to fill up all of 172736270Swpaul * the buffers, it will generate an end of channel interrupt and wait 172836270Swpaul * for us to empty the chain and restart the receiver. 172936270Swpaul */ 173036270Swpaulstatic int tl_intvec_rxeof(xsc, type) 173136270Swpaul void *xsc; 173236270Swpaul u_int32_t type; 173336270Swpaul{ 173436270Swpaul struct tl_softc *sc; 173536270Swpaul int r = 0, total_len = 0; 173636270Swpaul struct ether_header *eh; 173736270Swpaul struct mbuf *m; 173836270Swpaul struct ifnet *ifp; 173936270Swpaul struct tl_chain *cur_rx; 174036270Swpaul 174136270Swpaul sc = xsc; 174236270Swpaul ifp = &sc->arpcom.ac_if; 174336270Swpaul 174436270Swpaul while(sc->tl_cdata.tl_rx_head->tl_ptr->tlist_cstat & TL_CSTAT_FRAMECMP){ 174536270Swpaul r++; 174636270Swpaul cur_rx = sc->tl_cdata.tl_rx_head; 174736270Swpaul sc->tl_cdata.tl_rx_head = cur_rx->tl_next; 174836270Swpaul m = cur_rx->tl_mbuf; 174936270Swpaul total_len = cur_rx->tl_ptr->tlist_frsize; 175036270Swpaul 175136270Swpaul tl_newbuf(sc, cur_rx); 175236270Swpaul 175336270Swpaul sc->tl_cdata.tl_rx_tail->tl_ptr->tlist_fptr = 175436270Swpaul vtophys(cur_rx->tl_ptr); 175536270Swpaul sc->tl_cdata.tl_rx_tail->tl_next = cur_rx; 175636270Swpaul sc->tl_cdata.tl_rx_tail = cur_rx; 175736270Swpaul 175836270Swpaul eh = mtod(m, struct ether_header *); 175936270Swpaul m->m_pkthdr.rcvif = ifp; 176036270Swpaul 176136270Swpaul#if NBPFILTER > 0 176236270Swpaul /* 176336270Swpaul * Handle BPF listeners. Let the BPF user see the packet, but 176436270Swpaul * don't pass it up to the ether_input() layer unless it's 176536270Swpaul * a broadcast packet, multicast packet, matches our ethernet 176636270Swpaul * address or the interface is in promiscuous mode. If we don't 176736270Swpaul * want the packet, just forget it. We leave the mbuf in place 176836270Swpaul * since it can be used again later. 176936270Swpaul */ 177036270Swpaul if (ifp->if_bpf) { 177136270Swpaul m->m_pkthdr.len = m->m_len = total_len; 177236270Swpaul bpf_mtap(ifp, m); 177336270Swpaul if (ifp->if_flags & IFF_PROMISC && 177436270Swpaul (bcmp(eh->ether_dhost, sc->arpcom.ac_enaddr, 177536270Swpaul ETHER_ADDR_LEN) && 177636270Swpaul (eh->ether_dhost[0] & 1) == 0)) { 177736270Swpaul m_freem(m); 177836270Swpaul continue; 177936270Swpaul } 178036270Swpaul } 178136270Swpaul#endif 178236270Swpaul /* Remove header from mbuf and pass it on. */ 178336270Swpaul m->m_pkthdr.len = m->m_len = 178436270Swpaul total_len - sizeof(struct ether_header); 178536270Swpaul m->m_data += sizeof(struct ether_header); 178636270Swpaul ether_input(ifp, eh, m); 178736270Swpaul } 178836270Swpaul 178936270Swpaul return(r); 179036270Swpaul} 179136270Swpaul 179236270Swpaul/* 179336270Swpaul * The RX-EOC condition hits when the ch_parm address hasn't been 179436270Swpaul * initialized or the adapter reached a list with a forward pointer 179536270Swpaul * of 0 (which indicates the end of the chain). In our case, this means 179636270Swpaul * the card has hit the end of the receive buffer chain and we need to 179736270Swpaul * empty out the buffers and shift the pointer back to the beginning again. 179836270Swpaul */ 179936270Swpaulstatic int tl_intvec_rxeoc(xsc, type) 180036270Swpaul void *xsc; 180136270Swpaul u_int32_t type; 180236270Swpaul{ 180336270Swpaul struct tl_softc *sc; 180436270Swpaul int r; 180536270Swpaul 180636270Swpaul sc = xsc; 180736270Swpaul 180836270Swpaul /* Flush out the receive queue and ack RXEOF interrupts. */ 180936270Swpaul r = tl_intvec_rxeof(xsc, type); 181036270Swpaul sc->csr->tl_host_cmd = TL_CMD_ACK | r | (type & ~(0x00100000)); 181136270Swpaul r = 1; 181236270Swpaul sc->csr->tl_ch_parm = vtophys(sc->tl_cdata.tl_rx_head->tl_ptr); 181336270Swpaul r |= (TL_CMD_GO|TL_CMD_RT); 181436270Swpaul return(r); 181536270Swpaul} 181636270Swpaul 181736270Swpaul/* 181836270Swpaul * Invalid interrupt handler. The manual says invalid interrupts 181936270Swpaul * are caused by a hardware error in other hardware and that they 182036270Swpaul * should just be ignored. 182136270Swpaul */ 182236270Swpaulstatic int tl_intvec_invalid(xsc, type) 182336270Swpaul void *xsc; 182436270Swpaul u_int32_t type; 182536270Swpaul{ 182636270Swpaul struct tl_softc *sc; 182736270Swpaul 182836270Swpaul sc = xsc; 182936270Swpaul 183036270Swpaul#ifdef DIAGNOSTIC 183136270Swpaul printf("tl%d: got an invalid interrupt!\n", sc->tl_unit); 183236270Swpaul#endif 183336270Swpaul /* Re-enable interrupts but don't ack this one. */ 183436270Swpaul sc->csr->tl_host_cmd |= type; 183536270Swpaul 183636270Swpaul return(0); 183736270Swpaul} 183836270Swpaul 183936270Swpaul/* 184036270Swpaul * Dummy interrupt handler. Dummy interrupts are generated by setting 184136270Swpaul * the ReqInt bit in the host command register. They should only occur 184236270Swpaul * if we ask for them, and we never do, so if one magically appears, 184336270Swpaul * we should make some noise about it. 184436270Swpaul */ 184536270Swpaulstatic int tl_intvec_dummy(xsc, type) 184636270Swpaul void *xsc; 184736270Swpaul u_int32_t type; 184836270Swpaul{ 184936270Swpaul struct tl_softc *sc; 185036270Swpaul 185136270Swpaul sc = xsc; 185236270Swpaul printf("tl%d: got a dummy interrupt\n", sc->tl_unit); 185336270Swpaul 185436270Swpaul return(1); 185536270Swpaul} 185636270Swpaul 185736270Swpaul/* 185836270Swpaul * Stats counter overflow interrupt. The chip delivers one of these 185936270Swpaul * if we don't poll the stats counters often enough. 186036270Swpaul */ 186136270Swpaulstatic int tl_intvec_statoflow(xsc, type) 186236270Swpaul void *xsc; 186336270Swpaul u_int32_t type; 186436270Swpaul{ 186536270Swpaul struct tl_softc *sc; 186636270Swpaul 186736270Swpaul sc = xsc; 186836270Swpaul 186936270Swpaul tl_stats_update(sc); 187036270Swpaul 187136270Swpaul return(1); 187236270Swpaul} 187336270Swpaul 187436270Swpaulstatic int tl_intvec_txeof(xsc, type) 187536270Swpaul void *xsc; 187636270Swpaul u_int32_t type; 187736270Swpaul{ 187836270Swpaul struct tl_softc *sc; 187936270Swpaul int r = 0; 188036270Swpaul struct tl_chain *cur_tx; 188136270Swpaul 188236270Swpaul sc = xsc; 188336270Swpaul 188436270Swpaul /* 188536270Swpaul * Go through our tx list and free mbufs for those 188636270Swpaul * frames that have been sent. 188736270Swpaul */ 188836270Swpaul while (sc->tl_cdata.tl_tx_head != NULL) { 188936270Swpaul cur_tx = sc->tl_cdata.tl_tx_head; 189036270Swpaul if (!(cur_tx->tl_ptr->tlist_cstat & TL_CSTAT_FRAMECMP)) 189136270Swpaul break; 189236270Swpaul sc->tl_cdata.tl_tx_head = cur_tx->tl_next; 189336270Swpaul 189436270Swpaul r++; 189536270Swpaul m_freem(cur_tx->tl_mbuf); 189636270Swpaul cur_tx->tl_mbuf = NULL; 189736270Swpaul 189836270Swpaul cur_tx->tl_next = sc->tl_cdata.tl_tx_free; 189936270Swpaul sc->tl_cdata.tl_tx_free = cur_tx; 190036270Swpaul } 190136270Swpaul 190236270Swpaul return(r); 190336270Swpaul} 190436270Swpaul 190536270Swpaul/* 190636270Swpaul * The transmit end of channel interrupt. The adapter triggers this 190736270Swpaul * interrupt to tell us it hit the end of the current transmit list. 190836270Swpaul * 190936270Swpaul * A note about this: it's possible for a condition to arise where 191036270Swpaul * tl_start() may try to send frames between TXEOF and TXEOC interrupts. 191136270Swpaul * You have to avoid this since the chip expects things to go in a 191236270Swpaul * particular order: transmit, acknowledge TXEOF, acknowledge TXEOC. 191336270Swpaul * When the TXEOF handler is called, it will free all of the transmitted 191436270Swpaul * frames and reset the tx_head pointer to NULL. However, a TXEOC 191536270Swpaul * interrupt should be received and acknowledged before any more frames 191636270Swpaul * are queued for transmission. If tl_statrt() is called after TXEOF 191736270Swpaul * resets the tx_head pointer but _before_ the TXEOC interrupt arrives, 191836270Swpaul * it could attempt to issue a transmit command prematurely. 191936270Swpaul * 192036270Swpaul * To guard against this, tl_start() will only issue transmit commands 192136270Swpaul * if the tl_txeoc flag is set, and only the TXEOC interrupt handler 192236270Swpaul * can set this flag once tl_start() has cleared it. 192336270Swpaul */ 192436270Swpaulstatic int tl_intvec_txeoc(xsc, type) 192536270Swpaul void *xsc; 192636270Swpaul u_int32_t type; 192736270Swpaul{ 192836270Swpaul struct tl_softc *sc; 192936270Swpaul struct ifnet *ifp; 193036270Swpaul u_int32_t cmd; 193136270Swpaul 193236270Swpaul sc = xsc; 193336270Swpaul ifp = &sc->arpcom.ac_if; 193436270Swpaul 193536270Swpaul /* Clear the timeout timer. */ 193636270Swpaul ifp->if_timer = 0; 193736270Swpaul 193836270Swpaul if (sc->tl_cdata.tl_tx_head == NULL) { 193936270Swpaul ifp->if_flags &= ~IFF_OACTIVE; 194036270Swpaul sc->tl_cdata.tl_tx_tail = NULL; 194136270Swpaul sc->tl_txeoc = 1; 194236270Swpaul } else { 194336270Swpaul sc->tl_txeoc = 0; 194436270Swpaul /* First we have to ack the EOC interrupt. */ 194536270Swpaul sc->csr->tl_host_cmd = TL_CMD_ACK | 0x00000001 | type; 194636270Swpaul /* Then load the address of the next TX list. */ 194736270Swpaul sc->csr->tl_ch_parm = vtophys(sc->tl_cdata.tl_tx_head->tl_ptr); 194836270Swpaul /* Restart TX channel. */ 194936270Swpaul cmd = sc->csr->tl_host_cmd; 195036270Swpaul cmd &= ~TL_CMD_RT; 195136270Swpaul cmd |= TL_CMD_GO|TL_CMD_INTSON; 195236270Swpaul sc->csr->tl_host_cmd = cmd; 195336270Swpaul return(0); 195436270Swpaul } 195536270Swpaul 195636270Swpaul return(1); 195736270Swpaul} 195836270Swpaul 195936270Swpaulstatic int tl_intvec_adchk(xsc, type) 196036270Swpaul void *xsc; 196136270Swpaul u_int32_t type; 196236270Swpaul{ 196336270Swpaul struct tl_softc *sc; 196436270Swpaul 196536270Swpaul sc = xsc; 196636270Swpaul 196736270Swpaul printf("tl%d: adapter check: %x\n", sc->tl_unit, sc->csr->tl_ch_parm); 196836270Swpaul 196936270Swpaul tl_softreset(sc->csr, sc->tl_phy_addr == TL_PHYADDR_MAX ? 1 : 0); 197036270Swpaul tl_init(sc); 197136270Swpaul sc->csr->tl_host_cmd |= TL_CMD_INTSON; 197236270Swpaul 197336270Swpaul return(0); 197436270Swpaul} 197536270Swpaul 197636270Swpaulstatic int tl_intvec_netsts(xsc, type) 197736270Swpaul void *xsc; 197836270Swpaul u_int32_t type; 197936270Swpaul{ 198036270Swpaul struct tl_softc *sc; 198136270Swpaul u_int16_t netsts; 198236270Swpaul struct tl_csr *csr; 198336270Swpaul 198436270Swpaul sc = xsc; 198536270Swpaul csr = sc->csr; 198636270Swpaul 198736270Swpaul DIO_SEL(TL_NETSTS); 198836270Swpaul netsts = DIO_BYTE2_GET(0xFF); 198936270Swpaul DIO_BYTE2_SET(netsts); 199036270Swpaul 199136270Swpaul printf("tl%d: network status: %x\n", sc->tl_unit, netsts); 199236270Swpaul 199336270Swpaul return(1); 199436270Swpaul} 199536270Swpaul 199636270Swpaulstatic void tl_intr(xilist) 199736270Swpaul void *xilist; 199836270Swpaul{ 199936270Swpaul struct tl_iflist *ilist; 200036270Swpaul struct tl_softc *sc; 200136270Swpaul struct tl_csr *csr; 200236270Swpaul struct ifnet *ifp; 200336270Swpaul int r = 0; 200436270Swpaul u_int32_t type = 0; 200536270Swpaul u_int16_t ints = 0; 200636270Swpaul u_int8_t ivec = 0; 200736270Swpaul 200836270Swpaul ilist = xilist; 200936270Swpaul csr = ilist->csr; 201036270Swpaul 201136270Swpaul /* Disable interrupts */ 201236270Swpaul ints = csr->tl_host_int; 201336270Swpaul csr->tl_host_int = ints; 201436270Swpaul type = (ints << 16) & 0xFFFF0000; 201536270Swpaul ivec = (ints & TL_VEC_MASK) >> 5; 201636270Swpaul ints = (ints & TL_INT_MASK) >> 2; 201736270Swpaul /* 201836270Swpaul * An interrupt has been posted by the ThunderLAN, but we 201936270Swpaul * have to figure out which PHY generated it before we can 202036270Swpaul * do anything with it. If we receive an interrupt when we 202136270Swpaul * know none of the PHYs are turned on, then either there's 202236270Swpaul * a bug in the driver or we we handed an interrupt that 202336270Swpaul * doesn't actually belong to us. 202436270Swpaul */ 202536270Swpaul if (ilist->tl_active_phy == TL_PHYS_IDLE) { 202636270Swpaul printf("tlc%d: interrupt type %x with all phys idle\n", 202736270Swpaul ilist->tlc_unit, ints); 202836270Swpaul return; 202936270Swpaul } 203036270Swpaul 203136270Swpaul sc = ilist->tl_sc[ilist->tl_active_phy]; 203236270Swpaul csr = sc->csr; 203336270Swpaul ifp = &sc->arpcom.ac_if; 203436270Swpaul 203536270Swpaul switch(ints) { 203636270Swpaul case (TL_INTR_INVALID): 203736270Swpaul r = tl_intvec_invalid((void *)sc, type); 203836270Swpaul break; 203936270Swpaul case (TL_INTR_TXEOF): 204036270Swpaul r = tl_intvec_txeof((void *)sc, type); 204136270Swpaul break; 204236270Swpaul case (TL_INTR_TXEOC): 204336270Swpaul r = tl_intvec_txeoc((void *)sc, type); 204436270Swpaul break; 204536270Swpaul case (TL_INTR_STATOFLOW): 204636270Swpaul r = tl_intvec_statoflow((void *)sc, type); 204736270Swpaul break; 204836270Swpaul case (TL_INTR_RXEOF): 204936270Swpaul r = tl_intvec_rxeof((void *)sc, type); 205036270Swpaul break; 205136270Swpaul case (TL_INTR_DUMMY): 205236270Swpaul r = tl_intvec_dummy((void *)sc, type); 205336270Swpaul break; 205436270Swpaul case (TL_INTR_ADCHK): 205536270Swpaul if (ivec) 205636270Swpaul r = tl_intvec_adchk((void *)sc, type); 205736270Swpaul else 205836270Swpaul r = tl_intvec_netsts((void *)sc, type); 205936270Swpaul break; 206036270Swpaul case (TL_INTR_RXEOC): 206136270Swpaul r = tl_intvec_rxeoc((void *)sc, type); 206236270Swpaul break; 206336270Swpaul default: 206436270Swpaul printf("tl%d: bogus interrupt type\n", ifp->if_unit); 206536270Swpaul break; 206636270Swpaul } 206736270Swpaul 206836270Swpaul /* Re-enable interrupts */ 206936270Swpaul if (r) 207036270Swpaul csr->tl_host_cmd = TL_CMD_ACK | r | type; 207136270Swpaul 207236270Swpaul return; 207336270Swpaul} 207436270Swpaul 207536270Swpaulstatic void tl_stats_update(xsc) 207636270Swpaul void *xsc; 207736270Swpaul{ 207836270Swpaul struct tl_softc *sc; 207936270Swpaul struct ifnet *ifp; 208036270Swpaul struct tl_csr *csr; 208136270Swpaul struct tl_stats tl_stats; 208236270Swpaul u_int32_t *p; 208336270Swpaul 208436270Swpaul bzero((char *)&tl_stats, sizeof(struct tl_stats)); 208536270Swpaul 208636270Swpaul sc = xsc; 208736270Swpaul csr = sc->csr; 208836270Swpaul ifp = &sc->arpcom.ac_if; 208936270Swpaul 209036270Swpaul p = (u_int32_t *)&tl_stats; 209136270Swpaul 209236270Swpaul DIO_SEL(TL_TXGOODFRAMES|TL_DIO_ADDR_INC); 209336270Swpaul DIO_LONG_GET(*p++); 209436270Swpaul DIO_LONG_GET(*p++); 209536270Swpaul DIO_LONG_GET(*p++); 209636270Swpaul DIO_LONG_GET(*p++); 209736270Swpaul DIO_LONG_GET(*p++); 209836270Swpaul 209936270Swpaul ifp->if_opackets += tl_tx_goodframes(tl_stats); 210036270Swpaul ifp->if_collisions += tl_stats.tl_tx_single_collision + 210136270Swpaul tl_stats.tl_tx_multi_collision; 210236270Swpaul ifp->if_ipackets += tl_rx_goodframes(tl_stats); 210336270Swpaul ifp->if_ierrors += tl_stats.tl_crc_errors + tl_stats.tl_code_errors + 210436270Swpaul tl_rx_overrun(tl_stats); 210536270Swpaul ifp->if_oerrors += tl_tx_underrun(tl_stats); 210636270Swpaul 210736270Swpaul#if __FreeBSD_version >= 300000 210836270Swpaul sc->tl_stat_ch = timeout(tl_stats_update, sc, hz); 210936270Swpaul#else 211036270Swpaul timeout(tl_stats_update, sc, hz); 211136270Swpaul#endif 211236270Swpaul} 211336270Swpaul 211436270Swpaul/* 211536270Swpaul * Encapsulate an mbuf chain in a list by coupling the mbuf data 211636270Swpaul * pointers to the fragment pointers. 211736270Swpaul */ 211836270Swpaulstatic int tl_encap(sc, c, m_head) 211936270Swpaul struct tl_softc *sc; 212036270Swpaul struct tl_chain *c; 212136270Swpaul struct mbuf *m_head; 212236270Swpaul{ 212336270Swpaul int frag = 0; 212436270Swpaul struct tl_frag *f = NULL; 212536270Swpaul int total_len; 212636270Swpaul struct mbuf *m; 212736270Swpaul 212836270Swpaul /* 212936270Swpaul * Start packing the mbufs in this chain into 213036270Swpaul * the fragment pointers. Stop when we run out 213136270Swpaul * of fragments or hit the end of the mbuf chain. 213236270Swpaul */ 213336270Swpaul m = m_head; 213436270Swpaul total_len = 0; 213536270Swpaul 213636270Swpaul for (m = m_head, frag = 0; m != NULL; m = m->m_next) { 213736270Swpaul if (m->m_len != 0) { 213836270Swpaul if (frag == TL_MAXFRAGS) 213936270Swpaul break; 214036270Swpaul total_len+= m->m_len; 214136270Swpaul c->tl_ptr->tl_frag[frag].tlist_dadr = 214236270Swpaul vtophys(mtod(m, vm_offset_t)); 214336270Swpaul c->tl_ptr->tl_frag[frag].tlist_dcnt = m->m_len; 214436270Swpaul frag++; 214536270Swpaul } 214636270Swpaul } 214736270Swpaul 214836270Swpaul /* 214936270Swpaul * Handle special cases. 215036270Swpaul * Special case #1: we used up all 10 fragments, but 215136270Swpaul * we have more mbufs left in the chain. Copy the 215236270Swpaul * data into an mbuf cluster. Note that we don't 215336270Swpaul * bother clearing the values in the other fragment 215436270Swpaul * pointers/counters; it wouldn't gain us anything, 215536270Swpaul * and would waste cycles. 215636270Swpaul */ 215736270Swpaul if (m != NULL) { 215836270Swpaul struct mbuf *m_new = NULL; 215936270Swpaul 216036270Swpaul MGETHDR(m_new, M_DONTWAIT, MT_DATA); 216136270Swpaul if (m_new == NULL) { 216236270Swpaul printf("tl%d: no memory for tx list", sc->tl_unit); 216336270Swpaul return(1); 216436270Swpaul } 216536270Swpaul if (m_head->m_pkthdr.len > MHLEN) { 216636270Swpaul MCLGET(m_new, M_DONTWAIT); 216736270Swpaul if (!(m_new->m_flags & M_EXT)) { 216836270Swpaul m_freem(m_new); 216936270Swpaul printf("tl%d: no memory for tx list", 217036270Swpaul sc->tl_unit); 217136270Swpaul return(1); 217236270Swpaul } 217336270Swpaul } 217436270Swpaul m_copydata(m_head, 0, m_head->m_pkthdr.len, 217536270Swpaul mtod(m_new, caddr_t)); 217636270Swpaul m_new->m_pkthdr.len = m_new->m_len = m_head->m_pkthdr.len; 217736270Swpaul m_freem(m_head); 217836270Swpaul m_head = m_new; 217936270Swpaul f = &c->tl_ptr->tl_frag[0]; 218036270Swpaul f->tlist_dadr = vtophys(mtod(m_new, caddr_t)); 218136270Swpaul f->tlist_dcnt = total_len = m_new->m_len; 218236270Swpaul frag = 1; 218336270Swpaul } 218436270Swpaul 218536270Swpaul /* 218636270Swpaul * Special case #2: the frame is smaller than the minimum 218736270Swpaul * frame size. We have to pad it to make the chip happy. 218836270Swpaul */ 218936270Swpaul if (total_len < TL_MIN_FRAMELEN) { 219036270Swpaul if (frag == TL_MAXFRAGS) 219136270Swpaul printf("all frags filled but frame still to small!\n"); 219236270Swpaul f = &c->tl_ptr->tl_frag[frag]; 219336270Swpaul f->tlist_dcnt = TL_MIN_FRAMELEN - total_len; 219436270Swpaul f->tlist_dadr = vtophys(&sc->tl_ldata->tl_pad); 219536270Swpaul total_len += f->tlist_dcnt; 219636270Swpaul frag++; 219736270Swpaul } 219836270Swpaul 219936270Swpaul c->tl_mbuf = m_head; 220036270Swpaul c->tl_ptr->tl_frag[frag - 1].tlist_dcnt |= TL_LAST_FRAG; 220136270Swpaul c->tl_ptr->tlist_frsize = total_len; 220236270Swpaul c->tl_ptr->tlist_cstat = TL_CSTAT_READY; 220336270Swpaul c->tl_ptr->tlist_fptr = 0; 220436270Swpaul 220536270Swpaul return(0); 220636270Swpaul} 220736270Swpaul 220836270Swpaul/* 220936270Swpaul * Main transmit routine. To avoid having to do mbuf copies, we put pointers 221036270Swpaul * to the mbuf data regions directly in the transmit lists. We also save a 221136270Swpaul * copy of the pointers since the transmit list fragment pointers are 221236270Swpaul * physical addresses. 221336270Swpaul */ 221436270Swpaulstatic void tl_start(ifp) 221536270Swpaul struct ifnet *ifp; 221636270Swpaul{ 221736270Swpaul struct tl_softc *sc; 221836270Swpaul struct tl_csr *csr; 221936270Swpaul struct mbuf *m_head = NULL; 222036270Swpaul u_int32_t cmd; 222136270Swpaul struct tl_chain *prev = NULL, *cur_tx = NULL, *start_tx; 222236270Swpaul 222336270Swpaul sc = ifp->if_softc; 222436270Swpaul csr = sc->csr; 222536270Swpaul 222636270Swpaul /* 222736270Swpaul * Check for an available queue slot. If there are none, 222836270Swpaul * punt. 222936270Swpaul */ 223036270Swpaul if (sc->tl_cdata.tl_tx_free == NULL) { 223136270Swpaul ifp->if_flags |= IFF_OACTIVE; 223236270Swpaul return; 223336270Swpaul } 223436270Swpaul 223536270Swpaul start_tx = sc->tl_cdata.tl_tx_free; 223636270Swpaul 223736270Swpaul while(sc->tl_cdata.tl_tx_free != NULL) { 223836270Swpaul IF_DEQUEUE(&ifp->if_snd, m_head); 223936270Swpaul if (m_head == NULL) 224036270Swpaul break; 224136270Swpaul 224236270Swpaul /* Pick a chain member off the free list. */ 224336270Swpaul cur_tx = sc->tl_cdata.tl_tx_free; 224436270Swpaul sc->tl_cdata.tl_tx_free = cur_tx->tl_next; 224536270Swpaul 224636270Swpaul cur_tx->tl_next = NULL; 224736270Swpaul 224836270Swpaul /* Pack the data into the list. */ 224936270Swpaul tl_encap(sc, cur_tx, m_head); 225036270Swpaul 225136270Swpaul /* Chain it together */ 225236270Swpaul if (prev != NULL) { 225336270Swpaul prev->tl_next = cur_tx; 225436270Swpaul prev->tl_ptr->tlist_fptr = vtophys(cur_tx->tl_ptr); 225536270Swpaul } 225636270Swpaul prev = cur_tx; 225736270Swpaul 225836270Swpaul /* 225936270Swpaul * If there's a BPF listener, bounce a copy of this frame 226036270Swpaul * to him. 226136270Swpaul */ 226236270Swpaul#if NBPFILTER > 0 226336270Swpaul if (ifp->if_bpf) 226436270Swpaul bpf_mtap(ifp, cur_tx->tl_mbuf); 226536270Swpaul#endif 226636270Swpaul } 226736270Swpaul 226836270Swpaul /* 226936270Swpaul * That's all we can stands, we can't stands no more. 227036270Swpaul * If there are no other transfers pending, then issue the 227136270Swpaul * TX GO command to the adapter to start things moving. 227236270Swpaul * Otherwise, just leave the data in the queue and let 227336270Swpaul * the EOF/EOC interrupt handler send. 227436270Swpaul */ 227536270Swpaul if (sc->tl_cdata.tl_tx_head == NULL) { 227636270Swpaul sc->tl_cdata.tl_tx_head = start_tx; 227736270Swpaul sc->tl_cdata.tl_tx_tail = cur_tx; 227836270Swpaul if (sc->tl_txeoc) { 227936270Swpaul sc->tl_txeoc = 0; 228036270Swpaul sc->csr->tl_ch_parm = vtophys(start_tx->tl_ptr); 228136270Swpaul cmd = sc->csr->tl_host_cmd; 228236270Swpaul cmd &= ~TL_CMD_RT; 228336270Swpaul cmd |= TL_CMD_GO|TL_CMD_INTSON; 228436270Swpaul sc->csr->tl_host_cmd = cmd; 228536270Swpaul } 228636270Swpaul } else { 228736270Swpaul sc->tl_cdata.tl_tx_tail->tl_next = start_tx; 228836270Swpaul sc->tl_cdata.tl_tx_tail->tl_ptr->tlist_fptr = 228936270Swpaul vtophys(start_tx->tl_ptr); 229036270Swpaul sc->tl_cdata.tl_tx_tail = start_tx; 229136270Swpaul } 229236270Swpaul 229336270Swpaul /* 229436270Swpaul * Set a timeout in case the chip goes out to lunch. 229536270Swpaul */ 229636270Swpaul ifp->if_timer = 5; 229736270Swpaul 229836270Swpaul return; 229936270Swpaul} 230036270Swpaul 230136270Swpaulstatic void tl_init(xsc) 230236270Swpaul void *xsc; 230336270Swpaul{ 230436270Swpaul struct tl_softc *sc = xsc; 230536270Swpaul struct ifnet *ifp = &sc->arpcom.ac_if; 230636270Swpaul struct tl_csr *csr = sc->csr; 230736270Swpaul int s; 230836270Swpaul u_int16_t phy_sts; 230936270Swpaul 231036270Swpaul s = splimp(); 231136270Swpaul 231236270Swpaul ifp = &sc->arpcom.ac_if; 231336270Swpaul 231436270Swpaul /* 231536270Swpaul * Cancel pending I/O. 231636270Swpaul */ 231736270Swpaul tl_stop(sc); 231836270Swpaul 231936270Swpaul /* 232036270Swpaul * Set 'capture all frames' bit for promiscuous mode. 232136270Swpaul */ 232236270Swpaul if (ifp->if_flags & IFF_PROMISC) { 232336270Swpaul DIO_SEL(TL_NETCMD); 232436270Swpaul DIO_BYTE0_SET(TL_CMD_CAF); 232536270Swpaul } else { 232636270Swpaul DIO_SEL(TL_NETCMD); 232736270Swpaul DIO_BYTE0_CLR(TL_CMD_CAF); 232836270Swpaul } 232936270Swpaul 233036270Swpaul /* 233136270Swpaul * Set capture broadcast bit to capture broadcast frames. 233236270Swpaul */ 233336270Swpaul if (ifp->if_flags & IFF_BROADCAST) { 233436270Swpaul DIO_SEL(TL_NETCMD); 233536270Swpaul DIO_BYTE0_CLR(TL_CMD_NOBRX); 233636270Swpaul } else { 233736270Swpaul DIO_SEL(TL_NETCMD); 233836270Swpaul DIO_BYTE0_SET(TL_CMD_NOBRX); 233936270Swpaul } 234036270Swpaul 234136270Swpaul /* Init our MAC address */ 234236270Swpaul DIO_SEL(TL_AREG0_B5); 234336270Swpaul csr->u.tl_dio_bytes.byte0 = sc->arpcom.ac_enaddr[0]; 234436270Swpaul csr->u.tl_dio_bytes.byte1 = sc->arpcom.ac_enaddr[1]; 234536270Swpaul csr->u.tl_dio_bytes.byte2 = sc->arpcom.ac_enaddr[2]; 234636270Swpaul csr->u.tl_dio_bytes.byte3 = sc->arpcom.ac_enaddr[3]; 234736270Swpaul DIO_SEL(TL_AREG0_B1); 234836270Swpaul csr->u.tl_dio_bytes.byte0 = sc->arpcom.ac_enaddr[4]; 234936270Swpaul csr->u.tl_dio_bytes.byte1 = sc->arpcom.ac_enaddr[5]; 235036270Swpaul 235136270Swpaul /* Init circular RX list. */ 235236270Swpaul if (tl_list_rx_init(sc)) { 235336270Swpaul printf("tl%d: failed to set up rx lists\n", sc->tl_unit); 235436270Swpaul return; 235536270Swpaul } 235636270Swpaul 235736270Swpaul /* Init TX pointers. */ 235836270Swpaul tl_list_tx_init(sc); 235936270Swpaul 236036270Swpaul /* 236136270Swpaul * Enable PHY interrupts. 236236270Swpaul */ 236336270Swpaul phy_sts = tl_phy_readreg(sc, TL_PHY_CTL); 236436270Swpaul phy_sts |= PHY_CTL_INTEN; 236536270Swpaul tl_phy_writereg(sc, TL_PHY_CTL, phy_sts); 236636270Swpaul 236736270Swpaul /* Enable MII interrupts. */ 236836270Swpaul DIO_SEL(TL_NETSIO); 236936270Swpaul DIO_BYTE1_SET(TL_SIO_MINTEN); 237036270Swpaul 237136270Swpaul /* Enable PCI interrupts. */ 237236270Swpaul csr->tl_host_cmd |= TL_CMD_INTSON; 237336270Swpaul 237436270Swpaul /* Load the address of the rx list */ 237536270Swpaul sc->csr->tl_host_cmd |= TL_CMD_RT; 237636270Swpaul sc->csr->tl_ch_parm = vtophys(&sc->tl_ldata->tl_rx_list[0]); 237736270Swpaul 237836270Swpaul /* Send the RX go command */ 237936270Swpaul sc->csr->tl_host_cmd |= (TL_CMD_GO|TL_CMD_RT); 238036270Swpaul sc->tl_iflist->tl_active_phy = sc->tl_phy_addr; 238136270Swpaul 238236270Swpaul ifp->if_flags |= IFF_RUNNING; 238336270Swpaul ifp->if_flags &= ~IFF_OACTIVE; 238436270Swpaul 238536270Swpaul (void)splx(s); 238636270Swpaul 238736270Swpaul /* Start the stats update counter */ 238836270Swpaul#if __FreeBSD_version >= 300000 238936270Swpaul sc->tl_stat_ch = timeout(tl_stats_update, sc, hz); 239036270Swpaul#else 239136270Swpaul timeout(tl_stats_update, sc, hz); 239236270Swpaul#endif 239336270Swpaul 239436270Swpaul return; 239536270Swpaul} 239636270Swpaul 239736270Swpaul/* 239836270Swpaul * Set media options. 239936270Swpaul */ 240036270Swpaulstatic int tl_ifmedia_upd(ifp) 240136270Swpaul struct ifnet *ifp; 240236270Swpaul{ 240336270Swpaul struct tl_softc *sc; 240436270Swpaul struct tl_csr *csr; 240536270Swpaul struct ifmedia *ifm; 240636270Swpaul 240736270Swpaul sc = ifp->if_softc; 240836270Swpaul csr = sc->csr; 240936270Swpaul ifm = &sc->ifmedia; 241036270Swpaul 241136270Swpaul if (IFM_TYPE(ifm->ifm_media) != IFM_ETHER) 241236270Swpaul return(EINVAL); 241336270Swpaul 241436270Swpaul if (IFM_SUBTYPE(ifm->ifm_media) == IFM_AUTO) 241536270Swpaul tl_autoneg(sc, TL_FLAG_SCHEDDELAY, 1); 241636270Swpaul else 241736270Swpaul tl_setmode(sc, ifm->ifm_media); 241836270Swpaul 241936270Swpaul return(0); 242036270Swpaul} 242136270Swpaul 242236270Swpaul/* 242336270Swpaul * Report current media status. 242436270Swpaul */ 242536270Swpaulstatic void tl_ifmedia_sts(ifp, ifmr) 242636270Swpaul struct ifnet *ifp; 242736270Swpaul struct ifmediareq *ifmr; 242836270Swpaul{ 242936270Swpaul u_int16_t phy_ctl; 243036270Swpaul u_int16_t phy_sts; 243136270Swpaul struct tl_softc *sc; 243236270Swpaul struct tl_csr *csr; 243336270Swpaul 243436270Swpaul sc = ifp->if_softc; 243536270Swpaul csr = sc->csr; 243636270Swpaul 243736270Swpaul ifmr->ifm_active = IFM_ETHER; 243836270Swpaul 243936270Swpaul phy_ctl = tl_phy_readreg(sc, PHY_BMCR); 244036270Swpaul phy_sts = tl_phy_readreg(sc, TL_PHY_CTL); 244136270Swpaul 244236270Swpaul if (phy_sts & PHY_CTL_AUISEL) 244336270Swpaul ifmr->ifm_active |= IFM_10_5; 244436270Swpaul 244536270Swpaul if (phy_ctl & PHY_BMCR_LOOPBK) 244636270Swpaul ifmr->ifm_active |= IFM_LOOP; 244736270Swpaul 244836270Swpaul if (phy_ctl & PHY_BMCR_SPEEDSEL) 244936270Swpaul ifmr->ifm_active |= IFM_100_TX; 245036270Swpaul else 245136270Swpaul ifmr->ifm_active |= IFM_10_T; 245236270Swpaul 245336270Swpaul if (phy_ctl & PHY_BMCR_DUPLEX) { 245436270Swpaul ifmr->ifm_active |= IFM_FDX; 245536270Swpaul ifmr->ifm_active &= ~IFM_HDX; 245636270Swpaul } else { 245736270Swpaul ifmr->ifm_active &= ~IFM_FDX; 245836270Swpaul ifmr->ifm_active |= IFM_HDX; 245936270Swpaul } 246036270Swpaul 246136270Swpaul if (phy_ctl & PHY_BMCR_AUTONEGENBL) 246236270Swpaul ifmr->ifm_active |= IFM_AUTO; 246336270Swpaul 246436270Swpaul return; 246536270Swpaul} 246636270Swpaul 246736270Swpaulstatic int tl_ioctl(ifp, command, data) 246836270Swpaul struct ifnet *ifp; 246936270Swpaul int command; 247036270Swpaul caddr_t data; 247136270Swpaul{ 247236270Swpaul struct tl_softc *sc = ifp->if_softc; 247336270Swpaul struct ifreq *ifr = (struct ifreq *) data; 247436270Swpaul int s, error = 0; 247536270Swpaul 247636270Swpaul s = splimp(); 247736270Swpaul 247836270Swpaul switch(command) { 247936270Swpaul case SIOCSIFADDR: 248036270Swpaul case SIOCGIFADDR: 248136270Swpaul case SIOCSIFMTU: 248236270Swpaul error = ether_ioctl(ifp, command, data); 248336270Swpaul break; 248436270Swpaul case SIOCSIFFLAGS: 248536270Swpaul /* 248636270Swpaul * Make sure no more than one PHY is active 248736270Swpaul * at any one time. 248836270Swpaul */ 248936270Swpaul if (ifp->if_flags & IFF_UP) { 249036270Swpaul if (sc->tl_iflist->tl_active_phy != TL_PHYS_IDLE && 249136270Swpaul sc->tl_iflist->tl_active_phy != sc->tl_phy_addr) { 249236270Swpaul error = EINVAL; 249336270Swpaul break; 249436270Swpaul } 249536270Swpaul sc->tl_iflist->tl_active_phy = sc->tl_phy_addr; 249636270Swpaul tl_init(sc); 249736270Swpaul } else { 249836270Swpaul if (ifp->if_flags & IFF_RUNNING) { 249936270Swpaul sc->tl_iflist->tl_active_phy = TL_PHYS_IDLE; 250036270Swpaul tl_stop(sc); 250136270Swpaul } 250236270Swpaul } 250336270Swpaul error = 0; 250436270Swpaul break; 250536270Swpaul case SIOCADDMULTI: 250636270Swpaul case SIOCDELMULTI: 250736270Swpaul#if __FreeBSD_version < 300000 250836270Swpaul if (command == SIOCADDMULTI) 250936270Swpaul error = ether_addmulti(ifr, &sc->arpcom); 251036270Swpaul else 251136270Swpaul error = ether_delmulti(ifr, &sc->arpcom); 251236270Swpaul if (error == ENETRESET) { 251336270Swpaul tl_setmulti(sc); 251436270Swpaul error = 0; 251536270Swpaul } 251636270Swpaul#else 251736270Swpaul tl_setmulti(sc); 251836270Swpaul error = 0; 251936270Swpaul#endif 252036270Swpaul break; 252136270Swpaul case SIOCSIFMEDIA: 252236270Swpaul case SIOCGIFMEDIA: 252336270Swpaul error = ifmedia_ioctl(ifp, ifr, &sc->ifmedia, command); 252436270Swpaul break; 252536270Swpaul default: 252636270Swpaul error = EINVAL; 252736270Swpaul break; 252836270Swpaul } 252936270Swpaul 253036270Swpaul (void)splx(s); 253136270Swpaul 253236270Swpaul return(error); 253336270Swpaul} 253436270Swpaul 253536270Swpaulstatic void tl_watchdog(ifp) 253636270Swpaul struct ifnet *ifp; 253736270Swpaul{ 253836270Swpaul struct tl_softc *sc; 253936270Swpaul u_int16_t bmsr; 254036270Swpaul 254136270Swpaul sc = ifp->if_softc; 254236270Swpaul 254336270Swpaul if (sc->tl_autoneg) { 254436270Swpaul tl_autoneg(sc, TL_FLAG_DELAYTIMEO, 1); 254536270Swpaul return; 254636270Swpaul } 254736270Swpaul 254836270Swpaul /* Check that we're still connected. */ 254936270Swpaul tl_phy_readreg(sc, PHY_BMSR); 255036270Swpaul bmsr = tl_phy_readreg(sc, PHY_BMSR); 255136270Swpaul if (!(bmsr & PHY_BMSR_LINKSTAT)) { 255236270Swpaul printf("tl%d: no carrier\n", sc->tl_unit); 255336270Swpaul tl_autoneg(sc, TL_FLAG_SCHEDDELAY, 1); 255436270Swpaul } else 255536270Swpaul printf("tl%d: device timeout\n", sc->tl_unit); 255636270Swpaul 255736270Swpaul ifp->if_oerrors++; 255836270Swpaul 255936270Swpaul tl_init(sc); 256036270Swpaul 256136270Swpaul return; 256236270Swpaul} 256336270Swpaul 256436270Swpaul/* 256536270Swpaul * Stop the adapter and free any mbufs allocated to the 256636270Swpaul * RX and TX lists. 256736270Swpaul */ 256836270Swpaulstatic void tl_stop(sc) 256936270Swpaul struct tl_softc *sc; 257036270Swpaul{ 257136270Swpaul register int i; 257236270Swpaul struct ifnet *ifp; 257336270Swpaul struct tl_csr *csr; 257436270Swpaul struct tl_mii_frame frame; 257536270Swpaul 257636270Swpaul csr = sc->csr; 257736270Swpaul ifp = &sc->arpcom.ac_if; 257836270Swpaul 257936270Swpaul /* Stop the stats updater. */ 258036270Swpaul#if __FreeBSD_version >= 300000 258136270Swpaul untimeout(tl_stats_update, sc, sc->tl_stat_ch); 258236270Swpaul#else 258336270Swpaul untimeout(tl_stats_update, sc); 258436270Swpaul#endif 258536270Swpaul 258636270Swpaul /* Stop the transmitter */ 258736270Swpaul sc->csr->tl_host_cmd &= TL_CMD_RT; 258836270Swpaul sc->csr->tl_host_cmd |= TL_CMD_STOP; 258936270Swpaul 259036270Swpaul /* Stop the receiver */ 259136270Swpaul sc->csr->tl_host_cmd |= TL_CMD_RT; 259236270Swpaul sc->csr->tl_host_cmd |= TL_CMD_STOP; 259336270Swpaul 259436270Swpaul /* 259536270Swpaul * Disable host interrupts. 259636270Swpaul */ 259736270Swpaul sc->csr->tl_host_cmd |= TL_CMD_INTSOFF; 259836270Swpaul 259936270Swpaul /* 260036270Swpaul * Disable PHY interrupts. 260136270Swpaul */ 260236270Swpaul bzero((char *)&frame, sizeof(frame)); 260336270Swpaul 260436270Swpaul frame.mii_phyaddr = sc->tl_phy_addr; 260536270Swpaul frame.mii_regaddr = TL_PHY_CTL; 260636270Swpaul tl_mii_readreg(csr, &frame); 260736270Swpaul frame.mii_data |= PHY_CTL_INTEN; 260836270Swpaul tl_mii_writereg(csr, &frame); 260936270Swpaul 261036270Swpaul /* 261136270Swpaul * Disable MII interrupts. 261236270Swpaul */ 261336270Swpaul DIO_SEL(TL_NETSIO); 261436270Swpaul DIO_BYTE1_CLR(TL_SIO_MINTEN); 261536270Swpaul 261636270Swpaul /* 261736270Swpaul * Clear list pointer. 261836270Swpaul */ 261936270Swpaul sc->csr->tl_ch_parm = 0; 262036270Swpaul 262136270Swpaul /* 262236270Swpaul * Free the RX lists. 262336270Swpaul */ 262436270Swpaul for (i = 0; i < TL_RX_LIST_CNT; i++) { 262536270Swpaul if (sc->tl_cdata.tl_rx_chain[i].tl_mbuf != NULL) { 262636270Swpaul m_freem(sc->tl_cdata.tl_rx_chain[i].tl_mbuf); 262736270Swpaul sc->tl_cdata.tl_rx_chain[i].tl_mbuf = NULL; 262836270Swpaul } 262936270Swpaul } 263036270Swpaul bzero((char *)&sc->tl_ldata->tl_rx_list, 263136270Swpaul sizeof(sc->tl_ldata->tl_rx_list)); 263236270Swpaul 263336270Swpaul /* 263436270Swpaul * Free the TX list buffers. 263536270Swpaul */ 263636270Swpaul for (i = 0; i < TL_TX_LIST_CNT; i++) { 263736270Swpaul if (sc->tl_cdata.tl_tx_chain[i].tl_mbuf != NULL) { 263836270Swpaul m_freem(sc->tl_cdata.tl_tx_chain[i].tl_mbuf); 263936270Swpaul sc->tl_cdata.tl_tx_chain[i].tl_mbuf = NULL; 264036270Swpaul } 264136270Swpaul } 264236270Swpaul bzero((char *)&sc->tl_ldata->tl_tx_list, 264336270Swpaul sizeof(sc->tl_ldata->tl_tx_list)); 264436270Swpaul 264536270Swpaul sc->tl_iflist->tl_active_phy = TL_PHYS_IDLE; 264636270Swpaul ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE); 264736270Swpaul 264836270Swpaul return; 264936270Swpaul} 265036270Swpaul 265136270Swpaul/* 265236270Swpaul * Stop all chip I/O so that the kernel's probe routines don't 265336270Swpaul * get confused by errant DMAs when rebooting. 265436270Swpaul */ 265536270Swpaulstatic void tl_shutdown(howto, xilist) 265636270Swpaul int howto; 265736270Swpaul void *xilist; 265836270Swpaul{ 265936270Swpaul struct tl_iflist *ilist = (struct tl_iflist *)xilist; 266036270Swpaul struct tl_csr *csr = ilist->csr; 266136270Swpaul struct tl_mii_frame frame; 266236270Swpaul int i; 266336270Swpaul 266436270Swpaul /* Stop the transmitter */ 266536270Swpaul csr->tl_host_cmd &= TL_CMD_RT; 266636270Swpaul csr->tl_host_cmd |= TL_CMD_STOP; 266736270Swpaul 266836270Swpaul /* Stop the receiver */ 266936270Swpaul csr->tl_host_cmd |= TL_CMD_RT; 267036270Swpaul csr->tl_host_cmd |= TL_CMD_STOP; 267136270Swpaul 267236270Swpaul /* 267336270Swpaul * Disable host interrupts. 267436270Swpaul */ 267536270Swpaul csr->tl_host_cmd |= TL_CMD_INTSOFF; 267636270Swpaul 267736270Swpaul /* 267836270Swpaul * Disable PHY interrupts. 267936270Swpaul */ 268036270Swpaul bzero((char *)&frame, sizeof(frame)); 268136270Swpaul 268236270Swpaul for (i = TL_PHYADDR_MIN; i < TL_PHYADDR_MAX + 1; i++) { 268336270Swpaul frame.mii_phyaddr = i; 268436270Swpaul frame.mii_regaddr = TL_PHY_CTL; 268536270Swpaul tl_mii_readreg(csr, &frame); 268636270Swpaul frame.mii_data |= PHY_CTL_INTEN; 268736270Swpaul tl_mii_writereg(csr, &frame); 268836270Swpaul }; 268936270Swpaul 269036270Swpaul /* 269136270Swpaul * Disable MII interrupts. 269236270Swpaul */ 269336270Swpaul DIO_SEL(TL_NETSIO); 269436270Swpaul DIO_BYTE1_CLR(TL_SIO_MINTEN); 269536270Swpaul 269636270Swpaul return; 269736270Swpaul} 269836270Swpaul 269936270Swpaul 270036270Swpaulstatic struct pci_device tlc_device = { 270136270Swpaul "tlc", 270236270Swpaul tl_probe, 270336270Swpaul tl_attach_ctlr, 270436270Swpaul &tl_count, 270536270Swpaul NULL 270636270Swpaul}; 270736270SwpaulDATA_SET(pcidevice_set, tlc_device); 2708