if_alc.c revision 195049
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 28193880Syongari/* Driver for Atheros AR8131/AR8132 PCIe Ethernet. */ 29193880Syongari 30193880Syongari#include <sys/cdefs.h> 31193880Syongari__FBSDID("$FreeBSD: head/sys/dev/alc/if_alc.c 195049 2009-06-26 11:45:06Z rwatson $"); 32193880Syongari 33193880Syongari#include <sys/param.h> 34193880Syongari#include <sys/systm.h> 35193880Syongari#include <sys/bus.h> 36193880Syongari#include <sys/endian.h> 37193880Syongari#include <sys/kernel.h> 38193880Syongari#include <sys/lock.h> 39193880Syongari#include <sys/malloc.h> 40193880Syongari#include <sys/mbuf.h> 41193880Syongari#include <sys/module.h> 42193880Syongari#include <sys/mutex.h> 43193880Syongari#include <sys/rman.h> 44193880Syongari#include <sys/queue.h> 45193880Syongari#include <sys/socket.h> 46193880Syongari#include <sys/sockio.h> 47193880Syongari#include <sys/sysctl.h> 48193880Syongari#include <sys/taskqueue.h> 49193880Syongari 50193880Syongari#include <net/bpf.h> 51193880Syongari#include <net/if.h> 52193880Syongari#include <net/if_arp.h> 53193880Syongari#include <net/ethernet.h> 54193880Syongari#include <net/if_dl.h> 55193880Syongari#include <net/if_llc.h> 56193880Syongari#include <net/if_media.h> 57193880Syongari#include <net/if_types.h> 58193880Syongari#include <net/if_vlan_var.h> 59193880Syongari 60193880Syongari#include <netinet/in.h> 61193880Syongari#include <netinet/in_systm.h> 62193880Syongari#include <netinet/ip.h> 63193880Syongari#include <netinet/tcp.h> 64193880Syongari 65193880Syongari#include <dev/mii/mii.h> 66193880Syongari#include <dev/mii/miivar.h> 67193880Syongari 68193880Syongari#include <dev/pci/pcireg.h> 69193880Syongari#include <dev/pci/pcivar.h> 70193880Syongari 71193880Syongari#include <machine/atomic.h> 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#ifndef IFCAP_VLAN_HWTSO 88193880Syongari#define IFCAP_VLAN_HWTSO 0 89193880Syongari#endif 90193880Syongari 91193880SyongariMODULE_DEPEND(alc, pci, 1, 1, 1); 92193880SyongariMODULE_DEPEND(alc, ether, 1, 1, 1); 93193880SyongariMODULE_DEPEND(alc, miibus, 1, 1, 1); 94193880Syongari 95193880Syongari/* Tunables. */ 96193880Syongaristatic int msi_disable = 0; 97193880Syongaristatic int msix_disable = 0; 98193880SyongariTUNABLE_INT("hw.alc.msi_disable", &msi_disable); 99193880SyongariTUNABLE_INT("hw.alc.msix_disable", &msix_disable); 100193880Syongari 101193880Syongari/* 102193880Syongari * Devices supported by this driver. 103193880Syongari */ 104193880Syongaristatic struct alc_dev { 105193880Syongari uint16_t alc_vendorid; 106193880Syongari uint16_t alc_deviceid; 107193880Syongari const char *alc_name; 108193880Syongari} alc_devs[] = { 109193880Syongari { VENDORID_ATHEROS, DEVICEID_ATHEROS_AR8131, 110193880Syongari "Atheros AR8131 PCIe Gigabit Ethernet" }, 111193880Syongari { VENDORID_ATHEROS, DEVICEID_ATHEROS_AR8132, 112193880Syongari "Atheros AR8132 PCIe Fast Ethernet" } 113193880Syongari}; 114193880Syongari 115193880Syongaristatic void alc_aspm(struct alc_softc *); 116193880Syongaristatic int alc_attach(device_t); 117193880Syongaristatic int alc_check_boundary(struct alc_softc *); 118193880Syongaristatic int alc_detach(device_t); 119193880Syongaristatic void alc_disable_l0s_l1(struct alc_softc *); 120193880Syongaristatic int alc_dma_alloc(struct alc_softc *); 121193880Syongaristatic void alc_dma_free(struct alc_softc *); 122193880Syongaristatic void alc_dmamap_cb(void *, bus_dma_segment_t *, int, int); 123193880Syongaristatic int alc_encap(struct alc_softc *, struct mbuf **); 124193880Syongari#ifndef __NO_STRICT_ALIGNMENT 125193880Syongaristatic struct mbuf * 126193880Syongari alc_fixup_rx(struct ifnet *, struct mbuf *); 127193880Syongari#endif 128193880Syongaristatic void alc_get_macaddr(struct alc_softc *); 129193880Syongaristatic void alc_init(void *); 130193880Syongaristatic void alc_init_cmb(struct alc_softc *); 131193880Syongaristatic void alc_init_locked(struct alc_softc *); 132193880Syongaristatic void alc_init_rr_ring(struct alc_softc *); 133193880Syongaristatic int alc_init_rx_ring(struct alc_softc *); 134193880Syongaristatic void alc_init_smb(struct alc_softc *); 135193880Syongaristatic void alc_init_tx_ring(struct alc_softc *); 136193880Syongaristatic void alc_int_task(void *, int); 137193880Syongaristatic int alc_intr(void *); 138193880Syongaristatic int alc_ioctl(struct ifnet *, u_long, caddr_t); 139193880Syongaristatic void alc_mac_config(struct alc_softc *); 140193880Syongaristatic int alc_miibus_readreg(device_t, int, int); 141193880Syongaristatic void alc_miibus_statchg(device_t); 142193880Syongaristatic int alc_miibus_writereg(device_t, int, int, int); 143193880Syongaristatic int alc_mediachange(struct ifnet *); 144193880Syongaristatic void alc_mediastatus(struct ifnet *, struct ifmediareq *); 145193880Syongaristatic int alc_newbuf(struct alc_softc *, struct alc_rxdesc *); 146193880Syongaristatic void alc_phy_down(struct alc_softc *); 147193880Syongaristatic void alc_phy_reset(struct alc_softc *); 148193880Syongaristatic int alc_probe(device_t); 149193880Syongaristatic void alc_reset(struct alc_softc *); 150193880Syongaristatic int alc_resume(device_t); 151193880Syongaristatic void alc_rxeof(struct alc_softc *, struct rx_rdesc *); 152193880Syongaristatic int alc_rxintr(struct alc_softc *, int); 153193880Syongaristatic void alc_rxfilter(struct alc_softc *); 154193880Syongaristatic void alc_rxvlan(struct alc_softc *); 155193880Syongaristatic void alc_setlinkspeed(struct alc_softc *); 156193880Syongaristatic void alc_setwol(struct alc_softc *); 157193880Syongaristatic int alc_shutdown(device_t); 158193880Syongaristatic void alc_start(struct ifnet *); 159193880Syongaristatic void alc_start_queue(struct alc_softc *); 160193880Syongaristatic void alc_stats_clear(struct alc_softc *); 161193880Syongaristatic void alc_stats_update(struct alc_softc *); 162193880Syongaristatic void alc_stop(struct alc_softc *); 163193880Syongaristatic void alc_stop_mac(struct alc_softc *); 164193880Syongaristatic void alc_stop_queue(struct alc_softc *); 165193880Syongaristatic int alc_suspend(device_t); 166193880Syongaristatic void alc_sysctl_node(struct alc_softc *); 167193880Syongaristatic void alc_tick(void *); 168193880Syongaristatic void alc_tx_task(void *, int); 169193880Syongaristatic void alc_txeof(struct alc_softc *); 170193880Syongaristatic void alc_watchdog(struct alc_softc *); 171193880Syongaristatic int sysctl_int_range(SYSCTL_HANDLER_ARGS, int, int); 172193880Syongaristatic int sysctl_hw_alc_proc_limit(SYSCTL_HANDLER_ARGS); 173193880Syongaristatic int sysctl_hw_alc_int_mod(SYSCTL_HANDLER_ARGS); 174193880Syongari 175193880Syongaristatic device_method_t alc_methods[] = { 176193880Syongari /* Device interface. */ 177193880Syongari DEVMETHOD(device_probe, alc_probe), 178193880Syongari DEVMETHOD(device_attach, alc_attach), 179193880Syongari DEVMETHOD(device_detach, alc_detach), 180193880Syongari DEVMETHOD(device_shutdown, alc_shutdown), 181193880Syongari DEVMETHOD(device_suspend, alc_suspend), 182193880Syongari DEVMETHOD(device_resume, alc_resume), 183193880Syongari 184193880Syongari /* MII interface. */ 185193880Syongari DEVMETHOD(miibus_readreg, alc_miibus_readreg), 186193880Syongari DEVMETHOD(miibus_writereg, alc_miibus_writereg), 187193880Syongari DEVMETHOD(miibus_statchg, alc_miibus_statchg), 188193880Syongari 189193880Syongari { NULL, NULL } 190193880Syongari}; 191193880Syongari 192193880Syongaristatic driver_t alc_driver = { 193193880Syongari "alc", 194193880Syongari alc_methods, 195193880Syongari sizeof(struct alc_softc) 196193880Syongari}; 197193880Syongari 198193880Syongaristatic devclass_t alc_devclass; 199193880Syongari 200193880SyongariDRIVER_MODULE(alc, pci, alc_driver, alc_devclass, 0, 0); 201193880SyongariDRIVER_MODULE(miibus, alc, miibus_driver, miibus_devclass, 0, 0); 202193880Syongari 203193880Syongaristatic struct resource_spec alc_res_spec_mem[] = { 204193880Syongari { SYS_RES_MEMORY, PCIR_BAR(0), RF_ACTIVE }, 205193880Syongari { -1, 0, 0 } 206193880Syongari}; 207193880Syongari 208193880Syongaristatic struct resource_spec alc_irq_spec_legacy[] = { 209193880Syongari { SYS_RES_IRQ, 0, RF_ACTIVE | RF_SHAREABLE }, 210193880Syongari { -1, 0, 0 } 211193880Syongari}; 212193880Syongari 213193880Syongaristatic struct resource_spec alc_irq_spec_msi[] = { 214193880Syongari { SYS_RES_IRQ, 1, RF_ACTIVE }, 215193880Syongari { -1, 0, 0 } 216193880Syongari}; 217193880Syongari 218193880Syongaristatic struct resource_spec alc_irq_spec_msix[] = { 219193880Syongari { SYS_RES_IRQ, 1, RF_ACTIVE }, 220193880Syongari { -1, 0, 0 } 221193880Syongari}; 222193880Syongari 223193880Syongaristatic uint32_t alc_dma_burst[] = { 128, 256, 512, 1024, 2048, 4096, 0 }; 224193880Syongari 225193880Syongaristatic int 226193880Syongarialc_miibus_readreg(device_t dev, int phy, int reg) 227193880Syongari{ 228193880Syongari struct alc_softc *sc; 229193880Syongari uint32_t v; 230193880Syongari int i; 231193880Syongari 232193880Syongari sc = device_get_softc(dev); 233193880Syongari 234193880Syongari if (phy != sc->alc_phyaddr) 235193880Syongari return (0); 236193880Syongari 237193880Syongari CSR_WRITE_4(sc, ALC_MDIO, MDIO_OP_EXECUTE | MDIO_OP_READ | 238193880Syongari MDIO_SUP_PREAMBLE | MDIO_CLK_25_4 | MDIO_REG_ADDR(reg)); 239193880Syongari for (i = ALC_PHY_TIMEOUT; i > 0; i--) { 240193880Syongari DELAY(5); 241193880Syongari v = CSR_READ_4(sc, ALC_MDIO); 242193880Syongari if ((v & (MDIO_OP_EXECUTE | MDIO_OP_BUSY)) == 0) 243193880Syongari break; 244193880Syongari } 245193880Syongari 246193880Syongari if (i == 0) { 247193880Syongari device_printf(sc->alc_dev, "phy read timeout : %d\n", reg); 248193880Syongari return (0); 249193880Syongari } 250193880Syongari 251193880Syongari return ((v & MDIO_DATA_MASK) >> MDIO_DATA_SHIFT); 252193880Syongari} 253193880Syongari 254193880Syongaristatic int 255193880Syongarialc_miibus_writereg(device_t dev, int phy, int reg, int val) 256193880Syongari{ 257193880Syongari struct alc_softc *sc; 258193880Syongari uint32_t v; 259193880Syongari int i; 260193880Syongari 261193880Syongari sc = device_get_softc(dev); 262193880Syongari 263193880Syongari if (phy != sc->alc_phyaddr) 264193880Syongari return (0); 265193880Syongari 266193880Syongari CSR_WRITE_4(sc, ALC_MDIO, MDIO_OP_EXECUTE | MDIO_OP_WRITE | 267193880Syongari (val & MDIO_DATA_MASK) << MDIO_DATA_SHIFT | 268193880Syongari MDIO_SUP_PREAMBLE | MDIO_CLK_25_4 | MDIO_REG_ADDR(reg)); 269193880Syongari for (i = ALC_PHY_TIMEOUT; i > 0; i--) { 270193880Syongari DELAY(5); 271193880Syongari v = CSR_READ_4(sc, ALC_MDIO); 272193880Syongari if ((v & (MDIO_OP_EXECUTE | MDIO_OP_BUSY)) == 0) 273193880Syongari break; 274193880Syongari } 275193880Syongari 276193880Syongari if (i == 0) 277193880Syongari device_printf(sc->alc_dev, "phy write timeout : %d\n", reg); 278193880Syongari 279193880Syongari return (0); 280193880Syongari} 281193880Syongari 282193880Syongaristatic void 283193880Syongarialc_miibus_statchg(device_t dev) 284193880Syongari{ 285193880Syongari struct alc_softc *sc; 286193880Syongari struct mii_data *mii; 287193880Syongari struct ifnet *ifp; 288193880Syongari uint32_t reg; 289193880Syongari 290193880Syongari sc = device_get_softc(dev); 291193880Syongari 292193880Syongari mii = device_get_softc(sc->alc_miibus); 293193880Syongari ifp = sc->alc_ifp; 294193880Syongari if (mii == NULL || ifp == NULL || 295193880Syongari (ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) 296193880Syongari return; 297193880Syongari 298193880Syongari sc->alc_flags &= ~ALC_FLAG_LINK; 299193880Syongari if ((mii->mii_media_status & (IFM_ACTIVE | IFM_AVALID)) == 300193880Syongari (IFM_ACTIVE | IFM_AVALID)) { 301193880Syongari switch (IFM_SUBTYPE(mii->mii_media_active)) { 302193880Syongari case IFM_10_T: 303193880Syongari case IFM_100_TX: 304193880Syongari sc->alc_flags |= ALC_FLAG_LINK; 305193880Syongari break; 306193880Syongari case IFM_1000_T: 307193880Syongari if ((sc->alc_flags & ALC_FLAG_FASTETHER) == 0) 308193880Syongari sc->alc_flags |= ALC_FLAG_LINK; 309193880Syongari break; 310193880Syongari default: 311193880Syongari break; 312193880Syongari } 313193880Syongari } 314193880Syongari alc_stop_queue(sc); 315193880Syongari /* Stop Rx/Tx MACs. */ 316193880Syongari alc_stop_mac(sc); 317193880Syongari 318193880Syongari /* Program MACs with resolved speed/duplex/flow-control. */ 319193880Syongari if ((sc->alc_flags & ALC_FLAG_LINK) != 0) { 320193880Syongari alc_start_queue(sc); 321193880Syongari alc_mac_config(sc); 322193880Syongari /* Re-enable Tx/Rx MACs. */ 323193880Syongari reg = CSR_READ_4(sc, ALC_MAC_CFG); 324193880Syongari reg |= MAC_CFG_TX_ENB | MAC_CFG_RX_ENB; 325193880Syongari CSR_WRITE_4(sc, ALC_MAC_CFG, reg); 326193880Syongari } 327193880Syongari alc_aspm(sc); 328193880Syongari} 329193880Syongari 330193880Syongaristatic void 331193880Syongarialc_mediastatus(struct ifnet *ifp, struct ifmediareq *ifmr) 332193880Syongari{ 333193880Syongari struct alc_softc *sc; 334193880Syongari struct mii_data *mii; 335193880Syongari 336193880Syongari sc = ifp->if_softc; 337193880Syongari ALC_LOCK(sc); 338193880Syongari if ((ifp->if_flags & IFF_UP) == 0) { 339193880Syongari ALC_UNLOCK(sc); 340193880Syongari return; 341193880Syongari } 342193880Syongari mii = device_get_softc(sc->alc_miibus); 343193880Syongari 344193880Syongari mii_pollstat(mii); 345193880Syongari ALC_UNLOCK(sc); 346193880Syongari ifmr->ifm_status = mii->mii_media_status; 347193880Syongari ifmr->ifm_active = mii->mii_media_active; 348193880Syongari} 349193880Syongari 350193880Syongaristatic int 351193880Syongarialc_mediachange(struct ifnet *ifp) 352193880Syongari{ 353193880Syongari struct alc_softc *sc; 354193880Syongari struct mii_data *mii; 355193880Syongari struct mii_softc *miisc; 356193880Syongari int error; 357193880Syongari 358193880Syongari sc = ifp->if_softc; 359193880Syongari ALC_LOCK(sc); 360193880Syongari mii = device_get_softc(sc->alc_miibus); 361193880Syongari if (mii->mii_instance != 0) { 362193880Syongari LIST_FOREACH(miisc, &mii->mii_phys, mii_list) 363193880Syongari mii_phy_reset(miisc); 364193880Syongari } 365193880Syongari error = mii_mediachg(mii); 366193880Syongari ALC_UNLOCK(sc); 367193880Syongari 368193880Syongari return (error); 369193880Syongari} 370193880Syongari 371193880Syongaristatic int 372193880Syongarialc_probe(device_t dev) 373193880Syongari{ 374193880Syongari struct alc_dev *sp; 375193880Syongari int i; 376193880Syongari uint16_t vendor, devid; 377193880Syongari 378193880Syongari vendor = pci_get_vendor(dev); 379193880Syongari devid = pci_get_device(dev); 380193880Syongari sp = alc_devs; 381193880Syongari for (i = 0; i < sizeof(alc_devs) / sizeof(alc_devs[0]); i++) { 382193880Syongari if (vendor == sp->alc_vendorid && 383193880Syongari devid == sp->alc_deviceid) { 384193880Syongari device_set_desc(dev, sp->alc_name); 385193880Syongari return (BUS_PROBE_DEFAULT); 386193880Syongari } 387193880Syongari sp++; 388193880Syongari } 389193880Syongari 390193880Syongari return (ENXIO); 391193880Syongari} 392193880Syongari 393193880Syongaristatic void 394193880Syongarialc_get_macaddr(struct alc_softc *sc) 395193880Syongari{ 396193880Syongari uint32_t ea[2], opt; 397193880Syongari int i; 398193880Syongari 399193880Syongari opt = CSR_READ_4(sc, ALC_OPT_CFG); 400193880Syongari if ((CSR_READ_4(sc, ALC_TWSI_DEBUG) & TWSI_DEBUG_DEV_EXIST) != 0) { 401193880Syongari /* 402193880Syongari * EEPROM found, let TWSI reload EEPROM configuration. 403193880Syongari * This will set ethernet address of controller. 404193880Syongari */ 405193880Syongari if ((opt & OPT_CFG_CLK_ENB) == 0) { 406193880Syongari opt |= OPT_CFG_CLK_ENB; 407193880Syongari CSR_WRITE_4(sc, ALC_OPT_CFG, opt); 408193880Syongari CSR_READ_4(sc, ALC_OPT_CFG); 409193880Syongari DELAY(1000); 410193880Syongari } 411193880Syongari CSR_WRITE_4(sc, ALC_TWSI_CFG, CSR_READ_4(sc, ALC_TWSI_CFG) | 412193880Syongari TWSI_CFG_SW_LD_START); 413193880Syongari for (i = 100; i > 0; i--) { 414193880Syongari DELAY(1000); 415193880Syongari if ((CSR_READ_4(sc, ALC_TWSI_CFG) & 416193880Syongari TWSI_CFG_SW_LD_START) == 0) 417193880Syongari break; 418193880Syongari } 419193880Syongari if (i == 0) 420193880Syongari device_printf(sc->alc_dev, 421193880Syongari "reloading EEPROM timeout!\n"); 422193880Syongari } else { 423193880Syongari if (bootverbose) 424193880Syongari device_printf(sc->alc_dev, "EEPROM not found!\n"); 425193880Syongari } 426193880Syongari if ((opt & OPT_CFG_CLK_ENB) != 0) { 427193880Syongari opt &= ~OPT_CFG_CLK_ENB; 428193880Syongari CSR_WRITE_4(sc, ALC_OPT_CFG, opt); 429193880Syongari CSR_READ_4(sc, ALC_OPT_CFG); 430193880Syongari DELAY(1000); 431193880Syongari } 432193880Syongari 433193880Syongari ea[0] = CSR_READ_4(sc, ALC_PAR0); 434193880Syongari ea[1] = CSR_READ_4(sc, ALC_PAR1); 435193880Syongari sc->alc_eaddr[0] = (ea[1] >> 8) & 0xFF; 436193880Syongari sc->alc_eaddr[1] = (ea[1] >> 0) & 0xFF; 437193880Syongari sc->alc_eaddr[2] = (ea[0] >> 24) & 0xFF; 438193880Syongari sc->alc_eaddr[3] = (ea[0] >> 16) & 0xFF; 439193880Syongari sc->alc_eaddr[4] = (ea[0] >> 8) & 0xFF; 440193880Syongari sc->alc_eaddr[5] = (ea[0] >> 0) & 0xFF; 441193880Syongari} 442193880Syongari 443193880Syongaristatic void 444193880Syongarialc_disable_l0s_l1(struct alc_softc *sc) 445193880Syongari{ 446193880Syongari uint32_t pmcfg; 447193880Syongari 448193880Syongari /* Another magic from vendor. */ 449193880Syongari pmcfg = CSR_READ_4(sc, ALC_PM_CFG); 450193880Syongari pmcfg &= ~(PM_CFG_L1_ENTRY_TIMER_MASK | PM_CFG_CLK_SWH_L1 | 451193880Syongari PM_CFG_ASPM_L0S_ENB | PM_CFG_ASPM_L1_ENB | PM_CFG_MAC_ASPM_CHK | 452193880Syongari PM_CFG_SERDES_PD_EX_L1); 453193880Syongari pmcfg |= PM_CFG_SERDES_BUDS_RX_L1_ENB | PM_CFG_SERDES_PLL_L1_ENB | 454193880Syongari PM_CFG_SERDES_L1_ENB; 455193880Syongari CSR_WRITE_4(sc, ALC_PM_CFG, pmcfg); 456193880Syongari} 457193880Syongari 458193880Syongaristatic void 459193880Syongarialc_phy_reset(struct alc_softc *sc) 460193880Syongari{ 461193880Syongari uint16_t data; 462193880Syongari 463193880Syongari /* Reset magic from Linux. */ 464193880Syongari CSR_WRITE_2(sc, ALC_GPHY_CFG, 465193880Syongari GPHY_CFG_HIB_EN | GPHY_CFG_HIB_PULSE | GPHY_CFG_SEL_ANA_RESET); 466193880Syongari CSR_READ_2(sc, ALC_GPHY_CFG); 467193880Syongari DELAY(10 * 1000); 468193880Syongari 469193880Syongari CSR_WRITE_2(sc, ALC_GPHY_CFG, 470193880Syongari GPHY_CFG_EXT_RESET | GPHY_CFG_HIB_EN | GPHY_CFG_HIB_PULSE | 471193880Syongari GPHY_CFG_SEL_ANA_RESET); 472193880Syongari CSR_READ_2(sc, ALC_GPHY_CFG); 473193880Syongari DELAY(10 * 1000); 474193880Syongari 475193880Syongari /* Load DSP codes, vendor magic. */ 476193880Syongari data = ANA_LOOP_SEL_10BT | ANA_EN_MASK_TB | ANA_EN_10BT_IDLE | 477193880Syongari ((1 << ANA_INTERVAL_SEL_TIMER_SHIFT) & ANA_INTERVAL_SEL_TIMER_MASK); 478193880Syongari alc_miibus_writereg(sc->alc_dev, sc->alc_phyaddr, 479193880Syongari ALC_MII_DBG_ADDR, MII_ANA_CFG18); 480193880Syongari alc_miibus_writereg(sc->alc_dev, sc->alc_phyaddr, 481193880Syongari ALC_MII_DBG_DATA, data); 482193880Syongari 483193880Syongari data = ((2 << ANA_SERDES_CDR_BW_SHIFT) & ANA_SERDES_CDR_BW_MASK) | 484193880Syongari ANA_SERDES_EN_DEEM | ANA_SERDES_SEL_HSP | ANA_SERDES_EN_PLL | 485193880Syongari ANA_SERDES_EN_LCKDT; 486193880Syongari alc_miibus_writereg(sc->alc_dev, sc->alc_phyaddr, 487193880Syongari ALC_MII_DBG_ADDR, MII_ANA_CFG5); 488193880Syongari alc_miibus_writereg(sc->alc_dev, sc->alc_phyaddr, 489193880Syongari ALC_MII_DBG_DATA, data); 490193880Syongari 491193880Syongari data = ((44 << ANA_LONG_CABLE_TH_100_SHIFT) & 492193880Syongari ANA_LONG_CABLE_TH_100_MASK) | 493193880Syongari ((33 << ANA_SHORT_CABLE_TH_100_SHIFT) & 494193880Syongari ANA_SHORT_CABLE_TH_100_SHIFT) | 495193880Syongari ANA_BP_BAD_LINK_ACCUM | ANA_BP_SMALL_BW; 496193880Syongari alc_miibus_writereg(sc->alc_dev, sc->alc_phyaddr, 497193880Syongari ALC_MII_DBG_ADDR, MII_ANA_CFG54); 498193880Syongari alc_miibus_writereg(sc->alc_dev, sc->alc_phyaddr, 499193880Syongari ALC_MII_DBG_DATA, data); 500193880Syongari 501193880Syongari data = ((11 << ANA_IECHO_ADJ_3_SHIFT) & ANA_IECHO_ADJ_3_MASK) | 502193880Syongari ((11 << ANA_IECHO_ADJ_2_SHIFT) & ANA_IECHO_ADJ_2_MASK) | 503193880Syongari ((8 << ANA_IECHO_ADJ_1_SHIFT) & ANA_IECHO_ADJ_1_MASK) | 504193880Syongari ((8 << ANA_IECHO_ADJ_0_SHIFT) & ANA_IECHO_ADJ_0_MASK); 505193880Syongari alc_miibus_writereg(sc->alc_dev, sc->alc_phyaddr, 506193880Syongari ALC_MII_DBG_ADDR, MII_ANA_CFG4); 507193880Syongari alc_miibus_writereg(sc->alc_dev, sc->alc_phyaddr, 508193880Syongari ALC_MII_DBG_DATA, data); 509193880Syongari 510193880Syongari data = ((7 & ANA_MANUL_SWICH_ON_SHIFT) & ANA_MANUL_SWICH_ON_MASK) | 511193880Syongari ANA_RESTART_CAL | ANA_MAN_ENABLE | ANA_SEL_HSP | ANA_EN_HB | 512193880Syongari ANA_OEN_125M; 513193880Syongari alc_miibus_writereg(sc->alc_dev, sc->alc_phyaddr, 514193880Syongari ALC_MII_DBG_ADDR, MII_ANA_CFG0); 515193880Syongari alc_miibus_writereg(sc->alc_dev, sc->alc_phyaddr, 516193880Syongari ALC_MII_DBG_DATA, data); 517193880Syongari DELAY(1000); 518193880Syongari} 519193880Syongari 520193880Syongaristatic void 521193880Syongarialc_phy_down(struct alc_softc *sc) 522193880Syongari{ 523193880Syongari 524193880Syongari /* Force PHY down. */ 525193880Syongari CSR_WRITE_2(sc, ALC_GPHY_CFG, 526193880Syongari GPHY_CFG_EXT_RESET | GPHY_CFG_HIB_EN | GPHY_CFG_HIB_PULSE | 527193880Syongari GPHY_CFG_SEL_ANA_RESET | GPHY_CFG_PHY_IDDQ | GPHY_CFG_PWDOWN_HW); 528193880Syongari DELAY(1000); 529193880Syongari} 530193880Syongari 531193880Syongaristatic void 532193880Syongarialc_aspm(struct alc_softc *sc) 533193880Syongari{ 534193880Syongari uint32_t pmcfg; 535193880Syongari 536193880Syongari ALC_LOCK_ASSERT(sc); 537193880Syongari 538193880Syongari pmcfg = CSR_READ_4(sc, ALC_PM_CFG); 539193880Syongari pmcfg &= ~PM_CFG_SERDES_PD_EX_L1; 540193880Syongari pmcfg |= PM_CFG_SERDES_BUDS_RX_L1_ENB; 541193880Syongari pmcfg |= PM_CFG_SERDES_L1_ENB; 542193880Syongari pmcfg &= ~PM_CFG_L1_ENTRY_TIMER_MASK; 543193880Syongari pmcfg |= PM_CFG_MAC_ASPM_CHK; 544193880Syongari if ((sc->alc_flags & ALC_FLAG_LINK) != 0) { 545193880Syongari pmcfg |= PM_CFG_SERDES_PLL_L1_ENB; 546193880Syongari pmcfg &= ~PM_CFG_CLK_SWH_L1; 547193880Syongari pmcfg &= ~PM_CFG_ASPM_L1_ENB; 548193880Syongari pmcfg &= ~PM_CFG_ASPM_L0S_ENB; 549193880Syongari } else { 550193880Syongari pmcfg &= ~PM_CFG_SERDES_PLL_L1_ENB; 551193880Syongari pmcfg |= PM_CFG_CLK_SWH_L1; 552193880Syongari pmcfg &= ~PM_CFG_ASPM_L1_ENB; 553193880Syongari pmcfg &= ~PM_CFG_ASPM_L0S_ENB; 554193880Syongari } 555193880Syongari CSR_WRITE_4(sc, ALC_PM_CFG, pmcfg); 556193880Syongari} 557193880Syongari 558193880Syongaristatic int 559193880Syongarialc_attach(device_t dev) 560193880Syongari{ 561193880Syongari struct alc_softc *sc; 562193880Syongari struct ifnet *ifp; 563193880Syongari char *aspm_state[] = { "L0s/L1", "L0s", "L1", "L0s/l1" }; 564193880Syongari uint16_t burst; 565193880Syongari int base, error, i, msic, msixc, pmc, state; 566193880Syongari uint32_t cap, ctl, val; 567193880Syongari 568193880Syongari error = 0; 569193880Syongari sc = device_get_softc(dev); 570193880Syongari sc->alc_dev = dev; 571193880Syongari 572193880Syongari mtx_init(&sc->alc_mtx, device_get_nameunit(dev), MTX_NETWORK_LOCK, 573193880Syongari MTX_DEF); 574193880Syongari callout_init_mtx(&sc->alc_tick_ch, &sc->alc_mtx, 0); 575193880Syongari TASK_INIT(&sc->alc_int_task, 0, alc_int_task, sc); 576193880Syongari 577193880Syongari /* Map the device. */ 578193880Syongari pci_enable_busmaster(dev); 579193880Syongari sc->alc_res_spec = alc_res_spec_mem; 580193880Syongari sc->alc_irq_spec = alc_irq_spec_legacy; 581193880Syongari error = bus_alloc_resources(dev, sc->alc_res_spec, sc->alc_res); 582193880Syongari if (error != 0) { 583193880Syongari device_printf(dev, "cannot allocate memory resources.\n"); 584193880Syongari goto fail; 585193880Syongari } 586193880Syongari 587193880Syongari /* Set PHY address. */ 588193880Syongari sc->alc_phyaddr = ALC_PHY_ADDR; 589193880Syongari 590193880Syongari /* Initialize DMA parameters. */ 591193880Syongari sc->alc_dma_rd_burst = 0; 592193880Syongari sc->alc_dma_wr_burst = 0; 593193880Syongari sc->alc_rcb = DMA_CFG_RCB_64; 594193880Syongari if (pci_find_extcap(dev, PCIY_EXPRESS, &base) == 0) { 595193880Syongari sc->alc_flags |= ALC_FLAG_PCIE; 596193880Syongari burst = CSR_READ_2(sc, base + PCIR_EXPRESS_DEVICE_CTL); 597193880Syongari sc->alc_dma_rd_burst = 598193880Syongari (burst & PCIM_EXP_CTL_MAX_READ_REQUEST) >> 12; 599193880Syongari sc->alc_dma_wr_burst = (burst & PCIM_EXP_CTL_MAX_PAYLOAD) >> 5; 600193880Syongari if (bootverbose) { 601193880Syongari device_printf(dev, "Read request size : %u bytes.\n", 602193880Syongari alc_dma_burst[sc->alc_dma_rd_burst]); 603193880Syongari device_printf(dev, "TLP payload size : %u bytes.\n", 604193880Syongari alc_dma_burst[sc->alc_dma_wr_burst]); 605193880Syongari } 606193880Syongari /* Clear data link and flow-control protocol error. */ 607193880Syongari val = CSR_READ_4(sc, ALC_PEX_UNC_ERR_SEV); 608193880Syongari val &= ~(PEX_UNC_ERR_SEV_DLP | PEX_UNC_ERR_SEV_FCP); 609193880Syongari CSR_WRITE_4(sc, ALC_PEX_UNC_ERR_SEV, val); 610193880Syongari /* Disable ASPM L0S and L1. */ 611193880Syongari cap = CSR_READ_2(sc, base + PCIR_EXPRESS_LINK_CAP); 612193880Syongari if ((cap & PCIM_LINK_CAP_ASPM) != 0) { 613193880Syongari ctl = CSR_READ_2(sc, base + PCIR_EXPRESS_LINK_CTL); 614193880Syongari if ((ctl & 0x08) != 0) 615193880Syongari sc->alc_rcb = DMA_CFG_RCB_128; 616193880Syongari if (bootverbose) 617193880Syongari device_printf(dev, "RCB %u bytes\n", 618193880Syongari sc->alc_rcb == DMA_CFG_RCB_64 ? 64 : 128); 619193880Syongari state = ctl & 0x03; 620193880Syongari if (bootverbose) 621193880Syongari device_printf(sc->alc_dev, "ASPM %s %s\n", 622193880Syongari aspm_state[state], 623193880Syongari state == 0 ? "disabled" : "enabled"); 624193880Syongari if (state != 0) 625193880Syongari alc_disable_l0s_l1(sc); 626193880Syongari } 627193880Syongari } 628193880Syongari 629193880Syongari /* Reset PHY. */ 630193880Syongari alc_phy_reset(sc); 631193880Syongari 632193880Syongari /* Reset the ethernet controller. */ 633193880Syongari alc_reset(sc); 634193880Syongari 635193880Syongari /* 636193880Syongari * One odd thing is AR8132 uses the same PHY hardware(F1 637193880Syongari * gigabit PHY) of AR8131. So atphy(4) of AR8132 reports 638193880Syongari * the PHY supports 1000Mbps but that's not true. The PHY 639193880Syongari * used in AR8132 can't establish gigabit link even if it 640193880Syongari * shows the same PHY model/revision number of AR8131. 641193880Syongari */ 642193880Syongari if (pci_get_device(dev) == DEVICEID_ATHEROS_AR8132) 643193880Syongari sc->alc_flags |= ALC_FLAG_FASTETHER | ALC_FLAG_JUMBO; 644193880Syongari else 645193880Syongari sc->alc_flags |= ALC_FLAG_JUMBO | ALC_FLAG_ASPM_MON; 646193880Syongari /* 647193880Syongari * It seems that AR8131/AR8132 has silicon bug for SMB. In 648193880Syongari * addition, Atheros said that enabling SMB wouldn't improve 649193880Syongari * performance. However I think it's bad to access lots of 650193880Syongari * registers to extract MAC statistics. 651193880Syongari */ 652193880Syongari sc->alc_flags |= ALC_FLAG_SMB_BUG; 653193880Syongari /* 654193880Syongari * Don't use Tx CMB. It is known to have silicon bug. 655193880Syongari */ 656193880Syongari sc->alc_flags |= ALC_FLAG_CMB_BUG; 657193880Syongari sc->alc_rev = pci_get_revid(dev); 658193880Syongari sc->alc_chip_rev = CSR_READ_4(sc, ALC_MASTER_CFG) >> 659193880Syongari MASTER_CHIP_REV_SHIFT; 660193880Syongari if (bootverbose) { 661193880Syongari device_printf(dev, "PCI device revision : 0x%04x\n", 662193880Syongari sc->alc_rev); 663193880Syongari device_printf(dev, "Chip id/revision : 0x%04x\n", 664193880Syongari sc->alc_chip_rev); 665193880Syongari } 666193880Syongari device_printf(dev, "%u Tx FIFO, %u Rx FIFO\n", 667193880Syongari CSR_READ_4(sc, ALC_SRAM_TX_FIFO_LEN) * 8, 668193880Syongari CSR_READ_4(sc, ALC_SRAM_RX_FIFO_LEN) * 8); 669193880Syongari 670193880Syongari /* Allocate IRQ resources. */ 671193880Syongari msixc = pci_msix_count(dev); 672193880Syongari msic = pci_msi_count(dev); 673193880Syongari if (bootverbose) { 674193880Syongari device_printf(dev, "MSIX count : %d\n", msixc); 675193880Syongari device_printf(dev, "MSI count : %d\n", msic); 676193880Syongari } 677193880Syongari /* Prefer MSIX over MSI. */ 678193880Syongari if (msix_disable == 0 || msi_disable == 0) { 679193880Syongari if (msix_disable == 0 && msixc == ALC_MSIX_MESSAGES && 680193880Syongari pci_alloc_msix(dev, &msixc) == 0) { 681193880Syongari if (msic == ALC_MSIX_MESSAGES) { 682193880Syongari device_printf(dev, 683193880Syongari "Using %d MSIX message(s).\n", msixc); 684193880Syongari sc->alc_flags |= ALC_FLAG_MSIX; 685193880Syongari sc->alc_irq_spec = alc_irq_spec_msix; 686193880Syongari } else 687193880Syongari pci_release_msi(dev); 688193880Syongari } 689193880Syongari if (msi_disable == 0 && (sc->alc_flags & ALC_FLAG_MSIX) == 0 && 690193880Syongari msic == ALC_MSI_MESSAGES && 691193880Syongari pci_alloc_msi(dev, &msic) == 0) { 692193880Syongari if (msic == ALC_MSI_MESSAGES) { 693193880Syongari device_printf(dev, 694193880Syongari "Using %d MSI message(s).\n", msic); 695193880Syongari sc->alc_flags |= ALC_FLAG_MSI; 696193880Syongari sc->alc_irq_spec = alc_irq_spec_msi; 697193880Syongari } else 698193880Syongari pci_release_msi(dev); 699193880Syongari } 700193880Syongari } 701193880Syongari 702193880Syongari error = bus_alloc_resources(dev, sc->alc_irq_spec, sc->alc_irq); 703193880Syongari if (error != 0) { 704193880Syongari device_printf(dev, "cannot allocate IRQ resources.\n"); 705193880Syongari goto fail; 706193880Syongari } 707193880Syongari 708193880Syongari /* Create device sysctl node. */ 709193880Syongari alc_sysctl_node(sc); 710193880Syongari 711193880Syongari if ((error = alc_dma_alloc(sc) != 0)) 712193880Syongari goto fail; 713193880Syongari 714193880Syongari /* Load station address. */ 715193880Syongari alc_get_macaddr(sc); 716193880Syongari 717193880Syongari ifp = sc->alc_ifp = if_alloc(IFT_ETHER); 718193880Syongari if (ifp == NULL) { 719193880Syongari device_printf(dev, "cannot allocate ifnet structure.\n"); 720193880Syongari error = ENXIO; 721193880Syongari goto fail; 722193880Syongari } 723193880Syongari 724193880Syongari ifp->if_softc = sc; 725193880Syongari if_initname(ifp, device_get_name(dev), device_get_unit(dev)); 726193880Syongari ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 727193880Syongari ifp->if_ioctl = alc_ioctl; 728193880Syongari ifp->if_start = alc_start; 729193880Syongari ifp->if_init = alc_init; 730193880Syongari ifp->if_snd.ifq_drv_maxlen = ALC_TX_RING_CNT - 1; 731193880Syongari IFQ_SET_MAXLEN(&ifp->if_snd, ifp->if_snd.ifq_drv_maxlen); 732193880Syongari IFQ_SET_READY(&ifp->if_snd); 733193880Syongari ifp->if_capabilities = IFCAP_TXCSUM | IFCAP_TSO4; 734193880Syongari ifp->if_hwassist = ALC_CSUM_FEATURES | CSUM_TSO; 735193880Syongari if (pci_find_extcap(dev, PCIY_PMG, &pmc) == 0) 736193880Syongari ifp->if_capabilities |= IFCAP_WOL_MAGIC | IFCAP_WOL_MCAST; 737193880Syongari ifp->if_capenable = ifp->if_capabilities; 738193880Syongari 739193880Syongari /* Set up MII bus. */ 740193880Syongari if ((error = mii_phy_probe(dev, &sc->alc_miibus, alc_mediachange, 741193880Syongari alc_mediastatus)) != 0) { 742193880Syongari device_printf(dev, "no PHY found!\n"); 743193880Syongari goto fail; 744193880Syongari } 745193880Syongari 746193880Syongari ether_ifattach(ifp, sc->alc_eaddr); 747193880Syongari 748193880Syongari /* VLAN capability setup. */ 749193880Syongari ifp->if_capabilities |= IFCAP_VLAN_MTU; 750193880Syongari ifp->if_capabilities |= IFCAP_VLAN_HWTAGGING | IFCAP_VLAN_HWCSUM; 751193880Syongari ifp->if_capenable = ifp->if_capabilities; 752193880Syongari /* 753193880Syongari * XXX 754193880Syongari * It seems enabling Tx checksum offloading makes more trouble. 755193880Syongari * Sometimes the controller does not receive any frames when 756193880Syongari * Tx checksum offloading is enabled. I'm not sure whether this 757193880Syongari * is a bug in Tx checksum offloading logic or I got broken 758193880Syongari * sample boards. To safety, don't enable Tx checksum offloading 759193880Syongari * by default but give chance to users to toggle it if they know 760193880Syongari * their controllers work without problems. 761193880Syongari */ 762193880Syongari ifp->if_capenable &= ~IFCAP_TXCSUM; 763193880Syongari ifp->if_hwassist &= ~ALC_CSUM_FEATURES; 764193880Syongari 765193880Syongari /* Tell the upper layer(s) we support long frames. */ 766193880Syongari ifp->if_data.ifi_hdrlen = sizeof(struct ether_vlan_header); 767193880Syongari 768193880Syongari /* Create local taskq. */ 769193880Syongari TASK_INIT(&sc->alc_tx_task, 1, alc_tx_task, ifp); 770193880Syongari sc->alc_tq = taskqueue_create_fast("alc_taskq", M_WAITOK, 771193880Syongari taskqueue_thread_enqueue, &sc->alc_tq); 772193880Syongari if (sc->alc_tq == NULL) { 773193880Syongari device_printf(dev, "could not create taskqueue.\n"); 774193880Syongari ether_ifdetach(ifp); 775193880Syongari error = ENXIO; 776193880Syongari goto fail; 777193880Syongari } 778193880Syongari taskqueue_start_threads(&sc->alc_tq, 1, PI_NET, "%s taskq", 779193880Syongari device_get_nameunit(sc->alc_dev)); 780193880Syongari 781193880Syongari if ((sc->alc_flags & ALC_FLAG_MSIX) != 0) 782193880Syongari msic = ALC_MSIX_MESSAGES; 783193880Syongari else if ((sc->alc_flags & ALC_FLAG_MSI) != 0) 784193880Syongari msic = ALC_MSI_MESSAGES; 785193880Syongari else 786193880Syongari msic = 1; 787193880Syongari for (i = 0; i < msic; i++) { 788193880Syongari error = bus_setup_intr(dev, sc->alc_irq[i], 789193880Syongari INTR_TYPE_NET | INTR_MPSAFE, alc_intr, NULL, sc, 790193880Syongari &sc->alc_intrhand[i]); 791193880Syongari if (error != 0) 792193880Syongari break; 793193880Syongari } 794193880Syongari if (error != 0) { 795193880Syongari device_printf(dev, "could not set up interrupt handler.\n"); 796193880Syongari taskqueue_free(sc->alc_tq); 797193880Syongari sc->alc_tq = NULL; 798193880Syongari ether_ifdetach(ifp); 799193880Syongari goto fail; 800193880Syongari } 801193880Syongari 802193880Syongarifail: 803193880Syongari if (error != 0) 804193880Syongari alc_detach(dev); 805193880Syongari 806193880Syongari return (error); 807193880Syongari} 808193880Syongari 809193880Syongaristatic int 810193880Syongarialc_detach(device_t dev) 811193880Syongari{ 812193880Syongari struct alc_softc *sc; 813193880Syongari struct ifnet *ifp; 814193880Syongari int i, msic; 815193880Syongari 816193880Syongari sc = device_get_softc(dev); 817193880Syongari 818193880Syongari ifp = sc->alc_ifp; 819193880Syongari if (device_is_attached(dev)) { 820193880Syongari ALC_LOCK(sc); 821193880Syongari sc->alc_flags |= ALC_FLAG_DETACH; 822193880Syongari alc_stop(sc); 823193880Syongari ALC_UNLOCK(sc); 824193880Syongari callout_drain(&sc->alc_tick_ch); 825193880Syongari taskqueue_drain(sc->alc_tq, &sc->alc_int_task); 826193880Syongari taskqueue_drain(sc->alc_tq, &sc->alc_tx_task); 827193880Syongari ether_ifdetach(ifp); 828193880Syongari } 829193880Syongari 830193880Syongari if (sc->alc_tq != NULL) { 831193880Syongari taskqueue_drain(sc->alc_tq, &sc->alc_int_task); 832193880Syongari taskqueue_free(sc->alc_tq); 833193880Syongari sc->alc_tq = NULL; 834193880Syongari } 835193880Syongari 836193880Syongari if (sc->alc_miibus != NULL) { 837193880Syongari device_delete_child(dev, sc->alc_miibus); 838193880Syongari sc->alc_miibus = NULL; 839193880Syongari } 840193880Syongari bus_generic_detach(dev); 841193880Syongari alc_dma_free(sc); 842193880Syongari 843193880Syongari if (ifp != NULL) { 844193880Syongari if_free(ifp); 845193880Syongari sc->alc_ifp = NULL; 846193880Syongari } 847193880Syongari 848193880Syongari if ((sc->alc_flags & ALC_FLAG_MSIX) != 0) 849193880Syongari msic = ALC_MSIX_MESSAGES; 850193880Syongari else if ((sc->alc_flags & ALC_FLAG_MSI) != 0) 851193880Syongari msic = ALC_MSI_MESSAGES; 852193880Syongari else 853193880Syongari msic = 1; 854193880Syongari for (i = 0; i < msic; i++) { 855193880Syongari if (sc->alc_intrhand[i] != NULL) { 856193880Syongari bus_teardown_intr(dev, sc->alc_irq[i], 857193880Syongari sc->alc_intrhand[i]); 858193880Syongari sc->alc_intrhand[i] = NULL; 859193880Syongari } 860193880Syongari } 861193880Syongari alc_phy_down(sc); 862193880Syongari bus_release_resources(dev, sc->alc_irq_spec, sc->alc_irq); 863193880Syongari if ((sc->alc_flags & (ALC_FLAG_MSI | ALC_FLAG_MSIX)) != 0) 864193880Syongari pci_release_msi(dev); 865193880Syongari bus_release_resources(dev, sc->alc_res_spec, sc->alc_res); 866193880Syongari mtx_destroy(&sc->alc_mtx); 867193880Syongari 868193880Syongari return (0); 869193880Syongari} 870193880Syongari 871193880Syongari#define ALC_SYSCTL_STAT_ADD32(c, h, n, p, d) \ 872193880Syongari SYSCTL_ADD_UINT(c, h, OID_AUTO, n, CTLFLAG_RD, p, 0, d) 873193880Syongari#define ALC_SYSCTL_STAT_ADD64(c, h, n, p, d) \ 874193880Syongari SYSCTL_ADD_QUAD(c, h, OID_AUTO, n, CTLFLAG_RD, p, d) 875193880Syongari 876193880Syongaristatic void 877193880Syongarialc_sysctl_node(struct alc_softc *sc) 878193880Syongari{ 879193880Syongari struct sysctl_ctx_list *ctx; 880193880Syongari struct sysctl_oid_list *child, *parent; 881193880Syongari struct sysctl_oid *tree; 882193880Syongari struct alc_hw_stats *stats; 883193880Syongari int error; 884193880Syongari 885193880Syongari stats = &sc->alc_stats; 886193880Syongari ctx = device_get_sysctl_ctx(sc->alc_dev); 887193880Syongari child = SYSCTL_CHILDREN(device_get_sysctl_tree(sc->alc_dev)); 888193880Syongari 889193880Syongari SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "int_rx_mod", 890193880Syongari CTLTYPE_INT | CTLFLAG_RW, &sc->alc_int_rx_mod, 0, 891193880Syongari sysctl_hw_alc_int_mod, "I", "alc Rx interrupt moderation"); 892193880Syongari SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "int_tx_mod", 893193880Syongari CTLTYPE_INT | CTLFLAG_RW, &sc->alc_int_tx_mod, 0, 894193880Syongari sysctl_hw_alc_int_mod, "I", "alc Tx interrupt moderation"); 895193880Syongari /* Pull in device tunables. */ 896193880Syongari sc->alc_int_rx_mod = ALC_IM_RX_TIMER_DEFAULT; 897193880Syongari error = resource_int_value(device_get_name(sc->alc_dev), 898193880Syongari device_get_unit(sc->alc_dev), "int_rx_mod", &sc->alc_int_rx_mod); 899193880Syongari if (error == 0) { 900193880Syongari if (sc->alc_int_rx_mod < ALC_IM_TIMER_MIN || 901193880Syongari sc->alc_int_rx_mod > ALC_IM_TIMER_MAX) { 902193880Syongari device_printf(sc->alc_dev, "int_rx_mod value out of " 903193880Syongari "range; using default: %d\n", 904193880Syongari ALC_IM_RX_TIMER_DEFAULT); 905193880Syongari sc->alc_int_rx_mod = ALC_IM_RX_TIMER_DEFAULT; 906193880Syongari } 907193880Syongari } 908193880Syongari sc->alc_int_tx_mod = ALC_IM_TX_TIMER_DEFAULT; 909193880Syongari error = resource_int_value(device_get_name(sc->alc_dev), 910193880Syongari device_get_unit(sc->alc_dev), "int_tx_mod", &sc->alc_int_tx_mod); 911193880Syongari if (error == 0) { 912193880Syongari if (sc->alc_int_tx_mod < ALC_IM_TIMER_MIN || 913193880Syongari sc->alc_int_tx_mod > ALC_IM_TIMER_MAX) { 914193880Syongari device_printf(sc->alc_dev, "int_tx_mod value out of " 915193880Syongari "range; using default: %d\n", 916193880Syongari ALC_IM_TX_TIMER_DEFAULT); 917193880Syongari sc->alc_int_tx_mod = ALC_IM_TX_TIMER_DEFAULT; 918193880Syongari } 919193880Syongari } 920193880Syongari SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "process_limit", 921193880Syongari CTLTYPE_INT | CTLFLAG_RW, &sc->alc_process_limit, 0, 922193880Syongari sysctl_hw_alc_proc_limit, "I", 923193880Syongari "max number of Rx events to process"); 924193880Syongari /* Pull in device tunables. */ 925193880Syongari sc->alc_process_limit = ALC_PROC_DEFAULT; 926193880Syongari error = resource_int_value(device_get_name(sc->alc_dev), 927193880Syongari device_get_unit(sc->alc_dev), "process_limit", 928193880Syongari &sc->alc_process_limit); 929193880Syongari if (error == 0) { 930193880Syongari if (sc->alc_process_limit < ALC_PROC_MIN || 931193880Syongari sc->alc_process_limit > ALC_PROC_MAX) { 932193880Syongari device_printf(sc->alc_dev, 933193880Syongari "process_limit value out of range; " 934193880Syongari "using default: %d\n", ALC_PROC_DEFAULT); 935193880Syongari sc->alc_process_limit = ALC_PROC_DEFAULT; 936193880Syongari } 937193880Syongari } 938193880Syongari 939193880Syongari tree = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, "stats", CTLFLAG_RD, 940193880Syongari NULL, "ALC statistics"); 941193880Syongari parent = SYSCTL_CHILDREN(tree); 942193880Syongari 943193880Syongari /* Rx statistics. */ 944193880Syongari tree = SYSCTL_ADD_NODE(ctx, parent, OID_AUTO, "rx", CTLFLAG_RD, 945193880Syongari NULL, "Rx MAC statistics"); 946193880Syongari child = SYSCTL_CHILDREN(tree); 947193880Syongari ALC_SYSCTL_STAT_ADD32(ctx, child, "good_frames", 948193880Syongari &stats->rx_frames, "Good frames"); 949193880Syongari ALC_SYSCTL_STAT_ADD32(ctx, child, "good_bcast_frames", 950193880Syongari &stats->rx_bcast_frames, "Good broadcast frames"); 951193880Syongari ALC_SYSCTL_STAT_ADD32(ctx, child, "good_mcast_frames", 952193880Syongari &stats->rx_mcast_frames, "Good multicast frames"); 953193880Syongari ALC_SYSCTL_STAT_ADD32(ctx, child, "pause_frames", 954193880Syongari &stats->rx_pause_frames, "Pause control frames"); 955193880Syongari ALC_SYSCTL_STAT_ADD32(ctx, child, "control_frames", 956193880Syongari &stats->rx_control_frames, "Control frames"); 957193880Syongari ALC_SYSCTL_STAT_ADD32(ctx, child, "crc_errs", 958193880Syongari &stats->rx_crcerrs, "CRC errors"); 959193880Syongari ALC_SYSCTL_STAT_ADD32(ctx, child, "len_errs", 960193880Syongari &stats->rx_lenerrs, "Frames with length mismatched"); 961193880Syongari ALC_SYSCTL_STAT_ADD64(ctx, child, "good_octets", 962193880Syongari &stats->rx_bytes, "Good octets"); 963193880Syongari ALC_SYSCTL_STAT_ADD64(ctx, child, "good_bcast_octets", 964193880Syongari &stats->rx_bcast_bytes, "Good broadcast octets"); 965193880Syongari ALC_SYSCTL_STAT_ADD64(ctx, child, "good_mcast_octets", 966193880Syongari &stats->rx_mcast_bytes, "Good multicast octets"); 967193880Syongari ALC_SYSCTL_STAT_ADD32(ctx, child, "runts", 968193880Syongari &stats->rx_runts, "Too short frames"); 969193880Syongari ALC_SYSCTL_STAT_ADD32(ctx, child, "fragments", 970193880Syongari &stats->rx_fragments, "Fragmented frames"); 971193880Syongari ALC_SYSCTL_STAT_ADD32(ctx, child, "frames_64", 972193880Syongari &stats->rx_pkts_64, "64 bytes frames"); 973193880Syongari ALC_SYSCTL_STAT_ADD32(ctx, child, "frames_65_127", 974193880Syongari &stats->rx_pkts_65_127, "65 to 127 bytes frames"); 975193880Syongari ALC_SYSCTL_STAT_ADD32(ctx, child, "frames_128_255", 976193880Syongari &stats->rx_pkts_128_255, "128 to 255 bytes frames"); 977193880Syongari ALC_SYSCTL_STAT_ADD32(ctx, child, "frames_256_511", 978193880Syongari &stats->rx_pkts_256_511, "256 to 511 bytes frames"); 979193880Syongari ALC_SYSCTL_STAT_ADD32(ctx, child, "frames_512_1023", 980193880Syongari &stats->rx_pkts_512_1023, "512 to 1023 bytes frames"); 981193880Syongari ALC_SYSCTL_STAT_ADD32(ctx, child, "frames_1024_1518", 982193880Syongari &stats->rx_pkts_1024_1518, "1024 to 1518 bytes frames"); 983193880Syongari ALC_SYSCTL_STAT_ADD32(ctx, child, "frames_1519_max", 984193880Syongari &stats->rx_pkts_1519_max, "1519 to max frames"); 985193880Syongari ALC_SYSCTL_STAT_ADD32(ctx, child, "trunc_errs", 986193880Syongari &stats->rx_pkts_truncated, "Truncated frames due to MTU size"); 987193880Syongari ALC_SYSCTL_STAT_ADD32(ctx, child, "fifo_oflows", 988193880Syongari &stats->rx_fifo_oflows, "FIFO overflows"); 989193880Syongari ALC_SYSCTL_STAT_ADD32(ctx, child, "rrs_errs", 990193880Syongari &stats->rx_rrs_errs, "Return status write-back errors"); 991193880Syongari ALC_SYSCTL_STAT_ADD32(ctx, child, "align_errs", 992193880Syongari &stats->rx_alignerrs, "Alignment errors"); 993193880Syongari ALC_SYSCTL_STAT_ADD32(ctx, child, "filtered", 994193880Syongari &stats->rx_pkts_filtered, 995193880Syongari "Frames dropped due to address filtering"); 996193880Syongari 997193880Syongari /* Tx statistics. */ 998193880Syongari tree = SYSCTL_ADD_NODE(ctx, parent, OID_AUTO, "tx", CTLFLAG_RD, 999193880Syongari NULL, "Tx MAC statistics"); 1000193880Syongari child = SYSCTL_CHILDREN(tree); 1001193880Syongari ALC_SYSCTL_STAT_ADD32(ctx, child, "good_frames", 1002193880Syongari &stats->tx_frames, "Good frames"); 1003193880Syongari ALC_SYSCTL_STAT_ADD32(ctx, child, "good_bcast_frames", 1004193880Syongari &stats->tx_bcast_frames, "Good broadcast frames"); 1005193880Syongari ALC_SYSCTL_STAT_ADD32(ctx, child, "good_mcast_frames", 1006193880Syongari &stats->tx_mcast_frames, "Good multicast frames"); 1007193880Syongari ALC_SYSCTL_STAT_ADD32(ctx, child, "pause_frames", 1008193880Syongari &stats->tx_pause_frames, "Pause control frames"); 1009193880Syongari ALC_SYSCTL_STAT_ADD32(ctx, child, "control_frames", 1010193880Syongari &stats->tx_control_frames, "Control frames"); 1011193880Syongari ALC_SYSCTL_STAT_ADD32(ctx, child, "excess_defers", 1012193880Syongari &stats->tx_excess_defer, "Frames with excessive derferrals"); 1013193880Syongari ALC_SYSCTL_STAT_ADD32(ctx, child, "defers", 1014193880Syongari &stats->tx_excess_defer, "Frames with derferrals"); 1015193880Syongari ALC_SYSCTL_STAT_ADD64(ctx, child, "good_octets", 1016193880Syongari &stats->tx_bytes, "Good octets"); 1017193880Syongari ALC_SYSCTL_STAT_ADD64(ctx, child, "good_bcast_octets", 1018193880Syongari &stats->tx_bcast_bytes, "Good broadcast octets"); 1019193880Syongari ALC_SYSCTL_STAT_ADD64(ctx, child, "good_mcast_octets", 1020193880Syongari &stats->tx_mcast_bytes, "Good multicast octets"); 1021193880Syongari ALC_SYSCTL_STAT_ADD32(ctx, child, "frames_64", 1022193880Syongari &stats->tx_pkts_64, "64 bytes frames"); 1023193880Syongari ALC_SYSCTL_STAT_ADD32(ctx, child, "frames_65_127", 1024193880Syongari &stats->tx_pkts_65_127, "65 to 127 bytes frames"); 1025193880Syongari ALC_SYSCTL_STAT_ADD32(ctx, child, "frames_128_255", 1026193880Syongari &stats->tx_pkts_128_255, "128 to 255 bytes frames"); 1027193880Syongari ALC_SYSCTL_STAT_ADD32(ctx, child, "frames_256_511", 1028193880Syongari &stats->tx_pkts_256_511, "256 to 511 bytes frames"); 1029193880Syongari ALC_SYSCTL_STAT_ADD32(ctx, child, "frames_512_1023", 1030193880Syongari &stats->tx_pkts_512_1023, "512 to 1023 bytes frames"); 1031193880Syongari ALC_SYSCTL_STAT_ADD32(ctx, child, "frames_1024_1518", 1032193880Syongari &stats->tx_pkts_1024_1518, "1024 to 1518 bytes frames"); 1033193880Syongari ALC_SYSCTL_STAT_ADD32(ctx, child, "frames_1519_max", 1034193880Syongari &stats->tx_pkts_1519_max, "1519 to max frames"); 1035193880Syongari ALC_SYSCTL_STAT_ADD32(ctx, child, "single_colls", 1036193880Syongari &stats->tx_single_colls, "Single collisions"); 1037193880Syongari ALC_SYSCTL_STAT_ADD32(ctx, child, "multi_colls", 1038193880Syongari &stats->tx_multi_colls, "Multiple collisions"); 1039193880Syongari ALC_SYSCTL_STAT_ADD32(ctx, child, "late_colls", 1040193880Syongari &stats->tx_late_colls, "Late collisions"); 1041193880Syongari ALC_SYSCTL_STAT_ADD32(ctx, child, "excess_colls", 1042193880Syongari &stats->tx_excess_colls, "Excessive collisions"); 1043193880Syongari ALC_SYSCTL_STAT_ADD32(ctx, child, "abort", 1044193880Syongari &stats->tx_abort, "Aborted frames due to Excessive collisions"); 1045193880Syongari ALC_SYSCTL_STAT_ADD32(ctx, child, "underruns", 1046193880Syongari &stats->tx_underrun, "FIFO underruns"); 1047193880Syongari ALC_SYSCTL_STAT_ADD32(ctx, child, "desc_underruns", 1048193880Syongari &stats->tx_desc_underrun, "Descriptor write-back errors"); 1049193880Syongari ALC_SYSCTL_STAT_ADD32(ctx, child, "len_errs", 1050193880Syongari &stats->tx_lenerrs, "Frames with length mismatched"); 1051193880Syongari ALC_SYSCTL_STAT_ADD32(ctx, child, "trunc_errs", 1052193880Syongari &stats->tx_pkts_truncated, "Truncated frames due to MTU size"); 1053193880Syongari} 1054193880Syongari 1055193880Syongari#undef ALC_SYSCTL_STAT_ADD32 1056193880Syongari#undef ALC_SYSCTL_STAT_ADD64 1057193880Syongari 1058193880Syongaristruct alc_dmamap_arg { 1059193880Syongari bus_addr_t alc_busaddr; 1060193880Syongari}; 1061193880Syongari 1062193880Syongaristatic void 1063193880Syongarialc_dmamap_cb(void *arg, bus_dma_segment_t *segs, int nsegs, int error) 1064193880Syongari{ 1065193880Syongari struct alc_dmamap_arg *ctx; 1066193880Syongari 1067193880Syongari if (error != 0) 1068193880Syongari return; 1069193880Syongari 1070193880Syongari KASSERT(nsegs == 1, ("%s: %d segments returned!", __func__, nsegs)); 1071193880Syongari 1072193880Syongari ctx = (struct alc_dmamap_arg *)arg; 1073193880Syongari ctx->alc_busaddr = segs[0].ds_addr; 1074193880Syongari} 1075193880Syongari 1076193880Syongari/* 1077193880Syongari * Normal and high Tx descriptors shares single Tx high address. 1078193880Syongari * Four Rx descriptor/return rings and CMB shares the same Rx 1079193880Syongari * high address. 1080193880Syongari */ 1081193880Syongaristatic int 1082193880Syongarialc_check_boundary(struct alc_softc *sc) 1083193880Syongari{ 1084193880Syongari bus_addr_t cmb_end, rx_ring_end, rr_ring_end, tx_ring_end; 1085193880Syongari 1086193880Syongari rx_ring_end = sc->alc_rdata.alc_rx_ring_paddr + ALC_RX_RING_SZ; 1087193880Syongari rr_ring_end = sc->alc_rdata.alc_rr_ring_paddr + ALC_RR_RING_SZ; 1088193880Syongari cmb_end = sc->alc_rdata.alc_cmb_paddr + ALC_CMB_SZ; 1089193880Syongari tx_ring_end = sc->alc_rdata.alc_tx_ring_paddr + ALC_TX_RING_SZ; 1090193880Syongari 1091193880Syongari /* 4GB boundary crossing is not allowed. */ 1092193880Syongari if ((ALC_ADDR_HI(rx_ring_end) != 1093193880Syongari ALC_ADDR_HI(sc->alc_rdata.alc_rx_ring_paddr)) || 1094193880Syongari (ALC_ADDR_HI(rr_ring_end) != 1095193880Syongari ALC_ADDR_HI(sc->alc_rdata.alc_rr_ring_paddr)) || 1096193880Syongari (ALC_ADDR_HI(cmb_end) != 1097193880Syongari ALC_ADDR_HI(sc->alc_rdata.alc_cmb_paddr)) || 1098193880Syongari (ALC_ADDR_HI(tx_ring_end) != 1099193880Syongari ALC_ADDR_HI(sc->alc_rdata.alc_tx_ring_paddr))) 1100193880Syongari return (EFBIG); 1101193880Syongari /* 1102193880Syongari * Make sure Rx return descriptor/Rx descriptor/CMB use 1103193880Syongari * the same high address. 1104193880Syongari */ 1105193880Syongari if ((ALC_ADDR_HI(rx_ring_end) != ALC_ADDR_HI(rr_ring_end)) || 1106193880Syongari (ALC_ADDR_HI(rx_ring_end) != ALC_ADDR_HI(cmb_end))) 1107193880Syongari return (EFBIG); 1108193880Syongari 1109193880Syongari return (0); 1110193880Syongari} 1111193880Syongari 1112193880Syongaristatic int 1113193880Syongarialc_dma_alloc(struct alc_softc *sc) 1114193880Syongari{ 1115193880Syongari struct alc_txdesc *txd; 1116193880Syongari struct alc_rxdesc *rxd; 1117193880Syongari bus_addr_t lowaddr; 1118193880Syongari struct alc_dmamap_arg ctx; 1119193880Syongari int error, i; 1120193880Syongari 1121193880Syongari lowaddr = BUS_SPACE_MAXADDR; 1122193880Syongariagain: 1123193880Syongari /* Create parent DMA tag. */ 1124193880Syongari error = bus_dma_tag_create( 1125193880Syongari bus_get_dma_tag(sc->alc_dev), /* parent */ 1126193880Syongari 1, 0, /* alignment, boundary */ 1127193880Syongari lowaddr, /* lowaddr */ 1128193880Syongari BUS_SPACE_MAXADDR, /* highaddr */ 1129193880Syongari NULL, NULL, /* filter, filterarg */ 1130193880Syongari BUS_SPACE_MAXSIZE_32BIT, /* maxsize */ 1131193880Syongari 0, /* nsegments */ 1132193880Syongari BUS_SPACE_MAXSIZE_32BIT, /* maxsegsize */ 1133193880Syongari 0, /* flags */ 1134193880Syongari NULL, NULL, /* lockfunc, lockarg */ 1135193880Syongari &sc->alc_cdata.alc_parent_tag); 1136193880Syongari if (error != 0) { 1137193880Syongari device_printf(sc->alc_dev, 1138193880Syongari "could not create parent DMA tag.\n"); 1139193880Syongari goto fail; 1140193880Syongari } 1141193880Syongari 1142193880Syongari /* Create DMA tag for Tx descriptor ring. */ 1143193880Syongari error = bus_dma_tag_create( 1144193880Syongari sc->alc_cdata.alc_parent_tag, /* parent */ 1145193880Syongari ALC_TX_RING_ALIGN, 0, /* alignment, boundary */ 1146193880Syongari BUS_SPACE_MAXADDR, /* lowaddr */ 1147193880Syongari BUS_SPACE_MAXADDR, /* highaddr */ 1148193880Syongari NULL, NULL, /* filter, filterarg */ 1149193880Syongari ALC_TX_RING_SZ, /* maxsize */ 1150193880Syongari 1, /* nsegments */ 1151193880Syongari ALC_TX_RING_SZ, /* maxsegsize */ 1152193880Syongari 0, /* flags */ 1153193880Syongari NULL, NULL, /* lockfunc, lockarg */ 1154193880Syongari &sc->alc_cdata.alc_tx_ring_tag); 1155193880Syongari if (error != 0) { 1156193880Syongari device_printf(sc->alc_dev, 1157193880Syongari "could not create Tx ring DMA tag.\n"); 1158193880Syongari goto fail; 1159193880Syongari } 1160193880Syongari 1161193880Syongari /* Create DMA tag for Rx free descriptor ring. */ 1162193880Syongari error = bus_dma_tag_create( 1163193880Syongari sc->alc_cdata.alc_parent_tag, /* parent */ 1164193880Syongari ALC_RX_RING_ALIGN, 0, /* alignment, boundary */ 1165193880Syongari BUS_SPACE_MAXADDR, /* lowaddr */ 1166193880Syongari BUS_SPACE_MAXADDR, /* highaddr */ 1167193880Syongari NULL, NULL, /* filter, filterarg */ 1168193880Syongari ALC_RX_RING_SZ, /* maxsize */ 1169193880Syongari 1, /* nsegments */ 1170193880Syongari ALC_RX_RING_SZ, /* maxsegsize */ 1171193880Syongari 0, /* flags */ 1172193880Syongari NULL, NULL, /* lockfunc, lockarg */ 1173193880Syongari &sc->alc_cdata.alc_rx_ring_tag); 1174193880Syongari if (error != 0) { 1175193880Syongari device_printf(sc->alc_dev, 1176193880Syongari "could not create Rx ring DMA tag.\n"); 1177193880Syongari goto fail; 1178193880Syongari } 1179193880Syongari /* Create DMA tag for Rx return descriptor ring. */ 1180193880Syongari error = bus_dma_tag_create( 1181193880Syongari sc->alc_cdata.alc_parent_tag, /* parent */ 1182193880Syongari ALC_RR_RING_ALIGN, 0, /* alignment, boundary */ 1183193880Syongari BUS_SPACE_MAXADDR, /* lowaddr */ 1184193880Syongari BUS_SPACE_MAXADDR, /* highaddr */ 1185193880Syongari NULL, NULL, /* filter, filterarg */ 1186193880Syongari ALC_RR_RING_SZ, /* maxsize */ 1187193880Syongari 1, /* nsegments */ 1188193880Syongari ALC_RR_RING_SZ, /* maxsegsize */ 1189193880Syongari 0, /* flags */ 1190193880Syongari NULL, NULL, /* lockfunc, lockarg */ 1191193880Syongari &sc->alc_cdata.alc_rr_ring_tag); 1192193880Syongari if (error != 0) { 1193193880Syongari device_printf(sc->alc_dev, 1194193880Syongari "could not create Rx return ring DMA tag.\n"); 1195193880Syongari goto fail; 1196193880Syongari } 1197193880Syongari 1198193880Syongari /* Create DMA tag for coalescing message block. */ 1199193880Syongari error = bus_dma_tag_create( 1200193880Syongari sc->alc_cdata.alc_parent_tag, /* parent */ 1201193880Syongari ALC_CMB_ALIGN, 0, /* alignment, boundary */ 1202193880Syongari BUS_SPACE_MAXADDR, /* lowaddr */ 1203193880Syongari BUS_SPACE_MAXADDR, /* highaddr */ 1204193880Syongari NULL, NULL, /* filter, filterarg */ 1205193880Syongari ALC_CMB_SZ, /* maxsize */ 1206193880Syongari 1, /* nsegments */ 1207193880Syongari ALC_CMB_SZ, /* maxsegsize */ 1208193880Syongari 0, /* flags */ 1209193880Syongari NULL, NULL, /* lockfunc, lockarg */ 1210193880Syongari &sc->alc_cdata.alc_cmb_tag); 1211193880Syongari if (error != 0) { 1212193880Syongari device_printf(sc->alc_dev, 1213193880Syongari "could not create CMB DMA tag.\n"); 1214193880Syongari goto fail; 1215193880Syongari } 1216193880Syongari /* Create DMA tag for status message block. */ 1217193880Syongari error = bus_dma_tag_create( 1218193880Syongari sc->alc_cdata.alc_parent_tag, /* parent */ 1219193880Syongari ALC_SMB_ALIGN, 0, /* alignment, boundary */ 1220193880Syongari BUS_SPACE_MAXADDR, /* lowaddr */ 1221193880Syongari BUS_SPACE_MAXADDR, /* highaddr */ 1222193880Syongari NULL, NULL, /* filter, filterarg */ 1223193880Syongari ALC_SMB_SZ, /* maxsize */ 1224193880Syongari 1, /* nsegments */ 1225193880Syongari ALC_SMB_SZ, /* maxsegsize */ 1226193880Syongari 0, /* flags */ 1227193880Syongari NULL, NULL, /* lockfunc, lockarg */ 1228193880Syongari &sc->alc_cdata.alc_smb_tag); 1229193880Syongari if (error != 0) { 1230193880Syongari device_printf(sc->alc_dev, 1231193880Syongari "could not create SMB DMA tag.\n"); 1232193880Syongari goto fail; 1233193880Syongari } 1234193880Syongari 1235193880Syongari /* Allocate DMA'able memory and load the DMA map for Tx ring. */ 1236193880Syongari error = bus_dmamem_alloc(sc->alc_cdata.alc_tx_ring_tag, 1237193880Syongari (void **)&sc->alc_rdata.alc_tx_ring, 1238193880Syongari BUS_DMA_WAITOK | BUS_DMA_ZERO | BUS_DMA_COHERENT, 1239193880Syongari &sc->alc_cdata.alc_tx_ring_map); 1240193880Syongari if (error != 0) { 1241193880Syongari device_printf(sc->alc_dev, 1242193880Syongari "could not allocate DMA'able memory for Tx ring.\n"); 1243193880Syongari goto fail; 1244193880Syongari } 1245193880Syongari ctx.alc_busaddr = 0; 1246193880Syongari error = bus_dmamap_load(sc->alc_cdata.alc_tx_ring_tag, 1247193880Syongari sc->alc_cdata.alc_tx_ring_map, sc->alc_rdata.alc_tx_ring, 1248193880Syongari ALC_TX_RING_SZ, alc_dmamap_cb, &ctx, 0); 1249193880Syongari if (error != 0 || ctx.alc_busaddr == 0) { 1250193880Syongari device_printf(sc->alc_dev, 1251193880Syongari "could not load DMA'able memory for Tx ring.\n"); 1252193880Syongari goto fail; 1253193880Syongari } 1254193880Syongari sc->alc_rdata.alc_tx_ring_paddr = ctx.alc_busaddr; 1255193880Syongari 1256193880Syongari /* Allocate DMA'able memory and load the DMA map for Rx ring. */ 1257193880Syongari error = bus_dmamem_alloc(sc->alc_cdata.alc_rx_ring_tag, 1258193880Syongari (void **)&sc->alc_rdata.alc_rx_ring, 1259193880Syongari BUS_DMA_WAITOK | BUS_DMA_ZERO | BUS_DMA_COHERENT, 1260193880Syongari &sc->alc_cdata.alc_rx_ring_map); 1261193880Syongari if (error != 0) { 1262193880Syongari device_printf(sc->alc_dev, 1263193880Syongari "could not allocate DMA'able memory for Rx ring.\n"); 1264193880Syongari goto fail; 1265193880Syongari } 1266193880Syongari ctx.alc_busaddr = 0; 1267193880Syongari error = bus_dmamap_load(sc->alc_cdata.alc_rx_ring_tag, 1268193880Syongari sc->alc_cdata.alc_rx_ring_map, sc->alc_rdata.alc_rx_ring, 1269193880Syongari ALC_RX_RING_SZ, alc_dmamap_cb, &ctx, 0); 1270193880Syongari if (error != 0 || ctx.alc_busaddr == 0) { 1271193880Syongari device_printf(sc->alc_dev, 1272193880Syongari "could not load DMA'able memory for Rx ring.\n"); 1273193880Syongari goto fail; 1274193880Syongari } 1275193880Syongari sc->alc_rdata.alc_rx_ring_paddr = ctx.alc_busaddr; 1276193880Syongari 1277193880Syongari /* Allocate DMA'able memory and load the DMA map for Rx return ring. */ 1278193880Syongari error = bus_dmamem_alloc(sc->alc_cdata.alc_rr_ring_tag, 1279193880Syongari (void **)&sc->alc_rdata.alc_rr_ring, 1280193880Syongari BUS_DMA_WAITOK | BUS_DMA_ZERO | BUS_DMA_COHERENT, 1281193880Syongari &sc->alc_cdata.alc_rr_ring_map); 1282193880Syongari if (error != 0) { 1283193880Syongari device_printf(sc->alc_dev, 1284193880Syongari "could not allocate DMA'able memory for Rx return ring.\n"); 1285193880Syongari goto fail; 1286193880Syongari } 1287193880Syongari ctx.alc_busaddr = 0; 1288193880Syongari error = bus_dmamap_load(sc->alc_cdata.alc_rr_ring_tag, 1289193880Syongari sc->alc_cdata.alc_rr_ring_map, sc->alc_rdata.alc_rr_ring, 1290193880Syongari ALC_RR_RING_SZ, alc_dmamap_cb, &ctx, 0); 1291193880Syongari if (error != 0 || ctx.alc_busaddr == 0) { 1292193880Syongari device_printf(sc->alc_dev, 1293193880Syongari "could not load DMA'able memory for Tx ring.\n"); 1294193880Syongari goto fail; 1295193880Syongari } 1296193880Syongari sc->alc_rdata.alc_rr_ring_paddr = ctx.alc_busaddr; 1297193880Syongari 1298193880Syongari /* Allocate DMA'able memory and load the DMA map for CMB. */ 1299193880Syongari error = bus_dmamem_alloc(sc->alc_cdata.alc_cmb_tag, 1300193880Syongari (void **)&sc->alc_rdata.alc_cmb, 1301193880Syongari BUS_DMA_WAITOK | BUS_DMA_ZERO | BUS_DMA_COHERENT, 1302193880Syongari &sc->alc_cdata.alc_cmb_map); 1303193880Syongari if (error != 0) { 1304193880Syongari device_printf(sc->alc_dev, 1305193880Syongari "could not allocate DMA'able memory for CMB.\n"); 1306193880Syongari goto fail; 1307193880Syongari } 1308193880Syongari ctx.alc_busaddr = 0; 1309193880Syongari error = bus_dmamap_load(sc->alc_cdata.alc_cmb_tag, 1310193880Syongari sc->alc_cdata.alc_cmb_map, sc->alc_rdata.alc_cmb, 1311193880Syongari ALC_CMB_SZ, alc_dmamap_cb, &ctx, 0); 1312193880Syongari if (error != 0 || ctx.alc_busaddr == 0) { 1313193880Syongari device_printf(sc->alc_dev, 1314193880Syongari "could not load DMA'able memory for CMB.\n"); 1315193880Syongari goto fail; 1316193880Syongari } 1317193880Syongari sc->alc_rdata.alc_cmb_paddr = ctx.alc_busaddr; 1318193880Syongari 1319193880Syongari /* Allocate DMA'able memory and load the DMA map for SMB. */ 1320193880Syongari error = bus_dmamem_alloc(sc->alc_cdata.alc_smb_tag, 1321193880Syongari (void **)&sc->alc_rdata.alc_smb, 1322193880Syongari BUS_DMA_WAITOK | BUS_DMA_ZERO | BUS_DMA_COHERENT, 1323193880Syongari &sc->alc_cdata.alc_smb_map); 1324193880Syongari if (error != 0) { 1325193880Syongari device_printf(sc->alc_dev, 1326193880Syongari "could not allocate DMA'able memory for SMB.\n"); 1327193880Syongari goto fail; 1328193880Syongari } 1329193880Syongari ctx.alc_busaddr = 0; 1330193880Syongari error = bus_dmamap_load(sc->alc_cdata.alc_smb_tag, 1331193880Syongari sc->alc_cdata.alc_smb_map, sc->alc_rdata.alc_smb, 1332193880Syongari ALC_SMB_SZ, alc_dmamap_cb, &ctx, 0); 1333193880Syongari if (error != 0 || ctx.alc_busaddr == 0) { 1334193880Syongari device_printf(sc->alc_dev, 1335193880Syongari "could not load DMA'able memory for CMB.\n"); 1336193880Syongari goto fail; 1337193880Syongari } 1338193880Syongari sc->alc_rdata.alc_smb_paddr = ctx.alc_busaddr; 1339193880Syongari 1340193880Syongari /* Make sure we've not crossed 4GB boundary. */ 1341193880Syongari if (lowaddr != BUS_SPACE_MAXADDR_32BIT && 1342193880Syongari (error = alc_check_boundary(sc)) != 0) { 1343193880Syongari device_printf(sc->alc_dev, "4GB boundary crossed, " 1344193880Syongari "switching to 32bit DMA addressing mode.\n"); 1345193880Syongari alc_dma_free(sc); 1346193880Syongari /* 1347193880Syongari * Limit max allowable DMA address space to 32bit 1348193880Syongari * and try again. 1349193880Syongari */ 1350193880Syongari lowaddr = BUS_SPACE_MAXADDR_32BIT; 1351193880Syongari goto again; 1352193880Syongari } 1353193880Syongari 1354193880Syongari /* 1355193880Syongari * Create Tx buffer parent tag. 1356193880Syongari * AR8131/AR8132 allows 64bit DMA addressing of Tx/Rx buffers 1357193880Syongari * so it needs separate parent DMA tag as parent DMA address 1358193880Syongari * space could be restricted to be within 32bit address space 1359193880Syongari * by 4GB boundary crossing. 1360193880Syongari */ 1361193880Syongari error = bus_dma_tag_create( 1362193880Syongari bus_get_dma_tag(sc->alc_dev), /* parent */ 1363193880Syongari 1, 0, /* alignment, boundary */ 1364193880Syongari BUS_SPACE_MAXADDR, /* lowaddr */ 1365193880Syongari BUS_SPACE_MAXADDR, /* highaddr */ 1366193880Syongari NULL, NULL, /* filter, filterarg */ 1367193880Syongari BUS_SPACE_MAXSIZE_32BIT, /* maxsize */ 1368193880Syongari 0, /* nsegments */ 1369193880Syongari BUS_SPACE_MAXSIZE_32BIT, /* maxsegsize */ 1370193880Syongari 0, /* flags */ 1371193880Syongari NULL, NULL, /* lockfunc, lockarg */ 1372193880Syongari &sc->alc_cdata.alc_buffer_tag); 1373193880Syongari if (error != 0) { 1374193880Syongari device_printf(sc->alc_dev, 1375193880Syongari "could not create parent buffer DMA tag.\n"); 1376193880Syongari goto fail; 1377193880Syongari } 1378193880Syongari 1379193880Syongari /* Create DMA tag for Tx buffers. */ 1380193880Syongari error = bus_dma_tag_create( 1381193880Syongari sc->alc_cdata.alc_buffer_tag, /* parent */ 1382193880Syongari 1, 0, /* alignment, boundary */ 1383193880Syongari BUS_SPACE_MAXADDR, /* lowaddr */ 1384193880Syongari BUS_SPACE_MAXADDR, /* highaddr */ 1385193880Syongari NULL, NULL, /* filter, filterarg */ 1386193880Syongari ALC_TSO_MAXSIZE, /* maxsize */ 1387193880Syongari ALC_MAXTXSEGS, /* nsegments */ 1388193880Syongari ALC_TSO_MAXSEGSIZE, /* maxsegsize */ 1389193880Syongari 0, /* flags */ 1390193880Syongari NULL, NULL, /* lockfunc, lockarg */ 1391193880Syongari &sc->alc_cdata.alc_tx_tag); 1392193880Syongari if (error != 0) { 1393193880Syongari device_printf(sc->alc_dev, "could not create Tx DMA tag.\n"); 1394193880Syongari goto fail; 1395193880Syongari } 1396193880Syongari 1397193880Syongari /* Create DMA tag for Rx buffers. */ 1398193880Syongari error = bus_dma_tag_create( 1399193880Syongari sc->alc_cdata.alc_buffer_tag, /* parent */ 1400193880Syongari ALC_RX_BUF_ALIGN, 0, /* alignment, boundary */ 1401193880Syongari BUS_SPACE_MAXADDR, /* lowaddr */ 1402193880Syongari BUS_SPACE_MAXADDR, /* highaddr */ 1403193880Syongari NULL, NULL, /* filter, filterarg */ 1404193880Syongari MCLBYTES, /* maxsize */ 1405193880Syongari 1, /* nsegments */ 1406193880Syongari MCLBYTES, /* maxsegsize */ 1407193880Syongari 0, /* flags */ 1408193880Syongari NULL, NULL, /* lockfunc, lockarg */ 1409193880Syongari &sc->alc_cdata.alc_rx_tag); 1410193880Syongari if (error != 0) { 1411193880Syongari device_printf(sc->alc_dev, "could not create Rx DMA tag.\n"); 1412193880Syongari goto fail; 1413193880Syongari } 1414193880Syongari /* Create DMA maps for Tx buffers. */ 1415193880Syongari for (i = 0; i < ALC_TX_RING_CNT; i++) { 1416193880Syongari txd = &sc->alc_cdata.alc_txdesc[i]; 1417193880Syongari txd->tx_m = NULL; 1418193880Syongari txd->tx_dmamap = NULL; 1419193880Syongari error = bus_dmamap_create(sc->alc_cdata.alc_tx_tag, 0, 1420193880Syongari &txd->tx_dmamap); 1421193880Syongari if (error != 0) { 1422193880Syongari device_printf(sc->alc_dev, 1423193880Syongari "could not create Tx dmamap.\n"); 1424193880Syongari goto fail; 1425193880Syongari } 1426193880Syongari } 1427193880Syongari /* Create DMA maps for Rx buffers. */ 1428193880Syongari if ((error = bus_dmamap_create(sc->alc_cdata.alc_rx_tag, 0, 1429193880Syongari &sc->alc_cdata.alc_rx_sparemap)) != 0) { 1430193880Syongari device_printf(sc->alc_dev, 1431193880Syongari "could not create spare Rx dmamap.\n"); 1432193880Syongari goto fail; 1433193880Syongari } 1434193880Syongari for (i = 0; i < ALC_RX_RING_CNT; i++) { 1435193880Syongari rxd = &sc->alc_cdata.alc_rxdesc[i]; 1436193880Syongari rxd->rx_m = NULL; 1437193880Syongari rxd->rx_dmamap = NULL; 1438193880Syongari error = bus_dmamap_create(sc->alc_cdata.alc_rx_tag, 0, 1439193880Syongari &rxd->rx_dmamap); 1440193880Syongari if (error != 0) { 1441193880Syongari device_printf(sc->alc_dev, 1442193880Syongari "could not create Rx dmamap.\n"); 1443193880Syongari goto fail; 1444193880Syongari } 1445193880Syongari } 1446193880Syongari 1447193880Syongarifail: 1448193880Syongari return (error); 1449193880Syongari} 1450193880Syongari 1451193880Syongaristatic void 1452193880Syongarialc_dma_free(struct alc_softc *sc) 1453193880Syongari{ 1454193880Syongari struct alc_txdesc *txd; 1455193880Syongari struct alc_rxdesc *rxd; 1456193880Syongari int i; 1457193880Syongari 1458193880Syongari /* Tx buffers. */ 1459193880Syongari if (sc->alc_cdata.alc_tx_tag != NULL) { 1460193880Syongari for (i = 0; i < ALC_TX_RING_CNT; i++) { 1461193880Syongari txd = &sc->alc_cdata.alc_txdesc[i]; 1462193880Syongari if (txd->tx_dmamap != NULL) { 1463193880Syongari bus_dmamap_destroy(sc->alc_cdata.alc_tx_tag, 1464193880Syongari txd->tx_dmamap); 1465193880Syongari txd->tx_dmamap = NULL; 1466193880Syongari } 1467193880Syongari } 1468193880Syongari bus_dma_tag_destroy(sc->alc_cdata.alc_tx_tag); 1469193880Syongari sc->alc_cdata.alc_tx_tag = NULL; 1470193880Syongari } 1471193880Syongari /* Rx buffers */ 1472193880Syongari if (sc->alc_cdata.alc_rx_tag != NULL) { 1473193880Syongari for (i = 0; i < ALC_RX_RING_CNT; i++) { 1474193880Syongari rxd = &sc->alc_cdata.alc_rxdesc[i]; 1475193880Syongari if (rxd->rx_dmamap != NULL) { 1476193880Syongari bus_dmamap_destroy(sc->alc_cdata.alc_rx_tag, 1477193880Syongari rxd->rx_dmamap); 1478193880Syongari rxd->rx_dmamap = NULL; 1479193880Syongari } 1480193880Syongari } 1481193880Syongari if (sc->alc_cdata.alc_rx_sparemap != NULL) { 1482193880Syongari bus_dmamap_destroy(sc->alc_cdata.alc_rx_tag, 1483193880Syongari sc->alc_cdata.alc_rx_sparemap); 1484193880Syongari sc->alc_cdata.alc_rx_sparemap = NULL; 1485193880Syongari } 1486193880Syongari bus_dma_tag_destroy(sc->alc_cdata.alc_rx_tag); 1487193880Syongari sc->alc_cdata.alc_rx_tag = NULL; 1488193880Syongari } 1489193880Syongari /* Tx descriptor ring. */ 1490193880Syongari if (sc->alc_cdata.alc_tx_ring_tag != NULL) { 1491193880Syongari if (sc->alc_cdata.alc_tx_ring_map != NULL) 1492193880Syongari bus_dmamap_unload(sc->alc_cdata.alc_tx_ring_tag, 1493193880Syongari sc->alc_cdata.alc_tx_ring_map); 1494193880Syongari if (sc->alc_cdata.alc_tx_ring_map != NULL && 1495193880Syongari sc->alc_rdata.alc_tx_ring != NULL) 1496193880Syongari bus_dmamem_free(sc->alc_cdata.alc_tx_ring_tag, 1497193880Syongari sc->alc_rdata.alc_tx_ring, 1498193880Syongari sc->alc_cdata.alc_tx_ring_map); 1499193880Syongari sc->alc_rdata.alc_tx_ring = NULL; 1500193880Syongari sc->alc_cdata.alc_tx_ring_map = NULL; 1501193880Syongari bus_dma_tag_destroy(sc->alc_cdata.alc_tx_ring_tag); 1502193880Syongari sc->alc_cdata.alc_tx_ring_tag = NULL; 1503193880Syongari } 1504193880Syongari /* Rx return ring. */ 1505193880Syongari if (sc->alc_cdata.alc_rr_ring_tag != NULL) { 1506193880Syongari if (sc->alc_cdata.alc_rr_ring_map != NULL) 1507193880Syongari bus_dmamap_unload(sc->alc_cdata.alc_rr_ring_tag, 1508193880Syongari sc->alc_cdata.alc_rr_ring_map); 1509193880Syongari if (sc->alc_cdata.alc_rr_ring_map != NULL && 1510193880Syongari sc->alc_rdata.alc_rr_ring != NULL) 1511193880Syongari bus_dmamem_free(sc->alc_cdata.alc_rr_ring_tag, 1512193880Syongari sc->alc_rdata.alc_rr_ring, 1513193880Syongari sc->alc_cdata.alc_rr_ring_map); 1514193880Syongari sc->alc_rdata.alc_rr_ring = NULL; 1515193880Syongari sc->alc_cdata.alc_rr_ring_map = NULL; 1516193880Syongari bus_dma_tag_destroy(sc->alc_cdata.alc_rr_ring_tag); 1517193880Syongari sc->alc_cdata.alc_rr_ring_tag = NULL; 1518193880Syongari } 1519193880Syongari /* CMB block */ 1520193880Syongari if (sc->alc_cdata.alc_cmb_tag != NULL) { 1521193880Syongari if (sc->alc_cdata.alc_cmb_map != NULL) 1522193880Syongari bus_dmamap_unload(sc->alc_cdata.alc_cmb_tag, 1523193880Syongari sc->alc_cdata.alc_cmb_map); 1524193880Syongari if (sc->alc_cdata.alc_cmb_map != NULL && 1525193880Syongari sc->alc_rdata.alc_cmb != NULL) 1526193880Syongari bus_dmamem_free(sc->alc_cdata.alc_cmb_tag, 1527193880Syongari sc->alc_rdata.alc_cmb, 1528193880Syongari sc->alc_cdata.alc_cmb_map); 1529193880Syongari sc->alc_rdata.alc_cmb = NULL; 1530193880Syongari sc->alc_cdata.alc_cmb_map = NULL; 1531193880Syongari bus_dma_tag_destroy(sc->alc_cdata.alc_cmb_tag); 1532193880Syongari sc->alc_cdata.alc_cmb_tag = NULL; 1533193880Syongari } 1534193880Syongari /* SMB block */ 1535193880Syongari if (sc->alc_cdata.alc_smb_tag != NULL) { 1536193880Syongari if (sc->alc_cdata.alc_smb_map != NULL) 1537193880Syongari bus_dmamap_unload(sc->alc_cdata.alc_smb_tag, 1538193880Syongari sc->alc_cdata.alc_smb_map); 1539193880Syongari if (sc->alc_cdata.alc_smb_map != NULL && 1540193880Syongari sc->alc_rdata.alc_smb != NULL) 1541193880Syongari bus_dmamem_free(sc->alc_cdata.alc_smb_tag, 1542193880Syongari sc->alc_rdata.alc_smb, 1543193880Syongari sc->alc_cdata.alc_smb_map); 1544193880Syongari sc->alc_rdata.alc_smb = NULL; 1545193880Syongari sc->alc_cdata.alc_smb_map = NULL; 1546193880Syongari bus_dma_tag_destroy(sc->alc_cdata.alc_smb_tag); 1547193880Syongari sc->alc_cdata.alc_smb_tag = NULL; 1548193880Syongari } 1549193880Syongari if (sc->alc_cdata.alc_buffer_tag != NULL) { 1550193880Syongari bus_dma_tag_destroy(sc->alc_cdata.alc_buffer_tag); 1551193880Syongari sc->alc_cdata.alc_buffer_tag = NULL; 1552193880Syongari } 1553193880Syongari if (sc->alc_cdata.alc_parent_tag != NULL) { 1554193880Syongari bus_dma_tag_destroy(sc->alc_cdata.alc_parent_tag); 1555193880Syongari sc->alc_cdata.alc_parent_tag = NULL; 1556193880Syongari } 1557193880Syongari} 1558193880Syongari 1559193880Syongaristatic int 1560193880Syongarialc_shutdown(device_t dev) 1561193880Syongari{ 1562193880Syongari 1563193880Syongari return (alc_suspend(dev)); 1564193880Syongari} 1565193880Syongari 1566193880Syongari/* 1567193880Syongari * Note, this driver resets the link speed to 10/100Mbps by 1568193880Syongari * restarting auto-negotiation in suspend/shutdown phase but we 1569193880Syongari * don't know whether that auto-negotiation would succeed or not 1570193880Syongari * as driver has no control after powering off/suspend operation. 1571193880Syongari * If the renegotiation fail WOL may not work. Running at 1Gbps 1572193880Syongari * will draw more power than 375mA at 3.3V which is specified in 1573193880Syongari * PCI specification and that would result in complete 1574193880Syongari * shutdowning power to ethernet controller. 1575193880Syongari * 1576193880Syongari * TODO 1577193880Syongari * Save current negotiated media speed/duplex/flow-control to 1578193880Syongari * softc and restore the same link again after resuming. PHY 1579193880Syongari * handling such as power down/resetting to 100Mbps may be better 1580193880Syongari * handled in suspend method in phy driver. 1581193880Syongari */ 1582193880Syongaristatic void 1583193880Syongarialc_setlinkspeed(struct alc_softc *sc) 1584193880Syongari{ 1585193880Syongari struct mii_data *mii; 1586193880Syongari int aneg, i; 1587193880Syongari 1588193880Syongari mii = device_get_softc(sc->alc_miibus); 1589193880Syongari mii_pollstat(mii); 1590193880Syongari aneg = 0; 1591193880Syongari if ((mii->mii_media_status & (IFM_ACTIVE | IFM_AVALID)) == 1592193880Syongari (IFM_ACTIVE | IFM_AVALID)) { 1593193880Syongari switch IFM_SUBTYPE(mii->mii_media_active) { 1594193880Syongari case IFM_10_T: 1595193880Syongari case IFM_100_TX: 1596193880Syongari return; 1597193880Syongari case IFM_1000_T: 1598193880Syongari aneg++; 1599193880Syongari break; 1600193880Syongari default: 1601193880Syongari break; 1602193880Syongari } 1603193880Syongari } 1604193880Syongari alc_miibus_writereg(sc->alc_dev, sc->alc_phyaddr, MII_100T2CR, 0); 1605193880Syongari alc_miibus_writereg(sc->alc_dev, sc->alc_phyaddr, 1606193880Syongari MII_ANAR, ANAR_TX_FD | ANAR_TX | ANAR_10_FD | ANAR_10 | ANAR_CSMA); 1607193880Syongari alc_miibus_writereg(sc->alc_dev, sc->alc_phyaddr, 1608193880Syongari MII_BMCR, BMCR_RESET | BMCR_AUTOEN | BMCR_STARTNEG); 1609193880Syongari DELAY(1000); 1610193880Syongari if (aneg != 0) { 1611193880Syongari /* 1612193880Syongari * Poll link state until alc(4) get a 10/100Mbps link. 1613193880Syongari */ 1614193880Syongari for (i = 0; i < MII_ANEGTICKS_GIGE; i++) { 1615193880Syongari mii_pollstat(mii); 1616193880Syongari if ((mii->mii_media_status & (IFM_ACTIVE | IFM_AVALID)) 1617193880Syongari == (IFM_ACTIVE | IFM_AVALID)) { 1618193880Syongari switch (IFM_SUBTYPE( 1619193880Syongari mii->mii_media_active)) { 1620193880Syongari case IFM_10_T: 1621193880Syongari case IFM_100_TX: 1622193880Syongari alc_mac_config(sc); 1623193880Syongari return; 1624193880Syongari default: 1625193880Syongari break; 1626193880Syongari } 1627193880Syongari } 1628193880Syongari ALC_UNLOCK(sc); 1629193880Syongari pause("alclnk", hz); 1630193880Syongari ALC_LOCK(sc); 1631193880Syongari } 1632193880Syongari if (i == MII_ANEGTICKS_GIGE) 1633193880Syongari device_printf(sc->alc_dev, 1634193880Syongari "establishing a link failed, WOL may not work!"); 1635193880Syongari } 1636193880Syongari /* 1637193880Syongari * No link, force MAC to have 100Mbps, full-duplex link. 1638193880Syongari * This is the last resort and may/may not work. 1639193880Syongari */ 1640193880Syongari mii->mii_media_status = IFM_AVALID | IFM_ACTIVE; 1641193880Syongari mii->mii_media_active = IFM_ETHER | IFM_100_TX | IFM_FDX; 1642193880Syongari alc_mac_config(sc); 1643193880Syongari} 1644193880Syongari 1645193880Syongaristatic void 1646193880Syongarialc_setwol(struct alc_softc *sc) 1647193880Syongari{ 1648193880Syongari struct ifnet *ifp; 1649193880Syongari uint32_t cap, reg, pmcs; 1650193880Syongari uint16_t pmstat; 1651193880Syongari int base, pmc; 1652193880Syongari 1653193880Syongari ALC_LOCK_ASSERT(sc); 1654193880Syongari 1655193880Syongari if (pci_find_extcap(sc->alc_dev, PCIY_EXPRESS, &base) == 0) { 1656193880Syongari cap = CSR_READ_2(sc, base + PCIR_EXPRESS_LINK_CAP); 1657193880Syongari if ((cap & PCIM_LINK_CAP_ASPM) != 0) { 1658193880Syongari cap = CSR_READ_2(sc, base + PCIR_EXPRESS_LINK_CTL); 1659193880Syongari alc_disable_l0s_l1(sc); 1660193880Syongari } 1661193880Syongari } 1662193880Syongari if (pci_find_extcap(sc->alc_dev, PCIY_PMG, &pmc) != 0) { 1663193880Syongari /* Disable WOL. */ 1664193880Syongari CSR_WRITE_4(sc, ALC_WOL_CFG, 0); 1665193880Syongari reg = CSR_READ_4(sc, ALC_PCIE_PHYMISC); 1666193880Syongari reg |= PCIE_PHYMISC_FORCE_RCV_DET; 1667193880Syongari CSR_WRITE_4(sc, ALC_PCIE_PHYMISC, reg); 1668193880Syongari /* Force PHY power down. */ 1669193880Syongari alc_phy_down(sc); 1670193880Syongari return; 1671193880Syongari } 1672193880Syongari 1673193880Syongari ifp = sc->alc_ifp; 1674193880Syongari if ((ifp->if_capenable & IFCAP_WOL) != 0) { 1675193880Syongari if ((sc->alc_flags & ALC_FLAG_FASTETHER) == 0) 1676193880Syongari alc_setlinkspeed(sc); 1677193880Syongari reg = CSR_READ_4(sc, ALC_MASTER_CFG); 1678193880Syongari reg &= ~MASTER_CLK_SEL_DIS; 1679193880Syongari CSR_WRITE_4(sc, ALC_MASTER_CFG, reg); 1680193880Syongari } 1681193880Syongari 1682193880Syongari pmcs = 0; 1683193880Syongari if ((ifp->if_capenable & IFCAP_WOL_MAGIC) != 0) 1684193880Syongari pmcs |= WOL_CFG_MAGIC | WOL_CFG_MAGIC_ENB; 1685193880Syongari CSR_WRITE_4(sc, ALC_WOL_CFG, pmcs); 1686193880Syongari reg = CSR_READ_4(sc, ALC_MAC_CFG); 1687193880Syongari reg &= ~(MAC_CFG_DBG | MAC_CFG_PROMISC | MAC_CFG_ALLMULTI | 1688193880Syongari MAC_CFG_BCAST); 1689193880Syongari if ((ifp->if_capenable & IFCAP_WOL_MCAST) != 0) 1690193880Syongari reg |= MAC_CFG_ALLMULTI | MAC_CFG_BCAST; 1691193880Syongari if ((ifp->if_capenable & IFCAP_WOL) != 0) 1692193880Syongari reg |= MAC_CFG_RX_ENB; 1693193880Syongari CSR_WRITE_4(sc, ALC_MAC_CFG, reg); 1694193880Syongari 1695193880Syongari reg = CSR_READ_4(sc, ALC_PCIE_PHYMISC); 1696193880Syongari reg |= PCIE_PHYMISC_FORCE_RCV_DET; 1697193880Syongari CSR_WRITE_4(sc, ALC_PCIE_PHYMISC, reg); 1698193880Syongari if ((ifp->if_capenable & IFCAP_WOL) == 0) { 1699193880Syongari /* WOL disabled, PHY power down. */ 1700193880Syongari alc_phy_down(sc); 1701193880Syongari } 1702193880Syongari /* Request PME. */ 1703193880Syongari pmstat = pci_read_config(sc->alc_dev, pmc + PCIR_POWER_STATUS, 2); 1704193880Syongari pmstat &= ~(PCIM_PSTAT_PME | PCIM_PSTAT_PMEENABLE); 1705193880Syongari if ((ifp->if_capenable & IFCAP_WOL) != 0) 1706193880Syongari pmstat |= PCIM_PSTAT_PME | PCIM_PSTAT_PMEENABLE; 1707193880Syongari pci_write_config(sc->alc_dev, pmc + PCIR_POWER_STATUS, pmstat, 2); 1708193880Syongari} 1709193880Syongari 1710193880Syongaristatic int 1711193880Syongarialc_suspend(device_t dev) 1712193880Syongari{ 1713193880Syongari struct alc_softc *sc; 1714193880Syongari 1715193880Syongari sc = device_get_softc(dev); 1716193880Syongari 1717193880Syongari ALC_LOCK(sc); 1718193880Syongari alc_stop(sc); 1719193880Syongari alc_setwol(sc); 1720193880Syongari ALC_UNLOCK(sc); 1721193880Syongari 1722193880Syongari return (0); 1723193880Syongari} 1724193880Syongari 1725193880Syongaristatic int 1726193880Syongarialc_resume(device_t dev) 1727193880Syongari{ 1728193880Syongari struct alc_softc *sc; 1729193880Syongari struct ifnet *ifp; 1730193880Syongari int pmc; 1731193880Syongari uint16_t pmstat; 1732193880Syongari 1733193880Syongari sc = device_get_softc(dev); 1734193880Syongari 1735193880Syongari ALC_LOCK(sc); 1736193880Syongari if (pci_find_extcap(sc->alc_dev, PCIY_PMG, &pmc) == 0) { 1737193880Syongari /* Disable PME and clear PME status. */ 1738193880Syongari pmstat = pci_read_config(sc->alc_dev, 1739193880Syongari pmc + PCIR_POWER_STATUS, 2); 1740193880Syongari if ((pmstat & PCIM_PSTAT_PMEENABLE) != 0) { 1741193880Syongari pmstat &= ~PCIM_PSTAT_PMEENABLE; 1742193880Syongari pci_write_config(sc->alc_dev, 1743193880Syongari pmc + PCIR_POWER_STATUS, pmstat, 2); 1744193880Syongari } 1745193880Syongari } 1746193880Syongari /* Reset PHY. */ 1747193880Syongari alc_phy_reset(sc); 1748193880Syongari ifp = sc->alc_ifp; 1749193880Syongari if ((ifp->if_flags & IFF_UP) != 0) { 1750193880Syongari ifp->if_drv_flags &= ~IFF_DRV_RUNNING; 1751193880Syongari alc_init_locked(sc); 1752193880Syongari } 1753193880Syongari ALC_UNLOCK(sc); 1754193880Syongari 1755193880Syongari return (0); 1756193880Syongari} 1757193880Syongari 1758193880Syongaristatic int 1759193880Syongarialc_encap(struct alc_softc *sc, struct mbuf **m_head) 1760193880Syongari{ 1761193880Syongari struct alc_txdesc *txd, *txd_last; 1762193880Syongari struct tx_desc *desc; 1763193880Syongari struct mbuf *m; 1764193880Syongari struct ip *ip; 1765193880Syongari struct tcphdr *tcp; 1766193880Syongari bus_dma_segment_t txsegs[ALC_MAXTXSEGS]; 1767193880Syongari bus_dmamap_t map; 1768193880Syongari uint32_t cflags, hdrlen, ip_off, poff, vtag; 1769193880Syongari int error, idx, nsegs, prod; 1770193880Syongari 1771193880Syongari ALC_LOCK_ASSERT(sc); 1772193880Syongari 1773193880Syongari M_ASSERTPKTHDR((*m_head)); 1774193880Syongari 1775193880Syongari m = *m_head; 1776193880Syongari ip = NULL; 1777193880Syongari tcp = NULL; 1778193880Syongari ip_off = poff = 0; 1779193880Syongari if ((m->m_pkthdr.csum_flags & (ALC_CSUM_FEATURES | CSUM_TSO)) != 0) { 1780193880Syongari /* 1781193880Syongari * AR8131/AR8132 requires offset of TCP/UDP header in its 1782193880Syongari * Tx descriptor to perform Tx checksum offloading. TSO 1783193880Syongari * also requires TCP header offset and modification of 1784193880Syongari * IP/TCP header. This kind of operation takes many CPU 1785193880Syongari * cycles on FreeBSD so fast host CPU is required to get 1786193880Syongari * smooth TSO performance. 1787193880Syongari */ 1788193880Syongari struct ether_header *eh; 1789193880Syongari 1790193880Syongari if (M_WRITABLE(m) == 0) { 1791193880Syongari /* Get a writable copy. */ 1792193880Syongari m = m_dup(*m_head, M_DONTWAIT); 1793193880Syongari /* Release original mbufs. */ 1794193880Syongari m_freem(*m_head); 1795193880Syongari if (m == NULL) { 1796193880Syongari *m_head = NULL; 1797193880Syongari return (ENOBUFS); 1798193880Syongari } 1799193880Syongari *m_head = m; 1800193880Syongari } 1801193880Syongari 1802193880Syongari ip_off = sizeof(struct ether_header); 1803193880Syongari m = m_pullup(m, ip_off); 1804193880Syongari if (m == NULL) { 1805193880Syongari *m_head = NULL; 1806193880Syongari return (ENOBUFS); 1807193880Syongari } 1808193880Syongari eh = mtod(m, struct ether_header *); 1809193880Syongari /* 1810193880Syongari * Check if hardware VLAN insertion is off. 1811193880Syongari * Additional check for LLC/SNAP frame? 1812193880Syongari */ 1813193880Syongari if (eh->ether_type == htons(ETHERTYPE_VLAN)) { 1814193880Syongari ip_off = sizeof(struct ether_vlan_header); 1815193880Syongari m = m_pullup(m, ip_off); 1816193880Syongari if (m == NULL) { 1817193880Syongari *m_head = NULL; 1818193880Syongari return (ENOBUFS); 1819193880Syongari } 1820193880Syongari } 1821193880Syongari m = m_pullup(m, ip_off + sizeof(struct ip)); 1822193880Syongari if (m == NULL) { 1823193880Syongari *m_head = NULL; 1824193880Syongari return (ENOBUFS); 1825193880Syongari } 1826193880Syongari ip = (struct ip *)(mtod(m, char *) + ip_off); 1827193880Syongari poff = ip_off + (ip->ip_hl << 2); 1828193880Syongari if ((m->m_pkthdr.csum_flags & CSUM_TSO) != 0) { 1829193880Syongari m = m_pullup(m, poff + sizeof(struct tcphdr)); 1830193880Syongari if (m == NULL) { 1831193880Syongari *m_head = NULL; 1832193880Syongari return (ENOBUFS); 1833193880Syongari } 1834193880Syongari tcp = (struct tcphdr *)(mtod(m, char *) + poff); 1835193880Syongari m = m_pullup(m, poff + (tcp->th_off << 2)); 1836193880Syongari if (m == NULL) { 1837193880Syongari *m_head = NULL; 1838193880Syongari return (ENOBUFS); 1839193880Syongari } 1840193880Syongari /* 1841193880Syongari * Due to strict adherence of Microsoft NDIS 1842193880Syongari * Large Send specification, hardware expects 1843193880Syongari * a pseudo TCP checksum inserted by upper 1844193880Syongari * stack. Unfortunately the pseudo TCP 1845193880Syongari * checksum that NDIS refers to does not include 1846193880Syongari * TCP payload length so driver should recompute 1847193880Syongari * the pseudo checksum here. Hopefully this 1848193880Syongari * wouldn't be much burden on modern CPUs. 1849193880Syongari * 1850193880Syongari * Reset IP checksum and recompute TCP pseudo 1851193880Syongari * checksum as NDIS specification said. 1852193880Syongari */ 1853193880Syongari ip->ip_sum = 0; 1854193880Syongari tcp->th_sum = in_pseudo(ip->ip_src.s_addr, 1855193880Syongari ip->ip_dst.s_addr, htons(IPPROTO_TCP)); 1856193880Syongari } 1857193880Syongari *m_head = m; 1858193880Syongari } 1859193880Syongari 1860193880Syongari prod = sc->alc_cdata.alc_tx_prod; 1861193880Syongari txd = &sc->alc_cdata.alc_txdesc[prod]; 1862193880Syongari txd_last = txd; 1863193880Syongari map = txd->tx_dmamap; 1864193880Syongari 1865193880Syongari error = bus_dmamap_load_mbuf_sg(sc->alc_cdata.alc_tx_tag, map, 1866193880Syongari *m_head, txsegs, &nsegs, 0); 1867193880Syongari if (error == EFBIG) { 1868193880Syongari m = m_collapse(*m_head, M_DONTWAIT, ALC_MAXTXSEGS); 1869193880Syongari if (m == NULL) { 1870193880Syongari m_freem(*m_head); 1871193880Syongari *m_head = NULL; 1872193880Syongari return (ENOMEM); 1873193880Syongari } 1874193880Syongari *m_head = m; 1875193880Syongari error = bus_dmamap_load_mbuf_sg(sc->alc_cdata.alc_tx_tag, map, 1876193880Syongari *m_head, txsegs, &nsegs, 0); 1877193880Syongari if (error != 0) { 1878193880Syongari m_freem(*m_head); 1879193880Syongari *m_head = NULL; 1880193880Syongari return (error); 1881193880Syongari } 1882193880Syongari } else if (error != 0) 1883193880Syongari return (error); 1884193880Syongari if (nsegs == 0) { 1885193880Syongari m_freem(*m_head); 1886193880Syongari *m_head = NULL; 1887193880Syongari return (EIO); 1888193880Syongari } 1889193880Syongari 1890193880Syongari /* Check descriptor overrun. */ 1891193880Syongari if (sc->alc_cdata.alc_tx_cnt + nsegs >= ALC_TX_RING_CNT - 3) { 1892193880Syongari bus_dmamap_unload(sc->alc_cdata.alc_tx_tag, map); 1893193880Syongari return (ENOBUFS); 1894193880Syongari } 1895193880Syongari bus_dmamap_sync(sc->alc_cdata.alc_tx_tag, map, BUS_DMASYNC_PREWRITE); 1896193880Syongari 1897193880Syongari m = *m_head; 1898193880Syongari cflags = TD_ETHERNET; 1899193880Syongari vtag = 0; 1900193880Syongari desc = NULL; 1901193880Syongari idx = 0; 1902193880Syongari /* Configure VLAN hardware tag insertion. */ 1903193880Syongari if ((m->m_flags & M_VLANTAG) != 0) { 1904193880Syongari vtag = htons(m->m_pkthdr.ether_vtag); 1905193880Syongari vtag = (vtag << TD_VLAN_SHIFT) & TD_VLAN_MASK; 1906193880Syongari cflags |= TD_INS_VLAN_TAG; 1907193880Syongari } 1908193880Syongari /* Configure Tx checksum offload. */ 1909193880Syongari if ((m->m_pkthdr.csum_flags & ALC_CSUM_FEATURES) != 0) { 1910193880Syongari#ifdef ALC_USE_CUSTOM_CSUM 1911193880Syongari cflags |= TD_CUSTOM_CSUM; 1912193880Syongari /* Set checksum start offset. */ 1913193880Syongari cflags |= ((poff >> 1) << TD_PLOAD_OFFSET_SHIFT) & 1914193880Syongari TD_PLOAD_OFFSET_MASK; 1915193880Syongari /* Set checksum insertion position of TCP/UDP. */ 1916193880Syongari cflags |= (((poff + m->m_pkthdr.csum_data) >> 1) << 1917193880Syongari TD_CUSTOM_CSUM_OFFSET_SHIFT) & TD_CUSTOM_CSUM_OFFSET_MASK; 1918193880Syongari#else 1919193880Syongari if ((m->m_pkthdr.csum_flags & CSUM_IP) != 0) 1920193880Syongari cflags |= TD_IPCSUM; 1921193880Syongari if ((m->m_pkthdr.csum_flags & CSUM_TCP) != 0) 1922193880Syongari cflags |= TD_TCPCSUM; 1923193880Syongari if ((m->m_pkthdr.csum_flags & CSUM_UDP) != 0) 1924193880Syongari cflags |= TD_UDPCSUM; 1925193880Syongari /* Set TCP/UDP header offset. */ 1926193880Syongari cflags |= (poff << TD_L4HDR_OFFSET_SHIFT) & 1927193880Syongari TD_L4HDR_OFFSET_MASK; 1928193880Syongari#endif 1929193880Syongari } else if ((m->m_pkthdr.csum_flags & CSUM_TSO) != 0) { 1930193880Syongari /* Request TSO and set MSS. */ 1931193880Syongari cflags |= TD_TSO | TD_TSO_DESCV1; 1932193880Syongari cflags |= ((uint32_t)m->m_pkthdr.tso_segsz << TD_MSS_SHIFT) & 1933193880Syongari TD_MSS_MASK; 1934193880Syongari /* Set TCP header offset. */ 1935193880Syongari cflags |= (poff << TD_TCPHDR_OFFSET_SHIFT) & 1936193880Syongari TD_TCPHDR_OFFSET_MASK; 1937193880Syongari /* 1938193880Syongari * AR8131/AR8132 requires the first buffer should 1939193880Syongari * only hold IP/TCP header data. Payload should 1940193880Syongari * be handled in other descriptors. 1941193880Syongari */ 1942193880Syongari hdrlen = poff + (tcp->th_off << 2); 1943193880Syongari desc = &sc->alc_rdata.alc_tx_ring[prod]; 1944193880Syongari desc->len = htole32(TX_BYTES(hdrlen | vtag)); 1945193880Syongari desc->flags = htole32(cflags); 1946193880Syongari desc->addr = htole64(txsegs[0].ds_addr); 1947193880Syongari sc->alc_cdata.alc_tx_cnt++; 1948193880Syongari ALC_DESC_INC(prod, ALC_TX_RING_CNT); 1949193880Syongari if (m->m_len - hdrlen > 0) { 1950193880Syongari /* Handle remaining payload of the first fragment. */ 1951193880Syongari desc = &sc->alc_rdata.alc_tx_ring[prod]; 1952193880Syongari desc->len = htole32(TX_BYTES((m->m_len - hdrlen) | 1953193880Syongari vtag)); 1954193880Syongari desc->flags = htole32(cflags); 1955193880Syongari desc->addr = htole64(txsegs[0].ds_addr + hdrlen); 1956193880Syongari sc->alc_cdata.alc_tx_cnt++; 1957193880Syongari ALC_DESC_INC(prod, ALC_TX_RING_CNT); 1958193880Syongari } 1959193880Syongari /* Handle remaining fragments. */ 1960193880Syongari idx = 1; 1961193880Syongari } 1962193880Syongari for (; idx < nsegs; idx++) { 1963193880Syongari desc = &sc->alc_rdata.alc_tx_ring[prod]; 1964193880Syongari desc->len = htole32(TX_BYTES(txsegs[idx].ds_len) | vtag); 1965193880Syongari desc->flags = htole32(cflags); 1966193880Syongari desc->addr = htole64(txsegs[idx].ds_addr); 1967193880Syongari sc->alc_cdata.alc_tx_cnt++; 1968193880Syongari ALC_DESC_INC(prod, ALC_TX_RING_CNT); 1969193880Syongari } 1970193880Syongari /* Update producer index. */ 1971193880Syongari sc->alc_cdata.alc_tx_prod = prod; 1972193880Syongari 1973193880Syongari /* Finally set EOP on the last descriptor. */ 1974193880Syongari prod = (prod + ALC_TX_RING_CNT - 1) % ALC_TX_RING_CNT; 1975193880Syongari desc = &sc->alc_rdata.alc_tx_ring[prod]; 1976193880Syongari desc->flags |= htole32(TD_EOP); 1977193880Syongari 1978193880Syongari /* Swap dmamap of the first and the last. */ 1979193880Syongari txd = &sc->alc_cdata.alc_txdesc[prod]; 1980193880Syongari map = txd_last->tx_dmamap; 1981193880Syongari txd_last->tx_dmamap = txd->tx_dmamap; 1982193880Syongari txd->tx_dmamap = map; 1983193880Syongari txd->tx_m = m; 1984193880Syongari 1985193880Syongari return (0); 1986193880Syongari} 1987193880Syongari 1988193880Syongaristatic void 1989193880Syongarialc_tx_task(void *arg, int pending) 1990193880Syongari{ 1991193880Syongari struct ifnet *ifp; 1992193880Syongari 1993193880Syongari ifp = (struct ifnet *)arg; 1994193880Syongari alc_start(ifp); 1995193880Syongari} 1996193880Syongari 1997193880Syongaristatic void 1998193880Syongarialc_start(struct ifnet *ifp) 1999193880Syongari{ 2000193880Syongari struct alc_softc *sc; 2001193880Syongari struct mbuf *m_head; 2002193880Syongari int enq; 2003193880Syongari 2004193880Syongari sc = ifp->if_softc; 2005193880Syongari 2006193880Syongari ALC_LOCK(sc); 2007193880Syongari 2008193880Syongari /* Reclaim transmitted frames. */ 2009193880Syongari if (sc->alc_cdata.alc_tx_cnt >= ALC_TX_DESC_HIWAT) 2010193880Syongari alc_txeof(sc); 2011193880Syongari 2012193880Syongari if ((ifp->if_drv_flags & (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)) != 2013193880Syongari IFF_DRV_RUNNING || (sc->alc_flags & ALC_FLAG_LINK) == 0) { 2014193880Syongari ALC_UNLOCK(sc); 2015193880Syongari return; 2016193880Syongari } 2017193880Syongari 2018193880Syongari for (enq = 0; !IFQ_DRV_IS_EMPTY(&ifp->if_snd); ) { 2019193880Syongari IFQ_DRV_DEQUEUE(&ifp->if_snd, m_head); 2020193880Syongari if (m_head == NULL) 2021193880Syongari break; 2022193880Syongari /* 2023193880Syongari * Pack the data into the transmit ring. If we 2024193880Syongari * don't have room, set the OACTIVE flag and wait 2025193880Syongari * for the NIC to drain the ring. 2026193880Syongari */ 2027193880Syongari if (alc_encap(sc, &m_head)) { 2028193880Syongari if (m_head == NULL) 2029193880Syongari break; 2030193880Syongari IFQ_DRV_PREPEND(&ifp->if_snd, m_head); 2031193880Syongari ifp->if_drv_flags |= IFF_DRV_OACTIVE; 2032193880Syongari break; 2033193880Syongari } 2034193880Syongari 2035193880Syongari enq++; 2036193880Syongari /* 2037193880Syongari * If there's a BPF listener, bounce a copy of this frame 2038193880Syongari * to him. 2039193880Syongari */ 2040193880Syongari ETHER_BPF_MTAP(ifp, m_head); 2041193880Syongari } 2042193880Syongari 2043193880Syongari if (enq > 0) { 2044193880Syongari /* Sync descriptors. */ 2045193880Syongari bus_dmamap_sync(sc->alc_cdata.alc_tx_ring_tag, 2046193880Syongari sc->alc_cdata.alc_tx_ring_map, BUS_DMASYNC_PREWRITE); 2047193880Syongari /* Kick. Assume we're using normal Tx priority queue. */ 2048193880Syongari CSR_WRITE_4(sc, ALC_MBOX_TD_PROD_IDX, 2049193880Syongari (sc->alc_cdata.alc_tx_prod << 2050193880Syongari MBOX_TD_PROD_LO_IDX_SHIFT) & 2051193880Syongari MBOX_TD_PROD_LO_IDX_MASK); 2052193880Syongari /* Set a timeout in case the chip goes out to lunch. */ 2053193880Syongari sc->alc_watchdog_timer = ALC_TX_TIMEOUT; 2054193880Syongari } 2055193880Syongari 2056193880Syongari ALC_UNLOCK(sc); 2057193880Syongari} 2058193880Syongari 2059193880Syongaristatic void 2060193880Syongarialc_watchdog(struct alc_softc *sc) 2061193880Syongari{ 2062193880Syongari struct ifnet *ifp; 2063193880Syongari 2064193880Syongari ALC_LOCK_ASSERT(sc); 2065193880Syongari 2066193880Syongari if (sc->alc_watchdog_timer == 0 || --sc->alc_watchdog_timer) 2067193880Syongari return; 2068193880Syongari 2069193880Syongari ifp = sc->alc_ifp; 2070193880Syongari if ((sc->alc_flags & ALC_FLAG_LINK) == 0) { 2071193880Syongari if_printf(sc->alc_ifp, "watchdog timeout (lost link)\n"); 2072193880Syongari ifp->if_oerrors++; 2073193880Syongari ifp->if_drv_flags &= ~IFF_DRV_RUNNING; 2074193880Syongari alc_init_locked(sc); 2075193880Syongari return; 2076193880Syongari } 2077193880Syongari if_printf(sc->alc_ifp, "watchdog timeout -- resetting\n"); 2078193880Syongari ifp->if_oerrors++; 2079193880Syongari ifp->if_drv_flags &= ~IFF_DRV_RUNNING; 2080193880Syongari alc_init_locked(sc); 2081193880Syongari if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) 2082193880Syongari taskqueue_enqueue(sc->alc_tq, &sc->alc_tx_task); 2083193880Syongari} 2084193880Syongari 2085193880Syongaristatic int 2086193880Syongarialc_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) 2087193880Syongari{ 2088193880Syongari struct alc_softc *sc; 2089193880Syongari struct ifreq *ifr; 2090193880Syongari struct mii_data *mii; 2091193880Syongari int error, mask; 2092193880Syongari 2093193880Syongari sc = ifp->if_softc; 2094193880Syongari ifr = (struct ifreq *)data; 2095193880Syongari error = 0; 2096193880Syongari switch (cmd) { 2097193880Syongari case SIOCSIFMTU: 2098193880Syongari if (ifr->ifr_mtu < ETHERMIN || ifr->ifr_mtu > ALC_JUMBO_MTU || 2099193880Syongari ((sc->alc_flags & ALC_FLAG_JUMBO) == 0 && 2100193880Syongari ifr->ifr_mtu > ETHERMTU)) 2101193880Syongari error = EINVAL; 2102193880Syongari else if (ifp->if_mtu != ifr->ifr_mtu) { 2103193880Syongari ALC_LOCK(sc); 2104193880Syongari ifp->if_mtu = ifr->ifr_mtu; 2105193880Syongari /* AR8131/AR8132 has 13 bits MSS field. */ 2106193880Syongari if (ifp->if_mtu > ALC_TSO_MTU && 2107193880Syongari (ifp->if_capenable & IFCAP_TSO4) != 0) { 2108193880Syongari ifp->if_capenable &= ~IFCAP_TSO4; 2109193880Syongari ifp->if_hwassist &= ~CSUM_TSO; 2110193880Syongari } 2111193880Syongari ALC_UNLOCK(sc); 2112193880Syongari } 2113193880Syongari break; 2114193880Syongari case SIOCSIFFLAGS: 2115193880Syongari ALC_LOCK(sc); 2116193880Syongari if ((ifp->if_flags & IFF_UP) != 0) { 2117193880Syongari if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0 && 2118193880Syongari ((ifp->if_flags ^ sc->alc_if_flags) & 2119193880Syongari (IFF_PROMISC | IFF_ALLMULTI)) != 0) 2120193880Syongari alc_rxfilter(sc); 2121193880Syongari else if ((sc->alc_flags & ALC_FLAG_DETACH) == 0) 2122193880Syongari alc_init_locked(sc); 2123193880Syongari } else if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0) 2124193880Syongari alc_stop(sc); 2125193880Syongari sc->alc_if_flags = ifp->if_flags; 2126193880Syongari ALC_UNLOCK(sc); 2127193880Syongari break; 2128193880Syongari case SIOCADDMULTI: 2129193880Syongari case SIOCDELMULTI: 2130193880Syongari ALC_LOCK(sc); 2131193880Syongari if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0) 2132193880Syongari alc_rxfilter(sc); 2133193880Syongari ALC_UNLOCK(sc); 2134193880Syongari break; 2135193880Syongari case SIOCSIFMEDIA: 2136193880Syongari case SIOCGIFMEDIA: 2137193880Syongari mii = device_get_softc(sc->alc_miibus); 2138193880Syongari error = ifmedia_ioctl(ifp, ifr, &mii->mii_media, cmd); 2139193880Syongari break; 2140193880Syongari case SIOCSIFCAP: 2141193880Syongari ALC_LOCK(sc); 2142193880Syongari mask = ifr->ifr_reqcap ^ ifp->if_capenable; 2143193880Syongari if ((mask & IFCAP_TXCSUM) != 0 && 2144193880Syongari (ifp->if_capabilities & IFCAP_TXCSUM) != 0) { 2145193880Syongari ifp->if_capenable ^= IFCAP_TXCSUM; 2146193880Syongari if ((ifp->if_capenable & IFCAP_TXCSUM) != 0) 2147193880Syongari ifp->if_hwassist |= ALC_CSUM_FEATURES; 2148193880Syongari else 2149193880Syongari ifp->if_hwassist &= ~ALC_CSUM_FEATURES; 2150193880Syongari } 2151193880Syongari if ((mask & IFCAP_TSO4) != 0 && 2152193880Syongari (ifp->if_capabilities & IFCAP_TSO4) != 0) { 2153193880Syongari ifp->if_capenable ^= IFCAP_TSO4; 2154193880Syongari if ((ifp->if_capenable & IFCAP_TSO4) != 0) { 2155193880Syongari /* AR8131/AR8132 has 13 bits MSS field. */ 2156193880Syongari if (ifp->if_mtu > ALC_TSO_MTU) { 2157193880Syongari ifp->if_capenable &= ~IFCAP_TSO4; 2158193880Syongari ifp->if_hwassist &= ~CSUM_TSO; 2159193880Syongari } else 2160193880Syongari ifp->if_hwassist |= CSUM_TSO; 2161193880Syongari } else 2162193880Syongari ifp->if_hwassist &= ~CSUM_TSO; 2163193880Syongari } 2164193880Syongari if ((mask & IFCAP_WOL_MCAST) != 0 && 2165193880Syongari (ifp->if_capabilities & IFCAP_WOL_MCAST) != 0) 2166193880Syongari ifp->if_capenable ^= IFCAP_WOL_MCAST; 2167193880Syongari if ((mask & IFCAP_WOL_MAGIC) != 0 && 2168193880Syongari (ifp->if_capabilities & IFCAP_WOL_MAGIC) != 0) 2169193880Syongari ifp->if_capenable ^= IFCAP_WOL_MAGIC; 2170193880Syongari if ((mask & IFCAP_VLAN_HWTAGGING) != 0 && 2171193880Syongari (ifp->if_capabilities & IFCAP_VLAN_HWTAGGING) != 0) { 2172193880Syongari ifp->if_capenable ^= IFCAP_VLAN_HWTAGGING; 2173193880Syongari alc_rxvlan(sc); 2174193880Syongari } 2175193880Syongari if ((mask & IFCAP_VLAN_HWCSUM) != 0 && 2176193880Syongari (ifp->if_capabilities & IFCAP_VLAN_HWCSUM) != 0) 2177193880Syongari ifp->if_capenable ^= IFCAP_VLAN_HWCSUM; 2178193880Syongari if ((mask & IFCAP_VLAN_HWTSO) != 0 && 2179193880Syongari (ifp->if_capabilities & IFCAP_VLAN_HWTSO) != 0) 2180193880Syongari ifp->if_capenable ^= IFCAP_VLAN_HWTSO; 2181193880Syongari /* 2182193880Syongari * VLAN hardware tagging is required to do checksum 2183193880Syongari * offload or TSO on VLAN interface. Checksum offload 2184193880Syongari * on VLAN interface also requires hardware checksum 2185193880Syongari * offload of parent interface. 2186193880Syongari */ 2187193880Syongari if ((ifp->if_capenable & IFCAP_TXCSUM) == 0) 2188193880Syongari ifp->if_capenable &= ~IFCAP_VLAN_HWCSUM; 2189193880Syongari if ((ifp->if_capenable & IFCAP_VLAN_HWTAGGING) == 0) 2190193880Syongari ifp->if_capenable &= 2191193880Syongari ~(IFCAP_VLAN_HWTSO | IFCAP_VLAN_HWCSUM); 2192193880Syongari ALC_UNLOCK(sc); 2193193880Syongari VLAN_CAPABILITIES(ifp); 2194193880Syongari break; 2195193880Syongari default: 2196193880Syongari error = ether_ioctl(ifp, cmd, data); 2197193880Syongari break; 2198193880Syongari } 2199193880Syongari 2200193880Syongari return (error); 2201193880Syongari} 2202193880Syongari 2203193880Syongaristatic void 2204193880Syongarialc_mac_config(struct alc_softc *sc) 2205193880Syongari{ 2206193880Syongari struct mii_data *mii; 2207193880Syongari uint32_t reg; 2208193880Syongari 2209193880Syongari ALC_LOCK_ASSERT(sc); 2210193880Syongari 2211193880Syongari mii = device_get_softc(sc->alc_miibus); 2212193880Syongari reg = CSR_READ_4(sc, ALC_MAC_CFG); 2213193880Syongari reg &= ~(MAC_CFG_FULL_DUPLEX | MAC_CFG_TX_FC | MAC_CFG_RX_FC | 2214193880Syongari MAC_CFG_SPEED_MASK); 2215193880Syongari /* Reprogram MAC with resolved speed/duplex. */ 2216193880Syongari switch (IFM_SUBTYPE(mii->mii_media_active)) { 2217193880Syongari case IFM_10_T: 2218193880Syongari case IFM_100_TX: 2219193880Syongari reg |= MAC_CFG_SPEED_10_100; 2220193880Syongari break; 2221193880Syongari case IFM_1000_T: 2222193880Syongari reg |= MAC_CFG_SPEED_1000; 2223193880Syongari break; 2224193880Syongari } 2225193880Syongari if ((IFM_OPTIONS(mii->mii_media_active) & IFM_FDX) != 0) { 2226193880Syongari reg |= MAC_CFG_FULL_DUPLEX; 2227193880Syongari#ifdef notyet 2228193880Syongari if ((IFM_OPTIONS(mii->mii_media_active) & IFM_ETH_TXPAUSE) != 0) 2229193880Syongari reg |= MAC_CFG_TX_FC; 2230193880Syongari if ((IFM_OPTIONS(mii->mii_media_active) & IFM_ETH_RXPAUSE) != 0) 2231193880Syongari reg |= MAC_CFG_RX_FC; 2232193880Syongari#endif 2233193880Syongari } 2234193880Syongari CSR_WRITE_4(sc, ALC_MAC_CFG, reg); 2235193880Syongari} 2236193880Syongari 2237193880Syongaristatic void 2238193880Syongarialc_stats_clear(struct alc_softc *sc) 2239193880Syongari{ 2240193880Syongari struct smb sb, *smb; 2241193880Syongari uint32_t *reg; 2242193880Syongari int i; 2243193880Syongari 2244193880Syongari if ((sc->alc_flags & ALC_FLAG_SMB_BUG) == 0) { 2245193880Syongari bus_dmamap_sync(sc->alc_cdata.alc_smb_tag, 2246193880Syongari sc->alc_cdata.alc_smb_map, 2247193880Syongari BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); 2248193880Syongari smb = sc->alc_rdata.alc_smb; 2249193880Syongari /* Update done, clear. */ 2250193880Syongari smb->updated = 0; 2251193880Syongari bus_dmamap_sync(sc->alc_cdata.alc_smb_tag, 2252193880Syongari sc->alc_cdata.alc_smb_map, 2253193880Syongari BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 2254193880Syongari } else { 2255193880Syongari for (reg = &sb.rx_frames, i = 0; reg <= &sb.rx_pkts_filtered; 2256193880Syongari reg++) { 2257193880Syongari CSR_READ_4(sc, ALC_RX_MIB_BASE + i); 2258193880Syongari i += sizeof(uint32_t); 2259193880Syongari } 2260193880Syongari /* Read Tx statistics. */ 2261193880Syongari for (reg = &sb.tx_frames, i = 0; reg <= &sb.tx_mcast_bytes; 2262193880Syongari reg++) { 2263193880Syongari CSR_READ_4(sc, ALC_TX_MIB_BASE + i); 2264193880Syongari i += sizeof(uint32_t); 2265193880Syongari } 2266193880Syongari } 2267193880Syongari} 2268193880Syongari 2269193880Syongaristatic void 2270193880Syongarialc_stats_update(struct alc_softc *sc) 2271193880Syongari{ 2272193880Syongari struct alc_hw_stats *stat; 2273193880Syongari struct smb sb, *smb; 2274193880Syongari struct ifnet *ifp; 2275193880Syongari uint32_t *reg; 2276193880Syongari int i; 2277193880Syongari 2278193880Syongari ALC_LOCK_ASSERT(sc); 2279193880Syongari 2280193880Syongari ifp = sc->alc_ifp; 2281193880Syongari stat = &sc->alc_stats; 2282193880Syongari if ((sc->alc_flags & ALC_FLAG_SMB_BUG) == 0) { 2283193880Syongari bus_dmamap_sync(sc->alc_cdata.alc_smb_tag, 2284193880Syongari sc->alc_cdata.alc_smb_map, 2285193880Syongari BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); 2286193880Syongari smb = sc->alc_rdata.alc_smb; 2287193880Syongari if (smb->updated == 0) 2288193880Syongari return; 2289193880Syongari } else { 2290193880Syongari smb = &sb; 2291193880Syongari /* Read Rx statistics. */ 2292193880Syongari for (reg = &sb.rx_frames, i = 0; reg <= &sb.rx_pkts_filtered; 2293193880Syongari reg++) { 2294193880Syongari *reg = CSR_READ_4(sc, ALC_RX_MIB_BASE + i); 2295193880Syongari i += sizeof(uint32_t); 2296193880Syongari } 2297193880Syongari /* Read Tx statistics. */ 2298193880Syongari for (reg = &sb.tx_frames, i = 0; reg <= &sb.tx_mcast_bytes; 2299193880Syongari reg++) { 2300193880Syongari *reg = CSR_READ_4(sc, ALC_TX_MIB_BASE + i); 2301193880Syongari i += sizeof(uint32_t); 2302193880Syongari } 2303193880Syongari } 2304193880Syongari 2305193880Syongari /* Rx stats. */ 2306193880Syongari stat->rx_frames += smb->rx_frames; 2307193880Syongari stat->rx_bcast_frames += smb->rx_bcast_frames; 2308193880Syongari stat->rx_mcast_frames += smb->rx_mcast_frames; 2309193880Syongari stat->rx_pause_frames += smb->rx_pause_frames; 2310193880Syongari stat->rx_control_frames += smb->rx_control_frames; 2311193880Syongari stat->rx_crcerrs += smb->rx_crcerrs; 2312193880Syongari stat->rx_lenerrs += smb->rx_lenerrs; 2313193880Syongari stat->rx_bytes += smb->rx_bytes; 2314193880Syongari stat->rx_runts += smb->rx_runts; 2315193880Syongari stat->rx_fragments += smb->rx_fragments; 2316193880Syongari stat->rx_pkts_64 += smb->rx_pkts_64; 2317193880Syongari stat->rx_pkts_65_127 += smb->rx_pkts_65_127; 2318193880Syongari stat->rx_pkts_128_255 += smb->rx_pkts_128_255; 2319193880Syongari stat->rx_pkts_256_511 += smb->rx_pkts_256_511; 2320193880Syongari stat->rx_pkts_512_1023 += smb->rx_pkts_512_1023; 2321193880Syongari stat->rx_pkts_1024_1518 += smb->rx_pkts_1024_1518; 2322193880Syongari stat->rx_pkts_1519_max += smb->rx_pkts_1519_max; 2323193880Syongari stat->rx_pkts_truncated += smb->rx_pkts_truncated; 2324193880Syongari stat->rx_fifo_oflows += smb->rx_fifo_oflows; 2325193880Syongari stat->rx_rrs_errs += smb->rx_rrs_errs; 2326193880Syongari stat->rx_alignerrs += smb->rx_alignerrs; 2327193880Syongari stat->rx_bcast_bytes += smb->rx_bcast_bytes; 2328193880Syongari stat->rx_mcast_bytes += smb->rx_mcast_bytes; 2329193880Syongari stat->rx_pkts_filtered += smb->rx_pkts_filtered; 2330193880Syongari 2331193880Syongari /* Tx stats. */ 2332193880Syongari stat->tx_frames += smb->tx_frames; 2333193880Syongari stat->tx_bcast_frames += smb->tx_bcast_frames; 2334193880Syongari stat->tx_mcast_frames += smb->tx_mcast_frames; 2335193880Syongari stat->tx_pause_frames += smb->tx_pause_frames; 2336193880Syongari stat->tx_excess_defer += smb->tx_excess_defer; 2337193880Syongari stat->tx_control_frames += smb->tx_control_frames; 2338193880Syongari stat->tx_deferred += smb->tx_deferred; 2339193880Syongari stat->tx_bytes += smb->tx_bytes; 2340193880Syongari stat->tx_pkts_64 += smb->tx_pkts_64; 2341193880Syongari stat->tx_pkts_65_127 += smb->tx_pkts_65_127; 2342193880Syongari stat->tx_pkts_128_255 += smb->tx_pkts_128_255; 2343193880Syongari stat->tx_pkts_256_511 += smb->tx_pkts_256_511; 2344193880Syongari stat->tx_pkts_512_1023 += smb->tx_pkts_512_1023; 2345193880Syongari stat->tx_pkts_1024_1518 += smb->tx_pkts_1024_1518; 2346193880Syongari stat->tx_pkts_1519_max += smb->tx_pkts_1519_max; 2347193880Syongari stat->tx_single_colls += smb->tx_single_colls; 2348193880Syongari stat->tx_multi_colls += smb->tx_multi_colls; 2349193880Syongari stat->tx_late_colls += smb->tx_late_colls; 2350193880Syongari stat->tx_excess_colls += smb->tx_excess_colls; 2351193880Syongari stat->tx_abort += smb->tx_abort; 2352193880Syongari stat->tx_underrun += smb->tx_underrun; 2353193880Syongari stat->tx_desc_underrun += smb->tx_desc_underrun; 2354193880Syongari stat->tx_lenerrs += smb->tx_lenerrs; 2355193880Syongari stat->tx_pkts_truncated += smb->tx_pkts_truncated; 2356193880Syongari stat->tx_bcast_bytes += smb->tx_bcast_bytes; 2357193880Syongari stat->tx_mcast_bytes += smb->tx_mcast_bytes; 2358193880Syongari 2359193880Syongari /* Update counters in ifnet. */ 2360193880Syongari ifp->if_opackets += smb->tx_frames; 2361193880Syongari 2362193880Syongari ifp->if_collisions += smb->tx_single_colls + 2363193880Syongari smb->tx_multi_colls * 2 + smb->tx_late_colls + 2364193880Syongari smb->tx_abort * HDPX_CFG_RETRY_DEFAULT; 2365193880Syongari 2366193880Syongari /* 2367193880Syongari * XXX 2368193880Syongari * tx_pkts_truncated counter looks suspicious. It constantly 2369193880Syongari * increments with no sign of Tx errors. This may indicate 2370193880Syongari * the counter name is not correct one so I've removed the 2371193880Syongari * counter in output errors. 2372193880Syongari */ 2373193880Syongari ifp->if_oerrors += smb->tx_abort + smb->tx_late_colls + 2374193880Syongari smb->tx_underrun; 2375193880Syongari 2376193880Syongari ifp->if_ipackets += smb->rx_frames; 2377193880Syongari 2378193880Syongari ifp->if_ierrors += smb->rx_crcerrs + smb->rx_lenerrs + 2379193880Syongari smb->rx_runts + smb->rx_pkts_truncated + 2380193880Syongari smb->rx_fifo_oflows + smb->rx_rrs_errs + 2381193880Syongari smb->rx_alignerrs; 2382193880Syongari 2383193880Syongari if ((sc->alc_flags & ALC_FLAG_SMB_BUG) == 0) { 2384193880Syongari /* Update done, clear. */ 2385193880Syongari smb->updated = 0; 2386193880Syongari bus_dmamap_sync(sc->alc_cdata.alc_smb_tag, 2387193880Syongari sc->alc_cdata.alc_smb_map, 2388193880Syongari BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 2389193880Syongari } 2390193880Syongari} 2391193880Syongari 2392193880Syongaristatic int 2393193880Syongarialc_intr(void *arg) 2394193880Syongari{ 2395193880Syongari struct alc_softc *sc; 2396193880Syongari uint32_t status; 2397193880Syongari 2398193880Syongari sc = (struct alc_softc *)arg; 2399193880Syongari 2400193880Syongari status = CSR_READ_4(sc, ALC_INTR_STATUS); 2401193880Syongari if ((status & ALC_INTRS) == 0) 2402193880Syongari return (FILTER_STRAY); 2403193880Syongari /* Disable interrupts. */ 2404193880Syongari CSR_WRITE_4(sc, ALC_INTR_STATUS, INTR_DIS_INT); 2405193880Syongari taskqueue_enqueue(sc->alc_tq, &sc->alc_int_task); 2406193880Syongari 2407193880Syongari return (FILTER_HANDLED); 2408193880Syongari} 2409193880Syongari 2410193880Syongaristatic void 2411193880Syongarialc_int_task(void *arg, int pending) 2412193880Syongari{ 2413193880Syongari struct alc_softc *sc; 2414193880Syongari struct ifnet *ifp; 2415193880Syongari uint32_t status; 2416193880Syongari int more; 2417193880Syongari 2418193880Syongari sc = (struct alc_softc *)arg; 2419193880Syongari ifp = sc->alc_ifp; 2420193880Syongari 2421193880Syongari status = CSR_READ_4(sc, ALC_INTR_STATUS); 2422193880Syongari more = atomic_readandclear_int(&sc->alc_morework); 2423193880Syongari if (more != 0) 2424193880Syongari status |= INTR_RX_PKT; 2425193880Syongari if ((status & ALC_INTRS) == 0) 2426193880Syongari goto done; 2427193880Syongari 2428193880Syongari /* Acknowledge interrupts but still disable interrupts. */ 2429193880Syongari CSR_WRITE_4(sc, ALC_INTR_STATUS, status | INTR_DIS_INT); 2430193880Syongari 2431193880Syongari more = 0; 2432193880Syongari if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0) { 2433193880Syongari if ((status & INTR_RX_PKT) != 0) { 2434193880Syongari more = alc_rxintr(sc, sc->alc_process_limit); 2435193880Syongari if (more == EAGAIN) 2436193880Syongari atomic_set_int(&sc->alc_morework, 1); 2437193880Syongari else if (more == EIO) { 2438193880Syongari ALC_LOCK(sc); 2439193880Syongari ifp->if_drv_flags &= ~IFF_DRV_RUNNING; 2440193880Syongari alc_init_locked(sc); 2441193880Syongari ALC_UNLOCK(sc); 2442193880Syongari return; 2443193880Syongari } 2444193880Syongari } 2445193880Syongari if ((status & (INTR_DMA_RD_TO_RST | INTR_DMA_WR_TO_RST | 2446193880Syongari INTR_TXQ_TO_RST)) != 0) { 2447193880Syongari if ((status & INTR_DMA_RD_TO_RST) != 0) 2448193880Syongari device_printf(sc->alc_dev, 2449193880Syongari "DMA read error! -- resetting\n"); 2450193880Syongari if ((status & INTR_DMA_WR_TO_RST) != 0) 2451193880Syongari device_printf(sc->alc_dev, 2452193880Syongari "DMA write error! -- resetting\n"); 2453193880Syongari if ((status & INTR_TXQ_TO_RST) != 0) 2454193880Syongari device_printf(sc->alc_dev, 2455193880Syongari "TxQ reset! -- resetting\n"); 2456193880Syongari ALC_LOCK(sc); 2457193880Syongari ifp->if_drv_flags &= ~IFF_DRV_RUNNING; 2458193880Syongari alc_init_locked(sc); 2459193880Syongari ALC_UNLOCK(sc); 2460193880Syongari return; 2461193880Syongari } 2462193880Syongari if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0 && 2463193880Syongari !IFQ_DRV_IS_EMPTY(&ifp->if_snd)) 2464193880Syongari taskqueue_enqueue(sc->alc_tq, &sc->alc_tx_task); 2465193880Syongari } 2466193880Syongari 2467193880Syongari if (more == EAGAIN || 2468193880Syongari (CSR_READ_4(sc, ALC_INTR_STATUS) & ALC_INTRS) != 0) { 2469193880Syongari taskqueue_enqueue(sc->alc_tq, &sc->alc_int_task); 2470193880Syongari return; 2471193880Syongari } 2472193880Syongari 2473193880Syongaridone: 2474193880Syongari if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0) { 2475193880Syongari /* Re-enable interrupts if we're running. */ 2476193880Syongari CSR_WRITE_4(sc, ALC_INTR_STATUS, 0x7FFFFFFF); 2477193880Syongari } 2478193880Syongari} 2479193880Syongari 2480193880Syongaristatic void 2481193880Syongarialc_txeof(struct alc_softc *sc) 2482193880Syongari{ 2483193880Syongari struct ifnet *ifp; 2484193880Syongari struct alc_txdesc *txd; 2485193880Syongari uint32_t cons, prod; 2486193880Syongari int prog; 2487193880Syongari 2488193880Syongari ALC_LOCK_ASSERT(sc); 2489193880Syongari 2490193880Syongari ifp = sc->alc_ifp; 2491193880Syongari 2492193880Syongari if (sc->alc_cdata.alc_tx_cnt == 0) 2493193880Syongari return; 2494193880Syongari bus_dmamap_sync(sc->alc_cdata.alc_tx_ring_tag, 2495193880Syongari sc->alc_cdata.alc_tx_ring_map, BUS_DMASYNC_POSTWRITE); 2496193880Syongari if ((sc->alc_flags & ALC_FLAG_CMB_BUG) == 0) { 2497193880Syongari bus_dmamap_sync(sc->alc_cdata.alc_cmb_tag, 2498193880Syongari sc->alc_cdata.alc_cmb_map, BUS_DMASYNC_POSTREAD); 2499193880Syongari prod = sc->alc_rdata.alc_cmb->cons; 2500193880Syongari } else 2501193880Syongari prod = CSR_READ_4(sc, ALC_MBOX_TD_CONS_IDX); 2502193880Syongari /* Assume we're using normal Tx priority queue. */ 2503193880Syongari prod = (prod & MBOX_TD_CONS_LO_IDX_MASK) >> 2504193880Syongari MBOX_TD_CONS_LO_IDX_SHIFT; 2505193880Syongari cons = sc->alc_cdata.alc_tx_cons; 2506193880Syongari /* 2507193880Syongari * Go through our Tx list and free mbufs for those 2508193880Syongari * frames which have been transmitted. 2509193880Syongari */ 2510193880Syongari for (prog = 0; cons != prod; prog++, 2511193880Syongari ALC_DESC_INC(cons, ALC_TX_RING_CNT)) { 2512193880Syongari if (sc->alc_cdata.alc_tx_cnt <= 0) 2513193880Syongari break; 2514193880Syongari prog++; 2515193880Syongari ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 2516193880Syongari sc->alc_cdata.alc_tx_cnt--; 2517193880Syongari txd = &sc->alc_cdata.alc_txdesc[cons]; 2518193880Syongari if (txd->tx_m != NULL) { 2519193880Syongari /* Reclaim transmitted mbufs. */ 2520193880Syongari bus_dmamap_sync(sc->alc_cdata.alc_tx_tag, 2521193880Syongari txd->tx_dmamap, BUS_DMASYNC_POSTWRITE); 2522193880Syongari bus_dmamap_unload(sc->alc_cdata.alc_tx_tag, 2523193880Syongari txd->tx_dmamap); 2524193880Syongari m_freem(txd->tx_m); 2525193880Syongari txd->tx_m = NULL; 2526193880Syongari } 2527193880Syongari } 2528193880Syongari 2529193880Syongari if ((sc->alc_flags & ALC_FLAG_CMB_BUG) == 0) 2530193880Syongari bus_dmamap_sync(sc->alc_cdata.alc_cmb_tag, 2531193880Syongari sc->alc_cdata.alc_cmb_map, BUS_DMASYNC_PREREAD); 2532193880Syongari sc->alc_cdata.alc_tx_cons = cons; 2533193880Syongari /* 2534193880Syongari * Unarm watchdog timer only when there is no pending 2535193880Syongari * frames in Tx queue. 2536193880Syongari */ 2537193880Syongari if (sc->alc_cdata.alc_tx_cnt == 0) 2538193880Syongari sc->alc_watchdog_timer = 0; 2539193880Syongari} 2540193880Syongari 2541193880Syongaristatic int 2542193880Syongarialc_newbuf(struct alc_softc *sc, struct alc_rxdesc *rxd) 2543193880Syongari{ 2544193880Syongari struct mbuf *m; 2545193880Syongari bus_dma_segment_t segs[1]; 2546193880Syongari bus_dmamap_t map; 2547193880Syongari int nsegs; 2548193880Syongari 2549193880Syongari m = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR); 2550193880Syongari if (m == NULL) 2551193880Syongari return (ENOBUFS); 2552193880Syongari m->m_len = m->m_pkthdr.len = RX_BUF_SIZE_MAX; 2553193880Syongari#ifndef __NO_STRICT_ALIGNMENT 2554193880Syongari m_adj(m, sizeof(uint64_t)); 2555193880Syongari#endif 2556193880Syongari 2557193880Syongari if (bus_dmamap_load_mbuf_sg(sc->alc_cdata.alc_rx_tag, 2558193880Syongari sc->alc_cdata.alc_rx_sparemap, m, segs, &nsegs, 0) != 0) { 2559193880Syongari m_freem(m); 2560193880Syongari return (ENOBUFS); 2561193880Syongari } 2562193880Syongari KASSERT(nsegs == 1, ("%s: %d segments returned!", __func__, nsegs)); 2563193880Syongari 2564193880Syongari if (rxd->rx_m != NULL) { 2565193880Syongari bus_dmamap_sync(sc->alc_cdata.alc_rx_tag, rxd->rx_dmamap, 2566193880Syongari BUS_DMASYNC_POSTREAD); 2567193880Syongari bus_dmamap_unload(sc->alc_cdata.alc_rx_tag, rxd->rx_dmamap); 2568193880Syongari } 2569193880Syongari map = rxd->rx_dmamap; 2570193880Syongari rxd->rx_dmamap = sc->alc_cdata.alc_rx_sparemap; 2571193880Syongari sc->alc_cdata.alc_rx_sparemap = map; 2572193880Syongari bus_dmamap_sync(sc->alc_cdata.alc_rx_tag, rxd->rx_dmamap, 2573193880Syongari BUS_DMASYNC_PREREAD); 2574193880Syongari rxd->rx_m = m; 2575193880Syongari rxd->rx_desc->addr = htole64(segs[0].ds_addr); 2576193880Syongari return (0); 2577193880Syongari} 2578193880Syongari 2579193880Syongaristatic int 2580193880Syongarialc_rxintr(struct alc_softc *sc, int count) 2581193880Syongari{ 2582193880Syongari struct ifnet *ifp; 2583193880Syongari struct rx_rdesc *rrd; 2584193880Syongari uint32_t nsegs, status; 2585193880Syongari int rr_cons, prog; 2586193880Syongari 2587193880Syongari bus_dmamap_sync(sc->alc_cdata.alc_rr_ring_tag, 2588193880Syongari sc->alc_cdata.alc_rr_ring_map, 2589193880Syongari BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); 2590193880Syongari bus_dmamap_sync(sc->alc_cdata.alc_rx_ring_tag, 2591193880Syongari sc->alc_cdata.alc_rx_ring_map, BUS_DMASYNC_POSTWRITE); 2592193880Syongari rr_cons = sc->alc_cdata.alc_rr_cons; 2593193880Syongari ifp = sc->alc_ifp; 2594193880Syongari for (prog = 0; (ifp->if_drv_flags & IFF_DRV_RUNNING) != 0;) { 2595193880Syongari if (count-- <= 0) 2596193880Syongari break; 2597193880Syongari rrd = &sc->alc_rdata.alc_rr_ring[rr_cons]; 2598193880Syongari status = le32toh(rrd->status); 2599193880Syongari if ((status & RRD_VALID) == 0) 2600193880Syongari break; 2601193880Syongari nsegs = RRD_RD_CNT(le32toh(rrd->rdinfo)); 2602193880Syongari if (nsegs == 0) { 2603193880Syongari /* This should not happen! */ 2604193880Syongari device_printf(sc->alc_dev, 2605193880Syongari "unexpected segment count -- resetting\n"); 2606193880Syongari return (EIO); 2607193880Syongari } 2608193880Syongari alc_rxeof(sc, rrd); 2609193880Syongari /* Clear Rx return status. */ 2610193880Syongari rrd->status = 0; 2611193880Syongari ALC_DESC_INC(rr_cons, ALC_RR_RING_CNT); 2612193880Syongari sc->alc_cdata.alc_rx_cons += nsegs; 2613193880Syongari sc->alc_cdata.alc_rx_cons %= ALC_RR_RING_CNT; 2614193880Syongari prog += nsegs; 2615193880Syongari } 2616193880Syongari 2617193880Syongari if (prog > 0) { 2618193880Syongari /* Update the consumer index. */ 2619193880Syongari sc->alc_cdata.alc_rr_cons = rr_cons; 2620193880Syongari /* Sync Rx return descriptors. */ 2621193880Syongari bus_dmamap_sync(sc->alc_cdata.alc_rr_ring_tag, 2622193880Syongari sc->alc_cdata.alc_rr_ring_map, 2623193880Syongari BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 2624193880Syongari /* 2625193880Syongari * Sync updated Rx descriptors such that controller see 2626193880Syongari * modified buffer addresses. 2627193880Syongari */ 2628193880Syongari bus_dmamap_sync(sc->alc_cdata.alc_rx_ring_tag, 2629193880Syongari sc->alc_cdata.alc_rx_ring_map, BUS_DMASYNC_PREWRITE); 2630193880Syongari /* 2631193880Syongari * Let controller know availability of new Rx buffers. 2632193880Syongari * Since alc(4) use RXQ_CFG_RD_BURST_DEFAULT descriptors 2633193880Syongari * it may be possible to update ALC_MBOX_RD0_PROD_IDX 2634193880Syongari * only when Rx buffer pre-fetching is required. In 2635193880Syongari * addition we already set ALC_RX_RD_FREE_THRESH to 2636193880Syongari * RX_RD_FREE_THRESH_LO_DEFAULT descriptors. However 2637193880Syongari * it still seems that pre-fetching needs more 2638193880Syongari * experimentation. 2639193880Syongari */ 2640193880Syongari CSR_WRITE_4(sc, ALC_MBOX_RD0_PROD_IDX, 2641193880Syongari sc->alc_cdata.alc_rx_cons); 2642193880Syongari } 2643193880Syongari 2644193880Syongari return (count > 0 ? 0 : EAGAIN); 2645193880Syongari} 2646193880Syongari 2647193880Syongari#ifndef __NO_STRICT_ALIGNMENT 2648193880Syongaristatic struct mbuf * 2649193880Syongarialc_fixup_rx(struct ifnet *ifp, struct mbuf *m) 2650193880Syongari{ 2651193880Syongari struct mbuf *n; 2652193880Syongari int i; 2653193880Syongari uint16_t *src, *dst; 2654193880Syongari 2655193880Syongari src = mtod(m, uint16_t *); 2656193880Syongari dst = src - 3; 2657193880Syongari 2658193880Syongari if (m->m_next == NULL) { 2659193880Syongari for (i = 0; i < (m->m_len / sizeof(uint16_t) + 1); i++) 2660193880Syongari *dst++ = *src++; 2661193880Syongari m->m_data -= 6; 2662193880Syongari return (m); 2663193880Syongari } 2664193880Syongari /* 2665193880Syongari * Append a new mbuf to received mbuf chain and copy ethernet 2666193880Syongari * header from the mbuf chain. This can save lots of CPU 2667193880Syongari * cycles for jumbo frame. 2668193880Syongari */ 2669193880Syongari MGETHDR(n, M_DONTWAIT, MT_DATA); 2670193880Syongari if (n == NULL) { 2671193880Syongari ifp->if_iqdrops++; 2672193880Syongari m_freem(m); 2673193880Syongari return (NULL); 2674193880Syongari } 2675193880Syongari bcopy(m->m_data, n->m_data, ETHER_HDR_LEN); 2676193880Syongari m->m_data += ETHER_HDR_LEN; 2677193880Syongari m->m_len -= ETHER_HDR_LEN; 2678193880Syongari n->m_len = ETHER_HDR_LEN; 2679193880Syongari M_MOVE_PKTHDR(n, m); 2680193880Syongari n->m_next = m; 2681193880Syongari return (n); 2682193880Syongari} 2683193880Syongari#endif 2684193880Syongari 2685193880Syongari/* Receive a frame. */ 2686193880Syongaristatic void 2687193880Syongarialc_rxeof(struct alc_softc *sc, struct rx_rdesc *rrd) 2688193880Syongari{ 2689193880Syongari struct alc_rxdesc *rxd; 2690193880Syongari struct ifnet *ifp; 2691193880Syongari struct mbuf *mp, *m; 2692193880Syongari uint32_t rdinfo, status, vtag; 2693193880Syongari int count, nsegs, rx_cons; 2694193880Syongari 2695193880Syongari ifp = sc->alc_ifp; 2696193880Syongari status = le32toh(rrd->status); 2697193880Syongari rdinfo = le32toh(rrd->rdinfo); 2698193880Syongari rx_cons = RRD_RD_IDX(rdinfo); 2699193880Syongari nsegs = RRD_RD_CNT(rdinfo); 2700193880Syongari 2701193880Syongari sc->alc_cdata.alc_rxlen = RRD_BYTES(status); 2702193880Syongari if ((status & (RRD_ERR_SUM | RRD_ERR_LENGTH)) != 0) { 2703193880Syongari /* 2704193880Syongari * We want to pass the following frames to upper 2705193880Syongari * layer regardless of error status of Rx return 2706193880Syongari * ring. 2707193880Syongari * 2708193880Syongari * o IP/TCP/UDP checksum is bad. 2709193880Syongari * o frame length and protocol specific length 2710193880Syongari * does not match. 2711193880Syongari * 2712193880Syongari * Force network stack compute checksum for 2713193880Syongari * errored frames. 2714193880Syongari */ 2715193880Syongari status |= RRD_TCP_UDPCSUM_NOK | RRD_IPCSUM_NOK; 2716193880Syongari if ((RRD_ERR_CRC | RRD_ERR_ALIGN | RRD_ERR_TRUNC | 2717193880Syongari RRD_ERR_RUNT) != 0) 2718193880Syongari return; 2719193880Syongari } 2720193880Syongari 2721193880Syongari for (count = 0; count < nsegs; count++, 2722193880Syongari ALC_DESC_INC(rx_cons, ALC_RX_RING_CNT)) { 2723193880Syongari rxd = &sc->alc_cdata.alc_rxdesc[rx_cons]; 2724193880Syongari mp = rxd->rx_m; 2725193880Syongari /* Add a new receive buffer to the ring. */ 2726193880Syongari if (alc_newbuf(sc, rxd) != 0) { 2727193880Syongari ifp->if_iqdrops++; 2728193880Syongari /* Reuse Rx buffers. */ 2729193880Syongari if (sc->alc_cdata.alc_rxhead != NULL) 2730193880Syongari m_freem(sc->alc_cdata.alc_rxhead); 2731193880Syongari break; 2732193880Syongari } 2733193880Syongari 2734193880Syongari /* 2735193880Syongari * Assume we've received a full sized frame. 2736193880Syongari * Actual size is fixed when we encounter the end of 2737193880Syongari * multi-segmented frame. 2738193880Syongari */ 2739193880Syongari mp->m_len = sc->alc_buf_size; 2740193880Syongari 2741193880Syongari /* Chain received mbufs. */ 2742193880Syongari if (sc->alc_cdata.alc_rxhead == NULL) { 2743193880Syongari sc->alc_cdata.alc_rxhead = mp; 2744193880Syongari sc->alc_cdata.alc_rxtail = mp; 2745193880Syongari } else { 2746193880Syongari mp->m_flags &= ~M_PKTHDR; 2747193880Syongari sc->alc_cdata.alc_rxprev_tail = 2748193880Syongari sc->alc_cdata.alc_rxtail; 2749193880Syongari sc->alc_cdata.alc_rxtail->m_next = mp; 2750193880Syongari sc->alc_cdata.alc_rxtail = mp; 2751193880Syongari } 2752193880Syongari 2753193880Syongari if (count == nsegs - 1) { 2754193880Syongari /* Last desc. for this frame. */ 2755193880Syongari m = sc->alc_cdata.alc_rxhead; 2756193880Syongari m->m_flags |= M_PKTHDR; 2757193880Syongari /* 2758193880Syongari * It seems that L1C/L2C controller has no way 2759193880Syongari * to tell hardware to strip CRC bytes. 2760193880Syongari */ 2761193880Syongari m->m_pkthdr.len = 2762193880Syongari sc->alc_cdata.alc_rxlen - ETHER_CRC_LEN; 2763193880Syongari if (nsegs > 1) { 2764193880Syongari /* Set last mbuf size. */ 2765193880Syongari mp->m_len = sc->alc_cdata.alc_rxlen - 2766193880Syongari (nsegs - 1) * sc->alc_buf_size; 2767193880Syongari /* Remove the CRC bytes in chained mbufs. */ 2768193880Syongari if (mp->m_len <= ETHER_CRC_LEN) { 2769193880Syongari sc->alc_cdata.alc_rxtail = 2770193880Syongari sc->alc_cdata.alc_rxprev_tail; 2771193880Syongari sc->alc_cdata.alc_rxtail->m_len -= 2772193880Syongari (ETHER_CRC_LEN - mp->m_len); 2773193880Syongari sc->alc_cdata.alc_rxtail->m_next = NULL; 2774193880Syongari m_freem(mp); 2775193880Syongari } else { 2776193880Syongari mp->m_len -= ETHER_CRC_LEN; 2777193880Syongari } 2778193880Syongari } else 2779193880Syongari m->m_len = m->m_pkthdr.len; 2780193880Syongari m->m_pkthdr.rcvif = ifp; 2781193880Syongari /* 2782193880Syongari * Due to hardware bugs, Rx checksum offloading 2783193880Syongari * was intentionally disabled. 2784193880Syongari */ 2785193880Syongari if ((ifp->if_capenable & IFCAP_VLAN_HWTAGGING) != 0 && 2786193880Syongari (status & RRD_VLAN_TAG) != 0) { 2787193880Syongari vtag = RRD_VLAN(le32toh(rrd->vtag)); 2788193880Syongari m->m_pkthdr.ether_vtag = ntohs(vtag); 2789193880Syongari m->m_flags |= M_VLANTAG; 2790193880Syongari } 2791193880Syongari#ifndef __NO_STRICT_ALIGNMENT 2792193880Syongari m = alc_fixup_rx(ifp, m); 2793193880Syongari if (m != NULL) 2794193880Syongari#endif 2795193880Syongari { 2796193880Syongari /* Pass it on. */ 2797193880Syongari (*ifp->if_input)(ifp, m); 2798193880Syongari } 2799193880Syongari } 2800193880Syongari } 2801193880Syongari /* Reset mbuf chains. */ 2802193880Syongari ALC_RXCHAIN_RESET(sc); 2803193880Syongari} 2804193880Syongari 2805193880Syongaristatic void 2806193880Syongarialc_tick(void *arg) 2807193880Syongari{ 2808193880Syongari struct alc_softc *sc; 2809193880Syongari struct mii_data *mii; 2810193880Syongari 2811193880Syongari sc = (struct alc_softc *)arg; 2812193880Syongari 2813193880Syongari ALC_LOCK_ASSERT(sc); 2814193880Syongari 2815193880Syongari mii = device_get_softc(sc->alc_miibus); 2816193880Syongari mii_tick(mii); 2817193880Syongari alc_stats_update(sc); 2818193880Syongari /* 2819193880Syongari * alc(4) does not rely on Tx completion interrupts to reclaim 2820193880Syongari * transferred buffers. Instead Tx completion interrupts are 2821193880Syongari * used to hint for scheduling Tx task. So it's necessary to 2822193880Syongari * release transmitted buffers by kicking Tx completion 2823193880Syongari * handler. This limits the maximum reclamation delay to a hz. 2824193880Syongari */ 2825193880Syongari alc_txeof(sc); 2826193880Syongari alc_watchdog(sc); 2827193880Syongari callout_reset(&sc->alc_tick_ch, hz, alc_tick, sc); 2828193880Syongari} 2829193880Syongari 2830193880Syongaristatic void 2831193880Syongarialc_reset(struct alc_softc *sc) 2832193880Syongari{ 2833193880Syongari uint32_t reg; 2834193880Syongari int i; 2835193880Syongari 2836193880Syongari CSR_WRITE_4(sc, ALC_MASTER_CFG, MASTER_RESET); 2837193880Syongari for (i = ALC_RESET_TIMEOUT; i > 0; i--) { 2838193880Syongari DELAY(10); 2839193880Syongari if ((CSR_READ_4(sc, ALC_MASTER_CFG) & MASTER_RESET) == 0) 2840193880Syongari break; 2841193880Syongari } 2842193880Syongari if (i == 0) 2843193880Syongari device_printf(sc->alc_dev, "master reset timeout!\n"); 2844193880Syongari 2845193880Syongari for (i = ALC_RESET_TIMEOUT; i > 0; i--) { 2846193880Syongari if ((reg = CSR_READ_4(sc, ALC_IDLE_STATUS)) == 0) 2847193880Syongari break; 2848193880Syongari DELAY(10); 2849193880Syongari } 2850193880Syongari 2851193880Syongari if (i == 0) 2852193880Syongari device_printf(sc->alc_dev, "reset timeout(0x%08x)!\n", reg); 2853193880Syongari} 2854193880Syongari 2855193880Syongaristatic void 2856193880Syongarialc_init(void *xsc) 2857193880Syongari{ 2858193880Syongari struct alc_softc *sc; 2859193880Syongari 2860193880Syongari sc = (struct alc_softc *)xsc; 2861193880Syongari ALC_LOCK(sc); 2862193880Syongari alc_init_locked(sc); 2863193880Syongari ALC_UNLOCK(sc); 2864193880Syongari} 2865193880Syongari 2866193880Syongaristatic void 2867193880Syongarialc_init_locked(struct alc_softc *sc) 2868193880Syongari{ 2869193880Syongari struct ifnet *ifp; 2870193880Syongari struct mii_data *mii; 2871193880Syongari uint8_t eaddr[ETHER_ADDR_LEN]; 2872193880Syongari bus_addr_t paddr; 2873193880Syongari uint32_t reg, rxf_hi, rxf_lo; 2874193880Syongari 2875193880Syongari ALC_LOCK_ASSERT(sc); 2876193880Syongari 2877193880Syongari ifp = sc->alc_ifp; 2878193880Syongari mii = device_get_softc(sc->alc_miibus); 2879193880Syongari 2880193880Syongari if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0) 2881193880Syongari return; 2882193880Syongari /* 2883193880Syongari * Cancel any pending I/O. 2884193880Syongari */ 2885193880Syongari alc_stop(sc); 2886193880Syongari /* 2887193880Syongari * Reset the chip to a known state. 2888193880Syongari */ 2889193880Syongari alc_reset(sc); 2890193880Syongari 2891193880Syongari /* Initialize Rx descriptors. */ 2892193880Syongari if (alc_init_rx_ring(sc) != 0) { 2893193880Syongari device_printf(sc->alc_dev, "no memory for Rx buffers.\n"); 2894193880Syongari alc_stop(sc); 2895193880Syongari return; 2896193880Syongari } 2897193880Syongari alc_init_rr_ring(sc); 2898193880Syongari alc_init_tx_ring(sc); 2899193880Syongari alc_init_cmb(sc); 2900193880Syongari alc_init_smb(sc); 2901193880Syongari 2902193880Syongari /* Reprogram the station address. */ 2903193880Syongari bcopy(IF_LLADDR(ifp), eaddr, ETHER_ADDR_LEN); 2904193880Syongari CSR_WRITE_4(sc, ALC_PAR0, 2905193880Syongari eaddr[2] << 24 | eaddr[3] << 16 | eaddr[4] << 8 | eaddr[5]); 2906193880Syongari CSR_WRITE_4(sc, ALC_PAR1, eaddr[0] << 8 | eaddr[1]); 2907193880Syongari /* 2908193880Syongari * Clear WOL status and disable all WOL feature as WOL 2909193880Syongari * would interfere Rx operation under normal environments. 2910193880Syongari */ 2911193880Syongari CSR_READ_4(sc, ALC_WOL_CFG); 2912193880Syongari CSR_WRITE_4(sc, ALC_WOL_CFG, 0); 2913193880Syongari /* Set Tx descriptor base addresses. */ 2914193880Syongari paddr = sc->alc_rdata.alc_tx_ring_paddr; 2915193880Syongari CSR_WRITE_4(sc, ALC_TX_BASE_ADDR_HI, ALC_ADDR_HI(paddr)); 2916193880Syongari CSR_WRITE_4(sc, ALC_TDL_HEAD_ADDR_LO, ALC_ADDR_LO(paddr)); 2917193880Syongari /* We don't use high priority ring. */ 2918193880Syongari CSR_WRITE_4(sc, ALC_TDH_HEAD_ADDR_LO, 0); 2919193880Syongari /* Set Tx descriptor counter. */ 2920193880Syongari CSR_WRITE_4(sc, ALC_TD_RING_CNT, 2921193880Syongari (ALC_TX_RING_CNT << TD_RING_CNT_SHIFT) & TD_RING_CNT_MASK); 2922193880Syongari /* Set Rx descriptor base addresses. */ 2923193880Syongari paddr = sc->alc_rdata.alc_rx_ring_paddr; 2924193880Syongari CSR_WRITE_4(sc, ALC_RX_BASE_ADDR_HI, ALC_ADDR_HI(paddr)); 2925193880Syongari CSR_WRITE_4(sc, ALC_RD0_HEAD_ADDR_LO, ALC_ADDR_LO(paddr)); 2926193880Syongari /* We use one Rx ring. */ 2927193880Syongari CSR_WRITE_4(sc, ALC_RD1_HEAD_ADDR_LO, 0); 2928193880Syongari CSR_WRITE_4(sc, ALC_RD2_HEAD_ADDR_LO, 0); 2929193880Syongari CSR_WRITE_4(sc, ALC_RD3_HEAD_ADDR_LO, 0); 2930193880Syongari /* Set Rx descriptor counter. */ 2931193880Syongari CSR_WRITE_4(sc, ALC_RD_RING_CNT, 2932193880Syongari (ALC_RX_RING_CNT << RD_RING_CNT_SHIFT) & RD_RING_CNT_MASK); 2933193880Syongari 2934193880Syongari /* 2935193880Syongari * Let hardware split jumbo frames into alc_max_buf_sized chunks. 2936193880Syongari * if it do not fit the buffer size. Rx return descriptor holds 2937193880Syongari * a counter that indicates how many fragments were made by the 2938193880Syongari * hardware. The buffer size should be multiple of 8 bytes. 2939193880Syongari * Since hardware has limit on the size of buffer size, always 2940193880Syongari * use the maximum value. 2941193880Syongari * For strict-alignment architectures make sure to reduce buffer 2942193880Syongari * size by 8 bytes to make room for alignment fixup. 2943193880Syongari */ 2944193880Syongari#ifndef __NO_STRICT_ALIGNMENT 2945193880Syongari sc->alc_buf_size = RX_BUF_SIZE_MAX - sizeof(uint64_t); 2946193880Syongari#else 2947193880Syongari sc->alc_buf_size = RX_BUF_SIZE_MAX; 2948193880Syongari#endif 2949193880Syongari CSR_WRITE_4(sc, ALC_RX_BUF_SIZE, sc->alc_buf_size); 2950193880Syongari 2951193880Syongari paddr = sc->alc_rdata.alc_rr_ring_paddr; 2952193880Syongari /* Set Rx return descriptor base addresses. */ 2953193880Syongari CSR_WRITE_4(sc, ALC_RRD0_HEAD_ADDR_LO, ALC_ADDR_LO(paddr)); 2954193880Syongari /* We use one Rx return ring. */ 2955193880Syongari CSR_WRITE_4(sc, ALC_RRD1_HEAD_ADDR_LO, 0); 2956193880Syongari CSR_WRITE_4(sc, ALC_RRD2_HEAD_ADDR_LO, 0); 2957193880Syongari CSR_WRITE_4(sc, ALC_RRD3_HEAD_ADDR_LO, 0); 2958193880Syongari /* Set Rx return descriptor counter. */ 2959193880Syongari CSR_WRITE_4(sc, ALC_RRD_RING_CNT, 2960193880Syongari (ALC_RR_RING_CNT << RRD_RING_CNT_SHIFT) & RRD_RING_CNT_MASK); 2961193880Syongari paddr = sc->alc_rdata.alc_cmb_paddr; 2962193880Syongari CSR_WRITE_4(sc, ALC_CMB_BASE_ADDR_LO, ALC_ADDR_LO(paddr)); 2963193880Syongari paddr = sc->alc_rdata.alc_smb_paddr; 2964193880Syongari CSR_WRITE_4(sc, ALC_SMB_BASE_ADDR_HI, ALC_ADDR_HI(paddr)); 2965193880Syongari CSR_WRITE_4(sc, ALC_SMB_BASE_ADDR_LO, ALC_ADDR_LO(paddr)); 2966193880Syongari 2967193880Syongari /* Tell hardware that we're ready to load DMA blocks. */ 2968193880Syongari CSR_WRITE_4(sc, ALC_DMA_BLOCK, DMA_BLOCK_LOAD); 2969193880Syongari 2970193880Syongari /* Configure interrupt moderation timer. */ 2971193880Syongari reg = ALC_USECS(sc->alc_int_rx_mod) << IM_TIMER_RX_SHIFT; 2972193880Syongari reg |= ALC_USECS(sc->alc_int_tx_mod) << IM_TIMER_TX_SHIFT; 2973193880Syongari CSR_WRITE_4(sc, ALC_IM_TIMER, reg); 2974193880Syongari reg = CSR_READ_4(sc, ALC_MASTER_CFG); 2975193880Syongari reg &= ~(MASTER_CHIP_REV_MASK | MASTER_CHIP_ID_MASK); 2976193880Syongari /* 2977193880Syongari * We don't want to automatic interrupt clear as task queue 2978193880Syongari * for the interrupt should know interrupt status. 2979193880Syongari */ 2980193880Syongari reg &= ~MASTER_INTR_RD_CLR; 2981193880Syongari reg &= ~(MASTER_IM_RX_TIMER_ENB | MASTER_IM_TX_TIMER_ENB); 2982193880Syongari if (ALC_USECS(sc->alc_int_rx_mod) != 0) 2983193880Syongari reg |= MASTER_IM_RX_TIMER_ENB; 2984193880Syongari if (ALC_USECS(sc->alc_int_tx_mod) != 0) 2985193880Syongari reg |= MASTER_IM_TX_TIMER_ENB; 2986193880Syongari CSR_WRITE_4(sc, ALC_MASTER_CFG, reg); 2987193880Syongari /* 2988193880Syongari * Disable interrupt re-trigger timer. We don't want automatic 2989193880Syongari * re-triggering of un-ACKed interrupts. 2990193880Syongari */ 2991193880Syongari CSR_WRITE_4(sc, ALC_INTR_RETRIG_TIMER, ALC_USECS(0)); 2992193880Syongari /* Configure CMB. */ 2993193880Syongari CSR_WRITE_4(sc, ALC_CMB_TD_THRESH, 4); 2994193880Syongari if ((sc->alc_flags & ALC_FLAG_CMB_BUG) == 0) 2995193880Syongari CSR_WRITE_4(sc, ALC_CMB_TX_TIMER, ALC_USECS(5000)); 2996193880Syongari else 2997193880Syongari CSR_WRITE_4(sc, ALC_CMB_TX_TIMER, ALC_USECS(0)); 2998193880Syongari /* 2999193880Syongari * Hardware can be configured to issue SMB interrupt based 3000193880Syongari * on programmed interval. Since there is a callout that is 3001193880Syongari * invoked for every hz in driver we use that instead of 3002193880Syongari * relying on periodic SMB interrupt. 3003193880Syongari */ 3004193880Syongari CSR_WRITE_4(sc, ALC_SMB_STAT_TIMER, ALC_USECS(0)); 3005193880Syongari /* Clear MAC statistics. */ 3006193880Syongari alc_stats_clear(sc); 3007193880Syongari 3008193880Syongari /* 3009193880Syongari * Always use maximum frame size that controller can support. 3010193880Syongari * Otherwise received frames that has larger frame length 3011193880Syongari * than alc(4) MTU would be silently dropped in hardware. This 3012193880Syongari * would make path-MTU discovery hard as sender wouldn't get 3013193880Syongari * any responses from receiver. alc(4) supports 3014193880Syongari * multi-fragmented frames on Rx path so it has no issue on 3015193880Syongari * assembling fragmented frames. Using maximum frame size also 3016193880Syongari * removes the need to reinitialize hardware when interface 3017193880Syongari * MTU configuration was changed. 3018193880Syongari * 3019193880Syongari * Be conservative in what you do, be liberal in what you 3020193880Syongari * accept from others - RFC 793. 3021193880Syongari */ 3022193880Syongari CSR_WRITE_4(sc, ALC_FRAME_SIZE, ALC_JUMBO_FRAMELEN); 3023193880Syongari 3024193880Syongari /* Disable header split(?) */ 3025193880Syongari CSR_WRITE_4(sc, ALC_HDS_CFG, 0); 3026193880Syongari 3027193880Syongari /* Configure IPG/IFG parameters. */ 3028193880Syongari CSR_WRITE_4(sc, ALC_IPG_IFG_CFG, 3029193880Syongari ((IPG_IFG_IPGT_DEFAULT << IPG_IFG_IPGT_SHIFT) & IPG_IFG_IPGT_MASK) | 3030193880Syongari ((IPG_IFG_MIFG_DEFAULT << IPG_IFG_MIFG_SHIFT) & IPG_IFG_MIFG_MASK) | 3031193880Syongari ((IPG_IFG_IPG1_DEFAULT << IPG_IFG_IPG1_SHIFT) & IPG_IFG_IPG1_MASK) | 3032193880Syongari ((IPG_IFG_IPG2_DEFAULT << IPG_IFG_IPG2_SHIFT) & IPG_IFG_IPG2_MASK)); 3033193880Syongari /* Set parameters for half-duplex media. */ 3034193880Syongari CSR_WRITE_4(sc, ALC_HDPX_CFG, 3035193880Syongari ((HDPX_CFG_LCOL_DEFAULT << HDPX_CFG_LCOL_SHIFT) & 3036193880Syongari HDPX_CFG_LCOL_MASK) | 3037193880Syongari ((HDPX_CFG_RETRY_DEFAULT << HDPX_CFG_RETRY_SHIFT) & 3038193880Syongari HDPX_CFG_RETRY_MASK) | HDPX_CFG_EXC_DEF_EN | 3039193880Syongari ((HDPX_CFG_ABEBT_DEFAULT << HDPX_CFG_ABEBT_SHIFT) & 3040193880Syongari HDPX_CFG_ABEBT_MASK) | 3041193880Syongari ((HDPX_CFG_JAMIPG_DEFAULT << HDPX_CFG_JAMIPG_SHIFT) & 3042193880Syongari HDPX_CFG_JAMIPG_MASK)); 3043193880Syongari /* 3044193880Syongari * Set TSO/checksum offload threshold. For frames that is 3045193880Syongari * larger than this threshold, hardware wouldn't do 3046193880Syongari * TSO/checksum offloading. 3047193880Syongari */ 3048193880Syongari CSR_WRITE_4(sc, ALC_TSO_OFFLOAD_THRESH, 3049193880Syongari (ALC_JUMBO_FRAMELEN >> TSO_OFFLOAD_THRESH_UNIT_SHIFT) & 3050193880Syongari TSO_OFFLOAD_THRESH_MASK); 3051193880Syongari /* Configure TxQ. */ 3052193880Syongari reg = (alc_dma_burst[sc->alc_dma_rd_burst] << 3053193880Syongari TXQ_CFG_TX_FIFO_BURST_SHIFT) & TXQ_CFG_TX_FIFO_BURST_MASK; 3054193880Syongari reg |= (TXQ_CFG_TD_BURST_DEFAULT << TXQ_CFG_TD_BURST_SHIFT) & 3055193880Syongari TXQ_CFG_TD_BURST_MASK; 3056193880Syongari CSR_WRITE_4(sc, ALC_TXQ_CFG, reg | TXQ_CFG_ENHANCED_MODE); 3057193880Syongari 3058193880Syongari /* Configure Rx free descriptor pre-fetching. */ 3059193880Syongari CSR_WRITE_4(sc, ALC_RX_RD_FREE_THRESH, 3060193880Syongari ((RX_RD_FREE_THRESH_HI_DEFAULT << RX_RD_FREE_THRESH_HI_SHIFT) & 3061193880Syongari RX_RD_FREE_THRESH_HI_MASK) | 3062193880Syongari ((RX_RD_FREE_THRESH_LO_DEFAULT << RX_RD_FREE_THRESH_LO_SHIFT) & 3063193880Syongari RX_RD_FREE_THRESH_LO_MASK)); 3064193880Syongari 3065193880Syongari /* 3066193880Syongari * Configure flow control parameters. 3067193880Syongari * XON : 80% of Rx FIFO 3068193880Syongari * XOFF : 30% of Rx FIFO 3069193880Syongari */ 3070193880Syongari reg = CSR_READ_4(sc, ALC_SRAM_RX_FIFO_LEN); 3071193880Syongari rxf_hi = (reg * 8) / 10; 3072193880Syongari rxf_lo = (reg * 3)/ 10; 3073193880Syongari CSR_WRITE_4(sc, ALC_RX_FIFO_PAUSE_THRESH, 3074193880Syongari ((rxf_lo << RX_FIFO_PAUSE_THRESH_LO_SHIFT) & 3075193880Syongari RX_FIFO_PAUSE_THRESH_LO_MASK) | 3076193880Syongari ((rxf_hi << RX_FIFO_PAUSE_THRESH_HI_SHIFT) & 3077193880Syongari RX_FIFO_PAUSE_THRESH_HI_MASK)); 3078193880Syongari 3079193880Syongari /* Disable RSS until I understand L1C/L2C's RSS logic. */ 3080193880Syongari CSR_WRITE_4(sc, ALC_RSS_IDT_TABLE0, 0); 3081193880Syongari CSR_WRITE_4(sc, ALC_RSS_CPU, 0); 3082193880Syongari 3083193880Syongari /* Configure RxQ. */ 3084193880Syongari reg = (RXQ_CFG_RD_BURST_DEFAULT << RXQ_CFG_RD_BURST_SHIFT) & 3085193880Syongari RXQ_CFG_RD_BURST_MASK; 3086193880Syongari reg |= RXQ_CFG_RSS_MODE_DIS; 3087193880Syongari if ((sc->alc_flags & ALC_FLAG_ASPM_MON) != 0) 3088193880Syongari reg |= RXQ_CFG_ASPM_THROUGHPUT_LIMIT_100M; 3089193880Syongari CSR_WRITE_4(sc, ALC_RXQ_CFG, reg); 3090193880Syongari 3091193880Syongari /* Configure Rx DMAW request thresold. */ 3092193880Syongari CSR_WRITE_4(sc, ALC_RD_DMA_CFG, 3093193880Syongari ((RD_DMA_CFG_THRESH_DEFAULT << RD_DMA_CFG_THRESH_SHIFT) & 3094193880Syongari RD_DMA_CFG_THRESH_MASK) | 3095193880Syongari ((ALC_RD_DMA_CFG_USECS(0) << RD_DMA_CFG_TIMER_SHIFT) & 3096193880Syongari RD_DMA_CFG_TIMER_MASK)); 3097193880Syongari /* Configure DMA parameters. */ 3098193880Syongari reg = DMA_CFG_OUT_ORDER | DMA_CFG_RD_REQ_PRI; 3099193880Syongari reg |= sc->alc_rcb; 3100193880Syongari if ((sc->alc_flags & ALC_FLAG_CMB_BUG) == 0) 3101193880Syongari reg |= DMA_CFG_CMB_ENB; 3102193880Syongari if ((sc->alc_flags & ALC_FLAG_SMB_BUG) == 0) 3103193880Syongari reg |= DMA_CFG_SMB_ENB; 3104193880Syongari else 3105193880Syongari reg |= DMA_CFG_SMB_DIS; 3106193880Syongari reg |= (sc->alc_dma_rd_burst & DMA_CFG_RD_BURST_MASK) << 3107193880Syongari DMA_CFG_RD_BURST_SHIFT; 3108193880Syongari reg |= (sc->alc_dma_wr_burst & DMA_CFG_WR_BURST_MASK) << 3109193880Syongari DMA_CFG_WR_BURST_SHIFT; 3110193880Syongari reg |= (DMA_CFG_RD_DELAY_CNT_DEFAULT << DMA_CFG_RD_DELAY_CNT_SHIFT) & 3111193880Syongari DMA_CFG_RD_DELAY_CNT_MASK; 3112193880Syongari reg |= (DMA_CFG_WR_DELAY_CNT_DEFAULT << DMA_CFG_WR_DELAY_CNT_SHIFT) & 3113193880Syongari DMA_CFG_WR_DELAY_CNT_MASK; 3114193880Syongari CSR_WRITE_4(sc, ALC_DMA_CFG, reg); 3115193880Syongari 3116193880Syongari /* 3117193880Syongari * Configure Tx/Rx MACs. 3118193880Syongari * - Auto-padding for short frames. 3119193880Syongari * - Enable CRC generation. 3120193880Syongari * Actual reconfiguration of MAC for resolved speed/duplex 3121193880Syongari * is followed after detection of link establishment. 3122193880Syongari * AR8131/AR8132 always does checksum computation regardless 3123193880Syongari * of MAC_CFG_RXCSUM_ENB bit. Also the controller is known to 3124193880Syongari * have bug in protocol field in Rx return structure so 3125193880Syongari * these controllers can't handle fragmented frames. Disable 3126193880Syongari * Rx checksum offloading until there is a newer controller 3127193880Syongari * that has sane implementation. 3128193880Syongari */ 3129193880Syongari reg = MAC_CFG_TX_CRC_ENB | MAC_CFG_TX_AUTO_PAD | MAC_CFG_FULL_DUPLEX | 3130193880Syongari ((MAC_CFG_PREAMBLE_DEFAULT << MAC_CFG_PREAMBLE_SHIFT) & 3131193880Syongari MAC_CFG_PREAMBLE_MASK); 3132193880Syongari if ((sc->alc_flags & ALC_FLAG_FASTETHER) != 0) 3133193880Syongari reg |= MAC_CFG_SPEED_10_100; 3134193880Syongari else 3135193880Syongari reg |= MAC_CFG_SPEED_1000; 3136193880Syongari CSR_WRITE_4(sc, ALC_MAC_CFG, reg); 3137193880Syongari 3138193880Syongari /* Set up the receive filter. */ 3139193880Syongari alc_rxfilter(sc); 3140193880Syongari alc_rxvlan(sc); 3141193880Syongari 3142193880Syongari /* Acknowledge all pending interrupts and clear it. */ 3143193880Syongari CSR_WRITE_4(sc, ALC_INTR_MASK, ALC_INTRS); 3144193880Syongari CSR_WRITE_4(sc, ALC_INTR_STATUS, 0xFFFFFFFF); 3145193880Syongari CSR_WRITE_4(sc, ALC_INTR_STATUS, 0); 3146193880Syongari 3147193880Syongari sc->alc_flags &= ~ALC_FLAG_LINK; 3148193880Syongari /* Switch to the current media. */ 3149193880Syongari mii_mediachg(mii); 3150193880Syongari 3151193880Syongari callout_reset(&sc->alc_tick_ch, hz, alc_tick, sc); 3152193880Syongari 3153193880Syongari ifp->if_drv_flags |= IFF_DRV_RUNNING; 3154193880Syongari ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 3155193880Syongari} 3156193880Syongari 3157193880Syongaristatic void 3158193880Syongarialc_stop(struct alc_softc *sc) 3159193880Syongari{ 3160193880Syongari struct ifnet *ifp; 3161193880Syongari struct alc_txdesc *txd; 3162193880Syongari struct alc_rxdesc *rxd; 3163193880Syongari uint32_t reg; 3164193880Syongari int i; 3165193880Syongari 3166193880Syongari ALC_LOCK_ASSERT(sc); 3167193880Syongari /* 3168193880Syongari * Mark the interface down and cancel the watchdog timer. 3169193880Syongari */ 3170193880Syongari ifp = sc->alc_ifp; 3171193880Syongari ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE); 3172193880Syongari sc->alc_flags &= ~ALC_FLAG_LINK; 3173193880Syongari callout_stop(&sc->alc_tick_ch); 3174193880Syongari sc->alc_watchdog_timer = 0; 3175193880Syongari alc_stats_update(sc); 3176193880Syongari /* Disable interrupts. */ 3177193880Syongari CSR_WRITE_4(sc, ALC_INTR_MASK, 0); 3178193880Syongari CSR_WRITE_4(sc, ALC_INTR_STATUS, 0xFFFFFFFF); 3179193880Syongari alc_stop_queue(sc); 3180193880Syongari /* Disable DMA. */ 3181193880Syongari reg = CSR_READ_4(sc, ALC_DMA_CFG); 3182193880Syongari reg &= ~(DMA_CFG_CMB_ENB | DMA_CFG_SMB_ENB); 3183193880Syongari reg |= DMA_CFG_SMB_DIS; 3184193880Syongari CSR_WRITE_4(sc, ALC_DMA_CFG, reg); 3185193880Syongari DELAY(1000); 3186193880Syongari /* Stop Rx/Tx MACs. */ 3187193880Syongari alc_stop_mac(sc); 3188193880Syongari /* Disable interrupts which might be touched in taskq handler. */ 3189193880Syongari CSR_WRITE_4(sc, ALC_INTR_STATUS, 0xFFFFFFFF); 3190193880Syongari 3191193880Syongari /* Reclaim Rx buffers that have been processed. */ 3192193880Syongari if (sc->alc_cdata.alc_rxhead != NULL) 3193193880Syongari m_freem(sc->alc_cdata.alc_rxhead); 3194193880Syongari ALC_RXCHAIN_RESET(sc); 3195193880Syongari /* 3196193880Syongari * Free Tx/Rx mbufs still in the queues. 3197193880Syongari */ 3198193880Syongari for (i = 0; i < ALC_RX_RING_CNT; i++) { 3199193880Syongari rxd = &sc->alc_cdata.alc_rxdesc[i]; 3200193880Syongari if (rxd->rx_m != NULL) { 3201193880Syongari bus_dmamap_sync(sc->alc_cdata.alc_rx_tag, 3202193880Syongari rxd->rx_dmamap, BUS_DMASYNC_POSTREAD); 3203193880Syongari bus_dmamap_unload(sc->alc_cdata.alc_rx_tag, 3204193880Syongari rxd->rx_dmamap); 3205193880Syongari m_freem(rxd->rx_m); 3206193880Syongari rxd->rx_m = NULL; 3207193880Syongari } 3208193880Syongari } 3209193880Syongari for (i = 0; i < ALC_TX_RING_CNT; i++) { 3210193880Syongari txd = &sc->alc_cdata.alc_txdesc[i]; 3211193880Syongari if (txd->tx_m != NULL) { 3212193880Syongari bus_dmamap_sync(sc->alc_cdata.alc_tx_tag, 3213193880Syongari txd->tx_dmamap, BUS_DMASYNC_POSTWRITE); 3214193880Syongari bus_dmamap_unload(sc->alc_cdata.alc_tx_tag, 3215193880Syongari txd->tx_dmamap); 3216193880Syongari m_freem(txd->tx_m); 3217193880Syongari txd->tx_m = NULL; 3218193880Syongari } 3219193880Syongari } 3220193880Syongari} 3221193880Syongari 3222193880Syongaristatic void 3223193880Syongarialc_stop_mac(struct alc_softc *sc) 3224193880Syongari{ 3225193880Syongari uint32_t reg; 3226193880Syongari int i; 3227193880Syongari 3228193880Syongari ALC_LOCK_ASSERT(sc); 3229193880Syongari 3230193880Syongari /* Disable Rx/Tx MAC. */ 3231193880Syongari reg = CSR_READ_4(sc, ALC_MAC_CFG); 3232193880Syongari if ((reg & (MAC_CFG_TX_ENB | MAC_CFG_RX_ENB)) != 0) { 3233193880Syongari reg &= ~MAC_CFG_TX_ENB | MAC_CFG_RX_ENB; 3234193880Syongari CSR_WRITE_4(sc, ALC_MAC_CFG, reg); 3235193880Syongari } 3236193880Syongari for (i = ALC_TIMEOUT; i > 0; i--) { 3237193880Syongari reg = CSR_READ_4(sc, ALC_IDLE_STATUS); 3238193880Syongari if (reg == 0) 3239193880Syongari break; 3240193880Syongari DELAY(10); 3241193880Syongari } 3242193880Syongari if (i == 0) 3243193880Syongari device_printf(sc->alc_dev, 3244193880Syongari "could not disable Rx/Tx MAC(0x%08x)!\n", reg); 3245193880Syongari} 3246193880Syongari 3247193880Syongaristatic void 3248193880Syongarialc_start_queue(struct alc_softc *sc) 3249193880Syongari{ 3250193880Syongari uint32_t qcfg[] = { 3251193880Syongari 0, 3252193880Syongari RXQ_CFG_QUEUE0_ENB, 3253193880Syongari RXQ_CFG_QUEUE0_ENB | RXQ_CFG_QUEUE1_ENB, 3254193880Syongari RXQ_CFG_QUEUE0_ENB | RXQ_CFG_QUEUE1_ENB | RXQ_CFG_QUEUE2_ENB, 3255193880Syongari RXQ_CFG_ENB 3256193880Syongari }; 3257193880Syongari uint32_t cfg; 3258193880Syongari 3259193880Syongari ALC_LOCK_ASSERT(sc); 3260193880Syongari 3261193880Syongari /* Enable RxQ. */ 3262193880Syongari cfg = CSR_READ_4(sc, ALC_RXQ_CFG); 3263193880Syongari cfg &= ~RXQ_CFG_ENB; 3264193880Syongari cfg |= qcfg[1]; 3265193880Syongari CSR_WRITE_4(sc, ALC_RXQ_CFG, cfg); 3266193880Syongari /* Enable TxQ. */ 3267193880Syongari cfg = CSR_READ_4(sc, ALC_TXQ_CFG); 3268193880Syongari cfg |= TXQ_CFG_ENB; 3269193880Syongari CSR_WRITE_4(sc, ALC_TXQ_CFG, cfg); 3270193880Syongari} 3271193880Syongari 3272193880Syongaristatic void 3273193880Syongarialc_stop_queue(struct alc_softc *sc) 3274193880Syongari{ 3275193880Syongari uint32_t reg; 3276193880Syongari int i; 3277193880Syongari 3278193880Syongari ALC_LOCK_ASSERT(sc); 3279193880Syongari 3280193880Syongari /* Disable RxQ. */ 3281193880Syongari reg = CSR_READ_4(sc, ALC_RXQ_CFG); 3282193880Syongari if ((reg & RXQ_CFG_ENB) != 0) { 3283193880Syongari reg &= ~RXQ_CFG_ENB; 3284193880Syongari CSR_WRITE_4(sc, ALC_RXQ_CFG, reg); 3285193880Syongari } 3286193880Syongari /* Disable TxQ. */ 3287193880Syongari reg = CSR_READ_4(sc, ALC_TXQ_CFG); 3288193880Syongari if ((reg & TXQ_CFG_ENB) == 0) { 3289193880Syongari reg &= ~TXQ_CFG_ENB; 3290193880Syongari CSR_WRITE_4(sc, ALC_TXQ_CFG, reg); 3291193880Syongari } 3292193880Syongari for (i = ALC_TIMEOUT; i > 0; i--) { 3293193880Syongari reg = CSR_READ_4(sc, ALC_IDLE_STATUS); 3294193880Syongari if ((reg & (IDLE_STATUS_RXQ | IDLE_STATUS_TXQ)) == 0) 3295193880Syongari break; 3296193880Syongari DELAY(10); 3297193880Syongari } 3298193880Syongari if (i == 0) 3299193880Syongari device_printf(sc->alc_dev, 3300193880Syongari "could not disable RxQ/TxQ (0x%08x)!\n", reg); 3301193880Syongari} 3302193880Syongari 3303193880Syongaristatic void 3304193880Syongarialc_init_tx_ring(struct alc_softc *sc) 3305193880Syongari{ 3306193880Syongari struct alc_ring_data *rd; 3307193880Syongari struct alc_txdesc *txd; 3308193880Syongari int i; 3309193880Syongari 3310193880Syongari ALC_LOCK_ASSERT(sc); 3311193880Syongari 3312193880Syongari sc->alc_cdata.alc_tx_prod = 0; 3313193880Syongari sc->alc_cdata.alc_tx_cons = 0; 3314193880Syongari sc->alc_cdata.alc_tx_cnt = 0; 3315193880Syongari 3316193880Syongari rd = &sc->alc_rdata; 3317193880Syongari bzero(rd->alc_tx_ring, ALC_TX_RING_SZ); 3318193880Syongari for (i = 0; i < ALC_TX_RING_CNT; i++) { 3319193880Syongari txd = &sc->alc_cdata.alc_txdesc[i]; 3320193880Syongari txd->tx_m = NULL; 3321193880Syongari } 3322193880Syongari 3323193880Syongari bus_dmamap_sync(sc->alc_cdata.alc_tx_ring_tag, 3324193880Syongari sc->alc_cdata.alc_tx_ring_map, BUS_DMASYNC_PREWRITE); 3325193880Syongari} 3326193880Syongari 3327193880Syongaristatic int 3328193880Syongarialc_init_rx_ring(struct alc_softc *sc) 3329193880Syongari{ 3330193880Syongari struct alc_ring_data *rd; 3331193880Syongari struct alc_rxdesc *rxd; 3332193880Syongari int i; 3333193880Syongari 3334193880Syongari ALC_LOCK_ASSERT(sc); 3335193880Syongari 3336193880Syongari sc->alc_cdata.alc_rx_cons = ALC_RX_RING_CNT - 1; 3337193880Syongari sc->alc_morework = 0; 3338193880Syongari rd = &sc->alc_rdata; 3339193880Syongari bzero(rd->alc_rx_ring, ALC_RX_RING_SZ); 3340193880Syongari for (i = 0; i < ALC_RX_RING_CNT; i++) { 3341193880Syongari rxd = &sc->alc_cdata.alc_rxdesc[i]; 3342193880Syongari rxd->rx_m = NULL; 3343193880Syongari rxd->rx_desc = &rd->alc_rx_ring[i]; 3344193880Syongari if (alc_newbuf(sc, rxd) != 0) 3345193880Syongari return (ENOBUFS); 3346193880Syongari } 3347193880Syongari 3348193880Syongari /* 3349193880Syongari * Since controller does not update Rx descriptors, driver 3350193880Syongari * does have to read Rx descriptors back so BUS_DMASYNC_PREWRITE 3351193880Syongari * is enough to ensure coherence. 3352193880Syongari */ 3353193880Syongari bus_dmamap_sync(sc->alc_cdata.alc_rx_ring_tag, 3354193880Syongari sc->alc_cdata.alc_rx_ring_map, BUS_DMASYNC_PREWRITE); 3355193880Syongari /* Let controller know availability of new Rx buffers. */ 3356193880Syongari CSR_WRITE_4(sc, ALC_MBOX_RD0_PROD_IDX, sc->alc_cdata.alc_rx_cons); 3357193880Syongari 3358193880Syongari return (0); 3359193880Syongari} 3360193880Syongari 3361193880Syongaristatic void 3362193880Syongarialc_init_rr_ring(struct alc_softc *sc) 3363193880Syongari{ 3364193880Syongari struct alc_ring_data *rd; 3365193880Syongari 3366193880Syongari ALC_LOCK_ASSERT(sc); 3367193880Syongari 3368193880Syongari sc->alc_cdata.alc_rr_cons = 0; 3369193880Syongari ALC_RXCHAIN_RESET(sc); 3370193880Syongari 3371193880Syongari rd = &sc->alc_rdata; 3372193880Syongari bzero(rd->alc_rr_ring, ALC_RR_RING_SZ); 3373193880Syongari bus_dmamap_sync(sc->alc_cdata.alc_rr_ring_tag, 3374193880Syongari sc->alc_cdata.alc_rr_ring_map, 3375193880Syongari BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 3376193880Syongari} 3377193880Syongari 3378193880Syongaristatic void 3379193880Syongarialc_init_cmb(struct alc_softc *sc) 3380193880Syongari{ 3381193880Syongari struct alc_ring_data *rd; 3382193880Syongari 3383193880Syongari ALC_LOCK_ASSERT(sc); 3384193880Syongari 3385193880Syongari rd = &sc->alc_rdata; 3386193880Syongari bzero(rd->alc_cmb, ALC_CMB_SZ); 3387193880Syongari bus_dmamap_sync(sc->alc_cdata.alc_cmb_tag, sc->alc_cdata.alc_cmb_map, 3388193880Syongari BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 3389193880Syongari} 3390193880Syongari 3391193880Syongaristatic void 3392193880Syongarialc_init_smb(struct alc_softc *sc) 3393193880Syongari{ 3394193880Syongari struct alc_ring_data *rd; 3395193880Syongari 3396193880Syongari ALC_LOCK_ASSERT(sc); 3397193880Syongari 3398193880Syongari rd = &sc->alc_rdata; 3399193880Syongari bzero(rd->alc_smb, ALC_SMB_SZ); 3400193880Syongari bus_dmamap_sync(sc->alc_cdata.alc_smb_tag, sc->alc_cdata.alc_smb_map, 3401193880Syongari BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 3402193880Syongari} 3403193880Syongari 3404193880Syongaristatic void 3405193880Syongarialc_rxvlan(struct alc_softc *sc) 3406193880Syongari{ 3407193880Syongari struct ifnet *ifp; 3408193880Syongari uint32_t reg; 3409193880Syongari 3410193880Syongari ALC_LOCK_ASSERT(sc); 3411193880Syongari 3412193880Syongari ifp = sc->alc_ifp; 3413193880Syongari reg = CSR_READ_4(sc, ALC_MAC_CFG); 3414193880Syongari if ((ifp->if_capenable & IFCAP_VLAN_HWTAGGING) != 0) 3415193880Syongari reg |= MAC_CFG_VLAN_TAG_STRIP; 3416193880Syongari else 3417193880Syongari reg &= ~MAC_CFG_VLAN_TAG_STRIP; 3418193880Syongari CSR_WRITE_4(sc, ALC_MAC_CFG, reg); 3419193880Syongari} 3420193880Syongari 3421193880Syongaristatic void 3422193880Syongarialc_rxfilter(struct alc_softc *sc) 3423193880Syongari{ 3424193880Syongari struct ifnet *ifp; 3425193880Syongari struct ifmultiaddr *ifma; 3426193880Syongari uint32_t crc; 3427193880Syongari uint32_t mchash[2]; 3428193880Syongari uint32_t rxcfg; 3429193880Syongari 3430193880Syongari ALC_LOCK_ASSERT(sc); 3431193880Syongari 3432193880Syongari ifp = sc->alc_ifp; 3433193880Syongari 3434193880Syongari bzero(mchash, sizeof(mchash)); 3435193880Syongari rxcfg = CSR_READ_4(sc, ALC_MAC_CFG); 3436193880Syongari rxcfg &= ~(MAC_CFG_ALLMULTI | MAC_CFG_BCAST | MAC_CFG_PROMISC); 3437193880Syongari if ((ifp->if_flags & IFF_BROADCAST) != 0) 3438193880Syongari rxcfg |= MAC_CFG_BCAST; 3439193880Syongari if ((ifp->if_flags & (IFF_PROMISC | IFF_ALLMULTI)) != 0) { 3440193880Syongari if ((ifp->if_flags & IFF_PROMISC) != 0) 3441193880Syongari rxcfg |= MAC_CFG_PROMISC; 3442193880Syongari if ((ifp->if_flags & IFF_ALLMULTI) != 0) 3443193880Syongari rxcfg |= MAC_CFG_ALLMULTI; 3444193880Syongari mchash[0] = 0xFFFFFFFF; 3445193880Syongari mchash[1] = 0xFFFFFFFF; 3446193880Syongari goto chipit; 3447193880Syongari } 3448193880Syongari 3449195049Srwatson if_maddr_rlock(ifp); 3450193880Syongari TAILQ_FOREACH(ifma, &sc->alc_ifp->if_multiaddrs, ifma_link) { 3451193880Syongari if (ifma->ifma_addr->sa_family != AF_LINK) 3452193880Syongari continue; 3453193880Syongari crc = ether_crc32_le(LLADDR((struct sockaddr_dl *) 3454193880Syongari ifma->ifma_addr), ETHER_ADDR_LEN); 3455193880Syongari mchash[crc >> 31] |= 1 << ((crc >> 26) & 0x1f); 3456193880Syongari } 3457195049Srwatson if_maddr_runlock(ifp); 3458193880Syongari 3459193880Syongarichipit: 3460193880Syongari CSR_WRITE_4(sc, ALC_MAR0, mchash[0]); 3461193880Syongari CSR_WRITE_4(sc, ALC_MAR1, mchash[1]); 3462193880Syongari CSR_WRITE_4(sc, ALC_MAC_CFG, rxcfg); 3463193880Syongari} 3464193880Syongari 3465193880Syongaristatic int 3466193880Syongarisysctl_int_range(SYSCTL_HANDLER_ARGS, int low, int high) 3467193880Syongari{ 3468193880Syongari int error, value; 3469193880Syongari 3470193880Syongari if (arg1 == NULL) 3471193880Syongari return (EINVAL); 3472193880Syongari value = *(int *)arg1; 3473193880Syongari error = sysctl_handle_int(oidp, &value, 0, req); 3474193880Syongari if (error || req->newptr == NULL) 3475193880Syongari return (error); 3476193880Syongari if (value < low || value > high) 3477193880Syongari return (EINVAL); 3478193880Syongari *(int *)arg1 = value; 3479193880Syongari 3480193880Syongari return (0); 3481193880Syongari} 3482193880Syongari 3483193880Syongaristatic int 3484193880Syongarisysctl_hw_alc_proc_limit(SYSCTL_HANDLER_ARGS) 3485193880Syongari{ 3486193880Syongari return (sysctl_int_range(oidp, arg1, arg2, req, 3487193880Syongari ALC_PROC_MIN, ALC_PROC_MAX)); 3488193880Syongari} 3489193880Syongari 3490193880Syongaristatic int 3491193880Syongarisysctl_hw_alc_int_mod(SYSCTL_HANDLER_ARGS) 3492193880Syongari{ 3493193880Syongari 3494193880Syongari return (sysctl_int_range(oidp, arg1, arg2, req, 3495193880Syongari ALC_IM_TIMER_MIN, ALC_IM_TIMER_MAX)); 3496193880Syongari} 3497