if_rl.c revision 59758
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 59758 2000-04-29 13:41:57Z 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 8640516Swpaul#include <sys/param.h> 8740516Swpaul#include <sys/systm.h> 8840516Swpaul#include <sys/sockio.h> 8940516Swpaul#include <sys/mbuf.h> 9040516Swpaul#include <sys/malloc.h> 9140516Swpaul#include <sys/kernel.h> 9240516Swpaul#include <sys/socket.h> 9340516Swpaul 9440516Swpaul#include <net/if.h> 9540516Swpaul#include <net/if_arp.h> 9640516Swpaul#include <net/ethernet.h> 9740516Swpaul#include <net/if_dl.h> 9840516Swpaul#include <net/if_media.h> 9940516Swpaul 10040516Swpaul#include <net/bpf.h> 10140516Swpaul 10240516Swpaul#include <vm/vm.h> /* for vtophys */ 10340516Swpaul#include <vm/pmap.h> /* for vtophys */ 10440516Swpaul#include <machine/clock.h> /* for DELAY */ 10541569Swpaul#include <machine/bus_pio.h> 10641569Swpaul#include <machine/bus_memio.h> 10741569Swpaul#include <machine/bus.h> 10850703Swpaul#include <machine/resource.h> 10950703Swpaul#include <sys/bus.h> 11050703Swpaul#include <sys/rman.h> 11140516Swpaul 11250703Swpaul#include <dev/mii/mii.h> 11350703Swpaul#include <dev/mii/miivar.h> 11450703Swpaul 11540516Swpaul#include <pci/pcireg.h> 11640516Swpaul#include <pci/pcivar.h> 11740516Swpaul 11859758SpeterMODULE_DEPEND(rl, miibus, 1, 1, 1); 11959758Speter 12051089Speter/* "controller miibus0" required. See GENERIC if you get errors here. */ 12150703Swpaul#include "miibus_if.h" 12250703Swpaul 12340516Swpaul/* 12440516Swpaul * Default to using PIO access for this driver. On SMP systems, 12540516Swpaul * there appear to be problems with memory mapped mode: it looks like 12640516Swpaul * doing too many memory mapped access back to back in rapid succession 12740516Swpaul * can hang the bus. I'm inclined to blame this on crummy design/construction 12840516Swpaul * on the part of RealTek. Memory mapped mode does appear to work on 12940516Swpaul * uniprocessor systems though. 13040516Swpaul */ 13140516Swpaul#define RL_USEIOSPACE 13240516Swpaul 13340516Swpaul#include <pci/if_rlreg.h> 13440516Swpaul 13540516Swpaul#ifndef lint 13641591Sarchiestatic const char rcsid[] = 13750477Speter "$FreeBSD: head/sys/pci/if_rl.c 59758 2000-04-29 13:41:57Z peter $"; 13840516Swpaul#endif 13940516Swpaul 14040516Swpaul/* 14140516Swpaul * Various supported device vendors/types and their names. 14240516Swpaul */ 14340516Swpaulstatic struct rl_type rl_devs[] = { 14440516Swpaul { RT_VENDORID, RT_DEVICEID_8129, 14540516Swpaul "RealTek 8129 10/100BaseTX" }, 14640516Swpaul { RT_VENDORID, RT_DEVICEID_8139, 14740516Swpaul "RealTek 8139 10/100BaseTX" }, 14841243Swpaul { ACCTON_VENDORID, ACCTON_DEVICEID_5030, 14941243Swpaul "Accton MPX 5030/5038 10/100BaseTX" }, 15044238Swpaul { DELTA_VENDORID, DELTA_DEVICEID_8139, 15144238Swpaul "Delta Electronics 8139 10/100BaseTX" }, 15244238Swpaul { ADDTRON_VENDORID, ADDTRON_DEVICEID_8139, 15344238Swpaul "Addtron Technolgy 8139 10/100BaseTX" }, 15440516Swpaul { 0, 0, NULL } 15540516Swpaul}; 15640516Swpaul 15750703Swpaulstatic int rl_probe __P((device_t)); 15850703Swpaulstatic int rl_attach __P((device_t)); 15950703Swpaulstatic int rl_detach __P((device_t)); 16040516Swpaul 16145633Swpaulstatic int rl_encap __P((struct rl_softc *, struct mbuf * )); 16240516Swpaul 16340516Swpaulstatic void rl_rxeof __P((struct rl_softc *)); 16440516Swpaulstatic void rl_txeof __P((struct rl_softc *)); 16540516Swpaulstatic void rl_intr __P((void *)); 16650703Swpaulstatic void rl_tick __P((void *)); 16740516Swpaulstatic void rl_start __P((struct ifnet *)); 16840516Swpaulstatic int rl_ioctl __P((struct ifnet *, u_long, caddr_t)); 16940516Swpaulstatic void rl_init __P((void *)); 17040516Swpaulstatic void rl_stop __P((struct rl_softc *)); 17140516Swpaulstatic void rl_watchdog __P((struct ifnet *)); 17250703Swpaulstatic void rl_shutdown __P((device_t)); 17340516Swpaulstatic int rl_ifmedia_upd __P((struct ifnet *)); 17440516Swpaulstatic void rl_ifmedia_sts __P((struct ifnet *, struct ifmediareq *)); 17540516Swpaul 17641656Swpaulstatic void rl_eeprom_putbyte __P((struct rl_softc *, int)); 17741656Swpaulstatic void rl_eeprom_getword __P((struct rl_softc *, int, u_int16_t *)); 17840516Swpaulstatic void rl_read_eeprom __P((struct rl_softc *, caddr_t, 17940516Swpaul int, int, int)); 18040516Swpaulstatic void rl_mii_sync __P((struct rl_softc *)); 18140516Swpaulstatic void rl_mii_send __P((struct rl_softc *, u_int32_t, int)); 18240516Swpaulstatic int rl_mii_readreg __P((struct rl_softc *, struct rl_mii_frame *)); 18340516Swpaulstatic int rl_mii_writereg __P((struct rl_softc *, struct rl_mii_frame *)); 18440516Swpaul 18550703Swpaulstatic int rl_miibus_readreg __P((device_t, int, int)); 18650703Swpaulstatic int rl_miibus_writereg __P((device_t, int, int, int)); 18750703Swpaulstatic void rl_miibus_statchg __P((device_t)); 18840516Swpaul 18941656Swpaulstatic u_int8_t rl_calchash __P((caddr_t)); 19040516Swpaulstatic void rl_setmulti __P((struct rl_softc *)); 19140516Swpaulstatic void rl_reset __P((struct rl_softc *)); 19240516Swpaulstatic int rl_list_tx_init __P((struct rl_softc *)); 19340516Swpaul 19450703Swpaul#ifdef RL_USEIOSPACE 19550703Swpaul#define RL_RES SYS_RES_IOPORT 19650703Swpaul#define RL_RID RL_PCI_LOIO 19750703Swpaul#else 19850703Swpaul#define RL_RES SYS_RES_MEMORY 19950703Swpaul#define RL_RID RL_PCI_LOMEM 20050703Swpaul#endif 20150703Swpaul 20250703Swpaulstatic device_method_t rl_methods[] = { 20350703Swpaul /* Device interface */ 20450703Swpaul DEVMETHOD(device_probe, rl_probe), 20550703Swpaul DEVMETHOD(device_attach, rl_attach), 20650703Swpaul DEVMETHOD(device_detach, rl_detach), 20750703Swpaul DEVMETHOD(device_shutdown, rl_shutdown), 20850703Swpaul 20950703Swpaul /* bus interface */ 21050703Swpaul DEVMETHOD(bus_print_child, bus_generic_print_child), 21150703Swpaul DEVMETHOD(bus_driver_added, bus_generic_driver_added), 21250703Swpaul 21350703Swpaul /* MII interface */ 21450703Swpaul DEVMETHOD(miibus_readreg, rl_miibus_readreg), 21550703Swpaul DEVMETHOD(miibus_writereg, rl_miibus_writereg), 21650703Swpaul DEVMETHOD(miibus_statchg, rl_miibus_statchg), 21750703Swpaul 21850703Swpaul { 0, 0 } 21950703Swpaul}; 22050703Swpaul 22150703Swpaulstatic driver_t rl_driver = { 22251455Swpaul "rl", 22350703Swpaul rl_methods, 22450703Swpaul sizeof(struct rl_softc) 22550703Swpaul}; 22650703Swpaul 22750703Swpaulstatic devclass_t rl_devclass; 22850703Swpaul 22951533SwpaulDRIVER_MODULE(if_rl, pci, rl_driver, rl_devclass, 0, 0); 23051473SwpaulDRIVER_MODULE(miibus, rl, miibus_driver, miibus_devclass, 0, 0); 23150703Swpaul 23240516Swpaul#define EE_SET(x) \ 23340516Swpaul CSR_WRITE_1(sc, RL_EECMD, \ 23440516Swpaul CSR_READ_1(sc, RL_EECMD) | x) 23540516Swpaul 23640516Swpaul#define EE_CLR(x) \ 23740516Swpaul CSR_WRITE_1(sc, RL_EECMD, \ 23840516Swpaul CSR_READ_1(sc, RL_EECMD) & ~x) 23940516Swpaul 24040516Swpaul/* 24140516Swpaul * Send a read command and address to the EEPROM, check for ACK. 24240516Swpaul */ 24340516Swpaulstatic void rl_eeprom_putbyte(sc, addr) 24440516Swpaul struct rl_softc *sc; 24541656Swpaul int addr; 24640516Swpaul{ 24740516Swpaul register int d, i; 24840516Swpaul 24940516Swpaul d = addr | RL_EECMD_READ; 25040516Swpaul 25140516Swpaul /* 25255170Sbillf * Feed in each bit and strobe the clock. 25340516Swpaul */ 25440516Swpaul for (i = 0x400; i; i >>= 1) { 25540516Swpaul if (d & i) { 25640516Swpaul EE_SET(RL_EE_DATAIN); 25740516Swpaul } else { 25840516Swpaul EE_CLR(RL_EE_DATAIN); 25940516Swpaul } 26040516Swpaul DELAY(100); 26140516Swpaul EE_SET(RL_EE_CLK); 26240516Swpaul DELAY(150); 26340516Swpaul EE_CLR(RL_EE_CLK); 26440516Swpaul DELAY(100); 26540516Swpaul } 26640516Swpaul 26740516Swpaul return; 26840516Swpaul} 26940516Swpaul 27040516Swpaul/* 27140516Swpaul * Read a word of data stored in the EEPROM at address 'addr.' 27240516Swpaul */ 27340516Swpaulstatic void rl_eeprom_getword(sc, addr, dest) 27440516Swpaul struct rl_softc *sc; 27541656Swpaul int addr; 27640516Swpaul u_int16_t *dest; 27740516Swpaul{ 27840516Swpaul register int i; 27940516Swpaul u_int16_t word = 0; 28040516Swpaul 28140516Swpaul /* Enter EEPROM access mode. */ 28240516Swpaul CSR_WRITE_1(sc, RL_EECMD, RL_EEMODE_PROGRAM|RL_EE_SEL); 28340516Swpaul 28440516Swpaul /* 28540516Swpaul * Send address of word we want to read. 28640516Swpaul */ 28740516Swpaul rl_eeprom_putbyte(sc, addr); 28840516Swpaul 28940516Swpaul CSR_WRITE_1(sc, RL_EECMD, RL_EEMODE_PROGRAM|RL_EE_SEL); 29040516Swpaul 29140516Swpaul /* 29240516Swpaul * Start reading bits from EEPROM. 29340516Swpaul */ 29440516Swpaul for (i = 0x8000; i; i >>= 1) { 29540516Swpaul EE_SET(RL_EE_CLK); 29640516Swpaul DELAY(100); 29740516Swpaul if (CSR_READ_1(sc, RL_EECMD) & RL_EE_DATAOUT) 29840516Swpaul word |= i; 29940516Swpaul EE_CLR(RL_EE_CLK); 30040516Swpaul DELAY(100); 30140516Swpaul } 30240516Swpaul 30340516Swpaul /* Turn off EEPROM access mode. */ 30440516Swpaul CSR_WRITE_1(sc, RL_EECMD, RL_EEMODE_OFF); 30540516Swpaul 30640516Swpaul *dest = word; 30740516Swpaul 30840516Swpaul return; 30940516Swpaul} 31040516Swpaul 31140516Swpaul/* 31240516Swpaul * Read a sequence of words from the EEPROM. 31340516Swpaul */ 31440516Swpaulstatic void rl_read_eeprom(sc, dest, off, cnt, swap) 31540516Swpaul struct rl_softc *sc; 31640516Swpaul caddr_t dest; 31740516Swpaul int off; 31840516Swpaul int cnt; 31940516Swpaul int swap; 32040516Swpaul{ 32140516Swpaul int i; 32240516Swpaul u_int16_t word = 0, *ptr; 32340516Swpaul 32440516Swpaul for (i = 0; i < cnt; i++) { 32540516Swpaul rl_eeprom_getword(sc, off + i, &word); 32640516Swpaul ptr = (u_int16_t *)(dest + (i * 2)); 32740516Swpaul if (swap) 32840516Swpaul *ptr = ntohs(word); 32940516Swpaul else 33040516Swpaul *ptr = word; 33140516Swpaul } 33240516Swpaul 33340516Swpaul return; 33440516Swpaul} 33540516Swpaul 33640516Swpaul 33740516Swpaul/* 33840516Swpaul * MII access routines are provided for the 8129, which 33940516Swpaul * doesn't have a built-in PHY. For the 8139, we fake things 34040516Swpaul * up by diverting rl_phy_readreg()/rl_phy_writereg() to the 34140516Swpaul * direct access PHY registers. 34240516Swpaul */ 34340516Swpaul#define MII_SET(x) \ 34440516Swpaul CSR_WRITE_1(sc, RL_MII, \ 34540516Swpaul CSR_READ_1(sc, RL_MII) | x) 34640516Swpaul 34740516Swpaul#define MII_CLR(x) \ 34840516Swpaul CSR_WRITE_1(sc, RL_MII, \ 34940516Swpaul CSR_READ_1(sc, RL_MII) & ~x) 35040516Swpaul 35140516Swpaul/* 35240516Swpaul * Sync the PHYs by setting data bit and strobing the clock 32 times. 35340516Swpaul */ 35440516Swpaulstatic void rl_mii_sync(sc) 35540516Swpaul struct rl_softc *sc; 35640516Swpaul{ 35740516Swpaul register int i; 35840516Swpaul 35940516Swpaul MII_SET(RL_MII_DIR|RL_MII_DATAOUT); 36040516Swpaul 36140516Swpaul for (i = 0; i < 32; i++) { 36240516Swpaul MII_SET(RL_MII_CLK); 36340516Swpaul DELAY(1); 36440516Swpaul MII_CLR(RL_MII_CLK); 36540516Swpaul DELAY(1); 36640516Swpaul } 36740516Swpaul 36840516Swpaul return; 36940516Swpaul} 37040516Swpaul 37140516Swpaul/* 37240516Swpaul * Clock a series of bits through the MII. 37340516Swpaul */ 37440516Swpaulstatic void rl_mii_send(sc, bits, cnt) 37540516Swpaul struct rl_softc *sc; 37640516Swpaul u_int32_t bits; 37740516Swpaul int cnt; 37840516Swpaul{ 37940516Swpaul int i; 38040516Swpaul 38140516Swpaul MII_CLR(RL_MII_CLK); 38240516Swpaul 38340516Swpaul for (i = (0x1 << (cnt - 1)); i; i >>= 1) { 38440516Swpaul if (bits & i) { 38540516Swpaul MII_SET(RL_MII_DATAOUT); 38640516Swpaul } else { 38740516Swpaul MII_CLR(RL_MII_DATAOUT); 38840516Swpaul } 38940516Swpaul DELAY(1); 39040516Swpaul MII_CLR(RL_MII_CLK); 39140516Swpaul DELAY(1); 39240516Swpaul MII_SET(RL_MII_CLK); 39340516Swpaul } 39440516Swpaul} 39540516Swpaul 39640516Swpaul/* 39740516Swpaul * Read an PHY register through the MII. 39840516Swpaul */ 39940516Swpaulstatic int rl_mii_readreg(sc, frame) 40040516Swpaul struct rl_softc *sc; 40140516Swpaul struct rl_mii_frame *frame; 40240516Swpaul 40340516Swpaul{ 40440516Swpaul int i, ack, s; 40540516Swpaul 40640516Swpaul s = splimp(); 40740516Swpaul 40840516Swpaul /* 40940516Swpaul * Set up frame for RX. 41040516Swpaul */ 41140516Swpaul frame->mii_stdelim = RL_MII_STARTDELIM; 41240516Swpaul frame->mii_opcode = RL_MII_READOP; 41340516Swpaul frame->mii_turnaround = 0; 41440516Swpaul frame->mii_data = 0; 41540516Swpaul 41640516Swpaul CSR_WRITE_2(sc, RL_MII, 0); 41740516Swpaul 41840516Swpaul /* 41940516Swpaul * Turn on data xmit. 42040516Swpaul */ 42140516Swpaul MII_SET(RL_MII_DIR); 42240516Swpaul 42340516Swpaul rl_mii_sync(sc); 42440516Swpaul 42540516Swpaul /* 42640516Swpaul * Send command/address info. 42740516Swpaul */ 42840516Swpaul rl_mii_send(sc, frame->mii_stdelim, 2); 42940516Swpaul rl_mii_send(sc, frame->mii_opcode, 2); 43040516Swpaul rl_mii_send(sc, frame->mii_phyaddr, 5); 43140516Swpaul rl_mii_send(sc, frame->mii_regaddr, 5); 43240516Swpaul 43340516Swpaul /* Idle bit */ 43440516Swpaul MII_CLR((RL_MII_CLK|RL_MII_DATAOUT)); 43540516Swpaul DELAY(1); 43640516Swpaul MII_SET(RL_MII_CLK); 43740516Swpaul DELAY(1); 43840516Swpaul 43940516Swpaul /* Turn off xmit. */ 44040516Swpaul MII_CLR(RL_MII_DIR); 44140516Swpaul 44240516Swpaul /* Check for ack */ 44340516Swpaul MII_CLR(RL_MII_CLK); 44440516Swpaul DELAY(1); 44540516Swpaul MII_SET(RL_MII_CLK); 44640516Swpaul DELAY(1); 44740516Swpaul ack = CSR_READ_2(sc, RL_MII) & RL_MII_DATAIN; 44840516Swpaul 44940516Swpaul /* 45040516Swpaul * Now try reading data bits. If the ack failed, we still 45140516Swpaul * need to clock through 16 cycles to keep the PHY(s) in sync. 45240516Swpaul */ 45340516Swpaul if (ack) { 45440516Swpaul for(i = 0; i < 16; i++) { 45540516Swpaul MII_CLR(RL_MII_CLK); 45640516Swpaul DELAY(1); 45740516Swpaul MII_SET(RL_MII_CLK); 45840516Swpaul DELAY(1); 45940516Swpaul } 46040516Swpaul goto fail; 46140516Swpaul } 46240516Swpaul 46340516Swpaul for (i = 0x8000; i; i >>= 1) { 46440516Swpaul MII_CLR(RL_MII_CLK); 46540516Swpaul DELAY(1); 46640516Swpaul if (!ack) { 46740516Swpaul if (CSR_READ_2(sc, RL_MII) & RL_MII_DATAIN) 46840516Swpaul frame->mii_data |= i; 46940516Swpaul DELAY(1); 47040516Swpaul } 47140516Swpaul MII_SET(RL_MII_CLK); 47240516Swpaul DELAY(1); 47340516Swpaul } 47440516Swpaul 47540516Swpaulfail: 47640516Swpaul 47740516Swpaul MII_CLR(RL_MII_CLK); 47840516Swpaul DELAY(1); 47940516Swpaul MII_SET(RL_MII_CLK); 48040516Swpaul DELAY(1); 48140516Swpaul 48240516Swpaul splx(s); 48340516Swpaul 48440516Swpaul if (ack) 48540516Swpaul return(1); 48640516Swpaul return(0); 48740516Swpaul} 48840516Swpaul 48940516Swpaul/* 49040516Swpaul * Write to a PHY register through the MII. 49140516Swpaul */ 49240516Swpaulstatic int rl_mii_writereg(sc, frame) 49340516Swpaul struct rl_softc *sc; 49440516Swpaul struct rl_mii_frame *frame; 49540516Swpaul 49640516Swpaul{ 49740516Swpaul int s; 49840516Swpaul 49940516Swpaul s = splimp(); 50040516Swpaul /* 50140516Swpaul * Set up frame for TX. 50240516Swpaul */ 50340516Swpaul 50440516Swpaul frame->mii_stdelim = RL_MII_STARTDELIM; 50540516Swpaul frame->mii_opcode = RL_MII_WRITEOP; 50640516Swpaul frame->mii_turnaround = RL_MII_TURNAROUND; 50740516Swpaul 50840516Swpaul /* 50940516Swpaul * Turn on data output. 51040516Swpaul */ 51140516Swpaul MII_SET(RL_MII_DIR); 51240516Swpaul 51340516Swpaul rl_mii_sync(sc); 51440516Swpaul 51540516Swpaul rl_mii_send(sc, frame->mii_stdelim, 2); 51640516Swpaul rl_mii_send(sc, frame->mii_opcode, 2); 51740516Swpaul rl_mii_send(sc, frame->mii_phyaddr, 5); 51840516Swpaul rl_mii_send(sc, frame->mii_regaddr, 5); 51940516Swpaul rl_mii_send(sc, frame->mii_turnaround, 2); 52040516Swpaul rl_mii_send(sc, frame->mii_data, 16); 52140516Swpaul 52240516Swpaul /* Idle bit. */ 52340516Swpaul MII_SET(RL_MII_CLK); 52440516Swpaul DELAY(1); 52540516Swpaul MII_CLR(RL_MII_CLK); 52640516Swpaul DELAY(1); 52740516Swpaul 52840516Swpaul /* 52940516Swpaul * Turn off xmit. 53040516Swpaul */ 53140516Swpaul MII_CLR(RL_MII_DIR); 53240516Swpaul 53340516Swpaul splx(s); 53440516Swpaul 53540516Swpaul return(0); 53640516Swpaul} 53740516Swpaul 53850703Swpaulstatic int rl_miibus_readreg(dev, phy, reg) 53950703Swpaul device_t dev; 54050703Swpaul int phy, reg; 54150703Swpaul{ 54240516Swpaul struct rl_softc *sc; 54340516Swpaul struct rl_mii_frame frame; 54440516Swpaul u_int16_t rval = 0; 54540516Swpaul u_int16_t rl8139_reg = 0; 54640516Swpaul 54750703Swpaul sc = device_get_softc(dev); 54850703Swpaul 54940516Swpaul if (sc->rl_type == RL_8139) { 55050703Swpaul /* Pretend the internal PHY is only at address 0 */ 55150703Swpaul if (phy) 55250703Swpaul return(0); 55340516Swpaul switch(reg) { 55450703Swpaul case MII_BMCR: 55540516Swpaul rl8139_reg = RL_BMCR; 55640516Swpaul break; 55750703Swpaul case MII_BMSR: 55840516Swpaul rl8139_reg = RL_BMSR; 55940516Swpaul break; 56050703Swpaul case MII_ANAR: 56140516Swpaul rl8139_reg = RL_ANAR; 56240516Swpaul break; 56350703Swpaul case MII_ANER: 56450703Swpaul rl8139_reg = RL_ANER; 56550703Swpaul break; 56650703Swpaul case MII_ANLPAR: 56740516Swpaul rl8139_reg = RL_LPAR; 56840516Swpaul break; 56950703Swpaul case MII_PHYIDR1: 57050703Swpaul case MII_PHYIDR2: 57150703Swpaul return(0); 57250703Swpaul break; 57340516Swpaul default: 57440516Swpaul printf("rl%d: bad phy register\n", sc->rl_unit); 57540516Swpaul return(0); 57640516Swpaul } 57740516Swpaul rval = CSR_READ_2(sc, rl8139_reg); 57840516Swpaul return(rval); 57940516Swpaul } 58040516Swpaul 58140516Swpaul bzero((char *)&frame, sizeof(frame)); 58240516Swpaul 58350703Swpaul frame.mii_phyaddr = phy; 58440516Swpaul frame.mii_regaddr = reg; 58540516Swpaul rl_mii_readreg(sc, &frame); 58640516Swpaul 58740516Swpaul return(frame.mii_data); 58840516Swpaul} 58940516Swpaul 59050703Swpaulstatic int rl_miibus_writereg(dev, phy, reg, data) 59150703Swpaul device_t dev; 59250703Swpaul int phy, reg, data; 59350703Swpaul{ 59440516Swpaul struct rl_softc *sc; 59540516Swpaul struct rl_mii_frame frame; 59640516Swpaul u_int16_t rl8139_reg = 0; 59740516Swpaul 59850703Swpaul sc = device_get_softc(dev); 59950703Swpaul 60040516Swpaul if (sc->rl_type == RL_8139) { 60150703Swpaul /* Pretend the internal PHY is only at address 0 */ 60250703Swpaul if (phy) 60350703Swpaul return(0); 60440516Swpaul switch(reg) { 60550703Swpaul case MII_BMCR: 60640516Swpaul rl8139_reg = RL_BMCR; 60740516Swpaul break; 60850703Swpaul case MII_BMSR: 60940516Swpaul rl8139_reg = RL_BMSR; 61040516Swpaul break; 61150703Swpaul case MII_ANAR: 61240516Swpaul rl8139_reg = RL_ANAR; 61340516Swpaul break; 61450703Swpaul case MII_ANER: 61550703Swpaul rl8139_reg = RL_ANER; 61650703Swpaul break; 61750703Swpaul case MII_ANLPAR: 61840516Swpaul rl8139_reg = RL_LPAR; 61940516Swpaul break; 62050703Swpaul case MII_PHYIDR1: 62150703Swpaul case MII_PHYIDR2: 62250703Swpaul return(0); 62350703Swpaul break; 62440516Swpaul default: 62540516Swpaul printf("rl%d: bad phy register\n", sc->rl_unit); 62650703Swpaul return(0); 62740516Swpaul } 62840516Swpaul CSR_WRITE_2(sc, rl8139_reg, data); 62950703Swpaul return(0); 63040516Swpaul } 63140516Swpaul 63240516Swpaul bzero((char *)&frame, sizeof(frame)); 63340516Swpaul 63450703Swpaul frame.mii_phyaddr = phy; 63540516Swpaul frame.mii_regaddr = reg; 63640516Swpaul frame.mii_data = data; 63740516Swpaul 63840516Swpaul rl_mii_writereg(sc, &frame); 63940516Swpaul 64050703Swpaul return(0); 64150703Swpaul} 64250703Swpaul 64350703Swpaulstatic void rl_miibus_statchg(dev) 64450703Swpaul device_t dev; 64550703Swpaul{ 64640516Swpaul return; 64740516Swpaul} 64840516Swpaul 64940516Swpaul/* 65043062Swpaul * Calculate CRC of a multicast group address, return the upper 6 bits. 65140516Swpaul */ 65240516Swpaulstatic u_int8_t rl_calchash(addr) 65341656Swpaul caddr_t addr; 65440516Swpaul{ 65540516Swpaul u_int32_t crc, carry; 65640516Swpaul int i, j; 65740516Swpaul u_int8_t c; 65840516Swpaul 65940516Swpaul /* Compute CRC for the address value. */ 66040516Swpaul crc = 0xFFFFFFFF; /* initial value */ 66140516Swpaul 66240516Swpaul for (i = 0; i < 6; i++) { 66340516Swpaul c = *(addr + i); 66440516Swpaul for (j = 0; j < 8; j++) { 66540516Swpaul carry = ((crc & 0x80000000) ? 1 : 0) ^ (c & 0x01); 66640516Swpaul crc <<= 1; 66740516Swpaul c >>= 1; 66840516Swpaul if (carry) 66940516Swpaul crc = (crc ^ 0x04c11db6) | carry; 67040516Swpaul } 67140516Swpaul } 67240516Swpaul 67340516Swpaul /* return the filter bit position */ 67443062Swpaul return(crc >> 26); 67540516Swpaul} 67640516Swpaul 67740516Swpaul/* 67840516Swpaul * Program the 64-bit multicast hash filter. 67940516Swpaul */ 68040516Swpaulstatic void rl_setmulti(sc) 68140516Swpaul struct rl_softc *sc; 68240516Swpaul{ 68340516Swpaul struct ifnet *ifp; 68440516Swpaul int h = 0; 68540516Swpaul u_int32_t hashes[2] = { 0, 0 }; 68640516Swpaul struct ifmultiaddr *ifma; 68740516Swpaul u_int32_t rxfilt; 68840516Swpaul int mcnt = 0; 68940516Swpaul 69040516Swpaul ifp = &sc->arpcom.ac_if; 69140516Swpaul 69240516Swpaul rxfilt = CSR_READ_4(sc, RL_RXCFG); 69340516Swpaul 69443062Swpaul if (ifp->if_flags & IFF_ALLMULTI || ifp->if_flags & IFF_PROMISC) { 69540516Swpaul rxfilt |= RL_RXCFG_RX_MULTI; 69640516Swpaul CSR_WRITE_4(sc, RL_RXCFG, rxfilt); 69740516Swpaul CSR_WRITE_4(sc, RL_MAR0, 0xFFFFFFFF); 69840516Swpaul CSR_WRITE_4(sc, RL_MAR4, 0xFFFFFFFF); 69940516Swpaul return; 70040516Swpaul } 70140516Swpaul 70240516Swpaul /* first, zot all the existing hash bits */ 70340516Swpaul CSR_WRITE_4(sc, RL_MAR0, 0); 70440516Swpaul CSR_WRITE_4(sc, RL_MAR4, 0); 70540516Swpaul 70640516Swpaul /* now program new ones */ 70740516Swpaul for (ifma = ifp->if_multiaddrs.lh_first; ifma != NULL; 70840516Swpaul ifma = ifma->ifma_link.le_next) { 70940516Swpaul if (ifma->ifma_addr->sa_family != AF_LINK) 71040516Swpaul continue; 71140516Swpaul h = rl_calchash(LLADDR((struct sockaddr_dl *)ifma->ifma_addr)); 71240516Swpaul if (h < 32) 71340516Swpaul hashes[0] |= (1 << h); 71440516Swpaul else 71540516Swpaul hashes[1] |= (1 << (h - 32)); 71640516Swpaul mcnt++; 71740516Swpaul } 71840516Swpaul 71940516Swpaul if (mcnt) 72040516Swpaul rxfilt |= RL_RXCFG_RX_MULTI; 72140516Swpaul else 72240516Swpaul rxfilt &= ~RL_RXCFG_RX_MULTI; 72340516Swpaul 72440516Swpaul CSR_WRITE_4(sc, RL_RXCFG, rxfilt); 72540516Swpaul CSR_WRITE_4(sc, RL_MAR0, hashes[0]); 72640516Swpaul CSR_WRITE_4(sc, RL_MAR4, hashes[1]); 72740516Swpaul 72840516Swpaul return; 72940516Swpaul} 73040516Swpaul 73140516Swpaulstatic void rl_reset(sc) 73240516Swpaul struct rl_softc *sc; 73340516Swpaul{ 73440516Swpaul register int i; 73540516Swpaul 73640516Swpaul CSR_WRITE_1(sc, RL_COMMAND, RL_CMD_RESET); 73740516Swpaul 73840516Swpaul for (i = 0; i < RL_TIMEOUT; i++) { 73940516Swpaul DELAY(10); 74040516Swpaul if (!(CSR_READ_1(sc, RL_COMMAND) & RL_CMD_RESET)) 74140516Swpaul break; 74240516Swpaul } 74340516Swpaul if (i == RL_TIMEOUT) 74440516Swpaul printf("rl%d: reset never completed!\n", sc->rl_unit); 74540516Swpaul 74640516Swpaul return; 74740516Swpaul} 74840516Swpaul 74940516Swpaul/* 75040516Swpaul * Probe for a RealTek 8129/8139 chip. Check the PCI vendor and device 75140516Swpaul * IDs against our list and return a device name if we find a match. 75240516Swpaul */ 75350703Swpaulstatic int rl_probe(dev) 75450703Swpaul device_t dev; 75540516Swpaul{ 75640516Swpaul struct rl_type *t; 75740516Swpaul 75840516Swpaul t = rl_devs; 75940516Swpaul 76040516Swpaul while(t->rl_name != NULL) { 76150703Swpaul if ((pci_get_vendor(dev) == t->rl_vid) && 76250703Swpaul (pci_get_device(dev) == t->rl_did)) { 76350703Swpaul device_set_desc(dev, t->rl_name); 76450703Swpaul return(0); 76540516Swpaul } 76640516Swpaul t++; 76740516Swpaul } 76840516Swpaul 76950703Swpaul return(ENXIO); 77040516Swpaul} 77140516Swpaul 77240516Swpaul/* 77340516Swpaul * Attach the interface. Allocate softc structures, do ifmedia 77440516Swpaul * setup and ethernet/BPF attach. 77540516Swpaul */ 77650703Swpaulstatic int rl_attach(dev) 77750703Swpaul device_t dev; 77840516Swpaul{ 77950703Swpaul int s; 78040516Swpaul u_char eaddr[ETHER_ADDR_LEN]; 78140516Swpaul u_int32_t command; 78240516Swpaul struct rl_softc *sc; 78340516Swpaul struct ifnet *ifp; 78440516Swpaul u_int16_t rl_did = 0; 78550703Swpaul int unit, error = 0, rid; 78640516Swpaul 78740516Swpaul s = splimp(); 78840516Swpaul 78950703Swpaul sc = device_get_softc(dev); 79050703Swpaul unit = device_get_unit(dev); 79140516Swpaul bzero(sc, sizeof(struct rl_softc)); 79240516Swpaul 79340516Swpaul /* 79440516Swpaul * Handle power management nonsense. 79540516Swpaul */ 79640516Swpaul 79750703Swpaul command = pci_read_config(dev, RL_PCI_CAPID, 4) & 0x000000FF; 79840516Swpaul if (command == 0x01) { 79940516Swpaul 80050703Swpaul command = pci_read_config(dev, RL_PCI_PWRMGMTCTRL, 4); 80140516Swpaul if (command & RL_PSTATE_MASK) { 80240516Swpaul u_int32_t iobase, membase, irq; 80340516Swpaul 80440516Swpaul /* Save important PCI config data. */ 80550703Swpaul iobase = pci_read_config(dev, RL_PCI_LOIO, 4); 80650703Swpaul membase = pci_read_config(dev, RL_PCI_LOMEM, 4); 80750703Swpaul irq = pci_read_config(dev, RL_PCI_INTLINE, 4); 80840516Swpaul 80940516Swpaul /* Reset the power state. */ 81040516Swpaul printf("rl%d: chip is is in D%d power mode " 81140516Swpaul "-- setting to D0\n", unit, command & RL_PSTATE_MASK); 81240516Swpaul command &= 0xFFFFFFFC; 81350703Swpaul pci_write_config(dev, RL_PCI_PWRMGMTCTRL, command, 4); 81440516Swpaul 81540516Swpaul /* Restore PCI config data. */ 81650703Swpaul pci_write_config(dev, RL_PCI_LOIO, iobase, 4); 81750703Swpaul pci_write_config(dev, RL_PCI_LOMEM, membase, 4); 81850703Swpaul pci_write_config(dev, RL_PCI_INTLINE, irq, 4); 81940516Swpaul } 82040516Swpaul } 82140516Swpaul 82240516Swpaul /* 82340516Swpaul * Map control/status registers. 82440516Swpaul */ 82550703Swpaul command = pci_read_config(dev, PCI_COMMAND_STATUS_REG, 4); 82640516Swpaul command |= (PCIM_CMD_PORTEN|PCIM_CMD_MEMEN|PCIM_CMD_BUSMASTEREN); 82750703Swpaul pci_write_config(dev, PCI_COMMAND_STATUS_REG, command, 4); 82850703Swpaul command = pci_read_config(dev, PCI_COMMAND_STATUS_REG, 4); 82940516Swpaul 83040516Swpaul#ifdef RL_USEIOSPACE 83140516Swpaul if (!(command & PCIM_CMD_PORTEN)) { 83240516Swpaul printf("rl%d: failed to enable I/O ports!\n", unit); 83350703Swpaul error = ENXIO; 83440516Swpaul goto fail; 83540516Swpaul } 83640516Swpaul#else 83740516Swpaul if (!(command & PCIM_CMD_MEMEN)) { 83840516Swpaul printf("rl%d: failed to enable memory mapping!\n", unit); 83950703Swpaul error = ENXIO; 84040516Swpaul goto fail; 84140516Swpaul } 84250703Swpaul#endif 84340516Swpaul 84450703Swpaul rid = RL_RID; 84550703Swpaul sc->rl_res = bus_alloc_resource(dev, RL_RES, &rid, 84650703Swpaul 0, ~0, 1, RF_ACTIVE); 84750703Swpaul 84850703Swpaul if (sc->rl_res == NULL) { 84950703Swpaul printf ("rl%d: couldn't map ports/memory\n", unit); 85050703Swpaul error = ENXIO; 85140516Swpaul goto fail; 85240516Swpaul } 85340516Swpaul 85450703Swpaul sc->rl_btag = rman_get_bustag(sc->rl_res); 85550703Swpaul sc->rl_bhandle = rman_get_bushandle(sc->rl_res); 85650703Swpaul 85750703Swpaul rid = 0; 85850703Swpaul sc->rl_irq = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, 0, ~0, 1, 85950703Swpaul RF_SHAREABLE | RF_ACTIVE); 86050703Swpaul 86150703Swpaul if (sc->rl_irq == NULL) { 86240516Swpaul printf("rl%d: couldn't map interrupt\n", unit); 86350703Swpaul bus_release_resource(dev, RL_RES, RL_RID, sc->rl_res); 86450703Swpaul error = ENXIO; 86540516Swpaul goto fail; 86640516Swpaul } 86740516Swpaul 86850703Swpaul error = bus_setup_intr(dev, sc->rl_irq, INTR_TYPE_NET, 86950703Swpaul rl_intr, sc, &sc->rl_intrhand); 87050703Swpaul 87150703Swpaul if (error) { 87250703Swpaul bus_release_resource(dev, SYS_RES_IRQ, 0, sc->rl_res); 87350703Swpaul bus_release_resource(dev, RL_RES, RL_RID, sc->rl_res); 87450703Swpaul printf("rl%d: couldn't set up irq\n", unit); 87550703Swpaul goto fail; 87650703Swpaul } 87750703Swpaul 87850703Swpaul callout_handle_init(&sc->rl_stat_ch); 87950703Swpaul 88040516Swpaul /* Reset the adapter. */ 88140516Swpaul rl_reset(sc); 88240516Swpaul 88340516Swpaul /* 88440516Swpaul * Get station address from the EEPROM. 88540516Swpaul */ 88640516Swpaul rl_read_eeprom(sc, (caddr_t)&eaddr, RL_EE_EADDR, 3, 0); 88740516Swpaul 88840516Swpaul /* 88940516Swpaul * A RealTek chip was detected. Inform the world. 89040516Swpaul */ 89140516Swpaul printf("rl%d: Ethernet address: %6D\n", unit, eaddr, ":"); 89240516Swpaul 89340516Swpaul sc->rl_unit = unit; 89440516Swpaul bcopy(eaddr, (char *)&sc->arpcom.ac_enaddr, ETHER_ADDR_LEN); 89540516Swpaul 89640516Swpaul /* 89740516Swpaul * Now read the exact device type from the EEPROM to find 89840516Swpaul * out if it's an 8129 or 8139. 89940516Swpaul */ 90040516Swpaul rl_read_eeprom(sc, (caddr_t)&rl_did, RL_EE_PCI_DID, 1, 0); 90140516Swpaul 90244238Swpaul if (rl_did == RT_DEVICEID_8139 || rl_did == ACCTON_DEVICEID_5030 || 90349001Swpaul rl_did == DELTA_DEVICEID_8139 || rl_did == ADDTRON_DEVICEID_8139) 90440516Swpaul sc->rl_type = RL_8139; 90540516Swpaul else if (rl_did == RT_DEVICEID_8129) 90640516Swpaul sc->rl_type = RL_8129; 90740516Swpaul else { 90840516Swpaul printf("rl%d: unknown device ID: %x\n", unit, rl_did); 90950703Swpaul bus_teardown_intr(dev, sc->rl_irq, sc->rl_intrhand); 91050703Swpaul bus_release_resource(dev, SYS_RES_IRQ, 0, sc->rl_res); 91150703Swpaul bus_release_resource(dev, RL_RES, RL_RID, sc->rl_res); 91250703Swpaul error = ENXIO; 91340516Swpaul goto fail; 91440516Swpaul } 91540516Swpaul 91648028Swpaul sc->rl_cdata.rl_rx_buf = contigmalloc(RL_RXBUFLEN + 32, M_DEVBUF, 91751657Swpaul M_NOWAIT, 0, 0xffffffff, PAGE_SIZE, 0); 91840516Swpaul 91940516Swpaul if (sc->rl_cdata.rl_rx_buf == NULL) { 92040516Swpaul printf("rl%d: no memory for list buffers!\n", unit); 92150703Swpaul bus_teardown_intr(dev, sc->rl_irq, sc->rl_intrhand); 92250703Swpaul bus_release_resource(dev, SYS_RES_IRQ, 0, sc->rl_res); 92350703Swpaul bus_release_resource(dev, RL_RES, RL_RID, sc->rl_res); 92450703Swpaul error = ENXIO; 92540516Swpaul goto fail; 92640516Swpaul } 92740516Swpaul 92848028Swpaul /* Leave a few bytes before the start of the RX ring buffer. */ 92948028Swpaul sc->rl_cdata.rl_rx_buf_ptr = sc->rl_cdata.rl_rx_buf; 93048028Swpaul sc->rl_cdata.rl_rx_buf += sizeof(u_int64_t); 93148028Swpaul 93250703Swpaul /* Do MII setup */ 93350703Swpaul if (mii_phy_probe(dev, &sc->rl_miibus, 93450703Swpaul rl_ifmedia_upd, rl_ifmedia_sts)) { 93550703Swpaul printf("rl%d: MII without any phy!\n", sc->rl_unit); 93650703Swpaul bus_teardown_intr(dev, sc->rl_irq, sc->rl_intrhand); 93750703Swpaul bus_release_resource(dev, SYS_RES_IRQ, 0, sc->rl_res); 93850703Swpaul bus_release_resource(dev, RL_RES, RL_RID, sc->rl_res); 93950703Swpaul free(sc->rl_cdata.rl_rx_buf, M_DEVBUF); 94050703Swpaul error = ENXIO; 94150703Swpaul goto fail; 94250703Swpaul } 94350703Swpaul 94440516Swpaul ifp = &sc->arpcom.ac_if; 94540516Swpaul ifp->if_softc = sc; 94640516Swpaul ifp->if_unit = unit; 94740516Swpaul ifp->if_name = "rl"; 94840516Swpaul ifp->if_mtu = ETHERMTU; 94940516Swpaul ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 95040516Swpaul ifp->if_ioctl = rl_ioctl; 95140516Swpaul ifp->if_output = ether_output; 95240516Swpaul ifp->if_start = rl_start; 95340516Swpaul ifp->if_watchdog = rl_watchdog; 95440516Swpaul ifp->if_init = rl_init; 95540516Swpaul ifp->if_baudrate = 10000000; 95645633Swpaul ifp->if_snd.ifq_maxlen = IFQ_MAXLEN; 95740516Swpaul 95840516Swpaul /* 95940516Swpaul * Call MI attach routines. 96040516Swpaul */ 96140516Swpaul if_attach(ifp); 96240516Swpaul ether_ifattach(ifp); 96340516Swpaul 96440516Swpaul bpfattach(ifp, DLT_EN10MB, sizeof(struct ether_header)); 96540516Swpaul 96640516Swpaulfail: 96740516Swpaul splx(s); 96850703Swpaul return(error); 96940516Swpaul} 97040516Swpaul 97150703Swpaulstatic int rl_detach(dev) 97250703Swpaul device_t dev; 97350703Swpaul{ 97450703Swpaul struct rl_softc *sc; 97550703Swpaul struct ifnet *ifp; 97650703Swpaul int s; 97750703Swpaul 97850703Swpaul s = splimp(); 97950703Swpaul 98050703Swpaul sc = device_get_softc(dev); 98150703Swpaul ifp = &sc->arpcom.ac_if; 98250703Swpaul 98350703Swpaul if_detach(ifp); 98450703Swpaul rl_stop(sc); 98550703Swpaul 98650703Swpaul bus_generic_detach(dev); 98750703Swpaul device_delete_child(dev, sc->rl_miibus); 98850703Swpaul 98950703Swpaul bus_teardown_intr(dev, sc->rl_irq, sc->rl_intrhand); 99050703Swpaul bus_release_resource(dev, SYS_RES_IRQ, 0, sc->rl_res); 99150703Swpaul bus_release_resource(dev, RL_RES, RL_RID, sc->rl_res); 99250703Swpaul 99352426Swpaul contigfree(sc->rl_cdata.rl_rx_buf, RL_RXBUFLEN + 32, M_DEVBUF); 99450703Swpaul 99550703Swpaul splx(s); 99650703Swpaul 99750703Swpaul return(0); 99850703Swpaul} 99950703Swpaul 100040516Swpaul/* 100140516Swpaul * Initialize the transmit descriptors. 100240516Swpaul */ 100340516Swpaulstatic int rl_list_tx_init(sc) 100440516Swpaul struct rl_softc *sc; 100540516Swpaul{ 100640516Swpaul struct rl_chain_data *cd; 100740516Swpaul int i; 100840516Swpaul 100940516Swpaul cd = &sc->rl_cdata; 101040516Swpaul for (i = 0; i < RL_TX_LIST_CNT; i++) { 101145633Swpaul cd->rl_tx_chain[i] = NULL; 101248028Swpaul CSR_WRITE_4(sc, 101348028Swpaul RL_TXADDR0 + (i * sizeof(u_int32_t)), 0x0000000); 101440516Swpaul } 101540516Swpaul 101645633Swpaul sc->rl_cdata.cur_tx = 0; 101745633Swpaul sc->rl_cdata.last_tx = 0; 101840516Swpaul 101940516Swpaul return(0); 102040516Swpaul} 102140516Swpaul 102240516Swpaul/* 102340516Swpaul * A frame has been uploaded: pass the resulting mbuf chain up to 102440516Swpaul * the higher level protocols. 102540516Swpaul * 102640516Swpaul * You know there's something wrong with a PCI bus-master chip design 102740516Swpaul * when you have to use m_devget(). 102840516Swpaul * 102940516Swpaul * The receive operation is badly documented in the datasheet, so I'll 103040516Swpaul * attempt to document it here. The driver provides a buffer area and 103140516Swpaul * places its base address in the RX buffer start address register. 103240516Swpaul * The chip then begins copying frames into the RX buffer. Each frame 103340516Swpaul * is preceeded by a 32-bit RX status word which specifies the length 103440516Swpaul * of the frame and certain other status bits. Each frame (starting with 103540516Swpaul * the status word) is also 32-bit aligned. The frame length is in the 103640516Swpaul * first 16 bits of the status word; the lower 15 bits correspond with 103740516Swpaul * the 'rx status register' mentioned in the datasheet. 103848028Swpaul * 103948028Swpaul * Note: to make the Alpha happy, the frame payload needs to be aligned 104048028Swpaul * on a 32-bit boundary. To achieve this, we cheat a bit by copying from 104148028Swpaul * the ring buffer starting at an address two bytes before the actual 104248028Swpaul * data location. We can then shave off the first two bytes using m_adj(). 104348028Swpaul * The reason we do this is because m_devget() doesn't let us specify an 104448028Swpaul * offset into the mbuf storage space, so we have to artificially create 104548028Swpaul * one. The ring is allocated in such a way that there are a few unused 104648028Swpaul * bytes of space preceecing it so that it will be safe for us to do the 104748028Swpaul * 2-byte backstep even if reading from the ring at offset 0. 104840516Swpaul */ 104940516Swpaulstatic void rl_rxeof(sc) 105040516Swpaul struct rl_softc *sc; 105140516Swpaul{ 105240516Swpaul struct ether_header *eh; 105340516Swpaul struct mbuf *m; 105440516Swpaul struct ifnet *ifp; 105540516Swpaul int total_len = 0; 105640516Swpaul u_int32_t rxstat; 105740516Swpaul caddr_t rxbufpos; 105840516Swpaul int wrap = 0; 105940516Swpaul u_int16_t cur_rx; 106040516Swpaul u_int16_t limit; 106140516Swpaul u_int16_t rx_bytes = 0, max_bytes; 106240516Swpaul 106340516Swpaul ifp = &sc->arpcom.ac_if; 106440516Swpaul 106540516Swpaul cur_rx = (CSR_READ_2(sc, RL_CURRXADDR) + 16) % RL_RXBUFLEN; 106640516Swpaul 106740516Swpaul /* Do not try to read past this point. */ 106840516Swpaul limit = CSR_READ_2(sc, RL_CURRXBUF) % RL_RXBUFLEN; 106940516Swpaul 107040516Swpaul if (limit < cur_rx) 107140516Swpaul max_bytes = (RL_RXBUFLEN - cur_rx) + limit; 107240516Swpaul else 107340516Swpaul max_bytes = limit - cur_rx; 107440516Swpaul 107542738Swpaul while((CSR_READ_1(sc, RL_COMMAND) & RL_CMD_EMPTY_RXBUF) == 0) { 107640516Swpaul rxbufpos = sc->rl_cdata.rl_rx_buf + cur_rx; 107740516Swpaul rxstat = *(u_int32_t *)rxbufpos; 107840516Swpaul 107940516Swpaul /* 108040516Swpaul * Here's a totally undocumented fact for you. When the 108140516Swpaul * RealTek chip is in the process of copying a packet into 108240516Swpaul * RAM for you, the length will be 0xfff0. If you spot a 108340516Swpaul * packet header with this value, you need to stop. The 108440516Swpaul * datasheet makes absolutely no mention of this and 108540516Swpaul * RealTek should be shot for this. 108640516Swpaul */ 108740516Swpaul if ((u_int16_t)(rxstat >> 16) == RL_RXSTAT_UNFINISHED) 108840516Swpaul break; 108940516Swpaul 109040516Swpaul if (!(rxstat & RL_RXSTAT_RXOK)) { 109140516Swpaul ifp->if_ierrors++; 109250703Swpaul rl_init(sc); 109350703Swpaul return; 109440516Swpaul } 109540516Swpaul 109640516Swpaul /* No errors; receive the packet. */ 109740516Swpaul total_len = rxstat >> 16; 109840516Swpaul rx_bytes += total_len + 4; 109940516Swpaul 110040516Swpaul /* 110142051Swpaul * XXX The RealTek chip includes the CRC with every 110242051Swpaul * received frame, and there's no way to turn this 110342051Swpaul * behavior off (at least, I can't find anything in 110442051Swpaul * the manual that explains how to do it) so we have 110542051Swpaul * to trim off the CRC manually. 110642051Swpaul */ 110742051Swpaul total_len -= ETHER_CRC_LEN; 110842051Swpaul 110942051Swpaul /* 111040516Swpaul * Avoid trying to read more bytes than we know 111140516Swpaul * the chip has prepared for us. 111240516Swpaul */ 111340516Swpaul if (rx_bytes > max_bytes) 111440516Swpaul break; 111540516Swpaul 111640516Swpaul rxbufpos = sc->rl_cdata.rl_rx_buf + 111740516Swpaul ((cur_rx + sizeof(u_int32_t)) % RL_RXBUFLEN); 111840516Swpaul 111940516Swpaul if (rxbufpos == (sc->rl_cdata.rl_rx_buf + RL_RXBUFLEN)) 112040516Swpaul rxbufpos = sc->rl_cdata.rl_rx_buf; 112140516Swpaul 112240516Swpaul wrap = (sc->rl_cdata.rl_rx_buf + RL_RXBUFLEN) - rxbufpos; 112340516Swpaul 112440516Swpaul if (total_len > wrap) { 112548028Swpaul m = m_devget(rxbufpos - RL_ETHER_ALIGN, 112648028Swpaul wrap + RL_ETHER_ALIGN, 0, ifp, NULL); 112740516Swpaul if (m == NULL) { 112840516Swpaul ifp->if_ierrors++; 112940516Swpaul printf("rl%d: out of mbufs, tried to " 113052426Swpaul "copy %d bytes\n", sc->rl_unit, wrap); 113152426Swpaul } else { 113248028Swpaul m_adj(m, RL_ETHER_ALIGN); 113340516Swpaul m_copyback(m, wrap, total_len - wrap, 113440516Swpaul sc->rl_cdata.rl_rx_buf); 113558801Swpaul if (m->m_len < sizeof(struct ether_header)) 113658801Swpaul m = m_pullup(m, 113758801Swpaul sizeof(struct ether_header)); 113855058Swpaul if (m == NULL) { 113955058Swpaul printf("rl%d: m_pullup failed", 114055058Swpaul sc->rl_unit); 114155058Swpaul ifp->if_ierrors++; 114255058Swpaul } 114348028Swpaul } 114442051Swpaul cur_rx = (total_len - wrap + ETHER_CRC_LEN); 114540516Swpaul } else { 114648028Swpaul m = m_devget(rxbufpos - RL_ETHER_ALIGN, 114748028Swpaul total_len + RL_ETHER_ALIGN, 0, ifp, NULL); 114840516Swpaul if (m == NULL) { 114940516Swpaul ifp->if_ierrors++; 115040516Swpaul printf("rl%d: out of mbufs, tried to " 115152426Swpaul "copy %d bytes\n", sc->rl_unit, total_len); 115248028Swpaul } else 115348028Swpaul m_adj(m, RL_ETHER_ALIGN); 115442051Swpaul cur_rx += total_len + 4 + ETHER_CRC_LEN; 115540516Swpaul } 115640516Swpaul 115740516Swpaul /* 115840516Swpaul * Round up to 32-bit boundary. 115940516Swpaul */ 116040516Swpaul cur_rx = (cur_rx + 3) & ~3; 116140516Swpaul CSR_WRITE_2(sc, RL_CURRXADDR, cur_rx - 16); 116240516Swpaul 116340516Swpaul if (m == NULL) 116440516Swpaul continue; 116540516Swpaul 116640516Swpaul eh = mtod(m, struct ether_header *); 116740516Swpaul ifp->if_ipackets++; 116840516Swpaul 116940516Swpaul /* 117040516Swpaul * Handle BPF listeners. Let the BPF user see the packet, but 117140516Swpaul * don't pass it up to the ether_input() layer unless it's 117240516Swpaul * a broadcast packet, multicast packet, matches our ethernet 117340516Swpaul * address or the interface is in promiscuous mode. 117440516Swpaul */ 117540516Swpaul if (ifp->if_bpf) { 117640516Swpaul bpf_mtap(ifp, m); 117740516Swpaul if (ifp->if_flags & IFF_PROMISC && 117840516Swpaul (bcmp(eh->ether_dhost, sc->arpcom.ac_enaddr, 117940516Swpaul ETHER_ADDR_LEN) && 118040516Swpaul (eh->ether_dhost[0] & 1) == 0)) { 118140516Swpaul m_freem(m); 118240516Swpaul continue; 118340516Swpaul } 118440516Swpaul } 118551583Swpaul 118640516Swpaul /* Remove header from mbuf and pass it on. */ 118740516Swpaul m_adj(m, sizeof(struct ether_header)); 118840516Swpaul ether_input(ifp, eh, m); 118940516Swpaul } 119040516Swpaul 119140516Swpaul return; 119240516Swpaul} 119340516Swpaul 119440516Swpaul/* 119540516Swpaul * A frame was downloaded to the chip. It's safe for us to clean up 119640516Swpaul * the list buffers. 119740516Swpaul */ 119840516Swpaulstatic void rl_txeof(sc) 119940516Swpaul struct rl_softc *sc; 120040516Swpaul{ 120140516Swpaul struct ifnet *ifp; 120240516Swpaul u_int32_t txstat; 120340516Swpaul 120440516Swpaul ifp = &sc->arpcom.ac_if; 120540516Swpaul 120640516Swpaul /* Clear the timeout timer. */ 120740516Swpaul ifp->if_timer = 0; 120840516Swpaul 120940516Swpaul /* 121040516Swpaul * Go through our tx list and free mbufs for those 121140516Swpaul * frames that have been uploaded. 121240516Swpaul */ 121345633Swpaul do { 121445633Swpaul txstat = CSR_READ_4(sc, RL_LAST_TXSTAT(sc)); 121545633Swpaul if (!(txstat & (RL_TXSTAT_TX_OK| 121645633Swpaul RL_TXSTAT_TX_UNDERRUN|RL_TXSTAT_TXABRT))) 121740516Swpaul break; 121840516Swpaul 121945633Swpaul ifp->if_collisions += (txstat & RL_TXSTAT_COLLCNT) >> 24; 122040516Swpaul 122145633Swpaul if (RL_LAST_TXMBUF(sc) != NULL) { 122245633Swpaul m_freem(RL_LAST_TXMBUF(sc)); 122345633Swpaul RL_LAST_TXMBUF(sc) = NULL; 122445633Swpaul } 122545633Swpaul if (txstat & RL_TXSTAT_TX_OK) 122645633Swpaul ifp->if_opackets++; 122745633Swpaul else { 122852426Swpaul int oldthresh; 122945633Swpaul ifp->if_oerrors++; 123045633Swpaul if ((txstat & RL_TXSTAT_TXABRT) || 123145633Swpaul (txstat & RL_TXSTAT_OUTOFWIN)) 123245633Swpaul CSR_WRITE_4(sc, RL_TXCFG, RL_TXCFG_CONFIG); 123352426Swpaul oldthresh = sc->rl_txthresh; 123452426Swpaul /* error recovery */ 123552426Swpaul rl_reset(sc); 123652426Swpaul rl_init(sc); 123752426Swpaul /* 123852426Swpaul * If there was a transmit underrun, 123952426Swpaul * bump the TX threshold. 124052426Swpaul */ 124152426Swpaul if (txstat & RL_TXSTAT_TX_UNDERRUN) 124252426Swpaul sc->rl_txthresh = oldthresh + 32; 124352426Swpaul return; 124445633Swpaul } 124545633Swpaul RL_INC(sc->rl_cdata.last_tx); 124645633Swpaul ifp->if_flags &= ~IFF_OACTIVE; 124745633Swpaul } while (sc->rl_cdata.last_tx != sc->rl_cdata.cur_tx); 124840516Swpaul 124950703Swpaul return; 125050703Swpaul} 125140516Swpaul 125250703Swpaulstatic void rl_tick(xsc) 125350703Swpaul void *xsc; 125450703Swpaul{ 125550703Swpaul struct rl_softc *sc; 125650703Swpaul struct mii_data *mii; 125750703Swpaul int s; 125850703Swpaul 125950703Swpaul s = splimp(); 126050703Swpaul 126150703Swpaul sc = xsc; 126250703Swpaul mii = device_get_softc(sc->rl_miibus); 126350703Swpaul 126450703Swpaul mii_tick(mii); 126550703Swpaul 126650703Swpaul splx(s); 126750703Swpaul 126850703Swpaul sc->rl_stat_ch = timeout(rl_tick, sc, hz); 126950703Swpaul 127040516Swpaul return; 127140516Swpaul} 127240516Swpaul 127340516Swpaulstatic void rl_intr(arg) 127440516Swpaul void *arg; 127540516Swpaul{ 127640516Swpaul struct rl_softc *sc; 127740516Swpaul struct ifnet *ifp; 127840516Swpaul u_int16_t status; 127940516Swpaul 128040516Swpaul sc = arg; 128140516Swpaul ifp = &sc->arpcom.ac_if; 128240516Swpaul 128340516Swpaul /* Disable interrupts. */ 128440516Swpaul CSR_WRITE_2(sc, RL_IMR, 0x0000); 128540516Swpaul 128640516Swpaul for (;;) { 128740516Swpaul 128840516Swpaul status = CSR_READ_2(sc, RL_ISR); 128940516Swpaul if (status) 129040516Swpaul CSR_WRITE_2(sc, RL_ISR, status); 129140516Swpaul 129240516Swpaul if ((status & RL_INTRS) == 0) 129340516Swpaul break; 129440516Swpaul 129540516Swpaul if (status & RL_ISR_RX_OK) 129640516Swpaul rl_rxeof(sc); 129740516Swpaul 129840516Swpaul if (status & RL_ISR_RX_ERR) 129940516Swpaul rl_rxeof(sc); 130040516Swpaul 130145633Swpaul if ((status & RL_ISR_TX_OK) || (status & RL_ISR_TX_ERR)) 130240516Swpaul rl_txeof(sc); 130340516Swpaul 130440516Swpaul if (status & RL_ISR_SYSTEM_ERR) { 130540516Swpaul rl_reset(sc); 130640516Swpaul rl_init(sc); 130740516Swpaul } 130840516Swpaul 130940516Swpaul } 131040516Swpaul 131140516Swpaul /* Re-enable interrupts. */ 131240516Swpaul CSR_WRITE_2(sc, RL_IMR, RL_INTRS); 131340516Swpaul 131452426Swpaul if (ifp->if_snd.ifq_head != NULL) 131540516Swpaul rl_start(ifp); 131640516Swpaul 131740516Swpaul return; 131840516Swpaul} 131940516Swpaul 132040516Swpaul/* 132140516Swpaul * Encapsulate an mbuf chain in a descriptor by coupling the mbuf data 132240516Swpaul * pointers to the fragment pointers. 132340516Swpaul */ 132445633Swpaulstatic int rl_encap(sc, m_head) 132540516Swpaul struct rl_softc *sc; 132640516Swpaul struct mbuf *m_head; 132740516Swpaul{ 132841243Swpaul struct mbuf *m_new = NULL; 132940516Swpaul 133040516Swpaul /* 133145633Swpaul * The RealTek is brain damaged and wants longword-aligned 133245633Swpaul * TX buffers, plus we can only have one fragment buffer 133345633Swpaul * per packet. We have to copy pretty much all the time. 133440516Swpaul */ 133540516Swpaul 133641243Swpaul MGETHDR(m_new, M_DONTWAIT, MT_DATA); 133741243Swpaul if (m_new == NULL) { 133841243Swpaul printf("rl%d: no memory for tx list", sc->rl_unit); 133941243Swpaul return(1); 134041243Swpaul } 134141243Swpaul if (m_head->m_pkthdr.len > MHLEN) { 134241243Swpaul MCLGET(m_new, M_DONTWAIT); 134341243Swpaul if (!(m_new->m_flags & M_EXT)) { 134441243Swpaul m_freem(m_new); 134541243Swpaul printf("rl%d: no memory for tx list", 134641243Swpaul sc->rl_unit); 134740516Swpaul return(1); 134840516Swpaul } 134940516Swpaul } 135052426Swpaul m_copydata(m_head, 0, m_head->m_pkthdr.len, mtod(m_new, caddr_t)); 135141243Swpaul m_new->m_pkthdr.len = m_new->m_len = m_head->m_pkthdr.len; 135241243Swpaul m_freem(m_head); 135341243Swpaul m_head = m_new; 135440516Swpaul 135540516Swpaul /* Pad frames to at least 60 bytes. */ 135641243Swpaul if (m_head->m_pkthdr.len < RL_MIN_FRAMELEN) { 135755058Swpaul /* 135855058Swpaul * Make security concious people happy: zero out the 135955058Swpaul * bytes in the pad area, since we don't know what 136055058Swpaul * this mbuf cluster buffer's previous user might 136155058Swpaul * have left in it. 136255058Swpaul */ 136355058Swpaul bzero(mtod(m_head, char *) + m_head->m_pkthdr.len, 136455058Swpaul RL_MIN_FRAMELEN - m_head->m_pkthdr.len); 136540516Swpaul m_head->m_pkthdr.len += 136652426Swpaul (RL_MIN_FRAMELEN - m_head->m_pkthdr.len); 136741243Swpaul m_head->m_len = m_head->m_pkthdr.len; 136841243Swpaul } 136940516Swpaul 137045633Swpaul RL_CUR_TXMBUF(sc) = m_head; 137140516Swpaul 137240516Swpaul return(0); 137340516Swpaul} 137440516Swpaul 137540516Swpaul/* 137640516Swpaul * Main transmit routine. 137740516Swpaul */ 137840516Swpaul 137940516Swpaulstatic void rl_start(ifp) 138040516Swpaul struct ifnet *ifp; 138140516Swpaul{ 138240516Swpaul struct rl_softc *sc; 138340516Swpaul struct mbuf *m_head = NULL; 138440516Swpaul 138540516Swpaul sc = ifp->if_softc; 138640516Swpaul 138745633Swpaul while(RL_CUR_TXMBUF(sc) == NULL) { 138840516Swpaul IF_DEQUEUE(&ifp->if_snd, m_head); 138940516Swpaul if (m_head == NULL) 139040516Swpaul break; 139140516Swpaul 139258801Swpaul if (rl_encap(sc, m_head)) { 139358801Swpaul IF_PREPEND(&ifp->if_snd, m_head); 139458801Swpaul ifp->if_flags |= IFF_OACTIVE; 139558801Swpaul break; 139658801Swpaul } 139740516Swpaul 139840516Swpaul /* 139940516Swpaul * If there's a BPF listener, bounce a copy of this frame 140040516Swpaul * to him. 140140516Swpaul */ 140240516Swpaul if (ifp->if_bpf) 140345633Swpaul bpf_mtap(ifp, RL_CUR_TXMBUF(sc)); 140451583Swpaul 140540516Swpaul /* 140640516Swpaul * Transmit the frame. 140740516Swpaul */ 140845633Swpaul CSR_WRITE_4(sc, RL_CUR_TXADDR(sc), 140945633Swpaul vtophys(mtod(RL_CUR_TXMBUF(sc), caddr_t))); 141045633Swpaul CSR_WRITE_4(sc, RL_CUR_TXSTAT(sc), 141152426Swpaul RL_TXTHRESH(sc->rl_txthresh) | 141252426Swpaul RL_CUR_TXMBUF(sc)->m_pkthdr.len); 141345633Swpaul 141445633Swpaul RL_INC(sc->rl_cdata.cur_tx); 141540516Swpaul } 141640516Swpaul 141740516Swpaul /* 141845633Swpaul * We broke out of the loop because all our TX slots are 141945633Swpaul * full. Mark the NIC as busy until it drains some of the 142045633Swpaul * packets from the queue. 142145633Swpaul */ 142245633Swpaul if (RL_CUR_TXMBUF(sc) != NULL) 142345633Swpaul ifp->if_flags |= IFF_OACTIVE; 142445633Swpaul 142545633Swpaul /* 142640516Swpaul * Set a timeout in case the chip goes out to lunch. 142740516Swpaul */ 142840516Swpaul ifp->if_timer = 5; 142940516Swpaul 143040516Swpaul return; 143140516Swpaul} 143240516Swpaul 143340516Swpaulstatic void rl_init(xsc) 143440516Swpaul void *xsc; 143540516Swpaul{ 143640516Swpaul struct rl_softc *sc = xsc; 143740516Swpaul struct ifnet *ifp = &sc->arpcom.ac_if; 143850703Swpaul struct mii_data *mii; 143940516Swpaul int s, i; 144040516Swpaul u_int32_t rxcfg = 0; 144140516Swpaul 144240516Swpaul s = splimp(); 144340516Swpaul 144450703Swpaul mii = device_get_softc(sc->rl_miibus); 144540516Swpaul 144640516Swpaul /* 144740516Swpaul * Cancel pending I/O and free all RX/TX buffers. 144840516Swpaul */ 144940516Swpaul rl_stop(sc); 145040516Swpaul 145140516Swpaul /* Init our MAC address */ 145240516Swpaul for (i = 0; i < ETHER_ADDR_LEN; i++) { 145340516Swpaul CSR_WRITE_1(sc, RL_IDR0 + i, sc->arpcom.ac_enaddr[i]); 145440516Swpaul } 145540516Swpaul 145640516Swpaul /* Init the RX buffer pointer register. */ 145740516Swpaul CSR_WRITE_4(sc, RL_RXADDR, vtophys(sc->rl_cdata.rl_rx_buf)); 145840516Swpaul 145940516Swpaul /* Init TX descriptors. */ 146040516Swpaul rl_list_tx_init(sc); 146140516Swpaul 146240516Swpaul /* 146340516Swpaul * Enable transmit and receive. 146440516Swpaul */ 146540516Swpaul CSR_WRITE_1(sc, RL_COMMAND, RL_CMD_TX_ENB|RL_CMD_RX_ENB); 146640516Swpaul 146740516Swpaul /* 146845633Swpaul * Set the initial TX and RX configuration. 146940516Swpaul */ 147045633Swpaul CSR_WRITE_4(sc, RL_TXCFG, RL_TXCFG_CONFIG); 147140516Swpaul CSR_WRITE_4(sc, RL_RXCFG, RL_RXCFG_CONFIG); 147240516Swpaul 147340516Swpaul /* Set the individual bit to receive frames for this host only. */ 147440516Swpaul rxcfg = CSR_READ_4(sc, RL_RXCFG); 147540516Swpaul rxcfg |= RL_RXCFG_RX_INDIV; 147640516Swpaul 147740516Swpaul /* If we want promiscuous mode, set the allframes bit. */ 147840516Swpaul if (ifp->if_flags & IFF_PROMISC) { 147940516Swpaul rxcfg |= RL_RXCFG_RX_ALLPHYS; 148040516Swpaul CSR_WRITE_4(sc, RL_RXCFG, rxcfg); 148140516Swpaul } else { 148240516Swpaul rxcfg &= ~RL_RXCFG_RX_ALLPHYS; 148340516Swpaul CSR_WRITE_4(sc, RL_RXCFG, rxcfg); 148440516Swpaul } 148540516Swpaul 148640516Swpaul /* 148740516Swpaul * Set capture broadcast bit to capture broadcast frames. 148840516Swpaul */ 148940516Swpaul if (ifp->if_flags & IFF_BROADCAST) { 149040516Swpaul rxcfg |= RL_RXCFG_RX_BROAD; 149140516Swpaul CSR_WRITE_4(sc, RL_RXCFG, rxcfg); 149240516Swpaul } else { 149340516Swpaul rxcfg &= ~RL_RXCFG_RX_BROAD; 149440516Swpaul CSR_WRITE_4(sc, RL_RXCFG, rxcfg); 149540516Swpaul } 149640516Swpaul 149740516Swpaul /* 149840516Swpaul * Program the multicast filter, if necessary. 149940516Swpaul */ 150040516Swpaul rl_setmulti(sc); 150140516Swpaul 150240516Swpaul /* 150340516Swpaul * Enable interrupts. 150440516Swpaul */ 150540516Swpaul CSR_WRITE_2(sc, RL_IMR, RL_INTRS); 150640516Swpaul 150752426Swpaul /* Set initial TX threshold */ 150852426Swpaul sc->rl_txthresh = RL_TX_THRESH_INIT; 150952426Swpaul 151040516Swpaul /* Start RX/TX process. */ 151140516Swpaul CSR_WRITE_4(sc, RL_MISSEDPKT, 0); 151240516Swpaul 151340516Swpaul /* Enable receiver and transmitter. */ 151440516Swpaul CSR_WRITE_1(sc, RL_COMMAND, RL_CMD_TX_ENB|RL_CMD_RX_ENB); 151540516Swpaul 151650703Swpaul mii_mediachg(mii); 151740516Swpaul 151840516Swpaul CSR_WRITE_1(sc, RL_CFG1, RL_CFG1_DRVLOAD|RL_CFG1_FULLDUPLEX); 151940516Swpaul 152040516Swpaul ifp->if_flags |= IFF_RUNNING; 152140516Swpaul ifp->if_flags &= ~IFF_OACTIVE; 152240516Swpaul 152340516Swpaul (void)splx(s); 152440516Swpaul 152550703Swpaul sc->rl_stat_ch = timeout(rl_tick, sc, hz); 152650703Swpaul 152740516Swpaul return; 152840516Swpaul} 152940516Swpaul 153040516Swpaul/* 153140516Swpaul * Set media options. 153240516Swpaul */ 153340516Swpaulstatic int rl_ifmedia_upd(ifp) 153440516Swpaul struct ifnet *ifp; 153540516Swpaul{ 153640516Swpaul struct rl_softc *sc; 153750703Swpaul struct mii_data *mii; 153840516Swpaul 153940516Swpaul sc = ifp->if_softc; 154050703Swpaul mii = device_get_softc(sc->rl_miibus); 154150703Swpaul mii_mediachg(mii); 154240516Swpaul 154340516Swpaul return(0); 154440516Swpaul} 154540516Swpaul 154640516Swpaul/* 154740516Swpaul * Report current media status. 154840516Swpaul */ 154940516Swpaulstatic void rl_ifmedia_sts(ifp, ifmr) 155040516Swpaul struct ifnet *ifp; 155140516Swpaul struct ifmediareq *ifmr; 155240516Swpaul{ 155340516Swpaul struct rl_softc *sc; 155450703Swpaul struct mii_data *mii; 155540516Swpaul 155640516Swpaul sc = ifp->if_softc; 155750703Swpaul mii = device_get_softc(sc->rl_miibus); 155840516Swpaul 155950703Swpaul mii_pollstat(mii); 156050703Swpaul ifmr->ifm_active = mii->mii_media_active; 156150703Swpaul ifmr->ifm_status = mii->mii_media_status; 156240516Swpaul 156340516Swpaul return; 156440516Swpaul} 156540516Swpaul 156640516Swpaulstatic int rl_ioctl(ifp, command, data) 156740516Swpaul struct ifnet *ifp; 156840516Swpaul u_long command; 156940516Swpaul caddr_t data; 157040516Swpaul{ 157140516Swpaul struct rl_softc *sc = ifp->if_softc; 157240516Swpaul struct ifreq *ifr = (struct ifreq *) data; 157350703Swpaul struct mii_data *mii; 157440516Swpaul int s, error = 0; 157540516Swpaul 157640516Swpaul s = splimp(); 157740516Swpaul 157840516Swpaul switch(command) { 157940516Swpaul case SIOCSIFADDR: 158040516Swpaul case SIOCGIFADDR: 158140516Swpaul case SIOCSIFMTU: 158240516Swpaul error = ether_ioctl(ifp, command, data); 158340516Swpaul break; 158440516Swpaul case SIOCSIFFLAGS: 158540516Swpaul if (ifp->if_flags & IFF_UP) { 158640516Swpaul rl_init(sc); 158740516Swpaul } else { 158840516Swpaul if (ifp->if_flags & IFF_RUNNING) 158940516Swpaul rl_stop(sc); 159040516Swpaul } 159140516Swpaul error = 0; 159240516Swpaul break; 159340516Swpaul case SIOCADDMULTI: 159440516Swpaul case SIOCDELMULTI: 159540516Swpaul rl_setmulti(sc); 159640516Swpaul error = 0; 159740516Swpaul break; 159840516Swpaul case SIOCGIFMEDIA: 159940516Swpaul case SIOCSIFMEDIA: 160050703Swpaul mii = device_get_softc(sc->rl_miibus); 160150703Swpaul error = ifmedia_ioctl(ifp, ifr, &mii->mii_media, command); 160240516Swpaul break; 160340516Swpaul default: 160440516Swpaul error = EINVAL; 160540516Swpaul break; 160640516Swpaul } 160740516Swpaul 160840516Swpaul (void)splx(s); 160940516Swpaul 161040516Swpaul return(error); 161140516Swpaul} 161240516Swpaul 161340516Swpaulstatic void rl_watchdog(ifp) 161440516Swpaul struct ifnet *ifp; 161540516Swpaul{ 161640516Swpaul struct rl_softc *sc; 161740516Swpaul 161840516Swpaul sc = ifp->if_softc; 161940516Swpaul 162040516Swpaul printf("rl%d: watchdog timeout\n", sc->rl_unit); 162140516Swpaul ifp->if_oerrors++; 162250703Swpaul 162340516Swpaul rl_txeof(sc); 162440516Swpaul rl_rxeof(sc); 162540516Swpaul rl_init(sc); 162640516Swpaul 162740516Swpaul return; 162840516Swpaul} 162940516Swpaul 163040516Swpaul/* 163140516Swpaul * Stop the adapter and free any mbufs allocated to the 163240516Swpaul * RX and TX lists. 163340516Swpaul */ 163440516Swpaulstatic void rl_stop(sc) 163540516Swpaul struct rl_softc *sc; 163640516Swpaul{ 163740516Swpaul register int i; 163840516Swpaul struct ifnet *ifp; 163940516Swpaul 164040516Swpaul ifp = &sc->arpcom.ac_if; 164140516Swpaul ifp->if_timer = 0; 164240516Swpaul 164350703Swpaul untimeout(rl_tick, sc, sc->rl_stat_ch); 164450703Swpaul 164540516Swpaul CSR_WRITE_1(sc, RL_COMMAND, 0x00); 164640516Swpaul CSR_WRITE_2(sc, RL_IMR, 0x0000); 164740516Swpaul 164840516Swpaul /* 164940516Swpaul * Free the TX list buffers. 165040516Swpaul */ 165140516Swpaul for (i = 0; i < RL_TX_LIST_CNT; i++) { 165245633Swpaul if (sc->rl_cdata.rl_tx_chain[i] != NULL) { 165345633Swpaul m_freem(sc->rl_cdata.rl_tx_chain[i]); 165445633Swpaul sc->rl_cdata.rl_tx_chain[i] = NULL; 165545633Swpaul CSR_WRITE_4(sc, RL_TXADDR0 + i, 0x0000000); 165640516Swpaul } 165740516Swpaul } 165840516Swpaul 165940516Swpaul ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE); 166040516Swpaul 166140516Swpaul return; 166240516Swpaul} 166340516Swpaul 166440516Swpaul/* 166540516Swpaul * Stop all chip I/O so that the kernel's probe routines don't 166640516Swpaul * get confused by errant DMAs when rebooting. 166740516Swpaul */ 166850703Swpaulstatic void rl_shutdown(dev) 166950703Swpaul device_t dev; 167040516Swpaul{ 167150703Swpaul struct rl_softc *sc; 167240516Swpaul 167350703Swpaul sc = device_get_softc(dev); 167450703Swpaul 167540516Swpaul rl_stop(sc); 167640516Swpaul 167740516Swpaul return; 167840516Swpaul} 1679