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, &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 ***


More information about the svn-src-head mailing list