diff --git a/sys/dev/ena/ena.c b/sys/dev/ena/ena.c
index 4ce9af80f258..51fbdaa2f0ec 100644
--- a/sys/dev/ena/ena.c
+++ b/sys/dev/ena/ena.c
@@ -1,3865 +1,3818 @@
 /*-
  * BSD LICENSE
  *
  * Copyright (c) 2015-2017 Amazon.com, Inc. or its affiliates.
  * 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.
  *
  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT
  * OWNER 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/endian.h>
 #include <sys/kernel.h>
 #include <sys/kthread.h>
 #include <sys/malloc.h>
 #include <sys/mbuf.h>
 #include <sys/module.h>
 #include <sys/rman.h>
 #include <sys/smp.h>
 #include <sys/socket.h>
 #include <sys/sockio.h>
 #include <sys/sysctl.h>
 #include <sys/taskqueue.h>
 #include <sys/time.h>
 #include <sys/eventhandler.h>
 
 #include <machine/bus.h>
 #include <machine/resource.h>
 #include <machine/in_cksum.h>
 
 #include <net/bpf.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/rss_config.h>
 #include <net/if_types.h>
 #include <net/if_vlan_var.h>
 
 #include <netinet/in_rss.h>
 #include <netinet/in_systm.h>
 #include <netinet/in.h>
 #include <netinet/if_ether.h>
 #include <netinet/ip.h>
 #include <netinet/ip6.h>
 #include <netinet/tcp.h>
 #include <netinet/udp.h>
 
 #include <dev/pci/pcivar.h>
 #include <dev/pci/pcireg.h>
 
 #include "ena.h"
 #include "ena_sysctl.h"
 
 /*********************************************************
  *  Function prototypes
  *********************************************************/
 static int	ena_probe(device_t);
 static void	ena_intr_msix_mgmnt(void *);
 static int	ena_allocate_pci_resources(struct ena_adapter*);
 static void	ena_free_pci_resources(struct ena_adapter *);
 static int	ena_change_mtu(if_t, int);
 static inline void ena_alloc_counters(counter_u64_t *, int);
 static inline void ena_free_counters(counter_u64_t *, int);
 static inline void ena_reset_counters(counter_u64_t *, int);
 static void	ena_init_io_rings_common(struct ena_adapter *,
     struct ena_ring *, uint16_t);
 static int	ena_init_io_rings(struct ena_adapter *);
 static void	ena_free_io_ring_resources(struct ena_adapter *, unsigned int);
 static void	ena_free_all_io_rings_resources(struct ena_adapter *);
 static int	ena_setup_tx_dma_tag(struct ena_adapter *);
 static int	ena_free_tx_dma_tag(struct ena_adapter *);
 static int	ena_setup_rx_dma_tag(struct ena_adapter *);
 static int	ena_free_rx_dma_tag(struct ena_adapter *);
 static int	ena_setup_tx_resources(struct ena_adapter *, int);
 static void	ena_free_tx_resources(struct ena_adapter *, int);
 static int	ena_setup_all_tx_resources(struct ena_adapter *);
 static void	ena_free_all_tx_resources(struct ena_adapter *);
 static int	ena_setup_rx_resources(struct ena_adapter *, unsigned int);
 static void	ena_free_rx_resources(struct ena_adapter *, unsigned int);
 static int	ena_setup_all_rx_resources(struct ena_adapter *);
 static void	ena_free_all_rx_resources(struct ena_adapter *);
 static inline int ena_alloc_rx_mbuf(struct ena_adapter *, struct ena_ring *,
     struct ena_rx_buffer *);
 static void	ena_free_rx_mbuf(struct ena_adapter *, struct ena_ring *,
     struct ena_rx_buffer *);
 static int	ena_refill_rx_bufs(struct ena_ring *, uint32_t);
 static void	ena_free_rx_bufs(struct ena_adapter *, unsigned int);
 static void	ena_refill_all_rx_bufs(struct ena_adapter *);
 static void	ena_free_all_rx_bufs(struct ena_adapter *);
 static void	ena_free_tx_bufs(struct ena_adapter *, unsigned int);
 static void	ena_free_all_tx_bufs(struct ena_adapter *);
 static void	ena_destroy_all_tx_queues(struct ena_adapter *);
 static void	ena_destroy_all_rx_queues(struct ena_adapter *);
 static void	ena_destroy_all_io_queues(struct ena_adapter *);
 static int	ena_create_io_queues(struct ena_adapter *);
 static int	ena_tx_cleanup(struct ena_ring *);
 static int	ena_rx_cleanup(struct ena_ring *);
 static int	validate_tx_req_id(struct ena_ring *, uint16_t);
 static void	ena_rx_hash_mbuf(struct ena_ring *, struct ena_com_rx_ctx *,
     struct mbuf *);
 static struct mbuf* ena_rx_mbuf(struct ena_ring *, struct ena_com_rx_buf_info *,
     struct ena_com_rx_ctx *, uint16_t *);
 static inline void ena_rx_checksum(struct ena_ring *, struct ena_com_rx_ctx *,
     struct mbuf *);
 static void	ena_handle_msix(void *);
 static int	ena_enable_msix(struct ena_adapter *);
 static void	ena_setup_mgmnt_intr(struct ena_adapter *);
 static void	ena_setup_io_intr(struct ena_adapter *);
 static int	ena_request_mgmnt_irq(struct ena_adapter *);
 static int	ena_request_io_irq(struct ena_adapter *);
 static void	ena_free_mgmnt_irq(struct ena_adapter *);
 static void	ena_free_io_irq(struct ena_adapter *);
 static void	ena_free_irqs(struct ena_adapter*);
 static void	ena_disable_msix(struct ena_adapter *);
 static void	ena_unmask_all_io_irqs(struct ena_adapter *);
 static int	ena_rss_configure(struct ena_adapter *);
-static void	ena_update_hw_stats(void *, int);
 static int	ena_up_complete(struct ena_adapter *);
 static int	ena_up(struct ena_adapter *);
 static void	ena_down(struct ena_adapter *);
 static uint64_t	ena_get_counter(if_t, ift_counter);
 static int	ena_media_change(if_t);
 static void	ena_media_status(if_t, struct ifmediareq *);
 static void	ena_init(void *);
 static int	ena_ioctl(if_t, u_long, caddr_t);
 static int	ena_get_dev_offloads(struct ena_com_dev_get_features_ctx *);
 static void	ena_update_host_info(struct ena_admin_host_info *, if_t);
 static void	ena_update_hwassist(struct ena_adapter *);
 static int	ena_setup_ifnet(device_t, struct ena_adapter *,
     struct ena_com_dev_get_features_ctx *);
 static void	ena_tx_csum(struct ena_com_tx_ctx *, struct mbuf *);
 static int	ena_check_and_collapse_mbuf(struct ena_ring *tx_ring,
     struct mbuf **mbuf);
 static int	ena_xmit_mbuf(struct ena_ring *, struct mbuf **);
 static void	ena_start_xmit(struct ena_ring *);
 static int	ena_mq_start(if_t, struct mbuf *);
 static void	ena_deferred_mq_start(void *, int);
 static void	ena_qflush(if_t);
 static int	ena_calc_io_queue_num(struct ena_adapter *,
     struct ena_com_dev_get_features_ctx *);
 static int	ena_calc_queue_size(struct ena_adapter *, uint16_t *,
     uint16_t *, struct ena_com_dev_get_features_ctx *);
 static int	ena_rss_init_default(struct ena_adapter *);
 static void	ena_rss_init_default_deferred(void *);
 static void	ena_config_host_info(struct ena_com_dev *);
 static int	ena_attach(device_t);
 static int	ena_detach(device_t);
 static int	ena_device_init(struct ena_adapter *, device_t,
     struct ena_com_dev_get_features_ctx *, int *);
 static int	ena_enable_msix_and_set_admin_interrupts(struct ena_adapter *,
     int);
 static void ena_update_on_link_change(void *, struct ena_admin_aenq_entry *);
 static void	unimplemented_aenq_handler(void *,
     struct ena_admin_aenq_entry *);
 static void	ena_timer_service(void *);
 
 static char ena_version[] = DEVICE_NAME DRV_MODULE_NAME " v" DRV_MODULE_VERSION;
 
 static SYSCTL_NODE(_hw, OID_AUTO, ena, CTLFLAG_RD, 0, "ENA driver parameters");
 
 /*
  * Tuneable number of buffers in the buf-ring (drbr)
  */
 static int ena_buf_ring_size = 4096;
 SYSCTL_INT(_hw_ena, OID_AUTO, buf_ring_size, CTLFLAG_RWTUN,
     &ena_buf_ring_size, 0, "Size of the bufring");
 
 
 static ena_vendor_info_t ena_vendor_info_array[] = {
     { PCI_VENDOR_ID_AMAZON, PCI_DEV_ID_ENA_PF, 0},
     { PCI_VENDOR_ID_AMAZON, PCI_DEV_ID_ENA_LLQ_PF, 0},
     { PCI_VENDOR_ID_AMAZON, PCI_DEV_ID_ENA_VF, 0},
     { PCI_VENDOR_ID_AMAZON, PCI_DEV_ID_ENA_LLQ_VF, 0},
     /* Last entry */
     { 0, 0, 0 }
 };
 
 /*
  * Contains pointers to event handlers, e.g. link state chage.
  */
 static struct ena_aenq_handlers aenq_handlers;
 
 void
 ena_dmamap_callback(void *arg, bus_dma_segment_t *segs, int nseg, int error)
 {
 	if (error)
 		return;
 	*(bus_addr_t *) arg = segs[0].ds_addr;
 	return;
 }
 
 int
 ena_dma_alloc(device_t dmadev, bus_size_t size,
     ena_mem_handle_t *dma , int mapflags)
 {
 	struct ena_adapter* adapter = device_get_softc(dmadev);
 	uint32_t maxsize = ((size - 1)/PAGE_SIZE + 1) * PAGE_SIZE;
 	uint64_t dma_space_addr = ENA_DMA_BIT_MASK(adapter->dma_width);
 	int error;
 
 	if (dma_space_addr == 0)
 		dma_space_addr = BUS_SPACE_MAXADDR;
 	error = bus_dma_tag_create(bus_get_dma_tag(dmadev), /* parent */
 	    8, 0,	      /* alignment, bounds 		*/
 	    dma_space_addr,   /* lowaddr of exclusion window	*/
 	    BUS_SPACE_MAXADDR,/* highaddr of exclusion window	*/
 	    NULL, NULL,	      /* filter, filterarg 		*/
 	    maxsize,	      /* maxsize 			*/
 	    1,		      /* nsegments 			*/
 	    maxsize,	      /* maxsegsize 			*/
 	    BUS_DMA_ALLOCNOW, /* flags 				*/
 	    NULL,	      /* lockfunc 			*/
 	    NULL,	      /* lockarg 			*/
 	    &dma->tag);
 	if (error) {
 		device_printf(dmadev,
 		"%s: bus_dma_tag_create failed: %d\n",
 		__func__, error);
 		goto fail_tag;
 	}
 
 	error = bus_dmamem_alloc(dma->tag, (void**) &dma->vaddr,
 	    BUS_DMA_COHERENT | BUS_DMA_ZERO, &dma->map);
 	if (error) {
 		device_printf(dmadev,
 		"%s: bus_dmamem_alloc(%ju) failed: %d\n",
 		__func__, (uintmax_t)size, error);
 		goto fail_map_create;
 	}
 
 	dma->paddr = 0;
 	error = bus_dmamap_load(dma->tag, dma->map, dma->vaddr,
 	    size, ena_dmamap_callback, &dma->paddr, mapflags);
 	if (error || dma->paddr == 0) {
 		device_printf(dmadev,
 		"%s: bus_dmamap_load failed: %d\n",
 		__func__, error);
 		goto fail_map_load;
 	}
 
 	return (0);
 
 fail_map_load:
 	bus_dmamap_unload(dma->tag, dma->map);
 fail_map_create:
 	bus_dmamem_free(dma->tag, dma->vaddr, dma->map);
 	bus_dma_tag_destroy(dma->tag);
 fail_tag:
 	dma->tag = NULL;
 
 	return (error);
 }
 
 static int
 ena_allocate_pci_resources(struct ena_adapter* adapter)
 {
 	device_t pdev = adapter->pdev;
 	int rid;
 
 	rid = PCIR_BAR(ENA_REG_BAR);
 	adapter->memory = NULL;
 	adapter->registers = bus_alloc_resource_any(pdev, SYS_RES_MEMORY,
 	    &rid, RF_ACTIVE);
 	if (adapter->registers == NULL) {
 		device_printf(pdev, "Unable to allocate bus resource: "
 		    "registers\n");
 		return (ENXIO);
 	}
 
 	return (0);
 }
 
 static void
 ena_free_pci_resources(struct ena_adapter *adapter)
 {
 	device_t pdev = adapter->pdev;
 
 	if (adapter->memory != NULL) {
 		bus_release_resource(pdev, SYS_RES_MEMORY,
 		    PCIR_BAR(ENA_MEM_BAR), adapter->memory);
 	}
 
 	if (adapter->registers != NULL) {
 		bus_release_resource(pdev, SYS_RES_MEMORY,
 		    PCIR_BAR(ENA_REG_BAR), adapter->registers);
 	}
 
 	return;
 }
 
 static int
 ena_probe(device_t dev)
 {
 	ena_vendor_info_t *ent;
 	char		adapter_name[60];
 	uint16_t	pci_vendor_id = 0;
 	uint16_t	pci_device_id = 0;
 
 	pci_vendor_id = pci_get_vendor(dev);
 	pci_device_id = pci_get_device(dev);
 
 	ent = ena_vendor_info_array;
 	while (ent->vendor_id != 0) {
 		if ((pci_vendor_id == ent->vendor_id) &&
 		    (pci_device_id == ent->device_id)) {
 			ena_trace(ENA_DBG, "vendor=%x device=%x ",
 			    pci_vendor_id, pci_device_id);
 
 			sprintf(adapter_name, DEVICE_DESC);
 			device_set_desc_copy(dev, adapter_name);
 			return (BUS_PROBE_DEFAULT);
 		}
 
 		ent++;
 
 	}
 
 	return (ENXIO);
 }
 
 static int
 ena_change_mtu(if_t ifp, int new_mtu)
 {
 	struct ena_adapter *adapter = if_getsoftc(ifp);
 	struct ena_com_dev_get_features_ctx get_feat_ctx;
 	int rc, old_mtu, max_frame;
 
 	rc = ena_com_get_dev_attr_feat(adapter->ena_dev, &get_feat_ctx);
 	if (rc) {
 		device_printf(adapter->pdev,
 		    "Cannot get attribute for ena device\n");
 		return (ENXIO);
 	}
 
 	/* Save old MTU in case of fail */
 	old_mtu = if_getmtu(ifp);
 
 	/* Change MTU and calculate max frame */
 	if_setmtu(ifp, new_mtu);
 	max_frame = ETHER_MAX_FRAME(ifp, ETHERTYPE_VLAN, 1);
 
 	if ((new_mtu < ENA_MIN_FRAME_LEN) ||
 	    (new_mtu > get_feat_ctx.dev_attr.max_mtu) ||
 	    (max_frame > ENA_MAX_FRAME_LEN)) {
 		device_printf(adapter->pdev, "Invalid MTU setting. "
 		    "new_mtu: %d\n", new_mtu);
 		goto error;
 	}
 
 	rc = ena_com_set_dev_mtu(adapter->ena_dev, new_mtu);
 	if (rc != 0)
 		goto error;
 
 	return (0);
 error:
 	if_setmtu(ifp, old_mtu);
 	return (EINVAL);
 }
 
 static inline void
 ena_alloc_counters(counter_u64_t *begin, int size)
 {
 	counter_u64_t *end = (counter_u64_t *)((char *)begin + size);
 
 	for (; begin < end; ++begin)
 		*begin = counter_u64_alloc(M_WAITOK);
 }
 
 static inline void
 ena_free_counters(counter_u64_t *begin, int size)
 {
 	counter_u64_t *end = (counter_u64_t *)((char *)begin + size);
 
 	for (; begin < end; ++begin)
 		counter_u64_free(*begin);
 }
 
 static inline void
 ena_reset_counters(counter_u64_t *begin, int size)
 {
 	counter_u64_t *end = (counter_u64_t *)((char *)begin + size);
 
 	for (; begin < end; ++begin)
 		counter_u64_zero(*begin);
 }
 
 static void
 ena_init_io_rings_common(struct ena_adapter *adapter, struct ena_ring *ring,
     uint16_t qid)
 {
 
 	ring->qid = qid;
 	ring->adapter = adapter;
 	ring->ena_dev = adapter->ena_dev;
 }
 
 static int
 ena_init_io_rings(struct ena_adapter *adapter)
 {
 	struct ena_com_dev *ena_dev;
 	struct ena_ring *txr, *rxr;
 	struct ena_que *que;
 	int i;
 	int rc;
 
 	ena_dev = adapter->ena_dev;
 
 	for (i = 0; i < adapter->num_queues; i++) {
 		txr = &adapter->tx_ring[i];
 		rxr = &adapter->rx_ring[i];
 
 		/* TX/RX common ring state */
 		ena_init_io_rings_common(adapter, txr, i);
 		ena_init_io_rings_common(adapter, rxr, i);
 
 		/* TX specific ring state */
 		txr->ring_size = adapter->tx_ring_size;
 		txr->tx_max_header_size = ena_dev->tx_max_header_size;
 		txr->tx_mem_queue_type = ena_dev->tx_mem_queue_type;
 		txr->smoothed_interval =
 		    ena_com_get_nonadaptive_moderation_interval_tx(ena_dev);
 
 		/* Allocate a buf ring */
 		txr->br = buf_ring_alloc(ena_buf_ring_size, M_DEVBUF,
 		    M_WAITOK, &txr->ring_mtx);
 		if (txr->br == NULL) {
 			device_printf(adapter->pdev,
 			    "Error while setting up bufring\n");
 			rc = ENOMEM;
 			goto err_bufr_free;
 		}
 
 		/* Alloc TX statistics. */
 		ena_alloc_counters((counter_u64_t *)&txr->tx_stats,
 		    sizeof(txr->tx_stats));
 
 		/* RX specific ring state */
 		rxr->ring_size = adapter->rx_ring_size;
 		rxr->rx_small_copy_len = adapter->small_copy_len;
 		rxr->smoothed_interval =
 		    ena_com_get_nonadaptive_moderation_interval_rx(ena_dev);
 
 		/* Alloc RX statistics. */
 		ena_alloc_counters((counter_u64_t *)&rxr->rx_stats,
 		    sizeof(rxr->rx_stats));
 
 		/* Initialize locks */
 		snprintf(txr->mtx_name, nitems(txr->mtx_name), "%s:tx(%d)",
 		    device_get_nameunit(adapter->pdev), i);
 		snprintf(rxr->mtx_name, nitems(rxr->mtx_name), "%s:rx(%d)",
 		    device_get_nameunit(adapter->pdev), i);
 
 		mtx_init(&txr->ring_mtx, txr->mtx_name, NULL, MTX_DEF);
 
 		que = &adapter->que[i];
 		que->adapter = adapter;
 		que->id = i;
 		que->tx_ring = txr;
 		que->rx_ring = rxr;
 
 		txr->que = que;
 		rxr->que = que;
 	}
 
 	return 0;
 
 err_bufr_free:
 	while (i--)
 		ena_free_io_ring_resources(adapter, i);
 
 	return (rc);
 }
 
 static void
 ena_free_io_ring_resources(struct ena_adapter *adapter, unsigned int qid)
 {
 	struct ena_ring *txr = &adapter->tx_ring[qid];
 	struct ena_ring *rxr = &adapter->rx_ring[qid];
 
 	ena_free_counters((counter_u64_t *)&txr->tx_stats,
 	    sizeof(txr->tx_stats));
 	ena_free_counters((counter_u64_t *)&rxr->rx_stats,
 	    sizeof(rxr->rx_stats));
 
 	mtx_destroy(&txr->ring_mtx);
 
 	drbr_free(txr->br, M_DEVBUF);
 
 }
 
 static void
 ena_free_all_io_rings_resources(struct ena_adapter *adapter)
 {
 	int i;
 
 	for (i = 0; i < adapter->num_queues; i++)
 		ena_free_io_ring_resources(adapter, i);
 
 }
 
 static int
 ena_setup_tx_dma_tag(struct ena_adapter *adapter)
 {
 	int ret;
 
 	/* Create DMA tag for Tx buffers */
 	ret = bus_dma_tag_create(bus_get_dma_tag(adapter->pdev),
 	    1, 0,				  /* alignment, bounds 	     */
 	    ENA_DMA_BIT_MASK(adapter->dma_width), /* lowaddr of excl window  */
 	    BUS_SPACE_MAXADDR, 			  /* highaddr of excl window */
 	    NULL, NULL,				  /* filter, filterarg 	     */
 	    ENA_TSO_MAXSIZE,			  /* maxsize 		     */
 	    adapter->max_tx_sgl_size - 1,	  /* nsegments 		     */
 	    ENA_TSO_MAXSIZE,			  /* maxsegsize 	     */
 	    0,					  /* flags 		     */
 	    NULL,				  /* lockfunc 		     */
 	    NULL,				  /* lockfuncarg 	     */
 	    &adapter->tx_buf_tag);
 
 	if (ret != 0)
 		device_printf(adapter->pdev, "Unable to create Tx DMA tag\n");
 
 	return (ret);
 }
 
 static int
 ena_free_tx_dma_tag(struct ena_adapter *adapter)
 {
 	int ret;
 
 	ret = bus_dma_tag_destroy(adapter->tx_buf_tag);
 
 	if (ret == 0)
 		adapter->tx_buf_tag = NULL;
 
 	return (ret);
 }
 
 static int
 ena_setup_rx_dma_tag(struct ena_adapter *adapter)
 {
 	int ret;
 
 	/* Create DMA tag for Rx buffers*/
 	ret = bus_dma_tag_create(bus_get_dma_tag(adapter->pdev), /* parent   */
 	    1, 0,				  /* alignment, bounds 	     */
 	    ENA_DMA_BIT_MASK(adapter->dma_width), /* lowaddr of excl window  */
 	    BUS_SPACE_MAXADDR, 			  /* highaddr of excl window */
 	    NULL, NULL,				  /* filter, filterarg 	     */
 	    MJUM16BYTES,			  /* maxsize 		     */
 	    1,					  /* nsegments 		     */
 	    MJUM16BYTES,			  /* maxsegsize 	     */
 	    0,					  /* flags 		     */
 	    NULL,				  /* lockfunc 		     */
 	    NULL,				  /* lockarg 		     */
 	    &adapter->rx_buf_tag);
 
 	if (ret != 0)
 		device_printf(adapter->pdev, "Unable to create Rx DMA tag\n");
 
 	return (ret);
 }
 
 static int
 ena_free_rx_dma_tag(struct ena_adapter *adapter)
 {
 	int ret;
 
 	ret = bus_dma_tag_destroy(adapter->rx_buf_tag);
 
 	if (ret == 0)
 		adapter->rx_buf_tag = NULL;
 
 	return (ret);
 }
 
 
 /**
  * ena_setup_tx_resources - allocate Tx resources (Descriptors)
  * @adapter: network interface device structure
  * @qid: queue index
  *
  * Returns 0 on success, otherwise on failure.
  **/
 static int
 ena_setup_tx_resources(struct ena_adapter *adapter, int qid)
 {
 	struct ena_que *que = &adapter->que[qid];
 	struct ena_ring *tx_ring = que->tx_ring;
 	int size, i, err;
 #ifdef	RSS
 	cpuset_t cpu_mask;
 #endif
 
 	size = sizeof(struct ena_tx_buffer) * tx_ring->ring_size;
 
 	tx_ring->tx_buffer_info = malloc(size, M_DEVBUF, M_NOWAIT | M_ZERO);
 	if (!tx_ring->tx_buffer_info)
 		goto err_tx_buffer_info;
 
 	size = sizeof(uint16_t) * tx_ring->ring_size;
 	tx_ring->free_tx_ids = malloc(size, M_DEVBUF, M_NOWAIT | M_ZERO);
 	if (!tx_ring->free_tx_ids)
 		goto err_tx_reqs;
 
 	/* Req id stack for TX OOO completions */
 	for (i = 0; i < tx_ring->ring_size; i++)
 		tx_ring->free_tx_ids[i] = i;
 
 	/* Reset TX statistics. */
 	ena_reset_counters((counter_u64_t *)&tx_ring->tx_stats,
 	    sizeof(tx_ring->tx_stats));
 
 	tx_ring->next_to_use = 0;
 	tx_ring->next_to_clean = 0;
 
 	/* Make sure that drbr is empty */
 	ENA_RING_MTX_LOCK(tx_ring);
 	drbr_flush(adapter->ifp, tx_ring->br);
 	ENA_RING_MTX_UNLOCK(tx_ring);
 
 	/* ... and create the buffer DMA maps */
 	for (i = 0; i < tx_ring->ring_size; i++) {
 		err = bus_dmamap_create(adapter->tx_buf_tag, 0,
 		    &tx_ring->tx_buffer_info[i].map);
 		if (err != 0) {
 			device_printf(adapter->pdev,
 			    "Unable to create Tx DMA map for buffer %d\n", i);
 			goto err_tx_map;
 		}
 	}
 
 	/* Allocate taskqueues */
 	TASK_INIT(&tx_ring->enqueue_task, 0, ena_deferred_mq_start, tx_ring);
 	tx_ring->enqueue_tq = taskqueue_create_fast("ena_tx_enque", M_NOWAIT,
 	    taskqueue_thread_enqueue, &tx_ring->enqueue_tq);
 	if (tx_ring->enqueue_tq == NULL) {
 		device_printf(adapter->pdev,
 		    "Unable to create taskqueue for enqueue task\n");
 		i = tx_ring->ring_size;
 		goto err_tx_map;
 	}
 
 	/* RSS set cpu for thread */
 #ifdef RSS
 	CPU_SETOF(que->cpu, &cpu_mask);
 	taskqueue_start_threads_cpuset(&tx_ring->enqueue_tq, 1, PI_NET,
 	    &cpu_mask, "%s tx_ring enq (bucket %d)",
 	    device_get_nameunit(adapter->pdev), que->cpu);
 #else /* RSS */
 	taskqueue_start_threads(&tx_ring->enqueue_tq, 1, PI_NET,
 	    "%s txeq %d", device_get_nameunit(adapter->pdev), que->cpu);
 #endif /* RSS */
 
 	return (0);
 
 err_tx_map:
 	while (i--) {
 		bus_dmamap_destroy(adapter->tx_buf_tag,
 		    tx_ring->tx_buffer_info[i].map);
 	}
 	ENA_MEM_FREE(adapter->ena_dev->dmadev, tx_ring->free_tx_ids);
 err_tx_reqs:
 	ENA_MEM_FREE(adapter->ena_dev->dmadev, tx_ring->tx_buffer_info);
 err_tx_buffer_info:
 	return (ENOMEM);
 }
 
 /**
  * ena_free_tx_resources - Free Tx Resources per Queue
  * @adapter: network interface device structure
  * @qid: queue index
  *
  * Free all transmit software resources
  **/
 static void
 ena_free_tx_resources(struct ena_adapter *adapter, int qid)
 {
 	struct ena_ring *tx_ring = &adapter->tx_ring[qid];
 
 	while (taskqueue_cancel(tx_ring->enqueue_tq, &tx_ring->enqueue_task,
 	    NULL))
 		taskqueue_drain(tx_ring->enqueue_tq, &tx_ring->enqueue_task);
 
 	taskqueue_free(tx_ring->enqueue_tq);
 
 	ENA_RING_MTX_LOCK(tx_ring);
 	/* Flush buffer ring, */
 	drbr_flush(adapter->ifp, tx_ring->br);
 
 	/* Free buffer DMA maps, */
 	for (int i = 0; i < tx_ring->ring_size; i++) {
 		m_freem(tx_ring->tx_buffer_info[i].mbuf);
 		tx_ring->tx_buffer_info[i].mbuf = NULL;
 		bus_dmamap_unload(adapter->tx_buf_tag,
 		    tx_ring->tx_buffer_info[i].map);
 		bus_dmamap_destroy(adapter->tx_buf_tag,
 		    tx_ring->tx_buffer_info[i].map);
 	}
 	ENA_RING_MTX_UNLOCK(tx_ring);
 
 	/* And free allocated memory. */
 	ENA_MEM_FREE(adapter->ena_dev->dmadev, tx_ring->tx_buffer_info);
 	tx_ring->tx_buffer_info = NULL;
 
 	ENA_MEM_FREE(adapter->ena_dev->dmadev, tx_ring->free_tx_ids);
 	tx_ring->free_tx_ids = NULL;
 }
 
 /**
  * ena_setup_all_tx_resources - allocate all queues Tx resources
  * @adapter: network interface device structure
  *
  * Returns 0 on success, otherwise on failure.
  **/
 static int
 ena_setup_all_tx_resources(struct ena_adapter *adapter)
 {
 	int i, rc;
 
 	for (i = 0; i < adapter->num_queues; i++) {
 		rc = ena_setup_tx_resources(adapter, i);
 		if (!rc)
 			continue;
 
 		device_printf(adapter->pdev,
 		    "Allocation for Tx Queue %u failed\n", i);
 		goto err_setup_tx;
 	}
 
 	return (0);
 
 err_setup_tx:
 	/* Rewind the index freeing the rings as we go */
 	while (i--)
 		ena_free_tx_resources(adapter, i);
 	return (rc);
 }
 
 /**
  * ena_free_all_tx_resources - Free Tx Resources for All Queues
  * @adapter: network interface device structure
  *
  * Free all transmit software resources
  **/
 static void
 ena_free_all_tx_resources(struct ena_adapter *adapter)
 {
 	int i;
 
 	for (i = 0; i < adapter->num_queues; i++)
 		ena_free_tx_resources(adapter, i);
 
 	return;
 }
 
 /**
  * ena_setup_rx_resources - allocate Rx resources (Descriptors)
  * @adapter: network interface device structure
  * @qid: queue index
  *
  * Returns 0 on success, otherwise on failure.
  **/
 static int
 ena_setup_rx_resources(struct ena_adapter *adapter, unsigned int qid)
 {
 	struct ena_que *que = &adapter->que[qid];
 	struct ena_ring *rx_ring = que->rx_ring;
 	int size, err, i;
 #ifdef	RSS
 	cpuset_t cpu_mask;
 #endif
 
 	size = sizeof(struct ena_rx_buffer) * rx_ring->ring_size;
 
 	/*
 	 * Alloc extra element so in rx path
 	 * we can always prefetch rx_info + 1
 	 */
 	size += sizeof(struct ena_rx_buffer);
 
 	rx_ring->rx_buffer_info = ENA_MEM_ALLOC(adapter->ena_dev->dmadev, size);
 	if (!rx_ring->rx_buffer_info)
 		return (ENOMEM);
 
 	/* Reset RX statistics. */
 	ena_reset_counters((counter_u64_t *)&rx_ring->rx_stats,
 	    sizeof(rx_ring->rx_stats));
 
 	rx_ring->next_to_clean = 0;
 	rx_ring->next_to_use = 0;
 
 	/* ... and create the buffer DMA maps */
 	for (i = 0; i < rx_ring->ring_size; i++) {
 		err = bus_dmamap_create(adapter->rx_buf_tag, 0,
 		    &(rx_ring->rx_buffer_info[i].map));
 		if (err != 0) {
 			device_printf(adapter->pdev,
 			    "Unable to create Rx DMA map for buffer %d\n", i);
 			goto err_rx_dma;
 		}
 	}
 
 	/* Create LRO for the ring */
 	if (adapter->ifp->if_capenable & IFCAP_LRO) {
 		int err = tcp_lro_init(&rx_ring->lro);
 		if (err) {
 			device_printf(adapter->pdev,
 			    "LRO[%d] Initialization failed!\n", qid);
 		} else {
 			ena_trace(ENA_INFO,
 			    "RX Soft LRO[%d] Initialized\n", qid);
 			rx_ring->lro.ifp = adapter->ifp;
 		}
 	}
 
 	return (0);
 
 err_rx_dma:
 	while (i--) {
 		bus_dmamap_destroy(adapter->rx_buf_tag,
 		    rx_ring->rx_buffer_info[i].map);
 	}
 
 	ENA_MEM_FREE(adapter->ena_dev->dmadev, rx_ring->rx_buffer_info);
 	rx_ring->rx_buffer_info = NULL;
 	ena_trace(ENA_ALERT, "RX resource allocation fail");
 	return (ENOMEM);
 }
 
 /**
  * ena_free_rx_resources - Free Rx Resources
  * @adapter: network interface device structure
  * @qid: queue index
  *
  * Free all receive software resources
  **/
 static void
 ena_free_rx_resources(struct ena_adapter *adapter, unsigned int qid)
 {
 	struct ena_ring *rx_ring = &adapter->rx_ring[qid];
 
 	ena_trace(ENA_INFO, "%s qid %d\n", __func__, qid);
 
 	/* Free buffer DMA maps, */
 	for (int i = 0; i < rx_ring->ring_size; i++) {
 		m_freem(rx_ring->rx_buffer_info[i].mbuf);
 		rx_ring->rx_buffer_info[i].mbuf = NULL;
 		bus_dmamap_unload(adapter->rx_buf_tag,
 		    rx_ring->rx_buffer_info[i].map);
 		bus_dmamap_destroy(adapter->rx_buf_tag,
 		    rx_ring->rx_buffer_info[i].map);
 	}
 
 	/* free LRO resources, */
 	tcp_lro_free(&rx_ring->lro);
 
 	/* free allocated memory */
 	ENA_MEM_FREE(adapter->ena_dev->dmadev, rx_ring->rx_buffer_info);
 	rx_ring->rx_buffer_info = NULL;
 
 	return;
 }
 
 /**
  * ena_setup_all_rx_resources - allocate all queues Rx resources
  * @adapter: network interface device structure
  *
  * Returns 0 on success, otherwise on failure.
  **/
 static int
 ena_setup_all_rx_resources(struct ena_adapter *adapter)
 {
 	int i, rc = 0;
 
 	for (i = 0; i < adapter->num_queues; i++) {
 		rc = ena_setup_rx_resources(adapter, i);
 		if (!rc)
 			continue;
 
 		device_printf(adapter->pdev,
 		    "Allocation for Rx Queue %u failed\n", i);
 		goto err_setup_rx;
 	}
 	return (0);
 
 err_setup_rx:
 	/* rewind the index freeing the rings as we go */
 	while (i--)
 		ena_free_rx_resources(adapter, i);
 	return (rc);
 }
 
 /**
  * ena_free_all_rx_resources - Free Rx resources for all queues
  * @adapter: network interface device structure
  *
  * Free all receive software resources
  **/
 static void
 ena_free_all_rx_resources(struct ena_adapter *adapter)
 {
 	int i;
 
 	for (i = 0; i < adapter->num_queues; i++)
 		ena_free_rx_resources(adapter, i);
 
 	return;
 }
 
 static inline int
 ena_alloc_rx_mbuf(struct ena_adapter *adapter,
     struct ena_ring *rx_ring, struct ena_rx_buffer *rx_info)
 {
 	struct ena_com_buf *ena_buf;
 	bus_dma_segment_t segs[1];
 	int nsegs, error;
 
 	/* if previous allocated frag is not used */
 	if (rx_info->mbuf != NULL)
 		return (0);
 
 	/* Get mbuf using UMA allocator */
 	rx_info->mbuf = m_getjcl(M_NOWAIT, MT_DATA, M_PKTHDR, MJUM16BYTES);
 
 	if (!rx_info->mbuf) {
 		counter_u64_add(rx_ring->rx_stats.mbuf_alloc_fail, 1);
 		return (ENOMEM);
 	}
 	/* Set mbuf length*/
 	rx_info->mbuf->m_pkthdr.len = rx_info->mbuf->m_len = MJUM16BYTES;
 
 	/* Map packets for DMA */
 	ena_trace(ENA_DBG | ENA_RSC | ENA_RXPTH,
 	    "Using tag %p for buffers' DMA mapping, mbuf %p len: %d",
 	    adapter->rx_buf_tag,rx_info->mbuf, rx_info->mbuf->m_len);
 	error = bus_dmamap_load_mbuf_sg(adapter->rx_buf_tag, rx_info->map,
 	    rx_info->mbuf, segs, &nsegs, BUS_DMA_NOWAIT);
 	if (error || (nsegs != 1)) {
 		device_printf(adapter->pdev, "failed to map mbuf, error: %d, "
 		    "nsegs: %d\n", error, nsegs);
 		counter_u64_add(rx_ring->rx_stats.dma_mapping_err, 1);
 		goto exit;
 
 	}
 
 	bus_dmamap_sync(adapter->rx_buf_tag, rx_info->map, BUS_DMASYNC_PREREAD);
 
 	ena_buf = &rx_info->ena_buf;
 	ena_buf->paddr = segs[0].ds_addr;
 	ena_buf->len = MJUM16BYTES;
 
 	ena_trace(ENA_DBG | ENA_RSC | ENA_RXPTH,
 	    "ALLOC RX BUF: mbuf %p, rx_info %p, len %d, paddr %#jx\n",
 	    rx_info->mbuf, rx_info,ena_buf->len, (uintmax_t)ena_buf->paddr);
 
 	return (0);
 
 exit:
 	m_freem(rx_info->mbuf);
 	rx_info->mbuf = NULL;
 	return (EFAULT);
 }
 
 static void
 ena_free_rx_mbuf(struct ena_adapter *adapter, struct ena_ring *rx_ring,
     struct ena_rx_buffer *rx_info)
 {
 
 	if (!rx_info->mbuf)
 		return;
 
 	bus_dmamap_unload(adapter->rx_buf_tag, rx_info->map);
 	m_freem(rx_info->mbuf);
 	rx_info->mbuf = NULL;
 
 	return;
 }
 
 
 /**
  * ena_refill_rx_bufs - Refills ring with descriptors
  * @rx_ring: the ring which we want to feed with free descriptors
  * @num: number of descriptors to refill
  * Refills the ring with newly allocated DMA-mapped mbufs for receiving
  **/
 static int
 ena_refill_rx_bufs(struct ena_ring *rx_ring, uint32_t num)
 {
 	struct ena_adapter *adapter = rx_ring->adapter;
 	uint16_t next_to_use;
 	uint32_t i;
 	int rc;
 
 	ena_trace(ENA_DBG | ENA_RXPTH | ENA_RSC, "refill qid: %d",
 	    rx_ring->qid);
 
 	next_to_use = rx_ring->next_to_use;
 
 	for (i = 0; i < num; i++) {
 		ena_trace(ENA_DBG | ENA_RXPTH | ENA_RSC,
 		    "RX buffer - next to use: %d", next_to_use);
 
 		struct ena_rx_buffer *rx_info =
 		    &rx_ring->rx_buffer_info[next_to_use];
 
 		rc = ena_alloc_rx_mbuf(adapter, rx_ring, rx_info);
 		if (rc != 0) {
 			device_printf(adapter->pdev,
 			    "failed to alloc buffer for rx queue\n");
 			break;
 		}
 		rc = ena_com_add_single_rx_desc(rx_ring->ena_com_io_sq,
 		    &rx_info->ena_buf, next_to_use);
 		if (unlikely(rc)) {
 			device_printf(adapter->pdev,
 			    "failed to add buffer for rx queue %d\n",
 			    rx_ring->qid);
 			break;
 		}
 		next_to_use = ENA_RX_RING_IDX_NEXT(next_to_use,
 		    rx_ring->ring_size);
 	}
 
 	if (i < num) {
 		counter_u64_add(rx_ring->rx_stats.refil_partial, 1);
 		device_printf(adapter->pdev,
 		    "refilled rx queue %d with %d pages only\n",
 		    rx_ring->qid, i);
 	}
 
 	if (i != 0) {
 		wmb();
 		ena_com_write_sq_doorbell(rx_ring->ena_com_io_sq);
 	}
 	rx_ring->next_to_use = next_to_use;
 	return (i);
 }
 
 static void
 ena_free_rx_bufs(struct ena_adapter *adapter, unsigned int qid)
 {
 	struct ena_ring *rx_ring = &adapter->rx_ring[qid];
 	unsigned int i;
 
 	for (i = 0; i < rx_ring->ring_size; i++) {
 		struct ena_rx_buffer *rx_info = &rx_ring->rx_buffer_info[i];
 
 		if (rx_info->mbuf)
 			ena_free_rx_mbuf(adapter, rx_ring, rx_info);
 	}
 
 	return;
 }
 
 /**
  * ena_refill_all_rx_bufs - allocate all queues Rx buffers
  * @adapter: network interface device structure
  *
  */
 static void
 ena_refill_all_rx_bufs(struct ena_adapter *adapter)
 {
 	struct ena_ring *rx_ring;
 	int i, rc, bufs_num;
 
 	for (i = 0; i < adapter->num_queues; i++) {
 		rx_ring = &adapter->rx_ring[i];
 		bufs_num = rx_ring->ring_size - 1;
 		rc = ena_refill_rx_bufs(rx_ring, bufs_num);
 
 		if (unlikely(rc != bufs_num))
 			device_printf(adapter->pdev,
 			    "refilling Queue %d failed. allocated %d buffers"
 			    " from: %d\n", i, rc, bufs_num);
 	}
 }
 
 static void
 ena_free_all_rx_bufs(struct ena_adapter *adapter)
 {
 	int i;
 
 	for (i = 0; i < adapter->num_queues; i++)
 		ena_free_rx_bufs(adapter, i);
 	return;
 }
 
 /**
  * ena_free_tx_bufs - Free Tx Buffers per Queue
  * @adapter: network interface device structure
  * @qid: queue index
  **/
 static void
 ena_free_tx_bufs(struct ena_adapter *adapter, unsigned int qid)
 {
 	struct ena_ring *tx_ring = &adapter->tx_ring[qid];
 
 	ENA_RING_MTX_LOCK(tx_ring);
 	for (int i = 0; i < tx_ring->ring_size; i++) {
 		struct ena_tx_buffer *tx_info = &tx_ring->tx_buffer_info[i];
 
 		if (tx_info->mbuf == NULL)
 			continue;
 
 		ena_trace(ENA_DBG | ENA_TXPTH | ENA_RSC,
 		    "free uncompleted Tx mbufs qid[%d] idx: 0x%x", qid, i);
 
 		bus_dmamap_unload(adapter->tx_buf_tag, tx_info->map);
 		m_free(tx_info->mbuf);
 		tx_info->mbuf = NULL;
 	}
 	ENA_RING_MTX_UNLOCK(tx_ring);
 
 	return;
 }
 
 static void
 ena_free_all_tx_bufs(struct ena_adapter *adapter)
 {
 
 	for (int i = 0; i < adapter->num_queues; i++)
 		ena_free_tx_bufs(adapter, i);
 
 	return;
 }
 
 static void
 ena_destroy_all_tx_queues(struct ena_adapter *adapter)
 {
 	uint16_t ena_qid;
 	int i;
 
 	for (i = 0; i < adapter->num_queues; i++) {
 		ena_qid = ENA_IO_TXQ_IDX(i);
 		ena_com_destroy_io_queue(adapter->ena_dev, ena_qid);
 	}
 }
 
 static void
 ena_destroy_all_rx_queues(struct ena_adapter *adapter)
 {
 	uint16_t ena_qid;
 	int i;
 
 	for (i = 0; i < adapter->num_queues; i++) {
 		ena_qid = ENA_IO_RXQ_IDX(i);
 		ena_com_destroy_io_queue(adapter->ena_dev, ena_qid);
 	}
 }
 
 static void
 ena_destroy_all_io_queues(struct ena_adapter *adapter)
 {
 	ena_destroy_all_tx_queues(adapter);
 	ena_destroy_all_rx_queues(adapter);
 }
 
 static int
 validate_tx_req_id(struct ena_ring *tx_ring, uint16_t req_id)
 {
 	struct ena_tx_buffer *tx_info = NULL;
 
 	if (likely(req_id < tx_ring->ring_size)) {
 		tx_info = &tx_ring->tx_buffer_info[req_id];
 		if (tx_info->mbuf)
 			return 0;
 	}
 
 	counter_u64_add(tx_ring->tx_stats.bad_req_id, 1);
 
 	return (EFAULT);
 }
 
 static int
 ena_create_io_queues(struct ena_adapter *adapter)
 {
 	struct ena_com_dev *ena_dev = adapter->ena_dev;
 	struct ena_com_create_io_ctx ctx;
 	struct ena_ring *ring;
 	uint16_t ena_qid;
 	uint32_t msix_vector;
 	int rc, i;
 
 	/* Create TX queues */
 	for (i = 0; i < adapter->num_queues; i++) {
 		msix_vector = ENA_IO_IRQ_IDX(i);
 		ena_qid = ENA_IO_TXQ_IDX(i);
 		ctx.mem_queue_type = ena_dev->tx_mem_queue_type;
 		ctx.direction = ENA_COM_IO_QUEUE_DIRECTION_TX;
 		ctx.queue_size = adapter->tx_ring_size;
 		ctx.msix_vector = msix_vector;
 		ctx.qid = ena_qid;
 		rc = ena_com_create_io_queue(ena_dev, &ctx);
 		if (rc) {
 			device_printf(adapter->pdev,
 			    "Failed to create io TX queue #%d rc: %d\n", i, rc);
 			goto err_tx;
 		}
 		ring = &adapter->tx_ring[i];
 		rc = ena_com_get_io_handlers(ena_dev, ena_qid,
 		    &ring->ena_com_io_sq,
 		    &ring->ena_com_io_cq);
 		if (rc) {
 			device_printf(adapter->pdev,
 			    "Failed to get TX queue handlers. TX queue num"
 			    " %d rc: %d\n", i, rc);
 			ena_com_destroy_io_queue(ena_dev, ena_qid);
 			goto err_tx;
 		}
 	}
 
 	/* Create RX queues */
 	for (i = 0; i < adapter->num_queues; i++) {
 		msix_vector = ENA_IO_IRQ_IDX(i);
 		ena_qid = ENA_IO_RXQ_IDX(i);
 		ctx.mem_queue_type = ENA_ADMIN_PLACEMENT_POLICY_HOST;
 		ctx.direction = ENA_COM_IO_QUEUE_DIRECTION_RX;
 		ctx.queue_size = adapter->rx_ring_size;
 		ctx.msix_vector = msix_vector;
 		ctx.qid = ena_qid;
 		rc = ena_com_create_io_queue(ena_dev, &ctx);
 		if (rc) {
 			device_printf(adapter->pdev,
 			    "Failed to create io RX queue[%d] rc: %d\n", i, rc);
 			goto err_rx;
 		}
 
 		ring = &adapter->rx_ring[i];
 		rc = ena_com_get_io_handlers(ena_dev, ena_qid,
 		    &ring->ena_com_io_sq,
 		    &ring->ena_com_io_cq);
 		if (rc) {
 			device_printf(adapter->pdev,
 			    "Failed to get RX queue handlers. RX queue num"
 			    " %d rc: %d\n", i, rc);
 			ena_com_destroy_io_queue(ena_dev, ena_qid);
 			goto err_rx;
 		}
 	}
 
 	return (0);
 
 err_rx:
 	while (i--)
 		ena_com_destroy_io_queue(ena_dev, ENA_IO_RXQ_IDX(i));
 	i = adapter->num_queues;
 err_tx:
 	while (i--)
 		ena_com_destroy_io_queue(ena_dev, ENA_IO_TXQ_IDX(i));
 
 	return (ENXIO);
 }
 
 /**
  * ena_tx_cleanup - clear sent packets and corresponding descriptors
  * @tx_ring: ring for which we want to clean packets
  *
  * Once packets are sent, we ask the device in a loop for no longer used
  * descriptors. We find the related mbuf chain in a map (index in an array)
  * and free it, then update ring state.
  * This is performed in "endless" loop, updating ring pointers every
  * TX_COMMIT. The first check of free descriptor is performed before the actual
  * loop, then repeated at the loop end.
  **/
 static int
 ena_tx_cleanup(struct ena_ring *tx_ring)
 {
 	struct ena_adapter *adapter;
 	struct ena_com_io_cq* io_cq;
 	uint16_t next_to_clean;
 	uint16_t req_id;
 	uint16_t ena_qid;
 	unsigned int total_done = 0;
 	int rc;
 	int commit = TX_COMMIT;
 	int budget = TX_BUDGET;
 	int work_done;
 
 	adapter = tx_ring->que->adapter;
 	ena_qid = ENA_IO_TXQ_IDX(tx_ring->que->id);
 	io_cq = &adapter->ena_dev->io_cq_queues[ena_qid];
 	next_to_clean = tx_ring->next_to_clean;
 
 	do {
 		struct ena_tx_buffer *tx_info;
 		struct mbuf *mbuf;
 
 		rc = ena_com_tx_comp_req_id_get(io_cq, &req_id);
 		if (rc != 0)
 			break;
 
 		rc = validate_tx_req_id(tx_ring, req_id);
 		if (rc)
 			break;
 
 		tx_info = &tx_ring->tx_buffer_info[req_id];
 
 		mbuf = tx_info->mbuf;
 
 		tx_info->mbuf = NULL;
 		bintime_clear(&tx_info->timestamp);
 
 		if (tx_info->num_of_bufs != 0) {
 			/* Map is no longer required */
 			bus_dmamap_unload(adapter->tx_buf_tag, tx_info->map);
 		}
 
 		m_freem(mbuf);
 
 		total_done += tx_info->tx_descs;
 
 		tx_ring->free_tx_ids[next_to_clean] = req_id;
 		next_to_clean = ENA_TX_RING_IDX_NEXT(next_to_clean,
 		    tx_ring->ring_size);
 
 		if (--commit == 0) {
 			commit = TX_COMMIT;
 			/* update ring state every TX_COMMIT descriptor */
 			tx_ring->next_to_clean = next_to_clean;
 			ena_com_comp_ack(&adapter->ena_dev->io_sq_queues[ena_qid], total_done);
 			ena_com_update_dev_comp_head(io_cq);
 			total_done = 0;
 		}
 	} while (--budget);
 
 	work_done = TX_BUDGET - budget;
 
 	/* If there is still something to commit update ring state */
 	if (commit != TX_COMMIT) {
 		tx_ring->next_to_clean = next_to_clean;
 		ena_com_comp_ack(&adapter->ena_dev->io_sq_queues[ena_qid], total_done);
 		ena_com_update_dev_comp_head(io_cq);
 	}
 
 	taskqueue_enqueue(tx_ring->enqueue_tq, &tx_ring->enqueue_task);
 
 	return (work_done);
 }
 
 static void
 ena_rx_hash_mbuf(struct ena_ring *rx_ring, struct ena_com_rx_ctx *ena_rx_ctx,
     struct mbuf *mbuf)
 {
 	struct ena_adapter *adapter = rx_ring->adapter;
 
 	if (adapter->rss_support) {
 		mbuf->m_pkthdr.flowid = ena_rx_ctx->hash;
 
 		if (ena_rx_ctx->frag &&
 		    ena_rx_ctx->l3_proto != ENA_ETH_IO_L4_PROTO_UNKNOWN) {
 			M_HASHTYPE_SET(mbuf, M_HASHTYPE_OPAQUE_HASH);
 			return;
 		}
 
 		switch (ena_rx_ctx->l3_proto) {
 		case ENA_ETH_IO_L3_PROTO_IPV4:
 			switch (ena_rx_ctx->l4_proto) {
 			case ENA_ETH_IO_L4_PROTO_TCP:
 				M_HASHTYPE_SET(mbuf, M_HASHTYPE_RSS_TCP_IPV4);
 				break;
 			case ENA_ETH_IO_L4_PROTO_UDP:
 				M_HASHTYPE_SET(mbuf, M_HASHTYPE_RSS_UDP_IPV4);
 				break;
 			default:
 				M_HASHTYPE_SET(mbuf, M_HASHTYPE_RSS_IPV4);
 			}
 			break;
 		case ENA_ETH_IO_L3_PROTO_IPV6:
 			switch (ena_rx_ctx->l4_proto) {
 			case ENA_ETH_IO_L4_PROTO_TCP:
 				M_HASHTYPE_SET(mbuf, M_HASHTYPE_RSS_TCP_IPV6);
 				break;
 			case ENA_ETH_IO_L4_PROTO_UDP:
 				M_HASHTYPE_SET(mbuf, M_HASHTYPE_RSS_UDP_IPV6);
 				break;
 			default:
 				M_HASHTYPE_SET(mbuf, M_HASHTYPE_RSS_IPV6);
 			}
 			break;
 		case ENA_ETH_IO_L3_PROTO_UNKNOWN:
 			M_HASHTYPE_SET(mbuf, M_HASHTYPE_NONE);
 			break;
 		default:
 			M_HASHTYPE_SET(mbuf, M_HASHTYPE_OPAQUE_HASH);
 		}
 	} else {
 		mbuf->m_pkthdr.flowid = rx_ring->qid;
 		M_HASHTYPE_SET(mbuf, M_HASHTYPE_NONE);
 	}
 }
 
 /**
  * ena_rx_mbuf - assemble mbuf from descriptors
  * @rx_ring: ring for which we want to clean packets
  * @ena_bufs: buffer info
  * @ena_rx_ctx: metadata for this packet(s)
  * @next_to_clean: ring pointer
  *
  **/
 static struct mbuf*
 ena_rx_mbuf(struct ena_ring *rx_ring, struct ena_com_rx_buf_info *ena_bufs,
     struct ena_com_rx_ctx *ena_rx_ctx, uint16_t *next_to_clean)
 {
 	struct mbuf *mbuf;
 	struct ena_rx_buffer *rx_info;
 	struct ena_adapter *adapter;
 	unsigned int len, buf = 0;
 	unsigned int descs = ena_rx_ctx->descs;
 
 	adapter = rx_ring->adapter;
 	rx_info = &rx_ring->rx_buffer_info[*next_to_clean];
 
 	ENA_ASSERT(rx_info->mbuf, "Invalid alloc frag buffer\n");
 
 	len = ena_bufs[0].len;
 	ena_trace(ENA_DBG | ENA_RXPTH, "rx_info %p, mbuf %p, paddr %jx",
 	    rx_info, rx_info->mbuf, (uintmax_t)rx_info->ena_buf.paddr);
 
 	mbuf = rx_info->mbuf;
 	mbuf->m_flags |= M_PKTHDR;
 	mbuf->m_pkthdr.len = len;
 	mbuf->m_len = len;
 	mbuf->m_pkthdr.rcvif = rx_ring->que->adapter->ifp;
 
 	/* Fill mbuf with hash key and it's interpretation for optimization */
 	ena_rx_hash_mbuf(rx_ring, ena_rx_ctx, mbuf);
 
 	ena_trace(ENA_DBG | ENA_RXPTH, "rx mbuf 0x%p, flags=0x%x, len: %d",
 	    mbuf, mbuf->m_flags, mbuf->m_pkthdr.len);
 
 	/* DMA address is not needed anymore, unmap it */
 	bus_dmamap_unload(rx_ring->adapter->rx_buf_tag, rx_info->map);
 
 	rx_info->mbuf = NULL;
 	*next_to_clean = ENA_RX_RING_IDX_NEXT(*next_to_clean,
 	    rx_ring->ring_size);
 
 	/*
 	 * While we have more than 1 descriptors for one rcvd packet, append
 	 * other mbufs to the main one
 	 */
 	while (--descs) {
 		rx_info = &rx_ring->rx_buffer_info[*next_to_clean];
 		len = ena_bufs[++buf].len;
 
 		if (!m_append(mbuf, len, rx_info->mbuf->m_data)) {
 			counter_u64_add(rx_ring->rx_stats.mbuf_alloc_fail, 1);
 			ena_trace(ENA_WARNING, "Failed to append Rx mbuf %p",
 			    mbuf);
 		}
 		/* Free already appended mbuf, it won't be useful anymore */
 		bus_dmamap_unload(rx_ring->adapter->rx_buf_tag, rx_info->map);
 		m_freem(rx_info->mbuf);
 		rx_info->mbuf = NULL;
 
 		*next_to_clean = ENA_RX_RING_IDX_NEXT(*next_to_clean,
 		    rx_ring->ring_size);
 	}
 
 	return (mbuf);
 }
 
 /**
  * ena_rx_checksum - indicate in mbuf if hw indicated a good cksum
  **/
 static inline void
 ena_rx_checksum(struct ena_ring *rx_ring, struct ena_com_rx_ctx *ena_rx_ctx,
     struct mbuf *mbuf)
 {
 
 	/* if IP and error */
 	if ((ena_rx_ctx->l3_proto == ENA_ETH_IO_L3_PROTO_IPV4) &&
 	    (ena_rx_ctx->l3_csum_err)) {
 		/* ipv4 checksum error */
 		mbuf->m_pkthdr.csum_flags = 0;
 		counter_u64_add(rx_ring->rx_stats.bad_csum, 1);
 		return;
 	}
 
 	/* if TCP/UDP */
 	if ((ena_rx_ctx->l4_proto == ENA_ETH_IO_L4_PROTO_TCP) ||
 	    (ena_rx_ctx->l4_proto == ENA_ETH_IO_L4_PROTO_UDP)) {
 		if (ena_rx_ctx->l4_csum_err) {
 			/* TCP/UDP checksum error */
 			mbuf->m_pkthdr.csum_flags = 0;
 			counter_u64_add(rx_ring->rx_stats.bad_csum, 1);
 		} else {
 			mbuf->m_pkthdr.csum_flags = CSUM_IP_CHECKED;
 			mbuf->m_pkthdr.csum_flags |= CSUM_IP_VALID;
 		}
 	}
 
 	return;
 }
 
 /**
  * ena_rx_cleanup - handle rx irq
  * @arg: ring for which irq is being handled
  **/
 static int
 ena_rx_cleanup(struct ena_ring *rx_ring)
 {
 	struct ena_adapter *adapter;
 	struct mbuf *mbuf;
 	struct ena_com_rx_ctx ena_rx_ctx;
 	struct ena_com_io_cq* io_cq;
 	struct ena_com_io_sq* io_sq;
 	/* struct ena_eth_io_intr_reg intr_reg; */
 	if_t ifp;
 	uint16_t ena_qid;
 	uint16_t next_to_clean;
 	uint32_t refill_required;
 	uint32_t refill_threshold;
 	uint32_t do_if_input = 0;
 	unsigned int qid;
 	int rc;
 	int budget = RX_BUDGET;
 
 	adapter = rx_ring->que->adapter;
 	ifp = adapter->ifp;
 	qid = rx_ring->que->id;
 	ena_qid = ENA_IO_RXQ_IDX(qid);
 	io_cq = &adapter->ena_dev->io_cq_queues[ena_qid];
 	io_sq = &adapter->ena_dev->io_sq_queues[ena_qid];
 	next_to_clean = rx_ring->next_to_clean;
 
 	do {
 		ena_rx_ctx.ena_bufs = rx_ring->ena_bufs;
 		ena_rx_ctx.max_bufs = adapter->max_rx_sgl_size;
 		ena_rx_ctx.descs = 0;
 		rc = ena_com_rx_pkt(io_cq, io_sq, &ena_rx_ctx);
 
 		if (unlikely(rc))
 			goto error;
 
 		if (unlikely(ena_rx_ctx.descs == 0))
 			break;
 
 		/* Receive mbuf from the ring */
 		mbuf = ena_rx_mbuf(rx_ring, rx_ring->ena_bufs,
 		    &ena_rx_ctx, &next_to_clean);
 
 		/* Exit if we failed to retrieve a buffer */
 		if (unlikely(!mbuf)) {
 			next_to_clean = ENA_RX_RING_IDX_ADD(next_to_clean,
 			    ena_rx_ctx.descs, rx_ring->ring_size);
 			break;
 		}
 		ena_trace(ENA_DBG | ENA_RXPTH, "Rx: %d bytes",
 		    mbuf->m_pkthdr.len);
 
 		if ((ifp->if_capenable & IFCAP_RXCSUM) ||
 		    (ifp->if_capenable & IFCAP_RXCSUM_IPV6)) {
 			ena_rx_checksum(rx_ring, &ena_rx_ctx, mbuf);
 		}
 
-		counter_u64_add(rx_ring->rx_stats.bytes, mbuf->m_pkthdr.len);
+		counter_enter();
+		counter_u64_add_protected(rx_ring->rx_stats.bytes,
+		    mbuf->m_pkthdr.len);
+		counter_u64_add_protected(adapter->hw_stats.rx_bytes,
+		    mbuf->m_pkthdr.len);
+		counter_exit();
 		/*
 		 * LRO is only for IP/TCP packets and TCP checksum of the packet
 		 * should be computed by hardware.
 		 */
 		do_if_input = 1;
 		if ((ifp->if_capenable & IFCAP_LRO) &&
 		    (mbuf->m_pkthdr.csum_flags & CSUM_IP_VALID) &&
 		    ena_rx_ctx.l4_proto == ENA_ETH_IO_L4_PROTO_TCP) {
 			/*
 			 * Send to the stack if:
 			 *  - LRO not enabled, or
 			 *  - no LRO resources, or
 			 *  - lro enqueue fails
 			 */
 			if (rx_ring->lro.lro_cnt != 0 &&
 			    tcp_lro_rx(&rx_ring->lro, mbuf, 0) == 0)
 					do_if_input = 0;
 		}
 		if (do_if_input) {
 			ena_trace(ENA_DBG | ENA_RXPTH, "calling if_input() with mbuf %p",
 			    mbuf);
 			(*ifp->if_input)(ifp, mbuf);
 		}
 
-		counter_u64_add(rx_ring->rx_stats.cnt, 1);
+		counter_enter();
+		counter_u64_add_protected(rx_ring->rx_stats.cnt, 1);
+		counter_u64_add_protected(adapter->hw_stats.rx_packets, 1);
+		counter_exit();
 	} while (--budget);
 
 	rx_ring->next_to_clean = next_to_clean;
 
 	refill_required = ena_com_free_desc(io_sq);
 	refill_threshold = rx_ring->ring_size / ENA_RX_REFILL_THRESH_DEVIDER;
 
 	if (refill_required > refill_threshold) {
 		ena_com_update_dev_comp_head(rx_ring->ena_com_io_cq);
 		ena_refill_rx_bufs(rx_ring, refill_required);
 	}
 
 	tcp_lro_flush_all(&rx_ring->lro);
 
 	return (RX_BUDGET - budget);
 
 error:
 	counter_u64_add(rx_ring->rx_stats.bad_desc_num, 1);
 	return (RX_BUDGET - budget);
 }
 
 /*********************************************************************
  *
  *  MSIX & Interrupt Service routine
  *
  **********************************************************************/
 
 /**
  * ena_handle_msix - MSIX Interrupt Handler for admin/async queue
  * @arg: interrupt number
  **/
 static void
 ena_intr_msix_mgmnt(void *arg)
 {
 	struct ena_adapter *adapter = (struct ena_adapter *)arg;
 
 	ena_com_admin_q_comp_intr_handler(adapter->ena_dev);
 	if (likely(adapter->running))
 		ena_com_aenq_intr_handler(adapter->ena_dev, arg);
 }
 
 /**
  * ena_handle_msix - MSIX Interrupt Handler for Tx/Rx
  * @arg: interrupt number
  **/
 static void
 ena_handle_msix(void *arg)
 {
 	struct ena_que	*que = arg;
 	struct ena_adapter *adapter = que->adapter;
 	if_t ifp = adapter->ifp;
 	struct ena_ring *tx_ring;
 	struct ena_ring *rx_ring;
 	struct ena_com_io_cq* io_cq;
 	struct ena_eth_io_intr_reg intr_reg;
 	int qid, ena_qid;
 	int txc, rxc, i;
 
 	if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0)
 		return;
 
 	ena_trace(ENA_DBG, "MSI-X TX/RX routine");
 
 	tx_ring = que->tx_ring;
 	rx_ring = que->rx_ring;
 	qid = que->id;
 	ena_qid = ENA_IO_TXQ_IDX(qid);
 	io_cq = &adapter->ena_dev->io_cq_queues[ena_qid];
 
 	for (i = 0; i < CLEAN_BUDGET; ++i) {
 		rxc = ena_rx_cleanup(rx_ring);
 
 		/* Protection from calling ena_tx_cleanup from ena_start_xmit */
 		ENA_RING_MTX_LOCK(tx_ring);
 		txc = ena_tx_cleanup(tx_ring);
 		ENA_RING_MTX_UNLOCK(tx_ring);
 
 		if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0)
 			return;
 
 		if (txc != TX_BUDGET && rxc != RX_BUDGET)
 		       break;
 	}
 
 	/* Signal that work is done and unmask interrupt */
 	ena_com_update_intr_reg(&intr_reg,
 	    RX_IRQ_INTERVAL,
 	    TX_IRQ_INTERVAL,
 	    true);
 	ena_com_unmask_intr(io_cq, &intr_reg);
 }
 
 static int
 ena_enable_msix(struct ena_adapter *adapter)
 {
 	device_t dev = adapter->pdev;
 	int i, msix_vecs, rc = 0;
 
 	/* Reserved the max msix vectors we might need */
 	msix_vecs = ENA_MAX_MSIX_VEC(adapter->num_queues);
 
 	adapter->msix_entries = ENA_MEM_ALLOC(adapter->ena_dev->dmadev,
 	    msix_vecs * sizeof(struct msix_entry));
 	if (!adapter->msix_entries) {
 		device_printf(dev,
 		    "Failed to allocate msix_entries, vectors %d\n", msix_vecs);
 		rc = ENOMEM;
 		goto error;
 	}
 	device_printf(dev, "Allocated msix_entries, vectors (cnt: %d)\n",
 	    msix_vecs);
 
 	for (i = 0; i < msix_vecs; i++) {
 		adapter->msix_entries[i].entry = i;
 		/* Vectors must start from 1 */
 		adapter->msix_entries[i].vector = i + 1;
 	}
 
 	rc = pci_alloc_msix(dev, &msix_vecs);
 	if (rc != 0) {
 		device_printf(dev,
 		    "Failed to enable MSIX, vectors %d rc %d\n", msix_vecs, rc);
 		ENA_MEM_FREE(adapter->ena_dev->dmadev, adapter->msix_entries);
 		adapter->msix_entries = NULL;
 		rc = ENOSPC;
 		goto error;
 	}
 
 	adapter->msix_vecs = msix_vecs;
 	adapter->msix_enabled = true;
 
 error:
 	return (rc);
 }
 
 static void
 ena_setup_mgmnt_intr(struct ena_adapter *adapter)
 {
 
 	snprintf(adapter->irq_tbl[ENA_MGMNT_IRQ_IDX].name,
 	    ENA_IRQNAME_SIZE, "ena-mgmnt@pci:%s",
 	    device_get_nameunit(adapter->pdev));
 	/*
 	 * Handler is NULL on purpose, it will be set
 	 * when mgmnt interrupt is acquired
 	 */
 	adapter->irq_tbl[ENA_MGMNT_IRQ_IDX].handler = NULL;
 	adapter->irq_tbl[ENA_MGMNT_IRQ_IDX].data = adapter;
 	adapter->irq_tbl[ENA_MGMNT_IRQ_IDX].vector =
 	    adapter->msix_entries[ENA_MGMNT_IRQ_IDX].vector;
 
 	return;
 }
 
 static void
 ena_setup_io_intr(struct ena_adapter *adapter)
 {
 	static int last_bind_cpu = -1;
 	int irq_idx;
 	ena_trace(ENA_DBG, "enter");
 
 	for (int i = 0; i < adapter->num_queues; i++) {
 		irq_idx = ENA_IO_IRQ_IDX(i);
 
 		snprintf(adapter->irq_tbl[irq_idx].name, ENA_IRQNAME_SIZE,
 		    "%s-TxRx-%d", device_get_nameunit(adapter->pdev), i);
 		adapter->irq_tbl[irq_idx].handler = ena_handle_msix;
 		adapter->irq_tbl[irq_idx].data = &adapter->que[i];
 		adapter->irq_tbl[irq_idx].vector =
 		    adapter->msix_entries[irq_idx].vector;
 		ena_trace(ENA_INFO | ENA_IOQ, "ena_setup_io_intr vector: %d\n",
 		    adapter->msix_entries[irq_idx].vector);
 #ifdef	RSS
 		adapter->que[i].cpu = adapter->irq_tbl[irq_idx].cpu =
 		    rss_getcpu(i % rss_getnumbuckets());
 #else
 		/*
 		 * We still want to bind rings to the corresponding cpu
 		 * using something similar to the RSS round-robin technique.
 		 */
 		if (last_bind_cpu < 0)
 			last_bind_cpu = CPU_FIRST();
 		adapter->que[i].cpu = adapter->irq_tbl[irq_idx].cpu =
 		    last_bind_cpu;
 		last_bind_cpu = CPU_NEXT(last_bind_cpu);
 #endif
 	}
 
 	return;
 }
 
 static int
 ena_request_mgmnt_irq(struct ena_adapter *adapter)
 {
 	struct ena_irq *irq;
 	unsigned long flags;
 	int rc, rcc;
 
 	flags = RF_ACTIVE | RF_SHAREABLE;
 
 	irq = &adapter->irq_tbl[ENA_MGMNT_IRQ_IDX];
 	irq->res = bus_alloc_resource_any(adapter->pdev, SYS_RES_IRQ,
 	    &irq->vector, flags);
 
 	if (irq->res == NULL) {
 		device_printf(adapter->pdev, "could not allocate "
 		    "irq vector: %d\n", irq->vector);
 		rc = ENXIO;
 		goto exit_res;
 	}
 
 	if ((rc = bus_activate_resource(adapter->pdev, SYS_RES_IRQ, irq->vector,
 	    irq->res)) != 0) {
 		device_printf(adapter->pdev, "could not activate "
 		    "irq vector: %d\n", irq->vector);
 		goto exit_intr;
 	}
 
 	if ((rc = bus_setup_intr(adapter->pdev, irq->res,
 	    INTR_TYPE_NET | INTR_MPSAFE, NULL,
 	    ena_intr_msix_mgmnt, irq->data, &irq->cookie)) != 0) {
 		device_printf(adapter->pdev, "failed to register "
 		    "interrupt handler for irq %ju: %d\n",
 		    rman_get_start(irq->res), rc);
 		goto exit_intr;
 	}
 	irq->requested = true;
 
 	return (rc);
 
 exit_intr:
 	device_printf(adapter->pdev, "exit_intr: releasing resource"
 	    " for irq %d\n", irq->vector);
 	rcc = bus_release_resource(adapter->pdev, SYS_RES_IRQ,
 	    irq->vector, irq->res);
 	if (rcc)
 		device_printf(adapter->pdev, "dev has no parent while "
 		    "releasing res for irq: %d\n", irq->vector);
 	irq->res = NULL;
 
 exit_res:
 	return (rc);
 }
 
 static int
 ena_request_io_irq(struct ena_adapter *adapter)
 {
 	struct ena_irq *irq;
 	unsigned long flags = 0;
 	int rc = 0, i, rcc;
 
 	if (!adapter->msix_enabled) {
 		device_printf(adapter->pdev, "failed to request irq\n");
 		return (EINVAL);
 	} else {
 		flags = RF_ACTIVE | RF_SHAREABLE;
 	}
 
 	for (i = ENA_IO_IRQ_FIRST_IDX; i < adapter->msix_vecs; i++) {
 		irq = &adapter->irq_tbl[i];
 
 		if (irq->requested)
 			continue;
 
 		irq->res = bus_alloc_resource_any(adapter->pdev, SYS_RES_IRQ,
 		    &irq->vector, flags);
 		if (irq->res == NULL) {
 			device_printf(adapter->pdev, "could not allocate "
 			    "irq vector: %d\n", irq->vector);
 			goto err;
 		}
 
 		if ((rc = bus_setup_intr(adapter->pdev, irq->res,
 			    INTR_TYPE_NET | INTR_MPSAFE, NULL, irq->handler,
 			    irq->data, &irq->cookie)) != 0) {
 			device_printf(adapter->pdev, "failed to register "
 			    "interrupt handler for irq %ju: %d\n",
 			    rman_get_start(irq->res), rc);
 			goto err;
 		}
 		irq->requested = true;
 
 #ifdef	RSS
 		device_printf(adapter->pdev, "queue %d - RSS bucket %d\n",
 		    i - ENA_IO_IRQ_FIRST_IDX, irq->cpu);
 #else
 		device_printf(adapter->pdev, "queue %d - cpu %d\n",
 		    i - ENA_IO_IRQ_FIRST_IDX, irq->cpu);
 #endif
 	}
 
 	return (rc);
 
 err:
 
 	for (; i >= ENA_IO_IRQ_FIRST_IDX; i--) {
 		irq = &adapter->irq_tbl[i];
 		rcc = 0;
 
 		/* Once we entered err: section and irq->requested is true we
 		   free both intr and resources */
 		if (irq->requested == true)
 			rcc = bus_teardown_intr(adapter->pdev, irq->res, irq->cookie);
 		if (rcc)
 			device_printf(adapter->pdev, "could not release"
 			    " irq: %d, error: %d\n", irq->vector, rcc);
 
 		/* If we entred err: section without irq->requested set we know
 		   it was bus_alloc_resource_any() that needs cleanup, provided
 		   res is not NULL. In case res is NULL no work in needed in
 		   this iteration */
 		rcc = 0;
 		if (irq->res != NULL) {
 			rcc = bus_release_resource(adapter->pdev, SYS_RES_IRQ,
 			    irq->vector, irq->res);
 		}
 		if (rcc)
 			device_printf(adapter->pdev, "dev has no parent while "
 			    "releasing res for irq: %d\n", irq->vector);
 		irq->requested = false;
 		irq->res = NULL;
 	}
 
 	return (rc);
 }
 
 static void
 ena_free_mgmnt_irq(struct ena_adapter *adapter)
 {
 	struct ena_irq *irq;
 	int rc;
 
 	irq = &adapter->irq_tbl[ENA_MGMNT_IRQ_IDX];
 	if (irq->requested) {
 		ena_trace(ENA_INFO | ENA_ADMQ, "tear down irq: %d\n",
 		    irq->vector);
 		rc = bus_teardown_intr(adapter->pdev, irq->res, irq->cookie);
 		if (rc)
 			device_printf(adapter->pdev, "failed to tear "
 			    "down irq: %d\n", irq->vector);
 		irq->requested = 0;
 	}
 
 	if (irq->res != NULL) {
 		ena_trace(ENA_INFO | ENA_ADMQ, "release resource irq: %d\n",
 		    irq->vector);
 		rc = bus_release_resource(adapter->pdev, SYS_RES_IRQ,
 		    irq->vector, irq->res);
 		irq->res = NULL;
 		if (rc)
 			device_printf(adapter->pdev, "dev has no parent while "
 			    "releasing res for irq: %d\n", irq->vector);
 	}
 
 	return;
 }
 
 static void
 ena_free_io_irq(struct ena_adapter *adapter)
 {
 	struct ena_irq *irq;
 	int rc;
 
 	for (int i = ENA_IO_IRQ_FIRST_IDX; i < adapter->msix_vecs; i++) {
 		irq = &adapter->irq_tbl[i];
 		if (irq->requested) {
 			ena_trace(ENA_INFO | ENA_IOQ, "tear down irq: %d\n",
 			    irq->vector);
 			rc = bus_teardown_intr(adapter->pdev, irq->res,
 			    irq->cookie);
 			if (rc) {
 				device_printf(adapter->pdev, "failed to tear "
 				    "down irq: %d\n", irq->vector);
 			}
 			irq->requested = 0;
 		}
 
 		if (irq->res != NULL) {
 			ena_trace(ENA_INFO | ENA_IOQ, "release resource irq: %d\n",
 			    irq->vector);
 			rc = bus_release_resource(adapter->pdev, SYS_RES_IRQ,
 			    irq->vector, irq->res);
 			irq->res = NULL;
 			if (rc) {
 				device_printf(adapter->pdev, "dev has no parent"
 				    " while releasing res for irq: %d\n",
 				    irq->vector);
 			}
 		}
 	}
 
 	return;
 }
 
 static void
 ena_free_irqs(struct ena_adapter* adapter)
 {
 
 	ena_free_io_irq(adapter);
 	ena_free_mgmnt_irq(adapter);
 	ena_disable_msix(adapter);
 }
 
 static void
 ena_disable_msix(struct ena_adapter *adapter)
 {
 
 	pci_release_msi(adapter->pdev);
 
 	adapter->msix_vecs = 0;
 	ENA_MEM_FREE(adapter->ena_dev->dmadev, adapter->msix_entries);
 	adapter->msix_entries = NULL;
 }
 
 static void
 ena_unmask_all_io_irqs(struct ena_adapter *adapter)
 {
 	struct ena_com_io_cq* io_cq;
 	struct ena_eth_io_intr_reg intr_reg;
 	uint16_t ena_qid;
 	int i;
 
 	/* Unmask interrupts for all queues */
 	for (i = 0; i < adapter->num_queues; i++) {
 		ena_qid = ENA_IO_TXQ_IDX(i);
 		io_cq = &adapter->ena_dev->io_cq_queues[ena_qid];
 		ena_com_update_intr_reg(&intr_reg, 0, 0, true);
 		ena_com_unmask_intr(io_cq, &intr_reg);
 	}
 }
 
 /* Configure the Rx forwarding */
 static int ena_rss_configure(struct ena_adapter *adapter)
 {
 	struct ena_com_dev *ena_dev = adapter->ena_dev;
 	int rc;
 
 	/* Set indirect table */
 	rc = ena_com_indirect_table_set(ena_dev);
 	if (unlikely(rc && rc != EOPNOTSUPP))
 		return rc;
 
 	/* Configure hash function (if supported) */
 	rc = ena_com_set_hash_function(ena_dev);
 	if (unlikely(rc && (rc != EOPNOTSUPP)))
 		return rc;
 
 	/* Configure hash inputs (if supported) */
 	rc = ena_com_set_hash_ctrl(ena_dev);
 	if (unlikely(rc && (rc != EOPNOTSUPP)))
 		return rc;
 
 	return 0;
 }
 
-static void
-ena_update_hw_stats(void *arg, int pending)
-{
-	struct ena_adapter *adapter = arg;
-	int rc;
-
-	for (;;) {
-		if (!adapter->up)
-			return;
-
-		rc = ena_update_stats_counters(adapter);
-		if (rc)
-			ena_trace(ENA_WARNING,
-			    "Error updating stats counters, rc = %d", rc);
-
-		pause("ena update hw stats", hz);
-	}
-}
-
 static int
 ena_up_complete(struct ena_adapter *adapter)
 {
 	int rc;
 
 	if (adapter->rss_support) {
 		rc = ena_rss_configure(adapter);
 		if (rc)
 			return (rc);
 	}
 
 	ena_change_mtu(adapter->ifp, adapter->ifp->if_mtu);
 	ena_refill_all_rx_bufs(adapter);
+	ena_reset_counters((counter_u64_t *)&adapter->hw_stats,
+	    sizeof(adapter->hw_stats));
 
 	return (0);
 }
 
 static int
 ena_up(struct ena_adapter *adapter)
 {
 	int rc = 0;
 
 	if (!device_is_attached(adapter->pdev)) {
 		device_printf(adapter->pdev, "device is not attached!\n");
 		return (ENXIO);
 	}
 
 	if (!adapter->running) {
 		device_printf(adapter->pdev, "device is not running!\n");
 		return (ENXIO);
 	}
 
 	if (!adapter->up) {
 		device_printf(adapter->pdev, "device is going UP\n");
 
 		/* setup interrupts for IO queues */
 		ena_setup_io_intr(adapter);
 		rc = ena_request_io_irq(adapter);
 		if (rc) {
 			ena_trace(ENA_ALERT, "err_req_irq");
 			goto err_req_irq;
 		}
 
 		/* allocate transmit descriptors */
 		rc = ena_setup_all_tx_resources(adapter);
 		if (rc) {
 			ena_trace(ENA_ALERT, "err_setup_tx");
 			goto err_setup_tx;
 		}
 
 		/* allocate receive descriptors */
 		rc = ena_setup_all_rx_resources(adapter);
 		if (rc) {
 			ena_trace(ENA_ALERT, "err_setup_rx");
 			goto err_setup_rx;
 		}
 
 		/* create IO queues for Rx & Tx */
 		rc = ena_create_io_queues(adapter);
 		if (rc) {
 			ena_trace(ENA_ALERT,
 			    "create IO queues failed");
 			goto err_io_que;
 		}
 
 		if (adapter->link_status)
 			if_link_state_change(adapter->ifp, LINK_STATE_UP);
 
 		rc = ena_up_complete(adapter);
 		if (rc)
 			goto err_up_complete;
 
 		counter_u64_add(adapter->dev_stats.interface_up, 1);
 
 		ena_update_hwassist(adapter);
 
 		if_setdrvflagbits(adapter->ifp, IFF_DRV_RUNNING,
 		    IFF_DRV_OACTIVE);
 
 		callout_reset_sbt(&adapter->timer_service, SBT_1S, SBT_1S,
 		    ena_timer_service, (void *)adapter, 0);
 
-		taskqueue_enqueue(adapter->stats_tq, &adapter->stats_task);
-
 		adapter->up = true;
 
 		ena_unmask_all_io_irqs(adapter);
 	}
 
 	return (0);
 
 err_up_complete:
 	ena_destroy_all_io_queues(adapter);
 err_io_que:
 	ena_free_all_rx_resources(adapter);
 err_setup_rx:
 	ena_free_all_tx_resources(adapter);
 err_setup_tx:
 	ena_free_io_irq(adapter);
 err_req_irq:
 	return (rc);
 }
 
-int
-ena_update_stats_counters(struct ena_adapter *adapter)
-{
-	struct ena_admin_basic_stats ena_stats;
-	struct ena_hw_stats *stats = &adapter->hw_stats;
-	int rc = 0;
-
-	if (!adapter->up)
-		return (rc);
-
-	rc = ena_com_get_dev_basic_stats(adapter->ena_dev, &ena_stats);
-	if (rc)
-		return (rc);
-
-	stats->tx_bytes = ((uint64_t)ena_stats.tx_bytes_high << 32) |
-		ena_stats.tx_bytes_low;
-	stats->rx_bytes = ((uint64_t)ena_stats.rx_bytes_high << 32) |
-		ena_stats.rx_bytes_low;
-
-	stats->rx_packets = ((uint64_t)ena_stats.rx_pkts_high << 32) |
-		ena_stats.rx_pkts_low;
-	stats->tx_packets = ((uint64_t)ena_stats.tx_pkts_high << 32) |
-		ena_stats.tx_pkts_low;
-
-	stats->rx_drops = ((uint64_t)ena_stats.rx_drops_high << 32) |
-		ena_stats.rx_drops_low;
-
-	return (0);
-}
-
 static uint64_t
 ena_get_counter(if_t ifp, ift_counter cnt)
 {
 	struct ena_adapter *adapter;
 	struct ena_hw_stats *stats;
 
 	adapter = if_getsoftc(ifp);
 	stats = &adapter->hw_stats;
 
 	switch (cnt) {
 	case IFCOUNTER_IPACKETS:
-		return (stats->rx_packets);
+		return (counter_u64_fetch(stats->rx_packets));
 	case IFCOUNTER_OPACKETS:
-		return (stats->tx_packets);
+		return (counter_u64_fetch(stats->tx_packets));
 	case IFCOUNTER_IBYTES:
-		return (stats->rx_bytes);
+		return (counter_u64_fetch(stats->rx_bytes));
 	case IFCOUNTER_OBYTES:
-		return (stats->tx_bytes);
+		return (counter_u64_fetch(stats->tx_bytes));
 	case IFCOUNTER_IQDROPS:
-		return (stats->rx_drops);
+		return (counter_u64_fetch(stats->rx_drops));
 	default:
 		return (if_get_counter_default(ifp, cnt));
 	}
 }
 
 static int
 ena_media_change(if_t ifp)
 {
 	/* Media Change is not supported by firmware */
 	return (0);
 }
 
 static void
 ena_media_status(if_t ifp, struct ifmediareq *ifmr)
 {
 	struct ena_adapter *adapter = if_getsoftc(ifp);
 	ena_trace(ENA_DBG, "enter");
 
 	ENA_DEV_LOCK;
 
 	ifmr->ifm_status = IFM_AVALID;
 	ifmr->ifm_active = IFM_ETHER;
 
 	if (!adapter->link_status) {
 		ENA_DEV_UNLOCK;
 		ena_trace(ENA_WARNING, "link_status = false");
 		return;
 	}
 
 	ifmr->ifm_status |= IFM_ACTIVE;
 	ifmr->ifm_active |= IFM_10G_T | IFM_FDX;
 
 	ENA_DEV_UNLOCK;
 
 	return;
 }
 
 static void
 ena_init(void *arg)
 {
 	struct ena_adapter *adapter = (struct ena_adapter *)arg;
 
 	if (adapter->up == false) {
 		sx_xlock(&adapter->ioctl_sx);
 		ena_up(adapter);
 		sx_unlock(&adapter->ioctl_sx);
 	}
 
 	return;
 }
 
 static int
 ena_ioctl(if_t ifp, u_long command, caddr_t data)
 {
 	struct ena_adapter *adapter;
 	struct ifreq *ifr;
 	int rc;
 
 	adapter = ifp->if_softc;
 	ifr = (struct ifreq *)data;
 
 	/*
 	 * Acquiring lock to prevent from running up and down routines parallel.
 	 */
 	rc = 0;
 	switch (command) {
 	case SIOCSIFMTU:
 		sx_xlock(&adapter->ioctl_sx);
 		ena_down(adapter);
 
 		ena_change_mtu(ifp, ifr->ifr_mtu);
 
 		rc = ena_up(adapter);
 		sx_unlock(&adapter->ioctl_sx);
 		break;
 
 	case SIOCSIFFLAGS:
 		if (ifp->if_flags & IFF_UP) {
 			if ((ifp->if_drv_flags & IFF_DRV_RUNNING)) {
 				if (ifp->if_flags & (IFF_PROMISC |
 				    IFF_ALLMULTI)) {
 					device_printf(adapter->pdev,
 					    "ioctl promisc/allmulti\n");
 				}
 			} else {
 				sx_xlock(&adapter->ioctl_sx);
 				rc = ena_up(adapter);
 				sx_unlock(&adapter->ioctl_sx);
 			}
 		} else {
 			if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
 				sx_xlock(&adapter->ioctl_sx);
 				ena_down(adapter);
 				sx_unlock(&adapter->ioctl_sx);
 			}
 		}
 		break;
 
 	case SIOCADDMULTI:
 	case SIOCDELMULTI:
 		break;
 
 	case SIOCSIFMEDIA:
 	case SIOCGIFMEDIA:
 		rc = ifmedia_ioctl(ifp, ifr, &adapter->media, command);
 		break;
 
 	case SIOCSIFCAP:
 		{
 			int reinit = 0;
 
 			if (ifr->ifr_reqcap != ifp->if_capenable) {
 				ifp->if_capenable = ifr->ifr_reqcap;
 				reinit = 1;
 			}
 
 			if (reinit && (ifp->if_drv_flags & IFF_DRV_RUNNING)) {
 				sx_xlock(&adapter->ioctl_sx);
 				ena_down(adapter);
 				rc = ena_up(adapter);
 				sx_unlock(&adapter->ioctl_sx);
 			}
 		}
 
 		break;
 	default:
 		rc = ether_ioctl(ifp, command, data);
 		break;
 	}
 
 	return (rc);
 }
 
 static int
 ena_get_dev_offloads(struct ena_com_dev_get_features_ctx *feat)
 {
 	int caps = 0;
 
 	if (feat->offload.tx &
 	    (ENA_ADMIN_FEATURE_OFFLOAD_DESC_TX_L4_IPV4_CSUM_FULL_MASK |
 	    ENA_ADMIN_FEATURE_OFFLOAD_DESC_TX_L4_IPV4_CSUM_PART_MASK |
 	    ENA_ADMIN_FEATURE_OFFLOAD_DESC_TX_L3_CSUM_IPV4_MASK))
 		caps |= IFCAP_TXCSUM;
 
 	if (feat->offload.tx &
 	    (ENA_ADMIN_FEATURE_OFFLOAD_DESC_TX_L4_IPV6_CSUM_FULL_MASK |
 	    ENA_ADMIN_FEATURE_OFFLOAD_DESC_TX_L4_IPV6_CSUM_PART_MASK))
 		caps |= IFCAP_TXCSUM_IPV6;
 
 	if (feat->offload.tx & ENA_ADMIN_FEATURE_OFFLOAD_DESC_TSO_IPV4_MASK)
 		caps |= IFCAP_TSO4;
 
 	if (feat->offload.tx & ENA_ADMIN_FEATURE_OFFLOAD_DESC_TSO_IPV6_MASK)
 		caps |= IFCAP_TSO6;
 
 	if (feat->offload.rx_supported &
 	    (ENA_ADMIN_FEATURE_OFFLOAD_DESC_RX_L4_IPV4_CSUM_MASK |
 	    ENA_ADMIN_FEATURE_OFFLOAD_DESC_RX_L3_CSUM_IPV4_MASK))
 		caps |= IFCAP_RXCSUM;
 
 	if (feat->offload.rx_supported &
 	    ENA_ADMIN_FEATURE_OFFLOAD_DESC_RX_L4_IPV6_CSUM_MASK)
 		caps |= IFCAP_RXCSUM_IPV6;
 
 	caps |= IFCAP_LRO | IFCAP_JUMBO_MTU;
 
 	return (caps);
 }
 
 static void
 ena_update_host_info(struct ena_admin_host_info *host_info, if_t ifp)
 {
 
 	host_info->supported_network_features[0] =
 	    (uint32_t)if_getcapabilities(ifp);
 }
 
 static void
 ena_update_hwassist(struct ena_adapter *adapter)
 {
 	if_t ifp = adapter->ifp;
 	uint32_t feat = adapter->tx_offload_cap;
 	int cap = if_getcapenable(ifp);
 	int flags = 0;
 
 	if_clearhwassist(ifp);
 
 	if (cap & IFCAP_TXCSUM) {
 		if (feat & ENA_ADMIN_FEATURE_OFFLOAD_DESC_TX_L3_CSUM_IPV4_MASK)
 			flags |= CSUM_IP;
 		if (feat &
 		    (ENA_ADMIN_FEATURE_OFFLOAD_DESC_TX_L4_IPV4_CSUM_FULL_MASK |
 		    ENA_ADMIN_FEATURE_OFFLOAD_DESC_TX_L4_IPV4_CSUM_PART_MASK))
 			flags |= CSUM_IP_UDP | CSUM_IP_TCP;
 	}
 
 	if (cap & IFCAP_TXCSUM_IPV6)
 		flags |= CSUM_IP6_UDP | CSUM_IP6_TCP;
 
 	if (cap & IFCAP_TSO4)
 		flags |= CSUM_IP_TSO;
 
 	if (cap & IFCAP_TSO6)
 		flags |= CSUM_IP6_TSO;
 
 	if_sethwassistbits(ifp, flags, 0);
 }
 
 static int
 ena_setup_ifnet(device_t pdev, struct ena_adapter *adapter,
     struct ena_com_dev_get_features_ctx *feat)
 {
 	if_t ifp;
 	int caps = 0;
 
 	ena_trace(ENA_DBG, "enter");
 
 	ifp = adapter->ifp = if_gethandle(IFT_ETHER);
 	if (ifp == 0) {
 		device_printf(pdev, "can not allocate ifnet structure\n");
 		return (ENXIO);
 	}
 	if_initname(ifp, device_get_name(pdev), device_get_unit(pdev));
 	if_setdev(ifp, pdev);
 	if_setsoftc(ifp, adapter);
 
 	if_setflags(ifp, IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST);
 	if_setinitfn(ifp, ena_init);
 	if_settransmitfn(ifp, ena_mq_start);
 	if_setqflushfn(ifp, ena_qflush);
 	if_setioctlfn(ifp, ena_ioctl);
 	if_setgetcounterfn(ifp, ena_get_counter);
 
 	if_setsendqlen(ifp, adapter->tx_ring_size);
 	if_setsendqready(ifp);
 	if_setmtu(ifp, ETHERMTU);
 	if_setbaudrate(ifp, 0);
 	/* Zeroize capabilities... */
 	if_setcapabilities(ifp, 0);
 	if_setcapenable(ifp, 0);
 	/* check hardware support */
 	caps = ena_get_dev_offloads(feat);
 	/* ... and set them */
 	if_setcapabilitiesbit(ifp, caps, 0);
 
 	/* TSO parameters */
 	ifp->if_hw_tsomax = ENA_TSO_MAXSIZE -
 	    (ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN);
 	ifp->if_hw_tsomaxsegcount = adapter->max_tx_sgl_size - 1;
 	ifp->if_hw_tsomaxsegsize = ENA_TSO_MAXSIZE;
 
 	if_setifheaderlen(ifp, sizeof(struct ether_vlan_header));
 	if_setcapenable(ifp, if_getcapabilities(ifp));
 
 	/*
 	 * Specify the media types supported by this adapter and register
 	 * callbacks to update media and link information
 	 */
 	ifmedia_init(&adapter->media, IFM_IMASK,
 	    ena_media_change, ena_media_status);
 	ifmedia_add(&adapter->media, IFM_ETHER | IFM_AUTO, 0, NULL);
 	ifmedia_set(&adapter->media, IFM_ETHER | IFM_AUTO);
 
 	ether_ifattach(ifp, adapter->mac_addr);
 
 	return (0);
 }
 
 static void
 ena_down(struct ena_adapter *adapter)
 {
 	int rc;
 
 	if (adapter->up) {
 		device_printf(adapter->pdev, "device is going DOWN\n");
 
 		callout_drain(&adapter->timer_service);
 
 		adapter->up = false;
 		if_setdrvflagbits(adapter->ifp, IFF_DRV_OACTIVE,
 		    IFF_DRV_RUNNING);
 
-		/* Drain task responsible for updating hw stats */
-		while (taskqueue_cancel(adapter->stats_tq, &adapter->stats_task, NULL))
-			taskqueue_drain(adapter->stats_tq, &adapter->stats_task);
-
 		ena_free_io_irq(adapter);
 
 		if (adapter->trigger_reset) {
 			rc = ena_com_dev_reset(adapter->ena_dev,
 			    adapter->reset_reason);
 			if (rc)
 				device_printf(adapter->pdev,
 				    "Device reset failed\n");
 		}
 
 		ena_destroy_all_io_queues(adapter);
 
 		ena_free_all_tx_bufs(adapter);
 		ena_free_all_rx_bufs(adapter);
 		ena_free_all_tx_resources(adapter);
 		ena_free_all_rx_resources(adapter);
 
 		counter_u64_add(adapter->dev_stats.interface_down, 1);
 	}
 
 	return;
 }
 
 static void
 ena_tx_csum(struct ena_com_tx_ctx *ena_tx_ctx, struct mbuf *mbuf)
 {
 	struct ena_com_tx_meta *ena_meta;
 	struct ether_vlan_header *eh;
 	u32 mss;
 	bool offload;
 	uint16_t etype;
 	int ehdrlen;
 	struct ip *ip;
 	int iphlen;
 	struct tcphdr *th;
 
 	offload = false;
 	ena_meta = &ena_tx_ctx->ena_meta;
 	mss = mbuf->m_pkthdr.tso_segsz;
 
 	if (mss != 0)
 		offload = true;
 
 	if ((mbuf->m_pkthdr.csum_flags & CSUM_TSO) != 0)
 		offload = true;
 
 	if ((mbuf->m_pkthdr.csum_flags & CSUM_OFFLOAD) != 0)
 		offload = true;
 
 	if (offload == false) {
 		ena_tx_ctx->meta_valid = 0;
 		return;
 	}
 
 	/* Determine where frame payload starts. */
 	eh = mtod(mbuf, struct ether_vlan_header *);
 	if (eh->evl_encap_proto == htons(ETHERTYPE_VLAN)) {
 		etype = ntohs(eh->evl_proto);
 		ehdrlen = ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN;
 	} else {
 		etype = ntohs(eh->evl_encap_proto);
 		ehdrlen = ETHER_HDR_LEN;
 	}
 
 	ip = (struct ip *)(mbuf->m_data + ehdrlen);
 	iphlen = ip->ip_hl << 2;
 	th = (struct tcphdr *)((caddr_t)ip + iphlen);
 
 	if ((mbuf->m_pkthdr.csum_flags & CSUM_IP) != 0) {
 		ena_tx_ctx->l3_csum_enable = 1;
 	}
 	if ((mbuf->m_pkthdr.csum_flags & CSUM_TSO) != 0) {
 		ena_tx_ctx->tso_enable = 1;
 		ena_meta->l4_hdr_len = (th->th_off);
 	}
 
 	switch (etype) {
 	case ETHERTYPE_IP:
 		ena_tx_ctx->l3_proto = ENA_ETH_IO_L3_PROTO_IPV4;
 		if (ip->ip_off == 0)
 			ena_tx_ctx->df = 1;
 		break;
 	case ETHERTYPE_IPV6:
 		ena_tx_ctx->l3_proto = ENA_ETH_IO_L3_PROTO_IPV6;
 
 	default:
 		break;
 	}
 
 	if (ip->ip_p == IPPROTO_TCP) {
 		ena_tx_ctx->l4_proto = ENA_ETH_IO_L4_PROTO_TCP;
 		if (mbuf->m_pkthdr.csum_flags & (CSUM_IP_TCP | CSUM_IP6_TCP))
 		    ena_tx_ctx->l4_csum_enable = 1;
 		else
 		    ena_tx_ctx->l4_csum_enable = 0;
 	} else if (ip->ip_p == IPPROTO_UDP) {
 		ena_tx_ctx->l4_proto = ENA_ETH_IO_L4_PROTO_UDP;
 		if (mbuf->m_pkthdr.csum_flags & (CSUM_IP_UDP | CSUM_IP6_UDP))
 		    ena_tx_ctx->l4_csum_enable = 1;
 		else
 		    ena_tx_ctx->l4_csum_enable = 0;
 	} else {
 		ena_tx_ctx->l4_proto = ENA_ETH_IO_L4_PROTO_UNKNOWN;
 		ena_tx_ctx->l4_csum_enable = 0;
 	}
 
 	ena_meta->mss = mss;
 	ena_meta->l3_hdr_len = iphlen;
 	ena_meta->l3_hdr_offset = ehdrlen;
 	ena_tx_ctx->meta_valid = 1;
 }
 
 static int
 ena_check_and_collapse_mbuf(struct ena_ring *tx_ring, struct mbuf **mbuf)
 {
 	struct ena_adapter *adapter;
 	struct mbuf *collapsed_mbuf;
 	int num_frags;
 
 	adapter = tx_ring->adapter;
 	num_frags = ena_mbuf_count(*mbuf);
 
 	/* One segment must be reserved for configuration descriptor. */
 	if (num_frags < adapter->max_tx_sgl_size)
 		return (0);
 	counter_u64_add(tx_ring->tx_stats.collapse, 1);
 
 	collapsed_mbuf = m_collapse(*mbuf, M_NOWAIT,
 	    adapter->max_tx_sgl_size - 1);
 	if (collapsed_mbuf == NULL) {
 		counter_u64_add(tx_ring->tx_stats.collapse_err, 1);
 		return (ENOMEM);
 	}
 
 	/* If mbuf was collapsed succesfully, original mbuf is released. */
 	*mbuf = collapsed_mbuf;
 
 	return (0);
 }
 
 static int
 ena_xmit_mbuf(struct ena_ring *tx_ring, struct mbuf **mbuf)
 {
 	struct ena_adapter *adapter;
 	struct ena_tx_buffer *tx_info;
 	struct ena_com_tx_ctx ena_tx_ctx;
 	struct ena_com_dev *ena_dev;
 	struct ena_com_buf *ena_buf;
 	struct ena_com_io_sq* io_sq;
 	bus_dma_segment_t segs[ENA_BUS_DMA_SEGS];
 	void *push_hdr;
 	uint16_t next_to_use;
 	uint16_t req_id;
 	uint16_t push_len;
 	uint16_t ena_qid;
 	uint32_t len, nsegs, header_len;
 	int i, rc;
 	int nb_hw_desc;
 
 	ena_qid = ENA_IO_TXQ_IDX(tx_ring->que->id);
 	adapter = tx_ring->que->adapter;
 	ena_dev = adapter->ena_dev;
 	io_sq = &adapter->ena_dev->io_sq_queues[ena_qid];
 
 	ENA_ASSERT(*mbuf, "mbuf is NULL\n");
 
 	rc = ena_check_and_collapse_mbuf(tx_ring, mbuf);
 	if (rc) {
 		ena_trace(ENA_WARNING,
 		    "Failed to collapse mbuf! err: %d", rc);
 		return (rc);
 	}
 
 	next_to_use = tx_ring->next_to_use;
 	req_id = tx_ring->free_tx_ids[next_to_use];
 	tx_info = &tx_ring->tx_buffer_info[req_id];
 
 	tx_info->mbuf = *mbuf;
 	tx_info->num_of_bufs = 0;
 
 	ena_buf = tx_info->bufs;
 	len = (*mbuf)->m_len;
 
 	ena_trace(ENA_DBG | ENA_TXPTH, "Tx: %d bytes", (*mbuf)->m_pkthdr.len);
 
 	push_len = 0;
 	header_len = min_t(uint32_t, len, tx_ring->tx_max_header_size);
 	push_hdr = NULL;
 
 	rc = bus_dmamap_load_mbuf_sg(adapter->tx_buf_tag, tx_info->map,
 	    *mbuf, segs, &nsegs, BUS_DMA_NOWAIT);
 
 	if (rc || (nsegs == 0)) {
 		ena_trace(ENA_WARNING,
 		    "dmamap load failed! err: %d nsegs: %d", rc, nsegs);
 		counter_u64_add(tx_ring->tx_stats.dma_mapping_err, 1);
 		tx_info->mbuf = NULL;
 		if (rc == ENOMEM)
 			return (ENA_COM_NO_MEM);
 		else
 			return (ENA_COM_INVAL);
 	}
 
 	for (i = 0; i < nsegs; i++) {
 		ena_buf->len = segs[i].ds_len;
 		ena_buf->paddr = segs[i].ds_addr;
 		ena_buf++;
 	}
 	tx_info->num_of_bufs = nsegs;
 
 	memset(&ena_tx_ctx, 0x0, sizeof(struct ena_com_tx_ctx));
 	ena_tx_ctx.ena_bufs = tx_info->bufs;
 	ena_tx_ctx.push_header = push_hdr;
 	ena_tx_ctx.num_bufs = tx_info->num_of_bufs;
 	ena_tx_ctx.req_id = req_id;
 	ena_tx_ctx.header_len = header_len;
 
 	/* Set flags and meta data */
 	ena_tx_csum(&ena_tx_ctx, *mbuf);
 	/* Prepare the packet's descriptors and send them to device */
 	rc = ena_com_prepare_tx(io_sq, &ena_tx_ctx, &nb_hw_desc);
 	if (rc != 0) {
 		ena_trace(ENA_WARNING, "failed to prepare tx bufs\n");
 		counter_enter();
 		counter_u64_add_protected(tx_ring->tx_stats.queue_stop, 1);
 		counter_u64_add_protected(tx_ring->tx_stats.prepare_ctx_err, 1);
 		counter_exit();
 		goto dma_error;
 	}
 
 	counter_enter();
 	counter_u64_add_protected(tx_ring->tx_stats.cnt, 1);
 	counter_u64_add_protected(tx_ring->tx_stats.bytes,  (*mbuf)->m_pkthdr.len);
+
+	counter_u64_add_protected(adapter->hw_stats.tx_packets, 1);
+	counter_u64_add_protected(adapter->hw_stats.tx_bytes,
+	    (*mbuf)->m_pkthdr.len);
 	counter_exit();
 
 	tx_info->tx_descs = nb_hw_desc;
 	getbinuptime(&tx_info->timestamp);
 	tx_info->print_once = true;
 
 	tx_ring->next_to_use = ENA_TX_RING_IDX_NEXT(next_to_use,
 	    tx_ring->ring_size);
 
 	bus_dmamap_sync(adapter->tx_buf_tag, tx_info->map, BUS_DMASYNC_PREWRITE);
 
 	return (0);
 
 dma_error:
 	tx_info->mbuf = NULL;
 	bus_dmamap_unload(adapter->tx_buf_tag, tx_info->map);
 
 	return (rc);
 }
 
 static void
 ena_start_xmit(struct ena_ring *tx_ring)
 {
 	struct mbuf *mbuf;
 	struct ena_adapter *adapter = tx_ring->adapter;
 	struct ena_com_io_sq* io_sq;
 	int ena_qid;
 	int acum_pkts = 0;
 	int ret = 0;
 
 	if ((adapter->ifp->if_drv_flags & IFF_DRV_RUNNING) == 0)
 		return;
 
 	if (!adapter->link_status)
 		return;
 
 	ena_qid = ENA_IO_TXQ_IDX(tx_ring->que->id);
 	io_sq = &adapter->ena_dev->io_sq_queues[ena_qid];
 
 	while ((mbuf = drbr_peek(adapter->ifp, tx_ring->br)) != NULL) {
 		ena_trace(ENA_DBG | ENA_TXPTH, "\ndequeued mbuf %p with flags %#x and"
 		    " header csum flags %#jx",
 		    mbuf, mbuf->m_flags, mbuf->m_pkthdr.csum_flags);
 
 		if (!ena_com_sq_have_enough_space(io_sq,
 		    ENA_TX_CLEANUP_THRESHOLD))
 			ena_tx_cleanup(tx_ring);
 
 		if ((ret = ena_xmit_mbuf(tx_ring, &mbuf)) != 0) {
 			if (ret == ENA_COM_NO_MEM) {
 				drbr_putback(adapter->ifp, tx_ring->br, mbuf);
 			} else if (ret == ENA_COM_NO_SPACE) {
 				drbr_putback(adapter->ifp, tx_ring->br, mbuf);
 			} else {
 				m_freem(mbuf);
 				drbr_advance(adapter->ifp, tx_ring->br);
 			}
 
 			break;
 		}
 
 		drbr_advance(adapter->ifp, tx_ring->br);
 
 		if ((adapter->ifp->if_drv_flags & IFF_DRV_RUNNING) == 0)
 			return;
 
 		acum_pkts++;
 
 		BPF_MTAP(adapter->ifp, mbuf);
 
 		if (acum_pkts == DB_THRESHOLD) {
 			acum_pkts = 0;
 			wmb();
 			/* Trigger the dma engine */
 			ena_com_write_sq_doorbell(io_sq);
 			counter_u64_add(tx_ring->tx_stats.doorbells, 1);
 		}
 
 	}
 
 	if (acum_pkts) {
 		wmb();
 		/* Trigger the dma engine */
 		ena_com_write_sq_doorbell(io_sq);
 		counter_u64_add(tx_ring->tx_stats.doorbells, 1);
 	}
 
 	if (!ena_com_sq_have_enough_space(io_sq,
 	    ENA_TX_CLEANUP_THRESHOLD))
 		ena_tx_cleanup(tx_ring);
 }
 
 static void
 ena_deferred_mq_start(void *arg, int pending)
 {
 	struct ena_ring *tx_ring = (struct ena_ring *)arg;
 	struct ifnet *ifp = tx_ring->adapter->ifp;
 
 	while (drbr_empty(ifp, tx_ring->br) == FALSE &&
 	    (ifp->if_drv_flags & IFF_DRV_RUNNING) != 0) {
 		ENA_RING_MTX_LOCK(tx_ring);
 		ena_start_xmit(tx_ring);
 		ENA_RING_MTX_UNLOCK(tx_ring);
 	}
 }
 
 static int
 ena_mq_start(if_t ifp, struct mbuf *m)
 {
 	struct ena_adapter *adapter = ifp->if_softc;
 	struct ena_ring *tx_ring;
 	int ret, is_drbr_empty;
 	uint32_t i;
 
 	if ((adapter->ifp->if_drv_flags & IFF_DRV_RUNNING) == 0)
 		return (ENODEV);
 
 	/* Which queue to use */
 	/*
 	 * If everything is setup correctly, it should be the
 	 * same bucket that the current CPU we're on is.
 	 * It should improve performance.
 	 */
 	if (M_HASHTYPE_GET(m) != M_HASHTYPE_NONE) {
 #ifdef	RSS
 		if (rss_hash2bucket(m->m_pkthdr.flowid,
 		    M_HASHTYPE_GET(m), &i) == 0) {
 			i = i % adapter->num_queues;
 
 		} else
 #endif
 		{
 			i = m->m_pkthdr.flowid % adapter->num_queues;
 		}
 	} else {
 		i = curcpu % adapter->num_queues;
 	}
 	tx_ring = &adapter->tx_ring[i];
 
 	/* Check if drbr is empty before putting packet */
 	is_drbr_empty = drbr_empty(ifp, tx_ring->br);
 	ret = drbr_enqueue(ifp, tx_ring->br, m);
 	if (ret) {
 		taskqueue_enqueue(tx_ring->enqueue_tq, &tx_ring->enqueue_task);
 		return (ret);
 	}
 
 	if (is_drbr_empty && ENA_RING_MTX_TRYLOCK(tx_ring)) {
 		ena_start_xmit(tx_ring);
 		ENA_RING_MTX_UNLOCK(tx_ring);
 	} else {
 		taskqueue_enqueue(tx_ring->enqueue_tq, &tx_ring->enqueue_task);
 	}
 
 	return (0);
 }
 
 static void
 ena_qflush(if_t ifp)
 {
 	struct ena_adapter *adapter = ifp->if_softc;
 	struct ena_ring *tx_ring = adapter->tx_ring;
 	int i;
 
 	for(i = 0; i < adapter->num_queues; ++i, ++tx_ring)
 		if (drbr_empty(ifp, tx_ring->br) == FALSE) {
 			ENA_RING_MTX_LOCK(tx_ring);
 			drbr_flush(ifp, tx_ring->br);
 			ENA_RING_MTX_UNLOCK(tx_ring);
 		}
 
 	if_qflush(ifp);
 
 	return;
 }
 
 static int ena_calc_io_queue_num(struct ena_adapter *adapter,
     struct ena_com_dev_get_features_ctx *get_feat_ctx)
 {
 	int io_sq_num, io_cq_num, io_queue_num;
 
 	io_sq_num = get_feat_ctx->max_queues.max_sq_num;
 	io_cq_num = get_feat_ctx->max_queues.max_sq_num;
 
 	io_queue_num = min_t(int, mp_ncpus, ENA_MAX_NUM_IO_QUEUES);
 	io_queue_num = min_t(int, io_queue_num, io_sq_num);
 	io_queue_num = min_t(int, io_queue_num, io_cq_num);
 	/* 1 IRQ for for mgmnt and 1 IRQ for each TX/RX pair */
 	io_queue_num = min_t(int, io_queue_num,
 	    pci_msix_count(adapter->pdev) - 1);
 #ifdef	RSS
 	io_queue_num = min_t(int, io_queue_num, rss_getnumbuckets());
 #endif
 
 	return io_queue_num;
 }
 
 static int ena_calc_queue_size(struct ena_adapter *adapter,
     uint16_t *max_tx_sgl_size,  uint16_t *max_rx_sgl_size,
     struct ena_com_dev_get_features_ctx *feat)
 {
 	uint32_t queue_size = ENA_DEFAULT_RING_SIZE;
 	uint32_t v;
 	uint32_t q;
 
 	queue_size = min_t(uint32_t, queue_size,
 	    feat->max_queues.max_cq_depth);
 	queue_size = min_t(uint32_t, queue_size,
 	    feat->max_queues.max_sq_depth);
 
 	/* round down to the nearest power of 2 */
 	v = queue_size;
 	while (v != 0) {
 		if (powerof2(queue_size))
 			break;
 		v /= 2;
 		q = rounddown2(queue_size, v);
 		if (q != 0) {
 			queue_size = q;
 			break;
 		}
 	}
 
 	if (unlikely(!queue_size)) {
 		device_printf(adapter->pdev, "Invalid queue size\n");
 		return ENA_COM_FAULT;
 	}
 
 	*max_tx_sgl_size = min_t(uint16_t, ENA_PKT_MAX_BUFS,
 	    feat->max_queues.max_packet_tx_descs);
 	*max_rx_sgl_size = min_t(uint16_t, ENA_PKT_MAX_BUFS,
 	    feat->max_queues.max_packet_rx_descs);
 
 	return queue_size;
 }
 
 static int ena_rss_init_default(struct ena_adapter *adapter)
 {
 	struct ena_com_dev *ena_dev = adapter->ena_dev;
 	device_t dev = adapter->pdev;
 	int qid, rc, i;
 
 	rc = ena_com_rss_init(ena_dev, ENA_RX_RSS_TABLE_LOG_SIZE);
 	if (unlikely(rc)) {
 		device_printf(dev, "Cannot init RSS\n");
 		goto err_rss_init;
 	}
 
 	for (i = 0; i < ENA_RX_RSS_TABLE_SIZE; i++) {
 #ifdef	RSS
 		qid = rss_get_indirection_to_bucket(i);
 		qid = qid % adapter->num_queues;
 #else
 		qid = i % adapter->num_queues;
 #endif
 		rc = ena_com_indirect_table_fill_entry(ena_dev, i,
 						       ENA_IO_RXQ_IDX(qid));
 		if (unlikely(rc && (rc != EOPNOTSUPP))) {
 			device_printf(dev, "Cannot fill indirect table\n");
 			goto err_fill_indir;
 		}
 	}
 
 	rc = ena_com_fill_hash_function(ena_dev, ENA_ADMIN_CRC32, NULL,
 					ENA_HASH_KEY_SIZE, 0xFFFFFFFF);
 	if (unlikely(rc && (rc != EOPNOTSUPP))) {
 		device_printf(dev, "Cannot fill hash function\n");
 		goto err_fill_indir;
 	}
 
 	rc = ena_com_set_default_hash_ctrl(ena_dev);
 	if (unlikely(rc && (rc != EOPNOTSUPP))) {
 		device_printf(dev, "Cannot fill hash control\n");
 		goto err_fill_indir;
 	}
 
 	return (0);
 
 err_fill_indir:
 	ena_com_rss_destroy(ena_dev);
 err_rss_init:
 	return (rc);
 }
 
 static void
 ena_rss_init_default_deferred(void *arg)
 {
 	struct ena_adapter *adapter;
 	devclass_t dc;
 	int max;
 	int rc;
 
 	dc = devclass_find("ena");
 	if (dc == NULL) {
 		ena_trace(ENA_DBG, "No devclass ena\n");
 		return;
 	}
 
 	max = devclass_get_maxunit(dc);
 	while (max-- >= 0) {
 		adapter = devclass_get_softc(dc, max);
 		if (adapter != NULL) {
 			rc = ena_rss_init_default(adapter);
 			adapter->rss_support = true;
 			if (rc) {
 				device_printf(adapter->pdev,
 				    "WARNING: RSS was not properly initialized,"
 				    " it will affect bandwith\n");
 				adapter->rss_support = false;
 			}
 		}
 	}
 }
 SYSINIT(ena_rss_init, SI_SUB_KICK_SCHEDULER, SI_ORDER_SECOND, ena_rss_init_default_deferred, NULL);
 
 static void ena_config_host_info(struct ena_com_dev *ena_dev)
 {
 	struct ena_admin_host_info *host_info;
 	int rc;
 
 	/* Allocate only the host info */
 	rc = ena_com_allocate_host_info(ena_dev);
 	if (rc) {
 		ena_trace(ENA_ALERT, "Cannot allocate host info\n");
 		return;
 	}
 
 	host_info = ena_dev->host_attr.host_info;
 
 	host_info->os_type = ENA_ADMIN_OS_FREEBSD;
 	host_info->kernel_ver = osreldate;
 
 	sprintf(host_info->kernel_ver_str, "%d", osreldate);
 	host_info->os_dist = 0;
 	strncpy(host_info->os_dist_str, osrelease,
 	    sizeof(host_info->os_dist_str) - 1);
 
 	host_info->driver_version =
 		(DRV_MODULE_VER_MAJOR) |
 		(DRV_MODULE_VER_MINOR << ENA_ADMIN_HOST_INFO_MINOR_SHIFT) |
 		(DRV_MODULE_VER_SUBMINOR << ENA_ADMIN_HOST_INFO_SUB_MINOR_SHIFT);
 
 	rc = ena_com_set_host_attributes(ena_dev);
 	if (rc) {
 		if (rc == EOPNOTSUPP)
 			ena_trace(ENA_WARNING, "Cannot set host attributes\n");
 		else
 			ena_trace(ENA_ALERT, "Cannot set host attributes\n");
 
 		goto err;
 	}
 
 	return;
 
 err:
 	ena_com_delete_host_info(ena_dev);
 }
 
 static int
 ena_device_init(struct ena_adapter *adapter, device_t pdev,
 	struct ena_com_dev_get_features_ctx *get_feat_ctx, int *wd_active)
 {
 	struct ena_com_dev* ena_dev = adapter->ena_dev;
 	bool readless_supported;
 	uint32_t aenq_groups;
 	int dma_width;
 	int rc;
 
 	rc = ena_com_mmio_reg_read_request_init(ena_dev);
 	if (rc) {
 		device_printf(pdev, "failed to init mmio read less\n");
 		return rc;
 	}
 
 	/*
 	 * The PCIe configuration space revision id indicate if mmio reg
 	 * read is disabled
 	 */
 	readless_supported = !(pci_get_revid(pdev) & ENA_MMIO_DISABLE_REG_READ);
 	ena_com_set_mmio_read_mode(ena_dev, readless_supported);
 
 	rc = ena_com_dev_reset(ena_dev, ENA_REGS_RESET_NORMAL);
 	if (rc) {
 		device_printf(pdev, "Can not reset device\n");
 		goto err_mmio_read_less;
 	}
 
 	rc = ena_com_validate_version(ena_dev);
 	if (rc) {
 		device_printf(pdev, "device version is too low\n");
 		goto err_mmio_read_less;
 	}
 
 	dma_width = ena_com_get_dma_width(ena_dev);
 	if (dma_width < 0) {
 		device_printf(pdev, "Invalid dma width value %d", dma_width);
 		rc = dma_width;
 		goto err_mmio_read_less;
 	}
 	adapter->dma_width = dma_width;
 
 	/* ENA admin level init */
 	rc = ena_com_admin_init(ena_dev, &aenq_handlers, true);
 	if (rc) {
 		device_printf(pdev,
 		    "Can not initialize ena admin queue with device\n");
 		goto err_mmio_read_less;
 	}
 
 	/*
 	 * To enable the msix interrupts the driver needs to know the number
 	 * of queues. So the driver uses polling mode to retrieve this
 	 * information
 	 */
 	ena_com_set_admin_polling_mode(ena_dev, true);
 
 	ena_config_host_info(ena_dev);
 
 	/* Get Device Attributes */
 	rc = ena_com_get_dev_attr_feat(ena_dev, get_feat_ctx);
 	if (rc) {
 		device_printf(pdev,
 		    "Cannot get attribute for ena device rc: %d\n", rc);
 		goto err_admin_init;
 	}
 
 	aenq_groups = BIT(ENA_ADMIN_LINK_CHANGE) |
 	    BIT(ENA_ADMIN_FATAL_ERROR) |
 	    BIT(ENA_ADMIN_WARNING) |
 	    BIT(ENA_ADMIN_NOTIFICATION) |
 	    BIT(ENA_ADMIN_KEEP_ALIVE);
 
 	aenq_groups &= get_feat_ctx->aenq.supported_groups;
 	rc = ena_com_set_aenq_config(ena_dev, aenq_groups);
 	if (rc) {
 		device_printf(pdev, "Cannot configure aenq groups rc: %d\n", rc);
 		goto err_admin_init;
 	}
 
 	*wd_active = !!(aenq_groups & BIT(ENA_ADMIN_KEEP_ALIVE));
 
 	return 0;
 
 err_admin_init:
 	ena_com_delete_host_info(ena_dev);
 	ena_com_admin_destroy(ena_dev);
 err_mmio_read_less:
 	ena_com_mmio_reg_read_request_destroy(ena_dev);
 
 	return rc;
 }
 
 static int ena_enable_msix_and_set_admin_interrupts(struct ena_adapter *adapter,
     int io_vectors)
 {
 	struct ena_com_dev *ena_dev = adapter->ena_dev;
 	int rc;
 
 	rc = ena_enable_msix(adapter);
 	if (rc) {
 		device_printf(adapter->pdev, "Error with MSI-X enablement\n");
 		return rc;
 	}
 
 	ena_setup_mgmnt_intr(adapter);
 
 	rc = ena_request_mgmnt_irq(adapter);
 	if (rc) {
 		device_printf(adapter->pdev, "Cannot setup mgmnt queue intr\n");
 		goto err_disable_msix;
 	}
 
 	ena_com_set_admin_polling_mode(ena_dev, false);
 
 	ena_com_admin_aenq_enable(ena_dev);
 
 	return 0;
 
 err_disable_msix:
 	ena_disable_msix(adapter);
 
 	return rc;
 }
 
 /* Function called on ENA_ADMIN_KEEP_ALIVE event */
 static void ena_keep_alive_wd(void *adapter_data,
     struct ena_admin_aenq_entry *aenq_e)
 {
 	struct ena_adapter *adapter = (struct ena_adapter *)adapter_data;
+	struct ena_admin_aenq_keep_alive_desc *desc;
 	sbintime_t stime;
+	uint64_t rx_drops;
+
+	desc = (struct ena_admin_aenq_keep_alive_desc *)aenq_e;
+
+	rx_drops = ((uint64_t)desc->rx_drops_high << 32) | desc->rx_drops_low;
+	counter_u64_zero(adapter->hw_stats.rx_drops);
+	counter_u64_add(adapter->hw_stats.rx_drops, rx_drops);
 
 	stime = getsbinuptime();
 	atomic_store_rel_64(&adapter->keep_alive_timestamp, stime);
 }
 
 /* Check for keep alive expiration */
 static void check_for_missing_keep_alive(struct ena_adapter *adapter)
 {
 	sbintime_t timestamp, time;
 
 	if (adapter->wd_active == 0)
 		return;
 
 	if (adapter->keep_alive_timeout == 0)
 		return;
 
 	timestamp = atomic_load_acq_64(&adapter->keep_alive_timestamp);
 	time = getsbinuptime() - timestamp;
 	if (unlikely(time > adapter->keep_alive_timeout)) {
 		device_printf(adapter->pdev,
 		    "Keep alive watchdog timeout.\n");
 		counter_u64_add(adapter->dev_stats.wd_expired, 1);
 		adapter->reset_reason = ENA_REGS_RESET_KEEP_ALIVE_TO;
 		adapter->trigger_reset = true;
 	}
 }
 
 /* Check if admin queue is enabled */
 static void check_for_admin_com_state(struct ena_adapter *adapter)
 {
 	if (unlikely(!ena_com_get_admin_running_state(adapter->ena_dev))) {
 		device_printf(adapter->pdev,
 		    "ENA admin queue is not in running state!\n");
 		counter_u64_add(adapter->dev_stats.admin_q_pause, 1);
 		adapter->reset_reason = ENA_REGS_RESET_ADMIN_TO;
 		adapter->trigger_reset = true;
 	}
 }
 
 /*
  * Check for TX which were not completed on time.
  * Timeout is defined by "missing_tx_timeout".
  * Reset will be performed if number of incompleted
  * transactions exceeds "missing_tx_threshold".
  */
 static void check_for_missing_tx_completions(struct ena_adapter *adapter)
 {
 	struct ena_ring *tx_ring;
 	struct ena_tx_buffer *tx_info;
 	struct bintime curtime, time;
 	int i, j, budget, missed_tx;
 
 	/* Make sure the driver doesn't turn the device in other process */
 	rmb();
 
 	if (!adapter->up)
 		return;
 
 	if (adapter->trigger_reset)
 		return;
 
 	if (adapter->missing_tx_timeout == 0)
 		return;
 
 	budget = adapter->missing_tx_max_queues;
 	getbinuptime(&curtime);
 
 	for (i = adapter->next_monitored_tx_qid; i < adapter->num_queues; i++) {
 		tx_ring = &adapter->tx_ring[i];
 
 		missed_tx = 0;
 
 		for (j = 0; j < tx_ring->ring_size; j++) {
 			tx_info = &tx_ring->tx_buffer_info[j];
 
 			if (!bintime_isset(&tx_info->timestamp))
 				continue;
 
 			time = curtime;
 			bintime_sub(&time, &tx_info->timestamp);
 
 			/* Check again if packet is still waiting */
 			if (bintime_isset(&tx_info->timestamp) && unlikely(
 			    bttosbt(time) > adapter->missing_tx_timeout)) {
 				if (tx_info->print_once)
 					device_printf(adapter->pdev,
 					    "Found a Tx that wasn't completed "
 					    "on time, qid %d, index %d.\n",
 					    tx_ring->qid, j);
 
 				tx_info->print_once = false;
 				missed_tx++;
 
 				if (unlikely(missed_tx >
 				    adapter->missing_tx_threshold)) {
 					device_printf(adapter->pdev,
 					    "The number of lost tx completion "
 					    "is above the threshold (%d > %d). "
 					    "Reset the device\n", missed_tx,
 					    adapter->missing_tx_threshold);
 					adapter->reset_reason =
 					    ENA_REGS_RESET_MISS_TX_CMPL;
 					adapter->trigger_reset = true;
 					return;
 				}
 			}
 		}
 
 		budget--;
 		if (!budget) {
 			i++;
 			break;
 		}
 	}
 
 	adapter->next_monitored_tx_qid = i % adapter->num_queues;
 }
 
 
 static void
 ena_timer_service(void *data)
 {
 	struct ena_adapter *adapter = (struct ena_adapter *)data;
 	struct ena_admin_host_info *host_info =
 	    adapter->ena_dev->host_attr.host_info;
 
 	check_for_missing_keep_alive(adapter);
 
 	check_for_admin_com_state(adapter);
 
 	check_for_missing_tx_completions(adapter);
 
 	if (host_info)
 		ena_update_host_info(host_info, adapter->ifp);
 
 	if (unlikely(adapter->trigger_reset)) {
 		device_printf(adapter->pdev, "Trigger reset is on\n");
 		taskqueue_enqueue(adapter->reset_tq, &adapter->reset_task);
 		return;
 	}
 
 	/*
 	 * Schedule another timeout one second from now.
 	 */
 	callout_schedule_sbt(&adapter->timer_service, SBT_1S, SBT_1S, 0);
 }
 
 static void
 ena_reset_task(void *arg, int pending)
 {
 	struct ena_com_dev_get_features_ctx get_feat_ctx;
 	struct ena_adapter *adapter = (struct ena_adapter *)arg;
 	struct ena_com_dev *ena_dev = adapter->ena_dev;
 	bool dev_up;
 	int rc;
 
 	if (unlikely(!adapter->trigger_reset)) {
 		device_printf(adapter->pdev,
 		    "device reset scheduled but trigger_reset is off\n");
 		return;
 	}
 
 	sx_xlock(&adapter->ioctl_sx);
 
 	callout_drain(&adapter->timer_service);
 
 	dev_up = adapter->up;
 
 	ena_com_set_admin_running_state(ena_dev, false);
 	ena_down(adapter);
 	ena_free_mgmnt_irq(adapter);
 	ena_disable_msix(adapter);
 	ena_com_abort_admin_commands(ena_dev);
 	ena_com_wait_for_abort_completion(ena_dev);
 	ena_com_admin_destroy(ena_dev);
 	ena_com_mmio_reg_read_request_destroy(ena_dev);
 
 	adapter->reset_reason = ENA_REGS_RESET_NORMAL;
 	adapter->trigger_reset = false;
 
 	/* Finished destroy part. Restart the device */
 	rc = ena_device_init(adapter, adapter->pdev, &get_feat_ctx,
 	    &adapter->wd_active);
 	if (rc) {
 		device_printf(adapter->pdev,
 		    "ENA device init failed! (err: %d)\n", rc);
 		goto err_dev_free;
 	}
 
 	rc = ena_enable_msix_and_set_admin_interrupts(adapter,
 	    adapter->num_queues);
 	if (rc) {
 		device_printf(adapter->pdev, "Enable MSI-X failed\n");
 		goto err_com_free;
 	}
 
 	/* If the interface was up before the reset bring it up */
 	if (dev_up) {
 		rc = ena_up(adapter);
 		if (rc) {
 			device_printf(adapter->pdev,
 			    "Failed to create I/O queues\n");
 			goto err_msix_free;
 		}
 	}
 
 	callout_reset_sbt(&adapter->timer_service, SBT_1S, SBT_1S,
 	    ena_timer_service, (void *)adapter, 0);
 
 	sx_unlock(&adapter->ioctl_sx);
 
 	return;
 
 err_msix_free:
 	ena_free_mgmnt_irq(adapter);
 	ena_disable_msix(adapter);
 err_com_free:
 	ena_com_admin_destroy(ena_dev);
 err_dev_free:
 	device_printf(adapter->pdev, "ENA reset failed!\n");
 	adapter->running = false;
 	sx_unlock(&adapter->ioctl_sx);
 }
 
 /**
  * ena_attach - Device Initialization Routine
  * @pdev: device information struct
  *
  * Returns 0 on success, otherwise on failure.
  *
  * ena_attach initializes an adapter identified by a device structure.
  * The OS initialization, configuring of the adapter private structure,
  * and a hardware reset occur.
  **/
 static int
 ena_attach(device_t pdev)
 {
 	struct ena_com_dev_get_features_ctx get_feat_ctx;
 	static int version_printed;
 	struct ena_adapter *adapter;
 	struct ena_com_dev *ena_dev = NULL;
 	uint16_t tx_sgl_size = 0;
 	uint16_t rx_sgl_size = 0;
 	int io_queue_num;
 	int queue_size;
 	int rc;
 	struct sysctl_ctx_list *ctx;
 	struct sysctl_oid_list *children;
 
 	adapter = device_get_softc(pdev);
 	adapter->pdev = pdev;
 	ctx = device_get_sysctl_ctx(pdev);
 	children = SYSCTL_CHILDREN(device_get_sysctl_tree(pdev));
 
 	mtx_init(&adapter->global_mtx, "ENA global mtx", NULL, MTX_DEF);
 	sx_init(&adapter->ioctl_sx, "ENA ioctl sx");
 
 	/* Sysctl calls for Watchdog service */
 	SYSCTL_ADD_INT(ctx, children, OID_AUTO, "wd_active",
 	    CTLFLAG_RWTUN, &adapter->wd_active, 0,
 	    "Watchdog is active");
 
 	SYSCTL_ADD_QUAD(ctx, children, OID_AUTO, "keep_alive_timeout",
 	    CTLFLAG_RWTUN, &adapter->keep_alive_timeout,
 	    "Timeout for Keep Alive messages");
 
 	SYSCTL_ADD_QUAD(ctx, children, OID_AUTO, "missing_tx_timeout",
 	    CTLFLAG_RWTUN, &adapter->missing_tx_timeout,
 	    "Timeout for TX completion");
 
 	SYSCTL_ADD_U32(ctx, children, OID_AUTO, "missing_tx_max_queues",
 	    CTLFLAG_RWTUN, &adapter->missing_tx_max_queues, 0,
 	    "Number of TX queues to check per run");
 
 	SYSCTL_ADD_U32(ctx, children, OID_AUTO, "missing_tx_threshold",
 	    CTLFLAG_RWTUN, &adapter->missing_tx_threshold, 0,
 	    "Max number of timeouted packets");
 
 	/* Set up the timer service */
 	callout_init_mtx(&adapter->timer_service, &adapter->global_mtx, 0);
 	adapter->keep_alive_timeout = DEFAULT_KEEP_ALIVE_TO;
 	adapter->missing_tx_timeout = DEFAULT_TX_CMP_TO;
 	adapter->missing_tx_max_queues = DEFAULT_TX_MONITORED_QUEUES;
 	adapter->missing_tx_threshold = DEFAULT_TX_CMP_THRESHOLD;
 
 	if (version_printed++ == 0)
 		device_printf(pdev, "%s\n", ena_version);
 
 	rc = ena_allocate_pci_resources(adapter);
 	if (rc) {
 		device_printf(pdev, "PCI resource allocation failed!\n");
 		ena_free_pci_resources(adapter);
 		goto err_pci_res;
 	}
 
 	/* Allocate memory for ena_dev structure */
 	ena_dev = ENA_MEM_ALLOC(pdev, sizeof(struct ena_com_dev));
 	if (!ena_dev) {
 		device_printf(pdev, "allocating ena_dev failed\n");
 		rc = ENOMEM;
 		goto err_select_region;
 	}
 
 	adapter->ena_dev = ena_dev;
 	ena_dev->dmadev = pdev;
 	ena_dev->bus = malloc(sizeof(struct ena_bus), M_DEVBUF,
 	    M_WAITOK | M_ZERO);
 
 	/* Store register resources */
 	((struct ena_bus*)(ena_dev->bus))->reg_bar_t =
 	    rman_get_bustag(adapter->registers);
 	((struct ena_bus*)(ena_dev->bus))->reg_bar_h =
 	    rman_get_bushandle(adapter->registers);
 
 	if (((struct ena_bus*)(ena_dev->bus))->reg_bar_h == 0) {
 		device_printf(pdev, "failed to pmap registers bar\n");
 		rc = ENXIO;
 		goto err_dev_free;
 	}
 
 	ena_dev->tx_mem_queue_type = ENA_ADMIN_PLACEMENT_POLICY_HOST;
 
 	/* Device initialization */
 	rc = ena_device_init(adapter, pdev, &get_feat_ctx, &adapter->wd_active);
 	if (rc) {
 		device_printf(pdev, "ENA device init failed! (err: %d)\n", rc);
 		rc = ENXIO;
 		goto err_bus_free;
 	}
 
 	adapter->keep_alive_timestamp = getsbinuptime();
 
 	adapter->tx_offload_cap = get_feat_ctx.offload.tx;
 
 	/* Set for sure that interface is not up */
 	adapter->up = false;
 
 	memcpy(adapter->mac_addr, get_feat_ctx.dev_attr.mac_addr,
 	    ETHER_ADDR_LEN);
 
 	adapter->small_copy_len =
 	    ENA_DEFAULT_SMALL_PACKET_LEN;
 
 	/* calculate IO queue number to create */
 	io_queue_num = ena_calc_io_queue_num(adapter, &get_feat_ctx);
 
 	ENA_ASSERT(io_queue_num > 0, "Invalid queue number: %d\n",
 	    io_queue_num);
 	adapter->num_queues = io_queue_num;
 
 	/* calculatre ring sizes */
 	queue_size = ena_calc_queue_size(adapter,&tx_sgl_size,
 	    &rx_sgl_size, &get_feat_ctx);
 	if ((queue_size <= 0) || (io_queue_num <= 0)) {
 		rc = ENA_COM_FAULT;
 		goto err_com_free;
 	}
 
 	adapter->reset_reason = ENA_REGS_RESET_NORMAL;
 
 	adapter->tx_ring_size = queue_size;
 	adapter->rx_ring_size = queue_size;
 
 	adapter->max_tx_sgl_size = tx_sgl_size;
 	adapter->max_rx_sgl_size = rx_sgl_size;
 
 	/* set up dma tags for rx and tx buffers */
 	rc = ena_setup_tx_dma_tag(adapter);
 	if (rc)
 		goto dma_tx_err;
 
 	rc = ena_setup_rx_dma_tag(adapter);
 	if (rc)
 		goto dma_rx_err;
 
 	/* initialize rings basic information */
 	device_printf(pdev, "initalize %d io queues\n", io_queue_num);
 	rc = ena_init_io_rings(adapter);
 	if (rc) {
 		device_printf(pdev,"Error with initialization of IO rings\n");
 		goto err_io_init;
 	}
 
 	/* setup network interface */
 	rc = ena_setup_ifnet(pdev, adapter, &get_feat_ctx);
 	if (rc) {
 		device_printf(pdev,"Error with network interface setup\n");
 		goto err_com_free;
 	}
 
 	rc = ena_enable_msix_and_set_admin_interrupts(adapter, io_queue_num);
 	if (rc) {
 		device_printf(pdev,
 		    "Failed to enable and set the admin interrupts\n");
 		goto err_ifp_free;
 	}
 
 	/* Initialize reset task queue */
 	TASK_INIT(&adapter->reset_task, 0, ena_reset_task, adapter);
 	adapter->reset_tq = taskqueue_create("ena_reset_enqueue",
 	    M_WAITOK | M_ZERO, taskqueue_thread_enqueue, &adapter->reset_tq);
 	if (adapter->reset_tq == NULL) {
 		device_printf(adapter->pdev,
 		    "Unable to create reset task queue\n");
 		goto err_reset_tq;
 	}
 	taskqueue_start_threads(&adapter->reset_tq, 1, PI_NET,
 	    "%s rstq", device_get_nameunit(adapter->pdev));
 
-	/* Initialize task queue responsible for updating hw stats */
-	TASK_INIT(&adapter->stats_task, 0, ena_update_hw_stats, adapter);
-	adapter->stats_tq = taskqueue_create_fast("ena_stats_update",
-	    M_WAITOK | M_ZERO, taskqueue_thread_enqueue, &adapter->stats_tq);
-	if (adapter->stats_tq == NULL) {
-		device_printf(adapter->pdev,
-		    "Unable to create taskqueue for updating hw stats\n");
-		goto err_stats_tq;
-	}
-	taskqueue_start_threads(&adapter->stats_tq, 1, PI_REALTIME,
-	    "%s stats tq", device_get_nameunit(adapter->pdev));
-
 	/* Initialize statistics */
 	ena_alloc_counters((counter_u64_t *)&adapter->dev_stats,
 	    sizeof(struct ena_stats_dev));
-	ena_update_stats_counters(adapter);
+	ena_alloc_counters((counter_u64_t *)&adapter->hw_stats,
+	    sizeof(struct ena_hw_stats));
 	ena_sysctl_add_nodes(adapter);
 
 	/* Tell the stack that the interface is not active */
 	if_setdrvflagbits(adapter->ifp, IFF_DRV_OACTIVE, IFF_DRV_RUNNING);
 
 	adapter->running = true;
 	return (0);
 
-err_stats_tq:
-	taskqueue_free(adapter->reset_tq);
 err_reset_tq:
 	ena_com_dev_reset(ena_dev, ENA_REGS_RESET_INIT_ERR);
 	ena_free_mgmnt_irq(adapter);
 	ena_disable_msix(adapter);
 err_ifp_free:
 	if_detach(adapter->ifp);
 	if_free(adapter->ifp);
 err_com_free:
 	ena_free_all_io_rings_resources(adapter);
 err_io_init:
 	ena_free_rx_dma_tag(adapter);
 dma_rx_err:
 	ena_free_tx_dma_tag(adapter);
 dma_tx_err:
 	ena_com_admin_destroy(ena_dev);
 	ena_com_delete_host_info(ena_dev);
 err_bus_free:
 	free(ena_dev->bus, M_DEVBUF);
 err_dev_free:
 	free(ena_dev, M_DEVBUF);
 err_select_region:
 	ena_free_pci_resources(adapter);
 err_pci_res:
 	return (rc);
 }
 
 /**
  * ena_detach - Device Removal Routine
  * @pdev: device information struct
  *
  * ena_detach is called by the device subsystem to alert the driver
  * that it should release a PCI device.
  **/
 static int
 ena_detach(device_t pdev)
 {
 	struct ena_adapter *adapter = device_get_softc(pdev);
 	struct ena_com_dev *ena_dev = adapter->ena_dev;
 	int rc;
 
 	/* Make sure VLANS are not using driver */
 	if (adapter->ifp->if_vlantrunk != NULL) {
 		device_printf(adapter->pdev ,"VLAN is in use, detach first\n");
 		return (EBUSY);
 	}
 
 	/* Free reset task and callout */
 	callout_drain(&adapter->timer_service);
 	while (taskqueue_cancel(adapter->reset_tq, &adapter->reset_task, NULL))
 		taskqueue_drain(adapter->reset_tq, &adapter->reset_task);
 	taskqueue_free(adapter->reset_tq);
 
 	sx_xlock(&adapter->ioctl_sx);
 	ena_down(adapter);
 	sx_unlock(&adapter->ioctl_sx);
 
-	taskqueue_free(adapter->stats_tq);
-
 	if (adapter->ifp != NULL) {
 		ether_ifdetach(adapter->ifp);
 		if_free(adapter->ifp);
 	}
 
 	ena_free_all_io_rings_resources(adapter);
 
+	ena_free_counters((counter_u64_t *)&adapter->hw_stats,
+	    sizeof(struct ena_hw_stats));
 	ena_free_counters((counter_u64_t *)&adapter->dev_stats,
 	    sizeof(struct ena_stats_dev));
 
 	if (adapter->rss_support)
 		ena_com_rss_destroy(ena_dev);
 
 	rc = ena_free_rx_dma_tag(adapter);
 	if (rc)
 		device_printf(adapter->pdev,
 		    "Unmapped RX DMA tag associations\n");
 
 	rc = ena_free_tx_dma_tag(adapter);
 	if (rc)
 		device_printf(adapter->pdev,
 		    "Unmapped TX DMA tag associations\n");
 
 	/* Reset the device only if the device is running. */
 	if (adapter->running)
 		ena_com_dev_reset(ena_dev, adapter->reset_reason);
 
 	ena_com_delete_host_info(ena_dev);
 
 	ena_com_admin_destroy(ena_dev);
 
 	ena_free_irqs(adapter);
 
 	ena_com_mmio_reg_read_request_destroy(ena_dev);
 
 	ena_free_pci_resources(adapter);
 
 	mtx_destroy(&adapter->global_mtx);
 	sx_destroy(&adapter->ioctl_sx);
 
 	if (ena_dev->bus != NULL)
 		free(ena_dev->bus, M_DEVBUF);
 
 	if (ena_dev != NULL)
 		free(ena_dev, M_DEVBUF);
 
 	return (bus_generic_detach(pdev));
 }
 
 /******************************************************************************
  ******************************** AENQ Handlers *******************************
  *****************************************************************************/
 /**
  * ena_update_on_link_change:
  * Notify the network interface about the change in link status
  **/
 static void
 ena_update_on_link_change(void *adapter_data,
     struct ena_admin_aenq_entry *aenq_e)
 {
 	struct ena_adapter *adapter = (struct ena_adapter *)adapter_data;
 	struct ena_admin_aenq_link_change_desc *aenq_desc;
 	int status;
 	if_t ifp;
 
 	aenq_desc = (struct ena_admin_aenq_link_change_desc *)aenq_e;
 	ifp = adapter->ifp;
 	status = aenq_desc->flags &
 	    ENA_ADMIN_AENQ_LINK_CHANGE_DESC_LINK_STATUS_MASK;
 
 	if (status != 0) {
 		device_printf(adapter->pdev, "link is UP\n");
 		if_link_state_change(ifp, LINK_STATE_UP);
 	} else if (status == 0) {
 		device_printf(adapter->pdev, "link is DOWN\n");
 		if_link_state_change(ifp, LINK_STATE_DOWN);
 	} else {
 		device_printf(adapter->pdev, "invalid value recvd\n");
 		BUG();
 	}
 
 	adapter->link_status = status;
 
 	return;
 }
 
 /**
  * This handler will called for unknown event group or unimplemented handlers
  **/
 static void
 unimplemented_aenq_handler(void *data,
     struct ena_admin_aenq_entry *aenq_e)
 {
 	return;
 }
 
 static struct ena_aenq_handlers aenq_handlers = {
     .handlers = {
 	    [ENA_ADMIN_LINK_CHANGE] = ena_update_on_link_change,
 	    [ENA_ADMIN_KEEP_ALIVE] = ena_keep_alive_wd,
     },
     .unimplemented_handler = unimplemented_aenq_handler
 };
 
 /*********************************************************************
  *  FreeBSD Device Interface Entry Points
  *********************************************************************/
 
 static device_method_t ena_methods[] = {
     /* Device interface */
     DEVMETHOD(device_probe, ena_probe),
     DEVMETHOD(device_attach, ena_attach),
     DEVMETHOD(device_detach, ena_detach),
     DEVMETHOD_END
 };
 
 static driver_t ena_driver = {
     "ena", ena_methods, sizeof(struct ena_adapter),
 };
 
 devclass_t ena_devclass;
 DRIVER_MODULE(ena, pci, ena_driver, ena_devclass, 0, 0);
 MODULE_DEPEND(ena, pci, 1, 1, 1);
 MODULE_DEPEND(ena, ether, 1, 1, 1);
 
 /*********************************************************************/
diff --git a/sys/dev/ena/ena.h b/sys/dev/ena/ena.h
index a7f273c97c2e..6ab468ceb9b3 100644
--- a/sys/dev/ena/ena.h
+++ b/sys/dev/ena/ena.h
@@ -1,442 +1,436 @@
 /*-
  * BSD LICENSE
  *
  * Copyright (c) 2015-2017 Amazon.com, Inc. or its affiliates.
  * 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.
  *
  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT
  * OWNER 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.
  *
  * $FreeBSD$
  *
  */
 
 #ifndef ENA_H
 #define ENA_H
 
 #include <sys/types.h>
 
 #include "ena-com/ena_com.h"
 #include "ena-com/ena_eth_com.h"
 
 #define DRV_MODULE_VER_MAJOR	0
 #define DRV_MODULE_VER_MINOR	8
 #define DRV_MODULE_VER_SUBMINOR 0
 
 #define DRV_MODULE_NAME		"ena"
 
 #ifndef DRV_MODULE_VERSION
 #define DRV_MODULE_VERSION				\
 	__XSTRING(DRV_MODULE_VER_MAJOR) "."		\
 	__XSTRING(DRV_MODULE_VER_MINOR) "."		\
 	__XSTRING(DRV_MODULE_VER_SUBMINOR)
 #endif
 #define DEVICE_NAME	"Elastic Network Adapter (ENA)"
 #define DEVICE_DESC	"ENA adapter"
 
 /* Calculate DMA mask - width for ena cannot exceed 48, so it is safe */
 #define ENA_DMA_BIT_MASK(x)		((1ULL << (x)) - 1ULL)
 
 /* 1 for AENQ + ADMIN */
 #define	ENA_MAX_MSIX_VEC(io_queues)	(1 + (io_queues))
 
 #define	ENA_REG_BAR			0
 #define	ENA_MEM_BAR			2
 
 #define	ENA_BUS_DMA_SEGS		32
 
 #define	ENA_DEFAULT_RING_SIZE		1024
 #define	ENA_DEFAULT_SMALL_PACKET_LEN	128
 #define	ENA_DEFAULT_MAX_RX_BUFF_ALLOC_SIZE	1536
 
 #define	ENA_RX_REFILL_THRESH_DEVIDER	8
 
 #define	ENA_MAX_PUSH_PKT_SIZE		128
 
 #define	ENA_NAME_MAX_LEN		20
 #define	ENA_IRQNAME_SIZE		40
 
 #define	ENA_PKT_MAX_BUFS 		19
 #define	ENA_STALL_TIMEOUT		100
 
 #define	ENA_RX_RSS_TABLE_LOG_SIZE	7
 #define	ENA_RX_RSS_TABLE_SIZE		(1 << ENA_RX_RSS_TABLE_LOG_SIZE)
 
 #define	ENA_HASH_KEY_SIZE		40
 
 #define	ENA_DMA_BITS_MASK		40
 #define	ENA_MAX_FRAME_LEN		10000
 #define	ENA_MIN_FRAME_LEN 		60
 #define	ENA_RX_HASH_KEY_NUM		10
 #define	ENA_RX_THASH_TABLE_SIZE 	(1 << 8)
 
 #define ENA_TX_CLEANUP_THRESHOLD	128
 
 #define DB_THRESHOLD	64
 
 #define TX_COMMIT	32
  /*
  * TX budget for cleaning. It should be half of the RX budget to reduce amount
  *  of TCP retransmissions.
  */
 #define TX_BUDGET	128
 /* RX cleanup budget. -1 stands for infinity. */
 #define RX_BUDGET	256
 /*
  * How many times we can repeat cleanup in the io irq handling routine if the
  * RX or TX budget was depleted.
  */
 #define CLEAN_BUDGET	8
 
 #define RX_IRQ_INTERVAL 20
 #define TX_IRQ_INTERVAL 50
 
 #define	ENA_MAX_MTU		9216
 #define	ENA_TSO_MAXSIZE		65536
 #define	ENA_TSO_NSEGS		ENA_PKT_MAX_BUFS
 #define	ENA_RX_OFFSET		NET_SKB_PAD + NET_IP_ALIGN
 
 #define	ENA_MMIO_DISABLE_REG_READ	BIT(0)
 
 #define	ENA_TX_RING_IDX_NEXT(idx, ring_size) (((idx) + 1) & ((ring_size) - 1))
 
 #define	ENA_RX_RING_IDX_NEXT(idx, ring_size) (((idx) + 1) & ((ring_size) - 1))
 #define	ENA_RX_RING_IDX_ADD(idx, n, ring_size)	\
 	(((idx) + (n)) & ((ring_size) - 1))
 
 #define	ENA_IO_TXQ_IDX(q)		(2 * (q))
 #define	ENA_IO_RXQ_IDX(q)		(2 * (q) + 1)
 
 #define	ENA_MGMNT_IRQ_IDX		0
 #define	ENA_IO_IRQ_FIRST_IDX		1
 #define	ENA_IO_IRQ_IDX(q)		(ENA_IO_IRQ_FIRST_IDX + (q))
 
 /*
  * ENA device should send keep alive msg every 1 sec.
  * We wait for 6 sec just to be on the safe side.
  */
 #define DEFAULT_KEEP_ALIVE_TO		(SBT_1S * 6)
 
 /* Time in jiffies before concluding the transmitter is hung. */
 #define DEFAULT_TX_CMP_TO		(SBT_1S * 5)
 
 /* Number of queues to check for missing queues per timer tick */
 #define DEFAULT_TX_MONITORED_QUEUES	(4)
 
 /* Max number of timeouted packets before device reset */
 #define DEFAULT_TX_CMP_THRESHOLD	(128)
 
 /*
  * Supported PCI vendor and devices IDs
  */
 #define	PCI_VENDOR_ID_AMAZON	0x1d0f
 
 #define	PCI_DEV_ID_ENA_PF	0x0ec2
 #define	PCI_DEV_ID_ENA_LLQ_PF	0x1ec2
 #define	PCI_DEV_ID_ENA_VF	0xec20
 #define	PCI_DEV_ID_ENA_LLQ_VF	0xec21
 
 struct msix_entry {
 	int entry;
 	int vector;
 };
 
 typedef struct _ena_vendor_info_t {
 	unsigned int vendor_id;
 	unsigned int device_id;
 	unsigned int index;
 } ena_vendor_info_t;
 
 struct ena_irq {
 	/* Interrupt resources */
 	struct resource *res;
 	driver_intr_t *handler;
 	void *data;
 	void *cookie;
 	unsigned int vector;
 	bool requested;
 	int cpu;
 	char name[ENA_IRQNAME_SIZE];
 };
 
 struct ena_que {
 	struct ena_adapter *adapter;
 	struct ena_ring *tx_ring;
 	struct ena_ring *rx_ring;
 	uint32_t id;
 	int cpu;
 };
 
 struct ena_tx_buffer {
 	struct mbuf *mbuf;
 	/* # of ena desc for this specific mbuf
 	 * (includes data desc and metadata desc) */
 	unsigned int tx_descs;
 	/* # of buffers used by this mbuf */
 	unsigned int num_of_bufs;
 	bus_dmamap_t map;
 
 	/* Used to detect missing tx packets */
 	struct bintime timestamp;
 	bool print_once;
 
 	struct ena_com_buf bufs[ENA_PKT_MAX_BUFS];
 } __aligned(CACHE_LINE_SIZE);
 
 struct ena_rx_buffer {
 	struct mbuf *mbuf;
 	bus_dmamap_t map;
 	struct ena_com_buf ena_buf;
 } __aligned(CACHE_LINE_SIZE);
 
 
 struct ena_stats_tx {
 	counter_u64_t cnt;
 	counter_u64_t bytes;
 	counter_u64_t queue_stop;
 	counter_u64_t prepare_ctx_err;
 	counter_u64_t queue_wakeup;
 	counter_u64_t dma_mapping_err;
 	/* Not counted */
 	counter_u64_t unsupported_desc_num;
 	/* Not counted */
 	counter_u64_t napi_comp;
 	/* Not counted */
 	counter_u64_t tx_poll;
 	counter_u64_t doorbells;
 	counter_u64_t missing_tx_comp;
 	counter_u64_t bad_req_id;
 	counter_u64_t collapse;
 	counter_u64_t collapse_err;
 };
 
 struct ena_stats_rx {
 	counter_u64_t cnt;
 	counter_u64_t bytes;
 	counter_u64_t refil_partial;
 	counter_u64_t bad_csum;
 	/* Not counted */
 	counter_u64_t page_alloc_fail;
 	counter_u64_t mbuf_alloc_fail;
 	counter_u64_t dma_mapping_err;
 	counter_u64_t bad_desc_num;
 	/* Not counted */
 	counter_u64_t small_copy_len_pkt;
 };
 
 
 struct ena_ring {
 	/* Holds the empty requests for TX out of order completions */
 	uint16_t *free_tx_ids;
 	struct ena_com_dev *ena_dev;
 	struct ena_adapter *adapter;
 	struct ena_com_io_cq *ena_com_io_cq;
 	struct ena_com_io_sq *ena_com_io_sq;
 
 	/* The maximum length the driver can push to the device (For LLQ) */
 	enum ena_admin_placement_policy_type tx_mem_queue_type;
 	uint16_t rx_small_copy_len;
 	uint16_t qid;
 	uint16_t mtu;
 	uint8_t tx_max_header_size;
 
 	struct ena_com_rx_buf_info ena_bufs[ENA_PKT_MAX_BUFS];
 	uint32_t  smoothed_interval;
 	enum ena_intr_moder_level moder_tbl_idx;
 
 	struct ena_que *que;
 	struct lro_ctrl lro;
 
 	uint16_t next_to_use;
 	uint16_t next_to_clean;
 
 	union {
 		struct ena_tx_buffer *tx_buffer_info; /* contex of tx packet */
 		struct ena_rx_buffer *rx_buffer_info; /* contex of rx packet */
 	};
 	int ring_size; /* number of tx/rx_buffer_info's entries */
 
 	struct buf_ring *br; /* only for TX */
 	struct mtx ring_mtx;
 	char mtx_name[16];
 	struct task enqueue_task;
 	struct taskqueue *enqueue_tq;
 	struct task cmpl_task;
 	struct taskqueue *cmpl_tq;
 
 	union {
 		struct ena_stats_tx tx_stats;
 		struct ena_stats_rx rx_stats;
 	};
 
 } __aligned(CACHE_LINE_SIZE);
 
 struct ena_stats_dev {
 	/* Not counted */
 	counter_u64_t tx_timeout;
 	/* Not counted */
 	counter_u64_t io_suspend;
 	/* Not counted */
 	counter_u64_t io_resume;
 	/* Not counted */
 	counter_u64_t wd_expired;
 	counter_u64_t interface_up;
 	counter_u64_t interface_down;
 	/* Not counted */
 	counter_u64_t admin_q_pause;
 };
 
 struct ena_hw_stats {
-	uint64_t rx_packets;
-	uint64_t tx_packets;
+	counter_u64_t rx_packets;
+	counter_u64_t tx_packets;
 
-	uint64_t rx_bytes;
-	uint64_t tx_bytes;
+	counter_u64_t rx_bytes;
+	counter_u64_t tx_bytes;
 
-	uint64_t rx_drops;
+	counter_u64_t rx_drops;
 };
 
 /* Board specific private data structure */
 struct ena_adapter {
 	struct ena_com_dev *ena_dev;
 
 	/* OS defined structs */
 	if_t ifp;
 	device_t pdev;
 	struct ifmedia	media;
 
 	/* OS resources */
 	struct resource * memory;
 	struct resource * registers;
 
 	struct mtx global_mtx;
 	struct sx ioctl_sx;
 
 	/* MSI-X */
 	uint32_t msix_enabled;
 	struct msix_entry *msix_entries;
 	int msix_vecs;
 
 	/* DMA tags used throughout the driver adapter for Tx and Rx */
 	bus_dma_tag_t tx_buf_tag;
 	bus_dma_tag_t rx_buf_tag;
 	int dma_width;
 	/*
 	 * RX packets that shorter that this len will be copied to the skb
 	 * header
 	 */
 	unsigned int small_copy_len;
 
 	uint16_t max_tx_sgl_size;
 	uint16_t max_rx_sgl_size;
 
 	uint32_t tx_offload_cap;
 
 	/* Tx fast path data */
 	int num_queues;
 
 	unsigned int tx_usecs, rx_usecs; /* Interrupt coalescing */
 
 	unsigned int tx_ring_size;
 	unsigned int rx_ring_size;
 
 	/* RSS*/
 	uint8_t	 rss_ind_tbl[ENA_RX_RSS_TABLE_SIZE];
 	bool rss_support;
 
 	uint32_t msg_enable;
 
 	uint8_t mac_addr[ETHER_ADDR_LEN];
 	/* mdio and phy*/
 
 	char name[ENA_NAME_MAX_LEN];
 	bool link_status;
 	bool trigger_reset;
 	bool up;
 	bool running;
 
 	uint32_t wol;
 
 	/* Queue will represent one TX and one RX ring */
 	struct ena_que que[ENA_MAX_NUM_IO_QUEUES]
 	    __aligned(CACHE_LINE_SIZE);
 
 	/* TX */
 	struct ena_ring tx_ring[ENA_MAX_NUM_IO_QUEUES]
 	    __aligned(CACHE_LINE_SIZE);
 
 	/* RX */
 	struct ena_ring rx_ring[ENA_MAX_NUM_IO_QUEUES]
 	    __aligned(CACHE_LINE_SIZE);
 
 	struct ena_irq irq_tbl[ENA_MAX_MSIX_VEC(ENA_MAX_NUM_IO_QUEUES)];
 
 	/* Timer service */
 	struct callout timer_service;
 	sbintime_t keep_alive_timestamp;
 	uint32_t next_monitored_tx_qid;
 	struct task reset_task;
 	struct taskqueue *reset_tq;
 	int wd_active;
 	sbintime_t keep_alive_timeout;
 	sbintime_t missing_tx_timeout;
 	uint32_t missing_tx_max_queues;
 	uint32_t missing_tx_threshold;
 
-	/* Task updating hw stats */
-	struct task stats_task;
-	struct taskqueue *stats_tq;
-
 	/* Statistics */
 	struct ena_stats_dev dev_stats;
 	struct ena_hw_stats hw_stats;
 
 	enum ena_regs_reset_reason_types reset_reason;
 };
 
 
 #define	ENA_DEV_LOCK			mtx_lock(&adapter->global_mtx)
 #define	ENA_DEV_UNLOCK			mtx_unlock(&adapter->global_mtx)
 
 #define	ENA_RING_MTX_LOCK(_ring)		mtx_lock(&(_ring)->ring_mtx)
 #define	ENA_RING_MTX_TRYLOCK(_ring)		mtx_trylock(&(_ring)->ring_mtx)
 #define	ENA_RING_MTX_UNLOCK(_ring)		mtx_unlock(&(_ring)->ring_mtx)
 
 struct ena_dev *ena_efa_enadev_get(device_t pdev);
 
 int ena_register_adapter(struct ena_adapter *adapter);
 void ena_unregister_adapter(struct ena_adapter *adapter);
 
-int ena_update_stats_counters(struct ena_adapter *adapter);
-
 static inline int ena_mbuf_count(struct mbuf *mbuf)
 {
 	int count = 1;
 
 	while ((mbuf = mbuf->m_next) != NULL)
 		++count;
 
 	return count;
 }
 
 #endif /* !(ENA_H) */
diff --git a/sys/dev/ena/ena_sysctl.c b/sys/dev/ena/ena_sysctl.c
index cf2f8438d124..eb94d5a4136c 100644
--- a/sys/dev/ena/ena_sysctl.c
+++ b/sys/dev/ena/ena_sysctl.c
@@ -1,252 +1,234 @@
 /*-
  * BSD LICENSE
  *
  * Copyright (c) 2015-2017 Amazon.com, Inc. or its affiliates.
  * 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.
  *
  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT
  * OWNER 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 "ena_sysctl.h"
 
-static int	ena_sysctl_update_stats(SYSCTL_HANDLER_ARGS);
 static void	ena_sysctl_add_stats(struct ena_adapter *);
 
 void
 ena_sysctl_add_nodes(struct ena_adapter *adapter)
 {
 	ena_sysctl_add_stats(adapter);
 }
 
 static void
 ena_sysctl_add_stats(struct ena_adapter *adapter)
 {
 	device_t dev;
 
 	struct ena_ring *tx_ring;
 	struct ena_ring *rx_ring;
 
 	struct ena_hw_stats *hw_stats;
 	struct ena_stats_dev *dev_stats;
 	struct ena_stats_tx *tx_stats;
 	struct ena_stats_rx *rx_stats;
 	struct ena_com_stats_admin *admin_stats;
 
 	struct sysctl_ctx_list *ctx;
 	struct sysctl_oid *tree;
 	struct sysctl_oid_list *child;
 
 	struct sysctl_oid *queue_node, *tx_node, *rx_node, *hw_node;
 	struct sysctl_oid *admin_node;
 	struct sysctl_oid_list *queue_list, *tx_list, *rx_list, *hw_list;
 	struct sysctl_oid_list *admin_list;
 
 #define QUEUE_NAME_LEN 32
 	char namebuf[QUEUE_NAME_LEN];
 	int i;
 
 	dev = adapter->pdev;
 
 	ctx = device_get_sysctl_ctx(dev);
 	tree = device_get_sysctl_tree(dev);
 	child = SYSCTL_CHILDREN(tree);
 
 	tx_ring = adapter->tx_ring;
 	rx_ring = adapter->rx_ring;
 
 	hw_stats = &adapter->hw_stats;
 	dev_stats = &adapter->dev_stats;
 	admin_stats = &adapter->ena_dev->admin_queue.stats;
 
 	SYSCTL_ADD_COUNTER_U64(ctx, child, OID_AUTO, "tx_timeout",
 	    CTLFLAG_RD, &dev_stats->tx_timeout,
 	    "Driver TX timeouts");
 	SYSCTL_ADD_COUNTER_U64(ctx, child, OID_AUTO, "io_suspend",
 	    CTLFLAG_RD, &dev_stats->io_suspend,
 	    "IO queue suspends");
 	SYSCTL_ADD_COUNTER_U64(ctx, child, OID_AUTO, "io_resume",
 	    CTLFLAG_RD, &dev_stats->io_resume,
 	    "IO queue resumes");
 	SYSCTL_ADD_COUNTER_U64(ctx, child, OID_AUTO, "wd_expired",
 	    CTLFLAG_RD, &dev_stats->wd_expired,
 	    "Watchdog expiry count");
 	SYSCTL_ADD_COUNTER_U64(ctx, child, OID_AUTO, "interface_up",
 	    CTLFLAG_RD, &dev_stats->interface_up,
 	    "Network interface up count");
 	SYSCTL_ADD_COUNTER_U64(ctx, child, OID_AUTO, "interface_down",
 	    CTLFLAG_RD, &dev_stats->interface_down,
 	    "Network interface down count");
 	SYSCTL_ADD_COUNTER_U64(ctx, child, OID_AUTO, "admin_q_pause",
 	    CTLFLAG_RD, &dev_stats->admin_q_pause,
 	    "Admin queue pauses");
 
 	for (i = 0; i < adapter->num_queues; ++i, ++tx_ring, ++rx_ring) {
 		snprintf(namebuf, QUEUE_NAME_LEN, "queue%d", i);
 
 		queue_node = SYSCTL_ADD_NODE(ctx, child, OID_AUTO,
 		    namebuf, CTLFLAG_RD, NULL, "Queue Name");
 		queue_list = SYSCTL_CHILDREN(queue_node);
 
 		/* TX specific stats */
 		tx_node = SYSCTL_ADD_NODE(ctx, queue_list, OID_AUTO,
 		    "tx_ring", CTLFLAG_RD, NULL, "TX ring");
 		tx_list = SYSCTL_CHILDREN(tx_node);
 
 		tx_stats = &tx_ring->tx_stats;
 
 		SYSCTL_ADD_COUNTER_U64(ctx, tx_list, OID_AUTO,
 		    "count", CTLFLAG_RD,
 		    &tx_stats->cnt, "Packets sent");
 		SYSCTL_ADD_COUNTER_U64(ctx, tx_list, OID_AUTO,
 		    "bytes", CTLFLAG_RD,
 		    &tx_stats->bytes, "Bytes sent");
 		SYSCTL_ADD_COUNTER_U64(ctx, tx_list, OID_AUTO,
 		    "prepare_ctx_err", CTLFLAG_RD,
 		    &tx_stats->prepare_ctx_err,
 		    "TX buffer preparation failures");
 		SYSCTL_ADD_COUNTER_U64(ctx, tx_list, OID_AUTO,
 		    "queue_wakeup", CTLFLAG_RD,
 		    &tx_stats->queue_wakeup, "Queue wakeups");
 		SYSCTL_ADD_COUNTER_U64(ctx, tx_list, OID_AUTO,
 		    "dma_mapping_err", CTLFLAG_RD,
 		    &tx_stats->dma_mapping_err, "DMA mapping failures");
 		SYSCTL_ADD_COUNTER_U64(ctx, tx_list, OID_AUTO,
 		    "unsupported_desc_num", CTLFLAG_RD,
 		    &tx_stats->unsupported_desc_num,
 		    "Excessive descriptor packet discards");
 		SYSCTL_ADD_COUNTER_U64(ctx, tx_list, OID_AUTO,
 		    "napi_comp", CTLFLAG_RD,
 		    &tx_stats->napi_comp, "Napi completions");
 		SYSCTL_ADD_COUNTER_U64(ctx, tx_list, OID_AUTO,
 		    "tx_poll", CTLFLAG_RD,
 		    &tx_stats->tx_poll, "TX poll count");
 		SYSCTL_ADD_COUNTER_U64(ctx, tx_list, OID_AUTO,
 		    "doorbells", CTLFLAG_RD,
 		    &tx_stats->doorbells, "Queue doorbells");
 		SYSCTL_ADD_COUNTER_U64(ctx, tx_list, OID_AUTO,
 		    "missing_tx_comp", CTLFLAG_RD,
 		    &tx_stats->missing_tx_comp, "TX completions missed");
 		SYSCTL_ADD_COUNTER_U64(ctx, tx_list, OID_AUTO,
 		    "bad_req_id", CTLFLAG_RD,
 		    &tx_stats->bad_req_id, "Bad request id count");
 		SYSCTL_ADD_COUNTER_U64(ctx, tx_list, OID_AUTO,
 		    "stops", CTLFLAG_RD,
 		    &tx_stats->queue_stop, "Queue stops");
 		SYSCTL_ADD_COUNTER_U64(ctx, tx_list, OID_AUTO,
 		        "mbuf_collapses", CTLFLAG_RD,
 		        &tx_stats->collapse,
 		        "Mbuf collapse count");
 		SYSCTL_ADD_COUNTER_U64(ctx, tx_list, OID_AUTO,
 		        "mbuf_collapse_err", CTLFLAG_RD,
 		        &tx_stats->collapse_err,
 		        "Mbuf collapse failures");
 
 		/* RX specific stats */
 		rx_node = SYSCTL_ADD_NODE(ctx, queue_list, OID_AUTO,
 		    "rx_ring", CTLFLAG_RD, NULL, "RX ring");
 		rx_list = SYSCTL_CHILDREN(rx_node);
 
 		rx_stats = &rx_ring->rx_stats;
 
 		SYSCTL_ADD_COUNTER_U64(ctx, rx_list, OID_AUTO,
 		    "count", CTLFLAG_RD,
 		    &rx_stats->cnt, "Packets received");
 		SYSCTL_ADD_COUNTER_U64(ctx, rx_list, OID_AUTO,
 		    "bytes", CTLFLAG_RD,
 		    &rx_stats->bytes, "Bytes received");
 		SYSCTL_ADD_COUNTER_U64(ctx, rx_list, OID_AUTO,
 		    "refil_partial", CTLFLAG_RD,
 		    &rx_stats->refil_partial, "Partial refilled mbufs");
 		SYSCTL_ADD_COUNTER_U64(ctx, rx_list, OID_AUTO,
 		    "bad_csum", CTLFLAG_RD,
 		    &rx_stats->bad_csum, "Bad RX checksum");
 		SYSCTL_ADD_COUNTER_U64(ctx, rx_list, OID_AUTO,
 		    "page_alloc_fail", CTLFLAG_RD,
 		    &rx_stats->page_alloc_fail, "Failed page allocs");
 		SYSCTL_ADD_COUNTER_U64(ctx, rx_list, OID_AUTO,
 		    "mbuf_alloc_fail", CTLFLAG_RD,
 		    &rx_stats->mbuf_alloc_fail, "Failed mbuf allocs");
 		SYSCTL_ADD_COUNTER_U64(ctx, rx_list, OID_AUTO,
 		    "dma_mapping_err", CTLFLAG_RD,
 		    &rx_stats->dma_mapping_err, "DMA mapping errors");
 		SYSCTL_ADD_COUNTER_U64(ctx, rx_list, OID_AUTO,
 		    "bad_desc_num", CTLFLAG_RD,
 		    &rx_stats->bad_desc_num, "Bad descriptor count");
 		SYSCTL_ADD_COUNTER_U64(ctx, rx_list, OID_AUTO,
 		    "small_copy_len_pkt", CTLFLAG_RD,
 		    &rx_stats->small_copy_len_pkt, "Small copy packet count");
 	}
 
 	/* Stats read from device */
 	hw_node = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, "hw_stats",
 	    CTLFLAG_RD, NULL, "Statistics from hardware");
 	hw_list = SYSCTL_CHILDREN(hw_node);
 
-	SYSCTL_ADD_U64(ctx, hw_list, OID_AUTO, "rx_packets", CTLFLAG_RD,
-	    &hw_stats->rx_packets, 0, "Packets received");
-	SYSCTL_ADD_U64(ctx, hw_list, OID_AUTO, "tx_packets", CTLFLAG_RD,
-	    &hw_stats->tx_packets, 0, "Packets transmitted");
-	SYSCTL_ADD_U64(ctx, hw_list, OID_AUTO, "rx_bytes", CTLFLAG_RD,
-	    &hw_stats->rx_bytes, 0, "Bytes received");
-	SYSCTL_ADD_U64(ctx, hw_list, OID_AUTO, "tx_bytes", CTLFLAG_RD,
-	    &hw_stats->tx_bytes, 0, "Bytes transmitted");
-	SYSCTL_ADD_U64(ctx, hw_list, OID_AUTO, "rx_drops", CTLFLAG_RD,
-	    &hw_stats->rx_drops, 0, "Receive packet drops");
-
-	SYSCTL_ADD_PROC(ctx, hw_list, OID_AUTO, "update_stats",
-	    CTLTYPE_INT|CTLFLAG_RD, adapter, 0, ena_sysctl_update_stats,
-	    "A", "Update stats from hardware");
+	SYSCTL_ADD_COUNTER_U64(ctx, hw_list, OID_AUTO, "rx_packets", CTLFLAG_RD,
+	    &hw_stats->rx_packets, "Packets received");
+	SYSCTL_ADD_COUNTER_U64(ctx, hw_list, OID_AUTO, "tx_packets", CTLFLAG_RD,
+	    &hw_stats->tx_packets, "Packets transmitted");
+	SYSCTL_ADD_COUNTER_U64(ctx, hw_list, OID_AUTO, "rx_bytes", CTLFLAG_RD,
+	    &hw_stats->rx_bytes, "Bytes received");
+	SYSCTL_ADD_COUNTER_U64(ctx, hw_list, OID_AUTO, "tx_bytes", CTLFLAG_RD,
+	    &hw_stats->tx_bytes, "Bytes transmitted");
+	SYSCTL_ADD_COUNTER_U64(ctx, hw_list, OID_AUTO, "rx_drops", CTLFLAG_RD,
+	    &hw_stats->rx_drops, "Receive packet drops");
 
 	/* ENA Admin queue stats */
 	admin_node = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, "admin_stats",
 	    CTLFLAG_RD, NULL, "ENA Admin Queue statistics");
 	admin_list = SYSCTL_CHILDREN(admin_node);
 
 	SYSCTL_ADD_U32(ctx, admin_list, OID_AUTO, "aborted_cmd", CTLFLAG_RD,
 	    &admin_stats->aborted_cmd, 0, "Aborted commands");
 	SYSCTL_ADD_U32(ctx, admin_list, OID_AUTO, "sumbitted_cmd", CTLFLAG_RD,
 	    &admin_stats->submitted_cmd, 0, "Submitted commands");
 	SYSCTL_ADD_U32(ctx, admin_list, OID_AUTO, "completed_cmd", CTLFLAG_RD,
 	    &admin_stats->completed_cmd, 0, "Completed commands");
 	SYSCTL_ADD_U32(ctx, admin_list, OID_AUTO, "out_of_space", CTLFLAG_RD,
 	    &admin_stats->out_of_space, 0, "Queue out of space");
 	SYSCTL_ADD_U32(ctx, admin_list, OID_AUTO, "no_completion", CTLFLAG_RD,
 	    &admin_stats->no_completion, 0, "Commands not completed");
 }
 
-static int
-ena_sysctl_update_stats(SYSCTL_HANDLER_ARGS)
-{
-	struct ena_adapter *adapter = (struct ena_adapter *)arg1;
-	int rc;
-
-	if (adapter->up)
-		ena_update_stats_counters(adapter);
-
-	rc = sysctl_handle_string(oidp, "", 1, req);
-	return (rc);
-}
-