if_rl.c revision 51089
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 51089 1999-09-08 15:01:58Z peter $ 3340516Swpaul */ 3440516Swpaul 3540516Swpaul/* 3640516Swpaul * RealTek 8129/8139 PCI NIC driver 3740516Swpaul * 3840516Swpaul * Supports several extremely cheap PCI 10/100 adapters based on 3940516Swpaul * the RealTek chipset. Datasheets can be obtained from 4040516Swpaul * www.realtek.com.tw. 4140516Swpaul * 4240516Swpaul * Written by Bill Paul <wpaul@ctr.columbia.edu> 4340516Swpaul * Electrical Engineering Department 4440516Swpaul * Columbia University, New York City 4540516Swpaul */ 4640516Swpaul 4740516Swpaul/* 4840516Swpaul * The RealTek 8139 PCI NIC redefines the meaning of 'low end.' This is 4940516Swpaul * probably the worst PCI ethernet controller ever made, with the possible 5040516Swpaul * exception of the FEAST chip made by SMC. The 8139 supports bus-master 5140516Swpaul * DMA, but it has a terrible interface that nullifies any performance 5240516Swpaul * gains that bus-master DMA usually offers. 5340516Swpaul * 5440516Swpaul * For transmission, the chip offers a series of four TX descriptor 5540516Swpaul * registers. Each transmit frame must be in a contiguous buffer, aligned 5641569Swpaul * on a longword (32-bit) boundary. This means we almost always have to 5740516Swpaul * do mbuf copies in order to transmit a frame, except in the unlikely 5840516Swpaul * case where a) the packet fits into a single mbuf, and b) the packet 5940516Swpaul * is 32-bit aligned within the mbuf's data area. The presence of only 6040516Swpaul * four descriptor registers means that we can never have more than four 6140516Swpaul * packets queued for transmission at any one time. 6240516Swpaul * 6340516Swpaul * Reception is not much better. The driver has to allocate a single large 6440516Swpaul * buffer area (up to 64K in size) into which the chip will DMA received 6540516Swpaul * frames. Because we don't know where within this region received packets 6640516Swpaul * will begin or end, we have no choice but to copy data from the buffer 6740516Swpaul * area into mbufs in order to pass the packets up to the higher protocol 6840516Swpaul * levels. 6940516Swpaul * 7040516Swpaul * It's impossible given this rotten design to really achieve decent 7140516Swpaul * performance at 100Mbps, unless you happen to have a 400Mhz PII or 7240516Swpaul * some equally overmuscled CPU to drive it. 7340516Swpaul * 7440516Swpaul * On the bright side, the 8139 does have a built-in PHY, although 7540516Swpaul * rather than using an MDIO serial interface like most other NICs, the 7640516Swpaul * PHY registers are directly accessible through the 8139's register 7740516Swpaul * space. The 8139 supports autonegotiation, as well as a 64-bit multicast 7840516Swpaul * filter. 7940516Swpaul * 8040516Swpaul * The 8129 chip is an older version of the 8139 that uses an external PHY 8140516Swpaul * chip. The 8129 has a serial MDIO interface for accessing the MII where 8240516Swpaul * the 8139 lets you directly access the on-board PHY registers. We need 8340516Swpaul * to select which interface to use depending on the chip type. 8440516Swpaul */ 8540516Swpaul 8648645Sdes#include "bpf.h" 8740516Swpaul 8840516Swpaul#include <sys/param.h> 8940516Swpaul#include <sys/systm.h> 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 10248645Sdes#if NBPF > 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> 11250703Swpaul#include <machine/resource.h> 11350703Swpaul#include <sys/bus.h> 11450703Swpaul#include <sys/rman.h> 11540516Swpaul 11650703Swpaul#include <dev/mii/mii.h> 11750703Swpaul#include <dev/mii/miivar.h> 11850703Swpaul 11940516Swpaul#include <pci/pcireg.h> 12040516Swpaul#include <pci/pcivar.h> 12140516Swpaul 12251089Speter/* "controller miibus0" required. See GENERIC if you get errors here. */ 12350703Swpaul#include "miibus_if.h" 12450703Swpaul 12540516Swpaul/* 12640516Swpaul * Default to using PIO access for this driver. On SMP systems, 12740516Swpaul * there appear to be problems with memory mapped mode: it looks like 12840516Swpaul * doing too many memory mapped access back to back in rapid succession 12940516Swpaul * can hang the bus. I'm inclined to blame this on crummy design/construction 13040516Swpaul * on the part of RealTek. Memory mapped mode does appear to work on 13140516Swpaul * uniprocessor systems though. 13240516Swpaul */ 13340516Swpaul#define RL_USEIOSPACE 13440516Swpaul 13540516Swpaul#include <pci/if_rlreg.h> 13640516Swpaul 13740516Swpaul#ifndef lint 13841591Sarchiestatic const char rcsid[] = 13950477Speter "$FreeBSD: head/sys/pci/if_rl.c 51089 1999-09-08 15:01:58Z peter $"; 14040516Swpaul#endif 14140516Swpaul 14240516Swpaul/* 14340516Swpaul * Various supported device vendors/types and their names. 14440516Swpaul */ 14540516Swpaulstatic struct rl_type rl_devs[] = { 14640516Swpaul { RT_VENDORID, RT_DEVICEID_8129, 14740516Swpaul "RealTek 8129 10/100BaseTX" }, 14840516Swpaul { RT_VENDORID, RT_DEVICEID_8139, 14940516Swpaul "RealTek 8139 10/100BaseTX" }, 15041243Swpaul { ACCTON_VENDORID, ACCTON_DEVICEID_5030, 15141243Swpaul "Accton MPX 5030/5038 10/100BaseTX" }, 15244238Swpaul { DELTA_VENDORID, DELTA_DEVICEID_8139, 15344238Swpaul "Delta Electronics 8139 10/100BaseTX" }, 15444238Swpaul { ADDTRON_VENDORID, ADDTRON_DEVICEID_8139, 15544238Swpaul "Addtron Technolgy 8139 10/100BaseTX" }, 15640516Swpaul { 0, 0, NULL } 15740516Swpaul}; 15840516Swpaul 15950703Swpaulstatic int rl_probe __P((device_t)); 16050703Swpaulstatic int rl_attach __P((device_t)); 16150703Swpaulstatic int rl_detach __P((device_t)); 16240516Swpaul 16345633Swpaulstatic int rl_encap __P((struct rl_softc *, struct mbuf * )); 16440516Swpaul 16540516Swpaulstatic void rl_rxeof __P((struct rl_softc *)); 16640516Swpaulstatic void rl_txeof __P((struct rl_softc *)); 16740516Swpaulstatic void rl_intr __P((void *)); 16850703Swpaulstatic void rl_tick __P((void *)); 16940516Swpaulstatic void rl_start __P((struct ifnet *)); 17040516Swpaulstatic int rl_ioctl __P((struct ifnet *, u_long, caddr_t)); 17140516Swpaulstatic void rl_init __P((void *)); 17240516Swpaulstatic void rl_stop __P((struct rl_softc *)); 17340516Swpaulstatic void rl_watchdog __P((struct ifnet *)); 17450703Swpaulstatic void rl_shutdown __P((device_t)); 17540516Swpaulstatic int rl_ifmedia_upd __P((struct ifnet *)); 17640516Swpaulstatic void rl_ifmedia_sts __P((struct ifnet *, struct ifmediareq *)); 17740516Swpaul 17841656Swpaulstatic void rl_eeprom_putbyte __P((struct rl_softc *, int)); 17941656Swpaulstatic void rl_eeprom_getword __P((struct rl_softc *, int, u_int16_t *)); 18040516Swpaulstatic void rl_read_eeprom __P((struct rl_softc *, caddr_t, 18140516Swpaul int, int, int)); 18240516Swpaulstatic void rl_mii_sync __P((struct rl_softc *)); 18340516Swpaulstatic void rl_mii_send __P((struct rl_softc *, u_int32_t, int)); 18440516Swpaulstatic int rl_mii_readreg __P((struct rl_softc *, struct rl_mii_frame *)); 18540516Swpaulstatic int rl_mii_writereg __P((struct rl_softc *, struct rl_mii_frame *)); 18640516Swpaul 18750703Swpaulstatic int rl_miibus_readreg __P((device_t, int, int)); 18850703Swpaulstatic int rl_miibus_writereg __P((device_t, int, int, int)); 18950703Swpaulstatic void rl_miibus_statchg __P((device_t)); 19040516Swpaul 19141656Swpaulstatic u_int8_t rl_calchash __P((caddr_t)); 19240516Swpaulstatic void rl_setmulti __P((struct rl_softc *)); 19340516Swpaulstatic void rl_reset __P((struct rl_softc *)); 19440516Swpaulstatic int rl_list_tx_init __P((struct rl_softc *)); 19540516Swpaul 19650703Swpaul#ifdef RL_USEIOSPACE 19750703Swpaul#define RL_RES SYS_RES_IOPORT 19850703Swpaul#define RL_RID RL_PCI_LOIO 19950703Swpaul#else 20050703Swpaul#define RL_RES SYS_RES_MEMORY 20150703Swpaul#define RL_RID RL_PCI_LOMEM 20250703Swpaul#endif 20350703Swpaul 20450703Swpaulstatic device_method_t rl_methods[] = { 20550703Swpaul /* Device interface */ 20650703Swpaul DEVMETHOD(device_probe, rl_probe), 20750703Swpaul DEVMETHOD(device_attach, rl_attach), 20850703Swpaul DEVMETHOD(device_detach, rl_detach), 20950703Swpaul DEVMETHOD(device_shutdown, rl_shutdown), 21050703Swpaul 21150703Swpaul /* bus interface */ 21250703Swpaul DEVMETHOD(bus_print_child, bus_generic_print_child), 21350703Swpaul DEVMETHOD(bus_driver_added, bus_generic_driver_added), 21450703Swpaul 21550703Swpaul /* MII interface */ 21650703Swpaul DEVMETHOD(miibus_readreg, rl_miibus_readreg), 21750703Swpaul DEVMETHOD(miibus_writereg, rl_miibus_writereg), 21850703Swpaul DEVMETHOD(miibus_statchg, rl_miibus_statchg), 21950703Swpaul 22050703Swpaul { 0, 0 } 22150703Swpaul}; 22250703Swpaul 22350703Swpaulstatic driver_t rl_driver = { 22450703Swpaul "rl", 22550703Swpaul rl_methods, 22650703Swpaul sizeof(struct rl_softc) 22750703Swpaul}; 22850703Swpaul 22950703Swpaulstatic devclass_t rl_devclass; 23050703Swpaul 23150703SwpaulDRIVER_MODULE(rl, pci, rl_driver, rl_devclass, 0, 0); 23250703SwpaulDRIVER_MODULE(miibus, rl, miibus_driver, miibus_devclass, 0, 0); 23350703Swpaul 23440516Swpaul#define EE_SET(x) \ 23540516Swpaul CSR_WRITE_1(sc, RL_EECMD, \ 23640516Swpaul CSR_READ_1(sc, RL_EECMD) | x) 23740516Swpaul 23840516Swpaul#define EE_CLR(x) \ 23940516Swpaul CSR_WRITE_1(sc, RL_EECMD, \ 24040516Swpaul CSR_READ_1(sc, RL_EECMD) & ~x) 24140516Swpaul 24240516Swpaul/* 24340516Swpaul * Send a read command and address to the EEPROM, check for ACK. 24440516Swpaul */ 24540516Swpaulstatic void rl_eeprom_putbyte(sc, addr) 24640516Swpaul struct rl_softc *sc; 24741656Swpaul int addr; 24840516Swpaul{ 24940516Swpaul register int d, i; 25040516Swpaul 25140516Swpaul d = addr | RL_EECMD_READ; 25240516Swpaul 25340516Swpaul /* 25440516Swpaul * Feed in each bit and stobe the clock. 25540516Swpaul */ 25640516Swpaul for (i = 0x400; i; i >>= 1) { 25740516Swpaul if (d & i) { 25840516Swpaul EE_SET(RL_EE_DATAIN); 25940516Swpaul } else { 26040516Swpaul EE_CLR(RL_EE_DATAIN); 26140516Swpaul } 26240516Swpaul DELAY(100); 26340516Swpaul EE_SET(RL_EE_CLK); 26440516Swpaul DELAY(150); 26540516Swpaul EE_CLR(RL_EE_CLK); 26640516Swpaul DELAY(100); 26740516Swpaul } 26840516Swpaul 26940516Swpaul return; 27040516Swpaul} 27140516Swpaul 27240516Swpaul/* 27340516Swpaul * Read a word of data stored in the EEPROM at address 'addr.' 27440516Swpaul */ 27540516Swpaulstatic void rl_eeprom_getword(sc, addr, dest) 27640516Swpaul struct rl_softc *sc; 27741656Swpaul int addr; 27840516Swpaul u_int16_t *dest; 27940516Swpaul{ 28040516Swpaul register int i; 28140516Swpaul u_int16_t word = 0; 28240516Swpaul 28340516Swpaul /* Enter EEPROM access mode. */ 28440516Swpaul CSR_WRITE_1(sc, RL_EECMD, RL_EEMODE_PROGRAM|RL_EE_SEL); 28540516Swpaul 28640516Swpaul /* 28740516Swpaul * Send address of word we want to read. 28840516Swpaul */ 28940516Swpaul rl_eeprom_putbyte(sc, addr); 29040516Swpaul 29140516Swpaul CSR_WRITE_1(sc, RL_EECMD, RL_EEMODE_PROGRAM|RL_EE_SEL); 29240516Swpaul 29340516Swpaul /* 29440516Swpaul * Start reading bits from EEPROM. 29540516Swpaul */ 29640516Swpaul for (i = 0x8000; i; i >>= 1) { 29740516Swpaul EE_SET(RL_EE_CLK); 29840516Swpaul DELAY(100); 29940516Swpaul if (CSR_READ_1(sc, RL_EECMD) & RL_EE_DATAOUT) 30040516Swpaul word |= i; 30140516Swpaul EE_CLR(RL_EE_CLK); 30240516Swpaul DELAY(100); 30340516Swpaul } 30440516Swpaul 30540516Swpaul /* Turn off EEPROM access mode. */ 30640516Swpaul CSR_WRITE_1(sc, RL_EECMD, RL_EEMODE_OFF); 30740516Swpaul 30840516Swpaul *dest = word; 30940516Swpaul 31040516Swpaul return; 31140516Swpaul} 31240516Swpaul 31340516Swpaul/* 31440516Swpaul * Read a sequence of words from the EEPROM. 31540516Swpaul */ 31640516Swpaulstatic void rl_read_eeprom(sc, dest, off, cnt, swap) 31740516Swpaul struct rl_softc *sc; 31840516Swpaul caddr_t dest; 31940516Swpaul int off; 32040516Swpaul int cnt; 32140516Swpaul int swap; 32240516Swpaul{ 32340516Swpaul int i; 32440516Swpaul u_int16_t word = 0, *ptr; 32540516Swpaul 32640516Swpaul for (i = 0; i < cnt; i++) { 32740516Swpaul rl_eeprom_getword(sc, off + i, &word); 32840516Swpaul ptr = (u_int16_t *)(dest + (i * 2)); 32940516Swpaul if (swap) 33040516Swpaul *ptr = ntohs(word); 33140516Swpaul else 33240516Swpaul *ptr = word; 33340516Swpaul } 33440516Swpaul 33540516Swpaul return; 33640516Swpaul} 33740516Swpaul 33840516Swpaul 33940516Swpaul/* 34040516Swpaul * MII access routines are provided for the 8129, which 34140516Swpaul * doesn't have a built-in PHY. For the 8139, we fake things 34240516Swpaul * up by diverting rl_phy_readreg()/rl_phy_writereg() to the 34340516Swpaul * direct access PHY registers. 34440516Swpaul */ 34540516Swpaul#define MII_SET(x) \ 34640516Swpaul CSR_WRITE_1(sc, RL_MII, \ 34740516Swpaul CSR_READ_1(sc, RL_MII) | x) 34840516Swpaul 34940516Swpaul#define MII_CLR(x) \ 35040516Swpaul CSR_WRITE_1(sc, RL_MII, \ 35140516Swpaul CSR_READ_1(sc, RL_MII) & ~x) 35240516Swpaul 35340516Swpaul/* 35440516Swpaul * Sync the PHYs by setting data bit and strobing the clock 32 times. 35540516Swpaul */ 35640516Swpaulstatic void rl_mii_sync(sc) 35740516Swpaul struct rl_softc *sc; 35840516Swpaul{ 35940516Swpaul register int i; 36040516Swpaul 36140516Swpaul MII_SET(RL_MII_DIR|RL_MII_DATAOUT); 36240516Swpaul 36340516Swpaul for (i = 0; i < 32; i++) { 36440516Swpaul MII_SET(RL_MII_CLK); 36540516Swpaul DELAY(1); 36640516Swpaul MII_CLR(RL_MII_CLK); 36740516Swpaul DELAY(1); 36840516Swpaul } 36940516Swpaul 37040516Swpaul return; 37140516Swpaul} 37240516Swpaul 37340516Swpaul/* 37440516Swpaul * Clock a series of bits through the MII. 37540516Swpaul */ 37640516Swpaulstatic void rl_mii_send(sc, bits, cnt) 37740516Swpaul struct rl_softc *sc; 37840516Swpaul u_int32_t bits; 37940516Swpaul int cnt; 38040516Swpaul{ 38140516Swpaul int i; 38240516Swpaul 38340516Swpaul MII_CLR(RL_MII_CLK); 38440516Swpaul 38540516Swpaul for (i = (0x1 << (cnt - 1)); i; i >>= 1) { 38640516Swpaul if (bits & i) { 38740516Swpaul MII_SET(RL_MII_DATAOUT); 38840516Swpaul } else { 38940516Swpaul MII_CLR(RL_MII_DATAOUT); 39040516Swpaul } 39140516Swpaul DELAY(1); 39240516Swpaul MII_CLR(RL_MII_CLK); 39340516Swpaul DELAY(1); 39440516Swpaul MII_SET(RL_MII_CLK); 39540516Swpaul } 39640516Swpaul} 39740516Swpaul 39840516Swpaul/* 39940516Swpaul * Read an PHY register through the MII. 40040516Swpaul */ 40140516Swpaulstatic int rl_mii_readreg(sc, frame) 40240516Swpaul struct rl_softc *sc; 40340516Swpaul struct rl_mii_frame *frame; 40440516Swpaul 40540516Swpaul{ 40640516Swpaul int i, ack, s; 40740516Swpaul 40840516Swpaul s = splimp(); 40940516Swpaul 41040516Swpaul /* 41140516Swpaul * Set up frame for RX. 41240516Swpaul */ 41340516Swpaul frame->mii_stdelim = RL_MII_STARTDELIM; 41440516Swpaul frame->mii_opcode = RL_MII_READOP; 41540516Swpaul frame->mii_turnaround = 0; 41640516Swpaul frame->mii_data = 0; 41740516Swpaul 41840516Swpaul CSR_WRITE_2(sc, RL_MII, 0); 41940516Swpaul 42040516Swpaul /* 42140516Swpaul * Turn on data xmit. 42240516Swpaul */ 42340516Swpaul MII_SET(RL_MII_DIR); 42440516Swpaul 42540516Swpaul rl_mii_sync(sc); 42640516Swpaul 42740516Swpaul /* 42840516Swpaul * Send command/address info. 42940516Swpaul */ 43040516Swpaul rl_mii_send(sc, frame->mii_stdelim, 2); 43140516Swpaul rl_mii_send(sc, frame->mii_opcode, 2); 43240516Swpaul rl_mii_send(sc, frame->mii_phyaddr, 5); 43340516Swpaul rl_mii_send(sc, frame->mii_regaddr, 5); 43440516Swpaul 43540516Swpaul /* Idle bit */ 43640516Swpaul MII_CLR((RL_MII_CLK|RL_MII_DATAOUT)); 43740516Swpaul DELAY(1); 43840516Swpaul MII_SET(RL_MII_CLK); 43940516Swpaul DELAY(1); 44040516Swpaul 44140516Swpaul /* Turn off xmit. */ 44240516Swpaul MII_CLR(RL_MII_DIR); 44340516Swpaul 44440516Swpaul /* Check for ack */ 44540516Swpaul MII_CLR(RL_MII_CLK); 44640516Swpaul DELAY(1); 44740516Swpaul MII_SET(RL_MII_CLK); 44840516Swpaul DELAY(1); 44940516Swpaul ack = CSR_READ_2(sc, RL_MII) & RL_MII_DATAIN; 45040516Swpaul 45140516Swpaul /* 45240516Swpaul * Now try reading data bits. If the ack failed, we still 45340516Swpaul * need to clock through 16 cycles to keep the PHY(s) in sync. 45440516Swpaul */ 45540516Swpaul if (ack) { 45640516Swpaul for(i = 0; i < 16; i++) { 45740516Swpaul MII_CLR(RL_MII_CLK); 45840516Swpaul DELAY(1); 45940516Swpaul MII_SET(RL_MII_CLK); 46040516Swpaul DELAY(1); 46140516Swpaul } 46240516Swpaul goto fail; 46340516Swpaul } 46440516Swpaul 46540516Swpaul for (i = 0x8000; i; i >>= 1) { 46640516Swpaul MII_CLR(RL_MII_CLK); 46740516Swpaul DELAY(1); 46840516Swpaul if (!ack) { 46940516Swpaul if (CSR_READ_2(sc, RL_MII) & RL_MII_DATAIN) 47040516Swpaul frame->mii_data |= i; 47140516Swpaul DELAY(1); 47240516Swpaul } 47340516Swpaul MII_SET(RL_MII_CLK); 47440516Swpaul DELAY(1); 47540516Swpaul } 47640516Swpaul 47740516Swpaulfail: 47840516Swpaul 47940516Swpaul MII_CLR(RL_MII_CLK); 48040516Swpaul DELAY(1); 48140516Swpaul MII_SET(RL_MII_CLK); 48240516Swpaul DELAY(1); 48340516Swpaul 48440516Swpaul splx(s); 48540516Swpaul 48640516Swpaul if (ack) 48740516Swpaul return(1); 48840516Swpaul return(0); 48940516Swpaul} 49040516Swpaul 49140516Swpaul/* 49240516Swpaul * Write to a PHY register through the MII. 49340516Swpaul */ 49440516Swpaulstatic int rl_mii_writereg(sc, frame) 49540516Swpaul struct rl_softc *sc; 49640516Swpaul struct rl_mii_frame *frame; 49740516Swpaul 49840516Swpaul{ 49940516Swpaul int s; 50040516Swpaul 50140516Swpaul s = splimp(); 50240516Swpaul /* 50340516Swpaul * Set up frame for TX. 50440516Swpaul */ 50540516Swpaul 50640516Swpaul frame->mii_stdelim = RL_MII_STARTDELIM; 50740516Swpaul frame->mii_opcode = RL_MII_WRITEOP; 50840516Swpaul frame->mii_turnaround = RL_MII_TURNAROUND; 50940516Swpaul 51040516Swpaul /* 51140516Swpaul * Turn on data output. 51240516Swpaul */ 51340516Swpaul MII_SET(RL_MII_DIR); 51440516Swpaul 51540516Swpaul rl_mii_sync(sc); 51640516Swpaul 51740516Swpaul rl_mii_send(sc, frame->mii_stdelim, 2); 51840516Swpaul rl_mii_send(sc, frame->mii_opcode, 2); 51940516Swpaul rl_mii_send(sc, frame->mii_phyaddr, 5); 52040516Swpaul rl_mii_send(sc, frame->mii_regaddr, 5); 52140516Swpaul rl_mii_send(sc, frame->mii_turnaround, 2); 52240516Swpaul rl_mii_send(sc, frame->mii_data, 16); 52340516Swpaul 52440516Swpaul /* Idle bit. */ 52540516Swpaul MII_SET(RL_MII_CLK); 52640516Swpaul DELAY(1); 52740516Swpaul MII_CLR(RL_MII_CLK); 52840516Swpaul DELAY(1); 52940516Swpaul 53040516Swpaul /* 53140516Swpaul * Turn off xmit. 53240516Swpaul */ 53340516Swpaul MII_CLR(RL_MII_DIR); 53440516Swpaul 53540516Swpaul splx(s); 53640516Swpaul 53740516Swpaul return(0); 53840516Swpaul} 53940516Swpaul 54050703Swpaulstatic int rl_miibus_readreg(dev, phy, reg) 54150703Swpaul device_t dev; 54250703Swpaul int phy, reg; 54350703Swpaul{ 54440516Swpaul struct rl_softc *sc; 54540516Swpaul struct rl_mii_frame frame; 54640516Swpaul u_int16_t rval = 0; 54740516Swpaul u_int16_t rl8139_reg = 0; 54840516Swpaul 54950703Swpaul sc = device_get_softc(dev); 55050703Swpaul 55140516Swpaul if (sc->rl_type == RL_8139) { 55250703Swpaul /* Pretend the internal PHY is only at address 0 */ 55350703Swpaul if (phy) 55450703Swpaul return(0); 55540516Swpaul switch(reg) { 55650703Swpaul case MII_BMCR: 55740516Swpaul rl8139_reg = RL_BMCR; 55840516Swpaul break; 55950703Swpaul case MII_BMSR: 56040516Swpaul rl8139_reg = RL_BMSR; 56140516Swpaul break; 56250703Swpaul case MII_ANAR: 56340516Swpaul rl8139_reg = RL_ANAR; 56440516Swpaul break; 56550703Swpaul case MII_ANER: 56650703Swpaul rl8139_reg = RL_ANER; 56750703Swpaul break; 56850703Swpaul case MII_ANLPAR: 56940516Swpaul rl8139_reg = RL_LPAR; 57040516Swpaul break; 57150703Swpaul case MII_PHYIDR1: 57250703Swpaul case MII_PHYIDR2: 57350703Swpaul return(0); 57450703Swpaul break; 57540516Swpaul default: 57640516Swpaul printf("rl%d: bad phy register\n", sc->rl_unit); 57740516Swpaul return(0); 57840516Swpaul } 57940516Swpaul rval = CSR_READ_2(sc, rl8139_reg); 58040516Swpaul return(rval); 58140516Swpaul } 58240516Swpaul 58340516Swpaul bzero((char *)&frame, sizeof(frame)); 58440516Swpaul 58550703Swpaul frame.mii_phyaddr = phy; 58640516Swpaul frame.mii_regaddr = reg; 58740516Swpaul rl_mii_readreg(sc, &frame); 58840516Swpaul 58940516Swpaul return(frame.mii_data); 59040516Swpaul} 59140516Swpaul 59250703Swpaulstatic int rl_miibus_writereg(dev, phy, reg, data) 59350703Swpaul device_t dev; 59450703Swpaul int phy, reg, data; 59550703Swpaul{ 59640516Swpaul struct rl_softc *sc; 59740516Swpaul struct rl_mii_frame frame; 59840516Swpaul u_int16_t rl8139_reg = 0; 59940516Swpaul 60050703Swpaul sc = device_get_softc(dev); 60150703Swpaul 60240516Swpaul if (sc->rl_type == RL_8139) { 60350703Swpaul /* Pretend the internal PHY is only at address 0 */ 60450703Swpaul if (phy) 60550703Swpaul return(0); 60640516Swpaul switch(reg) { 60750703Swpaul case MII_BMCR: 60840516Swpaul rl8139_reg = RL_BMCR; 60940516Swpaul break; 61050703Swpaul case MII_BMSR: 61140516Swpaul rl8139_reg = RL_BMSR; 61240516Swpaul break; 61350703Swpaul case MII_ANAR: 61440516Swpaul rl8139_reg = RL_ANAR; 61540516Swpaul break; 61650703Swpaul case MII_ANER: 61750703Swpaul rl8139_reg = RL_ANER; 61850703Swpaul break; 61950703Swpaul case MII_ANLPAR: 62040516Swpaul rl8139_reg = RL_LPAR; 62140516Swpaul break; 62250703Swpaul case MII_PHYIDR1: 62350703Swpaul case MII_PHYIDR2: 62450703Swpaul return(0); 62550703Swpaul break; 62640516Swpaul default: 62740516Swpaul printf("rl%d: bad phy register\n", sc->rl_unit); 62850703Swpaul return(0); 62940516Swpaul } 63040516Swpaul CSR_WRITE_2(sc, rl8139_reg, data); 63150703Swpaul return(0); 63240516Swpaul } 63340516Swpaul 63440516Swpaul bzero((char *)&frame, sizeof(frame)); 63540516Swpaul 63650703Swpaul frame.mii_phyaddr = phy; 63740516Swpaul frame.mii_regaddr = reg; 63840516Swpaul frame.mii_data = data; 63940516Swpaul 64040516Swpaul rl_mii_writereg(sc, &frame); 64140516Swpaul 64250703Swpaul return(0); 64350703Swpaul} 64450703Swpaul 64550703Swpaulstatic void rl_miibus_statchg(dev) 64650703Swpaul device_t dev; 64750703Swpaul{ 64840516Swpaul return; 64940516Swpaul} 65040516Swpaul 65140516Swpaul/* 65243062Swpaul * Calculate CRC of a multicast group address, return the upper 6 bits. 65340516Swpaul */ 65440516Swpaulstatic u_int8_t rl_calchash(addr) 65541656Swpaul caddr_t addr; 65640516Swpaul{ 65740516Swpaul u_int32_t crc, carry; 65840516Swpaul int i, j; 65940516Swpaul u_int8_t c; 66040516Swpaul 66140516Swpaul /* Compute CRC for the address value. */ 66240516Swpaul crc = 0xFFFFFFFF; /* initial value */ 66340516Swpaul 66440516Swpaul for (i = 0; i < 6; i++) { 66540516Swpaul c = *(addr + i); 66640516Swpaul for (j = 0; j < 8; j++) { 66740516Swpaul carry = ((crc & 0x80000000) ? 1 : 0) ^ (c & 0x01); 66840516Swpaul crc <<= 1; 66940516Swpaul c >>= 1; 67040516Swpaul if (carry) 67140516Swpaul crc = (crc ^ 0x04c11db6) | carry; 67240516Swpaul } 67340516Swpaul } 67440516Swpaul 67540516Swpaul /* return the filter bit position */ 67643062Swpaul return(crc >> 26); 67740516Swpaul} 67840516Swpaul 67940516Swpaul/* 68040516Swpaul * Program the 64-bit multicast hash filter. 68140516Swpaul */ 68240516Swpaulstatic void rl_setmulti(sc) 68340516Swpaul struct rl_softc *sc; 68440516Swpaul{ 68540516Swpaul struct ifnet *ifp; 68640516Swpaul int h = 0; 68740516Swpaul u_int32_t hashes[2] = { 0, 0 }; 68840516Swpaul struct ifmultiaddr *ifma; 68940516Swpaul u_int32_t rxfilt; 69040516Swpaul int mcnt = 0; 69140516Swpaul 69240516Swpaul ifp = &sc->arpcom.ac_if; 69340516Swpaul 69440516Swpaul rxfilt = CSR_READ_4(sc, RL_RXCFG); 69540516Swpaul 69643062Swpaul if (ifp->if_flags & IFF_ALLMULTI || ifp->if_flags & IFF_PROMISC) { 69740516Swpaul rxfilt |= RL_RXCFG_RX_MULTI; 69840516Swpaul CSR_WRITE_4(sc, RL_RXCFG, rxfilt); 69940516Swpaul CSR_WRITE_4(sc, RL_MAR0, 0xFFFFFFFF); 70040516Swpaul CSR_WRITE_4(sc, RL_MAR4, 0xFFFFFFFF); 70140516Swpaul return; 70240516Swpaul } 70340516Swpaul 70440516Swpaul /* first, zot all the existing hash bits */ 70540516Swpaul CSR_WRITE_4(sc, RL_MAR0, 0); 70640516Swpaul CSR_WRITE_4(sc, RL_MAR4, 0); 70740516Swpaul 70840516Swpaul /* now program new ones */ 70940516Swpaul for (ifma = ifp->if_multiaddrs.lh_first; ifma != NULL; 71040516Swpaul ifma = ifma->ifma_link.le_next) { 71140516Swpaul if (ifma->ifma_addr->sa_family != AF_LINK) 71240516Swpaul continue; 71340516Swpaul h = rl_calchash(LLADDR((struct sockaddr_dl *)ifma->ifma_addr)); 71440516Swpaul if (h < 32) 71540516Swpaul hashes[0] |= (1 << h); 71640516Swpaul else 71740516Swpaul hashes[1] |= (1 << (h - 32)); 71840516Swpaul mcnt++; 71940516Swpaul } 72040516Swpaul 72140516Swpaul if (mcnt) 72240516Swpaul rxfilt |= RL_RXCFG_RX_MULTI; 72340516Swpaul else 72440516Swpaul rxfilt &= ~RL_RXCFG_RX_MULTI; 72540516Swpaul 72640516Swpaul CSR_WRITE_4(sc, RL_RXCFG, rxfilt); 72740516Swpaul CSR_WRITE_4(sc, RL_MAR0, hashes[0]); 72840516Swpaul CSR_WRITE_4(sc, RL_MAR4, hashes[1]); 72940516Swpaul 73040516Swpaul return; 73140516Swpaul} 73240516Swpaul 73340516Swpaulstatic void rl_reset(sc) 73440516Swpaul struct rl_softc *sc; 73540516Swpaul{ 73640516Swpaul register int i; 73740516Swpaul 73840516Swpaul CSR_WRITE_1(sc, RL_COMMAND, RL_CMD_RESET); 73940516Swpaul 74040516Swpaul for (i = 0; i < RL_TIMEOUT; i++) { 74140516Swpaul DELAY(10); 74240516Swpaul if (!(CSR_READ_1(sc, RL_COMMAND) & RL_CMD_RESET)) 74340516Swpaul break; 74440516Swpaul } 74540516Swpaul if (i == RL_TIMEOUT) 74640516Swpaul printf("rl%d: reset never completed!\n", sc->rl_unit); 74740516Swpaul 74840516Swpaul return; 74940516Swpaul} 75040516Swpaul 75140516Swpaul/* 75240516Swpaul * Probe for a RealTek 8129/8139 chip. Check the PCI vendor and device 75340516Swpaul * IDs against our list and return a device name if we find a match. 75440516Swpaul */ 75550703Swpaulstatic int rl_probe(dev) 75650703Swpaul device_t dev; 75740516Swpaul{ 75840516Swpaul struct rl_type *t; 75940516Swpaul 76040516Swpaul t = rl_devs; 76140516Swpaul 76240516Swpaul while(t->rl_name != NULL) { 76350703Swpaul if ((pci_get_vendor(dev) == t->rl_vid) && 76450703Swpaul (pci_get_device(dev) == t->rl_did)) { 76550703Swpaul device_set_desc(dev, t->rl_name); 76650703Swpaul return(0); 76740516Swpaul } 76840516Swpaul t++; 76940516Swpaul } 77040516Swpaul 77150703Swpaul return(ENXIO); 77240516Swpaul} 77340516Swpaul 77440516Swpaul/* 77540516Swpaul * Attach the interface. Allocate softc structures, do ifmedia 77640516Swpaul * setup and ethernet/BPF attach. 77740516Swpaul */ 77850703Swpaulstatic int rl_attach(dev) 77950703Swpaul device_t dev; 78040516Swpaul{ 78150703Swpaul int s; 78240516Swpaul u_char eaddr[ETHER_ADDR_LEN]; 78340516Swpaul u_int32_t command; 78440516Swpaul struct rl_softc *sc; 78540516Swpaul struct ifnet *ifp; 78640516Swpaul u_int16_t rl_did = 0; 78750703Swpaul int unit, error = 0, rid; 78840516Swpaul 78940516Swpaul s = splimp(); 79040516Swpaul 79150703Swpaul sc = device_get_softc(dev); 79250703Swpaul unit = device_get_unit(dev); 79340516Swpaul bzero(sc, sizeof(struct rl_softc)); 79440516Swpaul 79540516Swpaul /* 79640516Swpaul * Handle power management nonsense. 79740516Swpaul */ 79840516Swpaul 79950703Swpaul command = pci_read_config(dev, RL_PCI_CAPID, 4) & 0x000000FF; 80040516Swpaul if (command == 0x01) { 80140516Swpaul 80250703Swpaul command = pci_read_config(dev, RL_PCI_PWRMGMTCTRL, 4); 80340516Swpaul if (command & RL_PSTATE_MASK) { 80440516Swpaul u_int32_t iobase, membase, irq; 80540516Swpaul 80640516Swpaul /* Save important PCI config data. */ 80750703Swpaul iobase = pci_read_config(dev, RL_PCI_LOIO, 4); 80850703Swpaul membase = pci_read_config(dev, RL_PCI_LOMEM, 4); 80950703Swpaul irq = pci_read_config(dev, RL_PCI_INTLINE, 4); 81040516Swpaul 81140516Swpaul /* Reset the power state. */ 81240516Swpaul printf("rl%d: chip is is in D%d power mode " 81340516Swpaul "-- setting to D0\n", unit, command & RL_PSTATE_MASK); 81440516Swpaul command &= 0xFFFFFFFC; 81550703Swpaul pci_write_config(dev, RL_PCI_PWRMGMTCTRL, command, 4); 81640516Swpaul 81740516Swpaul /* Restore PCI config data. */ 81850703Swpaul pci_write_config(dev, RL_PCI_LOIO, iobase, 4); 81950703Swpaul pci_write_config(dev, RL_PCI_LOMEM, membase, 4); 82050703Swpaul pci_write_config(dev, RL_PCI_INTLINE, irq, 4); 82140516Swpaul } 82240516Swpaul } 82340516Swpaul 82440516Swpaul /* 82540516Swpaul * Map control/status registers. 82640516Swpaul */ 82750703Swpaul command = pci_read_config(dev, PCI_COMMAND_STATUS_REG, 4); 82840516Swpaul command |= (PCIM_CMD_PORTEN|PCIM_CMD_MEMEN|PCIM_CMD_BUSMASTEREN); 82950703Swpaul pci_write_config(dev, PCI_COMMAND_STATUS_REG, command, 4); 83050703Swpaul command = pci_read_config(dev, PCI_COMMAND_STATUS_REG, 4); 83140516Swpaul 83240516Swpaul#ifdef RL_USEIOSPACE 83340516Swpaul if (!(command & PCIM_CMD_PORTEN)) { 83440516Swpaul printf("rl%d: failed to enable I/O ports!\n", unit); 83550703Swpaul error = ENXIO; 83640516Swpaul goto fail; 83740516Swpaul } 83840516Swpaul#else 83940516Swpaul if (!(command & PCIM_CMD_MEMEN)) { 84040516Swpaul printf("rl%d: failed to enable memory mapping!\n", unit); 84150703Swpaul error = ENXIO; 84240516Swpaul goto fail; 84340516Swpaul } 84450703Swpaul#endif 84540516Swpaul 84650703Swpaul rid = RL_RID; 84750703Swpaul sc->rl_res = bus_alloc_resource(dev, RL_RES, &rid, 84850703Swpaul 0, ~0, 1, RF_ACTIVE); 84950703Swpaul 85050703Swpaul if (sc->rl_res == NULL) { 85150703Swpaul printf ("rl%d: couldn't map ports/memory\n", unit); 85250703Swpaul error = ENXIO; 85340516Swpaul goto fail; 85440516Swpaul } 85540516Swpaul 85650703Swpaul sc->rl_btag = rman_get_bustag(sc->rl_res); 85750703Swpaul sc->rl_bhandle = rman_get_bushandle(sc->rl_res); 85850703Swpaul 85950703Swpaul rid = 0; 86050703Swpaul sc->rl_irq = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, 0, ~0, 1, 86150703Swpaul RF_SHAREABLE | RF_ACTIVE); 86250703Swpaul 86350703Swpaul if (sc->rl_irq == NULL) { 86440516Swpaul printf("rl%d: couldn't map interrupt\n", unit); 86550703Swpaul bus_release_resource(dev, RL_RES, RL_RID, sc->rl_res); 86650703Swpaul error = ENXIO; 86740516Swpaul goto fail; 86840516Swpaul } 86940516Swpaul 87050703Swpaul error = bus_setup_intr(dev, sc->rl_irq, INTR_TYPE_NET, 87150703Swpaul rl_intr, sc, &sc->rl_intrhand); 87250703Swpaul 87350703Swpaul if (error) { 87450703Swpaul bus_release_resource(dev, SYS_RES_IRQ, 0, sc->rl_res); 87550703Swpaul bus_release_resource(dev, RL_RES, RL_RID, sc->rl_res); 87650703Swpaul printf("rl%d: couldn't set up irq\n", unit); 87750703Swpaul goto fail; 87850703Swpaul } 87950703Swpaul 88050703Swpaul callout_handle_init(&sc->rl_stat_ch); 88150703Swpaul 88240516Swpaul /* Reset the adapter. */ 88340516Swpaul rl_reset(sc); 88440516Swpaul 88540516Swpaul /* 88640516Swpaul * Get station address from the EEPROM. 88740516Swpaul */ 88840516Swpaul rl_read_eeprom(sc, (caddr_t)&eaddr, RL_EE_EADDR, 3, 0); 88940516Swpaul 89040516Swpaul /* 89140516Swpaul * A RealTek chip was detected. Inform the world. 89240516Swpaul */ 89340516Swpaul printf("rl%d: Ethernet address: %6D\n", unit, eaddr, ":"); 89440516Swpaul 89540516Swpaul sc->rl_unit = unit; 89640516Swpaul bcopy(eaddr, (char *)&sc->arpcom.ac_enaddr, ETHER_ADDR_LEN); 89740516Swpaul 89840516Swpaul /* 89940516Swpaul * Now read the exact device type from the EEPROM to find 90040516Swpaul * out if it's an 8129 or 8139. 90140516Swpaul */ 90240516Swpaul rl_read_eeprom(sc, (caddr_t)&rl_did, RL_EE_PCI_DID, 1, 0); 90340516Swpaul 90444238Swpaul if (rl_did == RT_DEVICEID_8139 || rl_did == ACCTON_DEVICEID_5030 || 90549001Swpaul rl_did == DELTA_DEVICEID_8139 || rl_did == ADDTRON_DEVICEID_8139) 90640516Swpaul sc->rl_type = RL_8139; 90740516Swpaul else if (rl_did == RT_DEVICEID_8129) 90840516Swpaul sc->rl_type = RL_8129; 90940516Swpaul else { 91040516Swpaul printf("rl%d: unknown device ID: %x\n", unit, rl_did); 91150703Swpaul bus_teardown_intr(dev, sc->rl_irq, sc->rl_intrhand); 91250703Swpaul bus_release_resource(dev, SYS_RES_IRQ, 0, sc->rl_res); 91350703Swpaul bus_release_resource(dev, RL_RES, RL_RID, sc->rl_res); 91450703Swpaul error = ENXIO; 91540516Swpaul goto fail; 91640516Swpaul } 91740516Swpaul 91848028Swpaul sc->rl_cdata.rl_rx_buf = contigmalloc(RL_RXBUFLEN + 32, M_DEVBUF, 91950703Swpaul M_NOWAIT, 0x100000, 0xffffffff, PAGE_SIZE, 0); 92040516Swpaul 92140516Swpaul if (sc->rl_cdata.rl_rx_buf == NULL) { 92240516Swpaul printf("rl%d: no memory for list buffers!\n", unit); 92350703Swpaul bus_teardown_intr(dev, sc->rl_irq, sc->rl_intrhand); 92450703Swpaul bus_release_resource(dev, SYS_RES_IRQ, 0, sc->rl_res); 92550703Swpaul bus_release_resource(dev, RL_RES, RL_RID, sc->rl_res); 92650703Swpaul error = ENXIO; 92740516Swpaul goto fail; 92840516Swpaul } 92940516Swpaul 93048028Swpaul /* Leave a few bytes before the start of the RX ring buffer. */ 93148028Swpaul sc->rl_cdata.rl_rx_buf_ptr = sc->rl_cdata.rl_rx_buf; 93248028Swpaul sc->rl_cdata.rl_rx_buf += sizeof(u_int64_t); 93348028Swpaul 93450703Swpaul /* Do MII setup */ 93550703Swpaul if (mii_phy_probe(dev, &sc->rl_miibus, 93650703Swpaul rl_ifmedia_upd, rl_ifmedia_sts)) { 93750703Swpaul printf("rl%d: MII without any phy!\n", sc->rl_unit); 93850703Swpaul bus_teardown_intr(dev, sc->rl_irq, sc->rl_intrhand); 93950703Swpaul bus_release_resource(dev, SYS_RES_IRQ, 0, sc->rl_res); 94050703Swpaul bus_release_resource(dev, RL_RES, RL_RID, sc->rl_res); 94150703Swpaul free(sc->rl_cdata.rl_rx_buf, M_DEVBUF); 94250703Swpaul error = ENXIO; 94350703Swpaul goto fail; 94450703Swpaul } 94550703Swpaul 94640516Swpaul ifp = &sc->arpcom.ac_if; 94740516Swpaul ifp->if_softc = sc; 94840516Swpaul ifp->if_unit = unit; 94940516Swpaul ifp->if_name = "rl"; 95040516Swpaul ifp->if_mtu = ETHERMTU; 95140516Swpaul ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 95240516Swpaul ifp->if_ioctl = rl_ioctl; 95340516Swpaul ifp->if_output = ether_output; 95440516Swpaul ifp->if_start = rl_start; 95540516Swpaul ifp->if_watchdog = rl_watchdog; 95640516Swpaul ifp->if_init = rl_init; 95740516Swpaul ifp->if_baudrate = 10000000; 95845633Swpaul ifp->if_snd.ifq_maxlen = IFQ_MAXLEN; 95940516Swpaul 96040516Swpaul /* 96140516Swpaul * Call MI attach routines. 96240516Swpaul */ 96340516Swpaul if_attach(ifp); 96440516Swpaul ether_ifattach(ifp); 96540516Swpaul 96648645Sdes#if NBPF > 0 96740516Swpaul bpfattach(ifp, DLT_EN10MB, sizeof(struct ether_header)); 96840516Swpaul#endif 96940516Swpaul 97040516Swpaulfail: 97140516Swpaul splx(s); 97250703Swpaul return(error); 97340516Swpaul} 97440516Swpaul 97550703Swpaulstatic int rl_detach(dev) 97650703Swpaul device_t dev; 97750703Swpaul{ 97850703Swpaul struct rl_softc *sc; 97950703Swpaul struct ifnet *ifp; 98050703Swpaul int s; 98150703Swpaul 98250703Swpaul s = splimp(); 98350703Swpaul 98450703Swpaul sc = device_get_softc(dev); 98550703Swpaul ifp = &sc->arpcom.ac_if; 98650703Swpaul 98750703Swpaul if_detach(ifp); 98850703Swpaul rl_stop(sc); 98950703Swpaul 99050703Swpaul bus_generic_detach(dev); 99150703Swpaul device_delete_child(dev, sc->rl_miibus); 99250703Swpaul 99350703Swpaul bus_teardown_intr(dev, sc->rl_irq, sc->rl_intrhand); 99450703Swpaul bus_release_resource(dev, SYS_RES_IRQ, 0, sc->rl_res); 99550703Swpaul bus_release_resource(dev, RL_RES, RL_RID, sc->rl_res); 99650703Swpaul 99750703Swpaul free(sc->rl_cdata.rl_rx_buf, M_DEVBUF); 99850703Swpaul 99950703Swpaul splx(s); 100050703Swpaul 100150703Swpaul return(0); 100250703Swpaul} 100350703Swpaul 100440516Swpaul/* 100540516Swpaul * Initialize the transmit descriptors. 100640516Swpaul */ 100740516Swpaulstatic int rl_list_tx_init(sc) 100840516Swpaul struct rl_softc *sc; 100940516Swpaul{ 101040516Swpaul struct rl_chain_data *cd; 101140516Swpaul int i; 101240516Swpaul 101340516Swpaul cd = &sc->rl_cdata; 101440516Swpaul for (i = 0; i < RL_TX_LIST_CNT; i++) { 101545633Swpaul cd->rl_tx_chain[i] = NULL; 101648028Swpaul CSR_WRITE_4(sc, 101748028Swpaul RL_TXADDR0 + (i * sizeof(u_int32_t)), 0x0000000); 101840516Swpaul } 101940516Swpaul 102045633Swpaul sc->rl_cdata.cur_tx = 0; 102145633Swpaul sc->rl_cdata.last_tx = 0; 102240516Swpaul 102340516Swpaul return(0); 102440516Swpaul} 102540516Swpaul 102640516Swpaul/* 102740516Swpaul * A frame has been uploaded: pass the resulting mbuf chain up to 102840516Swpaul * the higher level protocols. 102940516Swpaul * 103040516Swpaul * You know there's something wrong with a PCI bus-master chip design 103140516Swpaul * when you have to use m_devget(). 103240516Swpaul * 103340516Swpaul * The receive operation is badly documented in the datasheet, so I'll 103440516Swpaul * attempt to document it here. The driver provides a buffer area and 103540516Swpaul * places its base address in the RX buffer start address register. 103640516Swpaul * The chip then begins copying frames into the RX buffer. Each frame 103740516Swpaul * is preceeded by a 32-bit RX status word which specifies the length 103840516Swpaul * of the frame and certain other status bits. Each frame (starting with 103940516Swpaul * the status word) is also 32-bit aligned. The frame length is in the 104040516Swpaul * first 16 bits of the status word; the lower 15 bits correspond with 104140516Swpaul * the 'rx status register' mentioned in the datasheet. 104248028Swpaul * 104348028Swpaul * Note: to make the Alpha happy, the frame payload needs to be aligned 104448028Swpaul * on a 32-bit boundary. To achieve this, we cheat a bit by copying from 104548028Swpaul * the ring buffer starting at an address two bytes before the actual 104648028Swpaul * data location. We can then shave off the first two bytes using m_adj(). 104748028Swpaul * The reason we do this is because m_devget() doesn't let us specify an 104848028Swpaul * offset into the mbuf storage space, so we have to artificially create 104948028Swpaul * one. The ring is allocated in such a way that there are a few unused 105048028Swpaul * bytes of space preceecing it so that it will be safe for us to do the 105148028Swpaul * 2-byte backstep even if reading from the ring at offset 0. 105240516Swpaul */ 105340516Swpaulstatic void rl_rxeof(sc) 105440516Swpaul struct rl_softc *sc; 105540516Swpaul{ 105640516Swpaul struct ether_header *eh; 105740516Swpaul struct mbuf *m; 105840516Swpaul struct ifnet *ifp; 105940516Swpaul int total_len = 0; 106040516Swpaul u_int32_t rxstat; 106140516Swpaul caddr_t rxbufpos; 106240516Swpaul int wrap = 0; 106340516Swpaul u_int16_t cur_rx; 106440516Swpaul u_int16_t limit; 106540516Swpaul u_int16_t rx_bytes = 0, max_bytes; 106640516Swpaul 106740516Swpaul ifp = &sc->arpcom.ac_if; 106840516Swpaul 106940516Swpaul cur_rx = (CSR_READ_2(sc, RL_CURRXADDR) + 16) % RL_RXBUFLEN; 107040516Swpaul 107140516Swpaul /* Do not try to read past this point. */ 107240516Swpaul limit = CSR_READ_2(sc, RL_CURRXBUF) % RL_RXBUFLEN; 107340516Swpaul 107440516Swpaul if (limit < cur_rx) 107540516Swpaul max_bytes = (RL_RXBUFLEN - cur_rx) + limit; 107640516Swpaul else 107740516Swpaul max_bytes = limit - cur_rx; 107840516Swpaul 107942738Swpaul while((CSR_READ_1(sc, RL_COMMAND) & RL_CMD_EMPTY_RXBUF) == 0) { 108040516Swpaul rxbufpos = sc->rl_cdata.rl_rx_buf + cur_rx; 108140516Swpaul rxstat = *(u_int32_t *)rxbufpos; 108240516Swpaul 108340516Swpaul /* 108440516Swpaul * Here's a totally undocumented fact for you. When the 108540516Swpaul * RealTek chip is in the process of copying a packet into 108640516Swpaul * RAM for you, the length will be 0xfff0. If you spot a 108740516Swpaul * packet header with this value, you need to stop. The 108840516Swpaul * datasheet makes absolutely no mention of this and 108940516Swpaul * RealTek should be shot for this. 109040516Swpaul */ 109140516Swpaul if ((u_int16_t)(rxstat >> 16) == RL_RXSTAT_UNFINISHED) 109240516Swpaul break; 109340516Swpaul 109440516Swpaul if (!(rxstat & RL_RXSTAT_RXOK)) { 109540516Swpaul ifp->if_ierrors++; 109650703Swpaul rl_init(sc); 109750703Swpaul return; 109840516Swpaul } 109940516Swpaul 110040516Swpaul /* No errors; receive the packet. */ 110140516Swpaul total_len = rxstat >> 16; 110240516Swpaul rx_bytes += total_len + 4; 110340516Swpaul 110440516Swpaul /* 110542051Swpaul * XXX The RealTek chip includes the CRC with every 110642051Swpaul * received frame, and there's no way to turn this 110742051Swpaul * behavior off (at least, I can't find anything in 110842051Swpaul * the manual that explains how to do it) so we have 110942051Swpaul * to trim off the CRC manually. 111042051Swpaul */ 111142051Swpaul total_len -= ETHER_CRC_LEN; 111242051Swpaul 111342051Swpaul /* 111440516Swpaul * Avoid trying to read more bytes than we know 111540516Swpaul * the chip has prepared for us. 111640516Swpaul */ 111740516Swpaul if (rx_bytes > max_bytes) 111840516Swpaul break; 111940516Swpaul 112040516Swpaul rxbufpos = sc->rl_cdata.rl_rx_buf + 112140516Swpaul ((cur_rx + sizeof(u_int32_t)) % RL_RXBUFLEN); 112240516Swpaul 112340516Swpaul if (rxbufpos == (sc->rl_cdata.rl_rx_buf + RL_RXBUFLEN)) 112440516Swpaul rxbufpos = sc->rl_cdata.rl_rx_buf; 112540516Swpaul 112640516Swpaul wrap = (sc->rl_cdata.rl_rx_buf + RL_RXBUFLEN) - rxbufpos; 112740516Swpaul 112840516Swpaul if (total_len > wrap) { 112948028Swpaul m = m_devget(rxbufpos - RL_ETHER_ALIGN, 113048028Swpaul wrap + RL_ETHER_ALIGN, 0, ifp, NULL); 113140516Swpaul if (m == NULL) { 113240516Swpaul ifp->if_ierrors++; 113340516Swpaul printf("rl%d: out of mbufs, tried to " 113440516Swpaul "copy %d bytes\n", sc->rl_unit, wrap); 113540516Swpaul } 113648028Swpaul else { 113748028Swpaul m_adj(m, RL_ETHER_ALIGN); 113840516Swpaul m_copyback(m, wrap, total_len - wrap, 113940516Swpaul sc->rl_cdata.rl_rx_buf); 114048028Swpaul } 114142051Swpaul cur_rx = (total_len - wrap + ETHER_CRC_LEN); 114240516Swpaul } else { 114348028Swpaul m = m_devget(rxbufpos - RL_ETHER_ALIGN, 114448028Swpaul total_len + RL_ETHER_ALIGN, 0, ifp, NULL); 114540516Swpaul if (m == NULL) { 114640516Swpaul ifp->if_ierrors++; 114740516Swpaul printf("rl%d: out of mbufs, tried to " 114840516Swpaul "copy %d bytes\n", sc->rl_unit, total_len); 114948028Swpaul } else 115048028Swpaul m_adj(m, RL_ETHER_ALIGN); 115142051Swpaul cur_rx += total_len + 4 + ETHER_CRC_LEN; 115240516Swpaul } 115340516Swpaul 115440516Swpaul /* 115540516Swpaul * Round up to 32-bit boundary. 115640516Swpaul */ 115740516Swpaul cur_rx = (cur_rx + 3) & ~3; 115840516Swpaul CSR_WRITE_2(sc, RL_CURRXADDR, cur_rx - 16); 115940516Swpaul 116040516Swpaul if (m == NULL) 116140516Swpaul continue; 116240516Swpaul 116340516Swpaul eh = mtod(m, struct ether_header *); 116440516Swpaul ifp->if_ipackets++; 116540516Swpaul 116648645Sdes#if NBPF > 0 116740516Swpaul /* 116840516Swpaul * Handle BPF listeners. Let the BPF user see the packet, but 116940516Swpaul * don't pass it up to the ether_input() layer unless it's 117040516Swpaul * a broadcast packet, multicast packet, matches our ethernet 117140516Swpaul * address or the interface is in promiscuous mode. 117240516Swpaul */ 117340516Swpaul if (ifp->if_bpf) { 117440516Swpaul bpf_mtap(ifp, m); 117540516Swpaul if (ifp->if_flags & IFF_PROMISC && 117640516Swpaul (bcmp(eh->ether_dhost, sc->arpcom.ac_enaddr, 117740516Swpaul ETHER_ADDR_LEN) && 117840516Swpaul (eh->ether_dhost[0] & 1) == 0)) { 117940516Swpaul m_freem(m); 118040516Swpaul continue; 118140516Swpaul } 118240516Swpaul } 118340516Swpaul#endif 118440516Swpaul /* Remove header from mbuf and pass it on. */ 118540516Swpaul m_adj(m, sizeof(struct ether_header)); 118640516Swpaul ether_input(ifp, eh, m); 118740516Swpaul } 118840516Swpaul 118940516Swpaul return; 119040516Swpaul} 119140516Swpaul 119240516Swpaul/* 119340516Swpaul * A frame was downloaded to the chip. It's safe for us to clean up 119440516Swpaul * the list buffers. 119540516Swpaul */ 119640516Swpaulstatic void rl_txeof(sc) 119740516Swpaul struct rl_softc *sc; 119840516Swpaul{ 119940516Swpaul struct ifnet *ifp; 120040516Swpaul u_int32_t txstat; 120140516Swpaul 120240516Swpaul ifp = &sc->arpcom.ac_if; 120340516Swpaul 120440516Swpaul /* Clear the timeout timer. */ 120540516Swpaul ifp->if_timer = 0; 120640516Swpaul 120740516Swpaul /* 120840516Swpaul * Go through our tx list and free mbufs for those 120940516Swpaul * frames that have been uploaded. 121040516Swpaul */ 121145633Swpaul do { 121245633Swpaul txstat = CSR_READ_4(sc, RL_LAST_TXSTAT(sc)); 121345633Swpaul if (!(txstat & (RL_TXSTAT_TX_OK| 121445633Swpaul RL_TXSTAT_TX_UNDERRUN|RL_TXSTAT_TXABRT))) 121540516Swpaul break; 121640516Swpaul 121745633Swpaul ifp->if_collisions += (txstat & RL_TXSTAT_COLLCNT) >> 24; 121840516Swpaul 121945633Swpaul if (RL_LAST_TXMBUF(sc) != NULL) { 122045633Swpaul m_freem(RL_LAST_TXMBUF(sc)); 122145633Swpaul RL_LAST_TXMBUF(sc) = NULL; 122245633Swpaul } 122345633Swpaul if (txstat & RL_TXSTAT_TX_OK) 122445633Swpaul ifp->if_opackets++; 122545633Swpaul else { 122645633Swpaul ifp->if_oerrors++; 122745633Swpaul if ((txstat & RL_TXSTAT_TXABRT) || 122845633Swpaul (txstat & RL_TXSTAT_OUTOFWIN)) 122945633Swpaul CSR_WRITE_4(sc, RL_TXCFG, RL_TXCFG_CONFIG); 123045633Swpaul } 123145633Swpaul RL_INC(sc->rl_cdata.last_tx); 123245633Swpaul ifp->if_flags &= ~IFF_OACTIVE; 123345633Swpaul } while (sc->rl_cdata.last_tx != sc->rl_cdata.cur_tx); 123440516Swpaul 123550703Swpaul return; 123650703Swpaul} 123740516Swpaul 123850703Swpaulstatic void rl_tick(xsc) 123950703Swpaul void *xsc; 124050703Swpaul{ 124150703Swpaul struct rl_softc *sc; 124250703Swpaul struct mii_data *mii; 124350703Swpaul int s; 124450703Swpaul 124550703Swpaul s = splimp(); 124650703Swpaul 124750703Swpaul sc = xsc; 124850703Swpaul mii = device_get_softc(sc->rl_miibus); 124950703Swpaul 125050703Swpaul mii_tick(mii); 125150703Swpaul 125250703Swpaul splx(s); 125350703Swpaul 125450703Swpaul sc->rl_stat_ch = timeout(rl_tick, sc, hz); 125550703Swpaul 125640516Swpaul return; 125740516Swpaul} 125840516Swpaul 125940516Swpaulstatic void rl_intr(arg) 126040516Swpaul void *arg; 126140516Swpaul{ 126240516Swpaul struct rl_softc *sc; 126340516Swpaul struct ifnet *ifp; 126440516Swpaul u_int16_t status; 126540516Swpaul 126640516Swpaul sc = arg; 126740516Swpaul ifp = &sc->arpcom.ac_if; 126840516Swpaul 126940516Swpaul /* Disable interrupts. */ 127040516Swpaul CSR_WRITE_2(sc, RL_IMR, 0x0000); 127140516Swpaul 127240516Swpaul for (;;) { 127340516Swpaul 127440516Swpaul status = CSR_READ_2(sc, RL_ISR); 127540516Swpaul if (status) 127640516Swpaul CSR_WRITE_2(sc, RL_ISR, status); 127740516Swpaul 127840516Swpaul if ((status & RL_INTRS) == 0) 127940516Swpaul break; 128040516Swpaul 128140516Swpaul if (status & RL_ISR_RX_OK) 128240516Swpaul rl_rxeof(sc); 128340516Swpaul 128440516Swpaul if (status & RL_ISR_RX_ERR) 128540516Swpaul rl_rxeof(sc); 128640516Swpaul 128745633Swpaul if ((status & RL_ISR_TX_OK) || (status & RL_ISR_TX_ERR)) 128840516Swpaul rl_txeof(sc); 128940516Swpaul 129040516Swpaul if (status & RL_ISR_SYSTEM_ERR) { 129140516Swpaul rl_reset(sc); 129240516Swpaul rl_init(sc); 129340516Swpaul } 129440516Swpaul 129540516Swpaul } 129640516Swpaul 129740516Swpaul /* Re-enable interrupts. */ 129840516Swpaul CSR_WRITE_2(sc, RL_IMR, RL_INTRS); 129940516Swpaul 130040516Swpaul if (ifp->if_snd.ifq_head != NULL) { 130140516Swpaul rl_start(ifp); 130240516Swpaul } 130340516Swpaul 130440516Swpaul return; 130540516Swpaul} 130640516Swpaul 130740516Swpaul/* 130840516Swpaul * Encapsulate an mbuf chain in a descriptor by coupling the mbuf data 130940516Swpaul * pointers to the fragment pointers. 131040516Swpaul */ 131145633Swpaulstatic int rl_encap(sc, m_head) 131240516Swpaul struct rl_softc *sc; 131340516Swpaul struct mbuf *m_head; 131440516Swpaul{ 131541243Swpaul struct mbuf *m_new = NULL; 131640516Swpaul 131740516Swpaul /* 131845633Swpaul * The RealTek is brain damaged and wants longword-aligned 131945633Swpaul * TX buffers, plus we can only have one fragment buffer 132045633Swpaul * per packet. We have to copy pretty much all the time. 132140516Swpaul */ 132240516Swpaul 132341243Swpaul MGETHDR(m_new, M_DONTWAIT, MT_DATA); 132441243Swpaul if (m_new == NULL) { 132541243Swpaul printf("rl%d: no memory for tx list", sc->rl_unit); 132641243Swpaul return(1); 132741243Swpaul } 132841243Swpaul if (m_head->m_pkthdr.len > MHLEN) { 132941243Swpaul MCLGET(m_new, M_DONTWAIT); 133041243Swpaul if (!(m_new->m_flags & M_EXT)) { 133141243Swpaul m_freem(m_new); 133241243Swpaul printf("rl%d: no memory for tx list", 133341243Swpaul sc->rl_unit); 133440516Swpaul return(1); 133540516Swpaul } 133640516Swpaul } 133741243Swpaul m_copydata(m_head, 0, m_head->m_pkthdr.len, 133841243Swpaul mtod(m_new, caddr_t)); 133941243Swpaul m_new->m_pkthdr.len = m_new->m_len = m_head->m_pkthdr.len; 134041243Swpaul m_freem(m_head); 134141243Swpaul m_head = m_new; 134240516Swpaul 134340516Swpaul /* Pad frames to at least 60 bytes. */ 134441243Swpaul if (m_head->m_pkthdr.len < RL_MIN_FRAMELEN) { 134540516Swpaul m_head->m_pkthdr.len += 134640516Swpaul (RL_MIN_FRAMELEN - m_head->m_pkthdr.len); 134741243Swpaul m_head->m_len = m_head->m_pkthdr.len; 134841243Swpaul } 134940516Swpaul 135045633Swpaul RL_CUR_TXMBUF(sc) = m_head; 135140516Swpaul 135240516Swpaul return(0); 135340516Swpaul} 135440516Swpaul 135540516Swpaul/* 135640516Swpaul * Main transmit routine. 135740516Swpaul */ 135840516Swpaul 135940516Swpaulstatic void rl_start(ifp) 136040516Swpaul struct ifnet *ifp; 136140516Swpaul{ 136240516Swpaul struct rl_softc *sc; 136340516Swpaul struct mbuf *m_head = NULL; 136440516Swpaul 136540516Swpaul sc = ifp->if_softc; 136640516Swpaul 136745633Swpaul while(RL_CUR_TXMBUF(sc) == NULL) { 136840516Swpaul IF_DEQUEUE(&ifp->if_snd, m_head); 136940516Swpaul if (m_head == NULL) 137040516Swpaul break; 137140516Swpaul 137245633Swpaul rl_encap(sc, m_head); 137340516Swpaul 137448645Sdes#if NBPF > 0 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)); 138140516Swpaul#endif 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), 138845633Swpaul RL_TX_EARLYTHRESH | RL_CUR_TXMBUF(sc)->m_pkthdr.len); 138945633Swpaul 139045633Swpaul RL_INC(sc->rl_cdata.cur_tx); 139140516Swpaul } 139240516Swpaul 139340516Swpaul /* 139445633Swpaul * We broke out of the loop because all our TX slots are 139545633Swpaul * full. Mark the NIC as busy until it drains some of the 139645633Swpaul * packets from the queue. 139745633Swpaul */ 139845633Swpaul if (RL_CUR_TXMBUF(sc) != NULL) 139945633Swpaul ifp->if_flags |= IFF_OACTIVE; 140045633Swpaul 140145633Swpaul /* 140240516Swpaul * Set a timeout in case the chip goes out to lunch. 140340516Swpaul */ 140440516Swpaul ifp->if_timer = 5; 140540516Swpaul 140640516Swpaul return; 140740516Swpaul} 140840516Swpaul 140940516Swpaulstatic void rl_init(xsc) 141040516Swpaul void *xsc; 141140516Swpaul{ 141240516Swpaul struct rl_softc *sc = xsc; 141340516Swpaul struct ifnet *ifp = &sc->arpcom.ac_if; 141450703Swpaul struct mii_data *mii; 141540516Swpaul int s, i; 141640516Swpaul u_int32_t rxcfg = 0; 141740516Swpaul 141840516Swpaul s = splimp(); 141940516Swpaul 142050703Swpaul mii = device_get_softc(sc->rl_miibus); 142140516Swpaul 142240516Swpaul /* 142340516Swpaul * Cancel pending I/O and free all RX/TX buffers. 142440516Swpaul */ 142540516Swpaul rl_stop(sc); 142640516Swpaul 142740516Swpaul /* Init our MAC address */ 142840516Swpaul for (i = 0; i < ETHER_ADDR_LEN; i++) { 142940516Swpaul CSR_WRITE_1(sc, RL_IDR0 + i, sc->arpcom.ac_enaddr[i]); 143040516Swpaul } 143140516Swpaul 143240516Swpaul /* Init the RX buffer pointer register. */ 143340516Swpaul CSR_WRITE_4(sc, RL_RXADDR, vtophys(sc->rl_cdata.rl_rx_buf)); 143440516Swpaul 143540516Swpaul /* Init TX descriptors. */ 143640516Swpaul rl_list_tx_init(sc); 143740516Swpaul 143840516Swpaul /* 143940516Swpaul * Enable transmit and receive. 144040516Swpaul */ 144140516Swpaul CSR_WRITE_1(sc, RL_COMMAND, RL_CMD_TX_ENB|RL_CMD_RX_ENB); 144240516Swpaul 144340516Swpaul /* 144445633Swpaul * Set the initial TX and RX configuration. 144540516Swpaul */ 144645633Swpaul CSR_WRITE_4(sc, RL_TXCFG, RL_TXCFG_CONFIG); 144740516Swpaul CSR_WRITE_4(sc, RL_RXCFG, RL_RXCFG_CONFIG); 144840516Swpaul 144940516Swpaul /* Set the individual bit to receive frames for this host only. */ 145040516Swpaul rxcfg = CSR_READ_4(sc, RL_RXCFG); 145140516Swpaul rxcfg |= RL_RXCFG_RX_INDIV; 145240516Swpaul 145340516Swpaul /* If we want promiscuous mode, set the allframes bit. */ 145440516Swpaul if (ifp->if_flags & IFF_PROMISC) { 145540516Swpaul rxcfg |= RL_RXCFG_RX_ALLPHYS; 145640516Swpaul CSR_WRITE_4(sc, RL_RXCFG, rxcfg); 145740516Swpaul } else { 145840516Swpaul rxcfg &= ~RL_RXCFG_RX_ALLPHYS; 145940516Swpaul CSR_WRITE_4(sc, RL_RXCFG, rxcfg); 146040516Swpaul } 146140516Swpaul 146240516Swpaul /* 146340516Swpaul * Set capture broadcast bit to capture broadcast frames. 146440516Swpaul */ 146540516Swpaul if (ifp->if_flags & IFF_BROADCAST) { 146640516Swpaul rxcfg |= RL_RXCFG_RX_BROAD; 146740516Swpaul CSR_WRITE_4(sc, RL_RXCFG, rxcfg); 146840516Swpaul } else { 146940516Swpaul rxcfg &= ~RL_RXCFG_RX_BROAD; 147040516Swpaul CSR_WRITE_4(sc, RL_RXCFG, rxcfg); 147140516Swpaul } 147240516Swpaul 147340516Swpaul /* 147440516Swpaul * Program the multicast filter, if necessary. 147540516Swpaul */ 147640516Swpaul rl_setmulti(sc); 147740516Swpaul 147840516Swpaul /* 147940516Swpaul * Enable interrupts. 148040516Swpaul */ 148140516Swpaul CSR_WRITE_2(sc, RL_IMR, RL_INTRS); 148240516Swpaul 148340516Swpaul /* Start RX/TX process. */ 148440516Swpaul CSR_WRITE_4(sc, RL_MISSEDPKT, 0); 148540516Swpaul 148640516Swpaul /* Enable receiver and transmitter. */ 148740516Swpaul CSR_WRITE_1(sc, RL_COMMAND, RL_CMD_TX_ENB|RL_CMD_RX_ENB); 148840516Swpaul 148950703Swpaul mii_mediachg(mii); 149040516Swpaul 149140516Swpaul CSR_WRITE_1(sc, RL_CFG1, RL_CFG1_DRVLOAD|RL_CFG1_FULLDUPLEX); 149240516Swpaul 149340516Swpaul ifp->if_flags |= IFF_RUNNING; 149440516Swpaul ifp->if_flags &= ~IFF_OACTIVE; 149540516Swpaul 149640516Swpaul (void)splx(s); 149740516Swpaul 149850703Swpaul sc->rl_stat_ch = timeout(rl_tick, sc, hz); 149950703Swpaul 150040516Swpaul return; 150140516Swpaul} 150240516Swpaul 150340516Swpaul/* 150440516Swpaul * Set media options. 150540516Swpaul */ 150640516Swpaulstatic int rl_ifmedia_upd(ifp) 150740516Swpaul struct ifnet *ifp; 150840516Swpaul{ 150940516Swpaul struct rl_softc *sc; 151050703Swpaul struct mii_data *mii; 151140516Swpaul 151240516Swpaul sc = ifp->if_softc; 151350703Swpaul mii = device_get_softc(sc->rl_miibus); 151450703Swpaul mii_mediachg(mii); 151540516Swpaul 151640516Swpaul return(0); 151740516Swpaul} 151840516Swpaul 151940516Swpaul/* 152040516Swpaul * Report current media status. 152140516Swpaul */ 152240516Swpaulstatic void rl_ifmedia_sts(ifp, ifmr) 152340516Swpaul struct ifnet *ifp; 152440516Swpaul struct ifmediareq *ifmr; 152540516Swpaul{ 152640516Swpaul struct rl_softc *sc; 152750703Swpaul struct mii_data *mii; 152840516Swpaul 152940516Swpaul sc = ifp->if_softc; 153050703Swpaul mii = device_get_softc(sc->rl_miibus); 153140516Swpaul 153250703Swpaul mii_pollstat(mii); 153350703Swpaul ifmr->ifm_active = mii->mii_media_active; 153450703Swpaul ifmr->ifm_status = mii->mii_media_status; 153540516Swpaul 153640516Swpaul return; 153740516Swpaul} 153840516Swpaul 153940516Swpaulstatic int rl_ioctl(ifp, command, data) 154040516Swpaul struct ifnet *ifp; 154140516Swpaul u_long command; 154240516Swpaul caddr_t data; 154340516Swpaul{ 154440516Swpaul struct rl_softc *sc = ifp->if_softc; 154540516Swpaul struct ifreq *ifr = (struct ifreq *) data; 154650703Swpaul struct mii_data *mii; 154740516Swpaul int s, error = 0; 154840516Swpaul 154940516Swpaul s = splimp(); 155040516Swpaul 155140516Swpaul switch(command) { 155240516Swpaul case SIOCSIFADDR: 155340516Swpaul case SIOCGIFADDR: 155440516Swpaul case SIOCSIFMTU: 155540516Swpaul error = ether_ioctl(ifp, command, data); 155640516Swpaul break; 155740516Swpaul case SIOCSIFFLAGS: 155840516Swpaul if (ifp->if_flags & IFF_UP) { 155940516Swpaul rl_init(sc); 156040516Swpaul } else { 156140516Swpaul if (ifp->if_flags & IFF_RUNNING) 156240516Swpaul rl_stop(sc); 156340516Swpaul } 156440516Swpaul error = 0; 156540516Swpaul break; 156640516Swpaul case SIOCADDMULTI: 156740516Swpaul case SIOCDELMULTI: 156840516Swpaul rl_setmulti(sc); 156940516Swpaul error = 0; 157040516Swpaul break; 157140516Swpaul case SIOCGIFMEDIA: 157240516Swpaul case SIOCSIFMEDIA: 157350703Swpaul mii = device_get_softc(sc->rl_miibus); 157450703Swpaul error = ifmedia_ioctl(ifp, ifr, &mii->mii_media, command); 157540516Swpaul break; 157640516Swpaul default: 157740516Swpaul error = EINVAL; 157840516Swpaul break; 157940516Swpaul } 158040516Swpaul 158140516Swpaul (void)splx(s); 158240516Swpaul 158340516Swpaul return(error); 158440516Swpaul} 158540516Swpaul 158640516Swpaulstatic void rl_watchdog(ifp) 158740516Swpaul struct ifnet *ifp; 158840516Swpaul{ 158940516Swpaul struct rl_softc *sc; 159040516Swpaul 159140516Swpaul sc = ifp->if_softc; 159240516Swpaul 159340516Swpaul printf("rl%d: watchdog timeout\n", sc->rl_unit); 159440516Swpaul ifp->if_oerrors++; 159550703Swpaul 159640516Swpaul rl_txeof(sc); 159740516Swpaul rl_rxeof(sc); 159840516Swpaul rl_init(sc); 159940516Swpaul 160040516Swpaul return; 160140516Swpaul} 160240516Swpaul 160340516Swpaul/* 160440516Swpaul * Stop the adapter and free any mbufs allocated to the 160540516Swpaul * RX and TX lists. 160640516Swpaul */ 160740516Swpaulstatic void rl_stop(sc) 160840516Swpaul struct rl_softc *sc; 160940516Swpaul{ 161040516Swpaul register int i; 161140516Swpaul struct ifnet *ifp; 161240516Swpaul 161340516Swpaul ifp = &sc->arpcom.ac_if; 161440516Swpaul ifp->if_timer = 0; 161540516Swpaul 161650703Swpaul untimeout(rl_tick, sc, sc->rl_stat_ch); 161750703Swpaul 161840516Swpaul CSR_WRITE_1(sc, RL_COMMAND, 0x00); 161940516Swpaul CSR_WRITE_2(sc, RL_IMR, 0x0000); 162040516Swpaul 162140516Swpaul /* 162240516Swpaul * Free the TX list buffers. 162340516Swpaul */ 162440516Swpaul for (i = 0; i < RL_TX_LIST_CNT; i++) { 162545633Swpaul if (sc->rl_cdata.rl_tx_chain[i] != NULL) { 162645633Swpaul m_freem(sc->rl_cdata.rl_tx_chain[i]); 162745633Swpaul sc->rl_cdata.rl_tx_chain[i] = NULL; 162845633Swpaul CSR_WRITE_4(sc, RL_TXADDR0 + i, 0x0000000); 162940516Swpaul } 163040516Swpaul } 163140516Swpaul 163240516Swpaul ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE); 163340516Swpaul 163440516Swpaul return; 163540516Swpaul} 163640516Swpaul 163740516Swpaul/* 163840516Swpaul * Stop all chip I/O so that the kernel's probe routines don't 163940516Swpaul * get confused by errant DMAs when rebooting. 164040516Swpaul */ 164150703Swpaulstatic void rl_shutdown(dev) 164250703Swpaul device_t dev; 164340516Swpaul{ 164450703Swpaul struct rl_softc *sc; 164540516Swpaul 164650703Swpaul sc = device_get_softc(dev); 164750703Swpaul 164840516Swpaul rl_stop(sc); 164940516Swpaul 165040516Swpaul return; 165140516Swpaul} 1652