1f85e0762SSepherosa Ziehau /*- 2f85e0762SSepherosa Ziehau * Copyright (c) 2008 Stanislav Sedov <stas@FreeBSD.org>. 3f85e0762SSepherosa Ziehau * All rights reserved. 4f85e0762SSepherosa Ziehau * 5f85e0762SSepherosa Ziehau * Redistribution and use in source and binary forms, with or without 6f85e0762SSepherosa Ziehau * modification, are permitted provided that the following conditions 7f85e0762SSepherosa Ziehau * are met: 8f85e0762SSepherosa Ziehau * 1. Redistributions of source code must retain the above copyright 9f85e0762SSepherosa Ziehau * notice, this list of conditions and the following disclaimer. 10f85e0762SSepherosa Ziehau * 2. Redistributions in binary form must reproduce the above copyright 11f85e0762SSepherosa Ziehau * notice, this list of conditions and the following disclaimer in the 12f85e0762SSepherosa Ziehau * documentation and/or other materials provided with the distribution. 13f85e0762SSepherosa Ziehau * 14f85e0762SSepherosa Ziehau * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 15f85e0762SSepherosa Ziehau * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 16f85e0762SSepherosa Ziehau * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 17f85e0762SSepherosa Ziehau * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 18f85e0762SSepherosa Ziehau * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 19f85e0762SSepherosa Ziehau * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 20f85e0762SSepherosa Ziehau * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 21f85e0762SSepherosa Ziehau * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22f85e0762SSepherosa Ziehau * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 23f85e0762SSepherosa Ziehau * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24f85e0762SSepherosa Ziehau * 25f85e0762SSepherosa Ziehau * Driver for Attansic Technology Corp. L2 FastEthernet adapter. 26f85e0762SSepherosa Ziehau * 27f85e0762SSepherosa Ziehau * This driver is heavily based on age(4) Attansic L1 driver by Pyun YongHyeon. 28f85e0762SSepherosa Ziehau * 29f85e0762SSepherosa Ziehau * $FreeBSD: src/sys/dev/ae/if_ae.c,v 1.1.2.3.2.1 2009/04/15 03:14:26 kensmith Exp $ 30f85e0762SSepherosa Ziehau */ 31f85e0762SSepherosa Ziehau 32f85e0762SSepherosa Ziehau #include <sys/param.h> 33f85e0762SSepherosa Ziehau #include <sys/endian.h> 34f85e0762SSepherosa Ziehau #include <sys/kernel.h> 35f85e0762SSepherosa Ziehau #include <sys/bus.h> 36f85e0762SSepherosa Ziehau #include <sys/interrupt.h> 37f85e0762SSepherosa Ziehau #include <sys/malloc.h> 38f85e0762SSepherosa Ziehau #include <sys/proc.h> 39f85e0762SSepherosa Ziehau #include <sys/rman.h> 40f85e0762SSepherosa Ziehau #include <sys/serialize.h> 41f85e0762SSepherosa Ziehau #include <sys/socket.h> 42f85e0762SSepherosa Ziehau #include <sys/sockio.h> 43f85e0762SSepherosa Ziehau #include <sys/sysctl.h> 44f85e0762SSepherosa Ziehau 45f85e0762SSepherosa Ziehau #include <net/ethernet.h> 46f85e0762SSepherosa Ziehau #include <net/if.h> 47f85e0762SSepherosa Ziehau #include <net/bpf.h> 48f85e0762SSepherosa Ziehau #include <net/if_arp.h> 49f85e0762SSepherosa Ziehau #include <net/if_dl.h> 50f85e0762SSepherosa Ziehau #include <net/if_media.h> 51f85e0762SSepherosa Ziehau #include <net/ifq_var.h> 52f85e0762SSepherosa Ziehau #include <net/vlan/if_vlan_var.h> 53f85e0762SSepherosa Ziehau #include <net/vlan/if_vlan_ether.h> 54f85e0762SSepherosa Ziehau 55f85e0762SSepherosa Ziehau #include <bus/pci/pcireg.h> 56f85e0762SSepherosa Ziehau #include <bus/pci/pcivar.h> 57f85e0762SSepherosa Ziehau #include <bus/pci/pcidevs.h> 58f85e0762SSepherosa Ziehau 59f85e0762SSepherosa Ziehau #include <dev/netif/mii_layer/miivar.h> 60f85e0762SSepherosa Ziehau 61f85e0762SSepherosa Ziehau #include <dev/netif/ae/if_aereg.h> 62f85e0762SSepherosa Ziehau #include <dev/netif/ae/if_aevar.h> 63f85e0762SSepherosa Ziehau 64f85e0762SSepherosa Ziehau /* "device miibus" required. See GENERIC if you get errors here. */ 65f85e0762SSepherosa Ziehau #include "miibus_if.h" 66f85e0762SSepherosa Ziehau 67f85e0762SSepherosa Ziehau /* 68f85e0762SSepherosa Ziehau * Devices supported by this driver. 69f85e0762SSepherosa Ziehau */ 70f85e0762SSepherosa Ziehau static const struct ae_dev { 71f85e0762SSepherosa Ziehau uint16_t ae_vendorid; 72f85e0762SSepherosa Ziehau uint16_t ae_deviceid; 73f85e0762SSepherosa Ziehau const char *ae_name; 74f85e0762SSepherosa Ziehau } ae_devs[] = { 75f85e0762SSepherosa Ziehau { VENDORID_ATTANSIC, DEVICEID_ATTANSIC_L2, 76f85e0762SSepherosa Ziehau "Attansic Technology Corp, L2 Fast Ethernet" }, 77f85e0762SSepherosa Ziehau /* Required last entry */ 78f85e0762SSepherosa Ziehau { 0, 0, NULL } 79f85e0762SSepherosa Ziehau }; 80f85e0762SSepherosa Ziehau 81f85e0762SSepherosa Ziehau 82f85e0762SSepherosa Ziehau static int ae_probe(device_t); 83f85e0762SSepherosa Ziehau static int ae_attach(device_t); 84f85e0762SSepherosa Ziehau static int ae_detach(device_t); 85f85e0762SSepherosa Ziehau static int ae_shutdown(device_t); 86f85e0762SSepherosa Ziehau static int ae_suspend(device_t); 87f85e0762SSepherosa Ziehau static int ae_resume(device_t); 88f85e0762SSepherosa Ziehau static int ae_miibus_readreg(device_t, int, int); 89f85e0762SSepherosa Ziehau static int ae_miibus_writereg(device_t, int, int, int); 90f85e0762SSepherosa Ziehau static void ae_miibus_statchg(device_t); 91f85e0762SSepherosa Ziehau 92f85e0762SSepherosa Ziehau static int ae_mediachange(struct ifnet *); 93f85e0762SSepherosa Ziehau static void ae_mediastatus(struct ifnet *, struct ifmediareq *); 94f85e0762SSepherosa Ziehau static void ae_init(void *); 95f0a26983SSepherosa Ziehau static void ae_start(struct ifnet *, struct ifaltq_subque *); 96f85e0762SSepherosa Ziehau static int ae_ioctl(struct ifnet *, u_long, caddr_t, struct ucred *); 97f85e0762SSepherosa Ziehau static void ae_watchdog(struct ifnet *); 98f85e0762SSepherosa Ziehau static void ae_stop(struct ae_softc *); 99f85e0762SSepherosa Ziehau static void ae_tick(void *); 100f85e0762SSepherosa Ziehau 101f85e0762SSepherosa Ziehau static void ae_intr(void *); 102f85e0762SSepherosa Ziehau static void ae_tx_intr(struct ae_softc *); 103f85e0762SSepherosa Ziehau static void ae_rx_intr(struct ae_softc *); 104f85e0762SSepherosa Ziehau static int ae_rxeof(struct ae_softc *, struct ae_rxd *); 105f85e0762SSepherosa Ziehau 106f85e0762SSepherosa Ziehau static int ae_encap(struct ae_softc *, struct mbuf **); 107f85e0762SSepherosa Ziehau static void ae_sysctl_node(struct ae_softc *); 108f85e0762SSepherosa Ziehau static void ae_phy_reset(struct ae_softc *); 109f85e0762SSepherosa Ziehau static int ae_reset(struct ae_softc *); 110f85e0762SSepherosa Ziehau static void ae_pcie_init(struct ae_softc *); 111f85e0762SSepherosa Ziehau static void ae_get_eaddr(struct ae_softc *); 112f85e0762SSepherosa Ziehau static void ae_dma_free(struct ae_softc *); 113f85e0762SSepherosa Ziehau static int ae_dma_alloc(struct ae_softc *); 114f85e0762SSepherosa Ziehau static void ae_mac_config(struct ae_softc *); 115f85e0762SSepherosa Ziehau static void ae_stop_rxmac(struct ae_softc *); 116f85e0762SSepherosa Ziehau static void ae_stop_txmac(struct ae_softc *); 117f85e0762SSepherosa Ziehau static void ae_rxfilter(struct ae_softc *); 118f85e0762SSepherosa Ziehau static void ae_rxvlan(struct ae_softc *); 119f85e0762SSepherosa Ziehau static void ae_update_stats_rx(uint16_t, struct ae_stats *); 120f85e0762SSepherosa Ziehau static void ae_update_stats_tx(uint16_t, struct ae_stats *); 121f85e0762SSepherosa Ziehau static void ae_powersave_disable(struct ae_softc *); 122f85e0762SSepherosa Ziehau static void ae_powersave_enable(struct ae_softc *); 123f85e0762SSepherosa Ziehau 124f85e0762SSepherosa Ziehau static device_method_t ae_methods[] = { 125f85e0762SSepherosa Ziehau /* Device interface. */ 126f85e0762SSepherosa Ziehau DEVMETHOD(device_probe, ae_probe), 127f85e0762SSepherosa Ziehau DEVMETHOD(device_attach, ae_attach), 128f85e0762SSepherosa Ziehau DEVMETHOD(device_detach, ae_detach), 129f85e0762SSepherosa Ziehau DEVMETHOD(device_shutdown, ae_shutdown), 130f85e0762SSepherosa Ziehau DEVMETHOD(device_suspend, ae_suspend), 131f85e0762SSepherosa Ziehau DEVMETHOD(device_resume, ae_resume), 132f85e0762SSepherosa Ziehau 133f85e0762SSepherosa Ziehau /* Bus interface. */ 134f85e0762SSepherosa Ziehau DEVMETHOD(bus_print_child, bus_generic_print_child), 135f85e0762SSepherosa Ziehau DEVMETHOD(bus_driver_added, bus_generic_driver_added), 136f85e0762SSepherosa Ziehau 137f85e0762SSepherosa Ziehau /* MII interface. */ 138f85e0762SSepherosa Ziehau DEVMETHOD(miibus_readreg, ae_miibus_readreg), 139f85e0762SSepherosa Ziehau DEVMETHOD(miibus_writereg, ae_miibus_writereg), 140f85e0762SSepherosa Ziehau DEVMETHOD(miibus_statchg, ae_miibus_statchg), 141f85e0762SSepherosa Ziehau { NULL, NULL } 142f85e0762SSepherosa Ziehau }; 143f85e0762SSepherosa Ziehau 144f85e0762SSepherosa Ziehau static driver_t ae_driver = { 145f85e0762SSepherosa Ziehau "ae", 146f85e0762SSepherosa Ziehau ae_methods, 147f85e0762SSepherosa Ziehau sizeof(struct ae_softc) 148f85e0762SSepherosa Ziehau }; 149f85e0762SSepherosa Ziehau 150f85e0762SSepherosa Ziehau static devclass_t ae_devclass; 151f85e0762SSepherosa Ziehau DECLARE_DUMMY_MODULE(if_ae); 152f85e0762SSepherosa Ziehau MODULE_DEPEND(if_ae, miibus, 1, 1, 1); 153aa2b9d05SSascha Wildner DRIVER_MODULE(if_ae, pci, ae_driver, ae_devclass, NULL, NULL); 154aa2b9d05SSascha Wildner DRIVER_MODULE(miibus, ae, miibus_driver, miibus_devclass, NULL, NULL); 155f85e0762SSepherosa Ziehau 156f85e0762SSepherosa Ziehau /* Register access macros. */ 157f85e0762SSepherosa Ziehau #define AE_WRITE_4(_sc, reg, val) \ 158f85e0762SSepherosa Ziehau bus_space_write_4((_sc)->ae_mem_bt, (_sc)->ae_mem_bh, (reg), (val)) 159f85e0762SSepherosa Ziehau #define AE_WRITE_2(_sc, reg, val) \ 160f85e0762SSepherosa Ziehau bus_space_write_2((_sc)->ae_mem_bt, (_sc)->ae_mem_bh, (reg), (val)) 161f85e0762SSepherosa Ziehau #define AE_WRITE_1(_sc, reg, val) \ 162f85e0762SSepherosa Ziehau bus_space_write_1((_sc)->ae_mem_bt, (_sc)->ae_mem_bh, (reg), (val)) 163f85e0762SSepherosa Ziehau #define AE_READ_4(_sc, reg) \ 164f85e0762SSepherosa Ziehau bus_space_read_4((_sc)->ae_mem_bt, (_sc)->ae_mem_bh, (reg)) 165f85e0762SSepherosa Ziehau #define AE_READ_2(_sc, reg) \ 166f85e0762SSepherosa Ziehau bus_space_read_2((_sc)->ae_mem_bt, (_sc)->ae_mem_bh, (reg)) 167f85e0762SSepherosa Ziehau #define AE_READ_1(_sc, reg) \ 168f85e0762SSepherosa Ziehau bus_space_read_1((_sc)->ae_mem_bt, (_sc)->ae_mem_bh, (reg)) 169f85e0762SSepherosa Ziehau 170f85e0762SSepherosa Ziehau #define AE_PHY_READ(sc, reg) \ 171f85e0762SSepherosa Ziehau ae_miibus_readreg(sc->ae_dev, 0, reg) 172f85e0762SSepherosa Ziehau #define AE_PHY_WRITE(sc, reg, val) \ 173f85e0762SSepherosa Ziehau ae_miibus_writereg(sc->ae_dev, 0, reg, val) 174f85e0762SSepherosa Ziehau #define AE_CHECK_EADDR_VALID(eaddr) \ 175f85e0762SSepherosa Ziehau ((eaddr[0] == 0 && eaddr[1] == 0) || \ 176f85e0762SSepherosa Ziehau (eaddr[0] == 0xffffffff && eaddr[1] == 0xffff)) 177f85e0762SSepherosa Ziehau #define AE_RXD_VLAN(vtag) \ 178f85e0762SSepherosa Ziehau (((vtag) >> 4) | (((vtag) & 0x07) << 13) | (((vtag) & 0x08) << 9)) 179f85e0762SSepherosa Ziehau #define AE_TXD_VLAN(vtag) \ 180f85e0762SSepherosa Ziehau (((vtag) << 4) | (((vtag) >> 13) & 0x07) | (((vtag) >> 9) & 0x08)) 181f85e0762SSepherosa Ziehau 182f85e0762SSepherosa Ziehau /* 183f85e0762SSepherosa Ziehau * ae statistics. 184f85e0762SSepherosa Ziehau */ 185f85e0762SSepherosa Ziehau #define STATS_ENTRY(node, desc, field) \ 186f85e0762SSepherosa Ziehau { node, desc, offsetof(struct ae_stats, field) } 187f85e0762SSepherosa Ziehau struct { 188f85e0762SSepherosa Ziehau const char *node; 189f85e0762SSepherosa Ziehau const char *desc; 190f85e0762SSepherosa Ziehau intptr_t offset; 191f85e0762SSepherosa Ziehau } ae_stats_tx[] = { 192f85e0762SSepherosa Ziehau STATS_ENTRY("bcast", "broadcast frames", tx_bcast), 193f85e0762SSepherosa Ziehau STATS_ENTRY("mcast", "multicast frames", tx_mcast), 194f85e0762SSepherosa Ziehau STATS_ENTRY("pause", "PAUSE frames", tx_pause), 195f85e0762SSepherosa Ziehau STATS_ENTRY("control", "control frames", tx_ctrl), 196f85e0762SSepherosa Ziehau STATS_ENTRY("defers", "deferrals occuried", tx_defer), 197f85e0762SSepherosa Ziehau STATS_ENTRY("exc_defers", "excessive deferrals occuried", tx_excdefer), 198f85e0762SSepherosa Ziehau STATS_ENTRY("singlecols", "single collisions occuried", tx_singlecol), 199f85e0762SSepherosa Ziehau STATS_ENTRY("multicols", "multiple collisions occuried", tx_multicol), 200f85e0762SSepherosa Ziehau STATS_ENTRY("latecols", "late collisions occuried", tx_latecol), 201f85e0762SSepherosa Ziehau STATS_ENTRY("aborts", "transmit aborts due collisions", tx_abortcol), 202f85e0762SSepherosa Ziehau STATS_ENTRY("underruns", "Tx FIFO underruns", tx_underrun) 203f85e0762SSepherosa Ziehau }, ae_stats_rx[] = { 204f85e0762SSepherosa Ziehau STATS_ENTRY("bcast", "broadcast frames", rx_bcast), 205f85e0762SSepherosa Ziehau STATS_ENTRY("mcast", "multicast frames", rx_mcast), 206f85e0762SSepherosa Ziehau STATS_ENTRY("pause", "PAUSE frames", rx_pause), 207f85e0762SSepherosa Ziehau STATS_ENTRY("control", "control frames", rx_ctrl), 208f85e0762SSepherosa Ziehau STATS_ENTRY("crc_errors", "frames with CRC errors", rx_crcerr), 209f85e0762SSepherosa Ziehau STATS_ENTRY("code_errors", "frames with invalid opcode", rx_codeerr), 210f85e0762SSepherosa Ziehau STATS_ENTRY("runt", "runt frames", rx_runt), 211f85e0762SSepherosa Ziehau STATS_ENTRY("frag", "fragmented frames", rx_frag), 212f85e0762SSepherosa Ziehau STATS_ENTRY("align_errors", "frames with alignment errors", rx_align), 213f85e0762SSepherosa Ziehau STATS_ENTRY("truncated", "frames truncated due to Rx FIFO inderrun", 214f85e0762SSepherosa Ziehau rx_trunc) 215f85e0762SSepherosa Ziehau }; 216b370aff7SSascha Wildner #define AE_STATS_RX_LEN NELEM(ae_stats_rx) 217b370aff7SSascha Wildner #define AE_STATS_TX_LEN NELEM(ae_stats_tx) 218f85e0762SSepherosa Ziehau 219f85e0762SSepherosa Ziehau static void 220f85e0762SSepherosa Ziehau ae_stop(struct ae_softc *sc) 221f85e0762SSepherosa Ziehau { 222f85e0762SSepherosa Ziehau struct ifnet *ifp = &sc->arpcom.ac_if; 223f85e0762SSepherosa Ziehau int i; 224f85e0762SSepherosa Ziehau 225f85e0762SSepherosa Ziehau ASSERT_SERIALIZED(ifp->if_serializer); 226f85e0762SSepherosa Ziehau 2279ed293e0SSepherosa Ziehau ifp->if_flags &= ~IFF_RUNNING; 2289ed293e0SSepherosa Ziehau ifq_clr_oactive(&ifp->if_snd); 229f85e0762SSepherosa Ziehau ifp->if_timer = 0; 230f85e0762SSepherosa Ziehau 231f85e0762SSepherosa Ziehau sc->ae_flags &= ~AE_FLAG_LINK; 232f85e0762SSepherosa Ziehau callout_stop(&sc->ae_tick_ch); 233f85e0762SSepherosa Ziehau 234f85e0762SSepherosa Ziehau /* 235f85e0762SSepherosa Ziehau * Clear and disable interrupts. 236f85e0762SSepherosa Ziehau */ 237f85e0762SSepherosa Ziehau AE_WRITE_4(sc, AE_IMR_REG, 0); 238f85e0762SSepherosa Ziehau AE_WRITE_4(sc, AE_ISR_REG, 0xffffffff); 239f85e0762SSepherosa Ziehau 240f85e0762SSepherosa Ziehau /* 241f85e0762SSepherosa Ziehau * Stop Rx/Tx MACs. 242f85e0762SSepherosa Ziehau */ 243f85e0762SSepherosa Ziehau ae_stop_txmac(sc); 244f85e0762SSepherosa Ziehau ae_stop_rxmac(sc); 245f85e0762SSepherosa Ziehau 246f85e0762SSepherosa Ziehau /* 247f85e0762SSepherosa Ziehau * Stop DMA engines. 248f85e0762SSepherosa Ziehau */ 249f85e0762SSepherosa Ziehau AE_WRITE_1(sc, AE_DMAREAD_REG, ~AE_DMAREAD_EN); 250f85e0762SSepherosa Ziehau AE_WRITE_1(sc, AE_DMAWRITE_REG, ~AE_DMAWRITE_EN); 251f85e0762SSepherosa Ziehau 252f85e0762SSepherosa Ziehau /* 253f85e0762SSepherosa Ziehau * Wait for everything to enter idle state. 254f85e0762SSepherosa Ziehau */ 255f85e0762SSepherosa Ziehau for (i = 0; i < AE_IDLE_TIMEOUT; i++) { 256f85e0762SSepherosa Ziehau if (AE_READ_4(sc, AE_IDLE_REG) == 0) 257f85e0762SSepherosa Ziehau break; 258f85e0762SSepherosa Ziehau DELAY(100); 259f85e0762SSepherosa Ziehau } 260f85e0762SSepherosa Ziehau if (i == AE_IDLE_TIMEOUT) 261f85e0762SSepherosa Ziehau if_printf(ifp, "could not enter idle state in stop.\n"); 262f85e0762SSepherosa Ziehau } 263f85e0762SSepherosa Ziehau 264f85e0762SSepherosa Ziehau static void 265f85e0762SSepherosa Ziehau ae_stop_rxmac(struct ae_softc *sc) 266f85e0762SSepherosa Ziehau { 267f85e0762SSepherosa Ziehau uint32_t val; 268f85e0762SSepherosa Ziehau int i; 269f85e0762SSepherosa Ziehau 270f85e0762SSepherosa Ziehau /* 271f85e0762SSepherosa Ziehau * Stop Rx MAC engine. 272f85e0762SSepherosa Ziehau */ 273f85e0762SSepherosa Ziehau val = AE_READ_4(sc, AE_MAC_REG); 274f85e0762SSepherosa Ziehau if ((val & AE_MAC_RX_EN) != 0) { 275f85e0762SSepherosa Ziehau val &= ~AE_MAC_RX_EN; 276f85e0762SSepherosa Ziehau AE_WRITE_4(sc, AE_MAC_REG, val); 277f85e0762SSepherosa Ziehau } 278f85e0762SSepherosa Ziehau 279f85e0762SSepherosa Ziehau /* 280f85e0762SSepherosa Ziehau * Stop Rx DMA engine. 281f85e0762SSepherosa Ziehau */ 282f85e0762SSepherosa Ziehau if (AE_READ_1(sc, AE_DMAWRITE_REG) == AE_DMAWRITE_EN) 283f85e0762SSepherosa Ziehau AE_WRITE_1(sc, AE_DMAWRITE_REG, 0); 284f85e0762SSepherosa Ziehau 285f85e0762SSepherosa Ziehau /* 286f85e0762SSepherosa Ziehau * Wait for IDLE state. 287f85e0762SSepherosa Ziehau */ 288f85e0762SSepherosa Ziehau for (i = 0; i < AE_IDLE_TIMEOUT; i--) { 289f85e0762SSepherosa Ziehau val = AE_READ_4(sc, AE_IDLE_REG); 290f85e0762SSepherosa Ziehau if ((val & (AE_IDLE_RXMAC | AE_IDLE_DMAWRITE)) == 0) 291f85e0762SSepherosa Ziehau break; 292f85e0762SSepherosa Ziehau DELAY(100); 293f85e0762SSepherosa Ziehau } 294f85e0762SSepherosa Ziehau if (i == AE_IDLE_TIMEOUT) { 295f85e0762SSepherosa Ziehau if_printf(&sc->arpcom.ac_if, 296f85e0762SSepherosa Ziehau "timed out while stopping Rx MAC.\n"); 297f85e0762SSepherosa Ziehau } 298f85e0762SSepherosa Ziehau } 299f85e0762SSepherosa Ziehau 300f85e0762SSepherosa Ziehau static void 301f85e0762SSepherosa Ziehau ae_stop_txmac(struct ae_softc *sc) 302f85e0762SSepherosa Ziehau { 303f85e0762SSepherosa Ziehau uint32_t val; 304f85e0762SSepherosa Ziehau int i; 305f85e0762SSepherosa Ziehau 306f85e0762SSepherosa Ziehau /* 307f85e0762SSepherosa Ziehau * Stop Tx MAC engine. 308f85e0762SSepherosa Ziehau */ 309f85e0762SSepherosa Ziehau val = AE_READ_4(sc, AE_MAC_REG); 310f85e0762SSepherosa Ziehau if ((val & AE_MAC_TX_EN) != 0) { 311f85e0762SSepherosa Ziehau val &= ~AE_MAC_TX_EN; 312f85e0762SSepherosa Ziehau AE_WRITE_4(sc, AE_MAC_REG, val); 313f85e0762SSepherosa Ziehau } 314f85e0762SSepherosa Ziehau 315f85e0762SSepherosa Ziehau /* 316f85e0762SSepherosa Ziehau * Stop Tx DMA engine. 317f85e0762SSepherosa Ziehau */ 318f85e0762SSepherosa Ziehau if (AE_READ_1(sc, AE_DMAREAD_REG) == AE_DMAREAD_EN) 319f85e0762SSepherosa Ziehau AE_WRITE_1(sc, AE_DMAREAD_REG, 0); 320f85e0762SSepherosa Ziehau 321f85e0762SSepherosa Ziehau /* 322f85e0762SSepherosa Ziehau * Wait for IDLE state. 323f85e0762SSepherosa Ziehau */ 324f85e0762SSepherosa Ziehau for (i = 0; i < AE_IDLE_TIMEOUT; i--) { 325f85e0762SSepherosa Ziehau val = AE_READ_4(sc, AE_IDLE_REG); 326f85e0762SSepherosa Ziehau if ((val & (AE_IDLE_TXMAC | AE_IDLE_DMAREAD)) == 0) 327f85e0762SSepherosa Ziehau break; 328f85e0762SSepherosa Ziehau DELAY(100); 329f85e0762SSepherosa Ziehau } 330f85e0762SSepherosa Ziehau if (i == AE_IDLE_TIMEOUT) { 331f85e0762SSepherosa Ziehau if_printf(&sc->arpcom.ac_if, 332f85e0762SSepherosa Ziehau "timed out while stopping Tx MAC.\n"); 333f85e0762SSepherosa Ziehau } 334f85e0762SSepherosa Ziehau } 335f85e0762SSepherosa Ziehau 336f85e0762SSepherosa Ziehau /* 337f85e0762SSepherosa Ziehau * Callback from MII layer when media changes. 338f85e0762SSepherosa Ziehau */ 339f85e0762SSepherosa Ziehau static void 340f85e0762SSepherosa Ziehau ae_miibus_statchg(device_t dev) 341f85e0762SSepherosa Ziehau { 342f85e0762SSepherosa Ziehau struct ae_softc *sc = device_get_softc(dev); 343f85e0762SSepherosa Ziehau struct ifnet *ifp = &sc->arpcom.ac_if; 344f85e0762SSepherosa Ziehau struct mii_data *mii; 345f85e0762SSepherosa Ziehau uint32_t val; 346f85e0762SSepherosa Ziehau 347f85e0762SSepherosa Ziehau ASSERT_SERIALIZED(ifp->if_serializer); 348f85e0762SSepherosa Ziehau 349f85e0762SSepherosa Ziehau if ((ifp->if_flags & IFF_RUNNING) == 0) 350f85e0762SSepherosa Ziehau return; 351f85e0762SSepherosa Ziehau 352f85e0762SSepherosa Ziehau mii = device_get_softc(sc->ae_miibus); 353f85e0762SSepherosa Ziehau sc->ae_flags &= ~AE_FLAG_LINK; 354f85e0762SSepherosa Ziehau if ((mii->mii_media_status & IFM_AVALID) != 0) { 355f85e0762SSepherosa Ziehau switch (IFM_SUBTYPE(mii->mii_media_active)) { 356f85e0762SSepherosa Ziehau case IFM_10_T: 357f85e0762SSepherosa Ziehau case IFM_100_TX: 358f85e0762SSepherosa Ziehau sc->ae_flags |= AE_FLAG_LINK; 359f85e0762SSepherosa Ziehau break; 360f85e0762SSepherosa Ziehau default: 361f85e0762SSepherosa Ziehau break; 362f85e0762SSepherosa Ziehau } 363f85e0762SSepherosa Ziehau } 364f85e0762SSepherosa Ziehau 365f85e0762SSepherosa Ziehau /* Stop Rx/Tx MACs. */ 366f85e0762SSepherosa Ziehau ae_stop_rxmac(sc); 367f85e0762SSepherosa Ziehau ae_stop_txmac(sc); 368f85e0762SSepherosa Ziehau 369f85e0762SSepherosa Ziehau /* Program MACs with resolved speed/duplex/flow-control. */ 370f85e0762SSepherosa Ziehau if ((sc->ae_flags & AE_FLAG_LINK) != 0) { 371f85e0762SSepherosa Ziehau ae_mac_config(sc); 372f85e0762SSepherosa Ziehau 373f85e0762SSepherosa Ziehau /* 374f85e0762SSepherosa Ziehau * Restart DMA engines. 375f85e0762SSepherosa Ziehau */ 376f85e0762SSepherosa Ziehau AE_WRITE_1(sc, AE_DMAREAD_REG, AE_DMAREAD_EN); 377f85e0762SSepherosa Ziehau AE_WRITE_1(sc, AE_DMAWRITE_REG, AE_DMAWRITE_EN); 378f85e0762SSepherosa Ziehau 379f85e0762SSepherosa Ziehau /* 380f85e0762SSepherosa Ziehau * Enable Rx and Tx MACs. 381f85e0762SSepherosa Ziehau */ 382f85e0762SSepherosa Ziehau val = AE_READ_4(sc, AE_MAC_REG); 383f85e0762SSepherosa Ziehau val |= AE_MAC_TX_EN | AE_MAC_RX_EN; 384f85e0762SSepherosa Ziehau AE_WRITE_4(sc, AE_MAC_REG, val); 385f85e0762SSepherosa Ziehau } 386f85e0762SSepherosa Ziehau } 387f85e0762SSepherosa Ziehau 388f85e0762SSepherosa Ziehau static void 389f85e0762SSepherosa Ziehau ae_sysctl_node(struct ae_softc *sc) 390f85e0762SSepherosa Ziehau { 391f85e0762SSepherosa Ziehau struct sysctl_ctx_list *ctx; 392f85e0762SSepherosa Ziehau struct sysctl_oid *root, *stats, *stats_rx, *stats_tx; 393f85e0762SSepherosa Ziehau struct ae_stats *ae_stats; 394f85e0762SSepherosa Ziehau unsigned int i; 395f85e0762SSepherosa Ziehau 396f85e0762SSepherosa Ziehau ae_stats = &sc->stats; 397f85e0762SSepherosa Ziehau sysctl_ctx_init(&sc->ae_sysctl_ctx); 398f85e0762SSepherosa Ziehau sc->ae_sysctl_tree = SYSCTL_ADD_NODE(&sc->ae_sysctl_ctx, 399f85e0762SSepherosa Ziehau SYSCTL_STATIC_CHILDREN(_hw), OID_AUTO, 400f85e0762SSepherosa Ziehau device_get_nameunit(sc->ae_dev), 401f85e0762SSepherosa Ziehau CTLFLAG_RD, 0, ""); 402f85e0762SSepherosa Ziehau if (sc->ae_sysctl_tree == NULL) { 403f85e0762SSepherosa Ziehau device_printf(sc->ae_dev, "can't add sysctl node\n"); 404f85e0762SSepherosa Ziehau return; 405f85e0762SSepherosa Ziehau } 406f85e0762SSepherosa Ziehau ctx = &sc->ae_sysctl_ctx; 407f85e0762SSepherosa Ziehau root = sc->ae_sysctl_tree; 408f85e0762SSepherosa Ziehau 409f85e0762SSepherosa Ziehau stats = SYSCTL_ADD_NODE(ctx, SYSCTL_CHILDREN(root), OID_AUTO, "stats", 410f85e0762SSepherosa Ziehau CTLFLAG_RD, NULL, "ae statistics"); 411f85e0762SSepherosa Ziehau if (stats == NULL) { 412f85e0762SSepherosa Ziehau device_printf(sc->ae_dev, "can't add stats sysctl node\n"); 413f85e0762SSepherosa Ziehau return; 414f85e0762SSepherosa Ziehau } 415f85e0762SSepherosa Ziehau 416f85e0762SSepherosa Ziehau /* 417f85e0762SSepherosa Ziehau * Receiver statistcics. 418f85e0762SSepherosa Ziehau */ 419f85e0762SSepherosa Ziehau stats_rx = SYSCTL_ADD_NODE(ctx, SYSCTL_CHILDREN(stats), OID_AUTO, "rx", 420f85e0762SSepherosa Ziehau CTLFLAG_RD, NULL, "Rx MAC statistics"); 421f85e0762SSepherosa Ziehau if (stats_rx != NULL) { 422f85e0762SSepherosa Ziehau for (i = 0; i < AE_STATS_RX_LEN; i++) { 423f85e0762SSepherosa Ziehau SYSCTL_ADD_UINT(ctx, SYSCTL_CHILDREN(stats_rx), 424f85e0762SSepherosa Ziehau OID_AUTO, ae_stats_rx[i].node, CTLFLAG_RD, 425f85e0762SSepherosa Ziehau (char *)ae_stats + ae_stats_rx[i].offset, 0, 426f85e0762SSepherosa Ziehau ae_stats_rx[i].desc); 427f85e0762SSepherosa Ziehau } 428f85e0762SSepherosa Ziehau } 429f85e0762SSepherosa Ziehau 430f85e0762SSepherosa Ziehau /* 431f85e0762SSepherosa Ziehau * Transmitter statistcics. 432f85e0762SSepherosa Ziehau */ 433f85e0762SSepherosa Ziehau stats_tx = SYSCTL_ADD_NODE(ctx, SYSCTL_CHILDREN(stats), OID_AUTO, "tx", 434f85e0762SSepherosa Ziehau CTLFLAG_RD, NULL, "Tx MAC statistics"); 435f85e0762SSepherosa Ziehau if (stats_tx != NULL) { 436f85e0762SSepherosa Ziehau for (i = 0; i < AE_STATS_TX_LEN; i++) { 437f85e0762SSepherosa Ziehau SYSCTL_ADD_UINT(ctx, SYSCTL_CHILDREN(stats_tx), 438f85e0762SSepherosa Ziehau OID_AUTO, ae_stats_tx[i].node, CTLFLAG_RD, 439f85e0762SSepherosa Ziehau (char *)ae_stats + ae_stats_tx[i].offset, 0, 440f85e0762SSepherosa Ziehau ae_stats_tx[i].desc); 441f85e0762SSepherosa Ziehau } 442f85e0762SSepherosa Ziehau } 443f85e0762SSepherosa Ziehau } 444f85e0762SSepherosa Ziehau 445f85e0762SSepherosa Ziehau static int 446f85e0762SSepherosa Ziehau ae_miibus_readreg(device_t dev, int phy, int reg) 447f85e0762SSepherosa Ziehau { 448f85e0762SSepherosa Ziehau struct ae_softc *sc = device_get_softc(dev); 449f85e0762SSepherosa Ziehau uint32_t val; 450f85e0762SSepherosa Ziehau int i; 451f85e0762SSepherosa Ziehau 452f85e0762SSepherosa Ziehau /* 453f85e0762SSepherosa Ziehau * Locking is done in upper layers. 454f85e0762SSepherosa Ziehau */ 455f85e0762SSepherosa Ziehau if (phy != sc->ae_phyaddr) 456f85e0762SSepherosa Ziehau return (0); 457f85e0762SSepherosa Ziehau val = ((reg << AE_MDIO_REGADDR_SHIFT) & AE_MDIO_REGADDR_MASK) | 458f85e0762SSepherosa Ziehau AE_MDIO_START | AE_MDIO_READ | AE_MDIO_SUP_PREAMBLE | 459f85e0762SSepherosa Ziehau ((AE_MDIO_CLK_25_4 << AE_MDIO_CLK_SHIFT) & AE_MDIO_CLK_MASK); 460f85e0762SSepherosa Ziehau AE_WRITE_4(sc, AE_MDIO_REG, val); 461f85e0762SSepherosa Ziehau 462f85e0762SSepherosa Ziehau /* 463f85e0762SSepherosa Ziehau * Wait for operation to complete. 464f85e0762SSepherosa Ziehau */ 465f85e0762SSepherosa Ziehau for (i = 0; i < AE_MDIO_TIMEOUT; i++) { 466f85e0762SSepherosa Ziehau DELAY(2); 467f85e0762SSepherosa Ziehau val = AE_READ_4(sc, AE_MDIO_REG); 468f85e0762SSepherosa Ziehau if ((val & (AE_MDIO_START | AE_MDIO_BUSY)) == 0) 469f85e0762SSepherosa Ziehau break; 470f85e0762SSepherosa Ziehau } 471f85e0762SSepherosa Ziehau if (i == AE_MDIO_TIMEOUT) { 472f85e0762SSepherosa Ziehau device_printf(sc->ae_dev, "phy read timeout: %d.\n", reg); 473f85e0762SSepherosa Ziehau return (0); 474f85e0762SSepherosa Ziehau } 475f85e0762SSepherosa Ziehau return ((val << AE_MDIO_DATA_SHIFT) & AE_MDIO_DATA_MASK); 476f85e0762SSepherosa Ziehau } 477f85e0762SSepherosa Ziehau 478f85e0762SSepherosa Ziehau static int 479f85e0762SSepherosa Ziehau ae_miibus_writereg(device_t dev, int phy, int reg, int val) 480f85e0762SSepherosa Ziehau { 481f85e0762SSepherosa Ziehau struct ae_softc *sc = device_get_softc(dev); 482f85e0762SSepherosa Ziehau uint32_t aereg; 483f85e0762SSepherosa Ziehau int i; 484f85e0762SSepherosa Ziehau 485f85e0762SSepherosa Ziehau /* 486f85e0762SSepherosa Ziehau * Locking is done in upper layers. 487f85e0762SSepherosa Ziehau */ 488f85e0762SSepherosa Ziehau if (phy != sc->ae_phyaddr) 489f85e0762SSepherosa Ziehau return (0); 490f85e0762SSepherosa Ziehau aereg = ((reg << AE_MDIO_REGADDR_SHIFT) & AE_MDIO_REGADDR_MASK) | 491f85e0762SSepherosa Ziehau AE_MDIO_START | AE_MDIO_SUP_PREAMBLE | 492f85e0762SSepherosa Ziehau ((AE_MDIO_CLK_25_4 << AE_MDIO_CLK_SHIFT) & AE_MDIO_CLK_MASK) | 493f85e0762SSepherosa Ziehau ((val << AE_MDIO_DATA_SHIFT) & AE_MDIO_DATA_MASK); 494f85e0762SSepherosa Ziehau AE_WRITE_4(sc, AE_MDIO_REG, aereg); 495f85e0762SSepherosa Ziehau 496f85e0762SSepherosa Ziehau /* 497f85e0762SSepherosa Ziehau * Wait for operation to complete. 498f85e0762SSepherosa Ziehau */ 499f85e0762SSepherosa Ziehau for (i = 0; i < AE_MDIO_TIMEOUT; i++) { 500f85e0762SSepherosa Ziehau DELAY(2); 501f85e0762SSepherosa Ziehau aereg = AE_READ_4(sc, AE_MDIO_REG); 502f85e0762SSepherosa Ziehau if ((aereg & (AE_MDIO_START | AE_MDIO_BUSY)) == 0) 503f85e0762SSepherosa Ziehau break; 504f85e0762SSepherosa Ziehau } 505f85e0762SSepherosa Ziehau if (i == AE_MDIO_TIMEOUT) 506f85e0762SSepherosa Ziehau device_printf(sc->ae_dev, "phy write timeout: %d.\n", reg); 507f85e0762SSepherosa Ziehau return (0); 508f85e0762SSepherosa Ziehau } 509f85e0762SSepherosa Ziehau 510f85e0762SSepherosa Ziehau static int 511f85e0762SSepherosa Ziehau ae_probe(device_t dev) 512f85e0762SSepherosa Ziehau { 513f85e0762SSepherosa Ziehau uint16_t vendor, devid; 514f85e0762SSepherosa Ziehau const struct ae_dev *sp; 515f85e0762SSepherosa Ziehau 516f85e0762SSepherosa Ziehau vendor = pci_get_vendor(dev); 517f85e0762SSepherosa Ziehau devid = pci_get_device(dev); 518f85e0762SSepherosa Ziehau for (sp = ae_devs; sp->ae_name != NULL; sp++) { 519f85e0762SSepherosa Ziehau if (vendor == sp->ae_vendorid && 520f85e0762SSepherosa Ziehau devid == sp->ae_deviceid) { 521f85e0762SSepherosa Ziehau device_set_desc(dev, sp->ae_name); 522f85e0762SSepherosa Ziehau return (0); 523f85e0762SSepherosa Ziehau } 524f85e0762SSepherosa Ziehau } 525f85e0762SSepherosa Ziehau return (ENXIO); 526f85e0762SSepherosa Ziehau } 527f85e0762SSepherosa Ziehau 528f85e0762SSepherosa Ziehau static int 529f85e0762SSepherosa Ziehau ae_dma_alloc(struct ae_softc *sc) 530f85e0762SSepherosa Ziehau { 531f85e0762SSepherosa Ziehau bus_addr_t busaddr; 532f85e0762SSepherosa Ziehau int error; 533f85e0762SSepherosa Ziehau 534f85e0762SSepherosa Ziehau /* 535f85e0762SSepherosa Ziehau * Create parent DMA tag. 536f85e0762SSepherosa Ziehau */ 537f85e0762SSepherosa Ziehau error = bus_dma_tag_create(NULL, 1, 0, 538f85e0762SSepherosa Ziehau BUS_SPACE_MAXADDR_32BIT, 539f85e0762SSepherosa Ziehau BUS_SPACE_MAXADDR, 540f85e0762SSepherosa Ziehau NULL, NULL, 541f85e0762SSepherosa Ziehau BUS_SPACE_MAXSIZE_32BIT, 542f85e0762SSepherosa Ziehau 0, 543f85e0762SSepherosa Ziehau BUS_SPACE_MAXSIZE_32BIT, 544f85e0762SSepherosa Ziehau 0, &sc->dma_parent_tag); 545f85e0762SSepherosa Ziehau if (error) { 546f85e0762SSepherosa Ziehau device_printf(sc->ae_dev, "could not creare parent DMA tag.\n"); 547f85e0762SSepherosa Ziehau return (error); 548f85e0762SSepherosa Ziehau } 549f85e0762SSepherosa Ziehau 550f85e0762SSepherosa Ziehau /* 551f85e0762SSepherosa Ziehau * Create DMA stuffs for TxD. 552f85e0762SSepherosa Ziehau */ 553f85e0762SSepherosa Ziehau sc->txd_base = bus_dmamem_coherent_any(sc->dma_parent_tag, 4, 554f85e0762SSepherosa Ziehau AE_TXD_BUFSIZE_DEFAULT, BUS_DMA_WAITOK | BUS_DMA_ZERO, 555f85e0762SSepherosa Ziehau &sc->dma_txd_tag, &sc->dma_txd_map, 556f85e0762SSepherosa Ziehau &sc->dma_txd_busaddr); 557f85e0762SSepherosa Ziehau if (sc->txd_base == NULL) { 558f85e0762SSepherosa Ziehau device_printf(sc->ae_dev, "could not creare TxD DMA stuffs.\n"); 559f85e0762SSepherosa Ziehau return ENOMEM; 560f85e0762SSepherosa Ziehau } 561f85e0762SSepherosa Ziehau 562f85e0762SSepherosa Ziehau /* 563f85e0762SSepherosa Ziehau * Create DMA stuffs for TxS. 564f85e0762SSepherosa Ziehau */ 565f85e0762SSepherosa Ziehau sc->txs_base = bus_dmamem_coherent_any(sc->dma_parent_tag, 4, 566f85e0762SSepherosa Ziehau AE_TXS_COUNT_DEFAULT * 4, BUS_DMA_WAITOK | BUS_DMA_ZERO, 567f85e0762SSepherosa Ziehau &sc->dma_txs_tag, &sc->dma_txs_map, 568f85e0762SSepherosa Ziehau &sc->dma_txs_busaddr); 569f85e0762SSepherosa Ziehau if (sc->txs_base == NULL) { 570f85e0762SSepherosa Ziehau device_printf(sc->ae_dev, "could not creare TxS DMA stuffs.\n"); 571f85e0762SSepherosa Ziehau return ENOMEM; 572f85e0762SSepherosa Ziehau } 573f85e0762SSepherosa Ziehau 574f85e0762SSepherosa Ziehau /* 575f85e0762SSepherosa Ziehau * Create DMA stuffs for RxD. 576f85e0762SSepherosa Ziehau */ 577f85e0762SSepherosa Ziehau sc->rxd_base_dma = bus_dmamem_coherent_any(sc->dma_parent_tag, 128, 578f85e0762SSepherosa Ziehau AE_RXD_COUNT_DEFAULT * 1536 + 120, 579f85e0762SSepherosa Ziehau BUS_DMA_WAITOK | BUS_DMA_ZERO, 580f85e0762SSepherosa Ziehau &sc->dma_rxd_tag, &sc->dma_rxd_map, 581f85e0762SSepherosa Ziehau &busaddr); 582f85e0762SSepherosa Ziehau if (sc->rxd_base_dma == NULL) { 583f85e0762SSepherosa Ziehau device_printf(sc->ae_dev, "could not creare RxD DMA stuffs.\n"); 584f85e0762SSepherosa Ziehau return ENOMEM; 585f85e0762SSepherosa Ziehau } 586f85e0762SSepherosa Ziehau sc->dma_rxd_busaddr = busaddr + 120; 587f85e0762SSepherosa Ziehau sc->rxd_base = (struct ae_rxd *)(sc->rxd_base_dma + 120); 588f85e0762SSepherosa Ziehau 589f85e0762SSepherosa Ziehau return (0); 590f85e0762SSepherosa Ziehau } 591f85e0762SSepherosa Ziehau 592f85e0762SSepherosa Ziehau static void 593f85e0762SSepherosa Ziehau ae_mac_config(struct ae_softc *sc) 594f85e0762SSepherosa Ziehau { 595f85e0762SSepherosa Ziehau struct mii_data *mii; 596f85e0762SSepherosa Ziehau uint32_t val; 597f85e0762SSepherosa Ziehau 598f85e0762SSepherosa Ziehau mii = device_get_softc(sc->ae_miibus); 599f85e0762SSepherosa Ziehau val = AE_READ_4(sc, AE_MAC_REG); 600f85e0762SSepherosa Ziehau val &= ~AE_MAC_FULL_DUPLEX; 601f85e0762SSepherosa Ziehau /* XXX disable AE_MAC_TX_FLOW_EN? */ 602f85e0762SSepherosa Ziehau if ((IFM_OPTIONS(mii->mii_media_active) & IFM_FDX) != 0) 603f85e0762SSepherosa Ziehau val |= AE_MAC_FULL_DUPLEX; 604f85e0762SSepherosa Ziehau AE_WRITE_4(sc, AE_MAC_REG, val); 605f85e0762SSepherosa Ziehau } 606f85e0762SSepherosa Ziehau 607f85e0762SSepherosa Ziehau static int 608f85e0762SSepherosa Ziehau ae_rxeof(struct ae_softc *sc, struct ae_rxd *rxd) 609f85e0762SSepherosa Ziehau { 610f85e0762SSepherosa Ziehau struct ifnet *ifp = &sc->arpcom.ac_if; 611f85e0762SSepherosa Ziehau struct mbuf *m; 612f85e0762SSepherosa Ziehau unsigned int size; 613f85e0762SSepherosa Ziehau uint16_t flags; 614f85e0762SSepherosa Ziehau 615f85e0762SSepherosa Ziehau flags = le16toh(rxd->flags); 616f85e0762SSepherosa Ziehau #ifdef AE_DEBUG 617f85e0762SSepherosa Ziehau if_printf(ifp, "Rx interrupt occuried.\n"); 618f85e0762SSepherosa Ziehau #endif 619f85e0762SSepherosa Ziehau size = le16toh(rxd->len) - ETHER_CRC_LEN; 620f85e0762SSepherosa Ziehau if (size < (ETHER_MIN_LEN - ETHER_CRC_LEN - 621f85e0762SSepherosa Ziehau sizeof(struct ether_vlan_header))) { 622f85e0762SSepherosa Ziehau if_printf(ifp, "Runt frame received."); 623f85e0762SSepherosa Ziehau return (EIO); 624f85e0762SSepherosa Ziehau } 625f85e0762SSepherosa Ziehau 626f85e0762SSepherosa Ziehau m = m_devget(&rxd->data[0], size, ETHER_ALIGN, ifp, NULL); 627f85e0762SSepherosa Ziehau if (m == NULL) 628f85e0762SSepherosa Ziehau return (ENOBUFS); 629f85e0762SSepherosa Ziehau 630f85e0762SSepherosa Ziehau if ((ifp->if_capenable & IFCAP_VLAN_HWTAGGING) && 631f85e0762SSepherosa Ziehau (flags & AE_RXD_HAS_VLAN)) { 632f85e0762SSepherosa Ziehau m->m_pkthdr.ether_vlantag = AE_RXD_VLAN(le16toh(rxd->vlan)); 633f85e0762SSepherosa Ziehau m->m_flags |= M_VLANTAG; 634f85e0762SSepherosa Ziehau } 635f85e0762SSepherosa Ziehau ifp->if_input(ifp, m); 636f85e0762SSepherosa Ziehau 637f85e0762SSepherosa Ziehau return (0); 638f85e0762SSepherosa Ziehau } 639f85e0762SSepherosa Ziehau 640f85e0762SSepherosa Ziehau static void 641f85e0762SSepherosa Ziehau ae_rx_intr(struct ae_softc *sc) 642f85e0762SSepherosa Ziehau { 643f85e0762SSepherosa Ziehau struct ifnet *ifp = &sc->arpcom.ac_if; 644f85e0762SSepherosa Ziehau struct ae_rxd *rxd; 645f85e0762SSepherosa Ziehau uint16_t flags; 646f85e0762SSepherosa Ziehau int error; 647f85e0762SSepherosa Ziehau 648f85e0762SSepherosa Ziehau /* 649f85e0762SSepherosa Ziehau * Syncronize DMA buffers. 650f85e0762SSepherosa Ziehau */ 651f85e0762SSepherosa Ziehau bus_dmamap_sync(sc->dma_rxd_tag, sc->dma_rxd_map, 652f85e0762SSepherosa Ziehau BUS_DMASYNC_POSTREAD); 653f85e0762SSepherosa Ziehau for (;;) { 654f85e0762SSepherosa Ziehau rxd = (struct ae_rxd *)(sc->rxd_base + sc->rxd_cur); 655f85e0762SSepherosa Ziehau 656f85e0762SSepherosa Ziehau flags = le16toh(rxd->flags); 657f85e0762SSepherosa Ziehau if ((flags & AE_RXD_UPDATE) == 0) 658f85e0762SSepherosa Ziehau break; 659f85e0762SSepherosa Ziehau rxd->flags = htole16(flags & ~AE_RXD_UPDATE); 660f85e0762SSepherosa Ziehau 661f85e0762SSepherosa Ziehau /* Update stats. */ 662f85e0762SSepherosa Ziehau ae_update_stats_rx(flags, &sc->stats); 663f85e0762SSepherosa Ziehau 664f85e0762SSepherosa Ziehau /* 665f85e0762SSepherosa Ziehau * Update position index. 666f85e0762SSepherosa Ziehau */ 667f85e0762SSepherosa Ziehau sc->rxd_cur = (sc->rxd_cur + 1) % AE_RXD_COUNT_DEFAULT; 668f85e0762SSepherosa Ziehau if ((flags & AE_RXD_SUCCESS) == 0) { 669d40991efSSepherosa Ziehau IFNET_STAT_INC(ifp, ierrors, 1); 670f85e0762SSepherosa Ziehau continue; 671f85e0762SSepherosa Ziehau } 672f85e0762SSepherosa Ziehau 673f85e0762SSepherosa Ziehau error = ae_rxeof(sc, rxd); 674f85e0762SSepherosa Ziehau if (error) 675d40991efSSepherosa Ziehau IFNET_STAT_INC(ifp, ierrors, 1); 676f85e0762SSepherosa Ziehau else 677d40991efSSepherosa Ziehau IFNET_STAT_INC(ifp, ipackets, 1); 678f85e0762SSepherosa Ziehau } 679f85e0762SSepherosa Ziehau 680f85e0762SSepherosa Ziehau /* Update Rx index. */ 681f85e0762SSepherosa Ziehau AE_WRITE_2(sc, AE_MB_RXD_IDX_REG, sc->rxd_cur); 682f85e0762SSepherosa Ziehau } 683f85e0762SSepherosa Ziehau 684f85e0762SSepherosa Ziehau static void 685f85e0762SSepherosa Ziehau ae_tx_intr(struct ae_softc *sc) 686f85e0762SSepherosa Ziehau { 687f85e0762SSepherosa Ziehau struct ifnet *ifp = &sc->arpcom.ac_if; 688f85e0762SSepherosa Ziehau struct ae_txd *txd; 689f85e0762SSepherosa Ziehau struct ae_txs *txs; 690f85e0762SSepherosa Ziehau uint16_t flags; 691f85e0762SSepherosa Ziehau 692f85e0762SSepherosa Ziehau /* 693f85e0762SSepherosa Ziehau * Syncronize DMA buffers. 694f85e0762SSepherosa Ziehau */ 695f85e0762SSepherosa Ziehau bus_dmamap_sync(sc->dma_txd_tag, sc->dma_txd_map, BUS_DMASYNC_POSTREAD); 696f85e0762SSepherosa Ziehau bus_dmamap_sync(sc->dma_txs_tag, sc->dma_txs_map, BUS_DMASYNC_POSTREAD); 697f85e0762SSepherosa Ziehau 698f85e0762SSepherosa Ziehau for (;;) { 699f85e0762SSepherosa Ziehau txs = sc->txs_base + sc->txs_ack; 700f85e0762SSepherosa Ziehau 701f85e0762SSepherosa Ziehau flags = le16toh(txs->flags); 702f85e0762SSepherosa Ziehau if ((flags & AE_TXS_UPDATE) == 0) 703f85e0762SSepherosa Ziehau break; 704f85e0762SSepherosa Ziehau txs->flags = htole16(flags & ~AE_TXS_UPDATE); 705f85e0762SSepherosa Ziehau 706f85e0762SSepherosa Ziehau /* Update stats. */ 707f85e0762SSepherosa Ziehau ae_update_stats_tx(flags, &sc->stats); 708f85e0762SSepherosa Ziehau 709f85e0762SSepherosa Ziehau /* 710f85e0762SSepherosa Ziehau * Update TxS position. 711f85e0762SSepherosa Ziehau */ 712f85e0762SSepherosa Ziehau sc->txs_ack = (sc->txs_ack + 1) % AE_TXS_COUNT_DEFAULT; 713f85e0762SSepherosa Ziehau sc->ae_flags |= AE_FLAG_TXAVAIL; 714f85e0762SSepherosa Ziehau txd = (struct ae_txd *)(sc->txd_base + sc->txd_ack); 715f85e0762SSepherosa Ziehau if (txs->len != txd->len) { 716f85e0762SSepherosa Ziehau device_printf(sc->ae_dev, "Size mismatch: " 717f85e0762SSepherosa Ziehau "TxS:%d TxD:%d\n", 718f85e0762SSepherosa Ziehau le16toh(txs->len), le16toh(txd->len)); 719f85e0762SSepherosa Ziehau } 720f85e0762SSepherosa Ziehau 721f85e0762SSepherosa Ziehau /* 722f85e0762SSepherosa Ziehau * Move txd ack and align on 4-byte boundary. 723f85e0762SSepherosa Ziehau */ 724f85e0762SSepherosa Ziehau sc->txd_ack = ((sc->txd_ack + le16toh(txd->len) + 4 + 3) & ~3) % 725f85e0762SSepherosa Ziehau AE_TXD_BUFSIZE_DEFAULT; 726f85e0762SSepherosa Ziehau if ((flags & AE_TXS_SUCCESS) != 0) 727d40991efSSepherosa Ziehau IFNET_STAT_INC(ifp, opackets, 1); 728f85e0762SSepherosa Ziehau else 729d40991efSSepherosa Ziehau IFNET_STAT_INC(ifp, oerrors, 1); 730f85e0762SSepherosa Ziehau sc->tx_inproc--; 731f85e0762SSepherosa Ziehau } 732f85e0762SSepherosa Ziehau 733f85e0762SSepherosa Ziehau if (sc->tx_inproc < 0) { 734f85e0762SSepherosa Ziehau /* XXX assert? */ 735f85e0762SSepherosa Ziehau if_printf(ifp, "Received stray Tx interrupt(s).\n"); 736f85e0762SSepherosa Ziehau sc->tx_inproc = 0; 737f85e0762SSepherosa Ziehau } 738f85e0762SSepherosa Ziehau if (sc->tx_inproc == 0) 739f85e0762SSepherosa Ziehau ifp->if_timer = 0; /* Unarm watchdog. */ 740f85e0762SSepherosa Ziehau if (sc->ae_flags & AE_FLAG_TXAVAIL) { 7419ed293e0SSepherosa Ziehau ifq_clr_oactive(&ifp->if_snd); 742f85e0762SSepherosa Ziehau if (!ifq_is_empty(&ifp->if_snd)) 743f85e0762SSepherosa Ziehau #ifdef foo 744f85e0762SSepherosa Ziehau ae_intr(sc); 745f85e0762SSepherosa Ziehau #else 746f85e0762SSepherosa Ziehau if_devstart(ifp); 747f85e0762SSepherosa Ziehau #endif 748f85e0762SSepherosa Ziehau } 749f85e0762SSepherosa Ziehau 750f85e0762SSepherosa Ziehau /* 751f85e0762SSepherosa Ziehau * Syncronize DMA buffers. 752f85e0762SSepherosa Ziehau */ 753f85e0762SSepherosa Ziehau bus_dmamap_sync(sc->dma_txd_tag, sc->dma_txd_map, BUS_DMASYNC_PREWRITE); 754f85e0762SSepherosa Ziehau bus_dmamap_sync(sc->dma_txs_tag, sc->dma_txs_map, BUS_DMASYNC_PREWRITE); 755f85e0762SSepherosa Ziehau } 756f85e0762SSepherosa Ziehau 757f85e0762SSepherosa Ziehau static void 758f85e0762SSepherosa Ziehau ae_intr(void *xsc) 759f85e0762SSepherosa Ziehau { 760f85e0762SSepherosa Ziehau struct ae_softc *sc = xsc; 761f85e0762SSepherosa Ziehau struct ifnet *ifp = &sc->arpcom.ac_if; 762f85e0762SSepherosa Ziehau uint32_t val; 763f85e0762SSepherosa Ziehau 764f85e0762SSepherosa Ziehau ASSERT_SERIALIZED(ifp->if_serializer); 765f85e0762SSepherosa Ziehau 766f85e0762SSepherosa Ziehau val = AE_READ_4(sc, AE_ISR_REG); 767f85e0762SSepherosa Ziehau if (val == 0 || (val & AE_IMR_DEFAULT) == 0) 768f85e0762SSepherosa Ziehau return; 769f85e0762SSepherosa Ziehau 770f85e0762SSepherosa Ziehau #ifdef foo 771f85e0762SSepherosa Ziehau AE_WRITE_4(sc, AE_ISR_REG, AE_ISR_DISABLE); 772f85e0762SSepherosa Ziehau #endif 773f85e0762SSepherosa Ziehau 774f85e0762SSepherosa Ziehau /* Read interrupt status. */ 775f85e0762SSepherosa Ziehau val = AE_READ_4(sc, AE_ISR_REG); 776f85e0762SSepherosa Ziehau 777f85e0762SSepherosa Ziehau /* Clear interrupts and disable them. */ 778f85e0762SSepherosa Ziehau AE_WRITE_4(sc, AE_ISR_REG, val | AE_ISR_DISABLE); 779f85e0762SSepherosa Ziehau 780f85e0762SSepherosa Ziehau if (ifp->if_flags & IFF_RUNNING) { 781f85e0762SSepherosa Ziehau if (val & (AE_ISR_DMAR_TIMEOUT | 782f85e0762SSepherosa Ziehau AE_ISR_DMAW_TIMEOUT | 783f85e0762SSepherosa Ziehau AE_ISR_PHY_LINKDOWN)) { 784f85e0762SSepherosa Ziehau ae_init(sc); 785f85e0762SSepherosa Ziehau } 786f85e0762SSepherosa Ziehau if (val & AE_ISR_TX_EVENT) 787f85e0762SSepherosa Ziehau ae_tx_intr(sc); 788f85e0762SSepherosa Ziehau if (val & AE_ISR_RX_EVENT) 789f85e0762SSepherosa Ziehau ae_rx_intr(sc); 790f85e0762SSepherosa Ziehau } 791f85e0762SSepherosa Ziehau 792f85e0762SSepherosa Ziehau /* Re-enable interrupts. */ 793f85e0762SSepherosa Ziehau AE_WRITE_4(sc, AE_ISR_REG, 0); 794f85e0762SSepherosa Ziehau } 795f85e0762SSepherosa Ziehau 796f85e0762SSepherosa Ziehau static void 797f85e0762SSepherosa Ziehau ae_init(void *xsc) 798f85e0762SSepherosa Ziehau { 799f85e0762SSepherosa Ziehau struct ae_softc *sc = xsc; 800f85e0762SSepherosa Ziehau struct ifnet *ifp = &sc->arpcom.ac_if; 801f85e0762SSepherosa Ziehau struct mii_data *mii; 802f85e0762SSepherosa Ziehau uint8_t eaddr[ETHER_ADDR_LEN]; 803f85e0762SSepherosa Ziehau uint32_t val; 804f85e0762SSepherosa Ziehau bus_addr_t addr; 805f85e0762SSepherosa Ziehau 806f85e0762SSepherosa Ziehau ASSERT_SERIALIZED(ifp->if_serializer); 807f85e0762SSepherosa Ziehau 808f85e0762SSepherosa Ziehau mii = device_get_softc(sc->ae_miibus); 809f85e0762SSepherosa Ziehau ae_stop(sc); 810f85e0762SSepherosa Ziehau ae_reset(sc); 811f85e0762SSepherosa Ziehau ae_pcie_init(sc); 812f85e0762SSepherosa Ziehau ae_powersave_disable(sc); 813f85e0762SSepherosa Ziehau 814f85e0762SSepherosa Ziehau /* 815f85e0762SSepherosa Ziehau * Clear and disable interrupts. 816f85e0762SSepherosa Ziehau */ 817f85e0762SSepherosa Ziehau AE_WRITE_4(sc, AE_ISR_REG, 0xffffffff); 818f85e0762SSepherosa Ziehau 819f85e0762SSepherosa Ziehau /* 820f85e0762SSepherosa Ziehau * Set the MAC address. 821f85e0762SSepherosa Ziehau */ 822f85e0762SSepherosa Ziehau bcopy(IF_LLADDR(ifp), eaddr, ETHER_ADDR_LEN); 823f85e0762SSepherosa Ziehau val = eaddr[2] << 24 | eaddr[3] << 16 | eaddr[4] << 8 | eaddr[5]; 824f85e0762SSepherosa Ziehau AE_WRITE_4(sc, AE_EADDR0_REG, val); 825f85e0762SSepherosa Ziehau val = eaddr[0] << 8 | eaddr[1]; 826f85e0762SSepherosa Ziehau AE_WRITE_4(sc, AE_EADDR1_REG, val); 827f85e0762SSepherosa Ziehau 828f85e0762SSepherosa Ziehau /* 829f85e0762SSepherosa Ziehau * Set ring buffers base addresses. 830f85e0762SSepherosa Ziehau */ 831f85e0762SSepherosa Ziehau addr = sc->dma_rxd_busaddr; 832f85e0762SSepherosa Ziehau AE_WRITE_4(sc, AE_DESC_ADDR_HI_REG, BUS_ADDR_HI(addr)); 833f85e0762SSepherosa Ziehau AE_WRITE_4(sc, AE_RXD_ADDR_LO_REG, BUS_ADDR_LO(addr)); 834f85e0762SSepherosa Ziehau addr = sc->dma_txd_busaddr; 835f85e0762SSepherosa Ziehau AE_WRITE_4(sc, AE_TXD_ADDR_LO_REG, BUS_ADDR_LO(addr)); 836f85e0762SSepherosa Ziehau addr = sc->dma_txs_busaddr; 837f85e0762SSepherosa Ziehau AE_WRITE_4(sc, AE_TXS_ADDR_LO_REG, BUS_ADDR_LO(addr)); 838f85e0762SSepherosa Ziehau 839f85e0762SSepherosa Ziehau /* 840f85e0762SSepherosa Ziehau * Configure ring buffers sizes. 841f85e0762SSepherosa Ziehau */ 842f85e0762SSepherosa Ziehau AE_WRITE_2(sc, AE_RXD_COUNT_REG, AE_RXD_COUNT_DEFAULT); 843f85e0762SSepherosa Ziehau AE_WRITE_2(sc, AE_TXD_BUFSIZE_REG, AE_TXD_BUFSIZE_DEFAULT / 4); 844f85e0762SSepherosa Ziehau AE_WRITE_2(sc, AE_TXS_COUNT_REG, AE_TXS_COUNT_DEFAULT); 845f85e0762SSepherosa Ziehau 846f85e0762SSepherosa Ziehau /* 847f85e0762SSepherosa Ziehau * Configure interframe gap parameters. 848f85e0762SSepherosa Ziehau */ 849f85e0762SSepherosa Ziehau val = ((AE_IFG_TXIPG_DEFAULT << AE_IFG_TXIPG_SHIFT) & 850f85e0762SSepherosa Ziehau AE_IFG_TXIPG_MASK) | 851f85e0762SSepherosa Ziehau ((AE_IFG_RXIPG_DEFAULT << AE_IFG_RXIPG_SHIFT) & 852f85e0762SSepherosa Ziehau AE_IFG_RXIPG_MASK) | 853f85e0762SSepherosa Ziehau ((AE_IFG_IPGR1_DEFAULT << AE_IFG_IPGR1_SHIFT) & 854f85e0762SSepherosa Ziehau AE_IFG_IPGR1_MASK) | 855f85e0762SSepherosa Ziehau ((AE_IFG_IPGR2_DEFAULT << AE_IFG_IPGR2_SHIFT) & 856f85e0762SSepherosa Ziehau AE_IFG_IPGR2_MASK); 857f85e0762SSepherosa Ziehau AE_WRITE_4(sc, AE_IFG_REG, val); 858f85e0762SSepherosa Ziehau 859f85e0762SSepherosa Ziehau /* 860f85e0762SSepherosa Ziehau * Configure half-duplex operation. 861f85e0762SSepherosa Ziehau */ 862f85e0762SSepherosa Ziehau val = ((AE_HDPX_LCOL_DEFAULT << AE_HDPX_LCOL_SHIFT) & 863f85e0762SSepherosa Ziehau AE_HDPX_LCOL_MASK) | 864f85e0762SSepherosa Ziehau ((AE_HDPX_RETRY_DEFAULT << AE_HDPX_RETRY_SHIFT) & 865f85e0762SSepherosa Ziehau AE_HDPX_RETRY_MASK) | 866f85e0762SSepherosa Ziehau ((AE_HDPX_ABEBT_DEFAULT << AE_HDPX_ABEBT_SHIFT) & 867f85e0762SSepherosa Ziehau AE_HDPX_ABEBT_MASK) | 868f85e0762SSepherosa Ziehau ((AE_HDPX_JAMIPG_DEFAULT << AE_HDPX_JAMIPG_SHIFT) & 869f85e0762SSepherosa Ziehau AE_HDPX_JAMIPG_MASK) | AE_HDPX_EXC_EN; 870f85e0762SSepherosa Ziehau AE_WRITE_4(sc, AE_HDPX_REG, val); 871f85e0762SSepherosa Ziehau 872f85e0762SSepherosa Ziehau /* 873f85e0762SSepherosa Ziehau * Configure interrupt moderate timer. 874f85e0762SSepherosa Ziehau */ 875f85e0762SSepherosa Ziehau AE_WRITE_2(sc, AE_IMT_REG, AE_IMT_DEFAULT); 876f85e0762SSepherosa Ziehau val = AE_READ_4(sc, AE_MASTER_REG); 877f85e0762SSepherosa Ziehau val |= AE_MASTER_IMT_EN; 878f85e0762SSepherosa Ziehau AE_WRITE_4(sc, AE_MASTER_REG, val); 879f85e0762SSepherosa Ziehau 880f85e0762SSepherosa Ziehau /* 881f85e0762SSepherosa Ziehau * Configure interrupt clearing timer. 882f85e0762SSepherosa Ziehau */ 883f85e0762SSepherosa Ziehau AE_WRITE_2(sc, AE_ICT_REG, AE_ICT_DEFAULT); 884f85e0762SSepherosa Ziehau 885f85e0762SSepherosa Ziehau /* 886f85e0762SSepherosa Ziehau * Configure MTU. 887f85e0762SSepherosa Ziehau */ 888f85e0762SSepherosa Ziehau val = ifp->if_mtu + ETHER_HDR_LEN + sizeof(struct ether_vlan_header) + 889f85e0762SSepherosa Ziehau ETHER_CRC_LEN; 890f85e0762SSepherosa Ziehau AE_WRITE_2(sc, AE_MTU_REG, val); 891f85e0762SSepherosa Ziehau 892f85e0762SSepherosa Ziehau /* 893f85e0762SSepherosa Ziehau * Configure cut-through threshold. 894f85e0762SSepherosa Ziehau */ 895f85e0762SSepherosa Ziehau AE_WRITE_4(sc, AE_CUT_THRESH_REG, AE_CUT_THRESH_DEFAULT); 896f85e0762SSepherosa Ziehau 897f85e0762SSepherosa Ziehau /* 898f85e0762SSepherosa Ziehau * Configure flow control. 899f85e0762SSepherosa Ziehau */ 900f85e0762SSepherosa Ziehau AE_WRITE_2(sc, AE_FLOW_THRESH_HI_REG, (AE_RXD_COUNT_DEFAULT / 8) * 7); 901f85e0762SSepherosa Ziehau AE_WRITE_2(sc, AE_FLOW_THRESH_LO_REG, (AE_RXD_COUNT_MIN / 8) > 902f85e0762SSepherosa Ziehau (AE_RXD_COUNT_DEFAULT / 12) ? (AE_RXD_COUNT_MIN / 8) : 903f85e0762SSepherosa Ziehau (AE_RXD_COUNT_DEFAULT / 12)); 904f85e0762SSepherosa Ziehau 905f85e0762SSepherosa Ziehau /* 906f85e0762SSepherosa Ziehau * Init mailboxes. 907f85e0762SSepherosa Ziehau */ 908f85e0762SSepherosa Ziehau sc->txd_cur = sc->rxd_cur = 0; 909f85e0762SSepherosa Ziehau sc->txs_ack = sc->txd_ack = 0; 910f85e0762SSepherosa Ziehau sc->rxd_cur = 0; 911f85e0762SSepherosa Ziehau AE_WRITE_2(sc, AE_MB_TXD_IDX_REG, sc->txd_cur); 912f85e0762SSepherosa Ziehau AE_WRITE_2(sc, AE_MB_RXD_IDX_REG, sc->rxd_cur); 913f85e0762SSepherosa Ziehau sc->tx_inproc = 0; 914f85e0762SSepherosa Ziehau sc->ae_flags |= AE_FLAG_TXAVAIL; /* Free Tx's available. */ 915f85e0762SSepherosa Ziehau 916f85e0762SSepherosa Ziehau /* 917f85e0762SSepherosa Ziehau * Enable DMA. 918f85e0762SSepherosa Ziehau */ 919f85e0762SSepherosa Ziehau AE_WRITE_1(sc, AE_DMAREAD_REG, AE_DMAREAD_EN); 920f85e0762SSepherosa Ziehau AE_WRITE_1(sc, AE_DMAWRITE_REG, AE_DMAWRITE_EN); 921f85e0762SSepherosa Ziehau 922f85e0762SSepherosa Ziehau /* 923f85e0762SSepherosa Ziehau * Check if everything is OK. 924f85e0762SSepherosa Ziehau */ 925f85e0762SSepherosa Ziehau val = AE_READ_4(sc, AE_ISR_REG); 926f85e0762SSepherosa Ziehau if ((val & AE_ISR_PHY_LINKDOWN) != 0) { 927f85e0762SSepherosa Ziehau device_printf(sc->ae_dev, "Initialization failed.\n"); 928f85e0762SSepherosa Ziehau return; 929f85e0762SSepherosa Ziehau } 930f85e0762SSepherosa Ziehau 931f85e0762SSepherosa Ziehau /* 932f85e0762SSepherosa Ziehau * Clear interrupt status. 933f85e0762SSepherosa Ziehau */ 934f85e0762SSepherosa Ziehau AE_WRITE_4(sc, AE_ISR_REG, 0x3fffffff); 935f85e0762SSepherosa Ziehau AE_WRITE_4(sc, AE_ISR_REG, 0x0); 936f85e0762SSepherosa Ziehau 937f85e0762SSepherosa Ziehau /* 938f85e0762SSepherosa Ziehau * Enable interrupts. 939f85e0762SSepherosa Ziehau */ 940f85e0762SSepherosa Ziehau val = AE_READ_4(sc, AE_MASTER_REG); 941f85e0762SSepherosa Ziehau AE_WRITE_4(sc, AE_MASTER_REG, val | AE_MASTER_MANUAL_INT); 942f85e0762SSepherosa Ziehau AE_WRITE_4(sc, AE_IMR_REG, AE_IMR_DEFAULT); 943f85e0762SSepherosa Ziehau 944f85e0762SSepherosa Ziehau /* 945f85e0762SSepherosa Ziehau * Disable WOL. 946f85e0762SSepherosa Ziehau */ 947f85e0762SSepherosa Ziehau AE_WRITE_4(sc, AE_WOL_REG, 0); 948f85e0762SSepherosa Ziehau 949f85e0762SSepherosa Ziehau /* 950f85e0762SSepherosa Ziehau * Configure MAC. 951f85e0762SSepherosa Ziehau */ 952f85e0762SSepherosa Ziehau val = AE_MAC_TX_CRC_EN | AE_MAC_TX_AUTOPAD | 953f85e0762SSepherosa Ziehau AE_MAC_FULL_DUPLEX | AE_MAC_CLK_PHY | 954f85e0762SSepherosa Ziehau AE_MAC_TX_FLOW_EN | AE_MAC_RX_FLOW_EN | 955f85e0762SSepherosa Ziehau ((AE_HALFBUF_DEFAULT << AE_HALFBUF_SHIFT) & AE_HALFBUF_MASK) | 956f85e0762SSepherosa Ziehau ((AE_MAC_PREAMBLE_DEFAULT << AE_MAC_PREAMBLE_SHIFT) & 957f85e0762SSepherosa Ziehau AE_MAC_PREAMBLE_MASK); 958f85e0762SSepherosa Ziehau AE_WRITE_4(sc, AE_MAC_REG, val); 959f85e0762SSepherosa Ziehau 960f85e0762SSepherosa Ziehau /* 961f85e0762SSepherosa Ziehau * Configure Rx MAC. 962f85e0762SSepherosa Ziehau */ 963f85e0762SSepherosa Ziehau ae_rxfilter(sc); 964f85e0762SSepherosa Ziehau ae_rxvlan(sc); 965f85e0762SSepherosa Ziehau 966f85e0762SSepherosa Ziehau /* 967f85e0762SSepherosa Ziehau * Enable Tx/Rx. 968f85e0762SSepherosa Ziehau */ 969f85e0762SSepherosa Ziehau val = AE_READ_4(sc, AE_MAC_REG); 970f85e0762SSepherosa Ziehau AE_WRITE_4(sc, AE_MAC_REG, val | AE_MAC_TX_EN | AE_MAC_RX_EN); 971f85e0762SSepherosa Ziehau 972f85e0762SSepherosa Ziehau sc->ae_flags &= ~AE_FLAG_LINK; 973f85e0762SSepherosa Ziehau mii_mediachg(mii); /* Switch to the current media. */ 974f85e0762SSepherosa Ziehau 975f85e0762SSepherosa Ziehau callout_reset(&sc->ae_tick_ch, hz, ae_tick, sc); 976f85e0762SSepherosa Ziehau ifp->if_flags |= IFF_RUNNING; 9779ed293e0SSepherosa Ziehau ifq_clr_oactive(&ifp->if_snd); 978f85e0762SSepherosa Ziehau } 979f85e0762SSepherosa Ziehau 980f85e0762SSepherosa Ziehau static void 981f85e0762SSepherosa Ziehau ae_watchdog(struct ifnet *ifp) 982f85e0762SSepherosa Ziehau { 983f85e0762SSepherosa Ziehau struct ae_softc *sc = ifp->if_softc; 984f85e0762SSepherosa Ziehau 985f85e0762SSepherosa Ziehau ASSERT_SERIALIZED(ifp->if_serializer); 986f85e0762SSepherosa Ziehau 987f85e0762SSepherosa Ziehau if ((sc->ae_flags & AE_FLAG_LINK) == 0) 988f85e0762SSepherosa Ziehau if_printf(ifp, "watchdog timeout (missed link).\n"); 989f85e0762SSepherosa Ziehau else 990f85e0762SSepherosa Ziehau if_printf(ifp, "watchdog timeout - resetting.\n"); 991d40991efSSepherosa Ziehau IFNET_STAT_INC(ifp, oerrors, 1); 992f85e0762SSepherosa Ziehau 993f85e0762SSepherosa Ziehau ae_init(sc); 994f85e0762SSepherosa Ziehau if (!ifq_is_empty(&ifp->if_snd)) 995f85e0762SSepherosa Ziehau if_devstart(ifp); 996f85e0762SSepherosa Ziehau } 997f85e0762SSepherosa Ziehau 998f85e0762SSepherosa Ziehau static void 999f85e0762SSepherosa Ziehau ae_tick(void *xsc) 1000f85e0762SSepherosa Ziehau { 1001f85e0762SSepherosa Ziehau struct ae_softc *sc = xsc; 1002f85e0762SSepherosa Ziehau struct ifnet *ifp = &sc->arpcom.ac_if; 1003f85e0762SSepherosa Ziehau struct mii_data *mii = device_get_softc(sc->ae_miibus); 1004f85e0762SSepherosa Ziehau 1005f85e0762SSepherosa Ziehau lwkt_serialize_enter(ifp->if_serializer); 1006f85e0762SSepherosa Ziehau mii_tick(mii); 1007f85e0762SSepherosa Ziehau callout_reset(&sc->ae_tick_ch, hz, ae_tick, sc); 1008f85e0762SSepherosa Ziehau lwkt_serialize_exit(ifp->if_serializer); 1009f85e0762SSepherosa Ziehau } 1010f85e0762SSepherosa Ziehau 1011f85e0762SSepherosa Ziehau static void 1012f85e0762SSepherosa Ziehau ae_rxvlan(struct ae_softc *sc) 1013f85e0762SSepherosa Ziehau { 1014f85e0762SSepherosa Ziehau struct ifnet *ifp = &sc->arpcom.ac_if; 1015f85e0762SSepherosa Ziehau uint32_t val; 1016f85e0762SSepherosa Ziehau 1017f85e0762SSepherosa Ziehau val = AE_READ_4(sc, AE_MAC_REG); 1018f85e0762SSepherosa Ziehau val &= ~AE_MAC_RMVLAN_EN; 1019f85e0762SSepherosa Ziehau if (ifp->if_capenable & IFCAP_VLAN_HWTAGGING) 1020f85e0762SSepherosa Ziehau val |= AE_MAC_RMVLAN_EN; 1021f85e0762SSepherosa Ziehau AE_WRITE_4(sc, AE_MAC_REG, val); 1022f85e0762SSepherosa Ziehau } 1023f85e0762SSepherosa Ziehau 1024f85e0762SSepherosa Ziehau static void 1025f85e0762SSepherosa Ziehau ae_rxfilter(struct ae_softc *sc) 1026f85e0762SSepherosa Ziehau { 1027f85e0762SSepherosa Ziehau struct ifnet *ifp = &sc->arpcom.ac_if; 1028f85e0762SSepherosa Ziehau struct ifmultiaddr *ifma; 1029f85e0762SSepherosa Ziehau uint32_t crc; 1030f85e0762SSepherosa Ziehau uint32_t mchash[2]; 1031f85e0762SSepherosa Ziehau uint32_t rxcfg; 1032f85e0762SSepherosa Ziehau 1033f85e0762SSepherosa Ziehau rxcfg = AE_READ_4(sc, AE_MAC_REG); 1034f85e0762SSepherosa Ziehau rxcfg &= ~(AE_MAC_MCAST_EN | AE_MAC_BCAST_EN | AE_MAC_PROMISC_EN); 1035f85e0762SSepherosa Ziehau rxcfg |= AE_MAC_BCAST_EN; 1036f85e0762SSepherosa Ziehau if (ifp->if_flags & IFF_PROMISC) 1037f85e0762SSepherosa Ziehau rxcfg |= AE_MAC_PROMISC_EN; 1038f85e0762SSepherosa Ziehau if (ifp->if_flags & IFF_ALLMULTI) 1039f85e0762SSepherosa Ziehau rxcfg |= AE_MAC_MCAST_EN; 1040f85e0762SSepherosa Ziehau 1041f85e0762SSepherosa Ziehau /* 1042f85e0762SSepherosa Ziehau * Wipe old settings. 1043f85e0762SSepherosa Ziehau */ 1044f85e0762SSepherosa Ziehau AE_WRITE_4(sc, AE_REG_MHT0, 0); 1045f85e0762SSepherosa Ziehau AE_WRITE_4(sc, AE_REG_MHT1, 0); 1046f85e0762SSepherosa Ziehau if (ifp->if_flags & (IFF_PROMISC | IFF_ALLMULTI)) { 1047f85e0762SSepherosa Ziehau AE_WRITE_4(sc, AE_REG_MHT0, 0xffffffff); 1048f85e0762SSepherosa Ziehau AE_WRITE_4(sc, AE_REG_MHT1, 0xffffffff); 1049f85e0762SSepherosa Ziehau AE_WRITE_4(sc, AE_MAC_REG, rxcfg); 1050f85e0762SSepherosa Ziehau return; 1051f85e0762SSepherosa Ziehau } 1052f85e0762SSepherosa Ziehau 1053f85e0762SSepherosa Ziehau /* 1054f85e0762SSepherosa Ziehau * Load multicast tables. 1055f85e0762SSepherosa Ziehau */ 1056f85e0762SSepherosa Ziehau bzero(mchash, sizeof(mchash)); 1057441d34b2SSascha Wildner TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { 1058f85e0762SSepherosa Ziehau if (ifma->ifma_addr->sa_family != AF_LINK) 1059f85e0762SSepherosa Ziehau continue; 1060f85e0762SSepherosa Ziehau crc = ether_crc32_le(LLADDR((struct sockaddr_dl *) 1061f85e0762SSepherosa Ziehau ifma->ifma_addr), ETHER_ADDR_LEN); 1062f85e0762SSepherosa Ziehau mchash[crc >> 31] |= 1 << ((crc >> 26) & 0x1f); 1063f85e0762SSepherosa Ziehau } 1064f85e0762SSepherosa Ziehau AE_WRITE_4(sc, AE_REG_MHT0, mchash[0]); 1065f85e0762SSepherosa Ziehau AE_WRITE_4(sc, AE_REG_MHT1, mchash[1]); 1066f85e0762SSepherosa Ziehau AE_WRITE_4(sc, AE_MAC_REG, rxcfg); 1067f85e0762SSepherosa Ziehau } 1068f85e0762SSepherosa Ziehau 1069f85e0762SSepherosa Ziehau static unsigned int 1070f85e0762SSepherosa Ziehau ae_tx_avail_size(struct ae_softc *sc) 1071f85e0762SSepherosa Ziehau { 1072f85e0762SSepherosa Ziehau unsigned int avail; 1073f85e0762SSepherosa Ziehau 1074f85e0762SSepherosa Ziehau if (sc->txd_cur >= sc->txd_ack) 1075f85e0762SSepherosa Ziehau avail = AE_TXD_BUFSIZE_DEFAULT - (sc->txd_cur - sc->txd_ack); 1076f85e0762SSepherosa Ziehau else 1077f85e0762SSepherosa Ziehau avail = sc->txd_ack - sc->txd_cur; 1078f85e0762SSepherosa Ziehau return (avail - 4); /* 4-byte header. */ 1079f85e0762SSepherosa Ziehau } 1080f85e0762SSepherosa Ziehau 1081f85e0762SSepherosa Ziehau static int 1082f85e0762SSepherosa Ziehau ae_encap(struct ae_softc *sc, struct mbuf **m_head) 1083f85e0762SSepherosa Ziehau { 1084f85e0762SSepherosa Ziehau struct mbuf *m0; 1085f85e0762SSepherosa Ziehau struct ae_txd *hdr; 1086f85e0762SSepherosa Ziehau unsigned int to_end; 1087f85e0762SSepherosa Ziehau uint16_t len; 1088f85e0762SSepherosa Ziehau 1089f85e0762SSepherosa Ziehau M_ASSERTPKTHDR((*m_head)); 1090f85e0762SSepherosa Ziehau m0 = *m_head; 1091f85e0762SSepherosa Ziehau len = m0->m_pkthdr.len; 1092f85e0762SSepherosa Ziehau if ((sc->ae_flags & AE_FLAG_TXAVAIL) == 0 || 1093f85e0762SSepherosa Ziehau ae_tx_avail_size(sc) < len) { 1094f85e0762SSepherosa Ziehau #ifdef AE_DEBUG 1095f85e0762SSepherosa Ziehau if_printf(sc->ifp, "No free Tx available.\n"); 1096f85e0762SSepherosa Ziehau #endif 1097f85e0762SSepherosa Ziehau return ENOBUFS; 1098f85e0762SSepherosa Ziehau } 1099f85e0762SSepherosa Ziehau 1100f85e0762SSepherosa Ziehau hdr = (struct ae_txd *)(sc->txd_base + sc->txd_cur); 1101f85e0762SSepherosa Ziehau bzero(hdr, sizeof(*hdr)); 1102f85e0762SSepherosa Ziehau 1103f85e0762SSepherosa Ziehau /* Header size. */ 1104f85e0762SSepherosa Ziehau sc->txd_cur = (sc->txd_cur + 4) % AE_TXD_BUFSIZE_DEFAULT; 1105f85e0762SSepherosa Ziehau 1106f85e0762SSepherosa Ziehau /* Space available to the end of the ring */ 1107f85e0762SSepherosa Ziehau to_end = AE_TXD_BUFSIZE_DEFAULT - sc->txd_cur; 1108f85e0762SSepherosa Ziehau 1109f85e0762SSepherosa Ziehau if (to_end >= len) { 1110f85e0762SSepherosa Ziehau m_copydata(m0, 0, len, (caddr_t)(sc->txd_base + sc->txd_cur)); 1111f85e0762SSepherosa Ziehau } else { 1112f85e0762SSepherosa Ziehau m_copydata(m0, 0, to_end, (caddr_t)(sc->txd_base + 1113f85e0762SSepherosa Ziehau sc->txd_cur)); 1114f85e0762SSepherosa Ziehau m_copydata(m0, to_end, len - to_end, (caddr_t)sc->txd_base); 1115f85e0762SSepherosa Ziehau } 1116f85e0762SSepherosa Ziehau 1117f85e0762SSepherosa Ziehau /* 1118f85e0762SSepherosa Ziehau * Set TxD flags and parameters. 1119f85e0762SSepherosa Ziehau */ 1120f85e0762SSepherosa Ziehau if ((m0->m_flags & M_VLANTAG) != 0) { 1121f85e0762SSepherosa Ziehau hdr->vlan = htole16(AE_TXD_VLAN(m0->m_pkthdr.ether_vlantag)); 1122f85e0762SSepherosa Ziehau hdr->len = htole16(len | AE_TXD_INSERT_VTAG); 1123f85e0762SSepherosa Ziehau } else { 1124f85e0762SSepherosa Ziehau hdr->len = htole16(len); 1125f85e0762SSepherosa Ziehau } 1126f85e0762SSepherosa Ziehau 1127f85e0762SSepherosa Ziehau /* 1128f85e0762SSepherosa Ziehau * Set current TxD position and round up to a 4-byte boundary. 1129f85e0762SSepherosa Ziehau */ 1130f85e0762SSepherosa Ziehau sc->txd_cur = ((sc->txd_cur + len + 3) & ~3) % AE_TXD_BUFSIZE_DEFAULT; 1131f85e0762SSepherosa Ziehau if (sc->txd_cur == sc->txd_ack) 1132f85e0762SSepherosa Ziehau sc->ae_flags &= ~AE_FLAG_TXAVAIL; 1133f85e0762SSepherosa Ziehau #ifdef AE_DEBUG 1134f85e0762SSepherosa Ziehau if_printf(sc->ifp, "New txd_cur = %d.\n", sc->txd_cur); 1135f85e0762SSepherosa Ziehau #endif 1136f85e0762SSepherosa Ziehau 1137f85e0762SSepherosa Ziehau /* 1138f85e0762SSepherosa Ziehau * Update TxS position and check if there are empty TxS available. 1139f85e0762SSepherosa Ziehau */ 1140f85e0762SSepherosa Ziehau sc->txs_base[sc->txs_cur].flags &= ~htole16(AE_TXS_UPDATE); 1141f85e0762SSepherosa Ziehau sc->txs_cur = (sc->txs_cur + 1) % AE_TXS_COUNT_DEFAULT; 1142f85e0762SSepherosa Ziehau if (sc->txs_cur == sc->txs_ack) 1143f85e0762SSepherosa Ziehau sc->ae_flags &= ~AE_FLAG_TXAVAIL; 1144f85e0762SSepherosa Ziehau 1145f85e0762SSepherosa Ziehau /* 1146f85e0762SSepherosa Ziehau * Synchronize DMA memory. 1147f85e0762SSepherosa Ziehau */ 1148f85e0762SSepherosa Ziehau bus_dmamap_sync(sc->dma_txd_tag, sc->dma_txd_map, BUS_DMASYNC_PREWRITE); 1149f85e0762SSepherosa Ziehau bus_dmamap_sync(sc->dma_txs_tag, sc->dma_txs_map, BUS_DMASYNC_PREWRITE); 1150f85e0762SSepherosa Ziehau 1151f85e0762SSepherosa Ziehau return (0); 1152f85e0762SSepherosa Ziehau } 1153f85e0762SSepherosa Ziehau 1154f85e0762SSepherosa Ziehau static void 1155f0a26983SSepherosa Ziehau ae_start(struct ifnet *ifp, struct ifaltq_subque *ifsq) 1156f85e0762SSepherosa Ziehau { 1157f85e0762SSepherosa Ziehau struct ae_softc *sc = ifp->if_softc; 1158f85e0762SSepherosa Ziehau int error, trans; 1159f85e0762SSepherosa Ziehau 1160f0a26983SSepherosa Ziehau ASSERT_ALTQ_SQ_DEFAULT(ifp, ifsq); 1161f85e0762SSepherosa Ziehau ASSERT_SERIALIZED(ifp->if_serializer); 1162f85e0762SSepherosa Ziehau 1163f85e0762SSepherosa Ziehau #ifdef AE_DEBUG 1164f85e0762SSepherosa Ziehau if_printf(ifp, "Start called.\n"); 1165f85e0762SSepherosa Ziehau #endif 1166f85e0762SSepherosa Ziehau if ((sc->ae_flags & AE_FLAG_LINK) == 0) { 1167f85e0762SSepherosa Ziehau ifq_purge(&ifp->if_snd); 1168f85e0762SSepherosa Ziehau return; 1169f85e0762SSepherosa Ziehau } 11709ed293e0SSepherosa Ziehau if ((ifp->if_flags & IFF_RUNNING) == 0 || ifq_is_oactive(&ifp->if_snd)) 1171f85e0762SSepherosa Ziehau return; 1172f85e0762SSepherosa Ziehau 1173f85e0762SSepherosa Ziehau trans = 0; 1174f85e0762SSepherosa Ziehau while (!ifq_is_empty(&ifp->if_snd)) { 1175f85e0762SSepherosa Ziehau struct mbuf *m0; 1176f85e0762SSepherosa Ziehau 1177f85e0762SSepherosa Ziehau m0 = ifq_dequeue(&ifp->if_snd, NULL); 1178f85e0762SSepherosa Ziehau if (m0 == NULL) 1179f85e0762SSepherosa Ziehau break; /* Nothing to do. */ 1180f85e0762SSepherosa Ziehau 1181f85e0762SSepherosa Ziehau error = ae_encap(sc, &m0); 1182f85e0762SSepherosa Ziehau if (error != 0) { 1183f85e0762SSepherosa Ziehau if (m0 != NULL) { 1184f85e0762SSepherosa Ziehau ifq_prepend(&ifp->if_snd, m0); 11859ed293e0SSepherosa Ziehau ifq_set_oactive(&ifp->if_snd); 1186f85e0762SSepherosa Ziehau #ifdef AE_DEBUG 1187f85e0762SSepherosa Ziehau if_printf(ifp, "Setting OACTIVE.\n"); 1188f85e0762SSepherosa Ziehau #endif 1189f85e0762SSepherosa Ziehau } 1190f85e0762SSepherosa Ziehau break; 1191f85e0762SSepherosa Ziehau } 1192f85e0762SSepherosa Ziehau trans = 1; 1193f85e0762SSepherosa Ziehau sc->tx_inproc++; 1194f85e0762SSepherosa Ziehau 1195f85e0762SSepherosa Ziehau /* Bounce a copy of the frame to BPF. */ 1196f85e0762SSepherosa Ziehau ETHER_BPF_MTAP(ifp, m0); 1197f85e0762SSepherosa Ziehau m_freem(m0); 1198f85e0762SSepherosa Ziehau } 1199f85e0762SSepherosa Ziehau if (trans) { /* Something was dequeued. */ 1200f85e0762SSepherosa Ziehau AE_WRITE_2(sc, AE_MB_TXD_IDX_REG, sc->txd_cur / 4); 1201f85e0762SSepherosa Ziehau ifp->if_timer = AE_TX_TIMEOUT; /* Load watchdog. */ 1202f85e0762SSepherosa Ziehau #ifdef AE_DEBUG 1203f85e0762SSepherosa Ziehau if_printf(ifp, "%d packets dequeued.\n", count); 1204f85e0762SSepherosa Ziehau if_printf(ifp, "Tx pos now is %d.\n", sc->txd_cur); 1205f85e0762SSepherosa Ziehau #endif 1206f85e0762SSepherosa Ziehau } 1207f85e0762SSepherosa Ziehau } 1208f85e0762SSepherosa Ziehau 1209f85e0762SSepherosa Ziehau static int 1210f85e0762SSepherosa Ziehau ae_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data, struct ucred *cr) 1211f85e0762SSepherosa Ziehau { 1212f85e0762SSepherosa Ziehau struct ae_softc *sc = ifp->if_softc; 1213f85e0762SSepherosa Ziehau struct ifreq *ifr; 1214f85e0762SSepherosa Ziehau struct mii_data *mii; 1215f85e0762SSepherosa Ziehau int error = 0, mask; 1216f85e0762SSepherosa Ziehau 1217f85e0762SSepherosa Ziehau ASSERT_SERIALIZED(ifp->if_serializer); 1218f85e0762SSepherosa Ziehau 1219f85e0762SSepherosa Ziehau ifr = (struct ifreq *)data; 1220f85e0762SSepherosa Ziehau switch (cmd) { 1221f85e0762SSepherosa Ziehau case SIOCSIFFLAGS: 1222f85e0762SSepherosa Ziehau if (ifp->if_flags & IFF_UP) { 1223f85e0762SSepherosa Ziehau if (ifp->if_flags & IFF_RUNNING) { 1224f85e0762SSepherosa Ziehau if (((ifp->if_flags ^ sc->ae_if_flags) 1225f85e0762SSepherosa Ziehau & (IFF_PROMISC | IFF_ALLMULTI)) != 0) 1226f85e0762SSepherosa Ziehau ae_rxfilter(sc); 1227f85e0762SSepherosa Ziehau } else { 1228f85e0762SSepherosa Ziehau ae_init(sc); 1229f85e0762SSepherosa Ziehau } 1230f85e0762SSepherosa Ziehau } else { 1231f85e0762SSepherosa Ziehau if (ifp->if_flags & IFF_RUNNING) 1232f85e0762SSepherosa Ziehau ae_stop(sc); 1233f85e0762SSepherosa Ziehau } 1234f85e0762SSepherosa Ziehau sc->ae_if_flags = ifp->if_flags; 1235f85e0762SSepherosa Ziehau break; 1236f85e0762SSepherosa Ziehau 1237f85e0762SSepherosa Ziehau case SIOCADDMULTI: 1238f85e0762SSepherosa Ziehau case SIOCDELMULTI: 1239f85e0762SSepherosa Ziehau if (ifp->if_flags & IFF_RUNNING) 1240f85e0762SSepherosa Ziehau ae_rxfilter(sc); 1241f85e0762SSepherosa Ziehau break; 1242f85e0762SSepherosa Ziehau 1243f85e0762SSepherosa Ziehau case SIOCSIFMEDIA: 1244f85e0762SSepherosa Ziehau case SIOCGIFMEDIA: 1245f85e0762SSepherosa Ziehau mii = device_get_softc(sc->ae_miibus); 1246f85e0762SSepherosa Ziehau error = ifmedia_ioctl(ifp, ifr, &mii->mii_media, cmd); 1247f85e0762SSepherosa Ziehau break; 1248f85e0762SSepherosa Ziehau 1249f85e0762SSepherosa Ziehau case SIOCSIFCAP: 1250f85e0762SSepherosa Ziehau mask = ifr->ifr_reqcap ^ ifp->if_capenable; 1251f85e0762SSepherosa Ziehau if (mask & IFCAP_VLAN_HWTAGGING) { 1252f85e0762SSepherosa Ziehau ifp->if_capenable ^= IFCAP_VLAN_HWTAGGING; 1253f85e0762SSepherosa Ziehau ae_rxvlan(sc); 1254f85e0762SSepherosa Ziehau } 1255f85e0762SSepherosa Ziehau break; 1256f85e0762SSepherosa Ziehau 1257f85e0762SSepherosa Ziehau default: 1258f85e0762SSepherosa Ziehau error = ether_ioctl(ifp, cmd, data); 1259f85e0762SSepherosa Ziehau break; 1260f85e0762SSepherosa Ziehau } 1261f85e0762SSepherosa Ziehau return (error); 1262f85e0762SSepherosa Ziehau } 1263f85e0762SSepherosa Ziehau 1264f85e0762SSepherosa Ziehau static int 1265f85e0762SSepherosa Ziehau ae_attach(device_t dev) 1266f85e0762SSepherosa Ziehau { 1267f85e0762SSepherosa Ziehau struct ae_softc *sc = device_get_softc(dev); 1268f85e0762SSepherosa Ziehau struct ifnet *ifp = &sc->arpcom.ac_if; 1269f85e0762SSepherosa Ziehau int error = 0; 1270f85e0762SSepherosa Ziehau 1271f85e0762SSepherosa Ziehau sc->ae_dev = dev; 1272f85e0762SSepherosa Ziehau if_initname(ifp, device_get_name(dev), device_get_unit(dev)); 1273f85e0762SSepherosa Ziehau callout_init(&sc->ae_tick_ch); 1274f85e0762SSepherosa Ziehau 1275f85e0762SSepherosa Ziehau /* Enable bus mastering */ 1276f85e0762SSepherosa Ziehau pci_enable_busmaster(dev); 1277f85e0762SSepherosa Ziehau 1278f85e0762SSepherosa Ziehau /* 1279f85e0762SSepherosa Ziehau * Allocate memory mapped IO 1280f85e0762SSepherosa Ziehau */ 1281f85e0762SSepherosa Ziehau sc->ae_mem_rid = PCIR_BAR(0); 1282f85e0762SSepherosa Ziehau sc->ae_mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, 1283f85e0762SSepherosa Ziehau &sc->ae_mem_rid, RF_ACTIVE); 1284f85e0762SSepherosa Ziehau if (sc->ae_mem_res == NULL) { 1285f85e0762SSepherosa Ziehau device_printf(dev, "can't allocate IO memory\n"); 1286f85e0762SSepherosa Ziehau return ENXIO; 1287f85e0762SSepherosa Ziehau } 1288f85e0762SSepherosa Ziehau sc->ae_mem_bt = rman_get_bustag(sc->ae_mem_res); 1289f85e0762SSepherosa Ziehau sc->ae_mem_bh = rman_get_bushandle(sc->ae_mem_res); 1290f85e0762SSepherosa Ziehau 1291f85e0762SSepherosa Ziehau /* 1292f85e0762SSepherosa Ziehau * Allocate IRQ 1293f85e0762SSepherosa Ziehau */ 1294f85e0762SSepherosa Ziehau sc->ae_irq_rid = 0; 1295f85e0762SSepherosa Ziehau sc->ae_irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, 1296f85e0762SSepherosa Ziehau &sc->ae_irq_rid, 1297f85e0762SSepherosa Ziehau RF_SHAREABLE | RF_ACTIVE); 1298f85e0762SSepherosa Ziehau if (sc->ae_irq_res == NULL) { 1299f85e0762SSepherosa Ziehau device_printf(dev, "can't allocate irq\n"); 1300f85e0762SSepherosa Ziehau error = ENXIO; 1301f85e0762SSepherosa Ziehau goto fail; 1302f85e0762SSepherosa Ziehau } 1303f85e0762SSepherosa Ziehau 1304f85e0762SSepherosa Ziehau /* Set PHY address. */ 1305f85e0762SSepherosa Ziehau sc->ae_phyaddr = AE_PHYADDR_DEFAULT; 1306f85e0762SSepherosa Ziehau 1307f85e0762SSepherosa Ziehau /* Create sysctl tree */ 1308f85e0762SSepherosa Ziehau ae_sysctl_node(sc); 1309f85e0762SSepherosa Ziehau 1310f85e0762SSepherosa Ziehau /* Reset PHY. */ 1311f85e0762SSepherosa Ziehau ae_phy_reset(sc); 1312f85e0762SSepherosa Ziehau 1313f85e0762SSepherosa Ziehau /* 1314f85e0762SSepherosa Ziehau * Reset the ethernet controller. 1315f85e0762SSepherosa Ziehau */ 1316f85e0762SSepherosa Ziehau ae_reset(sc); 1317f85e0762SSepherosa Ziehau ae_pcie_init(sc); 1318f85e0762SSepherosa Ziehau 1319f85e0762SSepherosa Ziehau /* 1320f85e0762SSepherosa Ziehau * Get PCI and chip id/revision. 1321f85e0762SSepherosa Ziehau */ 1322f85e0762SSepherosa Ziehau sc->ae_rev = pci_get_revid(dev); 1323f85e0762SSepherosa Ziehau sc->ae_chip_rev = 1324f85e0762SSepherosa Ziehau (AE_READ_4(sc, AE_MASTER_REG) >> AE_MASTER_REVNUM_SHIFT) & 1325f85e0762SSepherosa Ziehau AE_MASTER_REVNUM_MASK; 1326f85e0762SSepherosa Ziehau if (bootverbose) { 1327f85e0762SSepherosa Ziehau device_printf(dev, "PCI device revision : 0x%04x\n", sc->ae_rev); 1328f85e0762SSepherosa Ziehau device_printf(dev, "Chip id/revision : 0x%04x\n", 1329f85e0762SSepherosa Ziehau sc->ae_chip_rev); 1330f85e0762SSepherosa Ziehau } 1331f85e0762SSepherosa Ziehau 1332f85e0762SSepherosa Ziehau /* 1333f85e0762SSepherosa Ziehau * XXX 1334f85e0762SSepherosa Ziehau * Unintialized hardware returns an invalid chip id/revision 1335f85e0762SSepherosa Ziehau * as well as 0xFFFFFFFF for Tx/Rx fifo length. It seems that 1336f85e0762SSepherosa Ziehau * unplugged cable results in putting hardware into automatic 1337f85e0762SSepherosa Ziehau * power down mode which in turn returns invalld chip revision. 1338f85e0762SSepherosa Ziehau */ 1339f85e0762SSepherosa Ziehau if (sc->ae_chip_rev == 0xFFFF) { 1340f85e0762SSepherosa Ziehau device_printf(dev,"invalid chip revision : 0x%04x -- " 1341f85e0762SSepherosa Ziehau "not initialized?\n", sc->ae_chip_rev); 1342f85e0762SSepherosa Ziehau error = ENXIO; 1343f85e0762SSepherosa Ziehau goto fail; 1344f85e0762SSepherosa Ziehau } 1345f85e0762SSepherosa Ziehau #if 0 1346f85e0762SSepherosa Ziehau /* Get DMA parameters from PCIe device control register. */ 1347f85e0762SSepherosa Ziehau pcie_ptr = pci_get_pciecap_ptr(dev); 1348f85e0762SSepherosa Ziehau if (pcie_ptr) { 1349f85e0762SSepherosa Ziehau uint16_t devctl; 1350f85e0762SSepherosa Ziehau sc->ae_flags |= AE_FLAG_PCIE; 1351f85e0762SSepherosa Ziehau devctl = pci_read_config(dev, pcie_ptr + PCIER_DEVCTRL, 2); 1352f85e0762SSepherosa Ziehau /* Max read request size. */ 1353f85e0762SSepherosa Ziehau sc->ae_dma_rd_burst = ((devctl >> 12) & 0x07) << 1354f85e0762SSepherosa Ziehau DMA_CFG_RD_BURST_SHIFT; 1355f85e0762SSepherosa Ziehau /* Max payload size. */ 1356f85e0762SSepherosa Ziehau sc->ae_dma_wr_burst = ((devctl >> 5) & 0x07) << 1357f85e0762SSepherosa Ziehau DMA_CFG_WR_BURST_SHIFT; 1358f85e0762SSepherosa Ziehau if (bootverbose) { 1359f85e0762SSepherosa Ziehau device_printf(dev, "Read request size : %d bytes.\n", 1360f85e0762SSepherosa Ziehau 128 << ((devctl >> 12) & 0x07)); 1361f85e0762SSepherosa Ziehau device_printf(dev, "TLP payload size : %d bytes.\n", 1362f85e0762SSepherosa Ziehau 128 << ((devctl >> 5) & 0x07)); 1363f85e0762SSepherosa Ziehau } 1364f85e0762SSepherosa Ziehau } else { 1365f85e0762SSepherosa Ziehau sc->ae_dma_rd_burst = DMA_CFG_RD_BURST_128; 1366f85e0762SSepherosa Ziehau sc->ae_dma_wr_burst = DMA_CFG_WR_BURST_128; 1367f85e0762SSepherosa Ziehau } 1368f85e0762SSepherosa Ziehau #endif 1369f85e0762SSepherosa Ziehau 1370f85e0762SSepherosa Ziehau /* Create DMA stuffs */ 1371f85e0762SSepherosa Ziehau error = ae_dma_alloc(sc); 1372f85e0762SSepherosa Ziehau if (error) 1373f85e0762SSepherosa Ziehau goto fail; 1374f85e0762SSepherosa Ziehau 1375f85e0762SSepherosa Ziehau /* Load station address. */ 1376f85e0762SSepherosa Ziehau ae_get_eaddr(sc); 1377f85e0762SSepherosa Ziehau 1378f85e0762SSepherosa Ziehau ifp->if_softc = sc; 1379f85e0762SSepherosa Ziehau ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 1380f85e0762SSepherosa Ziehau ifp->if_ioctl = ae_ioctl; 1381f85e0762SSepherosa Ziehau ifp->if_start = ae_start; 1382f85e0762SSepherosa Ziehau ifp->if_init = ae_init; 1383f85e0762SSepherosa Ziehau ifp->if_watchdog = ae_watchdog; 1384f85e0762SSepherosa Ziehau ifq_set_maxlen(&ifp->if_snd, IFQ_MAXLEN - 1); 1385f85e0762SSepherosa Ziehau ifq_set_ready(&ifp->if_snd); 1386f85e0762SSepherosa Ziehau ifp->if_capabilities = IFCAP_VLAN_MTU | 1387f85e0762SSepherosa Ziehau IFCAP_VLAN_HWTAGGING; 1388f85e0762SSepherosa Ziehau ifp->if_hwassist = 0; 1389f85e0762SSepherosa Ziehau ifp->if_capenable = ifp->if_capabilities; 1390f85e0762SSepherosa Ziehau 1391f85e0762SSepherosa Ziehau /* Set up MII bus. */ 1392f85e0762SSepherosa Ziehau error = mii_phy_probe(dev, &sc->ae_miibus, 1393f85e0762SSepherosa Ziehau ae_mediachange, ae_mediastatus); 1394f85e0762SSepherosa Ziehau if (error) { 1395f85e0762SSepherosa Ziehau device_printf(dev, "no PHY found!\n"); 1396f85e0762SSepherosa Ziehau goto fail; 1397f85e0762SSepherosa Ziehau } 1398f85e0762SSepherosa Ziehau ether_ifattach(ifp, sc->ae_eaddr, NULL); 1399f85e0762SSepherosa Ziehau 1400f85e0762SSepherosa Ziehau /* Tell the upper layer(s) we support long frames. */ 1401f85e0762SSepherosa Ziehau ifp->if_data.ifi_hdrlen = sizeof(struct ether_vlan_header); 1402f85e0762SSepherosa Ziehau 1403*4c77af2dSSepherosa Ziehau ifq_set_cpuid(&ifp->if_snd, rman_get_cpuid(sc->ae_irq_res)); 1404*4c77af2dSSepherosa Ziehau 1405f85e0762SSepherosa Ziehau error = bus_setup_intr(dev, sc->ae_irq_res, INTR_MPSAFE, ae_intr, sc, 1406f85e0762SSepherosa Ziehau &sc->ae_irq_handle, ifp->if_serializer); 1407f85e0762SSepherosa Ziehau if (error) { 1408f85e0762SSepherosa Ziehau device_printf(dev, "could not set up interrupt handler.\n"); 1409f85e0762SSepherosa Ziehau ether_ifdetach(ifp); 1410f85e0762SSepherosa Ziehau goto fail; 1411f85e0762SSepherosa Ziehau } 1412f85e0762SSepherosa Ziehau return 0; 1413f85e0762SSepherosa Ziehau fail: 1414f85e0762SSepherosa Ziehau ae_detach(dev); 1415f85e0762SSepherosa Ziehau return (error); 1416f85e0762SSepherosa Ziehau } 1417f85e0762SSepherosa Ziehau 1418f85e0762SSepherosa Ziehau static int 1419f85e0762SSepherosa Ziehau ae_detach(device_t dev) 1420f85e0762SSepherosa Ziehau { 1421f85e0762SSepherosa Ziehau struct ae_softc *sc = device_get_softc(dev); 1422f85e0762SSepherosa Ziehau 1423f85e0762SSepherosa Ziehau if (device_is_attached(dev)) { 1424f85e0762SSepherosa Ziehau struct ifnet *ifp = &sc->arpcom.ac_if; 1425f85e0762SSepherosa Ziehau 1426f85e0762SSepherosa Ziehau lwkt_serialize_enter(ifp->if_serializer); 1427f85e0762SSepherosa Ziehau sc->ae_flags |= AE_FLAG_DETACH; 1428f85e0762SSepherosa Ziehau ae_stop(sc); 1429f85e0762SSepherosa Ziehau bus_teardown_intr(dev, sc->ae_irq_res, sc->ae_irq_handle); 1430f85e0762SSepherosa Ziehau lwkt_serialize_exit(ifp->if_serializer); 1431f85e0762SSepherosa Ziehau 1432f85e0762SSepherosa Ziehau ether_ifdetach(ifp); 1433f85e0762SSepherosa Ziehau } 1434f85e0762SSepherosa Ziehau 1435f85e0762SSepherosa Ziehau if (sc->ae_miibus != NULL) 1436f85e0762SSepherosa Ziehau device_delete_child(dev, sc->ae_miibus); 1437f85e0762SSepherosa Ziehau bus_generic_detach(dev); 1438f85e0762SSepherosa Ziehau 1439f85e0762SSepherosa Ziehau if (sc->ae_irq_res != NULL) { 1440f85e0762SSepherosa Ziehau bus_release_resource(dev, SYS_RES_IRQ, sc->ae_irq_rid, 1441f85e0762SSepherosa Ziehau sc->ae_irq_res); 1442f85e0762SSepherosa Ziehau } 1443f85e0762SSepherosa Ziehau if (sc->ae_mem_res != NULL) { 1444f85e0762SSepherosa Ziehau bus_release_resource(dev, SYS_RES_MEMORY, sc->ae_mem_rid, 1445f85e0762SSepherosa Ziehau sc->ae_mem_res); 1446f85e0762SSepherosa Ziehau } 1447f85e0762SSepherosa Ziehau 1448f85e0762SSepherosa Ziehau if (sc->ae_sysctl_tree != NULL) 1449f85e0762SSepherosa Ziehau sysctl_ctx_free(&sc->ae_sysctl_ctx); 1450f85e0762SSepherosa Ziehau 1451f85e0762SSepherosa Ziehau ae_dma_free(sc); 1452f85e0762SSepherosa Ziehau 1453f85e0762SSepherosa Ziehau return (0); 1454f85e0762SSepherosa Ziehau } 1455f85e0762SSepherosa Ziehau 1456f85e0762SSepherosa Ziehau static void 1457f85e0762SSepherosa Ziehau ae_dma_free(struct ae_softc *sc) 1458f85e0762SSepherosa Ziehau { 1459f85e0762SSepherosa Ziehau if (sc->dma_txd_tag != NULL) { 1460f85e0762SSepherosa Ziehau bus_dmamap_unload(sc->dma_txd_tag, sc->dma_txd_map); 1461f85e0762SSepherosa Ziehau bus_dmamem_free(sc->dma_txd_tag, sc->txd_base, 1462f85e0762SSepherosa Ziehau sc->dma_txd_map); 1463f85e0762SSepherosa Ziehau bus_dma_tag_destroy(sc->dma_txd_tag); 1464f85e0762SSepherosa Ziehau } 1465f85e0762SSepherosa Ziehau if (sc->dma_txs_tag != NULL) { 1466f85e0762SSepherosa Ziehau bus_dmamap_unload(sc->dma_txs_tag, sc->dma_txs_map); 1467f85e0762SSepherosa Ziehau bus_dmamem_free(sc->dma_txs_tag, sc->txs_base, 1468f85e0762SSepherosa Ziehau sc->dma_txs_map); 1469f85e0762SSepherosa Ziehau bus_dma_tag_destroy(sc->dma_txs_tag); 1470f85e0762SSepherosa Ziehau } 1471f85e0762SSepherosa Ziehau if (sc->dma_rxd_tag != NULL) { 1472f85e0762SSepherosa Ziehau bus_dmamap_unload(sc->dma_rxd_tag, sc->dma_rxd_map); 1473f85e0762SSepherosa Ziehau bus_dmamem_free(sc->dma_rxd_tag, 1474f85e0762SSepherosa Ziehau sc->rxd_base_dma, sc->dma_rxd_map); 1475f85e0762SSepherosa Ziehau bus_dma_tag_destroy(sc->dma_rxd_tag); 1476f85e0762SSepherosa Ziehau } 1477f85e0762SSepherosa Ziehau if (sc->dma_parent_tag != NULL) 1478f85e0762SSepherosa Ziehau bus_dma_tag_destroy(sc->dma_parent_tag); 1479f85e0762SSepherosa Ziehau } 1480f85e0762SSepherosa Ziehau 1481f85e0762SSepherosa Ziehau static void 1482f85e0762SSepherosa Ziehau ae_pcie_init(struct ae_softc *sc) 1483f85e0762SSepherosa Ziehau { 1484f85e0762SSepherosa Ziehau AE_WRITE_4(sc, AE_PCIE_LTSSM_TESTMODE_REG, 1485f85e0762SSepherosa Ziehau AE_PCIE_LTSSM_TESTMODE_DEFAULT); 1486f85e0762SSepherosa Ziehau AE_WRITE_4(sc, AE_PCIE_DLL_TX_CTRL_REG, 1487f85e0762SSepherosa Ziehau AE_PCIE_DLL_TX_CTRL_DEFAULT); 1488f85e0762SSepherosa Ziehau } 1489f85e0762SSepherosa Ziehau 1490f85e0762SSepherosa Ziehau static void 1491f85e0762SSepherosa Ziehau ae_phy_reset(struct ae_softc *sc) 1492f85e0762SSepherosa Ziehau { 1493f85e0762SSepherosa Ziehau AE_WRITE_4(sc, AE_PHY_ENABLE_REG, AE_PHY_ENABLE); 1494f85e0762SSepherosa Ziehau DELAY(1000); /* XXX: pause(9) ? */ 1495f85e0762SSepherosa Ziehau } 1496f85e0762SSepherosa Ziehau 1497f85e0762SSepherosa Ziehau static int 1498f85e0762SSepherosa Ziehau ae_reset(struct ae_softc *sc) 1499f85e0762SSepherosa Ziehau { 1500f85e0762SSepherosa Ziehau int i; 1501f85e0762SSepherosa Ziehau 1502f85e0762SSepherosa Ziehau /* 1503f85e0762SSepherosa Ziehau * Issue a soft reset. 1504f85e0762SSepherosa Ziehau */ 1505f85e0762SSepherosa Ziehau AE_WRITE_4(sc, AE_MASTER_REG, AE_MASTER_SOFT_RESET); 1506f85e0762SSepherosa Ziehau bus_space_barrier(sc->ae_mem_bt, sc->ae_mem_bh, AE_MASTER_REG, 4, 1507f85e0762SSepherosa Ziehau BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE); 1508f85e0762SSepherosa Ziehau 1509f85e0762SSepherosa Ziehau /* 1510f85e0762SSepherosa Ziehau * Wait for reset to complete. 1511f85e0762SSepherosa Ziehau */ 1512f85e0762SSepherosa Ziehau for (i = 0; i < AE_RESET_TIMEOUT; i++) { 1513f85e0762SSepherosa Ziehau if ((AE_READ_4(sc, AE_MASTER_REG) & AE_MASTER_SOFT_RESET) == 0) 1514f85e0762SSepherosa Ziehau break; 1515f85e0762SSepherosa Ziehau DELAY(10); 1516f85e0762SSepherosa Ziehau } 1517f85e0762SSepherosa Ziehau if (i == AE_RESET_TIMEOUT) { 1518f85e0762SSepherosa Ziehau device_printf(sc->ae_dev, "reset timeout.\n"); 1519f85e0762SSepherosa Ziehau return (ENXIO); 1520f85e0762SSepherosa Ziehau } 1521f85e0762SSepherosa Ziehau 1522f85e0762SSepherosa Ziehau /* 1523f85e0762SSepherosa Ziehau * Wait for everything to enter idle state. 1524f85e0762SSepherosa Ziehau */ 1525f85e0762SSepherosa Ziehau for (i = 0; i < AE_IDLE_TIMEOUT; i++) { 1526f85e0762SSepherosa Ziehau if (AE_READ_4(sc, AE_IDLE_REG) == 0) 1527f85e0762SSepherosa Ziehau break; 1528f85e0762SSepherosa Ziehau DELAY(100); 1529f85e0762SSepherosa Ziehau } 1530f85e0762SSepherosa Ziehau if (i == AE_IDLE_TIMEOUT) { 1531f85e0762SSepherosa Ziehau device_printf(sc->ae_dev, "could not enter idle state.\n"); 1532f85e0762SSepherosa Ziehau return (ENXIO); 1533f85e0762SSepherosa Ziehau } 1534f85e0762SSepherosa Ziehau return (0); 1535f85e0762SSepherosa Ziehau } 1536f85e0762SSepherosa Ziehau 1537f85e0762SSepherosa Ziehau static int 1538f85e0762SSepherosa Ziehau ae_check_eeprom_present(struct ae_softc *sc, int *vpdc) 1539f85e0762SSepherosa Ziehau { 1540f85e0762SSepherosa Ziehau int error; 1541f85e0762SSepherosa Ziehau uint32_t val; 1542f85e0762SSepherosa Ziehau 1543f85e0762SSepherosa Ziehau /* 1544f85e0762SSepherosa Ziehau * Not sure why, but Linux does this. 1545f85e0762SSepherosa Ziehau */ 1546f85e0762SSepherosa Ziehau val = AE_READ_4(sc, AE_SPICTL_REG); 1547f85e0762SSepherosa Ziehau if ((val & AE_SPICTL_VPD_EN) != 0) { 1548f85e0762SSepherosa Ziehau val &= ~AE_SPICTL_VPD_EN; 1549f85e0762SSepherosa Ziehau AE_WRITE_4(sc, AE_SPICTL_REG, val); 1550f85e0762SSepherosa Ziehau } 1551f85e0762SSepherosa Ziehau error = pci_find_extcap(sc->ae_dev, PCIY_VPD, vpdc); 1552f85e0762SSepherosa Ziehau return (error); 1553f85e0762SSepherosa Ziehau } 1554f85e0762SSepherosa Ziehau 1555f85e0762SSepherosa Ziehau static int 1556f85e0762SSepherosa Ziehau ae_vpd_read_word(struct ae_softc *sc, int reg, uint32_t *word) 1557f85e0762SSepherosa Ziehau { 1558f85e0762SSepherosa Ziehau uint32_t val; 1559f85e0762SSepherosa Ziehau int i; 1560f85e0762SSepherosa Ziehau 1561f85e0762SSepherosa Ziehau AE_WRITE_4(sc, AE_VPD_DATA_REG, 0); /* Clear register value. */ 1562f85e0762SSepherosa Ziehau 1563f85e0762SSepherosa Ziehau /* 1564f85e0762SSepherosa Ziehau * VPD registers start at offset 0x100. Read them. 1565f85e0762SSepherosa Ziehau */ 1566f85e0762SSepherosa Ziehau val = 0x100 + reg * 4; 1567f85e0762SSepherosa Ziehau AE_WRITE_4(sc, AE_VPD_CAP_REG, (val << AE_VPD_CAP_ADDR_SHIFT) & 1568f85e0762SSepherosa Ziehau AE_VPD_CAP_ADDR_MASK); 1569f85e0762SSepherosa Ziehau for (i = 0; i < AE_VPD_TIMEOUT; i++) { 1570f85e0762SSepherosa Ziehau DELAY(2000); 1571f85e0762SSepherosa Ziehau val = AE_READ_4(sc, AE_VPD_CAP_REG); 1572f85e0762SSepherosa Ziehau if ((val & AE_VPD_CAP_DONE) != 0) 1573f85e0762SSepherosa Ziehau break; 1574f85e0762SSepherosa Ziehau } 1575f85e0762SSepherosa Ziehau if (i == AE_VPD_TIMEOUT) { 1576f85e0762SSepherosa Ziehau device_printf(sc->ae_dev, "timeout reading VPD register %d.\n", 1577f85e0762SSepherosa Ziehau reg); 1578f85e0762SSepherosa Ziehau return (ETIMEDOUT); 1579f85e0762SSepherosa Ziehau } 1580f85e0762SSepherosa Ziehau *word = AE_READ_4(sc, AE_VPD_DATA_REG); 1581f85e0762SSepherosa Ziehau return (0); 1582f85e0762SSepherosa Ziehau } 1583f85e0762SSepherosa Ziehau 1584f85e0762SSepherosa Ziehau static int 1585f85e0762SSepherosa Ziehau ae_get_vpd_eaddr(struct ae_softc *sc, uint32_t *eaddr) 1586f85e0762SSepherosa Ziehau { 1587f85e0762SSepherosa Ziehau uint32_t word, reg, val; 1588f85e0762SSepherosa Ziehau int error; 1589f85e0762SSepherosa Ziehau int found; 1590f85e0762SSepherosa Ziehau int vpdc; 1591f85e0762SSepherosa Ziehau int i; 1592f85e0762SSepherosa Ziehau 1593f85e0762SSepherosa Ziehau /* 1594f85e0762SSepherosa Ziehau * Check for EEPROM. 1595f85e0762SSepherosa Ziehau */ 1596f85e0762SSepherosa Ziehau error = ae_check_eeprom_present(sc, &vpdc); 1597f85e0762SSepherosa Ziehau if (error != 0) 1598f85e0762SSepherosa Ziehau return (error); 1599f85e0762SSepherosa Ziehau 1600f85e0762SSepherosa Ziehau /* 1601f85e0762SSepherosa Ziehau * Read the VPD configuration space. 1602f85e0762SSepherosa Ziehau * Each register is prefixed with signature, 1603f85e0762SSepherosa Ziehau * so we can check if it is valid. 1604f85e0762SSepherosa Ziehau */ 1605f85e0762SSepherosa Ziehau for (i = 0, found = 0; i < AE_VPD_NREGS; i++) { 1606f85e0762SSepherosa Ziehau error = ae_vpd_read_word(sc, i, &word); 1607f85e0762SSepherosa Ziehau if (error != 0) 1608f85e0762SSepherosa Ziehau break; 1609f85e0762SSepherosa Ziehau 1610f85e0762SSepherosa Ziehau /* 1611f85e0762SSepherosa Ziehau * Check signature. 1612f85e0762SSepherosa Ziehau */ 1613f85e0762SSepherosa Ziehau if ((word & AE_VPD_SIG_MASK) != AE_VPD_SIG) 1614f85e0762SSepherosa Ziehau break; 1615f85e0762SSepherosa Ziehau reg = word >> AE_VPD_REG_SHIFT; 1616f85e0762SSepherosa Ziehau i++; /* Move to the next word. */ 1617f85e0762SSepherosa Ziehau if (reg != AE_EADDR0_REG && reg != AE_EADDR1_REG) 1618f85e0762SSepherosa Ziehau continue; 1619f85e0762SSepherosa Ziehau 1620f85e0762SSepherosa Ziehau error = ae_vpd_read_word(sc, i, &val); 1621f85e0762SSepherosa Ziehau if (error != 0) 1622f85e0762SSepherosa Ziehau break; 1623f85e0762SSepherosa Ziehau if (reg == AE_EADDR0_REG) 1624f85e0762SSepherosa Ziehau eaddr[0] = val; 1625f85e0762SSepherosa Ziehau else 1626f85e0762SSepherosa Ziehau eaddr[1] = val; 1627f85e0762SSepherosa Ziehau found++; 1628f85e0762SSepherosa Ziehau } 1629f85e0762SSepherosa Ziehau if (found < 2) 1630f85e0762SSepherosa Ziehau return (ENOENT); 1631f85e0762SSepherosa Ziehau 1632f85e0762SSepherosa Ziehau eaddr[1] &= 0xffff; /* Only last 2 bytes are used. */ 1633f85e0762SSepherosa Ziehau if (AE_CHECK_EADDR_VALID(eaddr) != 0) { 1634f85e0762SSepherosa Ziehau if (bootverbose) 1635f85e0762SSepherosa Ziehau device_printf(sc->ae_dev, 1636f85e0762SSepherosa Ziehau "VPD ethernet address registers are invalid.\n"); 1637f85e0762SSepherosa Ziehau return (EINVAL); 1638f85e0762SSepherosa Ziehau } 1639f85e0762SSepherosa Ziehau return (0); 1640f85e0762SSepherosa Ziehau } 1641f85e0762SSepherosa Ziehau 1642f85e0762SSepherosa Ziehau static int 1643f85e0762SSepherosa Ziehau ae_get_reg_eaddr(struct ae_softc *sc, uint32_t *eaddr) 1644f85e0762SSepherosa Ziehau { 1645f85e0762SSepherosa Ziehau /* 1646f85e0762SSepherosa Ziehau * BIOS is supposed to set this. 1647f85e0762SSepherosa Ziehau */ 1648f85e0762SSepherosa Ziehau eaddr[0] = AE_READ_4(sc, AE_EADDR0_REG); 1649f85e0762SSepherosa Ziehau eaddr[1] = AE_READ_4(sc, AE_EADDR1_REG); 1650f85e0762SSepherosa Ziehau eaddr[1] &= 0xffff; /* Only last 2 bytes are used. */ 1651f85e0762SSepherosa Ziehau if (AE_CHECK_EADDR_VALID(eaddr) != 0) { 1652f85e0762SSepherosa Ziehau if (bootverbose) 1653f85e0762SSepherosa Ziehau device_printf(sc->ae_dev, 1654f85e0762SSepherosa Ziehau "Ethetnet address registers are invalid.\n"); 1655f85e0762SSepherosa Ziehau return (EINVAL); 1656f85e0762SSepherosa Ziehau } 1657f85e0762SSepherosa Ziehau return (0); 1658f85e0762SSepherosa Ziehau } 1659f85e0762SSepherosa Ziehau 1660f85e0762SSepherosa Ziehau static void 1661f85e0762SSepherosa Ziehau ae_get_eaddr(struct ae_softc *sc) 1662f85e0762SSepherosa Ziehau { 1663f85e0762SSepherosa Ziehau uint32_t eaddr[2] = {0, 0}; 1664f85e0762SSepherosa Ziehau int error; 1665f85e0762SSepherosa Ziehau 1666f85e0762SSepherosa Ziehau /* 1667f85e0762SSepherosa Ziehau *Check for EEPROM. 1668f85e0762SSepherosa Ziehau */ 1669f85e0762SSepherosa Ziehau error = ae_get_vpd_eaddr(sc, eaddr); 1670f85e0762SSepherosa Ziehau if (error) 1671f85e0762SSepherosa Ziehau error = ae_get_reg_eaddr(sc, eaddr); 1672f85e0762SSepherosa Ziehau if (error) { 1673f85e0762SSepherosa Ziehau if (bootverbose) 1674f85e0762SSepherosa Ziehau device_printf(sc->ae_dev, 1675f85e0762SSepherosa Ziehau "Generating random ethernet address.\n"); 1676f85e0762SSepherosa Ziehau eaddr[0] = karc4random(); 1677f85e0762SSepherosa Ziehau /* 1678f85e0762SSepherosa Ziehau * Set OUI to ASUSTek COMPUTER INC. 1679f85e0762SSepherosa Ziehau */ 1680f85e0762SSepherosa Ziehau sc->ae_eaddr[0] = 0x02; /* U/L bit set. */ 1681f85e0762SSepherosa Ziehau sc->ae_eaddr[1] = 0x1f; 1682f85e0762SSepherosa Ziehau sc->ae_eaddr[2] = 0xc6; 1683f85e0762SSepherosa Ziehau sc->ae_eaddr[3] = (eaddr[0] >> 16) & 0xff; 1684f85e0762SSepherosa Ziehau sc->ae_eaddr[4] = (eaddr[0] >> 8) & 0xff; 1685f85e0762SSepherosa Ziehau sc->ae_eaddr[5] = (eaddr[0] >> 0) & 0xff; 1686f85e0762SSepherosa Ziehau } else { 1687f85e0762SSepherosa Ziehau sc->ae_eaddr[0] = (eaddr[1] >> 8) & 0xff; 1688f85e0762SSepherosa Ziehau sc->ae_eaddr[1] = (eaddr[1] >> 0) & 0xff; 1689f85e0762SSepherosa Ziehau sc->ae_eaddr[2] = (eaddr[0] >> 24) & 0xff; 1690f85e0762SSepherosa Ziehau sc->ae_eaddr[3] = (eaddr[0] >> 16) & 0xff; 1691f85e0762SSepherosa Ziehau sc->ae_eaddr[4] = (eaddr[0] >> 8) & 0xff; 1692f85e0762SSepherosa Ziehau sc->ae_eaddr[5] = (eaddr[0] >> 0) & 0xff; 1693f85e0762SSepherosa Ziehau } 1694f85e0762SSepherosa Ziehau } 1695f85e0762SSepherosa Ziehau 1696f85e0762SSepherosa Ziehau static int 1697f85e0762SSepherosa Ziehau ae_mediachange(struct ifnet *ifp) 1698f85e0762SSepherosa Ziehau { 1699f85e0762SSepherosa Ziehau struct ae_softc *sc = ifp->if_softc; 1700f85e0762SSepherosa Ziehau struct mii_data *mii = device_get_softc(sc->ae_miibus); 1701f85e0762SSepherosa Ziehau int error; 1702f85e0762SSepherosa Ziehau 1703f85e0762SSepherosa Ziehau ASSERT_SERIALIZED(ifp->if_serializer); 1704f85e0762SSepherosa Ziehau if (mii->mii_instance != 0) { 1705f85e0762SSepherosa Ziehau struct mii_softc *miisc; 1706f85e0762SSepherosa Ziehau LIST_FOREACH(miisc, &mii->mii_phys, mii_list) 1707f85e0762SSepherosa Ziehau mii_phy_reset(miisc); 1708f85e0762SSepherosa Ziehau } 1709f85e0762SSepherosa Ziehau error = mii_mediachg(mii); 1710f85e0762SSepherosa Ziehau return (error); 1711f85e0762SSepherosa Ziehau } 1712f85e0762SSepherosa Ziehau 1713f85e0762SSepherosa Ziehau static void 1714f85e0762SSepherosa Ziehau ae_mediastatus(struct ifnet *ifp, struct ifmediareq *ifmr) 1715f85e0762SSepherosa Ziehau { 1716f85e0762SSepherosa Ziehau struct ae_softc *sc = ifp->if_softc; 1717f85e0762SSepherosa Ziehau struct mii_data *mii = device_get_softc(sc->ae_miibus); 1718f85e0762SSepherosa Ziehau 1719f85e0762SSepherosa Ziehau ASSERT_SERIALIZED(ifp->if_serializer); 1720f85e0762SSepherosa Ziehau mii_pollstat(mii); 1721f85e0762SSepherosa Ziehau ifmr->ifm_status = mii->mii_media_status; 1722f85e0762SSepherosa Ziehau ifmr->ifm_active = mii->mii_media_active; 1723f85e0762SSepherosa Ziehau } 1724f85e0762SSepherosa Ziehau 1725f85e0762SSepherosa Ziehau static void 1726f85e0762SSepherosa Ziehau ae_update_stats_tx(uint16_t flags, struct ae_stats *stats) 1727f85e0762SSepherosa Ziehau { 1728f85e0762SSepherosa Ziehau if ((flags & AE_TXS_BCAST) != 0) 1729f85e0762SSepherosa Ziehau stats->tx_bcast++; 1730f85e0762SSepherosa Ziehau if ((flags & AE_TXS_MCAST) != 0) 1731f85e0762SSepherosa Ziehau stats->tx_mcast++; 1732f85e0762SSepherosa Ziehau if ((flags & AE_TXS_PAUSE) != 0) 1733f85e0762SSepherosa Ziehau stats->tx_pause++; 1734f85e0762SSepherosa Ziehau if ((flags & AE_TXS_CTRL) != 0) 1735f85e0762SSepherosa Ziehau stats->tx_ctrl++; 1736f85e0762SSepherosa Ziehau if ((flags & AE_TXS_DEFER) != 0) 1737f85e0762SSepherosa Ziehau stats->tx_defer++; 1738f85e0762SSepherosa Ziehau if ((flags & AE_TXS_EXCDEFER) != 0) 1739f85e0762SSepherosa Ziehau stats->tx_excdefer++; 1740f85e0762SSepherosa Ziehau if ((flags & AE_TXS_SINGLECOL) != 0) 1741f85e0762SSepherosa Ziehau stats->tx_singlecol++; 1742f85e0762SSepherosa Ziehau if ((flags & AE_TXS_MULTICOL) != 0) 1743f85e0762SSepherosa Ziehau stats->tx_multicol++; 1744f85e0762SSepherosa Ziehau if ((flags & AE_TXS_LATECOL) != 0) 1745f85e0762SSepherosa Ziehau stats->tx_latecol++; 1746f85e0762SSepherosa Ziehau if ((flags & AE_TXS_ABORTCOL) != 0) 1747f85e0762SSepherosa Ziehau stats->tx_abortcol++; 1748f85e0762SSepherosa Ziehau if ((flags & AE_TXS_UNDERRUN) != 0) 1749f85e0762SSepherosa Ziehau stats->tx_underrun++; 1750f85e0762SSepherosa Ziehau } 1751f85e0762SSepherosa Ziehau 1752f85e0762SSepherosa Ziehau static void 1753f85e0762SSepherosa Ziehau ae_update_stats_rx(uint16_t flags, struct ae_stats *stats) 1754f85e0762SSepherosa Ziehau { 1755f85e0762SSepherosa Ziehau if ((flags & AE_RXD_BCAST) != 0) 1756f85e0762SSepherosa Ziehau stats->rx_bcast++; 1757f85e0762SSepherosa Ziehau if ((flags & AE_RXD_MCAST) != 0) 1758f85e0762SSepherosa Ziehau stats->rx_mcast++; 1759f85e0762SSepherosa Ziehau if ((flags & AE_RXD_PAUSE) != 0) 1760f85e0762SSepherosa Ziehau stats->rx_pause++; 1761f85e0762SSepherosa Ziehau if ((flags & AE_RXD_CTRL) != 0) 1762f85e0762SSepherosa Ziehau stats->rx_ctrl++; 1763f85e0762SSepherosa Ziehau if ((flags & AE_RXD_CRCERR) != 0) 1764f85e0762SSepherosa Ziehau stats->rx_crcerr++; 1765f85e0762SSepherosa Ziehau if ((flags & AE_RXD_CODEERR) != 0) 1766f85e0762SSepherosa Ziehau stats->rx_codeerr++; 1767f85e0762SSepherosa Ziehau if ((flags & AE_RXD_RUNT) != 0) 1768f85e0762SSepherosa Ziehau stats->rx_runt++; 1769f85e0762SSepherosa Ziehau if ((flags & AE_RXD_FRAG) != 0) 1770f85e0762SSepherosa Ziehau stats->rx_frag++; 1771f85e0762SSepherosa Ziehau if ((flags & AE_RXD_TRUNC) != 0) 1772f85e0762SSepherosa Ziehau stats->rx_trunc++; 1773f85e0762SSepherosa Ziehau if ((flags & AE_RXD_ALIGN) != 0) 1774f85e0762SSepherosa Ziehau stats->rx_align++; 1775f85e0762SSepherosa Ziehau } 1776f85e0762SSepherosa Ziehau 1777f85e0762SSepherosa Ziehau static int 1778f85e0762SSepherosa Ziehau ae_resume(device_t dev) 1779f85e0762SSepherosa Ziehau { 1780f85e0762SSepherosa Ziehau struct ae_softc *sc = device_get_softc(dev); 1781f85e0762SSepherosa Ziehau struct ifnet *ifp = &sc->arpcom.ac_if; 1782f85e0762SSepherosa Ziehau 1783f85e0762SSepherosa Ziehau lwkt_serialize_enter(ifp->if_serializer); 1784f85e0762SSepherosa Ziehau #if 0 1785f85e0762SSepherosa Ziehau AE_READ_4(sc, AE_WOL_REG); /* Clear WOL status. */ 1786f85e0762SSepherosa Ziehau #endif 178797c1b3a4SSepherosa Ziehau ae_phy_reset(sc); 1788f85e0762SSepherosa Ziehau if ((ifp->if_flags & IFF_UP) != 0) 1789f85e0762SSepherosa Ziehau ae_init(sc); 1790f85e0762SSepherosa Ziehau lwkt_serialize_exit(ifp->if_serializer); 1791f85e0762SSepherosa Ziehau return (0); 1792f85e0762SSepherosa Ziehau } 1793f85e0762SSepherosa Ziehau 1794f85e0762SSepherosa Ziehau static int 1795f85e0762SSepherosa Ziehau ae_suspend(device_t dev) 1796f85e0762SSepherosa Ziehau { 1797f85e0762SSepherosa Ziehau struct ae_softc *sc = device_get_softc(dev); 1798f85e0762SSepherosa Ziehau struct ifnet *ifp = &sc->arpcom.ac_if; 1799f85e0762SSepherosa Ziehau 1800f85e0762SSepherosa Ziehau lwkt_serialize_enter(ifp->if_serializer); 1801f85e0762SSepherosa Ziehau ae_stop(sc); 1802f85e0762SSepherosa Ziehau #if 0 1803f85e0762SSepherosa Ziehau /* we don't use ae_pm_init because we don't want WOL */ 1804f85e0762SSepherosa Ziehau ae_pm_init(sc); 1805f85e0762SSepherosa Ziehau #endif 1806f85e0762SSepherosa Ziehau lwkt_serialize_exit(ifp->if_serializer); 1807f85e0762SSepherosa Ziehau return (0); 1808f85e0762SSepherosa Ziehau } 1809f85e0762SSepherosa Ziehau 1810f85e0762SSepherosa Ziehau static int 1811f85e0762SSepherosa Ziehau ae_shutdown(device_t dev) 1812f85e0762SSepherosa Ziehau { 1813f85e0762SSepherosa Ziehau struct ae_softc *sc = device_get_softc(dev); 1814f85e0762SSepherosa Ziehau struct ifnet *ifp = &sc->arpcom.ac_if; 1815f85e0762SSepherosa Ziehau 1816f85e0762SSepherosa Ziehau ae_suspend(dev); 1817f85e0762SSepherosa Ziehau 1818f85e0762SSepherosa Ziehau lwkt_serialize_enter(ifp->if_serializer); 1819f85e0762SSepherosa Ziehau ae_powersave_enable(sc); 1820f85e0762SSepherosa Ziehau lwkt_serialize_exit(ifp->if_serializer); 1821f85e0762SSepherosa Ziehau 1822f85e0762SSepherosa Ziehau return (0); 1823f85e0762SSepherosa Ziehau } 1824f85e0762SSepherosa Ziehau 1825f85e0762SSepherosa Ziehau static void 1826f85e0762SSepherosa Ziehau ae_powersave_disable(struct ae_softc *sc) 1827f85e0762SSepherosa Ziehau { 1828f85e0762SSepherosa Ziehau uint32_t val; 1829f85e0762SSepherosa Ziehau 1830f85e0762SSepherosa Ziehau AE_PHY_WRITE(sc, AE_PHY_DBG_ADDR, 0); 1831f85e0762SSepherosa Ziehau val = AE_PHY_READ(sc, AE_PHY_DBG_DATA); 1832f85e0762SSepherosa Ziehau if (val & AE_PHY_DBG_POWERSAVE) { 1833f85e0762SSepherosa Ziehau val &= ~AE_PHY_DBG_POWERSAVE; 1834f85e0762SSepherosa Ziehau AE_PHY_WRITE(sc, AE_PHY_DBG_DATA, val); 1835f85e0762SSepherosa Ziehau DELAY(1000); 1836f85e0762SSepherosa Ziehau } 1837f85e0762SSepherosa Ziehau } 1838f85e0762SSepherosa Ziehau 1839f85e0762SSepherosa Ziehau static void 1840f85e0762SSepherosa Ziehau ae_powersave_enable(struct ae_softc *sc) 1841f85e0762SSepherosa Ziehau { 1842f85e0762SSepherosa Ziehau uint32_t val; 1843f85e0762SSepherosa Ziehau 1844f85e0762SSepherosa Ziehau /* 1845f85e0762SSepherosa Ziehau * XXX magic numbers. 1846f85e0762SSepherosa Ziehau */ 1847f85e0762SSepherosa Ziehau AE_PHY_WRITE(sc, AE_PHY_DBG_ADDR, 0); 1848f85e0762SSepherosa Ziehau val = AE_PHY_READ(sc, AE_PHY_DBG_DATA); 1849f85e0762SSepherosa Ziehau AE_PHY_WRITE(sc, AE_PHY_DBG_ADDR, val | 0x1000); 1850f85e0762SSepherosa Ziehau AE_PHY_WRITE(sc, AE_PHY_DBG_ADDR, 2); 1851f85e0762SSepherosa Ziehau AE_PHY_WRITE(sc, AE_PHY_DBG_DATA, 0x3000); 1852f85e0762SSepherosa Ziehau AE_PHY_WRITE(sc, AE_PHY_DBG_ADDR, 3); 1853f85e0762SSepherosa Ziehau AE_PHY_WRITE(sc, AE_PHY_DBG_DATA, 0); 1854f85e0762SSepherosa Ziehau } 1855