diff options
Diffstat (limited to 'sys/dev/aq/aq_main.c')
| -rw-r--r-- | sys/dev/aq/aq_main.c | 1329 |
1 files changed, 1329 insertions, 0 deletions
diff --git a/sys/dev/aq/aq_main.c b/sys/dev/aq/aq_main.c new file mode 100644 index 000000000000..48f8305fcd15 --- /dev/null +++ b/sys/dev/aq/aq_main.c @@ -0,0 +1,1329 @@ +/* + * aQuantia Corporation Network Driver + * Copyright (C) 2019 aQuantia Corporation. All rights reserved + * + * 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. + * + * (3)The name of the author may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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/malloc.h> +#include <sys/socket.h> +#include <sys/kernel.h> +#include <sys/bus.h> +#include <sys/module.h> +#include <sys/rman.h> +#include <sys/endian.h> +#include <sys/sockio.h> +#include <sys/priv.h> +#include <sys/sysctl.h> +#include <sys/sbuf.h> +#include <sys/bitstring.h> + +#include <machine/bus.h> +#include <machine/resource.h> + +#include <dev/pci/pcireg.h> +#include <dev/pci/pcivar.h> + +#include <net/if.h> +#include <net/if_media.h> +#include <net/if_var.h> +#include <net/if_dl.h> +#include <net/ethernet.h> +#include <net/iflib.h> +#include <net/rss_config.h> + +#include "opt_inet.h" +#include "opt_inet6.h" +#include "opt_rss.h" + +#include "ifdi_if.h" + +#include "aq_device.h" +#include "aq_fw.h" +#include "aq_hw.h" +#include "aq_hw_llh.h" +#include "aq_ring.h" +#include "aq_dbg.h" + + +#define AQ_XXX_UNIMPLEMENTED_FUNCTION do { \ + printf("atlantic: unimplemented function: %s@%s:%d\n", __func__, \ + __FILE__, __LINE__); \ +} while (0) + +MALLOC_DEFINE(M_AQ, "aq", "Aquantia"); + +char aq_driver_version[] = AQ_VER; + +#define AQUANTIA_VENDOR_ID 0x1D6A + +#define AQ_DEVICE_ID_0001 0x0001 +#define AQ_DEVICE_ID_D100 0xD100 +#define AQ_DEVICE_ID_D107 0xD107 +#define AQ_DEVICE_ID_D108 0xD108 +#define AQ_DEVICE_ID_D109 0xD109 + +#define AQ_DEVICE_ID_AQC100 0x00B1 +#define AQ_DEVICE_ID_AQC107 0x07B1 +#define AQ_DEVICE_ID_AQC108 0x08B1 +#define AQ_DEVICE_ID_AQC109 0x09B1 +#define AQ_DEVICE_ID_AQC111 0x11B1 +#define AQ_DEVICE_ID_AQC112 0x12B1 + +#define AQ_DEVICE_ID_AQC100S 0x80B1 +#define AQ_DEVICE_ID_AQC107S 0x87B1 +#define AQ_DEVICE_ID_AQC108S 0x88B1 +#define AQ_DEVICE_ID_AQC109S 0x89B1 +#define AQ_DEVICE_ID_AQC111S 0x91B1 +#define AQ_DEVICE_ID_AQC112S 0x92B1 + +static pci_vendor_info_t aq_vendor_info_array[] = { + PVID(AQUANTIA_VENDOR_ID, AQ_DEVICE_ID_0001, "Aquantia AQtion 10Gbit Network Adapter"), + PVID(AQUANTIA_VENDOR_ID, AQ_DEVICE_ID_D107, "Aquantia AQtion 10Gbit Network Adapter"), + PVID(AQUANTIA_VENDOR_ID, AQ_DEVICE_ID_D108, "Aquantia AQtion 5Gbit Network Adapter"), + PVID(AQUANTIA_VENDOR_ID, AQ_DEVICE_ID_D109, "Aquantia AQtion 2.5Gbit Network Adapter"), + + PVID(AQUANTIA_VENDOR_ID, AQ_DEVICE_ID_AQC107, "Aquantia AQtion 10Gbit Network Adapter"), + PVID(AQUANTIA_VENDOR_ID, AQ_DEVICE_ID_AQC108, "Aquantia AQtion 5Gbit Network Adapter"), + PVID(AQUANTIA_VENDOR_ID, AQ_DEVICE_ID_AQC109, "Aquantia AQtion 2.5Gbit Network Adapter"), + PVID(AQUANTIA_VENDOR_ID, AQ_DEVICE_ID_AQC100, "Aquantia AQtion 10Gbit Network Adapter"), + + PVID(AQUANTIA_VENDOR_ID, AQ_DEVICE_ID_AQC107S, "Aquantia AQtion 10Gbit Network Adapter"), + PVID(AQUANTIA_VENDOR_ID, AQ_DEVICE_ID_AQC108S, "Aquantia AQtion 5Gbit Network Adapter"), + PVID(AQUANTIA_VENDOR_ID, AQ_DEVICE_ID_AQC109S, "Aquantia AQtion 2.5Gbit Network Adapter"), + PVID(AQUANTIA_VENDOR_ID, AQ_DEVICE_ID_AQC100S, "Aquantia AQtion 10Gbit Network Adapter"), + + PVID(AQUANTIA_VENDOR_ID, AQ_DEVICE_ID_AQC111, "Aquantia AQtion 5Gbit Network Adapter"), + PVID(AQUANTIA_VENDOR_ID, AQ_DEVICE_ID_AQC112, "Aquantia AQtion 2.5Gbit Network Adapter"), + PVID(AQUANTIA_VENDOR_ID, AQ_DEVICE_ID_AQC111S, "Aquantia AQtion 5Gbit Network Adapter"), + PVID(AQUANTIA_VENDOR_ID, AQ_DEVICE_ID_AQC112S, "Aquantia AQtion 2.5Gbit Network Adapter"), + + PVID_END +}; + + +/* Device setup, teardown, etc */ +static void *aq_register(device_t dev); +static int aq_if_attach_pre(if_ctx_t ctx); +static int aq_if_attach_post(if_ctx_t ctx); +static int aq_if_detach(if_ctx_t ctx); +static int aq_if_shutdown(if_ctx_t ctx); +static int aq_if_suspend(if_ctx_t ctx); +static int aq_if_resume(if_ctx_t ctx); + +/* Soft queue setup and teardown */ +static int aq_if_tx_queues_alloc(if_ctx_t ctx, caddr_t *vaddrs, + uint64_t *paddrs, int ntxqs, int ntxqsets); +static int aq_if_rx_queues_alloc(if_ctx_t ctx, caddr_t *vaddrs, + uint64_t *paddrs, int nrxqs, int nrxqsets); +static void aq_if_queues_free(if_ctx_t ctx); + +/* Device configuration */ +static void aq_if_init(if_ctx_t ctx); +static void aq_if_stop(if_ctx_t ctx); +static void aq_if_multi_set(if_ctx_t ctx); +static int aq_if_mtu_set(if_ctx_t ctx, uint32_t mtu); +static void aq_if_media_status(if_ctx_t ctx, struct ifmediareq *ifmr); +static int aq_if_media_change(if_ctx_t ctx); +static int aq_if_promisc_set(if_ctx_t ctx, int flags); +static uint64_t aq_if_get_counter(if_ctx_t ctx, ift_counter cnt); +static void aq_if_timer(if_ctx_t ctx, uint16_t qid); +static int aq_hw_capabilities(struct aq_dev *softc); +static void aq_add_stats_sysctls(struct aq_dev *softc); + +/* Interrupt enable / disable */ +static void aq_if_enable_intr(if_ctx_t ctx); +static void aq_if_disable_intr(if_ctx_t ctx); +static int aq_if_rx_queue_intr_enable(if_ctx_t ctx, uint16_t rxqid); +static int aq_if_msix_intr_assign(if_ctx_t ctx, int msix); + +/* VLAN support */ +static bool aq_is_vlan_promisc_required(struct aq_dev *softc); +static void aq_update_vlan_filters(struct aq_dev *softc); +static void aq_if_vlan_register(if_ctx_t ctx, uint16_t vtag); +static void aq_if_vlan_unregister(if_ctx_t ctx, uint16_t vtag); + +/* Informational/diagnostic */ +static void aq_if_led_func(if_ctx_t ctx, int onoff); + +static device_method_t aq_methods[] = { + DEVMETHOD(device_register, aq_register), + DEVMETHOD(device_probe, iflib_device_probe), + DEVMETHOD(device_attach, iflib_device_attach), + DEVMETHOD(device_detach, iflib_device_detach), + DEVMETHOD(device_shutdown, iflib_device_shutdown), + DEVMETHOD(device_suspend, iflib_device_suspend), + DEVMETHOD(device_resume, iflib_device_resume), + + DEVMETHOD_END +}; + +static driver_t aq_driver = { + "aq", aq_methods, sizeof(struct aq_dev), +}; + +#if __FreeBSD_version >= 1400058 +DRIVER_MODULE(atlantic, pci, aq_driver, 0, 0); +#else +static devclass_t aq_devclass; +DRIVER_MODULE(atlantic, pci, aq_driver, aq_devclass, 0, 0); +#endif + +MODULE_DEPEND(atlantic, pci, 1, 1, 1); +MODULE_DEPEND(atlantic, ether, 1, 1, 1); +MODULE_DEPEND(atlantic, iflib, 1, 1, 1); + +IFLIB_PNP_INFO(pci, atlantic, aq_vendor_info_array); + +static device_method_t aq_if_methods[] = { + /* Device setup, teardown, etc */ + DEVMETHOD(ifdi_attach_pre, aq_if_attach_pre), + DEVMETHOD(ifdi_attach_post, aq_if_attach_post), + DEVMETHOD(ifdi_detach, aq_if_detach), + + DEVMETHOD(ifdi_shutdown, aq_if_shutdown), + DEVMETHOD(ifdi_suspend, aq_if_suspend), + DEVMETHOD(ifdi_resume, aq_if_resume), + + /* Soft queue setup and teardown */ + DEVMETHOD(ifdi_tx_queues_alloc, aq_if_tx_queues_alloc), + DEVMETHOD(ifdi_rx_queues_alloc, aq_if_rx_queues_alloc), + DEVMETHOD(ifdi_queues_free, aq_if_queues_free), + + /* Device configuration */ + DEVMETHOD(ifdi_init, aq_if_init), + DEVMETHOD(ifdi_stop, aq_if_stop), + DEVMETHOD(ifdi_multi_set, aq_if_multi_set), + DEVMETHOD(ifdi_mtu_set, aq_if_mtu_set), + DEVMETHOD(ifdi_media_status, aq_if_media_status), + DEVMETHOD(ifdi_media_change, aq_if_media_change), + DEVMETHOD(ifdi_promisc_set, aq_if_promisc_set), + DEVMETHOD(ifdi_get_counter, aq_if_get_counter), + DEVMETHOD(ifdi_update_admin_status, aq_if_update_admin_status), + DEVMETHOD(ifdi_timer, aq_if_timer), + + /* Interrupt enable / disable */ + DEVMETHOD(ifdi_intr_enable, aq_if_enable_intr), + DEVMETHOD(ifdi_intr_disable, aq_if_disable_intr), + DEVMETHOD(ifdi_rx_queue_intr_enable, aq_if_rx_queue_intr_enable), + DEVMETHOD(ifdi_tx_queue_intr_enable, aq_if_rx_queue_intr_enable), + DEVMETHOD(ifdi_msix_intr_assign, aq_if_msix_intr_assign), + + /* VLAN support */ + DEVMETHOD(ifdi_vlan_register, aq_if_vlan_register), + DEVMETHOD(ifdi_vlan_unregister, aq_if_vlan_unregister), + + /* Informational/diagnostic */ + DEVMETHOD(ifdi_led_func, aq_if_led_func), + + DEVMETHOD_END +}; + +static driver_t aq_if_driver = { + "aq_if", aq_if_methods, sizeof(struct aq_dev) +}; + +static struct if_shared_ctx aq_sctx_init = { + .isc_magic = IFLIB_MAGIC, + .isc_q_align = PAGE_SIZE, + .isc_tx_maxsize = HW_ATL_B0_TSO_SIZE, + .isc_tx_maxsegsize = HW_ATL_B0_MTU_JUMBO, +#if __FreeBSD__ >= 12 + .isc_tso_maxsize = HW_ATL_B0_TSO_SIZE, + .isc_tso_maxsegsize = HW_ATL_B0_MTU_JUMBO, +#endif + .isc_rx_maxsize = HW_ATL_B0_MTU_JUMBO, + .isc_rx_nsegments = 16, + .isc_rx_maxsegsize = PAGE_SIZE, + .isc_nfl = 1, + .isc_nrxqs = 1, + .isc_ntxqs = 1, + .isc_admin_intrcnt = 1, + .isc_vendor_info = aq_vendor_info_array, + .isc_driver_version = aq_driver_version, + .isc_driver = &aq_if_driver, + .isc_flags = IFLIB_NEED_SCRATCH | IFLIB_TSO_INIT_IP | + IFLIB_NEED_ZERO_CSUM, + + .isc_nrxd_min = {HW_ATL_B0_MIN_RXD}, + .isc_ntxd_min = {HW_ATL_B0_MIN_TXD}, + .isc_nrxd_max = {HW_ATL_B0_MAX_RXD}, + .isc_ntxd_max = {HW_ATL_B0_MAX_TXD}, + .isc_nrxd_default = {PAGE_SIZE / sizeof(aq_txc_desc_t) * 4}, + .isc_ntxd_default = {PAGE_SIZE / sizeof(aq_txc_desc_t) * 4}, +}; + +/* + * TUNEABLE PARAMETERS: + */ + +static SYSCTL_NODE(_hw, OID_AUTO, aq, CTLFLAG_RD, 0, "Atlantic driver parameters"); +/* UDP Receive-Side Scaling */ +static int aq_enable_rss_udp = 1; +SYSCTL_INT(_hw_aq, OID_AUTO, enable_rss_udp, CTLFLAG_RDTUN, &aq_enable_rss_udp, 0, + "Enable Receive-Side Scaling (RSS) for UDP"); + + +/* + * Device Methods + */ +static void *aq_register(device_t dev) +{ + return (&aq_sctx_init); +} + +static int aq_if_attach_pre(if_ctx_t ctx) +{ + struct aq_dev *softc; + struct aq_hw *hw; + if_softc_ctx_t scctx; + int rc; + + AQ_DBG_ENTER(); + softc = iflib_get_softc(ctx); + rc = 0; + + softc->ctx = ctx; + softc->dev = iflib_get_dev(ctx); + softc->media = iflib_get_media(ctx); + softc->scctx = iflib_get_softc_ctx(ctx); + softc->sctx = iflib_get_sctx(ctx); + scctx = softc->scctx; + + softc->mmio_rid = PCIR_BAR(0); + softc->mmio_res = bus_alloc_resource_any(softc->dev, SYS_RES_MEMORY, + &softc->mmio_rid, RF_ACTIVE|RF_SHAREABLE); + if (softc->mmio_res == NULL) { + device_printf(softc->dev, + "failed to allocate MMIO resources\n"); + rc = ENXIO; + goto fail; + } + + softc->mmio_tag = rman_get_bustag(softc->mmio_res); + softc->mmio_handle = rman_get_bushandle(softc->mmio_res); + softc->mmio_size = rman_get_size(softc->mmio_res); + softc->hw.hw_addr = (u8*) softc->mmio_handle; + hw = &softc->hw; + hw->link_rate = aq_fw_speed_auto; + hw->itr = -1; + hw->fc.fc_rx = 1; + hw->fc.fc_tx = 1; + softc->linkup = 0U; + + /* Look up ops and caps. */ + rc = aq_hw_mpi_create(hw); + if (rc < 0) { + AQ_DBG_ERROR(" %s: aq_hw_mpi_create fail err=%d", __func__, rc); + goto fail; + } + + if (hw->fast_start_enabled) { + if (hw->fw_ops && hw->fw_ops->reset) + hw->fw_ops->reset(hw); + } else + aq_hw_reset(&softc->hw); + aq_hw_capabilities(softc); + + if (aq_hw_get_mac_permanent(hw, hw->mac_addr) < 0) { + AQ_DBG_ERROR("Unable to get mac addr from hw"); + goto fail; + }; + + softc->admin_ticks = 0; + + iflib_set_mac(ctx, hw->mac_addr); +#if __FreeBSD__ < 13 + /* since FreeBSD13 deadlock due to calling iflib_led_func() under CTX_LOCK() */ + iflib_led_create(ctx); +#endif + scctx->isc_tx_csum_flags = CSUM_IP | CSUM_TCP | CSUM_UDP | CSUM_TSO; +#if __FreeBSD__ >= 12 + scctx->isc_capabilities = IFCAP_RXCSUM | IFCAP_TXCSUM | IFCAP_HWCSUM | IFCAP_TSO | + IFCAP_JUMBO_MTU | IFCAP_VLAN_HWFILTER | + IFCAP_VLAN_MTU | IFCAP_VLAN_HWTAGGING | + IFCAP_VLAN_HWCSUM; + scctx->isc_capenable = scctx->isc_capabilities; +#else + if_t ifp; + ifp = iflib_get_ifp(ctx); + if_setcapenable(ifp, IFCAP_RXCSUM | IFCAP_TXCSUM | IFCAP_HWCSUM | IFCAP_TSO | + IFCAP_JUMBO_MTU | IFCAP_VLAN_HWFILTER | + IFCAP_VLAN_MTU | IFCAP_VLAN_HWTAGGING | + IFCAP_VLAN_HWCSUM; +#endif + scctx->isc_tx_nsegments = 31, + scctx->isc_tx_tso_segments_max = 31; + scctx->isc_tx_tso_size_max = HW_ATL_B0_TSO_SIZE - sizeof(struct ether_vlan_header); + scctx->isc_tx_tso_segsize_max = HW_ATL_B0_MTU_JUMBO; + scctx->isc_min_frame_size = 52; + scctx->isc_txrx = &aq_txrx; + + scctx->isc_txqsizes[0] = sizeof(aq_tx_desc_t) * scctx->isc_ntxd[0]; + scctx->isc_rxqsizes[0] = sizeof(aq_rx_desc_t) * scctx->isc_nrxd[0]; + + scctx->isc_ntxqsets_max = HW_ATL_B0_RINGS_MAX; + scctx->isc_nrxqsets_max = HW_ATL_B0_RINGS_MAX; + + /* iflib will map and release this bar */ + scctx->isc_msix_bar = pci_msix_table_bar(softc->dev); + + softc->vlan_tags = bit_alloc(4096, M_AQ, M_NOWAIT); + + AQ_DBG_EXIT(rc); + return (rc); + +fail: + if (softc->mmio_res != NULL) + bus_release_resource(softc->dev, SYS_RES_MEMORY, + softc->mmio_rid, softc->mmio_res); + + AQ_DBG_EXIT(rc); + return (ENXIO); +} + + +static int aq_if_attach_post(if_ctx_t ctx) +{ + struct aq_dev *softc; + int rc; + + AQ_DBG_ENTER(); + + softc = iflib_get_softc(ctx); + rc = 0; + + aq_update_hw_stats(softc); + + aq_initmedia(softc); + + + switch (softc->scctx->isc_intr) { + case IFLIB_INTR_LEGACY: + rc = EOPNOTSUPP; + goto exit; + goto exit; + break; + case IFLIB_INTR_MSI: + break; + case IFLIB_INTR_MSIX: + break; + default: + device_printf(softc->dev, "unknown interrupt mode\n"); + rc = EOPNOTSUPP; + goto exit; + } + + aq_add_stats_sysctls(softc); + /* RSS */ + arc4rand(softc->rss_key, HW_ATL_RSS_HASHKEY_SIZE, 0); + for (int i = ARRAY_SIZE(softc->rss_table); i--;){ + softc->rss_table[i] = i & (softc->rx_rings_count - 1); + } +exit: + AQ_DBG_EXIT(rc); + return (rc); +} + + +static int aq_if_detach(if_ctx_t ctx) +{ + struct aq_dev *softc; + int i; + + AQ_DBG_ENTER(); + softc = iflib_get_softc(ctx); + + aq_hw_deinit(&softc->hw); + + for (i = 0; i < softc->scctx->isc_nrxqsets; i++) + iflib_irq_free(ctx, &softc->rx_rings[i]->irq); + iflib_irq_free(ctx, &softc->irq); + + + if (softc->mmio_res != NULL) + bus_release_resource(softc->dev, SYS_RES_MEMORY, + softc->mmio_rid, softc->mmio_res); + + free(softc->vlan_tags, M_AQ); + + AQ_DBG_EXIT(0); + return (0); +} + +static int aq_if_shutdown(if_ctx_t ctx) +{ + + AQ_DBG_ENTER(); + + AQ_XXX_UNIMPLEMENTED_FUNCTION; + + AQ_DBG_EXIT(0); + return (0); +} + +static int aq_if_suspend(if_ctx_t ctx) +{ + AQ_DBG_ENTER(); + + AQ_XXX_UNIMPLEMENTED_FUNCTION; + + AQ_DBG_EXIT(0); + return (0); +} + +static int aq_if_resume(if_ctx_t ctx) +{ + AQ_DBG_ENTER(); + + AQ_XXX_UNIMPLEMENTED_FUNCTION; + + AQ_DBG_EXIT(0); + return (0); +} + +/* Soft queue setup and teardown */ +static int aq_if_tx_queues_alloc(if_ctx_t ctx, caddr_t *vaddrs, + uint64_t *paddrs, int ntxqs, int ntxqsets) +{ + struct aq_dev *softc; + struct aq_ring *ring; + int rc = 0, i; + + AQ_DBG_ENTERA("ntxqs=%d, ntxqsets=%d", ntxqs, ntxqsets); + softc = iflib_get_softc(ctx); + AQ_DBG_PRINT("tx descriptors number %d", softc->scctx->isc_ntxd[0]); + + for (i = 0; i < ntxqsets; i++) { + ring = softc->tx_rings[i] = malloc(sizeof(struct aq_ring), + M_AQ, M_NOWAIT | M_ZERO); + if (!ring){ + rc = ENOMEM; + device_printf(softc->dev, "atlantic: tx_ring malloc fail\n"); + goto fail; + } + ring->tx_descs = (aq_tx_desc_t*)vaddrs[i]; + ring->tx_size = softc->scctx->isc_ntxd[0]; + ring->tx_descs_phys = paddrs[i]; + ring->tx_head = ring->tx_tail = 0; + ring->index = i; + ring->dev = softc; + + softc->tx_rings_count++; + } + + AQ_DBG_EXIT(rc); + return (rc); + +fail: + aq_if_queues_free(ctx); + AQ_DBG_EXIT(rc); + return (rc); +} + +static int aq_if_rx_queues_alloc(if_ctx_t ctx, caddr_t *vaddrs, + uint64_t *paddrs, int nrxqs, int nrxqsets) +{ + struct aq_dev *softc; + struct aq_ring *ring; + int rc = 0, i; + + AQ_DBG_ENTERA("nrxqs=%d, nrxqsets=%d", nrxqs, nrxqsets); + softc = iflib_get_softc(ctx); + + for (i = 0; i < nrxqsets; i++) { + ring = softc->rx_rings[i] = malloc(sizeof(struct aq_ring), + M_AQ, M_NOWAIT | M_ZERO); + if (!ring){ + rc = ENOMEM; + device_printf(softc->dev, "atlantic: rx_ring malloc fail\n"); + goto fail; + } + + ring->rx_descs = (aq_rx_desc_t*)vaddrs[i]; + ring->rx_descs_phys = paddrs[i]; + ring->rx_size = softc->scctx->isc_nrxd[0]; + ring->index = i; + ring->dev = softc; + + switch (MCLBYTES) { + case (4 * 1024): + case (8 * 1024): + case (16 * 1024): + ring->rx_max_frame_size = MCLBYTES; + break; + default: + ring->rx_max_frame_size = 2048; + break; + } + + softc->rx_rings_count++; + } + + AQ_DBG_EXIT(rc); + return (rc); + +fail: + aq_if_queues_free(ctx); + AQ_DBG_EXIT(rc); + return (rc); +} + +static void aq_if_queues_free(if_ctx_t ctx) +{ + struct aq_dev *softc; + int i; + + AQ_DBG_ENTER(); + softc = iflib_get_softc(ctx); + + for (i = 0; i < softc->tx_rings_count; i++) { + if (softc->tx_rings[i]) { + free(softc->tx_rings[i], M_AQ); + softc->tx_rings[i] = NULL; + } + } + softc->tx_rings_count = 0; + for (i = 0; i < softc->rx_rings_count; i++) { + if (softc->rx_rings[i]){ + free(softc->rx_rings[i], M_AQ); + softc->rx_rings[i] = NULL; + } + } + softc->rx_rings_count = 0; + + AQ_DBG_EXIT(0); + return; +} + +/* Device configuration */ +static void aq_if_init(if_ctx_t ctx) +{ + struct aq_dev *softc; + struct aq_hw *hw; + struct ifmediareq ifmr; + int i, err; + + AQ_DBG_ENTER(); + softc = iflib_get_softc(ctx); + hw = &softc->hw; + + err = aq_hw_init(&softc->hw, softc->hw.mac_addr, softc->msix, + softc->scctx->isc_intr == IFLIB_INTR_MSIX); + if (err != EOK) { + device_printf(softc->dev, "atlantic: aq_hw_init: %d", err); + } + + aq_if_media_status(ctx, &ifmr); + + aq_update_vlan_filters(softc); + + for (i = 0; i < softc->tx_rings_count; i++) { + struct aq_ring *ring = softc->tx_rings[i]; + err = aq_ring_tx_init(&softc->hw, ring); + if (err) { + device_printf(softc->dev, "atlantic: aq_ring_tx_init: %d", err); + } + err = aq_ring_tx_start(hw, ring); + if (err != EOK) { + device_printf(softc->dev, "atlantic: aq_ring_tx_start: %d", err); + } + } + for (i = 0; i < softc->rx_rings_count; i++) { + struct aq_ring *ring = softc->rx_rings[i]; + err = aq_ring_rx_init(&softc->hw, ring); + if (err) { + device_printf(softc->dev, "atlantic: aq_ring_rx_init: %d", err); + } + err = aq_ring_rx_start(hw, ring); + if (err != EOK) { + device_printf(softc->dev, "atlantic: aq_ring_rx_start: %d", err); + } + aq_if_rx_queue_intr_enable(ctx, i); + } + + aq_hw_start(hw); + aq_if_enable_intr(ctx); + aq_hw_rss_hash_set(&softc->hw, softc->rss_key); + aq_hw_rss_set(&softc->hw, softc->rss_table); + aq_hw_udp_rss_enable(hw, aq_enable_rss_udp); + aq_hw_set_link_speed(hw, hw->link_rate); + + AQ_DBG_EXIT(0); +} + + +static void aq_if_stop(if_ctx_t ctx) +{ + struct aq_dev *softc; + struct aq_hw *hw; + int i; + + AQ_DBG_ENTER(); + + softc = iflib_get_softc(ctx); + hw = &softc->hw; + + /* disable interrupt */ + aq_if_disable_intr(ctx); + + for (i = 0; i < softc->tx_rings_count; i++) { + aq_ring_tx_stop(hw, softc->tx_rings[i]); + softc->tx_rings[i]->tx_head = 0; + softc->tx_rings[i]->tx_tail = 0; + } + for (i = 0; i < softc->rx_rings_count; i++) { + aq_ring_rx_stop(hw, softc->rx_rings[i]); + } + + aq_hw_reset(&softc->hw); + memset(&softc->last_stats, 0, sizeof(softc->last_stats)); + softc->linkup = false; + aq_if_update_admin_status(ctx); + AQ_DBG_EXIT(0); +} + +static uint64_t aq_if_get_counter(if_ctx_t ctx, ift_counter cnt) +{ + struct aq_dev *softc = iflib_get_softc(ctx); + if_t ifp = iflib_get_ifp(ctx); + + switch (cnt) { + case IFCOUNTER_IERRORS: + return (softc->curr_stats.erpr); + case IFCOUNTER_IQDROPS: + return (softc->curr_stats.dpc); + case IFCOUNTER_OERRORS: + return (softc->curr_stats.erpt); + default: + return (if_get_counter_default(ifp, cnt)); + } +} + +#if __FreeBSD_version >= 1300054 +static u_int aq_mc_filter_apply(void *arg, struct sockaddr_dl *dl, u_int count) +{ + struct aq_dev *softc = arg; + struct aq_hw *hw = &softc->hw; + u8 *mac_addr = NULL; + + if (count == AQ_HW_MAC_MAX) + return (0); + + mac_addr = LLADDR(dl); + aq_hw_mac_addr_set(hw, mac_addr, count + 1); + + aq_log_detail("set %d mc address %6D", count + 1, mac_addr, ":"); + return (1); +} +#else +static int aq_mc_filter_apply(void *arg, struct ifmultiaddr *ifma, int count) +{ + struct aq_dev *softc = arg; + struct aq_hw *hw = &softc->hw; + u8 *mac_addr = NULL; + + if (ifma->ifma_addr->sa_family != AF_LINK) + return (0); + if (count == AQ_HW_MAC_MAX) + return (0); + + mac_addr = LLADDR((struct sockaddr_dl *)ifma->ifma_addr); + aq_hw_mac_addr_set(hw, mac_addr, count + 1); + + aq_log_detail("set %d mc address %6D", count + 1, mac_addr, ":"); + return (1); +} +#endif + +static bool aq_is_mc_promisc_required(struct aq_dev *softc) +{ + return (softc->mcnt >= AQ_HW_MAC_MAX); +} + +static void aq_if_multi_set(if_ctx_t ctx) +{ + struct aq_dev *softc = iflib_get_softc(ctx); + if_t ifp = iflib_get_ifp(ctx); + struct aq_hw *hw = &softc->hw; + AQ_DBG_ENTER(); +#if __FreeBSD_version >= 1300054 + softc->mcnt = if_llmaddr_count(iflib_get_ifp(ctx)); +#else + softc->mcnt = if_multiaddr_count(iflib_get_ifp(ctx), AQ_HW_MAC_MAX); +#endif + if (softc->mcnt >= AQ_HW_MAC_MAX) + { + aq_hw_set_promisc(hw, !!(if_getflags(ifp) & IFF_PROMISC), + aq_is_vlan_promisc_required(softc), + !!(if_getflags(ifp) & IFF_ALLMULTI) || aq_is_mc_promisc_required(softc)); + }else{ +#if __FreeBSD_version >= 1300054 + if_foreach_llmaddr(iflib_get_ifp(ctx), &aq_mc_filter_apply, softc); +#else + if_multi_apply(iflib_get_ifp(ctx), aq_mc_filter_apply, softc); +#endif + } + AQ_DBG_EXIT(0); +} + +static int aq_if_mtu_set(if_ctx_t ctx, uint32_t mtu) +{ + int err = 0; + AQ_DBG_ENTER(); + + AQ_DBG_EXIT(err); + return (err); +} + +static void aq_if_media_status(if_ctx_t ctx, struct ifmediareq *ifmr) +{ + if_t ifp; + + AQ_DBG_ENTER(); + + ifp = iflib_get_ifp(ctx); + + aq_mediastatus(ifp, ifmr); + + AQ_DBG_EXIT(0); +} + +static int aq_if_media_change(if_ctx_t ctx) +{ + struct aq_dev *softc = iflib_get_softc(ctx); + if_t ifp = iflib_get_ifp(ctx); + int rc = 0; + + AQ_DBG_ENTER(); + + /* Not allowd in UP state, since causes unsync of rings */ + if ((if_getflags(ifp) & IFF_UP)){ + rc = EPERM; + goto exit; + } + + ifp = iflib_get_ifp(softc->ctx); + + rc = aq_mediachange(ifp); + +exit: + AQ_DBG_EXIT(rc); + return (rc); +} + +static int aq_if_promisc_set(if_ctx_t ctx, int flags) +{ + struct aq_dev *softc; + + AQ_DBG_ENTER(); + + softc = iflib_get_softc(ctx); + + aq_hw_set_promisc(&softc->hw, !!(flags & IFF_PROMISC), + aq_is_vlan_promisc_required(softc), + !!(flags & IFF_ALLMULTI) || aq_is_mc_promisc_required(softc)); + + AQ_DBG_EXIT(0); + return (0); +} + +static void aq_if_timer(if_ctx_t ctx, uint16_t qid) +{ + struct aq_dev *softc; + uint64_t ticks_now; + +// AQ_DBG_ENTER(); + + softc = iflib_get_softc(ctx); + ticks_now = ticks; + + /* Schedule aqc_if_update_admin_status() once per sec */ + if (ticks_now - softc->admin_ticks >= hz) { + softc->admin_ticks = ticks_now; + iflib_admin_intr_deferred(ctx); + } + +// AQ_DBG_EXIT(0); + return; + +} + +/* Interrupt enable / disable */ +static void aq_if_enable_intr(if_ctx_t ctx) +{ + struct aq_dev *softc = iflib_get_softc(ctx); + struct aq_hw *hw = &softc->hw; + + AQ_DBG_ENTER(); + + /* Enable interrupts */ + itr_irq_msk_setlsw_set(hw, BIT(softc->msix + 1) - 1); + + AQ_DBG_EXIT(0); +} + +static void aq_if_disable_intr(if_ctx_t ctx) +{ + struct aq_dev *softc = iflib_get_softc(ctx); + struct aq_hw *hw = &softc->hw; + + AQ_DBG_ENTER(); + + /* Disable interrupts */ + itr_irq_msk_clearlsw_set(hw, BIT(softc->msix + 1) - 1); + + AQ_DBG_EXIT(0); +} + +static int aq_if_rx_queue_intr_enable(if_ctx_t ctx, uint16_t rxqid) +{ + struct aq_dev *softc = iflib_get_softc(ctx); + struct aq_hw *hw = &softc->hw; + + AQ_DBG_ENTER(); + + itr_irq_msk_setlsw_set(hw, BIT(softc->rx_rings[rxqid]->msix)); + + AQ_DBG_EXIT(0); + return (0); +} + +static int aq_if_msix_intr_assign(if_ctx_t ctx, int msix) +{ + struct aq_dev *softc; + int i, vector = 0, rc; + char irq_name[16]; + int rx_vectors; + + AQ_DBG_ENTER(); + softc = iflib_get_softc(ctx); + + for (i = 0; i < softc->rx_rings_count; i++, vector++) { + snprintf(irq_name, sizeof(irq_name), "rxq%d", i); + rc = iflib_irq_alloc_generic(ctx, &softc->rx_rings[i]->irq, + vector + 1, IFLIB_INTR_RX, aq_isr_rx, softc->rx_rings[i], + softc->rx_rings[i]->index, irq_name); + device_printf(softc->dev, "Assign IRQ %u to rx ring %u\n", + vector, softc->rx_rings[i]->index); + + if (rc) { + device_printf(softc->dev, "failed to set up RX handler\n"); + i--; + goto fail; + } + + softc->rx_rings[i]->msix = vector; + } + + rx_vectors = vector; + + for (i = 0; i < softc->tx_rings_count; i++, vector++) { + snprintf(irq_name, sizeof(irq_name), "txq%d", i); + iflib_softirq_alloc_generic(ctx, &softc->rx_rings[i]->irq, IFLIB_INTR_TX, + softc->tx_rings[i], i, irq_name); + + softc->tx_rings[i]->msix = (vector % softc->rx_rings_count); + device_printf(softc->dev, "Assign IRQ %u to tx ring %u\n", + softc->tx_rings[i]->msix, softc->tx_rings[i]->index); + } + + rc = iflib_irq_alloc_generic(ctx, &softc->irq, rx_vectors + 1, + IFLIB_INTR_ADMIN, aq_linkstat_isr, + softc, 0, "aq"); + softc->msix = rx_vectors; + device_printf(softc->dev, "Assign IRQ %u to admin proc \n", + rx_vectors); + if (rc) { + device_printf(iflib_get_dev(ctx), "Failed to register admin handler"); + i = softc->rx_rings_count; + goto fail; + } + AQ_DBG_EXIT(0); + return (0); + +fail: + for (; i >= 0; i--) + iflib_irq_free(ctx, &softc->rx_rings[i]->irq); + AQ_DBG_EXIT(rc); + return (rc); +} + +static bool aq_is_vlan_promisc_required(struct aq_dev *softc) +{ + int vlan_tag_count; + + bit_count(softc->vlan_tags, 0, 4096, &vlan_tag_count); + + if (vlan_tag_count <= AQ_HW_VLAN_MAX_FILTERS) + return (false); + else + return (true); + +} + +static void aq_update_vlan_filters(struct aq_dev *softc) +{ + struct aq_rx_filter_vlan aq_vlans[AQ_HW_VLAN_MAX_FILTERS]; + struct aq_hw *hw = &softc->hw; + int bit_pos = 0; + int vlan_tag = -1; + int i; + + hw_atl_b0_hw_vlan_promisc_set(hw, true); + for (i = 0; i < AQ_HW_VLAN_MAX_FILTERS; i++) { + bit_ffs_at(softc->vlan_tags, bit_pos, 4096, &vlan_tag); + if (vlan_tag != -1) { + aq_vlans[i].enable = true; + aq_vlans[i].location = i; + aq_vlans[i].queue = 0xFF; + aq_vlans[i].vlan_id = vlan_tag; + bit_pos = vlan_tag; + } else { + aq_vlans[i].enable = false; + } + } + + hw_atl_b0_hw_vlan_set(hw, aq_vlans); + hw_atl_b0_hw_vlan_promisc_set(hw, aq_is_vlan_promisc_required(softc)); +} + +/* VLAN support */ +static void aq_if_vlan_register(if_ctx_t ctx, uint16_t vtag) +{ + struct aq_dev *softc = iflib_get_softc(ctx); + + AQ_DBG_ENTERA("%d", vtag); + + bit_set(softc->vlan_tags, vtag); + + aq_update_vlan_filters(softc); + + AQ_DBG_EXIT(0); +} + +static void aq_if_vlan_unregister(if_ctx_t ctx, uint16_t vtag) +{ + struct aq_dev *softc = iflib_get_softc(ctx); + + AQ_DBG_ENTERA("%d", vtag); + + bit_clear(softc->vlan_tags, vtag); + + aq_update_vlan_filters(softc); + + AQ_DBG_EXIT(0); +} + +static void aq_if_led_func(if_ctx_t ctx, int onoff) +{ + struct aq_dev *softc = iflib_get_softc(ctx); + struct aq_hw *hw = &softc->hw; + + AQ_DBG_ENTERA("%d", onoff); + if (hw->fw_ops && hw->fw_ops->led_control) + hw->fw_ops->led_control(hw, onoff); + + AQ_DBG_EXIT(0); +} + +static int aq_hw_capabilities(struct aq_dev *softc) +{ + + if (pci_get_vendor(softc->dev) != AQUANTIA_VENDOR_ID) + return (ENXIO); + + switch (pci_get_device(softc->dev)) { + case AQ_DEVICE_ID_D100: + case AQ_DEVICE_ID_AQC100: + case AQ_DEVICE_ID_AQC100S: + softc->media_type = AQ_MEDIA_TYPE_FIBRE; + softc->link_speeds = AQ_LINK_ALL & ~AQ_LINK_10G; + break; + + case AQ_DEVICE_ID_0001: + case AQ_DEVICE_ID_D107: + case AQ_DEVICE_ID_AQC107: + case AQ_DEVICE_ID_AQC107S: + softc->media_type = AQ_MEDIA_TYPE_TP; + softc->link_speeds = AQ_LINK_ALL; + break; + + case AQ_DEVICE_ID_D108: + case AQ_DEVICE_ID_AQC108: + case AQ_DEVICE_ID_AQC108S: + case AQ_DEVICE_ID_AQC111: + case AQ_DEVICE_ID_AQC111S: + softc->media_type = AQ_MEDIA_TYPE_TP; + softc->link_speeds = AQ_LINK_ALL & ~AQ_LINK_10G; + break; + + case AQ_DEVICE_ID_D109: + case AQ_DEVICE_ID_AQC109: + case AQ_DEVICE_ID_AQC109S: + case AQ_DEVICE_ID_AQC112: + case AQ_DEVICE_ID_AQC112S: + softc->media_type = AQ_MEDIA_TYPE_TP; + softc->link_speeds = AQ_LINK_ALL & ~(AQ_LINK_10G | AQ_LINK_5G); + break; + + default: + return (ENXIO); + } + + return (0); +} + +static int aq_sysctl_print_rss_config(SYSCTL_HANDLER_ARGS) +{ + struct aq_dev *softc = (struct aq_dev *)arg1; + device_t dev = softc->dev; + struct sbuf *buf; + int error = 0; + + buf = sbuf_new_for_sysctl(NULL, NULL, 256, req); + if (!buf) { + device_printf(dev, "Could not allocate sbuf for output.\n"); + return (ENOMEM); + } + + /* Print out the redirection table */ + sbuf_cat(buf, "\nRSS Indirection table:\n"); + for (int i = 0; i < HW_ATL_RSS_INDIRECTION_TABLE_MAX; i++) { + sbuf_printf(buf, "%d ", softc->rss_table[i]); + if ((i+1) % 10 == 0) + sbuf_printf(buf, "\n"); + } + + sbuf_cat(buf, "\nRSS Key:\n"); + for (int i = 0; i < HW_ATL_RSS_HASHKEY_SIZE; i++) { + sbuf_printf(buf, "0x%02x ", softc->rss_key[i]); + } + sbuf_printf(buf, "\n"); + + error = sbuf_finish(buf); + if (error) + device_printf(dev, "Error finishing sbuf: %d\n", error); + + sbuf_delete(buf); + + return (0); +} + +static int aq_sysctl_print_tx_head(SYSCTL_HANDLER_ARGS) +{ + struct aq_ring *ring = arg1; + int error = 0; + unsigned int val; + + if (!ring) + return (0); + + val = tdm_tx_desc_head_ptr_get(&ring->dev->hw, ring->index); + + error = sysctl_handle_int(oidp, &val, 0, req); + if (error || !req->newptr) + return (error); + + return (0); +} + +static int aq_sysctl_print_tx_tail(SYSCTL_HANDLER_ARGS) +{ + struct aq_ring *ring = arg1; + int error = 0; + unsigned int val; + + if (!ring) + return (0); + + val = reg_tx_dma_desc_tail_ptr_get(&ring->dev->hw, ring->index); + + error = sysctl_handle_int(oidp, &val, 0, req); + if (error || !req->newptr) + return (error); + + return (0); +} + +static int aq_sysctl_print_rx_head(SYSCTL_HANDLER_ARGS) +{ + struct aq_ring *ring = arg1; + int error = 0; + unsigned int val; + + if (!ring) + return (0); + + val = rdm_rx_desc_head_ptr_get(&ring->dev->hw, ring->index); + + error = sysctl_handle_int(oidp, &val, 0, req); + if (error || !req->newptr) + return (error); + + return (0); +} + +static int aq_sysctl_print_rx_tail(SYSCTL_HANDLER_ARGS) +{ + struct aq_ring *ring = arg1; + int error = 0; + unsigned int val; + + if (!ring) + return (0); + + val = reg_rx_dma_desc_tail_ptr_get(&ring->dev->hw, ring->index); + + error = sysctl_handle_int(oidp, &val, 0, req); + if (error || !req->newptr) + return (error); + + return (0); +} + +static void aq_add_stats_sysctls(struct aq_dev *softc) +{ + device_t dev = softc->dev; + struct sysctl_ctx_list *ctx = device_get_sysctl_ctx(dev); + struct sysctl_oid *tree = device_get_sysctl_tree(dev); + struct sysctl_oid_list *child = SYSCTL_CHILDREN(tree); + struct aq_stats_s *stats = &softc->curr_stats; + struct sysctl_oid *stat_node, *queue_node; + struct sysctl_oid_list *stat_list, *queue_list; + +#define QUEUE_NAME_LEN 32 + char namebuf[QUEUE_NAME_LEN]; + /* RSS configuration */ + SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "print_rss_config", + CTLTYPE_STRING | CTLFLAG_RD, softc, 0, + aq_sysctl_print_rss_config, "A", "Prints RSS Configuration"); + + /* Driver Statistics */ + for (int i = 0; i < softc->tx_rings_count; i++) { + struct aq_ring *ring = softc->tx_rings[i]; + snprintf(namebuf, QUEUE_NAME_LEN, "tx_queue%d", i); + queue_node = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, namebuf, + CTLFLAG_RD, NULL, "Queue Name"); + queue_list = SYSCTL_CHILDREN(queue_node); + + SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "tx_pkts", + CTLFLAG_RD, &(ring->stats.tx_pkts), "TX Packets"); + SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "tx_bytes", + CTLFLAG_RD, &(ring->stats.tx_bytes), "TX Octets"); + SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "tx_drops", + CTLFLAG_RD, &(ring->stats.tx_drops), "TX Drops"); + SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "tx_queue_full", + CTLFLAG_RD, &(ring->stats.tx_queue_full), "TX Queue Full"); + SYSCTL_ADD_PROC(ctx, queue_list, OID_AUTO, "tx_head", + CTLTYPE_UINT | CTLFLAG_RD, ring, 0, + aq_sysctl_print_tx_head, "IU", "ring head pointer"); + SYSCTL_ADD_PROC(ctx, queue_list, OID_AUTO, "tx_tail", + CTLTYPE_UINT | CTLFLAG_RD, ring, 0, + aq_sysctl_print_tx_tail, "IU", "ring tail pointer"); + } + + for (int i = 0; i < softc->rx_rings_count; i++) { + struct aq_ring *ring = softc->rx_rings[i]; + snprintf(namebuf, QUEUE_NAME_LEN, "rx_queue%d", i); + queue_node = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, namebuf, + CTLFLAG_RD, NULL, "Queue Name"); + queue_list = SYSCTL_CHILDREN(queue_node); + + SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "rx_pkts", + CTLFLAG_RD, &(ring->stats.rx_pkts), "RX Packets"); + SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "rx_bytes", + CTLFLAG_RD, &(ring->stats.rx_bytes), "TX Octets"); + SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "jumbo_pkts", + CTLFLAG_RD, &(ring->stats.jumbo_pkts), "Jumbo Packets"); + SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "rx_err", + CTLFLAG_RD, &(ring->stats.rx_err), "RX Errors"); + SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "irq", + CTLFLAG_RD, &(ring->stats.irq), "RX interrupts"); + SYSCTL_ADD_PROC(ctx, queue_list, OID_AUTO, "rx_head", + CTLTYPE_UINT | CTLFLAG_RD, ring, 0, + aq_sysctl_print_rx_head, "IU", "ring head pointer"); + SYSCTL_ADD_PROC(ctx, queue_list, OID_AUTO, "rx_tail", + CTLTYPE_UINT | CTLFLAG_RD, ring, 0, + aq_sysctl_print_rx_tail, "IU", " ring tail pointer"); + } + + stat_node = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, "mac", + CTLFLAG_RD, NULL, "Statistics (read from HW registers)"); + stat_list = SYSCTL_CHILDREN(stat_node); + + SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "good_pkts_rcvd", + CTLFLAG_RD, &stats->prc, "Good Packets Received"); + SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "ucast_pkts_rcvd", + CTLFLAG_RD, &stats->uprc, "Unicast Packets Received"); + SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "mcast_pkts_rcvd", + CTLFLAG_RD, &stats->mprc, "Multicast Packets Received"); + SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "bcast_pkts_rcvd", + CTLFLAG_RD, &stats->bprc, "Broadcast Packets Received"); + SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "rsc_pkts_rcvd", + CTLFLAG_RD, &stats->cprc, "Coalesced Packets Received"); + SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "err_pkts_rcvd", + CTLFLAG_RD, &stats->erpr, "Errors of Packet Receive"); + SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "drop_pkts_dma", + CTLFLAG_RD, &stats->dpc, "Dropped Packets in DMA"); + SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "good_octets_rcvd", + CTLFLAG_RD, &stats->brc, "Good Octets Received"); + SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "ucast_octets_rcvd", + CTLFLAG_RD, &stats->ubrc, "Unicast Octets Received"); + SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "mcast_octets_rcvd", + CTLFLAG_RD, &stats->mbrc, "Multicast Octets Received"); + SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "bcast_octets_rcvd", + CTLFLAG_RD, &stats->bbrc, "Broadcast Octets Received"); + + SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "good_pkts_txd", + CTLFLAG_RD, &stats->ptc, "Good Packets Transmitted"); + SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "ucast_pkts_txd", + CTLFLAG_RD, &stats->uptc, "Unicast Packets Transmitted"); + SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "mcast_pkts_txd", + CTLFLAG_RD, &stats->mptc, "Multicast Packets Transmitted"); + SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "bcast_pkts_txd", + CTLFLAG_RD, &stats->bptc, "Broadcast Packets Transmitted"); + + SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "err_pkts_txd", + CTLFLAG_RD, &stats->erpt, "Errors of Packet Transmit"); + SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "good_octets_txd", + CTLFLAG_RD, &stats->btc, "Good Octets Transmitted"); + SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "ucast_octets_txd", + CTLFLAG_RD, &stats->ubtc, "Unicast Octets Transmitted"); + SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "mcast_octets_txd", + CTLFLAG_RD, &stats->mbtc, "Multicast Octets Transmitted"); + SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "bcast_octets_txd", + CTLFLAG_RD, &stats->bbtc, "Broadcast Octets Transmitted"); +} |
