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