17902c8dcSWojciech Macek /*- 27902c8dcSWojciech Macek * Copyright (c) 2015,2016 Annapurna Labs Ltd. and affiliates 37902c8dcSWojciech Macek * All rights reserved. 47902c8dcSWojciech Macek * 57902c8dcSWojciech Macek * Developed by Semihalf. 67902c8dcSWojciech Macek * 77902c8dcSWojciech Macek * Redistribution and use in source and binary forms, with or without 87902c8dcSWojciech Macek * modification, are permitted provided that the following conditions 97902c8dcSWojciech Macek * are met: 107902c8dcSWojciech Macek * 1. Redistributions of source code must retain the above copyright 117902c8dcSWojciech Macek * notice, this list of conditions and the following disclaimer. 127902c8dcSWojciech Macek * 2. Redistributions in binary form must reproduce the above copyright 137902c8dcSWojciech Macek * notice, this list of conditions and the following disclaimer in the 147902c8dcSWojciech Macek * documentation and/or other materials provided with the distribution. 157902c8dcSWojciech Macek * 167902c8dcSWojciech Macek * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 177902c8dcSWojciech Macek * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 187902c8dcSWojciech Macek * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 197902c8dcSWojciech Macek * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 207902c8dcSWojciech Macek * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 217902c8dcSWojciech Macek * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 227902c8dcSWojciech Macek * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 237902c8dcSWojciech Macek * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 247902c8dcSWojciech Macek * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 257902c8dcSWojciech Macek * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 267902c8dcSWojciech Macek * SUCH DAMAGE. 277902c8dcSWojciech Macek */ 287902c8dcSWojciech Macek 297902c8dcSWojciech Macek #include <sys/param.h> 307902c8dcSWojciech Macek #include <sys/systm.h> 317902c8dcSWojciech Macek #include <sys/bus.h> 327902c8dcSWojciech Macek #include <sys/kernel.h> 337902c8dcSWojciech Macek #include <sys/kthread.h> 347902c8dcSWojciech Macek #include <sys/lock.h> 357902c8dcSWojciech Macek #include <sys/mbuf.h> 367902c8dcSWojciech Macek #include <sys/malloc.h> 377902c8dcSWojciech Macek #include <sys/module.h> 387902c8dcSWojciech Macek #include <sys/rman.h> 397902c8dcSWojciech Macek #include <sys/socket.h> 407902c8dcSWojciech Macek #include <sys/sockio.h> 417902c8dcSWojciech Macek #include <sys/sysctl.h> 427902c8dcSWojciech Macek #include <sys/taskqueue.h> 437902c8dcSWojciech Macek 447902c8dcSWojciech Macek #include <machine/atomic.h> 457902c8dcSWojciech Macek 467902c8dcSWojciech Macek #include "opt_inet.h" 477902c8dcSWojciech Macek #include "opt_inet6.h" 487902c8dcSWojciech Macek 497902c8dcSWojciech Macek #include <net/ethernet.h> 507902c8dcSWojciech Macek #include <net/if.h> 517902c8dcSWojciech Macek #include <net/if_var.h> 527902c8dcSWojciech Macek #include <net/if_arp.h> 537902c8dcSWojciech Macek #include <net/if_dl.h> 547902c8dcSWojciech Macek #include <net/if_media.h> 557902c8dcSWojciech Macek #include <net/if_types.h> 567902c8dcSWojciech Macek #include <netinet/in.h> 577902c8dcSWojciech Macek #include <net/if_vlan_var.h> 587902c8dcSWojciech Macek #include <netinet/tcp.h> 597902c8dcSWojciech Macek #include <netinet/tcp_lro.h> 607902c8dcSWojciech Macek 617902c8dcSWojciech Macek #ifdef INET 627902c8dcSWojciech Macek #include <netinet/in.h> 637902c8dcSWojciech Macek #include <netinet/in_systm.h> 647902c8dcSWojciech Macek #include <netinet/in_var.h> 657902c8dcSWojciech Macek #include <netinet/ip.h> 667902c8dcSWojciech Macek #endif 677902c8dcSWojciech Macek 687902c8dcSWojciech Macek #ifdef INET6 697902c8dcSWojciech Macek #include <netinet/ip6.h> 707902c8dcSWojciech Macek #endif 717902c8dcSWojciech Macek 727902c8dcSWojciech Macek #include <sys/sockio.h> 737902c8dcSWojciech Macek 747902c8dcSWojciech Macek #include <dev/pci/pcireg.h> 757902c8dcSWojciech Macek #include <dev/pci/pcivar.h> 767902c8dcSWojciech Macek 777902c8dcSWojciech Macek #include <dev/mii/mii.h> 787902c8dcSWojciech Macek #include <dev/mii/miivar.h> 797902c8dcSWojciech Macek 807902c8dcSWojciech Macek #include <al_hal_common.h> 817902c8dcSWojciech Macek #include <al_hal_plat_services.h> 827902c8dcSWojciech Macek #include <al_hal_udma_config.h> 837902c8dcSWojciech Macek #include <al_hal_udma_iofic.h> 847902c8dcSWojciech Macek #include <al_hal_udma_debug.h> 857902c8dcSWojciech Macek #include <al_hal_eth.h> 867902c8dcSWojciech Macek 877902c8dcSWojciech Macek #include "al_eth.h" 887902c8dcSWojciech Macek #include "al_init_eth_lm.h" 897902c8dcSWojciech Macek #include "arm/annapurna/alpine/alpine_serdes.h" 907902c8dcSWojciech Macek 917902c8dcSWojciech Macek #include "miibus_if.h" 927902c8dcSWojciech Macek 937902c8dcSWojciech Macek #define device_printf_dbg(fmt, ...) do { \ 947902c8dcSWojciech Macek if (AL_DBG_LEVEL >= AL_DBG_LEVEL_DBG) { AL_DBG_LOCK(); \ 957902c8dcSWojciech Macek device_printf(fmt, __VA_ARGS__); AL_DBG_UNLOCK();} \ 967902c8dcSWojciech Macek } while (0) 977902c8dcSWojciech Macek 987902c8dcSWojciech Macek MALLOC_DEFINE(M_IFAL, "if_al_malloc", "All allocated data for AL ETH driver"); 997902c8dcSWojciech Macek 1007902c8dcSWojciech Macek /* move out to some pci header file */ 1017902c8dcSWojciech Macek #define PCI_VENDOR_ID_ANNAPURNA_LABS 0x1c36 1027902c8dcSWojciech Macek #define PCI_DEVICE_ID_AL_ETH 0x0001 1037902c8dcSWojciech Macek #define PCI_DEVICE_ID_AL_ETH_ADVANCED 0x0002 1047902c8dcSWojciech Macek #define PCI_DEVICE_ID_AL_ETH_NIC 0x0003 1057902c8dcSWojciech Macek #define PCI_DEVICE_ID_AL_ETH_FPGA_NIC 0x0030 1067902c8dcSWojciech Macek #define PCI_DEVICE_ID_AL_CRYPTO 0x0011 1077902c8dcSWojciech Macek #define PCI_DEVICE_ID_AL_CRYPTO_VF 0x8011 1087902c8dcSWojciech Macek #define PCI_DEVICE_ID_AL_RAID_DMA 0x0021 1097902c8dcSWojciech Macek #define PCI_DEVICE_ID_AL_RAID_DMA_VF 0x8021 1107902c8dcSWojciech Macek #define PCI_DEVICE_ID_AL_USB 0x0041 1117902c8dcSWojciech Macek 1127902c8dcSWojciech Macek #define MAC_ADDR_STR "%02x:%02x:%02x:%02x:%02x:%02x" 1137902c8dcSWojciech Macek #define MAC_ADDR(addr) addr[0], addr[1], addr[2], addr[3], addr[4], addr[5] 1147902c8dcSWojciech Macek 1157902c8dcSWojciech Macek #define AL_ETH_MAC_TABLE_UNICAST_IDX_BASE 0 1167902c8dcSWojciech Macek #define AL_ETH_MAC_TABLE_UNICAST_MAX_COUNT 4 1177902c8dcSWojciech Macek #define AL_ETH_MAC_TABLE_ALL_MULTICAST_IDX (AL_ETH_MAC_TABLE_UNICAST_IDX_BASE + \ 1187902c8dcSWojciech Macek AL_ETH_MAC_TABLE_UNICAST_MAX_COUNT) 1197902c8dcSWojciech Macek 1207902c8dcSWojciech Macek #define AL_ETH_MAC_TABLE_DROP_IDX (AL_ETH_FWD_MAC_NUM - 1) 1217902c8dcSWojciech Macek #define AL_ETH_MAC_TABLE_BROADCAST_IDX (AL_ETH_MAC_TABLE_DROP_IDX - 1) 1227902c8dcSWojciech Macek 1237902c8dcSWojciech Macek #define AL_ETH_THASH_UDMA_SHIFT 0 1247902c8dcSWojciech Macek #define AL_ETH_THASH_UDMA_MASK (0xF << AL_ETH_THASH_UDMA_SHIFT) 1257902c8dcSWojciech Macek 1267902c8dcSWojciech Macek #define AL_ETH_THASH_Q_SHIFT 4 1277902c8dcSWojciech Macek #define AL_ETH_THASH_Q_MASK (0x3 << AL_ETH_THASH_Q_SHIFT) 1287902c8dcSWojciech Macek 1297902c8dcSWojciech Macek /* the following defines should be moved to hal */ 1307902c8dcSWojciech Macek #define AL_ETH_FSM_ENTRY_IPV4_TCP 0 1317902c8dcSWojciech Macek #define AL_ETH_FSM_ENTRY_IPV4_UDP 1 1327902c8dcSWojciech Macek #define AL_ETH_FSM_ENTRY_IPV6_TCP 2 1337902c8dcSWojciech Macek #define AL_ETH_FSM_ENTRY_IPV6_UDP 3 1347902c8dcSWojciech Macek #define AL_ETH_FSM_ENTRY_IPV6_NO_UDP_TCP 4 1357902c8dcSWojciech Macek #define AL_ETH_FSM_ENTRY_IPV4_NO_UDP_TCP 5 1367902c8dcSWojciech Macek 1377902c8dcSWojciech Macek /* FSM DATA format */ 1387902c8dcSWojciech Macek #define AL_ETH_FSM_DATA_OUTER_2_TUPLE 0 1397902c8dcSWojciech Macek #define AL_ETH_FSM_DATA_OUTER_4_TUPLE 1 1407902c8dcSWojciech Macek #define AL_ETH_FSM_DATA_INNER_2_TUPLE 2 1417902c8dcSWojciech Macek #define AL_ETH_FSM_DATA_INNER_4_TUPLE 3 1427902c8dcSWojciech Macek 1437902c8dcSWojciech Macek #define AL_ETH_FSM_DATA_HASH_SEL (1 << 2) 1447902c8dcSWojciech Macek 1457902c8dcSWojciech Macek #define AL_ETH_FSM_DATA_DEFAULT_Q 0 1467902c8dcSWojciech Macek #define AL_ETH_FSM_DATA_DEFAULT_UDMA 0 1477902c8dcSWojciech Macek 1487902c8dcSWojciech Macek #define AL_BR_SIZE 512 1497902c8dcSWojciech Macek #define AL_TSO_SIZE 65500 1507902c8dcSWojciech Macek #define AL_DEFAULT_MTU 1500 1517902c8dcSWojciech Macek 1527902c8dcSWojciech Macek #define CSUM_OFFLOAD (CSUM_IP|CSUM_TCP|CSUM_UDP|CSUM_SCTP) 1537902c8dcSWojciech Macek 1547902c8dcSWojciech Macek #define AL_IP_ALIGNMENT_OFFSET 2 1557902c8dcSWojciech Macek 1567902c8dcSWojciech Macek #define SFP_I2C_ADDR 0x50 1577902c8dcSWojciech Macek 1587902c8dcSWojciech Macek #define AL_MASK_GROUP_A_INT 0x7 1597902c8dcSWojciech Macek #define AL_MASK_GROUP_B_INT 0xF 1607902c8dcSWojciech Macek #define AL_MASK_GROUP_C_INT 0xF 1617902c8dcSWojciech Macek #define AL_MASK_GROUP_D_INT 0xFFFFFFFF 1627902c8dcSWojciech Macek 1637902c8dcSWojciech Macek #define AL_REG_OFFSET_FORWARD_INTR (0x1800000 + 0x1210) 1647902c8dcSWojciech Macek #define AL_EN_FORWARD_INTR 0x1FFFF 1657902c8dcSWojciech Macek #define AL_DIS_FORWARD_INTR 0 1667902c8dcSWojciech Macek 1677902c8dcSWojciech Macek #define AL_M2S_MASK_INIT 0x480 1687902c8dcSWojciech Macek #define AL_S2M_MASK_INIT 0x1E0 1697902c8dcSWojciech Macek #define AL_M2S_S2M_MASK_NOT_INT (0x3f << 25) 1707902c8dcSWojciech Macek 1717902c8dcSWojciech Macek #define AL_10BASE_T_SPEED 10 1727902c8dcSWojciech Macek #define AL_100BASE_TX_SPEED 100 1737902c8dcSWojciech Macek #define AL_1000BASE_T_SPEED 1000 1747902c8dcSWojciech Macek 1757902c8dcSWojciech Macek #define AL_RX_LOCK_INIT(_sc) mtx_init(&((_sc)->if_rx_lock), "ALRXL", "ALRXL", MTX_DEF) 1767902c8dcSWojciech Macek #define AL_RX_LOCK(_sc) mtx_lock(&((_sc)->if_rx_lock)) 1777902c8dcSWojciech Macek #define AL_RX_UNLOCK(_sc) mtx_unlock(&((_sc)->if_rx_lock)) 1787902c8dcSWojciech Macek 1797902c8dcSWojciech Macek /* helper functions */ 1807902c8dcSWojciech Macek static int al_is_device_supported(device_t); 1817902c8dcSWojciech Macek 1827902c8dcSWojciech Macek static void al_eth_init_rings(struct al_eth_adapter *); 1837902c8dcSWojciech Macek static void al_eth_flow_ctrl_disable(struct al_eth_adapter *); 1847902c8dcSWojciech Macek int al_eth_fpga_read_pci_config(void *, int, uint32_t *); 1857902c8dcSWojciech Macek int al_eth_fpga_write_pci_config(void *, int, uint32_t); 1867902c8dcSWojciech Macek int al_eth_read_pci_config(void *, int, uint32_t *); 1877902c8dcSWojciech Macek int al_eth_write_pci_config(void *, int, uint32_t); 1887902c8dcSWojciech Macek void al_eth_irq_config(uint32_t *, uint32_t); 1897902c8dcSWojciech Macek void al_eth_forward_int_config(uint32_t *, uint32_t); 1907902c8dcSWojciech Macek static void al_eth_start_xmit(void *, int); 1917902c8dcSWojciech Macek static void al_eth_rx_recv_work(void *, int); 1927902c8dcSWojciech Macek static int al_eth_up(struct al_eth_adapter *); 1937902c8dcSWojciech Macek static void al_eth_down(struct al_eth_adapter *); 1947902c8dcSWojciech Macek static void al_eth_interrupts_unmask(struct al_eth_adapter *); 1957902c8dcSWojciech Macek static void al_eth_interrupts_mask(struct al_eth_adapter *); 1967902c8dcSWojciech Macek static int al_eth_check_mtu(struct al_eth_adapter *, int); 197bc14c73bSJustin Hibbits static uint64_t al_get_counter(if_t, ift_counter); 1987902c8dcSWojciech Macek static void al_eth_req_rx_buff_size(struct al_eth_adapter *, int); 1997902c8dcSWojciech Macek static int al_eth_board_params_init(struct al_eth_adapter *); 200bc14c73bSJustin Hibbits static int al_media_update(if_t); 201bc14c73bSJustin Hibbits static void al_media_status(if_t, struct ifmediareq *); 2027902c8dcSWojciech Macek static int al_eth_function_reset(struct al_eth_adapter *); 2037902c8dcSWojciech Macek static int al_eth_hw_init_adapter(struct al_eth_adapter *); 2047902c8dcSWojciech Macek static void al_eth_serdes_init(struct al_eth_adapter *); 2057902c8dcSWojciech Macek static void al_eth_lm_config(struct al_eth_adapter *); 2067902c8dcSWojciech Macek static int al_eth_hw_init(struct al_eth_adapter *); 2077902c8dcSWojciech Macek 2087902c8dcSWojciech Macek static void al_tick_stats(void *); 2097902c8dcSWojciech Macek 2107902c8dcSWojciech Macek /* ifnet entry points */ 2117902c8dcSWojciech Macek static void al_init(void *); 212bc14c73bSJustin Hibbits static int al_mq_start(if_t, struct mbuf *); 213bc14c73bSJustin Hibbits static void al_qflush(if_t); 214bc14c73bSJustin Hibbits static int al_ioctl(if_t ifp, u_long, caddr_t); 2157902c8dcSWojciech Macek 2167902c8dcSWojciech Macek /* bus entry points */ 2177902c8dcSWojciech Macek static int al_probe(device_t); 2187902c8dcSWojciech Macek static int al_attach(device_t); 2197902c8dcSWojciech Macek static int al_detach(device_t); 2207902c8dcSWojciech Macek static int al_shutdown(device_t); 2217902c8dcSWojciech Macek 2227902c8dcSWojciech Macek /* mii bus support routines */ 2237902c8dcSWojciech Macek static int al_miibus_readreg(device_t, int, int); 2247902c8dcSWojciech Macek static int al_miibus_writereg(device_t, int, int, int); 2257902c8dcSWojciech Macek static void al_miibus_statchg(device_t); 2267902c8dcSWojciech Macek static void al_miibus_linkchg(device_t); 2277902c8dcSWojciech Macek 2287902c8dcSWojciech Macek struct al_eth_adapter* g_adapters[16]; 2297902c8dcSWojciech Macek uint32_t g_adapters_count; 2307902c8dcSWojciech Macek 2317902c8dcSWojciech Macek /* flag for napi-like mbuf processing, controlled from sysctl */ 2327902c8dcSWojciech Macek static int napi = 0; 2337902c8dcSWojciech Macek 2347902c8dcSWojciech Macek static device_method_t al_methods[] = { 2357902c8dcSWojciech Macek /* Device interface */ 2367902c8dcSWojciech Macek DEVMETHOD(device_probe, al_probe), 2377902c8dcSWojciech Macek DEVMETHOD(device_attach, al_attach), 2387902c8dcSWojciech Macek DEVMETHOD(device_detach, al_detach), 2397902c8dcSWojciech Macek DEVMETHOD(device_shutdown, al_shutdown), 2407902c8dcSWojciech Macek 2417902c8dcSWojciech Macek DEVMETHOD(miibus_readreg, al_miibus_readreg), 2427902c8dcSWojciech Macek DEVMETHOD(miibus_writereg, al_miibus_writereg), 2437902c8dcSWojciech Macek DEVMETHOD(miibus_statchg, al_miibus_statchg), 2447902c8dcSWojciech Macek DEVMETHOD(miibus_linkchg, al_miibus_linkchg), 2457902c8dcSWojciech Macek { 0, 0 } 2467902c8dcSWojciech Macek }; 2477902c8dcSWojciech Macek 2487902c8dcSWojciech Macek static driver_t al_driver = { 2497902c8dcSWojciech Macek "al", 2507902c8dcSWojciech Macek al_methods, 2517902c8dcSWojciech Macek sizeof(struct al_eth_adapter), 2527902c8dcSWojciech Macek }; 2537902c8dcSWojciech Macek 2546a9d865cSJohn Baldwin DRIVER_MODULE(al, pci, al_driver, 0, 0); 2553e38757dSJohn Baldwin DRIVER_MODULE(miibus, al, miibus_driver, 0, 0); 2567902c8dcSWojciech Macek 2577902c8dcSWojciech Macek static int 2587902c8dcSWojciech Macek al_probe(device_t dev) 2597902c8dcSWojciech Macek { 2607902c8dcSWojciech Macek if ((al_is_device_supported(dev)) != 0) { 2617902c8dcSWojciech Macek device_set_desc(dev, "al"); 2627902c8dcSWojciech Macek return (BUS_PROBE_DEFAULT); 2637902c8dcSWojciech Macek } 2647902c8dcSWojciech Macek return (ENXIO); 2657902c8dcSWojciech Macek } 2667902c8dcSWojciech Macek 2677902c8dcSWojciech Macek static int 2687902c8dcSWojciech Macek al_attach(device_t dev) 2697902c8dcSWojciech Macek { 2707902c8dcSWojciech Macek struct al_eth_adapter *adapter; 2717902c8dcSWojciech Macek struct sysctl_oid_list *child; 2727902c8dcSWojciech Macek struct sysctl_ctx_list *ctx; 2737902c8dcSWojciech Macek struct sysctl_oid *tree; 274bc14c73bSJustin Hibbits if_t ifp; 2757902c8dcSWojciech Macek uint32_t dev_id; 2767902c8dcSWojciech Macek uint32_t rev_id; 2777902c8dcSWojciech Macek int bar_udma; 2787902c8dcSWojciech Macek int bar_mac; 2797902c8dcSWojciech Macek int bar_ec; 2807902c8dcSWojciech Macek int err; 2817902c8dcSWojciech Macek 2827902c8dcSWojciech Macek err = 0; 2837902c8dcSWojciech Macek ifp = NULL; 2847902c8dcSWojciech Macek dev_id = rev_id = 0; 2857902c8dcSWojciech Macek ctx = device_get_sysctl_ctx(dev); 2867902c8dcSWojciech Macek tree = SYSCTL_PARENT(device_get_sysctl_tree(dev)); 2877902c8dcSWojciech Macek child = SYSCTL_CHILDREN(tree); 2887902c8dcSWojciech Macek 2897902c8dcSWojciech Macek if (g_adapters_count == 0) { 2907902c8dcSWojciech Macek SYSCTL_ADD_INT(ctx, child, OID_AUTO, "napi", 2917902c8dcSWojciech Macek CTLFLAG_RW, &napi, 0, "Use pseudo-napi mechanism"); 2927902c8dcSWojciech Macek } 2937902c8dcSWojciech Macek adapter = device_get_softc(dev); 2947902c8dcSWojciech Macek adapter->dev = dev; 2957902c8dcSWojciech Macek adapter->board_type = ALPINE_INTEGRATED; 2967902c8dcSWojciech Macek snprintf(adapter->name, AL_ETH_NAME_MAX_LEN, "%s", 2977902c8dcSWojciech Macek device_get_nameunit(dev)); 2987902c8dcSWojciech Macek AL_RX_LOCK_INIT(adapter); 2997902c8dcSWojciech Macek 3007902c8dcSWojciech Macek g_adapters[g_adapters_count] = adapter; 3017902c8dcSWojciech Macek 3027902c8dcSWojciech Macek bar_udma = PCIR_BAR(AL_ETH_UDMA_BAR); 3037902c8dcSWojciech Macek adapter->udma_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, 3047902c8dcSWojciech Macek &bar_udma, RF_ACTIVE); 3057902c8dcSWojciech Macek if (adapter->udma_res == NULL) { 3067902c8dcSWojciech Macek device_printf(adapter->dev, 3077902c8dcSWojciech Macek "could not allocate memory resources for DMA.\n"); 3087902c8dcSWojciech Macek err = ENOMEM; 3097902c8dcSWojciech Macek goto err_res_dma; 3107902c8dcSWojciech Macek } 3117902c8dcSWojciech Macek adapter->udma_base = al_bus_dma_to_va(rman_get_bustag(adapter->udma_res), 3127902c8dcSWojciech Macek rman_get_bushandle(adapter->udma_res)); 3137902c8dcSWojciech Macek bar_mac = PCIR_BAR(AL_ETH_MAC_BAR); 3147902c8dcSWojciech Macek adapter->mac_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, 3157902c8dcSWojciech Macek &bar_mac, RF_ACTIVE); 3167902c8dcSWojciech Macek if (adapter->mac_res == NULL) { 3177902c8dcSWojciech Macek device_printf(adapter->dev, 3187902c8dcSWojciech Macek "could not allocate memory resources for MAC.\n"); 3197902c8dcSWojciech Macek err = ENOMEM; 3207902c8dcSWojciech Macek goto err_res_mac; 3217902c8dcSWojciech Macek } 3227902c8dcSWojciech Macek adapter->mac_base = al_bus_dma_to_va(rman_get_bustag(adapter->mac_res), 3237902c8dcSWojciech Macek rman_get_bushandle(adapter->mac_res)); 3247902c8dcSWojciech Macek 3257902c8dcSWojciech Macek bar_ec = PCIR_BAR(AL_ETH_EC_BAR); 3267902c8dcSWojciech Macek adapter->ec_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &bar_ec, 3277902c8dcSWojciech Macek RF_ACTIVE); 3287902c8dcSWojciech Macek if (adapter->ec_res == NULL) { 3297902c8dcSWojciech Macek device_printf(adapter->dev, 3307902c8dcSWojciech Macek "could not allocate memory resources for EC.\n"); 3317902c8dcSWojciech Macek err = ENOMEM; 3327902c8dcSWojciech Macek goto err_res_ec; 3337902c8dcSWojciech Macek } 3347902c8dcSWojciech Macek adapter->ec_base = al_bus_dma_to_va(rman_get_bustag(adapter->ec_res), 3357902c8dcSWojciech Macek rman_get_bushandle(adapter->ec_res)); 3367902c8dcSWojciech Macek 3377902c8dcSWojciech Macek adapter->netdev = ifp = if_alloc(IFT_ETHER); 3387902c8dcSWojciech Macek 339bc14c73bSJustin Hibbits if_setsoftc(ifp, adapter); 3407902c8dcSWojciech Macek if_initname(ifp, device_get_name(dev), device_get_unit(dev)); 341bc14c73bSJustin Hibbits if_setdrvflagbits(ifp, 0, IFF_DRV_OACTIVE); 342bc14c73bSJustin Hibbits if_setflags(ifp, if_getdrvflags(ifp)); 343bc14c73bSJustin Hibbits if_setflagbits(ifp, IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST | IFF_ALLMULTI, 0); 344bc14c73bSJustin Hibbits if_settransmitfn(ifp, al_mq_start); 345bc14c73bSJustin Hibbits if_setqflushfn(ifp, al_qflush); 346bc14c73bSJustin Hibbits if_setioctlfn(ifp, al_ioctl); 347bc14c73bSJustin Hibbits if_setinitfn(ifp, al_init); 348bc14c73bSJustin Hibbits if_setgetcounterfn(ifp, al_get_counter); 349bc14c73bSJustin Hibbits if_setmtu(ifp, AL_DEFAULT_MTU); 3507902c8dcSWojciech Macek 351bc14c73bSJustin Hibbits adapter->if_flags = if_getflags(ifp); 3527902c8dcSWojciech Macek 353bc14c73bSJustin Hibbits if_setcapabilities(ifp, if_getcapenable(ifp) ); 3547902c8dcSWojciech Macek 355bc14c73bSJustin Hibbits if_setcapabilitiesbit(ifp, IFCAP_HWCSUM | 3567902c8dcSWojciech Macek IFCAP_HWCSUM_IPV6 | IFCAP_TSO | 357bc14c73bSJustin Hibbits IFCAP_LRO | IFCAP_JUMBO_MTU, 0); 3587902c8dcSWojciech Macek 359bc14c73bSJustin Hibbits if_setcapenable(ifp, if_getcapabilities(ifp)); 3607902c8dcSWojciech Macek 3617902c8dcSWojciech Macek adapter->id_number = g_adapters_count; 3627902c8dcSWojciech Macek 3637902c8dcSWojciech Macek if (adapter->board_type == ALPINE_INTEGRATED) { 3647902c8dcSWojciech Macek dev_id = pci_get_device(adapter->dev); 3657902c8dcSWojciech Macek rev_id = pci_get_revid(adapter->dev); 3667902c8dcSWojciech Macek } else { 3677902c8dcSWojciech Macek al_eth_fpga_read_pci_config(adapter->internal_pcie_base, 3687902c8dcSWojciech Macek PCIR_DEVICE, &dev_id); 3697902c8dcSWojciech Macek al_eth_fpga_read_pci_config(adapter->internal_pcie_base, 3707902c8dcSWojciech Macek PCIR_REVID, &rev_id); 3717902c8dcSWojciech Macek } 3727902c8dcSWojciech Macek 3737902c8dcSWojciech Macek adapter->dev_id = dev_id; 3747902c8dcSWojciech Macek adapter->rev_id = rev_id; 3757902c8dcSWojciech Macek 3767902c8dcSWojciech Macek /* set default ring sizes */ 3777902c8dcSWojciech Macek adapter->tx_ring_count = AL_ETH_DEFAULT_TX_SW_DESCS; 3787902c8dcSWojciech Macek adapter->tx_descs_count = AL_ETH_DEFAULT_TX_HW_DESCS; 3797902c8dcSWojciech Macek adapter->rx_ring_count = AL_ETH_DEFAULT_RX_DESCS; 3807902c8dcSWojciech Macek adapter->rx_descs_count = AL_ETH_DEFAULT_RX_DESCS; 3817902c8dcSWojciech Macek 3827902c8dcSWojciech Macek adapter->num_tx_queues = AL_ETH_NUM_QUEUES; 3837902c8dcSWojciech Macek adapter->num_rx_queues = AL_ETH_NUM_QUEUES; 3847902c8dcSWojciech Macek 3857902c8dcSWojciech Macek adapter->small_copy_len = AL_ETH_DEFAULT_SMALL_PACKET_LEN; 3867902c8dcSWojciech Macek adapter->link_poll_interval = AL_ETH_DEFAULT_LINK_POLL_INTERVAL; 3877902c8dcSWojciech Macek adapter->max_rx_buff_alloc_size = AL_ETH_DEFAULT_MAX_RX_BUFF_ALLOC_SIZE; 3887902c8dcSWojciech Macek 389f46a05b5SJustin Hibbits al_eth_req_rx_buff_size(adapter, if_getmtu(adapter->netdev)); 3907902c8dcSWojciech Macek 3917902c8dcSWojciech Macek adapter->link_config.force_1000_base_x = AL_ETH_DEFAULT_FORCE_1000_BASEX; 3927902c8dcSWojciech Macek 3937902c8dcSWojciech Macek err = al_eth_board_params_init(adapter); 3947902c8dcSWojciech Macek if (err != 0) 3957902c8dcSWojciech Macek goto err; 3967902c8dcSWojciech Macek 3977902c8dcSWojciech Macek if (adapter->mac_mode == AL_ETH_MAC_MODE_10GbE_Serial) { 3987902c8dcSWojciech Macek ifmedia_init(&adapter->media, IFM_IMASK, 3997902c8dcSWojciech Macek al_media_update, al_media_status); 4007902c8dcSWojciech Macek ifmedia_add(&adapter->media, IFM_ETHER | IFM_1000_LX, 0, NULL); 4017902c8dcSWojciech Macek ifmedia_add(&adapter->media, IFM_ETHER | IFM_10G_LR, 0, NULL); 4027902c8dcSWojciech Macek ifmedia_add(&adapter->media, IFM_ETHER | IFM_AUTO, 0, NULL); 4037902c8dcSWojciech Macek ifmedia_set(&adapter->media, IFM_ETHER | IFM_AUTO); 4047902c8dcSWojciech Macek } 4057902c8dcSWojciech Macek 4067902c8dcSWojciech Macek al_eth_function_reset(adapter); 4077902c8dcSWojciech Macek 4087902c8dcSWojciech Macek err = al_eth_hw_init_adapter(adapter); 4097902c8dcSWojciech Macek if (err != 0) 4107902c8dcSWojciech Macek goto err; 4117902c8dcSWojciech Macek 4127902c8dcSWojciech Macek al_eth_init_rings(adapter); 4137902c8dcSWojciech Macek g_adapters_count++; 4147902c8dcSWojciech Macek 4157902c8dcSWojciech Macek al_eth_lm_config(adapter); 4167902c8dcSWojciech Macek mtx_init(&adapter->stats_mtx, "AlStatsMtx", NULL, MTX_DEF); 4177902c8dcSWojciech Macek mtx_init(&adapter->wd_mtx, "AlWdMtx", NULL, MTX_DEF); 4187902c8dcSWojciech Macek callout_init_mtx(&adapter->stats_callout, &adapter->stats_mtx, 0); 4197902c8dcSWojciech Macek callout_init_mtx(&adapter->wd_callout, &adapter->wd_mtx, 0); 4207902c8dcSWojciech Macek 4217902c8dcSWojciech Macek ether_ifattach(ifp, adapter->mac_addr); 422bc14c73bSJustin Hibbits if_setmtu(ifp, AL_DEFAULT_MTU); 4237902c8dcSWojciech Macek 4247902c8dcSWojciech Macek if (adapter->mac_mode == AL_ETH_MAC_MODE_RGMII) { 4257902c8dcSWojciech Macek al_eth_hw_init(adapter); 4267902c8dcSWojciech Macek 4277902c8dcSWojciech Macek /* Attach PHY(s) */ 4287902c8dcSWojciech Macek err = mii_attach(adapter->dev, &adapter->miibus, adapter->netdev, 4297902c8dcSWojciech Macek al_media_update, al_media_status, BMSR_DEFCAPMASK, 0, 4307902c8dcSWojciech Macek MII_OFFSET_ANY, 0); 4317902c8dcSWojciech Macek if (err != 0) { 4327902c8dcSWojciech Macek device_printf(adapter->dev, "attaching PHYs failed\n"); 4337902c8dcSWojciech Macek return (err); 4347902c8dcSWojciech Macek } 4357902c8dcSWojciech Macek 4367902c8dcSWojciech Macek adapter->mii = device_get_softc(adapter->miibus); 4377902c8dcSWojciech Macek } 4387902c8dcSWojciech Macek 4397902c8dcSWojciech Macek return (err); 4407902c8dcSWojciech Macek 4417902c8dcSWojciech Macek err: 4427902c8dcSWojciech Macek bus_release_resource(dev, SYS_RES_MEMORY, bar_ec, adapter->ec_res); 4437902c8dcSWojciech Macek err_res_ec: 4447902c8dcSWojciech Macek bus_release_resource(dev, SYS_RES_MEMORY, bar_mac, adapter->mac_res); 4457902c8dcSWojciech Macek err_res_mac: 4467902c8dcSWojciech Macek bus_release_resource(dev, SYS_RES_MEMORY, bar_udma, adapter->udma_res); 4477902c8dcSWojciech Macek err_res_dma: 4487902c8dcSWojciech Macek return (err); 4497902c8dcSWojciech Macek } 4507902c8dcSWojciech Macek 4517902c8dcSWojciech Macek static int 4527902c8dcSWojciech Macek al_detach(device_t dev) 4537902c8dcSWojciech Macek { 4547902c8dcSWojciech Macek struct al_eth_adapter *adapter; 4557902c8dcSWojciech Macek 4567902c8dcSWojciech Macek adapter = device_get_softc(dev); 4577902c8dcSWojciech Macek ether_ifdetach(adapter->netdev); 4587902c8dcSWojciech Macek 4597902c8dcSWojciech Macek mtx_destroy(&adapter->stats_mtx); 4607902c8dcSWojciech Macek mtx_destroy(&adapter->wd_mtx); 4617902c8dcSWojciech Macek 4627902c8dcSWojciech Macek al_eth_down(adapter); 4637902c8dcSWojciech Macek 4647902c8dcSWojciech Macek bus_release_resource(dev, SYS_RES_IRQ, 0, adapter->irq_res); 4657902c8dcSWojciech Macek bus_release_resource(dev, SYS_RES_MEMORY, 0, adapter->ec_res); 4667902c8dcSWojciech Macek bus_release_resource(dev, SYS_RES_MEMORY, 0, adapter->mac_res); 4677902c8dcSWojciech Macek bus_release_resource(dev, SYS_RES_MEMORY, 0, adapter->udma_res); 4687902c8dcSWojciech Macek 4697902c8dcSWojciech Macek return (0); 4707902c8dcSWojciech Macek } 4717902c8dcSWojciech Macek 4727902c8dcSWojciech Macek int 4737902c8dcSWojciech Macek al_eth_fpga_read_pci_config(void *handle, int where, uint32_t *val) 4747902c8dcSWojciech Macek { 4757902c8dcSWojciech Macek 4767902c8dcSWojciech Macek /* handle is the base address of the adapter */ 4777902c8dcSWojciech Macek *val = al_reg_read32((void*)((u_long)handle + where)); 4787902c8dcSWojciech Macek 4797902c8dcSWojciech Macek return (0); 4807902c8dcSWojciech Macek } 4817902c8dcSWojciech Macek 4827902c8dcSWojciech Macek int 4837902c8dcSWojciech Macek al_eth_fpga_write_pci_config(void *handle, int where, uint32_t val) 4847902c8dcSWojciech Macek { 4857902c8dcSWojciech Macek 4867902c8dcSWojciech Macek /* handle is the base address of the adapter */ 4877902c8dcSWojciech Macek al_reg_write32((void*)((u_long)handle + where), val); 4887902c8dcSWojciech Macek return (0); 4897902c8dcSWojciech Macek } 4907902c8dcSWojciech Macek 4917902c8dcSWojciech Macek int 4927902c8dcSWojciech Macek al_eth_read_pci_config(void *handle, int where, uint32_t *val) 4937902c8dcSWojciech Macek { 4947902c8dcSWojciech Macek 4957902c8dcSWojciech Macek /* handle is a pci_dev */ 4967902c8dcSWojciech Macek *val = pci_read_config((device_t)handle, where, sizeof(*val)); 4977902c8dcSWojciech Macek return (0); 4987902c8dcSWojciech Macek } 4997902c8dcSWojciech Macek 5007902c8dcSWojciech Macek int 5017902c8dcSWojciech Macek al_eth_write_pci_config(void *handle, int where, uint32_t val) 5027902c8dcSWojciech Macek { 5037902c8dcSWojciech Macek 5047902c8dcSWojciech Macek /* handle is a pci_dev */ 5057902c8dcSWojciech Macek pci_write_config((device_t)handle, where, val, sizeof(val)); 5067902c8dcSWojciech Macek return (0); 5077902c8dcSWojciech Macek } 5087902c8dcSWojciech Macek 5097902c8dcSWojciech Macek void 5107902c8dcSWojciech Macek al_eth_irq_config(uint32_t *offset, uint32_t value) 5117902c8dcSWojciech Macek { 5127902c8dcSWojciech Macek 5137902c8dcSWojciech Macek al_reg_write32_relaxed(offset, value); 5147902c8dcSWojciech Macek } 5157902c8dcSWojciech Macek 5167902c8dcSWojciech Macek void 5177902c8dcSWojciech Macek al_eth_forward_int_config(uint32_t *offset, uint32_t value) 5187902c8dcSWojciech Macek { 5197902c8dcSWojciech Macek 5207902c8dcSWojciech Macek al_reg_write32(offset, value); 5217902c8dcSWojciech Macek } 5227902c8dcSWojciech Macek 5237902c8dcSWojciech Macek static void 5247902c8dcSWojciech Macek al_eth_serdes_init(struct al_eth_adapter *adapter) 5257902c8dcSWojciech Macek { 5267902c8dcSWojciech Macek void __iomem *serdes_base; 5277902c8dcSWojciech Macek 5287902c8dcSWojciech Macek adapter->serdes_init = false; 5297902c8dcSWojciech Macek 5307902c8dcSWojciech Macek serdes_base = alpine_serdes_resource_get(adapter->serdes_grp); 5317902c8dcSWojciech Macek if (serdes_base == NULL) { 5327902c8dcSWojciech Macek device_printf(adapter->dev, "serdes_base get failed!\n"); 5337902c8dcSWojciech Macek return; 5347902c8dcSWojciech Macek } 5357902c8dcSWojciech Macek 5367902c8dcSWojciech Macek serdes_base = al_bus_dma_to_va(serdes_tag, serdes_base); 5377902c8dcSWojciech Macek 5387902c8dcSWojciech Macek al_serdes_handle_grp_init(serdes_base, adapter->serdes_grp, 5397902c8dcSWojciech Macek &adapter->serdes_obj); 5407902c8dcSWojciech Macek 5417902c8dcSWojciech Macek adapter->serdes_init = true; 5427902c8dcSWojciech Macek } 5437902c8dcSWojciech Macek 5447902c8dcSWojciech Macek static void 5457902c8dcSWojciech Macek al_dma_map_addr(void *arg, bus_dma_segment_t *segs, int nseg, int error) 5467902c8dcSWojciech Macek { 5477902c8dcSWojciech Macek bus_addr_t *paddr; 5487902c8dcSWojciech Macek 5497902c8dcSWojciech Macek paddr = arg; 5507902c8dcSWojciech Macek *paddr = segs->ds_addr; 5517902c8dcSWojciech Macek } 5527902c8dcSWojciech Macek 5537902c8dcSWojciech Macek static int 554d8b1601dSMark Johnston al_dma_alloc_coherent(device_t dev, bus_dma_tag_t *tag, bus_dmamap_t *map, 5557902c8dcSWojciech Macek bus_addr_t *baddr, void **vaddr, uint32_t size) 5567902c8dcSWojciech Macek { 5577902c8dcSWojciech Macek int ret; 5587902c8dcSWojciech Macek uint32_t maxsize = ((size - 1)/PAGE_SIZE + 1) * PAGE_SIZE; 5597902c8dcSWojciech Macek 5607902c8dcSWojciech Macek ret = bus_dma_tag_create(bus_get_dma_tag(dev), 8, 0, 5617902c8dcSWojciech Macek BUS_SPACE_MAXADDR, BUS_SPACE_MAXADDR, NULL, NULL, 5627902c8dcSWojciech Macek maxsize, 1, maxsize, BUS_DMA_COHERENT, NULL, NULL, tag); 5637902c8dcSWojciech Macek if (ret != 0) { 5647902c8dcSWojciech Macek device_printf(dev, 5657902c8dcSWojciech Macek "failed to create bus tag, ret = %d\n", ret); 5667902c8dcSWojciech Macek return (ret); 5677902c8dcSWojciech Macek } 5687902c8dcSWojciech Macek 5697902c8dcSWojciech Macek ret = bus_dmamem_alloc(*tag, vaddr, 5707902c8dcSWojciech Macek BUS_DMA_COHERENT | BUS_DMA_ZERO, map); 5717902c8dcSWojciech Macek if (ret != 0) { 5727902c8dcSWojciech Macek device_printf(dev, 5737902c8dcSWojciech Macek "failed to allocate dmamem, ret = %d\n", ret); 5747902c8dcSWojciech Macek return (ret); 5757902c8dcSWojciech Macek } 5767902c8dcSWojciech Macek 5777902c8dcSWojciech Macek ret = bus_dmamap_load(*tag, *map, *vaddr, 5787902c8dcSWojciech Macek size, al_dma_map_addr, baddr, 0); 5797902c8dcSWojciech Macek if (ret != 0) { 5807902c8dcSWojciech Macek device_printf(dev, 5817902c8dcSWojciech Macek "failed to allocate bus_dmamap_load, ret = %d\n", ret); 5827902c8dcSWojciech Macek return (ret); 5837902c8dcSWojciech Macek } 5847902c8dcSWojciech Macek 5857902c8dcSWojciech Macek return (0); 5867902c8dcSWojciech Macek } 5877902c8dcSWojciech Macek 5887902c8dcSWojciech Macek static void 5897902c8dcSWojciech Macek al_dma_free_coherent(bus_dma_tag_t tag, bus_dmamap_t map, void *vaddr) 5907902c8dcSWojciech Macek { 5917902c8dcSWojciech Macek 5927902c8dcSWojciech Macek bus_dmamap_unload(tag, map); 5937902c8dcSWojciech Macek bus_dmamem_free(tag, vaddr, map); 5947902c8dcSWojciech Macek bus_dma_tag_destroy(tag); 5957902c8dcSWojciech Macek } 5967902c8dcSWojciech Macek 5977902c8dcSWojciech Macek static void 5987902c8dcSWojciech Macek al_eth_mac_table_unicast_add(struct al_eth_adapter *adapter, 59957d36163SGleb Smirnoff uint8_t idx, uint8_t udma_mask) 6007902c8dcSWojciech Macek { 6017902c8dcSWojciech Macek struct al_eth_fwd_mac_table_entry entry = { { 0 } }; 6027902c8dcSWojciech Macek 6037902c8dcSWojciech Macek memcpy(entry.addr, adapter->mac_addr, sizeof(adapter->mac_addr)); 6047902c8dcSWojciech Macek 6057902c8dcSWojciech Macek memset(entry.mask, 0xff, sizeof(entry.mask)); 6067902c8dcSWojciech Macek entry.rx_valid = true; 6077902c8dcSWojciech Macek entry.tx_valid = false; 6087902c8dcSWojciech Macek entry.udma_mask = udma_mask; 6097902c8dcSWojciech Macek entry.filter = false; 6107902c8dcSWojciech Macek 6117902c8dcSWojciech Macek device_printf_dbg(adapter->dev, 6127902c8dcSWojciech Macek "%s: [%d]: addr "MAC_ADDR_STR" mask "MAC_ADDR_STR"\n", 6137902c8dcSWojciech Macek __func__, idx, MAC_ADDR(entry.addr), MAC_ADDR(entry.mask)); 6147902c8dcSWojciech Macek 6157902c8dcSWojciech Macek al_eth_fwd_mac_table_set(&adapter->hal_adapter, idx, &entry); 6167902c8dcSWojciech Macek } 6177902c8dcSWojciech Macek 6187902c8dcSWojciech Macek static void 6197902c8dcSWojciech Macek al_eth_mac_table_all_multicast_add(struct al_eth_adapter *adapter, uint8_t idx, 6207902c8dcSWojciech Macek uint8_t udma_mask) 6217902c8dcSWojciech Macek { 6227902c8dcSWojciech Macek struct al_eth_fwd_mac_table_entry entry = { { 0 } }; 6237902c8dcSWojciech Macek 6247902c8dcSWojciech Macek memset(entry.addr, 0x00, sizeof(entry.addr)); 6257902c8dcSWojciech Macek memset(entry.mask, 0x00, sizeof(entry.mask)); 6267902c8dcSWojciech Macek entry.mask[0] |= 1; 6277902c8dcSWojciech Macek entry.addr[0] |= 1; 6287902c8dcSWojciech Macek 6297902c8dcSWojciech Macek entry.rx_valid = true; 6307902c8dcSWojciech Macek entry.tx_valid = false; 6317902c8dcSWojciech Macek entry.udma_mask = udma_mask; 6327902c8dcSWojciech Macek entry.filter = false; 6337902c8dcSWojciech Macek 6347902c8dcSWojciech Macek device_printf_dbg(adapter->dev, 6357902c8dcSWojciech Macek "%s: [%d]: addr "MAC_ADDR_STR" mask "MAC_ADDR_STR"\n", 6367902c8dcSWojciech Macek __func__, idx, MAC_ADDR(entry.addr), MAC_ADDR(entry.mask)); 6377902c8dcSWojciech Macek 6387902c8dcSWojciech Macek al_eth_fwd_mac_table_set(&adapter->hal_adapter, idx, &entry); 6397902c8dcSWojciech Macek } 6407902c8dcSWojciech Macek 6417902c8dcSWojciech Macek static void 6427902c8dcSWojciech Macek al_eth_mac_table_broadcast_add(struct al_eth_adapter *adapter, 6437902c8dcSWojciech Macek uint8_t idx, uint8_t udma_mask) 6447902c8dcSWojciech Macek { 6457902c8dcSWojciech Macek struct al_eth_fwd_mac_table_entry entry = { { 0 } }; 6467902c8dcSWojciech Macek 6477902c8dcSWojciech Macek memset(entry.addr, 0xff, sizeof(entry.addr)); 6487902c8dcSWojciech Macek memset(entry.mask, 0xff, sizeof(entry.mask)); 6497902c8dcSWojciech Macek 6507902c8dcSWojciech Macek entry.rx_valid = true; 6517902c8dcSWojciech Macek entry.tx_valid = false; 6527902c8dcSWojciech Macek entry.udma_mask = udma_mask; 6537902c8dcSWojciech Macek entry.filter = false; 6547902c8dcSWojciech Macek 6557902c8dcSWojciech Macek device_printf_dbg(adapter->dev, 6567902c8dcSWojciech Macek "%s: [%d]: addr "MAC_ADDR_STR" mask "MAC_ADDR_STR"\n", 6577902c8dcSWojciech Macek __func__, idx, MAC_ADDR(entry.addr), MAC_ADDR(entry.mask)); 6587902c8dcSWojciech Macek 6597902c8dcSWojciech Macek al_eth_fwd_mac_table_set(&adapter->hal_adapter, idx, &entry); 6607902c8dcSWojciech Macek } 6617902c8dcSWojciech Macek 6627902c8dcSWojciech Macek static void 6637902c8dcSWojciech Macek al_eth_mac_table_promiscuous_set(struct al_eth_adapter *adapter, 664463edaf4SJohn Baldwin bool promiscuous) 6657902c8dcSWojciech Macek { 6667902c8dcSWojciech Macek struct al_eth_fwd_mac_table_entry entry = { { 0 } }; 6677902c8dcSWojciech Macek 6687902c8dcSWojciech Macek memset(entry.addr, 0x00, sizeof(entry.addr)); 6697902c8dcSWojciech Macek memset(entry.mask, 0x00, sizeof(entry.mask)); 6707902c8dcSWojciech Macek 6717902c8dcSWojciech Macek entry.rx_valid = true; 6727902c8dcSWojciech Macek entry.tx_valid = false; 6737902c8dcSWojciech Macek entry.udma_mask = (promiscuous) ? 1 : 0; 6747902c8dcSWojciech Macek entry.filter = (promiscuous) ? false : true; 6757902c8dcSWojciech Macek 6767902c8dcSWojciech Macek device_printf_dbg(adapter->dev, "%s: %s promiscuous mode\n", 6777902c8dcSWojciech Macek __func__, (promiscuous) ? "enter" : "exit"); 6787902c8dcSWojciech Macek 6797902c8dcSWojciech Macek al_eth_fwd_mac_table_set(&adapter->hal_adapter, 6807902c8dcSWojciech Macek AL_ETH_MAC_TABLE_DROP_IDX, &entry); 6817902c8dcSWojciech Macek } 6827902c8dcSWojciech Macek 6837902c8dcSWojciech Macek static void 6847902c8dcSWojciech Macek al_eth_set_thash_table_entry(struct al_eth_adapter *adapter, uint8_t idx, 6857902c8dcSWojciech Macek uint8_t udma, uint32_t queue) 6867902c8dcSWojciech Macek { 6877902c8dcSWojciech Macek 6887902c8dcSWojciech Macek if (udma != 0) 6897902c8dcSWojciech Macek panic("only UDMA0 is supporter"); 6907902c8dcSWojciech Macek 6917902c8dcSWojciech Macek if (queue >= AL_ETH_NUM_QUEUES) 6927902c8dcSWojciech Macek panic("invalid queue number"); 6937902c8dcSWojciech Macek 6947902c8dcSWojciech Macek al_eth_thash_table_set(&adapter->hal_adapter, idx, udma, queue); 6957902c8dcSWojciech Macek } 6967902c8dcSWojciech Macek 6977902c8dcSWojciech Macek /* init FSM, no tunneling supported yet, if packet is tcp/udp over ipv4/ipv6, use 4 tuple hash */ 6987902c8dcSWojciech Macek static void 6997902c8dcSWojciech Macek al_eth_fsm_table_init(struct al_eth_adapter *adapter) 7007902c8dcSWojciech Macek { 7017902c8dcSWojciech Macek uint32_t val; 7027902c8dcSWojciech Macek int i; 7037902c8dcSWojciech Macek 7047902c8dcSWojciech Macek for (i = 0; i < AL_ETH_RX_FSM_TABLE_SIZE; i++) { 7057902c8dcSWojciech Macek uint8_t outer_type = AL_ETH_FSM_ENTRY_OUTER(i); 7067902c8dcSWojciech Macek switch (outer_type) { 7077902c8dcSWojciech Macek case AL_ETH_FSM_ENTRY_IPV4_TCP: 7087902c8dcSWojciech Macek case AL_ETH_FSM_ENTRY_IPV4_UDP: 7097902c8dcSWojciech Macek case AL_ETH_FSM_ENTRY_IPV6_TCP: 7107902c8dcSWojciech Macek case AL_ETH_FSM_ENTRY_IPV6_UDP: 7117902c8dcSWojciech Macek val = AL_ETH_FSM_DATA_OUTER_4_TUPLE | 7127902c8dcSWojciech Macek AL_ETH_FSM_DATA_HASH_SEL; 7137902c8dcSWojciech Macek break; 7147902c8dcSWojciech Macek case AL_ETH_FSM_ENTRY_IPV6_NO_UDP_TCP: 7157902c8dcSWojciech Macek case AL_ETH_FSM_ENTRY_IPV4_NO_UDP_TCP: 7167902c8dcSWojciech Macek val = AL_ETH_FSM_DATA_OUTER_2_TUPLE | 7177902c8dcSWojciech Macek AL_ETH_FSM_DATA_HASH_SEL; 7187902c8dcSWojciech Macek break; 7197902c8dcSWojciech Macek default: 7207902c8dcSWojciech Macek val = AL_ETH_FSM_DATA_DEFAULT_Q | 7217902c8dcSWojciech Macek AL_ETH_FSM_DATA_DEFAULT_UDMA; 7227902c8dcSWojciech Macek } 7237902c8dcSWojciech Macek al_eth_fsm_table_set(&adapter->hal_adapter, i, val); 7247902c8dcSWojciech Macek } 7257902c8dcSWojciech Macek } 7267902c8dcSWojciech Macek 7277902c8dcSWojciech Macek static void 7287902c8dcSWojciech Macek al_eth_mac_table_entry_clear(struct al_eth_adapter *adapter, 7297902c8dcSWojciech Macek uint8_t idx) 7307902c8dcSWojciech Macek { 7317902c8dcSWojciech Macek struct al_eth_fwd_mac_table_entry entry = { { 0 } }; 7327902c8dcSWojciech Macek 7337902c8dcSWojciech Macek device_printf_dbg(adapter->dev, "%s: clear entry %d\n", __func__, idx); 7347902c8dcSWojciech Macek 7357902c8dcSWojciech Macek al_eth_fwd_mac_table_set(&adapter->hal_adapter, idx, &entry); 7367902c8dcSWojciech Macek } 7377902c8dcSWojciech Macek 7387902c8dcSWojciech Macek static int 7397902c8dcSWojciech Macek al_eth_hw_init_adapter(struct al_eth_adapter *adapter) 7407902c8dcSWojciech Macek { 7417902c8dcSWojciech Macek struct al_eth_adapter_params *params = &adapter->eth_hal_params; 7427902c8dcSWojciech Macek int rc; 7437902c8dcSWojciech Macek 7447902c8dcSWojciech Macek /* params->dev_id = adapter->dev_id; */ 7457902c8dcSWojciech Macek params->rev_id = adapter->rev_id; 7467902c8dcSWojciech Macek params->udma_id = 0; 7477902c8dcSWojciech Macek params->enable_rx_parser = 1; /* enable rx epe parser*/ 7487902c8dcSWojciech Macek params->udma_regs_base = adapter->udma_base; /* UDMA register base address */ 7497902c8dcSWojciech Macek params->ec_regs_base = adapter->ec_base; /* Ethernet controller registers base address */ 7507902c8dcSWojciech Macek params->mac_regs_base = adapter->mac_base; /* Ethernet MAC registers base address */ 7517902c8dcSWojciech Macek params->name = adapter->name; 7527902c8dcSWojciech Macek params->serdes_lane = adapter->serdes_lane; 7537902c8dcSWojciech Macek 7547902c8dcSWojciech Macek rc = al_eth_adapter_init(&adapter->hal_adapter, params); 7557902c8dcSWojciech Macek if (rc != 0) 7567902c8dcSWojciech Macek device_printf(adapter->dev, "%s failed at hal init!\n", 7577902c8dcSWojciech Macek __func__); 7587902c8dcSWojciech Macek 7597902c8dcSWojciech Macek if ((adapter->board_type == ALPINE_NIC) || 7607902c8dcSWojciech Macek (adapter->board_type == ALPINE_FPGA_NIC)) { 7617902c8dcSWojciech Macek /* in pcie NIC mode, force eth UDMA to access PCIE0 using the vmid */ 7627902c8dcSWojciech Macek struct al_udma_gen_tgtid_conf conf; 7637902c8dcSWojciech Macek int i; 7647902c8dcSWojciech Macek for (i = 0; i < DMA_MAX_Q; i++) { 7657902c8dcSWojciech Macek conf.tx_q_conf[i].queue_en = AL_TRUE; 7667902c8dcSWojciech Macek conf.tx_q_conf[i].desc_en = AL_FALSE; 7677902c8dcSWojciech Macek conf.tx_q_conf[i].tgtid = 0x100; /* for access from PCIE0 */ 7687902c8dcSWojciech Macek conf.rx_q_conf[i].queue_en = AL_TRUE; 7697902c8dcSWojciech Macek conf.rx_q_conf[i].desc_en = AL_FALSE; 7707902c8dcSWojciech Macek conf.rx_q_conf[i].tgtid = 0x100; /* for access from PCIE0 */ 7717902c8dcSWojciech Macek } 7727902c8dcSWojciech Macek al_udma_gen_tgtid_conf_set(adapter->udma_base, &conf); 7737902c8dcSWojciech Macek } 7747902c8dcSWojciech Macek 7757902c8dcSWojciech Macek return (rc); 7767902c8dcSWojciech Macek } 7777902c8dcSWojciech Macek 7787902c8dcSWojciech Macek static void 7797902c8dcSWojciech Macek al_eth_lm_config(struct al_eth_adapter *adapter) 7807902c8dcSWojciech Macek { 7817902c8dcSWojciech Macek struct al_eth_lm_init_params params = {0}; 7827902c8dcSWojciech Macek 7837902c8dcSWojciech Macek params.adapter = &adapter->hal_adapter; 7847902c8dcSWojciech Macek params.serdes_obj = &adapter->serdes_obj; 7857902c8dcSWojciech Macek params.lane = adapter->serdes_lane; 7867902c8dcSWojciech Macek params.sfp_detection = adapter->sfp_detection_needed; 7877902c8dcSWojciech Macek if (adapter->sfp_detection_needed == true) { 7887902c8dcSWojciech Macek params.sfp_bus_id = adapter->i2c_adapter_id; 7897902c8dcSWojciech Macek params.sfp_i2c_addr = SFP_I2C_ADDR; 7907902c8dcSWojciech Macek } 7917902c8dcSWojciech Macek 7927902c8dcSWojciech Macek if (adapter->sfp_detection_needed == false) { 7937902c8dcSWojciech Macek switch (adapter->mac_mode) { 7947902c8dcSWojciech Macek case AL_ETH_MAC_MODE_10GbE_Serial: 7957902c8dcSWojciech Macek if ((adapter->lt_en != 0) && (adapter->an_en != 0)) 7967902c8dcSWojciech Macek params.default_mode = AL_ETH_LM_MODE_10G_DA; 7977902c8dcSWojciech Macek else 7987902c8dcSWojciech Macek params.default_mode = AL_ETH_LM_MODE_10G_OPTIC; 7997902c8dcSWojciech Macek break; 8007902c8dcSWojciech Macek case AL_ETH_MAC_MODE_SGMII: 8017902c8dcSWojciech Macek params.default_mode = AL_ETH_LM_MODE_1G; 8027902c8dcSWojciech Macek break; 8037902c8dcSWojciech Macek default: 8047902c8dcSWojciech Macek params.default_mode = AL_ETH_LM_MODE_10G_DA; 8057902c8dcSWojciech Macek } 8067902c8dcSWojciech Macek } else 8077902c8dcSWojciech Macek params.default_mode = AL_ETH_LM_MODE_10G_DA; 8087902c8dcSWojciech Macek 8097902c8dcSWojciech Macek params.link_training = adapter->lt_en; 8107902c8dcSWojciech Macek params.rx_equal = true; 8117902c8dcSWojciech Macek params.static_values = !adapter->dont_override_serdes; 8127902c8dcSWojciech Macek params.i2c_context = adapter; 8137902c8dcSWojciech Macek params.kr_fec_enable = false; 8147902c8dcSWojciech Macek 8157902c8dcSWojciech Macek params.retimer_exist = adapter->retimer.exist; 8167902c8dcSWojciech Macek params.retimer_bus_id = adapter->retimer.bus_id; 8177902c8dcSWojciech Macek params.retimer_i2c_addr = adapter->retimer.i2c_addr; 8187902c8dcSWojciech Macek params.retimer_channel = adapter->retimer.channel; 8197902c8dcSWojciech Macek 8207902c8dcSWojciech Macek al_eth_lm_init(&adapter->lm_context, ¶ms); 8217902c8dcSWojciech Macek } 8227902c8dcSWojciech Macek 8237902c8dcSWojciech Macek static int 8247902c8dcSWojciech Macek al_eth_board_params_init(struct al_eth_adapter *adapter) 8257902c8dcSWojciech Macek { 8267902c8dcSWojciech Macek 8277902c8dcSWojciech Macek if (adapter->board_type == ALPINE_NIC) { 8287902c8dcSWojciech Macek adapter->mac_mode = AL_ETH_MAC_MODE_10GbE_Serial; 8297902c8dcSWojciech Macek adapter->sfp_detection_needed = false; 8307902c8dcSWojciech Macek adapter->phy_exist = false; 8317902c8dcSWojciech Macek adapter->an_en = false; 8327902c8dcSWojciech Macek adapter->lt_en = false; 8337902c8dcSWojciech Macek adapter->ref_clk_freq = AL_ETH_REF_FREQ_375_MHZ; 8347902c8dcSWojciech Macek adapter->mdio_freq = AL_ETH_DEFAULT_MDIO_FREQ_KHZ; 8357902c8dcSWojciech Macek } else if (adapter->board_type == ALPINE_FPGA_NIC) { 8367902c8dcSWojciech Macek adapter->mac_mode = AL_ETH_MAC_MODE_SGMII; 8377902c8dcSWojciech Macek adapter->sfp_detection_needed = false; 8387902c8dcSWojciech Macek adapter->phy_exist = false; 8397902c8dcSWojciech Macek adapter->an_en = false; 8407902c8dcSWojciech Macek adapter->lt_en = false; 8417902c8dcSWojciech Macek adapter->ref_clk_freq = AL_ETH_REF_FREQ_375_MHZ; 8427902c8dcSWojciech Macek adapter->mdio_freq = AL_ETH_DEFAULT_MDIO_FREQ_KHZ; 8437902c8dcSWojciech Macek } else { 8447902c8dcSWojciech Macek struct al_eth_board_params params; 8457902c8dcSWojciech Macek int rc; 8467902c8dcSWojciech Macek 8477902c8dcSWojciech Macek adapter->auto_speed = false; 8487902c8dcSWojciech Macek 8497902c8dcSWojciech Macek rc = al_eth_board_params_get(adapter->mac_base, ¶ms); 8507902c8dcSWojciech Macek if (rc != 0) { 8517902c8dcSWojciech Macek device_printf(adapter->dev, 8527902c8dcSWojciech Macek "board info not available\n"); 8537902c8dcSWojciech Macek return (-1); 8547902c8dcSWojciech Macek } 8557902c8dcSWojciech Macek 856463edaf4SJohn Baldwin adapter->phy_exist = params.phy_exist == true; 8577902c8dcSWojciech Macek adapter->phy_addr = params.phy_mdio_addr; 8587902c8dcSWojciech Macek adapter->an_en = params.autoneg_enable; 8597902c8dcSWojciech Macek adapter->lt_en = params.kr_lt_enable; 8607902c8dcSWojciech Macek adapter->serdes_grp = params.serdes_grp; 8617902c8dcSWojciech Macek adapter->serdes_lane = params.serdes_lane; 8627902c8dcSWojciech Macek adapter->sfp_detection_needed = params.sfp_plus_module_exist; 8637902c8dcSWojciech Macek adapter->i2c_adapter_id = params.i2c_adapter_id; 8647902c8dcSWojciech Macek adapter->ref_clk_freq = params.ref_clk_freq; 8657902c8dcSWojciech Macek adapter->dont_override_serdes = params.dont_override_serdes; 8667902c8dcSWojciech Macek adapter->link_config.active_duplex = !params.half_duplex; 8677902c8dcSWojciech Macek adapter->link_config.autoneg = !params.an_disable; 8687902c8dcSWojciech Macek adapter->link_config.force_1000_base_x = params.force_1000_base_x; 8697902c8dcSWojciech Macek adapter->retimer.exist = params.retimer_exist; 8707902c8dcSWojciech Macek adapter->retimer.bus_id = params.retimer_bus_id; 8717902c8dcSWojciech Macek adapter->retimer.i2c_addr = params.retimer_i2c_addr; 8727902c8dcSWojciech Macek adapter->retimer.channel = params.retimer_channel; 8737902c8dcSWojciech Macek 8747902c8dcSWojciech Macek switch (params.speed) { 8757902c8dcSWojciech Macek default: 8767902c8dcSWojciech Macek device_printf(adapter->dev, 8777902c8dcSWojciech Macek "%s: invalid speed (%d)\n", __func__, params.speed); 8787902c8dcSWojciech Macek case AL_ETH_BOARD_1G_SPEED_1000M: 8797902c8dcSWojciech Macek adapter->link_config.active_speed = 1000; 8807902c8dcSWojciech Macek break; 8817902c8dcSWojciech Macek case AL_ETH_BOARD_1G_SPEED_100M: 8827902c8dcSWojciech Macek adapter->link_config.active_speed = 100; 8837902c8dcSWojciech Macek break; 8847902c8dcSWojciech Macek case AL_ETH_BOARD_1G_SPEED_10M: 8857902c8dcSWojciech Macek adapter->link_config.active_speed = 10; 8867902c8dcSWojciech Macek break; 8877902c8dcSWojciech Macek } 8887902c8dcSWojciech Macek 8897902c8dcSWojciech Macek switch (params.mdio_freq) { 8907902c8dcSWojciech Macek default: 8917902c8dcSWojciech Macek device_printf(adapter->dev, 8927902c8dcSWojciech Macek "%s: invalid mdio freq (%d)\n", __func__, 8937902c8dcSWojciech Macek params.mdio_freq); 8947902c8dcSWojciech Macek case AL_ETH_BOARD_MDIO_FREQ_2_5_MHZ: 8957902c8dcSWojciech Macek adapter->mdio_freq = AL_ETH_DEFAULT_MDIO_FREQ_KHZ; 8967902c8dcSWojciech Macek break; 8977902c8dcSWojciech Macek case AL_ETH_BOARD_MDIO_FREQ_1_MHZ: 8987902c8dcSWojciech Macek adapter->mdio_freq = AL_ETH_MDIO_FREQ_1000_KHZ; 8997902c8dcSWojciech Macek break; 9007902c8dcSWojciech Macek } 9017902c8dcSWojciech Macek 9027902c8dcSWojciech Macek switch (params.media_type) { 9037902c8dcSWojciech Macek case AL_ETH_BOARD_MEDIA_TYPE_RGMII: 904463edaf4SJohn Baldwin if (params.sfp_plus_module_exist == true) 9057902c8dcSWojciech Macek /* Backward compatibility */ 9067902c8dcSWojciech Macek adapter->mac_mode = AL_ETH_MAC_MODE_SGMII; 9077902c8dcSWojciech Macek else 9087902c8dcSWojciech Macek adapter->mac_mode = AL_ETH_MAC_MODE_RGMII; 9097902c8dcSWojciech Macek 9107902c8dcSWojciech Macek adapter->use_lm = false; 9117902c8dcSWojciech Macek break; 9127902c8dcSWojciech Macek case AL_ETH_BOARD_MEDIA_TYPE_SGMII: 9137902c8dcSWojciech Macek adapter->mac_mode = AL_ETH_MAC_MODE_SGMII; 9147902c8dcSWojciech Macek adapter->use_lm = true; 9157902c8dcSWojciech Macek break; 9167902c8dcSWojciech Macek case AL_ETH_BOARD_MEDIA_TYPE_10GBASE_SR: 9177902c8dcSWojciech Macek adapter->mac_mode = AL_ETH_MAC_MODE_10GbE_Serial; 9187902c8dcSWojciech Macek adapter->use_lm = true; 9197902c8dcSWojciech Macek break; 9207902c8dcSWojciech Macek case AL_ETH_BOARD_MEDIA_TYPE_AUTO_DETECT: 921463edaf4SJohn Baldwin adapter->sfp_detection_needed = true; 9227902c8dcSWojciech Macek adapter->auto_speed = false; 9237902c8dcSWojciech Macek adapter->use_lm = true; 9247902c8dcSWojciech Macek break; 9257902c8dcSWojciech Macek case AL_ETH_BOARD_MEDIA_TYPE_AUTO_DETECT_AUTO_SPEED: 926463edaf4SJohn Baldwin adapter->sfp_detection_needed = true; 9277902c8dcSWojciech Macek adapter->auto_speed = true; 9287902c8dcSWojciech Macek adapter->mac_mode_set = false; 9297902c8dcSWojciech Macek adapter->use_lm = true; 9307902c8dcSWojciech Macek 9317902c8dcSWojciech Macek adapter->mac_mode = AL_ETH_MAC_MODE_10GbE_Serial; 9327902c8dcSWojciech Macek break; 9337902c8dcSWojciech Macek default: 9347902c8dcSWojciech Macek device_printf(adapter->dev, 9357902c8dcSWojciech Macek "%s: unsupported media type %d\n", 9367902c8dcSWojciech Macek __func__, params.media_type); 9377902c8dcSWojciech Macek return (-1); 9387902c8dcSWojciech Macek } 9397902c8dcSWojciech Macek 9407902c8dcSWojciech Macek device_printf(adapter->dev, 9417902c8dcSWojciech Macek "Board info: phy exist %s. phy addr %d. mdio freq %u Khz. " 9427902c8dcSWojciech Macek "SFP connected %s. media %d\n", 943463edaf4SJohn Baldwin params.phy_exist ? "Yes" : "No", 9447902c8dcSWojciech Macek params.phy_mdio_addr, adapter->mdio_freq, 945463edaf4SJohn Baldwin params.sfp_plus_module_exist ? "Yes" : "No", 9467902c8dcSWojciech Macek params.media_type); 9477902c8dcSWojciech Macek } 9487902c8dcSWojciech Macek 9497902c8dcSWojciech Macek al_eth_mac_addr_read(adapter->ec_base, 0, adapter->mac_addr); 9507902c8dcSWojciech Macek 9517902c8dcSWojciech Macek return (0); 9527902c8dcSWojciech Macek } 9537902c8dcSWojciech Macek 9547902c8dcSWojciech Macek static int 9557902c8dcSWojciech Macek al_eth_function_reset(struct al_eth_adapter *adapter) 9567902c8dcSWojciech Macek { 9577902c8dcSWojciech Macek struct al_eth_board_params params; 9587902c8dcSWojciech Macek int rc; 9597902c8dcSWojciech Macek 9607902c8dcSWojciech Macek /* save board params so we restore it after reset */ 9617902c8dcSWojciech Macek al_eth_board_params_get(adapter->mac_base, ¶ms); 9627902c8dcSWojciech Macek al_eth_mac_addr_read(adapter->ec_base, 0, adapter->mac_addr); 9637902c8dcSWojciech Macek if (adapter->board_type == ALPINE_INTEGRATED) 9647902c8dcSWojciech Macek rc = al_eth_flr_rmn(&al_eth_read_pci_config, 9657902c8dcSWojciech Macek &al_eth_write_pci_config, 9667902c8dcSWojciech Macek adapter->dev, adapter->mac_base); 9677902c8dcSWojciech Macek else 9687902c8dcSWojciech Macek rc = al_eth_flr_rmn(&al_eth_fpga_read_pci_config, 9697902c8dcSWojciech Macek &al_eth_fpga_write_pci_config, 9707902c8dcSWojciech Macek adapter->internal_pcie_base, adapter->mac_base); 9717902c8dcSWojciech Macek 9727902c8dcSWojciech Macek /* restore params */ 9737902c8dcSWojciech Macek al_eth_board_params_set(adapter->mac_base, ¶ms); 9747902c8dcSWojciech Macek al_eth_mac_addr_store(adapter->ec_base, 0, adapter->mac_addr); 9757902c8dcSWojciech Macek 9767902c8dcSWojciech Macek return (rc); 9777902c8dcSWojciech Macek } 9787902c8dcSWojciech Macek 9797902c8dcSWojciech Macek static void 9807902c8dcSWojciech Macek al_eth_init_rings(struct al_eth_adapter *adapter) 9817902c8dcSWojciech Macek { 9827902c8dcSWojciech Macek int i; 9837902c8dcSWojciech Macek 9847902c8dcSWojciech Macek for (i = 0; i < adapter->num_tx_queues; i++) { 9857902c8dcSWojciech Macek struct al_eth_ring *ring = &adapter->tx_ring[i]; 9867902c8dcSWojciech Macek 9877902c8dcSWojciech Macek ring->ring_id = i; 9887902c8dcSWojciech Macek ring->dev = adapter->dev; 9897902c8dcSWojciech Macek ring->adapter = adapter; 9907902c8dcSWojciech Macek ring->netdev = adapter->netdev; 9917902c8dcSWojciech Macek al_udma_q_handle_get(&adapter->hal_adapter.tx_udma, i, 9927902c8dcSWojciech Macek &ring->dma_q); 9937902c8dcSWojciech Macek ring->sw_count = adapter->tx_ring_count; 9947902c8dcSWojciech Macek ring->hw_count = adapter->tx_descs_count; 9957902c8dcSWojciech Macek ring->unmask_reg_offset = al_udma_iofic_unmask_offset_get((struct unit_regs *)adapter->udma_base, AL_UDMA_IOFIC_LEVEL_PRIMARY, AL_INT_GROUP_C); 9967902c8dcSWojciech Macek ring->unmask_val = ~(1 << i); 9977902c8dcSWojciech Macek } 9987902c8dcSWojciech Macek 9997902c8dcSWojciech Macek for (i = 0; i < adapter->num_rx_queues; i++) { 10007902c8dcSWojciech Macek struct al_eth_ring *ring = &adapter->rx_ring[i]; 10017902c8dcSWojciech Macek 10027902c8dcSWojciech Macek ring->ring_id = i; 10037902c8dcSWojciech Macek ring->dev = adapter->dev; 10047902c8dcSWojciech Macek ring->adapter = adapter; 10057902c8dcSWojciech Macek ring->netdev = adapter->netdev; 10067902c8dcSWojciech Macek al_udma_q_handle_get(&adapter->hal_adapter.rx_udma, i, &ring->dma_q); 10077902c8dcSWojciech Macek ring->sw_count = adapter->rx_ring_count; 10087902c8dcSWojciech Macek ring->hw_count = adapter->rx_descs_count; 10097902c8dcSWojciech Macek ring->unmask_reg_offset = al_udma_iofic_unmask_offset_get( 10107902c8dcSWojciech Macek (struct unit_regs *)adapter->udma_base, 10117902c8dcSWojciech Macek AL_UDMA_IOFIC_LEVEL_PRIMARY, AL_INT_GROUP_B); 10127902c8dcSWojciech Macek ring->unmask_val = ~(1 << i); 10137902c8dcSWojciech Macek } 10147902c8dcSWojciech Macek } 10157902c8dcSWojciech Macek 10167902c8dcSWojciech Macek static void 10177902c8dcSWojciech Macek al_init_locked(void *arg) 10187902c8dcSWojciech Macek { 10197902c8dcSWojciech Macek struct al_eth_adapter *adapter = arg; 10207902c8dcSWojciech Macek if_t ifp = adapter->netdev; 10217902c8dcSWojciech Macek int rc = 0; 10227902c8dcSWojciech Macek 10237902c8dcSWojciech Macek al_eth_down(adapter); 10247902c8dcSWojciech Macek rc = al_eth_up(adapter); 10257902c8dcSWojciech Macek 1026bc14c73bSJustin Hibbits if_setdrvflagbits(ifp, 0, IFF_DRV_OACTIVE); 10277902c8dcSWojciech Macek if (rc == 0) 1028bc14c73bSJustin Hibbits if_setdrvflagbits(ifp, IFF_DRV_RUNNING, 0); 10297902c8dcSWojciech Macek } 10307902c8dcSWojciech Macek 10317902c8dcSWojciech Macek static void 10327902c8dcSWojciech Macek al_init(void *arg) 10337902c8dcSWojciech Macek { 10347902c8dcSWojciech Macek struct al_eth_adapter *adapter = arg; 10357902c8dcSWojciech Macek 10367902c8dcSWojciech Macek al_init_locked(adapter); 10377902c8dcSWojciech Macek } 10387902c8dcSWojciech Macek 10397902c8dcSWojciech Macek static inline int 10407902c8dcSWojciech Macek al_eth_alloc_rx_buf(struct al_eth_adapter *adapter, 10417902c8dcSWojciech Macek struct al_eth_ring *rx_ring, 10427902c8dcSWojciech Macek struct al_eth_rx_buffer *rx_info) 10437902c8dcSWojciech Macek { 10447902c8dcSWojciech Macek struct al_buf *al_buf; 10457902c8dcSWojciech Macek bus_dma_segment_t segs[2]; 10467902c8dcSWojciech Macek int error; 10477902c8dcSWojciech Macek int nsegs; 10487902c8dcSWojciech Macek 10497902c8dcSWojciech Macek if (rx_info->m != NULL) 10507902c8dcSWojciech Macek return (0); 10517902c8dcSWojciech Macek 10527902c8dcSWojciech Macek rx_info->data_size = adapter->rx_mbuf_sz; 10537902c8dcSWojciech Macek 10547902c8dcSWojciech Macek AL_RX_LOCK(adapter); 10557902c8dcSWojciech Macek 10567902c8dcSWojciech Macek /* Get mbuf using UMA allocator */ 10577902c8dcSWojciech Macek rx_info->m = m_getjcl(M_NOWAIT, MT_DATA, M_PKTHDR, 10587902c8dcSWojciech Macek rx_info->data_size); 10597902c8dcSWojciech Macek AL_RX_UNLOCK(adapter); 10607902c8dcSWojciech Macek 10617902c8dcSWojciech Macek if (rx_info->m == NULL) 10627902c8dcSWojciech Macek return (ENOMEM); 10637902c8dcSWojciech Macek 10647902c8dcSWojciech Macek rx_info->m->m_pkthdr.len = rx_info->m->m_len = adapter->rx_mbuf_sz; 10657902c8dcSWojciech Macek 10667902c8dcSWojciech Macek /* Map packets for DMA */ 10677902c8dcSWojciech Macek error = bus_dmamap_load_mbuf_sg(rx_ring->dma_buf_tag, rx_info->dma_map, 10687902c8dcSWojciech Macek rx_info->m, segs, &nsegs, BUS_DMA_NOWAIT); 10697902c8dcSWojciech Macek if (__predict_false(error)) { 10707902c8dcSWojciech Macek device_printf(rx_ring->dev, "failed to map mbuf, error = %d\n", 10717902c8dcSWojciech Macek error); 10727902c8dcSWojciech Macek m_freem(rx_info->m); 10737902c8dcSWojciech Macek rx_info->m = NULL; 10747902c8dcSWojciech Macek return (EFAULT); 10757902c8dcSWojciech Macek } 10767902c8dcSWojciech Macek 10777902c8dcSWojciech Macek al_buf = &rx_info->al_buf; 10787902c8dcSWojciech Macek al_buf->addr = segs[0].ds_addr + AL_IP_ALIGNMENT_OFFSET; 10797902c8dcSWojciech Macek al_buf->len = rx_info->data_size - AL_IP_ALIGNMENT_OFFSET; 10807902c8dcSWojciech Macek 10817902c8dcSWojciech Macek return (0); 10827902c8dcSWojciech Macek } 10837902c8dcSWojciech Macek 10847902c8dcSWojciech Macek static int 10857902c8dcSWojciech Macek al_eth_refill_rx_bufs(struct al_eth_adapter *adapter, unsigned int qid, 10867902c8dcSWojciech Macek unsigned int num) 10877902c8dcSWojciech Macek { 10887902c8dcSWojciech Macek struct al_eth_ring *rx_ring = &adapter->rx_ring[qid]; 10897902c8dcSWojciech Macek uint16_t next_to_use; 10907902c8dcSWojciech Macek unsigned int i; 10917902c8dcSWojciech Macek 10927902c8dcSWojciech Macek next_to_use = rx_ring->next_to_use; 10937902c8dcSWojciech Macek 10947902c8dcSWojciech Macek for (i = 0; i < num; i++) { 10957902c8dcSWojciech Macek int rc; 10967902c8dcSWojciech Macek struct al_eth_rx_buffer *rx_info = 10977902c8dcSWojciech Macek &rx_ring->rx_buffer_info[next_to_use]; 10987902c8dcSWojciech Macek 10997902c8dcSWojciech Macek if (__predict_false(al_eth_alloc_rx_buf(adapter, 11007902c8dcSWojciech Macek rx_ring, rx_info) < 0)) { 11017902c8dcSWojciech Macek device_printf(adapter->dev, 11027902c8dcSWojciech Macek "failed to alloc buffer for rx queue %d\n", qid); 11037902c8dcSWojciech Macek break; 11047902c8dcSWojciech Macek } 11057902c8dcSWojciech Macek 11067902c8dcSWojciech Macek rc = al_eth_rx_buffer_add(rx_ring->dma_q, 11077902c8dcSWojciech Macek &rx_info->al_buf, AL_ETH_RX_FLAGS_INT, NULL); 11087902c8dcSWojciech Macek if (__predict_false(rc)) { 11097902c8dcSWojciech Macek device_printf(adapter->dev, 11107902c8dcSWojciech Macek "failed to add buffer for rx queue %d\n", qid); 11117902c8dcSWojciech Macek break; 11127902c8dcSWojciech Macek } 11137902c8dcSWojciech Macek 11147902c8dcSWojciech Macek next_to_use = AL_ETH_RX_RING_IDX_NEXT(rx_ring, next_to_use); 11157902c8dcSWojciech Macek } 11167902c8dcSWojciech Macek 11177902c8dcSWojciech Macek if (__predict_false(i < num)) 11187902c8dcSWojciech Macek device_printf(adapter->dev, 11197902c8dcSWojciech Macek "refilled rx queue %d with %d pages only - available %d\n", 11207902c8dcSWojciech Macek qid, i, al_udma_available_get(rx_ring->dma_q)); 11217902c8dcSWojciech Macek 11227902c8dcSWojciech Macek if (__predict_true(i)) 11237902c8dcSWojciech Macek al_eth_rx_buffer_action(rx_ring->dma_q, i); 11247902c8dcSWojciech Macek 11257902c8dcSWojciech Macek rx_ring->next_to_use = next_to_use; 11267902c8dcSWojciech Macek 11277902c8dcSWojciech Macek return (i); 11287902c8dcSWojciech Macek } 11297902c8dcSWojciech Macek 11307902c8dcSWojciech Macek /* 11317902c8dcSWojciech Macek * al_eth_refill_all_rx_bufs - allocate all queues Rx buffers 11327902c8dcSWojciech Macek * @adapter: board private structure 11337902c8dcSWojciech Macek */ 11347902c8dcSWojciech Macek static void 11357902c8dcSWojciech Macek al_eth_refill_all_rx_bufs(struct al_eth_adapter *adapter) 11367902c8dcSWojciech Macek { 11377902c8dcSWojciech Macek int i; 11387902c8dcSWojciech Macek 11397902c8dcSWojciech Macek for (i = 0; i < adapter->num_rx_queues; i++) 11407902c8dcSWojciech Macek al_eth_refill_rx_bufs(adapter, i, AL_ETH_DEFAULT_RX_DESCS - 1); 11417902c8dcSWojciech Macek } 11427902c8dcSWojciech Macek 11437902c8dcSWojciech Macek static void 11447902c8dcSWojciech Macek al_eth_tx_do_cleanup(struct al_eth_ring *tx_ring) 11457902c8dcSWojciech Macek { 11467902c8dcSWojciech Macek unsigned int total_done; 11477902c8dcSWojciech Macek uint16_t next_to_clean; 11487902c8dcSWojciech Macek int qid = tx_ring->ring_id; 11497902c8dcSWojciech Macek 11507902c8dcSWojciech Macek total_done = al_eth_comp_tx_get(tx_ring->dma_q); 11517902c8dcSWojciech Macek device_printf_dbg(tx_ring->dev, 11527902c8dcSWojciech Macek "tx_poll: q %d total completed descs %x\n", qid, total_done); 11537902c8dcSWojciech Macek next_to_clean = tx_ring->next_to_clean; 11547902c8dcSWojciech Macek 11557902c8dcSWojciech Macek while (total_done != 0) { 11567902c8dcSWojciech Macek struct al_eth_tx_buffer *tx_info; 11577902c8dcSWojciech Macek struct mbuf *mbuf; 11587902c8dcSWojciech Macek 11597902c8dcSWojciech Macek tx_info = &tx_ring->tx_buffer_info[next_to_clean]; 11607902c8dcSWojciech Macek /* stop if not all descriptors of the packet are completed */ 11617902c8dcSWojciech Macek if (tx_info->tx_descs > total_done) 11627902c8dcSWojciech Macek break; 11637902c8dcSWojciech Macek 11647902c8dcSWojciech Macek mbuf = tx_info->m; 11657902c8dcSWojciech Macek 11667902c8dcSWojciech Macek tx_info->m = NULL; 11677902c8dcSWojciech Macek 11687902c8dcSWojciech Macek device_printf_dbg(tx_ring->dev, 11697902c8dcSWojciech Macek "tx_poll: q %d mbuf %p completed\n", qid, mbuf); 11707902c8dcSWojciech Macek 11717902c8dcSWojciech Macek /* map is no longer required */ 11727902c8dcSWojciech Macek bus_dmamap_unload(tx_ring->dma_buf_tag, tx_info->dma_map); 11737902c8dcSWojciech Macek 11747902c8dcSWojciech Macek m_freem(mbuf); 11757902c8dcSWojciech Macek total_done -= tx_info->tx_descs; 11767902c8dcSWojciech Macek next_to_clean = AL_ETH_TX_RING_IDX_NEXT(tx_ring, next_to_clean); 11777902c8dcSWojciech Macek } 11787902c8dcSWojciech Macek 11797902c8dcSWojciech Macek tx_ring->next_to_clean = next_to_clean; 11807902c8dcSWojciech Macek 11817902c8dcSWojciech Macek device_printf_dbg(tx_ring->dev, "tx_poll: q %d done next to clean %x\n", 11827902c8dcSWojciech Macek qid, next_to_clean); 11837902c8dcSWojciech Macek 11847902c8dcSWojciech Macek /* 11857902c8dcSWojciech Macek * need to make the rings circular update visible to 11867902c8dcSWojciech Macek * al_eth_start_xmit() before checking for netif_queue_stopped(). 11877902c8dcSWojciech Macek */ 11887902c8dcSWojciech Macek al_smp_data_memory_barrier(); 11897902c8dcSWojciech Macek } 11907902c8dcSWojciech Macek 11917902c8dcSWojciech Macek static void 11927902c8dcSWojciech Macek al_eth_tx_csum(struct al_eth_ring *tx_ring, struct al_eth_tx_buffer *tx_info, 11937902c8dcSWojciech Macek struct al_eth_pkt *hal_pkt, struct mbuf *m) 11947902c8dcSWojciech Macek { 11957902c8dcSWojciech Macek uint32_t mss = m->m_pkthdr.tso_segsz; 11967902c8dcSWojciech Macek struct ether_vlan_header *eh; 11977902c8dcSWojciech Macek uint16_t etype; 11980b5cab4eSMarcin Wojtas #ifdef INET 11997902c8dcSWojciech Macek struct ip *ip; 12000b5cab4eSMarcin Wojtas #endif 12010b5cab4eSMarcin Wojtas #ifdef INET6 12027902c8dcSWojciech Macek struct ip6_hdr *ip6; 12030b5cab4eSMarcin Wojtas #endif 12047902c8dcSWojciech Macek struct tcphdr *th = NULL; 12057902c8dcSWojciech Macek int ehdrlen, ip_hlen = 0; 12067902c8dcSWojciech Macek uint8_t ipproto = 0; 12077902c8dcSWojciech Macek uint32_t offload = 0; 12087902c8dcSWojciech Macek 12097902c8dcSWojciech Macek if (mss != 0) 12107902c8dcSWojciech Macek offload = 1; 12117902c8dcSWojciech Macek 12127902c8dcSWojciech Macek if ((m->m_pkthdr.csum_flags & CSUM_TSO) != 0) 12137902c8dcSWojciech Macek offload = 1; 12147902c8dcSWojciech Macek 12157902c8dcSWojciech Macek if ((m->m_pkthdr.csum_flags & CSUM_OFFLOAD) != 0) 12167902c8dcSWojciech Macek offload = 1; 12177902c8dcSWojciech Macek 12187902c8dcSWojciech Macek if (offload != 0) { 12197902c8dcSWojciech Macek struct al_eth_meta_data *meta = &tx_ring->hal_meta; 12207902c8dcSWojciech Macek 12217902c8dcSWojciech Macek if (mss != 0) 12227902c8dcSWojciech Macek hal_pkt->flags |= (AL_ETH_TX_FLAGS_TSO | 12237902c8dcSWojciech Macek AL_ETH_TX_FLAGS_L4_CSUM); 12247902c8dcSWojciech Macek else 12257902c8dcSWojciech Macek hal_pkt->flags |= (AL_ETH_TX_FLAGS_L4_CSUM | 12267902c8dcSWojciech Macek AL_ETH_TX_FLAGS_L4_PARTIAL_CSUM); 12277902c8dcSWojciech Macek 12287902c8dcSWojciech Macek /* 12297902c8dcSWojciech Macek * Determine where frame payload starts. 12307902c8dcSWojciech Macek * Jump over vlan headers if already present, 12317902c8dcSWojciech Macek * helpful for QinQ too. 12327902c8dcSWojciech Macek */ 12337902c8dcSWojciech Macek eh = mtod(m, struct ether_vlan_header *); 12347902c8dcSWojciech Macek if (eh->evl_encap_proto == htons(ETHERTYPE_VLAN)) { 12357902c8dcSWojciech Macek etype = ntohs(eh->evl_proto); 12367902c8dcSWojciech Macek ehdrlen = ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN; 12377902c8dcSWojciech Macek } else { 12387902c8dcSWojciech Macek etype = ntohs(eh->evl_encap_proto); 12397902c8dcSWojciech Macek ehdrlen = ETHER_HDR_LEN; 12407902c8dcSWojciech Macek } 12417902c8dcSWojciech Macek 12427902c8dcSWojciech Macek switch (etype) { 12430b5cab4eSMarcin Wojtas #ifdef INET 12447902c8dcSWojciech Macek case ETHERTYPE_IP: 12457902c8dcSWojciech Macek ip = (struct ip *)(m->m_data + ehdrlen); 12467902c8dcSWojciech Macek ip_hlen = ip->ip_hl << 2; 12477902c8dcSWojciech Macek ipproto = ip->ip_p; 12487902c8dcSWojciech Macek hal_pkt->l3_proto_idx = AL_ETH_PROTO_ID_IPv4; 12497902c8dcSWojciech Macek th = (struct tcphdr *)((caddr_t)ip + ip_hlen); 12507902c8dcSWojciech Macek if (mss != 0) 12517902c8dcSWojciech Macek hal_pkt->flags |= AL_ETH_TX_FLAGS_IPV4_L3_CSUM; 12527902c8dcSWojciech Macek if (ipproto == IPPROTO_TCP) 12537902c8dcSWojciech Macek hal_pkt->l4_proto_idx = AL_ETH_PROTO_ID_TCP; 12547902c8dcSWojciech Macek else 12557902c8dcSWojciech Macek hal_pkt->l4_proto_idx = AL_ETH_PROTO_ID_UDP; 12567902c8dcSWojciech Macek break; 12570b5cab4eSMarcin Wojtas #endif /* INET */ 12580b5cab4eSMarcin Wojtas #ifdef INET6 12597902c8dcSWojciech Macek case ETHERTYPE_IPV6: 12607902c8dcSWojciech Macek ip6 = (struct ip6_hdr *)(m->m_data + ehdrlen); 12617902c8dcSWojciech Macek hal_pkt->l3_proto_idx = AL_ETH_PROTO_ID_IPv6; 12627902c8dcSWojciech Macek ip_hlen = sizeof(struct ip6_hdr); 12637902c8dcSWojciech Macek th = (struct tcphdr *)((caddr_t)ip6 + ip_hlen); 12647902c8dcSWojciech Macek ipproto = ip6->ip6_nxt; 12657902c8dcSWojciech Macek if (ipproto == IPPROTO_TCP) 12667902c8dcSWojciech Macek hal_pkt->l4_proto_idx = AL_ETH_PROTO_ID_TCP; 12677902c8dcSWojciech Macek else 12687902c8dcSWojciech Macek hal_pkt->l4_proto_idx = AL_ETH_PROTO_ID_UDP; 12697902c8dcSWojciech Macek break; 12700b5cab4eSMarcin Wojtas #endif /* INET6 */ 12717902c8dcSWojciech Macek default: 12727902c8dcSWojciech Macek break; 12737902c8dcSWojciech Macek } 12747902c8dcSWojciech Macek 12757902c8dcSWojciech Macek meta->words_valid = 4; 12767902c8dcSWojciech Macek meta->l3_header_len = ip_hlen; 12777902c8dcSWojciech Macek meta->l3_header_offset = ehdrlen; 12787902c8dcSWojciech Macek if (th != NULL) 12797902c8dcSWojciech Macek meta->l4_header_len = th->th_off; /* this param needed only for TSO */ 12807902c8dcSWojciech Macek meta->mss_idx_sel = 0; /* check how to select MSS */ 12817902c8dcSWojciech Macek meta->mss_val = mss; 12827902c8dcSWojciech Macek hal_pkt->meta = meta; 12837902c8dcSWojciech Macek } else 12847902c8dcSWojciech Macek hal_pkt->meta = NULL; 12857902c8dcSWojciech Macek } 12867902c8dcSWojciech Macek 12877902c8dcSWojciech Macek #define XMIT_QUEUE_TIMEOUT 100 12887902c8dcSWojciech Macek 12897902c8dcSWojciech Macek static void 12907902c8dcSWojciech Macek al_eth_xmit_mbuf(struct al_eth_ring *tx_ring, struct mbuf *m) 12917902c8dcSWojciech Macek { 12927902c8dcSWojciech Macek struct al_eth_tx_buffer *tx_info; 12937902c8dcSWojciech Macek int error; 12947902c8dcSWojciech Macek int nsegs, a; 12957902c8dcSWojciech Macek uint16_t next_to_use; 12967902c8dcSWojciech Macek bus_dma_segment_t segs[AL_ETH_PKT_MAX_BUFS + 1]; 12977902c8dcSWojciech Macek struct al_eth_pkt *hal_pkt; 12987902c8dcSWojciech Macek struct al_buf *al_buf; 1299463edaf4SJohn Baldwin bool remap; 13007902c8dcSWojciech Macek 13017902c8dcSWojciech Macek /* Check if queue is ready */ 13027902c8dcSWojciech Macek if (unlikely(tx_ring->stall) != 0) { 13037902c8dcSWojciech Macek for (a = 0; a < XMIT_QUEUE_TIMEOUT; a++) { 13047902c8dcSWojciech Macek if (al_udma_available_get(tx_ring->dma_q) >= 13057902c8dcSWojciech Macek (AL_ETH_DEFAULT_TX_HW_DESCS - 13067902c8dcSWojciech Macek AL_ETH_TX_WAKEUP_THRESH)) { 13077902c8dcSWojciech Macek tx_ring->stall = 0; 13087902c8dcSWojciech Macek break; 13097902c8dcSWojciech Macek } 13107902c8dcSWojciech Macek pause("stall", 1); 13117902c8dcSWojciech Macek } 13127902c8dcSWojciech Macek if (a == XMIT_QUEUE_TIMEOUT) { 13137902c8dcSWojciech Macek device_printf(tx_ring->dev, 13147902c8dcSWojciech Macek "timeout waiting for queue %d ready!\n", 13157902c8dcSWojciech Macek tx_ring->ring_id); 13167902c8dcSWojciech Macek return; 13177902c8dcSWojciech Macek } else { 13187902c8dcSWojciech Macek device_printf_dbg(tx_ring->dev, 13197902c8dcSWojciech Macek "queue %d is ready!\n", tx_ring->ring_id); 13207902c8dcSWojciech Macek } 13217902c8dcSWojciech Macek } 13227902c8dcSWojciech Macek 13237902c8dcSWojciech Macek next_to_use = tx_ring->next_to_use; 13247902c8dcSWojciech Macek tx_info = &tx_ring->tx_buffer_info[next_to_use]; 13257902c8dcSWojciech Macek tx_info->m = m; 13267902c8dcSWojciech Macek hal_pkt = &tx_info->hal_pkt; 13277902c8dcSWojciech Macek 13287902c8dcSWojciech Macek if (m == NULL) { 13297902c8dcSWojciech Macek device_printf(tx_ring->dev, "mbuf is NULL\n"); 13307902c8dcSWojciech Macek return; 13317902c8dcSWojciech Macek } 13327902c8dcSWojciech Macek 1333463edaf4SJohn Baldwin remap = true; 13347902c8dcSWojciech Macek /* Map packets for DMA */ 13357902c8dcSWojciech Macek retry: 13367902c8dcSWojciech Macek error = bus_dmamap_load_mbuf_sg(tx_ring->dma_buf_tag, tx_info->dma_map, 13377902c8dcSWojciech Macek m, segs, &nsegs, BUS_DMA_NOWAIT); 13387902c8dcSWojciech Macek if (__predict_false(error)) { 13397902c8dcSWojciech Macek struct mbuf *m_new; 13407902c8dcSWojciech Macek 13417902c8dcSWojciech Macek if (error == EFBIG) { 13427902c8dcSWojciech Macek /* Try it again? - one try */ 1343463edaf4SJohn Baldwin if (remap == true) { 1344463edaf4SJohn Baldwin remap = false; 13457902c8dcSWojciech Macek m_new = m_defrag(m, M_NOWAIT); 13467902c8dcSWojciech Macek if (m_new == NULL) { 13477902c8dcSWojciech Macek device_printf(tx_ring->dev, 13487902c8dcSWojciech Macek "failed to defrag mbuf\n"); 13497902c8dcSWojciech Macek goto exit; 13507902c8dcSWojciech Macek } 13517902c8dcSWojciech Macek m = m_new; 13527902c8dcSWojciech Macek goto retry; 13537902c8dcSWojciech Macek } else { 13547902c8dcSWojciech Macek device_printf(tx_ring->dev, 13557902c8dcSWojciech Macek "failed to map mbuf, error %d\n", error); 13567902c8dcSWojciech Macek goto exit; 13577902c8dcSWojciech Macek } 13587902c8dcSWojciech Macek } else { 13597902c8dcSWojciech Macek device_printf(tx_ring->dev, 13607902c8dcSWojciech Macek "failed to map mbuf, error %d\n", error); 13617902c8dcSWojciech Macek goto exit; 13627902c8dcSWojciech Macek } 13637902c8dcSWojciech Macek } 13647902c8dcSWojciech Macek 13657902c8dcSWojciech Macek /* set flags and meta data */ 13667902c8dcSWojciech Macek hal_pkt->flags = AL_ETH_TX_FLAGS_INT; 13677902c8dcSWojciech Macek al_eth_tx_csum(tx_ring, tx_info, hal_pkt, m); 13687902c8dcSWojciech Macek 13697902c8dcSWojciech Macek al_buf = hal_pkt->bufs; 13707902c8dcSWojciech Macek for (a = 0; a < nsegs; a++) { 13717902c8dcSWojciech Macek al_buf->addr = segs[a].ds_addr; 13727902c8dcSWojciech Macek al_buf->len = segs[a].ds_len; 13737902c8dcSWojciech Macek 13747902c8dcSWojciech Macek al_buf++; 13757902c8dcSWojciech Macek } 13767902c8dcSWojciech Macek 13777902c8dcSWojciech Macek hal_pkt->num_of_bufs = nsegs; 13787902c8dcSWojciech Macek 13797902c8dcSWojciech Macek /* prepare the packet's descriptors to dma engine */ 13807902c8dcSWojciech Macek tx_info->tx_descs = al_eth_tx_pkt_prepare(tx_ring->dma_q, hal_pkt); 13817902c8dcSWojciech Macek 13827902c8dcSWojciech Macek if (tx_info->tx_descs == 0) 13837902c8dcSWojciech Macek goto exit; 13847902c8dcSWojciech Macek 13857902c8dcSWojciech Macek /* 13867902c8dcSWojciech Macek * stop the queue when no more space available, the packet can have up 13877902c8dcSWojciech Macek * to AL_ETH_PKT_MAX_BUFS + 1 buffers and a meta descriptor 13887902c8dcSWojciech Macek */ 13897902c8dcSWojciech Macek if (unlikely(al_udma_available_get(tx_ring->dma_q) < 13907902c8dcSWojciech Macek (AL_ETH_PKT_MAX_BUFS + 2))) { 13917902c8dcSWojciech Macek tx_ring->stall = 1; 13927902c8dcSWojciech Macek device_printf_dbg(tx_ring->dev, "stall, stopping queue %d...\n", 13937902c8dcSWojciech Macek tx_ring->ring_id); 13947902c8dcSWojciech Macek al_data_memory_barrier(); 13957902c8dcSWojciech Macek } 13967902c8dcSWojciech Macek 13977902c8dcSWojciech Macek tx_ring->next_to_use = AL_ETH_TX_RING_IDX_NEXT(tx_ring, next_to_use); 13987902c8dcSWojciech Macek 13997902c8dcSWojciech Macek /* trigger the dma engine */ 14007902c8dcSWojciech Macek al_eth_tx_dma_action(tx_ring->dma_q, tx_info->tx_descs); 14017902c8dcSWojciech Macek return; 14027902c8dcSWojciech Macek 14037902c8dcSWojciech Macek exit: 14047902c8dcSWojciech Macek m_freem(m); 14057902c8dcSWojciech Macek } 14067902c8dcSWojciech Macek 14077902c8dcSWojciech Macek static void 14087902c8dcSWojciech Macek al_eth_tx_cmpl_work(void *arg, int pending) 14097902c8dcSWojciech Macek { 14107902c8dcSWojciech Macek struct al_eth_ring *tx_ring = arg; 14117902c8dcSWojciech Macek 14127902c8dcSWojciech Macek if (napi != 0) { 14137902c8dcSWojciech Macek tx_ring->cmpl_is_running = 1; 14147902c8dcSWojciech Macek al_data_memory_barrier(); 14157902c8dcSWojciech Macek } 14167902c8dcSWojciech Macek 14177902c8dcSWojciech Macek al_eth_tx_do_cleanup(tx_ring); 14187902c8dcSWojciech Macek 14197902c8dcSWojciech Macek if (napi != 0) { 14207902c8dcSWojciech Macek tx_ring->cmpl_is_running = 0; 14217902c8dcSWojciech Macek al_data_memory_barrier(); 14227902c8dcSWojciech Macek } 14237902c8dcSWojciech Macek /* all work done, enable IRQs */ 14247902c8dcSWojciech Macek al_eth_irq_config(tx_ring->unmask_reg_offset, tx_ring->unmask_val); 14257902c8dcSWojciech Macek } 14267902c8dcSWojciech Macek 14277902c8dcSWojciech Macek static int 14287902c8dcSWojciech Macek al_eth_tx_cmlp_irq_filter(void *arg) 14297902c8dcSWojciech Macek { 14307902c8dcSWojciech Macek struct al_eth_ring *tx_ring = arg; 14317902c8dcSWojciech Macek 14327902c8dcSWojciech Macek /* Interrupt should be auto-masked upon arrival */ 14337902c8dcSWojciech Macek 14347902c8dcSWojciech Macek device_printf_dbg(tx_ring->dev, "%s for ring ID = %d\n", __func__, 14357902c8dcSWojciech Macek tx_ring->ring_id); 14367902c8dcSWojciech Macek 14377902c8dcSWojciech Macek /* 14387902c8dcSWojciech Macek * For napi, if work is not running, schedule it. Always schedule 14397902c8dcSWojciech Macek * for casual (non-napi) packet handling. 14407902c8dcSWojciech Macek */ 14417902c8dcSWojciech Macek if ((napi == 0) || (napi && tx_ring->cmpl_is_running == 0)) 14427902c8dcSWojciech Macek taskqueue_enqueue(tx_ring->cmpl_tq, &tx_ring->cmpl_task); 14437902c8dcSWojciech Macek 14447902c8dcSWojciech Macek /* Do not run bottom half */ 14457902c8dcSWojciech Macek return (FILTER_HANDLED); 14467902c8dcSWojciech Macek } 14477902c8dcSWojciech Macek 14487902c8dcSWojciech Macek static int 14497902c8dcSWojciech Macek al_eth_rx_recv_irq_filter(void *arg) 14507902c8dcSWojciech Macek { 14517902c8dcSWojciech Macek struct al_eth_ring *rx_ring = arg; 14527902c8dcSWojciech Macek 14537902c8dcSWojciech Macek /* Interrupt should be auto-masked upon arrival */ 14547902c8dcSWojciech Macek 14557902c8dcSWojciech Macek device_printf_dbg(rx_ring->dev, "%s for ring ID = %d\n", __func__, 14567902c8dcSWojciech Macek rx_ring->ring_id); 14577902c8dcSWojciech Macek 14587902c8dcSWojciech Macek /* 14597902c8dcSWojciech Macek * For napi, if work is not running, schedule it. Always schedule 14607902c8dcSWojciech Macek * for casual (non-napi) packet handling. 14617902c8dcSWojciech Macek */ 14627902c8dcSWojciech Macek if ((napi == 0) || (napi && rx_ring->enqueue_is_running == 0)) 14637902c8dcSWojciech Macek taskqueue_enqueue(rx_ring->enqueue_tq, &rx_ring->enqueue_task); 14647902c8dcSWojciech Macek 14657902c8dcSWojciech Macek /* Do not run bottom half */ 14667902c8dcSWojciech Macek return (FILTER_HANDLED); 14677902c8dcSWojciech Macek } 14687902c8dcSWojciech Macek 14697902c8dcSWojciech Macek /* 14707902c8dcSWojciech Macek * al_eth_rx_checksum - indicate in mbuf if hw indicated a good cksum 14717902c8dcSWojciech Macek * @adapter: structure containing adapter specific data 14727902c8dcSWojciech Macek * @hal_pkt: HAL structure for the packet 14737902c8dcSWojciech Macek * @mbuf: mbuf currently being received and modified 14747902c8dcSWojciech Macek */ 14757902c8dcSWojciech Macek static inline void 14767902c8dcSWojciech Macek al_eth_rx_checksum(struct al_eth_adapter *adapter, 14777902c8dcSWojciech Macek struct al_eth_pkt *hal_pkt, struct mbuf *mbuf) 14787902c8dcSWojciech Macek { 14797902c8dcSWojciech Macek 14807902c8dcSWojciech Macek /* if IPv4 and error */ 1481f46a05b5SJustin Hibbits if (unlikely((if_getcapenable(adapter->netdev) & IFCAP_RXCSUM) && 14827902c8dcSWojciech Macek (hal_pkt->l3_proto_idx == AL_ETH_PROTO_ID_IPv4) && 14837902c8dcSWojciech Macek (hal_pkt->flags & AL_ETH_RX_FLAGS_L3_CSUM_ERR))) { 14847902c8dcSWojciech Macek device_printf(adapter->dev,"rx ipv4 header checksum error\n"); 14857902c8dcSWojciech Macek return; 14867902c8dcSWojciech Macek } 14877902c8dcSWojciech Macek 14887902c8dcSWojciech Macek /* if IPv6 and error */ 1489f46a05b5SJustin Hibbits if (unlikely((if_getcapenable(adapter->netdev) & IFCAP_RXCSUM_IPV6) && 14907902c8dcSWojciech Macek (hal_pkt->l3_proto_idx == AL_ETH_PROTO_ID_IPv6) && 14917902c8dcSWojciech Macek (hal_pkt->flags & AL_ETH_RX_FLAGS_L3_CSUM_ERR))) { 14927902c8dcSWojciech Macek device_printf(adapter->dev,"rx ipv6 header checksum error\n"); 14937902c8dcSWojciech Macek return; 14947902c8dcSWojciech Macek } 14957902c8dcSWojciech Macek 14967902c8dcSWojciech Macek /* if TCP/UDP */ 14977902c8dcSWojciech Macek if (likely((hal_pkt->l4_proto_idx == AL_ETH_PROTO_ID_TCP) || 14987902c8dcSWojciech Macek (hal_pkt->l4_proto_idx == AL_ETH_PROTO_ID_UDP))) { 14997902c8dcSWojciech Macek if (unlikely(hal_pkt->flags & AL_ETH_RX_FLAGS_L4_CSUM_ERR)) { 15007902c8dcSWojciech Macek device_printf_dbg(adapter->dev, "rx L4 checksum error\n"); 15017902c8dcSWojciech Macek 15027902c8dcSWojciech Macek /* TCP/UDP checksum error */ 15037902c8dcSWojciech Macek mbuf->m_pkthdr.csum_flags = 0; 15047902c8dcSWojciech Macek } else { 15057902c8dcSWojciech Macek device_printf_dbg(adapter->dev, "rx checksum correct\n"); 15067902c8dcSWojciech Macek 15077902c8dcSWojciech Macek /* IP Checksum Good */ 15087902c8dcSWojciech Macek mbuf->m_pkthdr.csum_flags = CSUM_IP_CHECKED; 15097902c8dcSWojciech Macek mbuf->m_pkthdr.csum_flags |= CSUM_IP_VALID; 15107902c8dcSWojciech Macek } 15117902c8dcSWojciech Macek } 15127902c8dcSWojciech Macek } 15137902c8dcSWojciech Macek 15147902c8dcSWojciech Macek static struct mbuf* 15157902c8dcSWojciech Macek al_eth_rx_mbuf(struct al_eth_adapter *adapter, 15167902c8dcSWojciech Macek struct al_eth_ring *rx_ring, struct al_eth_pkt *hal_pkt, 15177902c8dcSWojciech Macek unsigned int descs, uint16_t *next_to_clean) 15187902c8dcSWojciech Macek { 15197902c8dcSWojciech Macek struct mbuf *mbuf; 15207902c8dcSWojciech Macek struct al_eth_rx_buffer *rx_info = 15217902c8dcSWojciech Macek &rx_ring->rx_buffer_info[*next_to_clean]; 15227902c8dcSWojciech Macek unsigned int len; 15237902c8dcSWojciech Macek 15247902c8dcSWojciech Macek len = hal_pkt->bufs[0].len; 15257902c8dcSWojciech Macek device_printf_dbg(adapter->dev, "rx_info %p data %p\n", rx_info, 15267902c8dcSWojciech Macek rx_info->m); 15277902c8dcSWojciech Macek 15287902c8dcSWojciech Macek if (rx_info->m == NULL) { 15297902c8dcSWojciech Macek *next_to_clean = AL_ETH_RX_RING_IDX_NEXT(rx_ring, 15307902c8dcSWojciech Macek *next_to_clean); 15317902c8dcSWojciech Macek return (NULL); 15327902c8dcSWojciech Macek } 15337902c8dcSWojciech Macek 15347902c8dcSWojciech Macek mbuf = rx_info->m; 15357902c8dcSWojciech Macek mbuf->m_pkthdr.len = len; 15367902c8dcSWojciech Macek mbuf->m_len = len; 15377902c8dcSWojciech Macek mbuf->m_pkthdr.rcvif = rx_ring->netdev; 15387902c8dcSWojciech Macek mbuf->m_flags |= M_PKTHDR; 15397902c8dcSWojciech Macek 15407902c8dcSWojciech Macek if (len <= adapter->small_copy_len) { 15417902c8dcSWojciech Macek struct mbuf *smbuf; 15427902c8dcSWojciech Macek device_printf_dbg(adapter->dev, "rx small packet. len %d\n", len); 15437902c8dcSWojciech Macek 15447902c8dcSWojciech Macek AL_RX_LOCK(adapter); 15457902c8dcSWojciech Macek smbuf = m_gethdr(M_NOWAIT, MT_DATA); 15467902c8dcSWojciech Macek AL_RX_UNLOCK(adapter); 15477902c8dcSWojciech Macek if (__predict_false(smbuf == NULL)) { 15487902c8dcSWojciech Macek device_printf(adapter->dev, "smbuf is NULL\n"); 15497902c8dcSWojciech Macek return (NULL); 15507902c8dcSWojciech Macek } 15517902c8dcSWojciech Macek 15527902c8dcSWojciech Macek smbuf->m_data = smbuf->m_data + AL_IP_ALIGNMENT_OFFSET; 15537902c8dcSWojciech Macek memcpy(smbuf->m_data, mbuf->m_data + AL_IP_ALIGNMENT_OFFSET, len); 15547902c8dcSWojciech Macek 15557902c8dcSWojciech Macek smbuf->m_len = len; 15567902c8dcSWojciech Macek smbuf->m_pkthdr.rcvif = rx_ring->netdev; 15577902c8dcSWojciech Macek 15587902c8dcSWojciech Macek /* first desc of a non-ps chain */ 15597902c8dcSWojciech Macek smbuf->m_flags |= M_PKTHDR; 15607902c8dcSWojciech Macek smbuf->m_pkthdr.len = smbuf->m_len; 15617902c8dcSWojciech Macek 15627902c8dcSWojciech Macek *next_to_clean = AL_ETH_RX_RING_IDX_NEXT(rx_ring, 15637902c8dcSWojciech Macek *next_to_clean); 15647902c8dcSWojciech Macek 15657902c8dcSWojciech Macek return (smbuf); 15667902c8dcSWojciech Macek } 15677902c8dcSWojciech Macek mbuf->m_data = mbuf->m_data + AL_IP_ALIGNMENT_OFFSET; 15687902c8dcSWojciech Macek 15697902c8dcSWojciech Macek /* Unmap the buffer */ 15707902c8dcSWojciech Macek bus_dmamap_unload(rx_ring->dma_buf_tag, rx_info->dma_map); 15717902c8dcSWojciech Macek 15727902c8dcSWojciech Macek rx_info->m = NULL; 15737902c8dcSWojciech Macek *next_to_clean = AL_ETH_RX_RING_IDX_NEXT(rx_ring, *next_to_clean); 15747902c8dcSWojciech Macek 15757902c8dcSWojciech Macek return (mbuf); 15767902c8dcSWojciech Macek } 15777902c8dcSWojciech Macek 15787902c8dcSWojciech Macek static void 15797902c8dcSWojciech Macek al_eth_rx_recv_work(void *arg, int pending) 15807902c8dcSWojciech Macek { 15817902c8dcSWojciech Macek struct al_eth_ring *rx_ring = arg; 15827902c8dcSWojciech Macek struct mbuf *mbuf; 15837902c8dcSWojciech Macek unsigned int qid = rx_ring->ring_id; 15847902c8dcSWojciech Macek struct al_eth_pkt *hal_pkt = &rx_ring->hal_pkt; 15857902c8dcSWojciech Macek uint16_t next_to_clean = rx_ring->next_to_clean; 15867902c8dcSWojciech Macek uint32_t refill_required; 15877902c8dcSWojciech Macek uint32_t refill_actual; 15887902c8dcSWojciech Macek uint32_t do_if_input; 15897902c8dcSWojciech Macek 15907902c8dcSWojciech Macek if (napi != 0) { 15917902c8dcSWojciech Macek rx_ring->enqueue_is_running = 1; 15927902c8dcSWojciech Macek al_data_memory_barrier(); 15937902c8dcSWojciech Macek } 15947902c8dcSWojciech Macek 15957902c8dcSWojciech Macek do { 15967902c8dcSWojciech Macek unsigned int descs; 15977902c8dcSWojciech Macek 15987902c8dcSWojciech Macek descs = al_eth_pkt_rx(rx_ring->dma_q, hal_pkt); 15997902c8dcSWojciech Macek if (unlikely(descs == 0)) 16007902c8dcSWojciech Macek break; 16017902c8dcSWojciech Macek 16027902c8dcSWojciech Macek device_printf_dbg(rx_ring->dev, "rx_poll: q %d got packet " 16037902c8dcSWojciech Macek "from hal. descs %d\n", qid, descs); 16047902c8dcSWojciech Macek device_printf_dbg(rx_ring->dev, "rx_poll: q %d flags %x. " 16057902c8dcSWojciech Macek "l3 proto %d l4 proto %d\n", qid, hal_pkt->flags, 16067902c8dcSWojciech Macek hal_pkt->l3_proto_idx, hal_pkt->l4_proto_idx); 16077902c8dcSWojciech Macek 16087902c8dcSWojciech Macek /* ignore if detected dma or eth controller errors */ 16097902c8dcSWojciech Macek if ((hal_pkt->flags & (AL_ETH_RX_ERROR | 16107902c8dcSWojciech Macek AL_UDMA_CDESC_ERROR)) != 0) { 16117902c8dcSWojciech Macek device_printf(rx_ring->dev, "receive packet with error. " 16127902c8dcSWojciech Macek "flags = 0x%x\n", hal_pkt->flags); 16137902c8dcSWojciech Macek next_to_clean = AL_ETH_RX_RING_IDX_ADD(rx_ring, 16147902c8dcSWojciech Macek next_to_clean, descs); 16157902c8dcSWojciech Macek continue; 16167902c8dcSWojciech Macek } 16177902c8dcSWojciech Macek 16187902c8dcSWojciech Macek /* allocate mbuf and fill it */ 16197902c8dcSWojciech Macek mbuf = al_eth_rx_mbuf(rx_ring->adapter, rx_ring, hal_pkt, descs, 16207902c8dcSWojciech Macek &next_to_clean); 16217902c8dcSWojciech Macek 16227902c8dcSWojciech Macek /* exit if we failed to retrieve a buffer */ 16237902c8dcSWojciech Macek if (unlikely(mbuf == NULL)) { 16247902c8dcSWojciech Macek next_to_clean = AL_ETH_RX_RING_IDX_ADD(rx_ring, 16257902c8dcSWojciech Macek next_to_clean, descs); 16267902c8dcSWojciech Macek break; 16277902c8dcSWojciech Macek } 16287902c8dcSWojciech Macek 1629f46a05b5SJustin Hibbits if (__predict_true(if_getcapenable(rx_ring->netdev) & IFCAP_RXCSUM || 1630f46a05b5SJustin Hibbits if_getcapenable(rx_ring->netdev) & IFCAP_RXCSUM_IPV6)) { 16317902c8dcSWojciech Macek al_eth_rx_checksum(rx_ring->adapter, hal_pkt, mbuf); 16327902c8dcSWojciech Macek } 16337902c8dcSWojciech Macek 16347902c8dcSWojciech Macek mbuf->m_pkthdr.flowid = qid; 16357902c8dcSWojciech Macek M_HASHTYPE_SET(mbuf, M_HASHTYPE_OPAQUE); 16367902c8dcSWojciech Macek 16377902c8dcSWojciech Macek /* 16387902c8dcSWojciech Macek * LRO is only for IP/TCP packets and TCP checksum of the packet 16397902c8dcSWojciech Macek * should be computed by hardware. 16407902c8dcSWojciech Macek */ 16417902c8dcSWojciech Macek do_if_input = 1; 16427902c8dcSWojciech Macek if ((rx_ring->lro_enabled != 0) && 16437902c8dcSWojciech Macek ((mbuf->m_pkthdr.csum_flags & CSUM_IP_VALID) != 0) && 16447902c8dcSWojciech Macek hal_pkt->l4_proto_idx == AL_ETH_PROTO_ID_TCP) { 16457902c8dcSWojciech Macek /* 16467902c8dcSWojciech Macek * Send to the stack if: 16477902c8dcSWojciech Macek * - LRO not enabled, or 16487902c8dcSWojciech Macek * - no LRO resources, or 16497902c8dcSWojciech Macek * - lro enqueue fails 16507902c8dcSWojciech Macek */ 16517902c8dcSWojciech Macek if (rx_ring->lro.lro_cnt != 0) { 16527902c8dcSWojciech Macek if (tcp_lro_rx(&rx_ring->lro, mbuf, 0) == 0) 16537902c8dcSWojciech Macek do_if_input = 0; 16547902c8dcSWojciech Macek } 16557902c8dcSWojciech Macek } 16567902c8dcSWojciech Macek 16577902c8dcSWojciech Macek if (do_if_input) 1658f46a05b5SJustin Hibbits if_input(rx_ring->netdev, mbuf); 16597902c8dcSWojciech Macek 16607902c8dcSWojciech Macek } while (1); 16617902c8dcSWojciech Macek 16627902c8dcSWojciech Macek rx_ring->next_to_clean = next_to_clean; 16637902c8dcSWojciech Macek 16647902c8dcSWojciech Macek refill_required = al_udma_available_get(rx_ring->dma_q); 16657902c8dcSWojciech Macek refill_actual = al_eth_refill_rx_bufs(rx_ring->adapter, qid, 16667902c8dcSWojciech Macek refill_required); 16677902c8dcSWojciech Macek 16687902c8dcSWojciech Macek if (unlikely(refill_actual < refill_required)) { 16697902c8dcSWojciech Macek device_printf_dbg(rx_ring->dev, 16707902c8dcSWojciech Macek "%s: not filling rx queue %d\n", __func__, qid); 16717902c8dcSWojciech Macek } 16727902c8dcSWojciech Macek 1673*0b45d365SMichael Tuexen tcp_lro_flush_all(&rx_ring->lro); 16747902c8dcSWojciech Macek 16757902c8dcSWojciech Macek if (napi != 0) { 16767902c8dcSWojciech Macek rx_ring->enqueue_is_running = 0; 16777902c8dcSWojciech Macek al_data_memory_barrier(); 16787902c8dcSWojciech Macek } 16797902c8dcSWojciech Macek /* unmask irq */ 16807902c8dcSWojciech Macek al_eth_irq_config(rx_ring->unmask_reg_offset, rx_ring->unmask_val); 16817902c8dcSWojciech Macek } 16827902c8dcSWojciech Macek 16837902c8dcSWojciech Macek static void 16847902c8dcSWojciech Macek al_eth_start_xmit(void *arg, int pending) 16857902c8dcSWojciech Macek { 16867902c8dcSWojciech Macek struct al_eth_ring *tx_ring = arg; 16877902c8dcSWojciech Macek struct mbuf *mbuf; 16887902c8dcSWojciech Macek 16897902c8dcSWojciech Macek if (napi != 0) { 16907902c8dcSWojciech Macek tx_ring->enqueue_is_running = 1; 16917902c8dcSWojciech Macek al_data_memory_barrier(); 16927902c8dcSWojciech Macek } 16937902c8dcSWojciech Macek 16947902c8dcSWojciech Macek while (1) { 16957902c8dcSWojciech Macek mtx_lock(&tx_ring->br_mtx); 16967902c8dcSWojciech Macek mbuf = drbr_dequeue(NULL, tx_ring->br); 16977902c8dcSWojciech Macek mtx_unlock(&tx_ring->br_mtx); 16987902c8dcSWojciech Macek 16997902c8dcSWojciech Macek if (mbuf == NULL) 17007902c8dcSWojciech Macek break; 17017902c8dcSWojciech Macek 17027902c8dcSWojciech Macek al_eth_xmit_mbuf(tx_ring, mbuf); 17037902c8dcSWojciech Macek } 17047902c8dcSWojciech Macek 17057902c8dcSWojciech Macek if (napi != 0) { 17067902c8dcSWojciech Macek tx_ring->enqueue_is_running = 0; 17077902c8dcSWojciech Macek al_data_memory_barrier(); 17087902c8dcSWojciech Macek while (1) { 17097902c8dcSWojciech Macek mtx_lock(&tx_ring->br_mtx); 17107902c8dcSWojciech Macek mbuf = drbr_dequeue(NULL, tx_ring->br); 17117902c8dcSWojciech Macek mtx_unlock(&tx_ring->br_mtx); 17127902c8dcSWojciech Macek if (mbuf == NULL) 17137902c8dcSWojciech Macek break; 17147902c8dcSWojciech Macek al_eth_xmit_mbuf(tx_ring, mbuf); 17157902c8dcSWojciech Macek } 17167902c8dcSWojciech Macek } 17177902c8dcSWojciech Macek } 17187902c8dcSWojciech Macek 17197902c8dcSWojciech Macek static int 1720bc14c73bSJustin Hibbits al_mq_start(if_t ifp, struct mbuf *m) 17217902c8dcSWojciech Macek { 1722bc14c73bSJustin Hibbits struct al_eth_adapter *adapter = if_getsoftc(ifp); 17237902c8dcSWojciech Macek struct al_eth_ring *tx_ring; 17247902c8dcSWojciech Macek int i; 17257902c8dcSWojciech Macek int ret; 17267902c8dcSWojciech Macek 17277902c8dcSWojciech Macek /* Which queue to use */ 17287902c8dcSWojciech Macek if (M_HASHTYPE_GET(m) != M_HASHTYPE_NONE) 17297902c8dcSWojciech Macek i = m->m_pkthdr.flowid % adapter->num_tx_queues; 17307902c8dcSWojciech Macek else 17317902c8dcSWojciech Macek i = curcpu % adapter->num_tx_queues; 17327902c8dcSWojciech Macek 1733bc14c73bSJustin Hibbits if ((if_getdrvflags(ifp) & (IFF_DRV_RUNNING|IFF_DRV_OACTIVE)) != 17347902c8dcSWojciech Macek IFF_DRV_RUNNING) { 17357902c8dcSWojciech Macek return (EFAULT); 17367902c8dcSWojciech Macek } 17377902c8dcSWojciech Macek 17387902c8dcSWojciech Macek tx_ring = &adapter->tx_ring[i]; 17397902c8dcSWojciech Macek 17407902c8dcSWojciech Macek device_printf_dbg(adapter->dev, "dgb start() - assuming link is active, " 17417902c8dcSWojciech Macek "sending packet to queue %d\n", i); 17427902c8dcSWojciech Macek 17437902c8dcSWojciech Macek ret = drbr_enqueue(ifp, tx_ring->br, m); 17447902c8dcSWojciech Macek 17457902c8dcSWojciech Macek /* 17467902c8dcSWojciech Macek * For napi, if work is not running, schedule it. Always schedule 17477902c8dcSWojciech Macek * for casual (non-napi) packet handling. 17487902c8dcSWojciech Macek */ 17497902c8dcSWojciech Macek if ((napi == 0) || ((napi != 0) && (tx_ring->enqueue_is_running == 0))) 17507902c8dcSWojciech Macek taskqueue_enqueue(tx_ring->enqueue_tq, &tx_ring->enqueue_task); 17517902c8dcSWojciech Macek 17527902c8dcSWojciech Macek return (ret); 17537902c8dcSWojciech Macek } 17547902c8dcSWojciech Macek 17557902c8dcSWojciech Macek static void 1756bc14c73bSJustin Hibbits al_qflush(if_t ifp) 17577902c8dcSWojciech Macek { 17587902c8dcSWojciech Macek 17597902c8dcSWojciech Macek /* unused */ 17607902c8dcSWojciech Macek } 17617902c8dcSWojciech Macek 17627902c8dcSWojciech Macek static inline void 17637902c8dcSWojciech Macek al_eth_flow_ctrl_init(struct al_eth_adapter *adapter) 17647902c8dcSWojciech Macek { 17657902c8dcSWojciech Macek uint8_t default_flow_ctrl; 17667902c8dcSWojciech Macek 17677902c8dcSWojciech Macek default_flow_ctrl = AL_ETH_FLOW_CTRL_TX_PAUSE; 17687902c8dcSWojciech Macek default_flow_ctrl |= AL_ETH_FLOW_CTRL_RX_PAUSE; 17697902c8dcSWojciech Macek 17707902c8dcSWojciech Macek adapter->link_config.flow_ctrl_supported = default_flow_ctrl; 17717902c8dcSWojciech Macek } 17727902c8dcSWojciech Macek 17737902c8dcSWojciech Macek static int 17747902c8dcSWojciech Macek al_eth_flow_ctrl_config(struct al_eth_adapter *adapter) 17757902c8dcSWojciech Macek { 17767902c8dcSWojciech Macek struct al_eth_flow_control_params *flow_ctrl_params; 17777902c8dcSWojciech Macek uint8_t active = adapter->link_config.flow_ctrl_active; 17787902c8dcSWojciech Macek int i; 17797902c8dcSWojciech Macek 17807902c8dcSWojciech Macek flow_ctrl_params = &adapter->flow_ctrl_params; 17817902c8dcSWojciech Macek 17827902c8dcSWojciech Macek flow_ctrl_params->type = AL_ETH_FLOW_CONTROL_TYPE_LINK_PAUSE; 17837902c8dcSWojciech Macek flow_ctrl_params->obay_enable = 17847902c8dcSWojciech Macek ((active & AL_ETH_FLOW_CTRL_RX_PAUSE) != 0); 17857902c8dcSWojciech Macek flow_ctrl_params->gen_enable = 17867902c8dcSWojciech Macek ((active & AL_ETH_FLOW_CTRL_TX_PAUSE) != 0); 17877902c8dcSWojciech Macek 17887902c8dcSWojciech Macek flow_ctrl_params->rx_fifo_th_high = AL_ETH_FLOW_CTRL_RX_FIFO_TH_HIGH; 17897902c8dcSWojciech Macek flow_ctrl_params->rx_fifo_th_low = AL_ETH_FLOW_CTRL_RX_FIFO_TH_LOW; 17907902c8dcSWojciech Macek flow_ctrl_params->quanta = AL_ETH_FLOW_CTRL_QUANTA; 17917902c8dcSWojciech Macek flow_ctrl_params->quanta_th = AL_ETH_FLOW_CTRL_QUANTA_TH; 17927902c8dcSWojciech Macek 17937902c8dcSWojciech Macek /* map priority to queue index, queue id = priority/2 */ 17947902c8dcSWojciech Macek for (i = 0; i < AL_ETH_FWD_PRIO_TABLE_NUM; i++) 17957902c8dcSWojciech Macek flow_ctrl_params->prio_q_map[0][i] = 1 << (i >> 1); 17967902c8dcSWojciech Macek 17977902c8dcSWojciech Macek al_eth_flow_control_config(&adapter->hal_adapter, flow_ctrl_params); 17987902c8dcSWojciech Macek 17997902c8dcSWojciech Macek return (0); 18007902c8dcSWojciech Macek } 18017902c8dcSWojciech Macek 18027902c8dcSWojciech Macek static void 18037902c8dcSWojciech Macek al_eth_flow_ctrl_enable(struct al_eth_adapter *adapter) 18047902c8dcSWojciech Macek { 18057902c8dcSWojciech Macek 18067902c8dcSWojciech Macek /* 18077902c8dcSWojciech Macek * change the active configuration to the default / force by ethtool 18087902c8dcSWojciech Macek * and call to configure 18097902c8dcSWojciech Macek */ 18107902c8dcSWojciech Macek adapter->link_config.flow_ctrl_active = 18117902c8dcSWojciech Macek adapter->link_config.flow_ctrl_supported; 18127902c8dcSWojciech Macek 18137902c8dcSWojciech Macek al_eth_flow_ctrl_config(adapter); 18147902c8dcSWojciech Macek } 18157902c8dcSWojciech Macek 18167902c8dcSWojciech Macek static void 18177902c8dcSWojciech Macek al_eth_flow_ctrl_disable(struct al_eth_adapter *adapter) 18187902c8dcSWojciech Macek { 18197902c8dcSWojciech Macek 18207902c8dcSWojciech Macek adapter->link_config.flow_ctrl_active = 0; 18217902c8dcSWojciech Macek al_eth_flow_ctrl_config(adapter); 18227902c8dcSWojciech Macek } 18237902c8dcSWojciech Macek 18247902c8dcSWojciech Macek static int 18257902c8dcSWojciech Macek al_eth_hw_init(struct al_eth_adapter *adapter) 18267902c8dcSWojciech Macek { 18277902c8dcSWojciech Macek int rc; 18287902c8dcSWojciech Macek 18297902c8dcSWojciech Macek rc = al_eth_hw_init_adapter(adapter); 18307902c8dcSWojciech Macek if (rc != 0) 18317902c8dcSWojciech Macek return (rc); 18327902c8dcSWojciech Macek 18337902c8dcSWojciech Macek rc = al_eth_mac_config(&adapter->hal_adapter, adapter->mac_mode); 18347902c8dcSWojciech Macek if (rc < 0) { 18357902c8dcSWojciech Macek device_printf(adapter->dev, "%s failed to configure mac!\n", 18367902c8dcSWojciech Macek __func__); 18377902c8dcSWojciech Macek return (rc); 18387902c8dcSWojciech Macek } 18397902c8dcSWojciech Macek 18407902c8dcSWojciech Macek if ((adapter->mac_mode == AL_ETH_MAC_MODE_SGMII) || 18417902c8dcSWojciech Macek (adapter->mac_mode == AL_ETH_MAC_MODE_RGMII && 1842463edaf4SJohn Baldwin adapter->phy_exist == false)) { 18437902c8dcSWojciech Macek rc = al_eth_mac_link_config(&adapter->hal_adapter, 18447902c8dcSWojciech Macek adapter->link_config.force_1000_base_x, 18457902c8dcSWojciech Macek adapter->link_config.autoneg, 18467902c8dcSWojciech Macek adapter->link_config.active_speed, 18477902c8dcSWojciech Macek adapter->link_config.active_duplex); 18487902c8dcSWojciech Macek if (rc != 0) { 18497902c8dcSWojciech Macek device_printf(adapter->dev, 18507902c8dcSWojciech Macek "%s failed to configure link parameters!\n", 18517902c8dcSWojciech Macek __func__); 18527902c8dcSWojciech Macek return (rc); 18537902c8dcSWojciech Macek } 18547902c8dcSWojciech Macek } 18557902c8dcSWojciech Macek 18567902c8dcSWojciech Macek rc = al_eth_mdio_config(&adapter->hal_adapter, 1857463edaf4SJohn Baldwin AL_ETH_MDIO_TYPE_CLAUSE_22, AL_TRUE /* shared_mdio_if */, 18587902c8dcSWojciech Macek adapter->ref_clk_freq, adapter->mdio_freq); 18597902c8dcSWojciech Macek if (rc != 0) { 18607902c8dcSWojciech Macek device_printf(adapter->dev, "%s failed at mdio config!\n", 18617902c8dcSWojciech Macek __func__); 18627902c8dcSWojciech Macek return (rc); 18637902c8dcSWojciech Macek } 18647902c8dcSWojciech Macek 18657902c8dcSWojciech Macek al_eth_flow_ctrl_init(adapter); 18667902c8dcSWojciech Macek 18677902c8dcSWojciech Macek return (rc); 18687902c8dcSWojciech Macek } 18697902c8dcSWojciech Macek 18707902c8dcSWojciech Macek static int 18717902c8dcSWojciech Macek al_eth_hw_stop(struct al_eth_adapter *adapter) 18727902c8dcSWojciech Macek { 18737902c8dcSWojciech Macek 18747902c8dcSWojciech Macek al_eth_mac_stop(&adapter->hal_adapter); 18757902c8dcSWojciech Macek 18767902c8dcSWojciech Macek /* 18777902c8dcSWojciech Macek * wait till pending rx packets written and UDMA becomes idle, 187845b143d2SGordon Bergling * the MAC has ~10KB fifo, 10us should be enough time for the 18797902c8dcSWojciech Macek * UDMA to write to the memory 18807902c8dcSWojciech Macek */ 18817902c8dcSWojciech Macek DELAY(10); 18827902c8dcSWojciech Macek 18837902c8dcSWojciech Macek al_eth_adapter_stop(&adapter->hal_adapter); 18847902c8dcSWojciech Macek 18857902c8dcSWojciech Macek adapter->flags |= AL_ETH_FLAG_RESET_REQUESTED; 18867902c8dcSWojciech Macek 18877902c8dcSWojciech Macek /* disable flow ctrl to avoid pause packets*/ 18887902c8dcSWojciech Macek al_eth_flow_ctrl_disable(adapter); 18897902c8dcSWojciech Macek 18907902c8dcSWojciech Macek return (0); 18917902c8dcSWojciech Macek } 18927902c8dcSWojciech Macek 18937902c8dcSWojciech Macek /* 18947902c8dcSWojciech Macek * al_eth_intr_intx_all - Legacy Interrupt Handler for all interrupts 18957902c8dcSWojciech Macek * @irq: interrupt number 18967902c8dcSWojciech Macek * @data: pointer to a network interface device structure 18977902c8dcSWojciech Macek */ 18987902c8dcSWojciech Macek static int 18997902c8dcSWojciech Macek al_eth_intr_intx_all(void *data) 19007902c8dcSWojciech Macek { 19017902c8dcSWojciech Macek struct al_eth_adapter *adapter = data; 19027902c8dcSWojciech Macek 19037902c8dcSWojciech Macek struct unit_regs __iomem *regs_base = 19047902c8dcSWojciech Macek (struct unit_regs __iomem *)adapter->udma_base; 19057902c8dcSWojciech Macek uint32_t reg; 19067902c8dcSWojciech Macek 19077902c8dcSWojciech Macek reg = al_udma_iofic_read_cause(regs_base, AL_UDMA_IOFIC_LEVEL_PRIMARY, 19087902c8dcSWojciech Macek AL_INT_GROUP_A); 19097902c8dcSWojciech Macek if (likely(reg)) 19107902c8dcSWojciech Macek device_printf_dbg(adapter->dev, "%s group A cause %x\n", 19117902c8dcSWojciech Macek __func__, reg); 19127902c8dcSWojciech Macek 19137902c8dcSWojciech Macek if (unlikely(reg & AL_INT_GROUP_A_GROUP_D_SUM)) { 19147902c8dcSWojciech Macek struct al_iofic_grp_ctrl __iomem *sec_ints_base; 19157902c8dcSWojciech Macek uint32_t cause_d = al_udma_iofic_read_cause(regs_base, 19167902c8dcSWojciech Macek AL_UDMA_IOFIC_LEVEL_PRIMARY, AL_INT_GROUP_D); 19177902c8dcSWojciech Macek 19187902c8dcSWojciech Macek sec_ints_base = 19197902c8dcSWojciech Macek ®s_base->gen.interrupt_regs.secondary_iofic_ctrl[0]; 19207902c8dcSWojciech Macek if (cause_d != 0) { 19217902c8dcSWojciech Macek device_printf_dbg(adapter->dev, 19227902c8dcSWojciech Macek "got interrupt from group D. cause %x\n", cause_d); 19237902c8dcSWojciech Macek 19247902c8dcSWojciech Macek cause_d = al_iofic_read_cause(sec_ints_base, 19257902c8dcSWojciech Macek AL_INT_GROUP_A); 19267902c8dcSWojciech Macek device_printf(adapter->dev, 19277902c8dcSWojciech Macek "secondary A cause %x\n", cause_d); 19287902c8dcSWojciech Macek 19297902c8dcSWojciech Macek cause_d = al_iofic_read_cause(sec_ints_base, 19307902c8dcSWojciech Macek AL_INT_GROUP_B); 19317902c8dcSWojciech Macek 19327902c8dcSWojciech Macek device_printf_dbg(adapter->dev, 19337902c8dcSWojciech Macek "secondary B cause %x\n", cause_d); 19347902c8dcSWojciech Macek } 19357902c8dcSWojciech Macek } 19367902c8dcSWojciech Macek if ((reg & AL_INT_GROUP_A_GROUP_B_SUM) != 0 ) { 19377902c8dcSWojciech Macek uint32_t cause_b = al_udma_iofic_read_cause(regs_base, 19387902c8dcSWojciech Macek AL_UDMA_IOFIC_LEVEL_PRIMARY, AL_INT_GROUP_B); 19397902c8dcSWojciech Macek int qid; 19407902c8dcSWojciech Macek device_printf_dbg(adapter->dev, "secondary B cause %x\n", 19417902c8dcSWojciech Macek cause_b); 19427902c8dcSWojciech Macek for (qid = 0; qid < adapter->num_rx_queues; qid++) { 19437902c8dcSWojciech Macek if (cause_b & (1 << qid)) { 19447902c8dcSWojciech Macek /* mask */ 19457902c8dcSWojciech Macek al_udma_iofic_mask( 19467902c8dcSWojciech Macek (struct unit_regs __iomem *)adapter->udma_base, 19477902c8dcSWojciech Macek AL_UDMA_IOFIC_LEVEL_PRIMARY, 19487902c8dcSWojciech Macek AL_INT_GROUP_B, 1 << qid); 19497902c8dcSWojciech Macek } 19507902c8dcSWojciech Macek } 19517902c8dcSWojciech Macek } 19527902c8dcSWojciech Macek if ((reg & AL_INT_GROUP_A_GROUP_C_SUM) != 0) { 19537902c8dcSWojciech Macek uint32_t cause_c = al_udma_iofic_read_cause(regs_base, 19547902c8dcSWojciech Macek AL_UDMA_IOFIC_LEVEL_PRIMARY, AL_INT_GROUP_C); 19557902c8dcSWojciech Macek int qid; 19567902c8dcSWojciech Macek device_printf_dbg(adapter->dev, "secondary C cause %x\n", cause_c); 19577902c8dcSWojciech Macek for (qid = 0; qid < adapter->num_tx_queues; qid++) { 19587902c8dcSWojciech Macek if ((cause_c & (1 << qid)) != 0) { 19597902c8dcSWojciech Macek al_udma_iofic_mask( 19607902c8dcSWojciech Macek (struct unit_regs __iomem *)adapter->udma_base, 19617902c8dcSWojciech Macek AL_UDMA_IOFIC_LEVEL_PRIMARY, 19627902c8dcSWojciech Macek AL_INT_GROUP_C, 1 << qid); 19637902c8dcSWojciech Macek } 19647902c8dcSWojciech Macek } 19657902c8dcSWojciech Macek } 19667902c8dcSWojciech Macek 19677902c8dcSWojciech Macek al_eth_tx_cmlp_irq_filter(adapter->tx_ring); 19687902c8dcSWojciech Macek 19697902c8dcSWojciech Macek return (0); 19707902c8dcSWojciech Macek } 19717902c8dcSWojciech Macek 19727902c8dcSWojciech Macek static int 19737902c8dcSWojciech Macek al_eth_intr_msix_all(void *data) 19747902c8dcSWojciech Macek { 19757902c8dcSWojciech Macek struct al_eth_adapter *adapter = data; 19767902c8dcSWojciech Macek 19777902c8dcSWojciech Macek device_printf_dbg(adapter->dev, "%s\n", __func__); 19787902c8dcSWojciech Macek return (0); 19797902c8dcSWojciech Macek } 19807902c8dcSWojciech Macek 19817902c8dcSWojciech Macek static int 19827902c8dcSWojciech Macek al_eth_intr_msix_mgmt(void *data) 19837902c8dcSWojciech Macek { 19847902c8dcSWojciech Macek struct al_eth_adapter *adapter = data; 19857902c8dcSWojciech Macek 19867902c8dcSWojciech Macek device_printf_dbg(adapter->dev, "%s\n", __func__); 19877902c8dcSWojciech Macek return (0); 19887902c8dcSWojciech Macek } 19897902c8dcSWojciech Macek 19907902c8dcSWojciech Macek static int 19917902c8dcSWojciech Macek al_eth_enable_msix(struct al_eth_adapter *adapter) 19927902c8dcSWojciech Macek { 19937902c8dcSWojciech Macek int i, msix_vecs, rc, count; 19947902c8dcSWojciech Macek 19957902c8dcSWojciech Macek device_printf_dbg(adapter->dev, "%s\n", __func__); 19967902c8dcSWojciech Macek msix_vecs = 1 + adapter->num_rx_queues + adapter->num_tx_queues; 19977902c8dcSWojciech Macek 19987902c8dcSWojciech Macek device_printf_dbg(adapter->dev, 19997902c8dcSWojciech Macek "Try to enable MSIX, vector numbers = %d\n", msix_vecs); 20007902c8dcSWojciech Macek 20017902c8dcSWojciech Macek adapter->msix_entries = malloc(msix_vecs*sizeof(*adapter->msix_entries), 20027902c8dcSWojciech Macek M_IFAL, M_ZERO | M_WAITOK); 20037902c8dcSWojciech Macek /* management vector (GROUP_A) @2*/ 20047902c8dcSWojciech Macek adapter->msix_entries[AL_ETH_MGMT_IRQ_IDX].entry = 2; 20057902c8dcSWojciech Macek adapter->msix_entries[AL_ETH_MGMT_IRQ_IDX].vector = 0; 20067902c8dcSWojciech Macek 20077902c8dcSWojciech Macek /* rx queues start @3 */ 20087902c8dcSWojciech Macek for (i = 0; i < adapter->num_rx_queues; i++) { 20097902c8dcSWojciech Macek int irq_idx = AL_ETH_RXQ_IRQ_IDX(adapter, i); 20107902c8dcSWojciech Macek 20117902c8dcSWojciech Macek adapter->msix_entries[irq_idx].entry = 3 + i; 20127902c8dcSWojciech Macek adapter->msix_entries[irq_idx].vector = 0; 20137902c8dcSWojciech Macek } 20147902c8dcSWojciech Macek /* tx queues start @7 */ 20157902c8dcSWojciech Macek for (i = 0; i < adapter->num_tx_queues; i++) { 20167902c8dcSWojciech Macek int irq_idx = AL_ETH_TXQ_IRQ_IDX(adapter, i); 20177902c8dcSWojciech Macek 20187902c8dcSWojciech Macek adapter->msix_entries[irq_idx].entry = 3 + 20197902c8dcSWojciech Macek AL_ETH_MAX_HW_QUEUES + i; 20207902c8dcSWojciech Macek adapter->msix_entries[irq_idx].vector = 0; 20217902c8dcSWojciech Macek } 20227902c8dcSWojciech Macek 20237902c8dcSWojciech Macek count = msix_vecs + 2; /* entries start from 2 */ 20247902c8dcSWojciech Macek rc = pci_alloc_msix(adapter->dev, &count); 20257902c8dcSWojciech Macek 20267902c8dcSWojciech Macek if (rc != 0) { 20277902c8dcSWojciech Macek device_printf_dbg(adapter->dev, "failed to allocate MSIX " 20287902c8dcSWojciech Macek "vectors %d\n", msix_vecs+2); 20297902c8dcSWojciech Macek device_printf_dbg(adapter->dev, "ret = %d\n", rc); 20307902c8dcSWojciech Macek goto msix_entries_exit; 20317902c8dcSWojciech Macek } 20327902c8dcSWojciech Macek 20337902c8dcSWojciech Macek if (count != msix_vecs + 2) { 20347902c8dcSWojciech Macek device_printf_dbg(adapter->dev, "failed to allocate all MSIX " 20357902c8dcSWojciech Macek "vectors %d, allocated %d\n", msix_vecs+2, count); 20367902c8dcSWojciech Macek rc = ENOSPC; 20377902c8dcSWojciech Macek goto msix_entries_exit; 20387902c8dcSWojciech Macek } 20397902c8dcSWojciech Macek 20407902c8dcSWojciech Macek for (i = 0; i < msix_vecs; i++) 20417902c8dcSWojciech Macek adapter->msix_entries[i].vector = 2 + 1 + i; 20427902c8dcSWojciech Macek 20437902c8dcSWojciech Macek device_printf_dbg(adapter->dev, "successfully enabled MSIX," 20447902c8dcSWojciech Macek " vectors %d\n", msix_vecs); 20457902c8dcSWojciech Macek 20467902c8dcSWojciech Macek adapter->msix_vecs = msix_vecs; 20477902c8dcSWojciech Macek adapter->flags |= AL_ETH_FLAG_MSIX_ENABLED; 20487902c8dcSWojciech Macek goto exit; 20497902c8dcSWojciech Macek 20507902c8dcSWojciech Macek msix_entries_exit: 20517902c8dcSWojciech Macek adapter->msix_vecs = 0; 20527902c8dcSWojciech Macek free(adapter->msix_entries, M_IFAL); 20537902c8dcSWojciech Macek adapter->msix_entries = NULL; 20547902c8dcSWojciech Macek 20557902c8dcSWojciech Macek exit: 20567902c8dcSWojciech Macek return (rc); 20577902c8dcSWojciech Macek } 20587902c8dcSWojciech Macek 20597902c8dcSWojciech Macek static int 20607902c8dcSWojciech Macek al_eth_setup_int_mode(struct al_eth_adapter *adapter) 20617902c8dcSWojciech Macek { 20627902c8dcSWojciech Macek int i, rc; 20637902c8dcSWojciech Macek 20647902c8dcSWojciech Macek rc = al_eth_enable_msix(adapter); 20657902c8dcSWojciech Macek if (rc != 0) { 20667902c8dcSWojciech Macek device_printf(adapter->dev, "Failed to enable MSIX mode.\n"); 20677902c8dcSWojciech Macek return (rc); 20687902c8dcSWojciech Macek } 20697902c8dcSWojciech Macek 20707902c8dcSWojciech Macek adapter->irq_vecs = max(1, adapter->msix_vecs); 20717902c8dcSWojciech Macek /* single INTX mode */ 20727902c8dcSWojciech Macek if (adapter->msix_vecs == 0) { 20737902c8dcSWojciech Macek snprintf(adapter->irq_tbl[AL_ETH_MGMT_IRQ_IDX].name, 20747902c8dcSWojciech Macek AL_ETH_IRQNAME_SIZE, "al-eth-intx-all@pci:%s", 20757902c8dcSWojciech Macek device_get_name(adapter->dev)); 20767902c8dcSWojciech Macek adapter->irq_tbl[AL_ETH_MGMT_IRQ_IDX].handler = 20777902c8dcSWojciech Macek al_eth_intr_intx_all; 20787902c8dcSWojciech Macek /* IRQ vector will be resolved from device resources */ 20797902c8dcSWojciech Macek adapter->irq_tbl[AL_ETH_MGMT_IRQ_IDX].vector = 0; 20807902c8dcSWojciech Macek adapter->irq_tbl[AL_ETH_MGMT_IRQ_IDX].data = adapter; 20817902c8dcSWojciech Macek 20827902c8dcSWojciech Macek device_printf(adapter->dev, "%s and vector %d \n", __func__, 20837902c8dcSWojciech Macek adapter->irq_tbl[AL_ETH_MGMT_IRQ_IDX].vector); 20847902c8dcSWojciech Macek 20857902c8dcSWojciech Macek return (0); 20867902c8dcSWojciech Macek } 20877902c8dcSWojciech Macek /* single MSI-X mode */ 20887902c8dcSWojciech Macek if (adapter->msix_vecs == 1) { 20897902c8dcSWojciech Macek snprintf(adapter->irq_tbl[AL_ETH_MGMT_IRQ_IDX].name, 20907902c8dcSWojciech Macek AL_ETH_IRQNAME_SIZE, "al-eth-msix-all@pci:%s", 20917902c8dcSWojciech Macek device_get_name(adapter->dev)); 20927902c8dcSWojciech Macek adapter->irq_tbl[AL_ETH_MGMT_IRQ_IDX].handler = 20937902c8dcSWojciech Macek al_eth_intr_msix_all; 20947902c8dcSWojciech Macek adapter->irq_tbl[AL_ETH_MGMT_IRQ_IDX].vector = 20957902c8dcSWojciech Macek adapter->msix_entries[AL_ETH_MGMT_IRQ_IDX].vector; 20967902c8dcSWojciech Macek adapter->irq_tbl[AL_ETH_MGMT_IRQ_IDX].data = adapter; 20977902c8dcSWojciech Macek 20987902c8dcSWojciech Macek return (0); 20997902c8dcSWojciech Macek } 21007902c8dcSWojciech Macek /* MSI-X per queue */ 21017902c8dcSWojciech Macek snprintf(adapter->irq_tbl[AL_ETH_MGMT_IRQ_IDX].name, AL_ETH_IRQNAME_SIZE, 21027902c8dcSWojciech Macek "al-eth-msix-mgmt@pci:%s", device_get_name(adapter->dev)); 21037902c8dcSWojciech Macek adapter->irq_tbl[AL_ETH_MGMT_IRQ_IDX].handler = al_eth_intr_msix_mgmt; 21047902c8dcSWojciech Macek 21057902c8dcSWojciech Macek adapter->irq_tbl[AL_ETH_MGMT_IRQ_IDX].data = adapter; 21067902c8dcSWojciech Macek adapter->irq_tbl[AL_ETH_MGMT_IRQ_IDX].vector = 21077902c8dcSWojciech Macek adapter->msix_entries[AL_ETH_MGMT_IRQ_IDX].vector; 21087902c8dcSWojciech Macek 21097902c8dcSWojciech Macek for (i = 0; i < adapter->num_rx_queues; i++) { 21107902c8dcSWojciech Macek int irq_idx = AL_ETH_RXQ_IRQ_IDX(adapter, i); 21117902c8dcSWojciech Macek 21127902c8dcSWojciech Macek snprintf(adapter->irq_tbl[irq_idx].name, AL_ETH_IRQNAME_SIZE, 21137902c8dcSWojciech Macek "al-eth-rx-comp-%d@pci:%s", i, 21147902c8dcSWojciech Macek device_get_name(adapter->dev)); 21157902c8dcSWojciech Macek adapter->irq_tbl[irq_idx].handler = al_eth_rx_recv_irq_filter; 21167902c8dcSWojciech Macek adapter->irq_tbl[irq_idx].data = &adapter->rx_ring[i]; 21177902c8dcSWojciech Macek adapter->irq_tbl[irq_idx].vector = 21187902c8dcSWojciech Macek adapter->msix_entries[irq_idx].vector; 21197902c8dcSWojciech Macek } 21207902c8dcSWojciech Macek 21217902c8dcSWojciech Macek for (i = 0; i < adapter->num_tx_queues; i++) { 21227902c8dcSWojciech Macek int irq_idx = AL_ETH_TXQ_IRQ_IDX(adapter, i); 21237902c8dcSWojciech Macek 21247902c8dcSWojciech Macek snprintf(adapter->irq_tbl[irq_idx].name, 21257902c8dcSWojciech Macek AL_ETH_IRQNAME_SIZE, "al-eth-tx-comp-%d@pci:%s", i, 21267902c8dcSWojciech Macek device_get_name(adapter->dev)); 21277902c8dcSWojciech Macek adapter->irq_tbl[irq_idx].handler = al_eth_tx_cmlp_irq_filter; 21287902c8dcSWojciech Macek adapter->irq_tbl[irq_idx].data = &adapter->tx_ring[i]; 21297902c8dcSWojciech Macek adapter->irq_tbl[irq_idx].vector = 21307902c8dcSWojciech Macek adapter->msix_entries[irq_idx].vector; 21317902c8dcSWojciech Macek } 21327902c8dcSWojciech Macek 21337902c8dcSWojciech Macek return (0); 21347902c8dcSWojciech Macek } 21357902c8dcSWojciech Macek 21367902c8dcSWojciech Macek static void 21377902c8dcSWojciech Macek __al_eth_free_irq(struct al_eth_adapter *adapter) 21387902c8dcSWojciech Macek { 21397902c8dcSWojciech Macek struct al_eth_irq *irq; 21407902c8dcSWojciech Macek int i, rc; 21417902c8dcSWojciech Macek 21427902c8dcSWojciech Macek for (i = 0; i < adapter->irq_vecs; i++) { 21437902c8dcSWojciech Macek irq = &adapter->irq_tbl[i]; 21447902c8dcSWojciech Macek if (irq->requested != 0) { 21457902c8dcSWojciech Macek device_printf_dbg(adapter->dev, "tear down irq: %d\n", 21467902c8dcSWojciech Macek irq->vector); 21477902c8dcSWojciech Macek rc = bus_teardown_intr(adapter->dev, irq->res, 21487902c8dcSWojciech Macek irq->cookie); 21497902c8dcSWojciech Macek if (rc != 0) 21507902c8dcSWojciech Macek device_printf(adapter->dev, "failed to tear " 21517902c8dcSWojciech Macek "down irq: %d\n", irq->vector); 21527902c8dcSWojciech Macek } 21537902c8dcSWojciech Macek irq->requested = 0; 21547902c8dcSWojciech Macek } 21557902c8dcSWojciech Macek } 21567902c8dcSWojciech Macek 21577902c8dcSWojciech Macek static void 21587902c8dcSWojciech Macek al_eth_free_irq(struct al_eth_adapter *adapter) 21597902c8dcSWojciech Macek { 21607902c8dcSWojciech Macek struct al_eth_irq *irq; 21617902c8dcSWojciech Macek int i, rc; 21627902c8dcSWojciech Macek #ifdef CONFIG_RFS_ACCEL 21637902c8dcSWojciech Macek if (adapter->msix_vecs >= 1) { 21647902c8dcSWojciech Macek free_irq_cpu_rmap(adapter->netdev->rx_cpu_rmap); 21657902c8dcSWojciech Macek adapter->netdev->rx_cpu_rmap = NULL; 21667902c8dcSWojciech Macek } 21677902c8dcSWojciech Macek #endif 21687902c8dcSWojciech Macek 21697902c8dcSWojciech Macek __al_eth_free_irq(adapter); 21707902c8dcSWojciech Macek 21717902c8dcSWojciech Macek for (i = 0; i < adapter->irq_vecs; i++) { 21727902c8dcSWojciech Macek irq = &adapter->irq_tbl[i]; 21737902c8dcSWojciech Macek if (irq->res == NULL) 21747902c8dcSWojciech Macek continue; 21757902c8dcSWojciech Macek device_printf_dbg(adapter->dev, "release resource irq: %d\n", 21767902c8dcSWojciech Macek irq->vector); 21777902c8dcSWojciech Macek rc = bus_release_resource(adapter->dev, SYS_RES_IRQ, irq->vector, 21787902c8dcSWojciech Macek irq->res); 21797902c8dcSWojciech Macek irq->res = NULL; 21807902c8dcSWojciech Macek if (rc != 0) 21817902c8dcSWojciech Macek device_printf(adapter->dev, "dev has no parent while " 21827902c8dcSWojciech Macek "releasing res for irq: %d\n", irq->vector); 21837902c8dcSWojciech Macek } 21847902c8dcSWojciech Macek 21857902c8dcSWojciech Macek pci_release_msi(adapter->dev); 21867902c8dcSWojciech Macek 21877902c8dcSWojciech Macek adapter->flags &= ~AL_ETH_FLAG_MSIX_ENABLED; 21887902c8dcSWojciech Macek 21897902c8dcSWojciech Macek adapter->msix_vecs = 0; 21907902c8dcSWojciech Macek free(adapter->msix_entries, M_IFAL); 21917902c8dcSWojciech Macek adapter->msix_entries = NULL; 21927902c8dcSWojciech Macek } 21937902c8dcSWojciech Macek 21947902c8dcSWojciech Macek static int 21957902c8dcSWojciech Macek al_eth_request_irq(struct al_eth_adapter *adapter) 21967902c8dcSWojciech Macek { 21977902c8dcSWojciech Macek unsigned long flags; 21987902c8dcSWojciech Macek struct al_eth_irq *irq; 21997902c8dcSWojciech Macek int rc = 0, i, v; 22007902c8dcSWojciech Macek 22017902c8dcSWojciech Macek if ((adapter->flags & AL_ETH_FLAG_MSIX_ENABLED) != 0) 22027902c8dcSWojciech Macek flags = RF_ACTIVE; 22037902c8dcSWojciech Macek else 22047902c8dcSWojciech Macek flags = RF_ACTIVE | RF_SHAREABLE; 22057902c8dcSWojciech Macek 22067902c8dcSWojciech Macek for (i = 0; i < adapter->irq_vecs; i++) { 22077902c8dcSWojciech Macek irq = &adapter->irq_tbl[i]; 22087902c8dcSWojciech Macek 22097902c8dcSWojciech Macek if (irq->requested != 0) 22107902c8dcSWojciech Macek continue; 22117902c8dcSWojciech Macek 22127902c8dcSWojciech Macek irq->res = bus_alloc_resource_any(adapter->dev, SYS_RES_IRQ, 22137902c8dcSWojciech Macek &irq->vector, flags); 22147902c8dcSWojciech Macek if (irq->res == NULL) { 22157902c8dcSWojciech Macek device_printf(adapter->dev, "could not allocate " 22167902c8dcSWojciech Macek "irq vector=%d\n", irq->vector); 22177902c8dcSWojciech Macek rc = ENXIO; 22187902c8dcSWojciech Macek goto exit_res; 22197902c8dcSWojciech Macek } 22207902c8dcSWojciech Macek 22217902c8dcSWojciech Macek if ((rc = bus_setup_intr(adapter->dev, irq->res, 22227902c8dcSWojciech Macek INTR_TYPE_NET | INTR_MPSAFE, irq->handler, 22237902c8dcSWojciech Macek NULL, irq->data, &irq->cookie)) != 0) { 22247902c8dcSWojciech Macek device_printf(adapter->dev, "failed to register " 22257902c8dcSWojciech Macek "interrupt handler for irq %ju: %d\n", 22267902c8dcSWojciech Macek (uintmax_t)rman_get_start(irq->res), rc); 22277902c8dcSWojciech Macek goto exit_intr; 22287902c8dcSWojciech Macek } 22297902c8dcSWojciech Macek irq->requested = 1; 22307902c8dcSWojciech Macek } 22317902c8dcSWojciech Macek goto exit; 22327902c8dcSWojciech Macek 22337902c8dcSWojciech Macek exit_intr: 22347902c8dcSWojciech Macek v = i - 1; /* -1 because we omit the operation that failed */ 22357902c8dcSWojciech Macek while (v-- >= 0) { 22367902c8dcSWojciech Macek int bti; 22377902c8dcSWojciech Macek irq = &adapter->irq_tbl[v]; 22387902c8dcSWojciech Macek bti = bus_teardown_intr(adapter->dev, irq->res, irq->cookie); 22397902c8dcSWojciech Macek if (bti != 0) { 22407902c8dcSWojciech Macek device_printf(adapter->dev, "failed to tear " 22417902c8dcSWojciech Macek "down irq: %d\n", irq->vector); 22427902c8dcSWojciech Macek } 22437902c8dcSWojciech Macek 22447902c8dcSWojciech Macek irq->requested = 0; 22457902c8dcSWojciech Macek device_printf_dbg(adapter->dev, "exit_intr: releasing irq %d\n", 22467902c8dcSWojciech Macek irq->vector); 22477902c8dcSWojciech Macek } 22487902c8dcSWojciech Macek 22497902c8dcSWojciech Macek exit_res: 22507902c8dcSWojciech Macek v = i - 1; /* -1 because we omit the operation that failed */ 22517902c8dcSWojciech Macek while (v-- >= 0) { 22527902c8dcSWojciech Macek int brr; 22537902c8dcSWojciech Macek irq = &adapter->irq_tbl[v]; 22547902c8dcSWojciech Macek device_printf_dbg(adapter->dev, "exit_res: releasing resource" 22557902c8dcSWojciech Macek " for irq %d\n", irq->vector); 22567902c8dcSWojciech Macek brr = bus_release_resource(adapter->dev, SYS_RES_IRQ, 22577902c8dcSWojciech Macek irq->vector, irq->res); 22587902c8dcSWojciech Macek if (brr != 0) 22597902c8dcSWojciech Macek device_printf(adapter->dev, "dev has no parent while " 22607902c8dcSWojciech Macek "releasing res for irq: %d\n", irq->vector); 22617902c8dcSWojciech Macek irq->res = NULL; 22627902c8dcSWojciech Macek } 22637902c8dcSWojciech Macek 22647902c8dcSWojciech Macek exit: 22657902c8dcSWojciech Macek return (rc); 22667902c8dcSWojciech Macek } 22677902c8dcSWojciech Macek 22687902c8dcSWojciech Macek /** 22697902c8dcSWojciech Macek * al_eth_setup_tx_resources - allocate Tx resources (Descriptors) 22707902c8dcSWojciech Macek * @adapter: network interface device structure 22717902c8dcSWojciech Macek * @qid: queue index 22727902c8dcSWojciech Macek * 22737902c8dcSWojciech Macek * Return 0 on success, negative on failure 22747902c8dcSWojciech Macek **/ 22757902c8dcSWojciech Macek static int 22767902c8dcSWojciech Macek al_eth_setup_tx_resources(struct al_eth_adapter *adapter, int qid) 22777902c8dcSWojciech Macek { 22787902c8dcSWojciech Macek struct al_eth_ring *tx_ring = &adapter->tx_ring[qid]; 2279d8b1601dSMark Johnston device_t dev = tx_ring->dev; 22807902c8dcSWojciech Macek struct al_udma_q_params *q_params = &tx_ring->q_params; 22817902c8dcSWojciech Macek int size; 22827902c8dcSWojciech Macek int ret; 22837902c8dcSWojciech Macek 22847902c8dcSWojciech Macek if (adapter->up) 22857902c8dcSWojciech Macek return (0); 22867902c8dcSWojciech Macek 22877902c8dcSWojciech Macek size = sizeof(struct al_eth_tx_buffer) * tx_ring->sw_count; 22887902c8dcSWojciech Macek 22897902c8dcSWojciech Macek tx_ring->tx_buffer_info = malloc(size, M_IFAL, M_ZERO | M_WAITOK); 22907902c8dcSWojciech Macek tx_ring->descs_size = tx_ring->hw_count * sizeof(union al_udma_desc); 22917902c8dcSWojciech Macek q_params->size = tx_ring->hw_count; 22927902c8dcSWojciech Macek 22937902c8dcSWojciech Macek ret = al_dma_alloc_coherent(dev, &q_params->desc_phy_base_tag, 22947902c8dcSWojciech Macek (bus_dmamap_t *)&q_params->desc_phy_base_map, 22957902c8dcSWojciech Macek (bus_addr_t *)&q_params->desc_phy_base, 22967902c8dcSWojciech Macek (void**)&q_params->desc_base, tx_ring->descs_size); 22977902c8dcSWojciech Macek if (ret != 0) { 22987902c8dcSWojciech Macek device_printf(dev, "failed to al_dma_alloc_coherent," 22997902c8dcSWojciech Macek " ret = %d\n", ret); 23007902c8dcSWojciech Macek return (ENOMEM); 23017902c8dcSWojciech Macek } 23027902c8dcSWojciech Macek 23037902c8dcSWojciech Macek if (q_params->desc_base == NULL) 23047902c8dcSWojciech Macek return (ENOMEM); 23057902c8dcSWojciech Macek 23067902c8dcSWojciech Macek device_printf_dbg(dev, "Initializing ring queues %d\n", qid); 23077902c8dcSWojciech Macek 23087902c8dcSWojciech Macek /* Allocate Ring Queue */ 23097902c8dcSWojciech Macek mtx_init(&tx_ring->br_mtx, "AlRingMtx", NULL, MTX_DEF); 23107902c8dcSWojciech Macek tx_ring->br = buf_ring_alloc(AL_BR_SIZE, M_DEVBUF, M_WAITOK, 23117902c8dcSWojciech Macek &tx_ring->br_mtx); 23127902c8dcSWojciech Macek 23137902c8dcSWojciech Macek /* Allocate taskqueues */ 23147902c8dcSWojciech Macek TASK_INIT(&tx_ring->enqueue_task, 0, al_eth_start_xmit, tx_ring); 23157902c8dcSWojciech Macek tx_ring->enqueue_tq = taskqueue_create_fast("al_tx_enque", M_NOWAIT, 23167902c8dcSWojciech Macek taskqueue_thread_enqueue, &tx_ring->enqueue_tq); 23177902c8dcSWojciech Macek taskqueue_start_threads(&tx_ring->enqueue_tq, 1, PI_NET, "%s txeq", 23187902c8dcSWojciech Macek device_get_nameunit(adapter->dev)); 23197902c8dcSWojciech Macek TASK_INIT(&tx_ring->cmpl_task, 0, al_eth_tx_cmpl_work, tx_ring); 23207902c8dcSWojciech Macek tx_ring->cmpl_tq = taskqueue_create_fast("al_tx_cmpl", M_NOWAIT, 23217902c8dcSWojciech Macek taskqueue_thread_enqueue, &tx_ring->cmpl_tq); 23227902c8dcSWojciech Macek taskqueue_start_threads(&tx_ring->cmpl_tq, 1, PI_REALTIME, "%s txcq", 23237902c8dcSWojciech Macek device_get_nameunit(adapter->dev)); 23247902c8dcSWojciech Macek 23257902c8dcSWojciech Macek /* Setup DMA descriptor areas. */ 23267902c8dcSWojciech Macek ret = bus_dma_tag_create(bus_get_dma_tag(dev), 23277902c8dcSWojciech Macek 1, 0, /* alignment, bounds */ 23287902c8dcSWojciech Macek BUS_SPACE_MAXADDR, /* lowaddr */ 23297902c8dcSWojciech Macek BUS_SPACE_MAXADDR, /* highaddr */ 23307902c8dcSWojciech Macek NULL, NULL, /* filter, filterarg */ 23317902c8dcSWojciech Macek AL_TSO_SIZE, /* maxsize */ 23327902c8dcSWojciech Macek AL_ETH_PKT_MAX_BUFS, /* nsegments */ 23337902c8dcSWojciech Macek PAGE_SIZE, /* maxsegsize */ 23347902c8dcSWojciech Macek 0, /* flags */ 23357902c8dcSWojciech Macek NULL, /* lockfunc */ 23367902c8dcSWojciech Macek NULL, /* lockfuncarg */ 23377902c8dcSWojciech Macek &tx_ring->dma_buf_tag); 23387902c8dcSWojciech Macek 23397902c8dcSWojciech Macek if (ret != 0) { 23407902c8dcSWojciech Macek device_printf(dev,"Unable to allocate dma_buf_tag, ret = %d\n", 23417902c8dcSWojciech Macek ret); 23427902c8dcSWojciech Macek return (ret); 23437902c8dcSWojciech Macek } 23447902c8dcSWojciech Macek 23457902c8dcSWojciech Macek for (size = 0; size < tx_ring->sw_count; size++) { 23467902c8dcSWojciech Macek ret = bus_dmamap_create(tx_ring->dma_buf_tag, 0, 23477902c8dcSWojciech Macek &tx_ring->tx_buffer_info[size].dma_map); 23487902c8dcSWojciech Macek if (ret != 0) { 23497902c8dcSWojciech Macek device_printf(dev, "Unable to map DMA TX " 23507902c8dcSWojciech Macek "buffer memory [iter=%d]\n", size); 23517902c8dcSWojciech Macek return (ret); 23527902c8dcSWojciech Macek } 23537902c8dcSWojciech Macek } 23547902c8dcSWojciech Macek 23557902c8dcSWojciech Macek /* completion queue not used for tx */ 23567902c8dcSWojciech Macek q_params->cdesc_base = NULL; 23577902c8dcSWojciech Macek /* size in bytes of the udma completion ring descriptor */ 23587902c8dcSWojciech Macek q_params->cdesc_size = 8; 23597902c8dcSWojciech Macek tx_ring->next_to_use = 0; 23607902c8dcSWojciech Macek tx_ring->next_to_clean = 0; 23617902c8dcSWojciech Macek 23627902c8dcSWojciech Macek return (0); 23637902c8dcSWojciech Macek } 23647902c8dcSWojciech Macek 23657902c8dcSWojciech Macek /* 23667902c8dcSWojciech Macek * al_eth_free_tx_resources - Free Tx Resources per Queue 23677902c8dcSWojciech Macek * @adapter: network interface device structure 23687902c8dcSWojciech Macek * @qid: queue index 23697902c8dcSWojciech Macek * 23707902c8dcSWojciech Macek * Free all transmit software resources 23717902c8dcSWojciech Macek */ 23727902c8dcSWojciech Macek static void 23737902c8dcSWojciech Macek al_eth_free_tx_resources(struct al_eth_adapter *adapter, int qid) 23747902c8dcSWojciech Macek { 23757902c8dcSWojciech Macek struct al_eth_ring *tx_ring = &adapter->tx_ring[qid]; 23767902c8dcSWojciech Macek struct al_udma_q_params *q_params = &tx_ring->q_params; 23777902c8dcSWojciech Macek int size; 23787902c8dcSWojciech Macek 23797902c8dcSWojciech Macek /* At this point interrupts' handlers must be deactivated */ 23807902c8dcSWojciech Macek while (taskqueue_cancel(tx_ring->cmpl_tq, &tx_ring->cmpl_task, NULL)) 23817902c8dcSWojciech Macek taskqueue_drain(tx_ring->cmpl_tq, &tx_ring->cmpl_task); 23827902c8dcSWojciech Macek 23837902c8dcSWojciech Macek taskqueue_free(tx_ring->cmpl_tq); 23847902c8dcSWojciech Macek while (taskqueue_cancel(tx_ring->enqueue_tq, 23857902c8dcSWojciech Macek &tx_ring->enqueue_task, NULL)) { 23867902c8dcSWojciech Macek taskqueue_drain(tx_ring->enqueue_tq, &tx_ring->enqueue_task); 23877902c8dcSWojciech Macek } 23887902c8dcSWojciech Macek 23897902c8dcSWojciech Macek taskqueue_free(tx_ring->enqueue_tq); 23907902c8dcSWojciech Macek 23917902c8dcSWojciech Macek if (tx_ring->br != NULL) { 23927902c8dcSWojciech Macek drbr_flush(adapter->netdev, tx_ring->br); 23937902c8dcSWojciech Macek buf_ring_free(tx_ring->br, M_DEVBUF); 23947902c8dcSWojciech Macek } 23957902c8dcSWojciech Macek 23967902c8dcSWojciech Macek for (size = 0; size < tx_ring->sw_count; size++) { 23977902c8dcSWojciech Macek m_freem(tx_ring->tx_buffer_info[size].m); 23987902c8dcSWojciech Macek tx_ring->tx_buffer_info[size].m = NULL; 23997902c8dcSWojciech Macek 24007902c8dcSWojciech Macek bus_dmamap_unload(tx_ring->dma_buf_tag, 24017902c8dcSWojciech Macek tx_ring->tx_buffer_info[size].dma_map); 24027902c8dcSWojciech Macek bus_dmamap_destroy(tx_ring->dma_buf_tag, 24037902c8dcSWojciech Macek tx_ring->tx_buffer_info[size].dma_map); 24047902c8dcSWojciech Macek } 24057902c8dcSWojciech Macek bus_dma_tag_destroy(tx_ring->dma_buf_tag); 24067902c8dcSWojciech Macek 24077902c8dcSWojciech Macek free(tx_ring->tx_buffer_info, M_IFAL); 24087902c8dcSWojciech Macek tx_ring->tx_buffer_info = NULL; 24097902c8dcSWojciech Macek 24107902c8dcSWojciech Macek mtx_destroy(&tx_ring->br_mtx); 24117902c8dcSWojciech Macek 24127902c8dcSWojciech Macek /* if not set, then don't free */ 24137902c8dcSWojciech Macek if (q_params->desc_base == NULL) 24147902c8dcSWojciech Macek return; 24157902c8dcSWojciech Macek 24167902c8dcSWojciech Macek al_dma_free_coherent(q_params->desc_phy_base_tag, 24177902c8dcSWojciech Macek q_params->desc_phy_base_map, q_params->desc_base); 24187902c8dcSWojciech Macek 24197902c8dcSWojciech Macek q_params->desc_base = NULL; 24207902c8dcSWojciech Macek } 24217902c8dcSWojciech Macek 24227902c8dcSWojciech Macek /* 24237902c8dcSWojciech Macek * al_eth_free_all_tx_resources - Free Tx Resources for All Queues 24247902c8dcSWojciech Macek * @adapter: board private structure 24257902c8dcSWojciech Macek * 24267902c8dcSWojciech Macek * Free all transmit software resources 24277902c8dcSWojciech Macek */ 24287902c8dcSWojciech Macek static void 24297902c8dcSWojciech Macek al_eth_free_all_tx_resources(struct al_eth_adapter *adapter) 24307902c8dcSWojciech Macek { 24317902c8dcSWojciech Macek int i; 24327902c8dcSWojciech Macek 24337902c8dcSWojciech Macek for (i = 0; i < adapter->num_tx_queues; i++) 24347902c8dcSWojciech Macek if (adapter->tx_ring[i].q_params.desc_base) 24357902c8dcSWojciech Macek al_eth_free_tx_resources(adapter, i); 24367902c8dcSWojciech Macek } 24377902c8dcSWojciech Macek 24387902c8dcSWojciech Macek /* 24397902c8dcSWojciech Macek * al_eth_setup_rx_resources - allocate Rx resources (Descriptors) 24407902c8dcSWojciech Macek * @adapter: network interface device structure 24417902c8dcSWojciech Macek * @qid: queue index 24427902c8dcSWojciech Macek * 24437902c8dcSWojciech Macek * Returns 0 on success, negative on failure 24447902c8dcSWojciech Macek */ 24457902c8dcSWojciech Macek static int 24467902c8dcSWojciech Macek al_eth_setup_rx_resources(struct al_eth_adapter *adapter, unsigned int qid) 24477902c8dcSWojciech Macek { 24487902c8dcSWojciech Macek struct al_eth_ring *rx_ring = &adapter->rx_ring[qid]; 2449d8b1601dSMark Johnston device_t dev = rx_ring->dev; 24507902c8dcSWojciech Macek struct al_udma_q_params *q_params = &rx_ring->q_params; 24517902c8dcSWojciech Macek int size; 24527902c8dcSWojciech Macek int ret; 24537902c8dcSWojciech Macek 24547902c8dcSWojciech Macek size = sizeof(struct al_eth_rx_buffer) * rx_ring->sw_count; 24557902c8dcSWojciech Macek 24567902c8dcSWojciech Macek /* alloc extra element so in rx path we can always prefetch rx_info + 1 */ 24577902c8dcSWojciech Macek size += 1; 24587902c8dcSWojciech Macek 24597902c8dcSWojciech Macek rx_ring->rx_buffer_info = malloc(size, M_IFAL, M_ZERO | M_WAITOK); 24607902c8dcSWojciech Macek rx_ring->descs_size = rx_ring->hw_count * sizeof(union al_udma_desc); 24617902c8dcSWojciech Macek q_params->size = rx_ring->hw_count; 24627902c8dcSWojciech Macek 24637902c8dcSWojciech Macek ret = al_dma_alloc_coherent(dev, &q_params->desc_phy_base_tag, 24647902c8dcSWojciech Macek &q_params->desc_phy_base_map, 24657902c8dcSWojciech Macek (bus_addr_t *)&q_params->desc_phy_base, 24667902c8dcSWojciech Macek (void**)&q_params->desc_base, rx_ring->descs_size); 24677902c8dcSWojciech Macek 24687902c8dcSWojciech Macek if ((q_params->desc_base == NULL) || (ret != 0)) 24697902c8dcSWojciech Macek return (ENOMEM); 24707902c8dcSWojciech Macek 24717902c8dcSWojciech Macek /* size in bytes of the udma completion ring descriptor */ 24727902c8dcSWojciech Macek q_params->cdesc_size = 16; 24737902c8dcSWojciech Macek rx_ring->cdescs_size = rx_ring->hw_count * q_params->cdesc_size; 24747902c8dcSWojciech Macek ret = al_dma_alloc_coherent(dev, &q_params->cdesc_phy_base_tag, 24757902c8dcSWojciech Macek &q_params->cdesc_phy_base_map, 24767902c8dcSWojciech Macek (bus_addr_t *)&q_params->cdesc_phy_base, 24777902c8dcSWojciech Macek (void**)&q_params->cdesc_base, rx_ring->cdescs_size); 24787902c8dcSWojciech Macek 24797902c8dcSWojciech Macek if ((q_params->cdesc_base == NULL) || (ret != 0)) 24807902c8dcSWojciech Macek return (ENOMEM); 24817902c8dcSWojciech Macek 24827902c8dcSWojciech Macek /* Allocate taskqueues */ 24836c3e93cbSGleb Smirnoff NET_TASK_INIT(&rx_ring->enqueue_task, 0, al_eth_rx_recv_work, rx_ring); 24847902c8dcSWojciech Macek rx_ring->enqueue_tq = taskqueue_create_fast("al_rx_enque", M_NOWAIT, 24857902c8dcSWojciech Macek taskqueue_thread_enqueue, &rx_ring->enqueue_tq); 24867902c8dcSWojciech Macek taskqueue_start_threads(&rx_ring->enqueue_tq, 1, PI_NET, "%s rxeq", 24877902c8dcSWojciech Macek device_get_nameunit(adapter->dev)); 24887902c8dcSWojciech Macek 24897902c8dcSWojciech Macek /* Setup DMA descriptor areas. */ 24907902c8dcSWojciech Macek ret = bus_dma_tag_create(bus_get_dma_tag(dev), 24917902c8dcSWojciech Macek 1, 0, /* alignment, bounds */ 24927902c8dcSWojciech Macek BUS_SPACE_MAXADDR, /* lowaddr */ 24937902c8dcSWojciech Macek BUS_SPACE_MAXADDR, /* highaddr */ 24947902c8dcSWojciech Macek NULL, NULL, /* filter, filterarg */ 24957902c8dcSWojciech Macek AL_TSO_SIZE, /* maxsize */ 24967902c8dcSWojciech Macek 1, /* nsegments */ 24977902c8dcSWojciech Macek AL_TSO_SIZE, /* maxsegsize */ 24987902c8dcSWojciech Macek 0, /* flags */ 24997902c8dcSWojciech Macek NULL, /* lockfunc */ 25007902c8dcSWojciech Macek NULL, /* lockfuncarg */ 25017902c8dcSWojciech Macek &rx_ring->dma_buf_tag); 25027902c8dcSWojciech Macek 25037902c8dcSWojciech Macek if (ret != 0) { 25047902c8dcSWojciech Macek device_printf(dev,"Unable to allocate RX dma_buf_tag\n"); 25057902c8dcSWojciech Macek return (ret); 25067902c8dcSWojciech Macek } 25077902c8dcSWojciech Macek 25087902c8dcSWojciech Macek for (size = 0; size < rx_ring->sw_count; size++) { 25097902c8dcSWojciech Macek ret = bus_dmamap_create(rx_ring->dma_buf_tag, 0, 25107902c8dcSWojciech Macek &rx_ring->rx_buffer_info[size].dma_map); 25117902c8dcSWojciech Macek if (ret != 0) { 25127902c8dcSWojciech Macek device_printf(dev,"Unable to map DMA RX buffer memory\n"); 25137902c8dcSWojciech Macek return (ret); 25147902c8dcSWojciech Macek } 25157902c8dcSWojciech Macek } 25167902c8dcSWojciech Macek 25177902c8dcSWojciech Macek /* Zero out the descriptor ring */ 25187902c8dcSWojciech Macek memset(q_params->cdesc_base, 0, rx_ring->cdescs_size); 25197902c8dcSWojciech Macek 25207902c8dcSWojciech Macek /* Create LRO for the ring */ 2521f46a05b5SJustin Hibbits if ((if_getcapenable(adapter->netdev) & IFCAP_LRO) != 0) { 25227902c8dcSWojciech Macek int err = tcp_lro_init(&rx_ring->lro); 25237902c8dcSWojciech Macek if (err != 0) { 25247902c8dcSWojciech Macek device_printf(adapter->dev, 25257902c8dcSWojciech Macek "LRO[%d] Initialization failed!\n", qid); 25267902c8dcSWojciech Macek } else { 25277902c8dcSWojciech Macek device_printf_dbg(adapter->dev, 25287902c8dcSWojciech Macek "RX Soft LRO[%d] Initialized\n", qid); 2529463edaf4SJohn Baldwin rx_ring->lro_enabled = true; 25307902c8dcSWojciech Macek rx_ring->lro.ifp = adapter->netdev; 25317902c8dcSWojciech Macek } 25327902c8dcSWojciech Macek } 25337902c8dcSWojciech Macek 25347902c8dcSWojciech Macek rx_ring->next_to_clean = 0; 25357902c8dcSWojciech Macek rx_ring->next_to_use = 0; 25367902c8dcSWojciech Macek 25377902c8dcSWojciech Macek return (0); 25387902c8dcSWojciech Macek } 25397902c8dcSWojciech Macek 25407902c8dcSWojciech Macek /* 25417902c8dcSWojciech Macek * al_eth_free_rx_resources - Free Rx Resources 25427902c8dcSWojciech Macek * @adapter: network interface device structure 25437902c8dcSWojciech Macek * @qid: queue index 25447902c8dcSWojciech Macek * 25457902c8dcSWojciech Macek * Free all receive software resources 25467902c8dcSWojciech Macek */ 25477902c8dcSWojciech Macek static void 25487902c8dcSWojciech Macek al_eth_free_rx_resources(struct al_eth_adapter *adapter, unsigned int qid) 25497902c8dcSWojciech Macek { 25507902c8dcSWojciech Macek struct al_eth_ring *rx_ring = &adapter->rx_ring[qid]; 25517902c8dcSWojciech Macek struct al_udma_q_params *q_params = &rx_ring->q_params; 25527902c8dcSWojciech Macek int size; 25537902c8dcSWojciech Macek 25547902c8dcSWojciech Macek /* At this point interrupts' handlers must be deactivated */ 25557902c8dcSWojciech Macek while (taskqueue_cancel(rx_ring->enqueue_tq, 25567902c8dcSWojciech Macek &rx_ring->enqueue_task, NULL)) { 25577902c8dcSWojciech Macek taskqueue_drain(rx_ring->enqueue_tq, &rx_ring->enqueue_task); 25587902c8dcSWojciech Macek } 25597902c8dcSWojciech Macek 25607902c8dcSWojciech Macek taskqueue_free(rx_ring->enqueue_tq); 25617902c8dcSWojciech Macek 25627902c8dcSWojciech Macek for (size = 0; size < rx_ring->sw_count; size++) { 25637902c8dcSWojciech Macek m_freem(rx_ring->rx_buffer_info[size].m); 25647902c8dcSWojciech Macek rx_ring->rx_buffer_info[size].m = NULL; 25657902c8dcSWojciech Macek bus_dmamap_unload(rx_ring->dma_buf_tag, 25667902c8dcSWojciech Macek rx_ring->rx_buffer_info[size].dma_map); 25677902c8dcSWojciech Macek bus_dmamap_destroy(rx_ring->dma_buf_tag, 25687902c8dcSWojciech Macek rx_ring->rx_buffer_info[size].dma_map); 25697902c8dcSWojciech Macek } 25707902c8dcSWojciech Macek bus_dma_tag_destroy(rx_ring->dma_buf_tag); 25717902c8dcSWojciech Macek 25727902c8dcSWojciech Macek free(rx_ring->rx_buffer_info, M_IFAL); 25737902c8dcSWojciech Macek rx_ring->rx_buffer_info = NULL; 25747902c8dcSWojciech Macek 25757902c8dcSWojciech Macek /* if not set, then don't free */ 25767902c8dcSWojciech Macek if (q_params->desc_base == NULL) 25777902c8dcSWojciech Macek return; 25787902c8dcSWojciech Macek 25797902c8dcSWojciech Macek al_dma_free_coherent(q_params->desc_phy_base_tag, 25807902c8dcSWojciech Macek q_params->desc_phy_base_map, q_params->desc_base); 25817902c8dcSWojciech Macek 25827902c8dcSWojciech Macek q_params->desc_base = NULL; 25837902c8dcSWojciech Macek 25847902c8dcSWojciech Macek /* if not set, then don't free */ 25857902c8dcSWojciech Macek if (q_params->cdesc_base == NULL) 25867902c8dcSWojciech Macek return; 25877902c8dcSWojciech Macek 25887902c8dcSWojciech Macek al_dma_free_coherent(q_params->cdesc_phy_base_tag, 25897902c8dcSWojciech Macek q_params->cdesc_phy_base_map, q_params->cdesc_base); 25907902c8dcSWojciech Macek 25917902c8dcSWojciech Macek q_params->cdesc_phy_base = 0; 25927902c8dcSWojciech Macek 25937902c8dcSWojciech Macek /* Free LRO resources */ 25947902c8dcSWojciech Macek tcp_lro_free(&rx_ring->lro); 25957902c8dcSWojciech Macek } 25967902c8dcSWojciech Macek 25977902c8dcSWojciech Macek /* 25987902c8dcSWojciech Macek * al_eth_free_all_rx_resources - Free Rx Resources for All Queues 25997902c8dcSWojciech Macek * @adapter: board private structure 26007902c8dcSWojciech Macek * 26017902c8dcSWojciech Macek * Free all receive software resources 26027902c8dcSWojciech Macek */ 26037902c8dcSWojciech Macek static void 26047902c8dcSWojciech Macek al_eth_free_all_rx_resources(struct al_eth_adapter *adapter) 26057902c8dcSWojciech Macek { 26067902c8dcSWojciech Macek int i; 26077902c8dcSWojciech Macek 26087902c8dcSWojciech Macek for (i = 0; i < adapter->num_rx_queues; i++) 26097902c8dcSWojciech Macek if (adapter->rx_ring[i].q_params.desc_base != 0) 26107902c8dcSWojciech Macek al_eth_free_rx_resources(adapter, i); 26117902c8dcSWojciech Macek } 26127902c8dcSWojciech Macek 26137902c8dcSWojciech Macek /* 26147902c8dcSWojciech Macek * al_eth_setup_all_rx_resources - allocate all queues Rx resources 26157902c8dcSWojciech Macek * @adapter: board private structure 26167902c8dcSWojciech Macek * 26177902c8dcSWojciech Macek * Return 0 on success, negative on failure 26187902c8dcSWojciech Macek */ 26197902c8dcSWojciech Macek static int 26207902c8dcSWojciech Macek al_eth_setup_all_rx_resources(struct al_eth_adapter *adapter) 26217902c8dcSWojciech Macek { 26227902c8dcSWojciech Macek int i, rc = 0; 26237902c8dcSWojciech Macek 26247902c8dcSWojciech Macek for (i = 0; i < adapter->num_rx_queues; i++) { 26257902c8dcSWojciech Macek rc = al_eth_setup_rx_resources(adapter, i); 26267902c8dcSWojciech Macek if (rc == 0) 26277902c8dcSWojciech Macek continue; 26287902c8dcSWojciech Macek 26297902c8dcSWojciech Macek device_printf(adapter->dev, "Allocation for Rx Queue %u failed\n", i); 26307902c8dcSWojciech Macek goto err_setup_rx; 26317902c8dcSWojciech Macek } 26327902c8dcSWojciech Macek return (0); 26337902c8dcSWojciech Macek 26347902c8dcSWojciech Macek err_setup_rx: 26357902c8dcSWojciech Macek /* rewind the index freeing the rings as we go */ 26367902c8dcSWojciech Macek while (i--) 26377902c8dcSWojciech Macek al_eth_free_rx_resources(adapter, i); 26387902c8dcSWojciech Macek return (rc); 26397902c8dcSWojciech Macek } 26407902c8dcSWojciech Macek 26417902c8dcSWojciech Macek /* 26427902c8dcSWojciech Macek * al_eth_setup_all_tx_resources - allocate all queues Tx resources 26437902c8dcSWojciech Macek * @adapter: private structure 26447902c8dcSWojciech Macek * 26457902c8dcSWojciech Macek * Return 0 on success, negative on failure 26467902c8dcSWojciech Macek */ 26477902c8dcSWojciech Macek static int 26487902c8dcSWojciech Macek al_eth_setup_all_tx_resources(struct al_eth_adapter *adapter) 26497902c8dcSWojciech Macek { 26507902c8dcSWojciech Macek int i, rc = 0; 26517902c8dcSWojciech Macek 26527902c8dcSWojciech Macek for (i = 0; i < adapter->num_tx_queues; i++) { 26537902c8dcSWojciech Macek rc = al_eth_setup_tx_resources(adapter, i); 26547902c8dcSWojciech Macek if (rc == 0) 26557902c8dcSWojciech Macek continue; 26567902c8dcSWojciech Macek 26577902c8dcSWojciech Macek device_printf(adapter->dev, 26587902c8dcSWojciech Macek "Allocation for Tx Queue %u failed\n", i); 26597902c8dcSWojciech Macek goto err_setup_tx; 26607902c8dcSWojciech Macek } 26617902c8dcSWojciech Macek 26627902c8dcSWojciech Macek return (0); 26637902c8dcSWojciech Macek 26647902c8dcSWojciech Macek err_setup_tx: 26657902c8dcSWojciech Macek /* rewind the index freeing the rings as we go */ 26667902c8dcSWojciech Macek while (i--) 26677902c8dcSWojciech Macek al_eth_free_tx_resources(adapter, i); 26687902c8dcSWojciech Macek 26697902c8dcSWojciech Macek return (rc); 26707902c8dcSWojciech Macek } 26717902c8dcSWojciech Macek 26727902c8dcSWojciech Macek static void 26737902c8dcSWojciech Macek al_eth_disable_int_sync(struct al_eth_adapter *adapter) 26747902c8dcSWojciech Macek { 26757902c8dcSWojciech Macek 26767902c8dcSWojciech Macek /* disable forwarding interrupts from eth through pci end point */ 26777902c8dcSWojciech Macek if ((adapter->board_type == ALPINE_FPGA_NIC) || 26787902c8dcSWojciech Macek (adapter->board_type == ALPINE_NIC)) { 26797902c8dcSWojciech Macek al_eth_forward_int_config((uint32_t*)adapter->internal_pcie_base + 26807902c8dcSWojciech Macek AL_REG_OFFSET_FORWARD_INTR, AL_DIS_FORWARD_INTR); 26817902c8dcSWojciech Macek } 26827902c8dcSWojciech Macek 26837902c8dcSWojciech Macek /* mask hw interrupts */ 26847902c8dcSWojciech Macek al_eth_interrupts_mask(adapter); 26857902c8dcSWojciech Macek } 26867902c8dcSWojciech Macek 26877902c8dcSWojciech Macek static void 26887902c8dcSWojciech Macek al_eth_interrupts_unmask(struct al_eth_adapter *adapter) 26897902c8dcSWojciech Macek { 26907902c8dcSWojciech Macek uint32_t group_a_mask = AL_INT_GROUP_A_GROUP_D_SUM; /* enable group D summery */ 26917902c8dcSWojciech Macek uint32_t group_b_mask = (1 << adapter->num_rx_queues) - 1;/* bit per Rx q*/ 26927902c8dcSWojciech Macek uint32_t group_c_mask = (1 << adapter->num_tx_queues) - 1;/* bit per Tx q*/ 26937902c8dcSWojciech Macek uint32_t group_d_mask = 3 << 8; 26947902c8dcSWojciech Macek struct unit_regs __iomem *regs_base = 26957902c8dcSWojciech Macek (struct unit_regs __iomem *)adapter->udma_base; 26967902c8dcSWojciech Macek 26977902c8dcSWojciech Macek if (adapter->int_mode == AL_IOFIC_MODE_LEGACY) 26987902c8dcSWojciech Macek group_a_mask |= AL_INT_GROUP_A_GROUP_B_SUM | 26997902c8dcSWojciech Macek AL_INT_GROUP_A_GROUP_C_SUM | 27007902c8dcSWojciech Macek AL_INT_GROUP_A_GROUP_D_SUM; 27017902c8dcSWojciech Macek 27027902c8dcSWojciech Macek al_udma_iofic_unmask(regs_base, AL_UDMA_IOFIC_LEVEL_PRIMARY, 27037902c8dcSWojciech Macek AL_INT_GROUP_A, group_a_mask); 27047902c8dcSWojciech Macek al_udma_iofic_unmask(regs_base, AL_UDMA_IOFIC_LEVEL_PRIMARY, 27057902c8dcSWojciech Macek AL_INT_GROUP_B, group_b_mask); 27067902c8dcSWojciech Macek al_udma_iofic_unmask(regs_base, AL_UDMA_IOFIC_LEVEL_PRIMARY, 27077902c8dcSWojciech Macek AL_INT_GROUP_C, group_c_mask); 27087902c8dcSWojciech Macek al_udma_iofic_unmask(regs_base, AL_UDMA_IOFIC_LEVEL_PRIMARY, 27097902c8dcSWojciech Macek AL_INT_GROUP_D, group_d_mask); 27107902c8dcSWojciech Macek } 27117902c8dcSWojciech Macek 27127902c8dcSWojciech Macek static void 27137902c8dcSWojciech Macek al_eth_interrupts_mask(struct al_eth_adapter *adapter) 27147902c8dcSWojciech Macek { 27157902c8dcSWojciech Macek struct unit_regs __iomem *regs_base = 27167902c8dcSWojciech Macek (struct unit_regs __iomem *)adapter->udma_base; 27177902c8dcSWojciech Macek 27187902c8dcSWojciech Macek /* mask all interrupts */ 27197902c8dcSWojciech Macek al_udma_iofic_mask(regs_base, AL_UDMA_IOFIC_LEVEL_PRIMARY, 27207902c8dcSWojciech Macek AL_INT_GROUP_A, AL_MASK_GROUP_A_INT); 27217902c8dcSWojciech Macek al_udma_iofic_mask(regs_base, AL_UDMA_IOFIC_LEVEL_PRIMARY, 27227902c8dcSWojciech Macek AL_INT_GROUP_B, AL_MASK_GROUP_B_INT); 27237902c8dcSWojciech Macek al_udma_iofic_mask(regs_base, AL_UDMA_IOFIC_LEVEL_PRIMARY, 27247902c8dcSWojciech Macek AL_INT_GROUP_C, AL_MASK_GROUP_C_INT); 27257902c8dcSWojciech Macek al_udma_iofic_mask(regs_base, AL_UDMA_IOFIC_LEVEL_PRIMARY, 27267902c8dcSWojciech Macek AL_INT_GROUP_D, AL_MASK_GROUP_D_INT); 27277902c8dcSWojciech Macek } 27287902c8dcSWojciech Macek 27297902c8dcSWojciech Macek static int 27307902c8dcSWojciech Macek al_eth_configure_int_mode(struct al_eth_adapter *adapter) 27317902c8dcSWojciech Macek { 27327902c8dcSWojciech Macek enum al_iofic_mode int_mode; 27337902c8dcSWojciech Macek uint32_t m2s_errors_disable = AL_M2S_MASK_INIT; 27347902c8dcSWojciech Macek uint32_t m2s_aborts_disable = AL_M2S_MASK_INIT; 27357902c8dcSWojciech Macek uint32_t s2m_errors_disable = AL_S2M_MASK_INIT; 27367902c8dcSWojciech Macek uint32_t s2m_aborts_disable = AL_S2M_MASK_INIT; 27377902c8dcSWojciech Macek 27387902c8dcSWojciech Macek /* single INTX mode */ 27397902c8dcSWojciech Macek if (adapter->msix_vecs == 0) 27407902c8dcSWojciech Macek int_mode = AL_IOFIC_MODE_LEGACY; 27417902c8dcSWojciech Macek else if (adapter->msix_vecs > 1) 27427902c8dcSWojciech Macek int_mode = AL_IOFIC_MODE_MSIX_PER_Q; 27437902c8dcSWojciech Macek else { 27447902c8dcSWojciech Macek device_printf(adapter->dev, 27457902c8dcSWojciech Macek "udma doesn't support single MSI-X mode yet.\n"); 27467902c8dcSWojciech Macek return (EIO); 27477902c8dcSWojciech Macek } 27487902c8dcSWojciech Macek 27497902c8dcSWojciech Macek if (adapter->board_type != ALPINE_INTEGRATED) { 27507902c8dcSWojciech Macek m2s_errors_disable |= AL_M2S_S2M_MASK_NOT_INT; 27517902c8dcSWojciech Macek m2s_errors_disable |= AL_M2S_S2M_MASK_NOT_INT; 27527902c8dcSWojciech Macek s2m_aborts_disable |= AL_M2S_S2M_MASK_NOT_INT; 27537902c8dcSWojciech Macek s2m_aborts_disable |= AL_M2S_S2M_MASK_NOT_INT; 27547902c8dcSWojciech Macek } 27557902c8dcSWojciech Macek 27567902c8dcSWojciech Macek if (al_udma_iofic_config((struct unit_regs __iomem *)adapter->udma_base, 27577902c8dcSWojciech Macek int_mode, m2s_errors_disable, m2s_aborts_disable, 27587902c8dcSWojciech Macek s2m_errors_disable, s2m_aborts_disable)) { 27597902c8dcSWojciech Macek device_printf(adapter->dev, 27607902c8dcSWojciech Macek "al_udma_unit_int_config failed!.\n"); 27617902c8dcSWojciech Macek return (EIO); 27627902c8dcSWojciech Macek } 27637902c8dcSWojciech Macek adapter->int_mode = int_mode; 27647902c8dcSWojciech Macek device_printf_dbg(adapter->dev, "using %s interrupt mode\n", 27657902c8dcSWojciech Macek int_mode == AL_IOFIC_MODE_LEGACY ? "INTx" : 27667902c8dcSWojciech Macek int_mode == AL_IOFIC_MODE_MSIX_PER_Q ? "MSI-X per Queue" : "Unknown"); 27677902c8dcSWojciech Macek /* set interrupt moderation resolution to 15us */ 27687902c8dcSWojciech Macek al_iofic_moder_res_config(&((struct unit_regs *)(adapter->udma_base))->gen.interrupt_regs.main_iofic, AL_INT_GROUP_B, 15); 27697902c8dcSWojciech Macek al_iofic_moder_res_config(&((struct unit_regs *)(adapter->udma_base))->gen.interrupt_regs.main_iofic, AL_INT_GROUP_C, 15); 27707902c8dcSWojciech Macek /* by default interrupt coalescing is disabled */ 27717902c8dcSWojciech Macek adapter->tx_usecs = 0; 27727902c8dcSWojciech Macek adapter->rx_usecs = 0; 27737902c8dcSWojciech Macek 27747902c8dcSWojciech Macek return (0); 27757902c8dcSWojciech Macek } 27767902c8dcSWojciech Macek 27777902c8dcSWojciech Macek /* 27787902c8dcSWojciech Macek * ethtool_rxfh_indir_default - get default value for RX flow hash indirection 27797902c8dcSWojciech Macek * @index: Index in RX flow hash indirection table 27807902c8dcSWojciech Macek * @n_rx_rings: Number of RX rings to use 27817902c8dcSWojciech Macek * 27827902c8dcSWojciech Macek * This function provides the default policy for RX flow hash indirection. 27837902c8dcSWojciech Macek */ 27847902c8dcSWojciech Macek static inline uint32_t 27857902c8dcSWojciech Macek ethtool_rxfh_indir_default(uint32_t index, uint32_t n_rx_rings) 27867902c8dcSWojciech Macek { 27877902c8dcSWojciech Macek 27887902c8dcSWojciech Macek return (index % n_rx_rings); 27897902c8dcSWojciech Macek } 27907902c8dcSWojciech Macek 27917902c8dcSWojciech Macek static void* 27927902c8dcSWojciech Macek al_eth_update_stats(struct al_eth_adapter *adapter) 27937902c8dcSWojciech Macek { 27947902c8dcSWojciech Macek struct al_eth_mac_stats *mac_stats = &adapter->mac_stats; 27957902c8dcSWojciech Macek 27967902c8dcSWojciech Macek if (adapter->up == 0) 27977902c8dcSWojciech Macek return (NULL); 27987902c8dcSWojciech Macek 27997902c8dcSWojciech Macek al_eth_mac_stats_get(&adapter->hal_adapter, mac_stats); 28007902c8dcSWojciech Macek 28017902c8dcSWojciech Macek return (NULL); 28027902c8dcSWojciech Macek } 28037902c8dcSWojciech Macek 28047902c8dcSWojciech Macek static uint64_t 2805bc14c73bSJustin Hibbits al_get_counter(if_t ifp, ift_counter cnt) 28067902c8dcSWojciech Macek { 28077902c8dcSWojciech Macek struct al_eth_adapter *adapter; 28087902c8dcSWojciech Macek struct al_eth_mac_stats *mac_stats; 28097902c8dcSWojciech Macek uint64_t rv; 28107902c8dcSWojciech Macek 28117902c8dcSWojciech Macek adapter = if_getsoftc(ifp); 28127902c8dcSWojciech Macek mac_stats = &adapter->mac_stats; 28137902c8dcSWojciech Macek 28147902c8dcSWojciech Macek switch (cnt) { 28157902c8dcSWojciech Macek case IFCOUNTER_IPACKETS: 28167902c8dcSWojciech Macek return (mac_stats->aFramesReceivedOK); /* including pause frames */ 28177902c8dcSWojciech Macek case IFCOUNTER_OPACKETS: 28187902c8dcSWojciech Macek return (mac_stats->aFramesTransmittedOK); 28197902c8dcSWojciech Macek case IFCOUNTER_IBYTES: 28207902c8dcSWojciech Macek return (mac_stats->aOctetsReceivedOK); 28217902c8dcSWojciech Macek case IFCOUNTER_OBYTES: 28227902c8dcSWojciech Macek return (mac_stats->aOctetsTransmittedOK); 28237902c8dcSWojciech Macek case IFCOUNTER_IMCASTS: 28247902c8dcSWojciech Macek return (mac_stats->ifInMulticastPkts); 28257902c8dcSWojciech Macek case IFCOUNTER_OMCASTS: 28267902c8dcSWojciech Macek return (mac_stats->ifOutMulticastPkts); 28277902c8dcSWojciech Macek case IFCOUNTER_COLLISIONS: 28287902c8dcSWojciech Macek return (0); 28297902c8dcSWojciech Macek case IFCOUNTER_IQDROPS: 28307902c8dcSWojciech Macek return (mac_stats->etherStatsDropEvents); 28317902c8dcSWojciech Macek case IFCOUNTER_IERRORS: 28327902c8dcSWojciech Macek rv = mac_stats->ifInErrors + 28337902c8dcSWojciech Macek mac_stats->etherStatsUndersizePkts + /* good but short */ 28347902c8dcSWojciech Macek mac_stats->etherStatsFragments + /* short and bad*/ 28357902c8dcSWojciech Macek mac_stats->etherStatsJabbers + /* with crc errors */ 28367902c8dcSWojciech Macek mac_stats->etherStatsOversizePkts + 28377902c8dcSWojciech Macek mac_stats->aFrameCheckSequenceErrors + 28387902c8dcSWojciech Macek mac_stats->aAlignmentErrors; 28397902c8dcSWojciech Macek return (rv); 28407902c8dcSWojciech Macek case IFCOUNTER_OERRORS: 28417902c8dcSWojciech Macek return (mac_stats->ifOutErrors); 28427902c8dcSWojciech Macek default: 28437902c8dcSWojciech Macek return (if_get_counter_default(ifp, cnt)); 28447902c8dcSWojciech Macek } 28457902c8dcSWojciech Macek } 28467902c8dcSWojciech Macek 284757d36163SGleb Smirnoff static u_int 284857d36163SGleb Smirnoff al_count_maddr(void *arg, struct sockaddr_dl *sdl, u_int cnt) 284957d36163SGleb Smirnoff { 285057d36163SGleb Smirnoff unsigned char *mac; 285157d36163SGleb Smirnoff 285257d36163SGleb Smirnoff mac = LLADDR(sdl); 285357d36163SGleb Smirnoff /* default mc address inside mac address */ 285457d36163SGleb Smirnoff if (mac[3] != 0 && mac[4] != 0 && mac[5] != 1) 285557d36163SGleb Smirnoff return (1); 285657d36163SGleb Smirnoff else 285757d36163SGleb Smirnoff return (0); 285857d36163SGleb Smirnoff } 285957d36163SGleb Smirnoff 286057d36163SGleb Smirnoff static u_int 286157d36163SGleb Smirnoff al_program_addr(void *arg, struct sockaddr_dl *sdl, u_int cnt) 286257d36163SGleb Smirnoff { 286357d36163SGleb Smirnoff struct al_eth_adapter *adapter = arg; 286457d36163SGleb Smirnoff 286557d36163SGleb Smirnoff al_eth_mac_table_unicast_add(adapter, 286657d36163SGleb Smirnoff AL_ETH_MAC_TABLE_UNICAST_IDX_BASE + 1 + cnt, 1); 286757d36163SGleb Smirnoff 286857d36163SGleb Smirnoff return (1); 286957d36163SGleb Smirnoff } 287057d36163SGleb Smirnoff 28717902c8dcSWojciech Macek /* 28727902c8dcSWojciech Macek * Unicast, Multicast and Promiscuous mode set 28737902c8dcSWojciech Macek * 28747902c8dcSWojciech Macek * The set_rx_mode entry point is called whenever the unicast or multicast 28757902c8dcSWojciech Macek * address lists or the network interface flags are updated. This routine is 28767902c8dcSWojciech Macek * responsible for configuring the hardware for proper unicast, multicast, 28777902c8dcSWojciech Macek * promiscuous mode, and all-multi behavior. 28787902c8dcSWojciech Macek */ 28797902c8dcSWojciech Macek static void 28807902c8dcSWojciech Macek al_eth_set_rx_mode(struct al_eth_adapter *adapter) 28817902c8dcSWojciech Macek { 2882bc14c73bSJustin Hibbits if_t ifp = adapter->netdev; 288357d36163SGleb Smirnoff int mc, uc; 28847902c8dcSWojciech Macek uint8_t i; 28857902c8dcSWojciech Macek 288657d36163SGleb Smirnoff /* XXXGL: why generic count won't work? */ 288757d36163SGleb Smirnoff mc = if_foreach_llmaddr(ifp, al_count_maddr, NULL); 288857d36163SGleb Smirnoff uc = if_lladdr_count(ifp); 28897902c8dcSWojciech Macek 2890bc14c73bSJustin Hibbits if ((if_getflags(ifp) & IFF_PROMISC) != 0) { 28917902c8dcSWojciech Macek al_eth_mac_table_promiscuous_set(adapter, true); 28927902c8dcSWojciech Macek } else { 2893bc14c73bSJustin Hibbits if ((if_getflags(ifp) & IFF_ALLMULTI) != 0) { 28947902c8dcSWojciech Macek /* This interface is in all-multicasts mode (used by multicast routers). */ 28957902c8dcSWojciech Macek al_eth_mac_table_all_multicast_add(adapter, 28967902c8dcSWojciech Macek AL_ETH_MAC_TABLE_ALL_MULTICAST_IDX, 1); 28977902c8dcSWojciech Macek } else { 28987902c8dcSWojciech Macek if (mc == 0) { 28997902c8dcSWojciech Macek al_eth_mac_table_entry_clear(adapter, 29007902c8dcSWojciech Macek AL_ETH_MAC_TABLE_ALL_MULTICAST_IDX); 29017902c8dcSWojciech Macek } else { 29027902c8dcSWojciech Macek al_eth_mac_table_all_multicast_add(adapter, 29037902c8dcSWojciech Macek AL_ETH_MAC_TABLE_ALL_MULTICAST_IDX, 1); 29047902c8dcSWojciech Macek } 29057902c8dcSWojciech Macek } 29067902c8dcSWojciech Macek if (uc != 0) { 29077902c8dcSWojciech Macek i = AL_ETH_MAC_TABLE_UNICAST_IDX_BASE + 1; 29087902c8dcSWojciech Macek if (uc > AL_ETH_MAC_TABLE_UNICAST_MAX_COUNT) { 29097902c8dcSWojciech Macek /* 29107902c8dcSWojciech Macek * In this case there are more addresses then 29117902c8dcSWojciech Macek * entries in the mac table - set promiscuous 29127902c8dcSWojciech Macek */ 29137902c8dcSWojciech Macek al_eth_mac_table_promiscuous_set(adapter, true); 29147902c8dcSWojciech Macek return; 29157902c8dcSWojciech Macek } 29167902c8dcSWojciech Macek 29177902c8dcSWojciech Macek /* clear the last configuration */ 29187902c8dcSWojciech Macek while (i < (AL_ETH_MAC_TABLE_UNICAST_IDX_BASE + 29197902c8dcSWojciech Macek AL_ETH_MAC_TABLE_UNICAST_MAX_COUNT)) { 29207902c8dcSWojciech Macek al_eth_mac_table_entry_clear(adapter, i); 29217902c8dcSWojciech Macek i++; 29227902c8dcSWojciech Macek } 29237902c8dcSWojciech Macek 29247902c8dcSWojciech Macek /* set new addresses */ 292557d36163SGleb Smirnoff if_foreach_lladdr(ifp, al_program_addr, adapter); 29267902c8dcSWojciech Macek } 29277902c8dcSWojciech Macek al_eth_mac_table_promiscuous_set(adapter, false); 29287902c8dcSWojciech Macek } 29297902c8dcSWojciech Macek } 29307902c8dcSWojciech Macek 29317902c8dcSWojciech Macek static void 29327902c8dcSWojciech Macek al_eth_config_rx_fwd(struct al_eth_adapter *adapter) 29337902c8dcSWojciech Macek { 29347902c8dcSWojciech Macek struct al_eth_fwd_ctrl_table_entry entry; 29357902c8dcSWojciech Macek int i; 29367902c8dcSWojciech Macek 29377902c8dcSWojciech Macek /* let priority be equal to pbits */ 29387902c8dcSWojciech Macek for (i = 0; i < AL_ETH_FWD_PBITS_TABLE_NUM; i++) 29397902c8dcSWojciech Macek al_eth_fwd_pbits_table_set(&adapter->hal_adapter, i, i); 29407902c8dcSWojciech Macek 29417902c8dcSWojciech Macek /* map priority to queue index, queue id = priority/2 */ 29427902c8dcSWojciech Macek for (i = 0; i < AL_ETH_FWD_PRIO_TABLE_NUM; i++) 29437902c8dcSWojciech Macek al_eth_fwd_priority_table_set(&adapter->hal_adapter, i, i >> 1); 29447902c8dcSWojciech Macek 29457902c8dcSWojciech Macek entry.prio_sel = AL_ETH_CTRL_TABLE_PRIO_SEL_VAL_0; 29467902c8dcSWojciech Macek entry.queue_sel_1 = AL_ETH_CTRL_TABLE_QUEUE_SEL_1_THASH_TABLE; 29477902c8dcSWojciech Macek entry.queue_sel_2 = AL_ETH_CTRL_TABLE_QUEUE_SEL_2_NO_PRIO; 29487902c8dcSWojciech Macek entry.udma_sel = AL_ETH_CTRL_TABLE_UDMA_SEL_MAC_TABLE; 2949463edaf4SJohn Baldwin entry.filter = false; 29507902c8dcSWojciech Macek 2951463edaf4SJohn Baldwin al_eth_ctrl_table_def_set(&adapter->hal_adapter, AL_FALSE, &entry); 29527902c8dcSWojciech Macek 29537902c8dcSWojciech Macek /* 29547902c8dcSWojciech Macek * By default set the mac table to forward all unicast packets to our 29557902c8dcSWojciech Macek * MAC address and all broadcast. all the rest will be dropped. 29567902c8dcSWojciech Macek */ 29577902c8dcSWojciech Macek al_eth_mac_table_unicast_add(adapter, AL_ETH_MAC_TABLE_UNICAST_IDX_BASE, 295857d36163SGleb Smirnoff 1); 29597902c8dcSWojciech Macek al_eth_mac_table_broadcast_add(adapter, AL_ETH_MAC_TABLE_BROADCAST_IDX, 1); 29607902c8dcSWojciech Macek al_eth_mac_table_promiscuous_set(adapter, false); 29617902c8dcSWojciech Macek 29627902c8dcSWojciech Macek /* set toeplitz hash keys */ 29637902c8dcSWojciech Macek for (i = 0; i < sizeof(adapter->toeplitz_hash_key); i++) 29647902c8dcSWojciech Macek *((uint8_t*)adapter->toeplitz_hash_key + i) = (uint8_t)random(); 29657902c8dcSWojciech Macek 29667902c8dcSWojciech Macek for (i = 0; i < AL_ETH_RX_HASH_KEY_NUM; i++) 29677902c8dcSWojciech Macek al_eth_hash_key_set(&adapter->hal_adapter, i, 29687902c8dcSWojciech Macek htonl(adapter->toeplitz_hash_key[i])); 29697902c8dcSWojciech Macek 29707902c8dcSWojciech Macek for (i = 0; i < AL_ETH_RX_RSS_TABLE_SIZE; i++) { 29717902c8dcSWojciech Macek adapter->rss_ind_tbl[i] = ethtool_rxfh_indir_default(i, 29727902c8dcSWojciech Macek AL_ETH_NUM_QUEUES); 29737902c8dcSWojciech Macek al_eth_set_thash_table_entry(adapter, i, 0, 29747902c8dcSWojciech Macek adapter->rss_ind_tbl[i]); 29757902c8dcSWojciech Macek } 29767902c8dcSWojciech Macek 29777902c8dcSWojciech Macek al_eth_fsm_table_init(adapter); 29787902c8dcSWojciech Macek } 29797902c8dcSWojciech Macek 29807902c8dcSWojciech Macek static void 29817902c8dcSWojciech Macek al_eth_req_rx_buff_size(struct al_eth_adapter *adapter, int size) 29827902c8dcSWojciech Macek { 29837902c8dcSWojciech Macek 29847902c8dcSWojciech Macek /* 29857902c8dcSWojciech Macek * Determine the correct mbuf pool 29867902c8dcSWojciech Macek * for doing jumbo frames 29877902c8dcSWojciech Macek * Try from the smallest up to maximum supported 29887902c8dcSWojciech Macek */ 29897902c8dcSWojciech Macek adapter->rx_mbuf_sz = MCLBYTES; 29907902c8dcSWojciech Macek if (size > 2048) { 29917902c8dcSWojciech Macek if (adapter->max_rx_buff_alloc_size > 2048) 29927902c8dcSWojciech Macek adapter->rx_mbuf_sz = MJUMPAGESIZE; 29937902c8dcSWojciech Macek else 29947902c8dcSWojciech Macek return; 29957902c8dcSWojciech Macek } 29967902c8dcSWojciech Macek if (size > 4096) { 29977902c8dcSWojciech Macek if (adapter->max_rx_buff_alloc_size > 4096) 29987902c8dcSWojciech Macek adapter->rx_mbuf_sz = MJUM9BYTES; 29997902c8dcSWojciech Macek else 30007902c8dcSWojciech Macek return; 30017902c8dcSWojciech Macek } 30027902c8dcSWojciech Macek if (size > 9216) { 30037902c8dcSWojciech Macek if (adapter->max_rx_buff_alloc_size > 9216) 30047902c8dcSWojciech Macek adapter->rx_mbuf_sz = MJUM16BYTES; 30057902c8dcSWojciech Macek else 30067902c8dcSWojciech Macek return; 30077902c8dcSWojciech Macek } 30087902c8dcSWojciech Macek } 30097902c8dcSWojciech Macek 30107902c8dcSWojciech Macek static int 30117902c8dcSWojciech Macek al_eth_change_mtu(struct al_eth_adapter *adapter, int new_mtu) 30127902c8dcSWojciech Macek { 30137902c8dcSWojciech Macek int max_frame = new_mtu + ETHER_HDR_LEN + ETHER_CRC_LEN + 30147902c8dcSWojciech Macek ETHER_VLAN_ENCAP_LEN; 30157902c8dcSWojciech Macek 30167902c8dcSWojciech Macek al_eth_req_rx_buff_size(adapter, new_mtu); 30177902c8dcSWojciech Macek 30187902c8dcSWojciech Macek device_printf_dbg(adapter->dev, "set MTU to %d\n", new_mtu); 30197902c8dcSWojciech Macek al_eth_rx_pkt_limit_config(&adapter->hal_adapter, 30207902c8dcSWojciech Macek AL_ETH_MIN_FRAME_LEN, max_frame); 30217902c8dcSWojciech Macek 30227902c8dcSWojciech Macek al_eth_tso_mss_config(&adapter->hal_adapter, 0, new_mtu - 100); 30237902c8dcSWojciech Macek 30247902c8dcSWojciech Macek return (0); 30257902c8dcSWojciech Macek } 30267902c8dcSWojciech Macek 30277902c8dcSWojciech Macek static int 30287902c8dcSWojciech Macek al_eth_check_mtu(struct al_eth_adapter *adapter, int new_mtu) 30297902c8dcSWojciech Macek { 30307902c8dcSWojciech Macek int max_frame = new_mtu + ETHER_HDR_LEN + ETHER_CRC_LEN + ETHER_VLAN_ENCAP_LEN; 30317902c8dcSWojciech Macek 30327902c8dcSWojciech Macek if ((new_mtu < AL_ETH_MIN_FRAME_LEN) || 30337902c8dcSWojciech Macek (max_frame > AL_ETH_MAX_FRAME_LEN)) { 30347902c8dcSWojciech Macek return (EINVAL); 30357902c8dcSWojciech Macek } 30367902c8dcSWojciech Macek 30377902c8dcSWojciech Macek return (0); 30387902c8dcSWojciech Macek } 30397902c8dcSWojciech Macek 30407902c8dcSWojciech Macek static int 30417902c8dcSWojciech Macek al_eth_udma_queue_enable(struct al_eth_adapter *adapter, enum al_udma_type type, 30427902c8dcSWojciech Macek int qid) 30437902c8dcSWojciech Macek { 30447902c8dcSWojciech Macek int rc = 0; 30457902c8dcSWojciech Macek char *name = (type == UDMA_TX) ? "Tx" : "Rx"; 30467902c8dcSWojciech Macek struct al_udma_q_params *q_params; 30477902c8dcSWojciech Macek 30487902c8dcSWojciech Macek if (type == UDMA_TX) 30497902c8dcSWojciech Macek q_params = &adapter->tx_ring[qid].q_params; 30507902c8dcSWojciech Macek else 30517902c8dcSWojciech Macek q_params = &adapter->rx_ring[qid].q_params; 30527902c8dcSWojciech Macek 30537902c8dcSWojciech Macek rc = al_eth_queue_config(&adapter->hal_adapter, type, qid, q_params); 30547902c8dcSWojciech Macek if (rc < 0) { 30557902c8dcSWojciech Macek device_printf(adapter->dev, "config %s queue %u failed\n", name, 30567902c8dcSWojciech Macek qid); 30577902c8dcSWojciech Macek return (rc); 30587902c8dcSWojciech Macek } 30597902c8dcSWojciech Macek return (rc); 30607902c8dcSWojciech Macek } 30617902c8dcSWojciech Macek 30627902c8dcSWojciech Macek static int 30637902c8dcSWojciech Macek al_eth_udma_queues_enable_all(struct al_eth_adapter *adapter) 30647902c8dcSWojciech Macek { 30657902c8dcSWojciech Macek int i; 30667902c8dcSWojciech Macek 30677902c8dcSWojciech Macek for (i = 0; i < adapter->num_tx_queues; i++) 30687902c8dcSWojciech Macek al_eth_udma_queue_enable(adapter, UDMA_TX, i); 30697902c8dcSWojciech Macek 30707902c8dcSWojciech Macek for (i = 0; i < adapter->num_rx_queues; i++) 30717902c8dcSWojciech Macek al_eth_udma_queue_enable(adapter, UDMA_RX, i); 30727902c8dcSWojciech Macek 30737902c8dcSWojciech Macek return (0); 30747902c8dcSWojciech Macek } 30757902c8dcSWojciech Macek 30767902c8dcSWojciech Macek static void 30777902c8dcSWojciech Macek al_eth_up_complete(struct al_eth_adapter *adapter) 30787902c8dcSWojciech Macek { 30797902c8dcSWojciech Macek 30807902c8dcSWojciech Macek al_eth_configure_int_mode(adapter); 30817902c8dcSWojciech Macek al_eth_config_rx_fwd(adapter); 3082f46a05b5SJustin Hibbits al_eth_change_mtu(adapter, if_getmtu(adapter->netdev)); 30837902c8dcSWojciech Macek al_eth_udma_queues_enable_all(adapter); 30847902c8dcSWojciech Macek al_eth_refill_all_rx_bufs(adapter); 30857902c8dcSWojciech Macek al_eth_interrupts_unmask(adapter); 30867902c8dcSWojciech Macek 30877902c8dcSWojciech Macek /* enable forwarding interrupts from eth through pci end point */ 30887902c8dcSWojciech Macek if ((adapter->board_type == ALPINE_FPGA_NIC) || 30897902c8dcSWojciech Macek (adapter->board_type == ALPINE_NIC)) { 30907902c8dcSWojciech Macek al_eth_forward_int_config((uint32_t*)adapter->internal_pcie_base + 30917902c8dcSWojciech Macek AL_REG_OFFSET_FORWARD_INTR, AL_EN_FORWARD_INTR); 30927902c8dcSWojciech Macek } 30937902c8dcSWojciech Macek 30947902c8dcSWojciech Macek al_eth_flow_ctrl_enable(adapter); 30957902c8dcSWojciech Macek 30967902c8dcSWojciech Macek mtx_lock(&adapter->stats_mtx); 30977902c8dcSWojciech Macek callout_reset(&adapter->stats_callout, hz, al_tick_stats, (void*)adapter); 30987902c8dcSWojciech Macek mtx_unlock(&adapter->stats_mtx); 30997902c8dcSWojciech Macek 31007902c8dcSWojciech Macek al_eth_mac_start(&adapter->hal_adapter); 31017902c8dcSWojciech Macek } 31027902c8dcSWojciech Macek 31037902c8dcSWojciech Macek static int 3104bc14c73bSJustin Hibbits al_media_update(if_t ifp) 31057902c8dcSWojciech Macek { 3106bc14c73bSJustin Hibbits struct al_eth_adapter *adapter = if_getsoftc(ifp); 31077902c8dcSWojciech Macek 3108bc14c73bSJustin Hibbits if ((if_getflags(ifp) & IFF_UP) != 0) 31097902c8dcSWojciech Macek mii_mediachg(adapter->mii); 31107902c8dcSWojciech Macek 31117902c8dcSWojciech Macek return (0); 31127902c8dcSWojciech Macek } 31137902c8dcSWojciech Macek 31147902c8dcSWojciech Macek static void 3115bc14c73bSJustin Hibbits al_media_status(if_t ifp, struct ifmediareq *ifmr) 31167902c8dcSWojciech Macek { 3117bc14c73bSJustin Hibbits struct al_eth_adapter *sc = if_getsoftc(ifp); 31187902c8dcSWojciech Macek struct mii_data *mii; 31197902c8dcSWojciech Macek 31207902c8dcSWojciech Macek if (sc->mii == NULL) { 31217902c8dcSWojciech Macek ifmr->ifm_active = IFM_ETHER | IFM_NONE; 31227902c8dcSWojciech Macek ifmr->ifm_status = 0; 31237902c8dcSWojciech Macek 31247902c8dcSWojciech Macek return; 31257902c8dcSWojciech Macek } 31267902c8dcSWojciech Macek 31277902c8dcSWojciech Macek mii = sc->mii; 31287902c8dcSWojciech Macek mii_pollstat(mii); 31297902c8dcSWojciech Macek 31307902c8dcSWojciech Macek ifmr->ifm_active = mii->mii_media_active; 31317902c8dcSWojciech Macek ifmr->ifm_status = mii->mii_media_status; 31327902c8dcSWojciech Macek } 31337902c8dcSWojciech Macek 31347902c8dcSWojciech Macek static void 31357902c8dcSWojciech Macek al_tick(void *arg) 31367902c8dcSWojciech Macek { 31377902c8dcSWojciech Macek struct al_eth_adapter *adapter = arg; 31387902c8dcSWojciech Macek 31397902c8dcSWojciech Macek mii_tick(adapter->mii); 31407902c8dcSWojciech Macek 31417902c8dcSWojciech Macek /* Schedule another timeout one second from now */ 31427902c8dcSWojciech Macek callout_schedule(&adapter->wd_callout, hz); 31437902c8dcSWojciech Macek } 31447902c8dcSWojciech Macek 31457902c8dcSWojciech Macek static void 31467902c8dcSWojciech Macek al_tick_stats(void *arg) 31477902c8dcSWojciech Macek { 31487902c8dcSWojciech Macek struct al_eth_adapter *adapter = arg; 31497902c8dcSWojciech Macek 31507902c8dcSWojciech Macek al_eth_update_stats(adapter); 31517902c8dcSWojciech Macek 31527902c8dcSWojciech Macek callout_schedule(&adapter->stats_callout, hz); 31537902c8dcSWojciech Macek } 31547902c8dcSWojciech Macek 31557902c8dcSWojciech Macek static int 31567902c8dcSWojciech Macek al_eth_up(struct al_eth_adapter *adapter) 31577902c8dcSWojciech Macek { 3158bc14c73bSJustin Hibbits if_t ifp = adapter->netdev; 31597902c8dcSWojciech Macek int rc; 31607902c8dcSWojciech Macek 31617902c8dcSWojciech Macek if (adapter->up) 31627902c8dcSWojciech Macek return (0); 31637902c8dcSWojciech Macek 31647902c8dcSWojciech Macek if ((adapter->flags & AL_ETH_FLAG_RESET_REQUESTED) != 0) { 31657902c8dcSWojciech Macek al_eth_function_reset(adapter); 31667902c8dcSWojciech Macek adapter->flags &= ~AL_ETH_FLAG_RESET_REQUESTED; 31677902c8dcSWojciech Macek } 31687902c8dcSWojciech Macek 3169bc14c73bSJustin Hibbits if_sethwassist(ifp, 0); 3170bc14c73bSJustin Hibbits if ((if_getcapenable(ifp) & IFCAP_TSO) != 0) 3171bc14c73bSJustin Hibbits if_sethwassistbits(ifp, CSUM_TSO, 0); 3172bc14c73bSJustin Hibbits if ((if_getcapenable(ifp) & IFCAP_TXCSUM) != 0) 3173bc14c73bSJustin Hibbits if_sethwassistbits(ifp, (CSUM_TCP | CSUM_UDP), 0); 3174bc14c73bSJustin Hibbits if ((if_getcapenable(ifp) & IFCAP_TXCSUM_IPV6) != 0) 3175bc14c73bSJustin Hibbits if_sethwassistbits(ifp, (CSUM_TCP_IPV6 | CSUM_UDP_IPV6), 0); 31767902c8dcSWojciech Macek 31777902c8dcSWojciech Macek al_eth_serdes_init(adapter); 31787902c8dcSWojciech Macek 31797902c8dcSWojciech Macek rc = al_eth_hw_init(adapter); 31807902c8dcSWojciech Macek if (rc != 0) 31817902c8dcSWojciech Macek goto err_hw_init_open; 31827902c8dcSWojciech Macek 31837902c8dcSWojciech Macek rc = al_eth_setup_int_mode(adapter); 31847902c8dcSWojciech Macek if (rc != 0) { 31857902c8dcSWojciech Macek device_printf(adapter->dev, 31867902c8dcSWojciech Macek "%s failed at setup interrupt mode!\n", __func__); 31877902c8dcSWojciech Macek goto err_setup_int; 31887902c8dcSWojciech Macek } 31897902c8dcSWojciech Macek 31907902c8dcSWojciech Macek /* allocate transmit descriptors */ 31917902c8dcSWojciech Macek rc = al_eth_setup_all_tx_resources(adapter); 31927902c8dcSWojciech Macek if (rc != 0) 31937902c8dcSWojciech Macek goto err_setup_tx; 31947902c8dcSWojciech Macek 31957902c8dcSWojciech Macek /* allocate receive descriptors */ 31967902c8dcSWojciech Macek rc = al_eth_setup_all_rx_resources(adapter); 31977902c8dcSWojciech Macek if (rc != 0) 31987902c8dcSWojciech Macek goto err_setup_rx; 31997902c8dcSWojciech Macek 32007902c8dcSWojciech Macek rc = al_eth_request_irq(adapter); 32017902c8dcSWojciech Macek if (rc != 0) 32027902c8dcSWojciech Macek goto err_req_irq; 32037902c8dcSWojciech Macek 32047902c8dcSWojciech Macek al_eth_up_complete(adapter); 32057902c8dcSWojciech Macek 32067902c8dcSWojciech Macek adapter->up = true; 32077902c8dcSWojciech Macek 32087902c8dcSWojciech Macek if (adapter->mac_mode == AL_ETH_MAC_MODE_10GbE_Serial) 3209f46a05b5SJustin Hibbits if_link_state_change(adapter->netdev, LINK_STATE_UP); 32107902c8dcSWojciech Macek 32117902c8dcSWojciech Macek if (adapter->mac_mode == AL_ETH_MAC_MODE_RGMII) { 32127902c8dcSWojciech Macek mii_mediachg(adapter->mii); 32137902c8dcSWojciech Macek 32147902c8dcSWojciech Macek /* Schedule watchdog timeout */ 32157902c8dcSWojciech Macek mtx_lock(&adapter->wd_mtx); 32167902c8dcSWojciech Macek callout_reset(&adapter->wd_callout, hz, al_tick, adapter); 32177902c8dcSWojciech Macek mtx_unlock(&adapter->wd_mtx); 32187902c8dcSWojciech Macek 32197902c8dcSWojciech Macek mii_pollstat(adapter->mii); 32207902c8dcSWojciech Macek } 32217902c8dcSWojciech Macek 32227902c8dcSWojciech Macek return (rc); 32237902c8dcSWojciech Macek 32247902c8dcSWojciech Macek err_req_irq: 32257902c8dcSWojciech Macek al_eth_free_all_rx_resources(adapter); 32267902c8dcSWojciech Macek err_setup_rx: 32277902c8dcSWojciech Macek al_eth_free_all_tx_resources(adapter); 32287902c8dcSWojciech Macek err_setup_tx: 32297902c8dcSWojciech Macek al_eth_free_irq(adapter); 32307902c8dcSWojciech Macek err_setup_int: 32317902c8dcSWojciech Macek al_eth_hw_stop(adapter); 32327902c8dcSWojciech Macek err_hw_init_open: 32337902c8dcSWojciech Macek al_eth_function_reset(adapter); 32347902c8dcSWojciech Macek 32357902c8dcSWojciech Macek return (rc); 32367902c8dcSWojciech Macek } 32377902c8dcSWojciech Macek 32387902c8dcSWojciech Macek static int 32397902c8dcSWojciech Macek al_shutdown(device_t dev) 32407902c8dcSWojciech Macek { 32417902c8dcSWojciech Macek struct al_eth_adapter *adapter = device_get_softc(dev); 32427902c8dcSWojciech Macek 32437902c8dcSWojciech Macek al_eth_down(adapter); 32447902c8dcSWojciech Macek 32457902c8dcSWojciech Macek return (0); 32467902c8dcSWojciech Macek } 32477902c8dcSWojciech Macek 32487902c8dcSWojciech Macek static void 32497902c8dcSWojciech Macek al_eth_down(struct al_eth_adapter *adapter) 32507902c8dcSWojciech Macek { 32517902c8dcSWojciech Macek 32527902c8dcSWojciech Macek device_printf_dbg(adapter->dev, "al_eth_down: begin\n"); 32537902c8dcSWojciech Macek 32547902c8dcSWojciech Macek adapter->up = false; 32557902c8dcSWojciech Macek 32567902c8dcSWojciech Macek mtx_lock(&adapter->wd_mtx); 32577902c8dcSWojciech Macek callout_stop(&adapter->wd_callout); 32587902c8dcSWojciech Macek mtx_unlock(&adapter->wd_mtx); 32597902c8dcSWojciech Macek 32607902c8dcSWojciech Macek al_eth_disable_int_sync(adapter); 32617902c8dcSWojciech Macek 32627902c8dcSWojciech Macek mtx_lock(&adapter->stats_mtx); 32637902c8dcSWojciech Macek callout_stop(&adapter->stats_callout); 32647902c8dcSWojciech Macek mtx_unlock(&adapter->stats_mtx); 32657902c8dcSWojciech Macek 32667902c8dcSWojciech Macek al_eth_free_irq(adapter); 32677902c8dcSWojciech Macek al_eth_hw_stop(adapter); 32687902c8dcSWojciech Macek 32697902c8dcSWojciech Macek al_eth_free_all_tx_resources(adapter); 32707902c8dcSWojciech Macek al_eth_free_all_rx_resources(adapter); 32717902c8dcSWojciech Macek } 32727902c8dcSWojciech Macek 32737902c8dcSWojciech Macek static int 3274bc14c73bSJustin Hibbits al_ioctl(if_t ifp, u_long command, caddr_t data) 32757902c8dcSWojciech Macek { 3276bc14c73bSJustin Hibbits struct al_eth_adapter *adapter = if_getsoftc(ifp); 32777902c8dcSWojciech Macek struct ifreq *ifr = (struct ifreq *)data; 32787902c8dcSWojciech Macek int error = 0; 32797902c8dcSWojciech Macek 32807902c8dcSWojciech Macek switch (command) { 32817902c8dcSWojciech Macek case SIOCSIFMTU: 32827902c8dcSWojciech Macek { 32837902c8dcSWojciech Macek error = al_eth_check_mtu(adapter, ifr->ifr_mtu); 32847902c8dcSWojciech Macek if (error != 0) { 32857902c8dcSWojciech Macek device_printf(adapter->dev, "ioctl wrong mtu %u\n", 3286f46a05b5SJustin Hibbits if_getmtu(adapter->netdev)); 32877902c8dcSWojciech Macek break; 32887902c8dcSWojciech Macek } 32897902c8dcSWojciech Macek 3290bc14c73bSJustin Hibbits if_setdrvflagbits(ifp, 0, IFF_DRV_RUNNING); 3291f46a05b5SJustin Hibbits if_setmtu(adapter->netdev, ifr->ifr_mtu); 32927902c8dcSWojciech Macek al_init(adapter); 32937902c8dcSWojciech Macek break; 32947902c8dcSWojciech Macek } 32957902c8dcSWojciech Macek case SIOCSIFFLAGS: 3296bc14c73bSJustin Hibbits if ((if_getflags(ifp) & IFF_UP) != 0) { 3297bc14c73bSJustin Hibbits if ((if_getdrvflags(ifp) & IFF_DRV_RUNNING) != 0) { 3298bc14c73bSJustin Hibbits if (((if_getflags(ifp) ^ adapter->if_flags) & 32997902c8dcSWojciech Macek (IFF_PROMISC | IFF_ALLMULTI)) != 0) { 33007902c8dcSWojciech Macek device_printf_dbg(adapter->dev, 33017902c8dcSWojciech Macek "ioctl promisc/allmulti\n"); 33027902c8dcSWojciech Macek al_eth_set_rx_mode(adapter); 33037902c8dcSWojciech Macek } 33047902c8dcSWojciech Macek } else { 33057902c8dcSWojciech Macek error = al_eth_up(adapter); 33067902c8dcSWojciech Macek if (error == 0) 3307bc14c73bSJustin Hibbits if_setdrvflagbits(ifp, IFF_DRV_RUNNING, 0); 33087902c8dcSWojciech Macek } 33097902c8dcSWojciech Macek } else { 3310bc14c73bSJustin Hibbits if ((if_getdrvflags(ifp) & IFF_DRV_RUNNING) != 0) { 33117902c8dcSWojciech Macek al_eth_down(adapter); 3312bc14c73bSJustin Hibbits if_setdrvflagbits(ifp, 0, IFF_DRV_RUNNING); 33137902c8dcSWojciech Macek } 33147902c8dcSWojciech Macek } 33157902c8dcSWojciech Macek 3316bc14c73bSJustin Hibbits adapter->if_flags = if_getflags(ifp); 33177902c8dcSWojciech Macek break; 33187902c8dcSWojciech Macek 33197902c8dcSWojciech Macek case SIOCADDMULTI: 33207902c8dcSWojciech Macek case SIOCDELMULTI: 3321bc14c73bSJustin Hibbits if ((if_getdrvflags(ifp) & IFF_DRV_RUNNING) != 0) { 33227902c8dcSWojciech Macek device_printf_dbg(adapter->dev, 33237902c8dcSWojciech Macek "ioctl add/del multi before\n"); 33247902c8dcSWojciech Macek al_eth_set_rx_mode(adapter); 33257902c8dcSWojciech Macek #ifdef DEVICE_POLLING 3326bc14c73bSJustin Hibbits if ((if_getcapenable(ifp) & IFCAP_POLLING) == 0) 33277902c8dcSWojciech Macek #endif 33287902c8dcSWojciech Macek } 33297902c8dcSWojciech Macek break; 33307902c8dcSWojciech Macek case SIOCSIFMEDIA: 33317902c8dcSWojciech Macek case SIOCGIFMEDIA: 33327902c8dcSWojciech Macek if (adapter->mii != NULL) 33337902c8dcSWojciech Macek error = ifmedia_ioctl(ifp, ifr, 33347902c8dcSWojciech Macek &adapter->mii->mii_media, command); 33357902c8dcSWojciech Macek else 33367902c8dcSWojciech Macek error = ifmedia_ioctl(ifp, ifr, 33377902c8dcSWojciech Macek &adapter->media, command); 33387902c8dcSWojciech Macek break; 33397902c8dcSWojciech Macek case SIOCSIFCAP: 33407902c8dcSWojciech Macek { 33417902c8dcSWojciech Macek int mask, reinit; 33427902c8dcSWojciech Macek 33437902c8dcSWojciech Macek reinit = 0; 3344bc14c73bSJustin Hibbits mask = ifr->ifr_reqcap ^ if_getcapenable(ifp); 33457902c8dcSWojciech Macek #ifdef DEVICE_POLLING 33467902c8dcSWojciech Macek if ((mask & IFCAP_POLLING) != 0) { 33477902c8dcSWojciech Macek if ((ifr->ifr_reqcap & IFCAP_POLLING) != 0) { 33487902c8dcSWojciech Macek if (error != 0) 33497902c8dcSWojciech Macek return (error); 3350bc14c73bSJustin Hibbits if_setcapenablebit(ifp, IFCAP_POLLING, 0); 33517902c8dcSWojciech Macek } else { 33527902c8dcSWojciech Macek error = ether_poll_deregister(ifp); 33537902c8dcSWojciech Macek /* Enable interrupt even in error case */ 3354bc14c73bSJustin Hibbits if_setcapenablebit(ifp, 0, IFCAP_POLLING); 33557902c8dcSWojciech Macek } 33567902c8dcSWojciech Macek } 33577902c8dcSWojciech Macek #endif 33587902c8dcSWojciech Macek if ((mask & IFCAP_HWCSUM) != 0) { 33597902c8dcSWojciech Macek /* apply to both rx and tx */ 3360bc14c73bSJustin Hibbits if_togglecapenable(ifp, IFCAP_HWCSUM); 33617902c8dcSWojciech Macek reinit = 1; 33627902c8dcSWojciech Macek } 33637902c8dcSWojciech Macek if ((mask & IFCAP_HWCSUM_IPV6) != 0) { 3364bc14c73bSJustin Hibbits if_togglecapenable(ifp, IFCAP_HWCSUM_IPV6); 33657902c8dcSWojciech Macek reinit = 1; 33667902c8dcSWojciech Macek } 33677902c8dcSWojciech Macek if ((mask & IFCAP_TSO) != 0) { 3368bc14c73bSJustin Hibbits if_togglecapenable(ifp, IFCAP_TSO); 33697902c8dcSWojciech Macek reinit = 1; 33707902c8dcSWojciech Macek } 33717902c8dcSWojciech Macek if ((mask & IFCAP_LRO) != 0) { 3372bc14c73bSJustin Hibbits if_togglecapenable(ifp, IFCAP_LRO); 33737902c8dcSWojciech Macek } 33747902c8dcSWojciech Macek if ((mask & IFCAP_VLAN_HWTAGGING) != 0) { 3375bc14c73bSJustin Hibbits if_togglecapenable(ifp, IFCAP_VLAN_HWTAGGING); 33767902c8dcSWojciech Macek reinit = 1; 33777902c8dcSWojciech Macek } 33787902c8dcSWojciech Macek if ((mask & IFCAP_VLAN_HWFILTER) != 0) { 3379bc14c73bSJustin Hibbits if_togglecapenable(ifp, IFCAP_VLAN_HWFILTER); 33807902c8dcSWojciech Macek reinit = 1; 33817902c8dcSWojciech Macek } 33827902c8dcSWojciech Macek if ((mask & IFCAP_VLAN_HWTSO) != 0) { 3383bc14c73bSJustin Hibbits if_togglecapenable(ifp, IFCAP_VLAN_HWTSO); 33847902c8dcSWojciech Macek reinit = 1; 33857902c8dcSWojciech Macek } 33867902c8dcSWojciech Macek if ((reinit != 0) && 3387bc14c73bSJustin Hibbits ((if_getdrvflags(ifp) & IFF_DRV_RUNNING)) != 0) 33887902c8dcSWojciech Macek { 33897902c8dcSWojciech Macek al_init(adapter); 33907902c8dcSWojciech Macek } 33917902c8dcSWojciech Macek break; 33927902c8dcSWojciech Macek } 33937902c8dcSWojciech Macek 33947902c8dcSWojciech Macek default: 33957902c8dcSWojciech Macek error = ether_ioctl(ifp, command, data); 33967902c8dcSWojciech Macek break; 33977902c8dcSWojciech Macek } 33987902c8dcSWojciech Macek 33997902c8dcSWojciech Macek return (error); 34007902c8dcSWojciech Macek } 34017902c8dcSWojciech Macek 34027902c8dcSWojciech Macek static int 34037902c8dcSWojciech Macek al_is_device_supported(device_t dev) 34047902c8dcSWojciech Macek { 34057902c8dcSWojciech Macek uint16_t pci_vendor_id = pci_get_vendor(dev); 34067902c8dcSWojciech Macek uint16_t pci_device_id = pci_get_device(dev); 34077902c8dcSWojciech Macek 34087902c8dcSWojciech Macek return (pci_vendor_id == PCI_VENDOR_ID_ANNAPURNA_LABS && 34097902c8dcSWojciech Macek (pci_device_id == PCI_DEVICE_ID_AL_ETH || 34107902c8dcSWojciech Macek pci_device_id == PCI_DEVICE_ID_AL_ETH_ADVANCED || 34117902c8dcSWojciech Macek pci_device_id == PCI_DEVICE_ID_AL_ETH_NIC || 34127902c8dcSWojciech Macek pci_device_id == PCI_DEVICE_ID_AL_ETH_FPGA_NIC)); 34137902c8dcSWojciech Macek } 34147902c8dcSWojciech Macek 34157902c8dcSWojciech Macek /* Time in mSec to keep trying to read / write from MDIO in case of error */ 34167902c8dcSWojciech Macek #define MDIO_TIMEOUT_MSEC 100 34177902c8dcSWojciech Macek #define MDIO_PAUSE_MSEC 10 34187902c8dcSWojciech Macek 34197902c8dcSWojciech Macek static int 34207902c8dcSWojciech Macek al_miibus_readreg(device_t dev, int phy, int reg) 34217902c8dcSWojciech Macek { 34227902c8dcSWojciech Macek struct al_eth_adapter *adapter = device_get_softc(dev); 34237902c8dcSWojciech Macek uint16_t value = 0; 34247902c8dcSWojciech Macek int rc; 34257902c8dcSWojciech Macek int timeout = MDIO_TIMEOUT_MSEC; 34267902c8dcSWojciech Macek 34277902c8dcSWojciech Macek while (timeout > 0) { 34287902c8dcSWojciech Macek rc = al_eth_mdio_read(&adapter->hal_adapter, adapter->phy_addr, 34297902c8dcSWojciech Macek -1, reg, &value); 34307902c8dcSWojciech Macek 34317902c8dcSWojciech Macek if (rc == 0) 34327902c8dcSWojciech Macek return (value); 34337902c8dcSWojciech Macek 34347902c8dcSWojciech Macek device_printf_dbg(adapter->dev, 34357902c8dcSWojciech Macek "mdio read failed. try again in 10 msec\n"); 34367902c8dcSWojciech Macek 34377902c8dcSWojciech Macek timeout -= MDIO_PAUSE_MSEC; 34387902c8dcSWojciech Macek pause("readred pause", MDIO_PAUSE_MSEC); 34397902c8dcSWojciech Macek } 34407902c8dcSWojciech Macek 34417902c8dcSWojciech Macek if (rc != 0) 34427902c8dcSWojciech Macek device_printf(adapter->dev, "MDIO read failed on timeout\n"); 34437902c8dcSWojciech Macek 34447902c8dcSWojciech Macek return (value); 34457902c8dcSWojciech Macek } 34467902c8dcSWojciech Macek 34477902c8dcSWojciech Macek static int 34487902c8dcSWojciech Macek al_miibus_writereg(device_t dev, int phy, int reg, int value) 34497902c8dcSWojciech Macek { 34507902c8dcSWojciech Macek struct al_eth_adapter *adapter = device_get_softc(dev); 34517902c8dcSWojciech Macek int rc; 34527902c8dcSWojciech Macek int timeout = MDIO_TIMEOUT_MSEC; 34537902c8dcSWojciech Macek 34547902c8dcSWojciech Macek while (timeout > 0) { 34557902c8dcSWojciech Macek rc = al_eth_mdio_write(&adapter->hal_adapter, adapter->phy_addr, 34567902c8dcSWojciech Macek -1, reg, value); 34577902c8dcSWojciech Macek 34587902c8dcSWojciech Macek if (rc == 0) 34597902c8dcSWojciech Macek return (0); 34607902c8dcSWojciech Macek 34617902c8dcSWojciech Macek device_printf(adapter->dev, 34627902c8dcSWojciech Macek "mdio write failed. try again in 10 msec\n"); 34637902c8dcSWojciech Macek 34647902c8dcSWojciech Macek timeout -= MDIO_PAUSE_MSEC; 34657902c8dcSWojciech Macek pause("miibus writereg", MDIO_PAUSE_MSEC); 34667902c8dcSWojciech Macek } 34677902c8dcSWojciech Macek 34687902c8dcSWojciech Macek if (rc != 0) 34697902c8dcSWojciech Macek device_printf(adapter->dev, "MDIO write failed on timeout\n"); 34707902c8dcSWojciech Macek 34717902c8dcSWojciech Macek return (rc); 34727902c8dcSWojciech Macek } 34737902c8dcSWojciech Macek 34747902c8dcSWojciech Macek static void 34757902c8dcSWojciech Macek al_miibus_statchg(device_t dev) 34767902c8dcSWojciech Macek { 34777902c8dcSWojciech Macek struct al_eth_adapter *adapter = device_get_softc(dev); 34787902c8dcSWojciech Macek 34797902c8dcSWojciech Macek device_printf_dbg(adapter->dev, 34807902c8dcSWojciech Macek "al_miibus_statchg: state has changed!\n"); 34817902c8dcSWojciech Macek device_printf_dbg(adapter->dev, 34827902c8dcSWojciech Macek "al_miibus_statchg: active = 0x%x status = 0x%x\n", 34837902c8dcSWojciech Macek adapter->mii->mii_media_active, adapter->mii->mii_media_status); 34847902c8dcSWojciech Macek 34857902c8dcSWojciech Macek if (adapter->up == 0) 34867902c8dcSWojciech Macek return; 34877902c8dcSWojciech Macek 34887902c8dcSWojciech Macek if ((adapter->mii->mii_media_status & IFM_AVALID) != 0) { 34897902c8dcSWojciech Macek if (adapter->mii->mii_media_status & IFM_ACTIVE) { 34907902c8dcSWojciech Macek device_printf(adapter->dev, "link is UP\n"); 3491f46a05b5SJustin Hibbits if_link_state_change(adapter->netdev, LINK_STATE_UP); 34927902c8dcSWojciech Macek } else { 34937902c8dcSWojciech Macek device_printf(adapter->dev, "link is DOWN\n"); 3494f46a05b5SJustin Hibbits if_link_state_change(adapter->netdev, LINK_STATE_DOWN); 34957902c8dcSWojciech Macek } 34967902c8dcSWojciech Macek } 34977902c8dcSWojciech Macek } 34987902c8dcSWojciech Macek 34997902c8dcSWojciech Macek static void 35007902c8dcSWojciech Macek al_miibus_linkchg(device_t dev) 35017902c8dcSWojciech Macek { 35027902c8dcSWojciech Macek struct al_eth_adapter *adapter = device_get_softc(dev); 35037902c8dcSWojciech Macek uint8_t duplex = 0; 35047902c8dcSWojciech Macek uint8_t speed = 0; 35057902c8dcSWojciech Macek 35064d24901aSPedro F. Giffuni if (adapter->mii == NULL) 35077902c8dcSWojciech Macek return; 35087902c8dcSWojciech Macek 3509f46a05b5SJustin Hibbits if ((if_getflags(adapter->netdev) & IFF_UP) == 0) 35107902c8dcSWojciech Macek return; 35117902c8dcSWojciech Macek 35127902c8dcSWojciech Macek /* Ignore link changes when link is not ready */ 35137902c8dcSWojciech Macek if ((adapter->mii->mii_media_status & (IFM_AVALID | IFM_ACTIVE)) != 35147902c8dcSWojciech Macek (IFM_AVALID | IFM_ACTIVE)) { 35157902c8dcSWojciech Macek return; 35167902c8dcSWojciech Macek } 35177902c8dcSWojciech Macek 35187902c8dcSWojciech Macek if ((adapter->mii->mii_media_active & IFM_FDX) != 0) 35197902c8dcSWojciech Macek duplex = 1; 35207902c8dcSWojciech Macek 35217902c8dcSWojciech Macek speed = IFM_SUBTYPE(adapter->mii->mii_media_active); 35227902c8dcSWojciech Macek 35237902c8dcSWojciech Macek if (speed == IFM_10_T) { 35247902c8dcSWojciech Macek al_eth_mac_link_config(&adapter->hal_adapter, 0, 1, 35257902c8dcSWojciech Macek AL_10BASE_T_SPEED, duplex); 35267902c8dcSWojciech Macek return; 35277902c8dcSWojciech Macek } 35287902c8dcSWojciech Macek 35297902c8dcSWojciech Macek if (speed == IFM_100_TX) { 35307902c8dcSWojciech Macek al_eth_mac_link_config(&adapter->hal_adapter, 0, 1, 35317902c8dcSWojciech Macek AL_100BASE_TX_SPEED, duplex); 35327902c8dcSWojciech Macek return; 35337902c8dcSWojciech Macek } 35347902c8dcSWojciech Macek 35357902c8dcSWojciech Macek if (speed == IFM_1000_T) { 35367902c8dcSWojciech Macek al_eth_mac_link_config(&adapter->hal_adapter, 0, 1, 35377902c8dcSWojciech Macek AL_1000BASE_T_SPEED, duplex); 35387902c8dcSWojciech Macek return; 35397902c8dcSWojciech Macek } 35407902c8dcSWojciech Macek 35417902c8dcSWojciech Macek device_printf(adapter->dev, "ERROR: unknown MII media active 0x%08x\n", 35427902c8dcSWojciech Macek adapter->mii->mii_media_active); 35437902c8dcSWojciech Macek } 3544