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 <m...@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, &params);
+}
+
+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, &params);
+               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 ***
_______________________________________________
svn-src-all@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to