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