1139825Simp/*- 249076Swpaul * Copyright (c) 1997, 1998, 1999 349076Swpaul * Bill Paul <wpaul@ctr.columbia.edu>. All rights reserved. 449076Swpaul * 549076Swpaul * Redistribution and use in source and binary forms, with or without 649076Swpaul * modification, are permitted provided that the following conditions 749076Swpaul * are met: 849076Swpaul * 1. Redistributions of source code must retain the above copyright 949076Swpaul * notice, this list of conditions and the following disclaimer. 1049076Swpaul * 2. Redistributions in binary form must reproduce the above copyright 1149076Swpaul * notice, this list of conditions and the following disclaimer in the 1249076Swpaul * documentation and/or other materials provided with the distribution. 1349076Swpaul * 3. All advertising materials mentioning features or use of this software 1449076Swpaul * must display the following acknowledgement: 1549076Swpaul * This product includes software developed by Bill Paul. 1649076Swpaul * 4. Neither the name of the author nor the names of any co-contributors 1749076Swpaul * may be used to endorse or promote products derived from this software 1849076Swpaul * without specific prior written permission. 1949076Swpaul * 2049076Swpaul * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND 2149076Swpaul * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2249076Swpaul * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2349076Swpaul * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD 2449076Swpaul * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 2549076Swpaul * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 2649076Swpaul * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 2749076Swpaul * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 2849076Swpaul * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 2949076Swpaul * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 3049076Swpaul * THE POSSIBILITY OF SUCH DAMAGE. 3149076Swpaul */ 3249076Swpaul 33122678Sobrien#include <sys/cdefs.h> 34122678Sobrien__FBSDID("$FreeBSD$"); 35122678Sobrien 3649076Swpaul/* 3749076Swpaul * Adaptec AIC-6915 "Starfire" PCI fast ethernet driver for FreeBSD. 3851682Swpaul * Programming manual is available from: 39137835Sbrueffer * http://download.adaptec.com/pdfs/user_guides/aic6915_pg.pdf. 4049076Swpaul * 4149076Swpaul * Written by Bill Paul <wpaul@ctr.columbia.edu> 4249076Swpaul * Department of Electical Engineering 4349076Swpaul * Columbia University, New York City 4449076Swpaul */ 4549076Swpaul/* 4649076Swpaul * The Adaptec AIC-6915 "Starfire" is a 64-bit 10/100 PCI ethernet 4749076Swpaul * controller designed with flexibility and reducing CPU load in mind. 4849076Swpaul * The Starfire offers high and low priority buffer queues, a 4949076Swpaul * producer/consumer index mechanism and several different buffer 5049076Swpaul * queue and completion queue descriptor types. Any one of a number 5149076Swpaul * of different driver designs can be used, depending on system and 52175526Syongari * OS requirements. This driver makes use of type2 transmit frame 53175526Syongari * descriptors to take full advantage of fragmented packets buffers 5449076Swpaul * and two RX buffer queues prioritized on size (one queue for small 5549076Swpaul * frames that will fit into a single mbuf, another with full size 5649076Swpaul * mbuf clusters for everything else). The producer/consumer indexes 5749076Swpaul * and completion queues are also used. 5849076Swpaul * 5949076Swpaul * One downside to the Starfire has to do with alignment: buffer 6049076Swpaul * queues must be aligned on 256-byte boundaries, and receive buffers 6149076Swpaul * must be aligned on longword boundaries. The receive buffer alignment 62175526Syongari * causes problems on the strict alignment architecture, where the 63175526Syongari * packet payload should be longword aligned. There is no simple way 64175526Syongari * around this. 6549076Swpaul * 6649076Swpaul * For receive filtering, the Starfire offers 16 perfect filter slots 6749076Swpaul * and a 512-bit hash table. 6849076Swpaul * 6949076Swpaul * The Starfire has no internal transceiver, relying instead on an 7049076Swpaul * external MII-based transceiver. Accessing registers on external 7149076Swpaul * PHYs is done through a special register map rather than with the 7249076Swpaul * usual bitbang MDIO method. 7349076Swpaul * 7449076Swpaul * Acesssing the registers on the Starfire is a little tricky. The 7549076Swpaul * Starfire has a 512K internal register space. When programmed for 7649076Swpaul * PCI memory mapped mode, the entire register space can be accessed 7749076Swpaul * directly. However in I/O space mode, only 256 bytes are directly 7849076Swpaul * mapped into PCI I/O space. The other registers can be accessed 7949076Swpaul * indirectly using the SF_INDIRECTIO_ADDR and SF_INDIRECTIO_DATA 8049076Swpaul * registers inside the 256-byte I/O window. 8149076Swpaul */ 8249076Swpaul 83150968Sglebius#ifdef HAVE_KERNEL_OPTION_HEADERS 84150968Sglebius#include "opt_device_polling.h" 85150968Sglebius#endif 86150968Sglebius 8749076Swpaul#include <sys/param.h> 8849076Swpaul#include <sys/systm.h> 89175526Syongari#include <sys/bus.h> 90175526Syongari#include <sys/endian.h> 91175526Syongari#include <sys/kernel.h> 92175526Syongari#include <sys/malloc.h> 9349076Swpaul#include <sys/mbuf.h> 94175526Syongari#include <sys/rman.h> 95129878Sphk#include <sys/module.h> 9649076Swpaul#include <sys/socket.h> 97175526Syongari#include <sys/sockio.h> 98175526Syongari#include <sys/sysctl.h> 9949076Swpaul 100175526Syongari#include <net/bpf.h> 10149076Swpaul#include <net/if.h> 10249076Swpaul#include <net/if_arp.h> 10349076Swpaul#include <net/ethernet.h> 10449076Swpaul#include <net/if_dl.h> 10549076Swpaul#include <net/if_media.h> 106147256Sbrooks#include <net/if_types.h> 107175526Syongari#include <net/if_vlan_var.h> 10849076Swpaul 10950675Swpaul#include <dev/mii/mii.h> 11050675Swpaul#include <dev/mii/miivar.h> 11150675Swpaul 112119288Simp#include <dev/pci/pcireg.h> 113119288Simp#include <dev/pci/pcivar.h> 11449076Swpaul 115175526Syongari#include <machine/bus.h> 11649076Swpaul 117175520Syongari#include <dev/sf/if_sfreg.h> 118175526Syongari#include <dev/sf/starfire_rx.h> 119175526Syongari#include <dev/sf/starfire_tx.h> 12049076Swpaul 121175526Syongari/* "device miibus" required. See GENERIC if you get errors here. */ 122175526Syongari#include "miibus_if.h" 123175526Syongari 124113506SmdoddMODULE_DEPEND(sf, pci, 1, 1, 1); 125113506SmdoddMODULE_DEPEND(sf, ether, 1, 1, 1); 12659758SpeterMODULE_DEPEND(sf, miibus, 1, 1, 1); 12759758Speter 128175526Syongari#undef SF_GFP_DEBUG 129175526Syongari#define SF_CSUM_FEATURES (CSUM_TCP | CSUM_UDP) 130175526Syongari/* Define this to activate partial TCP/UDP checksum offload. */ 131175526Syongari#undef SF_PARTIAL_CSUM_SUPPORT 132175526Syongari 13349076Swpaulstatic struct sf_type sf_devs[] = { 134175526Syongari { AD_VENDORID, AD_DEVICEID_STARFIRE, "Adaptec AIC-6915 10/100BaseTX", 135175526Syongari AD_SUBSYSID_62011_REV0, "Adaptec ANA-62011 (rev 0) 10/100BaseTX" }, 136175526Syongari { AD_VENDORID, AD_DEVICEID_STARFIRE, "Adaptec AIC-6915 10/100BaseTX", 137175526Syongari AD_SUBSYSID_62011_REV1, "Adaptec ANA-62011 (rev 1) 10/100BaseTX" }, 138175526Syongari { AD_VENDORID, AD_DEVICEID_STARFIRE, "Adaptec AIC-6915 10/100BaseTX", 139175526Syongari AD_SUBSYSID_62022, "Adaptec ANA-62022 10/100BaseTX" }, 140175526Syongari { AD_VENDORID, AD_DEVICEID_STARFIRE, "Adaptec AIC-6915 10/100BaseTX", 141175526Syongari AD_SUBSYSID_62044_REV0, "Adaptec ANA-62044 (rev 0) 10/100BaseTX" }, 142175526Syongari { AD_VENDORID, AD_DEVICEID_STARFIRE, "Adaptec AIC-6915 10/100BaseTX", 143175526Syongari AD_SUBSYSID_62044_REV1, "Adaptec ANA-62044 (rev 1) 10/100BaseTX" }, 144175526Syongari { AD_VENDORID, AD_DEVICEID_STARFIRE, "Adaptec AIC-6915 10/100BaseTX", 145175526Syongari AD_SUBSYSID_62020, "Adaptec ANA-62020 10/100BaseFX" }, 146175526Syongari { AD_VENDORID, AD_DEVICEID_STARFIRE, "Adaptec AIC-6915 10/100BaseTX", 147175526Syongari AD_SUBSYSID_69011, "Adaptec ANA-69011 10/100BaseTX" }, 14849076Swpaul}; 14949076Swpaul 150142407Simpstatic int sf_probe(device_t); 151142407Simpstatic int sf_attach(device_t); 152142407Simpstatic int sf_detach(device_t); 153175526Syongaristatic int sf_shutdown(device_t); 154175526Syongaristatic int sf_suspend(device_t); 155175526Syongaristatic int sf_resume(device_t); 156142407Simpstatic void sf_intr(void *); 157175526Syongaristatic void sf_tick(void *); 158175526Syongaristatic void sf_stats_update(struct sf_softc *); 159175526Syongari#ifndef __NO_STRICT_ALIGNMENT 160175526Syongaristatic __inline void sf_fixup_rx(struct mbuf *); 161175526Syongari#endif 162193096Sattiliostatic int sf_rxeof(struct sf_softc *); 163142407Simpstatic void sf_txeof(struct sf_softc *); 164175526Syongaristatic int sf_encap(struct sf_softc *, struct mbuf **); 165142407Simpstatic void sf_start(struct ifnet *); 166149240Sjhbstatic void sf_start_locked(struct ifnet *); 167142407Simpstatic int sf_ioctl(struct ifnet *, u_long, caddr_t); 168175526Syongaristatic void sf_download_fw(struct sf_softc *); 169142407Simpstatic void sf_init(void *); 170149240Sjhbstatic void sf_init_locked(struct sf_softc *); 171142407Simpstatic void sf_stop(struct sf_softc *); 172175526Syongaristatic void sf_watchdog(struct sf_softc *); 173142407Simpstatic int sf_ifmedia_upd(struct ifnet *); 174232025Syongaristatic int sf_ifmedia_upd_locked(struct ifnet *); 175142407Simpstatic void sf_ifmedia_sts(struct ifnet *, struct ifmediareq *); 176142407Simpstatic void sf_reset(struct sf_softc *); 177175526Syongaristatic int sf_dma_alloc(struct sf_softc *); 178175526Syongaristatic void sf_dma_free(struct sf_softc *); 179142407Simpstatic int sf_init_rx_ring(struct sf_softc *); 180142407Simpstatic void sf_init_tx_ring(struct sf_softc *); 181175526Syongaristatic int sf_newbuf(struct sf_softc *, int); 182175526Syongaristatic void sf_rxfilter(struct sf_softc *); 183175526Syongaristatic int sf_setperf(struct sf_softc *, int, uint8_t *); 184142407Simpstatic int sf_sethash(struct sf_softc *, caddr_t, int); 18549076Swpaul#ifdef notdef 186175526Syongaristatic int sf_setvlan(struct sf_softc *, int, uint32_t); 18749076Swpaul#endif 18849076Swpaul 189175526Syongaristatic uint8_t sf_read_eeprom(struct sf_softc *, int); 19049076Swpaul 191142407Simpstatic int sf_miibus_readreg(device_t, int, int); 192142407Simpstatic int sf_miibus_writereg(device_t, int, int, int); 193142407Simpstatic void sf_miibus_statchg(device_t); 194137557Sbrueffer#ifdef DEVICE_POLLING 195193096Sattiliostatic int sf_poll(struct ifnet *ifp, enum poll_cmd cmd, int count); 196150789Sglebius#endif 19749076Swpaul 198175526Syongaristatic uint32_t csr_read_4(struct sf_softc *, int); 199175526Syongaristatic void csr_write_4(struct sf_softc *, int, uint32_t); 200142407Simpstatic void sf_txthresh_adjust(struct sf_softc *); 201175526Syongaristatic int sf_sysctl_stats(SYSCTL_HANDLER_ARGS); 202175526Syongaristatic int sysctl_int_range(SYSCTL_HANDLER_ARGS, int, int); 203175526Syongaristatic int sysctl_hw_sf_int_mod(SYSCTL_HANDLER_ARGS); 20449076Swpaul 20549076Swpaulstatic device_method_t sf_methods[] = { 20649076Swpaul /* Device interface */ 20749076Swpaul DEVMETHOD(device_probe, sf_probe), 20849076Swpaul DEVMETHOD(device_attach, sf_attach), 20949076Swpaul DEVMETHOD(device_detach, sf_detach), 21049076Swpaul DEVMETHOD(device_shutdown, sf_shutdown), 211175526Syongari DEVMETHOD(device_suspend, sf_suspend), 212175526Syongari DEVMETHOD(device_resume, sf_resume), 21350675Swpaul 21450675Swpaul /* MII interface */ 21550675Swpaul DEVMETHOD(miibus_readreg, sf_miibus_readreg), 21650675Swpaul DEVMETHOD(miibus_writereg, sf_miibus_writereg), 21750675Swpaul DEVMETHOD(miibus_statchg, sf_miibus_statchg), 21850675Swpaul 219227843Smarius DEVMETHOD_END 22049076Swpaul}; 22149076Swpaul 22249076Swpaulstatic driver_t sf_driver = { 22351455Swpaul "sf", 22449076Swpaul sf_methods, 22549076Swpaul sizeof(struct sf_softc), 22649076Swpaul}; 22749076Swpaul 22849076Swpaulstatic devclass_t sf_devclass; 22949076Swpaul 230113506SmdoddDRIVER_MODULE(sf, pci, sf_driver, sf_devclass, 0, 0); 23151473SwpaulDRIVER_MODULE(miibus, sf, miibus_driver, miibus_devclass, 0, 0); 23249076Swpaul 23349076Swpaul#define SF_SETBIT(sc, reg, x) \ 234105221Sphk csr_write_4(sc, reg, csr_read_4(sc, reg) | (x)) 23549076Swpaul 23649076Swpaul#define SF_CLRBIT(sc, reg, x) \ 237105221Sphk csr_write_4(sc, reg, csr_read_4(sc, reg) & ~(x)) 23849076Swpaul 239175526Syongaristatic uint32_t 240175526Syongaricsr_read_4(struct sf_softc *sc, int reg) 24149076Swpaul{ 242175526Syongari uint32_t val; 24349076Swpaul 244175526Syongari if (sc->sf_restype == SYS_RES_MEMORY) 245175526Syongari val = CSR_READ_4(sc, (reg + SF_RMAP_INTREG_BASE)); 246175526Syongari else { 247175526Syongari CSR_WRITE_4(sc, SF_INDIRECTIO_ADDR, reg + SF_RMAP_INTREG_BASE); 248175526Syongari val = CSR_READ_4(sc, SF_INDIRECTIO_DATA); 249175526Syongari } 25049076Swpaul 251175526Syongari return (val); 25249076Swpaul} 25349076Swpaul 254175526Syongaristatic uint8_t 255175526Syongarisf_read_eeprom(struct sf_softc *sc, int reg) 25649076Swpaul{ 257175526Syongari uint8_t val; 25849076Swpaul 25949076Swpaul val = (csr_read_4(sc, SF_EEADDR_BASE + 26049076Swpaul (reg & 0xFFFFFFFC)) >> (8 * (reg & 3))) & 0xFF; 26149076Swpaul 262175526Syongari return (val); 26349076Swpaul} 26449076Swpaul 265102335Salfredstatic void 266175526Syongaricsr_write_4(struct sf_softc *sc, int reg, uint32_t val) 26749076Swpaul{ 268175526Syongari 269175526Syongari if (sc->sf_restype == SYS_RES_MEMORY) 270175526Syongari CSR_WRITE_4(sc, (reg + SF_RMAP_INTREG_BASE), val); 271175526Syongari else { 272175526Syongari CSR_WRITE_4(sc, SF_INDIRECTIO_ADDR, reg + SF_RMAP_INTREG_BASE); 273175526Syongari CSR_WRITE_4(sc, SF_INDIRECTIO_DATA, val); 274175526Syongari } 27549076Swpaul} 27649076Swpaul 27749076Swpaul/* 27849076Swpaul * Copy the address 'mac' into the perfect RX filter entry at 27949076Swpaul * offset 'idx.' The perfect filter only has 16 entries so do 28049076Swpaul * some sanity tests. 28149076Swpaul */ 282102335Salfredstatic int 283175526Syongarisf_setperf(struct sf_softc *sc, int idx, uint8_t *mac) 28449076Swpaul{ 28549076Swpaul 28649076Swpaul if (idx < 0 || idx > SF_RXFILT_PERFECT_CNT) 287175526Syongari return (EINVAL); 28849076Swpaul 28949076Swpaul if (mac == NULL) 290175526Syongari return (EINVAL); 29149076Swpaul 29249076Swpaul csr_write_4(sc, SF_RXFILT_PERFECT_BASE + 293175526Syongari (idx * SF_RXFILT_PERFECT_SKIP) + 0, mac[5] | (mac[4] << 8)); 29449076Swpaul csr_write_4(sc, SF_RXFILT_PERFECT_BASE + 295175526Syongari (idx * SF_RXFILT_PERFECT_SKIP) + 4, mac[3] | (mac[2] << 8)); 29649076Swpaul csr_write_4(sc, SF_RXFILT_PERFECT_BASE + 297175526Syongari (idx * SF_RXFILT_PERFECT_SKIP) + 8, mac[1] | (mac[0] << 8)); 29849076Swpaul 299175526Syongari return (0); 30049076Swpaul} 30149076Swpaul 30249076Swpaul/* 30349076Swpaul * Set the bit in the 512-bit hash table that corresponds to the 30449076Swpaul * specified mac address 'mac.' If 'prio' is nonzero, update the 30549076Swpaul * priority hash table instead of the filter hash table. 30649076Swpaul */ 307102335Salfredstatic int 308175526Syongarisf_sethash(struct sf_softc *sc, caddr_t mac, int prio) 30949076Swpaul{ 310175526Syongari uint32_t h; 31149076Swpaul 31249076Swpaul if (mac == NULL) 313175526Syongari return (EINVAL); 31449076Swpaul 315130270Snaddy h = ether_crc32_be(mac, ETHER_ADDR_LEN) >> 23; 31649076Swpaul 31749076Swpaul if (prio) { 31849076Swpaul SF_SETBIT(sc, SF_RXFILT_HASH_BASE + SF_RXFILT_HASH_PRIOOFF + 31949076Swpaul (SF_RXFILT_HASH_SKIP * (h >> 4)), (1 << (h & 0xF))); 32049076Swpaul } else { 32149076Swpaul SF_SETBIT(sc, SF_RXFILT_HASH_BASE + SF_RXFILT_HASH_ADDROFF + 32249076Swpaul (SF_RXFILT_HASH_SKIP * (h >> 4)), (1 << (h & 0xF))); 32349076Swpaul } 32449076Swpaul 325175526Syongari return (0); 32649076Swpaul} 32749076Swpaul 32849076Swpaul#ifdef notdef 32949076Swpaul/* 33049076Swpaul * Set a VLAN tag in the receive filter. 33149076Swpaul */ 332102335Salfredstatic int 333175526Syongarisf_setvlan(struct sf_softc *sc, int idx, uint32_t vlan) 33449076Swpaul{ 335175526Syongari 33649076Swpaul if (idx < 0 || idx >> SF_RXFILT_HASH_CNT) 337175526Syongari return (EINVAL); 33849076Swpaul 33949076Swpaul csr_write_4(sc, SF_RXFILT_HASH_BASE + 34049076Swpaul (idx * SF_RXFILT_HASH_SKIP) + SF_RXFILT_HASH_VLANOFF, vlan); 34149076Swpaul 342175526Syongari return (0); 34349076Swpaul} 34449076Swpaul#endif 34549076Swpaul 346102335Salfredstatic int 347175526Syongarisf_miibus_readreg(device_t dev, int phy, int reg) 34850675Swpaul{ 34949076Swpaul struct sf_softc *sc; 35049076Swpaul int i; 351175526Syongari uint32_t val = 0; 35249076Swpaul 35350675Swpaul sc = device_get_softc(dev); 35450675Swpaul 35549076Swpaul for (i = 0; i < SF_TIMEOUT; i++) { 35650675Swpaul val = csr_read_4(sc, SF_PHY_REG(phy, reg)); 357175526Syongari if ((val & SF_MII_DATAVALID) != 0) 35849076Swpaul break; 35949076Swpaul } 36049076Swpaul 36149076Swpaul if (i == SF_TIMEOUT) 362175526Syongari return (0); 36349076Swpaul 364175526Syongari val &= SF_MII_DATAPORT; 365175526Syongari if (val == 0xffff) 366175526Syongari return (0); 36749076Swpaul 368175526Syongari return (val); 36949076Swpaul} 37049076Swpaul 371102335Salfredstatic int 372175526Syongarisf_miibus_writereg(device_t dev, int phy, int reg, int val) 37350675Swpaul{ 37449076Swpaul struct sf_softc *sc; 37549076Swpaul int i; 37649076Swpaul int busy; 37749076Swpaul 37850675Swpaul sc = device_get_softc(dev); 37949076Swpaul 38050675Swpaul csr_write_4(sc, SF_PHY_REG(phy, reg), val); 38150675Swpaul 38249076Swpaul for (i = 0; i < SF_TIMEOUT; i++) { 38350675Swpaul busy = csr_read_4(sc, SF_PHY_REG(phy, reg)); 384175526Syongari if ((busy & SF_MII_BUSY) == 0) 38549076Swpaul break; 38649076Swpaul } 38749076Swpaul 388175526Syongari return (0); 38950675Swpaul} 39050675Swpaul 391102335Salfredstatic void 392175526Syongarisf_miibus_statchg(device_t dev) 39350675Swpaul{ 39450675Swpaul struct sf_softc *sc; 39550675Swpaul struct mii_data *mii; 396175526Syongari struct ifnet *ifp; 397175526Syongari uint32_t val; 39850675Swpaul 399232029Syongari sc = device_get_softc(dev); 40050675Swpaul mii = device_get_softc(sc->sf_miibus); 401175526Syongari ifp = sc->sf_ifp; 402175526Syongari if (mii == NULL || ifp == NULL || 403232029Syongari (ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) 404175526Syongari return; 40550675Swpaul 406232031Syongari sc->sf_link = 0; 407232031Syongari if ((mii->mii_media_status & (IFM_ACTIVE | IFM_AVALID)) == 408232031Syongari (IFM_ACTIVE | IFM_AVALID)) { 409232031Syongari switch (IFM_SUBTYPE(mii->mii_media_active)) { 410232031Syongari case IFM_10_T: 411232031Syongari case IFM_100_TX: 412232031Syongari case IFM_100_FX: 413175526Syongari sc->sf_link = 1; 414232031Syongari break; 415232031Syongari } 416232031Syongari } 417232031Syongari if (sc->sf_link == 0) 418232031Syongari return; 419175526Syongari 420175526Syongari val = csr_read_4(sc, SF_MACCFG_1); 421175526Syongari val &= ~SF_MACCFG1_FULLDUPLEX; 422175526Syongari val &= ~(SF_MACCFG1_RX_FLOWENB | SF_MACCFG1_TX_FLOWENB); 423175526Syongari if ((IFM_OPTIONS(mii->mii_media_active) & IFM_FDX) != 0) { 424175526Syongari val |= SF_MACCFG1_FULLDUPLEX; 42554161Swpaul csr_write_4(sc, SF_BKTOBKIPG, SF_IPGT_FDX); 426175526Syongari#ifdef notyet 427175526Syongari /* Configure flow-control bits. */ 428175526Syongari if ((IFM_OPTIONS(sc->sc_mii->mii_media_active) & 429175526Syongari IFM_ETH_RXPAUSE) != 0) 430175526Syongari val |= SF_MACCFG1_RX_FLOWENB; 431175526Syongari if ((IFM_OPTIONS(sc->sc_mii->mii_media_active) & 432175526Syongari IFM_ETH_TXPAUSE) != 0) 433175526Syongari val |= SF_MACCFG1_TX_FLOWENB; 434175526Syongari#endif 435175526Syongari } else 43654161Swpaul csr_write_4(sc, SF_BKTOBKIPG, SF_IPGT_HDX); 437175526Syongari 438175526Syongari /* Make sure to reset MAC to take changes effect. */ 439175526Syongari csr_write_4(sc, SF_MACCFG_1, val | SF_MACCFG1_SOFTRESET); 440175526Syongari DELAY(1000); 441175526Syongari csr_write_4(sc, SF_MACCFG_1, val); 442175526Syongari 443175526Syongari val = csr_read_4(sc, SF_TIMER_CTL); 444175526Syongari if (IFM_SUBTYPE(mii->mii_media_active) == IFM_100_TX) 445175526Syongari val |= SF_TIMER_TIMES_TEN; 446175526Syongari else 447175526Syongari val &= ~SF_TIMER_TIMES_TEN; 448175526Syongari csr_write_4(sc, SF_TIMER_CTL, val); 44949076Swpaul} 45049076Swpaul 451102335Salfredstatic void 452175526Syongarisf_rxfilter(struct sf_softc *sc) 45349076Swpaul{ 45449076Swpaul struct ifnet *ifp; 45549076Swpaul int i; 45649076Swpaul struct ifmultiaddr *ifma; 457175526Syongari uint8_t dummy[ETHER_ADDR_LEN] = { 0, 0, 0, 0, 0, 0 }; 458175526Syongari uint32_t rxfilt; 45949076Swpaul 460147256Sbrooks ifp = sc->sf_ifp; 46149076Swpaul 46249076Swpaul /* First zot all the existing filters. */ 46349076Swpaul for (i = 1; i < SF_RXFILT_PERFECT_CNT; i++) 464175526Syongari sf_setperf(sc, i, dummy); 465175526Syongari for (i = SF_RXFILT_HASH_BASE; i < (SF_RXFILT_HASH_MAX + 1); 466175526Syongari i += sizeof(uint32_t)) 46749076Swpaul csr_write_4(sc, i, 0); 46849076Swpaul 469175526Syongari rxfilt = csr_read_4(sc, SF_RXFILT); 470175526Syongari rxfilt &= ~(SF_RXFILT_PROMISC | SF_RXFILT_ALLMULTI | SF_RXFILT_BROAD); 471175526Syongari if ((ifp->if_flags & IFF_BROADCAST) != 0) 472175526Syongari rxfilt |= SF_RXFILT_BROAD; 473175526Syongari if ((ifp->if_flags & IFF_ALLMULTI) != 0 || 474175526Syongari (ifp->if_flags & IFF_PROMISC) != 0) { 475175526Syongari if ((ifp->if_flags & IFF_PROMISC) != 0) 476175526Syongari rxfilt |= SF_RXFILT_PROMISC; 477175526Syongari if ((ifp->if_flags & IFF_ALLMULTI) != 0) 478175526Syongari rxfilt |= SF_RXFILT_ALLMULTI; 479175526Syongari goto done; 480175526Syongari } 481175526Syongari 48249076Swpaul /* Now program new ones. */ 483175526Syongari i = 1; 484195049Srwatson if_maddr_rlock(ifp); 485175526Syongari TAILQ_FOREACH_REVERSE(ifma, &ifp->if_multiaddrs, ifmultihead, 486175526Syongari ifma_link) { 487175526Syongari if (ifma->ifma_addr->sa_family != AF_LINK) 488175526Syongari continue; 489175526Syongari /* 490175526Syongari * Program the first 15 multicast groups 491175526Syongari * into the perfect filter. For all others, 492175526Syongari * use the hash table. 493175526Syongari */ 494175526Syongari if (i < SF_RXFILT_PERFECT_CNT) { 495175526Syongari sf_setperf(sc, i, 496175526Syongari LLADDR((struct sockaddr_dl *)ifma->ifma_addr)); 497175526Syongari i++; 498175526Syongari continue; 499175526Syongari } 50049076Swpaul 501175526Syongari sf_sethash(sc, 502175526Syongari LLADDR((struct sockaddr_dl *)ifma->ifma_addr), 0); 50349076Swpaul } 504195049Srwatson if_maddr_runlock(ifp); 505175526Syongari 506175526Syongaridone: 507175526Syongari csr_write_4(sc, SF_RXFILT, rxfilt); 50849076Swpaul} 50949076Swpaul 51049076Swpaul/* 51149076Swpaul * Set media options. 51249076Swpaul */ 513102335Salfredstatic int 514175526Syongarisf_ifmedia_upd(struct ifnet *ifp) 51549076Swpaul{ 51649076Swpaul struct sf_softc *sc; 517175526Syongari int error; 518149240Sjhb 519149240Sjhb sc = ifp->if_softc; 520149240Sjhb SF_LOCK(sc); 521232025Syongari error = sf_ifmedia_upd_locked(ifp); 522232025Syongari SF_UNLOCK(sc); 523232025Syongari return (error); 524232025Syongari} 525149240Sjhb 526232025Syongaristatic int 527232025Syongarisf_ifmedia_upd_locked(struct ifnet *ifp) 528232025Syongari{ 529232025Syongari struct sf_softc *sc; 530232025Syongari struct mii_data *mii; 531232025Syongari struct mii_softc *miisc; 532232025Syongari 533232025Syongari sc = ifp->if_softc; 53450675Swpaul mii = device_get_softc(sc->sf_miibus); 535221407Smarius LIST_FOREACH(miisc, &mii->mii_phys, mii_list) 536221407Smarius PHY_RESET(miisc); 537232025Syongari return (mii_mediachg(mii)); 53849076Swpaul} 53949076Swpaul 54049076Swpaul/* 54149076Swpaul * Report current media status. 54249076Swpaul */ 543102335Salfredstatic void 544175526Syongarisf_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr) 54549076Swpaul{ 54649076Swpaul struct sf_softc *sc; 54750675Swpaul struct mii_data *mii; 54849076Swpaul 54949076Swpaul sc = ifp->if_softc; 550149240Sjhb SF_LOCK(sc); 551232029Syongari if ((ifp->if_flags & IFF_UP) == 0) { 552232029Syongari SF_UNLOCK(sc); 553232029Syongari return; 554232029Syongari } 555232029Syongari 55650675Swpaul mii = device_get_softc(sc->sf_miibus); 55750675Swpaul mii_pollstat(mii); 55850675Swpaul ifmr->ifm_active = mii->mii_media_active; 55950675Swpaul ifmr->ifm_status = mii->mii_media_status; 560149240Sjhb SF_UNLOCK(sc); 56149076Swpaul} 56249076Swpaul 563102335Salfredstatic int 564175526Syongarisf_ioctl(struct ifnet *ifp, u_long command, caddr_t data) 56549076Swpaul{ 566175526Syongari struct sf_softc *sc; 567175526Syongari struct ifreq *ifr; 56850675Swpaul struct mii_data *mii; 569175526Syongari int error, mask; 57049076Swpaul 571175526Syongari sc = ifp->if_softc; 572175526Syongari ifr = (struct ifreq *)data; 573175526Syongari error = 0; 574175526Syongari 575175526Syongari switch (command) { 57649076Swpaul case SIOCSIFFLAGS: 577149240Sjhb SF_LOCK(sc); 57849076Swpaul if (ifp->if_flags & IFF_UP) { 579175526Syongari if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0) { 580175526Syongari if ((ifp->if_flags ^ sc->sf_if_flags) & 581175526Syongari (IFF_PROMISC | IFF_ALLMULTI)) 582175526Syongari sf_rxfilter(sc); 583175526Syongari } else { 584175526Syongari if (sc->sf_detach == 0) 585175526Syongari sf_init_locked(sc); 586175526Syongari } 58749076Swpaul } else { 588175526Syongari if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0) 58949076Swpaul sf_stop(sc); 59049076Swpaul } 59154161Swpaul sc->sf_if_flags = ifp->if_flags; 592149240Sjhb SF_UNLOCK(sc); 59349076Swpaul break; 59449076Swpaul case SIOCADDMULTI: 59549076Swpaul case SIOCDELMULTI: 596149240Sjhb SF_LOCK(sc); 597232027Syongari if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0) 598232027Syongari sf_rxfilter(sc); 599149240Sjhb SF_UNLOCK(sc); 60049076Swpaul break; 60149076Swpaul case SIOCGIFMEDIA: 60249076Swpaul case SIOCSIFMEDIA: 60350675Swpaul mii = device_get_softc(sc->sf_miibus); 60450675Swpaul error = ifmedia_ioctl(ifp, ifr, &mii->mii_media, command); 60549076Swpaul break; 606137557Sbrueffer case SIOCSIFCAP: 607175526Syongari mask = ifr->ifr_reqcap ^ ifp->if_capenable; 608150789Sglebius#ifdef DEVICE_POLLING 609175526Syongari if ((mask & IFCAP_POLLING) != 0) { 610175526Syongari if ((ifr->ifr_reqcap & IFCAP_POLLING) != 0) { 611175526Syongari error = ether_poll_register(sf_poll, ifp); 612175526Syongari if (error != 0) 613175526Syongari break; 614175526Syongari SF_LOCK(sc); 615175526Syongari /* Disable interrupts. */ 616175526Syongari csr_write_4(sc, SF_IMR, 0); 617175526Syongari ifp->if_capenable |= IFCAP_POLLING; 618175526Syongari SF_UNLOCK(sc); 619175526Syongari } else { 620175526Syongari error = ether_poll_deregister(ifp); 621175526Syongari /* Enable interrupts. */ 622175526Syongari SF_LOCK(sc); 623175526Syongari csr_write_4(sc, SF_IMR, SF_INTRS); 624175526Syongari ifp->if_capenable &= ~IFCAP_POLLING; 625175526Syongari SF_UNLOCK(sc); 626175526Syongari } 627150789Sglebius } 628175526Syongari#endif /* DEVICE_POLLING */ 629175526Syongari if ((mask & IFCAP_TXCSUM) != 0) { 630175526Syongari if ((IFCAP_TXCSUM & ifp->if_capabilities) != 0) { 631175526Syongari SF_LOCK(sc); 632175526Syongari ifp->if_capenable ^= IFCAP_TXCSUM; 633175526Syongari if ((IFCAP_TXCSUM & ifp->if_capenable) != 0) { 634175526Syongari ifp->if_hwassist |= SF_CSUM_FEATURES; 635175526Syongari SF_SETBIT(sc, SF_GEN_ETH_CTL, 636175526Syongari SF_ETHCTL_TXGFP_ENB); 637175526Syongari } else { 638175526Syongari ifp->if_hwassist &= ~SF_CSUM_FEATURES; 639175526Syongari SF_CLRBIT(sc, SF_GEN_ETH_CTL, 640175526Syongari SF_ETHCTL_TXGFP_ENB); 641175526Syongari } 642175526Syongari SF_UNLOCK(sc); 643175526Syongari } 644150789Sglebius } 645175526Syongari if ((mask & IFCAP_RXCSUM) != 0) { 646175526Syongari if ((IFCAP_RXCSUM & ifp->if_capabilities) != 0) { 647175526Syongari SF_LOCK(sc); 648175526Syongari ifp->if_capenable ^= IFCAP_RXCSUM; 649175526Syongari if ((IFCAP_RXCSUM & ifp->if_capenable) != 0) 650175526Syongari SF_SETBIT(sc, SF_GEN_ETH_CTL, 651175526Syongari SF_ETHCTL_RXGFP_ENB); 652175526Syongari else 653175526Syongari SF_CLRBIT(sc, SF_GEN_ETH_CTL, 654175526Syongari SF_ETHCTL_RXGFP_ENB); 655175526Syongari SF_UNLOCK(sc); 656175526Syongari } 657175526Syongari } 658137557Sbrueffer break; 65949076Swpaul default: 660106936Ssam error = ether_ioctl(ifp, command, data); 66149076Swpaul break; 66249076Swpaul } 66349076Swpaul 664175526Syongari return (error); 66549076Swpaul} 66649076Swpaul 667102335Salfredstatic void 668175526Syongarisf_reset(struct sf_softc *sc) 66949076Swpaul{ 670175526Syongari int i; 67149076Swpaul 67249076Swpaul csr_write_4(sc, SF_GEN_ETH_CTL, 0); 67349076Swpaul SF_SETBIT(sc, SF_MACCFG_1, SF_MACCFG1_SOFTRESET); 67449076Swpaul DELAY(1000); 67549076Swpaul SF_CLRBIT(sc, SF_MACCFG_1, SF_MACCFG1_SOFTRESET); 67649076Swpaul 67749076Swpaul SF_SETBIT(sc, SF_PCI_DEVCFG, SF_PCIDEVCFG_RESET); 67849076Swpaul 67949076Swpaul for (i = 0; i < SF_TIMEOUT; i++) { 68049076Swpaul DELAY(10); 68149076Swpaul if (!(csr_read_4(sc, SF_PCI_DEVCFG) & SF_PCIDEVCFG_RESET)) 68249076Swpaul break; 68349076Swpaul } 68449076Swpaul 68549076Swpaul if (i == SF_TIMEOUT) 686162315Sglebius device_printf(sc->sf_dev, "reset never completed!\n"); 68749076Swpaul 68849076Swpaul /* Wait a little while for the chip to get its brains in order. */ 68949076Swpaul DELAY(1000); 69049076Swpaul} 69149076Swpaul 69249076Swpaul/* 69349076Swpaul * Probe for an Adaptec AIC-6915 chip. Check the PCI vendor and device 69449076Swpaul * IDs against our list and return a device name if we find a match. 69549076Swpaul * We also check the subsystem ID so that we can identify exactly which 69649076Swpaul * NIC has been found, if possible. 69749076Swpaul */ 698102335Salfredstatic int 699175526Syongarisf_probe(device_t dev) 70049076Swpaul{ 70149076Swpaul struct sf_type *t; 702175526Syongari uint16_t vid; 703175526Syongari uint16_t did; 704175526Syongari uint16_t sdid; 705175526Syongari int i; 70649076Swpaul 707175526Syongari vid = pci_get_vendor(dev); 708175526Syongari did = pci_get_device(dev); 709175526Syongari sdid = pci_get_subdevice(dev); 710175526Syongari 71149076Swpaul t = sf_devs; 712175526Syongari for (i = 0; i < sizeof(sf_devs) / sizeof(sf_devs[0]); i++, t++) { 713175526Syongari if (vid == t->sf_vid && did == t->sf_did) { 714175526Syongari if (sdid == t->sf_sdid) { 715175526Syongari device_set_desc(dev, t->sf_sname); 716142398Simp return (BUS_PROBE_DEFAULT); 71749076Swpaul } 71849076Swpaul } 71949076Swpaul } 72049076Swpaul 721175526Syongari if (vid == AD_VENDORID && did == AD_DEVICEID_STARFIRE) { 722175526Syongari /* unkown subdevice */ 723175526Syongari device_set_desc(dev, sf_devs[0].sf_name); 724175526Syongari return (BUS_PROBE_DEFAULT); 725175526Syongari } 726175526Syongari 727175526Syongari return (ENXIO); 72849076Swpaul} 72949076Swpaul 73049076Swpaul/* 73149076Swpaul * Attach the interface. Allocate softc structures, do ifmedia 73249076Swpaul * setup and ethernet/BPF attach. 73349076Swpaul */ 734102335Salfredstatic int 735175526Syongarisf_attach(device_t dev) 73649076Swpaul{ 73767087Swpaul int i; 73849076Swpaul struct sf_softc *sc; 73949076Swpaul struct ifnet *ifp; 740175526Syongari uint32_t reg; 741148947Sjhb int rid, error = 0; 742175526Syongari uint8_t eaddr[ETHER_ADDR_LEN]; 74349076Swpaul 74449076Swpaul sc = device_get_softc(dev); 745162315Sglebius sc->sf_dev = dev; 74649076Swpaul 74793818Sjhb mtx_init(&sc->sf_mtx, device_get_nameunit(dev), MTX_NETWORK_LOCK, 748149240Sjhb MTX_DEF); 749175526Syongari callout_init_mtx(&sc->sf_co, &sc->sf_mtx, 0); 750175526Syongari 75149076Swpaul /* 75249076Swpaul * Map control/status registers. 75349076Swpaul */ 75472813Swpaul pci_enable_busmaster(dev); 75549076Swpaul 756175526Syongari /* 757175526Syongari * Prefer memory space register mapping over I/O space as the 758175526Syongari * hardware requires lots of register access to get various 759175526Syongari * producer/consumer index during Tx/Rx operation. However this 760175526Syongari * requires large memory space(512K) to map the entire register 761175526Syongari * space. 762175526Syongari */ 763175526Syongari sc->sf_rid = PCIR_BAR(0); 764175526Syongari sc->sf_restype = SYS_RES_MEMORY; 765175526Syongari sc->sf_res = bus_alloc_resource_any(dev, sc->sf_restype, &sc->sf_rid, 766175526Syongari RF_ACTIVE); 76749076Swpaul if (sc->sf_res == NULL) { 768175526Syongari reg = pci_read_config(dev, PCIR_BAR(0), 4); 769175526Syongari if ((reg & PCIM_BAR_MEM_64) == PCIM_BAR_MEM_64) 770175526Syongari sc->sf_rid = PCIR_BAR(2); 771175526Syongari else 772175526Syongari sc->sf_rid = PCIR_BAR(1); 773175526Syongari sc->sf_restype = SYS_RES_IOPORT; 774175526Syongari sc->sf_res = bus_alloc_resource_any(dev, sc->sf_restype, 775175526Syongari &sc->sf_rid, RF_ACTIVE); 776175526Syongari if (sc->sf_res == NULL) { 777175526Syongari device_printf(dev, "couldn't allocate resources\n"); 778175526Syongari mtx_destroy(&sc->sf_mtx); 779175526Syongari return (ENXIO); 780175526Syongari } 78149076Swpaul } 782175526Syongari if (bootverbose) 783175526Syongari device_printf(dev, "using %s space register mapping\n", 784175526Syongari sc->sf_restype == SYS_RES_MEMORY ? "memory" : "I/O"); 78549076Swpaul 786175526Syongari reg = pci_read_config(dev, PCIR_CACHELNSZ, 1); 787175526Syongari if (reg == 0) { 788175526Syongari /* 789175526Syongari * If cache line size is 0, MWI is not used at all, so set 790175526Syongari * reasonable default. AIC-6915 supports 0, 4, 8, 16, 32 791175526Syongari * and 64. 792175526Syongari */ 793175526Syongari reg = 16; 794175526Syongari device_printf(dev, "setting PCI cache line size to %u\n", reg); 795175526Syongari pci_write_config(dev, PCIR_CACHELNSZ, reg, 1); 796175526Syongari } else { 797175526Syongari if (bootverbose) 798175526Syongari device_printf(dev, "PCI cache line size : %u\n", reg); 799175526Syongari } 800175526Syongari /* Enable MWI. */ 801175526Syongari reg = pci_read_config(dev, PCIR_COMMAND, 2); 802175526Syongari reg |= PCIM_CMD_MWRICEN; 803175526Syongari pci_write_config(dev, PCIR_COMMAND, reg, 2); 80449076Swpaul 805175526Syongari /* Allocate interrupt. */ 80649076Swpaul rid = 0; 807127135Snjl sc->sf_irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, 80849076Swpaul RF_SHAREABLE | RF_ACTIVE); 80949076Swpaul 81049076Swpaul if (sc->sf_irq == NULL) { 811148947Sjhb device_printf(dev, "couldn't map interrupt\n"); 81249076Swpaul error = ENXIO; 81349076Swpaul goto fail; 81449076Swpaul } 81549076Swpaul 816175526Syongari SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), 817175526Syongari SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 818175526Syongari OID_AUTO, "stats", CTLTYPE_INT | CTLFLAG_RW, sc, 0, 819175526Syongari sf_sysctl_stats, "I", "Statistics"); 820149240Sjhb 821175526Syongari SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), 822175526Syongari SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 823175526Syongari OID_AUTO, "int_mod", CTLTYPE_INT | CTLFLAG_RW, 824175526Syongari &sc->sf_int_mod, 0, sysctl_hw_sf_int_mod, "I", 825175526Syongari "sf interrupt moderation"); 826175526Syongari /* Pull in device tunables. */ 827175526Syongari sc->sf_int_mod = SF_IM_DEFAULT; 828175526Syongari error = resource_int_value(device_get_name(dev), device_get_unit(dev), 829175526Syongari "int_mod", &sc->sf_int_mod); 830175526Syongari if (error == 0) { 831175526Syongari if (sc->sf_int_mod < SF_IM_MIN || 832175526Syongari sc->sf_int_mod > SF_IM_MAX) { 833175526Syongari device_printf(dev, "int_mod value out of range; " 834175526Syongari "using default: %d\n", SF_IM_DEFAULT); 835175526Syongari sc->sf_int_mod = SF_IM_DEFAULT; 836175526Syongari } 837175526Syongari } 838175526Syongari 83949076Swpaul /* Reset the adapter. */ 84049076Swpaul sf_reset(sc); 84149076Swpaul 84249076Swpaul /* 84349076Swpaul * Get station address from the EEPROM. 84449076Swpaul */ 84549076Swpaul for (i = 0; i < ETHER_ADDR_LEN; i++) 846147256Sbrooks eaddr[i] = 84749076Swpaul sf_read_eeprom(sc, SF_EE_NODEADDR + ETHER_ADDR_LEN - i); 84849076Swpaul 849175526Syongari /* Allocate DMA resources. */ 850175526Syongari if (sf_dma_alloc(sc) != 0) { 851175526Syongari error = ENOSPC; 85249076Swpaul goto fail; 85349076Swpaul } 85449076Swpaul 855175526Syongari sc->sf_txthresh = SF_MIN_TX_THRESHOLD; 85649076Swpaul 857147291Sbrooks ifp = sc->sf_ifp = if_alloc(IFT_ETHER); 858147291Sbrooks if (ifp == NULL) { 859175526Syongari device_printf(dev, "can not allocate ifnet structure\n"); 860147291Sbrooks error = ENOSPC; 861147291Sbrooks goto fail; 862147291Sbrooks } 863147291Sbrooks 86450675Swpaul /* Do MII setup. */ 865213894Smarius error = mii_attach(dev, &sc->sf_miibus, ifp, sf_ifmedia_upd, 866213894Smarius sf_ifmedia_sts, BMSR_DEFCAPMASK, MII_PHY_ANY, MII_OFFSET_ANY, 0); 867213894Smarius if (error != 0) { 868213894Smarius device_printf(dev, "attaching PHYs failed\n"); 86949076Swpaul goto fail; 87049076Swpaul } 87149076Swpaul 87249076Swpaul ifp->if_softc = sc; 873121816Sbrooks if_initname(ifp, device_get_name(dev), device_get_unit(dev)); 874149240Sjhb ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 87549076Swpaul ifp->if_ioctl = sf_ioctl; 87649076Swpaul ifp->if_start = sf_start; 87749076Swpaul ifp->if_init = sf_init; 878137620Sbrueffer IFQ_SET_MAXLEN(&ifp->if_snd, SF_TX_DLIST_CNT - 1); 879137620Sbrueffer ifp->if_snd.ifq_drv_maxlen = SF_TX_DLIST_CNT - 1; 880137620Sbrueffer IFQ_SET_READY(&ifp->if_snd); 881175526Syongari /* 882175526Syongari * With the help of firmware, AIC-6915 supports 883175526Syongari * Tx/Rx TCP/UDP checksum offload. 884175526Syongari */ 885175526Syongari ifp->if_hwassist = SF_CSUM_FEATURES; 886175526Syongari ifp->if_capabilities = IFCAP_HWCSUM; 887175526Syongari 888175526Syongari /* 889175526Syongari * Call MI attach routine. 890175526Syongari */ 891175526Syongari ether_ifattach(ifp, eaddr); 892175526Syongari 893175526Syongari /* VLAN capability setup. */ 894175526Syongari ifp->if_capabilities |= IFCAP_VLAN_MTU; 895150789Sglebius ifp->if_capenable = ifp->if_capabilities; 896137557Sbrueffer#ifdef DEVICE_POLLING 897137557Sbrueffer ifp->if_capabilities |= IFCAP_POLLING; 898150789Sglebius#endif 89949076Swpaul /* 900175526Syongari * Tell the upper layer(s) we support long frames. 901175526Syongari * Must appear after the call to ether_ifattach() because 902175526Syongari * ether_ifattach() sets ifi_hdrlen to the default value. 90349076Swpaul */ 904175526Syongari ifp->if_data.ifi_hdrlen = sizeof(struct ether_vlan_header); 90549076Swpaul 906113609Snjl /* Hook interrupt last to avoid having to lock softc */ 907149240Sjhb error = bus_setup_intr(dev, sc->sf_irq, INTR_TYPE_NET | INTR_MPSAFE, 908166901Spiso NULL, sf_intr, sc, &sc->sf_intrhand); 909112872Snjl 910112872Snjl if (error) { 911148947Sjhb device_printf(dev, "couldn't set up irq\n"); 912113609Snjl ether_ifdetach(ifp); 913112872Snjl goto fail; 914112872Snjl } 915112872Snjl 91649076Swpaulfail: 917112872Snjl if (error) 918112872Snjl sf_detach(dev); 919112872Snjl 920175526Syongari return (error); 92149076Swpaul} 92249076Swpaul 923113609Snjl/* 924113609Snjl * Shutdown hardware and free up resources. This can be called any 925113609Snjl * time after the mutex has been initialized. It is called in both 926113609Snjl * the error case in attach and the normal detach case so it needs 927113609Snjl * to be careful about only freeing resources that have actually been 928113609Snjl * allocated. 929113609Snjl */ 930102335Salfredstatic int 931175526Syongarisf_detach(device_t dev) 93249076Swpaul{ 93349076Swpaul struct sf_softc *sc; 93449076Swpaul struct ifnet *ifp; 93549076Swpaul 93649076Swpaul sc = device_get_softc(dev); 937147256Sbrooks ifp = sc->sf_ifp; 93849076Swpaul 939150789Sglebius#ifdef DEVICE_POLLING 940175526Syongari if (ifp != NULL && ifp->if_capenable & IFCAP_POLLING) 941150789Sglebius ether_poll_deregister(ifp); 942150789Sglebius#endif 943175526Syongari 944113609Snjl /* These should only be active if attach succeeded */ 945113812Simp if (device_is_attached(dev)) { 946149240Sjhb SF_LOCK(sc); 947175526Syongari sc->sf_detach = 1; 948113609Snjl sf_stop(sc); 949149240Sjhb SF_UNLOCK(sc); 950175526Syongari callout_drain(&sc->sf_co); 951175526Syongari if (ifp != NULL) 952175526Syongari ether_ifdetach(ifp); 953150213Sru } 954175526Syongari if (sc->sf_miibus) { 955112872Snjl device_delete_child(dev, sc->sf_miibus); 956175526Syongari sc->sf_miibus = NULL; 957175526Syongari } 958113609Snjl bus_generic_detach(dev); 95949076Swpaul 960175526Syongari if (sc->sf_intrhand != NULL) 961112872Snjl bus_teardown_intr(dev, sc->sf_irq, sc->sf_intrhand); 962175526Syongari if (sc->sf_irq != NULL) 963112872Snjl bus_release_resource(dev, SYS_RES_IRQ, 0, sc->sf_irq); 964175526Syongari if (sc->sf_res != NULL) 965175526Syongari bus_release_resource(dev, sc->sf_restype, sc->sf_rid, 966175526Syongari sc->sf_res); 96750675Swpaul 968175526Syongari sf_dma_free(sc); 969175526Syongari if (ifp != NULL) 970151297Sru if_free(ifp); 971151297Sru 97267087Swpaul mtx_destroy(&sc->sf_mtx); 97349076Swpaul 974175526Syongari return (0); 97549076Swpaul} 97649076Swpaul 977175526Syongaristruct sf_dmamap_arg { 978175526Syongari bus_addr_t sf_busaddr; 979175526Syongari}; 980175526Syongari 981175526Syongaristatic void 982175526Syongarisf_dmamap_cb(void *arg, bus_dma_segment_t *segs, int nseg, int error) 983175526Syongari{ 984175526Syongari struct sf_dmamap_arg *ctx; 985175526Syongari 986175526Syongari if (error != 0) 987175526Syongari return; 988175526Syongari ctx = arg; 989175526Syongari ctx->sf_busaddr = segs[0].ds_addr; 990175526Syongari} 991175526Syongari 992102335Salfredstatic int 993175526Syongarisf_dma_alloc(struct sf_softc *sc) 99449076Swpaul{ 995175526Syongari struct sf_dmamap_arg ctx; 996175526Syongari struct sf_txdesc *txd; 997175526Syongari struct sf_rxdesc *rxd; 998175526Syongari bus_addr_t lowaddr; 999175526Syongari bus_addr_t rx_ring_end, rx_cring_end; 1000175526Syongari bus_addr_t tx_ring_end, tx_cring_end; 1001175526Syongari int error, i; 100249076Swpaul 1003175526Syongari lowaddr = BUS_SPACE_MAXADDR; 100449076Swpaul 1005175526Syongariagain: 1006175526Syongari /* Create parent DMA tag. */ 1007175526Syongari error = bus_dma_tag_create( 1008175526Syongari bus_get_dma_tag(sc->sf_dev), /* parent */ 1009175526Syongari 1, 0, /* alignment, boundary */ 1010175526Syongari lowaddr, /* lowaddr */ 1011175526Syongari BUS_SPACE_MAXADDR, /* highaddr */ 1012175526Syongari NULL, NULL, /* filter, filterarg */ 1013175526Syongari BUS_SPACE_MAXSIZE_32BIT, /* maxsize */ 1014175526Syongari 0, /* nsegments */ 1015175526Syongari BUS_SPACE_MAXSIZE_32BIT, /* maxsegsize */ 1016175526Syongari 0, /* flags */ 1017175526Syongari NULL, NULL, /* lockfunc, lockarg */ 1018175526Syongari &sc->sf_cdata.sf_parent_tag); 1019175526Syongari if (error != 0) { 1020175526Syongari device_printf(sc->sf_dev, "failed to create parent DMA tag\n"); 1021175526Syongari goto fail; 1022175526Syongari } 1023175526Syongari /* Create tag for Tx ring. */ 1024175526Syongari error = bus_dma_tag_create(sc->sf_cdata.sf_parent_tag,/* parent */ 1025175526Syongari SF_RING_ALIGN, 0, /* alignment, boundary */ 1026175526Syongari BUS_SPACE_MAXADDR, /* lowaddr */ 1027175526Syongari BUS_SPACE_MAXADDR, /* highaddr */ 1028175526Syongari NULL, NULL, /* filter, filterarg */ 1029175526Syongari SF_TX_DLIST_SIZE, /* maxsize */ 1030175526Syongari 1, /* nsegments */ 1031175526Syongari SF_TX_DLIST_SIZE, /* maxsegsize */ 1032175526Syongari 0, /* flags */ 1033175526Syongari NULL, NULL, /* lockfunc, lockarg */ 1034175526Syongari &sc->sf_cdata.sf_tx_ring_tag); 1035175526Syongari if (error != 0) { 1036175526Syongari device_printf(sc->sf_dev, "failed to create Tx ring DMA tag\n"); 1037175526Syongari goto fail; 1038175526Syongari } 103949076Swpaul 1040175526Syongari /* Create tag for Tx completion ring. */ 1041175526Syongari error = bus_dma_tag_create(sc->sf_cdata.sf_parent_tag,/* parent */ 1042175526Syongari SF_RING_ALIGN, 0, /* alignment, boundary */ 1043175526Syongari BUS_SPACE_MAXADDR, /* lowaddr */ 1044175526Syongari BUS_SPACE_MAXADDR, /* highaddr */ 1045175526Syongari NULL, NULL, /* filter, filterarg */ 1046175526Syongari SF_TX_CLIST_SIZE, /* maxsize */ 1047175526Syongari 1, /* nsegments */ 1048175526Syongari SF_TX_CLIST_SIZE, /* maxsegsize */ 1049175526Syongari 0, /* flags */ 1050175526Syongari NULL, NULL, /* lockfunc, lockarg */ 1051175526Syongari &sc->sf_cdata.sf_tx_cring_tag); 1052175526Syongari if (error != 0) { 1053175526Syongari device_printf(sc->sf_dev, 1054175526Syongari "failed to create Tx completion ring DMA tag\n"); 1055175526Syongari goto fail; 1056175526Syongari } 1057175526Syongari 1058175526Syongari /* Create tag for Rx ring. */ 1059175526Syongari error = bus_dma_tag_create(sc->sf_cdata.sf_parent_tag,/* parent */ 1060175526Syongari SF_RING_ALIGN, 0, /* alignment, boundary */ 1061175526Syongari BUS_SPACE_MAXADDR, /* lowaddr */ 1062175526Syongari BUS_SPACE_MAXADDR, /* highaddr */ 1063175526Syongari NULL, NULL, /* filter, filterarg */ 1064175526Syongari SF_RX_DLIST_SIZE, /* maxsize */ 1065175526Syongari 1, /* nsegments */ 1066175526Syongari SF_RX_DLIST_SIZE, /* maxsegsize */ 1067175526Syongari 0, /* flags */ 1068175526Syongari NULL, NULL, /* lockfunc, lockarg */ 1069175526Syongari &sc->sf_cdata.sf_rx_ring_tag); 1070175526Syongari if (error != 0) { 1071175526Syongari device_printf(sc->sf_dev, 1072175526Syongari "failed to create Rx ring DMA tag\n"); 1073175526Syongari goto fail; 1074175526Syongari } 1075175526Syongari 1076175526Syongari /* Create tag for Rx completion ring. */ 1077175526Syongari error = bus_dma_tag_create(sc->sf_cdata.sf_parent_tag,/* parent */ 1078175526Syongari SF_RING_ALIGN, 0, /* alignment, boundary */ 1079175526Syongari BUS_SPACE_MAXADDR, /* lowaddr */ 1080175526Syongari BUS_SPACE_MAXADDR, /* highaddr */ 1081175526Syongari NULL, NULL, /* filter, filterarg */ 1082175526Syongari SF_RX_CLIST_SIZE, /* maxsize */ 1083175526Syongari 1, /* nsegments */ 1084175526Syongari SF_RX_CLIST_SIZE, /* maxsegsize */ 1085175526Syongari 0, /* flags */ 1086175526Syongari NULL, NULL, /* lockfunc, lockarg */ 1087175526Syongari &sc->sf_cdata.sf_rx_cring_tag); 1088175526Syongari if (error != 0) { 1089175526Syongari device_printf(sc->sf_dev, 1090175526Syongari "failed to create Rx completion ring DMA tag\n"); 1091175526Syongari goto fail; 1092175526Syongari } 1093175526Syongari 1094175526Syongari /* Create tag for Tx buffers. */ 1095175526Syongari error = bus_dma_tag_create(sc->sf_cdata.sf_parent_tag,/* parent */ 1096175526Syongari 1, 0, /* alignment, boundary */ 1097175526Syongari BUS_SPACE_MAXADDR, /* lowaddr */ 1098175526Syongari BUS_SPACE_MAXADDR, /* highaddr */ 1099175526Syongari NULL, NULL, /* filter, filterarg */ 1100175526Syongari MCLBYTES * SF_MAXTXSEGS, /* maxsize */ 1101175526Syongari SF_MAXTXSEGS, /* nsegments */ 1102175526Syongari MCLBYTES, /* maxsegsize */ 1103175526Syongari 0, /* flags */ 1104175526Syongari NULL, NULL, /* lockfunc, lockarg */ 1105175526Syongari &sc->sf_cdata.sf_tx_tag); 1106175526Syongari if (error != 0) { 1107175526Syongari device_printf(sc->sf_dev, "failed to create Tx DMA tag\n"); 1108175526Syongari goto fail; 1109175526Syongari } 1110175526Syongari 1111175526Syongari /* Create tag for Rx buffers. */ 1112175526Syongari error = bus_dma_tag_create(sc->sf_cdata.sf_parent_tag,/* parent */ 1113175526Syongari SF_RX_ALIGN, 0, /* alignment, boundary */ 1114175526Syongari BUS_SPACE_MAXADDR, /* lowaddr */ 1115175526Syongari BUS_SPACE_MAXADDR, /* highaddr */ 1116175526Syongari NULL, NULL, /* filter, filterarg */ 1117175526Syongari MCLBYTES, /* maxsize */ 1118175526Syongari 1, /* nsegments */ 1119175526Syongari MCLBYTES, /* maxsegsize */ 1120175526Syongari 0, /* flags */ 1121175526Syongari NULL, NULL, /* lockfunc, lockarg */ 1122175526Syongari &sc->sf_cdata.sf_rx_tag); 1123175526Syongari if (error != 0) { 1124175526Syongari device_printf(sc->sf_dev, "failed to create Rx DMA tag\n"); 1125175526Syongari goto fail; 1126175526Syongari } 1127175526Syongari 1128175526Syongari /* Allocate DMA'able memory and load the DMA map for Tx ring. */ 1129175526Syongari error = bus_dmamem_alloc(sc->sf_cdata.sf_tx_ring_tag, 1130175526Syongari (void **)&sc->sf_rdata.sf_tx_ring, BUS_DMA_WAITOK | 1131175526Syongari BUS_DMA_COHERENT | BUS_DMA_ZERO, &sc->sf_cdata.sf_tx_ring_map); 1132175526Syongari if (error != 0) { 1133175526Syongari device_printf(sc->sf_dev, 1134175526Syongari "failed to allocate DMA'able memory for Tx ring\n"); 1135175526Syongari goto fail; 1136175526Syongari } 1137175526Syongari 1138175526Syongari ctx.sf_busaddr = 0; 1139175526Syongari error = bus_dmamap_load(sc->sf_cdata.sf_tx_ring_tag, 1140175526Syongari sc->sf_cdata.sf_tx_ring_map, sc->sf_rdata.sf_tx_ring, 1141175526Syongari SF_TX_DLIST_SIZE, sf_dmamap_cb, &ctx, 0); 1142175526Syongari if (error != 0 || ctx.sf_busaddr == 0) { 1143175526Syongari device_printf(sc->sf_dev, 1144175526Syongari "failed to load DMA'able memory for Tx ring\n"); 1145175526Syongari goto fail; 1146175526Syongari } 1147175526Syongari sc->sf_rdata.sf_tx_ring_paddr = ctx.sf_busaddr; 1148175526Syongari 1149175526Syongari /* 1150175526Syongari * Allocate DMA'able memory and load the DMA map for Tx completion ring. 1151175526Syongari */ 1152175526Syongari error = bus_dmamem_alloc(sc->sf_cdata.sf_tx_cring_tag, 1153175526Syongari (void **)&sc->sf_rdata.sf_tx_cring, BUS_DMA_WAITOK | 1154175526Syongari BUS_DMA_COHERENT | BUS_DMA_ZERO, &sc->sf_cdata.sf_tx_cring_map); 1155175526Syongari if (error != 0) { 1156175526Syongari device_printf(sc->sf_dev, 1157175526Syongari "failed to allocate DMA'able memory for " 1158175526Syongari "Tx completion ring\n"); 1159175526Syongari goto fail; 1160175526Syongari } 1161175526Syongari 1162175526Syongari ctx.sf_busaddr = 0; 1163175526Syongari error = bus_dmamap_load(sc->sf_cdata.sf_tx_cring_tag, 1164175526Syongari sc->sf_cdata.sf_tx_cring_map, sc->sf_rdata.sf_tx_cring, 1165175526Syongari SF_TX_CLIST_SIZE, sf_dmamap_cb, &ctx, 0); 1166175526Syongari if (error != 0 || ctx.sf_busaddr == 0) { 1167175526Syongari device_printf(sc->sf_dev, 1168175526Syongari "failed to load DMA'able memory for Tx completion ring\n"); 1169175526Syongari goto fail; 1170175526Syongari } 1171175526Syongari sc->sf_rdata.sf_tx_cring_paddr = ctx.sf_busaddr; 1172175526Syongari 1173175526Syongari /* Allocate DMA'able memory and load the DMA map for Rx ring. */ 1174175526Syongari error = bus_dmamem_alloc(sc->sf_cdata.sf_rx_ring_tag, 1175175526Syongari (void **)&sc->sf_rdata.sf_rx_ring, BUS_DMA_WAITOK | 1176175526Syongari BUS_DMA_COHERENT | BUS_DMA_ZERO, &sc->sf_cdata.sf_rx_ring_map); 1177175526Syongari if (error != 0) { 1178175526Syongari device_printf(sc->sf_dev, 1179175526Syongari "failed to allocate DMA'able memory for Rx ring\n"); 1180175526Syongari goto fail; 1181175526Syongari } 1182175526Syongari 1183175526Syongari ctx.sf_busaddr = 0; 1184175526Syongari error = bus_dmamap_load(sc->sf_cdata.sf_rx_ring_tag, 1185175526Syongari sc->sf_cdata.sf_rx_ring_map, sc->sf_rdata.sf_rx_ring, 1186175526Syongari SF_RX_DLIST_SIZE, sf_dmamap_cb, &ctx, 0); 1187175526Syongari if (error != 0 || ctx.sf_busaddr == 0) { 1188175526Syongari device_printf(sc->sf_dev, 1189175526Syongari "failed to load DMA'able memory for Rx ring\n"); 1190175526Syongari goto fail; 1191175526Syongari } 1192175526Syongari sc->sf_rdata.sf_rx_ring_paddr = ctx.sf_busaddr; 1193175526Syongari 1194175526Syongari /* 1195175526Syongari * Allocate DMA'able memory and load the DMA map for Rx completion ring. 1196175526Syongari */ 1197175526Syongari error = bus_dmamem_alloc(sc->sf_cdata.sf_rx_cring_tag, 1198175526Syongari (void **)&sc->sf_rdata.sf_rx_cring, BUS_DMA_WAITOK | 1199175526Syongari BUS_DMA_COHERENT | BUS_DMA_ZERO, &sc->sf_cdata.sf_rx_cring_map); 1200175526Syongari if (error != 0) { 1201175526Syongari device_printf(sc->sf_dev, 1202175526Syongari "failed to allocate DMA'able memory for " 1203175526Syongari "Rx completion ring\n"); 1204175526Syongari goto fail; 1205175526Syongari } 1206175526Syongari 1207175526Syongari ctx.sf_busaddr = 0; 1208175526Syongari error = bus_dmamap_load(sc->sf_cdata.sf_rx_cring_tag, 1209175526Syongari sc->sf_cdata.sf_rx_cring_map, sc->sf_rdata.sf_rx_cring, 1210175526Syongari SF_RX_CLIST_SIZE, sf_dmamap_cb, &ctx, 0); 1211175526Syongari if (error != 0 || ctx.sf_busaddr == 0) { 1212175526Syongari device_printf(sc->sf_dev, 1213175526Syongari "failed to load DMA'able memory for Rx completion ring\n"); 1214175526Syongari goto fail; 1215175526Syongari } 1216175526Syongari sc->sf_rdata.sf_rx_cring_paddr = ctx.sf_busaddr; 1217175526Syongari 1218175526Syongari /* 1219175526Syongari * Tx desciptor ring and Tx completion ring should be addressed in 1220175526Syongari * the same 4GB space. The same rule applys to Rx ring and Rx 1221175526Syongari * completion ring. Unfortunately there is no way to specify this 1222175526Syongari * boundary restriction with bus_dma(9). So just try to allocate 1223175526Syongari * without the restriction and check the restriction was satisfied. 1224175526Syongari * If not, fall back to 32bit dma addressing mode which always 1225175526Syongari * guarantees the restriction. 1226175526Syongari */ 1227175526Syongari tx_ring_end = sc->sf_rdata.sf_tx_ring_paddr + SF_TX_DLIST_SIZE; 1228175526Syongari tx_cring_end = sc->sf_rdata.sf_tx_cring_paddr + SF_TX_CLIST_SIZE; 1229175526Syongari rx_ring_end = sc->sf_rdata.sf_rx_ring_paddr + SF_RX_DLIST_SIZE; 1230175526Syongari rx_cring_end = sc->sf_rdata.sf_rx_cring_paddr + SF_RX_CLIST_SIZE; 1231175526Syongari if ((SF_ADDR_HI(sc->sf_rdata.sf_tx_ring_paddr) != 1232175526Syongari SF_ADDR_HI(tx_cring_end)) || 1233175526Syongari (SF_ADDR_HI(sc->sf_rdata.sf_tx_cring_paddr) != 1234175526Syongari SF_ADDR_HI(tx_ring_end)) || 1235175526Syongari (SF_ADDR_HI(sc->sf_rdata.sf_rx_ring_paddr) != 1236175526Syongari SF_ADDR_HI(rx_cring_end)) || 1237175526Syongari (SF_ADDR_HI(sc->sf_rdata.sf_rx_cring_paddr) != 1238175526Syongari SF_ADDR_HI(rx_ring_end))) { 1239175526Syongari device_printf(sc->sf_dev, 1240175526Syongari "switching to 32bit DMA mode\n"); 1241175526Syongari sf_dma_free(sc); 1242175526Syongari /* Limit DMA address space to 32bit and try again. */ 1243175526Syongari lowaddr = BUS_SPACE_MAXADDR_32BIT; 1244175526Syongari goto again; 1245175526Syongari } 1246175526Syongari 1247175526Syongari /* Create DMA maps for Tx buffers. */ 1248175526Syongari for (i = 0; i < SF_TX_DLIST_CNT; i++) { 1249175526Syongari txd = &sc->sf_cdata.sf_txdesc[i]; 1250175526Syongari txd->tx_m = NULL; 1251175526Syongari txd->ndesc = 0; 1252175526Syongari txd->tx_dmamap = NULL; 1253175526Syongari error = bus_dmamap_create(sc->sf_cdata.sf_tx_tag, 0, 1254175526Syongari &txd->tx_dmamap); 1255175526Syongari if (error != 0) { 1256175526Syongari device_printf(sc->sf_dev, 1257175526Syongari "failed to create Tx dmamap\n"); 1258175526Syongari goto fail; 1259175526Syongari } 1260175526Syongari } 1261175526Syongari /* Create DMA maps for Rx buffers. */ 1262175526Syongari if ((error = bus_dmamap_create(sc->sf_cdata.sf_rx_tag, 0, 1263175526Syongari &sc->sf_cdata.sf_rx_sparemap)) != 0) { 1264175526Syongari device_printf(sc->sf_dev, 1265175526Syongari "failed to create spare Rx dmamap\n"); 1266175526Syongari goto fail; 1267175526Syongari } 126849076Swpaul for (i = 0; i < SF_RX_DLIST_CNT; i++) { 1269175526Syongari rxd = &sc->sf_cdata.sf_rxdesc[i]; 1270175526Syongari rxd->rx_m = NULL; 1271175526Syongari rxd->rx_dmamap = NULL; 1272175526Syongari error = bus_dmamap_create(sc->sf_cdata.sf_rx_tag, 0, 1273175526Syongari &rxd->rx_dmamap); 1274175526Syongari if (error != 0) { 1275175526Syongari device_printf(sc->sf_dev, 1276175526Syongari "failed to create Rx dmamap\n"); 1277175526Syongari goto fail; 1278175526Syongari } 127949076Swpaul } 128049076Swpaul 1281175526Syongarifail: 1282175526Syongari return (error); 128349076Swpaul} 128449076Swpaul 1285102335Salfredstatic void 1286175526Syongarisf_dma_free(struct sf_softc *sc) 128749076Swpaul{ 1288175526Syongari struct sf_txdesc *txd; 1289175526Syongari struct sf_rxdesc *rxd; 129049076Swpaul int i; 129149076Swpaul 1292175526Syongari /* Tx ring. */ 1293175526Syongari if (sc->sf_cdata.sf_tx_ring_tag) { 1294175526Syongari if (sc->sf_cdata.sf_tx_ring_map) 1295175526Syongari bus_dmamap_unload(sc->sf_cdata.sf_tx_ring_tag, 1296175526Syongari sc->sf_cdata.sf_tx_ring_map); 1297175526Syongari if (sc->sf_cdata.sf_tx_ring_map && 1298175526Syongari sc->sf_rdata.sf_tx_ring) 1299175526Syongari bus_dmamem_free(sc->sf_cdata.sf_tx_ring_tag, 1300175526Syongari sc->sf_rdata.sf_tx_ring, 1301175526Syongari sc->sf_cdata.sf_tx_ring_map); 1302175526Syongari sc->sf_rdata.sf_tx_ring = NULL; 1303175526Syongari sc->sf_cdata.sf_tx_ring_map = NULL; 1304175526Syongari bus_dma_tag_destroy(sc->sf_cdata.sf_tx_ring_tag); 1305175526Syongari sc->sf_cdata.sf_tx_ring_tag = NULL; 1306175526Syongari } 1307175526Syongari /* Tx completion ring. */ 1308175526Syongari if (sc->sf_cdata.sf_tx_cring_tag) { 1309175526Syongari if (sc->sf_cdata.sf_tx_cring_map) 1310175526Syongari bus_dmamap_unload(sc->sf_cdata.sf_tx_cring_tag, 1311175526Syongari sc->sf_cdata.sf_tx_cring_map); 1312175526Syongari if (sc->sf_cdata.sf_tx_cring_map && 1313175526Syongari sc->sf_rdata.sf_tx_cring) 1314175526Syongari bus_dmamem_free(sc->sf_cdata.sf_tx_cring_tag, 1315175526Syongari sc->sf_rdata.sf_tx_cring, 1316175526Syongari sc->sf_cdata.sf_tx_cring_map); 1317175526Syongari sc->sf_rdata.sf_tx_cring = NULL; 1318175526Syongari sc->sf_cdata.sf_tx_cring_map = NULL; 1319175526Syongari bus_dma_tag_destroy(sc->sf_cdata.sf_tx_cring_tag); 1320175526Syongari sc->sf_cdata.sf_tx_cring_tag = NULL; 1321175526Syongari } 1322175526Syongari /* Rx ring. */ 1323175526Syongari if (sc->sf_cdata.sf_rx_ring_tag) { 1324175526Syongari if (sc->sf_cdata.sf_rx_ring_map) 1325175526Syongari bus_dmamap_unload(sc->sf_cdata.sf_rx_ring_tag, 1326175526Syongari sc->sf_cdata.sf_rx_ring_map); 1327175526Syongari if (sc->sf_cdata.sf_rx_ring_map && 1328175526Syongari sc->sf_rdata.sf_rx_ring) 1329175526Syongari bus_dmamem_free(sc->sf_cdata.sf_rx_ring_tag, 1330175526Syongari sc->sf_rdata.sf_rx_ring, 1331175526Syongari sc->sf_cdata.sf_rx_ring_map); 1332175526Syongari sc->sf_rdata.sf_rx_ring = NULL; 1333175526Syongari sc->sf_cdata.sf_rx_ring_map = NULL; 1334175526Syongari bus_dma_tag_destroy(sc->sf_cdata.sf_rx_ring_tag); 1335175526Syongari sc->sf_cdata.sf_rx_ring_tag = NULL; 1336175526Syongari } 1337175526Syongari /* Rx completion ring. */ 1338175526Syongari if (sc->sf_cdata.sf_rx_cring_tag) { 1339175526Syongari if (sc->sf_cdata.sf_rx_cring_map) 1340175526Syongari bus_dmamap_unload(sc->sf_cdata.sf_rx_cring_tag, 1341175526Syongari sc->sf_cdata.sf_rx_cring_map); 1342175526Syongari if (sc->sf_cdata.sf_rx_cring_map && 1343175526Syongari sc->sf_rdata.sf_rx_cring) 1344175526Syongari bus_dmamem_free(sc->sf_cdata.sf_rx_cring_tag, 1345175526Syongari sc->sf_rdata.sf_rx_cring, 1346175526Syongari sc->sf_cdata.sf_rx_cring_map); 1347175526Syongari sc->sf_rdata.sf_rx_cring = NULL; 1348175526Syongari sc->sf_cdata.sf_rx_cring_map = NULL; 1349175526Syongari bus_dma_tag_destroy(sc->sf_cdata.sf_rx_cring_tag); 1350175526Syongari sc->sf_cdata.sf_rx_cring_tag = NULL; 1351175526Syongari } 1352175526Syongari /* Tx buffers. */ 1353175526Syongari if (sc->sf_cdata.sf_tx_tag) { 1354175526Syongari for (i = 0; i < SF_TX_DLIST_CNT; i++) { 1355175526Syongari txd = &sc->sf_cdata.sf_txdesc[i]; 1356175526Syongari if (txd->tx_dmamap) { 1357175526Syongari bus_dmamap_destroy(sc->sf_cdata.sf_tx_tag, 1358175526Syongari txd->tx_dmamap); 1359175526Syongari txd->tx_dmamap = NULL; 1360175526Syongari } 1361175526Syongari } 1362175526Syongari bus_dma_tag_destroy(sc->sf_cdata.sf_tx_tag); 1363175526Syongari sc->sf_cdata.sf_tx_tag = NULL; 1364175526Syongari } 1365175526Syongari /* Rx buffers. */ 1366175526Syongari if (sc->sf_cdata.sf_rx_tag) { 1367175526Syongari for (i = 0; i < SF_RX_DLIST_CNT; i++) { 1368175526Syongari rxd = &sc->sf_cdata.sf_rxdesc[i]; 1369175526Syongari if (rxd->rx_dmamap) { 1370175526Syongari bus_dmamap_destroy(sc->sf_cdata.sf_rx_tag, 1371175526Syongari rxd->rx_dmamap); 1372175526Syongari rxd->rx_dmamap = NULL; 1373175526Syongari } 1374175526Syongari } 1375175526Syongari if (sc->sf_cdata.sf_rx_sparemap) { 1376175526Syongari bus_dmamap_destroy(sc->sf_cdata.sf_rx_tag, 1377175526Syongari sc->sf_cdata.sf_rx_sparemap); 1378175526Syongari sc->sf_cdata.sf_rx_sparemap = 0; 1379175526Syongari } 1380175526Syongari bus_dma_tag_destroy(sc->sf_cdata.sf_rx_tag); 1381175526Syongari sc->sf_cdata.sf_rx_tag = NULL; 1382175526Syongari } 138349076Swpaul 1384175526Syongari if (sc->sf_cdata.sf_parent_tag) { 1385175526Syongari bus_dma_tag_destroy(sc->sf_cdata.sf_parent_tag); 1386175526Syongari sc->sf_cdata.sf_parent_tag = NULL; 1387175526Syongari } 1388175526Syongari} 138949076Swpaul 1390175526Syongaristatic int 1391175526Syongarisf_init_rx_ring(struct sf_softc *sc) 1392175526Syongari{ 1393175526Syongari struct sf_ring_data *rd; 1394175526Syongari int i; 139549076Swpaul 1396175526Syongari sc->sf_cdata.sf_rxc_cons = 0; 1397175526Syongari 1398175526Syongari rd = &sc->sf_rdata; 1399175526Syongari bzero(rd->sf_rx_ring, SF_RX_DLIST_SIZE); 1400175526Syongari bzero(rd->sf_rx_cring, SF_RX_CLIST_SIZE); 1401175526Syongari 1402175526Syongari for (i = 0; i < SF_RX_DLIST_CNT; i++) { 1403175526Syongari if (sf_newbuf(sc, i) != 0) 1404175526Syongari return (ENOBUFS); 1405175526Syongari } 1406175526Syongari 1407175526Syongari bus_dmamap_sync(sc->sf_cdata.sf_rx_cring_tag, 1408175526Syongari sc->sf_cdata.sf_rx_cring_map, 1409175526Syongari BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 1410175526Syongari bus_dmamap_sync(sc->sf_cdata.sf_rx_ring_tag, 1411175526Syongari sc->sf_cdata.sf_rx_ring_map, 1412175526Syongari BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 1413175526Syongari 1414175526Syongari return (0); 141549076Swpaul} 141649076Swpaul 1417175526Syongaristatic void 1418175526Syongarisf_init_tx_ring(struct sf_softc *sc) 1419175526Syongari{ 1420175526Syongari struct sf_ring_data *rd; 1421175526Syongari int i; 1422175526Syongari 1423175526Syongari sc->sf_cdata.sf_tx_prod = 0; 1424175526Syongari sc->sf_cdata.sf_tx_cnt = 0; 1425175526Syongari sc->sf_cdata.sf_txc_cons = 0; 1426175526Syongari 1427175526Syongari rd = &sc->sf_rdata; 1428175526Syongari bzero(rd->sf_tx_ring, SF_TX_DLIST_SIZE); 1429175526Syongari bzero(rd->sf_tx_cring, SF_TX_CLIST_SIZE); 1430175526Syongari for (i = 0; i < SF_TX_DLIST_CNT; i++) { 1431175526Syongari rd->sf_tx_ring[i].sf_tx_ctrl = htole32(SF_TX_DESC_ID); 1432175526Syongari sc->sf_cdata.sf_txdesc[i].tx_m = NULL; 1433175526Syongari sc->sf_cdata.sf_txdesc[i].ndesc = 0; 1434175526Syongari } 1435175526Syongari rd->sf_tx_ring[i].sf_tx_ctrl |= htole32(SF_TX_DESC_END); 1436175526Syongari 1437175526Syongari bus_dmamap_sync(sc->sf_cdata.sf_tx_ring_tag, 1438175526Syongari sc->sf_cdata.sf_tx_ring_map, 1439175526Syongari BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 1440175526Syongari bus_dmamap_sync(sc->sf_cdata.sf_tx_cring_tag, 1441175526Syongari sc->sf_cdata.sf_tx_cring_map, 1442175526Syongari BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 1443175526Syongari} 1444175526Syongari 1445175526Syongari/* 1446175526Syongari * Initialize an RX descriptor and attach an MBUF cluster. 1447175526Syongari */ 1448102335Salfredstatic int 1449175526Syongarisf_newbuf(struct sf_softc *sc, int idx) 1450175526Syongari{ 1451175526Syongari struct sf_rx_rdesc *desc; 1452175526Syongari struct sf_rxdesc *rxd; 145349076Swpaul struct mbuf *m; 1454175526Syongari bus_dma_segment_t segs[1]; 1455175526Syongari bus_dmamap_t map; 1456175526Syongari int nsegs; 145749076Swpaul 1458243857Sglebius m = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR); 1459175526Syongari if (m == NULL) 1460175526Syongari return (ENOBUFS); 1461175526Syongari m->m_len = m->m_pkthdr.len = MCLBYTES; 1462175526Syongari m_adj(m, sizeof(uint32_t)); 146349076Swpaul 1464175526Syongari if (bus_dmamap_load_mbuf_sg(sc->sf_cdata.sf_rx_tag, 1465175526Syongari sc->sf_cdata.sf_rx_sparemap, m, segs, &nsegs, 0) != 0) { 1466175526Syongari m_freem(m); 1467175526Syongari return (ENOBUFS); 146849076Swpaul } 1469175526Syongari KASSERT(nsegs == 1, ("%s: %d segments returned!", __func__, nsegs)); 147049076Swpaul 1471175526Syongari rxd = &sc->sf_cdata.sf_rxdesc[idx]; 1472175526Syongari if (rxd->rx_m != NULL) { 1473175526Syongari bus_dmamap_sync(sc->sf_cdata.sf_rx_tag, rxd->rx_dmamap, 1474175526Syongari BUS_DMASYNC_POSTREAD); 1475175526Syongari bus_dmamap_unload(sc->sf_cdata.sf_rx_tag, rxd->rx_dmamap); 1476175526Syongari } 1477175526Syongari map = rxd->rx_dmamap; 1478175526Syongari rxd->rx_dmamap = sc->sf_cdata.sf_rx_sparemap; 1479175526Syongari sc->sf_cdata.sf_rx_sparemap = map; 1480175526Syongari bus_dmamap_sync(sc->sf_cdata.sf_rx_tag, rxd->rx_dmamap, 1481175526Syongari BUS_DMASYNC_PREREAD); 1482175526Syongari rxd->rx_m = m; 1483175526Syongari desc = &sc->sf_rdata.sf_rx_ring[idx]; 1484175526Syongari desc->sf_addr = htole64(segs[0].ds_addr); 148549076Swpaul 1486175526Syongari return (0); 1487175526Syongari} 148849076Swpaul 1489175526Syongari#ifndef __NO_STRICT_ALIGNMENT 1490175526Syongaristatic __inline void 1491175526Syongarisf_fixup_rx(struct mbuf *m) 1492175526Syongari{ 1493175526Syongari int i; 1494175526Syongari uint16_t *src, *dst; 1495175526Syongari 1496175526Syongari src = mtod(m, uint16_t *); 1497175526Syongari dst = src - 1; 1498175526Syongari 1499175526Syongari for (i = 0; i < (m->m_len / sizeof(uint16_t) + 1); i++) 1500175526Syongari *dst++ = *src++; 1501175526Syongari 1502175526Syongari m->m_data -= ETHER_ALIGN; 150349076Swpaul} 1504175526Syongari#endif 150549076Swpaul 150649076Swpaul/* 150749076Swpaul * The starfire is programmed to use 'normal' mode for packet reception, 150849076Swpaul * which means we use the consumer/producer model for both the buffer 150949076Swpaul * descriptor queue and the completion descriptor queue. The only problem 151049076Swpaul * with this is that it involves a lot of register accesses: we have to 151149076Swpaul * read the RX completion consumer and producer indexes and the RX buffer 151249076Swpaul * producer index, plus the RX completion consumer and RX buffer producer 151349076Swpaul * indexes have to be updated. It would have been easier if Adaptec had 151449076Swpaul * put each index in a separate register, especially given that the damn 151549076Swpaul * NIC has a 512K register space. 151649076Swpaul * 151749076Swpaul * In spite of all the lovely features that Adaptec crammed into the 6915, 151849076Swpaul * it is marred by one truly stupid design flaw, which is that receive 151949076Swpaul * buffer addresses must be aligned on a longword boundary. This forces 152049076Swpaul * the packet payload to be unaligned, which is suboptimal on the x86 and 152149076Swpaul * completely unuseable on the Alpha. Our only recourse is to copy received 152249076Swpaul * packets into properly aligned buffers before handing them off. 152349076Swpaul */ 1524193096Sattiliostatic int 1525175526Syongarisf_rxeof(struct sf_softc *sc) 152649076Swpaul{ 152749076Swpaul struct mbuf *m; 152849076Swpaul struct ifnet *ifp; 1529175526Syongari struct sf_rxdesc *rxd; 1530175526Syongari struct sf_rx_rcdesc *cur_cmp; 1531193096Sattilio int cons, eidx, prog, rx_npkts; 1532175526Syongari uint32_t status, status2; 153349076Swpaul 1534122689Ssam SF_LOCK_ASSERT(sc); 1535122689Ssam 1536147256Sbrooks ifp = sc->sf_ifp; 1537193096Sattilio rx_npkts = 0; 153849076Swpaul 1539175526Syongari bus_dmamap_sync(sc->sf_cdata.sf_rx_ring_tag, 1540175526Syongari sc->sf_cdata.sf_rx_ring_map, 1541175526Syongari BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); 1542175526Syongari bus_dmamap_sync(sc->sf_cdata.sf_rx_cring_tag, 1543175526Syongari sc->sf_cdata.sf_rx_cring_map, 1544175526Syongari BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); 154549076Swpaul 1546175526Syongari /* 1547175526Syongari * To reduce register access, directly read Receive completion 1548175526Syongari * queue entry. 1549175526Syongari */ 1550175526Syongari eidx = 0; 1551175526Syongari prog = 0; 1552232040Syongari for (cons = sc->sf_cdata.sf_rxc_cons; 1553232040Syongari (ifp->if_drv_flags & IFF_DRV_RUNNING) != 0; 1554232040Syongari SF_INC(cons, SF_RX_CLIST_CNT)) { 1555175526Syongari cur_cmp = &sc->sf_rdata.sf_rx_cring[cons]; 1556175526Syongari status = le32toh(cur_cmp->sf_rx_status1); 1557175526Syongari if (status == 0) 1558175526Syongari break; 1559137557Sbrueffer#ifdef DEVICE_POLLING 1560175526Syongari if ((ifp->if_capenable & IFCAP_POLLING) != 0) { 1561137557Sbrueffer if (sc->rxcycles <= 0) 1562137557Sbrueffer break; 1563137557Sbrueffer sc->rxcycles--; 1564137557Sbrueffer } 1565150789Sglebius#endif 1566175526Syongari prog++; 1567175526Syongari eidx = (status & SF_RX_CMPDESC_EIDX) >> 16; 1568175526Syongari rxd = &sc->sf_cdata.sf_rxdesc[eidx]; 1569175526Syongari m = rxd->rx_m; 1570137557Sbrueffer 1571175526Syongari /* 1572175526Syongari * Note, if_ipackets and if_ierrors counters 1573175526Syongari * are handled in sf_stats_update(). 1574175526Syongari */ 1575175526Syongari if ((status & SF_RXSTAT1_OK) == 0) { 1576175526Syongari cur_cmp->sf_rx_status1 = 0; 157749076Swpaul continue; 157849076Swpaul } 157949076Swpaul 1580175526Syongari if (sf_newbuf(sc, eidx) != 0) { 1581175526Syongari ifp->if_iqdrops++; 1582175526Syongari cur_cmp->sf_rx_status1 = 0; 158349076Swpaul continue; 158449076Swpaul } 158549076Swpaul 1586175526Syongari /* AIC-6915 supports TCP/UDP checksum offload. */ 1587175526Syongari if ((ifp->if_capenable & IFCAP_RXCSUM) != 0) { 1588175526Syongari status2 = le32toh(cur_cmp->sf_rx_status2); 1589175526Syongari /* 1590175526Syongari * Sometimes AIC-6915 generates an interrupt to 1591175526Syongari * warn RxGFP stall with bad checksum bit set 1592175526Syongari * in status word. I'm not sure what conditioan 1593175526Syongari * triggers it but recevied packet's checksum 1594175526Syongari * was correct even though AIC-6915 does not 1595175526Syongari * agree on this. This may be an indication of 1596175526Syongari * firmware bug. To fix the issue, do not rely 1597175526Syongari * on bad checksum bit in status word and let 1598175526Syongari * upper layer verify integrity of received 1599175526Syongari * frame. 1600175526Syongari * Another nice feature of AIC-6915 is hardware 1601175526Syongari * assistance of checksum calculation by 1602175526Syongari * providing partial checksum value for received 1603175526Syongari * frame. The partial checksum value can be used 1604175526Syongari * to accelerate checksum computation for 1605175526Syongari * fragmented TCP/UDP packets. Upper network 1606175526Syongari * stack already takes advantage of the partial 1607175526Syongari * checksum value in IP reassembly stage. But 1608175526Syongari * I'm not sure the correctness of the partial 1609175526Syongari * hardware checksum assistance as frequent 1610175526Syongari * RxGFP stalls are seen on non-fragmented 1611175526Syongari * frames. Due to the nature of the complexity 1612175526Syongari * of checksum computation code in firmware it's 1613175526Syongari * possible to see another bug in RxGFP so 1614175526Syongari * ignore checksum assistance for fragmented 1615175526Syongari * frames. This can be changed in future. 1616175526Syongari */ 1617175526Syongari if ((status2 & SF_RXSTAT2_FRAG) == 0) { 1618175526Syongari if ((status2 & (SF_RXSTAT2_TCP | 1619175526Syongari SF_RXSTAT2_UDP)) != 0) { 1620175526Syongari if ((status2 & SF_RXSTAT2_CSUM_OK)) { 1621175526Syongari m->m_pkthdr.csum_flags = 1622175526Syongari CSUM_DATA_VALID | 1623175526Syongari CSUM_PSEUDO_HDR; 1624175526Syongari m->m_pkthdr.csum_data = 0xffff; 1625175526Syongari } 1626175526Syongari } 1627175526Syongari } 1628175526Syongari#ifdef SF_PARTIAL_CSUM_SUPPORT 1629175526Syongari else if ((status2 & SF_RXSTAT2_FRAG) != 0) { 1630175526Syongari if ((status2 & (SF_RXSTAT2_TCP | 1631175526Syongari SF_RXSTAT2_UDP)) != 0) { 1632175526Syongari if ((status2 & SF_RXSTAT2_PCSUM_OK)) { 1633175526Syongari m->m_pkthdr.csum_flags = 1634175526Syongari CSUM_DATA_VALID; 1635175526Syongari m->m_pkthdr.csum_data = 1636175526Syongari (status & 1637175526Syongari SF_RX_CMPDESC_CSUM2); 1638175526Syongari } 1639175526Syongari } 1640175526Syongari } 1641175526Syongari#endif 1642175526Syongari } 1643175526Syongari 1644175526Syongari m->m_pkthdr.len = m->m_len = status & SF_RX_CMPDESC_LEN; 1645175526Syongari#ifndef __NO_STRICT_ALIGNMENT 1646175526Syongari sf_fixup_rx(m); 1647175526Syongari#endif 1648175526Syongari m->m_pkthdr.rcvif = ifp; 1649175526Syongari 1650122689Ssam SF_UNLOCK(sc); 1651106936Ssam (*ifp->if_input)(ifp, m); 1652122689Ssam SF_LOCK(sc); 1653193096Sattilio rx_npkts++; 1654175526Syongari 1655175526Syongari /* Clear completion status. */ 1656175526Syongari cur_cmp->sf_rx_status1 = 0; 165749076Swpaul } 165849076Swpaul 1659175526Syongari if (prog > 0) { 1660175526Syongari sc->sf_cdata.sf_rxc_cons = cons; 1661175526Syongari bus_dmamap_sync(sc->sf_cdata.sf_rx_ring_tag, 1662175526Syongari sc->sf_cdata.sf_rx_ring_map, 1663175526Syongari BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 1664175526Syongari bus_dmamap_sync(sc->sf_cdata.sf_rx_cring_tag, 1665175526Syongari sc->sf_cdata.sf_rx_cring_map, 1666175526Syongari BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 1667175526Syongari 1668175526Syongari /* Update Rx completion Q1 consumer index. */ 1669175526Syongari csr_write_4(sc, SF_CQ_CONSIDX, 1670175526Syongari (csr_read_4(sc, SF_CQ_CONSIDX) & ~SF_CQ_CONSIDX_RXQ1) | 1671175526Syongari (cons & SF_CQ_CONSIDX_RXQ1)); 1672175526Syongari /* Update Rx descriptor Q1 ptr. */ 1673175526Syongari csr_write_4(sc, SF_RXDQ_PTR_Q1, 1674175526Syongari (csr_read_4(sc, SF_RXDQ_PTR_Q1) & ~SF_RXDQ_PRODIDX) | 1675175526Syongari (eidx & SF_RXDQ_PRODIDX)); 1676175526Syongari } 1677193096Sattilio return (rx_npkts); 167849076Swpaul} 167949076Swpaul 168049076Swpaul/* 168149076Swpaul * Read the transmit status from the completion queue and release 168249076Swpaul * mbufs. Note that the buffer descriptor index in the completion 168349076Swpaul * descriptor is an offset from the start of the transmit buffer 168449076Swpaul * descriptor list in bytes. This is important because the manual 168549076Swpaul * gives the impression that it should match the producer/consumer 168649076Swpaul * index, which is the offset in 8 byte blocks. 168749076Swpaul */ 1688102335Salfredstatic void 1689175526Syongarisf_txeof(struct sf_softc *sc) 169049076Swpaul{ 1691175526Syongari struct sf_txdesc *txd; 1692175526Syongari struct sf_tx_rcdesc *cur_cmp; 169349076Swpaul struct ifnet *ifp; 1694175526Syongari uint32_t status; 1695175526Syongari int cons, idx, prod; 169649076Swpaul 1697175526Syongari SF_LOCK_ASSERT(sc); 1698175526Syongari 1699147256Sbrooks ifp = sc->sf_ifp; 170049076Swpaul 1701175526Syongari bus_dmamap_sync(sc->sf_cdata.sf_tx_cring_tag, 1702175526Syongari sc->sf_cdata.sf_tx_cring_map, 1703175526Syongari BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); 170449076Swpaul 1705175526Syongari cons = sc->sf_cdata.sf_txc_cons; 1706175526Syongari prod = (csr_read_4(sc, SF_CQ_PRODIDX) & SF_TXDQ_PRODIDX_HIPRIO) >> 16; 1707175526Syongari if (prod == cons) 1708175526Syongari return; 170949076Swpaul 1710175526Syongari for (; cons != prod; SF_INC(cons, SF_TX_CLIST_CNT)) { 1711175526Syongari cur_cmp = &sc->sf_rdata.sf_tx_cring[cons]; 1712175526Syongari status = le32toh(cur_cmp->sf_tx_status1); 1713175526Syongari if (status == 0) 1714175526Syongari break; 1715175526Syongari switch (status & SF_TX_CMPDESC_TYPE) { 1716175526Syongari case SF_TXCMPTYPE_TX: 1717175526Syongari /* Tx complete entry. */ 1718175526Syongari break; 1719175526Syongari case SF_TXCMPTYPE_DMA: 1720175526Syongari /* DMA complete entry. */ 1721175526Syongari idx = status & SF_TX_CMPDESC_IDX; 1722175526Syongari idx = idx / sizeof(struct sf_tx_rdesc); 1723175526Syongari /* 1724175526Syongari * We don't need to check Tx status here. 1725175526Syongari * SF_ISR_TX_LOFIFO intr would handle this. 1726175526Syongari * Note, if_opackets, if_collisions and if_oerrors 1727175526Syongari * counters are handled in sf_stats_update(). 1728175526Syongari */ 1729175526Syongari txd = &sc->sf_cdata.sf_txdesc[idx]; 1730175526Syongari if (txd->tx_m != NULL) { 1731175526Syongari bus_dmamap_sync(sc->sf_cdata.sf_tx_tag, 1732175526Syongari txd->tx_dmamap, 1733175526Syongari BUS_DMASYNC_POSTWRITE); 1734175526Syongari bus_dmamap_unload(sc->sf_cdata.sf_tx_tag, 1735175526Syongari txd->tx_dmamap); 1736175526Syongari m_freem(txd->tx_m); 1737175526Syongari txd->tx_m = NULL; 1738175526Syongari } 1739175526Syongari sc->sf_cdata.sf_tx_cnt -= txd->ndesc; 1740175526Syongari KASSERT(sc->sf_cdata.sf_tx_cnt >= 0, 1741175526Syongari ("%s: Active Tx desc counter was garbled\n", 1742175526Syongari __func__)); 1743175526Syongari txd->ndesc = 0; 1744175526Syongari ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 1745175526Syongari break; 1746175526Syongari default: 1747175526Syongari /* It should not happen. */ 1748175526Syongari device_printf(sc->sf_dev, 1749175526Syongari "unknown Tx completion type : 0x%08x : %d : %d\n", 1750175526Syongari status, cons, prod); 1751175526Syongari break; 175281737Swpaul } 1753175526Syongari cur_cmp->sf_tx_status1 = 0; 175449076Swpaul } 175549076Swpaul 1756175526Syongari sc->sf_cdata.sf_txc_cons = cons; 1757175526Syongari bus_dmamap_sync(sc->sf_cdata.sf_tx_cring_tag, 1758175526Syongari sc->sf_cdata.sf_tx_cring_map, 1759175526Syongari BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 176049076Swpaul 1761175526Syongari if (sc->sf_cdata.sf_tx_cnt == 0) 1762175526Syongari sc->sf_watchdog_timer = 0; 1763175526Syongari 1764175526Syongari /* Update Tx completion consumer index. */ 176549076Swpaul csr_write_4(sc, SF_CQ_CONSIDX, 1766175526Syongari (csr_read_4(sc, SF_CQ_CONSIDX) & 0xffff) | 1767175526Syongari ((cons << 16) & 0xffff0000)); 176849076Swpaul} 176949076Swpaul 1770102335Salfredstatic void 1771175526Syongarisf_txthresh_adjust(struct sf_softc *sc) 177281737Swpaul{ 1773175526Syongari uint32_t txfctl; 177481737Swpaul 1775175526Syongari device_printf(sc->sf_dev, "Tx underrun -- "); 1776175526Syongari if (sc->sf_txthresh < SF_MAX_TX_THRESHOLD) { 1777175526Syongari txfctl = csr_read_4(sc, SF_TX_FRAMCTL); 1778175526Syongari /* Increase Tx threshold 256 bytes. */ 1779175526Syongari sc->sf_txthresh += 16; 1780175526Syongari if (sc->sf_txthresh > SF_MAX_TX_THRESHOLD) 1781175526Syongari sc->sf_txthresh = SF_MAX_TX_THRESHOLD; 178281737Swpaul txfctl &= ~SF_TXFRMCTL_TXTHRESH; 1783175526Syongari txfctl |= sc->sf_txthresh; 1784175526Syongari printf("increasing Tx threshold to %d bytes\n", 1785175526Syongari sc->sf_txthresh * SF_TX_THRESHOLD_UNIT); 178681737Swpaul csr_write_4(sc, SF_TX_FRAMCTL, txfctl); 1787175526Syongari } else 1788175526Syongari printf("\n"); 178981737Swpaul} 179081737Swpaul 1791137557Sbrueffer#ifdef DEVICE_POLLING 1792193096Sattiliostatic int 1793137557Sbrueffersf_poll(struct ifnet *ifp, enum poll_cmd cmd, int count) 1794137557Sbrueffer{ 1795175526Syongari struct sf_softc *sc; 1796175526Syongari uint32_t status; 1797193096Sattilio int rx_npkts; 1798137557Sbrueffer 1799175526Syongari sc = ifp->if_softc; 1800193096Sattilio rx_npkts = 0; 1801137557Sbrueffer SF_LOCK(sc); 1802137557Sbrueffer 1803175526Syongari if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) { 1804175526Syongari SF_UNLOCK(sc); 1805193096Sattilio return (rx_npkts); 1806175526Syongari } 1807137557Sbrueffer 1808137557Sbrueffer sc->rxcycles = count; 1809193096Sattilio rx_npkts = sf_rxeof(sc); 1810137557Sbrueffer sf_txeof(sc); 1811137620Sbrueffer if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) 1812149240Sjhb sf_start_locked(ifp); 1813137557Sbrueffer 1814137557Sbrueffer if (cmd == POLL_AND_CHECK_STATUS) { 1815175526Syongari /* Reading the ISR register clears all interrrupts. */ 1816137557Sbrueffer status = csr_read_4(sc, SF_ISR); 1817137557Sbrueffer 1818175526Syongari if ((status & SF_ISR_ABNORMALINTR) != 0) { 1819175526Syongari if ((status & SF_ISR_STATSOFLOW) != 0) 1820137557Sbrueffer sf_stats_update(sc); 1821175526Syongari else if ((status & SF_ISR_TX_LOFIFO) != 0) 1822175526Syongari sf_txthresh_adjust(sc); 1823175526Syongari else if ((status & SF_ISR_DMAERR) != 0) { 1824175526Syongari device_printf(sc->sf_dev, 1825175526Syongari "DMA error, resetting\n"); 1826212971Syongari ifp->if_drv_flags &= ~IFF_DRV_RUNNING; 1827149240Sjhb sf_init_locked(sc); 1828212971Syongari SF_UNLOCK(sc); 1829212971Syongari return (rx_npkts); 1830175526Syongari } else if ((status & SF_ISR_NO_TX_CSUM) != 0) { 1831175531Syongari sc->sf_statistics.sf_tx_gfp_stall++; 1832175526Syongari#ifdef SF_GFP_DEBUG 1833175526Syongari device_printf(sc->sf_dev, 1834175526Syongari "TxGFP is not responding!\n"); 1835175526Syongari#endif 1836175526Syongari } else if ((status & SF_ISR_RXGFP_NORESP) != 0) { 1837175531Syongari sc->sf_statistics.sf_rx_gfp_stall++; 1838175526Syongari#ifdef SF_GFP_DEBUG 1839175526Syongari device_printf(sc->sf_dev, 1840175526Syongari "RxGFP is not responding!\n"); 1841175526Syongari#endif 1842175526Syongari } 1843137557Sbrueffer } 1844137557Sbrueffer } 1845175526Syongari 1846175526Syongari SF_UNLOCK(sc); 1847193096Sattilio return (rx_npkts); 1848137557Sbrueffer} 1849137557Sbrueffer#endif /* DEVICE_POLLING */ 1850137557Sbrueffer 1851137557Sbruefferstatic void 1852175526Syongarisf_intr(void *arg) 185349076Swpaul{ 185449076Swpaul struct sf_softc *sc; 185549076Swpaul struct ifnet *ifp; 1856175526Syongari uint32_t status; 1857232040Syongari int cnt; 185849076Swpaul 1859175526Syongari sc = (struct sf_softc *)arg; 186067087Swpaul SF_LOCK(sc); 186167087Swpaul 1862175526Syongari if (sc->sf_suspended != 0) 1863175526Syongari goto done_locked; 1864175526Syongari 1865175526Syongari /* Reading the ISR register clears all interrrupts. */ 1866175526Syongari status = csr_read_4(sc, SF_ISR); 1867175526Syongari if (status == 0 || status == 0xffffffff || 1868175526Syongari (status & SF_ISR_PCIINT_ASSERTED) == 0) 1869175526Syongari goto done_locked; 1870175526Syongari 1871147256Sbrooks ifp = sc->sf_ifp; 1872137557Sbrueffer#ifdef DEVICE_POLLING 1873175526Syongari if ((ifp->if_capenable & IFCAP_POLLING) != 0) 1874175526Syongari goto done_locked; 1875150789Sglebius#endif 1876137557Sbrueffer 187749076Swpaul /* Disable interrupts. */ 187849076Swpaul csr_write_4(sc, SF_IMR, 0x00000000); 187949076Swpaul 1880232040Syongari for (cnt = 32; (status & SF_INTRS) != 0;) { 1881232040Syongari if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) 1882232040Syongari break; 1883175526Syongari if ((status & SF_ISR_RXDQ1_DMADONE) != 0) 188449076Swpaul sf_rxeof(sc); 188549076Swpaul 1886175526Syongari if ((status & (SF_ISR_TX_TXDONE | SF_ISR_TX_DMADONE | 1887175526Syongari SF_ISR_TX_QUEUEDONE)) != 0) 188849076Swpaul sf_txeof(sc); 188949076Swpaul 1890175526Syongari if ((status & SF_ISR_ABNORMALINTR) != 0) { 1891175526Syongari if ((status & SF_ISR_STATSOFLOW) != 0) 189249076Swpaul sf_stats_update(sc); 1893175526Syongari else if ((status & SF_ISR_TX_LOFIFO) != 0) 1894175526Syongari sf_txthresh_adjust(sc); 1895175526Syongari else if ((status & SF_ISR_DMAERR) != 0) { 1896175526Syongari device_printf(sc->sf_dev, 1897175526Syongari "DMA error, resetting\n"); 1898212971Syongari ifp->if_drv_flags &= ~IFF_DRV_RUNNING; 1899149240Sjhb sf_init_locked(sc); 1900212971Syongari SF_UNLOCK(sc); 1901212971Syongari return; 1902175526Syongari } else if ((status & SF_ISR_NO_TX_CSUM) != 0) { 1903175526Syongari sc->sf_statistics.sf_tx_gfp_stall++; 1904175526Syongari#ifdef SF_GFP_DEBUG 1905175526Syongari device_printf(sc->sf_dev, 1906175526Syongari "TxGFP is not responding!\n"); 1907175526Syongari#endif 1908175526Syongari } 1909175526Syongari else if ((status & SF_ISR_RXGFP_NORESP) != 0) { 1910175526Syongari sc->sf_statistics.sf_rx_gfp_stall++; 1911175526Syongari#ifdef SF_GFP_DEBUG 1912175526Syongari device_printf(sc->sf_dev, 1913175526Syongari "RxGFP is not responding!\n"); 1914175526Syongari#endif 1915175526Syongari } 191649076Swpaul } 1917232040Syongari if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) 1918232040Syongari sf_start_locked(ifp); 1919232040Syongari if (--cnt <= 0) 1920232040Syongari break; 1921175526Syongari /* Reading the ISR register clears all interrrupts. */ 1922175526Syongari status = csr_read_4(sc, SF_ISR); 192349076Swpaul } 192449076Swpaul 1925232040Syongari if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0) { 1926232040Syongari /* Re-enable interrupts. */ 1927232040Syongari csr_write_4(sc, SF_IMR, SF_INTRS); 1928232040Syongari } 192949076Swpaul 1930175526Syongaridone_locked: 193167087Swpaul SF_UNLOCK(sc); 193249076Swpaul} 193349076Swpaul 1934102335Salfredstatic void 1935175526Syongarisf_download_fw(struct sf_softc *sc) 193649076Swpaul{ 1937175526Syongari uint32_t gfpinst; 1938175526Syongari int i, ndx; 1939175526Syongari uint8_t *p; 1940175526Syongari 1941175526Syongari /* 1942175526Syongari * A FP instruction is composed of 48bits so we have to 1943175526Syongari * write it with two parts. 1944175526Syongari */ 1945175526Syongari p = txfwdata; 1946175526Syongari ndx = 0; 1947175526Syongari for (i = 0; i < sizeof(txfwdata) / SF_GFP_INST_BYTES; i++) { 1948175526Syongari gfpinst = p[2] << 24 | p[3] << 16 | p[4] << 8 | p[5]; 1949175526Syongari csr_write_4(sc, SF_TXGFP_MEM_BASE + ndx * 4, gfpinst); 1950175526Syongari gfpinst = p[0] << 8 | p[1]; 1951175526Syongari csr_write_4(sc, SF_TXGFP_MEM_BASE + (ndx + 1) * 4, gfpinst); 1952175526Syongari p += SF_GFP_INST_BYTES; 1953175526Syongari ndx += 2; 1954175526Syongari } 1955175526Syongari if (bootverbose) 1956175526Syongari device_printf(sc->sf_dev, "%d Tx instructions downloaded\n", i); 1957175526Syongari 1958175526Syongari p = rxfwdata; 1959175526Syongari ndx = 0; 1960175526Syongari for (i = 0; i < sizeof(rxfwdata) / SF_GFP_INST_BYTES; i++) { 1961175526Syongari gfpinst = p[2] << 24 | p[3] << 16 | p[4] << 8 | p[5]; 1962175526Syongari csr_write_4(sc, SF_RXGFP_MEM_BASE + (ndx * 4), gfpinst); 1963175526Syongari gfpinst = p[0] << 8 | p[1]; 1964175526Syongari csr_write_4(sc, SF_RXGFP_MEM_BASE + (ndx + 1) * 4, gfpinst); 1965175526Syongari p += SF_GFP_INST_BYTES; 1966175526Syongari ndx += 2; 1967175526Syongari } 1968175526Syongari if (bootverbose) 1969175526Syongari device_printf(sc->sf_dev, "%d Rx instructions downloaded\n", i); 1970175526Syongari} 1971175526Syongari 1972175526Syongaristatic void 1973175526Syongarisf_init(void *xsc) 1974175526Syongari{ 197549076Swpaul struct sf_softc *sc; 1976149240Sjhb 1977175526Syongari sc = (struct sf_softc *)xsc; 1978149240Sjhb SF_LOCK(sc); 1979149240Sjhb sf_init_locked(sc); 1980149240Sjhb SF_UNLOCK(sc); 1981149240Sjhb} 1982149240Sjhb 1983149240Sjhbstatic void 1984175526Syongarisf_init_locked(struct sf_softc *sc) 1985149240Sjhb{ 198649076Swpaul struct ifnet *ifp; 1987175526Syongari uint8_t eaddr[ETHER_ADDR_LEN]; 1988175526Syongari bus_addr_t addr; 198967087Swpaul int i; 199049076Swpaul 1991149240Sjhb SF_LOCK_ASSERT(sc); 1992147256Sbrooks ifp = sc->sf_ifp; 1993212971Syongari if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0) 1994212971Syongari return; 199549076Swpaul 199649076Swpaul sf_stop(sc); 1997175526Syongari /* Reset the hardware to a known state. */ 199849076Swpaul sf_reset(sc); 199949076Swpaul 200049076Swpaul /* Init all the receive filter registers */ 200149076Swpaul for (i = SF_RXFILT_PERFECT_BASE; 2002175526Syongari i < (SF_RXFILT_HASH_MAX + 1); i += sizeof(uint32_t)) 200349076Swpaul csr_write_4(sc, i, 0); 200449076Swpaul 200549076Swpaul /* Empty stats counter registers. */ 2006175526Syongari for (i = SF_STATS_BASE; i < (SF_STATS_END + 1); i += sizeof(uint32_t)) 2007175526Syongari csr_write_4(sc, i, 0); 200849076Swpaul 2009175526Syongari /* Init our MAC address. */ 2010175526Syongari bcopy(IF_LLADDR(sc->sf_ifp), eaddr, sizeof(eaddr)); 2011175526Syongari csr_write_4(sc, SF_PAR0, 2012175526Syongari eaddr[2] << 24 | eaddr[3] << 16 | eaddr[4] << 8 | eaddr[5]); 2013175526Syongari csr_write_4(sc, SF_PAR1, eaddr[0] << 8 | eaddr[1]); 2014175526Syongari sf_setperf(sc, 0, eaddr); 201549076Swpaul 201649076Swpaul if (sf_init_rx_ring(sc) == ENOBUFS) { 2017162315Sglebius device_printf(sc->sf_dev, 2018148947Sjhb "initialization failed: no memory for rx buffers\n"); 2019232021Syongari sf_stop(sc); 202049076Swpaul return; 202149076Swpaul } 202249076Swpaul 202349076Swpaul sf_init_tx_ring(sc); 202449076Swpaul 2025175526Syongari /* 2026175526Syongari * 16 perfect address filtering. 2027175526Syongari * Hash only multicast destination address, Accept matching 2028175526Syongari * frames regardless of VLAN ID. 2029175526Syongari */ 2030175526Syongari csr_write_4(sc, SF_RXFILT, SF_PERFMODE_NORMAL | SF_HASHMODE_ANYVLAN); 203149076Swpaul 203263166Swpaul /* 2033175526Syongari * Set Rx filter. 203463166Swpaul */ 2035175526Syongari sf_rxfilter(sc); 203663166Swpaul 2037175526Syongari /* Init the completion queue indexes. */ 203849076Swpaul csr_write_4(sc, SF_CQ_CONSIDX, 0); 203949076Swpaul csr_write_4(sc, SF_CQ_PRODIDX, 0); 204049076Swpaul 2041175526Syongari /* Init the RX completion queue. */ 2042175526Syongari addr = sc->sf_rdata.sf_rx_cring_paddr; 2043175526Syongari csr_write_4(sc, SF_CQ_ADDR_HI, SF_ADDR_HI(addr)); 2044175526Syongari csr_write_4(sc, SF_RXCQ_CTL_1, SF_ADDR_LO(addr) & SF_RXCQ_ADDR); 2045175526Syongari if (SF_ADDR_HI(addr) != 0) 2046175526Syongari SF_SETBIT(sc, SF_RXCQ_CTL_1, SF_RXCQ_USE_64BIT); 2047175526Syongari /* Set RX completion queue type 2. */ 2048175526Syongari SF_SETBIT(sc, SF_RXCQ_CTL_1, SF_RXCQTYPE_2); 2049175526Syongari csr_write_4(sc, SF_RXCQ_CTL_2, 0); 205049076Swpaul 2051175526Syongari /* 2052175526Syongari * Init RX DMA control. 2053175526Syongari * default RxHighPriority Threshold, 2054175526Syongari * default RxBurstSize, 128bytes. 2055175526Syongari */ 2056175526Syongari SF_SETBIT(sc, SF_RXDMA_CTL, 2057175526Syongari SF_RXDMA_REPORTBADPKTS | 2058175526Syongari (SF_RXDMA_HIGHPRIO_THRESH << 8) | 2059175526Syongari SF_RXDMA_BURST); 206049076Swpaul 206149076Swpaul /* Init the RX buffer descriptor queue. */ 2062175526Syongari addr = sc->sf_rdata.sf_rx_ring_paddr; 2063175526Syongari csr_write_4(sc, SF_RXDQ_ADDR_HI, SF_ADDR_HI(addr)); 2064175526Syongari csr_write_4(sc, SF_RXDQ_ADDR_Q1, SF_ADDR_LO(addr)); 2065175526Syongari 2066175526Syongari /* Set RX queue buffer length. */ 2067175526Syongari csr_write_4(sc, SF_RXDQ_CTL_1, 2068175526Syongari ((MCLBYTES - sizeof(uint32_t)) << 16) | 2069175526Syongari SF_RXDQCTL_64BITBADDR | SF_RXDQCTL_VARIABLE); 2070175526Syongari 2071175526Syongari if (SF_ADDR_HI(addr) != 0) 2072175526Syongari SF_SETBIT(sc, SF_RXDQ_CTL_1, SF_RXDQCTL_64BITDADDR); 207349076Swpaul csr_write_4(sc, SF_RXDQ_PTR_Q1, SF_RX_DLIST_CNT - 1); 2074175526Syongari csr_write_4(sc, SF_RXDQ_CTL_2, 0); 207549076Swpaul 207649076Swpaul /* Init the TX completion queue */ 2077175526Syongari addr = sc->sf_rdata.sf_tx_cring_paddr; 2078175526Syongari csr_write_4(sc, SF_TXCQ_CTL, SF_ADDR_LO(addr) & SF_TXCQ_ADDR); 2079175526Syongari if (SF_ADDR_HI(addr) != 0) 2080175526Syongari SF_SETBIT(sc, SF_TXCQ_CTL, SF_TXCQ_USE_64BIT); 208149076Swpaul 208249076Swpaul /* Init the TX buffer descriptor queue. */ 2083175526Syongari addr = sc->sf_rdata.sf_tx_ring_paddr; 2084175526Syongari csr_write_4(sc, SF_TXDQ_ADDR_HI, SF_ADDR_HI(addr)); 2085175526Syongari csr_write_4(sc, SF_TXDQ_ADDR_HIPRIO, 0); 2086175526Syongari csr_write_4(sc, SF_TXDQ_ADDR_LOPRIO, SF_ADDR_LO(addr)); 2087175526Syongari csr_write_4(sc, SF_TX_FRAMCTL, 2088175526Syongari SF_TXFRMCTL_CPLAFTERTX | sc->sf_txthresh); 208949076Swpaul csr_write_4(sc, SF_TXDQ_CTL, 2090175526Syongari SF_TXDMA_HIPRIO_THRESH << 24 | 2091175526Syongari SF_TXSKIPLEN_0BYTES << 16 | 2092175526Syongari SF_TXDDMA_BURST << 8 | 2093175526Syongari SF_TXBUFDESC_TYPE2 | SF_TXMINSPACE_UNLIMIT); 2094175526Syongari if (SF_ADDR_HI(addr) != 0) 2095175526Syongari SF_SETBIT(sc, SF_TXDQ_CTL, SF_TXDQCTL_64BITADDR); 209649076Swpaul 2097175526Syongari /* Set VLAN Type register. */ 2098175526Syongari csr_write_4(sc, SF_VLANTYPE, ETHERTYPE_VLAN); 2099175526Syongari 2100175526Syongari /* Set TxPause Timer. */ 2101175526Syongari csr_write_4(sc, SF_TXPAUSETIMER, 0xffff); 2102175526Syongari 210349076Swpaul /* Enable autopadding of short TX frames. */ 210449076Swpaul SF_SETBIT(sc, SF_MACCFG_1, SF_MACCFG1_AUTOPAD); 2105175526Syongari SF_SETBIT(sc, SF_MACCFG_2, SF_MACCFG2_AUTOVLANPAD); 2106175526Syongari /* Make sure to reset MAC to take changes effect. */ 2107175526Syongari SF_SETBIT(sc, SF_MACCFG_1, SF_MACCFG1_SOFTRESET); 2108175526Syongari DELAY(1000); 2109175526Syongari SF_CLRBIT(sc, SF_MACCFG_1, SF_MACCFG1_SOFTRESET); 211049076Swpaul 2111175526Syongari /* Enable PCI bus master. */ 2112175526Syongari SF_SETBIT(sc, SF_PCI_DEVCFG, SF_PCIDEVCFG_PCIMEN); 2113175526Syongari 2114175526Syongari /* Load StarFire firmware. */ 2115175526Syongari sf_download_fw(sc); 2116175526Syongari 2117175526Syongari /* Intialize interrupt moderation. */ 2118175526Syongari csr_write_4(sc, SF_TIMER_CTL, SF_TIMER_IMASK_MODE | SF_TIMER_TIMES_TEN | 2119175526Syongari (sc->sf_int_mod & SF_TIMER_IMASK_INTERVAL)); 2120175526Syongari 2121137557Sbrueffer#ifdef DEVICE_POLLING 2122137557Sbrueffer /* Disable interrupts if we are polling. */ 2123175526Syongari if ((ifp->if_capenable & IFCAP_POLLING) != 0) 2124137557Sbrueffer csr_write_4(sc, SF_IMR, 0x00000000); 2125137557Sbrueffer else 2126150789Sglebius#endif 212749076Swpaul /* Enable interrupts. */ 212849076Swpaul csr_write_4(sc, SF_IMR, SF_INTRS); 212949076Swpaul SF_SETBIT(sc, SF_PCI_DEVCFG, SF_PCIDEVCFG_INTR_ENB); 213049076Swpaul 213149076Swpaul /* Enable the RX and TX engines. */ 2132175526Syongari csr_write_4(sc, SF_GEN_ETH_CTL, 2133175526Syongari SF_ETHCTL_RX_ENB | SF_ETHCTL_RXDMA_ENB | 2134175526Syongari SF_ETHCTL_TX_ENB | SF_ETHCTL_TXDMA_ENB); 213549076Swpaul 2136175526Syongari if ((ifp->if_capenable & IFCAP_TXCSUM) != 0) 2137175526Syongari SF_SETBIT(sc, SF_GEN_ETH_CTL, SF_ETHCTL_TXGFP_ENB); 2138175526Syongari else 2139175526Syongari SF_CLRBIT(sc, SF_GEN_ETH_CTL, SF_ETHCTL_TXGFP_ENB); 2140175526Syongari if ((ifp->if_capenable & IFCAP_RXCSUM) != 0) 2141175526Syongari SF_SETBIT(sc, SF_GEN_ETH_CTL, SF_ETHCTL_RXGFP_ENB); 2142175526Syongari else 2143175526Syongari SF_CLRBIT(sc, SF_GEN_ETH_CTL, SF_ETHCTL_RXGFP_ENB); 214450675Swpaul 2145148887Srwatson ifp->if_drv_flags |= IFF_DRV_RUNNING; 2146148887Srwatson ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 214749076Swpaul 2148232025Syongari sc->sf_link = 0; 2149232025Syongari sf_ifmedia_upd_locked(ifp); 2150232025Syongari 2151175526Syongari callout_reset(&sc->sf_co, hz, sf_tick, sc); 215249076Swpaul} 215349076Swpaul 2154102335Salfredstatic int 2155175526Syongarisf_encap(struct sf_softc *sc, struct mbuf **m_head) 215649076Swpaul{ 2157175526Syongari struct sf_txdesc *txd; 2158175526Syongari struct sf_tx_rdesc *desc; 215949076Swpaul struct mbuf *m; 2160175526Syongari bus_dmamap_t map; 2161175526Syongari bus_dma_segment_t txsegs[SF_MAXTXSEGS]; 2162175526Syongari int error, i, nsegs, prod, si; 2163175526Syongari int avail, nskip; 216449076Swpaul 2165175526Syongari SF_LOCK_ASSERT(sc); 216649076Swpaul 2167175526Syongari m = *m_head; 2168175526Syongari prod = sc->sf_cdata.sf_tx_prod; 2169175526Syongari txd = &sc->sf_cdata.sf_txdesc[prod]; 2170175526Syongari map = txd->tx_dmamap; 2171175526Syongari error = bus_dmamap_load_mbuf_sg(sc->sf_cdata.sf_tx_tag, map, 2172175526Syongari *m_head, txsegs, &nsegs, BUS_DMA_NOWAIT); 2173175526Syongari if (error == EFBIG) { 2174243857Sglebius m = m_collapse(*m_head, M_NOWAIT, SF_MAXTXSEGS); 2175175526Syongari if (m == NULL) { 2176175526Syongari m_freem(*m_head); 2177175526Syongari *m_head = NULL; 2178175526Syongari return (ENOBUFS); 217949076Swpaul } 2180175526Syongari *m_head = m; 2181175526Syongari error = bus_dmamap_load_mbuf_sg(sc->sf_cdata.sf_tx_tag, 2182175526Syongari map, *m_head, txsegs, &nsegs, BUS_DMA_NOWAIT); 2183175526Syongari if (error != 0) { 2184175526Syongari m_freem(*m_head); 2185175526Syongari *m_head = NULL; 2186175526Syongari return (error); 2187175526Syongari } 2188175526Syongari } else if (error != 0) 2189175526Syongari return (error); 2190175526Syongari if (nsegs == 0) { 2191175526Syongari m_freem(*m_head); 2192175526Syongari *m_head = NULL; 2193175526Syongari return (EIO); 219449076Swpaul } 219549076Swpaul 2196175526Syongari /* Check number of available descriptors. */ 2197175526Syongari avail = (SF_TX_DLIST_CNT - 1) - sc->sf_cdata.sf_tx_cnt; 2198175526Syongari if (avail < nsegs) { 2199175526Syongari bus_dmamap_unload(sc->sf_cdata.sf_tx_tag, map); 2200175526Syongari return (ENOBUFS); 2201175526Syongari } 2202175526Syongari nskip = 0; 2203175526Syongari if (prod + nsegs >= SF_TX_DLIST_CNT) { 2204175526Syongari nskip = SF_TX_DLIST_CNT - prod - 1; 2205175526Syongari if (avail < nsegs + nskip) { 2206175526Syongari bus_dmamap_unload(sc->sf_cdata.sf_tx_tag, map); 2207175526Syongari return (ENOBUFS); 220849076Swpaul } 2209175526Syongari } 221049076Swpaul 2211175526Syongari bus_dmamap_sync(sc->sf_cdata.sf_tx_tag, map, BUS_DMASYNC_PREWRITE); 2212175526Syongari 2213175526Syongari si = prod; 2214175526Syongari for (i = 0; i < nsegs; i++) { 2215175526Syongari desc = &sc->sf_rdata.sf_tx_ring[prod]; 2216175526Syongari desc->sf_tx_ctrl = htole32(SF_TX_DESC_ID | 2217175526Syongari (txsegs[i].ds_len & SF_TX_DESC_FRAGLEN)); 2218175526Syongari desc->sf_tx_reserved = 0; 2219175526Syongari desc->sf_addr = htole64(txsegs[i].ds_addr); 2220175526Syongari if (i == 0 && prod + nsegs >= SF_TX_DLIST_CNT) { 2221175526Syongari /* Queue wraps! */ 2222175526Syongari desc->sf_tx_ctrl |= htole32(SF_TX_DESC_END); 2223175526Syongari prod = 0; 2224175526Syongari } else 2225175526Syongari SF_INC(prod, SF_TX_DLIST_CNT); 222649076Swpaul } 2227175526Syongari /* Update producer index. */ 2228175526Syongari sc->sf_cdata.sf_tx_prod = prod; 2229175526Syongari sc->sf_cdata.sf_tx_cnt += nsegs + nskip; 223049076Swpaul 2231175526Syongari desc = &sc->sf_rdata.sf_tx_ring[si]; 2232175526Syongari /* Check TDP/UDP checksum offload request. */ 2233175526Syongari if ((m->m_pkthdr.csum_flags & SF_CSUM_FEATURES) != 0) 2234175526Syongari desc->sf_tx_ctrl |= htole32(SF_TX_DESC_CALTCP); 2235175526Syongari desc->sf_tx_ctrl |= 2236175526Syongari htole32(SF_TX_DESC_CRCEN | SF_TX_DESC_INTR | (nsegs << 16)); 223749076Swpaul 2238175526Syongari txd->tx_dmamap = map; 2239175526Syongari txd->tx_m = m; 2240175526Syongari txd->ndesc = nsegs + nskip; 2241175526Syongari 2242175526Syongari return (0); 224349076Swpaul} 224449076Swpaul 2245102335Salfredstatic void 2246175526Syongarisf_start(struct ifnet *ifp) 224749076Swpaul{ 224849076Swpaul struct sf_softc *sc; 2249149240Sjhb 2250149240Sjhb sc = ifp->if_softc; 2251149240Sjhb SF_LOCK(sc); 2252149240Sjhb sf_start_locked(ifp); 2253149240Sjhb SF_UNLOCK(sc); 2254149240Sjhb} 2255149240Sjhb 2256149240Sjhbstatic void 2257175526Syongarisf_start_locked(struct ifnet *ifp) 2258149240Sjhb{ 2259149240Sjhb struct sf_softc *sc; 2260175526Syongari struct mbuf *m_head; 2261175526Syongari int enq; 226249076Swpaul 226349076Swpaul sc = ifp->if_softc; 2264149240Sjhb SF_LOCK_ASSERT(sc); 226549076Swpaul 2266175526Syongari if ((ifp->if_drv_flags & (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)) != 2267175526Syongari IFF_DRV_RUNNING || sc->sf_link == 0) 226854161Swpaul return; 226954161Swpaul 2270175526Syongari /* 2271175526Syongari * Since we don't know when descriptor wrap occurrs in advance 2272175526Syongari * limit available number of active Tx descriptor counter to be 2273175526Syongari * higher than maximum number of DMA segments allowed in driver. 2274175526Syongari */ 2275175526Syongari for (enq = 0; !IFQ_DRV_IS_EMPTY(&ifp->if_snd) && 2276175526Syongari sc->sf_cdata.sf_tx_cnt < SF_TX_DLIST_CNT - SF_MAXTXSEGS; ) { 2277137620Sbrueffer IFQ_DRV_DEQUEUE(&ifp->if_snd, m_head); 227849076Swpaul if (m_head == NULL) 227949076Swpaul break; 2280175526Syongari /* 2281175526Syongari * Pack the data into the transmit ring. If we 2282175526Syongari * don't have room, set the OACTIVE flag and wait 2283175526Syongari * for the NIC to drain the ring. 2284175526Syongari */ 2285175526Syongari if (sf_encap(sc, &m_head)) { 2286175526Syongari if (m_head == NULL) 2287175526Syongari break; 2288137620Sbrueffer IFQ_DRV_PREPEND(&ifp->if_snd, m_head); 2289148887Srwatson ifp->if_drv_flags |= IFF_DRV_OACTIVE; 229071276Swpaul break; 229171276Swpaul } 229249076Swpaul 2293175526Syongari enq++; 229449076Swpaul /* 229549076Swpaul * If there's a BPF listener, bounce a copy of this frame 229649076Swpaul * to him. 229749076Swpaul */ 2298175526Syongari ETHER_BPF_MTAP(ifp, m_head); 229949076Swpaul } 230049076Swpaul 2301175526Syongari if (enq > 0) { 2302175526Syongari bus_dmamap_sync(sc->sf_cdata.sf_tx_ring_tag, 2303175526Syongari sc->sf_cdata.sf_tx_ring_map, 2304175526Syongari BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 2305175526Syongari /* Kick transmit. */ 2306175526Syongari csr_write_4(sc, SF_TXDQ_PRODIDX, 2307175526Syongari sc->sf_cdata.sf_tx_prod * (sizeof(struct sf_tx_rdesc) / 8)); 230849076Swpaul 2309175526Syongari /* Set a timeout in case the chip goes out to lunch. */ 2310175526Syongari sc->sf_watchdog_timer = 5; 2311175526Syongari } 231249076Swpaul} 231349076Swpaul 2314102335Salfredstatic void 2315175526Syongarisf_stop(struct sf_softc *sc) 231649076Swpaul{ 2317175526Syongari struct sf_txdesc *txd; 2318175526Syongari struct sf_rxdesc *rxd; 2319175526Syongari struct ifnet *ifp; 232049076Swpaul int i; 232149076Swpaul 2322149240Sjhb SF_LOCK_ASSERT(sc); 232367087Swpaul 2324147256Sbrooks ifp = sc->sf_ifp; 232549077Swpaul 2326175526Syongari ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE); 2327175526Syongari sc->sf_link = 0; 2328175526Syongari callout_stop(&sc->sf_co); 2329175526Syongari sc->sf_watchdog_timer = 0; 233049076Swpaul 2331175526Syongari /* Reading the ISR register clears all interrrupts. */ 2332175526Syongari csr_read_4(sc, SF_ISR); 2333175526Syongari /* Disable further interrupts. */ 2334175526Syongari csr_write_4(sc, SF_IMR, 0); 2335175526Syongari 2336175526Syongari /* Disable Tx/Rx egine. */ 233749076Swpaul csr_write_4(sc, SF_GEN_ETH_CTL, 0); 2338175526Syongari 2339232019Syongari /* Give hardware chance to drain active DMA cycles. */ 2340232019Syongari DELAY(1000); 2341232019Syongari 234249076Swpaul csr_write_4(sc, SF_CQ_CONSIDX, 0); 234349076Swpaul csr_write_4(sc, SF_CQ_PRODIDX, 0); 234449076Swpaul csr_write_4(sc, SF_RXDQ_ADDR_Q1, 0); 234549076Swpaul csr_write_4(sc, SF_RXDQ_CTL_1, 0); 234649076Swpaul csr_write_4(sc, SF_RXDQ_PTR_Q1, 0); 234749076Swpaul csr_write_4(sc, SF_TXCQ_CTL, 0); 234849076Swpaul csr_write_4(sc, SF_TXDQ_ADDR_HIPRIO, 0); 234949076Swpaul csr_write_4(sc, SF_TXDQ_CTL, 0); 235049076Swpaul 2351175526Syongari /* 2352175526Syongari * Free RX and TX mbufs still in the queues. 2353175526Syongari */ 235449076Swpaul for (i = 0; i < SF_RX_DLIST_CNT; i++) { 2355175526Syongari rxd = &sc->sf_cdata.sf_rxdesc[i]; 2356175526Syongari if (rxd->rx_m != NULL) { 2357175526Syongari bus_dmamap_sync(sc->sf_cdata.sf_rx_tag, 2358175526Syongari rxd->rx_dmamap, BUS_DMASYNC_POSTREAD); 2359175526Syongari bus_dmamap_unload(sc->sf_cdata.sf_rx_tag, 2360175526Syongari rxd->rx_dmamap); 2361175526Syongari m_freem(rxd->rx_m); 2362175526Syongari rxd->rx_m = NULL; 236349076Swpaul } 2364175526Syongari } 236549076Swpaul for (i = 0; i < SF_TX_DLIST_CNT; i++) { 2366175526Syongari txd = &sc->sf_cdata.sf_txdesc[i]; 2367175526Syongari if (txd->tx_m != NULL) { 2368175526Syongari bus_dmamap_sync(sc->sf_cdata.sf_tx_tag, 2369175526Syongari txd->tx_dmamap, BUS_DMASYNC_POSTWRITE); 2370175526Syongari bus_dmamap_unload(sc->sf_cdata.sf_tx_tag, 2371175526Syongari txd->tx_dmamap); 2372175526Syongari m_freem(txd->tx_m); 2373175526Syongari txd->tx_m = NULL; 2374175526Syongari txd->ndesc = 0; 237549076Swpaul } 2376175526Syongari } 2377175526Syongari} 237849076Swpaul 2379175526Syongaristatic void 2380175526Syongarisf_tick(void *xsc) 2381175526Syongari{ 2382175526Syongari struct sf_softc *sc; 2383175526Syongari struct mii_data *mii; 2384175526Syongari 2385175526Syongari sc = xsc; 2386175526Syongari SF_LOCK_ASSERT(sc); 2387175526Syongari mii = device_get_softc(sc->sf_miibus); 2388175526Syongari mii_tick(mii); 2389175526Syongari sf_stats_update(sc); 2390175526Syongari sf_watchdog(sc); 2391175526Syongari callout_reset(&sc->sf_co, hz, sf_tick, sc); 239249076Swpaul} 239349076Swpaul 239449076Swpaul/* 239549076Swpaul * Note: it is important that this function not be interrupted. We 239649076Swpaul * use a two-stage register access scheme: if we are interrupted in 239749076Swpaul * between setting the indirect address register and reading from the 239849076Swpaul * indirect data register, the contents of the address register could 239949076Swpaul * be changed out from under us. 2400131657Sbms */ 2401102335Salfredstatic void 2402175526Syongarisf_stats_update(struct sf_softc *sc) 240349076Swpaul{ 240449076Swpaul struct ifnet *ifp; 2405175526Syongari struct sf_stats now, *stats, *nstats; 240667087Swpaul int i; 240749076Swpaul 2408149240Sjhb SF_LOCK_ASSERT(sc); 2409175526Syongari 2410147256Sbrooks ifp = sc->sf_ifp; 2411175526Syongari stats = &now; 241249076Swpaul 2413175526Syongari stats->sf_tx_frames = 2414175526Syongari csr_read_4(sc, SF_STATS_BASE + SF_STATS_TX_FRAMES); 2415175526Syongari stats->sf_tx_single_colls = 2416175526Syongari csr_read_4(sc, SF_STATS_BASE + SF_STATS_TX_SINGLE_COL); 2417175526Syongari stats->sf_tx_multi_colls = 2418175526Syongari csr_read_4(sc, SF_STATS_BASE + SF_STATS_TX_MULTI_COL); 2419175526Syongari stats->sf_tx_crcerrs = 2420175526Syongari csr_read_4(sc, SF_STATS_BASE + SF_STATS_TX_CRC_ERRS); 2421175526Syongari stats->sf_tx_bytes = 2422175526Syongari csr_read_4(sc, SF_STATS_BASE + SF_STATS_TX_BYTES); 2423175526Syongari stats->sf_tx_deferred = 2424175526Syongari csr_read_4(sc, SF_STATS_BASE + SF_STATS_TX_DEFERRED); 2425175526Syongari stats->sf_tx_late_colls = 2426175526Syongari csr_read_4(sc, SF_STATS_BASE + SF_STATS_TX_LATE_COL); 2427175526Syongari stats->sf_tx_pause_frames = 2428175526Syongari csr_read_4(sc, SF_STATS_BASE + SF_STATS_TX_PAUSE); 2429175526Syongari stats->sf_tx_control_frames = 2430175526Syongari csr_read_4(sc, SF_STATS_BASE + SF_STATS_TX_CTL_FRAME); 2431175526Syongari stats->sf_tx_excess_colls = 2432175526Syongari csr_read_4(sc, SF_STATS_BASE + SF_STATS_TX_EXCESS_COL); 2433175526Syongari stats->sf_tx_excess_defer = 2434175526Syongari csr_read_4(sc, SF_STATS_BASE + SF_STATS_TX_EXCESS_DEF); 2435175526Syongari stats->sf_tx_mcast_frames = 2436175526Syongari csr_read_4(sc, SF_STATS_BASE + SF_STATS_TX_MULTI); 2437175526Syongari stats->sf_tx_bcast_frames = 2438175526Syongari csr_read_4(sc, SF_STATS_BASE + SF_STATS_TX_BCAST); 2439175526Syongari stats->sf_tx_frames_lost = 2440175526Syongari csr_read_4(sc, SF_STATS_BASE + SF_STATS_TX_FRAME_LOST); 2441175526Syongari stats->sf_rx_frames = 2442175526Syongari csr_read_4(sc, SF_STATS_BASE + SF_STATS_RX_FRAMES); 2443175526Syongari stats->sf_rx_crcerrs = 2444175526Syongari csr_read_4(sc, SF_STATS_BASE + SF_STATS_RX_CRC_ERRS); 2445175526Syongari stats->sf_rx_alignerrs = 2446175526Syongari csr_read_4(sc, SF_STATS_BASE + SF_STATS_RX_ALIGN_ERRS); 2447175526Syongari stats->sf_rx_bytes = 2448175526Syongari csr_read_4(sc, SF_STATS_BASE + SF_STATS_RX_BYTES); 2449175526Syongari stats->sf_rx_pause_frames = 2450175526Syongari csr_read_4(sc, SF_STATS_BASE + SF_STATS_RX_PAUSE); 2451175526Syongari stats->sf_rx_control_frames = 2452175526Syongari csr_read_4(sc, SF_STATS_BASE + SF_STATS_RX_CTL_FRAME); 2453175526Syongari stats->sf_rx_unsup_control_frames = 2454175526Syongari csr_read_4(sc, SF_STATS_BASE + SF_STATS_RX_UNSUP_FRAME); 2455175526Syongari stats->sf_rx_giants = 2456175526Syongari csr_read_4(sc, SF_STATS_BASE + SF_STATS_RX_GIANTS); 2457175526Syongari stats->sf_rx_runts = 2458175526Syongari csr_read_4(sc, SF_STATS_BASE + SF_STATS_RX_RUNTS); 2459175526Syongari stats->sf_rx_jabbererrs = 2460175526Syongari csr_read_4(sc, SF_STATS_BASE + SF_STATS_RX_JABBER); 2461175526Syongari stats->sf_rx_fragments = 2462175526Syongari csr_read_4(sc, SF_STATS_BASE + SF_STATS_RX_FRAGMENTS); 2463175526Syongari stats->sf_rx_pkts_64 = 2464175526Syongari csr_read_4(sc, SF_STATS_BASE + SF_STATS_RX_64); 2465175526Syongari stats->sf_rx_pkts_65_127 = 2466175526Syongari csr_read_4(sc, SF_STATS_BASE + SF_STATS_RX_65_127); 2467175526Syongari stats->sf_rx_pkts_128_255 = 2468175526Syongari csr_read_4(sc, SF_STATS_BASE + SF_STATS_RX_128_255); 2469175526Syongari stats->sf_rx_pkts_256_511 = 2470175526Syongari csr_read_4(sc, SF_STATS_BASE + SF_STATS_RX_256_511); 2471175526Syongari stats->sf_rx_pkts_512_1023 = 2472175526Syongari csr_read_4(sc, SF_STATS_BASE + SF_STATS_RX_512_1023); 2473175526Syongari stats->sf_rx_pkts_1024_1518 = 2474175526Syongari csr_read_4(sc, SF_STATS_BASE + SF_STATS_RX_1024_1518); 2475175526Syongari stats->sf_rx_frames_lost = 2476175526Syongari csr_read_4(sc, SF_STATS_BASE + SF_STATS_RX_FRAME_LOST); 2477175526Syongari /* Lower 16bits are valid. */ 2478175526Syongari stats->sf_tx_underruns = 2479175526Syongari (csr_read_4(sc, SF_STATS_BASE + SF_STATS_TX_UNDERRUN) & 0xffff); 248049076Swpaul 2481175526Syongari /* Empty stats counter registers. */ 2482175526Syongari for (i = SF_STATS_BASE; i < (SF_STATS_END + 1); i += sizeof(uint32_t)) 2483175526Syongari csr_write_4(sc, i, 0); 248449076Swpaul 2485175526Syongari ifp->if_opackets += (u_long)stats->sf_tx_frames; 248649076Swpaul 2487175526Syongari ifp->if_collisions += (u_long)stats->sf_tx_single_colls + 2488175526Syongari (u_long)stats->sf_tx_multi_colls; 248984147Sjlemon 2490175526Syongari ifp->if_oerrors += (u_long)stats->sf_tx_excess_colls + 2491175526Syongari (u_long)stats->sf_tx_excess_defer + 2492175526Syongari (u_long)stats->sf_tx_frames_lost; 249350675Swpaul 2494175526Syongari ifp->if_ipackets += (u_long)stats->sf_rx_frames; 2495175526Syongari 2496175526Syongari ifp->if_ierrors += (u_long)stats->sf_rx_crcerrs + 2497175526Syongari (u_long)stats->sf_rx_alignerrs + 2498175526Syongari (u_long)stats->sf_rx_giants + 2499175526Syongari (u_long)stats->sf_rx_runts + 2500175526Syongari (u_long)stats->sf_rx_jabbererrs + 2501175526Syongari (u_long)stats->sf_rx_frames_lost; 2502175526Syongari 2503175526Syongari nstats = &sc->sf_statistics; 2504175526Syongari 2505175526Syongari nstats->sf_tx_frames += stats->sf_tx_frames; 2506175526Syongari nstats->sf_tx_single_colls += stats->sf_tx_single_colls; 2507175526Syongari nstats->sf_tx_multi_colls += stats->sf_tx_multi_colls; 2508175526Syongari nstats->sf_tx_crcerrs += stats->sf_tx_crcerrs; 2509175526Syongari nstats->sf_tx_bytes += stats->sf_tx_bytes; 2510175526Syongari nstats->sf_tx_deferred += stats->sf_tx_deferred; 2511175526Syongari nstats->sf_tx_late_colls += stats->sf_tx_late_colls; 2512175526Syongari nstats->sf_tx_pause_frames += stats->sf_tx_pause_frames; 2513175526Syongari nstats->sf_tx_control_frames += stats->sf_tx_control_frames; 2514175526Syongari nstats->sf_tx_excess_colls += stats->sf_tx_excess_colls; 2515175526Syongari nstats->sf_tx_excess_defer += stats->sf_tx_excess_defer; 2516175526Syongari nstats->sf_tx_mcast_frames += stats->sf_tx_mcast_frames; 2517175526Syongari nstats->sf_tx_bcast_frames += stats->sf_tx_bcast_frames; 2518175526Syongari nstats->sf_tx_frames_lost += stats->sf_tx_frames_lost; 2519175526Syongari nstats->sf_rx_frames += stats->sf_rx_frames; 2520175526Syongari nstats->sf_rx_crcerrs += stats->sf_rx_crcerrs; 2521175526Syongari nstats->sf_rx_alignerrs += stats->sf_rx_alignerrs; 2522175526Syongari nstats->sf_rx_bytes += stats->sf_rx_bytes; 2523175526Syongari nstats->sf_rx_pause_frames += stats->sf_rx_pause_frames; 2524175526Syongari nstats->sf_rx_control_frames += stats->sf_rx_control_frames; 2525175526Syongari nstats->sf_rx_unsup_control_frames += stats->sf_rx_unsup_control_frames; 2526175526Syongari nstats->sf_rx_giants += stats->sf_rx_giants; 2527175526Syongari nstats->sf_rx_runts += stats->sf_rx_runts; 2528175526Syongari nstats->sf_rx_jabbererrs += stats->sf_rx_jabbererrs; 2529175526Syongari nstats->sf_rx_fragments += stats->sf_rx_fragments; 2530175526Syongari nstats->sf_rx_pkts_64 += stats->sf_rx_pkts_64; 2531175526Syongari nstats->sf_rx_pkts_65_127 += stats->sf_rx_pkts_65_127; 2532175526Syongari nstats->sf_rx_pkts_128_255 += stats->sf_rx_pkts_128_255; 2533175526Syongari nstats->sf_rx_pkts_256_511 += stats->sf_rx_pkts_256_511; 2534175526Syongari nstats->sf_rx_pkts_512_1023 += stats->sf_rx_pkts_512_1023; 2535175526Syongari nstats->sf_rx_pkts_1024_1518 += stats->sf_rx_pkts_1024_1518; 2536175526Syongari nstats->sf_rx_frames_lost += stats->sf_rx_frames_lost; 2537175526Syongari nstats->sf_tx_underruns += stats->sf_tx_underruns; 253849076Swpaul} 253949076Swpaul 2540102335Salfredstatic void 2541175526Syongarisf_watchdog(struct sf_softc *sc) 2542175526Syongari{ 254349076Swpaul struct ifnet *ifp; 254449076Swpaul 2545175526Syongari SF_LOCK_ASSERT(sc); 254649076Swpaul 2547175526Syongari if (sc->sf_watchdog_timer == 0 || --sc->sf_watchdog_timer) 2548175526Syongari return; 254967087Swpaul 2550175526Syongari ifp = sc->sf_ifp; 2551175526Syongari 255249076Swpaul ifp->if_oerrors++; 2553175526Syongari if (sc->sf_link == 0) { 2554175526Syongari if (bootverbose) 2555175526Syongari if_printf(sc->sf_ifp, "watchdog timeout " 2556175526Syongari "(missed link)\n"); 2557175526Syongari } else 2558175526Syongari if_printf(ifp, "watchdog timeout, %d Tx descs are active\n", 2559175526Syongari sc->sf_cdata.sf_tx_cnt); 256049076Swpaul 2561212971Syongari ifp->if_drv_flags &= ~IFF_DRV_RUNNING; 2562149240Sjhb sf_init_locked(sc); 256349076Swpaul 2564137620Sbrueffer if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) 2565149240Sjhb sf_start_locked(ifp); 2566175526Syongari} 256749076Swpaul 2568175526Syongaristatic int 2569175526Syongarisf_shutdown(device_t dev) 2570175526Syongari{ 2571175526Syongari struct sf_softc *sc; 2572175526Syongari 2573175526Syongari sc = device_get_softc(dev); 2574175526Syongari 2575175526Syongari SF_LOCK(sc); 2576175526Syongari sf_stop(sc); 257767087Swpaul SF_UNLOCK(sc); 2578175526Syongari 2579175526Syongari return (0); 258049076Swpaul} 258149076Swpaul 2582173839Syongaristatic int 2583175526Syongarisf_suspend(device_t dev) 258449076Swpaul{ 258549076Swpaul struct sf_softc *sc; 258649076Swpaul 258749076Swpaul sc = device_get_softc(dev); 258849076Swpaul 2589149240Sjhb SF_LOCK(sc); 259049076Swpaul sf_stop(sc); 2591175526Syongari sc->sf_suspended = 1; 2592175526Syongari bus_generic_suspend(dev); 2593149240Sjhb SF_UNLOCK(sc); 2594173839Syongari 2595173839Syongari return (0); 259649076Swpaul} 2597175526Syongari 2598175526Syongaristatic int 2599175526Syongarisf_resume(device_t dev) 2600175526Syongari{ 2601175526Syongari struct sf_softc *sc; 2602175526Syongari struct ifnet *ifp; 2603175526Syongari 2604175526Syongari sc = device_get_softc(dev); 2605175526Syongari 2606175526Syongari SF_LOCK(sc); 2607175526Syongari bus_generic_resume(dev); 2608175526Syongari ifp = sc->sf_ifp; 2609175526Syongari if ((ifp->if_flags & IFF_UP) != 0) 2610175526Syongari sf_init_locked(sc); 2611175526Syongari 2612175526Syongari sc->sf_suspended = 0; 2613175526Syongari SF_UNLOCK(sc); 2614175526Syongari 2615175526Syongari return (0); 2616175526Syongari} 2617175526Syongari 2618175526Syongaristatic int 2619175526Syongarisf_sysctl_stats(SYSCTL_HANDLER_ARGS) 2620175526Syongari{ 2621175526Syongari struct sf_softc *sc; 2622175526Syongari struct sf_stats *stats; 2623175526Syongari int error; 2624175526Syongari int result; 2625175526Syongari 2626175526Syongari result = -1; 2627175526Syongari error = sysctl_handle_int(oidp, &result, 0, req); 2628175526Syongari 2629175526Syongari if (error != 0 || req->newptr == NULL) 2630175526Syongari return (error); 2631175526Syongari 2632175526Syongari if (result != 1) 2633175526Syongari return (error); 2634175526Syongari 2635175526Syongari sc = (struct sf_softc *)arg1; 2636175526Syongari stats = &sc->sf_statistics; 2637175526Syongari 2638175526Syongari printf("%s statistics:\n", device_get_nameunit(sc->sf_dev)); 2639175526Syongari printf("Transmit good frames : %ju\n", 2640175526Syongari (uintmax_t)stats->sf_tx_frames); 2641175526Syongari printf("Transmit good octets : %ju\n", 2642175526Syongari (uintmax_t)stats->sf_tx_bytes); 2643175526Syongari printf("Transmit single collisions : %u\n", 2644175526Syongari stats->sf_tx_single_colls); 2645175526Syongari printf("Transmit multiple collisions : %u\n", 2646175526Syongari stats->sf_tx_multi_colls); 2647175526Syongari printf("Transmit late collisions : %u\n", 2648175526Syongari stats->sf_tx_late_colls); 2649175526Syongari printf("Transmit abort due to excessive collisions : %u\n", 2650175526Syongari stats->sf_tx_excess_colls); 2651175526Syongari printf("Transmit CRC errors : %u\n", 2652175526Syongari stats->sf_tx_crcerrs); 2653175526Syongari printf("Transmit deferrals : %u\n", 2654175526Syongari stats->sf_tx_deferred); 2655175526Syongari printf("Transmit abort due to excessive deferrals : %u\n", 2656175526Syongari stats->sf_tx_excess_defer); 2657175526Syongari printf("Transmit pause control frames : %u\n", 2658175526Syongari stats->sf_tx_pause_frames); 2659175526Syongari printf("Transmit control frames : %u\n", 2660175526Syongari stats->sf_tx_control_frames); 2661175526Syongari printf("Transmit good multicast frames : %u\n", 2662175526Syongari stats->sf_tx_mcast_frames); 2663175526Syongari printf("Transmit good broadcast frames : %u\n", 2664175526Syongari stats->sf_tx_bcast_frames); 2665175526Syongari printf("Transmit frames lost due to internal transmit errors : %u\n", 2666175526Syongari stats->sf_tx_frames_lost); 2667175526Syongari printf("Transmit FIFO underflows : %u\n", 2668175526Syongari stats->sf_tx_underruns); 2669175526Syongari printf("Transmit GFP stalls : %u\n", stats->sf_tx_gfp_stall); 2670175526Syongari printf("Receive good frames : %ju\n", 2671175526Syongari (uint64_t)stats->sf_rx_frames); 2672175526Syongari printf("Receive good octets : %ju\n", 2673175526Syongari (uint64_t)stats->sf_rx_bytes); 2674175526Syongari printf("Receive CRC errors : %u\n", 2675175526Syongari stats->sf_rx_crcerrs); 2676175526Syongari printf("Receive alignment errors : %u\n", 2677175526Syongari stats->sf_rx_alignerrs); 2678175526Syongari printf("Receive pause frames : %u\n", 2679175526Syongari stats->sf_rx_pause_frames); 2680175526Syongari printf("Receive control frames : %u\n", 2681175526Syongari stats->sf_rx_control_frames); 2682175526Syongari printf("Receive control frames with unsupported opcode : %u\n", 2683175526Syongari stats->sf_rx_unsup_control_frames); 2684175526Syongari printf("Receive frames too long : %u\n", 2685175526Syongari stats->sf_rx_giants); 2686175526Syongari printf("Receive frames too short : %u\n", 2687175526Syongari stats->sf_rx_runts); 2688175526Syongari printf("Receive frames jabber errors : %u\n", 2689175526Syongari stats->sf_rx_jabbererrs); 2690175526Syongari printf("Receive frames fragments : %u\n", 2691175526Syongari stats->sf_rx_fragments); 2692175526Syongari printf("Receive packets 64 bytes : %ju\n", 2693175526Syongari (uint64_t)stats->sf_rx_pkts_64); 2694175526Syongari printf("Receive packets 65 to 127 bytes : %ju\n", 2695175526Syongari (uint64_t)stats->sf_rx_pkts_65_127); 2696175526Syongari printf("Receive packets 128 to 255 bytes : %ju\n", 2697175526Syongari (uint64_t)stats->sf_rx_pkts_128_255); 2698175526Syongari printf("Receive packets 256 to 511 bytes : %ju\n", 2699175526Syongari (uint64_t)stats->sf_rx_pkts_256_511); 2700175526Syongari printf("Receive packets 512 to 1023 bytes : %ju\n", 2701175526Syongari (uint64_t)stats->sf_rx_pkts_512_1023); 2702175526Syongari printf("Receive packets 1024 to 1518 bytes : %ju\n", 2703175526Syongari (uint64_t)stats->sf_rx_pkts_1024_1518); 2704175526Syongari printf("Receive frames lost due to internal receive errors : %u\n", 2705175526Syongari stats->sf_rx_frames_lost); 2706175526Syongari printf("Receive GFP stalls : %u\n", stats->sf_rx_gfp_stall); 2707175526Syongari 2708175526Syongari return (error); 2709175526Syongari} 2710175526Syongari 2711175526Syongaristatic int 2712175526Syongarisysctl_int_range(SYSCTL_HANDLER_ARGS, int low, int high) 2713175526Syongari{ 2714175526Syongari int error, value; 2715175526Syongari 2716175526Syongari if (!arg1) 2717175526Syongari return (EINVAL); 2718175526Syongari value = *(int *)arg1; 2719175526Syongari error = sysctl_handle_int(oidp, &value, 0, req); 2720175526Syongari if (error || !req->newptr) 2721175526Syongari return (error); 2722175526Syongari if (value < low || value > high) 2723175526Syongari return (EINVAL); 2724175526Syongari *(int *)arg1 = value; 2725175526Syongari 2726175526Syongari return (0); 2727175526Syongari} 2728175526Syongari 2729175526Syongaristatic int 2730175526Syongarisysctl_hw_sf_int_mod(SYSCTL_HANDLER_ARGS) 2731175526Syongari{ 2732175526Syongari 2733175526Syongari return (sysctl_int_range(oidp, arg1, arg2, req, SF_IM_MIN, SF_IM_MAX)); 2734175526Syongari} 2735