1183567Sstas/*- 2183567Sstas * Copyright (c) 2008 Stanislav Sedov <stas@FreeBSD.org>. 3183567Sstas * All rights reserved. 4183567Sstas * 5183567Sstas * Redistribution and use in source and binary forms, with or without 6183567Sstas * modification, are permitted provided that the following conditions 7183567Sstas * are met: 8183567Sstas * 1. Redistributions of source code must retain the above copyright 9183567Sstas * notice, this list of conditions and the following disclaimer. 10183567Sstas * 2. Redistributions in binary form must reproduce the above copyright 11183567Sstas * notice, this list of conditions and the following disclaimer in the 12183567Sstas * documentation and/or other materials provided with the distribution. 13183567Sstas * 14183567Sstas * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 15183567Sstas * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 16183567Sstas * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 17183567Sstas * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 18183567Sstas * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 19183567Sstas * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 20183567Sstas * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 21183567Sstas * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22183567Sstas * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 23183567Sstas * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24183567Sstas * 25183567Sstas * Driver for Attansic Technology Corp. L2 FastEthernet adapter. 26183567Sstas * 27183567Sstas * This driver is heavily based on age(4) Attansic L1 driver by Pyun YongHyeon. 28183567Sstas */ 29183567Sstas 30183567Sstas#include <sys/cdefs.h> 31183567Sstas__FBSDID("$FreeBSD$"); 32183567Sstas 33183567Sstas#include <sys/param.h> 34183567Sstas#include <sys/systm.h> 35183567Sstas#include <sys/bus.h> 36183567Sstas#include <sys/endian.h> 37183567Sstas#include <sys/kernel.h> 38183567Sstas#include <sys/malloc.h> 39183567Sstas#include <sys/mbuf.h> 40183567Sstas#include <sys/rman.h> 41183567Sstas#include <sys/module.h> 42183567Sstas#include <sys/queue.h> 43183567Sstas#include <sys/socket.h> 44183567Sstas#include <sys/sockio.h> 45183567Sstas#include <sys/sysctl.h> 46183567Sstas#include <sys/taskqueue.h> 47183567Sstas 48183567Sstas#include <net/bpf.h> 49183567Sstas#include <net/if.h> 50183567Sstas#include <net/if_arp.h> 51183567Sstas#include <net/ethernet.h> 52183567Sstas#include <net/if_dl.h> 53183567Sstas#include <net/if_media.h> 54183567Sstas#include <net/if_types.h> 55183567Sstas#include <net/if_vlan_var.h> 56183567Sstas 57183567Sstas#include <netinet/in.h> 58183567Sstas#include <netinet/in_systm.h> 59183567Sstas#include <netinet/ip.h> 60183567Sstas#include <netinet/tcp.h> 61183567Sstas 62183567Sstas#include <dev/mii/mii.h> 63183567Sstas#include <dev/mii/miivar.h> 64183567Sstas#include <dev/pci/pcireg.h> 65183567Sstas#include <dev/pci/pcivar.h> 66183567Sstas 67183567Sstas#include <machine/bus.h> 68183567Sstas 69183567Sstas#include "miibus_if.h" 70183567Sstas 71183567Sstas#include "if_aereg.h" 72183567Sstas#include "if_aevar.h" 73183567Sstas 74183567Sstas/* 75183567Sstas * Devices supported by this driver. 76183567Sstas */ 77183567Sstasstatic struct ae_dev { 78183567Sstas uint16_t vendorid; 79183567Sstas uint16_t deviceid; 80183567Sstas const char *name; 81183567Sstas} ae_devs[] = { 82183567Sstas { VENDORID_ATTANSIC, DEVICEID_ATTANSIC_L2, 83183567Sstas "Attansic Technology Corp, L2 FastEthernet" }, 84183567Sstas}; 85183567Sstas#define AE_DEVS_COUNT (sizeof(ae_devs) / sizeof(*ae_devs)) 86183567Sstas 87183567Sstasstatic struct resource_spec ae_res_spec_mem[] = { 88183567Sstas { SYS_RES_MEMORY, PCIR_BAR(0), RF_ACTIVE }, 89183567Sstas { -1, 0, 0 } 90183567Sstas}; 91183567Sstasstatic struct resource_spec ae_res_spec_irq[] = { 92183567Sstas { SYS_RES_IRQ, 0, RF_ACTIVE | RF_SHAREABLE }, 93183567Sstas { -1, 0, 0 } 94183567Sstas}; 95183567Sstasstatic struct resource_spec ae_res_spec_msi[] = { 96183567Sstas { SYS_RES_IRQ, 1, RF_ACTIVE }, 97183567Sstas { -1, 0, 0 } 98183567Sstas}; 99183567Sstas 100183567Sstasstatic int ae_probe(device_t dev); 101183567Sstasstatic int ae_attach(device_t dev); 102183567Sstasstatic void ae_pcie_init(ae_softc_t *sc); 103183567Sstasstatic void ae_phy_reset(ae_softc_t *sc); 104183567Sstasstatic void ae_phy_init(ae_softc_t *sc); 105183567Sstasstatic int ae_reset(ae_softc_t *sc); 106183567Sstasstatic void ae_init(void *arg); 107183567Sstasstatic int ae_init_locked(ae_softc_t *sc); 108188127Simpstatic int ae_detach(device_t dev); 109183567Sstasstatic int ae_miibus_readreg(device_t dev, int phy, int reg); 110183567Sstasstatic int ae_miibus_writereg(device_t dev, int phy, int reg, int val); 111183567Sstasstatic void ae_miibus_statchg(device_t dev); 112183567Sstasstatic void ae_mediastatus(struct ifnet *ifp, struct ifmediareq *ifmr); 113183567Sstasstatic int ae_mediachange(struct ifnet *ifp); 114183567Sstasstatic void ae_retrieve_address(ae_softc_t *sc); 115183567Sstasstatic void ae_dmamap_cb(void *arg, bus_dma_segment_t *segs, int nsegs, 116183567Sstas int error); 117183567Sstasstatic int ae_alloc_rings(ae_softc_t *sc); 118183567Sstasstatic void ae_dma_free(ae_softc_t *sc); 119183567Sstasstatic int ae_shutdown(device_t dev); 120183567Sstasstatic int ae_suspend(device_t dev); 121183567Sstasstatic void ae_powersave_disable(ae_softc_t *sc); 122183567Sstasstatic void ae_powersave_enable(ae_softc_t *sc); 123183567Sstasstatic int ae_resume(device_t dev); 124183567Sstasstatic unsigned int ae_tx_avail_size(ae_softc_t *sc); 125183567Sstasstatic int ae_encap(ae_softc_t *sc, struct mbuf **m_head); 126183567Sstasstatic void ae_start(struct ifnet *ifp); 127216925Sjhbstatic void ae_start_locked(struct ifnet *ifp); 128183567Sstasstatic void ae_link_task(void *arg, int pending); 129183567Sstasstatic void ae_stop_rxmac(ae_softc_t *sc); 130183567Sstasstatic void ae_stop_txmac(ae_softc_t *sc); 131183567Sstasstatic void ae_mac_config(ae_softc_t *sc); 132183567Sstasstatic int ae_intr(void *arg); 133183567Sstasstatic void ae_int_task(void *arg, int pending); 134183567Sstasstatic void ae_tx_intr(ae_softc_t *sc); 135264444Syongaristatic void ae_rxeof(ae_softc_t *sc, ae_rxd_t *rxd); 136183567Sstasstatic void ae_rx_intr(ae_softc_t *sc); 137183567Sstasstatic void ae_watchdog(ae_softc_t *sc); 138183567Sstasstatic void ae_tick(void *arg); 139183567Sstasstatic void ae_rxfilter(ae_softc_t *sc); 140183567Sstasstatic void ae_rxvlan(ae_softc_t *sc); 141183567Sstasstatic int ae_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data); 142183567Sstasstatic void ae_stop(ae_softc_t *sc); 143183567Sstasstatic int ae_check_eeprom_present(ae_softc_t *sc, int *vpdc); 144183567Sstasstatic int ae_vpd_read_word(ae_softc_t *sc, int reg, uint32_t *word); 145183567Sstasstatic int ae_get_vpd_eaddr(ae_softc_t *sc, uint32_t *eaddr); 146183567Sstasstatic int ae_get_reg_eaddr(ae_softc_t *sc, uint32_t *eaddr); 147183567Sstasstatic void ae_update_stats_rx(uint16_t flags, ae_stats_t *stats); 148183567Sstasstatic void ae_update_stats_tx(uint16_t flags, ae_stats_t *stats); 149183567Sstasstatic void ae_init_tunables(ae_softc_t *sc); 150183567Sstas 151183567Sstasstatic device_method_t ae_methods[] = { 152183567Sstas /* Device interface. */ 153183567Sstas DEVMETHOD(device_probe, ae_probe), 154183567Sstas DEVMETHOD(device_attach, ae_attach), 155183567Sstas DEVMETHOD(device_detach, ae_detach), 156183567Sstas DEVMETHOD(device_shutdown, ae_shutdown), 157183567Sstas DEVMETHOD(device_suspend, ae_suspend), 158183567Sstas DEVMETHOD(device_resume, ae_resume), 159183567Sstas 160183567Sstas /* MII interface. */ 161183567Sstas DEVMETHOD(miibus_readreg, ae_miibus_readreg), 162183567Sstas DEVMETHOD(miibus_writereg, ae_miibus_writereg), 163183567Sstas DEVMETHOD(miibus_statchg, ae_miibus_statchg), 164183567Sstas 165183567Sstas { NULL, NULL } 166183567Sstas}; 167183567Sstasstatic driver_t ae_driver = { 168183567Sstas "ae", 169183567Sstas ae_methods, 170183567Sstas sizeof(ae_softc_t) 171183567Sstas}; 172183567Sstasstatic devclass_t ae_devclass; 173183567Sstas 174183567SstasDRIVER_MODULE(ae, pci, ae_driver, ae_devclass, 0, 0); 175183567SstasDRIVER_MODULE(miibus, ae, miibus_driver, miibus_devclass, 0, 0); 176183567SstasMODULE_DEPEND(ae, pci, 1, 1, 1); 177183567SstasMODULE_DEPEND(ae, ether, 1, 1, 1); 178183567SstasMODULE_DEPEND(ae, miibus, 1, 1, 1); 179183567Sstas 180183567Sstas/* 181183567Sstas * Tunables. 182183567Sstas */ 183183567Sstasstatic int msi_disable = 0; 184183567SstasTUNABLE_INT("hw.ae.msi_disable", &msi_disable); 185183567Sstas 186183567Sstas#define AE_READ_4(sc, reg) \ 187183567Sstas bus_read_4((sc)->mem[0], (reg)) 188183567Sstas#define AE_READ_2(sc, reg) \ 189183567Sstas bus_read_2((sc)->mem[0], (reg)) 190183567Sstas#define AE_READ_1(sc, reg) \ 191183567Sstas bus_read_1((sc)->mem[0], (reg)) 192183567Sstas#define AE_WRITE_4(sc, reg, val) \ 193183567Sstas bus_write_4((sc)->mem[0], (reg), (val)) 194183567Sstas#define AE_WRITE_2(sc, reg, val) \ 195183567Sstas bus_write_2((sc)->mem[0], (reg), (val)) 196183567Sstas#define AE_WRITE_1(sc, reg, val) \ 197183567Sstas bus_write_1((sc)->mem[0], (reg), (val)) 198183567Sstas#define AE_PHY_READ(sc, reg) \ 199183567Sstas ae_miibus_readreg(sc->dev, 0, reg) 200183567Sstas#define AE_PHY_WRITE(sc, reg, val) \ 201183567Sstas ae_miibus_writereg(sc->dev, 0, reg, val) 202183567Sstas#define AE_CHECK_EADDR_VALID(eaddr) \ 203183567Sstas ((eaddr[0] == 0 && eaddr[1] == 0) || \ 204183567Sstas (eaddr[0] == 0xffffffff && eaddr[1] == 0xffff)) 205183567Sstas#define AE_RXD_VLAN(vtag) \ 206183567Sstas (((vtag) >> 4) | (((vtag) & 0x07) << 13) | (((vtag) & 0x08) << 9)) 207183567Sstas#define AE_TXD_VLAN(vtag) \ 208183567Sstas (((vtag) << 4) | (((vtag) >> 13) & 0x07) | (((vtag) >> 9) & 0x08)) 209183567Sstas 210183567Sstasstatic int 211183567Sstasae_probe(device_t dev) 212183567Sstas{ 213183567Sstas uint16_t deviceid, vendorid; 214183567Sstas int i; 215183567Sstas 216183567Sstas vendorid = pci_get_vendor(dev); 217183567Sstas deviceid = pci_get_device(dev); 218183567Sstas 219183567Sstas /* 220183567Sstas * Search through the list of supported devs for matching one. 221183567Sstas */ 222183567Sstas for (i = 0; i < AE_DEVS_COUNT; i++) { 223183567Sstas if (vendorid == ae_devs[i].vendorid && 224183567Sstas deviceid == ae_devs[i].deviceid) { 225183567Sstas device_set_desc(dev, ae_devs[i].name); 226183567Sstas return (BUS_PROBE_DEFAULT); 227183567Sstas } 228183567Sstas } 229183567Sstas return (ENXIO); 230183567Sstas} 231183567Sstas 232183567Sstasstatic int 233183567Sstasae_attach(device_t dev) 234183567Sstas{ 235183567Sstas ae_softc_t *sc; 236183567Sstas struct ifnet *ifp; 237183567Sstas uint8_t chiprev; 238183567Sstas uint32_t pcirev; 239183567Sstas int nmsi, pmc; 240183567Sstas int error; 241183567Sstas 242183567Sstas sc = device_get_softc(dev); /* Automatically allocated and zeroed 243183567Sstas on attach. */ 244183567Sstas KASSERT(sc != NULL, ("[ae, %d]: sc is NULL", __LINE__)); 245183567Sstas sc->dev = dev; 246183567Sstas 247183567Sstas /* 248183567Sstas * Initialize mutexes and tasks. 249183567Sstas */ 250183567Sstas mtx_init(&sc->mtx, device_get_nameunit(dev), MTX_NETWORK_LOCK, MTX_DEF); 251183567Sstas callout_init_mtx(&sc->tick_ch, &sc->mtx, 0); 252183567Sstas TASK_INIT(&sc->int_task, 0, ae_int_task, sc); 253183567Sstas TASK_INIT(&sc->link_task, 0, ae_link_task, sc); 254183567Sstas 255183567Sstas pci_enable_busmaster(dev); /* Enable bus mastering. */ 256183567Sstas 257183567Sstas sc->spec_mem = ae_res_spec_mem; 258183567Sstas 259183567Sstas /* 260183567Sstas * Allocate memory-mapped registers. 261183567Sstas */ 262183567Sstas error = bus_alloc_resources(dev, sc->spec_mem, sc->mem); 263183567Sstas if (error != 0) { 264183567Sstas device_printf(dev, "could not allocate memory resources.\n"); 265183567Sstas sc->spec_mem = NULL; 266183567Sstas goto fail; 267183567Sstas } 268183567Sstas 269183567Sstas /* 270183567Sstas * Retrieve PCI and chip revisions. 271183567Sstas */ 272183567Sstas pcirev = pci_get_revid(dev); 273183567Sstas chiprev = (AE_READ_4(sc, AE_MASTER_REG) >> AE_MASTER_REVNUM_SHIFT) & 274183567Sstas AE_MASTER_REVNUM_MASK; 275183567Sstas if (bootverbose) { 276183567Sstas device_printf(dev, "pci device revision: %#04x\n", pcirev); 277183567Sstas device_printf(dev, "chip id: %#02x\n", chiprev); 278183567Sstas } 279183567Sstas nmsi = pci_msi_count(dev); 280183567Sstas if (bootverbose) 281183567Sstas device_printf(dev, "MSI count: %d.\n", nmsi); 282183567Sstas 283183567Sstas /* 284183567Sstas * Allocate interrupt resources. 285183567Sstas */ 286183567Sstas if (msi_disable == 0 && nmsi == 1) { 287183567Sstas error = pci_alloc_msi(dev, &nmsi); 288183567Sstas if (error == 0) { 289183567Sstas device_printf(dev, "Using MSI messages.\n"); 290183567Sstas sc->spec_irq = ae_res_spec_msi; 291183567Sstas error = bus_alloc_resources(dev, sc->spec_irq, sc->irq); 292183567Sstas if (error != 0) { 293183567Sstas device_printf(dev, "MSI allocation failed.\n"); 294183567Sstas sc->spec_irq = NULL; 295183567Sstas pci_release_msi(dev); 296183567Sstas } else { 297183567Sstas sc->flags |= AE_FLAG_MSI; 298183567Sstas } 299183567Sstas } 300183567Sstas } 301183567Sstas if (sc->spec_irq == NULL) { 302183567Sstas sc->spec_irq = ae_res_spec_irq; 303183567Sstas error = bus_alloc_resources(dev, sc->spec_irq, sc->irq); 304183567Sstas if (error != 0) { 305183567Sstas device_printf(dev, "could not allocate IRQ resources.\n"); 306183567Sstas sc->spec_irq = NULL; 307183567Sstas goto fail; 308183567Sstas } 309183567Sstas } 310183567Sstas 311183567Sstas ae_init_tunables(sc); 312183567Sstas 313183567Sstas ae_phy_reset(sc); /* Reset PHY. */ 314183567Sstas error = ae_reset(sc); /* Reset the controller itself. */ 315183567Sstas if (error != 0) 316183567Sstas goto fail; 317183567Sstas 318183567Sstas ae_pcie_init(sc); 319183567Sstas 320183567Sstas ae_retrieve_address(sc); /* Load MAC address. */ 321183567Sstas 322183567Sstas error = ae_alloc_rings(sc); /* Allocate ring buffers. */ 323183567Sstas if (error != 0) 324183567Sstas goto fail; 325183567Sstas 326183567Sstas ifp = sc->ifp = if_alloc(IFT_ETHER); 327183567Sstas if (ifp == NULL) { 328183567Sstas device_printf(dev, "could not allocate ifnet structure.\n"); 329183567Sstas error = ENXIO; 330202000Sgavin goto fail; 331183567Sstas } 332183567Sstas 333183567Sstas ifp->if_softc = sc; 334183567Sstas if_initname(ifp, device_get_name(dev), device_get_unit(dev)); 335183567Sstas ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 336183567Sstas ifp->if_ioctl = ae_ioctl; 337183567Sstas ifp->if_start = ae_start; 338183567Sstas ifp->if_init = ae_init; 339183567Sstas ifp->if_capabilities = IFCAP_VLAN_MTU | IFCAP_VLAN_HWTAGGING; 340183567Sstas ifp->if_hwassist = 0; 341207554Ssobomax ifp->if_snd.ifq_drv_maxlen = ifqmaxlen; 342183567Sstas IFQ_SET_MAXLEN(&ifp->if_snd, ifp->if_snd.ifq_drv_maxlen); 343183567Sstas IFQ_SET_READY(&ifp->if_snd); 344219902Sjhb if (pci_find_cap(dev, PCIY_PMG, &pmc) == 0) { 345183567Sstas ifp->if_capabilities |= IFCAP_WOL_MAGIC; 346183567Sstas sc->flags |= AE_FLAG_PMG; 347183567Sstas } 348183567Sstas ifp->if_capenable = ifp->if_capabilities; 349183567Sstas 350183567Sstas /* 351183567Sstas * Configure and attach MII bus. 352183567Sstas */ 353213893Smarius error = mii_attach(dev, &sc->miibus, ifp, ae_mediachange, 354213893Smarius ae_mediastatus, BMSR_DEFCAPMASK, AE_PHYADDR_DEFAULT, 355213893Smarius MII_OFFSET_ANY, 0); 356183567Sstas if (error != 0) { 357213893Smarius device_printf(dev, "attaching PHYs failed\n"); 358183567Sstas goto fail; 359183567Sstas } 360183567Sstas 361183567Sstas ether_ifattach(ifp, sc->eaddr); 362183567Sstas /* Tell the upper layer(s) we support long frames. */ 363183567Sstas ifp->if_data.ifi_hdrlen = sizeof(struct ether_vlan_header); 364183567Sstas 365183567Sstas /* 366183567Sstas * Create and run all helper tasks. 367183567Sstas */ 368183567Sstas sc->tq = taskqueue_create_fast("ae_taskq", M_WAITOK, 369183567Sstas taskqueue_thread_enqueue, &sc->tq); 370183567Sstas if (sc->tq == NULL) { 371183567Sstas device_printf(dev, "could not create taskqueue.\n"); 372183567Sstas ether_ifdetach(ifp); 373183567Sstas error = ENXIO; 374183567Sstas goto fail; 375183567Sstas } 376183567Sstas taskqueue_start_threads(&sc->tq, 1, PI_NET, "%s taskq", 377183567Sstas device_get_nameunit(sc->dev)); 378183567Sstas 379183567Sstas /* 380183567Sstas * Configure interrupt handlers. 381183567Sstas */ 382183567Sstas error = bus_setup_intr(dev, sc->irq[0], INTR_TYPE_NET | INTR_MPSAFE, 383183567Sstas ae_intr, NULL, sc, &sc->intrhand); 384183567Sstas if (error != 0) { 385183567Sstas device_printf(dev, "could not set up interrupt handler.\n"); 386183567Sstas taskqueue_free(sc->tq); 387183567Sstas sc->tq = NULL; 388183567Sstas ether_ifdetach(ifp); 389183567Sstas goto fail; 390183567Sstas } 391183567Sstas 392183567Sstasfail: 393183567Sstas if (error != 0) 394183567Sstas ae_detach(dev); 395183567Sstas 396183567Sstas return (error); 397183567Sstas} 398183567Sstas 399217323Smdf#define AE_SYSCTL(stx, parent, name, desc, ptr) \ 400217323Smdf SYSCTL_ADD_UINT(ctx, parent, OID_AUTO, name, CTLFLAG_RD, ptr, 0, desc) 401217323Smdf 402183567Sstasstatic void 403183567Sstasae_init_tunables(ae_softc_t *sc) 404183567Sstas{ 405183567Sstas struct sysctl_ctx_list *ctx; 406183567Sstas struct sysctl_oid *root, *stats, *stats_rx, *stats_tx; 407183567Sstas struct ae_stats *ae_stats; 408183567Sstas 409183567Sstas KASSERT(sc != NULL, ("[ae, %d]: sc is NULL", __LINE__)); 410183567Sstas ae_stats = &sc->stats; 411183567Sstas 412183567Sstas ctx = device_get_sysctl_ctx(sc->dev); 413183567Sstas root = device_get_sysctl_tree(sc->dev); 414183567Sstas stats = SYSCTL_ADD_NODE(ctx, SYSCTL_CHILDREN(root), OID_AUTO, "stats", 415183567Sstas CTLFLAG_RD, NULL, "ae statistics"); 416183567Sstas 417183567Sstas /* 418183567Sstas * Receiver statistcics. 419183567Sstas */ 420183567Sstas stats_rx = SYSCTL_ADD_NODE(ctx, SYSCTL_CHILDREN(stats), OID_AUTO, "rx", 421183567Sstas CTLFLAG_RD, NULL, "Rx MAC statistics"); 422217323Smdf AE_SYSCTL(ctx, SYSCTL_CHILDREN(stats_rx), "bcast", 423217323Smdf "broadcast frames", &ae_stats->rx_bcast); 424217323Smdf AE_SYSCTL(ctx, SYSCTL_CHILDREN(stats_rx), "mcast", 425217323Smdf "multicast frames", &ae_stats->rx_mcast); 426217323Smdf AE_SYSCTL(ctx, SYSCTL_CHILDREN(stats_rx), "pause", 427217323Smdf "PAUSE frames", &ae_stats->rx_pause); 428217323Smdf AE_SYSCTL(ctx, SYSCTL_CHILDREN(stats_rx), "control", 429217323Smdf "control frames", &ae_stats->rx_ctrl); 430217323Smdf AE_SYSCTL(ctx, SYSCTL_CHILDREN(stats_rx), "crc_errors", 431217323Smdf "frames with CRC errors", &ae_stats->rx_crcerr); 432217323Smdf AE_SYSCTL(ctx, SYSCTL_CHILDREN(stats_rx), "code_errors", 433217323Smdf "frames with invalid opcode", &ae_stats->rx_codeerr); 434217323Smdf AE_SYSCTL(ctx, SYSCTL_CHILDREN(stats_rx), "runt", 435217323Smdf "runt frames", &ae_stats->rx_runt); 436217323Smdf AE_SYSCTL(ctx, SYSCTL_CHILDREN(stats_rx), "frag", 437217323Smdf "fragmented frames", &ae_stats->rx_frag); 438217323Smdf AE_SYSCTL(ctx, SYSCTL_CHILDREN(stats_rx), "align_errors", 439217323Smdf "frames with alignment errors", &ae_stats->rx_align); 440217323Smdf AE_SYSCTL(ctx, SYSCTL_CHILDREN(stats_rx), "truncated", 441217323Smdf "frames truncated due to Rx FIFO inderrun", &ae_stats->rx_trunc); 442183567Sstas 443183567Sstas /* 444183567Sstas * Receiver statistcics. 445183567Sstas */ 446183567Sstas stats_tx = SYSCTL_ADD_NODE(ctx, SYSCTL_CHILDREN(stats), OID_AUTO, "tx", 447183567Sstas CTLFLAG_RD, NULL, "Tx MAC statistics"); 448217323Smdf AE_SYSCTL(ctx, SYSCTL_CHILDREN(stats_tx), "bcast", 449217323Smdf "broadcast frames", &ae_stats->tx_bcast); 450217323Smdf AE_SYSCTL(ctx, SYSCTL_CHILDREN(stats_tx), "mcast", 451217323Smdf "multicast frames", &ae_stats->tx_mcast); 452217323Smdf AE_SYSCTL(ctx, SYSCTL_CHILDREN(stats_tx), "pause", 453217323Smdf "PAUSE frames", &ae_stats->tx_pause); 454217323Smdf AE_SYSCTL(ctx, SYSCTL_CHILDREN(stats_tx), "control", 455217323Smdf "control frames", &ae_stats->tx_ctrl); 456217323Smdf AE_SYSCTL(ctx, SYSCTL_CHILDREN(stats_tx), "defers", 457217323Smdf "deferrals occuried", &ae_stats->tx_defer); 458217323Smdf AE_SYSCTL(ctx, SYSCTL_CHILDREN(stats_tx), "exc_defers", 459217323Smdf "excessive deferrals occuried", &ae_stats->tx_excdefer); 460217323Smdf AE_SYSCTL(ctx, SYSCTL_CHILDREN(stats_tx), "singlecols", 461217323Smdf "single collisions occuried", &ae_stats->tx_singlecol); 462217323Smdf AE_SYSCTL(ctx, SYSCTL_CHILDREN(stats_tx), "multicols", 463217323Smdf "multiple collisions occuried", &ae_stats->tx_multicol); 464217323Smdf AE_SYSCTL(ctx, SYSCTL_CHILDREN(stats_tx), "latecols", 465217323Smdf "late collisions occuried", &ae_stats->tx_latecol); 466217323Smdf AE_SYSCTL(ctx, SYSCTL_CHILDREN(stats_tx), "aborts", 467217323Smdf "transmit aborts due collisions", &ae_stats->tx_abortcol); 468217323Smdf AE_SYSCTL(ctx, SYSCTL_CHILDREN(stats_tx), "underruns", 469217323Smdf "Tx FIFO underruns", &ae_stats->tx_underrun); 470183567Sstas} 471183567Sstas 472183567Sstasstatic void 473183567Sstasae_pcie_init(ae_softc_t *sc) 474183567Sstas{ 475183567Sstas 476183567Sstas AE_WRITE_4(sc, AE_PCIE_LTSSM_TESTMODE_REG, AE_PCIE_LTSSM_TESTMODE_DEFAULT); 477183567Sstas AE_WRITE_4(sc, AE_PCIE_DLL_TX_CTRL_REG, AE_PCIE_DLL_TX_CTRL_DEFAULT); 478183567Sstas} 479183567Sstas 480183567Sstasstatic void 481183567Sstasae_phy_reset(ae_softc_t *sc) 482183567Sstas{ 483183567Sstas 484183567Sstas AE_WRITE_4(sc, AE_PHY_ENABLE_REG, AE_PHY_ENABLE); 485183567Sstas DELAY(1000); /* XXX: pause(9) ? */ 486183567Sstas} 487183567Sstas 488183567Sstasstatic int 489183567Sstasae_reset(ae_softc_t *sc) 490183567Sstas{ 491183567Sstas int i; 492183567Sstas 493183567Sstas /* 494183567Sstas * Issue a soft reset. 495183567Sstas */ 496183567Sstas AE_WRITE_4(sc, AE_MASTER_REG, AE_MASTER_SOFT_RESET); 497183567Sstas bus_barrier(sc->mem[0], AE_MASTER_REG, 4, 498183567Sstas BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE); 499183567Sstas 500183567Sstas /* 501183567Sstas * Wait for reset to complete. 502183567Sstas */ 503183567Sstas for (i = 0; i < AE_RESET_TIMEOUT; i++) { 504183567Sstas if ((AE_READ_4(sc, AE_MASTER_REG) & AE_MASTER_SOFT_RESET) == 0) 505183567Sstas break; 506183567Sstas DELAY(10); 507183567Sstas } 508183567Sstas if (i == AE_RESET_TIMEOUT) { 509183567Sstas device_printf(sc->dev, "reset timeout.\n"); 510183567Sstas return (ENXIO); 511183567Sstas } 512183567Sstas 513183567Sstas /* 514183567Sstas * Wait for everything to enter idle state. 515183567Sstas */ 516183567Sstas for (i = 0; i < AE_IDLE_TIMEOUT; i++) { 517183567Sstas if (AE_READ_4(sc, AE_IDLE_REG) == 0) 518183567Sstas break; 519183567Sstas DELAY(100); 520183567Sstas } 521183567Sstas if (i == AE_IDLE_TIMEOUT) { 522183567Sstas device_printf(sc->dev, "could not enter idle state.\n"); 523183567Sstas return (ENXIO); 524183567Sstas } 525183567Sstas return (0); 526183567Sstas} 527183567Sstas 528183567Sstasstatic void 529183567Sstasae_init(void *arg) 530183567Sstas{ 531183567Sstas ae_softc_t *sc; 532183567Sstas 533183567Sstas sc = (ae_softc_t *)arg; 534183567Sstas AE_LOCK(sc); 535183567Sstas ae_init_locked(sc); 536183567Sstas AE_UNLOCK(sc); 537183567Sstas} 538183567Sstas 539183567Sstasstatic void 540183567Sstasae_phy_init(ae_softc_t *sc) 541183567Sstas{ 542183567Sstas 543183567Sstas /* 544183567Sstas * Enable link status change interrupt. 545183567Sstas * XXX magic numbers. 546183567Sstas */ 547183567Sstas#ifdef notyet 548183567Sstas AE_PHY_WRITE(sc, 18, 0xc00); 549183567Sstas#endif 550183567Sstas} 551183567Sstas 552183567Sstasstatic int 553183567Sstasae_init_locked(ae_softc_t *sc) 554183567Sstas{ 555183567Sstas struct ifnet *ifp; 556183567Sstas struct mii_data *mii; 557183567Sstas uint8_t eaddr[ETHER_ADDR_LEN]; 558183567Sstas uint32_t val; 559183567Sstas bus_addr_t addr; 560183567Sstas 561183567Sstas AE_LOCK_ASSERT(sc); 562183567Sstas 563183567Sstas ifp = sc->ifp; 564212968Syongari if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0) 565212968Syongari return (0); 566183567Sstas mii = device_get_softc(sc->miibus); 567183567Sstas 568183567Sstas ae_stop(sc); 569183567Sstas ae_reset(sc); 570183567Sstas ae_pcie_init(sc); /* Initialize PCIE stuff. */ 571183567Sstas ae_phy_init(sc); 572183567Sstas ae_powersave_disable(sc); 573183567Sstas 574183567Sstas /* 575183567Sstas * Clear and disable interrupts. 576183567Sstas */ 577183567Sstas AE_WRITE_4(sc, AE_ISR_REG, 0xffffffff); 578183567Sstas 579183567Sstas /* 580183567Sstas * Set the MAC address. 581183567Sstas */ 582183567Sstas bcopy(IF_LLADDR(ifp), eaddr, ETHER_ADDR_LEN); 583183567Sstas val = eaddr[2] << 24 | eaddr[3] << 16 | eaddr[4] << 8 | eaddr[5]; 584183567Sstas AE_WRITE_4(sc, AE_EADDR0_REG, val); 585183567Sstas val = eaddr[0] << 8 | eaddr[1]; 586183567Sstas AE_WRITE_4(sc, AE_EADDR1_REG, val); 587183567Sstas 588253406Syongari bzero(sc->rxd_base_dma, AE_RXD_COUNT_DEFAULT * 1536 + AE_RXD_PADDING); 589253404Syongari bzero(sc->txd_base, AE_TXD_BUFSIZE_DEFAULT); 590253404Syongari bzero(sc->txs_base, AE_TXS_COUNT_DEFAULT * 4); 591183567Sstas /* 592183567Sstas * Set ring buffers base addresses. 593183567Sstas */ 594183567Sstas addr = sc->dma_rxd_busaddr; 595183567Sstas AE_WRITE_4(sc, AE_DESC_ADDR_HI_REG, BUS_ADDR_HI(addr)); 596183567Sstas AE_WRITE_4(sc, AE_RXD_ADDR_LO_REG, BUS_ADDR_LO(addr)); 597183567Sstas addr = sc->dma_txd_busaddr; 598183567Sstas AE_WRITE_4(sc, AE_TXD_ADDR_LO_REG, BUS_ADDR_LO(addr)); 599183567Sstas addr = sc->dma_txs_busaddr; 600183567Sstas AE_WRITE_4(sc, AE_TXS_ADDR_LO_REG, BUS_ADDR_LO(addr)); 601183567Sstas 602183567Sstas /* 603183567Sstas * Configure ring buffers sizes. 604183567Sstas */ 605183567Sstas AE_WRITE_2(sc, AE_RXD_COUNT_REG, AE_RXD_COUNT_DEFAULT); 606183567Sstas AE_WRITE_2(sc, AE_TXD_BUFSIZE_REG, AE_TXD_BUFSIZE_DEFAULT / 4); 607183567Sstas AE_WRITE_2(sc, AE_TXS_COUNT_REG, AE_TXS_COUNT_DEFAULT); 608183567Sstas 609183567Sstas /* 610183567Sstas * Configure interframe gap parameters. 611183567Sstas */ 612183567Sstas val = ((AE_IFG_TXIPG_DEFAULT << AE_IFG_TXIPG_SHIFT) & 613183567Sstas AE_IFG_TXIPG_MASK) | 614183567Sstas ((AE_IFG_RXIPG_DEFAULT << AE_IFG_RXIPG_SHIFT) & 615183567Sstas AE_IFG_RXIPG_MASK) | 616183567Sstas ((AE_IFG_IPGR1_DEFAULT << AE_IFG_IPGR1_SHIFT) & 617183567Sstas AE_IFG_IPGR1_MASK) | 618183567Sstas ((AE_IFG_IPGR2_DEFAULT << AE_IFG_IPGR2_SHIFT) & 619183567Sstas AE_IFG_IPGR2_MASK); 620183567Sstas AE_WRITE_4(sc, AE_IFG_REG, val); 621183567Sstas 622183567Sstas /* 623183567Sstas * Configure half-duplex operation. 624183567Sstas */ 625183567Sstas val = ((AE_HDPX_LCOL_DEFAULT << AE_HDPX_LCOL_SHIFT) & 626183567Sstas AE_HDPX_LCOL_MASK) | 627183567Sstas ((AE_HDPX_RETRY_DEFAULT << AE_HDPX_RETRY_SHIFT) & 628183567Sstas AE_HDPX_RETRY_MASK) | 629183567Sstas ((AE_HDPX_ABEBT_DEFAULT << AE_HDPX_ABEBT_SHIFT) & 630183567Sstas AE_HDPX_ABEBT_MASK) | 631183567Sstas ((AE_HDPX_JAMIPG_DEFAULT << AE_HDPX_JAMIPG_SHIFT) & 632183567Sstas AE_HDPX_JAMIPG_MASK) | AE_HDPX_EXC_EN; 633183567Sstas AE_WRITE_4(sc, AE_HDPX_REG, val); 634183567Sstas 635183567Sstas /* 636183567Sstas * Configure interrupt moderate timer. 637183567Sstas */ 638183567Sstas AE_WRITE_2(sc, AE_IMT_REG, AE_IMT_DEFAULT); 639183567Sstas val = AE_READ_4(sc, AE_MASTER_REG); 640183567Sstas val |= AE_MASTER_IMT_EN; 641183567Sstas AE_WRITE_4(sc, AE_MASTER_REG, val); 642183567Sstas 643183567Sstas /* 644183567Sstas * Configure interrupt clearing timer. 645183567Sstas */ 646183567Sstas AE_WRITE_2(sc, AE_ICT_REG, AE_ICT_DEFAULT); 647183567Sstas 648183567Sstas /* 649183567Sstas * Configure MTU. 650183567Sstas */ 651183567Sstas val = ifp->if_mtu + ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN + 652183567Sstas ETHER_CRC_LEN; 653183567Sstas AE_WRITE_2(sc, AE_MTU_REG, val); 654183567Sstas 655183567Sstas /* 656183567Sstas * Configure cut-through threshold. 657183567Sstas */ 658183567Sstas AE_WRITE_4(sc, AE_CUT_THRESH_REG, AE_CUT_THRESH_DEFAULT); 659183567Sstas 660183567Sstas /* 661183567Sstas * Configure flow control. 662183567Sstas */ 663183567Sstas AE_WRITE_2(sc, AE_FLOW_THRESH_HI_REG, (AE_RXD_COUNT_DEFAULT / 8) * 7); 664183567Sstas AE_WRITE_2(sc, AE_FLOW_THRESH_LO_REG, (AE_RXD_COUNT_MIN / 8) > 665183567Sstas (AE_RXD_COUNT_DEFAULT / 12) ? (AE_RXD_COUNT_MIN / 8) : 666183567Sstas (AE_RXD_COUNT_DEFAULT / 12)); 667183567Sstas 668183567Sstas /* 669183567Sstas * Init mailboxes. 670183567Sstas */ 671183567Sstas sc->txd_cur = sc->rxd_cur = 0; 672183567Sstas sc->txs_ack = sc->txd_ack = 0; 673183567Sstas sc->rxd_cur = 0; 674183567Sstas AE_WRITE_2(sc, AE_MB_TXD_IDX_REG, sc->txd_cur); 675183567Sstas AE_WRITE_2(sc, AE_MB_RXD_IDX_REG, sc->rxd_cur); 676183567Sstas 677183567Sstas sc->tx_inproc = 0; /* Number of packets the chip processes now. */ 678183567Sstas sc->flags |= AE_FLAG_TXAVAIL; /* Free Tx's available. */ 679183567Sstas 680183567Sstas /* 681183567Sstas * Enable DMA. 682183567Sstas */ 683183567Sstas AE_WRITE_1(sc, AE_DMAREAD_REG, AE_DMAREAD_EN); 684183567Sstas AE_WRITE_1(sc, AE_DMAWRITE_REG, AE_DMAWRITE_EN); 685183567Sstas 686183567Sstas /* 687183567Sstas * Check if everything is OK. 688183567Sstas */ 689183567Sstas val = AE_READ_4(sc, AE_ISR_REG); 690183567Sstas if ((val & AE_ISR_PHY_LINKDOWN) != 0) { 691183567Sstas device_printf(sc->dev, "Initialization failed.\n"); 692183567Sstas return (ENXIO); 693183567Sstas } 694183567Sstas 695183567Sstas /* 696183567Sstas * Clear interrupt status. 697183567Sstas */ 698183567Sstas AE_WRITE_4(sc, AE_ISR_REG, 0x3fffffff); 699183567Sstas AE_WRITE_4(sc, AE_ISR_REG, 0x0); 700183567Sstas 701183567Sstas /* 702183567Sstas * Enable interrupts. 703183567Sstas */ 704183567Sstas val = AE_READ_4(sc, AE_MASTER_REG); 705183567Sstas AE_WRITE_4(sc, AE_MASTER_REG, val | AE_MASTER_MANUAL_INT); 706183567Sstas AE_WRITE_4(sc, AE_IMR_REG, AE_IMR_DEFAULT); 707183567Sstas 708183567Sstas /* 709183567Sstas * Disable WOL. 710183567Sstas */ 711183567Sstas AE_WRITE_4(sc, AE_WOL_REG, 0); 712183567Sstas 713183567Sstas /* 714183567Sstas * Configure MAC. 715183567Sstas */ 716183567Sstas val = AE_MAC_TX_CRC_EN | AE_MAC_TX_AUTOPAD | 717183567Sstas AE_MAC_FULL_DUPLEX | AE_MAC_CLK_PHY | 718183567Sstas AE_MAC_TX_FLOW_EN | AE_MAC_RX_FLOW_EN | 719183567Sstas ((AE_HALFBUF_DEFAULT << AE_HALFBUF_SHIFT) & AE_HALFBUF_MASK) | 720183567Sstas ((AE_MAC_PREAMBLE_DEFAULT << AE_MAC_PREAMBLE_SHIFT) & 721183567Sstas AE_MAC_PREAMBLE_MASK); 722183567Sstas AE_WRITE_4(sc, AE_MAC_REG, val); 723183567Sstas 724183567Sstas /* 725183567Sstas * Configure Rx MAC. 726183567Sstas */ 727183567Sstas ae_rxfilter(sc); 728183567Sstas ae_rxvlan(sc); 729183567Sstas 730183567Sstas /* 731183567Sstas * Enable Tx/Rx. 732183567Sstas */ 733183567Sstas val = AE_READ_4(sc, AE_MAC_REG); 734183567Sstas AE_WRITE_4(sc, AE_MAC_REG, val | AE_MAC_TX_EN | AE_MAC_RX_EN); 735183567Sstas 736183567Sstas sc->flags &= ~AE_FLAG_LINK; 737183567Sstas mii_mediachg(mii); /* Switch to the current media. */ 738183567Sstas 739183567Sstas callout_reset(&sc->tick_ch, hz, ae_tick, sc); 740183567Sstas 741183567Sstas ifp->if_drv_flags |= IFF_DRV_RUNNING; 742183567Sstas ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 743183567Sstas 744183567Sstas#ifdef AE_DEBUG 745183567Sstas device_printf(sc->dev, "Initialization complete.\n"); 746183567Sstas#endif 747183567Sstas 748183567Sstas return (0); 749183567Sstas} 750183567Sstas 751188127Simpstatic int 752183567Sstasae_detach(device_t dev) 753183567Sstas{ 754183567Sstas struct ae_softc *sc; 755183567Sstas struct ifnet *ifp; 756183567Sstas 757183567Sstas sc = device_get_softc(dev); 758183567Sstas KASSERT(sc != NULL, ("[ae: %d]: sc is NULL", __LINE__)); 759183567Sstas ifp = sc->ifp; 760183567Sstas if (device_is_attached(dev)) { 761183567Sstas AE_LOCK(sc); 762183567Sstas sc->flags |= AE_FLAG_DETACH; 763183567Sstas ae_stop(sc); 764183567Sstas AE_UNLOCK(sc); 765183567Sstas callout_drain(&sc->tick_ch); 766183567Sstas taskqueue_drain(sc->tq, &sc->int_task); 767183567Sstas taskqueue_drain(taskqueue_swi, &sc->link_task); 768183567Sstas ether_ifdetach(ifp); 769183567Sstas } 770183567Sstas if (sc->tq != NULL) { 771183567Sstas taskqueue_drain(sc->tq, &sc->int_task); 772183567Sstas taskqueue_free(sc->tq); 773183567Sstas sc->tq = NULL; 774183567Sstas } 775183567Sstas if (sc->miibus != NULL) { 776183567Sstas device_delete_child(dev, sc->miibus); 777183567Sstas sc->miibus = NULL; 778183567Sstas } 779183567Sstas bus_generic_detach(sc->dev); 780183567Sstas ae_dma_free(sc); 781183567Sstas if (sc->intrhand != NULL) { 782183567Sstas bus_teardown_intr(dev, sc->irq[0], sc->intrhand); 783183567Sstas sc->intrhand = NULL; 784183567Sstas } 785183567Sstas if (ifp != NULL) { 786183567Sstas if_free(ifp); 787183567Sstas sc->ifp = NULL; 788183567Sstas } 789183567Sstas if (sc->spec_irq != NULL) 790183567Sstas bus_release_resources(dev, sc->spec_irq, sc->irq); 791183567Sstas if (sc->spec_mem != NULL) 792183567Sstas bus_release_resources(dev, sc->spec_mem, sc->mem); 793183567Sstas if ((sc->flags & AE_FLAG_MSI) != 0) 794183567Sstas pci_release_msi(dev); 795183567Sstas mtx_destroy(&sc->mtx); 796183567Sstas 797183567Sstas return (0); 798183567Sstas} 799183567Sstas 800183567Sstasstatic int 801183567Sstasae_miibus_readreg(device_t dev, int phy, int reg) 802183567Sstas{ 803183567Sstas ae_softc_t *sc; 804183567Sstas uint32_t val; 805183567Sstas int i; 806183567Sstas 807183567Sstas sc = device_get_softc(dev); 808183567Sstas KASSERT(sc != NULL, ("[ae, %d]: sc is NULL", __LINE__)); 809183567Sstas 810183567Sstas /* 811183567Sstas * Locking is done in upper layers. 812183567Sstas */ 813183567Sstas 814183567Sstas val = ((reg << AE_MDIO_REGADDR_SHIFT) & AE_MDIO_REGADDR_MASK) | 815183567Sstas AE_MDIO_START | AE_MDIO_READ | AE_MDIO_SUP_PREAMBLE | 816183567Sstas ((AE_MDIO_CLK_25_4 << AE_MDIO_CLK_SHIFT) & AE_MDIO_CLK_MASK); 817183567Sstas AE_WRITE_4(sc, AE_MDIO_REG, val); 818183567Sstas 819183567Sstas /* 820183567Sstas * Wait for operation to complete. 821183567Sstas */ 822183567Sstas for (i = 0; i < AE_MDIO_TIMEOUT; i++) { 823183567Sstas DELAY(2); 824183567Sstas val = AE_READ_4(sc, AE_MDIO_REG); 825183567Sstas if ((val & (AE_MDIO_START | AE_MDIO_BUSY)) == 0) 826183567Sstas break; 827183567Sstas } 828183567Sstas if (i == AE_MDIO_TIMEOUT) { 829183567Sstas device_printf(sc->dev, "phy read timeout: %d.\n", reg); 830183567Sstas return (0); 831183567Sstas } 832183567Sstas return ((val << AE_MDIO_DATA_SHIFT) & AE_MDIO_DATA_MASK); 833183567Sstas} 834183567Sstas 835183567Sstasstatic int 836183567Sstasae_miibus_writereg(device_t dev, int phy, int reg, int val) 837183567Sstas{ 838183567Sstas ae_softc_t *sc; 839183567Sstas uint32_t aereg; 840183567Sstas int i; 841183567Sstas 842183567Sstas sc = device_get_softc(dev); 843183567Sstas KASSERT(sc != NULL, ("[ae, %d]: sc is NULL", __LINE__)); 844183567Sstas 845183567Sstas /* 846183567Sstas * Locking is done in upper layers. 847183567Sstas */ 848183567Sstas 849183567Sstas aereg = ((reg << AE_MDIO_REGADDR_SHIFT) & AE_MDIO_REGADDR_MASK) | 850183567Sstas AE_MDIO_START | AE_MDIO_SUP_PREAMBLE | 851183567Sstas ((AE_MDIO_CLK_25_4 << AE_MDIO_CLK_SHIFT) & AE_MDIO_CLK_MASK) | 852183567Sstas ((val << AE_MDIO_DATA_SHIFT) & AE_MDIO_DATA_MASK); 853183567Sstas AE_WRITE_4(sc, AE_MDIO_REG, aereg); 854183567Sstas 855183567Sstas /* 856183567Sstas * Wait for operation to complete. 857183567Sstas */ 858183567Sstas for (i = 0; i < AE_MDIO_TIMEOUT; i++) { 859183567Sstas DELAY(2); 860183567Sstas aereg = AE_READ_4(sc, AE_MDIO_REG); 861183567Sstas if ((aereg & (AE_MDIO_START | AE_MDIO_BUSY)) == 0) 862183567Sstas break; 863183567Sstas } 864183567Sstas if (i == AE_MDIO_TIMEOUT) { 865183567Sstas device_printf(sc->dev, "phy write timeout: %d.\n", reg); 866183567Sstas } 867183567Sstas return (0); 868183567Sstas} 869183567Sstas 870183567Sstasstatic void 871183567Sstasae_miibus_statchg(device_t dev) 872183567Sstas{ 873183567Sstas ae_softc_t *sc; 874183567Sstas 875183567Sstas sc = device_get_softc(dev); 876183567Sstas taskqueue_enqueue(taskqueue_swi, &sc->link_task); 877183567Sstas} 878183567Sstas 879183567Sstasstatic void 880183567Sstasae_mediastatus(struct ifnet *ifp, struct ifmediareq *ifmr) 881183567Sstas{ 882183567Sstas ae_softc_t *sc; 883183567Sstas struct mii_data *mii; 884183567Sstas 885183567Sstas sc = ifp->if_softc; 886183567Sstas KASSERT(sc != NULL, ("[ae, %d]: sc is NULL", __LINE__)); 887183567Sstas 888183567Sstas AE_LOCK(sc); 889183567Sstas mii = device_get_softc(sc->miibus); 890183567Sstas mii_pollstat(mii); 891183567Sstas ifmr->ifm_status = mii->mii_media_status; 892183567Sstas ifmr->ifm_active = mii->mii_media_active; 893183567Sstas AE_UNLOCK(sc); 894183567Sstas} 895183567Sstas 896183567Sstasstatic int 897183567Sstasae_mediachange(struct ifnet *ifp) 898183567Sstas{ 899183567Sstas ae_softc_t *sc; 900183567Sstas struct mii_data *mii; 901183567Sstas struct mii_softc *mii_sc; 902183567Sstas int error; 903183567Sstas 904183567Sstas /* XXX: check IFF_UP ?? */ 905183567Sstas sc = ifp->if_softc; 906183567Sstas KASSERT(sc != NULL, ("[ae, %d]: sc is NULL", __LINE__)); 907183567Sstas AE_LOCK(sc); 908183567Sstas mii = device_get_softc(sc->miibus); 909221407Smarius LIST_FOREACH(mii_sc, &mii->mii_phys, mii_list) 910221407Smarius PHY_RESET(mii_sc); 911183567Sstas error = mii_mediachg(mii); 912183567Sstas AE_UNLOCK(sc); 913183567Sstas 914183567Sstas return (error); 915183567Sstas} 916183567Sstas 917183567Sstasstatic int 918183567Sstasae_check_eeprom_present(ae_softc_t *sc, int *vpdc) 919183567Sstas{ 920183567Sstas int error; 921183567Sstas uint32_t val; 922183567Sstas 923183567Sstas KASSERT(vpdc != NULL, ("[ae, %d]: vpdc is NULL!\n", __LINE__)); 924183567Sstas 925183567Sstas /* 926183567Sstas * Not sure why, but Linux does this. 927183567Sstas */ 928183567Sstas val = AE_READ_4(sc, AE_SPICTL_REG); 929183567Sstas if ((val & AE_SPICTL_VPD_EN) != 0) { 930183567Sstas val &= ~AE_SPICTL_VPD_EN; 931183567Sstas AE_WRITE_4(sc, AE_SPICTL_REG, val); 932183567Sstas } 933219902Sjhb error = pci_find_cap(sc->dev, PCIY_VPD, vpdc); 934183567Sstas return (error); 935183567Sstas} 936183567Sstas 937183567Sstasstatic int 938183567Sstasae_vpd_read_word(ae_softc_t *sc, int reg, uint32_t *word) 939183567Sstas{ 940183567Sstas uint32_t val; 941183567Sstas int i; 942183567Sstas 943183567Sstas AE_WRITE_4(sc, AE_VPD_DATA_REG, 0); /* Clear register value. */ 944183567Sstas 945183567Sstas /* 946183567Sstas * VPD registers start at offset 0x100. Read them. 947183567Sstas */ 948183567Sstas val = 0x100 + reg * 4; 949183567Sstas AE_WRITE_4(sc, AE_VPD_CAP_REG, (val << AE_VPD_CAP_ADDR_SHIFT) & 950183567Sstas AE_VPD_CAP_ADDR_MASK); 951183567Sstas for (i = 0; i < AE_VPD_TIMEOUT; i++) { 952183567Sstas DELAY(2000); 953183567Sstas val = AE_READ_4(sc, AE_VPD_CAP_REG); 954183567Sstas if ((val & AE_VPD_CAP_DONE) != 0) 955183567Sstas break; 956183567Sstas } 957183567Sstas if (i == AE_VPD_TIMEOUT) { 958183567Sstas device_printf(sc->dev, "timeout reading VPD register %d.\n", 959183567Sstas reg); 960183567Sstas return (ETIMEDOUT); 961183567Sstas } 962183567Sstas *word = AE_READ_4(sc, AE_VPD_DATA_REG); 963183567Sstas return (0); 964183567Sstas} 965183567Sstas 966183567Sstasstatic int 967183567Sstasae_get_vpd_eaddr(ae_softc_t *sc, uint32_t *eaddr) 968183567Sstas{ 969183567Sstas uint32_t word, reg, val; 970183567Sstas int error; 971183567Sstas int found; 972183567Sstas int vpdc; 973183567Sstas int i; 974183567Sstas 975183567Sstas KASSERT(sc != NULL, ("[ae, %d]: sc is NULL", __LINE__)); 976183567Sstas KASSERT(eaddr != NULL, ("[ae, %d]: eaddr is NULL", __LINE__)); 977183567Sstas 978183567Sstas /* 979183567Sstas * Check for EEPROM. 980183567Sstas */ 981183567Sstas error = ae_check_eeprom_present(sc, &vpdc); 982183567Sstas if (error != 0) 983183567Sstas return (error); 984183567Sstas 985183567Sstas /* 986183567Sstas * Read the VPD configuration space. 987183567Sstas * Each register is prefixed with signature, 988183567Sstas * so we can check if it is valid. 989183567Sstas */ 990183567Sstas for (i = 0, found = 0; i < AE_VPD_NREGS; i++) { 991183567Sstas error = ae_vpd_read_word(sc, i, &word); 992183567Sstas if (error != 0) 993183567Sstas break; 994183567Sstas 995183567Sstas /* 996183567Sstas * Check signature. 997183567Sstas */ 998183567Sstas if ((word & AE_VPD_SIG_MASK) != AE_VPD_SIG) 999183567Sstas break; 1000183567Sstas reg = word >> AE_VPD_REG_SHIFT; 1001183567Sstas i++; /* Move to the next word. */ 1002183567Sstas 1003183567Sstas if (reg != AE_EADDR0_REG && reg != AE_EADDR1_REG) 1004183567Sstas continue; 1005183567Sstas 1006183567Sstas error = ae_vpd_read_word(sc, i, &val); 1007183567Sstas if (error != 0) 1008183567Sstas break; 1009183567Sstas if (reg == AE_EADDR0_REG) 1010183567Sstas eaddr[0] = val; 1011183567Sstas else 1012183567Sstas eaddr[1] = val; 1013183567Sstas found++; 1014183567Sstas } 1015183567Sstas 1016183567Sstas if (found < 2) 1017183567Sstas return (ENOENT); 1018183567Sstas 1019183567Sstas eaddr[1] &= 0xffff; /* Only last 2 bytes are used. */ 1020183567Sstas if (AE_CHECK_EADDR_VALID(eaddr) != 0) { 1021183567Sstas if (bootverbose) 1022183567Sstas device_printf(sc->dev, 1023183567Sstas "VPD ethernet address registers are invalid.\n"); 1024183567Sstas return (EINVAL); 1025183567Sstas } 1026183567Sstas return (0); 1027183567Sstas} 1028183567Sstas 1029183567Sstasstatic int 1030183567Sstasae_get_reg_eaddr(ae_softc_t *sc, uint32_t *eaddr) 1031183567Sstas{ 1032183567Sstas 1033183567Sstas /* 1034183567Sstas * BIOS is supposed to set this. 1035183567Sstas */ 1036183567Sstas eaddr[0] = AE_READ_4(sc, AE_EADDR0_REG); 1037183567Sstas eaddr[1] = AE_READ_4(sc, AE_EADDR1_REG); 1038183567Sstas eaddr[1] &= 0xffff; /* Only last 2 bytes are used. */ 1039183567Sstas 1040183567Sstas if (AE_CHECK_EADDR_VALID(eaddr) != 0) { 1041183567Sstas if (bootverbose) 1042183567Sstas device_printf(sc->dev, 1043200993Sgavin "Ethernet address registers are invalid.\n"); 1044183567Sstas return (EINVAL); 1045183567Sstas } 1046183567Sstas return (0); 1047183567Sstas} 1048183567Sstas 1049183567Sstasstatic void 1050183567Sstasae_retrieve_address(ae_softc_t *sc) 1051183567Sstas{ 1052183567Sstas uint32_t eaddr[2] = {0, 0}; 1053183567Sstas int error; 1054183567Sstas 1055183567Sstas /* 1056183567Sstas *Check for EEPROM. 1057183567Sstas */ 1058183567Sstas error = ae_get_vpd_eaddr(sc, eaddr); 1059183567Sstas if (error != 0) 1060183567Sstas error = ae_get_reg_eaddr(sc, eaddr); 1061183567Sstas if (error != 0) { 1062183567Sstas if (bootverbose) 1063183567Sstas device_printf(sc->dev, 1064183567Sstas "Generating random ethernet address.\n"); 1065183567Sstas eaddr[0] = arc4random(); 1066183567Sstas 1067183567Sstas /* 1068183567Sstas * Set OUI to ASUSTek COMPUTER INC. 1069183567Sstas */ 1070183567Sstas sc->eaddr[0] = 0x02; /* U/L bit set. */ 1071183567Sstas sc->eaddr[1] = 0x1f; 1072183567Sstas sc->eaddr[2] = 0xc6; 1073183567Sstas sc->eaddr[3] = (eaddr[0] >> 16) & 0xff; 1074183567Sstas sc->eaddr[4] = (eaddr[0] >> 8) & 0xff; 1075183567Sstas sc->eaddr[5] = (eaddr[0] >> 0) & 0xff; 1076183567Sstas } else { 1077183567Sstas sc->eaddr[0] = (eaddr[1] >> 8) & 0xff; 1078183567Sstas sc->eaddr[1] = (eaddr[1] >> 0) & 0xff; 1079183567Sstas sc->eaddr[2] = (eaddr[0] >> 24) & 0xff; 1080183567Sstas sc->eaddr[3] = (eaddr[0] >> 16) & 0xff; 1081183567Sstas sc->eaddr[4] = (eaddr[0] >> 8) & 0xff; 1082183567Sstas sc->eaddr[5] = (eaddr[0] >> 0) & 0xff; 1083183567Sstas } 1084183567Sstas} 1085183567Sstas 1086183567Sstasstatic void 1087183567Sstasae_dmamap_cb(void *arg, bus_dma_segment_t *segs, int nsegs, int error) 1088183567Sstas{ 1089183567Sstas bus_addr_t *addr = arg; 1090183567Sstas 1091183567Sstas if (error != 0) 1092183567Sstas return; 1093183567Sstas KASSERT(nsegs == 1, ("[ae, %d]: %d segments instead of 1!", __LINE__, 1094183567Sstas nsegs)); 1095183567Sstas *addr = segs[0].ds_addr; 1096183567Sstas} 1097183567Sstas 1098183567Sstasstatic int 1099183567Sstasae_alloc_rings(ae_softc_t *sc) 1100183567Sstas{ 1101183567Sstas bus_addr_t busaddr; 1102183567Sstas int error; 1103183567Sstas 1104183567Sstas /* 1105183567Sstas * Create parent DMA tag. 1106183567Sstas */ 1107183567Sstas error = bus_dma_tag_create(bus_get_dma_tag(sc->dev), 1108183567Sstas 1, 0, BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, 1109183567Sstas NULL, NULL, BUS_SPACE_MAXSIZE_32BIT, 0, 1110183567Sstas BUS_SPACE_MAXSIZE_32BIT, 0, NULL, NULL, 1111183567Sstas &sc->dma_parent_tag); 1112183567Sstas if (error != 0) { 1113183567Sstas device_printf(sc->dev, "could not creare parent DMA tag.\n"); 1114183567Sstas return (error); 1115183567Sstas } 1116183567Sstas 1117183567Sstas /* 1118183567Sstas * Create DMA tag for TxD. 1119183567Sstas */ 1120183567Sstas error = bus_dma_tag_create(sc->dma_parent_tag, 1121253404Syongari 8, 0, BUS_SPACE_MAXADDR, BUS_SPACE_MAXADDR, 1122183567Sstas NULL, NULL, AE_TXD_BUFSIZE_DEFAULT, 1, 1123183567Sstas AE_TXD_BUFSIZE_DEFAULT, 0, NULL, NULL, 1124183567Sstas &sc->dma_txd_tag); 1125183567Sstas if (error != 0) { 1126183567Sstas device_printf(sc->dev, "could not creare TxD DMA tag.\n"); 1127183567Sstas return (error); 1128183567Sstas } 1129183567Sstas 1130183567Sstas /* 1131183567Sstas * Create DMA tag for TxS. 1132183567Sstas */ 1133183567Sstas error = bus_dma_tag_create(sc->dma_parent_tag, 1134253404Syongari 8, 0, BUS_SPACE_MAXADDR, BUS_SPACE_MAXADDR, 1135183567Sstas NULL, NULL, AE_TXS_COUNT_DEFAULT * 4, 1, 1136183567Sstas AE_TXS_COUNT_DEFAULT * 4, 0, NULL, NULL, 1137183567Sstas &sc->dma_txs_tag); 1138183567Sstas if (error != 0) { 1139183567Sstas device_printf(sc->dev, "could not creare TxS DMA tag.\n"); 1140183567Sstas return (error); 1141183567Sstas } 1142183567Sstas 1143183567Sstas /* 1144183567Sstas * Create DMA tag for RxD. 1145183567Sstas */ 1146183567Sstas error = bus_dma_tag_create(sc->dma_parent_tag, 1147183567Sstas 128, 0, BUS_SPACE_MAXADDR, BUS_SPACE_MAXADDR, 1148253406Syongari NULL, NULL, AE_RXD_COUNT_DEFAULT * 1536 + AE_RXD_PADDING, 1, 1149253406Syongari AE_RXD_COUNT_DEFAULT * 1536 + AE_RXD_PADDING, 0, NULL, NULL, 1150183567Sstas &sc->dma_rxd_tag); 1151183567Sstas if (error != 0) { 1152183567Sstas device_printf(sc->dev, "could not creare TxS DMA tag.\n"); 1153183567Sstas return (error); 1154183567Sstas } 1155183567Sstas 1156183567Sstas /* 1157183567Sstas * Allocate TxD DMA memory. 1158183567Sstas */ 1159183567Sstas error = bus_dmamem_alloc(sc->dma_txd_tag, (void **)&sc->txd_base, 1160183567Sstas BUS_DMA_WAITOK | BUS_DMA_ZERO | BUS_DMA_COHERENT, 1161183567Sstas &sc->dma_txd_map); 1162183567Sstas if (error != 0) { 1163183567Sstas device_printf(sc->dev, 1164183567Sstas "could not allocate DMA memory for TxD ring.\n"); 1165183567Sstas return (error); 1166183567Sstas } 1167183567Sstas error = bus_dmamap_load(sc->dma_txd_tag, sc->dma_txd_map, sc->txd_base, 1168183567Sstas AE_TXD_BUFSIZE_DEFAULT, ae_dmamap_cb, &busaddr, BUS_DMA_NOWAIT); 1169183567Sstas if (error != 0 || busaddr == 0) { 1170183567Sstas device_printf(sc->dev, 1171183567Sstas "could not load DMA map for TxD ring.\n"); 1172183567Sstas return (error); 1173183567Sstas } 1174183567Sstas sc->dma_txd_busaddr = busaddr; 1175183567Sstas 1176183567Sstas /* 1177183567Sstas * Allocate TxS DMA memory. 1178183567Sstas */ 1179183567Sstas error = bus_dmamem_alloc(sc->dma_txs_tag, (void **)&sc->txs_base, 1180183567Sstas BUS_DMA_WAITOK | BUS_DMA_ZERO | BUS_DMA_COHERENT, 1181183567Sstas &sc->dma_txs_map); 1182183567Sstas if (error != 0) { 1183183567Sstas device_printf(sc->dev, 1184183567Sstas "could not allocate DMA memory for TxS ring.\n"); 1185183567Sstas return (error); 1186183567Sstas } 1187183567Sstas error = bus_dmamap_load(sc->dma_txs_tag, sc->dma_txs_map, sc->txs_base, 1188183567Sstas AE_TXS_COUNT_DEFAULT * 4, ae_dmamap_cb, &busaddr, BUS_DMA_NOWAIT); 1189183567Sstas if (error != 0 || busaddr == 0) { 1190183567Sstas device_printf(sc->dev, 1191183567Sstas "could not load DMA map for TxS ring.\n"); 1192183567Sstas return (error); 1193183567Sstas } 1194183567Sstas sc->dma_txs_busaddr = busaddr; 1195183567Sstas 1196183567Sstas /* 1197183567Sstas * Allocate RxD DMA memory. 1198183567Sstas */ 1199183567Sstas error = bus_dmamem_alloc(sc->dma_rxd_tag, (void **)&sc->rxd_base_dma, 1200183567Sstas BUS_DMA_WAITOK | BUS_DMA_ZERO | BUS_DMA_COHERENT, 1201183567Sstas &sc->dma_rxd_map); 1202183567Sstas if (error != 0) { 1203183567Sstas device_printf(sc->dev, 1204183567Sstas "could not allocate DMA memory for RxD ring.\n"); 1205183567Sstas return (error); 1206183567Sstas } 1207183567Sstas error = bus_dmamap_load(sc->dma_rxd_tag, sc->dma_rxd_map, 1208253406Syongari sc->rxd_base_dma, AE_RXD_COUNT_DEFAULT * 1536 + AE_RXD_PADDING, 1209253406Syongari ae_dmamap_cb, &busaddr, BUS_DMA_NOWAIT); 1210183567Sstas if (error != 0 || busaddr == 0) { 1211183567Sstas device_printf(sc->dev, 1212183567Sstas "could not load DMA map for RxD ring.\n"); 1213183567Sstas return (error); 1214183567Sstas } 1215253406Syongari sc->dma_rxd_busaddr = busaddr + AE_RXD_PADDING; 1216253406Syongari sc->rxd_base = (ae_rxd_t *)(sc->rxd_base_dma + AE_RXD_PADDING); 1217183567Sstas 1218183567Sstas return (0); 1219183567Sstas} 1220183567Sstas 1221183567Sstasstatic void 1222183567Sstasae_dma_free(ae_softc_t *sc) 1223183567Sstas{ 1224183567Sstas 1225183567Sstas if (sc->dma_txd_tag != NULL) { 1226183567Sstas if (sc->dma_txd_map != NULL) { 1227183567Sstas bus_dmamap_unload(sc->dma_txd_tag, sc->dma_txd_map); 1228183567Sstas if (sc->txd_base != NULL) 1229183567Sstas bus_dmamem_free(sc->dma_txd_tag, sc->txd_base, 1230183567Sstas sc->dma_txd_map); 1231183567Sstas 1232183567Sstas } 1233183567Sstas bus_dma_tag_destroy(sc->dma_txd_tag); 1234183567Sstas sc->dma_txd_map = NULL; 1235183567Sstas sc->dma_txd_tag = NULL; 1236183567Sstas sc->txd_base = NULL; 1237183567Sstas } 1238183567Sstas if (sc->dma_txs_tag != NULL) { 1239183567Sstas if (sc->dma_txs_map != NULL) { 1240183567Sstas bus_dmamap_unload(sc->dma_txs_tag, sc->dma_txs_map); 1241183567Sstas if (sc->txs_base != NULL) 1242183567Sstas bus_dmamem_free(sc->dma_txs_tag, sc->txs_base, 1243183567Sstas sc->dma_txs_map); 1244183567Sstas 1245183567Sstas } 1246183567Sstas bus_dma_tag_destroy(sc->dma_txs_tag); 1247183567Sstas sc->dma_txs_map = NULL; 1248183567Sstas sc->dma_txs_tag = NULL; 1249183567Sstas sc->txs_base = NULL; 1250183567Sstas } 1251183567Sstas if (sc->dma_rxd_tag != NULL) { 1252183567Sstas if (sc->dma_rxd_map != NULL) { 1253183567Sstas bus_dmamap_unload(sc->dma_rxd_tag, sc->dma_rxd_map); 1254183567Sstas if (sc->rxd_base_dma != NULL) 1255183567Sstas bus_dmamem_free(sc->dma_rxd_tag, 1256183567Sstas sc->rxd_base_dma, sc->dma_rxd_map); 1257183567Sstas 1258183567Sstas } 1259183567Sstas bus_dma_tag_destroy(sc->dma_rxd_tag); 1260183567Sstas sc->dma_rxd_map = NULL; 1261183567Sstas sc->dma_rxd_tag = NULL; 1262183567Sstas sc->rxd_base_dma = NULL; 1263183567Sstas } 1264183567Sstas if (sc->dma_parent_tag != NULL) { 1265183567Sstas bus_dma_tag_destroy(sc->dma_parent_tag); 1266183567Sstas sc->dma_parent_tag = NULL; 1267183567Sstas } 1268183567Sstas} 1269183567Sstas 1270183567Sstasstatic int 1271183567Sstasae_shutdown(device_t dev) 1272183567Sstas{ 1273183567Sstas ae_softc_t *sc; 1274183567Sstas int error; 1275183567Sstas 1276183567Sstas sc = device_get_softc(dev); 1277183567Sstas KASSERT(sc != NULL, ("[ae: %d]: sc is NULL", __LINE__)); 1278183567Sstas 1279183567Sstas error = ae_suspend(dev); 1280183567Sstas AE_LOCK(sc); 1281183567Sstas ae_powersave_enable(sc); 1282183567Sstas AE_UNLOCK(sc); 1283183567Sstas return (error); 1284183567Sstas} 1285183567Sstas 1286183567Sstasstatic void 1287183567Sstasae_powersave_disable(ae_softc_t *sc) 1288183567Sstas{ 1289183567Sstas uint32_t val; 1290183567Sstas 1291183567Sstas AE_LOCK_ASSERT(sc); 1292183567Sstas 1293183567Sstas AE_PHY_WRITE(sc, AE_PHY_DBG_ADDR, 0); 1294183567Sstas val = AE_PHY_READ(sc, AE_PHY_DBG_DATA); 1295183567Sstas if (val & AE_PHY_DBG_POWERSAVE) { 1296183567Sstas val &= ~AE_PHY_DBG_POWERSAVE; 1297183567Sstas AE_PHY_WRITE(sc, AE_PHY_DBG_DATA, val); 1298183567Sstas DELAY(1000); 1299183567Sstas } 1300183567Sstas} 1301183567Sstas 1302183567Sstasstatic void 1303183567Sstasae_powersave_enable(ae_softc_t *sc) 1304183567Sstas{ 1305183567Sstas uint32_t val; 1306183567Sstas 1307183567Sstas AE_LOCK_ASSERT(sc); 1308183567Sstas 1309183567Sstas /* 1310183567Sstas * XXX magic numbers. 1311183567Sstas */ 1312183567Sstas AE_PHY_WRITE(sc, AE_PHY_DBG_ADDR, 0); 1313183567Sstas val = AE_PHY_READ(sc, AE_PHY_DBG_DATA); 1314183567Sstas AE_PHY_WRITE(sc, AE_PHY_DBG_ADDR, val | 0x1000); 1315183567Sstas AE_PHY_WRITE(sc, AE_PHY_DBG_ADDR, 2); 1316183567Sstas AE_PHY_WRITE(sc, AE_PHY_DBG_DATA, 0x3000); 1317183567Sstas AE_PHY_WRITE(sc, AE_PHY_DBG_ADDR, 3); 1318183567Sstas AE_PHY_WRITE(sc, AE_PHY_DBG_DATA, 0); 1319183567Sstas} 1320183567Sstas 1321183567Sstasstatic void 1322183567Sstasae_pm_init(ae_softc_t *sc) 1323183567Sstas{ 1324183567Sstas struct ifnet *ifp; 1325183567Sstas uint32_t val; 1326183567Sstas uint16_t pmstat; 1327183567Sstas struct mii_data *mii; 1328183567Sstas int pmc; 1329183567Sstas 1330183567Sstas AE_LOCK_ASSERT(sc); 1331183567Sstas 1332183567Sstas ifp = sc->ifp; 1333183567Sstas if ((sc->flags & AE_FLAG_PMG) == 0) { 1334183567Sstas /* Disable WOL entirely. */ 1335183567Sstas AE_WRITE_4(sc, AE_WOL_REG, 0); 1336183567Sstas return; 1337183567Sstas } 1338183567Sstas 1339183567Sstas /* 1340183567Sstas * Configure WOL if enabled. 1341183567Sstas */ 1342183567Sstas if ((ifp->if_capenable & IFCAP_WOL) != 0) { 1343183567Sstas mii = device_get_softc(sc->miibus); 1344183567Sstas mii_pollstat(mii); 1345183567Sstas if ((mii->mii_media_status & IFM_AVALID) != 0 && 1346183567Sstas (mii->mii_media_status & IFM_ACTIVE) != 0) { 1347183567Sstas AE_WRITE_4(sc, AE_WOL_REG, AE_WOL_MAGIC | \ 1348183567Sstas AE_WOL_MAGIC_PME); 1349183567Sstas 1350183567Sstas /* 1351183567Sstas * Configure MAC. 1352183567Sstas */ 1353183567Sstas val = AE_MAC_RX_EN | AE_MAC_CLK_PHY | \ 1354183567Sstas AE_MAC_TX_CRC_EN | AE_MAC_TX_AUTOPAD | \ 1355183567Sstas ((AE_HALFBUF_DEFAULT << AE_HALFBUF_SHIFT) & \ 1356183567Sstas AE_HALFBUF_MASK) | \ 1357183567Sstas ((AE_MAC_PREAMBLE_DEFAULT << \ 1358183567Sstas AE_MAC_PREAMBLE_SHIFT) & AE_MAC_PREAMBLE_MASK) | \ 1359183567Sstas AE_MAC_BCAST_EN | AE_MAC_MCAST_EN; 1360183567Sstas if ((IFM_OPTIONS(mii->mii_media_active) & \ 1361183567Sstas IFM_FDX) != 0) 1362183567Sstas val |= AE_MAC_FULL_DUPLEX; 1363183567Sstas AE_WRITE_4(sc, AE_MAC_REG, val); 1364183567Sstas 1365183567Sstas } else { /* No link. */ 1366183567Sstas AE_WRITE_4(sc, AE_WOL_REG, AE_WOL_LNKCHG | \ 1367183567Sstas AE_WOL_LNKCHG_PME); 1368183567Sstas AE_WRITE_4(sc, AE_MAC_REG, 0); 1369183567Sstas } 1370183567Sstas } else { 1371183567Sstas ae_powersave_enable(sc); 1372183567Sstas } 1373183567Sstas 1374183567Sstas /* 1375183567Sstas * PCIE hacks. Magic numbers. 1376183567Sstas */ 1377183567Sstas val = AE_READ_4(sc, AE_PCIE_PHYMISC_REG); 1378183567Sstas val |= AE_PCIE_PHYMISC_FORCE_RCV_DET; 1379183567Sstas AE_WRITE_4(sc, AE_PCIE_PHYMISC_REG, val); 1380183567Sstas val = AE_READ_4(sc, AE_PCIE_DLL_TX_CTRL_REG); 1381183567Sstas val |= AE_PCIE_DLL_TX_CTRL_SEL_NOR_CLK; 1382183567Sstas AE_WRITE_4(sc, AE_PCIE_DLL_TX_CTRL_REG, val); 1383183567Sstas 1384183567Sstas /* 1385183567Sstas * Configure PME. 1386183567Sstas */ 1387236670Spluknet if (pci_find_cap(sc->dev, PCIY_PMG, &pmc) == 0) { 1388236649Skevlo pmstat = pci_read_config(sc->dev, pmc + PCIR_POWER_STATUS, 2); 1389236649Skevlo pmstat &= ~(PCIM_PSTAT_PME | PCIM_PSTAT_PMEENABLE); 1390236649Skevlo if ((ifp->if_capenable & IFCAP_WOL) != 0) 1391236649Skevlo pmstat |= PCIM_PSTAT_PME | PCIM_PSTAT_PMEENABLE; 1392236649Skevlo pci_write_config(sc->dev, pmc + PCIR_POWER_STATUS, pmstat, 2); 1393236649Skevlo } 1394183567Sstas} 1395183567Sstas 1396183567Sstasstatic int 1397183567Sstasae_suspend(device_t dev) 1398183567Sstas{ 1399183567Sstas ae_softc_t *sc; 1400183567Sstas 1401183567Sstas sc = device_get_softc(dev); 1402183567Sstas 1403183567Sstas AE_LOCK(sc); 1404183567Sstas ae_stop(sc); 1405183567Sstas ae_pm_init(sc); 1406183567Sstas AE_UNLOCK(sc); 1407183567Sstas 1408183567Sstas return (0); 1409183567Sstas} 1410183567Sstas 1411183567Sstasstatic int 1412183567Sstasae_resume(device_t dev) 1413183567Sstas{ 1414183567Sstas ae_softc_t *sc; 1415183567Sstas 1416183567Sstas sc = device_get_softc(dev); 1417183567Sstas KASSERT(sc != NULL, ("[ae, %d]: sc is NULL", __LINE__)); 1418183567Sstas 1419183567Sstas AE_LOCK(sc); 1420183567Sstas AE_READ_4(sc, AE_WOL_REG); /* Clear WOL status. */ 1421183567Sstas if ((sc->ifp->if_flags & IFF_UP) != 0) 1422183567Sstas ae_init_locked(sc); 1423183567Sstas AE_UNLOCK(sc); 1424183567Sstas 1425183567Sstas return (0); 1426183567Sstas} 1427183567Sstas 1428183567Sstasstatic unsigned int 1429183567Sstasae_tx_avail_size(ae_softc_t *sc) 1430183567Sstas{ 1431183567Sstas unsigned int avail; 1432183567Sstas 1433183567Sstas if (sc->txd_cur >= sc->txd_ack) 1434183567Sstas avail = AE_TXD_BUFSIZE_DEFAULT - (sc->txd_cur - sc->txd_ack); 1435183567Sstas else 1436183567Sstas avail = sc->txd_ack - sc->txd_cur; 1437183567Sstas 1438227452Syongari return (avail); 1439183567Sstas} 1440183567Sstas 1441183567Sstasstatic int 1442183567Sstasae_encap(ae_softc_t *sc, struct mbuf **m_head) 1443183567Sstas{ 1444183567Sstas struct mbuf *m0; 1445183567Sstas ae_txd_t *hdr; 1446183567Sstas unsigned int to_end; 1447183567Sstas uint16_t len; 1448183567Sstas 1449183567Sstas AE_LOCK_ASSERT(sc); 1450183567Sstas 1451183567Sstas m0 = *m_head; 1452183567Sstas len = m0->m_pkthdr.len; 1453183567Sstas 1454183567Sstas if ((sc->flags & AE_FLAG_TXAVAIL) == 0 || 1455227452Syongari len + sizeof(ae_txd_t) + 3 > ae_tx_avail_size(sc)) { 1456183567Sstas#ifdef AE_DEBUG 1457183567Sstas if_printf(sc->ifp, "No free Tx available.\n"); 1458183567Sstas#endif 1459183567Sstas return ENOBUFS; 1460183567Sstas } 1461183567Sstas 1462183567Sstas hdr = (ae_txd_t *)(sc->txd_base + sc->txd_cur); 1463183567Sstas bzero(hdr, sizeof(*hdr)); 1464227452Syongari /* Skip header size. */ 1465227452Syongari sc->txd_cur = (sc->txd_cur + sizeof(ae_txd_t)) % AE_TXD_BUFSIZE_DEFAULT; 1466227452Syongari /* Space available to the end of the ring */ 1467227452Syongari to_end = AE_TXD_BUFSIZE_DEFAULT - sc->txd_cur; 1468183567Sstas if (to_end >= len) { 1469183567Sstas m_copydata(m0, 0, len, (caddr_t)(sc->txd_base + sc->txd_cur)); 1470183567Sstas } else { 1471183567Sstas m_copydata(m0, 0, to_end, (caddr_t)(sc->txd_base + 1472183567Sstas sc->txd_cur)); 1473183567Sstas m_copydata(m0, to_end, len - to_end, (caddr_t)sc->txd_base); 1474183567Sstas } 1475183567Sstas 1476183567Sstas /* 1477183567Sstas * Set TxD flags and parameters. 1478183567Sstas */ 1479183567Sstas if ((m0->m_flags & M_VLANTAG) != 0) { 1480183567Sstas hdr->vlan = htole16(AE_TXD_VLAN(m0->m_pkthdr.ether_vtag)); 1481183567Sstas hdr->len = htole16(len | AE_TXD_INSERT_VTAG); 1482183567Sstas } else { 1483183567Sstas hdr->len = htole16(len); 1484183567Sstas } 1485183567Sstas 1486183567Sstas /* 1487183567Sstas * Set current TxD position and round up to a 4-byte boundary. 1488183567Sstas */ 1489183567Sstas sc->txd_cur = ((sc->txd_cur + len + 3) & ~3) % AE_TXD_BUFSIZE_DEFAULT; 1490183567Sstas if (sc->txd_cur == sc->txd_ack) 1491183567Sstas sc->flags &= ~AE_FLAG_TXAVAIL; 1492183567Sstas#ifdef AE_DEBUG 1493183567Sstas if_printf(sc->ifp, "New txd_cur = %d.\n", sc->txd_cur); 1494183567Sstas#endif 1495183567Sstas 1496183567Sstas /* 1497183567Sstas * Update TxS position and check if there are empty TxS available. 1498183567Sstas */ 1499183567Sstas sc->txs_base[sc->txs_cur].flags &= ~htole16(AE_TXS_UPDATE); 1500183567Sstas sc->txs_cur = (sc->txs_cur + 1) % AE_TXS_COUNT_DEFAULT; 1501183567Sstas if (sc->txs_cur == sc->txs_ack) 1502183567Sstas sc->flags &= ~AE_FLAG_TXAVAIL; 1503183567Sstas 1504183567Sstas /* 1505183567Sstas * Synchronize DMA memory. 1506183567Sstas */ 1507183567Sstas bus_dmamap_sync(sc->dma_txd_tag, sc->dma_txd_map, BUS_DMASYNC_PREREAD | 1508183567Sstas BUS_DMASYNC_PREWRITE); 1509183567Sstas bus_dmamap_sync(sc->dma_txs_tag, sc->dma_txs_map, 1510183567Sstas BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 1511183567Sstas 1512183567Sstas return (0); 1513183567Sstas} 1514183567Sstas 1515183567Sstasstatic void 1516183567Sstasae_start(struct ifnet *ifp) 1517183567Sstas{ 1518183567Sstas ae_softc_t *sc; 1519216925Sjhb 1520216925Sjhb sc = ifp->if_softc; 1521216925Sjhb AE_LOCK(sc); 1522216925Sjhb ae_start_locked(ifp); 1523216925Sjhb AE_UNLOCK(sc); 1524216925Sjhb} 1525216925Sjhb 1526216925Sjhbstatic void 1527216925Sjhbae_start_locked(struct ifnet *ifp) 1528216925Sjhb{ 1529216925Sjhb ae_softc_t *sc; 1530183567Sstas unsigned int count; 1531183567Sstas struct mbuf *m0; 1532183567Sstas int error; 1533183567Sstas 1534183567Sstas sc = ifp->if_softc; 1535183567Sstas KASSERT(sc != NULL, ("[ae, %d]: sc is NULL", __LINE__)); 1536216925Sjhb AE_LOCK_ASSERT(sc); 1537183567Sstas 1538183567Sstas#ifdef AE_DEBUG 1539183567Sstas if_printf(ifp, "Start called.\n"); 1540183567Sstas#endif 1541183567Sstas 1542183567Sstas if ((ifp->if_drv_flags & (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)) != 1543216925Sjhb IFF_DRV_RUNNING || (sc->flags & AE_FLAG_LINK) == 0) 1544183567Sstas return; 1545183567Sstas 1546183567Sstas count = 0; 1547183567Sstas while (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) { 1548183567Sstas IFQ_DRV_DEQUEUE(&ifp->if_snd, m0); 1549183567Sstas if (m0 == NULL) 1550183567Sstas break; /* Nothing to do. */ 1551183567Sstas 1552183567Sstas error = ae_encap(sc, &m0); 1553183567Sstas if (error != 0) { 1554183567Sstas if (m0 != NULL) { 1555183567Sstas IFQ_DRV_PREPEND(&ifp->if_snd, m0); 1556183567Sstas ifp->if_drv_flags |= IFF_DRV_OACTIVE; 1557183567Sstas#ifdef AE_DEBUG 1558183567Sstas if_printf(ifp, "Setting OACTIVE.\n"); 1559183567Sstas#endif 1560183567Sstas } 1561183567Sstas break; 1562183567Sstas } 1563183567Sstas count++; 1564183567Sstas sc->tx_inproc++; 1565183567Sstas 1566183567Sstas /* Bounce a copy of the frame to BPF. */ 1567183567Sstas ETHER_BPF_MTAP(ifp, m0); 1568183567Sstas 1569183567Sstas m_freem(m0); 1570183567Sstas } 1571183567Sstas 1572183567Sstas if (count > 0) { /* Something was dequeued. */ 1573183567Sstas AE_WRITE_2(sc, AE_MB_TXD_IDX_REG, sc->txd_cur / 4); 1574183567Sstas sc->wd_timer = AE_TX_TIMEOUT; /* Load watchdog. */ 1575183567Sstas#ifdef AE_DEBUG 1576183567Sstas if_printf(ifp, "%d packets dequeued.\n", count); 1577183567Sstas if_printf(ifp, "Tx pos now is %d.\n", sc->txd_cur); 1578183567Sstas#endif 1579183567Sstas } 1580183567Sstas} 1581183567Sstas 1582183567Sstasstatic void 1583183567Sstasae_link_task(void *arg, int pending) 1584183567Sstas{ 1585183567Sstas ae_softc_t *sc; 1586183567Sstas struct mii_data *mii; 1587183567Sstas struct ifnet *ifp; 1588183567Sstas uint32_t val; 1589183567Sstas 1590183567Sstas sc = (ae_softc_t *)arg; 1591183567Sstas KASSERT(sc != NULL, ("[ae, %d]: sc is NULL", __LINE__)); 1592183567Sstas AE_LOCK(sc); 1593183567Sstas 1594183567Sstas ifp = sc->ifp; 1595183567Sstas mii = device_get_softc(sc->miibus); 1596183567Sstas if (mii == NULL || ifp == NULL || 1597183567Sstas (ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) { 1598183567Sstas AE_UNLOCK(sc); /* XXX: could happen? */ 1599183567Sstas return; 1600183567Sstas } 1601183567Sstas 1602183567Sstas sc->flags &= ~AE_FLAG_LINK; 1603183567Sstas if ((mii->mii_media_status & (IFM_AVALID | IFM_ACTIVE)) == 1604183567Sstas (IFM_AVALID | IFM_ACTIVE)) { 1605183567Sstas switch(IFM_SUBTYPE(mii->mii_media_active)) { 1606183567Sstas case IFM_10_T: 1607183567Sstas case IFM_100_TX: 1608183567Sstas sc->flags |= AE_FLAG_LINK; 1609183567Sstas break; 1610183567Sstas default: 1611183567Sstas break; 1612183567Sstas } 1613183567Sstas } 1614183567Sstas 1615183567Sstas /* 1616183567Sstas * Stop Rx/Tx MACs. 1617183567Sstas */ 1618183567Sstas ae_stop_rxmac(sc); 1619183567Sstas ae_stop_txmac(sc); 1620183567Sstas 1621183567Sstas if ((sc->flags & AE_FLAG_LINK) != 0) { 1622183567Sstas ae_mac_config(sc); 1623183567Sstas 1624183567Sstas /* 1625183567Sstas * Restart DMA engines. 1626183567Sstas */ 1627183567Sstas AE_WRITE_1(sc, AE_DMAREAD_REG, AE_DMAREAD_EN); 1628183567Sstas AE_WRITE_1(sc, AE_DMAWRITE_REG, AE_DMAWRITE_EN); 1629183567Sstas 1630183567Sstas /* 1631183567Sstas * Enable Rx and Tx MACs. 1632183567Sstas */ 1633183567Sstas val = AE_READ_4(sc, AE_MAC_REG); 1634183567Sstas val |= AE_MAC_TX_EN | AE_MAC_RX_EN; 1635183567Sstas AE_WRITE_4(sc, AE_MAC_REG, val); 1636183567Sstas } 1637183567Sstas AE_UNLOCK(sc); 1638183567Sstas} 1639183567Sstas 1640183567Sstasstatic void 1641183567Sstasae_stop_rxmac(ae_softc_t *sc) 1642183567Sstas{ 1643183567Sstas uint32_t val; 1644183567Sstas int i; 1645183567Sstas 1646183567Sstas AE_LOCK_ASSERT(sc); 1647183567Sstas 1648183567Sstas /* 1649183567Sstas * Stop Rx MAC engine. 1650183567Sstas */ 1651183567Sstas val = AE_READ_4(sc, AE_MAC_REG); 1652183567Sstas if ((val & AE_MAC_RX_EN) != 0) { 1653183567Sstas val &= ~AE_MAC_RX_EN; 1654183567Sstas AE_WRITE_4(sc, AE_MAC_REG, val); 1655183567Sstas } 1656183567Sstas 1657183567Sstas /* 1658183567Sstas * Stop Rx DMA engine. 1659183567Sstas */ 1660183567Sstas if (AE_READ_1(sc, AE_DMAWRITE_REG) == AE_DMAWRITE_EN) 1661183567Sstas AE_WRITE_1(sc, AE_DMAWRITE_REG, 0); 1662183567Sstas 1663183567Sstas /* 1664183567Sstas * Wait for IDLE state. 1665183567Sstas */ 1666183567Sstas for (i = 0; i < AE_IDLE_TIMEOUT; i--) { 1667183567Sstas val = AE_READ_4(sc, AE_IDLE_REG); 1668183567Sstas if ((val & (AE_IDLE_RXMAC | AE_IDLE_DMAWRITE)) == 0) 1669183567Sstas break; 1670183567Sstas DELAY(100); 1671183567Sstas } 1672183567Sstas if (i == AE_IDLE_TIMEOUT) 1673183567Sstas device_printf(sc->dev, "timed out while stopping Rx MAC.\n"); 1674183567Sstas} 1675183567Sstas 1676183567Sstasstatic void 1677183567Sstasae_stop_txmac(ae_softc_t *sc) 1678183567Sstas{ 1679183567Sstas uint32_t val; 1680183567Sstas int i; 1681183567Sstas 1682183567Sstas AE_LOCK_ASSERT(sc); 1683183567Sstas 1684183567Sstas /* 1685183567Sstas * Stop Tx MAC engine. 1686183567Sstas */ 1687183567Sstas val = AE_READ_4(sc, AE_MAC_REG); 1688183567Sstas if ((val & AE_MAC_TX_EN) != 0) { 1689183567Sstas val &= ~AE_MAC_TX_EN; 1690183567Sstas AE_WRITE_4(sc, AE_MAC_REG, val); 1691183567Sstas } 1692183567Sstas 1693183567Sstas /* 1694183567Sstas * Stop Tx DMA engine. 1695183567Sstas */ 1696183567Sstas if (AE_READ_1(sc, AE_DMAREAD_REG) == AE_DMAREAD_EN) 1697183567Sstas AE_WRITE_1(sc, AE_DMAREAD_REG, 0); 1698183567Sstas 1699183567Sstas /* 1700183567Sstas * Wait for IDLE state. 1701183567Sstas */ 1702183567Sstas for (i = 0; i < AE_IDLE_TIMEOUT; i--) { 1703183567Sstas val = AE_READ_4(sc, AE_IDLE_REG); 1704183567Sstas if ((val & (AE_IDLE_TXMAC | AE_IDLE_DMAREAD)) == 0) 1705183567Sstas break; 1706183567Sstas DELAY(100); 1707183567Sstas } 1708183567Sstas if (i == AE_IDLE_TIMEOUT) 1709183567Sstas device_printf(sc->dev, "timed out while stopping Tx MAC.\n"); 1710183567Sstas} 1711183567Sstas 1712183567Sstasstatic void 1713183567Sstasae_mac_config(ae_softc_t *sc) 1714183567Sstas{ 1715183567Sstas struct mii_data *mii; 1716183567Sstas uint32_t val; 1717183567Sstas 1718183567Sstas AE_LOCK_ASSERT(sc); 1719183567Sstas 1720183567Sstas mii = device_get_softc(sc->miibus); 1721183567Sstas val = AE_READ_4(sc, AE_MAC_REG); 1722183567Sstas val &= ~AE_MAC_FULL_DUPLEX; 1723183567Sstas /* XXX disable AE_MAC_TX_FLOW_EN? */ 1724183567Sstas 1725183567Sstas if ((IFM_OPTIONS(mii->mii_media_active) & IFM_FDX) != 0) 1726183567Sstas val |= AE_MAC_FULL_DUPLEX; 1727183567Sstas 1728183567Sstas AE_WRITE_4(sc, AE_MAC_REG, val); 1729183567Sstas} 1730183567Sstas 1731183567Sstasstatic int 1732183567Sstasae_intr(void *arg) 1733183567Sstas{ 1734183567Sstas ae_softc_t *sc; 1735183567Sstas uint32_t val; 1736183567Sstas 1737183567Sstas sc = (ae_softc_t *)arg; 1738183567Sstas KASSERT(sc != NULL, ("[ae, %d]: sc is NULL", __LINE__)); 1739183567Sstas 1740183567Sstas val = AE_READ_4(sc, AE_ISR_REG); 1741183567Sstas if (val == 0 || (val & AE_IMR_DEFAULT) == 0) 1742183567Sstas return (FILTER_STRAY); 1743183567Sstas 1744183567Sstas /* Disable interrupts. */ 1745183567Sstas AE_WRITE_4(sc, AE_ISR_REG, AE_ISR_DISABLE); 1746183567Sstas 1747183567Sstas /* Schedule interrupt processing. */ 1748183567Sstas taskqueue_enqueue(sc->tq, &sc->int_task); 1749183567Sstas 1750183567Sstas return (FILTER_HANDLED); 1751183567Sstas} 1752183567Sstas 1753183567Sstasstatic void 1754183567Sstasae_int_task(void *arg, int pending) 1755183567Sstas{ 1756183567Sstas ae_softc_t *sc; 1757183567Sstas struct ifnet *ifp; 1758183567Sstas uint32_t val; 1759183567Sstas 1760183567Sstas sc = (ae_softc_t *)arg; 1761183567Sstas 1762183567Sstas AE_LOCK(sc); 1763183567Sstas 1764183567Sstas ifp = sc->ifp; 1765183567Sstas 1766183567Sstas val = AE_READ_4(sc, AE_ISR_REG); /* Read interrupt status. */ 1767253404Syongari if (val == 0) { 1768253404Syongari AE_UNLOCK(sc); 1769253404Syongari return; 1770253404Syongari } 1771183567Sstas 1772183567Sstas /* 1773183567Sstas * Clear interrupts and disable them. 1774183567Sstas */ 1775183567Sstas AE_WRITE_4(sc, AE_ISR_REG, val | AE_ISR_DISABLE); 1776183567Sstas 1777183567Sstas#ifdef AE_DEBUG 1778183567Sstas if_printf(ifp, "Interrupt received: 0x%08x\n", val); 1779183567Sstas#endif 1780183567Sstas 1781183567Sstas if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0) { 1782183567Sstas if ((val & (AE_ISR_DMAR_TIMEOUT | AE_ISR_DMAW_TIMEOUT | 1783183567Sstas AE_ISR_PHY_LINKDOWN)) != 0) { 1784212968Syongari ifp->if_drv_flags &= ~IFF_DRV_RUNNING; 1785183567Sstas ae_init_locked(sc); 1786212968Syongari AE_UNLOCK(sc); 1787212968Syongari return; 1788183567Sstas } 1789183567Sstas if ((val & AE_ISR_TX_EVENT) != 0) 1790183567Sstas ae_tx_intr(sc); 1791183567Sstas if ((val & AE_ISR_RX_EVENT) != 0) 1792183567Sstas ae_rx_intr(sc); 1793253404Syongari /* 1794253404Syongari * Re-enable interrupts. 1795253404Syongari */ 1796253404Syongari AE_WRITE_4(sc, AE_ISR_REG, 0); 1797253404Syongari 1798253404Syongari if ((sc->flags & AE_FLAG_TXAVAIL) != 0) { 1799253404Syongari if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) 1800253404Syongari ae_start_locked(ifp); 1801253404Syongari } 1802183567Sstas } 1803183567Sstas 1804183567Sstas AE_UNLOCK(sc); 1805183567Sstas} 1806183567Sstas 1807183567Sstasstatic void 1808183567Sstasae_tx_intr(ae_softc_t *sc) 1809183567Sstas{ 1810183567Sstas struct ifnet *ifp; 1811183567Sstas ae_txd_t *txd; 1812183567Sstas ae_txs_t *txs; 1813183567Sstas uint16_t flags; 1814183567Sstas 1815183567Sstas AE_LOCK_ASSERT(sc); 1816183567Sstas 1817183567Sstas ifp = sc->ifp; 1818183567Sstas 1819183567Sstas#ifdef AE_DEBUG 1820183567Sstas if_printf(ifp, "Tx interrupt occuried.\n"); 1821183567Sstas#endif 1822183567Sstas 1823183567Sstas /* 1824183567Sstas * Syncronize DMA buffers. 1825183567Sstas */ 1826183567Sstas bus_dmamap_sync(sc->dma_txd_tag, sc->dma_txd_map, 1827183567Sstas BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); 1828183567Sstas bus_dmamap_sync(sc->dma_txs_tag, sc->dma_txs_map, 1829183567Sstas BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); 1830183567Sstas 1831183567Sstas for (;;) { 1832183567Sstas txs = sc->txs_base + sc->txs_ack; 1833183567Sstas flags = le16toh(txs->flags); 1834183567Sstas if ((flags & AE_TXS_UPDATE) == 0) 1835183567Sstas break; 1836183567Sstas txs->flags = htole16(flags & ~AE_TXS_UPDATE); 1837183567Sstas /* Update stats. */ 1838183567Sstas ae_update_stats_tx(flags, &sc->stats); 1839183567Sstas 1840183567Sstas /* 1841183567Sstas * Update TxS position. 1842183567Sstas */ 1843183567Sstas sc->txs_ack = (sc->txs_ack + 1) % AE_TXS_COUNT_DEFAULT; 1844183567Sstas sc->flags |= AE_FLAG_TXAVAIL; 1845183567Sstas 1846183567Sstas txd = (ae_txd_t *)(sc->txd_base + sc->txd_ack); 1847183567Sstas if (txs->len != txd->len) 1848183567Sstas device_printf(sc->dev, "Size mismatch: TxS:%d TxD:%d\n", 1849183567Sstas le16toh(txs->len), le16toh(txd->len)); 1850183567Sstas 1851183567Sstas /* 1852183567Sstas * Move txd ack and align on 4-byte boundary. 1853183567Sstas */ 1854227452Syongari sc->txd_ack = ((sc->txd_ack + le16toh(txd->len) + 1855227452Syongari sizeof(ae_txs_t) + 3) & ~3) % AE_TXD_BUFSIZE_DEFAULT; 1856183567Sstas 1857183567Sstas if ((flags & AE_TXS_SUCCESS) != 0) 1858183567Sstas ifp->if_opackets++; 1859183567Sstas else 1860183567Sstas ifp->if_oerrors++; 1861183567Sstas 1862183567Sstas sc->tx_inproc--; 1863253404Syongari } 1864183567Sstas 1865253404Syongari if ((sc->flags & AE_FLAG_TXAVAIL) != 0) 1866183567Sstas ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 1867183567Sstas if (sc->tx_inproc < 0) { 1868183567Sstas if_printf(ifp, "Received stray Tx interrupt(s).\n"); 1869183567Sstas sc->tx_inproc = 0; 1870183567Sstas } 1871183567Sstas 1872183567Sstas if (sc->tx_inproc == 0) 1873183567Sstas sc->wd_timer = 0; /* Unarm watchdog. */ 1874183567Sstas 1875183567Sstas /* 1876183567Sstas * Syncronize DMA buffers. 1877183567Sstas */ 1878183567Sstas bus_dmamap_sync(sc->dma_txd_tag, sc->dma_txd_map, 1879183567Sstas BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 1880183567Sstas bus_dmamap_sync(sc->dma_txs_tag, sc->dma_txs_map, 1881183567Sstas BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 1882183567Sstas} 1883183567Sstas 1884264444Syongaristatic void 1885183567Sstasae_rxeof(ae_softc_t *sc, ae_rxd_t *rxd) 1886183567Sstas{ 1887183567Sstas struct ifnet *ifp; 1888183567Sstas struct mbuf *m; 1889183567Sstas unsigned int size; 1890183567Sstas uint16_t flags; 1891183567Sstas 1892183567Sstas AE_LOCK_ASSERT(sc); 1893183567Sstas 1894183567Sstas ifp = sc->ifp; 1895183567Sstas flags = le16toh(rxd->flags); 1896183567Sstas 1897183567Sstas#ifdef AE_DEBUG 1898183567Sstas if_printf(ifp, "Rx interrupt occuried.\n"); 1899183567Sstas#endif 1900183567Sstas size = le16toh(rxd->len) - ETHER_CRC_LEN; 1901185707Sstas if (size < (ETHER_MIN_LEN - ETHER_CRC_LEN - ETHER_VLAN_ENCAP_LEN)) { 1902185707Sstas if_printf(ifp, "Runt frame received."); 1903264444Syongari ifp->if_ierrors++; 1904264444Syongari return; 1905183567Sstas } 1906183567Sstas 1907183567Sstas m = m_devget(&rxd->data[0], size, ETHER_ALIGN, ifp, NULL); 1908264444Syongari if (m == NULL) { 1909264444Syongari ifp->if_iqdrops++; 1910264444Syongari return; 1911264444Syongari } 1912183567Sstas 1913183567Sstas if ((ifp->if_capenable & IFCAP_VLAN_HWTAGGING) != 0 && 1914183567Sstas (flags & AE_RXD_HAS_VLAN) != 0) { 1915183567Sstas m->m_pkthdr.ether_vtag = AE_RXD_VLAN(le16toh(rxd->vlan)); 1916183567Sstas m->m_flags |= M_VLANTAG; 1917183567Sstas } 1918183567Sstas 1919264444Syongari ifp->if_ipackets++; 1920183567Sstas /* 1921183567Sstas * Pass it through. 1922183567Sstas */ 1923183567Sstas AE_UNLOCK(sc); 1924183567Sstas (*ifp->if_input)(ifp, m); 1925183567Sstas AE_LOCK(sc); 1926183567Sstas} 1927183567Sstas 1928183567Sstasstatic void 1929183567Sstasae_rx_intr(ae_softc_t *sc) 1930183567Sstas{ 1931183567Sstas ae_rxd_t *rxd; 1932183567Sstas struct ifnet *ifp; 1933183567Sstas uint16_t flags; 1934264444Syongari int count; 1935183567Sstas 1936183567Sstas KASSERT(sc != NULL, ("[ae, %d]: sc is NULL!", __LINE__)); 1937183567Sstas 1938183567Sstas AE_LOCK_ASSERT(sc); 1939183567Sstas 1940183567Sstas ifp = sc->ifp; 1941183567Sstas 1942183567Sstas /* 1943183567Sstas * Syncronize DMA buffers. 1944183567Sstas */ 1945183567Sstas bus_dmamap_sync(sc->dma_rxd_tag, sc->dma_rxd_map, 1946183567Sstas BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); 1947183567Sstas 1948253404Syongari for (count = 0;; count++) { 1949183567Sstas rxd = (ae_rxd_t *)(sc->rxd_base + sc->rxd_cur); 1950183567Sstas flags = le16toh(rxd->flags); 1951183567Sstas if ((flags & AE_RXD_UPDATE) == 0) 1952183567Sstas break; 1953183567Sstas rxd->flags = htole16(flags & ~AE_RXD_UPDATE); 1954183567Sstas /* Update stats. */ 1955183567Sstas ae_update_stats_rx(flags, &sc->stats); 1956183567Sstas 1957183567Sstas /* 1958183567Sstas * Update position index. 1959183567Sstas */ 1960183567Sstas sc->rxd_cur = (sc->rxd_cur + 1) % AE_RXD_COUNT_DEFAULT; 1961183567Sstas 1962264444Syongari if ((flags & AE_RXD_SUCCESS) != 0) 1963264444Syongari ae_rxeof(sc, rxd); 1964264444Syongari else 1965183567Sstas ifp->if_ierrors++; 1966183567Sstas } 1967183567Sstas 1968253404Syongari if (count > 0) { 1969253404Syongari bus_dmamap_sync(sc->dma_rxd_tag, sc->dma_rxd_map, 1970253404Syongari BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 1971253404Syongari /* 1972253404Syongari * Update Rx index. 1973253404Syongari */ 1974253404Syongari AE_WRITE_2(sc, AE_MB_RXD_IDX_REG, sc->rxd_cur); 1975253404Syongari } 1976183567Sstas} 1977183567Sstas 1978183567Sstasstatic void 1979183567Sstasae_watchdog(ae_softc_t *sc) 1980183567Sstas{ 1981183567Sstas struct ifnet *ifp; 1982183567Sstas 1983183567Sstas KASSERT(sc != NULL, ("[ae, %d]: sc is NULL!", __LINE__)); 1984183567Sstas AE_LOCK_ASSERT(sc); 1985183567Sstas ifp = sc->ifp; 1986183567Sstas 1987183567Sstas if (sc->wd_timer == 0 || --sc->wd_timer != 0) 1988183567Sstas return; /* Noting to do. */ 1989183567Sstas 1990183567Sstas if ((sc->flags & AE_FLAG_LINK) == 0) 1991183567Sstas if_printf(ifp, "watchdog timeout (missed link).\n"); 1992183567Sstas else 1993183567Sstas if_printf(ifp, "watchdog timeout - resetting.\n"); 1994183567Sstas 1995183567Sstas ifp->if_oerrors++; 1996212968Syongari ifp->if_drv_flags &= ~IFF_DRV_RUNNING; 1997183567Sstas ae_init_locked(sc); 1998183567Sstas if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) 1999216925Sjhb ae_start_locked(ifp); 2000183567Sstas} 2001183567Sstas 2002183567Sstasstatic void 2003183567Sstasae_tick(void *arg) 2004183567Sstas{ 2005183567Sstas ae_softc_t *sc; 2006183567Sstas struct mii_data *mii; 2007183567Sstas 2008183567Sstas sc = (ae_softc_t *)arg; 2009183567Sstas KASSERT(sc != NULL, ("[ae, %d]: sc is NULL!", __LINE__)); 2010183567Sstas AE_LOCK_ASSERT(sc); 2011183567Sstas 2012183567Sstas mii = device_get_softc(sc->miibus); 2013183567Sstas mii_tick(mii); 2014183567Sstas ae_watchdog(sc); /* Watchdog check. */ 2015183567Sstas callout_reset(&sc->tick_ch, hz, ae_tick, sc); 2016183567Sstas} 2017183567Sstas 2018183567Sstasstatic void 2019183567Sstasae_rxvlan(ae_softc_t *sc) 2020183567Sstas{ 2021183567Sstas struct ifnet *ifp; 2022183567Sstas uint32_t val; 2023183567Sstas 2024183567Sstas AE_LOCK_ASSERT(sc); 2025183567Sstas ifp = sc->ifp; 2026183567Sstas val = AE_READ_4(sc, AE_MAC_REG); 2027183567Sstas val &= ~AE_MAC_RMVLAN_EN; 2028183567Sstas if ((ifp->if_capenable & IFCAP_VLAN_HWTAGGING) != 0) 2029183567Sstas val |= AE_MAC_RMVLAN_EN; 2030183567Sstas AE_WRITE_4(sc, AE_MAC_REG, val); 2031183567Sstas} 2032183567Sstas 2033183567Sstasstatic void 2034183567Sstasae_rxfilter(ae_softc_t *sc) 2035183567Sstas{ 2036183567Sstas struct ifnet *ifp; 2037183567Sstas struct ifmultiaddr *ifma; 2038183567Sstas uint32_t crc; 2039183567Sstas uint32_t mchash[2]; 2040183567Sstas uint32_t rxcfg; 2041183567Sstas 2042183567Sstas KASSERT(sc != NULL, ("[ae, %d]: sc is NULL!", __LINE__)); 2043183567Sstas 2044183567Sstas AE_LOCK_ASSERT(sc); 2045183567Sstas 2046183567Sstas ifp = sc->ifp; 2047183567Sstas 2048183567Sstas rxcfg = AE_READ_4(sc, AE_MAC_REG); 2049183567Sstas rxcfg &= ~(AE_MAC_MCAST_EN | AE_MAC_BCAST_EN | AE_MAC_PROMISC_EN); 2050183567Sstas 2051183567Sstas if ((ifp->if_flags & IFF_BROADCAST) != 0) 2052183567Sstas rxcfg |= AE_MAC_BCAST_EN; 2053183567Sstas if ((ifp->if_flags & IFF_PROMISC) != 0) 2054183567Sstas rxcfg |= AE_MAC_PROMISC_EN; 2055183567Sstas if ((ifp->if_flags & IFF_ALLMULTI) != 0) 2056183567Sstas rxcfg |= AE_MAC_MCAST_EN; 2057183567Sstas 2058183567Sstas /* 2059183567Sstas * Wipe old settings. 2060183567Sstas */ 2061183567Sstas AE_WRITE_4(sc, AE_REG_MHT0, 0); 2062183567Sstas AE_WRITE_4(sc, AE_REG_MHT1, 0); 2063183567Sstas if ((ifp->if_flags & (IFF_PROMISC | IFF_ALLMULTI)) != 0) { 2064183567Sstas AE_WRITE_4(sc, AE_REG_MHT0, 0xffffffff); 2065183567Sstas AE_WRITE_4(sc, AE_REG_MHT1, 0xffffffff); 2066183567Sstas AE_WRITE_4(sc, AE_MAC_REG, rxcfg); 2067183567Sstas return; 2068183567Sstas } 2069183567Sstas 2070183567Sstas /* 2071183567Sstas * Load multicast tables. 2072183567Sstas */ 2073183567Sstas bzero(mchash, sizeof(mchash)); 2074195049Srwatson if_maddr_rlock(ifp); 2075183567Sstas TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { 2076183567Sstas if (ifma->ifma_addr->sa_family != AF_LINK) 2077183567Sstas continue; 2078197627Syongari crc = ether_crc32_be(LLADDR((struct sockaddr_dl *) 2079183567Sstas ifma->ifma_addr), ETHER_ADDR_LEN); 2080183567Sstas mchash[crc >> 31] |= 1 << ((crc >> 26) & 0x1f); 2081183567Sstas } 2082195049Srwatson if_maddr_runlock(ifp); 2083183567Sstas AE_WRITE_4(sc, AE_REG_MHT0, mchash[0]); 2084183567Sstas AE_WRITE_4(sc, AE_REG_MHT1, mchash[1]); 2085183567Sstas AE_WRITE_4(sc, AE_MAC_REG, rxcfg); 2086183567Sstas} 2087183567Sstas 2088183567Sstasstatic int 2089183567Sstasae_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) 2090183567Sstas{ 2091183567Sstas struct ae_softc *sc; 2092183567Sstas struct ifreq *ifr; 2093183567Sstas struct mii_data *mii; 2094183567Sstas int error, mask; 2095183567Sstas 2096183567Sstas sc = ifp->if_softc; 2097183567Sstas ifr = (struct ifreq *)data; 2098183567Sstas error = 0; 2099183567Sstas 2100183567Sstas switch (cmd) { 2101183567Sstas case SIOCSIFMTU: 2102183567Sstas if (ifr->ifr_mtu < ETHERMIN || ifr->ifr_mtu > ETHERMTU) 2103183567Sstas error = EINVAL; 2104183567Sstas else if (ifp->if_mtu != ifr->ifr_mtu) { 2105183567Sstas AE_LOCK(sc); 2106183567Sstas ifp->if_mtu = ifr->ifr_mtu; 2107212968Syongari if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0) { 2108212968Syongari ifp->if_drv_flags &= ~IFF_DRV_RUNNING; 2109183567Sstas ae_init_locked(sc); 2110212968Syongari } 2111183567Sstas AE_UNLOCK(sc); 2112183567Sstas } 2113183567Sstas break; 2114183567Sstas case SIOCSIFFLAGS: 2115183567Sstas AE_LOCK(sc); 2116183567Sstas if ((ifp->if_flags & IFF_UP) != 0) { 2117183567Sstas if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0) { 2118183567Sstas if (((ifp->if_flags ^ sc->if_flags) 2119183567Sstas & (IFF_PROMISC | IFF_ALLMULTI)) != 0) 2120183567Sstas ae_rxfilter(sc); 2121183567Sstas } else { 2122183567Sstas if ((sc->flags & AE_FLAG_DETACH) == 0) 2123183567Sstas ae_init_locked(sc); 2124183567Sstas } 2125183567Sstas } else { 2126183567Sstas if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0) 2127183567Sstas ae_stop(sc); 2128183567Sstas } 2129183567Sstas sc->if_flags = ifp->if_flags; 2130183567Sstas AE_UNLOCK(sc); 2131183567Sstas break; 2132183567Sstas case SIOCADDMULTI: 2133183567Sstas case SIOCDELMULTI: 2134183567Sstas AE_LOCK(sc); 2135183567Sstas if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0) 2136183567Sstas ae_rxfilter(sc); 2137183567Sstas AE_UNLOCK(sc); 2138183567Sstas break; 2139183567Sstas case SIOCSIFMEDIA: 2140183567Sstas case SIOCGIFMEDIA: 2141183567Sstas mii = device_get_softc(sc->miibus); 2142183567Sstas error = ifmedia_ioctl(ifp, ifr, &mii->mii_media, cmd); 2143183567Sstas break; 2144183567Sstas case SIOCSIFCAP: 2145183567Sstas AE_LOCK(sc); 2146183567Sstas mask = ifr->ifr_reqcap ^ ifp->if_capenable; 2147183567Sstas if ((mask & IFCAP_VLAN_HWTAGGING) != 0 && 2148183567Sstas (ifp->if_capabilities & IFCAP_VLAN_HWTAGGING) != 0) { 2149183567Sstas ifp->if_capenable ^= IFCAP_VLAN_HWTAGGING; 2150183567Sstas ae_rxvlan(sc); 2151183567Sstas } 2152183567Sstas VLAN_CAPABILITIES(ifp); 2153183567Sstas AE_UNLOCK(sc); 2154183567Sstas break; 2155183567Sstas default: 2156183567Sstas error = ether_ioctl(ifp, cmd, data); 2157183567Sstas break; 2158183567Sstas } 2159183567Sstas return (error); 2160183567Sstas} 2161183567Sstas 2162183567Sstasstatic void 2163183567Sstasae_stop(ae_softc_t *sc) 2164183567Sstas{ 2165183567Sstas struct ifnet *ifp; 2166183567Sstas int i; 2167183567Sstas 2168183567Sstas AE_LOCK_ASSERT(sc); 2169183567Sstas 2170183567Sstas ifp = sc->ifp; 2171183567Sstas ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE); 2172183567Sstas sc->flags &= ~AE_FLAG_LINK; 2173183567Sstas sc->wd_timer = 0; /* Cancel watchdog. */ 2174183567Sstas callout_stop(&sc->tick_ch); 2175183567Sstas 2176183567Sstas /* 2177183567Sstas * Clear and disable interrupts. 2178183567Sstas */ 2179183567Sstas AE_WRITE_4(sc, AE_IMR_REG, 0); 2180183567Sstas AE_WRITE_4(sc, AE_ISR_REG, 0xffffffff); 2181183567Sstas 2182183567Sstas /* 2183183567Sstas * Stop Rx/Tx MACs. 2184183567Sstas */ 2185183567Sstas ae_stop_txmac(sc); 2186183567Sstas ae_stop_rxmac(sc); 2187183567Sstas 2188183567Sstas /* 2189183567Sstas * Stop DMA engines. 2190183567Sstas */ 2191183567Sstas AE_WRITE_1(sc, AE_DMAREAD_REG, ~AE_DMAREAD_EN); 2192183567Sstas AE_WRITE_1(sc, AE_DMAWRITE_REG, ~AE_DMAWRITE_EN); 2193183567Sstas 2194183567Sstas /* 2195183567Sstas * Wait for everything to enter idle state. 2196183567Sstas */ 2197183567Sstas for (i = 0; i < AE_IDLE_TIMEOUT; i++) { 2198183567Sstas if (AE_READ_4(sc, AE_IDLE_REG) == 0) 2199183567Sstas break; 2200183567Sstas DELAY(100); 2201183567Sstas } 2202183567Sstas if (i == AE_IDLE_TIMEOUT) 2203183567Sstas device_printf(sc->dev, "could not enter idle state in stop.\n"); 2204183567Sstas} 2205183567Sstas 2206183567Sstasstatic void 2207183567Sstasae_update_stats_tx(uint16_t flags, ae_stats_t *stats) 2208183567Sstas{ 2209183567Sstas 2210183567Sstas if ((flags & AE_TXS_BCAST) != 0) 2211183567Sstas stats->tx_bcast++; 2212183567Sstas if ((flags & AE_TXS_MCAST) != 0) 2213183567Sstas stats->tx_mcast++; 2214183567Sstas if ((flags & AE_TXS_PAUSE) != 0) 2215183567Sstas stats->tx_pause++; 2216183567Sstas if ((flags & AE_TXS_CTRL) != 0) 2217183567Sstas stats->tx_ctrl++; 2218183567Sstas if ((flags & AE_TXS_DEFER) != 0) 2219183567Sstas stats->tx_defer++; 2220183567Sstas if ((flags & AE_TXS_EXCDEFER) != 0) 2221183567Sstas stats->tx_excdefer++; 2222183567Sstas if ((flags & AE_TXS_SINGLECOL) != 0) 2223183567Sstas stats->tx_singlecol++; 2224183567Sstas if ((flags & AE_TXS_MULTICOL) != 0) 2225183567Sstas stats->tx_multicol++; 2226183567Sstas if ((flags & AE_TXS_LATECOL) != 0) 2227183567Sstas stats->tx_latecol++; 2228183567Sstas if ((flags & AE_TXS_ABORTCOL) != 0) 2229183567Sstas stats->tx_abortcol++; 2230183567Sstas if ((flags & AE_TXS_UNDERRUN) != 0) 2231183567Sstas stats->tx_underrun++; 2232183567Sstas} 2233183567Sstas 2234183567Sstasstatic void 2235183567Sstasae_update_stats_rx(uint16_t flags, ae_stats_t *stats) 2236183567Sstas{ 2237183567Sstas 2238183567Sstas if ((flags & AE_RXD_BCAST) != 0) 2239183567Sstas stats->rx_bcast++; 2240183567Sstas if ((flags & AE_RXD_MCAST) != 0) 2241183567Sstas stats->rx_mcast++; 2242183567Sstas if ((flags & AE_RXD_PAUSE) != 0) 2243183567Sstas stats->rx_pause++; 2244183567Sstas if ((flags & AE_RXD_CTRL) != 0) 2245183567Sstas stats->rx_ctrl++; 2246183567Sstas if ((flags & AE_RXD_CRCERR) != 0) 2247183567Sstas stats->rx_crcerr++; 2248183567Sstas if ((flags & AE_RXD_CODEERR) != 0) 2249183567Sstas stats->rx_codeerr++; 2250183567Sstas if ((flags & AE_RXD_RUNT) != 0) 2251183567Sstas stats->rx_runt++; 2252183567Sstas if ((flags & AE_RXD_FRAG) != 0) 2253183567Sstas stats->rx_frag++; 2254183567Sstas if ((flags & AE_RXD_TRUNC) != 0) 2255183567Sstas stats->rx_trunc++; 2256183567Sstas if ((flags & AE_RXD_ALIGN) != 0) 2257183567Sstas stats->rx_align++; 2258183567Sstas} 2259