1139825Simp/*- 250128Swpaul * Copyright (c) 1997, 1998, 1999 350128Swpaul * Bill Paul <wpaul@ctr.columbia.edu>. All rights reserved. 450128Swpaul * 550128Swpaul * Redistribution and use in source and binary forms, with or without 650128Swpaul * modification, are permitted provided that the following conditions 750128Swpaul * are met: 850128Swpaul * 1. Redistributions of source code must retain the above copyright 950128Swpaul * notice, this list of conditions and the following disclaimer. 1050128Swpaul * 2. Redistributions in binary form must reproduce the above copyright 1150128Swpaul * notice, this list of conditions and the following disclaimer in the 1250128Swpaul * documentation and/or other materials provided with the distribution. 1350128Swpaul * 3. All advertising materials mentioning features or use of this software 1450128Swpaul * must display the following acknowledgement: 1550128Swpaul * This product includes software developed by Bill Paul. 1650128Swpaul * 4. Neither the name of the author nor the names of any co-contributors 1750128Swpaul * may be used to endorse or promote products derived from this software 1850128Swpaul * without specific prior written permission. 1950128Swpaul * 2050128Swpaul * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND 2150128Swpaul * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2250128Swpaul * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2350128Swpaul * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD 2450128Swpaul * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 2550128Swpaul * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 2650128Swpaul * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 2750128Swpaul * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 2850128Swpaul * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 2950128Swpaul * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 3050128Swpaul * THE POSSIBILITY OF SUCH DAMAGE. 3150128Swpaul */ 3250128Swpaul 33113038Sobrien#include <sys/cdefs.h> 34113038Sobrien__FBSDID("$FreeBSD: releng/10.3/sys/dev/ste/if_ste.c 243857 2012-12-04 09:32:43Z glebius $"); 35113038Sobrien 36150968Sglebius#ifdef HAVE_KERNEL_OPTION_HEADERS 37150968Sglebius#include "opt_device_polling.h" 38150968Sglebius#endif 39150968Sglebius 4050128Swpaul#include <sys/param.h> 4150128Swpaul#include <sys/systm.h> 42200853Syongari#include <sys/bus.h> 43200853Syongari#include <sys/endian.h> 44200853Syongari#include <sys/kernel.h> 45200853Syongari#include <sys/lock.h> 46200853Syongari#include <sys/malloc.h> 4750128Swpaul#include <sys/mbuf.h> 48129878Sphk#include <sys/module.h> 49200853Syongari#include <sys/rman.h> 5050128Swpaul#include <sys/socket.h> 51200853Syongari#include <sys/sockio.h> 52127688Sru#include <sys/sysctl.h> 5350128Swpaul 54200853Syongari#include <net/bpf.h> 5550128Swpaul#include <net/if.h> 5650128Swpaul#include <net/if_arp.h> 5750128Swpaul#include <net/ethernet.h> 5850128Swpaul#include <net/if_dl.h> 5950128Swpaul#include <net/if_media.h> 60147256Sbrooks#include <net/if_types.h> 61101493Sambrisko#include <net/if_vlan_var.h> 6250128Swpaul 6350128Swpaul#include <machine/bus.h> 6450128Swpaul#include <machine/resource.h> 6550128Swpaul 6650128Swpaul#include <dev/mii/mii.h> 67226995Smarius#include <dev/mii/mii_bitbang.h> 6850128Swpaul#include <dev/mii/miivar.h> 6950128Swpaul 70119288Simp#include <dev/pci/pcireg.h> 71119288Simp#include <dev/pci/pcivar.h> 7250128Swpaul 73200853Syongari#include <dev/ste/if_stereg.h> 74200853Syongari 75151545Simp/* "device miibus" required. See GENERIC if you get errors here. */ 7650128Swpaul#include "miibus_if.h" 7750128Swpaul 78113506SmdoddMODULE_DEPEND(ste, pci, 1, 1, 1); 79113506SmdoddMODULE_DEPEND(ste, ether, 1, 1, 1); 8059758SpeterMODULE_DEPEND(ste, miibus, 1, 1, 1); 8159758Speter 82200884Syongari/* Define to show Tx error status. */ 83200884Syongari#define STE_SHOW_TXERRORS 84200884Syongari 8550128Swpaul/* 8650128Swpaul * Various supported device vendors/types and their names. 8750128Swpaul */ 88242625Sdimstatic const struct ste_type ste_devs[] = { 89167407Syongari { ST_VENDORID, ST_DEVICEID_ST201_1, "Sundance ST201 10/100BaseTX" }, 90167407Syongari { ST_VENDORID, ST_DEVICEID_ST201_2, "Sundance ST201 10/100BaseTX" }, 91108237Sphk { DL_VENDORID, DL_DEVICEID_DL10050, "D-Link DL10050 10/100BaseTX" }, 9250128Swpaul { 0, 0, NULL } 9350128Swpaul}; 9450128Swpaul 95200810Syongaristatic int ste_attach(device_t); 96200810Syongaristatic int ste_detach(device_t); 97200810Syongaristatic int ste_probe(device_t); 98200955Syongaristatic int ste_resume(device_t); 99200810Syongaristatic int ste_shutdown(device_t); 100200955Syongaristatic int ste_suspend(device_t); 10150128Swpaul 102200853Syongaristatic int ste_dma_alloc(struct ste_softc *); 103200853Syongaristatic void ste_dma_free(struct ste_softc *); 104200853Syongaristatic void ste_dmamap_cb(void *, bus_dma_segment_t *, int, int); 105200810Syongaristatic int ste_eeprom_wait(struct ste_softc *); 106200853Syongaristatic int ste_encap(struct ste_softc *, struct mbuf **, 107200853Syongari struct ste_chain *); 108200810Syongaristatic int ste_ifmedia_upd(struct ifnet *); 109200810Syongaristatic void ste_ifmedia_sts(struct ifnet *, struct ifmediareq *); 110200810Syongaristatic void ste_init(void *); 111200810Syongaristatic void ste_init_locked(struct ste_softc *); 112200810Syongaristatic int ste_init_rx_list(struct ste_softc *); 113200810Syongaristatic void ste_init_tx_list(struct ste_softc *); 114200810Syongaristatic void ste_intr(void *); 115200810Syongaristatic int ste_ioctl(struct ifnet *, u_long, caddr_t); 116226995Smariusstatic uint32_t ste_mii_bitbang_read(device_t); 117226995Smariusstatic void ste_mii_bitbang_write(device_t, uint32_t); 118200810Syongaristatic int ste_miibus_readreg(device_t, int, int); 119200810Syongaristatic void ste_miibus_statchg(device_t); 120200810Syongaristatic int ste_miibus_writereg(device_t, int, int, int); 121200853Syongaristatic int ste_newbuf(struct ste_softc *, struct ste_chain_onefrag *); 122201767Syongaristatic int ste_read_eeprom(struct ste_softc *, uint16_t *, int, int); 123200810Syongaristatic void ste_reset(struct ste_softc *); 124200884Syongaristatic void ste_restart_tx(struct ste_softc *); 125200853Syongaristatic int ste_rxeof(struct ste_softc *, int); 126200906Syongaristatic void ste_rxfilter(struct ste_softc *); 127200955Syongaristatic void ste_setwol(struct ste_softc *); 128200810Syongaristatic void ste_start(struct ifnet *); 129200810Syongaristatic void ste_start_locked(struct ifnet *); 130200910Syongaristatic void ste_stats_clear(struct ste_softc *); 131200865Syongaristatic void ste_stats_update(struct ste_softc *); 132200810Syongaristatic void ste_stop(struct ste_softc *); 133200910Syongaristatic void ste_sysctl_node(struct ste_softc *); 134200865Syongaristatic void ste_tick(void *); 135200810Syongaristatic void ste_txeoc(struct ste_softc *); 136200810Syongaristatic void ste_txeof(struct ste_softc *); 137200810Syongaristatic void ste_wait(struct ste_softc *); 138200810Syongaristatic void ste_watchdog(struct ste_softc *); 13950128Swpaul 140226995Smarius/* 141226995Smarius * MII bit-bang glue 142226995Smarius */ 143226995Smariusstatic const struct mii_bitbang_ops ste_mii_bitbang_ops = { 144226995Smarius ste_mii_bitbang_read, 145226995Smarius ste_mii_bitbang_write, 146226995Smarius { 147226995Smarius STE_PHYCTL_MDATA, /* MII_BIT_MDO */ 148226995Smarius STE_PHYCTL_MDATA, /* MII_BIT_MDI */ 149226995Smarius STE_PHYCTL_MCLK, /* MII_BIT_MDC */ 150226995Smarius STE_PHYCTL_MDIR, /* MII_BIT_DIR_HOST_PHY */ 151226995Smarius 0, /* MII_BIT_DIR_PHY_HOST */ 152226995Smarius } 153226995Smarius}; 154226995Smarius 15550128Swpaulstatic device_method_t ste_methods[] = { 15650128Swpaul /* Device interface */ 15750128Swpaul DEVMETHOD(device_probe, ste_probe), 15850128Swpaul DEVMETHOD(device_attach, ste_attach), 15950128Swpaul DEVMETHOD(device_detach, ste_detach), 16050128Swpaul DEVMETHOD(device_shutdown, ste_shutdown), 161200955Syongari DEVMETHOD(device_suspend, ste_suspend), 162200955Syongari DEVMETHOD(device_resume, ste_resume), 16350128Swpaul 16450128Swpaul /* MII interface */ 16550128Swpaul DEVMETHOD(miibus_readreg, ste_miibus_readreg), 16650128Swpaul DEVMETHOD(miibus_writereg, ste_miibus_writereg), 16750128Swpaul DEVMETHOD(miibus_statchg, ste_miibus_statchg), 16850128Swpaul 169227843Smarius DEVMETHOD_END 17050128Swpaul}; 17150128Swpaul 17250128Swpaulstatic driver_t ste_driver = { 17351455Swpaul "ste", 17450128Swpaul ste_methods, 17550128Swpaul sizeof(struct ste_softc) 17650128Swpaul}; 17750128Swpaul 17850128Swpaulstatic devclass_t ste_devclass; 17950128Swpaul 180113506SmdoddDRIVER_MODULE(ste, pci, ste_driver, ste_devclass, 0, 0); 18151473SwpaulDRIVER_MODULE(miibus, ste, miibus_driver, miibus_devclass, 0, 0); 18250128Swpaul 18350128Swpaul#define STE_SETBIT4(sc, reg, x) \ 184106696Salfred CSR_WRITE_4(sc, reg, CSR_READ_4(sc, reg) | (x)) 18550128Swpaul 18650128Swpaul#define STE_CLRBIT4(sc, reg, x) \ 187106696Salfred CSR_WRITE_4(sc, reg, CSR_READ_4(sc, reg) & ~(x)) 18850128Swpaul 18950128Swpaul#define STE_SETBIT2(sc, reg, x) \ 190106696Salfred CSR_WRITE_2(sc, reg, CSR_READ_2(sc, reg) | (x)) 19150128Swpaul 19250128Swpaul#define STE_CLRBIT2(sc, reg, x) \ 193106696Salfred CSR_WRITE_2(sc, reg, CSR_READ_2(sc, reg) & ~(x)) 19450128Swpaul 19550128Swpaul#define STE_SETBIT1(sc, reg, x) \ 196106696Salfred CSR_WRITE_1(sc, reg, CSR_READ_1(sc, reg) | (x)) 19750128Swpaul 19850128Swpaul#define STE_CLRBIT1(sc, reg, x) \ 199106696Salfred CSR_WRITE_1(sc, reg, CSR_READ_1(sc, reg) & ~(x)) 20050128Swpaul 20150128Swpaul/* 202226995Smarius * Read the MII serial port for the MII bit-bang module. 20350128Swpaul */ 204226995Smariusstatic uint32_t 205226995Smariusste_mii_bitbang_read(device_t dev) 20650128Swpaul{ 207226995Smarius struct ste_softc *sc; 208226995Smarius uint32_t val; 20950128Swpaul 210226995Smarius sc = device_get_softc(dev); 21150128Swpaul 212226995Smarius val = CSR_READ_1(sc, STE_PHYCTL); 213226995Smarius CSR_BARRIER(sc, STE_PHYCTL, 1, 214226995Smarius BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE); 215226995Smarius 216226995Smarius return (val); 21750128Swpaul} 21850128Swpaul 21950128Swpaul/* 220226995Smarius * Write the MII serial port for the MII bit-bang module. 22150128Swpaul */ 222102335Salfredstatic void 223226995Smariusste_mii_bitbang_write(device_t dev, uint32_t val) 22450128Swpaul{ 225226995Smarius struct ste_softc *sc; 22650128Swpaul 227226995Smarius sc = device_get_softc(dev); 22850128Swpaul 229226995Smarius CSR_WRITE_1(sc, STE_PHYCTL, val); 230226995Smarius CSR_BARRIER(sc, STE_PHYCTL, 1, 231226995Smarius BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE); 23250128Swpaul} 23350128Swpaul 234102335Salfredstatic int 235200798Syongariste_miibus_readreg(device_t dev, int phy, int reg) 23650128Swpaul{ 23750128Swpaul 238226995Smarius return (mii_bitbang_readreg(dev, &ste_mii_bitbang_ops, phy, reg)); 23950128Swpaul} 24050128Swpaul 241102335Salfredstatic int 242200798Syongariste_miibus_writereg(device_t dev, int phy, int reg, int data) 24350128Swpaul{ 24450128Swpaul 245226995Smarius mii_bitbang_writereg(dev, &ste_mii_bitbang_ops, phy, reg, data); 24650128Swpaul 247200808Syongari return (0); 24850128Swpaul} 24950128Swpaul 250102335Salfredstatic void 251200798Syongariste_miibus_statchg(device_t dev) 25250128Swpaul{ 253200808Syongari struct ste_softc *sc; 254200808Syongari struct mii_data *mii; 255200865Syongari struct ifnet *ifp; 256200865Syongari uint16_t cfg; 25750128Swpaul 25850128Swpaul sc = device_get_softc(dev); 259149646Sjhb 26050128Swpaul mii = device_get_softc(sc->ste_miibus); 261200865Syongari ifp = sc->ste_ifp; 262200865Syongari if (mii == NULL || ifp == NULL || 263200865Syongari (ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) 264200865Syongari return; 26550128Swpaul 266200865Syongari sc->ste_flags &= ~STE_FLAG_LINK; 267200865Syongari if ((mii->mii_media_status & (IFM_ACTIVE | IFM_AVALID)) == 268200865Syongari (IFM_ACTIVE | IFM_AVALID)) { 269200865Syongari switch (IFM_SUBTYPE(mii->mii_media_active)) { 270200865Syongari case IFM_10_T: 271200865Syongari case IFM_100_TX: 272200865Syongari case IFM_100_FX: 273200865Syongari case IFM_100_T4: 274200865Syongari sc->ste_flags |= STE_FLAG_LINK; 275200865Syongari default: 276200865Syongari break; 277200865Syongari } 27850128Swpaul } 279200865Syongari 280200865Syongari /* Program MACs with resolved speed/duplex/flow-control. */ 281200865Syongari if ((sc->ste_flags & STE_FLAG_LINK) != 0) { 282200865Syongari cfg = CSR_READ_2(sc, STE_MACCTL0); 283200865Syongari cfg &= ~(STE_MACCTL0_FLOWCTL_ENABLE | STE_MACCTL0_FULLDUPLEX); 284200865Syongari if ((IFM_OPTIONS(mii->mii_media_active) & IFM_FDX) != 0) { 285200865Syongari /* 286200865Syongari * ST201 data sheet says driver should enable receiving 287200865Syongari * MAC control frames bit of receive mode register to 288200865Syongari * receive flow-control frames but the register has no 289200865Syongari * such bits. In addition the controller has no ability 290200865Syongari * to send pause frames so it should be handled in 291200865Syongari * driver. Implementing pause timer handling in driver 292200865Syongari * layer is not trivial, so don't enable flow-control 293200865Syongari * here. 294200865Syongari */ 295200865Syongari cfg |= STE_MACCTL0_FULLDUPLEX; 296200865Syongari } 297200865Syongari CSR_WRITE_2(sc, STE_MACCTL0, cfg); 298200865Syongari } 29950128Swpaul} 300200804Syongari 301102335Salfredstatic int 302200798Syongariste_ifmedia_upd(struct ifnet *ifp) 30350128Swpaul{ 304200808Syongari struct ste_softc *sc; 305200908Syongari struct mii_data *mii; 306200908Syongari struct mii_softc *miisc; 307200908Syongari int error; 308149646Sjhb 309149646Sjhb sc = ifp->if_softc; 310149646Sjhb STE_LOCK(sc); 31150128Swpaul mii = device_get_softc(sc->ste_miibus); 312221407Smarius LIST_FOREACH(miisc, &mii->mii_phys, mii_list) 313221407Smarius PHY_RESET(miisc); 314200908Syongari error = mii_mediachg(mii); 315200908Syongari STE_UNLOCK(sc); 316200908Syongari 317200908Syongari return (error); 31850128Swpaul} 31950128Swpaul 320102335Salfredstatic void 321200798Syongariste_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr) 32250128Swpaul{ 323200808Syongari struct ste_softc *sc; 324200808Syongari struct mii_data *mii; 32550128Swpaul 32650128Swpaul sc = ifp->if_softc; 32750128Swpaul mii = device_get_softc(sc->ste_miibus); 32850128Swpaul 329149646Sjhb STE_LOCK(sc); 330200907Syongari if ((ifp->if_flags & IFF_UP) == 0) { 331200907Syongari STE_UNLOCK(sc); 332200907Syongari return; 333200907Syongari } 33450128Swpaul mii_pollstat(mii); 33550128Swpaul ifmr->ifm_active = mii->mii_media_active; 33650128Swpaul ifmr->ifm_status = mii->mii_media_status; 337149646Sjhb STE_UNLOCK(sc); 33850128Swpaul} 33950128Swpaul 340102335Salfredstatic void 341200798Syongariste_wait(struct ste_softc *sc) 34250128Swpaul{ 343200808Syongari int i; 34450128Swpaul 34550128Swpaul for (i = 0; i < STE_TIMEOUT; i++) { 34650128Swpaul if (!(CSR_READ_4(sc, STE_DMACTL) & STE_DMACTL_DMA_HALTINPROG)) 34750128Swpaul break; 348200854Syongari DELAY(1); 34950128Swpaul } 35050128Swpaul 35150128Swpaul if (i == STE_TIMEOUT) 352162315Sglebius device_printf(sc->ste_dev, "command never completed!\n"); 35350128Swpaul} 35450128Swpaul 35550128Swpaul/* 35650128Swpaul * The EEPROM is slow: give it time to come ready after issuing 35750128Swpaul * it a command. 35850128Swpaul */ 359102335Salfredstatic int 360200798Syongariste_eeprom_wait(struct ste_softc *sc) 36150128Swpaul{ 362200808Syongari int i; 36350128Swpaul 36450128Swpaul DELAY(1000); 36550128Swpaul 36650128Swpaul for (i = 0; i < 100; i++) { 36750128Swpaul if (CSR_READ_2(sc, STE_EEPROM_CTL) & STE_EECTL_BUSY) 36850128Swpaul DELAY(1000); 36950128Swpaul else 37050128Swpaul break; 37150128Swpaul } 37250128Swpaul 37350128Swpaul if (i == 100) { 374162315Sglebius device_printf(sc->ste_dev, "eeprom failed to come ready\n"); 375200808Syongari return (1); 37650128Swpaul } 37750128Swpaul 378200808Syongari return (0); 37950128Swpaul} 38050128Swpaul 38150128Swpaul/* 38250128Swpaul * Read a sequence of words from the EEPROM. Note that ethernet address 38350128Swpaul * data is stored in the EEPROM in network byte order. 38450128Swpaul */ 385102335Salfredstatic int 386201767Syongariste_read_eeprom(struct ste_softc *sc, uint16_t *dest, int off, int cnt) 38750128Swpaul{ 388200808Syongari int err = 0, i; 38950128Swpaul 39050128Swpaul if (ste_eeprom_wait(sc)) 391200808Syongari return (1); 39250128Swpaul 39350128Swpaul for (i = 0; i < cnt; i++) { 39450128Swpaul CSR_WRITE_2(sc, STE_EEPROM_CTL, STE_EEOPCODE_READ | (off + i)); 39550128Swpaul err = ste_eeprom_wait(sc); 39650128Swpaul if (err) 39750128Swpaul break; 398201767Syongari *dest = le16toh(CSR_READ_2(sc, STE_EEPROM_DATA)); 399201767Syongari dest++; 40050128Swpaul } 40150128Swpaul 402200808Syongari return (err ? 1 : 0); 40350128Swpaul} 40450128Swpaul 405102335Salfredstatic void 406200906Syongariste_rxfilter(struct ste_softc *sc) 40750128Swpaul{ 408200808Syongari struct ifnet *ifp; 409200808Syongari struct ifmultiaddr *ifma; 410200808Syongari uint32_t hashes[2] = { 0, 0 }; 411200906Syongari uint8_t rxcfg; 412200808Syongari int h; 41350128Swpaul 414200906Syongari STE_LOCK_ASSERT(sc); 415200906Syongari 416147256Sbrooks ifp = sc->ste_ifp; 417200906Syongari rxcfg = CSR_READ_1(sc, STE_RX_MODE); 418200906Syongari rxcfg |= STE_RXMODE_UNICAST; 419200906Syongari rxcfg &= ~(STE_RXMODE_ALLMULTI | STE_RXMODE_MULTIHASH | 420200906Syongari STE_RXMODE_BROADCAST | STE_RXMODE_PROMISC); 421200906Syongari if (ifp->if_flags & IFF_BROADCAST) 422200906Syongari rxcfg |= STE_RXMODE_BROADCAST; 423200906Syongari if ((ifp->if_flags & (IFF_ALLMULTI | IFF_PROMISC)) != 0) { 424200906Syongari if ((ifp->if_flags & IFF_ALLMULTI) != 0) 425200906Syongari rxcfg |= STE_RXMODE_ALLMULTI; 426200906Syongari if ((ifp->if_flags & IFF_PROMISC) != 0) 427200906Syongari rxcfg |= STE_RXMODE_PROMISC; 428200906Syongari goto chipit; 42950128Swpaul } 43050128Swpaul 431200906Syongari rxcfg |= STE_RXMODE_MULTIHASH; 432200906Syongari /* Now program new ones. */ 433195049Srwatson if_maddr_rlock(ifp); 43472084Sphk TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { 43550128Swpaul if (ifma->ifma_addr->sa_family != AF_LINK) 43650128Swpaul continue; 437130270Snaddy h = ether_crc32_be(LLADDR((struct sockaddr_dl *) 438130270Snaddy ifma->ifma_addr), ETHER_ADDR_LEN) & 0x3F; 43950128Swpaul if (h < 32) 44050128Swpaul hashes[0] |= (1 << h); 44150128Swpaul else 44250128Swpaul hashes[1] |= (1 << (h - 32)); 44350128Swpaul } 444195049Srwatson if_maddr_runlock(ifp); 44550128Swpaul 446200906Syongarichipit: 44782214Swpaul CSR_WRITE_2(sc, STE_MAR0, hashes[0] & 0xFFFF); 44882214Swpaul CSR_WRITE_2(sc, STE_MAR1, (hashes[0] >> 16) & 0xFFFF); 44982214Swpaul CSR_WRITE_2(sc, STE_MAR2, hashes[1] & 0xFFFF); 45082214Swpaul CSR_WRITE_2(sc, STE_MAR3, (hashes[1] >> 16) & 0xFFFF); 451200906Syongari CSR_WRITE_1(sc, STE_RX_MODE, rxcfg); 452200906Syongari CSR_READ_1(sc, STE_RX_MODE); 45350128Swpaul} 45450128Swpaul 455127686Sru#ifdef DEVICE_POLLING 456149646Sjhbstatic poll_handler_t ste_poll, ste_poll_locked; 457127686Sru 458193096Sattiliostatic int 459127686Sruste_poll(struct ifnet *ifp, enum poll_cmd cmd, int count) 460127686Sru{ 461127686Sru struct ste_softc *sc = ifp->if_softc; 462193096Sattilio int rx_npkts = 0; 463127686Sru 464127686Sru STE_LOCK(sc); 465150789Sglebius if (ifp->if_drv_flags & IFF_DRV_RUNNING) 466193096Sattilio rx_npkts = ste_poll_locked(ifp, cmd, count); 467149646Sjhb STE_UNLOCK(sc); 468193096Sattilio return (rx_npkts); 469149646Sjhb} 470149646Sjhb 471193096Sattiliostatic int 472149646Sjhbste_poll_locked(struct ifnet *ifp, enum poll_cmd cmd, int count) 473149646Sjhb{ 474149646Sjhb struct ste_softc *sc = ifp->if_softc; 475193096Sattilio int rx_npkts; 476149646Sjhb 477149646Sjhb STE_LOCK_ASSERT(sc); 478127686Sru 479200853Syongari rx_npkts = ste_rxeof(sc, count); 480127686Sru ste_txeof(sc); 481200884Syongari ste_txeoc(sc); 482147828Smlaier if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) 483149646Sjhb ste_start_locked(ifp); 484127686Sru 485127937Sru if (cmd == POLL_AND_CHECK_STATUS) { 486200803Syongari uint16_t status; 487127686Sru 488127686Sru status = CSR_READ_2(sc, STE_ISR_ACK); 489127686Sru 490200865Syongari if (status & STE_ISR_STATS_OFLOW) 491127686Sru ste_stats_update(sc); 492127686Sru 493200904Syongari if (status & STE_ISR_HOSTERR) { 494200904Syongari ifp->if_drv_flags &= ~IFF_DRV_RUNNING; 495149646Sjhb ste_init_locked(sc); 496200904Syongari } 497127686Sru } 498193096Sattilio return (rx_npkts); 499127686Sru} 500127686Sru#endif /* DEVICE_POLLING */ 501127686Sru 502127686Srustatic void 503200798Syongariste_intr(void *xsc) 50450128Swpaul{ 505200808Syongari struct ste_softc *sc; 506200808Syongari struct ifnet *ifp; 507200950Syongari uint16_t intrs, status; 50850128Swpaul 50950128Swpaul sc = xsc; 51067089Swpaul STE_LOCK(sc); 511147256Sbrooks ifp = sc->ste_ifp; 51250128Swpaul 513127686Sru#ifdef DEVICE_POLLING 514150789Sglebius if (ifp->if_capenable & IFCAP_POLLING) { 515150789Sglebius STE_UNLOCK(sc); 516150789Sglebius return; 517127686Sru } 518150789Sglebius#endif 519200950Syongari /* Reading STE_ISR_ACK clears STE_IMR register. */ 520200950Syongari status = CSR_READ_2(sc, STE_ISR_ACK); 521200950Syongari if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) { 52267089Swpaul STE_UNLOCK(sc); 52350128Swpaul return; 52467089Swpaul } 52550128Swpaul 526200950Syongari intrs = STE_INTRS; 527200950Syongari if (status == 0xFFFF || (status & intrs) == 0) 528200950Syongari goto done; 52950128Swpaul 530200950Syongari if (sc->ste_int_rx_act > 0) { 531200950Syongari status &= ~STE_ISR_RX_DMADONE; 532200950Syongari intrs &= ~STE_IMR_RX_DMADONE; 533200950Syongari } 53450128Swpaul 535200950Syongari if ((status & (STE_ISR_SOFTINTR | STE_ISR_RX_DMADONE)) != 0) { 536200950Syongari ste_rxeof(sc, -1); 537200950Syongari /* 538200950Syongari * The controller has no ability to Rx interrupt 539200950Syongari * moderation feature. Receiving 64 bytes frames 540200950Syongari * from wire generates too many interrupts which in 541200950Syongari * turn make system useless to process other useful 542200950Syongari * things. Fortunately ST201 supports single shot 543200950Syongari * timer so use the timer to implement Rx interrupt 544200950Syongari * moderation in driver. This adds more register 545200950Syongari * access but it greatly reduces number of Rx 546200950Syongari * interrupts under high network load. 547200950Syongari */ 548200950Syongari if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0 && 549200950Syongari (sc->ste_int_rx_mod != 0)) { 550200950Syongari if ((status & STE_ISR_RX_DMADONE) != 0) { 551200950Syongari CSR_WRITE_2(sc, STE_COUNTDOWN, 552200950Syongari STE_TIMER_USECS(sc->ste_int_rx_mod)); 553200950Syongari intrs &= ~STE_IMR_RX_DMADONE; 554200950Syongari sc->ste_int_rx_act = 1; 555200950Syongari } else { 556200950Syongari intrs |= STE_IMR_RX_DMADONE; 557200950Syongari sc->ste_int_rx_act = 0; 558200950Syongari } 559200950Syongari } 560200950Syongari } 561200950Syongari if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0) { 562200950Syongari if ((status & STE_ISR_TX_DMADONE) != 0) 56350128Swpaul ste_txeof(sc); 564200950Syongari if ((status & STE_ISR_TX_DONE) != 0) 56550128Swpaul ste_txeoc(sc); 566200950Syongari if ((status & STE_ISR_STATS_OFLOW) != 0) 56750128Swpaul ste_stats_update(sc); 568200950Syongari if ((status & STE_ISR_HOSTERR) != 0) { 569200950Syongari ifp->if_drv_flags &= ~IFF_DRV_RUNNING; 570149646Sjhb ste_init_locked(sc); 571200950Syongari STE_UNLOCK(sc); 572200950Syongari return; 573200904Syongari } 574200950Syongari if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) 575200950Syongari ste_start_locked(ifp); 576200950Syongaridone: 577200950Syongari /* Re-enable interrupts */ 578200950Syongari CSR_WRITE_2(sc, STE_IMR, intrs); 57950128Swpaul } 58067089Swpaul STE_UNLOCK(sc); 58150128Swpaul} 58250128Swpaul 58350128Swpaul/* 58450128Swpaul * A frame has been uploaded: pass the resulting mbuf chain up to 58550128Swpaul * the higher level protocols. 58650128Swpaul */ 587193096Sattiliostatic int 588200853Syongariste_rxeof(struct ste_softc *sc, int count) 58950128Swpaul{ 590200808Syongari struct mbuf *m; 591200808Syongari struct ifnet *ifp; 592200808Syongari struct ste_chain_onefrag *cur_rx; 593200808Syongari uint32_t rxstat; 594200853Syongari int total_len, rx_npkts; 59550128Swpaul 596147256Sbrooks ifp = sc->ste_ifp; 59750128Swpaul 598200853Syongari bus_dmamap_sync(sc->ste_cdata.ste_rx_list_tag, 599200853Syongari sc->ste_cdata.ste_rx_list_map, 600200853Syongari BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); 601200853Syongari 602200853Syongari cur_rx = sc->ste_cdata.ste_rx_head; 603200853Syongari for (rx_npkts = 0; rx_npkts < STE_RX_LIST_CNT; rx_npkts++, 604200853Syongari cur_rx = cur_rx->ste_next) { 605200853Syongari rxstat = le32toh(cur_rx->ste_ptr->ste_status); 606200853Syongari if ((rxstat & STE_RXSTAT_DMADONE) == 0) 607200853Syongari break; 608127686Sru#ifdef DEVICE_POLLING 609150789Sglebius if (ifp->if_capenable & IFCAP_POLLING) { 610200853Syongari if (count == 0) 611127686Sru break; 612200853Syongari count--; 613127686Sru } 614150789Sglebius#endif 615200853Syongari if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) 616101493Sambrisko break; 61750128Swpaul /* 61850128Swpaul * If an error occurs, update stats, clear the 61950128Swpaul * status word and leave the mbuf cluster in place: 62050128Swpaul * it should simply get re-used next time this descriptor 62150128Swpaul * comes up in the ring. 62250128Swpaul */ 62350128Swpaul if (rxstat & STE_RXSTAT_FRAME_ERR) { 62450128Swpaul ifp->if_ierrors++; 62550128Swpaul cur_rx->ste_ptr->ste_status = 0; 62650128Swpaul continue; 62750128Swpaul } 62850128Swpaul 629200804Syongari /* No errors; receive the packet. */ 63050128Swpaul m = cur_rx->ste_mbuf; 631200853Syongari total_len = STE_RX_BYTES(rxstat); 63250128Swpaul 63350128Swpaul /* 63450128Swpaul * Try to conjure up a new mbuf cluster. If that 63550128Swpaul * fails, it means we have an out of memory condition and 63650128Swpaul * should leave the buffer in place and continue. This will 63750128Swpaul * result in a lost packet, but there's little else we 63850128Swpaul * can do in this situation. 63950128Swpaul */ 640200853Syongari if (ste_newbuf(sc, cur_rx) != 0) { 641200965Syongari ifp->if_iqdrops++; 64250128Swpaul cur_rx->ste_ptr->ste_status = 0; 64350128Swpaul continue; 64450128Swpaul } 64550128Swpaul 64650128Swpaul m->m_pkthdr.rcvif = ifp; 64750128Swpaul m->m_pkthdr.len = m->m_len = total_len; 64850128Swpaul 649106936Ssam ifp->if_ipackets++; 650122689Ssam STE_UNLOCK(sc); 651106936Ssam (*ifp->if_input)(ifp, m); 652122689Ssam STE_LOCK(sc); 653200853Syongari } 65450128Swpaul 655200853Syongari if (rx_npkts > 0) { 656200853Syongari sc->ste_cdata.ste_rx_head = cur_rx; 657200853Syongari bus_dmamap_sync(sc->ste_cdata.ste_rx_list_tag, 658200853Syongari sc->ste_cdata.ste_rx_list_map, 659200853Syongari BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 66050128Swpaul } 66150128Swpaul 662193096Sattilio return (rx_npkts); 66350128Swpaul} 66450128Swpaul 665102335Salfredstatic void 666200798Syongariste_txeoc(struct ste_softc *sc) 66750128Swpaul{ 668200884Syongari uint16_t txstat; 669200808Syongari struct ifnet *ifp; 67050128Swpaul 671200884Syongari STE_LOCK_ASSERT(sc); 672200884Syongari 673147256Sbrooks ifp = sc->ste_ifp; 67450128Swpaul 675200884Syongari /* 676200884Syongari * STE_TX_STATUS register implements a queue of up to 31 677200884Syongari * transmit status byte. Writing an arbitrary value to the 678200884Syongari * register will advance the queue to the next transmit 679200884Syongari * status byte. This means if driver does not read 680200884Syongari * STE_TX_STATUS register after completing sending more 681200884Syongari * than 31 frames the controller would be stalled so driver 682200884Syongari * should re-wake the Tx MAC. This is the most severe 683200884Syongari * limitation of ST201 based controller. 684200884Syongari */ 685200884Syongari for (;;) { 686200884Syongari txstat = CSR_READ_2(sc, STE_TX_STATUS); 687200884Syongari if ((txstat & STE_TXSTATUS_TXDONE) == 0) 688200884Syongari break; 689200884Syongari if ((txstat & (STE_TXSTATUS_UNDERRUN | 690200884Syongari STE_TXSTATUS_EXCESSCOLLS | STE_TXSTATUS_RECLAIMERR | 691200884Syongari STE_TXSTATUS_STATSOFLOW)) != 0) { 69250128Swpaul ifp->if_oerrors++; 693200884Syongari#ifdef STE_SHOW_TXERRORS 694200884Syongari device_printf(sc->ste_dev, "TX error : 0x%b\n", 695200884Syongari txstat & 0xFF, STE_ERR_BITS); 696200884Syongari#endif 697200884Syongari if ((txstat & STE_TXSTATUS_UNDERRUN) != 0 && 69850128Swpaul sc->ste_tx_thresh < STE_PACKET_SIZE) { 69950128Swpaul sc->ste_tx_thresh += STE_MIN_FRAMELEN; 700200884Syongari if (sc->ste_tx_thresh > STE_PACKET_SIZE) 701200884Syongari sc->ste_tx_thresh = STE_PACKET_SIZE; 702162315Sglebius device_printf(sc->ste_dev, 703200884Syongari "TX underrun, increasing TX" 70450128Swpaul " start threshold to %d bytes\n", 705149189Sjhb sc->ste_tx_thresh); 706200884Syongari /* Make sure to disable active DMA cycles. */ 707200884Syongari STE_SETBIT4(sc, STE_DMACTL, 708200884Syongari STE_DMACTL_TXDMA_STALL); 709200884Syongari ste_wait(sc); 710200904Syongari ifp->if_drv_flags &= ~IFF_DRV_RUNNING; 711200884Syongari ste_init_locked(sc); 712200884Syongari break; 71350128Swpaul } 714200884Syongari /* Restart Tx. */ 715200884Syongari ste_restart_tx(sc); 71650128Swpaul } 717200884Syongari /* 718200884Syongari * Advance to next status and ACK TxComplete 719200884Syongari * interrupt. ST201 data sheet was wrong here, to 720200884Syongari * get next Tx status, we have to write both 721200884Syongari * STE_TX_STATUS and STE_TX_FRAMEID register. 722200884Syongari * Otherwise controller returns the same status 723200884Syongari * as well as not acknowledge Tx completion 724200884Syongari * interrupt. 725200884Syongari */ 72650128Swpaul CSR_WRITE_2(sc, STE_TX_STATUS, txstat); 72750128Swpaul } 72850128Swpaul} 72950128Swpaul 730102335Salfredstatic void 731200865Syongariste_tick(void *arg) 732200865Syongari{ 733200865Syongari struct ste_softc *sc; 734200865Syongari struct mii_data *mii; 735200865Syongari 736200865Syongari sc = (struct ste_softc *)arg; 737200865Syongari 738200865Syongari STE_LOCK_ASSERT(sc); 739200865Syongari 740200865Syongari mii = device_get_softc(sc->ste_miibus); 741200865Syongari mii_tick(mii); 742200865Syongari /* 743200865Syongari * ukphy(4) does not seem to generate CB that reports 744200865Syongari * resolved link state so if we know we lost a link, 745200865Syongari * explicitly check the link state. 746200865Syongari */ 747200865Syongari if ((sc->ste_flags & STE_FLAG_LINK) == 0) 748200865Syongari ste_miibus_statchg(sc->ste_dev); 749200913Syongari /* 750200913Syongari * Because we are not generating Tx completion 751200913Syongari * interrupt for every frame, reclaim transmitted 752200913Syongari * buffers here. 753200913Syongari */ 754200913Syongari ste_txeof(sc); 755200913Syongari ste_txeoc(sc); 756200865Syongari ste_stats_update(sc); 757200865Syongari ste_watchdog(sc); 758200865Syongari callout_reset(&sc->ste_callout, hz, ste_tick, sc); 759200865Syongari} 760200865Syongari 761200865Syongaristatic void 762200798Syongariste_txeof(struct ste_softc *sc) 76350128Swpaul{ 764200808Syongari struct ifnet *ifp; 765200808Syongari struct ste_chain *cur_tx; 766200853Syongari uint32_t txstat; 767200808Syongari int idx; 76850128Swpaul 769200853Syongari STE_LOCK_ASSERT(sc); 770200853Syongari 771147256Sbrooks ifp = sc->ste_ifp; 772200853Syongari idx = sc->ste_cdata.ste_tx_cons; 773200853Syongari if (idx == sc->ste_cdata.ste_tx_prod) 774200853Syongari return; 77550128Swpaul 776200853Syongari bus_dmamap_sync(sc->ste_cdata.ste_tx_list_tag, 777200853Syongari sc->ste_cdata.ste_tx_list_map, 778200853Syongari BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); 779200853Syongari 780200808Syongari while (idx != sc->ste_cdata.ste_tx_prod) { 78154268Swpaul cur_tx = &sc->ste_cdata.ste_tx_chain[idx]; 782200853Syongari txstat = le32toh(cur_tx->ste_ptr->ste_ctl); 783200853Syongari if ((txstat & STE_TXCTL_DMADONE) == 0) 78450128Swpaul break; 785200853Syongari bus_dmamap_sync(sc->ste_cdata.ste_tx_tag, cur_tx->ste_map, 786200853Syongari BUS_DMASYNC_POSTWRITE); 787200853Syongari bus_dmamap_unload(sc->ste_cdata.ste_tx_tag, cur_tx->ste_map); 788200853Syongari KASSERT(cur_tx->ste_mbuf != NULL, 789200853Syongari ("%s: freeing NULL mbuf!\n", __func__)); 790127775Sru m_freem(cur_tx->ste_mbuf); 791127775Sru cur_tx->ste_mbuf = NULL; 792148887Srwatson ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 79350128Swpaul ifp->if_opackets++; 794200853Syongari sc->ste_cdata.ste_tx_cnt--; 79554268Swpaul STE_INC(idx, STE_TX_LIST_CNT); 79650128Swpaul } 79750128Swpaul 798127927Sru sc->ste_cdata.ste_tx_cons = idx; 799200853Syongari if (sc->ste_cdata.ste_tx_cnt == 0) 800199559Sjhb sc->ste_timer = 0; 80150128Swpaul} 80250128Swpaul 803102335Salfredstatic void 804200910Syongariste_stats_clear(struct ste_softc *sc) 805200910Syongari{ 806200910Syongari 807200910Syongari STE_LOCK_ASSERT(sc); 808200910Syongari 809200910Syongari /* Rx stats. */ 810200910Syongari CSR_READ_2(sc, STE_STAT_RX_OCTETS_LO); 811200910Syongari CSR_READ_2(sc, STE_STAT_RX_OCTETS_HI); 812200910Syongari CSR_READ_2(sc, STE_STAT_RX_FRAMES); 813200910Syongari CSR_READ_1(sc, STE_STAT_RX_BCAST); 814200910Syongari CSR_READ_1(sc, STE_STAT_RX_MCAST); 815200910Syongari CSR_READ_1(sc, STE_STAT_RX_LOST); 816200910Syongari /* Tx stats. */ 817200910Syongari CSR_READ_2(sc, STE_STAT_TX_OCTETS_LO); 818200910Syongari CSR_READ_2(sc, STE_STAT_TX_OCTETS_HI); 819200910Syongari CSR_READ_2(sc, STE_STAT_TX_FRAMES); 820200910Syongari CSR_READ_1(sc, STE_STAT_TX_BCAST); 821200910Syongari CSR_READ_1(sc, STE_STAT_TX_MCAST); 822200910Syongari CSR_READ_1(sc, STE_STAT_CARRIER_ERR); 823200910Syongari CSR_READ_1(sc, STE_STAT_SINGLE_COLLS); 824200910Syongari CSR_READ_1(sc, STE_STAT_MULTI_COLLS); 825200910Syongari CSR_READ_1(sc, STE_STAT_LATE_COLLS); 826200910Syongari CSR_READ_1(sc, STE_STAT_TX_DEFER); 827200910Syongari CSR_READ_1(sc, STE_STAT_TX_EXDEFER); 828200910Syongari CSR_READ_1(sc, STE_STAT_TX_ABORT); 829200910Syongari} 830200910Syongari 831200910Syongaristatic void 832200865Syongariste_stats_update(struct ste_softc *sc) 83350128Swpaul{ 834200808Syongari struct ifnet *ifp; 835200910Syongari struct ste_hw_stats *stats; 836200910Syongari uint32_t val; 83750128Swpaul 838149646Sjhb STE_LOCK_ASSERT(sc); 83950128Swpaul 840147256Sbrooks ifp = sc->ste_ifp; 841200910Syongari stats = &sc->ste_stats; 842200910Syongari /* Rx stats. */ 843200910Syongari val = (uint32_t)CSR_READ_2(sc, STE_STAT_RX_OCTETS_LO) | 844200910Syongari ((uint32_t)CSR_READ_2(sc, STE_STAT_RX_OCTETS_HI)) << 16; 845200910Syongari val &= 0x000FFFFF; 846200910Syongari stats->rx_bytes += val; 847200910Syongari stats->rx_frames += CSR_READ_2(sc, STE_STAT_RX_FRAMES); 848200910Syongari stats->rx_bcast_frames += CSR_READ_1(sc, STE_STAT_RX_BCAST); 849200910Syongari stats->rx_mcast_frames += CSR_READ_1(sc, STE_STAT_RX_MCAST); 850200910Syongari stats->rx_lost_frames += CSR_READ_1(sc, STE_STAT_RX_LOST); 851200910Syongari /* Tx stats. */ 852200910Syongari val = (uint32_t)CSR_READ_2(sc, STE_STAT_TX_OCTETS_LO) | 853200910Syongari ((uint32_t)CSR_READ_2(sc, STE_STAT_TX_OCTETS_HI)) << 16; 854200910Syongari val &= 0x000FFFFF; 855200910Syongari stats->tx_bytes += val; 856200910Syongari stats->tx_frames += CSR_READ_2(sc, STE_STAT_TX_FRAMES); 857200910Syongari stats->tx_bcast_frames += CSR_READ_1(sc, STE_STAT_TX_BCAST); 858200910Syongari stats->tx_mcast_frames += CSR_READ_1(sc, STE_STAT_TX_MCAST); 859200910Syongari stats->tx_carrsense_errs += CSR_READ_1(sc, STE_STAT_CARRIER_ERR); 860200910Syongari val = CSR_READ_1(sc, STE_STAT_SINGLE_COLLS); 861200910Syongari stats->tx_single_colls += val; 862200910Syongari ifp->if_collisions += val; 863200910Syongari val = CSR_READ_1(sc, STE_STAT_MULTI_COLLS); 864200910Syongari stats->tx_multi_colls += val; 865200910Syongari ifp->if_collisions += val; 866200910Syongari val += CSR_READ_1(sc, STE_STAT_LATE_COLLS); 867200910Syongari stats->tx_late_colls += val; 868200910Syongari ifp->if_collisions += val; 869200910Syongari stats->tx_frames_defered += CSR_READ_1(sc, STE_STAT_TX_DEFER); 870200910Syongari stats->tx_excess_defers += CSR_READ_1(sc, STE_STAT_TX_EXDEFER); 871200910Syongari stats->tx_abort += CSR_READ_1(sc, STE_STAT_TX_ABORT); 87250128Swpaul} 87350128Swpaul 87450128Swpaul/* 87550128Swpaul * Probe for a Sundance ST201 chip. Check the PCI vendor and device 87650128Swpaul * IDs against our list and return a device name if we find a match. 87750128Swpaul */ 878102335Salfredstatic int 879200798Syongariste_probe(device_t dev) 88050128Swpaul{ 881226995Smarius const struct ste_type *t; 88250128Swpaul 88350128Swpaul t = ste_devs; 88450128Swpaul 885200808Syongari while (t->ste_name != NULL) { 88650128Swpaul if ((pci_get_vendor(dev) == t->ste_vid) && 88750128Swpaul (pci_get_device(dev) == t->ste_did)) { 88850128Swpaul device_set_desc(dev, t->ste_name); 889142398Simp return (BUS_PROBE_DEFAULT); 89050128Swpaul } 89150128Swpaul t++; 89250128Swpaul } 89350128Swpaul 894200808Syongari return (ENXIO); 89550128Swpaul} 89650128Swpaul 89750128Swpaul/* 89850128Swpaul * Attach the interface. Allocate softc structures, do ifmedia 89950128Swpaul * setup and ethernet/BPF attach. 90050128Swpaul */ 901102335Salfredstatic int 902200798Syongariste_attach(device_t dev) 90350128Swpaul{ 904200808Syongari struct ste_softc *sc; 905200808Syongari struct ifnet *ifp; 906201767Syongari uint16_t eaddr[ETHER_ADDR_LEN / 2]; 907213893Smarius int error = 0, phy, pmc, prefer_iomap, rid; 90850128Swpaul 90950128Swpaul sc = device_get_softc(dev); 910101493Sambrisko sc->ste_dev = dev; 91150128Swpaul 912102113Sambrisko /* 913103238Sambrisko * Only use one PHY since this chip reports multiple 914103238Sambrisko * Note on the DFE-550 the PHY is at 1 on the DFE-580 915103238Sambrisko * it is at 0 & 1. It is rev 0x12. 916102113Sambrisko */ 917102113Sambrisko if (pci_get_vendor(dev) == DL_VENDORID && 918108237Sphk pci_get_device(dev) == DL_DEVICEID_DL10050 && 919103238Sambrisko pci_get_revid(dev) == 0x12 ) 920200856Syongari sc->ste_flags |= STE_FLAG_ONE_PHY; 921102113Sambrisko 92293818Sjhb mtx_init(&sc->ste_mtx, device_get_nameunit(dev), MTX_NETWORK_LOCK, 923149646Sjhb MTX_DEF); 92450128Swpaul /* 92550128Swpaul * Map control/status registers. 92650128Swpaul */ 92772813Swpaul pci_enable_busmaster(dev); 92850128Swpaul 929211089Syongari /* 930211089Syongari * Prefer memory space register mapping over IO space but use 931211089Syongari * IO space for a device that is known to have issues on memory 932211089Syongari * mapping. 933211089Syongari */ 934211089Syongari prefer_iomap = 0; 935211089Syongari if (pci_get_device(dev) == ST_DEVICEID_ST201_1) 936211089Syongari prefer_iomap = 1; 937211089Syongari else 938211089Syongari resource_int_value(device_get_name(sc->ste_dev), 939211089Syongari device_get_unit(sc->ste_dev), "prefer_iomap", 940211089Syongari &prefer_iomap); 941211089Syongari if (prefer_iomap == 0) { 942211089Syongari sc->ste_res_id = PCIR_BAR(1); 943211089Syongari sc->ste_res_type = SYS_RES_MEMORY; 944211089Syongari sc->ste_res = bus_alloc_resource_any(dev, sc->ste_res_type, 945211089Syongari &sc->ste_res_id, RF_ACTIVE); 946211089Syongari } 947211089Syongari if (prefer_iomap || sc->ste_res == NULL) { 948200875Syongari sc->ste_res_id = PCIR_BAR(0); 949200875Syongari sc->ste_res_type = SYS_RES_IOPORT; 950200875Syongari sc->ste_res = bus_alloc_resource_any(dev, sc->ste_res_type, 951200875Syongari &sc->ste_res_id, RF_ACTIVE); 952200875Syongari } 953200875Syongari if (sc->ste_res == NULL) { 954149189Sjhb device_printf(dev, "couldn't map ports/memory\n"); 95550128Swpaul error = ENXIO; 95650128Swpaul goto fail; 95750128Swpaul } 95850128Swpaul 959112872Snjl /* Allocate interrupt */ 96050128Swpaul rid = 0; 961127135Snjl sc->ste_irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, 96250128Swpaul RF_SHAREABLE | RF_ACTIVE); 96350128Swpaul 96450128Swpaul if (sc->ste_irq == NULL) { 965149189Sjhb device_printf(dev, "couldn't map interrupt\n"); 96650128Swpaul error = ENXIO; 96750128Swpaul goto fail; 96850128Swpaul } 96950128Swpaul 970200865Syongari callout_init_mtx(&sc->ste_callout, &sc->ste_mtx, 0); 97150128Swpaul 97250128Swpaul /* Reset the adapter. */ 97350128Swpaul ste_reset(sc); 97450128Swpaul 97550128Swpaul /* 97650128Swpaul * Get station address from the EEPROM. 97750128Swpaul */ 978201767Syongari if (ste_read_eeprom(sc, eaddr, STE_EEADDR_NODE0, ETHER_ADDR_LEN / 2)) { 979149189Sjhb device_printf(dev, "failed to read station address\n"); 980201758Smbr error = ENXIO; 98150128Swpaul goto fail; 98250128Swpaul } 983200910Syongari ste_sysctl_node(sc); 98450128Swpaul 985200853Syongari if ((error = ste_dma_alloc(sc)) != 0) 98650128Swpaul goto fail; 98750128Swpaul 988147291Sbrooks ifp = sc->ste_ifp = if_alloc(IFT_ETHER); 989147291Sbrooks if (ifp == NULL) { 990149189Sjhb device_printf(dev, "can not if_alloc()\n"); 991147291Sbrooks error = ENOSPC; 992147291Sbrooks goto fail; 993147291Sbrooks } 994147291Sbrooks 99550128Swpaul /* Do MII setup. */ 996213893Smarius phy = MII_PHY_ANY; 997213893Smarius if ((sc->ste_flags & STE_FLAG_ONE_PHY) != 0) 998213893Smarius phy = 0; 999213893Smarius error = mii_attach(dev, &sc->ste_miibus, ifp, ste_ifmedia_upd, 1000213893Smarius ste_ifmedia_sts, BMSR_DEFCAPMASK, phy, MII_OFFSET_ANY, 0); 1001213893Smarius if (error != 0) { 1002213893Smarius device_printf(dev, "attaching PHYs failed\n"); 100350128Swpaul goto fail; 100450128Swpaul } 100550128Swpaul 100650128Swpaul ifp->if_softc = sc; 1007121816Sbrooks if_initname(ifp, device_get_name(dev), device_get_unit(dev)); 1008149646Sjhb ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 100950128Swpaul ifp->if_ioctl = ste_ioctl; 101050128Swpaul ifp->if_start = ste_start; 101150128Swpaul ifp->if_init = ste_init; 1012147828Smlaier IFQ_SET_MAXLEN(&ifp->if_snd, STE_TX_LIST_CNT - 1); 1013147828Smlaier ifp->if_snd.ifq_drv_maxlen = STE_TX_LIST_CNT - 1; 1014147828Smlaier IFQ_SET_READY(&ifp->if_snd); 101550128Swpaul 1016101493Sambrisko sc->ste_tx_thresh = STE_TXSTART_THRESH; 1017101493Sambrisko 101850128Swpaul /* 101963090Sarchie * Call MI attach routine. 102050128Swpaul */ 1021201767Syongari ether_ifattach(ifp, (uint8_t *)eaddr); 1022101493Sambrisko 1023101493Sambrisko /* 1024101493Sambrisko * Tell the upper layer(s) we support long frames. 1025101493Sambrisko */ 1026101493Sambrisko ifp->if_data.ifi_hdrlen = sizeof(struct ether_vlan_header); 1027106936Ssam ifp->if_capabilities |= IFCAP_VLAN_MTU; 1028219902Sjhb if (pci_find_cap(dev, PCIY_PMG, &pmc) == 0) 1029200955Syongari ifp->if_capabilities |= IFCAP_WOL_MAGIC; 1030150789Sglebius ifp->if_capenable = ifp->if_capabilities; 1031128117Sru#ifdef DEVICE_POLLING 1032128117Sru ifp->if_capabilities |= IFCAP_POLLING; 1033128117Sru#endif 1034101493Sambrisko 1035113609Snjl /* Hook interrupt last to avoid having to lock softc */ 1036149646Sjhb error = bus_setup_intr(dev, sc->ste_irq, INTR_TYPE_NET | INTR_MPSAFE, 1037166901Spiso NULL, ste_intr, sc, &sc->ste_intrhand); 103850128Swpaul 1039112872Snjl if (error) { 1040149189Sjhb device_printf(dev, "couldn't set up irq\n"); 1041113609Snjl ether_ifdetach(ifp); 1042112872Snjl goto fail; 1043112872Snjl } 1044112872Snjl 104550128Swpaulfail: 1046112872Snjl if (error) 1047112872Snjl ste_detach(dev); 1048112872Snjl 1049200808Syongari return (error); 105050128Swpaul} 105150128Swpaul 1052113609Snjl/* 1053113609Snjl * Shutdown hardware and free up resources. This can be called any 1054113609Snjl * time after the mutex has been initialized. It is called in both 1055113609Snjl * the error case in attach and the normal detach case so it needs 1056113609Snjl * to be careful about only freeing resources that have actually been 1057113609Snjl * allocated. 1058113609Snjl */ 1059102335Salfredstatic int 1060200798Syongariste_detach(device_t dev) 106150128Swpaul{ 1062200808Syongari struct ste_softc *sc; 1063200808Syongari struct ifnet *ifp; 106450128Swpaul 106550128Swpaul sc = device_get_softc(dev); 1066112880Sjhb KASSERT(mtx_initialized(&sc->ste_mtx), ("ste mutex not initialized")); 1067147256Sbrooks ifp = sc->ste_ifp; 106850128Swpaul 1069150789Sglebius#ifdef DEVICE_POLLING 1070150789Sglebius if (ifp->if_capenable & IFCAP_POLLING) 1071150789Sglebius ether_poll_deregister(ifp); 1072150789Sglebius#endif 1073150789Sglebius 1074113609Snjl /* These should only be active if attach succeeded */ 1075113812Simp if (device_is_attached(dev)) { 1076199559Sjhb ether_ifdetach(ifp); 1077149646Sjhb STE_LOCK(sc); 1078113609Snjl ste_stop(sc); 1079149646Sjhb STE_UNLOCK(sc); 1080200865Syongari callout_drain(&sc->ste_callout); 1081150213Sru } 1082113609Snjl if (sc->ste_miibus) 1083112872Snjl device_delete_child(dev, sc->ste_miibus); 1084113609Snjl bus_generic_detach(dev); 108550128Swpaul 1086112872Snjl if (sc->ste_intrhand) 1087112872Snjl bus_teardown_intr(dev, sc->ste_irq, sc->ste_intrhand); 1088112872Snjl if (sc->ste_irq) 1089112872Snjl bus_release_resource(dev, SYS_RES_IRQ, 0, sc->ste_irq); 1090112872Snjl if (sc->ste_res) 1091200875Syongari bus_release_resource(dev, sc->ste_res_type, sc->ste_res_id, 1092200875Syongari sc->ste_res); 109350128Swpaul 1094151297Sru if (ifp) 1095151297Sru if_free(ifp); 1096151297Sru 1097200853Syongari ste_dma_free(sc); 109867089Swpaul mtx_destroy(&sc->ste_mtx); 109950128Swpaul 1100200808Syongari return (0); 110150128Swpaul} 110250128Swpaul 1103200853Syongaristruct ste_dmamap_arg { 1104200853Syongari bus_addr_t ste_busaddr; 1105200853Syongari}; 1106200853Syongari 1107200853Syongaristatic void 1108200853Syongariste_dmamap_cb(void *arg, bus_dma_segment_t *segs, int nsegs, int error) 1109200853Syongari{ 1110200853Syongari struct ste_dmamap_arg *ctx; 1111200853Syongari 1112200853Syongari if (error != 0) 1113200853Syongari return; 1114200853Syongari 1115200853Syongari KASSERT(nsegs == 1, ("%s: %d segments returned!", __func__, nsegs)); 1116200853Syongari 1117200853Syongari ctx = (struct ste_dmamap_arg *)arg; 1118200853Syongari ctx->ste_busaddr = segs[0].ds_addr; 1119200853Syongari} 1120200853Syongari 1121102335Salfredstatic int 1122200853Syongariste_dma_alloc(struct ste_softc *sc) 112350128Swpaul{ 1124200853Syongari struct ste_chain *txc; 1125200853Syongari struct ste_chain_onefrag *rxc; 1126200853Syongari struct ste_dmamap_arg ctx; 1127200853Syongari int error, i; 112850128Swpaul 1129200853Syongari /* Create parent DMA tag. */ 1130200853Syongari error = bus_dma_tag_create( 1131200853Syongari bus_get_dma_tag(sc->ste_dev), /* parent */ 1132200853Syongari 1, 0, /* alignment, boundary */ 1133200853Syongari BUS_SPACE_MAXADDR_32BIT, /* lowaddr */ 1134200853Syongari BUS_SPACE_MAXADDR, /* highaddr */ 1135200853Syongari NULL, NULL, /* filter, filterarg */ 1136200853Syongari BUS_SPACE_MAXSIZE_32BIT, /* maxsize */ 1137200853Syongari 0, /* nsegments */ 1138200853Syongari BUS_SPACE_MAXSIZE_32BIT, /* maxsegsize */ 1139200853Syongari 0, /* flags */ 1140200853Syongari NULL, NULL, /* lockfunc, lockarg */ 1141200853Syongari &sc->ste_cdata.ste_parent_tag); 1142200853Syongari if (error != 0) { 1143200853Syongari device_printf(sc->ste_dev, 1144200853Syongari "could not create parent DMA tag.\n"); 1145200853Syongari goto fail; 1146200853Syongari } 1147200853Syongari 1148200853Syongari /* Create DMA tag for Tx descriptor list. */ 1149200853Syongari error = bus_dma_tag_create( 1150200853Syongari sc->ste_cdata.ste_parent_tag, /* parent */ 1151200853Syongari STE_DESC_ALIGN, 0, /* alignment, boundary */ 1152200853Syongari BUS_SPACE_MAXADDR, /* lowaddr */ 1153200853Syongari BUS_SPACE_MAXADDR, /* highaddr */ 1154200853Syongari NULL, NULL, /* filter, filterarg */ 1155200853Syongari STE_TX_LIST_SZ, /* maxsize */ 1156200853Syongari 1, /* nsegments */ 1157200853Syongari STE_TX_LIST_SZ, /* maxsegsize */ 1158200853Syongari 0, /* flags */ 1159200853Syongari NULL, NULL, /* lockfunc, lockarg */ 1160200853Syongari &sc->ste_cdata.ste_tx_list_tag); 1161200853Syongari if (error != 0) { 1162200853Syongari device_printf(sc->ste_dev, 1163200853Syongari "could not create Tx list DMA tag.\n"); 1164200853Syongari goto fail; 1165200853Syongari } 1166200853Syongari 1167200853Syongari /* Create DMA tag for Rx descriptor list. */ 1168200853Syongari error = bus_dma_tag_create( 1169200853Syongari sc->ste_cdata.ste_parent_tag, /* parent */ 1170200853Syongari STE_DESC_ALIGN, 0, /* alignment, boundary */ 1171200853Syongari BUS_SPACE_MAXADDR, /* lowaddr */ 1172200853Syongari BUS_SPACE_MAXADDR, /* highaddr */ 1173200853Syongari NULL, NULL, /* filter, filterarg */ 1174200853Syongari STE_RX_LIST_SZ, /* maxsize */ 1175200853Syongari 1, /* nsegments */ 1176200853Syongari STE_RX_LIST_SZ, /* maxsegsize */ 1177200853Syongari 0, /* flags */ 1178200853Syongari NULL, NULL, /* lockfunc, lockarg */ 1179200853Syongari &sc->ste_cdata.ste_rx_list_tag); 1180200853Syongari if (error != 0) { 1181200853Syongari device_printf(sc->ste_dev, 1182200853Syongari "could not create Rx list DMA tag.\n"); 1183200853Syongari goto fail; 1184200853Syongari } 1185200853Syongari 1186200853Syongari /* Create DMA tag for Tx buffers. */ 1187200853Syongari error = bus_dma_tag_create( 1188200853Syongari sc->ste_cdata.ste_parent_tag, /* parent */ 1189200853Syongari 1, 0, /* alignment, boundary */ 1190200853Syongari BUS_SPACE_MAXADDR, /* lowaddr */ 1191200853Syongari BUS_SPACE_MAXADDR, /* highaddr */ 1192200853Syongari NULL, NULL, /* filter, filterarg */ 1193200853Syongari MCLBYTES * STE_MAXFRAGS, /* maxsize */ 1194200853Syongari STE_MAXFRAGS, /* nsegments */ 1195200853Syongari MCLBYTES, /* maxsegsize */ 1196200853Syongari 0, /* flags */ 1197200853Syongari NULL, NULL, /* lockfunc, lockarg */ 1198200853Syongari &sc->ste_cdata.ste_tx_tag); 1199200853Syongari if (error != 0) { 1200200853Syongari device_printf(sc->ste_dev, "could not create Tx DMA tag.\n"); 1201200853Syongari goto fail; 1202200853Syongari } 1203200853Syongari 1204200853Syongari /* Create DMA tag for Rx buffers. */ 1205200853Syongari error = bus_dma_tag_create( 1206200853Syongari sc->ste_cdata.ste_parent_tag, /* parent */ 1207200853Syongari 1, 0, /* alignment, boundary */ 1208200853Syongari BUS_SPACE_MAXADDR, /* lowaddr */ 1209200853Syongari BUS_SPACE_MAXADDR, /* highaddr */ 1210200853Syongari NULL, NULL, /* filter, filterarg */ 1211200853Syongari MCLBYTES, /* maxsize */ 1212200853Syongari 1, /* nsegments */ 1213200853Syongari MCLBYTES, /* maxsegsize */ 1214200853Syongari 0, /* flags */ 1215200853Syongari NULL, NULL, /* lockfunc, lockarg */ 1216200853Syongari &sc->ste_cdata.ste_rx_tag); 1217200853Syongari if (error != 0) { 1218200853Syongari device_printf(sc->ste_dev, "could not create Rx DMA tag.\n"); 1219200853Syongari goto fail; 1220200853Syongari } 1221200853Syongari 1222200853Syongari /* Allocate DMA'able memory and load the DMA map for Tx list. */ 1223200853Syongari error = bus_dmamem_alloc(sc->ste_cdata.ste_tx_list_tag, 1224200853Syongari (void **)&sc->ste_ldata.ste_tx_list, 1225200853Syongari BUS_DMA_WAITOK | BUS_DMA_ZERO | BUS_DMA_COHERENT, 1226200853Syongari &sc->ste_cdata.ste_tx_list_map); 1227200853Syongari if (error != 0) { 1228200853Syongari device_printf(sc->ste_dev, 1229200853Syongari "could not allocate DMA'able memory for Tx list.\n"); 1230200853Syongari goto fail; 1231200853Syongari } 1232200853Syongari ctx.ste_busaddr = 0; 1233200853Syongari error = bus_dmamap_load(sc->ste_cdata.ste_tx_list_tag, 1234200853Syongari sc->ste_cdata.ste_tx_list_map, sc->ste_ldata.ste_tx_list, 1235200853Syongari STE_TX_LIST_SZ, ste_dmamap_cb, &ctx, 0); 1236200853Syongari if (error != 0 || ctx.ste_busaddr == 0) { 1237200853Syongari device_printf(sc->ste_dev, 1238200853Syongari "could not load DMA'able memory for Tx list.\n"); 1239200853Syongari goto fail; 1240200853Syongari } 1241200853Syongari sc->ste_ldata.ste_tx_list_paddr = ctx.ste_busaddr; 1242200853Syongari 1243200853Syongari /* Allocate DMA'able memory and load the DMA map for Rx list. */ 1244200853Syongari error = bus_dmamem_alloc(sc->ste_cdata.ste_rx_list_tag, 1245200853Syongari (void **)&sc->ste_ldata.ste_rx_list, 1246200853Syongari BUS_DMA_WAITOK | BUS_DMA_ZERO | BUS_DMA_COHERENT, 1247200853Syongari &sc->ste_cdata.ste_rx_list_map); 1248200853Syongari if (error != 0) { 1249200853Syongari device_printf(sc->ste_dev, 1250200853Syongari "could not allocate DMA'able memory for Rx list.\n"); 1251200853Syongari goto fail; 1252200853Syongari } 1253200853Syongari ctx.ste_busaddr = 0; 1254200853Syongari error = bus_dmamap_load(sc->ste_cdata.ste_rx_list_tag, 1255200853Syongari sc->ste_cdata.ste_rx_list_map, sc->ste_ldata.ste_rx_list, 1256200853Syongari STE_RX_LIST_SZ, ste_dmamap_cb, &ctx, 0); 1257200853Syongari if (error != 0 || ctx.ste_busaddr == 0) { 1258200853Syongari device_printf(sc->ste_dev, 1259200853Syongari "could not load DMA'able memory for Rx list.\n"); 1260200853Syongari goto fail; 1261200853Syongari } 1262200853Syongari sc->ste_ldata.ste_rx_list_paddr = ctx.ste_busaddr; 1263200853Syongari 1264200853Syongari /* Create DMA maps for Tx buffers. */ 1265200853Syongari for (i = 0; i < STE_TX_LIST_CNT; i++) { 1266200853Syongari txc = &sc->ste_cdata.ste_tx_chain[i]; 1267200853Syongari txc->ste_ptr = NULL; 1268200853Syongari txc->ste_mbuf = NULL; 1269200853Syongari txc->ste_next = NULL; 1270200853Syongari txc->ste_phys = 0; 1271200853Syongari txc->ste_map = NULL; 1272200853Syongari error = bus_dmamap_create(sc->ste_cdata.ste_tx_tag, 0, 1273200853Syongari &txc->ste_map); 1274200853Syongari if (error != 0) { 1275200853Syongari device_printf(sc->ste_dev, 1276200853Syongari "could not create Tx dmamap.\n"); 1277200853Syongari goto fail; 127850128Swpaul } 127950128Swpaul } 1280200853Syongari /* Create DMA maps for Rx buffers. */ 1281200853Syongari if ((error = bus_dmamap_create(sc->ste_cdata.ste_rx_tag, 0, 1282200853Syongari &sc->ste_cdata.ste_rx_sparemap)) != 0) { 1283200853Syongari device_printf(sc->ste_dev, 1284200853Syongari "could not create spare Rx dmamap.\n"); 1285200853Syongari goto fail; 1286200853Syongari } 1287200853Syongari for (i = 0; i < STE_RX_LIST_CNT; i++) { 1288200853Syongari rxc = &sc->ste_cdata.ste_rx_chain[i]; 1289200853Syongari rxc->ste_ptr = NULL; 1290200853Syongari rxc->ste_mbuf = NULL; 1291200853Syongari rxc->ste_next = NULL; 1292200853Syongari rxc->ste_map = NULL; 1293200853Syongari error = bus_dmamap_create(sc->ste_cdata.ste_rx_tag, 0, 1294200853Syongari &rxc->ste_map); 1295200853Syongari if (error != 0) { 1296200853Syongari device_printf(sc->ste_dev, 1297200853Syongari "could not create Rx dmamap.\n"); 1298200853Syongari goto fail; 1299200853Syongari } 1300200853Syongari } 130150128Swpaul 1302200853Syongarifail: 1303200853Syongari return (error); 1304200853Syongari} 130550128Swpaul 1306200853Syongaristatic void 1307200853Syongariste_dma_free(struct ste_softc *sc) 1308200853Syongari{ 1309200853Syongari struct ste_chain *txc; 1310200853Syongari struct ste_chain_onefrag *rxc; 1311200853Syongari int i; 131250128Swpaul 1313200853Syongari /* Tx buffers. */ 1314200853Syongari if (sc->ste_cdata.ste_tx_tag != NULL) { 1315200853Syongari for (i = 0; i < STE_TX_LIST_CNT; i++) { 1316200853Syongari txc = &sc->ste_cdata.ste_tx_chain[i]; 1317200853Syongari if (txc->ste_map != NULL) { 1318200853Syongari bus_dmamap_destroy(sc->ste_cdata.ste_tx_tag, 1319200853Syongari txc->ste_map); 1320200853Syongari txc->ste_map = NULL; 1321200853Syongari } 1322200853Syongari } 1323200853Syongari bus_dma_tag_destroy(sc->ste_cdata.ste_tx_tag); 1324200853Syongari sc->ste_cdata.ste_tx_tag = NULL; 1325200853Syongari } 1326200853Syongari /* Rx buffers. */ 1327200853Syongari if (sc->ste_cdata.ste_rx_tag != NULL) { 1328200853Syongari for (i = 0; i < STE_RX_LIST_CNT; i++) { 1329200853Syongari rxc = &sc->ste_cdata.ste_rx_chain[i]; 1330200853Syongari if (rxc->ste_map != NULL) { 1331200853Syongari bus_dmamap_destroy(sc->ste_cdata.ste_rx_tag, 1332200853Syongari rxc->ste_map); 1333200853Syongari rxc->ste_map = NULL; 1334200853Syongari } 1335200853Syongari } 1336200853Syongari if (sc->ste_cdata.ste_rx_sparemap != NULL) { 1337200853Syongari bus_dmamap_destroy(sc->ste_cdata.ste_rx_tag, 1338200853Syongari sc->ste_cdata.ste_rx_sparemap); 1339200853Syongari sc->ste_cdata.ste_rx_sparemap = NULL; 1340200853Syongari } 1341200853Syongari bus_dma_tag_destroy(sc->ste_cdata.ste_rx_tag); 1342200853Syongari sc->ste_cdata.ste_rx_tag = NULL; 1343200853Syongari } 1344200853Syongari /* Tx descriptor list. */ 1345200853Syongari if (sc->ste_cdata.ste_tx_list_tag != NULL) { 1346200853Syongari if (sc->ste_cdata.ste_tx_list_map != NULL) 1347200853Syongari bus_dmamap_unload(sc->ste_cdata.ste_tx_list_tag, 1348200853Syongari sc->ste_cdata.ste_tx_list_map); 1349200853Syongari if (sc->ste_cdata.ste_tx_list_map != NULL && 1350200853Syongari sc->ste_ldata.ste_tx_list != NULL) 1351200853Syongari bus_dmamem_free(sc->ste_cdata.ste_tx_list_tag, 1352200853Syongari sc->ste_ldata.ste_tx_list, 1353200853Syongari sc->ste_cdata.ste_tx_list_map); 1354200853Syongari sc->ste_ldata.ste_tx_list = NULL; 1355200853Syongari sc->ste_cdata.ste_tx_list_map = NULL; 1356200853Syongari bus_dma_tag_destroy(sc->ste_cdata.ste_tx_list_tag); 1357200853Syongari sc->ste_cdata.ste_tx_list_tag = NULL; 1358200853Syongari } 1359200853Syongari /* Rx descriptor list. */ 1360200853Syongari if (sc->ste_cdata.ste_rx_list_tag != NULL) { 1361200853Syongari if (sc->ste_cdata.ste_rx_list_map != NULL) 1362200853Syongari bus_dmamap_unload(sc->ste_cdata.ste_rx_list_tag, 1363200853Syongari sc->ste_cdata.ste_rx_list_map); 1364200853Syongari if (sc->ste_cdata.ste_rx_list_map != NULL && 1365200853Syongari sc->ste_ldata.ste_rx_list != NULL) 1366200853Syongari bus_dmamem_free(sc->ste_cdata.ste_rx_list_tag, 1367200853Syongari sc->ste_ldata.ste_rx_list, 1368200853Syongari sc->ste_cdata.ste_rx_list_map); 1369200853Syongari sc->ste_ldata.ste_rx_list = NULL; 1370200853Syongari sc->ste_cdata.ste_rx_list_map = NULL; 1371200853Syongari bus_dma_tag_destroy(sc->ste_cdata.ste_rx_list_tag); 1372200853Syongari sc->ste_cdata.ste_rx_list_tag = NULL; 1373200853Syongari } 1374200853Syongari if (sc->ste_cdata.ste_parent_tag != NULL) { 1375200853Syongari bus_dma_tag_destroy(sc->ste_cdata.ste_parent_tag); 1376200853Syongari sc->ste_cdata.ste_parent_tag = NULL; 1377200853Syongari } 1378200853Syongari} 1379200853Syongari 1380200853Syongaristatic int 1381200853Syongariste_newbuf(struct ste_softc *sc, struct ste_chain_onefrag *rxc) 1382200853Syongari{ 1383200853Syongari struct mbuf *m; 1384200853Syongari bus_dma_segment_t segs[1]; 1385200853Syongari bus_dmamap_t map; 1386200853Syongari int error, nsegs; 1387200853Syongari 1388243857Sglebius m = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR); 1389200853Syongari if (m == NULL) 1390200853Syongari return (ENOBUFS); 1391200853Syongari m->m_len = m->m_pkthdr.len = MCLBYTES; 1392200853Syongari m_adj(m, ETHER_ALIGN); 1393200853Syongari 1394200853Syongari if ((error = bus_dmamap_load_mbuf_sg(sc->ste_cdata.ste_rx_tag, 1395200853Syongari sc->ste_cdata.ste_rx_sparemap, m, segs, &nsegs, 0)) != 0) { 1396200853Syongari m_freem(m); 1397200853Syongari return (error); 1398200853Syongari } 1399200853Syongari KASSERT(nsegs == 1, ("%s: %d segments returned!", __func__, nsegs)); 1400200853Syongari 1401200853Syongari if (rxc->ste_mbuf != NULL) { 1402200853Syongari bus_dmamap_sync(sc->ste_cdata.ste_rx_tag, rxc->ste_map, 1403200853Syongari BUS_DMASYNC_POSTREAD); 1404200853Syongari bus_dmamap_unload(sc->ste_cdata.ste_rx_tag, rxc->ste_map); 1405200853Syongari } 1406200853Syongari map = rxc->ste_map; 1407200853Syongari rxc->ste_map = sc->ste_cdata.ste_rx_sparemap; 1408200853Syongari sc->ste_cdata.ste_rx_sparemap = map; 1409200853Syongari bus_dmamap_sync(sc->ste_cdata.ste_rx_tag, rxc->ste_map, 1410200853Syongari BUS_DMASYNC_PREREAD); 1411200853Syongari rxc->ste_mbuf = m; 1412200853Syongari rxc->ste_ptr->ste_status = 0; 1413200853Syongari rxc->ste_ptr->ste_frag.ste_addr = htole32(segs[0].ds_addr); 1414200853Syongari rxc->ste_ptr->ste_frag.ste_len = htole32(segs[0].ds_len | 1415200853Syongari STE_FRAG_LAST); 1416200808Syongari return (0); 141750128Swpaul} 141850128Swpaul 1419102335Salfredstatic int 1420200798Syongariste_init_rx_list(struct ste_softc *sc) 142150128Swpaul{ 1422200808Syongari struct ste_chain_data *cd; 1423200808Syongari struct ste_list_data *ld; 1424200853Syongari int error, i; 142550128Swpaul 1426200950Syongari sc->ste_int_rx_act = 0; 142750128Swpaul cd = &sc->ste_cdata; 1428200853Syongari ld = &sc->ste_ldata; 1429200853Syongari bzero(ld->ste_rx_list, STE_RX_LIST_SZ); 143050128Swpaul for (i = 0; i < STE_RX_LIST_CNT; i++) { 143150128Swpaul cd->ste_rx_chain[i].ste_ptr = &ld->ste_rx_list[i]; 1432200853Syongari error = ste_newbuf(sc, &cd->ste_rx_chain[i]); 1433200853Syongari if (error != 0) 1434200853Syongari return (error); 143550128Swpaul if (i == (STE_RX_LIST_CNT - 1)) { 1436200853Syongari cd->ste_rx_chain[i].ste_next = &cd->ste_rx_chain[0]; 1437201768Syongari ld->ste_rx_list[i].ste_next = 1438201768Syongari htole32(ld->ste_rx_list_paddr + 1439201768Syongari (sizeof(struct ste_desc_onefrag) * 0)); 144050128Swpaul } else { 1441200853Syongari cd->ste_rx_chain[i].ste_next = &cd->ste_rx_chain[i + 1]; 1442201768Syongari ld->ste_rx_list[i].ste_next = 1443201768Syongari htole32(ld->ste_rx_list_paddr + 1444201768Syongari (sizeof(struct ste_desc_onefrag) * (i + 1))); 144550128Swpaul } 144650128Swpaul } 144750128Swpaul 144850128Swpaul cd->ste_rx_head = &cd->ste_rx_chain[0]; 1449200853Syongari bus_dmamap_sync(sc->ste_cdata.ste_rx_list_tag, 1450200853Syongari sc->ste_cdata.ste_rx_list_map, 1451200853Syongari BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 145250128Swpaul 1453200808Syongari return (0); 145450128Swpaul} 145550128Swpaul 1456102335Salfredstatic void 1457200798Syongariste_init_tx_list(struct ste_softc *sc) 145850128Swpaul{ 1459200808Syongari struct ste_chain_data *cd; 1460200808Syongari struct ste_list_data *ld; 1461200808Syongari int i; 146250128Swpaul 146350128Swpaul cd = &sc->ste_cdata; 1464200853Syongari ld = &sc->ste_ldata; 1465200853Syongari bzero(ld->ste_tx_list, STE_TX_LIST_SZ); 146650128Swpaul for (i = 0; i < STE_TX_LIST_CNT; i++) { 146750128Swpaul cd->ste_tx_chain[i].ste_ptr = &ld->ste_tx_list[i]; 1468200853Syongari cd->ste_tx_chain[i].ste_mbuf = NULL; 1469200853Syongari if (i == (STE_TX_LIST_CNT - 1)) { 1470200853Syongari cd->ste_tx_chain[i].ste_next = &cd->ste_tx_chain[0]; 1471200853Syongari cd->ste_tx_chain[i].ste_phys = htole32(STE_ADDR_LO( 1472200853Syongari ld->ste_tx_list_paddr + 1473200853Syongari (sizeof(struct ste_desc) * 0))); 1474200853Syongari } else { 1475200853Syongari cd->ste_tx_chain[i].ste_next = &cd->ste_tx_chain[i + 1]; 1476200853Syongari cd->ste_tx_chain[i].ste_phys = htole32(STE_ADDR_LO( 1477200853Syongari ld->ste_tx_list_paddr + 1478200853Syongari (sizeof(struct ste_desc) * (i + 1)))); 1479200853Syongari } 148050128Swpaul } 148150128Swpaul 1482200853Syongari cd->ste_last_tx = NULL; 148354268Swpaul cd->ste_tx_prod = 0; 148454268Swpaul cd->ste_tx_cons = 0; 1485200853Syongari cd->ste_tx_cnt = 0; 1486200853Syongari 1487200853Syongari bus_dmamap_sync(sc->ste_cdata.ste_tx_list_tag, 1488200853Syongari sc->ste_cdata.ste_tx_list_map, 1489200853Syongari BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 149050128Swpaul} 149150128Swpaul 1492102335Salfredstatic void 1493200798Syongariste_init(void *xsc) 149450128Swpaul{ 1495200808Syongari struct ste_softc *sc; 1496149646Sjhb 1497149646Sjhb sc = xsc; 1498149646Sjhb STE_LOCK(sc); 1499149646Sjhb ste_init_locked(sc); 1500149646Sjhb STE_UNLOCK(sc); 1501149646Sjhb} 1502149646Sjhb 1503149646Sjhbstatic void 1504200798Syongariste_init_locked(struct ste_softc *sc) 1505149646Sjhb{ 1506200808Syongari struct ifnet *ifp; 1507200908Syongari struct mii_data *mii; 1508200955Syongari uint8_t val; 1509200808Syongari int i; 151050128Swpaul 1511149646Sjhb STE_LOCK_ASSERT(sc); 1512147256Sbrooks ifp = sc->ste_ifp; 1513200908Syongari mii = device_get_softc(sc->ste_miibus); 151450128Swpaul 1515200904Syongari if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0) 1516200904Syongari return; 1517200904Syongari 151850128Swpaul ste_stop(sc); 1519200873Syongari /* Reset the chip to a known state. */ 1520200873Syongari ste_reset(sc); 152150128Swpaul 152250128Swpaul /* Init our MAC address */ 1523170794Sthompsa for (i = 0; i < ETHER_ADDR_LEN; i += 2) { 1524170794Sthompsa CSR_WRITE_2(sc, STE_PAR0 + i, 1525170794Sthompsa ((IF_LLADDR(sc->ste_ifp)[i] & 0xff) | 1526170794Sthompsa IF_LLADDR(sc->ste_ifp)[i + 1] << 8)); 152750128Swpaul } 152850128Swpaul 152950128Swpaul /* Init RX list */ 1530200853Syongari if (ste_init_rx_list(sc) != 0) { 1531162315Sglebius device_printf(sc->ste_dev, 1532149189Sjhb "initialization failed: no memory for RX buffers\n"); 153350128Swpaul ste_stop(sc); 153450128Swpaul return; 153550128Swpaul } 153650128Swpaul 1537101493Sambrisko /* Set RX polling interval */ 1538127688Sru CSR_WRITE_1(sc, STE_RX_DMAPOLL_PERIOD, 64); 1539101493Sambrisko 154050128Swpaul /* Init TX descriptors */ 154150128Swpaul ste_init_tx_list(sc); 154250128Swpaul 1543200955Syongari /* Clear and disable WOL. */ 1544200955Syongari val = CSR_READ_1(sc, STE_WAKE_EVENT); 1545200955Syongari val &= ~(STE_WAKEEVENT_WAKEPKT_ENB | STE_WAKEEVENT_MAGICPKT_ENB | 1546200955Syongari STE_WAKEEVENT_LINKEVT_ENB | STE_WAKEEVENT_WAKEONLAN_ENB); 1547200955Syongari CSR_WRITE_1(sc, STE_WAKE_EVENT, val); 1548200955Syongari 154950128Swpaul /* Set the TX freethresh value */ 155050128Swpaul CSR_WRITE_1(sc, STE_TX_DMABURST_THRESH, STE_PACKET_SIZE >> 8); 155150128Swpaul 155250128Swpaul /* Set the TX start threshold for best performance. */ 155350128Swpaul CSR_WRITE_2(sc, STE_TX_STARTTHRESH, sc->ste_tx_thresh); 155450128Swpaul 155550128Swpaul /* Set the TX reclaim threshold. */ 155650128Swpaul CSR_WRITE_1(sc, STE_TX_RECLAIM_THRESH, (STE_PACKET_SIZE >> 4)); 155750128Swpaul 1558200906Syongari /* Accept VLAN length packets */ 1559200906Syongari CSR_WRITE_2(sc, STE_MAX_FRAMELEN, ETHER_MAX_LEN + ETHER_VLAN_ENCAP_LEN); 1560200906Syongari 156150128Swpaul /* Set up the RX filter. */ 1562200906Syongari ste_rxfilter(sc); 156350128Swpaul 156450128Swpaul /* Load the address of the RX list. */ 156550128Swpaul STE_SETBIT4(sc, STE_DMACTL, STE_DMACTL_RXDMA_STALL); 156650128Swpaul ste_wait(sc); 156750128Swpaul CSR_WRITE_4(sc, STE_RX_DMALIST_PTR, 1568200853Syongari STE_ADDR_LO(sc->ste_ldata.ste_rx_list_paddr)); 156950128Swpaul STE_SETBIT4(sc, STE_DMACTL, STE_DMACTL_RXDMA_UNSTALL); 157050128Swpaul STE_SETBIT4(sc, STE_DMACTL, STE_DMACTL_RXDMA_UNSTALL); 157150128Swpaul 1572200853Syongari /* Set TX polling interval(defer until we TX first packet). */ 1573101493Sambrisko CSR_WRITE_1(sc, STE_TX_DMAPOLL_PERIOD, 0); 157454268Swpaul 157554268Swpaul /* Load address of the TX list */ 157654268Swpaul STE_SETBIT4(sc, STE_DMACTL, STE_DMACTL_TXDMA_STALL); 157754268Swpaul ste_wait(sc); 1578101493Sambrisko CSR_WRITE_4(sc, STE_TX_DMALIST_PTR, 0); 157954268Swpaul STE_SETBIT4(sc, STE_DMACTL, STE_DMACTL_TXDMA_UNSTALL); 158054268Swpaul STE_SETBIT4(sc, STE_DMACTL, STE_DMACTL_TXDMA_UNSTALL); 158154268Swpaul ste_wait(sc); 1582200950Syongari /* Select 3.2us timer. */ 1583200950Syongari STE_CLRBIT4(sc, STE_DMACTL, STE_DMACTL_COUNTDOWN_SPEED | 1584200950Syongari STE_DMACTL_COUNTDOWN_MODE); 158554268Swpaul 158650128Swpaul /* Enable receiver and transmitter */ 158750128Swpaul CSR_WRITE_2(sc, STE_MACCTL0, 0); 1588101493Sambrisko CSR_WRITE_2(sc, STE_MACCTL1, 0); 158950128Swpaul STE_SETBIT2(sc, STE_MACCTL1, STE_MACCTL1_TX_ENABLE); 159050128Swpaul STE_SETBIT2(sc, STE_MACCTL1, STE_MACCTL1_RX_ENABLE); 159150128Swpaul 159250128Swpaul /* Enable stats counters. */ 159350128Swpaul STE_SETBIT2(sc, STE_MACCTL1, STE_MACCTL1_STATS_ENABLE); 1594200910Syongari /* Clear stats counters. */ 1595200910Syongari ste_stats_clear(sc); 159650128Swpaul 1597200950Syongari CSR_WRITE_2(sc, STE_COUNTDOWN, 0); 1598127686Sru CSR_WRITE_2(sc, STE_ISR, 0xFFFF); 1599127686Sru#ifdef DEVICE_POLLING 1600127686Sru /* Disable interrupts if we are polling. */ 1601150789Sglebius if (ifp->if_capenable & IFCAP_POLLING) 1602127686Sru CSR_WRITE_2(sc, STE_IMR, 0); 1603200804Syongari else 1604150789Sglebius#endif 160550128Swpaul /* Enable interrupts. */ 160650128Swpaul CSR_WRITE_2(sc, STE_IMR, STE_INTRS); 160750128Swpaul 1608200908Syongari sc->ste_flags &= ~STE_FLAG_LINK; 1609200908Syongari /* Switch to the current media. */ 1610200908Syongari mii_mediachg(mii); 161150128Swpaul 1612148887Srwatson ifp->if_drv_flags |= IFF_DRV_RUNNING; 1613148887Srwatson ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 161450128Swpaul 1615200865Syongari callout_reset(&sc->ste_callout, hz, ste_tick, sc); 161650128Swpaul} 161750128Swpaul 1618102335Salfredstatic void 1619200798Syongariste_stop(struct ste_softc *sc) 162050128Swpaul{ 1621200808Syongari struct ifnet *ifp; 1622200853Syongari struct ste_chain_onefrag *cur_rx; 1623200853Syongari struct ste_chain *cur_tx; 1624200873Syongari uint32_t val; 1625200808Syongari int i; 162650128Swpaul 1627149646Sjhb STE_LOCK_ASSERT(sc); 1628147256Sbrooks ifp = sc->ste_ifp; 162950128Swpaul 1630200865Syongari callout_stop(&sc->ste_callout); 1631200865Syongari sc->ste_timer = 0; 1632148887Srwatson ifp->if_drv_flags &= ~(IFF_DRV_RUNNING|IFF_DRV_OACTIVE); 163350128Swpaul 163450128Swpaul CSR_WRITE_2(sc, STE_IMR, 0); 1635200950Syongari CSR_WRITE_2(sc, STE_COUNTDOWN, 0); 1636200873Syongari /* Stop pending DMA. */ 1637200873Syongari val = CSR_READ_4(sc, STE_DMACTL); 1638200873Syongari val |= STE_DMACTL_TXDMA_STALL | STE_DMACTL_RXDMA_STALL; 1639200873Syongari CSR_WRITE_4(sc, STE_DMACTL, val); 164050128Swpaul ste_wait(sc); 1641200873Syongari /* Disable auto-polling. */ 1642200873Syongari CSR_WRITE_1(sc, STE_RX_DMAPOLL_PERIOD, 0); 1643200873Syongari CSR_WRITE_1(sc, STE_TX_DMAPOLL_PERIOD, 0); 1644200873Syongari /* Nullify DMA address to stop any further DMA. */ 1645200873Syongari CSR_WRITE_4(sc, STE_RX_DMALIST_PTR, 0); 1646200873Syongari CSR_WRITE_4(sc, STE_TX_DMALIST_PTR, 0); 1647200873Syongari /* Stop TX/RX MAC. */ 1648200873Syongari val = CSR_READ_2(sc, STE_MACCTL1); 1649200873Syongari val |= STE_MACCTL1_TX_DISABLE | STE_MACCTL1_RX_DISABLE | 1650200873Syongari STE_MACCTL1_STATS_DISABLE; 1651200873Syongari CSR_WRITE_2(sc, STE_MACCTL1, val); 1652200873Syongari for (i = 0; i < STE_TIMEOUT; i++) { 1653200873Syongari DELAY(10); 1654200873Syongari if ((CSR_READ_2(sc, STE_MACCTL1) & (STE_MACCTL1_TX_DISABLE | 1655200873Syongari STE_MACCTL1_RX_DISABLE | STE_MACCTL1_STATS_DISABLE)) == 0) 1656200873Syongari break; 1657200873Syongari } 1658200873Syongari if (i == STE_TIMEOUT) 1659200873Syongari device_printf(sc->ste_dev, "Stopping MAC timed out\n"); 1660200873Syongari /* Acknowledge any pending interrupts. */ 1661200873Syongari CSR_READ_2(sc, STE_ISR_ACK); 1662200873Syongari ste_stats_update(sc); 166350128Swpaul 166450128Swpaul for (i = 0; i < STE_RX_LIST_CNT; i++) { 1665200853Syongari cur_rx = &sc->ste_cdata.ste_rx_chain[i]; 1666200853Syongari if (cur_rx->ste_mbuf != NULL) { 1667200853Syongari bus_dmamap_sync(sc->ste_cdata.ste_rx_tag, 1668200853Syongari cur_rx->ste_map, BUS_DMASYNC_POSTREAD); 1669200853Syongari bus_dmamap_unload(sc->ste_cdata.ste_rx_tag, 1670200853Syongari cur_rx->ste_map); 1671200853Syongari m_freem(cur_rx->ste_mbuf); 1672200853Syongari cur_rx->ste_mbuf = NULL; 167350128Swpaul } 167450128Swpaul } 167550128Swpaul 167650128Swpaul for (i = 0; i < STE_TX_LIST_CNT; i++) { 1677200853Syongari cur_tx = &sc->ste_cdata.ste_tx_chain[i]; 1678200853Syongari if (cur_tx->ste_mbuf != NULL) { 1679200853Syongari bus_dmamap_sync(sc->ste_cdata.ste_tx_tag, 1680200853Syongari cur_tx->ste_map, BUS_DMASYNC_POSTWRITE); 1681200853Syongari bus_dmamap_unload(sc->ste_cdata.ste_tx_tag, 1682200853Syongari cur_tx->ste_map); 1683200853Syongari m_freem(cur_tx->ste_mbuf); 1684200853Syongari cur_tx->ste_mbuf = NULL; 168550128Swpaul } 168650128Swpaul } 168750128Swpaul} 168850128Swpaul 1689102335Salfredstatic void 1690200798Syongariste_reset(struct ste_softc *sc) 169150128Swpaul{ 1692200905Syongari uint32_t ctl; 1693200808Syongari int i; 169450128Swpaul 1695200905Syongari ctl = CSR_READ_4(sc, STE_ASICCTL); 1696200905Syongari ctl |= STE_ASICCTL_GLOBAL_RESET | STE_ASICCTL_RX_RESET | 1697200905Syongari STE_ASICCTL_TX_RESET | STE_ASICCTL_DMA_RESET | 1698200905Syongari STE_ASICCTL_FIFO_RESET | STE_ASICCTL_NETWORK_RESET | 1699200905Syongari STE_ASICCTL_AUTOINIT_RESET |STE_ASICCTL_HOST_RESET | 1700200905Syongari STE_ASICCTL_EXTRESET_RESET; 1701200905Syongari CSR_WRITE_4(sc, STE_ASICCTL, ctl); 1702200905Syongari CSR_READ_4(sc, STE_ASICCTL); 1703200905Syongari /* 1704200905Syongari * Due to the need of accessing EEPROM controller can take 1705200905Syongari * up to 1ms to complete the global reset. 1706200905Syongari */ 1707200905Syongari DELAY(1000); 170850128Swpaul 170950128Swpaul for (i = 0; i < STE_TIMEOUT; i++) { 171050128Swpaul if (!(CSR_READ_4(sc, STE_ASICCTL) & STE_ASICCTL_RESET_BUSY)) 171150128Swpaul break; 1712200905Syongari DELAY(10); 171350128Swpaul } 171450128Swpaul 171550128Swpaul if (i == STE_TIMEOUT) 1716162315Sglebius device_printf(sc->ste_dev, "global reset never completed\n"); 171750128Swpaul} 171850128Swpaul 1719200884Syongaristatic void 1720200884Syongariste_restart_tx(struct ste_softc *sc) 1721200884Syongari{ 1722200884Syongari uint16_t mac; 1723200884Syongari int i; 1724200884Syongari 1725200884Syongari for (i = 0; i < STE_TIMEOUT; i++) { 1726200884Syongari mac = CSR_READ_2(sc, STE_MACCTL1); 1727200884Syongari mac |= STE_MACCTL1_TX_ENABLE; 1728200884Syongari CSR_WRITE_2(sc, STE_MACCTL1, mac); 1729200884Syongari mac = CSR_READ_2(sc, STE_MACCTL1); 1730200884Syongari if ((mac & STE_MACCTL1_TX_ENABLED) != 0) 1731200884Syongari break; 1732200884Syongari DELAY(10); 1733200884Syongari } 1734200884Syongari 1735200884Syongari if (i == STE_TIMEOUT) 1736200884Syongari device_printf(sc->ste_dev, "starting Tx failed"); 1737200884Syongari} 1738200884Syongari 1739102335Salfredstatic int 1740200798Syongariste_ioctl(struct ifnet *ifp, u_long command, caddr_t data) 174150128Swpaul{ 1742200808Syongari struct ste_softc *sc; 1743200808Syongari struct ifreq *ifr; 1744200808Syongari struct mii_data *mii; 1745200955Syongari int error = 0, mask; 174650128Swpaul 174750128Swpaul sc = ifp->if_softc; 174850128Swpaul ifr = (struct ifreq *)data; 174950128Swpaul 1750200808Syongari switch (command) { 175150128Swpaul case SIOCSIFFLAGS: 1752149646Sjhb STE_LOCK(sc); 1753200906Syongari if ((ifp->if_flags & IFF_UP) != 0) { 1754200906Syongari if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0 && 1755200906Syongari ((ifp->if_flags ^ sc->ste_if_flags) & 1756200906Syongari (IFF_PROMISC | IFF_ALLMULTI)) != 0) 1757200906Syongari ste_rxfilter(sc); 1758200906Syongari else 1759149646Sjhb ste_init_locked(sc); 1760200906Syongari } else if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0) 1761200906Syongari ste_stop(sc); 176254268Swpaul sc->ste_if_flags = ifp->if_flags; 1763149646Sjhb STE_UNLOCK(sc); 176450128Swpaul break; 176550128Swpaul case SIOCADDMULTI: 176650128Swpaul case SIOCDELMULTI: 1767149646Sjhb STE_LOCK(sc); 1768200906Syongari if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0) 1769200906Syongari ste_rxfilter(sc); 1770149646Sjhb STE_UNLOCK(sc); 177150128Swpaul break; 177250128Swpaul case SIOCGIFMEDIA: 177350128Swpaul case SIOCSIFMEDIA: 177450128Swpaul mii = device_get_softc(sc->ste_miibus); 177550128Swpaul error = ifmedia_ioctl(ifp, ifr, &mii->mii_media, command); 177650128Swpaul break; 1777128117Sru case SIOCSIFCAP: 1778200955Syongari STE_LOCK(sc); 1779200955Syongari mask = ifr->ifr_reqcap ^ ifp->if_capenable; 1780150789Sglebius#ifdef DEVICE_POLLING 1781200955Syongari if ((mask & IFCAP_POLLING) != 0 && 1782200955Syongari (IFCAP_POLLING & ifp->if_capabilities) != 0) { 1783200955Syongari ifp->if_capenable ^= IFCAP_POLLING; 1784200955Syongari if ((IFCAP_POLLING & ifp->if_capenable) != 0) { 1785200955Syongari error = ether_poll_register(ste_poll, ifp); 1786200955Syongari if (error != 0) { 1787200955Syongari STE_UNLOCK(sc); 1788200955Syongari break; 1789200955Syongari } 1790200955Syongari /* Disable interrupts. */ 1791200955Syongari CSR_WRITE_2(sc, STE_IMR, 0); 1792200955Syongari } else { 1793200955Syongari error = ether_poll_deregister(ifp); 1794200955Syongari /* Enable interrupts. */ 1795200955Syongari CSR_WRITE_2(sc, STE_IMR, STE_INTRS); 1796200955Syongari } 1797150789Sglebius } 1798150789Sglebius#endif /* DEVICE_POLLING */ 1799200955Syongari if ((mask & IFCAP_WOL_MAGIC) != 0 && 1800200955Syongari (ifp->if_capabilities & IFCAP_WOL_MAGIC) != 0) 1801200955Syongari ifp->if_capenable ^= IFCAP_WOL_MAGIC; 1802200955Syongari STE_UNLOCK(sc); 1803128117Sru break; 180450128Swpaul default: 1805106936Ssam error = ether_ioctl(ifp, command, data); 180650128Swpaul break; 180750128Swpaul } 180850128Swpaul 1809200808Syongari return (error); 181050128Swpaul} 181150128Swpaul 1812102335Salfredstatic int 1813200853Syongariste_encap(struct ste_softc *sc, struct mbuf **m_head, struct ste_chain *txc) 181450128Swpaul{ 1815200853Syongari struct ste_frag *frag; 1816200808Syongari struct mbuf *m; 1817200853Syongari struct ste_desc *desc; 1818200853Syongari bus_dma_segment_t txsegs[STE_MAXFRAGS]; 1819200853Syongari int error, i, nsegs; 182050128Swpaul 1821200853Syongari STE_LOCK_ASSERT(sc); 1822200853Syongari M_ASSERTPKTHDR((*m_head)); 182350128Swpaul 1824200853Syongari error = bus_dmamap_load_mbuf_sg(sc->ste_cdata.ste_tx_tag, 1825200853Syongari txc->ste_map, *m_head, txsegs, &nsegs, 0); 1826200853Syongari if (error == EFBIG) { 1827243857Sglebius m = m_collapse(*m_head, M_NOWAIT, STE_MAXFRAGS); 1828200853Syongari if (m == NULL) { 1829200853Syongari m_freem(*m_head); 1830200853Syongari *m_head = NULL; 1831200853Syongari return (ENOMEM); 183250128Swpaul } 1833200853Syongari *m_head = m; 1834200853Syongari error = bus_dmamap_load_mbuf_sg(sc->ste_cdata.ste_tx_tag, 1835200853Syongari txc->ste_map, *m_head, txsegs, &nsegs, 0); 1836200853Syongari if (error != 0) { 1837200853Syongari m_freem(*m_head); 1838200853Syongari *m_head = NULL; 1839200853Syongari return (error); 1840200853Syongari } 1841200853Syongari } else if (error != 0) 1842200853Syongari return (error); 1843200853Syongari if (nsegs == 0) { 1844200853Syongari m_freem(*m_head); 1845200853Syongari *m_head = NULL; 1846200853Syongari return (EIO); 184750128Swpaul } 1848200853Syongari bus_dmamap_sync(sc->ste_cdata.ste_tx_tag, txc->ste_map, 1849200853Syongari BUS_DMASYNC_PREWRITE); 185050128Swpaul 1851200853Syongari desc = txc->ste_ptr; 1852200853Syongari for (i = 0; i < nsegs; i++) { 1853200853Syongari frag = &desc->ste_frags[i]; 1854200853Syongari frag->ste_addr = htole32(STE_ADDR_LO(txsegs[i].ds_addr)); 1855200853Syongari frag->ste_len = htole32(txsegs[i].ds_len); 1856103238Sambrisko } 1857200853Syongari desc->ste_frags[i - 1].ste_len |= htole32(STE_FRAG_LAST); 1858200853Syongari /* 1859200853Syongari * Because we use Tx polling we can't chain multiple 1860200853Syongari * Tx descriptors here. Otherwise we race with controller. 1861200853Syongari */ 1862200853Syongari desc->ste_next = 0; 1863200913Syongari if ((sc->ste_cdata.ste_tx_prod % STE_TX_INTR_FRAMES) == 0) 1864200913Syongari desc->ste_ctl = htole32(STE_TXCTL_ALIGN_DIS | 1865200913Syongari STE_TXCTL_DMAINTR); 1866200913Syongari else 1867200913Syongari desc->ste_ctl = htole32(STE_TXCTL_ALIGN_DIS); 1868200853Syongari txc->ste_mbuf = *m_head; 1869200853Syongari STE_INC(sc->ste_cdata.ste_tx_prod, STE_TX_LIST_CNT); 1870200853Syongari sc->ste_cdata.ste_tx_cnt++; 1871103238Sambrisko 1872200808Syongari return (0); 187350128Swpaul} 187450128Swpaul 1875102335Salfredstatic void 1876200798Syongariste_start(struct ifnet *ifp) 187750128Swpaul{ 1878200808Syongari struct ste_softc *sc; 1879149646Sjhb 1880149646Sjhb sc = ifp->if_softc; 1881149646Sjhb STE_LOCK(sc); 1882149646Sjhb ste_start_locked(ifp); 1883149646Sjhb STE_UNLOCK(sc); 1884149646Sjhb} 1885149646Sjhb 1886149646Sjhbstatic void 1887200798Syongariste_start_locked(struct ifnet *ifp) 1888149646Sjhb{ 1889200808Syongari struct ste_softc *sc; 1890200808Syongari struct ste_chain *cur_tx; 1891200808Syongari struct mbuf *m_head = NULL; 1892200853Syongari int enq; 189350128Swpaul 189450128Swpaul sc = ifp->if_softc; 1895149646Sjhb STE_LOCK_ASSERT(sc); 189650128Swpaul 1897200856Syongari if ((ifp->if_drv_flags & (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)) != 1898200856Syongari IFF_DRV_RUNNING || (sc->ste_flags & STE_FLAG_LINK) == 0) 189950128Swpaul return; 190050128Swpaul 1901200853Syongari for (enq = 0; !IFQ_DRV_IS_EMPTY(&ifp->if_snd);) { 1902200853Syongari if (sc->ste_cdata.ste_tx_cnt == STE_TX_LIST_CNT - 1) { 1903200853Syongari /* 1904200853Syongari * Controller may have cached copy of the last used 1905200853Syongari * next ptr so we have to reserve one TFD to avoid 1906200853Syongari * TFD overruns. 1907200853Syongari */ 1908148887Srwatson ifp->if_drv_flags |= IFF_DRV_OACTIVE; 190954268Swpaul break; 191054268Swpaul } 1911147828Smlaier IFQ_DRV_DEQUEUE(&ifp->if_snd, m_head); 191250128Swpaul if (m_head == NULL) 191350128Swpaul break; 1914200853Syongari cur_tx = &sc->ste_cdata.ste_tx_chain[sc->ste_cdata.ste_tx_prod]; 1915200853Syongari if (ste_encap(sc, &m_head, cur_tx) != 0) { 1916200853Syongari if (m_head == NULL) 1917200853Syongari break; 1918200853Syongari IFQ_DRV_PREPEND(&ifp->if_snd, m_head); 1919103238Sambrisko break; 1920200853Syongari } 1921200853Syongari if (sc->ste_cdata.ste_last_tx == NULL) { 1922200853Syongari bus_dmamap_sync(sc->ste_cdata.ste_tx_list_tag, 1923200853Syongari sc->ste_cdata.ste_tx_list_map, 1924200853Syongari BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 1925101493Sambrisko STE_SETBIT4(sc, STE_DMACTL, STE_DMACTL_TXDMA_STALL); 1926101493Sambrisko ste_wait(sc); 1927101493Sambrisko CSR_WRITE_4(sc, STE_TX_DMALIST_PTR, 1928200853Syongari STE_ADDR_LO(sc->ste_ldata.ste_tx_list_paddr)); 1929101493Sambrisko CSR_WRITE_1(sc, STE_TX_DMAPOLL_PERIOD, 64); 1930101493Sambrisko STE_SETBIT4(sc, STE_DMACTL, STE_DMACTL_TXDMA_UNSTALL); 1931101493Sambrisko ste_wait(sc); 1932200853Syongari } else { 1933200853Syongari sc->ste_cdata.ste_last_tx->ste_ptr->ste_next = 1934200853Syongari sc->ste_cdata.ste_last_tx->ste_phys; 1935200853Syongari bus_dmamap_sync(sc->ste_cdata.ste_tx_list_tag, 1936200853Syongari sc->ste_cdata.ste_tx_list_map, 1937200853Syongari BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 1938101493Sambrisko } 1939200853Syongari sc->ste_cdata.ste_last_tx = cur_tx; 1940101493Sambrisko 1941200853Syongari enq++; 194250128Swpaul /* 194354268Swpaul * If there's a BPF listener, bounce a copy of this frame 194450128Swpaul * to him. 194550128Swpaul */ 1946200853Syongari BPF_MTAP(ifp, m_head); 1947200853Syongari } 194854268Swpaul 1949200853Syongari if (enq > 0) 1950200853Syongari sc->ste_timer = STE_TX_TIMEOUT; 195150128Swpaul} 195250128Swpaul 1953102335Salfredstatic void 1954199559Sjhbste_watchdog(struct ste_softc *sc) 1955199559Sjhb{ 1956200808Syongari struct ifnet *ifp; 195750128Swpaul 1958199559Sjhb ifp = sc->ste_ifp; 1959199559Sjhb STE_LOCK_ASSERT(sc); 196050128Swpaul 1961200865Syongari if (sc->ste_timer == 0 || --sc->ste_timer) 1962200865Syongari return; 1963200865Syongari 196450128Swpaul ifp->if_oerrors++; 1965149189Sjhb if_printf(ifp, "watchdog timeout\n"); 196650128Swpaul 1967200884Syongari ste_txeof(sc); 196850128Swpaul ste_txeoc(sc); 1969200853Syongari ste_rxeof(sc, -1); 1970200904Syongari ifp->if_drv_flags &= ~IFF_DRV_RUNNING; 1971149646Sjhb ste_init_locked(sc); 197250128Swpaul 1973147828Smlaier if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) 1974149646Sjhb ste_start_locked(ifp); 197550128Swpaul} 197650128Swpaul 1977173839Syongaristatic int 1978200798Syongariste_shutdown(device_t dev) 197950128Swpaul{ 1980200955Syongari 1981200955Syongari return (ste_suspend(dev)); 1982200955Syongari} 1983200955Syongari 1984200955Syongaristatic int 1985200955Syongariste_suspend(device_t dev) 1986200955Syongari{ 1987200808Syongari struct ste_softc *sc; 198850128Swpaul 198950128Swpaul sc = device_get_softc(dev); 199050128Swpaul 1991149646Sjhb STE_LOCK(sc); 199250128Swpaul ste_stop(sc); 1993200955Syongari ste_setwol(sc); 1994149646Sjhb STE_UNLOCK(sc); 199550128Swpaul 1996173839Syongari return (0); 199750128Swpaul} 1998200910Syongari 1999200955Syongaristatic int 2000200955Syongariste_resume(device_t dev) 2001200955Syongari{ 2002200955Syongari struct ste_softc *sc; 2003200955Syongari struct ifnet *ifp; 2004200955Syongari int pmc; 2005200955Syongari uint16_t pmstat; 2006200955Syongari 2007200955Syongari sc = device_get_softc(dev); 2008200955Syongari STE_LOCK(sc); 2009219902Sjhb if (pci_find_cap(sc->ste_dev, PCIY_PMG, &pmc) == 0) { 2010200955Syongari /* Disable PME and clear PME status. */ 2011200955Syongari pmstat = pci_read_config(sc->ste_dev, 2012200955Syongari pmc + PCIR_POWER_STATUS, 2); 2013200955Syongari if ((pmstat & PCIM_PSTAT_PMEENABLE) != 0) { 2014200955Syongari pmstat &= ~PCIM_PSTAT_PMEENABLE; 2015200955Syongari pci_write_config(sc->ste_dev, 2016200955Syongari pmc + PCIR_POWER_STATUS, pmstat, 2); 2017200955Syongari } 2018200955Syongari } 2019200955Syongari ifp = sc->ste_ifp; 2020200955Syongari if ((ifp->if_flags & IFF_UP) != 0) { 2021200955Syongari ifp->if_drv_flags &= ~IFF_DRV_RUNNING; 2022200955Syongari ste_init_locked(sc); 2023200955Syongari } 2024200955Syongari STE_UNLOCK(sc); 2025200955Syongari 2026200955Syongari return (0); 2027200955Syongari} 2028200955Syongari 2029200910Syongari#define STE_SYSCTL_STAT_ADD32(c, h, n, p, d) \ 2030200910Syongari SYSCTL_ADD_UINT(c, h, OID_AUTO, n, CTLFLAG_RD, p, 0, d) 2031200910Syongari#define STE_SYSCTL_STAT_ADD64(c, h, n, p, d) \ 2032217323Smdf SYSCTL_ADD_UQUAD(c, h, OID_AUTO, n, CTLFLAG_RD, p, d) 2033200910Syongari 2034200910Syongaristatic void 2035200910Syongariste_sysctl_node(struct ste_softc *sc) 2036200910Syongari{ 2037200910Syongari struct sysctl_ctx_list *ctx; 2038200910Syongari struct sysctl_oid_list *child, *parent; 2039200910Syongari struct sysctl_oid *tree; 2040200910Syongari struct ste_hw_stats *stats; 2041200910Syongari 2042200910Syongari stats = &sc->ste_stats; 2043200910Syongari ctx = device_get_sysctl_ctx(sc->ste_dev); 2044200910Syongari child = SYSCTL_CHILDREN(device_get_sysctl_tree(sc->ste_dev)); 2045200910Syongari 2046200950Syongari SYSCTL_ADD_INT(ctx, child, OID_AUTO, "int_rx_mod", 2047200950Syongari CTLFLAG_RW, &sc->ste_int_rx_mod, 0, "ste RX interrupt moderation"); 2048200950Syongari /* Pull in device tunables. */ 2049200950Syongari sc->ste_int_rx_mod = STE_IM_RX_TIMER_DEFAULT; 2050200950Syongari resource_int_value(device_get_name(sc->ste_dev), 2051200950Syongari device_get_unit(sc->ste_dev), "int_rx_mod", &sc->ste_int_rx_mod); 2052200950Syongari 2053200910Syongari tree = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, "stats", CTLFLAG_RD, 2054200910Syongari NULL, "STE statistics"); 2055200910Syongari parent = SYSCTL_CHILDREN(tree); 2056200910Syongari 2057200910Syongari /* Rx statistics. */ 2058200910Syongari tree = SYSCTL_ADD_NODE(ctx, parent, OID_AUTO, "rx", CTLFLAG_RD, 2059200910Syongari NULL, "Rx MAC statistics"); 2060200910Syongari child = SYSCTL_CHILDREN(tree); 2061200910Syongari STE_SYSCTL_STAT_ADD64(ctx, child, "good_octets", 2062200910Syongari &stats->rx_bytes, "Good octets"); 2063200910Syongari STE_SYSCTL_STAT_ADD32(ctx, child, "good_frames", 2064200910Syongari &stats->rx_frames, "Good frames"); 2065200910Syongari STE_SYSCTL_STAT_ADD32(ctx, child, "good_bcast_frames", 2066200910Syongari &stats->rx_bcast_frames, "Good broadcast frames"); 2067200910Syongari STE_SYSCTL_STAT_ADD32(ctx, child, "good_mcast_frames", 2068200910Syongari &stats->rx_mcast_frames, "Good multicast frames"); 2069200910Syongari STE_SYSCTL_STAT_ADD32(ctx, child, "lost_frames", 2070200910Syongari &stats->rx_lost_frames, "Lost frames"); 2071200910Syongari 2072200910Syongari /* Tx statistics. */ 2073200910Syongari tree = SYSCTL_ADD_NODE(ctx, parent, OID_AUTO, "tx", CTLFLAG_RD, 2074200910Syongari NULL, "Tx MAC statistics"); 2075200910Syongari child = SYSCTL_CHILDREN(tree); 2076200910Syongari STE_SYSCTL_STAT_ADD64(ctx, child, "good_octets", 2077200910Syongari &stats->tx_bytes, "Good octets"); 2078200910Syongari STE_SYSCTL_STAT_ADD32(ctx, child, "good_frames", 2079200910Syongari &stats->tx_frames, "Good frames"); 2080200910Syongari STE_SYSCTL_STAT_ADD32(ctx, child, "good_bcast_frames", 2081200910Syongari &stats->tx_bcast_frames, "Good broadcast frames"); 2082200910Syongari STE_SYSCTL_STAT_ADD32(ctx, child, "good_mcast_frames", 2083200910Syongari &stats->tx_mcast_frames, "Good multicast frames"); 2084200910Syongari STE_SYSCTL_STAT_ADD32(ctx, child, "carrier_errs", 2085200910Syongari &stats->tx_carrsense_errs, "Carrier sense errors"); 2086200910Syongari STE_SYSCTL_STAT_ADD32(ctx, child, "single_colls", 2087200910Syongari &stats->tx_single_colls, "Single collisions"); 2088200910Syongari STE_SYSCTL_STAT_ADD32(ctx, child, "multi_colls", 2089200910Syongari &stats->tx_multi_colls, "Multiple collisions"); 2090200910Syongari STE_SYSCTL_STAT_ADD32(ctx, child, "late_colls", 2091200910Syongari &stats->tx_late_colls, "Late collisions"); 2092200910Syongari STE_SYSCTL_STAT_ADD32(ctx, child, "defers", 2093200910Syongari &stats->tx_frames_defered, "Frames with deferrals"); 2094200910Syongari STE_SYSCTL_STAT_ADD32(ctx, child, "excess_defers", 2095200910Syongari &stats->tx_excess_defers, "Frames with excessive derferrals"); 2096200910Syongari STE_SYSCTL_STAT_ADD32(ctx, child, "abort", 2097200910Syongari &stats->tx_abort, "Aborted frames due to Excessive collisions"); 2098200910Syongari} 2099200910Syongari 2100200910Syongari#undef STE_SYSCTL_STAT_ADD32 2101200910Syongari#undef STE_SYSCTL_STAT_ADD64 2102200955Syongari 2103200955Syongaristatic void 2104200955Syongariste_setwol(struct ste_softc *sc) 2105200955Syongari{ 2106200955Syongari struct ifnet *ifp; 2107200955Syongari uint16_t pmstat; 2108200955Syongari uint8_t val; 2109200955Syongari int pmc; 2110200955Syongari 2111200955Syongari STE_LOCK_ASSERT(sc); 2112200955Syongari 2113219902Sjhb if (pci_find_cap(sc->ste_dev, PCIY_PMG, &pmc) != 0) { 2114200955Syongari /* Disable WOL. */ 2115200955Syongari CSR_READ_1(sc, STE_WAKE_EVENT); 2116200955Syongari CSR_WRITE_1(sc, STE_WAKE_EVENT, 0); 2117200955Syongari return; 2118200955Syongari } 2119200955Syongari 2120200955Syongari ifp = sc->ste_ifp; 2121200955Syongari val = CSR_READ_1(sc, STE_WAKE_EVENT); 2122200955Syongari val &= ~(STE_WAKEEVENT_WAKEPKT_ENB | STE_WAKEEVENT_MAGICPKT_ENB | 2123200955Syongari STE_WAKEEVENT_LINKEVT_ENB | STE_WAKEEVENT_WAKEONLAN_ENB); 2124200955Syongari if ((ifp->if_capenable & IFCAP_WOL_MAGIC) != 0) 2125200955Syongari val |= STE_WAKEEVENT_MAGICPKT_ENB | STE_WAKEEVENT_WAKEONLAN_ENB; 2126200955Syongari CSR_WRITE_1(sc, STE_WAKE_EVENT, val); 2127200955Syongari /* Request PME. */ 2128200955Syongari pmstat = pci_read_config(sc->ste_dev, pmc + PCIR_POWER_STATUS, 2); 2129200955Syongari pmstat &= ~(PCIM_PSTAT_PME | PCIM_PSTAT_PMEENABLE); 2130200955Syongari if ((ifp->if_capenable & IFCAP_WOL_MAGIC) != 0) 2131200955Syongari pmstat |= PCIM_PSTAT_PME | PCIM_PSTAT_PMEENABLE; 2132200955Syongari pci_write_config(sc->ste_dev, pmc + PCIR_POWER_STATUS, pmstat, 2); 2133200955Syongari} 2134