svn commit: r307670 - in head/sys: arm/conf arm64/conf conf dev/al_eth
Wojciech Macek
wma at FreeBSD.org
Thu Oct 20 11:31:12 UTC 2016
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 at 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 ***
More information about the svn-src-all
mailing list