162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Copyright 2015-2020 Amazon.com, Inc. or its affiliates. All rights reserved.
462306a36Sopenharmony_ci */
562306a36Sopenharmony_ci
662306a36Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
762306a36Sopenharmony_ci
862306a36Sopenharmony_ci#ifdef CONFIG_RFS_ACCEL
962306a36Sopenharmony_ci#include <linux/cpu_rmap.h>
1062306a36Sopenharmony_ci#endif /* CONFIG_RFS_ACCEL */
1162306a36Sopenharmony_ci#include <linux/ethtool.h>
1262306a36Sopenharmony_ci#include <linux/kernel.h>
1362306a36Sopenharmony_ci#include <linux/module.h>
1462306a36Sopenharmony_ci#include <linux/numa.h>
1562306a36Sopenharmony_ci#include <linux/pci.h>
1662306a36Sopenharmony_ci#include <linux/utsname.h>
1762306a36Sopenharmony_ci#include <linux/version.h>
1862306a36Sopenharmony_ci#include <linux/vmalloc.h>
1962306a36Sopenharmony_ci#include <net/ip.h>
2062306a36Sopenharmony_ci
2162306a36Sopenharmony_ci#include "ena_netdev.h"
2262306a36Sopenharmony_ci#include <linux/bpf_trace.h>
2362306a36Sopenharmony_ci#include "ena_pci_id_tbl.h"
2462306a36Sopenharmony_ci
2562306a36Sopenharmony_ciMODULE_AUTHOR("Amazon.com, Inc. or its affiliates");
2662306a36Sopenharmony_ciMODULE_DESCRIPTION(DEVICE_NAME);
2762306a36Sopenharmony_ciMODULE_LICENSE("GPL");
2862306a36Sopenharmony_ci
2962306a36Sopenharmony_ci/* Time in jiffies before concluding the transmitter is hung. */
3062306a36Sopenharmony_ci#define TX_TIMEOUT  (5 * HZ)
3162306a36Sopenharmony_ci
3262306a36Sopenharmony_ci#define ENA_MAX_RINGS min_t(unsigned int, ENA_MAX_NUM_IO_QUEUES, num_possible_cpus())
3362306a36Sopenharmony_ci
3462306a36Sopenharmony_ci#define DEFAULT_MSG_ENABLE (NETIF_MSG_DRV | NETIF_MSG_PROBE | NETIF_MSG_IFUP | \
3562306a36Sopenharmony_ci		NETIF_MSG_TX_DONE | NETIF_MSG_TX_ERR | NETIF_MSG_RX_ERR)
3662306a36Sopenharmony_ci
3762306a36Sopenharmony_cistatic struct ena_aenq_handlers aenq_handlers;
3862306a36Sopenharmony_ci
3962306a36Sopenharmony_cistatic struct workqueue_struct *ena_wq;
4062306a36Sopenharmony_ci
4162306a36Sopenharmony_ciMODULE_DEVICE_TABLE(pci, ena_pci_tbl);
4262306a36Sopenharmony_ci
4362306a36Sopenharmony_cistatic int ena_rss_init_default(struct ena_adapter *adapter);
4462306a36Sopenharmony_cistatic void check_for_admin_com_state(struct ena_adapter *adapter);
4562306a36Sopenharmony_cistatic void ena_destroy_device(struct ena_adapter *adapter, bool graceful);
4662306a36Sopenharmony_cistatic int ena_restore_device(struct ena_adapter *adapter);
4762306a36Sopenharmony_ci
4862306a36Sopenharmony_cistatic void ena_init_io_rings(struct ena_adapter *adapter,
4962306a36Sopenharmony_ci			      int first_index, int count);
5062306a36Sopenharmony_cistatic void ena_init_napi_in_range(struct ena_adapter *adapter, int first_index,
5162306a36Sopenharmony_ci				   int count);
5262306a36Sopenharmony_cistatic void ena_del_napi_in_range(struct ena_adapter *adapter, int first_index,
5362306a36Sopenharmony_ci				  int count);
5462306a36Sopenharmony_cistatic int ena_setup_tx_resources(struct ena_adapter *adapter, int qid);
5562306a36Sopenharmony_cistatic int ena_setup_tx_resources_in_range(struct ena_adapter *adapter,
5662306a36Sopenharmony_ci					   int first_index,
5762306a36Sopenharmony_ci					   int count);
5862306a36Sopenharmony_cistatic int ena_create_io_tx_queue(struct ena_adapter *adapter, int qid);
5962306a36Sopenharmony_cistatic void ena_free_tx_resources(struct ena_adapter *adapter, int qid);
6062306a36Sopenharmony_cistatic int ena_clean_xdp_irq(struct ena_ring *xdp_ring, u32 budget);
6162306a36Sopenharmony_cistatic void ena_destroy_all_tx_queues(struct ena_adapter *adapter);
6262306a36Sopenharmony_cistatic void ena_free_all_io_tx_resources(struct ena_adapter *adapter);
6362306a36Sopenharmony_cistatic void ena_napi_disable_in_range(struct ena_adapter *adapter,
6462306a36Sopenharmony_ci				      int first_index, int count);
6562306a36Sopenharmony_cistatic void ena_napi_enable_in_range(struct ena_adapter *adapter,
6662306a36Sopenharmony_ci				     int first_index, int count);
6762306a36Sopenharmony_cistatic int ena_up(struct ena_adapter *adapter);
6862306a36Sopenharmony_cistatic void ena_down(struct ena_adapter *adapter);
6962306a36Sopenharmony_cistatic void ena_unmask_interrupt(struct ena_ring *tx_ring,
7062306a36Sopenharmony_ci				 struct ena_ring *rx_ring);
7162306a36Sopenharmony_cistatic void ena_update_ring_numa_node(struct ena_ring *tx_ring,
7262306a36Sopenharmony_ci				      struct ena_ring *rx_ring);
7362306a36Sopenharmony_cistatic void ena_unmap_tx_buff(struct ena_ring *tx_ring,
7462306a36Sopenharmony_ci			      struct ena_tx_buffer *tx_info);
7562306a36Sopenharmony_cistatic int ena_create_io_tx_queues_in_range(struct ena_adapter *adapter,
7662306a36Sopenharmony_ci					    int first_index, int count);
7762306a36Sopenharmony_cistatic void ena_free_all_io_tx_resources_in_range(struct ena_adapter *adapter,
7862306a36Sopenharmony_ci						  int first_index, int count);
7962306a36Sopenharmony_ci
8062306a36Sopenharmony_ci/* Increase a stat by cnt while holding syncp seqlock on 32bit machines */
8162306a36Sopenharmony_cistatic void ena_increase_stat(u64 *statp, u64 cnt,
8262306a36Sopenharmony_ci			      struct u64_stats_sync *syncp)
8362306a36Sopenharmony_ci{
8462306a36Sopenharmony_ci	u64_stats_update_begin(syncp);
8562306a36Sopenharmony_ci	(*statp) += cnt;
8662306a36Sopenharmony_ci	u64_stats_update_end(syncp);
8762306a36Sopenharmony_ci}
8862306a36Sopenharmony_ci
8962306a36Sopenharmony_cistatic void ena_ring_tx_doorbell(struct ena_ring *tx_ring)
9062306a36Sopenharmony_ci{
9162306a36Sopenharmony_ci	ena_com_write_sq_doorbell(tx_ring->ena_com_io_sq);
9262306a36Sopenharmony_ci	ena_increase_stat(&tx_ring->tx_stats.doorbells, 1, &tx_ring->syncp);
9362306a36Sopenharmony_ci}
9462306a36Sopenharmony_ci
9562306a36Sopenharmony_cistatic void ena_tx_timeout(struct net_device *dev, unsigned int txqueue)
9662306a36Sopenharmony_ci{
9762306a36Sopenharmony_ci	struct ena_adapter *adapter = netdev_priv(dev);
9862306a36Sopenharmony_ci
9962306a36Sopenharmony_ci	/* Change the state of the device to trigger reset
10062306a36Sopenharmony_ci	 * Check that we are not in the middle or a trigger already
10162306a36Sopenharmony_ci	 */
10262306a36Sopenharmony_ci
10362306a36Sopenharmony_ci	if (test_and_set_bit(ENA_FLAG_TRIGGER_RESET, &adapter->flags))
10462306a36Sopenharmony_ci		return;
10562306a36Sopenharmony_ci
10662306a36Sopenharmony_ci	ena_reset_device(adapter, ENA_REGS_RESET_OS_NETDEV_WD);
10762306a36Sopenharmony_ci	ena_increase_stat(&adapter->dev_stats.tx_timeout, 1, &adapter->syncp);
10862306a36Sopenharmony_ci
10962306a36Sopenharmony_ci	netif_err(adapter, tx_err, dev, "Transmit time out\n");
11062306a36Sopenharmony_ci}
11162306a36Sopenharmony_ci
11262306a36Sopenharmony_cistatic void update_rx_ring_mtu(struct ena_adapter *adapter, int mtu)
11362306a36Sopenharmony_ci{
11462306a36Sopenharmony_ci	int i;
11562306a36Sopenharmony_ci
11662306a36Sopenharmony_ci	for (i = 0; i < adapter->num_io_queues; i++)
11762306a36Sopenharmony_ci		adapter->rx_ring[i].mtu = mtu;
11862306a36Sopenharmony_ci}
11962306a36Sopenharmony_ci
12062306a36Sopenharmony_cistatic int ena_change_mtu(struct net_device *dev, int new_mtu)
12162306a36Sopenharmony_ci{
12262306a36Sopenharmony_ci	struct ena_adapter *adapter = netdev_priv(dev);
12362306a36Sopenharmony_ci	int ret;
12462306a36Sopenharmony_ci
12562306a36Sopenharmony_ci	ret = ena_com_set_dev_mtu(adapter->ena_dev, new_mtu);
12662306a36Sopenharmony_ci	if (!ret) {
12762306a36Sopenharmony_ci		netif_dbg(adapter, drv, dev, "Set MTU to %d\n", new_mtu);
12862306a36Sopenharmony_ci		update_rx_ring_mtu(adapter, new_mtu);
12962306a36Sopenharmony_ci		dev->mtu = new_mtu;
13062306a36Sopenharmony_ci	} else {
13162306a36Sopenharmony_ci		netif_err(adapter, drv, dev, "Failed to set MTU to %d\n",
13262306a36Sopenharmony_ci			  new_mtu);
13362306a36Sopenharmony_ci	}
13462306a36Sopenharmony_ci
13562306a36Sopenharmony_ci	return ret;
13662306a36Sopenharmony_ci}
13762306a36Sopenharmony_ci
13862306a36Sopenharmony_cistatic int ena_xmit_common(struct net_device *dev,
13962306a36Sopenharmony_ci			   struct ena_ring *ring,
14062306a36Sopenharmony_ci			   struct ena_tx_buffer *tx_info,
14162306a36Sopenharmony_ci			   struct ena_com_tx_ctx *ena_tx_ctx,
14262306a36Sopenharmony_ci			   u16 next_to_use,
14362306a36Sopenharmony_ci			   u32 bytes)
14462306a36Sopenharmony_ci{
14562306a36Sopenharmony_ci	struct ena_adapter *adapter = netdev_priv(dev);
14662306a36Sopenharmony_ci	int rc, nb_hw_desc;
14762306a36Sopenharmony_ci
14862306a36Sopenharmony_ci	if (unlikely(ena_com_is_doorbell_needed(ring->ena_com_io_sq,
14962306a36Sopenharmony_ci						ena_tx_ctx))) {
15062306a36Sopenharmony_ci		netif_dbg(adapter, tx_queued, dev,
15162306a36Sopenharmony_ci			  "llq tx max burst size of queue %d achieved, writing doorbell to send burst\n",
15262306a36Sopenharmony_ci			  ring->qid);
15362306a36Sopenharmony_ci		ena_ring_tx_doorbell(ring);
15462306a36Sopenharmony_ci	}
15562306a36Sopenharmony_ci
15662306a36Sopenharmony_ci	/* prepare the packet's descriptors to dma engine */
15762306a36Sopenharmony_ci	rc = ena_com_prepare_tx(ring->ena_com_io_sq, ena_tx_ctx,
15862306a36Sopenharmony_ci				&nb_hw_desc);
15962306a36Sopenharmony_ci
16062306a36Sopenharmony_ci	/* In case there isn't enough space in the queue for the packet,
16162306a36Sopenharmony_ci	 * we simply drop it. All other failure reasons of
16262306a36Sopenharmony_ci	 * ena_com_prepare_tx() are fatal and therefore require a device reset.
16362306a36Sopenharmony_ci	 */
16462306a36Sopenharmony_ci	if (unlikely(rc)) {
16562306a36Sopenharmony_ci		netif_err(adapter, tx_queued, dev,
16662306a36Sopenharmony_ci			  "Failed to prepare tx bufs\n");
16762306a36Sopenharmony_ci		ena_increase_stat(&ring->tx_stats.prepare_ctx_err, 1,
16862306a36Sopenharmony_ci				  &ring->syncp);
16962306a36Sopenharmony_ci		if (rc != -ENOMEM)
17062306a36Sopenharmony_ci			ena_reset_device(adapter,
17162306a36Sopenharmony_ci					 ENA_REGS_RESET_DRIVER_INVALID_STATE);
17262306a36Sopenharmony_ci		return rc;
17362306a36Sopenharmony_ci	}
17462306a36Sopenharmony_ci
17562306a36Sopenharmony_ci	u64_stats_update_begin(&ring->syncp);
17662306a36Sopenharmony_ci	ring->tx_stats.cnt++;
17762306a36Sopenharmony_ci	ring->tx_stats.bytes += bytes;
17862306a36Sopenharmony_ci	u64_stats_update_end(&ring->syncp);
17962306a36Sopenharmony_ci
18062306a36Sopenharmony_ci	tx_info->tx_descs = nb_hw_desc;
18162306a36Sopenharmony_ci	tx_info->last_jiffies = jiffies;
18262306a36Sopenharmony_ci	tx_info->print_once = 0;
18362306a36Sopenharmony_ci
18462306a36Sopenharmony_ci	ring->next_to_use = ENA_TX_RING_IDX_NEXT(next_to_use,
18562306a36Sopenharmony_ci						 ring->ring_size);
18662306a36Sopenharmony_ci	return 0;
18762306a36Sopenharmony_ci}
18862306a36Sopenharmony_ci
18962306a36Sopenharmony_ci/* This is the XDP napi callback. XDP queues use a separate napi callback
19062306a36Sopenharmony_ci * than Rx/Tx queues.
19162306a36Sopenharmony_ci */
19262306a36Sopenharmony_cistatic int ena_xdp_io_poll(struct napi_struct *napi, int budget)
19362306a36Sopenharmony_ci{
19462306a36Sopenharmony_ci	struct ena_napi *ena_napi = container_of(napi, struct ena_napi, napi);
19562306a36Sopenharmony_ci	u32 xdp_work_done, xdp_budget;
19662306a36Sopenharmony_ci	struct ena_ring *xdp_ring;
19762306a36Sopenharmony_ci	int napi_comp_call = 0;
19862306a36Sopenharmony_ci	int ret;
19962306a36Sopenharmony_ci
20062306a36Sopenharmony_ci	xdp_ring = ena_napi->xdp_ring;
20162306a36Sopenharmony_ci
20262306a36Sopenharmony_ci	xdp_budget = budget;
20362306a36Sopenharmony_ci
20462306a36Sopenharmony_ci	if (!test_bit(ENA_FLAG_DEV_UP, &xdp_ring->adapter->flags) ||
20562306a36Sopenharmony_ci	    test_bit(ENA_FLAG_TRIGGER_RESET, &xdp_ring->adapter->flags)) {
20662306a36Sopenharmony_ci		napi_complete_done(napi, 0);
20762306a36Sopenharmony_ci		return 0;
20862306a36Sopenharmony_ci	}
20962306a36Sopenharmony_ci
21062306a36Sopenharmony_ci	xdp_work_done = ena_clean_xdp_irq(xdp_ring, xdp_budget);
21162306a36Sopenharmony_ci
21262306a36Sopenharmony_ci	/* If the device is about to reset or down, avoid unmask
21362306a36Sopenharmony_ci	 * the interrupt and return 0 so NAPI won't reschedule
21462306a36Sopenharmony_ci	 */
21562306a36Sopenharmony_ci	if (unlikely(!test_bit(ENA_FLAG_DEV_UP, &xdp_ring->adapter->flags))) {
21662306a36Sopenharmony_ci		napi_complete_done(napi, 0);
21762306a36Sopenharmony_ci		ret = 0;
21862306a36Sopenharmony_ci	} else if (xdp_budget > xdp_work_done) {
21962306a36Sopenharmony_ci		napi_comp_call = 1;
22062306a36Sopenharmony_ci		if (napi_complete_done(napi, xdp_work_done))
22162306a36Sopenharmony_ci			ena_unmask_interrupt(xdp_ring, NULL);
22262306a36Sopenharmony_ci		ena_update_ring_numa_node(xdp_ring, NULL);
22362306a36Sopenharmony_ci		ret = xdp_work_done;
22462306a36Sopenharmony_ci	} else {
22562306a36Sopenharmony_ci		ret = xdp_budget;
22662306a36Sopenharmony_ci	}
22762306a36Sopenharmony_ci
22862306a36Sopenharmony_ci	u64_stats_update_begin(&xdp_ring->syncp);
22962306a36Sopenharmony_ci	xdp_ring->tx_stats.napi_comp += napi_comp_call;
23062306a36Sopenharmony_ci	xdp_ring->tx_stats.tx_poll++;
23162306a36Sopenharmony_ci	u64_stats_update_end(&xdp_ring->syncp);
23262306a36Sopenharmony_ci	xdp_ring->tx_stats.last_napi_jiffies = jiffies;
23362306a36Sopenharmony_ci
23462306a36Sopenharmony_ci	return ret;
23562306a36Sopenharmony_ci}
23662306a36Sopenharmony_ci
23762306a36Sopenharmony_cistatic int ena_xdp_tx_map_frame(struct ena_ring *xdp_ring,
23862306a36Sopenharmony_ci				struct ena_tx_buffer *tx_info,
23962306a36Sopenharmony_ci				struct xdp_frame *xdpf,
24062306a36Sopenharmony_ci				struct ena_com_tx_ctx *ena_tx_ctx)
24162306a36Sopenharmony_ci{
24262306a36Sopenharmony_ci	struct ena_adapter *adapter = xdp_ring->adapter;
24362306a36Sopenharmony_ci	struct ena_com_buf *ena_buf;
24462306a36Sopenharmony_ci	int push_len = 0;
24562306a36Sopenharmony_ci	dma_addr_t dma;
24662306a36Sopenharmony_ci	void *data;
24762306a36Sopenharmony_ci	u32 size;
24862306a36Sopenharmony_ci
24962306a36Sopenharmony_ci	tx_info->xdpf = xdpf;
25062306a36Sopenharmony_ci	data = tx_info->xdpf->data;
25162306a36Sopenharmony_ci	size = tx_info->xdpf->len;
25262306a36Sopenharmony_ci
25362306a36Sopenharmony_ci	if (xdp_ring->tx_mem_queue_type == ENA_ADMIN_PLACEMENT_POLICY_DEV) {
25462306a36Sopenharmony_ci		/* Designate part of the packet for LLQ */
25562306a36Sopenharmony_ci		push_len = min_t(u32, size, xdp_ring->tx_max_header_size);
25662306a36Sopenharmony_ci
25762306a36Sopenharmony_ci		ena_tx_ctx->push_header = data;
25862306a36Sopenharmony_ci
25962306a36Sopenharmony_ci		size -= push_len;
26062306a36Sopenharmony_ci		data += push_len;
26162306a36Sopenharmony_ci	}
26262306a36Sopenharmony_ci
26362306a36Sopenharmony_ci	ena_tx_ctx->header_len = push_len;
26462306a36Sopenharmony_ci
26562306a36Sopenharmony_ci	if (size > 0) {
26662306a36Sopenharmony_ci		dma = dma_map_single(xdp_ring->dev,
26762306a36Sopenharmony_ci				     data,
26862306a36Sopenharmony_ci				     size,
26962306a36Sopenharmony_ci				     DMA_TO_DEVICE);
27062306a36Sopenharmony_ci		if (unlikely(dma_mapping_error(xdp_ring->dev, dma)))
27162306a36Sopenharmony_ci			goto error_report_dma_error;
27262306a36Sopenharmony_ci
27362306a36Sopenharmony_ci		tx_info->map_linear_data = 0;
27462306a36Sopenharmony_ci
27562306a36Sopenharmony_ci		ena_buf = tx_info->bufs;
27662306a36Sopenharmony_ci		ena_buf->paddr = dma;
27762306a36Sopenharmony_ci		ena_buf->len = size;
27862306a36Sopenharmony_ci
27962306a36Sopenharmony_ci		ena_tx_ctx->ena_bufs = ena_buf;
28062306a36Sopenharmony_ci		ena_tx_ctx->num_bufs = tx_info->num_of_bufs = 1;
28162306a36Sopenharmony_ci	}
28262306a36Sopenharmony_ci
28362306a36Sopenharmony_ci	return 0;
28462306a36Sopenharmony_ci
28562306a36Sopenharmony_cierror_report_dma_error:
28662306a36Sopenharmony_ci	ena_increase_stat(&xdp_ring->tx_stats.dma_mapping_err, 1,
28762306a36Sopenharmony_ci			  &xdp_ring->syncp);
28862306a36Sopenharmony_ci	netif_warn(adapter, tx_queued, adapter->netdev, "Failed to map xdp buff\n");
28962306a36Sopenharmony_ci
29062306a36Sopenharmony_ci	return -EINVAL;
29162306a36Sopenharmony_ci}
29262306a36Sopenharmony_ci
29362306a36Sopenharmony_cistatic int ena_xdp_xmit_frame(struct ena_ring *xdp_ring,
29462306a36Sopenharmony_ci			      struct net_device *dev,
29562306a36Sopenharmony_ci			      struct xdp_frame *xdpf,
29662306a36Sopenharmony_ci			      int flags)
29762306a36Sopenharmony_ci{
29862306a36Sopenharmony_ci	struct ena_com_tx_ctx ena_tx_ctx = {};
29962306a36Sopenharmony_ci	struct ena_tx_buffer *tx_info;
30062306a36Sopenharmony_ci	u16 next_to_use, req_id;
30162306a36Sopenharmony_ci	int rc;
30262306a36Sopenharmony_ci
30362306a36Sopenharmony_ci	next_to_use = xdp_ring->next_to_use;
30462306a36Sopenharmony_ci	req_id = xdp_ring->free_ids[next_to_use];
30562306a36Sopenharmony_ci	tx_info = &xdp_ring->tx_buffer_info[req_id];
30662306a36Sopenharmony_ci	tx_info->num_of_bufs = 0;
30762306a36Sopenharmony_ci
30862306a36Sopenharmony_ci	rc = ena_xdp_tx_map_frame(xdp_ring, tx_info, xdpf, &ena_tx_ctx);
30962306a36Sopenharmony_ci	if (unlikely(rc))
31062306a36Sopenharmony_ci		return rc;
31162306a36Sopenharmony_ci
31262306a36Sopenharmony_ci	ena_tx_ctx.req_id = req_id;
31362306a36Sopenharmony_ci
31462306a36Sopenharmony_ci	rc = ena_xmit_common(dev,
31562306a36Sopenharmony_ci			     xdp_ring,
31662306a36Sopenharmony_ci			     tx_info,
31762306a36Sopenharmony_ci			     &ena_tx_ctx,
31862306a36Sopenharmony_ci			     next_to_use,
31962306a36Sopenharmony_ci			     xdpf->len);
32062306a36Sopenharmony_ci	if (rc)
32162306a36Sopenharmony_ci		goto error_unmap_dma;
32262306a36Sopenharmony_ci
32362306a36Sopenharmony_ci	/* trigger the dma engine. ena_ring_tx_doorbell()
32462306a36Sopenharmony_ci	 * calls a memory barrier inside it.
32562306a36Sopenharmony_ci	 */
32662306a36Sopenharmony_ci	if (flags & XDP_XMIT_FLUSH)
32762306a36Sopenharmony_ci		ena_ring_tx_doorbell(xdp_ring);
32862306a36Sopenharmony_ci
32962306a36Sopenharmony_ci	return rc;
33062306a36Sopenharmony_ci
33162306a36Sopenharmony_cierror_unmap_dma:
33262306a36Sopenharmony_ci	ena_unmap_tx_buff(xdp_ring, tx_info);
33362306a36Sopenharmony_ci	tx_info->xdpf = NULL;
33462306a36Sopenharmony_ci	return rc;
33562306a36Sopenharmony_ci}
33662306a36Sopenharmony_ci
33762306a36Sopenharmony_cistatic int ena_xdp_xmit(struct net_device *dev, int n,
33862306a36Sopenharmony_ci			struct xdp_frame **frames, u32 flags)
33962306a36Sopenharmony_ci{
34062306a36Sopenharmony_ci	struct ena_adapter *adapter = netdev_priv(dev);
34162306a36Sopenharmony_ci	struct ena_ring *xdp_ring;
34262306a36Sopenharmony_ci	int qid, i, nxmit = 0;
34362306a36Sopenharmony_ci
34462306a36Sopenharmony_ci	if (unlikely(flags & ~XDP_XMIT_FLAGS_MASK))
34562306a36Sopenharmony_ci		return -EINVAL;
34662306a36Sopenharmony_ci
34762306a36Sopenharmony_ci	if (!test_bit(ENA_FLAG_DEV_UP, &adapter->flags))
34862306a36Sopenharmony_ci		return -ENETDOWN;
34962306a36Sopenharmony_ci
35062306a36Sopenharmony_ci	/* We assume that all rings have the same XDP program */
35162306a36Sopenharmony_ci	if (!READ_ONCE(adapter->rx_ring->xdp_bpf_prog))
35262306a36Sopenharmony_ci		return -ENXIO;
35362306a36Sopenharmony_ci
35462306a36Sopenharmony_ci	qid = smp_processor_id() % adapter->xdp_num_queues;
35562306a36Sopenharmony_ci	qid += adapter->xdp_first_ring;
35662306a36Sopenharmony_ci	xdp_ring = &adapter->tx_ring[qid];
35762306a36Sopenharmony_ci
35862306a36Sopenharmony_ci	/* Other CPU ids might try to send thorugh this queue */
35962306a36Sopenharmony_ci	spin_lock(&xdp_ring->xdp_tx_lock);
36062306a36Sopenharmony_ci
36162306a36Sopenharmony_ci	for (i = 0; i < n; i++) {
36262306a36Sopenharmony_ci		if (ena_xdp_xmit_frame(xdp_ring, dev, frames[i], 0))
36362306a36Sopenharmony_ci			break;
36462306a36Sopenharmony_ci		nxmit++;
36562306a36Sopenharmony_ci	}
36662306a36Sopenharmony_ci
36762306a36Sopenharmony_ci	/* Ring doorbell to make device aware of the packets */
36862306a36Sopenharmony_ci	if (flags & XDP_XMIT_FLUSH)
36962306a36Sopenharmony_ci		ena_ring_tx_doorbell(xdp_ring);
37062306a36Sopenharmony_ci
37162306a36Sopenharmony_ci	spin_unlock(&xdp_ring->xdp_tx_lock);
37262306a36Sopenharmony_ci
37362306a36Sopenharmony_ci	/* Return number of packets sent */
37462306a36Sopenharmony_ci	return nxmit;
37562306a36Sopenharmony_ci}
37662306a36Sopenharmony_ci
37762306a36Sopenharmony_cistatic int ena_xdp_execute(struct ena_ring *rx_ring, struct xdp_buff *xdp)
37862306a36Sopenharmony_ci{
37962306a36Sopenharmony_ci	u32 verdict = ENA_XDP_PASS;
38062306a36Sopenharmony_ci	struct bpf_prog *xdp_prog;
38162306a36Sopenharmony_ci	struct ena_ring *xdp_ring;
38262306a36Sopenharmony_ci	struct xdp_frame *xdpf;
38362306a36Sopenharmony_ci	u64 *xdp_stat;
38462306a36Sopenharmony_ci
38562306a36Sopenharmony_ci	xdp_prog = READ_ONCE(rx_ring->xdp_bpf_prog);
38662306a36Sopenharmony_ci
38762306a36Sopenharmony_ci	if (!xdp_prog)
38862306a36Sopenharmony_ci		goto out;
38962306a36Sopenharmony_ci
39062306a36Sopenharmony_ci	verdict = bpf_prog_run_xdp(xdp_prog, xdp);
39162306a36Sopenharmony_ci
39262306a36Sopenharmony_ci	switch (verdict) {
39362306a36Sopenharmony_ci	case XDP_TX:
39462306a36Sopenharmony_ci		xdpf = xdp_convert_buff_to_frame(xdp);
39562306a36Sopenharmony_ci		if (unlikely(!xdpf)) {
39662306a36Sopenharmony_ci			trace_xdp_exception(rx_ring->netdev, xdp_prog, verdict);
39762306a36Sopenharmony_ci			xdp_stat = &rx_ring->rx_stats.xdp_aborted;
39862306a36Sopenharmony_ci			verdict = ENA_XDP_DROP;
39962306a36Sopenharmony_ci			break;
40062306a36Sopenharmony_ci		}
40162306a36Sopenharmony_ci
40262306a36Sopenharmony_ci		/* Find xmit queue */
40362306a36Sopenharmony_ci		xdp_ring = rx_ring->xdp_ring;
40462306a36Sopenharmony_ci
40562306a36Sopenharmony_ci		/* The XDP queues are shared between XDP_TX and XDP_REDIRECT */
40662306a36Sopenharmony_ci		spin_lock(&xdp_ring->xdp_tx_lock);
40762306a36Sopenharmony_ci
40862306a36Sopenharmony_ci		if (ena_xdp_xmit_frame(xdp_ring, rx_ring->netdev, xdpf,
40962306a36Sopenharmony_ci				       XDP_XMIT_FLUSH))
41062306a36Sopenharmony_ci			xdp_return_frame(xdpf);
41162306a36Sopenharmony_ci
41262306a36Sopenharmony_ci		spin_unlock(&xdp_ring->xdp_tx_lock);
41362306a36Sopenharmony_ci		xdp_stat = &rx_ring->rx_stats.xdp_tx;
41462306a36Sopenharmony_ci		verdict = ENA_XDP_TX;
41562306a36Sopenharmony_ci		break;
41662306a36Sopenharmony_ci	case XDP_REDIRECT:
41762306a36Sopenharmony_ci		if (likely(!xdp_do_redirect(rx_ring->netdev, xdp, xdp_prog))) {
41862306a36Sopenharmony_ci			xdp_stat = &rx_ring->rx_stats.xdp_redirect;
41962306a36Sopenharmony_ci			verdict = ENA_XDP_REDIRECT;
42062306a36Sopenharmony_ci			break;
42162306a36Sopenharmony_ci		}
42262306a36Sopenharmony_ci		trace_xdp_exception(rx_ring->netdev, xdp_prog, verdict);
42362306a36Sopenharmony_ci		xdp_stat = &rx_ring->rx_stats.xdp_aborted;
42462306a36Sopenharmony_ci		verdict = ENA_XDP_DROP;
42562306a36Sopenharmony_ci		break;
42662306a36Sopenharmony_ci	case XDP_ABORTED:
42762306a36Sopenharmony_ci		trace_xdp_exception(rx_ring->netdev, xdp_prog, verdict);
42862306a36Sopenharmony_ci		xdp_stat = &rx_ring->rx_stats.xdp_aborted;
42962306a36Sopenharmony_ci		verdict = ENA_XDP_DROP;
43062306a36Sopenharmony_ci		break;
43162306a36Sopenharmony_ci	case XDP_DROP:
43262306a36Sopenharmony_ci		xdp_stat = &rx_ring->rx_stats.xdp_drop;
43362306a36Sopenharmony_ci		verdict = ENA_XDP_DROP;
43462306a36Sopenharmony_ci		break;
43562306a36Sopenharmony_ci	case XDP_PASS:
43662306a36Sopenharmony_ci		xdp_stat = &rx_ring->rx_stats.xdp_pass;
43762306a36Sopenharmony_ci		verdict = ENA_XDP_PASS;
43862306a36Sopenharmony_ci		break;
43962306a36Sopenharmony_ci	default:
44062306a36Sopenharmony_ci		bpf_warn_invalid_xdp_action(rx_ring->netdev, xdp_prog, verdict);
44162306a36Sopenharmony_ci		xdp_stat = &rx_ring->rx_stats.xdp_invalid;
44262306a36Sopenharmony_ci		verdict = ENA_XDP_DROP;
44362306a36Sopenharmony_ci	}
44462306a36Sopenharmony_ci
44562306a36Sopenharmony_ci	ena_increase_stat(xdp_stat, 1, &rx_ring->syncp);
44662306a36Sopenharmony_ciout:
44762306a36Sopenharmony_ci	return verdict;
44862306a36Sopenharmony_ci}
44962306a36Sopenharmony_ci
45062306a36Sopenharmony_cistatic void ena_init_all_xdp_queues(struct ena_adapter *adapter)
45162306a36Sopenharmony_ci{
45262306a36Sopenharmony_ci	adapter->xdp_first_ring = adapter->num_io_queues;
45362306a36Sopenharmony_ci	adapter->xdp_num_queues = adapter->num_io_queues;
45462306a36Sopenharmony_ci
45562306a36Sopenharmony_ci	ena_init_io_rings(adapter,
45662306a36Sopenharmony_ci			  adapter->xdp_first_ring,
45762306a36Sopenharmony_ci			  adapter->xdp_num_queues);
45862306a36Sopenharmony_ci}
45962306a36Sopenharmony_ci
46062306a36Sopenharmony_cistatic int ena_setup_and_create_all_xdp_queues(struct ena_adapter *adapter)
46162306a36Sopenharmony_ci{
46262306a36Sopenharmony_ci	u32 xdp_first_ring = adapter->xdp_first_ring;
46362306a36Sopenharmony_ci	u32 xdp_num_queues = adapter->xdp_num_queues;
46462306a36Sopenharmony_ci	int rc = 0;
46562306a36Sopenharmony_ci
46662306a36Sopenharmony_ci	rc = ena_setup_tx_resources_in_range(adapter, xdp_first_ring, xdp_num_queues);
46762306a36Sopenharmony_ci	if (rc)
46862306a36Sopenharmony_ci		goto setup_err;
46962306a36Sopenharmony_ci
47062306a36Sopenharmony_ci	rc = ena_create_io_tx_queues_in_range(adapter, xdp_first_ring, xdp_num_queues);
47162306a36Sopenharmony_ci	if (rc)
47262306a36Sopenharmony_ci		goto create_err;
47362306a36Sopenharmony_ci
47462306a36Sopenharmony_ci	return 0;
47562306a36Sopenharmony_ci
47662306a36Sopenharmony_cicreate_err:
47762306a36Sopenharmony_ci	ena_free_all_io_tx_resources_in_range(adapter, xdp_first_ring, xdp_num_queues);
47862306a36Sopenharmony_cisetup_err:
47962306a36Sopenharmony_ci	return rc;
48062306a36Sopenharmony_ci}
48162306a36Sopenharmony_ci
48262306a36Sopenharmony_ci/* Provides a way for both kernel and bpf-prog to know
48362306a36Sopenharmony_ci * more about the RX-queue a given XDP frame arrived on.
48462306a36Sopenharmony_ci */
48562306a36Sopenharmony_cistatic int ena_xdp_register_rxq_info(struct ena_ring *rx_ring)
48662306a36Sopenharmony_ci{
48762306a36Sopenharmony_ci	int rc;
48862306a36Sopenharmony_ci
48962306a36Sopenharmony_ci	rc = xdp_rxq_info_reg(&rx_ring->xdp_rxq, rx_ring->netdev, rx_ring->qid, 0);
49062306a36Sopenharmony_ci
49162306a36Sopenharmony_ci	if (rc) {
49262306a36Sopenharmony_ci		netif_err(rx_ring->adapter, ifup, rx_ring->netdev,
49362306a36Sopenharmony_ci			  "Failed to register xdp rx queue info. RX queue num %d rc: %d\n",
49462306a36Sopenharmony_ci			  rx_ring->qid, rc);
49562306a36Sopenharmony_ci		goto err;
49662306a36Sopenharmony_ci	}
49762306a36Sopenharmony_ci
49862306a36Sopenharmony_ci	rc = xdp_rxq_info_reg_mem_model(&rx_ring->xdp_rxq, MEM_TYPE_PAGE_SHARED,
49962306a36Sopenharmony_ci					NULL);
50062306a36Sopenharmony_ci
50162306a36Sopenharmony_ci	if (rc) {
50262306a36Sopenharmony_ci		netif_err(rx_ring->adapter, ifup, rx_ring->netdev,
50362306a36Sopenharmony_ci			  "Failed to register xdp rx queue info memory model. RX queue num %d rc: %d\n",
50462306a36Sopenharmony_ci			  rx_ring->qid, rc);
50562306a36Sopenharmony_ci		xdp_rxq_info_unreg(&rx_ring->xdp_rxq);
50662306a36Sopenharmony_ci	}
50762306a36Sopenharmony_ci
50862306a36Sopenharmony_cierr:
50962306a36Sopenharmony_ci	return rc;
51062306a36Sopenharmony_ci}
51162306a36Sopenharmony_ci
51262306a36Sopenharmony_cistatic void ena_xdp_unregister_rxq_info(struct ena_ring *rx_ring)
51362306a36Sopenharmony_ci{
51462306a36Sopenharmony_ci	xdp_rxq_info_unreg_mem_model(&rx_ring->xdp_rxq);
51562306a36Sopenharmony_ci	xdp_rxq_info_unreg(&rx_ring->xdp_rxq);
51662306a36Sopenharmony_ci}
51762306a36Sopenharmony_ci
51862306a36Sopenharmony_cistatic void ena_xdp_exchange_program_rx_in_range(struct ena_adapter *adapter,
51962306a36Sopenharmony_ci						 struct bpf_prog *prog,
52062306a36Sopenharmony_ci						 int first, int count)
52162306a36Sopenharmony_ci{
52262306a36Sopenharmony_ci	struct bpf_prog *old_bpf_prog;
52362306a36Sopenharmony_ci	struct ena_ring *rx_ring;
52462306a36Sopenharmony_ci	int i = 0;
52562306a36Sopenharmony_ci
52662306a36Sopenharmony_ci	for (i = first; i < count; i++) {
52762306a36Sopenharmony_ci		rx_ring = &adapter->rx_ring[i];
52862306a36Sopenharmony_ci		old_bpf_prog = xchg(&rx_ring->xdp_bpf_prog, prog);
52962306a36Sopenharmony_ci
53062306a36Sopenharmony_ci		if (!old_bpf_prog && prog) {
53162306a36Sopenharmony_ci			ena_xdp_register_rxq_info(rx_ring);
53262306a36Sopenharmony_ci			rx_ring->rx_headroom = XDP_PACKET_HEADROOM;
53362306a36Sopenharmony_ci		} else if (old_bpf_prog && !prog) {
53462306a36Sopenharmony_ci			ena_xdp_unregister_rxq_info(rx_ring);
53562306a36Sopenharmony_ci			rx_ring->rx_headroom = NET_SKB_PAD;
53662306a36Sopenharmony_ci		}
53762306a36Sopenharmony_ci	}
53862306a36Sopenharmony_ci}
53962306a36Sopenharmony_ci
54062306a36Sopenharmony_cistatic void ena_xdp_exchange_program(struct ena_adapter *adapter,
54162306a36Sopenharmony_ci				     struct bpf_prog *prog)
54262306a36Sopenharmony_ci{
54362306a36Sopenharmony_ci	struct bpf_prog *old_bpf_prog = xchg(&adapter->xdp_bpf_prog, prog);
54462306a36Sopenharmony_ci
54562306a36Sopenharmony_ci	ena_xdp_exchange_program_rx_in_range(adapter,
54662306a36Sopenharmony_ci					     prog,
54762306a36Sopenharmony_ci					     0,
54862306a36Sopenharmony_ci					     adapter->num_io_queues);
54962306a36Sopenharmony_ci
55062306a36Sopenharmony_ci	if (old_bpf_prog)
55162306a36Sopenharmony_ci		bpf_prog_put(old_bpf_prog);
55262306a36Sopenharmony_ci}
55362306a36Sopenharmony_ci
55462306a36Sopenharmony_cistatic int ena_destroy_and_free_all_xdp_queues(struct ena_adapter *adapter)
55562306a36Sopenharmony_ci{
55662306a36Sopenharmony_ci	bool was_up;
55762306a36Sopenharmony_ci	int rc;
55862306a36Sopenharmony_ci
55962306a36Sopenharmony_ci	was_up = test_bit(ENA_FLAG_DEV_UP, &adapter->flags);
56062306a36Sopenharmony_ci
56162306a36Sopenharmony_ci	if (was_up)
56262306a36Sopenharmony_ci		ena_down(adapter);
56362306a36Sopenharmony_ci
56462306a36Sopenharmony_ci	adapter->xdp_first_ring = 0;
56562306a36Sopenharmony_ci	adapter->xdp_num_queues = 0;
56662306a36Sopenharmony_ci	ena_xdp_exchange_program(adapter, NULL);
56762306a36Sopenharmony_ci	if (was_up) {
56862306a36Sopenharmony_ci		rc = ena_up(adapter);
56962306a36Sopenharmony_ci		if (rc)
57062306a36Sopenharmony_ci			return rc;
57162306a36Sopenharmony_ci	}
57262306a36Sopenharmony_ci	return 0;
57362306a36Sopenharmony_ci}
57462306a36Sopenharmony_ci
57562306a36Sopenharmony_cistatic int ena_xdp_set(struct net_device *netdev, struct netdev_bpf *bpf)
57662306a36Sopenharmony_ci{
57762306a36Sopenharmony_ci	struct ena_adapter *adapter = netdev_priv(netdev);
57862306a36Sopenharmony_ci	struct bpf_prog *prog = bpf->prog;
57962306a36Sopenharmony_ci	struct bpf_prog *old_bpf_prog;
58062306a36Sopenharmony_ci	int rc, prev_mtu;
58162306a36Sopenharmony_ci	bool is_up;
58262306a36Sopenharmony_ci
58362306a36Sopenharmony_ci	is_up = test_bit(ENA_FLAG_DEV_UP, &adapter->flags);
58462306a36Sopenharmony_ci	rc = ena_xdp_allowed(adapter);
58562306a36Sopenharmony_ci	if (rc == ENA_XDP_ALLOWED) {
58662306a36Sopenharmony_ci		old_bpf_prog = adapter->xdp_bpf_prog;
58762306a36Sopenharmony_ci		if (prog) {
58862306a36Sopenharmony_ci			if (!is_up) {
58962306a36Sopenharmony_ci				ena_init_all_xdp_queues(adapter);
59062306a36Sopenharmony_ci			} else if (!old_bpf_prog) {
59162306a36Sopenharmony_ci				ena_down(adapter);
59262306a36Sopenharmony_ci				ena_init_all_xdp_queues(adapter);
59362306a36Sopenharmony_ci			}
59462306a36Sopenharmony_ci			ena_xdp_exchange_program(adapter, prog);
59562306a36Sopenharmony_ci
59662306a36Sopenharmony_ci			if (is_up && !old_bpf_prog) {
59762306a36Sopenharmony_ci				rc = ena_up(adapter);
59862306a36Sopenharmony_ci				if (rc)
59962306a36Sopenharmony_ci					return rc;
60062306a36Sopenharmony_ci			}
60162306a36Sopenharmony_ci			xdp_features_set_redirect_target(netdev, false);
60262306a36Sopenharmony_ci		} else if (old_bpf_prog) {
60362306a36Sopenharmony_ci			xdp_features_clear_redirect_target(netdev);
60462306a36Sopenharmony_ci			rc = ena_destroy_and_free_all_xdp_queues(adapter);
60562306a36Sopenharmony_ci			if (rc)
60662306a36Sopenharmony_ci				return rc;
60762306a36Sopenharmony_ci		}
60862306a36Sopenharmony_ci
60962306a36Sopenharmony_ci		prev_mtu = netdev->max_mtu;
61062306a36Sopenharmony_ci		netdev->max_mtu = prog ? ENA_XDP_MAX_MTU : adapter->max_mtu;
61162306a36Sopenharmony_ci
61262306a36Sopenharmony_ci		if (!old_bpf_prog)
61362306a36Sopenharmony_ci			netif_info(adapter, drv, adapter->netdev,
61462306a36Sopenharmony_ci				   "XDP program is set, changing the max_mtu from %d to %d",
61562306a36Sopenharmony_ci				   prev_mtu, netdev->max_mtu);
61662306a36Sopenharmony_ci
61762306a36Sopenharmony_ci	} else if (rc == ENA_XDP_CURRENT_MTU_TOO_LARGE) {
61862306a36Sopenharmony_ci		netif_err(adapter, drv, adapter->netdev,
61962306a36Sopenharmony_ci			  "Failed to set xdp program, the current MTU (%d) is larger than the maximum allowed MTU (%lu) while xdp is on",
62062306a36Sopenharmony_ci			  netdev->mtu, ENA_XDP_MAX_MTU);
62162306a36Sopenharmony_ci		NL_SET_ERR_MSG_MOD(bpf->extack,
62262306a36Sopenharmony_ci				   "Failed to set xdp program, the current MTU is larger than the maximum allowed MTU. Check the dmesg for more info");
62362306a36Sopenharmony_ci		return -EINVAL;
62462306a36Sopenharmony_ci	} else if (rc == ENA_XDP_NO_ENOUGH_QUEUES) {
62562306a36Sopenharmony_ci		netif_err(adapter, drv, adapter->netdev,
62662306a36Sopenharmony_ci			  "Failed to set xdp program, the Rx/Tx channel count should be at most half of the maximum allowed channel count. The current queue count (%d), the maximal queue count (%d)\n",
62762306a36Sopenharmony_ci			  adapter->num_io_queues, adapter->max_num_io_queues);
62862306a36Sopenharmony_ci		NL_SET_ERR_MSG_MOD(bpf->extack,
62962306a36Sopenharmony_ci				   "Failed to set xdp program, there is no enough space for allocating XDP queues, Check the dmesg for more info");
63062306a36Sopenharmony_ci		return -EINVAL;
63162306a36Sopenharmony_ci	}
63262306a36Sopenharmony_ci
63362306a36Sopenharmony_ci	return 0;
63462306a36Sopenharmony_ci}
63562306a36Sopenharmony_ci
63662306a36Sopenharmony_ci/* This is the main xdp callback, it's used by the kernel to set/unset the xdp
63762306a36Sopenharmony_ci * program as well as to query the current xdp program id.
63862306a36Sopenharmony_ci */
63962306a36Sopenharmony_cistatic int ena_xdp(struct net_device *netdev, struct netdev_bpf *bpf)
64062306a36Sopenharmony_ci{
64162306a36Sopenharmony_ci	switch (bpf->command) {
64262306a36Sopenharmony_ci	case XDP_SETUP_PROG:
64362306a36Sopenharmony_ci		return ena_xdp_set(netdev, bpf);
64462306a36Sopenharmony_ci	default:
64562306a36Sopenharmony_ci		return -EINVAL;
64662306a36Sopenharmony_ci	}
64762306a36Sopenharmony_ci	return 0;
64862306a36Sopenharmony_ci}
64962306a36Sopenharmony_ci
65062306a36Sopenharmony_cistatic int ena_init_rx_cpu_rmap(struct ena_adapter *adapter)
65162306a36Sopenharmony_ci{
65262306a36Sopenharmony_ci#ifdef CONFIG_RFS_ACCEL
65362306a36Sopenharmony_ci	u32 i;
65462306a36Sopenharmony_ci	int rc;
65562306a36Sopenharmony_ci
65662306a36Sopenharmony_ci	adapter->netdev->rx_cpu_rmap = alloc_irq_cpu_rmap(adapter->num_io_queues);
65762306a36Sopenharmony_ci	if (!adapter->netdev->rx_cpu_rmap)
65862306a36Sopenharmony_ci		return -ENOMEM;
65962306a36Sopenharmony_ci	for (i = 0; i < adapter->num_io_queues; i++) {
66062306a36Sopenharmony_ci		int irq_idx = ENA_IO_IRQ_IDX(i);
66162306a36Sopenharmony_ci
66262306a36Sopenharmony_ci		rc = irq_cpu_rmap_add(adapter->netdev->rx_cpu_rmap,
66362306a36Sopenharmony_ci				      pci_irq_vector(adapter->pdev, irq_idx));
66462306a36Sopenharmony_ci		if (rc) {
66562306a36Sopenharmony_ci			free_irq_cpu_rmap(adapter->netdev->rx_cpu_rmap);
66662306a36Sopenharmony_ci			adapter->netdev->rx_cpu_rmap = NULL;
66762306a36Sopenharmony_ci			return rc;
66862306a36Sopenharmony_ci		}
66962306a36Sopenharmony_ci	}
67062306a36Sopenharmony_ci#endif /* CONFIG_RFS_ACCEL */
67162306a36Sopenharmony_ci	return 0;
67262306a36Sopenharmony_ci}
67362306a36Sopenharmony_ci
67462306a36Sopenharmony_cistatic void ena_init_io_rings_common(struct ena_adapter *adapter,
67562306a36Sopenharmony_ci				     struct ena_ring *ring, u16 qid)
67662306a36Sopenharmony_ci{
67762306a36Sopenharmony_ci	ring->qid = qid;
67862306a36Sopenharmony_ci	ring->pdev = adapter->pdev;
67962306a36Sopenharmony_ci	ring->dev = &adapter->pdev->dev;
68062306a36Sopenharmony_ci	ring->netdev = adapter->netdev;
68162306a36Sopenharmony_ci	ring->napi = &adapter->ena_napi[qid].napi;
68262306a36Sopenharmony_ci	ring->adapter = adapter;
68362306a36Sopenharmony_ci	ring->ena_dev = adapter->ena_dev;
68462306a36Sopenharmony_ci	ring->per_napi_packets = 0;
68562306a36Sopenharmony_ci	ring->cpu = 0;
68662306a36Sopenharmony_ci	ring->numa_node = 0;
68762306a36Sopenharmony_ci	ring->no_interrupt_event_cnt = 0;
68862306a36Sopenharmony_ci	u64_stats_init(&ring->syncp);
68962306a36Sopenharmony_ci}
69062306a36Sopenharmony_ci
69162306a36Sopenharmony_cistatic void ena_init_io_rings(struct ena_adapter *adapter,
69262306a36Sopenharmony_ci			      int first_index, int count)
69362306a36Sopenharmony_ci{
69462306a36Sopenharmony_ci	struct ena_com_dev *ena_dev;
69562306a36Sopenharmony_ci	struct ena_ring *txr, *rxr;
69662306a36Sopenharmony_ci	int i;
69762306a36Sopenharmony_ci
69862306a36Sopenharmony_ci	ena_dev = adapter->ena_dev;
69962306a36Sopenharmony_ci
70062306a36Sopenharmony_ci	for (i = first_index; i < first_index + count; i++) {
70162306a36Sopenharmony_ci		txr = &adapter->tx_ring[i];
70262306a36Sopenharmony_ci		rxr = &adapter->rx_ring[i];
70362306a36Sopenharmony_ci
70462306a36Sopenharmony_ci		/* TX common ring state */
70562306a36Sopenharmony_ci		ena_init_io_rings_common(adapter, txr, i);
70662306a36Sopenharmony_ci
70762306a36Sopenharmony_ci		/* TX specific ring state */
70862306a36Sopenharmony_ci		txr->ring_size = adapter->requested_tx_ring_size;
70962306a36Sopenharmony_ci		txr->tx_max_header_size = ena_dev->tx_max_header_size;
71062306a36Sopenharmony_ci		txr->tx_mem_queue_type = ena_dev->tx_mem_queue_type;
71162306a36Sopenharmony_ci		txr->sgl_size = adapter->max_tx_sgl_size;
71262306a36Sopenharmony_ci		txr->smoothed_interval =
71362306a36Sopenharmony_ci			ena_com_get_nonadaptive_moderation_interval_tx(ena_dev);
71462306a36Sopenharmony_ci		txr->disable_meta_caching = adapter->disable_meta_caching;
71562306a36Sopenharmony_ci		spin_lock_init(&txr->xdp_tx_lock);
71662306a36Sopenharmony_ci
71762306a36Sopenharmony_ci		/* Don't init RX queues for xdp queues */
71862306a36Sopenharmony_ci		if (!ENA_IS_XDP_INDEX(adapter, i)) {
71962306a36Sopenharmony_ci			/* RX common ring state */
72062306a36Sopenharmony_ci			ena_init_io_rings_common(adapter, rxr, i);
72162306a36Sopenharmony_ci
72262306a36Sopenharmony_ci			/* RX specific ring state */
72362306a36Sopenharmony_ci			rxr->ring_size = adapter->requested_rx_ring_size;
72462306a36Sopenharmony_ci			rxr->rx_copybreak = adapter->rx_copybreak;
72562306a36Sopenharmony_ci			rxr->sgl_size = adapter->max_rx_sgl_size;
72662306a36Sopenharmony_ci			rxr->smoothed_interval =
72762306a36Sopenharmony_ci				ena_com_get_nonadaptive_moderation_interval_rx(ena_dev);
72862306a36Sopenharmony_ci			rxr->empty_rx_queue = 0;
72962306a36Sopenharmony_ci			rxr->rx_headroom = NET_SKB_PAD;
73062306a36Sopenharmony_ci			adapter->ena_napi[i].dim.mode = DIM_CQ_PERIOD_MODE_START_FROM_EQE;
73162306a36Sopenharmony_ci			rxr->xdp_ring = &adapter->tx_ring[i + adapter->num_io_queues];
73262306a36Sopenharmony_ci		}
73362306a36Sopenharmony_ci	}
73462306a36Sopenharmony_ci}
73562306a36Sopenharmony_ci
73662306a36Sopenharmony_ci/* ena_setup_tx_resources - allocate I/O Tx resources (Descriptors)
73762306a36Sopenharmony_ci * @adapter: network interface device structure
73862306a36Sopenharmony_ci * @qid: queue index
73962306a36Sopenharmony_ci *
74062306a36Sopenharmony_ci * Return 0 on success, negative on failure
74162306a36Sopenharmony_ci */
74262306a36Sopenharmony_cistatic int ena_setup_tx_resources(struct ena_adapter *adapter, int qid)
74362306a36Sopenharmony_ci{
74462306a36Sopenharmony_ci	struct ena_ring *tx_ring = &adapter->tx_ring[qid];
74562306a36Sopenharmony_ci	struct ena_irq *ena_irq = &adapter->irq_tbl[ENA_IO_IRQ_IDX(qid)];
74662306a36Sopenharmony_ci	int size, i, node;
74762306a36Sopenharmony_ci
74862306a36Sopenharmony_ci	if (tx_ring->tx_buffer_info) {
74962306a36Sopenharmony_ci		netif_err(adapter, ifup,
75062306a36Sopenharmony_ci			  adapter->netdev, "tx_buffer_info info is not NULL");
75162306a36Sopenharmony_ci		return -EEXIST;
75262306a36Sopenharmony_ci	}
75362306a36Sopenharmony_ci
75462306a36Sopenharmony_ci	size = sizeof(struct ena_tx_buffer) * tx_ring->ring_size;
75562306a36Sopenharmony_ci	node = cpu_to_node(ena_irq->cpu);
75662306a36Sopenharmony_ci
75762306a36Sopenharmony_ci	tx_ring->tx_buffer_info = vzalloc_node(size, node);
75862306a36Sopenharmony_ci	if (!tx_ring->tx_buffer_info) {
75962306a36Sopenharmony_ci		tx_ring->tx_buffer_info = vzalloc(size);
76062306a36Sopenharmony_ci		if (!tx_ring->tx_buffer_info)
76162306a36Sopenharmony_ci			goto err_tx_buffer_info;
76262306a36Sopenharmony_ci	}
76362306a36Sopenharmony_ci
76462306a36Sopenharmony_ci	size = sizeof(u16) * tx_ring->ring_size;
76562306a36Sopenharmony_ci	tx_ring->free_ids = vzalloc_node(size, node);
76662306a36Sopenharmony_ci	if (!tx_ring->free_ids) {
76762306a36Sopenharmony_ci		tx_ring->free_ids = vzalloc(size);
76862306a36Sopenharmony_ci		if (!tx_ring->free_ids)
76962306a36Sopenharmony_ci			goto err_tx_free_ids;
77062306a36Sopenharmony_ci	}
77162306a36Sopenharmony_ci
77262306a36Sopenharmony_ci	size = tx_ring->tx_max_header_size;
77362306a36Sopenharmony_ci	tx_ring->push_buf_intermediate_buf = vzalloc_node(size, node);
77462306a36Sopenharmony_ci	if (!tx_ring->push_buf_intermediate_buf) {
77562306a36Sopenharmony_ci		tx_ring->push_buf_intermediate_buf = vzalloc(size);
77662306a36Sopenharmony_ci		if (!tx_ring->push_buf_intermediate_buf)
77762306a36Sopenharmony_ci			goto err_push_buf_intermediate_buf;
77862306a36Sopenharmony_ci	}
77962306a36Sopenharmony_ci
78062306a36Sopenharmony_ci	/* Req id ring for TX out of order completions */
78162306a36Sopenharmony_ci	for (i = 0; i < tx_ring->ring_size; i++)
78262306a36Sopenharmony_ci		tx_ring->free_ids[i] = i;
78362306a36Sopenharmony_ci
78462306a36Sopenharmony_ci	/* Reset tx statistics */
78562306a36Sopenharmony_ci	memset(&tx_ring->tx_stats, 0x0, sizeof(tx_ring->tx_stats));
78662306a36Sopenharmony_ci
78762306a36Sopenharmony_ci	tx_ring->next_to_use = 0;
78862306a36Sopenharmony_ci	tx_ring->next_to_clean = 0;
78962306a36Sopenharmony_ci	tx_ring->cpu = ena_irq->cpu;
79062306a36Sopenharmony_ci	tx_ring->numa_node = node;
79162306a36Sopenharmony_ci	return 0;
79262306a36Sopenharmony_ci
79362306a36Sopenharmony_cierr_push_buf_intermediate_buf:
79462306a36Sopenharmony_ci	vfree(tx_ring->free_ids);
79562306a36Sopenharmony_ci	tx_ring->free_ids = NULL;
79662306a36Sopenharmony_cierr_tx_free_ids:
79762306a36Sopenharmony_ci	vfree(tx_ring->tx_buffer_info);
79862306a36Sopenharmony_ci	tx_ring->tx_buffer_info = NULL;
79962306a36Sopenharmony_cierr_tx_buffer_info:
80062306a36Sopenharmony_ci	return -ENOMEM;
80162306a36Sopenharmony_ci}
80262306a36Sopenharmony_ci
80362306a36Sopenharmony_ci/* ena_free_tx_resources - Free I/O Tx Resources per Queue
80462306a36Sopenharmony_ci * @adapter: network interface device structure
80562306a36Sopenharmony_ci * @qid: queue index
80662306a36Sopenharmony_ci *
80762306a36Sopenharmony_ci * Free all transmit software resources
80862306a36Sopenharmony_ci */
80962306a36Sopenharmony_cistatic void ena_free_tx_resources(struct ena_adapter *adapter, int qid)
81062306a36Sopenharmony_ci{
81162306a36Sopenharmony_ci	struct ena_ring *tx_ring = &adapter->tx_ring[qid];
81262306a36Sopenharmony_ci
81362306a36Sopenharmony_ci	vfree(tx_ring->tx_buffer_info);
81462306a36Sopenharmony_ci	tx_ring->tx_buffer_info = NULL;
81562306a36Sopenharmony_ci
81662306a36Sopenharmony_ci	vfree(tx_ring->free_ids);
81762306a36Sopenharmony_ci	tx_ring->free_ids = NULL;
81862306a36Sopenharmony_ci
81962306a36Sopenharmony_ci	vfree(tx_ring->push_buf_intermediate_buf);
82062306a36Sopenharmony_ci	tx_ring->push_buf_intermediate_buf = NULL;
82162306a36Sopenharmony_ci}
82262306a36Sopenharmony_ci
82362306a36Sopenharmony_cistatic int ena_setup_tx_resources_in_range(struct ena_adapter *adapter,
82462306a36Sopenharmony_ci					   int first_index,
82562306a36Sopenharmony_ci					   int count)
82662306a36Sopenharmony_ci{
82762306a36Sopenharmony_ci	int i, rc = 0;
82862306a36Sopenharmony_ci
82962306a36Sopenharmony_ci	for (i = first_index; i < first_index + count; i++) {
83062306a36Sopenharmony_ci		rc = ena_setup_tx_resources(adapter, i);
83162306a36Sopenharmony_ci		if (rc)
83262306a36Sopenharmony_ci			goto err_setup_tx;
83362306a36Sopenharmony_ci	}
83462306a36Sopenharmony_ci
83562306a36Sopenharmony_ci	return 0;
83662306a36Sopenharmony_ci
83762306a36Sopenharmony_cierr_setup_tx:
83862306a36Sopenharmony_ci
83962306a36Sopenharmony_ci	netif_err(adapter, ifup, adapter->netdev,
84062306a36Sopenharmony_ci		  "Tx queue %d: allocation failed\n", i);
84162306a36Sopenharmony_ci
84262306a36Sopenharmony_ci	/* rewind the index freeing the rings as we go */
84362306a36Sopenharmony_ci	while (first_index < i--)
84462306a36Sopenharmony_ci		ena_free_tx_resources(adapter, i);
84562306a36Sopenharmony_ci	return rc;
84662306a36Sopenharmony_ci}
84762306a36Sopenharmony_ci
84862306a36Sopenharmony_cistatic void ena_free_all_io_tx_resources_in_range(struct ena_adapter *adapter,
84962306a36Sopenharmony_ci						  int first_index, int count)
85062306a36Sopenharmony_ci{
85162306a36Sopenharmony_ci	int i;
85262306a36Sopenharmony_ci
85362306a36Sopenharmony_ci	for (i = first_index; i < first_index + count; i++)
85462306a36Sopenharmony_ci		ena_free_tx_resources(adapter, i);
85562306a36Sopenharmony_ci}
85662306a36Sopenharmony_ci
85762306a36Sopenharmony_ci/* ena_free_all_io_tx_resources - Free I/O Tx Resources for All Queues
85862306a36Sopenharmony_ci * @adapter: board private structure
85962306a36Sopenharmony_ci *
86062306a36Sopenharmony_ci * Free all transmit software resources
86162306a36Sopenharmony_ci */
86262306a36Sopenharmony_cistatic void ena_free_all_io_tx_resources(struct ena_adapter *adapter)
86362306a36Sopenharmony_ci{
86462306a36Sopenharmony_ci	ena_free_all_io_tx_resources_in_range(adapter,
86562306a36Sopenharmony_ci					      0,
86662306a36Sopenharmony_ci					      adapter->xdp_num_queues +
86762306a36Sopenharmony_ci					      adapter->num_io_queues);
86862306a36Sopenharmony_ci}
86962306a36Sopenharmony_ci
87062306a36Sopenharmony_ci/* ena_setup_rx_resources - allocate I/O Rx resources (Descriptors)
87162306a36Sopenharmony_ci * @adapter: network interface device structure
87262306a36Sopenharmony_ci * @qid: queue index
87362306a36Sopenharmony_ci *
87462306a36Sopenharmony_ci * Returns 0 on success, negative on failure
87562306a36Sopenharmony_ci */
87662306a36Sopenharmony_cistatic int ena_setup_rx_resources(struct ena_adapter *adapter,
87762306a36Sopenharmony_ci				  u32 qid)
87862306a36Sopenharmony_ci{
87962306a36Sopenharmony_ci	struct ena_ring *rx_ring = &adapter->rx_ring[qid];
88062306a36Sopenharmony_ci	struct ena_irq *ena_irq = &adapter->irq_tbl[ENA_IO_IRQ_IDX(qid)];
88162306a36Sopenharmony_ci	int size, node, i;
88262306a36Sopenharmony_ci
88362306a36Sopenharmony_ci	if (rx_ring->rx_buffer_info) {
88462306a36Sopenharmony_ci		netif_err(adapter, ifup, adapter->netdev,
88562306a36Sopenharmony_ci			  "rx_buffer_info is not NULL");
88662306a36Sopenharmony_ci		return -EEXIST;
88762306a36Sopenharmony_ci	}
88862306a36Sopenharmony_ci
88962306a36Sopenharmony_ci	/* alloc extra element so in rx path
89062306a36Sopenharmony_ci	 * we can always prefetch rx_info + 1
89162306a36Sopenharmony_ci	 */
89262306a36Sopenharmony_ci	size = sizeof(struct ena_rx_buffer) * (rx_ring->ring_size + 1);
89362306a36Sopenharmony_ci	node = cpu_to_node(ena_irq->cpu);
89462306a36Sopenharmony_ci
89562306a36Sopenharmony_ci	rx_ring->rx_buffer_info = vzalloc_node(size, node);
89662306a36Sopenharmony_ci	if (!rx_ring->rx_buffer_info) {
89762306a36Sopenharmony_ci		rx_ring->rx_buffer_info = vzalloc(size);
89862306a36Sopenharmony_ci		if (!rx_ring->rx_buffer_info)
89962306a36Sopenharmony_ci			return -ENOMEM;
90062306a36Sopenharmony_ci	}
90162306a36Sopenharmony_ci
90262306a36Sopenharmony_ci	size = sizeof(u16) * rx_ring->ring_size;
90362306a36Sopenharmony_ci	rx_ring->free_ids = vzalloc_node(size, node);
90462306a36Sopenharmony_ci	if (!rx_ring->free_ids) {
90562306a36Sopenharmony_ci		rx_ring->free_ids = vzalloc(size);
90662306a36Sopenharmony_ci		if (!rx_ring->free_ids) {
90762306a36Sopenharmony_ci			vfree(rx_ring->rx_buffer_info);
90862306a36Sopenharmony_ci			rx_ring->rx_buffer_info = NULL;
90962306a36Sopenharmony_ci			return -ENOMEM;
91062306a36Sopenharmony_ci		}
91162306a36Sopenharmony_ci	}
91262306a36Sopenharmony_ci
91362306a36Sopenharmony_ci	/* Req id ring for receiving RX pkts out of order */
91462306a36Sopenharmony_ci	for (i = 0; i < rx_ring->ring_size; i++)
91562306a36Sopenharmony_ci		rx_ring->free_ids[i] = i;
91662306a36Sopenharmony_ci
91762306a36Sopenharmony_ci	/* Reset rx statistics */
91862306a36Sopenharmony_ci	memset(&rx_ring->rx_stats, 0x0, sizeof(rx_ring->rx_stats));
91962306a36Sopenharmony_ci
92062306a36Sopenharmony_ci	rx_ring->next_to_clean = 0;
92162306a36Sopenharmony_ci	rx_ring->next_to_use = 0;
92262306a36Sopenharmony_ci	rx_ring->cpu = ena_irq->cpu;
92362306a36Sopenharmony_ci	rx_ring->numa_node = node;
92462306a36Sopenharmony_ci
92562306a36Sopenharmony_ci	return 0;
92662306a36Sopenharmony_ci}
92762306a36Sopenharmony_ci
92862306a36Sopenharmony_ci/* ena_free_rx_resources - Free I/O Rx Resources
92962306a36Sopenharmony_ci * @adapter: network interface device structure
93062306a36Sopenharmony_ci * @qid: queue index
93162306a36Sopenharmony_ci *
93262306a36Sopenharmony_ci * Free all receive software resources
93362306a36Sopenharmony_ci */
93462306a36Sopenharmony_cistatic void ena_free_rx_resources(struct ena_adapter *adapter,
93562306a36Sopenharmony_ci				  u32 qid)
93662306a36Sopenharmony_ci{
93762306a36Sopenharmony_ci	struct ena_ring *rx_ring = &adapter->rx_ring[qid];
93862306a36Sopenharmony_ci
93962306a36Sopenharmony_ci	vfree(rx_ring->rx_buffer_info);
94062306a36Sopenharmony_ci	rx_ring->rx_buffer_info = NULL;
94162306a36Sopenharmony_ci
94262306a36Sopenharmony_ci	vfree(rx_ring->free_ids);
94362306a36Sopenharmony_ci	rx_ring->free_ids = NULL;
94462306a36Sopenharmony_ci}
94562306a36Sopenharmony_ci
94662306a36Sopenharmony_ci/* ena_setup_all_rx_resources - allocate I/O Rx queues resources for all queues
94762306a36Sopenharmony_ci * @adapter: board private structure
94862306a36Sopenharmony_ci *
94962306a36Sopenharmony_ci * Return 0 on success, negative on failure
95062306a36Sopenharmony_ci */
95162306a36Sopenharmony_cistatic int ena_setup_all_rx_resources(struct ena_adapter *adapter)
95262306a36Sopenharmony_ci{
95362306a36Sopenharmony_ci	int i, rc = 0;
95462306a36Sopenharmony_ci
95562306a36Sopenharmony_ci	for (i = 0; i < adapter->num_io_queues; i++) {
95662306a36Sopenharmony_ci		rc = ena_setup_rx_resources(adapter, i);
95762306a36Sopenharmony_ci		if (rc)
95862306a36Sopenharmony_ci			goto err_setup_rx;
95962306a36Sopenharmony_ci	}
96062306a36Sopenharmony_ci
96162306a36Sopenharmony_ci	return 0;
96262306a36Sopenharmony_ci
96362306a36Sopenharmony_cierr_setup_rx:
96462306a36Sopenharmony_ci
96562306a36Sopenharmony_ci	netif_err(adapter, ifup, adapter->netdev,
96662306a36Sopenharmony_ci		  "Rx queue %d: allocation failed\n", i);
96762306a36Sopenharmony_ci
96862306a36Sopenharmony_ci	/* rewind the index freeing the rings as we go */
96962306a36Sopenharmony_ci	while (i--)
97062306a36Sopenharmony_ci		ena_free_rx_resources(adapter, i);
97162306a36Sopenharmony_ci	return rc;
97262306a36Sopenharmony_ci}
97362306a36Sopenharmony_ci
97462306a36Sopenharmony_ci/* ena_free_all_io_rx_resources - Free I/O Rx Resources for All Queues
97562306a36Sopenharmony_ci * @adapter: board private structure
97662306a36Sopenharmony_ci *
97762306a36Sopenharmony_ci * Free all receive software resources
97862306a36Sopenharmony_ci */
97962306a36Sopenharmony_cistatic void ena_free_all_io_rx_resources(struct ena_adapter *adapter)
98062306a36Sopenharmony_ci{
98162306a36Sopenharmony_ci	int i;
98262306a36Sopenharmony_ci
98362306a36Sopenharmony_ci	for (i = 0; i < adapter->num_io_queues; i++)
98462306a36Sopenharmony_ci		ena_free_rx_resources(adapter, i);
98562306a36Sopenharmony_ci}
98662306a36Sopenharmony_ci
98762306a36Sopenharmony_cistatic struct page *ena_alloc_map_page(struct ena_ring *rx_ring,
98862306a36Sopenharmony_ci				       dma_addr_t *dma)
98962306a36Sopenharmony_ci{
99062306a36Sopenharmony_ci	struct page *page;
99162306a36Sopenharmony_ci
99262306a36Sopenharmony_ci	/* This would allocate the page on the same NUMA node the executing code
99362306a36Sopenharmony_ci	 * is running on.
99462306a36Sopenharmony_ci	 */
99562306a36Sopenharmony_ci	page = dev_alloc_page();
99662306a36Sopenharmony_ci	if (!page) {
99762306a36Sopenharmony_ci		ena_increase_stat(&rx_ring->rx_stats.page_alloc_fail, 1,
99862306a36Sopenharmony_ci				  &rx_ring->syncp);
99962306a36Sopenharmony_ci		return ERR_PTR(-ENOSPC);
100062306a36Sopenharmony_ci	}
100162306a36Sopenharmony_ci
100262306a36Sopenharmony_ci	/* To enable NIC-side port-mirroring, AKA SPAN port,
100362306a36Sopenharmony_ci	 * we make the buffer readable from the nic as well
100462306a36Sopenharmony_ci	 */
100562306a36Sopenharmony_ci	*dma = dma_map_page(rx_ring->dev, page, 0, ENA_PAGE_SIZE,
100662306a36Sopenharmony_ci			    DMA_BIDIRECTIONAL);
100762306a36Sopenharmony_ci	if (unlikely(dma_mapping_error(rx_ring->dev, *dma))) {
100862306a36Sopenharmony_ci		ena_increase_stat(&rx_ring->rx_stats.dma_mapping_err, 1,
100962306a36Sopenharmony_ci				  &rx_ring->syncp);
101062306a36Sopenharmony_ci		__free_page(page);
101162306a36Sopenharmony_ci		return ERR_PTR(-EIO);
101262306a36Sopenharmony_ci	}
101362306a36Sopenharmony_ci
101462306a36Sopenharmony_ci	return page;
101562306a36Sopenharmony_ci}
101662306a36Sopenharmony_ci
101762306a36Sopenharmony_cistatic int ena_alloc_rx_buffer(struct ena_ring *rx_ring,
101862306a36Sopenharmony_ci			       struct ena_rx_buffer *rx_info)
101962306a36Sopenharmony_ci{
102062306a36Sopenharmony_ci	int headroom = rx_ring->rx_headroom;
102162306a36Sopenharmony_ci	struct ena_com_buf *ena_buf;
102262306a36Sopenharmony_ci	struct page *page;
102362306a36Sopenharmony_ci	dma_addr_t dma;
102462306a36Sopenharmony_ci	int tailroom;
102562306a36Sopenharmony_ci
102662306a36Sopenharmony_ci	/* restore page offset value in case it has been changed by device */
102762306a36Sopenharmony_ci	rx_info->buf_offset = headroom;
102862306a36Sopenharmony_ci
102962306a36Sopenharmony_ci	/* if previous allocated page is not used */
103062306a36Sopenharmony_ci	if (unlikely(rx_info->page))
103162306a36Sopenharmony_ci		return 0;
103262306a36Sopenharmony_ci
103362306a36Sopenharmony_ci	/* We handle DMA here */
103462306a36Sopenharmony_ci	page = ena_alloc_map_page(rx_ring, &dma);
103562306a36Sopenharmony_ci	if (unlikely(IS_ERR(page)))
103662306a36Sopenharmony_ci		return PTR_ERR(page);
103762306a36Sopenharmony_ci
103862306a36Sopenharmony_ci	netif_dbg(rx_ring->adapter, rx_status, rx_ring->netdev,
103962306a36Sopenharmony_ci		  "Allocate page %p, rx_info %p\n", page, rx_info);
104062306a36Sopenharmony_ci
104162306a36Sopenharmony_ci	tailroom = SKB_DATA_ALIGN(sizeof(struct skb_shared_info));
104262306a36Sopenharmony_ci
104362306a36Sopenharmony_ci	rx_info->page = page;
104462306a36Sopenharmony_ci	rx_info->dma_addr = dma;
104562306a36Sopenharmony_ci	rx_info->page_offset = 0;
104662306a36Sopenharmony_ci	ena_buf = &rx_info->ena_buf;
104762306a36Sopenharmony_ci	ena_buf->paddr = dma + headroom;
104862306a36Sopenharmony_ci	ena_buf->len = ENA_PAGE_SIZE - headroom - tailroom;
104962306a36Sopenharmony_ci
105062306a36Sopenharmony_ci	return 0;
105162306a36Sopenharmony_ci}
105262306a36Sopenharmony_ci
105362306a36Sopenharmony_cistatic void ena_unmap_rx_buff_attrs(struct ena_ring *rx_ring,
105462306a36Sopenharmony_ci				    struct ena_rx_buffer *rx_info,
105562306a36Sopenharmony_ci				    unsigned long attrs)
105662306a36Sopenharmony_ci{
105762306a36Sopenharmony_ci	dma_unmap_page_attrs(rx_ring->dev, rx_info->dma_addr, ENA_PAGE_SIZE,
105862306a36Sopenharmony_ci			     DMA_BIDIRECTIONAL, attrs);
105962306a36Sopenharmony_ci}
106062306a36Sopenharmony_ci
106162306a36Sopenharmony_cistatic void ena_free_rx_page(struct ena_ring *rx_ring,
106262306a36Sopenharmony_ci			     struct ena_rx_buffer *rx_info)
106362306a36Sopenharmony_ci{
106462306a36Sopenharmony_ci	struct page *page = rx_info->page;
106562306a36Sopenharmony_ci
106662306a36Sopenharmony_ci	if (unlikely(!page)) {
106762306a36Sopenharmony_ci		netif_warn(rx_ring->adapter, rx_err, rx_ring->netdev,
106862306a36Sopenharmony_ci			   "Trying to free unallocated buffer\n");
106962306a36Sopenharmony_ci		return;
107062306a36Sopenharmony_ci	}
107162306a36Sopenharmony_ci
107262306a36Sopenharmony_ci	ena_unmap_rx_buff_attrs(rx_ring, rx_info, 0);
107362306a36Sopenharmony_ci
107462306a36Sopenharmony_ci	__free_page(page);
107562306a36Sopenharmony_ci	rx_info->page = NULL;
107662306a36Sopenharmony_ci}
107762306a36Sopenharmony_ci
107862306a36Sopenharmony_cistatic int ena_refill_rx_bufs(struct ena_ring *rx_ring, u32 num)
107962306a36Sopenharmony_ci{
108062306a36Sopenharmony_ci	u16 next_to_use, req_id;
108162306a36Sopenharmony_ci	u32 i;
108262306a36Sopenharmony_ci	int rc;
108362306a36Sopenharmony_ci
108462306a36Sopenharmony_ci	next_to_use = rx_ring->next_to_use;
108562306a36Sopenharmony_ci
108662306a36Sopenharmony_ci	for (i = 0; i < num; i++) {
108762306a36Sopenharmony_ci		struct ena_rx_buffer *rx_info;
108862306a36Sopenharmony_ci
108962306a36Sopenharmony_ci		req_id = rx_ring->free_ids[next_to_use];
109062306a36Sopenharmony_ci
109162306a36Sopenharmony_ci		rx_info = &rx_ring->rx_buffer_info[req_id];
109262306a36Sopenharmony_ci
109362306a36Sopenharmony_ci		rc = ena_alloc_rx_buffer(rx_ring, rx_info);
109462306a36Sopenharmony_ci		if (unlikely(rc < 0)) {
109562306a36Sopenharmony_ci			netif_warn(rx_ring->adapter, rx_err, rx_ring->netdev,
109662306a36Sopenharmony_ci				   "Failed to allocate buffer for rx queue %d\n",
109762306a36Sopenharmony_ci				   rx_ring->qid);
109862306a36Sopenharmony_ci			break;
109962306a36Sopenharmony_ci		}
110062306a36Sopenharmony_ci		rc = ena_com_add_single_rx_desc(rx_ring->ena_com_io_sq,
110162306a36Sopenharmony_ci						&rx_info->ena_buf,
110262306a36Sopenharmony_ci						req_id);
110362306a36Sopenharmony_ci		if (unlikely(rc)) {
110462306a36Sopenharmony_ci			netif_warn(rx_ring->adapter, rx_status, rx_ring->netdev,
110562306a36Sopenharmony_ci				   "Failed to add buffer for rx queue %d\n",
110662306a36Sopenharmony_ci				   rx_ring->qid);
110762306a36Sopenharmony_ci			break;
110862306a36Sopenharmony_ci		}
110962306a36Sopenharmony_ci		next_to_use = ENA_RX_RING_IDX_NEXT(next_to_use,
111062306a36Sopenharmony_ci						   rx_ring->ring_size);
111162306a36Sopenharmony_ci	}
111262306a36Sopenharmony_ci
111362306a36Sopenharmony_ci	if (unlikely(i < num)) {
111462306a36Sopenharmony_ci		ena_increase_stat(&rx_ring->rx_stats.refil_partial, 1,
111562306a36Sopenharmony_ci				  &rx_ring->syncp);
111662306a36Sopenharmony_ci		netif_warn(rx_ring->adapter, rx_err, rx_ring->netdev,
111762306a36Sopenharmony_ci			   "Refilled rx qid %d with only %d buffers (from %d)\n",
111862306a36Sopenharmony_ci			   rx_ring->qid, i, num);
111962306a36Sopenharmony_ci	}
112062306a36Sopenharmony_ci
112162306a36Sopenharmony_ci	/* ena_com_write_sq_doorbell issues a wmb() */
112262306a36Sopenharmony_ci	if (likely(i))
112362306a36Sopenharmony_ci		ena_com_write_sq_doorbell(rx_ring->ena_com_io_sq);
112462306a36Sopenharmony_ci
112562306a36Sopenharmony_ci	rx_ring->next_to_use = next_to_use;
112662306a36Sopenharmony_ci
112762306a36Sopenharmony_ci	return i;
112862306a36Sopenharmony_ci}
112962306a36Sopenharmony_ci
113062306a36Sopenharmony_cistatic void ena_free_rx_bufs(struct ena_adapter *adapter,
113162306a36Sopenharmony_ci			     u32 qid)
113262306a36Sopenharmony_ci{
113362306a36Sopenharmony_ci	struct ena_ring *rx_ring = &adapter->rx_ring[qid];
113462306a36Sopenharmony_ci	u32 i;
113562306a36Sopenharmony_ci
113662306a36Sopenharmony_ci	for (i = 0; i < rx_ring->ring_size; i++) {
113762306a36Sopenharmony_ci		struct ena_rx_buffer *rx_info = &rx_ring->rx_buffer_info[i];
113862306a36Sopenharmony_ci
113962306a36Sopenharmony_ci		if (rx_info->page)
114062306a36Sopenharmony_ci			ena_free_rx_page(rx_ring, rx_info);
114162306a36Sopenharmony_ci	}
114262306a36Sopenharmony_ci}
114362306a36Sopenharmony_ci
114462306a36Sopenharmony_ci/* ena_refill_all_rx_bufs - allocate all queues Rx buffers
114562306a36Sopenharmony_ci * @adapter: board private structure
114662306a36Sopenharmony_ci */
114762306a36Sopenharmony_cistatic void ena_refill_all_rx_bufs(struct ena_adapter *adapter)
114862306a36Sopenharmony_ci{
114962306a36Sopenharmony_ci	struct ena_ring *rx_ring;
115062306a36Sopenharmony_ci	int i, rc, bufs_num;
115162306a36Sopenharmony_ci
115262306a36Sopenharmony_ci	for (i = 0; i < adapter->num_io_queues; i++) {
115362306a36Sopenharmony_ci		rx_ring = &adapter->rx_ring[i];
115462306a36Sopenharmony_ci		bufs_num = rx_ring->ring_size - 1;
115562306a36Sopenharmony_ci		rc = ena_refill_rx_bufs(rx_ring, bufs_num);
115662306a36Sopenharmony_ci
115762306a36Sopenharmony_ci		if (unlikely(rc != bufs_num))
115862306a36Sopenharmony_ci			netif_warn(rx_ring->adapter, rx_status, rx_ring->netdev,
115962306a36Sopenharmony_ci				   "Refilling Queue %d failed. allocated %d buffers from: %d\n",
116062306a36Sopenharmony_ci				   i, rc, bufs_num);
116162306a36Sopenharmony_ci	}
116262306a36Sopenharmony_ci}
116362306a36Sopenharmony_ci
116462306a36Sopenharmony_cistatic void ena_free_all_rx_bufs(struct ena_adapter *adapter)
116562306a36Sopenharmony_ci{
116662306a36Sopenharmony_ci	int i;
116762306a36Sopenharmony_ci
116862306a36Sopenharmony_ci	for (i = 0; i < adapter->num_io_queues; i++)
116962306a36Sopenharmony_ci		ena_free_rx_bufs(adapter, i);
117062306a36Sopenharmony_ci}
117162306a36Sopenharmony_ci
117262306a36Sopenharmony_cistatic void ena_unmap_tx_buff(struct ena_ring *tx_ring,
117362306a36Sopenharmony_ci			      struct ena_tx_buffer *tx_info)
117462306a36Sopenharmony_ci{
117562306a36Sopenharmony_ci	struct ena_com_buf *ena_buf;
117662306a36Sopenharmony_ci	u32 cnt;
117762306a36Sopenharmony_ci	int i;
117862306a36Sopenharmony_ci
117962306a36Sopenharmony_ci	ena_buf = tx_info->bufs;
118062306a36Sopenharmony_ci	cnt = tx_info->num_of_bufs;
118162306a36Sopenharmony_ci
118262306a36Sopenharmony_ci	if (unlikely(!cnt))
118362306a36Sopenharmony_ci		return;
118462306a36Sopenharmony_ci
118562306a36Sopenharmony_ci	if (tx_info->map_linear_data) {
118662306a36Sopenharmony_ci		dma_unmap_single(tx_ring->dev,
118762306a36Sopenharmony_ci				 dma_unmap_addr(ena_buf, paddr),
118862306a36Sopenharmony_ci				 dma_unmap_len(ena_buf, len),
118962306a36Sopenharmony_ci				 DMA_TO_DEVICE);
119062306a36Sopenharmony_ci		ena_buf++;
119162306a36Sopenharmony_ci		cnt--;
119262306a36Sopenharmony_ci	}
119362306a36Sopenharmony_ci
119462306a36Sopenharmony_ci	/* unmap remaining mapped pages */
119562306a36Sopenharmony_ci	for (i = 0; i < cnt; i++) {
119662306a36Sopenharmony_ci		dma_unmap_page(tx_ring->dev, dma_unmap_addr(ena_buf, paddr),
119762306a36Sopenharmony_ci			       dma_unmap_len(ena_buf, len), DMA_TO_DEVICE);
119862306a36Sopenharmony_ci		ena_buf++;
119962306a36Sopenharmony_ci	}
120062306a36Sopenharmony_ci}
120162306a36Sopenharmony_ci
120262306a36Sopenharmony_ci/* ena_free_tx_bufs - Free Tx Buffers per Queue
120362306a36Sopenharmony_ci * @tx_ring: TX ring for which buffers be freed
120462306a36Sopenharmony_ci */
120562306a36Sopenharmony_cistatic void ena_free_tx_bufs(struct ena_ring *tx_ring)
120662306a36Sopenharmony_ci{
120762306a36Sopenharmony_ci	bool print_once = true;
120862306a36Sopenharmony_ci	u32 i;
120962306a36Sopenharmony_ci
121062306a36Sopenharmony_ci	for (i = 0; i < tx_ring->ring_size; i++) {
121162306a36Sopenharmony_ci		struct ena_tx_buffer *tx_info = &tx_ring->tx_buffer_info[i];
121262306a36Sopenharmony_ci
121362306a36Sopenharmony_ci		if (!tx_info->skb)
121462306a36Sopenharmony_ci			continue;
121562306a36Sopenharmony_ci
121662306a36Sopenharmony_ci		if (print_once) {
121762306a36Sopenharmony_ci			netif_notice(tx_ring->adapter, ifdown, tx_ring->netdev,
121862306a36Sopenharmony_ci				     "Free uncompleted tx skb qid %d idx 0x%x\n",
121962306a36Sopenharmony_ci				     tx_ring->qid, i);
122062306a36Sopenharmony_ci			print_once = false;
122162306a36Sopenharmony_ci		} else {
122262306a36Sopenharmony_ci			netif_dbg(tx_ring->adapter, ifdown, tx_ring->netdev,
122362306a36Sopenharmony_ci				  "Free uncompleted tx skb qid %d idx 0x%x\n",
122462306a36Sopenharmony_ci				  tx_ring->qid, i);
122562306a36Sopenharmony_ci		}
122662306a36Sopenharmony_ci
122762306a36Sopenharmony_ci		ena_unmap_tx_buff(tx_ring, tx_info);
122862306a36Sopenharmony_ci
122962306a36Sopenharmony_ci		dev_kfree_skb_any(tx_info->skb);
123062306a36Sopenharmony_ci	}
123162306a36Sopenharmony_ci	netdev_tx_reset_queue(netdev_get_tx_queue(tx_ring->netdev,
123262306a36Sopenharmony_ci						  tx_ring->qid));
123362306a36Sopenharmony_ci}
123462306a36Sopenharmony_ci
123562306a36Sopenharmony_cistatic void ena_free_all_tx_bufs(struct ena_adapter *adapter)
123662306a36Sopenharmony_ci{
123762306a36Sopenharmony_ci	struct ena_ring *tx_ring;
123862306a36Sopenharmony_ci	int i;
123962306a36Sopenharmony_ci
124062306a36Sopenharmony_ci	for (i = 0; i < adapter->num_io_queues + adapter->xdp_num_queues; i++) {
124162306a36Sopenharmony_ci		tx_ring = &adapter->tx_ring[i];
124262306a36Sopenharmony_ci		ena_free_tx_bufs(tx_ring);
124362306a36Sopenharmony_ci	}
124462306a36Sopenharmony_ci}
124562306a36Sopenharmony_ci
124662306a36Sopenharmony_cistatic void ena_destroy_all_tx_queues(struct ena_adapter *adapter)
124762306a36Sopenharmony_ci{
124862306a36Sopenharmony_ci	u16 ena_qid;
124962306a36Sopenharmony_ci	int i;
125062306a36Sopenharmony_ci
125162306a36Sopenharmony_ci	for (i = 0; i < adapter->num_io_queues + adapter->xdp_num_queues; i++) {
125262306a36Sopenharmony_ci		ena_qid = ENA_IO_TXQ_IDX(i);
125362306a36Sopenharmony_ci		ena_com_destroy_io_queue(adapter->ena_dev, ena_qid);
125462306a36Sopenharmony_ci	}
125562306a36Sopenharmony_ci}
125662306a36Sopenharmony_ci
125762306a36Sopenharmony_cistatic void ena_destroy_all_rx_queues(struct ena_adapter *adapter)
125862306a36Sopenharmony_ci{
125962306a36Sopenharmony_ci	u16 ena_qid;
126062306a36Sopenharmony_ci	int i;
126162306a36Sopenharmony_ci
126262306a36Sopenharmony_ci	for (i = 0; i < adapter->num_io_queues; i++) {
126362306a36Sopenharmony_ci		ena_qid = ENA_IO_RXQ_IDX(i);
126462306a36Sopenharmony_ci		cancel_work_sync(&adapter->ena_napi[i].dim.work);
126562306a36Sopenharmony_ci		ena_com_destroy_io_queue(adapter->ena_dev, ena_qid);
126662306a36Sopenharmony_ci	}
126762306a36Sopenharmony_ci}
126862306a36Sopenharmony_ci
126962306a36Sopenharmony_cistatic void ena_destroy_all_io_queues(struct ena_adapter *adapter)
127062306a36Sopenharmony_ci{
127162306a36Sopenharmony_ci	ena_destroy_all_tx_queues(adapter);
127262306a36Sopenharmony_ci	ena_destroy_all_rx_queues(adapter);
127362306a36Sopenharmony_ci}
127462306a36Sopenharmony_ci
127562306a36Sopenharmony_cistatic int handle_invalid_req_id(struct ena_ring *ring, u16 req_id,
127662306a36Sopenharmony_ci				 struct ena_tx_buffer *tx_info, bool is_xdp)
127762306a36Sopenharmony_ci{
127862306a36Sopenharmony_ci	if (tx_info)
127962306a36Sopenharmony_ci		netif_err(ring->adapter,
128062306a36Sopenharmony_ci			  tx_done,
128162306a36Sopenharmony_ci			  ring->netdev,
128262306a36Sopenharmony_ci			  "tx_info doesn't have valid %s. qid %u req_id %u",
128362306a36Sopenharmony_ci			   is_xdp ? "xdp frame" : "skb", ring->qid, req_id);
128462306a36Sopenharmony_ci	else
128562306a36Sopenharmony_ci		netif_err(ring->adapter,
128662306a36Sopenharmony_ci			  tx_done,
128762306a36Sopenharmony_ci			  ring->netdev,
128862306a36Sopenharmony_ci			  "Invalid req_id %u in qid %u\n",
128962306a36Sopenharmony_ci			  req_id, ring->qid);
129062306a36Sopenharmony_ci
129162306a36Sopenharmony_ci	ena_increase_stat(&ring->tx_stats.bad_req_id, 1, &ring->syncp);
129262306a36Sopenharmony_ci	ena_reset_device(ring->adapter, ENA_REGS_RESET_INV_TX_REQ_ID);
129362306a36Sopenharmony_ci
129462306a36Sopenharmony_ci	return -EFAULT;
129562306a36Sopenharmony_ci}
129662306a36Sopenharmony_ci
129762306a36Sopenharmony_cistatic int validate_tx_req_id(struct ena_ring *tx_ring, u16 req_id)
129862306a36Sopenharmony_ci{
129962306a36Sopenharmony_ci	struct ena_tx_buffer *tx_info;
130062306a36Sopenharmony_ci
130162306a36Sopenharmony_ci	tx_info = &tx_ring->tx_buffer_info[req_id];
130262306a36Sopenharmony_ci	if (likely(tx_info->skb))
130362306a36Sopenharmony_ci		return 0;
130462306a36Sopenharmony_ci
130562306a36Sopenharmony_ci	return handle_invalid_req_id(tx_ring, req_id, tx_info, false);
130662306a36Sopenharmony_ci}
130762306a36Sopenharmony_ci
130862306a36Sopenharmony_cistatic int validate_xdp_req_id(struct ena_ring *xdp_ring, u16 req_id)
130962306a36Sopenharmony_ci{
131062306a36Sopenharmony_ci	struct ena_tx_buffer *tx_info;
131162306a36Sopenharmony_ci
131262306a36Sopenharmony_ci	tx_info = &xdp_ring->tx_buffer_info[req_id];
131362306a36Sopenharmony_ci	if (likely(tx_info->xdpf))
131462306a36Sopenharmony_ci		return 0;
131562306a36Sopenharmony_ci
131662306a36Sopenharmony_ci	return handle_invalid_req_id(xdp_ring, req_id, tx_info, true);
131762306a36Sopenharmony_ci}
131862306a36Sopenharmony_ci
131962306a36Sopenharmony_cistatic int ena_clean_tx_irq(struct ena_ring *tx_ring, u32 budget)
132062306a36Sopenharmony_ci{
132162306a36Sopenharmony_ci	struct netdev_queue *txq;
132262306a36Sopenharmony_ci	bool above_thresh;
132362306a36Sopenharmony_ci	u32 tx_bytes = 0;
132462306a36Sopenharmony_ci	u32 total_done = 0;
132562306a36Sopenharmony_ci	u16 next_to_clean;
132662306a36Sopenharmony_ci	u16 req_id;
132762306a36Sopenharmony_ci	int tx_pkts = 0;
132862306a36Sopenharmony_ci	int rc;
132962306a36Sopenharmony_ci
133062306a36Sopenharmony_ci	next_to_clean = tx_ring->next_to_clean;
133162306a36Sopenharmony_ci	txq = netdev_get_tx_queue(tx_ring->netdev, tx_ring->qid);
133262306a36Sopenharmony_ci
133362306a36Sopenharmony_ci	while (tx_pkts < budget) {
133462306a36Sopenharmony_ci		struct ena_tx_buffer *tx_info;
133562306a36Sopenharmony_ci		struct sk_buff *skb;
133662306a36Sopenharmony_ci
133762306a36Sopenharmony_ci		rc = ena_com_tx_comp_req_id_get(tx_ring->ena_com_io_cq,
133862306a36Sopenharmony_ci						&req_id);
133962306a36Sopenharmony_ci		if (rc) {
134062306a36Sopenharmony_ci			if (unlikely(rc == -EINVAL))
134162306a36Sopenharmony_ci				handle_invalid_req_id(tx_ring, req_id, NULL,
134262306a36Sopenharmony_ci						      false);
134362306a36Sopenharmony_ci			break;
134462306a36Sopenharmony_ci		}
134562306a36Sopenharmony_ci
134662306a36Sopenharmony_ci		/* validate that the request id points to a valid skb */
134762306a36Sopenharmony_ci		rc = validate_tx_req_id(tx_ring, req_id);
134862306a36Sopenharmony_ci		if (rc)
134962306a36Sopenharmony_ci			break;
135062306a36Sopenharmony_ci
135162306a36Sopenharmony_ci		tx_info = &tx_ring->tx_buffer_info[req_id];
135262306a36Sopenharmony_ci		skb = tx_info->skb;
135362306a36Sopenharmony_ci
135462306a36Sopenharmony_ci		/* prefetch skb_end_pointer() to speedup skb_shinfo(skb) */
135562306a36Sopenharmony_ci		prefetch(&skb->end);
135662306a36Sopenharmony_ci
135762306a36Sopenharmony_ci		tx_info->skb = NULL;
135862306a36Sopenharmony_ci		tx_info->last_jiffies = 0;
135962306a36Sopenharmony_ci
136062306a36Sopenharmony_ci		ena_unmap_tx_buff(tx_ring, tx_info);
136162306a36Sopenharmony_ci
136262306a36Sopenharmony_ci		netif_dbg(tx_ring->adapter, tx_done, tx_ring->netdev,
136362306a36Sopenharmony_ci			  "tx_poll: q %d skb %p completed\n", tx_ring->qid,
136462306a36Sopenharmony_ci			  skb);
136562306a36Sopenharmony_ci
136662306a36Sopenharmony_ci		tx_bytes += skb->len;
136762306a36Sopenharmony_ci		dev_kfree_skb(skb);
136862306a36Sopenharmony_ci		tx_pkts++;
136962306a36Sopenharmony_ci		total_done += tx_info->tx_descs;
137062306a36Sopenharmony_ci
137162306a36Sopenharmony_ci		tx_ring->free_ids[next_to_clean] = req_id;
137262306a36Sopenharmony_ci		next_to_clean = ENA_TX_RING_IDX_NEXT(next_to_clean,
137362306a36Sopenharmony_ci						     tx_ring->ring_size);
137462306a36Sopenharmony_ci	}
137562306a36Sopenharmony_ci
137662306a36Sopenharmony_ci	tx_ring->next_to_clean = next_to_clean;
137762306a36Sopenharmony_ci	ena_com_comp_ack(tx_ring->ena_com_io_sq, total_done);
137862306a36Sopenharmony_ci	ena_com_update_dev_comp_head(tx_ring->ena_com_io_cq);
137962306a36Sopenharmony_ci
138062306a36Sopenharmony_ci	netdev_tx_completed_queue(txq, tx_pkts, tx_bytes);
138162306a36Sopenharmony_ci
138262306a36Sopenharmony_ci	netif_dbg(tx_ring->adapter, tx_done, tx_ring->netdev,
138362306a36Sopenharmony_ci		  "tx_poll: q %d done. total pkts: %d\n",
138462306a36Sopenharmony_ci		  tx_ring->qid, tx_pkts);
138562306a36Sopenharmony_ci
138662306a36Sopenharmony_ci	/* need to make the rings circular update visible to
138762306a36Sopenharmony_ci	 * ena_start_xmit() before checking for netif_queue_stopped().
138862306a36Sopenharmony_ci	 */
138962306a36Sopenharmony_ci	smp_mb();
139062306a36Sopenharmony_ci
139162306a36Sopenharmony_ci	above_thresh = ena_com_sq_have_enough_space(tx_ring->ena_com_io_sq,
139262306a36Sopenharmony_ci						    ENA_TX_WAKEUP_THRESH);
139362306a36Sopenharmony_ci	if (unlikely(netif_tx_queue_stopped(txq) && above_thresh)) {
139462306a36Sopenharmony_ci		__netif_tx_lock(txq, smp_processor_id());
139562306a36Sopenharmony_ci		above_thresh =
139662306a36Sopenharmony_ci			ena_com_sq_have_enough_space(tx_ring->ena_com_io_sq,
139762306a36Sopenharmony_ci						     ENA_TX_WAKEUP_THRESH);
139862306a36Sopenharmony_ci		if (netif_tx_queue_stopped(txq) && above_thresh &&
139962306a36Sopenharmony_ci		    test_bit(ENA_FLAG_DEV_UP, &tx_ring->adapter->flags)) {
140062306a36Sopenharmony_ci			netif_tx_wake_queue(txq);
140162306a36Sopenharmony_ci			ena_increase_stat(&tx_ring->tx_stats.queue_wakeup, 1,
140262306a36Sopenharmony_ci					  &tx_ring->syncp);
140362306a36Sopenharmony_ci		}
140462306a36Sopenharmony_ci		__netif_tx_unlock(txq);
140562306a36Sopenharmony_ci	}
140662306a36Sopenharmony_ci
140762306a36Sopenharmony_ci	return tx_pkts;
140862306a36Sopenharmony_ci}
140962306a36Sopenharmony_ci
141062306a36Sopenharmony_cistatic struct sk_buff *ena_alloc_skb(struct ena_ring *rx_ring, void *first_frag, u16 len)
141162306a36Sopenharmony_ci{
141262306a36Sopenharmony_ci	struct sk_buff *skb;
141362306a36Sopenharmony_ci
141462306a36Sopenharmony_ci	if (!first_frag)
141562306a36Sopenharmony_ci		skb = napi_alloc_skb(rx_ring->napi, len);
141662306a36Sopenharmony_ci	else
141762306a36Sopenharmony_ci		skb = napi_build_skb(first_frag, len);
141862306a36Sopenharmony_ci
141962306a36Sopenharmony_ci	if (unlikely(!skb)) {
142062306a36Sopenharmony_ci		ena_increase_stat(&rx_ring->rx_stats.skb_alloc_fail, 1,
142162306a36Sopenharmony_ci				  &rx_ring->syncp);
142262306a36Sopenharmony_ci
142362306a36Sopenharmony_ci		netif_dbg(rx_ring->adapter, rx_err, rx_ring->netdev,
142462306a36Sopenharmony_ci			  "Failed to allocate skb. first_frag %s\n",
142562306a36Sopenharmony_ci			  first_frag ? "provided" : "not provided");
142662306a36Sopenharmony_ci	}
142762306a36Sopenharmony_ci
142862306a36Sopenharmony_ci	return skb;
142962306a36Sopenharmony_ci}
143062306a36Sopenharmony_ci
143162306a36Sopenharmony_cistatic bool ena_try_rx_buf_page_reuse(struct ena_rx_buffer *rx_info, u16 buf_len,
143262306a36Sopenharmony_ci				      u16 len, int pkt_offset)
143362306a36Sopenharmony_ci{
143462306a36Sopenharmony_ci	struct ena_com_buf *ena_buf = &rx_info->ena_buf;
143562306a36Sopenharmony_ci
143662306a36Sopenharmony_ci	/* More than ENA_MIN_RX_BUF_SIZE left in the reused buffer
143762306a36Sopenharmony_ci	 * for data + headroom + tailroom.
143862306a36Sopenharmony_ci	 */
143962306a36Sopenharmony_ci	if (SKB_DATA_ALIGN(len + pkt_offset) + ENA_MIN_RX_BUF_SIZE <= ena_buf->len) {
144062306a36Sopenharmony_ci		page_ref_inc(rx_info->page);
144162306a36Sopenharmony_ci		rx_info->page_offset += buf_len;
144262306a36Sopenharmony_ci		ena_buf->paddr += buf_len;
144362306a36Sopenharmony_ci		ena_buf->len -= buf_len;
144462306a36Sopenharmony_ci		return true;
144562306a36Sopenharmony_ci	}
144662306a36Sopenharmony_ci
144762306a36Sopenharmony_ci	return false;
144862306a36Sopenharmony_ci}
144962306a36Sopenharmony_ci
145062306a36Sopenharmony_cistatic struct sk_buff *ena_rx_skb(struct ena_ring *rx_ring,
145162306a36Sopenharmony_ci				  struct ena_com_rx_buf_info *ena_bufs,
145262306a36Sopenharmony_ci				  u32 descs,
145362306a36Sopenharmony_ci				  u16 *next_to_clean)
145462306a36Sopenharmony_ci{
145562306a36Sopenharmony_ci	int tailroom = SKB_DATA_ALIGN(sizeof(struct skb_shared_info));
145662306a36Sopenharmony_ci	bool is_xdp_loaded = ena_xdp_present_ring(rx_ring);
145762306a36Sopenharmony_ci	struct ena_rx_buffer *rx_info;
145862306a36Sopenharmony_ci	struct ena_adapter *adapter;
145962306a36Sopenharmony_ci	int page_offset, pkt_offset;
146062306a36Sopenharmony_ci	dma_addr_t pre_reuse_paddr;
146162306a36Sopenharmony_ci	u16 len, req_id, buf = 0;
146262306a36Sopenharmony_ci	bool reuse_rx_buf_page;
146362306a36Sopenharmony_ci	struct sk_buff *skb;
146462306a36Sopenharmony_ci	void *buf_addr;
146562306a36Sopenharmony_ci	int buf_offset;
146662306a36Sopenharmony_ci	u16 buf_len;
146762306a36Sopenharmony_ci
146862306a36Sopenharmony_ci	len = ena_bufs[buf].len;
146962306a36Sopenharmony_ci	req_id = ena_bufs[buf].req_id;
147062306a36Sopenharmony_ci
147162306a36Sopenharmony_ci	rx_info = &rx_ring->rx_buffer_info[req_id];
147262306a36Sopenharmony_ci
147362306a36Sopenharmony_ci	if (unlikely(!rx_info->page)) {
147462306a36Sopenharmony_ci		adapter = rx_ring->adapter;
147562306a36Sopenharmony_ci		netif_err(adapter, rx_err, rx_ring->netdev,
147662306a36Sopenharmony_ci			  "Page is NULL. qid %u req_id %u\n", rx_ring->qid, req_id);
147762306a36Sopenharmony_ci		ena_increase_stat(&rx_ring->rx_stats.bad_req_id, 1, &rx_ring->syncp);
147862306a36Sopenharmony_ci		ena_reset_device(adapter, ENA_REGS_RESET_INV_RX_REQ_ID);
147962306a36Sopenharmony_ci		return NULL;
148062306a36Sopenharmony_ci	}
148162306a36Sopenharmony_ci
148262306a36Sopenharmony_ci	netif_dbg(rx_ring->adapter, rx_status, rx_ring->netdev,
148362306a36Sopenharmony_ci		  "rx_info %p page %p\n",
148462306a36Sopenharmony_ci		  rx_info, rx_info->page);
148562306a36Sopenharmony_ci
148662306a36Sopenharmony_ci	buf_offset = rx_info->buf_offset;
148762306a36Sopenharmony_ci	pkt_offset = buf_offset - rx_ring->rx_headroom;
148862306a36Sopenharmony_ci	page_offset = rx_info->page_offset;
148962306a36Sopenharmony_ci	buf_addr = page_address(rx_info->page) + page_offset;
149062306a36Sopenharmony_ci
149162306a36Sopenharmony_ci	if (len <= rx_ring->rx_copybreak) {
149262306a36Sopenharmony_ci		skb = ena_alloc_skb(rx_ring, NULL, len);
149362306a36Sopenharmony_ci		if (unlikely(!skb))
149462306a36Sopenharmony_ci			return NULL;
149562306a36Sopenharmony_ci
149662306a36Sopenharmony_ci		skb_copy_to_linear_data(skb, buf_addr + buf_offset, len);
149762306a36Sopenharmony_ci		dma_sync_single_for_device(rx_ring->dev,
149862306a36Sopenharmony_ci					   dma_unmap_addr(&rx_info->ena_buf, paddr) + pkt_offset,
149962306a36Sopenharmony_ci					   len,
150062306a36Sopenharmony_ci					   DMA_FROM_DEVICE);
150162306a36Sopenharmony_ci
150262306a36Sopenharmony_ci		skb_put(skb, len);
150362306a36Sopenharmony_ci		netif_dbg(rx_ring->adapter, rx_status, rx_ring->netdev,
150462306a36Sopenharmony_ci			  "RX allocated small packet. len %d.\n", skb->len);
150562306a36Sopenharmony_ci		skb->protocol = eth_type_trans(skb, rx_ring->netdev);
150662306a36Sopenharmony_ci		rx_ring->free_ids[*next_to_clean] = req_id;
150762306a36Sopenharmony_ci		*next_to_clean = ENA_RX_RING_IDX_ADD(*next_to_clean, descs,
150862306a36Sopenharmony_ci						     rx_ring->ring_size);
150962306a36Sopenharmony_ci		return skb;
151062306a36Sopenharmony_ci	}
151162306a36Sopenharmony_ci
151262306a36Sopenharmony_ci	buf_len = SKB_DATA_ALIGN(len + buf_offset + tailroom);
151362306a36Sopenharmony_ci
151462306a36Sopenharmony_ci	/* If XDP isn't loaded try to reuse part of the RX buffer */
151562306a36Sopenharmony_ci	reuse_rx_buf_page = !is_xdp_loaded &&
151662306a36Sopenharmony_ci			    ena_try_rx_buf_page_reuse(rx_info, buf_len, len, pkt_offset);
151762306a36Sopenharmony_ci
151862306a36Sopenharmony_ci	if (!reuse_rx_buf_page)
151962306a36Sopenharmony_ci		ena_unmap_rx_buff_attrs(rx_ring, rx_info, DMA_ATTR_SKIP_CPU_SYNC);
152062306a36Sopenharmony_ci
152162306a36Sopenharmony_ci	skb = ena_alloc_skb(rx_ring, buf_addr, buf_len);
152262306a36Sopenharmony_ci	if (unlikely(!skb))
152362306a36Sopenharmony_ci		return NULL;
152462306a36Sopenharmony_ci
152562306a36Sopenharmony_ci	/* Populate skb's linear part */
152662306a36Sopenharmony_ci	skb_reserve(skb, buf_offset);
152762306a36Sopenharmony_ci	skb_put(skb, len);
152862306a36Sopenharmony_ci	skb->protocol = eth_type_trans(skb, rx_ring->netdev);
152962306a36Sopenharmony_ci
153062306a36Sopenharmony_ci	do {
153162306a36Sopenharmony_ci		netif_dbg(rx_ring->adapter, rx_status, rx_ring->netdev,
153262306a36Sopenharmony_ci			  "RX skb updated. len %d. data_len %d\n",
153362306a36Sopenharmony_ci			  skb->len, skb->data_len);
153462306a36Sopenharmony_ci
153562306a36Sopenharmony_ci		if (!reuse_rx_buf_page)
153662306a36Sopenharmony_ci			rx_info->page = NULL;
153762306a36Sopenharmony_ci
153862306a36Sopenharmony_ci		rx_ring->free_ids[*next_to_clean] = req_id;
153962306a36Sopenharmony_ci		*next_to_clean =
154062306a36Sopenharmony_ci			ENA_RX_RING_IDX_NEXT(*next_to_clean,
154162306a36Sopenharmony_ci					     rx_ring->ring_size);
154262306a36Sopenharmony_ci		if (likely(--descs == 0))
154362306a36Sopenharmony_ci			break;
154462306a36Sopenharmony_ci
154562306a36Sopenharmony_ci		buf++;
154662306a36Sopenharmony_ci		len = ena_bufs[buf].len;
154762306a36Sopenharmony_ci		req_id = ena_bufs[buf].req_id;
154862306a36Sopenharmony_ci
154962306a36Sopenharmony_ci		rx_info = &rx_ring->rx_buffer_info[req_id];
155062306a36Sopenharmony_ci
155162306a36Sopenharmony_ci		/* rx_info->buf_offset includes rx_ring->rx_headroom */
155262306a36Sopenharmony_ci		buf_offset = rx_info->buf_offset;
155362306a36Sopenharmony_ci		pkt_offset = buf_offset - rx_ring->rx_headroom;
155462306a36Sopenharmony_ci		buf_len = SKB_DATA_ALIGN(len + buf_offset + tailroom);
155562306a36Sopenharmony_ci		page_offset = rx_info->page_offset;
155662306a36Sopenharmony_ci
155762306a36Sopenharmony_ci		pre_reuse_paddr = dma_unmap_addr(&rx_info->ena_buf, paddr);
155862306a36Sopenharmony_ci
155962306a36Sopenharmony_ci		reuse_rx_buf_page = !is_xdp_loaded &&
156062306a36Sopenharmony_ci				    ena_try_rx_buf_page_reuse(rx_info, buf_len, len, pkt_offset);
156162306a36Sopenharmony_ci
156262306a36Sopenharmony_ci		dma_sync_single_for_cpu(rx_ring->dev,
156362306a36Sopenharmony_ci					pre_reuse_paddr + pkt_offset,
156462306a36Sopenharmony_ci					len,
156562306a36Sopenharmony_ci					DMA_FROM_DEVICE);
156662306a36Sopenharmony_ci
156762306a36Sopenharmony_ci		if (!reuse_rx_buf_page)
156862306a36Sopenharmony_ci			ena_unmap_rx_buff_attrs(rx_ring, rx_info,
156962306a36Sopenharmony_ci						DMA_ATTR_SKIP_CPU_SYNC);
157062306a36Sopenharmony_ci
157162306a36Sopenharmony_ci		skb_add_rx_frag(skb, skb_shinfo(skb)->nr_frags, rx_info->page,
157262306a36Sopenharmony_ci				page_offset + buf_offset, len, buf_len);
157362306a36Sopenharmony_ci
157462306a36Sopenharmony_ci	} while (1);
157562306a36Sopenharmony_ci
157662306a36Sopenharmony_ci	return skb;
157762306a36Sopenharmony_ci}
157862306a36Sopenharmony_ci
157962306a36Sopenharmony_ci/* ena_rx_checksum - indicate in skb if hw indicated a good cksum
158062306a36Sopenharmony_ci * @adapter: structure containing adapter specific data
158162306a36Sopenharmony_ci * @ena_rx_ctx: received packet context/metadata
158262306a36Sopenharmony_ci * @skb: skb currently being received and modified
158362306a36Sopenharmony_ci */
158462306a36Sopenharmony_cistatic void ena_rx_checksum(struct ena_ring *rx_ring,
158562306a36Sopenharmony_ci				   struct ena_com_rx_ctx *ena_rx_ctx,
158662306a36Sopenharmony_ci				   struct sk_buff *skb)
158762306a36Sopenharmony_ci{
158862306a36Sopenharmony_ci	/* Rx csum disabled */
158962306a36Sopenharmony_ci	if (unlikely(!(rx_ring->netdev->features & NETIF_F_RXCSUM))) {
159062306a36Sopenharmony_ci		skb->ip_summed = CHECKSUM_NONE;
159162306a36Sopenharmony_ci		return;
159262306a36Sopenharmony_ci	}
159362306a36Sopenharmony_ci
159462306a36Sopenharmony_ci	/* For fragmented packets the checksum isn't valid */
159562306a36Sopenharmony_ci	if (ena_rx_ctx->frag) {
159662306a36Sopenharmony_ci		skb->ip_summed = CHECKSUM_NONE;
159762306a36Sopenharmony_ci		return;
159862306a36Sopenharmony_ci	}
159962306a36Sopenharmony_ci
160062306a36Sopenharmony_ci	/* if IP and error */
160162306a36Sopenharmony_ci	if (unlikely((ena_rx_ctx->l3_proto == ENA_ETH_IO_L3_PROTO_IPV4) &&
160262306a36Sopenharmony_ci		     (ena_rx_ctx->l3_csum_err))) {
160362306a36Sopenharmony_ci		/* ipv4 checksum error */
160462306a36Sopenharmony_ci		skb->ip_summed = CHECKSUM_NONE;
160562306a36Sopenharmony_ci		ena_increase_stat(&rx_ring->rx_stats.csum_bad, 1,
160662306a36Sopenharmony_ci				  &rx_ring->syncp);
160762306a36Sopenharmony_ci		netif_dbg(rx_ring->adapter, rx_err, rx_ring->netdev,
160862306a36Sopenharmony_ci			  "RX IPv4 header checksum error\n");
160962306a36Sopenharmony_ci		return;
161062306a36Sopenharmony_ci	}
161162306a36Sopenharmony_ci
161262306a36Sopenharmony_ci	/* if TCP/UDP */
161362306a36Sopenharmony_ci	if (likely((ena_rx_ctx->l4_proto == ENA_ETH_IO_L4_PROTO_TCP) ||
161462306a36Sopenharmony_ci		   (ena_rx_ctx->l4_proto == ENA_ETH_IO_L4_PROTO_UDP))) {
161562306a36Sopenharmony_ci		if (unlikely(ena_rx_ctx->l4_csum_err)) {
161662306a36Sopenharmony_ci			/* TCP/UDP checksum error */
161762306a36Sopenharmony_ci			ena_increase_stat(&rx_ring->rx_stats.csum_bad, 1,
161862306a36Sopenharmony_ci					  &rx_ring->syncp);
161962306a36Sopenharmony_ci			netif_dbg(rx_ring->adapter, rx_err, rx_ring->netdev,
162062306a36Sopenharmony_ci				  "RX L4 checksum error\n");
162162306a36Sopenharmony_ci			skb->ip_summed = CHECKSUM_NONE;
162262306a36Sopenharmony_ci			return;
162362306a36Sopenharmony_ci		}
162462306a36Sopenharmony_ci
162562306a36Sopenharmony_ci		if (likely(ena_rx_ctx->l4_csum_checked)) {
162662306a36Sopenharmony_ci			skb->ip_summed = CHECKSUM_UNNECESSARY;
162762306a36Sopenharmony_ci			ena_increase_stat(&rx_ring->rx_stats.csum_good, 1,
162862306a36Sopenharmony_ci					  &rx_ring->syncp);
162962306a36Sopenharmony_ci		} else {
163062306a36Sopenharmony_ci			ena_increase_stat(&rx_ring->rx_stats.csum_unchecked, 1,
163162306a36Sopenharmony_ci					  &rx_ring->syncp);
163262306a36Sopenharmony_ci			skb->ip_summed = CHECKSUM_NONE;
163362306a36Sopenharmony_ci		}
163462306a36Sopenharmony_ci	} else {
163562306a36Sopenharmony_ci		skb->ip_summed = CHECKSUM_NONE;
163662306a36Sopenharmony_ci		return;
163762306a36Sopenharmony_ci	}
163862306a36Sopenharmony_ci
163962306a36Sopenharmony_ci}
164062306a36Sopenharmony_ci
164162306a36Sopenharmony_cistatic void ena_set_rx_hash(struct ena_ring *rx_ring,
164262306a36Sopenharmony_ci			    struct ena_com_rx_ctx *ena_rx_ctx,
164362306a36Sopenharmony_ci			    struct sk_buff *skb)
164462306a36Sopenharmony_ci{
164562306a36Sopenharmony_ci	enum pkt_hash_types hash_type;
164662306a36Sopenharmony_ci
164762306a36Sopenharmony_ci	if (likely(rx_ring->netdev->features & NETIF_F_RXHASH)) {
164862306a36Sopenharmony_ci		if (likely((ena_rx_ctx->l4_proto == ENA_ETH_IO_L4_PROTO_TCP) ||
164962306a36Sopenharmony_ci			   (ena_rx_ctx->l4_proto == ENA_ETH_IO_L4_PROTO_UDP)))
165062306a36Sopenharmony_ci
165162306a36Sopenharmony_ci			hash_type = PKT_HASH_TYPE_L4;
165262306a36Sopenharmony_ci		else
165362306a36Sopenharmony_ci			hash_type = PKT_HASH_TYPE_NONE;
165462306a36Sopenharmony_ci
165562306a36Sopenharmony_ci		/* Override hash type if the packet is fragmented */
165662306a36Sopenharmony_ci		if (ena_rx_ctx->frag)
165762306a36Sopenharmony_ci			hash_type = PKT_HASH_TYPE_NONE;
165862306a36Sopenharmony_ci
165962306a36Sopenharmony_ci		skb_set_hash(skb, ena_rx_ctx->hash, hash_type);
166062306a36Sopenharmony_ci	}
166162306a36Sopenharmony_ci}
166262306a36Sopenharmony_ci
166362306a36Sopenharmony_cistatic int ena_xdp_handle_buff(struct ena_ring *rx_ring, struct xdp_buff *xdp, u16 num_descs)
166462306a36Sopenharmony_ci{
166562306a36Sopenharmony_ci	struct ena_rx_buffer *rx_info;
166662306a36Sopenharmony_ci	int ret;
166762306a36Sopenharmony_ci
166862306a36Sopenharmony_ci	/* XDP multi-buffer packets not supported */
166962306a36Sopenharmony_ci	if (unlikely(num_descs > 1)) {
167062306a36Sopenharmony_ci		netdev_err_once(rx_ring->adapter->netdev,
167162306a36Sopenharmony_ci				"xdp: dropped unsupported multi-buffer packets\n");
167262306a36Sopenharmony_ci		ena_increase_stat(&rx_ring->rx_stats.xdp_drop, 1, &rx_ring->syncp);
167362306a36Sopenharmony_ci		return ENA_XDP_DROP;
167462306a36Sopenharmony_ci	}
167562306a36Sopenharmony_ci
167662306a36Sopenharmony_ci	rx_info = &rx_ring->rx_buffer_info[rx_ring->ena_bufs[0].req_id];
167762306a36Sopenharmony_ci	xdp_prepare_buff(xdp, page_address(rx_info->page),
167862306a36Sopenharmony_ci			 rx_info->buf_offset,
167962306a36Sopenharmony_ci			 rx_ring->ena_bufs[0].len, false);
168062306a36Sopenharmony_ci
168162306a36Sopenharmony_ci	ret = ena_xdp_execute(rx_ring, xdp);
168262306a36Sopenharmony_ci
168362306a36Sopenharmony_ci	/* The xdp program might expand the headers */
168462306a36Sopenharmony_ci	if (ret == ENA_XDP_PASS) {
168562306a36Sopenharmony_ci		rx_info->buf_offset = xdp->data - xdp->data_hard_start;
168662306a36Sopenharmony_ci		rx_ring->ena_bufs[0].len = xdp->data_end - xdp->data;
168762306a36Sopenharmony_ci	}
168862306a36Sopenharmony_ci
168962306a36Sopenharmony_ci	return ret;
169062306a36Sopenharmony_ci}
169162306a36Sopenharmony_ci/* ena_clean_rx_irq - Cleanup RX irq
169262306a36Sopenharmony_ci * @rx_ring: RX ring to clean
169362306a36Sopenharmony_ci * @napi: napi handler
169462306a36Sopenharmony_ci * @budget: how many packets driver is allowed to clean
169562306a36Sopenharmony_ci *
169662306a36Sopenharmony_ci * Returns the number of cleaned buffers.
169762306a36Sopenharmony_ci */
169862306a36Sopenharmony_cistatic int ena_clean_rx_irq(struct ena_ring *rx_ring, struct napi_struct *napi,
169962306a36Sopenharmony_ci			    u32 budget)
170062306a36Sopenharmony_ci{
170162306a36Sopenharmony_ci	u16 next_to_clean = rx_ring->next_to_clean;
170262306a36Sopenharmony_ci	struct ena_com_rx_ctx ena_rx_ctx;
170362306a36Sopenharmony_ci	struct ena_rx_buffer *rx_info;
170462306a36Sopenharmony_ci	struct ena_adapter *adapter;
170562306a36Sopenharmony_ci	u32 res_budget, work_done;
170662306a36Sopenharmony_ci	int rx_copybreak_pkt = 0;
170762306a36Sopenharmony_ci	int refill_threshold;
170862306a36Sopenharmony_ci	struct sk_buff *skb;
170962306a36Sopenharmony_ci	int refill_required;
171062306a36Sopenharmony_ci	struct xdp_buff xdp;
171162306a36Sopenharmony_ci	int xdp_flags = 0;
171262306a36Sopenharmony_ci	int total_len = 0;
171362306a36Sopenharmony_ci	int xdp_verdict;
171462306a36Sopenharmony_ci	u8 pkt_offset;
171562306a36Sopenharmony_ci	int rc = 0;
171662306a36Sopenharmony_ci	int i;
171762306a36Sopenharmony_ci
171862306a36Sopenharmony_ci	netif_dbg(rx_ring->adapter, rx_status, rx_ring->netdev,
171962306a36Sopenharmony_ci		  "%s qid %d\n", __func__, rx_ring->qid);
172062306a36Sopenharmony_ci	res_budget = budget;
172162306a36Sopenharmony_ci	xdp_init_buff(&xdp, ENA_PAGE_SIZE, &rx_ring->xdp_rxq);
172262306a36Sopenharmony_ci
172362306a36Sopenharmony_ci	do {
172462306a36Sopenharmony_ci		xdp_verdict = ENA_XDP_PASS;
172562306a36Sopenharmony_ci		skb = NULL;
172662306a36Sopenharmony_ci		ena_rx_ctx.ena_bufs = rx_ring->ena_bufs;
172762306a36Sopenharmony_ci		ena_rx_ctx.max_bufs = rx_ring->sgl_size;
172862306a36Sopenharmony_ci		ena_rx_ctx.descs = 0;
172962306a36Sopenharmony_ci		ena_rx_ctx.pkt_offset = 0;
173062306a36Sopenharmony_ci		rc = ena_com_rx_pkt(rx_ring->ena_com_io_cq,
173162306a36Sopenharmony_ci				    rx_ring->ena_com_io_sq,
173262306a36Sopenharmony_ci				    &ena_rx_ctx);
173362306a36Sopenharmony_ci		if (unlikely(rc))
173462306a36Sopenharmony_ci			goto error;
173562306a36Sopenharmony_ci
173662306a36Sopenharmony_ci		if (unlikely(ena_rx_ctx.descs == 0))
173762306a36Sopenharmony_ci			break;
173862306a36Sopenharmony_ci
173962306a36Sopenharmony_ci		/* First descriptor might have an offset set by the device */
174062306a36Sopenharmony_ci		rx_info = &rx_ring->rx_buffer_info[rx_ring->ena_bufs[0].req_id];
174162306a36Sopenharmony_ci		pkt_offset = ena_rx_ctx.pkt_offset;
174262306a36Sopenharmony_ci		rx_info->buf_offset += pkt_offset;
174362306a36Sopenharmony_ci
174462306a36Sopenharmony_ci		netif_dbg(rx_ring->adapter, rx_status, rx_ring->netdev,
174562306a36Sopenharmony_ci			  "rx_poll: q %d got packet from ena. descs #: %d l3 proto %d l4 proto %d hash: %x\n",
174662306a36Sopenharmony_ci			  rx_ring->qid, ena_rx_ctx.descs, ena_rx_ctx.l3_proto,
174762306a36Sopenharmony_ci			  ena_rx_ctx.l4_proto, ena_rx_ctx.hash);
174862306a36Sopenharmony_ci
174962306a36Sopenharmony_ci		dma_sync_single_for_cpu(rx_ring->dev,
175062306a36Sopenharmony_ci					dma_unmap_addr(&rx_info->ena_buf, paddr) + pkt_offset,
175162306a36Sopenharmony_ci					rx_ring->ena_bufs[0].len,
175262306a36Sopenharmony_ci					DMA_FROM_DEVICE);
175362306a36Sopenharmony_ci
175462306a36Sopenharmony_ci		if (ena_xdp_present_ring(rx_ring))
175562306a36Sopenharmony_ci			xdp_verdict = ena_xdp_handle_buff(rx_ring, &xdp, ena_rx_ctx.descs);
175662306a36Sopenharmony_ci
175762306a36Sopenharmony_ci		/* allocate skb and fill it */
175862306a36Sopenharmony_ci		if (xdp_verdict == ENA_XDP_PASS)
175962306a36Sopenharmony_ci			skb = ena_rx_skb(rx_ring,
176062306a36Sopenharmony_ci					 rx_ring->ena_bufs,
176162306a36Sopenharmony_ci					 ena_rx_ctx.descs,
176262306a36Sopenharmony_ci					 &next_to_clean);
176362306a36Sopenharmony_ci
176462306a36Sopenharmony_ci		if (unlikely(!skb)) {
176562306a36Sopenharmony_ci			for (i = 0; i < ena_rx_ctx.descs; i++) {
176662306a36Sopenharmony_ci				int req_id = rx_ring->ena_bufs[i].req_id;
176762306a36Sopenharmony_ci
176862306a36Sopenharmony_ci				rx_ring->free_ids[next_to_clean] = req_id;
176962306a36Sopenharmony_ci				next_to_clean =
177062306a36Sopenharmony_ci					ENA_RX_RING_IDX_NEXT(next_to_clean,
177162306a36Sopenharmony_ci							     rx_ring->ring_size);
177262306a36Sopenharmony_ci
177362306a36Sopenharmony_ci				/* Packets was passed for transmission, unmap it
177462306a36Sopenharmony_ci				 * from RX side.
177562306a36Sopenharmony_ci				 */
177662306a36Sopenharmony_ci				if (xdp_verdict & ENA_XDP_FORWARDED) {
177762306a36Sopenharmony_ci					ena_unmap_rx_buff_attrs(rx_ring,
177862306a36Sopenharmony_ci								&rx_ring->rx_buffer_info[req_id],
177962306a36Sopenharmony_ci								DMA_ATTR_SKIP_CPU_SYNC);
178062306a36Sopenharmony_ci					rx_ring->rx_buffer_info[req_id].page = NULL;
178162306a36Sopenharmony_ci				}
178262306a36Sopenharmony_ci			}
178362306a36Sopenharmony_ci			if (xdp_verdict != ENA_XDP_PASS) {
178462306a36Sopenharmony_ci				xdp_flags |= xdp_verdict;
178562306a36Sopenharmony_ci				total_len += ena_rx_ctx.ena_bufs[0].len;
178662306a36Sopenharmony_ci				res_budget--;
178762306a36Sopenharmony_ci				continue;
178862306a36Sopenharmony_ci			}
178962306a36Sopenharmony_ci			break;
179062306a36Sopenharmony_ci		}
179162306a36Sopenharmony_ci
179262306a36Sopenharmony_ci		ena_rx_checksum(rx_ring, &ena_rx_ctx, skb);
179362306a36Sopenharmony_ci
179462306a36Sopenharmony_ci		ena_set_rx_hash(rx_ring, &ena_rx_ctx, skb);
179562306a36Sopenharmony_ci
179662306a36Sopenharmony_ci		skb_record_rx_queue(skb, rx_ring->qid);
179762306a36Sopenharmony_ci
179862306a36Sopenharmony_ci		if (rx_ring->ena_bufs[0].len <= rx_ring->rx_copybreak)
179962306a36Sopenharmony_ci			rx_copybreak_pkt++;
180062306a36Sopenharmony_ci
180162306a36Sopenharmony_ci		total_len += skb->len;
180262306a36Sopenharmony_ci
180362306a36Sopenharmony_ci		napi_gro_receive(napi, skb);
180462306a36Sopenharmony_ci
180562306a36Sopenharmony_ci		res_budget--;
180662306a36Sopenharmony_ci	} while (likely(res_budget));
180762306a36Sopenharmony_ci
180862306a36Sopenharmony_ci	work_done = budget - res_budget;
180962306a36Sopenharmony_ci	rx_ring->per_napi_packets += work_done;
181062306a36Sopenharmony_ci	u64_stats_update_begin(&rx_ring->syncp);
181162306a36Sopenharmony_ci	rx_ring->rx_stats.bytes += total_len;
181262306a36Sopenharmony_ci	rx_ring->rx_stats.cnt += work_done;
181362306a36Sopenharmony_ci	rx_ring->rx_stats.rx_copybreak_pkt += rx_copybreak_pkt;
181462306a36Sopenharmony_ci	u64_stats_update_end(&rx_ring->syncp);
181562306a36Sopenharmony_ci
181662306a36Sopenharmony_ci	rx_ring->next_to_clean = next_to_clean;
181762306a36Sopenharmony_ci
181862306a36Sopenharmony_ci	refill_required = ena_com_free_q_entries(rx_ring->ena_com_io_sq);
181962306a36Sopenharmony_ci	refill_threshold =
182062306a36Sopenharmony_ci		min_t(int, rx_ring->ring_size / ENA_RX_REFILL_THRESH_DIVIDER,
182162306a36Sopenharmony_ci		      ENA_RX_REFILL_THRESH_PACKET);
182262306a36Sopenharmony_ci
182362306a36Sopenharmony_ci	/* Optimization, try to batch new rx buffers */
182462306a36Sopenharmony_ci	if (refill_required > refill_threshold) {
182562306a36Sopenharmony_ci		ena_com_update_dev_comp_head(rx_ring->ena_com_io_cq);
182662306a36Sopenharmony_ci		ena_refill_rx_bufs(rx_ring, refill_required);
182762306a36Sopenharmony_ci	}
182862306a36Sopenharmony_ci
182962306a36Sopenharmony_ci	if (xdp_flags & ENA_XDP_REDIRECT)
183062306a36Sopenharmony_ci		xdp_do_flush_map();
183162306a36Sopenharmony_ci
183262306a36Sopenharmony_ci	return work_done;
183362306a36Sopenharmony_ci
183462306a36Sopenharmony_cierror:
183562306a36Sopenharmony_ci	if (xdp_flags & ENA_XDP_REDIRECT)
183662306a36Sopenharmony_ci		xdp_do_flush();
183762306a36Sopenharmony_ci
183862306a36Sopenharmony_ci	adapter = netdev_priv(rx_ring->netdev);
183962306a36Sopenharmony_ci
184062306a36Sopenharmony_ci	if (rc == -ENOSPC) {
184162306a36Sopenharmony_ci		ena_increase_stat(&rx_ring->rx_stats.bad_desc_num, 1,
184262306a36Sopenharmony_ci				  &rx_ring->syncp);
184362306a36Sopenharmony_ci		ena_reset_device(adapter, ENA_REGS_RESET_TOO_MANY_RX_DESCS);
184462306a36Sopenharmony_ci	} else {
184562306a36Sopenharmony_ci		ena_increase_stat(&rx_ring->rx_stats.bad_req_id, 1,
184662306a36Sopenharmony_ci				  &rx_ring->syncp);
184762306a36Sopenharmony_ci		ena_reset_device(adapter, ENA_REGS_RESET_INV_RX_REQ_ID);
184862306a36Sopenharmony_ci	}
184962306a36Sopenharmony_ci	return 0;
185062306a36Sopenharmony_ci}
185162306a36Sopenharmony_ci
185262306a36Sopenharmony_cistatic void ena_dim_work(struct work_struct *w)
185362306a36Sopenharmony_ci{
185462306a36Sopenharmony_ci	struct dim *dim = container_of(w, struct dim, work);
185562306a36Sopenharmony_ci	struct dim_cq_moder cur_moder =
185662306a36Sopenharmony_ci		net_dim_get_rx_moderation(dim->mode, dim->profile_ix);
185762306a36Sopenharmony_ci	struct ena_napi *ena_napi = container_of(dim, struct ena_napi, dim);
185862306a36Sopenharmony_ci
185962306a36Sopenharmony_ci	ena_napi->rx_ring->smoothed_interval = cur_moder.usec;
186062306a36Sopenharmony_ci	dim->state = DIM_START_MEASURE;
186162306a36Sopenharmony_ci}
186262306a36Sopenharmony_ci
186362306a36Sopenharmony_cistatic void ena_adjust_adaptive_rx_intr_moderation(struct ena_napi *ena_napi)
186462306a36Sopenharmony_ci{
186562306a36Sopenharmony_ci	struct dim_sample dim_sample;
186662306a36Sopenharmony_ci	struct ena_ring *rx_ring = ena_napi->rx_ring;
186762306a36Sopenharmony_ci
186862306a36Sopenharmony_ci	if (!rx_ring->per_napi_packets)
186962306a36Sopenharmony_ci		return;
187062306a36Sopenharmony_ci
187162306a36Sopenharmony_ci	rx_ring->non_empty_napi_events++;
187262306a36Sopenharmony_ci
187362306a36Sopenharmony_ci	dim_update_sample(rx_ring->non_empty_napi_events,
187462306a36Sopenharmony_ci			  rx_ring->rx_stats.cnt,
187562306a36Sopenharmony_ci			  rx_ring->rx_stats.bytes,
187662306a36Sopenharmony_ci			  &dim_sample);
187762306a36Sopenharmony_ci
187862306a36Sopenharmony_ci	net_dim(&ena_napi->dim, dim_sample);
187962306a36Sopenharmony_ci
188062306a36Sopenharmony_ci	rx_ring->per_napi_packets = 0;
188162306a36Sopenharmony_ci}
188262306a36Sopenharmony_ci
188362306a36Sopenharmony_cistatic void ena_unmask_interrupt(struct ena_ring *tx_ring,
188462306a36Sopenharmony_ci					struct ena_ring *rx_ring)
188562306a36Sopenharmony_ci{
188662306a36Sopenharmony_ci	u32 rx_interval = tx_ring->smoothed_interval;
188762306a36Sopenharmony_ci	struct ena_eth_io_intr_reg intr_reg;
188862306a36Sopenharmony_ci
188962306a36Sopenharmony_ci	/* Rx ring can be NULL when for XDP tx queues which don't have an
189062306a36Sopenharmony_ci	 * accompanying rx_ring pair.
189162306a36Sopenharmony_ci	 */
189262306a36Sopenharmony_ci	if (rx_ring)
189362306a36Sopenharmony_ci		rx_interval = ena_com_get_adaptive_moderation_enabled(rx_ring->ena_dev) ?
189462306a36Sopenharmony_ci			rx_ring->smoothed_interval :
189562306a36Sopenharmony_ci			ena_com_get_nonadaptive_moderation_interval_rx(rx_ring->ena_dev);
189662306a36Sopenharmony_ci
189762306a36Sopenharmony_ci	/* Update intr register: rx intr delay,
189862306a36Sopenharmony_ci	 * tx intr delay and interrupt unmask
189962306a36Sopenharmony_ci	 */
190062306a36Sopenharmony_ci	ena_com_update_intr_reg(&intr_reg,
190162306a36Sopenharmony_ci				rx_interval,
190262306a36Sopenharmony_ci				tx_ring->smoothed_interval,
190362306a36Sopenharmony_ci				true);
190462306a36Sopenharmony_ci
190562306a36Sopenharmony_ci	ena_increase_stat(&tx_ring->tx_stats.unmask_interrupt, 1,
190662306a36Sopenharmony_ci			  &tx_ring->syncp);
190762306a36Sopenharmony_ci
190862306a36Sopenharmony_ci	/* It is a shared MSI-X.
190962306a36Sopenharmony_ci	 * Tx and Rx CQ have pointer to it.
191062306a36Sopenharmony_ci	 * So we use one of them to reach the intr reg
191162306a36Sopenharmony_ci	 * The Tx ring is used because the rx_ring is NULL for XDP queues
191262306a36Sopenharmony_ci	 */
191362306a36Sopenharmony_ci	ena_com_unmask_intr(tx_ring->ena_com_io_cq, &intr_reg);
191462306a36Sopenharmony_ci}
191562306a36Sopenharmony_ci
191662306a36Sopenharmony_cistatic void ena_update_ring_numa_node(struct ena_ring *tx_ring,
191762306a36Sopenharmony_ci					     struct ena_ring *rx_ring)
191862306a36Sopenharmony_ci{
191962306a36Sopenharmony_ci	int cpu = get_cpu();
192062306a36Sopenharmony_ci	int numa_node;
192162306a36Sopenharmony_ci
192262306a36Sopenharmony_ci	/* Check only one ring since the 2 rings are running on the same cpu */
192362306a36Sopenharmony_ci	if (likely(tx_ring->cpu == cpu))
192462306a36Sopenharmony_ci		goto out;
192562306a36Sopenharmony_ci
192662306a36Sopenharmony_ci	tx_ring->cpu = cpu;
192762306a36Sopenharmony_ci	if (rx_ring)
192862306a36Sopenharmony_ci		rx_ring->cpu = cpu;
192962306a36Sopenharmony_ci
193062306a36Sopenharmony_ci	numa_node = cpu_to_node(cpu);
193162306a36Sopenharmony_ci
193262306a36Sopenharmony_ci	if (likely(tx_ring->numa_node == numa_node))
193362306a36Sopenharmony_ci		goto out;
193462306a36Sopenharmony_ci
193562306a36Sopenharmony_ci	put_cpu();
193662306a36Sopenharmony_ci
193762306a36Sopenharmony_ci	if (numa_node != NUMA_NO_NODE) {
193862306a36Sopenharmony_ci		ena_com_update_numa_node(tx_ring->ena_com_io_cq, numa_node);
193962306a36Sopenharmony_ci		tx_ring->numa_node = numa_node;
194062306a36Sopenharmony_ci		if (rx_ring) {
194162306a36Sopenharmony_ci			rx_ring->numa_node = numa_node;
194262306a36Sopenharmony_ci			ena_com_update_numa_node(rx_ring->ena_com_io_cq,
194362306a36Sopenharmony_ci						 numa_node);
194462306a36Sopenharmony_ci		}
194562306a36Sopenharmony_ci	}
194662306a36Sopenharmony_ci
194762306a36Sopenharmony_ci	return;
194862306a36Sopenharmony_ciout:
194962306a36Sopenharmony_ci	put_cpu();
195062306a36Sopenharmony_ci}
195162306a36Sopenharmony_ci
195262306a36Sopenharmony_cistatic int ena_clean_xdp_irq(struct ena_ring *xdp_ring, u32 budget)
195362306a36Sopenharmony_ci{
195462306a36Sopenharmony_ci	u32 total_done = 0;
195562306a36Sopenharmony_ci	u16 next_to_clean;
195662306a36Sopenharmony_ci	int tx_pkts = 0;
195762306a36Sopenharmony_ci	u16 req_id;
195862306a36Sopenharmony_ci	int rc;
195962306a36Sopenharmony_ci
196062306a36Sopenharmony_ci	if (unlikely(!xdp_ring))
196162306a36Sopenharmony_ci		return 0;
196262306a36Sopenharmony_ci	next_to_clean = xdp_ring->next_to_clean;
196362306a36Sopenharmony_ci
196462306a36Sopenharmony_ci	while (tx_pkts < budget) {
196562306a36Sopenharmony_ci		struct ena_tx_buffer *tx_info;
196662306a36Sopenharmony_ci		struct xdp_frame *xdpf;
196762306a36Sopenharmony_ci
196862306a36Sopenharmony_ci		rc = ena_com_tx_comp_req_id_get(xdp_ring->ena_com_io_cq,
196962306a36Sopenharmony_ci						&req_id);
197062306a36Sopenharmony_ci		if (rc) {
197162306a36Sopenharmony_ci			if (unlikely(rc == -EINVAL))
197262306a36Sopenharmony_ci				handle_invalid_req_id(xdp_ring, req_id, NULL,
197362306a36Sopenharmony_ci						      true);
197462306a36Sopenharmony_ci			break;
197562306a36Sopenharmony_ci		}
197662306a36Sopenharmony_ci
197762306a36Sopenharmony_ci		/* validate that the request id points to a valid xdp_frame */
197862306a36Sopenharmony_ci		rc = validate_xdp_req_id(xdp_ring, req_id);
197962306a36Sopenharmony_ci		if (rc)
198062306a36Sopenharmony_ci			break;
198162306a36Sopenharmony_ci
198262306a36Sopenharmony_ci		tx_info = &xdp_ring->tx_buffer_info[req_id];
198362306a36Sopenharmony_ci		xdpf = tx_info->xdpf;
198462306a36Sopenharmony_ci
198562306a36Sopenharmony_ci		tx_info->xdpf = NULL;
198662306a36Sopenharmony_ci		tx_info->last_jiffies = 0;
198762306a36Sopenharmony_ci		ena_unmap_tx_buff(xdp_ring, tx_info);
198862306a36Sopenharmony_ci
198962306a36Sopenharmony_ci		netif_dbg(xdp_ring->adapter, tx_done, xdp_ring->netdev,
199062306a36Sopenharmony_ci			  "tx_poll: q %d skb %p completed\n", xdp_ring->qid,
199162306a36Sopenharmony_ci			  xdpf);
199262306a36Sopenharmony_ci
199362306a36Sopenharmony_ci		tx_pkts++;
199462306a36Sopenharmony_ci		total_done += tx_info->tx_descs;
199562306a36Sopenharmony_ci
199662306a36Sopenharmony_ci		xdp_return_frame(xdpf);
199762306a36Sopenharmony_ci		xdp_ring->free_ids[next_to_clean] = req_id;
199862306a36Sopenharmony_ci		next_to_clean = ENA_TX_RING_IDX_NEXT(next_to_clean,
199962306a36Sopenharmony_ci						     xdp_ring->ring_size);
200062306a36Sopenharmony_ci	}
200162306a36Sopenharmony_ci
200262306a36Sopenharmony_ci	xdp_ring->next_to_clean = next_to_clean;
200362306a36Sopenharmony_ci	ena_com_comp_ack(xdp_ring->ena_com_io_sq, total_done);
200462306a36Sopenharmony_ci	ena_com_update_dev_comp_head(xdp_ring->ena_com_io_cq);
200562306a36Sopenharmony_ci
200662306a36Sopenharmony_ci	netif_dbg(xdp_ring->adapter, tx_done, xdp_ring->netdev,
200762306a36Sopenharmony_ci		  "tx_poll: q %d done. total pkts: %d\n",
200862306a36Sopenharmony_ci		  xdp_ring->qid, tx_pkts);
200962306a36Sopenharmony_ci
201062306a36Sopenharmony_ci	return tx_pkts;
201162306a36Sopenharmony_ci}
201262306a36Sopenharmony_ci
201362306a36Sopenharmony_cistatic int ena_io_poll(struct napi_struct *napi, int budget)
201462306a36Sopenharmony_ci{
201562306a36Sopenharmony_ci	struct ena_napi *ena_napi = container_of(napi, struct ena_napi, napi);
201662306a36Sopenharmony_ci	struct ena_ring *tx_ring, *rx_ring;
201762306a36Sopenharmony_ci	int tx_work_done;
201862306a36Sopenharmony_ci	int rx_work_done = 0;
201962306a36Sopenharmony_ci	int tx_budget;
202062306a36Sopenharmony_ci	int napi_comp_call = 0;
202162306a36Sopenharmony_ci	int ret;
202262306a36Sopenharmony_ci
202362306a36Sopenharmony_ci	tx_ring = ena_napi->tx_ring;
202462306a36Sopenharmony_ci	rx_ring = ena_napi->rx_ring;
202562306a36Sopenharmony_ci
202662306a36Sopenharmony_ci	tx_budget = tx_ring->ring_size / ENA_TX_POLL_BUDGET_DIVIDER;
202762306a36Sopenharmony_ci
202862306a36Sopenharmony_ci	if (!test_bit(ENA_FLAG_DEV_UP, &tx_ring->adapter->flags) ||
202962306a36Sopenharmony_ci	    test_bit(ENA_FLAG_TRIGGER_RESET, &tx_ring->adapter->flags)) {
203062306a36Sopenharmony_ci		napi_complete_done(napi, 0);
203162306a36Sopenharmony_ci		return 0;
203262306a36Sopenharmony_ci	}
203362306a36Sopenharmony_ci
203462306a36Sopenharmony_ci	tx_work_done = ena_clean_tx_irq(tx_ring, tx_budget);
203562306a36Sopenharmony_ci	/* On netpoll the budget is zero and the handler should only clean the
203662306a36Sopenharmony_ci	 * tx completions.
203762306a36Sopenharmony_ci	 */
203862306a36Sopenharmony_ci	if (likely(budget))
203962306a36Sopenharmony_ci		rx_work_done = ena_clean_rx_irq(rx_ring, napi, budget);
204062306a36Sopenharmony_ci
204162306a36Sopenharmony_ci	/* If the device is about to reset or down, avoid unmask
204262306a36Sopenharmony_ci	 * the interrupt and return 0 so NAPI won't reschedule
204362306a36Sopenharmony_ci	 */
204462306a36Sopenharmony_ci	if (unlikely(!test_bit(ENA_FLAG_DEV_UP, &tx_ring->adapter->flags) ||
204562306a36Sopenharmony_ci		     test_bit(ENA_FLAG_TRIGGER_RESET, &tx_ring->adapter->flags))) {
204662306a36Sopenharmony_ci		napi_complete_done(napi, 0);
204762306a36Sopenharmony_ci		ret = 0;
204862306a36Sopenharmony_ci
204962306a36Sopenharmony_ci	} else if ((budget > rx_work_done) && (tx_budget > tx_work_done)) {
205062306a36Sopenharmony_ci		napi_comp_call = 1;
205162306a36Sopenharmony_ci
205262306a36Sopenharmony_ci		/* Update numa and unmask the interrupt only when schedule
205362306a36Sopenharmony_ci		 * from the interrupt context (vs from sk_busy_loop)
205462306a36Sopenharmony_ci		 */
205562306a36Sopenharmony_ci		if (napi_complete_done(napi, rx_work_done) &&
205662306a36Sopenharmony_ci		    READ_ONCE(ena_napi->interrupts_masked)) {
205762306a36Sopenharmony_ci			smp_rmb(); /* make sure interrupts_masked is read */
205862306a36Sopenharmony_ci			WRITE_ONCE(ena_napi->interrupts_masked, false);
205962306a36Sopenharmony_ci			/* We apply adaptive moderation on Rx path only.
206062306a36Sopenharmony_ci			 * Tx uses static interrupt moderation.
206162306a36Sopenharmony_ci			 */
206262306a36Sopenharmony_ci			if (ena_com_get_adaptive_moderation_enabled(rx_ring->ena_dev))
206362306a36Sopenharmony_ci				ena_adjust_adaptive_rx_intr_moderation(ena_napi);
206462306a36Sopenharmony_ci
206562306a36Sopenharmony_ci			ena_update_ring_numa_node(tx_ring, rx_ring);
206662306a36Sopenharmony_ci			ena_unmask_interrupt(tx_ring, rx_ring);
206762306a36Sopenharmony_ci		}
206862306a36Sopenharmony_ci
206962306a36Sopenharmony_ci		ret = rx_work_done;
207062306a36Sopenharmony_ci	} else {
207162306a36Sopenharmony_ci		ret = budget;
207262306a36Sopenharmony_ci	}
207362306a36Sopenharmony_ci
207462306a36Sopenharmony_ci	u64_stats_update_begin(&tx_ring->syncp);
207562306a36Sopenharmony_ci	tx_ring->tx_stats.napi_comp += napi_comp_call;
207662306a36Sopenharmony_ci	tx_ring->tx_stats.tx_poll++;
207762306a36Sopenharmony_ci	u64_stats_update_end(&tx_ring->syncp);
207862306a36Sopenharmony_ci
207962306a36Sopenharmony_ci	tx_ring->tx_stats.last_napi_jiffies = jiffies;
208062306a36Sopenharmony_ci
208162306a36Sopenharmony_ci	return ret;
208262306a36Sopenharmony_ci}
208362306a36Sopenharmony_ci
208462306a36Sopenharmony_cistatic irqreturn_t ena_intr_msix_mgmnt(int irq, void *data)
208562306a36Sopenharmony_ci{
208662306a36Sopenharmony_ci	struct ena_adapter *adapter = (struct ena_adapter *)data;
208762306a36Sopenharmony_ci
208862306a36Sopenharmony_ci	ena_com_admin_q_comp_intr_handler(adapter->ena_dev);
208962306a36Sopenharmony_ci
209062306a36Sopenharmony_ci	/* Don't call the aenq handler before probe is done */
209162306a36Sopenharmony_ci	if (likely(test_bit(ENA_FLAG_DEVICE_RUNNING, &adapter->flags)))
209262306a36Sopenharmony_ci		ena_com_aenq_intr_handler(adapter->ena_dev, data);
209362306a36Sopenharmony_ci
209462306a36Sopenharmony_ci	return IRQ_HANDLED;
209562306a36Sopenharmony_ci}
209662306a36Sopenharmony_ci
209762306a36Sopenharmony_ci/* ena_intr_msix_io - MSI-X Interrupt Handler for Tx/Rx
209862306a36Sopenharmony_ci * @irq: interrupt number
209962306a36Sopenharmony_ci * @data: pointer to a network interface private napi device structure
210062306a36Sopenharmony_ci */
210162306a36Sopenharmony_cistatic irqreturn_t ena_intr_msix_io(int irq, void *data)
210262306a36Sopenharmony_ci{
210362306a36Sopenharmony_ci	struct ena_napi *ena_napi = data;
210462306a36Sopenharmony_ci
210562306a36Sopenharmony_ci	/* Used to check HW health */
210662306a36Sopenharmony_ci	WRITE_ONCE(ena_napi->first_interrupt, true);
210762306a36Sopenharmony_ci
210862306a36Sopenharmony_ci	WRITE_ONCE(ena_napi->interrupts_masked, true);
210962306a36Sopenharmony_ci	smp_wmb(); /* write interrupts_masked before calling napi */
211062306a36Sopenharmony_ci
211162306a36Sopenharmony_ci	napi_schedule_irqoff(&ena_napi->napi);
211262306a36Sopenharmony_ci
211362306a36Sopenharmony_ci	return IRQ_HANDLED;
211462306a36Sopenharmony_ci}
211562306a36Sopenharmony_ci
211662306a36Sopenharmony_ci/* Reserve a single MSI-X vector for management (admin + aenq).
211762306a36Sopenharmony_ci * plus reserve one vector for each potential io queue.
211862306a36Sopenharmony_ci * the number of potential io queues is the minimum of what the device
211962306a36Sopenharmony_ci * supports and the number of vCPUs.
212062306a36Sopenharmony_ci */
212162306a36Sopenharmony_cistatic int ena_enable_msix(struct ena_adapter *adapter)
212262306a36Sopenharmony_ci{
212362306a36Sopenharmony_ci	int msix_vecs, irq_cnt;
212462306a36Sopenharmony_ci
212562306a36Sopenharmony_ci	if (test_bit(ENA_FLAG_MSIX_ENABLED, &adapter->flags)) {
212662306a36Sopenharmony_ci		netif_err(adapter, probe, adapter->netdev,
212762306a36Sopenharmony_ci			  "Error, MSI-X is already enabled\n");
212862306a36Sopenharmony_ci		return -EPERM;
212962306a36Sopenharmony_ci	}
213062306a36Sopenharmony_ci
213162306a36Sopenharmony_ci	/* Reserved the max msix vectors we might need */
213262306a36Sopenharmony_ci	msix_vecs = ENA_MAX_MSIX_VEC(adapter->max_num_io_queues);
213362306a36Sopenharmony_ci	netif_dbg(adapter, probe, adapter->netdev,
213462306a36Sopenharmony_ci		  "Trying to enable MSI-X, vectors %d\n", msix_vecs);
213562306a36Sopenharmony_ci
213662306a36Sopenharmony_ci	irq_cnt = pci_alloc_irq_vectors(adapter->pdev, ENA_MIN_MSIX_VEC,
213762306a36Sopenharmony_ci					msix_vecs, PCI_IRQ_MSIX);
213862306a36Sopenharmony_ci
213962306a36Sopenharmony_ci	if (irq_cnt < 0) {
214062306a36Sopenharmony_ci		netif_err(adapter, probe, adapter->netdev,
214162306a36Sopenharmony_ci			  "Failed to enable MSI-X. irq_cnt %d\n", irq_cnt);
214262306a36Sopenharmony_ci		return -ENOSPC;
214362306a36Sopenharmony_ci	}
214462306a36Sopenharmony_ci
214562306a36Sopenharmony_ci	if (irq_cnt != msix_vecs) {
214662306a36Sopenharmony_ci		netif_notice(adapter, probe, adapter->netdev,
214762306a36Sopenharmony_ci			     "Enable only %d MSI-X (out of %d), reduce the number of queues\n",
214862306a36Sopenharmony_ci			     irq_cnt, msix_vecs);
214962306a36Sopenharmony_ci		adapter->num_io_queues = irq_cnt - ENA_ADMIN_MSIX_VEC;
215062306a36Sopenharmony_ci	}
215162306a36Sopenharmony_ci
215262306a36Sopenharmony_ci	if (ena_init_rx_cpu_rmap(adapter))
215362306a36Sopenharmony_ci		netif_warn(adapter, probe, adapter->netdev,
215462306a36Sopenharmony_ci			   "Failed to map IRQs to CPUs\n");
215562306a36Sopenharmony_ci
215662306a36Sopenharmony_ci	adapter->msix_vecs = irq_cnt;
215762306a36Sopenharmony_ci	set_bit(ENA_FLAG_MSIX_ENABLED, &adapter->flags);
215862306a36Sopenharmony_ci
215962306a36Sopenharmony_ci	return 0;
216062306a36Sopenharmony_ci}
216162306a36Sopenharmony_ci
216262306a36Sopenharmony_cistatic void ena_setup_mgmnt_intr(struct ena_adapter *adapter)
216362306a36Sopenharmony_ci{
216462306a36Sopenharmony_ci	u32 cpu;
216562306a36Sopenharmony_ci
216662306a36Sopenharmony_ci	snprintf(adapter->irq_tbl[ENA_MGMNT_IRQ_IDX].name,
216762306a36Sopenharmony_ci		 ENA_IRQNAME_SIZE, "ena-mgmnt@pci:%s",
216862306a36Sopenharmony_ci		 pci_name(adapter->pdev));
216962306a36Sopenharmony_ci	adapter->irq_tbl[ENA_MGMNT_IRQ_IDX].handler =
217062306a36Sopenharmony_ci		ena_intr_msix_mgmnt;
217162306a36Sopenharmony_ci	adapter->irq_tbl[ENA_MGMNT_IRQ_IDX].data = adapter;
217262306a36Sopenharmony_ci	adapter->irq_tbl[ENA_MGMNT_IRQ_IDX].vector =
217362306a36Sopenharmony_ci		pci_irq_vector(adapter->pdev, ENA_MGMNT_IRQ_IDX);
217462306a36Sopenharmony_ci	cpu = cpumask_first(cpu_online_mask);
217562306a36Sopenharmony_ci	adapter->irq_tbl[ENA_MGMNT_IRQ_IDX].cpu = cpu;
217662306a36Sopenharmony_ci	cpumask_set_cpu(cpu,
217762306a36Sopenharmony_ci			&adapter->irq_tbl[ENA_MGMNT_IRQ_IDX].affinity_hint_mask);
217862306a36Sopenharmony_ci}
217962306a36Sopenharmony_ci
218062306a36Sopenharmony_cistatic void ena_setup_io_intr(struct ena_adapter *adapter)
218162306a36Sopenharmony_ci{
218262306a36Sopenharmony_ci	struct net_device *netdev;
218362306a36Sopenharmony_ci	int irq_idx, i, cpu;
218462306a36Sopenharmony_ci	int io_queue_count;
218562306a36Sopenharmony_ci
218662306a36Sopenharmony_ci	netdev = adapter->netdev;
218762306a36Sopenharmony_ci	io_queue_count = adapter->num_io_queues + adapter->xdp_num_queues;
218862306a36Sopenharmony_ci
218962306a36Sopenharmony_ci	for (i = 0; i < io_queue_count; i++) {
219062306a36Sopenharmony_ci		irq_idx = ENA_IO_IRQ_IDX(i);
219162306a36Sopenharmony_ci		cpu = i % num_online_cpus();
219262306a36Sopenharmony_ci
219362306a36Sopenharmony_ci		snprintf(adapter->irq_tbl[irq_idx].name, ENA_IRQNAME_SIZE,
219462306a36Sopenharmony_ci			 "%s-Tx-Rx-%d", netdev->name, i);
219562306a36Sopenharmony_ci		adapter->irq_tbl[irq_idx].handler = ena_intr_msix_io;
219662306a36Sopenharmony_ci		adapter->irq_tbl[irq_idx].data = &adapter->ena_napi[i];
219762306a36Sopenharmony_ci		adapter->irq_tbl[irq_idx].vector =
219862306a36Sopenharmony_ci			pci_irq_vector(adapter->pdev, irq_idx);
219962306a36Sopenharmony_ci		adapter->irq_tbl[irq_idx].cpu = cpu;
220062306a36Sopenharmony_ci
220162306a36Sopenharmony_ci		cpumask_set_cpu(cpu,
220262306a36Sopenharmony_ci				&adapter->irq_tbl[irq_idx].affinity_hint_mask);
220362306a36Sopenharmony_ci	}
220462306a36Sopenharmony_ci}
220562306a36Sopenharmony_ci
220662306a36Sopenharmony_cistatic int ena_request_mgmnt_irq(struct ena_adapter *adapter)
220762306a36Sopenharmony_ci{
220862306a36Sopenharmony_ci	unsigned long flags = 0;
220962306a36Sopenharmony_ci	struct ena_irq *irq;
221062306a36Sopenharmony_ci	int rc;
221162306a36Sopenharmony_ci
221262306a36Sopenharmony_ci	irq = &adapter->irq_tbl[ENA_MGMNT_IRQ_IDX];
221362306a36Sopenharmony_ci	rc = request_irq(irq->vector, irq->handler, flags, irq->name,
221462306a36Sopenharmony_ci			 irq->data);
221562306a36Sopenharmony_ci	if (rc) {
221662306a36Sopenharmony_ci		netif_err(adapter, probe, adapter->netdev,
221762306a36Sopenharmony_ci			  "Failed to request admin irq\n");
221862306a36Sopenharmony_ci		return rc;
221962306a36Sopenharmony_ci	}
222062306a36Sopenharmony_ci
222162306a36Sopenharmony_ci	netif_dbg(adapter, probe, adapter->netdev,
222262306a36Sopenharmony_ci		  "Set affinity hint of mgmnt irq.to 0x%lx (irq vector: %d)\n",
222362306a36Sopenharmony_ci		  irq->affinity_hint_mask.bits[0], irq->vector);
222462306a36Sopenharmony_ci
222562306a36Sopenharmony_ci	irq_set_affinity_hint(irq->vector, &irq->affinity_hint_mask);
222662306a36Sopenharmony_ci
222762306a36Sopenharmony_ci	return rc;
222862306a36Sopenharmony_ci}
222962306a36Sopenharmony_ci
223062306a36Sopenharmony_cistatic int ena_request_io_irq(struct ena_adapter *adapter)
223162306a36Sopenharmony_ci{
223262306a36Sopenharmony_ci	u32 io_queue_count = adapter->num_io_queues + adapter->xdp_num_queues;
223362306a36Sopenharmony_ci	unsigned long flags = 0;
223462306a36Sopenharmony_ci	struct ena_irq *irq;
223562306a36Sopenharmony_ci	int rc = 0, i, k;
223662306a36Sopenharmony_ci
223762306a36Sopenharmony_ci	if (!test_bit(ENA_FLAG_MSIX_ENABLED, &adapter->flags)) {
223862306a36Sopenharmony_ci		netif_err(adapter, ifup, adapter->netdev,
223962306a36Sopenharmony_ci			  "Failed to request I/O IRQ: MSI-X is not enabled\n");
224062306a36Sopenharmony_ci		return -EINVAL;
224162306a36Sopenharmony_ci	}
224262306a36Sopenharmony_ci
224362306a36Sopenharmony_ci	for (i = ENA_IO_IRQ_FIRST_IDX; i < ENA_MAX_MSIX_VEC(io_queue_count); i++) {
224462306a36Sopenharmony_ci		irq = &adapter->irq_tbl[i];
224562306a36Sopenharmony_ci		rc = request_irq(irq->vector, irq->handler, flags, irq->name,
224662306a36Sopenharmony_ci				 irq->data);
224762306a36Sopenharmony_ci		if (rc) {
224862306a36Sopenharmony_ci			netif_err(adapter, ifup, adapter->netdev,
224962306a36Sopenharmony_ci				  "Failed to request I/O IRQ. index %d rc %d\n",
225062306a36Sopenharmony_ci				   i, rc);
225162306a36Sopenharmony_ci			goto err;
225262306a36Sopenharmony_ci		}
225362306a36Sopenharmony_ci
225462306a36Sopenharmony_ci		netif_dbg(adapter, ifup, adapter->netdev,
225562306a36Sopenharmony_ci			  "Set affinity hint of irq. index %d to 0x%lx (irq vector: %d)\n",
225662306a36Sopenharmony_ci			  i, irq->affinity_hint_mask.bits[0], irq->vector);
225762306a36Sopenharmony_ci
225862306a36Sopenharmony_ci		irq_set_affinity_hint(irq->vector, &irq->affinity_hint_mask);
225962306a36Sopenharmony_ci	}
226062306a36Sopenharmony_ci
226162306a36Sopenharmony_ci	return rc;
226262306a36Sopenharmony_ci
226362306a36Sopenharmony_cierr:
226462306a36Sopenharmony_ci	for (k = ENA_IO_IRQ_FIRST_IDX; k < i; k++) {
226562306a36Sopenharmony_ci		irq = &adapter->irq_tbl[k];
226662306a36Sopenharmony_ci		free_irq(irq->vector, irq->data);
226762306a36Sopenharmony_ci	}
226862306a36Sopenharmony_ci
226962306a36Sopenharmony_ci	return rc;
227062306a36Sopenharmony_ci}
227162306a36Sopenharmony_ci
227262306a36Sopenharmony_cistatic void ena_free_mgmnt_irq(struct ena_adapter *adapter)
227362306a36Sopenharmony_ci{
227462306a36Sopenharmony_ci	struct ena_irq *irq;
227562306a36Sopenharmony_ci
227662306a36Sopenharmony_ci	irq = &adapter->irq_tbl[ENA_MGMNT_IRQ_IDX];
227762306a36Sopenharmony_ci	synchronize_irq(irq->vector);
227862306a36Sopenharmony_ci	irq_set_affinity_hint(irq->vector, NULL);
227962306a36Sopenharmony_ci	free_irq(irq->vector, irq->data);
228062306a36Sopenharmony_ci}
228162306a36Sopenharmony_ci
228262306a36Sopenharmony_cistatic void ena_free_io_irq(struct ena_adapter *adapter)
228362306a36Sopenharmony_ci{
228462306a36Sopenharmony_ci	u32 io_queue_count = adapter->num_io_queues + adapter->xdp_num_queues;
228562306a36Sopenharmony_ci	struct ena_irq *irq;
228662306a36Sopenharmony_ci	int i;
228762306a36Sopenharmony_ci
228862306a36Sopenharmony_ci#ifdef CONFIG_RFS_ACCEL
228962306a36Sopenharmony_ci	if (adapter->msix_vecs >= 1) {
229062306a36Sopenharmony_ci		free_irq_cpu_rmap(adapter->netdev->rx_cpu_rmap);
229162306a36Sopenharmony_ci		adapter->netdev->rx_cpu_rmap = NULL;
229262306a36Sopenharmony_ci	}
229362306a36Sopenharmony_ci#endif /* CONFIG_RFS_ACCEL */
229462306a36Sopenharmony_ci
229562306a36Sopenharmony_ci	for (i = ENA_IO_IRQ_FIRST_IDX; i < ENA_MAX_MSIX_VEC(io_queue_count); i++) {
229662306a36Sopenharmony_ci		irq = &adapter->irq_tbl[i];
229762306a36Sopenharmony_ci		irq_set_affinity_hint(irq->vector, NULL);
229862306a36Sopenharmony_ci		free_irq(irq->vector, irq->data);
229962306a36Sopenharmony_ci	}
230062306a36Sopenharmony_ci}
230162306a36Sopenharmony_ci
230262306a36Sopenharmony_cistatic void ena_disable_msix(struct ena_adapter *adapter)
230362306a36Sopenharmony_ci{
230462306a36Sopenharmony_ci	if (test_and_clear_bit(ENA_FLAG_MSIX_ENABLED, &adapter->flags))
230562306a36Sopenharmony_ci		pci_free_irq_vectors(adapter->pdev);
230662306a36Sopenharmony_ci}
230762306a36Sopenharmony_ci
230862306a36Sopenharmony_cistatic void ena_disable_io_intr_sync(struct ena_adapter *adapter)
230962306a36Sopenharmony_ci{
231062306a36Sopenharmony_ci	u32 io_queue_count = adapter->num_io_queues + adapter->xdp_num_queues;
231162306a36Sopenharmony_ci	int i;
231262306a36Sopenharmony_ci
231362306a36Sopenharmony_ci	if (!netif_running(adapter->netdev))
231462306a36Sopenharmony_ci		return;
231562306a36Sopenharmony_ci
231662306a36Sopenharmony_ci	for (i = ENA_IO_IRQ_FIRST_IDX; i < ENA_MAX_MSIX_VEC(io_queue_count); i++)
231762306a36Sopenharmony_ci		synchronize_irq(adapter->irq_tbl[i].vector);
231862306a36Sopenharmony_ci}
231962306a36Sopenharmony_ci
232062306a36Sopenharmony_cistatic void ena_del_napi_in_range(struct ena_adapter *adapter,
232162306a36Sopenharmony_ci				  int first_index,
232262306a36Sopenharmony_ci				  int count)
232362306a36Sopenharmony_ci{
232462306a36Sopenharmony_ci	int i;
232562306a36Sopenharmony_ci
232662306a36Sopenharmony_ci	for (i = first_index; i < first_index + count; i++) {
232762306a36Sopenharmony_ci		netif_napi_del(&adapter->ena_napi[i].napi);
232862306a36Sopenharmony_ci
232962306a36Sopenharmony_ci		WARN_ON(!ENA_IS_XDP_INDEX(adapter, i) &&
233062306a36Sopenharmony_ci			adapter->ena_napi[i].xdp_ring);
233162306a36Sopenharmony_ci	}
233262306a36Sopenharmony_ci}
233362306a36Sopenharmony_ci
233462306a36Sopenharmony_cistatic void ena_init_napi_in_range(struct ena_adapter *adapter,
233562306a36Sopenharmony_ci				   int first_index, int count)
233662306a36Sopenharmony_ci{
233762306a36Sopenharmony_ci	int i;
233862306a36Sopenharmony_ci
233962306a36Sopenharmony_ci	for (i = first_index; i < first_index + count; i++) {
234062306a36Sopenharmony_ci		struct ena_napi *napi = &adapter->ena_napi[i];
234162306a36Sopenharmony_ci
234262306a36Sopenharmony_ci		netif_napi_add(adapter->netdev, &napi->napi,
234362306a36Sopenharmony_ci			       ENA_IS_XDP_INDEX(adapter, i) ? ena_xdp_io_poll : ena_io_poll);
234462306a36Sopenharmony_ci
234562306a36Sopenharmony_ci		if (!ENA_IS_XDP_INDEX(adapter, i)) {
234662306a36Sopenharmony_ci			napi->rx_ring = &adapter->rx_ring[i];
234762306a36Sopenharmony_ci			napi->tx_ring = &adapter->tx_ring[i];
234862306a36Sopenharmony_ci		} else {
234962306a36Sopenharmony_ci			napi->xdp_ring = &adapter->tx_ring[i];
235062306a36Sopenharmony_ci		}
235162306a36Sopenharmony_ci		napi->qid = i;
235262306a36Sopenharmony_ci	}
235362306a36Sopenharmony_ci}
235462306a36Sopenharmony_ci
235562306a36Sopenharmony_cistatic void ena_napi_disable_in_range(struct ena_adapter *adapter,
235662306a36Sopenharmony_ci				      int first_index,
235762306a36Sopenharmony_ci				      int count)
235862306a36Sopenharmony_ci{
235962306a36Sopenharmony_ci	int i;
236062306a36Sopenharmony_ci
236162306a36Sopenharmony_ci	for (i = first_index; i < first_index + count; i++)
236262306a36Sopenharmony_ci		napi_disable(&adapter->ena_napi[i].napi);
236362306a36Sopenharmony_ci}
236462306a36Sopenharmony_ci
236562306a36Sopenharmony_cistatic void ena_napi_enable_in_range(struct ena_adapter *adapter,
236662306a36Sopenharmony_ci				     int first_index,
236762306a36Sopenharmony_ci				     int count)
236862306a36Sopenharmony_ci{
236962306a36Sopenharmony_ci	int i;
237062306a36Sopenharmony_ci
237162306a36Sopenharmony_ci	for (i = first_index; i < first_index + count; i++)
237262306a36Sopenharmony_ci		napi_enable(&adapter->ena_napi[i].napi);
237362306a36Sopenharmony_ci}
237462306a36Sopenharmony_ci
237562306a36Sopenharmony_ci/* Configure the Rx forwarding */
237662306a36Sopenharmony_cistatic int ena_rss_configure(struct ena_adapter *adapter)
237762306a36Sopenharmony_ci{
237862306a36Sopenharmony_ci	struct ena_com_dev *ena_dev = adapter->ena_dev;
237962306a36Sopenharmony_ci	int rc;
238062306a36Sopenharmony_ci
238162306a36Sopenharmony_ci	/* In case the RSS table wasn't initialized by probe */
238262306a36Sopenharmony_ci	if (!ena_dev->rss.tbl_log_size) {
238362306a36Sopenharmony_ci		rc = ena_rss_init_default(adapter);
238462306a36Sopenharmony_ci		if (rc && (rc != -EOPNOTSUPP)) {
238562306a36Sopenharmony_ci			netif_err(adapter, ifup, adapter->netdev,
238662306a36Sopenharmony_ci				  "Failed to init RSS rc: %d\n", rc);
238762306a36Sopenharmony_ci			return rc;
238862306a36Sopenharmony_ci		}
238962306a36Sopenharmony_ci	}
239062306a36Sopenharmony_ci
239162306a36Sopenharmony_ci	/* Set indirect table */
239262306a36Sopenharmony_ci	rc = ena_com_indirect_table_set(ena_dev);
239362306a36Sopenharmony_ci	if (unlikely(rc && rc != -EOPNOTSUPP))
239462306a36Sopenharmony_ci		return rc;
239562306a36Sopenharmony_ci
239662306a36Sopenharmony_ci	/* Configure hash function (if supported) */
239762306a36Sopenharmony_ci	rc = ena_com_set_hash_function(ena_dev);
239862306a36Sopenharmony_ci	if (unlikely(rc && (rc != -EOPNOTSUPP)))
239962306a36Sopenharmony_ci		return rc;
240062306a36Sopenharmony_ci
240162306a36Sopenharmony_ci	/* Configure hash inputs (if supported) */
240262306a36Sopenharmony_ci	rc = ena_com_set_hash_ctrl(ena_dev);
240362306a36Sopenharmony_ci	if (unlikely(rc && (rc != -EOPNOTSUPP)))
240462306a36Sopenharmony_ci		return rc;
240562306a36Sopenharmony_ci
240662306a36Sopenharmony_ci	return 0;
240762306a36Sopenharmony_ci}
240862306a36Sopenharmony_ci
240962306a36Sopenharmony_cistatic int ena_up_complete(struct ena_adapter *adapter)
241062306a36Sopenharmony_ci{
241162306a36Sopenharmony_ci	int rc;
241262306a36Sopenharmony_ci
241362306a36Sopenharmony_ci	rc = ena_rss_configure(adapter);
241462306a36Sopenharmony_ci	if (rc)
241562306a36Sopenharmony_ci		return rc;
241662306a36Sopenharmony_ci
241762306a36Sopenharmony_ci	ena_change_mtu(adapter->netdev, adapter->netdev->mtu);
241862306a36Sopenharmony_ci
241962306a36Sopenharmony_ci	ena_refill_all_rx_bufs(adapter);
242062306a36Sopenharmony_ci
242162306a36Sopenharmony_ci	/* enable transmits */
242262306a36Sopenharmony_ci	netif_tx_start_all_queues(adapter->netdev);
242362306a36Sopenharmony_ci
242462306a36Sopenharmony_ci	ena_napi_enable_in_range(adapter,
242562306a36Sopenharmony_ci				 0,
242662306a36Sopenharmony_ci				 adapter->xdp_num_queues + adapter->num_io_queues);
242762306a36Sopenharmony_ci
242862306a36Sopenharmony_ci	return 0;
242962306a36Sopenharmony_ci}
243062306a36Sopenharmony_ci
243162306a36Sopenharmony_cistatic int ena_create_io_tx_queue(struct ena_adapter *adapter, int qid)
243262306a36Sopenharmony_ci{
243362306a36Sopenharmony_ci	struct ena_com_create_io_ctx ctx;
243462306a36Sopenharmony_ci	struct ena_com_dev *ena_dev;
243562306a36Sopenharmony_ci	struct ena_ring *tx_ring;
243662306a36Sopenharmony_ci	u32 msix_vector;
243762306a36Sopenharmony_ci	u16 ena_qid;
243862306a36Sopenharmony_ci	int rc;
243962306a36Sopenharmony_ci
244062306a36Sopenharmony_ci	ena_dev = adapter->ena_dev;
244162306a36Sopenharmony_ci
244262306a36Sopenharmony_ci	tx_ring = &adapter->tx_ring[qid];
244362306a36Sopenharmony_ci	msix_vector = ENA_IO_IRQ_IDX(qid);
244462306a36Sopenharmony_ci	ena_qid = ENA_IO_TXQ_IDX(qid);
244562306a36Sopenharmony_ci
244662306a36Sopenharmony_ci	memset(&ctx, 0x0, sizeof(ctx));
244762306a36Sopenharmony_ci
244862306a36Sopenharmony_ci	ctx.direction = ENA_COM_IO_QUEUE_DIRECTION_TX;
244962306a36Sopenharmony_ci	ctx.qid = ena_qid;
245062306a36Sopenharmony_ci	ctx.mem_queue_type = ena_dev->tx_mem_queue_type;
245162306a36Sopenharmony_ci	ctx.msix_vector = msix_vector;
245262306a36Sopenharmony_ci	ctx.queue_size = tx_ring->ring_size;
245362306a36Sopenharmony_ci	ctx.numa_node = tx_ring->numa_node;
245462306a36Sopenharmony_ci
245562306a36Sopenharmony_ci	rc = ena_com_create_io_queue(ena_dev, &ctx);
245662306a36Sopenharmony_ci	if (rc) {
245762306a36Sopenharmony_ci		netif_err(adapter, ifup, adapter->netdev,
245862306a36Sopenharmony_ci			  "Failed to create I/O TX queue num %d rc: %d\n",
245962306a36Sopenharmony_ci			  qid, rc);
246062306a36Sopenharmony_ci		return rc;
246162306a36Sopenharmony_ci	}
246262306a36Sopenharmony_ci
246362306a36Sopenharmony_ci	rc = ena_com_get_io_handlers(ena_dev, ena_qid,
246462306a36Sopenharmony_ci				     &tx_ring->ena_com_io_sq,
246562306a36Sopenharmony_ci				     &tx_ring->ena_com_io_cq);
246662306a36Sopenharmony_ci	if (rc) {
246762306a36Sopenharmony_ci		netif_err(adapter, ifup, adapter->netdev,
246862306a36Sopenharmony_ci			  "Failed to get TX queue handlers. TX queue num %d rc: %d\n",
246962306a36Sopenharmony_ci			  qid, rc);
247062306a36Sopenharmony_ci		ena_com_destroy_io_queue(ena_dev, ena_qid);
247162306a36Sopenharmony_ci		return rc;
247262306a36Sopenharmony_ci	}
247362306a36Sopenharmony_ci
247462306a36Sopenharmony_ci	ena_com_update_numa_node(tx_ring->ena_com_io_cq, ctx.numa_node);
247562306a36Sopenharmony_ci	return rc;
247662306a36Sopenharmony_ci}
247762306a36Sopenharmony_ci
247862306a36Sopenharmony_cistatic int ena_create_io_tx_queues_in_range(struct ena_adapter *adapter,
247962306a36Sopenharmony_ci					    int first_index, int count)
248062306a36Sopenharmony_ci{
248162306a36Sopenharmony_ci	struct ena_com_dev *ena_dev = adapter->ena_dev;
248262306a36Sopenharmony_ci	int rc, i;
248362306a36Sopenharmony_ci
248462306a36Sopenharmony_ci	for (i = first_index; i < first_index + count; i++) {
248562306a36Sopenharmony_ci		rc = ena_create_io_tx_queue(adapter, i);
248662306a36Sopenharmony_ci		if (rc)
248762306a36Sopenharmony_ci			goto create_err;
248862306a36Sopenharmony_ci	}
248962306a36Sopenharmony_ci
249062306a36Sopenharmony_ci	return 0;
249162306a36Sopenharmony_ci
249262306a36Sopenharmony_cicreate_err:
249362306a36Sopenharmony_ci	while (i-- > first_index)
249462306a36Sopenharmony_ci		ena_com_destroy_io_queue(ena_dev, ENA_IO_TXQ_IDX(i));
249562306a36Sopenharmony_ci
249662306a36Sopenharmony_ci	return rc;
249762306a36Sopenharmony_ci}
249862306a36Sopenharmony_ci
249962306a36Sopenharmony_cistatic int ena_create_io_rx_queue(struct ena_adapter *adapter, int qid)
250062306a36Sopenharmony_ci{
250162306a36Sopenharmony_ci	struct ena_com_dev *ena_dev;
250262306a36Sopenharmony_ci	struct ena_com_create_io_ctx ctx;
250362306a36Sopenharmony_ci	struct ena_ring *rx_ring;
250462306a36Sopenharmony_ci	u32 msix_vector;
250562306a36Sopenharmony_ci	u16 ena_qid;
250662306a36Sopenharmony_ci	int rc;
250762306a36Sopenharmony_ci
250862306a36Sopenharmony_ci	ena_dev = adapter->ena_dev;
250962306a36Sopenharmony_ci
251062306a36Sopenharmony_ci	rx_ring = &adapter->rx_ring[qid];
251162306a36Sopenharmony_ci	msix_vector = ENA_IO_IRQ_IDX(qid);
251262306a36Sopenharmony_ci	ena_qid = ENA_IO_RXQ_IDX(qid);
251362306a36Sopenharmony_ci
251462306a36Sopenharmony_ci	memset(&ctx, 0x0, sizeof(ctx));
251562306a36Sopenharmony_ci
251662306a36Sopenharmony_ci	ctx.qid = ena_qid;
251762306a36Sopenharmony_ci	ctx.direction = ENA_COM_IO_QUEUE_DIRECTION_RX;
251862306a36Sopenharmony_ci	ctx.mem_queue_type = ENA_ADMIN_PLACEMENT_POLICY_HOST;
251962306a36Sopenharmony_ci	ctx.msix_vector = msix_vector;
252062306a36Sopenharmony_ci	ctx.queue_size = rx_ring->ring_size;
252162306a36Sopenharmony_ci	ctx.numa_node = rx_ring->numa_node;
252262306a36Sopenharmony_ci
252362306a36Sopenharmony_ci	rc = ena_com_create_io_queue(ena_dev, &ctx);
252462306a36Sopenharmony_ci	if (rc) {
252562306a36Sopenharmony_ci		netif_err(adapter, ifup, adapter->netdev,
252662306a36Sopenharmony_ci			  "Failed to create I/O RX queue num %d rc: %d\n",
252762306a36Sopenharmony_ci			  qid, rc);
252862306a36Sopenharmony_ci		return rc;
252962306a36Sopenharmony_ci	}
253062306a36Sopenharmony_ci
253162306a36Sopenharmony_ci	rc = ena_com_get_io_handlers(ena_dev, ena_qid,
253262306a36Sopenharmony_ci				     &rx_ring->ena_com_io_sq,
253362306a36Sopenharmony_ci				     &rx_ring->ena_com_io_cq);
253462306a36Sopenharmony_ci	if (rc) {
253562306a36Sopenharmony_ci		netif_err(adapter, ifup, adapter->netdev,
253662306a36Sopenharmony_ci			  "Failed to get RX queue handlers. RX queue num %d rc: %d\n",
253762306a36Sopenharmony_ci			  qid, rc);
253862306a36Sopenharmony_ci		goto err;
253962306a36Sopenharmony_ci	}
254062306a36Sopenharmony_ci
254162306a36Sopenharmony_ci	ena_com_update_numa_node(rx_ring->ena_com_io_cq, ctx.numa_node);
254262306a36Sopenharmony_ci
254362306a36Sopenharmony_ci	return rc;
254462306a36Sopenharmony_cierr:
254562306a36Sopenharmony_ci	ena_com_destroy_io_queue(ena_dev, ena_qid);
254662306a36Sopenharmony_ci	return rc;
254762306a36Sopenharmony_ci}
254862306a36Sopenharmony_ci
254962306a36Sopenharmony_cistatic int ena_create_all_io_rx_queues(struct ena_adapter *adapter)
255062306a36Sopenharmony_ci{
255162306a36Sopenharmony_ci	struct ena_com_dev *ena_dev = adapter->ena_dev;
255262306a36Sopenharmony_ci	int rc, i;
255362306a36Sopenharmony_ci
255462306a36Sopenharmony_ci	for (i = 0; i < adapter->num_io_queues; i++) {
255562306a36Sopenharmony_ci		rc = ena_create_io_rx_queue(adapter, i);
255662306a36Sopenharmony_ci		if (rc)
255762306a36Sopenharmony_ci			goto create_err;
255862306a36Sopenharmony_ci		INIT_WORK(&adapter->ena_napi[i].dim.work, ena_dim_work);
255962306a36Sopenharmony_ci	}
256062306a36Sopenharmony_ci
256162306a36Sopenharmony_ci	return 0;
256262306a36Sopenharmony_ci
256362306a36Sopenharmony_cicreate_err:
256462306a36Sopenharmony_ci	while (i--) {
256562306a36Sopenharmony_ci		cancel_work_sync(&adapter->ena_napi[i].dim.work);
256662306a36Sopenharmony_ci		ena_com_destroy_io_queue(ena_dev, ENA_IO_RXQ_IDX(i));
256762306a36Sopenharmony_ci	}
256862306a36Sopenharmony_ci
256962306a36Sopenharmony_ci	return rc;
257062306a36Sopenharmony_ci}
257162306a36Sopenharmony_ci
257262306a36Sopenharmony_cistatic void set_io_rings_size(struct ena_adapter *adapter,
257362306a36Sopenharmony_ci			      int new_tx_size,
257462306a36Sopenharmony_ci			      int new_rx_size)
257562306a36Sopenharmony_ci{
257662306a36Sopenharmony_ci	int i;
257762306a36Sopenharmony_ci
257862306a36Sopenharmony_ci	for (i = 0; i < adapter->num_io_queues; i++) {
257962306a36Sopenharmony_ci		adapter->tx_ring[i].ring_size = new_tx_size;
258062306a36Sopenharmony_ci		adapter->rx_ring[i].ring_size = new_rx_size;
258162306a36Sopenharmony_ci	}
258262306a36Sopenharmony_ci}
258362306a36Sopenharmony_ci
258462306a36Sopenharmony_ci/* This function allows queue allocation to backoff when the system is
258562306a36Sopenharmony_ci * low on memory. If there is not enough memory to allocate io queues
258662306a36Sopenharmony_ci * the driver will try to allocate smaller queues.
258762306a36Sopenharmony_ci *
258862306a36Sopenharmony_ci * The backoff algorithm is as follows:
258962306a36Sopenharmony_ci *  1. Try to allocate TX and RX and if successful.
259062306a36Sopenharmony_ci *  1.1. return success
259162306a36Sopenharmony_ci *
259262306a36Sopenharmony_ci *  2. Divide by 2 the size of the larger of RX and TX queues (or both if their size is the same).
259362306a36Sopenharmony_ci *
259462306a36Sopenharmony_ci *  3. If TX or RX is smaller than 256
259562306a36Sopenharmony_ci *  3.1. return failure.
259662306a36Sopenharmony_ci *  4. else
259762306a36Sopenharmony_ci *  4.1. go back to 1.
259862306a36Sopenharmony_ci */
259962306a36Sopenharmony_cistatic int create_queues_with_size_backoff(struct ena_adapter *adapter)
260062306a36Sopenharmony_ci{
260162306a36Sopenharmony_ci	int rc, cur_rx_ring_size, cur_tx_ring_size;
260262306a36Sopenharmony_ci	int new_rx_ring_size, new_tx_ring_size;
260362306a36Sopenharmony_ci
260462306a36Sopenharmony_ci	/* current queue sizes might be set to smaller than the requested
260562306a36Sopenharmony_ci	 * ones due to past queue allocation failures.
260662306a36Sopenharmony_ci	 */
260762306a36Sopenharmony_ci	set_io_rings_size(adapter, adapter->requested_tx_ring_size,
260862306a36Sopenharmony_ci			  adapter->requested_rx_ring_size);
260962306a36Sopenharmony_ci
261062306a36Sopenharmony_ci	while (1) {
261162306a36Sopenharmony_ci		if (ena_xdp_present(adapter)) {
261262306a36Sopenharmony_ci			rc = ena_setup_and_create_all_xdp_queues(adapter);
261362306a36Sopenharmony_ci
261462306a36Sopenharmony_ci			if (rc)
261562306a36Sopenharmony_ci				goto err_setup_tx;
261662306a36Sopenharmony_ci		}
261762306a36Sopenharmony_ci		rc = ena_setup_tx_resources_in_range(adapter,
261862306a36Sopenharmony_ci						     0,
261962306a36Sopenharmony_ci						     adapter->num_io_queues);
262062306a36Sopenharmony_ci		if (rc)
262162306a36Sopenharmony_ci			goto err_setup_tx;
262262306a36Sopenharmony_ci
262362306a36Sopenharmony_ci		rc = ena_create_io_tx_queues_in_range(adapter,
262462306a36Sopenharmony_ci						      0,
262562306a36Sopenharmony_ci						      adapter->num_io_queues);
262662306a36Sopenharmony_ci		if (rc)
262762306a36Sopenharmony_ci			goto err_create_tx_queues;
262862306a36Sopenharmony_ci
262962306a36Sopenharmony_ci		rc = ena_setup_all_rx_resources(adapter);
263062306a36Sopenharmony_ci		if (rc)
263162306a36Sopenharmony_ci			goto err_setup_rx;
263262306a36Sopenharmony_ci
263362306a36Sopenharmony_ci		rc = ena_create_all_io_rx_queues(adapter);
263462306a36Sopenharmony_ci		if (rc)
263562306a36Sopenharmony_ci			goto err_create_rx_queues;
263662306a36Sopenharmony_ci
263762306a36Sopenharmony_ci		return 0;
263862306a36Sopenharmony_ci
263962306a36Sopenharmony_cierr_create_rx_queues:
264062306a36Sopenharmony_ci		ena_free_all_io_rx_resources(adapter);
264162306a36Sopenharmony_cierr_setup_rx:
264262306a36Sopenharmony_ci		ena_destroy_all_tx_queues(adapter);
264362306a36Sopenharmony_cierr_create_tx_queues:
264462306a36Sopenharmony_ci		ena_free_all_io_tx_resources(adapter);
264562306a36Sopenharmony_cierr_setup_tx:
264662306a36Sopenharmony_ci		if (rc != -ENOMEM) {
264762306a36Sopenharmony_ci			netif_err(adapter, ifup, adapter->netdev,
264862306a36Sopenharmony_ci				  "Queue creation failed with error code %d\n",
264962306a36Sopenharmony_ci				  rc);
265062306a36Sopenharmony_ci			return rc;
265162306a36Sopenharmony_ci		}
265262306a36Sopenharmony_ci
265362306a36Sopenharmony_ci		cur_tx_ring_size = adapter->tx_ring[0].ring_size;
265462306a36Sopenharmony_ci		cur_rx_ring_size = adapter->rx_ring[0].ring_size;
265562306a36Sopenharmony_ci
265662306a36Sopenharmony_ci		netif_err(adapter, ifup, adapter->netdev,
265762306a36Sopenharmony_ci			  "Not enough memory to create queues with sizes TX=%d, RX=%d\n",
265862306a36Sopenharmony_ci			  cur_tx_ring_size, cur_rx_ring_size);
265962306a36Sopenharmony_ci
266062306a36Sopenharmony_ci		new_tx_ring_size = cur_tx_ring_size;
266162306a36Sopenharmony_ci		new_rx_ring_size = cur_rx_ring_size;
266262306a36Sopenharmony_ci
266362306a36Sopenharmony_ci		/* Decrease the size of the larger queue, or
266462306a36Sopenharmony_ci		 * decrease both if they are the same size.
266562306a36Sopenharmony_ci		 */
266662306a36Sopenharmony_ci		if (cur_rx_ring_size <= cur_tx_ring_size)
266762306a36Sopenharmony_ci			new_tx_ring_size = cur_tx_ring_size / 2;
266862306a36Sopenharmony_ci		if (cur_rx_ring_size >= cur_tx_ring_size)
266962306a36Sopenharmony_ci			new_rx_ring_size = cur_rx_ring_size / 2;
267062306a36Sopenharmony_ci
267162306a36Sopenharmony_ci		if (new_tx_ring_size < ENA_MIN_RING_SIZE ||
267262306a36Sopenharmony_ci		    new_rx_ring_size < ENA_MIN_RING_SIZE) {
267362306a36Sopenharmony_ci			netif_err(adapter, ifup, adapter->netdev,
267462306a36Sopenharmony_ci				  "Queue creation failed with the smallest possible queue size of %d for both queues. Not retrying with smaller queues\n",
267562306a36Sopenharmony_ci				  ENA_MIN_RING_SIZE);
267662306a36Sopenharmony_ci			return rc;
267762306a36Sopenharmony_ci		}
267862306a36Sopenharmony_ci
267962306a36Sopenharmony_ci		netif_err(adapter, ifup, adapter->netdev,
268062306a36Sopenharmony_ci			  "Retrying queue creation with sizes TX=%d, RX=%d\n",
268162306a36Sopenharmony_ci			  new_tx_ring_size,
268262306a36Sopenharmony_ci			  new_rx_ring_size);
268362306a36Sopenharmony_ci
268462306a36Sopenharmony_ci		set_io_rings_size(adapter, new_tx_ring_size,
268562306a36Sopenharmony_ci				  new_rx_ring_size);
268662306a36Sopenharmony_ci	}
268762306a36Sopenharmony_ci}
268862306a36Sopenharmony_ci
268962306a36Sopenharmony_cistatic int ena_up(struct ena_adapter *adapter)
269062306a36Sopenharmony_ci{
269162306a36Sopenharmony_ci	int io_queue_count, rc, i;
269262306a36Sopenharmony_ci
269362306a36Sopenharmony_ci	netif_dbg(adapter, ifup, adapter->netdev, "%s\n", __func__);
269462306a36Sopenharmony_ci
269562306a36Sopenharmony_ci	io_queue_count = adapter->num_io_queues + adapter->xdp_num_queues;
269662306a36Sopenharmony_ci	ena_setup_io_intr(adapter);
269762306a36Sopenharmony_ci
269862306a36Sopenharmony_ci	/* napi poll functions should be initialized before running
269962306a36Sopenharmony_ci	 * request_irq(), to handle a rare condition where there is a pending
270062306a36Sopenharmony_ci	 * interrupt, causing the ISR to fire immediately while the poll
270162306a36Sopenharmony_ci	 * function wasn't set yet, causing a null dereference
270262306a36Sopenharmony_ci	 */
270362306a36Sopenharmony_ci	ena_init_napi_in_range(adapter, 0, io_queue_count);
270462306a36Sopenharmony_ci
270562306a36Sopenharmony_ci	rc = ena_request_io_irq(adapter);
270662306a36Sopenharmony_ci	if (rc)
270762306a36Sopenharmony_ci		goto err_req_irq;
270862306a36Sopenharmony_ci
270962306a36Sopenharmony_ci	rc = create_queues_with_size_backoff(adapter);
271062306a36Sopenharmony_ci	if (rc)
271162306a36Sopenharmony_ci		goto err_create_queues_with_backoff;
271262306a36Sopenharmony_ci
271362306a36Sopenharmony_ci	rc = ena_up_complete(adapter);
271462306a36Sopenharmony_ci	if (rc)
271562306a36Sopenharmony_ci		goto err_up;
271662306a36Sopenharmony_ci
271762306a36Sopenharmony_ci	if (test_bit(ENA_FLAG_LINK_UP, &adapter->flags))
271862306a36Sopenharmony_ci		netif_carrier_on(adapter->netdev);
271962306a36Sopenharmony_ci
272062306a36Sopenharmony_ci	ena_increase_stat(&adapter->dev_stats.interface_up, 1,
272162306a36Sopenharmony_ci			  &adapter->syncp);
272262306a36Sopenharmony_ci
272362306a36Sopenharmony_ci	set_bit(ENA_FLAG_DEV_UP, &adapter->flags);
272462306a36Sopenharmony_ci
272562306a36Sopenharmony_ci	/* Enable completion queues interrupt */
272662306a36Sopenharmony_ci	for (i = 0; i < adapter->num_io_queues; i++)
272762306a36Sopenharmony_ci		ena_unmask_interrupt(&adapter->tx_ring[i],
272862306a36Sopenharmony_ci				     &adapter->rx_ring[i]);
272962306a36Sopenharmony_ci
273062306a36Sopenharmony_ci	/* schedule napi in case we had pending packets
273162306a36Sopenharmony_ci	 * from the last time we disable napi
273262306a36Sopenharmony_ci	 */
273362306a36Sopenharmony_ci	for (i = 0; i < io_queue_count; i++)
273462306a36Sopenharmony_ci		napi_schedule(&adapter->ena_napi[i].napi);
273562306a36Sopenharmony_ci
273662306a36Sopenharmony_ci	return rc;
273762306a36Sopenharmony_ci
273862306a36Sopenharmony_cierr_up:
273962306a36Sopenharmony_ci	ena_destroy_all_tx_queues(adapter);
274062306a36Sopenharmony_ci	ena_free_all_io_tx_resources(adapter);
274162306a36Sopenharmony_ci	ena_destroy_all_rx_queues(adapter);
274262306a36Sopenharmony_ci	ena_free_all_io_rx_resources(adapter);
274362306a36Sopenharmony_cierr_create_queues_with_backoff:
274462306a36Sopenharmony_ci	ena_free_io_irq(adapter);
274562306a36Sopenharmony_cierr_req_irq:
274662306a36Sopenharmony_ci	ena_del_napi_in_range(adapter, 0, io_queue_count);
274762306a36Sopenharmony_ci
274862306a36Sopenharmony_ci	return rc;
274962306a36Sopenharmony_ci}
275062306a36Sopenharmony_ci
275162306a36Sopenharmony_cistatic void ena_down(struct ena_adapter *adapter)
275262306a36Sopenharmony_ci{
275362306a36Sopenharmony_ci	int io_queue_count = adapter->num_io_queues + adapter->xdp_num_queues;
275462306a36Sopenharmony_ci
275562306a36Sopenharmony_ci	netif_info(adapter, ifdown, adapter->netdev, "%s\n", __func__);
275662306a36Sopenharmony_ci
275762306a36Sopenharmony_ci	clear_bit(ENA_FLAG_DEV_UP, &adapter->flags);
275862306a36Sopenharmony_ci
275962306a36Sopenharmony_ci	ena_increase_stat(&adapter->dev_stats.interface_down, 1,
276062306a36Sopenharmony_ci			  &adapter->syncp);
276162306a36Sopenharmony_ci
276262306a36Sopenharmony_ci	netif_carrier_off(adapter->netdev);
276362306a36Sopenharmony_ci	netif_tx_disable(adapter->netdev);
276462306a36Sopenharmony_ci
276562306a36Sopenharmony_ci	/* After this point the napi handler won't enable the tx queue */
276662306a36Sopenharmony_ci	ena_napi_disable_in_range(adapter, 0, io_queue_count);
276762306a36Sopenharmony_ci
276862306a36Sopenharmony_ci	/* After destroy the queue there won't be any new interrupts */
276962306a36Sopenharmony_ci
277062306a36Sopenharmony_ci	if (test_bit(ENA_FLAG_TRIGGER_RESET, &adapter->flags)) {
277162306a36Sopenharmony_ci		int rc;
277262306a36Sopenharmony_ci
277362306a36Sopenharmony_ci		rc = ena_com_dev_reset(adapter->ena_dev, adapter->reset_reason);
277462306a36Sopenharmony_ci		if (rc)
277562306a36Sopenharmony_ci			netif_err(adapter, ifdown, adapter->netdev,
277662306a36Sopenharmony_ci				  "Device reset failed\n");
277762306a36Sopenharmony_ci		/* stop submitting admin commands on a device that was reset */
277862306a36Sopenharmony_ci		ena_com_set_admin_running_state(adapter->ena_dev, false);
277962306a36Sopenharmony_ci	}
278062306a36Sopenharmony_ci
278162306a36Sopenharmony_ci	ena_destroy_all_io_queues(adapter);
278262306a36Sopenharmony_ci
278362306a36Sopenharmony_ci	ena_disable_io_intr_sync(adapter);
278462306a36Sopenharmony_ci	ena_free_io_irq(adapter);
278562306a36Sopenharmony_ci	ena_del_napi_in_range(adapter, 0, io_queue_count);
278662306a36Sopenharmony_ci
278762306a36Sopenharmony_ci	ena_free_all_tx_bufs(adapter);
278862306a36Sopenharmony_ci	ena_free_all_rx_bufs(adapter);
278962306a36Sopenharmony_ci	ena_free_all_io_tx_resources(adapter);
279062306a36Sopenharmony_ci	ena_free_all_io_rx_resources(adapter);
279162306a36Sopenharmony_ci}
279262306a36Sopenharmony_ci
279362306a36Sopenharmony_ci/* ena_open - Called when a network interface is made active
279462306a36Sopenharmony_ci * @netdev: network interface device structure
279562306a36Sopenharmony_ci *
279662306a36Sopenharmony_ci * Returns 0 on success, negative value on failure
279762306a36Sopenharmony_ci *
279862306a36Sopenharmony_ci * The open entry point is called when a network interface is made
279962306a36Sopenharmony_ci * active by the system (IFF_UP).  At this point all resources needed
280062306a36Sopenharmony_ci * for transmit and receive operations are allocated, the interrupt
280162306a36Sopenharmony_ci * handler is registered with the OS, the watchdog timer is started,
280262306a36Sopenharmony_ci * and the stack is notified that the interface is ready.
280362306a36Sopenharmony_ci */
280462306a36Sopenharmony_cistatic int ena_open(struct net_device *netdev)
280562306a36Sopenharmony_ci{
280662306a36Sopenharmony_ci	struct ena_adapter *adapter = netdev_priv(netdev);
280762306a36Sopenharmony_ci	int rc;
280862306a36Sopenharmony_ci
280962306a36Sopenharmony_ci	/* Notify the stack of the actual queue counts. */
281062306a36Sopenharmony_ci	rc = netif_set_real_num_tx_queues(netdev, adapter->num_io_queues);
281162306a36Sopenharmony_ci	if (rc) {
281262306a36Sopenharmony_ci		netif_err(adapter, ifup, netdev, "Can't set num tx queues\n");
281362306a36Sopenharmony_ci		return rc;
281462306a36Sopenharmony_ci	}
281562306a36Sopenharmony_ci
281662306a36Sopenharmony_ci	rc = netif_set_real_num_rx_queues(netdev, adapter->num_io_queues);
281762306a36Sopenharmony_ci	if (rc) {
281862306a36Sopenharmony_ci		netif_err(adapter, ifup, netdev, "Can't set num rx queues\n");
281962306a36Sopenharmony_ci		return rc;
282062306a36Sopenharmony_ci	}
282162306a36Sopenharmony_ci
282262306a36Sopenharmony_ci	rc = ena_up(adapter);
282362306a36Sopenharmony_ci	if (rc)
282462306a36Sopenharmony_ci		return rc;
282562306a36Sopenharmony_ci
282662306a36Sopenharmony_ci	return rc;
282762306a36Sopenharmony_ci}
282862306a36Sopenharmony_ci
282962306a36Sopenharmony_ci/* ena_close - Disables a network interface
283062306a36Sopenharmony_ci * @netdev: network interface device structure
283162306a36Sopenharmony_ci *
283262306a36Sopenharmony_ci * Returns 0, this is not allowed to fail
283362306a36Sopenharmony_ci *
283462306a36Sopenharmony_ci * The close entry point is called when an interface is de-activated
283562306a36Sopenharmony_ci * by the OS.  The hardware is still under the drivers control, but
283662306a36Sopenharmony_ci * needs to be disabled.  A global MAC reset is issued to stop the
283762306a36Sopenharmony_ci * hardware, and all transmit and receive resources are freed.
283862306a36Sopenharmony_ci */
283962306a36Sopenharmony_cistatic int ena_close(struct net_device *netdev)
284062306a36Sopenharmony_ci{
284162306a36Sopenharmony_ci	struct ena_adapter *adapter = netdev_priv(netdev);
284262306a36Sopenharmony_ci
284362306a36Sopenharmony_ci	netif_dbg(adapter, ifdown, netdev, "%s\n", __func__);
284462306a36Sopenharmony_ci
284562306a36Sopenharmony_ci	if (!test_bit(ENA_FLAG_DEVICE_RUNNING, &adapter->flags))
284662306a36Sopenharmony_ci		return 0;
284762306a36Sopenharmony_ci
284862306a36Sopenharmony_ci	if (test_bit(ENA_FLAG_DEV_UP, &adapter->flags))
284962306a36Sopenharmony_ci		ena_down(adapter);
285062306a36Sopenharmony_ci
285162306a36Sopenharmony_ci	/* Check for device status and issue reset if needed*/
285262306a36Sopenharmony_ci	check_for_admin_com_state(adapter);
285362306a36Sopenharmony_ci	if (unlikely(test_bit(ENA_FLAG_TRIGGER_RESET, &adapter->flags))) {
285462306a36Sopenharmony_ci		netif_err(adapter, ifdown, adapter->netdev,
285562306a36Sopenharmony_ci			  "Destroy failure, restarting device\n");
285662306a36Sopenharmony_ci		ena_dump_stats_to_dmesg(adapter);
285762306a36Sopenharmony_ci		/* rtnl lock already obtained in dev_ioctl() layer */
285862306a36Sopenharmony_ci		ena_destroy_device(adapter, false);
285962306a36Sopenharmony_ci		ena_restore_device(adapter);
286062306a36Sopenharmony_ci	}
286162306a36Sopenharmony_ci
286262306a36Sopenharmony_ci	return 0;
286362306a36Sopenharmony_ci}
286462306a36Sopenharmony_ci
286562306a36Sopenharmony_ciint ena_update_queue_params(struct ena_adapter *adapter,
286662306a36Sopenharmony_ci			    u32 new_tx_size,
286762306a36Sopenharmony_ci			    u32 new_rx_size,
286862306a36Sopenharmony_ci			    u32 new_llq_header_len)
286962306a36Sopenharmony_ci{
287062306a36Sopenharmony_ci	bool dev_was_up, large_llq_changed = false;
287162306a36Sopenharmony_ci	int rc = 0;
287262306a36Sopenharmony_ci
287362306a36Sopenharmony_ci	dev_was_up = test_bit(ENA_FLAG_DEV_UP, &adapter->flags);
287462306a36Sopenharmony_ci	ena_close(adapter->netdev);
287562306a36Sopenharmony_ci	adapter->requested_tx_ring_size = new_tx_size;
287662306a36Sopenharmony_ci	adapter->requested_rx_ring_size = new_rx_size;
287762306a36Sopenharmony_ci	ena_init_io_rings(adapter,
287862306a36Sopenharmony_ci			  0,
287962306a36Sopenharmony_ci			  adapter->xdp_num_queues +
288062306a36Sopenharmony_ci			  adapter->num_io_queues);
288162306a36Sopenharmony_ci
288262306a36Sopenharmony_ci	large_llq_changed = adapter->ena_dev->tx_mem_queue_type ==
288362306a36Sopenharmony_ci			    ENA_ADMIN_PLACEMENT_POLICY_DEV;
288462306a36Sopenharmony_ci	large_llq_changed &=
288562306a36Sopenharmony_ci		new_llq_header_len != adapter->ena_dev->tx_max_header_size;
288662306a36Sopenharmony_ci
288762306a36Sopenharmony_ci	/* a check that the configuration is valid is done by caller */
288862306a36Sopenharmony_ci	if (large_llq_changed) {
288962306a36Sopenharmony_ci		adapter->large_llq_header_enabled = !adapter->large_llq_header_enabled;
289062306a36Sopenharmony_ci
289162306a36Sopenharmony_ci		ena_destroy_device(adapter, false);
289262306a36Sopenharmony_ci		rc = ena_restore_device(adapter);
289362306a36Sopenharmony_ci	}
289462306a36Sopenharmony_ci
289562306a36Sopenharmony_ci	return dev_was_up && !rc ? ena_up(adapter) : rc;
289662306a36Sopenharmony_ci}
289762306a36Sopenharmony_ci
289862306a36Sopenharmony_ciint ena_set_rx_copybreak(struct ena_adapter *adapter, u32 rx_copybreak)
289962306a36Sopenharmony_ci{
290062306a36Sopenharmony_ci	struct ena_ring *rx_ring;
290162306a36Sopenharmony_ci	int i;
290262306a36Sopenharmony_ci
290362306a36Sopenharmony_ci	if (rx_copybreak > min_t(u16, adapter->netdev->mtu, ENA_PAGE_SIZE))
290462306a36Sopenharmony_ci		return -EINVAL;
290562306a36Sopenharmony_ci
290662306a36Sopenharmony_ci	adapter->rx_copybreak = rx_copybreak;
290762306a36Sopenharmony_ci
290862306a36Sopenharmony_ci	for (i = 0; i < adapter->num_io_queues; i++) {
290962306a36Sopenharmony_ci		rx_ring = &adapter->rx_ring[i];
291062306a36Sopenharmony_ci		rx_ring->rx_copybreak = rx_copybreak;
291162306a36Sopenharmony_ci	}
291262306a36Sopenharmony_ci
291362306a36Sopenharmony_ci	return 0;
291462306a36Sopenharmony_ci}
291562306a36Sopenharmony_ci
291662306a36Sopenharmony_ciint ena_update_queue_count(struct ena_adapter *adapter, u32 new_channel_count)
291762306a36Sopenharmony_ci{
291862306a36Sopenharmony_ci	struct ena_com_dev *ena_dev = adapter->ena_dev;
291962306a36Sopenharmony_ci	int prev_channel_count;
292062306a36Sopenharmony_ci	bool dev_was_up;
292162306a36Sopenharmony_ci
292262306a36Sopenharmony_ci	dev_was_up = test_bit(ENA_FLAG_DEV_UP, &adapter->flags);
292362306a36Sopenharmony_ci	ena_close(adapter->netdev);
292462306a36Sopenharmony_ci	prev_channel_count = adapter->num_io_queues;
292562306a36Sopenharmony_ci	adapter->num_io_queues = new_channel_count;
292662306a36Sopenharmony_ci	if (ena_xdp_present(adapter) &&
292762306a36Sopenharmony_ci	    ena_xdp_allowed(adapter) == ENA_XDP_ALLOWED) {
292862306a36Sopenharmony_ci		adapter->xdp_first_ring = new_channel_count;
292962306a36Sopenharmony_ci		adapter->xdp_num_queues = new_channel_count;
293062306a36Sopenharmony_ci		if (prev_channel_count > new_channel_count)
293162306a36Sopenharmony_ci			ena_xdp_exchange_program_rx_in_range(adapter,
293262306a36Sopenharmony_ci							     NULL,
293362306a36Sopenharmony_ci							     new_channel_count,
293462306a36Sopenharmony_ci							     prev_channel_count);
293562306a36Sopenharmony_ci		else
293662306a36Sopenharmony_ci			ena_xdp_exchange_program_rx_in_range(adapter,
293762306a36Sopenharmony_ci							     adapter->xdp_bpf_prog,
293862306a36Sopenharmony_ci							     prev_channel_count,
293962306a36Sopenharmony_ci							     new_channel_count);
294062306a36Sopenharmony_ci	}
294162306a36Sopenharmony_ci
294262306a36Sopenharmony_ci	/* We need to destroy the rss table so that the indirection
294362306a36Sopenharmony_ci	 * table will be reinitialized by ena_up()
294462306a36Sopenharmony_ci	 */
294562306a36Sopenharmony_ci	ena_com_rss_destroy(ena_dev);
294662306a36Sopenharmony_ci	ena_init_io_rings(adapter,
294762306a36Sopenharmony_ci			  0,
294862306a36Sopenharmony_ci			  adapter->xdp_num_queues +
294962306a36Sopenharmony_ci			  adapter->num_io_queues);
295062306a36Sopenharmony_ci	return dev_was_up ? ena_open(adapter->netdev) : 0;
295162306a36Sopenharmony_ci}
295262306a36Sopenharmony_ci
295362306a36Sopenharmony_cistatic void ena_tx_csum(struct ena_com_tx_ctx *ena_tx_ctx,
295462306a36Sopenharmony_ci			struct sk_buff *skb,
295562306a36Sopenharmony_ci			bool disable_meta_caching)
295662306a36Sopenharmony_ci{
295762306a36Sopenharmony_ci	u32 mss = skb_shinfo(skb)->gso_size;
295862306a36Sopenharmony_ci	struct ena_com_tx_meta *ena_meta = &ena_tx_ctx->ena_meta;
295962306a36Sopenharmony_ci	u8 l4_protocol = 0;
296062306a36Sopenharmony_ci
296162306a36Sopenharmony_ci	if ((skb->ip_summed == CHECKSUM_PARTIAL) || mss) {
296262306a36Sopenharmony_ci		ena_tx_ctx->l4_csum_enable = 1;
296362306a36Sopenharmony_ci		if (mss) {
296462306a36Sopenharmony_ci			ena_tx_ctx->tso_enable = 1;
296562306a36Sopenharmony_ci			ena_meta->l4_hdr_len = tcp_hdr(skb)->doff;
296662306a36Sopenharmony_ci			ena_tx_ctx->l4_csum_partial = 0;
296762306a36Sopenharmony_ci		} else {
296862306a36Sopenharmony_ci			ena_tx_ctx->tso_enable = 0;
296962306a36Sopenharmony_ci			ena_meta->l4_hdr_len = 0;
297062306a36Sopenharmony_ci			ena_tx_ctx->l4_csum_partial = 1;
297162306a36Sopenharmony_ci		}
297262306a36Sopenharmony_ci
297362306a36Sopenharmony_ci		switch (ip_hdr(skb)->version) {
297462306a36Sopenharmony_ci		case IPVERSION:
297562306a36Sopenharmony_ci			ena_tx_ctx->l3_proto = ENA_ETH_IO_L3_PROTO_IPV4;
297662306a36Sopenharmony_ci			if (ip_hdr(skb)->frag_off & htons(IP_DF))
297762306a36Sopenharmony_ci				ena_tx_ctx->df = 1;
297862306a36Sopenharmony_ci			if (mss)
297962306a36Sopenharmony_ci				ena_tx_ctx->l3_csum_enable = 1;
298062306a36Sopenharmony_ci			l4_protocol = ip_hdr(skb)->protocol;
298162306a36Sopenharmony_ci			break;
298262306a36Sopenharmony_ci		case 6:
298362306a36Sopenharmony_ci			ena_tx_ctx->l3_proto = ENA_ETH_IO_L3_PROTO_IPV6;
298462306a36Sopenharmony_ci			l4_protocol = ipv6_hdr(skb)->nexthdr;
298562306a36Sopenharmony_ci			break;
298662306a36Sopenharmony_ci		default:
298762306a36Sopenharmony_ci			break;
298862306a36Sopenharmony_ci		}
298962306a36Sopenharmony_ci
299062306a36Sopenharmony_ci		if (l4_protocol == IPPROTO_TCP)
299162306a36Sopenharmony_ci			ena_tx_ctx->l4_proto = ENA_ETH_IO_L4_PROTO_TCP;
299262306a36Sopenharmony_ci		else
299362306a36Sopenharmony_ci			ena_tx_ctx->l4_proto = ENA_ETH_IO_L4_PROTO_UDP;
299462306a36Sopenharmony_ci
299562306a36Sopenharmony_ci		ena_meta->mss = mss;
299662306a36Sopenharmony_ci		ena_meta->l3_hdr_len = skb_network_header_len(skb);
299762306a36Sopenharmony_ci		ena_meta->l3_hdr_offset = skb_network_offset(skb);
299862306a36Sopenharmony_ci		ena_tx_ctx->meta_valid = 1;
299962306a36Sopenharmony_ci	} else if (disable_meta_caching) {
300062306a36Sopenharmony_ci		memset(ena_meta, 0, sizeof(*ena_meta));
300162306a36Sopenharmony_ci		ena_tx_ctx->meta_valid = 1;
300262306a36Sopenharmony_ci	} else {
300362306a36Sopenharmony_ci		ena_tx_ctx->meta_valid = 0;
300462306a36Sopenharmony_ci	}
300562306a36Sopenharmony_ci}
300662306a36Sopenharmony_ci
300762306a36Sopenharmony_cistatic int ena_check_and_linearize_skb(struct ena_ring *tx_ring,
300862306a36Sopenharmony_ci				       struct sk_buff *skb)
300962306a36Sopenharmony_ci{
301062306a36Sopenharmony_ci	int num_frags, header_len, rc;
301162306a36Sopenharmony_ci
301262306a36Sopenharmony_ci	num_frags = skb_shinfo(skb)->nr_frags;
301362306a36Sopenharmony_ci	header_len = skb_headlen(skb);
301462306a36Sopenharmony_ci
301562306a36Sopenharmony_ci	if (num_frags < tx_ring->sgl_size)
301662306a36Sopenharmony_ci		return 0;
301762306a36Sopenharmony_ci
301862306a36Sopenharmony_ci	if ((num_frags == tx_ring->sgl_size) &&
301962306a36Sopenharmony_ci	    (header_len < tx_ring->tx_max_header_size))
302062306a36Sopenharmony_ci		return 0;
302162306a36Sopenharmony_ci
302262306a36Sopenharmony_ci	ena_increase_stat(&tx_ring->tx_stats.linearize, 1, &tx_ring->syncp);
302362306a36Sopenharmony_ci
302462306a36Sopenharmony_ci	rc = skb_linearize(skb);
302562306a36Sopenharmony_ci	if (unlikely(rc)) {
302662306a36Sopenharmony_ci		ena_increase_stat(&tx_ring->tx_stats.linearize_failed, 1,
302762306a36Sopenharmony_ci				  &tx_ring->syncp);
302862306a36Sopenharmony_ci	}
302962306a36Sopenharmony_ci
303062306a36Sopenharmony_ci	return rc;
303162306a36Sopenharmony_ci}
303262306a36Sopenharmony_ci
303362306a36Sopenharmony_cistatic int ena_tx_map_skb(struct ena_ring *tx_ring,
303462306a36Sopenharmony_ci			  struct ena_tx_buffer *tx_info,
303562306a36Sopenharmony_ci			  struct sk_buff *skb,
303662306a36Sopenharmony_ci			  void **push_hdr,
303762306a36Sopenharmony_ci			  u16 *header_len)
303862306a36Sopenharmony_ci{
303962306a36Sopenharmony_ci	struct ena_adapter *adapter = tx_ring->adapter;
304062306a36Sopenharmony_ci	struct ena_com_buf *ena_buf;
304162306a36Sopenharmony_ci	dma_addr_t dma;
304262306a36Sopenharmony_ci	u32 skb_head_len, frag_len, last_frag;
304362306a36Sopenharmony_ci	u16 push_len = 0;
304462306a36Sopenharmony_ci	u16 delta = 0;
304562306a36Sopenharmony_ci	int i = 0;
304662306a36Sopenharmony_ci
304762306a36Sopenharmony_ci	skb_head_len = skb_headlen(skb);
304862306a36Sopenharmony_ci	tx_info->skb = skb;
304962306a36Sopenharmony_ci	ena_buf = tx_info->bufs;
305062306a36Sopenharmony_ci
305162306a36Sopenharmony_ci	if (tx_ring->tx_mem_queue_type == ENA_ADMIN_PLACEMENT_POLICY_DEV) {
305262306a36Sopenharmony_ci		/* When the device is LLQ mode, the driver will copy
305362306a36Sopenharmony_ci		 * the header into the device memory space.
305462306a36Sopenharmony_ci		 * the ena_com layer assume the header is in a linear
305562306a36Sopenharmony_ci		 * memory space.
305662306a36Sopenharmony_ci		 * This assumption might be wrong since part of the header
305762306a36Sopenharmony_ci		 * can be in the fragmented buffers.
305862306a36Sopenharmony_ci		 * Use skb_header_pointer to make sure the header is in a
305962306a36Sopenharmony_ci		 * linear memory space.
306062306a36Sopenharmony_ci		 */
306162306a36Sopenharmony_ci
306262306a36Sopenharmony_ci		push_len = min_t(u32, skb->len, tx_ring->tx_max_header_size);
306362306a36Sopenharmony_ci		*push_hdr = skb_header_pointer(skb, 0, push_len,
306462306a36Sopenharmony_ci					       tx_ring->push_buf_intermediate_buf);
306562306a36Sopenharmony_ci		*header_len = push_len;
306662306a36Sopenharmony_ci		if (unlikely(skb->data != *push_hdr)) {
306762306a36Sopenharmony_ci			ena_increase_stat(&tx_ring->tx_stats.llq_buffer_copy, 1,
306862306a36Sopenharmony_ci					  &tx_ring->syncp);
306962306a36Sopenharmony_ci
307062306a36Sopenharmony_ci			delta = push_len - skb_head_len;
307162306a36Sopenharmony_ci		}
307262306a36Sopenharmony_ci	} else {
307362306a36Sopenharmony_ci		*push_hdr = NULL;
307462306a36Sopenharmony_ci		*header_len = min_t(u32, skb_head_len,
307562306a36Sopenharmony_ci				    tx_ring->tx_max_header_size);
307662306a36Sopenharmony_ci	}
307762306a36Sopenharmony_ci
307862306a36Sopenharmony_ci	netif_dbg(adapter, tx_queued, adapter->netdev,
307962306a36Sopenharmony_ci		  "skb: %p header_buf->vaddr: %p push_len: %d\n", skb,
308062306a36Sopenharmony_ci		  *push_hdr, push_len);
308162306a36Sopenharmony_ci
308262306a36Sopenharmony_ci	if (skb_head_len > push_len) {
308362306a36Sopenharmony_ci		dma = dma_map_single(tx_ring->dev, skb->data + push_len,
308462306a36Sopenharmony_ci				     skb_head_len - push_len, DMA_TO_DEVICE);
308562306a36Sopenharmony_ci		if (unlikely(dma_mapping_error(tx_ring->dev, dma)))
308662306a36Sopenharmony_ci			goto error_report_dma_error;
308762306a36Sopenharmony_ci
308862306a36Sopenharmony_ci		ena_buf->paddr = dma;
308962306a36Sopenharmony_ci		ena_buf->len = skb_head_len - push_len;
309062306a36Sopenharmony_ci
309162306a36Sopenharmony_ci		ena_buf++;
309262306a36Sopenharmony_ci		tx_info->num_of_bufs++;
309362306a36Sopenharmony_ci		tx_info->map_linear_data = 1;
309462306a36Sopenharmony_ci	} else {
309562306a36Sopenharmony_ci		tx_info->map_linear_data = 0;
309662306a36Sopenharmony_ci	}
309762306a36Sopenharmony_ci
309862306a36Sopenharmony_ci	last_frag = skb_shinfo(skb)->nr_frags;
309962306a36Sopenharmony_ci
310062306a36Sopenharmony_ci	for (i = 0; i < last_frag; i++) {
310162306a36Sopenharmony_ci		const skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
310262306a36Sopenharmony_ci
310362306a36Sopenharmony_ci		frag_len = skb_frag_size(frag);
310462306a36Sopenharmony_ci
310562306a36Sopenharmony_ci		if (unlikely(delta >= frag_len)) {
310662306a36Sopenharmony_ci			delta -= frag_len;
310762306a36Sopenharmony_ci			continue;
310862306a36Sopenharmony_ci		}
310962306a36Sopenharmony_ci
311062306a36Sopenharmony_ci		dma = skb_frag_dma_map(tx_ring->dev, frag, delta,
311162306a36Sopenharmony_ci				       frag_len - delta, DMA_TO_DEVICE);
311262306a36Sopenharmony_ci		if (unlikely(dma_mapping_error(tx_ring->dev, dma)))
311362306a36Sopenharmony_ci			goto error_report_dma_error;
311462306a36Sopenharmony_ci
311562306a36Sopenharmony_ci		ena_buf->paddr = dma;
311662306a36Sopenharmony_ci		ena_buf->len = frag_len - delta;
311762306a36Sopenharmony_ci		ena_buf++;
311862306a36Sopenharmony_ci		tx_info->num_of_bufs++;
311962306a36Sopenharmony_ci		delta = 0;
312062306a36Sopenharmony_ci	}
312162306a36Sopenharmony_ci
312262306a36Sopenharmony_ci	return 0;
312362306a36Sopenharmony_ci
312462306a36Sopenharmony_cierror_report_dma_error:
312562306a36Sopenharmony_ci	ena_increase_stat(&tx_ring->tx_stats.dma_mapping_err, 1,
312662306a36Sopenharmony_ci			  &tx_ring->syncp);
312762306a36Sopenharmony_ci	netif_warn(adapter, tx_queued, adapter->netdev, "Failed to map skb\n");
312862306a36Sopenharmony_ci
312962306a36Sopenharmony_ci	tx_info->skb = NULL;
313062306a36Sopenharmony_ci
313162306a36Sopenharmony_ci	tx_info->num_of_bufs += i;
313262306a36Sopenharmony_ci	ena_unmap_tx_buff(tx_ring, tx_info);
313362306a36Sopenharmony_ci
313462306a36Sopenharmony_ci	return -EINVAL;
313562306a36Sopenharmony_ci}
313662306a36Sopenharmony_ci
313762306a36Sopenharmony_ci/* Called with netif_tx_lock. */
313862306a36Sopenharmony_cistatic netdev_tx_t ena_start_xmit(struct sk_buff *skb, struct net_device *dev)
313962306a36Sopenharmony_ci{
314062306a36Sopenharmony_ci	struct ena_adapter *adapter = netdev_priv(dev);
314162306a36Sopenharmony_ci	struct ena_tx_buffer *tx_info;
314262306a36Sopenharmony_ci	struct ena_com_tx_ctx ena_tx_ctx;
314362306a36Sopenharmony_ci	struct ena_ring *tx_ring;
314462306a36Sopenharmony_ci	struct netdev_queue *txq;
314562306a36Sopenharmony_ci	void *push_hdr;
314662306a36Sopenharmony_ci	u16 next_to_use, req_id, header_len;
314762306a36Sopenharmony_ci	int qid, rc;
314862306a36Sopenharmony_ci
314962306a36Sopenharmony_ci	netif_dbg(adapter, tx_queued, dev, "%s skb %p\n", __func__, skb);
315062306a36Sopenharmony_ci	/*  Determine which tx ring we will be placed on */
315162306a36Sopenharmony_ci	qid = skb_get_queue_mapping(skb);
315262306a36Sopenharmony_ci	tx_ring = &adapter->tx_ring[qid];
315362306a36Sopenharmony_ci	txq = netdev_get_tx_queue(dev, qid);
315462306a36Sopenharmony_ci
315562306a36Sopenharmony_ci	rc = ena_check_and_linearize_skb(tx_ring, skb);
315662306a36Sopenharmony_ci	if (unlikely(rc))
315762306a36Sopenharmony_ci		goto error_drop_packet;
315862306a36Sopenharmony_ci
315962306a36Sopenharmony_ci	skb_tx_timestamp(skb);
316062306a36Sopenharmony_ci
316162306a36Sopenharmony_ci	next_to_use = tx_ring->next_to_use;
316262306a36Sopenharmony_ci	req_id = tx_ring->free_ids[next_to_use];
316362306a36Sopenharmony_ci	tx_info = &tx_ring->tx_buffer_info[req_id];
316462306a36Sopenharmony_ci	tx_info->num_of_bufs = 0;
316562306a36Sopenharmony_ci
316662306a36Sopenharmony_ci	WARN(tx_info->skb, "SKB isn't NULL req_id %d\n", req_id);
316762306a36Sopenharmony_ci
316862306a36Sopenharmony_ci	rc = ena_tx_map_skb(tx_ring, tx_info, skb, &push_hdr, &header_len);
316962306a36Sopenharmony_ci	if (unlikely(rc))
317062306a36Sopenharmony_ci		goto error_drop_packet;
317162306a36Sopenharmony_ci
317262306a36Sopenharmony_ci	memset(&ena_tx_ctx, 0x0, sizeof(struct ena_com_tx_ctx));
317362306a36Sopenharmony_ci	ena_tx_ctx.ena_bufs = tx_info->bufs;
317462306a36Sopenharmony_ci	ena_tx_ctx.push_header = push_hdr;
317562306a36Sopenharmony_ci	ena_tx_ctx.num_bufs = tx_info->num_of_bufs;
317662306a36Sopenharmony_ci	ena_tx_ctx.req_id = req_id;
317762306a36Sopenharmony_ci	ena_tx_ctx.header_len = header_len;
317862306a36Sopenharmony_ci
317962306a36Sopenharmony_ci	/* set flags and meta data */
318062306a36Sopenharmony_ci	ena_tx_csum(&ena_tx_ctx, skb, tx_ring->disable_meta_caching);
318162306a36Sopenharmony_ci
318262306a36Sopenharmony_ci	rc = ena_xmit_common(dev,
318362306a36Sopenharmony_ci			     tx_ring,
318462306a36Sopenharmony_ci			     tx_info,
318562306a36Sopenharmony_ci			     &ena_tx_ctx,
318662306a36Sopenharmony_ci			     next_to_use,
318762306a36Sopenharmony_ci			     skb->len);
318862306a36Sopenharmony_ci	if (rc)
318962306a36Sopenharmony_ci		goto error_unmap_dma;
319062306a36Sopenharmony_ci
319162306a36Sopenharmony_ci	netdev_tx_sent_queue(txq, skb->len);
319262306a36Sopenharmony_ci
319362306a36Sopenharmony_ci	/* stop the queue when no more space available, the packet can have up
319462306a36Sopenharmony_ci	 * to sgl_size + 2. one for the meta descriptor and one for header
319562306a36Sopenharmony_ci	 * (if the header is larger than tx_max_header_size).
319662306a36Sopenharmony_ci	 */
319762306a36Sopenharmony_ci	if (unlikely(!ena_com_sq_have_enough_space(tx_ring->ena_com_io_sq,
319862306a36Sopenharmony_ci						   tx_ring->sgl_size + 2))) {
319962306a36Sopenharmony_ci		netif_dbg(adapter, tx_queued, dev, "%s stop queue %d\n",
320062306a36Sopenharmony_ci			  __func__, qid);
320162306a36Sopenharmony_ci
320262306a36Sopenharmony_ci		netif_tx_stop_queue(txq);
320362306a36Sopenharmony_ci		ena_increase_stat(&tx_ring->tx_stats.queue_stop, 1,
320462306a36Sopenharmony_ci				  &tx_ring->syncp);
320562306a36Sopenharmony_ci
320662306a36Sopenharmony_ci		/* There is a rare condition where this function decide to
320762306a36Sopenharmony_ci		 * stop the queue but meanwhile clean_tx_irq updates
320862306a36Sopenharmony_ci		 * next_to_completion and terminates.
320962306a36Sopenharmony_ci		 * The queue will remain stopped forever.
321062306a36Sopenharmony_ci		 * To solve this issue add a mb() to make sure that
321162306a36Sopenharmony_ci		 * netif_tx_stop_queue() write is vissible before checking if
321262306a36Sopenharmony_ci		 * there is additional space in the queue.
321362306a36Sopenharmony_ci		 */
321462306a36Sopenharmony_ci		smp_mb();
321562306a36Sopenharmony_ci
321662306a36Sopenharmony_ci		if (ena_com_sq_have_enough_space(tx_ring->ena_com_io_sq,
321762306a36Sopenharmony_ci						 ENA_TX_WAKEUP_THRESH)) {
321862306a36Sopenharmony_ci			netif_tx_wake_queue(txq);
321962306a36Sopenharmony_ci			ena_increase_stat(&tx_ring->tx_stats.queue_wakeup, 1,
322062306a36Sopenharmony_ci					  &tx_ring->syncp);
322162306a36Sopenharmony_ci		}
322262306a36Sopenharmony_ci	}
322362306a36Sopenharmony_ci
322462306a36Sopenharmony_ci	if (netif_xmit_stopped(txq) || !netdev_xmit_more())
322562306a36Sopenharmony_ci		/* trigger the dma engine. ena_ring_tx_doorbell()
322662306a36Sopenharmony_ci		 * calls a memory barrier inside it.
322762306a36Sopenharmony_ci		 */
322862306a36Sopenharmony_ci		ena_ring_tx_doorbell(tx_ring);
322962306a36Sopenharmony_ci
323062306a36Sopenharmony_ci	return NETDEV_TX_OK;
323162306a36Sopenharmony_ci
323262306a36Sopenharmony_cierror_unmap_dma:
323362306a36Sopenharmony_ci	ena_unmap_tx_buff(tx_ring, tx_info);
323462306a36Sopenharmony_ci	tx_info->skb = NULL;
323562306a36Sopenharmony_ci
323662306a36Sopenharmony_cierror_drop_packet:
323762306a36Sopenharmony_ci	dev_kfree_skb(skb);
323862306a36Sopenharmony_ci	return NETDEV_TX_OK;
323962306a36Sopenharmony_ci}
324062306a36Sopenharmony_ci
324162306a36Sopenharmony_cistatic void ena_config_host_info(struct ena_com_dev *ena_dev, struct pci_dev *pdev)
324262306a36Sopenharmony_ci{
324362306a36Sopenharmony_ci	struct device *dev = &pdev->dev;
324462306a36Sopenharmony_ci	struct ena_admin_host_info *host_info;
324562306a36Sopenharmony_ci	int rc;
324662306a36Sopenharmony_ci
324762306a36Sopenharmony_ci	/* Allocate only the host info */
324862306a36Sopenharmony_ci	rc = ena_com_allocate_host_info(ena_dev);
324962306a36Sopenharmony_ci	if (rc) {
325062306a36Sopenharmony_ci		dev_err(dev, "Cannot allocate host info\n");
325162306a36Sopenharmony_ci		return;
325262306a36Sopenharmony_ci	}
325362306a36Sopenharmony_ci
325462306a36Sopenharmony_ci	host_info = ena_dev->host_attr.host_info;
325562306a36Sopenharmony_ci
325662306a36Sopenharmony_ci	host_info->bdf = pci_dev_id(pdev);
325762306a36Sopenharmony_ci	host_info->os_type = ENA_ADMIN_OS_LINUX;
325862306a36Sopenharmony_ci	host_info->kernel_ver = LINUX_VERSION_CODE;
325962306a36Sopenharmony_ci	strscpy(host_info->kernel_ver_str, utsname()->version,
326062306a36Sopenharmony_ci		sizeof(host_info->kernel_ver_str) - 1);
326162306a36Sopenharmony_ci	host_info->os_dist = 0;
326262306a36Sopenharmony_ci	strncpy(host_info->os_dist_str, utsname()->release,
326362306a36Sopenharmony_ci		sizeof(host_info->os_dist_str) - 1);
326462306a36Sopenharmony_ci	host_info->driver_version =
326562306a36Sopenharmony_ci		(DRV_MODULE_GEN_MAJOR) |
326662306a36Sopenharmony_ci		(DRV_MODULE_GEN_MINOR << ENA_ADMIN_HOST_INFO_MINOR_SHIFT) |
326762306a36Sopenharmony_ci		(DRV_MODULE_GEN_SUBMINOR << ENA_ADMIN_HOST_INFO_SUB_MINOR_SHIFT) |
326862306a36Sopenharmony_ci		("K"[0] << ENA_ADMIN_HOST_INFO_MODULE_TYPE_SHIFT);
326962306a36Sopenharmony_ci	host_info->num_cpus = num_online_cpus();
327062306a36Sopenharmony_ci
327162306a36Sopenharmony_ci	host_info->driver_supported_features =
327262306a36Sopenharmony_ci		ENA_ADMIN_HOST_INFO_RX_OFFSET_MASK |
327362306a36Sopenharmony_ci		ENA_ADMIN_HOST_INFO_INTERRUPT_MODERATION_MASK |
327462306a36Sopenharmony_ci		ENA_ADMIN_HOST_INFO_RX_BUF_MIRRORING_MASK |
327562306a36Sopenharmony_ci		ENA_ADMIN_HOST_INFO_RSS_CONFIGURABLE_FUNCTION_KEY_MASK |
327662306a36Sopenharmony_ci		ENA_ADMIN_HOST_INFO_RX_PAGE_REUSE_MASK;
327762306a36Sopenharmony_ci
327862306a36Sopenharmony_ci	rc = ena_com_set_host_attributes(ena_dev);
327962306a36Sopenharmony_ci	if (rc) {
328062306a36Sopenharmony_ci		if (rc == -EOPNOTSUPP)
328162306a36Sopenharmony_ci			dev_warn(dev, "Cannot set host attributes\n");
328262306a36Sopenharmony_ci		else
328362306a36Sopenharmony_ci			dev_err(dev, "Cannot set host attributes\n");
328462306a36Sopenharmony_ci
328562306a36Sopenharmony_ci		goto err;
328662306a36Sopenharmony_ci	}
328762306a36Sopenharmony_ci
328862306a36Sopenharmony_ci	return;
328962306a36Sopenharmony_ci
329062306a36Sopenharmony_cierr:
329162306a36Sopenharmony_ci	ena_com_delete_host_info(ena_dev);
329262306a36Sopenharmony_ci}
329362306a36Sopenharmony_ci
329462306a36Sopenharmony_cistatic void ena_config_debug_area(struct ena_adapter *adapter)
329562306a36Sopenharmony_ci{
329662306a36Sopenharmony_ci	u32 debug_area_size;
329762306a36Sopenharmony_ci	int rc, ss_count;
329862306a36Sopenharmony_ci
329962306a36Sopenharmony_ci	ss_count = ena_get_sset_count(adapter->netdev, ETH_SS_STATS);
330062306a36Sopenharmony_ci	if (ss_count <= 0) {
330162306a36Sopenharmony_ci		netif_err(adapter, drv, adapter->netdev,
330262306a36Sopenharmony_ci			  "SS count is negative\n");
330362306a36Sopenharmony_ci		return;
330462306a36Sopenharmony_ci	}
330562306a36Sopenharmony_ci
330662306a36Sopenharmony_ci	/* allocate 32 bytes for each string and 64bit for the value */
330762306a36Sopenharmony_ci	debug_area_size = ss_count * ETH_GSTRING_LEN + sizeof(u64) * ss_count;
330862306a36Sopenharmony_ci
330962306a36Sopenharmony_ci	rc = ena_com_allocate_debug_area(adapter->ena_dev, debug_area_size);
331062306a36Sopenharmony_ci	if (rc) {
331162306a36Sopenharmony_ci		netif_err(adapter, drv, adapter->netdev,
331262306a36Sopenharmony_ci			  "Cannot allocate debug area\n");
331362306a36Sopenharmony_ci		return;
331462306a36Sopenharmony_ci	}
331562306a36Sopenharmony_ci
331662306a36Sopenharmony_ci	rc = ena_com_set_host_attributes(adapter->ena_dev);
331762306a36Sopenharmony_ci	if (rc) {
331862306a36Sopenharmony_ci		if (rc == -EOPNOTSUPP)
331962306a36Sopenharmony_ci			netif_warn(adapter, drv, adapter->netdev,
332062306a36Sopenharmony_ci				   "Cannot set host attributes\n");
332162306a36Sopenharmony_ci		else
332262306a36Sopenharmony_ci			netif_err(adapter, drv, adapter->netdev,
332362306a36Sopenharmony_ci				  "Cannot set host attributes\n");
332462306a36Sopenharmony_ci		goto err;
332562306a36Sopenharmony_ci	}
332662306a36Sopenharmony_ci
332762306a36Sopenharmony_ci	return;
332862306a36Sopenharmony_cierr:
332962306a36Sopenharmony_ci	ena_com_delete_debug_area(adapter->ena_dev);
333062306a36Sopenharmony_ci}
333162306a36Sopenharmony_ci
333262306a36Sopenharmony_ciint ena_update_hw_stats(struct ena_adapter *adapter)
333362306a36Sopenharmony_ci{
333462306a36Sopenharmony_ci	int rc;
333562306a36Sopenharmony_ci
333662306a36Sopenharmony_ci	rc = ena_com_get_eni_stats(adapter->ena_dev, &adapter->eni_stats);
333762306a36Sopenharmony_ci	if (rc) {
333862306a36Sopenharmony_ci		netdev_err(adapter->netdev, "Failed to get ENI stats\n");
333962306a36Sopenharmony_ci		return rc;
334062306a36Sopenharmony_ci	}
334162306a36Sopenharmony_ci
334262306a36Sopenharmony_ci	return 0;
334362306a36Sopenharmony_ci}
334462306a36Sopenharmony_ci
334562306a36Sopenharmony_cistatic void ena_get_stats64(struct net_device *netdev,
334662306a36Sopenharmony_ci			    struct rtnl_link_stats64 *stats)
334762306a36Sopenharmony_ci{
334862306a36Sopenharmony_ci	struct ena_adapter *adapter = netdev_priv(netdev);
334962306a36Sopenharmony_ci	struct ena_ring *rx_ring, *tx_ring;
335062306a36Sopenharmony_ci	unsigned int start;
335162306a36Sopenharmony_ci	u64 rx_drops;
335262306a36Sopenharmony_ci	u64 tx_drops;
335362306a36Sopenharmony_ci	int i;
335462306a36Sopenharmony_ci
335562306a36Sopenharmony_ci	if (!test_bit(ENA_FLAG_DEV_UP, &adapter->flags))
335662306a36Sopenharmony_ci		return;
335762306a36Sopenharmony_ci
335862306a36Sopenharmony_ci	for (i = 0; i < adapter->num_io_queues; i++) {
335962306a36Sopenharmony_ci		u64 bytes, packets;
336062306a36Sopenharmony_ci
336162306a36Sopenharmony_ci		tx_ring = &adapter->tx_ring[i];
336262306a36Sopenharmony_ci
336362306a36Sopenharmony_ci		do {
336462306a36Sopenharmony_ci			start = u64_stats_fetch_begin(&tx_ring->syncp);
336562306a36Sopenharmony_ci			packets = tx_ring->tx_stats.cnt;
336662306a36Sopenharmony_ci			bytes = tx_ring->tx_stats.bytes;
336762306a36Sopenharmony_ci		} while (u64_stats_fetch_retry(&tx_ring->syncp, start));
336862306a36Sopenharmony_ci
336962306a36Sopenharmony_ci		stats->tx_packets += packets;
337062306a36Sopenharmony_ci		stats->tx_bytes += bytes;
337162306a36Sopenharmony_ci
337262306a36Sopenharmony_ci		rx_ring = &adapter->rx_ring[i];
337362306a36Sopenharmony_ci
337462306a36Sopenharmony_ci		do {
337562306a36Sopenharmony_ci			start = u64_stats_fetch_begin(&rx_ring->syncp);
337662306a36Sopenharmony_ci			packets = rx_ring->rx_stats.cnt;
337762306a36Sopenharmony_ci			bytes = rx_ring->rx_stats.bytes;
337862306a36Sopenharmony_ci		} while (u64_stats_fetch_retry(&rx_ring->syncp, start));
337962306a36Sopenharmony_ci
338062306a36Sopenharmony_ci		stats->rx_packets += packets;
338162306a36Sopenharmony_ci		stats->rx_bytes += bytes;
338262306a36Sopenharmony_ci	}
338362306a36Sopenharmony_ci
338462306a36Sopenharmony_ci	do {
338562306a36Sopenharmony_ci		start = u64_stats_fetch_begin(&adapter->syncp);
338662306a36Sopenharmony_ci		rx_drops = adapter->dev_stats.rx_drops;
338762306a36Sopenharmony_ci		tx_drops = adapter->dev_stats.tx_drops;
338862306a36Sopenharmony_ci	} while (u64_stats_fetch_retry(&adapter->syncp, start));
338962306a36Sopenharmony_ci
339062306a36Sopenharmony_ci	stats->rx_dropped = rx_drops;
339162306a36Sopenharmony_ci	stats->tx_dropped = tx_drops;
339262306a36Sopenharmony_ci
339362306a36Sopenharmony_ci	stats->multicast = 0;
339462306a36Sopenharmony_ci	stats->collisions = 0;
339562306a36Sopenharmony_ci
339662306a36Sopenharmony_ci	stats->rx_length_errors = 0;
339762306a36Sopenharmony_ci	stats->rx_crc_errors = 0;
339862306a36Sopenharmony_ci	stats->rx_frame_errors = 0;
339962306a36Sopenharmony_ci	stats->rx_fifo_errors = 0;
340062306a36Sopenharmony_ci	stats->rx_missed_errors = 0;
340162306a36Sopenharmony_ci	stats->tx_window_errors = 0;
340262306a36Sopenharmony_ci
340362306a36Sopenharmony_ci	stats->rx_errors = 0;
340462306a36Sopenharmony_ci	stats->tx_errors = 0;
340562306a36Sopenharmony_ci}
340662306a36Sopenharmony_ci
340762306a36Sopenharmony_cistatic const struct net_device_ops ena_netdev_ops = {
340862306a36Sopenharmony_ci	.ndo_open		= ena_open,
340962306a36Sopenharmony_ci	.ndo_stop		= ena_close,
341062306a36Sopenharmony_ci	.ndo_start_xmit		= ena_start_xmit,
341162306a36Sopenharmony_ci	.ndo_get_stats64	= ena_get_stats64,
341262306a36Sopenharmony_ci	.ndo_tx_timeout		= ena_tx_timeout,
341362306a36Sopenharmony_ci	.ndo_change_mtu		= ena_change_mtu,
341462306a36Sopenharmony_ci	.ndo_set_mac_address	= NULL,
341562306a36Sopenharmony_ci	.ndo_validate_addr	= eth_validate_addr,
341662306a36Sopenharmony_ci	.ndo_bpf		= ena_xdp,
341762306a36Sopenharmony_ci	.ndo_xdp_xmit		= ena_xdp_xmit,
341862306a36Sopenharmony_ci};
341962306a36Sopenharmony_ci
342062306a36Sopenharmony_cistatic void ena_calc_io_queue_size(struct ena_adapter *adapter,
342162306a36Sopenharmony_ci				   struct ena_com_dev_get_features_ctx *get_feat_ctx)
342262306a36Sopenharmony_ci{
342362306a36Sopenharmony_ci	struct ena_admin_feature_llq_desc *llq = &get_feat_ctx->llq;
342462306a36Sopenharmony_ci	struct ena_com_dev *ena_dev = adapter->ena_dev;
342562306a36Sopenharmony_ci	u32 tx_queue_size = ENA_DEFAULT_RING_SIZE;
342662306a36Sopenharmony_ci	u32 rx_queue_size = ENA_DEFAULT_RING_SIZE;
342762306a36Sopenharmony_ci	u32 max_tx_queue_size;
342862306a36Sopenharmony_ci	u32 max_rx_queue_size;
342962306a36Sopenharmony_ci
343062306a36Sopenharmony_ci	/* If this function is called after driver load, the ring sizes have already
343162306a36Sopenharmony_ci	 * been configured. Take it into account when recalculating ring size.
343262306a36Sopenharmony_ci	 */
343362306a36Sopenharmony_ci	if (adapter->tx_ring->ring_size)
343462306a36Sopenharmony_ci		tx_queue_size = adapter->tx_ring->ring_size;
343562306a36Sopenharmony_ci
343662306a36Sopenharmony_ci	if (adapter->rx_ring->ring_size)
343762306a36Sopenharmony_ci		rx_queue_size = adapter->rx_ring->ring_size;
343862306a36Sopenharmony_ci
343962306a36Sopenharmony_ci	if (ena_dev->supported_features & BIT(ENA_ADMIN_MAX_QUEUES_EXT)) {
344062306a36Sopenharmony_ci		struct ena_admin_queue_ext_feature_fields *max_queue_ext =
344162306a36Sopenharmony_ci			&get_feat_ctx->max_queue_ext.max_queue_ext;
344262306a36Sopenharmony_ci		max_rx_queue_size = min_t(u32, max_queue_ext->max_rx_cq_depth,
344362306a36Sopenharmony_ci					  max_queue_ext->max_rx_sq_depth);
344462306a36Sopenharmony_ci		max_tx_queue_size = max_queue_ext->max_tx_cq_depth;
344562306a36Sopenharmony_ci
344662306a36Sopenharmony_ci		if (ena_dev->tx_mem_queue_type == ENA_ADMIN_PLACEMENT_POLICY_DEV)
344762306a36Sopenharmony_ci			max_tx_queue_size = min_t(u32, max_tx_queue_size,
344862306a36Sopenharmony_ci						  llq->max_llq_depth);
344962306a36Sopenharmony_ci		else
345062306a36Sopenharmony_ci			max_tx_queue_size = min_t(u32, max_tx_queue_size,
345162306a36Sopenharmony_ci						  max_queue_ext->max_tx_sq_depth);
345262306a36Sopenharmony_ci
345362306a36Sopenharmony_ci		adapter->max_tx_sgl_size = min_t(u16, ENA_PKT_MAX_BUFS,
345462306a36Sopenharmony_ci						 max_queue_ext->max_per_packet_tx_descs);
345562306a36Sopenharmony_ci		adapter->max_rx_sgl_size = min_t(u16, ENA_PKT_MAX_BUFS,
345662306a36Sopenharmony_ci						 max_queue_ext->max_per_packet_rx_descs);
345762306a36Sopenharmony_ci	} else {
345862306a36Sopenharmony_ci		struct ena_admin_queue_feature_desc *max_queues =
345962306a36Sopenharmony_ci			&get_feat_ctx->max_queues;
346062306a36Sopenharmony_ci		max_rx_queue_size = min_t(u32, max_queues->max_cq_depth,
346162306a36Sopenharmony_ci					  max_queues->max_sq_depth);
346262306a36Sopenharmony_ci		max_tx_queue_size = max_queues->max_cq_depth;
346362306a36Sopenharmony_ci
346462306a36Sopenharmony_ci		if (ena_dev->tx_mem_queue_type == ENA_ADMIN_PLACEMENT_POLICY_DEV)
346562306a36Sopenharmony_ci			max_tx_queue_size = min_t(u32, max_tx_queue_size,
346662306a36Sopenharmony_ci						  llq->max_llq_depth);
346762306a36Sopenharmony_ci		else
346862306a36Sopenharmony_ci			max_tx_queue_size = min_t(u32, max_tx_queue_size,
346962306a36Sopenharmony_ci						  max_queues->max_sq_depth);
347062306a36Sopenharmony_ci
347162306a36Sopenharmony_ci		adapter->max_tx_sgl_size = min_t(u16, ENA_PKT_MAX_BUFS,
347262306a36Sopenharmony_ci						 max_queues->max_packet_tx_descs);
347362306a36Sopenharmony_ci		adapter->max_rx_sgl_size = min_t(u16, ENA_PKT_MAX_BUFS,
347462306a36Sopenharmony_ci						 max_queues->max_packet_rx_descs);
347562306a36Sopenharmony_ci	}
347662306a36Sopenharmony_ci
347762306a36Sopenharmony_ci	max_tx_queue_size = rounddown_pow_of_two(max_tx_queue_size);
347862306a36Sopenharmony_ci	max_rx_queue_size = rounddown_pow_of_two(max_rx_queue_size);
347962306a36Sopenharmony_ci
348062306a36Sopenharmony_ci	/* When forcing large headers, we multiply the entry size by 2, and therefore divide
348162306a36Sopenharmony_ci	 * the queue size by 2, leaving the amount of memory used by the queues unchanged.
348262306a36Sopenharmony_ci	 */
348362306a36Sopenharmony_ci	if (adapter->large_llq_header_enabled) {
348462306a36Sopenharmony_ci		if ((llq->entry_size_ctrl_supported & ENA_ADMIN_LIST_ENTRY_SIZE_256B) &&
348562306a36Sopenharmony_ci		    ena_dev->tx_mem_queue_type == ENA_ADMIN_PLACEMENT_POLICY_DEV) {
348662306a36Sopenharmony_ci			max_tx_queue_size /= 2;
348762306a36Sopenharmony_ci			dev_info(&adapter->pdev->dev,
348862306a36Sopenharmony_ci				 "Forcing large headers and decreasing maximum TX queue size to %d\n",
348962306a36Sopenharmony_ci				 max_tx_queue_size);
349062306a36Sopenharmony_ci		} else {
349162306a36Sopenharmony_ci			dev_err(&adapter->pdev->dev,
349262306a36Sopenharmony_ci				"Forcing large headers failed: LLQ is disabled or device does not support large headers\n");
349362306a36Sopenharmony_ci
349462306a36Sopenharmony_ci			adapter->large_llq_header_enabled = false;
349562306a36Sopenharmony_ci		}
349662306a36Sopenharmony_ci	}
349762306a36Sopenharmony_ci
349862306a36Sopenharmony_ci	tx_queue_size = clamp_val(tx_queue_size, ENA_MIN_RING_SIZE,
349962306a36Sopenharmony_ci				  max_tx_queue_size);
350062306a36Sopenharmony_ci	rx_queue_size = clamp_val(rx_queue_size, ENA_MIN_RING_SIZE,
350162306a36Sopenharmony_ci				  max_rx_queue_size);
350262306a36Sopenharmony_ci
350362306a36Sopenharmony_ci	tx_queue_size = rounddown_pow_of_two(tx_queue_size);
350462306a36Sopenharmony_ci	rx_queue_size = rounddown_pow_of_two(rx_queue_size);
350562306a36Sopenharmony_ci
350662306a36Sopenharmony_ci	adapter->max_tx_ring_size  = max_tx_queue_size;
350762306a36Sopenharmony_ci	adapter->max_rx_ring_size = max_rx_queue_size;
350862306a36Sopenharmony_ci	adapter->requested_tx_ring_size = tx_queue_size;
350962306a36Sopenharmony_ci	adapter->requested_rx_ring_size = rx_queue_size;
351062306a36Sopenharmony_ci}
351162306a36Sopenharmony_ci
351262306a36Sopenharmony_cistatic int ena_device_validate_params(struct ena_adapter *adapter,
351362306a36Sopenharmony_ci				      struct ena_com_dev_get_features_ctx *get_feat_ctx)
351462306a36Sopenharmony_ci{
351562306a36Sopenharmony_ci	struct net_device *netdev = adapter->netdev;
351662306a36Sopenharmony_ci	int rc;
351762306a36Sopenharmony_ci
351862306a36Sopenharmony_ci	rc = ether_addr_equal(get_feat_ctx->dev_attr.mac_addr,
351962306a36Sopenharmony_ci			      adapter->mac_addr);
352062306a36Sopenharmony_ci	if (!rc) {
352162306a36Sopenharmony_ci		netif_err(adapter, drv, netdev,
352262306a36Sopenharmony_ci			  "Error, mac address are different\n");
352362306a36Sopenharmony_ci		return -EINVAL;
352462306a36Sopenharmony_ci	}
352562306a36Sopenharmony_ci
352662306a36Sopenharmony_ci	if (get_feat_ctx->dev_attr.max_mtu < netdev->mtu) {
352762306a36Sopenharmony_ci		netif_err(adapter, drv, netdev,
352862306a36Sopenharmony_ci			  "Error, device max mtu is smaller than netdev MTU\n");
352962306a36Sopenharmony_ci		return -EINVAL;
353062306a36Sopenharmony_ci	}
353162306a36Sopenharmony_ci
353262306a36Sopenharmony_ci	return 0;
353362306a36Sopenharmony_ci}
353462306a36Sopenharmony_ci
353562306a36Sopenharmony_cistatic void set_default_llq_configurations(struct ena_adapter *adapter,
353662306a36Sopenharmony_ci					   struct ena_llq_configurations *llq_config,
353762306a36Sopenharmony_ci					   struct ena_admin_feature_llq_desc *llq)
353862306a36Sopenharmony_ci{
353962306a36Sopenharmony_ci	struct ena_com_dev *ena_dev = adapter->ena_dev;
354062306a36Sopenharmony_ci
354162306a36Sopenharmony_ci	llq_config->llq_header_location = ENA_ADMIN_INLINE_HEADER;
354262306a36Sopenharmony_ci	llq_config->llq_stride_ctrl = ENA_ADMIN_MULTIPLE_DESCS_PER_ENTRY;
354362306a36Sopenharmony_ci	llq_config->llq_num_decs_before_header = ENA_ADMIN_LLQ_NUM_DESCS_BEFORE_HEADER_2;
354462306a36Sopenharmony_ci
354562306a36Sopenharmony_ci	adapter->large_llq_header_supported =
354662306a36Sopenharmony_ci		!!(ena_dev->supported_features & BIT(ENA_ADMIN_LLQ));
354762306a36Sopenharmony_ci	adapter->large_llq_header_supported &=
354862306a36Sopenharmony_ci		!!(llq->entry_size_ctrl_supported &
354962306a36Sopenharmony_ci			ENA_ADMIN_LIST_ENTRY_SIZE_256B);
355062306a36Sopenharmony_ci
355162306a36Sopenharmony_ci	if ((llq->entry_size_ctrl_supported & ENA_ADMIN_LIST_ENTRY_SIZE_256B) &&
355262306a36Sopenharmony_ci	    adapter->large_llq_header_enabled) {
355362306a36Sopenharmony_ci		llq_config->llq_ring_entry_size = ENA_ADMIN_LIST_ENTRY_SIZE_256B;
355462306a36Sopenharmony_ci		llq_config->llq_ring_entry_size_value = 256;
355562306a36Sopenharmony_ci	} else {
355662306a36Sopenharmony_ci		llq_config->llq_ring_entry_size = ENA_ADMIN_LIST_ENTRY_SIZE_128B;
355762306a36Sopenharmony_ci		llq_config->llq_ring_entry_size_value = 128;
355862306a36Sopenharmony_ci	}
355962306a36Sopenharmony_ci}
356062306a36Sopenharmony_ci
356162306a36Sopenharmony_cistatic int ena_set_queues_placement_policy(struct pci_dev *pdev,
356262306a36Sopenharmony_ci					   struct ena_com_dev *ena_dev,
356362306a36Sopenharmony_ci					   struct ena_admin_feature_llq_desc *llq,
356462306a36Sopenharmony_ci					   struct ena_llq_configurations *llq_default_configurations)
356562306a36Sopenharmony_ci{
356662306a36Sopenharmony_ci	int rc;
356762306a36Sopenharmony_ci	u32 llq_feature_mask;
356862306a36Sopenharmony_ci
356962306a36Sopenharmony_ci	llq_feature_mask = 1 << ENA_ADMIN_LLQ;
357062306a36Sopenharmony_ci	if (!(ena_dev->supported_features & llq_feature_mask)) {
357162306a36Sopenharmony_ci		dev_warn(&pdev->dev,
357262306a36Sopenharmony_ci			"LLQ is not supported Fallback to host mode policy.\n");
357362306a36Sopenharmony_ci		ena_dev->tx_mem_queue_type = ENA_ADMIN_PLACEMENT_POLICY_HOST;
357462306a36Sopenharmony_ci		return 0;
357562306a36Sopenharmony_ci	}
357662306a36Sopenharmony_ci
357762306a36Sopenharmony_ci	if (!ena_dev->mem_bar) {
357862306a36Sopenharmony_ci		netdev_err(ena_dev->net_device,
357962306a36Sopenharmony_ci			   "LLQ is advertised as supported but device doesn't expose mem bar\n");
358062306a36Sopenharmony_ci		ena_dev->tx_mem_queue_type = ENA_ADMIN_PLACEMENT_POLICY_HOST;
358162306a36Sopenharmony_ci		return 0;
358262306a36Sopenharmony_ci	}
358362306a36Sopenharmony_ci
358462306a36Sopenharmony_ci	rc = ena_com_config_dev_mode(ena_dev, llq, llq_default_configurations);
358562306a36Sopenharmony_ci	if (unlikely(rc)) {
358662306a36Sopenharmony_ci		dev_err(&pdev->dev,
358762306a36Sopenharmony_ci			"Failed to configure the device mode.  Fallback to host mode policy.\n");
358862306a36Sopenharmony_ci		ena_dev->tx_mem_queue_type = ENA_ADMIN_PLACEMENT_POLICY_HOST;
358962306a36Sopenharmony_ci	}
359062306a36Sopenharmony_ci
359162306a36Sopenharmony_ci	return 0;
359262306a36Sopenharmony_ci}
359362306a36Sopenharmony_ci
359462306a36Sopenharmony_cistatic int ena_map_llq_mem_bar(struct pci_dev *pdev, struct ena_com_dev *ena_dev,
359562306a36Sopenharmony_ci			       int bars)
359662306a36Sopenharmony_ci{
359762306a36Sopenharmony_ci	bool has_mem_bar = !!(bars & BIT(ENA_MEM_BAR));
359862306a36Sopenharmony_ci
359962306a36Sopenharmony_ci	if (!has_mem_bar)
360062306a36Sopenharmony_ci		return 0;
360162306a36Sopenharmony_ci
360262306a36Sopenharmony_ci	ena_dev->mem_bar = devm_ioremap_wc(&pdev->dev,
360362306a36Sopenharmony_ci					   pci_resource_start(pdev, ENA_MEM_BAR),
360462306a36Sopenharmony_ci					   pci_resource_len(pdev, ENA_MEM_BAR));
360562306a36Sopenharmony_ci
360662306a36Sopenharmony_ci	if (!ena_dev->mem_bar)
360762306a36Sopenharmony_ci		return -EFAULT;
360862306a36Sopenharmony_ci
360962306a36Sopenharmony_ci	return 0;
361062306a36Sopenharmony_ci}
361162306a36Sopenharmony_ci
361262306a36Sopenharmony_cistatic int ena_device_init(struct ena_adapter *adapter, struct pci_dev *pdev,
361362306a36Sopenharmony_ci			   struct ena_com_dev_get_features_ctx *get_feat_ctx,
361462306a36Sopenharmony_ci			   bool *wd_state)
361562306a36Sopenharmony_ci{
361662306a36Sopenharmony_ci	struct ena_com_dev *ena_dev = adapter->ena_dev;
361762306a36Sopenharmony_ci	struct ena_llq_configurations llq_config;
361862306a36Sopenharmony_ci	struct device *dev = &pdev->dev;
361962306a36Sopenharmony_ci	bool readless_supported;
362062306a36Sopenharmony_ci	u32 aenq_groups;
362162306a36Sopenharmony_ci	int dma_width;
362262306a36Sopenharmony_ci	int rc;
362362306a36Sopenharmony_ci
362462306a36Sopenharmony_ci	rc = ena_com_mmio_reg_read_request_init(ena_dev);
362562306a36Sopenharmony_ci	if (rc) {
362662306a36Sopenharmony_ci		dev_err(dev, "Failed to init mmio read less\n");
362762306a36Sopenharmony_ci		return rc;
362862306a36Sopenharmony_ci	}
362962306a36Sopenharmony_ci
363062306a36Sopenharmony_ci	/* The PCIe configuration space revision id indicate if mmio reg
363162306a36Sopenharmony_ci	 * read is disabled
363262306a36Sopenharmony_ci	 */
363362306a36Sopenharmony_ci	readless_supported = !(pdev->revision & ENA_MMIO_DISABLE_REG_READ);
363462306a36Sopenharmony_ci	ena_com_set_mmio_read_mode(ena_dev, readless_supported);
363562306a36Sopenharmony_ci
363662306a36Sopenharmony_ci	rc = ena_com_dev_reset(ena_dev, ENA_REGS_RESET_NORMAL);
363762306a36Sopenharmony_ci	if (rc) {
363862306a36Sopenharmony_ci		dev_err(dev, "Can not reset device\n");
363962306a36Sopenharmony_ci		goto err_mmio_read_less;
364062306a36Sopenharmony_ci	}
364162306a36Sopenharmony_ci
364262306a36Sopenharmony_ci	rc = ena_com_validate_version(ena_dev);
364362306a36Sopenharmony_ci	if (rc) {
364462306a36Sopenharmony_ci		dev_err(dev, "Device version is too low\n");
364562306a36Sopenharmony_ci		goto err_mmio_read_less;
364662306a36Sopenharmony_ci	}
364762306a36Sopenharmony_ci
364862306a36Sopenharmony_ci	dma_width = ena_com_get_dma_width(ena_dev);
364962306a36Sopenharmony_ci	if (dma_width < 0) {
365062306a36Sopenharmony_ci		dev_err(dev, "Invalid dma width value %d", dma_width);
365162306a36Sopenharmony_ci		rc = dma_width;
365262306a36Sopenharmony_ci		goto err_mmio_read_less;
365362306a36Sopenharmony_ci	}
365462306a36Sopenharmony_ci
365562306a36Sopenharmony_ci	rc = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(dma_width));
365662306a36Sopenharmony_ci	if (rc) {
365762306a36Sopenharmony_ci		dev_err(dev, "dma_set_mask_and_coherent failed %d\n", rc);
365862306a36Sopenharmony_ci		goto err_mmio_read_less;
365962306a36Sopenharmony_ci	}
366062306a36Sopenharmony_ci
366162306a36Sopenharmony_ci	/* ENA admin level init */
366262306a36Sopenharmony_ci	rc = ena_com_admin_init(ena_dev, &aenq_handlers);
366362306a36Sopenharmony_ci	if (rc) {
366462306a36Sopenharmony_ci		dev_err(dev,
366562306a36Sopenharmony_ci			"Can not initialize ena admin queue with device\n");
366662306a36Sopenharmony_ci		goto err_mmio_read_less;
366762306a36Sopenharmony_ci	}
366862306a36Sopenharmony_ci
366962306a36Sopenharmony_ci	/* To enable the msix interrupts the driver needs to know the number
367062306a36Sopenharmony_ci	 * of queues. So the driver uses polling mode to retrieve this
367162306a36Sopenharmony_ci	 * information
367262306a36Sopenharmony_ci	 */
367362306a36Sopenharmony_ci	ena_com_set_admin_polling_mode(ena_dev, true);
367462306a36Sopenharmony_ci
367562306a36Sopenharmony_ci	ena_config_host_info(ena_dev, pdev);
367662306a36Sopenharmony_ci
367762306a36Sopenharmony_ci	/* Get Device Attributes*/
367862306a36Sopenharmony_ci	rc = ena_com_get_dev_attr_feat(ena_dev, get_feat_ctx);
367962306a36Sopenharmony_ci	if (rc) {
368062306a36Sopenharmony_ci		dev_err(dev, "Cannot get attribute for ena device rc=%d\n", rc);
368162306a36Sopenharmony_ci		goto err_admin_init;
368262306a36Sopenharmony_ci	}
368362306a36Sopenharmony_ci
368462306a36Sopenharmony_ci	/* Try to turn all the available aenq groups */
368562306a36Sopenharmony_ci	aenq_groups = BIT(ENA_ADMIN_LINK_CHANGE) |
368662306a36Sopenharmony_ci		BIT(ENA_ADMIN_FATAL_ERROR) |
368762306a36Sopenharmony_ci		BIT(ENA_ADMIN_WARNING) |
368862306a36Sopenharmony_ci		BIT(ENA_ADMIN_NOTIFICATION) |
368962306a36Sopenharmony_ci		BIT(ENA_ADMIN_KEEP_ALIVE);
369062306a36Sopenharmony_ci
369162306a36Sopenharmony_ci	aenq_groups &= get_feat_ctx->aenq.supported_groups;
369262306a36Sopenharmony_ci
369362306a36Sopenharmony_ci	rc = ena_com_set_aenq_config(ena_dev, aenq_groups);
369462306a36Sopenharmony_ci	if (rc) {
369562306a36Sopenharmony_ci		dev_err(dev, "Cannot configure aenq groups rc= %d\n", rc);
369662306a36Sopenharmony_ci		goto err_admin_init;
369762306a36Sopenharmony_ci	}
369862306a36Sopenharmony_ci
369962306a36Sopenharmony_ci	*wd_state = !!(aenq_groups & BIT(ENA_ADMIN_KEEP_ALIVE));
370062306a36Sopenharmony_ci
370162306a36Sopenharmony_ci	set_default_llq_configurations(adapter, &llq_config, &get_feat_ctx->llq);
370262306a36Sopenharmony_ci
370362306a36Sopenharmony_ci	rc = ena_set_queues_placement_policy(pdev, ena_dev, &get_feat_ctx->llq,
370462306a36Sopenharmony_ci					     &llq_config);
370562306a36Sopenharmony_ci	if (rc) {
370662306a36Sopenharmony_ci		dev_err(dev, "ENA device init failed\n");
370762306a36Sopenharmony_ci		goto err_admin_init;
370862306a36Sopenharmony_ci	}
370962306a36Sopenharmony_ci
371062306a36Sopenharmony_ci	ena_calc_io_queue_size(adapter, get_feat_ctx);
371162306a36Sopenharmony_ci
371262306a36Sopenharmony_ci	return 0;
371362306a36Sopenharmony_ci
371462306a36Sopenharmony_cierr_admin_init:
371562306a36Sopenharmony_ci	ena_com_delete_host_info(ena_dev);
371662306a36Sopenharmony_ci	ena_com_admin_destroy(ena_dev);
371762306a36Sopenharmony_cierr_mmio_read_less:
371862306a36Sopenharmony_ci	ena_com_mmio_reg_read_request_destroy(ena_dev);
371962306a36Sopenharmony_ci
372062306a36Sopenharmony_ci	return rc;
372162306a36Sopenharmony_ci}
372262306a36Sopenharmony_ci
372362306a36Sopenharmony_cistatic int ena_enable_msix_and_set_admin_interrupts(struct ena_adapter *adapter)
372462306a36Sopenharmony_ci{
372562306a36Sopenharmony_ci	struct ena_com_dev *ena_dev = adapter->ena_dev;
372662306a36Sopenharmony_ci	struct device *dev = &adapter->pdev->dev;
372762306a36Sopenharmony_ci	int rc;
372862306a36Sopenharmony_ci
372962306a36Sopenharmony_ci	rc = ena_enable_msix(adapter);
373062306a36Sopenharmony_ci	if (rc) {
373162306a36Sopenharmony_ci		dev_err(dev, "Can not reserve msix vectors\n");
373262306a36Sopenharmony_ci		return rc;
373362306a36Sopenharmony_ci	}
373462306a36Sopenharmony_ci
373562306a36Sopenharmony_ci	ena_setup_mgmnt_intr(adapter);
373662306a36Sopenharmony_ci
373762306a36Sopenharmony_ci	rc = ena_request_mgmnt_irq(adapter);
373862306a36Sopenharmony_ci	if (rc) {
373962306a36Sopenharmony_ci		dev_err(dev, "Can not setup management interrupts\n");
374062306a36Sopenharmony_ci		goto err_disable_msix;
374162306a36Sopenharmony_ci	}
374262306a36Sopenharmony_ci
374362306a36Sopenharmony_ci	ena_com_set_admin_polling_mode(ena_dev, false);
374462306a36Sopenharmony_ci
374562306a36Sopenharmony_ci	ena_com_admin_aenq_enable(ena_dev);
374662306a36Sopenharmony_ci
374762306a36Sopenharmony_ci	return 0;
374862306a36Sopenharmony_ci
374962306a36Sopenharmony_cierr_disable_msix:
375062306a36Sopenharmony_ci	ena_disable_msix(adapter);
375162306a36Sopenharmony_ci
375262306a36Sopenharmony_ci	return rc;
375362306a36Sopenharmony_ci}
375462306a36Sopenharmony_ci
375562306a36Sopenharmony_cistatic void ena_destroy_device(struct ena_adapter *adapter, bool graceful)
375662306a36Sopenharmony_ci{
375762306a36Sopenharmony_ci	struct net_device *netdev = adapter->netdev;
375862306a36Sopenharmony_ci	struct ena_com_dev *ena_dev = adapter->ena_dev;
375962306a36Sopenharmony_ci	bool dev_up;
376062306a36Sopenharmony_ci
376162306a36Sopenharmony_ci	if (!test_bit(ENA_FLAG_DEVICE_RUNNING, &adapter->flags))
376262306a36Sopenharmony_ci		return;
376362306a36Sopenharmony_ci
376462306a36Sopenharmony_ci	netif_carrier_off(netdev);
376562306a36Sopenharmony_ci
376662306a36Sopenharmony_ci	del_timer_sync(&adapter->timer_service);
376762306a36Sopenharmony_ci
376862306a36Sopenharmony_ci	dev_up = test_bit(ENA_FLAG_DEV_UP, &adapter->flags);
376962306a36Sopenharmony_ci	adapter->dev_up_before_reset = dev_up;
377062306a36Sopenharmony_ci	if (!graceful)
377162306a36Sopenharmony_ci		ena_com_set_admin_running_state(ena_dev, false);
377262306a36Sopenharmony_ci
377362306a36Sopenharmony_ci	if (test_bit(ENA_FLAG_DEV_UP, &adapter->flags))
377462306a36Sopenharmony_ci		ena_down(adapter);
377562306a36Sopenharmony_ci
377662306a36Sopenharmony_ci	/* Stop the device from sending AENQ events (in case reset flag is set
377762306a36Sopenharmony_ci	 *  and device is up, ena_down() already reset the device.
377862306a36Sopenharmony_ci	 */
377962306a36Sopenharmony_ci	if (!(test_bit(ENA_FLAG_TRIGGER_RESET, &adapter->flags) && dev_up))
378062306a36Sopenharmony_ci		ena_com_dev_reset(adapter->ena_dev, adapter->reset_reason);
378162306a36Sopenharmony_ci
378262306a36Sopenharmony_ci	ena_free_mgmnt_irq(adapter);
378362306a36Sopenharmony_ci
378462306a36Sopenharmony_ci	ena_disable_msix(adapter);
378562306a36Sopenharmony_ci
378662306a36Sopenharmony_ci	ena_com_abort_admin_commands(ena_dev);
378762306a36Sopenharmony_ci
378862306a36Sopenharmony_ci	ena_com_wait_for_abort_completion(ena_dev);
378962306a36Sopenharmony_ci
379062306a36Sopenharmony_ci	ena_com_admin_destroy(ena_dev);
379162306a36Sopenharmony_ci
379262306a36Sopenharmony_ci	ena_com_mmio_reg_read_request_destroy(ena_dev);
379362306a36Sopenharmony_ci
379462306a36Sopenharmony_ci	/* return reset reason to default value */
379562306a36Sopenharmony_ci	adapter->reset_reason = ENA_REGS_RESET_NORMAL;
379662306a36Sopenharmony_ci
379762306a36Sopenharmony_ci	clear_bit(ENA_FLAG_TRIGGER_RESET, &adapter->flags);
379862306a36Sopenharmony_ci	clear_bit(ENA_FLAG_DEVICE_RUNNING, &adapter->flags);
379962306a36Sopenharmony_ci}
380062306a36Sopenharmony_ci
380162306a36Sopenharmony_cistatic int ena_restore_device(struct ena_adapter *adapter)
380262306a36Sopenharmony_ci{
380362306a36Sopenharmony_ci	struct ena_com_dev_get_features_ctx get_feat_ctx;
380462306a36Sopenharmony_ci	struct ena_com_dev *ena_dev = adapter->ena_dev;
380562306a36Sopenharmony_ci	struct pci_dev *pdev = adapter->pdev;
380662306a36Sopenharmony_ci	struct ena_ring *txr;
380762306a36Sopenharmony_ci	int rc, count, i;
380862306a36Sopenharmony_ci	bool wd_state;
380962306a36Sopenharmony_ci
381062306a36Sopenharmony_ci	set_bit(ENA_FLAG_ONGOING_RESET, &adapter->flags);
381162306a36Sopenharmony_ci	rc = ena_device_init(adapter, adapter->pdev, &get_feat_ctx, &wd_state);
381262306a36Sopenharmony_ci	if (rc) {
381362306a36Sopenharmony_ci		dev_err(&pdev->dev, "Can not initialize device\n");
381462306a36Sopenharmony_ci		goto err;
381562306a36Sopenharmony_ci	}
381662306a36Sopenharmony_ci	adapter->wd_state = wd_state;
381762306a36Sopenharmony_ci
381862306a36Sopenharmony_ci	count =  adapter->xdp_num_queues + adapter->num_io_queues;
381962306a36Sopenharmony_ci	for (i = 0 ; i < count; i++) {
382062306a36Sopenharmony_ci		txr = &adapter->tx_ring[i];
382162306a36Sopenharmony_ci		txr->tx_mem_queue_type = ena_dev->tx_mem_queue_type;
382262306a36Sopenharmony_ci		txr->tx_max_header_size = ena_dev->tx_max_header_size;
382362306a36Sopenharmony_ci	}
382462306a36Sopenharmony_ci
382562306a36Sopenharmony_ci	rc = ena_device_validate_params(adapter, &get_feat_ctx);
382662306a36Sopenharmony_ci	if (rc) {
382762306a36Sopenharmony_ci		dev_err(&pdev->dev, "Validation of device parameters failed\n");
382862306a36Sopenharmony_ci		goto err_device_destroy;
382962306a36Sopenharmony_ci	}
383062306a36Sopenharmony_ci
383162306a36Sopenharmony_ci	rc = ena_enable_msix_and_set_admin_interrupts(adapter);
383262306a36Sopenharmony_ci	if (rc) {
383362306a36Sopenharmony_ci		dev_err(&pdev->dev, "Enable MSI-X failed\n");
383462306a36Sopenharmony_ci		goto err_device_destroy;
383562306a36Sopenharmony_ci	}
383662306a36Sopenharmony_ci	/* If the interface was up before the reset bring it up */
383762306a36Sopenharmony_ci	if (adapter->dev_up_before_reset) {
383862306a36Sopenharmony_ci		rc = ena_up(adapter);
383962306a36Sopenharmony_ci		if (rc) {
384062306a36Sopenharmony_ci			dev_err(&pdev->dev, "Failed to create I/O queues\n");
384162306a36Sopenharmony_ci			goto err_disable_msix;
384262306a36Sopenharmony_ci		}
384362306a36Sopenharmony_ci	}
384462306a36Sopenharmony_ci
384562306a36Sopenharmony_ci	set_bit(ENA_FLAG_DEVICE_RUNNING, &adapter->flags);
384662306a36Sopenharmony_ci
384762306a36Sopenharmony_ci	clear_bit(ENA_FLAG_ONGOING_RESET, &adapter->flags);
384862306a36Sopenharmony_ci	if (test_bit(ENA_FLAG_LINK_UP, &adapter->flags))
384962306a36Sopenharmony_ci		netif_carrier_on(adapter->netdev);
385062306a36Sopenharmony_ci
385162306a36Sopenharmony_ci	mod_timer(&adapter->timer_service, round_jiffies(jiffies + HZ));
385262306a36Sopenharmony_ci	adapter->last_keep_alive_jiffies = jiffies;
385362306a36Sopenharmony_ci
385462306a36Sopenharmony_ci	return rc;
385562306a36Sopenharmony_cierr_disable_msix:
385662306a36Sopenharmony_ci	ena_free_mgmnt_irq(adapter);
385762306a36Sopenharmony_ci	ena_disable_msix(adapter);
385862306a36Sopenharmony_cierr_device_destroy:
385962306a36Sopenharmony_ci	ena_com_abort_admin_commands(ena_dev);
386062306a36Sopenharmony_ci	ena_com_wait_for_abort_completion(ena_dev);
386162306a36Sopenharmony_ci	ena_com_admin_destroy(ena_dev);
386262306a36Sopenharmony_ci	ena_com_dev_reset(ena_dev, ENA_REGS_RESET_DRIVER_INVALID_STATE);
386362306a36Sopenharmony_ci	ena_com_mmio_reg_read_request_destroy(ena_dev);
386462306a36Sopenharmony_cierr:
386562306a36Sopenharmony_ci	clear_bit(ENA_FLAG_DEVICE_RUNNING, &adapter->flags);
386662306a36Sopenharmony_ci	clear_bit(ENA_FLAG_ONGOING_RESET, &adapter->flags);
386762306a36Sopenharmony_ci	dev_err(&pdev->dev,
386862306a36Sopenharmony_ci		"Reset attempt failed. Can not reset the device\n");
386962306a36Sopenharmony_ci
387062306a36Sopenharmony_ci	return rc;
387162306a36Sopenharmony_ci}
387262306a36Sopenharmony_ci
387362306a36Sopenharmony_cistatic void ena_fw_reset_device(struct work_struct *work)
387462306a36Sopenharmony_ci{
387562306a36Sopenharmony_ci	struct ena_adapter *adapter =
387662306a36Sopenharmony_ci		container_of(work, struct ena_adapter, reset_task);
387762306a36Sopenharmony_ci
387862306a36Sopenharmony_ci	rtnl_lock();
387962306a36Sopenharmony_ci
388062306a36Sopenharmony_ci	if (likely(test_bit(ENA_FLAG_TRIGGER_RESET, &adapter->flags))) {
388162306a36Sopenharmony_ci		ena_destroy_device(adapter, false);
388262306a36Sopenharmony_ci		ena_restore_device(adapter);
388362306a36Sopenharmony_ci
388462306a36Sopenharmony_ci		dev_err(&adapter->pdev->dev, "Device reset completed successfully\n");
388562306a36Sopenharmony_ci	}
388662306a36Sopenharmony_ci
388762306a36Sopenharmony_ci	rtnl_unlock();
388862306a36Sopenharmony_ci}
388962306a36Sopenharmony_ci
389062306a36Sopenharmony_cistatic int check_for_rx_interrupt_queue(struct ena_adapter *adapter,
389162306a36Sopenharmony_ci					struct ena_ring *rx_ring)
389262306a36Sopenharmony_ci{
389362306a36Sopenharmony_ci	struct ena_napi *ena_napi = container_of(rx_ring->napi, struct ena_napi, napi);
389462306a36Sopenharmony_ci
389562306a36Sopenharmony_ci	if (likely(READ_ONCE(ena_napi->first_interrupt)))
389662306a36Sopenharmony_ci		return 0;
389762306a36Sopenharmony_ci
389862306a36Sopenharmony_ci	if (ena_com_cq_empty(rx_ring->ena_com_io_cq))
389962306a36Sopenharmony_ci		return 0;
390062306a36Sopenharmony_ci
390162306a36Sopenharmony_ci	rx_ring->no_interrupt_event_cnt++;
390262306a36Sopenharmony_ci
390362306a36Sopenharmony_ci	if (rx_ring->no_interrupt_event_cnt == ENA_MAX_NO_INTERRUPT_ITERATIONS) {
390462306a36Sopenharmony_ci		netif_err(adapter, rx_err, adapter->netdev,
390562306a36Sopenharmony_ci			  "Potential MSIX issue on Rx side Queue = %d. Reset the device\n",
390662306a36Sopenharmony_ci			  rx_ring->qid);
390762306a36Sopenharmony_ci
390862306a36Sopenharmony_ci		ena_reset_device(adapter, ENA_REGS_RESET_MISS_INTERRUPT);
390962306a36Sopenharmony_ci		return -EIO;
391062306a36Sopenharmony_ci	}
391162306a36Sopenharmony_ci
391262306a36Sopenharmony_ci	return 0;
391362306a36Sopenharmony_ci}
391462306a36Sopenharmony_ci
391562306a36Sopenharmony_cistatic int check_missing_comp_in_tx_queue(struct ena_adapter *adapter,
391662306a36Sopenharmony_ci					  struct ena_ring *tx_ring)
391762306a36Sopenharmony_ci{
391862306a36Sopenharmony_ci	struct ena_napi *ena_napi = container_of(tx_ring->napi, struct ena_napi, napi);
391962306a36Sopenharmony_ci	unsigned int time_since_last_napi;
392062306a36Sopenharmony_ci	unsigned int missing_tx_comp_to;
392162306a36Sopenharmony_ci	bool is_tx_comp_time_expired;
392262306a36Sopenharmony_ci	struct ena_tx_buffer *tx_buf;
392362306a36Sopenharmony_ci	unsigned long last_jiffies;
392462306a36Sopenharmony_ci	u32 missed_tx = 0;
392562306a36Sopenharmony_ci	int i, rc = 0;
392662306a36Sopenharmony_ci
392762306a36Sopenharmony_ci	for (i = 0; i < tx_ring->ring_size; i++) {
392862306a36Sopenharmony_ci		tx_buf = &tx_ring->tx_buffer_info[i];
392962306a36Sopenharmony_ci		last_jiffies = tx_buf->last_jiffies;
393062306a36Sopenharmony_ci
393162306a36Sopenharmony_ci		if (last_jiffies == 0)
393262306a36Sopenharmony_ci			/* no pending Tx at this location */
393362306a36Sopenharmony_ci			continue;
393462306a36Sopenharmony_ci
393562306a36Sopenharmony_ci		is_tx_comp_time_expired = time_is_before_jiffies(last_jiffies +
393662306a36Sopenharmony_ci			 2 * adapter->missing_tx_completion_to);
393762306a36Sopenharmony_ci
393862306a36Sopenharmony_ci		if (unlikely(!READ_ONCE(ena_napi->first_interrupt) && is_tx_comp_time_expired)) {
393962306a36Sopenharmony_ci			/* If after graceful period interrupt is still not
394062306a36Sopenharmony_ci			 * received, we schedule a reset
394162306a36Sopenharmony_ci			 */
394262306a36Sopenharmony_ci			netif_err(adapter, tx_err, adapter->netdev,
394362306a36Sopenharmony_ci				  "Potential MSIX issue on Tx side Queue = %d. Reset the device\n",
394462306a36Sopenharmony_ci				  tx_ring->qid);
394562306a36Sopenharmony_ci			ena_reset_device(adapter, ENA_REGS_RESET_MISS_INTERRUPT);
394662306a36Sopenharmony_ci			return -EIO;
394762306a36Sopenharmony_ci		}
394862306a36Sopenharmony_ci
394962306a36Sopenharmony_ci		is_tx_comp_time_expired = time_is_before_jiffies(last_jiffies +
395062306a36Sopenharmony_ci			adapter->missing_tx_completion_to);
395162306a36Sopenharmony_ci
395262306a36Sopenharmony_ci		if (unlikely(is_tx_comp_time_expired)) {
395362306a36Sopenharmony_ci			if (!tx_buf->print_once) {
395462306a36Sopenharmony_ci				time_since_last_napi = jiffies_to_usecs(jiffies - tx_ring->tx_stats.last_napi_jiffies);
395562306a36Sopenharmony_ci				missing_tx_comp_to = jiffies_to_msecs(adapter->missing_tx_completion_to);
395662306a36Sopenharmony_ci				netif_notice(adapter, tx_err, adapter->netdev,
395762306a36Sopenharmony_ci					     "Found a Tx that wasn't completed on time, qid %d, index %d. %u usecs have passed since last napi execution. Missing Tx timeout value %u msecs\n",
395862306a36Sopenharmony_ci					     tx_ring->qid, i, time_since_last_napi, missing_tx_comp_to);
395962306a36Sopenharmony_ci			}
396062306a36Sopenharmony_ci
396162306a36Sopenharmony_ci			tx_buf->print_once = 1;
396262306a36Sopenharmony_ci			missed_tx++;
396362306a36Sopenharmony_ci		}
396462306a36Sopenharmony_ci	}
396562306a36Sopenharmony_ci
396662306a36Sopenharmony_ci	if (unlikely(missed_tx > adapter->missing_tx_completion_threshold)) {
396762306a36Sopenharmony_ci		netif_err(adapter, tx_err, adapter->netdev,
396862306a36Sopenharmony_ci			  "The number of lost tx completions is above the threshold (%d > %d). Reset the device\n",
396962306a36Sopenharmony_ci			  missed_tx,
397062306a36Sopenharmony_ci			  adapter->missing_tx_completion_threshold);
397162306a36Sopenharmony_ci		ena_reset_device(adapter, ENA_REGS_RESET_MISS_TX_CMPL);
397262306a36Sopenharmony_ci		rc = -EIO;
397362306a36Sopenharmony_ci	}
397462306a36Sopenharmony_ci
397562306a36Sopenharmony_ci	ena_increase_stat(&tx_ring->tx_stats.missed_tx, missed_tx,
397662306a36Sopenharmony_ci			  &tx_ring->syncp);
397762306a36Sopenharmony_ci
397862306a36Sopenharmony_ci	return rc;
397962306a36Sopenharmony_ci}
398062306a36Sopenharmony_ci
398162306a36Sopenharmony_cistatic void check_for_missing_completions(struct ena_adapter *adapter)
398262306a36Sopenharmony_ci{
398362306a36Sopenharmony_ci	struct ena_ring *tx_ring;
398462306a36Sopenharmony_ci	struct ena_ring *rx_ring;
398562306a36Sopenharmony_ci	int i, budget, rc;
398662306a36Sopenharmony_ci	int io_queue_count;
398762306a36Sopenharmony_ci
398862306a36Sopenharmony_ci	io_queue_count = adapter->xdp_num_queues + adapter->num_io_queues;
398962306a36Sopenharmony_ci	/* Make sure the driver doesn't turn the device in other process */
399062306a36Sopenharmony_ci	smp_rmb();
399162306a36Sopenharmony_ci
399262306a36Sopenharmony_ci	if (!test_bit(ENA_FLAG_DEV_UP, &adapter->flags))
399362306a36Sopenharmony_ci		return;
399462306a36Sopenharmony_ci
399562306a36Sopenharmony_ci	if (test_bit(ENA_FLAG_TRIGGER_RESET, &adapter->flags))
399662306a36Sopenharmony_ci		return;
399762306a36Sopenharmony_ci
399862306a36Sopenharmony_ci	if (adapter->missing_tx_completion_to == ENA_HW_HINTS_NO_TIMEOUT)
399962306a36Sopenharmony_ci		return;
400062306a36Sopenharmony_ci
400162306a36Sopenharmony_ci	budget = ENA_MONITORED_TX_QUEUES;
400262306a36Sopenharmony_ci
400362306a36Sopenharmony_ci	for (i = adapter->last_monitored_tx_qid; i < io_queue_count; i++) {
400462306a36Sopenharmony_ci		tx_ring = &adapter->tx_ring[i];
400562306a36Sopenharmony_ci		rx_ring = &adapter->rx_ring[i];
400662306a36Sopenharmony_ci
400762306a36Sopenharmony_ci		rc = check_missing_comp_in_tx_queue(adapter, tx_ring);
400862306a36Sopenharmony_ci		if (unlikely(rc))
400962306a36Sopenharmony_ci			return;
401062306a36Sopenharmony_ci
401162306a36Sopenharmony_ci		rc =  !ENA_IS_XDP_INDEX(adapter, i) ?
401262306a36Sopenharmony_ci			check_for_rx_interrupt_queue(adapter, rx_ring) : 0;
401362306a36Sopenharmony_ci		if (unlikely(rc))
401462306a36Sopenharmony_ci			return;
401562306a36Sopenharmony_ci
401662306a36Sopenharmony_ci		budget--;
401762306a36Sopenharmony_ci		if (!budget)
401862306a36Sopenharmony_ci			break;
401962306a36Sopenharmony_ci	}
402062306a36Sopenharmony_ci
402162306a36Sopenharmony_ci	adapter->last_monitored_tx_qid = i % io_queue_count;
402262306a36Sopenharmony_ci}
402362306a36Sopenharmony_ci
402462306a36Sopenharmony_ci/* trigger napi schedule after 2 consecutive detections */
402562306a36Sopenharmony_ci#define EMPTY_RX_REFILL 2
402662306a36Sopenharmony_ci/* For the rare case where the device runs out of Rx descriptors and the
402762306a36Sopenharmony_ci * napi handler failed to refill new Rx descriptors (due to a lack of memory
402862306a36Sopenharmony_ci * for example).
402962306a36Sopenharmony_ci * This case will lead to a deadlock:
403062306a36Sopenharmony_ci * The device won't send interrupts since all the new Rx packets will be dropped
403162306a36Sopenharmony_ci * The napi handler won't allocate new Rx descriptors so the device will be
403262306a36Sopenharmony_ci * able to send new packets.
403362306a36Sopenharmony_ci *
403462306a36Sopenharmony_ci * This scenario can happen when the kernel's vm.min_free_kbytes is too small.
403562306a36Sopenharmony_ci * It is recommended to have at least 512MB, with a minimum of 128MB for
403662306a36Sopenharmony_ci * constrained environment).
403762306a36Sopenharmony_ci *
403862306a36Sopenharmony_ci * When such a situation is detected - Reschedule napi
403962306a36Sopenharmony_ci */
404062306a36Sopenharmony_cistatic void check_for_empty_rx_ring(struct ena_adapter *adapter)
404162306a36Sopenharmony_ci{
404262306a36Sopenharmony_ci	struct ena_ring *rx_ring;
404362306a36Sopenharmony_ci	int i, refill_required;
404462306a36Sopenharmony_ci
404562306a36Sopenharmony_ci	if (!test_bit(ENA_FLAG_DEV_UP, &adapter->flags))
404662306a36Sopenharmony_ci		return;
404762306a36Sopenharmony_ci
404862306a36Sopenharmony_ci	if (test_bit(ENA_FLAG_TRIGGER_RESET, &adapter->flags))
404962306a36Sopenharmony_ci		return;
405062306a36Sopenharmony_ci
405162306a36Sopenharmony_ci	for (i = 0; i < adapter->num_io_queues; i++) {
405262306a36Sopenharmony_ci		rx_ring = &adapter->rx_ring[i];
405362306a36Sopenharmony_ci
405462306a36Sopenharmony_ci		refill_required = ena_com_free_q_entries(rx_ring->ena_com_io_sq);
405562306a36Sopenharmony_ci		if (unlikely(refill_required == (rx_ring->ring_size - 1))) {
405662306a36Sopenharmony_ci			rx_ring->empty_rx_queue++;
405762306a36Sopenharmony_ci
405862306a36Sopenharmony_ci			if (rx_ring->empty_rx_queue >= EMPTY_RX_REFILL) {
405962306a36Sopenharmony_ci				ena_increase_stat(&rx_ring->rx_stats.empty_rx_ring, 1,
406062306a36Sopenharmony_ci						  &rx_ring->syncp);
406162306a36Sopenharmony_ci
406262306a36Sopenharmony_ci				netif_err(adapter, drv, adapter->netdev,
406362306a36Sopenharmony_ci					  "Trigger refill for ring %d\n", i);
406462306a36Sopenharmony_ci
406562306a36Sopenharmony_ci				napi_schedule(rx_ring->napi);
406662306a36Sopenharmony_ci				rx_ring->empty_rx_queue = 0;
406762306a36Sopenharmony_ci			}
406862306a36Sopenharmony_ci		} else {
406962306a36Sopenharmony_ci			rx_ring->empty_rx_queue = 0;
407062306a36Sopenharmony_ci		}
407162306a36Sopenharmony_ci	}
407262306a36Sopenharmony_ci}
407362306a36Sopenharmony_ci
407462306a36Sopenharmony_ci/* Check for keep alive expiration */
407562306a36Sopenharmony_cistatic void check_for_missing_keep_alive(struct ena_adapter *adapter)
407662306a36Sopenharmony_ci{
407762306a36Sopenharmony_ci	unsigned long keep_alive_expired;
407862306a36Sopenharmony_ci
407962306a36Sopenharmony_ci	if (!adapter->wd_state)
408062306a36Sopenharmony_ci		return;
408162306a36Sopenharmony_ci
408262306a36Sopenharmony_ci	if (adapter->keep_alive_timeout == ENA_HW_HINTS_NO_TIMEOUT)
408362306a36Sopenharmony_ci		return;
408462306a36Sopenharmony_ci
408562306a36Sopenharmony_ci	keep_alive_expired = adapter->last_keep_alive_jiffies +
408662306a36Sopenharmony_ci			     adapter->keep_alive_timeout;
408762306a36Sopenharmony_ci	if (unlikely(time_is_before_jiffies(keep_alive_expired))) {
408862306a36Sopenharmony_ci		netif_err(adapter, drv, adapter->netdev,
408962306a36Sopenharmony_ci			  "Keep alive watchdog timeout.\n");
409062306a36Sopenharmony_ci		ena_increase_stat(&adapter->dev_stats.wd_expired, 1,
409162306a36Sopenharmony_ci				  &adapter->syncp);
409262306a36Sopenharmony_ci		ena_reset_device(adapter, ENA_REGS_RESET_KEEP_ALIVE_TO);
409362306a36Sopenharmony_ci	}
409462306a36Sopenharmony_ci}
409562306a36Sopenharmony_ci
409662306a36Sopenharmony_cistatic void check_for_admin_com_state(struct ena_adapter *adapter)
409762306a36Sopenharmony_ci{
409862306a36Sopenharmony_ci	if (unlikely(!ena_com_get_admin_running_state(adapter->ena_dev))) {
409962306a36Sopenharmony_ci		netif_err(adapter, drv, adapter->netdev,
410062306a36Sopenharmony_ci			  "ENA admin queue is not in running state!\n");
410162306a36Sopenharmony_ci		ena_increase_stat(&adapter->dev_stats.admin_q_pause, 1,
410262306a36Sopenharmony_ci				  &adapter->syncp);
410362306a36Sopenharmony_ci		ena_reset_device(adapter, ENA_REGS_RESET_ADMIN_TO);
410462306a36Sopenharmony_ci	}
410562306a36Sopenharmony_ci}
410662306a36Sopenharmony_ci
410762306a36Sopenharmony_cistatic void ena_update_hints(struct ena_adapter *adapter,
410862306a36Sopenharmony_ci			     struct ena_admin_ena_hw_hints *hints)
410962306a36Sopenharmony_ci{
411062306a36Sopenharmony_ci	struct net_device *netdev = adapter->netdev;
411162306a36Sopenharmony_ci
411262306a36Sopenharmony_ci	if (hints->admin_completion_tx_timeout)
411362306a36Sopenharmony_ci		adapter->ena_dev->admin_queue.completion_timeout =
411462306a36Sopenharmony_ci			hints->admin_completion_tx_timeout * 1000;
411562306a36Sopenharmony_ci
411662306a36Sopenharmony_ci	if (hints->mmio_read_timeout)
411762306a36Sopenharmony_ci		/* convert to usec */
411862306a36Sopenharmony_ci		adapter->ena_dev->mmio_read.reg_read_to =
411962306a36Sopenharmony_ci			hints->mmio_read_timeout * 1000;
412062306a36Sopenharmony_ci
412162306a36Sopenharmony_ci	if (hints->missed_tx_completion_count_threshold_to_reset)
412262306a36Sopenharmony_ci		adapter->missing_tx_completion_threshold =
412362306a36Sopenharmony_ci			hints->missed_tx_completion_count_threshold_to_reset;
412462306a36Sopenharmony_ci
412562306a36Sopenharmony_ci	if (hints->missing_tx_completion_timeout) {
412662306a36Sopenharmony_ci		if (hints->missing_tx_completion_timeout == ENA_HW_HINTS_NO_TIMEOUT)
412762306a36Sopenharmony_ci			adapter->missing_tx_completion_to = ENA_HW_HINTS_NO_TIMEOUT;
412862306a36Sopenharmony_ci		else
412962306a36Sopenharmony_ci			adapter->missing_tx_completion_to =
413062306a36Sopenharmony_ci				msecs_to_jiffies(hints->missing_tx_completion_timeout);
413162306a36Sopenharmony_ci	}
413262306a36Sopenharmony_ci
413362306a36Sopenharmony_ci	if (hints->netdev_wd_timeout)
413462306a36Sopenharmony_ci		netdev->watchdog_timeo = msecs_to_jiffies(hints->netdev_wd_timeout);
413562306a36Sopenharmony_ci
413662306a36Sopenharmony_ci	if (hints->driver_watchdog_timeout) {
413762306a36Sopenharmony_ci		if (hints->driver_watchdog_timeout == ENA_HW_HINTS_NO_TIMEOUT)
413862306a36Sopenharmony_ci			adapter->keep_alive_timeout = ENA_HW_HINTS_NO_TIMEOUT;
413962306a36Sopenharmony_ci		else
414062306a36Sopenharmony_ci			adapter->keep_alive_timeout =
414162306a36Sopenharmony_ci				msecs_to_jiffies(hints->driver_watchdog_timeout);
414262306a36Sopenharmony_ci	}
414362306a36Sopenharmony_ci}
414462306a36Sopenharmony_ci
414562306a36Sopenharmony_cistatic void ena_update_host_info(struct ena_admin_host_info *host_info,
414662306a36Sopenharmony_ci				 struct net_device *netdev)
414762306a36Sopenharmony_ci{
414862306a36Sopenharmony_ci	host_info->supported_network_features[0] =
414962306a36Sopenharmony_ci		netdev->features & GENMASK_ULL(31, 0);
415062306a36Sopenharmony_ci	host_info->supported_network_features[1] =
415162306a36Sopenharmony_ci		(netdev->features & GENMASK_ULL(63, 32)) >> 32;
415262306a36Sopenharmony_ci}
415362306a36Sopenharmony_ci
415462306a36Sopenharmony_cistatic void ena_timer_service(struct timer_list *t)
415562306a36Sopenharmony_ci{
415662306a36Sopenharmony_ci	struct ena_adapter *adapter = from_timer(adapter, t, timer_service);
415762306a36Sopenharmony_ci	u8 *debug_area = adapter->ena_dev->host_attr.debug_area_virt_addr;
415862306a36Sopenharmony_ci	struct ena_admin_host_info *host_info =
415962306a36Sopenharmony_ci		adapter->ena_dev->host_attr.host_info;
416062306a36Sopenharmony_ci
416162306a36Sopenharmony_ci	check_for_missing_keep_alive(adapter);
416262306a36Sopenharmony_ci
416362306a36Sopenharmony_ci	check_for_admin_com_state(adapter);
416462306a36Sopenharmony_ci
416562306a36Sopenharmony_ci	check_for_missing_completions(adapter);
416662306a36Sopenharmony_ci
416762306a36Sopenharmony_ci	check_for_empty_rx_ring(adapter);
416862306a36Sopenharmony_ci
416962306a36Sopenharmony_ci	if (debug_area)
417062306a36Sopenharmony_ci		ena_dump_stats_to_buf(adapter, debug_area);
417162306a36Sopenharmony_ci
417262306a36Sopenharmony_ci	if (host_info)
417362306a36Sopenharmony_ci		ena_update_host_info(host_info, adapter->netdev);
417462306a36Sopenharmony_ci
417562306a36Sopenharmony_ci	if (unlikely(test_bit(ENA_FLAG_TRIGGER_RESET, &adapter->flags))) {
417662306a36Sopenharmony_ci		netif_err(adapter, drv, adapter->netdev,
417762306a36Sopenharmony_ci			  "Trigger reset is on\n");
417862306a36Sopenharmony_ci		ena_dump_stats_to_dmesg(adapter);
417962306a36Sopenharmony_ci		queue_work(ena_wq, &adapter->reset_task);
418062306a36Sopenharmony_ci		return;
418162306a36Sopenharmony_ci	}
418262306a36Sopenharmony_ci
418362306a36Sopenharmony_ci	/* Reset the timer */
418462306a36Sopenharmony_ci	mod_timer(&adapter->timer_service, round_jiffies(jiffies + HZ));
418562306a36Sopenharmony_ci}
418662306a36Sopenharmony_ci
418762306a36Sopenharmony_cistatic u32 ena_calc_max_io_queue_num(struct pci_dev *pdev,
418862306a36Sopenharmony_ci				     struct ena_com_dev *ena_dev,
418962306a36Sopenharmony_ci				     struct ena_com_dev_get_features_ctx *get_feat_ctx)
419062306a36Sopenharmony_ci{
419162306a36Sopenharmony_ci	u32 io_tx_sq_num, io_tx_cq_num, io_rx_num, max_num_io_queues;
419262306a36Sopenharmony_ci
419362306a36Sopenharmony_ci	if (ena_dev->supported_features & BIT(ENA_ADMIN_MAX_QUEUES_EXT)) {
419462306a36Sopenharmony_ci		struct ena_admin_queue_ext_feature_fields *max_queue_ext =
419562306a36Sopenharmony_ci			&get_feat_ctx->max_queue_ext.max_queue_ext;
419662306a36Sopenharmony_ci		io_rx_num = min_t(u32, max_queue_ext->max_rx_sq_num,
419762306a36Sopenharmony_ci				  max_queue_ext->max_rx_cq_num);
419862306a36Sopenharmony_ci
419962306a36Sopenharmony_ci		io_tx_sq_num = max_queue_ext->max_tx_sq_num;
420062306a36Sopenharmony_ci		io_tx_cq_num = max_queue_ext->max_tx_cq_num;
420162306a36Sopenharmony_ci	} else {
420262306a36Sopenharmony_ci		struct ena_admin_queue_feature_desc *max_queues =
420362306a36Sopenharmony_ci			&get_feat_ctx->max_queues;
420462306a36Sopenharmony_ci		io_tx_sq_num = max_queues->max_sq_num;
420562306a36Sopenharmony_ci		io_tx_cq_num = max_queues->max_cq_num;
420662306a36Sopenharmony_ci		io_rx_num = min_t(u32, io_tx_sq_num, io_tx_cq_num);
420762306a36Sopenharmony_ci	}
420862306a36Sopenharmony_ci
420962306a36Sopenharmony_ci	/* In case of LLQ use the llq fields for the tx SQ/CQ */
421062306a36Sopenharmony_ci	if (ena_dev->tx_mem_queue_type == ENA_ADMIN_PLACEMENT_POLICY_DEV)
421162306a36Sopenharmony_ci		io_tx_sq_num = get_feat_ctx->llq.max_llq_num;
421262306a36Sopenharmony_ci
421362306a36Sopenharmony_ci	max_num_io_queues = min_t(u32, num_online_cpus(), ENA_MAX_NUM_IO_QUEUES);
421462306a36Sopenharmony_ci	max_num_io_queues = min_t(u32, max_num_io_queues, io_rx_num);
421562306a36Sopenharmony_ci	max_num_io_queues = min_t(u32, max_num_io_queues, io_tx_sq_num);
421662306a36Sopenharmony_ci	max_num_io_queues = min_t(u32, max_num_io_queues, io_tx_cq_num);
421762306a36Sopenharmony_ci	/* 1 IRQ for mgmnt and 1 IRQs for each IO direction */
421862306a36Sopenharmony_ci	max_num_io_queues = min_t(u32, max_num_io_queues, pci_msix_vec_count(pdev) - 1);
421962306a36Sopenharmony_ci
422062306a36Sopenharmony_ci	return max_num_io_queues;
422162306a36Sopenharmony_ci}
422262306a36Sopenharmony_ci
422362306a36Sopenharmony_cistatic void ena_set_dev_offloads(struct ena_com_dev_get_features_ctx *feat,
422462306a36Sopenharmony_ci				 struct net_device *netdev)
422562306a36Sopenharmony_ci{
422662306a36Sopenharmony_ci	netdev_features_t dev_features = 0;
422762306a36Sopenharmony_ci
422862306a36Sopenharmony_ci	/* Set offload features */
422962306a36Sopenharmony_ci	if (feat->offload.tx &
423062306a36Sopenharmony_ci		ENA_ADMIN_FEATURE_OFFLOAD_DESC_TX_L4_IPV4_CSUM_PART_MASK)
423162306a36Sopenharmony_ci		dev_features |= NETIF_F_IP_CSUM;
423262306a36Sopenharmony_ci
423362306a36Sopenharmony_ci	if (feat->offload.tx &
423462306a36Sopenharmony_ci		ENA_ADMIN_FEATURE_OFFLOAD_DESC_TX_L4_IPV6_CSUM_PART_MASK)
423562306a36Sopenharmony_ci		dev_features |= NETIF_F_IPV6_CSUM;
423662306a36Sopenharmony_ci
423762306a36Sopenharmony_ci	if (feat->offload.tx & ENA_ADMIN_FEATURE_OFFLOAD_DESC_TSO_IPV4_MASK)
423862306a36Sopenharmony_ci		dev_features |= NETIF_F_TSO;
423962306a36Sopenharmony_ci
424062306a36Sopenharmony_ci	if (feat->offload.tx & ENA_ADMIN_FEATURE_OFFLOAD_DESC_TSO_IPV6_MASK)
424162306a36Sopenharmony_ci		dev_features |= NETIF_F_TSO6;
424262306a36Sopenharmony_ci
424362306a36Sopenharmony_ci	if (feat->offload.tx & ENA_ADMIN_FEATURE_OFFLOAD_DESC_TSO_ECN_MASK)
424462306a36Sopenharmony_ci		dev_features |= NETIF_F_TSO_ECN;
424562306a36Sopenharmony_ci
424662306a36Sopenharmony_ci	if (feat->offload.rx_supported &
424762306a36Sopenharmony_ci		ENA_ADMIN_FEATURE_OFFLOAD_DESC_RX_L4_IPV4_CSUM_MASK)
424862306a36Sopenharmony_ci		dev_features |= NETIF_F_RXCSUM;
424962306a36Sopenharmony_ci
425062306a36Sopenharmony_ci	if (feat->offload.rx_supported &
425162306a36Sopenharmony_ci		ENA_ADMIN_FEATURE_OFFLOAD_DESC_RX_L4_IPV6_CSUM_MASK)
425262306a36Sopenharmony_ci		dev_features |= NETIF_F_RXCSUM;
425362306a36Sopenharmony_ci
425462306a36Sopenharmony_ci	netdev->features =
425562306a36Sopenharmony_ci		dev_features |
425662306a36Sopenharmony_ci		NETIF_F_SG |
425762306a36Sopenharmony_ci		NETIF_F_RXHASH |
425862306a36Sopenharmony_ci		NETIF_F_HIGHDMA;
425962306a36Sopenharmony_ci
426062306a36Sopenharmony_ci	netdev->hw_features |= netdev->features;
426162306a36Sopenharmony_ci	netdev->vlan_features |= netdev->features;
426262306a36Sopenharmony_ci}
426362306a36Sopenharmony_ci
426462306a36Sopenharmony_cistatic void ena_set_conf_feat_params(struct ena_adapter *adapter,
426562306a36Sopenharmony_ci				     struct ena_com_dev_get_features_ctx *feat)
426662306a36Sopenharmony_ci{
426762306a36Sopenharmony_ci	struct net_device *netdev = adapter->netdev;
426862306a36Sopenharmony_ci
426962306a36Sopenharmony_ci	/* Copy mac address */
427062306a36Sopenharmony_ci	if (!is_valid_ether_addr(feat->dev_attr.mac_addr)) {
427162306a36Sopenharmony_ci		eth_hw_addr_random(netdev);
427262306a36Sopenharmony_ci		ether_addr_copy(adapter->mac_addr, netdev->dev_addr);
427362306a36Sopenharmony_ci	} else {
427462306a36Sopenharmony_ci		ether_addr_copy(adapter->mac_addr, feat->dev_attr.mac_addr);
427562306a36Sopenharmony_ci		eth_hw_addr_set(netdev, adapter->mac_addr);
427662306a36Sopenharmony_ci	}
427762306a36Sopenharmony_ci
427862306a36Sopenharmony_ci	/* Set offload features */
427962306a36Sopenharmony_ci	ena_set_dev_offloads(feat, netdev);
428062306a36Sopenharmony_ci
428162306a36Sopenharmony_ci	adapter->max_mtu = feat->dev_attr.max_mtu;
428262306a36Sopenharmony_ci	netdev->max_mtu = adapter->max_mtu;
428362306a36Sopenharmony_ci	netdev->min_mtu = ENA_MIN_MTU;
428462306a36Sopenharmony_ci}
428562306a36Sopenharmony_ci
428662306a36Sopenharmony_cistatic int ena_rss_init_default(struct ena_adapter *adapter)
428762306a36Sopenharmony_ci{
428862306a36Sopenharmony_ci	struct ena_com_dev *ena_dev = adapter->ena_dev;
428962306a36Sopenharmony_ci	struct device *dev = &adapter->pdev->dev;
429062306a36Sopenharmony_ci	int rc, i;
429162306a36Sopenharmony_ci	u32 val;
429262306a36Sopenharmony_ci
429362306a36Sopenharmony_ci	rc = ena_com_rss_init(ena_dev, ENA_RX_RSS_TABLE_LOG_SIZE);
429462306a36Sopenharmony_ci	if (unlikely(rc)) {
429562306a36Sopenharmony_ci		dev_err(dev, "Cannot init indirect table\n");
429662306a36Sopenharmony_ci		goto err_rss_init;
429762306a36Sopenharmony_ci	}
429862306a36Sopenharmony_ci
429962306a36Sopenharmony_ci	for (i = 0; i < ENA_RX_RSS_TABLE_SIZE; i++) {
430062306a36Sopenharmony_ci		val = ethtool_rxfh_indir_default(i, adapter->num_io_queues);
430162306a36Sopenharmony_ci		rc = ena_com_indirect_table_fill_entry(ena_dev, i,
430262306a36Sopenharmony_ci						       ENA_IO_RXQ_IDX(val));
430362306a36Sopenharmony_ci		if (unlikely(rc)) {
430462306a36Sopenharmony_ci			dev_err(dev, "Cannot fill indirect table\n");
430562306a36Sopenharmony_ci			goto err_fill_indir;
430662306a36Sopenharmony_ci		}
430762306a36Sopenharmony_ci	}
430862306a36Sopenharmony_ci
430962306a36Sopenharmony_ci	rc = ena_com_fill_hash_function(ena_dev, ENA_ADMIN_TOEPLITZ, NULL,
431062306a36Sopenharmony_ci					ENA_HASH_KEY_SIZE, 0xFFFFFFFF);
431162306a36Sopenharmony_ci	if (unlikely(rc && (rc != -EOPNOTSUPP))) {
431262306a36Sopenharmony_ci		dev_err(dev, "Cannot fill hash function\n");
431362306a36Sopenharmony_ci		goto err_fill_indir;
431462306a36Sopenharmony_ci	}
431562306a36Sopenharmony_ci
431662306a36Sopenharmony_ci	rc = ena_com_set_default_hash_ctrl(ena_dev);
431762306a36Sopenharmony_ci	if (unlikely(rc && (rc != -EOPNOTSUPP))) {
431862306a36Sopenharmony_ci		dev_err(dev, "Cannot fill hash control\n");
431962306a36Sopenharmony_ci		goto err_fill_indir;
432062306a36Sopenharmony_ci	}
432162306a36Sopenharmony_ci
432262306a36Sopenharmony_ci	return 0;
432362306a36Sopenharmony_ci
432462306a36Sopenharmony_cierr_fill_indir:
432562306a36Sopenharmony_ci	ena_com_rss_destroy(ena_dev);
432662306a36Sopenharmony_cierr_rss_init:
432762306a36Sopenharmony_ci
432862306a36Sopenharmony_ci	return rc;
432962306a36Sopenharmony_ci}
433062306a36Sopenharmony_ci
433162306a36Sopenharmony_cistatic void ena_release_bars(struct ena_com_dev *ena_dev, struct pci_dev *pdev)
433262306a36Sopenharmony_ci{
433362306a36Sopenharmony_ci	int release_bars = pci_select_bars(pdev, IORESOURCE_MEM) & ENA_BAR_MASK;
433462306a36Sopenharmony_ci
433562306a36Sopenharmony_ci	pci_release_selected_regions(pdev, release_bars);
433662306a36Sopenharmony_ci}
433762306a36Sopenharmony_ci
433862306a36Sopenharmony_ci/* ena_probe - Device Initialization Routine
433962306a36Sopenharmony_ci * @pdev: PCI device information struct
434062306a36Sopenharmony_ci * @ent: entry in ena_pci_tbl
434162306a36Sopenharmony_ci *
434262306a36Sopenharmony_ci * Returns 0 on success, negative on failure
434362306a36Sopenharmony_ci *
434462306a36Sopenharmony_ci * ena_probe initializes an adapter identified by a pci_dev structure.
434562306a36Sopenharmony_ci * The OS initialization, configuring of the adapter private structure,
434662306a36Sopenharmony_ci * and a hardware reset occur.
434762306a36Sopenharmony_ci */
434862306a36Sopenharmony_cistatic int ena_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
434962306a36Sopenharmony_ci{
435062306a36Sopenharmony_ci	struct ena_com_dev_get_features_ctx get_feat_ctx;
435162306a36Sopenharmony_ci	struct ena_com_dev *ena_dev = NULL;
435262306a36Sopenharmony_ci	struct ena_adapter *adapter;
435362306a36Sopenharmony_ci	struct net_device *netdev;
435462306a36Sopenharmony_ci	static int adapters_found;
435562306a36Sopenharmony_ci	u32 max_num_io_queues;
435662306a36Sopenharmony_ci	bool wd_state;
435762306a36Sopenharmony_ci	int bars, rc;
435862306a36Sopenharmony_ci
435962306a36Sopenharmony_ci	dev_dbg(&pdev->dev, "%s\n", __func__);
436062306a36Sopenharmony_ci
436162306a36Sopenharmony_ci	rc = pci_enable_device_mem(pdev);
436262306a36Sopenharmony_ci	if (rc) {
436362306a36Sopenharmony_ci		dev_err(&pdev->dev, "pci_enable_device_mem() failed!\n");
436462306a36Sopenharmony_ci		return rc;
436562306a36Sopenharmony_ci	}
436662306a36Sopenharmony_ci
436762306a36Sopenharmony_ci	rc = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(ENA_MAX_PHYS_ADDR_SIZE_BITS));
436862306a36Sopenharmony_ci	if (rc) {
436962306a36Sopenharmony_ci		dev_err(&pdev->dev, "dma_set_mask_and_coherent failed %d\n", rc);
437062306a36Sopenharmony_ci		goto err_disable_device;
437162306a36Sopenharmony_ci	}
437262306a36Sopenharmony_ci
437362306a36Sopenharmony_ci	pci_set_master(pdev);
437462306a36Sopenharmony_ci
437562306a36Sopenharmony_ci	ena_dev = vzalloc(sizeof(*ena_dev));
437662306a36Sopenharmony_ci	if (!ena_dev) {
437762306a36Sopenharmony_ci		rc = -ENOMEM;
437862306a36Sopenharmony_ci		goto err_disable_device;
437962306a36Sopenharmony_ci	}
438062306a36Sopenharmony_ci
438162306a36Sopenharmony_ci	bars = pci_select_bars(pdev, IORESOURCE_MEM) & ENA_BAR_MASK;
438262306a36Sopenharmony_ci	rc = pci_request_selected_regions(pdev, bars, DRV_MODULE_NAME);
438362306a36Sopenharmony_ci	if (rc) {
438462306a36Sopenharmony_ci		dev_err(&pdev->dev, "pci_request_selected_regions failed %d\n",
438562306a36Sopenharmony_ci			rc);
438662306a36Sopenharmony_ci		goto err_free_ena_dev;
438762306a36Sopenharmony_ci	}
438862306a36Sopenharmony_ci
438962306a36Sopenharmony_ci	ena_dev->reg_bar = devm_ioremap(&pdev->dev,
439062306a36Sopenharmony_ci					pci_resource_start(pdev, ENA_REG_BAR),
439162306a36Sopenharmony_ci					pci_resource_len(pdev, ENA_REG_BAR));
439262306a36Sopenharmony_ci	if (!ena_dev->reg_bar) {
439362306a36Sopenharmony_ci		dev_err(&pdev->dev, "Failed to remap regs bar\n");
439462306a36Sopenharmony_ci		rc = -EFAULT;
439562306a36Sopenharmony_ci		goto err_free_region;
439662306a36Sopenharmony_ci	}
439762306a36Sopenharmony_ci
439862306a36Sopenharmony_ci	ena_dev->ena_min_poll_delay_us = ENA_ADMIN_POLL_DELAY_US;
439962306a36Sopenharmony_ci
440062306a36Sopenharmony_ci	ena_dev->dmadev = &pdev->dev;
440162306a36Sopenharmony_ci
440262306a36Sopenharmony_ci	netdev = alloc_etherdev_mq(sizeof(struct ena_adapter), ENA_MAX_RINGS);
440362306a36Sopenharmony_ci	if (!netdev) {
440462306a36Sopenharmony_ci		dev_err(&pdev->dev, "alloc_etherdev_mq failed\n");
440562306a36Sopenharmony_ci		rc = -ENOMEM;
440662306a36Sopenharmony_ci		goto err_free_region;
440762306a36Sopenharmony_ci	}
440862306a36Sopenharmony_ci
440962306a36Sopenharmony_ci	SET_NETDEV_DEV(netdev, &pdev->dev);
441062306a36Sopenharmony_ci	adapter = netdev_priv(netdev);
441162306a36Sopenharmony_ci	adapter->ena_dev = ena_dev;
441262306a36Sopenharmony_ci	adapter->netdev = netdev;
441362306a36Sopenharmony_ci	adapter->pdev = pdev;
441462306a36Sopenharmony_ci	adapter->msg_enable = DEFAULT_MSG_ENABLE;
441562306a36Sopenharmony_ci
441662306a36Sopenharmony_ci	ena_dev->net_device = netdev;
441762306a36Sopenharmony_ci
441862306a36Sopenharmony_ci	pci_set_drvdata(pdev, adapter);
441962306a36Sopenharmony_ci
442062306a36Sopenharmony_ci	rc = ena_map_llq_mem_bar(pdev, ena_dev, bars);
442162306a36Sopenharmony_ci	if (rc) {
442262306a36Sopenharmony_ci		dev_err(&pdev->dev, "ENA LLQ bar mapping failed\n");
442362306a36Sopenharmony_ci		goto err_netdev_destroy;
442462306a36Sopenharmony_ci	}
442562306a36Sopenharmony_ci
442662306a36Sopenharmony_ci	rc = ena_device_init(adapter, pdev, &get_feat_ctx, &wd_state);
442762306a36Sopenharmony_ci	if (rc) {
442862306a36Sopenharmony_ci		dev_err(&pdev->dev, "ENA device init failed\n");
442962306a36Sopenharmony_ci		if (rc == -ETIME)
443062306a36Sopenharmony_ci			rc = -EPROBE_DEFER;
443162306a36Sopenharmony_ci		goto err_netdev_destroy;
443262306a36Sopenharmony_ci	}
443362306a36Sopenharmony_ci
443462306a36Sopenharmony_ci	/* Initial TX and RX interrupt delay. Assumes 1 usec granularity.
443562306a36Sopenharmony_ci	 * Updated during device initialization with the real granularity
443662306a36Sopenharmony_ci	 */
443762306a36Sopenharmony_ci	ena_dev->intr_moder_tx_interval = ENA_INTR_INITIAL_TX_INTERVAL_USECS;
443862306a36Sopenharmony_ci	ena_dev->intr_moder_rx_interval = ENA_INTR_INITIAL_RX_INTERVAL_USECS;
443962306a36Sopenharmony_ci	ena_dev->intr_delay_resolution = ENA_DEFAULT_INTR_DELAY_RESOLUTION;
444062306a36Sopenharmony_ci	max_num_io_queues = ena_calc_max_io_queue_num(pdev, ena_dev, &get_feat_ctx);
444162306a36Sopenharmony_ci	if (unlikely(!max_num_io_queues)) {
444262306a36Sopenharmony_ci		rc = -EFAULT;
444362306a36Sopenharmony_ci		goto err_device_destroy;
444462306a36Sopenharmony_ci	}
444562306a36Sopenharmony_ci
444662306a36Sopenharmony_ci	ena_set_conf_feat_params(adapter, &get_feat_ctx);
444762306a36Sopenharmony_ci
444862306a36Sopenharmony_ci	adapter->reset_reason = ENA_REGS_RESET_NORMAL;
444962306a36Sopenharmony_ci
445062306a36Sopenharmony_ci	adapter->num_io_queues = max_num_io_queues;
445162306a36Sopenharmony_ci	adapter->max_num_io_queues = max_num_io_queues;
445262306a36Sopenharmony_ci	adapter->last_monitored_tx_qid = 0;
445362306a36Sopenharmony_ci
445462306a36Sopenharmony_ci	adapter->xdp_first_ring = 0;
445562306a36Sopenharmony_ci	adapter->xdp_num_queues = 0;
445662306a36Sopenharmony_ci
445762306a36Sopenharmony_ci	adapter->rx_copybreak = ENA_DEFAULT_RX_COPYBREAK;
445862306a36Sopenharmony_ci	if (ena_dev->tx_mem_queue_type == ENA_ADMIN_PLACEMENT_POLICY_DEV)
445962306a36Sopenharmony_ci		adapter->disable_meta_caching =
446062306a36Sopenharmony_ci			!!(get_feat_ctx.llq.accel_mode.u.get.supported_flags &
446162306a36Sopenharmony_ci			   BIT(ENA_ADMIN_DISABLE_META_CACHING));
446262306a36Sopenharmony_ci
446362306a36Sopenharmony_ci	adapter->wd_state = wd_state;
446462306a36Sopenharmony_ci
446562306a36Sopenharmony_ci	snprintf(adapter->name, ENA_NAME_MAX_LEN, "ena_%d", adapters_found);
446662306a36Sopenharmony_ci
446762306a36Sopenharmony_ci	rc = ena_com_init_interrupt_moderation(adapter->ena_dev);
446862306a36Sopenharmony_ci	if (rc) {
446962306a36Sopenharmony_ci		dev_err(&pdev->dev,
447062306a36Sopenharmony_ci			"Failed to query interrupt moderation feature\n");
447162306a36Sopenharmony_ci		goto err_device_destroy;
447262306a36Sopenharmony_ci	}
447362306a36Sopenharmony_ci
447462306a36Sopenharmony_ci	ena_init_io_rings(adapter,
447562306a36Sopenharmony_ci			  0,
447662306a36Sopenharmony_ci			  adapter->xdp_num_queues +
447762306a36Sopenharmony_ci			  adapter->num_io_queues);
447862306a36Sopenharmony_ci
447962306a36Sopenharmony_ci	netdev->netdev_ops = &ena_netdev_ops;
448062306a36Sopenharmony_ci	netdev->watchdog_timeo = TX_TIMEOUT;
448162306a36Sopenharmony_ci	ena_set_ethtool_ops(netdev);
448262306a36Sopenharmony_ci
448362306a36Sopenharmony_ci	netdev->priv_flags |= IFF_UNICAST_FLT;
448462306a36Sopenharmony_ci
448562306a36Sopenharmony_ci	u64_stats_init(&adapter->syncp);
448662306a36Sopenharmony_ci
448762306a36Sopenharmony_ci	rc = ena_enable_msix_and_set_admin_interrupts(adapter);
448862306a36Sopenharmony_ci	if (rc) {
448962306a36Sopenharmony_ci		dev_err(&pdev->dev,
449062306a36Sopenharmony_ci			"Failed to enable and set the admin interrupts\n");
449162306a36Sopenharmony_ci		goto err_worker_destroy;
449262306a36Sopenharmony_ci	}
449362306a36Sopenharmony_ci	rc = ena_rss_init_default(adapter);
449462306a36Sopenharmony_ci	if (rc && (rc != -EOPNOTSUPP)) {
449562306a36Sopenharmony_ci		dev_err(&pdev->dev, "Cannot init RSS rc: %d\n", rc);
449662306a36Sopenharmony_ci		goto err_free_msix;
449762306a36Sopenharmony_ci	}
449862306a36Sopenharmony_ci
449962306a36Sopenharmony_ci	ena_config_debug_area(adapter);
450062306a36Sopenharmony_ci
450162306a36Sopenharmony_ci	if (ena_xdp_legal_queue_count(adapter, adapter->num_io_queues))
450262306a36Sopenharmony_ci		netdev->xdp_features = NETDEV_XDP_ACT_BASIC |
450362306a36Sopenharmony_ci				       NETDEV_XDP_ACT_REDIRECT;
450462306a36Sopenharmony_ci
450562306a36Sopenharmony_ci	memcpy(adapter->netdev->perm_addr, adapter->mac_addr, netdev->addr_len);
450662306a36Sopenharmony_ci
450762306a36Sopenharmony_ci	netif_carrier_off(netdev);
450862306a36Sopenharmony_ci
450962306a36Sopenharmony_ci	rc = register_netdev(netdev);
451062306a36Sopenharmony_ci	if (rc) {
451162306a36Sopenharmony_ci		dev_err(&pdev->dev, "Cannot register net device\n");
451262306a36Sopenharmony_ci		goto err_rss;
451362306a36Sopenharmony_ci	}
451462306a36Sopenharmony_ci
451562306a36Sopenharmony_ci	INIT_WORK(&adapter->reset_task, ena_fw_reset_device);
451662306a36Sopenharmony_ci
451762306a36Sopenharmony_ci	adapter->last_keep_alive_jiffies = jiffies;
451862306a36Sopenharmony_ci	adapter->keep_alive_timeout = ENA_DEVICE_KALIVE_TIMEOUT;
451962306a36Sopenharmony_ci	adapter->missing_tx_completion_to = TX_TIMEOUT;
452062306a36Sopenharmony_ci	adapter->missing_tx_completion_threshold = MAX_NUM_OF_TIMEOUTED_PACKETS;
452162306a36Sopenharmony_ci
452262306a36Sopenharmony_ci	ena_update_hints(adapter, &get_feat_ctx.hw_hints);
452362306a36Sopenharmony_ci
452462306a36Sopenharmony_ci	timer_setup(&adapter->timer_service, ena_timer_service, 0);
452562306a36Sopenharmony_ci	mod_timer(&adapter->timer_service, round_jiffies(jiffies + HZ));
452662306a36Sopenharmony_ci
452762306a36Sopenharmony_ci	dev_info(&pdev->dev,
452862306a36Sopenharmony_ci		 "%s found at mem %lx, mac addr %pM\n",
452962306a36Sopenharmony_ci		 DEVICE_NAME, (long)pci_resource_start(pdev, 0),
453062306a36Sopenharmony_ci		 netdev->dev_addr);
453162306a36Sopenharmony_ci
453262306a36Sopenharmony_ci	set_bit(ENA_FLAG_DEVICE_RUNNING, &adapter->flags);
453362306a36Sopenharmony_ci
453462306a36Sopenharmony_ci	adapters_found++;
453562306a36Sopenharmony_ci
453662306a36Sopenharmony_ci	return 0;
453762306a36Sopenharmony_ci
453862306a36Sopenharmony_cierr_rss:
453962306a36Sopenharmony_ci	ena_com_delete_debug_area(ena_dev);
454062306a36Sopenharmony_ci	ena_com_rss_destroy(ena_dev);
454162306a36Sopenharmony_cierr_free_msix:
454262306a36Sopenharmony_ci	ena_com_dev_reset(ena_dev, ENA_REGS_RESET_INIT_ERR);
454362306a36Sopenharmony_ci	/* stop submitting admin commands on a device that was reset */
454462306a36Sopenharmony_ci	ena_com_set_admin_running_state(ena_dev, false);
454562306a36Sopenharmony_ci	ena_free_mgmnt_irq(adapter);
454662306a36Sopenharmony_ci	ena_disable_msix(adapter);
454762306a36Sopenharmony_cierr_worker_destroy:
454862306a36Sopenharmony_ci	del_timer(&adapter->timer_service);
454962306a36Sopenharmony_cierr_device_destroy:
455062306a36Sopenharmony_ci	ena_com_delete_host_info(ena_dev);
455162306a36Sopenharmony_ci	ena_com_admin_destroy(ena_dev);
455262306a36Sopenharmony_cierr_netdev_destroy:
455362306a36Sopenharmony_ci	free_netdev(netdev);
455462306a36Sopenharmony_cierr_free_region:
455562306a36Sopenharmony_ci	ena_release_bars(ena_dev, pdev);
455662306a36Sopenharmony_cierr_free_ena_dev:
455762306a36Sopenharmony_ci	vfree(ena_dev);
455862306a36Sopenharmony_cierr_disable_device:
455962306a36Sopenharmony_ci	pci_disable_device(pdev);
456062306a36Sopenharmony_ci	return rc;
456162306a36Sopenharmony_ci}
456262306a36Sopenharmony_ci
456362306a36Sopenharmony_ci/*****************************************************************************/
456462306a36Sopenharmony_ci
456562306a36Sopenharmony_ci/* __ena_shutoff - Helper used in both PCI remove/shutdown routines
456662306a36Sopenharmony_ci * @pdev: PCI device information struct
456762306a36Sopenharmony_ci * @shutdown: Is it a shutdown operation? If false, means it is a removal
456862306a36Sopenharmony_ci *
456962306a36Sopenharmony_ci * __ena_shutoff is a helper routine that does the real work on shutdown and
457062306a36Sopenharmony_ci * removal paths; the difference between those paths is with regards to whether
457162306a36Sopenharmony_ci * dettach or unregister the netdevice.
457262306a36Sopenharmony_ci */
457362306a36Sopenharmony_cistatic void __ena_shutoff(struct pci_dev *pdev, bool shutdown)
457462306a36Sopenharmony_ci{
457562306a36Sopenharmony_ci	struct ena_adapter *adapter = pci_get_drvdata(pdev);
457662306a36Sopenharmony_ci	struct ena_com_dev *ena_dev;
457762306a36Sopenharmony_ci	struct net_device *netdev;
457862306a36Sopenharmony_ci
457962306a36Sopenharmony_ci	ena_dev = adapter->ena_dev;
458062306a36Sopenharmony_ci	netdev = adapter->netdev;
458162306a36Sopenharmony_ci
458262306a36Sopenharmony_ci#ifdef CONFIG_RFS_ACCEL
458362306a36Sopenharmony_ci	if ((adapter->msix_vecs >= 1) && (netdev->rx_cpu_rmap)) {
458462306a36Sopenharmony_ci		free_irq_cpu_rmap(netdev->rx_cpu_rmap);
458562306a36Sopenharmony_ci		netdev->rx_cpu_rmap = NULL;
458662306a36Sopenharmony_ci	}
458762306a36Sopenharmony_ci#endif /* CONFIG_RFS_ACCEL */
458862306a36Sopenharmony_ci
458962306a36Sopenharmony_ci	/* Make sure timer and reset routine won't be called after
459062306a36Sopenharmony_ci	 * freeing device resources.
459162306a36Sopenharmony_ci	 */
459262306a36Sopenharmony_ci	del_timer_sync(&adapter->timer_service);
459362306a36Sopenharmony_ci	cancel_work_sync(&adapter->reset_task);
459462306a36Sopenharmony_ci
459562306a36Sopenharmony_ci	rtnl_lock(); /* lock released inside the below if-else block */
459662306a36Sopenharmony_ci	adapter->reset_reason = ENA_REGS_RESET_SHUTDOWN;
459762306a36Sopenharmony_ci	ena_destroy_device(adapter, true);
459862306a36Sopenharmony_ci
459962306a36Sopenharmony_ci	if (shutdown) {
460062306a36Sopenharmony_ci		netif_device_detach(netdev);
460162306a36Sopenharmony_ci		dev_close(netdev);
460262306a36Sopenharmony_ci		rtnl_unlock();
460362306a36Sopenharmony_ci	} else {
460462306a36Sopenharmony_ci		rtnl_unlock();
460562306a36Sopenharmony_ci		unregister_netdev(netdev);
460662306a36Sopenharmony_ci		free_netdev(netdev);
460762306a36Sopenharmony_ci	}
460862306a36Sopenharmony_ci
460962306a36Sopenharmony_ci	ena_com_rss_destroy(ena_dev);
461062306a36Sopenharmony_ci
461162306a36Sopenharmony_ci	ena_com_delete_debug_area(ena_dev);
461262306a36Sopenharmony_ci
461362306a36Sopenharmony_ci	ena_com_delete_host_info(ena_dev);
461462306a36Sopenharmony_ci
461562306a36Sopenharmony_ci	ena_release_bars(ena_dev, pdev);
461662306a36Sopenharmony_ci
461762306a36Sopenharmony_ci	pci_disable_device(pdev);
461862306a36Sopenharmony_ci
461962306a36Sopenharmony_ci	vfree(ena_dev);
462062306a36Sopenharmony_ci}
462162306a36Sopenharmony_ci
462262306a36Sopenharmony_ci/* ena_remove - Device Removal Routine
462362306a36Sopenharmony_ci * @pdev: PCI device information struct
462462306a36Sopenharmony_ci *
462562306a36Sopenharmony_ci * ena_remove is called by the PCI subsystem to alert the driver
462662306a36Sopenharmony_ci * that it should release a PCI device.
462762306a36Sopenharmony_ci */
462862306a36Sopenharmony_ci
462962306a36Sopenharmony_cistatic void ena_remove(struct pci_dev *pdev)
463062306a36Sopenharmony_ci{
463162306a36Sopenharmony_ci	__ena_shutoff(pdev, false);
463262306a36Sopenharmony_ci}
463362306a36Sopenharmony_ci
463462306a36Sopenharmony_ci/* ena_shutdown - Device Shutdown Routine
463562306a36Sopenharmony_ci * @pdev: PCI device information struct
463662306a36Sopenharmony_ci *
463762306a36Sopenharmony_ci * ena_shutdown is called by the PCI subsystem to alert the driver that
463862306a36Sopenharmony_ci * a shutdown/reboot (or kexec) is happening and device must be disabled.
463962306a36Sopenharmony_ci */
464062306a36Sopenharmony_ci
464162306a36Sopenharmony_cistatic void ena_shutdown(struct pci_dev *pdev)
464262306a36Sopenharmony_ci{
464362306a36Sopenharmony_ci	__ena_shutoff(pdev, true);
464462306a36Sopenharmony_ci}
464562306a36Sopenharmony_ci
464662306a36Sopenharmony_ci/* ena_suspend - PM suspend callback
464762306a36Sopenharmony_ci * @dev_d: Device information struct
464862306a36Sopenharmony_ci */
464962306a36Sopenharmony_cistatic int __maybe_unused ena_suspend(struct device *dev_d)
465062306a36Sopenharmony_ci{
465162306a36Sopenharmony_ci	struct pci_dev *pdev = to_pci_dev(dev_d);
465262306a36Sopenharmony_ci	struct ena_adapter *adapter = pci_get_drvdata(pdev);
465362306a36Sopenharmony_ci
465462306a36Sopenharmony_ci	ena_increase_stat(&adapter->dev_stats.suspend, 1, &adapter->syncp);
465562306a36Sopenharmony_ci
465662306a36Sopenharmony_ci	rtnl_lock();
465762306a36Sopenharmony_ci	if (unlikely(test_bit(ENA_FLAG_TRIGGER_RESET, &adapter->flags))) {
465862306a36Sopenharmony_ci		dev_err(&pdev->dev,
465962306a36Sopenharmony_ci			"Ignoring device reset request as the device is being suspended\n");
466062306a36Sopenharmony_ci		clear_bit(ENA_FLAG_TRIGGER_RESET, &adapter->flags);
466162306a36Sopenharmony_ci	}
466262306a36Sopenharmony_ci	ena_destroy_device(adapter, true);
466362306a36Sopenharmony_ci	rtnl_unlock();
466462306a36Sopenharmony_ci	return 0;
466562306a36Sopenharmony_ci}
466662306a36Sopenharmony_ci
466762306a36Sopenharmony_ci/* ena_resume - PM resume callback
466862306a36Sopenharmony_ci * @dev_d: Device information struct
466962306a36Sopenharmony_ci */
467062306a36Sopenharmony_cistatic int __maybe_unused ena_resume(struct device *dev_d)
467162306a36Sopenharmony_ci{
467262306a36Sopenharmony_ci	struct ena_adapter *adapter = dev_get_drvdata(dev_d);
467362306a36Sopenharmony_ci	int rc;
467462306a36Sopenharmony_ci
467562306a36Sopenharmony_ci	ena_increase_stat(&adapter->dev_stats.resume, 1, &adapter->syncp);
467662306a36Sopenharmony_ci
467762306a36Sopenharmony_ci	rtnl_lock();
467862306a36Sopenharmony_ci	rc = ena_restore_device(adapter);
467962306a36Sopenharmony_ci	rtnl_unlock();
468062306a36Sopenharmony_ci	return rc;
468162306a36Sopenharmony_ci}
468262306a36Sopenharmony_ci
468362306a36Sopenharmony_cistatic SIMPLE_DEV_PM_OPS(ena_pm_ops, ena_suspend, ena_resume);
468462306a36Sopenharmony_ci
468562306a36Sopenharmony_cistatic struct pci_driver ena_pci_driver = {
468662306a36Sopenharmony_ci	.name		= DRV_MODULE_NAME,
468762306a36Sopenharmony_ci	.id_table	= ena_pci_tbl,
468862306a36Sopenharmony_ci	.probe		= ena_probe,
468962306a36Sopenharmony_ci	.remove		= ena_remove,
469062306a36Sopenharmony_ci	.shutdown	= ena_shutdown,
469162306a36Sopenharmony_ci	.driver.pm	= &ena_pm_ops,
469262306a36Sopenharmony_ci	.sriov_configure = pci_sriov_configure_simple,
469362306a36Sopenharmony_ci};
469462306a36Sopenharmony_ci
469562306a36Sopenharmony_cistatic int __init ena_init(void)
469662306a36Sopenharmony_ci{
469762306a36Sopenharmony_ci	int ret;
469862306a36Sopenharmony_ci
469962306a36Sopenharmony_ci	ena_wq = create_singlethread_workqueue(DRV_MODULE_NAME);
470062306a36Sopenharmony_ci	if (!ena_wq) {
470162306a36Sopenharmony_ci		pr_err("Failed to create workqueue\n");
470262306a36Sopenharmony_ci		return -ENOMEM;
470362306a36Sopenharmony_ci	}
470462306a36Sopenharmony_ci
470562306a36Sopenharmony_ci	ret = pci_register_driver(&ena_pci_driver);
470662306a36Sopenharmony_ci	if (ret)
470762306a36Sopenharmony_ci		destroy_workqueue(ena_wq);
470862306a36Sopenharmony_ci
470962306a36Sopenharmony_ci	return ret;
471062306a36Sopenharmony_ci}
471162306a36Sopenharmony_ci
471262306a36Sopenharmony_cistatic void __exit ena_cleanup(void)
471362306a36Sopenharmony_ci{
471462306a36Sopenharmony_ci	pci_unregister_driver(&ena_pci_driver);
471562306a36Sopenharmony_ci
471662306a36Sopenharmony_ci	if (ena_wq) {
471762306a36Sopenharmony_ci		destroy_workqueue(ena_wq);
471862306a36Sopenharmony_ci		ena_wq = NULL;
471962306a36Sopenharmony_ci	}
472062306a36Sopenharmony_ci}
472162306a36Sopenharmony_ci
472262306a36Sopenharmony_ci/******************************************************************************
472362306a36Sopenharmony_ci ******************************** AENQ Handlers *******************************
472462306a36Sopenharmony_ci *****************************************************************************/
472562306a36Sopenharmony_ci/* ena_update_on_link_change:
472662306a36Sopenharmony_ci * Notify the network interface about the change in link status
472762306a36Sopenharmony_ci */
472862306a36Sopenharmony_cistatic void ena_update_on_link_change(void *adapter_data,
472962306a36Sopenharmony_ci				      struct ena_admin_aenq_entry *aenq_e)
473062306a36Sopenharmony_ci{
473162306a36Sopenharmony_ci	struct ena_adapter *adapter = (struct ena_adapter *)adapter_data;
473262306a36Sopenharmony_ci	struct ena_admin_aenq_link_change_desc *aenq_desc =
473362306a36Sopenharmony_ci		(struct ena_admin_aenq_link_change_desc *)aenq_e;
473462306a36Sopenharmony_ci	int status = aenq_desc->flags &
473562306a36Sopenharmony_ci		ENA_ADMIN_AENQ_LINK_CHANGE_DESC_LINK_STATUS_MASK;
473662306a36Sopenharmony_ci
473762306a36Sopenharmony_ci	if (status) {
473862306a36Sopenharmony_ci		netif_dbg(adapter, ifup, adapter->netdev, "%s\n", __func__);
473962306a36Sopenharmony_ci		set_bit(ENA_FLAG_LINK_UP, &adapter->flags);
474062306a36Sopenharmony_ci		if (!test_bit(ENA_FLAG_ONGOING_RESET, &adapter->flags))
474162306a36Sopenharmony_ci			netif_carrier_on(adapter->netdev);
474262306a36Sopenharmony_ci	} else {
474362306a36Sopenharmony_ci		clear_bit(ENA_FLAG_LINK_UP, &adapter->flags);
474462306a36Sopenharmony_ci		netif_carrier_off(adapter->netdev);
474562306a36Sopenharmony_ci	}
474662306a36Sopenharmony_ci}
474762306a36Sopenharmony_ci
474862306a36Sopenharmony_cistatic void ena_keep_alive_wd(void *adapter_data,
474962306a36Sopenharmony_ci			      struct ena_admin_aenq_entry *aenq_e)
475062306a36Sopenharmony_ci{
475162306a36Sopenharmony_ci	struct ena_adapter *adapter = (struct ena_adapter *)adapter_data;
475262306a36Sopenharmony_ci	struct ena_admin_aenq_keep_alive_desc *desc;
475362306a36Sopenharmony_ci	u64 rx_drops;
475462306a36Sopenharmony_ci	u64 tx_drops;
475562306a36Sopenharmony_ci
475662306a36Sopenharmony_ci	desc = (struct ena_admin_aenq_keep_alive_desc *)aenq_e;
475762306a36Sopenharmony_ci	adapter->last_keep_alive_jiffies = jiffies;
475862306a36Sopenharmony_ci
475962306a36Sopenharmony_ci	rx_drops = ((u64)desc->rx_drops_high << 32) | desc->rx_drops_low;
476062306a36Sopenharmony_ci	tx_drops = ((u64)desc->tx_drops_high << 32) | desc->tx_drops_low;
476162306a36Sopenharmony_ci
476262306a36Sopenharmony_ci	u64_stats_update_begin(&adapter->syncp);
476362306a36Sopenharmony_ci	/* These stats are accumulated by the device, so the counters indicate
476462306a36Sopenharmony_ci	 * all drops since last reset.
476562306a36Sopenharmony_ci	 */
476662306a36Sopenharmony_ci	adapter->dev_stats.rx_drops = rx_drops;
476762306a36Sopenharmony_ci	adapter->dev_stats.tx_drops = tx_drops;
476862306a36Sopenharmony_ci	u64_stats_update_end(&adapter->syncp);
476962306a36Sopenharmony_ci}
477062306a36Sopenharmony_ci
477162306a36Sopenharmony_cistatic void ena_notification(void *adapter_data,
477262306a36Sopenharmony_ci			     struct ena_admin_aenq_entry *aenq_e)
477362306a36Sopenharmony_ci{
477462306a36Sopenharmony_ci	struct ena_adapter *adapter = (struct ena_adapter *)adapter_data;
477562306a36Sopenharmony_ci	struct ena_admin_ena_hw_hints *hints;
477662306a36Sopenharmony_ci
477762306a36Sopenharmony_ci	WARN(aenq_e->aenq_common_desc.group != ENA_ADMIN_NOTIFICATION,
477862306a36Sopenharmony_ci	     "Invalid group(%x) expected %x\n",
477962306a36Sopenharmony_ci	     aenq_e->aenq_common_desc.group,
478062306a36Sopenharmony_ci	     ENA_ADMIN_NOTIFICATION);
478162306a36Sopenharmony_ci
478262306a36Sopenharmony_ci	switch (aenq_e->aenq_common_desc.syndrome) {
478362306a36Sopenharmony_ci	case ENA_ADMIN_UPDATE_HINTS:
478462306a36Sopenharmony_ci		hints = (struct ena_admin_ena_hw_hints *)
478562306a36Sopenharmony_ci			(&aenq_e->inline_data_w4);
478662306a36Sopenharmony_ci		ena_update_hints(adapter, hints);
478762306a36Sopenharmony_ci		break;
478862306a36Sopenharmony_ci	default:
478962306a36Sopenharmony_ci		netif_err(adapter, drv, adapter->netdev,
479062306a36Sopenharmony_ci			  "Invalid aenq notification link state %d\n",
479162306a36Sopenharmony_ci			  aenq_e->aenq_common_desc.syndrome);
479262306a36Sopenharmony_ci	}
479362306a36Sopenharmony_ci}
479462306a36Sopenharmony_ci
479562306a36Sopenharmony_ci/* This handler will called for unknown event group or unimplemented handlers*/
479662306a36Sopenharmony_cistatic void unimplemented_aenq_handler(void *data,
479762306a36Sopenharmony_ci				       struct ena_admin_aenq_entry *aenq_e)
479862306a36Sopenharmony_ci{
479962306a36Sopenharmony_ci	struct ena_adapter *adapter = (struct ena_adapter *)data;
480062306a36Sopenharmony_ci
480162306a36Sopenharmony_ci	netif_err(adapter, drv, adapter->netdev,
480262306a36Sopenharmony_ci		  "Unknown event was received or event with unimplemented handler\n");
480362306a36Sopenharmony_ci}
480462306a36Sopenharmony_ci
480562306a36Sopenharmony_cistatic struct ena_aenq_handlers aenq_handlers = {
480662306a36Sopenharmony_ci	.handlers = {
480762306a36Sopenharmony_ci		[ENA_ADMIN_LINK_CHANGE] = ena_update_on_link_change,
480862306a36Sopenharmony_ci		[ENA_ADMIN_NOTIFICATION] = ena_notification,
480962306a36Sopenharmony_ci		[ENA_ADMIN_KEEP_ALIVE] = ena_keep_alive_wd,
481062306a36Sopenharmony_ci	},
481162306a36Sopenharmony_ci	.unimplemented_handler = unimplemented_aenq_handler
481262306a36Sopenharmony_ci};
481362306a36Sopenharmony_ci
481462306a36Sopenharmony_cimodule_init(ena_init);
481562306a36Sopenharmony_cimodule_exit(ena_cleanup);
4816