Date: Thu, 20 Oct 2016 11:31:11 +0000 (UTC) From: Wojciech Macek <wma@FreeBSD.org> To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r307670 - in head/sys: arm/conf arm64/conf conf dev/al_eth Message-ID: <201610201131.u9KBVBDk070088@repo.freebsd.org>
next in thread | raw e-mail | index | archive | help
Author: wma Date: Thu Oct 20 11:31:11 2016 New Revision: 307670 URL: https://svnweb.freebsd.org/changeset/base/307670 Log: Driver for PCI Ethernet NIC on Alpine V1 and V2. Obtained from: Semihalf Submitted by: Michal Stanek <mst@semihalf.com> Sponsored by: Annapurna Labs Reviewed by: wma Differential Revision: https://reviews.freebsd.org/D7814 Added: head/sys/dev/al_eth/ head/sys/dev/al_eth/al_eth.c (contents, props changed) head/sys/dev/al_eth/al_eth.h (contents, props changed) head/sys/dev/al_eth/al_init_eth_kr.c (contents, props changed) head/sys/dev/al_eth/al_init_eth_kr.h (contents, props changed) head/sys/dev/al_eth/al_init_eth_lm.c (contents, props changed) head/sys/dev/al_eth/al_init_eth_lm.h (contents, props changed) Modified: head/sys/arm/conf/ALPINE head/sys/arm64/conf/GENERIC head/sys/conf/files Modified: head/sys/arm/conf/ALPINE ============================================================================== --- head/sys/arm/conf/ALPINE Thu Oct 20 11:26:51 2016 (r307669) +++ head/sys/arm/conf/ALPINE Thu Oct 20 11:31:11 2016 (r307670) @@ -35,6 +35,9 @@ options INTRNG # Annapurna Alpine drivers device al_ccu # Alpine Cache Coherency Unit device al_nb_service # Alpine North Bridge Service +device al_iofic # I/O Fabric Interrupt Controller +device al_serdes # Serializer/Deserializer +device al_udma # Universal DMA # Pseudo devices device loop @@ -69,6 +72,7 @@ device al_pci # Annapurna Alpine PCI-E device ether device mii device bpf +device al_eth # Annapurna Alpine Ethernet NIC options DEVICE_POLLING # USB ethernet support, requires miibus Modified: head/sys/arm64/conf/GENERIC ============================================================================== --- head/sys/arm64/conf/GENERIC Thu Oct 20 11:26:51 2016 (r307669) +++ head/sys/arm64/conf/GENERIC Thu Oct 20 11:31:11 2016 (r307670) @@ -94,6 +94,9 @@ options SOC_HISI_HI6220 # Annapurna Alpine drivers device al_ccu # Alpine Cache Coherency Unit device al_nb_service # Alpine North Bridge Service +device al_iofic # I/O Fabric Interrupt Controller +device al_serdes # Serializer/Deserializer +device al_udma # Universal DMA # VirtIO support device virtio @@ -119,6 +122,7 @@ device igb # Intel PRO/1000 PCIE Serve device ix # Intel 10Gb Ethernet Family device msk # Marvell/SysKonnect Yukon II Gigabit Ethernet device vnic # Cavium ThunderX NIC +device al_eth # Annapurna Alpine Ethernet NIC # Block devices device ahci Modified: head/sys/conf/files ============================================================================== --- head/sys/conf/files Thu Oct 20 11:26:51 2016 (r307669) +++ head/sys/conf/files Thu Oct 20 11:31:11 2016 (r307670) @@ -709,6 +709,45 @@ dev/aic7xxx/aic7xxx_93cx6.c optional ahc dev/aic7xxx/aic7xxx_osm.c optional ahc dev/aic7xxx/aic7xxx_pci.c optional ahc pci dev/aic7xxx/aic7xxx_reg_print.c optional ahc ahc_reg_pretty_print +dev/al_eth/al_eth.c optional al_eth \ + no-depend \ + compile-with "${CC} -c -o ${.TARGET} ${CFLAGS} -I$S/contrib/alpine-hal -I$S/contrib/alpine-hal/eth ${PROF} ${.IMPSRC}" +dev/al_eth/al_init_eth_lm.c optional al_eth \ + no-depend \ + compile-with "${CC} -c -o ${.TARGET} ${CFLAGS} -I$S/contrib/alpine-hal -I$S/contrib/alpine-hal/eth ${PROF} ${.IMPSRC}" +dev/al_eth/al_init_eth_kr.c optional al_eth \ + no-depend \ + compile-with "${CC} -c -o ${.TARGET} ${CFLAGS} -I$S/contrib/alpine-hal -I$S/contrib/alpine-hal/eth ${PROF} ${.IMPSRC}" +contrib/alpine-hal/al_hal_iofic.c optional al_iofic \ + no-depend \ + compile-with "${CC} -c -o ${.TARGET} ${CFLAGS} -I$S/contrib/alpine-hal -I$S/contrib/alpine-hal/eth ${PROF} ${.IMPSRC}" +contrib/alpine-hal/al_hal_serdes_25g.c optional al_serdes \ + no-depend \ + compile-with "${CC} -c -o ${.TARGET} ${CFLAGS} -I$S/contrib/alpine-hal -I$S/contrib/alpine-hal/eth ${PROF} ${.IMPSRC}" +contrib/alpine-hal/al_hal_serdes_hssp.c optional al_serdes \ + no-depend \ + compile-with "${CC} -c -o ${.TARGET} ${CFLAGS} -I$S/contrib/alpine-hal -I$S/contrib/alpine-hal/eth ${PROF} ${.IMPSRC}" +contrib/alpine-hal/al_hal_udma_config.c optional al_udma \ + no-depend \ + compile-with "${CC} -c -o ${.TARGET} ${CFLAGS} -I$S/contrib/alpine-hal -I$S/contrib/alpine-hal/eth ${PROF} ${.IMPSRC}" +contrib/alpine-hal/al_hal_udma_debug.c optional al_udma \ + no-depend \ + compile-with "${CC} -c -o ${.TARGET} ${CFLAGS} -I$S/contrib/alpine-hal -I$S/contrib/alpine-hal/eth ${PROF} ${.IMPSRC}" +contrib/alpine-hal/al_hal_udma_iofic.c optional al_udma \ + no-depend \ + compile-with "${CC} -c -o ${.TARGET} ${CFLAGS} -I$S/contrib/alpine-hal -I$S/contrib/alpine-hal/eth ${PROF} ${.IMPSRC}" +contrib/alpine-hal/al_hal_udma_main.c optional al_udma \ + no-depend \ + compile-with "${CC} -c -o ${.TARGET} ${CFLAGS} -I$S/contrib/alpine-hal -I$S/contrib/alpine-hal/eth ${PROF} ${.IMPSRC}" +contrib/alpine-hal/al_serdes.c optional al_serdes \ + no-depend \ + compile-with "${CC} -c -o ${.TARGET} ${CFLAGS} -I$S/contrib/alpine-hal -I$S/contrib/alpine-hal/eth ${PROF} ${.IMPSRC}" +contrib/alpine-hal/eth/al_hal_eth_kr.c optional al_eth \ + no-depend \ + compile-with "${CC} -c -o ${.TARGET} ${CFLAGS} -I$S/contrib/alpine-hal -I$S/contrib/alpine-hal/eth ${PROF} ${.IMPSRC}" +contrib/alpine-hal/eth/al_hal_eth_main.c optional al_eth \ + no-depend \ + compile-with "${CC} -c -o ${.TARGET} ${CFLAGS} -I$S/contrib/alpine-hal -I$S/contrib/alpine-hal/eth ${PROF} ${.IMPSRC}" dev/alc/if_alc.c optional alc pci dev/ale/if_ale.c optional ale pci dev/alpm/alpm.c optional alpm pci Added: head/sys/dev/al_eth/al_eth.c ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ head/sys/dev/al_eth/al_eth.c Thu Oct 20 11:31:11 2016 (r307670) @@ -0,0 +1,3584 @@ +/*- + * Copyright (c) 2015,2016 Annapurna Labs Ltd. and affiliates + * All rights reserved. + * + * Developed by Semihalf. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/bus.h> +#include <sys/kernel.h> +#include <sys/kthread.h> +#include <sys/lock.h> +#include <sys/mbuf.h> +#include <sys/malloc.h> +#include <sys/module.h> +#include <sys/rman.h> +#include <sys/socket.h> +#include <sys/sockio.h> +#include <sys/sysctl.h> +#include <sys/taskqueue.h> + +#include <machine/atomic.h> + +#include "opt_inet.h" +#include "opt_inet6.h" + +#include <net/ethernet.h> +#include <net/if.h> +#include <net/if_var.h> +#include <net/if_arp.h> +#include <net/if_dl.h> +#include <net/if_media.h> +#include <net/if_types.h> +#include <netinet/in.h> +#include <net/if_vlan_var.h> +#include <netinet/tcp.h> +#include <netinet/tcp_lro.h> + +#ifdef INET +#include <netinet/in.h> +#include <netinet/in_systm.h> +#include <netinet/in_var.h> +#include <netinet/ip.h> +#endif + +#ifdef INET6 +#include <netinet/ip6.h> +#endif + +#include <sys/sockio.h> + +#include <dev/pci/pcireg.h> +#include <dev/pci/pcivar.h> + +#include <dev/mii/mii.h> +#include <dev/mii/miivar.h> + +#include <al_hal_common.h> +#include <al_hal_plat_services.h> +#include <al_hal_udma_config.h> +#include <al_hal_udma_iofic.h> +#include <al_hal_udma_debug.h> +#include <al_hal_eth.h> + +#include "al_eth.h" +#include "al_init_eth_lm.h" +#include "arm/annapurna/alpine/alpine_serdes.h" + +#include "miibus_if.h" + +#define device_printf_dbg(fmt, ...) do { \ + if (AL_DBG_LEVEL >= AL_DBG_LEVEL_DBG) { AL_DBG_LOCK(); \ + device_printf(fmt, __VA_ARGS__); AL_DBG_UNLOCK();} \ + } while (0) + +MALLOC_DEFINE(M_IFAL, "if_al_malloc", "All allocated data for AL ETH driver"); + +/* move out to some pci header file */ +#define PCI_VENDOR_ID_ANNAPURNA_LABS 0x1c36 +#define PCI_DEVICE_ID_AL_ETH 0x0001 +#define PCI_DEVICE_ID_AL_ETH_ADVANCED 0x0002 +#define PCI_DEVICE_ID_AL_ETH_NIC 0x0003 +#define PCI_DEVICE_ID_AL_ETH_FPGA_NIC 0x0030 +#define PCI_DEVICE_ID_AL_CRYPTO 0x0011 +#define PCI_DEVICE_ID_AL_CRYPTO_VF 0x8011 +#define PCI_DEVICE_ID_AL_RAID_DMA 0x0021 +#define PCI_DEVICE_ID_AL_RAID_DMA_VF 0x8021 +#define PCI_DEVICE_ID_AL_USB 0x0041 + +#define MAC_ADDR_STR "%02x:%02x:%02x:%02x:%02x:%02x" +#define MAC_ADDR(addr) addr[0], addr[1], addr[2], addr[3], addr[4], addr[5] + +#define AL_ETH_MAC_TABLE_UNICAST_IDX_BASE 0 +#define AL_ETH_MAC_TABLE_UNICAST_MAX_COUNT 4 +#define AL_ETH_MAC_TABLE_ALL_MULTICAST_IDX (AL_ETH_MAC_TABLE_UNICAST_IDX_BASE + \ + AL_ETH_MAC_TABLE_UNICAST_MAX_COUNT) + +#define AL_ETH_MAC_TABLE_DROP_IDX (AL_ETH_FWD_MAC_NUM - 1) +#define AL_ETH_MAC_TABLE_BROADCAST_IDX (AL_ETH_MAC_TABLE_DROP_IDX - 1) + +#define AL_ETH_THASH_UDMA_SHIFT 0 +#define AL_ETH_THASH_UDMA_MASK (0xF << AL_ETH_THASH_UDMA_SHIFT) + +#define AL_ETH_THASH_Q_SHIFT 4 +#define AL_ETH_THASH_Q_MASK (0x3 << AL_ETH_THASH_Q_SHIFT) + +/* the following defines should be moved to hal */ +#define AL_ETH_FSM_ENTRY_IPV4_TCP 0 +#define AL_ETH_FSM_ENTRY_IPV4_UDP 1 +#define AL_ETH_FSM_ENTRY_IPV6_TCP 2 +#define AL_ETH_FSM_ENTRY_IPV6_UDP 3 +#define AL_ETH_FSM_ENTRY_IPV6_NO_UDP_TCP 4 +#define AL_ETH_FSM_ENTRY_IPV4_NO_UDP_TCP 5 + +/* FSM DATA format */ +#define AL_ETH_FSM_DATA_OUTER_2_TUPLE 0 +#define AL_ETH_FSM_DATA_OUTER_4_TUPLE 1 +#define AL_ETH_FSM_DATA_INNER_2_TUPLE 2 +#define AL_ETH_FSM_DATA_INNER_4_TUPLE 3 + +#define AL_ETH_FSM_DATA_HASH_SEL (1 << 2) + +#define AL_ETH_FSM_DATA_DEFAULT_Q 0 +#define AL_ETH_FSM_DATA_DEFAULT_UDMA 0 + +#define AL_BR_SIZE 512 +#define AL_TSO_SIZE 65500 +#define AL_DEFAULT_MTU 1500 + +#define CSUM_OFFLOAD (CSUM_IP|CSUM_TCP|CSUM_UDP|CSUM_SCTP) + +#define AL_IP_ALIGNMENT_OFFSET 2 + +#define SFP_I2C_ADDR 0x50 + +#define AL_MASK_GROUP_A_INT 0x7 +#define AL_MASK_GROUP_B_INT 0xF +#define AL_MASK_GROUP_C_INT 0xF +#define AL_MASK_GROUP_D_INT 0xFFFFFFFF + +#define AL_REG_OFFSET_FORWARD_INTR (0x1800000 + 0x1210) +#define AL_EN_FORWARD_INTR 0x1FFFF +#define AL_DIS_FORWARD_INTR 0 + +#define AL_M2S_MASK_INIT 0x480 +#define AL_S2M_MASK_INIT 0x1E0 +#define AL_M2S_S2M_MASK_NOT_INT (0x3f << 25) + +#define AL_10BASE_T_SPEED 10 +#define AL_100BASE_TX_SPEED 100 +#define AL_1000BASE_T_SPEED 1000 + +static devclass_t al_devclass; + +#define AL_RX_LOCK_INIT(_sc) mtx_init(&((_sc)->if_rx_lock), "ALRXL", "ALRXL", MTX_DEF) +#define AL_RX_LOCK(_sc) mtx_lock(&((_sc)->if_rx_lock)) +#define AL_RX_UNLOCK(_sc) mtx_unlock(&((_sc)->if_rx_lock)) + +/* helper functions */ +static int al_is_device_supported(device_t); + +static void al_eth_init_rings(struct al_eth_adapter *); +static void al_eth_flow_ctrl_disable(struct al_eth_adapter *); +int al_eth_fpga_read_pci_config(void *, int, uint32_t *); +int al_eth_fpga_write_pci_config(void *, int, uint32_t); +int al_eth_read_pci_config(void *, int, uint32_t *); +int al_eth_write_pci_config(void *, int, uint32_t); +void al_eth_irq_config(uint32_t *, uint32_t); +void al_eth_forward_int_config(uint32_t *, uint32_t); +static void al_eth_start_xmit(void *, int); +static void al_eth_rx_recv_work(void *, int); +static int al_eth_up(struct al_eth_adapter *); +static void al_eth_down(struct al_eth_adapter *); +static void al_eth_interrupts_unmask(struct al_eth_adapter *); +static void al_eth_interrupts_mask(struct al_eth_adapter *); +static int al_eth_check_mtu(struct al_eth_adapter *, int); +static uint64_t al_get_counter(struct ifnet *, ift_counter); +static void al_eth_req_rx_buff_size(struct al_eth_adapter *, int); +static int al_eth_board_params_init(struct al_eth_adapter *); +static int al_media_update(struct ifnet *); +static void al_media_status(struct ifnet *, struct ifmediareq *); +static int al_eth_function_reset(struct al_eth_adapter *); +static int al_eth_hw_init_adapter(struct al_eth_adapter *); +static void al_eth_serdes_init(struct al_eth_adapter *); +static void al_eth_lm_config(struct al_eth_adapter *); +static int al_eth_hw_init(struct al_eth_adapter *); + +static void al_tick_stats(void *); + +/* ifnet entry points */ +static void al_init(void *); +static int al_mq_start(struct ifnet *, struct mbuf *); +static void al_qflush(struct ifnet *); +static int al_ioctl(struct ifnet * ifp, u_long, caddr_t); + +/* bus entry points */ +static int al_probe(device_t); +static int al_attach(device_t); +static int al_detach(device_t); +static int al_shutdown(device_t); + +/* mii bus support routines */ +static int al_miibus_readreg(device_t, int, int); +static int al_miibus_writereg(device_t, int, int, int); +static void al_miibus_statchg(device_t); +static void al_miibus_linkchg(device_t); + +struct al_eth_adapter* g_adapters[16]; +uint32_t g_adapters_count; + +/* flag for napi-like mbuf processing, controlled from sysctl */ +static int napi = 0; + +static device_method_t al_methods[] = { + /* Device interface */ + DEVMETHOD(device_probe, al_probe), + DEVMETHOD(device_attach, al_attach), + DEVMETHOD(device_detach, al_detach), + DEVMETHOD(device_shutdown, al_shutdown), + + DEVMETHOD(miibus_readreg, al_miibus_readreg), + DEVMETHOD(miibus_writereg, al_miibus_writereg), + DEVMETHOD(miibus_statchg, al_miibus_statchg), + DEVMETHOD(miibus_linkchg, al_miibus_linkchg), + { 0, 0 } +}; + +static driver_t al_driver = { + "al", + al_methods, + sizeof(struct al_eth_adapter), +}; + +DRIVER_MODULE(al, pci, al_driver, al_devclass, 0, 0); +DRIVER_MODULE(miibus, al, miibus_driver, miibus_devclass, 0, 0); + +static int +al_probe(device_t dev) +{ + if ((al_is_device_supported(dev)) != 0) { + device_set_desc(dev, "al"); + return (BUS_PROBE_DEFAULT); + } + return (ENXIO); +} + +static int +al_attach(device_t dev) +{ + struct al_eth_lm_context *lm_context; + struct al_eth_adapter *adapter; + struct sysctl_oid_list *child; + struct sysctl_ctx_list *ctx; + struct sysctl_oid *tree; + struct ifnet *ifp; + uint32_t dev_id; + uint32_t rev_id; + int bar_udma; + int bar_mac; + int bar_ec; + int err; + + err = 0; + ifp = NULL; + dev_id = rev_id = 0; + ctx = device_get_sysctl_ctx(dev); + tree = SYSCTL_PARENT(device_get_sysctl_tree(dev)); + child = SYSCTL_CHILDREN(tree); + + if (g_adapters_count == 0) { + SYSCTL_ADD_INT(ctx, child, OID_AUTO, "napi", + CTLFLAG_RW, &napi, 0, "Use pseudo-napi mechanism"); + } + adapter = device_get_softc(dev); + adapter->dev = dev; + adapter->board_type = ALPINE_INTEGRATED; + snprintf(adapter->name, AL_ETH_NAME_MAX_LEN, "%s", + device_get_nameunit(dev)); + AL_RX_LOCK_INIT(adapter); + + g_adapters[g_adapters_count] = adapter; + + lm_context = &adapter->lm_context; + + bar_udma = PCIR_BAR(AL_ETH_UDMA_BAR); + adapter->udma_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, + &bar_udma, RF_ACTIVE); + if (adapter->udma_res == NULL) { + device_printf(adapter->dev, + "could not allocate memory resources for DMA.\n"); + err = ENOMEM; + goto err_res_dma; + } + adapter->udma_base = al_bus_dma_to_va(rman_get_bustag(adapter->udma_res), + rman_get_bushandle(adapter->udma_res)); + bar_mac = PCIR_BAR(AL_ETH_MAC_BAR); + adapter->mac_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, + &bar_mac, RF_ACTIVE); + if (adapter->mac_res == NULL) { + device_printf(adapter->dev, + "could not allocate memory resources for MAC.\n"); + err = ENOMEM; + goto err_res_mac; + } + adapter->mac_base = al_bus_dma_to_va(rman_get_bustag(adapter->mac_res), + rman_get_bushandle(adapter->mac_res)); + + bar_ec = PCIR_BAR(AL_ETH_EC_BAR); + adapter->ec_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &bar_ec, + RF_ACTIVE); + if (adapter->ec_res == NULL) { + device_printf(adapter->dev, + "could not allocate memory resources for EC.\n"); + err = ENOMEM; + goto err_res_ec; + } + adapter->ec_base = al_bus_dma_to_va(rman_get_bustag(adapter->ec_res), + rman_get_bushandle(adapter->ec_res)); + + adapter->netdev = ifp = if_alloc(IFT_ETHER); + + adapter->netdev->if_link_state = LINK_STATE_DOWN; + + ifp->if_softc = adapter; + if_initname(ifp, device_get_name(dev), device_get_unit(dev)); + ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; + ifp->if_flags = ifp->if_drv_flags; + ifp->if_flags |= IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST | IFF_ALLMULTI; + ifp->if_transmit = al_mq_start; + ifp->if_qflush = al_qflush; + ifp->if_ioctl = al_ioctl; + ifp->if_init = al_init; + ifp->if_get_counter = al_get_counter; + ifp->if_mtu = AL_DEFAULT_MTU; + + adapter->if_flags = ifp->if_flags; + + ifp->if_capabilities = ifp->if_capenable = 0; + + ifp->if_capabilities |= IFCAP_HWCSUM | + IFCAP_HWCSUM_IPV6 | IFCAP_TSO | + IFCAP_LRO | IFCAP_JUMBO_MTU; + + ifp->if_capenable = ifp->if_capabilities; + + adapter->id_number = g_adapters_count; + + if (adapter->board_type == ALPINE_INTEGRATED) { + dev_id = pci_get_device(adapter->dev); + rev_id = pci_get_revid(adapter->dev); + } else { + al_eth_fpga_read_pci_config(adapter->internal_pcie_base, + PCIR_DEVICE, &dev_id); + al_eth_fpga_read_pci_config(adapter->internal_pcie_base, + PCIR_REVID, &rev_id); + } + + adapter->dev_id = dev_id; + adapter->rev_id = rev_id; + + /* set default ring sizes */ + adapter->tx_ring_count = AL_ETH_DEFAULT_TX_SW_DESCS; + adapter->tx_descs_count = AL_ETH_DEFAULT_TX_HW_DESCS; + adapter->rx_ring_count = AL_ETH_DEFAULT_RX_DESCS; + adapter->rx_descs_count = AL_ETH_DEFAULT_RX_DESCS; + + adapter->num_tx_queues = AL_ETH_NUM_QUEUES; + adapter->num_rx_queues = AL_ETH_NUM_QUEUES; + + adapter->small_copy_len = AL_ETH_DEFAULT_SMALL_PACKET_LEN; + adapter->link_poll_interval = AL_ETH_DEFAULT_LINK_POLL_INTERVAL; + adapter->max_rx_buff_alloc_size = AL_ETH_DEFAULT_MAX_RX_BUFF_ALLOC_SIZE; + + al_eth_req_rx_buff_size(adapter, adapter->netdev->if_mtu); + + adapter->link_config.force_1000_base_x = AL_ETH_DEFAULT_FORCE_1000_BASEX; + + err = al_eth_board_params_init(adapter); + if (err != 0) + goto err; + + if (adapter->mac_mode == AL_ETH_MAC_MODE_10GbE_Serial) { + ifmedia_init(&adapter->media, IFM_IMASK, + al_media_update, al_media_status); + ifmedia_add(&adapter->media, IFM_ETHER | IFM_1000_LX, 0, NULL); + ifmedia_add(&adapter->media, IFM_ETHER | IFM_10G_LR, 0, NULL); + ifmedia_add(&adapter->media, IFM_ETHER | IFM_AUTO, 0, NULL); + ifmedia_set(&adapter->media, IFM_ETHER | IFM_AUTO); + } + + al_eth_function_reset(adapter); + + err = al_eth_hw_init_adapter(adapter); + if (err != 0) + goto err; + + al_eth_init_rings(adapter); + g_adapters_count++; + + al_eth_lm_config(adapter); + mtx_init(&adapter->stats_mtx, "AlStatsMtx", NULL, MTX_DEF); + mtx_init(&adapter->wd_mtx, "AlWdMtx", NULL, MTX_DEF); + callout_init_mtx(&adapter->stats_callout, &adapter->stats_mtx, 0); + callout_init_mtx(&adapter->wd_callout, &adapter->wd_mtx, 0); + + ether_ifattach(ifp, adapter->mac_addr); + ifp->if_mtu = AL_DEFAULT_MTU; + + if (adapter->mac_mode == AL_ETH_MAC_MODE_RGMII) { + al_eth_hw_init(adapter); + + /* Attach PHY(s) */ + err = mii_attach(adapter->dev, &adapter->miibus, adapter->netdev, + al_media_update, al_media_status, BMSR_DEFCAPMASK, 0, + MII_OFFSET_ANY, 0); + if (err != 0) { + device_printf(adapter->dev, "attaching PHYs failed\n"); + return (err); + } + + adapter->mii = device_get_softc(adapter->miibus); + } + + return (err); + +err: + bus_release_resource(dev, SYS_RES_MEMORY, bar_ec, adapter->ec_res); +err_res_ec: + bus_release_resource(dev, SYS_RES_MEMORY, bar_mac, adapter->mac_res); +err_res_mac: + bus_release_resource(dev, SYS_RES_MEMORY, bar_udma, adapter->udma_res); +err_res_dma: + return (err); +} + +static int +al_detach(device_t dev) +{ + struct al_eth_adapter *adapter; + + adapter = device_get_softc(dev); + ether_ifdetach(adapter->netdev); + + mtx_destroy(&adapter->stats_mtx); + mtx_destroy(&adapter->wd_mtx); + + al_eth_down(adapter); + + bus_release_resource(dev, SYS_RES_IRQ, 0, adapter->irq_res); + bus_release_resource(dev, SYS_RES_MEMORY, 0, adapter->ec_res); + bus_release_resource(dev, SYS_RES_MEMORY, 0, adapter->mac_res); + bus_release_resource(dev, SYS_RES_MEMORY, 0, adapter->udma_res); + + return (0); +} + +int +al_eth_fpga_read_pci_config(void *handle, int where, uint32_t *val) +{ + + /* handle is the base address of the adapter */ + *val = al_reg_read32((void*)((u_long)handle + where)); + + return (0); +} + +int +al_eth_fpga_write_pci_config(void *handle, int where, uint32_t val) +{ + + /* handle is the base address of the adapter */ + al_reg_write32((void*)((u_long)handle + where), val); + return (0); +} + +int +al_eth_read_pci_config(void *handle, int where, uint32_t *val) +{ + + /* handle is a pci_dev */ + *val = pci_read_config((device_t)handle, where, sizeof(*val)); + return (0); +} + +int +al_eth_write_pci_config(void *handle, int where, uint32_t val) +{ + + /* handle is a pci_dev */ + pci_write_config((device_t)handle, where, val, sizeof(val)); + return (0); +} + +void +al_eth_irq_config(uint32_t *offset, uint32_t value) +{ + + al_reg_write32_relaxed(offset, value); +} + +void +al_eth_forward_int_config(uint32_t *offset, uint32_t value) +{ + + al_reg_write32(offset, value); +} + +static void +al_eth_serdes_init(struct al_eth_adapter *adapter) +{ + void __iomem *serdes_base; + + adapter->serdes_init = false; + + serdes_base = alpine_serdes_resource_get(adapter->serdes_grp); + if (serdes_base == NULL) { + device_printf(adapter->dev, "serdes_base get failed!\n"); + return; + } + + serdes_base = al_bus_dma_to_va(serdes_tag, serdes_base); + + al_serdes_handle_grp_init(serdes_base, adapter->serdes_grp, + &adapter->serdes_obj); + + adapter->serdes_init = true; +} + +static void +al_dma_map_addr(void *arg, bus_dma_segment_t *segs, int nseg, int error) +{ + bus_addr_t *paddr; + + paddr = arg; + *paddr = segs->ds_addr; +} + +static int +al_dma_alloc_coherent(struct device *dev, bus_dma_tag_t *tag, bus_dmamap_t *map, + bus_addr_t *baddr, void **vaddr, uint32_t size) +{ + int ret; + uint32_t maxsize = ((size - 1)/PAGE_SIZE + 1) * PAGE_SIZE; + + ret = bus_dma_tag_create(bus_get_dma_tag(dev), 8, 0, + BUS_SPACE_MAXADDR, BUS_SPACE_MAXADDR, NULL, NULL, + maxsize, 1, maxsize, BUS_DMA_COHERENT, NULL, NULL, tag); + if (ret != 0) { + device_printf(dev, + "failed to create bus tag, ret = %d\n", ret); + return (ret); + } + + ret = bus_dmamem_alloc(*tag, vaddr, + BUS_DMA_COHERENT | BUS_DMA_ZERO, map); + if (ret != 0) { + device_printf(dev, + "failed to allocate dmamem, ret = %d\n", ret); + return (ret); + } + + ret = bus_dmamap_load(*tag, *map, *vaddr, + size, al_dma_map_addr, baddr, 0); + if (ret != 0) { + device_printf(dev, + "failed to allocate bus_dmamap_load, ret = %d\n", ret); + return (ret); + } + + return (0); +} + +static void +al_dma_free_coherent(bus_dma_tag_t tag, bus_dmamap_t map, void *vaddr) +{ + + bus_dmamap_unload(tag, map); + bus_dmamem_free(tag, vaddr, map); + bus_dma_tag_destroy(tag); +} + +static void +al_eth_mac_table_unicast_add(struct al_eth_adapter *adapter, + uint8_t idx, uint8_t *addr, uint8_t udma_mask) +{ + struct al_eth_fwd_mac_table_entry entry = { { 0 } }; + + memcpy(entry.addr, adapter->mac_addr, sizeof(adapter->mac_addr)); + + memset(entry.mask, 0xff, sizeof(entry.mask)); + entry.rx_valid = true; + entry.tx_valid = false; + entry.udma_mask = udma_mask; + entry.filter = false; + + device_printf_dbg(adapter->dev, + "%s: [%d]: addr "MAC_ADDR_STR" mask "MAC_ADDR_STR"\n", + __func__, idx, MAC_ADDR(entry.addr), MAC_ADDR(entry.mask)); + + al_eth_fwd_mac_table_set(&adapter->hal_adapter, idx, &entry); +} + +static void +al_eth_mac_table_all_multicast_add(struct al_eth_adapter *adapter, uint8_t idx, + uint8_t udma_mask) +{ + struct al_eth_fwd_mac_table_entry entry = { { 0 } }; + + memset(entry.addr, 0x00, sizeof(entry.addr)); + memset(entry.mask, 0x00, sizeof(entry.mask)); + entry.mask[0] |= 1; + entry.addr[0] |= 1; + + entry.rx_valid = true; + entry.tx_valid = false; + entry.udma_mask = udma_mask; + entry.filter = false; + + device_printf_dbg(adapter->dev, + "%s: [%d]: addr "MAC_ADDR_STR" mask "MAC_ADDR_STR"\n", + __func__, idx, MAC_ADDR(entry.addr), MAC_ADDR(entry.mask)); + + al_eth_fwd_mac_table_set(&adapter->hal_adapter, idx, &entry); +} + +static void +al_eth_mac_table_broadcast_add(struct al_eth_adapter *adapter, + uint8_t idx, uint8_t udma_mask) +{ + struct al_eth_fwd_mac_table_entry entry = { { 0 } }; + + memset(entry.addr, 0xff, sizeof(entry.addr)); + memset(entry.mask, 0xff, sizeof(entry.mask)); + + entry.rx_valid = true; + entry.tx_valid = false; + entry.udma_mask = udma_mask; + entry.filter = false; + + device_printf_dbg(adapter->dev, + "%s: [%d]: addr "MAC_ADDR_STR" mask "MAC_ADDR_STR"\n", + __func__, idx, MAC_ADDR(entry.addr), MAC_ADDR(entry.mask)); + + al_eth_fwd_mac_table_set(&adapter->hal_adapter, idx, &entry); +} + +static void +al_eth_mac_table_promiscuous_set(struct al_eth_adapter *adapter, + boolean_t promiscuous) +{ + struct al_eth_fwd_mac_table_entry entry = { { 0 } }; + + memset(entry.addr, 0x00, sizeof(entry.addr)); + memset(entry.mask, 0x00, sizeof(entry.mask)); + + entry.rx_valid = true; + entry.tx_valid = false; + entry.udma_mask = (promiscuous) ? 1 : 0; + entry.filter = (promiscuous) ? false : true; + + device_printf_dbg(adapter->dev, "%s: %s promiscuous mode\n", + __func__, (promiscuous) ? "enter" : "exit"); + + al_eth_fwd_mac_table_set(&adapter->hal_adapter, + AL_ETH_MAC_TABLE_DROP_IDX, &entry); +} + +static void +al_eth_set_thash_table_entry(struct al_eth_adapter *adapter, uint8_t idx, + uint8_t udma, uint32_t queue) +{ + + if (udma != 0) + panic("only UDMA0 is supporter"); + + if (queue >= AL_ETH_NUM_QUEUES) + panic("invalid queue number"); + + al_eth_thash_table_set(&adapter->hal_adapter, idx, udma, queue); +} + +/* init FSM, no tunneling supported yet, if packet is tcp/udp over ipv4/ipv6, use 4 tuple hash */ +static void +al_eth_fsm_table_init(struct al_eth_adapter *adapter) +{ + uint32_t val; + int i; + + for (i = 0; i < AL_ETH_RX_FSM_TABLE_SIZE; i++) { + uint8_t outer_type = AL_ETH_FSM_ENTRY_OUTER(i); + switch (outer_type) { + case AL_ETH_FSM_ENTRY_IPV4_TCP: + case AL_ETH_FSM_ENTRY_IPV4_UDP: + case AL_ETH_FSM_ENTRY_IPV6_TCP: + case AL_ETH_FSM_ENTRY_IPV6_UDP: + val = AL_ETH_FSM_DATA_OUTER_4_TUPLE | + AL_ETH_FSM_DATA_HASH_SEL; + break; + case AL_ETH_FSM_ENTRY_IPV6_NO_UDP_TCP: + case AL_ETH_FSM_ENTRY_IPV4_NO_UDP_TCP: + val = AL_ETH_FSM_DATA_OUTER_2_TUPLE | + AL_ETH_FSM_DATA_HASH_SEL; + break; + default: + val = AL_ETH_FSM_DATA_DEFAULT_Q | + AL_ETH_FSM_DATA_DEFAULT_UDMA; + } + al_eth_fsm_table_set(&adapter->hal_adapter, i, val); + } +} + +static void +al_eth_mac_table_entry_clear(struct al_eth_adapter *adapter, + uint8_t idx) +{ + struct al_eth_fwd_mac_table_entry entry = { { 0 } }; + + device_printf_dbg(adapter->dev, "%s: clear entry %d\n", __func__, idx); + + al_eth_fwd_mac_table_set(&adapter->hal_adapter, idx, &entry); +} + +static int +al_eth_hw_init_adapter(struct al_eth_adapter *adapter) +{ + struct al_eth_adapter_params *params = &adapter->eth_hal_params; + int rc; + + /* params->dev_id = adapter->dev_id; */ + params->rev_id = adapter->rev_id; + params->udma_id = 0; + params->enable_rx_parser = 1; /* enable rx epe parser*/ + params->udma_regs_base = adapter->udma_base; /* UDMA register base address */ + params->ec_regs_base = adapter->ec_base; /* Ethernet controller registers base address */ + params->mac_regs_base = adapter->mac_base; /* Ethernet MAC registers base address */ + params->name = adapter->name; + params->serdes_lane = adapter->serdes_lane; + + rc = al_eth_adapter_init(&adapter->hal_adapter, params); + if (rc != 0) + device_printf(adapter->dev, "%s failed at hal init!\n", + __func__); + + if ((adapter->board_type == ALPINE_NIC) || + (adapter->board_type == ALPINE_FPGA_NIC)) { + /* in pcie NIC mode, force eth UDMA to access PCIE0 using the vmid */ + struct al_udma_gen_tgtid_conf conf; + int i; + for (i = 0; i < DMA_MAX_Q; i++) { + conf.tx_q_conf[i].queue_en = AL_TRUE; + conf.tx_q_conf[i].desc_en = AL_FALSE; + conf.tx_q_conf[i].tgtid = 0x100; /* for access from PCIE0 */ + conf.rx_q_conf[i].queue_en = AL_TRUE; + conf.rx_q_conf[i].desc_en = AL_FALSE; + conf.rx_q_conf[i].tgtid = 0x100; /* for access from PCIE0 */ + } + al_udma_gen_tgtid_conf_set(adapter->udma_base, &conf); + } + + return (rc); +} + +static void +al_eth_lm_config(struct al_eth_adapter *adapter) +{ + struct al_eth_lm_init_params params = {0}; + + params.adapter = &adapter->hal_adapter; + params.serdes_obj = &adapter->serdes_obj; + params.lane = adapter->serdes_lane; + params.sfp_detection = adapter->sfp_detection_needed; + if (adapter->sfp_detection_needed == true) { + params.sfp_bus_id = adapter->i2c_adapter_id; + params.sfp_i2c_addr = SFP_I2C_ADDR; + } + + if (adapter->sfp_detection_needed == false) { + switch (adapter->mac_mode) { + case AL_ETH_MAC_MODE_10GbE_Serial: + if ((adapter->lt_en != 0) && (adapter->an_en != 0)) + params.default_mode = AL_ETH_LM_MODE_10G_DA; + else + params.default_mode = AL_ETH_LM_MODE_10G_OPTIC; + break; + case AL_ETH_MAC_MODE_SGMII: + params.default_mode = AL_ETH_LM_MODE_1G; + break; + default: + params.default_mode = AL_ETH_LM_MODE_10G_DA; + } + } else + params.default_mode = AL_ETH_LM_MODE_10G_DA; + + params.link_training = adapter->lt_en; + params.rx_equal = true; + params.static_values = !adapter->dont_override_serdes; + params.i2c_context = adapter; + params.kr_fec_enable = false; + + params.retimer_exist = adapter->retimer.exist; + params.retimer_bus_id = adapter->retimer.bus_id; + params.retimer_i2c_addr = adapter->retimer.i2c_addr; + params.retimer_channel = adapter->retimer.channel; + + al_eth_lm_init(&adapter->lm_context, ¶ms); +} + +static int +al_eth_board_params_init(struct al_eth_adapter *adapter) +{ + + if (adapter->board_type == ALPINE_NIC) { + adapter->mac_mode = AL_ETH_MAC_MODE_10GbE_Serial; + adapter->sfp_detection_needed = false; + adapter->phy_exist = false; + adapter->an_en = false; + adapter->lt_en = false; + adapter->ref_clk_freq = AL_ETH_REF_FREQ_375_MHZ; + adapter->mdio_freq = AL_ETH_DEFAULT_MDIO_FREQ_KHZ; + } else if (adapter->board_type == ALPINE_FPGA_NIC) { + adapter->mac_mode = AL_ETH_MAC_MODE_SGMII; + adapter->sfp_detection_needed = false; + adapter->phy_exist = false; + adapter->an_en = false; + adapter->lt_en = false; + adapter->ref_clk_freq = AL_ETH_REF_FREQ_375_MHZ; + adapter->mdio_freq = AL_ETH_DEFAULT_MDIO_FREQ_KHZ; + } else { + struct al_eth_board_params params; + int rc; + + adapter->auto_speed = false; + + rc = al_eth_board_params_get(adapter->mac_base, ¶ms); + if (rc != 0) { + device_printf(adapter->dev, + "board info not available\n"); + return (-1); + } + + adapter->phy_exist = params.phy_exist == TRUE; + adapter->phy_addr = params.phy_mdio_addr; + adapter->an_en = params.autoneg_enable; + adapter->lt_en = params.kr_lt_enable; + adapter->serdes_grp = params.serdes_grp; + adapter->serdes_lane = params.serdes_lane; + adapter->sfp_detection_needed = params.sfp_plus_module_exist; + adapter->i2c_adapter_id = params.i2c_adapter_id; + adapter->ref_clk_freq = params.ref_clk_freq; + adapter->dont_override_serdes = params.dont_override_serdes; + adapter->link_config.active_duplex = !params.half_duplex; + adapter->link_config.autoneg = !params.an_disable; + adapter->link_config.force_1000_base_x = params.force_1000_base_x; + adapter->retimer.exist = params.retimer_exist; + adapter->retimer.bus_id = params.retimer_bus_id; + adapter->retimer.i2c_addr = params.retimer_i2c_addr; + adapter->retimer.channel = params.retimer_channel; + + switch (params.speed) { + default: + device_printf(adapter->dev, + "%s: invalid speed (%d)\n", __func__, params.speed); + case AL_ETH_BOARD_1G_SPEED_1000M: + adapter->link_config.active_speed = 1000; + break; + case AL_ETH_BOARD_1G_SPEED_100M: + adapter->link_config.active_speed = 100; + break; + case AL_ETH_BOARD_1G_SPEED_10M: + adapter->link_config.active_speed = 10; + break; + } + + switch (params.mdio_freq) { + default: + device_printf(adapter->dev, + "%s: invalid mdio freq (%d)\n", __func__, + params.mdio_freq); + case AL_ETH_BOARD_MDIO_FREQ_2_5_MHZ: + adapter->mdio_freq = AL_ETH_DEFAULT_MDIO_FREQ_KHZ; + break; + case AL_ETH_BOARD_MDIO_FREQ_1_MHZ: + adapter->mdio_freq = AL_ETH_MDIO_FREQ_1000_KHZ; + break; *** DIFF OUTPUT TRUNCATED AT 1000 LINES ***
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201610201131.u9KBVBDk070088>