if_rl.c revision 63090
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 63090 2000-07-13 22:54:34Z archie $ 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 <sys/param.h> 8740516Swpaul#include <sys/systm.h> 8840516Swpaul#include <sys/sockio.h> 8940516Swpaul#include <sys/mbuf.h> 9040516Swpaul#include <sys/malloc.h> 9140516Swpaul#include <sys/kernel.h> 9240516Swpaul#include <sys/socket.h> 9340516Swpaul 9440516Swpaul#include <net/if.h> 9540516Swpaul#include <net/if_arp.h> 9640516Swpaul#include <net/ethernet.h> 9740516Swpaul#include <net/if_dl.h> 9840516Swpaul#include <net/if_media.h> 9940516Swpaul 10040516Swpaul#include <net/bpf.h> 10140516Swpaul 10240516Swpaul#include <vm/vm.h> /* for vtophys */ 10340516Swpaul#include <vm/pmap.h> /* for vtophys */ 10440516Swpaul#include <machine/clock.h> /* for DELAY */ 10541569Swpaul#include <machine/bus_pio.h> 10641569Swpaul#include <machine/bus_memio.h> 10741569Swpaul#include <machine/bus.h> 10850703Swpaul#include <machine/resource.h> 10950703Swpaul#include <sys/bus.h> 11050703Swpaul#include <sys/rman.h> 11140516Swpaul 11250703Swpaul#include <dev/mii/mii.h> 11350703Swpaul#include <dev/mii/miivar.h> 11450703Swpaul 11540516Swpaul#include <pci/pcireg.h> 11640516Swpaul#include <pci/pcivar.h> 11740516Swpaul 11859758SpeterMODULE_DEPEND(rl, miibus, 1, 1, 1); 11959758Speter 12051089Speter/* "controller miibus0" required. See GENERIC if you get errors here. */ 12150703Swpaul#include "miibus_if.h" 12250703Swpaul 12340516Swpaul/* 12440516Swpaul * Default to using PIO access for this driver. On SMP systems, 12540516Swpaul * there appear to be problems with memory mapped mode: it looks like 12640516Swpaul * doing too many memory mapped access back to back in rapid succession 12740516Swpaul * can hang the bus. I'm inclined to blame this on crummy design/construction 12840516Swpaul * on the part of RealTek. Memory mapped mode does appear to work on 12940516Swpaul * uniprocessor systems though. 13040516Swpaul */ 13140516Swpaul#define RL_USEIOSPACE 13240516Swpaul 13340516Swpaul#include <pci/if_rlreg.h> 13440516Swpaul 13540516Swpaul#ifndef lint 13641591Sarchiestatic const char rcsid[] = 13750477Speter "$FreeBSD: head/sys/pci/if_rl.c 63090 2000-07-13 22:54:34Z archie $"; 13840516Swpaul#endif 13940516Swpaul 14040516Swpaul/* 14140516Swpaul * Various supported device vendors/types and their names. 14240516Swpaul */ 14340516Swpaulstatic struct rl_type rl_devs[] = { 14440516Swpaul { RT_VENDORID, RT_DEVICEID_8129, 14540516Swpaul "RealTek 8129 10/100BaseTX" }, 14640516Swpaul { RT_VENDORID, RT_DEVICEID_8139, 14740516Swpaul "RealTek 8139 10/100BaseTX" }, 14841243Swpaul { ACCTON_VENDORID, ACCTON_DEVICEID_5030, 14941243Swpaul "Accton MPX 5030/5038 10/100BaseTX" }, 15044238Swpaul { DELTA_VENDORID, DELTA_DEVICEID_8139, 15144238Swpaul "Delta Electronics 8139 10/100BaseTX" }, 15244238Swpaul { ADDTRON_VENDORID, ADDTRON_DEVICEID_8139, 15344238Swpaul "Addtron Technolgy 8139 10/100BaseTX" }, 15440516Swpaul { 0, 0, NULL } 15540516Swpaul}; 15640516Swpaul 15750703Swpaulstatic int rl_probe __P((device_t)); 15850703Swpaulstatic int rl_attach __P((device_t)); 15950703Swpaulstatic int rl_detach __P((device_t)); 16040516Swpaul 16145633Swpaulstatic int rl_encap __P((struct rl_softc *, struct mbuf * )); 16240516Swpaul 16340516Swpaulstatic void rl_rxeof __P((struct rl_softc *)); 16440516Swpaulstatic void rl_txeof __P((struct rl_softc *)); 16540516Swpaulstatic void rl_intr __P((void *)); 16650703Swpaulstatic void rl_tick __P((void *)); 16740516Swpaulstatic void rl_start __P((struct ifnet *)); 16840516Swpaulstatic int rl_ioctl __P((struct ifnet *, u_long, caddr_t)); 16940516Swpaulstatic void rl_init __P((void *)); 17040516Swpaulstatic void rl_stop __P((struct rl_softc *)); 17140516Swpaulstatic void rl_watchdog __P((struct ifnet *)); 17250703Swpaulstatic void rl_shutdown __P((device_t)); 17340516Swpaulstatic int rl_ifmedia_upd __P((struct ifnet *)); 17440516Swpaulstatic void rl_ifmedia_sts __P((struct ifnet *, struct ifmediareq *)); 17540516Swpaul 17641656Swpaulstatic void rl_eeprom_putbyte __P((struct rl_softc *, int)); 17741656Swpaulstatic void rl_eeprom_getword __P((struct rl_softc *, int, u_int16_t *)); 17840516Swpaulstatic void rl_read_eeprom __P((struct rl_softc *, caddr_t, 17940516Swpaul int, int, int)); 18040516Swpaulstatic void rl_mii_sync __P((struct rl_softc *)); 18140516Swpaulstatic void rl_mii_send __P((struct rl_softc *, u_int32_t, int)); 18240516Swpaulstatic int rl_mii_readreg __P((struct rl_softc *, struct rl_mii_frame *)); 18340516Swpaulstatic int rl_mii_writereg __P((struct rl_softc *, struct rl_mii_frame *)); 18440516Swpaul 18550703Swpaulstatic int rl_miibus_readreg __P((device_t, int, int)); 18650703Swpaulstatic int rl_miibus_writereg __P((device_t, int, int, int)); 18750703Swpaulstatic void rl_miibus_statchg __P((device_t)); 18840516Swpaul 18941656Swpaulstatic u_int8_t rl_calchash __P((caddr_t)); 19040516Swpaulstatic void rl_setmulti __P((struct rl_softc *)); 19140516Swpaulstatic void rl_reset __P((struct rl_softc *)); 19240516Swpaulstatic int rl_list_tx_init __P((struct rl_softc *)); 19340516Swpaul 19450703Swpaul#ifdef RL_USEIOSPACE 19550703Swpaul#define RL_RES SYS_RES_IOPORT 19650703Swpaul#define RL_RID RL_PCI_LOIO 19750703Swpaul#else 19850703Swpaul#define RL_RES SYS_RES_MEMORY 19950703Swpaul#define RL_RID RL_PCI_LOMEM 20050703Swpaul#endif 20150703Swpaul 20250703Swpaulstatic device_method_t rl_methods[] = { 20350703Swpaul /* Device interface */ 20450703Swpaul DEVMETHOD(device_probe, rl_probe), 20550703Swpaul DEVMETHOD(device_attach, rl_attach), 20650703Swpaul DEVMETHOD(device_detach, rl_detach), 20750703Swpaul DEVMETHOD(device_shutdown, rl_shutdown), 20850703Swpaul 20950703Swpaul /* bus interface */ 21050703Swpaul DEVMETHOD(bus_print_child, bus_generic_print_child), 21150703Swpaul DEVMETHOD(bus_driver_added, bus_generic_driver_added), 21250703Swpaul 21350703Swpaul /* MII interface */ 21450703Swpaul DEVMETHOD(miibus_readreg, rl_miibus_readreg), 21550703Swpaul DEVMETHOD(miibus_writereg, rl_miibus_writereg), 21650703Swpaul DEVMETHOD(miibus_statchg, rl_miibus_statchg), 21750703Swpaul 21850703Swpaul { 0, 0 } 21950703Swpaul}; 22050703Swpaul 22150703Swpaulstatic driver_t rl_driver = { 22251455Swpaul "rl", 22350703Swpaul rl_methods, 22450703Swpaul sizeof(struct rl_softc) 22550703Swpaul}; 22650703Swpaul 22750703Swpaulstatic devclass_t rl_devclass; 22850703Swpaul 22951533SwpaulDRIVER_MODULE(if_rl, pci, rl_driver, rl_devclass, 0, 0); 23051473SwpaulDRIVER_MODULE(miibus, rl, miibus_driver, miibus_devclass, 0, 0); 23150703Swpaul 23240516Swpaul#define EE_SET(x) \ 23340516Swpaul CSR_WRITE_1(sc, RL_EECMD, \ 23440516Swpaul CSR_READ_1(sc, RL_EECMD) | x) 23540516Swpaul 23640516Swpaul#define EE_CLR(x) \ 23740516Swpaul CSR_WRITE_1(sc, RL_EECMD, \ 23840516Swpaul CSR_READ_1(sc, RL_EECMD) & ~x) 23940516Swpaul 24040516Swpaul/* 24140516Swpaul * Send a read command and address to the EEPROM, check for ACK. 24240516Swpaul */ 24340516Swpaulstatic void rl_eeprom_putbyte(sc, addr) 24440516Swpaul struct rl_softc *sc; 24541656Swpaul int addr; 24640516Swpaul{ 24740516Swpaul register int d, i; 24840516Swpaul 24940516Swpaul d = addr | RL_EECMD_READ; 25040516Swpaul 25140516Swpaul /* 25255170Sbillf * Feed in each bit and strobe the clock. 25340516Swpaul */ 25440516Swpaul for (i = 0x400; i; i >>= 1) { 25540516Swpaul if (d & i) { 25640516Swpaul EE_SET(RL_EE_DATAIN); 25740516Swpaul } else { 25840516Swpaul EE_CLR(RL_EE_DATAIN); 25940516Swpaul } 26040516Swpaul DELAY(100); 26140516Swpaul EE_SET(RL_EE_CLK); 26240516Swpaul DELAY(150); 26340516Swpaul EE_CLR(RL_EE_CLK); 26440516Swpaul DELAY(100); 26540516Swpaul } 26640516Swpaul 26740516Swpaul return; 26840516Swpaul} 26940516Swpaul 27040516Swpaul/* 27140516Swpaul * Read a word of data stored in the EEPROM at address 'addr.' 27240516Swpaul */ 27340516Swpaulstatic void rl_eeprom_getword(sc, addr, dest) 27440516Swpaul struct rl_softc *sc; 27541656Swpaul int addr; 27640516Swpaul u_int16_t *dest; 27740516Swpaul{ 27840516Swpaul register int i; 27940516Swpaul u_int16_t word = 0; 28040516Swpaul 28140516Swpaul /* Enter EEPROM access mode. */ 28240516Swpaul CSR_WRITE_1(sc, RL_EECMD, RL_EEMODE_PROGRAM|RL_EE_SEL); 28340516Swpaul 28440516Swpaul /* 28540516Swpaul * Send address of word we want to read. 28640516Swpaul */ 28740516Swpaul rl_eeprom_putbyte(sc, addr); 28840516Swpaul 28940516Swpaul CSR_WRITE_1(sc, RL_EECMD, RL_EEMODE_PROGRAM|RL_EE_SEL); 29040516Swpaul 29140516Swpaul /* 29240516Swpaul * Start reading bits from EEPROM. 29340516Swpaul */ 29440516Swpaul for (i = 0x8000; i; i >>= 1) { 29540516Swpaul EE_SET(RL_EE_CLK); 29640516Swpaul DELAY(100); 29740516Swpaul if (CSR_READ_1(sc, RL_EECMD) & RL_EE_DATAOUT) 29840516Swpaul word |= i; 29940516Swpaul EE_CLR(RL_EE_CLK); 30040516Swpaul DELAY(100); 30140516Swpaul } 30240516Swpaul 30340516Swpaul /* Turn off EEPROM access mode. */ 30440516Swpaul CSR_WRITE_1(sc, RL_EECMD, RL_EEMODE_OFF); 30540516Swpaul 30640516Swpaul *dest = word; 30740516Swpaul 30840516Swpaul return; 30940516Swpaul} 31040516Swpaul 31140516Swpaul/* 31240516Swpaul * Read a sequence of words from the EEPROM. 31340516Swpaul */ 31440516Swpaulstatic void rl_read_eeprom(sc, dest, off, cnt, swap) 31540516Swpaul struct rl_softc *sc; 31640516Swpaul caddr_t dest; 31740516Swpaul int off; 31840516Swpaul int cnt; 31940516Swpaul int swap; 32040516Swpaul{ 32140516Swpaul int i; 32240516Swpaul u_int16_t word = 0, *ptr; 32340516Swpaul 32440516Swpaul for (i = 0; i < cnt; i++) { 32540516Swpaul rl_eeprom_getword(sc, off + i, &word); 32640516Swpaul ptr = (u_int16_t *)(dest + (i * 2)); 32740516Swpaul if (swap) 32840516Swpaul *ptr = ntohs(word); 32940516Swpaul else 33040516Swpaul *ptr = word; 33140516Swpaul } 33240516Swpaul 33340516Swpaul return; 33440516Swpaul} 33540516Swpaul 33640516Swpaul 33740516Swpaul/* 33840516Swpaul * MII access routines are provided for the 8129, which 33940516Swpaul * doesn't have a built-in PHY. For the 8139, we fake things 34040516Swpaul * up by diverting rl_phy_readreg()/rl_phy_writereg() to the 34140516Swpaul * direct access PHY registers. 34240516Swpaul */ 34340516Swpaul#define MII_SET(x) \ 34440516Swpaul CSR_WRITE_1(sc, RL_MII, \ 34540516Swpaul CSR_READ_1(sc, RL_MII) | x) 34640516Swpaul 34740516Swpaul#define MII_CLR(x) \ 34840516Swpaul CSR_WRITE_1(sc, RL_MII, \ 34940516Swpaul CSR_READ_1(sc, RL_MII) & ~x) 35040516Swpaul 35140516Swpaul/* 35240516Swpaul * Sync the PHYs by setting data bit and strobing the clock 32 times. 35340516Swpaul */ 35440516Swpaulstatic void rl_mii_sync(sc) 35540516Swpaul struct rl_softc *sc; 35640516Swpaul{ 35740516Swpaul register int i; 35840516Swpaul 35940516Swpaul MII_SET(RL_MII_DIR|RL_MII_DATAOUT); 36040516Swpaul 36140516Swpaul for (i = 0; i < 32; i++) { 36240516Swpaul MII_SET(RL_MII_CLK); 36340516Swpaul DELAY(1); 36440516Swpaul MII_CLR(RL_MII_CLK); 36540516Swpaul DELAY(1); 36640516Swpaul } 36740516Swpaul 36840516Swpaul return; 36940516Swpaul} 37040516Swpaul 37140516Swpaul/* 37240516Swpaul * Clock a series of bits through the MII. 37340516Swpaul */ 37440516Swpaulstatic void rl_mii_send(sc, bits, cnt) 37540516Swpaul struct rl_softc *sc; 37640516Swpaul u_int32_t bits; 37740516Swpaul int cnt; 37840516Swpaul{ 37940516Swpaul int i; 38040516Swpaul 38140516Swpaul MII_CLR(RL_MII_CLK); 38240516Swpaul 38340516Swpaul for (i = (0x1 << (cnt - 1)); i; i >>= 1) { 38440516Swpaul if (bits & i) { 38540516Swpaul MII_SET(RL_MII_DATAOUT); 38640516Swpaul } else { 38740516Swpaul MII_CLR(RL_MII_DATAOUT); 38840516Swpaul } 38940516Swpaul DELAY(1); 39040516Swpaul MII_CLR(RL_MII_CLK); 39140516Swpaul DELAY(1); 39240516Swpaul MII_SET(RL_MII_CLK); 39340516Swpaul } 39440516Swpaul} 39540516Swpaul 39640516Swpaul/* 39740516Swpaul * Read an PHY register through the MII. 39840516Swpaul */ 39940516Swpaulstatic int rl_mii_readreg(sc, frame) 40040516Swpaul struct rl_softc *sc; 40140516Swpaul struct rl_mii_frame *frame; 40240516Swpaul 40340516Swpaul{ 40440516Swpaul int i, ack, s; 40540516Swpaul 40640516Swpaul s = splimp(); 40740516Swpaul 40840516Swpaul /* 40940516Swpaul * Set up frame for RX. 41040516Swpaul */ 41140516Swpaul frame->mii_stdelim = RL_MII_STARTDELIM; 41240516Swpaul frame->mii_opcode = RL_MII_READOP; 41340516Swpaul frame->mii_turnaround = 0; 41440516Swpaul frame->mii_data = 0; 41540516Swpaul 41640516Swpaul CSR_WRITE_2(sc, RL_MII, 0); 41740516Swpaul 41840516Swpaul /* 41940516Swpaul * Turn on data xmit. 42040516Swpaul */ 42140516Swpaul MII_SET(RL_MII_DIR); 42240516Swpaul 42340516Swpaul rl_mii_sync(sc); 42440516Swpaul 42540516Swpaul /* 42640516Swpaul * Send command/address info. 42740516Swpaul */ 42840516Swpaul rl_mii_send(sc, frame->mii_stdelim, 2); 42940516Swpaul rl_mii_send(sc, frame->mii_opcode, 2); 43040516Swpaul rl_mii_send(sc, frame->mii_phyaddr, 5); 43140516Swpaul rl_mii_send(sc, frame->mii_regaddr, 5); 43240516Swpaul 43340516Swpaul /* Idle bit */ 43440516Swpaul MII_CLR((RL_MII_CLK|RL_MII_DATAOUT)); 43540516Swpaul DELAY(1); 43640516Swpaul MII_SET(RL_MII_CLK); 43740516Swpaul DELAY(1); 43840516Swpaul 43940516Swpaul /* Turn off xmit. */ 44040516Swpaul MII_CLR(RL_MII_DIR); 44140516Swpaul 44240516Swpaul /* Check for ack */ 44340516Swpaul MII_CLR(RL_MII_CLK); 44440516Swpaul DELAY(1); 44540516Swpaul MII_SET(RL_MII_CLK); 44640516Swpaul DELAY(1); 44740516Swpaul ack = CSR_READ_2(sc, RL_MII) & RL_MII_DATAIN; 44840516Swpaul 44940516Swpaul /* 45040516Swpaul * Now try reading data bits. If the ack failed, we still 45140516Swpaul * need to clock through 16 cycles to keep the PHY(s) in sync. 45240516Swpaul */ 45340516Swpaul if (ack) { 45440516Swpaul for(i = 0; i < 16; i++) { 45540516Swpaul MII_CLR(RL_MII_CLK); 45640516Swpaul DELAY(1); 45740516Swpaul MII_SET(RL_MII_CLK); 45840516Swpaul DELAY(1); 45940516Swpaul } 46040516Swpaul goto fail; 46140516Swpaul } 46240516Swpaul 46340516Swpaul for (i = 0x8000; i; i >>= 1) { 46440516Swpaul MII_CLR(RL_MII_CLK); 46540516Swpaul DELAY(1); 46640516Swpaul if (!ack) { 46740516Swpaul if (CSR_READ_2(sc, RL_MII) & RL_MII_DATAIN) 46840516Swpaul frame->mii_data |= i; 46940516Swpaul DELAY(1); 47040516Swpaul } 47140516Swpaul MII_SET(RL_MII_CLK); 47240516Swpaul DELAY(1); 47340516Swpaul } 47440516Swpaul 47540516Swpaulfail: 47640516Swpaul 47740516Swpaul MII_CLR(RL_MII_CLK); 47840516Swpaul DELAY(1); 47940516Swpaul MII_SET(RL_MII_CLK); 48040516Swpaul DELAY(1); 48140516Swpaul 48240516Swpaul splx(s); 48340516Swpaul 48440516Swpaul if (ack) 48540516Swpaul return(1); 48640516Swpaul return(0); 48740516Swpaul} 48840516Swpaul 48940516Swpaul/* 49040516Swpaul * Write to a PHY register through the MII. 49140516Swpaul */ 49240516Swpaulstatic int rl_mii_writereg(sc, frame) 49340516Swpaul struct rl_softc *sc; 49440516Swpaul struct rl_mii_frame *frame; 49540516Swpaul 49640516Swpaul{ 49740516Swpaul int s; 49840516Swpaul 49940516Swpaul s = splimp(); 50040516Swpaul /* 50140516Swpaul * Set up frame for TX. 50240516Swpaul */ 50340516Swpaul 50440516Swpaul frame->mii_stdelim = RL_MII_STARTDELIM; 50540516Swpaul frame->mii_opcode = RL_MII_WRITEOP; 50640516Swpaul frame->mii_turnaround = RL_MII_TURNAROUND; 50740516Swpaul 50840516Swpaul /* 50940516Swpaul * Turn on data output. 51040516Swpaul */ 51140516Swpaul MII_SET(RL_MII_DIR); 51240516Swpaul 51340516Swpaul rl_mii_sync(sc); 51440516Swpaul 51540516Swpaul rl_mii_send(sc, frame->mii_stdelim, 2); 51640516Swpaul rl_mii_send(sc, frame->mii_opcode, 2); 51740516Swpaul rl_mii_send(sc, frame->mii_phyaddr, 5); 51840516Swpaul rl_mii_send(sc, frame->mii_regaddr, 5); 51940516Swpaul rl_mii_send(sc, frame->mii_turnaround, 2); 52040516Swpaul rl_mii_send(sc, frame->mii_data, 16); 52140516Swpaul 52240516Swpaul /* Idle bit. */ 52340516Swpaul MII_SET(RL_MII_CLK); 52440516Swpaul DELAY(1); 52540516Swpaul MII_CLR(RL_MII_CLK); 52640516Swpaul DELAY(1); 52740516Swpaul 52840516Swpaul /* 52940516Swpaul * Turn off xmit. 53040516Swpaul */ 53140516Swpaul MII_CLR(RL_MII_DIR); 53240516Swpaul 53340516Swpaul splx(s); 53440516Swpaul 53540516Swpaul return(0); 53640516Swpaul} 53740516Swpaul 53850703Swpaulstatic int rl_miibus_readreg(dev, phy, reg) 53950703Swpaul device_t dev; 54050703Swpaul int phy, reg; 54150703Swpaul{ 54240516Swpaul struct rl_softc *sc; 54340516Swpaul struct rl_mii_frame frame; 54440516Swpaul u_int16_t rval = 0; 54540516Swpaul u_int16_t rl8139_reg = 0; 54640516Swpaul 54750703Swpaul sc = device_get_softc(dev); 54850703Swpaul 54940516Swpaul if (sc->rl_type == RL_8139) { 55050703Swpaul /* Pretend the internal PHY is only at address 0 */ 55150703Swpaul if (phy) 55250703Swpaul return(0); 55340516Swpaul switch(reg) { 55450703Swpaul case MII_BMCR: 55540516Swpaul rl8139_reg = RL_BMCR; 55640516Swpaul break; 55750703Swpaul case MII_BMSR: 55840516Swpaul rl8139_reg = RL_BMSR; 55940516Swpaul break; 56050703Swpaul case MII_ANAR: 56140516Swpaul rl8139_reg = RL_ANAR; 56240516Swpaul break; 56350703Swpaul case MII_ANER: 56450703Swpaul rl8139_reg = RL_ANER; 56550703Swpaul break; 56650703Swpaul case MII_ANLPAR: 56740516Swpaul rl8139_reg = RL_LPAR; 56840516Swpaul break; 56950703Swpaul case MII_PHYIDR1: 57050703Swpaul case MII_PHYIDR2: 57150703Swpaul return(0); 57250703Swpaul break; 57340516Swpaul default: 57440516Swpaul printf("rl%d: bad phy register\n", sc->rl_unit); 57540516Swpaul return(0); 57640516Swpaul } 57740516Swpaul rval = CSR_READ_2(sc, rl8139_reg); 57840516Swpaul return(rval); 57940516Swpaul } 58040516Swpaul 58140516Swpaul bzero((char *)&frame, sizeof(frame)); 58240516Swpaul 58350703Swpaul frame.mii_phyaddr = phy; 58440516Swpaul frame.mii_regaddr = reg; 58540516Swpaul rl_mii_readreg(sc, &frame); 58640516Swpaul 58740516Swpaul return(frame.mii_data); 58840516Swpaul} 58940516Swpaul 59050703Swpaulstatic int rl_miibus_writereg(dev, phy, reg, data) 59150703Swpaul device_t dev; 59250703Swpaul int phy, reg, data; 59350703Swpaul{ 59440516Swpaul struct rl_softc *sc; 59540516Swpaul struct rl_mii_frame frame; 59640516Swpaul u_int16_t rl8139_reg = 0; 59740516Swpaul 59850703Swpaul sc = device_get_softc(dev); 59950703Swpaul 60040516Swpaul if (sc->rl_type == RL_8139) { 60150703Swpaul /* Pretend the internal PHY is only at address 0 */ 60250703Swpaul if (phy) 60350703Swpaul return(0); 60440516Swpaul switch(reg) { 60550703Swpaul case MII_BMCR: 60640516Swpaul rl8139_reg = RL_BMCR; 60740516Swpaul break; 60850703Swpaul case MII_BMSR: 60940516Swpaul rl8139_reg = RL_BMSR; 61040516Swpaul break; 61150703Swpaul case MII_ANAR: 61240516Swpaul rl8139_reg = RL_ANAR; 61340516Swpaul break; 61450703Swpaul case MII_ANER: 61550703Swpaul rl8139_reg = RL_ANER; 61650703Swpaul break; 61750703Swpaul case MII_ANLPAR: 61840516Swpaul rl8139_reg = RL_LPAR; 61940516Swpaul break; 62050703Swpaul case MII_PHYIDR1: 62150703Swpaul case MII_PHYIDR2: 62250703Swpaul return(0); 62350703Swpaul break; 62440516Swpaul default: 62540516Swpaul printf("rl%d: bad phy register\n", sc->rl_unit); 62650703Swpaul return(0); 62740516Swpaul } 62840516Swpaul CSR_WRITE_2(sc, rl8139_reg, data); 62950703Swpaul return(0); 63040516Swpaul } 63140516Swpaul 63240516Swpaul bzero((char *)&frame, sizeof(frame)); 63340516Swpaul 63450703Swpaul frame.mii_phyaddr = phy; 63540516Swpaul frame.mii_regaddr = reg; 63640516Swpaul frame.mii_data = data; 63740516Swpaul 63840516Swpaul rl_mii_writereg(sc, &frame); 63940516Swpaul 64050703Swpaul return(0); 64150703Swpaul} 64250703Swpaul 64350703Swpaulstatic void rl_miibus_statchg(dev) 64450703Swpaul device_t dev; 64550703Swpaul{ 64640516Swpaul return; 64740516Swpaul} 64840516Swpaul 64940516Swpaul/* 65043062Swpaul * Calculate CRC of a multicast group address, return the upper 6 bits. 65140516Swpaul */ 65240516Swpaulstatic u_int8_t rl_calchash(addr) 65341656Swpaul caddr_t addr; 65440516Swpaul{ 65540516Swpaul u_int32_t crc, carry; 65640516Swpaul int i, j; 65740516Swpaul u_int8_t c; 65840516Swpaul 65940516Swpaul /* Compute CRC for the address value. */ 66040516Swpaul crc = 0xFFFFFFFF; /* initial value */ 66140516Swpaul 66240516Swpaul for (i = 0; i < 6; i++) { 66340516Swpaul c = *(addr + i); 66440516Swpaul for (j = 0; j < 8; j++) { 66540516Swpaul carry = ((crc & 0x80000000) ? 1 : 0) ^ (c & 0x01); 66640516Swpaul crc <<= 1; 66740516Swpaul c >>= 1; 66840516Swpaul if (carry) 66940516Swpaul crc = (crc ^ 0x04c11db6) | carry; 67040516Swpaul } 67140516Swpaul } 67240516Swpaul 67340516Swpaul /* return the filter bit position */ 67443062Swpaul return(crc >> 26); 67540516Swpaul} 67640516Swpaul 67740516Swpaul/* 67840516Swpaul * Program the 64-bit multicast hash filter. 67940516Swpaul */ 68040516Swpaulstatic void rl_setmulti(sc) 68140516Swpaul struct rl_softc *sc; 68240516Swpaul{ 68340516Swpaul struct ifnet *ifp; 68440516Swpaul int h = 0; 68540516Swpaul u_int32_t hashes[2] = { 0, 0 }; 68640516Swpaul struct ifmultiaddr *ifma; 68740516Swpaul u_int32_t rxfilt; 68840516Swpaul int mcnt = 0; 68940516Swpaul 69040516Swpaul ifp = &sc->arpcom.ac_if; 69140516Swpaul 69240516Swpaul rxfilt = CSR_READ_4(sc, RL_RXCFG); 69340516Swpaul 69443062Swpaul if (ifp->if_flags & IFF_ALLMULTI || ifp->if_flags & IFF_PROMISC) { 69540516Swpaul rxfilt |= RL_RXCFG_RX_MULTI; 69640516Swpaul CSR_WRITE_4(sc, RL_RXCFG, rxfilt); 69740516Swpaul CSR_WRITE_4(sc, RL_MAR0, 0xFFFFFFFF); 69840516Swpaul CSR_WRITE_4(sc, RL_MAR4, 0xFFFFFFFF); 69940516Swpaul return; 70040516Swpaul } 70140516Swpaul 70240516Swpaul /* first, zot all the existing hash bits */ 70340516Swpaul CSR_WRITE_4(sc, RL_MAR0, 0); 70440516Swpaul CSR_WRITE_4(sc, RL_MAR4, 0); 70540516Swpaul 70640516Swpaul /* now program new ones */ 70740516Swpaul for (ifma = ifp->if_multiaddrs.lh_first; ifma != NULL; 70840516Swpaul ifma = ifma->ifma_link.le_next) { 70940516Swpaul if (ifma->ifma_addr->sa_family != AF_LINK) 71040516Swpaul continue; 71140516Swpaul h = rl_calchash(LLADDR((struct sockaddr_dl *)ifma->ifma_addr)); 71240516Swpaul if (h < 32) 71340516Swpaul hashes[0] |= (1 << h); 71440516Swpaul else 71540516Swpaul hashes[1] |= (1 << (h - 32)); 71640516Swpaul mcnt++; 71740516Swpaul } 71840516Swpaul 71940516Swpaul if (mcnt) 72040516Swpaul rxfilt |= RL_RXCFG_RX_MULTI; 72140516Swpaul else 72240516Swpaul rxfilt &= ~RL_RXCFG_RX_MULTI; 72340516Swpaul 72440516Swpaul CSR_WRITE_4(sc, RL_RXCFG, rxfilt); 72540516Swpaul CSR_WRITE_4(sc, RL_MAR0, hashes[0]); 72640516Swpaul CSR_WRITE_4(sc, RL_MAR4, hashes[1]); 72740516Swpaul 72840516Swpaul return; 72940516Swpaul} 73040516Swpaul 73140516Swpaulstatic void rl_reset(sc) 73240516Swpaul struct rl_softc *sc; 73340516Swpaul{ 73440516Swpaul register int i; 73540516Swpaul 73640516Swpaul CSR_WRITE_1(sc, RL_COMMAND, RL_CMD_RESET); 73740516Swpaul 73840516Swpaul for (i = 0; i < RL_TIMEOUT; i++) { 73940516Swpaul DELAY(10); 74040516Swpaul if (!(CSR_READ_1(sc, RL_COMMAND) & RL_CMD_RESET)) 74140516Swpaul break; 74240516Swpaul } 74340516Swpaul if (i == RL_TIMEOUT) 74440516Swpaul printf("rl%d: reset never completed!\n", sc->rl_unit); 74540516Swpaul 74640516Swpaul return; 74740516Swpaul} 74840516Swpaul 74940516Swpaul/* 75040516Swpaul * Probe for a RealTek 8129/8139 chip. Check the PCI vendor and device 75140516Swpaul * IDs against our list and return a device name if we find a match. 75240516Swpaul */ 75350703Swpaulstatic int rl_probe(dev) 75450703Swpaul device_t dev; 75540516Swpaul{ 75640516Swpaul struct rl_type *t; 75740516Swpaul 75840516Swpaul t = rl_devs; 75940516Swpaul 76040516Swpaul while(t->rl_name != NULL) { 76150703Swpaul if ((pci_get_vendor(dev) == t->rl_vid) && 76250703Swpaul (pci_get_device(dev) == t->rl_did)) { 76350703Swpaul device_set_desc(dev, t->rl_name); 76450703Swpaul return(0); 76540516Swpaul } 76640516Swpaul t++; 76740516Swpaul } 76840516Swpaul 76950703Swpaul return(ENXIO); 77040516Swpaul} 77140516Swpaul 77240516Swpaul/* 77340516Swpaul * Attach the interface. Allocate softc structures, do ifmedia 77440516Swpaul * setup and ethernet/BPF attach. 77540516Swpaul */ 77650703Swpaulstatic int rl_attach(dev) 77750703Swpaul device_t dev; 77840516Swpaul{ 77950703Swpaul int s; 78040516Swpaul u_char eaddr[ETHER_ADDR_LEN]; 78140516Swpaul u_int32_t command; 78240516Swpaul struct rl_softc *sc; 78340516Swpaul struct ifnet *ifp; 78440516Swpaul u_int16_t rl_did = 0; 78550703Swpaul int unit, error = 0, rid; 78640516Swpaul 78740516Swpaul s = splimp(); 78840516Swpaul 78950703Swpaul sc = device_get_softc(dev); 79050703Swpaul unit = device_get_unit(dev); 79140516Swpaul bzero(sc, sizeof(struct rl_softc)); 79240516Swpaul 79340516Swpaul /* 79440516Swpaul * Handle power management nonsense. 79540516Swpaul */ 79640516Swpaul 79750703Swpaul command = pci_read_config(dev, RL_PCI_CAPID, 4) & 0x000000FF; 79840516Swpaul if (command == 0x01) { 79940516Swpaul 80050703Swpaul command = pci_read_config(dev, RL_PCI_PWRMGMTCTRL, 4); 80140516Swpaul if (command & RL_PSTATE_MASK) { 80240516Swpaul u_int32_t iobase, membase, irq; 80340516Swpaul 80440516Swpaul /* Save important PCI config data. */ 80550703Swpaul iobase = pci_read_config(dev, RL_PCI_LOIO, 4); 80650703Swpaul membase = pci_read_config(dev, RL_PCI_LOMEM, 4); 80750703Swpaul irq = pci_read_config(dev, RL_PCI_INTLINE, 4); 80840516Swpaul 80940516Swpaul /* Reset the power state. */ 81040516Swpaul printf("rl%d: chip is is in D%d power mode " 81140516Swpaul "-- setting to D0\n", unit, command & RL_PSTATE_MASK); 81240516Swpaul command &= 0xFFFFFFFC; 81350703Swpaul pci_write_config(dev, RL_PCI_PWRMGMTCTRL, command, 4); 81440516Swpaul 81540516Swpaul /* Restore PCI config data. */ 81650703Swpaul pci_write_config(dev, RL_PCI_LOIO, iobase, 4); 81750703Swpaul pci_write_config(dev, RL_PCI_LOMEM, membase, 4); 81850703Swpaul pci_write_config(dev, RL_PCI_INTLINE, irq, 4); 81940516Swpaul } 82040516Swpaul } 82140516Swpaul 82240516Swpaul /* 82340516Swpaul * Map control/status registers. 82440516Swpaul */ 82561041Speter command = pci_read_config(dev, PCIR_COMMAND, 4); 82640516Swpaul command |= (PCIM_CMD_PORTEN|PCIM_CMD_MEMEN|PCIM_CMD_BUSMASTEREN); 82761041Speter pci_write_config(dev, PCIR_COMMAND, command, 4); 82861041Speter command = pci_read_config(dev, PCIR_COMMAND, 4); 82940516Swpaul 83040516Swpaul#ifdef RL_USEIOSPACE 83140516Swpaul if (!(command & PCIM_CMD_PORTEN)) { 83240516Swpaul printf("rl%d: failed to enable I/O ports!\n", unit); 83350703Swpaul error = ENXIO; 83440516Swpaul goto fail; 83540516Swpaul } 83640516Swpaul#else 83740516Swpaul if (!(command & PCIM_CMD_MEMEN)) { 83840516Swpaul printf("rl%d: failed to enable memory mapping!\n", unit); 83950703Swpaul error = ENXIO; 84040516Swpaul goto fail; 84140516Swpaul } 84250703Swpaul#endif 84340516Swpaul 84450703Swpaul rid = RL_RID; 84550703Swpaul sc->rl_res = bus_alloc_resource(dev, RL_RES, &rid, 84650703Swpaul 0, ~0, 1, RF_ACTIVE); 84750703Swpaul 84850703Swpaul if (sc->rl_res == NULL) { 84950703Swpaul printf ("rl%d: couldn't map ports/memory\n", unit); 85050703Swpaul error = ENXIO; 85140516Swpaul goto fail; 85240516Swpaul } 85340516Swpaul 85450703Swpaul sc->rl_btag = rman_get_bustag(sc->rl_res); 85550703Swpaul sc->rl_bhandle = rman_get_bushandle(sc->rl_res); 85650703Swpaul 85750703Swpaul rid = 0; 85850703Swpaul sc->rl_irq = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, 0, ~0, 1, 85950703Swpaul RF_SHAREABLE | RF_ACTIVE); 86050703Swpaul 86150703Swpaul if (sc->rl_irq == NULL) { 86240516Swpaul printf("rl%d: couldn't map interrupt\n", unit); 86350703Swpaul bus_release_resource(dev, RL_RES, RL_RID, sc->rl_res); 86450703Swpaul error = ENXIO; 86540516Swpaul goto fail; 86640516Swpaul } 86740516Swpaul 86850703Swpaul error = bus_setup_intr(dev, sc->rl_irq, INTR_TYPE_NET, 86950703Swpaul rl_intr, sc, &sc->rl_intrhand); 87050703Swpaul 87150703Swpaul if (error) { 87250703Swpaul bus_release_resource(dev, SYS_RES_IRQ, 0, sc->rl_res); 87350703Swpaul bus_release_resource(dev, RL_RES, RL_RID, sc->rl_res); 87450703Swpaul printf("rl%d: couldn't set up irq\n", unit); 87550703Swpaul goto fail; 87650703Swpaul } 87750703Swpaul 87850703Swpaul callout_handle_init(&sc->rl_stat_ch); 87950703Swpaul 88040516Swpaul /* Reset the adapter. */ 88140516Swpaul rl_reset(sc); 88240516Swpaul 88340516Swpaul /* 88440516Swpaul * Get station address from the EEPROM. 88540516Swpaul */ 88640516Swpaul rl_read_eeprom(sc, (caddr_t)&eaddr, RL_EE_EADDR, 3, 0); 88740516Swpaul 88840516Swpaul /* 88940516Swpaul * A RealTek chip was detected. Inform the world. 89040516Swpaul */ 89140516Swpaul printf("rl%d: Ethernet address: %6D\n", unit, eaddr, ":"); 89240516Swpaul 89340516Swpaul sc->rl_unit = unit; 89440516Swpaul bcopy(eaddr, (char *)&sc->arpcom.ac_enaddr, ETHER_ADDR_LEN); 89540516Swpaul 89640516Swpaul /* 89740516Swpaul * Now read the exact device type from the EEPROM to find 89840516Swpaul * out if it's an 8129 or 8139. 89940516Swpaul */ 90040516Swpaul rl_read_eeprom(sc, (caddr_t)&rl_did, RL_EE_PCI_DID, 1, 0); 90140516Swpaul 90244238Swpaul if (rl_did == RT_DEVICEID_8139 || rl_did == ACCTON_DEVICEID_5030 || 90349001Swpaul rl_did == DELTA_DEVICEID_8139 || rl_did == ADDTRON_DEVICEID_8139) 90440516Swpaul sc->rl_type = RL_8139; 90540516Swpaul else if (rl_did == RT_DEVICEID_8129) 90640516Swpaul sc->rl_type = RL_8129; 90740516Swpaul else { 90840516Swpaul printf("rl%d: unknown device ID: %x\n", unit, rl_did); 90950703Swpaul bus_teardown_intr(dev, sc->rl_irq, sc->rl_intrhand); 91050703Swpaul bus_release_resource(dev, SYS_RES_IRQ, 0, sc->rl_res); 91150703Swpaul bus_release_resource(dev, RL_RES, RL_RID, sc->rl_res); 91250703Swpaul error = ENXIO; 91340516Swpaul goto fail; 91440516Swpaul } 91540516Swpaul 91660043Swpaul sc->rl_cdata.rl_rx_buf = contigmalloc(RL_RXBUFLEN + 1518, M_DEVBUF, 91751657Swpaul M_NOWAIT, 0, 0xffffffff, PAGE_SIZE, 0); 91840516Swpaul 91940516Swpaul if (sc->rl_cdata.rl_rx_buf == NULL) { 92040516Swpaul printf("rl%d: no memory for list buffers!\n", unit); 92150703Swpaul bus_teardown_intr(dev, sc->rl_irq, sc->rl_intrhand); 92250703Swpaul bus_release_resource(dev, SYS_RES_IRQ, 0, sc->rl_res); 92350703Swpaul bus_release_resource(dev, RL_RES, RL_RID, sc->rl_res); 92450703Swpaul error = ENXIO; 92540516Swpaul goto fail; 92640516Swpaul } 92740516Swpaul 92848028Swpaul /* Leave a few bytes before the start of the RX ring buffer. */ 92948028Swpaul sc->rl_cdata.rl_rx_buf_ptr = sc->rl_cdata.rl_rx_buf; 93048028Swpaul sc->rl_cdata.rl_rx_buf += sizeof(u_int64_t); 93148028Swpaul 93250703Swpaul /* Do MII setup */ 93350703Swpaul if (mii_phy_probe(dev, &sc->rl_miibus, 93450703Swpaul rl_ifmedia_upd, rl_ifmedia_sts)) { 93550703Swpaul printf("rl%d: MII without any phy!\n", sc->rl_unit); 93650703Swpaul bus_teardown_intr(dev, sc->rl_irq, sc->rl_intrhand); 93750703Swpaul bus_release_resource(dev, SYS_RES_IRQ, 0, sc->rl_res); 93850703Swpaul bus_release_resource(dev, RL_RES, RL_RID, sc->rl_res); 93950703Swpaul free(sc->rl_cdata.rl_rx_buf, M_DEVBUF); 94050703Swpaul error = ENXIO; 94150703Swpaul goto fail; 94250703Swpaul } 94350703Swpaul 94440516Swpaul ifp = &sc->arpcom.ac_if; 94540516Swpaul ifp->if_softc = sc; 94640516Swpaul ifp->if_unit = unit; 94740516Swpaul ifp->if_name = "rl"; 94840516Swpaul ifp->if_mtu = ETHERMTU; 94940516Swpaul ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 95040516Swpaul ifp->if_ioctl = rl_ioctl; 95140516Swpaul ifp->if_output = ether_output; 95240516Swpaul ifp->if_start = rl_start; 95340516Swpaul ifp->if_watchdog = rl_watchdog; 95440516Swpaul ifp->if_init = rl_init; 95540516Swpaul ifp->if_baudrate = 10000000; 95645633Swpaul ifp->if_snd.ifq_maxlen = IFQ_MAXLEN; 95740516Swpaul 95840516Swpaul /* 95963090Sarchie * Call MI attach routine. 96040516Swpaul */ 96163090Sarchie ether_ifattach(ifp, ETHER_BPF_SUPPORTED); 96240516Swpaul 96340516Swpaulfail: 96440516Swpaul splx(s); 96550703Swpaul return(error); 96640516Swpaul} 96740516Swpaul 96850703Swpaulstatic int rl_detach(dev) 96950703Swpaul device_t dev; 97050703Swpaul{ 97150703Swpaul struct rl_softc *sc; 97250703Swpaul struct ifnet *ifp; 97350703Swpaul int s; 97450703Swpaul 97550703Swpaul s = splimp(); 97650703Swpaul 97750703Swpaul sc = device_get_softc(dev); 97850703Swpaul ifp = &sc->arpcom.ac_if; 97950703Swpaul 98063090Sarchie ether_ifdetach(ifp, ETHER_BPF_SUPPORTED); 98150703Swpaul rl_stop(sc); 98250703Swpaul 98350703Swpaul bus_generic_detach(dev); 98450703Swpaul device_delete_child(dev, sc->rl_miibus); 98550703Swpaul 98650703Swpaul bus_teardown_intr(dev, sc->rl_irq, sc->rl_intrhand); 98750703Swpaul bus_release_resource(dev, SYS_RES_IRQ, 0, sc->rl_res); 98850703Swpaul bus_release_resource(dev, RL_RES, RL_RID, sc->rl_res); 98950703Swpaul 99052426Swpaul contigfree(sc->rl_cdata.rl_rx_buf, RL_RXBUFLEN + 32, M_DEVBUF); 99150703Swpaul 99250703Swpaul splx(s); 99350703Swpaul 99450703Swpaul return(0); 99550703Swpaul} 99650703Swpaul 99740516Swpaul/* 99840516Swpaul * Initialize the transmit descriptors. 99940516Swpaul */ 100040516Swpaulstatic int rl_list_tx_init(sc) 100140516Swpaul struct rl_softc *sc; 100240516Swpaul{ 100340516Swpaul struct rl_chain_data *cd; 100440516Swpaul int i; 100540516Swpaul 100640516Swpaul cd = &sc->rl_cdata; 100740516Swpaul for (i = 0; i < RL_TX_LIST_CNT; i++) { 100845633Swpaul cd->rl_tx_chain[i] = NULL; 100948028Swpaul CSR_WRITE_4(sc, 101048028Swpaul RL_TXADDR0 + (i * sizeof(u_int32_t)), 0x0000000); 101140516Swpaul } 101240516Swpaul 101345633Swpaul sc->rl_cdata.cur_tx = 0; 101445633Swpaul sc->rl_cdata.last_tx = 0; 101540516Swpaul 101640516Swpaul return(0); 101740516Swpaul} 101840516Swpaul 101940516Swpaul/* 102040516Swpaul * A frame has been uploaded: pass the resulting mbuf chain up to 102140516Swpaul * the higher level protocols. 102240516Swpaul * 102340516Swpaul * You know there's something wrong with a PCI bus-master chip design 102440516Swpaul * when you have to use m_devget(). 102540516Swpaul * 102640516Swpaul * The receive operation is badly documented in the datasheet, so I'll 102740516Swpaul * attempt to document it here. The driver provides a buffer area and 102840516Swpaul * places its base address in the RX buffer start address register. 102940516Swpaul * The chip then begins copying frames into the RX buffer. Each frame 103040516Swpaul * is preceeded by a 32-bit RX status word which specifies the length 103140516Swpaul * of the frame and certain other status bits. Each frame (starting with 103240516Swpaul * the status word) is also 32-bit aligned. The frame length is in the 103340516Swpaul * first 16 bits of the status word; the lower 15 bits correspond with 103440516Swpaul * the 'rx status register' mentioned in the datasheet. 103548028Swpaul * 103648028Swpaul * Note: to make the Alpha happy, the frame payload needs to be aligned 103748028Swpaul * on a 32-bit boundary. To achieve this, we cheat a bit by copying from 103848028Swpaul * the ring buffer starting at an address two bytes before the actual 103948028Swpaul * data location. We can then shave off the first two bytes using m_adj(). 104048028Swpaul * The reason we do this is because m_devget() doesn't let us specify an 104148028Swpaul * offset into the mbuf storage space, so we have to artificially create 104248028Swpaul * one. The ring is allocated in such a way that there are a few unused 104348028Swpaul * bytes of space preceecing it so that it will be safe for us to do the 104448028Swpaul * 2-byte backstep even if reading from the ring at offset 0. 104540516Swpaul */ 104640516Swpaulstatic void rl_rxeof(sc) 104740516Swpaul struct rl_softc *sc; 104840516Swpaul{ 104940516Swpaul struct ether_header *eh; 105040516Swpaul struct mbuf *m; 105140516Swpaul struct ifnet *ifp; 105240516Swpaul int total_len = 0; 105340516Swpaul u_int32_t rxstat; 105440516Swpaul caddr_t rxbufpos; 105540516Swpaul int wrap = 0; 105640516Swpaul u_int16_t cur_rx; 105740516Swpaul u_int16_t limit; 105840516Swpaul u_int16_t rx_bytes = 0, max_bytes; 105940516Swpaul 106040516Swpaul ifp = &sc->arpcom.ac_if; 106140516Swpaul 106240516Swpaul cur_rx = (CSR_READ_2(sc, RL_CURRXADDR) + 16) % RL_RXBUFLEN; 106340516Swpaul 106440516Swpaul /* Do not try to read past this point. */ 106540516Swpaul limit = CSR_READ_2(sc, RL_CURRXBUF) % RL_RXBUFLEN; 106640516Swpaul 106740516Swpaul if (limit < cur_rx) 106840516Swpaul max_bytes = (RL_RXBUFLEN - cur_rx) + limit; 106940516Swpaul else 107040516Swpaul max_bytes = limit - cur_rx; 107140516Swpaul 107242738Swpaul while((CSR_READ_1(sc, RL_COMMAND) & RL_CMD_EMPTY_RXBUF) == 0) { 107340516Swpaul rxbufpos = sc->rl_cdata.rl_rx_buf + cur_rx; 107440516Swpaul rxstat = *(u_int32_t *)rxbufpos; 107540516Swpaul 107640516Swpaul /* 107740516Swpaul * Here's a totally undocumented fact for you. When the 107840516Swpaul * RealTek chip is in the process of copying a packet into 107940516Swpaul * RAM for you, the length will be 0xfff0. If you spot a 108040516Swpaul * packet header with this value, you need to stop. The 108140516Swpaul * datasheet makes absolutely no mention of this and 108240516Swpaul * RealTek should be shot for this. 108340516Swpaul */ 108440516Swpaul if ((u_int16_t)(rxstat >> 16) == RL_RXSTAT_UNFINISHED) 108540516Swpaul break; 108640516Swpaul 108740516Swpaul if (!(rxstat & RL_RXSTAT_RXOK)) { 108840516Swpaul ifp->if_ierrors++; 108950703Swpaul rl_init(sc); 109050703Swpaul return; 109140516Swpaul } 109240516Swpaul 109340516Swpaul /* No errors; receive the packet. */ 109440516Swpaul total_len = rxstat >> 16; 109540516Swpaul rx_bytes += total_len + 4; 109640516Swpaul 109740516Swpaul /* 109842051Swpaul * XXX The RealTek chip includes the CRC with every 109942051Swpaul * received frame, and there's no way to turn this 110042051Swpaul * behavior off (at least, I can't find anything in 110142051Swpaul * the manual that explains how to do it) so we have 110242051Swpaul * to trim off the CRC manually. 110342051Swpaul */ 110442051Swpaul total_len -= ETHER_CRC_LEN; 110542051Swpaul 110642051Swpaul /* 110740516Swpaul * Avoid trying to read more bytes than we know 110840516Swpaul * the chip has prepared for us. 110940516Swpaul */ 111040516Swpaul if (rx_bytes > max_bytes) 111140516Swpaul break; 111240516Swpaul 111340516Swpaul rxbufpos = sc->rl_cdata.rl_rx_buf + 111440516Swpaul ((cur_rx + sizeof(u_int32_t)) % RL_RXBUFLEN); 111540516Swpaul 111640516Swpaul if (rxbufpos == (sc->rl_cdata.rl_rx_buf + RL_RXBUFLEN)) 111740516Swpaul rxbufpos = sc->rl_cdata.rl_rx_buf; 111840516Swpaul 111940516Swpaul wrap = (sc->rl_cdata.rl_rx_buf + RL_RXBUFLEN) - rxbufpos; 112040516Swpaul 112140516Swpaul if (total_len > wrap) { 112260043Swpaul /* 112360043Swpaul * Fool m_devget() into thinking we want to copy 112460043Swpaul * the whole buffer so we don't end up fragmenting 112560043Swpaul * the data. 112660043Swpaul */ 112748028Swpaul m = m_devget(rxbufpos - RL_ETHER_ALIGN, 112860043Swpaul total_len + RL_ETHER_ALIGN, 0, ifp, NULL); 112940516Swpaul if (m == NULL) { 113040516Swpaul ifp->if_ierrors++; 113140516Swpaul printf("rl%d: out of mbufs, tried to " 113252426Swpaul "copy %d bytes\n", sc->rl_unit, wrap); 113352426Swpaul } else { 113448028Swpaul m_adj(m, RL_ETHER_ALIGN); 113540516Swpaul m_copyback(m, wrap, total_len - wrap, 113640516Swpaul sc->rl_cdata.rl_rx_buf); 113748028Swpaul } 113842051Swpaul cur_rx = (total_len - wrap + ETHER_CRC_LEN); 113940516Swpaul } else { 114048028Swpaul m = m_devget(rxbufpos - RL_ETHER_ALIGN, 114148028Swpaul total_len + RL_ETHER_ALIGN, 0, ifp, NULL); 114240516Swpaul if (m == NULL) { 114340516Swpaul ifp->if_ierrors++; 114440516Swpaul printf("rl%d: out of mbufs, tried to " 114552426Swpaul "copy %d bytes\n", sc->rl_unit, total_len); 114648028Swpaul } else 114748028Swpaul m_adj(m, RL_ETHER_ALIGN); 114842051Swpaul cur_rx += total_len + 4 + ETHER_CRC_LEN; 114940516Swpaul } 115040516Swpaul 115140516Swpaul /* 115240516Swpaul * Round up to 32-bit boundary. 115340516Swpaul */ 115440516Swpaul cur_rx = (cur_rx + 3) & ~3; 115540516Swpaul CSR_WRITE_2(sc, RL_CURRXADDR, cur_rx - 16); 115640516Swpaul 115740516Swpaul if (m == NULL) 115840516Swpaul continue; 115940516Swpaul 116040516Swpaul eh = mtod(m, struct ether_header *); 116140516Swpaul ifp->if_ipackets++; 116240516Swpaul 116340516Swpaul /* Remove header from mbuf and pass it on. */ 116440516Swpaul m_adj(m, sizeof(struct ether_header)); 116540516Swpaul ether_input(ifp, eh, m); 116640516Swpaul } 116740516Swpaul 116840516Swpaul return; 116940516Swpaul} 117040516Swpaul 117140516Swpaul/* 117240516Swpaul * A frame was downloaded to the chip. It's safe for us to clean up 117340516Swpaul * the list buffers. 117440516Swpaul */ 117540516Swpaulstatic void rl_txeof(sc) 117640516Swpaul struct rl_softc *sc; 117740516Swpaul{ 117840516Swpaul struct ifnet *ifp; 117940516Swpaul u_int32_t txstat; 118040516Swpaul 118140516Swpaul ifp = &sc->arpcom.ac_if; 118240516Swpaul 118340516Swpaul /* Clear the timeout timer. */ 118440516Swpaul ifp->if_timer = 0; 118540516Swpaul 118640516Swpaul /* 118740516Swpaul * Go through our tx list and free mbufs for those 118840516Swpaul * frames that have been uploaded. 118940516Swpaul */ 119045633Swpaul do { 119145633Swpaul txstat = CSR_READ_4(sc, RL_LAST_TXSTAT(sc)); 119245633Swpaul if (!(txstat & (RL_TXSTAT_TX_OK| 119345633Swpaul RL_TXSTAT_TX_UNDERRUN|RL_TXSTAT_TXABRT))) 119440516Swpaul break; 119540516Swpaul 119645633Swpaul ifp->if_collisions += (txstat & RL_TXSTAT_COLLCNT) >> 24; 119740516Swpaul 119845633Swpaul if (RL_LAST_TXMBUF(sc) != NULL) { 119945633Swpaul m_freem(RL_LAST_TXMBUF(sc)); 120045633Swpaul RL_LAST_TXMBUF(sc) = NULL; 120145633Swpaul } 120245633Swpaul if (txstat & RL_TXSTAT_TX_OK) 120345633Swpaul ifp->if_opackets++; 120445633Swpaul else { 120552426Swpaul int oldthresh; 120645633Swpaul ifp->if_oerrors++; 120745633Swpaul if ((txstat & RL_TXSTAT_TXABRT) || 120845633Swpaul (txstat & RL_TXSTAT_OUTOFWIN)) 120945633Swpaul CSR_WRITE_4(sc, RL_TXCFG, RL_TXCFG_CONFIG); 121052426Swpaul oldthresh = sc->rl_txthresh; 121152426Swpaul /* error recovery */ 121252426Swpaul rl_reset(sc); 121352426Swpaul rl_init(sc); 121452426Swpaul /* 121552426Swpaul * If there was a transmit underrun, 121652426Swpaul * bump the TX threshold. 121752426Swpaul */ 121852426Swpaul if (txstat & RL_TXSTAT_TX_UNDERRUN) 121952426Swpaul sc->rl_txthresh = oldthresh + 32; 122052426Swpaul return; 122145633Swpaul } 122245633Swpaul RL_INC(sc->rl_cdata.last_tx); 122345633Swpaul ifp->if_flags &= ~IFF_OACTIVE; 122445633Swpaul } while (sc->rl_cdata.last_tx != sc->rl_cdata.cur_tx); 122540516Swpaul 122650703Swpaul return; 122750703Swpaul} 122840516Swpaul 122950703Swpaulstatic void rl_tick(xsc) 123050703Swpaul void *xsc; 123150703Swpaul{ 123250703Swpaul struct rl_softc *sc; 123350703Swpaul struct mii_data *mii; 123450703Swpaul int s; 123550703Swpaul 123650703Swpaul s = splimp(); 123750703Swpaul 123850703Swpaul sc = xsc; 123950703Swpaul mii = device_get_softc(sc->rl_miibus); 124050703Swpaul 124150703Swpaul mii_tick(mii); 124250703Swpaul 124350703Swpaul splx(s); 124450703Swpaul 124550703Swpaul sc->rl_stat_ch = timeout(rl_tick, sc, hz); 124650703Swpaul 124740516Swpaul return; 124840516Swpaul} 124940516Swpaul 125040516Swpaulstatic void rl_intr(arg) 125140516Swpaul void *arg; 125240516Swpaul{ 125340516Swpaul struct rl_softc *sc; 125440516Swpaul struct ifnet *ifp; 125540516Swpaul u_int16_t status; 125640516Swpaul 125740516Swpaul sc = arg; 125840516Swpaul ifp = &sc->arpcom.ac_if; 125940516Swpaul 126040516Swpaul /* Disable interrupts. */ 126140516Swpaul CSR_WRITE_2(sc, RL_IMR, 0x0000); 126240516Swpaul 126340516Swpaul for (;;) { 126440516Swpaul 126540516Swpaul status = CSR_READ_2(sc, RL_ISR); 126640516Swpaul if (status) 126740516Swpaul CSR_WRITE_2(sc, RL_ISR, status); 126840516Swpaul 126940516Swpaul if ((status & RL_INTRS) == 0) 127040516Swpaul break; 127140516Swpaul 127240516Swpaul if (status & RL_ISR_RX_OK) 127340516Swpaul rl_rxeof(sc); 127440516Swpaul 127540516Swpaul if (status & RL_ISR_RX_ERR) 127640516Swpaul rl_rxeof(sc); 127740516Swpaul 127845633Swpaul if ((status & RL_ISR_TX_OK) || (status & RL_ISR_TX_ERR)) 127940516Swpaul rl_txeof(sc); 128040516Swpaul 128140516Swpaul if (status & RL_ISR_SYSTEM_ERR) { 128240516Swpaul rl_reset(sc); 128340516Swpaul rl_init(sc); 128440516Swpaul } 128540516Swpaul 128640516Swpaul } 128740516Swpaul 128840516Swpaul /* Re-enable interrupts. */ 128940516Swpaul CSR_WRITE_2(sc, RL_IMR, RL_INTRS); 129040516Swpaul 129152426Swpaul if (ifp->if_snd.ifq_head != NULL) 129240516Swpaul rl_start(ifp); 129340516Swpaul 129440516Swpaul return; 129540516Swpaul} 129640516Swpaul 129740516Swpaul/* 129840516Swpaul * Encapsulate an mbuf chain in a descriptor by coupling the mbuf data 129940516Swpaul * pointers to the fragment pointers. 130040516Swpaul */ 130145633Swpaulstatic int rl_encap(sc, m_head) 130240516Swpaul struct rl_softc *sc; 130340516Swpaul struct mbuf *m_head; 130440516Swpaul{ 130541243Swpaul struct mbuf *m_new = NULL; 130640516Swpaul 130740516Swpaul /* 130845633Swpaul * The RealTek is brain damaged and wants longword-aligned 130945633Swpaul * TX buffers, plus we can only have one fragment buffer 131045633Swpaul * per packet. We have to copy pretty much all the time. 131140516Swpaul */ 131240516Swpaul 131341243Swpaul MGETHDR(m_new, M_DONTWAIT, MT_DATA); 131441243Swpaul if (m_new == NULL) { 131541243Swpaul printf("rl%d: no memory for tx list", sc->rl_unit); 131641243Swpaul return(1); 131741243Swpaul } 131841243Swpaul if (m_head->m_pkthdr.len > MHLEN) { 131941243Swpaul MCLGET(m_new, M_DONTWAIT); 132041243Swpaul if (!(m_new->m_flags & M_EXT)) { 132141243Swpaul m_freem(m_new); 132241243Swpaul printf("rl%d: no memory for tx list", 132341243Swpaul sc->rl_unit); 132440516Swpaul return(1); 132540516Swpaul } 132640516Swpaul } 132752426Swpaul m_copydata(m_head, 0, m_head->m_pkthdr.len, mtod(m_new, caddr_t)); 132841243Swpaul m_new->m_pkthdr.len = m_new->m_len = m_head->m_pkthdr.len; 132941243Swpaul m_freem(m_head); 133041243Swpaul m_head = m_new; 133140516Swpaul 133240516Swpaul /* Pad frames to at least 60 bytes. */ 133341243Swpaul if (m_head->m_pkthdr.len < RL_MIN_FRAMELEN) { 133455058Swpaul /* 133555058Swpaul * Make security concious people happy: zero out the 133655058Swpaul * bytes in the pad area, since we don't know what 133755058Swpaul * this mbuf cluster buffer's previous user might 133855058Swpaul * have left in it. 133955058Swpaul */ 134055058Swpaul bzero(mtod(m_head, char *) + m_head->m_pkthdr.len, 134155058Swpaul RL_MIN_FRAMELEN - m_head->m_pkthdr.len); 134240516Swpaul m_head->m_pkthdr.len += 134352426Swpaul (RL_MIN_FRAMELEN - m_head->m_pkthdr.len); 134441243Swpaul m_head->m_len = m_head->m_pkthdr.len; 134541243Swpaul } 134640516Swpaul 134745633Swpaul RL_CUR_TXMBUF(sc) = m_head; 134840516Swpaul 134940516Swpaul return(0); 135040516Swpaul} 135140516Swpaul 135240516Swpaul/* 135340516Swpaul * Main transmit routine. 135440516Swpaul */ 135540516Swpaul 135640516Swpaulstatic void rl_start(ifp) 135740516Swpaul struct ifnet *ifp; 135840516Swpaul{ 135940516Swpaul struct rl_softc *sc; 136040516Swpaul struct mbuf *m_head = NULL; 136140516Swpaul 136240516Swpaul sc = ifp->if_softc; 136340516Swpaul 136445633Swpaul while(RL_CUR_TXMBUF(sc) == NULL) { 136540516Swpaul IF_DEQUEUE(&ifp->if_snd, m_head); 136640516Swpaul if (m_head == NULL) 136740516Swpaul break; 136840516Swpaul 136958801Swpaul if (rl_encap(sc, m_head)) { 137058801Swpaul IF_PREPEND(&ifp->if_snd, m_head); 137158801Swpaul ifp->if_flags |= IFF_OACTIVE; 137258801Swpaul break; 137358801Swpaul } 137440516Swpaul 137540516Swpaul /* 137640516Swpaul * If there's a BPF listener, bounce a copy of this frame 137740516Swpaul * to him. 137840516Swpaul */ 137940516Swpaul if (ifp->if_bpf) 138045633Swpaul bpf_mtap(ifp, RL_CUR_TXMBUF(sc)); 138151583Swpaul 138240516Swpaul /* 138340516Swpaul * Transmit the frame. 138440516Swpaul */ 138545633Swpaul CSR_WRITE_4(sc, RL_CUR_TXADDR(sc), 138645633Swpaul vtophys(mtod(RL_CUR_TXMBUF(sc), caddr_t))); 138745633Swpaul CSR_WRITE_4(sc, RL_CUR_TXSTAT(sc), 138852426Swpaul RL_TXTHRESH(sc->rl_txthresh) | 138952426Swpaul RL_CUR_TXMBUF(sc)->m_pkthdr.len); 139045633Swpaul 139145633Swpaul RL_INC(sc->rl_cdata.cur_tx); 139240516Swpaul } 139340516Swpaul 139440516Swpaul /* 139545633Swpaul * We broke out of the loop because all our TX slots are 139645633Swpaul * full. Mark the NIC as busy until it drains some of the 139745633Swpaul * packets from the queue. 139845633Swpaul */ 139945633Swpaul if (RL_CUR_TXMBUF(sc) != NULL) 140045633Swpaul ifp->if_flags |= IFF_OACTIVE; 140145633Swpaul 140245633Swpaul /* 140340516Swpaul * Set a timeout in case the chip goes out to lunch. 140440516Swpaul */ 140540516Swpaul ifp->if_timer = 5; 140640516Swpaul 140740516Swpaul return; 140840516Swpaul} 140940516Swpaul 141040516Swpaulstatic void rl_init(xsc) 141140516Swpaul void *xsc; 141240516Swpaul{ 141340516Swpaul struct rl_softc *sc = xsc; 141440516Swpaul struct ifnet *ifp = &sc->arpcom.ac_if; 141550703Swpaul struct mii_data *mii; 141640516Swpaul int s, i; 141740516Swpaul u_int32_t rxcfg = 0; 141840516Swpaul 141940516Swpaul s = splimp(); 142040516Swpaul 142150703Swpaul mii = device_get_softc(sc->rl_miibus); 142240516Swpaul 142340516Swpaul /* 142440516Swpaul * Cancel pending I/O and free all RX/TX buffers. 142540516Swpaul */ 142640516Swpaul rl_stop(sc); 142740516Swpaul 142840516Swpaul /* Init our MAC address */ 142940516Swpaul for (i = 0; i < ETHER_ADDR_LEN; i++) { 143040516Swpaul CSR_WRITE_1(sc, RL_IDR0 + i, sc->arpcom.ac_enaddr[i]); 143140516Swpaul } 143240516Swpaul 143340516Swpaul /* Init the RX buffer pointer register. */ 143440516Swpaul CSR_WRITE_4(sc, RL_RXADDR, vtophys(sc->rl_cdata.rl_rx_buf)); 143540516Swpaul 143640516Swpaul /* Init TX descriptors. */ 143740516Swpaul rl_list_tx_init(sc); 143840516Swpaul 143940516Swpaul /* 144040516Swpaul * Enable transmit and receive. 144140516Swpaul */ 144240516Swpaul CSR_WRITE_1(sc, RL_COMMAND, RL_CMD_TX_ENB|RL_CMD_RX_ENB); 144340516Swpaul 144440516Swpaul /* 144545633Swpaul * Set the initial TX and RX configuration. 144640516Swpaul */ 144745633Swpaul CSR_WRITE_4(sc, RL_TXCFG, RL_TXCFG_CONFIG); 144840516Swpaul CSR_WRITE_4(sc, RL_RXCFG, RL_RXCFG_CONFIG); 144940516Swpaul 145040516Swpaul /* Set the individual bit to receive frames for this host only. */ 145140516Swpaul rxcfg = CSR_READ_4(sc, RL_RXCFG); 145240516Swpaul rxcfg |= RL_RXCFG_RX_INDIV; 145340516Swpaul 145440516Swpaul /* If we want promiscuous mode, set the allframes bit. */ 145540516Swpaul if (ifp->if_flags & IFF_PROMISC) { 145640516Swpaul rxcfg |= RL_RXCFG_RX_ALLPHYS; 145740516Swpaul CSR_WRITE_4(sc, RL_RXCFG, rxcfg); 145840516Swpaul } else { 145940516Swpaul rxcfg &= ~RL_RXCFG_RX_ALLPHYS; 146040516Swpaul CSR_WRITE_4(sc, RL_RXCFG, rxcfg); 146140516Swpaul } 146240516Swpaul 146340516Swpaul /* 146440516Swpaul * Set capture broadcast bit to capture broadcast frames. 146540516Swpaul */ 146640516Swpaul if (ifp->if_flags & IFF_BROADCAST) { 146740516Swpaul rxcfg |= RL_RXCFG_RX_BROAD; 146840516Swpaul CSR_WRITE_4(sc, RL_RXCFG, rxcfg); 146940516Swpaul } else { 147040516Swpaul rxcfg &= ~RL_RXCFG_RX_BROAD; 147140516Swpaul CSR_WRITE_4(sc, RL_RXCFG, rxcfg); 147240516Swpaul } 147340516Swpaul 147440516Swpaul /* 147540516Swpaul * Program the multicast filter, if necessary. 147640516Swpaul */ 147740516Swpaul rl_setmulti(sc); 147840516Swpaul 147940516Swpaul /* 148040516Swpaul * Enable interrupts. 148140516Swpaul */ 148240516Swpaul CSR_WRITE_2(sc, RL_IMR, RL_INTRS); 148340516Swpaul 148452426Swpaul /* Set initial TX threshold */ 148552426Swpaul sc->rl_txthresh = RL_TX_THRESH_INIT; 148652426Swpaul 148740516Swpaul /* Start RX/TX process. */ 148840516Swpaul CSR_WRITE_4(sc, RL_MISSEDPKT, 0); 148940516Swpaul 149040516Swpaul /* Enable receiver and transmitter. */ 149140516Swpaul CSR_WRITE_1(sc, RL_COMMAND, RL_CMD_TX_ENB|RL_CMD_RX_ENB); 149240516Swpaul 149350703Swpaul mii_mediachg(mii); 149440516Swpaul 149540516Swpaul CSR_WRITE_1(sc, RL_CFG1, RL_CFG1_DRVLOAD|RL_CFG1_FULLDUPLEX); 149640516Swpaul 149740516Swpaul ifp->if_flags |= IFF_RUNNING; 149840516Swpaul ifp->if_flags &= ~IFF_OACTIVE; 149940516Swpaul 150040516Swpaul (void)splx(s); 150140516Swpaul 150250703Swpaul sc->rl_stat_ch = timeout(rl_tick, sc, hz); 150350703Swpaul 150440516Swpaul return; 150540516Swpaul} 150640516Swpaul 150740516Swpaul/* 150840516Swpaul * Set media options. 150940516Swpaul */ 151040516Swpaulstatic int rl_ifmedia_upd(ifp) 151140516Swpaul struct ifnet *ifp; 151240516Swpaul{ 151340516Swpaul struct rl_softc *sc; 151450703Swpaul struct mii_data *mii; 151540516Swpaul 151640516Swpaul sc = ifp->if_softc; 151750703Swpaul mii = device_get_softc(sc->rl_miibus); 151850703Swpaul mii_mediachg(mii); 151940516Swpaul 152040516Swpaul return(0); 152140516Swpaul} 152240516Swpaul 152340516Swpaul/* 152440516Swpaul * Report current media status. 152540516Swpaul */ 152640516Swpaulstatic void rl_ifmedia_sts(ifp, ifmr) 152740516Swpaul struct ifnet *ifp; 152840516Swpaul struct ifmediareq *ifmr; 152940516Swpaul{ 153040516Swpaul struct rl_softc *sc; 153150703Swpaul struct mii_data *mii; 153240516Swpaul 153340516Swpaul sc = ifp->if_softc; 153450703Swpaul mii = device_get_softc(sc->rl_miibus); 153540516Swpaul 153650703Swpaul mii_pollstat(mii); 153750703Swpaul ifmr->ifm_active = mii->mii_media_active; 153850703Swpaul ifmr->ifm_status = mii->mii_media_status; 153940516Swpaul 154040516Swpaul return; 154140516Swpaul} 154240516Swpaul 154340516Swpaulstatic int rl_ioctl(ifp, command, data) 154440516Swpaul struct ifnet *ifp; 154540516Swpaul u_long command; 154640516Swpaul caddr_t data; 154740516Swpaul{ 154840516Swpaul struct rl_softc *sc = ifp->if_softc; 154940516Swpaul struct ifreq *ifr = (struct ifreq *) data; 155050703Swpaul struct mii_data *mii; 155140516Swpaul int s, error = 0; 155240516Swpaul 155340516Swpaul s = splimp(); 155440516Swpaul 155540516Swpaul switch(command) { 155640516Swpaul case SIOCSIFADDR: 155740516Swpaul case SIOCGIFADDR: 155840516Swpaul case SIOCSIFMTU: 155940516Swpaul error = ether_ioctl(ifp, command, data); 156040516Swpaul break; 156140516Swpaul case SIOCSIFFLAGS: 156240516Swpaul if (ifp->if_flags & IFF_UP) { 156340516Swpaul rl_init(sc); 156440516Swpaul } else { 156540516Swpaul if (ifp->if_flags & IFF_RUNNING) 156640516Swpaul rl_stop(sc); 156740516Swpaul } 156840516Swpaul error = 0; 156940516Swpaul break; 157040516Swpaul case SIOCADDMULTI: 157140516Swpaul case SIOCDELMULTI: 157240516Swpaul rl_setmulti(sc); 157340516Swpaul error = 0; 157440516Swpaul break; 157540516Swpaul case SIOCGIFMEDIA: 157640516Swpaul case SIOCSIFMEDIA: 157750703Swpaul mii = device_get_softc(sc->rl_miibus); 157850703Swpaul error = ifmedia_ioctl(ifp, ifr, &mii->mii_media, command); 157940516Swpaul break; 158040516Swpaul default: 158140516Swpaul error = EINVAL; 158240516Swpaul break; 158340516Swpaul } 158440516Swpaul 158540516Swpaul (void)splx(s); 158640516Swpaul 158740516Swpaul return(error); 158840516Swpaul} 158940516Swpaul 159040516Swpaulstatic void rl_watchdog(ifp) 159140516Swpaul struct ifnet *ifp; 159240516Swpaul{ 159340516Swpaul struct rl_softc *sc; 159440516Swpaul 159540516Swpaul sc = ifp->if_softc; 159640516Swpaul 159740516Swpaul printf("rl%d: watchdog timeout\n", sc->rl_unit); 159840516Swpaul ifp->if_oerrors++; 159950703Swpaul 160040516Swpaul rl_txeof(sc); 160140516Swpaul rl_rxeof(sc); 160240516Swpaul rl_init(sc); 160340516Swpaul 160440516Swpaul return; 160540516Swpaul} 160640516Swpaul 160740516Swpaul/* 160840516Swpaul * Stop the adapter and free any mbufs allocated to the 160940516Swpaul * RX and TX lists. 161040516Swpaul */ 161140516Swpaulstatic void rl_stop(sc) 161240516Swpaul struct rl_softc *sc; 161340516Swpaul{ 161440516Swpaul register int i; 161540516Swpaul struct ifnet *ifp; 161640516Swpaul 161740516Swpaul ifp = &sc->arpcom.ac_if; 161840516Swpaul ifp->if_timer = 0; 161940516Swpaul 162050703Swpaul untimeout(rl_tick, sc, sc->rl_stat_ch); 162150703Swpaul 162240516Swpaul CSR_WRITE_1(sc, RL_COMMAND, 0x00); 162340516Swpaul CSR_WRITE_2(sc, RL_IMR, 0x0000); 162440516Swpaul 162540516Swpaul /* 162640516Swpaul * Free the TX list buffers. 162740516Swpaul */ 162840516Swpaul for (i = 0; i < RL_TX_LIST_CNT; i++) { 162945633Swpaul if (sc->rl_cdata.rl_tx_chain[i] != NULL) { 163045633Swpaul m_freem(sc->rl_cdata.rl_tx_chain[i]); 163145633Swpaul sc->rl_cdata.rl_tx_chain[i] = NULL; 163245633Swpaul CSR_WRITE_4(sc, RL_TXADDR0 + i, 0x0000000); 163340516Swpaul } 163440516Swpaul } 163540516Swpaul 163640516Swpaul ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE); 163740516Swpaul 163840516Swpaul return; 163940516Swpaul} 164040516Swpaul 164140516Swpaul/* 164240516Swpaul * Stop all chip I/O so that the kernel's probe routines don't 164340516Swpaul * get confused by errant DMAs when rebooting. 164440516Swpaul */ 164550703Swpaulstatic void rl_shutdown(dev) 164650703Swpaul device_t dev; 164740516Swpaul{ 164850703Swpaul struct rl_softc *sc; 164940516Swpaul 165050703Swpaul sc = device_get_softc(dev); 165150703Swpaul 165240516Swpaul rl_stop(sc); 165340516Swpaul 165440516Swpaul return; 165540516Swpaul} 1656