1193880Syongari/*- 2193880Syongari * Copyright (c) 2009, Pyun YongHyeon <yongari@FreeBSD.org> 3193880Syongari * All rights reserved. 4193880Syongari * 5193880Syongari * Redistribution and use in source and binary forms, with or without 6193880Syongari * modification, are permitted provided that the following conditions 7193880Syongari * are met: 8193880Syongari * 1. Redistributions of source code must retain the above copyright 9193880Syongari * notice unmodified, this list of conditions, and the following 10193880Syongari * disclaimer. 11193880Syongari * 2. Redistributions in binary form must reproduce the above copyright 12193880Syongari * notice, this list of conditions and the following disclaimer in the 13193880Syongari * documentation and/or other materials provided with the distribution. 14193880Syongari * 15193880Syongari * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16193880Syongari * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17193880Syongari * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18193880Syongari * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19193880Syongari * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20193880Syongari * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21193880Syongari * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22193880Syongari * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23193880Syongari * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24193880Syongari * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25193880Syongari * SUCH DAMAGE. 26193880Syongari */ 27193880Syongari 28211105Syongari/* Driver for Atheros AR813x/AR815x PCIe Ethernet. */ 29193880Syongari 30193880Syongari#include <sys/cdefs.h> 31193880Syongari__FBSDID("$FreeBSD$"); 32193880Syongari 33193880Syongari#include <sys/param.h> 34193880Syongari#include <sys/systm.h> 35193880Syongari#include <sys/bus.h> 36193880Syongari#include <sys/endian.h> 37193880Syongari#include <sys/kernel.h> 38193880Syongari#include <sys/lock.h> 39193880Syongari#include <sys/malloc.h> 40193880Syongari#include <sys/mbuf.h> 41193880Syongari#include <sys/module.h> 42193880Syongari#include <sys/mutex.h> 43193880Syongari#include <sys/rman.h> 44193880Syongari#include <sys/queue.h> 45193880Syongari#include <sys/socket.h> 46193880Syongari#include <sys/sockio.h> 47193880Syongari#include <sys/sysctl.h> 48193880Syongari#include <sys/taskqueue.h> 49193880Syongari 50193880Syongari#include <net/bpf.h> 51193880Syongari#include <net/if.h> 52193880Syongari#include <net/if_arp.h> 53193880Syongari#include <net/ethernet.h> 54193880Syongari#include <net/if_dl.h> 55193880Syongari#include <net/if_llc.h> 56193880Syongari#include <net/if_media.h> 57193880Syongari#include <net/if_types.h> 58193880Syongari#include <net/if_vlan_var.h> 59193880Syongari 60193880Syongari#include <netinet/in.h> 61193880Syongari#include <netinet/in_systm.h> 62193880Syongari#include <netinet/ip.h> 63193880Syongari#include <netinet/tcp.h> 64193880Syongari 65193880Syongari#include <dev/mii/mii.h> 66193880Syongari#include <dev/mii/miivar.h> 67193880Syongari 68193880Syongari#include <dev/pci/pcireg.h> 69193880Syongari#include <dev/pci/pcivar.h> 70193880Syongari 71193880Syongari#include <machine/bus.h> 72193880Syongari#include <machine/in_cksum.h> 73193880Syongari 74193880Syongari#include <dev/alc/if_alcreg.h> 75193880Syongari#include <dev/alc/if_alcvar.h> 76193880Syongari 77193880Syongari/* "device miibus" required. See GENERIC if you get errors here. */ 78193880Syongari#include "miibus_if.h" 79193880Syongari#undef ALC_USE_CUSTOM_CSUM 80193880Syongari 81193880Syongari#ifdef ALC_USE_CUSTOM_CSUM 82193880Syongari#define ALC_CSUM_FEATURES (CSUM_TCP | CSUM_UDP) 83193880Syongari#else 84193880Syongari#define ALC_CSUM_FEATURES (CSUM_IP | CSUM_TCP | CSUM_UDP) 85193880Syongari#endif 86193880Syongari 87193880SyongariMODULE_DEPEND(alc, pci, 1, 1, 1); 88193880SyongariMODULE_DEPEND(alc, ether, 1, 1, 1); 89193880SyongariMODULE_DEPEND(alc, miibus, 1, 1, 1); 90193880Syongari 91193880Syongari/* Tunables. */ 92193880Syongaristatic int msi_disable = 0; 93193880Syongaristatic int msix_disable = 0; 94193880SyongariTUNABLE_INT("hw.alc.msi_disable", &msi_disable); 95193880SyongariTUNABLE_INT("hw.alc.msix_disable", &msix_disable); 96193880Syongari 97193880Syongari/* 98193880Syongari * Devices supported by this driver. 99193880Syongari */ 100211105Syongaristatic struct alc_ident alc_ident_table[] = { 101211105Syongari { VENDORID_ATHEROS, DEVICEID_ATHEROS_AR8131, 9 * 1024, 102193880Syongari "Atheros AR8131 PCIe Gigabit Ethernet" }, 103211105Syongari { VENDORID_ATHEROS, DEVICEID_ATHEROS_AR8132, 9 * 1024, 104211105Syongari "Atheros AR8132 PCIe Fast Ethernet" }, 105211105Syongari { VENDORID_ATHEROS, DEVICEID_ATHEROS_AR8151, 6 * 1024, 106211105Syongari "Atheros AR8151 v1.0 PCIe Gigabit Ethernet" }, 107211105Syongari { VENDORID_ATHEROS, DEVICEID_ATHEROS_AR8151_V2, 6 * 1024, 108211105Syongari "Atheros AR8151 v2.0 PCIe Gigabit Ethernet" }, 109211105Syongari { VENDORID_ATHEROS, DEVICEID_ATHEROS_AR8152_B, 6 * 1024, 110211105Syongari "Atheros AR8152 v1.1 PCIe Fast Ethernet" }, 111211105Syongari { VENDORID_ATHEROS, DEVICEID_ATHEROS_AR8152_B2, 6 * 1024, 112211105Syongari "Atheros AR8152 v2.0 PCIe Fast Ethernet" }, 113211105Syongari { 0, 0, 0, NULL} 114193880Syongari}; 115193880Syongari 116211105Syongaristatic void alc_aspm(struct alc_softc *, int); 117193880Syongaristatic int alc_attach(device_t); 118193880Syongaristatic int alc_check_boundary(struct alc_softc *); 119193880Syongaristatic int alc_detach(device_t); 120193880Syongaristatic void alc_disable_l0s_l1(struct alc_softc *); 121193880Syongaristatic int alc_dma_alloc(struct alc_softc *); 122193880Syongaristatic void alc_dma_free(struct alc_softc *); 123193880Syongaristatic void alc_dmamap_cb(void *, bus_dma_segment_t *, int, int); 124193880Syongaristatic int alc_encap(struct alc_softc *, struct mbuf **); 125211105Syongaristatic struct alc_ident * 126211105Syongari alc_find_ident(device_t); 127193880Syongari#ifndef __NO_STRICT_ALIGNMENT 128193880Syongaristatic struct mbuf * 129193880Syongari alc_fixup_rx(struct ifnet *, struct mbuf *); 130193880Syongari#endif 131193880Syongaristatic void alc_get_macaddr(struct alc_softc *); 132193880Syongaristatic void alc_init(void *); 133193880Syongaristatic void alc_init_cmb(struct alc_softc *); 134193880Syongaristatic void alc_init_locked(struct alc_softc *); 135193880Syongaristatic void alc_init_rr_ring(struct alc_softc *); 136193880Syongaristatic int alc_init_rx_ring(struct alc_softc *); 137193880Syongaristatic void alc_init_smb(struct alc_softc *); 138193880Syongaristatic void alc_init_tx_ring(struct alc_softc *); 139193880Syongaristatic void alc_int_task(void *, int); 140193880Syongaristatic int alc_intr(void *); 141193880Syongaristatic int alc_ioctl(struct ifnet *, u_long, caddr_t); 142193880Syongaristatic void alc_mac_config(struct alc_softc *); 143193880Syongaristatic int alc_miibus_readreg(device_t, int, int); 144193880Syongaristatic void alc_miibus_statchg(device_t); 145193880Syongaristatic int alc_miibus_writereg(device_t, int, int, int); 146193880Syongaristatic int alc_mediachange(struct ifnet *); 147193880Syongaristatic void alc_mediastatus(struct ifnet *, struct ifmediareq *); 148193880Syongaristatic int alc_newbuf(struct alc_softc *, struct alc_rxdesc *); 149193880Syongaristatic void alc_phy_down(struct alc_softc *); 150193880Syongaristatic void alc_phy_reset(struct alc_softc *); 151193880Syongaristatic int alc_probe(device_t); 152193880Syongaristatic void alc_reset(struct alc_softc *); 153193880Syongaristatic int alc_resume(device_t); 154193880Syongaristatic void alc_rxeof(struct alc_softc *, struct rx_rdesc *); 155193880Syongaristatic int alc_rxintr(struct alc_softc *, int); 156193880Syongaristatic void alc_rxfilter(struct alc_softc *); 157193880Syongaristatic void alc_rxvlan(struct alc_softc *); 158193880Syongaristatic void alc_setlinkspeed(struct alc_softc *); 159193880Syongaristatic void alc_setwol(struct alc_softc *); 160193880Syongaristatic int alc_shutdown(device_t); 161193880Syongaristatic void alc_start(struct ifnet *); 162216925Sjhbstatic void alc_start_locked(struct ifnet *); 163193880Syongaristatic void alc_start_queue(struct alc_softc *); 164193880Syongaristatic void alc_stats_clear(struct alc_softc *); 165193880Syongaristatic void alc_stats_update(struct alc_softc *); 166193880Syongaristatic void alc_stop(struct alc_softc *); 167193880Syongaristatic void alc_stop_mac(struct alc_softc *); 168193880Syongaristatic void alc_stop_queue(struct alc_softc *); 169193880Syongaristatic int alc_suspend(device_t); 170193880Syongaristatic void alc_sysctl_node(struct alc_softc *); 171193880Syongaristatic void alc_tick(void *); 172193880Syongaristatic void alc_txeof(struct alc_softc *); 173193880Syongaristatic void alc_watchdog(struct alc_softc *); 174193880Syongaristatic int sysctl_int_range(SYSCTL_HANDLER_ARGS, int, int); 175193880Syongaristatic int sysctl_hw_alc_proc_limit(SYSCTL_HANDLER_ARGS); 176193880Syongaristatic int sysctl_hw_alc_int_mod(SYSCTL_HANDLER_ARGS); 177193880Syongari 178193880Syongaristatic device_method_t alc_methods[] = { 179193880Syongari /* Device interface. */ 180193880Syongari DEVMETHOD(device_probe, alc_probe), 181193880Syongari DEVMETHOD(device_attach, alc_attach), 182193880Syongari DEVMETHOD(device_detach, alc_detach), 183193880Syongari DEVMETHOD(device_shutdown, alc_shutdown), 184193880Syongari DEVMETHOD(device_suspend, alc_suspend), 185193880Syongari DEVMETHOD(device_resume, alc_resume), 186193880Syongari 187193880Syongari /* MII interface. */ 188193880Syongari DEVMETHOD(miibus_readreg, alc_miibus_readreg), 189193880Syongari DEVMETHOD(miibus_writereg, alc_miibus_writereg), 190193880Syongari DEVMETHOD(miibus_statchg, alc_miibus_statchg), 191193880Syongari 192193880Syongari { NULL, NULL } 193193880Syongari}; 194193880Syongari 195193880Syongaristatic driver_t alc_driver = { 196193880Syongari "alc", 197193880Syongari alc_methods, 198193880Syongari sizeof(struct alc_softc) 199193880Syongari}; 200193880Syongari 201193880Syongaristatic devclass_t alc_devclass; 202193880Syongari 203193880SyongariDRIVER_MODULE(alc, pci, alc_driver, alc_devclass, 0, 0); 204193880SyongariDRIVER_MODULE(miibus, alc, miibus_driver, miibus_devclass, 0, 0); 205193880Syongari 206193880Syongaristatic struct resource_spec alc_res_spec_mem[] = { 207193880Syongari { SYS_RES_MEMORY, PCIR_BAR(0), RF_ACTIVE }, 208193880Syongari { -1, 0, 0 } 209193880Syongari}; 210193880Syongari 211193880Syongaristatic struct resource_spec alc_irq_spec_legacy[] = { 212193880Syongari { SYS_RES_IRQ, 0, RF_ACTIVE | RF_SHAREABLE }, 213193880Syongari { -1, 0, 0 } 214193880Syongari}; 215193880Syongari 216193880Syongaristatic struct resource_spec alc_irq_spec_msi[] = { 217193880Syongari { SYS_RES_IRQ, 1, RF_ACTIVE }, 218193880Syongari { -1, 0, 0 } 219193880Syongari}; 220193880Syongari 221193880Syongaristatic struct resource_spec alc_irq_spec_msix[] = { 222193880Syongari { SYS_RES_IRQ, 1, RF_ACTIVE }, 223193880Syongari { -1, 0, 0 } 224193880Syongari}; 225193880Syongari 226193880Syongaristatic uint32_t alc_dma_burst[] = { 128, 256, 512, 1024, 2048, 4096, 0 }; 227193880Syongari 228193880Syongaristatic int 229193880Syongarialc_miibus_readreg(device_t dev, int phy, int reg) 230193880Syongari{ 231193880Syongari struct alc_softc *sc; 232193880Syongari uint32_t v; 233193880Syongari int i; 234193880Syongari 235193880Syongari sc = device_get_softc(dev); 236193880Syongari 237197600Syongari /* 238197600Syongari * For AR8132 fast ethernet controller, do not report 1000baseT 239197600Syongari * capability to mii(4). Even though AR8132 uses the same 240197600Syongari * model/revision number of F1 gigabit PHY, the PHY has no 241197600Syongari * ability to establish 1000baseT link. 242197600Syongari */ 243197600Syongari if ((sc->alc_flags & ALC_FLAG_FASTETHER) != 0 && 244197600Syongari reg == MII_EXTSR) 245197600Syongari return (0); 246197600Syongari 247193880Syongari CSR_WRITE_4(sc, ALC_MDIO, MDIO_OP_EXECUTE | MDIO_OP_READ | 248193880Syongari MDIO_SUP_PREAMBLE | MDIO_CLK_25_4 | MDIO_REG_ADDR(reg)); 249193880Syongari for (i = ALC_PHY_TIMEOUT; i > 0; i--) { 250193880Syongari DELAY(5); 251193880Syongari v = CSR_READ_4(sc, ALC_MDIO); 252193880Syongari if ((v & (MDIO_OP_EXECUTE | MDIO_OP_BUSY)) == 0) 253193880Syongari break; 254193880Syongari } 255193880Syongari 256193880Syongari if (i == 0) { 257193880Syongari device_printf(sc->alc_dev, "phy read timeout : %d\n", reg); 258193880Syongari return (0); 259193880Syongari } 260193880Syongari 261193880Syongari return ((v & MDIO_DATA_MASK) >> MDIO_DATA_SHIFT); 262193880Syongari} 263193880Syongari 264193880Syongaristatic int 265193880Syongarialc_miibus_writereg(device_t dev, int phy, int reg, int val) 266193880Syongari{ 267193880Syongari struct alc_softc *sc; 268193880Syongari uint32_t v; 269193880Syongari int i; 270193880Syongari 271193880Syongari sc = device_get_softc(dev); 272193880Syongari 273193880Syongari CSR_WRITE_4(sc, ALC_MDIO, MDIO_OP_EXECUTE | MDIO_OP_WRITE | 274193880Syongari (val & MDIO_DATA_MASK) << MDIO_DATA_SHIFT | 275193880Syongari MDIO_SUP_PREAMBLE | MDIO_CLK_25_4 | MDIO_REG_ADDR(reg)); 276193880Syongari for (i = ALC_PHY_TIMEOUT; i > 0; i--) { 277193880Syongari DELAY(5); 278193880Syongari v = CSR_READ_4(sc, ALC_MDIO); 279193880Syongari if ((v & (MDIO_OP_EXECUTE | MDIO_OP_BUSY)) == 0) 280193880Syongari break; 281193880Syongari } 282193880Syongari 283193880Syongari if (i == 0) 284193880Syongari device_printf(sc->alc_dev, "phy write timeout : %d\n", reg); 285193880Syongari 286193880Syongari return (0); 287193880Syongari} 288193880Syongari 289193880Syongaristatic void 290193880Syongarialc_miibus_statchg(device_t dev) 291193880Syongari{ 292193880Syongari struct alc_softc *sc; 293193880Syongari struct mii_data *mii; 294193880Syongari struct ifnet *ifp; 295193880Syongari uint32_t reg; 296193880Syongari 297193880Syongari sc = device_get_softc(dev); 298193880Syongari 299193880Syongari mii = device_get_softc(sc->alc_miibus); 300193880Syongari ifp = sc->alc_ifp; 301193880Syongari if (mii == NULL || ifp == NULL || 302193880Syongari (ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) 303193880Syongari return; 304193880Syongari 305193880Syongari sc->alc_flags &= ~ALC_FLAG_LINK; 306193880Syongari if ((mii->mii_media_status & (IFM_ACTIVE | IFM_AVALID)) == 307193880Syongari (IFM_ACTIVE | IFM_AVALID)) { 308193880Syongari switch (IFM_SUBTYPE(mii->mii_media_active)) { 309193880Syongari case IFM_10_T: 310193880Syongari case IFM_100_TX: 311193880Syongari sc->alc_flags |= ALC_FLAG_LINK; 312193880Syongari break; 313193880Syongari case IFM_1000_T: 314193880Syongari if ((sc->alc_flags & ALC_FLAG_FASTETHER) == 0) 315193880Syongari sc->alc_flags |= ALC_FLAG_LINK; 316193880Syongari break; 317193880Syongari default: 318193880Syongari break; 319193880Syongari } 320193880Syongari } 321193880Syongari alc_stop_queue(sc); 322193880Syongari /* Stop Rx/Tx MACs. */ 323193880Syongari alc_stop_mac(sc); 324193880Syongari 325193880Syongari /* Program MACs with resolved speed/duplex/flow-control. */ 326193880Syongari if ((sc->alc_flags & ALC_FLAG_LINK) != 0) { 327193880Syongari alc_start_queue(sc); 328193880Syongari alc_mac_config(sc); 329193880Syongari /* Re-enable Tx/Rx MACs. */ 330193880Syongari reg = CSR_READ_4(sc, ALC_MAC_CFG); 331193880Syongari reg |= MAC_CFG_TX_ENB | MAC_CFG_RX_ENB; 332193880Syongari CSR_WRITE_4(sc, ALC_MAC_CFG, reg); 333214542Syongari alc_aspm(sc, IFM_SUBTYPE(mii->mii_media_active)); 334193880Syongari } 335193880Syongari} 336193880Syongari 337193880Syongaristatic void 338193880Syongarialc_mediastatus(struct ifnet *ifp, struct ifmediareq *ifmr) 339193880Syongari{ 340193880Syongari struct alc_softc *sc; 341193880Syongari struct mii_data *mii; 342193880Syongari 343193880Syongari sc = ifp->if_softc; 344193880Syongari ALC_LOCK(sc); 345193880Syongari if ((ifp->if_flags & IFF_UP) == 0) { 346193880Syongari ALC_UNLOCK(sc); 347193880Syongari return; 348193880Syongari } 349193880Syongari mii = device_get_softc(sc->alc_miibus); 350193880Syongari 351193880Syongari mii_pollstat(mii); 352193880Syongari ifmr->ifm_status = mii->mii_media_status; 353193880Syongari ifmr->ifm_active = mii->mii_media_active; 354226478Syongari ALC_UNLOCK(sc); 355193880Syongari} 356193880Syongari 357193880Syongaristatic int 358193880Syongarialc_mediachange(struct ifnet *ifp) 359193880Syongari{ 360193880Syongari struct alc_softc *sc; 361193880Syongari struct mii_data *mii; 362193880Syongari struct mii_softc *miisc; 363193880Syongari int error; 364193880Syongari 365193880Syongari sc = ifp->if_softc; 366193880Syongari ALC_LOCK(sc); 367193880Syongari mii = device_get_softc(sc->alc_miibus); 368221407Smarius LIST_FOREACH(miisc, &mii->mii_phys, mii_list) 369221407Smarius PHY_RESET(miisc); 370193880Syongari error = mii_mediachg(mii); 371193880Syongari ALC_UNLOCK(sc); 372193880Syongari 373193880Syongari return (error); 374193880Syongari} 375193880Syongari 376211105Syongaristatic struct alc_ident * 377211105Syongarialc_find_ident(device_t dev) 378193880Syongari{ 379211105Syongari struct alc_ident *ident; 380193880Syongari uint16_t vendor, devid; 381193880Syongari 382193880Syongari vendor = pci_get_vendor(dev); 383193880Syongari devid = pci_get_device(dev); 384211105Syongari for (ident = alc_ident_table; ident->name != NULL; ident++) { 385211105Syongari if (vendor == ident->vendorid && devid == ident->deviceid) 386211105Syongari return (ident); 387193880Syongari } 388193880Syongari 389211105Syongari return (NULL); 390211105Syongari} 391211105Syongari 392211105Syongaristatic int 393211105Syongarialc_probe(device_t dev) 394211105Syongari{ 395211105Syongari struct alc_ident *ident; 396211105Syongari 397211105Syongari ident = alc_find_ident(dev); 398211105Syongari if (ident != NULL) { 399211105Syongari device_set_desc(dev, ident->name); 400211105Syongari return (BUS_PROBE_DEFAULT); 401211105Syongari } 402211105Syongari 403193880Syongari return (ENXIO); 404193880Syongari} 405193880Syongari 406193880Syongaristatic void 407193880Syongarialc_get_macaddr(struct alc_softc *sc) 408193880Syongari{ 409193880Syongari uint32_t ea[2], opt; 410211105Syongari uint16_t val; 411211105Syongari int eeprom, i; 412193880Syongari 413211105Syongari eeprom = 0; 414193880Syongari opt = CSR_READ_4(sc, ALC_OPT_CFG); 415211105Syongari if ((CSR_READ_4(sc, ALC_MASTER_CFG) & MASTER_OTP_SEL) != 0 && 416211105Syongari (CSR_READ_4(sc, ALC_TWSI_DEBUG) & TWSI_DEBUG_DEV_EXIST) != 0) { 417193880Syongari /* 418193880Syongari * EEPROM found, let TWSI reload EEPROM configuration. 419193880Syongari * This will set ethernet address of controller. 420193880Syongari */ 421211105Syongari eeprom++; 422211105Syongari switch (sc->alc_ident->deviceid) { 423211105Syongari case DEVICEID_ATHEROS_AR8131: 424211105Syongari case DEVICEID_ATHEROS_AR8132: 425211105Syongari if ((opt & OPT_CFG_CLK_ENB) == 0) { 426211105Syongari opt |= OPT_CFG_CLK_ENB; 427211105Syongari CSR_WRITE_4(sc, ALC_OPT_CFG, opt); 428211105Syongari CSR_READ_4(sc, ALC_OPT_CFG); 429211105Syongari DELAY(1000); 430211105Syongari } 431211105Syongari break; 432211105Syongari case DEVICEID_ATHEROS_AR8151: 433211105Syongari case DEVICEID_ATHEROS_AR8151_V2: 434211105Syongari case DEVICEID_ATHEROS_AR8152_B: 435211105Syongari case DEVICEID_ATHEROS_AR8152_B2: 436211105Syongari alc_miibus_writereg(sc->alc_dev, sc->alc_phyaddr, 437211105Syongari ALC_MII_DBG_ADDR, 0x00); 438211105Syongari val = alc_miibus_readreg(sc->alc_dev, sc->alc_phyaddr, 439211105Syongari ALC_MII_DBG_DATA); 440211105Syongari alc_miibus_writereg(sc->alc_dev, sc->alc_phyaddr, 441211105Syongari ALC_MII_DBG_DATA, val & 0xFF7F); 442211105Syongari alc_miibus_writereg(sc->alc_dev, sc->alc_phyaddr, 443211105Syongari ALC_MII_DBG_ADDR, 0x3B); 444211105Syongari val = alc_miibus_readreg(sc->alc_dev, sc->alc_phyaddr, 445211105Syongari ALC_MII_DBG_DATA); 446211105Syongari alc_miibus_writereg(sc->alc_dev, sc->alc_phyaddr, 447211105Syongari ALC_MII_DBG_DATA, val | 0x0008); 448211105Syongari DELAY(20); 449211105Syongari break; 450193880Syongari } 451211105Syongari 452211105Syongari CSR_WRITE_4(sc, ALC_LTSSM_ID_CFG, 453211105Syongari CSR_READ_4(sc, ALC_LTSSM_ID_CFG) & ~LTSSM_ID_WRO_ENB); 454211105Syongari CSR_WRITE_4(sc, ALC_WOL_CFG, 0); 455211105Syongari CSR_READ_4(sc, ALC_WOL_CFG); 456211105Syongari 457193880Syongari CSR_WRITE_4(sc, ALC_TWSI_CFG, CSR_READ_4(sc, ALC_TWSI_CFG) | 458193880Syongari TWSI_CFG_SW_LD_START); 459193880Syongari for (i = 100; i > 0; i--) { 460193880Syongari DELAY(1000); 461193880Syongari if ((CSR_READ_4(sc, ALC_TWSI_CFG) & 462193880Syongari TWSI_CFG_SW_LD_START) == 0) 463193880Syongari break; 464193880Syongari } 465193880Syongari if (i == 0) 466193880Syongari device_printf(sc->alc_dev, 467193880Syongari "reloading EEPROM timeout!\n"); 468193880Syongari } else { 469193880Syongari if (bootverbose) 470193880Syongari device_printf(sc->alc_dev, "EEPROM not found!\n"); 471193880Syongari } 472211105Syongari if (eeprom != 0) { 473211105Syongari switch (sc->alc_ident->deviceid) { 474211105Syongari case DEVICEID_ATHEROS_AR8131: 475211105Syongari case DEVICEID_ATHEROS_AR8132: 476211105Syongari if ((opt & OPT_CFG_CLK_ENB) != 0) { 477211105Syongari opt &= ~OPT_CFG_CLK_ENB; 478211105Syongari CSR_WRITE_4(sc, ALC_OPT_CFG, opt); 479211105Syongari CSR_READ_4(sc, ALC_OPT_CFG); 480211105Syongari DELAY(1000); 481211105Syongari } 482211105Syongari break; 483211105Syongari case DEVICEID_ATHEROS_AR8151: 484211105Syongari case DEVICEID_ATHEROS_AR8151_V2: 485211105Syongari case DEVICEID_ATHEROS_AR8152_B: 486211105Syongari case DEVICEID_ATHEROS_AR8152_B2: 487211105Syongari alc_miibus_writereg(sc->alc_dev, sc->alc_phyaddr, 488211105Syongari ALC_MII_DBG_ADDR, 0x00); 489211105Syongari val = alc_miibus_readreg(sc->alc_dev, sc->alc_phyaddr, 490211105Syongari ALC_MII_DBG_DATA); 491211105Syongari alc_miibus_writereg(sc->alc_dev, sc->alc_phyaddr, 492211105Syongari ALC_MII_DBG_DATA, val | 0x0080); 493211105Syongari alc_miibus_writereg(sc->alc_dev, sc->alc_phyaddr, 494211105Syongari ALC_MII_DBG_ADDR, 0x3B); 495211105Syongari val = alc_miibus_readreg(sc->alc_dev, sc->alc_phyaddr, 496211105Syongari ALC_MII_DBG_DATA); 497211105Syongari alc_miibus_writereg(sc->alc_dev, sc->alc_phyaddr, 498211105Syongari ALC_MII_DBG_DATA, val & 0xFFF7); 499211105Syongari DELAY(20); 500211105Syongari break; 501211105Syongari } 502193880Syongari } 503193880Syongari 504193880Syongari ea[0] = CSR_READ_4(sc, ALC_PAR0); 505193880Syongari ea[1] = CSR_READ_4(sc, ALC_PAR1); 506193880Syongari sc->alc_eaddr[0] = (ea[1] >> 8) & 0xFF; 507193880Syongari sc->alc_eaddr[1] = (ea[1] >> 0) & 0xFF; 508193880Syongari sc->alc_eaddr[2] = (ea[0] >> 24) & 0xFF; 509193880Syongari sc->alc_eaddr[3] = (ea[0] >> 16) & 0xFF; 510193880Syongari sc->alc_eaddr[4] = (ea[0] >> 8) & 0xFF; 511193880Syongari sc->alc_eaddr[5] = (ea[0] >> 0) & 0xFF; 512193880Syongari} 513193880Syongari 514193880Syongaristatic void 515193880Syongarialc_disable_l0s_l1(struct alc_softc *sc) 516193880Syongari{ 517193880Syongari uint32_t pmcfg; 518193880Syongari 519193880Syongari /* Another magic from vendor. */ 520193880Syongari pmcfg = CSR_READ_4(sc, ALC_PM_CFG); 521193880Syongari pmcfg &= ~(PM_CFG_L1_ENTRY_TIMER_MASK | PM_CFG_CLK_SWH_L1 | 522193880Syongari PM_CFG_ASPM_L0S_ENB | PM_CFG_ASPM_L1_ENB | PM_CFG_MAC_ASPM_CHK | 523193880Syongari PM_CFG_SERDES_PD_EX_L1); 524193880Syongari pmcfg |= PM_CFG_SERDES_BUDS_RX_L1_ENB | PM_CFG_SERDES_PLL_L1_ENB | 525193880Syongari PM_CFG_SERDES_L1_ENB; 526193880Syongari CSR_WRITE_4(sc, ALC_PM_CFG, pmcfg); 527193880Syongari} 528193880Syongari 529193880Syongaristatic void 530193880Syongarialc_phy_reset(struct alc_softc *sc) 531193880Syongari{ 532193880Syongari uint16_t data; 533193880Syongari 534193880Syongari /* Reset magic from Linux. */ 535225088Syongari CSR_WRITE_2(sc, ALC_GPHY_CFG, GPHY_CFG_SEL_ANA_RESET); 536193880Syongari CSR_READ_2(sc, ALC_GPHY_CFG); 537193880Syongari DELAY(10 * 1000); 538193880Syongari 539225088Syongari CSR_WRITE_2(sc, ALC_GPHY_CFG, GPHY_CFG_EXT_RESET | 540193880Syongari GPHY_CFG_SEL_ANA_RESET); 541193880Syongari CSR_READ_2(sc, ALC_GPHY_CFG); 542193880Syongari DELAY(10 * 1000); 543193880Syongari 544211105Syongari /* DSP fixup, Vendor magic. */ 545211105Syongari if (sc->alc_ident->deviceid == DEVICEID_ATHEROS_AR8152_B) { 546211105Syongari alc_miibus_writereg(sc->alc_dev, sc->alc_phyaddr, 547211105Syongari ALC_MII_DBG_ADDR, 0x000A); 548211105Syongari data = alc_miibus_readreg(sc->alc_dev, sc->alc_phyaddr, 549211105Syongari ALC_MII_DBG_DATA); 550211105Syongari alc_miibus_writereg(sc->alc_dev, sc->alc_phyaddr, 551211105Syongari ALC_MII_DBG_DATA, data & 0xDFFF); 552211105Syongari } 553211105Syongari if (sc->alc_ident->deviceid == DEVICEID_ATHEROS_AR8151 || 554211105Syongari sc->alc_ident->deviceid == DEVICEID_ATHEROS_AR8151_V2 || 555211105Syongari sc->alc_ident->deviceid == DEVICEID_ATHEROS_AR8152_B || 556211105Syongari sc->alc_ident->deviceid == DEVICEID_ATHEROS_AR8152_B2) { 557211105Syongari alc_miibus_writereg(sc->alc_dev, sc->alc_phyaddr, 558211105Syongari ALC_MII_DBG_ADDR, 0x003B); 559211105Syongari data = alc_miibus_readreg(sc->alc_dev, sc->alc_phyaddr, 560211105Syongari ALC_MII_DBG_DATA); 561211105Syongari alc_miibus_writereg(sc->alc_dev, sc->alc_phyaddr, 562211105Syongari ALC_MII_DBG_DATA, data & 0xFFF7); 563211105Syongari DELAY(20 * 1000); 564211105Syongari } 565211105Syongari if (sc->alc_ident->deviceid == DEVICEID_ATHEROS_AR8151) { 566211105Syongari alc_miibus_writereg(sc->alc_dev, sc->alc_phyaddr, 567211105Syongari ALC_MII_DBG_ADDR, 0x0029); 568211105Syongari alc_miibus_writereg(sc->alc_dev, sc->alc_phyaddr, 569211105Syongari ALC_MII_DBG_DATA, 0x929D); 570211105Syongari } 571211105Syongari if (sc->alc_ident->deviceid == DEVICEID_ATHEROS_AR8131 || 572211105Syongari sc->alc_ident->deviceid == DEVICEID_ATHEROS_AR8132 || 573211105Syongari sc->alc_ident->deviceid == DEVICEID_ATHEROS_AR8151_V2 || 574211105Syongari sc->alc_ident->deviceid == DEVICEID_ATHEROS_AR8152_B2) { 575211105Syongari alc_miibus_writereg(sc->alc_dev, sc->alc_phyaddr, 576211105Syongari ALC_MII_DBG_ADDR, 0x0029); 577211105Syongari alc_miibus_writereg(sc->alc_dev, sc->alc_phyaddr, 578211105Syongari ALC_MII_DBG_DATA, 0xB6DD); 579211105Syongari } 580211105Syongari 581193880Syongari /* Load DSP codes, vendor magic. */ 582193880Syongari data = ANA_LOOP_SEL_10BT | ANA_EN_MASK_TB | ANA_EN_10BT_IDLE | 583193880Syongari ((1 << ANA_INTERVAL_SEL_TIMER_SHIFT) & ANA_INTERVAL_SEL_TIMER_MASK); 584193880Syongari alc_miibus_writereg(sc->alc_dev, sc->alc_phyaddr, 585193880Syongari ALC_MII_DBG_ADDR, MII_ANA_CFG18); 586193880Syongari alc_miibus_writereg(sc->alc_dev, sc->alc_phyaddr, 587193880Syongari ALC_MII_DBG_DATA, data); 588193880Syongari 589193880Syongari data = ((2 << ANA_SERDES_CDR_BW_SHIFT) & ANA_SERDES_CDR_BW_MASK) | 590193880Syongari ANA_SERDES_EN_DEEM | ANA_SERDES_SEL_HSP | ANA_SERDES_EN_PLL | 591193880Syongari ANA_SERDES_EN_LCKDT; 592193880Syongari alc_miibus_writereg(sc->alc_dev, sc->alc_phyaddr, 593193880Syongari ALC_MII_DBG_ADDR, MII_ANA_CFG5); 594193880Syongari alc_miibus_writereg(sc->alc_dev, sc->alc_phyaddr, 595193880Syongari ALC_MII_DBG_DATA, data); 596193880Syongari 597193880Syongari data = ((44 << ANA_LONG_CABLE_TH_100_SHIFT) & 598193880Syongari ANA_LONG_CABLE_TH_100_MASK) | 599193880Syongari ((33 << ANA_SHORT_CABLE_TH_100_SHIFT) & 600193880Syongari ANA_SHORT_CABLE_TH_100_SHIFT) | 601193880Syongari ANA_BP_BAD_LINK_ACCUM | ANA_BP_SMALL_BW; 602193880Syongari alc_miibus_writereg(sc->alc_dev, sc->alc_phyaddr, 603193880Syongari ALC_MII_DBG_ADDR, MII_ANA_CFG54); 604193880Syongari alc_miibus_writereg(sc->alc_dev, sc->alc_phyaddr, 605193880Syongari ALC_MII_DBG_DATA, data); 606193880Syongari 607193880Syongari data = ((11 << ANA_IECHO_ADJ_3_SHIFT) & ANA_IECHO_ADJ_3_MASK) | 608193880Syongari ((11 << ANA_IECHO_ADJ_2_SHIFT) & ANA_IECHO_ADJ_2_MASK) | 609193880Syongari ((8 << ANA_IECHO_ADJ_1_SHIFT) & ANA_IECHO_ADJ_1_MASK) | 610193880Syongari ((8 << ANA_IECHO_ADJ_0_SHIFT) & ANA_IECHO_ADJ_0_MASK); 611193880Syongari alc_miibus_writereg(sc->alc_dev, sc->alc_phyaddr, 612193880Syongari ALC_MII_DBG_ADDR, MII_ANA_CFG4); 613193880Syongari alc_miibus_writereg(sc->alc_dev, sc->alc_phyaddr, 614193880Syongari ALC_MII_DBG_DATA, data); 615193880Syongari 616193880Syongari data = ((7 & ANA_MANUL_SWICH_ON_SHIFT) & ANA_MANUL_SWICH_ON_MASK) | 617193880Syongari ANA_RESTART_CAL | ANA_MAN_ENABLE | ANA_SEL_HSP | ANA_EN_HB | 618193880Syongari ANA_OEN_125M; 619193880Syongari alc_miibus_writereg(sc->alc_dev, sc->alc_phyaddr, 620193880Syongari ALC_MII_DBG_ADDR, MII_ANA_CFG0); 621193880Syongari alc_miibus_writereg(sc->alc_dev, sc->alc_phyaddr, 622193880Syongari ALC_MII_DBG_DATA, data); 623193880Syongari DELAY(1000); 624225088Syongari 625225088Syongari /* Disable hibernation. */ 626225088Syongari alc_miibus_writereg(sc->alc_dev, sc->alc_phyaddr, ALC_MII_DBG_ADDR, 627225088Syongari 0x0029); 628225088Syongari data = alc_miibus_readreg(sc->alc_dev, sc->alc_phyaddr, 629225088Syongari ALC_MII_DBG_DATA); 630225088Syongari data &= ~0x8000; 631225088Syongari alc_miibus_writereg(sc->alc_dev, sc->alc_phyaddr, ALC_MII_DBG_DATA, 632225088Syongari data); 633225088Syongari 634225088Syongari alc_miibus_writereg(sc->alc_dev, sc->alc_phyaddr, ALC_MII_DBG_ADDR, 635225088Syongari 0x000B); 636225088Syongari data = alc_miibus_readreg(sc->alc_dev, sc->alc_phyaddr, 637225088Syongari ALC_MII_DBG_DATA); 638225088Syongari data &= ~0x8000; 639225088Syongari alc_miibus_writereg(sc->alc_dev, sc->alc_phyaddr, ALC_MII_DBG_DATA, 640225088Syongari data); 641193880Syongari} 642193880Syongari 643193880Syongaristatic void 644193880Syongarialc_phy_down(struct alc_softc *sc) 645193880Syongari{ 646193880Syongari 647211105Syongari switch (sc->alc_ident->deviceid) { 648211105Syongari case DEVICEID_ATHEROS_AR8151: 649211105Syongari case DEVICEID_ATHEROS_AR8151_V2: 650211105Syongari /* 651211105Syongari * GPHY power down caused more problems on AR8151 v2.0. 652211105Syongari * When driver is reloaded after GPHY power down, 653211105Syongari * accesses to PHY/MAC registers hung the system. Only 654211105Syongari * cold boot recovered from it. I'm not sure whether 655211105Syongari * AR8151 v1.0 also requires this one though. I don't 656211105Syongari * have AR8151 v1.0 controller in hand. 657211105Syongari * The only option left is to isolate the PHY and 658211105Syongari * initiates power down the PHY which in turn saves 659211105Syongari * more power when driver is unloaded. 660211105Syongari */ 661211105Syongari alc_miibus_writereg(sc->alc_dev, sc->alc_phyaddr, 662211105Syongari MII_BMCR, BMCR_ISO | BMCR_PDOWN); 663211105Syongari break; 664211105Syongari default: 665211105Syongari /* Force PHY down. */ 666225088Syongari CSR_WRITE_2(sc, ALC_GPHY_CFG, GPHY_CFG_EXT_RESET | 667211105Syongari GPHY_CFG_SEL_ANA_RESET | GPHY_CFG_PHY_IDDQ | 668211105Syongari GPHY_CFG_PWDOWN_HW); 669211105Syongari DELAY(1000); 670211105Syongari break; 671211105Syongari } 672193880Syongari} 673193880Syongari 674193880Syongaristatic void 675211105Syongarialc_aspm(struct alc_softc *sc, int media) 676193880Syongari{ 677193880Syongari uint32_t pmcfg; 678211105Syongari uint16_t linkcfg; 679193880Syongari 680193880Syongari ALC_LOCK_ASSERT(sc); 681193880Syongari 682193880Syongari pmcfg = CSR_READ_4(sc, ALC_PM_CFG); 683211105Syongari if ((sc->alc_flags & (ALC_FLAG_APS | ALC_FLAG_PCIE)) == 684211105Syongari (ALC_FLAG_APS | ALC_FLAG_PCIE)) 685211105Syongari linkcfg = CSR_READ_2(sc, sc->alc_expcap + 686240680Sgavin PCIER_LINK_CTL); 687211105Syongari else 688211105Syongari linkcfg = 0; 689193880Syongari pmcfg &= ~PM_CFG_SERDES_PD_EX_L1; 690211105Syongari pmcfg &= ~(PM_CFG_L1_ENTRY_TIMER_MASK | PM_CFG_LCKDET_TIMER_MASK); 691193880Syongari pmcfg |= PM_CFG_MAC_ASPM_CHK; 692217649Syongari pmcfg |= (PM_CFG_LCKDET_TIMER_DEFAULT << PM_CFG_LCKDET_TIMER_SHIFT); 693211105Syongari pmcfg &= ~(PM_CFG_ASPM_L1_ENB | PM_CFG_ASPM_L0S_ENB); 694211105Syongari 695211105Syongari if ((sc->alc_flags & ALC_FLAG_APS) != 0) { 696211105Syongari /* Disable extended sync except AR8152 B v1.0 */ 697240693Sgavin linkcfg &= ~PCIEM_LINK_CTL_EXTENDED_SYNC; 698211105Syongari if (sc->alc_ident->deviceid == DEVICEID_ATHEROS_AR8152_B && 699211105Syongari sc->alc_rev == ATHEROS_AR8152_B_V10) 700240693Sgavin linkcfg |= PCIEM_LINK_CTL_EXTENDED_SYNC; 701240680Sgavin CSR_WRITE_2(sc, sc->alc_expcap + PCIER_LINK_CTL, 702211105Syongari linkcfg); 703211105Syongari pmcfg &= ~(PM_CFG_EN_BUFS_RX_L0S | PM_CFG_SA_DLY_ENB | 704211105Syongari PM_CFG_HOTRST); 705211105Syongari pmcfg |= (PM_CFG_L1_ENTRY_TIMER_DEFAULT << 706211105Syongari PM_CFG_L1_ENTRY_TIMER_SHIFT); 707211105Syongari pmcfg &= ~PM_CFG_PM_REQ_TIMER_MASK; 708211105Syongari pmcfg |= (PM_CFG_PM_REQ_TIMER_DEFAULT << 709211105Syongari PM_CFG_PM_REQ_TIMER_SHIFT); 710211105Syongari pmcfg |= PM_CFG_SERDES_PD_EX_L1 | PM_CFG_PCIE_RECV; 711211105Syongari } 712211105Syongari 713193880Syongari if ((sc->alc_flags & ALC_FLAG_LINK) != 0) { 714211105Syongari if ((sc->alc_flags & ALC_FLAG_L0S) != 0) 715211105Syongari pmcfg |= PM_CFG_ASPM_L0S_ENB; 716211105Syongari if ((sc->alc_flags & ALC_FLAG_L1S) != 0) 717211105Syongari pmcfg |= PM_CFG_ASPM_L1_ENB; 718211105Syongari if ((sc->alc_flags & ALC_FLAG_APS) != 0) { 719211105Syongari if (sc->alc_ident->deviceid == 720211105Syongari DEVICEID_ATHEROS_AR8152_B) 721211105Syongari pmcfg &= ~PM_CFG_ASPM_L0S_ENB; 722211105Syongari pmcfg &= ~(PM_CFG_SERDES_L1_ENB | 723211105Syongari PM_CFG_SERDES_PLL_L1_ENB | 724211105Syongari PM_CFG_SERDES_BUDS_RX_L1_ENB); 725211105Syongari pmcfg |= PM_CFG_CLK_SWH_L1; 726211105Syongari if (media == IFM_100_TX || media == IFM_1000_T) { 727211105Syongari pmcfg &= ~PM_CFG_L1_ENTRY_TIMER_MASK; 728211105Syongari switch (sc->alc_ident->deviceid) { 729211105Syongari case DEVICEID_ATHEROS_AR8152_B: 730211105Syongari pmcfg |= (7 << 731211105Syongari PM_CFG_L1_ENTRY_TIMER_SHIFT); 732211105Syongari break; 733211105Syongari case DEVICEID_ATHEROS_AR8152_B2: 734211105Syongari case DEVICEID_ATHEROS_AR8151_V2: 735211105Syongari pmcfg |= (4 << 736211105Syongari PM_CFG_L1_ENTRY_TIMER_SHIFT); 737211105Syongari break; 738211105Syongari default: 739211105Syongari pmcfg |= (15 << 740211105Syongari PM_CFG_L1_ENTRY_TIMER_SHIFT); 741211105Syongari break; 742211105Syongari } 743211105Syongari } 744211105Syongari } else { 745211105Syongari pmcfg |= PM_CFG_SERDES_L1_ENB | 746211105Syongari PM_CFG_SERDES_PLL_L1_ENB | 747211105Syongari PM_CFG_SERDES_BUDS_RX_L1_ENB; 748211105Syongari pmcfg &= ~(PM_CFG_CLK_SWH_L1 | 749211105Syongari PM_CFG_ASPM_L1_ENB | PM_CFG_ASPM_L0S_ENB); 750211105Syongari } 751193880Syongari } else { 752211105Syongari pmcfg &= ~(PM_CFG_SERDES_BUDS_RX_L1_ENB | PM_CFG_SERDES_L1_ENB | 753211105Syongari PM_CFG_SERDES_PLL_L1_ENB); 754193880Syongari pmcfg |= PM_CFG_CLK_SWH_L1; 755211105Syongari if ((sc->alc_flags & ALC_FLAG_L1S) != 0) 756211105Syongari pmcfg |= PM_CFG_ASPM_L1_ENB; 757193880Syongari } 758193880Syongari CSR_WRITE_4(sc, ALC_PM_CFG, pmcfg); 759193880Syongari} 760193880Syongari 761193880Syongaristatic int 762193880Syongarialc_attach(device_t dev) 763193880Syongari{ 764193880Syongari struct alc_softc *sc; 765193880Syongari struct ifnet *ifp; 766211105Syongari char *aspm_state[] = { "L0s/L1", "L0s", "L1", "L0s/L1" }; 767193880Syongari uint16_t burst; 768211053Syongari int base, error, i, msic, msixc, state; 769193880Syongari uint32_t cap, ctl, val; 770193880Syongari 771193880Syongari error = 0; 772193880Syongari sc = device_get_softc(dev); 773193880Syongari sc->alc_dev = dev; 774193880Syongari 775193880Syongari mtx_init(&sc->alc_mtx, device_get_nameunit(dev), MTX_NETWORK_LOCK, 776193880Syongari MTX_DEF); 777193880Syongari callout_init_mtx(&sc->alc_tick_ch, &sc->alc_mtx, 0); 778193880Syongari TASK_INIT(&sc->alc_int_task, 0, alc_int_task, sc); 779211105Syongari sc->alc_ident = alc_find_ident(dev); 780193880Syongari 781193880Syongari /* Map the device. */ 782193880Syongari pci_enable_busmaster(dev); 783193880Syongari sc->alc_res_spec = alc_res_spec_mem; 784193880Syongari sc->alc_irq_spec = alc_irq_spec_legacy; 785193880Syongari error = bus_alloc_resources(dev, sc->alc_res_spec, sc->alc_res); 786193880Syongari if (error != 0) { 787193880Syongari device_printf(dev, "cannot allocate memory resources.\n"); 788193880Syongari goto fail; 789193880Syongari } 790193880Syongari 791193880Syongari /* Set PHY address. */ 792193880Syongari sc->alc_phyaddr = ALC_PHY_ADDR; 793193880Syongari 794193880Syongari /* Initialize DMA parameters. */ 795193880Syongari sc->alc_dma_rd_burst = 0; 796193880Syongari sc->alc_dma_wr_burst = 0; 797193880Syongari sc->alc_rcb = DMA_CFG_RCB_64; 798219902Sjhb if (pci_find_cap(dev, PCIY_EXPRESS, &base) == 0) { 799193880Syongari sc->alc_flags |= ALC_FLAG_PCIE; 800211053Syongari sc->alc_expcap = base; 801240680Sgavin burst = CSR_READ_2(sc, base + PCIER_DEVICE_CTL); 802193880Syongari sc->alc_dma_rd_burst = 803240680Sgavin (burst & PCIEM_CTL_MAX_READ_REQUEST) >> 12; 804240680Sgavin sc->alc_dma_wr_burst = (burst & PCIEM_CTL_MAX_PAYLOAD) >> 5; 805193880Syongari if (bootverbose) { 806193880Syongari device_printf(dev, "Read request size : %u bytes.\n", 807193880Syongari alc_dma_burst[sc->alc_dma_rd_burst]); 808193880Syongari device_printf(dev, "TLP payload size : %u bytes.\n", 809193880Syongari alc_dma_burst[sc->alc_dma_wr_burst]); 810193880Syongari } 811211047Syongari if (alc_dma_burst[sc->alc_dma_rd_burst] > 1024) 812211047Syongari sc->alc_dma_rd_burst = 3; 813211047Syongari if (alc_dma_burst[sc->alc_dma_wr_burst] > 1024) 814211047Syongari sc->alc_dma_wr_burst = 3; 815193880Syongari /* Clear data link and flow-control protocol error. */ 816193880Syongari val = CSR_READ_4(sc, ALC_PEX_UNC_ERR_SEV); 817193880Syongari val &= ~(PEX_UNC_ERR_SEV_DLP | PEX_UNC_ERR_SEV_FCP); 818193880Syongari CSR_WRITE_4(sc, ALC_PEX_UNC_ERR_SEV, val); 819211105Syongari CSR_WRITE_4(sc, ALC_LTSSM_ID_CFG, 820211105Syongari CSR_READ_4(sc, ALC_LTSSM_ID_CFG) & ~LTSSM_ID_WRO_ENB); 821211105Syongari CSR_WRITE_4(sc, ALC_PCIE_PHYMISC, 822211105Syongari CSR_READ_4(sc, ALC_PCIE_PHYMISC) | 823211105Syongari PCIE_PHYMISC_FORCE_RCV_DET); 824211105Syongari if (sc->alc_ident->deviceid == DEVICEID_ATHEROS_AR8152_B && 825218141Syongari pci_get_revid(dev) == ATHEROS_AR8152_B_V10) { 826211105Syongari val = CSR_READ_4(sc, ALC_PCIE_PHYMISC2); 827211105Syongari val &= ~(PCIE_PHYMISC2_SERDES_CDR_MASK | 828211105Syongari PCIE_PHYMISC2_SERDES_TH_MASK); 829211105Syongari val |= 3 << PCIE_PHYMISC2_SERDES_CDR_SHIFT; 830211105Syongari val |= 3 << PCIE_PHYMISC2_SERDES_TH_SHIFT; 831211105Syongari CSR_WRITE_4(sc, ALC_PCIE_PHYMISC2, val); 832211105Syongari } 833193880Syongari /* Disable ASPM L0S and L1. */ 834240680Sgavin cap = CSR_READ_2(sc, base + PCIER_LINK_CAP); 835240680Sgavin if ((cap & PCIEM_LINK_CAP_ASPM) != 0) { 836240680Sgavin ctl = CSR_READ_2(sc, base + PCIER_LINK_CTL); 837240693Sgavin if ((ctl & PCIEM_LINK_CTL_RCB) != 0) 838193880Syongari sc->alc_rcb = DMA_CFG_RCB_128; 839193880Syongari if (bootverbose) 840193880Syongari device_printf(dev, "RCB %u bytes\n", 841193880Syongari sc->alc_rcb == DMA_CFG_RCB_64 ? 64 : 128); 842240693Sgavin state = ctl & PCIEM_LINK_CTL_ASPMC; 843240693Sgavin if (state & PCIEM_LINK_CTL_ASPMC_L0S) 844211105Syongari sc->alc_flags |= ALC_FLAG_L0S; 845240693Sgavin if (state & PCIEM_LINK_CTL_ASPMC_L1) 846211105Syongari sc->alc_flags |= ALC_FLAG_L1S; 847193880Syongari if (bootverbose) 848193880Syongari device_printf(sc->alc_dev, "ASPM %s %s\n", 849193880Syongari aspm_state[state], 850193880Syongari state == 0 ? "disabled" : "enabled"); 851211105Syongari alc_disable_l0s_l1(sc); 852211105Syongari } else { 853211105Syongari if (bootverbose) 854211105Syongari device_printf(sc->alc_dev, 855211105Syongari "no ASPM support\n"); 856193880Syongari } 857193880Syongari } 858193880Syongari 859193880Syongari /* Reset PHY. */ 860193880Syongari alc_phy_reset(sc); 861193880Syongari 862193880Syongari /* Reset the ethernet controller. */ 863193880Syongari alc_reset(sc); 864193880Syongari 865193880Syongari /* 866193880Syongari * One odd thing is AR8132 uses the same PHY hardware(F1 867193880Syongari * gigabit PHY) of AR8131. So atphy(4) of AR8132 reports 868193880Syongari * the PHY supports 1000Mbps but that's not true. The PHY 869193880Syongari * used in AR8132 can't establish gigabit link even if it 870193880Syongari * shows the same PHY model/revision number of AR8131. 871193880Syongari */ 872211105Syongari switch (sc->alc_ident->deviceid) { 873211105Syongari case DEVICEID_ATHEROS_AR8152_B: 874211105Syongari case DEVICEID_ATHEROS_AR8152_B2: 875211105Syongari sc->alc_flags |= ALC_FLAG_APS; 876211105Syongari /* FALLTHROUGH */ 877211105Syongari case DEVICEID_ATHEROS_AR8132: 878211105Syongari sc->alc_flags |= ALC_FLAG_FASTETHER; 879211105Syongari break; 880211105Syongari case DEVICEID_ATHEROS_AR8151: 881211105Syongari case DEVICEID_ATHEROS_AR8151_V2: 882211105Syongari sc->alc_flags |= ALC_FLAG_APS; 883211105Syongari /* FALLTHROUGH */ 884211105Syongari default: 885211105Syongari break; 886211105Syongari } 887211105Syongari sc->alc_flags |= ALC_FLAG_ASPM_MON | ALC_FLAG_JUMBO; 888211105Syongari 889193880Syongari /* 890211105Syongari * It seems that AR813x/AR815x has silicon bug for SMB. In 891193880Syongari * addition, Atheros said that enabling SMB wouldn't improve 892193880Syongari * performance. However I think it's bad to access lots of 893193880Syongari * registers to extract MAC statistics. 894193880Syongari */ 895193880Syongari sc->alc_flags |= ALC_FLAG_SMB_BUG; 896193880Syongari /* 897193880Syongari * Don't use Tx CMB. It is known to have silicon bug. 898193880Syongari */ 899193880Syongari sc->alc_flags |= ALC_FLAG_CMB_BUG; 900193880Syongari sc->alc_rev = pci_get_revid(dev); 901193880Syongari sc->alc_chip_rev = CSR_READ_4(sc, ALC_MASTER_CFG) >> 902193880Syongari MASTER_CHIP_REV_SHIFT; 903193880Syongari if (bootverbose) { 904193880Syongari device_printf(dev, "PCI device revision : 0x%04x\n", 905193880Syongari sc->alc_rev); 906193880Syongari device_printf(dev, "Chip id/revision : 0x%04x\n", 907193880Syongari sc->alc_chip_rev); 908193880Syongari } 909193880Syongari device_printf(dev, "%u Tx FIFO, %u Rx FIFO\n", 910193880Syongari CSR_READ_4(sc, ALC_SRAM_TX_FIFO_LEN) * 8, 911193880Syongari CSR_READ_4(sc, ALC_SRAM_RX_FIFO_LEN) * 8); 912193880Syongari 913193880Syongari /* Allocate IRQ resources. */ 914193880Syongari msixc = pci_msix_count(dev); 915193880Syongari msic = pci_msi_count(dev); 916193880Syongari if (bootverbose) { 917193880Syongari device_printf(dev, "MSIX count : %d\n", msixc); 918193880Syongari device_printf(dev, "MSI count : %d\n", msic); 919193880Syongari } 920193880Syongari /* Prefer MSIX over MSI. */ 921193880Syongari if (msix_disable == 0 || msi_disable == 0) { 922193880Syongari if (msix_disable == 0 && msixc == ALC_MSIX_MESSAGES && 923193880Syongari pci_alloc_msix(dev, &msixc) == 0) { 924193880Syongari if (msic == ALC_MSIX_MESSAGES) { 925193880Syongari device_printf(dev, 926193880Syongari "Using %d MSIX message(s).\n", msixc); 927193880Syongari sc->alc_flags |= ALC_FLAG_MSIX; 928193880Syongari sc->alc_irq_spec = alc_irq_spec_msix; 929193880Syongari } else 930193880Syongari pci_release_msi(dev); 931193880Syongari } 932193880Syongari if (msi_disable == 0 && (sc->alc_flags & ALC_FLAG_MSIX) == 0 && 933193880Syongari msic == ALC_MSI_MESSAGES && 934193880Syongari pci_alloc_msi(dev, &msic) == 0) { 935193880Syongari if (msic == ALC_MSI_MESSAGES) { 936193880Syongari device_printf(dev, 937193880Syongari "Using %d MSI message(s).\n", msic); 938193880Syongari sc->alc_flags |= ALC_FLAG_MSI; 939193880Syongari sc->alc_irq_spec = alc_irq_spec_msi; 940193880Syongari } else 941193880Syongari pci_release_msi(dev); 942193880Syongari } 943193880Syongari } 944193880Syongari 945193880Syongari error = bus_alloc_resources(dev, sc->alc_irq_spec, sc->alc_irq); 946193880Syongari if (error != 0) { 947193880Syongari device_printf(dev, "cannot allocate IRQ resources.\n"); 948193880Syongari goto fail; 949193880Syongari } 950193880Syongari 951193880Syongari /* Create device sysctl node. */ 952193880Syongari alc_sysctl_node(sc); 953193880Syongari 954193880Syongari if ((error = alc_dma_alloc(sc) != 0)) 955193880Syongari goto fail; 956193880Syongari 957193880Syongari /* Load station address. */ 958193880Syongari alc_get_macaddr(sc); 959193880Syongari 960193880Syongari ifp = sc->alc_ifp = if_alloc(IFT_ETHER); 961193880Syongari if (ifp == NULL) { 962193880Syongari device_printf(dev, "cannot allocate ifnet structure.\n"); 963193880Syongari error = ENXIO; 964193880Syongari goto fail; 965193880Syongari } 966193880Syongari 967193880Syongari ifp->if_softc = sc; 968193880Syongari if_initname(ifp, device_get_name(dev), device_get_unit(dev)); 969193880Syongari ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 970193880Syongari ifp->if_ioctl = alc_ioctl; 971193880Syongari ifp->if_start = alc_start; 972193880Syongari ifp->if_init = alc_init; 973193880Syongari ifp->if_snd.ifq_drv_maxlen = ALC_TX_RING_CNT - 1; 974193880Syongari IFQ_SET_MAXLEN(&ifp->if_snd, ifp->if_snd.ifq_drv_maxlen); 975193880Syongari IFQ_SET_READY(&ifp->if_snd); 976193880Syongari ifp->if_capabilities = IFCAP_TXCSUM | IFCAP_TSO4; 977193880Syongari ifp->if_hwassist = ALC_CSUM_FEATURES | CSUM_TSO; 978219902Sjhb if (pci_find_cap(dev, PCIY_PMG, &base) == 0) { 979193880Syongari ifp->if_capabilities |= IFCAP_WOL_MAGIC | IFCAP_WOL_MCAST; 980211053Syongari sc->alc_flags |= ALC_FLAG_PM; 981211053Syongari sc->alc_pmcap = base; 982211053Syongari } 983193880Syongari ifp->if_capenable = ifp->if_capabilities; 984193880Syongari 985193880Syongari /* Set up MII bus. */ 986213893Smarius error = mii_attach(dev, &sc->alc_miibus, ifp, alc_mediachange, 987213893Smarius alc_mediastatus, BMSR_DEFCAPMASK, sc->alc_phyaddr, MII_OFFSET_ANY, 988215850Syongari MIIF_DOPAUSE); 989213893Smarius if (error != 0) { 990213893Smarius device_printf(dev, "attaching PHYs failed\n"); 991193880Syongari goto fail; 992193880Syongari } 993193880Syongari 994193880Syongari ether_ifattach(ifp, sc->alc_eaddr); 995193880Syongari 996193880Syongari /* VLAN capability setup. */ 997204228Syongari ifp->if_capabilities |= IFCAP_VLAN_MTU | IFCAP_VLAN_HWTAGGING | 998204228Syongari IFCAP_VLAN_HWCSUM | IFCAP_VLAN_HWTSO; 999193880Syongari ifp->if_capenable = ifp->if_capabilities; 1000193880Syongari /* 1001193880Syongari * XXX 1002193880Syongari * It seems enabling Tx checksum offloading makes more trouble. 1003193880Syongari * Sometimes the controller does not receive any frames when 1004193880Syongari * Tx checksum offloading is enabled. I'm not sure whether this 1005193880Syongari * is a bug in Tx checksum offloading logic or I got broken 1006193880Syongari * sample boards. To safety, don't enable Tx checksum offloading 1007193880Syongari * by default but give chance to users to toggle it if they know 1008193880Syongari * their controllers work without problems. 1009193880Syongari */ 1010193880Syongari ifp->if_capenable &= ~IFCAP_TXCSUM; 1011193880Syongari ifp->if_hwassist &= ~ALC_CSUM_FEATURES; 1012193880Syongari 1013193880Syongari /* Tell the upper layer(s) we support long frames. */ 1014193880Syongari ifp->if_data.ifi_hdrlen = sizeof(struct ether_vlan_header); 1015193880Syongari 1016193880Syongari /* Create local taskq. */ 1017193880Syongari sc->alc_tq = taskqueue_create_fast("alc_taskq", M_WAITOK, 1018193880Syongari taskqueue_thread_enqueue, &sc->alc_tq); 1019193880Syongari if (sc->alc_tq == NULL) { 1020193880Syongari device_printf(dev, "could not create taskqueue.\n"); 1021193880Syongari ether_ifdetach(ifp); 1022193880Syongari error = ENXIO; 1023193880Syongari goto fail; 1024193880Syongari } 1025193880Syongari taskqueue_start_threads(&sc->alc_tq, 1, PI_NET, "%s taskq", 1026193880Syongari device_get_nameunit(sc->alc_dev)); 1027193880Syongari 1028193880Syongari if ((sc->alc_flags & ALC_FLAG_MSIX) != 0) 1029193880Syongari msic = ALC_MSIX_MESSAGES; 1030193880Syongari else if ((sc->alc_flags & ALC_FLAG_MSI) != 0) 1031193880Syongari msic = ALC_MSI_MESSAGES; 1032193880Syongari else 1033193880Syongari msic = 1; 1034193880Syongari for (i = 0; i < msic; i++) { 1035193880Syongari error = bus_setup_intr(dev, sc->alc_irq[i], 1036193880Syongari INTR_TYPE_NET | INTR_MPSAFE, alc_intr, NULL, sc, 1037193880Syongari &sc->alc_intrhand[i]); 1038193880Syongari if (error != 0) 1039193880Syongari break; 1040193880Syongari } 1041193880Syongari if (error != 0) { 1042193880Syongari device_printf(dev, "could not set up interrupt handler.\n"); 1043193880Syongari taskqueue_free(sc->alc_tq); 1044193880Syongari sc->alc_tq = NULL; 1045193880Syongari ether_ifdetach(ifp); 1046193880Syongari goto fail; 1047193880Syongari } 1048193880Syongari 1049193880Syongarifail: 1050193880Syongari if (error != 0) 1051193880Syongari alc_detach(dev); 1052193880Syongari 1053193880Syongari return (error); 1054193880Syongari} 1055193880Syongari 1056193880Syongaristatic int 1057193880Syongarialc_detach(device_t dev) 1058193880Syongari{ 1059193880Syongari struct alc_softc *sc; 1060193880Syongari struct ifnet *ifp; 1061193880Syongari int i, msic; 1062193880Syongari 1063193880Syongari sc = device_get_softc(dev); 1064193880Syongari 1065193880Syongari ifp = sc->alc_ifp; 1066193880Syongari if (device_is_attached(dev)) { 1067217379Sjhb ether_ifdetach(ifp); 1068193880Syongari ALC_LOCK(sc); 1069193880Syongari alc_stop(sc); 1070193880Syongari ALC_UNLOCK(sc); 1071193880Syongari callout_drain(&sc->alc_tick_ch); 1072193880Syongari taskqueue_drain(sc->alc_tq, &sc->alc_int_task); 1073193880Syongari } 1074193880Syongari 1075193880Syongari if (sc->alc_tq != NULL) { 1076193880Syongari taskqueue_drain(sc->alc_tq, &sc->alc_int_task); 1077193880Syongari taskqueue_free(sc->alc_tq); 1078193880Syongari sc->alc_tq = NULL; 1079193880Syongari } 1080193880Syongari 1081193880Syongari if (sc->alc_miibus != NULL) { 1082193880Syongari device_delete_child(dev, sc->alc_miibus); 1083193880Syongari sc->alc_miibus = NULL; 1084193880Syongari } 1085193880Syongari bus_generic_detach(dev); 1086193880Syongari alc_dma_free(sc); 1087193880Syongari 1088193880Syongari if (ifp != NULL) { 1089193880Syongari if_free(ifp); 1090193880Syongari sc->alc_ifp = NULL; 1091193880Syongari } 1092193880Syongari 1093193880Syongari if ((sc->alc_flags & ALC_FLAG_MSIX) != 0) 1094193880Syongari msic = ALC_MSIX_MESSAGES; 1095193880Syongari else if ((sc->alc_flags & ALC_FLAG_MSI) != 0) 1096193880Syongari msic = ALC_MSI_MESSAGES; 1097193880Syongari else 1098193880Syongari msic = 1; 1099193880Syongari for (i = 0; i < msic; i++) { 1100193880Syongari if (sc->alc_intrhand[i] != NULL) { 1101193880Syongari bus_teardown_intr(dev, sc->alc_irq[i], 1102193880Syongari sc->alc_intrhand[i]); 1103193880Syongari sc->alc_intrhand[i] = NULL; 1104193880Syongari } 1105193880Syongari } 1106196517Syongari if (sc->alc_res[0] != NULL) 1107196517Syongari alc_phy_down(sc); 1108193880Syongari bus_release_resources(dev, sc->alc_irq_spec, sc->alc_irq); 1109193880Syongari if ((sc->alc_flags & (ALC_FLAG_MSI | ALC_FLAG_MSIX)) != 0) 1110193880Syongari pci_release_msi(dev); 1111193880Syongari bus_release_resources(dev, sc->alc_res_spec, sc->alc_res); 1112193880Syongari mtx_destroy(&sc->alc_mtx); 1113193880Syongari 1114193880Syongari return (0); 1115193880Syongari} 1116193880Syongari 1117193880Syongari#define ALC_SYSCTL_STAT_ADD32(c, h, n, p, d) \ 1118193880Syongari SYSCTL_ADD_UINT(c, h, OID_AUTO, n, CTLFLAG_RD, p, 0, d) 1119193880Syongari#define ALC_SYSCTL_STAT_ADD64(c, h, n, p, d) \ 1120217323Smdf SYSCTL_ADD_UQUAD(c, h, OID_AUTO, n, CTLFLAG_RD, p, d) 1121193880Syongari 1122193880Syongaristatic void 1123193880Syongarialc_sysctl_node(struct alc_softc *sc) 1124193880Syongari{ 1125193880Syongari struct sysctl_ctx_list *ctx; 1126193880Syongari struct sysctl_oid_list *child, *parent; 1127193880Syongari struct sysctl_oid *tree; 1128193880Syongari struct alc_hw_stats *stats; 1129193880Syongari int error; 1130193880Syongari 1131193880Syongari stats = &sc->alc_stats; 1132193880Syongari ctx = device_get_sysctl_ctx(sc->alc_dev); 1133193880Syongari child = SYSCTL_CHILDREN(device_get_sysctl_tree(sc->alc_dev)); 1134193880Syongari 1135193880Syongari SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "int_rx_mod", 1136193880Syongari CTLTYPE_INT | CTLFLAG_RW, &sc->alc_int_rx_mod, 0, 1137193880Syongari sysctl_hw_alc_int_mod, "I", "alc Rx interrupt moderation"); 1138193880Syongari SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "int_tx_mod", 1139193880Syongari CTLTYPE_INT | CTLFLAG_RW, &sc->alc_int_tx_mod, 0, 1140193880Syongari sysctl_hw_alc_int_mod, "I", "alc Tx interrupt moderation"); 1141193880Syongari /* Pull in device tunables. */ 1142193880Syongari sc->alc_int_rx_mod = ALC_IM_RX_TIMER_DEFAULT; 1143193880Syongari error = resource_int_value(device_get_name(sc->alc_dev), 1144193880Syongari device_get_unit(sc->alc_dev), "int_rx_mod", &sc->alc_int_rx_mod); 1145193880Syongari if (error == 0) { 1146193880Syongari if (sc->alc_int_rx_mod < ALC_IM_TIMER_MIN || 1147193880Syongari sc->alc_int_rx_mod > ALC_IM_TIMER_MAX) { 1148193880Syongari device_printf(sc->alc_dev, "int_rx_mod value out of " 1149193880Syongari "range; using default: %d\n", 1150193880Syongari ALC_IM_RX_TIMER_DEFAULT); 1151193880Syongari sc->alc_int_rx_mod = ALC_IM_RX_TIMER_DEFAULT; 1152193880Syongari } 1153193880Syongari } 1154193880Syongari sc->alc_int_tx_mod = ALC_IM_TX_TIMER_DEFAULT; 1155193880Syongari error = resource_int_value(device_get_name(sc->alc_dev), 1156193880Syongari device_get_unit(sc->alc_dev), "int_tx_mod", &sc->alc_int_tx_mod); 1157193880Syongari if (error == 0) { 1158193880Syongari if (sc->alc_int_tx_mod < ALC_IM_TIMER_MIN || 1159193880Syongari sc->alc_int_tx_mod > ALC_IM_TIMER_MAX) { 1160193880Syongari device_printf(sc->alc_dev, "int_tx_mod value out of " 1161193880Syongari "range; using default: %d\n", 1162193880Syongari ALC_IM_TX_TIMER_DEFAULT); 1163193880Syongari sc->alc_int_tx_mod = ALC_IM_TX_TIMER_DEFAULT; 1164193880Syongari } 1165193880Syongari } 1166193880Syongari SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "process_limit", 1167193880Syongari CTLTYPE_INT | CTLFLAG_RW, &sc->alc_process_limit, 0, 1168193880Syongari sysctl_hw_alc_proc_limit, "I", 1169193880Syongari "max number of Rx events to process"); 1170193880Syongari /* Pull in device tunables. */ 1171193880Syongari sc->alc_process_limit = ALC_PROC_DEFAULT; 1172193880Syongari error = resource_int_value(device_get_name(sc->alc_dev), 1173193880Syongari device_get_unit(sc->alc_dev), "process_limit", 1174193880Syongari &sc->alc_process_limit); 1175193880Syongari if (error == 0) { 1176193880Syongari if (sc->alc_process_limit < ALC_PROC_MIN || 1177193880Syongari sc->alc_process_limit > ALC_PROC_MAX) { 1178193880Syongari device_printf(sc->alc_dev, 1179193880Syongari "process_limit value out of range; " 1180193880Syongari "using default: %d\n", ALC_PROC_DEFAULT); 1181193880Syongari sc->alc_process_limit = ALC_PROC_DEFAULT; 1182193880Syongari } 1183193880Syongari } 1184193880Syongari 1185193880Syongari tree = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, "stats", CTLFLAG_RD, 1186193880Syongari NULL, "ALC statistics"); 1187193880Syongari parent = SYSCTL_CHILDREN(tree); 1188193880Syongari 1189193880Syongari /* Rx statistics. */ 1190193880Syongari tree = SYSCTL_ADD_NODE(ctx, parent, OID_AUTO, "rx", CTLFLAG_RD, 1191193880Syongari NULL, "Rx MAC statistics"); 1192193880Syongari child = SYSCTL_CHILDREN(tree); 1193193880Syongari ALC_SYSCTL_STAT_ADD32(ctx, child, "good_frames", 1194193880Syongari &stats->rx_frames, "Good frames"); 1195193880Syongari ALC_SYSCTL_STAT_ADD32(ctx, child, "good_bcast_frames", 1196193880Syongari &stats->rx_bcast_frames, "Good broadcast frames"); 1197193880Syongari ALC_SYSCTL_STAT_ADD32(ctx, child, "good_mcast_frames", 1198193880Syongari &stats->rx_mcast_frames, "Good multicast frames"); 1199193880Syongari ALC_SYSCTL_STAT_ADD32(ctx, child, "pause_frames", 1200193880Syongari &stats->rx_pause_frames, "Pause control frames"); 1201193880Syongari ALC_SYSCTL_STAT_ADD32(ctx, child, "control_frames", 1202193880Syongari &stats->rx_control_frames, "Control frames"); 1203193880Syongari ALC_SYSCTL_STAT_ADD32(ctx, child, "crc_errs", 1204193880Syongari &stats->rx_crcerrs, "CRC errors"); 1205193880Syongari ALC_SYSCTL_STAT_ADD32(ctx, child, "len_errs", 1206193880Syongari &stats->rx_lenerrs, "Frames with length mismatched"); 1207193880Syongari ALC_SYSCTL_STAT_ADD64(ctx, child, "good_octets", 1208193880Syongari &stats->rx_bytes, "Good octets"); 1209193880Syongari ALC_SYSCTL_STAT_ADD64(ctx, child, "good_bcast_octets", 1210193880Syongari &stats->rx_bcast_bytes, "Good broadcast octets"); 1211193880Syongari ALC_SYSCTL_STAT_ADD64(ctx, child, "good_mcast_octets", 1212193880Syongari &stats->rx_mcast_bytes, "Good multicast octets"); 1213193880Syongari ALC_SYSCTL_STAT_ADD32(ctx, child, "runts", 1214193880Syongari &stats->rx_runts, "Too short frames"); 1215193880Syongari ALC_SYSCTL_STAT_ADD32(ctx, child, "fragments", 1216193880Syongari &stats->rx_fragments, "Fragmented frames"); 1217193880Syongari ALC_SYSCTL_STAT_ADD32(ctx, child, "frames_64", 1218193880Syongari &stats->rx_pkts_64, "64 bytes frames"); 1219193880Syongari ALC_SYSCTL_STAT_ADD32(ctx, child, "frames_65_127", 1220193880Syongari &stats->rx_pkts_65_127, "65 to 127 bytes frames"); 1221193880Syongari ALC_SYSCTL_STAT_ADD32(ctx, child, "frames_128_255", 1222193880Syongari &stats->rx_pkts_128_255, "128 to 255 bytes frames"); 1223193880Syongari ALC_SYSCTL_STAT_ADD32(ctx, child, "frames_256_511", 1224193880Syongari &stats->rx_pkts_256_511, "256 to 511 bytes frames"); 1225193880Syongari ALC_SYSCTL_STAT_ADD32(ctx, child, "frames_512_1023", 1226193880Syongari &stats->rx_pkts_512_1023, "512 to 1023 bytes frames"); 1227193880Syongari ALC_SYSCTL_STAT_ADD32(ctx, child, "frames_1024_1518", 1228193880Syongari &stats->rx_pkts_1024_1518, "1024 to 1518 bytes frames"); 1229193880Syongari ALC_SYSCTL_STAT_ADD32(ctx, child, "frames_1519_max", 1230193880Syongari &stats->rx_pkts_1519_max, "1519 to max frames"); 1231193880Syongari ALC_SYSCTL_STAT_ADD32(ctx, child, "trunc_errs", 1232193880Syongari &stats->rx_pkts_truncated, "Truncated frames due to MTU size"); 1233193880Syongari ALC_SYSCTL_STAT_ADD32(ctx, child, "fifo_oflows", 1234193880Syongari &stats->rx_fifo_oflows, "FIFO overflows"); 1235193880Syongari ALC_SYSCTL_STAT_ADD32(ctx, child, "rrs_errs", 1236193880Syongari &stats->rx_rrs_errs, "Return status write-back errors"); 1237193880Syongari ALC_SYSCTL_STAT_ADD32(ctx, child, "align_errs", 1238193880Syongari &stats->rx_alignerrs, "Alignment errors"); 1239193880Syongari ALC_SYSCTL_STAT_ADD32(ctx, child, "filtered", 1240193880Syongari &stats->rx_pkts_filtered, 1241193880Syongari "Frames dropped due to address filtering"); 1242193880Syongari 1243193880Syongari /* Tx statistics. */ 1244193880Syongari tree = SYSCTL_ADD_NODE(ctx, parent, OID_AUTO, "tx", CTLFLAG_RD, 1245193880Syongari NULL, "Tx MAC statistics"); 1246193880Syongari child = SYSCTL_CHILDREN(tree); 1247193880Syongari ALC_SYSCTL_STAT_ADD32(ctx, child, "good_frames", 1248193880Syongari &stats->tx_frames, "Good frames"); 1249193880Syongari ALC_SYSCTL_STAT_ADD32(ctx, child, "good_bcast_frames", 1250193880Syongari &stats->tx_bcast_frames, "Good broadcast frames"); 1251193880Syongari ALC_SYSCTL_STAT_ADD32(ctx, child, "good_mcast_frames", 1252193880Syongari &stats->tx_mcast_frames, "Good multicast frames"); 1253193880Syongari ALC_SYSCTL_STAT_ADD32(ctx, child, "pause_frames", 1254193880Syongari &stats->tx_pause_frames, "Pause control frames"); 1255193880Syongari ALC_SYSCTL_STAT_ADD32(ctx, child, "control_frames", 1256193880Syongari &stats->tx_control_frames, "Control frames"); 1257193880Syongari ALC_SYSCTL_STAT_ADD32(ctx, child, "excess_defers", 1258193880Syongari &stats->tx_excess_defer, "Frames with excessive derferrals"); 1259193880Syongari ALC_SYSCTL_STAT_ADD32(ctx, child, "defers", 1260193880Syongari &stats->tx_excess_defer, "Frames with derferrals"); 1261193880Syongari ALC_SYSCTL_STAT_ADD64(ctx, child, "good_octets", 1262193880Syongari &stats->tx_bytes, "Good octets"); 1263193880Syongari ALC_SYSCTL_STAT_ADD64(ctx, child, "good_bcast_octets", 1264193880Syongari &stats->tx_bcast_bytes, "Good broadcast octets"); 1265193880Syongari ALC_SYSCTL_STAT_ADD64(ctx, child, "good_mcast_octets", 1266193880Syongari &stats->tx_mcast_bytes, "Good multicast octets"); 1267193880Syongari ALC_SYSCTL_STAT_ADD32(ctx, child, "frames_64", 1268193880Syongari &stats->tx_pkts_64, "64 bytes frames"); 1269193880Syongari ALC_SYSCTL_STAT_ADD32(ctx, child, "frames_65_127", 1270193880Syongari &stats->tx_pkts_65_127, "65 to 127 bytes frames"); 1271193880Syongari ALC_SYSCTL_STAT_ADD32(ctx, child, "frames_128_255", 1272193880Syongari &stats->tx_pkts_128_255, "128 to 255 bytes frames"); 1273193880Syongari ALC_SYSCTL_STAT_ADD32(ctx, child, "frames_256_511", 1274193880Syongari &stats->tx_pkts_256_511, "256 to 511 bytes frames"); 1275193880Syongari ALC_SYSCTL_STAT_ADD32(ctx, child, "frames_512_1023", 1276193880Syongari &stats->tx_pkts_512_1023, "512 to 1023 bytes frames"); 1277193880Syongari ALC_SYSCTL_STAT_ADD32(ctx, child, "frames_1024_1518", 1278193880Syongari &stats->tx_pkts_1024_1518, "1024 to 1518 bytes frames"); 1279193880Syongari ALC_SYSCTL_STAT_ADD32(ctx, child, "frames_1519_max", 1280193880Syongari &stats->tx_pkts_1519_max, "1519 to max frames"); 1281193880Syongari ALC_SYSCTL_STAT_ADD32(ctx, child, "single_colls", 1282193880Syongari &stats->tx_single_colls, "Single collisions"); 1283193880Syongari ALC_SYSCTL_STAT_ADD32(ctx, child, "multi_colls", 1284193880Syongari &stats->tx_multi_colls, "Multiple collisions"); 1285193880Syongari ALC_SYSCTL_STAT_ADD32(ctx, child, "late_colls", 1286193880Syongari &stats->tx_late_colls, "Late collisions"); 1287193880Syongari ALC_SYSCTL_STAT_ADD32(ctx, child, "excess_colls", 1288193880Syongari &stats->tx_excess_colls, "Excessive collisions"); 1289193880Syongari ALC_SYSCTL_STAT_ADD32(ctx, child, "abort", 1290193880Syongari &stats->tx_abort, "Aborted frames due to Excessive collisions"); 1291193880Syongari ALC_SYSCTL_STAT_ADD32(ctx, child, "underruns", 1292193880Syongari &stats->tx_underrun, "FIFO underruns"); 1293193880Syongari ALC_SYSCTL_STAT_ADD32(ctx, child, "desc_underruns", 1294193880Syongari &stats->tx_desc_underrun, "Descriptor write-back errors"); 1295193880Syongari ALC_SYSCTL_STAT_ADD32(ctx, child, "len_errs", 1296193880Syongari &stats->tx_lenerrs, "Frames with length mismatched"); 1297193880Syongari ALC_SYSCTL_STAT_ADD32(ctx, child, "trunc_errs", 1298193880Syongari &stats->tx_pkts_truncated, "Truncated frames due to MTU size"); 1299193880Syongari} 1300193880Syongari 1301193880Syongari#undef ALC_SYSCTL_STAT_ADD32 1302193880Syongari#undef ALC_SYSCTL_STAT_ADD64 1303193880Syongari 1304193880Syongaristruct alc_dmamap_arg { 1305193880Syongari bus_addr_t alc_busaddr; 1306193880Syongari}; 1307193880Syongari 1308193880Syongaristatic void 1309193880Syongarialc_dmamap_cb(void *arg, bus_dma_segment_t *segs, int nsegs, int error) 1310193880Syongari{ 1311193880Syongari struct alc_dmamap_arg *ctx; 1312193880Syongari 1313193880Syongari if (error != 0) 1314193880Syongari return; 1315193880Syongari 1316193880Syongari KASSERT(nsegs == 1, ("%s: %d segments returned!", __func__, nsegs)); 1317193880Syongari 1318193880Syongari ctx = (struct alc_dmamap_arg *)arg; 1319193880Syongari ctx->alc_busaddr = segs[0].ds_addr; 1320193880Syongari} 1321193880Syongari 1322193880Syongari/* 1323193880Syongari * Normal and high Tx descriptors shares single Tx high address. 1324193880Syongari * Four Rx descriptor/return rings and CMB shares the same Rx 1325193880Syongari * high address. 1326193880Syongari */ 1327193880Syongaristatic int 1328193880Syongarialc_check_boundary(struct alc_softc *sc) 1329193880Syongari{ 1330193880Syongari bus_addr_t cmb_end, rx_ring_end, rr_ring_end, tx_ring_end; 1331193880Syongari 1332193880Syongari rx_ring_end = sc->alc_rdata.alc_rx_ring_paddr + ALC_RX_RING_SZ; 1333193880Syongari rr_ring_end = sc->alc_rdata.alc_rr_ring_paddr + ALC_RR_RING_SZ; 1334193880Syongari cmb_end = sc->alc_rdata.alc_cmb_paddr + ALC_CMB_SZ; 1335193880Syongari tx_ring_end = sc->alc_rdata.alc_tx_ring_paddr + ALC_TX_RING_SZ; 1336193880Syongari 1337193880Syongari /* 4GB boundary crossing is not allowed. */ 1338193880Syongari if ((ALC_ADDR_HI(rx_ring_end) != 1339193880Syongari ALC_ADDR_HI(sc->alc_rdata.alc_rx_ring_paddr)) || 1340193880Syongari (ALC_ADDR_HI(rr_ring_end) != 1341193880Syongari ALC_ADDR_HI(sc->alc_rdata.alc_rr_ring_paddr)) || 1342193880Syongari (ALC_ADDR_HI(cmb_end) != 1343193880Syongari ALC_ADDR_HI(sc->alc_rdata.alc_cmb_paddr)) || 1344193880Syongari (ALC_ADDR_HI(tx_ring_end) != 1345193880Syongari ALC_ADDR_HI(sc->alc_rdata.alc_tx_ring_paddr))) 1346193880Syongari return (EFBIG); 1347193880Syongari /* 1348193880Syongari * Make sure Rx return descriptor/Rx descriptor/CMB use 1349193880Syongari * the same high address. 1350193880Syongari */ 1351193880Syongari if ((ALC_ADDR_HI(rx_ring_end) != ALC_ADDR_HI(rr_ring_end)) || 1352193880Syongari (ALC_ADDR_HI(rx_ring_end) != ALC_ADDR_HI(cmb_end))) 1353193880Syongari return (EFBIG); 1354193880Syongari 1355193880Syongari return (0); 1356193880Syongari} 1357193880Syongari 1358193880Syongaristatic int 1359193880Syongarialc_dma_alloc(struct alc_softc *sc) 1360193880Syongari{ 1361193880Syongari struct alc_txdesc *txd; 1362193880Syongari struct alc_rxdesc *rxd; 1363193880Syongari bus_addr_t lowaddr; 1364193880Syongari struct alc_dmamap_arg ctx; 1365193880Syongari int error, i; 1366193880Syongari 1367193880Syongari lowaddr = BUS_SPACE_MAXADDR; 1368193880Syongariagain: 1369193880Syongari /* Create parent DMA tag. */ 1370193880Syongari error = bus_dma_tag_create( 1371193880Syongari bus_get_dma_tag(sc->alc_dev), /* parent */ 1372193880Syongari 1, 0, /* alignment, boundary */ 1373193880Syongari lowaddr, /* lowaddr */ 1374193880Syongari BUS_SPACE_MAXADDR, /* highaddr */ 1375193880Syongari NULL, NULL, /* filter, filterarg */ 1376193880Syongari BUS_SPACE_MAXSIZE_32BIT, /* maxsize */ 1377193880Syongari 0, /* nsegments */ 1378193880Syongari BUS_SPACE_MAXSIZE_32BIT, /* maxsegsize */ 1379193880Syongari 0, /* flags */ 1380193880Syongari NULL, NULL, /* lockfunc, lockarg */ 1381193880Syongari &sc->alc_cdata.alc_parent_tag); 1382193880Syongari if (error != 0) { 1383193880Syongari device_printf(sc->alc_dev, 1384193880Syongari "could not create parent DMA tag.\n"); 1385193880Syongari goto fail; 1386193880Syongari } 1387193880Syongari 1388193880Syongari /* Create DMA tag for Tx descriptor ring. */ 1389193880Syongari error = bus_dma_tag_create( 1390193880Syongari sc->alc_cdata.alc_parent_tag, /* parent */ 1391193880Syongari ALC_TX_RING_ALIGN, 0, /* alignment, boundary */ 1392193880Syongari BUS_SPACE_MAXADDR, /* lowaddr */ 1393193880Syongari BUS_SPACE_MAXADDR, /* highaddr */ 1394193880Syongari NULL, NULL, /* filter, filterarg */ 1395193880Syongari ALC_TX_RING_SZ, /* maxsize */ 1396193880Syongari 1, /* nsegments */ 1397193880Syongari ALC_TX_RING_SZ, /* maxsegsize */ 1398193880Syongari 0, /* flags */ 1399193880Syongari NULL, NULL, /* lockfunc, lockarg */ 1400193880Syongari &sc->alc_cdata.alc_tx_ring_tag); 1401193880Syongari if (error != 0) { 1402193880Syongari device_printf(sc->alc_dev, 1403193880Syongari "could not create Tx ring DMA tag.\n"); 1404193880Syongari goto fail; 1405193880Syongari } 1406193880Syongari 1407193880Syongari /* Create DMA tag for Rx free descriptor ring. */ 1408193880Syongari error = bus_dma_tag_create( 1409193880Syongari sc->alc_cdata.alc_parent_tag, /* parent */ 1410193880Syongari ALC_RX_RING_ALIGN, 0, /* alignment, boundary */ 1411193880Syongari BUS_SPACE_MAXADDR, /* lowaddr */ 1412193880Syongari BUS_SPACE_MAXADDR, /* highaddr */ 1413193880Syongari NULL, NULL, /* filter, filterarg */ 1414193880Syongari ALC_RX_RING_SZ, /* maxsize */ 1415193880Syongari 1, /* nsegments */ 1416193880Syongari ALC_RX_RING_SZ, /* maxsegsize */ 1417193880Syongari 0, /* flags */ 1418193880Syongari NULL, NULL, /* lockfunc, lockarg */ 1419193880Syongari &sc->alc_cdata.alc_rx_ring_tag); 1420193880Syongari if (error != 0) { 1421193880Syongari device_printf(sc->alc_dev, 1422193880Syongari "could not create Rx ring DMA tag.\n"); 1423193880Syongari goto fail; 1424193880Syongari } 1425193880Syongari /* Create DMA tag for Rx return descriptor ring. */ 1426193880Syongari error = bus_dma_tag_create( 1427193880Syongari sc->alc_cdata.alc_parent_tag, /* parent */ 1428193880Syongari ALC_RR_RING_ALIGN, 0, /* alignment, boundary */ 1429193880Syongari BUS_SPACE_MAXADDR, /* lowaddr */ 1430193880Syongari BUS_SPACE_MAXADDR, /* highaddr */ 1431193880Syongari NULL, NULL, /* filter, filterarg */ 1432193880Syongari ALC_RR_RING_SZ, /* maxsize */ 1433193880Syongari 1, /* nsegments */ 1434193880Syongari ALC_RR_RING_SZ, /* maxsegsize */ 1435193880Syongari 0, /* flags */ 1436193880Syongari NULL, NULL, /* lockfunc, lockarg */ 1437193880Syongari &sc->alc_cdata.alc_rr_ring_tag); 1438193880Syongari if (error != 0) { 1439193880Syongari device_printf(sc->alc_dev, 1440193880Syongari "could not create Rx return ring DMA tag.\n"); 1441193880Syongari goto fail; 1442193880Syongari } 1443193880Syongari 1444193880Syongari /* Create DMA tag for coalescing message block. */ 1445193880Syongari error = bus_dma_tag_create( 1446193880Syongari sc->alc_cdata.alc_parent_tag, /* parent */ 1447193880Syongari ALC_CMB_ALIGN, 0, /* alignment, boundary */ 1448193880Syongari BUS_SPACE_MAXADDR, /* lowaddr */ 1449193880Syongari BUS_SPACE_MAXADDR, /* highaddr */ 1450193880Syongari NULL, NULL, /* filter, filterarg */ 1451193880Syongari ALC_CMB_SZ, /* maxsize */ 1452193880Syongari 1, /* nsegments */ 1453193880Syongari ALC_CMB_SZ, /* maxsegsize */ 1454193880Syongari 0, /* flags */ 1455193880Syongari NULL, NULL, /* lockfunc, lockarg */ 1456193880Syongari &sc->alc_cdata.alc_cmb_tag); 1457193880Syongari if (error != 0) { 1458193880Syongari device_printf(sc->alc_dev, 1459193880Syongari "could not create CMB DMA tag.\n"); 1460193880Syongari goto fail; 1461193880Syongari } 1462193880Syongari /* Create DMA tag for status message block. */ 1463193880Syongari error = bus_dma_tag_create( 1464193880Syongari sc->alc_cdata.alc_parent_tag, /* parent */ 1465193880Syongari ALC_SMB_ALIGN, 0, /* alignment, boundary */ 1466193880Syongari BUS_SPACE_MAXADDR, /* lowaddr */ 1467193880Syongari BUS_SPACE_MAXADDR, /* highaddr */ 1468193880Syongari NULL, NULL, /* filter, filterarg */ 1469193880Syongari ALC_SMB_SZ, /* maxsize */ 1470193880Syongari 1, /* nsegments */ 1471193880Syongari ALC_SMB_SZ, /* maxsegsize */ 1472193880Syongari 0, /* flags */ 1473193880Syongari NULL, NULL, /* lockfunc, lockarg */ 1474193880Syongari &sc->alc_cdata.alc_smb_tag); 1475193880Syongari if (error != 0) { 1476193880Syongari device_printf(sc->alc_dev, 1477193880Syongari "could not create SMB DMA tag.\n"); 1478193880Syongari goto fail; 1479193880Syongari } 1480193880Syongari 1481193880Syongari /* Allocate DMA'able memory and load the DMA map for Tx ring. */ 1482193880Syongari error = bus_dmamem_alloc(sc->alc_cdata.alc_tx_ring_tag, 1483193880Syongari (void **)&sc->alc_rdata.alc_tx_ring, 1484193880Syongari BUS_DMA_WAITOK | BUS_DMA_ZERO | BUS_DMA_COHERENT, 1485193880Syongari &sc->alc_cdata.alc_tx_ring_map); 1486193880Syongari if (error != 0) { 1487193880Syongari device_printf(sc->alc_dev, 1488193880Syongari "could not allocate DMA'able memory for Tx ring.\n"); 1489193880Syongari goto fail; 1490193880Syongari } 1491193880Syongari ctx.alc_busaddr = 0; 1492193880Syongari error = bus_dmamap_load(sc->alc_cdata.alc_tx_ring_tag, 1493193880Syongari sc->alc_cdata.alc_tx_ring_map, sc->alc_rdata.alc_tx_ring, 1494193880Syongari ALC_TX_RING_SZ, alc_dmamap_cb, &ctx, 0); 1495193880Syongari if (error != 0 || ctx.alc_busaddr == 0) { 1496193880Syongari device_printf(sc->alc_dev, 1497193880Syongari "could not load DMA'able memory for Tx ring.\n"); 1498193880Syongari goto fail; 1499193880Syongari } 1500193880Syongari sc->alc_rdata.alc_tx_ring_paddr = ctx.alc_busaddr; 1501193880Syongari 1502193880Syongari /* Allocate DMA'able memory and load the DMA map for Rx ring. */ 1503193880Syongari error = bus_dmamem_alloc(sc->alc_cdata.alc_rx_ring_tag, 1504193880Syongari (void **)&sc->alc_rdata.alc_rx_ring, 1505193880Syongari BUS_DMA_WAITOK | BUS_DMA_ZERO | BUS_DMA_COHERENT, 1506193880Syongari &sc->alc_cdata.alc_rx_ring_map); 1507193880Syongari if (error != 0) { 1508193880Syongari device_printf(sc->alc_dev, 1509193880Syongari "could not allocate DMA'able memory for Rx ring.\n"); 1510193880Syongari goto fail; 1511193880Syongari } 1512193880Syongari ctx.alc_busaddr = 0; 1513193880Syongari error = bus_dmamap_load(sc->alc_cdata.alc_rx_ring_tag, 1514193880Syongari sc->alc_cdata.alc_rx_ring_map, sc->alc_rdata.alc_rx_ring, 1515193880Syongari ALC_RX_RING_SZ, alc_dmamap_cb, &ctx, 0); 1516193880Syongari if (error != 0 || ctx.alc_busaddr == 0) { 1517193880Syongari device_printf(sc->alc_dev, 1518193880Syongari "could not load DMA'able memory for Rx ring.\n"); 1519193880Syongari goto fail; 1520193880Syongari } 1521193880Syongari sc->alc_rdata.alc_rx_ring_paddr = ctx.alc_busaddr; 1522193880Syongari 1523193880Syongari /* Allocate DMA'able memory and load the DMA map for Rx return ring. */ 1524193880Syongari error = bus_dmamem_alloc(sc->alc_cdata.alc_rr_ring_tag, 1525193880Syongari (void **)&sc->alc_rdata.alc_rr_ring, 1526193880Syongari BUS_DMA_WAITOK | BUS_DMA_ZERO | BUS_DMA_COHERENT, 1527193880Syongari &sc->alc_cdata.alc_rr_ring_map); 1528193880Syongari if (error != 0) { 1529193880Syongari device_printf(sc->alc_dev, 1530193880Syongari "could not allocate DMA'able memory for Rx return ring.\n"); 1531193880Syongari goto fail; 1532193880Syongari } 1533193880Syongari ctx.alc_busaddr = 0; 1534193880Syongari error = bus_dmamap_load(sc->alc_cdata.alc_rr_ring_tag, 1535193880Syongari sc->alc_cdata.alc_rr_ring_map, sc->alc_rdata.alc_rr_ring, 1536193880Syongari ALC_RR_RING_SZ, alc_dmamap_cb, &ctx, 0); 1537193880Syongari if (error != 0 || ctx.alc_busaddr == 0) { 1538193880Syongari device_printf(sc->alc_dev, 1539193880Syongari "could not load DMA'able memory for Tx ring.\n"); 1540193880Syongari goto fail; 1541193880Syongari } 1542193880Syongari sc->alc_rdata.alc_rr_ring_paddr = ctx.alc_busaddr; 1543193880Syongari 1544193880Syongari /* Allocate DMA'able memory and load the DMA map for CMB. */ 1545193880Syongari error = bus_dmamem_alloc(sc->alc_cdata.alc_cmb_tag, 1546193880Syongari (void **)&sc->alc_rdata.alc_cmb, 1547193880Syongari BUS_DMA_WAITOK | BUS_DMA_ZERO | BUS_DMA_COHERENT, 1548193880Syongari &sc->alc_cdata.alc_cmb_map); 1549193880Syongari if (error != 0) { 1550193880Syongari device_printf(sc->alc_dev, 1551193880Syongari "could not allocate DMA'able memory for CMB.\n"); 1552193880Syongari goto fail; 1553193880Syongari } 1554193880Syongari ctx.alc_busaddr = 0; 1555193880Syongari error = bus_dmamap_load(sc->alc_cdata.alc_cmb_tag, 1556193880Syongari sc->alc_cdata.alc_cmb_map, sc->alc_rdata.alc_cmb, 1557193880Syongari ALC_CMB_SZ, alc_dmamap_cb, &ctx, 0); 1558193880Syongari if (error != 0 || ctx.alc_busaddr == 0) { 1559193880Syongari device_printf(sc->alc_dev, 1560193880Syongari "could not load DMA'able memory for CMB.\n"); 1561193880Syongari goto fail; 1562193880Syongari } 1563193880Syongari sc->alc_rdata.alc_cmb_paddr = ctx.alc_busaddr; 1564193880Syongari 1565193880Syongari /* Allocate DMA'able memory and load the DMA map for SMB. */ 1566193880Syongari error = bus_dmamem_alloc(sc->alc_cdata.alc_smb_tag, 1567193880Syongari (void **)&sc->alc_rdata.alc_smb, 1568193880Syongari BUS_DMA_WAITOK | BUS_DMA_ZERO | BUS_DMA_COHERENT, 1569193880Syongari &sc->alc_cdata.alc_smb_map); 1570193880Syongari if (error != 0) { 1571193880Syongari device_printf(sc->alc_dev, 1572193880Syongari "could not allocate DMA'able memory for SMB.\n"); 1573193880Syongari goto fail; 1574193880Syongari } 1575193880Syongari ctx.alc_busaddr = 0; 1576193880Syongari error = bus_dmamap_load(sc->alc_cdata.alc_smb_tag, 1577193880Syongari sc->alc_cdata.alc_smb_map, sc->alc_rdata.alc_smb, 1578193880Syongari ALC_SMB_SZ, alc_dmamap_cb, &ctx, 0); 1579193880Syongari if (error != 0 || ctx.alc_busaddr == 0) { 1580193880Syongari device_printf(sc->alc_dev, 1581193880Syongari "could not load DMA'able memory for CMB.\n"); 1582193880Syongari goto fail; 1583193880Syongari } 1584193880Syongari sc->alc_rdata.alc_smb_paddr = ctx.alc_busaddr; 1585193880Syongari 1586193880Syongari /* Make sure we've not crossed 4GB boundary. */ 1587193880Syongari if (lowaddr != BUS_SPACE_MAXADDR_32BIT && 1588193880Syongari (error = alc_check_boundary(sc)) != 0) { 1589193880Syongari device_printf(sc->alc_dev, "4GB boundary crossed, " 1590193880Syongari "switching to 32bit DMA addressing mode.\n"); 1591193880Syongari alc_dma_free(sc); 1592193880Syongari /* 1593193880Syongari * Limit max allowable DMA address space to 32bit 1594193880Syongari * and try again. 1595193880Syongari */ 1596193880Syongari lowaddr = BUS_SPACE_MAXADDR_32BIT; 1597193880Syongari goto again; 1598193880Syongari } 1599193880Syongari 1600193880Syongari /* 1601193880Syongari * Create Tx buffer parent tag. 1602211105Syongari * AR813x/AR815x allows 64bit DMA addressing of Tx/Rx buffers 1603193880Syongari * so it needs separate parent DMA tag as parent DMA address 1604193880Syongari * space could be restricted to be within 32bit address space 1605193880Syongari * by 4GB boundary crossing. 1606193880Syongari */ 1607193880Syongari error = bus_dma_tag_create( 1608193880Syongari bus_get_dma_tag(sc->alc_dev), /* parent */ 1609193880Syongari 1, 0, /* alignment, boundary */ 1610193880Syongari BUS_SPACE_MAXADDR, /* lowaddr */ 1611193880Syongari BUS_SPACE_MAXADDR, /* highaddr */ 1612193880Syongari NULL, NULL, /* filter, filterarg */ 1613193880Syongari BUS_SPACE_MAXSIZE_32BIT, /* maxsize */ 1614193880Syongari 0, /* nsegments */ 1615193880Syongari BUS_SPACE_MAXSIZE_32BIT, /* maxsegsize */ 1616193880Syongari 0, /* flags */ 1617193880Syongari NULL, NULL, /* lockfunc, lockarg */ 1618193880Syongari &sc->alc_cdata.alc_buffer_tag); 1619193880Syongari if (error != 0) { 1620193880Syongari device_printf(sc->alc_dev, 1621193880Syongari "could not create parent buffer DMA tag.\n"); 1622193880Syongari goto fail; 1623193880Syongari } 1624193880Syongari 1625193880Syongari /* Create DMA tag for Tx buffers. */ 1626193880Syongari error = bus_dma_tag_create( 1627193880Syongari sc->alc_cdata.alc_buffer_tag, /* parent */ 1628193880Syongari 1, 0, /* alignment, boundary */ 1629193880Syongari BUS_SPACE_MAXADDR, /* lowaddr */ 1630193880Syongari BUS_SPACE_MAXADDR, /* highaddr */ 1631193880Syongari NULL, NULL, /* filter, filterarg */ 1632193880Syongari ALC_TSO_MAXSIZE, /* maxsize */ 1633193880Syongari ALC_MAXTXSEGS, /* nsegments */ 1634193880Syongari ALC_TSO_MAXSEGSIZE, /* maxsegsize */ 1635193880Syongari 0, /* flags */ 1636193880Syongari NULL, NULL, /* lockfunc, lockarg */ 1637193880Syongari &sc->alc_cdata.alc_tx_tag); 1638193880Syongari if (error != 0) { 1639193880Syongari device_printf(sc->alc_dev, "could not create Tx DMA tag.\n"); 1640193880Syongari goto fail; 1641193880Syongari } 1642193880Syongari 1643193880Syongari /* Create DMA tag for Rx buffers. */ 1644193880Syongari error = bus_dma_tag_create( 1645193880Syongari sc->alc_cdata.alc_buffer_tag, /* parent */ 1646193880Syongari ALC_RX_BUF_ALIGN, 0, /* alignment, boundary */ 1647193880Syongari BUS_SPACE_MAXADDR, /* lowaddr */ 1648193880Syongari BUS_SPACE_MAXADDR, /* highaddr */ 1649193880Syongari NULL, NULL, /* filter, filterarg */ 1650193880Syongari MCLBYTES, /* maxsize */ 1651193880Syongari 1, /* nsegments */ 1652193880Syongari MCLBYTES, /* maxsegsize */ 1653193880Syongari 0, /* flags */ 1654193880Syongari NULL, NULL, /* lockfunc, lockarg */ 1655193880Syongari &sc->alc_cdata.alc_rx_tag); 1656193880Syongari if (error != 0) { 1657193880Syongari device_printf(sc->alc_dev, "could not create Rx DMA tag.\n"); 1658193880Syongari goto fail; 1659193880Syongari } 1660193880Syongari /* Create DMA maps for Tx buffers. */ 1661193880Syongari for (i = 0; i < ALC_TX_RING_CNT; i++) { 1662193880Syongari txd = &sc->alc_cdata.alc_txdesc[i]; 1663193880Syongari txd->tx_m = NULL; 1664193880Syongari txd->tx_dmamap = NULL; 1665193880Syongari error = bus_dmamap_create(sc->alc_cdata.alc_tx_tag, 0, 1666193880Syongari &txd->tx_dmamap); 1667193880Syongari if (error != 0) { 1668193880Syongari device_printf(sc->alc_dev, 1669193880Syongari "could not create Tx dmamap.\n"); 1670193880Syongari goto fail; 1671193880Syongari } 1672193880Syongari } 1673193880Syongari /* Create DMA maps for Rx buffers. */ 1674193880Syongari if ((error = bus_dmamap_create(sc->alc_cdata.alc_rx_tag, 0, 1675193880Syongari &sc->alc_cdata.alc_rx_sparemap)) != 0) { 1676193880Syongari device_printf(sc->alc_dev, 1677193880Syongari "could not create spare Rx dmamap.\n"); 1678193880Syongari goto fail; 1679193880Syongari } 1680193880Syongari for (i = 0; i < ALC_RX_RING_CNT; i++) { 1681193880Syongari rxd = &sc->alc_cdata.alc_rxdesc[i]; 1682193880Syongari rxd->rx_m = NULL; 1683193880Syongari rxd->rx_dmamap = NULL; 1684193880Syongari error = bus_dmamap_create(sc->alc_cdata.alc_rx_tag, 0, 1685193880Syongari &rxd->rx_dmamap); 1686193880Syongari if (error != 0) { 1687193880Syongari device_printf(sc->alc_dev, 1688193880Syongari "could not create Rx dmamap.\n"); 1689193880Syongari goto fail; 1690193880Syongari } 1691193880Syongari } 1692193880Syongari 1693193880Syongarifail: 1694193880Syongari return (error); 1695193880Syongari} 1696193880Syongari 1697193880Syongaristatic void 1698193880Syongarialc_dma_free(struct alc_softc *sc) 1699193880Syongari{ 1700193880Syongari struct alc_txdesc *txd; 1701193880Syongari struct alc_rxdesc *rxd; 1702193880Syongari int i; 1703193880Syongari 1704193880Syongari /* Tx buffers. */ 1705193880Syongari if (sc->alc_cdata.alc_tx_tag != NULL) { 1706193880Syongari for (i = 0; i < ALC_TX_RING_CNT; i++) { 1707193880Syongari txd = &sc->alc_cdata.alc_txdesc[i]; 1708193880Syongari if (txd->tx_dmamap != NULL) { 1709193880Syongari bus_dmamap_destroy(sc->alc_cdata.alc_tx_tag, 1710193880Syongari txd->tx_dmamap); 1711193880Syongari txd->tx_dmamap = NULL; 1712193880Syongari } 1713193880Syongari } 1714193880Syongari bus_dma_tag_destroy(sc->alc_cdata.alc_tx_tag); 1715193880Syongari sc->alc_cdata.alc_tx_tag = NULL; 1716193880Syongari } 1717193880Syongari /* Rx buffers */ 1718193880Syongari if (sc->alc_cdata.alc_rx_tag != NULL) { 1719193880Syongari for (i = 0; i < ALC_RX_RING_CNT; i++) { 1720193880Syongari rxd = &sc->alc_cdata.alc_rxdesc[i]; 1721193880Syongari if (rxd->rx_dmamap != NULL) { 1722193880Syongari bus_dmamap_destroy(sc->alc_cdata.alc_rx_tag, 1723193880Syongari rxd->rx_dmamap); 1724193880Syongari rxd->rx_dmamap = NULL; 1725193880Syongari } 1726193880Syongari } 1727193880Syongari if (sc->alc_cdata.alc_rx_sparemap != NULL) { 1728193880Syongari bus_dmamap_destroy(sc->alc_cdata.alc_rx_tag, 1729193880Syongari sc->alc_cdata.alc_rx_sparemap); 1730193880Syongari sc->alc_cdata.alc_rx_sparemap = NULL; 1731193880Syongari } 1732193880Syongari bus_dma_tag_destroy(sc->alc_cdata.alc_rx_tag); 1733193880Syongari sc->alc_cdata.alc_rx_tag = NULL; 1734193880Syongari } 1735193880Syongari /* Tx descriptor ring. */ 1736193880Syongari if (sc->alc_cdata.alc_tx_ring_tag != NULL) { 1737193880Syongari if (sc->alc_cdata.alc_tx_ring_map != NULL) 1738193880Syongari bus_dmamap_unload(sc->alc_cdata.alc_tx_ring_tag, 1739193880Syongari sc->alc_cdata.alc_tx_ring_map); 1740193880Syongari if (sc->alc_cdata.alc_tx_ring_map != NULL && 1741193880Syongari sc->alc_rdata.alc_tx_ring != NULL) 1742193880Syongari bus_dmamem_free(sc->alc_cdata.alc_tx_ring_tag, 1743193880Syongari sc->alc_rdata.alc_tx_ring, 1744193880Syongari sc->alc_cdata.alc_tx_ring_map); 1745193880Syongari sc->alc_rdata.alc_tx_ring = NULL; 1746193880Syongari sc->alc_cdata.alc_tx_ring_map = NULL; 1747193880Syongari bus_dma_tag_destroy(sc->alc_cdata.alc_tx_ring_tag); 1748193880Syongari sc->alc_cdata.alc_tx_ring_tag = NULL; 1749193880Syongari } 1750195989Skevlo /* Rx ring. */ 1751195989Skevlo if (sc->alc_cdata.alc_rx_ring_tag != NULL) { 1752195989Skevlo if (sc->alc_cdata.alc_rx_ring_map != NULL) 1753195989Skevlo bus_dmamap_unload(sc->alc_cdata.alc_rx_ring_tag, 1754195989Skevlo sc->alc_cdata.alc_rx_ring_map); 1755195989Skevlo if (sc->alc_cdata.alc_rx_ring_map != NULL && 1756195989Skevlo sc->alc_rdata.alc_rx_ring != NULL) 1757195989Skevlo bus_dmamem_free(sc->alc_cdata.alc_rx_ring_tag, 1758195989Skevlo sc->alc_rdata.alc_rx_ring, 1759195989Skevlo sc->alc_cdata.alc_rx_ring_map); 1760195989Skevlo sc->alc_rdata.alc_rx_ring = NULL; 1761195989Skevlo sc->alc_cdata.alc_rx_ring_map = NULL; 1762195989Skevlo bus_dma_tag_destroy(sc->alc_cdata.alc_rx_ring_tag); 1763195989Skevlo sc->alc_cdata.alc_rx_ring_tag = NULL; 1764195989Skevlo } 1765193880Syongari /* Rx return ring. */ 1766193880Syongari if (sc->alc_cdata.alc_rr_ring_tag != NULL) { 1767193880Syongari if (sc->alc_cdata.alc_rr_ring_map != NULL) 1768193880Syongari bus_dmamap_unload(sc->alc_cdata.alc_rr_ring_tag, 1769193880Syongari sc->alc_cdata.alc_rr_ring_map); 1770193880Syongari if (sc->alc_cdata.alc_rr_ring_map != NULL && 1771193880Syongari sc->alc_rdata.alc_rr_ring != NULL) 1772193880Syongari bus_dmamem_free(sc->alc_cdata.alc_rr_ring_tag, 1773193880Syongari sc->alc_rdata.alc_rr_ring, 1774193880Syongari sc->alc_cdata.alc_rr_ring_map); 1775193880Syongari sc->alc_rdata.alc_rr_ring = NULL; 1776193880Syongari sc->alc_cdata.alc_rr_ring_map = NULL; 1777193880Syongari bus_dma_tag_destroy(sc->alc_cdata.alc_rr_ring_tag); 1778193880Syongari sc->alc_cdata.alc_rr_ring_tag = NULL; 1779193880Syongari } 1780193880Syongari /* CMB block */ 1781193880Syongari if (sc->alc_cdata.alc_cmb_tag != NULL) { 1782193880Syongari if (sc->alc_cdata.alc_cmb_map != NULL) 1783193880Syongari bus_dmamap_unload(sc->alc_cdata.alc_cmb_tag, 1784193880Syongari sc->alc_cdata.alc_cmb_map); 1785193880Syongari if (sc->alc_cdata.alc_cmb_map != NULL && 1786193880Syongari sc->alc_rdata.alc_cmb != NULL) 1787193880Syongari bus_dmamem_free(sc->alc_cdata.alc_cmb_tag, 1788193880Syongari sc->alc_rdata.alc_cmb, 1789193880Syongari sc->alc_cdata.alc_cmb_map); 1790193880Syongari sc->alc_rdata.alc_cmb = NULL; 1791193880Syongari sc->alc_cdata.alc_cmb_map = NULL; 1792193880Syongari bus_dma_tag_destroy(sc->alc_cdata.alc_cmb_tag); 1793193880Syongari sc->alc_cdata.alc_cmb_tag = NULL; 1794193880Syongari } 1795193880Syongari /* SMB block */ 1796193880Syongari if (sc->alc_cdata.alc_smb_tag != NULL) { 1797193880Syongari if (sc->alc_cdata.alc_smb_map != NULL) 1798193880Syongari bus_dmamap_unload(sc->alc_cdata.alc_smb_tag, 1799193880Syongari sc->alc_cdata.alc_smb_map); 1800193880Syongari if (sc->alc_cdata.alc_smb_map != NULL && 1801193880Syongari sc->alc_rdata.alc_smb != NULL) 1802193880Syongari bus_dmamem_free(sc->alc_cdata.alc_smb_tag, 1803193880Syongari sc->alc_rdata.alc_smb, 1804193880Syongari sc->alc_cdata.alc_smb_map); 1805193880Syongari sc->alc_rdata.alc_smb = NULL; 1806193880Syongari sc->alc_cdata.alc_smb_map = NULL; 1807193880Syongari bus_dma_tag_destroy(sc->alc_cdata.alc_smb_tag); 1808193880Syongari sc->alc_cdata.alc_smb_tag = NULL; 1809193880Syongari } 1810193880Syongari if (sc->alc_cdata.alc_buffer_tag != NULL) { 1811193880Syongari bus_dma_tag_destroy(sc->alc_cdata.alc_buffer_tag); 1812193880Syongari sc->alc_cdata.alc_buffer_tag = NULL; 1813193880Syongari } 1814193880Syongari if (sc->alc_cdata.alc_parent_tag != NULL) { 1815193880Syongari bus_dma_tag_destroy(sc->alc_cdata.alc_parent_tag); 1816193880Syongari sc->alc_cdata.alc_parent_tag = NULL; 1817193880Syongari } 1818193880Syongari} 1819193880Syongari 1820193880Syongaristatic int 1821193880Syongarialc_shutdown(device_t dev) 1822193880Syongari{ 1823193880Syongari 1824193880Syongari return (alc_suspend(dev)); 1825193880Syongari} 1826193880Syongari 1827193880Syongari/* 1828193880Syongari * Note, this driver resets the link speed to 10/100Mbps by 1829193880Syongari * restarting auto-negotiation in suspend/shutdown phase but we 1830193880Syongari * don't know whether that auto-negotiation would succeed or not 1831193880Syongari * as driver has no control after powering off/suspend operation. 1832193880Syongari * If the renegotiation fail WOL may not work. Running at 1Gbps 1833193880Syongari * will draw more power than 375mA at 3.3V which is specified in 1834193880Syongari * PCI specification and that would result in complete 1835193880Syongari * shutdowning power to ethernet controller. 1836193880Syongari * 1837193880Syongari * TODO 1838193880Syongari * Save current negotiated media speed/duplex/flow-control to 1839193880Syongari * softc and restore the same link again after resuming. PHY 1840193880Syongari * handling such as power down/resetting to 100Mbps may be better 1841193880Syongari * handled in suspend method in phy driver. 1842193880Syongari */ 1843193880Syongaristatic void 1844193880Syongarialc_setlinkspeed(struct alc_softc *sc) 1845193880Syongari{ 1846193880Syongari struct mii_data *mii; 1847193880Syongari int aneg, i; 1848193880Syongari 1849193880Syongari mii = device_get_softc(sc->alc_miibus); 1850193880Syongari mii_pollstat(mii); 1851193880Syongari aneg = 0; 1852193880Syongari if ((mii->mii_media_status & (IFM_ACTIVE | IFM_AVALID)) == 1853193880Syongari (IFM_ACTIVE | IFM_AVALID)) { 1854193880Syongari switch IFM_SUBTYPE(mii->mii_media_active) { 1855193880Syongari case IFM_10_T: 1856193880Syongari case IFM_100_TX: 1857193880Syongari return; 1858193880Syongari case IFM_1000_T: 1859193880Syongari aneg++; 1860193880Syongari break; 1861193880Syongari default: 1862193880Syongari break; 1863193880Syongari } 1864193880Syongari } 1865193880Syongari alc_miibus_writereg(sc->alc_dev, sc->alc_phyaddr, MII_100T2CR, 0); 1866193880Syongari alc_miibus_writereg(sc->alc_dev, sc->alc_phyaddr, 1867193880Syongari MII_ANAR, ANAR_TX_FD | ANAR_TX | ANAR_10_FD | ANAR_10 | ANAR_CSMA); 1868193880Syongari alc_miibus_writereg(sc->alc_dev, sc->alc_phyaddr, 1869193880Syongari MII_BMCR, BMCR_RESET | BMCR_AUTOEN | BMCR_STARTNEG); 1870193880Syongari DELAY(1000); 1871193880Syongari if (aneg != 0) { 1872193880Syongari /* 1873193880Syongari * Poll link state until alc(4) get a 10/100Mbps link. 1874193880Syongari */ 1875193880Syongari for (i = 0; i < MII_ANEGTICKS_GIGE; i++) { 1876193880Syongari mii_pollstat(mii); 1877193880Syongari if ((mii->mii_media_status & (IFM_ACTIVE | IFM_AVALID)) 1878193880Syongari == (IFM_ACTIVE | IFM_AVALID)) { 1879193880Syongari switch (IFM_SUBTYPE( 1880193880Syongari mii->mii_media_active)) { 1881193880Syongari case IFM_10_T: 1882193880Syongari case IFM_100_TX: 1883193880Syongari alc_mac_config(sc); 1884193880Syongari return; 1885193880Syongari default: 1886193880Syongari break; 1887193880Syongari } 1888193880Syongari } 1889193880Syongari ALC_UNLOCK(sc); 1890193880Syongari pause("alclnk", hz); 1891193880Syongari ALC_LOCK(sc); 1892193880Syongari } 1893193880Syongari if (i == MII_ANEGTICKS_GIGE) 1894193880Syongari device_printf(sc->alc_dev, 1895193880Syongari "establishing a link failed, WOL may not work!"); 1896193880Syongari } 1897193880Syongari /* 1898193880Syongari * No link, force MAC to have 100Mbps, full-duplex link. 1899193880Syongari * This is the last resort and may/may not work. 1900193880Syongari */ 1901193880Syongari mii->mii_media_status = IFM_AVALID | IFM_ACTIVE; 1902193880Syongari mii->mii_media_active = IFM_ETHER | IFM_100_TX | IFM_FDX; 1903193880Syongari alc_mac_config(sc); 1904193880Syongari} 1905193880Syongari 1906193880Syongaristatic void 1907193880Syongarialc_setwol(struct alc_softc *sc) 1908193880Syongari{ 1909193880Syongari struct ifnet *ifp; 1910211051Syongari uint32_t reg, pmcs; 1911193880Syongari uint16_t pmstat; 1912193880Syongari 1913193880Syongari ALC_LOCK_ASSERT(sc); 1914193880Syongari 1915211051Syongari alc_disable_l0s_l1(sc); 1916211051Syongari ifp = sc->alc_ifp; 1917211053Syongari if ((sc->alc_flags & ALC_FLAG_PM) == 0) { 1918193880Syongari /* Disable WOL. */ 1919193880Syongari CSR_WRITE_4(sc, ALC_WOL_CFG, 0); 1920193880Syongari reg = CSR_READ_4(sc, ALC_PCIE_PHYMISC); 1921193880Syongari reg |= PCIE_PHYMISC_FORCE_RCV_DET; 1922193880Syongari CSR_WRITE_4(sc, ALC_PCIE_PHYMISC, reg); 1923193880Syongari /* Force PHY power down. */ 1924193880Syongari alc_phy_down(sc); 1925211051Syongari CSR_WRITE_4(sc, ALC_MASTER_CFG, 1926211051Syongari CSR_READ_4(sc, ALC_MASTER_CFG) | MASTER_CLK_SEL_DIS); 1927193880Syongari return; 1928193880Syongari } 1929193880Syongari 1930193880Syongari if ((ifp->if_capenable & IFCAP_WOL) != 0) { 1931193880Syongari if ((sc->alc_flags & ALC_FLAG_FASTETHER) == 0) 1932193880Syongari alc_setlinkspeed(sc); 1933211051Syongari CSR_WRITE_4(sc, ALC_MASTER_CFG, 1934211051Syongari CSR_READ_4(sc, ALC_MASTER_CFG) & ~MASTER_CLK_SEL_DIS); 1935193880Syongari } 1936193880Syongari 1937193880Syongari pmcs = 0; 1938193880Syongari if ((ifp->if_capenable & IFCAP_WOL_MAGIC) != 0) 1939193880Syongari pmcs |= WOL_CFG_MAGIC | WOL_CFG_MAGIC_ENB; 1940193880Syongari CSR_WRITE_4(sc, ALC_WOL_CFG, pmcs); 1941193880Syongari reg = CSR_READ_4(sc, ALC_MAC_CFG); 1942193880Syongari reg &= ~(MAC_CFG_DBG | MAC_CFG_PROMISC | MAC_CFG_ALLMULTI | 1943193880Syongari MAC_CFG_BCAST); 1944193880Syongari if ((ifp->if_capenable & IFCAP_WOL_MCAST) != 0) 1945193880Syongari reg |= MAC_CFG_ALLMULTI | MAC_CFG_BCAST; 1946193880Syongari if ((ifp->if_capenable & IFCAP_WOL) != 0) 1947193880Syongari reg |= MAC_CFG_RX_ENB; 1948193880Syongari CSR_WRITE_4(sc, ALC_MAC_CFG, reg); 1949193880Syongari 1950193880Syongari reg = CSR_READ_4(sc, ALC_PCIE_PHYMISC); 1951193880Syongari reg |= PCIE_PHYMISC_FORCE_RCV_DET; 1952193880Syongari CSR_WRITE_4(sc, ALC_PCIE_PHYMISC, reg); 1953193880Syongari if ((ifp->if_capenable & IFCAP_WOL) == 0) { 1954193880Syongari /* WOL disabled, PHY power down. */ 1955193880Syongari alc_phy_down(sc); 1956211051Syongari CSR_WRITE_4(sc, ALC_MASTER_CFG, 1957211051Syongari CSR_READ_4(sc, ALC_MASTER_CFG) | MASTER_CLK_SEL_DIS); 1958193880Syongari } 1959193880Syongari /* Request PME. */ 1960211053Syongari pmstat = pci_read_config(sc->alc_dev, 1961211053Syongari sc->alc_pmcap + PCIR_POWER_STATUS, 2); 1962193880Syongari pmstat &= ~(PCIM_PSTAT_PME | PCIM_PSTAT_PMEENABLE); 1963193880Syongari if ((ifp->if_capenable & IFCAP_WOL) != 0) 1964193880Syongari pmstat |= PCIM_PSTAT_PME | PCIM_PSTAT_PMEENABLE; 1965211053Syongari pci_write_config(sc->alc_dev, 1966211053Syongari sc->alc_pmcap + PCIR_POWER_STATUS, pmstat, 2); 1967193880Syongari} 1968193880Syongari 1969193880Syongaristatic int 1970193880Syongarialc_suspend(device_t dev) 1971193880Syongari{ 1972193880Syongari struct alc_softc *sc; 1973193880Syongari 1974193880Syongari sc = device_get_softc(dev); 1975193880Syongari 1976193880Syongari ALC_LOCK(sc); 1977193880Syongari alc_stop(sc); 1978193880Syongari alc_setwol(sc); 1979193880Syongari ALC_UNLOCK(sc); 1980193880Syongari 1981193880Syongari return (0); 1982193880Syongari} 1983193880Syongari 1984193880Syongaristatic int 1985193880Syongarialc_resume(device_t dev) 1986193880Syongari{ 1987193880Syongari struct alc_softc *sc; 1988193880Syongari struct ifnet *ifp; 1989193880Syongari uint16_t pmstat; 1990193880Syongari 1991193880Syongari sc = device_get_softc(dev); 1992193880Syongari 1993193880Syongari ALC_LOCK(sc); 1994211053Syongari if ((sc->alc_flags & ALC_FLAG_PM) != 0) { 1995193880Syongari /* Disable PME and clear PME status. */ 1996193880Syongari pmstat = pci_read_config(sc->alc_dev, 1997211053Syongari sc->alc_pmcap + PCIR_POWER_STATUS, 2); 1998193880Syongari if ((pmstat & PCIM_PSTAT_PMEENABLE) != 0) { 1999193880Syongari pmstat &= ~PCIM_PSTAT_PMEENABLE; 2000193880Syongari pci_write_config(sc->alc_dev, 2001211053Syongari sc->alc_pmcap + PCIR_POWER_STATUS, pmstat, 2); 2002193880Syongari } 2003193880Syongari } 2004193880Syongari /* Reset PHY. */ 2005193880Syongari alc_phy_reset(sc); 2006193880Syongari ifp = sc->alc_ifp; 2007193880Syongari if ((ifp->if_flags & IFF_UP) != 0) { 2008193880Syongari ifp->if_drv_flags &= ~IFF_DRV_RUNNING; 2009193880Syongari alc_init_locked(sc); 2010193880Syongari } 2011193880Syongari ALC_UNLOCK(sc); 2012193880Syongari 2013193880Syongari return (0); 2014193880Syongari} 2015193880Syongari 2016193880Syongaristatic int 2017193880Syongarialc_encap(struct alc_softc *sc, struct mbuf **m_head) 2018193880Syongari{ 2019193880Syongari struct alc_txdesc *txd, *txd_last; 2020193880Syongari struct tx_desc *desc; 2021193880Syongari struct mbuf *m; 2022193880Syongari struct ip *ip; 2023193880Syongari struct tcphdr *tcp; 2024193880Syongari bus_dma_segment_t txsegs[ALC_MAXTXSEGS]; 2025193880Syongari bus_dmamap_t map; 2026213842Syongari uint32_t cflags, hdrlen, ip_off, poff, vtag; 2027193880Syongari int error, idx, nsegs, prod; 2028193880Syongari 2029193880Syongari ALC_LOCK_ASSERT(sc); 2030193880Syongari 2031193880Syongari M_ASSERTPKTHDR((*m_head)); 2032193880Syongari 2033193880Syongari m = *m_head; 2034193880Syongari ip = NULL; 2035193880Syongari tcp = NULL; 2036213842Syongari ip_off = poff = 0; 2037193880Syongari if ((m->m_pkthdr.csum_flags & (ALC_CSUM_FEATURES | CSUM_TSO)) != 0) { 2038193880Syongari /* 2039211105Syongari * AR813x/AR815x requires offset of TCP/UDP header in its 2040193880Syongari * Tx descriptor to perform Tx checksum offloading. TSO 2041193880Syongari * also requires TCP header offset and modification of 2042193880Syongari * IP/TCP header. This kind of operation takes many CPU 2043193880Syongari * cycles on FreeBSD so fast host CPU is required to get 2044193880Syongari * smooth TSO performance. 2045193880Syongari */ 2046213842Syongari struct ether_header *eh; 2047193880Syongari 2048193880Syongari if (M_WRITABLE(m) == 0) { 2049193880Syongari /* Get a writable copy. */ 2050243857Sglebius m = m_dup(*m_head, M_NOWAIT); 2051193880Syongari /* Release original mbufs. */ 2052193880Syongari m_freem(*m_head); 2053193880Syongari if (m == NULL) { 2054193880Syongari *m_head = NULL; 2055193880Syongari return (ENOBUFS); 2056193880Syongari } 2057193880Syongari *m_head = m; 2058193880Syongari } 2059193880Syongari 2060213842Syongari ip_off = sizeof(struct ether_header); 2061213842Syongari m = m_pullup(m, ip_off); 2062193880Syongari if (m == NULL) { 2063193880Syongari *m_head = NULL; 2064193880Syongari return (ENOBUFS); 2065193880Syongari } 2066213842Syongari eh = mtod(m, struct ether_header *); 2067213842Syongari /* 2068213842Syongari * Check if hardware VLAN insertion is off. 2069213842Syongari * Additional check for LLC/SNAP frame? 2070213842Syongari */ 2071213842Syongari if (eh->ether_type == htons(ETHERTYPE_VLAN)) { 2072213842Syongari ip_off = sizeof(struct ether_vlan_header); 2073213842Syongari m = m_pullup(m, ip_off); 2074213842Syongari if (m == NULL) { 2075213842Syongari *m_head = NULL; 2076213842Syongari return (ENOBUFS); 2077213842Syongari } 2078213842Syongari } 2079213842Syongari m = m_pullup(m, ip_off + sizeof(struct ip)); 2080213842Syongari if (m == NULL) { 2081213842Syongari *m_head = NULL; 2082213842Syongari return (ENOBUFS); 2083213842Syongari } 2084213842Syongari ip = (struct ip *)(mtod(m, char *) + ip_off); 2085213842Syongari poff = ip_off + (ip->ip_hl << 2); 2086193880Syongari if ((m->m_pkthdr.csum_flags & CSUM_TSO) != 0) { 2087193880Syongari m = m_pullup(m, poff + sizeof(struct tcphdr)); 2088193880Syongari if (m == NULL) { 2089193880Syongari *m_head = NULL; 2090193880Syongari return (ENOBUFS); 2091193880Syongari } 2092193880Syongari tcp = (struct tcphdr *)(mtod(m, char *) + poff); 2093193880Syongari m = m_pullup(m, poff + (tcp->th_off << 2)); 2094193880Syongari if (m == NULL) { 2095193880Syongari *m_head = NULL; 2096193880Syongari return (ENOBUFS); 2097193880Syongari } 2098193880Syongari /* 2099193880Syongari * Due to strict adherence of Microsoft NDIS 2100193880Syongari * Large Send specification, hardware expects 2101193880Syongari * a pseudo TCP checksum inserted by upper 2102193880Syongari * stack. Unfortunately the pseudo TCP 2103193880Syongari * checksum that NDIS refers to does not include 2104193880Syongari * TCP payload length so driver should recompute 2105193880Syongari * the pseudo checksum here. Hopefully this 2106193880Syongari * wouldn't be much burden on modern CPUs. 2107193880Syongari * 2108193880Syongari * Reset IP checksum and recompute TCP pseudo 2109193880Syongari * checksum as NDIS specification said. 2110193880Syongari */ 2111213844Syongari ip = (struct ip *)(mtod(m, char *) + ip_off); 2112213844Syongari tcp = (struct tcphdr *)(mtod(m, char *) + poff); 2113193880Syongari ip->ip_sum = 0; 2114193880Syongari tcp->th_sum = in_pseudo(ip->ip_src.s_addr, 2115193880Syongari ip->ip_dst.s_addr, htons(IPPROTO_TCP)); 2116193880Syongari } 2117193880Syongari *m_head = m; 2118193880Syongari } 2119193880Syongari 2120193880Syongari prod = sc->alc_cdata.alc_tx_prod; 2121193880Syongari txd = &sc->alc_cdata.alc_txdesc[prod]; 2122193880Syongari txd_last = txd; 2123193880Syongari map = txd->tx_dmamap; 2124193880Syongari 2125193880Syongari error = bus_dmamap_load_mbuf_sg(sc->alc_cdata.alc_tx_tag, map, 2126193880Syongari *m_head, txsegs, &nsegs, 0); 2127193880Syongari if (error == EFBIG) { 2128243857Sglebius m = m_collapse(*m_head, M_NOWAIT, ALC_MAXTXSEGS); 2129193880Syongari if (m == NULL) { 2130193880Syongari m_freem(*m_head); 2131193880Syongari *m_head = NULL; 2132193880Syongari return (ENOMEM); 2133193880Syongari } 2134193880Syongari *m_head = m; 2135193880Syongari error = bus_dmamap_load_mbuf_sg(sc->alc_cdata.alc_tx_tag, map, 2136193880Syongari *m_head, txsegs, &nsegs, 0); 2137193880Syongari if (error != 0) { 2138193880Syongari m_freem(*m_head); 2139193880Syongari *m_head = NULL; 2140193880Syongari return (error); 2141193880Syongari } 2142193880Syongari } else if (error != 0) 2143193880Syongari return (error); 2144193880Syongari if (nsegs == 0) { 2145193880Syongari m_freem(*m_head); 2146193880Syongari *m_head = NULL; 2147193880Syongari return (EIO); 2148193880Syongari } 2149193880Syongari 2150193880Syongari /* Check descriptor overrun. */ 2151193880Syongari if (sc->alc_cdata.alc_tx_cnt + nsegs >= ALC_TX_RING_CNT - 3) { 2152193880Syongari bus_dmamap_unload(sc->alc_cdata.alc_tx_tag, map); 2153193880Syongari return (ENOBUFS); 2154193880Syongari } 2155193880Syongari bus_dmamap_sync(sc->alc_cdata.alc_tx_tag, map, BUS_DMASYNC_PREWRITE); 2156193880Syongari 2157193880Syongari m = *m_head; 2158193880Syongari cflags = TD_ETHERNET; 2159193880Syongari vtag = 0; 2160193880Syongari desc = NULL; 2161193880Syongari idx = 0; 2162193880Syongari /* Configure VLAN hardware tag insertion. */ 2163193880Syongari if ((m->m_flags & M_VLANTAG) != 0) { 2164193880Syongari vtag = htons(m->m_pkthdr.ether_vtag); 2165193880Syongari vtag = (vtag << TD_VLAN_SHIFT) & TD_VLAN_MASK; 2166193880Syongari cflags |= TD_INS_VLAN_TAG; 2167193880Syongari } 2168206876Syongari if ((m->m_pkthdr.csum_flags & CSUM_TSO) != 0) { 2169193880Syongari /* Request TSO and set MSS. */ 2170193880Syongari cflags |= TD_TSO | TD_TSO_DESCV1; 2171193880Syongari cflags |= ((uint32_t)m->m_pkthdr.tso_segsz << TD_MSS_SHIFT) & 2172193880Syongari TD_MSS_MASK; 2173193880Syongari /* Set TCP header offset. */ 2174193880Syongari cflags |= (poff << TD_TCPHDR_OFFSET_SHIFT) & 2175193880Syongari TD_TCPHDR_OFFSET_MASK; 2176193880Syongari /* 2177211105Syongari * AR813x/AR815x requires the first buffer should 2178193880Syongari * only hold IP/TCP header data. Payload should 2179193880Syongari * be handled in other descriptors. 2180193880Syongari */ 2181193880Syongari hdrlen = poff + (tcp->th_off << 2); 2182193880Syongari desc = &sc->alc_rdata.alc_tx_ring[prod]; 2183193880Syongari desc->len = htole32(TX_BYTES(hdrlen | vtag)); 2184193880Syongari desc->flags = htole32(cflags); 2185193880Syongari desc->addr = htole64(txsegs[0].ds_addr); 2186193880Syongari sc->alc_cdata.alc_tx_cnt++; 2187193880Syongari ALC_DESC_INC(prod, ALC_TX_RING_CNT); 2188193880Syongari if (m->m_len - hdrlen > 0) { 2189193880Syongari /* Handle remaining payload of the first fragment. */ 2190193880Syongari desc = &sc->alc_rdata.alc_tx_ring[prod]; 2191193880Syongari desc->len = htole32(TX_BYTES((m->m_len - hdrlen) | 2192193880Syongari vtag)); 2193193880Syongari desc->flags = htole32(cflags); 2194193880Syongari desc->addr = htole64(txsegs[0].ds_addr + hdrlen); 2195193880Syongari sc->alc_cdata.alc_tx_cnt++; 2196193880Syongari ALC_DESC_INC(prod, ALC_TX_RING_CNT); 2197193880Syongari } 2198193880Syongari /* Handle remaining fragments. */ 2199193880Syongari idx = 1; 2200206876Syongari } else if ((m->m_pkthdr.csum_flags & ALC_CSUM_FEATURES) != 0) { 2201206876Syongari /* Configure Tx checksum offload. */ 2202206876Syongari#ifdef ALC_USE_CUSTOM_CSUM 2203206876Syongari cflags |= TD_CUSTOM_CSUM; 2204206876Syongari /* Set checksum start offset. */ 2205206876Syongari cflags |= ((poff >> 1) << TD_PLOAD_OFFSET_SHIFT) & 2206206876Syongari TD_PLOAD_OFFSET_MASK; 2207206876Syongari /* Set checksum insertion position of TCP/UDP. */ 2208206876Syongari cflags |= (((poff + m->m_pkthdr.csum_data) >> 1) << 2209206876Syongari TD_CUSTOM_CSUM_OFFSET_SHIFT) & TD_CUSTOM_CSUM_OFFSET_MASK; 2210206876Syongari#else 2211206876Syongari if ((m->m_pkthdr.csum_flags & CSUM_IP) != 0) 2212206876Syongari cflags |= TD_IPCSUM; 2213206876Syongari if ((m->m_pkthdr.csum_flags & CSUM_TCP) != 0) 2214206876Syongari cflags |= TD_TCPCSUM; 2215206876Syongari if ((m->m_pkthdr.csum_flags & CSUM_UDP) != 0) 2216206876Syongari cflags |= TD_UDPCSUM; 2217206876Syongari /* Set TCP/UDP header offset. */ 2218206876Syongari cflags |= (poff << TD_L4HDR_OFFSET_SHIFT) & 2219206876Syongari TD_L4HDR_OFFSET_MASK; 2220206876Syongari#endif 2221193880Syongari } 2222193880Syongari for (; idx < nsegs; idx++) { 2223193880Syongari desc = &sc->alc_rdata.alc_tx_ring[prod]; 2224193880Syongari desc->len = htole32(TX_BYTES(txsegs[idx].ds_len) | vtag); 2225193880Syongari desc->flags = htole32(cflags); 2226193880Syongari desc->addr = htole64(txsegs[idx].ds_addr); 2227193880Syongari sc->alc_cdata.alc_tx_cnt++; 2228193880Syongari ALC_DESC_INC(prod, ALC_TX_RING_CNT); 2229193880Syongari } 2230193880Syongari /* Update producer index. */ 2231193880Syongari sc->alc_cdata.alc_tx_prod = prod; 2232193880Syongari 2233193880Syongari /* Finally set EOP on the last descriptor. */ 2234193880Syongari prod = (prod + ALC_TX_RING_CNT - 1) % ALC_TX_RING_CNT; 2235193880Syongari desc = &sc->alc_rdata.alc_tx_ring[prod]; 2236193880Syongari desc->flags |= htole32(TD_EOP); 2237193880Syongari 2238193880Syongari /* Swap dmamap of the first and the last. */ 2239193880Syongari txd = &sc->alc_cdata.alc_txdesc[prod]; 2240193880Syongari map = txd_last->tx_dmamap; 2241193880Syongari txd_last->tx_dmamap = txd->tx_dmamap; 2242193880Syongari txd->tx_dmamap = map; 2243193880Syongari txd->tx_m = m; 2244193880Syongari 2245193880Syongari return (0); 2246193880Syongari} 2247193880Syongari 2248193880Syongaristatic void 2249216925Sjhbalc_start(struct ifnet *ifp) 2250193880Syongari{ 2251216925Sjhb struct alc_softc *sc; 2252193880Syongari 2253216925Sjhb sc = ifp->if_softc; 2254216925Sjhb ALC_LOCK(sc); 2255216925Sjhb alc_start_locked(ifp); 2256216925Sjhb ALC_UNLOCK(sc); 2257193880Syongari} 2258193880Syongari 2259193880Syongaristatic void 2260216925Sjhbalc_start_locked(struct ifnet *ifp) 2261193880Syongari{ 2262193880Syongari struct alc_softc *sc; 2263193880Syongari struct mbuf *m_head; 2264193880Syongari int enq; 2265193880Syongari 2266193880Syongari sc = ifp->if_softc; 2267193880Syongari 2268216925Sjhb ALC_LOCK_ASSERT(sc); 2269193880Syongari 2270193880Syongari /* Reclaim transmitted frames. */ 2271193880Syongari if (sc->alc_cdata.alc_tx_cnt >= ALC_TX_DESC_HIWAT) 2272193880Syongari alc_txeof(sc); 2273193880Syongari 2274193880Syongari if ((ifp->if_drv_flags & (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)) != 2275216925Sjhb IFF_DRV_RUNNING || (sc->alc_flags & ALC_FLAG_LINK) == 0) 2276193880Syongari return; 2277193880Syongari 2278193880Syongari for (enq = 0; !IFQ_DRV_IS_EMPTY(&ifp->if_snd); ) { 2279193880Syongari IFQ_DRV_DEQUEUE(&ifp->if_snd, m_head); 2280193880Syongari if (m_head == NULL) 2281193880Syongari break; 2282193880Syongari /* 2283193880Syongari * Pack the data into the transmit ring. If we 2284193880Syongari * don't have room, set the OACTIVE flag and wait 2285193880Syongari * for the NIC to drain the ring. 2286193880Syongari */ 2287193880Syongari if (alc_encap(sc, &m_head)) { 2288193880Syongari if (m_head == NULL) 2289193880Syongari break; 2290193880Syongari IFQ_DRV_PREPEND(&ifp->if_snd, m_head); 2291193880Syongari ifp->if_drv_flags |= IFF_DRV_OACTIVE; 2292193880Syongari break; 2293193880Syongari } 2294193880Syongari 2295193880Syongari enq++; 2296193880Syongari /* 2297193880Syongari * If there's a BPF listener, bounce a copy of this frame 2298193880Syongari * to him. 2299193880Syongari */ 2300193880Syongari ETHER_BPF_MTAP(ifp, m_head); 2301193880Syongari } 2302193880Syongari 2303193880Syongari if (enq > 0) { 2304193880Syongari /* Sync descriptors. */ 2305193880Syongari bus_dmamap_sync(sc->alc_cdata.alc_tx_ring_tag, 2306193880Syongari sc->alc_cdata.alc_tx_ring_map, BUS_DMASYNC_PREWRITE); 2307193880Syongari /* Kick. Assume we're using normal Tx priority queue. */ 2308193880Syongari CSR_WRITE_4(sc, ALC_MBOX_TD_PROD_IDX, 2309193880Syongari (sc->alc_cdata.alc_tx_prod << 2310193880Syongari MBOX_TD_PROD_LO_IDX_SHIFT) & 2311193880Syongari MBOX_TD_PROD_LO_IDX_MASK); 2312193880Syongari /* Set a timeout in case the chip goes out to lunch. */ 2313193880Syongari sc->alc_watchdog_timer = ALC_TX_TIMEOUT; 2314193880Syongari } 2315193880Syongari} 2316193880Syongari 2317193880Syongaristatic void 2318193880Syongarialc_watchdog(struct alc_softc *sc) 2319193880Syongari{ 2320193880Syongari struct ifnet *ifp; 2321193880Syongari 2322193880Syongari ALC_LOCK_ASSERT(sc); 2323193880Syongari 2324193880Syongari if (sc->alc_watchdog_timer == 0 || --sc->alc_watchdog_timer) 2325193880Syongari return; 2326193880Syongari 2327193880Syongari ifp = sc->alc_ifp; 2328193880Syongari if ((sc->alc_flags & ALC_FLAG_LINK) == 0) { 2329193880Syongari if_printf(sc->alc_ifp, "watchdog timeout (lost link)\n"); 2330193880Syongari ifp->if_oerrors++; 2331193880Syongari ifp->if_drv_flags &= ~IFF_DRV_RUNNING; 2332193880Syongari alc_init_locked(sc); 2333193880Syongari return; 2334193880Syongari } 2335193880Syongari if_printf(sc->alc_ifp, "watchdog timeout -- resetting\n"); 2336193880Syongari ifp->if_oerrors++; 2337193880Syongari ifp->if_drv_flags &= ~IFF_DRV_RUNNING; 2338193880Syongari alc_init_locked(sc); 2339193880Syongari if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) 2340216925Sjhb alc_start_locked(ifp); 2341193880Syongari} 2342193880Syongari 2343193880Syongaristatic int 2344193880Syongarialc_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) 2345193880Syongari{ 2346193880Syongari struct alc_softc *sc; 2347193880Syongari struct ifreq *ifr; 2348193880Syongari struct mii_data *mii; 2349193880Syongari int error, mask; 2350193880Syongari 2351193880Syongari sc = ifp->if_softc; 2352193880Syongari ifr = (struct ifreq *)data; 2353193880Syongari error = 0; 2354193880Syongari switch (cmd) { 2355193880Syongari case SIOCSIFMTU: 2356211105Syongari if (ifr->ifr_mtu < ETHERMIN || 2357211105Syongari ifr->ifr_mtu > (sc->alc_ident->max_framelen - 2358211105Syongari sizeof(struct ether_vlan_header) - ETHER_CRC_LEN) || 2359193880Syongari ((sc->alc_flags & ALC_FLAG_JUMBO) == 0 && 2360193880Syongari ifr->ifr_mtu > ETHERMTU)) 2361193880Syongari error = EINVAL; 2362193880Syongari else if (ifp->if_mtu != ifr->ifr_mtu) { 2363193880Syongari ALC_LOCK(sc); 2364193880Syongari ifp->if_mtu = ifr->ifr_mtu; 2365211105Syongari /* AR813x/AR815x has 13 bits MSS field. */ 2366193880Syongari if (ifp->if_mtu > ALC_TSO_MTU && 2367193880Syongari (ifp->if_capenable & IFCAP_TSO4) != 0) { 2368193880Syongari ifp->if_capenable &= ~IFCAP_TSO4; 2369193880Syongari ifp->if_hwassist &= ~CSUM_TSO; 2370204228Syongari VLAN_CAPABILITIES(ifp); 2371193880Syongari } 2372193880Syongari ALC_UNLOCK(sc); 2373193880Syongari } 2374193880Syongari break; 2375193880Syongari case SIOCSIFFLAGS: 2376193880Syongari ALC_LOCK(sc); 2377193880Syongari if ((ifp->if_flags & IFF_UP) != 0) { 2378193880Syongari if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0 && 2379193880Syongari ((ifp->if_flags ^ sc->alc_if_flags) & 2380193880Syongari (IFF_PROMISC | IFF_ALLMULTI)) != 0) 2381193880Syongari alc_rxfilter(sc); 2382217379Sjhb else 2383193880Syongari alc_init_locked(sc); 2384193880Syongari } else if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0) 2385193880Syongari alc_stop(sc); 2386193880Syongari sc->alc_if_flags = ifp->if_flags; 2387193880Syongari ALC_UNLOCK(sc); 2388193880Syongari break; 2389193880Syongari case SIOCADDMULTI: 2390193880Syongari case SIOCDELMULTI: 2391193880Syongari ALC_LOCK(sc); 2392193880Syongari if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0) 2393193880Syongari alc_rxfilter(sc); 2394193880Syongari ALC_UNLOCK(sc); 2395193880Syongari break; 2396193880Syongari case SIOCSIFMEDIA: 2397193880Syongari case SIOCGIFMEDIA: 2398193880Syongari mii = device_get_softc(sc->alc_miibus); 2399193880Syongari error = ifmedia_ioctl(ifp, ifr, &mii->mii_media, cmd); 2400193880Syongari break; 2401193880Syongari case SIOCSIFCAP: 2402193880Syongari ALC_LOCK(sc); 2403193880Syongari mask = ifr->ifr_reqcap ^ ifp->if_capenable; 2404193880Syongari if ((mask & IFCAP_TXCSUM) != 0 && 2405193880Syongari (ifp->if_capabilities & IFCAP_TXCSUM) != 0) { 2406193880Syongari ifp->if_capenable ^= IFCAP_TXCSUM; 2407193880Syongari if ((ifp->if_capenable & IFCAP_TXCSUM) != 0) 2408193880Syongari ifp->if_hwassist |= ALC_CSUM_FEATURES; 2409193880Syongari else 2410193880Syongari ifp->if_hwassist &= ~ALC_CSUM_FEATURES; 2411193880Syongari } 2412193880Syongari if ((mask & IFCAP_TSO4) != 0 && 2413193880Syongari (ifp->if_capabilities & IFCAP_TSO4) != 0) { 2414193880Syongari ifp->if_capenable ^= IFCAP_TSO4; 2415193880Syongari if ((ifp->if_capenable & IFCAP_TSO4) != 0) { 2416211105Syongari /* AR813x/AR815x has 13 bits MSS field. */ 2417193880Syongari if (ifp->if_mtu > ALC_TSO_MTU) { 2418193880Syongari ifp->if_capenable &= ~IFCAP_TSO4; 2419193880Syongari ifp->if_hwassist &= ~CSUM_TSO; 2420193880Syongari } else 2421193880Syongari ifp->if_hwassist |= CSUM_TSO; 2422193880Syongari } else 2423193880Syongari ifp->if_hwassist &= ~CSUM_TSO; 2424193880Syongari } 2425193880Syongari if ((mask & IFCAP_WOL_MCAST) != 0 && 2426193880Syongari (ifp->if_capabilities & IFCAP_WOL_MCAST) != 0) 2427193880Syongari ifp->if_capenable ^= IFCAP_WOL_MCAST; 2428193880Syongari if ((mask & IFCAP_WOL_MAGIC) != 0 && 2429193880Syongari (ifp->if_capabilities & IFCAP_WOL_MAGIC) != 0) 2430193880Syongari ifp->if_capenable ^= IFCAP_WOL_MAGIC; 2431193880Syongari if ((mask & IFCAP_VLAN_HWTAGGING) != 0 && 2432193880Syongari (ifp->if_capabilities & IFCAP_VLAN_HWTAGGING) != 0) { 2433193880Syongari ifp->if_capenable ^= IFCAP_VLAN_HWTAGGING; 2434193880Syongari alc_rxvlan(sc); 2435193880Syongari } 2436193880Syongari if ((mask & IFCAP_VLAN_HWCSUM) != 0 && 2437193880Syongari (ifp->if_capabilities & IFCAP_VLAN_HWCSUM) != 0) 2438193880Syongari ifp->if_capenable ^= IFCAP_VLAN_HWCSUM; 2439193880Syongari if ((mask & IFCAP_VLAN_HWTSO) != 0 && 2440193880Syongari (ifp->if_capabilities & IFCAP_VLAN_HWTSO) != 0) 2441193880Syongari ifp->if_capenable ^= IFCAP_VLAN_HWTSO; 2442193880Syongari if ((ifp->if_capenable & IFCAP_VLAN_HWTAGGING) == 0) 2443193880Syongari ifp->if_capenable &= 2444193880Syongari ~(IFCAP_VLAN_HWTSO | IFCAP_VLAN_HWCSUM); 2445193880Syongari ALC_UNLOCK(sc); 2446193880Syongari VLAN_CAPABILITIES(ifp); 2447193880Syongari break; 2448193880Syongari default: 2449193880Syongari error = ether_ioctl(ifp, cmd, data); 2450193880Syongari break; 2451193880Syongari } 2452193880Syongari 2453193880Syongari return (error); 2454193880Syongari} 2455193880Syongari 2456193880Syongaristatic void 2457193880Syongarialc_mac_config(struct alc_softc *sc) 2458193880Syongari{ 2459193880Syongari struct mii_data *mii; 2460193880Syongari uint32_t reg; 2461193880Syongari 2462193880Syongari ALC_LOCK_ASSERT(sc); 2463193880Syongari 2464193880Syongari mii = device_get_softc(sc->alc_miibus); 2465193880Syongari reg = CSR_READ_4(sc, ALC_MAC_CFG); 2466193880Syongari reg &= ~(MAC_CFG_FULL_DUPLEX | MAC_CFG_TX_FC | MAC_CFG_RX_FC | 2467193880Syongari MAC_CFG_SPEED_MASK); 2468211105Syongari if (sc->alc_ident->deviceid == DEVICEID_ATHEROS_AR8151 || 2469211105Syongari sc->alc_ident->deviceid == DEVICEID_ATHEROS_AR8151_V2 || 2470211105Syongari sc->alc_ident->deviceid == DEVICEID_ATHEROS_AR8152_B2) 2471211105Syongari reg |= MAC_CFG_HASH_ALG_CRC32 | MAC_CFG_SPEED_MODE_SW; 2472193880Syongari /* Reprogram MAC with resolved speed/duplex. */ 2473193880Syongari switch (IFM_SUBTYPE(mii->mii_media_active)) { 2474193880Syongari case IFM_10_T: 2475193880Syongari case IFM_100_TX: 2476193880Syongari reg |= MAC_CFG_SPEED_10_100; 2477193880Syongari break; 2478193880Syongari case IFM_1000_T: 2479193880Syongari reg |= MAC_CFG_SPEED_1000; 2480193880Syongari break; 2481193880Syongari } 2482193880Syongari if ((IFM_OPTIONS(mii->mii_media_active) & IFM_FDX) != 0) { 2483193880Syongari reg |= MAC_CFG_FULL_DUPLEX; 2484193880Syongari if ((IFM_OPTIONS(mii->mii_media_active) & IFM_ETH_TXPAUSE) != 0) 2485193880Syongari reg |= MAC_CFG_TX_FC; 2486193880Syongari if ((IFM_OPTIONS(mii->mii_media_active) & IFM_ETH_RXPAUSE) != 0) 2487193880Syongari reg |= MAC_CFG_RX_FC; 2488193880Syongari } 2489193880Syongari CSR_WRITE_4(sc, ALC_MAC_CFG, reg); 2490193880Syongari} 2491193880Syongari 2492193880Syongaristatic void 2493193880Syongarialc_stats_clear(struct alc_softc *sc) 2494193880Syongari{ 2495193880Syongari struct smb sb, *smb; 2496193880Syongari uint32_t *reg; 2497193880Syongari int i; 2498193880Syongari 2499193880Syongari if ((sc->alc_flags & ALC_FLAG_SMB_BUG) == 0) { 2500193880Syongari bus_dmamap_sync(sc->alc_cdata.alc_smb_tag, 2501193880Syongari sc->alc_cdata.alc_smb_map, 2502193880Syongari BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); 2503193880Syongari smb = sc->alc_rdata.alc_smb; 2504193880Syongari /* Update done, clear. */ 2505193880Syongari smb->updated = 0; 2506193880Syongari bus_dmamap_sync(sc->alc_cdata.alc_smb_tag, 2507193880Syongari sc->alc_cdata.alc_smb_map, 2508193880Syongari BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 2509193880Syongari } else { 2510193880Syongari for (reg = &sb.rx_frames, i = 0; reg <= &sb.rx_pkts_filtered; 2511193880Syongari reg++) { 2512193880Syongari CSR_READ_4(sc, ALC_RX_MIB_BASE + i); 2513193880Syongari i += sizeof(uint32_t); 2514193880Syongari } 2515193880Syongari /* Read Tx statistics. */ 2516193880Syongari for (reg = &sb.tx_frames, i = 0; reg <= &sb.tx_mcast_bytes; 2517193880Syongari reg++) { 2518193880Syongari CSR_READ_4(sc, ALC_TX_MIB_BASE + i); 2519193880Syongari i += sizeof(uint32_t); 2520193880Syongari } 2521193880Syongari } 2522193880Syongari} 2523193880Syongari 2524193880Syongaristatic void 2525193880Syongarialc_stats_update(struct alc_softc *sc) 2526193880Syongari{ 2527193880Syongari struct alc_hw_stats *stat; 2528193880Syongari struct smb sb, *smb; 2529193880Syongari struct ifnet *ifp; 2530193880Syongari uint32_t *reg; 2531193880Syongari int i; 2532193880Syongari 2533193880Syongari ALC_LOCK_ASSERT(sc); 2534193880Syongari 2535193880Syongari ifp = sc->alc_ifp; 2536193880Syongari stat = &sc->alc_stats; 2537193880Syongari if ((sc->alc_flags & ALC_FLAG_SMB_BUG) == 0) { 2538193880Syongari bus_dmamap_sync(sc->alc_cdata.alc_smb_tag, 2539193880Syongari sc->alc_cdata.alc_smb_map, 2540193880Syongari BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); 2541193880Syongari smb = sc->alc_rdata.alc_smb; 2542193880Syongari if (smb->updated == 0) 2543193880Syongari return; 2544193880Syongari } else { 2545193880Syongari smb = &sb; 2546193880Syongari /* Read Rx statistics. */ 2547193880Syongari for (reg = &sb.rx_frames, i = 0; reg <= &sb.rx_pkts_filtered; 2548193880Syongari reg++) { 2549193880Syongari *reg = CSR_READ_4(sc, ALC_RX_MIB_BASE + i); 2550193880Syongari i += sizeof(uint32_t); 2551193880Syongari } 2552193880Syongari /* Read Tx statistics. */ 2553193880Syongari for (reg = &sb.tx_frames, i = 0; reg <= &sb.tx_mcast_bytes; 2554193880Syongari reg++) { 2555193880Syongari *reg = CSR_READ_4(sc, ALC_TX_MIB_BASE + i); 2556193880Syongari i += sizeof(uint32_t); 2557193880Syongari } 2558193880Syongari } 2559193880Syongari 2560193880Syongari /* Rx stats. */ 2561193880Syongari stat->rx_frames += smb->rx_frames; 2562193880Syongari stat->rx_bcast_frames += smb->rx_bcast_frames; 2563193880Syongari stat->rx_mcast_frames += smb->rx_mcast_frames; 2564193880Syongari stat->rx_pause_frames += smb->rx_pause_frames; 2565193880Syongari stat->rx_control_frames += smb->rx_control_frames; 2566193880Syongari stat->rx_crcerrs += smb->rx_crcerrs; 2567193880Syongari stat->rx_lenerrs += smb->rx_lenerrs; 2568193880Syongari stat->rx_bytes += smb->rx_bytes; 2569193880Syongari stat->rx_runts += smb->rx_runts; 2570193880Syongari stat->rx_fragments += smb->rx_fragments; 2571193880Syongari stat->rx_pkts_64 += smb->rx_pkts_64; 2572193880Syongari stat->rx_pkts_65_127 += smb->rx_pkts_65_127; 2573193880Syongari stat->rx_pkts_128_255 += smb->rx_pkts_128_255; 2574193880Syongari stat->rx_pkts_256_511 += smb->rx_pkts_256_511; 2575193880Syongari stat->rx_pkts_512_1023 += smb->rx_pkts_512_1023; 2576193880Syongari stat->rx_pkts_1024_1518 += smb->rx_pkts_1024_1518; 2577193880Syongari stat->rx_pkts_1519_max += smb->rx_pkts_1519_max; 2578193880Syongari stat->rx_pkts_truncated += smb->rx_pkts_truncated; 2579193880Syongari stat->rx_fifo_oflows += smb->rx_fifo_oflows; 2580193880Syongari stat->rx_rrs_errs += smb->rx_rrs_errs; 2581193880Syongari stat->rx_alignerrs += smb->rx_alignerrs; 2582193880Syongari stat->rx_bcast_bytes += smb->rx_bcast_bytes; 2583193880Syongari stat->rx_mcast_bytes += smb->rx_mcast_bytes; 2584193880Syongari stat->rx_pkts_filtered += smb->rx_pkts_filtered; 2585193880Syongari 2586193880Syongari /* Tx stats. */ 2587193880Syongari stat->tx_frames += smb->tx_frames; 2588193880Syongari stat->tx_bcast_frames += smb->tx_bcast_frames; 2589193880Syongari stat->tx_mcast_frames += smb->tx_mcast_frames; 2590193880Syongari stat->tx_pause_frames += smb->tx_pause_frames; 2591193880Syongari stat->tx_excess_defer += smb->tx_excess_defer; 2592193880Syongari stat->tx_control_frames += smb->tx_control_frames; 2593193880Syongari stat->tx_deferred += smb->tx_deferred; 2594193880Syongari stat->tx_bytes += smb->tx_bytes; 2595193880Syongari stat->tx_pkts_64 += smb->tx_pkts_64; 2596193880Syongari stat->tx_pkts_65_127 += smb->tx_pkts_65_127; 2597193880Syongari stat->tx_pkts_128_255 += smb->tx_pkts_128_255; 2598193880Syongari stat->tx_pkts_256_511 += smb->tx_pkts_256_511; 2599193880Syongari stat->tx_pkts_512_1023 += smb->tx_pkts_512_1023; 2600193880Syongari stat->tx_pkts_1024_1518 += smb->tx_pkts_1024_1518; 2601193880Syongari stat->tx_pkts_1519_max += smb->tx_pkts_1519_max; 2602193880Syongari stat->tx_single_colls += smb->tx_single_colls; 2603193880Syongari stat->tx_multi_colls += smb->tx_multi_colls; 2604193880Syongari stat->tx_late_colls += smb->tx_late_colls; 2605193880Syongari stat->tx_excess_colls += smb->tx_excess_colls; 2606193880Syongari stat->tx_abort += smb->tx_abort; 2607193880Syongari stat->tx_underrun += smb->tx_underrun; 2608193880Syongari stat->tx_desc_underrun += smb->tx_desc_underrun; 2609193880Syongari stat->tx_lenerrs += smb->tx_lenerrs; 2610193880Syongari stat->tx_pkts_truncated += smb->tx_pkts_truncated; 2611193880Syongari stat->tx_bcast_bytes += smb->tx_bcast_bytes; 2612193880Syongari stat->tx_mcast_bytes += smb->tx_mcast_bytes; 2613193880Syongari 2614193880Syongari /* Update counters in ifnet. */ 2615193880Syongari ifp->if_opackets += smb->tx_frames; 2616193880Syongari 2617193880Syongari ifp->if_collisions += smb->tx_single_colls + 2618193880Syongari smb->tx_multi_colls * 2 + smb->tx_late_colls + 2619193880Syongari smb->tx_abort * HDPX_CFG_RETRY_DEFAULT; 2620193880Syongari 2621193880Syongari /* 2622193880Syongari * XXX 2623193880Syongari * tx_pkts_truncated counter looks suspicious. It constantly 2624193880Syongari * increments with no sign of Tx errors. This may indicate 2625193880Syongari * the counter name is not correct one so I've removed the 2626193880Syongari * counter in output errors. 2627193880Syongari */ 2628193880Syongari ifp->if_oerrors += smb->tx_abort + smb->tx_late_colls + 2629193880Syongari smb->tx_underrun; 2630193880Syongari 2631193880Syongari ifp->if_ipackets += smb->rx_frames; 2632193880Syongari 2633193880Syongari ifp->if_ierrors += smb->rx_crcerrs + smb->rx_lenerrs + 2634193880Syongari smb->rx_runts + smb->rx_pkts_truncated + 2635193880Syongari smb->rx_fifo_oflows + smb->rx_rrs_errs + 2636193880Syongari smb->rx_alignerrs; 2637193880Syongari 2638193880Syongari if ((sc->alc_flags & ALC_FLAG_SMB_BUG) == 0) { 2639193880Syongari /* Update done, clear. */ 2640193880Syongari smb->updated = 0; 2641193880Syongari bus_dmamap_sync(sc->alc_cdata.alc_smb_tag, 2642193880Syongari sc->alc_cdata.alc_smb_map, 2643193880Syongari BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 2644193880Syongari } 2645193880Syongari} 2646193880Syongari 2647193880Syongaristatic int 2648193880Syongarialc_intr(void *arg) 2649193880Syongari{ 2650193880Syongari struct alc_softc *sc; 2651193880Syongari uint32_t status; 2652193880Syongari 2653193880Syongari sc = (struct alc_softc *)arg; 2654193880Syongari 2655193880Syongari status = CSR_READ_4(sc, ALC_INTR_STATUS); 2656193880Syongari if ((status & ALC_INTRS) == 0) 2657193880Syongari return (FILTER_STRAY); 2658193880Syongari /* Disable interrupts. */ 2659193880Syongari CSR_WRITE_4(sc, ALC_INTR_STATUS, INTR_DIS_INT); 2660193880Syongari taskqueue_enqueue(sc->alc_tq, &sc->alc_int_task); 2661193880Syongari 2662193880Syongari return (FILTER_HANDLED); 2663193880Syongari} 2664193880Syongari 2665193880Syongaristatic void 2666193880Syongarialc_int_task(void *arg, int pending) 2667193880Syongari{ 2668193880Syongari struct alc_softc *sc; 2669193880Syongari struct ifnet *ifp; 2670193880Syongari uint32_t status; 2671193880Syongari int more; 2672193880Syongari 2673193880Syongari sc = (struct alc_softc *)arg; 2674193880Syongari ifp = sc->alc_ifp; 2675193880Syongari 2676193880Syongari status = CSR_READ_4(sc, ALC_INTR_STATUS); 2677217379Sjhb ALC_LOCK(sc); 2678216362Syongari if (sc->alc_morework != 0) { 2679216362Syongari sc->alc_morework = 0; 2680193880Syongari status |= INTR_RX_PKT; 2681216362Syongari } 2682193880Syongari if ((status & ALC_INTRS) == 0) 2683193880Syongari goto done; 2684193880Syongari 2685193880Syongari /* Acknowledge interrupts but still disable interrupts. */ 2686193880Syongari CSR_WRITE_4(sc, ALC_INTR_STATUS, status | INTR_DIS_INT); 2687193880Syongari 2688193880Syongari more = 0; 2689193880Syongari if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0) { 2690193880Syongari if ((status & INTR_RX_PKT) != 0) { 2691193880Syongari more = alc_rxintr(sc, sc->alc_process_limit); 2692193880Syongari if (more == EAGAIN) 2693216362Syongari sc->alc_morework = 1; 2694193880Syongari else if (more == EIO) { 2695193880Syongari ifp->if_drv_flags &= ~IFF_DRV_RUNNING; 2696193880Syongari alc_init_locked(sc); 2697193880Syongari ALC_UNLOCK(sc); 2698193880Syongari return; 2699193880Syongari } 2700193880Syongari } 2701193880Syongari if ((status & (INTR_DMA_RD_TO_RST | INTR_DMA_WR_TO_RST | 2702193880Syongari INTR_TXQ_TO_RST)) != 0) { 2703193880Syongari if ((status & INTR_DMA_RD_TO_RST) != 0) 2704193880Syongari device_printf(sc->alc_dev, 2705193880Syongari "DMA read error! -- resetting\n"); 2706193880Syongari if ((status & INTR_DMA_WR_TO_RST) != 0) 2707193880Syongari device_printf(sc->alc_dev, 2708193880Syongari "DMA write error! -- resetting\n"); 2709193880Syongari if ((status & INTR_TXQ_TO_RST) != 0) 2710193880Syongari device_printf(sc->alc_dev, 2711193880Syongari "TxQ reset! -- resetting\n"); 2712193880Syongari ifp->if_drv_flags &= ~IFF_DRV_RUNNING; 2713193880Syongari alc_init_locked(sc); 2714193880Syongari ALC_UNLOCK(sc); 2715193880Syongari return; 2716193880Syongari } 2717193880Syongari if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0 && 2718193880Syongari !IFQ_DRV_IS_EMPTY(&ifp->if_snd)) 2719217379Sjhb alc_start_locked(ifp); 2720193880Syongari } 2721193880Syongari 2722193880Syongari if (more == EAGAIN || 2723193880Syongari (CSR_READ_4(sc, ALC_INTR_STATUS) & ALC_INTRS) != 0) { 2724217379Sjhb ALC_UNLOCK(sc); 2725193880Syongari taskqueue_enqueue(sc->alc_tq, &sc->alc_int_task); 2726193880Syongari return; 2727193880Syongari } 2728193880Syongari 2729193880Syongaridone: 2730193880Syongari if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0) { 2731193880Syongari /* Re-enable interrupts if we're running. */ 2732193880Syongari CSR_WRITE_4(sc, ALC_INTR_STATUS, 0x7FFFFFFF); 2733193880Syongari } 2734217379Sjhb ALC_UNLOCK(sc); 2735193880Syongari} 2736193880Syongari 2737193880Syongaristatic void 2738193880Syongarialc_txeof(struct alc_softc *sc) 2739193880Syongari{ 2740193880Syongari struct ifnet *ifp; 2741193880Syongari struct alc_txdesc *txd; 2742193880Syongari uint32_t cons, prod; 2743193880Syongari int prog; 2744193880Syongari 2745193880Syongari ALC_LOCK_ASSERT(sc); 2746193880Syongari 2747193880Syongari ifp = sc->alc_ifp; 2748193880Syongari 2749193880Syongari if (sc->alc_cdata.alc_tx_cnt == 0) 2750193880Syongari return; 2751193880Syongari bus_dmamap_sync(sc->alc_cdata.alc_tx_ring_tag, 2752193880Syongari sc->alc_cdata.alc_tx_ring_map, BUS_DMASYNC_POSTWRITE); 2753193880Syongari if ((sc->alc_flags & ALC_FLAG_CMB_BUG) == 0) { 2754193880Syongari bus_dmamap_sync(sc->alc_cdata.alc_cmb_tag, 2755193880Syongari sc->alc_cdata.alc_cmb_map, BUS_DMASYNC_POSTREAD); 2756193880Syongari prod = sc->alc_rdata.alc_cmb->cons; 2757193880Syongari } else 2758193880Syongari prod = CSR_READ_4(sc, ALC_MBOX_TD_CONS_IDX); 2759193880Syongari /* Assume we're using normal Tx priority queue. */ 2760193880Syongari prod = (prod & MBOX_TD_CONS_LO_IDX_MASK) >> 2761193880Syongari MBOX_TD_CONS_LO_IDX_SHIFT; 2762193880Syongari cons = sc->alc_cdata.alc_tx_cons; 2763193880Syongari /* 2764193880Syongari * Go through our Tx list and free mbufs for those 2765193880Syongari * frames which have been transmitted. 2766193880Syongari */ 2767193880Syongari for (prog = 0; cons != prod; prog++, 2768193880Syongari ALC_DESC_INC(cons, ALC_TX_RING_CNT)) { 2769193880Syongari if (sc->alc_cdata.alc_tx_cnt <= 0) 2770193880Syongari break; 2771193880Syongari prog++; 2772193880Syongari ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 2773193880Syongari sc->alc_cdata.alc_tx_cnt--; 2774193880Syongari txd = &sc->alc_cdata.alc_txdesc[cons]; 2775193880Syongari if (txd->tx_m != NULL) { 2776193880Syongari /* Reclaim transmitted mbufs. */ 2777193880Syongari bus_dmamap_sync(sc->alc_cdata.alc_tx_tag, 2778193880Syongari txd->tx_dmamap, BUS_DMASYNC_POSTWRITE); 2779193880Syongari bus_dmamap_unload(sc->alc_cdata.alc_tx_tag, 2780193880Syongari txd->tx_dmamap); 2781193880Syongari m_freem(txd->tx_m); 2782193880Syongari txd->tx_m = NULL; 2783193880Syongari } 2784193880Syongari } 2785193880Syongari 2786193880Syongari if ((sc->alc_flags & ALC_FLAG_CMB_BUG) == 0) 2787193880Syongari bus_dmamap_sync(sc->alc_cdata.alc_cmb_tag, 2788193880Syongari sc->alc_cdata.alc_cmb_map, BUS_DMASYNC_PREREAD); 2789193880Syongari sc->alc_cdata.alc_tx_cons = cons; 2790193880Syongari /* 2791193880Syongari * Unarm watchdog timer only when there is no pending 2792193880Syongari * frames in Tx queue. 2793193880Syongari */ 2794193880Syongari if (sc->alc_cdata.alc_tx_cnt == 0) 2795193880Syongari sc->alc_watchdog_timer = 0; 2796193880Syongari} 2797193880Syongari 2798193880Syongaristatic int 2799193880Syongarialc_newbuf(struct alc_softc *sc, struct alc_rxdesc *rxd) 2800193880Syongari{ 2801193880Syongari struct mbuf *m; 2802193880Syongari bus_dma_segment_t segs[1]; 2803193880Syongari bus_dmamap_t map; 2804193880Syongari int nsegs; 2805193880Syongari 2806243857Sglebius m = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR); 2807193880Syongari if (m == NULL) 2808193880Syongari return (ENOBUFS); 2809193880Syongari m->m_len = m->m_pkthdr.len = RX_BUF_SIZE_MAX; 2810193880Syongari#ifndef __NO_STRICT_ALIGNMENT 2811193880Syongari m_adj(m, sizeof(uint64_t)); 2812193880Syongari#endif 2813193880Syongari 2814193880Syongari if (bus_dmamap_load_mbuf_sg(sc->alc_cdata.alc_rx_tag, 2815193880Syongari sc->alc_cdata.alc_rx_sparemap, m, segs, &nsegs, 0) != 0) { 2816193880Syongari m_freem(m); 2817193880Syongari return (ENOBUFS); 2818193880Syongari } 2819193880Syongari KASSERT(nsegs == 1, ("%s: %d segments returned!", __func__, nsegs)); 2820193880Syongari 2821193880Syongari if (rxd->rx_m != NULL) { 2822193880Syongari bus_dmamap_sync(sc->alc_cdata.alc_rx_tag, rxd->rx_dmamap, 2823193880Syongari BUS_DMASYNC_POSTREAD); 2824193880Syongari bus_dmamap_unload(sc->alc_cdata.alc_rx_tag, rxd->rx_dmamap); 2825193880Syongari } 2826193880Syongari map = rxd->rx_dmamap; 2827193880Syongari rxd->rx_dmamap = sc->alc_cdata.alc_rx_sparemap; 2828193880Syongari sc->alc_cdata.alc_rx_sparemap = map; 2829193880Syongari bus_dmamap_sync(sc->alc_cdata.alc_rx_tag, rxd->rx_dmamap, 2830193880Syongari BUS_DMASYNC_PREREAD); 2831193880Syongari rxd->rx_m = m; 2832193880Syongari rxd->rx_desc->addr = htole64(segs[0].ds_addr); 2833193880Syongari return (0); 2834193880Syongari} 2835193880Syongari 2836193880Syongaristatic int 2837193880Syongarialc_rxintr(struct alc_softc *sc, int count) 2838193880Syongari{ 2839193880Syongari struct ifnet *ifp; 2840193880Syongari struct rx_rdesc *rrd; 2841193880Syongari uint32_t nsegs, status; 2842193880Syongari int rr_cons, prog; 2843193880Syongari 2844193880Syongari bus_dmamap_sync(sc->alc_cdata.alc_rr_ring_tag, 2845193880Syongari sc->alc_cdata.alc_rr_ring_map, 2846193880Syongari BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); 2847193880Syongari bus_dmamap_sync(sc->alc_cdata.alc_rx_ring_tag, 2848193880Syongari sc->alc_cdata.alc_rx_ring_map, BUS_DMASYNC_POSTWRITE); 2849193880Syongari rr_cons = sc->alc_cdata.alc_rr_cons; 2850193880Syongari ifp = sc->alc_ifp; 2851193880Syongari for (prog = 0; (ifp->if_drv_flags & IFF_DRV_RUNNING) != 0;) { 2852193880Syongari if (count-- <= 0) 2853193880Syongari break; 2854193880Syongari rrd = &sc->alc_rdata.alc_rr_ring[rr_cons]; 2855193880Syongari status = le32toh(rrd->status); 2856193880Syongari if ((status & RRD_VALID) == 0) 2857193880Syongari break; 2858193880Syongari nsegs = RRD_RD_CNT(le32toh(rrd->rdinfo)); 2859193880Syongari if (nsegs == 0) { 2860193880Syongari /* This should not happen! */ 2861193880Syongari device_printf(sc->alc_dev, 2862193880Syongari "unexpected segment count -- resetting\n"); 2863193880Syongari return (EIO); 2864193880Syongari } 2865193880Syongari alc_rxeof(sc, rrd); 2866193880Syongari /* Clear Rx return status. */ 2867193880Syongari rrd->status = 0; 2868193880Syongari ALC_DESC_INC(rr_cons, ALC_RR_RING_CNT); 2869193880Syongari sc->alc_cdata.alc_rx_cons += nsegs; 2870193880Syongari sc->alc_cdata.alc_rx_cons %= ALC_RR_RING_CNT; 2871193880Syongari prog += nsegs; 2872193880Syongari } 2873193880Syongari 2874193880Syongari if (prog > 0) { 2875193880Syongari /* Update the consumer index. */ 2876193880Syongari sc->alc_cdata.alc_rr_cons = rr_cons; 2877193880Syongari /* Sync Rx return descriptors. */ 2878193880Syongari bus_dmamap_sync(sc->alc_cdata.alc_rr_ring_tag, 2879193880Syongari sc->alc_cdata.alc_rr_ring_map, 2880193880Syongari BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 2881193880Syongari /* 2882193880Syongari * Sync updated Rx descriptors such that controller see 2883193880Syongari * modified buffer addresses. 2884193880Syongari */ 2885193880Syongari bus_dmamap_sync(sc->alc_cdata.alc_rx_ring_tag, 2886193880Syongari sc->alc_cdata.alc_rx_ring_map, BUS_DMASYNC_PREWRITE); 2887193880Syongari /* 2888193880Syongari * Let controller know availability of new Rx buffers. 2889193880Syongari * Since alc(4) use RXQ_CFG_RD_BURST_DEFAULT descriptors 2890193880Syongari * it may be possible to update ALC_MBOX_RD0_PROD_IDX 2891193880Syongari * only when Rx buffer pre-fetching is required. In 2892193880Syongari * addition we already set ALC_RX_RD_FREE_THRESH to 2893193880Syongari * RX_RD_FREE_THRESH_LO_DEFAULT descriptors. However 2894193880Syongari * it still seems that pre-fetching needs more 2895193880Syongari * experimentation. 2896193880Syongari */ 2897193880Syongari CSR_WRITE_4(sc, ALC_MBOX_RD0_PROD_IDX, 2898193880Syongari sc->alc_cdata.alc_rx_cons); 2899193880Syongari } 2900193880Syongari 2901193880Syongari return (count > 0 ? 0 : EAGAIN); 2902193880Syongari} 2903193880Syongari 2904193880Syongari#ifndef __NO_STRICT_ALIGNMENT 2905193880Syongaristatic struct mbuf * 2906193880Syongarialc_fixup_rx(struct ifnet *ifp, struct mbuf *m) 2907193880Syongari{ 2908193880Syongari struct mbuf *n; 2909193880Syongari int i; 2910193880Syongari uint16_t *src, *dst; 2911193880Syongari 2912193880Syongari src = mtod(m, uint16_t *); 2913193880Syongari dst = src - 3; 2914193880Syongari 2915193880Syongari if (m->m_next == NULL) { 2916193880Syongari for (i = 0; i < (m->m_len / sizeof(uint16_t) + 1); i++) 2917193880Syongari *dst++ = *src++; 2918193880Syongari m->m_data -= 6; 2919193880Syongari return (m); 2920193880Syongari } 2921193880Syongari /* 2922193880Syongari * Append a new mbuf to received mbuf chain and copy ethernet 2923193880Syongari * header from the mbuf chain. This can save lots of CPU 2924193880Syongari * cycles for jumbo frame. 2925193880Syongari */ 2926243857Sglebius MGETHDR(n, M_NOWAIT, MT_DATA); 2927193880Syongari if (n == NULL) { 2928193880Syongari ifp->if_iqdrops++; 2929193880Syongari m_freem(m); 2930193880Syongari return (NULL); 2931193880Syongari } 2932193880Syongari bcopy(m->m_data, n->m_data, ETHER_HDR_LEN); 2933193880Syongari m->m_data += ETHER_HDR_LEN; 2934193880Syongari m->m_len -= ETHER_HDR_LEN; 2935193880Syongari n->m_len = ETHER_HDR_LEN; 2936193880Syongari M_MOVE_PKTHDR(n, m); 2937193880Syongari n->m_next = m; 2938193880Syongari return (n); 2939193880Syongari} 2940193880Syongari#endif 2941193880Syongari 2942193880Syongari/* Receive a frame. */ 2943193880Syongaristatic void 2944193880Syongarialc_rxeof(struct alc_softc *sc, struct rx_rdesc *rrd) 2945193880Syongari{ 2946193880Syongari struct alc_rxdesc *rxd; 2947193880Syongari struct ifnet *ifp; 2948193880Syongari struct mbuf *mp, *m; 2949193880Syongari uint32_t rdinfo, status, vtag; 2950193880Syongari int count, nsegs, rx_cons; 2951193880Syongari 2952193880Syongari ifp = sc->alc_ifp; 2953193880Syongari status = le32toh(rrd->status); 2954193880Syongari rdinfo = le32toh(rrd->rdinfo); 2955193880Syongari rx_cons = RRD_RD_IDX(rdinfo); 2956193880Syongari nsegs = RRD_RD_CNT(rdinfo); 2957193880Syongari 2958193880Syongari sc->alc_cdata.alc_rxlen = RRD_BYTES(status); 2959193880Syongari if ((status & (RRD_ERR_SUM | RRD_ERR_LENGTH)) != 0) { 2960193880Syongari /* 2961193880Syongari * We want to pass the following frames to upper 2962193880Syongari * layer regardless of error status of Rx return 2963193880Syongari * ring. 2964193880Syongari * 2965193880Syongari * o IP/TCP/UDP checksum is bad. 2966193880Syongari * o frame length and protocol specific length 2967193880Syongari * does not match. 2968193880Syongari * 2969193880Syongari * Force network stack compute checksum for 2970193880Syongari * errored frames. 2971193880Syongari */ 2972193880Syongari status |= RRD_TCP_UDPCSUM_NOK | RRD_IPCSUM_NOK; 2973212764Sdelphij if ((status & (RRD_ERR_CRC | RRD_ERR_ALIGN | 2974212764Sdelphij RRD_ERR_TRUNC | RRD_ERR_RUNT)) != 0) 2975193880Syongari return; 2976193880Syongari } 2977193880Syongari 2978193880Syongari for (count = 0; count < nsegs; count++, 2979193880Syongari ALC_DESC_INC(rx_cons, ALC_RX_RING_CNT)) { 2980193880Syongari rxd = &sc->alc_cdata.alc_rxdesc[rx_cons]; 2981193880Syongari mp = rxd->rx_m; 2982193880Syongari /* Add a new receive buffer to the ring. */ 2983193880Syongari if (alc_newbuf(sc, rxd) != 0) { 2984193880Syongari ifp->if_iqdrops++; 2985193880Syongari /* Reuse Rx buffers. */ 2986193880Syongari if (sc->alc_cdata.alc_rxhead != NULL) 2987193880Syongari m_freem(sc->alc_cdata.alc_rxhead); 2988193880Syongari break; 2989193880Syongari } 2990193880Syongari 2991193880Syongari /* 2992193880Syongari * Assume we've received a full sized frame. 2993193880Syongari * Actual size is fixed when we encounter the end of 2994193880Syongari * multi-segmented frame. 2995193880Syongari */ 2996193880Syongari mp->m_len = sc->alc_buf_size; 2997193880Syongari 2998193880Syongari /* Chain received mbufs. */ 2999193880Syongari if (sc->alc_cdata.alc_rxhead == NULL) { 3000193880Syongari sc->alc_cdata.alc_rxhead = mp; 3001193880Syongari sc->alc_cdata.alc_rxtail = mp; 3002193880Syongari } else { 3003193880Syongari mp->m_flags &= ~M_PKTHDR; 3004193880Syongari sc->alc_cdata.alc_rxprev_tail = 3005193880Syongari sc->alc_cdata.alc_rxtail; 3006193880Syongari sc->alc_cdata.alc_rxtail->m_next = mp; 3007193880Syongari sc->alc_cdata.alc_rxtail = mp; 3008193880Syongari } 3009193880Syongari 3010193880Syongari if (count == nsegs - 1) { 3011193880Syongari /* Last desc. for this frame. */ 3012193880Syongari m = sc->alc_cdata.alc_rxhead; 3013193880Syongari m->m_flags |= M_PKTHDR; 3014193880Syongari /* 3015193880Syongari * It seems that L1C/L2C controller has no way 3016193880Syongari * to tell hardware to strip CRC bytes. 3017193880Syongari */ 3018193880Syongari m->m_pkthdr.len = 3019193880Syongari sc->alc_cdata.alc_rxlen - ETHER_CRC_LEN; 3020193880Syongari if (nsegs > 1) { 3021193880Syongari /* Set last mbuf size. */ 3022193880Syongari mp->m_len = sc->alc_cdata.alc_rxlen - 3023193880Syongari (nsegs - 1) * sc->alc_buf_size; 3024193880Syongari /* Remove the CRC bytes in chained mbufs. */ 3025193880Syongari if (mp->m_len <= ETHER_CRC_LEN) { 3026193880Syongari sc->alc_cdata.alc_rxtail = 3027193880Syongari sc->alc_cdata.alc_rxprev_tail; 3028193880Syongari sc->alc_cdata.alc_rxtail->m_len -= 3029193880Syongari (ETHER_CRC_LEN - mp->m_len); 3030193880Syongari sc->alc_cdata.alc_rxtail->m_next = NULL; 3031193880Syongari m_freem(mp); 3032193880Syongari } else { 3033193880Syongari mp->m_len -= ETHER_CRC_LEN; 3034193880Syongari } 3035193880Syongari } else 3036193880Syongari m->m_len = m->m_pkthdr.len; 3037193880Syongari m->m_pkthdr.rcvif = ifp; 3038193880Syongari /* 3039193880Syongari * Due to hardware bugs, Rx checksum offloading 3040193880Syongari * was intentionally disabled. 3041193880Syongari */ 3042193880Syongari if ((ifp->if_capenable & IFCAP_VLAN_HWTAGGING) != 0 && 3043193880Syongari (status & RRD_VLAN_TAG) != 0) { 3044193880Syongari vtag = RRD_VLAN(le32toh(rrd->vtag)); 3045193880Syongari m->m_pkthdr.ether_vtag = ntohs(vtag); 3046193880Syongari m->m_flags |= M_VLANTAG; 3047193880Syongari } 3048193880Syongari#ifndef __NO_STRICT_ALIGNMENT 3049193880Syongari m = alc_fixup_rx(ifp, m); 3050193880Syongari if (m != NULL) 3051193880Syongari#endif 3052193880Syongari { 3053193880Syongari /* Pass it on. */ 3054217379Sjhb ALC_UNLOCK(sc); 3055193880Syongari (*ifp->if_input)(ifp, m); 3056217379Sjhb ALC_LOCK(sc); 3057193880Syongari } 3058193880Syongari } 3059193880Syongari } 3060193880Syongari /* Reset mbuf chains. */ 3061193880Syongari ALC_RXCHAIN_RESET(sc); 3062193880Syongari} 3063193880Syongari 3064193880Syongaristatic void 3065193880Syongarialc_tick(void *arg) 3066193880Syongari{ 3067193880Syongari struct alc_softc *sc; 3068193880Syongari struct mii_data *mii; 3069193880Syongari 3070193880Syongari sc = (struct alc_softc *)arg; 3071193880Syongari 3072193880Syongari ALC_LOCK_ASSERT(sc); 3073193880Syongari 3074193880Syongari mii = device_get_softc(sc->alc_miibus); 3075193880Syongari mii_tick(mii); 3076193880Syongari alc_stats_update(sc); 3077193880Syongari /* 3078193880Syongari * alc(4) does not rely on Tx completion interrupts to reclaim 3079193880Syongari * transferred buffers. Instead Tx completion interrupts are 3080193880Syongari * used to hint for scheduling Tx task. So it's necessary to 3081193880Syongari * release transmitted buffers by kicking Tx completion 3082193880Syongari * handler. This limits the maximum reclamation delay to a hz. 3083193880Syongari */ 3084193880Syongari alc_txeof(sc); 3085193880Syongari alc_watchdog(sc); 3086193880Syongari callout_reset(&sc->alc_tick_ch, hz, alc_tick, sc); 3087193880Syongari} 3088193880Syongari 3089193880Syongaristatic void 3090193880Syongarialc_reset(struct alc_softc *sc) 3091193880Syongari{ 3092193880Syongari uint32_t reg; 3093193880Syongari int i; 3094193880Syongari 3095211105Syongari reg = CSR_READ_4(sc, ALC_MASTER_CFG) & 0xFFFF; 3096211105Syongari reg |= MASTER_OOB_DIS_OFF | MASTER_RESET; 3097211105Syongari CSR_WRITE_4(sc, ALC_MASTER_CFG, reg); 3098193880Syongari for (i = ALC_RESET_TIMEOUT; i > 0; i--) { 3099193880Syongari DELAY(10); 3100193880Syongari if ((CSR_READ_4(sc, ALC_MASTER_CFG) & MASTER_RESET) == 0) 3101193880Syongari break; 3102193880Syongari } 3103193880Syongari if (i == 0) 3104193880Syongari device_printf(sc->alc_dev, "master reset timeout!\n"); 3105193880Syongari 3106193880Syongari for (i = ALC_RESET_TIMEOUT; i > 0; i--) { 3107193880Syongari if ((reg = CSR_READ_4(sc, ALC_IDLE_STATUS)) == 0) 3108193880Syongari break; 3109193880Syongari DELAY(10); 3110193880Syongari } 3111193880Syongari 3112193880Syongari if (i == 0) 3113193880Syongari device_printf(sc->alc_dev, "reset timeout(0x%08x)!\n", reg); 3114193880Syongari} 3115193880Syongari 3116193880Syongaristatic void 3117193880Syongarialc_init(void *xsc) 3118193880Syongari{ 3119193880Syongari struct alc_softc *sc; 3120193880Syongari 3121193880Syongari sc = (struct alc_softc *)xsc; 3122193880Syongari ALC_LOCK(sc); 3123193880Syongari alc_init_locked(sc); 3124193880Syongari ALC_UNLOCK(sc); 3125193880Syongari} 3126193880Syongari 3127193880Syongaristatic void 3128193880Syongarialc_init_locked(struct alc_softc *sc) 3129193880Syongari{ 3130193880Syongari struct ifnet *ifp; 3131193880Syongari struct mii_data *mii; 3132193880Syongari uint8_t eaddr[ETHER_ADDR_LEN]; 3133193880Syongari bus_addr_t paddr; 3134193880Syongari uint32_t reg, rxf_hi, rxf_lo; 3135193880Syongari 3136193880Syongari ALC_LOCK_ASSERT(sc); 3137193880Syongari 3138193880Syongari ifp = sc->alc_ifp; 3139193880Syongari mii = device_get_softc(sc->alc_miibus); 3140193880Syongari 3141193880Syongari if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0) 3142193880Syongari return; 3143193880Syongari /* 3144193880Syongari * Cancel any pending I/O. 3145193880Syongari */ 3146193880Syongari alc_stop(sc); 3147193880Syongari /* 3148193880Syongari * Reset the chip to a known state. 3149193880Syongari */ 3150193880Syongari alc_reset(sc); 3151193880Syongari 3152193880Syongari /* Initialize Rx descriptors. */ 3153193880Syongari if (alc_init_rx_ring(sc) != 0) { 3154193880Syongari device_printf(sc->alc_dev, "no memory for Rx buffers.\n"); 3155193880Syongari alc_stop(sc); 3156193880Syongari return; 3157193880Syongari } 3158193880Syongari alc_init_rr_ring(sc); 3159193880Syongari alc_init_tx_ring(sc); 3160193880Syongari alc_init_cmb(sc); 3161193880Syongari alc_init_smb(sc); 3162193880Syongari 3163217649Syongari /* Enable all clocks. */ 3164217649Syongari CSR_WRITE_4(sc, ALC_CLK_GATING_CFG, 0); 3165217649Syongari 3166193880Syongari /* Reprogram the station address. */ 3167193880Syongari bcopy(IF_LLADDR(ifp), eaddr, ETHER_ADDR_LEN); 3168193880Syongari CSR_WRITE_4(sc, ALC_PAR0, 3169193880Syongari eaddr[2] << 24 | eaddr[3] << 16 | eaddr[4] << 8 | eaddr[5]); 3170193880Syongari CSR_WRITE_4(sc, ALC_PAR1, eaddr[0] << 8 | eaddr[1]); 3171193880Syongari /* 3172193880Syongari * Clear WOL status and disable all WOL feature as WOL 3173193880Syongari * would interfere Rx operation under normal environments. 3174193880Syongari */ 3175193880Syongari CSR_READ_4(sc, ALC_WOL_CFG); 3176193880Syongari CSR_WRITE_4(sc, ALC_WOL_CFG, 0); 3177193880Syongari /* Set Tx descriptor base addresses. */ 3178193880Syongari paddr = sc->alc_rdata.alc_tx_ring_paddr; 3179193880Syongari CSR_WRITE_4(sc, ALC_TX_BASE_ADDR_HI, ALC_ADDR_HI(paddr)); 3180193880Syongari CSR_WRITE_4(sc, ALC_TDL_HEAD_ADDR_LO, ALC_ADDR_LO(paddr)); 3181193880Syongari /* We don't use high priority ring. */ 3182193880Syongari CSR_WRITE_4(sc, ALC_TDH_HEAD_ADDR_LO, 0); 3183193880Syongari /* Set Tx descriptor counter. */ 3184193880Syongari CSR_WRITE_4(sc, ALC_TD_RING_CNT, 3185193880Syongari (ALC_TX_RING_CNT << TD_RING_CNT_SHIFT) & TD_RING_CNT_MASK); 3186193880Syongari /* Set Rx descriptor base addresses. */ 3187193880Syongari paddr = sc->alc_rdata.alc_rx_ring_paddr; 3188193880Syongari CSR_WRITE_4(sc, ALC_RX_BASE_ADDR_HI, ALC_ADDR_HI(paddr)); 3189193880Syongari CSR_WRITE_4(sc, ALC_RD0_HEAD_ADDR_LO, ALC_ADDR_LO(paddr)); 3190193880Syongari /* We use one Rx ring. */ 3191193880Syongari CSR_WRITE_4(sc, ALC_RD1_HEAD_ADDR_LO, 0); 3192193880Syongari CSR_WRITE_4(sc, ALC_RD2_HEAD_ADDR_LO, 0); 3193193880Syongari CSR_WRITE_4(sc, ALC_RD3_HEAD_ADDR_LO, 0); 3194193880Syongari /* Set Rx descriptor counter. */ 3195193880Syongari CSR_WRITE_4(sc, ALC_RD_RING_CNT, 3196193880Syongari (ALC_RX_RING_CNT << RD_RING_CNT_SHIFT) & RD_RING_CNT_MASK); 3197193880Syongari 3198193880Syongari /* 3199193880Syongari * Let hardware split jumbo frames into alc_max_buf_sized chunks. 3200193880Syongari * if it do not fit the buffer size. Rx return descriptor holds 3201193880Syongari * a counter that indicates how many fragments were made by the 3202193880Syongari * hardware. The buffer size should be multiple of 8 bytes. 3203193880Syongari * Since hardware has limit on the size of buffer size, always 3204193880Syongari * use the maximum value. 3205193880Syongari * For strict-alignment architectures make sure to reduce buffer 3206193880Syongari * size by 8 bytes to make room for alignment fixup. 3207193880Syongari */ 3208193880Syongari#ifndef __NO_STRICT_ALIGNMENT 3209193880Syongari sc->alc_buf_size = RX_BUF_SIZE_MAX - sizeof(uint64_t); 3210193880Syongari#else 3211193880Syongari sc->alc_buf_size = RX_BUF_SIZE_MAX; 3212193880Syongari#endif 3213193880Syongari CSR_WRITE_4(sc, ALC_RX_BUF_SIZE, sc->alc_buf_size); 3214193880Syongari 3215193880Syongari paddr = sc->alc_rdata.alc_rr_ring_paddr; 3216193880Syongari /* Set Rx return descriptor base addresses. */ 3217193880Syongari CSR_WRITE_4(sc, ALC_RRD0_HEAD_ADDR_LO, ALC_ADDR_LO(paddr)); 3218193880Syongari /* We use one Rx return ring. */ 3219193880Syongari CSR_WRITE_4(sc, ALC_RRD1_HEAD_ADDR_LO, 0); 3220193880Syongari CSR_WRITE_4(sc, ALC_RRD2_HEAD_ADDR_LO, 0); 3221193880Syongari CSR_WRITE_4(sc, ALC_RRD3_HEAD_ADDR_LO, 0); 3222193880Syongari /* Set Rx return descriptor counter. */ 3223193880Syongari CSR_WRITE_4(sc, ALC_RRD_RING_CNT, 3224193880Syongari (ALC_RR_RING_CNT << RRD_RING_CNT_SHIFT) & RRD_RING_CNT_MASK); 3225193880Syongari paddr = sc->alc_rdata.alc_cmb_paddr; 3226193880Syongari CSR_WRITE_4(sc, ALC_CMB_BASE_ADDR_LO, ALC_ADDR_LO(paddr)); 3227193880Syongari paddr = sc->alc_rdata.alc_smb_paddr; 3228193880Syongari CSR_WRITE_4(sc, ALC_SMB_BASE_ADDR_HI, ALC_ADDR_HI(paddr)); 3229193880Syongari CSR_WRITE_4(sc, ALC_SMB_BASE_ADDR_LO, ALC_ADDR_LO(paddr)); 3230193880Syongari 3231211105Syongari if (sc->alc_ident->deviceid == DEVICEID_ATHEROS_AR8152_B) { 3232211105Syongari /* Reconfigure SRAM - Vendor magic. */ 3233211105Syongari CSR_WRITE_4(sc, ALC_SRAM_RX_FIFO_LEN, 0x000002A0); 3234211105Syongari CSR_WRITE_4(sc, ALC_SRAM_TX_FIFO_LEN, 0x00000100); 3235211105Syongari CSR_WRITE_4(sc, ALC_SRAM_RX_FIFO_ADDR, 0x029F0000); 3236211105Syongari CSR_WRITE_4(sc, ALC_SRAM_RD0_ADDR, 0x02BF02A0); 3237211105Syongari CSR_WRITE_4(sc, ALC_SRAM_TX_FIFO_ADDR, 0x03BF02C0); 3238211105Syongari CSR_WRITE_4(sc, ALC_SRAM_TD_ADDR, 0x03DF03C0); 3239211105Syongari CSR_WRITE_4(sc, ALC_TXF_WATER_MARK, 0x00000000); 3240211105Syongari CSR_WRITE_4(sc, ALC_RD_DMA_CFG, 0x00000000); 3241211105Syongari } 3242211105Syongari 3243193880Syongari /* Tell hardware that we're ready to load DMA blocks. */ 3244193880Syongari CSR_WRITE_4(sc, ALC_DMA_BLOCK, DMA_BLOCK_LOAD); 3245193880Syongari 3246193880Syongari /* Configure interrupt moderation timer. */ 3247193880Syongari reg = ALC_USECS(sc->alc_int_rx_mod) << IM_TIMER_RX_SHIFT; 3248193880Syongari reg |= ALC_USECS(sc->alc_int_tx_mod) << IM_TIMER_TX_SHIFT; 3249193880Syongari CSR_WRITE_4(sc, ALC_IM_TIMER, reg); 3250193880Syongari /* 3251193880Syongari * We don't want to automatic interrupt clear as task queue 3252193880Syongari * for the interrupt should know interrupt status. 3253193880Syongari */ 3254211105Syongari reg = MASTER_SA_TIMER_ENB; 3255193880Syongari if (ALC_USECS(sc->alc_int_rx_mod) != 0) 3256193880Syongari reg |= MASTER_IM_RX_TIMER_ENB; 3257193880Syongari if (ALC_USECS(sc->alc_int_tx_mod) != 0) 3258193880Syongari reg |= MASTER_IM_TX_TIMER_ENB; 3259193880Syongari CSR_WRITE_4(sc, ALC_MASTER_CFG, reg); 3260193880Syongari /* 3261193880Syongari * Disable interrupt re-trigger timer. We don't want automatic 3262193880Syongari * re-triggering of un-ACKed interrupts. 3263193880Syongari */ 3264193880Syongari CSR_WRITE_4(sc, ALC_INTR_RETRIG_TIMER, ALC_USECS(0)); 3265193880Syongari /* Configure CMB. */ 3266211048Syongari if ((sc->alc_flags & ALC_FLAG_CMB_BUG) == 0) { 3267211048Syongari CSR_WRITE_4(sc, ALC_CMB_TD_THRESH, 4); 3268193880Syongari CSR_WRITE_4(sc, ALC_CMB_TX_TIMER, ALC_USECS(5000)); 3269211048Syongari } else 3270193880Syongari CSR_WRITE_4(sc, ALC_CMB_TX_TIMER, ALC_USECS(0)); 3271193880Syongari /* 3272193880Syongari * Hardware can be configured to issue SMB interrupt based 3273193880Syongari * on programmed interval. Since there is a callout that is 3274193880Syongari * invoked for every hz in driver we use that instead of 3275193880Syongari * relying on periodic SMB interrupt. 3276193880Syongari */ 3277193880Syongari CSR_WRITE_4(sc, ALC_SMB_STAT_TIMER, ALC_USECS(0)); 3278193880Syongari /* Clear MAC statistics. */ 3279193880Syongari alc_stats_clear(sc); 3280193880Syongari 3281193880Syongari /* 3282193880Syongari * Always use maximum frame size that controller can support. 3283193880Syongari * Otherwise received frames that has larger frame length 3284193880Syongari * than alc(4) MTU would be silently dropped in hardware. This 3285193880Syongari * would make path-MTU discovery hard as sender wouldn't get 3286193880Syongari * any responses from receiver. alc(4) supports 3287193880Syongari * multi-fragmented frames on Rx path so it has no issue on 3288193880Syongari * assembling fragmented frames. Using maximum frame size also 3289193880Syongari * removes the need to reinitialize hardware when interface 3290193880Syongari * MTU configuration was changed. 3291193880Syongari * 3292193880Syongari * Be conservative in what you do, be liberal in what you 3293193880Syongari * accept from others - RFC 793. 3294193880Syongari */ 3295211105Syongari CSR_WRITE_4(sc, ALC_FRAME_SIZE, sc->alc_ident->max_framelen); 3296193880Syongari 3297193880Syongari /* Disable header split(?) */ 3298193880Syongari CSR_WRITE_4(sc, ALC_HDS_CFG, 0); 3299193880Syongari 3300193880Syongari /* Configure IPG/IFG parameters. */ 3301193880Syongari CSR_WRITE_4(sc, ALC_IPG_IFG_CFG, 3302193880Syongari ((IPG_IFG_IPGT_DEFAULT << IPG_IFG_IPGT_SHIFT) & IPG_IFG_IPGT_MASK) | 3303193880Syongari ((IPG_IFG_MIFG_DEFAULT << IPG_IFG_MIFG_SHIFT) & IPG_IFG_MIFG_MASK) | 3304193880Syongari ((IPG_IFG_IPG1_DEFAULT << IPG_IFG_IPG1_SHIFT) & IPG_IFG_IPG1_MASK) | 3305193880Syongari ((IPG_IFG_IPG2_DEFAULT << IPG_IFG_IPG2_SHIFT) & IPG_IFG_IPG2_MASK)); 3306193880Syongari /* Set parameters for half-duplex media. */ 3307193880Syongari CSR_WRITE_4(sc, ALC_HDPX_CFG, 3308193880Syongari ((HDPX_CFG_LCOL_DEFAULT << HDPX_CFG_LCOL_SHIFT) & 3309193880Syongari HDPX_CFG_LCOL_MASK) | 3310193880Syongari ((HDPX_CFG_RETRY_DEFAULT << HDPX_CFG_RETRY_SHIFT) & 3311193880Syongari HDPX_CFG_RETRY_MASK) | HDPX_CFG_EXC_DEF_EN | 3312193880Syongari ((HDPX_CFG_ABEBT_DEFAULT << HDPX_CFG_ABEBT_SHIFT) & 3313193880Syongari HDPX_CFG_ABEBT_MASK) | 3314193880Syongari ((HDPX_CFG_JAMIPG_DEFAULT << HDPX_CFG_JAMIPG_SHIFT) & 3315193880Syongari HDPX_CFG_JAMIPG_MASK)); 3316193880Syongari /* 3317193880Syongari * Set TSO/checksum offload threshold. For frames that is 3318193880Syongari * larger than this threshold, hardware wouldn't do 3319193880Syongari * TSO/checksum offloading. 3320193880Syongari */ 3321193880Syongari CSR_WRITE_4(sc, ALC_TSO_OFFLOAD_THRESH, 3322211105Syongari (sc->alc_ident->max_framelen >> TSO_OFFLOAD_THRESH_UNIT_SHIFT) & 3323193880Syongari TSO_OFFLOAD_THRESH_MASK); 3324193880Syongari /* Configure TxQ. */ 3325193880Syongari reg = (alc_dma_burst[sc->alc_dma_rd_burst] << 3326193880Syongari TXQ_CFG_TX_FIFO_BURST_SHIFT) & TXQ_CFG_TX_FIFO_BURST_MASK; 3327211105Syongari if (sc->alc_ident->deviceid == DEVICEID_ATHEROS_AR8152_B || 3328211105Syongari sc->alc_ident->deviceid == DEVICEID_ATHEROS_AR8152_B2) 3329211105Syongari reg >>= 1; 3330193880Syongari reg |= (TXQ_CFG_TD_BURST_DEFAULT << TXQ_CFG_TD_BURST_SHIFT) & 3331193880Syongari TXQ_CFG_TD_BURST_MASK; 3332193880Syongari CSR_WRITE_4(sc, ALC_TXQ_CFG, reg | TXQ_CFG_ENHANCED_MODE); 3333193880Syongari 3334193880Syongari /* Configure Rx free descriptor pre-fetching. */ 3335193880Syongari CSR_WRITE_4(sc, ALC_RX_RD_FREE_THRESH, 3336193880Syongari ((RX_RD_FREE_THRESH_HI_DEFAULT << RX_RD_FREE_THRESH_HI_SHIFT) & 3337193880Syongari RX_RD_FREE_THRESH_HI_MASK) | 3338193880Syongari ((RX_RD_FREE_THRESH_LO_DEFAULT << RX_RD_FREE_THRESH_LO_SHIFT) & 3339193880Syongari RX_RD_FREE_THRESH_LO_MASK)); 3340193880Syongari 3341193880Syongari /* 3342193880Syongari * Configure flow control parameters. 3343193880Syongari * XON : 80% of Rx FIFO 3344193880Syongari * XOFF : 30% of Rx FIFO 3345193880Syongari */ 3346211105Syongari if (sc->alc_ident->deviceid == DEVICEID_ATHEROS_AR8131 || 3347211105Syongari sc->alc_ident->deviceid == DEVICEID_ATHEROS_AR8132) { 3348211105Syongari reg = CSR_READ_4(sc, ALC_SRAM_RX_FIFO_LEN); 3349211105Syongari rxf_hi = (reg * 8) / 10; 3350211105Syongari rxf_lo = (reg * 3) / 10; 3351211105Syongari CSR_WRITE_4(sc, ALC_RX_FIFO_PAUSE_THRESH, 3352211105Syongari ((rxf_lo << RX_FIFO_PAUSE_THRESH_LO_SHIFT) & 3353211105Syongari RX_FIFO_PAUSE_THRESH_LO_MASK) | 3354211105Syongari ((rxf_hi << RX_FIFO_PAUSE_THRESH_HI_SHIFT) & 3355211105Syongari RX_FIFO_PAUSE_THRESH_HI_MASK)); 3356211105Syongari } 3357193880Syongari 3358211105Syongari if (sc->alc_ident->deviceid == DEVICEID_ATHEROS_AR8152_B || 3359211105Syongari sc->alc_ident->deviceid == DEVICEID_ATHEROS_AR8151_V2) 3360211105Syongari CSR_WRITE_4(sc, ALC_SERDES_LOCK, 3361211105Syongari CSR_READ_4(sc, ALC_SERDES_LOCK) | SERDES_MAC_CLK_SLOWDOWN | 3362211105Syongari SERDES_PHY_CLK_SLOWDOWN); 3363211105Syongari 3364193880Syongari /* Disable RSS until I understand L1C/L2C's RSS logic. */ 3365193880Syongari CSR_WRITE_4(sc, ALC_RSS_IDT_TABLE0, 0); 3366193880Syongari CSR_WRITE_4(sc, ALC_RSS_CPU, 0); 3367193880Syongari 3368193880Syongari /* Configure RxQ. */ 3369193880Syongari reg = (RXQ_CFG_RD_BURST_DEFAULT << RXQ_CFG_RD_BURST_SHIFT) & 3370193880Syongari RXQ_CFG_RD_BURST_MASK; 3371193880Syongari reg |= RXQ_CFG_RSS_MODE_DIS; 3372193880Syongari if ((sc->alc_flags & ALC_FLAG_ASPM_MON) != 0) 3373211105Syongari reg |= RXQ_CFG_ASPM_THROUGHPUT_LIMIT_1M; 3374193880Syongari CSR_WRITE_4(sc, ALC_RXQ_CFG, reg); 3375193880Syongari 3376193880Syongari /* Configure DMA parameters. */ 3377193880Syongari reg = DMA_CFG_OUT_ORDER | DMA_CFG_RD_REQ_PRI; 3378193880Syongari reg |= sc->alc_rcb; 3379193880Syongari if ((sc->alc_flags & ALC_FLAG_CMB_BUG) == 0) 3380193880Syongari reg |= DMA_CFG_CMB_ENB; 3381193880Syongari if ((sc->alc_flags & ALC_FLAG_SMB_BUG) == 0) 3382193880Syongari reg |= DMA_CFG_SMB_ENB; 3383193880Syongari else 3384193880Syongari reg |= DMA_CFG_SMB_DIS; 3385193880Syongari reg |= (sc->alc_dma_rd_burst & DMA_CFG_RD_BURST_MASK) << 3386193880Syongari DMA_CFG_RD_BURST_SHIFT; 3387193880Syongari reg |= (sc->alc_dma_wr_burst & DMA_CFG_WR_BURST_MASK) << 3388193880Syongari DMA_CFG_WR_BURST_SHIFT; 3389193880Syongari reg |= (DMA_CFG_RD_DELAY_CNT_DEFAULT << DMA_CFG_RD_DELAY_CNT_SHIFT) & 3390193880Syongari DMA_CFG_RD_DELAY_CNT_MASK; 3391193880Syongari reg |= (DMA_CFG_WR_DELAY_CNT_DEFAULT << DMA_CFG_WR_DELAY_CNT_SHIFT) & 3392193880Syongari DMA_CFG_WR_DELAY_CNT_MASK; 3393193880Syongari CSR_WRITE_4(sc, ALC_DMA_CFG, reg); 3394193880Syongari 3395193880Syongari /* 3396193880Syongari * Configure Tx/Rx MACs. 3397193880Syongari * - Auto-padding for short frames. 3398193880Syongari * - Enable CRC generation. 3399193880Syongari * Actual reconfiguration of MAC for resolved speed/duplex 3400193880Syongari * is followed after detection of link establishment. 3401211105Syongari * AR813x/AR815x always does checksum computation regardless 3402193880Syongari * of MAC_CFG_RXCSUM_ENB bit. Also the controller is known to 3403193880Syongari * have bug in protocol field in Rx return structure so 3404193880Syongari * these controllers can't handle fragmented frames. Disable 3405193880Syongari * Rx checksum offloading until there is a newer controller 3406193880Syongari * that has sane implementation. 3407193880Syongari */ 3408193880Syongari reg = MAC_CFG_TX_CRC_ENB | MAC_CFG_TX_AUTO_PAD | MAC_CFG_FULL_DUPLEX | 3409193880Syongari ((MAC_CFG_PREAMBLE_DEFAULT << MAC_CFG_PREAMBLE_SHIFT) & 3410193880Syongari MAC_CFG_PREAMBLE_MASK); 3411211105Syongari if (sc->alc_ident->deviceid == DEVICEID_ATHEROS_AR8151 || 3412211105Syongari sc->alc_ident->deviceid == DEVICEID_ATHEROS_AR8151_V2 || 3413211105Syongari sc->alc_ident->deviceid == DEVICEID_ATHEROS_AR8152_B2) 3414211105Syongari reg |= MAC_CFG_HASH_ALG_CRC32 | MAC_CFG_SPEED_MODE_SW; 3415193880Syongari if ((sc->alc_flags & ALC_FLAG_FASTETHER) != 0) 3416193880Syongari reg |= MAC_CFG_SPEED_10_100; 3417193880Syongari else 3418193880Syongari reg |= MAC_CFG_SPEED_1000; 3419193880Syongari CSR_WRITE_4(sc, ALC_MAC_CFG, reg); 3420193880Syongari 3421193880Syongari /* Set up the receive filter. */ 3422193880Syongari alc_rxfilter(sc); 3423193880Syongari alc_rxvlan(sc); 3424193880Syongari 3425193880Syongari /* Acknowledge all pending interrupts and clear it. */ 3426193880Syongari CSR_WRITE_4(sc, ALC_INTR_MASK, ALC_INTRS); 3427193880Syongari CSR_WRITE_4(sc, ALC_INTR_STATUS, 0xFFFFFFFF); 3428193880Syongari CSR_WRITE_4(sc, ALC_INTR_STATUS, 0); 3429193880Syongari 3430193880Syongari sc->alc_flags &= ~ALC_FLAG_LINK; 3431193880Syongari /* Switch to the current media. */ 3432193880Syongari mii_mediachg(mii); 3433193880Syongari 3434193880Syongari callout_reset(&sc->alc_tick_ch, hz, alc_tick, sc); 3435193880Syongari 3436193880Syongari ifp->if_drv_flags |= IFF_DRV_RUNNING; 3437193880Syongari ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 3438193880Syongari} 3439193880Syongari 3440193880Syongaristatic void 3441193880Syongarialc_stop(struct alc_softc *sc) 3442193880Syongari{ 3443193880Syongari struct ifnet *ifp; 3444193880Syongari struct alc_txdesc *txd; 3445193880Syongari struct alc_rxdesc *rxd; 3446193880Syongari uint32_t reg; 3447193880Syongari int i; 3448193880Syongari 3449193880Syongari ALC_LOCK_ASSERT(sc); 3450193880Syongari /* 3451193880Syongari * Mark the interface down and cancel the watchdog timer. 3452193880Syongari */ 3453193880Syongari ifp = sc->alc_ifp; 3454193880Syongari ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE); 3455193880Syongari sc->alc_flags &= ~ALC_FLAG_LINK; 3456193880Syongari callout_stop(&sc->alc_tick_ch); 3457193880Syongari sc->alc_watchdog_timer = 0; 3458193880Syongari alc_stats_update(sc); 3459193880Syongari /* Disable interrupts. */ 3460193880Syongari CSR_WRITE_4(sc, ALC_INTR_MASK, 0); 3461193880Syongari CSR_WRITE_4(sc, ALC_INTR_STATUS, 0xFFFFFFFF); 3462193880Syongari alc_stop_queue(sc); 3463193880Syongari /* Disable DMA. */ 3464193880Syongari reg = CSR_READ_4(sc, ALC_DMA_CFG); 3465193880Syongari reg &= ~(DMA_CFG_CMB_ENB | DMA_CFG_SMB_ENB); 3466193880Syongari reg |= DMA_CFG_SMB_DIS; 3467193880Syongari CSR_WRITE_4(sc, ALC_DMA_CFG, reg); 3468193880Syongari DELAY(1000); 3469193880Syongari /* Stop Rx/Tx MACs. */ 3470193880Syongari alc_stop_mac(sc); 3471193880Syongari /* Disable interrupts which might be touched in taskq handler. */ 3472193880Syongari CSR_WRITE_4(sc, ALC_INTR_STATUS, 0xFFFFFFFF); 3473193880Syongari 3474193880Syongari /* Reclaim Rx buffers that have been processed. */ 3475193880Syongari if (sc->alc_cdata.alc_rxhead != NULL) 3476193880Syongari m_freem(sc->alc_cdata.alc_rxhead); 3477193880Syongari ALC_RXCHAIN_RESET(sc); 3478193880Syongari /* 3479193880Syongari * Free Tx/Rx mbufs still in the queues. 3480193880Syongari */ 3481193880Syongari for (i = 0; i < ALC_RX_RING_CNT; i++) { 3482193880Syongari rxd = &sc->alc_cdata.alc_rxdesc[i]; 3483193880Syongari if (rxd->rx_m != NULL) { 3484193880Syongari bus_dmamap_sync(sc->alc_cdata.alc_rx_tag, 3485193880Syongari rxd->rx_dmamap, BUS_DMASYNC_POSTREAD); 3486193880Syongari bus_dmamap_unload(sc->alc_cdata.alc_rx_tag, 3487193880Syongari rxd->rx_dmamap); 3488193880Syongari m_freem(rxd->rx_m); 3489193880Syongari rxd->rx_m = NULL; 3490193880Syongari } 3491193880Syongari } 3492193880Syongari for (i = 0; i < ALC_TX_RING_CNT; i++) { 3493193880Syongari txd = &sc->alc_cdata.alc_txdesc[i]; 3494193880Syongari if (txd->tx_m != NULL) { 3495193880Syongari bus_dmamap_sync(sc->alc_cdata.alc_tx_tag, 3496193880Syongari txd->tx_dmamap, BUS_DMASYNC_POSTWRITE); 3497193880Syongari bus_dmamap_unload(sc->alc_cdata.alc_tx_tag, 3498193880Syongari txd->tx_dmamap); 3499193880Syongari m_freem(txd->tx_m); 3500193880Syongari txd->tx_m = NULL; 3501193880Syongari } 3502193880Syongari } 3503193880Syongari} 3504193880Syongari 3505193880Syongaristatic void 3506193880Syongarialc_stop_mac(struct alc_softc *sc) 3507193880Syongari{ 3508193880Syongari uint32_t reg; 3509193880Syongari int i; 3510193880Syongari 3511193880Syongari ALC_LOCK_ASSERT(sc); 3512193880Syongari 3513193880Syongari /* Disable Rx/Tx MAC. */ 3514193880Syongari reg = CSR_READ_4(sc, ALC_MAC_CFG); 3515193880Syongari if ((reg & (MAC_CFG_TX_ENB | MAC_CFG_RX_ENB)) != 0) { 3516211285Syongari reg &= ~(MAC_CFG_TX_ENB | MAC_CFG_RX_ENB); 3517193880Syongari CSR_WRITE_4(sc, ALC_MAC_CFG, reg); 3518193880Syongari } 3519193880Syongari for (i = ALC_TIMEOUT; i > 0; i--) { 3520193880Syongari reg = CSR_READ_4(sc, ALC_IDLE_STATUS); 3521193880Syongari if (reg == 0) 3522193880Syongari break; 3523193880Syongari DELAY(10); 3524193880Syongari } 3525193880Syongari if (i == 0) 3526193880Syongari device_printf(sc->alc_dev, 3527193880Syongari "could not disable Rx/Tx MAC(0x%08x)!\n", reg); 3528193880Syongari} 3529193880Syongari 3530193880Syongaristatic void 3531193880Syongarialc_start_queue(struct alc_softc *sc) 3532193880Syongari{ 3533193880Syongari uint32_t qcfg[] = { 3534193880Syongari 0, 3535193880Syongari RXQ_CFG_QUEUE0_ENB, 3536193880Syongari RXQ_CFG_QUEUE0_ENB | RXQ_CFG_QUEUE1_ENB, 3537193880Syongari RXQ_CFG_QUEUE0_ENB | RXQ_CFG_QUEUE1_ENB | RXQ_CFG_QUEUE2_ENB, 3538193880Syongari RXQ_CFG_ENB 3539193880Syongari }; 3540193880Syongari uint32_t cfg; 3541193880Syongari 3542193880Syongari ALC_LOCK_ASSERT(sc); 3543193880Syongari 3544193880Syongari /* Enable RxQ. */ 3545193880Syongari cfg = CSR_READ_4(sc, ALC_RXQ_CFG); 3546193880Syongari cfg &= ~RXQ_CFG_ENB; 3547193880Syongari cfg |= qcfg[1]; 3548193880Syongari CSR_WRITE_4(sc, ALC_RXQ_CFG, cfg); 3549193880Syongari /* Enable TxQ. */ 3550193880Syongari cfg = CSR_READ_4(sc, ALC_TXQ_CFG); 3551193880Syongari cfg |= TXQ_CFG_ENB; 3552193880Syongari CSR_WRITE_4(sc, ALC_TXQ_CFG, cfg); 3553193880Syongari} 3554193880Syongari 3555193880Syongaristatic void 3556193880Syongarialc_stop_queue(struct alc_softc *sc) 3557193880Syongari{ 3558193880Syongari uint32_t reg; 3559193880Syongari int i; 3560193880Syongari 3561193880Syongari ALC_LOCK_ASSERT(sc); 3562193880Syongari 3563193880Syongari /* Disable RxQ. */ 3564193880Syongari reg = CSR_READ_4(sc, ALC_RXQ_CFG); 3565193880Syongari if ((reg & RXQ_CFG_ENB) != 0) { 3566193880Syongari reg &= ~RXQ_CFG_ENB; 3567193880Syongari CSR_WRITE_4(sc, ALC_RXQ_CFG, reg); 3568193880Syongari } 3569193880Syongari /* Disable TxQ. */ 3570193880Syongari reg = CSR_READ_4(sc, ALC_TXQ_CFG); 3571218038Syongari if ((reg & TXQ_CFG_ENB) != 0) { 3572193880Syongari reg &= ~TXQ_CFG_ENB; 3573193880Syongari CSR_WRITE_4(sc, ALC_TXQ_CFG, reg); 3574193880Syongari } 3575193880Syongari for (i = ALC_TIMEOUT; i > 0; i--) { 3576193880Syongari reg = CSR_READ_4(sc, ALC_IDLE_STATUS); 3577193880Syongari if ((reg & (IDLE_STATUS_RXQ | IDLE_STATUS_TXQ)) == 0) 3578193880Syongari break; 3579193880Syongari DELAY(10); 3580193880Syongari } 3581193880Syongari if (i == 0) 3582193880Syongari device_printf(sc->alc_dev, 3583193880Syongari "could not disable RxQ/TxQ (0x%08x)!\n", reg); 3584193880Syongari} 3585193880Syongari 3586193880Syongaristatic void 3587193880Syongarialc_init_tx_ring(struct alc_softc *sc) 3588193880Syongari{ 3589193880Syongari struct alc_ring_data *rd; 3590193880Syongari struct alc_txdesc *txd; 3591193880Syongari int i; 3592193880Syongari 3593193880Syongari ALC_LOCK_ASSERT(sc); 3594193880Syongari 3595193880Syongari sc->alc_cdata.alc_tx_prod = 0; 3596193880Syongari sc->alc_cdata.alc_tx_cons = 0; 3597193880Syongari sc->alc_cdata.alc_tx_cnt = 0; 3598193880Syongari 3599193880Syongari rd = &sc->alc_rdata; 3600193880Syongari bzero(rd->alc_tx_ring, ALC_TX_RING_SZ); 3601193880Syongari for (i = 0; i < ALC_TX_RING_CNT; i++) { 3602193880Syongari txd = &sc->alc_cdata.alc_txdesc[i]; 3603193880Syongari txd->tx_m = NULL; 3604193880Syongari } 3605193880Syongari 3606193880Syongari bus_dmamap_sync(sc->alc_cdata.alc_tx_ring_tag, 3607193880Syongari sc->alc_cdata.alc_tx_ring_map, BUS_DMASYNC_PREWRITE); 3608193880Syongari} 3609193880Syongari 3610193880Syongaristatic int 3611193880Syongarialc_init_rx_ring(struct alc_softc *sc) 3612193880Syongari{ 3613193880Syongari struct alc_ring_data *rd; 3614193880Syongari struct alc_rxdesc *rxd; 3615193880Syongari int i; 3616193880Syongari 3617193880Syongari ALC_LOCK_ASSERT(sc); 3618193880Syongari 3619193880Syongari sc->alc_cdata.alc_rx_cons = ALC_RX_RING_CNT - 1; 3620193880Syongari sc->alc_morework = 0; 3621193880Syongari rd = &sc->alc_rdata; 3622193880Syongari bzero(rd->alc_rx_ring, ALC_RX_RING_SZ); 3623193880Syongari for (i = 0; i < ALC_RX_RING_CNT; i++) { 3624193880Syongari rxd = &sc->alc_cdata.alc_rxdesc[i]; 3625193880Syongari rxd->rx_m = NULL; 3626193880Syongari rxd->rx_desc = &rd->alc_rx_ring[i]; 3627193880Syongari if (alc_newbuf(sc, rxd) != 0) 3628193880Syongari return (ENOBUFS); 3629193880Syongari } 3630193880Syongari 3631193880Syongari /* 3632193880Syongari * Since controller does not update Rx descriptors, driver 3633193880Syongari * does have to read Rx descriptors back so BUS_DMASYNC_PREWRITE 3634193880Syongari * is enough to ensure coherence. 3635193880Syongari */ 3636193880Syongari bus_dmamap_sync(sc->alc_cdata.alc_rx_ring_tag, 3637193880Syongari sc->alc_cdata.alc_rx_ring_map, BUS_DMASYNC_PREWRITE); 3638193880Syongari /* Let controller know availability of new Rx buffers. */ 3639193880Syongari CSR_WRITE_4(sc, ALC_MBOX_RD0_PROD_IDX, sc->alc_cdata.alc_rx_cons); 3640193880Syongari 3641193880Syongari return (0); 3642193880Syongari} 3643193880Syongari 3644193880Syongaristatic void 3645193880Syongarialc_init_rr_ring(struct alc_softc *sc) 3646193880Syongari{ 3647193880Syongari struct alc_ring_data *rd; 3648193880Syongari 3649193880Syongari ALC_LOCK_ASSERT(sc); 3650193880Syongari 3651193880Syongari sc->alc_cdata.alc_rr_cons = 0; 3652193880Syongari ALC_RXCHAIN_RESET(sc); 3653193880Syongari 3654193880Syongari rd = &sc->alc_rdata; 3655193880Syongari bzero(rd->alc_rr_ring, ALC_RR_RING_SZ); 3656193880Syongari bus_dmamap_sync(sc->alc_cdata.alc_rr_ring_tag, 3657193880Syongari sc->alc_cdata.alc_rr_ring_map, 3658193880Syongari BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 3659193880Syongari} 3660193880Syongari 3661193880Syongaristatic void 3662193880Syongarialc_init_cmb(struct alc_softc *sc) 3663193880Syongari{ 3664193880Syongari struct alc_ring_data *rd; 3665193880Syongari 3666193880Syongari ALC_LOCK_ASSERT(sc); 3667193880Syongari 3668193880Syongari rd = &sc->alc_rdata; 3669193880Syongari bzero(rd->alc_cmb, ALC_CMB_SZ); 3670193880Syongari bus_dmamap_sync(sc->alc_cdata.alc_cmb_tag, sc->alc_cdata.alc_cmb_map, 3671193880Syongari BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 3672193880Syongari} 3673193880Syongari 3674193880Syongaristatic void 3675193880Syongarialc_init_smb(struct alc_softc *sc) 3676193880Syongari{ 3677193880Syongari struct alc_ring_data *rd; 3678193880Syongari 3679193880Syongari ALC_LOCK_ASSERT(sc); 3680193880Syongari 3681193880Syongari rd = &sc->alc_rdata; 3682193880Syongari bzero(rd->alc_smb, ALC_SMB_SZ); 3683193880Syongari bus_dmamap_sync(sc->alc_cdata.alc_smb_tag, sc->alc_cdata.alc_smb_map, 3684193880Syongari BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 3685193880Syongari} 3686193880Syongari 3687193880Syongaristatic void 3688193880Syongarialc_rxvlan(struct alc_softc *sc) 3689193880Syongari{ 3690193880Syongari struct ifnet *ifp; 3691193880Syongari uint32_t reg; 3692193880Syongari 3693193880Syongari ALC_LOCK_ASSERT(sc); 3694193880Syongari 3695193880Syongari ifp = sc->alc_ifp; 3696193880Syongari reg = CSR_READ_4(sc, ALC_MAC_CFG); 3697193880Syongari if ((ifp->if_capenable & IFCAP_VLAN_HWTAGGING) != 0) 3698193880Syongari reg |= MAC_CFG_VLAN_TAG_STRIP; 3699193880Syongari else 3700193880Syongari reg &= ~MAC_CFG_VLAN_TAG_STRIP; 3701193880Syongari CSR_WRITE_4(sc, ALC_MAC_CFG, reg); 3702193880Syongari} 3703193880Syongari 3704193880Syongaristatic void 3705193880Syongarialc_rxfilter(struct alc_softc *sc) 3706193880Syongari{ 3707193880Syongari struct ifnet *ifp; 3708193880Syongari struct ifmultiaddr *ifma; 3709193880Syongari uint32_t crc; 3710193880Syongari uint32_t mchash[2]; 3711193880Syongari uint32_t rxcfg; 3712193880Syongari 3713193880Syongari ALC_LOCK_ASSERT(sc); 3714193880Syongari 3715193880Syongari ifp = sc->alc_ifp; 3716193880Syongari 3717193880Syongari bzero(mchash, sizeof(mchash)); 3718193880Syongari rxcfg = CSR_READ_4(sc, ALC_MAC_CFG); 3719193880Syongari rxcfg &= ~(MAC_CFG_ALLMULTI | MAC_CFG_BCAST | MAC_CFG_PROMISC); 3720193880Syongari if ((ifp->if_flags & IFF_BROADCAST) != 0) 3721193880Syongari rxcfg |= MAC_CFG_BCAST; 3722193880Syongari if ((ifp->if_flags & (IFF_PROMISC | IFF_ALLMULTI)) != 0) { 3723193880Syongari if ((ifp->if_flags & IFF_PROMISC) != 0) 3724193880Syongari rxcfg |= MAC_CFG_PROMISC; 3725193880Syongari if ((ifp->if_flags & IFF_ALLMULTI) != 0) 3726193880Syongari rxcfg |= MAC_CFG_ALLMULTI; 3727193880Syongari mchash[0] = 0xFFFFFFFF; 3728193880Syongari mchash[1] = 0xFFFFFFFF; 3729193880Syongari goto chipit; 3730193880Syongari } 3731193880Syongari 3732195049Srwatson if_maddr_rlock(ifp); 3733193880Syongari TAILQ_FOREACH(ifma, &sc->alc_ifp->if_multiaddrs, ifma_link) { 3734193880Syongari if (ifma->ifma_addr->sa_family != AF_LINK) 3735193880Syongari continue; 3736197627Syongari crc = ether_crc32_be(LLADDR((struct sockaddr_dl *) 3737193880Syongari ifma->ifma_addr), ETHER_ADDR_LEN); 3738193880Syongari mchash[crc >> 31] |= 1 << ((crc >> 26) & 0x1f); 3739193880Syongari } 3740195049Srwatson if_maddr_runlock(ifp); 3741193880Syongari 3742193880Syongarichipit: 3743193880Syongari CSR_WRITE_4(sc, ALC_MAR0, mchash[0]); 3744193880Syongari CSR_WRITE_4(sc, ALC_MAR1, mchash[1]); 3745193880Syongari CSR_WRITE_4(sc, ALC_MAC_CFG, rxcfg); 3746193880Syongari} 3747193880Syongari 3748193880Syongaristatic int 3749193880Syongarisysctl_int_range(SYSCTL_HANDLER_ARGS, int low, int high) 3750193880Syongari{ 3751193880Syongari int error, value; 3752193880Syongari 3753193880Syongari if (arg1 == NULL) 3754193880Syongari return (EINVAL); 3755193880Syongari value = *(int *)arg1; 3756193880Syongari error = sysctl_handle_int(oidp, &value, 0, req); 3757193880Syongari if (error || req->newptr == NULL) 3758193880Syongari return (error); 3759193880Syongari if (value < low || value > high) 3760193880Syongari return (EINVAL); 3761193880Syongari *(int *)arg1 = value; 3762193880Syongari 3763193880Syongari return (0); 3764193880Syongari} 3765193880Syongari 3766193880Syongaristatic int 3767193880Syongarisysctl_hw_alc_proc_limit(SYSCTL_HANDLER_ARGS) 3768193880Syongari{ 3769193880Syongari return (sysctl_int_range(oidp, arg1, arg2, req, 3770193880Syongari ALC_PROC_MIN, ALC_PROC_MAX)); 3771193880Syongari} 3772193880Syongari 3773193880Syongaristatic int 3774193880Syongarisysctl_hw_alc_int_mod(SYSCTL_HANDLER_ARGS) 3775193880Syongari{ 3776193880Syongari 3777193880Syongari return (sysctl_int_range(oidp, arg1, arg2, req, 3778193880Syongari ALC_IM_TIMER_MIN, ALC_IM_TIMER_MAX)); 3779193880Syongari} 3780