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 *); 95f85e0762SSepherosa Ziehau static void ae_start(struct ifnet *); 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); 153f85e0762SSepherosa Ziehau DRIVER_MODULE(if_ae, pci, ae_driver, ae_devclass, 0, 0); 154f85e0762SSepherosa Ziehau DRIVER_MODULE(miibus, ae, miibus_driver, miibus_devclass, 0, 0); 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 }; 216f85e0762SSepherosa Ziehau #define AE_STATS_RX_LEN (sizeof(ae_stats_rx) / sizeof(*ae_stats_rx)) 217f85e0762SSepherosa Ziehau #define AE_STATS_TX_LEN (sizeof(ae_stats_tx) / sizeof(*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 227f85e0762SSepherosa Ziehau ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE); 228f85e0762SSepherosa Ziehau ifp->if_timer = 0; 229f85e0762SSepherosa Ziehau 230f85e0762SSepherosa Ziehau sc->ae_flags &= ~AE_FLAG_LINK; 231f85e0762SSepherosa Ziehau callout_stop(&sc->ae_tick_ch); 232f85e0762SSepherosa Ziehau 233f85e0762SSepherosa Ziehau /* 234f85e0762SSepherosa Ziehau * Clear and disable interrupts. 235f85e0762SSepherosa Ziehau */ 236f85e0762SSepherosa Ziehau AE_WRITE_4(sc, AE_IMR_REG, 0); 237f85e0762SSepherosa Ziehau AE_WRITE_4(sc, AE_ISR_REG, 0xffffffff); 238f85e0762SSepherosa Ziehau 239f85e0762SSepherosa Ziehau /* 240f85e0762SSepherosa Ziehau * Stop Rx/Tx MACs. 241f85e0762SSepherosa Ziehau */ 242f85e0762SSepherosa Ziehau ae_stop_txmac(sc); 243f85e0762SSepherosa Ziehau ae_stop_rxmac(sc); 244f85e0762SSepherosa Ziehau 245f85e0762SSepherosa Ziehau /* 246f85e0762SSepherosa Ziehau * Stop DMA engines. 247f85e0762SSepherosa Ziehau */ 248f85e0762SSepherosa Ziehau AE_WRITE_1(sc, AE_DMAREAD_REG, ~AE_DMAREAD_EN); 249f85e0762SSepherosa Ziehau AE_WRITE_1(sc, AE_DMAWRITE_REG, ~AE_DMAWRITE_EN); 250f85e0762SSepherosa Ziehau 251f85e0762SSepherosa Ziehau /* 252f85e0762SSepherosa Ziehau * Wait for everything to enter idle state. 253f85e0762SSepherosa Ziehau */ 254f85e0762SSepherosa Ziehau for (i = 0; i < AE_IDLE_TIMEOUT; i++) { 255f85e0762SSepherosa Ziehau if (AE_READ_4(sc, AE_IDLE_REG) == 0) 256f85e0762SSepherosa Ziehau break; 257f85e0762SSepherosa Ziehau DELAY(100); 258f85e0762SSepherosa Ziehau } 259f85e0762SSepherosa Ziehau if (i == AE_IDLE_TIMEOUT) 260f85e0762SSepherosa Ziehau if_printf(ifp, "could not enter idle state in stop.\n"); 261f85e0762SSepherosa Ziehau } 262f85e0762SSepherosa Ziehau 263f85e0762SSepherosa Ziehau static void 264f85e0762SSepherosa Ziehau ae_stop_rxmac(struct ae_softc *sc) 265f85e0762SSepherosa Ziehau { 266f85e0762SSepherosa Ziehau uint32_t val; 267f85e0762SSepherosa Ziehau int i; 268f85e0762SSepherosa Ziehau 269f85e0762SSepherosa Ziehau /* 270f85e0762SSepherosa Ziehau * Stop Rx MAC engine. 271f85e0762SSepherosa Ziehau */ 272f85e0762SSepherosa Ziehau val = AE_READ_4(sc, AE_MAC_REG); 273f85e0762SSepherosa Ziehau if ((val & AE_MAC_RX_EN) != 0) { 274f85e0762SSepherosa Ziehau val &= ~AE_MAC_RX_EN; 275f85e0762SSepherosa Ziehau AE_WRITE_4(sc, AE_MAC_REG, val); 276f85e0762SSepherosa Ziehau } 277f85e0762SSepherosa Ziehau 278f85e0762SSepherosa Ziehau /* 279f85e0762SSepherosa Ziehau * Stop Rx DMA engine. 280f85e0762SSepherosa Ziehau */ 281f85e0762SSepherosa Ziehau if (AE_READ_1(sc, AE_DMAWRITE_REG) == AE_DMAWRITE_EN) 282f85e0762SSepherosa Ziehau AE_WRITE_1(sc, AE_DMAWRITE_REG, 0); 283f85e0762SSepherosa Ziehau 284f85e0762SSepherosa Ziehau /* 285f85e0762SSepherosa Ziehau * Wait for IDLE state. 286f85e0762SSepherosa Ziehau */ 287f85e0762SSepherosa Ziehau for (i = 0; i < AE_IDLE_TIMEOUT; i--) { 288f85e0762SSepherosa Ziehau val = AE_READ_4(sc, AE_IDLE_REG); 289f85e0762SSepherosa Ziehau if ((val & (AE_IDLE_RXMAC | AE_IDLE_DMAWRITE)) == 0) 290f85e0762SSepherosa Ziehau break; 291f85e0762SSepherosa Ziehau DELAY(100); 292f85e0762SSepherosa Ziehau } 293f85e0762SSepherosa Ziehau if (i == AE_IDLE_TIMEOUT) { 294f85e0762SSepherosa Ziehau if_printf(&sc->arpcom.ac_if, 295f85e0762SSepherosa Ziehau "timed out while stopping Rx MAC.\n"); 296f85e0762SSepherosa Ziehau } 297f85e0762SSepherosa Ziehau } 298f85e0762SSepherosa Ziehau 299f85e0762SSepherosa Ziehau static void 300f85e0762SSepherosa Ziehau ae_stop_txmac(struct ae_softc *sc) 301f85e0762SSepherosa Ziehau { 302f85e0762SSepherosa Ziehau uint32_t val; 303f85e0762SSepherosa Ziehau int i; 304f85e0762SSepherosa Ziehau 305f85e0762SSepherosa Ziehau /* 306f85e0762SSepherosa Ziehau * Stop Tx MAC engine. 307f85e0762SSepherosa Ziehau */ 308f85e0762SSepherosa Ziehau val = AE_READ_4(sc, AE_MAC_REG); 309f85e0762SSepherosa Ziehau if ((val & AE_MAC_TX_EN) != 0) { 310f85e0762SSepherosa Ziehau val &= ~AE_MAC_TX_EN; 311f85e0762SSepherosa Ziehau AE_WRITE_4(sc, AE_MAC_REG, val); 312f85e0762SSepherosa Ziehau } 313f85e0762SSepherosa Ziehau 314f85e0762SSepherosa Ziehau /* 315f85e0762SSepherosa Ziehau * Stop Tx DMA engine. 316f85e0762SSepherosa Ziehau */ 317f85e0762SSepherosa Ziehau if (AE_READ_1(sc, AE_DMAREAD_REG) == AE_DMAREAD_EN) 318f85e0762SSepherosa Ziehau AE_WRITE_1(sc, AE_DMAREAD_REG, 0); 319f85e0762SSepherosa Ziehau 320f85e0762SSepherosa Ziehau /* 321f85e0762SSepherosa Ziehau * Wait for IDLE state. 322f85e0762SSepherosa Ziehau */ 323f85e0762SSepherosa Ziehau for (i = 0; i < AE_IDLE_TIMEOUT; i--) { 324f85e0762SSepherosa Ziehau val = AE_READ_4(sc, AE_IDLE_REG); 325f85e0762SSepherosa Ziehau if ((val & (AE_IDLE_TXMAC | AE_IDLE_DMAREAD)) == 0) 326f85e0762SSepherosa Ziehau break; 327f85e0762SSepherosa Ziehau DELAY(100); 328f85e0762SSepherosa Ziehau } 329f85e0762SSepherosa Ziehau if (i == AE_IDLE_TIMEOUT) { 330f85e0762SSepherosa Ziehau if_printf(&sc->arpcom.ac_if, 331f85e0762SSepherosa Ziehau "timed out while stopping Tx MAC.\n"); 332f85e0762SSepherosa Ziehau } 333f85e0762SSepherosa Ziehau } 334f85e0762SSepherosa Ziehau 335f85e0762SSepherosa Ziehau /* 336f85e0762SSepherosa Ziehau * Callback from MII layer when media changes. 337f85e0762SSepherosa Ziehau */ 338f85e0762SSepherosa Ziehau static void 339f85e0762SSepherosa Ziehau ae_miibus_statchg(device_t dev) 340f85e0762SSepherosa Ziehau { 341f85e0762SSepherosa Ziehau struct ae_softc *sc = device_get_softc(dev); 342f85e0762SSepherosa Ziehau struct ifnet *ifp = &sc->arpcom.ac_if; 343f85e0762SSepherosa Ziehau struct mii_data *mii; 344f85e0762SSepherosa Ziehau uint32_t val; 345f85e0762SSepherosa Ziehau 346f85e0762SSepherosa Ziehau ASSERT_SERIALIZED(ifp->if_serializer); 347f85e0762SSepherosa Ziehau 348f85e0762SSepherosa Ziehau if ((ifp->if_flags & IFF_RUNNING) == 0) 349f85e0762SSepherosa Ziehau return; 350f85e0762SSepherosa Ziehau 351f85e0762SSepherosa Ziehau mii = device_get_softc(sc->ae_miibus); 352f85e0762SSepherosa Ziehau sc->ae_flags &= ~AE_FLAG_LINK; 353f85e0762SSepherosa Ziehau if ((mii->mii_media_status & IFM_AVALID) != 0) { 354f85e0762SSepherosa Ziehau switch (IFM_SUBTYPE(mii->mii_media_active)) { 355f85e0762SSepherosa Ziehau case IFM_10_T: 356f85e0762SSepherosa Ziehau case IFM_100_TX: 357f85e0762SSepherosa Ziehau sc->ae_flags |= AE_FLAG_LINK; 358f85e0762SSepherosa Ziehau break; 359f85e0762SSepherosa Ziehau default: 360f85e0762SSepherosa Ziehau break; 361f85e0762SSepherosa Ziehau } 362f85e0762SSepherosa Ziehau } 363f85e0762SSepherosa Ziehau 364f85e0762SSepherosa Ziehau /* Stop Rx/Tx MACs. */ 365f85e0762SSepherosa Ziehau ae_stop_rxmac(sc); 366f85e0762SSepherosa Ziehau ae_stop_txmac(sc); 367f85e0762SSepherosa Ziehau 368f85e0762SSepherosa Ziehau /* Program MACs with resolved speed/duplex/flow-control. */ 369f85e0762SSepherosa Ziehau if ((sc->ae_flags & AE_FLAG_LINK) != 0) { 370f85e0762SSepherosa Ziehau ae_mac_config(sc); 371f85e0762SSepherosa Ziehau 372f85e0762SSepherosa Ziehau /* 373f85e0762SSepherosa Ziehau * Restart DMA engines. 374f85e0762SSepherosa Ziehau */ 375f85e0762SSepherosa Ziehau AE_WRITE_1(sc, AE_DMAREAD_REG, AE_DMAREAD_EN); 376f85e0762SSepherosa Ziehau AE_WRITE_1(sc, AE_DMAWRITE_REG, AE_DMAWRITE_EN); 377f85e0762SSepherosa Ziehau 378f85e0762SSepherosa Ziehau /* 379f85e0762SSepherosa Ziehau * Enable Rx and Tx MACs. 380f85e0762SSepherosa Ziehau */ 381f85e0762SSepherosa Ziehau val = AE_READ_4(sc, AE_MAC_REG); 382f85e0762SSepherosa Ziehau val |= AE_MAC_TX_EN | AE_MAC_RX_EN; 383f85e0762SSepherosa Ziehau AE_WRITE_4(sc, AE_MAC_REG, val); 384f85e0762SSepherosa Ziehau } 385f85e0762SSepherosa Ziehau } 386f85e0762SSepherosa Ziehau 387f85e0762SSepherosa Ziehau static void 388f85e0762SSepherosa Ziehau ae_sysctl_node(struct ae_softc *sc) 389f85e0762SSepherosa Ziehau { 390f85e0762SSepherosa Ziehau struct sysctl_ctx_list *ctx; 391f85e0762SSepherosa Ziehau struct sysctl_oid *root, *stats, *stats_rx, *stats_tx; 392f85e0762SSepherosa Ziehau struct ae_stats *ae_stats; 393f85e0762SSepherosa Ziehau unsigned int i; 394f85e0762SSepherosa Ziehau 395f85e0762SSepherosa Ziehau ae_stats = &sc->stats; 396f85e0762SSepherosa Ziehau sysctl_ctx_init(&sc->ae_sysctl_ctx); 397f85e0762SSepherosa Ziehau sc->ae_sysctl_tree = SYSCTL_ADD_NODE(&sc->ae_sysctl_ctx, 398f85e0762SSepherosa Ziehau SYSCTL_STATIC_CHILDREN(_hw), OID_AUTO, 399f85e0762SSepherosa Ziehau device_get_nameunit(sc->ae_dev), 400f85e0762SSepherosa Ziehau CTLFLAG_RD, 0, ""); 401f85e0762SSepherosa Ziehau if (sc->ae_sysctl_tree == NULL) { 402f85e0762SSepherosa Ziehau device_printf(sc->ae_dev, "can't add sysctl node\n"); 403f85e0762SSepherosa Ziehau return; 404f85e0762SSepherosa Ziehau } 405f85e0762SSepherosa Ziehau ctx = &sc->ae_sysctl_ctx; 406f85e0762SSepherosa Ziehau root = sc->ae_sysctl_tree; 407f85e0762SSepherosa Ziehau 408f85e0762SSepherosa Ziehau stats = SYSCTL_ADD_NODE(ctx, SYSCTL_CHILDREN(root), OID_AUTO, "stats", 409f85e0762SSepherosa Ziehau CTLFLAG_RD, NULL, "ae statistics"); 410f85e0762SSepherosa Ziehau if (stats == NULL) { 411f85e0762SSepherosa Ziehau device_printf(sc->ae_dev, "can't add stats sysctl node\n"); 412f85e0762SSepherosa Ziehau return; 413f85e0762SSepherosa Ziehau } 414f85e0762SSepherosa Ziehau 415f85e0762SSepherosa Ziehau /* 416f85e0762SSepherosa Ziehau * Receiver statistcics. 417f85e0762SSepherosa Ziehau */ 418f85e0762SSepherosa Ziehau stats_rx = SYSCTL_ADD_NODE(ctx, SYSCTL_CHILDREN(stats), OID_AUTO, "rx", 419f85e0762SSepherosa Ziehau CTLFLAG_RD, NULL, "Rx MAC statistics"); 420f85e0762SSepherosa Ziehau if (stats_rx != NULL) { 421f85e0762SSepherosa Ziehau for (i = 0; i < AE_STATS_RX_LEN; i++) { 422f85e0762SSepherosa Ziehau SYSCTL_ADD_UINT(ctx, SYSCTL_CHILDREN(stats_rx), 423f85e0762SSepherosa Ziehau OID_AUTO, ae_stats_rx[i].node, CTLFLAG_RD, 424f85e0762SSepherosa Ziehau (char *)ae_stats + ae_stats_rx[i].offset, 0, 425f85e0762SSepherosa Ziehau ae_stats_rx[i].desc); 426f85e0762SSepherosa Ziehau } 427f85e0762SSepherosa Ziehau } 428f85e0762SSepherosa Ziehau 429f85e0762SSepherosa Ziehau /* 430f85e0762SSepherosa Ziehau * Transmitter statistcics. 431f85e0762SSepherosa Ziehau */ 432f85e0762SSepherosa Ziehau stats_tx = SYSCTL_ADD_NODE(ctx, SYSCTL_CHILDREN(stats), OID_AUTO, "tx", 433f85e0762SSepherosa Ziehau CTLFLAG_RD, NULL, "Tx MAC statistics"); 434f85e0762SSepherosa Ziehau if (stats_tx != NULL) { 435f85e0762SSepherosa Ziehau for (i = 0; i < AE_STATS_TX_LEN; i++) { 436f85e0762SSepherosa Ziehau SYSCTL_ADD_UINT(ctx, SYSCTL_CHILDREN(stats_tx), 437f85e0762SSepherosa Ziehau OID_AUTO, ae_stats_tx[i].node, CTLFLAG_RD, 438f85e0762SSepherosa Ziehau (char *)ae_stats + ae_stats_tx[i].offset, 0, 439f85e0762SSepherosa Ziehau ae_stats_tx[i].desc); 440f85e0762SSepherosa Ziehau } 441f85e0762SSepherosa Ziehau } 442f85e0762SSepherosa Ziehau } 443f85e0762SSepherosa Ziehau 444f85e0762SSepherosa Ziehau static int 445f85e0762SSepherosa Ziehau ae_miibus_readreg(device_t dev, int phy, int reg) 446f85e0762SSepherosa Ziehau { 447f85e0762SSepherosa Ziehau struct ae_softc *sc = device_get_softc(dev); 448f85e0762SSepherosa Ziehau uint32_t val; 449f85e0762SSepherosa Ziehau int i; 450f85e0762SSepherosa Ziehau 451f85e0762SSepherosa Ziehau /* 452f85e0762SSepherosa Ziehau * Locking is done in upper layers. 453f85e0762SSepherosa Ziehau */ 454f85e0762SSepherosa Ziehau if (phy != sc->ae_phyaddr) 455f85e0762SSepherosa Ziehau return (0); 456f85e0762SSepherosa Ziehau val = ((reg << AE_MDIO_REGADDR_SHIFT) & AE_MDIO_REGADDR_MASK) | 457f85e0762SSepherosa Ziehau AE_MDIO_START | AE_MDIO_READ | AE_MDIO_SUP_PREAMBLE | 458f85e0762SSepherosa Ziehau ((AE_MDIO_CLK_25_4 << AE_MDIO_CLK_SHIFT) & AE_MDIO_CLK_MASK); 459f85e0762SSepherosa Ziehau AE_WRITE_4(sc, AE_MDIO_REG, val); 460f85e0762SSepherosa Ziehau 461f85e0762SSepherosa Ziehau /* 462f85e0762SSepherosa Ziehau * Wait for operation to complete. 463f85e0762SSepherosa Ziehau */ 464f85e0762SSepherosa Ziehau for (i = 0; i < AE_MDIO_TIMEOUT; i++) { 465f85e0762SSepherosa Ziehau DELAY(2); 466f85e0762SSepherosa Ziehau val = AE_READ_4(sc, AE_MDIO_REG); 467f85e0762SSepherosa Ziehau if ((val & (AE_MDIO_START | AE_MDIO_BUSY)) == 0) 468f85e0762SSepherosa Ziehau break; 469f85e0762SSepherosa Ziehau } 470f85e0762SSepherosa Ziehau if (i == AE_MDIO_TIMEOUT) { 471f85e0762SSepherosa Ziehau device_printf(sc->ae_dev, "phy read timeout: %d.\n", reg); 472f85e0762SSepherosa Ziehau return (0); 473f85e0762SSepherosa Ziehau } 474f85e0762SSepherosa Ziehau return ((val << AE_MDIO_DATA_SHIFT) & AE_MDIO_DATA_MASK); 475f85e0762SSepherosa Ziehau } 476f85e0762SSepherosa Ziehau 477f85e0762SSepherosa Ziehau static int 478f85e0762SSepherosa Ziehau ae_miibus_writereg(device_t dev, int phy, int reg, int val) 479f85e0762SSepherosa Ziehau { 480f85e0762SSepherosa Ziehau struct ae_softc *sc = device_get_softc(dev); 481f85e0762SSepherosa Ziehau uint32_t aereg; 482f85e0762SSepherosa Ziehau int i; 483f85e0762SSepherosa Ziehau 484f85e0762SSepherosa Ziehau /* 485f85e0762SSepherosa Ziehau * Locking is done in upper layers. 486f85e0762SSepherosa Ziehau */ 487f85e0762SSepherosa Ziehau if (phy != sc->ae_phyaddr) 488f85e0762SSepherosa Ziehau return (0); 489f85e0762SSepherosa Ziehau aereg = ((reg << AE_MDIO_REGADDR_SHIFT) & AE_MDIO_REGADDR_MASK) | 490f85e0762SSepherosa Ziehau AE_MDIO_START | AE_MDIO_SUP_PREAMBLE | 491f85e0762SSepherosa Ziehau ((AE_MDIO_CLK_25_4 << AE_MDIO_CLK_SHIFT) & AE_MDIO_CLK_MASK) | 492f85e0762SSepherosa Ziehau ((val << AE_MDIO_DATA_SHIFT) & AE_MDIO_DATA_MASK); 493f85e0762SSepherosa Ziehau AE_WRITE_4(sc, AE_MDIO_REG, aereg); 494f85e0762SSepherosa Ziehau 495f85e0762SSepherosa Ziehau /* 496f85e0762SSepherosa Ziehau * Wait for operation to complete. 497f85e0762SSepherosa Ziehau */ 498f85e0762SSepherosa Ziehau for (i = 0; i < AE_MDIO_TIMEOUT; i++) { 499f85e0762SSepherosa Ziehau DELAY(2); 500f85e0762SSepherosa Ziehau aereg = AE_READ_4(sc, AE_MDIO_REG); 501f85e0762SSepherosa Ziehau if ((aereg & (AE_MDIO_START | AE_MDIO_BUSY)) == 0) 502f85e0762SSepherosa Ziehau break; 503f85e0762SSepherosa Ziehau } 504f85e0762SSepherosa Ziehau if (i == AE_MDIO_TIMEOUT) 505f85e0762SSepherosa Ziehau device_printf(sc->ae_dev, "phy write timeout: %d.\n", reg); 506f85e0762SSepherosa Ziehau return (0); 507f85e0762SSepherosa Ziehau } 508f85e0762SSepherosa Ziehau 509f85e0762SSepherosa Ziehau static int 510f85e0762SSepherosa Ziehau ae_probe(device_t dev) 511f85e0762SSepherosa Ziehau { 512f85e0762SSepherosa Ziehau uint16_t vendor, devid; 513f85e0762SSepherosa Ziehau const struct ae_dev *sp; 514f85e0762SSepherosa Ziehau 515f85e0762SSepherosa Ziehau vendor = pci_get_vendor(dev); 516f85e0762SSepherosa Ziehau devid = pci_get_device(dev); 517f85e0762SSepherosa Ziehau for (sp = ae_devs; sp->ae_name != NULL; sp++) { 518f85e0762SSepherosa Ziehau if (vendor == sp->ae_vendorid && 519f85e0762SSepherosa Ziehau devid == sp->ae_deviceid) { 520f85e0762SSepherosa Ziehau device_set_desc(dev, sp->ae_name); 521f85e0762SSepherosa Ziehau return (0); 522f85e0762SSepherosa Ziehau } 523f85e0762SSepherosa Ziehau } 524f85e0762SSepherosa Ziehau return (ENXIO); 525f85e0762SSepherosa Ziehau } 526f85e0762SSepherosa Ziehau 527f85e0762SSepherosa Ziehau static int 528f85e0762SSepherosa Ziehau ae_dma_alloc(struct ae_softc *sc) 529f85e0762SSepherosa Ziehau { 530f85e0762SSepherosa Ziehau bus_addr_t busaddr; 531f85e0762SSepherosa Ziehau int error; 532f85e0762SSepherosa Ziehau 533f85e0762SSepherosa Ziehau /* 534f85e0762SSepherosa Ziehau * Create parent DMA tag. 535f85e0762SSepherosa Ziehau */ 536f85e0762SSepherosa Ziehau error = bus_dma_tag_create(NULL, 1, 0, 537f85e0762SSepherosa Ziehau BUS_SPACE_MAXADDR_32BIT, 538f85e0762SSepherosa Ziehau BUS_SPACE_MAXADDR, 539f85e0762SSepherosa Ziehau NULL, NULL, 540f85e0762SSepherosa Ziehau BUS_SPACE_MAXSIZE_32BIT, 541f85e0762SSepherosa Ziehau 0, 542f85e0762SSepherosa Ziehau BUS_SPACE_MAXSIZE_32BIT, 543f85e0762SSepherosa Ziehau 0, &sc->dma_parent_tag); 544f85e0762SSepherosa Ziehau if (error) { 545f85e0762SSepherosa Ziehau device_printf(sc->ae_dev, "could not creare parent DMA tag.\n"); 546f85e0762SSepherosa Ziehau return (error); 547f85e0762SSepherosa Ziehau } 548f85e0762SSepherosa Ziehau 549f85e0762SSepherosa Ziehau /* 550f85e0762SSepherosa Ziehau * Create DMA stuffs for TxD. 551f85e0762SSepherosa Ziehau */ 552f85e0762SSepherosa Ziehau sc->txd_base = bus_dmamem_coherent_any(sc->dma_parent_tag, 4, 553f85e0762SSepherosa Ziehau AE_TXD_BUFSIZE_DEFAULT, BUS_DMA_WAITOK | BUS_DMA_ZERO, 554f85e0762SSepherosa Ziehau &sc->dma_txd_tag, &sc->dma_txd_map, 555f85e0762SSepherosa Ziehau &sc->dma_txd_busaddr); 556f85e0762SSepherosa Ziehau if (sc->txd_base == NULL) { 557f85e0762SSepherosa Ziehau device_printf(sc->ae_dev, "could not creare TxD DMA stuffs.\n"); 558f85e0762SSepherosa Ziehau return ENOMEM; 559f85e0762SSepherosa Ziehau } 560f85e0762SSepherosa Ziehau 561f85e0762SSepherosa Ziehau /* 562f85e0762SSepherosa Ziehau * Create DMA stuffs for TxS. 563f85e0762SSepherosa Ziehau */ 564f85e0762SSepherosa Ziehau sc->txs_base = bus_dmamem_coherent_any(sc->dma_parent_tag, 4, 565f85e0762SSepherosa Ziehau AE_TXS_COUNT_DEFAULT * 4, BUS_DMA_WAITOK | BUS_DMA_ZERO, 566f85e0762SSepherosa Ziehau &sc->dma_txs_tag, &sc->dma_txs_map, 567f85e0762SSepherosa Ziehau &sc->dma_txs_busaddr); 568f85e0762SSepherosa Ziehau if (sc->txs_base == NULL) { 569f85e0762SSepherosa Ziehau device_printf(sc->ae_dev, "could not creare TxS DMA stuffs.\n"); 570f85e0762SSepherosa Ziehau return ENOMEM; 571f85e0762SSepherosa Ziehau } 572f85e0762SSepherosa Ziehau 573f85e0762SSepherosa Ziehau /* 574f85e0762SSepherosa Ziehau * Create DMA stuffs for RxD. 575f85e0762SSepherosa Ziehau */ 576f85e0762SSepherosa Ziehau sc->rxd_base_dma = bus_dmamem_coherent_any(sc->dma_parent_tag, 128, 577f85e0762SSepherosa Ziehau AE_RXD_COUNT_DEFAULT * 1536 + 120, 578f85e0762SSepherosa Ziehau BUS_DMA_WAITOK | BUS_DMA_ZERO, 579f85e0762SSepherosa Ziehau &sc->dma_rxd_tag, &sc->dma_rxd_map, 580f85e0762SSepherosa Ziehau &busaddr); 581f85e0762SSepherosa Ziehau if (sc->rxd_base_dma == NULL) { 582f85e0762SSepherosa Ziehau device_printf(sc->ae_dev, "could not creare RxD DMA stuffs.\n"); 583f85e0762SSepherosa Ziehau return ENOMEM; 584f85e0762SSepherosa Ziehau } 585f85e0762SSepherosa Ziehau sc->dma_rxd_busaddr = busaddr + 120; 586f85e0762SSepherosa Ziehau sc->rxd_base = (struct ae_rxd *)(sc->rxd_base_dma + 120); 587f85e0762SSepherosa Ziehau 588f85e0762SSepherosa Ziehau return (0); 589f85e0762SSepherosa Ziehau } 590f85e0762SSepherosa Ziehau 591f85e0762SSepherosa Ziehau static void 592f85e0762SSepherosa Ziehau ae_mac_config(struct ae_softc *sc) 593f85e0762SSepherosa Ziehau { 594f85e0762SSepherosa Ziehau struct mii_data *mii; 595f85e0762SSepherosa Ziehau uint32_t val; 596f85e0762SSepherosa Ziehau 597f85e0762SSepherosa Ziehau mii = device_get_softc(sc->ae_miibus); 598f85e0762SSepherosa Ziehau val = AE_READ_4(sc, AE_MAC_REG); 599f85e0762SSepherosa Ziehau val &= ~AE_MAC_FULL_DUPLEX; 600f85e0762SSepherosa Ziehau /* XXX disable AE_MAC_TX_FLOW_EN? */ 601f85e0762SSepherosa Ziehau if ((IFM_OPTIONS(mii->mii_media_active) & IFM_FDX) != 0) 602f85e0762SSepherosa Ziehau val |= AE_MAC_FULL_DUPLEX; 603f85e0762SSepherosa Ziehau AE_WRITE_4(sc, AE_MAC_REG, val); 604f85e0762SSepherosa Ziehau } 605f85e0762SSepherosa Ziehau 606f85e0762SSepherosa Ziehau static int 607f85e0762SSepherosa Ziehau ae_rxeof(struct ae_softc *sc, struct ae_rxd *rxd) 608f85e0762SSepherosa Ziehau { 609f85e0762SSepherosa Ziehau struct ifnet *ifp = &sc->arpcom.ac_if; 610f85e0762SSepherosa Ziehau struct mbuf *m; 611f85e0762SSepherosa Ziehau unsigned int size; 612f85e0762SSepherosa Ziehau uint16_t flags; 613f85e0762SSepherosa Ziehau 614f85e0762SSepherosa Ziehau flags = le16toh(rxd->flags); 615f85e0762SSepherosa Ziehau #ifdef AE_DEBUG 616f85e0762SSepherosa Ziehau if_printf(ifp, "Rx interrupt occuried.\n"); 617f85e0762SSepherosa Ziehau #endif 618f85e0762SSepherosa Ziehau size = le16toh(rxd->len) - ETHER_CRC_LEN; 619f85e0762SSepherosa Ziehau if (size < (ETHER_MIN_LEN - ETHER_CRC_LEN - 620f85e0762SSepherosa Ziehau sizeof(struct ether_vlan_header))) { 621f85e0762SSepherosa Ziehau if_printf(ifp, "Runt frame received."); 622f85e0762SSepherosa Ziehau return (EIO); 623f85e0762SSepherosa Ziehau } 624f85e0762SSepherosa Ziehau 625f85e0762SSepherosa Ziehau m = m_devget(&rxd->data[0], size, ETHER_ALIGN, ifp, NULL); 626f85e0762SSepherosa Ziehau if (m == NULL) 627f85e0762SSepherosa Ziehau return (ENOBUFS); 628f85e0762SSepherosa Ziehau 629f85e0762SSepherosa Ziehau if ((ifp->if_capenable & IFCAP_VLAN_HWTAGGING) && 630f85e0762SSepherosa Ziehau (flags & AE_RXD_HAS_VLAN)) { 631f85e0762SSepherosa Ziehau m->m_pkthdr.ether_vlantag = AE_RXD_VLAN(le16toh(rxd->vlan)); 632f85e0762SSepherosa Ziehau m->m_flags |= M_VLANTAG; 633f85e0762SSepherosa Ziehau } 634f85e0762SSepherosa Ziehau ifp->if_input(ifp, m); 635f85e0762SSepherosa Ziehau 636f85e0762SSepherosa Ziehau return (0); 637f85e0762SSepherosa Ziehau } 638f85e0762SSepherosa Ziehau 639f85e0762SSepherosa Ziehau static void 640f85e0762SSepherosa Ziehau ae_rx_intr(struct ae_softc *sc) 641f85e0762SSepherosa Ziehau { 642f85e0762SSepherosa Ziehau struct ifnet *ifp = &sc->arpcom.ac_if; 643f85e0762SSepherosa Ziehau struct ae_rxd *rxd; 644f85e0762SSepherosa Ziehau uint16_t flags; 645f85e0762SSepherosa Ziehau int error; 646f85e0762SSepherosa Ziehau 647f85e0762SSepherosa Ziehau /* 648f85e0762SSepherosa Ziehau * Syncronize DMA buffers. 649f85e0762SSepherosa Ziehau */ 650f85e0762SSepherosa Ziehau bus_dmamap_sync(sc->dma_rxd_tag, sc->dma_rxd_map, 651f85e0762SSepherosa Ziehau BUS_DMASYNC_POSTREAD); 652f85e0762SSepherosa Ziehau for (;;) { 653f85e0762SSepherosa Ziehau rxd = (struct ae_rxd *)(sc->rxd_base + sc->rxd_cur); 654f85e0762SSepherosa Ziehau 655f85e0762SSepherosa Ziehau flags = le16toh(rxd->flags); 656f85e0762SSepherosa Ziehau if ((flags & AE_RXD_UPDATE) == 0) 657f85e0762SSepherosa Ziehau break; 658f85e0762SSepherosa Ziehau rxd->flags = htole16(flags & ~AE_RXD_UPDATE); 659f85e0762SSepherosa Ziehau 660f85e0762SSepherosa Ziehau /* Update stats. */ 661f85e0762SSepherosa Ziehau ae_update_stats_rx(flags, &sc->stats); 662f85e0762SSepherosa Ziehau 663f85e0762SSepherosa Ziehau /* 664f85e0762SSepherosa Ziehau * Update position index. 665f85e0762SSepherosa Ziehau */ 666f85e0762SSepherosa Ziehau sc->rxd_cur = (sc->rxd_cur + 1) % AE_RXD_COUNT_DEFAULT; 667f85e0762SSepherosa Ziehau if ((flags & AE_RXD_SUCCESS) == 0) { 668f85e0762SSepherosa Ziehau ifp->if_ierrors++; 669f85e0762SSepherosa Ziehau continue; 670f85e0762SSepherosa Ziehau } 671f85e0762SSepherosa Ziehau 672f85e0762SSepherosa Ziehau error = ae_rxeof(sc, rxd); 673f85e0762SSepherosa Ziehau if (error) 674f85e0762SSepherosa Ziehau ifp->if_ierrors++; 675f85e0762SSepherosa Ziehau else 676f85e0762SSepherosa Ziehau ifp->if_ipackets++; 677f85e0762SSepherosa Ziehau } 678f85e0762SSepherosa Ziehau 679f85e0762SSepherosa Ziehau /* Update Rx index. */ 680f85e0762SSepherosa Ziehau AE_WRITE_2(sc, AE_MB_RXD_IDX_REG, sc->rxd_cur); 681f85e0762SSepherosa Ziehau } 682f85e0762SSepherosa Ziehau 683f85e0762SSepherosa Ziehau static void 684f85e0762SSepherosa Ziehau ae_tx_intr(struct ae_softc *sc) 685f85e0762SSepherosa Ziehau { 686f85e0762SSepherosa Ziehau struct ifnet *ifp = &sc->arpcom.ac_if; 687f85e0762SSepherosa Ziehau struct ae_txd *txd; 688f85e0762SSepherosa Ziehau struct ae_txs *txs; 689f85e0762SSepherosa Ziehau uint16_t flags; 690f85e0762SSepherosa Ziehau 691f85e0762SSepherosa Ziehau /* 692f85e0762SSepherosa Ziehau * Syncronize DMA buffers. 693f85e0762SSepherosa Ziehau */ 694f85e0762SSepherosa Ziehau bus_dmamap_sync(sc->dma_txd_tag, sc->dma_txd_map, BUS_DMASYNC_POSTREAD); 695f85e0762SSepherosa Ziehau bus_dmamap_sync(sc->dma_txs_tag, sc->dma_txs_map, BUS_DMASYNC_POSTREAD); 696f85e0762SSepherosa Ziehau 697f85e0762SSepherosa Ziehau for (;;) { 698f85e0762SSepherosa Ziehau txs = sc->txs_base + sc->txs_ack; 699f85e0762SSepherosa Ziehau 700f85e0762SSepherosa Ziehau flags = le16toh(txs->flags); 701f85e0762SSepherosa Ziehau if ((flags & AE_TXS_UPDATE) == 0) 702f85e0762SSepherosa Ziehau break; 703f85e0762SSepherosa Ziehau txs->flags = htole16(flags & ~AE_TXS_UPDATE); 704f85e0762SSepherosa Ziehau 705f85e0762SSepherosa Ziehau /* Update stats. */ 706f85e0762SSepherosa Ziehau ae_update_stats_tx(flags, &sc->stats); 707f85e0762SSepherosa Ziehau 708f85e0762SSepherosa Ziehau /* 709f85e0762SSepherosa Ziehau * Update TxS position. 710f85e0762SSepherosa Ziehau */ 711f85e0762SSepherosa Ziehau sc->txs_ack = (sc->txs_ack + 1) % AE_TXS_COUNT_DEFAULT; 712f85e0762SSepherosa Ziehau sc->ae_flags |= AE_FLAG_TXAVAIL; 713f85e0762SSepherosa Ziehau txd = (struct ae_txd *)(sc->txd_base + sc->txd_ack); 714f85e0762SSepherosa Ziehau if (txs->len != txd->len) { 715f85e0762SSepherosa Ziehau device_printf(sc->ae_dev, "Size mismatch: " 716f85e0762SSepherosa Ziehau "TxS:%d TxD:%d\n", 717f85e0762SSepherosa Ziehau le16toh(txs->len), le16toh(txd->len)); 718f85e0762SSepherosa Ziehau } 719f85e0762SSepherosa Ziehau 720f85e0762SSepherosa Ziehau /* 721f85e0762SSepherosa Ziehau * Move txd ack and align on 4-byte boundary. 722f85e0762SSepherosa Ziehau */ 723f85e0762SSepherosa Ziehau sc->txd_ack = ((sc->txd_ack + le16toh(txd->len) + 4 + 3) & ~3) % 724f85e0762SSepherosa Ziehau AE_TXD_BUFSIZE_DEFAULT; 725f85e0762SSepherosa Ziehau if ((flags & AE_TXS_SUCCESS) != 0) 726f85e0762SSepherosa Ziehau ifp->if_opackets++; 727f85e0762SSepherosa Ziehau else 728f85e0762SSepherosa Ziehau ifp->if_oerrors++; 729f85e0762SSepherosa Ziehau sc->tx_inproc--; 730f85e0762SSepherosa Ziehau } 731f85e0762SSepherosa Ziehau 732f85e0762SSepherosa Ziehau if (sc->tx_inproc < 0) { 733f85e0762SSepherosa Ziehau /* XXX assert? */ 734f85e0762SSepherosa Ziehau if_printf(ifp, "Received stray Tx interrupt(s).\n"); 735f85e0762SSepherosa Ziehau sc->tx_inproc = 0; 736f85e0762SSepherosa Ziehau } 737f85e0762SSepherosa Ziehau if (sc->tx_inproc == 0) 738f85e0762SSepherosa Ziehau ifp->if_timer = 0; /* Unarm watchdog. */ 739f85e0762SSepherosa Ziehau if (sc->ae_flags & AE_FLAG_TXAVAIL) { 740f85e0762SSepherosa Ziehau ifp->if_flags &= ~IFF_OACTIVE; 741f85e0762SSepherosa Ziehau if (!ifq_is_empty(&ifp->if_snd)) 742f85e0762SSepherosa Ziehau #ifdef foo 743f85e0762SSepherosa Ziehau ae_intr(sc); 744f85e0762SSepherosa Ziehau #else 745f85e0762SSepherosa Ziehau if_devstart(ifp); 746f85e0762SSepherosa Ziehau #endif 747f85e0762SSepherosa Ziehau } 748f85e0762SSepherosa Ziehau 749f85e0762SSepherosa Ziehau /* 750f85e0762SSepherosa Ziehau * Syncronize DMA buffers. 751f85e0762SSepherosa Ziehau */ 752f85e0762SSepherosa Ziehau bus_dmamap_sync(sc->dma_txd_tag, sc->dma_txd_map, BUS_DMASYNC_PREWRITE); 753f85e0762SSepherosa Ziehau bus_dmamap_sync(sc->dma_txs_tag, sc->dma_txs_map, BUS_DMASYNC_PREWRITE); 754f85e0762SSepherosa Ziehau } 755f85e0762SSepherosa Ziehau 756f85e0762SSepherosa Ziehau static void 757f85e0762SSepherosa Ziehau ae_intr(void *xsc) 758f85e0762SSepherosa Ziehau { 759f85e0762SSepherosa Ziehau struct ae_softc *sc = xsc; 760f85e0762SSepherosa Ziehau struct ifnet *ifp = &sc->arpcom.ac_if; 761f85e0762SSepherosa Ziehau uint32_t val; 762f85e0762SSepherosa Ziehau 763f85e0762SSepherosa Ziehau ASSERT_SERIALIZED(ifp->if_serializer); 764f85e0762SSepherosa Ziehau 765f85e0762SSepherosa Ziehau val = AE_READ_4(sc, AE_ISR_REG); 766f85e0762SSepherosa Ziehau if (val == 0 || (val & AE_IMR_DEFAULT) == 0) 767f85e0762SSepherosa Ziehau return; 768f85e0762SSepherosa Ziehau 769f85e0762SSepherosa Ziehau #ifdef foo 770f85e0762SSepherosa Ziehau AE_WRITE_4(sc, AE_ISR_REG, AE_ISR_DISABLE); 771f85e0762SSepherosa Ziehau #endif 772f85e0762SSepherosa Ziehau 773f85e0762SSepherosa Ziehau /* Read interrupt status. */ 774f85e0762SSepherosa Ziehau val = AE_READ_4(sc, AE_ISR_REG); 775f85e0762SSepherosa Ziehau 776f85e0762SSepherosa Ziehau /* Clear interrupts and disable them. */ 777f85e0762SSepherosa Ziehau AE_WRITE_4(sc, AE_ISR_REG, val | AE_ISR_DISABLE); 778f85e0762SSepherosa Ziehau 779f85e0762SSepherosa Ziehau if (ifp->if_flags & IFF_RUNNING) { 780f85e0762SSepherosa Ziehau if (val & (AE_ISR_DMAR_TIMEOUT | 781f85e0762SSepherosa Ziehau AE_ISR_DMAW_TIMEOUT | 782f85e0762SSepherosa Ziehau AE_ISR_PHY_LINKDOWN)) { 783f85e0762SSepherosa Ziehau ae_init(sc); 784f85e0762SSepherosa Ziehau } 785f85e0762SSepherosa Ziehau if (val & AE_ISR_TX_EVENT) 786f85e0762SSepherosa Ziehau ae_tx_intr(sc); 787f85e0762SSepherosa Ziehau if (val & AE_ISR_RX_EVENT) 788f85e0762SSepherosa Ziehau ae_rx_intr(sc); 789f85e0762SSepherosa Ziehau } 790f85e0762SSepherosa Ziehau 791f85e0762SSepherosa Ziehau /* Re-enable interrupts. */ 792f85e0762SSepherosa Ziehau AE_WRITE_4(sc, AE_ISR_REG, 0); 793f85e0762SSepherosa Ziehau } 794f85e0762SSepherosa Ziehau 795f85e0762SSepherosa Ziehau static void 796f85e0762SSepherosa Ziehau ae_init(void *xsc) 797f85e0762SSepherosa Ziehau { 798f85e0762SSepherosa Ziehau struct ae_softc *sc = xsc; 799f85e0762SSepherosa Ziehau struct ifnet *ifp = &sc->arpcom.ac_if; 800f85e0762SSepherosa Ziehau struct mii_data *mii; 801f85e0762SSepherosa Ziehau uint8_t eaddr[ETHER_ADDR_LEN]; 802f85e0762SSepherosa Ziehau uint32_t val; 803f85e0762SSepherosa Ziehau bus_addr_t addr; 804f85e0762SSepherosa Ziehau 805f85e0762SSepherosa Ziehau ASSERT_SERIALIZED(ifp->if_serializer); 806f85e0762SSepherosa Ziehau 807f85e0762SSepherosa Ziehau mii = device_get_softc(sc->ae_miibus); 808f85e0762SSepherosa Ziehau ae_stop(sc); 809f85e0762SSepherosa Ziehau ae_reset(sc); 810f85e0762SSepherosa Ziehau ae_pcie_init(sc); 811f85e0762SSepherosa Ziehau ae_powersave_disable(sc); 812f85e0762SSepherosa Ziehau 813f85e0762SSepherosa Ziehau /* 814f85e0762SSepherosa Ziehau * Clear and disable interrupts. 815f85e0762SSepherosa Ziehau */ 816f85e0762SSepherosa Ziehau AE_WRITE_4(sc, AE_ISR_REG, 0xffffffff); 817f85e0762SSepherosa Ziehau 818f85e0762SSepherosa Ziehau /* 819f85e0762SSepherosa Ziehau * Set the MAC address. 820f85e0762SSepherosa Ziehau */ 821f85e0762SSepherosa Ziehau bcopy(IF_LLADDR(ifp), eaddr, ETHER_ADDR_LEN); 822f85e0762SSepherosa Ziehau val = eaddr[2] << 24 | eaddr[3] << 16 | eaddr[4] << 8 | eaddr[5]; 823f85e0762SSepherosa Ziehau AE_WRITE_4(sc, AE_EADDR0_REG, val); 824f85e0762SSepherosa Ziehau val = eaddr[0] << 8 | eaddr[1]; 825f85e0762SSepherosa Ziehau AE_WRITE_4(sc, AE_EADDR1_REG, val); 826f85e0762SSepherosa Ziehau 827f85e0762SSepherosa Ziehau /* 828f85e0762SSepherosa Ziehau * Set ring buffers base addresses. 829f85e0762SSepherosa Ziehau */ 830f85e0762SSepherosa Ziehau addr = sc->dma_rxd_busaddr; 831f85e0762SSepherosa Ziehau AE_WRITE_4(sc, AE_DESC_ADDR_HI_REG, BUS_ADDR_HI(addr)); 832f85e0762SSepherosa Ziehau AE_WRITE_4(sc, AE_RXD_ADDR_LO_REG, BUS_ADDR_LO(addr)); 833f85e0762SSepherosa Ziehau addr = sc->dma_txd_busaddr; 834f85e0762SSepherosa Ziehau AE_WRITE_4(sc, AE_TXD_ADDR_LO_REG, BUS_ADDR_LO(addr)); 835f85e0762SSepherosa Ziehau addr = sc->dma_txs_busaddr; 836f85e0762SSepherosa Ziehau AE_WRITE_4(sc, AE_TXS_ADDR_LO_REG, BUS_ADDR_LO(addr)); 837f85e0762SSepherosa Ziehau 838f85e0762SSepherosa Ziehau /* 839f85e0762SSepherosa Ziehau * Configure ring buffers sizes. 840f85e0762SSepherosa Ziehau */ 841f85e0762SSepherosa Ziehau AE_WRITE_2(sc, AE_RXD_COUNT_REG, AE_RXD_COUNT_DEFAULT); 842f85e0762SSepherosa Ziehau AE_WRITE_2(sc, AE_TXD_BUFSIZE_REG, AE_TXD_BUFSIZE_DEFAULT / 4); 843f85e0762SSepherosa Ziehau AE_WRITE_2(sc, AE_TXS_COUNT_REG, AE_TXS_COUNT_DEFAULT); 844f85e0762SSepherosa Ziehau 845f85e0762SSepherosa Ziehau /* 846f85e0762SSepherosa Ziehau * Configure interframe gap parameters. 847f85e0762SSepherosa Ziehau */ 848f85e0762SSepherosa Ziehau val = ((AE_IFG_TXIPG_DEFAULT << AE_IFG_TXIPG_SHIFT) & 849f85e0762SSepherosa Ziehau AE_IFG_TXIPG_MASK) | 850f85e0762SSepherosa Ziehau ((AE_IFG_RXIPG_DEFAULT << AE_IFG_RXIPG_SHIFT) & 851f85e0762SSepherosa Ziehau AE_IFG_RXIPG_MASK) | 852f85e0762SSepherosa Ziehau ((AE_IFG_IPGR1_DEFAULT << AE_IFG_IPGR1_SHIFT) & 853f85e0762SSepherosa Ziehau AE_IFG_IPGR1_MASK) | 854f85e0762SSepherosa Ziehau ((AE_IFG_IPGR2_DEFAULT << AE_IFG_IPGR2_SHIFT) & 855f85e0762SSepherosa Ziehau AE_IFG_IPGR2_MASK); 856f85e0762SSepherosa Ziehau AE_WRITE_4(sc, AE_IFG_REG, val); 857f85e0762SSepherosa Ziehau 858f85e0762SSepherosa Ziehau /* 859f85e0762SSepherosa Ziehau * Configure half-duplex operation. 860f85e0762SSepherosa Ziehau */ 861f85e0762SSepherosa Ziehau val = ((AE_HDPX_LCOL_DEFAULT << AE_HDPX_LCOL_SHIFT) & 862f85e0762SSepherosa Ziehau AE_HDPX_LCOL_MASK) | 863f85e0762SSepherosa Ziehau ((AE_HDPX_RETRY_DEFAULT << AE_HDPX_RETRY_SHIFT) & 864f85e0762SSepherosa Ziehau AE_HDPX_RETRY_MASK) | 865f85e0762SSepherosa Ziehau ((AE_HDPX_ABEBT_DEFAULT << AE_HDPX_ABEBT_SHIFT) & 866f85e0762SSepherosa Ziehau AE_HDPX_ABEBT_MASK) | 867f85e0762SSepherosa Ziehau ((AE_HDPX_JAMIPG_DEFAULT << AE_HDPX_JAMIPG_SHIFT) & 868f85e0762SSepherosa Ziehau AE_HDPX_JAMIPG_MASK) | AE_HDPX_EXC_EN; 869f85e0762SSepherosa Ziehau AE_WRITE_4(sc, AE_HDPX_REG, val); 870f85e0762SSepherosa Ziehau 871f85e0762SSepherosa Ziehau /* 872f85e0762SSepherosa Ziehau * Configure interrupt moderate timer. 873f85e0762SSepherosa Ziehau */ 874f85e0762SSepherosa Ziehau AE_WRITE_2(sc, AE_IMT_REG, AE_IMT_DEFAULT); 875f85e0762SSepherosa Ziehau val = AE_READ_4(sc, AE_MASTER_REG); 876f85e0762SSepherosa Ziehau val |= AE_MASTER_IMT_EN; 877f85e0762SSepherosa Ziehau AE_WRITE_4(sc, AE_MASTER_REG, val); 878f85e0762SSepherosa Ziehau 879f85e0762SSepherosa Ziehau /* 880f85e0762SSepherosa Ziehau * Configure interrupt clearing timer. 881f85e0762SSepherosa Ziehau */ 882f85e0762SSepherosa Ziehau AE_WRITE_2(sc, AE_ICT_REG, AE_ICT_DEFAULT); 883f85e0762SSepherosa Ziehau 884f85e0762SSepherosa Ziehau /* 885f85e0762SSepherosa Ziehau * Configure MTU. 886f85e0762SSepherosa Ziehau */ 887f85e0762SSepherosa Ziehau val = ifp->if_mtu + ETHER_HDR_LEN + sizeof(struct ether_vlan_header) + 888f85e0762SSepherosa Ziehau ETHER_CRC_LEN; 889f85e0762SSepherosa Ziehau AE_WRITE_2(sc, AE_MTU_REG, val); 890f85e0762SSepherosa Ziehau 891f85e0762SSepherosa Ziehau /* 892f85e0762SSepherosa Ziehau * Configure cut-through threshold. 893f85e0762SSepherosa Ziehau */ 894f85e0762SSepherosa Ziehau AE_WRITE_4(sc, AE_CUT_THRESH_REG, AE_CUT_THRESH_DEFAULT); 895f85e0762SSepherosa Ziehau 896f85e0762SSepherosa Ziehau /* 897f85e0762SSepherosa Ziehau * Configure flow control. 898f85e0762SSepherosa Ziehau */ 899f85e0762SSepherosa Ziehau AE_WRITE_2(sc, AE_FLOW_THRESH_HI_REG, (AE_RXD_COUNT_DEFAULT / 8) * 7); 900f85e0762SSepherosa Ziehau AE_WRITE_2(sc, AE_FLOW_THRESH_LO_REG, (AE_RXD_COUNT_MIN / 8) > 901f85e0762SSepherosa Ziehau (AE_RXD_COUNT_DEFAULT / 12) ? (AE_RXD_COUNT_MIN / 8) : 902f85e0762SSepherosa Ziehau (AE_RXD_COUNT_DEFAULT / 12)); 903f85e0762SSepherosa Ziehau 904f85e0762SSepherosa Ziehau /* 905f85e0762SSepherosa Ziehau * Init mailboxes. 906f85e0762SSepherosa Ziehau */ 907f85e0762SSepherosa Ziehau sc->txd_cur = sc->rxd_cur = 0; 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; 977f85e0762SSepherosa Ziehau ifp->if_flags &= ~IFF_OACTIVE; 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"); 991f85e0762SSepherosa Ziehau ifp->if_oerrors++; 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)); 1057*441d34b2SSascha 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 1155f85e0762SSepherosa Ziehau ae_start(struct ifnet *ifp) 1156f85e0762SSepherosa Ziehau { 1157f85e0762SSepherosa Ziehau struct ae_softc *sc = ifp->if_softc; 1158f85e0762SSepherosa Ziehau int error, trans; 1159f85e0762SSepherosa Ziehau 1160f85e0762SSepherosa Ziehau ASSERT_SERIALIZED(ifp->if_serializer); 1161f85e0762SSepherosa Ziehau 1162f85e0762SSepherosa Ziehau #ifdef AE_DEBUG 1163f85e0762SSepherosa Ziehau if_printf(ifp, "Start called.\n"); 1164f85e0762SSepherosa Ziehau #endif 1165f85e0762SSepherosa Ziehau if ((sc->ae_flags & AE_FLAG_LINK) == 0) { 1166f85e0762SSepherosa Ziehau ifq_purge(&ifp->if_snd); 1167f85e0762SSepherosa Ziehau return; 1168f85e0762SSepherosa Ziehau } 1169f85e0762SSepherosa Ziehau if ((ifp->if_flags & (IFF_RUNNING | IFF_OACTIVE)) != IFF_RUNNING) 1170f85e0762SSepherosa Ziehau return; 1171f85e0762SSepherosa Ziehau 1172f85e0762SSepherosa Ziehau trans = 0; 1173f85e0762SSepherosa Ziehau while (!ifq_is_empty(&ifp->if_snd)) { 1174f85e0762SSepherosa Ziehau struct mbuf *m0; 1175f85e0762SSepherosa Ziehau 1176f85e0762SSepherosa Ziehau m0 = ifq_dequeue(&ifp->if_snd, NULL); 1177f85e0762SSepherosa Ziehau if (m0 == NULL) 1178f85e0762SSepherosa Ziehau break; /* Nothing to do. */ 1179f85e0762SSepherosa Ziehau 1180f85e0762SSepherosa Ziehau error = ae_encap(sc, &m0); 1181f85e0762SSepherosa Ziehau if (error != 0) { 1182f85e0762SSepherosa Ziehau if (m0 != NULL) { 1183f85e0762SSepherosa Ziehau ifq_prepend(&ifp->if_snd, m0); 1184f85e0762SSepherosa Ziehau ifp->if_flags |= IFF_OACTIVE; 1185f85e0762SSepherosa Ziehau #ifdef AE_DEBUG 1186f85e0762SSepherosa Ziehau if_printf(ifp, "Setting OACTIVE.\n"); 1187f85e0762SSepherosa Ziehau #endif 1188f85e0762SSepherosa Ziehau } 1189f85e0762SSepherosa Ziehau break; 1190f85e0762SSepherosa Ziehau } 1191f85e0762SSepherosa Ziehau trans = 1; 1192f85e0762SSepherosa Ziehau sc->tx_inproc++; 1193f85e0762SSepherosa Ziehau 1194f85e0762SSepherosa Ziehau /* Bounce a copy of the frame to BPF. */ 1195f85e0762SSepherosa Ziehau ETHER_BPF_MTAP(ifp, m0); 1196f85e0762SSepherosa Ziehau m_freem(m0); 1197f85e0762SSepherosa Ziehau } 1198f85e0762SSepherosa Ziehau if (trans) { /* Something was dequeued. */ 1199f85e0762SSepherosa Ziehau AE_WRITE_2(sc, AE_MB_TXD_IDX_REG, sc->txd_cur / 4); 1200f85e0762SSepherosa Ziehau ifp->if_timer = AE_TX_TIMEOUT; /* Load watchdog. */ 1201f85e0762SSepherosa Ziehau #ifdef AE_DEBUG 1202f85e0762SSepherosa Ziehau if_printf(ifp, "%d packets dequeued.\n", count); 1203f85e0762SSepherosa Ziehau if_printf(ifp, "Tx pos now is %d.\n", sc->txd_cur); 1204f85e0762SSepherosa Ziehau #endif 1205f85e0762SSepherosa Ziehau } 1206f85e0762SSepherosa Ziehau } 1207f85e0762SSepherosa Ziehau 1208f85e0762SSepherosa Ziehau static int 1209f85e0762SSepherosa Ziehau ae_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data, struct ucred *cr) 1210f85e0762SSepherosa Ziehau { 1211f85e0762SSepherosa Ziehau struct ae_softc *sc = ifp->if_softc; 1212f85e0762SSepherosa Ziehau struct ifreq *ifr; 1213f85e0762SSepherosa Ziehau struct mii_data *mii; 1214f85e0762SSepherosa Ziehau int error = 0, mask; 1215f85e0762SSepherosa Ziehau 1216f85e0762SSepherosa Ziehau ASSERT_SERIALIZED(ifp->if_serializer); 1217f85e0762SSepherosa Ziehau 1218f85e0762SSepherosa Ziehau ifr = (struct ifreq *)data; 1219f85e0762SSepherosa Ziehau switch (cmd) { 1220f85e0762SSepherosa Ziehau case SIOCSIFFLAGS: 1221f85e0762SSepherosa Ziehau if (ifp->if_flags & IFF_UP) { 1222f85e0762SSepherosa Ziehau if (ifp->if_flags & IFF_RUNNING) { 1223f85e0762SSepherosa Ziehau if (((ifp->if_flags ^ sc->ae_if_flags) 1224f85e0762SSepherosa Ziehau & (IFF_PROMISC | IFF_ALLMULTI)) != 0) 1225f85e0762SSepherosa Ziehau ae_rxfilter(sc); 1226f85e0762SSepherosa Ziehau } else { 1227f85e0762SSepherosa Ziehau ae_init(sc); 1228f85e0762SSepherosa Ziehau } 1229f85e0762SSepherosa Ziehau } else { 1230f85e0762SSepherosa Ziehau if (ifp->if_flags & IFF_RUNNING) 1231f85e0762SSepherosa Ziehau ae_stop(sc); 1232f85e0762SSepherosa Ziehau } 1233f85e0762SSepherosa Ziehau sc->ae_if_flags = ifp->if_flags; 1234f85e0762SSepherosa Ziehau break; 1235f85e0762SSepherosa Ziehau 1236f85e0762SSepherosa Ziehau case SIOCADDMULTI: 1237f85e0762SSepherosa Ziehau case SIOCDELMULTI: 1238f85e0762SSepherosa Ziehau if (ifp->if_flags & IFF_RUNNING) 1239f85e0762SSepherosa Ziehau ae_rxfilter(sc); 1240f85e0762SSepherosa Ziehau break; 1241f85e0762SSepherosa Ziehau 1242f85e0762SSepherosa Ziehau case SIOCSIFMEDIA: 1243f85e0762SSepherosa Ziehau case SIOCGIFMEDIA: 1244f85e0762SSepherosa Ziehau mii = device_get_softc(sc->ae_miibus); 1245f85e0762SSepherosa Ziehau error = ifmedia_ioctl(ifp, ifr, &mii->mii_media, cmd); 1246f85e0762SSepherosa Ziehau break; 1247f85e0762SSepherosa Ziehau 1248f85e0762SSepherosa Ziehau case SIOCSIFCAP: 1249f85e0762SSepherosa Ziehau mask = ifr->ifr_reqcap ^ ifp->if_capenable; 1250f85e0762SSepherosa Ziehau if (mask & IFCAP_VLAN_HWTAGGING) { 1251f85e0762SSepherosa Ziehau ifp->if_capenable ^= IFCAP_VLAN_HWTAGGING; 1252f85e0762SSepherosa Ziehau ae_rxvlan(sc); 1253f85e0762SSepherosa Ziehau } 1254f85e0762SSepherosa Ziehau break; 1255f85e0762SSepherosa Ziehau 1256f85e0762SSepherosa Ziehau default: 1257f85e0762SSepherosa Ziehau error = ether_ioctl(ifp, cmd, data); 1258f85e0762SSepherosa Ziehau break; 1259f85e0762SSepherosa Ziehau } 1260f85e0762SSepherosa Ziehau return (error); 1261f85e0762SSepherosa Ziehau } 1262f85e0762SSepherosa Ziehau 1263f85e0762SSepherosa Ziehau static int 1264f85e0762SSepherosa Ziehau ae_attach(device_t dev) 1265f85e0762SSepherosa Ziehau { 1266f85e0762SSepherosa Ziehau struct ae_softc *sc = device_get_softc(dev); 1267f85e0762SSepherosa Ziehau struct ifnet *ifp = &sc->arpcom.ac_if; 1268f85e0762SSepherosa Ziehau int error = 0; 1269f85e0762SSepherosa Ziehau 1270f85e0762SSepherosa Ziehau sc->ae_dev = dev; 1271f85e0762SSepherosa Ziehau if_initname(ifp, device_get_name(dev), device_get_unit(dev)); 1272f85e0762SSepherosa Ziehau callout_init(&sc->ae_tick_ch); 1273f85e0762SSepherosa Ziehau 1274f85e0762SSepherosa Ziehau /* Enable bus mastering */ 1275f85e0762SSepherosa Ziehau pci_enable_busmaster(dev); 1276f85e0762SSepherosa Ziehau 1277f85e0762SSepherosa Ziehau /* 1278f85e0762SSepherosa Ziehau * Allocate memory mapped IO 1279f85e0762SSepherosa Ziehau */ 1280f85e0762SSepherosa Ziehau sc->ae_mem_rid = PCIR_BAR(0); 1281f85e0762SSepherosa Ziehau sc->ae_mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, 1282f85e0762SSepherosa Ziehau &sc->ae_mem_rid, RF_ACTIVE); 1283f85e0762SSepherosa Ziehau if (sc->ae_mem_res == NULL) { 1284f85e0762SSepherosa Ziehau device_printf(dev, "can't allocate IO memory\n"); 1285f85e0762SSepherosa Ziehau return ENXIO; 1286f85e0762SSepherosa Ziehau } 1287f85e0762SSepherosa Ziehau sc->ae_mem_bt = rman_get_bustag(sc->ae_mem_res); 1288f85e0762SSepherosa Ziehau sc->ae_mem_bh = rman_get_bushandle(sc->ae_mem_res); 1289f85e0762SSepherosa Ziehau 1290f85e0762SSepherosa Ziehau /* 1291f85e0762SSepherosa Ziehau * Allocate IRQ 1292f85e0762SSepherosa Ziehau */ 1293f85e0762SSepherosa Ziehau sc->ae_irq_rid = 0; 1294f85e0762SSepherosa Ziehau sc->ae_irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, 1295f85e0762SSepherosa Ziehau &sc->ae_irq_rid, 1296f85e0762SSepherosa Ziehau RF_SHAREABLE | RF_ACTIVE); 1297f85e0762SSepherosa Ziehau if (sc->ae_irq_res == NULL) { 1298f85e0762SSepherosa Ziehau device_printf(dev, "can't allocate irq\n"); 1299f85e0762SSepherosa Ziehau error = ENXIO; 1300f85e0762SSepherosa Ziehau goto fail; 1301f85e0762SSepherosa Ziehau } 1302f85e0762SSepherosa Ziehau 1303f85e0762SSepherosa Ziehau /* Set PHY address. */ 1304f85e0762SSepherosa Ziehau sc->ae_phyaddr = AE_PHYADDR_DEFAULT; 1305f85e0762SSepherosa Ziehau 1306f85e0762SSepherosa Ziehau /* Create sysctl tree */ 1307f85e0762SSepherosa Ziehau ae_sysctl_node(sc); 1308f85e0762SSepherosa Ziehau 1309f85e0762SSepherosa Ziehau /* Reset PHY. */ 1310f85e0762SSepherosa Ziehau ae_phy_reset(sc); 1311f85e0762SSepherosa Ziehau 1312f85e0762SSepherosa Ziehau /* 1313f85e0762SSepherosa Ziehau * Reset the ethernet controller. 1314f85e0762SSepherosa Ziehau */ 1315f85e0762SSepherosa Ziehau ae_reset(sc); 1316f85e0762SSepherosa Ziehau ae_pcie_init(sc); 1317f85e0762SSepherosa Ziehau 1318f85e0762SSepherosa Ziehau /* 1319f85e0762SSepherosa Ziehau * Get PCI and chip id/revision. 1320f85e0762SSepherosa Ziehau */ 1321f85e0762SSepherosa Ziehau sc->ae_rev = pci_get_revid(dev); 1322f85e0762SSepherosa Ziehau sc->ae_chip_rev = 1323f85e0762SSepherosa Ziehau (AE_READ_4(sc, AE_MASTER_REG) >> AE_MASTER_REVNUM_SHIFT) & 1324f85e0762SSepherosa Ziehau AE_MASTER_REVNUM_MASK; 1325f85e0762SSepherosa Ziehau if (bootverbose) { 1326f85e0762SSepherosa Ziehau device_printf(dev, "PCI device revision : 0x%04x\n", sc->ae_rev); 1327f85e0762SSepherosa Ziehau device_printf(dev, "Chip id/revision : 0x%04x\n", 1328f85e0762SSepherosa Ziehau sc->ae_chip_rev); 1329f85e0762SSepherosa Ziehau } 1330f85e0762SSepherosa Ziehau 1331f85e0762SSepherosa Ziehau /* 1332f85e0762SSepherosa Ziehau * XXX 1333f85e0762SSepherosa Ziehau * Unintialized hardware returns an invalid chip id/revision 1334f85e0762SSepherosa Ziehau * as well as 0xFFFFFFFF for Tx/Rx fifo length. It seems that 1335f85e0762SSepherosa Ziehau * unplugged cable results in putting hardware into automatic 1336f85e0762SSepherosa Ziehau * power down mode which in turn returns invalld chip revision. 1337f85e0762SSepherosa Ziehau */ 1338f85e0762SSepherosa Ziehau if (sc->ae_chip_rev == 0xFFFF) { 1339f85e0762SSepherosa Ziehau device_printf(dev,"invalid chip revision : 0x%04x -- " 1340f85e0762SSepherosa Ziehau "not initialized?\n", sc->ae_chip_rev); 1341f85e0762SSepherosa Ziehau error = ENXIO; 1342f85e0762SSepherosa Ziehau goto fail; 1343f85e0762SSepherosa Ziehau } 1344f85e0762SSepherosa Ziehau #if 0 1345f85e0762SSepherosa Ziehau /* Get DMA parameters from PCIe device control register. */ 1346f85e0762SSepherosa Ziehau pcie_ptr = pci_get_pciecap_ptr(dev); 1347f85e0762SSepherosa Ziehau if (pcie_ptr) { 1348f85e0762SSepherosa Ziehau uint16_t devctl; 1349f85e0762SSepherosa Ziehau sc->ae_flags |= AE_FLAG_PCIE; 1350f85e0762SSepherosa Ziehau devctl = pci_read_config(dev, pcie_ptr + PCIER_DEVCTRL, 2); 1351f85e0762SSepherosa Ziehau /* Max read request size. */ 1352f85e0762SSepherosa Ziehau sc->ae_dma_rd_burst = ((devctl >> 12) & 0x07) << 1353f85e0762SSepherosa Ziehau DMA_CFG_RD_BURST_SHIFT; 1354f85e0762SSepherosa Ziehau /* Max payload size. */ 1355f85e0762SSepherosa Ziehau sc->ae_dma_wr_burst = ((devctl >> 5) & 0x07) << 1356f85e0762SSepherosa Ziehau DMA_CFG_WR_BURST_SHIFT; 1357f85e0762SSepherosa Ziehau if (bootverbose) { 1358f85e0762SSepherosa Ziehau device_printf(dev, "Read request size : %d bytes.\n", 1359f85e0762SSepherosa Ziehau 128 << ((devctl >> 12) & 0x07)); 1360f85e0762SSepherosa Ziehau device_printf(dev, "TLP payload size : %d bytes.\n", 1361f85e0762SSepherosa Ziehau 128 << ((devctl >> 5) & 0x07)); 1362f85e0762SSepherosa Ziehau } 1363f85e0762SSepherosa Ziehau } else { 1364f85e0762SSepherosa Ziehau sc->ae_dma_rd_burst = DMA_CFG_RD_BURST_128; 1365f85e0762SSepherosa Ziehau sc->ae_dma_wr_burst = DMA_CFG_WR_BURST_128; 1366f85e0762SSepherosa Ziehau } 1367f85e0762SSepherosa Ziehau #endif 1368f85e0762SSepherosa Ziehau 1369f85e0762SSepherosa Ziehau /* Create DMA stuffs */ 1370f85e0762SSepherosa Ziehau error = ae_dma_alloc(sc); 1371f85e0762SSepherosa Ziehau if (error) 1372f85e0762SSepherosa Ziehau goto fail; 1373f85e0762SSepherosa Ziehau 1374f85e0762SSepherosa Ziehau /* Load station address. */ 1375f85e0762SSepherosa Ziehau ae_get_eaddr(sc); 1376f85e0762SSepherosa Ziehau 1377f85e0762SSepherosa Ziehau ifp->if_softc = sc; 1378f85e0762SSepherosa Ziehau ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 1379f85e0762SSepherosa Ziehau ifp->if_ioctl = ae_ioctl; 1380f85e0762SSepherosa Ziehau ifp->if_start = ae_start; 1381f85e0762SSepherosa Ziehau ifp->if_init = ae_init; 1382f85e0762SSepherosa Ziehau ifp->if_watchdog = ae_watchdog; 1383f85e0762SSepherosa Ziehau ifq_set_maxlen(&ifp->if_snd, IFQ_MAXLEN - 1); 1384f85e0762SSepherosa Ziehau ifq_set_ready(&ifp->if_snd); 1385f85e0762SSepherosa Ziehau ifp->if_capabilities = IFCAP_VLAN_MTU | 1386f85e0762SSepherosa Ziehau IFCAP_VLAN_HWTAGGING; 1387f85e0762SSepherosa Ziehau ifp->if_hwassist = 0; 1388f85e0762SSepherosa Ziehau ifp->if_capenable = ifp->if_capabilities; 1389f85e0762SSepherosa Ziehau 1390f85e0762SSepherosa Ziehau /* Set up MII bus. */ 1391f85e0762SSepherosa Ziehau error = mii_phy_probe(dev, &sc->ae_miibus, 1392f85e0762SSepherosa Ziehau ae_mediachange, ae_mediastatus); 1393f85e0762SSepherosa Ziehau if (error) { 1394f85e0762SSepherosa Ziehau device_printf(dev, "no PHY found!\n"); 1395f85e0762SSepherosa Ziehau goto fail; 1396f85e0762SSepherosa Ziehau } 1397f85e0762SSepherosa Ziehau ether_ifattach(ifp, sc->ae_eaddr, NULL); 1398f85e0762SSepherosa Ziehau 1399f85e0762SSepherosa Ziehau /* Tell the upper layer(s) we support long frames. */ 1400f85e0762SSepherosa Ziehau ifp->if_data.ifi_hdrlen = sizeof(struct ether_vlan_header); 1401f85e0762SSepherosa Ziehau 1402f85e0762SSepherosa Ziehau error = bus_setup_intr(dev, sc->ae_irq_res, INTR_MPSAFE, ae_intr, sc, 1403f85e0762SSepherosa Ziehau &sc->ae_irq_handle, ifp->if_serializer); 1404f85e0762SSepherosa Ziehau if (error) { 1405f85e0762SSepherosa Ziehau device_printf(dev, "could not set up interrupt handler.\n"); 1406f85e0762SSepherosa Ziehau ether_ifdetach(ifp); 1407f85e0762SSepherosa Ziehau goto fail; 1408f85e0762SSepherosa Ziehau } 1409f85e0762SSepherosa Ziehau ifp->if_cpuid = ithread_cpuid(rman_get_start(sc->ae_irq_res)); 1410f85e0762SSepherosa Ziehau KKASSERT(ifp->if_cpuid >= 0 && ifp->if_cpuid < ncpus); 1411f85e0762SSepherosa Ziehau return 0; 1412f85e0762SSepherosa Ziehau fail: 1413f85e0762SSepherosa Ziehau ae_detach(dev); 1414f85e0762SSepherosa Ziehau return (error); 1415f85e0762SSepherosa Ziehau } 1416f85e0762SSepherosa Ziehau 1417f85e0762SSepherosa Ziehau static int 1418f85e0762SSepherosa Ziehau ae_detach(device_t dev) 1419f85e0762SSepherosa Ziehau { 1420f85e0762SSepherosa Ziehau struct ae_softc *sc = device_get_softc(dev); 1421f85e0762SSepherosa Ziehau 1422f85e0762SSepherosa Ziehau if (device_is_attached(dev)) { 1423f85e0762SSepherosa Ziehau struct ifnet *ifp = &sc->arpcom.ac_if; 1424f85e0762SSepherosa Ziehau 1425f85e0762SSepherosa Ziehau lwkt_serialize_enter(ifp->if_serializer); 1426f85e0762SSepherosa Ziehau sc->ae_flags |= AE_FLAG_DETACH; 1427f85e0762SSepherosa Ziehau ae_stop(sc); 1428f85e0762SSepherosa Ziehau bus_teardown_intr(dev, sc->ae_irq_res, sc->ae_irq_handle); 1429f85e0762SSepherosa Ziehau lwkt_serialize_exit(ifp->if_serializer); 1430f85e0762SSepherosa Ziehau 1431f85e0762SSepherosa Ziehau ether_ifdetach(ifp); 1432f85e0762SSepherosa Ziehau } 1433f85e0762SSepherosa Ziehau 1434f85e0762SSepherosa Ziehau if (sc->ae_miibus != NULL) 1435f85e0762SSepherosa Ziehau device_delete_child(dev, sc->ae_miibus); 1436f85e0762SSepherosa Ziehau bus_generic_detach(dev); 1437f85e0762SSepherosa Ziehau 1438f85e0762SSepherosa Ziehau if (sc->ae_irq_res != NULL) { 1439f85e0762SSepherosa Ziehau bus_release_resource(dev, SYS_RES_IRQ, sc->ae_irq_rid, 1440f85e0762SSepherosa Ziehau sc->ae_irq_res); 1441f85e0762SSepherosa Ziehau } 1442f85e0762SSepherosa Ziehau if (sc->ae_mem_res != NULL) { 1443f85e0762SSepherosa Ziehau bus_release_resource(dev, SYS_RES_MEMORY, sc->ae_mem_rid, 1444f85e0762SSepherosa Ziehau sc->ae_mem_res); 1445f85e0762SSepherosa Ziehau } 1446f85e0762SSepherosa Ziehau 1447f85e0762SSepherosa Ziehau if (sc->ae_sysctl_tree != NULL) 1448f85e0762SSepherosa Ziehau sysctl_ctx_free(&sc->ae_sysctl_ctx); 1449f85e0762SSepherosa Ziehau 1450f85e0762SSepherosa Ziehau ae_dma_free(sc); 1451f85e0762SSepherosa Ziehau 1452f85e0762SSepherosa Ziehau return (0); 1453f85e0762SSepherosa Ziehau } 1454f85e0762SSepherosa Ziehau 1455f85e0762SSepherosa Ziehau static void 1456f85e0762SSepherosa Ziehau ae_dma_free(struct ae_softc *sc) 1457f85e0762SSepherosa Ziehau { 1458f85e0762SSepherosa Ziehau if (sc->dma_txd_tag != NULL) { 1459f85e0762SSepherosa Ziehau bus_dmamap_unload(sc->dma_txd_tag, sc->dma_txd_map); 1460f85e0762SSepherosa Ziehau bus_dmamem_free(sc->dma_txd_tag, sc->txd_base, 1461f85e0762SSepherosa Ziehau sc->dma_txd_map); 1462f85e0762SSepherosa Ziehau bus_dma_tag_destroy(sc->dma_txd_tag); 1463f85e0762SSepherosa Ziehau } 1464f85e0762SSepherosa Ziehau if (sc->dma_txs_tag != NULL) { 1465f85e0762SSepherosa Ziehau bus_dmamap_unload(sc->dma_txs_tag, sc->dma_txs_map); 1466f85e0762SSepherosa Ziehau bus_dmamem_free(sc->dma_txs_tag, sc->txs_base, 1467f85e0762SSepherosa Ziehau sc->dma_txs_map); 1468f85e0762SSepherosa Ziehau bus_dma_tag_destroy(sc->dma_txs_tag); 1469f85e0762SSepherosa Ziehau } 1470f85e0762SSepherosa Ziehau if (sc->dma_rxd_tag != NULL) { 1471f85e0762SSepherosa Ziehau bus_dmamap_unload(sc->dma_rxd_tag, sc->dma_rxd_map); 1472f85e0762SSepherosa Ziehau bus_dmamem_free(sc->dma_rxd_tag, 1473f85e0762SSepherosa Ziehau sc->rxd_base_dma, sc->dma_rxd_map); 1474f85e0762SSepherosa Ziehau bus_dma_tag_destroy(sc->dma_rxd_tag); 1475f85e0762SSepherosa Ziehau } 1476f85e0762SSepherosa Ziehau if (sc->dma_parent_tag != NULL) 1477f85e0762SSepherosa Ziehau bus_dma_tag_destroy(sc->dma_parent_tag); 1478f85e0762SSepherosa Ziehau } 1479f85e0762SSepherosa Ziehau 1480f85e0762SSepherosa Ziehau static void 1481f85e0762SSepherosa Ziehau ae_pcie_init(struct ae_softc *sc) 1482f85e0762SSepherosa Ziehau { 1483f85e0762SSepherosa Ziehau AE_WRITE_4(sc, AE_PCIE_LTSSM_TESTMODE_REG, 1484f85e0762SSepherosa Ziehau AE_PCIE_LTSSM_TESTMODE_DEFAULT); 1485f85e0762SSepherosa Ziehau AE_WRITE_4(sc, AE_PCIE_DLL_TX_CTRL_REG, 1486f85e0762SSepherosa Ziehau AE_PCIE_DLL_TX_CTRL_DEFAULT); 1487f85e0762SSepherosa Ziehau } 1488f85e0762SSepherosa Ziehau 1489f85e0762SSepherosa Ziehau static void 1490f85e0762SSepherosa Ziehau ae_phy_reset(struct ae_softc *sc) 1491f85e0762SSepherosa Ziehau { 1492f85e0762SSepherosa Ziehau AE_WRITE_4(sc, AE_PHY_ENABLE_REG, AE_PHY_ENABLE); 1493f85e0762SSepherosa Ziehau DELAY(1000); /* XXX: pause(9) ? */ 1494f85e0762SSepherosa Ziehau } 1495f85e0762SSepherosa Ziehau 1496f85e0762SSepherosa Ziehau static int 1497f85e0762SSepherosa Ziehau ae_reset(struct ae_softc *sc) 1498f85e0762SSepherosa Ziehau { 1499f85e0762SSepherosa Ziehau int i; 1500f85e0762SSepherosa Ziehau 1501f85e0762SSepherosa Ziehau /* 1502f85e0762SSepherosa Ziehau * Issue a soft reset. 1503f85e0762SSepherosa Ziehau */ 1504f85e0762SSepherosa Ziehau AE_WRITE_4(sc, AE_MASTER_REG, AE_MASTER_SOFT_RESET); 1505f85e0762SSepherosa Ziehau bus_space_barrier(sc->ae_mem_bt, sc->ae_mem_bh, AE_MASTER_REG, 4, 1506f85e0762SSepherosa Ziehau BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE); 1507f85e0762SSepherosa Ziehau 1508f85e0762SSepherosa Ziehau /* 1509f85e0762SSepherosa Ziehau * Wait for reset to complete. 1510f85e0762SSepherosa Ziehau */ 1511f85e0762SSepherosa Ziehau for (i = 0; i < AE_RESET_TIMEOUT; i++) { 1512f85e0762SSepherosa Ziehau if ((AE_READ_4(sc, AE_MASTER_REG) & AE_MASTER_SOFT_RESET) == 0) 1513f85e0762SSepherosa Ziehau break; 1514f85e0762SSepherosa Ziehau DELAY(10); 1515f85e0762SSepherosa Ziehau } 1516f85e0762SSepherosa Ziehau if (i == AE_RESET_TIMEOUT) { 1517f85e0762SSepherosa Ziehau device_printf(sc->ae_dev, "reset timeout.\n"); 1518f85e0762SSepherosa Ziehau return (ENXIO); 1519f85e0762SSepherosa Ziehau } 1520f85e0762SSepherosa Ziehau 1521f85e0762SSepherosa Ziehau /* 1522f85e0762SSepherosa Ziehau * Wait for everything to enter idle state. 1523f85e0762SSepherosa Ziehau */ 1524f85e0762SSepherosa Ziehau for (i = 0; i < AE_IDLE_TIMEOUT; i++) { 1525f85e0762SSepherosa Ziehau if (AE_READ_4(sc, AE_IDLE_REG) == 0) 1526f85e0762SSepherosa Ziehau break; 1527f85e0762SSepherosa Ziehau DELAY(100); 1528f85e0762SSepherosa Ziehau } 1529f85e0762SSepherosa Ziehau if (i == AE_IDLE_TIMEOUT) { 1530f85e0762SSepherosa Ziehau device_printf(sc->ae_dev, "could not enter idle state.\n"); 1531f85e0762SSepherosa Ziehau return (ENXIO); 1532f85e0762SSepherosa Ziehau } 1533f85e0762SSepherosa Ziehau return (0); 1534f85e0762SSepherosa Ziehau } 1535f85e0762SSepherosa Ziehau 1536f85e0762SSepherosa Ziehau static int 1537f85e0762SSepherosa Ziehau ae_check_eeprom_present(struct ae_softc *sc, int *vpdc) 1538f85e0762SSepherosa Ziehau { 1539f85e0762SSepherosa Ziehau int error; 1540f85e0762SSepherosa Ziehau uint32_t val; 1541f85e0762SSepherosa Ziehau 1542f85e0762SSepherosa Ziehau /* 1543f85e0762SSepherosa Ziehau * Not sure why, but Linux does this. 1544f85e0762SSepherosa Ziehau */ 1545f85e0762SSepherosa Ziehau val = AE_READ_4(sc, AE_SPICTL_REG); 1546f85e0762SSepherosa Ziehau if ((val & AE_SPICTL_VPD_EN) != 0) { 1547f85e0762SSepherosa Ziehau val &= ~AE_SPICTL_VPD_EN; 1548f85e0762SSepherosa Ziehau AE_WRITE_4(sc, AE_SPICTL_REG, val); 1549f85e0762SSepherosa Ziehau } 1550f85e0762SSepherosa Ziehau error = pci_find_extcap(sc->ae_dev, PCIY_VPD, vpdc); 1551f85e0762SSepherosa Ziehau return (error); 1552f85e0762SSepherosa Ziehau } 1553f85e0762SSepherosa Ziehau 1554f85e0762SSepherosa Ziehau static int 1555f85e0762SSepherosa Ziehau ae_vpd_read_word(struct ae_softc *sc, int reg, uint32_t *word) 1556f85e0762SSepherosa Ziehau { 1557f85e0762SSepherosa Ziehau uint32_t val; 1558f85e0762SSepherosa Ziehau int i; 1559f85e0762SSepherosa Ziehau 1560f85e0762SSepherosa Ziehau AE_WRITE_4(sc, AE_VPD_DATA_REG, 0); /* Clear register value. */ 1561f85e0762SSepherosa Ziehau 1562f85e0762SSepherosa Ziehau /* 1563f85e0762SSepherosa Ziehau * VPD registers start at offset 0x100. Read them. 1564f85e0762SSepherosa Ziehau */ 1565f85e0762SSepherosa Ziehau val = 0x100 + reg * 4; 1566f85e0762SSepherosa Ziehau AE_WRITE_4(sc, AE_VPD_CAP_REG, (val << AE_VPD_CAP_ADDR_SHIFT) & 1567f85e0762SSepherosa Ziehau AE_VPD_CAP_ADDR_MASK); 1568f85e0762SSepherosa Ziehau for (i = 0; i < AE_VPD_TIMEOUT; i++) { 1569f85e0762SSepherosa Ziehau DELAY(2000); 1570f85e0762SSepherosa Ziehau val = AE_READ_4(sc, AE_VPD_CAP_REG); 1571f85e0762SSepherosa Ziehau if ((val & AE_VPD_CAP_DONE) != 0) 1572f85e0762SSepherosa Ziehau break; 1573f85e0762SSepherosa Ziehau } 1574f85e0762SSepherosa Ziehau if (i == AE_VPD_TIMEOUT) { 1575f85e0762SSepherosa Ziehau device_printf(sc->ae_dev, "timeout reading VPD register %d.\n", 1576f85e0762SSepherosa Ziehau reg); 1577f85e0762SSepherosa Ziehau return (ETIMEDOUT); 1578f85e0762SSepherosa Ziehau } 1579f85e0762SSepherosa Ziehau *word = AE_READ_4(sc, AE_VPD_DATA_REG); 1580f85e0762SSepherosa Ziehau return (0); 1581f85e0762SSepherosa Ziehau } 1582f85e0762SSepherosa Ziehau 1583f85e0762SSepherosa Ziehau static int 1584f85e0762SSepherosa Ziehau ae_get_vpd_eaddr(struct ae_softc *sc, uint32_t *eaddr) 1585f85e0762SSepherosa Ziehau { 1586f85e0762SSepherosa Ziehau uint32_t word, reg, val; 1587f85e0762SSepherosa Ziehau int error; 1588f85e0762SSepherosa Ziehau int found; 1589f85e0762SSepherosa Ziehau int vpdc; 1590f85e0762SSepherosa Ziehau int i; 1591f85e0762SSepherosa Ziehau 1592f85e0762SSepherosa Ziehau /* 1593f85e0762SSepherosa Ziehau * Check for EEPROM. 1594f85e0762SSepherosa Ziehau */ 1595f85e0762SSepherosa Ziehau error = ae_check_eeprom_present(sc, &vpdc); 1596f85e0762SSepherosa Ziehau if (error != 0) 1597f85e0762SSepherosa Ziehau return (error); 1598f85e0762SSepherosa Ziehau 1599f85e0762SSepherosa Ziehau /* 1600f85e0762SSepherosa Ziehau * Read the VPD configuration space. 1601f85e0762SSepherosa Ziehau * Each register is prefixed with signature, 1602f85e0762SSepherosa Ziehau * so we can check if it is valid. 1603f85e0762SSepherosa Ziehau */ 1604f85e0762SSepherosa Ziehau for (i = 0, found = 0; i < AE_VPD_NREGS; i++) { 1605f85e0762SSepherosa Ziehau error = ae_vpd_read_word(sc, i, &word); 1606f85e0762SSepherosa Ziehau if (error != 0) 1607f85e0762SSepherosa Ziehau break; 1608f85e0762SSepherosa Ziehau 1609f85e0762SSepherosa Ziehau /* 1610f85e0762SSepherosa Ziehau * Check signature. 1611f85e0762SSepherosa Ziehau */ 1612f85e0762SSepherosa Ziehau if ((word & AE_VPD_SIG_MASK) != AE_VPD_SIG) 1613f85e0762SSepherosa Ziehau break; 1614f85e0762SSepherosa Ziehau reg = word >> AE_VPD_REG_SHIFT; 1615f85e0762SSepherosa Ziehau i++; /* Move to the next word. */ 1616f85e0762SSepherosa Ziehau if (reg != AE_EADDR0_REG && reg != AE_EADDR1_REG) 1617f85e0762SSepherosa Ziehau continue; 1618f85e0762SSepherosa Ziehau 1619f85e0762SSepherosa Ziehau error = ae_vpd_read_word(sc, i, &val); 1620f85e0762SSepherosa Ziehau if (error != 0) 1621f85e0762SSepherosa Ziehau break; 1622f85e0762SSepherosa Ziehau if (reg == AE_EADDR0_REG) 1623f85e0762SSepherosa Ziehau eaddr[0] = val; 1624f85e0762SSepherosa Ziehau else 1625f85e0762SSepherosa Ziehau eaddr[1] = val; 1626f85e0762SSepherosa Ziehau found++; 1627f85e0762SSepherosa Ziehau } 1628f85e0762SSepherosa Ziehau if (found < 2) 1629f85e0762SSepherosa Ziehau return (ENOENT); 1630f85e0762SSepherosa Ziehau 1631f85e0762SSepherosa Ziehau eaddr[1] &= 0xffff; /* Only last 2 bytes are used. */ 1632f85e0762SSepherosa Ziehau if (AE_CHECK_EADDR_VALID(eaddr) != 0) { 1633f85e0762SSepherosa Ziehau if (bootverbose) 1634f85e0762SSepherosa Ziehau device_printf(sc->ae_dev, 1635f85e0762SSepherosa Ziehau "VPD ethernet address registers are invalid.\n"); 1636f85e0762SSepherosa Ziehau return (EINVAL); 1637f85e0762SSepherosa Ziehau } 1638f85e0762SSepherosa Ziehau return (0); 1639f85e0762SSepherosa Ziehau } 1640f85e0762SSepherosa Ziehau 1641f85e0762SSepherosa Ziehau static int 1642f85e0762SSepherosa Ziehau ae_get_reg_eaddr(struct ae_softc *sc, uint32_t *eaddr) 1643f85e0762SSepherosa Ziehau { 1644f85e0762SSepherosa Ziehau /* 1645f85e0762SSepherosa Ziehau * BIOS is supposed to set this. 1646f85e0762SSepherosa Ziehau */ 1647f85e0762SSepherosa Ziehau eaddr[0] = AE_READ_4(sc, AE_EADDR0_REG); 1648f85e0762SSepherosa Ziehau eaddr[1] = AE_READ_4(sc, AE_EADDR1_REG); 1649f85e0762SSepherosa Ziehau eaddr[1] &= 0xffff; /* Only last 2 bytes are used. */ 1650f85e0762SSepherosa Ziehau if (AE_CHECK_EADDR_VALID(eaddr) != 0) { 1651f85e0762SSepherosa Ziehau if (bootverbose) 1652f85e0762SSepherosa Ziehau device_printf(sc->ae_dev, 1653f85e0762SSepherosa Ziehau "Ethetnet address registers are invalid.\n"); 1654f85e0762SSepherosa Ziehau return (EINVAL); 1655f85e0762SSepherosa Ziehau } 1656f85e0762SSepherosa Ziehau return (0); 1657f85e0762SSepherosa Ziehau } 1658f85e0762SSepherosa Ziehau 1659f85e0762SSepherosa Ziehau static void 1660f85e0762SSepherosa Ziehau ae_get_eaddr(struct ae_softc *sc) 1661f85e0762SSepherosa Ziehau { 1662f85e0762SSepherosa Ziehau uint32_t eaddr[2] = {0, 0}; 1663f85e0762SSepherosa Ziehau int error; 1664f85e0762SSepherosa Ziehau 1665f85e0762SSepherosa Ziehau /* 1666f85e0762SSepherosa Ziehau *Check for EEPROM. 1667f85e0762SSepherosa Ziehau */ 1668f85e0762SSepherosa Ziehau error = ae_get_vpd_eaddr(sc, eaddr); 1669f85e0762SSepherosa Ziehau if (error) 1670f85e0762SSepherosa Ziehau error = ae_get_reg_eaddr(sc, eaddr); 1671f85e0762SSepherosa Ziehau if (error) { 1672f85e0762SSepherosa Ziehau if (bootverbose) 1673f85e0762SSepherosa Ziehau device_printf(sc->ae_dev, 1674f85e0762SSepherosa Ziehau "Generating random ethernet address.\n"); 1675f85e0762SSepherosa Ziehau eaddr[0] = karc4random(); 1676f85e0762SSepherosa Ziehau /* 1677f85e0762SSepherosa Ziehau * Set OUI to ASUSTek COMPUTER INC. 1678f85e0762SSepherosa Ziehau */ 1679f85e0762SSepherosa Ziehau sc->ae_eaddr[0] = 0x02; /* U/L bit set. */ 1680f85e0762SSepherosa Ziehau sc->ae_eaddr[1] = 0x1f; 1681f85e0762SSepherosa Ziehau sc->ae_eaddr[2] = 0xc6; 1682f85e0762SSepherosa Ziehau sc->ae_eaddr[3] = (eaddr[0] >> 16) & 0xff; 1683f85e0762SSepherosa Ziehau sc->ae_eaddr[4] = (eaddr[0] >> 8) & 0xff; 1684f85e0762SSepherosa Ziehau sc->ae_eaddr[5] = (eaddr[0] >> 0) & 0xff; 1685f85e0762SSepherosa Ziehau } else { 1686f85e0762SSepherosa Ziehau sc->ae_eaddr[0] = (eaddr[1] >> 8) & 0xff; 1687f85e0762SSepherosa Ziehau sc->ae_eaddr[1] = (eaddr[1] >> 0) & 0xff; 1688f85e0762SSepherosa Ziehau sc->ae_eaddr[2] = (eaddr[0] >> 24) & 0xff; 1689f85e0762SSepherosa Ziehau sc->ae_eaddr[3] = (eaddr[0] >> 16) & 0xff; 1690f85e0762SSepherosa Ziehau sc->ae_eaddr[4] = (eaddr[0] >> 8) & 0xff; 1691f85e0762SSepherosa Ziehau sc->ae_eaddr[5] = (eaddr[0] >> 0) & 0xff; 1692f85e0762SSepherosa Ziehau } 1693f85e0762SSepherosa Ziehau } 1694f85e0762SSepherosa Ziehau 1695f85e0762SSepherosa Ziehau static int 1696f85e0762SSepherosa Ziehau ae_mediachange(struct ifnet *ifp) 1697f85e0762SSepherosa Ziehau { 1698f85e0762SSepherosa Ziehau struct ae_softc *sc = ifp->if_softc; 1699f85e0762SSepherosa Ziehau struct mii_data *mii = device_get_softc(sc->ae_miibus); 1700f85e0762SSepherosa Ziehau int error; 1701f85e0762SSepherosa Ziehau 1702f85e0762SSepherosa Ziehau ASSERT_SERIALIZED(ifp->if_serializer); 1703f85e0762SSepherosa Ziehau if (mii->mii_instance != 0) { 1704f85e0762SSepherosa Ziehau struct mii_softc *miisc; 1705f85e0762SSepherosa Ziehau LIST_FOREACH(miisc, &mii->mii_phys, mii_list) 1706f85e0762SSepherosa Ziehau mii_phy_reset(miisc); 1707f85e0762SSepherosa Ziehau } 1708f85e0762SSepherosa Ziehau error = mii_mediachg(mii); 1709f85e0762SSepherosa Ziehau return (error); 1710f85e0762SSepherosa Ziehau } 1711f85e0762SSepherosa Ziehau 1712f85e0762SSepherosa Ziehau static void 1713f85e0762SSepherosa Ziehau ae_mediastatus(struct ifnet *ifp, struct ifmediareq *ifmr) 1714f85e0762SSepherosa Ziehau { 1715f85e0762SSepherosa Ziehau struct ae_softc *sc = ifp->if_softc; 1716f85e0762SSepherosa Ziehau struct mii_data *mii = device_get_softc(sc->ae_miibus); 1717f85e0762SSepherosa Ziehau 1718f85e0762SSepherosa Ziehau ASSERT_SERIALIZED(ifp->if_serializer); 1719f85e0762SSepherosa Ziehau mii_pollstat(mii); 1720f85e0762SSepherosa Ziehau ifmr->ifm_status = mii->mii_media_status; 1721f85e0762SSepherosa Ziehau ifmr->ifm_active = mii->mii_media_active; 1722f85e0762SSepherosa Ziehau } 1723f85e0762SSepherosa Ziehau 1724f85e0762SSepherosa Ziehau static void 1725f85e0762SSepherosa Ziehau ae_update_stats_tx(uint16_t flags, struct ae_stats *stats) 1726f85e0762SSepherosa Ziehau { 1727f85e0762SSepherosa Ziehau if ((flags & AE_TXS_BCAST) != 0) 1728f85e0762SSepherosa Ziehau stats->tx_bcast++; 1729f85e0762SSepherosa Ziehau if ((flags & AE_TXS_MCAST) != 0) 1730f85e0762SSepherosa Ziehau stats->tx_mcast++; 1731f85e0762SSepherosa Ziehau if ((flags & AE_TXS_PAUSE) != 0) 1732f85e0762SSepherosa Ziehau stats->tx_pause++; 1733f85e0762SSepherosa Ziehau if ((flags & AE_TXS_CTRL) != 0) 1734f85e0762SSepherosa Ziehau stats->tx_ctrl++; 1735f85e0762SSepherosa Ziehau if ((flags & AE_TXS_DEFER) != 0) 1736f85e0762SSepherosa Ziehau stats->tx_defer++; 1737f85e0762SSepherosa Ziehau if ((flags & AE_TXS_EXCDEFER) != 0) 1738f85e0762SSepherosa Ziehau stats->tx_excdefer++; 1739f85e0762SSepherosa Ziehau if ((flags & AE_TXS_SINGLECOL) != 0) 1740f85e0762SSepherosa Ziehau stats->tx_singlecol++; 1741f85e0762SSepherosa Ziehau if ((flags & AE_TXS_MULTICOL) != 0) 1742f85e0762SSepherosa Ziehau stats->tx_multicol++; 1743f85e0762SSepherosa Ziehau if ((flags & AE_TXS_LATECOL) != 0) 1744f85e0762SSepherosa Ziehau stats->tx_latecol++; 1745f85e0762SSepherosa Ziehau if ((flags & AE_TXS_ABORTCOL) != 0) 1746f85e0762SSepherosa Ziehau stats->tx_abortcol++; 1747f85e0762SSepherosa Ziehau if ((flags & AE_TXS_UNDERRUN) != 0) 1748f85e0762SSepherosa Ziehau stats->tx_underrun++; 1749f85e0762SSepherosa Ziehau } 1750f85e0762SSepherosa Ziehau 1751f85e0762SSepherosa Ziehau static void 1752f85e0762SSepherosa Ziehau ae_update_stats_rx(uint16_t flags, struct ae_stats *stats) 1753f85e0762SSepherosa Ziehau { 1754f85e0762SSepherosa Ziehau if ((flags & AE_RXD_BCAST) != 0) 1755f85e0762SSepherosa Ziehau stats->rx_bcast++; 1756f85e0762SSepherosa Ziehau if ((flags & AE_RXD_MCAST) != 0) 1757f85e0762SSepherosa Ziehau stats->rx_mcast++; 1758f85e0762SSepherosa Ziehau if ((flags & AE_RXD_PAUSE) != 0) 1759f85e0762SSepherosa Ziehau stats->rx_pause++; 1760f85e0762SSepherosa Ziehau if ((flags & AE_RXD_CTRL) != 0) 1761f85e0762SSepherosa Ziehau stats->rx_ctrl++; 1762f85e0762SSepherosa Ziehau if ((flags & AE_RXD_CRCERR) != 0) 1763f85e0762SSepherosa Ziehau stats->rx_crcerr++; 1764f85e0762SSepherosa Ziehau if ((flags & AE_RXD_CODEERR) != 0) 1765f85e0762SSepherosa Ziehau stats->rx_codeerr++; 1766f85e0762SSepherosa Ziehau if ((flags & AE_RXD_RUNT) != 0) 1767f85e0762SSepherosa Ziehau stats->rx_runt++; 1768f85e0762SSepherosa Ziehau if ((flags & AE_RXD_FRAG) != 0) 1769f85e0762SSepherosa Ziehau stats->rx_frag++; 1770f85e0762SSepherosa Ziehau if ((flags & AE_RXD_TRUNC) != 0) 1771f85e0762SSepherosa Ziehau stats->rx_trunc++; 1772f85e0762SSepherosa Ziehau if ((flags & AE_RXD_ALIGN) != 0) 1773f85e0762SSepherosa Ziehau stats->rx_align++; 1774f85e0762SSepherosa Ziehau } 1775f85e0762SSepherosa Ziehau 1776f85e0762SSepherosa Ziehau static int 1777f85e0762SSepherosa Ziehau ae_resume(device_t dev) 1778f85e0762SSepherosa Ziehau { 1779f85e0762SSepherosa Ziehau struct ae_softc *sc = device_get_softc(dev); 1780f85e0762SSepherosa Ziehau struct ifnet *ifp = &sc->arpcom.ac_if; 1781f85e0762SSepherosa Ziehau 1782f85e0762SSepherosa Ziehau lwkt_serialize_enter(ifp->if_serializer); 1783f85e0762SSepherosa Ziehau #if 0 1784f85e0762SSepherosa Ziehau AE_READ_4(sc, AE_WOL_REG); /* Clear WOL status. */ 1785f85e0762SSepherosa Ziehau #endif 178697c1b3a4SSepherosa Ziehau ae_phy_reset(sc); 1787f85e0762SSepherosa Ziehau if ((ifp->if_flags & IFF_UP) != 0) 1788f85e0762SSepherosa Ziehau ae_init(sc); 1789f85e0762SSepherosa Ziehau lwkt_serialize_exit(ifp->if_serializer); 1790f85e0762SSepherosa Ziehau return (0); 1791f85e0762SSepherosa Ziehau } 1792f85e0762SSepherosa Ziehau 1793f85e0762SSepherosa Ziehau static int 1794f85e0762SSepherosa Ziehau ae_suspend(device_t dev) 1795f85e0762SSepherosa Ziehau { 1796f85e0762SSepherosa Ziehau struct ae_softc *sc = device_get_softc(dev); 1797f85e0762SSepherosa Ziehau struct ifnet *ifp = &sc->arpcom.ac_if; 1798f85e0762SSepherosa Ziehau 1799f85e0762SSepherosa Ziehau lwkt_serialize_enter(ifp->if_serializer); 1800f85e0762SSepherosa Ziehau ae_stop(sc); 1801f85e0762SSepherosa Ziehau #if 0 1802f85e0762SSepherosa Ziehau /* we don't use ae_pm_init because we don't want WOL */ 1803f85e0762SSepherosa Ziehau ae_pm_init(sc); 1804f85e0762SSepherosa Ziehau #endif 1805f85e0762SSepherosa Ziehau lwkt_serialize_exit(ifp->if_serializer); 1806f85e0762SSepherosa Ziehau return (0); 1807f85e0762SSepherosa Ziehau } 1808f85e0762SSepherosa Ziehau 1809f85e0762SSepherosa Ziehau static int 1810f85e0762SSepherosa Ziehau ae_shutdown(device_t dev) 1811f85e0762SSepherosa Ziehau { 1812f85e0762SSepherosa Ziehau struct ae_softc *sc = device_get_softc(dev); 1813f85e0762SSepherosa Ziehau struct ifnet *ifp = &sc->arpcom.ac_if; 1814f85e0762SSepherosa Ziehau 1815f85e0762SSepherosa Ziehau ae_suspend(dev); 1816f85e0762SSepherosa Ziehau 1817f85e0762SSepherosa Ziehau lwkt_serialize_enter(ifp->if_serializer); 1818f85e0762SSepherosa Ziehau ae_powersave_enable(sc); 1819f85e0762SSepherosa Ziehau lwkt_serialize_exit(ifp->if_serializer); 1820f85e0762SSepherosa Ziehau 1821f85e0762SSepherosa Ziehau return (0); 1822f85e0762SSepherosa Ziehau } 1823f85e0762SSepherosa Ziehau 1824f85e0762SSepherosa Ziehau static void 1825f85e0762SSepherosa Ziehau ae_powersave_disable(struct ae_softc *sc) 1826f85e0762SSepherosa Ziehau { 1827f85e0762SSepherosa Ziehau uint32_t val; 1828f85e0762SSepherosa Ziehau 1829f85e0762SSepherosa Ziehau AE_PHY_WRITE(sc, AE_PHY_DBG_ADDR, 0); 1830f85e0762SSepherosa Ziehau val = AE_PHY_READ(sc, AE_PHY_DBG_DATA); 1831f85e0762SSepherosa Ziehau if (val & AE_PHY_DBG_POWERSAVE) { 1832f85e0762SSepherosa Ziehau val &= ~AE_PHY_DBG_POWERSAVE; 1833f85e0762SSepherosa Ziehau AE_PHY_WRITE(sc, AE_PHY_DBG_DATA, val); 1834f85e0762SSepherosa Ziehau DELAY(1000); 1835f85e0762SSepherosa Ziehau } 1836f85e0762SSepherosa Ziehau } 1837f85e0762SSepherosa Ziehau 1838f85e0762SSepherosa Ziehau static void 1839f85e0762SSepherosa Ziehau ae_powersave_enable(struct ae_softc *sc) 1840f85e0762SSepherosa Ziehau { 1841f85e0762SSepherosa Ziehau uint32_t val; 1842f85e0762SSepherosa Ziehau 1843f85e0762SSepherosa Ziehau /* 1844f85e0762SSepherosa Ziehau * XXX magic numbers. 1845f85e0762SSepherosa Ziehau */ 1846f85e0762SSepherosa Ziehau AE_PHY_WRITE(sc, AE_PHY_DBG_ADDR, 0); 1847f85e0762SSepherosa Ziehau val = AE_PHY_READ(sc, AE_PHY_DBG_DATA); 1848f85e0762SSepherosa Ziehau AE_PHY_WRITE(sc, AE_PHY_DBG_ADDR, val | 0x1000); 1849f85e0762SSepherosa Ziehau AE_PHY_WRITE(sc, AE_PHY_DBG_ADDR, 2); 1850f85e0762SSepherosa Ziehau AE_PHY_WRITE(sc, AE_PHY_DBG_DATA, 0x3000); 1851f85e0762SSepherosa Ziehau AE_PHY_WRITE(sc, AE_PHY_DBG_ADDR, 3); 1852f85e0762SSepherosa Ziehau AE_PHY_WRITE(sc, AE_PHY_DBG_DATA, 0); 1853f85e0762SSepherosa Ziehau } 1854