if_rl.c revision 42738
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 * 3242738Swpaul * $Id: if_rl.c,v 1.20 1999/01/16 20:46:24 wpaul Exp $ 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 8640516Swpaul#include "bpfilter.h" 8740516Swpaul 8840516Swpaul#include <sys/param.h> 8940516Swpaul#include <sys/systm.h> 9040516Swpaul#include <sys/sockio.h> 9140516Swpaul#include <sys/mbuf.h> 9240516Swpaul#include <sys/malloc.h> 9340516Swpaul#include <sys/kernel.h> 9440516Swpaul#include <sys/socket.h> 9540516Swpaul 9640516Swpaul#include <net/if.h> 9740516Swpaul#include <net/if_arp.h> 9840516Swpaul#include <net/ethernet.h> 9940516Swpaul#include <net/if_dl.h> 10040516Swpaul#include <net/if_media.h> 10140516Swpaul 10240516Swpaul#if NBPFILTER > 0 10340516Swpaul#include <net/bpf.h> 10440516Swpaul#endif 10540516Swpaul 10640516Swpaul#include <vm/vm.h> /* for vtophys */ 10740516Swpaul#include <vm/pmap.h> /* for vtophys */ 10840516Swpaul#include <machine/clock.h> /* for DELAY */ 10941569Swpaul#include <machine/bus_pio.h> 11041569Swpaul#include <machine/bus_memio.h> 11141569Swpaul#include <machine/bus.h> 11240516Swpaul 11340516Swpaul#include <pci/pcireg.h> 11440516Swpaul#include <pci/pcivar.h> 11540516Swpaul 11640516Swpaul/* 11740516Swpaul * Default to using PIO access for this driver. On SMP systems, 11840516Swpaul * there appear to be problems with memory mapped mode: it looks like 11940516Swpaul * doing too many memory mapped access back to back in rapid succession 12040516Swpaul * can hang the bus. I'm inclined to blame this on crummy design/construction 12140516Swpaul * on the part of RealTek. Memory mapped mode does appear to work on 12240516Swpaul * uniprocessor systems though. 12340516Swpaul */ 12440516Swpaul#define RL_USEIOSPACE 12540516Swpaul 12640516Swpaul#include <pci/if_rlreg.h> 12740516Swpaul 12840516Swpaul#ifndef lint 12941591Sarchiestatic const char rcsid[] = 13042738Swpaul "$Id: if_rl.c,v 1.20 1999/01/16 20:46:24 wpaul Exp $"; 13140516Swpaul#endif 13240516Swpaul 13340516Swpaul/* 13440516Swpaul * Various supported device vendors/types and their names. 13540516Swpaul */ 13640516Swpaulstatic struct rl_type rl_devs[] = { 13740516Swpaul { RT_VENDORID, RT_DEVICEID_8129, 13840516Swpaul "RealTek 8129 10/100BaseTX" }, 13940516Swpaul { RT_VENDORID, RT_DEVICEID_8139, 14040516Swpaul "RealTek 8139 10/100BaseTX" }, 14141243Swpaul { ACCTON_VENDORID, ACCTON_DEVICEID_5030, 14241243Swpaul "Accton MPX 5030/5038 10/100BaseTX" }, 14340516Swpaul { 0, 0, NULL } 14440516Swpaul}; 14540516Swpaul 14640516Swpaul/* 14740516Swpaul * Various supported PHY vendors/types and their names. Note that 14840516Swpaul * this driver will work with pretty much any MII-compliant PHY, 14940516Swpaul * so failure to positively identify the chip is not a fatal error. 15040516Swpaul */ 15140516Swpaul 15240516Swpaulstatic struct rl_type rl_phys[] = { 15340516Swpaul { TI_PHY_VENDORID, TI_PHY_10BT, "<TI ThunderLAN 10BT (internal)>" }, 15440516Swpaul { TI_PHY_VENDORID, TI_PHY_100VGPMI, "<TI TNETE211 100VG Any-LAN>" }, 15540516Swpaul { NS_PHY_VENDORID, NS_PHY_83840A, "<National Semiconductor DP83840A>"}, 15640516Swpaul { LEVEL1_PHY_VENDORID, LEVEL1_PHY_LXT970, "<Level 1 LXT970>" }, 15740516Swpaul { INTEL_PHY_VENDORID, INTEL_PHY_82555, "<Intel 82555>" }, 15840516Swpaul { SEEQ_PHY_VENDORID, SEEQ_PHY_80220, "<SEEQ 80220>" }, 15940516Swpaul { 0, 0, "<MII-compliant physical interface>" } 16040516Swpaul}; 16140516Swpaul 16240516Swpaulstatic unsigned long rl_count = 0; 16341771Sdillonstatic const char *rl_probe __P((pcici_t, pcidi_t)); 16440516Swpaulstatic void rl_attach __P((pcici_t, int)); 16540516Swpaul 16640516Swpaulstatic int rl_encap __P((struct rl_softc *, struct rl_chain *, 16740516Swpaul struct mbuf * )); 16840516Swpaul 16940516Swpaulstatic void rl_rxeof __P((struct rl_softc *)); 17040516Swpaulstatic void rl_txeof __P((struct rl_softc *)); 17140516Swpaulstatic void rl_txeoc __P((struct rl_softc *)); 17240516Swpaulstatic void rl_intr __P((void *)); 17340516Swpaulstatic void rl_start __P((struct ifnet *)); 17440516Swpaulstatic int rl_ioctl __P((struct ifnet *, u_long, caddr_t)); 17540516Swpaulstatic void rl_init __P((void *)); 17640516Swpaulstatic void rl_stop __P((struct rl_softc *)); 17740516Swpaulstatic void rl_watchdog __P((struct ifnet *)); 17840516Swpaulstatic void rl_shutdown __P((int, void *)); 17940516Swpaulstatic int rl_ifmedia_upd __P((struct ifnet *)); 18040516Swpaulstatic void rl_ifmedia_sts __P((struct ifnet *, struct ifmediareq *)); 18140516Swpaul 18241656Swpaulstatic void rl_eeprom_putbyte __P((struct rl_softc *, int)); 18341656Swpaulstatic void rl_eeprom_getword __P((struct rl_softc *, int, u_int16_t *)); 18440516Swpaulstatic void rl_read_eeprom __P((struct rl_softc *, caddr_t, 18540516Swpaul int, int, int)); 18640516Swpaulstatic void rl_mii_sync __P((struct rl_softc *)); 18740516Swpaulstatic void rl_mii_send __P((struct rl_softc *, u_int32_t, int)); 18840516Swpaulstatic int rl_mii_readreg __P((struct rl_softc *, struct rl_mii_frame *)); 18940516Swpaulstatic int rl_mii_writereg __P((struct rl_softc *, struct rl_mii_frame *)); 19040516Swpaul 19140516Swpaulstatic u_int16_t rl_phy_readreg __P((struct rl_softc *, int)); 19241656Swpaulstatic void rl_phy_writereg __P((struct rl_softc *, int, int)); 19340516Swpaul 19440516Swpaulstatic void rl_autoneg_xmit __P((struct rl_softc *)); 19540516Swpaulstatic void rl_autoneg_mii __P((struct rl_softc *, int, int)); 19640516Swpaulstatic void rl_setmode_mii __P((struct rl_softc *, int)); 19740516Swpaulstatic void rl_getmode_mii __P((struct rl_softc *)); 19841656Swpaulstatic u_int8_t rl_calchash __P((caddr_t)); 19940516Swpaulstatic void rl_setmulti __P((struct rl_softc *)); 20040516Swpaulstatic void rl_reset __P((struct rl_softc *)); 20140516Swpaulstatic int rl_list_tx_init __P((struct rl_softc *)); 20240516Swpaul 20340516Swpaul#define EE_SET(x) \ 20440516Swpaul CSR_WRITE_1(sc, RL_EECMD, \ 20540516Swpaul CSR_READ_1(sc, RL_EECMD) | x) 20640516Swpaul 20740516Swpaul#define EE_CLR(x) \ 20840516Swpaul CSR_WRITE_1(sc, RL_EECMD, \ 20940516Swpaul CSR_READ_1(sc, RL_EECMD) & ~x) 21040516Swpaul 21140516Swpaul/* 21240516Swpaul * Send a read command and address to the EEPROM, check for ACK. 21340516Swpaul */ 21440516Swpaulstatic void rl_eeprom_putbyte(sc, addr) 21540516Swpaul struct rl_softc *sc; 21641656Swpaul int addr; 21740516Swpaul{ 21840516Swpaul register int d, i; 21940516Swpaul 22040516Swpaul d = addr | RL_EECMD_READ; 22140516Swpaul 22240516Swpaul /* 22340516Swpaul * Feed in each bit and stobe the clock. 22440516Swpaul */ 22540516Swpaul for (i = 0x400; i; i >>= 1) { 22640516Swpaul if (d & i) { 22740516Swpaul EE_SET(RL_EE_DATAIN); 22840516Swpaul } else { 22940516Swpaul EE_CLR(RL_EE_DATAIN); 23040516Swpaul } 23140516Swpaul DELAY(100); 23240516Swpaul EE_SET(RL_EE_CLK); 23340516Swpaul DELAY(150); 23440516Swpaul EE_CLR(RL_EE_CLK); 23540516Swpaul DELAY(100); 23640516Swpaul } 23740516Swpaul 23840516Swpaul return; 23940516Swpaul} 24040516Swpaul 24140516Swpaul/* 24240516Swpaul * Read a word of data stored in the EEPROM at address 'addr.' 24340516Swpaul */ 24440516Swpaulstatic void rl_eeprom_getword(sc, addr, dest) 24540516Swpaul struct rl_softc *sc; 24641656Swpaul int addr; 24740516Swpaul u_int16_t *dest; 24840516Swpaul{ 24940516Swpaul register int i; 25040516Swpaul u_int16_t word = 0; 25140516Swpaul 25240516Swpaul /* Enter EEPROM access mode. */ 25340516Swpaul CSR_WRITE_1(sc, RL_EECMD, RL_EEMODE_PROGRAM|RL_EE_SEL); 25440516Swpaul 25540516Swpaul /* 25640516Swpaul * Send address of word we want to read. 25740516Swpaul */ 25840516Swpaul rl_eeprom_putbyte(sc, addr); 25940516Swpaul 26040516Swpaul CSR_WRITE_1(sc, RL_EECMD, RL_EEMODE_PROGRAM|RL_EE_SEL); 26140516Swpaul 26240516Swpaul /* 26340516Swpaul * Start reading bits from EEPROM. 26440516Swpaul */ 26540516Swpaul for (i = 0x8000; i; i >>= 1) { 26640516Swpaul EE_SET(RL_EE_CLK); 26740516Swpaul DELAY(100); 26840516Swpaul if (CSR_READ_1(sc, RL_EECMD) & RL_EE_DATAOUT) 26940516Swpaul word |= i; 27040516Swpaul EE_CLR(RL_EE_CLK); 27140516Swpaul DELAY(100); 27240516Swpaul } 27340516Swpaul 27440516Swpaul /* Turn off EEPROM access mode. */ 27540516Swpaul CSR_WRITE_1(sc, RL_EECMD, RL_EEMODE_OFF); 27640516Swpaul 27740516Swpaul *dest = word; 27840516Swpaul 27940516Swpaul return; 28040516Swpaul} 28140516Swpaul 28240516Swpaul/* 28340516Swpaul * Read a sequence of words from the EEPROM. 28440516Swpaul */ 28540516Swpaulstatic void rl_read_eeprom(sc, dest, off, cnt, swap) 28640516Swpaul struct rl_softc *sc; 28740516Swpaul caddr_t dest; 28840516Swpaul int off; 28940516Swpaul int cnt; 29040516Swpaul int swap; 29140516Swpaul{ 29240516Swpaul int i; 29340516Swpaul u_int16_t word = 0, *ptr; 29440516Swpaul 29540516Swpaul for (i = 0; i < cnt; i++) { 29640516Swpaul rl_eeprom_getword(sc, off + i, &word); 29740516Swpaul ptr = (u_int16_t *)(dest + (i * 2)); 29840516Swpaul if (swap) 29940516Swpaul *ptr = ntohs(word); 30040516Swpaul else 30140516Swpaul *ptr = word; 30240516Swpaul } 30340516Swpaul 30440516Swpaul return; 30540516Swpaul} 30640516Swpaul 30740516Swpaul 30840516Swpaul/* 30940516Swpaul * MII access routines are provided for the 8129, which 31040516Swpaul * doesn't have a built-in PHY. For the 8139, we fake things 31140516Swpaul * up by diverting rl_phy_readreg()/rl_phy_writereg() to the 31240516Swpaul * direct access PHY registers. 31340516Swpaul */ 31440516Swpaul#define MII_SET(x) \ 31540516Swpaul CSR_WRITE_1(sc, RL_MII, \ 31640516Swpaul CSR_READ_1(sc, RL_MII) | x) 31740516Swpaul 31840516Swpaul#define MII_CLR(x) \ 31940516Swpaul CSR_WRITE_1(sc, RL_MII, \ 32040516Swpaul CSR_READ_1(sc, RL_MII) & ~x) 32140516Swpaul 32240516Swpaul/* 32340516Swpaul * Sync the PHYs by setting data bit and strobing the clock 32 times. 32440516Swpaul */ 32540516Swpaulstatic void rl_mii_sync(sc) 32640516Swpaul struct rl_softc *sc; 32740516Swpaul{ 32840516Swpaul register int i; 32940516Swpaul 33040516Swpaul MII_SET(RL_MII_DIR|RL_MII_DATAOUT); 33140516Swpaul 33240516Swpaul for (i = 0; i < 32; i++) { 33340516Swpaul MII_SET(RL_MII_CLK); 33440516Swpaul DELAY(1); 33540516Swpaul MII_CLR(RL_MII_CLK); 33640516Swpaul DELAY(1); 33740516Swpaul } 33840516Swpaul 33940516Swpaul return; 34040516Swpaul} 34140516Swpaul 34240516Swpaul/* 34340516Swpaul * Clock a series of bits through the MII. 34440516Swpaul */ 34540516Swpaulstatic void rl_mii_send(sc, bits, cnt) 34640516Swpaul struct rl_softc *sc; 34740516Swpaul u_int32_t bits; 34840516Swpaul int cnt; 34940516Swpaul{ 35040516Swpaul int i; 35140516Swpaul 35240516Swpaul MII_CLR(RL_MII_CLK); 35340516Swpaul 35440516Swpaul for (i = (0x1 << (cnt - 1)); i; i >>= 1) { 35540516Swpaul if (bits & i) { 35640516Swpaul MII_SET(RL_MII_DATAOUT); 35740516Swpaul } else { 35840516Swpaul MII_CLR(RL_MII_DATAOUT); 35940516Swpaul } 36040516Swpaul DELAY(1); 36140516Swpaul MII_CLR(RL_MII_CLK); 36240516Swpaul DELAY(1); 36340516Swpaul MII_SET(RL_MII_CLK); 36440516Swpaul } 36540516Swpaul} 36640516Swpaul 36740516Swpaul/* 36840516Swpaul * Read an PHY register through the MII. 36940516Swpaul */ 37040516Swpaulstatic int rl_mii_readreg(sc, frame) 37140516Swpaul struct rl_softc *sc; 37240516Swpaul struct rl_mii_frame *frame; 37340516Swpaul 37440516Swpaul{ 37540516Swpaul int i, ack, s; 37640516Swpaul 37740516Swpaul s = splimp(); 37840516Swpaul 37940516Swpaul /* 38040516Swpaul * Set up frame for RX. 38140516Swpaul */ 38240516Swpaul frame->mii_stdelim = RL_MII_STARTDELIM; 38340516Swpaul frame->mii_opcode = RL_MII_READOP; 38440516Swpaul frame->mii_turnaround = 0; 38540516Swpaul frame->mii_data = 0; 38640516Swpaul 38740516Swpaul CSR_WRITE_2(sc, RL_MII, 0); 38840516Swpaul 38940516Swpaul /* 39040516Swpaul * Turn on data xmit. 39140516Swpaul */ 39240516Swpaul MII_SET(RL_MII_DIR); 39340516Swpaul 39440516Swpaul rl_mii_sync(sc); 39540516Swpaul 39640516Swpaul /* 39740516Swpaul * Send command/address info. 39840516Swpaul */ 39940516Swpaul rl_mii_send(sc, frame->mii_stdelim, 2); 40040516Swpaul rl_mii_send(sc, frame->mii_opcode, 2); 40140516Swpaul rl_mii_send(sc, frame->mii_phyaddr, 5); 40240516Swpaul rl_mii_send(sc, frame->mii_regaddr, 5); 40340516Swpaul 40440516Swpaul /* Idle bit */ 40540516Swpaul MII_CLR((RL_MII_CLK|RL_MII_DATAOUT)); 40640516Swpaul DELAY(1); 40740516Swpaul MII_SET(RL_MII_CLK); 40840516Swpaul DELAY(1); 40940516Swpaul 41040516Swpaul /* Turn off xmit. */ 41140516Swpaul MII_CLR(RL_MII_DIR); 41240516Swpaul 41340516Swpaul /* Check for ack */ 41440516Swpaul MII_CLR(RL_MII_CLK); 41540516Swpaul DELAY(1); 41640516Swpaul MII_SET(RL_MII_CLK); 41740516Swpaul DELAY(1); 41840516Swpaul ack = CSR_READ_2(sc, RL_MII) & RL_MII_DATAIN; 41940516Swpaul 42040516Swpaul /* 42140516Swpaul * Now try reading data bits. If the ack failed, we still 42240516Swpaul * need to clock through 16 cycles to keep the PHY(s) in sync. 42340516Swpaul */ 42440516Swpaul if (ack) { 42540516Swpaul for(i = 0; i < 16; i++) { 42640516Swpaul MII_CLR(RL_MII_CLK); 42740516Swpaul DELAY(1); 42840516Swpaul MII_SET(RL_MII_CLK); 42940516Swpaul DELAY(1); 43040516Swpaul } 43140516Swpaul goto fail; 43240516Swpaul } 43340516Swpaul 43440516Swpaul for (i = 0x8000; i; i >>= 1) { 43540516Swpaul MII_CLR(RL_MII_CLK); 43640516Swpaul DELAY(1); 43740516Swpaul if (!ack) { 43840516Swpaul if (CSR_READ_2(sc, RL_MII) & RL_MII_DATAIN) 43940516Swpaul frame->mii_data |= i; 44040516Swpaul DELAY(1); 44140516Swpaul } 44240516Swpaul MII_SET(RL_MII_CLK); 44340516Swpaul DELAY(1); 44440516Swpaul } 44540516Swpaul 44640516Swpaulfail: 44740516Swpaul 44840516Swpaul MII_CLR(RL_MII_CLK); 44940516Swpaul DELAY(1); 45040516Swpaul MII_SET(RL_MII_CLK); 45140516Swpaul DELAY(1); 45240516Swpaul 45340516Swpaul splx(s); 45440516Swpaul 45540516Swpaul if (ack) 45640516Swpaul return(1); 45740516Swpaul return(0); 45840516Swpaul} 45940516Swpaul 46040516Swpaul/* 46140516Swpaul * Write to a PHY register through the MII. 46240516Swpaul */ 46340516Swpaulstatic int rl_mii_writereg(sc, frame) 46440516Swpaul struct rl_softc *sc; 46540516Swpaul struct rl_mii_frame *frame; 46640516Swpaul 46740516Swpaul{ 46840516Swpaul int s; 46940516Swpaul 47040516Swpaul s = splimp(); 47140516Swpaul /* 47240516Swpaul * Set up frame for TX. 47340516Swpaul */ 47440516Swpaul 47540516Swpaul frame->mii_stdelim = RL_MII_STARTDELIM; 47640516Swpaul frame->mii_opcode = RL_MII_WRITEOP; 47740516Swpaul frame->mii_turnaround = RL_MII_TURNAROUND; 47840516Swpaul 47940516Swpaul /* 48040516Swpaul * Turn on data output. 48140516Swpaul */ 48240516Swpaul MII_SET(RL_MII_DIR); 48340516Swpaul 48440516Swpaul rl_mii_sync(sc); 48540516Swpaul 48640516Swpaul rl_mii_send(sc, frame->mii_stdelim, 2); 48740516Swpaul rl_mii_send(sc, frame->mii_opcode, 2); 48840516Swpaul rl_mii_send(sc, frame->mii_phyaddr, 5); 48940516Swpaul rl_mii_send(sc, frame->mii_regaddr, 5); 49040516Swpaul rl_mii_send(sc, frame->mii_turnaround, 2); 49140516Swpaul rl_mii_send(sc, frame->mii_data, 16); 49240516Swpaul 49340516Swpaul /* Idle bit. */ 49440516Swpaul MII_SET(RL_MII_CLK); 49540516Swpaul DELAY(1); 49640516Swpaul MII_CLR(RL_MII_CLK); 49740516Swpaul DELAY(1); 49840516Swpaul 49940516Swpaul /* 50040516Swpaul * Turn off xmit. 50140516Swpaul */ 50240516Swpaul MII_CLR(RL_MII_DIR); 50340516Swpaul 50440516Swpaul splx(s); 50540516Swpaul 50640516Swpaul return(0); 50740516Swpaul} 50840516Swpaul 50940516Swpaulstatic u_int16_t rl_phy_readreg(sc, reg) 51040516Swpaul struct rl_softc *sc; 51140516Swpaul int reg; 51240516Swpaul{ 51340516Swpaul struct rl_mii_frame frame; 51440516Swpaul u_int16_t rval = 0; 51540516Swpaul u_int16_t rl8139_reg = 0; 51640516Swpaul 51740516Swpaul if (sc->rl_type == RL_8139) { 51840516Swpaul switch(reg) { 51940516Swpaul case PHY_BMCR: 52040516Swpaul rl8139_reg = RL_BMCR; 52140516Swpaul break; 52240516Swpaul case PHY_BMSR: 52340516Swpaul rl8139_reg = RL_BMSR; 52440516Swpaul break; 52540516Swpaul case PHY_ANAR: 52640516Swpaul rl8139_reg = RL_ANAR; 52740516Swpaul break; 52840516Swpaul case PHY_LPAR: 52940516Swpaul rl8139_reg = RL_LPAR; 53040516Swpaul break; 53140516Swpaul default: 53240516Swpaul printf("rl%d: bad phy register\n", sc->rl_unit); 53340516Swpaul return(0); 53440516Swpaul } 53540516Swpaul rval = CSR_READ_2(sc, rl8139_reg); 53640516Swpaul return(rval); 53740516Swpaul } 53840516Swpaul 53940516Swpaul bzero((char *)&frame, sizeof(frame)); 54040516Swpaul 54140516Swpaul frame.mii_phyaddr = sc->rl_phy_addr; 54240516Swpaul frame.mii_regaddr = reg; 54340516Swpaul rl_mii_readreg(sc, &frame); 54440516Swpaul 54540516Swpaul return(frame.mii_data); 54640516Swpaul} 54740516Swpaul 54840516Swpaulstatic void rl_phy_writereg(sc, reg, data) 54940516Swpaul struct rl_softc *sc; 55041656Swpaul int reg; 55141656Swpaul int data; 55240516Swpaul{ 55340516Swpaul struct rl_mii_frame frame; 55440516Swpaul u_int16_t rl8139_reg = 0; 55540516Swpaul 55640516Swpaul if (sc->rl_type == RL_8139) { 55740516Swpaul switch(reg) { 55840516Swpaul case PHY_BMCR: 55940516Swpaul rl8139_reg = RL_BMCR; 56040516Swpaul break; 56140516Swpaul case PHY_BMSR: 56240516Swpaul rl8139_reg = RL_BMSR; 56340516Swpaul break; 56440516Swpaul case PHY_ANAR: 56540516Swpaul rl8139_reg = RL_ANAR; 56640516Swpaul break; 56740516Swpaul case PHY_LPAR: 56840516Swpaul rl8139_reg = RL_LPAR; 56940516Swpaul break; 57040516Swpaul default: 57140516Swpaul printf("rl%d: bad phy register\n", sc->rl_unit); 57240516Swpaul return; 57340516Swpaul } 57440516Swpaul CSR_WRITE_2(sc, rl8139_reg, data); 57541273Swpaul return; 57640516Swpaul } 57740516Swpaul 57840516Swpaul bzero((char *)&frame, sizeof(frame)); 57940516Swpaul 58040516Swpaul frame.mii_phyaddr = sc->rl_phy_addr; 58140516Swpaul frame.mii_regaddr = reg; 58240516Swpaul frame.mii_data = data; 58340516Swpaul 58440516Swpaul rl_mii_writereg(sc, &frame); 58540516Swpaul 58640516Swpaul return; 58740516Swpaul} 58840516Swpaul 58940516Swpaul/* 59040516Swpaul * Calculate CRC of a multicast group address, return the lower 6 bits. 59140516Swpaul */ 59240516Swpaulstatic u_int8_t rl_calchash(addr) 59341656Swpaul caddr_t addr; 59440516Swpaul{ 59540516Swpaul u_int32_t crc, carry; 59640516Swpaul int i, j; 59740516Swpaul u_int8_t c; 59840516Swpaul 59940516Swpaul /* Compute CRC for the address value. */ 60040516Swpaul crc = 0xFFFFFFFF; /* initial value */ 60140516Swpaul 60240516Swpaul for (i = 0; i < 6; i++) { 60340516Swpaul c = *(addr + i); 60440516Swpaul for (j = 0; j < 8; j++) { 60540516Swpaul carry = ((crc & 0x80000000) ? 1 : 0) ^ (c & 0x01); 60640516Swpaul crc <<= 1; 60740516Swpaul c >>= 1; 60840516Swpaul if (carry) 60940516Swpaul crc = (crc ^ 0x04c11db6) | carry; 61040516Swpaul } 61140516Swpaul } 61240516Swpaul 61340516Swpaul /* return the filter bit position */ 61440516Swpaul return(crc & 0x0000003F); 61540516Swpaul} 61640516Swpaul 61740516Swpaul/* 61840516Swpaul * Program the 64-bit multicast hash filter. 61940516Swpaul */ 62040516Swpaulstatic void rl_setmulti(sc) 62140516Swpaul struct rl_softc *sc; 62240516Swpaul{ 62340516Swpaul struct ifnet *ifp; 62440516Swpaul int h = 0; 62540516Swpaul u_int32_t hashes[2] = { 0, 0 }; 62640516Swpaul struct ifmultiaddr *ifma; 62740516Swpaul u_int32_t rxfilt; 62840516Swpaul int mcnt = 0; 62940516Swpaul 63040516Swpaul ifp = &sc->arpcom.ac_if; 63140516Swpaul 63240516Swpaul rxfilt = CSR_READ_4(sc, RL_RXCFG); 63340516Swpaul 63440516Swpaul if (ifp->if_flags & IFF_ALLMULTI) { 63540516Swpaul rxfilt |= RL_RXCFG_RX_MULTI; 63640516Swpaul CSR_WRITE_4(sc, RL_RXCFG, rxfilt); 63740516Swpaul CSR_WRITE_4(sc, RL_MAR0, 0xFFFFFFFF); 63840516Swpaul CSR_WRITE_4(sc, RL_MAR4, 0xFFFFFFFF); 63940516Swpaul return; 64040516Swpaul } 64140516Swpaul 64240516Swpaul /* first, zot all the existing hash bits */ 64340516Swpaul CSR_WRITE_4(sc, RL_MAR0, 0); 64440516Swpaul CSR_WRITE_4(sc, RL_MAR4, 0); 64540516Swpaul 64640516Swpaul /* now program new ones */ 64740516Swpaul for (ifma = ifp->if_multiaddrs.lh_first; ifma != NULL; 64840516Swpaul ifma = ifma->ifma_link.le_next) { 64940516Swpaul if (ifma->ifma_addr->sa_family != AF_LINK) 65040516Swpaul continue; 65140516Swpaul h = rl_calchash(LLADDR((struct sockaddr_dl *)ifma->ifma_addr)); 65240516Swpaul if (h < 32) 65340516Swpaul hashes[0] |= (1 << h); 65440516Swpaul else 65540516Swpaul hashes[1] |= (1 << (h - 32)); 65640516Swpaul mcnt++; 65740516Swpaul } 65840516Swpaul 65940516Swpaul if (mcnt) 66040516Swpaul rxfilt |= RL_RXCFG_RX_MULTI; 66140516Swpaul else 66240516Swpaul rxfilt &= ~RL_RXCFG_RX_MULTI; 66340516Swpaul 66440516Swpaul CSR_WRITE_4(sc, RL_RXCFG, rxfilt); 66540516Swpaul CSR_WRITE_4(sc, RL_MAR0, hashes[0]); 66640516Swpaul CSR_WRITE_4(sc, RL_MAR4, hashes[1]); 66740516Swpaul 66840516Swpaul return; 66940516Swpaul} 67040516Swpaul 67140516Swpaul/* 67240516Swpaul * Initiate an autonegotiation session. 67340516Swpaul */ 67440516Swpaulstatic void rl_autoneg_xmit(sc) 67540516Swpaul struct rl_softc *sc; 67640516Swpaul{ 67740516Swpaul u_int16_t phy_sts; 67840516Swpaul 67940516Swpaul rl_phy_writereg(sc, PHY_BMCR, PHY_BMCR_RESET); 68040516Swpaul DELAY(500); 68140516Swpaul while(rl_phy_readreg(sc, PHY_BMCR) 68240516Swpaul & PHY_BMCR_RESET); 68340516Swpaul 68440516Swpaul phy_sts = rl_phy_readreg(sc, PHY_BMCR); 68540516Swpaul phy_sts |= PHY_BMCR_AUTONEGENBL|PHY_BMCR_AUTONEGRSTR; 68640516Swpaul rl_phy_writereg(sc, PHY_BMCR, phy_sts); 68740516Swpaul 68840516Swpaul return; 68940516Swpaul} 69040516Swpaul 69140516Swpaul/* 69240516Swpaul * Invoke autonegotiation on a PHY. Also used with the 8139 internal 69340516Swpaul * transceiver. 69440516Swpaul */ 69540516Swpaulstatic void rl_autoneg_mii(sc, flag, verbose) 69640516Swpaul struct rl_softc *sc; 69740516Swpaul int flag; 69840516Swpaul int verbose; 69940516Swpaul{ 70040516Swpaul u_int16_t phy_sts = 0, media, advert, ability; 70140516Swpaul struct ifnet *ifp; 70240516Swpaul struct ifmedia *ifm; 70340516Swpaul 70440516Swpaul ifm = &sc->ifmedia; 70540516Swpaul ifp = &sc->arpcom.ac_if; 70640516Swpaul 70740516Swpaul /* 70840516Swpaul * The 100baseT4 PHY sometimes has the 'autoneg supported' 70940516Swpaul * bit cleared in the status register, but has the 'autoneg enabled' 71040516Swpaul * bit set in the control register. This is a contradiction, and 71140516Swpaul * I'm not sure how to handle it. If you want to force an attempt 71240516Swpaul * to autoneg for 100baseT4 PHYs, #define FORCE_AUTONEG_TFOUR 71340516Swpaul * and see what happens. 71440516Swpaul */ 71540516Swpaul#ifndef FORCE_AUTONEG_TFOUR 71640516Swpaul /* 71740516Swpaul * First, see if autoneg is supported. If not, there's 71840516Swpaul * no point in continuing. 71940516Swpaul */ 72040516Swpaul phy_sts = rl_phy_readreg(sc, PHY_BMSR); 72140516Swpaul if (!(phy_sts & PHY_BMSR_CANAUTONEG)) { 72240516Swpaul if (verbose) 72340516Swpaul printf("rl%d: autonegotiation not supported\n", 72440516Swpaul sc->rl_unit); 72540516Swpaul return; 72640516Swpaul } 72740516Swpaul#endif 72840516Swpaul 72940516Swpaul switch (flag) { 73040516Swpaul case RL_FLAG_FORCEDELAY: 73140516Swpaul /* 73240516Swpaul * XXX Never use this option anywhere but in the probe 73340516Swpaul * routine: making the kernel stop dead in its tracks 73440516Swpaul * for three whole seconds after we've gone multi-user 73540516Swpaul * is really bad manners. 73640516Swpaul */ 73740516Swpaul rl_autoneg_xmit(sc); 73840516Swpaul DELAY(5000000); 73940516Swpaul break; 74040516Swpaul case RL_FLAG_SCHEDDELAY: 74140516Swpaul /* 74240516Swpaul * Wait for the transmitter to go idle before starting 74340516Swpaul * an autoneg session, otherwise rl_start() may clobber 74440516Swpaul * our timeout, and we don't want to allow transmission 74540516Swpaul * during an autoneg session since that can screw it up. 74640516Swpaul */ 74740516Swpaul if (sc->rl_cdata.rl_tx_cnt) { 74840516Swpaul sc->rl_want_auto = 1; 74940516Swpaul return; 75040516Swpaul } 75140516Swpaul rl_autoneg_xmit(sc); 75240516Swpaul ifp->if_timer = 5; 75340516Swpaul sc->rl_autoneg = 1; 75440516Swpaul sc->rl_want_auto = 0; 75540516Swpaul return; 75640516Swpaul break; 75740516Swpaul case RL_FLAG_DELAYTIMEO: 75840516Swpaul ifp->if_timer = 0; 75940516Swpaul sc->rl_autoneg = 0; 76040516Swpaul break; 76140516Swpaul default: 76240516Swpaul printf("rl%d: invalid autoneg flag: %d\n", sc->rl_unit, flag); 76340516Swpaul return; 76440516Swpaul } 76540516Swpaul 76640516Swpaul if (rl_phy_readreg(sc, PHY_BMSR) & PHY_BMSR_AUTONEGCOMP) { 76740516Swpaul if (verbose) 76840516Swpaul printf("rl%d: autoneg complete, ", sc->rl_unit); 76940516Swpaul phy_sts = rl_phy_readreg(sc, PHY_BMSR); 77040516Swpaul } else { 77140516Swpaul if (verbose) 77240516Swpaul printf("rl%d: autoneg not complete, ", sc->rl_unit); 77340516Swpaul } 77440516Swpaul 77540516Swpaul media = rl_phy_readreg(sc, PHY_BMCR); 77640516Swpaul 77740516Swpaul /* Link is good. Report modes and set duplex mode. */ 77840516Swpaul if (rl_phy_readreg(sc, PHY_BMSR) & PHY_BMSR_LINKSTAT) { 77940516Swpaul if (verbose) 78040516Swpaul printf("link status good "); 78140516Swpaul advert = rl_phy_readreg(sc, PHY_ANAR); 78240516Swpaul ability = rl_phy_readreg(sc, PHY_LPAR); 78340516Swpaul 78440516Swpaul if (advert & PHY_ANAR_100BT4 && ability & PHY_ANAR_100BT4) { 78540516Swpaul ifm->ifm_media = IFM_ETHER|IFM_100_T4; 78640516Swpaul media |= PHY_BMCR_SPEEDSEL; 78740516Swpaul media &= ~PHY_BMCR_DUPLEX; 78840516Swpaul printf("(100baseT4)\n"); 78940516Swpaul } else if (advert & PHY_ANAR_100BTXFULL && 79040516Swpaul ability & PHY_ANAR_100BTXFULL) { 79140516Swpaul ifm->ifm_media = IFM_ETHER|IFM_100_TX|IFM_FDX; 79240516Swpaul media |= PHY_BMCR_SPEEDSEL; 79340516Swpaul media |= PHY_BMCR_DUPLEX; 79440516Swpaul printf("(full-duplex, 100Mbps)\n"); 79540516Swpaul } else if (advert & PHY_ANAR_100BTXHALF && 79640516Swpaul ability & PHY_ANAR_100BTXHALF) { 79740516Swpaul ifm->ifm_media = IFM_ETHER|IFM_100_TX|IFM_HDX; 79840516Swpaul media |= PHY_BMCR_SPEEDSEL; 79940516Swpaul media &= ~PHY_BMCR_DUPLEX; 80040516Swpaul printf("(half-duplex, 100Mbps)\n"); 80140516Swpaul } else if (advert & PHY_ANAR_10BTFULL && 80240516Swpaul ability & PHY_ANAR_10BTFULL) { 80340516Swpaul ifm->ifm_media = IFM_ETHER|IFM_10_T|IFM_FDX; 80440516Swpaul media &= ~PHY_BMCR_SPEEDSEL; 80540516Swpaul media |= PHY_BMCR_DUPLEX; 80640516Swpaul printf("(full-duplex, 10Mbps)\n"); 80741656Swpaul } else { 80840516Swpaul ifm->ifm_media = IFM_ETHER|IFM_10_T|IFM_HDX; 80940516Swpaul media &= ~PHY_BMCR_SPEEDSEL; 81040516Swpaul media &= ~PHY_BMCR_DUPLEX; 81140516Swpaul printf("(half-duplex, 10Mbps)\n"); 81240516Swpaul } 81340516Swpaul 81440516Swpaul /* Set ASIC's duplex mode to match the PHY. */ 81540516Swpaul rl_phy_writereg(sc, PHY_BMCR, media); 81640516Swpaul } else { 81740516Swpaul if (verbose) 81840516Swpaul printf("no carrier\n"); 81940516Swpaul } 82040516Swpaul 82140516Swpaul rl_init(sc); 82240516Swpaul 82340516Swpaul if (sc->rl_tx_pend) { 82440516Swpaul sc->rl_autoneg = 0; 82540516Swpaul sc->rl_tx_pend = 0; 82640516Swpaul rl_start(ifp); 82740516Swpaul } 82840516Swpaul 82940516Swpaul return; 83040516Swpaul} 83140516Swpaul 83240516Swpaulstatic void rl_getmode_mii(sc) 83340516Swpaul struct rl_softc *sc; 83440516Swpaul{ 83540516Swpaul u_int16_t bmsr; 83640516Swpaul struct ifnet *ifp; 83740516Swpaul 83840516Swpaul ifp = &sc->arpcom.ac_if; 83940516Swpaul 84040516Swpaul bmsr = rl_phy_readreg(sc, PHY_BMSR); 84140516Swpaul if (bootverbose) 84240516Swpaul printf("rl%d: PHY status word: %x\n", sc->rl_unit, bmsr); 84340516Swpaul 84440516Swpaul /* fallback */ 84540516Swpaul sc->ifmedia.ifm_media = IFM_ETHER|IFM_10_T|IFM_HDX; 84640516Swpaul 84740516Swpaul if (bmsr & PHY_BMSR_10BTHALF) { 84840516Swpaul if (bootverbose) 84940516Swpaul printf("rl%d: 10Mbps half-duplex mode supported\n", 85040516Swpaul sc->rl_unit); 85140516Swpaul ifmedia_add(&sc->ifmedia, 85240516Swpaul IFM_ETHER|IFM_10_T|IFM_HDX, 0, NULL); 85340516Swpaul ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_10_T, 0, NULL); 85440516Swpaul } 85540516Swpaul 85640516Swpaul if (bmsr & PHY_BMSR_10BTFULL) { 85740516Swpaul if (bootverbose) 85840516Swpaul printf("rl%d: 10Mbps full-duplex mode supported\n", 85940516Swpaul sc->rl_unit); 86040516Swpaul ifmedia_add(&sc->ifmedia, 86140516Swpaul IFM_ETHER|IFM_10_T|IFM_FDX, 0, NULL); 86240516Swpaul sc->ifmedia.ifm_media = IFM_ETHER|IFM_10_T|IFM_FDX; 86340516Swpaul } 86440516Swpaul 86540516Swpaul if (bmsr & PHY_BMSR_100BTXHALF) { 86640516Swpaul if (bootverbose) 86740516Swpaul printf("rl%d: 100Mbps half-duplex mode supported\n", 86840516Swpaul sc->rl_unit); 86940516Swpaul ifp->if_baudrate = 100000000; 87040516Swpaul ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_100_TX, 0, NULL); 87140516Swpaul ifmedia_add(&sc->ifmedia, 87240516Swpaul IFM_ETHER|IFM_100_TX|IFM_HDX, 0, NULL); 87340516Swpaul sc->ifmedia.ifm_media = IFM_ETHER|IFM_100_TX|IFM_HDX; 87440516Swpaul } 87540516Swpaul 87640516Swpaul if (bmsr & PHY_BMSR_100BTXFULL) { 87740516Swpaul if (bootverbose) 87840516Swpaul printf("rl%d: 100Mbps full-duplex mode supported\n", 87940516Swpaul sc->rl_unit); 88040516Swpaul ifp->if_baudrate = 100000000; 88140516Swpaul ifmedia_add(&sc->ifmedia, 88240516Swpaul IFM_ETHER|IFM_100_TX|IFM_FDX, 0, NULL); 88340516Swpaul sc->ifmedia.ifm_media = IFM_ETHER|IFM_100_TX|IFM_FDX; 88440516Swpaul } 88540516Swpaul 88640516Swpaul /* Some also support 100BaseT4. */ 88740516Swpaul if (bmsr & PHY_BMSR_100BT4) { 88840516Swpaul if (bootverbose) 88940516Swpaul printf("rl%d: 100baseT4 mode supported\n", sc->rl_unit); 89040516Swpaul ifp->if_baudrate = 100000000; 89140516Swpaul ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_100_T4, 0, NULL); 89240516Swpaul sc->ifmedia.ifm_media = IFM_ETHER|IFM_100_T4; 89340516Swpaul#ifdef FORCE_AUTONEG_TFOUR 89440516Swpaul if (bootverbose) 89540516Swpaul printf("rl%d: forcing on autoneg support for BT4\n", 89640516Swpaul sc->rl_unit); 89740516Swpaul ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_AUTO, 0 NULL): 89840516Swpaul sc->ifmedia.ifm_media = IFM_ETHER|IFM_AUTO; 89940516Swpaul#endif 90040516Swpaul } 90140516Swpaul 90240516Swpaul if (bmsr & PHY_BMSR_CANAUTONEG) { 90340516Swpaul if (bootverbose) 90440516Swpaul printf("rl%d: autoneg supported\n", sc->rl_unit); 90540516Swpaul ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_AUTO, 0, NULL); 90640516Swpaul sc->ifmedia.ifm_media = IFM_ETHER|IFM_AUTO; 90740516Swpaul } 90840516Swpaul 90940516Swpaul return; 91040516Swpaul} 91140516Swpaul 91240516Swpaul/* 91340516Swpaul * Set speed and duplex mode. 91440516Swpaul */ 91540516Swpaulstatic void rl_setmode_mii(sc, media) 91640516Swpaul struct rl_softc *sc; 91740516Swpaul int media; 91840516Swpaul{ 91940516Swpaul u_int16_t bmcr; 92040516Swpaul 92140516Swpaul printf("rl%d: selecting MII, ", sc->rl_unit); 92240516Swpaul 92340516Swpaul bmcr = rl_phy_readreg(sc, PHY_BMCR); 92440516Swpaul 92540516Swpaul bmcr &= ~(PHY_BMCR_AUTONEGENBL|PHY_BMCR_SPEEDSEL| 92640516Swpaul PHY_BMCR_DUPLEX|PHY_BMCR_LOOPBK); 92740516Swpaul 92840516Swpaul if (IFM_SUBTYPE(media) == IFM_100_T4) { 92940516Swpaul printf("100Mbps/T4, half-duplex\n"); 93040516Swpaul bmcr |= PHY_BMCR_SPEEDSEL; 93140516Swpaul bmcr &= ~PHY_BMCR_DUPLEX; 93240516Swpaul } 93340516Swpaul 93440516Swpaul if (IFM_SUBTYPE(media) == IFM_100_TX) { 93540516Swpaul printf("100Mbps, "); 93640516Swpaul bmcr |= PHY_BMCR_SPEEDSEL; 93740516Swpaul } 93840516Swpaul 93940516Swpaul if (IFM_SUBTYPE(media) == IFM_10_T) { 94040516Swpaul printf("10Mbps, "); 94140516Swpaul bmcr &= ~PHY_BMCR_SPEEDSEL; 94240516Swpaul } 94340516Swpaul 94440516Swpaul if ((media & IFM_GMASK) == IFM_FDX) { 94540516Swpaul printf("full duplex\n"); 94640516Swpaul bmcr |= PHY_BMCR_DUPLEX; 94740516Swpaul } else { 94840516Swpaul printf("half duplex\n"); 94940516Swpaul bmcr &= ~PHY_BMCR_DUPLEX; 95040516Swpaul } 95140516Swpaul 95240516Swpaul rl_phy_writereg(sc, PHY_BMCR, bmcr); 95340516Swpaul 95440516Swpaul return; 95540516Swpaul} 95640516Swpaul 95740516Swpaulstatic void rl_reset(sc) 95840516Swpaul struct rl_softc *sc; 95940516Swpaul{ 96040516Swpaul register int i; 96140516Swpaul 96240516Swpaul CSR_WRITE_1(sc, RL_COMMAND, RL_CMD_RESET); 96340516Swpaul 96440516Swpaul for (i = 0; i < RL_TIMEOUT; i++) { 96540516Swpaul DELAY(10); 96640516Swpaul if (!(CSR_READ_1(sc, RL_COMMAND) & RL_CMD_RESET)) 96740516Swpaul break; 96840516Swpaul } 96940516Swpaul if (i == RL_TIMEOUT) 97040516Swpaul printf("rl%d: reset never completed!\n", sc->rl_unit); 97140516Swpaul 97240516Swpaul return; 97340516Swpaul} 97440516Swpaul 97540516Swpaul/* 97640516Swpaul * Probe for a RealTek 8129/8139 chip. Check the PCI vendor and device 97740516Swpaul * IDs against our list and return a device name if we find a match. 97840516Swpaul */ 97941771Sdillonstatic const char * 98040516Swpaulrl_probe(config_id, device_id) 98140516Swpaul pcici_t config_id; 98240516Swpaul pcidi_t device_id; 98340516Swpaul{ 98440516Swpaul struct rl_type *t; 98540516Swpaul 98640516Swpaul t = rl_devs; 98740516Swpaul 98840516Swpaul while(t->rl_name != NULL) { 98940516Swpaul if ((device_id & 0xFFFF) == t->rl_vid && 99040516Swpaul ((device_id >> 16) & 0xFFFF) == t->rl_did) { 99140516Swpaul return(t->rl_name); 99240516Swpaul } 99340516Swpaul t++; 99440516Swpaul } 99540516Swpaul 99640516Swpaul return(NULL); 99740516Swpaul} 99840516Swpaul 99940516Swpaul/* 100040516Swpaul * Attach the interface. Allocate softc structures, do ifmedia 100140516Swpaul * setup and ethernet/BPF attach. 100240516Swpaul */ 100340516Swpaulstatic void 100440516Swpaulrl_attach(config_id, unit) 100540516Swpaul pcici_t config_id; 100640516Swpaul int unit; 100740516Swpaul{ 100840516Swpaul int s, i; 100940516Swpaul#ifndef RL_USEIOSPACE 101040516Swpaul vm_offset_t pbase, vbase; 101140516Swpaul#endif 101240516Swpaul u_char eaddr[ETHER_ADDR_LEN]; 101340516Swpaul u_int32_t command; 101440516Swpaul struct rl_softc *sc; 101540516Swpaul struct ifnet *ifp; 101640516Swpaul int media = IFM_ETHER|IFM_100_TX|IFM_FDX; 101740516Swpaul struct rl_type *p; 101840516Swpaul u_int16_t phy_vid, phy_did, phy_sts; 101940516Swpaul u_int16_t rl_did = 0; 102040516Swpaul 102140516Swpaul s = splimp(); 102240516Swpaul 102340516Swpaul sc = malloc(sizeof(struct rl_softc), M_DEVBUF, M_NOWAIT); 102440516Swpaul if (sc == NULL) { 102540516Swpaul printf("rl%d: no memory for softc struct!\n", unit); 102640516Swpaul return; 102740516Swpaul } 102840516Swpaul bzero(sc, sizeof(struct rl_softc)); 102940516Swpaul 103040516Swpaul /* 103140516Swpaul * Handle power management nonsense. 103240516Swpaul */ 103340516Swpaul 103440516Swpaul command = pci_conf_read(config_id, RL_PCI_CAPID) & 0x000000FF; 103540516Swpaul if (command == 0x01) { 103640516Swpaul 103740516Swpaul command = pci_conf_read(config_id, RL_PCI_PWRMGMTCTRL); 103840516Swpaul if (command & RL_PSTATE_MASK) { 103940516Swpaul u_int32_t iobase, membase, irq; 104040516Swpaul 104140516Swpaul /* Save important PCI config data. */ 104240516Swpaul iobase = pci_conf_read(config_id, RL_PCI_LOIO); 104340516Swpaul membase = pci_conf_read(config_id, RL_PCI_LOMEM); 104440516Swpaul irq = pci_conf_read(config_id, RL_PCI_INTLINE); 104540516Swpaul 104640516Swpaul /* Reset the power state. */ 104740516Swpaul printf("rl%d: chip is is in D%d power mode " 104840516Swpaul "-- setting to D0\n", unit, command & RL_PSTATE_MASK); 104940516Swpaul command &= 0xFFFFFFFC; 105040516Swpaul pci_conf_write(config_id, RL_PCI_PWRMGMTCTRL, command); 105140516Swpaul 105240516Swpaul /* Restore PCI config data. */ 105340516Swpaul pci_conf_write(config_id, RL_PCI_LOIO, iobase); 105440516Swpaul pci_conf_write(config_id, RL_PCI_LOMEM, membase); 105540516Swpaul pci_conf_write(config_id, RL_PCI_INTLINE, irq); 105640516Swpaul } 105740516Swpaul } 105840516Swpaul 105940516Swpaul /* 106040516Swpaul * Map control/status registers. 106140516Swpaul */ 106240516Swpaul command = pci_conf_read(config_id, PCI_COMMAND_STATUS_REG); 106340516Swpaul command |= (PCIM_CMD_PORTEN|PCIM_CMD_MEMEN|PCIM_CMD_BUSMASTEREN); 106440516Swpaul pci_conf_write(config_id, PCI_COMMAND_STATUS_REG, command); 106540516Swpaul command = pci_conf_read(config_id, PCI_COMMAND_STATUS_REG); 106640516Swpaul 106740516Swpaul#ifdef RL_USEIOSPACE 106840516Swpaul if (!(command & PCIM_CMD_PORTEN)) { 106940516Swpaul printf("rl%d: failed to enable I/O ports!\n", unit); 107040516Swpaul free(sc, M_DEVBUF); 107140516Swpaul goto fail; 107240516Swpaul } 107340516Swpaul 107441569Swpaul if (!pci_map_port(config_id, RL_PCI_LOIO, 107541569Swpaul (u_int16_t *)&(sc->rl_bhandle))) { 107641569Swpaul printf ("rl%d: couldn't map ports\n", unit); 107741569Swpaul goto fail; 107841569Swpaul } 107941569Swpaul sc->rl_btag = I386_BUS_SPACE_IO; 108040516Swpaul#else 108140516Swpaul if (!(command & PCIM_CMD_MEMEN)) { 108240516Swpaul printf("rl%d: failed to enable memory mapping!\n", unit); 108340516Swpaul goto fail; 108440516Swpaul } 108540516Swpaul 108640516Swpaul if (!pci_map_mem(config_id, RL_PCI_LOMEM, &vbase, &pbase)) { 108740516Swpaul printf ("rl%d: couldn't map memory\n", unit); 108840516Swpaul goto fail; 108940516Swpaul } 109041569Swpaul sc->rl_btag = I386_BUS_SPACE_MEM; 109141569Swpaul sc->rl_bhandle = vbase; 109240516Swpaul#endif 109340516Swpaul 109440516Swpaul /* Allocate interrupt */ 109540516Swpaul if (!pci_map_int(config_id, rl_intr, sc, &net_imask)) { 109640516Swpaul printf("rl%d: couldn't map interrupt\n", unit); 109740516Swpaul goto fail; 109840516Swpaul } 109940516Swpaul 110040516Swpaul /* Reset the adapter. */ 110140516Swpaul rl_reset(sc); 110240516Swpaul 110340516Swpaul /* 110440516Swpaul * Get station address from the EEPROM. 110540516Swpaul */ 110640516Swpaul rl_read_eeprom(sc, (caddr_t)&eaddr, RL_EE_EADDR, 3, 0); 110740516Swpaul 110840516Swpaul /* 110940516Swpaul * A RealTek chip was detected. Inform the world. 111040516Swpaul */ 111140516Swpaul printf("rl%d: Ethernet address: %6D\n", unit, eaddr, ":"); 111240516Swpaul 111340516Swpaul sc->rl_unit = unit; 111440516Swpaul bcopy(eaddr, (char *)&sc->arpcom.ac_enaddr, ETHER_ADDR_LEN); 111540516Swpaul 111640516Swpaul /* 111740516Swpaul * Now read the exact device type from the EEPROM to find 111840516Swpaul * out if it's an 8129 or 8139. 111940516Swpaul */ 112040516Swpaul rl_read_eeprom(sc, (caddr_t)&rl_did, RL_EE_PCI_DID, 1, 0); 112140516Swpaul 112241569Swpaul if (rl_did == RT_DEVICEID_8139 || rl_did == ACCTON_DEVICEID_5030) 112340516Swpaul sc->rl_type = RL_8139; 112440516Swpaul else if (rl_did == RT_DEVICEID_8129) 112540516Swpaul sc->rl_type = RL_8129; 112640516Swpaul else { 112740516Swpaul printf("rl%d: unknown device ID: %x\n", unit, rl_did); 112840516Swpaul free(sc, M_DEVBUF); 112940516Swpaul goto fail; 113040516Swpaul } 113140516Swpaul 113240516Swpaul sc->rl_cdata.rl_rx_buf = contigmalloc(RL_RXBUFLEN + 16, M_DEVBUF, 113340516Swpaul M_NOWAIT, 0x100000, 0xffffffff, PAGE_SIZE, 0); 113440516Swpaul 113540516Swpaul if (sc->rl_cdata.rl_rx_buf == NULL) { 113640516Swpaul free(sc, M_DEVBUF); 113740516Swpaul printf("rl%d: no memory for list buffers!\n", unit); 113840516Swpaul goto fail; 113940516Swpaul } 114040516Swpaul 114140516Swpaul ifp = &sc->arpcom.ac_if; 114240516Swpaul ifp->if_softc = sc; 114340516Swpaul ifp->if_unit = unit; 114440516Swpaul ifp->if_name = "rl"; 114540516Swpaul ifp->if_mtu = ETHERMTU; 114640516Swpaul ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 114740516Swpaul ifp->if_ioctl = rl_ioctl; 114840516Swpaul ifp->if_output = ether_output; 114940516Swpaul ifp->if_start = rl_start; 115040516Swpaul ifp->if_watchdog = rl_watchdog; 115140516Swpaul ifp->if_init = rl_init; 115240516Swpaul ifp->if_baudrate = 10000000; 115340516Swpaul 115440516Swpaul if (sc->rl_type == RL_8129) { 115540516Swpaul if (bootverbose) 115640516Swpaul printf("rl%d: probing for a PHY\n", sc->rl_unit); 115740516Swpaul for (i = RL_PHYADDR_MIN; i < RL_PHYADDR_MAX + 1; i++) { 115840516Swpaul if (bootverbose) 115940516Swpaul printf("rl%d: checking address: %d\n", 116040516Swpaul sc->rl_unit, i); 116140516Swpaul sc->rl_phy_addr = i; 116240516Swpaul rl_phy_writereg(sc, PHY_BMCR, PHY_BMCR_RESET); 116340516Swpaul DELAY(500); 116440516Swpaul while(rl_phy_readreg(sc, PHY_BMCR) 116540516Swpaul & PHY_BMCR_RESET); 116640516Swpaul if ((phy_sts = rl_phy_readreg(sc, PHY_BMSR))) 116740516Swpaul break; 116840516Swpaul } 116940516Swpaul if (phy_sts) { 117040516Swpaul phy_vid = rl_phy_readreg(sc, PHY_VENID); 117140516Swpaul phy_did = rl_phy_readreg(sc, PHY_DEVID); 117240516Swpaul if (bootverbose) 117340516Swpaul printf("rl%d: found PHY at address %d, ", 117440516Swpaul sc->rl_unit, sc->rl_phy_addr); 117540516Swpaul if (bootverbose) 117640516Swpaul printf("vendor id: %x device id: %x\n", 117740516Swpaul phy_vid, phy_did); 117840516Swpaul p = rl_phys; 117940516Swpaul while(p->rl_vid) { 118040516Swpaul if (phy_vid == p->rl_vid && 118140516Swpaul (phy_did | 0x000F) == p->rl_did) { 118240516Swpaul sc->rl_pinfo = p; 118340516Swpaul break; 118440516Swpaul } 118540516Swpaul p++; 118640516Swpaul } 118740516Swpaul if (sc->rl_pinfo == NULL) 118840516Swpaul sc->rl_pinfo = &rl_phys[PHY_UNKNOWN]; 118940516Swpaul if (bootverbose) 119040516Swpaul printf("rl%d: PHY type: %s\n", 119140516Swpaul sc->rl_unit, sc->rl_pinfo->rl_name); 119240516Swpaul } else { 119340516Swpaul printf("rl%d: MII without any phy!\n", sc->rl_unit); 119440516Swpaul } 119540516Swpaul } 119640516Swpaul 119740516Swpaul /* 119840516Swpaul * Do ifmedia setup. 119940516Swpaul */ 120040516Swpaul ifmedia_init(&sc->ifmedia, 0, rl_ifmedia_upd, rl_ifmedia_sts); 120140516Swpaul 120240516Swpaul rl_getmode_mii(sc); 120340516Swpaul 120440516Swpaul /* Choose a default media. */ 120540516Swpaul media = IFM_ETHER|IFM_AUTO; 120640516Swpaul ifmedia_set(&sc->ifmedia, media); 120740516Swpaul 120840516Swpaul rl_autoneg_mii(sc, RL_FLAG_FORCEDELAY, 1); 120940516Swpaul 121040516Swpaul /* 121140516Swpaul * Call MI attach routines. 121240516Swpaul */ 121340516Swpaul if_attach(ifp); 121440516Swpaul ether_ifattach(ifp); 121540516Swpaul 121640516Swpaul#if NBPFILTER > 0 121740516Swpaul bpfattach(ifp, DLT_EN10MB, sizeof(struct ether_header)); 121840516Swpaul#endif 121940516Swpaul at_shutdown(rl_shutdown, sc, SHUTDOWN_POST_SYNC); 122040516Swpaul 122140516Swpaulfail: 122240516Swpaul splx(s); 122340516Swpaul return; 122440516Swpaul} 122540516Swpaul 122640516Swpaul/* 122740516Swpaul * Initialize the transmit descriptors. 122840516Swpaul */ 122940516Swpaulstatic int rl_list_tx_init(sc) 123040516Swpaul struct rl_softc *sc; 123140516Swpaul{ 123240516Swpaul struct rl_chain_data *cd; 123340516Swpaul int i; 123440516Swpaul 123540516Swpaul cd = &sc->rl_cdata; 123640516Swpaul for (i = 0; i < RL_TX_LIST_CNT; i++) { 123740516Swpaul cd->rl_tx_chain[i].rl_desc = i * 4; 123840516Swpaul CSR_WRITE_4(sc, RL_TXADDR0 + cd->rl_tx_chain[i].rl_desc, 0); 123940516Swpaul CSR_WRITE_4(sc, RL_TXSTAT0 + cd->rl_tx_chain[i].rl_desc, 0); 124040516Swpaul if (i == (RL_TX_LIST_CNT - 1)) 124140516Swpaul cd->rl_tx_chain[i].rl_next = &cd->rl_tx_chain[0]; 124240516Swpaul else 124340516Swpaul cd->rl_tx_chain[i].rl_next = &cd->rl_tx_chain[i + 1]; 124440516Swpaul } 124540516Swpaul 124640516Swpaul sc->rl_cdata.rl_tx_cnt = 0; 124740516Swpaul cd->rl_tx_cur = cd->rl_tx_free = &cd->rl_tx_chain[0]; 124840516Swpaul 124940516Swpaul return(0); 125040516Swpaul} 125140516Swpaul 125240516Swpaul/* 125340516Swpaul * A frame has been uploaded: pass the resulting mbuf chain up to 125440516Swpaul * the higher level protocols. 125540516Swpaul * 125640516Swpaul * You know there's something wrong with a PCI bus-master chip design 125740516Swpaul * when you have to use m_devget(). 125840516Swpaul * 125940516Swpaul * The receive operation is badly documented in the datasheet, so I'll 126040516Swpaul * attempt to document it here. The driver provides a buffer area and 126140516Swpaul * places its base address in the RX buffer start address register. 126240516Swpaul * The chip then begins copying frames into the RX buffer. Each frame 126340516Swpaul * is preceeded by a 32-bit RX status word which specifies the length 126440516Swpaul * of the frame and certain other status bits. Each frame (starting with 126540516Swpaul * the status word) is also 32-bit aligned. The frame length is in the 126640516Swpaul * first 16 bits of the status word; the lower 15 bits correspond with 126740516Swpaul * the 'rx status register' mentioned in the datasheet. 126840516Swpaul */ 126940516Swpaulstatic void rl_rxeof(sc) 127040516Swpaul struct rl_softc *sc; 127140516Swpaul{ 127240516Swpaul struct ether_header *eh; 127340516Swpaul struct mbuf *m; 127440516Swpaul struct ifnet *ifp; 127540516Swpaul int total_len = 0; 127640516Swpaul u_int32_t rxstat; 127740516Swpaul caddr_t rxbufpos; 127840516Swpaul int wrap = 0; 127940516Swpaul u_int16_t cur_rx; 128040516Swpaul u_int16_t limit; 128140516Swpaul u_int16_t rx_bytes = 0, max_bytes; 128240516Swpaul 128340516Swpaul ifp = &sc->arpcom.ac_if; 128440516Swpaul 128540516Swpaul cur_rx = (CSR_READ_2(sc, RL_CURRXADDR) + 16) % RL_RXBUFLEN; 128640516Swpaul 128740516Swpaul /* Do not try to read past this point. */ 128840516Swpaul limit = CSR_READ_2(sc, RL_CURRXBUF) % RL_RXBUFLEN; 128940516Swpaul 129040516Swpaul if (limit < cur_rx) 129140516Swpaul max_bytes = (RL_RXBUFLEN - cur_rx) + limit; 129240516Swpaul else 129340516Swpaul max_bytes = limit - cur_rx; 129440516Swpaul 129542738Swpaul while((CSR_READ_1(sc, RL_COMMAND) & RL_CMD_EMPTY_RXBUF) == 0) { 129640516Swpaul rxbufpos = sc->rl_cdata.rl_rx_buf + cur_rx; 129740516Swpaul rxstat = *(u_int32_t *)rxbufpos; 129840516Swpaul 129940516Swpaul /* 130040516Swpaul * Here's a totally undocumented fact for you. When the 130140516Swpaul * RealTek chip is in the process of copying a packet into 130240516Swpaul * RAM for you, the length will be 0xfff0. If you spot a 130340516Swpaul * packet header with this value, you need to stop. The 130440516Swpaul * datasheet makes absolutely no mention of this and 130540516Swpaul * RealTek should be shot for this. 130640516Swpaul */ 130740516Swpaul if ((u_int16_t)(rxstat >> 16) == RL_RXSTAT_UNFINISHED) 130840516Swpaul break; 130940516Swpaul 131040516Swpaul if (!(rxstat & RL_RXSTAT_RXOK)) { 131140516Swpaul ifp->if_ierrors++; 131240516Swpaul if (rxstat & (RL_RXSTAT_BADSYM|RL_RXSTAT_RUNT| 131340516Swpaul RL_RXSTAT_GIANT|RL_RXSTAT_CRCERR| 131440516Swpaul RL_RXSTAT_ALIGNERR)) { 131540516Swpaul CSR_WRITE_2(sc, RL_COMMAND, RL_CMD_TX_ENB); 131640516Swpaul CSR_WRITE_2(sc, RL_COMMAND, RL_CMD_TX_ENB| 131740516Swpaul RL_CMD_RX_ENB); 131840516Swpaul CSR_WRITE_4(sc, RL_RXCFG, RL_RXCFG_CONFIG); 131940516Swpaul CSR_WRITE_4(sc, RL_RXADDR, 132040516Swpaul vtophys(sc->rl_cdata.rl_rx_buf)); 132140516Swpaul CSR_WRITE_2(sc, RL_CURRXADDR, cur_rx - 16); 132240516Swpaul cur_rx = 0; 132340516Swpaul } 132440516Swpaul break; 132540516Swpaul } 132640516Swpaul 132740516Swpaul /* No errors; receive the packet. */ 132840516Swpaul total_len = rxstat >> 16; 132940516Swpaul rx_bytes += total_len + 4; 133040516Swpaul 133140516Swpaul /* 133242051Swpaul * XXX The RealTek chip includes the CRC with every 133342051Swpaul * received frame, and there's no way to turn this 133442051Swpaul * behavior off (at least, I can't find anything in 133542051Swpaul * the manual that explains how to do it) so we have 133642051Swpaul * to trim off the CRC manually. 133742051Swpaul */ 133842051Swpaul total_len -= ETHER_CRC_LEN; 133942051Swpaul 134042051Swpaul /* 134140516Swpaul * Avoid trying to read more bytes than we know 134240516Swpaul * the chip has prepared for us. 134340516Swpaul */ 134440516Swpaul if (rx_bytes > max_bytes) 134540516Swpaul break; 134640516Swpaul 134740516Swpaul rxbufpos = sc->rl_cdata.rl_rx_buf + 134840516Swpaul ((cur_rx + sizeof(u_int32_t)) % RL_RXBUFLEN); 134940516Swpaul 135040516Swpaul if (rxbufpos == (sc->rl_cdata.rl_rx_buf + RL_RXBUFLEN)) 135140516Swpaul rxbufpos = sc->rl_cdata.rl_rx_buf; 135240516Swpaul 135340516Swpaul wrap = (sc->rl_cdata.rl_rx_buf + RL_RXBUFLEN) - rxbufpos; 135440516Swpaul 135540516Swpaul if (total_len > wrap) { 135640516Swpaul m = m_devget(rxbufpos, wrap, 0, ifp, NULL); 135740516Swpaul if (m == NULL) { 135840516Swpaul ifp->if_ierrors++; 135940516Swpaul printf("rl%d: out of mbufs, tried to " 136040516Swpaul "copy %d bytes\n", sc->rl_unit, wrap); 136140516Swpaul } 136240516Swpaul else 136340516Swpaul m_copyback(m, wrap, total_len - wrap, 136440516Swpaul sc->rl_cdata.rl_rx_buf); 136542051Swpaul cur_rx = (total_len - wrap + ETHER_CRC_LEN); 136640516Swpaul } else { 136740516Swpaul m = m_devget(rxbufpos, total_len, 0, ifp, NULL); 136840516Swpaul if (m == NULL) { 136940516Swpaul ifp->if_ierrors++; 137040516Swpaul printf("rl%d: out of mbufs, tried to " 137140516Swpaul "copy %d bytes\n", sc->rl_unit, total_len); 137240516Swpaul } 137342051Swpaul cur_rx += total_len + 4 + ETHER_CRC_LEN; 137440516Swpaul } 137540516Swpaul 137640516Swpaul /* 137740516Swpaul * Round up to 32-bit boundary. 137840516Swpaul */ 137940516Swpaul cur_rx = (cur_rx + 3) & ~3; 138040516Swpaul CSR_WRITE_2(sc, RL_CURRXADDR, cur_rx - 16); 138140516Swpaul 138240516Swpaul if (m == NULL) 138340516Swpaul continue; 138440516Swpaul 138540516Swpaul eh = mtod(m, struct ether_header *); 138640516Swpaul ifp->if_ipackets++; 138740516Swpaul 138840516Swpaul#if NBPFILTER > 0 138940516Swpaul /* 139040516Swpaul * Handle BPF listeners. Let the BPF user see the packet, but 139140516Swpaul * don't pass it up to the ether_input() layer unless it's 139240516Swpaul * a broadcast packet, multicast packet, matches our ethernet 139340516Swpaul * address or the interface is in promiscuous mode. 139440516Swpaul */ 139540516Swpaul if (ifp->if_bpf) { 139640516Swpaul bpf_mtap(ifp, m); 139740516Swpaul if (ifp->if_flags & IFF_PROMISC && 139840516Swpaul (bcmp(eh->ether_dhost, sc->arpcom.ac_enaddr, 139940516Swpaul ETHER_ADDR_LEN) && 140040516Swpaul (eh->ether_dhost[0] & 1) == 0)) { 140140516Swpaul m_freem(m); 140240516Swpaul continue; 140340516Swpaul } 140440516Swpaul } 140540516Swpaul#endif 140640516Swpaul /* Remove header from mbuf and pass it on. */ 140740516Swpaul m_adj(m, sizeof(struct ether_header)); 140840516Swpaul ether_input(ifp, eh, m); 140940516Swpaul } 141040516Swpaul 141140516Swpaul return; 141240516Swpaul} 141340516Swpaul 141440516Swpaul/* 141540516Swpaul * A frame was downloaded to the chip. It's safe for us to clean up 141640516Swpaul * the list buffers. 141740516Swpaul */ 141840516Swpaulstatic void rl_txeof(sc) 141940516Swpaul struct rl_softc *sc; 142040516Swpaul{ 142140516Swpaul struct rl_chain *cur_tx; 142240516Swpaul struct ifnet *ifp; 142340516Swpaul u_int32_t txstat; 142440516Swpaul 142540516Swpaul ifp = &sc->arpcom.ac_if; 142640516Swpaul 142740516Swpaul /* Clear the timeout timer. */ 142840516Swpaul ifp->if_timer = 0; 142940516Swpaul 143040516Swpaul /* 143140516Swpaul * Go through our tx list and free mbufs for those 143240516Swpaul * frames that have been uploaded. 143340516Swpaul */ 143440516Swpaul if (sc->rl_cdata.rl_tx_free == NULL) 143540516Swpaul return; 143640516Swpaul 143740516Swpaul while(sc->rl_cdata.rl_tx_free->rl_mbuf != NULL) { 143840516Swpaul cur_tx = sc->rl_cdata.rl_tx_free; 143940516Swpaul txstat = CSR_READ_4(sc, RL_TXSTAT0 + cur_tx->rl_desc); 144040516Swpaul 144140516Swpaul if (!(txstat & RL_TXSTAT_TX_OK)) 144240516Swpaul break; 144340516Swpaul 144440516Swpaul if (txstat & RL_TXSTAT_COLLCNT) 144540516Swpaul ifp->if_collisions += 144640516Swpaul (txstat & RL_TXSTAT_COLLCNT) >> 24; 144740516Swpaul 144840516Swpaul sc->rl_cdata.rl_tx_free = cur_tx->rl_next; 144940516Swpaul 145040516Swpaul sc->rl_cdata.rl_tx_cnt--; 145140516Swpaul m_freem(cur_tx->rl_mbuf); 145240516Swpaul cur_tx->rl_mbuf = NULL; 145340516Swpaul ifp->if_opackets++; 145440516Swpaul } 145540516Swpaul 145640516Swpaul if (!sc->rl_cdata.rl_tx_cnt) { 145740516Swpaul ifp->if_flags &= ~IFF_OACTIVE; 145840516Swpaul if (sc->rl_want_auto) 145940516Swpaul rl_autoneg_mii(sc, RL_FLAG_SCHEDDELAY, 1); 146040516Swpaul } else { 146140516Swpaul if (ifp->if_snd.ifq_head != NULL) 146240516Swpaul rl_start(ifp); 146340516Swpaul } 146440516Swpaul 146540516Swpaul return; 146640516Swpaul} 146740516Swpaul 146840516Swpaul/* 146940516Swpaul * TX error handler. 147040516Swpaul */ 147140516Swpaulstatic void rl_txeoc(sc) 147240516Swpaul struct rl_softc *sc; 147340516Swpaul{ 147440516Swpaul u_int32_t txstat; 147540516Swpaul struct rl_chain *cur_tx; 147640516Swpaul struct ifnet *ifp; 147740516Swpaul 147840516Swpaul ifp = &sc->arpcom.ac_if; 147940516Swpaul 148040516Swpaul if (sc->rl_cdata.rl_tx_free == NULL) 148140516Swpaul return; 148240516Swpaul 148340516Swpaul while(sc->rl_cdata.rl_tx_free->rl_mbuf != NULL) { 148440516Swpaul cur_tx = sc->rl_cdata.rl_tx_free; 148540516Swpaul txstat = CSR_READ_4(sc, RL_TXSTAT0 + cur_tx->rl_desc); 148640516Swpaul 148740516Swpaul if (!(txstat & RL_TXSTAT_OWN)) 148840516Swpaul break; 148940516Swpaul 149040516Swpaul if (!(txstat & RL_TXSTAT_TX_OK)) { 149140516Swpaul ifp->if_oerrors++; 149240516Swpaul if (txstat & RL_TXSTAT_COLLCNT) 149340516Swpaul ifp->if_collisions += 149440516Swpaul (txstat & RL_TXSTAT_COLLCNT) >> 24; 149540516Swpaul CSR_WRITE_4(sc, RL_TXADDR0 + cur_tx->rl_desc, 149640516Swpaul vtophys(mtod(cur_tx->rl_mbuf, caddr_t))); 149740516Swpaul CSR_WRITE_4(sc, RL_TXSTAT0 + cur_tx->rl_desc, 149840516Swpaul RL_TX_EARLYTHRESH | 149940516Swpaul cur_tx->rl_mbuf->m_pkthdr.len); 150040516Swpaul break; 150140516Swpaul } else { 150240516Swpaul if (txstat & RL_TXSTAT_COLLCNT) 150340516Swpaul ifp->if_collisions += 150440516Swpaul (txstat & RL_TXSTAT_COLLCNT) >> 24; 150540516Swpaul sc->rl_cdata.rl_tx_free = cur_tx->rl_next; 150640516Swpaul 150740516Swpaul sc->rl_cdata.rl_tx_cnt--; 150840516Swpaul m_freem(cur_tx->rl_mbuf); 150940516Swpaul cur_tx->rl_mbuf = NULL; 151040516Swpaul ifp->if_opackets++; 151140516Swpaul } 151240516Swpaul } 151340516Swpaul 151440516Swpaul return; 151540516Swpaul} 151640516Swpaul 151740516Swpaulstatic void rl_intr(arg) 151840516Swpaul void *arg; 151940516Swpaul{ 152040516Swpaul struct rl_softc *sc; 152140516Swpaul struct ifnet *ifp; 152240516Swpaul u_int16_t status; 152340516Swpaul 152440516Swpaul sc = arg; 152540516Swpaul ifp = &sc->arpcom.ac_if; 152640516Swpaul 152740516Swpaul /* Disable interrupts. */ 152840516Swpaul CSR_WRITE_2(sc, RL_IMR, 0x0000); 152940516Swpaul 153040516Swpaul for (;;) { 153140516Swpaul 153240516Swpaul status = CSR_READ_2(sc, RL_ISR); 153340516Swpaul if (status) 153440516Swpaul CSR_WRITE_2(sc, RL_ISR, status); 153540516Swpaul 153640516Swpaul if ((status & RL_INTRS) == 0) 153740516Swpaul break; 153840516Swpaul 153940516Swpaul if (status & RL_ISR_RX_OK) 154040516Swpaul rl_rxeof(sc); 154140516Swpaul 154240516Swpaul if (status & RL_ISR_RX_ERR) 154340516Swpaul rl_rxeof(sc); 154440516Swpaul 154540516Swpaul if (status & RL_ISR_TX_OK) 154640516Swpaul rl_txeof(sc); 154740516Swpaul 154840516Swpaul if (status & RL_ISR_TX_ERR) 154940516Swpaul rl_txeoc(sc); 155040516Swpaul 155140516Swpaul if (status & RL_ISR_SYSTEM_ERR) { 155240516Swpaul rl_reset(sc); 155340516Swpaul rl_init(sc); 155440516Swpaul } 155540516Swpaul 155640516Swpaul } 155740516Swpaul 155840516Swpaul /* Re-enable interrupts. */ 155940516Swpaul CSR_WRITE_2(sc, RL_IMR, RL_INTRS); 156040516Swpaul 156140516Swpaul if (ifp->if_snd.ifq_head != NULL) { 156240516Swpaul rl_start(ifp); 156340516Swpaul } 156440516Swpaul 156540516Swpaul return; 156640516Swpaul} 156740516Swpaul 156840516Swpaul/* 156940516Swpaul * Encapsulate an mbuf chain in a descriptor by coupling the mbuf data 157040516Swpaul * pointers to the fragment pointers. 157140516Swpaul */ 157240516Swpaulstatic int rl_encap(sc, c, m_head) 157340516Swpaul struct rl_softc *sc; 157440516Swpaul struct rl_chain *c; 157540516Swpaul struct mbuf *m_head; 157640516Swpaul{ 157740516Swpaul struct mbuf *m; 157841243Swpaul struct mbuf *m_new = NULL; 157940516Swpaul 158040516Swpaul /* 158140516Swpaul * There are two possible encapsulation mechanisms 158240516Swpaul * that we can use: an efficient one, and a very lossy 158340516Swpaul * one. The efficient one only happens very rarely, 158440516Swpaul * whereas the lossy one can and most likely will happen 158540516Swpaul * all the time. 158640516Swpaul * The efficient case happens if: 158740516Swpaul * - the packet fits in a single mbuf 158840516Swpaul * - the packet is 32-bit aligned within the mbuf data area 158940516Swpaul * In this case, we can DMA from the mbuf directly. 159040516Swpaul * The lossy case covers everything else. Bah. 159140516Swpaul */ 159240516Swpaul 159340516Swpaul m = m_head; 159440516Swpaul 159541243Swpaul MGETHDR(m_new, M_DONTWAIT, MT_DATA); 159641243Swpaul if (m_new == NULL) { 159741243Swpaul printf("rl%d: no memory for tx list", sc->rl_unit); 159841243Swpaul return(1); 159941243Swpaul } 160041243Swpaul if (m_head->m_pkthdr.len > MHLEN) { 160141243Swpaul MCLGET(m_new, M_DONTWAIT); 160241243Swpaul if (!(m_new->m_flags & M_EXT)) { 160341243Swpaul m_freem(m_new); 160441243Swpaul printf("rl%d: no memory for tx list", 160541243Swpaul sc->rl_unit); 160640516Swpaul return(1); 160740516Swpaul } 160840516Swpaul } 160941243Swpaul m_copydata(m_head, 0, m_head->m_pkthdr.len, 161041243Swpaul mtod(m_new, caddr_t)); 161141243Swpaul m_new->m_pkthdr.len = m_new->m_len = m_head->m_pkthdr.len; 161241243Swpaul m_freem(m_head); 161341243Swpaul m_head = m_new; 161440516Swpaul 161540516Swpaul /* Pad frames to at least 60 bytes. */ 161641243Swpaul if (m_head->m_pkthdr.len < RL_MIN_FRAMELEN) { 161740516Swpaul m_head->m_pkthdr.len += 161840516Swpaul (RL_MIN_FRAMELEN - m_head->m_pkthdr.len); 161941243Swpaul m_head->m_len = m_head->m_pkthdr.len; 162041243Swpaul } 162140516Swpaul 162240516Swpaul c->rl_mbuf = m_head; 162340516Swpaul 162440516Swpaul return(0); 162540516Swpaul} 162640516Swpaul 162740516Swpaul/* 162840516Swpaul * Main transmit routine. 162940516Swpaul */ 163040516Swpaul 163140516Swpaulstatic void rl_start(ifp) 163240516Swpaul struct ifnet *ifp; 163340516Swpaul{ 163440516Swpaul struct rl_softc *sc; 163540516Swpaul struct mbuf *m_head = NULL; 163640516Swpaul struct rl_chain *cur_tx = NULL; 163740516Swpaul 163840516Swpaul sc = ifp->if_softc; 163940516Swpaul 164040516Swpaul if (sc->rl_autoneg) { 164140516Swpaul sc->rl_tx_pend = 1; 164240516Swpaul return; 164340516Swpaul } 164440516Swpaul 164540516Swpaul /* 164640516Swpaul * Check for an available queue slot. If there are none, 164740516Swpaul * punt. 164840516Swpaul */ 164940516Swpaul if (sc->rl_cdata.rl_tx_cur->rl_mbuf != NULL) { 165040516Swpaul ifp->if_flags |= IFF_OACTIVE; 165140516Swpaul return; 165240516Swpaul } 165340516Swpaul 165440516Swpaul while(sc->rl_cdata.rl_tx_cur->rl_mbuf == NULL) { 165540516Swpaul IF_DEQUEUE(&ifp->if_snd, m_head); 165640516Swpaul if (m_head == NULL) 165740516Swpaul break; 165840516Swpaul 165940516Swpaul 166040516Swpaul /* Pick a descriptor off the free list. */ 166140516Swpaul cur_tx = sc->rl_cdata.rl_tx_cur; 166240516Swpaul sc->rl_cdata.rl_tx_cur = cur_tx->rl_next; 166340516Swpaul sc->rl_cdata.rl_tx_cnt++; 166440516Swpaul 166540516Swpaul /* Pack the data into the descriptor. */ 166640516Swpaul rl_encap(sc, cur_tx, m_head); 166740516Swpaul 166840516Swpaul#if NBPFILTER > 0 166940516Swpaul /* 167040516Swpaul * If there's a BPF listener, bounce a copy of this frame 167140516Swpaul * to him. 167240516Swpaul */ 167340516Swpaul if (ifp->if_bpf) 167440516Swpaul bpf_mtap(ifp, cur_tx->rl_mbuf); 167540516Swpaul#endif 167640516Swpaul /* 167740516Swpaul * Transmit the frame. 167840516Swpaul */ 167940516Swpaul CSR_WRITE_4(sc, RL_TXADDR0 + cur_tx->rl_desc, 168040516Swpaul vtophys(mtod(cur_tx->rl_mbuf, caddr_t))); 168140516Swpaul CSR_WRITE_4(sc, RL_TXSTAT0 + cur_tx->rl_desc, 168240516Swpaul RL_TX_EARLYTHRESH | cur_tx->rl_mbuf->m_pkthdr.len); 168340516Swpaul } 168440516Swpaul 168540516Swpaul /* 168640516Swpaul * Set a timeout in case the chip goes out to lunch. 168740516Swpaul */ 168840516Swpaul ifp->if_timer = 5; 168940516Swpaul 169040516Swpaul return; 169140516Swpaul} 169240516Swpaul 169340516Swpaulstatic void rl_init(xsc) 169440516Swpaul void *xsc; 169540516Swpaul{ 169640516Swpaul struct rl_softc *sc = xsc; 169740516Swpaul struct ifnet *ifp = &sc->arpcom.ac_if; 169840516Swpaul int s, i; 169940516Swpaul u_int32_t rxcfg = 0; 170040516Swpaul u_int16_t phy_bmcr = 0; 170140516Swpaul 170240516Swpaul if (sc->rl_autoneg) 170340516Swpaul return; 170440516Swpaul 170540516Swpaul s = splimp(); 170640516Swpaul 170740516Swpaul /* 170840516Swpaul * XXX Hack for the 8139: the built-in autoneg logic's state 170940516Swpaul * gets reset by rl_init() when we don't want it to. Try 171040516Swpaul * to preserve it. (For 8129 cards with real external PHYs, 171140516Swpaul * the BMCR register doesn't change, but this doesn't hurt.) 171240516Swpaul */ 171340516Swpaul if (sc->rl_type == RL_8139) 171440516Swpaul phy_bmcr = rl_phy_readreg(sc, PHY_BMCR); 171540516Swpaul 171640516Swpaul /* 171740516Swpaul * Cancel pending I/O and free all RX/TX buffers. 171840516Swpaul */ 171940516Swpaul rl_stop(sc); 172040516Swpaul 172140516Swpaul /* Init our MAC address */ 172240516Swpaul for (i = 0; i < ETHER_ADDR_LEN; i++) { 172340516Swpaul CSR_WRITE_1(sc, RL_IDR0 + i, sc->arpcom.ac_enaddr[i]); 172440516Swpaul } 172540516Swpaul 172640516Swpaul /* Init the RX buffer pointer register. */ 172740516Swpaul CSR_WRITE_4(sc, RL_RXADDR, vtophys(sc->rl_cdata.rl_rx_buf)); 172840516Swpaul 172940516Swpaul /* Init TX descriptors. */ 173040516Swpaul rl_list_tx_init(sc); 173140516Swpaul 173240516Swpaul /* 173340516Swpaul * Enable transmit and receive. 173440516Swpaul */ 173540516Swpaul CSR_WRITE_1(sc, RL_COMMAND, RL_CMD_TX_ENB|RL_CMD_RX_ENB); 173640516Swpaul 173740516Swpaul /* 173840516Swpaul * Set the buffer size values. 173940516Swpaul */ 174040516Swpaul CSR_WRITE_4(sc, RL_RXCFG, RL_RXCFG_CONFIG); 174140516Swpaul 174240516Swpaul /* Set the individual bit to receive frames for this host only. */ 174340516Swpaul rxcfg = CSR_READ_4(sc, RL_RXCFG); 174440516Swpaul rxcfg |= RL_RXCFG_RX_INDIV; 174540516Swpaul 174640516Swpaul /* If we want promiscuous mode, set the allframes bit. */ 174740516Swpaul if (ifp->if_flags & IFF_PROMISC) { 174840516Swpaul rxcfg |= RL_RXCFG_RX_ALLPHYS; 174940516Swpaul CSR_WRITE_4(sc, RL_RXCFG, rxcfg); 175040516Swpaul } else { 175140516Swpaul rxcfg &= ~RL_RXCFG_RX_ALLPHYS; 175240516Swpaul CSR_WRITE_4(sc, RL_RXCFG, rxcfg); 175340516Swpaul } 175440516Swpaul 175540516Swpaul /* 175640516Swpaul * Set capture broadcast bit to capture broadcast frames. 175740516Swpaul */ 175840516Swpaul if (ifp->if_flags & IFF_BROADCAST) { 175940516Swpaul rxcfg |= RL_RXCFG_RX_BROAD; 176040516Swpaul CSR_WRITE_4(sc, RL_RXCFG, rxcfg); 176140516Swpaul } else { 176240516Swpaul rxcfg &= ~RL_RXCFG_RX_BROAD; 176340516Swpaul CSR_WRITE_4(sc, RL_RXCFG, rxcfg); 176440516Swpaul } 176540516Swpaul 176640516Swpaul /* 176740516Swpaul * Program the multicast filter, if necessary. 176840516Swpaul */ 176940516Swpaul rl_setmulti(sc); 177040516Swpaul 177140516Swpaul /* 177240516Swpaul * Enable interrupts. 177340516Swpaul */ 177440516Swpaul CSR_WRITE_2(sc, RL_IMR, RL_INTRS); 177540516Swpaul 177640516Swpaul /* Start RX/TX process. */ 177740516Swpaul CSR_WRITE_4(sc, RL_MISSEDPKT, 0); 177840516Swpaul 177940516Swpaul /* Enable receiver and transmitter. */ 178040516Swpaul CSR_WRITE_1(sc, RL_COMMAND, RL_CMD_TX_ENB|RL_CMD_RX_ENB); 178140516Swpaul 178240516Swpaul /* Restore state of BMCR */ 178340516Swpaul if (sc->rl_pinfo != NULL) 178440516Swpaul rl_phy_writereg(sc, PHY_BMCR, phy_bmcr); 178540516Swpaul 178640516Swpaul CSR_WRITE_1(sc, RL_CFG1, RL_CFG1_DRVLOAD|RL_CFG1_FULLDUPLEX); 178740516Swpaul 178840516Swpaul ifp->if_flags |= IFF_RUNNING; 178940516Swpaul ifp->if_flags &= ~IFF_OACTIVE; 179040516Swpaul 179140516Swpaul (void)splx(s); 179240516Swpaul 179340516Swpaul return; 179440516Swpaul} 179540516Swpaul 179640516Swpaul/* 179740516Swpaul * Set media options. 179840516Swpaul */ 179940516Swpaulstatic int rl_ifmedia_upd(ifp) 180040516Swpaul struct ifnet *ifp; 180140516Swpaul{ 180240516Swpaul struct rl_softc *sc; 180340516Swpaul struct ifmedia *ifm; 180440516Swpaul 180540516Swpaul sc = ifp->if_softc; 180640516Swpaul ifm = &sc->ifmedia; 180740516Swpaul 180840516Swpaul if (IFM_TYPE(ifm->ifm_media) != IFM_ETHER) 180940516Swpaul return(EINVAL); 181040516Swpaul 181140516Swpaul if (IFM_SUBTYPE(ifm->ifm_media) == IFM_AUTO) 181240516Swpaul rl_autoneg_mii(sc, RL_FLAG_SCHEDDELAY, 1); 181340516Swpaul else 181440516Swpaul rl_setmode_mii(sc, ifm->ifm_media); 181540516Swpaul 181640516Swpaul return(0); 181740516Swpaul} 181840516Swpaul 181940516Swpaul/* 182040516Swpaul * Report current media status. 182140516Swpaul */ 182240516Swpaulstatic void rl_ifmedia_sts(ifp, ifmr) 182340516Swpaul struct ifnet *ifp; 182440516Swpaul struct ifmediareq *ifmr; 182540516Swpaul{ 182640516Swpaul struct rl_softc *sc; 182740516Swpaul u_int16_t advert = 0, ability = 0; 182840516Swpaul 182940516Swpaul sc = ifp->if_softc; 183040516Swpaul 183140516Swpaul if (!(rl_phy_readreg(sc, PHY_BMCR) & PHY_BMCR_AUTONEGENBL)) { 183240516Swpaul if (rl_phy_readreg(sc, PHY_BMCR) & PHY_BMCR_SPEEDSEL) 183340516Swpaul ifmr->ifm_active = IFM_ETHER|IFM_100_TX; 183440516Swpaul else 183540516Swpaul ifmr->ifm_active = IFM_ETHER|IFM_10_T; 183640516Swpaul 183740516Swpaul if (rl_phy_readreg(sc, PHY_BMCR) & PHY_BMCR_DUPLEX) 183840516Swpaul ifmr->ifm_active |= IFM_FDX; 183940516Swpaul else 184040516Swpaul ifmr->ifm_active |= IFM_HDX; 184140516Swpaul return; 184240516Swpaul } 184340516Swpaul 184440516Swpaul ability = rl_phy_readreg(sc, PHY_LPAR); 184540516Swpaul advert = rl_phy_readreg(sc, PHY_ANAR); 184640516Swpaul if (advert & PHY_ANAR_100BT4 && 184740516Swpaul ability & PHY_ANAR_100BT4) { 184840516Swpaul ifmr->ifm_active = IFM_ETHER|IFM_100_T4; 184940516Swpaul } else if (advert & PHY_ANAR_100BTXFULL && 185040516Swpaul ability & PHY_ANAR_100BTXFULL) { 185140516Swpaul ifmr->ifm_active = IFM_ETHER|IFM_100_TX|IFM_FDX; 185240516Swpaul } else if (advert & PHY_ANAR_100BTXHALF && 185340516Swpaul ability & PHY_ANAR_100BTXHALF) { 185440516Swpaul ifmr->ifm_active = IFM_ETHER|IFM_100_TX|IFM_HDX; 185540516Swpaul } else if (advert & PHY_ANAR_10BTFULL && 185640516Swpaul ability & PHY_ANAR_10BTFULL) { 185740516Swpaul ifmr->ifm_active = IFM_ETHER|IFM_10_T|IFM_FDX; 185840516Swpaul } else if (advert & PHY_ANAR_10BTHALF && 185940516Swpaul ability & PHY_ANAR_10BTHALF) { 186040516Swpaul ifmr->ifm_active = IFM_ETHER|IFM_10_T|IFM_HDX; 186140516Swpaul } 186240516Swpaul 186340516Swpaul return; 186440516Swpaul} 186540516Swpaul 186640516Swpaulstatic int rl_ioctl(ifp, command, data) 186740516Swpaul struct ifnet *ifp; 186840516Swpaul u_long command; 186940516Swpaul caddr_t data; 187040516Swpaul{ 187140516Swpaul struct rl_softc *sc = ifp->if_softc; 187240516Swpaul struct ifreq *ifr = (struct ifreq *) data; 187340516Swpaul int s, error = 0; 187440516Swpaul 187540516Swpaul s = splimp(); 187640516Swpaul 187740516Swpaul switch(command) { 187840516Swpaul case SIOCSIFADDR: 187940516Swpaul case SIOCGIFADDR: 188040516Swpaul case SIOCSIFMTU: 188140516Swpaul error = ether_ioctl(ifp, command, data); 188240516Swpaul break; 188340516Swpaul case SIOCSIFFLAGS: 188440516Swpaul if (ifp->if_flags & IFF_UP) { 188540516Swpaul rl_init(sc); 188640516Swpaul } else { 188740516Swpaul if (ifp->if_flags & IFF_RUNNING) 188840516Swpaul rl_stop(sc); 188940516Swpaul } 189040516Swpaul error = 0; 189140516Swpaul break; 189240516Swpaul case SIOCADDMULTI: 189340516Swpaul case SIOCDELMULTI: 189440516Swpaul rl_setmulti(sc); 189540516Swpaul error = 0; 189640516Swpaul break; 189740516Swpaul case SIOCGIFMEDIA: 189840516Swpaul case SIOCSIFMEDIA: 189940516Swpaul error = ifmedia_ioctl(ifp, ifr, &sc->ifmedia, command); 190040516Swpaul break; 190140516Swpaul default: 190240516Swpaul error = EINVAL; 190340516Swpaul break; 190440516Swpaul } 190540516Swpaul 190640516Swpaul (void)splx(s); 190740516Swpaul 190840516Swpaul return(error); 190940516Swpaul} 191040516Swpaul 191140516Swpaulstatic void rl_watchdog(ifp) 191240516Swpaul struct ifnet *ifp; 191340516Swpaul{ 191440516Swpaul struct rl_softc *sc; 191540516Swpaul 191640516Swpaul sc = ifp->if_softc; 191740516Swpaul 191840516Swpaul if (sc->rl_autoneg) { 191940516Swpaul rl_autoneg_mii(sc, RL_FLAG_DELAYTIMEO, 1); 192040516Swpaul return; 192140516Swpaul } 192240516Swpaul 192340516Swpaul printf("rl%d: watchdog timeout\n", sc->rl_unit); 192440516Swpaul ifp->if_oerrors++; 192540516Swpaul if (!(rl_phy_readreg(sc, PHY_BMSR) & PHY_BMSR_LINKSTAT)) 192640516Swpaul printf("rl%d: no carrier - transceiver cable problem?\n", 192740516Swpaul sc->rl_unit); 192840516Swpaul rl_txeoc(sc); 192940516Swpaul rl_txeof(sc); 193040516Swpaul rl_rxeof(sc); 193140516Swpaul rl_init(sc); 193240516Swpaul 193340516Swpaul return; 193440516Swpaul} 193540516Swpaul 193640516Swpaul/* 193740516Swpaul * Stop the adapter and free any mbufs allocated to the 193840516Swpaul * RX and TX lists. 193940516Swpaul */ 194040516Swpaulstatic void rl_stop(sc) 194140516Swpaul struct rl_softc *sc; 194240516Swpaul{ 194340516Swpaul register int i; 194440516Swpaul struct ifnet *ifp; 194540516Swpaul 194640516Swpaul ifp = &sc->arpcom.ac_if; 194740516Swpaul ifp->if_timer = 0; 194840516Swpaul 194940516Swpaul CSR_WRITE_1(sc, RL_COMMAND, 0x00); 195040516Swpaul CSR_WRITE_2(sc, RL_IMR, 0x0000); 195140516Swpaul 195240516Swpaul /* 195340516Swpaul * Free the TX list buffers. 195440516Swpaul */ 195540516Swpaul for (i = 0; i < RL_TX_LIST_CNT; i++) { 195640516Swpaul if (sc->rl_cdata.rl_tx_chain[i].rl_mbuf != NULL) { 195740516Swpaul m_freem(sc->rl_cdata.rl_tx_chain[i].rl_mbuf); 195840516Swpaul sc->rl_cdata.rl_tx_chain[i].rl_mbuf = NULL; 195940516Swpaul CSR_WRITE_4(sc, RL_TXADDR0 + 196040516Swpaul sc->rl_cdata.rl_tx_chain[i].rl_desc, 0x00000000); 196140516Swpaul } 196240516Swpaul } 196340516Swpaul 196440516Swpaul ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE); 196540516Swpaul 196640516Swpaul return; 196740516Swpaul} 196840516Swpaul 196940516Swpaul/* 197040516Swpaul * Stop all chip I/O so that the kernel's probe routines don't 197140516Swpaul * get confused by errant DMAs when rebooting. 197240516Swpaul */ 197340516Swpaulstatic void rl_shutdown(howto, arg) 197440516Swpaul int howto; 197540516Swpaul void *arg; 197640516Swpaul{ 197740516Swpaul struct rl_softc *sc = (struct rl_softc *)arg; 197840516Swpaul 197940516Swpaul rl_stop(sc); 198040516Swpaul 198140516Swpaul return; 198240516Swpaul} 198340516Swpaul 198440516Swpaul 198540516Swpaulstatic struct pci_device rl_device = { 198640516Swpaul "rl", 198740516Swpaul rl_probe, 198840516Swpaul rl_attach, 198940516Swpaul &rl_count, 199040516Swpaul NULL 199140516Swpaul}; 199240516SwpaulDATA_SET(pcidevice_set, rl_device); 1993