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: stable/11/sys/dev/alc/if_alc.c 314005 2017-02-21 02:19:19Z sephe $"); 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" }, 114272730Syongari { VENDORID_ATHEROS, DEVICEID_ATHEROS_AR8161, 9 * 1024, 115272730Syongari "Atheros AR8161 PCIe Gigabit Ethernet" }, 116272730Syongari { VENDORID_ATHEROS, DEVICEID_ATHEROS_AR8162, 9 * 1024, 117277907Syongari "Atheros AR8162 PCIe Fast Ethernet" }, 118272730Syongari { VENDORID_ATHEROS, DEVICEID_ATHEROS_AR8171, 9 * 1024, 119277907Syongari "Atheros AR8171 PCIe Gigabit Ethernet" }, 120272730Syongari { VENDORID_ATHEROS, DEVICEID_ATHEROS_AR8172, 9 * 1024, 121277907Syongari "Atheros AR8172 PCIe Fast Ethernet" }, 122272730Syongari { VENDORID_ATHEROS, DEVICEID_ATHEROS_E2200, 9 * 1024, 123272730Syongari "Killer E2200 Gigabit Ethernet" }, 124312358Syongari { VENDORID_ATHEROS, DEVICEID_ATHEROS_E2400, 9 * 1024, 125312358Syongari "Killer E2400 Gigabit Ethernet" }, 126314005Ssephe { VENDORID_ATHEROS, DEVICEID_ATHEROS_E2500, 9 * 1024, 127314005Ssephe "Killer E2500 Gigabit Ethernet" }, 128211105Syongari { 0, 0, 0, NULL} 129193880Syongari}; 130193880Syongari 131272730Syongaristatic void alc_aspm(struct alc_softc *, int, int); 132272730Syongaristatic void alc_aspm_813x(struct alc_softc *, int); 133272730Syongaristatic void alc_aspm_816x(struct alc_softc *, int); 134193880Syongaristatic int alc_attach(device_t); 135193880Syongaristatic int alc_check_boundary(struct alc_softc *); 136272730Syongaristatic void alc_config_msi(struct alc_softc *); 137193880Syongaristatic int alc_detach(device_t); 138193880Syongaristatic void alc_disable_l0s_l1(struct alc_softc *); 139193880Syongaristatic int alc_dma_alloc(struct alc_softc *); 140193880Syongaristatic void alc_dma_free(struct alc_softc *); 141193880Syongaristatic void alc_dmamap_cb(void *, bus_dma_segment_t *, int, int); 142272730Syongaristatic void alc_dsp_fixup(struct alc_softc *, int); 143193880Syongaristatic int alc_encap(struct alc_softc *, struct mbuf **); 144211105Syongaristatic struct alc_ident * 145211105Syongari alc_find_ident(device_t); 146193880Syongari#ifndef __NO_STRICT_ALIGNMENT 147193880Syongaristatic struct mbuf * 148193880Syongari alc_fixup_rx(struct ifnet *, struct mbuf *); 149193880Syongari#endif 150193880Syongaristatic void alc_get_macaddr(struct alc_softc *); 151272730Syongaristatic void alc_get_macaddr_813x(struct alc_softc *); 152272730Syongaristatic void alc_get_macaddr_816x(struct alc_softc *); 153272730Syongaristatic void alc_get_macaddr_par(struct alc_softc *); 154193880Syongaristatic void alc_init(void *); 155193880Syongaristatic void alc_init_cmb(struct alc_softc *); 156193880Syongaristatic void alc_init_locked(struct alc_softc *); 157193880Syongaristatic void alc_init_rr_ring(struct alc_softc *); 158193880Syongaristatic int alc_init_rx_ring(struct alc_softc *); 159193880Syongaristatic void alc_init_smb(struct alc_softc *); 160193880Syongaristatic void alc_init_tx_ring(struct alc_softc *); 161193880Syongaristatic void alc_int_task(void *, int); 162193880Syongaristatic int alc_intr(void *); 163193880Syongaristatic int alc_ioctl(struct ifnet *, u_long, caddr_t); 164193880Syongaristatic void alc_mac_config(struct alc_softc *); 165272730Syongaristatic uint32_t alc_mii_readreg_813x(struct alc_softc *, int, int); 166272730Syongaristatic uint32_t alc_mii_readreg_816x(struct alc_softc *, int, int); 167272730Syongaristatic uint32_t alc_mii_writereg_813x(struct alc_softc *, int, int, int); 168272730Syongaristatic uint32_t alc_mii_writereg_816x(struct alc_softc *, int, int, int); 169193880Syongaristatic int alc_miibus_readreg(device_t, int, int); 170193880Syongaristatic void alc_miibus_statchg(device_t); 171193880Syongaristatic int alc_miibus_writereg(device_t, int, int, int); 172272730Syongaristatic uint32_t alc_miidbg_readreg(struct alc_softc *, int); 173272730Syongaristatic uint32_t alc_miidbg_writereg(struct alc_softc *, int, int); 174272730Syongaristatic uint32_t alc_miiext_readreg(struct alc_softc *, int, int); 175272730Syongaristatic uint32_t alc_miiext_writereg(struct alc_softc *, int, int, int); 176193880Syongaristatic int alc_mediachange(struct ifnet *); 177272730Syongaristatic int alc_mediachange_locked(struct alc_softc *); 178193880Syongaristatic void alc_mediastatus(struct ifnet *, struct ifmediareq *); 179193880Syongaristatic int alc_newbuf(struct alc_softc *, struct alc_rxdesc *); 180272730Syongaristatic void alc_osc_reset(struct alc_softc *); 181193880Syongaristatic void alc_phy_down(struct alc_softc *); 182193880Syongaristatic void alc_phy_reset(struct alc_softc *); 183272730Syongaristatic void alc_phy_reset_813x(struct alc_softc *); 184272730Syongaristatic void alc_phy_reset_816x(struct alc_softc *); 185193880Syongaristatic int alc_probe(device_t); 186193880Syongaristatic void alc_reset(struct alc_softc *); 187193880Syongaristatic int alc_resume(device_t); 188193880Syongaristatic void alc_rxeof(struct alc_softc *, struct rx_rdesc *); 189193880Syongaristatic int alc_rxintr(struct alc_softc *, int); 190193880Syongaristatic void alc_rxfilter(struct alc_softc *); 191193880Syongaristatic void alc_rxvlan(struct alc_softc *); 192193880Syongaristatic void alc_setlinkspeed(struct alc_softc *); 193193880Syongaristatic void alc_setwol(struct alc_softc *); 194272730Syongaristatic void alc_setwol_813x(struct alc_softc *); 195272730Syongaristatic void alc_setwol_816x(struct alc_softc *); 196193880Syongaristatic int alc_shutdown(device_t); 197193880Syongaristatic void alc_start(struct ifnet *); 198216925Sjhbstatic void alc_start_locked(struct ifnet *); 199193880Syongaristatic void alc_start_queue(struct alc_softc *); 200193880Syongaristatic void alc_stats_clear(struct alc_softc *); 201193880Syongaristatic void alc_stats_update(struct alc_softc *); 202193880Syongaristatic void alc_stop(struct alc_softc *); 203193880Syongaristatic void alc_stop_mac(struct alc_softc *); 204193880Syongaristatic void alc_stop_queue(struct alc_softc *); 205193880Syongaristatic int alc_suspend(device_t); 206193880Syongaristatic void alc_sysctl_node(struct alc_softc *); 207193880Syongaristatic void alc_tick(void *); 208193880Syongaristatic void alc_txeof(struct alc_softc *); 209193880Syongaristatic void alc_watchdog(struct alc_softc *); 210193880Syongaristatic int sysctl_int_range(SYSCTL_HANDLER_ARGS, int, int); 211193880Syongaristatic int sysctl_hw_alc_proc_limit(SYSCTL_HANDLER_ARGS); 212193880Syongaristatic int sysctl_hw_alc_int_mod(SYSCTL_HANDLER_ARGS); 213193880Syongari 214193880Syongaristatic device_method_t alc_methods[] = { 215193880Syongari /* Device interface. */ 216193880Syongari DEVMETHOD(device_probe, alc_probe), 217193880Syongari DEVMETHOD(device_attach, alc_attach), 218193880Syongari DEVMETHOD(device_detach, alc_detach), 219193880Syongari DEVMETHOD(device_shutdown, alc_shutdown), 220193880Syongari DEVMETHOD(device_suspend, alc_suspend), 221193880Syongari DEVMETHOD(device_resume, alc_resume), 222193880Syongari 223193880Syongari /* MII interface. */ 224193880Syongari DEVMETHOD(miibus_readreg, alc_miibus_readreg), 225193880Syongari DEVMETHOD(miibus_writereg, alc_miibus_writereg), 226193880Syongari DEVMETHOD(miibus_statchg, alc_miibus_statchg), 227193880Syongari 228193880Syongari { NULL, NULL } 229193880Syongari}; 230193880Syongari 231193880Syongaristatic driver_t alc_driver = { 232193880Syongari "alc", 233193880Syongari alc_methods, 234193880Syongari sizeof(struct alc_softc) 235193880Syongari}; 236193880Syongari 237193880Syongaristatic devclass_t alc_devclass; 238193880Syongari 239193880SyongariDRIVER_MODULE(alc, pci, alc_driver, alc_devclass, 0, 0); 240193880SyongariDRIVER_MODULE(miibus, alc, miibus_driver, miibus_devclass, 0, 0); 241193880Syongari 242193880Syongaristatic struct resource_spec alc_res_spec_mem[] = { 243193880Syongari { SYS_RES_MEMORY, PCIR_BAR(0), RF_ACTIVE }, 244193880Syongari { -1, 0, 0 } 245193880Syongari}; 246193880Syongari 247193880Syongaristatic struct resource_spec alc_irq_spec_legacy[] = { 248193880Syongari { SYS_RES_IRQ, 0, RF_ACTIVE | RF_SHAREABLE }, 249193880Syongari { -1, 0, 0 } 250193880Syongari}; 251193880Syongari 252193880Syongaristatic struct resource_spec alc_irq_spec_msi[] = { 253193880Syongari { SYS_RES_IRQ, 1, RF_ACTIVE }, 254193880Syongari { -1, 0, 0 } 255193880Syongari}; 256193880Syongari 257193880Syongaristatic struct resource_spec alc_irq_spec_msix[] = { 258193880Syongari { SYS_RES_IRQ, 1, RF_ACTIVE }, 259193880Syongari { -1, 0, 0 } 260193880Syongari}; 261193880Syongari 262312358Syongaristatic uint32_t alc_dma_burst[] = { 128, 256, 512, 1024, 2048, 4096, 0, 0 }; 263193880Syongari 264193880Syongaristatic int 265193880Syongarialc_miibus_readreg(device_t dev, int phy, int reg) 266193880Syongari{ 267193880Syongari struct alc_softc *sc; 268272730Syongari int v; 269272730Syongari 270272730Syongari sc = device_get_softc(dev); 271272730Syongari if ((sc->alc_flags & ALC_FLAG_AR816X_FAMILY) != 0) 272272730Syongari v = alc_mii_readreg_816x(sc, phy, reg); 273272730Syongari else 274272730Syongari v = alc_mii_readreg_813x(sc, phy, reg); 275272730Syongari return (v); 276272730Syongari} 277272730Syongari 278272730Syongaristatic uint32_t 279272730Syongarialc_mii_readreg_813x(struct alc_softc *sc, int phy, int reg) 280272730Syongari{ 281193880Syongari uint32_t v; 282193880Syongari int i; 283193880Syongari 284197600Syongari /* 285197600Syongari * For AR8132 fast ethernet controller, do not report 1000baseT 286197600Syongari * capability to mii(4). Even though AR8132 uses the same 287197600Syongari * model/revision number of F1 gigabit PHY, the PHY has no 288197600Syongari * ability to establish 1000baseT link. 289197600Syongari */ 290197600Syongari if ((sc->alc_flags & ALC_FLAG_FASTETHER) != 0 && 291197600Syongari reg == MII_EXTSR) 292197600Syongari return (0); 293197600Syongari 294193880Syongari CSR_WRITE_4(sc, ALC_MDIO, MDIO_OP_EXECUTE | MDIO_OP_READ | 295193880Syongari MDIO_SUP_PREAMBLE | MDIO_CLK_25_4 | MDIO_REG_ADDR(reg)); 296193880Syongari for (i = ALC_PHY_TIMEOUT; i > 0; i--) { 297193880Syongari DELAY(5); 298193880Syongari v = CSR_READ_4(sc, ALC_MDIO); 299193880Syongari if ((v & (MDIO_OP_EXECUTE | MDIO_OP_BUSY)) == 0) 300193880Syongari break; 301193880Syongari } 302193880Syongari 303193880Syongari if (i == 0) { 304193880Syongari device_printf(sc->alc_dev, "phy read timeout : %d\n", reg); 305193880Syongari return (0); 306193880Syongari } 307193880Syongari 308193880Syongari return ((v & MDIO_DATA_MASK) >> MDIO_DATA_SHIFT); 309193880Syongari} 310193880Syongari 311272730Syongaristatic uint32_t 312272730Syongarialc_mii_readreg_816x(struct alc_softc *sc, int phy, int reg) 313272730Syongari{ 314272730Syongari uint32_t clk, v; 315272730Syongari int i; 316272730Syongari 317272730Syongari if ((sc->alc_flags & ALC_FLAG_LINK) != 0) 318272730Syongari clk = MDIO_CLK_25_128; 319272730Syongari else 320272730Syongari clk = MDIO_CLK_25_4; 321272730Syongari CSR_WRITE_4(sc, ALC_MDIO, MDIO_OP_EXECUTE | MDIO_OP_READ | 322272730Syongari MDIO_SUP_PREAMBLE | clk | MDIO_REG_ADDR(reg)); 323272730Syongari for (i = ALC_PHY_TIMEOUT; i > 0; i--) { 324272730Syongari DELAY(5); 325272730Syongari v = CSR_READ_4(sc, ALC_MDIO); 326272730Syongari if ((v & MDIO_OP_BUSY) == 0) 327272730Syongari break; 328272730Syongari } 329272730Syongari 330272730Syongari if (i == 0) { 331272730Syongari device_printf(sc->alc_dev, "phy read timeout : %d\n", reg); 332272730Syongari return (0); 333272730Syongari } 334272730Syongari 335272730Syongari return ((v & MDIO_DATA_MASK) >> MDIO_DATA_SHIFT); 336272730Syongari} 337272730Syongari 338193880Syongaristatic int 339193880Syongarialc_miibus_writereg(device_t dev, int phy, int reg, int val) 340193880Syongari{ 341193880Syongari struct alc_softc *sc; 342272730Syongari int v; 343272730Syongari 344272730Syongari sc = device_get_softc(dev); 345272730Syongari if ((sc->alc_flags & ALC_FLAG_AR816X_FAMILY) != 0) 346272730Syongari v = alc_mii_writereg_816x(sc, phy, reg, val); 347272730Syongari else 348272730Syongari v = alc_mii_writereg_813x(sc, phy, reg, val); 349272730Syongari return (v); 350272730Syongari} 351272730Syongari 352272730Syongaristatic uint32_t 353272730Syongarialc_mii_writereg_813x(struct alc_softc *sc, int phy, int reg, int val) 354272730Syongari{ 355193880Syongari uint32_t v; 356193880Syongari int i; 357193880Syongari 358193880Syongari CSR_WRITE_4(sc, ALC_MDIO, MDIO_OP_EXECUTE | MDIO_OP_WRITE | 359193880Syongari (val & MDIO_DATA_MASK) << MDIO_DATA_SHIFT | 360193880Syongari MDIO_SUP_PREAMBLE | MDIO_CLK_25_4 | MDIO_REG_ADDR(reg)); 361193880Syongari for (i = ALC_PHY_TIMEOUT; i > 0; i--) { 362193880Syongari DELAY(5); 363193880Syongari v = CSR_READ_4(sc, ALC_MDIO); 364193880Syongari if ((v & (MDIO_OP_EXECUTE | MDIO_OP_BUSY)) == 0) 365193880Syongari break; 366193880Syongari } 367193880Syongari 368193880Syongari if (i == 0) 369193880Syongari device_printf(sc->alc_dev, "phy write timeout : %d\n", reg); 370193880Syongari 371193880Syongari return (0); 372193880Syongari} 373193880Syongari 374272730Syongaristatic uint32_t 375272730Syongarialc_mii_writereg_816x(struct alc_softc *sc, int phy, int reg, int val) 376272730Syongari{ 377272730Syongari uint32_t clk, v; 378272730Syongari int i; 379272730Syongari 380272730Syongari if ((sc->alc_flags & ALC_FLAG_LINK) != 0) 381272730Syongari clk = MDIO_CLK_25_128; 382272730Syongari else 383272730Syongari clk = MDIO_CLK_25_4; 384272730Syongari CSR_WRITE_4(sc, ALC_MDIO, MDIO_OP_EXECUTE | MDIO_OP_WRITE | 385272730Syongari ((val & MDIO_DATA_MASK) << MDIO_DATA_SHIFT) | MDIO_REG_ADDR(reg) | 386272730Syongari MDIO_SUP_PREAMBLE | clk); 387272730Syongari for (i = ALC_PHY_TIMEOUT; i > 0; i--) { 388272730Syongari DELAY(5); 389272730Syongari v = CSR_READ_4(sc, ALC_MDIO); 390272730Syongari if ((v & MDIO_OP_BUSY) == 0) 391272730Syongari break; 392272730Syongari } 393272730Syongari 394272730Syongari if (i == 0) 395272730Syongari device_printf(sc->alc_dev, "phy write timeout : %d\n", reg); 396272730Syongari 397272730Syongari return (0); 398272730Syongari} 399272730Syongari 400193880Syongaristatic void 401193880Syongarialc_miibus_statchg(device_t dev) 402193880Syongari{ 403193880Syongari struct alc_softc *sc; 404193880Syongari struct mii_data *mii; 405193880Syongari struct ifnet *ifp; 406193880Syongari uint32_t reg; 407193880Syongari 408193880Syongari sc = device_get_softc(dev); 409193880Syongari 410193880Syongari mii = device_get_softc(sc->alc_miibus); 411193880Syongari ifp = sc->alc_ifp; 412193880Syongari if (mii == NULL || ifp == NULL || 413193880Syongari (ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) 414193880Syongari return; 415193880Syongari 416193880Syongari sc->alc_flags &= ~ALC_FLAG_LINK; 417193880Syongari if ((mii->mii_media_status & (IFM_ACTIVE | IFM_AVALID)) == 418193880Syongari (IFM_ACTIVE | IFM_AVALID)) { 419193880Syongari switch (IFM_SUBTYPE(mii->mii_media_active)) { 420193880Syongari case IFM_10_T: 421193880Syongari case IFM_100_TX: 422193880Syongari sc->alc_flags |= ALC_FLAG_LINK; 423193880Syongari break; 424193880Syongari case IFM_1000_T: 425193880Syongari if ((sc->alc_flags & ALC_FLAG_FASTETHER) == 0) 426193880Syongari sc->alc_flags |= ALC_FLAG_LINK; 427193880Syongari break; 428193880Syongari default: 429193880Syongari break; 430193880Syongari } 431193880Syongari } 432193880Syongari /* Stop Rx/Tx MACs. */ 433193880Syongari alc_stop_mac(sc); 434193880Syongari 435193880Syongari /* Program MACs with resolved speed/duplex/flow-control. */ 436193880Syongari if ((sc->alc_flags & ALC_FLAG_LINK) != 0) { 437193880Syongari alc_start_queue(sc); 438193880Syongari alc_mac_config(sc); 439193880Syongari /* Re-enable Tx/Rx MACs. */ 440193880Syongari reg = CSR_READ_4(sc, ALC_MAC_CFG); 441193880Syongari reg |= MAC_CFG_TX_ENB | MAC_CFG_RX_ENB; 442193880Syongari CSR_WRITE_4(sc, ALC_MAC_CFG, reg); 443193880Syongari } 444272730Syongari alc_aspm(sc, 0, IFM_SUBTYPE(mii->mii_media_active)); 445272730Syongari alc_dsp_fixup(sc, IFM_SUBTYPE(mii->mii_media_active)); 446193880Syongari} 447193880Syongari 448272730Syongaristatic uint32_t 449272730Syongarialc_miidbg_readreg(struct alc_softc *sc, int reg) 450272730Syongari{ 451272730Syongari 452272730Syongari alc_miibus_writereg(sc->alc_dev, sc->alc_phyaddr, ALC_MII_DBG_ADDR, 453272730Syongari reg); 454272730Syongari return (alc_miibus_readreg(sc->alc_dev, sc->alc_phyaddr, 455272730Syongari ALC_MII_DBG_DATA)); 456272730Syongari} 457272730Syongari 458272730Syongaristatic uint32_t 459272730Syongarialc_miidbg_writereg(struct alc_softc *sc, int reg, int val) 460272730Syongari{ 461272730Syongari 462272730Syongari alc_miibus_writereg(sc->alc_dev, sc->alc_phyaddr, ALC_MII_DBG_ADDR, 463272730Syongari reg); 464272730Syongari return (alc_miibus_writereg(sc->alc_dev, sc->alc_phyaddr, 465272730Syongari ALC_MII_DBG_DATA, val)); 466272730Syongari} 467272730Syongari 468272730Syongaristatic uint32_t 469272730Syongarialc_miiext_readreg(struct alc_softc *sc, int devaddr, int reg) 470272730Syongari{ 471272730Syongari uint32_t clk, v; 472272730Syongari int i; 473272730Syongari 474272730Syongari CSR_WRITE_4(sc, ALC_EXT_MDIO, EXT_MDIO_REG(reg) | 475272730Syongari EXT_MDIO_DEVADDR(devaddr)); 476272730Syongari if ((sc->alc_flags & ALC_FLAG_LINK) != 0) 477272730Syongari clk = MDIO_CLK_25_128; 478272730Syongari else 479272730Syongari clk = MDIO_CLK_25_4; 480272730Syongari CSR_WRITE_4(sc, ALC_MDIO, MDIO_OP_EXECUTE | MDIO_OP_READ | 481272730Syongari MDIO_SUP_PREAMBLE | clk | MDIO_MODE_EXT); 482272730Syongari for (i = ALC_PHY_TIMEOUT; i > 0; i--) { 483272730Syongari DELAY(5); 484272730Syongari v = CSR_READ_4(sc, ALC_MDIO); 485272730Syongari if ((v & MDIO_OP_BUSY) == 0) 486272730Syongari break; 487272730Syongari } 488272730Syongari 489272730Syongari if (i == 0) { 490272730Syongari device_printf(sc->alc_dev, "phy ext read timeout : %d, %d\n", 491272730Syongari devaddr, reg); 492272730Syongari return (0); 493272730Syongari } 494272730Syongari 495272730Syongari return ((v & MDIO_DATA_MASK) >> MDIO_DATA_SHIFT); 496272730Syongari} 497272730Syongari 498272730Syongaristatic uint32_t 499272730Syongarialc_miiext_writereg(struct alc_softc *sc, int devaddr, int reg, int val) 500272730Syongari{ 501272730Syongari uint32_t clk, v; 502272730Syongari int i; 503272730Syongari 504272730Syongari CSR_WRITE_4(sc, ALC_EXT_MDIO, EXT_MDIO_REG(reg) | 505272730Syongari EXT_MDIO_DEVADDR(devaddr)); 506272730Syongari if ((sc->alc_flags & ALC_FLAG_LINK) != 0) 507272730Syongari clk = MDIO_CLK_25_128; 508272730Syongari else 509272730Syongari clk = MDIO_CLK_25_4; 510272730Syongari CSR_WRITE_4(sc, ALC_MDIO, MDIO_OP_EXECUTE | MDIO_OP_WRITE | 511272730Syongari ((val & MDIO_DATA_MASK) << MDIO_DATA_SHIFT) | 512272730Syongari MDIO_SUP_PREAMBLE | clk | MDIO_MODE_EXT); 513272730Syongari for (i = ALC_PHY_TIMEOUT; i > 0; i--) { 514272730Syongari DELAY(5); 515272730Syongari v = CSR_READ_4(sc, ALC_MDIO); 516272730Syongari if ((v & MDIO_OP_BUSY) == 0) 517272730Syongari break; 518272730Syongari } 519272730Syongari 520272730Syongari if (i == 0) 521272730Syongari device_printf(sc->alc_dev, "phy ext write timeout : %d, %d\n", 522272730Syongari devaddr, reg); 523272730Syongari 524272730Syongari return (0); 525272730Syongari} 526272730Syongari 527193880Syongaristatic void 528272730Syongarialc_dsp_fixup(struct alc_softc *sc, int media) 529272730Syongari{ 530272730Syongari uint16_t agc, len, val; 531272730Syongari 532272730Syongari if ((sc->alc_flags & ALC_FLAG_AR816X_FAMILY) != 0) 533272730Syongari return; 534272730Syongari if (AR816X_REV(sc->alc_rev) >= AR816X_REV_C0) 535272730Syongari return; 536272730Syongari 537272730Syongari /* 538272730Syongari * Vendor PHY magic. 539272730Syongari * 1000BT/AZ, wrong cable length 540272730Syongari */ 541272730Syongari if ((sc->alc_flags & ALC_FLAG_LINK) != 0) { 542272730Syongari len = alc_miiext_readreg(sc, MII_EXT_PCS, MII_EXT_CLDCTL6); 543272730Syongari len = (len >> EXT_CLDCTL6_CAB_LEN_SHIFT) & 544272730Syongari EXT_CLDCTL6_CAB_LEN_MASK; 545272730Syongari agc = alc_miidbg_readreg(sc, MII_DBG_AGC); 546272730Syongari agc = (agc >> DBG_AGC_2_VGA_SHIFT) & DBG_AGC_2_VGA_MASK; 547272730Syongari if ((media == IFM_1000_T && len > EXT_CLDCTL6_CAB_LEN_SHORT1G && 548272730Syongari agc > DBG_AGC_LONG1G_LIMT) || 549272730Syongari (media == IFM_100_TX && len > DBG_AGC_LONG100M_LIMT && 550272730Syongari agc > DBG_AGC_LONG1G_LIMT)) { 551272730Syongari alc_miidbg_writereg(sc, MII_DBG_AZ_ANADECT, 552272730Syongari DBG_AZ_ANADECT_LONG); 553272730Syongari val = alc_miiext_readreg(sc, MII_EXT_ANEG, 554272730Syongari MII_EXT_ANEG_AFE); 555272730Syongari val |= ANEG_AFEE_10BT_100M_TH; 556272730Syongari alc_miiext_writereg(sc, MII_EXT_ANEG, MII_EXT_ANEG_AFE, 557272730Syongari val); 558272730Syongari } else { 559272730Syongari alc_miidbg_writereg(sc, MII_DBG_AZ_ANADECT, 560272730Syongari DBG_AZ_ANADECT_DEFAULT); 561272730Syongari val = alc_miiext_readreg(sc, MII_EXT_ANEG, 562272730Syongari MII_EXT_ANEG_AFE); 563272730Syongari val &= ~ANEG_AFEE_10BT_100M_TH; 564272730Syongari alc_miiext_writereg(sc, MII_EXT_ANEG, MII_EXT_ANEG_AFE, 565272730Syongari val); 566272730Syongari } 567272730Syongari if ((sc->alc_flags & ALC_FLAG_LINK_WAR) != 0 && 568272730Syongari AR816X_REV(sc->alc_rev) == AR816X_REV_B0) { 569272730Syongari if (media == IFM_1000_T) { 570272730Syongari /* 571272730Syongari * Giga link threshold, raise the tolerance of 572272730Syongari * noise 50%. 573272730Syongari */ 574272730Syongari val = alc_miidbg_readreg(sc, MII_DBG_MSE20DB); 575272730Syongari val &= ~DBG_MSE20DB_TH_MASK; 576272730Syongari val |= (DBG_MSE20DB_TH_HI << 577272730Syongari DBG_MSE20DB_TH_SHIFT); 578272730Syongari alc_miidbg_writereg(sc, MII_DBG_MSE20DB, val); 579272730Syongari } else if (media == IFM_100_TX) 580272730Syongari alc_miidbg_writereg(sc, MII_DBG_MSE16DB, 581272730Syongari DBG_MSE16DB_UP); 582272730Syongari } 583272730Syongari } else { 584272730Syongari val = alc_miiext_readreg(sc, MII_EXT_ANEG, MII_EXT_ANEG_AFE); 585272730Syongari val &= ~ANEG_AFEE_10BT_100M_TH; 586272730Syongari alc_miiext_writereg(sc, MII_EXT_ANEG, MII_EXT_ANEG_AFE, val); 587272730Syongari if ((sc->alc_flags & ALC_FLAG_LINK_WAR) != 0 && 588272730Syongari AR816X_REV(sc->alc_rev) == AR816X_REV_B0) { 589272730Syongari alc_miidbg_writereg(sc, MII_DBG_MSE16DB, 590272730Syongari DBG_MSE16DB_DOWN); 591272730Syongari val = alc_miidbg_readreg(sc, MII_DBG_MSE20DB); 592272730Syongari val &= ~DBG_MSE20DB_TH_MASK; 593272730Syongari val |= (DBG_MSE20DB_TH_DEFAULT << DBG_MSE20DB_TH_SHIFT); 594272730Syongari alc_miidbg_writereg(sc, MII_DBG_MSE20DB, val); 595272730Syongari } 596272730Syongari } 597272730Syongari} 598272730Syongari 599272730Syongaristatic void 600193880Syongarialc_mediastatus(struct ifnet *ifp, struct ifmediareq *ifmr) 601193880Syongari{ 602193880Syongari struct alc_softc *sc; 603193880Syongari struct mii_data *mii; 604193880Syongari 605193880Syongari sc = ifp->if_softc; 606193880Syongari ALC_LOCK(sc); 607193880Syongari if ((ifp->if_flags & IFF_UP) == 0) { 608193880Syongari ALC_UNLOCK(sc); 609193880Syongari return; 610193880Syongari } 611193880Syongari mii = device_get_softc(sc->alc_miibus); 612193880Syongari 613193880Syongari mii_pollstat(mii); 614193880Syongari ifmr->ifm_status = mii->mii_media_status; 615193880Syongari ifmr->ifm_active = mii->mii_media_active; 616226478Syongari ALC_UNLOCK(sc); 617193880Syongari} 618193880Syongari 619193880Syongaristatic int 620193880Syongarialc_mediachange(struct ifnet *ifp) 621193880Syongari{ 622193880Syongari struct alc_softc *sc; 623272730Syongari int error; 624272730Syongari 625272730Syongari sc = ifp->if_softc; 626272730Syongari ALC_LOCK(sc); 627272730Syongari error = alc_mediachange_locked(sc); 628272730Syongari ALC_UNLOCK(sc); 629272730Syongari 630272730Syongari return (error); 631272730Syongari} 632272730Syongari 633272730Syongaristatic int 634272730Syongarialc_mediachange_locked(struct alc_softc *sc) 635272730Syongari{ 636193880Syongari struct mii_data *mii; 637193880Syongari struct mii_softc *miisc; 638193880Syongari int error; 639193880Syongari 640272730Syongari ALC_LOCK_ASSERT(sc); 641272730Syongari 642193880Syongari mii = device_get_softc(sc->alc_miibus); 643221407Smarius LIST_FOREACH(miisc, &mii->mii_phys, mii_list) 644221407Smarius PHY_RESET(miisc); 645193880Syongari error = mii_mediachg(mii); 646193880Syongari 647193880Syongari return (error); 648193880Syongari} 649193880Syongari 650211105Syongaristatic struct alc_ident * 651211105Syongarialc_find_ident(device_t dev) 652193880Syongari{ 653211105Syongari struct alc_ident *ident; 654193880Syongari uint16_t vendor, devid; 655193880Syongari 656193880Syongari vendor = pci_get_vendor(dev); 657193880Syongari devid = pci_get_device(dev); 658211105Syongari for (ident = alc_ident_table; ident->name != NULL; ident++) { 659211105Syongari if (vendor == ident->vendorid && devid == ident->deviceid) 660211105Syongari return (ident); 661193880Syongari } 662193880Syongari 663211105Syongari return (NULL); 664211105Syongari} 665211105Syongari 666211105Syongaristatic int 667211105Syongarialc_probe(device_t dev) 668211105Syongari{ 669211105Syongari struct alc_ident *ident; 670211105Syongari 671211105Syongari ident = alc_find_ident(dev); 672211105Syongari if (ident != NULL) { 673211105Syongari device_set_desc(dev, ident->name); 674211105Syongari return (BUS_PROBE_DEFAULT); 675211105Syongari } 676211105Syongari 677193880Syongari return (ENXIO); 678193880Syongari} 679193880Syongari 680193880Syongaristatic void 681193880Syongarialc_get_macaddr(struct alc_softc *sc) 682193880Syongari{ 683272730Syongari 684272730Syongari if ((sc->alc_flags & ALC_FLAG_AR816X_FAMILY) != 0) 685272730Syongari alc_get_macaddr_816x(sc); 686272730Syongari else 687272730Syongari alc_get_macaddr_813x(sc); 688272730Syongari} 689272730Syongari 690272730Syongaristatic void 691272730Syongarialc_get_macaddr_813x(struct alc_softc *sc) 692272730Syongari{ 693272730Syongari uint32_t opt; 694211105Syongari uint16_t val; 695211105Syongari int eeprom, i; 696193880Syongari 697211105Syongari eeprom = 0; 698193880Syongari opt = CSR_READ_4(sc, ALC_OPT_CFG); 699211105Syongari if ((CSR_READ_4(sc, ALC_MASTER_CFG) & MASTER_OTP_SEL) != 0 && 700211105Syongari (CSR_READ_4(sc, ALC_TWSI_DEBUG) & TWSI_DEBUG_DEV_EXIST) != 0) { 701193880Syongari /* 702193880Syongari * EEPROM found, let TWSI reload EEPROM configuration. 703193880Syongari * This will set ethernet address of controller. 704193880Syongari */ 705211105Syongari eeprom++; 706211105Syongari switch (sc->alc_ident->deviceid) { 707211105Syongari case DEVICEID_ATHEROS_AR8131: 708211105Syongari case DEVICEID_ATHEROS_AR8132: 709211105Syongari if ((opt & OPT_CFG_CLK_ENB) == 0) { 710211105Syongari opt |= OPT_CFG_CLK_ENB; 711211105Syongari CSR_WRITE_4(sc, ALC_OPT_CFG, opt); 712211105Syongari CSR_READ_4(sc, ALC_OPT_CFG); 713211105Syongari DELAY(1000); 714211105Syongari } 715211105Syongari break; 716211105Syongari case DEVICEID_ATHEROS_AR8151: 717211105Syongari case DEVICEID_ATHEROS_AR8151_V2: 718211105Syongari case DEVICEID_ATHEROS_AR8152_B: 719211105Syongari case DEVICEID_ATHEROS_AR8152_B2: 720211105Syongari alc_miibus_writereg(sc->alc_dev, sc->alc_phyaddr, 721211105Syongari ALC_MII_DBG_ADDR, 0x00); 722211105Syongari val = alc_miibus_readreg(sc->alc_dev, sc->alc_phyaddr, 723211105Syongari ALC_MII_DBG_DATA); 724211105Syongari alc_miibus_writereg(sc->alc_dev, sc->alc_phyaddr, 725211105Syongari ALC_MII_DBG_DATA, val & 0xFF7F); 726211105Syongari alc_miibus_writereg(sc->alc_dev, sc->alc_phyaddr, 727211105Syongari ALC_MII_DBG_ADDR, 0x3B); 728211105Syongari val = alc_miibus_readreg(sc->alc_dev, sc->alc_phyaddr, 729211105Syongari ALC_MII_DBG_DATA); 730211105Syongari alc_miibus_writereg(sc->alc_dev, sc->alc_phyaddr, 731211105Syongari ALC_MII_DBG_DATA, val | 0x0008); 732211105Syongari DELAY(20); 733211105Syongari break; 734193880Syongari } 735211105Syongari 736211105Syongari CSR_WRITE_4(sc, ALC_LTSSM_ID_CFG, 737211105Syongari CSR_READ_4(sc, ALC_LTSSM_ID_CFG) & ~LTSSM_ID_WRO_ENB); 738211105Syongari CSR_WRITE_4(sc, ALC_WOL_CFG, 0); 739211105Syongari CSR_READ_4(sc, ALC_WOL_CFG); 740211105Syongari 741193880Syongari CSR_WRITE_4(sc, ALC_TWSI_CFG, CSR_READ_4(sc, ALC_TWSI_CFG) | 742193880Syongari TWSI_CFG_SW_LD_START); 743193880Syongari for (i = 100; i > 0; i--) { 744193880Syongari DELAY(1000); 745193880Syongari if ((CSR_READ_4(sc, ALC_TWSI_CFG) & 746193880Syongari TWSI_CFG_SW_LD_START) == 0) 747193880Syongari break; 748193880Syongari } 749193880Syongari if (i == 0) 750193880Syongari device_printf(sc->alc_dev, 751193880Syongari "reloading EEPROM timeout!\n"); 752193880Syongari } else { 753193880Syongari if (bootverbose) 754193880Syongari device_printf(sc->alc_dev, "EEPROM not found!\n"); 755193880Syongari } 756211105Syongari if (eeprom != 0) { 757211105Syongari switch (sc->alc_ident->deviceid) { 758211105Syongari case DEVICEID_ATHEROS_AR8131: 759211105Syongari case DEVICEID_ATHEROS_AR8132: 760211105Syongari if ((opt & OPT_CFG_CLK_ENB) != 0) { 761211105Syongari opt &= ~OPT_CFG_CLK_ENB; 762211105Syongari CSR_WRITE_4(sc, ALC_OPT_CFG, opt); 763211105Syongari CSR_READ_4(sc, ALC_OPT_CFG); 764211105Syongari DELAY(1000); 765211105Syongari } 766211105Syongari break; 767211105Syongari case DEVICEID_ATHEROS_AR8151: 768211105Syongari case DEVICEID_ATHEROS_AR8151_V2: 769211105Syongari case DEVICEID_ATHEROS_AR8152_B: 770211105Syongari case DEVICEID_ATHEROS_AR8152_B2: 771211105Syongari alc_miibus_writereg(sc->alc_dev, sc->alc_phyaddr, 772211105Syongari ALC_MII_DBG_ADDR, 0x00); 773211105Syongari val = alc_miibus_readreg(sc->alc_dev, sc->alc_phyaddr, 774211105Syongari ALC_MII_DBG_DATA); 775211105Syongari alc_miibus_writereg(sc->alc_dev, sc->alc_phyaddr, 776211105Syongari ALC_MII_DBG_DATA, val | 0x0080); 777211105Syongari alc_miibus_writereg(sc->alc_dev, sc->alc_phyaddr, 778211105Syongari ALC_MII_DBG_ADDR, 0x3B); 779211105Syongari val = alc_miibus_readreg(sc->alc_dev, sc->alc_phyaddr, 780211105Syongari ALC_MII_DBG_DATA); 781211105Syongari alc_miibus_writereg(sc->alc_dev, sc->alc_phyaddr, 782211105Syongari ALC_MII_DBG_DATA, val & 0xFFF7); 783211105Syongari DELAY(20); 784211105Syongari break; 785211105Syongari } 786193880Syongari } 787193880Syongari 788272730Syongari alc_get_macaddr_par(sc); 789272730Syongari} 790272730Syongari 791272730Syongaristatic void 792272730Syongarialc_get_macaddr_816x(struct alc_softc *sc) 793272730Syongari{ 794272730Syongari uint32_t reg; 795272730Syongari int i, reloaded; 796272730Syongari 797272730Syongari reloaded = 0; 798272730Syongari /* Try to reload station address via TWSI. */ 799272730Syongari for (i = 100; i > 0; i--) { 800272730Syongari reg = CSR_READ_4(sc, ALC_SLD); 801272730Syongari if ((reg & (SLD_PROGRESS | SLD_START)) == 0) 802272730Syongari break; 803272730Syongari DELAY(1000); 804272730Syongari } 805272730Syongari if (i != 0) { 806272730Syongari CSR_WRITE_4(sc, ALC_SLD, reg | SLD_START); 807272730Syongari for (i = 100; i > 0; i--) { 808272730Syongari DELAY(1000); 809272730Syongari reg = CSR_READ_4(sc, ALC_SLD); 810272730Syongari if ((reg & SLD_START) == 0) 811272730Syongari break; 812272730Syongari } 813272730Syongari if (i != 0) 814272730Syongari reloaded++; 815272730Syongari else if (bootverbose) 816272730Syongari device_printf(sc->alc_dev, 817272730Syongari "reloading station address via TWSI timed out!\n"); 818272730Syongari } 819272730Syongari 820272730Syongari /* Try to reload station address from EEPROM or FLASH. */ 821272730Syongari if (reloaded == 0) { 822272730Syongari reg = CSR_READ_4(sc, ALC_EEPROM_LD); 823272730Syongari if ((reg & (EEPROM_LD_EEPROM_EXIST | 824272730Syongari EEPROM_LD_FLASH_EXIST)) != 0) { 825272730Syongari for (i = 100; i > 0; i--) { 826272730Syongari reg = CSR_READ_4(sc, ALC_EEPROM_LD); 827272730Syongari if ((reg & (EEPROM_LD_PROGRESS | 828272730Syongari EEPROM_LD_START)) == 0) 829272730Syongari break; 830272730Syongari DELAY(1000); 831272730Syongari } 832272730Syongari if (i != 0) { 833272730Syongari CSR_WRITE_4(sc, ALC_EEPROM_LD, reg | 834272730Syongari EEPROM_LD_START); 835272730Syongari for (i = 100; i > 0; i--) { 836272730Syongari DELAY(1000); 837272730Syongari reg = CSR_READ_4(sc, ALC_EEPROM_LD); 838272730Syongari if ((reg & EEPROM_LD_START) == 0) 839272730Syongari break; 840272730Syongari } 841272730Syongari } else if (bootverbose) 842272730Syongari device_printf(sc->alc_dev, 843272730Syongari "reloading EEPROM/FLASH timed out!\n"); 844272730Syongari } 845272730Syongari } 846272730Syongari 847272730Syongari alc_get_macaddr_par(sc); 848272730Syongari} 849272730Syongari 850272730Syongaristatic void 851272730Syongarialc_get_macaddr_par(struct alc_softc *sc) 852272730Syongari{ 853272730Syongari uint32_t ea[2]; 854272730Syongari 855193880Syongari ea[0] = CSR_READ_4(sc, ALC_PAR0); 856193880Syongari ea[1] = CSR_READ_4(sc, ALC_PAR1); 857193880Syongari sc->alc_eaddr[0] = (ea[1] >> 8) & 0xFF; 858193880Syongari sc->alc_eaddr[1] = (ea[1] >> 0) & 0xFF; 859193880Syongari sc->alc_eaddr[2] = (ea[0] >> 24) & 0xFF; 860193880Syongari sc->alc_eaddr[3] = (ea[0] >> 16) & 0xFF; 861193880Syongari sc->alc_eaddr[4] = (ea[0] >> 8) & 0xFF; 862193880Syongari sc->alc_eaddr[5] = (ea[0] >> 0) & 0xFF; 863193880Syongari} 864193880Syongari 865193880Syongaristatic void 866193880Syongarialc_disable_l0s_l1(struct alc_softc *sc) 867193880Syongari{ 868193880Syongari uint32_t pmcfg; 869193880Syongari 870272730Syongari if ((sc->alc_flags & ALC_FLAG_AR816X_FAMILY) == 0) { 871272730Syongari /* Another magic from vendor. */ 872272730Syongari pmcfg = CSR_READ_4(sc, ALC_PM_CFG); 873272730Syongari pmcfg &= ~(PM_CFG_L1_ENTRY_TIMER_MASK | PM_CFG_CLK_SWH_L1 | 874272730Syongari PM_CFG_ASPM_L0S_ENB | PM_CFG_ASPM_L1_ENB | 875272730Syongari PM_CFG_MAC_ASPM_CHK | PM_CFG_SERDES_PD_EX_L1); 876272730Syongari pmcfg |= PM_CFG_SERDES_BUDS_RX_L1_ENB | 877272730Syongari PM_CFG_SERDES_PLL_L1_ENB | PM_CFG_SERDES_L1_ENB; 878272730Syongari CSR_WRITE_4(sc, ALC_PM_CFG, pmcfg); 879272730Syongari } 880193880Syongari} 881193880Syongari 882193880Syongaristatic void 883193880Syongarialc_phy_reset(struct alc_softc *sc) 884193880Syongari{ 885272730Syongari 886272730Syongari if ((sc->alc_flags & ALC_FLAG_AR816X_FAMILY) != 0) 887272730Syongari alc_phy_reset_816x(sc); 888272730Syongari else 889272730Syongari alc_phy_reset_813x(sc); 890272730Syongari} 891272730Syongari 892272730Syongaristatic void 893272730Syongarialc_phy_reset_813x(struct alc_softc *sc) 894272730Syongari{ 895193880Syongari uint16_t data; 896193880Syongari 897193880Syongari /* Reset magic from Linux. */ 898225088Syongari CSR_WRITE_2(sc, ALC_GPHY_CFG, GPHY_CFG_SEL_ANA_RESET); 899193880Syongari CSR_READ_2(sc, ALC_GPHY_CFG); 900193880Syongari DELAY(10 * 1000); 901193880Syongari 902225088Syongari CSR_WRITE_2(sc, ALC_GPHY_CFG, GPHY_CFG_EXT_RESET | 903193880Syongari GPHY_CFG_SEL_ANA_RESET); 904193880Syongari CSR_READ_2(sc, ALC_GPHY_CFG); 905193880Syongari DELAY(10 * 1000); 906193880Syongari 907211105Syongari /* DSP fixup, Vendor magic. */ 908211105Syongari if (sc->alc_ident->deviceid == DEVICEID_ATHEROS_AR8152_B) { 909211105Syongari alc_miibus_writereg(sc->alc_dev, sc->alc_phyaddr, 910211105Syongari ALC_MII_DBG_ADDR, 0x000A); 911211105Syongari data = alc_miibus_readreg(sc->alc_dev, sc->alc_phyaddr, 912211105Syongari ALC_MII_DBG_DATA); 913211105Syongari alc_miibus_writereg(sc->alc_dev, sc->alc_phyaddr, 914211105Syongari ALC_MII_DBG_DATA, data & 0xDFFF); 915211105Syongari } 916211105Syongari if (sc->alc_ident->deviceid == DEVICEID_ATHEROS_AR8151 || 917211105Syongari sc->alc_ident->deviceid == DEVICEID_ATHEROS_AR8151_V2 || 918211105Syongari sc->alc_ident->deviceid == DEVICEID_ATHEROS_AR8152_B || 919211105Syongari sc->alc_ident->deviceid == DEVICEID_ATHEROS_AR8152_B2) { 920211105Syongari alc_miibus_writereg(sc->alc_dev, sc->alc_phyaddr, 921211105Syongari ALC_MII_DBG_ADDR, 0x003B); 922211105Syongari data = alc_miibus_readreg(sc->alc_dev, sc->alc_phyaddr, 923211105Syongari ALC_MII_DBG_DATA); 924211105Syongari alc_miibus_writereg(sc->alc_dev, sc->alc_phyaddr, 925211105Syongari ALC_MII_DBG_DATA, data & 0xFFF7); 926211105Syongari DELAY(20 * 1000); 927211105Syongari } 928211105Syongari if (sc->alc_ident->deviceid == DEVICEID_ATHEROS_AR8151) { 929211105Syongari alc_miibus_writereg(sc->alc_dev, sc->alc_phyaddr, 930211105Syongari ALC_MII_DBG_ADDR, 0x0029); 931211105Syongari alc_miibus_writereg(sc->alc_dev, sc->alc_phyaddr, 932211105Syongari ALC_MII_DBG_DATA, 0x929D); 933211105Syongari } 934211105Syongari if (sc->alc_ident->deviceid == DEVICEID_ATHEROS_AR8131 || 935211105Syongari sc->alc_ident->deviceid == DEVICEID_ATHEROS_AR8132 || 936211105Syongari sc->alc_ident->deviceid == DEVICEID_ATHEROS_AR8151_V2 || 937211105Syongari sc->alc_ident->deviceid == DEVICEID_ATHEROS_AR8152_B2) { 938211105Syongari alc_miibus_writereg(sc->alc_dev, sc->alc_phyaddr, 939211105Syongari ALC_MII_DBG_ADDR, 0x0029); 940211105Syongari alc_miibus_writereg(sc->alc_dev, sc->alc_phyaddr, 941211105Syongari ALC_MII_DBG_DATA, 0xB6DD); 942211105Syongari } 943211105Syongari 944193880Syongari /* Load DSP codes, vendor magic. */ 945193880Syongari data = ANA_LOOP_SEL_10BT | ANA_EN_MASK_TB | ANA_EN_10BT_IDLE | 946193880Syongari ((1 << ANA_INTERVAL_SEL_TIMER_SHIFT) & ANA_INTERVAL_SEL_TIMER_MASK); 947193880Syongari alc_miibus_writereg(sc->alc_dev, sc->alc_phyaddr, 948193880Syongari ALC_MII_DBG_ADDR, MII_ANA_CFG18); 949193880Syongari alc_miibus_writereg(sc->alc_dev, sc->alc_phyaddr, 950193880Syongari ALC_MII_DBG_DATA, data); 951193880Syongari 952193880Syongari data = ((2 << ANA_SERDES_CDR_BW_SHIFT) & ANA_SERDES_CDR_BW_MASK) | 953193880Syongari ANA_SERDES_EN_DEEM | ANA_SERDES_SEL_HSP | ANA_SERDES_EN_PLL | 954193880Syongari ANA_SERDES_EN_LCKDT; 955193880Syongari alc_miibus_writereg(sc->alc_dev, sc->alc_phyaddr, 956193880Syongari ALC_MII_DBG_ADDR, MII_ANA_CFG5); 957193880Syongari alc_miibus_writereg(sc->alc_dev, sc->alc_phyaddr, 958193880Syongari ALC_MII_DBG_DATA, data); 959193880Syongari 960193880Syongari data = ((44 << ANA_LONG_CABLE_TH_100_SHIFT) & 961193880Syongari ANA_LONG_CABLE_TH_100_MASK) | 962193880Syongari ((33 << ANA_SHORT_CABLE_TH_100_SHIFT) & 963193880Syongari ANA_SHORT_CABLE_TH_100_SHIFT) | 964193880Syongari ANA_BP_BAD_LINK_ACCUM | ANA_BP_SMALL_BW; 965193880Syongari alc_miibus_writereg(sc->alc_dev, sc->alc_phyaddr, 966193880Syongari ALC_MII_DBG_ADDR, MII_ANA_CFG54); 967193880Syongari alc_miibus_writereg(sc->alc_dev, sc->alc_phyaddr, 968193880Syongari ALC_MII_DBG_DATA, data); 969193880Syongari 970193880Syongari data = ((11 << ANA_IECHO_ADJ_3_SHIFT) & ANA_IECHO_ADJ_3_MASK) | 971193880Syongari ((11 << ANA_IECHO_ADJ_2_SHIFT) & ANA_IECHO_ADJ_2_MASK) | 972193880Syongari ((8 << ANA_IECHO_ADJ_1_SHIFT) & ANA_IECHO_ADJ_1_MASK) | 973193880Syongari ((8 << ANA_IECHO_ADJ_0_SHIFT) & ANA_IECHO_ADJ_0_MASK); 974193880Syongari alc_miibus_writereg(sc->alc_dev, sc->alc_phyaddr, 975193880Syongari ALC_MII_DBG_ADDR, MII_ANA_CFG4); 976193880Syongari alc_miibus_writereg(sc->alc_dev, sc->alc_phyaddr, 977193880Syongari ALC_MII_DBG_DATA, data); 978193880Syongari 979193880Syongari data = ((7 & ANA_MANUL_SWICH_ON_SHIFT) & ANA_MANUL_SWICH_ON_MASK) | 980193880Syongari ANA_RESTART_CAL | ANA_MAN_ENABLE | ANA_SEL_HSP | ANA_EN_HB | 981193880Syongari ANA_OEN_125M; 982193880Syongari alc_miibus_writereg(sc->alc_dev, sc->alc_phyaddr, 983193880Syongari ALC_MII_DBG_ADDR, MII_ANA_CFG0); 984193880Syongari alc_miibus_writereg(sc->alc_dev, sc->alc_phyaddr, 985193880Syongari ALC_MII_DBG_DATA, data); 986193880Syongari DELAY(1000); 987225088Syongari 988225088Syongari /* Disable hibernation. */ 989225088Syongari alc_miibus_writereg(sc->alc_dev, sc->alc_phyaddr, ALC_MII_DBG_ADDR, 990225088Syongari 0x0029); 991225088Syongari data = alc_miibus_readreg(sc->alc_dev, sc->alc_phyaddr, 992225088Syongari ALC_MII_DBG_DATA); 993225088Syongari data &= ~0x8000; 994225088Syongari alc_miibus_writereg(sc->alc_dev, sc->alc_phyaddr, ALC_MII_DBG_DATA, 995225088Syongari data); 996225088Syongari 997225088Syongari alc_miibus_writereg(sc->alc_dev, sc->alc_phyaddr, ALC_MII_DBG_ADDR, 998225088Syongari 0x000B); 999225088Syongari data = alc_miibus_readreg(sc->alc_dev, sc->alc_phyaddr, 1000225088Syongari ALC_MII_DBG_DATA); 1001225088Syongari data &= ~0x8000; 1002225088Syongari alc_miibus_writereg(sc->alc_dev, sc->alc_phyaddr, ALC_MII_DBG_DATA, 1003225088Syongari data); 1004193880Syongari} 1005193880Syongari 1006193880Syongaristatic void 1007272730Syongarialc_phy_reset_816x(struct alc_softc *sc) 1008272730Syongari{ 1009272730Syongari uint32_t val; 1010272730Syongari 1011272730Syongari val = CSR_READ_4(sc, ALC_GPHY_CFG); 1012272730Syongari val &= ~(GPHY_CFG_EXT_RESET | GPHY_CFG_LED_MODE | 1013272730Syongari GPHY_CFG_GATE_25M_ENB | GPHY_CFG_PHY_IDDQ | GPHY_CFG_PHY_PLL_ON | 1014272730Syongari GPHY_CFG_PWDOWN_HW | GPHY_CFG_100AB_ENB); 1015272730Syongari val |= GPHY_CFG_SEL_ANA_RESET; 1016272730Syongari#ifdef notyet 1017272730Syongari val |= GPHY_CFG_HIB_PULSE | GPHY_CFG_HIB_EN | GPHY_CFG_SEL_ANA_RESET; 1018272730Syongari#else 1019272730Syongari /* Disable PHY hibernation. */ 1020272730Syongari val &= ~(GPHY_CFG_HIB_PULSE | GPHY_CFG_HIB_EN); 1021272730Syongari#endif 1022272730Syongari CSR_WRITE_4(sc, ALC_GPHY_CFG, val); 1023272730Syongari DELAY(10); 1024272730Syongari CSR_WRITE_4(sc, ALC_GPHY_CFG, val | GPHY_CFG_EXT_RESET); 1025272730Syongari DELAY(800); 1026272730Syongari 1027272730Syongari /* Vendor PHY magic. */ 1028272730Syongari#ifdef notyet 1029272730Syongari alc_miidbg_writereg(sc, MII_DBG_LEGCYPS, DBG_LEGCYPS_DEFAULT); 1030272730Syongari alc_miidbg_writereg(sc, MII_DBG_SYSMODCTL, DBG_SYSMODCTL_DEFAULT); 1031272730Syongari alc_miiext_writereg(sc, MII_EXT_PCS, MII_EXT_VDRVBIAS, 1032272730Syongari EXT_VDRVBIAS_DEFAULT); 1033272730Syongari#else 1034272730Syongari /* Disable PHY hibernation. */ 1035272730Syongari alc_miidbg_writereg(sc, MII_DBG_LEGCYPS, 1036272730Syongari DBG_LEGCYPS_DEFAULT & ~DBG_LEGCYPS_ENB); 1037272730Syongari alc_miidbg_writereg(sc, MII_DBG_HIBNEG, 1038272730Syongari DBG_HIBNEG_DEFAULT & ~(DBG_HIBNEG_PSHIB_EN | DBG_HIBNEG_HIB_PULSE)); 1039272730Syongari alc_miidbg_writereg(sc, MII_DBG_GREENCFG, DBG_GREENCFG_DEFAULT); 1040272730Syongari#endif 1041272730Syongari 1042272730Syongari /* XXX Disable EEE. */ 1043272730Syongari val = CSR_READ_4(sc, ALC_LPI_CTL); 1044272730Syongari val &= ~LPI_CTL_ENB; 1045272730Syongari CSR_WRITE_4(sc, ALC_LPI_CTL, val); 1046272730Syongari alc_miiext_writereg(sc, MII_EXT_ANEG, MII_EXT_ANEG_LOCAL_EEEADV, 0); 1047272730Syongari 1048272730Syongari /* PHY power saving. */ 1049272730Syongari alc_miidbg_writereg(sc, MII_DBG_TST10BTCFG, DBG_TST10BTCFG_DEFAULT); 1050272730Syongari alc_miidbg_writereg(sc, MII_DBG_SRDSYSMOD, DBG_SRDSYSMOD_DEFAULT); 1051272730Syongari alc_miidbg_writereg(sc, MII_DBG_TST100BTCFG, DBG_TST100BTCFG_DEFAULT); 1052272730Syongari alc_miidbg_writereg(sc, MII_DBG_ANACTL, DBG_ANACTL_DEFAULT); 1053272730Syongari val = alc_miidbg_readreg(sc, MII_DBG_GREENCFG2); 1054272730Syongari val &= ~DBG_GREENCFG2_GATE_DFSE_EN; 1055272730Syongari alc_miidbg_writereg(sc, MII_DBG_GREENCFG2, val); 1056272730Syongari 1057272730Syongari /* RTL8139C, 120m issue. */ 1058272730Syongari alc_miiext_writereg(sc, MII_EXT_ANEG, MII_EXT_ANEG_NLP78, 1059272730Syongari ANEG_NLP78_120M_DEFAULT); 1060272730Syongari alc_miiext_writereg(sc, MII_EXT_ANEG, MII_EXT_ANEG_S3DIG10, 1061272730Syongari ANEG_S3DIG10_DEFAULT); 1062272730Syongari 1063272730Syongari if ((sc->alc_flags & ALC_FLAG_LINK_WAR) != 0) { 1064272730Syongari /* Turn off half amplitude. */ 1065272730Syongari val = alc_miiext_readreg(sc, MII_EXT_PCS, MII_EXT_CLDCTL3); 1066272730Syongari val |= EXT_CLDCTL3_BP_CABLE1TH_DET_GT; 1067272730Syongari alc_miiext_writereg(sc, MII_EXT_PCS, MII_EXT_CLDCTL3, val); 1068272730Syongari /* Turn off Green feature. */ 1069272730Syongari val = alc_miidbg_readreg(sc, MII_DBG_GREENCFG2); 1070272730Syongari val |= DBG_GREENCFG2_BP_GREEN; 1071272730Syongari alc_miidbg_writereg(sc, MII_DBG_GREENCFG2, val); 1072272730Syongari /* Turn off half bias. */ 1073272730Syongari val = alc_miiext_readreg(sc, MII_EXT_PCS, MII_EXT_CLDCTL5); 1074272730Syongari val |= EXT_CLDCTL5_BP_VD_HLFBIAS; 1075272730Syongari alc_miiext_writereg(sc, MII_EXT_PCS, MII_EXT_CLDCTL5, val); 1076272730Syongari } 1077272730Syongari} 1078272730Syongari 1079272730Syongaristatic void 1080193880Syongarialc_phy_down(struct alc_softc *sc) 1081193880Syongari{ 1082272730Syongari uint32_t gphy; 1083193880Syongari 1084211105Syongari switch (sc->alc_ident->deviceid) { 1085272730Syongari case DEVICEID_ATHEROS_AR8161: 1086272730Syongari case DEVICEID_ATHEROS_E2200: 1087312358Syongari case DEVICEID_ATHEROS_E2400: 1088314005Ssephe case DEVICEID_ATHEROS_E2500: 1089272730Syongari case DEVICEID_ATHEROS_AR8162: 1090272730Syongari case DEVICEID_ATHEROS_AR8171: 1091272730Syongari case DEVICEID_ATHEROS_AR8172: 1092272730Syongari gphy = CSR_READ_4(sc, ALC_GPHY_CFG); 1093272730Syongari gphy &= ~(GPHY_CFG_EXT_RESET | GPHY_CFG_LED_MODE | 1094272730Syongari GPHY_CFG_100AB_ENB | GPHY_CFG_PHY_PLL_ON); 1095272730Syongari gphy |= GPHY_CFG_HIB_EN | GPHY_CFG_HIB_PULSE | 1096272730Syongari GPHY_CFG_SEL_ANA_RESET; 1097272730Syongari gphy |= GPHY_CFG_PHY_IDDQ | GPHY_CFG_PWDOWN_HW; 1098272730Syongari CSR_WRITE_4(sc, ALC_GPHY_CFG, gphy); 1099272730Syongari break; 1100211105Syongari case DEVICEID_ATHEROS_AR8151: 1101211105Syongari case DEVICEID_ATHEROS_AR8151_V2: 1102272730Syongari case DEVICEID_ATHEROS_AR8152_B: 1103272730Syongari case DEVICEID_ATHEROS_AR8152_B2: 1104211105Syongari /* 1105211105Syongari * GPHY power down caused more problems on AR8151 v2.0. 1106211105Syongari * When driver is reloaded after GPHY power down, 1107211105Syongari * accesses to PHY/MAC registers hung the system. Only 1108211105Syongari * cold boot recovered from it. I'm not sure whether 1109211105Syongari * AR8151 v1.0 also requires this one though. I don't 1110211105Syongari * have AR8151 v1.0 controller in hand. 1111211105Syongari * The only option left is to isolate the PHY and 1112211105Syongari * initiates power down the PHY which in turn saves 1113211105Syongari * more power when driver is unloaded. 1114211105Syongari */ 1115211105Syongari alc_miibus_writereg(sc->alc_dev, sc->alc_phyaddr, 1116211105Syongari MII_BMCR, BMCR_ISO | BMCR_PDOWN); 1117211105Syongari break; 1118211105Syongari default: 1119211105Syongari /* Force PHY down. */ 1120225088Syongari CSR_WRITE_2(sc, ALC_GPHY_CFG, GPHY_CFG_EXT_RESET | 1121211105Syongari GPHY_CFG_SEL_ANA_RESET | GPHY_CFG_PHY_IDDQ | 1122211105Syongari GPHY_CFG_PWDOWN_HW); 1123211105Syongari DELAY(1000); 1124211105Syongari break; 1125211105Syongari } 1126193880Syongari} 1127193880Syongari 1128193880Syongaristatic void 1129272730Syongarialc_aspm(struct alc_softc *sc, int init, int media) 1130193880Syongari{ 1131272730Syongari 1132272730Syongari if ((sc->alc_flags & ALC_FLAG_AR816X_FAMILY) != 0) 1133272730Syongari alc_aspm_816x(sc, init); 1134272730Syongari else 1135272730Syongari alc_aspm_813x(sc, media); 1136272730Syongari} 1137272730Syongari 1138272730Syongaristatic void 1139272730Syongarialc_aspm_813x(struct alc_softc *sc, int media) 1140272730Syongari{ 1141193880Syongari uint32_t pmcfg; 1142211105Syongari uint16_t linkcfg; 1143193880Syongari 1144272730Syongari if ((sc->alc_flags & ALC_FLAG_LINK) == 0) 1145272730Syongari return; 1146193880Syongari 1147193880Syongari pmcfg = CSR_READ_4(sc, ALC_PM_CFG); 1148211105Syongari if ((sc->alc_flags & (ALC_FLAG_APS | ALC_FLAG_PCIE)) == 1149211105Syongari (ALC_FLAG_APS | ALC_FLAG_PCIE)) 1150211105Syongari linkcfg = CSR_READ_2(sc, sc->alc_expcap + 1151240680Sgavin PCIER_LINK_CTL); 1152211105Syongari else 1153211105Syongari linkcfg = 0; 1154193880Syongari pmcfg &= ~PM_CFG_SERDES_PD_EX_L1; 1155211105Syongari pmcfg &= ~(PM_CFG_L1_ENTRY_TIMER_MASK | PM_CFG_LCKDET_TIMER_MASK); 1156193880Syongari pmcfg |= PM_CFG_MAC_ASPM_CHK; 1157217649Syongari pmcfg |= (PM_CFG_LCKDET_TIMER_DEFAULT << PM_CFG_LCKDET_TIMER_SHIFT); 1158211105Syongari pmcfg &= ~(PM_CFG_ASPM_L1_ENB | PM_CFG_ASPM_L0S_ENB); 1159211105Syongari 1160211105Syongari if ((sc->alc_flags & ALC_FLAG_APS) != 0) { 1161211105Syongari /* Disable extended sync except AR8152 B v1.0 */ 1162240693Sgavin linkcfg &= ~PCIEM_LINK_CTL_EXTENDED_SYNC; 1163211105Syongari if (sc->alc_ident->deviceid == DEVICEID_ATHEROS_AR8152_B && 1164211105Syongari sc->alc_rev == ATHEROS_AR8152_B_V10) 1165240693Sgavin linkcfg |= PCIEM_LINK_CTL_EXTENDED_SYNC; 1166240680Sgavin CSR_WRITE_2(sc, sc->alc_expcap + PCIER_LINK_CTL, 1167211105Syongari linkcfg); 1168211105Syongari pmcfg &= ~(PM_CFG_EN_BUFS_RX_L0S | PM_CFG_SA_DLY_ENB | 1169211105Syongari PM_CFG_HOTRST); 1170211105Syongari pmcfg |= (PM_CFG_L1_ENTRY_TIMER_DEFAULT << 1171211105Syongari PM_CFG_L1_ENTRY_TIMER_SHIFT); 1172211105Syongari pmcfg &= ~PM_CFG_PM_REQ_TIMER_MASK; 1173211105Syongari pmcfg |= (PM_CFG_PM_REQ_TIMER_DEFAULT << 1174211105Syongari PM_CFG_PM_REQ_TIMER_SHIFT); 1175211105Syongari pmcfg |= PM_CFG_SERDES_PD_EX_L1 | PM_CFG_PCIE_RECV; 1176211105Syongari } 1177211105Syongari 1178193880Syongari if ((sc->alc_flags & ALC_FLAG_LINK) != 0) { 1179211105Syongari if ((sc->alc_flags & ALC_FLAG_L0S) != 0) 1180211105Syongari pmcfg |= PM_CFG_ASPM_L0S_ENB; 1181211105Syongari if ((sc->alc_flags & ALC_FLAG_L1S) != 0) 1182211105Syongari pmcfg |= PM_CFG_ASPM_L1_ENB; 1183211105Syongari if ((sc->alc_flags & ALC_FLAG_APS) != 0) { 1184211105Syongari if (sc->alc_ident->deviceid == 1185211105Syongari DEVICEID_ATHEROS_AR8152_B) 1186211105Syongari pmcfg &= ~PM_CFG_ASPM_L0S_ENB; 1187211105Syongari pmcfg &= ~(PM_CFG_SERDES_L1_ENB | 1188211105Syongari PM_CFG_SERDES_PLL_L1_ENB | 1189211105Syongari PM_CFG_SERDES_BUDS_RX_L1_ENB); 1190211105Syongari pmcfg |= PM_CFG_CLK_SWH_L1; 1191211105Syongari if (media == IFM_100_TX || media == IFM_1000_T) { 1192211105Syongari pmcfg &= ~PM_CFG_L1_ENTRY_TIMER_MASK; 1193211105Syongari switch (sc->alc_ident->deviceid) { 1194211105Syongari case DEVICEID_ATHEROS_AR8152_B: 1195211105Syongari pmcfg |= (7 << 1196211105Syongari PM_CFG_L1_ENTRY_TIMER_SHIFT); 1197211105Syongari break; 1198211105Syongari case DEVICEID_ATHEROS_AR8152_B2: 1199211105Syongari case DEVICEID_ATHEROS_AR8151_V2: 1200211105Syongari pmcfg |= (4 << 1201211105Syongari PM_CFG_L1_ENTRY_TIMER_SHIFT); 1202211105Syongari break; 1203211105Syongari default: 1204211105Syongari pmcfg |= (15 << 1205211105Syongari PM_CFG_L1_ENTRY_TIMER_SHIFT); 1206211105Syongari break; 1207211105Syongari } 1208211105Syongari } 1209211105Syongari } else { 1210211105Syongari pmcfg |= PM_CFG_SERDES_L1_ENB | 1211211105Syongari PM_CFG_SERDES_PLL_L1_ENB | 1212211105Syongari PM_CFG_SERDES_BUDS_RX_L1_ENB; 1213211105Syongari pmcfg &= ~(PM_CFG_CLK_SWH_L1 | 1214211105Syongari PM_CFG_ASPM_L1_ENB | PM_CFG_ASPM_L0S_ENB); 1215211105Syongari } 1216193880Syongari } else { 1217211105Syongari pmcfg &= ~(PM_CFG_SERDES_BUDS_RX_L1_ENB | PM_CFG_SERDES_L1_ENB | 1218211105Syongari PM_CFG_SERDES_PLL_L1_ENB); 1219193880Syongari pmcfg |= PM_CFG_CLK_SWH_L1; 1220211105Syongari if ((sc->alc_flags & ALC_FLAG_L1S) != 0) 1221211105Syongari pmcfg |= PM_CFG_ASPM_L1_ENB; 1222193880Syongari } 1223193880Syongari CSR_WRITE_4(sc, ALC_PM_CFG, pmcfg); 1224193880Syongari} 1225193880Syongari 1226272730Syongaristatic void 1227272730Syongarialc_aspm_816x(struct alc_softc *sc, int init) 1228193880Syongari{ 1229272730Syongari uint32_t pmcfg; 1230193880Syongari 1231272730Syongari pmcfg = CSR_READ_4(sc, ALC_PM_CFG); 1232272730Syongari pmcfg &= ~PM_CFG_L1_ENTRY_TIMER_816X_MASK; 1233272730Syongari pmcfg |= PM_CFG_L1_ENTRY_TIMER_816X_DEFAULT; 1234272730Syongari pmcfg &= ~PM_CFG_PM_REQ_TIMER_MASK; 1235272730Syongari pmcfg |= PM_CFG_PM_REQ_TIMER_816X_DEFAULT; 1236272730Syongari pmcfg &= ~PM_CFG_LCKDET_TIMER_MASK; 1237272730Syongari pmcfg |= PM_CFG_LCKDET_TIMER_DEFAULT; 1238272730Syongari pmcfg |= PM_CFG_SERDES_PD_EX_L1 | PM_CFG_CLK_SWH_L1 | PM_CFG_PCIE_RECV; 1239272730Syongari pmcfg &= ~(PM_CFG_RX_L1_AFTER_L0S | PM_CFG_TX_L1_AFTER_L0S | 1240272730Syongari PM_CFG_ASPM_L1_ENB | PM_CFG_ASPM_L0S_ENB | 1241272730Syongari PM_CFG_SERDES_L1_ENB | PM_CFG_SERDES_PLL_L1_ENB | 1242272730Syongari PM_CFG_SERDES_BUDS_RX_L1_ENB | PM_CFG_SA_DLY_ENB | 1243272730Syongari PM_CFG_MAC_ASPM_CHK | PM_CFG_HOTRST); 1244272730Syongari if (AR816X_REV(sc->alc_rev) <= AR816X_REV_A1 && 1245272730Syongari (sc->alc_rev & 0x01) != 0) 1246272730Syongari pmcfg |= PM_CFG_SERDES_L1_ENB | PM_CFG_SERDES_PLL_L1_ENB; 1247272730Syongari if ((sc->alc_flags & ALC_FLAG_LINK) != 0) { 1248272730Syongari /* Link up, enable both L0s, L1s. */ 1249272730Syongari pmcfg |= PM_CFG_ASPM_L0S_ENB | PM_CFG_ASPM_L1_ENB | 1250272730Syongari PM_CFG_MAC_ASPM_CHK; 1251272730Syongari } else { 1252272730Syongari if (init != 0) 1253272730Syongari pmcfg |= PM_CFG_ASPM_L0S_ENB | PM_CFG_ASPM_L1_ENB | 1254272730Syongari PM_CFG_MAC_ASPM_CHK; 1255272730Syongari else if ((sc->alc_ifp->if_drv_flags & IFF_DRV_RUNNING) != 0) 1256272730Syongari pmcfg |= PM_CFG_ASPM_L1_ENB | PM_CFG_MAC_ASPM_CHK; 1257272730Syongari } 1258272730Syongari CSR_WRITE_4(sc, ALC_PM_CFG, pmcfg); 1259272730Syongari} 1260193880Syongari 1261272730Syongaristatic void 1262272730Syongarialc_init_pcie(struct alc_softc *sc) 1263272730Syongari{ 1264272730Syongari const char *aspm_state[] = { "L0s/L1", "L0s", "L1", "L0s/L1" }; 1265272730Syongari uint32_t cap, ctl, val; 1266272730Syongari int state; 1267193880Syongari 1268272730Syongari /* Clear data link and flow-control protocol error. */ 1269272730Syongari val = CSR_READ_4(sc, ALC_PEX_UNC_ERR_SEV); 1270272730Syongari val &= ~(PEX_UNC_ERR_SEV_DLP | PEX_UNC_ERR_SEV_FCP); 1271272730Syongari CSR_WRITE_4(sc, ALC_PEX_UNC_ERR_SEV, val); 1272193880Syongari 1273272730Syongari if ((sc->alc_flags & ALC_FLAG_AR816X_FAMILY) == 0) { 1274211105Syongari CSR_WRITE_4(sc, ALC_LTSSM_ID_CFG, 1275211105Syongari CSR_READ_4(sc, ALC_LTSSM_ID_CFG) & ~LTSSM_ID_WRO_ENB); 1276211105Syongari CSR_WRITE_4(sc, ALC_PCIE_PHYMISC, 1277211105Syongari CSR_READ_4(sc, ALC_PCIE_PHYMISC) | 1278211105Syongari PCIE_PHYMISC_FORCE_RCV_DET); 1279211105Syongari if (sc->alc_ident->deviceid == DEVICEID_ATHEROS_AR8152_B && 1280272730Syongari sc->alc_rev == ATHEROS_AR8152_B_V10) { 1281211105Syongari val = CSR_READ_4(sc, ALC_PCIE_PHYMISC2); 1282211105Syongari val &= ~(PCIE_PHYMISC2_SERDES_CDR_MASK | 1283211105Syongari PCIE_PHYMISC2_SERDES_TH_MASK); 1284211105Syongari val |= 3 << PCIE_PHYMISC2_SERDES_CDR_SHIFT; 1285211105Syongari val |= 3 << PCIE_PHYMISC2_SERDES_TH_SHIFT; 1286211105Syongari CSR_WRITE_4(sc, ALC_PCIE_PHYMISC2, val); 1287211105Syongari } 1288193880Syongari /* Disable ASPM L0S and L1. */ 1289272730Syongari cap = CSR_READ_2(sc, sc->alc_expcap + PCIER_LINK_CAP); 1290240680Sgavin if ((cap & PCIEM_LINK_CAP_ASPM) != 0) { 1291272730Syongari ctl = CSR_READ_2(sc, sc->alc_expcap + PCIER_LINK_CTL); 1292240693Sgavin if ((ctl & PCIEM_LINK_CTL_RCB) != 0) 1293193880Syongari sc->alc_rcb = DMA_CFG_RCB_128; 1294193880Syongari if (bootverbose) 1295272730Syongari device_printf(sc->alc_dev, "RCB %u bytes\n", 1296193880Syongari sc->alc_rcb == DMA_CFG_RCB_64 ? 64 : 128); 1297240693Sgavin state = ctl & PCIEM_LINK_CTL_ASPMC; 1298240693Sgavin if (state & PCIEM_LINK_CTL_ASPMC_L0S) 1299211105Syongari sc->alc_flags |= ALC_FLAG_L0S; 1300240693Sgavin if (state & PCIEM_LINK_CTL_ASPMC_L1) 1301211105Syongari sc->alc_flags |= ALC_FLAG_L1S; 1302193880Syongari if (bootverbose) 1303193880Syongari device_printf(sc->alc_dev, "ASPM %s %s\n", 1304193880Syongari aspm_state[state], 1305193880Syongari state == 0 ? "disabled" : "enabled"); 1306211105Syongari alc_disable_l0s_l1(sc); 1307211105Syongari } else { 1308211105Syongari if (bootverbose) 1309211105Syongari device_printf(sc->alc_dev, 1310211105Syongari "no ASPM support\n"); 1311193880Syongari } 1312272730Syongari } else { 1313272730Syongari val = CSR_READ_4(sc, ALC_PDLL_TRNS1); 1314272730Syongari val &= ~PDLL_TRNS1_D3PLLOFF_ENB; 1315272730Syongari CSR_WRITE_4(sc, ALC_PDLL_TRNS1, val); 1316272730Syongari val = CSR_READ_4(sc, ALC_MASTER_CFG); 1317272730Syongari if (AR816X_REV(sc->alc_rev) <= AR816X_REV_A1 && 1318272730Syongari (sc->alc_rev & 0x01) != 0) { 1319272730Syongari if ((val & MASTER_WAKEN_25M) == 0 || 1320272730Syongari (val & MASTER_CLK_SEL_DIS) == 0) { 1321272730Syongari val |= MASTER_WAKEN_25M | MASTER_CLK_SEL_DIS; 1322272730Syongari CSR_WRITE_4(sc, ALC_MASTER_CFG, val); 1323272730Syongari } 1324272730Syongari } else { 1325272730Syongari if ((val & MASTER_WAKEN_25M) == 0 || 1326272730Syongari (val & MASTER_CLK_SEL_DIS) != 0) { 1327272730Syongari val |= MASTER_WAKEN_25M; 1328272730Syongari val &= ~MASTER_CLK_SEL_DIS; 1329272730Syongari CSR_WRITE_4(sc, ALC_MASTER_CFG, val); 1330272730Syongari } 1331272730Syongari } 1332193880Syongari } 1333272730Syongari alc_aspm(sc, 1, IFM_UNKNOWN); 1334272730Syongari} 1335193880Syongari 1336272730Syongaristatic void 1337272730Syongarialc_config_msi(struct alc_softc *sc) 1338272730Syongari{ 1339272730Syongari uint32_t ctl, mod; 1340193880Syongari 1341272730Syongari if ((sc->alc_flags & ALC_FLAG_AR816X_FAMILY) != 0) { 1342272730Syongari /* 1343272730Syongari * It seems interrupt moderation is controlled by 1344272730Syongari * ALC_MSI_RETRANS_TIMER register if MSI/MSIX is active. 1345272730Syongari * Driver uses RX interrupt moderation parameter to 1346272730Syongari * program ALC_MSI_RETRANS_TIMER register. 1347272730Syongari */ 1348272730Syongari ctl = CSR_READ_4(sc, ALC_MSI_RETRANS_TIMER); 1349272730Syongari ctl &= ~MSI_RETRANS_TIMER_MASK; 1350272730Syongari ctl &= ~MSI_RETRANS_MASK_SEL_LINE; 1351272730Syongari mod = ALC_USECS(sc->alc_int_rx_mod); 1352272730Syongari if (mod == 0) 1353272730Syongari mod = 1; 1354272730Syongari ctl |= mod; 1355272730Syongari if ((sc->alc_flags & ALC_FLAG_MSIX) != 0) 1356272730Syongari CSR_WRITE_4(sc, ALC_MSI_RETRANS_TIMER, ctl | 1357272730Syongari MSI_RETRANS_MASK_SEL_STD); 1358272730Syongari else if ((sc->alc_flags & ALC_FLAG_MSI) != 0) 1359272730Syongari CSR_WRITE_4(sc, ALC_MSI_RETRANS_TIMER, ctl | 1360272730Syongari MSI_RETRANS_MASK_SEL_LINE); 1361272730Syongari else 1362272730Syongari CSR_WRITE_4(sc, ALC_MSI_RETRANS_TIMER, 0); 1363272730Syongari } 1364272730Syongari} 1365193880Syongari 1366272730Syongaristatic int 1367272730Syongarialc_attach(device_t dev) 1368272730Syongari{ 1369272730Syongari struct alc_softc *sc; 1370272730Syongari struct ifnet *ifp; 1371272730Syongari int base, error, i, msic, msixc; 1372272730Syongari uint16_t burst; 1373272730Syongari 1374272730Syongari error = 0; 1375272730Syongari sc = device_get_softc(dev); 1376272730Syongari sc->alc_dev = dev; 1377272730Syongari sc->alc_rev = pci_get_revid(dev); 1378272730Syongari 1379272730Syongari mtx_init(&sc->alc_mtx, device_get_nameunit(dev), MTX_NETWORK_LOCK, 1380272730Syongari MTX_DEF); 1381272730Syongari callout_init_mtx(&sc->alc_tick_ch, &sc->alc_mtx, 0); 1382272730Syongari TASK_INIT(&sc->alc_int_task, 0, alc_int_task, sc); 1383272730Syongari sc->alc_ident = alc_find_ident(dev); 1384272730Syongari 1385272730Syongari /* Map the device. */ 1386272730Syongari pci_enable_busmaster(dev); 1387272730Syongari sc->alc_res_spec = alc_res_spec_mem; 1388272730Syongari sc->alc_irq_spec = alc_irq_spec_legacy; 1389272730Syongari error = bus_alloc_resources(dev, sc->alc_res_spec, sc->alc_res); 1390272730Syongari if (error != 0) { 1391272730Syongari device_printf(dev, "cannot allocate memory resources.\n"); 1392272730Syongari goto fail; 1393272730Syongari } 1394272730Syongari 1395272730Syongari /* Set PHY address. */ 1396272730Syongari sc->alc_phyaddr = ALC_PHY_ADDR; 1397272730Syongari 1398193880Syongari /* 1399193880Syongari * One odd thing is AR8132 uses the same PHY hardware(F1 1400193880Syongari * gigabit PHY) of AR8131. So atphy(4) of AR8132 reports 1401193880Syongari * the PHY supports 1000Mbps but that's not true. The PHY 1402193880Syongari * used in AR8132 can't establish gigabit link even if it 1403193880Syongari * shows the same PHY model/revision number of AR8131. 1404193880Syongari */ 1405211105Syongari switch (sc->alc_ident->deviceid) { 1406312358Syongari case DEVICEID_ATHEROS_E2200: 1407312358Syongari case DEVICEID_ATHEROS_E2400: 1408314005Ssephe case DEVICEID_ATHEROS_E2500: 1409312358Syongari sc->alc_flags |= ALC_FLAG_E2X00; 1410312358Syongari /* FALLTHROUGH */ 1411272730Syongari case DEVICEID_ATHEROS_AR8161: 1412272730Syongari if (pci_get_subvendor(dev) == VENDORID_ATHEROS && 1413272730Syongari pci_get_subdevice(dev) == 0x0091 && sc->alc_rev == 0) 1414272730Syongari sc->alc_flags |= ALC_FLAG_LINK_WAR; 1415272730Syongari /* FALLTHROUGH */ 1416272730Syongari case DEVICEID_ATHEROS_AR8171: 1417272730Syongari sc->alc_flags |= ALC_FLAG_AR816X_FAMILY; 1418272730Syongari break; 1419272730Syongari case DEVICEID_ATHEROS_AR8162: 1420272730Syongari case DEVICEID_ATHEROS_AR8172: 1421272730Syongari sc->alc_flags |= ALC_FLAG_FASTETHER | ALC_FLAG_AR816X_FAMILY; 1422272730Syongari break; 1423211105Syongari case DEVICEID_ATHEROS_AR8152_B: 1424211105Syongari case DEVICEID_ATHEROS_AR8152_B2: 1425211105Syongari sc->alc_flags |= ALC_FLAG_APS; 1426211105Syongari /* FALLTHROUGH */ 1427211105Syongari case DEVICEID_ATHEROS_AR8132: 1428211105Syongari sc->alc_flags |= ALC_FLAG_FASTETHER; 1429211105Syongari break; 1430211105Syongari case DEVICEID_ATHEROS_AR8151: 1431211105Syongari case DEVICEID_ATHEROS_AR8151_V2: 1432211105Syongari sc->alc_flags |= ALC_FLAG_APS; 1433211105Syongari /* FALLTHROUGH */ 1434211105Syongari default: 1435211105Syongari break; 1436211105Syongari } 1437272730Syongari sc->alc_flags |= ALC_FLAG_JUMBO; 1438211105Syongari 1439193880Syongari /* 1440211105Syongari * It seems that AR813x/AR815x has silicon bug for SMB. In 1441193880Syongari * addition, Atheros said that enabling SMB wouldn't improve 1442193880Syongari * performance. However I think it's bad to access lots of 1443193880Syongari * registers to extract MAC statistics. 1444193880Syongari */ 1445193880Syongari sc->alc_flags |= ALC_FLAG_SMB_BUG; 1446193880Syongari /* 1447193880Syongari * Don't use Tx CMB. It is known to have silicon bug. 1448193880Syongari */ 1449193880Syongari sc->alc_flags |= ALC_FLAG_CMB_BUG; 1450193880Syongari sc->alc_chip_rev = CSR_READ_4(sc, ALC_MASTER_CFG) >> 1451193880Syongari MASTER_CHIP_REV_SHIFT; 1452193880Syongari if (bootverbose) { 1453193880Syongari device_printf(dev, "PCI device revision : 0x%04x\n", 1454193880Syongari sc->alc_rev); 1455193880Syongari device_printf(dev, "Chip id/revision : 0x%04x\n", 1456193880Syongari sc->alc_chip_rev); 1457272730Syongari if ((sc->alc_flags & ALC_FLAG_AR816X_FAMILY) != 0) 1458272730Syongari device_printf(dev, "AR816x revision : 0x%x\n", 1459272730Syongari AR816X_REV(sc->alc_rev)); 1460193880Syongari } 1461193880Syongari device_printf(dev, "%u Tx FIFO, %u Rx FIFO\n", 1462193880Syongari CSR_READ_4(sc, ALC_SRAM_TX_FIFO_LEN) * 8, 1463193880Syongari CSR_READ_4(sc, ALC_SRAM_RX_FIFO_LEN) * 8); 1464193880Syongari 1465272730Syongari /* Initialize DMA parameters. */ 1466272730Syongari sc->alc_dma_rd_burst = 0; 1467272730Syongari sc->alc_dma_wr_burst = 0; 1468272730Syongari sc->alc_rcb = DMA_CFG_RCB_64; 1469272730Syongari if (pci_find_cap(dev, PCIY_EXPRESS, &base) == 0) { 1470272730Syongari sc->alc_flags |= ALC_FLAG_PCIE; 1471272730Syongari sc->alc_expcap = base; 1472272730Syongari burst = CSR_READ_2(sc, base + PCIER_DEVICE_CTL); 1473272730Syongari sc->alc_dma_rd_burst = 1474272730Syongari (burst & PCIEM_CTL_MAX_READ_REQUEST) >> 12; 1475272730Syongari sc->alc_dma_wr_burst = (burst & PCIEM_CTL_MAX_PAYLOAD) >> 5; 1476272730Syongari if (bootverbose) { 1477272730Syongari device_printf(dev, "Read request size : %u bytes.\n", 1478272730Syongari alc_dma_burst[sc->alc_dma_rd_burst]); 1479272730Syongari device_printf(dev, "TLP payload size : %u bytes.\n", 1480272730Syongari alc_dma_burst[sc->alc_dma_wr_burst]); 1481272730Syongari } 1482272730Syongari if (alc_dma_burst[sc->alc_dma_rd_burst] > 1024) 1483272730Syongari sc->alc_dma_rd_burst = 3; 1484272730Syongari if (alc_dma_burst[sc->alc_dma_wr_burst] > 1024) 1485272730Syongari sc->alc_dma_wr_burst = 3; 1486312358Syongari /* 1487314005Ssephe * Force maximum payload size to 128 bytes for 1488314005Ssephe * E2200/E2400/E2500. 1489312358Syongari * Otherwise it triggers DMA write error. 1490312358Syongari */ 1491312358Syongari if ((sc->alc_flags & ALC_FLAG_E2X00) != 0) 1492312358Syongari sc->alc_dma_wr_burst = 0; 1493272730Syongari alc_init_pcie(sc); 1494272730Syongari } 1495272730Syongari 1496272730Syongari /* Reset PHY. */ 1497272730Syongari alc_phy_reset(sc); 1498272730Syongari 1499272730Syongari /* Reset the ethernet controller. */ 1500272730Syongari alc_stop_mac(sc); 1501272730Syongari alc_reset(sc); 1502272730Syongari 1503193880Syongari /* Allocate IRQ resources. */ 1504193880Syongari msixc = pci_msix_count(dev); 1505193880Syongari msic = pci_msi_count(dev); 1506193880Syongari if (bootverbose) { 1507193880Syongari device_printf(dev, "MSIX count : %d\n", msixc); 1508193880Syongari device_printf(dev, "MSI count : %d\n", msic); 1509193880Syongari } 1510272730Syongari if (msixc > 1) 1511272730Syongari msixc = 1; 1512272730Syongari if (msic > 1) 1513272730Syongari msic = 1; 1514272730Syongari /* 1515272730Syongari * Prefer MSIX over MSI. 1516272730Syongari * AR816x controller has a silicon bug that MSI interrupt 1517272730Syongari * does not assert if PCIM_CMD_INTxDIS bit of command 1518272730Syongari * register is set. pci(4) was taught to handle that case. 1519272730Syongari */ 1520193880Syongari if (msix_disable == 0 || msi_disable == 0) { 1521272730Syongari if (msix_disable == 0 && msixc > 0 && 1522193880Syongari pci_alloc_msix(dev, &msixc) == 0) { 1523272730Syongari if (msic == 1) { 1524193880Syongari device_printf(dev, 1525193880Syongari "Using %d MSIX message(s).\n", msixc); 1526193880Syongari sc->alc_flags |= ALC_FLAG_MSIX; 1527193880Syongari sc->alc_irq_spec = alc_irq_spec_msix; 1528193880Syongari } else 1529193880Syongari pci_release_msi(dev); 1530193880Syongari } 1531193880Syongari if (msi_disable == 0 && (sc->alc_flags & ALC_FLAG_MSIX) == 0 && 1532272730Syongari msic > 0 && pci_alloc_msi(dev, &msic) == 0) { 1533272730Syongari if (msic == 1) { 1534193880Syongari device_printf(dev, 1535193880Syongari "Using %d MSI message(s).\n", msic); 1536193880Syongari sc->alc_flags |= ALC_FLAG_MSI; 1537193880Syongari sc->alc_irq_spec = alc_irq_spec_msi; 1538193880Syongari } else 1539193880Syongari pci_release_msi(dev); 1540193880Syongari } 1541193880Syongari } 1542193880Syongari 1543193880Syongari error = bus_alloc_resources(dev, sc->alc_irq_spec, sc->alc_irq); 1544193880Syongari if (error != 0) { 1545193880Syongari device_printf(dev, "cannot allocate IRQ resources.\n"); 1546193880Syongari goto fail; 1547193880Syongari } 1548193880Syongari 1549193880Syongari /* Create device sysctl node. */ 1550193880Syongari alc_sysctl_node(sc); 1551193880Syongari 1552295735Syongari if ((error = alc_dma_alloc(sc)) != 0) 1553193880Syongari goto fail; 1554193880Syongari 1555193880Syongari /* Load station address. */ 1556193880Syongari alc_get_macaddr(sc); 1557193880Syongari 1558193880Syongari ifp = sc->alc_ifp = if_alloc(IFT_ETHER); 1559193880Syongari if (ifp == NULL) { 1560193880Syongari device_printf(dev, "cannot allocate ifnet structure.\n"); 1561193880Syongari error = ENXIO; 1562193880Syongari goto fail; 1563193880Syongari } 1564193880Syongari 1565193880Syongari ifp->if_softc = sc; 1566193880Syongari if_initname(ifp, device_get_name(dev), device_get_unit(dev)); 1567193880Syongari ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 1568193880Syongari ifp->if_ioctl = alc_ioctl; 1569193880Syongari ifp->if_start = alc_start; 1570193880Syongari ifp->if_init = alc_init; 1571193880Syongari ifp->if_snd.ifq_drv_maxlen = ALC_TX_RING_CNT - 1; 1572193880Syongari IFQ_SET_MAXLEN(&ifp->if_snd, ifp->if_snd.ifq_drv_maxlen); 1573193880Syongari IFQ_SET_READY(&ifp->if_snd); 1574193880Syongari ifp->if_capabilities = IFCAP_TXCSUM | IFCAP_TSO4; 1575193880Syongari ifp->if_hwassist = ALC_CSUM_FEATURES | CSUM_TSO; 1576219902Sjhb if (pci_find_cap(dev, PCIY_PMG, &base) == 0) { 1577193880Syongari ifp->if_capabilities |= IFCAP_WOL_MAGIC | IFCAP_WOL_MCAST; 1578211053Syongari sc->alc_flags |= ALC_FLAG_PM; 1579211053Syongari sc->alc_pmcap = base; 1580211053Syongari } 1581193880Syongari ifp->if_capenable = ifp->if_capabilities; 1582193880Syongari 1583193880Syongari /* Set up MII bus. */ 1584213893Smarius error = mii_attach(dev, &sc->alc_miibus, ifp, alc_mediachange, 1585213893Smarius alc_mediastatus, BMSR_DEFCAPMASK, sc->alc_phyaddr, MII_OFFSET_ANY, 1586215850Syongari MIIF_DOPAUSE); 1587213893Smarius if (error != 0) { 1588213893Smarius device_printf(dev, "attaching PHYs failed\n"); 1589193880Syongari goto fail; 1590193880Syongari } 1591193880Syongari 1592193880Syongari ether_ifattach(ifp, sc->alc_eaddr); 1593193880Syongari 1594193880Syongari /* VLAN capability setup. */ 1595204228Syongari ifp->if_capabilities |= IFCAP_VLAN_MTU | IFCAP_VLAN_HWTAGGING | 1596204228Syongari IFCAP_VLAN_HWCSUM | IFCAP_VLAN_HWTSO; 1597193880Syongari ifp->if_capenable = ifp->if_capabilities; 1598193880Syongari /* 1599193880Syongari * XXX 1600193880Syongari * It seems enabling Tx checksum offloading makes more trouble. 1601193880Syongari * Sometimes the controller does not receive any frames when 1602193880Syongari * Tx checksum offloading is enabled. I'm not sure whether this 1603193880Syongari * is a bug in Tx checksum offloading logic or I got broken 1604193880Syongari * sample boards. To safety, don't enable Tx checksum offloading 1605193880Syongari * by default but give chance to users to toggle it if they know 1606193880Syongari * their controllers work without problems. 1607272730Syongari * Fortunately, Tx checksum offloading for AR816x family 1608272730Syongari * seems to work. 1609193880Syongari */ 1610272730Syongari if ((sc->alc_flags & ALC_FLAG_AR816X_FAMILY) == 0) { 1611272730Syongari ifp->if_capenable &= ~IFCAP_TXCSUM; 1612272730Syongari ifp->if_hwassist &= ~ALC_CSUM_FEATURES; 1613272730Syongari } 1614193880Syongari 1615193880Syongari /* Tell the upper layer(s) we support long frames. */ 1616270856Sglebius ifp->if_hdrlen = sizeof(struct ether_vlan_header); 1617193880Syongari 1618193880Syongari /* Create local taskq. */ 1619193880Syongari sc->alc_tq = taskqueue_create_fast("alc_taskq", M_WAITOK, 1620193880Syongari taskqueue_thread_enqueue, &sc->alc_tq); 1621193880Syongari if (sc->alc_tq == NULL) { 1622193880Syongari device_printf(dev, "could not create taskqueue.\n"); 1623193880Syongari ether_ifdetach(ifp); 1624193880Syongari error = ENXIO; 1625193880Syongari goto fail; 1626193880Syongari } 1627193880Syongari taskqueue_start_threads(&sc->alc_tq, 1, PI_NET, "%s taskq", 1628193880Syongari device_get_nameunit(sc->alc_dev)); 1629193880Syongari 1630272730Syongari alc_config_msi(sc); 1631193880Syongari if ((sc->alc_flags & ALC_FLAG_MSIX) != 0) 1632193880Syongari msic = ALC_MSIX_MESSAGES; 1633193880Syongari else if ((sc->alc_flags & ALC_FLAG_MSI) != 0) 1634193880Syongari msic = ALC_MSI_MESSAGES; 1635193880Syongari else 1636193880Syongari msic = 1; 1637193880Syongari for (i = 0; i < msic; i++) { 1638193880Syongari error = bus_setup_intr(dev, sc->alc_irq[i], 1639193880Syongari INTR_TYPE_NET | INTR_MPSAFE, alc_intr, NULL, sc, 1640193880Syongari &sc->alc_intrhand[i]); 1641193880Syongari if (error != 0) 1642193880Syongari break; 1643193880Syongari } 1644193880Syongari if (error != 0) { 1645193880Syongari device_printf(dev, "could not set up interrupt handler.\n"); 1646193880Syongari taskqueue_free(sc->alc_tq); 1647193880Syongari sc->alc_tq = NULL; 1648193880Syongari ether_ifdetach(ifp); 1649193880Syongari goto fail; 1650193880Syongari } 1651193880Syongari 1652193880Syongarifail: 1653193880Syongari if (error != 0) 1654193880Syongari alc_detach(dev); 1655193880Syongari 1656193880Syongari return (error); 1657193880Syongari} 1658193880Syongari 1659193880Syongaristatic int 1660193880Syongarialc_detach(device_t dev) 1661193880Syongari{ 1662193880Syongari struct alc_softc *sc; 1663193880Syongari struct ifnet *ifp; 1664193880Syongari int i, msic; 1665193880Syongari 1666193880Syongari sc = device_get_softc(dev); 1667193880Syongari 1668193880Syongari ifp = sc->alc_ifp; 1669193880Syongari if (device_is_attached(dev)) { 1670217379Sjhb ether_ifdetach(ifp); 1671193880Syongari ALC_LOCK(sc); 1672193880Syongari alc_stop(sc); 1673193880Syongari ALC_UNLOCK(sc); 1674193880Syongari callout_drain(&sc->alc_tick_ch); 1675193880Syongari taskqueue_drain(sc->alc_tq, &sc->alc_int_task); 1676193880Syongari } 1677193880Syongari 1678193880Syongari if (sc->alc_tq != NULL) { 1679193880Syongari taskqueue_drain(sc->alc_tq, &sc->alc_int_task); 1680193880Syongari taskqueue_free(sc->alc_tq); 1681193880Syongari sc->alc_tq = NULL; 1682193880Syongari } 1683193880Syongari 1684193880Syongari if (sc->alc_miibus != NULL) { 1685193880Syongari device_delete_child(dev, sc->alc_miibus); 1686193880Syongari sc->alc_miibus = NULL; 1687193880Syongari } 1688193880Syongari bus_generic_detach(dev); 1689193880Syongari alc_dma_free(sc); 1690193880Syongari 1691193880Syongari if (ifp != NULL) { 1692193880Syongari if_free(ifp); 1693193880Syongari sc->alc_ifp = NULL; 1694193880Syongari } 1695193880Syongari 1696193880Syongari if ((sc->alc_flags & ALC_FLAG_MSIX) != 0) 1697193880Syongari msic = ALC_MSIX_MESSAGES; 1698193880Syongari else if ((sc->alc_flags & ALC_FLAG_MSI) != 0) 1699193880Syongari msic = ALC_MSI_MESSAGES; 1700193880Syongari else 1701193880Syongari msic = 1; 1702193880Syongari for (i = 0; i < msic; i++) { 1703193880Syongari if (sc->alc_intrhand[i] != NULL) { 1704193880Syongari bus_teardown_intr(dev, sc->alc_irq[i], 1705193880Syongari sc->alc_intrhand[i]); 1706193880Syongari sc->alc_intrhand[i] = NULL; 1707193880Syongari } 1708193880Syongari } 1709196517Syongari if (sc->alc_res[0] != NULL) 1710196517Syongari alc_phy_down(sc); 1711193880Syongari bus_release_resources(dev, sc->alc_irq_spec, sc->alc_irq); 1712193880Syongari if ((sc->alc_flags & (ALC_FLAG_MSI | ALC_FLAG_MSIX)) != 0) 1713193880Syongari pci_release_msi(dev); 1714193880Syongari bus_release_resources(dev, sc->alc_res_spec, sc->alc_res); 1715193880Syongari mtx_destroy(&sc->alc_mtx); 1716193880Syongari 1717193880Syongari return (0); 1718193880Syongari} 1719193880Syongari 1720193880Syongari#define ALC_SYSCTL_STAT_ADD32(c, h, n, p, d) \ 1721193880Syongari SYSCTL_ADD_UINT(c, h, OID_AUTO, n, CTLFLAG_RD, p, 0, d) 1722193880Syongari#define ALC_SYSCTL_STAT_ADD64(c, h, n, p, d) \ 1723217323Smdf SYSCTL_ADD_UQUAD(c, h, OID_AUTO, n, CTLFLAG_RD, p, d) 1724193880Syongari 1725193880Syongaristatic void 1726193880Syongarialc_sysctl_node(struct alc_softc *sc) 1727193880Syongari{ 1728193880Syongari struct sysctl_ctx_list *ctx; 1729193880Syongari struct sysctl_oid_list *child, *parent; 1730193880Syongari struct sysctl_oid *tree; 1731193880Syongari struct alc_hw_stats *stats; 1732193880Syongari int error; 1733193880Syongari 1734193880Syongari stats = &sc->alc_stats; 1735193880Syongari ctx = device_get_sysctl_ctx(sc->alc_dev); 1736193880Syongari child = SYSCTL_CHILDREN(device_get_sysctl_tree(sc->alc_dev)); 1737193880Syongari 1738193880Syongari SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "int_rx_mod", 1739193880Syongari CTLTYPE_INT | CTLFLAG_RW, &sc->alc_int_rx_mod, 0, 1740193880Syongari sysctl_hw_alc_int_mod, "I", "alc Rx interrupt moderation"); 1741193880Syongari SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "int_tx_mod", 1742193880Syongari CTLTYPE_INT | CTLFLAG_RW, &sc->alc_int_tx_mod, 0, 1743193880Syongari sysctl_hw_alc_int_mod, "I", "alc Tx interrupt moderation"); 1744193880Syongari /* Pull in device tunables. */ 1745193880Syongari sc->alc_int_rx_mod = ALC_IM_RX_TIMER_DEFAULT; 1746193880Syongari error = resource_int_value(device_get_name(sc->alc_dev), 1747193880Syongari device_get_unit(sc->alc_dev), "int_rx_mod", &sc->alc_int_rx_mod); 1748193880Syongari if (error == 0) { 1749193880Syongari if (sc->alc_int_rx_mod < ALC_IM_TIMER_MIN || 1750193880Syongari sc->alc_int_rx_mod > ALC_IM_TIMER_MAX) { 1751193880Syongari device_printf(sc->alc_dev, "int_rx_mod value out of " 1752193880Syongari "range; using default: %d\n", 1753193880Syongari ALC_IM_RX_TIMER_DEFAULT); 1754193880Syongari sc->alc_int_rx_mod = ALC_IM_RX_TIMER_DEFAULT; 1755193880Syongari } 1756193880Syongari } 1757193880Syongari sc->alc_int_tx_mod = ALC_IM_TX_TIMER_DEFAULT; 1758193880Syongari error = resource_int_value(device_get_name(sc->alc_dev), 1759193880Syongari device_get_unit(sc->alc_dev), "int_tx_mod", &sc->alc_int_tx_mod); 1760193880Syongari if (error == 0) { 1761193880Syongari if (sc->alc_int_tx_mod < ALC_IM_TIMER_MIN || 1762193880Syongari sc->alc_int_tx_mod > ALC_IM_TIMER_MAX) { 1763193880Syongari device_printf(sc->alc_dev, "int_tx_mod value out of " 1764193880Syongari "range; using default: %d\n", 1765193880Syongari ALC_IM_TX_TIMER_DEFAULT); 1766193880Syongari sc->alc_int_tx_mod = ALC_IM_TX_TIMER_DEFAULT; 1767193880Syongari } 1768193880Syongari } 1769193880Syongari SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "process_limit", 1770193880Syongari CTLTYPE_INT | CTLFLAG_RW, &sc->alc_process_limit, 0, 1771193880Syongari sysctl_hw_alc_proc_limit, "I", 1772193880Syongari "max number of Rx events to process"); 1773193880Syongari /* Pull in device tunables. */ 1774193880Syongari sc->alc_process_limit = ALC_PROC_DEFAULT; 1775193880Syongari error = resource_int_value(device_get_name(sc->alc_dev), 1776193880Syongari device_get_unit(sc->alc_dev), "process_limit", 1777193880Syongari &sc->alc_process_limit); 1778193880Syongari if (error == 0) { 1779193880Syongari if (sc->alc_process_limit < ALC_PROC_MIN || 1780193880Syongari sc->alc_process_limit > ALC_PROC_MAX) { 1781193880Syongari device_printf(sc->alc_dev, 1782193880Syongari "process_limit value out of range; " 1783193880Syongari "using default: %d\n", ALC_PROC_DEFAULT); 1784193880Syongari sc->alc_process_limit = ALC_PROC_DEFAULT; 1785193880Syongari } 1786193880Syongari } 1787193880Syongari 1788193880Syongari tree = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, "stats", CTLFLAG_RD, 1789193880Syongari NULL, "ALC statistics"); 1790193880Syongari parent = SYSCTL_CHILDREN(tree); 1791193880Syongari 1792193880Syongari /* Rx statistics. */ 1793193880Syongari tree = SYSCTL_ADD_NODE(ctx, parent, OID_AUTO, "rx", CTLFLAG_RD, 1794193880Syongari NULL, "Rx MAC statistics"); 1795193880Syongari child = SYSCTL_CHILDREN(tree); 1796193880Syongari ALC_SYSCTL_STAT_ADD32(ctx, child, "good_frames", 1797193880Syongari &stats->rx_frames, "Good frames"); 1798193880Syongari ALC_SYSCTL_STAT_ADD32(ctx, child, "good_bcast_frames", 1799193880Syongari &stats->rx_bcast_frames, "Good broadcast frames"); 1800193880Syongari ALC_SYSCTL_STAT_ADD32(ctx, child, "good_mcast_frames", 1801193880Syongari &stats->rx_mcast_frames, "Good multicast frames"); 1802193880Syongari ALC_SYSCTL_STAT_ADD32(ctx, child, "pause_frames", 1803193880Syongari &stats->rx_pause_frames, "Pause control frames"); 1804193880Syongari ALC_SYSCTL_STAT_ADD32(ctx, child, "control_frames", 1805193880Syongari &stats->rx_control_frames, "Control frames"); 1806193880Syongari ALC_SYSCTL_STAT_ADD32(ctx, child, "crc_errs", 1807193880Syongari &stats->rx_crcerrs, "CRC errors"); 1808193880Syongari ALC_SYSCTL_STAT_ADD32(ctx, child, "len_errs", 1809193880Syongari &stats->rx_lenerrs, "Frames with length mismatched"); 1810193880Syongari ALC_SYSCTL_STAT_ADD64(ctx, child, "good_octets", 1811193880Syongari &stats->rx_bytes, "Good octets"); 1812193880Syongari ALC_SYSCTL_STAT_ADD64(ctx, child, "good_bcast_octets", 1813193880Syongari &stats->rx_bcast_bytes, "Good broadcast octets"); 1814193880Syongari ALC_SYSCTL_STAT_ADD64(ctx, child, "good_mcast_octets", 1815193880Syongari &stats->rx_mcast_bytes, "Good multicast octets"); 1816193880Syongari ALC_SYSCTL_STAT_ADD32(ctx, child, "runts", 1817193880Syongari &stats->rx_runts, "Too short frames"); 1818193880Syongari ALC_SYSCTL_STAT_ADD32(ctx, child, "fragments", 1819193880Syongari &stats->rx_fragments, "Fragmented frames"); 1820193880Syongari ALC_SYSCTL_STAT_ADD32(ctx, child, "frames_64", 1821193880Syongari &stats->rx_pkts_64, "64 bytes frames"); 1822193880Syongari ALC_SYSCTL_STAT_ADD32(ctx, child, "frames_65_127", 1823193880Syongari &stats->rx_pkts_65_127, "65 to 127 bytes frames"); 1824193880Syongari ALC_SYSCTL_STAT_ADD32(ctx, child, "frames_128_255", 1825193880Syongari &stats->rx_pkts_128_255, "128 to 255 bytes frames"); 1826193880Syongari ALC_SYSCTL_STAT_ADD32(ctx, child, "frames_256_511", 1827193880Syongari &stats->rx_pkts_256_511, "256 to 511 bytes frames"); 1828193880Syongari ALC_SYSCTL_STAT_ADD32(ctx, child, "frames_512_1023", 1829193880Syongari &stats->rx_pkts_512_1023, "512 to 1023 bytes frames"); 1830193880Syongari ALC_SYSCTL_STAT_ADD32(ctx, child, "frames_1024_1518", 1831193880Syongari &stats->rx_pkts_1024_1518, "1024 to 1518 bytes frames"); 1832193880Syongari ALC_SYSCTL_STAT_ADD32(ctx, child, "frames_1519_max", 1833193880Syongari &stats->rx_pkts_1519_max, "1519 to max frames"); 1834193880Syongari ALC_SYSCTL_STAT_ADD32(ctx, child, "trunc_errs", 1835193880Syongari &stats->rx_pkts_truncated, "Truncated frames due to MTU size"); 1836193880Syongari ALC_SYSCTL_STAT_ADD32(ctx, child, "fifo_oflows", 1837193880Syongari &stats->rx_fifo_oflows, "FIFO overflows"); 1838193880Syongari ALC_SYSCTL_STAT_ADD32(ctx, child, "rrs_errs", 1839193880Syongari &stats->rx_rrs_errs, "Return status write-back errors"); 1840193880Syongari ALC_SYSCTL_STAT_ADD32(ctx, child, "align_errs", 1841193880Syongari &stats->rx_alignerrs, "Alignment errors"); 1842193880Syongari ALC_SYSCTL_STAT_ADD32(ctx, child, "filtered", 1843193880Syongari &stats->rx_pkts_filtered, 1844193880Syongari "Frames dropped due to address filtering"); 1845193880Syongari 1846193880Syongari /* Tx statistics. */ 1847193880Syongari tree = SYSCTL_ADD_NODE(ctx, parent, OID_AUTO, "tx", CTLFLAG_RD, 1848193880Syongari NULL, "Tx MAC statistics"); 1849193880Syongari child = SYSCTL_CHILDREN(tree); 1850193880Syongari ALC_SYSCTL_STAT_ADD32(ctx, child, "good_frames", 1851193880Syongari &stats->tx_frames, "Good frames"); 1852193880Syongari ALC_SYSCTL_STAT_ADD32(ctx, child, "good_bcast_frames", 1853193880Syongari &stats->tx_bcast_frames, "Good broadcast frames"); 1854193880Syongari ALC_SYSCTL_STAT_ADD32(ctx, child, "good_mcast_frames", 1855193880Syongari &stats->tx_mcast_frames, "Good multicast frames"); 1856193880Syongari ALC_SYSCTL_STAT_ADD32(ctx, child, "pause_frames", 1857193880Syongari &stats->tx_pause_frames, "Pause control frames"); 1858193880Syongari ALC_SYSCTL_STAT_ADD32(ctx, child, "control_frames", 1859193880Syongari &stats->tx_control_frames, "Control frames"); 1860193880Syongari ALC_SYSCTL_STAT_ADD32(ctx, child, "excess_defers", 1861193880Syongari &stats->tx_excess_defer, "Frames with excessive derferrals"); 1862193880Syongari ALC_SYSCTL_STAT_ADD32(ctx, child, "defers", 1863193880Syongari &stats->tx_excess_defer, "Frames with derferrals"); 1864193880Syongari ALC_SYSCTL_STAT_ADD64(ctx, child, "good_octets", 1865193880Syongari &stats->tx_bytes, "Good octets"); 1866193880Syongari ALC_SYSCTL_STAT_ADD64(ctx, child, "good_bcast_octets", 1867193880Syongari &stats->tx_bcast_bytes, "Good broadcast octets"); 1868193880Syongari ALC_SYSCTL_STAT_ADD64(ctx, child, "good_mcast_octets", 1869193880Syongari &stats->tx_mcast_bytes, "Good multicast octets"); 1870193880Syongari ALC_SYSCTL_STAT_ADD32(ctx, child, "frames_64", 1871193880Syongari &stats->tx_pkts_64, "64 bytes frames"); 1872193880Syongari ALC_SYSCTL_STAT_ADD32(ctx, child, "frames_65_127", 1873193880Syongari &stats->tx_pkts_65_127, "65 to 127 bytes frames"); 1874193880Syongari ALC_SYSCTL_STAT_ADD32(ctx, child, "frames_128_255", 1875193880Syongari &stats->tx_pkts_128_255, "128 to 255 bytes frames"); 1876193880Syongari ALC_SYSCTL_STAT_ADD32(ctx, child, "frames_256_511", 1877193880Syongari &stats->tx_pkts_256_511, "256 to 511 bytes frames"); 1878193880Syongari ALC_SYSCTL_STAT_ADD32(ctx, child, "frames_512_1023", 1879193880Syongari &stats->tx_pkts_512_1023, "512 to 1023 bytes frames"); 1880193880Syongari ALC_SYSCTL_STAT_ADD32(ctx, child, "frames_1024_1518", 1881193880Syongari &stats->tx_pkts_1024_1518, "1024 to 1518 bytes frames"); 1882193880Syongari ALC_SYSCTL_STAT_ADD32(ctx, child, "frames_1519_max", 1883193880Syongari &stats->tx_pkts_1519_max, "1519 to max frames"); 1884193880Syongari ALC_SYSCTL_STAT_ADD32(ctx, child, "single_colls", 1885193880Syongari &stats->tx_single_colls, "Single collisions"); 1886193880Syongari ALC_SYSCTL_STAT_ADD32(ctx, child, "multi_colls", 1887193880Syongari &stats->tx_multi_colls, "Multiple collisions"); 1888193880Syongari ALC_SYSCTL_STAT_ADD32(ctx, child, "late_colls", 1889193880Syongari &stats->tx_late_colls, "Late collisions"); 1890193880Syongari ALC_SYSCTL_STAT_ADD32(ctx, child, "excess_colls", 1891193880Syongari &stats->tx_excess_colls, "Excessive collisions"); 1892193880Syongari ALC_SYSCTL_STAT_ADD32(ctx, child, "underruns", 1893193880Syongari &stats->tx_underrun, "FIFO underruns"); 1894193880Syongari ALC_SYSCTL_STAT_ADD32(ctx, child, "desc_underruns", 1895193880Syongari &stats->tx_desc_underrun, "Descriptor write-back errors"); 1896193880Syongari ALC_SYSCTL_STAT_ADD32(ctx, child, "len_errs", 1897193880Syongari &stats->tx_lenerrs, "Frames with length mismatched"); 1898193880Syongari ALC_SYSCTL_STAT_ADD32(ctx, child, "trunc_errs", 1899193880Syongari &stats->tx_pkts_truncated, "Truncated frames due to MTU size"); 1900193880Syongari} 1901193880Syongari 1902193880Syongari#undef ALC_SYSCTL_STAT_ADD32 1903193880Syongari#undef ALC_SYSCTL_STAT_ADD64 1904193880Syongari 1905193880Syongaristruct alc_dmamap_arg { 1906193880Syongari bus_addr_t alc_busaddr; 1907193880Syongari}; 1908193880Syongari 1909193880Syongaristatic void 1910193880Syongarialc_dmamap_cb(void *arg, bus_dma_segment_t *segs, int nsegs, int error) 1911193880Syongari{ 1912193880Syongari struct alc_dmamap_arg *ctx; 1913193880Syongari 1914193880Syongari if (error != 0) 1915193880Syongari return; 1916193880Syongari 1917193880Syongari KASSERT(nsegs == 1, ("%s: %d segments returned!", __func__, nsegs)); 1918193880Syongari 1919193880Syongari ctx = (struct alc_dmamap_arg *)arg; 1920193880Syongari ctx->alc_busaddr = segs[0].ds_addr; 1921193880Syongari} 1922193880Syongari 1923193880Syongari/* 1924193880Syongari * Normal and high Tx descriptors shares single Tx high address. 1925193880Syongari * Four Rx descriptor/return rings and CMB shares the same Rx 1926193880Syongari * high address. 1927193880Syongari */ 1928193880Syongaristatic int 1929193880Syongarialc_check_boundary(struct alc_softc *sc) 1930193880Syongari{ 1931193880Syongari bus_addr_t cmb_end, rx_ring_end, rr_ring_end, tx_ring_end; 1932193880Syongari 1933193880Syongari rx_ring_end = sc->alc_rdata.alc_rx_ring_paddr + ALC_RX_RING_SZ; 1934193880Syongari rr_ring_end = sc->alc_rdata.alc_rr_ring_paddr + ALC_RR_RING_SZ; 1935193880Syongari cmb_end = sc->alc_rdata.alc_cmb_paddr + ALC_CMB_SZ; 1936193880Syongari tx_ring_end = sc->alc_rdata.alc_tx_ring_paddr + ALC_TX_RING_SZ; 1937193880Syongari 1938193880Syongari /* 4GB boundary crossing is not allowed. */ 1939193880Syongari if ((ALC_ADDR_HI(rx_ring_end) != 1940193880Syongari ALC_ADDR_HI(sc->alc_rdata.alc_rx_ring_paddr)) || 1941193880Syongari (ALC_ADDR_HI(rr_ring_end) != 1942193880Syongari ALC_ADDR_HI(sc->alc_rdata.alc_rr_ring_paddr)) || 1943193880Syongari (ALC_ADDR_HI(cmb_end) != 1944193880Syongari ALC_ADDR_HI(sc->alc_rdata.alc_cmb_paddr)) || 1945193880Syongari (ALC_ADDR_HI(tx_ring_end) != 1946193880Syongari ALC_ADDR_HI(sc->alc_rdata.alc_tx_ring_paddr))) 1947193880Syongari return (EFBIG); 1948193880Syongari /* 1949193880Syongari * Make sure Rx return descriptor/Rx descriptor/CMB use 1950193880Syongari * the same high address. 1951193880Syongari */ 1952193880Syongari if ((ALC_ADDR_HI(rx_ring_end) != ALC_ADDR_HI(rr_ring_end)) || 1953193880Syongari (ALC_ADDR_HI(rx_ring_end) != ALC_ADDR_HI(cmb_end))) 1954193880Syongari return (EFBIG); 1955193880Syongari 1956193880Syongari return (0); 1957193880Syongari} 1958193880Syongari 1959193880Syongaristatic int 1960193880Syongarialc_dma_alloc(struct alc_softc *sc) 1961193880Syongari{ 1962193880Syongari struct alc_txdesc *txd; 1963193880Syongari struct alc_rxdesc *rxd; 1964193880Syongari bus_addr_t lowaddr; 1965193880Syongari struct alc_dmamap_arg ctx; 1966193880Syongari int error, i; 1967193880Syongari 1968193880Syongari lowaddr = BUS_SPACE_MAXADDR; 1969193880Syongariagain: 1970193880Syongari /* Create parent DMA tag. */ 1971193880Syongari error = bus_dma_tag_create( 1972193880Syongari bus_get_dma_tag(sc->alc_dev), /* parent */ 1973193880Syongari 1, 0, /* alignment, boundary */ 1974193880Syongari lowaddr, /* lowaddr */ 1975193880Syongari BUS_SPACE_MAXADDR, /* highaddr */ 1976193880Syongari NULL, NULL, /* filter, filterarg */ 1977193880Syongari BUS_SPACE_MAXSIZE_32BIT, /* maxsize */ 1978193880Syongari 0, /* nsegments */ 1979193880Syongari BUS_SPACE_MAXSIZE_32BIT, /* maxsegsize */ 1980193880Syongari 0, /* flags */ 1981193880Syongari NULL, NULL, /* lockfunc, lockarg */ 1982193880Syongari &sc->alc_cdata.alc_parent_tag); 1983193880Syongari if (error != 0) { 1984193880Syongari device_printf(sc->alc_dev, 1985193880Syongari "could not create parent DMA tag.\n"); 1986193880Syongari goto fail; 1987193880Syongari } 1988193880Syongari 1989193880Syongari /* Create DMA tag for Tx descriptor ring. */ 1990193880Syongari error = bus_dma_tag_create( 1991193880Syongari sc->alc_cdata.alc_parent_tag, /* parent */ 1992193880Syongari ALC_TX_RING_ALIGN, 0, /* alignment, boundary */ 1993193880Syongari BUS_SPACE_MAXADDR, /* lowaddr */ 1994193880Syongari BUS_SPACE_MAXADDR, /* highaddr */ 1995193880Syongari NULL, NULL, /* filter, filterarg */ 1996193880Syongari ALC_TX_RING_SZ, /* maxsize */ 1997193880Syongari 1, /* nsegments */ 1998193880Syongari ALC_TX_RING_SZ, /* maxsegsize */ 1999193880Syongari 0, /* flags */ 2000193880Syongari NULL, NULL, /* lockfunc, lockarg */ 2001193880Syongari &sc->alc_cdata.alc_tx_ring_tag); 2002193880Syongari if (error != 0) { 2003193880Syongari device_printf(sc->alc_dev, 2004193880Syongari "could not create Tx ring DMA tag.\n"); 2005193880Syongari goto fail; 2006193880Syongari } 2007193880Syongari 2008193880Syongari /* Create DMA tag for Rx free descriptor ring. */ 2009193880Syongari error = bus_dma_tag_create( 2010193880Syongari sc->alc_cdata.alc_parent_tag, /* parent */ 2011193880Syongari ALC_RX_RING_ALIGN, 0, /* alignment, boundary */ 2012193880Syongari BUS_SPACE_MAXADDR, /* lowaddr */ 2013193880Syongari BUS_SPACE_MAXADDR, /* highaddr */ 2014193880Syongari NULL, NULL, /* filter, filterarg */ 2015193880Syongari ALC_RX_RING_SZ, /* maxsize */ 2016193880Syongari 1, /* nsegments */ 2017193880Syongari ALC_RX_RING_SZ, /* maxsegsize */ 2018193880Syongari 0, /* flags */ 2019193880Syongari NULL, NULL, /* lockfunc, lockarg */ 2020193880Syongari &sc->alc_cdata.alc_rx_ring_tag); 2021193880Syongari if (error != 0) { 2022193880Syongari device_printf(sc->alc_dev, 2023193880Syongari "could not create Rx ring DMA tag.\n"); 2024193880Syongari goto fail; 2025193880Syongari } 2026193880Syongari /* Create DMA tag for Rx return descriptor ring. */ 2027193880Syongari error = bus_dma_tag_create( 2028193880Syongari sc->alc_cdata.alc_parent_tag, /* parent */ 2029193880Syongari ALC_RR_RING_ALIGN, 0, /* alignment, boundary */ 2030193880Syongari BUS_SPACE_MAXADDR, /* lowaddr */ 2031193880Syongari BUS_SPACE_MAXADDR, /* highaddr */ 2032193880Syongari NULL, NULL, /* filter, filterarg */ 2033193880Syongari ALC_RR_RING_SZ, /* maxsize */ 2034193880Syongari 1, /* nsegments */ 2035193880Syongari ALC_RR_RING_SZ, /* maxsegsize */ 2036193880Syongari 0, /* flags */ 2037193880Syongari NULL, NULL, /* lockfunc, lockarg */ 2038193880Syongari &sc->alc_cdata.alc_rr_ring_tag); 2039193880Syongari if (error != 0) { 2040193880Syongari device_printf(sc->alc_dev, 2041193880Syongari "could not create Rx return ring DMA tag.\n"); 2042193880Syongari goto fail; 2043193880Syongari } 2044193880Syongari 2045193880Syongari /* Create DMA tag for coalescing message block. */ 2046193880Syongari error = bus_dma_tag_create( 2047193880Syongari sc->alc_cdata.alc_parent_tag, /* parent */ 2048193880Syongari ALC_CMB_ALIGN, 0, /* alignment, boundary */ 2049193880Syongari BUS_SPACE_MAXADDR, /* lowaddr */ 2050193880Syongari BUS_SPACE_MAXADDR, /* highaddr */ 2051193880Syongari NULL, NULL, /* filter, filterarg */ 2052193880Syongari ALC_CMB_SZ, /* maxsize */ 2053193880Syongari 1, /* nsegments */ 2054193880Syongari ALC_CMB_SZ, /* maxsegsize */ 2055193880Syongari 0, /* flags */ 2056193880Syongari NULL, NULL, /* lockfunc, lockarg */ 2057193880Syongari &sc->alc_cdata.alc_cmb_tag); 2058193880Syongari if (error != 0) { 2059193880Syongari device_printf(sc->alc_dev, 2060193880Syongari "could not create CMB DMA tag.\n"); 2061193880Syongari goto fail; 2062193880Syongari } 2063193880Syongari /* Create DMA tag for status message block. */ 2064193880Syongari error = bus_dma_tag_create( 2065193880Syongari sc->alc_cdata.alc_parent_tag, /* parent */ 2066193880Syongari ALC_SMB_ALIGN, 0, /* alignment, boundary */ 2067193880Syongari BUS_SPACE_MAXADDR, /* lowaddr */ 2068193880Syongari BUS_SPACE_MAXADDR, /* highaddr */ 2069193880Syongari NULL, NULL, /* filter, filterarg */ 2070193880Syongari ALC_SMB_SZ, /* maxsize */ 2071193880Syongari 1, /* nsegments */ 2072193880Syongari ALC_SMB_SZ, /* maxsegsize */ 2073193880Syongari 0, /* flags */ 2074193880Syongari NULL, NULL, /* lockfunc, lockarg */ 2075193880Syongari &sc->alc_cdata.alc_smb_tag); 2076193880Syongari if (error != 0) { 2077193880Syongari device_printf(sc->alc_dev, 2078193880Syongari "could not create SMB DMA tag.\n"); 2079193880Syongari goto fail; 2080193880Syongari } 2081193880Syongari 2082193880Syongari /* Allocate DMA'able memory and load the DMA map for Tx ring. */ 2083193880Syongari error = bus_dmamem_alloc(sc->alc_cdata.alc_tx_ring_tag, 2084193880Syongari (void **)&sc->alc_rdata.alc_tx_ring, 2085193880Syongari BUS_DMA_WAITOK | BUS_DMA_ZERO | BUS_DMA_COHERENT, 2086193880Syongari &sc->alc_cdata.alc_tx_ring_map); 2087193880Syongari if (error != 0) { 2088193880Syongari device_printf(sc->alc_dev, 2089193880Syongari "could not allocate DMA'able memory for Tx ring.\n"); 2090193880Syongari goto fail; 2091193880Syongari } 2092193880Syongari ctx.alc_busaddr = 0; 2093193880Syongari error = bus_dmamap_load(sc->alc_cdata.alc_tx_ring_tag, 2094193880Syongari sc->alc_cdata.alc_tx_ring_map, sc->alc_rdata.alc_tx_ring, 2095193880Syongari ALC_TX_RING_SZ, alc_dmamap_cb, &ctx, 0); 2096193880Syongari if (error != 0 || ctx.alc_busaddr == 0) { 2097193880Syongari device_printf(sc->alc_dev, 2098193880Syongari "could not load DMA'able memory for Tx ring.\n"); 2099193880Syongari goto fail; 2100193880Syongari } 2101193880Syongari sc->alc_rdata.alc_tx_ring_paddr = ctx.alc_busaddr; 2102193880Syongari 2103193880Syongari /* Allocate DMA'able memory and load the DMA map for Rx ring. */ 2104193880Syongari error = bus_dmamem_alloc(sc->alc_cdata.alc_rx_ring_tag, 2105193880Syongari (void **)&sc->alc_rdata.alc_rx_ring, 2106193880Syongari BUS_DMA_WAITOK | BUS_DMA_ZERO | BUS_DMA_COHERENT, 2107193880Syongari &sc->alc_cdata.alc_rx_ring_map); 2108193880Syongari if (error != 0) { 2109193880Syongari device_printf(sc->alc_dev, 2110193880Syongari "could not allocate DMA'able memory for Rx ring.\n"); 2111193880Syongari goto fail; 2112193880Syongari } 2113193880Syongari ctx.alc_busaddr = 0; 2114193880Syongari error = bus_dmamap_load(sc->alc_cdata.alc_rx_ring_tag, 2115193880Syongari sc->alc_cdata.alc_rx_ring_map, sc->alc_rdata.alc_rx_ring, 2116193880Syongari ALC_RX_RING_SZ, alc_dmamap_cb, &ctx, 0); 2117193880Syongari if (error != 0 || ctx.alc_busaddr == 0) { 2118193880Syongari device_printf(sc->alc_dev, 2119193880Syongari "could not load DMA'able memory for Rx ring.\n"); 2120193880Syongari goto fail; 2121193880Syongari } 2122193880Syongari sc->alc_rdata.alc_rx_ring_paddr = ctx.alc_busaddr; 2123193880Syongari 2124193880Syongari /* Allocate DMA'able memory and load the DMA map for Rx return ring. */ 2125193880Syongari error = bus_dmamem_alloc(sc->alc_cdata.alc_rr_ring_tag, 2126193880Syongari (void **)&sc->alc_rdata.alc_rr_ring, 2127193880Syongari BUS_DMA_WAITOK | BUS_DMA_ZERO | BUS_DMA_COHERENT, 2128193880Syongari &sc->alc_cdata.alc_rr_ring_map); 2129193880Syongari if (error != 0) { 2130193880Syongari device_printf(sc->alc_dev, 2131193880Syongari "could not allocate DMA'able memory for Rx return ring.\n"); 2132193880Syongari goto fail; 2133193880Syongari } 2134193880Syongari ctx.alc_busaddr = 0; 2135193880Syongari error = bus_dmamap_load(sc->alc_cdata.alc_rr_ring_tag, 2136193880Syongari sc->alc_cdata.alc_rr_ring_map, sc->alc_rdata.alc_rr_ring, 2137193880Syongari ALC_RR_RING_SZ, alc_dmamap_cb, &ctx, 0); 2138193880Syongari if (error != 0 || ctx.alc_busaddr == 0) { 2139193880Syongari device_printf(sc->alc_dev, 2140193880Syongari "could not load DMA'able memory for Tx ring.\n"); 2141193880Syongari goto fail; 2142193880Syongari } 2143193880Syongari sc->alc_rdata.alc_rr_ring_paddr = ctx.alc_busaddr; 2144193880Syongari 2145193880Syongari /* Allocate DMA'able memory and load the DMA map for CMB. */ 2146193880Syongari error = bus_dmamem_alloc(sc->alc_cdata.alc_cmb_tag, 2147193880Syongari (void **)&sc->alc_rdata.alc_cmb, 2148193880Syongari BUS_DMA_WAITOK | BUS_DMA_ZERO | BUS_DMA_COHERENT, 2149193880Syongari &sc->alc_cdata.alc_cmb_map); 2150193880Syongari if (error != 0) { 2151193880Syongari device_printf(sc->alc_dev, 2152193880Syongari "could not allocate DMA'able memory for CMB.\n"); 2153193880Syongari goto fail; 2154193880Syongari } 2155193880Syongari ctx.alc_busaddr = 0; 2156193880Syongari error = bus_dmamap_load(sc->alc_cdata.alc_cmb_tag, 2157193880Syongari sc->alc_cdata.alc_cmb_map, sc->alc_rdata.alc_cmb, 2158193880Syongari ALC_CMB_SZ, alc_dmamap_cb, &ctx, 0); 2159193880Syongari if (error != 0 || ctx.alc_busaddr == 0) { 2160193880Syongari device_printf(sc->alc_dev, 2161193880Syongari "could not load DMA'able memory for CMB.\n"); 2162193880Syongari goto fail; 2163193880Syongari } 2164193880Syongari sc->alc_rdata.alc_cmb_paddr = ctx.alc_busaddr; 2165193880Syongari 2166193880Syongari /* Allocate DMA'able memory and load the DMA map for SMB. */ 2167193880Syongari error = bus_dmamem_alloc(sc->alc_cdata.alc_smb_tag, 2168193880Syongari (void **)&sc->alc_rdata.alc_smb, 2169193880Syongari BUS_DMA_WAITOK | BUS_DMA_ZERO | BUS_DMA_COHERENT, 2170193880Syongari &sc->alc_cdata.alc_smb_map); 2171193880Syongari if (error != 0) { 2172193880Syongari device_printf(sc->alc_dev, 2173193880Syongari "could not allocate DMA'able memory for SMB.\n"); 2174193880Syongari goto fail; 2175193880Syongari } 2176193880Syongari ctx.alc_busaddr = 0; 2177193880Syongari error = bus_dmamap_load(sc->alc_cdata.alc_smb_tag, 2178193880Syongari sc->alc_cdata.alc_smb_map, sc->alc_rdata.alc_smb, 2179193880Syongari ALC_SMB_SZ, alc_dmamap_cb, &ctx, 0); 2180193880Syongari if (error != 0 || ctx.alc_busaddr == 0) { 2181193880Syongari device_printf(sc->alc_dev, 2182193880Syongari "could not load DMA'able memory for CMB.\n"); 2183193880Syongari goto fail; 2184193880Syongari } 2185193880Syongari sc->alc_rdata.alc_smb_paddr = ctx.alc_busaddr; 2186193880Syongari 2187193880Syongari /* Make sure we've not crossed 4GB boundary. */ 2188193880Syongari if (lowaddr != BUS_SPACE_MAXADDR_32BIT && 2189193880Syongari (error = alc_check_boundary(sc)) != 0) { 2190193880Syongari device_printf(sc->alc_dev, "4GB boundary crossed, " 2191193880Syongari "switching to 32bit DMA addressing mode.\n"); 2192193880Syongari alc_dma_free(sc); 2193193880Syongari /* 2194193880Syongari * Limit max allowable DMA address space to 32bit 2195193880Syongari * and try again. 2196193880Syongari */ 2197193880Syongari lowaddr = BUS_SPACE_MAXADDR_32BIT; 2198193880Syongari goto again; 2199193880Syongari } 2200193880Syongari 2201193880Syongari /* 2202193880Syongari * Create Tx buffer parent tag. 2203272730Syongari * AR81[3567]x allows 64bit DMA addressing of Tx/Rx buffers 2204193880Syongari * so it needs separate parent DMA tag as parent DMA address 2205193880Syongari * space could be restricted to be within 32bit address space 2206193880Syongari * by 4GB boundary crossing. 2207193880Syongari */ 2208193880Syongari error = bus_dma_tag_create( 2209193880Syongari bus_get_dma_tag(sc->alc_dev), /* parent */ 2210193880Syongari 1, 0, /* alignment, boundary */ 2211193880Syongari BUS_SPACE_MAXADDR, /* lowaddr */ 2212193880Syongari BUS_SPACE_MAXADDR, /* highaddr */ 2213193880Syongari NULL, NULL, /* filter, filterarg */ 2214193880Syongari BUS_SPACE_MAXSIZE_32BIT, /* maxsize */ 2215193880Syongari 0, /* nsegments */ 2216193880Syongari BUS_SPACE_MAXSIZE_32BIT, /* maxsegsize */ 2217193880Syongari 0, /* flags */ 2218193880Syongari NULL, NULL, /* lockfunc, lockarg */ 2219193880Syongari &sc->alc_cdata.alc_buffer_tag); 2220193880Syongari if (error != 0) { 2221193880Syongari device_printf(sc->alc_dev, 2222193880Syongari "could not create parent buffer DMA tag.\n"); 2223193880Syongari goto fail; 2224193880Syongari } 2225193880Syongari 2226193880Syongari /* Create DMA tag for Tx buffers. */ 2227193880Syongari error = bus_dma_tag_create( 2228193880Syongari sc->alc_cdata.alc_buffer_tag, /* parent */ 2229193880Syongari 1, 0, /* alignment, boundary */ 2230193880Syongari BUS_SPACE_MAXADDR, /* lowaddr */ 2231193880Syongari BUS_SPACE_MAXADDR, /* highaddr */ 2232193880Syongari NULL, NULL, /* filter, filterarg */ 2233193880Syongari ALC_TSO_MAXSIZE, /* maxsize */ 2234193880Syongari ALC_MAXTXSEGS, /* nsegments */ 2235193880Syongari ALC_TSO_MAXSEGSIZE, /* maxsegsize */ 2236193880Syongari 0, /* flags */ 2237193880Syongari NULL, NULL, /* lockfunc, lockarg */ 2238193880Syongari &sc->alc_cdata.alc_tx_tag); 2239193880Syongari if (error != 0) { 2240193880Syongari device_printf(sc->alc_dev, "could not create Tx DMA tag.\n"); 2241193880Syongari goto fail; 2242193880Syongari } 2243193880Syongari 2244193880Syongari /* Create DMA tag for Rx buffers. */ 2245193880Syongari error = bus_dma_tag_create( 2246193880Syongari sc->alc_cdata.alc_buffer_tag, /* parent */ 2247193880Syongari ALC_RX_BUF_ALIGN, 0, /* alignment, boundary */ 2248193880Syongari BUS_SPACE_MAXADDR, /* lowaddr */ 2249193880Syongari BUS_SPACE_MAXADDR, /* highaddr */ 2250193880Syongari NULL, NULL, /* filter, filterarg */ 2251193880Syongari MCLBYTES, /* maxsize */ 2252193880Syongari 1, /* nsegments */ 2253193880Syongari MCLBYTES, /* maxsegsize */ 2254193880Syongari 0, /* flags */ 2255193880Syongari NULL, NULL, /* lockfunc, lockarg */ 2256193880Syongari &sc->alc_cdata.alc_rx_tag); 2257193880Syongari if (error != 0) { 2258193880Syongari device_printf(sc->alc_dev, "could not create Rx DMA tag.\n"); 2259193880Syongari goto fail; 2260193880Syongari } 2261193880Syongari /* Create DMA maps for Tx buffers. */ 2262193880Syongari for (i = 0; i < ALC_TX_RING_CNT; i++) { 2263193880Syongari txd = &sc->alc_cdata.alc_txdesc[i]; 2264193880Syongari txd->tx_m = NULL; 2265193880Syongari txd->tx_dmamap = NULL; 2266193880Syongari error = bus_dmamap_create(sc->alc_cdata.alc_tx_tag, 0, 2267193880Syongari &txd->tx_dmamap); 2268193880Syongari if (error != 0) { 2269193880Syongari device_printf(sc->alc_dev, 2270193880Syongari "could not create Tx dmamap.\n"); 2271193880Syongari goto fail; 2272193880Syongari } 2273193880Syongari } 2274193880Syongari /* Create DMA maps for Rx buffers. */ 2275193880Syongari if ((error = bus_dmamap_create(sc->alc_cdata.alc_rx_tag, 0, 2276193880Syongari &sc->alc_cdata.alc_rx_sparemap)) != 0) { 2277193880Syongari device_printf(sc->alc_dev, 2278193880Syongari "could not create spare Rx dmamap.\n"); 2279193880Syongari goto fail; 2280193880Syongari } 2281193880Syongari for (i = 0; i < ALC_RX_RING_CNT; i++) { 2282193880Syongari rxd = &sc->alc_cdata.alc_rxdesc[i]; 2283193880Syongari rxd->rx_m = NULL; 2284193880Syongari rxd->rx_dmamap = NULL; 2285193880Syongari error = bus_dmamap_create(sc->alc_cdata.alc_rx_tag, 0, 2286193880Syongari &rxd->rx_dmamap); 2287193880Syongari if (error != 0) { 2288193880Syongari device_printf(sc->alc_dev, 2289193880Syongari "could not create Rx dmamap.\n"); 2290193880Syongari goto fail; 2291193880Syongari } 2292193880Syongari } 2293193880Syongari 2294193880Syongarifail: 2295193880Syongari return (error); 2296193880Syongari} 2297193880Syongari 2298193880Syongaristatic void 2299193880Syongarialc_dma_free(struct alc_softc *sc) 2300193880Syongari{ 2301193880Syongari struct alc_txdesc *txd; 2302193880Syongari struct alc_rxdesc *rxd; 2303193880Syongari int i; 2304193880Syongari 2305193880Syongari /* Tx buffers. */ 2306193880Syongari if (sc->alc_cdata.alc_tx_tag != NULL) { 2307193880Syongari for (i = 0; i < ALC_TX_RING_CNT; i++) { 2308193880Syongari txd = &sc->alc_cdata.alc_txdesc[i]; 2309193880Syongari if (txd->tx_dmamap != NULL) { 2310193880Syongari bus_dmamap_destroy(sc->alc_cdata.alc_tx_tag, 2311193880Syongari txd->tx_dmamap); 2312193880Syongari txd->tx_dmamap = NULL; 2313193880Syongari } 2314193880Syongari } 2315193880Syongari bus_dma_tag_destroy(sc->alc_cdata.alc_tx_tag); 2316193880Syongari sc->alc_cdata.alc_tx_tag = NULL; 2317193880Syongari } 2318193880Syongari /* Rx buffers */ 2319193880Syongari if (sc->alc_cdata.alc_rx_tag != NULL) { 2320193880Syongari for (i = 0; i < ALC_RX_RING_CNT; i++) { 2321193880Syongari rxd = &sc->alc_cdata.alc_rxdesc[i]; 2322193880Syongari if (rxd->rx_dmamap != NULL) { 2323193880Syongari bus_dmamap_destroy(sc->alc_cdata.alc_rx_tag, 2324193880Syongari rxd->rx_dmamap); 2325193880Syongari rxd->rx_dmamap = NULL; 2326193880Syongari } 2327193880Syongari } 2328193880Syongari if (sc->alc_cdata.alc_rx_sparemap != NULL) { 2329193880Syongari bus_dmamap_destroy(sc->alc_cdata.alc_rx_tag, 2330193880Syongari sc->alc_cdata.alc_rx_sparemap); 2331193880Syongari sc->alc_cdata.alc_rx_sparemap = NULL; 2332193880Syongari } 2333193880Syongari bus_dma_tag_destroy(sc->alc_cdata.alc_rx_tag); 2334193880Syongari sc->alc_cdata.alc_rx_tag = NULL; 2335193880Syongari } 2336193880Syongari /* Tx descriptor ring. */ 2337193880Syongari if (sc->alc_cdata.alc_tx_ring_tag != NULL) { 2338267363Sjhb if (sc->alc_rdata.alc_tx_ring_paddr != 0) 2339193880Syongari bus_dmamap_unload(sc->alc_cdata.alc_tx_ring_tag, 2340193880Syongari sc->alc_cdata.alc_tx_ring_map); 2341267363Sjhb if (sc->alc_rdata.alc_tx_ring != NULL) 2342193880Syongari bus_dmamem_free(sc->alc_cdata.alc_tx_ring_tag, 2343193880Syongari sc->alc_rdata.alc_tx_ring, 2344193880Syongari sc->alc_cdata.alc_tx_ring_map); 2345267363Sjhb sc->alc_rdata.alc_tx_ring_paddr = 0; 2346193880Syongari sc->alc_rdata.alc_tx_ring = NULL; 2347193880Syongari bus_dma_tag_destroy(sc->alc_cdata.alc_tx_ring_tag); 2348193880Syongari sc->alc_cdata.alc_tx_ring_tag = NULL; 2349193880Syongari } 2350195989Skevlo /* Rx ring. */ 2351195989Skevlo if (sc->alc_cdata.alc_rx_ring_tag != NULL) { 2352267363Sjhb if (sc->alc_rdata.alc_rx_ring_paddr != 0) 2353195989Skevlo bus_dmamap_unload(sc->alc_cdata.alc_rx_ring_tag, 2354195989Skevlo sc->alc_cdata.alc_rx_ring_map); 2355267363Sjhb if (sc->alc_rdata.alc_rx_ring != NULL) 2356195989Skevlo bus_dmamem_free(sc->alc_cdata.alc_rx_ring_tag, 2357195989Skevlo sc->alc_rdata.alc_rx_ring, 2358195989Skevlo sc->alc_cdata.alc_rx_ring_map); 2359267363Sjhb sc->alc_rdata.alc_rx_ring_paddr = 0; 2360195989Skevlo sc->alc_rdata.alc_rx_ring = NULL; 2361195989Skevlo bus_dma_tag_destroy(sc->alc_cdata.alc_rx_ring_tag); 2362195989Skevlo sc->alc_cdata.alc_rx_ring_tag = NULL; 2363195989Skevlo } 2364193880Syongari /* Rx return ring. */ 2365193880Syongari if (sc->alc_cdata.alc_rr_ring_tag != NULL) { 2366267363Sjhb if (sc->alc_rdata.alc_rr_ring_paddr != 0) 2367193880Syongari bus_dmamap_unload(sc->alc_cdata.alc_rr_ring_tag, 2368193880Syongari sc->alc_cdata.alc_rr_ring_map); 2369267363Sjhb if (sc->alc_rdata.alc_rr_ring != NULL) 2370193880Syongari bus_dmamem_free(sc->alc_cdata.alc_rr_ring_tag, 2371193880Syongari sc->alc_rdata.alc_rr_ring, 2372193880Syongari sc->alc_cdata.alc_rr_ring_map); 2373267363Sjhb sc->alc_rdata.alc_rr_ring_paddr = 0; 2374193880Syongari sc->alc_rdata.alc_rr_ring = NULL; 2375193880Syongari bus_dma_tag_destroy(sc->alc_cdata.alc_rr_ring_tag); 2376193880Syongari sc->alc_cdata.alc_rr_ring_tag = NULL; 2377193880Syongari } 2378193880Syongari /* CMB block */ 2379193880Syongari if (sc->alc_cdata.alc_cmb_tag != NULL) { 2380267363Sjhb if (sc->alc_rdata.alc_cmb_paddr != 0) 2381193880Syongari bus_dmamap_unload(sc->alc_cdata.alc_cmb_tag, 2382193880Syongari sc->alc_cdata.alc_cmb_map); 2383267363Sjhb if (sc->alc_rdata.alc_cmb != NULL) 2384193880Syongari bus_dmamem_free(sc->alc_cdata.alc_cmb_tag, 2385193880Syongari sc->alc_rdata.alc_cmb, 2386267363Sjhb sc->alc_cdata.alc_cmb_map); 2387267363Sjhb sc->alc_rdata.alc_cmb_paddr = 0; 2388193880Syongari sc->alc_rdata.alc_cmb = NULL; 2389193880Syongari bus_dma_tag_destroy(sc->alc_cdata.alc_cmb_tag); 2390193880Syongari sc->alc_cdata.alc_cmb_tag = NULL; 2391193880Syongari } 2392193880Syongari /* SMB block */ 2393193880Syongari if (sc->alc_cdata.alc_smb_tag != NULL) { 2394267363Sjhb if (sc->alc_rdata.alc_smb_paddr != 0) 2395193880Syongari bus_dmamap_unload(sc->alc_cdata.alc_smb_tag, 2396193880Syongari sc->alc_cdata.alc_smb_map); 2397267363Sjhb if (sc->alc_rdata.alc_smb != NULL) 2398193880Syongari bus_dmamem_free(sc->alc_cdata.alc_smb_tag, 2399193880Syongari sc->alc_rdata.alc_smb, 2400193880Syongari sc->alc_cdata.alc_smb_map); 2401267363Sjhb sc->alc_rdata.alc_smb_paddr = 0; 2402193880Syongari sc->alc_rdata.alc_smb = NULL; 2403193880Syongari bus_dma_tag_destroy(sc->alc_cdata.alc_smb_tag); 2404193880Syongari sc->alc_cdata.alc_smb_tag = NULL; 2405193880Syongari } 2406193880Syongari if (sc->alc_cdata.alc_buffer_tag != NULL) { 2407193880Syongari bus_dma_tag_destroy(sc->alc_cdata.alc_buffer_tag); 2408193880Syongari sc->alc_cdata.alc_buffer_tag = NULL; 2409193880Syongari } 2410193880Syongari if (sc->alc_cdata.alc_parent_tag != NULL) { 2411193880Syongari bus_dma_tag_destroy(sc->alc_cdata.alc_parent_tag); 2412193880Syongari sc->alc_cdata.alc_parent_tag = NULL; 2413193880Syongari } 2414193880Syongari} 2415193880Syongari 2416193880Syongaristatic int 2417193880Syongarialc_shutdown(device_t dev) 2418193880Syongari{ 2419193880Syongari 2420193880Syongari return (alc_suspend(dev)); 2421193880Syongari} 2422193880Syongari 2423193880Syongari/* 2424193880Syongari * Note, this driver resets the link speed to 10/100Mbps by 2425193880Syongari * restarting auto-negotiation in suspend/shutdown phase but we 2426193880Syongari * don't know whether that auto-negotiation would succeed or not 2427193880Syongari * as driver has no control after powering off/suspend operation. 2428193880Syongari * If the renegotiation fail WOL may not work. Running at 1Gbps 2429193880Syongari * will draw more power than 375mA at 3.3V which is specified in 2430193880Syongari * PCI specification and that would result in complete 2431193880Syongari * shutdowning power to ethernet controller. 2432193880Syongari * 2433193880Syongari * TODO 2434193880Syongari * Save current negotiated media speed/duplex/flow-control to 2435193880Syongari * softc and restore the same link again after resuming. PHY 2436193880Syongari * handling such as power down/resetting to 100Mbps may be better 2437193880Syongari * handled in suspend method in phy driver. 2438193880Syongari */ 2439193880Syongaristatic void 2440193880Syongarialc_setlinkspeed(struct alc_softc *sc) 2441193880Syongari{ 2442193880Syongari struct mii_data *mii; 2443193880Syongari int aneg, i; 2444193880Syongari 2445193880Syongari mii = device_get_softc(sc->alc_miibus); 2446193880Syongari mii_pollstat(mii); 2447193880Syongari aneg = 0; 2448193880Syongari if ((mii->mii_media_status & (IFM_ACTIVE | IFM_AVALID)) == 2449193880Syongari (IFM_ACTIVE | IFM_AVALID)) { 2450193880Syongari switch IFM_SUBTYPE(mii->mii_media_active) { 2451193880Syongari case IFM_10_T: 2452193880Syongari case IFM_100_TX: 2453193880Syongari return; 2454193880Syongari case IFM_1000_T: 2455193880Syongari aneg++; 2456193880Syongari break; 2457193880Syongari default: 2458193880Syongari break; 2459193880Syongari } 2460193880Syongari } 2461193880Syongari alc_miibus_writereg(sc->alc_dev, sc->alc_phyaddr, MII_100T2CR, 0); 2462193880Syongari alc_miibus_writereg(sc->alc_dev, sc->alc_phyaddr, 2463193880Syongari MII_ANAR, ANAR_TX_FD | ANAR_TX | ANAR_10_FD | ANAR_10 | ANAR_CSMA); 2464193880Syongari alc_miibus_writereg(sc->alc_dev, sc->alc_phyaddr, 2465193880Syongari MII_BMCR, BMCR_RESET | BMCR_AUTOEN | BMCR_STARTNEG); 2466193880Syongari DELAY(1000); 2467193880Syongari if (aneg != 0) { 2468193880Syongari /* 2469193880Syongari * Poll link state until alc(4) get a 10/100Mbps link. 2470193880Syongari */ 2471193880Syongari for (i = 0; i < MII_ANEGTICKS_GIGE; i++) { 2472193880Syongari mii_pollstat(mii); 2473193880Syongari if ((mii->mii_media_status & (IFM_ACTIVE | IFM_AVALID)) 2474193880Syongari == (IFM_ACTIVE | IFM_AVALID)) { 2475193880Syongari switch (IFM_SUBTYPE( 2476193880Syongari mii->mii_media_active)) { 2477193880Syongari case IFM_10_T: 2478193880Syongari case IFM_100_TX: 2479193880Syongari alc_mac_config(sc); 2480193880Syongari return; 2481193880Syongari default: 2482193880Syongari break; 2483193880Syongari } 2484193880Syongari } 2485193880Syongari ALC_UNLOCK(sc); 2486193880Syongari pause("alclnk", hz); 2487193880Syongari ALC_LOCK(sc); 2488193880Syongari } 2489193880Syongari if (i == MII_ANEGTICKS_GIGE) 2490193880Syongari device_printf(sc->alc_dev, 2491193880Syongari "establishing a link failed, WOL may not work!"); 2492193880Syongari } 2493193880Syongari /* 2494193880Syongari * No link, force MAC to have 100Mbps, full-duplex link. 2495193880Syongari * This is the last resort and may/may not work. 2496193880Syongari */ 2497193880Syongari mii->mii_media_status = IFM_AVALID | IFM_ACTIVE; 2498193880Syongari mii->mii_media_active = IFM_ETHER | IFM_100_TX | IFM_FDX; 2499193880Syongari alc_mac_config(sc); 2500193880Syongari} 2501193880Syongari 2502193880Syongaristatic void 2503193880Syongarialc_setwol(struct alc_softc *sc) 2504193880Syongari{ 2505272730Syongari 2506272730Syongari if ((sc->alc_flags & ALC_FLAG_AR816X_FAMILY) != 0) 2507272730Syongari alc_setwol_816x(sc); 2508272730Syongari else 2509272730Syongari alc_setwol_813x(sc); 2510272730Syongari} 2511272730Syongari 2512272730Syongaristatic void 2513272730Syongarialc_setwol_813x(struct alc_softc *sc) 2514272730Syongari{ 2515193880Syongari struct ifnet *ifp; 2516211051Syongari uint32_t reg, pmcs; 2517193880Syongari uint16_t pmstat; 2518193880Syongari 2519193880Syongari ALC_LOCK_ASSERT(sc); 2520193880Syongari 2521211051Syongari alc_disable_l0s_l1(sc); 2522211051Syongari ifp = sc->alc_ifp; 2523211053Syongari if ((sc->alc_flags & ALC_FLAG_PM) == 0) { 2524193880Syongari /* Disable WOL. */ 2525193880Syongari CSR_WRITE_4(sc, ALC_WOL_CFG, 0); 2526193880Syongari reg = CSR_READ_4(sc, ALC_PCIE_PHYMISC); 2527193880Syongari reg |= PCIE_PHYMISC_FORCE_RCV_DET; 2528193880Syongari CSR_WRITE_4(sc, ALC_PCIE_PHYMISC, reg); 2529193880Syongari /* Force PHY power down. */ 2530193880Syongari alc_phy_down(sc); 2531211051Syongari CSR_WRITE_4(sc, ALC_MASTER_CFG, 2532211051Syongari CSR_READ_4(sc, ALC_MASTER_CFG) | MASTER_CLK_SEL_DIS); 2533193880Syongari return; 2534193880Syongari } 2535193880Syongari 2536193880Syongari if ((ifp->if_capenable & IFCAP_WOL) != 0) { 2537193880Syongari if ((sc->alc_flags & ALC_FLAG_FASTETHER) == 0) 2538193880Syongari alc_setlinkspeed(sc); 2539211051Syongari CSR_WRITE_4(sc, ALC_MASTER_CFG, 2540211051Syongari CSR_READ_4(sc, ALC_MASTER_CFG) & ~MASTER_CLK_SEL_DIS); 2541193880Syongari } 2542193880Syongari 2543193880Syongari pmcs = 0; 2544193880Syongari if ((ifp->if_capenable & IFCAP_WOL_MAGIC) != 0) 2545193880Syongari pmcs |= WOL_CFG_MAGIC | WOL_CFG_MAGIC_ENB; 2546193880Syongari CSR_WRITE_4(sc, ALC_WOL_CFG, pmcs); 2547193880Syongari reg = CSR_READ_4(sc, ALC_MAC_CFG); 2548193880Syongari reg &= ~(MAC_CFG_DBG | MAC_CFG_PROMISC | MAC_CFG_ALLMULTI | 2549193880Syongari MAC_CFG_BCAST); 2550193880Syongari if ((ifp->if_capenable & IFCAP_WOL_MCAST) != 0) 2551193880Syongari reg |= MAC_CFG_ALLMULTI | MAC_CFG_BCAST; 2552193880Syongari if ((ifp->if_capenable & IFCAP_WOL) != 0) 2553193880Syongari reg |= MAC_CFG_RX_ENB; 2554193880Syongari CSR_WRITE_4(sc, ALC_MAC_CFG, reg); 2555193880Syongari 2556193880Syongari reg = CSR_READ_4(sc, ALC_PCIE_PHYMISC); 2557193880Syongari reg |= PCIE_PHYMISC_FORCE_RCV_DET; 2558193880Syongari CSR_WRITE_4(sc, ALC_PCIE_PHYMISC, reg); 2559193880Syongari if ((ifp->if_capenable & IFCAP_WOL) == 0) { 2560193880Syongari /* WOL disabled, PHY power down. */ 2561193880Syongari alc_phy_down(sc); 2562211051Syongari CSR_WRITE_4(sc, ALC_MASTER_CFG, 2563211051Syongari CSR_READ_4(sc, ALC_MASTER_CFG) | MASTER_CLK_SEL_DIS); 2564193880Syongari } 2565193880Syongari /* Request PME. */ 2566211053Syongari pmstat = pci_read_config(sc->alc_dev, 2567211053Syongari sc->alc_pmcap + PCIR_POWER_STATUS, 2); 2568193880Syongari pmstat &= ~(PCIM_PSTAT_PME | PCIM_PSTAT_PMEENABLE); 2569193880Syongari if ((ifp->if_capenable & IFCAP_WOL) != 0) 2570193880Syongari pmstat |= PCIM_PSTAT_PME | PCIM_PSTAT_PMEENABLE; 2571211053Syongari pci_write_config(sc->alc_dev, 2572211053Syongari sc->alc_pmcap + PCIR_POWER_STATUS, pmstat, 2); 2573193880Syongari} 2574193880Syongari 2575272730Syongaristatic void 2576272730Syongarialc_setwol_816x(struct alc_softc *sc) 2577272730Syongari{ 2578272730Syongari struct ifnet *ifp; 2579272730Syongari uint32_t gphy, mac, master, pmcs, reg; 2580272730Syongari uint16_t pmstat; 2581272730Syongari 2582272730Syongari ALC_LOCK_ASSERT(sc); 2583272730Syongari 2584272730Syongari ifp = sc->alc_ifp; 2585272730Syongari master = CSR_READ_4(sc, ALC_MASTER_CFG); 2586272730Syongari master &= ~MASTER_CLK_SEL_DIS; 2587272730Syongari gphy = CSR_READ_4(sc, ALC_GPHY_CFG); 2588272730Syongari gphy &= ~(GPHY_CFG_EXT_RESET | GPHY_CFG_LED_MODE | GPHY_CFG_100AB_ENB | 2589272730Syongari GPHY_CFG_PHY_PLL_ON); 2590272730Syongari gphy |= GPHY_CFG_HIB_EN | GPHY_CFG_HIB_PULSE | GPHY_CFG_SEL_ANA_RESET; 2591272730Syongari if ((sc->alc_flags & ALC_FLAG_PM) == 0) { 2592272730Syongari CSR_WRITE_4(sc, ALC_WOL_CFG, 0); 2593272730Syongari gphy |= GPHY_CFG_PHY_IDDQ | GPHY_CFG_PWDOWN_HW; 2594272730Syongari mac = CSR_READ_4(sc, ALC_MAC_CFG); 2595272730Syongari } else { 2596272730Syongari if ((ifp->if_capenable & IFCAP_WOL) != 0) { 2597272730Syongari gphy |= GPHY_CFG_EXT_RESET; 2598272730Syongari if ((sc->alc_flags & ALC_FLAG_FASTETHER) == 0) 2599272730Syongari alc_setlinkspeed(sc); 2600272730Syongari } 2601272730Syongari pmcs = 0; 2602272730Syongari if ((ifp->if_capenable & IFCAP_WOL_MAGIC) != 0) 2603272730Syongari pmcs |= WOL_CFG_MAGIC | WOL_CFG_MAGIC_ENB; 2604272730Syongari CSR_WRITE_4(sc, ALC_WOL_CFG, pmcs); 2605272730Syongari mac = CSR_READ_4(sc, ALC_MAC_CFG); 2606272730Syongari mac &= ~(MAC_CFG_DBG | MAC_CFG_PROMISC | MAC_CFG_ALLMULTI | 2607272730Syongari MAC_CFG_BCAST); 2608272730Syongari if ((ifp->if_capenable & IFCAP_WOL_MCAST) != 0) 2609272730Syongari mac |= MAC_CFG_ALLMULTI | MAC_CFG_BCAST; 2610272730Syongari if ((ifp->if_capenable & IFCAP_WOL) != 0) 2611272730Syongari mac |= MAC_CFG_RX_ENB; 2612272730Syongari alc_miiext_writereg(sc, MII_EXT_ANEG, MII_EXT_ANEG_S3DIG10, 2613272730Syongari ANEG_S3DIG10_SL); 2614272730Syongari } 2615272730Syongari 2616272730Syongari /* Enable OSC. */ 2617272730Syongari reg = CSR_READ_4(sc, ALC_MISC); 2618272730Syongari reg &= ~MISC_INTNLOSC_OPEN; 2619272730Syongari CSR_WRITE_4(sc, ALC_MISC, reg); 2620272730Syongari reg |= MISC_INTNLOSC_OPEN; 2621272730Syongari CSR_WRITE_4(sc, ALC_MISC, reg); 2622272730Syongari CSR_WRITE_4(sc, ALC_MASTER_CFG, master); 2623272730Syongari CSR_WRITE_4(sc, ALC_MAC_CFG, mac); 2624272730Syongari CSR_WRITE_4(sc, ALC_GPHY_CFG, gphy); 2625272730Syongari reg = CSR_READ_4(sc, ALC_PDLL_TRNS1); 2626272730Syongari reg |= PDLL_TRNS1_D3PLLOFF_ENB; 2627272730Syongari CSR_WRITE_4(sc, ALC_PDLL_TRNS1, reg); 2628272730Syongari 2629272730Syongari if ((sc->alc_flags & ALC_FLAG_PM) != 0) { 2630272730Syongari /* Request PME. */ 2631272730Syongari pmstat = pci_read_config(sc->alc_dev, 2632272730Syongari sc->alc_pmcap + PCIR_POWER_STATUS, 2); 2633272730Syongari pmstat &= ~(PCIM_PSTAT_PME | PCIM_PSTAT_PMEENABLE); 2634272730Syongari if ((ifp->if_capenable & IFCAP_WOL) != 0) 2635272730Syongari pmstat |= PCIM_PSTAT_PME | PCIM_PSTAT_PMEENABLE; 2636272730Syongari pci_write_config(sc->alc_dev, 2637272730Syongari sc->alc_pmcap + PCIR_POWER_STATUS, pmstat, 2); 2638272730Syongari } 2639272730Syongari} 2640272730Syongari 2641193880Syongaristatic int 2642193880Syongarialc_suspend(device_t dev) 2643193880Syongari{ 2644193880Syongari struct alc_softc *sc; 2645193880Syongari 2646193880Syongari sc = device_get_softc(dev); 2647193880Syongari 2648193880Syongari ALC_LOCK(sc); 2649193880Syongari alc_stop(sc); 2650193880Syongari alc_setwol(sc); 2651193880Syongari ALC_UNLOCK(sc); 2652193880Syongari 2653193880Syongari return (0); 2654193880Syongari} 2655193880Syongari 2656193880Syongaristatic int 2657193880Syongarialc_resume(device_t dev) 2658193880Syongari{ 2659193880Syongari struct alc_softc *sc; 2660193880Syongari struct ifnet *ifp; 2661193880Syongari uint16_t pmstat; 2662193880Syongari 2663193880Syongari sc = device_get_softc(dev); 2664193880Syongari 2665193880Syongari ALC_LOCK(sc); 2666211053Syongari if ((sc->alc_flags & ALC_FLAG_PM) != 0) { 2667193880Syongari /* Disable PME and clear PME status. */ 2668193880Syongari pmstat = pci_read_config(sc->alc_dev, 2669211053Syongari sc->alc_pmcap + PCIR_POWER_STATUS, 2); 2670193880Syongari if ((pmstat & PCIM_PSTAT_PMEENABLE) != 0) { 2671193880Syongari pmstat &= ~PCIM_PSTAT_PMEENABLE; 2672193880Syongari pci_write_config(sc->alc_dev, 2673211053Syongari sc->alc_pmcap + PCIR_POWER_STATUS, pmstat, 2); 2674193880Syongari } 2675193880Syongari } 2676193880Syongari /* Reset PHY. */ 2677193880Syongari alc_phy_reset(sc); 2678193880Syongari ifp = sc->alc_ifp; 2679193880Syongari if ((ifp->if_flags & IFF_UP) != 0) { 2680193880Syongari ifp->if_drv_flags &= ~IFF_DRV_RUNNING; 2681193880Syongari alc_init_locked(sc); 2682193880Syongari } 2683193880Syongari ALC_UNLOCK(sc); 2684193880Syongari 2685193880Syongari return (0); 2686193880Syongari} 2687193880Syongari 2688193880Syongaristatic int 2689193880Syongarialc_encap(struct alc_softc *sc, struct mbuf **m_head) 2690193880Syongari{ 2691193880Syongari struct alc_txdesc *txd, *txd_last; 2692193880Syongari struct tx_desc *desc; 2693193880Syongari struct mbuf *m; 2694193880Syongari struct ip *ip; 2695193880Syongari struct tcphdr *tcp; 2696193880Syongari bus_dma_segment_t txsegs[ALC_MAXTXSEGS]; 2697193880Syongari bus_dmamap_t map; 2698213842Syongari uint32_t cflags, hdrlen, ip_off, poff, vtag; 2699193880Syongari int error, idx, nsegs, prod; 2700193880Syongari 2701193880Syongari ALC_LOCK_ASSERT(sc); 2702193880Syongari 2703193880Syongari M_ASSERTPKTHDR((*m_head)); 2704193880Syongari 2705193880Syongari m = *m_head; 2706193880Syongari ip = NULL; 2707193880Syongari tcp = NULL; 2708213842Syongari ip_off = poff = 0; 2709193880Syongari if ((m->m_pkthdr.csum_flags & (ALC_CSUM_FEATURES | CSUM_TSO)) != 0) { 2710193880Syongari /* 2711272730Syongari * AR81[3567]x requires offset of TCP/UDP header in its 2712193880Syongari * Tx descriptor to perform Tx checksum offloading. TSO 2713193880Syongari * also requires TCP header offset and modification of 2714193880Syongari * IP/TCP header. This kind of operation takes many CPU 2715193880Syongari * cycles on FreeBSD so fast host CPU is required to get 2716193880Syongari * smooth TSO performance. 2717193880Syongari */ 2718213842Syongari struct ether_header *eh; 2719193880Syongari 2720193880Syongari if (M_WRITABLE(m) == 0) { 2721193880Syongari /* Get a writable copy. */ 2722243857Sglebius m = m_dup(*m_head, M_NOWAIT); 2723193880Syongari /* Release original mbufs. */ 2724193880Syongari m_freem(*m_head); 2725193880Syongari if (m == NULL) { 2726193880Syongari *m_head = NULL; 2727193880Syongari return (ENOBUFS); 2728193880Syongari } 2729193880Syongari *m_head = m; 2730193880Syongari } 2731193880Syongari 2732213842Syongari ip_off = sizeof(struct ether_header); 2733213842Syongari m = m_pullup(m, ip_off); 2734193880Syongari if (m == NULL) { 2735193880Syongari *m_head = NULL; 2736193880Syongari return (ENOBUFS); 2737193880Syongari } 2738213842Syongari eh = mtod(m, struct ether_header *); 2739213842Syongari /* 2740213842Syongari * Check if hardware VLAN insertion is off. 2741213842Syongari * Additional check for LLC/SNAP frame? 2742213842Syongari */ 2743213842Syongari if (eh->ether_type == htons(ETHERTYPE_VLAN)) { 2744213842Syongari ip_off = sizeof(struct ether_vlan_header); 2745213842Syongari m = m_pullup(m, ip_off); 2746213842Syongari if (m == NULL) { 2747213842Syongari *m_head = NULL; 2748213842Syongari return (ENOBUFS); 2749213842Syongari } 2750213842Syongari } 2751213842Syongari m = m_pullup(m, ip_off + sizeof(struct ip)); 2752213842Syongari if (m == NULL) { 2753213842Syongari *m_head = NULL; 2754213842Syongari return (ENOBUFS); 2755213842Syongari } 2756213842Syongari ip = (struct ip *)(mtod(m, char *) + ip_off); 2757213842Syongari poff = ip_off + (ip->ip_hl << 2); 2758193880Syongari if ((m->m_pkthdr.csum_flags & CSUM_TSO) != 0) { 2759193880Syongari m = m_pullup(m, poff + sizeof(struct tcphdr)); 2760193880Syongari if (m == NULL) { 2761193880Syongari *m_head = NULL; 2762193880Syongari return (ENOBUFS); 2763193880Syongari } 2764193880Syongari tcp = (struct tcphdr *)(mtod(m, char *) + poff); 2765193880Syongari m = m_pullup(m, poff + (tcp->th_off << 2)); 2766193880Syongari if (m == NULL) { 2767193880Syongari *m_head = NULL; 2768193880Syongari return (ENOBUFS); 2769193880Syongari } 2770193880Syongari /* 2771193880Syongari * Due to strict adherence of Microsoft NDIS 2772193880Syongari * Large Send specification, hardware expects 2773193880Syongari * a pseudo TCP checksum inserted by upper 2774193880Syongari * stack. Unfortunately the pseudo TCP 2775193880Syongari * checksum that NDIS refers to does not include 2776193880Syongari * TCP payload length so driver should recompute 2777193880Syongari * the pseudo checksum here. Hopefully this 2778193880Syongari * wouldn't be much burden on modern CPUs. 2779193880Syongari * 2780193880Syongari * Reset IP checksum and recompute TCP pseudo 2781193880Syongari * checksum as NDIS specification said. 2782193880Syongari */ 2783213844Syongari ip = (struct ip *)(mtod(m, char *) + ip_off); 2784213844Syongari tcp = (struct tcphdr *)(mtod(m, char *) + poff); 2785193880Syongari ip->ip_sum = 0; 2786193880Syongari tcp->th_sum = in_pseudo(ip->ip_src.s_addr, 2787193880Syongari ip->ip_dst.s_addr, htons(IPPROTO_TCP)); 2788193880Syongari } 2789193880Syongari *m_head = m; 2790193880Syongari } 2791193880Syongari 2792193880Syongari prod = sc->alc_cdata.alc_tx_prod; 2793193880Syongari txd = &sc->alc_cdata.alc_txdesc[prod]; 2794193880Syongari txd_last = txd; 2795193880Syongari map = txd->tx_dmamap; 2796193880Syongari 2797193880Syongari error = bus_dmamap_load_mbuf_sg(sc->alc_cdata.alc_tx_tag, map, 2798193880Syongari *m_head, txsegs, &nsegs, 0); 2799193880Syongari if (error == EFBIG) { 2800243857Sglebius m = m_collapse(*m_head, M_NOWAIT, ALC_MAXTXSEGS); 2801193880Syongari if (m == NULL) { 2802193880Syongari m_freem(*m_head); 2803193880Syongari *m_head = NULL; 2804193880Syongari return (ENOMEM); 2805193880Syongari } 2806193880Syongari *m_head = m; 2807193880Syongari error = bus_dmamap_load_mbuf_sg(sc->alc_cdata.alc_tx_tag, map, 2808193880Syongari *m_head, txsegs, &nsegs, 0); 2809193880Syongari if (error != 0) { 2810193880Syongari m_freem(*m_head); 2811193880Syongari *m_head = NULL; 2812193880Syongari return (error); 2813193880Syongari } 2814193880Syongari } else if (error != 0) 2815193880Syongari return (error); 2816193880Syongari if (nsegs == 0) { 2817193880Syongari m_freem(*m_head); 2818193880Syongari *m_head = NULL; 2819193880Syongari return (EIO); 2820193880Syongari } 2821193880Syongari 2822193880Syongari /* Check descriptor overrun. */ 2823193880Syongari if (sc->alc_cdata.alc_tx_cnt + nsegs >= ALC_TX_RING_CNT - 3) { 2824193880Syongari bus_dmamap_unload(sc->alc_cdata.alc_tx_tag, map); 2825193880Syongari return (ENOBUFS); 2826193880Syongari } 2827193880Syongari bus_dmamap_sync(sc->alc_cdata.alc_tx_tag, map, BUS_DMASYNC_PREWRITE); 2828193880Syongari 2829193880Syongari m = *m_head; 2830193880Syongari cflags = TD_ETHERNET; 2831193880Syongari vtag = 0; 2832193880Syongari desc = NULL; 2833193880Syongari idx = 0; 2834193880Syongari /* Configure VLAN hardware tag insertion. */ 2835193880Syongari if ((m->m_flags & M_VLANTAG) != 0) { 2836193880Syongari vtag = htons(m->m_pkthdr.ether_vtag); 2837193880Syongari vtag = (vtag << TD_VLAN_SHIFT) & TD_VLAN_MASK; 2838193880Syongari cflags |= TD_INS_VLAN_TAG; 2839193880Syongari } 2840206876Syongari if ((m->m_pkthdr.csum_flags & CSUM_TSO) != 0) { 2841193880Syongari /* Request TSO and set MSS. */ 2842193880Syongari cflags |= TD_TSO | TD_TSO_DESCV1; 2843193880Syongari cflags |= ((uint32_t)m->m_pkthdr.tso_segsz << TD_MSS_SHIFT) & 2844193880Syongari TD_MSS_MASK; 2845193880Syongari /* Set TCP header offset. */ 2846193880Syongari cflags |= (poff << TD_TCPHDR_OFFSET_SHIFT) & 2847193880Syongari TD_TCPHDR_OFFSET_MASK; 2848193880Syongari /* 2849272730Syongari * AR81[3567]x requires the first buffer should 2850193880Syongari * only hold IP/TCP header data. Payload should 2851193880Syongari * be handled in other descriptors. 2852193880Syongari */ 2853193880Syongari hdrlen = poff + (tcp->th_off << 2); 2854193880Syongari desc = &sc->alc_rdata.alc_tx_ring[prod]; 2855193880Syongari desc->len = htole32(TX_BYTES(hdrlen | vtag)); 2856193880Syongari desc->flags = htole32(cflags); 2857193880Syongari desc->addr = htole64(txsegs[0].ds_addr); 2858193880Syongari sc->alc_cdata.alc_tx_cnt++; 2859193880Syongari ALC_DESC_INC(prod, ALC_TX_RING_CNT); 2860193880Syongari if (m->m_len - hdrlen > 0) { 2861193880Syongari /* Handle remaining payload of the first fragment. */ 2862193880Syongari desc = &sc->alc_rdata.alc_tx_ring[prod]; 2863193880Syongari desc->len = htole32(TX_BYTES((m->m_len - hdrlen) | 2864193880Syongari vtag)); 2865193880Syongari desc->flags = htole32(cflags); 2866193880Syongari desc->addr = htole64(txsegs[0].ds_addr + hdrlen); 2867193880Syongari sc->alc_cdata.alc_tx_cnt++; 2868193880Syongari ALC_DESC_INC(prod, ALC_TX_RING_CNT); 2869193880Syongari } 2870193880Syongari /* Handle remaining fragments. */ 2871193880Syongari idx = 1; 2872206876Syongari } else if ((m->m_pkthdr.csum_flags & ALC_CSUM_FEATURES) != 0) { 2873206876Syongari /* Configure Tx checksum offload. */ 2874206876Syongari#ifdef ALC_USE_CUSTOM_CSUM 2875206876Syongari cflags |= TD_CUSTOM_CSUM; 2876206876Syongari /* Set checksum start offset. */ 2877206876Syongari cflags |= ((poff >> 1) << TD_PLOAD_OFFSET_SHIFT) & 2878206876Syongari TD_PLOAD_OFFSET_MASK; 2879206876Syongari /* Set checksum insertion position of TCP/UDP. */ 2880206876Syongari cflags |= (((poff + m->m_pkthdr.csum_data) >> 1) << 2881206876Syongari TD_CUSTOM_CSUM_OFFSET_SHIFT) & TD_CUSTOM_CSUM_OFFSET_MASK; 2882206876Syongari#else 2883206876Syongari if ((m->m_pkthdr.csum_flags & CSUM_IP) != 0) 2884206876Syongari cflags |= TD_IPCSUM; 2885206876Syongari if ((m->m_pkthdr.csum_flags & CSUM_TCP) != 0) 2886206876Syongari cflags |= TD_TCPCSUM; 2887206876Syongari if ((m->m_pkthdr.csum_flags & CSUM_UDP) != 0) 2888206876Syongari cflags |= TD_UDPCSUM; 2889206876Syongari /* Set TCP/UDP header offset. */ 2890206876Syongari cflags |= (poff << TD_L4HDR_OFFSET_SHIFT) & 2891206876Syongari TD_L4HDR_OFFSET_MASK; 2892206876Syongari#endif 2893193880Syongari } 2894193880Syongari for (; idx < nsegs; idx++) { 2895193880Syongari desc = &sc->alc_rdata.alc_tx_ring[prod]; 2896193880Syongari desc->len = htole32(TX_BYTES(txsegs[idx].ds_len) | vtag); 2897193880Syongari desc->flags = htole32(cflags); 2898193880Syongari desc->addr = htole64(txsegs[idx].ds_addr); 2899193880Syongari sc->alc_cdata.alc_tx_cnt++; 2900193880Syongari ALC_DESC_INC(prod, ALC_TX_RING_CNT); 2901193880Syongari } 2902193880Syongari /* Update producer index. */ 2903193880Syongari sc->alc_cdata.alc_tx_prod = prod; 2904193880Syongari 2905193880Syongari /* Finally set EOP on the last descriptor. */ 2906193880Syongari prod = (prod + ALC_TX_RING_CNT - 1) % ALC_TX_RING_CNT; 2907193880Syongari desc = &sc->alc_rdata.alc_tx_ring[prod]; 2908193880Syongari desc->flags |= htole32(TD_EOP); 2909193880Syongari 2910193880Syongari /* Swap dmamap of the first and the last. */ 2911193880Syongari txd = &sc->alc_cdata.alc_txdesc[prod]; 2912193880Syongari map = txd_last->tx_dmamap; 2913193880Syongari txd_last->tx_dmamap = txd->tx_dmamap; 2914193880Syongari txd->tx_dmamap = map; 2915193880Syongari txd->tx_m = m; 2916193880Syongari 2917193880Syongari return (0); 2918193880Syongari} 2919193880Syongari 2920193880Syongaristatic void 2921216925Sjhbalc_start(struct ifnet *ifp) 2922193880Syongari{ 2923216925Sjhb struct alc_softc *sc; 2924193880Syongari 2925216925Sjhb sc = ifp->if_softc; 2926216925Sjhb ALC_LOCK(sc); 2927216925Sjhb alc_start_locked(ifp); 2928216925Sjhb ALC_UNLOCK(sc); 2929193880Syongari} 2930193880Syongari 2931193880Syongaristatic void 2932216925Sjhbalc_start_locked(struct ifnet *ifp) 2933193880Syongari{ 2934193880Syongari struct alc_softc *sc; 2935193880Syongari struct mbuf *m_head; 2936193880Syongari int enq; 2937193880Syongari 2938193880Syongari sc = ifp->if_softc; 2939193880Syongari 2940216925Sjhb ALC_LOCK_ASSERT(sc); 2941193880Syongari 2942193880Syongari /* Reclaim transmitted frames. */ 2943193880Syongari if (sc->alc_cdata.alc_tx_cnt >= ALC_TX_DESC_HIWAT) 2944193880Syongari alc_txeof(sc); 2945193880Syongari 2946193880Syongari if ((ifp->if_drv_flags & (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)) != 2947216925Sjhb IFF_DRV_RUNNING || (sc->alc_flags & ALC_FLAG_LINK) == 0) 2948193880Syongari return; 2949193880Syongari 2950193880Syongari for (enq = 0; !IFQ_DRV_IS_EMPTY(&ifp->if_snd); ) { 2951193880Syongari IFQ_DRV_DEQUEUE(&ifp->if_snd, m_head); 2952193880Syongari if (m_head == NULL) 2953193880Syongari break; 2954193880Syongari /* 2955193880Syongari * Pack the data into the transmit ring. If we 2956193880Syongari * don't have room, set the OACTIVE flag and wait 2957193880Syongari * for the NIC to drain the ring. 2958193880Syongari */ 2959193880Syongari if (alc_encap(sc, &m_head)) { 2960193880Syongari if (m_head == NULL) 2961193880Syongari break; 2962193880Syongari IFQ_DRV_PREPEND(&ifp->if_snd, m_head); 2963193880Syongari ifp->if_drv_flags |= IFF_DRV_OACTIVE; 2964193880Syongari break; 2965193880Syongari } 2966193880Syongari 2967193880Syongari enq++; 2968193880Syongari /* 2969193880Syongari * If there's a BPF listener, bounce a copy of this frame 2970193880Syongari * to him. 2971193880Syongari */ 2972193880Syongari ETHER_BPF_MTAP(ifp, m_head); 2973193880Syongari } 2974193880Syongari 2975193880Syongari if (enq > 0) { 2976193880Syongari /* Sync descriptors. */ 2977193880Syongari bus_dmamap_sync(sc->alc_cdata.alc_tx_ring_tag, 2978193880Syongari sc->alc_cdata.alc_tx_ring_map, BUS_DMASYNC_PREWRITE); 2979193880Syongari /* Kick. Assume we're using normal Tx priority queue. */ 2980272730Syongari if ((sc->alc_flags & ALC_FLAG_AR816X_FAMILY) != 0) 2981272730Syongari CSR_WRITE_2(sc, ALC_MBOX_TD_PRI0_PROD_IDX, 2982272730Syongari (uint16_t)sc->alc_cdata.alc_tx_prod); 2983272730Syongari else 2984272730Syongari CSR_WRITE_4(sc, ALC_MBOX_TD_PROD_IDX, 2985272730Syongari (sc->alc_cdata.alc_tx_prod << 2986272730Syongari MBOX_TD_PROD_LO_IDX_SHIFT) & 2987272730Syongari MBOX_TD_PROD_LO_IDX_MASK); 2988193880Syongari /* Set a timeout in case the chip goes out to lunch. */ 2989193880Syongari sc->alc_watchdog_timer = ALC_TX_TIMEOUT; 2990193880Syongari } 2991193880Syongari} 2992193880Syongari 2993193880Syongaristatic void 2994193880Syongarialc_watchdog(struct alc_softc *sc) 2995193880Syongari{ 2996193880Syongari struct ifnet *ifp; 2997193880Syongari 2998193880Syongari ALC_LOCK_ASSERT(sc); 2999193880Syongari 3000193880Syongari if (sc->alc_watchdog_timer == 0 || --sc->alc_watchdog_timer) 3001193880Syongari return; 3002193880Syongari 3003193880Syongari ifp = sc->alc_ifp; 3004193880Syongari if ((sc->alc_flags & ALC_FLAG_LINK) == 0) { 3005193880Syongari if_printf(sc->alc_ifp, "watchdog timeout (lost link)\n"); 3006271833Sglebius if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); 3007193880Syongari ifp->if_drv_flags &= ~IFF_DRV_RUNNING; 3008193880Syongari alc_init_locked(sc); 3009193880Syongari return; 3010193880Syongari } 3011193880Syongari if_printf(sc->alc_ifp, "watchdog timeout -- resetting\n"); 3012271833Sglebius if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); 3013193880Syongari ifp->if_drv_flags &= ~IFF_DRV_RUNNING; 3014193880Syongari alc_init_locked(sc); 3015193880Syongari if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) 3016216925Sjhb alc_start_locked(ifp); 3017193880Syongari} 3018193880Syongari 3019193880Syongaristatic int 3020193880Syongarialc_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) 3021193880Syongari{ 3022193880Syongari struct alc_softc *sc; 3023193880Syongari struct ifreq *ifr; 3024193880Syongari struct mii_data *mii; 3025193880Syongari int error, mask; 3026193880Syongari 3027193880Syongari sc = ifp->if_softc; 3028193880Syongari ifr = (struct ifreq *)data; 3029193880Syongari error = 0; 3030193880Syongari switch (cmd) { 3031193880Syongari case SIOCSIFMTU: 3032211105Syongari if (ifr->ifr_mtu < ETHERMIN || 3033211105Syongari ifr->ifr_mtu > (sc->alc_ident->max_framelen - 3034211105Syongari sizeof(struct ether_vlan_header) - ETHER_CRC_LEN) || 3035193880Syongari ((sc->alc_flags & ALC_FLAG_JUMBO) == 0 && 3036193880Syongari ifr->ifr_mtu > ETHERMTU)) 3037193880Syongari error = EINVAL; 3038193880Syongari else if (ifp->if_mtu != ifr->ifr_mtu) { 3039193880Syongari ALC_LOCK(sc); 3040193880Syongari ifp->if_mtu = ifr->ifr_mtu; 3041272730Syongari /* AR81[3567]x has 13 bits MSS field. */ 3042193880Syongari if (ifp->if_mtu > ALC_TSO_MTU && 3043193880Syongari (ifp->if_capenable & IFCAP_TSO4) != 0) { 3044193880Syongari ifp->if_capenable &= ~IFCAP_TSO4; 3045193880Syongari ifp->if_hwassist &= ~CSUM_TSO; 3046204228Syongari VLAN_CAPABILITIES(ifp); 3047193880Syongari } 3048193880Syongari ALC_UNLOCK(sc); 3049193880Syongari } 3050193880Syongari break; 3051193880Syongari case SIOCSIFFLAGS: 3052193880Syongari ALC_LOCK(sc); 3053193880Syongari if ((ifp->if_flags & IFF_UP) != 0) { 3054193880Syongari if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0 && 3055193880Syongari ((ifp->if_flags ^ sc->alc_if_flags) & 3056193880Syongari (IFF_PROMISC | IFF_ALLMULTI)) != 0) 3057193880Syongari alc_rxfilter(sc); 3058217379Sjhb else 3059193880Syongari alc_init_locked(sc); 3060193880Syongari } else if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0) 3061193880Syongari alc_stop(sc); 3062193880Syongari sc->alc_if_flags = ifp->if_flags; 3063193880Syongari ALC_UNLOCK(sc); 3064193880Syongari break; 3065193880Syongari case SIOCADDMULTI: 3066193880Syongari case SIOCDELMULTI: 3067193880Syongari ALC_LOCK(sc); 3068193880Syongari if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0) 3069193880Syongari alc_rxfilter(sc); 3070193880Syongari ALC_UNLOCK(sc); 3071193880Syongari break; 3072193880Syongari case SIOCSIFMEDIA: 3073193880Syongari case SIOCGIFMEDIA: 3074193880Syongari mii = device_get_softc(sc->alc_miibus); 3075193880Syongari error = ifmedia_ioctl(ifp, ifr, &mii->mii_media, cmd); 3076193880Syongari break; 3077193880Syongari case SIOCSIFCAP: 3078193880Syongari ALC_LOCK(sc); 3079193880Syongari mask = ifr->ifr_reqcap ^ ifp->if_capenable; 3080193880Syongari if ((mask & IFCAP_TXCSUM) != 0 && 3081193880Syongari (ifp->if_capabilities & IFCAP_TXCSUM) != 0) { 3082193880Syongari ifp->if_capenable ^= IFCAP_TXCSUM; 3083193880Syongari if ((ifp->if_capenable & IFCAP_TXCSUM) != 0) 3084193880Syongari ifp->if_hwassist |= ALC_CSUM_FEATURES; 3085193880Syongari else 3086193880Syongari ifp->if_hwassist &= ~ALC_CSUM_FEATURES; 3087193880Syongari } 3088193880Syongari if ((mask & IFCAP_TSO4) != 0 && 3089193880Syongari (ifp->if_capabilities & IFCAP_TSO4) != 0) { 3090193880Syongari ifp->if_capenable ^= IFCAP_TSO4; 3091193880Syongari if ((ifp->if_capenable & IFCAP_TSO4) != 0) { 3092272730Syongari /* AR81[3567]x has 13 bits MSS field. */ 3093193880Syongari if (ifp->if_mtu > ALC_TSO_MTU) { 3094193880Syongari ifp->if_capenable &= ~IFCAP_TSO4; 3095193880Syongari ifp->if_hwassist &= ~CSUM_TSO; 3096193880Syongari } else 3097193880Syongari ifp->if_hwassist |= CSUM_TSO; 3098193880Syongari } else 3099193880Syongari ifp->if_hwassist &= ~CSUM_TSO; 3100193880Syongari } 3101193880Syongari if ((mask & IFCAP_WOL_MCAST) != 0 && 3102193880Syongari (ifp->if_capabilities & IFCAP_WOL_MCAST) != 0) 3103193880Syongari ifp->if_capenable ^= IFCAP_WOL_MCAST; 3104193880Syongari if ((mask & IFCAP_WOL_MAGIC) != 0 && 3105193880Syongari (ifp->if_capabilities & IFCAP_WOL_MAGIC) != 0) 3106193880Syongari ifp->if_capenable ^= IFCAP_WOL_MAGIC; 3107193880Syongari if ((mask & IFCAP_VLAN_HWTAGGING) != 0 && 3108193880Syongari (ifp->if_capabilities & IFCAP_VLAN_HWTAGGING) != 0) { 3109193880Syongari ifp->if_capenable ^= IFCAP_VLAN_HWTAGGING; 3110193880Syongari alc_rxvlan(sc); 3111193880Syongari } 3112193880Syongari if ((mask & IFCAP_VLAN_HWCSUM) != 0 && 3113193880Syongari (ifp->if_capabilities & IFCAP_VLAN_HWCSUM) != 0) 3114193880Syongari ifp->if_capenable ^= IFCAP_VLAN_HWCSUM; 3115193880Syongari if ((mask & IFCAP_VLAN_HWTSO) != 0 && 3116193880Syongari (ifp->if_capabilities & IFCAP_VLAN_HWTSO) != 0) 3117193880Syongari ifp->if_capenable ^= IFCAP_VLAN_HWTSO; 3118193880Syongari if ((ifp->if_capenable & IFCAP_VLAN_HWTAGGING) == 0) 3119193880Syongari ifp->if_capenable &= 3120193880Syongari ~(IFCAP_VLAN_HWTSO | IFCAP_VLAN_HWCSUM); 3121193880Syongari ALC_UNLOCK(sc); 3122193880Syongari VLAN_CAPABILITIES(ifp); 3123193880Syongari break; 3124193880Syongari default: 3125193880Syongari error = ether_ioctl(ifp, cmd, data); 3126193880Syongari break; 3127193880Syongari } 3128193880Syongari 3129193880Syongari return (error); 3130193880Syongari} 3131193880Syongari 3132193880Syongaristatic void 3133193880Syongarialc_mac_config(struct alc_softc *sc) 3134193880Syongari{ 3135193880Syongari struct mii_data *mii; 3136193880Syongari uint32_t reg; 3137193880Syongari 3138193880Syongari ALC_LOCK_ASSERT(sc); 3139193880Syongari 3140193880Syongari mii = device_get_softc(sc->alc_miibus); 3141193880Syongari reg = CSR_READ_4(sc, ALC_MAC_CFG); 3142193880Syongari reg &= ~(MAC_CFG_FULL_DUPLEX | MAC_CFG_TX_FC | MAC_CFG_RX_FC | 3143193880Syongari MAC_CFG_SPEED_MASK); 3144272730Syongari if ((sc->alc_flags & ALC_FLAG_AR816X_FAMILY) != 0 || 3145272730Syongari sc->alc_ident->deviceid == DEVICEID_ATHEROS_AR8151 || 3146211105Syongari sc->alc_ident->deviceid == DEVICEID_ATHEROS_AR8151_V2 || 3147211105Syongari sc->alc_ident->deviceid == DEVICEID_ATHEROS_AR8152_B2) 3148211105Syongari reg |= MAC_CFG_HASH_ALG_CRC32 | MAC_CFG_SPEED_MODE_SW; 3149193880Syongari /* Reprogram MAC with resolved speed/duplex. */ 3150193880Syongari switch (IFM_SUBTYPE(mii->mii_media_active)) { 3151193880Syongari case IFM_10_T: 3152193880Syongari case IFM_100_TX: 3153193880Syongari reg |= MAC_CFG_SPEED_10_100; 3154193880Syongari break; 3155193880Syongari case IFM_1000_T: 3156193880Syongari reg |= MAC_CFG_SPEED_1000; 3157193880Syongari break; 3158193880Syongari } 3159193880Syongari if ((IFM_OPTIONS(mii->mii_media_active) & IFM_FDX) != 0) { 3160193880Syongari reg |= MAC_CFG_FULL_DUPLEX; 3161193880Syongari if ((IFM_OPTIONS(mii->mii_media_active) & IFM_ETH_TXPAUSE) != 0) 3162193880Syongari reg |= MAC_CFG_TX_FC; 3163193880Syongari if ((IFM_OPTIONS(mii->mii_media_active) & IFM_ETH_RXPAUSE) != 0) 3164193880Syongari reg |= MAC_CFG_RX_FC; 3165193880Syongari } 3166193880Syongari CSR_WRITE_4(sc, ALC_MAC_CFG, reg); 3167193880Syongari} 3168193880Syongari 3169193880Syongaristatic void 3170193880Syongarialc_stats_clear(struct alc_softc *sc) 3171193880Syongari{ 3172193880Syongari struct smb sb, *smb; 3173193880Syongari uint32_t *reg; 3174193880Syongari int i; 3175193880Syongari 3176193880Syongari if ((sc->alc_flags & ALC_FLAG_SMB_BUG) == 0) { 3177193880Syongari bus_dmamap_sync(sc->alc_cdata.alc_smb_tag, 3178193880Syongari sc->alc_cdata.alc_smb_map, 3179193880Syongari BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); 3180193880Syongari smb = sc->alc_rdata.alc_smb; 3181193880Syongari /* Update done, clear. */ 3182193880Syongari smb->updated = 0; 3183193880Syongari bus_dmamap_sync(sc->alc_cdata.alc_smb_tag, 3184193880Syongari sc->alc_cdata.alc_smb_map, 3185193880Syongari BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 3186193880Syongari } else { 3187193880Syongari for (reg = &sb.rx_frames, i = 0; reg <= &sb.rx_pkts_filtered; 3188193880Syongari reg++) { 3189193880Syongari CSR_READ_4(sc, ALC_RX_MIB_BASE + i); 3190193880Syongari i += sizeof(uint32_t); 3191193880Syongari } 3192193880Syongari /* Read Tx statistics. */ 3193193880Syongari for (reg = &sb.tx_frames, i = 0; reg <= &sb.tx_mcast_bytes; 3194193880Syongari reg++) { 3195193880Syongari CSR_READ_4(sc, ALC_TX_MIB_BASE + i); 3196193880Syongari i += sizeof(uint32_t); 3197193880Syongari } 3198193880Syongari } 3199193880Syongari} 3200193880Syongari 3201193880Syongaristatic void 3202193880Syongarialc_stats_update(struct alc_softc *sc) 3203193880Syongari{ 3204193880Syongari struct alc_hw_stats *stat; 3205193880Syongari struct smb sb, *smb; 3206193880Syongari struct ifnet *ifp; 3207193880Syongari uint32_t *reg; 3208193880Syongari int i; 3209193880Syongari 3210193880Syongari ALC_LOCK_ASSERT(sc); 3211193880Syongari 3212193880Syongari ifp = sc->alc_ifp; 3213193880Syongari stat = &sc->alc_stats; 3214193880Syongari if ((sc->alc_flags & ALC_FLAG_SMB_BUG) == 0) { 3215193880Syongari bus_dmamap_sync(sc->alc_cdata.alc_smb_tag, 3216193880Syongari sc->alc_cdata.alc_smb_map, 3217193880Syongari BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); 3218193880Syongari smb = sc->alc_rdata.alc_smb; 3219193880Syongari if (smb->updated == 0) 3220193880Syongari return; 3221193880Syongari } else { 3222193880Syongari smb = &sb; 3223193880Syongari /* Read Rx statistics. */ 3224193880Syongari for (reg = &sb.rx_frames, i = 0; reg <= &sb.rx_pkts_filtered; 3225193880Syongari reg++) { 3226193880Syongari *reg = CSR_READ_4(sc, ALC_RX_MIB_BASE + i); 3227193880Syongari i += sizeof(uint32_t); 3228193880Syongari } 3229193880Syongari /* Read Tx statistics. */ 3230193880Syongari for (reg = &sb.tx_frames, i = 0; reg <= &sb.tx_mcast_bytes; 3231193880Syongari reg++) { 3232193880Syongari *reg = CSR_READ_4(sc, ALC_TX_MIB_BASE + i); 3233193880Syongari i += sizeof(uint32_t); 3234193880Syongari } 3235193880Syongari } 3236193880Syongari 3237193880Syongari /* Rx stats. */ 3238193880Syongari stat->rx_frames += smb->rx_frames; 3239193880Syongari stat->rx_bcast_frames += smb->rx_bcast_frames; 3240193880Syongari stat->rx_mcast_frames += smb->rx_mcast_frames; 3241193880Syongari stat->rx_pause_frames += smb->rx_pause_frames; 3242193880Syongari stat->rx_control_frames += smb->rx_control_frames; 3243193880Syongari stat->rx_crcerrs += smb->rx_crcerrs; 3244193880Syongari stat->rx_lenerrs += smb->rx_lenerrs; 3245193880Syongari stat->rx_bytes += smb->rx_bytes; 3246193880Syongari stat->rx_runts += smb->rx_runts; 3247193880Syongari stat->rx_fragments += smb->rx_fragments; 3248193880Syongari stat->rx_pkts_64 += smb->rx_pkts_64; 3249193880Syongari stat->rx_pkts_65_127 += smb->rx_pkts_65_127; 3250193880Syongari stat->rx_pkts_128_255 += smb->rx_pkts_128_255; 3251193880Syongari stat->rx_pkts_256_511 += smb->rx_pkts_256_511; 3252193880Syongari stat->rx_pkts_512_1023 += smb->rx_pkts_512_1023; 3253193880Syongari stat->rx_pkts_1024_1518 += smb->rx_pkts_1024_1518; 3254193880Syongari stat->rx_pkts_1519_max += smb->rx_pkts_1519_max; 3255193880Syongari stat->rx_pkts_truncated += smb->rx_pkts_truncated; 3256193880Syongari stat->rx_fifo_oflows += smb->rx_fifo_oflows; 3257193880Syongari stat->rx_rrs_errs += smb->rx_rrs_errs; 3258193880Syongari stat->rx_alignerrs += smb->rx_alignerrs; 3259193880Syongari stat->rx_bcast_bytes += smb->rx_bcast_bytes; 3260193880Syongari stat->rx_mcast_bytes += smb->rx_mcast_bytes; 3261193880Syongari stat->rx_pkts_filtered += smb->rx_pkts_filtered; 3262193880Syongari 3263193880Syongari /* Tx stats. */ 3264193880Syongari stat->tx_frames += smb->tx_frames; 3265193880Syongari stat->tx_bcast_frames += smb->tx_bcast_frames; 3266193880Syongari stat->tx_mcast_frames += smb->tx_mcast_frames; 3267193880Syongari stat->tx_pause_frames += smb->tx_pause_frames; 3268193880Syongari stat->tx_excess_defer += smb->tx_excess_defer; 3269193880Syongari stat->tx_control_frames += smb->tx_control_frames; 3270193880Syongari stat->tx_deferred += smb->tx_deferred; 3271193880Syongari stat->tx_bytes += smb->tx_bytes; 3272193880Syongari stat->tx_pkts_64 += smb->tx_pkts_64; 3273193880Syongari stat->tx_pkts_65_127 += smb->tx_pkts_65_127; 3274193880Syongari stat->tx_pkts_128_255 += smb->tx_pkts_128_255; 3275193880Syongari stat->tx_pkts_256_511 += smb->tx_pkts_256_511; 3276193880Syongari stat->tx_pkts_512_1023 += smb->tx_pkts_512_1023; 3277193880Syongari stat->tx_pkts_1024_1518 += smb->tx_pkts_1024_1518; 3278193880Syongari stat->tx_pkts_1519_max += smb->tx_pkts_1519_max; 3279193880Syongari stat->tx_single_colls += smb->tx_single_colls; 3280193880Syongari stat->tx_multi_colls += smb->tx_multi_colls; 3281193880Syongari stat->tx_late_colls += smb->tx_late_colls; 3282193880Syongari stat->tx_excess_colls += smb->tx_excess_colls; 3283193880Syongari stat->tx_underrun += smb->tx_underrun; 3284193880Syongari stat->tx_desc_underrun += smb->tx_desc_underrun; 3285193880Syongari stat->tx_lenerrs += smb->tx_lenerrs; 3286193880Syongari stat->tx_pkts_truncated += smb->tx_pkts_truncated; 3287193880Syongari stat->tx_bcast_bytes += smb->tx_bcast_bytes; 3288193880Syongari stat->tx_mcast_bytes += smb->tx_mcast_bytes; 3289193880Syongari 3290193880Syongari /* Update counters in ifnet. */ 3291271833Sglebius if_inc_counter(ifp, IFCOUNTER_OPACKETS, smb->tx_frames); 3292193880Syongari 3293271833Sglebius if_inc_counter(ifp, IFCOUNTER_COLLISIONS, smb->tx_single_colls + 3294193880Syongari smb->tx_multi_colls * 2 + smb->tx_late_colls + 3295272721Syongari smb->tx_excess_colls * HDPX_CFG_RETRY_DEFAULT); 3296193880Syongari 3297272721Syongari if_inc_counter(ifp, IFCOUNTER_OERRORS, smb->tx_late_colls + 3298272721Syongari smb->tx_excess_colls + smb->tx_underrun + smb->tx_pkts_truncated); 3299193880Syongari 3300271833Sglebius if_inc_counter(ifp, IFCOUNTER_IPACKETS, smb->rx_frames); 3301193880Syongari 3302271833Sglebius if_inc_counter(ifp, IFCOUNTER_IERRORS, 3303271833Sglebius smb->rx_crcerrs + smb->rx_lenerrs + 3304193880Syongari smb->rx_runts + smb->rx_pkts_truncated + 3305193880Syongari smb->rx_fifo_oflows + smb->rx_rrs_errs + 3306271833Sglebius smb->rx_alignerrs); 3307193880Syongari 3308193880Syongari if ((sc->alc_flags & ALC_FLAG_SMB_BUG) == 0) { 3309193880Syongari /* Update done, clear. */ 3310193880Syongari smb->updated = 0; 3311193880Syongari bus_dmamap_sync(sc->alc_cdata.alc_smb_tag, 3312193880Syongari sc->alc_cdata.alc_smb_map, 3313193880Syongari BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 3314193880Syongari } 3315193880Syongari} 3316193880Syongari 3317193880Syongaristatic int 3318193880Syongarialc_intr(void *arg) 3319193880Syongari{ 3320193880Syongari struct alc_softc *sc; 3321193880Syongari uint32_t status; 3322193880Syongari 3323193880Syongari sc = (struct alc_softc *)arg; 3324193880Syongari 3325193880Syongari status = CSR_READ_4(sc, ALC_INTR_STATUS); 3326193880Syongari if ((status & ALC_INTRS) == 0) 3327193880Syongari return (FILTER_STRAY); 3328193880Syongari /* Disable interrupts. */ 3329193880Syongari CSR_WRITE_4(sc, ALC_INTR_STATUS, INTR_DIS_INT); 3330193880Syongari taskqueue_enqueue(sc->alc_tq, &sc->alc_int_task); 3331193880Syongari 3332193880Syongari return (FILTER_HANDLED); 3333193880Syongari} 3334193880Syongari 3335193880Syongaristatic void 3336193880Syongarialc_int_task(void *arg, int pending) 3337193880Syongari{ 3338193880Syongari struct alc_softc *sc; 3339193880Syongari struct ifnet *ifp; 3340193880Syongari uint32_t status; 3341193880Syongari int more; 3342193880Syongari 3343193880Syongari sc = (struct alc_softc *)arg; 3344193880Syongari ifp = sc->alc_ifp; 3345193880Syongari 3346193880Syongari status = CSR_READ_4(sc, ALC_INTR_STATUS); 3347217379Sjhb ALC_LOCK(sc); 3348216362Syongari if (sc->alc_morework != 0) { 3349216362Syongari sc->alc_morework = 0; 3350193880Syongari status |= INTR_RX_PKT; 3351216362Syongari } 3352193880Syongari if ((status & ALC_INTRS) == 0) 3353193880Syongari goto done; 3354193880Syongari 3355193880Syongari /* Acknowledge interrupts but still disable interrupts. */ 3356193880Syongari CSR_WRITE_4(sc, ALC_INTR_STATUS, status | INTR_DIS_INT); 3357193880Syongari 3358193880Syongari more = 0; 3359193880Syongari if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0) { 3360193880Syongari if ((status & INTR_RX_PKT) != 0) { 3361193880Syongari more = alc_rxintr(sc, sc->alc_process_limit); 3362193880Syongari if (more == EAGAIN) 3363216362Syongari sc->alc_morework = 1; 3364193880Syongari else if (more == EIO) { 3365193880Syongari ifp->if_drv_flags &= ~IFF_DRV_RUNNING; 3366193880Syongari alc_init_locked(sc); 3367193880Syongari ALC_UNLOCK(sc); 3368193880Syongari return; 3369193880Syongari } 3370193880Syongari } 3371193880Syongari if ((status & (INTR_DMA_RD_TO_RST | INTR_DMA_WR_TO_RST | 3372193880Syongari INTR_TXQ_TO_RST)) != 0) { 3373193880Syongari if ((status & INTR_DMA_RD_TO_RST) != 0) 3374193880Syongari device_printf(sc->alc_dev, 3375193880Syongari "DMA read error! -- resetting\n"); 3376193880Syongari if ((status & INTR_DMA_WR_TO_RST) != 0) 3377193880Syongari device_printf(sc->alc_dev, 3378193880Syongari "DMA write error! -- resetting\n"); 3379193880Syongari if ((status & INTR_TXQ_TO_RST) != 0) 3380193880Syongari device_printf(sc->alc_dev, 3381193880Syongari "TxQ reset! -- resetting\n"); 3382193880Syongari ifp->if_drv_flags &= ~IFF_DRV_RUNNING; 3383193880Syongari alc_init_locked(sc); 3384193880Syongari ALC_UNLOCK(sc); 3385193880Syongari return; 3386193880Syongari } 3387193880Syongari if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0 && 3388193880Syongari !IFQ_DRV_IS_EMPTY(&ifp->if_snd)) 3389217379Sjhb alc_start_locked(ifp); 3390193880Syongari } 3391193880Syongari 3392193880Syongari if (more == EAGAIN || 3393193880Syongari (CSR_READ_4(sc, ALC_INTR_STATUS) & ALC_INTRS) != 0) { 3394217379Sjhb ALC_UNLOCK(sc); 3395193880Syongari taskqueue_enqueue(sc->alc_tq, &sc->alc_int_task); 3396193880Syongari return; 3397193880Syongari } 3398193880Syongari 3399193880Syongaridone: 3400193880Syongari if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0) { 3401193880Syongari /* Re-enable interrupts if we're running. */ 3402193880Syongari CSR_WRITE_4(sc, ALC_INTR_STATUS, 0x7FFFFFFF); 3403193880Syongari } 3404217379Sjhb ALC_UNLOCK(sc); 3405193880Syongari} 3406193880Syongari 3407193880Syongaristatic void 3408193880Syongarialc_txeof(struct alc_softc *sc) 3409193880Syongari{ 3410193880Syongari struct ifnet *ifp; 3411193880Syongari struct alc_txdesc *txd; 3412193880Syongari uint32_t cons, prod; 3413193880Syongari int prog; 3414193880Syongari 3415193880Syongari ALC_LOCK_ASSERT(sc); 3416193880Syongari 3417193880Syongari ifp = sc->alc_ifp; 3418193880Syongari 3419193880Syongari if (sc->alc_cdata.alc_tx_cnt == 0) 3420193880Syongari return; 3421193880Syongari bus_dmamap_sync(sc->alc_cdata.alc_tx_ring_tag, 3422193880Syongari sc->alc_cdata.alc_tx_ring_map, BUS_DMASYNC_POSTWRITE); 3423193880Syongari if ((sc->alc_flags & ALC_FLAG_CMB_BUG) == 0) { 3424193880Syongari bus_dmamap_sync(sc->alc_cdata.alc_cmb_tag, 3425193880Syongari sc->alc_cdata.alc_cmb_map, BUS_DMASYNC_POSTREAD); 3426193880Syongari prod = sc->alc_rdata.alc_cmb->cons; 3427272730Syongari } else { 3428272730Syongari if ((sc->alc_flags & ALC_FLAG_AR816X_FAMILY) != 0) 3429272730Syongari prod = CSR_READ_2(sc, ALC_MBOX_TD_PRI0_CONS_IDX); 3430272730Syongari else { 3431272730Syongari prod = CSR_READ_4(sc, ALC_MBOX_TD_CONS_IDX); 3432272730Syongari /* Assume we're using normal Tx priority queue. */ 3433272730Syongari prod = (prod & MBOX_TD_CONS_LO_IDX_MASK) >> 3434272730Syongari MBOX_TD_CONS_LO_IDX_SHIFT; 3435272730Syongari } 3436272730Syongari } 3437193880Syongari cons = sc->alc_cdata.alc_tx_cons; 3438193880Syongari /* 3439193880Syongari * Go through our Tx list and free mbufs for those 3440193880Syongari * frames which have been transmitted. 3441193880Syongari */ 3442193880Syongari for (prog = 0; cons != prod; prog++, 3443193880Syongari ALC_DESC_INC(cons, ALC_TX_RING_CNT)) { 3444193880Syongari if (sc->alc_cdata.alc_tx_cnt <= 0) 3445193880Syongari break; 3446193880Syongari prog++; 3447193880Syongari ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 3448193880Syongari sc->alc_cdata.alc_tx_cnt--; 3449193880Syongari txd = &sc->alc_cdata.alc_txdesc[cons]; 3450193880Syongari if (txd->tx_m != NULL) { 3451193880Syongari /* Reclaim transmitted mbufs. */ 3452193880Syongari bus_dmamap_sync(sc->alc_cdata.alc_tx_tag, 3453193880Syongari txd->tx_dmamap, BUS_DMASYNC_POSTWRITE); 3454193880Syongari bus_dmamap_unload(sc->alc_cdata.alc_tx_tag, 3455193880Syongari txd->tx_dmamap); 3456193880Syongari m_freem(txd->tx_m); 3457193880Syongari txd->tx_m = NULL; 3458193880Syongari } 3459193880Syongari } 3460193880Syongari 3461193880Syongari if ((sc->alc_flags & ALC_FLAG_CMB_BUG) == 0) 3462193880Syongari bus_dmamap_sync(sc->alc_cdata.alc_cmb_tag, 3463193880Syongari sc->alc_cdata.alc_cmb_map, BUS_DMASYNC_PREREAD); 3464193880Syongari sc->alc_cdata.alc_tx_cons = cons; 3465193880Syongari /* 3466193880Syongari * Unarm watchdog timer only when there is no pending 3467193880Syongari * frames in Tx queue. 3468193880Syongari */ 3469193880Syongari if (sc->alc_cdata.alc_tx_cnt == 0) 3470193880Syongari sc->alc_watchdog_timer = 0; 3471193880Syongari} 3472193880Syongari 3473193880Syongaristatic int 3474193880Syongarialc_newbuf(struct alc_softc *sc, struct alc_rxdesc *rxd) 3475193880Syongari{ 3476193880Syongari struct mbuf *m; 3477193880Syongari bus_dma_segment_t segs[1]; 3478193880Syongari bus_dmamap_t map; 3479193880Syongari int nsegs; 3480193880Syongari 3481243857Sglebius m = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR); 3482193880Syongari if (m == NULL) 3483193880Syongari return (ENOBUFS); 3484193880Syongari m->m_len = m->m_pkthdr.len = RX_BUF_SIZE_MAX; 3485193880Syongari#ifndef __NO_STRICT_ALIGNMENT 3486193880Syongari m_adj(m, sizeof(uint64_t)); 3487193880Syongari#endif 3488193880Syongari 3489193880Syongari if (bus_dmamap_load_mbuf_sg(sc->alc_cdata.alc_rx_tag, 3490193880Syongari sc->alc_cdata.alc_rx_sparemap, m, segs, &nsegs, 0) != 0) { 3491193880Syongari m_freem(m); 3492193880Syongari return (ENOBUFS); 3493193880Syongari } 3494193880Syongari KASSERT(nsegs == 1, ("%s: %d segments returned!", __func__, nsegs)); 3495193880Syongari 3496193880Syongari if (rxd->rx_m != NULL) { 3497193880Syongari bus_dmamap_sync(sc->alc_cdata.alc_rx_tag, rxd->rx_dmamap, 3498193880Syongari BUS_DMASYNC_POSTREAD); 3499193880Syongari bus_dmamap_unload(sc->alc_cdata.alc_rx_tag, rxd->rx_dmamap); 3500193880Syongari } 3501193880Syongari map = rxd->rx_dmamap; 3502193880Syongari rxd->rx_dmamap = sc->alc_cdata.alc_rx_sparemap; 3503193880Syongari sc->alc_cdata.alc_rx_sparemap = map; 3504193880Syongari bus_dmamap_sync(sc->alc_cdata.alc_rx_tag, rxd->rx_dmamap, 3505193880Syongari BUS_DMASYNC_PREREAD); 3506193880Syongari rxd->rx_m = m; 3507193880Syongari rxd->rx_desc->addr = htole64(segs[0].ds_addr); 3508193880Syongari return (0); 3509193880Syongari} 3510193880Syongari 3511193880Syongaristatic int 3512193880Syongarialc_rxintr(struct alc_softc *sc, int count) 3513193880Syongari{ 3514193880Syongari struct ifnet *ifp; 3515193880Syongari struct rx_rdesc *rrd; 3516193880Syongari uint32_t nsegs, status; 3517193880Syongari int rr_cons, prog; 3518193880Syongari 3519193880Syongari bus_dmamap_sync(sc->alc_cdata.alc_rr_ring_tag, 3520193880Syongari sc->alc_cdata.alc_rr_ring_map, 3521193880Syongari BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); 3522193880Syongari bus_dmamap_sync(sc->alc_cdata.alc_rx_ring_tag, 3523193880Syongari sc->alc_cdata.alc_rx_ring_map, BUS_DMASYNC_POSTWRITE); 3524193880Syongari rr_cons = sc->alc_cdata.alc_rr_cons; 3525193880Syongari ifp = sc->alc_ifp; 3526193880Syongari for (prog = 0; (ifp->if_drv_flags & IFF_DRV_RUNNING) != 0;) { 3527193880Syongari if (count-- <= 0) 3528193880Syongari break; 3529193880Syongari rrd = &sc->alc_rdata.alc_rr_ring[rr_cons]; 3530193880Syongari status = le32toh(rrd->status); 3531193880Syongari if ((status & RRD_VALID) == 0) 3532193880Syongari break; 3533193880Syongari nsegs = RRD_RD_CNT(le32toh(rrd->rdinfo)); 3534193880Syongari if (nsegs == 0) { 3535193880Syongari /* This should not happen! */ 3536193880Syongari device_printf(sc->alc_dev, 3537193880Syongari "unexpected segment count -- resetting\n"); 3538193880Syongari return (EIO); 3539193880Syongari } 3540193880Syongari alc_rxeof(sc, rrd); 3541193880Syongari /* Clear Rx return status. */ 3542193880Syongari rrd->status = 0; 3543193880Syongari ALC_DESC_INC(rr_cons, ALC_RR_RING_CNT); 3544193880Syongari sc->alc_cdata.alc_rx_cons += nsegs; 3545193880Syongari sc->alc_cdata.alc_rx_cons %= ALC_RR_RING_CNT; 3546193880Syongari prog += nsegs; 3547193880Syongari } 3548193880Syongari 3549193880Syongari if (prog > 0) { 3550193880Syongari /* Update the consumer index. */ 3551193880Syongari sc->alc_cdata.alc_rr_cons = rr_cons; 3552193880Syongari /* Sync Rx return descriptors. */ 3553193880Syongari bus_dmamap_sync(sc->alc_cdata.alc_rr_ring_tag, 3554193880Syongari sc->alc_cdata.alc_rr_ring_map, 3555193880Syongari BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 3556193880Syongari /* 3557193880Syongari * Sync updated Rx descriptors such that controller see 3558193880Syongari * modified buffer addresses. 3559193880Syongari */ 3560193880Syongari bus_dmamap_sync(sc->alc_cdata.alc_rx_ring_tag, 3561193880Syongari sc->alc_cdata.alc_rx_ring_map, BUS_DMASYNC_PREWRITE); 3562193880Syongari /* 3563193880Syongari * Let controller know availability of new Rx buffers. 3564193880Syongari * Since alc(4) use RXQ_CFG_RD_BURST_DEFAULT descriptors 3565193880Syongari * it may be possible to update ALC_MBOX_RD0_PROD_IDX 3566193880Syongari * only when Rx buffer pre-fetching is required. In 3567193880Syongari * addition we already set ALC_RX_RD_FREE_THRESH to 3568193880Syongari * RX_RD_FREE_THRESH_LO_DEFAULT descriptors. However 3569193880Syongari * it still seems that pre-fetching needs more 3570193880Syongari * experimentation. 3571193880Syongari */ 3572272730Syongari if ((sc->alc_flags & ALC_FLAG_AR816X_FAMILY) != 0) 3573272730Syongari CSR_WRITE_2(sc, ALC_MBOX_RD0_PROD_IDX, 3574272730Syongari (uint16_t)sc->alc_cdata.alc_rx_cons); 3575272730Syongari else 3576272730Syongari CSR_WRITE_4(sc, ALC_MBOX_RD0_PROD_IDX, 3577272730Syongari sc->alc_cdata.alc_rx_cons); 3578193880Syongari } 3579193880Syongari 3580193880Syongari return (count > 0 ? 0 : EAGAIN); 3581193880Syongari} 3582193880Syongari 3583193880Syongari#ifndef __NO_STRICT_ALIGNMENT 3584193880Syongaristatic struct mbuf * 3585193880Syongarialc_fixup_rx(struct ifnet *ifp, struct mbuf *m) 3586193880Syongari{ 3587193880Syongari struct mbuf *n; 3588193880Syongari int i; 3589193880Syongari uint16_t *src, *dst; 3590193880Syongari 3591193880Syongari src = mtod(m, uint16_t *); 3592193880Syongari dst = src - 3; 3593193880Syongari 3594193880Syongari if (m->m_next == NULL) { 3595193880Syongari for (i = 0; i < (m->m_len / sizeof(uint16_t) + 1); i++) 3596193880Syongari *dst++ = *src++; 3597193880Syongari m->m_data -= 6; 3598193880Syongari return (m); 3599193880Syongari } 3600193880Syongari /* 3601193880Syongari * Append a new mbuf to received mbuf chain and copy ethernet 3602193880Syongari * header from the mbuf chain. This can save lots of CPU 3603193880Syongari * cycles for jumbo frame. 3604193880Syongari */ 3605243857Sglebius MGETHDR(n, M_NOWAIT, MT_DATA); 3606193880Syongari if (n == NULL) { 3607271833Sglebius if_inc_counter(ifp, IFCOUNTER_IQDROPS, 1); 3608193880Syongari m_freem(m); 3609193880Syongari return (NULL); 3610193880Syongari } 3611193880Syongari bcopy(m->m_data, n->m_data, ETHER_HDR_LEN); 3612193880Syongari m->m_data += ETHER_HDR_LEN; 3613193880Syongari m->m_len -= ETHER_HDR_LEN; 3614193880Syongari n->m_len = ETHER_HDR_LEN; 3615193880Syongari M_MOVE_PKTHDR(n, m); 3616193880Syongari n->m_next = m; 3617193880Syongari return (n); 3618193880Syongari} 3619193880Syongari#endif 3620193880Syongari 3621193880Syongari/* Receive a frame. */ 3622193880Syongaristatic void 3623193880Syongarialc_rxeof(struct alc_softc *sc, struct rx_rdesc *rrd) 3624193880Syongari{ 3625193880Syongari struct alc_rxdesc *rxd; 3626193880Syongari struct ifnet *ifp; 3627193880Syongari struct mbuf *mp, *m; 3628193880Syongari uint32_t rdinfo, status, vtag; 3629193880Syongari int count, nsegs, rx_cons; 3630193880Syongari 3631193880Syongari ifp = sc->alc_ifp; 3632193880Syongari status = le32toh(rrd->status); 3633193880Syongari rdinfo = le32toh(rrd->rdinfo); 3634193880Syongari rx_cons = RRD_RD_IDX(rdinfo); 3635193880Syongari nsegs = RRD_RD_CNT(rdinfo); 3636193880Syongari 3637193880Syongari sc->alc_cdata.alc_rxlen = RRD_BYTES(status); 3638193880Syongari if ((status & (RRD_ERR_SUM | RRD_ERR_LENGTH)) != 0) { 3639193880Syongari /* 3640193880Syongari * We want to pass the following frames to upper 3641193880Syongari * layer regardless of error status of Rx return 3642193880Syongari * ring. 3643193880Syongari * 3644193880Syongari * o IP/TCP/UDP checksum is bad. 3645193880Syongari * o frame length and protocol specific length 3646193880Syongari * does not match. 3647193880Syongari * 3648193880Syongari * Force network stack compute checksum for 3649193880Syongari * errored frames. 3650193880Syongari */ 3651193880Syongari status |= RRD_TCP_UDPCSUM_NOK | RRD_IPCSUM_NOK; 3652212764Sdelphij if ((status & (RRD_ERR_CRC | RRD_ERR_ALIGN | 3653212764Sdelphij RRD_ERR_TRUNC | RRD_ERR_RUNT)) != 0) 3654193880Syongari return; 3655193880Syongari } 3656193880Syongari 3657193880Syongari for (count = 0; count < nsegs; count++, 3658193880Syongari ALC_DESC_INC(rx_cons, ALC_RX_RING_CNT)) { 3659193880Syongari rxd = &sc->alc_cdata.alc_rxdesc[rx_cons]; 3660193880Syongari mp = rxd->rx_m; 3661193880Syongari /* Add a new receive buffer to the ring. */ 3662193880Syongari if (alc_newbuf(sc, rxd) != 0) { 3663271833Sglebius if_inc_counter(ifp, IFCOUNTER_IQDROPS, 1); 3664193880Syongari /* Reuse Rx buffers. */ 3665193880Syongari if (sc->alc_cdata.alc_rxhead != NULL) 3666193880Syongari m_freem(sc->alc_cdata.alc_rxhead); 3667193880Syongari break; 3668193880Syongari } 3669193880Syongari 3670193880Syongari /* 3671193880Syongari * Assume we've received a full sized frame. 3672193880Syongari * Actual size is fixed when we encounter the end of 3673193880Syongari * multi-segmented frame. 3674193880Syongari */ 3675193880Syongari mp->m_len = sc->alc_buf_size; 3676193880Syongari 3677193880Syongari /* Chain received mbufs. */ 3678193880Syongari if (sc->alc_cdata.alc_rxhead == NULL) { 3679193880Syongari sc->alc_cdata.alc_rxhead = mp; 3680193880Syongari sc->alc_cdata.alc_rxtail = mp; 3681193880Syongari } else { 3682193880Syongari mp->m_flags &= ~M_PKTHDR; 3683193880Syongari sc->alc_cdata.alc_rxprev_tail = 3684193880Syongari sc->alc_cdata.alc_rxtail; 3685193880Syongari sc->alc_cdata.alc_rxtail->m_next = mp; 3686193880Syongari sc->alc_cdata.alc_rxtail = mp; 3687193880Syongari } 3688193880Syongari 3689193880Syongari if (count == nsegs - 1) { 3690193880Syongari /* Last desc. for this frame. */ 3691193880Syongari m = sc->alc_cdata.alc_rxhead; 3692193880Syongari m->m_flags |= M_PKTHDR; 3693193880Syongari /* 3694193880Syongari * It seems that L1C/L2C controller has no way 3695193880Syongari * to tell hardware to strip CRC bytes. 3696193880Syongari */ 3697193880Syongari m->m_pkthdr.len = 3698193880Syongari sc->alc_cdata.alc_rxlen - ETHER_CRC_LEN; 3699193880Syongari if (nsegs > 1) { 3700193880Syongari /* Set last mbuf size. */ 3701193880Syongari mp->m_len = sc->alc_cdata.alc_rxlen - 3702193880Syongari (nsegs - 1) * sc->alc_buf_size; 3703193880Syongari /* Remove the CRC bytes in chained mbufs. */ 3704193880Syongari if (mp->m_len <= ETHER_CRC_LEN) { 3705193880Syongari sc->alc_cdata.alc_rxtail = 3706193880Syongari sc->alc_cdata.alc_rxprev_tail; 3707193880Syongari sc->alc_cdata.alc_rxtail->m_len -= 3708193880Syongari (ETHER_CRC_LEN - mp->m_len); 3709193880Syongari sc->alc_cdata.alc_rxtail->m_next = NULL; 3710193880Syongari m_freem(mp); 3711193880Syongari } else { 3712193880Syongari mp->m_len -= ETHER_CRC_LEN; 3713193880Syongari } 3714193880Syongari } else 3715193880Syongari m->m_len = m->m_pkthdr.len; 3716193880Syongari m->m_pkthdr.rcvif = ifp; 3717193880Syongari /* 3718193880Syongari * Due to hardware bugs, Rx checksum offloading 3719193880Syongari * was intentionally disabled. 3720193880Syongari */ 3721193880Syongari if ((ifp->if_capenable & IFCAP_VLAN_HWTAGGING) != 0 && 3722193880Syongari (status & RRD_VLAN_TAG) != 0) { 3723193880Syongari vtag = RRD_VLAN(le32toh(rrd->vtag)); 3724193880Syongari m->m_pkthdr.ether_vtag = ntohs(vtag); 3725193880Syongari m->m_flags |= M_VLANTAG; 3726193880Syongari } 3727193880Syongari#ifndef __NO_STRICT_ALIGNMENT 3728193880Syongari m = alc_fixup_rx(ifp, m); 3729193880Syongari if (m != NULL) 3730193880Syongari#endif 3731193880Syongari { 3732193880Syongari /* Pass it on. */ 3733217379Sjhb ALC_UNLOCK(sc); 3734193880Syongari (*ifp->if_input)(ifp, m); 3735217379Sjhb ALC_LOCK(sc); 3736193880Syongari } 3737193880Syongari } 3738193880Syongari } 3739193880Syongari /* Reset mbuf chains. */ 3740193880Syongari ALC_RXCHAIN_RESET(sc); 3741193880Syongari} 3742193880Syongari 3743193880Syongaristatic void 3744193880Syongarialc_tick(void *arg) 3745193880Syongari{ 3746193880Syongari struct alc_softc *sc; 3747193880Syongari struct mii_data *mii; 3748193880Syongari 3749193880Syongari sc = (struct alc_softc *)arg; 3750193880Syongari 3751193880Syongari ALC_LOCK_ASSERT(sc); 3752193880Syongari 3753193880Syongari mii = device_get_softc(sc->alc_miibus); 3754193880Syongari mii_tick(mii); 3755193880Syongari alc_stats_update(sc); 3756193880Syongari /* 3757193880Syongari * alc(4) does not rely on Tx completion interrupts to reclaim 3758193880Syongari * transferred buffers. Instead Tx completion interrupts are 3759193880Syongari * used to hint for scheduling Tx task. So it's necessary to 3760193880Syongari * release transmitted buffers by kicking Tx completion 3761193880Syongari * handler. This limits the maximum reclamation delay to a hz. 3762193880Syongari */ 3763193880Syongari alc_txeof(sc); 3764193880Syongari alc_watchdog(sc); 3765193880Syongari callout_reset(&sc->alc_tick_ch, hz, alc_tick, sc); 3766193880Syongari} 3767193880Syongari 3768193880Syongaristatic void 3769272730Syongarialc_osc_reset(struct alc_softc *sc) 3770272730Syongari{ 3771272730Syongari uint32_t reg; 3772272730Syongari 3773272730Syongari reg = CSR_READ_4(sc, ALC_MISC3); 3774272730Syongari reg &= ~MISC3_25M_BY_SW; 3775272730Syongari reg |= MISC3_25M_NOTO_INTNL; 3776272730Syongari CSR_WRITE_4(sc, ALC_MISC3, reg); 3777272730Syongari 3778272730Syongari reg = CSR_READ_4(sc, ALC_MISC); 3779272730Syongari if (AR816X_REV(sc->alc_rev) >= AR816X_REV_B0) { 3780272730Syongari /* 3781272730Syongari * Restore over-current protection default value. 3782272730Syongari * This value could be reset by MAC reset. 3783272730Syongari */ 3784272730Syongari reg &= ~MISC_PSW_OCP_MASK; 3785272730Syongari reg |= (MISC_PSW_OCP_DEFAULT << MISC_PSW_OCP_SHIFT); 3786272730Syongari reg &= ~MISC_INTNLOSC_OPEN; 3787272730Syongari CSR_WRITE_4(sc, ALC_MISC, reg); 3788272730Syongari CSR_WRITE_4(sc, ALC_MISC, reg | MISC_INTNLOSC_OPEN); 3789272730Syongari reg = CSR_READ_4(sc, ALC_MISC2); 3790272730Syongari reg &= ~MISC2_CALB_START; 3791272730Syongari CSR_WRITE_4(sc, ALC_MISC2, reg); 3792272730Syongari CSR_WRITE_4(sc, ALC_MISC2, reg | MISC2_CALB_START); 3793272730Syongari 3794272730Syongari } else { 3795272730Syongari reg &= ~MISC_INTNLOSC_OPEN; 3796272730Syongari /* Disable isolate for revision A devices. */ 3797272730Syongari if (AR816X_REV(sc->alc_rev) <= AR816X_REV_A1) 3798272730Syongari reg &= ~MISC_ISO_ENB; 3799272730Syongari CSR_WRITE_4(sc, ALC_MISC, reg | MISC_INTNLOSC_OPEN); 3800272730Syongari CSR_WRITE_4(sc, ALC_MISC, reg); 3801272730Syongari } 3802272730Syongari 3803272730Syongari DELAY(20); 3804272730Syongari} 3805272730Syongari 3806272730Syongaristatic void 3807193880Syongarialc_reset(struct alc_softc *sc) 3808193880Syongari{ 3809272730Syongari uint32_t pmcfg, reg; 3810193880Syongari int i; 3811193880Syongari 3812272730Syongari pmcfg = 0; 3813272730Syongari if ((sc->alc_flags & ALC_FLAG_AR816X_FAMILY) != 0) { 3814272730Syongari /* Reset workaround. */ 3815272730Syongari CSR_WRITE_4(sc, ALC_MBOX_RD0_PROD_IDX, 1); 3816272730Syongari if (AR816X_REV(sc->alc_rev) <= AR816X_REV_A1 && 3817272730Syongari (sc->alc_rev & 0x01) != 0) { 3818272730Syongari /* Disable L0s/L1s before reset. */ 3819272730Syongari pmcfg = CSR_READ_4(sc, ALC_PM_CFG); 3820272730Syongari if ((pmcfg & (PM_CFG_ASPM_L0S_ENB | PM_CFG_ASPM_L1_ENB)) 3821272730Syongari != 0) { 3822272730Syongari pmcfg &= ~(PM_CFG_ASPM_L0S_ENB | 3823272730Syongari PM_CFG_ASPM_L1_ENB); 3824272730Syongari CSR_WRITE_4(sc, ALC_PM_CFG, pmcfg); 3825272730Syongari } 3826272730Syongari } 3827272730Syongari } 3828272730Syongari reg = CSR_READ_4(sc, ALC_MASTER_CFG); 3829211105Syongari reg |= MASTER_OOB_DIS_OFF | MASTER_RESET; 3830211105Syongari CSR_WRITE_4(sc, ALC_MASTER_CFG, reg); 3831272730Syongari 3832272730Syongari if ((sc->alc_flags & ALC_FLAG_AR816X_FAMILY) != 0) { 3833272730Syongari for (i = ALC_RESET_TIMEOUT; i > 0; i--) { 3834272730Syongari DELAY(10); 3835272730Syongari if (CSR_READ_4(sc, ALC_MBOX_RD0_PROD_IDX) == 0) 3836272730Syongari break; 3837272730Syongari } 3838272730Syongari if (i == 0) 3839272730Syongari device_printf(sc->alc_dev, "MAC reset timeout!\n"); 3840272730Syongari } 3841193880Syongari for (i = ALC_RESET_TIMEOUT; i > 0; i--) { 3842193880Syongari DELAY(10); 3843193880Syongari if ((CSR_READ_4(sc, ALC_MASTER_CFG) & MASTER_RESET) == 0) 3844193880Syongari break; 3845193880Syongari } 3846193880Syongari if (i == 0) 3847193880Syongari device_printf(sc->alc_dev, "master reset timeout!\n"); 3848193880Syongari 3849193880Syongari for (i = ALC_RESET_TIMEOUT; i > 0; i--) { 3850272730Syongari reg = CSR_READ_4(sc, ALC_IDLE_STATUS); 3851272730Syongari if ((reg & (IDLE_STATUS_RXMAC | IDLE_STATUS_TXMAC | 3852272730Syongari IDLE_STATUS_RXQ | IDLE_STATUS_TXQ)) == 0) 3853193880Syongari break; 3854193880Syongari DELAY(10); 3855193880Syongari } 3856193880Syongari if (i == 0) 3857193880Syongari device_printf(sc->alc_dev, "reset timeout(0x%08x)!\n", reg); 3858272730Syongari 3859272730Syongari if ((sc->alc_flags & ALC_FLAG_AR816X_FAMILY) != 0) { 3860272730Syongari if (AR816X_REV(sc->alc_rev) <= AR816X_REV_A1 && 3861272730Syongari (sc->alc_rev & 0x01) != 0) { 3862272730Syongari reg = CSR_READ_4(sc, ALC_MASTER_CFG); 3863272730Syongari reg |= MASTER_CLK_SEL_DIS; 3864272730Syongari CSR_WRITE_4(sc, ALC_MASTER_CFG, reg); 3865272730Syongari /* Restore L0s/L1s config. */ 3866272730Syongari if ((pmcfg & (PM_CFG_ASPM_L0S_ENB | PM_CFG_ASPM_L1_ENB)) 3867272730Syongari != 0) 3868272730Syongari CSR_WRITE_4(sc, ALC_PM_CFG, pmcfg); 3869272730Syongari } 3870272730Syongari 3871272730Syongari alc_osc_reset(sc); 3872272730Syongari reg = CSR_READ_4(sc, ALC_MISC3); 3873272730Syongari reg &= ~MISC3_25M_BY_SW; 3874272730Syongari reg |= MISC3_25M_NOTO_INTNL; 3875272730Syongari CSR_WRITE_4(sc, ALC_MISC3, reg); 3876272730Syongari reg = CSR_READ_4(sc, ALC_MISC); 3877272730Syongari reg &= ~MISC_INTNLOSC_OPEN; 3878272730Syongari if (AR816X_REV(sc->alc_rev) <= AR816X_REV_A1) 3879272730Syongari reg &= ~MISC_ISO_ENB; 3880272730Syongari CSR_WRITE_4(sc, ALC_MISC, reg); 3881272730Syongari DELAY(20); 3882272730Syongari } 3883272730Syongari if ((sc->alc_flags & ALC_FLAG_AR816X_FAMILY) != 0 || 3884272730Syongari sc->alc_ident->deviceid == DEVICEID_ATHEROS_AR8152_B || 3885272730Syongari sc->alc_ident->deviceid == DEVICEID_ATHEROS_AR8151_V2) 3886272730Syongari CSR_WRITE_4(sc, ALC_SERDES_LOCK, 3887272730Syongari CSR_READ_4(sc, ALC_SERDES_LOCK) | SERDES_MAC_CLK_SLOWDOWN | 3888272730Syongari SERDES_PHY_CLK_SLOWDOWN); 3889193880Syongari} 3890193880Syongari 3891193880Syongaristatic void 3892193880Syongarialc_init(void *xsc) 3893193880Syongari{ 3894193880Syongari struct alc_softc *sc; 3895193880Syongari 3896193880Syongari sc = (struct alc_softc *)xsc; 3897193880Syongari ALC_LOCK(sc); 3898193880Syongari alc_init_locked(sc); 3899193880Syongari ALC_UNLOCK(sc); 3900193880Syongari} 3901193880Syongari 3902193880Syongaristatic void 3903193880Syongarialc_init_locked(struct alc_softc *sc) 3904193880Syongari{ 3905193880Syongari struct ifnet *ifp; 3906193880Syongari struct mii_data *mii; 3907193880Syongari uint8_t eaddr[ETHER_ADDR_LEN]; 3908193880Syongari bus_addr_t paddr; 3909193880Syongari uint32_t reg, rxf_hi, rxf_lo; 3910193880Syongari 3911193880Syongari ALC_LOCK_ASSERT(sc); 3912193880Syongari 3913193880Syongari ifp = sc->alc_ifp; 3914193880Syongari mii = device_get_softc(sc->alc_miibus); 3915193880Syongari 3916193880Syongari if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0) 3917193880Syongari return; 3918193880Syongari /* 3919193880Syongari * Cancel any pending I/O. 3920193880Syongari */ 3921193880Syongari alc_stop(sc); 3922193880Syongari /* 3923193880Syongari * Reset the chip to a known state. 3924193880Syongari */ 3925193880Syongari alc_reset(sc); 3926193880Syongari 3927193880Syongari /* Initialize Rx descriptors. */ 3928193880Syongari if (alc_init_rx_ring(sc) != 0) { 3929193880Syongari device_printf(sc->alc_dev, "no memory for Rx buffers.\n"); 3930193880Syongari alc_stop(sc); 3931193880Syongari return; 3932193880Syongari } 3933193880Syongari alc_init_rr_ring(sc); 3934193880Syongari alc_init_tx_ring(sc); 3935193880Syongari alc_init_cmb(sc); 3936193880Syongari alc_init_smb(sc); 3937193880Syongari 3938217649Syongari /* Enable all clocks. */ 3939272730Syongari if ((sc->alc_flags & ALC_FLAG_AR816X_FAMILY) != 0) { 3940272730Syongari CSR_WRITE_4(sc, ALC_CLK_GATING_CFG, CLK_GATING_DMAW_ENB | 3941272730Syongari CLK_GATING_DMAR_ENB | CLK_GATING_TXQ_ENB | 3942272730Syongari CLK_GATING_RXQ_ENB | CLK_GATING_TXMAC_ENB | 3943272730Syongari CLK_GATING_RXMAC_ENB); 3944272730Syongari if (AR816X_REV(sc->alc_rev) >= AR816X_REV_B0) 3945272730Syongari CSR_WRITE_4(sc, ALC_IDLE_DECISN_TIMER, 3946272730Syongari IDLE_DECISN_TIMER_DEFAULT_1MS); 3947272730Syongari } else 3948272730Syongari CSR_WRITE_4(sc, ALC_CLK_GATING_CFG, 0); 3949217649Syongari 3950193880Syongari /* Reprogram the station address. */ 3951193880Syongari bcopy(IF_LLADDR(ifp), eaddr, ETHER_ADDR_LEN); 3952193880Syongari CSR_WRITE_4(sc, ALC_PAR0, 3953193880Syongari eaddr[2] << 24 | eaddr[3] << 16 | eaddr[4] << 8 | eaddr[5]); 3954193880Syongari CSR_WRITE_4(sc, ALC_PAR1, eaddr[0] << 8 | eaddr[1]); 3955193880Syongari /* 3956193880Syongari * Clear WOL status and disable all WOL feature as WOL 3957193880Syongari * would interfere Rx operation under normal environments. 3958193880Syongari */ 3959193880Syongari CSR_READ_4(sc, ALC_WOL_CFG); 3960193880Syongari CSR_WRITE_4(sc, ALC_WOL_CFG, 0); 3961193880Syongari /* Set Tx descriptor base addresses. */ 3962193880Syongari paddr = sc->alc_rdata.alc_tx_ring_paddr; 3963193880Syongari CSR_WRITE_4(sc, ALC_TX_BASE_ADDR_HI, ALC_ADDR_HI(paddr)); 3964193880Syongari CSR_WRITE_4(sc, ALC_TDL_HEAD_ADDR_LO, ALC_ADDR_LO(paddr)); 3965193880Syongari /* We don't use high priority ring. */ 3966193880Syongari CSR_WRITE_4(sc, ALC_TDH_HEAD_ADDR_LO, 0); 3967193880Syongari /* Set Tx descriptor counter. */ 3968193880Syongari CSR_WRITE_4(sc, ALC_TD_RING_CNT, 3969193880Syongari (ALC_TX_RING_CNT << TD_RING_CNT_SHIFT) & TD_RING_CNT_MASK); 3970193880Syongari /* Set Rx descriptor base addresses. */ 3971193880Syongari paddr = sc->alc_rdata.alc_rx_ring_paddr; 3972193880Syongari CSR_WRITE_4(sc, ALC_RX_BASE_ADDR_HI, ALC_ADDR_HI(paddr)); 3973193880Syongari CSR_WRITE_4(sc, ALC_RD0_HEAD_ADDR_LO, ALC_ADDR_LO(paddr)); 3974272730Syongari if ((sc->alc_flags & ALC_FLAG_AR816X_FAMILY) == 0) { 3975272730Syongari /* We use one Rx ring. */ 3976272730Syongari CSR_WRITE_4(sc, ALC_RD1_HEAD_ADDR_LO, 0); 3977272730Syongari CSR_WRITE_4(sc, ALC_RD2_HEAD_ADDR_LO, 0); 3978272730Syongari CSR_WRITE_4(sc, ALC_RD3_HEAD_ADDR_LO, 0); 3979272730Syongari } 3980193880Syongari /* Set Rx descriptor counter. */ 3981193880Syongari CSR_WRITE_4(sc, ALC_RD_RING_CNT, 3982193880Syongari (ALC_RX_RING_CNT << RD_RING_CNT_SHIFT) & RD_RING_CNT_MASK); 3983193880Syongari 3984193880Syongari /* 3985193880Syongari * Let hardware split jumbo frames into alc_max_buf_sized chunks. 3986193880Syongari * if it do not fit the buffer size. Rx return descriptor holds 3987193880Syongari * a counter that indicates how many fragments were made by the 3988193880Syongari * hardware. The buffer size should be multiple of 8 bytes. 3989193880Syongari * Since hardware has limit on the size of buffer size, always 3990193880Syongari * use the maximum value. 3991193880Syongari * For strict-alignment architectures make sure to reduce buffer 3992193880Syongari * size by 8 bytes to make room for alignment fixup. 3993193880Syongari */ 3994193880Syongari#ifndef __NO_STRICT_ALIGNMENT 3995193880Syongari sc->alc_buf_size = RX_BUF_SIZE_MAX - sizeof(uint64_t); 3996193880Syongari#else 3997193880Syongari sc->alc_buf_size = RX_BUF_SIZE_MAX; 3998193880Syongari#endif 3999193880Syongari CSR_WRITE_4(sc, ALC_RX_BUF_SIZE, sc->alc_buf_size); 4000193880Syongari 4001193880Syongari paddr = sc->alc_rdata.alc_rr_ring_paddr; 4002193880Syongari /* Set Rx return descriptor base addresses. */ 4003193880Syongari CSR_WRITE_4(sc, ALC_RRD0_HEAD_ADDR_LO, ALC_ADDR_LO(paddr)); 4004272730Syongari if ((sc->alc_flags & ALC_FLAG_AR816X_FAMILY) == 0) { 4005272730Syongari /* We use one Rx return ring. */ 4006272730Syongari CSR_WRITE_4(sc, ALC_RRD1_HEAD_ADDR_LO, 0); 4007272730Syongari CSR_WRITE_4(sc, ALC_RRD2_HEAD_ADDR_LO, 0); 4008272730Syongari CSR_WRITE_4(sc, ALC_RRD3_HEAD_ADDR_LO, 0); 4009272730Syongari } 4010193880Syongari /* Set Rx return descriptor counter. */ 4011193880Syongari CSR_WRITE_4(sc, ALC_RRD_RING_CNT, 4012193880Syongari (ALC_RR_RING_CNT << RRD_RING_CNT_SHIFT) & RRD_RING_CNT_MASK); 4013193880Syongari paddr = sc->alc_rdata.alc_cmb_paddr; 4014193880Syongari CSR_WRITE_4(sc, ALC_CMB_BASE_ADDR_LO, ALC_ADDR_LO(paddr)); 4015193880Syongari paddr = sc->alc_rdata.alc_smb_paddr; 4016193880Syongari CSR_WRITE_4(sc, ALC_SMB_BASE_ADDR_HI, ALC_ADDR_HI(paddr)); 4017193880Syongari CSR_WRITE_4(sc, ALC_SMB_BASE_ADDR_LO, ALC_ADDR_LO(paddr)); 4018193880Syongari 4019211105Syongari if (sc->alc_ident->deviceid == DEVICEID_ATHEROS_AR8152_B) { 4020211105Syongari /* Reconfigure SRAM - Vendor magic. */ 4021211105Syongari CSR_WRITE_4(sc, ALC_SRAM_RX_FIFO_LEN, 0x000002A0); 4022211105Syongari CSR_WRITE_4(sc, ALC_SRAM_TX_FIFO_LEN, 0x00000100); 4023211105Syongari CSR_WRITE_4(sc, ALC_SRAM_RX_FIFO_ADDR, 0x029F0000); 4024211105Syongari CSR_WRITE_4(sc, ALC_SRAM_RD0_ADDR, 0x02BF02A0); 4025211105Syongari CSR_WRITE_4(sc, ALC_SRAM_TX_FIFO_ADDR, 0x03BF02C0); 4026211105Syongari CSR_WRITE_4(sc, ALC_SRAM_TD_ADDR, 0x03DF03C0); 4027211105Syongari CSR_WRITE_4(sc, ALC_TXF_WATER_MARK, 0x00000000); 4028211105Syongari CSR_WRITE_4(sc, ALC_RD_DMA_CFG, 0x00000000); 4029211105Syongari } 4030211105Syongari 4031193880Syongari /* Tell hardware that we're ready to load DMA blocks. */ 4032193880Syongari CSR_WRITE_4(sc, ALC_DMA_BLOCK, DMA_BLOCK_LOAD); 4033193880Syongari 4034193880Syongari /* Configure interrupt moderation timer. */ 4035193880Syongari reg = ALC_USECS(sc->alc_int_rx_mod) << IM_TIMER_RX_SHIFT; 4036272730Syongari if ((sc->alc_flags & ALC_FLAG_AR816X_FAMILY) == 0) 4037272730Syongari reg |= ALC_USECS(sc->alc_int_tx_mod) << IM_TIMER_TX_SHIFT; 4038193880Syongari CSR_WRITE_4(sc, ALC_IM_TIMER, reg); 4039193880Syongari /* 4040193880Syongari * We don't want to automatic interrupt clear as task queue 4041193880Syongari * for the interrupt should know interrupt status. 4042193880Syongari */ 4043272730Syongari reg = CSR_READ_4(sc, ALC_MASTER_CFG); 4044272730Syongari reg &= ~(MASTER_IM_RX_TIMER_ENB | MASTER_IM_TX_TIMER_ENB); 4045272730Syongari reg |= MASTER_SA_TIMER_ENB; 4046193880Syongari if (ALC_USECS(sc->alc_int_rx_mod) != 0) 4047193880Syongari reg |= MASTER_IM_RX_TIMER_ENB; 4048272730Syongari if ((sc->alc_flags & ALC_FLAG_AR816X_FAMILY) == 0 && 4049272730Syongari ALC_USECS(sc->alc_int_tx_mod) != 0) 4050193880Syongari reg |= MASTER_IM_TX_TIMER_ENB; 4051193880Syongari CSR_WRITE_4(sc, ALC_MASTER_CFG, reg); 4052193880Syongari /* 4053193880Syongari * Disable interrupt re-trigger timer. We don't want automatic 4054193880Syongari * re-triggering of un-ACKed interrupts. 4055193880Syongari */ 4056193880Syongari CSR_WRITE_4(sc, ALC_INTR_RETRIG_TIMER, ALC_USECS(0)); 4057193880Syongari /* Configure CMB. */ 4058272730Syongari if ((sc->alc_flags & ALC_FLAG_AR816X_FAMILY) != 0) { 4059272730Syongari CSR_WRITE_4(sc, ALC_CMB_TD_THRESH, ALC_TX_RING_CNT / 3); 4060272730Syongari CSR_WRITE_4(sc, ALC_CMB_TX_TIMER, 4061272730Syongari ALC_USECS(sc->alc_int_tx_mod)); 4062272730Syongari } else { 4063272730Syongari if ((sc->alc_flags & ALC_FLAG_CMB_BUG) == 0) { 4064272730Syongari CSR_WRITE_4(sc, ALC_CMB_TD_THRESH, 4); 4065272730Syongari CSR_WRITE_4(sc, ALC_CMB_TX_TIMER, ALC_USECS(5000)); 4066272730Syongari } else 4067272730Syongari CSR_WRITE_4(sc, ALC_CMB_TX_TIMER, ALC_USECS(0)); 4068272730Syongari } 4069193880Syongari /* 4070193880Syongari * Hardware can be configured to issue SMB interrupt based 4071193880Syongari * on programmed interval. Since there is a callout that is 4072193880Syongari * invoked for every hz in driver we use that instead of 4073193880Syongari * relying on periodic SMB interrupt. 4074193880Syongari */ 4075193880Syongari CSR_WRITE_4(sc, ALC_SMB_STAT_TIMER, ALC_USECS(0)); 4076193880Syongari /* Clear MAC statistics. */ 4077193880Syongari alc_stats_clear(sc); 4078193880Syongari 4079193880Syongari /* 4080193880Syongari * Always use maximum frame size that controller can support. 4081193880Syongari * Otherwise received frames that has larger frame length 4082193880Syongari * than alc(4) MTU would be silently dropped in hardware. This 4083193880Syongari * would make path-MTU discovery hard as sender wouldn't get 4084193880Syongari * any responses from receiver. alc(4) supports 4085193880Syongari * multi-fragmented frames on Rx path so it has no issue on 4086193880Syongari * assembling fragmented frames. Using maximum frame size also 4087193880Syongari * removes the need to reinitialize hardware when interface 4088193880Syongari * MTU configuration was changed. 4089193880Syongari * 4090193880Syongari * Be conservative in what you do, be liberal in what you 4091193880Syongari * accept from others - RFC 793. 4092193880Syongari */ 4093211105Syongari CSR_WRITE_4(sc, ALC_FRAME_SIZE, sc->alc_ident->max_framelen); 4094193880Syongari 4095272730Syongari if ((sc->alc_flags & ALC_FLAG_AR816X_FAMILY) == 0) { 4096272730Syongari /* Disable header split(?) */ 4097272730Syongari CSR_WRITE_4(sc, ALC_HDS_CFG, 0); 4098193880Syongari 4099272730Syongari /* Configure IPG/IFG parameters. */ 4100272730Syongari CSR_WRITE_4(sc, ALC_IPG_IFG_CFG, 4101272730Syongari ((IPG_IFG_IPGT_DEFAULT << IPG_IFG_IPGT_SHIFT) & 4102272730Syongari IPG_IFG_IPGT_MASK) | 4103272730Syongari ((IPG_IFG_MIFG_DEFAULT << IPG_IFG_MIFG_SHIFT) & 4104272730Syongari IPG_IFG_MIFG_MASK) | 4105272730Syongari ((IPG_IFG_IPG1_DEFAULT << IPG_IFG_IPG1_SHIFT) & 4106272730Syongari IPG_IFG_IPG1_MASK) | 4107272730Syongari ((IPG_IFG_IPG2_DEFAULT << IPG_IFG_IPG2_SHIFT) & 4108272730Syongari IPG_IFG_IPG2_MASK)); 4109272730Syongari /* Set parameters for half-duplex media. */ 4110272730Syongari CSR_WRITE_4(sc, ALC_HDPX_CFG, 4111272730Syongari ((HDPX_CFG_LCOL_DEFAULT << HDPX_CFG_LCOL_SHIFT) & 4112272730Syongari HDPX_CFG_LCOL_MASK) | 4113272730Syongari ((HDPX_CFG_RETRY_DEFAULT << HDPX_CFG_RETRY_SHIFT) & 4114272730Syongari HDPX_CFG_RETRY_MASK) | HDPX_CFG_EXC_DEF_EN | 4115272730Syongari ((HDPX_CFG_ABEBT_DEFAULT << HDPX_CFG_ABEBT_SHIFT) & 4116272730Syongari HDPX_CFG_ABEBT_MASK) | 4117272730Syongari ((HDPX_CFG_JAMIPG_DEFAULT << HDPX_CFG_JAMIPG_SHIFT) & 4118272730Syongari HDPX_CFG_JAMIPG_MASK)); 4119272730Syongari } 4120272730Syongari 4121193880Syongari /* 4122193880Syongari * Set TSO/checksum offload threshold. For frames that is 4123193880Syongari * larger than this threshold, hardware wouldn't do 4124193880Syongari * TSO/checksum offloading. 4125193880Syongari */ 4126272730Syongari reg = (sc->alc_ident->max_framelen >> TSO_OFFLOAD_THRESH_UNIT_SHIFT) & 4127272730Syongari TSO_OFFLOAD_THRESH_MASK; 4128272730Syongari if ((sc->alc_flags & ALC_FLAG_AR816X_FAMILY) != 0) 4129272730Syongari reg |= TSO_OFFLOAD_ERRLGPKT_DROP_ENB; 4130272730Syongari CSR_WRITE_4(sc, ALC_TSO_OFFLOAD_THRESH, reg); 4131193880Syongari /* Configure TxQ. */ 4132193880Syongari reg = (alc_dma_burst[sc->alc_dma_rd_burst] << 4133193880Syongari TXQ_CFG_TX_FIFO_BURST_SHIFT) & TXQ_CFG_TX_FIFO_BURST_MASK; 4134211105Syongari if (sc->alc_ident->deviceid == DEVICEID_ATHEROS_AR8152_B || 4135211105Syongari sc->alc_ident->deviceid == DEVICEID_ATHEROS_AR8152_B2) 4136211105Syongari reg >>= 1; 4137193880Syongari reg |= (TXQ_CFG_TD_BURST_DEFAULT << TXQ_CFG_TD_BURST_SHIFT) & 4138193880Syongari TXQ_CFG_TD_BURST_MASK; 4139272730Syongari reg |= TXQ_CFG_IP_OPTION_ENB | TXQ_CFG_8023_ENB; 4140193880Syongari CSR_WRITE_4(sc, ALC_TXQ_CFG, reg | TXQ_CFG_ENHANCED_MODE); 4141272730Syongari if ((sc->alc_flags & ALC_FLAG_AR816X_FAMILY) != 0) { 4142272730Syongari reg = (TXQ_CFG_TD_BURST_DEFAULT << HQTD_CFG_Q1_BURST_SHIFT | 4143272730Syongari TXQ_CFG_TD_BURST_DEFAULT << HQTD_CFG_Q2_BURST_SHIFT | 4144272730Syongari TXQ_CFG_TD_BURST_DEFAULT << HQTD_CFG_Q3_BURST_SHIFT | 4145272730Syongari HQTD_CFG_BURST_ENB); 4146272730Syongari CSR_WRITE_4(sc, ALC_HQTD_CFG, reg); 4147272730Syongari reg = WRR_PRI_RESTRICT_NONE; 4148272730Syongari reg |= (WRR_PRI_DEFAULT << WRR_PRI0_SHIFT | 4149272730Syongari WRR_PRI_DEFAULT << WRR_PRI1_SHIFT | 4150272730Syongari WRR_PRI_DEFAULT << WRR_PRI2_SHIFT | 4151272730Syongari WRR_PRI_DEFAULT << WRR_PRI3_SHIFT); 4152272730Syongari CSR_WRITE_4(sc, ALC_WRR, reg); 4153272730Syongari } else { 4154272730Syongari /* Configure Rx free descriptor pre-fetching. */ 4155272730Syongari CSR_WRITE_4(sc, ALC_RX_RD_FREE_THRESH, 4156272730Syongari ((RX_RD_FREE_THRESH_HI_DEFAULT << 4157272730Syongari RX_RD_FREE_THRESH_HI_SHIFT) & RX_RD_FREE_THRESH_HI_MASK) | 4158272730Syongari ((RX_RD_FREE_THRESH_LO_DEFAULT << 4159272730Syongari RX_RD_FREE_THRESH_LO_SHIFT) & RX_RD_FREE_THRESH_LO_MASK)); 4160272730Syongari } 4161193880Syongari 4162193880Syongari /* 4163193880Syongari * Configure flow control parameters. 4164193880Syongari * XON : 80% of Rx FIFO 4165193880Syongari * XOFF : 30% of Rx FIFO 4166193880Syongari */ 4167272730Syongari if ((sc->alc_flags & ALC_FLAG_AR816X_FAMILY) != 0) { 4168272730Syongari reg = CSR_READ_4(sc, ALC_SRAM_RX_FIFO_LEN); 4169272730Syongari reg &= SRAM_RX_FIFO_LEN_MASK; 4170272730Syongari reg *= 8; 4171272730Syongari if (reg > 8 * 1024) 4172272730Syongari reg -= RX_FIFO_PAUSE_816X_RSVD; 4173272730Syongari else 4174272730Syongari reg -= RX_BUF_SIZE_MAX; 4175272730Syongari reg /= 8; 4176272730Syongari CSR_WRITE_4(sc, ALC_RX_FIFO_PAUSE_THRESH, 4177272730Syongari ((reg << RX_FIFO_PAUSE_THRESH_LO_SHIFT) & 4178272730Syongari RX_FIFO_PAUSE_THRESH_LO_MASK) | 4179272730Syongari (((RX_FIFO_PAUSE_816X_RSVD / 8) << 4180272730Syongari RX_FIFO_PAUSE_THRESH_HI_SHIFT) & 4181272730Syongari RX_FIFO_PAUSE_THRESH_HI_MASK)); 4182272730Syongari } else if (sc->alc_ident->deviceid == DEVICEID_ATHEROS_AR8131 || 4183211105Syongari sc->alc_ident->deviceid == DEVICEID_ATHEROS_AR8132) { 4184211105Syongari reg = CSR_READ_4(sc, ALC_SRAM_RX_FIFO_LEN); 4185211105Syongari rxf_hi = (reg * 8) / 10; 4186211105Syongari rxf_lo = (reg * 3) / 10; 4187211105Syongari CSR_WRITE_4(sc, ALC_RX_FIFO_PAUSE_THRESH, 4188211105Syongari ((rxf_lo << RX_FIFO_PAUSE_THRESH_LO_SHIFT) & 4189211105Syongari RX_FIFO_PAUSE_THRESH_LO_MASK) | 4190211105Syongari ((rxf_hi << RX_FIFO_PAUSE_THRESH_HI_SHIFT) & 4191211105Syongari RX_FIFO_PAUSE_THRESH_HI_MASK)); 4192211105Syongari } 4193193880Syongari 4194272730Syongari if ((sc->alc_flags & ALC_FLAG_AR816X_FAMILY) == 0) { 4195272730Syongari /* Disable RSS until I understand L1C/L2C's RSS logic. */ 4196272730Syongari CSR_WRITE_4(sc, ALC_RSS_IDT_TABLE0, 0); 4197272730Syongari CSR_WRITE_4(sc, ALC_RSS_CPU, 0); 4198272730Syongari } 4199211105Syongari 4200193880Syongari /* Configure RxQ. */ 4201193880Syongari reg = (RXQ_CFG_RD_BURST_DEFAULT << RXQ_CFG_RD_BURST_SHIFT) & 4202193880Syongari RXQ_CFG_RD_BURST_MASK; 4203193880Syongari reg |= RXQ_CFG_RSS_MODE_DIS; 4204312358Syongari if ((sc->alc_flags & ALC_FLAG_AR816X_FAMILY) != 0) { 4205272730Syongari reg |= (RXQ_CFG_816X_IDT_TBL_SIZE_DEFAULT << 4206272730Syongari RXQ_CFG_816X_IDT_TBL_SIZE_SHIFT) & 4207272730Syongari RXQ_CFG_816X_IDT_TBL_SIZE_MASK; 4208312358Syongari if ((sc->alc_flags & ALC_FLAG_FASTETHER) == 0) 4209312358Syongari reg |= RXQ_CFG_ASPM_THROUGHPUT_LIMIT_100M; 4210312358Syongari } else { 4211312358Syongari if ((sc->alc_flags & ALC_FLAG_FASTETHER) == 0 && 4212312358Syongari sc->alc_ident->deviceid != DEVICEID_ATHEROS_AR8151_V2) 4213312358Syongari reg |= RXQ_CFG_ASPM_THROUGHPUT_LIMIT_100M; 4214312358Syongari } 4215193880Syongari CSR_WRITE_4(sc, ALC_RXQ_CFG, reg); 4216193880Syongari 4217193880Syongari /* Configure DMA parameters. */ 4218193880Syongari reg = DMA_CFG_OUT_ORDER | DMA_CFG_RD_REQ_PRI; 4219193880Syongari reg |= sc->alc_rcb; 4220193880Syongari if ((sc->alc_flags & ALC_FLAG_CMB_BUG) == 0) 4221193880Syongari reg |= DMA_CFG_CMB_ENB; 4222193880Syongari if ((sc->alc_flags & ALC_FLAG_SMB_BUG) == 0) 4223193880Syongari reg |= DMA_CFG_SMB_ENB; 4224193880Syongari else 4225193880Syongari reg |= DMA_CFG_SMB_DIS; 4226193880Syongari reg |= (sc->alc_dma_rd_burst & DMA_CFG_RD_BURST_MASK) << 4227193880Syongari DMA_CFG_RD_BURST_SHIFT; 4228193880Syongari reg |= (sc->alc_dma_wr_burst & DMA_CFG_WR_BURST_MASK) << 4229193880Syongari DMA_CFG_WR_BURST_SHIFT; 4230193880Syongari reg |= (DMA_CFG_RD_DELAY_CNT_DEFAULT << DMA_CFG_RD_DELAY_CNT_SHIFT) & 4231193880Syongari DMA_CFG_RD_DELAY_CNT_MASK; 4232193880Syongari reg |= (DMA_CFG_WR_DELAY_CNT_DEFAULT << DMA_CFG_WR_DELAY_CNT_SHIFT) & 4233193880Syongari DMA_CFG_WR_DELAY_CNT_MASK; 4234272730Syongari if ((sc->alc_flags & ALC_FLAG_AR816X_FAMILY) != 0) { 4235272730Syongari switch (AR816X_REV(sc->alc_rev)) { 4236272730Syongari case AR816X_REV_A0: 4237272730Syongari case AR816X_REV_A1: 4238312358Syongari reg |= DMA_CFG_RD_CHNL_SEL_2; 4239272730Syongari break; 4240272730Syongari case AR816X_REV_B0: 4241272730Syongari /* FALLTHROUGH */ 4242272730Syongari default: 4243312358Syongari reg |= DMA_CFG_RD_CHNL_SEL_4; 4244272730Syongari break; 4245272730Syongari } 4246272730Syongari } 4247193880Syongari CSR_WRITE_4(sc, ALC_DMA_CFG, reg); 4248193880Syongari 4249193880Syongari /* 4250193880Syongari * Configure Tx/Rx MACs. 4251193880Syongari * - Auto-padding for short frames. 4252193880Syongari * - Enable CRC generation. 4253193880Syongari * Actual reconfiguration of MAC for resolved speed/duplex 4254193880Syongari * is followed after detection of link establishment. 4255211105Syongari * AR813x/AR815x always does checksum computation regardless 4256193880Syongari * of MAC_CFG_RXCSUM_ENB bit. Also the controller is known to 4257193880Syongari * have bug in protocol field in Rx return structure so 4258193880Syongari * these controllers can't handle fragmented frames. Disable 4259193880Syongari * Rx checksum offloading until there is a newer controller 4260193880Syongari * that has sane implementation. 4261193880Syongari */ 4262193880Syongari reg = MAC_CFG_TX_CRC_ENB | MAC_CFG_TX_AUTO_PAD | MAC_CFG_FULL_DUPLEX | 4263193880Syongari ((MAC_CFG_PREAMBLE_DEFAULT << MAC_CFG_PREAMBLE_SHIFT) & 4264193880Syongari MAC_CFG_PREAMBLE_MASK); 4265272730Syongari if ((sc->alc_flags & ALC_FLAG_AR816X_FAMILY) != 0 || 4266272730Syongari sc->alc_ident->deviceid == DEVICEID_ATHEROS_AR8151 || 4267211105Syongari sc->alc_ident->deviceid == DEVICEID_ATHEROS_AR8151_V2 || 4268211105Syongari sc->alc_ident->deviceid == DEVICEID_ATHEROS_AR8152_B2) 4269211105Syongari reg |= MAC_CFG_HASH_ALG_CRC32 | MAC_CFG_SPEED_MODE_SW; 4270193880Syongari if ((sc->alc_flags & ALC_FLAG_FASTETHER) != 0) 4271193880Syongari reg |= MAC_CFG_SPEED_10_100; 4272193880Syongari else 4273193880Syongari reg |= MAC_CFG_SPEED_1000; 4274193880Syongari CSR_WRITE_4(sc, ALC_MAC_CFG, reg); 4275193880Syongari 4276193880Syongari /* Set up the receive filter. */ 4277193880Syongari alc_rxfilter(sc); 4278193880Syongari alc_rxvlan(sc); 4279193880Syongari 4280193880Syongari /* Acknowledge all pending interrupts and clear it. */ 4281193880Syongari CSR_WRITE_4(sc, ALC_INTR_MASK, ALC_INTRS); 4282193880Syongari CSR_WRITE_4(sc, ALC_INTR_STATUS, 0xFFFFFFFF); 4283193880Syongari CSR_WRITE_4(sc, ALC_INTR_STATUS, 0); 4284193880Syongari 4285272730Syongari ifp->if_drv_flags |= IFF_DRV_RUNNING; 4286272730Syongari ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 4287272730Syongari 4288193880Syongari sc->alc_flags &= ~ALC_FLAG_LINK; 4289193880Syongari /* Switch to the current media. */ 4290272730Syongari alc_mediachange_locked(sc); 4291193880Syongari 4292193880Syongari callout_reset(&sc->alc_tick_ch, hz, alc_tick, sc); 4293193880Syongari} 4294193880Syongari 4295193880Syongaristatic void 4296193880Syongarialc_stop(struct alc_softc *sc) 4297193880Syongari{ 4298193880Syongari struct ifnet *ifp; 4299193880Syongari struct alc_txdesc *txd; 4300193880Syongari struct alc_rxdesc *rxd; 4301193880Syongari uint32_t reg; 4302193880Syongari int i; 4303193880Syongari 4304193880Syongari ALC_LOCK_ASSERT(sc); 4305193880Syongari /* 4306193880Syongari * Mark the interface down and cancel the watchdog timer. 4307193880Syongari */ 4308193880Syongari ifp = sc->alc_ifp; 4309193880Syongari ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE); 4310193880Syongari sc->alc_flags &= ~ALC_FLAG_LINK; 4311193880Syongari callout_stop(&sc->alc_tick_ch); 4312193880Syongari sc->alc_watchdog_timer = 0; 4313193880Syongari alc_stats_update(sc); 4314193880Syongari /* Disable interrupts. */ 4315193880Syongari CSR_WRITE_4(sc, ALC_INTR_MASK, 0); 4316193880Syongari CSR_WRITE_4(sc, ALC_INTR_STATUS, 0xFFFFFFFF); 4317193880Syongari /* Disable DMA. */ 4318193880Syongari reg = CSR_READ_4(sc, ALC_DMA_CFG); 4319193880Syongari reg &= ~(DMA_CFG_CMB_ENB | DMA_CFG_SMB_ENB); 4320193880Syongari reg |= DMA_CFG_SMB_DIS; 4321193880Syongari CSR_WRITE_4(sc, ALC_DMA_CFG, reg); 4322193880Syongari DELAY(1000); 4323193880Syongari /* Stop Rx/Tx MACs. */ 4324193880Syongari alc_stop_mac(sc); 4325193880Syongari /* Disable interrupts which might be touched in taskq handler. */ 4326193880Syongari CSR_WRITE_4(sc, ALC_INTR_STATUS, 0xFFFFFFFF); 4327272730Syongari /* Disable L0s/L1s */ 4328272730Syongari alc_aspm(sc, 0, IFM_UNKNOWN); 4329193880Syongari /* Reclaim Rx buffers that have been processed. */ 4330193880Syongari if (sc->alc_cdata.alc_rxhead != NULL) 4331193880Syongari m_freem(sc->alc_cdata.alc_rxhead); 4332193880Syongari ALC_RXCHAIN_RESET(sc); 4333193880Syongari /* 4334193880Syongari * Free Tx/Rx mbufs still in the queues. 4335193880Syongari */ 4336193880Syongari for (i = 0; i < ALC_RX_RING_CNT; i++) { 4337193880Syongari rxd = &sc->alc_cdata.alc_rxdesc[i]; 4338193880Syongari if (rxd->rx_m != NULL) { 4339193880Syongari bus_dmamap_sync(sc->alc_cdata.alc_rx_tag, 4340193880Syongari rxd->rx_dmamap, BUS_DMASYNC_POSTREAD); 4341193880Syongari bus_dmamap_unload(sc->alc_cdata.alc_rx_tag, 4342193880Syongari rxd->rx_dmamap); 4343193880Syongari m_freem(rxd->rx_m); 4344193880Syongari rxd->rx_m = NULL; 4345193880Syongari } 4346193880Syongari } 4347193880Syongari for (i = 0; i < ALC_TX_RING_CNT; i++) { 4348193880Syongari txd = &sc->alc_cdata.alc_txdesc[i]; 4349193880Syongari if (txd->tx_m != NULL) { 4350193880Syongari bus_dmamap_sync(sc->alc_cdata.alc_tx_tag, 4351193880Syongari txd->tx_dmamap, BUS_DMASYNC_POSTWRITE); 4352193880Syongari bus_dmamap_unload(sc->alc_cdata.alc_tx_tag, 4353193880Syongari txd->tx_dmamap); 4354193880Syongari m_freem(txd->tx_m); 4355193880Syongari txd->tx_m = NULL; 4356193880Syongari } 4357193880Syongari } 4358193880Syongari} 4359193880Syongari 4360193880Syongaristatic void 4361193880Syongarialc_stop_mac(struct alc_softc *sc) 4362193880Syongari{ 4363193880Syongari uint32_t reg; 4364193880Syongari int i; 4365193880Syongari 4366272730Syongari alc_stop_queue(sc); 4367193880Syongari /* Disable Rx/Tx MAC. */ 4368193880Syongari reg = CSR_READ_4(sc, ALC_MAC_CFG); 4369193880Syongari if ((reg & (MAC_CFG_TX_ENB | MAC_CFG_RX_ENB)) != 0) { 4370211285Syongari reg &= ~(MAC_CFG_TX_ENB | MAC_CFG_RX_ENB); 4371193880Syongari CSR_WRITE_4(sc, ALC_MAC_CFG, reg); 4372193880Syongari } 4373193880Syongari for (i = ALC_TIMEOUT; i > 0; i--) { 4374193880Syongari reg = CSR_READ_4(sc, ALC_IDLE_STATUS); 4375272730Syongari if ((reg & (IDLE_STATUS_RXMAC | IDLE_STATUS_TXMAC)) == 0) 4376193880Syongari break; 4377193880Syongari DELAY(10); 4378193880Syongari } 4379193880Syongari if (i == 0) 4380193880Syongari device_printf(sc->alc_dev, 4381193880Syongari "could not disable Rx/Tx MAC(0x%08x)!\n", reg); 4382193880Syongari} 4383193880Syongari 4384193880Syongaristatic void 4385193880Syongarialc_start_queue(struct alc_softc *sc) 4386193880Syongari{ 4387193880Syongari uint32_t qcfg[] = { 4388193880Syongari 0, 4389193880Syongari RXQ_CFG_QUEUE0_ENB, 4390193880Syongari RXQ_CFG_QUEUE0_ENB | RXQ_CFG_QUEUE1_ENB, 4391193880Syongari RXQ_CFG_QUEUE0_ENB | RXQ_CFG_QUEUE1_ENB | RXQ_CFG_QUEUE2_ENB, 4392193880Syongari RXQ_CFG_ENB 4393193880Syongari }; 4394193880Syongari uint32_t cfg; 4395193880Syongari 4396193880Syongari ALC_LOCK_ASSERT(sc); 4397193880Syongari 4398193880Syongari /* Enable RxQ. */ 4399193880Syongari cfg = CSR_READ_4(sc, ALC_RXQ_CFG); 4400272730Syongari if ((sc->alc_flags & ALC_FLAG_AR816X_FAMILY) == 0) { 4401272730Syongari cfg &= ~RXQ_CFG_ENB; 4402272730Syongari cfg |= qcfg[1]; 4403272730Syongari } else 4404272730Syongari cfg |= RXQ_CFG_QUEUE0_ENB; 4405193880Syongari CSR_WRITE_4(sc, ALC_RXQ_CFG, cfg); 4406193880Syongari /* Enable TxQ. */ 4407193880Syongari cfg = CSR_READ_4(sc, ALC_TXQ_CFG); 4408193880Syongari cfg |= TXQ_CFG_ENB; 4409193880Syongari CSR_WRITE_4(sc, ALC_TXQ_CFG, cfg); 4410193880Syongari} 4411193880Syongari 4412193880Syongaristatic void 4413193880Syongarialc_stop_queue(struct alc_softc *sc) 4414193880Syongari{ 4415193880Syongari uint32_t reg; 4416193880Syongari int i; 4417193880Syongari 4418193880Syongari /* Disable RxQ. */ 4419193880Syongari reg = CSR_READ_4(sc, ALC_RXQ_CFG); 4420272730Syongari if ((sc->alc_flags & ALC_FLAG_AR816X_FAMILY) == 0) { 4421272730Syongari if ((reg & RXQ_CFG_ENB) != 0) { 4422272730Syongari reg &= ~RXQ_CFG_ENB; 4423272730Syongari CSR_WRITE_4(sc, ALC_RXQ_CFG, reg); 4424272730Syongari } 4425272730Syongari } else { 4426272730Syongari if ((reg & RXQ_CFG_QUEUE0_ENB) != 0) { 4427272730Syongari reg &= ~RXQ_CFG_QUEUE0_ENB; 4428272730Syongari CSR_WRITE_4(sc, ALC_RXQ_CFG, reg); 4429272730Syongari } 4430193880Syongari } 4431193880Syongari /* Disable TxQ. */ 4432193880Syongari reg = CSR_READ_4(sc, ALC_TXQ_CFG); 4433218038Syongari if ((reg & TXQ_CFG_ENB) != 0) { 4434193880Syongari reg &= ~TXQ_CFG_ENB; 4435193880Syongari CSR_WRITE_4(sc, ALC_TXQ_CFG, reg); 4436193880Syongari } 4437272730Syongari DELAY(40); 4438193880Syongari for (i = ALC_TIMEOUT; i > 0; i--) { 4439193880Syongari reg = CSR_READ_4(sc, ALC_IDLE_STATUS); 4440193880Syongari if ((reg & (IDLE_STATUS_RXQ | IDLE_STATUS_TXQ)) == 0) 4441193880Syongari break; 4442193880Syongari DELAY(10); 4443193880Syongari } 4444193880Syongari if (i == 0) 4445193880Syongari device_printf(sc->alc_dev, 4446193880Syongari "could not disable RxQ/TxQ (0x%08x)!\n", reg); 4447193880Syongari} 4448193880Syongari 4449193880Syongaristatic void 4450193880Syongarialc_init_tx_ring(struct alc_softc *sc) 4451193880Syongari{ 4452193880Syongari struct alc_ring_data *rd; 4453193880Syongari struct alc_txdesc *txd; 4454193880Syongari int i; 4455193880Syongari 4456193880Syongari ALC_LOCK_ASSERT(sc); 4457193880Syongari 4458193880Syongari sc->alc_cdata.alc_tx_prod = 0; 4459193880Syongari sc->alc_cdata.alc_tx_cons = 0; 4460193880Syongari sc->alc_cdata.alc_tx_cnt = 0; 4461193880Syongari 4462193880Syongari rd = &sc->alc_rdata; 4463193880Syongari bzero(rd->alc_tx_ring, ALC_TX_RING_SZ); 4464193880Syongari for (i = 0; i < ALC_TX_RING_CNT; i++) { 4465193880Syongari txd = &sc->alc_cdata.alc_txdesc[i]; 4466193880Syongari txd->tx_m = NULL; 4467193880Syongari } 4468193880Syongari 4469193880Syongari bus_dmamap_sync(sc->alc_cdata.alc_tx_ring_tag, 4470193880Syongari sc->alc_cdata.alc_tx_ring_map, BUS_DMASYNC_PREWRITE); 4471193880Syongari} 4472193880Syongari 4473193880Syongaristatic int 4474193880Syongarialc_init_rx_ring(struct alc_softc *sc) 4475193880Syongari{ 4476193880Syongari struct alc_ring_data *rd; 4477193880Syongari struct alc_rxdesc *rxd; 4478193880Syongari int i; 4479193880Syongari 4480193880Syongari ALC_LOCK_ASSERT(sc); 4481193880Syongari 4482193880Syongari sc->alc_cdata.alc_rx_cons = ALC_RX_RING_CNT - 1; 4483193880Syongari sc->alc_morework = 0; 4484193880Syongari rd = &sc->alc_rdata; 4485193880Syongari bzero(rd->alc_rx_ring, ALC_RX_RING_SZ); 4486193880Syongari for (i = 0; i < ALC_RX_RING_CNT; i++) { 4487193880Syongari rxd = &sc->alc_cdata.alc_rxdesc[i]; 4488193880Syongari rxd->rx_m = NULL; 4489193880Syongari rxd->rx_desc = &rd->alc_rx_ring[i]; 4490193880Syongari if (alc_newbuf(sc, rxd) != 0) 4491193880Syongari return (ENOBUFS); 4492193880Syongari } 4493193880Syongari 4494193880Syongari /* 4495193880Syongari * Since controller does not update Rx descriptors, driver 4496193880Syongari * does have to read Rx descriptors back so BUS_DMASYNC_PREWRITE 4497193880Syongari * is enough to ensure coherence. 4498193880Syongari */ 4499193880Syongari bus_dmamap_sync(sc->alc_cdata.alc_rx_ring_tag, 4500193880Syongari sc->alc_cdata.alc_rx_ring_map, BUS_DMASYNC_PREWRITE); 4501193880Syongari /* Let controller know availability of new Rx buffers. */ 4502193880Syongari CSR_WRITE_4(sc, ALC_MBOX_RD0_PROD_IDX, sc->alc_cdata.alc_rx_cons); 4503193880Syongari 4504193880Syongari return (0); 4505193880Syongari} 4506193880Syongari 4507193880Syongaristatic void 4508193880Syongarialc_init_rr_ring(struct alc_softc *sc) 4509193880Syongari{ 4510193880Syongari struct alc_ring_data *rd; 4511193880Syongari 4512193880Syongari ALC_LOCK_ASSERT(sc); 4513193880Syongari 4514193880Syongari sc->alc_cdata.alc_rr_cons = 0; 4515193880Syongari ALC_RXCHAIN_RESET(sc); 4516193880Syongari 4517193880Syongari rd = &sc->alc_rdata; 4518193880Syongari bzero(rd->alc_rr_ring, ALC_RR_RING_SZ); 4519193880Syongari bus_dmamap_sync(sc->alc_cdata.alc_rr_ring_tag, 4520193880Syongari sc->alc_cdata.alc_rr_ring_map, 4521193880Syongari BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 4522193880Syongari} 4523193880Syongari 4524193880Syongaristatic void 4525193880Syongarialc_init_cmb(struct alc_softc *sc) 4526193880Syongari{ 4527193880Syongari struct alc_ring_data *rd; 4528193880Syongari 4529193880Syongari ALC_LOCK_ASSERT(sc); 4530193880Syongari 4531193880Syongari rd = &sc->alc_rdata; 4532193880Syongari bzero(rd->alc_cmb, ALC_CMB_SZ); 4533193880Syongari bus_dmamap_sync(sc->alc_cdata.alc_cmb_tag, sc->alc_cdata.alc_cmb_map, 4534193880Syongari BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 4535193880Syongari} 4536193880Syongari 4537193880Syongaristatic void 4538193880Syongarialc_init_smb(struct alc_softc *sc) 4539193880Syongari{ 4540193880Syongari struct alc_ring_data *rd; 4541193880Syongari 4542193880Syongari ALC_LOCK_ASSERT(sc); 4543193880Syongari 4544193880Syongari rd = &sc->alc_rdata; 4545193880Syongari bzero(rd->alc_smb, ALC_SMB_SZ); 4546193880Syongari bus_dmamap_sync(sc->alc_cdata.alc_smb_tag, sc->alc_cdata.alc_smb_map, 4547193880Syongari BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 4548193880Syongari} 4549193880Syongari 4550193880Syongaristatic void 4551193880Syongarialc_rxvlan(struct alc_softc *sc) 4552193880Syongari{ 4553193880Syongari struct ifnet *ifp; 4554193880Syongari uint32_t reg; 4555193880Syongari 4556193880Syongari ALC_LOCK_ASSERT(sc); 4557193880Syongari 4558193880Syongari ifp = sc->alc_ifp; 4559193880Syongari reg = CSR_READ_4(sc, ALC_MAC_CFG); 4560193880Syongari if ((ifp->if_capenable & IFCAP_VLAN_HWTAGGING) != 0) 4561193880Syongari reg |= MAC_CFG_VLAN_TAG_STRIP; 4562193880Syongari else 4563193880Syongari reg &= ~MAC_CFG_VLAN_TAG_STRIP; 4564193880Syongari CSR_WRITE_4(sc, ALC_MAC_CFG, reg); 4565193880Syongari} 4566193880Syongari 4567193880Syongaristatic void 4568193880Syongarialc_rxfilter(struct alc_softc *sc) 4569193880Syongari{ 4570193880Syongari struct ifnet *ifp; 4571193880Syongari struct ifmultiaddr *ifma; 4572193880Syongari uint32_t crc; 4573193880Syongari uint32_t mchash[2]; 4574193880Syongari uint32_t rxcfg; 4575193880Syongari 4576193880Syongari ALC_LOCK_ASSERT(sc); 4577193880Syongari 4578193880Syongari ifp = sc->alc_ifp; 4579193880Syongari 4580193880Syongari bzero(mchash, sizeof(mchash)); 4581193880Syongari rxcfg = CSR_READ_4(sc, ALC_MAC_CFG); 4582193880Syongari rxcfg &= ~(MAC_CFG_ALLMULTI | MAC_CFG_BCAST | MAC_CFG_PROMISC); 4583193880Syongari if ((ifp->if_flags & IFF_BROADCAST) != 0) 4584193880Syongari rxcfg |= MAC_CFG_BCAST; 4585193880Syongari if ((ifp->if_flags & (IFF_PROMISC | IFF_ALLMULTI)) != 0) { 4586193880Syongari if ((ifp->if_flags & IFF_PROMISC) != 0) 4587193880Syongari rxcfg |= MAC_CFG_PROMISC; 4588193880Syongari if ((ifp->if_flags & IFF_ALLMULTI) != 0) 4589193880Syongari rxcfg |= MAC_CFG_ALLMULTI; 4590193880Syongari mchash[0] = 0xFFFFFFFF; 4591193880Syongari mchash[1] = 0xFFFFFFFF; 4592193880Syongari goto chipit; 4593193880Syongari } 4594193880Syongari 4595195049Srwatson if_maddr_rlock(ifp); 4596193880Syongari TAILQ_FOREACH(ifma, &sc->alc_ifp->if_multiaddrs, ifma_link) { 4597193880Syongari if (ifma->ifma_addr->sa_family != AF_LINK) 4598193880Syongari continue; 4599197627Syongari crc = ether_crc32_be(LLADDR((struct sockaddr_dl *) 4600193880Syongari ifma->ifma_addr), ETHER_ADDR_LEN); 4601193880Syongari mchash[crc >> 31] |= 1 << ((crc >> 26) & 0x1f); 4602193880Syongari } 4603195049Srwatson if_maddr_runlock(ifp); 4604193880Syongari 4605193880Syongarichipit: 4606193880Syongari CSR_WRITE_4(sc, ALC_MAR0, mchash[0]); 4607193880Syongari CSR_WRITE_4(sc, ALC_MAR1, mchash[1]); 4608193880Syongari CSR_WRITE_4(sc, ALC_MAC_CFG, rxcfg); 4609193880Syongari} 4610193880Syongari 4611193880Syongaristatic int 4612193880Syongarisysctl_int_range(SYSCTL_HANDLER_ARGS, int low, int high) 4613193880Syongari{ 4614193880Syongari int error, value; 4615193880Syongari 4616193880Syongari if (arg1 == NULL) 4617193880Syongari return (EINVAL); 4618193880Syongari value = *(int *)arg1; 4619193880Syongari error = sysctl_handle_int(oidp, &value, 0, req); 4620193880Syongari if (error || req->newptr == NULL) 4621193880Syongari return (error); 4622193880Syongari if (value < low || value > high) 4623193880Syongari return (EINVAL); 4624193880Syongari *(int *)arg1 = value; 4625193880Syongari 4626193880Syongari return (0); 4627193880Syongari} 4628193880Syongari 4629193880Syongaristatic int 4630193880Syongarisysctl_hw_alc_proc_limit(SYSCTL_HANDLER_ARGS) 4631193880Syongari{ 4632193880Syongari return (sysctl_int_range(oidp, arg1, arg2, req, 4633193880Syongari ALC_PROC_MIN, ALC_PROC_MAX)); 4634193880Syongari} 4635193880Syongari 4636193880Syongaristatic int 4637193880Syongarisysctl_hw_alc_int_mod(SYSCTL_HANDLER_ARGS) 4638193880Syongari{ 4639193880Syongari 4640193880Syongari return (sysctl_int_range(oidp, arg1, arg2, req, 4641193880Syongari ALC_IM_TIMER_MIN, ALC_IM_TIMER_MAX)); 4642193880Syongari} 4643