if_rl.c revision 50477
140516Swpaul/* 240516Swpaul * Copyright (c) 1997, 1998 340516Swpaul * Bill Paul <wpaul@ctr.columbia.edu>. All rights reserved. 440516Swpaul * 540516Swpaul * Redistribution and use in source and binary forms, with or without 640516Swpaul * modification, are permitted provided that the following conditions 740516Swpaul * are met: 840516Swpaul * 1. Redistributions of source code must retain the above copyright 940516Swpaul * notice, this list of conditions and the following disclaimer. 1040516Swpaul * 2. Redistributions in binary form must reproduce the above copyright 1140516Swpaul * notice, this list of conditions and the following disclaimer in the 1240516Swpaul * documentation and/or other materials provided with the distribution. 1340516Swpaul * 3. All advertising materials mentioning features or use of this software 1440516Swpaul * must display the following acknowledgement: 1540516Swpaul * This product includes software developed by Bill Paul. 1640516Swpaul * 4. Neither the name of the author nor the names of any co-contributors 1740516Swpaul * may be used to endorse or promote products derived from this software 1840516Swpaul * without specific prior written permission. 1940516Swpaul * 2040516Swpaul * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND 2140516Swpaul * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2240516Swpaul * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2340516Swpaul * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD 2440516Swpaul * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 2540516Swpaul * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 2640516Swpaul * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 2740516Swpaul * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 2840516Swpaul * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 2940516Swpaul * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 3040516Swpaul * THE POSSIBILITY OF SUCH DAMAGE. 3140516Swpaul * 3250477Speter * $FreeBSD: head/sys/pci/if_rl.c 50477 1999-08-28 01:08:13Z peter $ 3340516Swpaul */ 3440516Swpaul 3540516Swpaul/* 3640516Swpaul * RealTek 8129/8139 PCI NIC driver 3740516Swpaul * 3840516Swpaul * Supports several extremely cheap PCI 10/100 adapters based on 3940516Swpaul * the RealTek chipset. Datasheets can be obtained from 4040516Swpaul * www.realtek.com.tw. 4140516Swpaul * 4240516Swpaul * Written by Bill Paul <wpaul@ctr.columbia.edu> 4340516Swpaul * Electrical Engineering Department 4440516Swpaul * Columbia University, New York City 4540516Swpaul */ 4640516Swpaul 4740516Swpaul/* 4840516Swpaul * The RealTek 8139 PCI NIC redefines the meaning of 'low end.' This is 4940516Swpaul * probably the worst PCI ethernet controller ever made, with the possible 5040516Swpaul * exception of the FEAST chip made by SMC. The 8139 supports bus-master 5140516Swpaul * DMA, but it has a terrible interface that nullifies any performance 5240516Swpaul * gains that bus-master DMA usually offers. 5340516Swpaul * 5440516Swpaul * For transmission, the chip offers a series of four TX descriptor 5540516Swpaul * registers. Each transmit frame must be in a contiguous buffer, aligned 5641569Swpaul * on a longword (32-bit) boundary. This means we almost always have to 5740516Swpaul * do mbuf copies in order to transmit a frame, except in the unlikely 5840516Swpaul * case where a) the packet fits into a single mbuf, and b) the packet 5940516Swpaul * is 32-bit aligned within the mbuf's data area. The presence of only 6040516Swpaul * four descriptor registers means that we can never have more than four 6140516Swpaul * packets queued for transmission at any one time. 6240516Swpaul * 6340516Swpaul * Reception is not much better. The driver has to allocate a single large 6440516Swpaul * buffer area (up to 64K in size) into which the chip will DMA received 6540516Swpaul * frames. Because we don't know where within this region received packets 6640516Swpaul * will begin or end, we have no choice but to copy data from the buffer 6740516Swpaul * area into mbufs in order to pass the packets up to the higher protocol 6840516Swpaul * levels. 6940516Swpaul * 7040516Swpaul * It's impossible given this rotten design to really achieve decent 7140516Swpaul * performance at 100Mbps, unless you happen to have a 400Mhz PII or 7240516Swpaul * some equally overmuscled CPU to drive it. 7340516Swpaul * 7440516Swpaul * On the bright side, the 8139 does have a built-in PHY, although 7540516Swpaul * rather than using an MDIO serial interface like most other NICs, the 7640516Swpaul * PHY registers are directly accessible through the 8139's register 7740516Swpaul * space. The 8139 supports autonegotiation, as well as a 64-bit multicast 7840516Swpaul * filter. 7940516Swpaul * 8040516Swpaul * The 8129 chip is an older version of the 8139 that uses an external PHY 8140516Swpaul * chip. The 8129 has a serial MDIO interface for accessing the MII where 8240516Swpaul * the 8139 lets you directly access the on-board PHY registers. We need 8340516Swpaul * to select which interface to use depending on the chip type. 8440516Swpaul */ 8540516Swpaul 8648645Sdes#include "bpf.h" 8740516Swpaul 8840516Swpaul#include <sys/param.h> 8940516Swpaul#include <sys/systm.h> 9050135Smsmith#include <sys/eventhandler.h> 9140516Swpaul#include <sys/sockio.h> 9240516Swpaul#include <sys/mbuf.h> 9340516Swpaul#include <sys/malloc.h> 9440516Swpaul#include <sys/kernel.h> 9540516Swpaul#include <sys/socket.h> 9640516Swpaul 9740516Swpaul#include <net/if.h> 9840516Swpaul#include <net/if_arp.h> 9940516Swpaul#include <net/ethernet.h> 10040516Swpaul#include <net/if_dl.h> 10140516Swpaul#include <net/if_media.h> 10240516Swpaul 10348645Sdes#if NBPF > 0 10440516Swpaul#include <net/bpf.h> 10540516Swpaul#endif 10640516Swpaul 10740516Swpaul#include <vm/vm.h> /* for vtophys */ 10840516Swpaul#include <vm/pmap.h> /* for vtophys */ 10940516Swpaul#include <machine/clock.h> /* for DELAY */ 11041569Swpaul#include <machine/bus_pio.h> 11141569Swpaul#include <machine/bus_memio.h> 11241569Swpaul#include <machine/bus.h> 11340516Swpaul 11440516Swpaul#include <pci/pcireg.h> 11540516Swpaul#include <pci/pcivar.h> 11640516Swpaul 11740516Swpaul/* 11840516Swpaul * Default to using PIO access for this driver. On SMP systems, 11940516Swpaul * there appear to be problems with memory mapped mode: it looks like 12040516Swpaul * doing too many memory mapped access back to back in rapid succession 12140516Swpaul * can hang the bus. I'm inclined to blame this on crummy design/construction 12240516Swpaul * on the part of RealTek. Memory mapped mode does appear to work on 12340516Swpaul * uniprocessor systems though. 12440516Swpaul */ 12540516Swpaul#define RL_USEIOSPACE 12640516Swpaul 12740516Swpaul#include <pci/if_rlreg.h> 12840516Swpaul 12940516Swpaul#ifndef lint 13041591Sarchiestatic const char rcsid[] = 13150477Speter "$FreeBSD: head/sys/pci/if_rl.c 50477 1999-08-28 01:08:13Z peter $"; 13240516Swpaul#endif 13340516Swpaul 13440516Swpaul/* 13540516Swpaul * Various supported device vendors/types and their names. 13640516Swpaul */ 13740516Swpaulstatic struct rl_type rl_devs[] = { 13840516Swpaul { RT_VENDORID, RT_DEVICEID_8129, 13940516Swpaul "RealTek 8129 10/100BaseTX" }, 14040516Swpaul { RT_VENDORID, RT_DEVICEID_8139, 14140516Swpaul "RealTek 8139 10/100BaseTX" }, 14241243Swpaul { ACCTON_VENDORID, ACCTON_DEVICEID_5030, 14341243Swpaul "Accton MPX 5030/5038 10/100BaseTX" }, 14444238Swpaul { DELTA_VENDORID, DELTA_DEVICEID_8139, 14544238Swpaul "Delta Electronics 8139 10/100BaseTX" }, 14644238Swpaul { ADDTRON_VENDORID, ADDTRON_DEVICEID_8139, 14744238Swpaul "Addtron Technolgy 8139 10/100BaseTX" }, 14840516Swpaul { 0, 0, NULL } 14940516Swpaul}; 15040516Swpaul 15140516Swpaul/* 15240516Swpaul * Various supported PHY vendors/types and their names. Note that 15340516Swpaul * this driver will work with pretty much any MII-compliant PHY, 15440516Swpaul * so failure to positively identify the chip is not a fatal error. 15540516Swpaul */ 15640516Swpaul 15740516Swpaulstatic struct rl_type rl_phys[] = { 15840516Swpaul { TI_PHY_VENDORID, TI_PHY_10BT, "<TI ThunderLAN 10BT (internal)>" }, 15940516Swpaul { TI_PHY_VENDORID, TI_PHY_100VGPMI, "<TI TNETE211 100VG Any-LAN>" }, 16040516Swpaul { NS_PHY_VENDORID, NS_PHY_83840A, "<National Semiconductor DP83840A>"}, 16140516Swpaul { LEVEL1_PHY_VENDORID, LEVEL1_PHY_LXT970, "<Level 1 LXT970>" }, 16240516Swpaul { INTEL_PHY_VENDORID, INTEL_PHY_82555, "<Intel 82555>" }, 16340516Swpaul { SEEQ_PHY_VENDORID, SEEQ_PHY_80220, "<SEEQ 80220>" }, 16440516Swpaul { 0, 0, "<MII-compliant physical interface>" } 16540516Swpaul}; 16640516Swpaul 16740516Swpaulstatic unsigned long rl_count = 0; 16841771Sdillonstatic const char *rl_probe __P((pcici_t, pcidi_t)); 16940516Swpaulstatic void rl_attach __P((pcici_t, int)); 17040516Swpaul 17145633Swpaulstatic int rl_encap __P((struct rl_softc *, struct mbuf * )); 17240516Swpaul 17340516Swpaulstatic void rl_rxeof __P((struct rl_softc *)); 17440516Swpaulstatic void rl_txeof __P((struct rl_softc *)); 17540516Swpaulstatic void rl_intr __P((void *)); 17640516Swpaulstatic void rl_start __P((struct ifnet *)); 17740516Swpaulstatic int rl_ioctl __P((struct ifnet *, u_long, caddr_t)); 17840516Swpaulstatic void rl_init __P((void *)); 17940516Swpaulstatic void rl_stop __P((struct rl_softc *)); 18040516Swpaulstatic void rl_watchdog __P((struct ifnet *)); 18150107Smsmithstatic void rl_shutdown __P((void *, int)); 18240516Swpaulstatic int rl_ifmedia_upd __P((struct ifnet *)); 18340516Swpaulstatic void rl_ifmedia_sts __P((struct ifnet *, struct ifmediareq *)); 18440516Swpaul 18541656Swpaulstatic void rl_eeprom_putbyte __P((struct rl_softc *, int)); 18641656Swpaulstatic void rl_eeprom_getword __P((struct rl_softc *, int, u_int16_t *)); 18740516Swpaulstatic void rl_read_eeprom __P((struct rl_softc *, caddr_t, 18840516Swpaul int, int, int)); 18940516Swpaulstatic void rl_mii_sync __P((struct rl_softc *)); 19040516Swpaulstatic void rl_mii_send __P((struct rl_softc *, u_int32_t, int)); 19140516Swpaulstatic int rl_mii_readreg __P((struct rl_softc *, struct rl_mii_frame *)); 19240516Swpaulstatic int rl_mii_writereg __P((struct rl_softc *, struct rl_mii_frame *)); 19340516Swpaul 19440516Swpaulstatic u_int16_t rl_phy_readreg __P((struct rl_softc *, int)); 19541656Swpaulstatic void rl_phy_writereg __P((struct rl_softc *, int, int)); 19640516Swpaul 19740516Swpaulstatic void rl_autoneg_xmit __P((struct rl_softc *)); 19840516Swpaulstatic void rl_autoneg_mii __P((struct rl_softc *, int, int)); 19940516Swpaulstatic void rl_setmode_mii __P((struct rl_softc *, int)); 20040516Swpaulstatic void rl_getmode_mii __P((struct rl_softc *)); 20141656Swpaulstatic u_int8_t rl_calchash __P((caddr_t)); 20240516Swpaulstatic void rl_setmulti __P((struct rl_softc *)); 20340516Swpaulstatic void rl_reset __P((struct rl_softc *)); 20440516Swpaulstatic int rl_list_tx_init __P((struct rl_softc *)); 20540516Swpaul 20640516Swpaul#define EE_SET(x) \ 20740516Swpaul CSR_WRITE_1(sc, RL_EECMD, \ 20840516Swpaul CSR_READ_1(sc, RL_EECMD) | x) 20940516Swpaul 21040516Swpaul#define EE_CLR(x) \ 21140516Swpaul CSR_WRITE_1(sc, RL_EECMD, \ 21240516Swpaul CSR_READ_1(sc, RL_EECMD) & ~x) 21340516Swpaul 21440516Swpaul/* 21540516Swpaul * Send a read command and address to the EEPROM, check for ACK. 21640516Swpaul */ 21740516Swpaulstatic void rl_eeprom_putbyte(sc, addr) 21840516Swpaul struct rl_softc *sc; 21941656Swpaul int addr; 22040516Swpaul{ 22140516Swpaul register int d, i; 22240516Swpaul 22340516Swpaul d = addr | RL_EECMD_READ; 22440516Swpaul 22540516Swpaul /* 22640516Swpaul * Feed in each bit and stobe the clock. 22740516Swpaul */ 22840516Swpaul for (i = 0x400; i; i >>= 1) { 22940516Swpaul if (d & i) { 23040516Swpaul EE_SET(RL_EE_DATAIN); 23140516Swpaul } else { 23240516Swpaul EE_CLR(RL_EE_DATAIN); 23340516Swpaul } 23440516Swpaul DELAY(100); 23540516Swpaul EE_SET(RL_EE_CLK); 23640516Swpaul DELAY(150); 23740516Swpaul EE_CLR(RL_EE_CLK); 23840516Swpaul DELAY(100); 23940516Swpaul } 24040516Swpaul 24140516Swpaul return; 24240516Swpaul} 24340516Swpaul 24440516Swpaul/* 24540516Swpaul * Read a word of data stored in the EEPROM at address 'addr.' 24640516Swpaul */ 24740516Swpaulstatic void rl_eeprom_getword(sc, addr, dest) 24840516Swpaul struct rl_softc *sc; 24941656Swpaul int addr; 25040516Swpaul u_int16_t *dest; 25140516Swpaul{ 25240516Swpaul register int i; 25340516Swpaul u_int16_t word = 0; 25440516Swpaul 25540516Swpaul /* Enter EEPROM access mode. */ 25640516Swpaul CSR_WRITE_1(sc, RL_EECMD, RL_EEMODE_PROGRAM|RL_EE_SEL); 25740516Swpaul 25840516Swpaul /* 25940516Swpaul * Send address of word we want to read. 26040516Swpaul */ 26140516Swpaul rl_eeprom_putbyte(sc, addr); 26240516Swpaul 26340516Swpaul CSR_WRITE_1(sc, RL_EECMD, RL_EEMODE_PROGRAM|RL_EE_SEL); 26440516Swpaul 26540516Swpaul /* 26640516Swpaul * Start reading bits from EEPROM. 26740516Swpaul */ 26840516Swpaul for (i = 0x8000; i; i >>= 1) { 26940516Swpaul EE_SET(RL_EE_CLK); 27040516Swpaul DELAY(100); 27140516Swpaul if (CSR_READ_1(sc, RL_EECMD) & RL_EE_DATAOUT) 27240516Swpaul word |= i; 27340516Swpaul EE_CLR(RL_EE_CLK); 27440516Swpaul DELAY(100); 27540516Swpaul } 27640516Swpaul 27740516Swpaul /* Turn off EEPROM access mode. */ 27840516Swpaul CSR_WRITE_1(sc, RL_EECMD, RL_EEMODE_OFF); 27940516Swpaul 28040516Swpaul *dest = word; 28140516Swpaul 28240516Swpaul return; 28340516Swpaul} 28440516Swpaul 28540516Swpaul/* 28640516Swpaul * Read a sequence of words from the EEPROM. 28740516Swpaul */ 28840516Swpaulstatic void rl_read_eeprom(sc, dest, off, cnt, swap) 28940516Swpaul struct rl_softc *sc; 29040516Swpaul caddr_t dest; 29140516Swpaul int off; 29240516Swpaul int cnt; 29340516Swpaul int swap; 29440516Swpaul{ 29540516Swpaul int i; 29640516Swpaul u_int16_t word = 0, *ptr; 29740516Swpaul 29840516Swpaul for (i = 0; i < cnt; i++) { 29940516Swpaul rl_eeprom_getword(sc, off + i, &word); 30040516Swpaul ptr = (u_int16_t *)(dest + (i * 2)); 30140516Swpaul if (swap) 30240516Swpaul *ptr = ntohs(word); 30340516Swpaul else 30440516Swpaul *ptr = word; 30540516Swpaul } 30640516Swpaul 30740516Swpaul return; 30840516Swpaul} 30940516Swpaul 31040516Swpaul 31140516Swpaul/* 31240516Swpaul * MII access routines are provided for the 8129, which 31340516Swpaul * doesn't have a built-in PHY. For the 8139, we fake things 31440516Swpaul * up by diverting rl_phy_readreg()/rl_phy_writereg() to the 31540516Swpaul * direct access PHY registers. 31640516Swpaul */ 31740516Swpaul#define MII_SET(x) \ 31840516Swpaul CSR_WRITE_1(sc, RL_MII, \ 31940516Swpaul CSR_READ_1(sc, RL_MII) | x) 32040516Swpaul 32140516Swpaul#define MII_CLR(x) \ 32240516Swpaul CSR_WRITE_1(sc, RL_MII, \ 32340516Swpaul CSR_READ_1(sc, RL_MII) & ~x) 32440516Swpaul 32540516Swpaul/* 32640516Swpaul * Sync the PHYs by setting data bit and strobing the clock 32 times. 32740516Swpaul */ 32840516Swpaulstatic void rl_mii_sync(sc) 32940516Swpaul struct rl_softc *sc; 33040516Swpaul{ 33140516Swpaul register int i; 33240516Swpaul 33340516Swpaul MII_SET(RL_MII_DIR|RL_MII_DATAOUT); 33440516Swpaul 33540516Swpaul for (i = 0; i < 32; i++) { 33640516Swpaul MII_SET(RL_MII_CLK); 33740516Swpaul DELAY(1); 33840516Swpaul MII_CLR(RL_MII_CLK); 33940516Swpaul DELAY(1); 34040516Swpaul } 34140516Swpaul 34240516Swpaul return; 34340516Swpaul} 34440516Swpaul 34540516Swpaul/* 34640516Swpaul * Clock a series of bits through the MII. 34740516Swpaul */ 34840516Swpaulstatic void rl_mii_send(sc, bits, cnt) 34940516Swpaul struct rl_softc *sc; 35040516Swpaul u_int32_t bits; 35140516Swpaul int cnt; 35240516Swpaul{ 35340516Swpaul int i; 35440516Swpaul 35540516Swpaul MII_CLR(RL_MII_CLK); 35640516Swpaul 35740516Swpaul for (i = (0x1 << (cnt - 1)); i; i >>= 1) { 35840516Swpaul if (bits & i) { 35940516Swpaul MII_SET(RL_MII_DATAOUT); 36040516Swpaul } else { 36140516Swpaul MII_CLR(RL_MII_DATAOUT); 36240516Swpaul } 36340516Swpaul DELAY(1); 36440516Swpaul MII_CLR(RL_MII_CLK); 36540516Swpaul DELAY(1); 36640516Swpaul MII_SET(RL_MII_CLK); 36740516Swpaul } 36840516Swpaul} 36940516Swpaul 37040516Swpaul/* 37140516Swpaul * Read an PHY register through the MII. 37240516Swpaul */ 37340516Swpaulstatic int rl_mii_readreg(sc, frame) 37440516Swpaul struct rl_softc *sc; 37540516Swpaul struct rl_mii_frame *frame; 37640516Swpaul 37740516Swpaul{ 37840516Swpaul int i, ack, s; 37940516Swpaul 38040516Swpaul s = splimp(); 38140516Swpaul 38240516Swpaul /* 38340516Swpaul * Set up frame for RX. 38440516Swpaul */ 38540516Swpaul frame->mii_stdelim = RL_MII_STARTDELIM; 38640516Swpaul frame->mii_opcode = RL_MII_READOP; 38740516Swpaul frame->mii_turnaround = 0; 38840516Swpaul frame->mii_data = 0; 38940516Swpaul 39040516Swpaul CSR_WRITE_2(sc, RL_MII, 0); 39140516Swpaul 39240516Swpaul /* 39340516Swpaul * Turn on data xmit. 39440516Swpaul */ 39540516Swpaul MII_SET(RL_MII_DIR); 39640516Swpaul 39740516Swpaul rl_mii_sync(sc); 39840516Swpaul 39940516Swpaul /* 40040516Swpaul * Send command/address info. 40140516Swpaul */ 40240516Swpaul rl_mii_send(sc, frame->mii_stdelim, 2); 40340516Swpaul rl_mii_send(sc, frame->mii_opcode, 2); 40440516Swpaul rl_mii_send(sc, frame->mii_phyaddr, 5); 40540516Swpaul rl_mii_send(sc, frame->mii_regaddr, 5); 40640516Swpaul 40740516Swpaul /* Idle bit */ 40840516Swpaul MII_CLR((RL_MII_CLK|RL_MII_DATAOUT)); 40940516Swpaul DELAY(1); 41040516Swpaul MII_SET(RL_MII_CLK); 41140516Swpaul DELAY(1); 41240516Swpaul 41340516Swpaul /* Turn off xmit. */ 41440516Swpaul MII_CLR(RL_MII_DIR); 41540516Swpaul 41640516Swpaul /* Check for ack */ 41740516Swpaul MII_CLR(RL_MII_CLK); 41840516Swpaul DELAY(1); 41940516Swpaul MII_SET(RL_MII_CLK); 42040516Swpaul DELAY(1); 42140516Swpaul ack = CSR_READ_2(sc, RL_MII) & RL_MII_DATAIN; 42240516Swpaul 42340516Swpaul /* 42440516Swpaul * Now try reading data bits. If the ack failed, we still 42540516Swpaul * need to clock through 16 cycles to keep the PHY(s) in sync. 42640516Swpaul */ 42740516Swpaul if (ack) { 42840516Swpaul for(i = 0; i < 16; i++) { 42940516Swpaul MII_CLR(RL_MII_CLK); 43040516Swpaul DELAY(1); 43140516Swpaul MII_SET(RL_MII_CLK); 43240516Swpaul DELAY(1); 43340516Swpaul } 43440516Swpaul goto fail; 43540516Swpaul } 43640516Swpaul 43740516Swpaul for (i = 0x8000; i; i >>= 1) { 43840516Swpaul MII_CLR(RL_MII_CLK); 43940516Swpaul DELAY(1); 44040516Swpaul if (!ack) { 44140516Swpaul if (CSR_READ_2(sc, RL_MII) & RL_MII_DATAIN) 44240516Swpaul frame->mii_data |= i; 44340516Swpaul DELAY(1); 44440516Swpaul } 44540516Swpaul MII_SET(RL_MII_CLK); 44640516Swpaul DELAY(1); 44740516Swpaul } 44840516Swpaul 44940516Swpaulfail: 45040516Swpaul 45140516Swpaul MII_CLR(RL_MII_CLK); 45240516Swpaul DELAY(1); 45340516Swpaul MII_SET(RL_MII_CLK); 45440516Swpaul DELAY(1); 45540516Swpaul 45640516Swpaul splx(s); 45740516Swpaul 45840516Swpaul if (ack) 45940516Swpaul return(1); 46040516Swpaul return(0); 46140516Swpaul} 46240516Swpaul 46340516Swpaul/* 46440516Swpaul * Write to a PHY register through the MII. 46540516Swpaul */ 46640516Swpaulstatic int rl_mii_writereg(sc, frame) 46740516Swpaul struct rl_softc *sc; 46840516Swpaul struct rl_mii_frame *frame; 46940516Swpaul 47040516Swpaul{ 47140516Swpaul int s; 47240516Swpaul 47340516Swpaul s = splimp(); 47440516Swpaul /* 47540516Swpaul * Set up frame for TX. 47640516Swpaul */ 47740516Swpaul 47840516Swpaul frame->mii_stdelim = RL_MII_STARTDELIM; 47940516Swpaul frame->mii_opcode = RL_MII_WRITEOP; 48040516Swpaul frame->mii_turnaround = RL_MII_TURNAROUND; 48140516Swpaul 48240516Swpaul /* 48340516Swpaul * Turn on data output. 48440516Swpaul */ 48540516Swpaul MII_SET(RL_MII_DIR); 48640516Swpaul 48740516Swpaul rl_mii_sync(sc); 48840516Swpaul 48940516Swpaul rl_mii_send(sc, frame->mii_stdelim, 2); 49040516Swpaul rl_mii_send(sc, frame->mii_opcode, 2); 49140516Swpaul rl_mii_send(sc, frame->mii_phyaddr, 5); 49240516Swpaul rl_mii_send(sc, frame->mii_regaddr, 5); 49340516Swpaul rl_mii_send(sc, frame->mii_turnaround, 2); 49440516Swpaul rl_mii_send(sc, frame->mii_data, 16); 49540516Swpaul 49640516Swpaul /* Idle bit. */ 49740516Swpaul MII_SET(RL_MII_CLK); 49840516Swpaul DELAY(1); 49940516Swpaul MII_CLR(RL_MII_CLK); 50040516Swpaul DELAY(1); 50140516Swpaul 50240516Swpaul /* 50340516Swpaul * Turn off xmit. 50440516Swpaul */ 50540516Swpaul MII_CLR(RL_MII_DIR); 50640516Swpaul 50740516Swpaul splx(s); 50840516Swpaul 50940516Swpaul return(0); 51040516Swpaul} 51140516Swpaul 51240516Swpaulstatic u_int16_t rl_phy_readreg(sc, reg) 51340516Swpaul struct rl_softc *sc; 51440516Swpaul int reg; 51540516Swpaul{ 51640516Swpaul struct rl_mii_frame frame; 51740516Swpaul u_int16_t rval = 0; 51840516Swpaul u_int16_t rl8139_reg = 0; 51940516Swpaul 52040516Swpaul if (sc->rl_type == RL_8139) { 52140516Swpaul switch(reg) { 52240516Swpaul case PHY_BMCR: 52340516Swpaul rl8139_reg = RL_BMCR; 52440516Swpaul break; 52540516Swpaul case PHY_BMSR: 52640516Swpaul rl8139_reg = RL_BMSR; 52740516Swpaul break; 52840516Swpaul case PHY_ANAR: 52940516Swpaul rl8139_reg = RL_ANAR; 53040516Swpaul break; 53140516Swpaul case PHY_LPAR: 53240516Swpaul rl8139_reg = RL_LPAR; 53340516Swpaul break; 53440516Swpaul default: 53540516Swpaul printf("rl%d: bad phy register\n", sc->rl_unit); 53640516Swpaul return(0); 53740516Swpaul } 53840516Swpaul rval = CSR_READ_2(sc, rl8139_reg); 53940516Swpaul return(rval); 54040516Swpaul } 54140516Swpaul 54240516Swpaul bzero((char *)&frame, sizeof(frame)); 54340516Swpaul 54440516Swpaul frame.mii_phyaddr = sc->rl_phy_addr; 54540516Swpaul frame.mii_regaddr = reg; 54640516Swpaul rl_mii_readreg(sc, &frame); 54740516Swpaul 54840516Swpaul return(frame.mii_data); 54940516Swpaul} 55040516Swpaul 55140516Swpaulstatic void rl_phy_writereg(sc, reg, data) 55240516Swpaul struct rl_softc *sc; 55341656Swpaul int reg; 55441656Swpaul int data; 55540516Swpaul{ 55640516Swpaul struct rl_mii_frame frame; 55740516Swpaul u_int16_t rl8139_reg = 0; 55840516Swpaul 55940516Swpaul if (sc->rl_type == RL_8139) { 56040516Swpaul switch(reg) { 56140516Swpaul case PHY_BMCR: 56240516Swpaul rl8139_reg = RL_BMCR; 56340516Swpaul break; 56440516Swpaul case PHY_BMSR: 56540516Swpaul rl8139_reg = RL_BMSR; 56640516Swpaul break; 56740516Swpaul case PHY_ANAR: 56840516Swpaul rl8139_reg = RL_ANAR; 56940516Swpaul break; 57040516Swpaul case PHY_LPAR: 57140516Swpaul rl8139_reg = RL_LPAR; 57240516Swpaul break; 57340516Swpaul default: 57440516Swpaul printf("rl%d: bad phy register\n", sc->rl_unit); 57540516Swpaul return; 57640516Swpaul } 57740516Swpaul CSR_WRITE_2(sc, rl8139_reg, data); 57841273Swpaul return; 57940516Swpaul } 58040516Swpaul 58140516Swpaul bzero((char *)&frame, sizeof(frame)); 58240516Swpaul 58340516Swpaul frame.mii_phyaddr = sc->rl_phy_addr; 58440516Swpaul frame.mii_regaddr = reg; 58540516Swpaul frame.mii_data = data; 58640516Swpaul 58740516Swpaul rl_mii_writereg(sc, &frame); 58840516Swpaul 58940516Swpaul return; 59040516Swpaul} 59140516Swpaul 59240516Swpaul/* 59343062Swpaul * Calculate CRC of a multicast group address, return the upper 6 bits. 59440516Swpaul */ 59540516Swpaulstatic u_int8_t rl_calchash(addr) 59641656Swpaul caddr_t addr; 59740516Swpaul{ 59840516Swpaul u_int32_t crc, carry; 59940516Swpaul int i, j; 60040516Swpaul u_int8_t c; 60140516Swpaul 60240516Swpaul /* Compute CRC for the address value. */ 60340516Swpaul crc = 0xFFFFFFFF; /* initial value */ 60440516Swpaul 60540516Swpaul for (i = 0; i < 6; i++) { 60640516Swpaul c = *(addr + i); 60740516Swpaul for (j = 0; j < 8; j++) { 60840516Swpaul carry = ((crc & 0x80000000) ? 1 : 0) ^ (c & 0x01); 60940516Swpaul crc <<= 1; 61040516Swpaul c >>= 1; 61140516Swpaul if (carry) 61240516Swpaul crc = (crc ^ 0x04c11db6) | carry; 61340516Swpaul } 61440516Swpaul } 61540516Swpaul 61640516Swpaul /* return the filter bit position */ 61743062Swpaul return(crc >> 26); 61840516Swpaul} 61940516Swpaul 62040516Swpaul/* 62140516Swpaul * Program the 64-bit multicast hash filter. 62240516Swpaul */ 62340516Swpaulstatic void rl_setmulti(sc) 62440516Swpaul struct rl_softc *sc; 62540516Swpaul{ 62640516Swpaul struct ifnet *ifp; 62740516Swpaul int h = 0; 62840516Swpaul u_int32_t hashes[2] = { 0, 0 }; 62940516Swpaul struct ifmultiaddr *ifma; 63040516Swpaul u_int32_t rxfilt; 63140516Swpaul int mcnt = 0; 63240516Swpaul 63340516Swpaul ifp = &sc->arpcom.ac_if; 63440516Swpaul 63540516Swpaul rxfilt = CSR_READ_4(sc, RL_RXCFG); 63640516Swpaul 63743062Swpaul if (ifp->if_flags & IFF_ALLMULTI || ifp->if_flags & IFF_PROMISC) { 63840516Swpaul rxfilt |= RL_RXCFG_RX_MULTI; 63940516Swpaul CSR_WRITE_4(sc, RL_RXCFG, rxfilt); 64040516Swpaul CSR_WRITE_4(sc, RL_MAR0, 0xFFFFFFFF); 64140516Swpaul CSR_WRITE_4(sc, RL_MAR4, 0xFFFFFFFF); 64240516Swpaul return; 64340516Swpaul } 64440516Swpaul 64540516Swpaul /* first, zot all the existing hash bits */ 64640516Swpaul CSR_WRITE_4(sc, RL_MAR0, 0); 64740516Swpaul CSR_WRITE_4(sc, RL_MAR4, 0); 64840516Swpaul 64940516Swpaul /* now program new ones */ 65040516Swpaul for (ifma = ifp->if_multiaddrs.lh_first; ifma != NULL; 65140516Swpaul ifma = ifma->ifma_link.le_next) { 65240516Swpaul if (ifma->ifma_addr->sa_family != AF_LINK) 65340516Swpaul continue; 65440516Swpaul h = rl_calchash(LLADDR((struct sockaddr_dl *)ifma->ifma_addr)); 65540516Swpaul if (h < 32) 65640516Swpaul hashes[0] |= (1 << h); 65740516Swpaul else 65840516Swpaul hashes[1] |= (1 << (h - 32)); 65940516Swpaul mcnt++; 66040516Swpaul } 66140516Swpaul 66240516Swpaul if (mcnt) 66340516Swpaul rxfilt |= RL_RXCFG_RX_MULTI; 66440516Swpaul else 66540516Swpaul rxfilt &= ~RL_RXCFG_RX_MULTI; 66640516Swpaul 66740516Swpaul CSR_WRITE_4(sc, RL_RXCFG, rxfilt); 66840516Swpaul CSR_WRITE_4(sc, RL_MAR0, hashes[0]); 66940516Swpaul CSR_WRITE_4(sc, RL_MAR4, hashes[1]); 67040516Swpaul 67140516Swpaul return; 67240516Swpaul} 67340516Swpaul 67440516Swpaul/* 67540516Swpaul * Initiate an autonegotiation session. 67640516Swpaul */ 67740516Swpaulstatic void rl_autoneg_xmit(sc) 67840516Swpaul struct rl_softc *sc; 67940516Swpaul{ 68040516Swpaul u_int16_t phy_sts; 68140516Swpaul 68240516Swpaul rl_phy_writereg(sc, PHY_BMCR, PHY_BMCR_RESET); 68340516Swpaul DELAY(500); 68440516Swpaul while(rl_phy_readreg(sc, PHY_BMCR) 68540516Swpaul & PHY_BMCR_RESET); 68640516Swpaul 68740516Swpaul phy_sts = rl_phy_readreg(sc, PHY_BMCR); 68840516Swpaul phy_sts |= PHY_BMCR_AUTONEGENBL|PHY_BMCR_AUTONEGRSTR; 68940516Swpaul rl_phy_writereg(sc, PHY_BMCR, phy_sts); 69040516Swpaul 69140516Swpaul return; 69240516Swpaul} 69340516Swpaul 69440516Swpaul/* 69540516Swpaul * Invoke autonegotiation on a PHY. Also used with the 8139 internal 69640516Swpaul * transceiver. 69740516Swpaul */ 69840516Swpaulstatic void rl_autoneg_mii(sc, flag, verbose) 69940516Swpaul struct rl_softc *sc; 70040516Swpaul int flag; 70140516Swpaul int verbose; 70240516Swpaul{ 70340516Swpaul u_int16_t phy_sts = 0, media, advert, ability; 70440516Swpaul struct ifnet *ifp; 70540516Swpaul struct ifmedia *ifm; 70640516Swpaul 70740516Swpaul ifm = &sc->ifmedia; 70840516Swpaul ifp = &sc->arpcom.ac_if; 70940516Swpaul 71040516Swpaul /* 71140516Swpaul * The 100baseT4 PHY sometimes has the 'autoneg supported' 71240516Swpaul * bit cleared in the status register, but has the 'autoneg enabled' 71340516Swpaul * bit set in the control register. This is a contradiction, and 71440516Swpaul * I'm not sure how to handle it. If you want to force an attempt 71540516Swpaul * to autoneg for 100baseT4 PHYs, #define FORCE_AUTONEG_TFOUR 71640516Swpaul * and see what happens. 71740516Swpaul */ 71840516Swpaul#ifndef FORCE_AUTONEG_TFOUR 71940516Swpaul /* 72040516Swpaul * First, see if autoneg is supported. If not, there's 72140516Swpaul * no point in continuing. 72240516Swpaul */ 72340516Swpaul phy_sts = rl_phy_readreg(sc, PHY_BMSR); 72440516Swpaul if (!(phy_sts & PHY_BMSR_CANAUTONEG)) { 72540516Swpaul if (verbose) 72640516Swpaul printf("rl%d: autonegotiation not supported\n", 72740516Swpaul sc->rl_unit); 72840516Swpaul return; 72940516Swpaul } 73040516Swpaul#endif 73140516Swpaul 73240516Swpaul switch (flag) { 73340516Swpaul case RL_FLAG_FORCEDELAY: 73440516Swpaul /* 73540516Swpaul * XXX Never use this option anywhere but in the probe 73640516Swpaul * routine: making the kernel stop dead in its tracks 73740516Swpaul * for three whole seconds after we've gone multi-user 73840516Swpaul * is really bad manners. 73940516Swpaul */ 74040516Swpaul rl_autoneg_xmit(sc); 74140516Swpaul DELAY(5000000); 74240516Swpaul break; 74340516Swpaul case RL_FLAG_SCHEDDELAY: 74440516Swpaul /* 74540516Swpaul * Wait for the transmitter to go idle before starting 74640516Swpaul * an autoneg session, otherwise rl_start() may clobber 74740516Swpaul * our timeout, and we don't want to allow transmission 74840516Swpaul * during an autoneg session since that can screw it up. 74940516Swpaul */ 75045633Swpaul if (sc->rl_cdata.last_tx != sc->rl_cdata.cur_tx) { 75140516Swpaul sc->rl_want_auto = 1; 75240516Swpaul return; 75340516Swpaul } 75440516Swpaul rl_autoneg_xmit(sc); 75540516Swpaul ifp->if_timer = 5; 75640516Swpaul sc->rl_autoneg = 1; 75740516Swpaul sc->rl_want_auto = 0; 75840516Swpaul return; 75940516Swpaul break; 76040516Swpaul case RL_FLAG_DELAYTIMEO: 76140516Swpaul ifp->if_timer = 0; 76240516Swpaul sc->rl_autoneg = 0; 76340516Swpaul break; 76440516Swpaul default: 76540516Swpaul printf("rl%d: invalid autoneg flag: %d\n", sc->rl_unit, flag); 76640516Swpaul return; 76740516Swpaul } 76840516Swpaul 76940516Swpaul if (rl_phy_readreg(sc, PHY_BMSR) & PHY_BMSR_AUTONEGCOMP) { 77040516Swpaul if (verbose) 77140516Swpaul printf("rl%d: autoneg complete, ", sc->rl_unit); 77240516Swpaul phy_sts = rl_phy_readreg(sc, PHY_BMSR); 77340516Swpaul } else { 77440516Swpaul if (verbose) 77540516Swpaul printf("rl%d: autoneg not complete, ", sc->rl_unit); 77640516Swpaul } 77740516Swpaul 77840516Swpaul media = rl_phy_readreg(sc, PHY_BMCR); 77940516Swpaul 78040516Swpaul /* Link is good. Report modes and set duplex mode. */ 78140516Swpaul if (rl_phy_readreg(sc, PHY_BMSR) & PHY_BMSR_LINKSTAT) { 78240516Swpaul if (verbose) 78340516Swpaul printf("link status good "); 78440516Swpaul advert = rl_phy_readreg(sc, PHY_ANAR); 78540516Swpaul ability = rl_phy_readreg(sc, PHY_LPAR); 78640516Swpaul 78740516Swpaul if (advert & PHY_ANAR_100BT4 && ability & PHY_ANAR_100BT4) { 78840516Swpaul ifm->ifm_media = IFM_ETHER|IFM_100_T4; 78940516Swpaul media |= PHY_BMCR_SPEEDSEL; 79040516Swpaul media &= ~PHY_BMCR_DUPLEX; 79140516Swpaul printf("(100baseT4)\n"); 79240516Swpaul } else if (advert & PHY_ANAR_100BTXFULL && 79340516Swpaul ability & PHY_ANAR_100BTXFULL) { 79440516Swpaul ifm->ifm_media = IFM_ETHER|IFM_100_TX|IFM_FDX; 79540516Swpaul media |= PHY_BMCR_SPEEDSEL; 79640516Swpaul media |= PHY_BMCR_DUPLEX; 79740516Swpaul printf("(full-duplex, 100Mbps)\n"); 79840516Swpaul } else if (advert & PHY_ANAR_100BTXHALF && 79940516Swpaul ability & PHY_ANAR_100BTXHALF) { 80040516Swpaul ifm->ifm_media = IFM_ETHER|IFM_100_TX|IFM_HDX; 80140516Swpaul media |= PHY_BMCR_SPEEDSEL; 80240516Swpaul media &= ~PHY_BMCR_DUPLEX; 80340516Swpaul printf("(half-duplex, 100Mbps)\n"); 80440516Swpaul } else if (advert & PHY_ANAR_10BTFULL && 80540516Swpaul ability & PHY_ANAR_10BTFULL) { 80640516Swpaul ifm->ifm_media = IFM_ETHER|IFM_10_T|IFM_FDX; 80740516Swpaul media &= ~PHY_BMCR_SPEEDSEL; 80840516Swpaul media |= PHY_BMCR_DUPLEX; 80940516Swpaul printf("(full-duplex, 10Mbps)\n"); 81041656Swpaul } else { 81140516Swpaul ifm->ifm_media = IFM_ETHER|IFM_10_T|IFM_HDX; 81240516Swpaul media &= ~PHY_BMCR_SPEEDSEL; 81340516Swpaul media &= ~PHY_BMCR_DUPLEX; 81440516Swpaul printf("(half-duplex, 10Mbps)\n"); 81540516Swpaul } 81640516Swpaul 81740516Swpaul /* Set ASIC's duplex mode to match the PHY. */ 81840516Swpaul rl_phy_writereg(sc, PHY_BMCR, media); 81940516Swpaul } else { 82040516Swpaul if (verbose) 82140516Swpaul printf("no carrier\n"); 82240516Swpaul } 82340516Swpaul 82440516Swpaul rl_init(sc); 82540516Swpaul 82640516Swpaul if (sc->rl_tx_pend) { 82740516Swpaul sc->rl_autoneg = 0; 82840516Swpaul sc->rl_tx_pend = 0; 82940516Swpaul rl_start(ifp); 83040516Swpaul } 83140516Swpaul 83240516Swpaul return; 83340516Swpaul} 83440516Swpaul 83540516Swpaulstatic void rl_getmode_mii(sc) 83640516Swpaul struct rl_softc *sc; 83740516Swpaul{ 83840516Swpaul u_int16_t bmsr; 83940516Swpaul struct ifnet *ifp; 84040516Swpaul 84140516Swpaul ifp = &sc->arpcom.ac_if; 84240516Swpaul 84340516Swpaul bmsr = rl_phy_readreg(sc, PHY_BMSR); 84440516Swpaul if (bootverbose) 84540516Swpaul printf("rl%d: PHY status word: %x\n", sc->rl_unit, bmsr); 84640516Swpaul 84740516Swpaul /* fallback */ 84840516Swpaul sc->ifmedia.ifm_media = IFM_ETHER|IFM_10_T|IFM_HDX; 84940516Swpaul 85040516Swpaul if (bmsr & PHY_BMSR_10BTHALF) { 85140516Swpaul if (bootverbose) 85240516Swpaul printf("rl%d: 10Mbps half-duplex mode supported\n", 85340516Swpaul sc->rl_unit); 85440516Swpaul ifmedia_add(&sc->ifmedia, 85540516Swpaul IFM_ETHER|IFM_10_T|IFM_HDX, 0, NULL); 85640516Swpaul ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_10_T, 0, NULL); 85740516Swpaul } 85840516Swpaul 85940516Swpaul if (bmsr & PHY_BMSR_10BTFULL) { 86040516Swpaul if (bootverbose) 86140516Swpaul printf("rl%d: 10Mbps full-duplex mode supported\n", 86240516Swpaul sc->rl_unit); 86340516Swpaul ifmedia_add(&sc->ifmedia, 86440516Swpaul IFM_ETHER|IFM_10_T|IFM_FDX, 0, NULL); 86540516Swpaul sc->ifmedia.ifm_media = IFM_ETHER|IFM_10_T|IFM_FDX; 86640516Swpaul } 86740516Swpaul 86840516Swpaul if (bmsr & PHY_BMSR_100BTXHALF) { 86940516Swpaul if (bootverbose) 87040516Swpaul printf("rl%d: 100Mbps half-duplex mode supported\n", 87140516Swpaul sc->rl_unit); 87240516Swpaul ifp->if_baudrate = 100000000; 87340516Swpaul ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_100_TX, 0, NULL); 87440516Swpaul ifmedia_add(&sc->ifmedia, 87540516Swpaul IFM_ETHER|IFM_100_TX|IFM_HDX, 0, NULL); 87640516Swpaul sc->ifmedia.ifm_media = IFM_ETHER|IFM_100_TX|IFM_HDX; 87740516Swpaul } 87840516Swpaul 87940516Swpaul if (bmsr & PHY_BMSR_100BTXFULL) { 88040516Swpaul if (bootverbose) 88140516Swpaul printf("rl%d: 100Mbps full-duplex mode supported\n", 88240516Swpaul sc->rl_unit); 88340516Swpaul ifp->if_baudrate = 100000000; 88440516Swpaul ifmedia_add(&sc->ifmedia, 88540516Swpaul IFM_ETHER|IFM_100_TX|IFM_FDX, 0, NULL); 88640516Swpaul sc->ifmedia.ifm_media = IFM_ETHER|IFM_100_TX|IFM_FDX; 88740516Swpaul } 88840516Swpaul 88940516Swpaul /* Some also support 100BaseT4. */ 89040516Swpaul if (bmsr & PHY_BMSR_100BT4) { 89140516Swpaul if (bootverbose) 89240516Swpaul printf("rl%d: 100baseT4 mode supported\n", sc->rl_unit); 89340516Swpaul ifp->if_baudrate = 100000000; 89440516Swpaul ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_100_T4, 0, NULL); 89540516Swpaul sc->ifmedia.ifm_media = IFM_ETHER|IFM_100_T4; 89640516Swpaul#ifdef FORCE_AUTONEG_TFOUR 89740516Swpaul if (bootverbose) 89840516Swpaul printf("rl%d: forcing on autoneg support for BT4\n", 89940516Swpaul sc->rl_unit); 90040516Swpaul ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_AUTO, 0 NULL): 90140516Swpaul sc->ifmedia.ifm_media = IFM_ETHER|IFM_AUTO; 90240516Swpaul#endif 90340516Swpaul } 90440516Swpaul 90540516Swpaul if (bmsr & PHY_BMSR_CANAUTONEG) { 90640516Swpaul if (bootverbose) 90740516Swpaul printf("rl%d: autoneg supported\n", sc->rl_unit); 90840516Swpaul ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_AUTO, 0, NULL); 90940516Swpaul sc->ifmedia.ifm_media = IFM_ETHER|IFM_AUTO; 91040516Swpaul } 91140516Swpaul 91240516Swpaul return; 91340516Swpaul} 91440516Swpaul 91540516Swpaul/* 91640516Swpaul * Set speed and duplex mode. 91740516Swpaul */ 91840516Swpaulstatic void rl_setmode_mii(sc, media) 91940516Swpaul struct rl_softc *sc; 92040516Swpaul int media; 92140516Swpaul{ 92240516Swpaul u_int16_t bmcr; 92340516Swpaul 92440516Swpaul printf("rl%d: selecting MII, ", sc->rl_unit); 92540516Swpaul 92640516Swpaul bmcr = rl_phy_readreg(sc, PHY_BMCR); 92740516Swpaul 92840516Swpaul bmcr &= ~(PHY_BMCR_AUTONEGENBL|PHY_BMCR_SPEEDSEL| 92940516Swpaul PHY_BMCR_DUPLEX|PHY_BMCR_LOOPBK); 93040516Swpaul 93140516Swpaul if (IFM_SUBTYPE(media) == IFM_100_T4) { 93240516Swpaul printf("100Mbps/T4, half-duplex\n"); 93340516Swpaul bmcr |= PHY_BMCR_SPEEDSEL; 93440516Swpaul bmcr &= ~PHY_BMCR_DUPLEX; 93540516Swpaul } 93640516Swpaul 93740516Swpaul if (IFM_SUBTYPE(media) == IFM_100_TX) { 93840516Swpaul printf("100Mbps, "); 93940516Swpaul bmcr |= PHY_BMCR_SPEEDSEL; 94040516Swpaul } 94140516Swpaul 94240516Swpaul if (IFM_SUBTYPE(media) == IFM_10_T) { 94340516Swpaul printf("10Mbps, "); 94440516Swpaul bmcr &= ~PHY_BMCR_SPEEDSEL; 94540516Swpaul } 94640516Swpaul 94740516Swpaul if ((media & IFM_GMASK) == IFM_FDX) { 94840516Swpaul printf("full duplex\n"); 94940516Swpaul bmcr |= PHY_BMCR_DUPLEX; 95040516Swpaul } else { 95140516Swpaul printf("half duplex\n"); 95240516Swpaul bmcr &= ~PHY_BMCR_DUPLEX; 95340516Swpaul } 95440516Swpaul 95540516Swpaul rl_phy_writereg(sc, PHY_BMCR, bmcr); 95640516Swpaul 95740516Swpaul return; 95840516Swpaul} 95940516Swpaul 96040516Swpaulstatic void rl_reset(sc) 96140516Swpaul struct rl_softc *sc; 96240516Swpaul{ 96340516Swpaul register int i; 96440516Swpaul 96540516Swpaul CSR_WRITE_1(sc, RL_COMMAND, RL_CMD_RESET); 96640516Swpaul 96740516Swpaul for (i = 0; i < RL_TIMEOUT; i++) { 96840516Swpaul DELAY(10); 96940516Swpaul if (!(CSR_READ_1(sc, RL_COMMAND) & RL_CMD_RESET)) 97040516Swpaul break; 97140516Swpaul } 97240516Swpaul if (i == RL_TIMEOUT) 97340516Swpaul printf("rl%d: reset never completed!\n", sc->rl_unit); 97440516Swpaul 97540516Swpaul return; 97640516Swpaul} 97740516Swpaul 97840516Swpaul/* 97940516Swpaul * Probe for a RealTek 8129/8139 chip. Check the PCI vendor and device 98040516Swpaul * IDs against our list and return a device name if we find a match. 98140516Swpaul */ 98241771Sdillonstatic const char * 98340516Swpaulrl_probe(config_id, device_id) 98440516Swpaul pcici_t config_id; 98540516Swpaul pcidi_t device_id; 98640516Swpaul{ 98740516Swpaul struct rl_type *t; 98840516Swpaul 98940516Swpaul t = rl_devs; 99040516Swpaul 99140516Swpaul while(t->rl_name != NULL) { 99240516Swpaul if ((device_id & 0xFFFF) == t->rl_vid && 99340516Swpaul ((device_id >> 16) & 0xFFFF) == t->rl_did) { 99440516Swpaul return(t->rl_name); 99540516Swpaul } 99640516Swpaul t++; 99740516Swpaul } 99840516Swpaul 99940516Swpaul return(NULL); 100040516Swpaul} 100140516Swpaul 100240516Swpaul/* 100340516Swpaul * Attach the interface. Allocate softc structures, do ifmedia 100440516Swpaul * setup and ethernet/BPF attach. 100540516Swpaul */ 100640516Swpaulstatic void 100740516Swpaulrl_attach(config_id, unit) 100840516Swpaul pcici_t config_id; 100940516Swpaul int unit; 101040516Swpaul{ 101140516Swpaul int s, i; 101240516Swpaul#ifndef RL_USEIOSPACE 101340516Swpaul vm_offset_t pbase, vbase; 101440516Swpaul#endif 101540516Swpaul u_char eaddr[ETHER_ADDR_LEN]; 101640516Swpaul u_int32_t command; 101740516Swpaul struct rl_softc *sc; 101840516Swpaul struct ifnet *ifp; 101940516Swpaul int media = IFM_ETHER|IFM_100_TX|IFM_FDX; 102040516Swpaul struct rl_type *p; 102140516Swpaul u_int16_t phy_vid, phy_did, phy_sts; 102240516Swpaul u_int16_t rl_did = 0; 102340516Swpaul 102440516Swpaul s = splimp(); 102540516Swpaul 102640516Swpaul sc = malloc(sizeof(struct rl_softc), M_DEVBUF, M_NOWAIT); 102740516Swpaul if (sc == NULL) { 102840516Swpaul printf("rl%d: no memory for softc struct!\n", unit); 102945633Swpaul goto fail; 103040516Swpaul } 103140516Swpaul bzero(sc, sizeof(struct rl_softc)); 103240516Swpaul 103340516Swpaul /* 103440516Swpaul * Handle power management nonsense. 103540516Swpaul */ 103640516Swpaul 103740516Swpaul command = pci_conf_read(config_id, RL_PCI_CAPID) & 0x000000FF; 103840516Swpaul if (command == 0x01) { 103940516Swpaul 104040516Swpaul command = pci_conf_read(config_id, RL_PCI_PWRMGMTCTRL); 104140516Swpaul if (command & RL_PSTATE_MASK) { 104240516Swpaul u_int32_t iobase, membase, irq; 104340516Swpaul 104440516Swpaul /* Save important PCI config data. */ 104540516Swpaul iobase = pci_conf_read(config_id, RL_PCI_LOIO); 104640516Swpaul membase = pci_conf_read(config_id, RL_PCI_LOMEM); 104740516Swpaul irq = pci_conf_read(config_id, RL_PCI_INTLINE); 104840516Swpaul 104940516Swpaul /* Reset the power state. */ 105040516Swpaul printf("rl%d: chip is is in D%d power mode " 105140516Swpaul "-- setting to D0\n", unit, command & RL_PSTATE_MASK); 105240516Swpaul command &= 0xFFFFFFFC; 105340516Swpaul pci_conf_write(config_id, RL_PCI_PWRMGMTCTRL, command); 105440516Swpaul 105540516Swpaul /* Restore PCI config data. */ 105640516Swpaul pci_conf_write(config_id, RL_PCI_LOIO, iobase); 105740516Swpaul pci_conf_write(config_id, RL_PCI_LOMEM, membase); 105840516Swpaul pci_conf_write(config_id, RL_PCI_INTLINE, irq); 105940516Swpaul } 106040516Swpaul } 106140516Swpaul 106240516Swpaul /* 106340516Swpaul * Map control/status registers. 106440516Swpaul */ 106540516Swpaul command = pci_conf_read(config_id, PCI_COMMAND_STATUS_REG); 106640516Swpaul command |= (PCIM_CMD_PORTEN|PCIM_CMD_MEMEN|PCIM_CMD_BUSMASTEREN); 106740516Swpaul pci_conf_write(config_id, PCI_COMMAND_STATUS_REG, command); 106840516Swpaul command = pci_conf_read(config_id, PCI_COMMAND_STATUS_REG); 106940516Swpaul 107040516Swpaul#ifdef RL_USEIOSPACE 107140516Swpaul if (!(command & PCIM_CMD_PORTEN)) { 107240516Swpaul printf("rl%d: failed to enable I/O ports!\n", unit); 107340516Swpaul free(sc, M_DEVBUF); 107440516Swpaul goto fail; 107540516Swpaul } 107640516Swpaul 107741569Swpaul if (!pci_map_port(config_id, RL_PCI_LOIO, 107848443Speter (pci_port_t *)&(sc->rl_bhandle))) { 107941569Swpaul printf ("rl%d: couldn't map ports\n", unit); 108041569Swpaul goto fail; 108141569Swpaul } 108248028Swpaul#ifdef __i386__ 108341569Swpaul sc->rl_btag = I386_BUS_SPACE_IO; 108448028Swpaul#endif 108548028Swpaul#ifdef __alpha__ 108648028Swpaul sc->rl_btag = ALPHA_BUS_SPACE_IO; 108748028Swpaul#endif 108840516Swpaul#else 108940516Swpaul if (!(command & PCIM_CMD_MEMEN)) { 109040516Swpaul printf("rl%d: failed to enable memory mapping!\n", unit); 109140516Swpaul goto fail; 109240516Swpaul } 109340516Swpaul 109440516Swpaul if (!pci_map_mem(config_id, RL_PCI_LOMEM, &vbase, &pbase)) { 109540516Swpaul printf ("rl%d: couldn't map memory\n", unit); 109640516Swpaul goto fail; 109740516Swpaul } 109848028Swpaul#ifdef __i386__ 109941569Swpaul sc->rl_btag = I386_BUS_SPACE_MEM; 110048028Swpaul#endif 110148028Swpaul#ifdef __alpha__ 110248028Swpaul sc->rl_btag = ALPHA_BUS_SPACE_MEM; 110348028Swpaul#endif 110441569Swpaul sc->rl_bhandle = vbase; 110540516Swpaul#endif 110640516Swpaul 110740516Swpaul /* Allocate interrupt */ 110840516Swpaul if (!pci_map_int(config_id, rl_intr, sc, &net_imask)) { 110940516Swpaul printf("rl%d: couldn't map interrupt\n", unit); 111040516Swpaul goto fail; 111140516Swpaul } 111240516Swpaul 111340516Swpaul /* Reset the adapter. */ 111440516Swpaul rl_reset(sc); 111540516Swpaul 111640516Swpaul /* 111740516Swpaul * Get station address from the EEPROM. 111840516Swpaul */ 111940516Swpaul rl_read_eeprom(sc, (caddr_t)&eaddr, RL_EE_EADDR, 3, 0); 112040516Swpaul 112140516Swpaul /* 112240516Swpaul * A RealTek chip was detected. Inform the world. 112340516Swpaul */ 112440516Swpaul printf("rl%d: Ethernet address: %6D\n", unit, eaddr, ":"); 112540516Swpaul 112640516Swpaul sc->rl_unit = unit; 112740516Swpaul bcopy(eaddr, (char *)&sc->arpcom.ac_enaddr, ETHER_ADDR_LEN); 112840516Swpaul 112940516Swpaul /* 113040516Swpaul * Now read the exact device type from the EEPROM to find 113140516Swpaul * out if it's an 8129 or 8139. 113240516Swpaul */ 113340516Swpaul rl_read_eeprom(sc, (caddr_t)&rl_did, RL_EE_PCI_DID, 1, 0); 113440516Swpaul 113544238Swpaul if (rl_did == RT_DEVICEID_8139 || rl_did == ACCTON_DEVICEID_5030 || 113649001Swpaul rl_did == DELTA_DEVICEID_8139 || rl_did == ADDTRON_DEVICEID_8139) 113740516Swpaul sc->rl_type = RL_8139; 113840516Swpaul else if (rl_did == RT_DEVICEID_8129) 113940516Swpaul sc->rl_type = RL_8129; 114040516Swpaul else { 114140516Swpaul printf("rl%d: unknown device ID: %x\n", unit, rl_did); 114240516Swpaul free(sc, M_DEVBUF); 114340516Swpaul goto fail; 114440516Swpaul } 114540516Swpaul 114648028Swpaul sc->rl_cdata.rl_rx_buf = contigmalloc(RL_RXBUFLEN + 32, M_DEVBUF, 114740516Swpaul M_NOWAIT, 0x100000, 0xffffffff, PAGE_SIZE, 0); 114840516Swpaul 114940516Swpaul if (sc->rl_cdata.rl_rx_buf == NULL) { 115040516Swpaul free(sc, M_DEVBUF); 115140516Swpaul printf("rl%d: no memory for list buffers!\n", unit); 115240516Swpaul goto fail; 115340516Swpaul } 115440516Swpaul 115548028Swpaul /* Leave a few bytes before the start of the RX ring buffer. */ 115648028Swpaul sc->rl_cdata.rl_rx_buf_ptr = sc->rl_cdata.rl_rx_buf; 115748028Swpaul sc->rl_cdata.rl_rx_buf += sizeof(u_int64_t); 115848028Swpaul 115940516Swpaul ifp = &sc->arpcom.ac_if; 116040516Swpaul ifp->if_softc = sc; 116140516Swpaul ifp->if_unit = unit; 116240516Swpaul ifp->if_name = "rl"; 116340516Swpaul ifp->if_mtu = ETHERMTU; 116440516Swpaul ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 116540516Swpaul ifp->if_ioctl = rl_ioctl; 116640516Swpaul ifp->if_output = ether_output; 116740516Swpaul ifp->if_start = rl_start; 116840516Swpaul ifp->if_watchdog = rl_watchdog; 116940516Swpaul ifp->if_init = rl_init; 117040516Swpaul ifp->if_baudrate = 10000000; 117145633Swpaul ifp->if_snd.ifq_maxlen = IFQ_MAXLEN; 117240516Swpaul 117340516Swpaul if (sc->rl_type == RL_8129) { 117440516Swpaul if (bootverbose) 117540516Swpaul printf("rl%d: probing for a PHY\n", sc->rl_unit); 117640516Swpaul for (i = RL_PHYADDR_MIN; i < RL_PHYADDR_MAX + 1; i++) { 117740516Swpaul if (bootverbose) 117840516Swpaul printf("rl%d: checking address: %d\n", 117940516Swpaul sc->rl_unit, i); 118040516Swpaul sc->rl_phy_addr = i; 118140516Swpaul rl_phy_writereg(sc, PHY_BMCR, PHY_BMCR_RESET); 118240516Swpaul DELAY(500); 118340516Swpaul while(rl_phy_readreg(sc, PHY_BMCR) 118440516Swpaul & PHY_BMCR_RESET); 118540516Swpaul if ((phy_sts = rl_phy_readreg(sc, PHY_BMSR))) 118640516Swpaul break; 118740516Swpaul } 118840516Swpaul if (phy_sts) { 118940516Swpaul phy_vid = rl_phy_readreg(sc, PHY_VENID); 119040516Swpaul phy_did = rl_phy_readreg(sc, PHY_DEVID); 119140516Swpaul if (bootverbose) 119240516Swpaul printf("rl%d: found PHY at address %d, ", 119340516Swpaul sc->rl_unit, sc->rl_phy_addr); 119440516Swpaul if (bootverbose) 119540516Swpaul printf("vendor id: %x device id: %x\n", 119640516Swpaul phy_vid, phy_did); 119740516Swpaul p = rl_phys; 119840516Swpaul while(p->rl_vid) { 119940516Swpaul if (phy_vid == p->rl_vid && 120040516Swpaul (phy_did | 0x000F) == p->rl_did) { 120140516Swpaul sc->rl_pinfo = p; 120240516Swpaul break; 120340516Swpaul } 120440516Swpaul p++; 120540516Swpaul } 120640516Swpaul if (sc->rl_pinfo == NULL) 120740516Swpaul sc->rl_pinfo = &rl_phys[PHY_UNKNOWN]; 120840516Swpaul if (bootverbose) 120940516Swpaul printf("rl%d: PHY type: %s\n", 121040516Swpaul sc->rl_unit, sc->rl_pinfo->rl_name); 121140516Swpaul } else { 121240516Swpaul printf("rl%d: MII without any phy!\n", sc->rl_unit); 121340516Swpaul } 121440516Swpaul } 121540516Swpaul 121640516Swpaul /* 121740516Swpaul * Do ifmedia setup. 121840516Swpaul */ 121940516Swpaul ifmedia_init(&sc->ifmedia, 0, rl_ifmedia_upd, rl_ifmedia_sts); 122040516Swpaul 122140516Swpaul rl_getmode_mii(sc); 122240516Swpaul 122340516Swpaul /* Choose a default media. */ 122440516Swpaul media = IFM_ETHER|IFM_AUTO; 122540516Swpaul ifmedia_set(&sc->ifmedia, media); 122640516Swpaul 122740516Swpaul rl_autoneg_mii(sc, RL_FLAG_FORCEDELAY, 1); 122840516Swpaul 122940516Swpaul /* 123040516Swpaul * Call MI attach routines. 123140516Swpaul */ 123240516Swpaul if_attach(ifp); 123340516Swpaul ether_ifattach(ifp); 123440516Swpaul 123548645Sdes#if NBPF > 0 123640516Swpaul bpfattach(ifp, DLT_EN10MB, sizeof(struct ether_header)); 123740516Swpaul#endif 123850107Smsmith EVENTHANDLER_REGISTER(shutdown_post_sync, rl_shutdown, sc, 123950107Smsmith SHUTDOWN_PRI_DEFAULT); 124040516Swpaul 124140516Swpaulfail: 124240516Swpaul splx(s); 124340516Swpaul return; 124440516Swpaul} 124540516Swpaul 124640516Swpaul/* 124740516Swpaul * Initialize the transmit descriptors. 124840516Swpaul */ 124940516Swpaulstatic int rl_list_tx_init(sc) 125040516Swpaul struct rl_softc *sc; 125140516Swpaul{ 125240516Swpaul struct rl_chain_data *cd; 125340516Swpaul int i; 125440516Swpaul 125540516Swpaul cd = &sc->rl_cdata; 125640516Swpaul for (i = 0; i < RL_TX_LIST_CNT; i++) { 125745633Swpaul cd->rl_tx_chain[i] = NULL; 125848028Swpaul CSR_WRITE_4(sc, 125948028Swpaul RL_TXADDR0 + (i * sizeof(u_int32_t)), 0x0000000); 126040516Swpaul } 126140516Swpaul 126245633Swpaul sc->rl_cdata.cur_tx = 0; 126345633Swpaul sc->rl_cdata.last_tx = 0; 126440516Swpaul 126540516Swpaul return(0); 126640516Swpaul} 126740516Swpaul 126840516Swpaul/* 126940516Swpaul * A frame has been uploaded: pass the resulting mbuf chain up to 127040516Swpaul * the higher level protocols. 127140516Swpaul * 127240516Swpaul * You know there's something wrong with a PCI bus-master chip design 127340516Swpaul * when you have to use m_devget(). 127440516Swpaul * 127540516Swpaul * The receive operation is badly documented in the datasheet, so I'll 127640516Swpaul * attempt to document it here. The driver provides a buffer area and 127740516Swpaul * places its base address in the RX buffer start address register. 127840516Swpaul * The chip then begins copying frames into the RX buffer. Each frame 127940516Swpaul * is preceeded by a 32-bit RX status word which specifies the length 128040516Swpaul * of the frame and certain other status bits. Each frame (starting with 128140516Swpaul * the status word) is also 32-bit aligned. The frame length is in the 128240516Swpaul * first 16 bits of the status word; the lower 15 bits correspond with 128340516Swpaul * the 'rx status register' mentioned in the datasheet. 128448028Swpaul * 128548028Swpaul * Note: to make the Alpha happy, the frame payload needs to be aligned 128648028Swpaul * on a 32-bit boundary. To achieve this, we cheat a bit by copying from 128748028Swpaul * the ring buffer starting at an address two bytes before the actual 128848028Swpaul * data location. We can then shave off the first two bytes using m_adj(). 128948028Swpaul * The reason we do this is because m_devget() doesn't let us specify an 129048028Swpaul * offset into the mbuf storage space, so we have to artificially create 129148028Swpaul * one. The ring is allocated in such a way that there are a few unused 129248028Swpaul * bytes of space preceecing it so that it will be safe for us to do the 129348028Swpaul * 2-byte backstep even if reading from the ring at offset 0. 129440516Swpaul */ 129540516Swpaulstatic void rl_rxeof(sc) 129640516Swpaul struct rl_softc *sc; 129740516Swpaul{ 129840516Swpaul struct ether_header *eh; 129940516Swpaul struct mbuf *m; 130040516Swpaul struct ifnet *ifp; 130140516Swpaul int total_len = 0; 130240516Swpaul u_int32_t rxstat; 130340516Swpaul caddr_t rxbufpos; 130440516Swpaul int wrap = 0; 130540516Swpaul u_int16_t cur_rx; 130640516Swpaul u_int16_t limit; 130740516Swpaul u_int16_t rx_bytes = 0, max_bytes; 130840516Swpaul 130940516Swpaul ifp = &sc->arpcom.ac_if; 131040516Swpaul 131140516Swpaul cur_rx = (CSR_READ_2(sc, RL_CURRXADDR) + 16) % RL_RXBUFLEN; 131240516Swpaul 131340516Swpaul /* Do not try to read past this point. */ 131440516Swpaul limit = CSR_READ_2(sc, RL_CURRXBUF) % RL_RXBUFLEN; 131540516Swpaul 131640516Swpaul if (limit < cur_rx) 131740516Swpaul max_bytes = (RL_RXBUFLEN - cur_rx) + limit; 131840516Swpaul else 131940516Swpaul max_bytes = limit - cur_rx; 132040516Swpaul 132142738Swpaul while((CSR_READ_1(sc, RL_COMMAND) & RL_CMD_EMPTY_RXBUF) == 0) { 132240516Swpaul rxbufpos = sc->rl_cdata.rl_rx_buf + cur_rx; 132340516Swpaul rxstat = *(u_int32_t *)rxbufpos; 132440516Swpaul 132540516Swpaul /* 132640516Swpaul * Here's a totally undocumented fact for you. When the 132740516Swpaul * RealTek chip is in the process of copying a packet into 132840516Swpaul * RAM for you, the length will be 0xfff0. If you spot a 132940516Swpaul * packet header with this value, you need to stop. The 133040516Swpaul * datasheet makes absolutely no mention of this and 133140516Swpaul * RealTek should be shot for this. 133240516Swpaul */ 133340516Swpaul if ((u_int16_t)(rxstat >> 16) == RL_RXSTAT_UNFINISHED) 133440516Swpaul break; 133540516Swpaul 133640516Swpaul if (!(rxstat & RL_RXSTAT_RXOK)) { 133740516Swpaul ifp->if_ierrors++; 133840516Swpaul if (rxstat & (RL_RXSTAT_BADSYM|RL_RXSTAT_RUNT| 133940516Swpaul RL_RXSTAT_GIANT|RL_RXSTAT_CRCERR| 134040516Swpaul RL_RXSTAT_ALIGNERR)) { 134140516Swpaul CSR_WRITE_2(sc, RL_COMMAND, RL_CMD_TX_ENB); 134240516Swpaul CSR_WRITE_2(sc, RL_COMMAND, RL_CMD_TX_ENB| 134340516Swpaul RL_CMD_RX_ENB); 134440516Swpaul CSR_WRITE_4(sc, RL_RXCFG, RL_RXCFG_CONFIG); 134540516Swpaul CSR_WRITE_4(sc, RL_RXADDR, 134640516Swpaul vtophys(sc->rl_cdata.rl_rx_buf)); 134740516Swpaul CSR_WRITE_2(sc, RL_CURRXADDR, cur_rx - 16); 134840516Swpaul cur_rx = 0; 134940516Swpaul } 135040516Swpaul break; 135140516Swpaul } 135240516Swpaul 135340516Swpaul /* No errors; receive the packet. */ 135440516Swpaul total_len = rxstat >> 16; 135540516Swpaul rx_bytes += total_len + 4; 135640516Swpaul 135740516Swpaul /* 135842051Swpaul * XXX The RealTek chip includes the CRC with every 135942051Swpaul * received frame, and there's no way to turn this 136042051Swpaul * behavior off (at least, I can't find anything in 136142051Swpaul * the manual that explains how to do it) so we have 136242051Swpaul * to trim off the CRC manually. 136342051Swpaul */ 136442051Swpaul total_len -= ETHER_CRC_LEN; 136542051Swpaul 136642051Swpaul /* 136740516Swpaul * Avoid trying to read more bytes than we know 136840516Swpaul * the chip has prepared for us. 136940516Swpaul */ 137040516Swpaul if (rx_bytes > max_bytes) 137140516Swpaul break; 137240516Swpaul 137340516Swpaul rxbufpos = sc->rl_cdata.rl_rx_buf + 137440516Swpaul ((cur_rx + sizeof(u_int32_t)) % RL_RXBUFLEN); 137540516Swpaul 137640516Swpaul if (rxbufpos == (sc->rl_cdata.rl_rx_buf + RL_RXBUFLEN)) 137740516Swpaul rxbufpos = sc->rl_cdata.rl_rx_buf; 137840516Swpaul 137940516Swpaul wrap = (sc->rl_cdata.rl_rx_buf + RL_RXBUFLEN) - rxbufpos; 138040516Swpaul 138140516Swpaul if (total_len > wrap) { 138248028Swpaul m = m_devget(rxbufpos - RL_ETHER_ALIGN, 138348028Swpaul wrap + RL_ETHER_ALIGN, 0, ifp, NULL); 138440516Swpaul if (m == NULL) { 138540516Swpaul ifp->if_ierrors++; 138640516Swpaul printf("rl%d: out of mbufs, tried to " 138740516Swpaul "copy %d bytes\n", sc->rl_unit, wrap); 138840516Swpaul } 138948028Swpaul else { 139048028Swpaul m_adj(m, RL_ETHER_ALIGN); 139140516Swpaul m_copyback(m, wrap, total_len - wrap, 139240516Swpaul sc->rl_cdata.rl_rx_buf); 139348028Swpaul } 139442051Swpaul cur_rx = (total_len - wrap + ETHER_CRC_LEN); 139540516Swpaul } else { 139648028Swpaul m = m_devget(rxbufpos - RL_ETHER_ALIGN, 139748028Swpaul total_len + RL_ETHER_ALIGN, 0, ifp, NULL); 139840516Swpaul if (m == NULL) { 139940516Swpaul ifp->if_ierrors++; 140040516Swpaul printf("rl%d: out of mbufs, tried to " 140140516Swpaul "copy %d bytes\n", sc->rl_unit, total_len); 140248028Swpaul } else 140348028Swpaul m_adj(m, RL_ETHER_ALIGN); 140442051Swpaul cur_rx += total_len + 4 + ETHER_CRC_LEN; 140540516Swpaul } 140640516Swpaul 140740516Swpaul /* 140840516Swpaul * Round up to 32-bit boundary. 140940516Swpaul */ 141040516Swpaul cur_rx = (cur_rx + 3) & ~3; 141140516Swpaul CSR_WRITE_2(sc, RL_CURRXADDR, cur_rx - 16); 141240516Swpaul 141340516Swpaul if (m == NULL) 141440516Swpaul continue; 141540516Swpaul 141640516Swpaul eh = mtod(m, struct ether_header *); 141740516Swpaul ifp->if_ipackets++; 141840516Swpaul 141948645Sdes#if NBPF > 0 142040516Swpaul /* 142140516Swpaul * Handle BPF listeners. Let the BPF user see the packet, but 142240516Swpaul * don't pass it up to the ether_input() layer unless it's 142340516Swpaul * a broadcast packet, multicast packet, matches our ethernet 142440516Swpaul * address or the interface is in promiscuous mode. 142540516Swpaul */ 142640516Swpaul if (ifp->if_bpf) { 142740516Swpaul bpf_mtap(ifp, m); 142840516Swpaul if (ifp->if_flags & IFF_PROMISC && 142940516Swpaul (bcmp(eh->ether_dhost, sc->arpcom.ac_enaddr, 143040516Swpaul ETHER_ADDR_LEN) && 143140516Swpaul (eh->ether_dhost[0] & 1) == 0)) { 143240516Swpaul m_freem(m); 143340516Swpaul continue; 143440516Swpaul } 143540516Swpaul } 143640516Swpaul#endif 143740516Swpaul /* Remove header from mbuf and pass it on. */ 143840516Swpaul m_adj(m, sizeof(struct ether_header)); 143940516Swpaul ether_input(ifp, eh, m); 144040516Swpaul } 144140516Swpaul 144240516Swpaul return; 144340516Swpaul} 144440516Swpaul 144540516Swpaul/* 144640516Swpaul * A frame was downloaded to the chip. It's safe for us to clean up 144740516Swpaul * the list buffers. 144840516Swpaul */ 144940516Swpaulstatic void rl_txeof(sc) 145040516Swpaul struct rl_softc *sc; 145140516Swpaul{ 145240516Swpaul struct ifnet *ifp; 145340516Swpaul u_int32_t txstat; 145440516Swpaul 145540516Swpaul ifp = &sc->arpcom.ac_if; 145640516Swpaul 145740516Swpaul /* Clear the timeout timer. */ 145840516Swpaul ifp->if_timer = 0; 145940516Swpaul 146040516Swpaul /* 146140516Swpaul * Go through our tx list and free mbufs for those 146240516Swpaul * frames that have been uploaded. 146340516Swpaul */ 146445633Swpaul do { 146545633Swpaul txstat = CSR_READ_4(sc, RL_LAST_TXSTAT(sc)); 146645633Swpaul if (!(txstat & (RL_TXSTAT_TX_OK| 146745633Swpaul RL_TXSTAT_TX_UNDERRUN|RL_TXSTAT_TXABRT))) 146840516Swpaul break; 146940516Swpaul 147045633Swpaul ifp->if_collisions += (txstat & RL_TXSTAT_COLLCNT) >> 24; 147140516Swpaul 147245633Swpaul if (RL_LAST_TXMBUF(sc) != NULL) { 147345633Swpaul m_freem(RL_LAST_TXMBUF(sc)); 147445633Swpaul RL_LAST_TXMBUF(sc) = NULL; 147545633Swpaul } 147645633Swpaul if (txstat & RL_TXSTAT_TX_OK) 147745633Swpaul ifp->if_opackets++; 147845633Swpaul else { 147945633Swpaul ifp->if_oerrors++; 148045633Swpaul if ((txstat & RL_TXSTAT_TXABRT) || 148145633Swpaul (txstat & RL_TXSTAT_OUTOFWIN)) 148245633Swpaul CSR_WRITE_4(sc, RL_TXCFG, RL_TXCFG_CONFIG); 148345633Swpaul } 148445633Swpaul RL_INC(sc->rl_cdata.last_tx); 148545633Swpaul ifp->if_flags &= ~IFF_OACTIVE; 148645633Swpaul } while (sc->rl_cdata.last_tx != sc->rl_cdata.cur_tx); 148740516Swpaul 148845633Swpaul if (sc->rl_cdata.last_tx == sc->rl_cdata.cur_tx) { 148940516Swpaul if (sc->rl_want_auto) 149040516Swpaul rl_autoneg_mii(sc, RL_FLAG_SCHEDDELAY, 1); 149140516Swpaul } 149240516Swpaul 149340516Swpaul return; 149440516Swpaul} 149540516Swpaul 149640516Swpaulstatic void rl_intr(arg) 149740516Swpaul void *arg; 149840516Swpaul{ 149940516Swpaul struct rl_softc *sc; 150040516Swpaul struct ifnet *ifp; 150140516Swpaul u_int16_t status; 150240516Swpaul 150340516Swpaul sc = arg; 150440516Swpaul ifp = &sc->arpcom.ac_if; 150540516Swpaul 150640516Swpaul /* Disable interrupts. */ 150740516Swpaul CSR_WRITE_2(sc, RL_IMR, 0x0000); 150840516Swpaul 150940516Swpaul for (;;) { 151040516Swpaul 151140516Swpaul status = CSR_READ_2(sc, RL_ISR); 151240516Swpaul if (status) 151340516Swpaul CSR_WRITE_2(sc, RL_ISR, status); 151440516Swpaul 151540516Swpaul if ((status & RL_INTRS) == 0) 151640516Swpaul break; 151740516Swpaul 151840516Swpaul if (status & RL_ISR_RX_OK) 151940516Swpaul rl_rxeof(sc); 152040516Swpaul 152140516Swpaul if (status & RL_ISR_RX_ERR) 152240516Swpaul rl_rxeof(sc); 152340516Swpaul 152445633Swpaul if ((status & RL_ISR_TX_OK) || (status & RL_ISR_TX_ERR)) 152540516Swpaul rl_txeof(sc); 152640516Swpaul 152740516Swpaul if (status & RL_ISR_SYSTEM_ERR) { 152840516Swpaul rl_reset(sc); 152940516Swpaul rl_init(sc); 153040516Swpaul } 153140516Swpaul 153240516Swpaul } 153340516Swpaul 153440516Swpaul /* Re-enable interrupts. */ 153540516Swpaul CSR_WRITE_2(sc, RL_IMR, RL_INTRS); 153640516Swpaul 153740516Swpaul if (ifp->if_snd.ifq_head != NULL) { 153840516Swpaul rl_start(ifp); 153940516Swpaul } 154040516Swpaul 154140516Swpaul return; 154240516Swpaul} 154340516Swpaul 154440516Swpaul/* 154540516Swpaul * Encapsulate an mbuf chain in a descriptor by coupling the mbuf data 154640516Swpaul * pointers to the fragment pointers. 154740516Swpaul */ 154845633Swpaulstatic int rl_encap(sc, m_head) 154940516Swpaul struct rl_softc *sc; 155040516Swpaul struct mbuf *m_head; 155140516Swpaul{ 155241243Swpaul struct mbuf *m_new = NULL; 155340516Swpaul 155440516Swpaul /* 155545633Swpaul * The RealTek is brain damaged and wants longword-aligned 155645633Swpaul * TX buffers, plus we can only have one fragment buffer 155745633Swpaul * per packet. We have to copy pretty much all the time. 155840516Swpaul */ 155940516Swpaul 156041243Swpaul MGETHDR(m_new, M_DONTWAIT, MT_DATA); 156141243Swpaul if (m_new == NULL) { 156241243Swpaul printf("rl%d: no memory for tx list", sc->rl_unit); 156341243Swpaul return(1); 156441243Swpaul } 156541243Swpaul if (m_head->m_pkthdr.len > MHLEN) { 156641243Swpaul MCLGET(m_new, M_DONTWAIT); 156741243Swpaul if (!(m_new->m_flags & M_EXT)) { 156841243Swpaul m_freem(m_new); 156941243Swpaul printf("rl%d: no memory for tx list", 157041243Swpaul sc->rl_unit); 157140516Swpaul return(1); 157240516Swpaul } 157340516Swpaul } 157441243Swpaul m_copydata(m_head, 0, m_head->m_pkthdr.len, 157541243Swpaul mtod(m_new, caddr_t)); 157641243Swpaul m_new->m_pkthdr.len = m_new->m_len = m_head->m_pkthdr.len; 157741243Swpaul m_freem(m_head); 157841243Swpaul m_head = m_new; 157940516Swpaul 158040516Swpaul /* Pad frames to at least 60 bytes. */ 158141243Swpaul if (m_head->m_pkthdr.len < RL_MIN_FRAMELEN) { 158240516Swpaul m_head->m_pkthdr.len += 158340516Swpaul (RL_MIN_FRAMELEN - m_head->m_pkthdr.len); 158441243Swpaul m_head->m_len = m_head->m_pkthdr.len; 158541243Swpaul } 158640516Swpaul 158745633Swpaul RL_CUR_TXMBUF(sc) = m_head; 158840516Swpaul 158940516Swpaul return(0); 159040516Swpaul} 159140516Swpaul 159240516Swpaul/* 159340516Swpaul * Main transmit routine. 159440516Swpaul */ 159540516Swpaul 159640516Swpaulstatic void rl_start(ifp) 159740516Swpaul struct ifnet *ifp; 159840516Swpaul{ 159940516Swpaul struct rl_softc *sc; 160040516Swpaul struct mbuf *m_head = NULL; 160140516Swpaul 160240516Swpaul sc = ifp->if_softc; 160340516Swpaul 160440516Swpaul if (sc->rl_autoneg) { 160540516Swpaul sc->rl_tx_pend = 1; 160640516Swpaul return; 160740516Swpaul } 160840516Swpaul 160945633Swpaul while(RL_CUR_TXMBUF(sc) == NULL) { 161040516Swpaul IF_DEQUEUE(&ifp->if_snd, m_head); 161140516Swpaul if (m_head == NULL) 161240516Swpaul break; 161340516Swpaul 161445633Swpaul rl_encap(sc, m_head); 161540516Swpaul 161648645Sdes#if NBPF > 0 161740516Swpaul /* 161840516Swpaul * If there's a BPF listener, bounce a copy of this frame 161940516Swpaul * to him. 162040516Swpaul */ 162140516Swpaul if (ifp->if_bpf) 162245633Swpaul bpf_mtap(ifp, RL_CUR_TXMBUF(sc)); 162340516Swpaul#endif 162440516Swpaul /* 162540516Swpaul * Transmit the frame. 162640516Swpaul */ 162745633Swpaul CSR_WRITE_4(sc, RL_CUR_TXADDR(sc), 162845633Swpaul vtophys(mtod(RL_CUR_TXMBUF(sc), caddr_t))); 162945633Swpaul CSR_WRITE_4(sc, RL_CUR_TXSTAT(sc), 163045633Swpaul RL_TX_EARLYTHRESH | RL_CUR_TXMBUF(sc)->m_pkthdr.len); 163145633Swpaul 163245633Swpaul RL_INC(sc->rl_cdata.cur_tx); 163340516Swpaul } 163440516Swpaul 163540516Swpaul /* 163645633Swpaul * We broke out of the loop because all our TX slots are 163745633Swpaul * full. Mark the NIC as busy until it drains some of the 163845633Swpaul * packets from the queue. 163945633Swpaul */ 164045633Swpaul if (RL_CUR_TXMBUF(sc) != NULL) 164145633Swpaul ifp->if_flags |= IFF_OACTIVE; 164245633Swpaul 164345633Swpaul /* 164440516Swpaul * Set a timeout in case the chip goes out to lunch. 164540516Swpaul */ 164640516Swpaul ifp->if_timer = 5; 164740516Swpaul 164840516Swpaul return; 164940516Swpaul} 165040516Swpaul 165140516Swpaulstatic void rl_init(xsc) 165240516Swpaul void *xsc; 165340516Swpaul{ 165440516Swpaul struct rl_softc *sc = xsc; 165540516Swpaul struct ifnet *ifp = &sc->arpcom.ac_if; 165640516Swpaul int s, i; 165740516Swpaul u_int32_t rxcfg = 0; 165840516Swpaul u_int16_t phy_bmcr = 0; 165940516Swpaul 166040516Swpaul if (sc->rl_autoneg) 166140516Swpaul return; 166240516Swpaul 166340516Swpaul s = splimp(); 166440516Swpaul 166540516Swpaul /* 166640516Swpaul * XXX Hack for the 8139: the built-in autoneg logic's state 166740516Swpaul * gets reset by rl_init() when we don't want it to. Try 166840516Swpaul * to preserve it. (For 8129 cards with real external PHYs, 166940516Swpaul * the BMCR register doesn't change, but this doesn't hurt.) 167040516Swpaul */ 167140516Swpaul if (sc->rl_type == RL_8139) 167240516Swpaul phy_bmcr = rl_phy_readreg(sc, PHY_BMCR); 167340516Swpaul 167440516Swpaul /* 167540516Swpaul * Cancel pending I/O and free all RX/TX buffers. 167640516Swpaul */ 167740516Swpaul rl_stop(sc); 167840516Swpaul 167940516Swpaul /* Init our MAC address */ 168040516Swpaul for (i = 0; i < ETHER_ADDR_LEN; i++) { 168140516Swpaul CSR_WRITE_1(sc, RL_IDR0 + i, sc->arpcom.ac_enaddr[i]); 168240516Swpaul } 168340516Swpaul 168440516Swpaul /* Init the RX buffer pointer register. */ 168540516Swpaul CSR_WRITE_4(sc, RL_RXADDR, vtophys(sc->rl_cdata.rl_rx_buf)); 168640516Swpaul 168740516Swpaul /* Init TX descriptors. */ 168840516Swpaul rl_list_tx_init(sc); 168940516Swpaul 169040516Swpaul /* 169140516Swpaul * Enable transmit and receive. 169240516Swpaul */ 169340516Swpaul CSR_WRITE_1(sc, RL_COMMAND, RL_CMD_TX_ENB|RL_CMD_RX_ENB); 169440516Swpaul 169540516Swpaul /* 169645633Swpaul * Set the initial TX and RX configuration. 169740516Swpaul */ 169845633Swpaul CSR_WRITE_4(sc, RL_TXCFG, RL_TXCFG_CONFIG); 169940516Swpaul CSR_WRITE_4(sc, RL_RXCFG, RL_RXCFG_CONFIG); 170040516Swpaul 170140516Swpaul /* Set the individual bit to receive frames for this host only. */ 170240516Swpaul rxcfg = CSR_READ_4(sc, RL_RXCFG); 170340516Swpaul rxcfg |= RL_RXCFG_RX_INDIV; 170440516Swpaul 170540516Swpaul /* If we want promiscuous mode, set the allframes bit. */ 170640516Swpaul if (ifp->if_flags & IFF_PROMISC) { 170740516Swpaul rxcfg |= RL_RXCFG_RX_ALLPHYS; 170840516Swpaul CSR_WRITE_4(sc, RL_RXCFG, rxcfg); 170940516Swpaul } else { 171040516Swpaul rxcfg &= ~RL_RXCFG_RX_ALLPHYS; 171140516Swpaul CSR_WRITE_4(sc, RL_RXCFG, rxcfg); 171240516Swpaul } 171340516Swpaul 171440516Swpaul /* 171540516Swpaul * Set capture broadcast bit to capture broadcast frames. 171640516Swpaul */ 171740516Swpaul if (ifp->if_flags & IFF_BROADCAST) { 171840516Swpaul rxcfg |= RL_RXCFG_RX_BROAD; 171940516Swpaul CSR_WRITE_4(sc, RL_RXCFG, rxcfg); 172040516Swpaul } else { 172140516Swpaul rxcfg &= ~RL_RXCFG_RX_BROAD; 172240516Swpaul CSR_WRITE_4(sc, RL_RXCFG, rxcfg); 172340516Swpaul } 172440516Swpaul 172540516Swpaul /* 172640516Swpaul * Program the multicast filter, if necessary. 172740516Swpaul */ 172840516Swpaul rl_setmulti(sc); 172940516Swpaul 173040516Swpaul /* 173140516Swpaul * Enable interrupts. 173240516Swpaul */ 173340516Swpaul CSR_WRITE_2(sc, RL_IMR, RL_INTRS); 173440516Swpaul 173540516Swpaul /* Start RX/TX process. */ 173640516Swpaul CSR_WRITE_4(sc, RL_MISSEDPKT, 0); 173740516Swpaul 173840516Swpaul /* Enable receiver and transmitter. */ 173940516Swpaul CSR_WRITE_1(sc, RL_COMMAND, RL_CMD_TX_ENB|RL_CMD_RX_ENB); 174040516Swpaul 174140516Swpaul /* Restore state of BMCR */ 174240516Swpaul if (sc->rl_pinfo != NULL) 174340516Swpaul rl_phy_writereg(sc, PHY_BMCR, phy_bmcr); 174440516Swpaul 174540516Swpaul CSR_WRITE_1(sc, RL_CFG1, RL_CFG1_DRVLOAD|RL_CFG1_FULLDUPLEX); 174640516Swpaul 174740516Swpaul ifp->if_flags |= IFF_RUNNING; 174840516Swpaul ifp->if_flags &= ~IFF_OACTIVE; 174940516Swpaul 175040516Swpaul (void)splx(s); 175140516Swpaul 175240516Swpaul return; 175340516Swpaul} 175440516Swpaul 175540516Swpaul/* 175640516Swpaul * Set media options. 175740516Swpaul */ 175840516Swpaulstatic int rl_ifmedia_upd(ifp) 175940516Swpaul struct ifnet *ifp; 176040516Swpaul{ 176140516Swpaul struct rl_softc *sc; 176240516Swpaul struct ifmedia *ifm; 176340516Swpaul 176440516Swpaul sc = ifp->if_softc; 176540516Swpaul ifm = &sc->ifmedia; 176640516Swpaul 176740516Swpaul if (IFM_TYPE(ifm->ifm_media) != IFM_ETHER) 176840516Swpaul return(EINVAL); 176940516Swpaul 177040516Swpaul if (IFM_SUBTYPE(ifm->ifm_media) == IFM_AUTO) 177140516Swpaul rl_autoneg_mii(sc, RL_FLAG_SCHEDDELAY, 1); 177240516Swpaul else 177340516Swpaul rl_setmode_mii(sc, ifm->ifm_media); 177440516Swpaul 177540516Swpaul return(0); 177640516Swpaul} 177740516Swpaul 177840516Swpaul/* 177940516Swpaul * Report current media status. 178040516Swpaul */ 178140516Swpaulstatic void rl_ifmedia_sts(ifp, ifmr) 178240516Swpaul struct ifnet *ifp; 178340516Swpaul struct ifmediareq *ifmr; 178440516Swpaul{ 178540516Swpaul struct rl_softc *sc; 178640516Swpaul u_int16_t advert = 0, ability = 0; 178740516Swpaul 178840516Swpaul sc = ifp->if_softc; 178940516Swpaul 179040516Swpaul if (!(rl_phy_readreg(sc, PHY_BMCR) & PHY_BMCR_AUTONEGENBL)) { 179140516Swpaul if (rl_phy_readreg(sc, PHY_BMCR) & PHY_BMCR_SPEEDSEL) 179240516Swpaul ifmr->ifm_active = IFM_ETHER|IFM_100_TX; 179340516Swpaul else 179440516Swpaul ifmr->ifm_active = IFM_ETHER|IFM_10_T; 179540516Swpaul 179640516Swpaul if (rl_phy_readreg(sc, PHY_BMCR) & PHY_BMCR_DUPLEX) 179740516Swpaul ifmr->ifm_active |= IFM_FDX; 179840516Swpaul else 179940516Swpaul ifmr->ifm_active |= IFM_HDX; 180040516Swpaul return; 180140516Swpaul } 180240516Swpaul 180340516Swpaul ability = rl_phy_readreg(sc, PHY_LPAR); 180440516Swpaul advert = rl_phy_readreg(sc, PHY_ANAR); 180540516Swpaul if (advert & PHY_ANAR_100BT4 && 180640516Swpaul ability & PHY_ANAR_100BT4) { 180740516Swpaul ifmr->ifm_active = IFM_ETHER|IFM_100_T4; 180840516Swpaul } else if (advert & PHY_ANAR_100BTXFULL && 180940516Swpaul ability & PHY_ANAR_100BTXFULL) { 181040516Swpaul ifmr->ifm_active = IFM_ETHER|IFM_100_TX|IFM_FDX; 181140516Swpaul } else if (advert & PHY_ANAR_100BTXHALF && 181240516Swpaul ability & PHY_ANAR_100BTXHALF) { 181340516Swpaul ifmr->ifm_active = IFM_ETHER|IFM_100_TX|IFM_HDX; 181440516Swpaul } else if (advert & PHY_ANAR_10BTFULL && 181540516Swpaul ability & PHY_ANAR_10BTFULL) { 181640516Swpaul ifmr->ifm_active = IFM_ETHER|IFM_10_T|IFM_FDX; 181740516Swpaul } else if (advert & PHY_ANAR_10BTHALF && 181840516Swpaul ability & PHY_ANAR_10BTHALF) { 181940516Swpaul ifmr->ifm_active = IFM_ETHER|IFM_10_T|IFM_HDX; 182040516Swpaul } 182140516Swpaul 182240516Swpaul return; 182340516Swpaul} 182440516Swpaul 182540516Swpaulstatic int rl_ioctl(ifp, command, data) 182640516Swpaul struct ifnet *ifp; 182740516Swpaul u_long command; 182840516Swpaul caddr_t data; 182940516Swpaul{ 183040516Swpaul struct rl_softc *sc = ifp->if_softc; 183140516Swpaul struct ifreq *ifr = (struct ifreq *) data; 183240516Swpaul int s, error = 0; 183340516Swpaul 183440516Swpaul s = splimp(); 183540516Swpaul 183640516Swpaul switch(command) { 183740516Swpaul case SIOCSIFADDR: 183840516Swpaul case SIOCGIFADDR: 183940516Swpaul case SIOCSIFMTU: 184040516Swpaul error = ether_ioctl(ifp, command, data); 184140516Swpaul break; 184240516Swpaul case SIOCSIFFLAGS: 184340516Swpaul if (ifp->if_flags & IFF_UP) { 184440516Swpaul rl_init(sc); 184540516Swpaul } else { 184640516Swpaul if (ifp->if_flags & IFF_RUNNING) 184740516Swpaul rl_stop(sc); 184840516Swpaul } 184940516Swpaul error = 0; 185040516Swpaul break; 185140516Swpaul case SIOCADDMULTI: 185240516Swpaul case SIOCDELMULTI: 185340516Swpaul rl_setmulti(sc); 185440516Swpaul error = 0; 185540516Swpaul break; 185640516Swpaul case SIOCGIFMEDIA: 185740516Swpaul case SIOCSIFMEDIA: 185840516Swpaul error = ifmedia_ioctl(ifp, ifr, &sc->ifmedia, command); 185940516Swpaul break; 186040516Swpaul default: 186140516Swpaul error = EINVAL; 186240516Swpaul break; 186340516Swpaul } 186440516Swpaul 186540516Swpaul (void)splx(s); 186640516Swpaul 186740516Swpaul return(error); 186840516Swpaul} 186940516Swpaul 187040516Swpaulstatic void rl_watchdog(ifp) 187140516Swpaul struct ifnet *ifp; 187240516Swpaul{ 187340516Swpaul struct rl_softc *sc; 187440516Swpaul 187540516Swpaul sc = ifp->if_softc; 187640516Swpaul 187740516Swpaul if (sc->rl_autoneg) { 187840516Swpaul rl_autoneg_mii(sc, RL_FLAG_DELAYTIMEO, 1); 187940516Swpaul return; 188040516Swpaul } 188140516Swpaul 188240516Swpaul printf("rl%d: watchdog timeout\n", sc->rl_unit); 188340516Swpaul ifp->if_oerrors++; 188440516Swpaul if (!(rl_phy_readreg(sc, PHY_BMSR) & PHY_BMSR_LINKSTAT)) 188540516Swpaul printf("rl%d: no carrier - transceiver cable problem?\n", 188640516Swpaul sc->rl_unit); 188740516Swpaul rl_txeof(sc); 188840516Swpaul rl_rxeof(sc); 188940516Swpaul rl_init(sc); 189040516Swpaul 189140516Swpaul return; 189240516Swpaul} 189340516Swpaul 189440516Swpaul/* 189540516Swpaul * Stop the adapter and free any mbufs allocated to the 189640516Swpaul * RX and TX lists. 189740516Swpaul */ 189840516Swpaulstatic void rl_stop(sc) 189940516Swpaul struct rl_softc *sc; 190040516Swpaul{ 190140516Swpaul register int i; 190240516Swpaul struct ifnet *ifp; 190340516Swpaul 190440516Swpaul ifp = &sc->arpcom.ac_if; 190540516Swpaul ifp->if_timer = 0; 190640516Swpaul 190740516Swpaul CSR_WRITE_1(sc, RL_COMMAND, 0x00); 190840516Swpaul CSR_WRITE_2(sc, RL_IMR, 0x0000); 190940516Swpaul 191040516Swpaul /* 191140516Swpaul * Free the TX list buffers. 191240516Swpaul */ 191340516Swpaul for (i = 0; i < RL_TX_LIST_CNT; i++) { 191445633Swpaul if (sc->rl_cdata.rl_tx_chain[i] != NULL) { 191545633Swpaul m_freem(sc->rl_cdata.rl_tx_chain[i]); 191645633Swpaul sc->rl_cdata.rl_tx_chain[i] = NULL; 191745633Swpaul CSR_WRITE_4(sc, RL_TXADDR0 + i, 0x0000000); 191840516Swpaul } 191940516Swpaul } 192040516Swpaul 192140516Swpaul ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE); 192240516Swpaul 192340516Swpaul return; 192440516Swpaul} 192540516Swpaul 192640516Swpaul/* 192740516Swpaul * Stop all chip I/O so that the kernel's probe routines don't 192840516Swpaul * get confused by errant DMAs when rebooting. 192940516Swpaul */ 193050107Smsmithstatic void rl_shutdown(arg, howto) 193150107Smsmith void *arg; 193240516Swpaul int howto; 193340516Swpaul{ 193440516Swpaul struct rl_softc *sc = (struct rl_softc *)arg; 193540516Swpaul 193640516Swpaul rl_stop(sc); 193740516Swpaul 193840516Swpaul return; 193940516Swpaul} 194040516Swpaul 194140516Swpaul 194240516Swpaulstatic struct pci_device rl_device = { 194340516Swpaul "rl", 194440516Swpaul rl_probe, 194540516Swpaul rl_attach, 194640516Swpaul &rl_count, 194740516Swpaul NULL 194840516Swpaul}; 194946024SpeterCOMPAT_PCI_DRIVER(rl, rl_device); 1950