if_rl.c revision 72813
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 72813 2001-02-21 20:54:22Z wpaul $ 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 */ 10441569Swpaul#include <machine/bus_pio.h> 10541569Swpaul#include <machine/bus_memio.h> 10641569Swpaul#include <machine/bus.h> 10750703Swpaul#include <machine/resource.h> 10850703Swpaul#include <sys/bus.h> 10950703Swpaul#include <sys/rman.h> 11040516Swpaul 11150703Swpaul#include <dev/mii/mii.h> 11250703Swpaul#include <dev/mii/miivar.h> 11350703Swpaul 11440516Swpaul#include <pci/pcireg.h> 11540516Swpaul#include <pci/pcivar.h> 11640516Swpaul 11759758SpeterMODULE_DEPEND(rl, miibus, 1, 1, 1); 11859758Speter 11951089Speter/* "controller miibus0" required. See GENERIC if you get errors here. */ 12050703Swpaul#include "miibus_if.h" 12150703Swpaul 12240516Swpaul/* 12340516Swpaul * Default to using PIO access for this driver. On SMP systems, 12440516Swpaul * there appear to be problems with memory mapped mode: it looks like 12540516Swpaul * doing too many memory mapped access back to back in rapid succession 12640516Swpaul * can hang the bus. I'm inclined to blame this on crummy design/construction 12740516Swpaul * on the part of RealTek. Memory mapped mode does appear to work on 12840516Swpaul * uniprocessor systems though. 12940516Swpaul */ 13040516Swpaul#define RL_USEIOSPACE 13140516Swpaul 13240516Swpaul#include <pci/if_rlreg.h> 13340516Swpaul 13440516Swpaul#ifndef lint 13541591Sarchiestatic const char rcsid[] = 13650477Speter "$FreeBSD: head/sys/pci/if_rl.c 72813 2001-02-21 20:54:22Z wpaul $"; 13740516Swpaul#endif 13840516Swpaul 13940516Swpaul/* 14040516Swpaul * Various supported device vendors/types and their names. 14140516Swpaul */ 14240516Swpaulstatic struct rl_type rl_devs[] = { 14340516Swpaul { RT_VENDORID, RT_DEVICEID_8129, 14440516Swpaul "RealTek 8129 10/100BaseTX" }, 14540516Swpaul { RT_VENDORID, RT_DEVICEID_8139, 14640516Swpaul "RealTek 8139 10/100BaseTX" }, 14767771Swpaul { RT_VENDORID, RT_DEVICEID_8138, 14867771Swpaul "RealTek 8139 10/100BaseTX CardBus" }, 14941243Swpaul { ACCTON_VENDORID, ACCTON_DEVICEID_5030, 15041243Swpaul "Accton MPX 5030/5038 10/100BaseTX" }, 15144238Swpaul { DELTA_VENDORID, DELTA_DEVICEID_8139, 15244238Swpaul "Delta Electronics 8139 10/100BaseTX" }, 15344238Swpaul { ADDTRON_VENDORID, ADDTRON_DEVICEID_8139, 15444238Swpaul "Addtron Technolgy 8139 10/100BaseTX" }, 15572813Swpaul { DLINK_VENDORID, DLINK_DEVICEID_530TXPLUS, 15672813Swpaul "D-Link DFE-530TX+ 10/100BaseTX" }, 15740516Swpaul { 0, 0, NULL } 15840516Swpaul}; 15940516Swpaul 16050703Swpaulstatic int rl_probe __P((device_t)); 16150703Swpaulstatic int rl_attach __P((device_t)); 16250703Swpaulstatic int rl_detach __P((device_t)); 16340516Swpaul 16445633Swpaulstatic int rl_encap __P((struct rl_softc *, struct mbuf * )); 16540516Swpaul 16640516Swpaulstatic void rl_rxeof __P((struct rl_softc *)); 16740516Swpaulstatic void rl_txeof __P((struct rl_softc *)); 16840516Swpaulstatic void rl_intr __P((void *)); 16950703Swpaulstatic void rl_tick __P((void *)); 17040516Swpaulstatic void rl_start __P((struct ifnet *)); 17140516Swpaulstatic int rl_ioctl __P((struct ifnet *, u_long, caddr_t)); 17240516Swpaulstatic void rl_init __P((void *)); 17340516Swpaulstatic void rl_stop __P((struct rl_softc *)); 17440516Swpaulstatic void rl_watchdog __P((struct ifnet *)); 17550703Swpaulstatic void rl_shutdown __P((device_t)); 17640516Swpaulstatic int rl_ifmedia_upd __P((struct ifnet *)); 17740516Swpaulstatic void rl_ifmedia_sts __P((struct ifnet *, struct ifmediareq *)); 17840516Swpaul 17941656Swpaulstatic void rl_eeprom_putbyte __P((struct rl_softc *, int)); 18041656Swpaulstatic void rl_eeprom_getword __P((struct rl_softc *, int, u_int16_t *)); 18140516Swpaulstatic void rl_read_eeprom __P((struct rl_softc *, caddr_t, 18240516Swpaul int, int, int)); 18340516Swpaulstatic void rl_mii_sync __P((struct rl_softc *)); 18440516Swpaulstatic void rl_mii_send __P((struct rl_softc *, u_int32_t, int)); 18540516Swpaulstatic int rl_mii_readreg __P((struct rl_softc *, struct rl_mii_frame *)); 18640516Swpaulstatic int rl_mii_writereg __P((struct rl_softc *, struct rl_mii_frame *)); 18740516Swpaul 18850703Swpaulstatic int rl_miibus_readreg __P((device_t, int, int)); 18950703Swpaulstatic int rl_miibus_writereg __P((device_t, int, int, int)); 19050703Swpaulstatic void rl_miibus_statchg __P((device_t)); 19140516Swpaul 19241656Swpaulstatic u_int8_t rl_calchash __P((caddr_t)); 19340516Swpaulstatic void rl_setmulti __P((struct rl_softc *)); 19440516Swpaulstatic void rl_reset __P((struct rl_softc *)); 19540516Swpaulstatic int rl_list_tx_init __P((struct rl_softc *)); 19640516Swpaul 19750703Swpaul#ifdef RL_USEIOSPACE 19850703Swpaul#define RL_RES SYS_RES_IOPORT 19950703Swpaul#define RL_RID RL_PCI_LOIO 20050703Swpaul#else 20150703Swpaul#define RL_RES SYS_RES_MEMORY 20250703Swpaul#define RL_RID RL_PCI_LOMEM 20350703Swpaul#endif 20450703Swpaul 20550703Swpaulstatic device_method_t rl_methods[] = { 20650703Swpaul /* Device interface */ 20750703Swpaul DEVMETHOD(device_probe, rl_probe), 20850703Swpaul DEVMETHOD(device_attach, rl_attach), 20950703Swpaul DEVMETHOD(device_detach, rl_detach), 21050703Swpaul DEVMETHOD(device_shutdown, rl_shutdown), 21150703Swpaul 21250703Swpaul /* bus interface */ 21350703Swpaul DEVMETHOD(bus_print_child, bus_generic_print_child), 21450703Swpaul DEVMETHOD(bus_driver_added, bus_generic_driver_added), 21550703Swpaul 21650703Swpaul /* MII interface */ 21750703Swpaul DEVMETHOD(miibus_readreg, rl_miibus_readreg), 21850703Swpaul DEVMETHOD(miibus_writereg, rl_miibus_writereg), 21950703Swpaul DEVMETHOD(miibus_statchg, rl_miibus_statchg), 22050703Swpaul 22150703Swpaul { 0, 0 } 22250703Swpaul}; 22350703Swpaul 22450703Swpaulstatic driver_t rl_driver = { 22551455Swpaul "rl", 22650703Swpaul rl_methods, 22750703Swpaul sizeof(struct rl_softc) 22850703Swpaul}; 22950703Swpaul 23050703Swpaulstatic devclass_t rl_devclass; 23150703Swpaul 23251533SwpaulDRIVER_MODULE(if_rl, pci, rl_driver, rl_devclass, 0, 0); 23367931SwpaulDRIVER_MODULE(if_rl, cardbus, rl_driver, rl_devclass, 0, 0); 23451473SwpaulDRIVER_MODULE(miibus, rl, miibus_driver, miibus_devclass, 0, 0); 23550703Swpaul 23640516Swpaul#define EE_SET(x) \ 23740516Swpaul CSR_WRITE_1(sc, RL_EECMD, \ 23840516Swpaul CSR_READ_1(sc, RL_EECMD) | x) 23940516Swpaul 24040516Swpaul#define EE_CLR(x) \ 24140516Swpaul CSR_WRITE_1(sc, RL_EECMD, \ 24240516Swpaul CSR_READ_1(sc, RL_EECMD) & ~x) 24340516Swpaul 24440516Swpaul/* 24540516Swpaul * Send a read command and address to the EEPROM, check for ACK. 24640516Swpaul */ 24740516Swpaulstatic void rl_eeprom_putbyte(sc, addr) 24840516Swpaul struct rl_softc *sc; 24941656Swpaul int addr; 25040516Swpaul{ 25140516Swpaul register int d, i; 25240516Swpaul 25367931Swpaul d = addr | sc->rl_eecmd_read; 25440516Swpaul 25540516Swpaul /* 25655170Sbillf * Feed in each bit and strobe the clock. 25740516Swpaul */ 25840516Swpaul for (i = 0x400; i; i >>= 1) { 25940516Swpaul if (d & i) { 26040516Swpaul EE_SET(RL_EE_DATAIN); 26140516Swpaul } else { 26240516Swpaul EE_CLR(RL_EE_DATAIN); 26340516Swpaul } 26440516Swpaul DELAY(100); 26540516Swpaul EE_SET(RL_EE_CLK); 26640516Swpaul DELAY(150); 26740516Swpaul EE_CLR(RL_EE_CLK); 26840516Swpaul DELAY(100); 26940516Swpaul } 27040516Swpaul 27140516Swpaul return; 27240516Swpaul} 27340516Swpaul 27440516Swpaul/* 27540516Swpaul * Read a word of data stored in the EEPROM at address 'addr.' 27640516Swpaul */ 27740516Swpaulstatic void rl_eeprom_getword(sc, addr, dest) 27840516Swpaul struct rl_softc *sc; 27941656Swpaul int addr; 28040516Swpaul u_int16_t *dest; 28140516Swpaul{ 28240516Swpaul register int i; 28340516Swpaul u_int16_t word = 0; 28440516Swpaul 28540516Swpaul /* Enter EEPROM access mode. */ 28640516Swpaul CSR_WRITE_1(sc, RL_EECMD, RL_EEMODE_PROGRAM|RL_EE_SEL); 28740516Swpaul 28840516Swpaul /* 28940516Swpaul * Send address of word we want to read. 29040516Swpaul */ 29140516Swpaul rl_eeprom_putbyte(sc, addr); 29240516Swpaul 29340516Swpaul CSR_WRITE_1(sc, RL_EECMD, RL_EEMODE_PROGRAM|RL_EE_SEL); 29440516Swpaul 29540516Swpaul /* 29640516Swpaul * Start reading bits from EEPROM. 29740516Swpaul */ 29840516Swpaul for (i = 0x8000; i; i >>= 1) { 29940516Swpaul EE_SET(RL_EE_CLK); 30040516Swpaul DELAY(100); 30140516Swpaul if (CSR_READ_1(sc, RL_EECMD) & RL_EE_DATAOUT) 30240516Swpaul word |= i; 30340516Swpaul EE_CLR(RL_EE_CLK); 30440516Swpaul DELAY(100); 30540516Swpaul } 30640516Swpaul 30740516Swpaul /* Turn off EEPROM access mode. */ 30840516Swpaul CSR_WRITE_1(sc, RL_EECMD, RL_EEMODE_OFF); 30940516Swpaul 31040516Swpaul *dest = word; 31140516Swpaul 31240516Swpaul return; 31340516Swpaul} 31440516Swpaul 31540516Swpaul/* 31640516Swpaul * Read a sequence of words from the EEPROM. 31740516Swpaul */ 31840516Swpaulstatic void rl_read_eeprom(sc, dest, off, cnt, swap) 31940516Swpaul struct rl_softc *sc; 32040516Swpaul caddr_t dest; 32140516Swpaul int off; 32240516Swpaul int cnt; 32340516Swpaul int swap; 32440516Swpaul{ 32540516Swpaul int i; 32640516Swpaul u_int16_t word = 0, *ptr; 32740516Swpaul 32840516Swpaul for (i = 0; i < cnt; i++) { 32940516Swpaul rl_eeprom_getword(sc, off + i, &word); 33040516Swpaul ptr = (u_int16_t *)(dest + (i * 2)); 33140516Swpaul if (swap) 33240516Swpaul *ptr = ntohs(word); 33340516Swpaul else 33440516Swpaul *ptr = word; 33540516Swpaul } 33640516Swpaul 33740516Swpaul return; 33840516Swpaul} 33940516Swpaul 34040516Swpaul 34140516Swpaul/* 34240516Swpaul * MII access routines are provided for the 8129, which 34340516Swpaul * doesn't have a built-in PHY. For the 8139, we fake things 34440516Swpaul * up by diverting rl_phy_readreg()/rl_phy_writereg() to the 34540516Swpaul * direct access PHY registers. 34640516Swpaul */ 34740516Swpaul#define MII_SET(x) \ 34840516Swpaul CSR_WRITE_1(sc, RL_MII, \ 34940516Swpaul CSR_READ_1(sc, RL_MII) | x) 35040516Swpaul 35140516Swpaul#define MII_CLR(x) \ 35240516Swpaul CSR_WRITE_1(sc, RL_MII, \ 35340516Swpaul CSR_READ_1(sc, RL_MII) & ~x) 35440516Swpaul 35540516Swpaul/* 35640516Swpaul * Sync the PHYs by setting data bit and strobing the clock 32 times. 35740516Swpaul */ 35840516Swpaulstatic void rl_mii_sync(sc) 35940516Swpaul struct rl_softc *sc; 36040516Swpaul{ 36140516Swpaul register int i; 36240516Swpaul 36340516Swpaul MII_SET(RL_MII_DIR|RL_MII_DATAOUT); 36440516Swpaul 36540516Swpaul for (i = 0; i < 32; i++) { 36640516Swpaul MII_SET(RL_MII_CLK); 36740516Swpaul DELAY(1); 36840516Swpaul MII_CLR(RL_MII_CLK); 36940516Swpaul DELAY(1); 37040516Swpaul } 37140516Swpaul 37240516Swpaul return; 37340516Swpaul} 37440516Swpaul 37540516Swpaul/* 37640516Swpaul * Clock a series of bits through the MII. 37740516Swpaul */ 37840516Swpaulstatic void rl_mii_send(sc, bits, cnt) 37940516Swpaul struct rl_softc *sc; 38040516Swpaul u_int32_t bits; 38140516Swpaul int cnt; 38240516Swpaul{ 38340516Swpaul int i; 38440516Swpaul 38540516Swpaul MII_CLR(RL_MII_CLK); 38640516Swpaul 38740516Swpaul for (i = (0x1 << (cnt - 1)); i; i >>= 1) { 38840516Swpaul if (bits & i) { 38940516Swpaul MII_SET(RL_MII_DATAOUT); 39040516Swpaul } else { 39140516Swpaul MII_CLR(RL_MII_DATAOUT); 39240516Swpaul } 39340516Swpaul DELAY(1); 39440516Swpaul MII_CLR(RL_MII_CLK); 39540516Swpaul DELAY(1); 39640516Swpaul MII_SET(RL_MII_CLK); 39740516Swpaul } 39840516Swpaul} 39940516Swpaul 40040516Swpaul/* 40140516Swpaul * Read an PHY register through the MII. 40240516Swpaul */ 40340516Swpaulstatic int rl_mii_readreg(sc, frame) 40440516Swpaul struct rl_softc *sc; 40540516Swpaul struct rl_mii_frame *frame; 40640516Swpaul 40740516Swpaul{ 40867087Swpaul int i, ack; 40940516Swpaul 41067087Swpaul RL_LOCK(sc); 41140516Swpaul 41240516Swpaul /* 41340516Swpaul * Set up frame for RX. 41440516Swpaul */ 41540516Swpaul frame->mii_stdelim = RL_MII_STARTDELIM; 41640516Swpaul frame->mii_opcode = RL_MII_READOP; 41740516Swpaul frame->mii_turnaround = 0; 41840516Swpaul frame->mii_data = 0; 41940516Swpaul 42040516Swpaul CSR_WRITE_2(sc, RL_MII, 0); 42140516Swpaul 42240516Swpaul /* 42340516Swpaul * Turn on data xmit. 42440516Swpaul */ 42540516Swpaul MII_SET(RL_MII_DIR); 42640516Swpaul 42740516Swpaul rl_mii_sync(sc); 42840516Swpaul 42940516Swpaul /* 43040516Swpaul * Send command/address info. 43140516Swpaul */ 43240516Swpaul rl_mii_send(sc, frame->mii_stdelim, 2); 43340516Swpaul rl_mii_send(sc, frame->mii_opcode, 2); 43440516Swpaul rl_mii_send(sc, frame->mii_phyaddr, 5); 43540516Swpaul rl_mii_send(sc, frame->mii_regaddr, 5); 43640516Swpaul 43740516Swpaul /* Idle bit */ 43840516Swpaul MII_CLR((RL_MII_CLK|RL_MII_DATAOUT)); 43940516Swpaul DELAY(1); 44040516Swpaul MII_SET(RL_MII_CLK); 44140516Swpaul DELAY(1); 44240516Swpaul 44340516Swpaul /* Turn off xmit. */ 44440516Swpaul MII_CLR(RL_MII_DIR); 44540516Swpaul 44640516Swpaul /* Check for ack */ 44740516Swpaul MII_CLR(RL_MII_CLK); 44840516Swpaul DELAY(1); 44940516Swpaul MII_SET(RL_MII_CLK); 45040516Swpaul DELAY(1); 45140516Swpaul ack = CSR_READ_2(sc, RL_MII) & RL_MII_DATAIN; 45240516Swpaul 45340516Swpaul /* 45440516Swpaul * Now try reading data bits. If the ack failed, we still 45540516Swpaul * need to clock through 16 cycles to keep the PHY(s) in sync. 45640516Swpaul */ 45740516Swpaul if (ack) { 45840516Swpaul for(i = 0; i < 16; i++) { 45940516Swpaul MII_CLR(RL_MII_CLK); 46040516Swpaul DELAY(1); 46140516Swpaul MII_SET(RL_MII_CLK); 46240516Swpaul DELAY(1); 46340516Swpaul } 46440516Swpaul goto fail; 46540516Swpaul } 46640516Swpaul 46740516Swpaul for (i = 0x8000; i; i >>= 1) { 46840516Swpaul MII_CLR(RL_MII_CLK); 46940516Swpaul DELAY(1); 47040516Swpaul if (!ack) { 47140516Swpaul if (CSR_READ_2(sc, RL_MII) & RL_MII_DATAIN) 47240516Swpaul frame->mii_data |= i; 47340516Swpaul DELAY(1); 47440516Swpaul } 47540516Swpaul MII_SET(RL_MII_CLK); 47640516Swpaul DELAY(1); 47740516Swpaul } 47840516Swpaul 47940516Swpaulfail: 48040516Swpaul 48140516Swpaul MII_CLR(RL_MII_CLK); 48240516Swpaul DELAY(1); 48340516Swpaul MII_SET(RL_MII_CLK); 48440516Swpaul DELAY(1); 48540516Swpaul 48667087Swpaul RL_UNLOCK(sc); 48740516Swpaul 48840516Swpaul if (ack) 48940516Swpaul return(1); 49040516Swpaul return(0); 49140516Swpaul} 49240516Swpaul 49340516Swpaul/* 49440516Swpaul * Write to a PHY register through the MII. 49540516Swpaul */ 49640516Swpaulstatic int rl_mii_writereg(sc, frame) 49740516Swpaul struct rl_softc *sc; 49840516Swpaul struct rl_mii_frame *frame; 49940516Swpaul 50040516Swpaul{ 50167087Swpaul RL_LOCK(sc); 50240516Swpaul 50340516Swpaul /* 50440516Swpaul * Set up frame for TX. 50540516Swpaul */ 50640516Swpaul 50740516Swpaul frame->mii_stdelim = RL_MII_STARTDELIM; 50840516Swpaul frame->mii_opcode = RL_MII_WRITEOP; 50940516Swpaul frame->mii_turnaround = RL_MII_TURNAROUND; 51040516Swpaul 51140516Swpaul /* 51240516Swpaul * Turn on data output. 51340516Swpaul */ 51440516Swpaul MII_SET(RL_MII_DIR); 51540516Swpaul 51640516Swpaul rl_mii_sync(sc); 51740516Swpaul 51840516Swpaul rl_mii_send(sc, frame->mii_stdelim, 2); 51940516Swpaul rl_mii_send(sc, frame->mii_opcode, 2); 52040516Swpaul rl_mii_send(sc, frame->mii_phyaddr, 5); 52140516Swpaul rl_mii_send(sc, frame->mii_regaddr, 5); 52240516Swpaul rl_mii_send(sc, frame->mii_turnaround, 2); 52340516Swpaul rl_mii_send(sc, frame->mii_data, 16); 52440516Swpaul 52540516Swpaul /* Idle bit. */ 52640516Swpaul MII_SET(RL_MII_CLK); 52740516Swpaul DELAY(1); 52840516Swpaul MII_CLR(RL_MII_CLK); 52940516Swpaul DELAY(1); 53040516Swpaul 53140516Swpaul /* 53240516Swpaul * Turn off xmit. 53340516Swpaul */ 53440516Swpaul MII_CLR(RL_MII_DIR); 53540516Swpaul 53667087Swpaul RL_UNLOCK(sc); 53740516Swpaul 53840516Swpaul return(0); 53940516Swpaul} 54040516Swpaul 54150703Swpaulstatic int rl_miibus_readreg(dev, phy, reg) 54250703Swpaul device_t dev; 54350703Swpaul int phy, reg; 54450703Swpaul{ 54540516Swpaul struct rl_softc *sc; 54640516Swpaul struct rl_mii_frame frame; 54740516Swpaul u_int16_t rval = 0; 54840516Swpaul u_int16_t rl8139_reg = 0; 54940516Swpaul 55050703Swpaul sc = device_get_softc(dev); 55167087Swpaul RL_LOCK(sc); 55250703Swpaul 55340516Swpaul if (sc->rl_type == RL_8139) { 55450703Swpaul /* Pretend the internal PHY is only at address 0 */ 55567087Swpaul if (phy) { 55667087Swpaul RL_UNLOCK(sc); 55750703Swpaul return(0); 55867087Swpaul } 55940516Swpaul switch(reg) { 56050703Swpaul case MII_BMCR: 56140516Swpaul rl8139_reg = RL_BMCR; 56240516Swpaul break; 56350703Swpaul case MII_BMSR: 56440516Swpaul rl8139_reg = RL_BMSR; 56540516Swpaul break; 56650703Swpaul case MII_ANAR: 56740516Swpaul rl8139_reg = RL_ANAR; 56840516Swpaul break; 56950703Swpaul case MII_ANER: 57050703Swpaul rl8139_reg = RL_ANER; 57150703Swpaul break; 57250703Swpaul case MII_ANLPAR: 57340516Swpaul rl8139_reg = RL_LPAR; 57440516Swpaul break; 57550703Swpaul case MII_PHYIDR1: 57650703Swpaul case MII_PHYIDR2: 57767087Swpaul RL_UNLOCK(sc); 57850703Swpaul return(0); 57950703Swpaul break; 58040516Swpaul default: 58140516Swpaul printf("rl%d: bad phy register\n", sc->rl_unit); 58267087Swpaul RL_UNLOCK(sc); 58340516Swpaul return(0); 58440516Swpaul } 58540516Swpaul rval = CSR_READ_2(sc, rl8139_reg); 58667087Swpaul RL_UNLOCK(sc); 58740516Swpaul return(rval); 58840516Swpaul } 58940516Swpaul 59040516Swpaul bzero((char *)&frame, sizeof(frame)); 59140516Swpaul 59250703Swpaul frame.mii_phyaddr = phy; 59340516Swpaul frame.mii_regaddr = reg; 59440516Swpaul rl_mii_readreg(sc, &frame); 59567087Swpaul RL_UNLOCK(sc); 59640516Swpaul 59740516Swpaul return(frame.mii_data); 59840516Swpaul} 59940516Swpaul 60050703Swpaulstatic int rl_miibus_writereg(dev, phy, reg, data) 60150703Swpaul device_t dev; 60250703Swpaul int phy, reg, data; 60350703Swpaul{ 60440516Swpaul struct rl_softc *sc; 60540516Swpaul struct rl_mii_frame frame; 60640516Swpaul u_int16_t rl8139_reg = 0; 60740516Swpaul 60850703Swpaul sc = device_get_softc(dev); 60967087Swpaul RL_LOCK(sc); 61050703Swpaul 61140516Swpaul if (sc->rl_type == RL_8139) { 61250703Swpaul /* Pretend the internal PHY is only at address 0 */ 61367087Swpaul if (phy) { 61467087Swpaul RL_UNLOCK(sc); 61550703Swpaul return(0); 61667087Swpaul } 61740516Swpaul switch(reg) { 61850703Swpaul case MII_BMCR: 61940516Swpaul rl8139_reg = RL_BMCR; 62040516Swpaul break; 62150703Swpaul case MII_BMSR: 62240516Swpaul rl8139_reg = RL_BMSR; 62340516Swpaul break; 62450703Swpaul case MII_ANAR: 62540516Swpaul rl8139_reg = RL_ANAR; 62640516Swpaul break; 62750703Swpaul case MII_ANER: 62850703Swpaul rl8139_reg = RL_ANER; 62950703Swpaul break; 63050703Swpaul case MII_ANLPAR: 63140516Swpaul rl8139_reg = RL_LPAR; 63240516Swpaul break; 63350703Swpaul case MII_PHYIDR1: 63450703Swpaul case MII_PHYIDR2: 63567087Swpaul RL_UNLOCK(sc); 63650703Swpaul return(0); 63750703Swpaul break; 63840516Swpaul default: 63940516Swpaul printf("rl%d: bad phy register\n", sc->rl_unit); 64067087Swpaul RL_UNLOCK(sc); 64150703Swpaul return(0); 64240516Swpaul } 64340516Swpaul CSR_WRITE_2(sc, rl8139_reg, data); 64467087Swpaul RL_UNLOCK(sc); 64550703Swpaul return(0); 64640516Swpaul } 64740516Swpaul 64840516Swpaul bzero((char *)&frame, sizeof(frame)); 64940516Swpaul 65050703Swpaul frame.mii_phyaddr = phy; 65140516Swpaul frame.mii_regaddr = reg; 65240516Swpaul frame.mii_data = data; 65340516Swpaul 65440516Swpaul rl_mii_writereg(sc, &frame); 65540516Swpaul 65667087Swpaul RL_UNLOCK(sc); 65750703Swpaul return(0); 65850703Swpaul} 65950703Swpaul 66050703Swpaulstatic void rl_miibus_statchg(dev) 66150703Swpaul device_t dev; 66250703Swpaul{ 66340516Swpaul return; 66440516Swpaul} 66540516Swpaul 66640516Swpaul/* 66743062Swpaul * Calculate CRC of a multicast group address, return the upper 6 bits. 66840516Swpaul */ 66940516Swpaulstatic u_int8_t rl_calchash(addr) 67041656Swpaul caddr_t addr; 67140516Swpaul{ 67240516Swpaul u_int32_t crc, carry; 67340516Swpaul int i, j; 67440516Swpaul u_int8_t c; 67540516Swpaul 67640516Swpaul /* Compute CRC for the address value. */ 67740516Swpaul crc = 0xFFFFFFFF; /* initial value */ 67840516Swpaul 67940516Swpaul for (i = 0; i < 6; i++) { 68040516Swpaul c = *(addr + i); 68140516Swpaul for (j = 0; j < 8; j++) { 68240516Swpaul carry = ((crc & 0x80000000) ? 1 : 0) ^ (c & 0x01); 68340516Swpaul crc <<= 1; 68440516Swpaul c >>= 1; 68540516Swpaul if (carry) 68640516Swpaul crc = (crc ^ 0x04c11db6) | carry; 68740516Swpaul } 68840516Swpaul } 68940516Swpaul 69040516Swpaul /* return the filter bit position */ 69143062Swpaul return(crc >> 26); 69240516Swpaul} 69340516Swpaul 69440516Swpaul/* 69540516Swpaul * Program the 64-bit multicast hash filter. 69640516Swpaul */ 69740516Swpaulstatic void rl_setmulti(sc) 69840516Swpaul struct rl_softc *sc; 69940516Swpaul{ 70040516Swpaul struct ifnet *ifp; 70140516Swpaul int h = 0; 70240516Swpaul u_int32_t hashes[2] = { 0, 0 }; 70340516Swpaul struct ifmultiaddr *ifma; 70440516Swpaul u_int32_t rxfilt; 70540516Swpaul int mcnt = 0; 70640516Swpaul 70740516Swpaul ifp = &sc->arpcom.ac_if; 70840516Swpaul 70940516Swpaul rxfilt = CSR_READ_4(sc, RL_RXCFG); 71040516Swpaul 71143062Swpaul if (ifp->if_flags & IFF_ALLMULTI || ifp->if_flags & IFF_PROMISC) { 71240516Swpaul rxfilt |= RL_RXCFG_RX_MULTI; 71340516Swpaul CSR_WRITE_4(sc, RL_RXCFG, rxfilt); 71440516Swpaul CSR_WRITE_4(sc, RL_MAR0, 0xFFFFFFFF); 71540516Swpaul CSR_WRITE_4(sc, RL_MAR4, 0xFFFFFFFF); 71640516Swpaul return; 71740516Swpaul } 71840516Swpaul 71940516Swpaul /* first, zot all the existing hash bits */ 72040516Swpaul CSR_WRITE_4(sc, RL_MAR0, 0); 72140516Swpaul CSR_WRITE_4(sc, RL_MAR4, 0); 72240516Swpaul 72340516Swpaul /* now program new ones */ 72472084Sphk TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { 72540516Swpaul if (ifma->ifma_addr->sa_family != AF_LINK) 72640516Swpaul continue; 72740516Swpaul h = rl_calchash(LLADDR((struct sockaddr_dl *)ifma->ifma_addr)); 72840516Swpaul if (h < 32) 72940516Swpaul hashes[0] |= (1 << h); 73040516Swpaul else 73140516Swpaul hashes[1] |= (1 << (h - 32)); 73240516Swpaul mcnt++; 73340516Swpaul } 73440516Swpaul 73540516Swpaul if (mcnt) 73640516Swpaul rxfilt |= RL_RXCFG_RX_MULTI; 73740516Swpaul else 73840516Swpaul rxfilt &= ~RL_RXCFG_RX_MULTI; 73940516Swpaul 74040516Swpaul CSR_WRITE_4(sc, RL_RXCFG, rxfilt); 74140516Swpaul CSR_WRITE_4(sc, RL_MAR0, hashes[0]); 74240516Swpaul CSR_WRITE_4(sc, RL_MAR4, hashes[1]); 74340516Swpaul 74440516Swpaul return; 74540516Swpaul} 74640516Swpaul 74740516Swpaulstatic void rl_reset(sc) 74840516Swpaul struct rl_softc *sc; 74940516Swpaul{ 75040516Swpaul register int i; 75140516Swpaul 75240516Swpaul CSR_WRITE_1(sc, RL_COMMAND, RL_CMD_RESET); 75340516Swpaul 75440516Swpaul for (i = 0; i < RL_TIMEOUT; i++) { 75540516Swpaul DELAY(10); 75640516Swpaul if (!(CSR_READ_1(sc, RL_COMMAND) & RL_CMD_RESET)) 75740516Swpaul break; 75840516Swpaul } 75940516Swpaul if (i == RL_TIMEOUT) 76040516Swpaul printf("rl%d: reset never completed!\n", sc->rl_unit); 76140516Swpaul 76240516Swpaul return; 76340516Swpaul} 76440516Swpaul 76540516Swpaul/* 76640516Swpaul * Probe for a RealTek 8129/8139 chip. Check the PCI vendor and device 76740516Swpaul * IDs against our list and return a device name if we find a match. 76840516Swpaul */ 76950703Swpaulstatic int rl_probe(dev) 77050703Swpaul device_t dev; 77140516Swpaul{ 77240516Swpaul struct rl_type *t; 77340516Swpaul 77440516Swpaul t = rl_devs; 77540516Swpaul 77640516Swpaul while(t->rl_name != NULL) { 77750703Swpaul if ((pci_get_vendor(dev) == t->rl_vid) && 77850703Swpaul (pci_get_device(dev) == t->rl_did)) { 77950703Swpaul device_set_desc(dev, t->rl_name); 78050703Swpaul return(0); 78140516Swpaul } 78240516Swpaul t++; 78340516Swpaul } 78440516Swpaul 78550703Swpaul return(ENXIO); 78640516Swpaul} 78740516Swpaul 78840516Swpaul/* 78940516Swpaul * Attach the interface. Allocate softc structures, do ifmedia 79040516Swpaul * setup and ethernet/BPF attach. 79140516Swpaul */ 79250703Swpaulstatic int rl_attach(dev) 79350703Swpaul device_t dev; 79440516Swpaul{ 79540516Swpaul u_char eaddr[ETHER_ADDR_LEN]; 79640516Swpaul u_int32_t command; 79740516Swpaul struct rl_softc *sc; 79840516Swpaul struct ifnet *ifp; 79940516Swpaul u_int16_t rl_did = 0; 80050703Swpaul int unit, error = 0, rid; 80140516Swpaul 80250703Swpaul sc = device_get_softc(dev); 80350703Swpaul unit = device_get_unit(dev); 80440516Swpaul bzero(sc, sizeof(struct rl_softc)); 80540516Swpaul 80671228Sbmilekic mtx_init(&sc->rl_mtx, device_get_nameunit(dev), MTX_DEF | MTX_RECURSE); 80769583Swpaul RL_LOCK(sc); 80869583Swpaul 80940516Swpaul /* 81040516Swpaul * Handle power management nonsense. 81140516Swpaul */ 81240516Swpaul 81370167Swpaul if (pci_get_powerstate(dev) != PCI_POWERSTATE_D0) { 81470167Swpaul u_int32_t iobase, membase, irq; 81540516Swpaul 81670167Swpaul /* Save important PCI config data. */ 81770167Swpaul iobase = pci_read_config(dev, RL_PCI_LOIO, 4); 81870167Swpaul membase = pci_read_config(dev, RL_PCI_LOMEM, 4); 81970167Swpaul irq = pci_read_config(dev, RL_PCI_INTLINE, 4); 82040516Swpaul 82170167Swpaul /* Reset the power state. */ 82270167Swpaul printf("rl%d: chip is is in D%d power mode " 82370167Swpaul "-- setting to D0\n", unit, 82470167Swpaul pci_get_powerstate(dev)); 82540516Swpaul 82670167Swpaul pci_set_powerstate(dev, PCI_POWERSTATE_D0); 82740516Swpaul 82870167Swpaul /* Restore PCI config data. */ 82970167Swpaul pci_write_config(dev, RL_PCI_LOIO, iobase, 4); 83070167Swpaul pci_write_config(dev, RL_PCI_LOMEM, membase, 4); 83170167Swpaul pci_write_config(dev, RL_PCI_INTLINE, irq, 4); 83240516Swpaul } 83340516Swpaul 83440516Swpaul /* 83540516Swpaul * Map control/status registers. 83640516Swpaul */ 83772813Swpaul pci_enable_busmaster(dev); 83872813Swpaul pci_enable_io(dev, PCIM_CMD_PORTEN); 83972813Swpaul pci_enable_io(dev, PCIM_CMD_MEMEN); 84061041Speter command = pci_read_config(dev, PCIR_COMMAND, 4); 84140516Swpaul 84240516Swpaul#ifdef RL_USEIOSPACE 84340516Swpaul if (!(command & PCIM_CMD_PORTEN)) { 84440516Swpaul printf("rl%d: failed to enable I/O ports!\n", unit); 84550703Swpaul error = ENXIO; 84640516Swpaul goto fail; 84740516Swpaul } 84840516Swpaul#else 84940516Swpaul if (!(command & PCIM_CMD_MEMEN)) { 85040516Swpaul printf("rl%d: failed to enable memory mapping!\n", unit); 85150703Swpaul error = ENXIO; 85240516Swpaul goto fail; 85340516Swpaul } 85450703Swpaul#endif 85540516Swpaul 85650703Swpaul rid = RL_RID; 85750703Swpaul sc->rl_res = bus_alloc_resource(dev, RL_RES, &rid, 85850703Swpaul 0, ~0, 1, RF_ACTIVE); 85950703Swpaul 86050703Swpaul if (sc->rl_res == NULL) { 86150703Swpaul printf ("rl%d: couldn't map ports/memory\n", unit); 86250703Swpaul error = ENXIO; 86340516Swpaul goto fail; 86440516Swpaul } 86540516Swpaul 86669127Sroger /* Detect the Realtek 8139B. For some reason, this chip is very 86769127Sroger * unstable when left to autoselect the media 86869127Sroger * The best workaround is to set the device to the required 86969127Sroger * media type or to set it to the 10 Meg speed. 87069127Sroger */ 87169127Sroger 87269127Sroger if ((rman_get_end(sc->rl_res)-rman_get_start(sc->rl_res))==0xff) { 87369127Sroger printf("rl%d: Realtek 8139B detected. Warning, this may be unstable in autoselect mode\n", unit); 87469127Sroger } 87569127Sroger 87650703Swpaul sc->rl_btag = rman_get_bustag(sc->rl_res); 87750703Swpaul sc->rl_bhandle = rman_get_bushandle(sc->rl_res); 87850703Swpaul 87950703Swpaul rid = 0; 88050703Swpaul sc->rl_irq = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, 0, ~0, 1, 88150703Swpaul RF_SHAREABLE | RF_ACTIVE); 88250703Swpaul 88350703Swpaul if (sc->rl_irq == NULL) { 88440516Swpaul printf("rl%d: couldn't map interrupt\n", unit); 88550703Swpaul bus_release_resource(dev, RL_RES, RL_RID, sc->rl_res); 88650703Swpaul error = ENXIO; 88740516Swpaul goto fail; 88840516Swpaul } 88940516Swpaul 89050703Swpaul error = bus_setup_intr(dev, sc->rl_irq, INTR_TYPE_NET, 89150703Swpaul rl_intr, sc, &sc->rl_intrhand); 89250703Swpaul 89350703Swpaul if (error) { 89468215Swpaul bus_release_resource(dev, SYS_RES_IRQ, 0, sc->rl_irq); 89550703Swpaul bus_release_resource(dev, RL_RES, RL_RID, sc->rl_res); 89650703Swpaul printf("rl%d: couldn't set up irq\n", unit); 89750703Swpaul goto fail; 89850703Swpaul } 89950703Swpaul 90050703Swpaul callout_handle_init(&sc->rl_stat_ch); 90150703Swpaul 90240516Swpaul /* Reset the adapter. */ 90340516Swpaul rl_reset(sc); 90467931Swpaul sc->rl_eecmd_read = RL_EECMD_READ_6BIT; 90567931Swpaul rl_read_eeprom(sc, (caddr_t)&rl_did, 0, 1, 0); 90668215Swpaul if (rl_did != 0x8129) 90767931Swpaul sc->rl_eecmd_read = RL_EECMD_READ_8BIT; 90840516Swpaul 90940516Swpaul /* 91040516Swpaul * Get station address from the EEPROM. 91140516Swpaul */ 91240516Swpaul rl_read_eeprom(sc, (caddr_t)&eaddr, RL_EE_EADDR, 3, 0); 91340516Swpaul 91440516Swpaul /* 91540516Swpaul * A RealTek chip was detected. Inform the world. 91640516Swpaul */ 91740516Swpaul printf("rl%d: Ethernet address: %6D\n", unit, eaddr, ":"); 91840516Swpaul 91940516Swpaul sc->rl_unit = unit; 92040516Swpaul bcopy(eaddr, (char *)&sc->arpcom.ac_enaddr, ETHER_ADDR_LEN); 92140516Swpaul 92240516Swpaul /* 92340516Swpaul * Now read the exact device type from the EEPROM to find 92440516Swpaul * out if it's an 8129 or 8139. 92540516Swpaul */ 92640516Swpaul rl_read_eeprom(sc, (caddr_t)&rl_did, RL_EE_PCI_DID, 1, 0); 92740516Swpaul 92844238Swpaul if (rl_did == RT_DEVICEID_8139 || rl_did == ACCTON_DEVICEID_5030 || 92967771Swpaul rl_did == DELTA_DEVICEID_8139 || rl_did == ADDTRON_DEVICEID_8139 || 93072813Swpaul rl_did == RT_DEVICEID_8138 || rl_did == DLINK_DEVICEID_530TXPLUS) 93140516Swpaul sc->rl_type = RL_8139; 93240516Swpaul else if (rl_did == RT_DEVICEID_8129) 93340516Swpaul sc->rl_type = RL_8129; 93440516Swpaul else { 93540516Swpaul printf("rl%d: unknown device ID: %x\n", unit, rl_did); 93650703Swpaul bus_teardown_intr(dev, sc->rl_irq, sc->rl_intrhand); 93768215Swpaul bus_release_resource(dev, SYS_RES_IRQ, 0, sc->rl_irq); 93850703Swpaul bus_release_resource(dev, RL_RES, RL_RID, sc->rl_res); 93950703Swpaul error = ENXIO; 94040516Swpaul goto fail; 94140516Swpaul } 94240516Swpaul 94360043Swpaul sc->rl_cdata.rl_rx_buf = contigmalloc(RL_RXBUFLEN + 1518, M_DEVBUF, 94451657Swpaul M_NOWAIT, 0, 0xffffffff, PAGE_SIZE, 0); 94540516Swpaul 94640516Swpaul if (sc->rl_cdata.rl_rx_buf == NULL) { 94740516Swpaul printf("rl%d: no memory for list buffers!\n", unit); 94850703Swpaul bus_teardown_intr(dev, sc->rl_irq, sc->rl_intrhand); 94968215Swpaul bus_release_resource(dev, SYS_RES_IRQ, 0, sc->rl_irq); 95050703Swpaul bus_release_resource(dev, RL_RES, RL_RID, sc->rl_res); 95150703Swpaul error = ENXIO; 95240516Swpaul goto fail; 95340516Swpaul } 95440516Swpaul 95548028Swpaul /* Leave a few bytes before the start of the RX ring buffer. */ 95648028Swpaul sc->rl_cdata.rl_rx_buf_ptr = sc->rl_cdata.rl_rx_buf; 95748028Swpaul sc->rl_cdata.rl_rx_buf += sizeof(u_int64_t); 95848028Swpaul 95950703Swpaul /* Do MII setup */ 96050703Swpaul if (mii_phy_probe(dev, &sc->rl_miibus, 96150703Swpaul rl_ifmedia_upd, rl_ifmedia_sts)) { 96250703Swpaul printf("rl%d: MII without any phy!\n", sc->rl_unit); 96350703Swpaul bus_teardown_intr(dev, sc->rl_irq, sc->rl_intrhand); 96468215Swpaul bus_release_resource(dev, SYS_RES_IRQ, 0, sc->rl_irq); 96550703Swpaul bus_release_resource(dev, RL_RES, RL_RID, sc->rl_res); 96650703Swpaul free(sc->rl_cdata.rl_rx_buf, M_DEVBUF); 96750703Swpaul error = ENXIO; 96850703Swpaul goto fail; 96950703Swpaul } 97050703Swpaul 97140516Swpaul ifp = &sc->arpcom.ac_if; 97240516Swpaul ifp->if_softc = sc; 97340516Swpaul ifp->if_unit = unit; 97440516Swpaul ifp->if_name = "rl"; 97540516Swpaul ifp->if_mtu = ETHERMTU; 97640516Swpaul ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 97740516Swpaul ifp->if_ioctl = rl_ioctl; 97840516Swpaul ifp->if_output = ether_output; 97940516Swpaul ifp->if_start = rl_start; 98040516Swpaul ifp->if_watchdog = rl_watchdog; 98140516Swpaul ifp->if_init = rl_init; 98240516Swpaul ifp->if_baudrate = 10000000; 98345633Swpaul ifp->if_snd.ifq_maxlen = IFQ_MAXLEN; 98440516Swpaul 98540516Swpaul /* 98663090Sarchie * Call MI attach routine. 98740516Swpaul */ 98863090Sarchie ether_ifattach(ifp, ETHER_BPF_SUPPORTED); 98967087Swpaul RL_UNLOCK(sc); 99067087Swpaul return(0); 99140516Swpaul 99240516Swpaulfail: 99367087Swpaul RL_UNLOCK(sc); 99467087Swpaul mtx_destroy(&sc->rl_mtx); 99550703Swpaul return(error); 99640516Swpaul} 99740516Swpaul 99850703Swpaulstatic int rl_detach(dev) 99950703Swpaul device_t dev; 100050703Swpaul{ 100150703Swpaul struct rl_softc *sc; 100250703Swpaul struct ifnet *ifp; 100350703Swpaul 100450703Swpaul sc = device_get_softc(dev); 100567087Swpaul RL_LOCK(sc); 100650703Swpaul ifp = &sc->arpcom.ac_if; 100750703Swpaul 100863090Sarchie ether_ifdetach(ifp, ETHER_BPF_SUPPORTED); 100950703Swpaul rl_stop(sc); 101050703Swpaul 101150703Swpaul bus_generic_detach(dev); 101250703Swpaul device_delete_child(dev, sc->rl_miibus); 101350703Swpaul 101450703Swpaul bus_teardown_intr(dev, sc->rl_irq, sc->rl_intrhand); 101568215Swpaul bus_release_resource(dev, SYS_RES_IRQ, 0, sc->rl_irq); 101650703Swpaul bus_release_resource(dev, RL_RES, RL_RID, sc->rl_res); 101750703Swpaul 101852426Swpaul contigfree(sc->rl_cdata.rl_rx_buf, RL_RXBUFLEN + 32, M_DEVBUF); 101950703Swpaul 102067087Swpaul RL_UNLOCK(sc); 102167087Swpaul mtx_destroy(&sc->rl_mtx); 102250703Swpaul 102350703Swpaul return(0); 102450703Swpaul} 102550703Swpaul 102640516Swpaul/* 102740516Swpaul * Initialize the transmit descriptors. 102840516Swpaul */ 102940516Swpaulstatic int rl_list_tx_init(sc) 103040516Swpaul struct rl_softc *sc; 103140516Swpaul{ 103240516Swpaul struct rl_chain_data *cd; 103340516Swpaul int i; 103440516Swpaul 103540516Swpaul cd = &sc->rl_cdata; 103640516Swpaul for (i = 0; i < RL_TX_LIST_CNT; i++) { 103745633Swpaul cd->rl_tx_chain[i] = NULL; 103848028Swpaul CSR_WRITE_4(sc, 103948028Swpaul RL_TXADDR0 + (i * sizeof(u_int32_t)), 0x0000000); 104040516Swpaul } 104140516Swpaul 104245633Swpaul sc->rl_cdata.cur_tx = 0; 104345633Swpaul sc->rl_cdata.last_tx = 0; 104440516Swpaul 104540516Swpaul return(0); 104640516Swpaul} 104740516Swpaul 104840516Swpaul/* 104940516Swpaul * A frame has been uploaded: pass the resulting mbuf chain up to 105040516Swpaul * the higher level protocols. 105140516Swpaul * 105240516Swpaul * You know there's something wrong with a PCI bus-master chip design 105340516Swpaul * when you have to use m_devget(). 105440516Swpaul * 105540516Swpaul * The receive operation is badly documented in the datasheet, so I'll 105640516Swpaul * attempt to document it here. The driver provides a buffer area and 105740516Swpaul * places its base address in the RX buffer start address register. 105840516Swpaul * The chip then begins copying frames into the RX buffer. Each frame 105972645Sasmodai * is preceded by a 32-bit RX status word which specifies the length 106040516Swpaul * of the frame and certain other status bits. Each frame (starting with 106140516Swpaul * the status word) is also 32-bit aligned. The frame length is in the 106240516Swpaul * first 16 bits of the status word; the lower 15 bits correspond with 106340516Swpaul * the 'rx status register' mentioned in the datasheet. 106448028Swpaul * 106548028Swpaul * Note: to make the Alpha happy, the frame payload needs to be aligned 106648028Swpaul * on a 32-bit boundary. To achieve this, we cheat a bit by copying from 106748028Swpaul * the ring buffer starting at an address two bytes before the actual 106848028Swpaul * data location. We can then shave off the first two bytes using m_adj(). 106948028Swpaul * The reason we do this is because m_devget() doesn't let us specify an 107048028Swpaul * offset into the mbuf storage space, so we have to artificially create 107148028Swpaul * one. The ring is allocated in such a way that there are a few unused 107248028Swpaul * bytes of space preceecing it so that it will be safe for us to do the 107348028Swpaul * 2-byte backstep even if reading from the ring at offset 0. 107440516Swpaul */ 107540516Swpaulstatic void rl_rxeof(sc) 107640516Swpaul struct rl_softc *sc; 107740516Swpaul{ 107840516Swpaul struct ether_header *eh; 107940516Swpaul struct mbuf *m; 108040516Swpaul struct ifnet *ifp; 108140516Swpaul int total_len = 0; 108240516Swpaul u_int32_t rxstat; 108340516Swpaul caddr_t rxbufpos; 108440516Swpaul int wrap = 0; 108540516Swpaul u_int16_t cur_rx; 108640516Swpaul u_int16_t limit; 108740516Swpaul u_int16_t rx_bytes = 0, max_bytes; 108840516Swpaul 108940516Swpaul ifp = &sc->arpcom.ac_if; 109040516Swpaul 109140516Swpaul cur_rx = (CSR_READ_2(sc, RL_CURRXADDR) + 16) % RL_RXBUFLEN; 109240516Swpaul 109340516Swpaul /* Do not try to read past this point. */ 109440516Swpaul limit = CSR_READ_2(sc, RL_CURRXBUF) % RL_RXBUFLEN; 109540516Swpaul 109640516Swpaul if (limit < cur_rx) 109740516Swpaul max_bytes = (RL_RXBUFLEN - cur_rx) + limit; 109840516Swpaul else 109940516Swpaul max_bytes = limit - cur_rx; 110040516Swpaul 110142738Swpaul while((CSR_READ_1(sc, RL_COMMAND) & RL_CMD_EMPTY_RXBUF) == 0) { 110240516Swpaul rxbufpos = sc->rl_cdata.rl_rx_buf + cur_rx; 110340516Swpaul rxstat = *(u_int32_t *)rxbufpos; 110440516Swpaul 110540516Swpaul /* 110640516Swpaul * Here's a totally undocumented fact for you. When the 110740516Swpaul * RealTek chip is in the process of copying a packet into 110840516Swpaul * RAM for you, the length will be 0xfff0. If you spot a 110940516Swpaul * packet header with this value, you need to stop. The 111040516Swpaul * datasheet makes absolutely no mention of this and 111140516Swpaul * RealTek should be shot for this. 111240516Swpaul */ 111340516Swpaul if ((u_int16_t)(rxstat >> 16) == RL_RXSTAT_UNFINISHED) 111440516Swpaul break; 111540516Swpaul 111640516Swpaul if (!(rxstat & RL_RXSTAT_RXOK)) { 111740516Swpaul ifp->if_ierrors++; 111850703Swpaul rl_init(sc); 111950703Swpaul return; 112040516Swpaul } 112140516Swpaul 112240516Swpaul /* No errors; receive the packet. */ 112340516Swpaul total_len = rxstat >> 16; 112440516Swpaul rx_bytes += total_len + 4; 112540516Swpaul 112640516Swpaul /* 112742051Swpaul * XXX The RealTek chip includes the CRC with every 112842051Swpaul * received frame, and there's no way to turn this 112942051Swpaul * behavior off (at least, I can't find anything in 113042051Swpaul * the manual that explains how to do it) so we have 113142051Swpaul * to trim off the CRC manually. 113242051Swpaul */ 113342051Swpaul total_len -= ETHER_CRC_LEN; 113442051Swpaul 113542051Swpaul /* 113640516Swpaul * Avoid trying to read more bytes than we know 113740516Swpaul * the chip has prepared for us. 113840516Swpaul */ 113940516Swpaul if (rx_bytes > max_bytes) 114040516Swpaul break; 114140516Swpaul 114240516Swpaul rxbufpos = sc->rl_cdata.rl_rx_buf + 114340516Swpaul ((cur_rx + sizeof(u_int32_t)) % RL_RXBUFLEN); 114440516Swpaul 114540516Swpaul if (rxbufpos == (sc->rl_cdata.rl_rx_buf + RL_RXBUFLEN)) 114640516Swpaul rxbufpos = sc->rl_cdata.rl_rx_buf; 114740516Swpaul 114840516Swpaul wrap = (sc->rl_cdata.rl_rx_buf + RL_RXBUFLEN) - rxbufpos; 114940516Swpaul 115040516Swpaul if (total_len > wrap) { 115160043Swpaul /* 115260043Swpaul * Fool m_devget() into thinking we want to copy 115360043Swpaul * the whole buffer so we don't end up fragmenting 115460043Swpaul * the data. 115560043Swpaul */ 115648028Swpaul m = m_devget(rxbufpos - RL_ETHER_ALIGN, 115760043Swpaul total_len + RL_ETHER_ALIGN, 0, ifp, NULL); 115840516Swpaul if (m == NULL) { 115940516Swpaul ifp->if_ierrors++; 116040516Swpaul printf("rl%d: out of mbufs, tried to " 116152426Swpaul "copy %d bytes\n", sc->rl_unit, wrap); 116252426Swpaul } else { 116348028Swpaul m_adj(m, RL_ETHER_ALIGN); 116440516Swpaul m_copyback(m, wrap, total_len - wrap, 116540516Swpaul sc->rl_cdata.rl_rx_buf); 116648028Swpaul } 116742051Swpaul cur_rx = (total_len - wrap + ETHER_CRC_LEN); 116840516Swpaul } else { 116948028Swpaul m = m_devget(rxbufpos - RL_ETHER_ALIGN, 117048028Swpaul total_len + RL_ETHER_ALIGN, 0, ifp, NULL); 117140516Swpaul if (m == NULL) { 117240516Swpaul ifp->if_ierrors++; 117340516Swpaul printf("rl%d: out of mbufs, tried to " 117452426Swpaul "copy %d bytes\n", sc->rl_unit, total_len); 117548028Swpaul } else 117648028Swpaul m_adj(m, RL_ETHER_ALIGN); 117742051Swpaul cur_rx += total_len + 4 + ETHER_CRC_LEN; 117840516Swpaul } 117940516Swpaul 118040516Swpaul /* 118140516Swpaul * Round up to 32-bit boundary. 118240516Swpaul */ 118340516Swpaul cur_rx = (cur_rx + 3) & ~3; 118440516Swpaul CSR_WRITE_2(sc, RL_CURRXADDR, cur_rx - 16); 118540516Swpaul 118640516Swpaul if (m == NULL) 118740516Swpaul continue; 118840516Swpaul 118940516Swpaul eh = mtod(m, struct ether_header *); 119040516Swpaul ifp->if_ipackets++; 119140516Swpaul 119240516Swpaul /* Remove header from mbuf and pass it on. */ 119340516Swpaul m_adj(m, sizeof(struct ether_header)); 119440516Swpaul ether_input(ifp, eh, m); 119540516Swpaul } 119640516Swpaul 119740516Swpaul return; 119840516Swpaul} 119940516Swpaul 120040516Swpaul/* 120140516Swpaul * A frame was downloaded to the chip. It's safe for us to clean up 120240516Swpaul * the list buffers. 120340516Swpaul */ 120440516Swpaulstatic void rl_txeof(sc) 120540516Swpaul struct rl_softc *sc; 120640516Swpaul{ 120740516Swpaul struct ifnet *ifp; 120840516Swpaul u_int32_t txstat; 120940516Swpaul 121040516Swpaul ifp = &sc->arpcom.ac_if; 121140516Swpaul 121240516Swpaul /* Clear the timeout timer. */ 121340516Swpaul ifp->if_timer = 0; 121440516Swpaul 121540516Swpaul /* 121640516Swpaul * Go through our tx list and free mbufs for those 121740516Swpaul * frames that have been uploaded. 121840516Swpaul */ 121945633Swpaul do { 122045633Swpaul txstat = CSR_READ_4(sc, RL_LAST_TXSTAT(sc)); 122145633Swpaul if (!(txstat & (RL_TXSTAT_TX_OK| 122245633Swpaul RL_TXSTAT_TX_UNDERRUN|RL_TXSTAT_TXABRT))) 122340516Swpaul break; 122440516Swpaul 122545633Swpaul ifp->if_collisions += (txstat & RL_TXSTAT_COLLCNT) >> 24; 122640516Swpaul 122745633Swpaul if (RL_LAST_TXMBUF(sc) != NULL) { 122845633Swpaul m_freem(RL_LAST_TXMBUF(sc)); 122945633Swpaul RL_LAST_TXMBUF(sc) = NULL; 123045633Swpaul } 123145633Swpaul if (txstat & RL_TXSTAT_TX_OK) 123245633Swpaul ifp->if_opackets++; 123345633Swpaul else { 123452426Swpaul int oldthresh; 123545633Swpaul ifp->if_oerrors++; 123645633Swpaul if ((txstat & RL_TXSTAT_TXABRT) || 123745633Swpaul (txstat & RL_TXSTAT_OUTOFWIN)) 123845633Swpaul CSR_WRITE_4(sc, RL_TXCFG, RL_TXCFG_CONFIG); 123952426Swpaul oldthresh = sc->rl_txthresh; 124052426Swpaul /* error recovery */ 124152426Swpaul rl_reset(sc); 124252426Swpaul rl_init(sc); 124352426Swpaul /* 124452426Swpaul * If there was a transmit underrun, 124552426Swpaul * bump the TX threshold. 124652426Swpaul */ 124752426Swpaul if (txstat & RL_TXSTAT_TX_UNDERRUN) 124852426Swpaul sc->rl_txthresh = oldthresh + 32; 124952426Swpaul return; 125045633Swpaul } 125145633Swpaul RL_INC(sc->rl_cdata.last_tx); 125245633Swpaul ifp->if_flags &= ~IFF_OACTIVE; 125345633Swpaul } while (sc->rl_cdata.last_tx != sc->rl_cdata.cur_tx); 125440516Swpaul 125550703Swpaul return; 125650703Swpaul} 125740516Swpaul 125850703Swpaulstatic void rl_tick(xsc) 125950703Swpaul void *xsc; 126050703Swpaul{ 126150703Swpaul struct rl_softc *sc; 126250703Swpaul struct mii_data *mii; 126350703Swpaul 126450703Swpaul sc = xsc; 126567087Swpaul RL_LOCK(sc); 126650703Swpaul mii = device_get_softc(sc->rl_miibus); 126750703Swpaul 126850703Swpaul mii_tick(mii); 126950703Swpaul 127050703Swpaul sc->rl_stat_ch = timeout(rl_tick, sc, hz); 127167087Swpaul RL_UNLOCK(sc); 127250703Swpaul 127340516Swpaul return; 127440516Swpaul} 127540516Swpaul 127640516Swpaulstatic void rl_intr(arg) 127740516Swpaul void *arg; 127840516Swpaul{ 127940516Swpaul struct rl_softc *sc; 128040516Swpaul struct ifnet *ifp; 128140516Swpaul u_int16_t status; 128240516Swpaul 128340516Swpaul sc = arg; 128467087Swpaul RL_LOCK(sc); 128540516Swpaul ifp = &sc->arpcom.ac_if; 128640516Swpaul 128740516Swpaul /* Disable interrupts. */ 128840516Swpaul CSR_WRITE_2(sc, RL_IMR, 0x0000); 128940516Swpaul 129040516Swpaul for (;;) { 129140516Swpaul 129240516Swpaul status = CSR_READ_2(sc, RL_ISR); 129340516Swpaul if (status) 129440516Swpaul CSR_WRITE_2(sc, RL_ISR, status); 129540516Swpaul 129640516Swpaul if ((status & RL_INTRS) == 0) 129740516Swpaul break; 129840516Swpaul 129940516Swpaul if (status & RL_ISR_RX_OK) 130040516Swpaul rl_rxeof(sc); 130140516Swpaul 130240516Swpaul if (status & RL_ISR_RX_ERR) 130340516Swpaul rl_rxeof(sc); 130440516Swpaul 130545633Swpaul if ((status & RL_ISR_TX_OK) || (status & RL_ISR_TX_ERR)) 130640516Swpaul rl_txeof(sc); 130740516Swpaul 130840516Swpaul if (status & RL_ISR_SYSTEM_ERR) { 130940516Swpaul rl_reset(sc); 131040516Swpaul rl_init(sc); 131140516Swpaul } 131240516Swpaul 131340516Swpaul } 131440516Swpaul 131540516Swpaul /* Re-enable interrupts. */ 131640516Swpaul CSR_WRITE_2(sc, RL_IMR, RL_INTRS); 131740516Swpaul 131852426Swpaul if (ifp->if_snd.ifq_head != NULL) 131940516Swpaul rl_start(ifp); 132040516Swpaul 132167087Swpaul RL_UNLOCK(sc); 132267087Swpaul 132340516Swpaul return; 132440516Swpaul} 132540516Swpaul 132640516Swpaul/* 132740516Swpaul * Encapsulate an mbuf chain in a descriptor by coupling the mbuf data 132840516Swpaul * pointers to the fragment pointers. 132940516Swpaul */ 133045633Swpaulstatic int rl_encap(sc, m_head) 133140516Swpaul struct rl_softc *sc; 133240516Swpaul struct mbuf *m_head; 133340516Swpaul{ 133441243Swpaul struct mbuf *m_new = NULL; 133540516Swpaul 133640516Swpaul /* 133745633Swpaul * The RealTek is brain damaged and wants longword-aligned 133845633Swpaul * TX buffers, plus we can only have one fragment buffer 133945633Swpaul * per packet. We have to copy pretty much all the time. 134040516Swpaul */ 134140516Swpaul 134241243Swpaul MGETHDR(m_new, M_DONTWAIT, MT_DATA); 134341243Swpaul if (m_new == NULL) { 134441243Swpaul printf("rl%d: no memory for tx list", sc->rl_unit); 134541243Swpaul return(1); 134641243Swpaul } 134741243Swpaul if (m_head->m_pkthdr.len > MHLEN) { 134841243Swpaul MCLGET(m_new, M_DONTWAIT); 134941243Swpaul if (!(m_new->m_flags & M_EXT)) { 135041243Swpaul m_freem(m_new); 135141243Swpaul printf("rl%d: no memory for tx list", 135241243Swpaul sc->rl_unit); 135340516Swpaul return(1); 135440516Swpaul } 135540516Swpaul } 135652426Swpaul m_copydata(m_head, 0, m_head->m_pkthdr.len, mtod(m_new, caddr_t)); 135741243Swpaul m_new->m_pkthdr.len = m_new->m_len = m_head->m_pkthdr.len; 135841243Swpaul m_freem(m_head); 135941243Swpaul m_head = m_new; 136040516Swpaul 136140516Swpaul /* Pad frames to at least 60 bytes. */ 136241243Swpaul if (m_head->m_pkthdr.len < RL_MIN_FRAMELEN) { 136355058Swpaul /* 136455058Swpaul * Make security concious people happy: zero out the 136555058Swpaul * bytes in the pad area, since we don't know what 136655058Swpaul * this mbuf cluster buffer's previous user might 136755058Swpaul * have left in it. 136855058Swpaul */ 136955058Swpaul bzero(mtod(m_head, char *) + m_head->m_pkthdr.len, 137055058Swpaul RL_MIN_FRAMELEN - m_head->m_pkthdr.len); 137140516Swpaul m_head->m_pkthdr.len += 137252426Swpaul (RL_MIN_FRAMELEN - m_head->m_pkthdr.len); 137341243Swpaul m_head->m_len = m_head->m_pkthdr.len; 137441243Swpaul } 137540516Swpaul 137645633Swpaul RL_CUR_TXMBUF(sc) = m_head; 137740516Swpaul 137840516Swpaul return(0); 137940516Swpaul} 138040516Swpaul 138140516Swpaul/* 138240516Swpaul * Main transmit routine. 138340516Swpaul */ 138440516Swpaul 138540516Swpaulstatic void rl_start(ifp) 138640516Swpaul struct ifnet *ifp; 138740516Swpaul{ 138840516Swpaul struct rl_softc *sc; 138940516Swpaul struct mbuf *m_head = NULL; 139040516Swpaul 139140516Swpaul sc = ifp->if_softc; 139267087Swpaul RL_LOCK(sc); 139340516Swpaul 139445633Swpaul while(RL_CUR_TXMBUF(sc) == NULL) { 139540516Swpaul IF_DEQUEUE(&ifp->if_snd, m_head); 139640516Swpaul if (m_head == NULL) 139740516Swpaul break; 139840516Swpaul 139958801Swpaul if (rl_encap(sc, m_head)) { 140058801Swpaul IF_PREPEND(&ifp->if_snd, m_head); 140158801Swpaul ifp->if_flags |= IFF_OACTIVE; 140258801Swpaul break; 140358801Swpaul } 140440516Swpaul 140540516Swpaul /* 140640516Swpaul * If there's a BPF listener, bounce a copy of this frame 140740516Swpaul * to him. 140840516Swpaul */ 140940516Swpaul if (ifp->if_bpf) 141045633Swpaul bpf_mtap(ifp, RL_CUR_TXMBUF(sc)); 141151583Swpaul 141240516Swpaul /* 141340516Swpaul * Transmit the frame. 141440516Swpaul */ 141545633Swpaul CSR_WRITE_4(sc, RL_CUR_TXADDR(sc), 141645633Swpaul vtophys(mtod(RL_CUR_TXMBUF(sc), caddr_t))); 141745633Swpaul CSR_WRITE_4(sc, RL_CUR_TXSTAT(sc), 141852426Swpaul RL_TXTHRESH(sc->rl_txthresh) | 141952426Swpaul RL_CUR_TXMBUF(sc)->m_pkthdr.len); 142045633Swpaul 142145633Swpaul RL_INC(sc->rl_cdata.cur_tx); 142240516Swpaul } 142340516Swpaul 142440516Swpaul /* 142545633Swpaul * We broke out of the loop because all our TX slots are 142645633Swpaul * full. Mark the NIC as busy until it drains some of the 142745633Swpaul * packets from the queue. 142845633Swpaul */ 142945633Swpaul if (RL_CUR_TXMBUF(sc) != NULL) 143045633Swpaul ifp->if_flags |= IFF_OACTIVE; 143145633Swpaul 143245633Swpaul /* 143340516Swpaul * Set a timeout in case the chip goes out to lunch. 143440516Swpaul */ 143540516Swpaul ifp->if_timer = 5; 143667087Swpaul RL_UNLOCK(sc); 143740516Swpaul 143840516Swpaul return; 143940516Swpaul} 144040516Swpaul 144140516Swpaulstatic void rl_init(xsc) 144240516Swpaul void *xsc; 144340516Swpaul{ 144440516Swpaul struct rl_softc *sc = xsc; 144540516Swpaul struct ifnet *ifp = &sc->arpcom.ac_if; 144650703Swpaul struct mii_data *mii; 144767087Swpaul int i; 144840516Swpaul u_int32_t rxcfg = 0; 144940516Swpaul 145067087Swpaul RL_LOCK(sc); 145150703Swpaul mii = device_get_softc(sc->rl_miibus); 145240516Swpaul 145340516Swpaul /* 145440516Swpaul * Cancel pending I/O and free all RX/TX buffers. 145540516Swpaul */ 145640516Swpaul rl_stop(sc); 145740516Swpaul 145840516Swpaul /* Init our MAC address */ 145940516Swpaul for (i = 0; i < ETHER_ADDR_LEN; i++) { 146040516Swpaul CSR_WRITE_1(sc, RL_IDR0 + i, sc->arpcom.ac_enaddr[i]); 146140516Swpaul } 146240516Swpaul 146340516Swpaul /* Init the RX buffer pointer register. */ 146440516Swpaul CSR_WRITE_4(sc, RL_RXADDR, vtophys(sc->rl_cdata.rl_rx_buf)); 146540516Swpaul 146640516Swpaul /* Init TX descriptors. */ 146740516Swpaul rl_list_tx_init(sc); 146840516Swpaul 146940516Swpaul /* 147040516Swpaul * Enable transmit and receive. 147140516Swpaul */ 147240516Swpaul CSR_WRITE_1(sc, RL_COMMAND, RL_CMD_TX_ENB|RL_CMD_RX_ENB); 147340516Swpaul 147440516Swpaul /* 147545633Swpaul * Set the initial TX and RX configuration. 147640516Swpaul */ 147745633Swpaul CSR_WRITE_4(sc, RL_TXCFG, RL_TXCFG_CONFIG); 147840516Swpaul CSR_WRITE_4(sc, RL_RXCFG, RL_RXCFG_CONFIG); 147940516Swpaul 148040516Swpaul /* Set the individual bit to receive frames for this host only. */ 148140516Swpaul rxcfg = CSR_READ_4(sc, RL_RXCFG); 148240516Swpaul rxcfg |= RL_RXCFG_RX_INDIV; 148340516Swpaul 148440516Swpaul /* If we want promiscuous mode, set the allframes bit. */ 148540516Swpaul if (ifp->if_flags & IFF_PROMISC) { 148640516Swpaul rxcfg |= RL_RXCFG_RX_ALLPHYS; 148740516Swpaul CSR_WRITE_4(sc, RL_RXCFG, rxcfg); 148840516Swpaul } else { 148940516Swpaul rxcfg &= ~RL_RXCFG_RX_ALLPHYS; 149040516Swpaul CSR_WRITE_4(sc, RL_RXCFG, rxcfg); 149140516Swpaul } 149240516Swpaul 149340516Swpaul /* 149440516Swpaul * Set capture broadcast bit to capture broadcast frames. 149540516Swpaul */ 149640516Swpaul if (ifp->if_flags & IFF_BROADCAST) { 149740516Swpaul rxcfg |= RL_RXCFG_RX_BROAD; 149840516Swpaul CSR_WRITE_4(sc, RL_RXCFG, rxcfg); 149940516Swpaul } else { 150040516Swpaul rxcfg &= ~RL_RXCFG_RX_BROAD; 150140516Swpaul CSR_WRITE_4(sc, RL_RXCFG, rxcfg); 150240516Swpaul } 150340516Swpaul 150440516Swpaul /* 150540516Swpaul * Program the multicast filter, if necessary. 150640516Swpaul */ 150740516Swpaul rl_setmulti(sc); 150840516Swpaul 150940516Swpaul /* 151040516Swpaul * Enable interrupts. 151140516Swpaul */ 151240516Swpaul CSR_WRITE_2(sc, RL_IMR, RL_INTRS); 151340516Swpaul 151452426Swpaul /* Set initial TX threshold */ 151552426Swpaul sc->rl_txthresh = RL_TX_THRESH_INIT; 151652426Swpaul 151740516Swpaul /* Start RX/TX process. */ 151840516Swpaul CSR_WRITE_4(sc, RL_MISSEDPKT, 0); 151940516Swpaul 152040516Swpaul /* Enable receiver and transmitter. */ 152140516Swpaul CSR_WRITE_1(sc, RL_COMMAND, RL_CMD_TX_ENB|RL_CMD_RX_ENB); 152240516Swpaul 152350703Swpaul mii_mediachg(mii); 152440516Swpaul 152540516Swpaul CSR_WRITE_1(sc, RL_CFG1, RL_CFG1_DRVLOAD|RL_CFG1_FULLDUPLEX); 152640516Swpaul 152740516Swpaul ifp->if_flags |= IFF_RUNNING; 152840516Swpaul ifp->if_flags &= ~IFF_OACTIVE; 152940516Swpaul 153050703Swpaul sc->rl_stat_ch = timeout(rl_tick, sc, hz); 153167087Swpaul RL_UNLOCK(sc); 153250703Swpaul 153340516Swpaul return; 153440516Swpaul} 153540516Swpaul 153640516Swpaul/* 153740516Swpaul * Set media options. 153840516Swpaul */ 153940516Swpaulstatic int rl_ifmedia_upd(ifp) 154040516Swpaul struct ifnet *ifp; 154140516Swpaul{ 154240516Swpaul struct rl_softc *sc; 154350703Swpaul struct mii_data *mii; 154440516Swpaul 154540516Swpaul sc = ifp->if_softc; 154650703Swpaul mii = device_get_softc(sc->rl_miibus); 154750703Swpaul mii_mediachg(mii); 154840516Swpaul 154940516Swpaul return(0); 155040516Swpaul} 155140516Swpaul 155240516Swpaul/* 155340516Swpaul * Report current media status. 155440516Swpaul */ 155540516Swpaulstatic void rl_ifmedia_sts(ifp, ifmr) 155640516Swpaul struct ifnet *ifp; 155740516Swpaul struct ifmediareq *ifmr; 155840516Swpaul{ 155940516Swpaul struct rl_softc *sc; 156050703Swpaul struct mii_data *mii; 156140516Swpaul 156240516Swpaul sc = ifp->if_softc; 156350703Swpaul mii = device_get_softc(sc->rl_miibus); 156440516Swpaul 156550703Swpaul mii_pollstat(mii); 156650703Swpaul ifmr->ifm_active = mii->mii_media_active; 156750703Swpaul ifmr->ifm_status = mii->mii_media_status; 156840516Swpaul 156940516Swpaul return; 157040516Swpaul} 157140516Swpaul 157240516Swpaulstatic int rl_ioctl(ifp, command, data) 157340516Swpaul struct ifnet *ifp; 157440516Swpaul u_long command; 157540516Swpaul caddr_t data; 157640516Swpaul{ 157740516Swpaul struct rl_softc *sc = ifp->if_softc; 157840516Swpaul struct ifreq *ifr = (struct ifreq *) data; 157950703Swpaul struct mii_data *mii; 158067087Swpaul int error = 0; 158140516Swpaul 158267087Swpaul RL_LOCK(sc); 158340516Swpaul 158440516Swpaul switch(command) { 158540516Swpaul case SIOCSIFADDR: 158640516Swpaul case SIOCGIFADDR: 158740516Swpaul case SIOCSIFMTU: 158840516Swpaul error = ether_ioctl(ifp, command, data); 158940516Swpaul break; 159040516Swpaul case SIOCSIFFLAGS: 159140516Swpaul if (ifp->if_flags & IFF_UP) { 159240516Swpaul rl_init(sc); 159340516Swpaul } else { 159440516Swpaul if (ifp->if_flags & IFF_RUNNING) 159540516Swpaul rl_stop(sc); 159640516Swpaul } 159740516Swpaul error = 0; 159840516Swpaul break; 159940516Swpaul case SIOCADDMULTI: 160040516Swpaul case SIOCDELMULTI: 160140516Swpaul rl_setmulti(sc); 160240516Swpaul error = 0; 160340516Swpaul break; 160440516Swpaul case SIOCGIFMEDIA: 160540516Swpaul case SIOCSIFMEDIA: 160650703Swpaul mii = device_get_softc(sc->rl_miibus); 160750703Swpaul error = ifmedia_ioctl(ifp, ifr, &mii->mii_media, command); 160840516Swpaul break; 160940516Swpaul default: 161040516Swpaul error = EINVAL; 161140516Swpaul break; 161240516Swpaul } 161340516Swpaul 161467087Swpaul RL_UNLOCK(sc); 161540516Swpaul 161640516Swpaul return(error); 161740516Swpaul} 161840516Swpaul 161940516Swpaulstatic void rl_watchdog(ifp) 162040516Swpaul struct ifnet *ifp; 162140516Swpaul{ 162240516Swpaul struct rl_softc *sc; 162340516Swpaul 162440516Swpaul sc = ifp->if_softc; 162567087Swpaul RL_LOCK(sc); 162640516Swpaul printf("rl%d: watchdog timeout\n", sc->rl_unit); 162740516Swpaul ifp->if_oerrors++; 162850703Swpaul 162940516Swpaul rl_txeof(sc); 163040516Swpaul rl_rxeof(sc); 163140516Swpaul rl_init(sc); 163267087Swpaul RL_UNLOCK(sc); 163340516Swpaul 163440516Swpaul return; 163540516Swpaul} 163640516Swpaul 163740516Swpaul/* 163840516Swpaul * Stop the adapter and free any mbufs allocated to the 163940516Swpaul * RX and TX lists. 164040516Swpaul */ 164140516Swpaulstatic void rl_stop(sc) 164240516Swpaul struct rl_softc *sc; 164340516Swpaul{ 164440516Swpaul register int i; 164540516Swpaul struct ifnet *ifp; 164640516Swpaul 164767087Swpaul RL_LOCK(sc); 164840516Swpaul ifp = &sc->arpcom.ac_if; 164940516Swpaul ifp->if_timer = 0; 165040516Swpaul 165150703Swpaul untimeout(rl_tick, sc, sc->rl_stat_ch); 165250703Swpaul 165340516Swpaul CSR_WRITE_1(sc, RL_COMMAND, 0x00); 165440516Swpaul CSR_WRITE_2(sc, RL_IMR, 0x0000); 165540516Swpaul 165640516Swpaul /* 165740516Swpaul * Free the TX list buffers. 165840516Swpaul */ 165940516Swpaul for (i = 0; i < RL_TX_LIST_CNT; i++) { 166045633Swpaul if (sc->rl_cdata.rl_tx_chain[i] != NULL) { 166145633Swpaul m_freem(sc->rl_cdata.rl_tx_chain[i]); 166245633Swpaul sc->rl_cdata.rl_tx_chain[i] = NULL; 166345633Swpaul CSR_WRITE_4(sc, RL_TXADDR0 + i, 0x0000000); 166440516Swpaul } 166540516Swpaul } 166640516Swpaul 166740516Swpaul ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE); 166867087Swpaul RL_UNLOCK(sc); 166940516Swpaul return; 167040516Swpaul} 167140516Swpaul 167240516Swpaul/* 167340516Swpaul * Stop all chip I/O so that the kernel's probe routines don't 167440516Swpaul * get confused by errant DMAs when rebooting. 167540516Swpaul */ 167650703Swpaulstatic void rl_shutdown(dev) 167750703Swpaul device_t dev; 167840516Swpaul{ 167950703Swpaul struct rl_softc *sc; 168040516Swpaul 168150703Swpaul sc = device_get_softc(dev); 168250703Swpaul 168340516Swpaul rl_stop(sc); 168440516Swpaul 168540516Swpaul return; 168640516Swpaul} 1687