xref: /freebsd/sys/dev/ena/ena.c (revision beaadec9eaec8e6b266faff3b0880a141728fcef)
19b8d05b8SZbigniew Bodek /*-
20835cc78SMarcin Wojtas  * SPDX-License-Identifier: BSD-2-Clause
39b8d05b8SZbigniew Bodek  *
4*beaadec9SMarcin Wojtas  * Copyright (c) 2015-2021 Amazon.com, Inc. or its affiliates.
59b8d05b8SZbigniew Bodek  * All rights reserved.
69b8d05b8SZbigniew Bodek  *
79b8d05b8SZbigniew Bodek  * Redistribution and use in source and binary forms, with or without
89b8d05b8SZbigniew Bodek  * modification, are permitted provided that the following conditions
99b8d05b8SZbigniew Bodek  * are met:
109b8d05b8SZbigniew Bodek  *
119b8d05b8SZbigniew Bodek  * 1. Redistributions of source code must retain the above copyright
129b8d05b8SZbigniew Bodek  *    notice, this list of conditions and the following disclaimer.
139b8d05b8SZbigniew Bodek  *
149b8d05b8SZbigniew Bodek  * 2. Redistributions in binary form must reproduce the above copyright
159b8d05b8SZbigniew Bodek  *    notice, this list of conditions and the following disclaimer in the
169b8d05b8SZbigniew Bodek  *    documentation and/or other materials provided with the distribution.
179b8d05b8SZbigniew Bodek  *
189b8d05b8SZbigniew Bodek  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
199b8d05b8SZbigniew Bodek  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
209b8d05b8SZbigniew Bodek  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
219b8d05b8SZbigniew Bodek  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
229b8d05b8SZbigniew Bodek  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
239b8d05b8SZbigniew Bodek  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
249b8d05b8SZbigniew Bodek  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
259b8d05b8SZbigniew Bodek  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
269b8d05b8SZbigniew Bodek  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
279b8d05b8SZbigniew Bodek  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
289b8d05b8SZbigniew Bodek  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
299b8d05b8SZbigniew Bodek  */
309b8d05b8SZbigniew Bodek #include <sys/cdefs.h>
319b8d05b8SZbigniew Bodek __FBSDID("$FreeBSD$");
329b8d05b8SZbigniew Bodek 
33b40dd828SAndriy Gapon #include "opt_rss.h"
34b40dd828SAndriy Gapon 
359b8d05b8SZbigniew Bodek #include <sys/param.h>
369b8d05b8SZbigniew Bodek #include <sys/systm.h>
379b8d05b8SZbigniew Bodek #include <sys/bus.h>
389b8d05b8SZbigniew Bodek #include <sys/endian.h>
399b8d05b8SZbigniew Bodek #include <sys/kernel.h>
409b8d05b8SZbigniew Bodek #include <sys/kthread.h>
419b8d05b8SZbigniew Bodek #include <sys/malloc.h>
429b8d05b8SZbigniew Bodek #include <sys/mbuf.h>
439b8d05b8SZbigniew Bodek #include <sys/module.h>
449b8d05b8SZbigniew Bodek #include <sys/rman.h>
459b8d05b8SZbigniew Bodek #include <sys/smp.h>
469b8d05b8SZbigniew Bodek #include <sys/socket.h>
479b8d05b8SZbigniew Bodek #include <sys/sockio.h>
489b8d05b8SZbigniew Bodek #include <sys/sysctl.h>
499b8d05b8SZbigniew Bodek #include <sys/taskqueue.h>
509b8d05b8SZbigniew Bodek #include <sys/time.h>
519b8d05b8SZbigniew Bodek #include <sys/eventhandler.h>
529b8d05b8SZbigniew Bodek 
539b8d05b8SZbigniew Bodek #include <machine/bus.h>
549b8d05b8SZbigniew Bodek #include <machine/resource.h>
559b8d05b8SZbigniew Bodek #include <machine/in_cksum.h>
569b8d05b8SZbigniew Bodek 
579b8d05b8SZbigniew Bodek #include <net/bpf.h>
589b8d05b8SZbigniew Bodek #include <net/ethernet.h>
599b8d05b8SZbigniew Bodek #include <net/if.h>
609b8d05b8SZbigniew Bodek #include <net/if_var.h>
619b8d05b8SZbigniew Bodek #include <net/if_arp.h>
629b8d05b8SZbigniew Bodek #include <net/if_dl.h>
639b8d05b8SZbigniew Bodek #include <net/if_media.h>
649b8d05b8SZbigniew Bodek #include <net/if_types.h>
659b8d05b8SZbigniew Bodek #include <net/if_vlan_var.h>
66b40dd828SAndriy Gapon #ifdef RSS
67b40dd828SAndriy Gapon #include <net/rss_config.h>
68b40dd828SAndriy Gapon #endif
699b8d05b8SZbigniew Bodek 
709b8d05b8SZbigniew Bodek #include <netinet/in_systm.h>
719b8d05b8SZbigniew Bodek #include <netinet/in.h>
729b8d05b8SZbigniew Bodek #include <netinet/if_ether.h>
739b8d05b8SZbigniew Bodek #include <netinet/ip.h>
749b8d05b8SZbigniew Bodek #include <netinet/ip6.h>
759b8d05b8SZbigniew Bodek #include <netinet/tcp.h>
769b8d05b8SZbigniew Bodek #include <netinet/udp.h>
779b8d05b8SZbigniew Bodek 
789b8d05b8SZbigniew Bodek #include <dev/pci/pcivar.h>
799b8d05b8SZbigniew Bodek #include <dev/pci/pcireg.h>
809b8d05b8SZbigniew Bodek 
814fa9e02dSMarcin Wojtas #include <vm/vm.h>
824fa9e02dSMarcin Wojtas #include <vm/pmap.h>
834fa9e02dSMarcin Wojtas 
8438c7b965SMarcin Wojtas #include "ena_datapath.h"
859b8d05b8SZbigniew Bodek #include "ena.h"
869b8d05b8SZbigniew Bodek #include "ena_sysctl.h"
879b8d05b8SZbigniew Bodek 
88d17b7d87SMarcin Wojtas #ifdef DEV_NETMAP
89d17b7d87SMarcin Wojtas #include "ena_netmap.h"
90d17b7d87SMarcin Wojtas #endif /* DEV_NETMAP */
91d17b7d87SMarcin Wojtas 
929b8d05b8SZbigniew Bodek /*********************************************************
939b8d05b8SZbigniew Bodek  *  Function prototypes
949b8d05b8SZbigniew Bodek  *********************************************************/
959b8d05b8SZbigniew Bodek static int	ena_probe(device_t);
969b8d05b8SZbigniew Bodek static void	ena_intr_msix_mgmnt(void *);
979b8d05b8SZbigniew Bodek static void	ena_free_pci_resources(struct ena_adapter *);
989b8d05b8SZbigniew Bodek static int	ena_change_mtu(if_t, int);
999b8d05b8SZbigniew Bodek static inline void ena_alloc_counters(counter_u64_t *, int);
1009b8d05b8SZbigniew Bodek static inline void ena_free_counters(counter_u64_t *, int);
1019b8d05b8SZbigniew Bodek static inline void ena_reset_counters(counter_u64_t *, int);
1029b8d05b8SZbigniew Bodek static void	ena_init_io_rings_common(struct ena_adapter *,
1039b8d05b8SZbigniew Bodek     struct ena_ring *, uint16_t);
1047d8c4feeSMarcin Wojtas static void	ena_init_io_rings_basic(struct ena_adapter *);
1057d8c4feeSMarcin Wojtas static void	ena_init_io_rings_advanced(struct ena_adapter *);
106cd5d5804SMarcin Wojtas static void	ena_init_io_rings(struct ena_adapter *);
1079b8d05b8SZbigniew Bodek static void	ena_free_io_ring_resources(struct ena_adapter *, unsigned int);
1089b8d05b8SZbigniew Bodek static void	ena_free_all_io_rings_resources(struct ena_adapter *);
1099b8d05b8SZbigniew Bodek static int	ena_setup_tx_dma_tag(struct ena_adapter *);
1109b8d05b8SZbigniew Bodek static int	ena_free_tx_dma_tag(struct ena_adapter *);
1119b8d05b8SZbigniew Bodek static int	ena_setup_rx_dma_tag(struct ena_adapter *);
1129b8d05b8SZbigniew Bodek static int	ena_free_rx_dma_tag(struct ena_adapter *);
1136f2128c7SMarcin Wojtas static void	ena_release_all_tx_dmamap(struct ena_ring *);
1149b8d05b8SZbigniew Bodek static int	ena_setup_tx_resources(struct ena_adapter *, int);
1159b8d05b8SZbigniew Bodek static void	ena_free_tx_resources(struct ena_adapter *, int);
1169b8d05b8SZbigniew Bodek static int	ena_setup_all_tx_resources(struct ena_adapter *);
1179b8d05b8SZbigniew Bodek static void	ena_free_all_tx_resources(struct ena_adapter *);
1189b8d05b8SZbigniew Bodek static int	ena_setup_rx_resources(struct ena_adapter *, unsigned int);
1199b8d05b8SZbigniew Bodek static void	ena_free_rx_resources(struct ena_adapter *, unsigned int);
1209b8d05b8SZbigniew Bodek static int	ena_setup_all_rx_resources(struct ena_adapter *);
1219b8d05b8SZbigniew Bodek static void	ena_free_all_rx_resources(struct ena_adapter *);
1229b8d05b8SZbigniew Bodek static inline int ena_alloc_rx_mbuf(struct ena_adapter *, struct ena_ring *,
1239b8d05b8SZbigniew Bodek     struct ena_rx_buffer *);
1249b8d05b8SZbigniew Bodek static void	ena_free_rx_mbuf(struct ena_adapter *, struct ena_ring *,
1259b8d05b8SZbigniew Bodek     struct ena_rx_buffer *);
1269b8d05b8SZbigniew Bodek static void	ena_free_rx_bufs(struct ena_adapter *, unsigned int);
1279b8d05b8SZbigniew Bodek static void	ena_refill_all_rx_bufs(struct ena_adapter *);
1289b8d05b8SZbigniew Bodek static void	ena_free_all_rx_bufs(struct ena_adapter *);
1299b8d05b8SZbigniew Bodek static void	ena_free_tx_bufs(struct ena_adapter *, unsigned int);
1309b8d05b8SZbigniew Bodek static void	ena_free_all_tx_bufs(struct ena_adapter *);
1319b8d05b8SZbigniew Bodek static void	ena_destroy_all_tx_queues(struct ena_adapter *);
1329b8d05b8SZbigniew Bodek static void	ena_destroy_all_rx_queues(struct ena_adapter *);
1339b8d05b8SZbigniew Bodek static void	ena_destroy_all_io_queues(struct ena_adapter *);
1349b8d05b8SZbigniew Bodek static int	ena_create_io_queues(struct ena_adapter *);
1355cb9db07SMarcin Wojtas static int	ena_handle_msix(void *);
1369b8d05b8SZbigniew Bodek static int	ena_enable_msix(struct ena_adapter *);
1379b8d05b8SZbigniew Bodek static void	ena_setup_mgmnt_intr(struct ena_adapter *);
13877958fcdSMarcin Wojtas static int	ena_setup_io_intr(struct ena_adapter *);
1399b8d05b8SZbigniew Bodek static int	ena_request_mgmnt_irq(struct ena_adapter *);
1409b8d05b8SZbigniew Bodek static int	ena_request_io_irq(struct ena_adapter *);
1419b8d05b8SZbigniew Bodek static void	ena_free_mgmnt_irq(struct ena_adapter *);
1429b8d05b8SZbigniew Bodek static void	ena_free_io_irq(struct ena_adapter *);
1439b8d05b8SZbigniew Bodek static void	ena_free_irqs(struct ena_adapter*);
1449b8d05b8SZbigniew Bodek static void	ena_disable_msix(struct ena_adapter *);
1459b8d05b8SZbigniew Bodek static void	ena_unmask_all_io_irqs(struct ena_adapter *);
1469b8d05b8SZbigniew Bodek static int	ena_rss_configure(struct ena_adapter *);
1479b8d05b8SZbigniew Bodek static int	ena_up_complete(struct ena_adapter *);
1489b8d05b8SZbigniew Bodek static uint64_t	ena_get_counter(if_t, ift_counter);
1499b8d05b8SZbigniew Bodek static int	ena_media_change(if_t);
1509b8d05b8SZbigniew Bodek static void	ena_media_status(if_t, struct ifmediareq *);
1519b8d05b8SZbigniew Bodek static void	ena_init(void *);
1529b8d05b8SZbigniew Bodek static int	ena_ioctl(if_t, u_long, caddr_t);
1539b8d05b8SZbigniew Bodek static int	ena_get_dev_offloads(struct ena_com_dev_get_features_ctx *);
1549b8d05b8SZbigniew Bodek static void	ena_update_host_info(struct ena_admin_host_info *, if_t);
1559b8d05b8SZbigniew Bodek static void	ena_update_hwassist(struct ena_adapter *);
1569b8d05b8SZbigniew Bodek static int	ena_setup_ifnet(device_t, struct ena_adapter *,
1579b8d05b8SZbigniew Bodek     struct ena_com_dev_get_features_ctx *);
1584fa9e02dSMarcin Wojtas static int	ena_enable_wc(struct resource *);
1594fa9e02dSMarcin Wojtas static int	ena_set_queues_placement_policy(device_t, struct ena_com_dev *,
1604fa9e02dSMarcin Wojtas     struct ena_admin_feature_llq_desc *, struct ena_llq_configurations *);
1617d8c4feeSMarcin Wojtas static uint32_t	ena_calc_max_io_queue_num(device_t, struct ena_com_dev *,
1629b8d05b8SZbigniew Bodek     struct ena_com_dev_get_features_ctx *);
1637d8c4feeSMarcin Wojtas static int	ena_calc_io_queue_size(struct ena_calc_queue_size_ctx *);
1649b8d05b8SZbigniew Bodek static int	ena_rss_init_default(struct ena_adapter *);
1659b8d05b8SZbigniew Bodek static void	ena_rss_init_default_deferred(void *);
16646021271SMarcin Wojtas static void	ena_config_host_info(struct ena_com_dev *, device_t);
1679b8d05b8SZbigniew Bodek static int	ena_attach(device_t);
1689b8d05b8SZbigniew Bodek static int	ena_detach(device_t);
1699b8d05b8SZbigniew Bodek static int	ena_device_init(struct ena_adapter *, device_t,
1709b8d05b8SZbigniew Bodek     struct ena_com_dev_get_features_ctx *, int *);
171aa9c3226SMarcin Wojtas static int	ena_enable_msix_and_set_admin_interrupts(struct ena_adapter *);
1729b8d05b8SZbigniew Bodek static void ena_update_on_link_change(void *, struct ena_admin_aenq_entry *);
1739b8d05b8SZbigniew Bodek static void	unimplemented_aenq_handler(void *,
1749b8d05b8SZbigniew Bodek     struct ena_admin_aenq_entry *);
175f180142cSMarcin Wojtas static int	ena_copy_eni_metrics(struct ena_adapter *);
1769b8d05b8SZbigniew Bodek static void	ena_timer_service(void *);
1779b8d05b8SZbigniew Bodek 
1789b8d05b8SZbigniew Bodek static char ena_version[] = DEVICE_NAME DRV_MODULE_NAME " v" DRV_MODULE_VERSION;
1799b8d05b8SZbigniew Bodek 
1809b8d05b8SZbigniew Bodek static ena_vendor_info_t ena_vendor_info_array[] = {
1819b8d05b8SZbigniew Bodek     { PCI_VENDOR_ID_AMAZON, PCI_DEV_ID_ENA_PF, 0},
1827d2e6f20SMarcin Wojtas     { PCI_VENDOR_ID_AMAZON, PCI_DEV_ID_ENA_PF_RSERV0, 0},
1839b8d05b8SZbigniew Bodek     { PCI_VENDOR_ID_AMAZON, PCI_DEV_ID_ENA_VF, 0},
1847d2e6f20SMarcin Wojtas     { PCI_VENDOR_ID_AMAZON, PCI_DEV_ID_ENA_VF_RSERV0, 0},
1859b8d05b8SZbigniew Bodek     /* Last entry */
1869b8d05b8SZbigniew Bodek     { 0, 0, 0 }
1879b8d05b8SZbigniew Bodek };
1889b8d05b8SZbigniew Bodek 
1899b8d05b8SZbigniew Bodek /*
1909b8d05b8SZbigniew Bodek  * Contains pointers to event handlers, e.g. link state chage.
1919b8d05b8SZbigniew Bodek  */
1929b8d05b8SZbigniew Bodek static struct ena_aenq_handlers aenq_handlers;
1939b8d05b8SZbigniew Bodek 
1949b8d05b8SZbigniew Bodek void
1959b8d05b8SZbigniew Bodek ena_dmamap_callback(void *arg, bus_dma_segment_t *segs, int nseg, int error)
1969b8d05b8SZbigniew Bodek {
1970bdffe59SMarcin Wojtas 	if (error != 0)
1989b8d05b8SZbigniew Bodek 		return;
1999b8d05b8SZbigniew Bodek 	*(bus_addr_t *) arg = segs[0].ds_addr;
2009b8d05b8SZbigniew Bodek }
2019b8d05b8SZbigniew Bodek 
2029b8d05b8SZbigniew Bodek int
2039b8d05b8SZbigniew Bodek ena_dma_alloc(device_t dmadev, bus_size_t size,
2044f8f476eSMarcin Wojtas     ena_mem_handle_t *dma, int mapflags, bus_size_t alignment)
2059b8d05b8SZbigniew Bodek {
2069b8d05b8SZbigniew Bodek 	struct ena_adapter* adapter = device_get_softc(dmadev);
2070bdffe59SMarcin Wojtas 	uint32_t maxsize;
2080bdffe59SMarcin Wojtas 	uint64_t dma_space_addr;
2099b8d05b8SZbigniew Bodek 	int error;
2109b8d05b8SZbigniew Bodek 
2110bdffe59SMarcin Wojtas 	maxsize = ((size - 1) / PAGE_SIZE + 1) * PAGE_SIZE;
2120bdffe59SMarcin Wojtas 
2130bdffe59SMarcin Wojtas 	dma_space_addr = ENA_DMA_BIT_MASK(adapter->dma_width);
2143f9ed7abSMarcin Wojtas 	if (unlikely(dma_space_addr == 0))
2159b8d05b8SZbigniew Bodek 		dma_space_addr = BUS_SPACE_MAXADDR;
2160bdffe59SMarcin Wojtas 
2179b8d05b8SZbigniew Bodek 	error = bus_dma_tag_create(bus_get_dma_tag(dmadev), /* parent */
2184f8f476eSMarcin Wojtas 	    alignment, 0,     /* alignment, bounds 		*/
2198a573700SZbigniew Bodek 	    dma_space_addr,   /* lowaddr of exclusion window	*/
2208a573700SZbigniew Bodek 	    BUS_SPACE_MAXADDR,/* highaddr of exclusion window	*/
2219b8d05b8SZbigniew Bodek 	    NULL, NULL,	      /* filter, filterarg 		*/
2229b8d05b8SZbigniew Bodek 	    maxsize,	      /* maxsize 			*/
2239b8d05b8SZbigniew Bodek 	    1,		      /* nsegments 			*/
2249b8d05b8SZbigniew Bodek 	    maxsize,	      /* maxsegsize 			*/
2259b8d05b8SZbigniew Bodek 	    BUS_DMA_ALLOCNOW, /* flags 				*/
2269b8d05b8SZbigniew Bodek 	    NULL,	      /* lockfunc 			*/
2279b8d05b8SZbigniew Bodek 	    NULL,	      /* lockarg 			*/
2289b8d05b8SZbigniew Bodek 	    &dma->tag);
2293f9ed7abSMarcin Wojtas 	if (unlikely(error != 0)) {
2309eb1615fSMarcin Wojtas 		ena_trace(NULL, ENA_ALERT, "bus_dma_tag_create failed: %d\n", error);
2319b8d05b8SZbigniew Bodek 		goto fail_tag;
2329b8d05b8SZbigniew Bodek 	}
2339b8d05b8SZbigniew Bodek 
2349b8d05b8SZbigniew Bodek 	error = bus_dmamem_alloc(dma->tag, (void**) &dma->vaddr,
2359b8d05b8SZbigniew Bodek 	    BUS_DMA_COHERENT | BUS_DMA_ZERO, &dma->map);
2363f9ed7abSMarcin Wojtas 	if (unlikely(error != 0)) {
2379eb1615fSMarcin Wojtas 		ena_trace(NULL, ENA_ALERT, "bus_dmamem_alloc(%ju) failed: %d\n",
2384e8acd84SMarcin Wojtas 		    (uintmax_t)size, error);
2399b8d05b8SZbigniew Bodek 		goto fail_map_create;
2409b8d05b8SZbigniew Bodek 	}
2419b8d05b8SZbigniew Bodek 
2429b8d05b8SZbigniew Bodek 	dma->paddr = 0;
2439b8d05b8SZbigniew Bodek 	error = bus_dmamap_load(dma->tag, dma->map, dma->vaddr,
2449b8d05b8SZbigniew Bodek 	    size, ena_dmamap_callback, &dma->paddr, mapflags);
2453f9ed7abSMarcin Wojtas 	if (unlikely((error != 0) || (dma->paddr == 0))) {
2469eb1615fSMarcin Wojtas 		ena_trace(NULL, ENA_ALERT, ": bus_dmamap_load failed: %d\n", error);
2479b8d05b8SZbigniew Bodek 		goto fail_map_load;
2489b8d05b8SZbigniew Bodek 	}
2499b8d05b8SZbigniew Bodek 
250e8073738SMarcin Wojtas 	bus_dmamap_sync(dma->tag, dma->map,
251e8073738SMarcin Wojtas 	    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
252e8073738SMarcin Wojtas 
2539b8d05b8SZbigniew Bodek 	return (0);
2549b8d05b8SZbigniew Bodek 
2559b8d05b8SZbigniew Bodek fail_map_load:
2569b8d05b8SZbigniew Bodek 	bus_dmamem_free(dma->tag, dma->vaddr, dma->map);
2577d2544e6SMarcin Wojtas fail_map_create:
2589b8d05b8SZbigniew Bodek 	bus_dma_tag_destroy(dma->tag);
2599b8d05b8SZbigniew Bodek fail_tag:
2609b8d05b8SZbigniew Bodek 	dma->tag = NULL;
2615b14f92eSMarcin Wojtas 	dma->vaddr = NULL;
2625b14f92eSMarcin Wojtas 	dma->paddr = 0;
2639b8d05b8SZbigniew Bodek 
2649b8d05b8SZbigniew Bodek 	return (error);
2659b8d05b8SZbigniew Bodek }
2669b8d05b8SZbigniew Bodek 
2678483b844SMarcin Wojtas /*
2688483b844SMarcin Wojtas  * This function should generate unique key for the whole driver.
2698483b844SMarcin Wojtas  * If the key was already genereated in the previous call (for example
2708483b844SMarcin Wojtas  * for another adapter), then it should be returned instead.
2718483b844SMarcin Wojtas  */
2728483b844SMarcin Wojtas void
2738483b844SMarcin Wojtas ena_rss_key_fill(void *key, size_t size)
2748483b844SMarcin Wojtas {
2758483b844SMarcin Wojtas 	static bool key_generated;
2768483b844SMarcin Wojtas 	static uint8_t default_key[ENA_HASH_KEY_SIZE];
2778483b844SMarcin Wojtas 
2788483b844SMarcin Wojtas 	KASSERT(size <= ENA_HASH_KEY_SIZE, ("Requested more bytes than ENA RSS key can hold"));
2798483b844SMarcin Wojtas 
2808483b844SMarcin Wojtas 	if (!key_generated) {
2818483b844SMarcin Wojtas 		arc4random_buf(default_key, ENA_HASH_KEY_SIZE);
2828483b844SMarcin Wojtas 		key_generated = true;
2838483b844SMarcin Wojtas 	}
2848483b844SMarcin Wojtas 
2858483b844SMarcin Wojtas 	memcpy(key, default_key, size);
2868483b844SMarcin Wojtas }
2878483b844SMarcin Wojtas 
2889b8d05b8SZbigniew Bodek static void
2899b8d05b8SZbigniew Bodek ena_free_pci_resources(struct ena_adapter *adapter)
2909b8d05b8SZbigniew Bodek {
2919b8d05b8SZbigniew Bodek 	device_t pdev = adapter->pdev;
2929b8d05b8SZbigniew Bodek 
2939b8d05b8SZbigniew Bodek 	if (adapter->memory != NULL) {
2949b8d05b8SZbigniew Bodek 		bus_release_resource(pdev, SYS_RES_MEMORY,
2959b8d05b8SZbigniew Bodek 		    PCIR_BAR(ENA_MEM_BAR), adapter->memory);
2969b8d05b8SZbigniew Bodek 	}
2979b8d05b8SZbigniew Bodek 
2989b8d05b8SZbigniew Bodek 	if (adapter->registers != NULL) {
2999b8d05b8SZbigniew Bodek 		bus_release_resource(pdev, SYS_RES_MEMORY,
3009b8d05b8SZbigniew Bodek 		    PCIR_BAR(ENA_REG_BAR), adapter->registers);
3019b8d05b8SZbigniew Bodek 	}
3021c808fcdSMichal Krawczyk 
3031c808fcdSMichal Krawczyk 	if (adapter->msix != NULL) {
3041c808fcdSMichal Krawczyk 		bus_release_resource(pdev, SYS_RES_MEMORY,
3051c808fcdSMichal Krawczyk 		    adapter->msix_rid, adapter->msix);
3061c808fcdSMichal Krawczyk 	}
3079b8d05b8SZbigniew Bodek }
3089b8d05b8SZbigniew Bodek 
3099b8d05b8SZbigniew Bodek static int
3109b8d05b8SZbigniew Bodek ena_probe(device_t dev)
3119b8d05b8SZbigniew Bodek {
3129b8d05b8SZbigniew Bodek 	ena_vendor_info_t *ent;
3139b8d05b8SZbigniew Bodek 	char		adapter_name[60];
3149b8d05b8SZbigniew Bodek 	uint16_t	pci_vendor_id = 0;
3159b8d05b8SZbigniew Bodek 	uint16_t	pci_device_id = 0;
3169b8d05b8SZbigniew Bodek 
3179b8d05b8SZbigniew Bodek 	pci_vendor_id = pci_get_vendor(dev);
3189b8d05b8SZbigniew Bodek 	pci_device_id = pci_get_device(dev);
3199b8d05b8SZbigniew Bodek 
3209b8d05b8SZbigniew Bodek 	ent = ena_vendor_info_array;
3219b8d05b8SZbigniew Bodek 	while (ent->vendor_id != 0) {
3229b8d05b8SZbigniew Bodek 		if ((pci_vendor_id == ent->vendor_id) &&
3239b8d05b8SZbigniew Bodek 		    (pci_device_id == ent->device_id)) {
3249eb1615fSMarcin Wojtas 			ena_trace(NULL, ENA_DBG, "vendor=%x device=%x\n",
3259b8d05b8SZbigniew Bodek 			    pci_vendor_id, pci_device_id);
3269b8d05b8SZbigniew Bodek 
3279b8d05b8SZbigniew Bodek 			sprintf(adapter_name, DEVICE_DESC);
3289b8d05b8SZbigniew Bodek 			device_set_desc_copy(dev, adapter_name);
3299b8d05b8SZbigniew Bodek 			return (BUS_PROBE_DEFAULT);
3309b8d05b8SZbigniew Bodek 		}
3319b8d05b8SZbigniew Bodek 
3329b8d05b8SZbigniew Bodek 		ent++;
3339b8d05b8SZbigniew Bodek 
3349b8d05b8SZbigniew Bodek 	}
3359b8d05b8SZbigniew Bodek 
3369b8d05b8SZbigniew Bodek 	return (ENXIO);
3379b8d05b8SZbigniew Bodek }
3389b8d05b8SZbigniew Bodek 
3399b8d05b8SZbigniew Bodek static int
3409b8d05b8SZbigniew Bodek ena_change_mtu(if_t ifp, int new_mtu)
3419b8d05b8SZbigniew Bodek {
3429b8d05b8SZbigniew Bodek 	struct ena_adapter *adapter = if_getsoftc(ifp);
3433cfadb28SMarcin Wojtas 	int rc;
3449b8d05b8SZbigniew Bodek 
3453cfadb28SMarcin Wojtas 	if ((new_mtu > adapter->max_mtu) || (new_mtu < ENA_MIN_MTU)) {
3469b8d05b8SZbigniew Bodek 		device_printf(adapter->pdev, "Invalid MTU setting. "
3473cfadb28SMarcin Wojtas 		    "new_mtu: %d max mtu: %d min mtu: %d\n",
3483cfadb28SMarcin Wojtas 		    new_mtu, adapter->max_mtu, ENA_MIN_MTU);
3493cfadb28SMarcin Wojtas 		return (EINVAL);
3509b8d05b8SZbigniew Bodek 	}
3519b8d05b8SZbigniew Bodek 
3529b8d05b8SZbigniew Bodek 	rc = ena_com_set_dev_mtu(adapter->ena_dev, new_mtu);
3533cfadb28SMarcin Wojtas 	if (likely(rc == 0)) {
3549eb1615fSMarcin Wojtas 		ena_trace(NULL, ENA_DBG, "set MTU to %d\n", new_mtu);
3553cfadb28SMarcin Wojtas 		if_setmtu(ifp, new_mtu);
3563cfadb28SMarcin Wojtas 	} else {
3573cfadb28SMarcin Wojtas 		device_printf(adapter->pdev, "Failed to set MTU to %d\n",
3583cfadb28SMarcin Wojtas 		    new_mtu);
3593cfadb28SMarcin Wojtas 	}
3609b8d05b8SZbigniew Bodek 
3613cfadb28SMarcin Wojtas 	return (rc);
3629b8d05b8SZbigniew Bodek }
3639b8d05b8SZbigniew Bodek 
3649b8d05b8SZbigniew Bodek static inline void
3659b8d05b8SZbigniew Bodek ena_alloc_counters(counter_u64_t *begin, int size)
3669b8d05b8SZbigniew Bodek {
3679b8d05b8SZbigniew Bodek 	counter_u64_t *end = (counter_u64_t *)((char *)begin + size);
3689b8d05b8SZbigniew Bodek 
3699b8d05b8SZbigniew Bodek 	for (; begin < end; ++begin)
3709b8d05b8SZbigniew Bodek 		*begin = counter_u64_alloc(M_WAITOK);
3719b8d05b8SZbigniew Bodek }
3729b8d05b8SZbigniew Bodek 
3739b8d05b8SZbigniew Bodek static inline void
3749b8d05b8SZbigniew Bodek ena_free_counters(counter_u64_t *begin, int size)
3759b8d05b8SZbigniew Bodek {
3769b8d05b8SZbigniew Bodek 	counter_u64_t *end = (counter_u64_t *)((char *)begin + size);
3779b8d05b8SZbigniew Bodek 
3789b8d05b8SZbigniew Bodek 	for (; begin < end; ++begin)
3799b8d05b8SZbigniew Bodek 		counter_u64_free(*begin);
3809b8d05b8SZbigniew Bodek }
3819b8d05b8SZbigniew Bodek 
3829b8d05b8SZbigniew Bodek static inline void
3839b8d05b8SZbigniew Bodek ena_reset_counters(counter_u64_t *begin, int size)
3849b8d05b8SZbigniew Bodek {
3859b8d05b8SZbigniew Bodek 	counter_u64_t *end = (counter_u64_t *)((char *)begin + size);
3869b8d05b8SZbigniew Bodek 
3879b8d05b8SZbigniew Bodek 	for (; begin < end; ++begin)
3889b8d05b8SZbigniew Bodek 		counter_u64_zero(*begin);
3899b8d05b8SZbigniew Bodek }
3909b8d05b8SZbigniew Bodek 
3919b8d05b8SZbigniew Bodek static void
3929b8d05b8SZbigniew Bodek ena_init_io_rings_common(struct ena_adapter *adapter, struct ena_ring *ring,
3939b8d05b8SZbigniew Bodek     uint16_t qid)
3949b8d05b8SZbigniew Bodek {
3959b8d05b8SZbigniew Bodek 
3969b8d05b8SZbigniew Bodek 	ring->qid = qid;
3979b8d05b8SZbigniew Bodek 	ring->adapter = adapter;
3989b8d05b8SZbigniew Bodek 	ring->ena_dev = adapter->ena_dev;
399d12f7bfcSMarcin Wojtas 	ring->first_interrupt = false;
400d12f7bfcSMarcin Wojtas 	ring->no_interrupt_event_cnt = 0;
4019b8d05b8SZbigniew Bodek }
4029b8d05b8SZbigniew Bodek 
403cd5d5804SMarcin Wojtas static void
4047d8c4feeSMarcin Wojtas ena_init_io_rings_basic(struct ena_adapter *adapter)
4059b8d05b8SZbigniew Bodek {
4069b8d05b8SZbigniew Bodek 	struct ena_com_dev *ena_dev;
4079b8d05b8SZbigniew Bodek 	struct ena_ring *txr, *rxr;
4089b8d05b8SZbigniew Bodek 	struct ena_que *que;
4099b8d05b8SZbigniew Bodek 	int i;
4109b8d05b8SZbigniew Bodek 
4119b8d05b8SZbigniew Bodek 	ena_dev = adapter->ena_dev;
4129b8d05b8SZbigniew Bodek 
4137d8c4feeSMarcin Wojtas 	for (i = 0; i < adapter->num_io_queues; i++) {
4149b8d05b8SZbigniew Bodek 		txr = &adapter->tx_ring[i];
4159b8d05b8SZbigniew Bodek 		rxr = &adapter->rx_ring[i];
4169b8d05b8SZbigniew Bodek 
4179b8d05b8SZbigniew Bodek 		/* TX/RX common ring state */
4189b8d05b8SZbigniew Bodek 		ena_init_io_rings_common(adapter, txr, i);
4199b8d05b8SZbigniew Bodek 		ena_init_io_rings_common(adapter, rxr, i);
4209b8d05b8SZbigniew Bodek 
4219b8d05b8SZbigniew Bodek 		/* TX specific ring state */
4229b8d05b8SZbigniew Bodek 		txr->tx_max_header_size = ena_dev->tx_max_header_size;
4239b8d05b8SZbigniew Bodek 		txr->tx_mem_queue_type = ena_dev->tx_mem_queue_type;
4249b8d05b8SZbigniew Bodek 
4259b8d05b8SZbigniew Bodek 		que = &adapter->que[i];
4269b8d05b8SZbigniew Bodek 		que->adapter = adapter;
4279b8d05b8SZbigniew Bodek 		que->id = i;
4289b8d05b8SZbigniew Bodek 		que->tx_ring = txr;
4299b8d05b8SZbigniew Bodek 		que->rx_ring = rxr;
4309b8d05b8SZbigniew Bodek 
4319b8d05b8SZbigniew Bodek 		txr->que = que;
4329b8d05b8SZbigniew Bodek 		rxr->que = que;
433efe6ab18SMarcin Wojtas 
434efe6ab18SMarcin Wojtas 		rxr->empty_rx_queue = 0;
4357d8c4feeSMarcin Wojtas 		rxr->rx_mbuf_sz = ena_mbuf_sz;
4369b8d05b8SZbigniew Bodek 	}
4379b8d05b8SZbigniew Bodek }
4389b8d05b8SZbigniew Bodek 
4399b8d05b8SZbigniew Bodek static void
4407d8c4feeSMarcin Wojtas ena_init_io_rings_advanced(struct ena_adapter *adapter)
4417d8c4feeSMarcin Wojtas {
4427d8c4feeSMarcin Wojtas 	struct ena_ring *txr, *rxr;
4437d8c4feeSMarcin Wojtas 	int i;
4447d8c4feeSMarcin Wojtas 
4457d8c4feeSMarcin Wojtas 	for (i = 0; i < adapter->num_io_queues; i++) {
4467d8c4feeSMarcin Wojtas 		txr = &adapter->tx_ring[i];
4477d8c4feeSMarcin Wojtas 		rxr = &adapter->rx_ring[i];
4487d8c4feeSMarcin Wojtas 
4497d8c4feeSMarcin Wojtas 		/* Allocate a buf ring */
4507d8c4feeSMarcin Wojtas 		txr->buf_ring_size = adapter->buf_ring_size;
4517d8c4feeSMarcin Wojtas 		txr->br = buf_ring_alloc(txr->buf_ring_size, M_DEVBUF,
4527d8c4feeSMarcin Wojtas 		    M_WAITOK, &txr->ring_mtx);
4537d8c4feeSMarcin Wojtas 
4547d8c4feeSMarcin Wojtas 		/* Allocate Tx statistics. */
4557d8c4feeSMarcin Wojtas 		ena_alloc_counters((counter_u64_t *)&txr->tx_stats,
4567d8c4feeSMarcin Wojtas 		    sizeof(txr->tx_stats));
4577d8c4feeSMarcin Wojtas 
4587d8c4feeSMarcin Wojtas 		/* Allocate Rx statistics. */
4597d8c4feeSMarcin Wojtas 		ena_alloc_counters((counter_u64_t *)&rxr->rx_stats,
4607d8c4feeSMarcin Wojtas 		    sizeof(rxr->rx_stats));
4617d8c4feeSMarcin Wojtas 
4627d8c4feeSMarcin Wojtas 		/* Initialize locks */
4637d8c4feeSMarcin Wojtas 		snprintf(txr->mtx_name, nitems(txr->mtx_name), "%s:tx(%d)",
4647d8c4feeSMarcin Wojtas 		    device_get_nameunit(adapter->pdev), i);
4657d8c4feeSMarcin Wojtas 		snprintf(rxr->mtx_name, nitems(rxr->mtx_name), "%s:rx(%d)",
4667d8c4feeSMarcin Wojtas 		    device_get_nameunit(adapter->pdev), i);
4677d8c4feeSMarcin Wojtas 
4687d8c4feeSMarcin Wojtas 		mtx_init(&txr->ring_mtx, txr->mtx_name, NULL, MTX_DEF);
4697d8c4feeSMarcin Wojtas 	}
4707d8c4feeSMarcin Wojtas }
4717d8c4feeSMarcin Wojtas 
4727d8c4feeSMarcin Wojtas static void
4737d8c4feeSMarcin Wojtas ena_init_io_rings(struct ena_adapter *adapter)
4747d8c4feeSMarcin Wojtas {
4757d8c4feeSMarcin Wojtas 	/*
4767d8c4feeSMarcin Wojtas 	 * IO rings initialization can be divided into the 2 steps:
4777d8c4feeSMarcin Wojtas 	 *   1. Initialize variables and fields with initial values and copy
4787d8c4feeSMarcin Wojtas 	 *      them from adapter/ena_dev (basic)
4797d8c4feeSMarcin Wojtas 	 *   2. Allocate mutex, counters and buf_ring (advanced)
4807d8c4feeSMarcin Wojtas 	 */
4817d8c4feeSMarcin Wojtas 	ena_init_io_rings_basic(adapter);
4827d8c4feeSMarcin Wojtas 	ena_init_io_rings_advanced(adapter);
4837d8c4feeSMarcin Wojtas }
4847d8c4feeSMarcin Wojtas 
4857d8c4feeSMarcin Wojtas static void
4869b8d05b8SZbigniew Bodek ena_free_io_ring_resources(struct ena_adapter *adapter, unsigned int qid)
4879b8d05b8SZbigniew Bodek {
4889b8d05b8SZbigniew Bodek 	struct ena_ring *txr = &adapter->tx_ring[qid];
4899b8d05b8SZbigniew Bodek 	struct ena_ring *rxr = &adapter->rx_ring[qid];
4909b8d05b8SZbigniew Bodek 
4919b8d05b8SZbigniew Bodek 	ena_free_counters((counter_u64_t *)&txr->tx_stats,
4929b8d05b8SZbigniew Bodek 	    sizeof(txr->tx_stats));
4939b8d05b8SZbigniew Bodek 	ena_free_counters((counter_u64_t *)&rxr->rx_stats,
4949b8d05b8SZbigniew Bodek 	    sizeof(rxr->rx_stats));
4959b8d05b8SZbigniew Bodek 
4967d2544e6SMarcin Wojtas 	ENA_RING_MTX_LOCK(txr);
4977d2544e6SMarcin Wojtas 	drbr_free(txr->br, M_DEVBUF);
4987d2544e6SMarcin Wojtas 	ENA_RING_MTX_UNLOCK(txr);
4997d2544e6SMarcin Wojtas 
5009b8d05b8SZbigniew Bodek 	mtx_destroy(&txr->ring_mtx);
5019b8d05b8SZbigniew Bodek }
5029b8d05b8SZbigniew Bodek 
5039b8d05b8SZbigniew Bodek static void
5049b8d05b8SZbigniew Bodek ena_free_all_io_rings_resources(struct ena_adapter *adapter)
5059b8d05b8SZbigniew Bodek {
5069b8d05b8SZbigniew Bodek 	int i;
5079b8d05b8SZbigniew Bodek 
5087d8c4feeSMarcin Wojtas 	for (i = 0; i < adapter->num_io_queues; i++)
5099b8d05b8SZbigniew Bodek 		ena_free_io_ring_resources(adapter, i);
5109b8d05b8SZbigniew Bodek 
5119b8d05b8SZbigniew Bodek }
5129b8d05b8SZbigniew Bodek 
5139b8d05b8SZbigniew Bodek static int
5149b8d05b8SZbigniew Bodek ena_setup_tx_dma_tag(struct ena_adapter *adapter)
5159b8d05b8SZbigniew Bodek {
5169b8d05b8SZbigniew Bodek 	int ret;
5179b8d05b8SZbigniew Bodek 
5189b8d05b8SZbigniew Bodek 	/* Create DMA tag for Tx buffers */
5199b8d05b8SZbigniew Bodek 	ret = bus_dma_tag_create(bus_get_dma_tag(adapter->pdev),
5209b8d05b8SZbigniew Bodek 	    1, 0,				  /* alignment, bounds 	     */
5218a573700SZbigniew Bodek 	    ENA_DMA_BIT_MASK(adapter->dma_width), /* lowaddr of excl window  */
5228a573700SZbigniew Bodek 	    BUS_SPACE_MAXADDR, 			  /* highaddr of excl window */
5239b8d05b8SZbigniew Bodek 	    NULL, NULL,				  /* filter, filterarg 	     */
5249b8d05b8SZbigniew Bodek 	    ENA_TSO_MAXSIZE,			  /* maxsize 		     */
5258a573700SZbigniew Bodek 	    adapter->max_tx_sgl_size - 1,	  /* nsegments 		     */
5269b8d05b8SZbigniew Bodek 	    ENA_TSO_MAXSIZE,			  /* maxsegsize 	     */
5279b8d05b8SZbigniew Bodek 	    0,					  /* flags 		     */
5289b8d05b8SZbigniew Bodek 	    NULL,				  /* lockfunc 		     */
5299b8d05b8SZbigniew Bodek 	    NULL,				  /* lockfuncarg 	     */
5309b8d05b8SZbigniew Bodek 	    &adapter->tx_buf_tag);
5319b8d05b8SZbigniew Bodek 
5329b8d05b8SZbigniew Bodek 	return (ret);
5339b8d05b8SZbigniew Bodek }
5349b8d05b8SZbigniew Bodek 
5359b8d05b8SZbigniew Bodek static int
5369b8d05b8SZbigniew Bodek ena_free_tx_dma_tag(struct ena_adapter *adapter)
5379b8d05b8SZbigniew Bodek {
5389b8d05b8SZbigniew Bodek 	int ret;
5399b8d05b8SZbigniew Bodek 
5409b8d05b8SZbigniew Bodek 	ret = bus_dma_tag_destroy(adapter->tx_buf_tag);
5419b8d05b8SZbigniew Bodek 
5423f9ed7abSMarcin Wojtas 	if (likely(ret == 0))
5439b8d05b8SZbigniew Bodek 		adapter->tx_buf_tag = NULL;
5449b8d05b8SZbigniew Bodek 
5459b8d05b8SZbigniew Bodek 	return (ret);
5469b8d05b8SZbigniew Bodek }
5479b8d05b8SZbigniew Bodek 
5489b8d05b8SZbigniew Bodek static int
5499b8d05b8SZbigniew Bodek ena_setup_rx_dma_tag(struct ena_adapter *adapter)
5509b8d05b8SZbigniew Bodek {
5519b8d05b8SZbigniew Bodek 	int ret;
5529b8d05b8SZbigniew Bodek 
5539b8d05b8SZbigniew Bodek 	/* Create DMA tag for Rx buffers*/
5549b8d05b8SZbigniew Bodek 	ret = bus_dma_tag_create(bus_get_dma_tag(adapter->pdev), /* parent   */
5559b8d05b8SZbigniew Bodek 	    1, 0,				  /* alignment, bounds 	     */
5568a573700SZbigniew Bodek 	    ENA_DMA_BIT_MASK(adapter->dma_width), /* lowaddr of excl window  */
5578a573700SZbigniew Bodek 	    BUS_SPACE_MAXADDR, 			  /* highaddr of excl window */
5589b8d05b8SZbigniew Bodek 	    NULL, NULL,				  /* filter, filterarg 	     */
55904cf2b88SMarcin Wojtas 	    ena_mbuf_sz,			  /* maxsize 		     */
5604727bda6SMarcin Wojtas 	    adapter->max_rx_sgl_size,		  /* nsegments 		     */
56104cf2b88SMarcin Wojtas 	    ena_mbuf_sz,			  /* maxsegsize 	     */
5629b8d05b8SZbigniew Bodek 	    0,					  /* flags 		     */
5639b8d05b8SZbigniew Bodek 	    NULL,				  /* lockfunc 		     */
5649b8d05b8SZbigniew Bodek 	    NULL,				  /* lockarg 		     */
5659b8d05b8SZbigniew Bodek 	    &adapter->rx_buf_tag);
5669b8d05b8SZbigniew Bodek 
5679b8d05b8SZbigniew Bodek 	return (ret);
5689b8d05b8SZbigniew Bodek }
5699b8d05b8SZbigniew Bodek 
5709b8d05b8SZbigniew Bodek static int
5719b8d05b8SZbigniew Bodek ena_free_rx_dma_tag(struct ena_adapter *adapter)
5729b8d05b8SZbigniew Bodek {
5739b8d05b8SZbigniew Bodek 	int ret;
5749b8d05b8SZbigniew Bodek 
5759b8d05b8SZbigniew Bodek 	ret = bus_dma_tag_destroy(adapter->rx_buf_tag);
5769b8d05b8SZbigniew Bodek 
5773f9ed7abSMarcin Wojtas 	if (likely(ret == 0))
5789b8d05b8SZbigniew Bodek 		adapter->rx_buf_tag = NULL;
5799b8d05b8SZbigniew Bodek 
5809b8d05b8SZbigniew Bodek 	return (ret);
5819b8d05b8SZbigniew Bodek }
5829b8d05b8SZbigniew Bodek 
5836f2128c7SMarcin Wojtas static void
5846f2128c7SMarcin Wojtas ena_release_all_tx_dmamap(struct ena_ring *tx_ring)
5856f2128c7SMarcin Wojtas {
5866f2128c7SMarcin Wojtas 	struct ena_adapter *adapter = tx_ring->adapter;
5876f2128c7SMarcin Wojtas 	struct ena_tx_buffer *tx_info;
5886f2128c7SMarcin Wojtas 	bus_dma_tag_t tx_tag = adapter->tx_buf_tag;;
5896f2128c7SMarcin Wojtas 	int i;
5906f2128c7SMarcin Wojtas #ifdef DEV_NETMAP
5916f2128c7SMarcin Wojtas 	struct ena_netmap_tx_info *nm_info;
5926f2128c7SMarcin Wojtas 	int j;
5936f2128c7SMarcin Wojtas #endif /* DEV_NETMAP */
5946f2128c7SMarcin Wojtas 
5956f2128c7SMarcin Wojtas 	for (i = 0; i < tx_ring->ring_size; ++i) {
5966f2128c7SMarcin Wojtas 		tx_info = &tx_ring->tx_buffer_info[i];
5976f2128c7SMarcin Wojtas #ifdef DEV_NETMAP
5986f2128c7SMarcin Wojtas 		if (adapter->ifp->if_capenable & IFCAP_NETMAP) {
5996f2128c7SMarcin Wojtas 			nm_info = &tx_info->nm_info;
6006f2128c7SMarcin Wojtas 			for (j = 0; j < ENA_PKT_MAX_BUFS; ++j) {
6016f2128c7SMarcin Wojtas 				if (nm_info->map_seg[j] != NULL) {
6026f2128c7SMarcin Wojtas 					bus_dmamap_destroy(tx_tag,
6036f2128c7SMarcin Wojtas 					    nm_info->map_seg[j]);
6046f2128c7SMarcin Wojtas 					nm_info->map_seg[j] = NULL;
6056f2128c7SMarcin Wojtas 				}
6066f2128c7SMarcin Wojtas 			}
6076f2128c7SMarcin Wojtas 		}
6086f2128c7SMarcin Wojtas #endif /* DEV_NETMAP */
609888810f0SMarcin Wojtas 		if (tx_info->dmamap != NULL) {
610888810f0SMarcin Wojtas 			bus_dmamap_destroy(tx_tag, tx_info->dmamap);
611888810f0SMarcin Wojtas 			tx_info->dmamap = NULL;
6126f2128c7SMarcin Wojtas 		}
6136f2128c7SMarcin Wojtas 	}
6146f2128c7SMarcin Wojtas }
6156f2128c7SMarcin Wojtas 
6169b8d05b8SZbigniew Bodek /**
6179b8d05b8SZbigniew Bodek  * ena_setup_tx_resources - allocate Tx resources (Descriptors)
6189b8d05b8SZbigniew Bodek  * @adapter: network interface device structure
6199b8d05b8SZbigniew Bodek  * @qid: queue index
6209b8d05b8SZbigniew Bodek  *
6219b8d05b8SZbigniew Bodek  * Returns 0 on success, otherwise on failure.
6229b8d05b8SZbigniew Bodek  **/
6239b8d05b8SZbigniew Bodek static int
6249b8d05b8SZbigniew Bodek ena_setup_tx_resources(struct ena_adapter *adapter, int qid)
6259b8d05b8SZbigniew Bodek {
6269b8d05b8SZbigniew Bodek 	struct ena_que *que = &adapter->que[qid];
6279b8d05b8SZbigniew Bodek 	struct ena_ring *tx_ring = que->tx_ring;
6289b8d05b8SZbigniew Bodek 	int size, i, err;
6296f2128c7SMarcin Wojtas #ifdef DEV_NETMAP
6306f2128c7SMarcin Wojtas 	bus_dmamap_t *map;
6316f2128c7SMarcin Wojtas 	int j;
6326f2128c7SMarcin Wojtas 
6336f2128c7SMarcin Wojtas 	ena_netmap_reset_tx_ring(adapter, qid);
6346f2128c7SMarcin Wojtas #endif /* DEV_NETMAP */
6359b8d05b8SZbigniew Bodek 
6369b8d05b8SZbigniew Bodek 	size = sizeof(struct ena_tx_buffer) * tx_ring->ring_size;
6379b8d05b8SZbigniew Bodek 
6389b8d05b8SZbigniew Bodek 	tx_ring->tx_buffer_info = malloc(size, M_DEVBUF, M_NOWAIT | M_ZERO);
6393f9ed7abSMarcin Wojtas 	if (unlikely(tx_ring->tx_buffer_info == NULL))
6407d2544e6SMarcin Wojtas 		return (ENOMEM);
6419b8d05b8SZbigniew Bodek 
6429b8d05b8SZbigniew Bodek 	size = sizeof(uint16_t) * tx_ring->ring_size;
6439b8d05b8SZbigniew Bodek 	tx_ring->free_tx_ids = malloc(size, M_DEVBUF, M_NOWAIT | M_ZERO);
6443f9ed7abSMarcin Wojtas 	if (unlikely(tx_ring->free_tx_ids == NULL))
6457d2544e6SMarcin Wojtas 		goto err_buf_info_free;
6469b8d05b8SZbigniew Bodek 
6474fa9e02dSMarcin Wojtas 	size = tx_ring->tx_max_header_size;
6484fa9e02dSMarcin Wojtas 	tx_ring->push_buf_intermediate_buf = malloc(size, M_DEVBUF,
6494fa9e02dSMarcin Wojtas 	    M_NOWAIT | M_ZERO);
6504fa9e02dSMarcin Wojtas 	if (unlikely(tx_ring->push_buf_intermediate_buf == NULL))
6514fa9e02dSMarcin Wojtas 		goto err_tx_ids_free;
6524fa9e02dSMarcin Wojtas 
6539b8d05b8SZbigniew Bodek 	/* Req id stack for TX OOO completions */
6549b8d05b8SZbigniew Bodek 	for (i = 0; i < tx_ring->ring_size; i++)
6559b8d05b8SZbigniew Bodek 		tx_ring->free_tx_ids[i] = i;
6569b8d05b8SZbigniew Bodek 
6579b8d05b8SZbigniew Bodek 	/* Reset TX statistics. */
6589b8d05b8SZbigniew Bodek 	ena_reset_counters((counter_u64_t *)&tx_ring->tx_stats,
6599b8d05b8SZbigniew Bodek 	    sizeof(tx_ring->tx_stats));
6609b8d05b8SZbigniew Bodek 
6619b8d05b8SZbigniew Bodek 	tx_ring->next_to_use = 0;
6629b8d05b8SZbigniew Bodek 	tx_ring->next_to_clean = 0;
663af66d7d0SMarcin Wojtas 	tx_ring->acum_pkts = 0;
6649b8d05b8SZbigniew Bodek 
6659b8d05b8SZbigniew Bodek 	/* Make sure that drbr is empty */
666b38cf613SZbigniew Bodek 	ENA_RING_MTX_LOCK(tx_ring);
6679b8d05b8SZbigniew Bodek 	drbr_flush(adapter->ifp, tx_ring->br);
668b38cf613SZbigniew Bodek 	ENA_RING_MTX_UNLOCK(tx_ring);
6699b8d05b8SZbigniew Bodek 
6709b8d05b8SZbigniew Bodek 	/* ... and create the buffer DMA maps */
6719b8d05b8SZbigniew Bodek 	for (i = 0; i < tx_ring->ring_size; i++) {
6729b8d05b8SZbigniew Bodek 		err = bus_dmamap_create(adapter->tx_buf_tag, 0,
673888810f0SMarcin Wojtas 		    &tx_ring->tx_buffer_info[i].dmamap);
6743f9ed7abSMarcin Wojtas 		if (unlikely(err != 0)) {
6759eb1615fSMarcin Wojtas 			ena_trace(NULL, ENA_ALERT,
676888810f0SMarcin Wojtas 			    "Unable to create Tx DMA map for buffer %d\n",
6774fa9e02dSMarcin Wojtas 			    i);
6786f2128c7SMarcin Wojtas 			goto err_map_release;
6799b8d05b8SZbigniew Bodek 		}
6806f2128c7SMarcin Wojtas 
6816f2128c7SMarcin Wojtas #ifdef DEV_NETMAP
6826f2128c7SMarcin Wojtas 		if (adapter->ifp->if_capenable & IFCAP_NETMAP) {
6836f2128c7SMarcin Wojtas 			map = tx_ring->tx_buffer_info[i].nm_info.map_seg;
6846f2128c7SMarcin Wojtas 			for (j = 0; j < ENA_PKT_MAX_BUFS; j++) {
6856f2128c7SMarcin Wojtas 				err = bus_dmamap_create(adapter->tx_buf_tag, 0,
6866f2128c7SMarcin Wojtas 				    &map[j]);
6876f2128c7SMarcin Wojtas 				if (unlikely(err != 0)) {
6889eb1615fSMarcin Wojtas 					ena_trace(NULL, ENA_ALERT, "Unable to create "
6896f2128c7SMarcin Wojtas 					    "Tx DMA for buffer %d %d\n", i, j);
6906f2128c7SMarcin Wojtas 					goto err_map_release;
6916f2128c7SMarcin Wojtas 				}
6926f2128c7SMarcin Wojtas 			}
6936f2128c7SMarcin Wojtas 		}
6946f2128c7SMarcin Wojtas #endif /* DEV_NETMAP */
6959b8d05b8SZbigniew Bodek 	}
6969b8d05b8SZbigniew Bodek 
6979b8d05b8SZbigniew Bodek 	/* Allocate taskqueues */
6989b8d05b8SZbigniew Bodek 	TASK_INIT(&tx_ring->enqueue_task, 0, ena_deferred_mq_start, tx_ring);
6999b8d05b8SZbigniew Bodek 	tx_ring->enqueue_tq = taskqueue_create_fast("ena_tx_enque", M_NOWAIT,
7009b8d05b8SZbigniew Bodek 	    taskqueue_thread_enqueue, &tx_ring->enqueue_tq);
7013f9ed7abSMarcin Wojtas 	if (unlikely(tx_ring->enqueue_tq == NULL)) {
7029eb1615fSMarcin Wojtas 		ena_trace(NULL, ENA_ALERT,
7039b8d05b8SZbigniew Bodek 		    "Unable to create taskqueue for enqueue task\n");
7049b8d05b8SZbigniew Bodek 		i = tx_ring->ring_size;
7056f2128c7SMarcin Wojtas 		goto err_map_release;
7069b8d05b8SZbigniew Bodek 	}
7079b8d05b8SZbigniew Bodek 
7085cb9db07SMarcin Wojtas 	tx_ring->running = true;
7095cb9db07SMarcin Wojtas 
7109b8d05b8SZbigniew Bodek 	taskqueue_start_threads(&tx_ring->enqueue_tq, 1, PI_NET,
7119b8d05b8SZbigniew Bodek 	    "%s txeq %d", device_get_nameunit(adapter->pdev), que->cpu);
7129b8d05b8SZbigniew Bodek 
7139b8d05b8SZbigniew Bodek 	return (0);
7149b8d05b8SZbigniew Bodek 
7156f2128c7SMarcin Wojtas err_map_release:
7166f2128c7SMarcin Wojtas 	ena_release_all_tx_dmamap(tx_ring);
7174fa9e02dSMarcin Wojtas err_tx_ids_free:
718cd5d5804SMarcin Wojtas 	free(tx_ring->free_tx_ids, M_DEVBUF);
7197d2544e6SMarcin Wojtas 	tx_ring->free_tx_ids = NULL;
7207d2544e6SMarcin Wojtas err_buf_info_free:
721cd5d5804SMarcin Wojtas 	free(tx_ring->tx_buffer_info, M_DEVBUF);
7227d2544e6SMarcin Wojtas 	tx_ring->tx_buffer_info = NULL;
7237d2544e6SMarcin Wojtas 
7249b8d05b8SZbigniew Bodek 	return (ENOMEM);
7259b8d05b8SZbigniew Bodek }
7269b8d05b8SZbigniew Bodek 
7279b8d05b8SZbigniew Bodek /**
7289b8d05b8SZbigniew Bodek  * ena_free_tx_resources - Free Tx Resources per Queue
7299b8d05b8SZbigniew Bodek  * @adapter: network interface device structure
7309b8d05b8SZbigniew Bodek  * @qid: queue index
7319b8d05b8SZbigniew Bodek  *
7329b8d05b8SZbigniew Bodek  * Free all transmit software resources
7339b8d05b8SZbigniew Bodek  **/
7349b8d05b8SZbigniew Bodek static void
7359b8d05b8SZbigniew Bodek ena_free_tx_resources(struct ena_adapter *adapter, int qid)
7369b8d05b8SZbigniew Bodek {
7379b8d05b8SZbigniew Bodek 	struct ena_ring *tx_ring = &adapter->tx_ring[qid];
7386f2128c7SMarcin Wojtas #ifdef DEV_NETMAP
7396f2128c7SMarcin Wojtas 	struct ena_netmap_tx_info *nm_info;
7406f2128c7SMarcin Wojtas 	int j;
7416f2128c7SMarcin Wojtas #endif /* DEV_NETMAP */
7429b8d05b8SZbigniew Bodek 
7439b8d05b8SZbigniew Bodek 	while (taskqueue_cancel(tx_ring->enqueue_tq, &tx_ring->enqueue_task,
7449b8d05b8SZbigniew Bodek 	    NULL))
7459b8d05b8SZbigniew Bodek 		taskqueue_drain(tx_ring->enqueue_tq, &tx_ring->enqueue_task);
7469b8d05b8SZbigniew Bodek 
7479b8d05b8SZbigniew Bodek 	taskqueue_free(tx_ring->enqueue_tq);
7489b8d05b8SZbigniew Bodek 
749b38cf613SZbigniew Bodek 	ENA_RING_MTX_LOCK(tx_ring);
7509b8d05b8SZbigniew Bodek 	/* Flush buffer ring, */
7519b8d05b8SZbigniew Bodek 	drbr_flush(adapter->ifp, tx_ring->br);
7529b8d05b8SZbigniew Bodek 
7539b8d05b8SZbigniew Bodek 	/* Free buffer DMA maps, */
7549b8d05b8SZbigniew Bodek 	for (int i = 0; i < tx_ring->ring_size; i++) {
755e8073738SMarcin Wojtas 		bus_dmamap_sync(adapter->tx_buf_tag,
756888810f0SMarcin Wojtas 		    tx_ring->tx_buffer_info[i].dmamap, BUS_DMASYNC_POSTWRITE);
7579b8d05b8SZbigniew Bodek 		bus_dmamap_unload(adapter->tx_buf_tag,
758888810f0SMarcin Wojtas 		    tx_ring->tx_buffer_info[i].dmamap);
7599b8d05b8SZbigniew Bodek 		bus_dmamap_destroy(adapter->tx_buf_tag,
760888810f0SMarcin Wojtas 		    tx_ring->tx_buffer_info[i].dmamap);
7614fa9e02dSMarcin Wojtas 
7626f2128c7SMarcin Wojtas #ifdef DEV_NETMAP
7636f2128c7SMarcin Wojtas 		if (adapter->ifp->if_capenable & IFCAP_NETMAP) {
7646f2128c7SMarcin Wojtas 			nm_info = &tx_ring->tx_buffer_info[i].nm_info;
7656f2128c7SMarcin Wojtas 			for (j = 0; j < ENA_PKT_MAX_BUFS; j++) {
7666f2128c7SMarcin Wojtas 				if (nm_info->socket_buf_idx[j] != 0) {
7676f2128c7SMarcin Wojtas 					bus_dmamap_sync(adapter->tx_buf_tag,
7686f2128c7SMarcin Wojtas 					    nm_info->map_seg[j],
7696f2128c7SMarcin Wojtas 					    BUS_DMASYNC_POSTWRITE);
7706f2128c7SMarcin Wojtas 					ena_netmap_unload(adapter,
7716f2128c7SMarcin Wojtas 					    nm_info->map_seg[j]);
7726f2128c7SMarcin Wojtas 				}
7736f2128c7SMarcin Wojtas 				bus_dmamap_destroy(adapter->tx_buf_tag,
7746f2128c7SMarcin Wojtas 				    nm_info->map_seg[j]);
7756f2128c7SMarcin Wojtas 				nm_info->socket_buf_idx[j] = 0;
7766f2128c7SMarcin Wojtas 			}
7776f2128c7SMarcin Wojtas 		}
7786f2128c7SMarcin Wojtas #endif /* DEV_NETMAP */
7796f2128c7SMarcin Wojtas 
780e8073738SMarcin Wojtas 		m_freem(tx_ring->tx_buffer_info[i].mbuf);
781e8073738SMarcin Wojtas 		tx_ring->tx_buffer_info[i].mbuf = NULL;
7829b8d05b8SZbigniew Bodek 	}
783416e8864SZbigniew Bodek 	ENA_RING_MTX_UNLOCK(tx_ring);
7849b8d05b8SZbigniew Bodek 
7859b8d05b8SZbigniew Bodek 	/* And free allocated memory. */
786cd5d5804SMarcin Wojtas 	free(tx_ring->tx_buffer_info, M_DEVBUF);
7879b8d05b8SZbigniew Bodek 	tx_ring->tx_buffer_info = NULL;
7889b8d05b8SZbigniew Bodek 
789cd5d5804SMarcin Wojtas 	free(tx_ring->free_tx_ids, M_DEVBUF);
7909b8d05b8SZbigniew Bodek 	tx_ring->free_tx_ids = NULL;
7914fa9e02dSMarcin Wojtas 
7928483b844SMarcin Wojtas 	free(tx_ring->push_buf_intermediate_buf, M_DEVBUF);
7934fa9e02dSMarcin Wojtas 	tx_ring->push_buf_intermediate_buf = NULL;
7949b8d05b8SZbigniew Bodek }
7959b8d05b8SZbigniew Bodek 
7969b8d05b8SZbigniew Bodek /**
7979b8d05b8SZbigniew Bodek  * ena_setup_all_tx_resources - allocate all queues Tx resources
7989b8d05b8SZbigniew Bodek  * @adapter: network interface device structure
7999b8d05b8SZbigniew Bodek  *
8009b8d05b8SZbigniew Bodek  * Returns 0 on success, otherwise on failure.
8019b8d05b8SZbigniew Bodek  **/
8029b8d05b8SZbigniew Bodek static int
8039b8d05b8SZbigniew Bodek ena_setup_all_tx_resources(struct ena_adapter *adapter)
8049b8d05b8SZbigniew Bodek {
8059b8d05b8SZbigniew Bodek 	int i, rc;
8069b8d05b8SZbigniew Bodek 
8077d8c4feeSMarcin Wojtas 	for (i = 0; i < adapter->num_io_queues; i++) {
8089b8d05b8SZbigniew Bodek 		rc = ena_setup_tx_resources(adapter, i);
8090bdffe59SMarcin Wojtas 		if (rc != 0) {
8109b8d05b8SZbigniew Bodek 			device_printf(adapter->pdev,
8119b8d05b8SZbigniew Bodek 			    "Allocation for Tx Queue %u failed\n", i);
8129b8d05b8SZbigniew Bodek 			goto err_setup_tx;
8139b8d05b8SZbigniew Bodek 		}
8147d2544e6SMarcin Wojtas 	}
8159b8d05b8SZbigniew Bodek 
8169b8d05b8SZbigniew Bodek 	return (0);
8179b8d05b8SZbigniew Bodek 
8189b8d05b8SZbigniew Bodek err_setup_tx:
8199b8d05b8SZbigniew Bodek 	/* Rewind the index freeing the rings as we go */
8209b8d05b8SZbigniew Bodek 	while (i--)
8219b8d05b8SZbigniew Bodek 		ena_free_tx_resources(adapter, i);
8229b8d05b8SZbigniew Bodek 	return (rc);
8239b8d05b8SZbigniew Bodek }
8249b8d05b8SZbigniew Bodek 
8259b8d05b8SZbigniew Bodek /**
8269b8d05b8SZbigniew Bodek  * ena_free_all_tx_resources - Free Tx Resources for All Queues
8279b8d05b8SZbigniew Bodek  * @adapter: network interface device structure
8289b8d05b8SZbigniew Bodek  *
8299b8d05b8SZbigniew Bodek  * Free all transmit software resources
8309b8d05b8SZbigniew Bodek  **/
8319b8d05b8SZbigniew Bodek static void
8329b8d05b8SZbigniew Bodek ena_free_all_tx_resources(struct ena_adapter *adapter)
8339b8d05b8SZbigniew Bodek {
8349b8d05b8SZbigniew Bodek 	int i;
8359b8d05b8SZbigniew Bodek 
8367d8c4feeSMarcin Wojtas 	for (i = 0; i < adapter->num_io_queues; i++)
8379b8d05b8SZbigniew Bodek 		ena_free_tx_resources(adapter, i);
8389b8d05b8SZbigniew Bodek }
8399b8d05b8SZbigniew Bodek 
8409b8d05b8SZbigniew Bodek /**
8419b8d05b8SZbigniew Bodek  * ena_setup_rx_resources - allocate Rx resources (Descriptors)
8429b8d05b8SZbigniew Bodek  * @adapter: network interface device structure
8439b8d05b8SZbigniew Bodek  * @qid: queue index
8449b8d05b8SZbigniew Bodek  *
8459b8d05b8SZbigniew Bodek  * Returns 0 on success, otherwise on failure.
8469b8d05b8SZbigniew Bodek  **/
8479b8d05b8SZbigniew Bodek static int
8489b8d05b8SZbigniew Bodek ena_setup_rx_resources(struct ena_adapter *adapter, unsigned int qid)
8499b8d05b8SZbigniew Bodek {
8509b8d05b8SZbigniew Bodek 	struct ena_que *que = &adapter->que[qid];
8519b8d05b8SZbigniew Bodek 	struct ena_ring *rx_ring = que->rx_ring;
8529b8d05b8SZbigniew Bodek 	int size, err, i;
8539b8d05b8SZbigniew Bodek 
8549b8d05b8SZbigniew Bodek 	size = sizeof(struct ena_rx_buffer) * rx_ring->ring_size;
8559b8d05b8SZbigniew Bodek 
8569a0f2079SMarcin Wojtas #ifdef DEV_NETMAP
8579a0f2079SMarcin Wojtas 	ena_netmap_reset_rx_ring(adapter, qid);
8589a0f2079SMarcin Wojtas 	rx_ring->initialized = false;
8599a0f2079SMarcin Wojtas #endif /* DEV_NETMAP */
8609a0f2079SMarcin Wojtas 
8619b8d05b8SZbigniew Bodek 	/*
8629b8d05b8SZbigniew Bodek 	 * Alloc extra element so in rx path
8639b8d05b8SZbigniew Bodek 	 * we can always prefetch rx_info + 1
8649b8d05b8SZbigniew Bodek 	 */
8659b8d05b8SZbigniew Bodek 	size += sizeof(struct ena_rx_buffer);
8669b8d05b8SZbigniew Bodek 
867cd5d5804SMarcin Wojtas 	rx_ring->rx_buffer_info = malloc(size, M_DEVBUF, M_WAITOK | M_ZERO);
8689b8d05b8SZbigniew Bodek 
86943fefd16SMarcin Wojtas 	size = sizeof(uint16_t) * rx_ring->ring_size;
87043fefd16SMarcin Wojtas 	rx_ring->free_rx_ids = malloc(size, M_DEVBUF, M_WAITOK);
87143fefd16SMarcin Wojtas 
87243fefd16SMarcin Wojtas 	for (i = 0; i < rx_ring->ring_size; i++)
87343fefd16SMarcin Wojtas 		rx_ring->free_rx_ids[i] = i;
87443fefd16SMarcin Wojtas 
8759b8d05b8SZbigniew Bodek 	/* Reset RX statistics. */
8769b8d05b8SZbigniew Bodek 	ena_reset_counters((counter_u64_t *)&rx_ring->rx_stats,
8779b8d05b8SZbigniew Bodek 	    sizeof(rx_ring->rx_stats));
8789b8d05b8SZbigniew Bodek 
8799b8d05b8SZbigniew Bodek 	rx_ring->next_to_clean = 0;
8809b8d05b8SZbigniew Bodek 	rx_ring->next_to_use = 0;
8819b8d05b8SZbigniew Bodek 
8829b8d05b8SZbigniew Bodek 	/* ... and create the buffer DMA maps */
8839b8d05b8SZbigniew Bodek 	for (i = 0; i < rx_ring->ring_size; i++) {
8849b8d05b8SZbigniew Bodek 		err = bus_dmamap_create(adapter->rx_buf_tag, 0,
8859b8d05b8SZbigniew Bodek 		    &(rx_ring->rx_buffer_info[i].map));
8869b8d05b8SZbigniew Bodek 		if (err != 0) {
8879eb1615fSMarcin Wojtas 			ena_trace(NULL, ENA_ALERT,
8889b8d05b8SZbigniew Bodek 			    "Unable to create Rx DMA map for buffer %d\n", i);
8897d2544e6SMarcin Wojtas 			goto err_buf_info_unmap;
8909b8d05b8SZbigniew Bodek 		}
8919b8d05b8SZbigniew Bodek 	}
8929b8d05b8SZbigniew Bodek 
8939b8d05b8SZbigniew Bodek 	/* Create LRO for the ring */
8940bdffe59SMarcin Wojtas 	if ((adapter->ifp->if_capenable & IFCAP_LRO) != 0) {
8959b8d05b8SZbigniew Bodek 		int err = tcp_lro_init(&rx_ring->lro);
8960bdffe59SMarcin Wojtas 		if (err != 0) {
8979b8d05b8SZbigniew Bodek 			device_printf(adapter->pdev,
8989b8d05b8SZbigniew Bodek 			    "LRO[%d] Initialization failed!\n", qid);
8999b8d05b8SZbigniew Bodek 		} else {
9009eb1615fSMarcin Wojtas 			ena_trace(NULL, ENA_INFO,
9019b8d05b8SZbigniew Bodek 			    "RX Soft LRO[%d] Initialized\n", qid);
9029b8d05b8SZbigniew Bodek 			rx_ring->lro.ifp = adapter->ifp;
9039b8d05b8SZbigniew Bodek 		}
9049b8d05b8SZbigniew Bodek 	}
9059b8d05b8SZbigniew Bodek 
9069b8d05b8SZbigniew Bodek 	return (0);
9079b8d05b8SZbigniew Bodek 
9087d2544e6SMarcin Wojtas err_buf_info_unmap:
9099b8d05b8SZbigniew Bodek 	while (i--) {
9109b8d05b8SZbigniew Bodek 		bus_dmamap_destroy(adapter->rx_buf_tag,
9119b8d05b8SZbigniew Bodek 		    rx_ring->rx_buffer_info[i].map);
9129b8d05b8SZbigniew Bodek 	}
9139b8d05b8SZbigniew Bodek 
91443fefd16SMarcin Wojtas 	free(rx_ring->free_rx_ids, M_DEVBUF);
91543fefd16SMarcin Wojtas 	rx_ring->free_rx_ids = NULL;
916cd5d5804SMarcin Wojtas 	free(rx_ring->rx_buffer_info, M_DEVBUF);
9179b8d05b8SZbigniew Bodek 	rx_ring->rx_buffer_info = NULL;
9189b8d05b8SZbigniew Bodek 	return (ENOMEM);
9199b8d05b8SZbigniew Bodek }
9209b8d05b8SZbigniew Bodek 
9219b8d05b8SZbigniew Bodek /**
9229b8d05b8SZbigniew Bodek  * ena_free_rx_resources - Free Rx Resources
9239b8d05b8SZbigniew Bodek  * @adapter: network interface device structure
9249b8d05b8SZbigniew Bodek  * @qid: queue index
9259b8d05b8SZbigniew Bodek  *
9269b8d05b8SZbigniew Bodek  * Free all receive software resources
9279b8d05b8SZbigniew Bodek  **/
9289b8d05b8SZbigniew Bodek static void
9299b8d05b8SZbigniew Bodek ena_free_rx_resources(struct ena_adapter *adapter, unsigned int qid)
9309b8d05b8SZbigniew Bodek {
9319b8d05b8SZbigniew Bodek 	struct ena_ring *rx_ring = &adapter->rx_ring[qid];
9329b8d05b8SZbigniew Bodek 
9339b8d05b8SZbigniew Bodek 	/* Free buffer DMA maps, */
9349b8d05b8SZbigniew Bodek 	for (int i = 0; i < rx_ring->ring_size; i++) {
935e8073738SMarcin Wojtas 		bus_dmamap_sync(adapter->rx_buf_tag,
936e8073738SMarcin Wojtas 		    rx_ring->rx_buffer_info[i].map, BUS_DMASYNC_POSTREAD);
9379b8d05b8SZbigniew Bodek 		m_freem(rx_ring->rx_buffer_info[i].mbuf);
9389b8d05b8SZbigniew Bodek 		rx_ring->rx_buffer_info[i].mbuf = NULL;
9399b8d05b8SZbigniew Bodek 		bus_dmamap_unload(adapter->rx_buf_tag,
9409b8d05b8SZbigniew Bodek 		    rx_ring->rx_buffer_info[i].map);
9419b8d05b8SZbigniew Bodek 		bus_dmamap_destroy(adapter->rx_buf_tag,
9429b8d05b8SZbigniew Bodek 		    rx_ring->rx_buffer_info[i].map);
9439b8d05b8SZbigniew Bodek 	}
9449b8d05b8SZbigniew Bodek 
9459b8d05b8SZbigniew Bodek 	/* free LRO resources, */
9469b8d05b8SZbigniew Bodek 	tcp_lro_free(&rx_ring->lro);
9479b8d05b8SZbigniew Bodek 
9489b8d05b8SZbigniew Bodek 	/* free allocated memory */
949cd5d5804SMarcin Wojtas 	free(rx_ring->rx_buffer_info, M_DEVBUF);
9509b8d05b8SZbigniew Bodek 	rx_ring->rx_buffer_info = NULL;
9519b8d05b8SZbigniew Bodek 
95243fefd16SMarcin Wojtas 	free(rx_ring->free_rx_ids, M_DEVBUF);
95343fefd16SMarcin Wojtas 	rx_ring->free_rx_ids = NULL;
9549b8d05b8SZbigniew Bodek }
9559b8d05b8SZbigniew Bodek 
9569b8d05b8SZbigniew Bodek /**
9579b8d05b8SZbigniew Bodek  * ena_setup_all_rx_resources - allocate all queues Rx resources
9589b8d05b8SZbigniew Bodek  * @adapter: network interface device structure
9599b8d05b8SZbigniew Bodek  *
9609b8d05b8SZbigniew Bodek  * Returns 0 on success, otherwise on failure.
9619b8d05b8SZbigniew Bodek  **/
9629b8d05b8SZbigniew Bodek static int
9639b8d05b8SZbigniew Bodek ena_setup_all_rx_resources(struct ena_adapter *adapter)
9649b8d05b8SZbigniew Bodek {
9659b8d05b8SZbigniew Bodek 	int i, rc = 0;
9669b8d05b8SZbigniew Bodek 
9677d8c4feeSMarcin Wojtas 	for (i = 0; i < adapter->num_io_queues; i++) {
9689b8d05b8SZbigniew Bodek 		rc = ena_setup_rx_resources(adapter, i);
9690bdffe59SMarcin Wojtas 		if (rc != 0) {
9709b8d05b8SZbigniew Bodek 			device_printf(adapter->pdev,
9719b8d05b8SZbigniew Bodek 			    "Allocation for Rx Queue %u failed\n", i);
9729b8d05b8SZbigniew Bodek 			goto err_setup_rx;
9739b8d05b8SZbigniew Bodek 		}
9747d2544e6SMarcin Wojtas 	}
9759b8d05b8SZbigniew Bodek 	return (0);
9769b8d05b8SZbigniew Bodek 
9779b8d05b8SZbigniew Bodek err_setup_rx:
9789b8d05b8SZbigniew Bodek 	/* rewind the index freeing the rings as we go */
9799b8d05b8SZbigniew Bodek 	while (i--)
9809b8d05b8SZbigniew Bodek 		ena_free_rx_resources(adapter, i);
9819b8d05b8SZbigniew Bodek 	return (rc);
9829b8d05b8SZbigniew Bodek }
9839b8d05b8SZbigniew Bodek 
9849b8d05b8SZbigniew Bodek /**
9859b8d05b8SZbigniew Bodek  * ena_free_all_rx_resources - Free Rx resources for all queues
9869b8d05b8SZbigniew Bodek  * @adapter: network interface device structure
9879b8d05b8SZbigniew Bodek  *
9889b8d05b8SZbigniew Bodek  * Free all receive software resources
9899b8d05b8SZbigniew Bodek  **/
9909b8d05b8SZbigniew Bodek static void
9919b8d05b8SZbigniew Bodek ena_free_all_rx_resources(struct ena_adapter *adapter)
9929b8d05b8SZbigniew Bodek {
9939b8d05b8SZbigniew Bodek 	int i;
9949b8d05b8SZbigniew Bodek 
9957d8c4feeSMarcin Wojtas 	for (i = 0; i < adapter->num_io_queues; i++)
9969b8d05b8SZbigniew Bodek 		ena_free_rx_resources(adapter, i);
9979b8d05b8SZbigniew Bodek }
9989b8d05b8SZbigniew Bodek 
9999b8d05b8SZbigniew Bodek static inline int
10009b8d05b8SZbigniew Bodek ena_alloc_rx_mbuf(struct ena_adapter *adapter,
10019b8d05b8SZbigniew Bodek     struct ena_ring *rx_ring, struct ena_rx_buffer *rx_info)
10029b8d05b8SZbigniew Bodek {
10039b8d05b8SZbigniew Bodek 	struct ena_com_buf *ena_buf;
10049b8d05b8SZbigniew Bodek 	bus_dma_segment_t segs[1];
10059b8d05b8SZbigniew Bodek 	int nsegs, error;
10064727bda6SMarcin Wojtas 	int mlen;
10079b8d05b8SZbigniew Bodek 
10089b8d05b8SZbigniew Bodek 	/* if previous allocated frag is not used */
10093f9ed7abSMarcin Wojtas 	if (unlikely(rx_info->mbuf != NULL))
10109b8d05b8SZbigniew Bodek 		return (0);
10119b8d05b8SZbigniew Bodek 
10129b8d05b8SZbigniew Bodek 	/* Get mbuf using UMA allocator */
101304cf2b88SMarcin Wojtas 	rx_info->mbuf = m_getjcl(M_NOWAIT, MT_DATA, M_PKTHDR,
101404cf2b88SMarcin Wojtas 	    rx_ring->rx_mbuf_sz);
10159b8d05b8SZbigniew Bodek 
10163f9ed7abSMarcin Wojtas 	if (unlikely(rx_info->mbuf == NULL)) {
10174727bda6SMarcin Wojtas 		counter_u64_add(rx_ring->rx_stats.mjum_alloc_fail, 1);
10184727bda6SMarcin Wojtas 		rx_info->mbuf = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR);
10194727bda6SMarcin Wojtas 		if (unlikely(rx_info->mbuf == NULL)) {
10209b8d05b8SZbigniew Bodek 			counter_u64_add(rx_ring->rx_stats.mbuf_alloc_fail, 1);
10219b8d05b8SZbigniew Bodek 			return (ENOMEM);
10229b8d05b8SZbigniew Bodek 		}
10234727bda6SMarcin Wojtas 		mlen = MCLBYTES;
10244727bda6SMarcin Wojtas 	} else {
102504cf2b88SMarcin Wojtas 		mlen = rx_ring->rx_mbuf_sz;
10264727bda6SMarcin Wojtas 	}
10279b8d05b8SZbigniew Bodek 	/* Set mbuf length*/
10284727bda6SMarcin Wojtas 	rx_info->mbuf->m_pkthdr.len = rx_info->mbuf->m_len = mlen;
10299b8d05b8SZbigniew Bodek 
10309b8d05b8SZbigniew Bodek 	/* Map packets for DMA */
10319eb1615fSMarcin Wojtas 	ena_trace(NULL, ENA_DBG | ENA_RSC | ENA_RXPTH,
103230425f93SMarcin Wojtas 	    "Using tag %p for buffers' DMA mapping, mbuf %p len: %d\n",
10339b8d05b8SZbigniew Bodek 	    adapter->rx_buf_tag,rx_info->mbuf, rx_info->mbuf->m_len);
10349b8d05b8SZbigniew Bodek 	error = bus_dmamap_load_mbuf_sg(adapter->rx_buf_tag, rx_info->map,
10359b8d05b8SZbigniew Bodek 	    rx_info->mbuf, segs, &nsegs, BUS_DMA_NOWAIT);
10363f9ed7abSMarcin Wojtas 	if (unlikely((error != 0) || (nsegs != 1))) {
10379eb1615fSMarcin Wojtas 		ena_trace(NULL, ENA_WARNING, "failed to map mbuf, error: %d, "
10389b8d05b8SZbigniew Bodek 		    "nsegs: %d\n", error, nsegs);
10399b8d05b8SZbigniew Bodek 		counter_u64_add(rx_ring->rx_stats.dma_mapping_err, 1);
10409b8d05b8SZbigniew Bodek 		goto exit;
10419b8d05b8SZbigniew Bodek 
10429b8d05b8SZbigniew Bodek 	}
10439b8d05b8SZbigniew Bodek 
10449b8d05b8SZbigniew Bodek 	bus_dmamap_sync(adapter->rx_buf_tag, rx_info->map, BUS_DMASYNC_PREREAD);
10459b8d05b8SZbigniew Bodek 
10469b8d05b8SZbigniew Bodek 	ena_buf = &rx_info->ena_buf;
10479b8d05b8SZbigniew Bodek 	ena_buf->paddr = segs[0].ds_addr;
10484727bda6SMarcin Wojtas 	ena_buf->len = mlen;
10499b8d05b8SZbigniew Bodek 
10509eb1615fSMarcin Wojtas 	ena_trace(NULL, ENA_DBG | ENA_RSC | ENA_RXPTH,
10519b8d05b8SZbigniew Bodek 	    "ALLOC RX BUF: mbuf %p, rx_info %p, len %d, paddr %#jx\n",
10529b8d05b8SZbigniew Bodek 	    rx_info->mbuf, rx_info,ena_buf->len, (uintmax_t)ena_buf->paddr);
10539b8d05b8SZbigniew Bodek 
10549b8d05b8SZbigniew Bodek 	return (0);
10559b8d05b8SZbigniew Bodek 
10569b8d05b8SZbigniew Bodek exit:
10579b8d05b8SZbigniew Bodek 	m_freem(rx_info->mbuf);
10589b8d05b8SZbigniew Bodek 	rx_info->mbuf = NULL;
10599b8d05b8SZbigniew Bodek 	return (EFAULT);
10609b8d05b8SZbigniew Bodek }
10619b8d05b8SZbigniew Bodek 
10629b8d05b8SZbigniew Bodek static void
10639b8d05b8SZbigniew Bodek ena_free_rx_mbuf(struct ena_adapter *adapter, struct ena_ring *rx_ring,
10649b8d05b8SZbigniew Bodek     struct ena_rx_buffer *rx_info)
10659b8d05b8SZbigniew Bodek {
10669b8d05b8SZbigniew Bodek 
10674e8acd84SMarcin Wojtas 	if (rx_info->mbuf == NULL) {
10689eb1615fSMarcin Wojtas 		ena_trace(NULL, ENA_WARNING, "Trying to free unallocated buffer\n");
10699b8d05b8SZbigniew Bodek 		return;
10704e8acd84SMarcin Wojtas 	}
10719b8d05b8SZbigniew Bodek 
1072e8073738SMarcin Wojtas 	bus_dmamap_sync(adapter->rx_buf_tag, rx_info->map,
1073e8073738SMarcin Wojtas 	    BUS_DMASYNC_POSTREAD);
10749b8d05b8SZbigniew Bodek 	bus_dmamap_unload(adapter->rx_buf_tag, rx_info->map);
10759b8d05b8SZbigniew Bodek 	m_freem(rx_info->mbuf);
10769b8d05b8SZbigniew Bodek 	rx_info->mbuf = NULL;
10779b8d05b8SZbigniew Bodek }
10789b8d05b8SZbigniew Bodek 
10799b8d05b8SZbigniew Bodek /**
10809b8d05b8SZbigniew Bodek  * ena_refill_rx_bufs - Refills ring with descriptors
10819b8d05b8SZbigniew Bodek  * @rx_ring: the ring which we want to feed with free descriptors
10829b8d05b8SZbigniew Bodek  * @num: number of descriptors to refill
10839b8d05b8SZbigniew Bodek  * Refills the ring with newly allocated DMA-mapped mbufs for receiving
10849b8d05b8SZbigniew Bodek  **/
108538c7b965SMarcin Wojtas int
10869b8d05b8SZbigniew Bodek ena_refill_rx_bufs(struct ena_ring *rx_ring, uint32_t num)
10879b8d05b8SZbigniew Bodek {
10889b8d05b8SZbigniew Bodek 	struct ena_adapter *adapter = rx_ring->adapter;
108943fefd16SMarcin Wojtas 	uint16_t next_to_use, req_id;
10909b8d05b8SZbigniew Bodek 	uint32_t i;
10919b8d05b8SZbigniew Bodek 	int rc;
10929b8d05b8SZbigniew Bodek 
10939eb1615fSMarcin Wojtas 	ena_trace(NULL, ENA_DBG | ENA_RXPTH | ENA_RSC, "refill qid: %d\n",
10949b8d05b8SZbigniew Bodek 	    rx_ring->qid);
10959b8d05b8SZbigniew Bodek 
10969b8d05b8SZbigniew Bodek 	next_to_use = rx_ring->next_to_use;
10979b8d05b8SZbigniew Bodek 
10989b8d05b8SZbigniew Bodek 	for (i = 0; i < num; i++) {
109943fefd16SMarcin Wojtas 		struct ena_rx_buffer *rx_info;
110043fefd16SMarcin Wojtas 
11019eb1615fSMarcin Wojtas 		ena_trace(NULL, ENA_DBG | ENA_RXPTH | ENA_RSC,
110230425f93SMarcin Wojtas 		    "RX buffer - next to use: %d\n", next_to_use);
11039b8d05b8SZbigniew Bodek 
110443fefd16SMarcin Wojtas 		req_id = rx_ring->free_rx_ids[next_to_use];
110543fefd16SMarcin Wojtas 		rx_info = &rx_ring->rx_buffer_info[req_id];
11069a0f2079SMarcin Wojtas #ifdef DEV_NETMAP
1107358bcc4cSMarcin Wojtas 		if (ena_rx_ring_in_netmap(adapter, rx_ring->qid))
11089a0f2079SMarcin Wojtas 			rc = ena_netmap_alloc_rx_slot(adapter, rx_ring, rx_info);
11099a0f2079SMarcin Wojtas 		else
11109a0f2079SMarcin Wojtas #endif /* DEV_NETMAP */
11119b8d05b8SZbigniew Bodek 			rc = ena_alloc_rx_mbuf(adapter, rx_ring, rx_info);
11123f9ed7abSMarcin Wojtas 		if (unlikely(rc != 0)) {
11139eb1615fSMarcin Wojtas 			ena_trace(NULL, ENA_WARNING,
11144e8acd84SMarcin Wojtas 			    "failed to alloc buffer for rx queue %d\n",
11154e8acd84SMarcin Wojtas 			    rx_ring->qid);
11169b8d05b8SZbigniew Bodek 			break;
11179b8d05b8SZbigniew Bodek 		}
11189b8d05b8SZbigniew Bodek 		rc = ena_com_add_single_rx_desc(rx_ring->ena_com_io_sq,
111943fefd16SMarcin Wojtas 		    &rx_info->ena_buf, req_id);
11200bdffe59SMarcin Wojtas 		if (unlikely(rc != 0)) {
11219eb1615fSMarcin Wojtas 			ena_trace(NULL, ENA_WARNING,
11229b8d05b8SZbigniew Bodek 			    "failed to add buffer for rx queue %d\n",
11239b8d05b8SZbigniew Bodek 			    rx_ring->qid);
11249b8d05b8SZbigniew Bodek 			break;
11259b8d05b8SZbigniew Bodek 		}
11269b8d05b8SZbigniew Bodek 		next_to_use = ENA_RX_RING_IDX_NEXT(next_to_use,
11279b8d05b8SZbigniew Bodek 		    rx_ring->ring_size);
11289b8d05b8SZbigniew Bodek 	}
11299b8d05b8SZbigniew Bodek 
11303f9ed7abSMarcin Wojtas 	if (unlikely(i < num)) {
11319b8d05b8SZbigniew Bodek 		counter_u64_add(rx_ring->rx_stats.refil_partial, 1);
11329eb1615fSMarcin Wojtas 		ena_trace(NULL, ENA_WARNING,
11334e8acd84SMarcin Wojtas 		     "refilled rx qid %d with only %d mbufs (from %d)\n",
11344e8acd84SMarcin Wojtas 		     rx_ring->qid, i, num);
11359b8d05b8SZbigniew Bodek 	}
11369b8d05b8SZbigniew Bodek 
11378483b844SMarcin Wojtas 	if (likely(i != 0))
11389b8d05b8SZbigniew Bodek 		ena_com_write_sq_doorbell(rx_ring->ena_com_io_sq);
11398483b844SMarcin Wojtas 
11409b8d05b8SZbigniew Bodek 	rx_ring->next_to_use = next_to_use;
11419b8d05b8SZbigniew Bodek 	return (i);
11429b8d05b8SZbigniew Bodek }
11439b8d05b8SZbigniew Bodek 
11447d8c4feeSMarcin Wojtas int
114521823546SMarcin Wojtas ena_update_buf_ring_size(struct ena_adapter *adapter,
114621823546SMarcin Wojtas     uint32_t new_buf_ring_size)
114721823546SMarcin Wojtas {
114821823546SMarcin Wojtas 	uint32_t old_buf_ring_size;
114921823546SMarcin Wojtas 	int rc = 0;
115021823546SMarcin Wojtas 	bool dev_was_up;
115121823546SMarcin Wojtas 
115221823546SMarcin Wojtas 	ENA_LOCK_LOCK(adapter);
115321823546SMarcin Wojtas 
115421823546SMarcin Wojtas 	old_buf_ring_size = adapter->buf_ring_size;
115521823546SMarcin Wojtas 	adapter->buf_ring_size = new_buf_ring_size;
115621823546SMarcin Wojtas 
115721823546SMarcin Wojtas 	dev_was_up = ENA_FLAG_ISSET(ENA_FLAG_DEV_UP, adapter);
115821823546SMarcin Wojtas 	ena_down(adapter);
115921823546SMarcin Wojtas 
116021823546SMarcin Wojtas 	/* Reconfigure buf ring for all Tx rings. */
116121823546SMarcin Wojtas 	ena_free_all_io_rings_resources(adapter);
116221823546SMarcin Wojtas 	ena_init_io_rings_advanced(adapter);
116321823546SMarcin Wojtas 	if (dev_was_up) {
116421823546SMarcin Wojtas 		/*
116521823546SMarcin Wojtas 		 * If ena_up() fails, it's not because of recent buf_ring size
116621823546SMarcin Wojtas 		 * changes. Because of that, we just want to revert old drbr
116721823546SMarcin Wojtas 		 * value and trigger the reset because something else had to
116821823546SMarcin Wojtas 		 * go wrong.
116921823546SMarcin Wojtas 		 */
117021823546SMarcin Wojtas 		rc = ena_up(adapter);
117121823546SMarcin Wojtas 		if (unlikely(rc != 0)) {
117221823546SMarcin Wojtas 			device_printf(adapter->pdev,
117321823546SMarcin Wojtas 			    "Failed to configure device after setting new drbr size: %u. Reverting old value: %u and triggering the reset\n",
117421823546SMarcin Wojtas 			    new_buf_ring_size, old_buf_ring_size);
117521823546SMarcin Wojtas 
117621823546SMarcin Wojtas 			/* Revert old size and trigger the reset */
117721823546SMarcin Wojtas 			adapter->buf_ring_size = old_buf_ring_size;
117821823546SMarcin Wojtas 			ena_free_all_io_rings_resources(adapter);
117921823546SMarcin Wojtas 			ena_init_io_rings_advanced(adapter);
118021823546SMarcin Wojtas 
118121823546SMarcin Wojtas 			ENA_FLAG_SET_ATOMIC(ENA_FLAG_DEV_UP_BEFORE_RESET,
118221823546SMarcin Wojtas 			    adapter);
118321823546SMarcin Wojtas 			ena_trigger_reset(adapter, ENA_REGS_RESET_OS_TRIGGER);
118421823546SMarcin Wojtas 
118521823546SMarcin Wojtas 		}
118621823546SMarcin Wojtas 	}
118721823546SMarcin Wojtas 
118821823546SMarcin Wojtas 	ENA_LOCK_UNLOCK(adapter);
118921823546SMarcin Wojtas 
119021823546SMarcin Wojtas 	return (rc);
119121823546SMarcin Wojtas }
119221823546SMarcin Wojtas 
119321823546SMarcin Wojtas int
11947d8c4feeSMarcin Wojtas ena_update_queue_size(struct ena_adapter *adapter, uint32_t new_tx_size,
11957d8c4feeSMarcin Wojtas     uint32_t new_rx_size)
11967d8c4feeSMarcin Wojtas {
11977d8c4feeSMarcin Wojtas 	uint32_t old_tx_size, old_rx_size;
11987d8c4feeSMarcin Wojtas 	int rc = 0;
11997d8c4feeSMarcin Wojtas 	bool dev_was_up;
12007d8c4feeSMarcin Wojtas 
12017d8c4feeSMarcin Wojtas 	ENA_LOCK_LOCK(adapter);
12027d8c4feeSMarcin Wojtas 
12039762a033SMarcin Wojtas 	old_tx_size = adapter->requested_tx_ring_size;
12049762a033SMarcin Wojtas 	old_rx_size = adapter->requested_rx_ring_size;
12059762a033SMarcin Wojtas 	adapter->requested_tx_ring_size = new_tx_size;
12069762a033SMarcin Wojtas 	adapter->requested_rx_ring_size = new_rx_size;
12077d8c4feeSMarcin Wojtas 
12087d8c4feeSMarcin Wojtas 	dev_was_up = ENA_FLAG_ISSET(ENA_FLAG_DEV_UP, adapter);
12097d8c4feeSMarcin Wojtas 	ena_down(adapter);
12107d8c4feeSMarcin Wojtas 
12117d8c4feeSMarcin Wojtas 	/* Configure queues with new size. */
12127d8c4feeSMarcin Wojtas 	ena_init_io_rings_basic(adapter);
12137d8c4feeSMarcin Wojtas 	if (dev_was_up) {
12147d8c4feeSMarcin Wojtas 		rc = ena_up(adapter);
12157d8c4feeSMarcin Wojtas 		if (unlikely(rc != 0)) {
12167d8c4feeSMarcin Wojtas 			device_printf(adapter->pdev,
12177d8c4feeSMarcin Wojtas 			    "Failed to configure device with the new sizes - Tx: %u Rx: %u. Reverting old values - Tx: %u Rx: %u\n",
12187d8c4feeSMarcin Wojtas 			    new_tx_size, new_rx_size, old_tx_size, old_rx_size);
12197d8c4feeSMarcin Wojtas 
12207d8c4feeSMarcin Wojtas 			/* Revert old size. */
12219762a033SMarcin Wojtas 			adapter->requested_tx_ring_size = old_tx_size;
12229762a033SMarcin Wojtas 			adapter->requested_rx_ring_size = old_rx_size;
12237d8c4feeSMarcin Wojtas 			ena_init_io_rings_basic(adapter);
12247d8c4feeSMarcin Wojtas 
12257d8c4feeSMarcin Wojtas 			/* And try again. */
12267d8c4feeSMarcin Wojtas 			rc = ena_up(adapter);
12277d8c4feeSMarcin Wojtas 			if (unlikely(rc != 0)) {
12287d8c4feeSMarcin Wojtas 				device_printf(adapter->pdev,
12297d8c4feeSMarcin Wojtas 				    "Failed to revert old queue sizes. Triggering device reset.\n");
12307d8c4feeSMarcin Wojtas 				/*
12317d8c4feeSMarcin Wojtas 				 * If we've failed again, something had to go
12327d8c4feeSMarcin Wojtas 				 * wrong. After reset, the device should try to
12337d8c4feeSMarcin Wojtas 				 * go up
12347d8c4feeSMarcin Wojtas 				 */
12357d8c4feeSMarcin Wojtas 				ENA_FLAG_SET_ATOMIC(
12367d8c4feeSMarcin Wojtas 				    ENA_FLAG_DEV_UP_BEFORE_RESET, adapter);
12377d8c4feeSMarcin Wojtas 				ena_trigger_reset(adapter,
12387d8c4feeSMarcin Wojtas 				    ENA_REGS_RESET_OS_TRIGGER);
12397d8c4feeSMarcin Wojtas 			}
12407d8c4feeSMarcin Wojtas 		}
12417d8c4feeSMarcin Wojtas 	}
12427d8c4feeSMarcin Wojtas 
12437d8c4feeSMarcin Wojtas 	ENA_LOCK_UNLOCK(adapter);
12447d8c4feeSMarcin Wojtas 
12457d8c4feeSMarcin Wojtas 	return (rc);
12467d8c4feeSMarcin Wojtas }
12477d8c4feeSMarcin Wojtas 
12489b8d05b8SZbigniew Bodek static void
124956d41ad5SMarcin Wojtas ena_update_io_rings(struct ena_adapter *adapter, uint32_t num)
125056d41ad5SMarcin Wojtas {
125156d41ad5SMarcin Wojtas 	ena_free_all_io_rings_resources(adapter);
125256d41ad5SMarcin Wojtas 	/* Force indirection table to be reinitialized */
125356d41ad5SMarcin Wojtas 	ena_com_rss_destroy(adapter->ena_dev);
125456d41ad5SMarcin Wojtas 
125556d41ad5SMarcin Wojtas 	adapter->num_io_queues = num;
125656d41ad5SMarcin Wojtas 	ena_init_io_rings(adapter);
125756d41ad5SMarcin Wojtas }
125856d41ad5SMarcin Wojtas 
125956d41ad5SMarcin Wojtas /* Caller should sanitize new_num */
126056d41ad5SMarcin Wojtas int
126156d41ad5SMarcin Wojtas ena_update_io_queue_nb(struct ena_adapter *adapter, uint32_t new_num)
126256d41ad5SMarcin Wojtas {
126356d41ad5SMarcin Wojtas 	uint32_t old_num;
126456d41ad5SMarcin Wojtas 	int rc = 0;
126556d41ad5SMarcin Wojtas 	bool dev_was_up;
126656d41ad5SMarcin Wojtas 
126756d41ad5SMarcin Wojtas 	ENA_LOCK_LOCK(adapter);
126856d41ad5SMarcin Wojtas 
126956d41ad5SMarcin Wojtas 	dev_was_up = ENA_FLAG_ISSET(ENA_FLAG_DEV_UP, adapter);
127056d41ad5SMarcin Wojtas 	old_num = adapter->num_io_queues;
127156d41ad5SMarcin Wojtas 	ena_down(adapter);
127256d41ad5SMarcin Wojtas 
127356d41ad5SMarcin Wojtas 	ena_update_io_rings(adapter, new_num);
127456d41ad5SMarcin Wojtas 
127556d41ad5SMarcin Wojtas 	if (dev_was_up) {
127656d41ad5SMarcin Wojtas 		rc = ena_up(adapter);
127756d41ad5SMarcin Wojtas 		if (unlikely(rc != 0)) {
127856d41ad5SMarcin Wojtas 			device_printf(adapter->pdev,
127956d41ad5SMarcin Wojtas 			    "Failed to configure device with %u IO queues. "
128056d41ad5SMarcin Wojtas 			    "Reverting to previous value: %u\n",
128156d41ad5SMarcin Wojtas 			    new_num, old_num);
128256d41ad5SMarcin Wojtas 
128356d41ad5SMarcin Wojtas 			ena_update_io_rings(adapter, old_num);
128456d41ad5SMarcin Wojtas 
128556d41ad5SMarcin Wojtas 			rc = ena_up(adapter);
128656d41ad5SMarcin Wojtas 			if (unlikely(rc != 0)) {
128756d41ad5SMarcin Wojtas 				device_printf(adapter->pdev,
128856d41ad5SMarcin Wojtas 				    "Failed to revert to previous setup IO "
128956d41ad5SMarcin Wojtas 				    "queues. Triggering device reset.\n");
129056d41ad5SMarcin Wojtas 				ENA_FLAG_SET_ATOMIC(
129156d41ad5SMarcin Wojtas 				    ENA_FLAG_DEV_UP_BEFORE_RESET, adapter);
129256d41ad5SMarcin Wojtas 				ena_trigger_reset(adapter,
129356d41ad5SMarcin Wojtas 				    ENA_REGS_RESET_OS_TRIGGER);
129456d41ad5SMarcin Wojtas 			}
129556d41ad5SMarcin Wojtas 		}
129656d41ad5SMarcin Wojtas 	}
129756d41ad5SMarcin Wojtas 
129856d41ad5SMarcin Wojtas 	ENA_LOCK_UNLOCK(adapter);
129956d41ad5SMarcin Wojtas 
130056d41ad5SMarcin Wojtas 	return (rc);
130156d41ad5SMarcin Wojtas }
130256d41ad5SMarcin Wojtas 
130356d41ad5SMarcin Wojtas static void
13049b8d05b8SZbigniew Bodek ena_free_rx_bufs(struct ena_adapter *adapter, unsigned int qid)
13059b8d05b8SZbigniew Bodek {
13069b8d05b8SZbigniew Bodek 	struct ena_ring *rx_ring = &adapter->rx_ring[qid];
13079b8d05b8SZbigniew Bodek 	unsigned int i;
13089b8d05b8SZbigniew Bodek 
13099b8d05b8SZbigniew Bodek 	for (i = 0; i < rx_ring->ring_size; i++) {
13109b8d05b8SZbigniew Bodek 		struct ena_rx_buffer *rx_info = &rx_ring->rx_buffer_info[i];
13119b8d05b8SZbigniew Bodek 
13120bdffe59SMarcin Wojtas 		if (rx_info->mbuf != NULL)
13139b8d05b8SZbigniew Bodek 			ena_free_rx_mbuf(adapter, rx_ring, rx_info);
13149a0f2079SMarcin Wojtas #ifdef DEV_NETMAP
13159a0f2079SMarcin Wojtas 		if (((if_getflags(adapter->ifp) & IFF_DYING) == 0) &&
13169a0f2079SMarcin Wojtas 		    (adapter->ifp->if_capenable & IFCAP_NETMAP)) {
13179a0f2079SMarcin Wojtas 			if (rx_info->netmap_buf_idx != 0)
13189a0f2079SMarcin Wojtas 				ena_netmap_free_rx_slot(adapter, rx_ring,
13199a0f2079SMarcin Wojtas 				    rx_info);
13209a0f2079SMarcin Wojtas 		}
13219a0f2079SMarcin Wojtas #endif /* DEV_NETMAP */
13229b8d05b8SZbigniew Bodek 	}
13239b8d05b8SZbigniew Bodek }
13249b8d05b8SZbigniew Bodek 
13259b8d05b8SZbigniew Bodek /**
13269b8d05b8SZbigniew Bodek  * ena_refill_all_rx_bufs - allocate all queues Rx buffers
13279b8d05b8SZbigniew Bodek  * @adapter: network interface device structure
13289b8d05b8SZbigniew Bodek  *
13299b8d05b8SZbigniew Bodek  */
13309b8d05b8SZbigniew Bodek static void
13319b8d05b8SZbigniew Bodek ena_refill_all_rx_bufs(struct ena_adapter *adapter)
13329b8d05b8SZbigniew Bodek {
13339b8d05b8SZbigniew Bodek 	struct ena_ring *rx_ring;
13349b8d05b8SZbigniew Bodek 	int i, rc, bufs_num;
13359b8d05b8SZbigniew Bodek 
13367d8c4feeSMarcin Wojtas 	for (i = 0; i < adapter->num_io_queues; i++) {
13379b8d05b8SZbigniew Bodek 		rx_ring = &adapter->rx_ring[i];
13389b8d05b8SZbigniew Bodek 		bufs_num = rx_ring->ring_size - 1;
13399b8d05b8SZbigniew Bodek 		rc = ena_refill_rx_bufs(rx_ring, bufs_num);
13409b8d05b8SZbigniew Bodek 		if (unlikely(rc != bufs_num))
13419eb1615fSMarcin Wojtas 			ena_trace(NULL, ENA_WARNING, "refilling Queue %d failed. "
13424e8acd84SMarcin Wojtas 			    "Allocated %d buffers from: %d\n", i, rc, bufs_num);
13439a0f2079SMarcin Wojtas #ifdef DEV_NETMAP
13449a0f2079SMarcin Wojtas 		rx_ring->initialized = true;
13459a0f2079SMarcin Wojtas #endif /* DEV_NETMAP */
13469b8d05b8SZbigniew Bodek 	}
13479b8d05b8SZbigniew Bodek }
13489b8d05b8SZbigniew Bodek 
13499b8d05b8SZbigniew Bodek static void
13509b8d05b8SZbigniew Bodek ena_free_all_rx_bufs(struct ena_adapter *adapter)
13519b8d05b8SZbigniew Bodek {
13529b8d05b8SZbigniew Bodek 	int i;
13539b8d05b8SZbigniew Bodek 
13547d8c4feeSMarcin Wojtas 	for (i = 0; i < adapter->num_io_queues; i++)
13559b8d05b8SZbigniew Bodek 		ena_free_rx_bufs(adapter, i);
13569b8d05b8SZbigniew Bodek }
13579b8d05b8SZbigniew Bodek 
13589b8d05b8SZbigniew Bodek /**
13599b8d05b8SZbigniew Bodek  * ena_free_tx_bufs - Free Tx Buffers per Queue
13609b8d05b8SZbigniew Bodek  * @adapter: network interface device structure
13619b8d05b8SZbigniew Bodek  * @qid: queue index
13629b8d05b8SZbigniew Bodek  **/
13639b8d05b8SZbigniew Bodek static void
13649b8d05b8SZbigniew Bodek ena_free_tx_bufs(struct ena_adapter *adapter, unsigned int qid)
13659b8d05b8SZbigniew Bodek {
13664e8acd84SMarcin Wojtas 	bool print_once = true;
13679b8d05b8SZbigniew Bodek 	struct ena_ring *tx_ring = &adapter->tx_ring[qid];
13689b8d05b8SZbigniew Bodek 
1369416e8864SZbigniew Bodek 	ENA_RING_MTX_LOCK(tx_ring);
13709b8d05b8SZbigniew Bodek 	for (int i = 0; i < tx_ring->ring_size; i++) {
13719b8d05b8SZbigniew Bodek 		struct ena_tx_buffer *tx_info = &tx_ring->tx_buffer_info[i];
13729b8d05b8SZbigniew Bodek 
13739b8d05b8SZbigniew Bodek 		if (tx_info->mbuf == NULL)
13749b8d05b8SZbigniew Bodek 			continue;
13759b8d05b8SZbigniew Bodek 
13764e8acd84SMarcin Wojtas 		if (print_once) {
13774e8acd84SMarcin Wojtas 			device_printf(adapter->pdev,
137830425f93SMarcin Wojtas 			    "free uncompleted tx mbuf qid %d idx 0x%x\n",
13794e8acd84SMarcin Wojtas 			    qid, i);
13804e8acd84SMarcin Wojtas 			print_once = false;
13814e8acd84SMarcin Wojtas 		} else {
13829eb1615fSMarcin Wojtas 			ena_trace(NULL, ENA_DBG,
138330425f93SMarcin Wojtas 			    "free uncompleted tx mbuf qid %d idx 0x%x\n",
13844e8acd84SMarcin Wojtas 			     qid, i);
13854e8acd84SMarcin Wojtas 		}
13869b8d05b8SZbigniew Bodek 
1387888810f0SMarcin Wojtas 		bus_dmamap_sync(adapter->tx_buf_tag, tx_info->dmamap,
1388e8073738SMarcin Wojtas 		    BUS_DMASYNC_POSTWRITE);
1389888810f0SMarcin Wojtas 		bus_dmamap_unload(adapter->tx_buf_tag, tx_info->dmamap);
13904fa9e02dSMarcin Wojtas 
13919b8d05b8SZbigniew Bodek 		m_free(tx_info->mbuf);
13929b8d05b8SZbigniew Bodek 		tx_info->mbuf = NULL;
13939b8d05b8SZbigniew Bodek 	}
1394416e8864SZbigniew Bodek 	ENA_RING_MTX_UNLOCK(tx_ring);
13959b8d05b8SZbigniew Bodek }
13969b8d05b8SZbigniew Bodek 
13979b8d05b8SZbigniew Bodek static void
13989b8d05b8SZbigniew Bodek ena_free_all_tx_bufs(struct ena_adapter *adapter)
13999b8d05b8SZbigniew Bodek {
14009b8d05b8SZbigniew Bodek 
14017d8c4feeSMarcin Wojtas 	for (int i = 0; i < adapter->num_io_queues; i++)
14029b8d05b8SZbigniew Bodek 		ena_free_tx_bufs(adapter, i);
14039b8d05b8SZbigniew Bodek }
14049b8d05b8SZbigniew Bodek 
14059b8d05b8SZbigniew Bodek static void
14069b8d05b8SZbigniew Bodek ena_destroy_all_tx_queues(struct ena_adapter *adapter)
14079b8d05b8SZbigniew Bodek {
14089b8d05b8SZbigniew Bodek 	uint16_t ena_qid;
14099b8d05b8SZbigniew Bodek 	int i;
14109b8d05b8SZbigniew Bodek 
14117d8c4feeSMarcin Wojtas 	for (i = 0; i < adapter->num_io_queues; i++) {
14129b8d05b8SZbigniew Bodek 		ena_qid = ENA_IO_TXQ_IDX(i);
14139b8d05b8SZbigniew Bodek 		ena_com_destroy_io_queue(adapter->ena_dev, ena_qid);
14149b8d05b8SZbigniew Bodek 	}
14159b8d05b8SZbigniew Bodek }
14169b8d05b8SZbigniew Bodek 
14179b8d05b8SZbigniew Bodek static void
14189b8d05b8SZbigniew Bodek ena_destroy_all_rx_queues(struct ena_adapter *adapter)
14199b8d05b8SZbigniew Bodek {
14209b8d05b8SZbigniew Bodek 	uint16_t ena_qid;
14219b8d05b8SZbigniew Bodek 	int i;
14229b8d05b8SZbigniew Bodek 
14237d8c4feeSMarcin Wojtas 	for (i = 0; i < adapter->num_io_queues; i++) {
14249b8d05b8SZbigniew Bodek 		ena_qid = ENA_IO_RXQ_IDX(i);
14259b8d05b8SZbigniew Bodek 		ena_com_destroy_io_queue(adapter->ena_dev, ena_qid);
14269b8d05b8SZbigniew Bodek 	}
14279b8d05b8SZbigniew Bodek }
14289b8d05b8SZbigniew Bodek 
14299b8d05b8SZbigniew Bodek static void
14309b8d05b8SZbigniew Bodek ena_destroy_all_io_queues(struct ena_adapter *adapter)
14319b8d05b8SZbigniew Bodek {
14325cb9db07SMarcin Wojtas 	struct ena_que *queue;
14335cb9db07SMarcin Wojtas 	int i;
14345cb9db07SMarcin Wojtas 
14357d8c4feeSMarcin Wojtas 	for (i = 0; i < adapter->num_io_queues; i++) {
14365cb9db07SMarcin Wojtas 		queue = &adapter->que[i];
14375cb9db07SMarcin Wojtas 		while (taskqueue_cancel(queue->cleanup_tq,
14385cb9db07SMarcin Wojtas 		    &queue->cleanup_task, NULL))
14395cb9db07SMarcin Wojtas 			taskqueue_drain(queue->cleanup_tq,
14405cb9db07SMarcin Wojtas 			    &queue->cleanup_task);
14415cb9db07SMarcin Wojtas 		taskqueue_free(queue->cleanup_tq);
14425cb9db07SMarcin Wojtas 	}
14435cb9db07SMarcin Wojtas 
14449b8d05b8SZbigniew Bodek 	ena_destroy_all_tx_queues(adapter);
14459b8d05b8SZbigniew Bodek 	ena_destroy_all_rx_queues(adapter);
14469b8d05b8SZbigniew Bodek }
14479b8d05b8SZbigniew Bodek 
14489b8d05b8SZbigniew Bodek static int
14499b8d05b8SZbigniew Bodek ena_create_io_queues(struct ena_adapter *adapter)
14509b8d05b8SZbigniew Bodek {
14519b8d05b8SZbigniew Bodek 	struct ena_com_dev *ena_dev = adapter->ena_dev;
14529b8d05b8SZbigniew Bodek 	struct ena_com_create_io_ctx ctx;
14539b8d05b8SZbigniew Bodek 	struct ena_ring *ring;
14545cb9db07SMarcin Wojtas 	struct ena_que *queue;
14559b8d05b8SZbigniew Bodek 	uint16_t ena_qid;
14569b8d05b8SZbigniew Bodek 	uint32_t msix_vector;
14579b8d05b8SZbigniew Bodek 	int rc, i;
14589b8d05b8SZbigniew Bodek 
14599b8d05b8SZbigniew Bodek 	/* Create TX queues */
14607d8c4feeSMarcin Wojtas 	for (i = 0; i < adapter->num_io_queues; i++) {
14619b8d05b8SZbigniew Bodek 		msix_vector = ENA_IO_IRQ_IDX(i);
14629b8d05b8SZbigniew Bodek 		ena_qid = ENA_IO_TXQ_IDX(i);
14639b8d05b8SZbigniew Bodek 		ctx.mem_queue_type = ena_dev->tx_mem_queue_type;
14649b8d05b8SZbigniew Bodek 		ctx.direction = ENA_COM_IO_QUEUE_DIRECTION_TX;
14659762a033SMarcin Wojtas 		ctx.queue_size = adapter->requested_tx_ring_size;
14669b8d05b8SZbigniew Bodek 		ctx.msix_vector = msix_vector;
14679b8d05b8SZbigniew Bodek 		ctx.qid = ena_qid;
14689b8d05b8SZbigniew Bodek 		rc = ena_com_create_io_queue(ena_dev, &ctx);
14690bdffe59SMarcin Wojtas 		if (rc != 0) {
14709b8d05b8SZbigniew Bodek 			device_printf(adapter->pdev,
14719b8d05b8SZbigniew Bodek 			    "Failed to create io TX queue #%d rc: %d\n", i, rc);
14729b8d05b8SZbigniew Bodek 			goto err_tx;
14739b8d05b8SZbigniew Bodek 		}
14749b8d05b8SZbigniew Bodek 		ring = &adapter->tx_ring[i];
14759b8d05b8SZbigniew Bodek 		rc = ena_com_get_io_handlers(ena_dev, ena_qid,
14769b8d05b8SZbigniew Bodek 		    &ring->ena_com_io_sq,
14779b8d05b8SZbigniew Bodek 		    &ring->ena_com_io_cq);
14780bdffe59SMarcin Wojtas 		if (rc != 0) {
14799b8d05b8SZbigniew Bodek 			device_printf(adapter->pdev,
14809b8d05b8SZbigniew Bodek 			    "Failed to get TX queue handlers. TX queue num"
14819b8d05b8SZbigniew Bodek 			    " %d rc: %d\n", i, rc);
14829b8d05b8SZbigniew Bodek 			ena_com_destroy_io_queue(ena_dev, ena_qid);
14839b8d05b8SZbigniew Bodek 			goto err_tx;
14849b8d05b8SZbigniew Bodek 		}
14859b8d05b8SZbigniew Bodek 	}
14869b8d05b8SZbigniew Bodek 
14879b8d05b8SZbigniew Bodek 	/* Create RX queues */
14887d8c4feeSMarcin Wojtas 	for (i = 0; i < adapter->num_io_queues; i++) {
14899b8d05b8SZbigniew Bodek 		msix_vector = ENA_IO_IRQ_IDX(i);
14909b8d05b8SZbigniew Bodek 		ena_qid = ENA_IO_RXQ_IDX(i);
14919b8d05b8SZbigniew Bodek 		ctx.mem_queue_type = ENA_ADMIN_PLACEMENT_POLICY_HOST;
14929b8d05b8SZbigniew Bodek 		ctx.direction = ENA_COM_IO_QUEUE_DIRECTION_RX;
14939762a033SMarcin Wojtas 		ctx.queue_size = adapter->requested_rx_ring_size;
14949b8d05b8SZbigniew Bodek 		ctx.msix_vector = msix_vector;
14959b8d05b8SZbigniew Bodek 		ctx.qid = ena_qid;
14969b8d05b8SZbigniew Bodek 		rc = ena_com_create_io_queue(ena_dev, &ctx);
14973f9ed7abSMarcin Wojtas 		if (unlikely(rc != 0)) {
14989b8d05b8SZbigniew Bodek 			device_printf(adapter->pdev,
14999b8d05b8SZbigniew Bodek 			    "Failed to create io RX queue[%d] rc: %d\n", i, rc);
15009b8d05b8SZbigniew Bodek 			goto err_rx;
15019b8d05b8SZbigniew Bodek 		}
15029b8d05b8SZbigniew Bodek 
15039b8d05b8SZbigniew Bodek 		ring = &adapter->rx_ring[i];
15049b8d05b8SZbigniew Bodek 		rc = ena_com_get_io_handlers(ena_dev, ena_qid,
15059b8d05b8SZbigniew Bodek 		    &ring->ena_com_io_sq,
15069b8d05b8SZbigniew Bodek 		    &ring->ena_com_io_cq);
15073f9ed7abSMarcin Wojtas 		if (unlikely(rc != 0)) {
15089b8d05b8SZbigniew Bodek 			device_printf(adapter->pdev,
15099b8d05b8SZbigniew Bodek 			    "Failed to get RX queue handlers. RX queue num"
15109b8d05b8SZbigniew Bodek 			    " %d rc: %d\n", i, rc);
15119b8d05b8SZbigniew Bodek 			ena_com_destroy_io_queue(ena_dev, ena_qid);
15129b8d05b8SZbigniew Bodek 			goto err_rx;
15139b8d05b8SZbigniew Bodek 		}
15149b8d05b8SZbigniew Bodek 	}
15159b8d05b8SZbigniew Bodek 
15167d8c4feeSMarcin Wojtas 	for (i = 0; i < adapter->num_io_queues; i++) {
15175cb9db07SMarcin Wojtas 		queue = &adapter->que[i];
15185cb9db07SMarcin Wojtas 
15196c3e93cbSGleb Smirnoff 		NET_TASK_INIT(&queue->cleanup_task, 0, ena_cleanup, queue);
15205cb9db07SMarcin Wojtas 		queue->cleanup_tq = taskqueue_create_fast("ena cleanup",
15215cb9db07SMarcin Wojtas 		    M_WAITOK, taskqueue_thread_enqueue, &queue->cleanup_tq);
15225cb9db07SMarcin Wojtas 
15235cb9db07SMarcin Wojtas 		taskqueue_start_threads(&queue->cleanup_tq, 1, PI_NET,
15245cb9db07SMarcin Wojtas 		    "%s queue %d cleanup",
15255cb9db07SMarcin Wojtas 		    device_get_nameunit(adapter->pdev), i);
15265cb9db07SMarcin Wojtas 	}
15275cb9db07SMarcin Wojtas 
15289b8d05b8SZbigniew Bodek 	return (0);
15299b8d05b8SZbigniew Bodek 
15309b8d05b8SZbigniew Bodek err_rx:
15319b8d05b8SZbigniew Bodek 	while (i--)
15329b8d05b8SZbigniew Bodek 		ena_com_destroy_io_queue(ena_dev, ENA_IO_RXQ_IDX(i));
15337d8c4feeSMarcin Wojtas 	i = adapter->num_io_queues;
15349b8d05b8SZbigniew Bodek err_tx:
15359b8d05b8SZbigniew Bodek 	while (i--)
15369b8d05b8SZbigniew Bodek 		ena_com_destroy_io_queue(ena_dev, ENA_IO_TXQ_IDX(i));
15379b8d05b8SZbigniew Bodek 
15389b8d05b8SZbigniew Bodek 	return (ENXIO);
15399b8d05b8SZbigniew Bodek }
15409b8d05b8SZbigniew Bodek 
15419b8d05b8SZbigniew Bodek /*********************************************************************
15429b8d05b8SZbigniew Bodek  *
15439b8d05b8SZbigniew Bodek  *  MSIX & Interrupt Service routine
15449b8d05b8SZbigniew Bodek  *
15459b8d05b8SZbigniew Bodek  **********************************************************************/
15469b8d05b8SZbigniew Bodek 
15479b8d05b8SZbigniew Bodek /**
15489b8d05b8SZbigniew Bodek  * ena_handle_msix - MSIX Interrupt Handler for admin/async queue
15499b8d05b8SZbigniew Bodek  * @arg: interrupt number
15509b8d05b8SZbigniew Bodek  **/
15519b8d05b8SZbigniew Bodek static void
15529b8d05b8SZbigniew Bodek ena_intr_msix_mgmnt(void *arg)
15539b8d05b8SZbigniew Bodek {
15549b8d05b8SZbigniew Bodek 	struct ena_adapter *adapter = (struct ena_adapter *)arg;
15559b8d05b8SZbigniew Bodek 
15569b8d05b8SZbigniew Bodek 	ena_com_admin_q_comp_intr_handler(adapter->ena_dev);
1557fd43fd2aSMarcin Wojtas 	if (likely(ENA_FLAG_ISSET(ENA_FLAG_DEVICE_RUNNING, adapter)))
15589b8d05b8SZbigniew Bodek 		ena_com_aenq_intr_handler(adapter->ena_dev, arg);
15599b8d05b8SZbigniew Bodek }
15609b8d05b8SZbigniew Bodek 
15615cb9db07SMarcin Wojtas /**
15625cb9db07SMarcin Wojtas  * ena_handle_msix - MSIX Interrupt Handler for Tx/Rx
15635cb9db07SMarcin Wojtas  * @arg: queue
15645cb9db07SMarcin Wojtas  **/
15655cb9db07SMarcin Wojtas static int
15665cb9db07SMarcin Wojtas ena_handle_msix(void *arg)
15675cb9db07SMarcin Wojtas {
15685cb9db07SMarcin Wojtas 	struct ena_que *queue = arg;
15695cb9db07SMarcin Wojtas 	struct ena_adapter *adapter = queue->adapter;
15705cb9db07SMarcin Wojtas 	if_t ifp = adapter->ifp;
15715cb9db07SMarcin Wojtas 
15725cb9db07SMarcin Wojtas 	if (unlikely((if_getdrvflags(ifp) & IFF_DRV_RUNNING) == 0))
15735cb9db07SMarcin Wojtas 		return (FILTER_STRAY);
15745cb9db07SMarcin Wojtas 
15755cb9db07SMarcin Wojtas 	taskqueue_enqueue(queue->cleanup_tq, &queue->cleanup_task);
15765cb9db07SMarcin Wojtas 
15775cb9db07SMarcin Wojtas 	return (FILTER_HANDLED);
15785cb9db07SMarcin Wojtas }
15795cb9db07SMarcin Wojtas 
15809b8d05b8SZbigniew Bodek static int
15819b8d05b8SZbigniew Bodek ena_enable_msix(struct ena_adapter *adapter)
15829b8d05b8SZbigniew Bodek {
15839b8d05b8SZbigniew Bodek 	device_t dev = adapter->pdev;
15848805021aSMarcin Wojtas 	int msix_vecs, msix_req;
15858805021aSMarcin Wojtas 	int i, rc = 0;
15869b8d05b8SZbigniew Bodek 
1587fd43fd2aSMarcin Wojtas 	if (ENA_FLAG_ISSET(ENA_FLAG_MSIX_ENABLED, adapter)) {
1588fd43fd2aSMarcin Wojtas 		device_printf(dev, "Error, MSI-X is already enabled\n");
1589fd43fd2aSMarcin Wojtas 		return (EINVAL);
1590fd43fd2aSMarcin Wojtas 	}
1591fd43fd2aSMarcin Wojtas 
15929b8d05b8SZbigniew Bodek 	/* Reserved the max msix vectors we might need */
15937d8c4feeSMarcin Wojtas 	msix_vecs = ENA_MAX_MSIX_VEC(adapter->max_num_io_queues);
15949b8d05b8SZbigniew Bodek 
1595cd5d5804SMarcin Wojtas 	adapter->msix_entries = malloc(msix_vecs * sizeof(struct msix_entry),
1596cd5d5804SMarcin Wojtas 	    M_DEVBUF, M_WAITOK | M_ZERO);
1597cd5d5804SMarcin Wojtas 
15989eb1615fSMarcin Wojtas 	ena_trace(NULL, ENA_DBG, "trying to enable MSI-X, vectors: %d\n", msix_vecs);
15999b8d05b8SZbigniew Bodek 
16009b8d05b8SZbigniew Bodek 	for (i = 0; i < msix_vecs; i++) {
16019b8d05b8SZbigniew Bodek 		adapter->msix_entries[i].entry = i;
16029b8d05b8SZbigniew Bodek 		/* Vectors must start from 1 */
16039b8d05b8SZbigniew Bodek 		adapter->msix_entries[i].vector = i + 1;
16049b8d05b8SZbigniew Bodek 	}
16059b8d05b8SZbigniew Bodek 
16068805021aSMarcin Wojtas 	msix_req = msix_vecs;
16079b8d05b8SZbigniew Bodek 	rc = pci_alloc_msix(dev, &msix_vecs);
16083f9ed7abSMarcin Wojtas 	if (unlikely(rc != 0)) {
16099b8d05b8SZbigniew Bodek 		device_printf(dev,
16109b8d05b8SZbigniew Bodek 		    "Failed to enable MSIX, vectors %d rc %d\n", msix_vecs, rc);
16117d2544e6SMarcin Wojtas 
16129b8d05b8SZbigniew Bodek 		rc = ENOSPC;
16137d2544e6SMarcin Wojtas 		goto err_msix_free;
16149b8d05b8SZbigniew Bodek 	}
16159b8d05b8SZbigniew Bodek 
16168805021aSMarcin Wojtas 	if (msix_vecs != msix_req) {
16172b5b60feSMarcin Wojtas 		if (msix_vecs == ENA_ADMIN_MSIX_VEC) {
16182b5b60feSMarcin Wojtas 			device_printf(dev,
16192b5b60feSMarcin Wojtas 			    "Not enough number of MSI-x allocated: %d\n",
16202b5b60feSMarcin Wojtas 			    msix_vecs);
16212b5b60feSMarcin Wojtas 			pci_release_msi(dev);
16222b5b60feSMarcin Wojtas 			rc = ENOSPC;
16232b5b60feSMarcin Wojtas 			goto err_msix_free;
16242b5b60feSMarcin Wojtas 		}
16258805021aSMarcin Wojtas 		device_printf(dev, "Enable only %d MSI-x (out of %d), reduce "
16268805021aSMarcin Wojtas 		    "the number of queues\n", msix_vecs, msix_req);
16278805021aSMarcin Wojtas 	}
16288805021aSMarcin Wojtas 
16299b8d05b8SZbigniew Bodek 	adapter->msix_vecs = msix_vecs;
1630fd43fd2aSMarcin Wojtas 	ENA_FLAG_SET_ATOMIC(ENA_FLAG_MSIX_ENABLED, adapter);
16319b8d05b8SZbigniew Bodek 
16327d2544e6SMarcin Wojtas 	return (0);
16337d2544e6SMarcin Wojtas 
16347d2544e6SMarcin Wojtas err_msix_free:
16357d2544e6SMarcin Wojtas 	free(adapter->msix_entries, M_DEVBUF);
16367d2544e6SMarcin Wojtas 	adapter->msix_entries = NULL;
16377d2544e6SMarcin Wojtas 
16389b8d05b8SZbigniew Bodek 	return (rc);
16399b8d05b8SZbigniew Bodek }
16409b8d05b8SZbigniew Bodek 
16419b8d05b8SZbigniew Bodek static void
16429b8d05b8SZbigniew Bodek ena_setup_mgmnt_intr(struct ena_adapter *adapter)
16439b8d05b8SZbigniew Bodek {
16449b8d05b8SZbigniew Bodek 
16459b8d05b8SZbigniew Bodek 	snprintf(adapter->irq_tbl[ENA_MGMNT_IRQ_IDX].name,
16469b8d05b8SZbigniew Bodek 	    ENA_IRQNAME_SIZE, "ena-mgmnt@pci:%s",
16479b8d05b8SZbigniew Bodek 	    device_get_nameunit(adapter->pdev));
16489b8d05b8SZbigniew Bodek 	/*
16499b8d05b8SZbigniew Bodek 	 * Handler is NULL on purpose, it will be set
16509b8d05b8SZbigniew Bodek 	 * when mgmnt interrupt is acquired
16519b8d05b8SZbigniew Bodek 	 */
16529b8d05b8SZbigniew Bodek 	adapter->irq_tbl[ENA_MGMNT_IRQ_IDX].handler = NULL;
16539b8d05b8SZbigniew Bodek 	adapter->irq_tbl[ENA_MGMNT_IRQ_IDX].data = adapter;
16549b8d05b8SZbigniew Bodek 	adapter->irq_tbl[ENA_MGMNT_IRQ_IDX].vector =
16559b8d05b8SZbigniew Bodek 	    adapter->msix_entries[ENA_MGMNT_IRQ_IDX].vector;
16569b8d05b8SZbigniew Bodek }
16579b8d05b8SZbigniew Bodek 
165877958fcdSMarcin Wojtas static int
16599b8d05b8SZbigniew Bodek ena_setup_io_intr(struct ena_adapter *adapter)
16609b8d05b8SZbigniew Bodek {
16619b8d05b8SZbigniew Bodek 	static int last_bind_cpu = -1;
16629b8d05b8SZbigniew Bodek 	int irq_idx;
16639b8d05b8SZbigniew Bodek 
166477958fcdSMarcin Wojtas 	if (adapter->msix_entries == NULL)
166577958fcdSMarcin Wojtas 		return (EINVAL);
166677958fcdSMarcin Wojtas 
16677d8c4feeSMarcin Wojtas 	for (int i = 0; i < adapter->num_io_queues; i++) {
16689b8d05b8SZbigniew Bodek 		irq_idx = ENA_IO_IRQ_IDX(i);
16699b8d05b8SZbigniew Bodek 
16709b8d05b8SZbigniew Bodek 		snprintf(adapter->irq_tbl[irq_idx].name, ENA_IRQNAME_SIZE,
16719b8d05b8SZbigniew Bodek 		    "%s-TxRx-%d", device_get_nameunit(adapter->pdev), i);
16729b8d05b8SZbigniew Bodek 		adapter->irq_tbl[irq_idx].handler = ena_handle_msix;
16739b8d05b8SZbigniew Bodek 		adapter->irq_tbl[irq_idx].data = &adapter->que[i];
16749b8d05b8SZbigniew Bodek 		adapter->irq_tbl[irq_idx].vector =
16759b8d05b8SZbigniew Bodek 		    adapter->msix_entries[irq_idx].vector;
16769eb1615fSMarcin Wojtas 		ena_trace(NULL, ENA_INFO | ENA_IOQ, "ena_setup_io_intr vector: %d\n",
16779b8d05b8SZbigniew Bodek 		    adapter->msix_entries[irq_idx].vector);
1678277f11c4SMarcin Wojtas 
16799b8d05b8SZbigniew Bodek 		/*
1680277f11c4SMarcin Wojtas 		 * We want to bind rings to the corresponding cpu
16819b8d05b8SZbigniew Bodek 		 * using something similar to the RSS round-robin technique.
16829b8d05b8SZbigniew Bodek 		 */
16833f9ed7abSMarcin Wojtas 		if (unlikely(last_bind_cpu < 0))
16849b8d05b8SZbigniew Bodek 			last_bind_cpu = CPU_FIRST();
16859b8d05b8SZbigniew Bodek 		adapter->que[i].cpu = adapter->irq_tbl[irq_idx].cpu =
16869b8d05b8SZbigniew Bodek 		    last_bind_cpu;
16879b8d05b8SZbigniew Bodek 		last_bind_cpu = CPU_NEXT(last_bind_cpu);
16889b8d05b8SZbigniew Bodek 	}
168977958fcdSMarcin Wojtas 
169077958fcdSMarcin Wojtas 	return (0);
16919b8d05b8SZbigniew Bodek }
16929b8d05b8SZbigniew Bodek 
16939b8d05b8SZbigniew Bodek static int
16949b8d05b8SZbigniew Bodek ena_request_mgmnt_irq(struct ena_adapter *adapter)
16959b8d05b8SZbigniew Bodek {
16969b8d05b8SZbigniew Bodek 	struct ena_irq *irq;
16979b8d05b8SZbigniew Bodek 	unsigned long flags;
16989b8d05b8SZbigniew Bodek 	int rc, rcc;
16999b8d05b8SZbigniew Bodek 
17009b8d05b8SZbigniew Bodek 	flags = RF_ACTIVE | RF_SHAREABLE;
17019b8d05b8SZbigniew Bodek 
17029b8d05b8SZbigniew Bodek 	irq = &adapter->irq_tbl[ENA_MGMNT_IRQ_IDX];
17039b8d05b8SZbigniew Bodek 	irq->res = bus_alloc_resource_any(adapter->pdev, SYS_RES_IRQ,
17049b8d05b8SZbigniew Bodek 	    &irq->vector, flags);
17059b8d05b8SZbigniew Bodek 
17063f9ed7abSMarcin Wojtas 	if (unlikely(irq->res == NULL)) {
17079b8d05b8SZbigniew Bodek 		device_printf(adapter->pdev, "could not allocate "
17089b8d05b8SZbigniew Bodek 		    "irq vector: %d\n", irq->vector);
17097d2544e6SMarcin Wojtas 		return (ENXIO);
17109b8d05b8SZbigniew Bodek 	}
17119b8d05b8SZbigniew Bodek 
17120bdffe59SMarcin Wojtas 	rc = bus_setup_intr(adapter->pdev, irq->res,
17130bdffe59SMarcin Wojtas 	    INTR_TYPE_NET | INTR_MPSAFE, NULL, ena_intr_msix_mgmnt,
17140bdffe59SMarcin Wojtas 	    irq->data, &irq->cookie);
17153f9ed7abSMarcin Wojtas 	if (unlikely(rc != 0)) {
17169b8d05b8SZbigniew Bodek 		device_printf(adapter->pdev, "failed to register "
17179b8d05b8SZbigniew Bodek 		    "interrupt handler for irq %ju: %d\n",
17189b8d05b8SZbigniew Bodek 		    rman_get_start(irq->res), rc);
17197d2544e6SMarcin Wojtas 		goto err_res_free;
17209b8d05b8SZbigniew Bodek 	}
17219b8d05b8SZbigniew Bodek 	irq->requested = true;
17229b8d05b8SZbigniew Bodek 
17239b8d05b8SZbigniew Bodek 	return (rc);
17249b8d05b8SZbigniew Bodek 
17257d2544e6SMarcin Wojtas err_res_free:
17269eb1615fSMarcin Wojtas 	ena_trace(NULL, ENA_INFO | ENA_ADMQ, "releasing resource for irq %d\n",
17277d2544e6SMarcin Wojtas 	    irq->vector);
17289b8d05b8SZbigniew Bodek 	rcc = bus_release_resource(adapter->pdev, SYS_RES_IRQ,
17299b8d05b8SZbigniew Bodek 	    irq->vector, irq->res);
17303f9ed7abSMarcin Wojtas 	if (unlikely(rcc != 0))
17319b8d05b8SZbigniew Bodek 		device_printf(adapter->pdev, "dev has no parent while "
17329b8d05b8SZbigniew Bodek 		    "releasing res for irq: %d\n", irq->vector);
17339b8d05b8SZbigniew Bodek 	irq->res = NULL;
17349b8d05b8SZbigniew Bodek 
17359b8d05b8SZbigniew Bodek 	return (rc);
17369b8d05b8SZbigniew Bodek }
17379b8d05b8SZbigniew Bodek 
17389b8d05b8SZbigniew Bodek static int
17399b8d05b8SZbigniew Bodek ena_request_io_irq(struct ena_adapter *adapter)
17409b8d05b8SZbigniew Bodek {
17419b8d05b8SZbigniew Bodek 	struct ena_irq *irq;
17429b8d05b8SZbigniew Bodek 	unsigned long flags = 0;
17439b8d05b8SZbigniew Bodek 	int rc = 0, i, rcc;
17449b8d05b8SZbigniew Bodek 
1745fd43fd2aSMarcin Wojtas 	if (unlikely(!ENA_FLAG_ISSET(ENA_FLAG_MSIX_ENABLED, adapter))) {
17464e8acd84SMarcin Wojtas 		device_printf(adapter->pdev,
17474e8acd84SMarcin Wojtas 		    "failed to request I/O IRQ: MSI-X is not enabled\n");
17489b8d05b8SZbigniew Bodek 		return (EINVAL);
17499b8d05b8SZbigniew Bodek 	} else {
17509b8d05b8SZbigniew Bodek 		flags = RF_ACTIVE | RF_SHAREABLE;
17519b8d05b8SZbigniew Bodek 	}
17529b8d05b8SZbigniew Bodek 
17539b8d05b8SZbigniew Bodek 	for (i = ENA_IO_IRQ_FIRST_IDX; i < adapter->msix_vecs; i++) {
17549b8d05b8SZbigniew Bodek 		irq = &adapter->irq_tbl[i];
17559b8d05b8SZbigniew Bodek 
17563f9ed7abSMarcin Wojtas 		if (unlikely(irq->requested))
17579b8d05b8SZbigniew Bodek 			continue;
17589b8d05b8SZbigniew Bodek 
17599b8d05b8SZbigniew Bodek 		irq->res = bus_alloc_resource_any(adapter->pdev, SYS_RES_IRQ,
17609b8d05b8SZbigniew Bodek 		    &irq->vector, flags);
17613f9ed7abSMarcin Wojtas 		if (unlikely(irq->res == NULL)) {
1762469a8407SMarcin Wojtas 			rc = ENOMEM;
17639b8d05b8SZbigniew Bodek 			device_printf(adapter->pdev, "could not allocate "
17649b8d05b8SZbigniew Bodek 			    "irq vector: %d\n", irq->vector);
17659b8d05b8SZbigniew Bodek 			goto err;
17669b8d05b8SZbigniew Bodek 		}
17679b8d05b8SZbigniew Bodek 
17680bdffe59SMarcin Wojtas 		rc = bus_setup_intr(adapter->pdev, irq->res,
17695cb9db07SMarcin Wojtas 		    INTR_TYPE_NET | INTR_MPSAFE, irq->handler, NULL,
17705cb9db07SMarcin Wojtas 		    irq->data, &irq->cookie);
17713f9ed7abSMarcin Wojtas 		 if (unlikely(rc != 0)) {
17729b8d05b8SZbigniew Bodek 			device_printf(adapter->pdev, "failed to register "
17739b8d05b8SZbigniew Bodek 			    "interrupt handler for irq %ju: %d\n",
17749b8d05b8SZbigniew Bodek 			    rman_get_start(irq->res), rc);
17759b8d05b8SZbigniew Bodek 			goto err;
17769b8d05b8SZbigniew Bodek 		}
17779b8d05b8SZbigniew Bodek 		irq->requested = true;
17789b8d05b8SZbigniew Bodek 
17799eb1615fSMarcin Wojtas 		ena_trace(NULL, ENA_INFO, "queue %d - cpu %d\n",
17809b8d05b8SZbigniew Bodek 		    i - ENA_IO_IRQ_FIRST_IDX, irq->cpu);
17819b8d05b8SZbigniew Bodek 	}
17829b8d05b8SZbigniew Bodek 
17839b8d05b8SZbigniew Bodek 	return (rc);
17849b8d05b8SZbigniew Bodek 
17859b8d05b8SZbigniew Bodek err:
17869b8d05b8SZbigniew Bodek 
17879b8d05b8SZbigniew Bodek 	for (; i >= ENA_IO_IRQ_FIRST_IDX; i--) {
17889b8d05b8SZbigniew Bodek 		irq = &adapter->irq_tbl[i];
17899b8d05b8SZbigniew Bodek 		rcc = 0;
17909b8d05b8SZbigniew Bodek 
17919b8d05b8SZbigniew Bodek 		/* Once we entered err: section and irq->requested is true we
17929b8d05b8SZbigniew Bodek 		   free both intr and resources */
17930bdffe59SMarcin Wojtas 		if (irq->requested)
17949b8d05b8SZbigniew Bodek 			rcc = bus_teardown_intr(adapter->pdev, irq->res, irq->cookie);
17953f9ed7abSMarcin Wojtas 		if (unlikely(rcc != 0))
17969b8d05b8SZbigniew Bodek 			device_printf(adapter->pdev, "could not release"
17979b8d05b8SZbigniew Bodek 			    " irq: %d, error: %d\n", irq->vector, rcc);
17989b8d05b8SZbigniew Bodek 
17999b8d05b8SZbigniew Bodek 		/* If we entred err: section without irq->requested set we know
18009b8d05b8SZbigniew Bodek 		   it was bus_alloc_resource_any() that needs cleanup, provided
18019b8d05b8SZbigniew Bodek 		   res is not NULL. In case res is NULL no work in needed in
18029b8d05b8SZbigniew Bodek 		   this iteration */
18039b8d05b8SZbigniew Bodek 		rcc = 0;
18049b8d05b8SZbigniew Bodek 		if (irq->res != NULL) {
18059b8d05b8SZbigniew Bodek 			rcc = bus_release_resource(adapter->pdev, SYS_RES_IRQ,
18069b8d05b8SZbigniew Bodek 			    irq->vector, irq->res);
18079b8d05b8SZbigniew Bodek 		}
18083f9ed7abSMarcin Wojtas 		if (unlikely(rcc != 0))
18099b8d05b8SZbigniew Bodek 			device_printf(adapter->pdev, "dev has no parent while "
18109b8d05b8SZbigniew Bodek 			    "releasing res for irq: %d\n", irq->vector);
18119b8d05b8SZbigniew Bodek 		irq->requested = false;
18129b8d05b8SZbigniew Bodek 		irq->res = NULL;
18139b8d05b8SZbigniew Bodek 	}
18149b8d05b8SZbigniew Bodek 
18159b8d05b8SZbigniew Bodek 	return (rc);
18169b8d05b8SZbigniew Bodek }
18179b8d05b8SZbigniew Bodek 
18189b8d05b8SZbigniew Bodek static void
18199b8d05b8SZbigniew Bodek ena_free_mgmnt_irq(struct ena_adapter *adapter)
18209b8d05b8SZbigniew Bodek {
18219b8d05b8SZbigniew Bodek 	struct ena_irq *irq;
18229b8d05b8SZbigniew Bodek 	int rc;
18239b8d05b8SZbigniew Bodek 
18249b8d05b8SZbigniew Bodek 	irq = &adapter->irq_tbl[ENA_MGMNT_IRQ_IDX];
18259b8d05b8SZbigniew Bodek 	if (irq->requested) {
18269eb1615fSMarcin Wojtas 		ena_trace(NULL, ENA_INFO | ENA_ADMQ, "tear down irq: %d\n",
18279b8d05b8SZbigniew Bodek 		    irq->vector);
18289b8d05b8SZbigniew Bodek 		rc = bus_teardown_intr(adapter->pdev, irq->res, irq->cookie);
18293f9ed7abSMarcin Wojtas 		if (unlikely(rc != 0))
18309b8d05b8SZbigniew Bodek 			device_printf(adapter->pdev, "failed to tear "
18319b8d05b8SZbigniew Bodek 			    "down irq: %d\n", irq->vector);
18329b8d05b8SZbigniew Bodek 		irq->requested = 0;
18339b8d05b8SZbigniew Bodek 	}
18349b8d05b8SZbigniew Bodek 
18359b8d05b8SZbigniew Bodek 	if (irq->res != NULL) {
18369eb1615fSMarcin Wojtas 		ena_trace(NULL, ENA_INFO | ENA_ADMQ, "release resource irq: %d\n",
18379b8d05b8SZbigniew Bodek 		    irq->vector);
18389b8d05b8SZbigniew Bodek 		rc = bus_release_resource(adapter->pdev, SYS_RES_IRQ,
18399b8d05b8SZbigniew Bodek 		    irq->vector, irq->res);
18409b8d05b8SZbigniew Bodek 		irq->res = NULL;
18413f9ed7abSMarcin Wojtas 		if (unlikely(rc != 0))
18429b8d05b8SZbigniew Bodek 			device_printf(adapter->pdev, "dev has no parent while "
18439b8d05b8SZbigniew Bodek 			    "releasing res for irq: %d\n", irq->vector);
18449b8d05b8SZbigniew Bodek 	}
18459b8d05b8SZbigniew Bodek }
18469b8d05b8SZbigniew Bodek 
18479b8d05b8SZbigniew Bodek static void
18489b8d05b8SZbigniew Bodek ena_free_io_irq(struct ena_adapter *adapter)
18499b8d05b8SZbigniew Bodek {
18509b8d05b8SZbigniew Bodek 	struct ena_irq *irq;
18519b8d05b8SZbigniew Bodek 	int rc;
18529b8d05b8SZbigniew Bodek 
18539b8d05b8SZbigniew Bodek 	for (int i = ENA_IO_IRQ_FIRST_IDX; i < adapter->msix_vecs; i++) {
18549b8d05b8SZbigniew Bodek 		irq = &adapter->irq_tbl[i];
18559b8d05b8SZbigniew Bodek 		if (irq->requested) {
18569eb1615fSMarcin Wojtas 			ena_trace(NULL, ENA_INFO | ENA_IOQ, "tear down irq: %d\n",
18579b8d05b8SZbigniew Bodek 			    irq->vector);
18589b8d05b8SZbigniew Bodek 			rc = bus_teardown_intr(adapter->pdev, irq->res,
18599b8d05b8SZbigniew Bodek 			    irq->cookie);
18603f9ed7abSMarcin Wojtas 			if (unlikely(rc != 0)) {
18619b8d05b8SZbigniew Bodek 				device_printf(adapter->pdev, "failed to tear "
18629b8d05b8SZbigniew Bodek 				    "down irq: %d\n", irq->vector);
18639b8d05b8SZbigniew Bodek 			}
18649b8d05b8SZbigniew Bodek 			irq->requested = 0;
18659b8d05b8SZbigniew Bodek 		}
18669b8d05b8SZbigniew Bodek 
18679b8d05b8SZbigniew Bodek 		if (irq->res != NULL) {
18689eb1615fSMarcin Wojtas 			ena_trace(NULL, ENA_INFO | ENA_IOQ, "release resource irq: %d\n",
18699b8d05b8SZbigniew Bodek 			    irq->vector);
18709b8d05b8SZbigniew Bodek 			rc = bus_release_resource(adapter->pdev, SYS_RES_IRQ,
18719b8d05b8SZbigniew Bodek 			    irq->vector, irq->res);
18729b8d05b8SZbigniew Bodek 			irq->res = NULL;
18733f9ed7abSMarcin Wojtas 			if (unlikely(rc != 0)) {
18749b8d05b8SZbigniew Bodek 				device_printf(adapter->pdev, "dev has no parent"
18759b8d05b8SZbigniew Bodek 				    " while releasing res for irq: %d\n",
18769b8d05b8SZbigniew Bodek 				    irq->vector);
18779b8d05b8SZbigniew Bodek 			}
18789b8d05b8SZbigniew Bodek 		}
18799b8d05b8SZbigniew Bodek 	}
18809b8d05b8SZbigniew Bodek }
18819b8d05b8SZbigniew Bodek 
18829b8d05b8SZbigniew Bodek static void
18839b8d05b8SZbigniew Bodek ena_free_irqs(struct ena_adapter* adapter)
18849b8d05b8SZbigniew Bodek {
18859b8d05b8SZbigniew Bodek 
18869b8d05b8SZbigniew Bodek 	ena_free_io_irq(adapter);
18879b8d05b8SZbigniew Bodek 	ena_free_mgmnt_irq(adapter);
18889b8d05b8SZbigniew Bodek 	ena_disable_msix(adapter);
18899b8d05b8SZbigniew Bodek }
18909b8d05b8SZbigniew Bodek 
18919b8d05b8SZbigniew Bodek static void
18929b8d05b8SZbigniew Bodek ena_disable_msix(struct ena_adapter *adapter)
18939b8d05b8SZbigniew Bodek {
18949b8d05b8SZbigniew Bodek 
1895fd43fd2aSMarcin Wojtas 	if (ENA_FLAG_ISSET(ENA_FLAG_MSIX_ENABLED, adapter)) {
1896fd43fd2aSMarcin Wojtas 		ENA_FLAG_CLEAR_ATOMIC(ENA_FLAG_MSIX_ENABLED, adapter);
18979b8d05b8SZbigniew Bodek 		pci_release_msi(adapter->pdev);
1898fd43fd2aSMarcin Wojtas 	}
18999b8d05b8SZbigniew Bodek 
19009b8d05b8SZbigniew Bodek 	adapter->msix_vecs = 0;
1901fd43fd2aSMarcin Wojtas 	if (adapter->msix_entries != NULL)
1902cd5d5804SMarcin Wojtas 		free(adapter->msix_entries, M_DEVBUF);
19039b8d05b8SZbigniew Bodek 	adapter->msix_entries = NULL;
19049b8d05b8SZbigniew Bodek }
19059b8d05b8SZbigniew Bodek 
19069b8d05b8SZbigniew Bodek static void
19079b8d05b8SZbigniew Bodek ena_unmask_all_io_irqs(struct ena_adapter *adapter)
19089b8d05b8SZbigniew Bodek {
19099b8d05b8SZbigniew Bodek 	struct ena_com_io_cq* io_cq;
19109b8d05b8SZbigniew Bodek 	struct ena_eth_io_intr_reg intr_reg;
19119b8d05b8SZbigniew Bodek 	uint16_t ena_qid;
19129b8d05b8SZbigniew Bodek 	int i;
19139b8d05b8SZbigniew Bodek 
19149b8d05b8SZbigniew Bodek 	/* Unmask interrupts for all queues */
19157d8c4feeSMarcin Wojtas 	for (i = 0; i < adapter->num_io_queues; i++) {
19169b8d05b8SZbigniew Bodek 		ena_qid = ENA_IO_TXQ_IDX(i);
19179b8d05b8SZbigniew Bodek 		io_cq = &adapter->ena_dev->io_cq_queues[ena_qid];
19189b8d05b8SZbigniew Bodek 		ena_com_update_intr_reg(&intr_reg, 0, 0, true);
19199b8d05b8SZbigniew Bodek 		ena_com_unmask_intr(io_cq, &intr_reg);
19209b8d05b8SZbigniew Bodek 	}
19219b8d05b8SZbigniew Bodek }
19229b8d05b8SZbigniew Bodek 
19239b8d05b8SZbigniew Bodek /* Configure the Rx forwarding */
19240bdffe59SMarcin Wojtas static int
19250bdffe59SMarcin Wojtas ena_rss_configure(struct ena_adapter *adapter)
19269b8d05b8SZbigniew Bodek {
19279b8d05b8SZbigniew Bodek 	struct ena_com_dev *ena_dev = adapter->ena_dev;
19289b8d05b8SZbigniew Bodek 	int rc;
19299b8d05b8SZbigniew Bodek 
193056d41ad5SMarcin Wojtas 	/* In case the RSS table was destroyed */
193156d41ad5SMarcin Wojtas 	if (!ena_dev->rss.tbl_log_size) {
193256d41ad5SMarcin Wojtas 		rc = ena_rss_init_default(adapter);
193356d41ad5SMarcin Wojtas 		if (unlikely((rc != 0) && (rc != EOPNOTSUPP))) {
193456d41ad5SMarcin Wojtas 			device_printf(adapter->pdev,
193556d41ad5SMarcin Wojtas 			    "WARNING: RSS was not properly re-initialized,"
193656d41ad5SMarcin Wojtas 			    " it will affect bandwidth\n");
193756d41ad5SMarcin Wojtas 			ENA_FLAG_CLEAR_ATOMIC(ENA_FLAG_RSS_ACTIVE, adapter);
193856d41ad5SMarcin Wojtas 			return (rc);
193956d41ad5SMarcin Wojtas 		}
194056d41ad5SMarcin Wojtas 	}
194156d41ad5SMarcin Wojtas 
19429b8d05b8SZbigniew Bodek 	/* Set indirect table */
19439b8d05b8SZbigniew Bodek 	rc = ena_com_indirect_table_set(ena_dev);
19440bdffe59SMarcin Wojtas 	if (unlikely((rc != 0) && (rc != EOPNOTSUPP)))
19450bdffe59SMarcin Wojtas 		return (rc);
19469b8d05b8SZbigniew Bodek 
19479b8d05b8SZbigniew Bodek 	/* Configure hash function (if supported) */
19489b8d05b8SZbigniew Bodek 	rc = ena_com_set_hash_function(ena_dev);
19490bdffe59SMarcin Wojtas 	if (unlikely((rc != 0) && (rc != EOPNOTSUPP)))
19500bdffe59SMarcin Wojtas 		return (rc);
19519b8d05b8SZbigniew Bodek 
19529b8d05b8SZbigniew Bodek 	/* Configure hash inputs (if supported) */
19539b8d05b8SZbigniew Bodek 	rc = ena_com_set_hash_ctrl(ena_dev);
19540bdffe59SMarcin Wojtas 	if (unlikely((rc != 0) && (rc != EOPNOTSUPP)))
19550bdffe59SMarcin Wojtas 		return (rc);
19569b8d05b8SZbigniew Bodek 
19570bdffe59SMarcin Wojtas 	return (0);
19589b8d05b8SZbigniew Bodek }
19599b8d05b8SZbigniew Bodek 
19609b8d05b8SZbigniew Bodek static int
19619b8d05b8SZbigniew Bodek ena_up_complete(struct ena_adapter *adapter)
19629b8d05b8SZbigniew Bodek {
19639b8d05b8SZbigniew Bodek 	int rc;
19649b8d05b8SZbigniew Bodek 
1965fd43fd2aSMarcin Wojtas 	if (likely(ENA_FLAG_ISSET(ENA_FLAG_RSS_ACTIVE, adapter))) {
19669b8d05b8SZbigniew Bodek 		rc = ena_rss_configure(adapter);
196756d41ad5SMarcin Wojtas 		if (rc != 0) {
196856d41ad5SMarcin Wojtas 			device_printf(adapter->pdev,
196956d41ad5SMarcin Wojtas 			    "Failed to configure RSS\n");
19709b8d05b8SZbigniew Bodek 			return (rc);
19719b8d05b8SZbigniew Bodek 		}
197256d41ad5SMarcin Wojtas 	}
19739b8d05b8SZbigniew Bodek 
19747d2544e6SMarcin Wojtas 	rc = ena_change_mtu(adapter->ifp, adapter->ifp->if_mtu);
19753f9ed7abSMarcin Wojtas 	if (unlikely(rc != 0))
19767d2544e6SMarcin Wojtas 		return (rc);
19777d2544e6SMarcin Wojtas 
19789b8d05b8SZbigniew Bodek 	ena_refill_all_rx_bufs(adapter);
197930217e2dSMarcin Wojtas 	ena_reset_counters((counter_u64_t *)&adapter->hw_stats,
198030217e2dSMarcin Wojtas 	    sizeof(adapter->hw_stats));
19819b8d05b8SZbigniew Bodek 
19829b8d05b8SZbigniew Bodek 	return (0);
19839b8d05b8SZbigniew Bodek }
19849b8d05b8SZbigniew Bodek 
19859762a033SMarcin Wojtas static void
19869762a033SMarcin Wojtas set_io_rings_size(struct ena_adapter *adapter, int new_tx_size,
19879762a033SMarcin Wojtas     int new_rx_size)
19889762a033SMarcin Wojtas {
19899762a033SMarcin Wojtas 	int i;
19909762a033SMarcin Wojtas 
19919762a033SMarcin Wojtas 	for (i = 0; i < adapter->num_io_queues; i++) {
19929762a033SMarcin Wojtas 		adapter->tx_ring[i].ring_size = new_tx_size;
19939762a033SMarcin Wojtas 		adapter->rx_ring[i].ring_size = new_rx_size;
19949762a033SMarcin Wojtas 	}
19959762a033SMarcin Wojtas }
19969762a033SMarcin Wojtas 
19979762a033SMarcin Wojtas static int
19989762a033SMarcin Wojtas create_queues_with_size_backoff(struct ena_adapter *adapter)
19999762a033SMarcin Wojtas {
20009762a033SMarcin Wojtas 	int rc;
20019762a033SMarcin Wojtas 	uint32_t cur_rx_ring_size, cur_tx_ring_size;
20029762a033SMarcin Wojtas 	uint32_t new_rx_ring_size, new_tx_ring_size;
20039762a033SMarcin Wojtas 
20049762a033SMarcin Wojtas 	/*
20059762a033SMarcin Wojtas 	 * Current queue sizes might be set to smaller than the requested
20069762a033SMarcin Wojtas 	 * ones due to past queue allocation failures.
20079762a033SMarcin Wojtas 	 */
20089762a033SMarcin Wojtas 	set_io_rings_size(adapter, adapter->requested_tx_ring_size,
20099762a033SMarcin Wojtas 	    adapter->requested_rx_ring_size);
20109762a033SMarcin Wojtas 
20119762a033SMarcin Wojtas 	while (1) {
20129762a033SMarcin Wojtas 		/* Allocate transmit descriptors */
20139762a033SMarcin Wojtas 		rc = ena_setup_all_tx_resources(adapter);
20149762a033SMarcin Wojtas 		if (unlikely(rc != 0)) {
20159eb1615fSMarcin Wojtas 			ena_trace(NULL, ENA_ALERT, "err_setup_tx\n");
20169762a033SMarcin Wojtas 			goto err_setup_tx;
20179762a033SMarcin Wojtas 		}
20189762a033SMarcin Wojtas 
20199762a033SMarcin Wojtas 		/* Allocate receive descriptors */
20209762a033SMarcin Wojtas 		rc = ena_setup_all_rx_resources(adapter);
20219762a033SMarcin Wojtas 		if (unlikely(rc != 0)) {
20229eb1615fSMarcin Wojtas 			ena_trace(NULL, ENA_ALERT, "err_setup_rx\n");
20239762a033SMarcin Wojtas 			goto err_setup_rx;
20249762a033SMarcin Wojtas 		}
20259762a033SMarcin Wojtas 
20269762a033SMarcin Wojtas 		/* Create IO queues for Rx & Tx */
20279762a033SMarcin Wojtas 		rc = ena_create_io_queues(adapter);
20289762a033SMarcin Wojtas 		if (unlikely(rc != 0)) {
20299eb1615fSMarcin Wojtas 			ena_trace(NULL, ENA_ALERT,
20309762a033SMarcin Wojtas 			    "create IO queues failed\n");
20319762a033SMarcin Wojtas 			goto err_io_que;
20329762a033SMarcin Wojtas 		}
20339762a033SMarcin Wojtas 
20349762a033SMarcin Wojtas 		return (0);
20359762a033SMarcin Wojtas 
20369762a033SMarcin Wojtas err_io_que:
20379762a033SMarcin Wojtas 		ena_free_all_rx_resources(adapter);
20389762a033SMarcin Wojtas err_setup_rx:
20399762a033SMarcin Wojtas 		ena_free_all_tx_resources(adapter);
20409762a033SMarcin Wojtas err_setup_tx:
20419762a033SMarcin Wojtas 		/*
20429762a033SMarcin Wojtas 		 * Lower the ring size if ENOMEM. Otherwise, return the
20439762a033SMarcin Wojtas 		 * error straightaway.
20449762a033SMarcin Wojtas 		 */
20459762a033SMarcin Wojtas 		if (unlikely(rc != ENOMEM)) {
20469eb1615fSMarcin Wojtas 			ena_trace(NULL, ENA_ALERT,
20479762a033SMarcin Wojtas 			    "Queue creation failed with error code: %d\n", rc);
20489762a033SMarcin Wojtas 			return (rc);
20499762a033SMarcin Wojtas 		}
20509762a033SMarcin Wojtas 
20519762a033SMarcin Wojtas 		cur_tx_ring_size = adapter->tx_ring[0].ring_size;
20529762a033SMarcin Wojtas 		cur_rx_ring_size = adapter->rx_ring[0].ring_size;
20539762a033SMarcin Wojtas 
20549762a033SMarcin Wojtas 		device_printf(adapter->pdev,
20559762a033SMarcin Wojtas 		    "Not enough memory to create queues with sizes TX=%d, RX=%d\n",
20569762a033SMarcin Wojtas 		    cur_tx_ring_size, cur_rx_ring_size);
20579762a033SMarcin Wojtas 
20589762a033SMarcin Wojtas 		new_tx_ring_size = cur_tx_ring_size;
20599762a033SMarcin Wojtas 		new_rx_ring_size = cur_rx_ring_size;
20609762a033SMarcin Wojtas 
20619762a033SMarcin Wojtas 		/*
20629762a033SMarcin Wojtas 		 * Decrease the size of a larger queue, or decrease both if they are
20639762a033SMarcin Wojtas 		 * the same size.
20649762a033SMarcin Wojtas 		 */
20659762a033SMarcin Wojtas 		if (cur_rx_ring_size <= cur_tx_ring_size)
20669762a033SMarcin Wojtas 			new_tx_ring_size = cur_tx_ring_size / 2;
20679762a033SMarcin Wojtas 		if (cur_rx_ring_size >= cur_tx_ring_size)
20689762a033SMarcin Wojtas 			new_rx_ring_size = cur_rx_ring_size / 2;
20699762a033SMarcin Wojtas 
20709762a033SMarcin Wojtas 		if (new_tx_ring_size < ENA_MIN_RING_SIZE ||
20719762a033SMarcin Wojtas 		    new_rx_ring_size < ENA_MIN_RING_SIZE) {
20729762a033SMarcin Wojtas 			device_printf(adapter->pdev,
20739762a033SMarcin Wojtas 			    "Queue creation failed with the smallest possible queue size"
20749762a033SMarcin Wojtas 			    "of %d for both queues. Not retrying with smaller queues\n",
20759762a033SMarcin Wojtas 			    ENA_MIN_RING_SIZE);
20769762a033SMarcin Wojtas 			return (rc);
20779762a033SMarcin Wojtas 		}
20789762a033SMarcin Wojtas 
20799762a033SMarcin Wojtas 		set_io_rings_size(adapter, new_tx_ring_size, new_rx_ring_size);
20809762a033SMarcin Wojtas 	}
20819762a033SMarcin Wojtas }
20829762a033SMarcin Wojtas 
208338c7b965SMarcin Wojtas int
20849b8d05b8SZbigniew Bodek ena_up(struct ena_adapter *adapter)
20859b8d05b8SZbigniew Bodek {
20869b8d05b8SZbigniew Bodek 	int rc = 0;
20879b8d05b8SZbigniew Bodek 
20883f9ed7abSMarcin Wojtas 	if (unlikely(device_is_attached(adapter->pdev) == 0)) {
20899b8d05b8SZbigniew Bodek 		device_printf(adapter->pdev, "device is not attached!\n");
20909b8d05b8SZbigniew Bodek 		return (ENXIO);
20919b8d05b8SZbigniew Bodek 	}
20929b8d05b8SZbigniew Bodek 
2093579d23aaSMarcin Wojtas 	if (ENA_FLAG_ISSET(ENA_FLAG_DEV_UP, adapter))
2094579d23aaSMarcin Wojtas 		return (0);
2095579d23aaSMarcin Wojtas 
20969b8d05b8SZbigniew Bodek 	device_printf(adapter->pdev, "device is going UP\n");
20979b8d05b8SZbigniew Bodek 
20989b8d05b8SZbigniew Bodek 	/* setup interrupts for IO queues */
209977958fcdSMarcin Wojtas 	rc = ena_setup_io_intr(adapter);
210077958fcdSMarcin Wojtas 	if (unlikely(rc != 0)) {
21019eb1615fSMarcin Wojtas 		ena_trace(NULL, ENA_ALERT, "error setting up IO interrupt\n");
210277958fcdSMarcin Wojtas 		goto error;
210377958fcdSMarcin Wojtas 	}
21049b8d05b8SZbigniew Bodek 	rc = ena_request_io_irq(adapter);
21053f9ed7abSMarcin Wojtas 	if (unlikely(rc != 0)) {
21069eb1615fSMarcin Wojtas 		ena_trace(NULL, ENA_ALERT, "err_req_irq\n");
210777958fcdSMarcin Wojtas 		goto error;
21089b8d05b8SZbigniew Bodek 	}
21099b8d05b8SZbigniew Bodek 
21107d8c4feeSMarcin Wojtas 	device_printf(adapter->pdev,
21119762a033SMarcin Wojtas 	    "Creating %u IO queues. Rx queue size: %d, Tx queue size: %d, "
21129762a033SMarcin Wojtas 	    "LLQ is %s\n",
21137d8c4feeSMarcin Wojtas 	    adapter->num_io_queues,
21149762a033SMarcin Wojtas 	    adapter->requested_rx_ring_size,
21159762a033SMarcin Wojtas 	    adapter->requested_tx_ring_size,
21169762a033SMarcin Wojtas 	    (adapter->ena_dev->tx_mem_queue_type ==
21179762a033SMarcin Wojtas 	        ENA_ADMIN_PLACEMENT_POLICY_DEV) ?  "ENABLED" : "DISABLED");
21187d8c4feeSMarcin Wojtas 
21199762a033SMarcin Wojtas 	rc = create_queues_with_size_backoff(adapter);
21203f9ed7abSMarcin Wojtas 	if (unlikely(rc != 0)) {
21219eb1615fSMarcin Wojtas 		ena_trace(NULL, ENA_ALERT,
21229762a033SMarcin Wojtas 		    "error creating queues with size backoff\n");
21239762a033SMarcin Wojtas 		goto err_create_queues_with_backoff;
21249b8d05b8SZbigniew Bodek 	}
21259b8d05b8SZbigniew Bodek 
2126fd43fd2aSMarcin Wojtas 	if (ENA_FLAG_ISSET(ENA_FLAG_LINK_UP, adapter))
21279b8d05b8SZbigniew Bodek 		if_link_state_change(adapter->ifp, LINK_STATE_UP);
21289b8d05b8SZbigniew Bodek 
21299b8d05b8SZbigniew Bodek 	rc = ena_up_complete(adapter);
21303f9ed7abSMarcin Wojtas 	if (unlikely(rc != 0))
21319b8d05b8SZbigniew Bodek 		goto err_up_complete;
21329b8d05b8SZbigniew Bodek 
21339b8d05b8SZbigniew Bodek 	counter_u64_add(adapter->dev_stats.interface_up, 1);
21349b8d05b8SZbigniew Bodek 
21359b8d05b8SZbigniew Bodek 	ena_update_hwassist(adapter);
21369b8d05b8SZbigniew Bodek 
21379b8d05b8SZbigniew Bodek 	if_setdrvflagbits(adapter->ifp, IFF_DRV_RUNNING,
21389b8d05b8SZbigniew Bodek 		IFF_DRV_OACTIVE);
21399b8d05b8SZbigniew Bodek 
214024392281SMarcin Wojtas 	/* Activate timer service only if the device is running.
214124392281SMarcin Wojtas 		* If this flag is not set, it means that the driver is being
214224392281SMarcin Wojtas 		* reset and timer service will be activated afterwards.
214324392281SMarcin Wojtas 		*/
214424392281SMarcin Wojtas 	if (ENA_FLAG_ISSET(ENA_FLAG_DEVICE_RUNNING, adapter)) {
214524392281SMarcin Wojtas 		callout_reset_sbt(&adapter->timer_service, SBT_1S,
214624392281SMarcin Wojtas 			SBT_1S, ena_timer_service, (void *)adapter, 0);
214724392281SMarcin Wojtas 	}
21489b8d05b8SZbigniew Bodek 
2149fd43fd2aSMarcin Wojtas 	ENA_FLAG_SET_ATOMIC(ENA_FLAG_DEV_UP, adapter);
215093471047SZbigniew Bodek 
215193471047SZbigniew Bodek 	ena_unmask_all_io_irqs(adapter);
21529b8d05b8SZbigniew Bodek 
21539b8d05b8SZbigniew Bodek 	return (0);
21549b8d05b8SZbigniew Bodek 
21559b8d05b8SZbigniew Bodek err_up_complete:
21569b8d05b8SZbigniew Bodek 	ena_destroy_all_io_queues(adapter);
21579b8d05b8SZbigniew Bodek 	ena_free_all_rx_resources(adapter);
21589b8d05b8SZbigniew Bodek 	ena_free_all_tx_resources(adapter);
21599762a033SMarcin Wojtas err_create_queues_with_backoff:
21609b8d05b8SZbigniew Bodek 	ena_free_io_irq(adapter);
216177958fcdSMarcin Wojtas error:
21629b8d05b8SZbigniew Bodek 	return (rc);
21639b8d05b8SZbigniew Bodek }
21649b8d05b8SZbigniew Bodek 
21659b8d05b8SZbigniew Bodek static uint64_t
21669b8d05b8SZbigniew Bodek ena_get_counter(if_t ifp, ift_counter cnt)
21679b8d05b8SZbigniew Bodek {
21689b8d05b8SZbigniew Bodek 	struct ena_adapter *adapter;
21699b8d05b8SZbigniew Bodek 	struct ena_hw_stats *stats;
21709b8d05b8SZbigniew Bodek 
21719b8d05b8SZbigniew Bodek 	adapter = if_getsoftc(ifp);
21729b8d05b8SZbigniew Bodek 	stats = &adapter->hw_stats;
21739b8d05b8SZbigniew Bodek 
21749b8d05b8SZbigniew Bodek 	switch (cnt) {
21759b8d05b8SZbigniew Bodek 	case IFCOUNTER_IPACKETS:
217630217e2dSMarcin Wojtas 		return (counter_u64_fetch(stats->rx_packets));
21779b8d05b8SZbigniew Bodek 	case IFCOUNTER_OPACKETS:
217830217e2dSMarcin Wojtas 		return (counter_u64_fetch(stats->tx_packets));
21799b8d05b8SZbigniew Bodek 	case IFCOUNTER_IBYTES:
218030217e2dSMarcin Wojtas 		return (counter_u64_fetch(stats->rx_bytes));
21819b8d05b8SZbigniew Bodek 	case IFCOUNTER_OBYTES:
218230217e2dSMarcin Wojtas 		return (counter_u64_fetch(stats->tx_bytes));
21839b8d05b8SZbigniew Bodek 	case IFCOUNTER_IQDROPS:
218430217e2dSMarcin Wojtas 		return (counter_u64_fetch(stats->rx_drops));
21856c84cec3SMarcin Wojtas 	case IFCOUNTER_OQDROPS:
21866c84cec3SMarcin Wojtas 		return (counter_u64_fetch(stats->tx_drops));
21879b8d05b8SZbigniew Bodek 	default:
21889b8d05b8SZbigniew Bodek 		return (if_get_counter_default(ifp, cnt));
21899b8d05b8SZbigniew Bodek 	}
21909b8d05b8SZbigniew Bodek }
21919b8d05b8SZbigniew Bodek 
21929b8d05b8SZbigniew Bodek static int
21939b8d05b8SZbigniew Bodek ena_media_change(if_t ifp)
21949b8d05b8SZbigniew Bodek {
21959b8d05b8SZbigniew Bodek 	/* Media Change is not supported by firmware */
21969b8d05b8SZbigniew Bodek 	return (0);
21979b8d05b8SZbigniew Bodek }
21989b8d05b8SZbigniew Bodek 
21999b8d05b8SZbigniew Bodek static void
22009b8d05b8SZbigniew Bodek ena_media_status(if_t ifp, struct ifmediareq *ifmr)
22019b8d05b8SZbigniew Bodek {
22029b8d05b8SZbigniew Bodek 	struct ena_adapter *adapter = if_getsoftc(ifp);
22039eb1615fSMarcin Wojtas 	ena_trace(NULL, ENA_DBG, "enter\n");
22049b8d05b8SZbigniew Bodek 
22056959869eSMarcin Wojtas 	ENA_LOCK_LOCK(adapter);
22069b8d05b8SZbigniew Bodek 
22079b8d05b8SZbigniew Bodek 	ifmr->ifm_status = IFM_AVALID;
22089b8d05b8SZbigniew Bodek 	ifmr->ifm_active = IFM_ETHER;
22099b8d05b8SZbigniew Bodek 
2210fd43fd2aSMarcin Wojtas 	if (!ENA_FLAG_ISSET(ENA_FLAG_LINK_UP, adapter)) {
22116959869eSMarcin Wojtas 		ENA_LOCK_UNLOCK(adapter);
22129eb1615fSMarcin Wojtas 		ena_trace(NULL, ENA_INFO, "Link is down\n");
22139b8d05b8SZbigniew Bodek 		return;
22149b8d05b8SZbigniew Bodek 	}
22159b8d05b8SZbigniew Bodek 
22169b8d05b8SZbigniew Bodek 	ifmr->ifm_status |= IFM_ACTIVE;
2217b8ca5dbeSMarcin Wojtas 	ifmr->ifm_active |= IFM_UNKNOWN | IFM_FDX;
22189b8d05b8SZbigniew Bodek 
22196959869eSMarcin Wojtas 	ENA_LOCK_UNLOCK(adapter);
22209b8d05b8SZbigniew Bodek }
22219b8d05b8SZbigniew Bodek 
22229b8d05b8SZbigniew Bodek static void
22239b8d05b8SZbigniew Bodek ena_init(void *arg)
22249b8d05b8SZbigniew Bodek {
22259b8d05b8SZbigniew Bodek 	struct ena_adapter *adapter = (struct ena_adapter *)arg;
22269b8d05b8SZbigniew Bodek 
2227fd43fd2aSMarcin Wojtas 	if (!ENA_FLAG_ISSET(ENA_FLAG_DEV_UP, adapter)) {
22286959869eSMarcin Wojtas 		ENA_LOCK_LOCK(adapter);
22299b8d05b8SZbigniew Bodek 		ena_up(adapter);
22306959869eSMarcin Wojtas 		ENA_LOCK_UNLOCK(adapter);
22313d3a90f9SZbigniew Bodek 	}
22329b8d05b8SZbigniew Bodek }
22339b8d05b8SZbigniew Bodek 
22349b8d05b8SZbigniew Bodek static int
22359b8d05b8SZbigniew Bodek ena_ioctl(if_t ifp, u_long command, caddr_t data)
22369b8d05b8SZbigniew Bodek {
22379b8d05b8SZbigniew Bodek 	struct ena_adapter *adapter;
22389b8d05b8SZbigniew Bodek 	struct ifreq *ifr;
22399b8d05b8SZbigniew Bodek 	int rc;
22409b8d05b8SZbigniew Bodek 
22419b8d05b8SZbigniew Bodek 	adapter = ifp->if_softc;
22429b8d05b8SZbigniew Bodek 	ifr = (struct ifreq *)data;
22439b8d05b8SZbigniew Bodek 
22449b8d05b8SZbigniew Bodek 	/*
22459b8d05b8SZbigniew Bodek 	 * Acquiring lock to prevent from running up and down routines parallel.
22469b8d05b8SZbigniew Bodek 	 */
22479b8d05b8SZbigniew Bodek 	rc = 0;
22489b8d05b8SZbigniew Bodek 	switch (command) {
22499b8d05b8SZbigniew Bodek 	case SIOCSIFMTU:
2250dbf2eb54SMarcin Wojtas 		if (ifp->if_mtu == ifr->ifr_mtu)
2251dbf2eb54SMarcin Wojtas 			break;
22526959869eSMarcin Wojtas 		ENA_LOCK_LOCK(adapter);
22539b8d05b8SZbigniew Bodek 		ena_down(adapter);
22549b8d05b8SZbigniew Bodek 
22559b8d05b8SZbigniew Bodek 		ena_change_mtu(ifp, ifr->ifr_mtu);
22569b8d05b8SZbigniew Bodek 
22579b8d05b8SZbigniew Bodek 		rc = ena_up(adapter);
22586959869eSMarcin Wojtas 		ENA_LOCK_UNLOCK(adapter);
22599b8d05b8SZbigniew Bodek 		break;
22609b8d05b8SZbigniew Bodek 
22619b8d05b8SZbigniew Bodek 	case SIOCSIFFLAGS:
22620bdffe59SMarcin Wojtas 		if ((ifp->if_flags & IFF_UP) != 0) {
22630bdffe59SMarcin Wojtas 			if ((if_getdrvflags(ifp) & IFF_DRV_RUNNING) != 0) {
22640bdffe59SMarcin Wojtas 				if ((ifp->if_flags & (IFF_PROMISC |
22650bdffe59SMarcin Wojtas 				    IFF_ALLMULTI)) != 0) {
22669b8d05b8SZbigniew Bodek 					device_printf(adapter->pdev,
22679b8d05b8SZbigniew Bodek 					    "ioctl promisc/allmulti\n");
22689b8d05b8SZbigniew Bodek 				}
22699b8d05b8SZbigniew Bodek 			} else {
22706959869eSMarcin Wojtas 				ENA_LOCK_LOCK(adapter);
22719b8d05b8SZbigniew Bodek 				rc = ena_up(adapter);
22726959869eSMarcin Wojtas 				ENA_LOCK_UNLOCK(adapter);
22739b8d05b8SZbigniew Bodek 			}
22749b8d05b8SZbigniew Bodek 		} else {
22750bdffe59SMarcin Wojtas 			if ((if_getdrvflags(ifp) & IFF_DRV_RUNNING) != 0) {
22766959869eSMarcin Wojtas 				ENA_LOCK_LOCK(adapter);
22779b8d05b8SZbigniew Bodek 				ena_down(adapter);
22786959869eSMarcin Wojtas 				ENA_LOCK_UNLOCK(adapter);
2279e67c6554SZbigniew Bodek 			}
22809b8d05b8SZbigniew Bodek 		}
22819b8d05b8SZbigniew Bodek 		break;
22829b8d05b8SZbigniew Bodek 
22839b8d05b8SZbigniew Bodek 	case SIOCADDMULTI:
22849b8d05b8SZbigniew Bodek 	case SIOCDELMULTI:
22859b8d05b8SZbigniew Bodek 		break;
22869b8d05b8SZbigniew Bodek 
22879b8d05b8SZbigniew Bodek 	case SIOCSIFMEDIA:
22889b8d05b8SZbigniew Bodek 	case SIOCGIFMEDIA:
22899b8d05b8SZbigniew Bodek 		rc = ifmedia_ioctl(ifp, ifr, &adapter->media, command);
22909b8d05b8SZbigniew Bodek 		break;
22919b8d05b8SZbigniew Bodek 
22929b8d05b8SZbigniew Bodek 	case SIOCSIFCAP:
22939b8d05b8SZbigniew Bodek 		{
22949b8d05b8SZbigniew Bodek 			int reinit = 0;
22959b8d05b8SZbigniew Bodek 
22969b8d05b8SZbigniew Bodek 			if (ifr->ifr_reqcap != ifp->if_capenable) {
22979b8d05b8SZbigniew Bodek 				ifp->if_capenable = ifr->ifr_reqcap;
22989b8d05b8SZbigniew Bodek 				reinit = 1;
22999b8d05b8SZbigniew Bodek 			}
23009b8d05b8SZbigniew Bodek 
23010bdffe59SMarcin Wojtas 			if ((reinit != 0) &&
23020bdffe59SMarcin Wojtas 			    ((if_getdrvflags(ifp) & IFF_DRV_RUNNING) != 0)) {
23036959869eSMarcin Wojtas 				ENA_LOCK_LOCK(adapter);
23049b8d05b8SZbigniew Bodek 				ena_down(adapter);
23059b8d05b8SZbigniew Bodek 				rc = ena_up(adapter);
23066959869eSMarcin Wojtas 				ENA_LOCK_UNLOCK(adapter);
23079b8d05b8SZbigniew Bodek 			}
23089b8d05b8SZbigniew Bodek 		}
23099b8d05b8SZbigniew Bodek 
23109b8d05b8SZbigniew Bodek 		break;
23119b8d05b8SZbigniew Bodek 	default:
23129b8d05b8SZbigniew Bodek 		rc = ether_ioctl(ifp, command, data);
23139b8d05b8SZbigniew Bodek 		break;
23149b8d05b8SZbigniew Bodek 	}
23159b8d05b8SZbigniew Bodek 
23169b8d05b8SZbigniew Bodek 	return (rc);
23179b8d05b8SZbigniew Bodek }
23189b8d05b8SZbigniew Bodek 
23199b8d05b8SZbigniew Bodek static int
23209b8d05b8SZbigniew Bodek ena_get_dev_offloads(struct ena_com_dev_get_features_ctx *feat)
23219b8d05b8SZbigniew Bodek {
23229b8d05b8SZbigniew Bodek 	int caps = 0;
23239b8d05b8SZbigniew Bodek 
23240bdffe59SMarcin Wojtas 	if ((feat->offload.tx &
23259b8d05b8SZbigniew Bodek 	    (ENA_ADMIN_FEATURE_OFFLOAD_DESC_TX_L4_IPV4_CSUM_FULL_MASK |
23269b8d05b8SZbigniew Bodek 	    ENA_ADMIN_FEATURE_OFFLOAD_DESC_TX_L4_IPV4_CSUM_PART_MASK |
23270bdffe59SMarcin Wojtas 	    ENA_ADMIN_FEATURE_OFFLOAD_DESC_TX_L3_CSUM_IPV4_MASK)) != 0)
23289b8d05b8SZbigniew Bodek 		caps |= IFCAP_TXCSUM;
23299b8d05b8SZbigniew Bodek 
23300bdffe59SMarcin Wojtas 	if ((feat->offload.tx &
23319b8d05b8SZbigniew Bodek 	    (ENA_ADMIN_FEATURE_OFFLOAD_DESC_TX_L4_IPV6_CSUM_FULL_MASK |
23320bdffe59SMarcin Wojtas 	    ENA_ADMIN_FEATURE_OFFLOAD_DESC_TX_L4_IPV6_CSUM_PART_MASK)) != 0)
23339b8d05b8SZbigniew Bodek 		caps |= IFCAP_TXCSUM_IPV6;
23349b8d05b8SZbigniew Bodek 
23350bdffe59SMarcin Wojtas 	if ((feat->offload.tx &
23360bdffe59SMarcin Wojtas 	    ENA_ADMIN_FEATURE_OFFLOAD_DESC_TSO_IPV4_MASK) != 0)
23379b8d05b8SZbigniew Bodek 		caps |= IFCAP_TSO4;
23389b8d05b8SZbigniew Bodek 
23390bdffe59SMarcin Wojtas 	if ((feat->offload.tx &
23400bdffe59SMarcin Wojtas 	    ENA_ADMIN_FEATURE_OFFLOAD_DESC_TSO_IPV6_MASK) != 0)
23419b8d05b8SZbigniew Bodek 		caps |= IFCAP_TSO6;
23429b8d05b8SZbigniew Bodek 
23430bdffe59SMarcin Wojtas 	if ((feat->offload.rx_supported &
23449b8d05b8SZbigniew Bodek 	    (ENA_ADMIN_FEATURE_OFFLOAD_DESC_RX_L4_IPV4_CSUM_MASK |
23450bdffe59SMarcin Wojtas 	    ENA_ADMIN_FEATURE_OFFLOAD_DESC_RX_L3_CSUM_IPV4_MASK)) != 0)
23469b8d05b8SZbigniew Bodek 		caps |= IFCAP_RXCSUM;
23479b8d05b8SZbigniew Bodek 
23480bdffe59SMarcin Wojtas 	if ((feat->offload.rx_supported &
23490bdffe59SMarcin Wojtas 	    ENA_ADMIN_FEATURE_OFFLOAD_DESC_RX_L4_IPV6_CSUM_MASK) != 0)
23509b8d05b8SZbigniew Bodek 		caps |= IFCAP_RXCSUM_IPV6;
23519b8d05b8SZbigniew Bodek 
23529b8d05b8SZbigniew Bodek 	caps |= IFCAP_LRO | IFCAP_JUMBO_MTU;
23539b8d05b8SZbigniew Bodek 
23549b8d05b8SZbigniew Bodek 	return (caps);
23559b8d05b8SZbigniew Bodek }
23569b8d05b8SZbigniew Bodek 
23579b8d05b8SZbigniew Bodek static void
23589b8d05b8SZbigniew Bodek ena_update_host_info(struct ena_admin_host_info *host_info, if_t ifp)
23599b8d05b8SZbigniew Bodek {
23609b8d05b8SZbigniew Bodek 
23619b8d05b8SZbigniew Bodek 	host_info->supported_network_features[0] =
23629b8d05b8SZbigniew Bodek 	    (uint32_t)if_getcapabilities(ifp);
23639b8d05b8SZbigniew Bodek }
23649b8d05b8SZbigniew Bodek 
23659b8d05b8SZbigniew Bodek static void
23669b8d05b8SZbigniew Bodek ena_update_hwassist(struct ena_adapter *adapter)
23679b8d05b8SZbigniew Bodek {
23689b8d05b8SZbigniew Bodek 	if_t ifp = adapter->ifp;
23699b8d05b8SZbigniew Bodek 	uint32_t feat = adapter->tx_offload_cap;
23709b8d05b8SZbigniew Bodek 	int cap = if_getcapenable(ifp);
23719b8d05b8SZbigniew Bodek 	int flags = 0;
23729b8d05b8SZbigniew Bodek 
23739b8d05b8SZbigniew Bodek 	if_clearhwassist(ifp);
23749b8d05b8SZbigniew Bodek 
23750bdffe59SMarcin Wojtas 	if ((cap & IFCAP_TXCSUM) != 0) {
23760bdffe59SMarcin Wojtas 		if ((feat &
23770bdffe59SMarcin Wojtas 		    ENA_ADMIN_FEATURE_OFFLOAD_DESC_TX_L3_CSUM_IPV4_MASK) != 0)
23789b8d05b8SZbigniew Bodek 			flags |= CSUM_IP;
23790bdffe59SMarcin Wojtas 		if ((feat &
23809b8d05b8SZbigniew Bodek 		    (ENA_ADMIN_FEATURE_OFFLOAD_DESC_TX_L4_IPV4_CSUM_FULL_MASK |
23810bdffe59SMarcin Wojtas 		    ENA_ADMIN_FEATURE_OFFLOAD_DESC_TX_L4_IPV4_CSUM_PART_MASK)) != 0)
23829b8d05b8SZbigniew Bodek 			flags |= CSUM_IP_UDP | CSUM_IP_TCP;
23839b8d05b8SZbigniew Bodek 	}
23849b8d05b8SZbigniew Bodek 
23850bdffe59SMarcin Wojtas 	if ((cap & IFCAP_TXCSUM_IPV6) != 0)
23869b8d05b8SZbigniew Bodek 		flags |= CSUM_IP6_UDP | CSUM_IP6_TCP;
23879b8d05b8SZbigniew Bodek 
23880bdffe59SMarcin Wojtas 	if ((cap & IFCAP_TSO4) != 0)
23899b8d05b8SZbigniew Bodek 		flags |= CSUM_IP_TSO;
23909b8d05b8SZbigniew Bodek 
23910bdffe59SMarcin Wojtas 	if ((cap & IFCAP_TSO6) != 0)
23929b8d05b8SZbigniew Bodek 		flags |= CSUM_IP6_TSO;
23939b8d05b8SZbigniew Bodek 
23949b8d05b8SZbigniew Bodek 	if_sethwassistbits(ifp, flags, 0);
23959b8d05b8SZbigniew Bodek }
23969b8d05b8SZbigniew Bodek 
23979b8d05b8SZbigniew Bodek static int
23989b8d05b8SZbigniew Bodek ena_setup_ifnet(device_t pdev, struct ena_adapter *adapter,
23999b8d05b8SZbigniew Bodek     struct ena_com_dev_get_features_ctx *feat)
24009b8d05b8SZbigniew Bodek {
24019b8d05b8SZbigniew Bodek 	if_t ifp;
24029b8d05b8SZbigniew Bodek 	int caps = 0;
24039b8d05b8SZbigniew Bodek 
24049b8d05b8SZbigniew Bodek 	ifp = adapter->ifp = if_gethandle(IFT_ETHER);
24053f9ed7abSMarcin Wojtas 	if (unlikely(ifp == NULL)) {
24069eb1615fSMarcin Wojtas 		ena_trace(NULL, ENA_ALERT, "can not allocate ifnet structure\n");
24079b8d05b8SZbigniew Bodek 		return (ENXIO);
24089b8d05b8SZbigniew Bodek 	}
24099b8d05b8SZbigniew Bodek 	if_initname(ifp, device_get_name(pdev), device_get_unit(pdev));
24109b8d05b8SZbigniew Bodek 	if_setdev(ifp, pdev);
24119b8d05b8SZbigniew Bodek 	if_setsoftc(ifp, adapter);
24129b8d05b8SZbigniew Bodek 
241392dc69a7SMarcin Wojtas 	if_setflags(ifp, IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST |
241492dc69a7SMarcin Wojtas 	    IFF_KNOWSEPOCH);
24159b8d05b8SZbigniew Bodek 	if_setinitfn(ifp, ena_init);
24169b8d05b8SZbigniew Bodek 	if_settransmitfn(ifp, ena_mq_start);
24179b8d05b8SZbigniew Bodek 	if_setqflushfn(ifp, ena_qflush);
24189b8d05b8SZbigniew Bodek 	if_setioctlfn(ifp, ena_ioctl);
24199b8d05b8SZbigniew Bodek 	if_setgetcounterfn(ifp, ena_get_counter);
24209b8d05b8SZbigniew Bodek 
24219762a033SMarcin Wojtas 	if_setsendqlen(ifp, adapter->requested_tx_ring_size);
24229b8d05b8SZbigniew Bodek 	if_setsendqready(ifp);
24239b8d05b8SZbigniew Bodek 	if_setmtu(ifp, ETHERMTU);
24249b8d05b8SZbigniew Bodek 	if_setbaudrate(ifp, 0);
24259b8d05b8SZbigniew Bodek 	/* Zeroize capabilities... */
24269b8d05b8SZbigniew Bodek 	if_setcapabilities(ifp, 0);
24279b8d05b8SZbigniew Bodek 	if_setcapenable(ifp, 0);
24289b8d05b8SZbigniew Bodek 	/* check hardware support */
24299b8d05b8SZbigniew Bodek 	caps = ena_get_dev_offloads(feat);
24309b8d05b8SZbigniew Bodek 	/* ... and set them */
24319b8d05b8SZbigniew Bodek 	if_setcapabilitiesbit(ifp, caps, 0);
24329b8d05b8SZbigniew Bodek 
24339b8d05b8SZbigniew Bodek 	/* TSO parameters */
24348a573700SZbigniew Bodek 	ifp->if_hw_tsomax = ENA_TSO_MAXSIZE -
24358a573700SZbigniew Bodek 	    (ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN);
24368a573700SZbigniew Bodek 	ifp->if_hw_tsomaxsegcount = adapter->max_tx_sgl_size - 1;
24378a573700SZbigniew Bodek 	ifp->if_hw_tsomaxsegsize = ENA_TSO_MAXSIZE;
24389b8d05b8SZbigniew Bodek 
24399b8d05b8SZbigniew Bodek 	if_setifheaderlen(ifp, sizeof(struct ether_vlan_header));
24409b8d05b8SZbigniew Bodek 	if_setcapenable(ifp, if_getcapabilities(ifp));
24419b8d05b8SZbigniew Bodek 
24429b8d05b8SZbigniew Bodek 	/*
24439b8d05b8SZbigniew Bodek 	 * Specify the media types supported by this adapter and register
24449b8d05b8SZbigniew Bodek 	 * callbacks to update media and link information
24459b8d05b8SZbigniew Bodek 	 */
24469b8d05b8SZbigniew Bodek 	ifmedia_init(&adapter->media, IFM_IMASK,
24479b8d05b8SZbigniew Bodek 	    ena_media_change, ena_media_status);
24489b8d05b8SZbigniew Bodek 	ifmedia_add(&adapter->media, IFM_ETHER | IFM_AUTO, 0, NULL);
24499b8d05b8SZbigniew Bodek 	ifmedia_set(&adapter->media, IFM_ETHER | IFM_AUTO);
24509b8d05b8SZbigniew Bodek 
24519b8d05b8SZbigniew Bodek 	ether_ifattach(ifp, adapter->mac_addr);
24529b8d05b8SZbigniew Bodek 
24539b8d05b8SZbigniew Bodek 	return (0);
24549b8d05b8SZbigniew Bodek }
24559b8d05b8SZbigniew Bodek 
245638c7b965SMarcin Wojtas void
24579b8d05b8SZbigniew Bodek ena_down(struct ena_adapter *adapter)
24589b8d05b8SZbigniew Bodek {
2459a195fab0SMarcin Wojtas 	int rc;
24609b8d05b8SZbigniew Bodek 
2461579d23aaSMarcin Wojtas 	if (!ENA_FLAG_ISSET(ENA_FLAG_DEV_UP, adapter))
2462579d23aaSMarcin Wojtas 		return;
2463579d23aaSMarcin Wojtas 
24649b8d05b8SZbigniew Bodek 	device_printf(adapter->pdev, "device is going DOWN\n");
24659b8d05b8SZbigniew Bodek 
24669b8d05b8SZbigniew Bodek 	callout_drain(&adapter->timer_service);
24679b8d05b8SZbigniew Bodek 
2468fd43fd2aSMarcin Wojtas 	ENA_FLAG_CLEAR_ATOMIC(ENA_FLAG_DEV_UP, adapter);
24699b8d05b8SZbigniew Bodek 	if_setdrvflagbits(adapter->ifp, IFF_DRV_OACTIVE,
24709b8d05b8SZbigniew Bodek 		IFF_DRV_RUNNING);
24719b8d05b8SZbigniew Bodek 
24729b8d05b8SZbigniew Bodek 	ena_free_io_irq(adapter);
24739b8d05b8SZbigniew Bodek 
2474fd43fd2aSMarcin Wojtas 	if (ENA_FLAG_ISSET(ENA_FLAG_TRIGGER_RESET, adapter)) {
2475a195fab0SMarcin Wojtas 		rc = ena_com_dev_reset(adapter->ena_dev,
2476a195fab0SMarcin Wojtas 			adapter->reset_reason);
24773f9ed7abSMarcin Wojtas 		if (unlikely(rc != 0))
2478a195fab0SMarcin Wojtas 			device_printf(adapter->pdev,
2479a195fab0SMarcin Wojtas 				"Device reset failed\n");
2480a195fab0SMarcin Wojtas 	}
2481a195fab0SMarcin Wojtas 
24829b8d05b8SZbigniew Bodek 	ena_destroy_all_io_queues(adapter);
24839b8d05b8SZbigniew Bodek 
24849b8d05b8SZbigniew Bodek 	ena_free_all_tx_bufs(adapter);
24859b8d05b8SZbigniew Bodek 	ena_free_all_rx_bufs(adapter);
24869b8d05b8SZbigniew Bodek 	ena_free_all_tx_resources(adapter);
24879b8d05b8SZbigniew Bodek 	ena_free_all_rx_resources(adapter);
24889b8d05b8SZbigniew Bodek 
24899b8d05b8SZbigniew Bodek 	counter_u64_add(adapter->dev_stats.interface_down, 1);
24909b8d05b8SZbigniew Bodek }
24919b8d05b8SZbigniew Bodek 
24927d8c4feeSMarcin Wojtas static uint32_t
24937d8c4feeSMarcin Wojtas ena_calc_max_io_queue_num(device_t pdev, struct ena_com_dev *ena_dev,
24949b8d05b8SZbigniew Bodek     struct ena_com_dev_get_features_ctx *get_feat_ctx)
24959b8d05b8SZbigniew Bodek {
24967d8c4feeSMarcin Wojtas 	uint32_t io_tx_sq_num, io_tx_cq_num, io_rx_num, max_num_io_queues;
24979b8d05b8SZbigniew Bodek 
24986064f289SMarcin Wojtas 	/* Regular queues capabilities */
24996064f289SMarcin Wojtas 	if (ena_dev->supported_features & BIT(ENA_ADMIN_MAX_QUEUES_EXT)) {
25006064f289SMarcin Wojtas 		struct ena_admin_queue_ext_feature_fields *max_queue_ext =
25016064f289SMarcin Wojtas 		    &get_feat_ctx->max_queue_ext.max_queue_ext;
25024fa9e02dSMarcin Wojtas 		io_rx_num = min_t(int, max_queue_ext->max_rx_sq_num,
25034fa9e02dSMarcin Wojtas 			max_queue_ext->max_rx_cq_num);
25046064f289SMarcin Wojtas 
25054fa9e02dSMarcin Wojtas 		io_tx_sq_num = max_queue_ext->max_tx_sq_num;
25064fa9e02dSMarcin Wojtas 		io_tx_cq_num = max_queue_ext->max_tx_cq_num;
25076064f289SMarcin Wojtas 	} else {
25086064f289SMarcin Wojtas 		struct ena_admin_queue_feature_desc *max_queues =
25096064f289SMarcin Wojtas 		    &get_feat_ctx->max_queues;
25104fa9e02dSMarcin Wojtas 		io_tx_sq_num = max_queues->max_sq_num;
25114fa9e02dSMarcin Wojtas 		io_tx_cq_num = max_queues->max_cq_num;
25124fa9e02dSMarcin Wojtas 		io_rx_num = min_t(int, io_tx_sq_num, io_tx_cq_num);
25136064f289SMarcin Wojtas 	}
25149b8d05b8SZbigniew Bodek 
25154fa9e02dSMarcin Wojtas 	/* In case of LLQ use the llq fields for the tx SQ/CQ */
25164fa9e02dSMarcin Wojtas 	if (ena_dev->tx_mem_queue_type == ENA_ADMIN_PLACEMENT_POLICY_DEV)
25174fa9e02dSMarcin Wojtas 		io_tx_sq_num = get_feat_ctx->llq.max_llq_num;
25184fa9e02dSMarcin Wojtas 
25197d8c4feeSMarcin Wojtas 	max_num_io_queues = min_t(uint32_t, mp_ncpus, ENA_MAX_NUM_IO_QUEUES);
25207d8c4feeSMarcin Wojtas 	max_num_io_queues = min_t(uint32_t, max_num_io_queues, io_rx_num);
25217d8c4feeSMarcin Wojtas 	max_num_io_queues = min_t(uint32_t, max_num_io_queues, io_tx_sq_num);
25227d8c4feeSMarcin Wojtas 	max_num_io_queues = min_t(uint32_t, max_num_io_queues, io_tx_cq_num);
25239b8d05b8SZbigniew Bodek 	/* 1 IRQ for for mgmnt and 1 IRQ for each TX/RX pair */
25247d8c4feeSMarcin Wojtas 	max_num_io_queues = min_t(uint32_t, max_num_io_queues,
25257d8c4feeSMarcin Wojtas 	    pci_msix_count(pdev) - 1);
25269b8d05b8SZbigniew Bodek 
25277d8c4feeSMarcin Wojtas 	return (max_num_io_queues);
25289b8d05b8SZbigniew Bodek }
25299b8d05b8SZbigniew Bodek 
25300bdffe59SMarcin Wojtas static int
25314fa9e02dSMarcin Wojtas ena_enable_wc(struct resource *res)
25324fa9e02dSMarcin Wojtas {
2533472d4784SMarcin Wojtas #if defined(__i386) || defined(__amd64) || defined(__aarch64__)
25344fa9e02dSMarcin Wojtas 	vm_offset_t va;
25354fa9e02dSMarcin Wojtas 	vm_size_t len;
25364fa9e02dSMarcin Wojtas 	int rc;
25374fa9e02dSMarcin Wojtas 
25384fa9e02dSMarcin Wojtas 	va = (vm_offset_t)rman_get_virtual(res);
25394fa9e02dSMarcin Wojtas 	len = rman_get_size(res);
25404fa9e02dSMarcin Wojtas 	/* Enable write combining */
2541472d4784SMarcin Wojtas 	rc = pmap_change_attr(va, len, VM_MEMATTR_WRITE_COMBINING);
25424fa9e02dSMarcin Wojtas 	if (unlikely(rc != 0)) {
25439eb1615fSMarcin Wojtas 		ena_trace(NULL, ENA_ALERT, "pmap_change_attr failed, %d\n", rc);
25444fa9e02dSMarcin Wojtas 		return (rc);
25454fa9e02dSMarcin Wojtas 	}
25464fa9e02dSMarcin Wojtas 
25474fa9e02dSMarcin Wojtas 	return (0);
25484fa9e02dSMarcin Wojtas #endif
25494fa9e02dSMarcin Wojtas 	return (EOPNOTSUPP);
25504fa9e02dSMarcin Wojtas }
25514fa9e02dSMarcin Wojtas 
25524fa9e02dSMarcin Wojtas static int
25534fa9e02dSMarcin Wojtas ena_set_queues_placement_policy(device_t pdev, struct ena_com_dev *ena_dev,
25544fa9e02dSMarcin Wojtas     struct ena_admin_feature_llq_desc *llq,
25554fa9e02dSMarcin Wojtas     struct ena_llq_configurations *llq_default_configurations)
25564fa9e02dSMarcin Wojtas {
25574fa9e02dSMarcin Wojtas 	struct ena_adapter *adapter = device_get_softc(pdev);
25584fa9e02dSMarcin Wojtas 	int rc, rid;
25594fa9e02dSMarcin Wojtas 	uint32_t llq_feature_mask;
25604fa9e02dSMarcin Wojtas 
25614fa9e02dSMarcin Wojtas 	llq_feature_mask = 1 << ENA_ADMIN_LLQ;
25624fa9e02dSMarcin Wojtas 	if (!(ena_dev->supported_features & llq_feature_mask)) {
25634fa9e02dSMarcin Wojtas 		device_printf(pdev,
25644fa9e02dSMarcin Wojtas 		    "LLQ is not supported. Fallback to host mode policy.\n");
25654fa9e02dSMarcin Wojtas 		ena_dev->tx_mem_queue_type = ENA_ADMIN_PLACEMENT_POLICY_HOST;
25664fa9e02dSMarcin Wojtas 		return (0);
25674fa9e02dSMarcin Wojtas 	}
25684fa9e02dSMarcin Wojtas 
25694fa9e02dSMarcin Wojtas 	rc = ena_com_config_dev_mode(ena_dev, llq, llq_default_configurations);
25704fa9e02dSMarcin Wojtas 	if (unlikely(rc != 0)) {
25714fa9e02dSMarcin Wojtas 		device_printf(pdev, "Failed to configure the device mode. "
25724fa9e02dSMarcin Wojtas 		    "Fallback to host mode policy.\n");
25734fa9e02dSMarcin Wojtas 		ena_dev->tx_mem_queue_type = ENA_ADMIN_PLACEMENT_POLICY_HOST;
25744fa9e02dSMarcin Wojtas 		return (0);
25754fa9e02dSMarcin Wojtas 	}
25764fa9e02dSMarcin Wojtas 
25774fa9e02dSMarcin Wojtas 	/* Nothing to config, exit */
25784fa9e02dSMarcin Wojtas 	if (ena_dev->tx_mem_queue_type == ENA_ADMIN_PLACEMENT_POLICY_HOST)
25794fa9e02dSMarcin Wojtas 		return (0);
25804fa9e02dSMarcin Wojtas 
25814fa9e02dSMarcin Wojtas 	/* Try to allocate resources for LLQ bar */
25824fa9e02dSMarcin Wojtas 	rid = PCIR_BAR(ENA_MEM_BAR);
25834fa9e02dSMarcin Wojtas 	adapter->memory = bus_alloc_resource_any(pdev, SYS_RES_MEMORY,
25844fa9e02dSMarcin Wojtas 	    &rid, RF_ACTIVE);
25854fa9e02dSMarcin Wojtas 	if (unlikely(adapter->memory == NULL)) {
25864fa9e02dSMarcin Wojtas 		device_printf(pdev, "unable to allocate LLQ bar resource. "
25874fa9e02dSMarcin Wojtas 		    "Fallback to host mode policy.\n");
25884fa9e02dSMarcin Wojtas 		ena_dev->tx_mem_queue_type = ENA_ADMIN_PLACEMENT_POLICY_HOST;
25894fa9e02dSMarcin Wojtas 		return (0);
25904fa9e02dSMarcin Wojtas 	}
25914fa9e02dSMarcin Wojtas 
25924fa9e02dSMarcin Wojtas 	/* Enable write combining for better LLQ performance */
25934fa9e02dSMarcin Wojtas 	rc = ena_enable_wc(adapter->memory);
25944fa9e02dSMarcin Wojtas 	if (unlikely(rc != 0)) {
25954fa9e02dSMarcin Wojtas 		device_printf(pdev, "failed to enable write combining.\n");
25964fa9e02dSMarcin Wojtas 		return (rc);
25974fa9e02dSMarcin Wojtas 	}
25984fa9e02dSMarcin Wojtas 
25994fa9e02dSMarcin Wojtas 	/*
26004fa9e02dSMarcin Wojtas 	 * Save virtual address of the device's memory region
26014fa9e02dSMarcin Wojtas 	 * for the ena_com layer.
26024fa9e02dSMarcin Wojtas 	 */
26034fa9e02dSMarcin Wojtas 	ena_dev->mem_bar = rman_get_virtual(adapter->memory);
26044fa9e02dSMarcin Wojtas 
26054fa9e02dSMarcin Wojtas 	return (0);
26064fa9e02dSMarcin Wojtas }
26074fa9e02dSMarcin Wojtas 
26084fa9e02dSMarcin Wojtas static inline
2609*beaadec9SMarcin Wojtas void set_default_llq_configurations(struct ena_llq_configurations *llq_config,
2610*beaadec9SMarcin Wojtas 	struct ena_admin_feature_llq_desc *llq)
26114fa9e02dSMarcin Wojtas {
2612*beaadec9SMarcin Wojtas 
26134fa9e02dSMarcin Wojtas 	llq_config->llq_header_location = ENA_ADMIN_INLINE_HEADER;
26144fa9e02dSMarcin Wojtas 	llq_config->llq_stride_ctrl = ENA_ADMIN_MULTIPLE_DESCS_PER_ENTRY;
26154fa9e02dSMarcin Wojtas 	llq_config->llq_num_decs_before_header =
26164fa9e02dSMarcin Wojtas 	    ENA_ADMIN_LLQ_NUM_DESCS_BEFORE_HEADER_2;
2617*beaadec9SMarcin Wojtas 	if ((llq->entry_size_ctrl_supported &
2618*beaadec9SMarcin Wojtas 	     ENA_ADMIN_LIST_ENTRY_SIZE_256B) != 0 &&
2619*beaadec9SMarcin Wojtas 	    ena_force_large_llq_header) {
2620*beaadec9SMarcin Wojtas 		llq_config->llq_ring_entry_size =
2621*beaadec9SMarcin Wojtas 		    ENA_ADMIN_LIST_ENTRY_SIZE_256B;
2622*beaadec9SMarcin Wojtas 		llq_config->llq_ring_entry_size_value = 256;
2623*beaadec9SMarcin Wojtas 	} else {
2624*beaadec9SMarcin Wojtas 		llq_config->llq_ring_entry_size =
2625*beaadec9SMarcin Wojtas 		    ENA_ADMIN_LIST_ENTRY_SIZE_128B;
26264fa9e02dSMarcin Wojtas 		llq_config->llq_ring_entry_size_value = 128;
26274fa9e02dSMarcin Wojtas 	}
2628*beaadec9SMarcin Wojtas }
26294fa9e02dSMarcin Wojtas 
26304fa9e02dSMarcin Wojtas static int
26317d8c4feeSMarcin Wojtas ena_calc_io_queue_size(struct ena_calc_queue_size_ctx *ctx)
26329b8d05b8SZbigniew Bodek {
26334fa9e02dSMarcin Wojtas 	struct ena_admin_feature_llq_desc *llq = &ctx->get_feat_ctx->llq;
26344fa9e02dSMarcin Wojtas 	struct ena_com_dev *ena_dev = ctx->ena_dev;
26356064f289SMarcin Wojtas 	uint32_t tx_queue_size = ENA_DEFAULT_RING_SIZE;
26367d8c4feeSMarcin Wojtas 	uint32_t rx_queue_size = ENA_DEFAULT_RING_SIZE;
26377d8c4feeSMarcin Wojtas 	uint32_t max_tx_queue_size;
26387d8c4feeSMarcin Wojtas 	uint32_t max_rx_queue_size;
26399b8d05b8SZbigniew Bodek 
26404fa9e02dSMarcin Wojtas 	if (ena_dev->supported_features & BIT(ENA_ADMIN_MAX_QUEUES_EXT)) {
26416064f289SMarcin Wojtas 		struct ena_admin_queue_ext_feature_fields *max_queue_ext =
26426064f289SMarcin Wojtas 		    &ctx->get_feat_ctx->max_queue_ext.max_queue_ext;
26437d8c4feeSMarcin Wojtas 		max_rx_queue_size = min_t(uint32_t,
26447d8c4feeSMarcin Wojtas 		    max_queue_ext->max_rx_cq_depth,
26456064f289SMarcin Wojtas 		    max_queue_ext->max_rx_sq_depth);
26467d8c4feeSMarcin Wojtas 		max_tx_queue_size = max_queue_ext->max_tx_cq_depth;
26474fa9e02dSMarcin Wojtas 
26484fa9e02dSMarcin Wojtas 		if (ena_dev->tx_mem_queue_type ==
26494fa9e02dSMarcin Wojtas 		    ENA_ADMIN_PLACEMENT_POLICY_DEV)
26507d8c4feeSMarcin Wojtas 			max_tx_queue_size = min_t(uint32_t, max_tx_queue_size,
26514fa9e02dSMarcin Wojtas 			    llq->max_llq_depth);
26524fa9e02dSMarcin Wojtas 		else
26537d8c4feeSMarcin Wojtas 			max_tx_queue_size = min_t(uint32_t, max_tx_queue_size,
26546064f289SMarcin Wojtas 			    max_queue_ext->max_tx_sq_depth);
26554fa9e02dSMarcin Wojtas 
26566064f289SMarcin Wojtas 		ctx->max_tx_sgl_size = min_t(uint16_t, ENA_PKT_MAX_BUFS,
26576064f289SMarcin Wojtas 		    max_queue_ext->max_per_packet_tx_descs);
26587d8c4feeSMarcin Wojtas 		ctx->max_rx_sgl_size = min_t(uint16_t, ENA_PKT_MAX_BUFS,
26597d8c4feeSMarcin Wojtas 		    max_queue_ext->max_per_packet_rx_descs);
26606064f289SMarcin Wojtas 	} else {
26616064f289SMarcin Wojtas 		struct ena_admin_queue_feature_desc *max_queues =
26626064f289SMarcin Wojtas 		    &ctx->get_feat_ctx->max_queues;
26637d8c4feeSMarcin Wojtas 		max_rx_queue_size = min_t(uint32_t,
26647d8c4feeSMarcin Wojtas 		    max_queues->max_cq_depth,
26656064f289SMarcin Wojtas 		    max_queues->max_sq_depth);
26667d8c4feeSMarcin Wojtas 		max_tx_queue_size = max_queues->max_cq_depth;
26674fa9e02dSMarcin Wojtas 
26684fa9e02dSMarcin Wojtas 		if (ena_dev->tx_mem_queue_type ==
26694fa9e02dSMarcin Wojtas 		    ENA_ADMIN_PLACEMENT_POLICY_DEV)
26707d8c4feeSMarcin Wojtas 			max_tx_queue_size = min_t(uint32_t, max_tx_queue_size,
26714fa9e02dSMarcin Wojtas 			    llq->max_llq_depth);
26724fa9e02dSMarcin Wojtas 		else
26737d8c4feeSMarcin Wojtas 			max_tx_queue_size = min_t(uint32_t, max_tx_queue_size,
26744fa9e02dSMarcin Wojtas 			    max_queues->max_sq_depth);
26754fa9e02dSMarcin Wojtas 
26766064f289SMarcin Wojtas 		ctx->max_tx_sgl_size = min_t(uint16_t, ENA_PKT_MAX_BUFS,
26777d8c4feeSMarcin Wojtas 		    max_queues->max_packet_tx_descs);
26787d8c4feeSMarcin Wojtas 		ctx->max_rx_sgl_size = min_t(uint16_t, ENA_PKT_MAX_BUFS,
26796064f289SMarcin Wojtas 		    max_queues->max_packet_rx_descs);
26806064f289SMarcin Wojtas 	}
26819b8d05b8SZbigniew Bodek 
26829b8d05b8SZbigniew Bodek 	/* round down to the nearest power of 2 */
26837d8c4feeSMarcin Wojtas 	max_tx_queue_size = 1 << (flsl(max_tx_queue_size) - 1);
26847d8c4feeSMarcin Wojtas 	max_rx_queue_size = 1 << (flsl(max_rx_queue_size) - 1);
26856064f289SMarcin Wojtas 
2686*beaadec9SMarcin Wojtas 	/*
2687*beaadec9SMarcin Wojtas 	 * When forcing large headers, we multiply the entry size by 2,
2688*beaadec9SMarcin Wojtas 	 * and therefore divide the queue size by 2, leaving the amount
2689*beaadec9SMarcin Wojtas 	 * of memory used by the queues unchanged.
2690*beaadec9SMarcin Wojtas 	 */
2691*beaadec9SMarcin Wojtas 	if (ena_force_large_llq_header) {
2692*beaadec9SMarcin Wojtas 		if ((llq->entry_size_ctrl_supported &
2693*beaadec9SMarcin Wojtas 		     ENA_ADMIN_LIST_ENTRY_SIZE_256B) != 0 &&
2694*beaadec9SMarcin Wojtas 		    ena_dev->tx_mem_queue_type ==
2695*beaadec9SMarcin Wojtas 		     ENA_ADMIN_PLACEMENT_POLICY_DEV) {
2696*beaadec9SMarcin Wojtas 			max_tx_queue_size /= 2;
2697*beaadec9SMarcin Wojtas 			device_printf(ctx->pdev,
2698*beaadec9SMarcin Wojtas 			    "Forcing large headers and decreasing maximum Tx queue size to %d\n",
2699*beaadec9SMarcin Wojtas 			    max_tx_queue_size);
2700*beaadec9SMarcin Wojtas 		} else {
2701*beaadec9SMarcin Wojtas 			device_printf(ctx->pdev,
2702*beaadec9SMarcin Wojtas 			    "Forcing large headers failed: LLQ is disabled or device does not support large headers\n");
2703*beaadec9SMarcin Wojtas 		}
2704*beaadec9SMarcin Wojtas 	}
2705*beaadec9SMarcin Wojtas 
27067d8c4feeSMarcin Wojtas 	tx_queue_size = clamp_val(tx_queue_size, ENA_MIN_RING_SIZE,
27077d8c4feeSMarcin Wojtas 	    max_tx_queue_size);
27087d8c4feeSMarcin Wojtas 	rx_queue_size = clamp_val(rx_queue_size, ENA_MIN_RING_SIZE,
27097d8c4feeSMarcin Wojtas 	    max_rx_queue_size);
27109b8d05b8SZbigniew Bodek 
27117d8c4feeSMarcin Wojtas 	tx_queue_size = 1 << (flsl(tx_queue_size) - 1);
27127d8c4feeSMarcin Wojtas 	rx_queue_size = 1 << (flsl(rx_queue_size) - 1);
27137d8c4feeSMarcin Wojtas 
27147d8c4feeSMarcin Wojtas 	ctx->max_tx_queue_size = max_tx_queue_size;
27157d8c4feeSMarcin Wojtas 	ctx->max_rx_queue_size = max_rx_queue_size;
27166064f289SMarcin Wojtas 	ctx->tx_queue_size = tx_queue_size;
27177d8c4feeSMarcin Wojtas 	ctx->rx_queue_size = rx_queue_size;
27186064f289SMarcin Wojtas 
27196064f289SMarcin Wojtas 	return (0);
27209b8d05b8SZbigniew Bodek }
27219b8d05b8SZbigniew Bodek 
27220bdffe59SMarcin Wojtas static int
27230bdffe59SMarcin Wojtas ena_rss_init_default(struct ena_adapter *adapter)
27249b8d05b8SZbigniew Bodek {
27259b8d05b8SZbigniew Bodek 	struct ena_com_dev *ena_dev = adapter->ena_dev;
27269b8d05b8SZbigniew Bodek 	device_t dev = adapter->pdev;
27279b8d05b8SZbigniew Bodek 	int qid, rc, i;
27289b8d05b8SZbigniew Bodek 
27299b8d05b8SZbigniew Bodek 	rc = ena_com_rss_init(ena_dev, ENA_RX_RSS_TABLE_LOG_SIZE);
27300bdffe59SMarcin Wojtas 	if (unlikely(rc != 0)) {
27314e8acd84SMarcin Wojtas 		device_printf(dev, "Cannot init indirect table\n");
27327d2544e6SMarcin Wojtas 		return (rc);
27339b8d05b8SZbigniew Bodek 	}
27349b8d05b8SZbigniew Bodek 
27359b8d05b8SZbigniew Bodek 	for (i = 0; i < ENA_RX_RSS_TABLE_SIZE; i++) {
27367d8c4feeSMarcin Wojtas 		qid = i % adapter->num_io_queues;
27379b8d05b8SZbigniew Bodek 		rc = ena_com_indirect_table_fill_entry(ena_dev, i,
27389b8d05b8SZbigniew Bodek 		    ENA_IO_RXQ_IDX(qid));
27390bdffe59SMarcin Wojtas 		if (unlikely((rc != 0) && (rc != EOPNOTSUPP))) {
27409b8d05b8SZbigniew Bodek 			device_printf(dev, "Cannot fill indirect table\n");
27417d2544e6SMarcin Wojtas 			goto err_rss_destroy;
27429b8d05b8SZbigniew Bodek 		}
27439b8d05b8SZbigniew Bodek 	}
27449b8d05b8SZbigniew Bodek 
2745b40dd828SAndriy Gapon #ifdef RSS
2746b40dd828SAndriy Gapon 	uint8_t rss_algo = rss_gethashalgo();
2747b40dd828SAndriy Gapon 	if (rss_algo == RSS_HASH_TOEPLITZ) {
2748b40dd828SAndriy Gapon 		uint8_t hash_key[RSS_KEYSIZE];
2749b40dd828SAndriy Gapon 
2750b40dd828SAndriy Gapon 		rss_getkey(hash_key);
2751b40dd828SAndriy Gapon 		rc = ena_com_fill_hash_function(ena_dev, ENA_ADMIN_TOEPLITZ,
2752b40dd828SAndriy Gapon 		    hash_key, RSS_KEYSIZE, 0xFFFFFFFF);
2753b40dd828SAndriy Gapon 	} else
2754b40dd828SAndriy Gapon #endif
27559b8d05b8SZbigniew Bodek 	rc = ena_com_fill_hash_function(ena_dev, ENA_ADMIN_CRC32, NULL,
27569b8d05b8SZbigniew Bodek 	    ENA_HASH_KEY_SIZE, 0xFFFFFFFF);
27570bdffe59SMarcin Wojtas 	if (unlikely((rc != 0) && (rc != EOPNOTSUPP))) {
27589b8d05b8SZbigniew Bodek 		device_printf(dev, "Cannot fill hash function\n");
27597d2544e6SMarcin Wojtas 		goto err_rss_destroy;
27609b8d05b8SZbigniew Bodek 	}
27619b8d05b8SZbigniew Bodek 
27629b8d05b8SZbigniew Bodek 	rc = ena_com_set_default_hash_ctrl(ena_dev);
27630bdffe59SMarcin Wojtas 	if (unlikely((rc != 0) && (rc != EOPNOTSUPP))) {
27649b8d05b8SZbigniew Bodek 		device_printf(dev, "Cannot fill hash control\n");
27657d2544e6SMarcin Wojtas 		goto err_rss_destroy;
27669b8d05b8SZbigniew Bodek 	}
27679b8d05b8SZbigniew Bodek 
27689b8d05b8SZbigniew Bodek 	return (0);
27699b8d05b8SZbigniew Bodek 
27707d2544e6SMarcin Wojtas err_rss_destroy:
27719b8d05b8SZbigniew Bodek 	ena_com_rss_destroy(ena_dev);
27729b8d05b8SZbigniew Bodek 	return (rc);
27739b8d05b8SZbigniew Bodek }
27749b8d05b8SZbigniew Bodek 
27759b8d05b8SZbigniew Bodek static void
27769b8d05b8SZbigniew Bodek ena_rss_init_default_deferred(void *arg)
27779b8d05b8SZbigniew Bodek {
27789b8d05b8SZbigniew Bodek 	struct ena_adapter *adapter;
27799b8d05b8SZbigniew Bodek 	devclass_t dc;
27809b8d05b8SZbigniew Bodek 	int max;
27819b8d05b8SZbigniew Bodek 	int rc;
27829b8d05b8SZbigniew Bodek 
27839b8d05b8SZbigniew Bodek 	dc = devclass_find("ena");
27843f9ed7abSMarcin Wojtas 	if (unlikely(dc == NULL)) {
27859eb1615fSMarcin Wojtas 		ena_trace(NULL, ENA_ALERT, "No devclass ena\n");
27869b8d05b8SZbigniew Bodek 		return;
27879b8d05b8SZbigniew Bodek 	}
27889b8d05b8SZbigniew Bodek 
27899b8d05b8SZbigniew Bodek 	max = devclass_get_maxunit(dc);
27909b8d05b8SZbigniew Bodek 	while (max-- >= 0) {
27919b8d05b8SZbigniew Bodek 		adapter = devclass_get_softc(dc, max);
27929b8d05b8SZbigniew Bodek 		if (adapter != NULL) {
27939b8d05b8SZbigniew Bodek 			rc = ena_rss_init_default(adapter);
2794fd43fd2aSMarcin Wojtas 			ENA_FLAG_SET_ATOMIC(ENA_FLAG_RSS_ACTIVE, adapter);
27953f9ed7abSMarcin Wojtas 			if (unlikely(rc != 0)) {
27969b8d05b8SZbigniew Bodek 				device_printf(adapter->pdev,
27979b8d05b8SZbigniew Bodek 				    "WARNING: RSS was not properly initialized,"
27980bdffe59SMarcin Wojtas 				    " it will affect bandwidth\n");
2799fd43fd2aSMarcin Wojtas 				ENA_FLAG_CLEAR_ATOMIC(ENA_FLAG_RSS_ACTIVE, adapter);
28009b8d05b8SZbigniew Bodek 			}
28019b8d05b8SZbigniew Bodek 		}
28029b8d05b8SZbigniew Bodek 	}
28039b8d05b8SZbigniew Bodek }
28049b8d05b8SZbigniew Bodek SYSINIT(ena_rss_init, SI_SUB_KICK_SCHEDULER, SI_ORDER_SECOND, ena_rss_init_default_deferred, NULL);
28059b8d05b8SZbigniew Bodek 
28060bdffe59SMarcin Wojtas static void
280746021271SMarcin Wojtas ena_config_host_info(struct ena_com_dev *ena_dev, device_t dev)
28089b8d05b8SZbigniew Bodek {
28099b8d05b8SZbigniew Bodek 	struct ena_admin_host_info *host_info;
281046021271SMarcin Wojtas 	uintptr_t rid;
28119b8d05b8SZbigniew Bodek 	int rc;
28129b8d05b8SZbigniew Bodek 
28139b8d05b8SZbigniew Bodek 	/* Allocate only the host info */
28149b8d05b8SZbigniew Bodek 	rc = ena_com_allocate_host_info(ena_dev);
28153f9ed7abSMarcin Wojtas 	if (unlikely(rc != 0)) {
28169eb1615fSMarcin Wojtas 		ena_trace(NULL, ENA_ALERT, "Cannot allocate host info\n");
28179b8d05b8SZbigniew Bodek 		return;
28189b8d05b8SZbigniew Bodek 	}
28199b8d05b8SZbigniew Bodek 
28209b8d05b8SZbigniew Bodek 	host_info = ena_dev->host_attr.host_info;
28219b8d05b8SZbigniew Bodek 
282246021271SMarcin Wojtas 	if (pci_get_id(dev, PCI_ID_RID, &rid) == 0)
282346021271SMarcin Wojtas 		host_info->bdf = rid;
28249b8d05b8SZbigniew Bodek 	host_info->os_type = ENA_ADMIN_OS_FREEBSD;
28259b8d05b8SZbigniew Bodek 	host_info->kernel_ver = osreldate;
28269b8d05b8SZbigniew Bodek 
28279b8d05b8SZbigniew Bodek 	sprintf(host_info->kernel_ver_str, "%d", osreldate);
28289b8d05b8SZbigniew Bodek 	host_info->os_dist = 0;
28299b8d05b8SZbigniew Bodek 	strncpy(host_info->os_dist_str, osrelease,
28309b8d05b8SZbigniew Bodek 	    sizeof(host_info->os_dist_str) - 1);
28319b8d05b8SZbigniew Bodek 
28329b8d05b8SZbigniew Bodek 	host_info->driver_version =
28339b8d05b8SZbigniew Bodek 		(DRV_MODULE_VER_MAJOR) |
28349b8d05b8SZbigniew Bodek 		(DRV_MODULE_VER_MINOR << ENA_ADMIN_HOST_INFO_MINOR_SHIFT) |
28359b8d05b8SZbigniew Bodek 		(DRV_MODULE_VER_SUBMINOR << ENA_ADMIN_HOST_INFO_SUB_MINOR_SHIFT);
28368ece6b25SMarcin Wojtas 	host_info->num_cpus = mp_ncpus;
2837c7444389SMarcin Wojtas 	host_info->driver_supported_features =
2838c7444389SMarcin Wojtas 	    ENA_ADMIN_HOST_INFO_RX_OFFSET_MASK;
28399b8d05b8SZbigniew Bodek 
28409b8d05b8SZbigniew Bodek 	rc = ena_com_set_host_attributes(ena_dev);
28413f9ed7abSMarcin Wojtas 	if (unlikely(rc != 0)) {
2842a195fab0SMarcin Wojtas 		if (rc == EOPNOTSUPP)
28439eb1615fSMarcin Wojtas 			ena_trace(NULL, ENA_WARNING, "Cannot set host attributes\n");
28449b8d05b8SZbigniew Bodek 		else
28459eb1615fSMarcin Wojtas 			ena_trace(NULL, ENA_ALERT, "Cannot set host attributes\n");
28469b8d05b8SZbigniew Bodek 
28479b8d05b8SZbigniew Bodek 		goto err;
28489b8d05b8SZbigniew Bodek 	}
28499b8d05b8SZbigniew Bodek 
28509b8d05b8SZbigniew Bodek 	return;
28519b8d05b8SZbigniew Bodek 
28529b8d05b8SZbigniew Bodek err:
28539b8d05b8SZbigniew Bodek 	ena_com_delete_host_info(ena_dev);
28549b8d05b8SZbigniew Bodek }
28559b8d05b8SZbigniew Bodek 
28569b8d05b8SZbigniew Bodek static int
28579b8d05b8SZbigniew Bodek ena_device_init(struct ena_adapter *adapter, device_t pdev,
28589b8d05b8SZbigniew Bodek     struct ena_com_dev_get_features_ctx *get_feat_ctx, int *wd_active)
28599b8d05b8SZbigniew Bodek {
28609b8d05b8SZbigniew Bodek 	struct ena_com_dev* ena_dev = adapter->ena_dev;
28619b8d05b8SZbigniew Bodek 	bool readless_supported;
28629b8d05b8SZbigniew Bodek 	uint32_t aenq_groups;
28639b8d05b8SZbigniew Bodek 	int dma_width;
28649b8d05b8SZbigniew Bodek 	int rc;
28659b8d05b8SZbigniew Bodek 
28669b8d05b8SZbigniew Bodek 	rc = ena_com_mmio_reg_read_request_init(ena_dev);
28673f9ed7abSMarcin Wojtas 	if (unlikely(rc != 0)) {
28689b8d05b8SZbigniew Bodek 		device_printf(pdev, "failed to init mmio read less\n");
28690bdffe59SMarcin Wojtas 		return (rc);
28709b8d05b8SZbigniew Bodek 	}
28719b8d05b8SZbigniew Bodek 
28729b8d05b8SZbigniew Bodek 	/*
28739b8d05b8SZbigniew Bodek 	 * The PCIe configuration space revision id indicate if mmio reg
28749b8d05b8SZbigniew Bodek 	 * read is disabled
28759b8d05b8SZbigniew Bodek 	 */
28769b8d05b8SZbigniew Bodek 	readless_supported = !(pci_get_revid(pdev) & ENA_MMIO_DISABLE_REG_READ);
28779b8d05b8SZbigniew Bodek 	ena_com_set_mmio_read_mode(ena_dev, readless_supported);
28789b8d05b8SZbigniew Bodek 
2879a195fab0SMarcin Wojtas 	rc = ena_com_dev_reset(ena_dev, ENA_REGS_RESET_NORMAL);
28803f9ed7abSMarcin Wojtas 	if (unlikely(rc != 0)) {
28819b8d05b8SZbigniew Bodek 		device_printf(pdev, "Can not reset device\n");
28829b8d05b8SZbigniew Bodek 		goto err_mmio_read_less;
28839b8d05b8SZbigniew Bodek 	}
28849b8d05b8SZbigniew Bodek 
28859b8d05b8SZbigniew Bodek 	rc = ena_com_validate_version(ena_dev);
28863f9ed7abSMarcin Wojtas 	if (unlikely(rc != 0)) {
28879b8d05b8SZbigniew Bodek 		device_printf(pdev, "device version is too low\n");
28889b8d05b8SZbigniew Bodek 		goto err_mmio_read_less;
28899b8d05b8SZbigniew Bodek 	}
28909b8d05b8SZbigniew Bodek 
28919b8d05b8SZbigniew Bodek 	dma_width = ena_com_get_dma_width(ena_dev);
28923f9ed7abSMarcin Wojtas 	if (unlikely(dma_width < 0)) {
28939b8d05b8SZbigniew Bodek 		device_printf(pdev, "Invalid dma width value %d", dma_width);
28949b8d05b8SZbigniew Bodek 		rc = dma_width;
28959b8d05b8SZbigniew Bodek 		goto err_mmio_read_less;
28969b8d05b8SZbigniew Bodek 	}
28979b8d05b8SZbigniew Bodek 	adapter->dma_width = dma_width;
28989b8d05b8SZbigniew Bodek 
28999b8d05b8SZbigniew Bodek 	/* ENA admin level init */
290067ec48bbSMarcin Wojtas 	rc = ena_com_admin_init(ena_dev, &aenq_handlers);
29013f9ed7abSMarcin Wojtas 	if (unlikely(rc != 0)) {
29029b8d05b8SZbigniew Bodek 		device_printf(pdev,
29039b8d05b8SZbigniew Bodek 		    "Can not initialize ena admin queue with device\n");
29049b8d05b8SZbigniew Bodek 		goto err_mmio_read_less;
29059b8d05b8SZbigniew Bodek 	}
29069b8d05b8SZbigniew Bodek 
29079b8d05b8SZbigniew Bodek 	/*
29089b8d05b8SZbigniew Bodek 	 * To enable the msix interrupts the driver needs to know the number
29099b8d05b8SZbigniew Bodek 	 * of queues. So the driver uses polling mode to retrieve this
29109b8d05b8SZbigniew Bodek 	 * information
29119b8d05b8SZbigniew Bodek 	 */
29129b8d05b8SZbigniew Bodek 	ena_com_set_admin_polling_mode(ena_dev, true);
29139b8d05b8SZbigniew Bodek 
291446021271SMarcin Wojtas 	ena_config_host_info(ena_dev, pdev);
29159b8d05b8SZbigniew Bodek 
29169b8d05b8SZbigniew Bodek 	/* Get Device Attributes */
29179b8d05b8SZbigniew Bodek 	rc = ena_com_get_dev_attr_feat(ena_dev, get_feat_ctx);
29183f9ed7abSMarcin Wojtas 	if (unlikely(rc != 0)) {
29199b8d05b8SZbigniew Bodek 		device_printf(pdev,
29209b8d05b8SZbigniew Bodek 		    "Cannot get attribute for ena device rc: %d\n", rc);
29219b8d05b8SZbigniew Bodek 		goto err_admin_init;
29229b8d05b8SZbigniew Bodek 	}
29239b8d05b8SZbigniew Bodek 
2924e6de9a83SMarcin Wojtas 	aenq_groups = BIT(ENA_ADMIN_LINK_CHANGE) |
2925e6de9a83SMarcin Wojtas 	    BIT(ENA_ADMIN_FATAL_ERROR) |
2926e6de9a83SMarcin Wojtas 	    BIT(ENA_ADMIN_WARNING) |
292740621d71SMarcin Wojtas 	    BIT(ENA_ADMIN_NOTIFICATION) |
2928e6de9a83SMarcin Wojtas 	    BIT(ENA_ADMIN_KEEP_ALIVE);
29299b8d05b8SZbigniew Bodek 
29309b8d05b8SZbigniew Bodek 	aenq_groups &= get_feat_ctx->aenq.supported_groups;
29319b8d05b8SZbigniew Bodek 	rc = ena_com_set_aenq_config(ena_dev, aenq_groups);
29323f9ed7abSMarcin Wojtas 	if (unlikely(rc != 0)) {
29339b8d05b8SZbigniew Bodek 		device_printf(pdev, "Cannot configure aenq groups rc: %d\n", rc);
29349b8d05b8SZbigniew Bodek 		goto err_admin_init;
29359b8d05b8SZbigniew Bodek 	}
29369b8d05b8SZbigniew Bodek 
29379b8d05b8SZbigniew Bodek 	*wd_active = !!(aenq_groups & BIT(ENA_ADMIN_KEEP_ALIVE));
29389b8d05b8SZbigniew Bodek 
29390bdffe59SMarcin Wojtas 	return (0);
29409b8d05b8SZbigniew Bodek 
29419b8d05b8SZbigniew Bodek err_admin_init:
29429b8d05b8SZbigniew Bodek 	ena_com_delete_host_info(ena_dev);
29439b8d05b8SZbigniew Bodek 	ena_com_admin_destroy(ena_dev);
29449b8d05b8SZbigniew Bodek err_mmio_read_less:
29459b8d05b8SZbigniew Bodek 	ena_com_mmio_reg_read_request_destroy(ena_dev);
29469b8d05b8SZbigniew Bodek 
29470bdffe59SMarcin Wojtas 	return (rc);
29489b8d05b8SZbigniew Bodek }
29499b8d05b8SZbigniew Bodek 
2950aa9c3226SMarcin Wojtas static int ena_enable_msix_and_set_admin_interrupts(struct ena_adapter *adapter)
29519b8d05b8SZbigniew Bodek {
29529b8d05b8SZbigniew Bodek 	struct ena_com_dev *ena_dev = adapter->ena_dev;
29539b8d05b8SZbigniew Bodek 	int rc;
29549b8d05b8SZbigniew Bodek 
29559b8d05b8SZbigniew Bodek 	rc = ena_enable_msix(adapter);
29563f9ed7abSMarcin Wojtas 	if (unlikely(rc != 0)) {
29579b8d05b8SZbigniew Bodek 		device_printf(adapter->pdev, "Error with MSI-X enablement\n");
29580bdffe59SMarcin Wojtas 		return (rc);
29599b8d05b8SZbigniew Bodek 	}
29609b8d05b8SZbigniew Bodek 
29619b8d05b8SZbigniew Bodek 	ena_setup_mgmnt_intr(adapter);
29629b8d05b8SZbigniew Bodek 
29639b8d05b8SZbigniew Bodek 	rc = ena_request_mgmnt_irq(adapter);
29643f9ed7abSMarcin Wojtas 	if (unlikely(rc != 0)) {
29659b8d05b8SZbigniew Bodek 		device_printf(adapter->pdev, "Cannot setup mgmnt queue intr\n");
29669b8d05b8SZbigniew Bodek 		goto err_disable_msix;
29679b8d05b8SZbigniew Bodek 	}
29689b8d05b8SZbigniew Bodek 
29699b8d05b8SZbigniew Bodek 	ena_com_set_admin_polling_mode(ena_dev, false);
29709b8d05b8SZbigniew Bodek 
29719b8d05b8SZbigniew Bodek 	ena_com_admin_aenq_enable(ena_dev);
29729b8d05b8SZbigniew Bodek 
29730bdffe59SMarcin Wojtas 	return (0);
29749b8d05b8SZbigniew Bodek 
29759b8d05b8SZbigniew Bodek err_disable_msix:
29769b8d05b8SZbigniew Bodek 	ena_disable_msix(adapter);
29779b8d05b8SZbigniew Bodek 
29780bdffe59SMarcin Wojtas 	return (rc);
29799b8d05b8SZbigniew Bodek }
29809b8d05b8SZbigniew Bodek 
29819b8d05b8SZbigniew Bodek /* Function called on ENA_ADMIN_KEEP_ALIVE event */
29829b8d05b8SZbigniew Bodek static void ena_keep_alive_wd(void *adapter_data,
29839b8d05b8SZbigniew Bodek     struct ena_admin_aenq_entry *aenq_e)
29849b8d05b8SZbigniew Bodek {
29859b8d05b8SZbigniew Bodek 	struct ena_adapter *adapter = (struct ena_adapter *)adapter_data;
298630217e2dSMarcin Wojtas 	struct ena_admin_aenq_keep_alive_desc *desc;
29879b8d05b8SZbigniew Bodek 	sbintime_t stime;
298830217e2dSMarcin Wojtas 	uint64_t rx_drops;
29896c84cec3SMarcin Wojtas 	uint64_t tx_drops;
299030217e2dSMarcin Wojtas 
299130217e2dSMarcin Wojtas 	desc = (struct ena_admin_aenq_keep_alive_desc *)aenq_e;
299230217e2dSMarcin Wojtas 
299330217e2dSMarcin Wojtas 	rx_drops = ((uint64_t)desc->rx_drops_high << 32) | desc->rx_drops_low;
29946c84cec3SMarcin Wojtas 	tx_drops = ((uint64_t)desc->tx_drops_high << 32) | desc->tx_drops_low;
299530217e2dSMarcin Wojtas 	counter_u64_zero(adapter->hw_stats.rx_drops);
299630217e2dSMarcin Wojtas 	counter_u64_add(adapter->hw_stats.rx_drops, rx_drops);
29976c84cec3SMarcin Wojtas 	counter_u64_zero(adapter->hw_stats.tx_drops);
29986c84cec3SMarcin Wojtas 	counter_u64_add(adapter->hw_stats.tx_drops, tx_drops);
29999b8d05b8SZbigniew Bodek 
30009b8d05b8SZbigniew Bodek 	stime = getsbinuptime();
30019b8d05b8SZbigniew Bodek 	atomic_store_rel_64(&adapter->keep_alive_timestamp, stime);
30029b8d05b8SZbigniew Bodek }
30039b8d05b8SZbigniew Bodek 
30049b8d05b8SZbigniew Bodek /* Check for keep alive expiration */
30059b8d05b8SZbigniew Bodek static void check_for_missing_keep_alive(struct ena_adapter *adapter)
30069b8d05b8SZbigniew Bodek {
30079b8d05b8SZbigniew Bodek 	sbintime_t timestamp, time;
30089b8d05b8SZbigniew Bodek 
30099b8d05b8SZbigniew Bodek 	if (adapter->wd_active == 0)
30109b8d05b8SZbigniew Bodek 		return;
30119b8d05b8SZbigniew Bodek 
301240621d71SMarcin Wojtas 	if (adapter->keep_alive_timeout == ENA_HW_HINTS_NO_TIMEOUT)
30139b8d05b8SZbigniew Bodek 		return;
30149b8d05b8SZbigniew Bodek 
30159b8d05b8SZbigniew Bodek 	timestamp = atomic_load_acq_64(&adapter->keep_alive_timestamp);
30169b8d05b8SZbigniew Bodek 	time = getsbinuptime() - timestamp;
30179b8d05b8SZbigniew Bodek 	if (unlikely(time > adapter->keep_alive_timeout)) {
30189b8d05b8SZbigniew Bodek 		device_printf(adapter->pdev,
30199b8d05b8SZbigniew Bodek 		    "Keep alive watchdog timeout.\n");
30209b8d05b8SZbigniew Bodek 		counter_u64_add(adapter->dev_stats.wd_expired, 1);
30217926bc44SMarcin Wojtas 		ena_trigger_reset(adapter, ENA_REGS_RESET_KEEP_ALIVE_TO);
30229b8d05b8SZbigniew Bodek 	}
3023858659f7SMarcin Wojtas }
30249b8d05b8SZbigniew Bodek 
30259b8d05b8SZbigniew Bodek /* Check if admin queue is enabled */
30269b8d05b8SZbigniew Bodek static void check_for_admin_com_state(struct ena_adapter *adapter)
30279b8d05b8SZbigniew Bodek {
30280bdffe59SMarcin Wojtas 	if (unlikely(ena_com_get_admin_running_state(adapter->ena_dev) ==
30290bdffe59SMarcin Wojtas 	    false)) {
30309b8d05b8SZbigniew Bodek 		device_printf(adapter->pdev,
30319b8d05b8SZbigniew Bodek 		    "ENA admin queue is not in running state!\n");
30329b8d05b8SZbigniew Bodek 		counter_u64_add(adapter->dev_stats.admin_q_pause, 1);
30337926bc44SMarcin Wojtas 		ena_trigger_reset(adapter, ENA_REGS_RESET_ADMIN_TO);
30349b8d05b8SZbigniew Bodek 	}
3035858659f7SMarcin Wojtas }
30369b8d05b8SZbigniew Bodek 
303774dba3adSMarcin Wojtas static int
3038d12f7bfcSMarcin Wojtas check_for_rx_interrupt_queue(struct ena_adapter *adapter,
3039d12f7bfcSMarcin Wojtas     struct ena_ring *rx_ring)
3040d12f7bfcSMarcin Wojtas {
3041d12f7bfcSMarcin Wojtas 	if (likely(rx_ring->first_interrupt))
3042d12f7bfcSMarcin Wojtas 		return (0);
3043d12f7bfcSMarcin Wojtas 
3044d12f7bfcSMarcin Wojtas 	if (ena_com_cq_empty(rx_ring->ena_com_io_cq))
3045d12f7bfcSMarcin Wojtas 		return (0);
3046d12f7bfcSMarcin Wojtas 
3047d12f7bfcSMarcin Wojtas 	rx_ring->no_interrupt_event_cnt++;
3048d12f7bfcSMarcin Wojtas 
3049d12f7bfcSMarcin Wojtas 	if (rx_ring->no_interrupt_event_cnt == ENA_MAX_NO_INTERRUPT_ITERATIONS) {
3050d12f7bfcSMarcin Wojtas 		device_printf(adapter->pdev, "Potential MSIX issue on Rx side "
3051d12f7bfcSMarcin Wojtas 		    "Queue = %d. Reset the device\n", rx_ring->qid);
30527926bc44SMarcin Wojtas 		ena_trigger_reset(adapter, ENA_REGS_RESET_MISS_INTERRUPT);
3053d12f7bfcSMarcin Wojtas 		return (EIO);
3054d12f7bfcSMarcin Wojtas 	}
3055d12f7bfcSMarcin Wojtas 
3056d12f7bfcSMarcin Wojtas 	return (0);
3057d12f7bfcSMarcin Wojtas }
3058d12f7bfcSMarcin Wojtas 
3059d12f7bfcSMarcin Wojtas static int
3060d12f7bfcSMarcin Wojtas check_missing_comp_in_tx_queue(struct ena_adapter *adapter,
306174dba3adSMarcin Wojtas     struct ena_ring *tx_ring)
306274dba3adSMarcin Wojtas {
306374dba3adSMarcin Wojtas 	struct bintime curtime, time;
306474dba3adSMarcin Wojtas 	struct ena_tx_buffer *tx_buf;
3065d12f7bfcSMarcin Wojtas 	sbintime_t time_offset;
306674dba3adSMarcin Wojtas 	uint32_t missed_tx = 0;
3067d12f7bfcSMarcin Wojtas 	int i, rc = 0;
306874dba3adSMarcin Wojtas 
306974dba3adSMarcin Wojtas 	getbinuptime(&curtime);
307074dba3adSMarcin Wojtas 
307174dba3adSMarcin Wojtas 	for (i = 0; i < tx_ring->ring_size; i++) {
307274dba3adSMarcin Wojtas 		tx_buf = &tx_ring->tx_buffer_info[i];
307374dba3adSMarcin Wojtas 
30740bdffe59SMarcin Wojtas 		if (bintime_isset(&tx_buf->timestamp) == 0)
307574dba3adSMarcin Wojtas 			continue;
307674dba3adSMarcin Wojtas 
307774dba3adSMarcin Wojtas 		time = curtime;
307874dba3adSMarcin Wojtas 		bintime_sub(&time, &tx_buf->timestamp);
3079d12f7bfcSMarcin Wojtas 		time_offset = bttosbt(time);
3080d12f7bfcSMarcin Wojtas 
3081d12f7bfcSMarcin Wojtas 		if (unlikely(!tx_ring->first_interrupt &&
3082d12f7bfcSMarcin Wojtas 		    time_offset > 2 * adapter->missing_tx_timeout)) {
3083d12f7bfcSMarcin Wojtas 			/*
3084d12f7bfcSMarcin Wojtas 			 * If after graceful period interrupt is still not
3085d12f7bfcSMarcin Wojtas 			 * received, we schedule a reset.
3086d12f7bfcSMarcin Wojtas 			 */
3087d12f7bfcSMarcin Wojtas 			device_printf(adapter->pdev,
3088d12f7bfcSMarcin Wojtas 			    "Potential MSIX issue on Tx side Queue = %d. "
3089d12f7bfcSMarcin Wojtas 			    "Reset the device\n", tx_ring->qid);
30907926bc44SMarcin Wojtas 			ena_trigger_reset(adapter,
30917926bc44SMarcin Wojtas 			    ENA_REGS_RESET_MISS_INTERRUPT);
3092d12f7bfcSMarcin Wojtas 			return (EIO);
3093d12f7bfcSMarcin Wojtas 		}
309474dba3adSMarcin Wojtas 
309574dba3adSMarcin Wojtas 		/* Check again if packet is still waiting */
3096d12f7bfcSMarcin Wojtas 		if (unlikely(time_offset > adapter->missing_tx_timeout)) {
309774dba3adSMarcin Wojtas 
309874dba3adSMarcin Wojtas 			if (!tx_buf->print_once)
30999eb1615fSMarcin Wojtas 				ena_trace(NULL, ENA_WARNING, "Found a Tx that wasn't "
310074dba3adSMarcin Wojtas 				    "completed on time, qid %d, index %d.\n",
310174dba3adSMarcin Wojtas 				    tx_ring->qid, i);
310274dba3adSMarcin Wojtas 
310374dba3adSMarcin Wojtas 			tx_buf->print_once = true;
310474dba3adSMarcin Wojtas 			missed_tx++;
3105d12f7bfcSMarcin Wojtas 		}
3106d12f7bfcSMarcin Wojtas 	}
310774dba3adSMarcin Wojtas 
3108d12f7bfcSMarcin Wojtas 	if (unlikely(missed_tx > adapter->missing_tx_threshold)) {
310974dba3adSMarcin Wojtas 		device_printf(adapter->pdev,
3110d12f7bfcSMarcin Wojtas 		    "The number of lost tx completion is above the threshold "
3111d12f7bfcSMarcin Wojtas 		    "(%d > %d). Reset the device\n",
31124e8acd84SMarcin Wojtas 		    missed_tx, adapter->missing_tx_threshold);
31137926bc44SMarcin Wojtas 		ena_trigger_reset(adapter, ENA_REGS_RESET_MISS_TX_CMPL);
3114d12f7bfcSMarcin Wojtas 		rc = EIO;
311574dba3adSMarcin Wojtas 	}
311674dba3adSMarcin Wojtas 
3117d12f7bfcSMarcin Wojtas 	counter_u64_add(tx_ring->tx_stats.missing_tx_comp, missed_tx);
3118d12f7bfcSMarcin Wojtas 
3119d12f7bfcSMarcin Wojtas 	return (rc);
312074dba3adSMarcin Wojtas }
312174dba3adSMarcin Wojtas 
31229b8d05b8SZbigniew Bodek /*
31239b8d05b8SZbigniew Bodek  * Check for TX which were not completed on time.
31249b8d05b8SZbigniew Bodek  * Timeout is defined by "missing_tx_timeout".
31259b8d05b8SZbigniew Bodek  * Reset will be performed if number of incompleted
31269b8d05b8SZbigniew Bodek  * transactions exceeds "missing_tx_threshold".
31279b8d05b8SZbigniew Bodek  */
31280bdffe59SMarcin Wojtas static void
3129d12f7bfcSMarcin Wojtas check_for_missing_completions(struct ena_adapter *adapter)
31309b8d05b8SZbigniew Bodek {
31319b8d05b8SZbigniew Bodek 	struct ena_ring *tx_ring;
3132d12f7bfcSMarcin Wojtas 	struct ena_ring *rx_ring;
313374dba3adSMarcin Wojtas 	int i, budget, rc;
31349b8d05b8SZbigniew Bodek 
31359b8d05b8SZbigniew Bodek 	/* Make sure the driver doesn't turn the device in other process */
31369b8d05b8SZbigniew Bodek 	rmb();
31379b8d05b8SZbigniew Bodek 
3138fd43fd2aSMarcin Wojtas 	if (!ENA_FLAG_ISSET(ENA_FLAG_DEV_UP, adapter))
31399b8d05b8SZbigniew Bodek 		return;
31409b8d05b8SZbigniew Bodek 
3141fd43fd2aSMarcin Wojtas 	if (ENA_FLAG_ISSET(ENA_FLAG_TRIGGER_RESET, adapter))
31429b8d05b8SZbigniew Bodek 		return;
31439b8d05b8SZbigniew Bodek 
314440621d71SMarcin Wojtas 	if (adapter->missing_tx_timeout == ENA_HW_HINTS_NO_TIMEOUT)
31459b8d05b8SZbigniew Bodek 		return;
31469b8d05b8SZbigniew Bodek 
31479b8d05b8SZbigniew Bodek 	budget = adapter->missing_tx_max_queues;
31489b8d05b8SZbigniew Bodek 
31497d8c4feeSMarcin Wojtas 	for (i = adapter->next_monitored_tx_qid; i < adapter->num_io_queues; i++) {
31509b8d05b8SZbigniew Bodek 		tx_ring = &adapter->tx_ring[i];
3151d12f7bfcSMarcin Wojtas 		rx_ring = &adapter->rx_ring[i];
31529b8d05b8SZbigniew Bodek 
3153d12f7bfcSMarcin Wojtas 		rc = check_missing_comp_in_tx_queue(adapter, tx_ring);
3154d12f7bfcSMarcin Wojtas 		if (unlikely(rc != 0))
3155d12f7bfcSMarcin Wojtas 			return;
3156d12f7bfcSMarcin Wojtas 
3157d12f7bfcSMarcin Wojtas 		rc = check_for_rx_interrupt_queue(adapter, rx_ring);
31580bdffe59SMarcin Wojtas 		if (unlikely(rc != 0))
31599b8d05b8SZbigniew Bodek 			return;
31609b8d05b8SZbigniew Bodek 
31619b8d05b8SZbigniew Bodek 		budget--;
3162cd5d5804SMarcin Wojtas 		if (budget == 0) {
31639b8d05b8SZbigniew Bodek 			i++;
31649b8d05b8SZbigniew Bodek 			break;
31659b8d05b8SZbigniew Bodek 		}
31669b8d05b8SZbigniew Bodek 	}
31679b8d05b8SZbigniew Bodek 
31687d8c4feeSMarcin Wojtas 	adapter->next_monitored_tx_qid = i % adapter->num_io_queues;
31699b8d05b8SZbigniew Bodek }
31709b8d05b8SZbigniew Bodek 
31715cb9db07SMarcin Wojtas /* trigger rx cleanup after 2 consecutive detections */
3172efe6ab18SMarcin Wojtas #define EMPTY_RX_REFILL 2
3173efe6ab18SMarcin Wojtas /* For the rare case where the device runs out of Rx descriptors and the
3174efe6ab18SMarcin Wojtas  * msix handler failed to refill new Rx descriptors (due to a lack of memory
3175efe6ab18SMarcin Wojtas  * for example).
3176efe6ab18SMarcin Wojtas  * This case will lead to a deadlock:
3177efe6ab18SMarcin Wojtas  * The device won't send interrupts since all the new Rx packets will be dropped
3178efe6ab18SMarcin Wojtas  * The msix handler won't allocate new Rx descriptors so the device won't be
3179efe6ab18SMarcin Wojtas  * able to send new packets.
3180efe6ab18SMarcin Wojtas  *
3181efe6ab18SMarcin Wojtas  * When such a situation is detected - execute rx cleanup task in another thread
3182efe6ab18SMarcin Wojtas  */
3183efe6ab18SMarcin Wojtas static void
3184efe6ab18SMarcin Wojtas check_for_empty_rx_ring(struct ena_adapter *adapter)
3185efe6ab18SMarcin Wojtas {
3186efe6ab18SMarcin Wojtas 	struct ena_ring *rx_ring;
3187efe6ab18SMarcin Wojtas 	int i, refill_required;
3188efe6ab18SMarcin Wojtas 
3189fd43fd2aSMarcin Wojtas 	if (!ENA_FLAG_ISSET(ENA_FLAG_DEV_UP, adapter))
3190efe6ab18SMarcin Wojtas 		return;
3191efe6ab18SMarcin Wojtas 
3192fd43fd2aSMarcin Wojtas 	if (ENA_FLAG_ISSET(ENA_FLAG_TRIGGER_RESET, adapter))
3193efe6ab18SMarcin Wojtas 		return;
3194efe6ab18SMarcin Wojtas 
31957d8c4feeSMarcin Wojtas 	for (i = 0; i < adapter->num_io_queues; i++) {
3196efe6ab18SMarcin Wojtas 		rx_ring = &adapter->rx_ring[i];
3197efe6ab18SMarcin Wojtas 
31988483b844SMarcin Wojtas 		refill_required = ena_com_free_q_entries(rx_ring->ena_com_io_sq);
3199efe6ab18SMarcin Wojtas 		if (unlikely(refill_required == (rx_ring->ring_size - 1))) {
3200efe6ab18SMarcin Wojtas 			rx_ring->empty_rx_queue++;
3201efe6ab18SMarcin Wojtas 
3202efe6ab18SMarcin Wojtas 			if (rx_ring->empty_rx_queue >= EMPTY_RX_REFILL)	{
3203efe6ab18SMarcin Wojtas 				counter_u64_add(rx_ring->rx_stats.empty_rx_ring,
3204efe6ab18SMarcin Wojtas 				    1);
3205efe6ab18SMarcin Wojtas 
3206efe6ab18SMarcin Wojtas 				device_printf(adapter->pdev,
3207efe6ab18SMarcin Wojtas 				    "trigger refill for ring %d\n", i);
3208efe6ab18SMarcin Wojtas 
32095cb9db07SMarcin Wojtas 				taskqueue_enqueue(rx_ring->que->cleanup_tq,
32105cb9db07SMarcin Wojtas 				    &rx_ring->que->cleanup_task);
3211efe6ab18SMarcin Wojtas 				rx_ring->empty_rx_queue = 0;
3212efe6ab18SMarcin Wojtas 			}
3213efe6ab18SMarcin Wojtas 		} else {
3214efe6ab18SMarcin Wojtas 			rx_ring->empty_rx_queue = 0;
3215efe6ab18SMarcin Wojtas 		}
3216efe6ab18SMarcin Wojtas 	}
3217efe6ab18SMarcin Wojtas }
32189b8d05b8SZbigniew Bodek 
321940621d71SMarcin Wojtas static void ena_update_hints(struct ena_adapter *adapter,
322040621d71SMarcin Wojtas 			     struct ena_admin_ena_hw_hints *hints)
322140621d71SMarcin Wojtas {
322240621d71SMarcin Wojtas 	struct ena_com_dev *ena_dev = adapter->ena_dev;
322340621d71SMarcin Wojtas 
322440621d71SMarcin Wojtas 	if (hints->admin_completion_tx_timeout)
322540621d71SMarcin Wojtas 		ena_dev->admin_queue.completion_timeout =
322640621d71SMarcin Wojtas 		    hints->admin_completion_tx_timeout * 1000;
322740621d71SMarcin Wojtas 
322840621d71SMarcin Wojtas 	if (hints->mmio_read_timeout)
322940621d71SMarcin Wojtas 		/* convert to usec */
323040621d71SMarcin Wojtas 		ena_dev->mmio_read.reg_read_to =
323140621d71SMarcin Wojtas 		    hints->mmio_read_timeout * 1000;
323240621d71SMarcin Wojtas 
323340621d71SMarcin Wojtas 	if (hints->missed_tx_completion_count_threshold_to_reset)
323440621d71SMarcin Wojtas 		adapter->missing_tx_threshold =
323540621d71SMarcin Wojtas 		    hints->missed_tx_completion_count_threshold_to_reset;
323640621d71SMarcin Wojtas 
323740621d71SMarcin Wojtas 	if (hints->missing_tx_completion_timeout) {
323840621d71SMarcin Wojtas 		if (hints->missing_tx_completion_timeout ==
323940621d71SMarcin Wojtas 		     ENA_HW_HINTS_NO_TIMEOUT)
324040621d71SMarcin Wojtas 			adapter->missing_tx_timeout = ENA_HW_HINTS_NO_TIMEOUT;
324140621d71SMarcin Wojtas 		else
324240621d71SMarcin Wojtas 			adapter->missing_tx_timeout =
324340621d71SMarcin Wojtas 			    SBT_1MS * hints->missing_tx_completion_timeout;
324440621d71SMarcin Wojtas 	}
324540621d71SMarcin Wojtas 
324640621d71SMarcin Wojtas 	if (hints->driver_watchdog_timeout) {
324740621d71SMarcin Wojtas 		if (hints->driver_watchdog_timeout == ENA_HW_HINTS_NO_TIMEOUT)
324840621d71SMarcin Wojtas 			adapter->keep_alive_timeout = ENA_HW_HINTS_NO_TIMEOUT;
324940621d71SMarcin Wojtas 		else
325040621d71SMarcin Wojtas 			adapter->keep_alive_timeout =
325140621d71SMarcin Wojtas 			    SBT_1MS * hints->driver_watchdog_timeout;
325240621d71SMarcin Wojtas 	}
325340621d71SMarcin Wojtas }
325440621d71SMarcin Wojtas 
3255f180142cSMarcin Wojtas /**
3256f180142cSMarcin Wojtas  * ena_copy_eni_metrics - Get and copy ENI metrics from the HW.
3257f180142cSMarcin Wojtas  * @adapter: ENA device adapter
3258f180142cSMarcin Wojtas  *
3259f180142cSMarcin Wojtas  * Returns 0 on success, EOPNOTSUPP if current HW doesn't support those metrics
3260f180142cSMarcin Wojtas  * and other error codes on failure.
3261f180142cSMarcin Wojtas  *
3262f180142cSMarcin Wojtas  * This function can possibly cause a race with other calls to the admin queue.
3263f180142cSMarcin Wojtas  * Because of that, the caller should either lock this function or make sure
3264f180142cSMarcin Wojtas  * that there is no race in the current context.
3265f180142cSMarcin Wojtas  */
3266f180142cSMarcin Wojtas static int
3267f180142cSMarcin Wojtas ena_copy_eni_metrics(struct ena_adapter *adapter)
3268f180142cSMarcin Wojtas {
3269f180142cSMarcin Wojtas 	static bool print_once = true;
3270f180142cSMarcin Wojtas 	int rc;
3271f180142cSMarcin Wojtas 
3272f180142cSMarcin Wojtas 	rc = ena_com_get_eni_stats(adapter->ena_dev, &adapter->eni_metrics);
3273f180142cSMarcin Wojtas 
3274f180142cSMarcin Wojtas 	if (rc != 0) {
3275f180142cSMarcin Wojtas 		if (rc == ENA_COM_UNSUPPORTED) {
3276f180142cSMarcin Wojtas 			if (print_once) {
3277f180142cSMarcin Wojtas 				device_printf(adapter->pdev,
3278f180142cSMarcin Wojtas 				    "Retrieving ENI metrics is not supported.\n");
3279f180142cSMarcin Wojtas 				print_once = false;
3280f180142cSMarcin Wojtas 			} else {
3281f180142cSMarcin Wojtas 				ena_trace(NULL, ENA_DBG,
3282f180142cSMarcin Wojtas 				    "Retrieving ENI metrics is not supported.\n");
3283f180142cSMarcin Wojtas 			}
3284f180142cSMarcin Wojtas 		} else {
3285f180142cSMarcin Wojtas 			device_printf(adapter->pdev,
3286f180142cSMarcin Wojtas 			    "Failed to get ENI metrics: %d\n", rc);
3287f180142cSMarcin Wojtas 		}
3288f180142cSMarcin Wojtas 	}
3289f180142cSMarcin Wojtas 
3290f180142cSMarcin Wojtas 	return (rc);
3291f180142cSMarcin Wojtas }
3292f180142cSMarcin Wojtas 
32939b8d05b8SZbigniew Bodek static void
32949b8d05b8SZbigniew Bodek ena_timer_service(void *data)
32959b8d05b8SZbigniew Bodek {
32969b8d05b8SZbigniew Bodek 	struct ena_adapter *adapter = (struct ena_adapter *)data;
32979b8d05b8SZbigniew Bodek 	struct ena_admin_host_info *host_info =
32989b8d05b8SZbigniew Bodek 	    adapter->ena_dev->host_attr.host_info;
32999b8d05b8SZbigniew Bodek 
33009b8d05b8SZbigniew Bodek 	check_for_missing_keep_alive(adapter);
33019b8d05b8SZbigniew Bodek 
33029b8d05b8SZbigniew Bodek 	check_for_admin_com_state(adapter);
33039b8d05b8SZbigniew Bodek 
3304d12f7bfcSMarcin Wojtas 	check_for_missing_completions(adapter);
33059b8d05b8SZbigniew Bodek 
3306efe6ab18SMarcin Wojtas 	check_for_empty_rx_ring(adapter);
3307efe6ab18SMarcin Wojtas 
3308f180142cSMarcin Wojtas 	/*
3309f180142cSMarcin Wojtas 	 * User controller update of the ENI metrics.
3310f180142cSMarcin Wojtas 	 * If the delay was set to 0, then the stats shouldn't be updated at
3311f180142cSMarcin Wojtas 	 * all.
3312f180142cSMarcin Wojtas 	 * Otherwise, wait 'eni_metrics_sample_interval' seconds, before
3313f180142cSMarcin Wojtas 	 * updating stats.
3314f180142cSMarcin Wojtas 	 * As timer service is executed every second, it's enough to increment
3315f180142cSMarcin Wojtas 	 * appropriate counter each time the timer service is executed.
3316f180142cSMarcin Wojtas 	 */
3317f180142cSMarcin Wojtas 	if ((adapter->eni_metrics_sample_interval != 0) &&
3318f180142cSMarcin Wojtas 	    (++adapter->eni_metrics_sample_interval_cnt >=
3319f180142cSMarcin Wojtas 	     adapter->eni_metrics_sample_interval)) {
3320f180142cSMarcin Wojtas 		/*
3321f180142cSMarcin Wojtas 		 * There is no race with other admin queue calls, as:
3322f180142cSMarcin Wojtas 		 *   - Timer service runs after interface is up, so all
3323f180142cSMarcin Wojtas 		 *     configuration calls to the admin queue are finished.
3324f180142cSMarcin Wojtas 		 *   - After interface is up, the driver doesn't use (at least
3325f180142cSMarcin Wojtas 		 *     for now) other functions writing to the admin queue.
3326f180142cSMarcin Wojtas 		 *
3327f180142cSMarcin Wojtas 		 * It may change in the future, so in that situation, the lock
3328f180142cSMarcin Wojtas 		 * will be needed. ENA_LOCK_*() cannot be used for that purpose,
3329f180142cSMarcin Wojtas 		 * as callout ena_timer_service is protected by them. It could
3330f180142cSMarcin Wojtas 		 * lead to the deadlock if callout_drain() would hold the lock
3331f180142cSMarcin Wojtas 		 * before ena_copy_eni_metrics() was executed. It's advised to
3332f180142cSMarcin Wojtas 		 * use separate lock in that situation which will be used only
3333f180142cSMarcin Wojtas 		 * for the admin queue.
3334f180142cSMarcin Wojtas 		 */
3335f180142cSMarcin Wojtas 		(void)ena_copy_eni_metrics(adapter);
3336f180142cSMarcin Wojtas 		adapter->eni_metrics_sample_interval_cnt = 0;
3337f180142cSMarcin Wojtas 	}
3338f180142cSMarcin Wojtas 
3339f180142cSMarcin Wojtas 
33400bdffe59SMarcin Wojtas 	if (host_info != NULL)
33419b8d05b8SZbigniew Bodek 		ena_update_host_info(host_info, adapter->ifp);
33429b8d05b8SZbigniew Bodek 
3343fd43fd2aSMarcin Wojtas 	if (unlikely(ENA_FLAG_ISSET(ENA_FLAG_TRIGGER_RESET, adapter))) {
33449b8d05b8SZbigniew Bodek 		device_printf(adapter->pdev, "Trigger reset is on\n");
33459b8d05b8SZbigniew Bodek 		taskqueue_enqueue(adapter->reset_tq, &adapter->reset_task);
33469b8d05b8SZbigniew Bodek 		return;
33479b8d05b8SZbigniew Bodek 	}
33489b8d05b8SZbigniew Bodek 
33499b8d05b8SZbigniew Bodek 	/*
33509b8d05b8SZbigniew Bodek 	 * Schedule another timeout one second from now.
33519b8d05b8SZbigniew Bodek 	 */
33529b8d05b8SZbigniew Bodek 	callout_schedule_sbt(&adapter->timer_service, SBT_1S, SBT_1S, 0);
33539b8d05b8SZbigniew Bodek }
33549b8d05b8SZbigniew Bodek 
335538c7b965SMarcin Wojtas void
335632f63fa7SMarcin Wojtas ena_destroy_device(struct ena_adapter *adapter, bool graceful)
33579b8d05b8SZbigniew Bodek {
335832f63fa7SMarcin Wojtas 	if_t ifp = adapter->ifp;
33599b8d05b8SZbigniew Bodek 	struct ena_com_dev *ena_dev = adapter->ena_dev;
33609b8d05b8SZbigniew Bodek 	bool dev_up;
336132f63fa7SMarcin Wojtas 
336232f63fa7SMarcin Wojtas 	if (!ENA_FLAG_ISSET(ENA_FLAG_DEVICE_RUNNING, adapter))
336332f63fa7SMarcin Wojtas 		return;
336432f63fa7SMarcin Wojtas 
336532f63fa7SMarcin Wojtas 	if_link_state_change(ifp, LINK_STATE_DOWN);
336632f63fa7SMarcin Wojtas 
336732f63fa7SMarcin Wojtas 	callout_drain(&adapter->timer_service);
336832f63fa7SMarcin Wojtas 
336932f63fa7SMarcin Wojtas 	dev_up = ENA_FLAG_ISSET(ENA_FLAG_DEV_UP, adapter);
337032f63fa7SMarcin Wojtas 	if (dev_up)
337132f63fa7SMarcin Wojtas 		ENA_FLAG_SET_ATOMIC(ENA_FLAG_DEV_UP_BEFORE_RESET, adapter);
337232f63fa7SMarcin Wojtas 
337332f63fa7SMarcin Wojtas 	if (!graceful)
337432f63fa7SMarcin Wojtas 		ena_com_set_admin_running_state(ena_dev, false);
337532f63fa7SMarcin Wojtas 
337632f63fa7SMarcin Wojtas 	if (ENA_FLAG_ISSET(ENA_FLAG_DEV_UP, adapter))
337732f63fa7SMarcin Wojtas 		ena_down(adapter);
337832f63fa7SMarcin Wojtas 
337932f63fa7SMarcin Wojtas 	/*
338032f63fa7SMarcin Wojtas 	 * Stop the device from sending AENQ events (if the device was up, and
338132f63fa7SMarcin Wojtas 	 * the trigger reset was on, ena_down already performs device reset)
338232f63fa7SMarcin Wojtas 	 */
338332f63fa7SMarcin Wojtas 	if (!(ENA_FLAG_ISSET(ENA_FLAG_TRIGGER_RESET, adapter) && dev_up))
338432f63fa7SMarcin Wojtas 		ena_com_dev_reset(adapter->ena_dev, adapter->reset_reason);
338532f63fa7SMarcin Wojtas 
338632f63fa7SMarcin Wojtas 	ena_free_mgmnt_irq(adapter);
338732f63fa7SMarcin Wojtas 
338832f63fa7SMarcin Wojtas 	ena_disable_msix(adapter);
338932f63fa7SMarcin Wojtas 
3390e2735b09SMarcin Wojtas 	/*
3391e2735b09SMarcin Wojtas 	 * IO rings resources should be freed because `ena_restore_device()`
3392e2735b09SMarcin Wojtas 	 * calls (not directly) `ena_enable_msix()`, which re-allocates MSIX
3393e2735b09SMarcin Wojtas 	 * vectors. The amount of MSIX vectors after destroy-restore may be
3394e2735b09SMarcin Wojtas 	 * different than before. Therefore, IO rings resources should be
3395e2735b09SMarcin Wojtas 	 * established from scratch each time.
3396e2735b09SMarcin Wojtas 	 */
3397e2735b09SMarcin Wojtas 	ena_free_all_io_rings_resources(adapter);
3398e2735b09SMarcin Wojtas 
339932f63fa7SMarcin Wojtas 	ena_com_abort_admin_commands(ena_dev);
340032f63fa7SMarcin Wojtas 
340132f63fa7SMarcin Wojtas 	ena_com_wait_for_abort_completion(ena_dev);
340232f63fa7SMarcin Wojtas 
340332f63fa7SMarcin Wojtas 	ena_com_admin_destroy(ena_dev);
340432f63fa7SMarcin Wojtas 
340532f63fa7SMarcin Wojtas 	ena_com_mmio_reg_read_request_destroy(ena_dev);
340632f63fa7SMarcin Wojtas 
340732f63fa7SMarcin Wojtas 	adapter->reset_reason = ENA_REGS_RESET_NORMAL;
340832f63fa7SMarcin Wojtas 
340932f63fa7SMarcin Wojtas 	ENA_FLAG_CLEAR_ATOMIC(ENA_FLAG_TRIGGER_RESET, adapter);
341032f63fa7SMarcin Wojtas 	ENA_FLAG_CLEAR_ATOMIC(ENA_FLAG_DEVICE_RUNNING, adapter);
341132f63fa7SMarcin Wojtas }
341232f63fa7SMarcin Wojtas 
341332f63fa7SMarcin Wojtas static int
341432f63fa7SMarcin Wojtas ena_device_validate_params(struct ena_adapter *adapter,
341532f63fa7SMarcin Wojtas     struct ena_com_dev_get_features_ctx *get_feat_ctx)
341632f63fa7SMarcin Wojtas {
341732f63fa7SMarcin Wojtas 
341832f63fa7SMarcin Wojtas 	if (memcmp(get_feat_ctx->dev_attr.mac_addr, adapter->mac_addr,
341932f63fa7SMarcin Wojtas 	    ETHER_ADDR_LEN) != 0) {
342032f63fa7SMarcin Wojtas 		device_printf(adapter->pdev,
342132f63fa7SMarcin Wojtas 		    "Error, mac address are different\n");
342232f63fa7SMarcin Wojtas 		return (EINVAL);
342332f63fa7SMarcin Wojtas 	}
342432f63fa7SMarcin Wojtas 
342532f63fa7SMarcin Wojtas 	if (get_feat_ctx->dev_attr.max_mtu < if_getmtu(adapter->ifp)) {
342632f63fa7SMarcin Wojtas 		device_printf(adapter->pdev,
342732f63fa7SMarcin Wojtas 		    "Error, device max mtu is smaller than ifp MTU\n");
342832f63fa7SMarcin Wojtas 		return (EINVAL);
342932f63fa7SMarcin Wojtas 	}
343032f63fa7SMarcin Wojtas 
343132f63fa7SMarcin Wojtas 	return 0;
343232f63fa7SMarcin Wojtas }
343332f63fa7SMarcin Wojtas 
343438c7b965SMarcin Wojtas int
343532f63fa7SMarcin Wojtas ena_restore_device(struct ena_adapter *adapter)
343632f63fa7SMarcin Wojtas {
343732f63fa7SMarcin Wojtas 	struct ena_com_dev_get_features_ctx get_feat_ctx;
343832f63fa7SMarcin Wojtas 	struct ena_com_dev *ena_dev = adapter->ena_dev;
343932f63fa7SMarcin Wojtas 	if_t ifp = adapter->ifp;
344032f63fa7SMarcin Wojtas 	device_t dev = adapter->pdev;
344132f63fa7SMarcin Wojtas 	int wd_active;
34429b8d05b8SZbigniew Bodek 	int rc;
34439b8d05b8SZbigniew Bodek 
344432f63fa7SMarcin Wojtas 	ENA_FLAG_SET_ATOMIC(ENA_FLAG_ONGOING_RESET, adapter);
344532f63fa7SMarcin Wojtas 
344632f63fa7SMarcin Wojtas 	rc = ena_device_init(adapter, dev, &get_feat_ctx, &wd_active);
344732f63fa7SMarcin Wojtas 	if (rc != 0) {
344832f63fa7SMarcin Wojtas 		device_printf(dev, "Cannot initialize device\n");
344932f63fa7SMarcin Wojtas 		goto err;
345032f63fa7SMarcin Wojtas 	}
345132f63fa7SMarcin Wojtas 	/*
345232f63fa7SMarcin Wojtas 	 * Only enable WD if it was enabled before reset, so it won't override
345332f63fa7SMarcin Wojtas 	 * value set by the user by the sysctl.
345432f63fa7SMarcin Wojtas 	 */
345532f63fa7SMarcin Wojtas 	if (adapter->wd_active != 0)
345632f63fa7SMarcin Wojtas 		adapter->wd_active = wd_active;
345732f63fa7SMarcin Wojtas 
345832f63fa7SMarcin Wojtas 	rc = ena_device_validate_params(adapter, &get_feat_ctx);
345932f63fa7SMarcin Wojtas 	if (rc != 0) {
346032f63fa7SMarcin Wojtas 		device_printf(dev, "Validation of device parameters failed\n");
346132f63fa7SMarcin Wojtas 		goto err_device_destroy;
346232f63fa7SMarcin Wojtas 	}
346332f63fa7SMarcin Wojtas 
346432f63fa7SMarcin Wojtas 	ENA_FLAG_CLEAR_ATOMIC(ENA_FLAG_ONGOING_RESET, adapter);
346532f63fa7SMarcin Wojtas 	/* Make sure we don't have a race with AENQ Links state handler */
346632f63fa7SMarcin Wojtas 	if (ENA_FLAG_ISSET(ENA_FLAG_LINK_UP, adapter))
346732f63fa7SMarcin Wojtas 		if_link_state_change(ifp, LINK_STATE_UP);
346832f63fa7SMarcin Wojtas 
3469aa9c3226SMarcin Wojtas 	rc = ena_enable_msix_and_set_admin_interrupts(adapter);
347032f63fa7SMarcin Wojtas 	if (rc != 0) {
347132f63fa7SMarcin Wojtas 		device_printf(dev, "Enable MSI-X failed\n");
347232f63fa7SMarcin Wojtas 		goto err_device_destroy;
347332f63fa7SMarcin Wojtas 	}
347432f63fa7SMarcin Wojtas 
3475e2735b09SMarcin Wojtas 	/*
3476e2735b09SMarcin Wojtas 	 * Effective value of used MSIX vectors should be the same as before
3477e2735b09SMarcin Wojtas 	 * `ena_destroy_device()`, if possible, or closest to it if less vectors
3478e2735b09SMarcin Wojtas 	 * are available.
3479e2735b09SMarcin Wojtas 	 */
3480e2735b09SMarcin Wojtas 	if ((adapter->msix_vecs - ENA_ADMIN_MSIX_VEC) < adapter->num_io_queues)
3481e2735b09SMarcin Wojtas 		adapter->num_io_queues =
3482e2735b09SMarcin Wojtas 		    adapter->msix_vecs - ENA_ADMIN_MSIX_VEC;
3483e2735b09SMarcin Wojtas 
3484e2735b09SMarcin Wojtas 	/* Re-initialize rings basic information */
3485e2735b09SMarcin Wojtas 	ena_init_io_rings(adapter);
3486e2735b09SMarcin Wojtas 
348732f63fa7SMarcin Wojtas 	/* If the interface was up before the reset bring it up */
348832f63fa7SMarcin Wojtas 	if (ENA_FLAG_ISSET(ENA_FLAG_DEV_UP_BEFORE_RESET, adapter)) {
348932f63fa7SMarcin Wojtas 		rc = ena_up(adapter);
349032f63fa7SMarcin Wojtas 		if (rc != 0) {
349132f63fa7SMarcin Wojtas 			device_printf(dev, "Failed to create I/O queues\n");
349232f63fa7SMarcin Wojtas 			goto err_disable_msix;
349332f63fa7SMarcin Wojtas 		}
349432f63fa7SMarcin Wojtas 	}
349532f63fa7SMarcin Wojtas 
349624392281SMarcin Wojtas 	/* Indicate that device is running again and ready to work */
349732f63fa7SMarcin Wojtas 	ENA_FLAG_SET_ATOMIC(ENA_FLAG_DEVICE_RUNNING, adapter);
349824392281SMarcin Wojtas 
349924392281SMarcin Wojtas 	if (ENA_FLAG_ISSET(ENA_FLAG_DEV_UP_BEFORE_RESET, adapter)) {
350024392281SMarcin Wojtas 		/*
350124392281SMarcin Wojtas 		 * As the AENQ handlers weren't executed during reset because
350224392281SMarcin Wojtas 		 * the flag ENA_FLAG_DEVICE_RUNNING was turned off, the
350324392281SMarcin Wojtas 		 * timestamp must be updated again That will prevent next reset
350424392281SMarcin Wojtas 		 * caused by missing keep alive.
350524392281SMarcin Wojtas 		 */
350624392281SMarcin Wojtas 		adapter->keep_alive_timestamp = getsbinuptime();
350732f63fa7SMarcin Wojtas 		callout_reset_sbt(&adapter->timer_service, SBT_1S, SBT_1S,
350832f63fa7SMarcin Wojtas 		    ena_timer_service, (void *)adapter, 0);
350924392281SMarcin Wojtas 	}
35107d8c4feeSMarcin Wojtas 	ENA_FLAG_CLEAR_ATOMIC(ENA_FLAG_DEV_UP_BEFORE_RESET, adapter);
351132f63fa7SMarcin Wojtas 
351232f63fa7SMarcin Wojtas 	device_printf(dev,
351332f63fa7SMarcin Wojtas 	    "Device reset completed successfully, Driver info: %s\n", ena_version);
351432f63fa7SMarcin Wojtas 
351532f63fa7SMarcin Wojtas 	return (rc);
351632f63fa7SMarcin Wojtas 
351732f63fa7SMarcin Wojtas err_disable_msix:
351832f63fa7SMarcin Wojtas 	ena_free_mgmnt_irq(adapter);
351932f63fa7SMarcin Wojtas 	ena_disable_msix(adapter);
352032f63fa7SMarcin Wojtas err_device_destroy:
352132f63fa7SMarcin Wojtas 	ena_com_abort_admin_commands(ena_dev);
352232f63fa7SMarcin Wojtas 	ena_com_wait_for_abort_completion(ena_dev);
352332f63fa7SMarcin Wojtas 	ena_com_admin_destroy(ena_dev);
352432f63fa7SMarcin Wojtas 	ena_com_dev_reset(ena_dev, ENA_REGS_RESET_DRIVER_INVALID_STATE);
352532f63fa7SMarcin Wojtas 	ena_com_mmio_reg_read_request_destroy(ena_dev);
352632f63fa7SMarcin Wojtas err:
352732f63fa7SMarcin Wojtas 	ENA_FLAG_CLEAR_ATOMIC(ENA_FLAG_DEVICE_RUNNING, adapter);
352832f63fa7SMarcin Wojtas 	ENA_FLAG_CLEAR_ATOMIC(ENA_FLAG_ONGOING_RESET, adapter);
352932f63fa7SMarcin Wojtas 	device_printf(dev, "Reset attempt failed. Can not reset the device\n");
353032f63fa7SMarcin Wojtas 
353132f63fa7SMarcin Wojtas 	return (rc);
353232f63fa7SMarcin Wojtas }
353332f63fa7SMarcin Wojtas 
353432f63fa7SMarcin Wojtas static void
353532f63fa7SMarcin Wojtas ena_reset_task(void *arg, int pending)
353632f63fa7SMarcin Wojtas {
353732f63fa7SMarcin Wojtas 	struct ena_adapter *adapter = (struct ena_adapter *)arg;
353832f63fa7SMarcin Wojtas 
3539fd43fd2aSMarcin Wojtas 	if (unlikely(!ENA_FLAG_ISSET(ENA_FLAG_TRIGGER_RESET, adapter))) {
35409b8d05b8SZbigniew Bodek 		device_printf(adapter->pdev,
35419b8d05b8SZbigniew Bodek 		    "device reset scheduled but trigger_reset is off\n");
35429b8d05b8SZbigniew Bodek 		return;
35439b8d05b8SZbigniew Bodek 	}
35449b8d05b8SZbigniew Bodek 
35456959869eSMarcin Wojtas 	ENA_LOCK_LOCK(adapter);
354632f63fa7SMarcin Wojtas 	ena_destroy_device(adapter, false);
354732f63fa7SMarcin Wojtas 	ena_restore_device(adapter);
35486959869eSMarcin Wojtas 	ENA_LOCK_UNLOCK(adapter);
35499b8d05b8SZbigniew Bodek }
35509b8d05b8SZbigniew Bodek 
35519b8d05b8SZbigniew Bodek /**
35529b8d05b8SZbigniew Bodek  * ena_attach - Device Initialization Routine
35539b8d05b8SZbigniew Bodek  * @pdev: device information struct
35549b8d05b8SZbigniew Bodek  *
35559b8d05b8SZbigniew Bodek  * Returns 0 on success, otherwise on failure.
35569b8d05b8SZbigniew Bodek  *
35579b8d05b8SZbigniew Bodek  * ena_attach initializes an adapter identified by a device structure.
35589b8d05b8SZbigniew Bodek  * The OS initialization, configuring of the adapter private structure,
35599b8d05b8SZbigniew Bodek  * and a hardware reset occur.
35609b8d05b8SZbigniew Bodek  **/
35619b8d05b8SZbigniew Bodek static int
35629b8d05b8SZbigniew Bodek ena_attach(device_t pdev)
35639b8d05b8SZbigniew Bodek {
35649b8d05b8SZbigniew Bodek 	struct ena_com_dev_get_features_ctx get_feat_ctx;
35654fa9e02dSMarcin Wojtas 	struct ena_llq_configurations llq_config;
35666064f289SMarcin Wojtas 	struct ena_calc_queue_size_ctx calc_queue_ctx = { 0 };
35679b8d05b8SZbigniew Bodek 	static int version_printed;
35689b8d05b8SZbigniew Bodek 	struct ena_adapter *adapter;
35699b8d05b8SZbigniew Bodek 	struct ena_com_dev *ena_dev = NULL;
35707d8c4feeSMarcin Wojtas 	uint32_t max_num_io_queues;
35711c808fcdSMichal Krawczyk 	int msix_rid;
35724fa9e02dSMarcin Wojtas 	int rid, rc;
35734fa9e02dSMarcin Wojtas 
35749b8d05b8SZbigniew Bodek 	adapter = device_get_softc(pdev);
35759b8d05b8SZbigniew Bodek 	adapter->pdev = pdev;
35769b8d05b8SZbigniew Bodek 
35776959869eSMarcin Wojtas 	ENA_LOCK_INIT(adapter);
35789b8d05b8SZbigniew Bodek 
35796959869eSMarcin Wojtas 	/*
35806959869eSMarcin Wojtas 	 * Set up the timer service - driver is responsible for avoiding
35816959869eSMarcin Wojtas 	 * concurrency, as the callout won't be using any locking inside.
35826959869eSMarcin Wojtas 	 */
35836959869eSMarcin Wojtas 	callout_init(&adapter->timer_service, true);
35849b8d05b8SZbigniew Bodek 	adapter->keep_alive_timeout = DEFAULT_KEEP_ALIVE_TO;
35859b8d05b8SZbigniew Bodek 	adapter->missing_tx_timeout = DEFAULT_TX_CMP_TO;
35869b8d05b8SZbigniew Bodek 	adapter->missing_tx_max_queues = DEFAULT_TX_MONITORED_QUEUES;
35879b8d05b8SZbigniew Bodek 	adapter->missing_tx_threshold = DEFAULT_TX_CMP_THRESHOLD;
35889b8d05b8SZbigniew Bodek 
35899b8d05b8SZbigniew Bodek 	if (version_printed++ == 0)
35909b8d05b8SZbigniew Bodek 		device_printf(pdev, "%s\n", ena_version);
35919b8d05b8SZbigniew Bodek 
35929b8d05b8SZbigniew Bodek 	/* Allocate memory for ena_dev structure */
3593cd5d5804SMarcin Wojtas 	ena_dev = malloc(sizeof(struct ena_com_dev), M_DEVBUF,
3594cd5d5804SMarcin Wojtas 	    M_WAITOK | M_ZERO);
35959b8d05b8SZbigniew Bodek 
35969b8d05b8SZbigniew Bodek 	adapter->ena_dev = ena_dev;
35979b8d05b8SZbigniew Bodek 	ena_dev->dmadev = pdev;
35984fa9e02dSMarcin Wojtas 
35994fa9e02dSMarcin Wojtas 	rid = PCIR_BAR(ENA_REG_BAR);
36004fa9e02dSMarcin Wojtas 	adapter->memory = NULL;
36014fa9e02dSMarcin Wojtas 	adapter->registers = bus_alloc_resource_any(pdev, SYS_RES_MEMORY,
36024fa9e02dSMarcin Wojtas 	    &rid, RF_ACTIVE);
36034fa9e02dSMarcin Wojtas 	if (unlikely(adapter->registers == NULL)) {
36044fa9e02dSMarcin Wojtas 		device_printf(pdev,
36054fa9e02dSMarcin Wojtas 		    "unable to allocate bus resource: registers!\n");
36064fa9e02dSMarcin Wojtas 		rc = ENOMEM;
36074fa9e02dSMarcin Wojtas 		goto err_dev_free;
36084fa9e02dSMarcin Wojtas 	}
36094fa9e02dSMarcin Wojtas 
36101c808fcdSMichal Krawczyk 	/* MSIx vector table may reside on BAR0 with registers or on BAR1. */
36111c808fcdSMichal Krawczyk 	msix_rid = pci_msix_table_bar(pdev);
36121c808fcdSMichal Krawczyk 	if (msix_rid != rid) {
36131c808fcdSMichal Krawczyk 		adapter->msix = bus_alloc_resource_any(pdev, SYS_RES_MEMORY,
36141c808fcdSMichal Krawczyk 		    &msix_rid, RF_ACTIVE);
36151c808fcdSMichal Krawczyk 		if (unlikely(adapter->msix == NULL)) {
36161c808fcdSMichal Krawczyk 			device_printf(pdev,
36171c808fcdSMichal Krawczyk 			    "unable to allocate bus resource: msix!\n");
36181c808fcdSMichal Krawczyk 			rc = ENOMEM;
36191c808fcdSMichal Krawczyk 			goto err_pci_free;
36201c808fcdSMichal Krawczyk 		}
36211c808fcdSMichal Krawczyk 		adapter->msix_rid = msix_rid;
36221c808fcdSMichal Krawczyk 	}
36231c808fcdSMichal Krawczyk 
36249b8d05b8SZbigniew Bodek 	ena_dev->bus = malloc(sizeof(struct ena_bus), M_DEVBUF,
36259b8d05b8SZbigniew Bodek 	    M_WAITOK | M_ZERO);
36269b8d05b8SZbigniew Bodek 
36279b8d05b8SZbigniew Bodek 	/* Store register resources */
36289b8d05b8SZbigniew Bodek 	((struct ena_bus*)(ena_dev->bus))->reg_bar_t =
36299b8d05b8SZbigniew Bodek 	    rman_get_bustag(adapter->registers);
36309b8d05b8SZbigniew Bodek 	((struct ena_bus*)(ena_dev->bus))->reg_bar_h =
36319b8d05b8SZbigniew Bodek 	    rman_get_bushandle(adapter->registers);
36329b8d05b8SZbigniew Bodek 
36333f9ed7abSMarcin Wojtas 	if (unlikely(((struct ena_bus*)(ena_dev->bus))->reg_bar_h == 0)) {
36349b8d05b8SZbigniew Bodek 		device_printf(pdev, "failed to pmap registers bar\n");
36359b8d05b8SZbigniew Bodek 		rc = ENXIO;
3636cd5d5804SMarcin Wojtas 		goto err_bus_free;
36379b8d05b8SZbigniew Bodek 	}
36389b8d05b8SZbigniew Bodek 
36399b8d05b8SZbigniew Bodek 	ena_dev->tx_mem_queue_type = ENA_ADMIN_PLACEMENT_POLICY_HOST;
36409b8d05b8SZbigniew Bodek 
3641fd43fd2aSMarcin Wojtas 	/* Initially clear all the flags */
3642fd43fd2aSMarcin Wojtas 	ENA_FLAG_ZERO(adapter);
3643fd43fd2aSMarcin Wojtas 
36449b8d05b8SZbigniew Bodek 	/* Device initialization */
36459b8d05b8SZbigniew Bodek 	rc = ena_device_init(adapter, pdev, &get_feat_ctx, &adapter->wd_active);
36463f9ed7abSMarcin Wojtas 	if (unlikely(rc != 0)) {
36479b8d05b8SZbigniew Bodek 		device_printf(pdev, "ENA device init failed! (err: %d)\n", rc);
36489b8d05b8SZbigniew Bodek 		rc = ENXIO;
36499b8d05b8SZbigniew Bodek 		goto err_bus_free;
36509b8d05b8SZbigniew Bodek 	}
36519b8d05b8SZbigniew Bodek 
3652*beaadec9SMarcin Wojtas 	set_default_llq_configurations(&llq_config, &get_feat_ctx.llq);
36534fa9e02dSMarcin Wojtas 
36544fa9e02dSMarcin Wojtas 	rc = ena_set_queues_placement_policy(pdev, ena_dev, &get_feat_ctx.llq,
36554fa9e02dSMarcin Wojtas 	     &llq_config);
36564fa9e02dSMarcin Wojtas 	if (unlikely(rc != 0)) {
36574fa9e02dSMarcin Wojtas 		device_printf(pdev, "failed to set placement policy\n");
36584fa9e02dSMarcin Wojtas 		goto err_com_free;
36594fa9e02dSMarcin Wojtas 	}
36604fa9e02dSMarcin Wojtas 
36610b432b70SMarcin Wojtas 	if (ena_dev->tx_mem_queue_type == ENA_ADMIN_PLACEMENT_POLICY_DEV)
36620b432b70SMarcin Wojtas 		adapter->disable_meta_caching =
36630b432b70SMarcin Wojtas 		    !!(get_feat_ctx.llq.accel_mode.u.get.supported_flags &
36640b432b70SMarcin Wojtas 		    BIT(ENA_ADMIN_DISABLE_META_CACHING));
36650b432b70SMarcin Wojtas 
36669b8d05b8SZbigniew Bodek 	adapter->keep_alive_timestamp = getsbinuptime();
36679b8d05b8SZbigniew Bodek 
36689b8d05b8SZbigniew Bodek 	adapter->tx_offload_cap = get_feat_ctx.offload.tx;
36699b8d05b8SZbigniew Bodek 
36709b8d05b8SZbigniew Bodek 	memcpy(adapter->mac_addr, get_feat_ctx.dev_attr.mac_addr,
36719b8d05b8SZbigniew Bodek 	    ETHER_ADDR_LEN);
36729b8d05b8SZbigniew Bodek 
36737d8c4feeSMarcin Wojtas 	calc_queue_ctx.pdev = pdev;
36746064f289SMarcin Wojtas 	calc_queue_ctx.ena_dev = ena_dev;
36756064f289SMarcin Wojtas 	calc_queue_ctx.get_feat_ctx = &get_feat_ctx;
36766064f289SMarcin Wojtas 
36777d8c4feeSMarcin Wojtas 	/* Calculate initial and maximum IO queue number and size */
36787d8c4feeSMarcin Wojtas 	max_num_io_queues = ena_calc_max_io_queue_num(pdev, ena_dev,
36797d8c4feeSMarcin Wojtas 	    &get_feat_ctx);
36807d8c4feeSMarcin Wojtas 	rc = ena_calc_io_queue_size(&calc_queue_ctx);
36817d8c4feeSMarcin Wojtas 	if (unlikely((rc != 0) || (max_num_io_queues <= 0))) {
36826064f289SMarcin Wojtas 		rc = EFAULT;
36839b8d05b8SZbigniew Bodek 		goto err_com_free;
36849b8d05b8SZbigniew Bodek 	}
36859b8d05b8SZbigniew Bodek 
36869762a033SMarcin Wojtas 	adapter->requested_tx_ring_size = calc_queue_ctx.tx_queue_size;
36879762a033SMarcin Wojtas 	adapter->requested_rx_ring_size = calc_queue_ctx.rx_queue_size;
36887d8c4feeSMarcin Wojtas 	adapter->max_tx_ring_size = calc_queue_ctx.max_tx_queue_size;
36897d8c4feeSMarcin Wojtas 	adapter->max_rx_ring_size = calc_queue_ctx.max_rx_queue_size;
36906064f289SMarcin Wojtas 	adapter->max_tx_sgl_size = calc_queue_ctx.max_tx_sgl_size;
36916064f289SMarcin Wojtas 	adapter->max_rx_sgl_size = calc_queue_ctx.max_rx_sgl_size;
36926064f289SMarcin Wojtas 
36937d8c4feeSMarcin Wojtas 	adapter->max_num_io_queues = max_num_io_queues;
36947d8c4feeSMarcin Wojtas 
36956064f289SMarcin Wojtas 	adapter->buf_ring_size = ENA_DEFAULT_BUF_RING_SIZE;
36969b8d05b8SZbigniew Bodek 
36977d8c4feeSMarcin Wojtas 	adapter->max_mtu = get_feat_ctx.dev_attr.max_mtu;
36987d8c4feeSMarcin Wojtas 
36997d8c4feeSMarcin Wojtas 	adapter->reset_reason = ENA_REGS_RESET_NORMAL;
37007d8c4feeSMarcin Wojtas 
37019b8d05b8SZbigniew Bodek 	/* set up dma tags for rx and tx buffers */
37029b8d05b8SZbigniew Bodek 	rc = ena_setup_tx_dma_tag(adapter);
37034e8acd84SMarcin Wojtas 	if (unlikely(rc != 0)) {
37044e8acd84SMarcin Wojtas 		device_printf(pdev, "Failed to create TX DMA tag\n");
3705cd5d5804SMarcin Wojtas 		goto err_com_free;
37064e8acd84SMarcin Wojtas 	}
37079b8d05b8SZbigniew Bodek 
37089b8d05b8SZbigniew Bodek 	rc = ena_setup_rx_dma_tag(adapter);
37094e8acd84SMarcin Wojtas 	if (unlikely(rc != 0)) {
37104e8acd84SMarcin Wojtas 		device_printf(pdev, "Failed to create RX DMA tag\n");
3711cd5d5804SMarcin Wojtas 		goto err_tx_tag_free;
37124e8acd84SMarcin Wojtas 	}
37139b8d05b8SZbigniew Bodek 
3714e2735b09SMarcin Wojtas 	/*
3715e2735b09SMarcin Wojtas 	 * The amount of requested MSIX vectors is equal to
3716e2735b09SMarcin Wojtas 	 * adapter::max_num_io_queues (see `ena_enable_msix()`), plus a constant
3717e2735b09SMarcin Wojtas 	 * number of admin queue interrupts. The former is initially determined
3718e2735b09SMarcin Wojtas 	 * by HW capabilities (see `ena_calc_max_io_queue_num())` but may not be
3719e2735b09SMarcin Wojtas 	 * achieved if there are not enough system resources. By default, the
3720e2735b09SMarcin Wojtas 	 * number of effectively used IO queues is the same but later on it can
3721e2735b09SMarcin Wojtas 	 * be limited by the user using sysctl interface.
3722e2735b09SMarcin Wojtas 	 */
3723aa9c3226SMarcin Wojtas 	rc = ena_enable_msix_and_set_admin_interrupts(adapter);
37243f9ed7abSMarcin Wojtas 	if (unlikely(rc != 0)) {
37259b8d05b8SZbigniew Bodek 		device_printf(pdev,
37269b8d05b8SZbigniew Bodek 		    "Failed to enable and set the admin interrupts\n");
3727c115a1e2SMarcin Wojtas 		goto err_io_free;
3728c115a1e2SMarcin Wojtas 	}
3729e2735b09SMarcin Wojtas 	/* By default all of allocated MSIX vectors are actively used */
3730e2735b09SMarcin Wojtas 	adapter->num_io_queues = adapter->msix_vecs - ENA_ADMIN_MSIX_VEC;
3731e2735b09SMarcin Wojtas 
3732e2735b09SMarcin Wojtas 	/* initialize rings basic information */
3733e2735b09SMarcin Wojtas 	ena_init_io_rings(adapter);
3734c115a1e2SMarcin Wojtas 
3735c115a1e2SMarcin Wojtas 	/* setup network interface */
3736c115a1e2SMarcin Wojtas 	rc = ena_setup_ifnet(pdev, adapter, &get_feat_ctx);
3737c115a1e2SMarcin Wojtas 	if (unlikely(rc != 0)) {
3738c115a1e2SMarcin Wojtas 		device_printf(pdev, "Error with network interface setup\n");
3739c115a1e2SMarcin Wojtas 		goto err_msix_free;
37409b8d05b8SZbigniew Bodek 	}
37419b8d05b8SZbigniew Bodek 
3742081169f2SZbigniew Bodek 	/* Initialize reset task queue */
3743081169f2SZbigniew Bodek 	TASK_INIT(&adapter->reset_task, 0, ena_reset_task, adapter);
3744081169f2SZbigniew Bodek 	adapter->reset_tq = taskqueue_create("ena_reset_enqueue",
3745081169f2SZbigniew Bodek 	    M_WAITOK | M_ZERO, taskqueue_thread_enqueue, &adapter->reset_tq);
3746081169f2SZbigniew Bodek 	taskqueue_start_threads(&adapter->reset_tq, 1, PI_NET,
3747081169f2SZbigniew Bodek 	    "%s rstq", device_get_nameunit(adapter->pdev));
3748081169f2SZbigniew Bodek 
37499b8d05b8SZbigniew Bodek 	/* Initialize statistics */
37509b8d05b8SZbigniew Bodek 	ena_alloc_counters((counter_u64_t *)&adapter->dev_stats,
37519b8d05b8SZbigniew Bodek 	    sizeof(struct ena_stats_dev));
375230217e2dSMarcin Wojtas 	ena_alloc_counters((counter_u64_t *)&adapter->hw_stats,
375330217e2dSMarcin Wojtas 	    sizeof(struct ena_hw_stats));
37549b8d05b8SZbigniew Bodek 	ena_sysctl_add_nodes(adapter);
37559b8d05b8SZbigniew Bodek 
3756d17b7d87SMarcin Wojtas #ifdef DEV_NETMAP
3757d17b7d87SMarcin Wojtas 	rc = ena_netmap_attach(adapter);
3758d17b7d87SMarcin Wojtas 	if (rc != 0) {
3759d17b7d87SMarcin Wojtas 		device_printf(pdev, "netmap attach failed: %d\n", rc);
3760d17b7d87SMarcin Wojtas 		goto err_detach;
3761d17b7d87SMarcin Wojtas 	}
3762d17b7d87SMarcin Wojtas #endif /* DEV_NETMAP */
3763d17b7d87SMarcin Wojtas 
37649b8d05b8SZbigniew Bodek 	/* Tell the stack that the interface is not active */
37659b8d05b8SZbigniew Bodek 	if_setdrvflagbits(adapter->ifp, IFF_DRV_OACTIVE, IFF_DRV_RUNNING);
3766fd43fd2aSMarcin Wojtas 	ENA_FLAG_SET_ATOMIC(ENA_FLAG_DEVICE_RUNNING, adapter);
37679b8d05b8SZbigniew Bodek 
37689b8d05b8SZbigniew Bodek 	return (0);
37699b8d05b8SZbigniew Bodek 
3770d17b7d87SMarcin Wojtas #ifdef DEV_NETMAP
3771d17b7d87SMarcin Wojtas err_detach:
3772d17b7d87SMarcin Wojtas 	ether_ifdetach(adapter->ifp);
3773d17b7d87SMarcin Wojtas #endif /* DEV_NETMAP */
3774c115a1e2SMarcin Wojtas err_msix_free:
3775c115a1e2SMarcin Wojtas 	ena_com_dev_reset(adapter->ena_dev, ENA_REGS_RESET_INIT_ERR);
3776c115a1e2SMarcin Wojtas 	ena_free_mgmnt_irq(adapter);
3777c115a1e2SMarcin Wojtas 	ena_disable_msix(adapter);
3778cd5d5804SMarcin Wojtas err_io_free:
37799b8d05b8SZbigniew Bodek 	ena_free_all_io_rings_resources(adapter);
37809b8d05b8SZbigniew Bodek 	ena_free_rx_dma_tag(adapter);
3781cd5d5804SMarcin Wojtas err_tx_tag_free:
37829b8d05b8SZbigniew Bodek 	ena_free_tx_dma_tag(adapter);
3783cd5d5804SMarcin Wojtas err_com_free:
37849b8d05b8SZbigniew Bodek 	ena_com_admin_destroy(ena_dev);
37859b8d05b8SZbigniew Bodek 	ena_com_delete_host_info(ena_dev);
3786cd5d5804SMarcin Wojtas 	ena_com_mmio_reg_read_request_destroy(ena_dev);
37879b8d05b8SZbigniew Bodek err_bus_free:
37889b8d05b8SZbigniew Bodek 	free(ena_dev->bus, M_DEVBUF);
37891c808fcdSMichal Krawczyk err_pci_free:
37909b8d05b8SZbigniew Bodek 	ena_free_pci_resources(adapter);
37914fa9e02dSMarcin Wojtas err_dev_free:
37924fa9e02dSMarcin Wojtas 	free(ena_dev, M_DEVBUF);
3793cd5d5804SMarcin Wojtas 
37949b8d05b8SZbigniew Bodek 	return (rc);
37959b8d05b8SZbigniew Bodek }
37969b8d05b8SZbigniew Bodek 
37979b8d05b8SZbigniew Bodek /**
37989b8d05b8SZbigniew Bodek  * ena_detach - Device Removal Routine
37999b8d05b8SZbigniew Bodek  * @pdev: device information struct
38009b8d05b8SZbigniew Bodek  *
38019b8d05b8SZbigniew Bodek  * ena_detach is called by the device subsystem to alert the driver
38029b8d05b8SZbigniew Bodek  * that it should release a PCI device.
38039b8d05b8SZbigniew Bodek  **/
38049b8d05b8SZbigniew Bodek static int
38059b8d05b8SZbigniew Bodek ena_detach(device_t pdev)
38069b8d05b8SZbigniew Bodek {
38079b8d05b8SZbigniew Bodek 	struct ena_adapter *adapter = device_get_softc(pdev);
38089b8d05b8SZbigniew Bodek 	struct ena_com_dev *ena_dev = adapter->ena_dev;
38099b8d05b8SZbigniew Bodek 	int rc;
38109b8d05b8SZbigniew Bodek 
38119b8d05b8SZbigniew Bodek 	/* Make sure VLANS are not using driver */
38129b8d05b8SZbigniew Bodek 	if (adapter->ifp->if_vlantrunk != NULL) {
38139b8d05b8SZbigniew Bodek 		device_printf(adapter->pdev ,"VLAN is in use, detach first\n");
38149b8d05b8SZbigniew Bodek 		return (EBUSY);
38159b8d05b8SZbigniew Bodek 	}
38169b8d05b8SZbigniew Bodek 
38179151c55dSMarcin Wojtas 	ether_ifdetach(adapter->ifp);
38189151c55dSMarcin Wojtas 
38196959869eSMarcin Wojtas 	/* Stop timer service */
38206959869eSMarcin Wojtas 	ENA_LOCK_LOCK(adapter);
38219b8d05b8SZbigniew Bodek 	callout_drain(&adapter->timer_service);
38226959869eSMarcin Wojtas 	ENA_LOCK_UNLOCK(adapter);
38236959869eSMarcin Wojtas 
38246959869eSMarcin Wojtas 	/* Release reset task */
38259b8d05b8SZbigniew Bodek 	while (taskqueue_cancel(adapter->reset_tq, &adapter->reset_task, NULL))
38269b8d05b8SZbigniew Bodek 		taskqueue_drain(adapter->reset_tq, &adapter->reset_task);
38279b8d05b8SZbigniew Bodek 	taskqueue_free(adapter->reset_tq);
38289b8d05b8SZbigniew Bodek 
38296959869eSMarcin Wojtas 	ENA_LOCK_LOCK(adapter);
38309b8d05b8SZbigniew Bodek 	ena_down(adapter);
383132f63fa7SMarcin Wojtas 	ena_destroy_device(adapter, true);
38326959869eSMarcin Wojtas 	ENA_LOCK_UNLOCK(adapter);
38339b8d05b8SZbigniew Bodek 
3834d17b7d87SMarcin Wojtas #ifdef DEV_NETMAP
3835d17b7d87SMarcin Wojtas 	netmap_detach(adapter->ifp);
3836d17b7d87SMarcin Wojtas #endif /* DEV_NETMAP */
3837d17b7d87SMarcin Wojtas 
383830217e2dSMarcin Wojtas 	ena_free_counters((counter_u64_t *)&adapter->hw_stats,
383930217e2dSMarcin Wojtas 	    sizeof(struct ena_hw_stats));
38409b8d05b8SZbigniew Bodek 	ena_free_counters((counter_u64_t *)&adapter->dev_stats,
38419b8d05b8SZbigniew Bodek 	    sizeof(struct ena_stats_dev));
38429b8d05b8SZbigniew Bodek 
38439b8d05b8SZbigniew Bodek 	rc = ena_free_rx_dma_tag(adapter);
38443f9ed7abSMarcin Wojtas 	if (unlikely(rc != 0))
38459b8d05b8SZbigniew Bodek 		device_printf(adapter->pdev,
38469b8d05b8SZbigniew Bodek 		    "Unmapped RX DMA tag associations\n");
38479b8d05b8SZbigniew Bodek 
38489b8d05b8SZbigniew Bodek 	rc = ena_free_tx_dma_tag(adapter);
38493f9ed7abSMarcin Wojtas 	if (unlikely(rc != 0))
38509b8d05b8SZbigniew Bodek 		device_printf(adapter->pdev,
38519b8d05b8SZbigniew Bodek 		    "Unmapped TX DMA tag associations\n");
38529b8d05b8SZbigniew Bodek 
38539b8d05b8SZbigniew Bodek 	ena_free_irqs(adapter);
38549b8d05b8SZbigniew Bodek 
38559b8d05b8SZbigniew Bodek 	ena_free_pci_resources(adapter);
38569b8d05b8SZbigniew Bodek 
385732f63fa7SMarcin Wojtas 	if (likely(ENA_FLAG_ISSET(ENA_FLAG_RSS_ACTIVE, adapter)))
385832f63fa7SMarcin Wojtas 		ena_com_rss_destroy(ena_dev);
385932f63fa7SMarcin Wojtas 
386032f63fa7SMarcin Wojtas 	ena_com_delete_host_info(ena_dev);
386132f63fa7SMarcin Wojtas 
38626959869eSMarcin Wojtas 	ENA_LOCK_DESTROY(adapter);
38639b8d05b8SZbigniew Bodek 
38649151c55dSMarcin Wojtas 	if_free(adapter->ifp);
38659151c55dSMarcin Wojtas 
38669b8d05b8SZbigniew Bodek 	if (ena_dev->bus != NULL)
38679b8d05b8SZbigniew Bodek 		free(ena_dev->bus, M_DEVBUF);
38689b8d05b8SZbigniew Bodek 
38699b8d05b8SZbigniew Bodek 	if (ena_dev != NULL)
38709b8d05b8SZbigniew Bodek 		free(ena_dev, M_DEVBUF);
38719b8d05b8SZbigniew Bodek 
38729b8d05b8SZbigniew Bodek 	return (bus_generic_detach(pdev));
38739b8d05b8SZbigniew Bodek }
38749b8d05b8SZbigniew Bodek 
38759b8d05b8SZbigniew Bodek /******************************************************************************
38769b8d05b8SZbigniew Bodek  ******************************** AENQ Handlers *******************************
38779b8d05b8SZbigniew Bodek  *****************************************************************************/
38789b8d05b8SZbigniew Bodek /**
38799b8d05b8SZbigniew Bodek  * ena_update_on_link_change:
38809b8d05b8SZbigniew Bodek  * Notify the network interface about the change in link status
38819b8d05b8SZbigniew Bodek  **/
38829b8d05b8SZbigniew Bodek static void
38839b8d05b8SZbigniew Bodek ena_update_on_link_change(void *adapter_data,
38849b8d05b8SZbigniew Bodek     struct ena_admin_aenq_entry *aenq_e)
38859b8d05b8SZbigniew Bodek {
38869b8d05b8SZbigniew Bodek 	struct ena_adapter *adapter = (struct ena_adapter *)adapter_data;
38879b8d05b8SZbigniew Bodek 	struct ena_admin_aenq_link_change_desc *aenq_desc;
38889b8d05b8SZbigniew Bodek 	int status;
38899b8d05b8SZbigniew Bodek 	if_t ifp;
38909b8d05b8SZbigniew Bodek 
38919b8d05b8SZbigniew Bodek 	aenq_desc = (struct ena_admin_aenq_link_change_desc *)aenq_e;
38929b8d05b8SZbigniew Bodek 	ifp = adapter->ifp;
38939b8d05b8SZbigniew Bodek 	status = aenq_desc->flags &
38949b8d05b8SZbigniew Bodek 	    ENA_ADMIN_AENQ_LINK_CHANGE_DESC_LINK_STATUS_MASK;
38959b8d05b8SZbigniew Bodek 
38969b8d05b8SZbigniew Bodek 	if (status != 0) {
38979b8d05b8SZbigniew Bodek 		device_printf(adapter->pdev, "link is UP\n");
3898fd43fd2aSMarcin Wojtas 		ENA_FLAG_SET_ATOMIC(ENA_FLAG_LINK_UP, adapter);
389932f63fa7SMarcin Wojtas 		if (!ENA_FLAG_ISSET(ENA_FLAG_ONGOING_RESET, adapter))
390032f63fa7SMarcin Wojtas 			if_link_state_change(ifp, LINK_STATE_UP);
390132f63fa7SMarcin Wojtas 	} else {
39029b8d05b8SZbigniew Bodek 		device_printf(adapter->pdev, "link is DOWN\n");
39039b8d05b8SZbigniew Bodek 		if_link_state_change(ifp, LINK_STATE_DOWN);
3904fd43fd2aSMarcin Wojtas 		ENA_FLAG_CLEAR_ATOMIC(ENA_FLAG_LINK_UP, adapter);
39059b8d05b8SZbigniew Bodek 	}
39069b8d05b8SZbigniew Bodek }
39079b8d05b8SZbigniew Bodek 
390840621d71SMarcin Wojtas static void ena_notification(void *adapter_data,
390940621d71SMarcin Wojtas     struct ena_admin_aenq_entry *aenq_e)
391040621d71SMarcin Wojtas {
391140621d71SMarcin Wojtas 	struct ena_adapter *adapter = (struct ena_adapter *)adapter_data;
391240621d71SMarcin Wojtas 	struct ena_admin_ena_hw_hints *hints;
391340621d71SMarcin Wojtas 
39149eb1615fSMarcin Wojtas 	ENA_WARN(NULL, aenq_e->aenq_common_desc.group != ENA_ADMIN_NOTIFICATION,
391540621d71SMarcin Wojtas 	    "Invalid group(%x) expected %x\n",	aenq_e->aenq_common_desc.group,
391640621d71SMarcin Wojtas 	    ENA_ADMIN_NOTIFICATION);
391740621d71SMarcin Wojtas 
39189eb1615fSMarcin Wojtas 	switch (aenq_e->aenq_common_desc.syndrome) {
391940621d71SMarcin Wojtas 	case ENA_ADMIN_UPDATE_HINTS:
392040621d71SMarcin Wojtas 		hints =
392140621d71SMarcin Wojtas 		    (struct ena_admin_ena_hw_hints *)(&aenq_e->inline_data_w4);
392240621d71SMarcin Wojtas 		ena_update_hints(adapter, hints);
392340621d71SMarcin Wojtas 		break;
392440621d71SMarcin Wojtas 	default:
392540621d71SMarcin Wojtas 		device_printf(adapter->pdev,
392640621d71SMarcin Wojtas 		    "Invalid aenq notification link state %d\n",
39279eb1615fSMarcin Wojtas 		    aenq_e->aenq_common_desc.syndrome);
392840621d71SMarcin Wojtas 	}
392940621d71SMarcin Wojtas }
393040621d71SMarcin Wojtas 
39319b8d05b8SZbigniew Bodek /**
39329b8d05b8SZbigniew Bodek  * This handler will called for unknown event group or unimplemented handlers
39339b8d05b8SZbigniew Bodek  **/
39349b8d05b8SZbigniew Bodek static void
3935e6de9a83SMarcin Wojtas unimplemented_aenq_handler(void *adapter_data,
39369b8d05b8SZbigniew Bodek     struct ena_admin_aenq_entry *aenq_e)
39379b8d05b8SZbigniew Bodek {
3938e6de9a83SMarcin Wojtas 	struct ena_adapter *adapter = (struct ena_adapter *)adapter_data;
3939e6de9a83SMarcin Wojtas 
3940e6de9a83SMarcin Wojtas 	device_printf(adapter->pdev,
3941e6de9a83SMarcin Wojtas 	    "Unknown event was received or event with unimplemented handler\n");
39429b8d05b8SZbigniew Bodek }
39439b8d05b8SZbigniew Bodek 
39449b8d05b8SZbigniew Bodek static struct ena_aenq_handlers aenq_handlers = {
39459b8d05b8SZbigniew Bodek     .handlers = {
39469b8d05b8SZbigniew Bodek 	    [ENA_ADMIN_LINK_CHANGE] = ena_update_on_link_change,
394740621d71SMarcin Wojtas 	    [ENA_ADMIN_NOTIFICATION] = ena_notification,
39489b8d05b8SZbigniew Bodek 	    [ENA_ADMIN_KEEP_ALIVE] = ena_keep_alive_wd,
39499b8d05b8SZbigniew Bodek     },
39509b8d05b8SZbigniew Bodek     .unimplemented_handler = unimplemented_aenq_handler
39519b8d05b8SZbigniew Bodek };
39529b8d05b8SZbigniew Bodek 
39539b8d05b8SZbigniew Bodek /*********************************************************************
39549b8d05b8SZbigniew Bodek  *  FreeBSD Device Interface Entry Points
39559b8d05b8SZbigniew Bodek  *********************************************************************/
39569b8d05b8SZbigniew Bodek 
39579b8d05b8SZbigniew Bodek static device_method_t ena_methods[] = {
39589b8d05b8SZbigniew Bodek     /* Device interface */
39599b8d05b8SZbigniew Bodek     DEVMETHOD(device_probe, ena_probe),
39609b8d05b8SZbigniew Bodek     DEVMETHOD(device_attach, ena_attach),
39619b8d05b8SZbigniew Bodek     DEVMETHOD(device_detach, ena_detach),
39629b8d05b8SZbigniew Bodek     DEVMETHOD_END
39639b8d05b8SZbigniew Bodek };
39649b8d05b8SZbigniew Bodek 
39659b8d05b8SZbigniew Bodek static driver_t ena_driver = {
39669b8d05b8SZbigniew Bodek     "ena", ena_methods, sizeof(struct ena_adapter),
39679b8d05b8SZbigniew Bodek };
39689b8d05b8SZbigniew Bodek 
39699b8d05b8SZbigniew Bodek devclass_t ena_devclass;
39709b8d05b8SZbigniew Bodek DRIVER_MODULE(ena, pci, ena_driver, ena_devclass, 0, 0);
397140abe76bSWarner Losh MODULE_PNP_INFO("U16:vendor;U16:device", pci, ena, ena_vendor_info_array,
3972329e817fSWarner Losh     nitems(ena_vendor_info_array) - 1);
39739b8d05b8SZbigniew Bodek MODULE_DEPEND(ena, pci, 1, 1, 1);
39749b8d05b8SZbigniew Bodek MODULE_DEPEND(ena, ether, 1, 1, 1);
3975d17b7d87SMarcin Wojtas #ifdef DEV_NETMAP
3976d17b7d87SMarcin Wojtas MODULE_DEPEND(ena, netmap, 1, 1, 1);
3977d17b7d87SMarcin Wojtas #endif /* DEV_NETMAP */
39789b8d05b8SZbigniew Bodek 
39799b8d05b8SZbigniew Bodek /*********************************************************************/
3980