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: stable/11/sys/dev/sf/if_sf.c 347962 2019-05-18 20:43:13Z brooks $"); 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> 102257176Sglebius#include <net/if_var.h> 10349076Swpaul#include <net/if_arp.h> 10449076Swpaul#include <net/ethernet.h> 10549076Swpaul#include <net/if_dl.h> 10649076Swpaul#include <net/if_media.h> 107147256Sbrooks#include <net/if_types.h> 108175526Syongari#include <net/if_vlan_var.h> 10949076Swpaul 11050675Swpaul#include <dev/mii/mii.h> 11150675Swpaul#include <dev/mii/miivar.h> 11250675Swpaul 113119288Simp#include <dev/pci/pcireg.h> 114119288Simp#include <dev/pci/pcivar.h> 11549076Swpaul 116175526Syongari#include <machine/bus.h> 11749076Swpaul 118175520Syongari#include <dev/sf/if_sfreg.h> 119175526Syongari#include <dev/sf/starfire_rx.h> 120175526Syongari#include <dev/sf/starfire_tx.h> 12149076Swpaul 122175526Syongari/* "device miibus" required. See GENERIC if you get errors here. */ 123175526Syongari#include "miibus_if.h" 124175526Syongari 125113506SmdoddMODULE_DEPEND(sf, pci, 1, 1, 1); 126113506SmdoddMODULE_DEPEND(sf, ether, 1, 1, 1); 12759758SpeterMODULE_DEPEND(sf, miibus, 1, 1, 1); 12859758Speter 129175526Syongari#undef SF_GFP_DEBUG 130175526Syongari#define SF_CSUM_FEATURES (CSUM_TCP | CSUM_UDP) 131175526Syongari/* Define this to activate partial TCP/UDP checksum offload. */ 132175526Syongari#undef SF_PARTIAL_CSUM_SUPPORT 133175526Syongari 13449076Swpaulstatic struct sf_type sf_devs[] = { 135175526Syongari { AD_VENDORID, AD_DEVICEID_STARFIRE, "Adaptec AIC-6915 10/100BaseTX", 136175526Syongari AD_SUBSYSID_62011_REV0, "Adaptec ANA-62011 (rev 0) 10/100BaseTX" }, 137175526Syongari { AD_VENDORID, AD_DEVICEID_STARFIRE, "Adaptec AIC-6915 10/100BaseTX", 138175526Syongari AD_SUBSYSID_62011_REV1, "Adaptec ANA-62011 (rev 1) 10/100BaseTX" }, 139175526Syongari { AD_VENDORID, AD_DEVICEID_STARFIRE, "Adaptec AIC-6915 10/100BaseTX", 140175526Syongari AD_SUBSYSID_62022, "Adaptec ANA-62022 10/100BaseTX" }, 141175526Syongari { AD_VENDORID, AD_DEVICEID_STARFIRE, "Adaptec AIC-6915 10/100BaseTX", 142175526Syongari AD_SUBSYSID_62044_REV0, "Adaptec ANA-62044 (rev 0) 10/100BaseTX" }, 143175526Syongari { AD_VENDORID, AD_DEVICEID_STARFIRE, "Adaptec AIC-6915 10/100BaseTX", 144175526Syongari AD_SUBSYSID_62044_REV1, "Adaptec ANA-62044 (rev 1) 10/100BaseTX" }, 145175526Syongari { AD_VENDORID, AD_DEVICEID_STARFIRE, "Adaptec AIC-6915 10/100BaseTX", 146175526Syongari AD_SUBSYSID_62020, "Adaptec ANA-62020 10/100BaseFX" }, 147175526Syongari { AD_VENDORID, AD_DEVICEID_STARFIRE, "Adaptec AIC-6915 10/100BaseTX", 148175526Syongari AD_SUBSYSID_69011, "Adaptec ANA-69011 10/100BaseTX" }, 14949076Swpaul}; 15049076Swpaul 151142407Simpstatic int sf_probe(device_t); 152142407Simpstatic int sf_attach(device_t); 153142407Simpstatic int sf_detach(device_t); 154175526Syongaristatic int sf_shutdown(device_t); 155175526Syongaristatic int sf_suspend(device_t); 156175526Syongaristatic int sf_resume(device_t); 157142407Simpstatic void sf_intr(void *); 158175526Syongaristatic void sf_tick(void *); 159175526Syongaristatic void sf_stats_update(struct sf_softc *); 160175526Syongari#ifndef __NO_STRICT_ALIGNMENT 161175526Syongaristatic __inline void sf_fixup_rx(struct mbuf *); 162175526Syongari#endif 163193096Sattiliostatic int sf_rxeof(struct sf_softc *); 164142407Simpstatic void sf_txeof(struct sf_softc *); 165175526Syongaristatic int sf_encap(struct sf_softc *, struct mbuf **); 166142407Simpstatic void sf_start(struct ifnet *); 167149240Sjhbstatic void sf_start_locked(struct ifnet *); 168142407Simpstatic int sf_ioctl(struct ifnet *, u_long, caddr_t); 169175526Syongaristatic void sf_download_fw(struct sf_softc *); 170142407Simpstatic void sf_init(void *); 171149240Sjhbstatic void sf_init_locked(struct sf_softc *); 172142407Simpstatic void sf_stop(struct sf_softc *); 173175526Syongaristatic void sf_watchdog(struct sf_softc *); 174142407Simpstatic int sf_ifmedia_upd(struct ifnet *); 175232025Syongaristatic int sf_ifmedia_upd_locked(struct ifnet *); 176142407Simpstatic void sf_ifmedia_sts(struct ifnet *, struct ifmediareq *); 177142407Simpstatic void sf_reset(struct sf_softc *); 178175526Syongaristatic int sf_dma_alloc(struct sf_softc *); 179175526Syongaristatic void sf_dma_free(struct sf_softc *); 180142407Simpstatic int sf_init_rx_ring(struct sf_softc *); 181142407Simpstatic void sf_init_tx_ring(struct sf_softc *); 182175526Syongaristatic int sf_newbuf(struct sf_softc *, int); 183175526Syongaristatic void sf_rxfilter(struct sf_softc *); 184175526Syongaristatic int sf_setperf(struct sf_softc *, int, uint8_t *); 185142407Simpstatic int sf_sethash(struct sf_softc *, caddr_t, int); 18649076Swpaul#ifdef notdef 187175526Syongaristatic int sf_setvlan(struct sf_softc *, int, uint32_t); 18849076Swpaul#endif 18949076Swpaul 190175526Syongaristatic uint8_t sf_read_eeprom(struct sf_softc *, int); 19149076Swpaul 192142407Simpstatic int sf_miibus_readreg(device_t, int, int); 193142407Simpstatic int sf_miibus_writereg(device_t, int, int, int); 194142407Simpstatic void sf_miibus_statchg(device_t); 195137557Sbrueffer#ifdef DEVICE_POLLING 196193096Sattiliostatic int sf_poll(struct ifnet *ifp, enum poll_cmd cmd, int count); 197150789Sglebius#endif 19849076Swpaul 199175526Syongaristatic uint32_t csr_read_4(struct sf_softc *, int); 200175526Syongaristatic void csr_write_4(struct sf_softc *, int, uint32_t); 201142407Simpstatic void sf_txthresh_adjust(struct sf_softc *); 202175526Syongaristatic int sf_sysctl_stats(SYSCTL_HANDLER_ARGS); 203175526Syongaristatic int sysctl_int_range(SYSCTL_HANDLER_ARGS, int, int); 204175526Syongaristatic int sysctl_hw_sf_int_mod(SYSCTL_HANDLER_ARGS); 20549076Swpaul 20649076Swpaulstatic device_method_t sf_methods[] = { 20749076Swpaul /* Device interface */ 20849076Swpaul DEVMETHOD(device_probe, sf_probe), 20949076Swpaul DEVMETHOD(device_attach, sf_attach), 21049076Swpaul DEVMETHOD(device_detach, sf_detach), 21149076Swpaul DEVMETHOD(device_shutdown, sf_shutdown), 212175526Syongari DEVMETHOD(device_suspend, sf_suspend), 213175526Syongari DEVMETHOD(device_resume, sf_resume), 21450675Swpaul 21550675Swpaul /* MII interface */ 21650675Swpaul DEVMETHOD(miibus_readreg, sf_miibus_readreg), 21750675Swpaul DEVMETHOD(miibus_writereg, sf_miibus_writereg), 21850675Swpaul DEVMETHOD(miibus_statchg, sf_miibus_statchg), 21950675Swpaul 220227843Smarius DEVMETHOD_END 22149076Swpaul}; 22249076Swpaul 22349076Swpaulstatic driver_t sf_driver = { 22451455Swpaul "sf", 22549076Swpaul sf_methods, 22649076Swpaul sizeof(struct sf_softc), 22749076Swpaul}; 22849076Swpaul 22949076Swpaulstatic devclass_t sf_devclass; 23049076Swpaul 231113506SmdoddDRIVER_MODULE(sf, pci, sf_driver, sf_devclass, 0, 0); 23251473SwpaulDRIVER_MODULE(miibus, sf, miibus_driver, miibus_devclass, 0, 0); 23349076Swpaul 23449076Swpaul#define SF_SETBIT(sc, reg, x) \ 235105221Sphk csr_write_4(sc, reg, csr_read_4(sc, reg) | (x)) 23649076Swpaul 23749076Swpaul#define SF_CLRBIT(sc, reg, x) \ 238105221Sphk csr_write_4(sc, reg, csr_read_4(sc, reg) & ~(x)) 23949076Swpaul 240175526Syongaristatic uint32_t 241175526Syongaricsr_read_4(struct sf_softc *sc, int reg) 24249076Swpaul{ 243175526Syongari uint32_t val; 24449076Swpaul 245175526Syongari if (sc->sf_restype == SYS_RES_MEMORY) 246175526Syongari val = CSR_READ_4(sc, (reg + SF_RMAP_INTREG_BASE)); 247175526Syongari else { 248175526Syongari CSR_WRITE_4(sc, SF_INDIRECTIO_ADDR, reg + SF_RMAP_INTREG_BASE); 249175526Syongari val = CSR_READ_4(sc, SF_INDIRECTIO_DATA); 250175526Syongari } 25149076Swpaul 252175526Syongari return (val); 25349076Swpaul} 25449076Swpaul 255175526Syongaristatic uint8_t 256175526Syongarisf_read_eeprom(struct sf_softc *sc, int reg) 25749076Swpaul{ 258175526Syongari uint8_t val; 25949076Swpaul 26049076Swpaul val = (csr_read_4(sc, SF_EEADDR_BASE + 26149076Swpaul (reg & 0xFFFFFFFC)) >> (8 * (reg & 3))) & 0xFF; 26249076Swpaul 263175526Syongari return (val); 26449076Swpaul} 26549076Swpaul 266102335Salfredstatic void 267175526Syongaricsr_write_4(struct sf_softc *sc, int reg, uint32_t val) 26849076Swpaul{ 269175526Syongari 270175526Syongari if (sc->sf_restype == SYS_RES_MEMORY) 271175526Syongari CSR_WRITE_4(sc, (reg + SF_RMAP_INTREG_BASE), val); 272175526Syongari else { 273175526Syongari CSR_WRITE_4(sc, SF_INDIRECTIO_ADDR, reg + SF_RMAP_INTREG_BASE); 274175526Syongari CSR_WRITE_4(sc, SF_INDIRECTIO_DATA, val); 275175526Syongari } 27649076Swpaul} 27749076Swpaul 27849076Swpaul/* 27949076Swpaul * Copy the address 'mac' into the perfect RX filter entry at 28049076Swpaul * offset 'idx.' The perfect filter only has 16 entries so do 28149076Swpaul * some sanity tests. 28249076Swpaul */ 283102335Salfredstatic int 284175526Syongarisf_setperf(struct sf_softc *sc, int idx, uint8_t *mac) 28549076Swpaul{ 28649076Swpaul 28749076Swpaul if (idx < 0 || idx > SF_RXFILT_PERFECT_CNT) 288175526Syongari return (EINVAL); 28949076Swpaul 29049076Swpaul if (mac == NULL) 291175526Syongari return (EINVAL); 29249076Swpaul 29349076Swpaul csr_write_4(sc, SF_RXFILT_PERFECT_BASE + 294175526Syongari (idx * SF_RXFILT_PERFECT_SKIP) + 0, mac[5] | (mac[4] << 8)); 29549076Swpaul csr_write_4(sc, SF_RXFILT_PERFECT_BASE + 296175526Syongari (idx * SF_RXFILT_PERFECT_SKIP) + 4, mac[3] | (mac[2] << 8)); 29749076Swpaul csr_write_4(sc, SF_RXFILT_PERFECT_BASE + 298175526Syongari (idx * SF_RXFILT_PERFECT_SKIP) + 8, mac[1] | (mac[0] << 8)); 29949076Swpaul 300175526Syongari return (0); 30149076Swpaul} 30249076Swpaul 30349076Swpaul/* 30449076Swpaul * Set the bit in the 512-bit hash table that corresponds to the 30549076Swpaul * specified mac address 'mac.' If 'prio' is nonzero, update the 30649076Swpaul * priority hash table instead of the filter hash table. 30749076Swpaul */ 308102335Salfredstatic int 309175526Syongarisf_sethash(struct sf_softc *sc, caddr_t mac, int prio) 31049076Swpaul{ 311175526Syongari uint32_t h; 31249076Swpaul 31349076Swpaul if (mac == NULL) 314175526Syongari return (EINVAL); 31549076Swpaul 316130270Snaddy h = ether_crc32_be(mac, ETHER_ADDR_LEN) >> 23; 31749076Swpaul 31849076Swpaul if (prio) { 31949076Swpaul SF_SETBIT(sc, SF_RXFILT_HASH_BASE + SF_RXFILT_HASH_PRIOOFF + 32049076Swpaul (SF_RXFILT_HASH_SKIP * (h >> 4)), (1 << (h & 0xF))); 32149076Swpaul } else { 32249076Swpaul SF_SETBIT(sc, SF_RXFILT_HASH_BASE + SF_RXFILT_HASH_ADDROFF + 32349076Swpaul (SF_RXFILT_HASH_SKIP * (h >> 4)), (1 << (h & 0xF))); 32449076Swpaul } 32549076Swpaul 326175526Syongari return (0); 32749076Swpaul} 32849076Swpaul 32949076Swpaul#ifdef notdef 33049076Swpaul/* 33149076Swpaul * Set a VLAN tag in the receive filter. 33249076Swpaul */ 333102335Salfredstatic int 334175526Syongarisf_setvlan(struct sf_softc *sc, int idx, uint32_t vlan) 33549076Swpaul{ 336175526Syongari 33749076Swpaul if (idx < 0 || idx >> SF_RXFILT_HASH_CNT) 338175526Syongari return (EINVAL); 33949076Swpaul 34049076Swpaul csr_write_4(sc, SF_RXFILT_HASH_BASE + 34149076Swpaul (idx * SF_RXFILT_HASH_SKIP) + SF_RXFILT_HASH_VLANOFF, vlan); 34249076Swpaul 343175526Syongari return (0); 34449076Swpaul} 34549076Swpaul#endif 34649076Swpaul 347102335Salfredstatic int 348175526Syongarisf_miibus_readreg(device_t dev, int phy, int reg) 34950675Swpaul{ 35049076Swpaul struct sf_softc *sc; 35149076Swpaul int i; 352175526Syongari uint32_t val = 0; 35349076Swpaul 35450675Swpaul sc = device_get_softc(dev); 35550675Swpaul 35649076Swpaul for (i = 0; i < SF_TIMEOUT; i++) { 35750675Swpaul val = csr_read_4(sc, SF_PHY_REG(phy, reg)); 358175526Syongari if ((val & SF_MII_DATAVALID) != 0) 35949076Swpaul break; 36049076Swpaul } 36149076Swpaul 36249076Swpaul if (i == SF_TIMEOUT) 363175526Syongari return (0); 36449076Swpaul 365175526Syongari val &= SF_MII_DATAPORT; 366175526Syongari if (val == 0xffff) 367175526Syongari return (0); 36849076Swpaul 369175526Syongari return (val); 37049076Swpaul} 37149076Swpaul 372102335Salfredstatic int 373175526Syongarisf_miibus_writereg(device_t dev, int phy, int reg, int val) 37450675Swpaul{ 37549076Swpaul struct sf_softc *sc; 37649076Swpaul int i; 37749076Swpaul int busy; 37849076Swpaul 37950675Swpaul sc = device_get_softc(dev); 38049076Swpaul 38150675Swpaul csr_write_4(sc, SF_PHY_REG(phy, reg), val); 38250675Swpaul 38349076Swpaul for (i = 0; i < SF_TIMEOUT; i++) { 38450675Swpaul busy = csr_read_4(sc, SF_PHY_REG(phy, reg)); 385175526Syongari if ((busy & SF_MII_BUSY) == 0) 38649076Swpaul break; 38749076Swpaul } 38849076Swpaul 389175526Syongari return (0); 39050675Swpaul} 39150675Swpaul 392102335Salfredstatic void 393175526Syongarisf_miibus_statchg(device_t dev) 39450675Swpaul{ 39550675Swpaul struct sf_softc *sc; 39650675Swpaul struct mii_data *mii; 397175526Syongari struct ifnet *ifp; 398175526Syongari uint32_t val; 39950675Swpaul 400232029Syongari sc = device_get_softc(dev); 40150675Swpaul mii = device_get_softc(sc->sf_miibus); 402175526Syongari ifp = sc->sf_ifp; 403175526Syongari if (mii == NULL || ifp == NULL || 404232029Syongari (ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) 405175526Syongari return; 40650675Swpaul 407232031Syongari sc->sf_link = 0; 408232031Syongari if ((mii->mii_media_status & (IFM_ACTIVE | IFM_AVALID)) == 409232031Syongari (IFM_ACTIVE | IFM_AVALID)) { 410232031Syongari switch (IFM_SUBTYPE(mii->mii_media_active)) { 411232031Syongari case IFM_10_T: 412232031Syongari case IFM_100_TX: 413232031Syongari case IFM_100_FX: 414175526Syongari sc->sf_link = 1; 415232031Syongari break; 416232031Syongari } 417232031Syongari } 418232031Syongari if (sc->sf_link == 0) 419232031Syongari return; 420175526Syongari 421175526Syongari val = csr_read_4(sc, SF_MACCFG_1); 422175526Syongari val &= ~SF_MACCFG1_FULLDUPLEX; 423175526Syongari val &= ~(SF_MACCFG1_RX_FLOWENB | SF_MACCFG1_TX_FLOWENB); 424175526Syongari if ((IFM_OPTIONS(mii->mii_media_active) & IFM_FDX) != 0) { 425175526Syongari val |= SF_MACCFG1_FULLDUPLEX; 42654161Swpaul csr_write_4(sc, SF_BKTOBKIPG, SF_IPGT_FDX); 427175526Syongari#ifdef notyet 428175526Syongari /* Configure flow-control bits. */ 429175526Syongari if ((IFM_OPTIONS(sc->sc_mii->mii_media_active) & 430175526Syongari IFM_ETH_RXPAUSE) != 0) 431175526Syongari val |= SF_MACCFG1_RX_FLOWENB; 432175526Syongari if ((IFM_OPTIONS(sc->sc_mii->mii_media_active) & 433175526Syongari IFM_ETH_TXPAUSE) != 0) 434175526Syongari val |= SF_MACCFG1_TX_FLOWENB; 435175526Syongari#endif 436175526Syongari } else 43754161Swpaul csr_write_4(sc, SF_BKTOBKIPG, SF_IPGT_HDX); 438175526Syongari 439175526Syongari /* Make sure to reset MAC to take changes effect. */ 440175526Syongari csr_write_4(sc, SF_MACCFG_1, val | SF_MACCFG1_SOFTRESET); 441175526Syongari DELAY(1000); 442175526Syongari csr_write_4(sc, SF_MACCFG_1, val); 443175526Syongari 444175526Syongari val = csr_read_4(sc, SF_TIMER_CTL); 445175526Syongari if (IFM_SUBTYPE(mii->mii_media_active) == IFM_100_TX) 446175526Syongari val |= SF_TIMER_TIMES_TEN; 447175526Syongari else 448175526Syongari val &= ~SF_TIMER_TIMES_TEN; 449175526Syongari csr_write_4(sc, SF_TIMER_CTL, val); 45049076Swpaul} 45149076Swpaul 452102335Salfredstatic void 453175526Syongarisf_rxfilter(struct sf_softc *sc) 45449076Swpaul{ 45549076Swpaul struct ifnet *ifp; 45649076Swpaul int i; 45749076Swpaul struct ifmultiaddr *ifma; 458175526Syongari uint8_t dummy[ETHER_ADDR_LEN] = { 0, 0, 0, 0, 0, 0 }; 459175526Syongari uint32_t rxfilt; 46049076Swpaul 461147256Sbrooks ifp = sc->sf_ifp; 46249076Swpaul 46349076Swpaul /* First zot all the existing filters. */ 46449076Swpaul for (i = 1; i < SF_RXFILT_PERFECT_CNT; i++) 465175526Syongari sf_setperf(sc, i, dummy); 466175526Syongari for (i = SF_RXFILT_HASH_BASE; i < (SF_RXFILT_HASH_MAX + 1); 467175526Syongari i += sizeof(uint32_t)) 46849076Swpaul csr_write_4(sc, i, 0); 46949076Swpaul 470175526Syongari rxfilt = csr_read_4(sc, SF_RXFILT); 471175526Syongari rxfilt &= ~(SF_RXFILT_PROMISC | SF_RXFILT_ALLMULTI | SF_RXFILT_BROAD); 472175526Syongari if ((ifp->if_flags & IFF_BROADCAST) != 0) 473175526Syongari rxfilt |= SF_RXFILT_BROAD; 474175526Syongari if ((ifp->if_flags & IFF_ALLMULTI) != 0 || 475175526Syongari (ifp->if_flags & IFF_PROMISC) != 0) { 476175526Syongari if ((ifp->if_flags & IFF_PROMISC) != 0) 477175526Syongari rxfilt |= SF_RXFILT_PROMISC; 478175526Syongari if ((ifp->if_flags & IFF_ALLMULTI) != 0) 479175526Syongari rxfilt |= SF_RXFILT_ALLMULTI; 480175526Syongari goto done; 481175526Syongari } 482175526Syongari 48349076Swpaul /* Now program new ones. */ 484175526Syongari i = 1; 485195049Srwatson if_maddr_rlock(ifp); 486175526Syongari TAILQ_FOREACH_REVERSE(ifma, &ifp->if_multiaddrs, ifmultihead, 487175526Syongari ifma_link) { 488175526Syongari if (ifma->ifma_addr->sa_family != AF_LINK) 489175526Syongari continue; 490175526Syongari /* 491175526Syongari * Program the first 15 multicast groups 492175526Syongari * into the perfect filter. For all others, 493175526Syongari * use the hash table. 494175526Syongari */ 495175526Syongari if (i < SF_RXFILT_PERFECT_CNT) { 496175526Syongari sf_setperf(sc, i, 497175526Syongari LLADDR((struct sockaddr_dl *)ifma->ifma_addr)); 498175526Syongari i++; 499175526Syongari continue; 500175526Syongari } 50149076Swpaul 502175526Syongari sf_sethash(sc, 503175526Syongari LLADDR((struct sockaddr_dl *)ifma->ifma_addr), 0); 50449076Swpaul } 505195049Srwatson if_maddr_runlock(ifp); 506175526Syongari 507175526Syongaridone: 508175526Syongari csr_write_4(sc, SF_RXFILT, rxfilt); 50949076Swpaul} 51049076Swpaul 51149076Swpaul/* 51249076Swpaul * Set media options. 51349076Swpaul */ 514102335Salfredstatic int 515175526Syongarisf_ifmedia_upd(struct ifnet *ifp) 51649076Swpaul{ 51749076Swpaul struct sf_softc *sc; 518175526Syongari int error; 519149240Sjhb 520149240Sjhb sc = ifp->if_softc; 521149240Sjhb SF_LOCK(sc); 522232025Syongari error = sf_ifmedia_upd_locked(ifp); 523232025Syongari SF_UNLOCK(sc); 524232025Syongari return (error); 525232025Syongari} 526149240Sjhb 527232025Syongaristatic int 528232025Syongarisf_ifmedia_upd_locked(struct ifnet *ifp) 529232025Syongari{ 530232025Syongari struct sf_softc *sc; 531232025Syongari struct mii_data *mii; 532232025Syongari struct mii_softc *miisc; 533232025Syongari 534232025Syongari sc = ifp->if_softc; 53550675Swpaul mii = device_get_softc(sc->sf_miibus); 536221407Smarius LIST_FOREACH(miisc, &mii->mii_phys, mii_list) 537221407Smarius PHY_RESET(miisc); 538232025Syongari return (mii_mediachg(mii)); 53949076Swpaul} 54049076Swpaul 54149076Swpaul/* 54249076Swpaul * Report current media status. 54349076Swpaul */ 544102335Salfredstatic void 545175526Syongarisf_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr) 54649076Swpaul{ 54749076Swpaul struct sf_softc *sc; 54850675Swpaul struct mii_data *mii; 54949076Swpaul 55049076Swpaul sc = ifp->if_softc; 551149240Sjhb SF_LOCK(sc); 552232029Syongari if ((ifp->if_flags & IFF_UP) == 0) { 553232029Syongari SF_UNLOCK(sc); 554232029Syongari return; 555232029Syongari } 556232029Syongari 55750675Swpaul mii = device_get_softc(sc->sf_miibus); 55850675Swpaul mii_pollstat(mii); 55950675Swpaul ifmr->ifm_active = mii->mii_media_active; 56050675Swpaul ifmr->ifm_status = mii->mii_media_status; 561149240Sjhb SF_UNLOCK(sc); 56249076Swpaul} 56349076Swpaul 564102335Salfredstatic int 565175526Syongarisf_ioctl(struct ifnet *ifp, u_long command, caddr_t data) 56649076Swpaul{ 567175526Syongari struct sf_softc *sc; 568175526Syongari struct ifreq *ifr; 56950675Swpaul struct mii_data *mii; 570175526Syongari int error, mask; 57149076Swpaul 572175526Syongari sc = ifp->if_softc; 573175526Syongari ifr = (struct ifreq *)data; 574175526Syongari error = 0; 575175526Syongari 576175526Syongari switch (command) { 57749076Swpaul case SIOCSIFFLAGS: 578149240Sjhb SF_LOCK(sc); 57949076Swpaul if (ifp->if_flags & IFF_UP) { 580175526Syongari if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0) { 581175526Syongari if ((ifp->if_flags ^ sc->sf_if_flags) & 582175526Syongari (IFF_PROMISC | IFF_ALLMULTI)) 583175526Syongari sf_rxfilter(sc); 584175526Syongari } else { 585175526Syongari if (sc->sf_detach == 0) 586175526Syongari sf_init_locked(sc); 587175526Syongari } 58849076Swpaul } else { 589175526Syongari if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0) 59049076Swpaul sf_stop(sc); 59149076Swpaul } 59254161Swpaul sc->sf_if_flags = ifp->if_flags; 593149240Sjhb SF_UNLOCK(sc); 59449076Swpaul break; 59549076Swpaul case SIOCADDMULTI: 59649076Swpaul case SIOCDELMULTI: 597149240Sjhb SF_LOCK(sc); 598232027Syongari if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0) 599232027Syongari sf_rxfilter(sc); 600149240Sjhb SF_UNLOCK(sc); 60149076Swpaul break; 60249076Swpaul case SIOCGIFMEDIA: 60349076Swpaul case SIOCSIFMEDIA: 60450675Swpaul mii = device_get_softc(sc->sf_miibus); 60550675Swpaul error = ifmedia_ioctl(ifp, ifr, &mii->mii_media, command); 60649076Swpaul break; 607137557Sbrueffer case SIOCSIFCAP: 608175526Syongari mask = ifr->ifr_reqcap ^ ifp->if_capenable; 609150789Sglebius#ifdef DEVICE_POLLING 610175526Syongari if ((mask & IFCAP_POLLING) != 0) { 611175526Syongari if ((ifr->ifr_reqcap & IFCAP_POLLING) != 0) { 612175526Syongari error = ether_poll_register(sf_poll, ifp); 613175526Syongari if (error != 0) 614175526Syongari break; 615175526Syongari SF_LOCK(sc); 616175526Syongari /* Disable interrupts. */ 617175526Syongari csr_write_4(sc, SF_IMR, 0); 618175526Syongari ifp->if_capenable |= IFCAP_POLLING; 619175526Syongari SF_UNLOCK(sc); 620175526Syongari } else { 621175526Syongari error = ether_poll_deregister(ifp); 622175526Syongari /* Enable interrupts. */ 623175526Syongari SF_LOCK(sc); 624175526Syongari csr_write_4(sc, SF_IMR, SF_INTRS); 625175526Syongari ifp->if_capenable &= ~IFCAP_POLLING; 626175526Syongari SF_UNLOCK(sc); 627175526Syongari } 628150789Sglebius } 629175526Syongari#endif /* DEVICE_POLLING */ 630175526Syongari if ((mask & IFCAP_TXCSUM) != 0) { 631175526Syongari if ((IFCAP_TXCSUM & ifp->if_capabilities) != 0) { 632175526Syongari SF_LOCK(sc); 633175526Syongari ifp->if_capenable ^= IFCAP_TXCSUM; 634175526Syongari if ((IFCAP_TXCSUM & ifp->if_capenable) != 0) { 635175526Syongari ifp->if_hwassist |= SF_CSUM_FEATURES; 636175526Syongari SF_SETBIT(sc, SF_GEN_ETH_CTL, 637175526Syongari SF_ETHCTL_TXGFP_ENB); 638175526Syongari } else { 639175526Syongari ifp->if_hwassist &= ~SF_CSUM_FEATURES; 640175526Syongari SF_CLRBIT(sc, SF_GEN_ETH_CTL, 641175526Syongari SF_ETHCTL_TXGFP_ENB); 642175526Syongari } 643175526Syongari SF_UNLOCK(sc); 644175526Syongari } 645150789Sglebius } 646175526Syongari if ((mask & IFCAP_RXCSUM) != 0) { 647175526Syongari if ((IFCAP_RXCSUM & ifp->if_capabilities) != 0) { 648175526Syongari SF_LOCK(sc); 649175526Syongari ifp->if_capenable ^= IFCAP_RXCSUM; 650175526Syongari if ((IFCAP_RXCSUM & ifp->if_capenable) != 0) 651175526Syongari SF_SETBIT(sc, SF_GEN_ETH_CTL, 652175526Syongari SF_ETHCTL_RXGFP_ENB); 653175526Syongari else 654175526Syongari SF_CLRBIT(sc, SF_GEN_ETH_CTL, 655175526Syongari SF_ETHCTL_RXGFP_ENB); 656175526Syongari SF_UNLOCK(sc); 657175526Syongari } 658175526Syongari } 659137557Sbrueffer break; 66049076Swpaul default: 661106936Ssam error = ether_ioctl(ifp, command, data); 66249076Swpaul break; 66349076Swpaul } 66449076Swpaul 665175526Syongari return (error); 66649076Swpaul} 66749076Swpaul 668102335Salfredstatic void 669175526Syongarisf_reset(struct sf_softc *sc) 67049076Swpaul{ 671175526Syongari int i; 67249076Swpaul 67349076Swpaul csr_write_4(sc, SF_GEN_ETH_CTL, 0); 67449076Swpaul SF_SETBIT(sc, SF_MACCFG_1, SF_MACCFG1_SOFTRESET); 67549076Swpaul DELAY(1000); 67649076Swpaul SF_CLRBIT(sc, SF_MACCFG_1, SF_MACCFG1_SOFTRESET); 67749076Swpaul 67849076Swpaul SF_SETBIT(sc, SF_PCI_DEVCFG, SF_PCIDEVCFG_RESET); 67949076Swpaul 68049076Swpaul for (i = 0; i < SF_TIMEOUT; i++) { 68149076Swpaul DELAY(10); 68249076Swpaul if (!(csr_read_4(sc, SF_PCI_DEVCFG) & SF_PCIDEVCFG_RESET)) 68349076Swpaul break; 68449076Swpaul } 68549076Swpaul 68649076Swpaul if (i == SF_TIMEOUT) 687162315Sglebius device_printf(sc->sf_dev, "reset never completed!\n"); 68849076Swpaul 68949076Swpaul /* Wait a little while for the chip to get its brains in order. */ 69049076Swpaul DELAY(1000); 69149076Swpaul} 69249076Swpaul 69349076Swpaul/* 69449076Swpaul * Probe for an Adaptec AIC-6915 chip. Check the PCI vendor and device 69549076Swpaul * IDs against our list and return a device name if we find a match. 69649076Swpaul * We also check the subsystem ID so that we can identify exactly which 69749076Swpaul * NIC has been found, if possible. 69849076Swpaul */ 699102335Salfredstatic int 700175526Syongarisf_probe(device_t dev) 70149076Swpaul{ 70249076Swpaul struct sf_type *t; 703175526Syongari uint16_t vid; 704175526Syongari uint16_t did; 705175526Syongari uint16_t sdid; 706175526Syongari int i; 70749076Swpaul 708175526Syongari vid = pci_get_vendor(dev); 709175526Syongari did = pci_get_device(dev); 710175526Syongari sdid = pci_get_subdevice(dev); 711175526Syongari 71249076Swpaul t = sf_devs; 713298307Spfg for (i = 0; i < nitems(sf_devs); i++, t++) { 714175526Syongari if (vid == t->sf_vid && did == t->sf_did) { 715175526Syongari if (sdid == t->sf_sdid) { 716175526Syongari device_set_desc(dev, t->sf_sname); 717142398Simp return (BUS_PROBE_DEFAULT); 71849076Swpaul } 71949076Swpaul } 72049076Swpaul } 72149076Swpaul 722175526Syongari if (vid == AD_VENDORID && did == AD_DEVICEID_STARFIRE) { 723298955Spfg /* unknown subdevice */ 724175526Syongari device_set_desc(dev, sf_devs[0].sf_name); 725175526Syongari return (BUS_PROBE_DEFAULT); 726175526Syongari } 727175526Syongari 728175526Syongari return (ENXIO); 72949076Swpaul} 73049076Swpaul 73149076Swpaul/* 73249076Swpaul * Attach the interface. Allocate softc structures, do ifmedia 73349076Swpaul * setup and ethernet/BPF attach. 73449076Swpaul */ 735102335Salfredstatic int 736175526Syongarisf_attach(device_t dev) 73749076Swpaul{ 73867087Swpaul int i; 73949076Swpaul struct sf_softc *sc; 74049076Swpaul struct ifnet *ifp; 741175526Syongari uint32_t reg; 742148947Sjhb int rid, error = 0; 743175526Syongari uint8_t eaddr[ETHER_ADDR_LEN]; 74449076Swpaul 74549076Swpaul sc = device_get_softc(dev); 746162315Sglebius sc->sf_dev = dev; 74749076Swpaul 74893818Sjhb mtx_init(&sc->sf_mtx, device_get_nameunit(dev), MTX_NETWORK_LOCK, 749149240Sjhb MTX_DEF); 750175526Syongari callout_init_mtx(&sc->sf_co, &sc->sf_mtx, 0); 751175526Syongari 75249076Swpaul /* 75349076Swpaul * Map control/status registers. 75449076Swpaul */ 75572813Swpaul pci_enable_busmaster(dev); 75649076Swpaul 757175526Syongari /* 758175526Syongari * Prefer memory space register mapping over I/O space as the 759175526Syongari * hardware requires lots of register access to get various 760175526Syongari * producer/consumer index during Tx/Rx operation. However this 761175526Syongari * requires large memory space(512K) to map the entire register 762175526Syongari * space. 763175526Syongari */ 764175526Syongari sc->sf_rid = PCIR_BAR(0); 765175526Syongari sc->sf_restype = SYS_RES_MEMORY; 766175526Syongari sc->sf_res = bus_alloc_resource_any(dev, sc->sf_restype, &sc->sf_rid, 767175526Syongari RF_ACTIVE); 76849076Swpaul if (sc->sf_res == NULL) { 769175526Syongari reg = pci_read_config(dev, PCIR_BAR(0), 4); 770175526Syongari if ((reg & PCIM_BAR_MEM_64) == PCIM_BAR_MEM_64) 771175526Syongari sc->sf_rid = PCIR_BAR(2); 772175526Syongari else 773175526Syongari sc->sf_rid = PCIR_BAR(1); 774175526Syongari sc->sf_restype = SYS_RES_IOPORT; 775175526Syongari sc->sf_res = bus_alloc_resource_any(dev, sc->sf_restype, 776175526Syongari &sc->sf_rid, RF_ACTIVE); 777175526Syongari if (sc->sf_res == NULL) { 778175526Syongari device_printf(dev, "couldn't allocate resources\n"); 779175526Syongari mtx_destroy(&sc->sf_mtx); 780175526Syongari return (ENXIO); 781175526Syongari } 78249076Swpaul } 783175526Syongari if (bootverbose) 784175526Syongari device_printf(dev, "using %s space register mapping\n", 785175526Syongari sc->sf_restype == SYS_RES_MEMORY ? "memory" : "I/O"); 78649076Swpaul 787175526Syongari reg = pci_read_config(dev, PCIR_CACHELNSZ, 1); 788175526Syongari if (reg == 0) { 789175526Syongari /* 790175526Syongari * If cache line size is 0, MWI is not used at all, so set 791175526Syongari * reasonable default. AIC-6915 supports 0, 4, 8, 16, 32 792175526Syongari * and 64. 793175526Syongari */ 794175526Syongari reg = 16; 795175526Syongari device_printf(dev, "setting PCI cache line size to %u\n", reg); 796175526Syongari pci_write_config(dev, PCIR_CACHELNSZ, reg, 1); 797175526Syongari } else { 798175526Syongari if (bootverbose) 799175526Syongari device_printf(dev, "PCI cache line size : %u\n", reg); 800175526Syongari } 801175526Syongari /* Enable MWI. */ 802175526Syongari reg = pci_read_config(dev, PCIR_COMMAND, 2); 803175526Syongari reg |= PCIM_CMD_MWRICEN; 804175526Syongari pci_write_config(dev, PCIR_COMMAND, reg, 2); 80549076Swpaul 806175526Syongari /* Allocate interrupt. */ 80749076Swpaul rid = 0; 808127135Snjl sc->sf_irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, 80949076Swpaul RF_SHAREABLE | RF_ACTIVE); 81049076Swpaul 81149076Swpaul if (sc->sf_irq == NULL) { 812148947Sjhb device_printf(dev, "couldn't map interrupt\n"); 81349076Swpaul error = ENXIO; 81449076Swpaul goto fail; 81549076Swpaul } 81649076Swpaul 817175526Syongari SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), 818175526Syongari SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 819175526Syongari OID_AUTO, "stats", CTLTYPE_INT | CTLFLAG_RW, sc, 0, 820175526Syongari sf_sysctl_stats, "I", "Statistics"); 821149240Sjhb 822175526Syongari SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), 823175526Syongari SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 824175526Syongari OID_AUTO, "int_mod", CTLTYPE_INT | CTLFLAG_RW, 825175526Syongari &sc->sf_int_mod, 0, sysctl_hw_sf_int_mod, "I", 826175526Syongari "sf interrupt moderation"); 827175526Syongari /* Pull in device tunables. */ 828175526Syongari sc->sf_int_mod = SF_IM_DEFAULT; 829175526Syongari error = resource_int_value(device_get_name(dev), device_get_unit(dev), 830175526Syongari "int_mod", &sc->sf_int_mod); 831175526Syongari if (error == 0) { 832175526Syongari if (sc->sf_int_mod < SF_IM_MIN || 833175526Syongari sc->sf_int_mod > SF_IM_MAX) { 834175526Syongari device_printf(dev, "int_mod value out of range; " 835175526Syongari "using default: %d\n", SF_IM_DEFAULT); 836175526Syongari sc->sf_int_mod = SF_IM_DEFAULT; 837175526Syongari } 838175526Syongari } 839175526Syongari 84049076Swpaul /* Reset the adapter. */ 84149076Swpaul sf_reset(sc); 84249076Swpaul 84349076Swpaul /* 84449076Swpaul * Get station address from the EEPROM. 84549076Swpaul */ 84649076Swpaul for (i = 0; i < ETHER_ADDR_LEN; i++) 847147256Sbrooks eaddr[i] = 84849076Swpaul sf_read_eeprom(sc, SF_EE_NODEADDR + ETHER_ADDR_LEN - i); 84949076Swpaul 850175526Syongari /* Allocate DMA resources. */ 851175526Syongari if (sf_dma_alloc(sc) != 0) { 852175526Syongari error = ENOSPC; 85349076Swpaul goto fail; 85449076Swpaul } 85549076Swpaul 856175526Syongari sc->sf_txthresh = SF_MIN_TX_THRESHOLD; 85749076Swpaul 858147291Sbrooks ifp = sc->sf_ifp = if_alloc(IFT_ETHER); 859147291Sbrooks if (ifp == NULL) { 860175526Syongari device_printf(dev, "can not allocate ifnet structure\n"); 861147291Sbrooks error = ENOSPC; 862147291Sbrooks goto fail; 863147291Sbrooks } 864147291Sbrooks 86550675Swpaul /* Do MII setup. */ 866213894Smarius error = mii_attach(dev, &sc->sf_miibus, ifp, sf_ifmedia_upd, 867213894Smarius sf_ifmedia_sts, BMSR_DEFCAPMASK, MII_PHY_ANY, MII_OFFSET_ANY, 0); 868213894Smarius if (error != 0) { 869213894Smarius device_printf(dev, "attaching PHYs failed\n"); 87049076Swpaul goto fail; 87149076Swpaul } 87249076Swpaul 87349076Swpaul ifp->if_softc = sc; 874121816Sbrooks if_initname(ifp, device_get_name(dev), device_get_unit(dev)); 875149240Sjhb ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 87649076Swpaul ifp->if_ioctl = sf_ioctl; 87749076Swpaul ifp->if_start = sf_start; 87849076Swpaul ifp->if_init = sf_init; 879137620Sbrueffer IFQ_SET_MAXLEN(&ifp->if_snd, SF_TX_DLIST_CNT - 1); 880137620Sbrueffer ifp->if_snd.ifq_drv_maxlen = SF_TX_DLIST_CNT - 1; 881137620Sbrueffer IFQ_SET_READY(&ifp->if_snd); 882175526Syongari /* 883175526Syongari * With the help of firmware, AIC-6915 supports 884175526Syongari * Tx/Rx TCP/UDP checksum offload. 885175526Syongari */ 886175526Syongari ifp->if_hwassist = SF_CSUM_FEATURES; 887175526Syongari ifp->if_capabilities = IFCAP_HWCSUM; 888175526Syongari 889175526Syongari /* 890175526Syongari * Call MI attach routine. 891175526Syongari */ 892175526Syongari ether_ifattach(ifp, eaddr); 893175526Syongari 894175526Syongari /* VLAN capability setup. */ 895175526Syongari ifp->if_capabilities |= IFCAP_VLAN_MTU; 896150789Sglebius ifp->if_capenable = ifp->if_capabilities; 897137557Sbrueffer#ifdef DEVICE_POLLING 898137557Sbrueffer ifp->if_capabilities |= IFCAP_POLLING; 899150789Sglebius#endif 90049076Swpaul /* 901175526Syongari * Tell the upper layer(s) we support long frames. 902175526Syongari * Must appear after the call to ether_ifattach() because 903175526Syongari * ether_ifattach() sets ifi_hdrlen to the default value. 90449076Swpaul */ 905270856Sglebius ifp->if_hdrlen = sizeof(struct ether_vlan_header); 90649076Swpaul 907113609Snjl /* Hook interrupt last to avoid having to lock softc */ 908149240Sjhb error = bus_setup_intr(dev, sc->sf_irq, INTR_TYPE_NET | INTR_MPSAFE, 909166901Spiso NULL, sf_intr, sc, &sc->sf_intrhand); 910112872Snjl 911112872Snjl if (error) { 912148947Sjhb device_printf(dev, "couldn't set up irq\n"); 913113609Snjl ether_ifdetach(ifp); 914112872Snjl goto fail; 915112872Snjl } 916112872Snjl 917347962Sbrooks gone_by_fcp101_dev(dev); 918347962Sbrooks 91949076Swpaulfail: 920112872Snjl if (error) 921112872Snjl sf_detach(dev); 922112872Snjl 923175526Syongari return (error); 92449076Swpaul} 92549076Swpaul 926113609Snjl/* 927113609Snjl * Shutdown hardware and free up resources. This can be called any 928113609Snjl * time after the mutex has been initialized. It is called in both 929113609Snjl * the error case in attach and the normal detach case so it needs 930113609Snjl * to be careful about only freeing resources that have actually been 931113609Snjl * allocated. 932113609Snjl */ 933102335Salfredstatic int 934175526Syongarisf_detach(device_t dev) 93549076Swpaul{ 93649076Swpaul struct sf_softc *sc; 93749076Swpaul struct ifnet *ifp; 93849076Swpaul 93949076Swpaul sc = device_get_softc(dev); 940147256Sbrooks ifp = sc->sf_ifp; 94149076Swpaul 942150789Sglebius#ifdef DEVICE_POLLING 943175526Syongari if (ifp != NULL && ifp->if_capenable & IFCAP_POLLING) 944150789Sglebius ether_poll_deregister(ifp); 945150789Sglebius#endif 946175526Syongari 947113609Snjl /* These should only be active if attach succeeded */ 948113812Simp if (device_is_attached(dev)) { 949149240Sjhb SF_LOCK(sc); 950175526Syongari sc->sf_detach = 1; 951113609Snjl sf_stop(sc); 952149240Sjhb SF_UNLOCK(sc); 953175526Syongari callout_drain(&sc->sf_co); 954175526Syongari if (ifp != NULL) 955175526Syongari ether_ifdetach(ifp); 956150213Sru } 957175526Syongari if (sc->sf_miibus) { 958112872Snjl device_delete_child(dev, sc->sf_miibus); 959175526Syongari sc->sf_miibus = NULL; 960175526Syongari } 961113609Snjl bus_generic_detach(dev); 96249076Swpaul 963175526Syongari if (sc->sf_intrhand != NULL) 964112872Snjl bus_teardown_intr(dev, sc->sf_irq, sc->sf_intrhand); 965175526Syongari if (sc->sf_irq != NULL) 966112872Snjl bus_release_resource(dev, SYS_RES_IRQ, 0, sc->sf_irq); 967175526Syongari if (sc->sf_res != NULL) 968175526Syongari bus_release_resource(dev, sc->sf_restype, sc->sf_rid, 969175526Syongari sc->sf_res); 97050675Swpaul 971175526Syongari sf_dma_free(sc); 972175526Syongari if (ifp != NULL) 973151297Sru if_free(ifp); 974151297Sru 97567087Swpaul mtx_destroy(&sc->sf_mtx); 97649076Swpaul 977175526Syongari return (0); 97849076Swpaul} 97949076Swpaul 980175526Syongaristruct sf_dmamap_arg { 981175526Syongari bus_addr_t sf_busaddr; 982175526Syongari}; 983175526Syongari 984175526Syongaristatic void 985175526Syongarisf_dmamap_cb(void *arg, bus_dma_segment_t *segs, int nseg, int error) 986175526Syongari{ 987175526Syongari struct sf_dmamap_arg *ctx; 988175526Syongari 989175526Syongari if (error != 0) 990175526Syongari return; 991175526Syongari ctx = arg; 992175526Syongari ctx->sf_busaddr = segs[0].ds_addr; 993175526Syongari} 994175526Syongari 995102335Salfredstatic int 996175526Syongarisf_dma_alloc(struct sf_softc *sc) 99749076Swpaul{ 998175526Syongari struct sf_dmamap_arg ctx; 999175526Syongari struct sf_txdesc *txd; 1000175526Syongari struct sf_rxdesc *rxd; 1001175526Syongari bus_addr_t lowaddr; 1002175526Syongari bus_addr_t rx_ring_end, rx_cring_end; 1003175526Syongari bus_addr_t tx_ring_end, tx_cring_end; 1004175526Syongari int error, i; 100549076Swpaul 1006175526Syongari lowaddr = BUS_SPACE_MAXADDR; 100749076Swpaul 1008175526Syongariagain: 1009175526Syongari /* Create parent DMA tag. */ 1010175526Syongari error = bus_dma_tag_create( 1011175526Syongari bus_get_dma_tag(sc->sf_dev), /* parent */ 1012175526Syongari 1, 0, /* alignment, boundary */ 1013175526Syongari lowaddr, /* lowaddr */ 1014175526Syongari BUS_SPACE_MAXADDR, /* highaddr */ 1015175526Syongari NULL, NULL, /* filter, filterarg */ 1016175526Syongari BUS_SPACE_MAXSIZE_32BIT, /* maxsize */ 1017175526Syongari 0, /* nsegments */ 1018175526Syongari BUS_SPACE_MAXSIZE_32BIT, /* maxsegsize */ 1019175526Syongari 0, /* flags */ 1020175526Syongari NULL, NULL, /* lockfunc, lockarg */ 1021175526Syongari &sc->sf_cdata.sf_parent_tag); 1022175526Syongari if (error != 0) { 1023175526Syongari device_printf(sc->sf_dev, "failed to create parent DMA tag\n"); 1024175526Syongari goto fail; 1025175526Syongari } 1026175526Syongari /* Create tag for Tx ring. */ 1027175526Syongari error = bus_dma_tag_create(sc->sf_cdata.sf_parent_tag,/* parent */ 1028175526Syongari SF_RING_ALIGN, 0, /* alignment, boundary */ 1029175526Syongari BUS_SPACE_MAXADDR, /* lowaddr */ 1030175526Syongari BUS_SPACE_MAXADDR, /* highaddr */ 1031175526Syongari NULL, NULL, /* filter, filterarg */ 1032175526Syongari SF_TX_DLIST_SIZE, /* maxsize */ 1033175526Syongari 1, /* nsegments */ 1034175526Syongari SF_TX_DLIST_SIZE, /* maxsegsize */ 1035175526Syongari 0, /* flags */ 1036175526Syongari NULL, NULL, /* lockfunc, lockarg */ 1037175526Syongari &sc->sf_cdata.sf_tx_ring_tag); 1038175526Syongari if (error != 0) { 1039175526Syongari device_printf(sc->sf_dev, "failed to create Tx ring DMA tag\n"); 1040175526Syongari goto fail; 1041175526Syongari } 104249076Swpaul 1043175526Syongari /* Create tag for Tx completion ring. */ 1044175526Syongari error = bus_dma_tag_create(sc->sf_cdata.sf_parent_tag,/* parent */ 1045175526Syongari SF_RING_ALIGN, 0, /* alignment, boundary */ 1046175526Syongari BUS_SPACE_MAXADDR, /* lowaddr */ 1047175526Syongari BUS_SPACE_MAXADDR, /* highaddr */ 1048175526Syongari NULL, NULL, /* filter, filterarg */ 1049175526Syongari SF_TX_CLIST_SIZE, /* maxsize */ 1050175526Syongari 1, /* nsegments */ 1051175526Syongari SF_TX_CLIST_SIZE, /* maxsegsize */ 1052175526Syongari 0, /* flags */ 1053175526Syongari NULL, NULL, /* lockfunc, lockarg */ 1054175526Syongari &sc->sf_cdata.sf_tx_cring_tag); 1055175526Syongari if (error != 0) { 1056175526Syongari device_printf(sc->sf_dev, 1057175526Syongari "failed to create Tx completion ring DMA tag\n"); 1058175526Syongari goto fail; 1059175526Syongari } 1060175526Syongari 1061175526Syongari /* Create tag for Rx ring. */ 1062175526Syongari error = bus_dma_tag_create(sc->sf_cdata.sf_parent_tag,/* parent */ 1063175526Syongari SF_RING_ALIGN, 0, /* alignment, boundary */ 1064175526Syongari BUS_SPACE_MAXADDR, /* lowaddr */ 1065175526Syongari BUS_SPACE_MAXADDR, /* highaddr */ 1066175526Syongari NULL, NULL, /* filter, filterarg */ 1067175526Syongari SF_RX_DLIST_SIZE, /* maxsize */ 1068175526Syongari 1, /* nsegments */ 1069175526Syongari SF_RX_DLIST_SIZE, /* maxsegsize */ 1070175526Syongari 0, /* flags */ 1071175526Syongari NULL, NULL, /* lockfunc, lockarg */ 1072175526Syongari &sc->sf_cdata.sf_rx_ring_tag); 1073175526Syongari if (error != 0) { 1074175526Syongari device_printf(sc->sf_dev, 1075175526Syongari "failed to create Rx ring DMA tag\n"); 1076175526Syongari goto fail; 1077175526Syongari } 1078175526Syongari 1079175526Syongari /* Create tag for Rx completion ring. */ 1080175526Syongari error = bus_dma_tag_create(sc->sf_cdata.sf_parent_tag,/* parent */ 1081175526Syongari SF_RING_ALIGN, 0, /* alignment, boundary */ 1082175526Syongari BUS_SPACE_MAXADDR, /* lowaddr */ 1083175526Syongari BUS_SPACE_MAXADDR, /* highaddr */ 1084175526Syongari NULL, NULL, /* filter, filterarg */ 1085175526Syongari SF_RX_CLIST_SIZE, /* maxsize */ 1086175526Syongari 1, /* nsegments */ 1087175526Syongari SF_RX_CLIST_SIZE, /* maxsegsize */ 1088175526Syongari 0, /* flags */ 1089175526Syongari NULL, NULL, /* lockfunc, lockarg */ 1090175526Syongari &sc->sf_cdata.sf_rx_cring_tag); 1091175526Syongari if (error != 0) { 1092175526Syongari device_printf(sc->sf_dev, 1093175526Syongari "failed to create Rx completion ring DMA tag\n"); 1094175526Syongari goto fail; 1095175526Syongari } 1096175526Syongari 1097175526Syongari /* Create tag for Tx buffers. */ 1098175526Syongari error = bus_dma_tag_create(sc->sf_cdata.sf_parent_tag,/* parent */ 1099175526Syongari 1, 0, /* alignment, boundary */ 1100175526Syongari BUS_SPACE_MAXADDR, /* lowaddr */ 1101175526Syongari BUS_SPACE_MAXADDR, /* highaddr */ 1102175526Syongari NULL, NULL, /* filter, filterarg */ 1103175526Syongari MCLBYTES * SF_MAXTXSEGS, /* maxsize */ 1104175526Syongari SF_MAXTXSEGS, /* nsegments */ 1105175526Syongari MCLBYTES, /* maxsegsize */ 1106175526Syongari 0, /* flags */ 1107175526Syongari NULL, NULL, /* lockfunc, lockarg */ 1108175526Syongari &sc->sf_cdata.sf_tx_tag); 1109175526Syongari if (error != 0) { 1110175526Syongari device_printf(sc->sf_dev, "failed to create Tx DMA tag\n"); 1111175526Syongari goto fail; 1112175526Syongari } 1113175526Syongari 1114175526Syongari /* Create tag for Rx buffers. */ 1115175526Syongari error = bus_dma_tag_create(sc->sf_cdata.sf_parent_tag,/* parent */ 1116175526Syongari SF_RX_ALIGN, 0, /* alignment, boundary */ 1117175526Syongari BUS_SPACE_MAXADDR, /* lowaddr */ 1118175526Syongari BUS_SPACE_MAXADDR, /* highaddr */ 1119175526Syongari NULL, NULL, /* filter, filterarg */ 1120175526Syongari MCLBYTES, /* maxsize */ 1121175526Syongari 1, /* nsegments */ 1122175526Syongari MCLBYTES, /* maxsegsize */ 1123175526Syongari 0, /* flags */ 1124175526Syongari NULL, NULL, /* lockfunc, lockarg */ 1125175526Syongari &sc->sf_cdata.sf_rx_tag); 1126175526Syongari if (error != 0) { 1127175526Syongari device_printf(sc->sf_dev, "failed to create Rx DMA tag\n"); 1128175526Syongari goto fail; 1129175526Syongari } 1130175526Syongari 1131175526Syongari /* Allocate DMA'able memory and load the DMA map for Tx ring. */ 1132175526Syongari error = bus_dmamem_alloc(sc->sf_cdata.sf_tx_ring_tag, 1133175526Syongari (void **)&sc->sf_rdata.sf_tx_ring, BUS_DMA_WAITOK | 1134175526Syongari BUS_DMA_COHERENT | BUS_DMA_ZERO, &sc->sf_cdata.sf_tx_ring_map); 1135175526Syongari if (error != 0) { 1136175526Syongari device_printf(sc->sf_dev, 1137175526Syongari "failed to allocate DMA'able memory for Tx ring\n"); 1138175526Syongari goto fail; 1139175526Syongari } 1140175526Syongari 1141175526Syongari ctx.sf_busaddr = 0; 1142175526Syongari error = bus_dmamap_load(sc->sf_cdata.sf_tx_ring_tag, 1143175526Syongari sc->sf_cdata.sf_tx_ring_map, sc->sf_rdata.sf_tx_ring, 1144175526Syongari SF_TX_DLIST_SIZE, sf_dmamap_cb, &ctx, 0); 1145175526Syongari if (error != 0 || ctx.sf_busaddr == 0) { 1146175526Syongari device_printf(sc->sf_dev, 1147175526Syongari "failed to load DMA'able memory for Tx ring\n"); 1148175526Syongari goto fail; 1149175526Syongari } 1150175526Syongari sc->sf_rdata.sf_tx_ring_paddr = ctx.sf_busaddr; 1151175526Syongari 1152175526Syongari /* 1153175526Syongari * Allocate DMA'able memory and load the DMA map for Tx completion ring. 1154175526Syongari */ 1155175526Syongari error = bus_dmamem_alloc(sc->sf_cdata.sf_tx_cring_tag, 1156175526Syongari (void **)&sc->sf_rdata.sf_tx_cring, BUS_DMA_WAITOK | 1157175526Syongari BUS_DMA_COHERENT | BUS_DMA_ZERO, &sc->sf_cdata.sf_tx_cring_map); 1158175526Syongari if (error != 0) { 1159175526Syongari device_printf(sc->sf_dev, 1160175526Syongari "failed to allocate DMA'able memory for " 1161175526Syongari "Tx completion ring\n"); 1162175526Syongari goto fail; 1163175526Syongari } 1164175526Syongari 1165175526Syongari ctx.sf_busaddr = 0; 1166175526Syongari error = bus_dmamap_load(sc->sf_cdata.sf_tx_cring_tag, 1167175526Syongari sc->sf_cdata.sf_tx_cring_map, sc->sf_rdata.sf_tx_cring, 1168175526Syongari SF_TX_CLIST_SIZE, sf_dmamap_cb, &ctx, 0); 1169175526Syongari if (error != 0 || ctx.sf_busaddr == 0) { 1170175526Syongari device_printf(sc->sf_dev, 1171175526Syongari "failed to load DMA'able memory for Tx completion ring\n"); 1172175526Syongari goto fail; 1173175526Syongari } 1174175526Syongari sc->sf_rdata.sf_tx_cring_paddr = ctx.sf_busaddr; 1175175526Syongari 1176175526Syongari /* Allocate DMA'able memory and load the DMA map for Rx ring. */ 1177175526Syongari error = bus_dmamem_alloc(sc->sf_cdata.sf_rx_ring_tag, 1178175526Syongari (void **)&sc->sf_rdata.sf_rx_ring, BUS_DMA_WAITOK | 1179175526Syongari BUS_DMA_COHERENT | BUS_DMA_ZERO, &sc->sf_cdata.sf_rx_ring_map); 1180175526Syongari if (error != 0) { 1181175526Syongari device_printf(sc->sf_dev, 1182175526Syongari "failed to allocate DMA'able memory for Rx ring\n"); 1183175526Syongari goto fail; 1184175526Syongari } 1185175526Syongari 1186175526Syongari ctx.sf_busaddr = 0; 1187175526Syongari error = bus_dmamap_load(sc->sf_cdata.sf_rx_ring_tag, 1188175526Syongari sc->sf_cdata.sf_rx_ring_map, sc->sf_rdata.sf_rx_ring, 1189175526Syongari SF_RX_DLIST_SIZE, sf_dmamap_cb, &ctx, 0); 1190175526Syongari if (error != 0 || ctx.sf_busaddr == 0) { 1191175526Syongari device_printf(sc->sf_dev, 1192175526Syongari "failed to load DMA'able memory for Rx ring\n"); 1193175526Syongari goto fail; 1194175526Syongari } 1195175526Syongari sc->sf_rdata.sf_rx_ring_paddr = ctx.sf_busaddr; 1196175526Syongari 1197175526Syongari /* 1198175526Syongari * Allocate DMA'able memory and load the DMA map for Rx completion ring. 1199175526Syongari */ 1200175526Syongari error = bus_dmamem_alloc(sc->sf_cdata.sf_rx_cring_tag, 1201175526Syongari (void **)&sc->sf_rdata.sf_rx_cring, BUS_DMA_WAITOK | 1202175526Syongari BUS_DMA_COHERENT | BUS_DMA_ZERO, &sc->sf_cdata.sf_rx_cring_map); 1203175526Syongari if (error != 0) { 1204175526Syongari device_printf(sc->sf_dev, 1205175526Syongari "failed to allocate DMA'able memory for " 1206175526Syongari "Rx completion ring\n"); 1207175526Syongari goto fail; 1208175526Syongari } 1209175526Syongari 1210175526Syongari ctx.sf_busaddr = 0; 1211175526Syongari error = bus_dmamap_load(sc->sf_cdata.sf_rx_cring_tag, 1212175526Syongari sc->sf_cdata.sf_rx_cring_map, sc->sf_rdata.sf_rx_cring, 1213175526Syongari SF_RX_CLIST_SIZE, sf_dmamap_cb, &ctx, 0); 1214175526Syongari if (error != 0 || ctx.sf_busaddr == 0) { 1215175526Syongari device_printf(sc->sf_dev, 1216175526Syongari "failed to load DMA'able memory for Rx completion ring\n"); 1217175526Syongari goto fail; 1218175526Syongari } 1219175526Syongari sc->sf_rdata.sf_rx_cring_paddr = ctx.sf_busaddr; 1220175526Syongari 1221175526Syongari /* 1222175526Syongari * Tx desciptor ring and Tx completion ring should be addressed in 1223175526Syongari * the same 4GB space. The same rule applys to Rx ring and Rx 1224175526Syongari * completion ring. Unfortunately there is no way to specify this 1225175526Syongari * boundary restriction with bus_dma(9). So just try to allocate 1226175526Syongari * without the restriction and check the restriction was satisfied. 1227175526Syongari * If not, fall back to 32bit dma addressing mode which always 1228175526Syongari * guarantees the restriction. 1229175526Syongari */ 1230175526Syongari tx_ring_end = sc->sf_rdata.sf_tx_ring_paddr + SF_TX_DLIST_SIZE; 1231175526Syongari tx_cring_end = sc->sf_rdata.sf_tx_cring_paddr + SF_TX_CLIST_SIZE; 1232175526Syongari rx_ring_end = sc->sf_rdata.sf_rx_ring_paddr + SF_RX_DLIST_SIZE; 1233175526Syongari rx_cring_end = sc->sf_rdata.sf_rx_cring_paddr + SF_RX_CLIST_SIZE; 1234175526Syongari if ((SF_ADDR_HI(sc->sf_rdata.sf_tx_ring_paddr) != 1235175526Syongari SF_ADDR_HI(tx_cring_end)) || 1236175526Syongari (SF_ADDR_HI(sc->sf_rdata.sf_tx_cring_paddr) != 1237175526Syongari SF_ADDR_HI(tx_ring_end)) || 1238175526Syongari (SF_ADDR_HI(sc->sf_rdata.sf_rx_ring_paddr) != 1239175526Syongari SF_ADDR_HI(rx_cring_end)) || 1240175526Syongari (SF_ADDR_HI(sc->sf_rdata.sf_rx_cring_paddr) != 1241175526Syongari SF_ADDR_HI(rx_ring_end))) { 1242175526Syongari device_printf(sc->sf_dev, 1243175526Syongari "switching to 32bit DMA mode\n"); 1244175526Syongari sf_dma_free(sc); 1245175526Syongari /* Limit DMA address space to 32bit and try again. */ 1246175526Syongari lowaddr = BUS_SPACE_MAXADDR_32BIT; 1247175526Syongari goto again; 1248175526Syongari } 1249175526Syongari 1250175526Syongari /* Create DMA maps for Tx buffers. */ 1251175526Syongari for (i = 0; i < SF_TX_DLIST_CNT; i++) { 1252175526Syongari txd = &sc->sf_cdata.sf_txdesc[i]; 1253175526Syongari txd->tx_m = NULL; 1254175526Syongari txd->ndesc = 0; 1255175526Syongari txd->tx_dmamap = NULL; 1256175526Syongari error = bus_dmamap_create(sc->sf_cdata.sf_tx_tag, 0, 1257175526Syongari &txd->tx_dmamap); 1258175526Syongari if (error != 0) { 1259175526Syongari device_printf(sc->sf_dev, 1260175526Syongari "failed to create Tx dmamap\n"); 1261175526Syongari goto fail; 1262175526Syongari } 1263175526Syongari } 1264175526Syongari /* Create DMA maps for Rx buffers. */ 1265175526Syongari if ((error = bus_dmamap_create(sc->sf_cdata.sf_rx_tag, 0, 1266175526Syongari &sc->sf_cdata.sf_rx_sparemap)) != 0) { 1267175526Syongari device_printf(sc->sf_dev, 1268175526Syongari "failed to create spare Rx dmamap\n"); 1269175526Syongari goto fail; 1270175526Syongari } 127149076Swpaul for (i = 0; i < SF_RX_DLIST_CNT; i++) { 1272175526Syongari rxd = &sc->sf_cdata.sf_rxdesc[i]; 1273175526Syongari rxd->rx_m = NULL; 1274175526Syongari rxd->rx_dmamap = NULL; 1275175526Syongari error = bus_dmamap_create(sc->sf_cdata.sf_rx_tag, 0, 1276175526Syongari &rxd->rx_dmamap); 1277175526Syongari if (error != 0) { 1278175526Syongari device_printf(sc->sf_dev, 1279175526Syongari "failed to create Rx dmamap\n"); 1280175526Syongari goto fail; 1281175526Syongari } 128249076Swpaul } 128349076Swpaul 1284175526Syongarifail: 1285175526Syongari return (error); 128649076Swpaul} 128749076Swpaul 1288102335Salfredstatic void 1289175526Syongarisf_dma_free(struct sf_softc *sc) 129049076Swpaul{ 1291175526Syongari struct sf_txdesc *txd; 1292175526Syongari struct sf_rxdesc *rxd; 129349076Swpaul int i; 129449076Swpaul 1295175526Syongari /* Tx ring. */ 1296175526Syongari if (sc->sf_cdata.sf_tx_ring_tag) { 1297267363Sjhb if (sc->sf_rdata.sf_tx_ring_paddr) 1298175526Syongari bus_dmamap_unload(sc->sf_cdata.sf_tx_ring_tag, 1299175526Syongari sc->sf_cdata.sf_tx_ring_map); 1300267363Sjhb if (sc->sf_rdata.sf_tx_ring) 1301175526Syongari bus_dmamem_free(sc->sf_cdata.sf_tx_ring_tag, 1302175526Syongari sc->sf_rdata.sf_tx_ring, 1303175526Syongari sc->sf_cdata.sf_tx_ring_map); 1304175526Syongari sc->sf_rdata.sf_tx_ring = NULL; 1305267363Sjhb sc->sf_rdata.sf_tx_ring_paddr = 0; 1306175526Syongari bus_dma_tag_destroy(sc->sf_cdata.sf_tx_ring_tag); 1307175526Syongari sc->sf_cdata.sf_tx_ring_tag = NULL; 1308175526Syongari } 1309175526Syongari /* Tx completion ring. */ 1310175526Syongari if (sc->sf_cdata.sf_tx_cring_tag) { 1311267363Sjhb if (sc->sf_rdata.sf_tx_cring_paddr) 1312175526Syongari bus_dmamap_unload(sc->sf_cdata.sf_tx_cring_tag, 1313175526Syongari sc->sf_cdata.sf_tx_cring_map); 1314267363Sjhb if (sc->sf_rdata.sf_tx_cring) 1315175526Syongari bus_dmamem_free(sc->sf_cdata.sf_tx_cring_tag, 1316175526Syongari sc->sf_rdata.sf_tx_cring, 1317175526Syongari sc->sf_cdata.sf_tx_cring_map); 1318175526Syongari sc->sf_rdata.sf_tx_cring = NULL; 1319267363Sjhb sc->sf_rdata.sf_tx_cring_paddr = 0; 1320175526Syongari bus_dma_tag_destroy(sc->sf_cdata.sf_tx_cring_tag); 1321175526Syongari sc->sf_cdata.sf_tx_cring_tag = NULL; 1322175526Syongari } 1323175526Syongari /* Rx ring. */ 1324175526Syongari if (sc->sf_cdata.sf_rx_ring_tag) { 1325267363Sjhb if (sc->sf_rdata.sf_rx_ring_paddr) 1326175526Syongari bus_dmamap_unload(sc->sf_cdata.sf_rx_ring_tag, 1327175526Syongari sc->sf_cdata.sf_rx_ring_map); 1328267363Sjhb if (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; 1333267363Sjhb sc->sf_rdata.sf_rx_ring_paddr = 0; 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) { 1339267363Sjhb if (sc->sf_rdata.sf_rx_cring_paddr) 1340175526Syongari bus_dmamap_unload(sc->sf_cdata.sf_rx_cring_tag, 1341175526Syongari sc->sf_cdata.sf_rx_cring_map); 1342267363Sjhb if (sc->sf_rdata.sf_rx_cring) 1343175526Syongari bus_dmamem_free(sc->sf_cdata.sf_rx_cring_tag, 1344175526Syongari sc->sf_rdata.sf_rx_cring, 1345175526Syongari sc->sf_cdata.sf_rx_cring_map); 1346175526Syongari sc->sf_rdata.sf_rx_cring = NULL; 1347267363Sjhb sc->sf_rdata.sf_rx_cring_paddr = 0; 1348175526Syongari bus_dma_tag_destroy(sc->sf_cdata.sf_rx_cring_tag); 1349175526Syongari sc->sf_cdata.sf_rx_cring_tag = NULL; 1350175526Syongari } 1351175526Syongari /* Tx buffers. */ 1352175526Syongari if (sc->sf_cdata.sf_tx_tag) { 1353175526Syongari for (i = 0; i < SF_TX_DLIST_CNT; i++) { 1354175526Syongari txd = &sc->sf_cdata.sf_txdesc[i]; 1355175526Syongari if (txd->tx_dmamap) { 1356175526Syongari bus_dmamap_destroy(sc->sf_cdata.sf_tx_tag, 1357175526Syongari txd->tx_dmamap); 1358175526Syongari txd->tx_dmamap = NULL; 1359175526Syongari } 1360175526Syongari } 1361175526Syongari bus_dma_tag_destroy(sc->sf_cdata.sf_tx_tag); 1362175526Syongari sc->sf_cdata.sf_tx_tag = NULL; 1363175526Syongari } 1364175526Syongari /* Rx buffers. */ 1365175526Syongari if (sc->sf_cdata.sf_rx_tag) { 1366175526Syongari for (i = 0; i < SF_RX_DLIST_CNT; i++) { 1367175526Syongari rxd = &sc->sf_cdata.sf_rxdesc[i]; 1368175526Syongari if (rxd->rx_dmamap) { 1369175526Syongari bus_dmamap_destroy(sc->sf_cdata.sf_rx_tag, 1370175526Syongari rxd->rx_dmamap); 1371175526Syongari rxd->rx_dmamap = NULL; 1372175526Syongari } 1373175526Syongari } 1374175526Syongari if (sc->sf_cdata.sf_rx_sparemap) { 1375175526Syongari bus_dmamap_destroy(sc->sf_cdata.sf_rx_tag, 1376175526Syongari sc->sf_cdata.sf_rx_sparemap); 1377175526Syongari sc->sf_cdata.sf_rx_sparemap = 0; 1378175526Syongari } 1379175526Syongari bus_dma_tag_destroy(sc->sf_cdata.sf_rx_tag); 1380175526Syongari sc->sf_cdata.sf_rx_tag = NULL; 1381175526Syongari } 138249076Swpaul 1383175526Syongari if (sc->sf_cdata.sf_parent_tag) { 1384175526Syongari bus_dma_tag_destroy(sc->sf_cdata.sf_parent_tag); 1385175526Syongari sc->sf_cdata.sf_parent_tag = NULL; 1386175526Syongari } 1387175526Syongari} 138849076Swpaul 1389175526Syongaristatic int 1390175526Syongarisf_init_rx_ring(struct sf_softc *sc) 1391175526Syongari{ 1392175526Syongari struct sf_ring_data *rd; 1393175526Syongari int i; 139449076Swpaul 1395175526Syongari sc->sf_cdata.sf_rxc_cons = 0; 1396175526Syongari 1397175526Syongari rd = &sc->sf_rdata; 1398175526Syongari bzero(rd->sf_rx_ring, SF_RX_DLIST_SIZE); 1399175526Syongari bzero(rd->sf_rx_cring, SF_RX_CLIST_SIZE); 1400175526Syongari 1401175526Syongari for (i = 0; i < SF_RX_DLIST_CNT; i++) { 1402175526Syongari if (sf_newbuf(sc, i) != 0) 1403175526Syongari return (ENOBUFS); 1404175526Syongari } 1405175526Syongari 1406175526Syongari bus_dmamap_sync(sc->sf_cdata.sf_rx_cring_tag, 1407175526Syongari sc->sf_cdata.sf_rx_cring_map, 1408175526Syongari BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 1409175526Syongari bus_dmamap_sync(sc->sf_cdata.sf_rx_ring_tag, 1410175526Syongari sc->sf_cdata.sf_rx_ring_map, 1411175526Syongari BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 1412175526Syongari 1413175526Syongari return (0); 141449076Swpaul} 141549076Swpaul 1416175526Syongaristatic void 1417175526Syongarisf_init_tx_ring(struct sf_softc *sc) 1418175526Syongari{ 1419175526Syongari struct sf_ring_data *rd; 1420175526Syongari int i; 1421175526Syongari 1422175526Syongari sc->sf_cdata.sf_tx_prod = 0; 1423175526Syongari sc->sf_cdata.sf_tx_cnt = 0; 1424175526Syongari sc->sf_cdata.sf_txc_cons = 0; 1425175526Syongari 1426175526Syongari rd = &sc->sf_rdata; 1427175526Syongari bzero(rd->sf_tx_ring, SF_TX_DLIST_SIZE); 1428175526Syongari bzero(rd->sf_tx_cring, SF_TX_CLIST_SIZE); 1429175526Syongari for (i = 0; i < SF_TX_DLIST_CNT; i++) { 1430175526Syongari rd->sf_tx_ring[i].sf_tx_ctrl = htole32(SF_TX_DESC_ID); 1431175526Syongari sc->sf_cdata.sf_txdesc[i].tx_m = NULL; 1432175526Syongari sc->sf_cdata.sf_txdesc[i].ndesc = 0; 1433175526Syongari } 1434175526Syongari rd->sf_tx_ring[i].sf_tx_ctrl |= htole32(SF_TX_DESC_END); 1435175526Syongari 1436175526Syongari bus_dmamap_sync(sc->sf_cdata.sf_tx_ring_tag, 1437175526Syongari sc->sf_cdata.sf_tx_ring_map, 1438175526Syongari BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 1439175526Syongari bus_dmamap_sync(sc->sf_cdata.sf_tx_cring_tag, 1440175526Syongari sc->sf_cdata.sf_tx_cring_map, 1441175526Syongari BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 1442175526Syongari} 1443175526Syongari 1444175526Syongari/* 1445175526Syongari * Initialize an RX descriptor and attach an MBUF cluster. 1446175526Syongari */ 1447102335Salfredstatic int 1448175526Syongarisf_newbuf(struct sf_softc *sc, int idx) 1449175526Syongari{ 1450175526Syongari struct sf_rx_rdesc *desc; 1451175526Syongari struct sf_rxdesc *rxd; 145249076Swpaul struct mbuf *m; 1453175526Syongari bus_dma_segment_t segs[1]; 1454175526Syongari bus_dmamap_t map; 1455175526Syongari int nsegs; 145649076Swpaul 1457243857Sglebius m = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR); 1458175526Syongari if (m == NULL) 1459175526Syongari return (ENOBUFS); 1460175526Syongari m->m_len = m->m_pkthdr.len = MCLBYTES; 1461175526Syongari m_adj(m, sizeof(uint32_t)); 146249076Swpaul 1463175526Syongari if (bus_dmamap_load_mbuf_sg(sc->sf_cdata.sf_rx_tag, 1464175526Syongari sc->sf_cdata.sf_rx_sparemap, m, segs, &nsegs, 0) != 0) { 1465175526Syongari m_freem(m); 1466175526Syongari return (ENOBUFS); 146749076Swpaul } 1468175526Syongari KASSERT(nsegs == 1, ("%s: %d segments returned!", __func__, nsegs)); 146949076Swpaul 1470175526Syongari rxd = &sc->sf_cdata.sf_rxdesc[idx]; 1471175526Syongari if (rxd->rx_m != NULL) { 1472175526Syongari bus_dmamap_sync(sc->sf_cdata.sf_rx_tag, rxd->rx_dmamap, 1473175526Syongari BUS_DMASYNC_POSTREAD); 1474175526Syongari bus_dmamap_unload(sc->sf_cdata.sf_rx_tag, rxd->rx_dmamap); 1475175526Syongari } 1476175526Syongari map = rxd->rx_dmamap; 1477175526Syongari rxd->rx_dmamap = sc->sf_cdata.sf_rx_sparemap; 1478175526Syongari sc->sf_cdata.sf_rx_sparemap = map; 1479175526Syongari bus_dmamap_sync(sc->sf_cdata.sf_rx_tag, rxd->rx_dmamap, 1480175526Syongari BUS_DMASYNC_PREREAD); 1481175526Syongari rxd->rx_m = m; 1482175526Syongari desc = &sc->sf_rdata.sf_rx_ring[idx]; 1483175526Syongari desc->sf_addr = htole64(segs[0].ds_addr); 148449076Swpaul 1485175526Syongari return (0); 1486175526Syongari} 148749076Swpaul 1488175526Syongari#ifndef __NO_STRICT_ALIGNMENT 1489175526Syongaristatic __inline void 1490175526Syongarisf_fixup_rx(struct mbuf *m) 1491175526Syongari{ 1492175526Syongari int i; 1493175526Syongari uint16_t *src, *dst; 1494175526Syongari 1495175526Syongari src = mtod(m, uint16_t *); 1496175526Syongari dst = src - 1; 1497175526Syongari 1498175526Syongari for (i = 0; i < (m->m_len / sizeof(uint16_t) + 1); i++) 1499175526Syongari *dst++ = *src++; 1500175526Syongari 1501175526Syongari m->m_data -= ETHER_ALIGN; 150249076Swpaul} 1503175526Syongari#endif 150449076Swpaul 150549076Swpaul/* 150649076Swpaul * The starfire is programmed to use 'normal' mode for packet reception, 150749076Swpaul * which means we use the consumer/producer model for both the buffer 150849076Swpaul * descriptor queue and the completion descriptor queue. The only problem 150949076Swpaul * with this is that it involves a lot of register accesses: we have to 151049076Swpaul * read the RX completion consumer and producer indexes and the RX buffer 151149076Swpaul * producer index, plus the RX completion consumer and RX buffer producer 151249076Swpaul * indexes have to be updated. It would have been easier if Adaptec had 151349076Swpaul * put each index in a separate register, especially given that the damn 151449076Swpaul * NIC has a 512K register space. 151549076Swpaul * 151649076Swpaul * In spite of all the lovely features that Adaptec crammed into the 6915, 151749076Swpaul * it is marred by one truly stupid design flaw, which is that receive 151849076Swpaul * buffer addresses must be aligned on a longword boundary. This forces 151949076Swpaul * the packet payload to be unaligned, which is suboptimal on the x86 and 1520298955Spfg * completely unusable on the Alpha. Our only recourse is to copy received 152149076Swpaul * packets into properly aligned buffers before handing them off. 152249076Swpaul */ 1523193096Sattiliostatic int 1524175526Syongarisf_rxeof(struct sf_softc *sc) 152549076Swpaul{ 152649076Swpaul struct mbuf *m; 152749076Swpaul struct ifnet *ifp; 1528175526Syongari struct sf_rxdesc *rxd; 1529175526Syongari struct sf_rx_rcdesc *cur_cmp; 1530193096Sattilio int cons, eidx, prog, rx_npkts; 1531175526Syongari uint32_t status, status2; 153249076Swpaul 1533122689Ssam SF_LOCK_ASSERT(sc); 1534122689Ssam 1535147256Sbrooks ifp = sc->sf_ifp; 1536193096Sattilio rx_npkts = 0; 153749076Swpaul 1538175526Syongari bus_dmamap_sync(sc->sf_cdata.sf_rx_ring_tag, 1539175526Syongari sc->sf_cdata.sf_rx_ring_map, 1540175526Syongari BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); 1541175526Syongari bus_dmamap_sync(sc->sf_cdata.sf_rx_cring_tag, 1542175526Syongari sc->sf_cdata.sf_rx_cring_map, 1543175526Syongari BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); 154449076Swpaul 1545175526Syongari /* 1546175526Syongari * To reduce register access, directly read Receive completion 1547175526Syongari * queue entry. 1548175526Syongari */ 1549175526Syongari eidx = 0; 1550175526Syongari prog = 0; 1551232040Syongari for (cons = sc->sf_cdata.sf_rxc_cons; 1552232040Syongari (ifp->if_drv_flags & IFF_DRV_RUNNING) != 0; 1553232040Syongari SF_INC(cons, SF_RX_CLIST_CNT)) { 1554175526Syongari cur_cmp = &sc->sf_rdata.sf_rx_cring[cons]; 1555175526Syongari status = le32toh(cur_cmp->sf_rx_status1); 1556175526Syongari if (status == 0) 1557175526Syongari break; 1558137557Sbrueffer#ifdef DEVICE_POLLING 1559175526Syongari if ((ifp->if_capenable & IFCAP_POLLING) != 0) { 1560137557Sbrueffer if (sc->rxcycles <= 0) 1561137557Sbrueffer break; 1562137557Sbrueffer sc->rxcycles--; 1563137557Sbrueffer } 1564150789Sglebius#endif 1565175526Syongari prog++; 1566175526Syongari eidx = (status & SF_RX_CMPDESC_EIDX) >> 16; 1567175526Syongari rxd = &sc->sf_cdata.sf_rxdesc[eidx]; 1568175526Syongari m = rxd->rx_m; 1569137557Sbrueffer 1570175526Syongari /* 1571271850Sglebius * Note, IFCOUNTER_IPACKETS and IFCOUNTER_IERRORS 1572175526Syongari * are handled in sf_stats_update(). 1573175526Syongari */ 1574175526Syongari if ((status & SF_RXSTAT1_OK) == 0) { 1575175526Syongari cur_cmp->sf_rx_status1 = 0; 157649076Swpaul continue; 157749076Swpaul } 157849076Swpaul 1579175526Syongari if (sf_newbuf(sc, eidx) != 0) { 1580271838Sglebius if_inc_counter(ifp, IFCOUNTER_IQDROPS, 1); 1581175526Syongari cur_cmp->sf_rx_status1 = 0; 158249076Swpaul continue; 158349076Swpaul } 158449076Swpaul 1585175526Syongari /* AIC-6915 supports TCP/UDP checksum offload. */ 1586175526Syongari if ((ifp->if_capenable & IFCAP_RXCSUM) != 0) { 1587175526Syongari status2 = le32toh(cur_cmp->sf_rx_status2); 1588175526Syongari /* 1589175526Syongari * Sometimes AIC-6915 generates an interrupt to 1590175526Syongari * warn RxGFP stall with bad checksum bit set 1591175526Syongari * in status word. I'm not sure what conditioan 1592175526Syongari * triggers it but recevied packet's checksum 1593175526Syongari * was correct even though AIC-6915 does not 1594175526Syongari * agree on this. This may be an indication of 1595175526Syongari * firmware bug. To fix the issue, do not rely 1596175526Syongari * on bad checksum bit in status word and let 1597175526Syongari * upper layer verify integrity of received 1598175526Syongari * frame. 1599175526Syongari * Another nice feature of AIC-6915 is hardware 1600175526Syongari * assistance of checksum calculation by 1601175526Syongari * providing partial checksum value for received 1602175526Syongari * frame. The partial checksum value can be used 1603175526Syongari * to accelerate checksum computation for 1604175526Syongari * fragmented TCP/UDP packets. Upper network 1605175526Syongari * stack already takes advantage of the partial 1606175526Syongari * checksum value in IP reassembly stage. But 1607175526Syongari * I'm not sure the correctness of the partial 1608175526Syongari * hardware checksum assistance as frequent 1609175526Syongari * RxGFP stalls are seen on non-fragmented 1610175526Syongari * frames. Due to the nature of the complexity 1611175526Syongari * of checksum computation code in firmware it's 1612175526Syongari * possible to see another bug in RxGFP so 1613175526Syongari * ignore checksum assistance for fragmented 1614175526Syongari * frames. This can be changed in future. 1615175526Syongari */ 1616175526Syongari if ((status2 & SF_RXSTAT2_FRAG) == 0) { 1617175526Syongari if ((status2 & (SF_RXSTAT2_TCP | 1618175526Syongari SF_RXSTAT2_UDP)) != 0) { 1619175526Syongari if ((status2 & SF_RXSTAT2_CSUM_OK)) { 1620175526Syongari m->m_pkthdr.csum_flags = 1621175526Syongari CSUM_DATA_VALID | 1622175526Syongari CSUM_PSEUDO_HDR; 1623175526Syongari m->m_pkthdr.csum_data = 0xffff; 1624175526Syongari } 1625175526Syongari } 1626175526Syongari } 1627175526Syongari#ifdef SF_PARTIAL_CSUM_SUPPORT 1628175526Syongari else if ((status2 & SF_RXSTAT2_FRAG) != 0) { 1629175526Syongari if ((status2 & (SF_RXSTAT2_TCP | 1630175526Syongari SF_RXSTAT2_UDP)) != 0) { 1631175526Syongari if ((status2 & SF_RXSTAT2_PCSUM_OK)) { 1632175526Syongari m->m_pkthdr.csum_flags = 1633175526Syongari CSUM_DATA_VALID; 1634175526Syongari m->m_pkthdr.csum_data = 1635175526Syongari (status & 1636175526Syongari SF_RX_CMPDESC_CSUM2); 1637175526Syongari } 1638175526Syongari } 1639175526Syongari } 1640175526Syongari#endif 1641175526Syongari } 1642175526Syongari 1643175526Syongari m->m_pkthdr.len = m->m_len = status & SF_RX_CMPDESC_LEN; 1644175526Syongari#ifndef __NO_STRICT_ALIGNMENT 1645175526Syongari sf_fixup_rx(m); 1646175526Syongari#endif 1647175526Syongari m->m_pkthdr.rcvif = ifp; 1648175526Syongari 1649122689Ssam SF_UNLOCK(sc); 1650106936Ssam (*ifp->if_input)(ifp, m); 1651122689Ssam SF_LOCK(sc); 1652193096Sattilio rx_npkts++; 1653175526Syongari 1654175526Syongari /* Clear completion status. */ 1655175526Syongari cur_cmp->sf_rx_status1 = 0; 165649076Swpaul } 165749076Swpaul 1658175526Syongari if (prog > 0) { 1659175526Syongari sc->sf_cdata.sf_rxc_cons = cons; 1660175526Syongari bus_dmamap_sync(sc->sf_cdata.sf_rx_ring_tag, 1661175526Syongari sc->sf_cdata.sf_rx_ring_map, 1662175526Syongari BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 1663175526Syongari bus_dmamap_sync(sc->sf_cdata.sf_rx_cring_tag, 1664175526Syongari sc->sf_cdata.sf_rx_cring_map, 1665175526Syongari BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 1666175526Syongari 1667175526Syongari /* Update Rx completion Q1 consumer index. */ 1668175526Syongari csr_write_4(sc, SF_CQ_CONSIDX, 1669175526Syongari (csr_read_4(sc, SF_CQ_CONSIDX) & ~SF_CQ_CONSIDX_RXQ1) | 1670175526Syongari (cons & SF_CQ_CONSIDX_RXQ1)); 1671175526Syongari /* Update Rx descriptor Q1 ptr. */ 1672175526Syongari csr_write_4(sc, SF_RXDQ_PTR_Q1, 1673175526Syongari (csr_read_4(sc, SF_RXDQ_PTR_Q1) & ~SF_RXDQ_PRODIDX) | 1674175526Syongari (eidx & SF_RXDQ_PRODIDX)); 1675175526Syongari } 1676193096Sattilio return (rx_npkts); 167749076Swpaul} 167849076Swpaul 167949076Swpaul/* 168049076Swpaul * Read the transmit status from the completion queue and release 168149076Swpaul * mbufs. Note that the buffer descriptor index in the completion 168249076Swpaul * descriptor is an offset from the start of the transmit buffer 168349076Swpaul * descriptor list in bytes. This is important because the manual 168449076Swpaul * gives the impression that it should match the producer/consumer 168549076Swpaul * index, which is the offset in 8 byte blocks. 168649076Swpaul */ 1687102335Salfredstatic void 1688175526Syongarisf_txeof(struct sf_softc *sc) 168949076Swpaul{ 1690175526Syongari struct sf_txdesc *txd; 1691175526Syongari struct sf_tx_rcdesc *cur_cmp; 169249076Swpaul struct ifnet *ifp; 1693175526Syongari uint32_t status; 1694175526Syongari int cons, idx, prod; 169549076Swpaul 1696175526Syongari SF_LOCK_ASSERT(sc); 1697175526Syongari 1698147256Sbrooks ifp = sc->sf_ifp; 169949076Swpaul 1700175526Syongari bus_dmamap_sync(sc->sf_cdata.sf_tx_cring_tag, 1701175526Syongari sc->sf_cdata.sf_tx_cring_map, 1702175526Syongari BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); 170349076Swpaul 1704175526Syongari cons = sc->sf_cdata.sf_txc_cons; 1705175526Syongari prod = (csr_read_4(sc, SF_CQ_PRODIDX) & SF_TXDQ_PRODIDX_HIPRIO) >> 16; 1706175526Syongari if (prod == cons) 1707175526Syongari return; 170849076Swpaul 1709175526Syongari for (; cons != prod; SF_INC(cons, SF_TX_CLIST_CNT)) { 1710175526Syongari cur_cmp = &sc->sf_rdata.sf_tx_cring[cons]; 1711175526Syongari status = le32toh(cur_cmp->sf_tx_status1); 1712175526Syongari if (status == 0) 1713175526Syongari break; 1714175526Syongari switch (status & SF_TX_CMPDESC_TYPE) { 1715175526Syongari case SF_TXCMPTYPE_TX: 1716175526Syongari /* Tx complete entry. */ 1717175526Syongari break; 1718175526Syongari case SF_TXCMPTYPE_DMA: 1719175526Syongari /* DMA complete entry. */ 1720175526Syongari idx = status & SF_TX_CMPDESC_IDX; 1721175526Syongari idx = idx / sizeof(struct sf_tx_rdesc); 1722175526Syongari /* 1723175526Syongari * We don't need to check Tx status here. 1724175526Syongari * SF_ISR_TX_LOFIFO intr would handle this. 1725271838Sglebius * Note, IFCOUNTER_OPACKETS, IFCOUNTER_COLLISIONS 1726271838Sglebius * and IFCOUNTER_OERROR are handled in 1727271838Sglebius * 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 2485271838Sglebius if_inc_counter(ifp, IFCOUNTER_OPACKETS, (u_long)stats->sf_tx_frames); 248649076Swpaul 2487271838Sglebius if_inc_counter(ifp, IFCOUNTER_COLLISIONS, 2488271838Sglebius (u_long)stats->sf_tx_single_colls + 2489271838Sglebius (u_long)stats->sf_tx_multi_colls); 249084147Sjlemon 2491271838Sglebius if_inc_counter(ifp, IFCOUNTER_OERRORS, 2492271838Sglebius (u_long)stats->sf_tx_excess_colls + 2493175526Syongari (u_long)stats->sf_tx_excess_defer + 2494271838Sglebius (u_long)stats->sf_tx_frames_lost); 249550675Swpaul 2496271838Sglebius if_inc_counter(ifp, IFCOUNTER_IPACKETS, (u_long)stats->sf_rx_frames); 2497175526Syongari 2498271838Sglebius if_inc_counter(ifp, IFCOUNTER_IERRORS, 2499271838Sglebius (u_long)stats->sf_rx_crcerrs + 2500175526Syongari (u_long)stats->sf_rx_alignerrs + 2501175526Syongari (u_long)stats->sf_rx_giants + 2502175526Syongari (u_long)stats->sf_rx_runts + 2503175526Syongari (u_long)stats->sf_rx_jabbererrs + 2504271838Sglebius (u_long)stats->sf_rx_frames_lost); 2505175526Syongari 2506175526Syongari nstats = &sc->sf_statistics; 2507175526Syongari 2508175526Syongari nstats->sf_tx_frames += stats->sf_tx_frames; 2509175526Syongari nstats->sf_tx_single_colls += stats->sf_tx_single_colls; 2510175526Syongari nstats->sf_tx_multi_colls += stats->sf_tx_multi_colls; 2511175526Syongari nstats->sf_tx_crcerrs += stats->sf_tx_crcerrs; 2512175526Syongari nstats->sf_tx_bytes += stats->sf_tx_bytes; 2513175526Syongari nstats->sf_tx_deferred += stats->sf_tx_deferred; 2514175526Syongari nstats->sf_tx_late_colls += stats->sf_tx_late_colls; 2515175526Syongari nstats->sf_tx_pause_frames += stats->sf_tx_pause_frames; 2516175526Syongari nstats->sf_tx_control_frames += stats->sf_tx_control_frames; 2517175526Syongari nstats->sf_tx_excess_colls += stats->sf_tx_excess_colls; 2518175526Syongari nstats->sf_tx_excess_defer += stats->sf_tx_excess_defer; 2519175526Syongari nstats->sf_tx_mcast_frames += stats->sf_tx_mcast_frames; 2520175526Syongari nstats->sf_tx_bcast_frames += stats->sf_tx_bcast_frames; 2521175526Syongari nstats->sf_tx_frames_lost += stats->sf_tx_frames_lost; 2522175526Syongari nstats->sf_rx_frames += stats->sf_rx_frames; 2523175526Syongari nstats->sf_rx_crcerrs += stats->sf_rx_crcerrs; 2524175526Syongari nstats->sf_rx_alignerrs += stats->sf_rx_alignerrs; 2525175526Syongari nstats->sf_rx_bytes += stats->sf_rx_bytes; 2526175526Syongari nstats->sf_rx_pause_frames += stats->sf_rx_pause_frames; 2527175526Syongari nstats->sf_rx_control_frames += stats->sf_rx_control_frames; 2528175526Syongari nstats->sf_rx_unsup_control_frames += stats->sf_rx_unsup_control_frames; 2529175526Syongari nstats->sf_rx_giants += stats->sf_rx_giants; 2530175526Syongari nstats->sf_rx_runts += stats->sf_rx_runts; 2531175526Syongari nstats->sf_rx_jabbererrs += stats->sf_rx_jabbererrs; 2532175526Syongari nstats->sf_rx_fragments += stats->sf_rx_fragments; 2533175526Syongari nstats->sf_rx_pkts_64 += stats->sf_rx_pkts_64; 2534175526Syongari nstats->sf_rx_pkts_65_127 += stats->sf_rx_pkts_65_127; 2535175526Syongari nstats->sf_rx_pkts_128_255 += stats->sf_rx_pkts_128_255; 2536175526Syongari nstats->sf_rx_pkts_256_511 += stats->sf_rx_pkts_256_511; 2537175526Syongari nstats->sf_rx_pkts_512_1023 += stats->sf_rx_pkts_512_1023; 2538175526Syongari nstats->sf_rx_pkts_1024_1518 += stats->sf_rx_pkts_1024_1518; 2539175526Syongari nstats->sf_rx_frames_lost += stats->sf_rx_frames_lost; 2540175526Syongari nstats->sf_tx_underruns += stats->sf_tx_underruns; 254149076Swpaul} 254249076Swpaul 2543102335Salfredstatic void 2544175526Syongarisf_watchdog(struct sf_softc *sc) 2545175526Syongari{ 254649076Swpaul struct ifnet *ifp; 254749076Swpaul 2548175526Syongari SF_LOCK_ASSERT(sc); 254949076Swpaul 2550175526Syongari if (sc->sf_watchdog_timer == 0 || --sc->sf_watchdog_timer) 2551175526Syongari return; 255267087Swpaul 2553175526Syongari ifp = sc->sf_ifp; 2554175526Syongari 2555271838Sglebius if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); 2556175526Syongari if (sc->sf_link == 0) { 2557175526Syongari if (bootverbose) 2558175526Syongari if_printf(sc->sf_ifp, "watchdog timeout " 2559175526Syongari "(missed link)\n"); 2560175526Syongari } else 2561175526Syongari if_printf(ifp, "watchdog timeout, %d Tx descs are active\n", 2562175526Syongari sc->sf_cdata.sf_tx_cnt); 256349076Swpaul 2564212971Syongari ifp->if_drv_flags &= ~IFF_DRV_RUNNING; 2565149240Sjhb sf_init_locked(sc); 256649076Swpaul 2567137620Sbrueffer if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) 2568149240Sjhb sf_start_locked(ifp); 2569175526Syongari} 257049076Swpaul 2571175526Syongaristatic int 2572175526Syongarisf_shutdown(device_t dev) 2573175526Syongari{ 2574175526Syongari struct sf_softc *sc; 2575175526Syongari 2576175526Syongari sc = device_get_softc(dev); 2577175526Syongari 2578175526Syongari SF_LOCK(sc); 2579175526Syongari sf_stop(sc); 258067087Swpaul SF_UNLOCK(sc); 2581175526Syongari 2582175526Syongari return (0); 258349076Swpaul} 258449076Swpaul 2585173839Syongaristatic int 2586175526Syongarisf_suspend(device_t dev) 258749076Swpaul{ 258849076Swpaul struct sf_softc *sc; 258949076Swpaul 259049076Swpaul sc = device_get_softc(dev); 259149076Swpaul 2592149240Sjhb SF_LOCK(sc); 259349076Swpaul sf_stop(sc); 2594175526Syongari sc->sf_suspended = 1; 2595175526Syongari bus_generic_suspend(dev); 2596149240Sjhb SF_UNLOCK(sc); 2597173839Syongari 2598173839Syongari return (0); 259949076Swpaul} 2600175526Syongari 2601175526Syongaristatic int 2602175526Syongarisf_resume(device_t dev) 2603175526Syongari{ 2604175526Syongari struct sf_softc *sc; 2605175526Syongari struct ifnet *ifp; 2606175526Syongari 2607175526Syongari sc = device_get_softc(dev); 2608175526Syongari 2609175526Syongari SF_LOCK(sc); 2610175526Syongari bus_generic_resume(dev); 2611175526Syongari ifp = sc->sf_ifp; 2612175526Syongari if ((ifp->if_flags & IFF_UP) != 0) 2613175526Syongari sf_init_locked(sc); 2614175526Syongari 2615175526Syongari sc->sf_suspended = 0; 2616175526Syongari SF_UNLOCK(sc); 2617175526Syongari 2618175526Syongari return (0); 2619175526Syongari} 2620175526Syongari 2621175526Syongaristatic int 2622175526Syongarisf_sysctl_stats(SYSCTL_HANDLER_ARGS) 2623175526Syongari{ 2624175526Syongari struct sf_softc *sc; 2625175526Syongari struct sf_stats *stats; 2626175526Syongari int error; 2627175526Syongari int result; 2628175526Syongari 2629175526Syongari result = -1; 2630175526Syongari error = sysctl_handle_int(oidp, &result, 0, req); 2631175526Syongari 2632175526Syongari if (error != 0 || req->newptr == NULL) 2633175526Syongari return (error); 2634175526Syongari 2635175526Syongari if (result != 1) 2636175526Syongari return (error); 2637175526Syongari 2638175526Syongari sc = (struct sf_softc *)arg1; 2639175526Syongari stats = &sc->sf_statistics; 2640175526Syongari 2641175526Syongari printf("%s statistics:\n", device_get_nameunit(sc->sf_dev)); 2642175526Syongari printf("Transmit good frames : %ju\n", 2643175526Syongari (uintmax_t)stats->sf_tx_frames); 2644175526Syongari printf("Transmit good octets : %ju\n", 2645175526Syongari (uintmax_t)stats->sf_tx_bytes); 2646175526Syongari printf("Transmit single collisions : %u\n", 2647175526Syongari stats->sf_tx_single_colls); 2648175526Syongari printf("Transmit multiple collisions : %u\n", 2649175526Syongari stats->sf_tx_multi_colls); 2650175526Syongari printf("Transmit late collisions : %u\n", 2651175526Syongari stats->sf_tx_late_colls); 2652175526Syongari printf("Transmit abort due to excessive collisions : %u\n", 2653175526Syongari stats->sf_tx_excess_colls); 2654175526Syongari printf("Transmit CRC errors : %u\n", 2655175526Syongari stats->sf_tx_crcerrs); 2656175526Syongari printf("Transmit deferrals : %u\n", 2657175526Syongari stats->sf_tx_deferred); 2658175526Syongari printf("Transmit abort due to excessive deferrals : %u\n", 2659175526Syongari stats->sf_tx_excess_defer); 2660175526Syongari printf("Transmit pause control frames : %u\n", 2661175526Syongari stats->sf_tx_pause_frames); 2662175526Syongari printf("Transmit control frames : %u\n", 2663175526Syongari stats->sf_tx_control_frames); 2664175526Syongari printf("Transmit good multicast frames : %u\n", 2665175526Syongari stats->sf_tx_mcast_frames); 2666175526Syongari printf("Transmit good broadcast frames : %u\n", 2667175526Syongari stats->sf_tx_bcast_frames); 2668175526Syongari printf("Transmit frames lost due to internal transmit errors : %u\n", 2669175526Syongari stats->sf_tx_frames_lost); 2670175526Syongari printf("Transmit FIFO underflows : %u\n", 2671175526Syongari stats->sf_tx_underruns); 2672175526Syongari printf("Transmit GFP stalls : %u\n", stats->sf_tx_gfp_stall); 2673175526Syongari printf("Receive good frames : %ju\n", 2674175526Syongari (uint64_t)stats->sf_rx_frames); 2675175526Syongari printf("Receive good octets : %ju\n", 2676175526Syongari (uint64_t)stats->sf_rx_bytes); 2677175526Syongari printf("Receive CRC errors : %u\n", 2678175526Syongari stats->sf_rx_crcerrs); 2679175526Syongari printf("Receive alignment errors : %u\n", 2680175526Syongari stats->sf_rx_alignerrs); 2681175526Syongari printf("Receive pause frames : %u\n", 2682175526Syongari stats->sf_rx_pause_frames); 2683175526Syongari printf("Receive control frames : %u\n", 2684175526Syongari stats->sf_rx_control_frames); 2685175526Syongari printf("Receive control frames with unsupported opcode : %u\n", 2686175526Syongari stats->sf_rx_unsup_control_frames); 2687175526Syongari printf("Receive frames too long : %u\n", 2688175526Syongari stats->sf_rx_giants); 2689175526Syongari printf("Receive frames too short : %u\n", 2690175526Syongari stats->sf_rx_runts); 2691175526Syongari printf("Receive frames jabber errors : %u\n", 2692175526Syongari stats->sf_rx_jabbererrs); 2693175526Syongari printf("Receive frames fragments : %u\n", 2694175526Syongari stats->sf_rx_fragments); 2695175526Syongari printf("Receive packets 64 bytes : %ju\n", 2696175526Syongari (uint64_t)stats->sf_rx_pkts_64); 2697175526Syongari printf("Receive packets 65 to 127 bytes : %ju\n", 2698175526Syongari (uint64_t)stats->sf_rx_pkts_65_127); 2699175526Syongari printf("Receive packets 128 to 255 bytes : %ju\n", 2700175526Syongari (uint64_t)stats->sf_rx_pkts_128_255); 2701175526Syongari printf("Receive packets 256 to 511 bytes : %ju\n", 2702175526Syongari (uint64_t)stats->sf_rx_pkts_256_511); 2703175526Syongari printf("Receive packets 512 to 1023 bytes : %ju\n", 2704175526Syongari (uint64_t)stats->sf_rx_pkts_512_1023); 2705175526Syongari printf("Receive packets 1024 to 1518 bytes : %ju\n", 2706175526Syongari (uint64_t)stats->sf_rx_pkts_1024_1518); 2707175526Syongari printf("Receive frames lost due to internal receive errors : %u\n", 2708175526Syongari stats->sf_rx_frames_lost); 2709175526Syongari printf("Receive GFP stalls : %u\n", stats->sf_rx_gfp_stall); 2710175526Syongari 2711175526Syongari return (error); 2712175526Syongari} 2713175526Syongari 2714175526Syongaristatic int 2715175526Syongarisysctl_int_range(SYSCTL_HANDLER_ARGS, int low, int high) 2716175526Syongari{ 2717175526Syongari int error, value; 2718175526Syongari 2719175526Syongari if (!arg1) 2720175526Syongari return (EINVAL); 2721175526Syongari value = *(int *)arg1; 2722175526Syongari error = sysctl_handle_int(oidp, &value, 0, req); 2723175526Syongari if (error || !req->newptr) 2724175526Syongari return (error); 2725175526Syongari if (value < low || value > high) 2726175526Syongari return (EINVAL); 2727175526Syongari *(int *)arg1 = value; 2728175526Syongari 2729175526Syongari return (0); 2730175526Syongari} 2731175526Syongari 2732175526Syongaristatic int 2733175526Syongarisysctl_hw_sf_int_mod(SYSCTL_HANDLER_ARGS) 2734175526Syongari{ 2735175526Syongari 2736175526Syongari return (sysctl_int_range(oidp, arg1, arg2, req, SF_IM_MIN, SF_IM_MAX)); 2737175526Syongari} 2738