Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 


Quelle  ena_netdev.c   Sprache: C

 
// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
/*
 * Copyright 2015-2020 Amazon.com, Inc. or its affiliates. All rights reserved.
 */


#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt

#include <linux/ethtool.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/numa.h>
#include <linux/pci.h>
#include <linux/utsname.h>
#include <linux/version.h>
#include <linux/vmalloc.h>
#include <net/ip.h>

#include "ena_netdev.h"
#include "ena_pci_id_tbl.h"
#include "ena_xdp.h"

#include "ena_phc.h"

#include "ena_devlink.h"

#include "ena_debugfs.h"

MODULE_AUTHOR("Amazon.com, Inc. or its affiliates");
MODULE_DESCRIPTION(DEVICE_NAME);
MODULE_LICENSE("GPL");

/* Time in jiffies before concluding the transmitter is hung. */
#define TX_TIMEOUT  (5 * HZ)

#define ENA_MAX_RINGS min_t(unsigned int, ENA_MAX_NUM_IO_QUEUES, num_possible_cpus())

#define DEFAULT_MSG_ENABLE (NETIF_MSG_DRV | NETIF_MSG_PROBE | NETIF_MSG_IFUP | \
  NETIF_MSG_IFDOWN | NETIF_MSG_TX_ERR | NETIF_MSG_RX_ERR)

static struct ena_aenq_handlers aenq_handlers;

static struct workqueue_struct *ena_wq;

MODULE_DEVICE_TABLE(pci, ena_pci_tbl);

static int ena_rss_init_default(struct ena_adapter *adapter);
static void check_for_admin_com_state(struct ena_adapter *adapter);

static void ena_tx_timeout(struct net_device *dev, unsigned int txqueue)
{
 enum ena_regs_reset_reason_types reset_reason = ENA_REGS_RESET_OS_NETDEV_WD;
 struct ena_adapter *adapter = netdev_priv(dev);
 unsigned int time_since_last_napi, threshold;
 struct ena_ring *tx_ring;
 int napi_scheduled;

 if (txqueue >= adapter->num_io_queues) {
  netdev_err(dev, "TX timeout on invalid queue %u\n", txqueue);
  goto schedule_reset;
 }

 threshold = jiffies_to_usecs(dev->watchdog_timeo);
 tx_ring = &adapter->tx_ring[txqueue];

 time_since_last_napi = jiffies_to_usecs(jiffies - tx_ring->tx_stats.last_napi_jiffies);
 napi_scheduled = !!(tx_ring->napi->state & NAPIF_STATE_SCHED);

 netdev_err(dev,
     "TX q %d is paused for too long (threshold %u). Time since last napi %u usec. napi scheduled: %d\n",
     txqueue,
     threshold,
     time_since_last_napi,
     napi_scheduled);

 if (threshold < time_since_last_napi && napi_scheduled) {
  netdev_err(dev,
      "napi handler hasn't been called for a long time but is scheduled\n");
  reset_reason = ENA_REGS_RESET_SUSPECTED_POLL_STARVATION;
 }
schedule_reset:
 /* Change the state of the device to trigger reset
 * Check that we are not in the middle or a trigger already
 */

 if (test_and_set_bit(ENA_FLAG_TRIGGER_RESET, &adapter->flags))
  return;

 ena_reset_device(adapter, reset_reason);
 ena_increase_stat(&adapter->dev_stats.tx_timeout, 1, &adapter->syncp);
}

static void update_rx_ring_mtu(struct ena_adapter *adapter, int mtu)
{
 int i;

 for (i = 0; i < adapter->num_io_queues; i++)
  adapter->rx_ring[i].mtu = mtu;
}

static int ena_change_mtu(struct net_device *dev, int new_mtu)
{
 struct ena_adapter *adapter = netdev_priv(dev);
 int ret;

 ret = ena_com_set_dev_mtu(adapter->ena_dev, new_mtu);
 if (!ret) {
  netif_dbg(adapter, drv, dev, "Set MTU to %d\n", new_mtu);
  update_rx_ring_mtu(adapter, new_mtu);
  WRITE_ONCE(dev->mtu, new_mtu);
 } else {
  netif_err(adapter, drv, dev, "Failed to set MTU to %d\n",
     new_mtu);
 }

 return ret;
}

int ena_xmit_common(struct ena_adapter *adapter,
      struct ena_ring *ring,
      struct ena_tx_buffer *tx_info,
      struct ena_com_tx_ctx *ena_tx_ctx,
      u16 next_to_use,
      u32 bytes)
{
 int rc, nb_hw_desc;

 if (unlikely(ena_com_is_doorbell_needed(ring->ena_com_io_sq,
      ena_tx_ctx))) {
  netif_dbg(adapter, tx_queued, adapter->netdev,
     "llq tx max burst size of queue %d achieved, writing doorbell to send burst\n",
     ring->qid);
  ena_ring_tx_doorbell(ring);
 }

 /* prepare the packet's descriptors to dma engine */
 rc = ena_com_prepare_tx(ring->ena_com_io_sq, ena_tx_ctx,
    &nb_hw_desc);

 /* In case there isn't enough space in the queue for the packet,
 * we simply drop it. All other failure reasons of
 * ena_com_prepare_tx() are fatal and therefore require a device reset.
 */

 if (unlikely(rc)) {
  netif_err(adapter, tx_queued, adapter->netdev,
     "Failed to prepare tx bufs\n");
  ena_increase_stat(&ring->tx_stats.prepare_ctx_err, 1, &ring->syncp);
  if (rc != -ENOMEM)
   ena_reset_device(adapter, ENA_REGS_RESET_DRIVER_INVALID_STATE);
  return rc;
 }

 u64_stats_update_begin(&ring->syncp);
 ring->tx_stats.cnt++;
 ring->tx_stats.bytes += bytes;
 u64_stats_update_end(&ring->syncp);

 tx_info->tx_descs = nb_hw_desc;
 tx_info->total_tx_size = bytes;
 tx_info->last_jiffies = jiffies;
 tx_info->print_once = 0;

 ring->next_to_use = ENA_TX_RING_IDX_NEXT(next_to_use,
       ring->ring_size);
 return 0;
}

static void ena_init_io_rings_common(struct ena_adapter *adapter,
         struct ena_ring *ring, u16 qid)
{
 ring->qid = qid;
 ring->pdev = adapter->pdev;
 ring->dev = &adapter->pdev->dev;
 ring->netdev = adapter->netdev;
 ring->napi = &adapter->ena_napi[qid].napi;
 ring->adapter = adapter;
 ring->ena_dev = adapter->ena_dev;
 ring->per_napi_packets = 0;
 ring->cpu = 0;
 ring->numa_node = 0;
 ring->no_interrupt_event_cnt = 0;
 u64_stats_init(&ring->syncp);
}

void ena_init_io_rings(struct ena_adapter *adapter,
         int first_index, int count)
{
 struct ena_com_dev *ena_dev;
 struct ena_ring *txr, *rxr;
 int i;

 ena_dev = adapter->ena_dev;

 for (i = first_index; i < first_index + count; i++) {
  txr = &adapter->tx_ring[i];
  rxr = &adapter->rx_ring[i];

  /* TX common ring state */
  ena_init_io_rings_common(adapter, txr, i);

  /* TX specific ring state */
  txr->ring_size = adapter->requested_tx_ring_size;
  txr->tx_max_header_size = ena_dev->tx_max_header_size;
  txr->tx_mem_queue_type = ena_dev->tx_mem_queue_type;
  txr->sgl_size = adapter->max_tx_sgl_size;
  txr->smoothed_interval =
   ena_com_get_nonadaptive_moderation_interval_tx(ena_dev);
  txr->disable_meta_caching = adapter->disable_meta_caching;
  spin_lock_init(&txr->xdp_tx_lock);

  /* Don't init RX queues for xdp queues */
  if (!ENA_IS_XDP_INDEX(adapter, i)) {
   /* RX common ring state */
   ena_init_io_rings_common(adapter, rxr, i);

   /* RX specific ring state */
   rxr->ring_size = adapter->requested_rx_ring_size;
   rxr->rx_copybreak = adapter->rx_copybreak;
   rxr->sgl_size = adapter->max_rx_sgl_size;
   rxr->smoothed_interval =
    ena_com_get_nonadaptive_moderation_interval_rx(ena_dev);
   rxr->empty_rx_queue = 0;
   rxr->rx_headroom = NET_SKB_PAD;
   adapter->ena_napi[i].dim.mode = DIM_CQ_PERIOD_MODE_START_FROM_EQE;
   rxr->xdp_ring = &adapter->tx_ring[i + adapter->num_io_queues];
  }
 }
}

/* ena_setup_tx_resources - allocate I/O Tx resources (Descriptors)
 * @adapter: network interface device structure
 * @qid: queue index
 *
 * Return 0 on success, negative on failure
 */

static int ena_setup_tx_resources(struct ena_adapter *adapter, int qid)
{
 struct ena_ring *tx_ring = &adapter->tx_ring[qid];
 struct ena_irq *ena_irq = &adapter->irq_tbl[ENA_IO_IRQ_IDX(qid)];
 int size, i, node;

 if (tx_ring->tx_buffer_info) {
  netif_err(adapter, ifup,
     adapter->netdev, "tx_buffer_info info is not NULL");
  return -EEXIST;
 }

 size = sizeof(struct ena_tx_buffer) * tx_ring->ring_size;
 node = cpu_to_node(ena_irq->cpu);

 tx_ring->tx_buffer_info = vzalloc_node(size, node);
 if (!tx_ring->tx_buffer_info) {
  tx_ring->tx_buffer_info = vzalloc(size);
  if (!tx_ring->tx_buffer_info)
   goto err_tx_buffer_info;
 }

 size = sizeof(u16) * tx_ring->ring_size;
 tx_ring->free_ids = vzalloc_node(size, node);
 if (!tx_ring->free_ids) {
  tx_ring->free_ids = vzalloc(size);
  if (!tx_ring->free_ids)
   goto err_tx_free_ids;
 }

 size = tx_ring->tx_max_header_size;
 tx_ring->push_buf_intermediate_buf = vzalloc_node(size, node);
 if (!tx_ring->push_buf_intermediate_buf) {
  tx_ring->push_buf_intermediate_buf = vzalloc(size);
  if (!tx_ring->push_buf_intermediate_buf)
   goto err_push_buf_intermediate_buf;
 }

 /* Req id ring for TX out of order completions */
 for (i = 0; i < tx_ring->ring_size; i++)
  tx_ring->free_ids[i] = i;

 /* Reset tx statistics */
 memset(&tx_ring->tx_stats, 0x0, sizeof(tx_ring->tx_stats));

 tx_ring->next_to_use = 0;
 tx_ring->next_to_clean = 0;
 tx_ring->cpu = ena_irq->cpu;
 tx_ring->numa_node = node;
 return 0;

err_push_buf_intermediate_buf:
 vfree(tx_ring->free_ids);
 tx_ring->free_ids = NULL;
err_tx_free_ids:
 vfree(tx_ring->tx_buffer_info);
 tx_ring->tx_buffer_info = NULL;
err_tx_buffer_info:
 return -ENOMEM;
}

/* ena_free_tx_resources - Free I/O Tx Resources per Queue
 * @adapter: network interface device structure
 * @qid: queue index
 *
 * Free all transmit software resources
 */

static void ena_free_tx_resources(struct ena_adapter *adapter, int qid)
{
 struct ena_ring *tx_ring = &adapter->tx_ring[qid];

 vfree(tx_ring->tx_buffer_info);
 tx_ring->tx_buffer_info = NULL;

 vfree(tx_ring->free_ids);
 tx_ring->free_ids = NULL;

 vfree(tx_ring->push_buf_intermediate_buf);
 tx_ring->push_buf_intermediate_buf = NULL;
}

int ena_setup_tx_resources_in_range(struct ena_adapter *adapter,
        int first_index, int count)
{
 int i, rc = 0;

 for (i = first_index; i < first_index + count; i++) {
  rc = ena_setup_tx_resources(adapter, i);
  if (rc)
   goto err_setup_tx;
 }

 return 0;

err_setup_tx:

 netif_err(adapter, ifup, adapter->netdev,
    "Tx queue %d: allocation failed\n", i);

 /* rewind the index freeing the rings as we go */
 while (first_index < i--)
  ena_free_tx_resources(adapter, i);
 return rc;
}

void ena_free_all_io_tx_resources_in_range(struct ena_adapter *adapter,
        int first_index, int count)
{
 int i;

 for (i = first_index; i < first_index + count; i++)
  ena_free_tx_resources(adapter, i);
}

/* ena_free_all_io_tx_resources - Free I/O Tx Resources for All Queues
 * @adapter: board private structure
 *
 * Free all transmit software resources
 */

void ena_free_all_io_tx_resources(struct ena_adapter *adapter)
{
 ena_free_all_io_tx_resources_in_range(adapter,
           0,
           adapter->xdp_num_queues +
           adapter->num_io_queues);
}

/* ena_setup_rx_resources - allocate I/O Rx resources (Descriptors)
 * @adapter: network interface device structure
 * @qid: queue index
 *
 * Returns 0 on success, negative on failure
 */

static int ena_setup_rx_resources(struct ena_adapter *adapter,
      u32 qid)
{
 struct ena_ring *rx_ring = &adapter->rx_ring[qid];
 struct ena_irq *ena_irq = &adapter->irq_tbl[ENA_IO_IRQ_IDX(qid)];
 int size, node, i;

 if (rx_ring->rx_buffer_info) {
  netif_err(adapter, ifup, adapter->netdev,
     "rx_buffer_info is not NULL");
  return -EEXIST;
 }

 /* alloc extra element so in rx path
 * we can always prefetch rx_info + 1
 */

 size = sizeof(struct ena_rx_buffer) * (rx_ring->ring_size + 1);
 node = cpu_to_node(ena_irq->cpu);

 rx_ring->rx_buffer_info = vzalloc_node(size, node);
 if (!rx_ring->rx_buffer_info) {
  rx_ring->rx_buffer_info = vzalloc(size);
  if (!rx_ring->rx_buffer_info)
   return -ENOMEM;
 }

 size = sizeof(u16) * rx_ring->ring_size;
 rx_ring->free_ids = vzalloc_node(size, node);
 if (!rx_ring->free_ids) {
  rx_ring->free_ids = vzalloc(size);
  if (!rx_ring->free_ids) {
   vfree(rx_ring->rx_buffer_info);
   rx_ring->rx_buffer_info = NULL;
   return -ENOMEM;
  }
 }

 /* Req id ring for receiving RX pkts out of order */
 for (i = 0; i < rx_ring->ring_size; i++)
  rx_ring->free_ids[i] = i;

 /* Reset rx statistics */
 memset(&rx_ring->rx_stats, 0x0, sizeof(rx_ring->rx_stats));

 rx_ring->next_to_clean = 0;
 rx_ring->next_to_use = 0;
 rx_ring->cpu = ena_irq->cpu;
 rx_ring->numa_node = node;

 return 0;
}

/* ena_free_rx_resources - Free I/O Rx Resources
 * @adapter: network interface device structure
 * @qid: queue index
 *
 * Free all receive software resources
 */

static void ena_free_rx_resources(struct ena_adapter *adapter,
      u32 qid)
{
 struct ena_ring *rx_ring = &adapter->rx_ring[qid];

 vfree(rx_ring->rx_buffer_info);
 rx_ring->rx_buffer_info = NULL;

 vfree(rx_ring->free_ids);
 rx_ring->free_ids = NULL;
}

/* ena_setup_all_rx_resources - allocate I/O Rx queues resources for all queues
 * @adapter: board private structure
 *
 * Return 0 on success, negative on failure
 */

static int ena_setup_all_rx_resources(struct ena_adapter *adapter)
{
 int i, rc = 0;

 for (i = 0; i < adapter->num_io_queues; i++) {
  rc = ena_setup_rx_resources(adapter, i);
  if (rc)
   goto err_setup_rx;
 }

 return 0;

err_setup_rx:

 netif_err(adapter, ifup, adapter->netdev,
    "Rx queue %d: allocation failed\n", i);

 /* rewind the index freeing the rings as we go */
 while (i--)
  ena_free_rx_resources(adapter, i);
 return rc;
}

/* ena_free_all_io_rx_resources - Free I/O Rx Resources for All Queues
 * @adapter: board private structure
 *
 * Free all receive software resources
 */

static void ena_free_all_io_rx_resources(struct ena_adapter *adapter)
{
 int i;

 for (i = 0; i < adapter->num_io_queues; i++)
  ena_free_rx_resources(adapter, i);
}

static struct page *ena_alloc_map_page(struct ena_ring *rx_ring,
           dma_addr_t *dma)
{
 struct page *page;

 /* This would allocate the page on the same NUMA node the executing code
 * is running on.
 */

 page = dev_alloc_page();
 if (!page) {
  ena_increase_stat(&rx_ring->rx_stats.page_alloc_fail, 1, &rx_ring->syncp);
  return ERR_PTR(-ENOSPC);
 }

 /* To enable NIC-side port-mirroring, AKA SPAN port,
 * we make the buffer readable from the nic as well
 */

 *dma = dma_map_page(rx_ring->dev, page, 0, ENA_PAGE_SIZE,
       DMA_BIDIRECTIONAL);
 if (unlikely(dma_mapping_error(rx_ring->dev, *dma))) {
  ena_increase_stat(&rx_ring->rx_stats.dma_mapping_err, 1,
      &rx_ring->syncp);
  __free_page(page);
  return ERR_PTR(-EIO);
 }

 return page;
}

static int ena_alloc_rx_buffer(struct ena_ring *rx_ring,
          struct ena_rx_buffer *rx_info)
{
 int headroom = rx_ring->rx_headroom;
 struct ena_com_buf *ena_buf;
 struct page *page;
 dma_addr_t dma;
 int tailroom;

 /* restore page offset value in case it has been changed by device */
 rx_info->buf_offset = headroom;

 /* if previous allocated page is not used */
 if (unlikely(rx_info->page))
  return 0;

 /* We handle DMA here */
 page = ena_alloc_map_page(rx_ring, &dma);
 if (IS_ERR(page))
  return PTR_ERR(page);

 netif_dbg(rx_ring->adapter, rx_status, rx_ring->netdev,
    "Allocate page %p, rx_info %p\n", page, rx_info);

 tailroom = SKB_DATA_ALIGN(sizeof(struct skb_shared_info));

 rx_info->page = page;
 rx_info->dma_addr = dma;
 rx_info->page_offset = 0;
 ena_buf = &rx_info->ena_buf;
 ena_buf->paddr = dma + headroom;
 ena_buf->len = ENA_PAGE_SIZE - headroom - tailroom;

 return 0;
}

static void ena_unmap_rx_buff_attrs(struct ena_ring *rx_ring,
        struct ena_rx_buffer *rx_info,
        unsigned long attrs)
{
 dma_unmap_page_attrs(rx_ring->dev, rx_info->dma_addr, ENA_PAGE_SIZE, DMA_BIDIRECTIONAL,
        attrs);
}

static void ena_free_rx_page(struct ena_ring *rx_ring,
        struct ena_rx_buffer *rx_info)
{
 struct page *page = rx_info->page;

 if (unlikely(!page)) {
  netif_warn(rx_ring->adapter, rx_err, rx_ring->netdev,
      "Trying to free unallocated buffer\n");
  return;
 }

 ena_unmap_rx_buff_attrs(rx_ring, rx_info, 0);

 __free_page(page);
 rx_info->page = NULL;
}

static int ena_refill_rx_bufs(struct ena_ring *rx_ring, u32 num)
{
 u16 next_to_use, req_id;
 u32 i;
 int rc;

 next_to_use = rx_ring->next_to_use;

 for (i = 0; i < num; i++) {
  struct ena_rx_buffer *rx_info;

  req_id = rx_ring->free_ids[next_to_use];

  rx_info = &rx_ring->rx_buffer_info[req_id];

  rc = ena_alloc_rx_buffer(rx_ring, rx_info);
  if (unlikely(rc < 0)) {
   netif_warn(rx_ring->adapter, rx_err, rx_ring->netdev,
       "Failed to allocate buffer for rx queue %d\n",
       rx_ring->qid);
   break;
  }
  rc = ena_com_add_single_rx_desc(rx_ring->ena_com_io_sq,
      &rx_info->ena_buf,
      req_id);
  if (unlikely(rc)) {
   netif_warn(rx_ring->adapter, rx_status, rx_ring->netdev,
       "Failed to add buffer for rx queue %d\n",
       rx_ring->qid);
   break;
  }
  next_to_use = ENA_RX_RING_IDX_NEXT(next_to_use,
         rx_ring->ring_size);
 }

 if (unlikely(i < num)) {
  ena_increase_stat(&rx_ring->rx_stats.refil_partial, 1,
      &rx_ring->syncp);
  netif_warn(rx_ring->adapter, rx_err, rx_ring->netdev,
      "Refilled rx qid %d with only %d buffers (from %d)\n",
      rx_ring->qid, i, num);
 }

 /* ena_com_write_sq_doorbell issues a wmb() */
 if (likely(i))
  ena_com_write_sq_doorbell(rx_ring->ena_com_io_sq);

 rx_ring->next_to_use = next_to_use;

 return i;
}

static void ena_free_rx_bufs(struct ena_adapter *adapter,
        u32 qid)
{
 struct ena_ring *rx_ring = &adapter->rx_ring[qid];
 u32 i;

 for (i = 0; i < rx_ring->ring_size; i++) {
  struct ena_rx_buffer *rx_info = &rx_ring->rx_buffer_info[i];

  if (rx_info->page)
   ena_free_rx_page(rx_ring, rx_info);
 }
}

/* ena_refill_all_rx_bufs - allocate all queues Rx buffers
 * @adapter: board private structure
 */

static void ena_refill_all_rx_bufs(struct ena_adapter *adapter)
{
 struct ena_ring *rx_ring;
 int i, rc, bufs_num;

 for (i = 0; i < adapter->num_io_queues; i++) {
  rx_ring = &adapter->rx_ring[i];
  bufs_num = rx_ring->ring_size - 1;
  rc = ena_refill_rx_bufs(rx_ring, bufs_num);

  if (unlikely(rc != bufs_num))
   netif_warn(rx_ring->adapter, rx_status, rx_ring->netdev,
       "Refilling Queue %d failed. allocated %d buffers from: %d\n",
       i, rc, bufs_num);
 }
}

static void ena_free_all_rx_bufs(struct ena_adapter *adapter)
{
 int i;

 for (i = 0; i < adapter->num_io_queues; i++)
  ena_free_rx_bufs(adapter, i);
}

void ena_unmap_tx_buff(struct ena_ring *tx_ring,
         struct ena_tx_buffer *tx_info)
{
 struct ena_com_buf *ena_buf;
 u32 cnt;
 int i;

 ena_buf = tx_info->bufs;
 cnt = tx_info->num_of_bufs;

 if (unlikely(!cnt))
  return;

 if (tx_info->map_linear_data) {
  dma_unmap_single(tx_ring->dev,
     dma_unmap_addr(ena_buf, paddr),
     dma_unmap_len(ena_buf, len),
     DMA_TO_DEVICE);
  ena_buf++;
  cnt--;
 }

 /* unmap remaining mapped pages */
 for (i = 0; i < cnt; i++) {
  dma_unmap_page(tx_ring->dev, dma_unmap_addr(ena_buf, paddr),
          dma_unmap_len(ena_buf, len), DMA_TO_DEVICE);
  ena_buf++;
 }
}

/* ena_free_tx_bufs - Free Tx Buffers per Queue
 * @tx_ring: TX ring for which buffers be freed
 */

static void ena_free_tx_bufs(struct ena_ring *tx_ring)
{
 bool print_once = true;
 bool is_xdp_ring;
 u32 i;

 is_xdp_ring = ENA_IS_XDP_INDEX(tx_ring->adapter, tx_ring->qid);

 for (i = 0; i < tx_ring->ring_size; i++) {
  struct ena_tx_buffer *tx_info = &tx_ring->tx_buffer_info[i];

  if (!tx_info->skb)
   continue;

  if (print_once) {
   netif_notice(tx_ring->adapter, ifdown, tx_ring->netdev,
         "Free uncompleted tx skb qid %d idx 0x%x\n",
         tx_ring->qid, i);
   print_once = false;
  } else {
   netif_dbg(tx_ring->adapter, ifdown, tx_ring->netdev,
      "Free uncompleted tx skb qid %d idx 0x%x\n",
      tx_ring->qid, i);
  }

  ena_unmap_tx_buff(tx_ring, tx_info);

  if (is_xdp_ring)
   xdp_return_frame(tx_info->xdpf);
  else
   dev_kfree_skb_any(tx_info->skb);
 }

 if (!is_xdp_ring)
  netdev_tx_reset_queue(netdev_get_tx_queue(tx_ring->netdev,
         tx_ring->qid));
}

static void ena_free_all_tx_bufs(struct ena_adapter *adapter)
{
 struct ena_ring *tx_ring;
 int i;

 for (i = 0; i < adapter->num_io_queues + adapter->xdp_num_queues; i++) {
  tx_ring = &adapter->tx_ring[i];
  ena_free_tx_bufs(tx_ring);
 }
}

static void ena_destroy_all_tx_queues(struct ena_adapter *adapter)
{
 u16 ena_qid;
 int i;

 for (i = 0; i < adapter->num_io_queues + adapter->xdp_num_queues; i++) {
  ena_qid = ENA_IO_TXQ_IDX(i);
  ena_com_destroy_io_queue(adapter->ena_dev, ena_qid);
 }
}

static void ena_destroy_all_rx_queues(struct ena_adapter *adapter)
{
 u16 ena_qid;
 int i;

 for (i = 0; i < adapter->num_io_queues; i++) {
  ena_qid = ENA_IO_RXQ_IDX(i);
  cancel_work_sync(&adapter->ena_napi[i].dim.work);
  ena_xdp_unregister_rxq_info(&adapter->rx_ring[i]);
  ena_com_destroy_io_queue(adapter->ena_dev, ena_qid);
 }
}

static void ena_destroy_all_io_queues(struct ena_adapter *adapter)
{
 ena_destroy_all_tx_queues(adapter);
 ena_destroy_all_rx_queues(adapter);
}

int handle_invalid_req_id(struct ena_ring *ring, u16 req_id,
     struct ena_tx_buffer *tx_info, bool is_xdp)
{
 if (tx_info)
  netif_err(ring->adapter,
     tx_done,
     ring->netdev,
     "tx_info doesn't have valid %s. qid %u req_id %u",
      is_xdp ? "xdp frame" : "skb", ring->qid, req_id);
 else
  netif_err(ring->adapter,
     tx_done,
     ring->netdev,
     "Invalid req_id %u in qid %u\n",
     req_id, ring->qid);

 ena_increase_stat(&ring->tx_stats.bad_req_id, 1, &ring->syncp);
 ena_reset_device(ring->adapter, ENA_REGS_RESET_INV_TX_REQ_ID);

 return -EFAULT;
}

static int validate_tx_req_id(struct ena_ring *tx_ring, u16 req_id)
{
 struct ena_tx_buffer *tx_info;

 tx_info = &tx_ring->tx_buffer_info[req_id];
 if (likely(tx_info->skb))
  return 0;

 return handle_invalid_req_id(tx_ring, req_id, tx_info, false);
}

static int ena_clean_tx_irq(struct ena_ring *tx_ring, u32 budget)
{
 struct netdev_queue *txq;
 bool above_thresh;
 u32 tx_bytes = 0;
 u32 total_done = 0;
 u16 next_to_clean;
 u16 req_id;
 int tx_pkts = 0;
 int rc;

 next_to_clean = tx_ring->next_to_clean;
 txq = netdev_get_tx_queue(tx_ring->netdev, tx_ring->qid);

 while (tx_pkts < budget) {
  struct ena_tx_buffer *tx_info;
  struct sk_buff *skb;

  rc = ena_com_tx_comp_req_id_get(tx_ring->ena_com_io_cq,
      &req_id);
  if (rc) {
   if (unlikely(rc == -EINVAL))
    handle_invalid_req_id(tx_ring, req_id, NULL, false);
   break;
  }

  /* validate that the request id points to a valid skb */
  rc = validate_tx_req_id(tx_ring, req_id);
  if (rc)
   break;

  tx_info = &tx_ring->tx_buffer_info[req_id];
  skb = tx_info->skb;

  /* prefetch skb_end_pointer() to speedup skb_shinfo(skb) */
  prefetch(&skb->end);

  tx_info->skb = NULL;
  tx_info->last_jiffies = 0;

  ena_unmap_tx_buff(tx_ring, tx_info);

  netif_dbg(tx_ring->adapter, tx_done, tx_ring->netdev,
     "tx_poll: q %d skb %p completed\n", tx_ring->qid,
     skb);

  tx_bytes += tx_info->total_tx_size;
  dev_kfree_skb(skb);
  tx_pkts++;
  total_done += tx_info->tx_descs;

  tx_ring->free_ids[next_to_clean] = req_id;
  next_to_clean = ENA_TX_RING_IDX_NEXT(next_to_clean,
           tx_ring->ring_size);
 }

 tx_ring->next_to_clean = next_to_clean;
 ena_com_comp_ack(tx_ring->ena_com_io_sq, total_done);

 netdev_tx_completed_queue(txq, tx_pkts, tx_bytes);

 netif_dbg(tx_ring->adapter, tx_done, tx_ring->netdev,
    "tx_poll: q %d done. total pkts: %d\n",
    tx_ring->qid, tx_pkts);

 /* need to make the rings circular update visible to
 * ena_start_xmit() before checking for netif_queue_stopped().
 */

 smp_mb();

 above_thresh = ena_com_sq_have_enough_space(tx_ring->ena_com_io_sq,
          ENA_TX_WAKEUP_THRESH);
 if (unlikely(netif_tx_queue_stopped(txq) && above_thresh)) {
  __netif_tx_lock(txq, smp_processor_id());
  above_thresh =
   ena_com_sq_have_enough_space(tx_ring->ena_com_io_sq,
           ENA_TX_WAKEUP_THRESH);
  if (netif_tx_queue_stopped(txq) && above_thresh &&
      test_bit(ENA_FLAG_DEV_UP, &tx_ring->adapter->flags)) {
   netif_tx_wake_queue(txq);
   ena_increase_stat(&tx_ring->tx_stats.queue_wakeup, 1,
       &tx_ring->syncp);
  }
  __netif_tx_unlock(txq);
 }

 return tx_pkts;
}

static struct sk_buff *ena_alloc_skb(struct ena_ring *rx_ring, void *first_frag, u16 len)
{
 struct sk_buff *skb;

 if (!first_frag)
  skb = napi_alloc_skb(rx_ring->napi, len);
 else
  skb = napi_build_skb(first_frag, len);

 if (unlikely(!skb)) {
  ena_increase_stat(&rx_ring->rx_stats.skb_alloc_fail, 1,
      &rx_ring->syncp);

  netif_dbg(rx_ring->adapter, rx_err, rx_ring->netdev,
     "Failed to allocate skb. first_frag %s\n",
     first_frag ? "provided" : "not provided");
 }

 return skb;
}

static bool ena_try_rx_buf_page_reuse(struct ena_rx_buffer *rx_info, u16 buf_len,
          u16 len, int pkt_offset)
{
 struct ena_com_buf *ena_buf = &rx_info->ena_buf;

 /* More than ENA_MIN_RX_BUF_SIZE left in the reused buffer
 * for data + headroom + tailroom.
 */

 if (SKB_DATA_ALIGN(len + pkt_offset) + ENA_MIN_RX_BUF_SIZE <= ena_buf->len) {
  page_ref_inc(rx_info->page);
  rx_info->page_offset += buf_len;
  ena_buf->paddr += buf_len;
  ena_buf->len -= buf_len;
  return true;
 }

 return false;
}

static struct sk_buff *ena_rx_skb(struct ena_ring *rx_ring,
      struct ena_com_rx_buf_info *ena_bufs,
      u32 descs,
      u16 *next_to_clean)
{
 int tailroom = SKB_DATA_ALIGN(sizeof(struct skb_shared_info));
 bool is_xdp_loaded = ena_xdp_present_ring(rx_ring);
 struct ena_rx_buffer *rx_info;
 struct ena_adapter *adapter;
 int page_offset, pkt_offset;
 dma_addr_t pre_reuse_paddr;
 u16 len, req_id, buf = 0;
 bool reuse_rx_buf_page;
 struct sk_buff *skb;
 void *buf_addr;
 int buf_offset;
 u16 buf_len;

 len = ena_bufs[buf].len;
 req_id = ena_bufs[buf].req_id;

 rx_info = &rx_ring->rx_buffer_info[req_id];

 if (unlikely(!rx_info->page)) {
  adapter = rx_ring->adapter;
  netif_err(adapter, rx_err, rx_ring->netdev,
     "Page is NULL. qid %u req_id %u\n", rx_ring->qid, req_id);
  ena_increase_stat(&rx_ring->rx_stats.bad_req_id, 1, &rx_ring->syncp);
  ena_reset_device(adapter, ENA_REGS_RESET_INV_RX_REQ_ID);
  return NULL;
 }

 netif_dbg(rx_ring->adapter, rx_status, rx_ring->netdev,
    "rx_info %p page %p\n",
    rx_info, rx_info->page);

 buf_offset = rx_info->buf_offset;
 pkt_offset = buf_offset - rx_ring->rx_headroom;
 page_offset = rx_info->page_offset;
 buf_addr = page_address(rx_info->page) + page_offset;

 if (len <= rx_ring->rx_copybreak) {
  skb = ena_alloc_skb(rx_ring, NULL, len);
  if (unlikely(!skb))
   return NULL;

  skb_copy_to_linear_data(skb, buf_addr + buf_offset, len);
  dma_sync_single_for_device(rx_ring->dev,
        dma_unmap_addr(&rx_info->ena_buf, paddr) + pkt_offset,
        len,
        DMA_FROM_DEVICE);

  skb_put(skb, len);
  netif_dbg(rx_ring->adapter, rx_status, rx_ring->netdev,
     "RX allocated small packet. len %d.\n", skb->len);
  skb->protocol = eth_type_trans(skb, rx_ring->netdev);
  rx_ring->free_ids[*next_to_clean] = req_id;
  *next_to_clean = ENA_RX_RING_IDX_ADD(*next_to_clean, descs,
           rx_ring->ring_size);
  return skb;
 }

 buf_len = SKB_DATA_ALIGN(len + buf_offset + tailroom);

 /* If XDP isn't loaded try to reuse part of the RX buffer */
 reuse_rx_buf_page = !is_xdp_loaded &&
       ena_try_rx_buf_page_reuse(rx_info, buf_len, len, pkt_offset);

 if (!reuse_rx_buf_page)
  ena_unmap_rx_buff_attrs(rx_ring, rx_info, DMA_ATTR_SKIP_CPU_SYNC);

 skb = ena_alloc_skb(rx_ring, buf_addr, buf_len);
 if (unlikely(!skb))
  return NULL;

 /* Populate skb's linear part */
 skb_reserve(skb, buf_offset);
 skb_put(skb, len);
 skb->protocol = eth_type_trans(skb, rx_ring->netdev);

 do {
  netif_dbg(rx_ring->adapter, rx_status, rx_ring->netdev,
     "RX skb updated. len %d. data_len %d\n",
     skb->len, skb->data_len);

  if (!reuse_rx_buf_page)
   rx_info->page = NULL;

  rx_ring->free_ids[*next_to_clean] = req_id;
  *next_to_clean =
   ENA_RX_RING_IDX_NEXT(*next_to_clean,
          rx_ring->ring_size);
  if (likely(--descs == 0))
   break;

  buf++;
  len = ena_bufs[buf].len;
  req_id = ena_bufs[buf].req_id;

  rx_info = &rx_ring->rx_buffer_info[req_id];

  /* rx_info->buf_offset includes rx_ring->rx_headroom */
  buf_offset = rx_info->buf_offset;
  pkt_offset = buf_offset - rx_ring->rx_headroom;
  buf_len = SKB_DATA_ALIGN(len + buf_offset + tailroom);
  page_offset = rx_info->page_offset;

  pre_reuse_paddr = dma_unmap_addr(&rx_info->ena_buf, paddr);

  reuse_rx_buf_page = !is_xdp_loaded &&
        ena_try_rx_buf_page_reuse(rx_info, buf_len, len, pkt_offset);

  dma_sync_single_for_cpu(rx_ring->dev,
     pre_reuse_paddr + pkt_offset,
     len,
     DMA_FROM_DEVICE);

  if (!reuse_rx_buf_page)
   ena_unmap_rx_buff_attrs(rx_ring, rx_info, DMA_ATTR_SKIP_CPU_SYNC);

  skb_add_rx_frag(skb, skb_shinfo(skb)->nr_frags, rx_info->page,
    page_offset + buf_offset, len, buf_len);

 } while (1);

 return skb;
}

/* ena_rx_checksum - indicate in skb if hw indicated a good cksum
 * @adapter: structure containing adapter specific data
 * @ena_rx_ctx: received packet context/metadata
 * @skb: skb currently being received and modified
 */

static void ena_rx_checksum(struct ena_ring *rx_ring,
       struct ena_com_rx_ctx *ena_rx_ctx,
       struct sk_buff *skb)
{
 /* Rx csum disabled */
 if (unlikely(!(rx_ring->netdev->features & NETIF_F_RXCSUM))) {
  skb->ip_summed = CHECKSUM_NONE;
  return;
 }

 /* For fragmented packets the checksum isn't valid */
 if (ena_rx_ctx->frag) {
  skb->ip_summed = CHECKSUM_NONE;
  return;
 }

 /* if IP and error */
 if (unlikely((ena_rx_ctx->l3_proto == ENA_ETH_IO_L3_PROTO_IPV4) &&
       (ena_rx_ctx->l3_csum_err))) {
  /* ipv4 checksum error */
  skb->ip_summed = CHECKSUM_NONE;
  ena_increase_stat(&rx_ring->rx_stats.csum_bad, 1,
      &rx_ring->syncp);
  netif_dbg(rx_ring->adapter, rx_err, rx_ring->netdev,
     "RX IPv4 header checksum error\n");
  return;
 }

 /* if TCP/UDP */
 if (likely((ena_rx_ctx->l4_proto == ENA_ETH_IO_L4_PROTO_TCP) ||
     (ena_rx_ctx->l4_proto == ENA_ETH_IO_L4_PROTO_UDP))) {
  if (unlikely(ena_rx_ctx->l4_csum_err)) {
   /* TCP/UDP checksum error */
   ena_increase_stat(&rx_ring->rx_stats.csum_bad, 1,
       &rx_ring->syncp);
   netif_dbg(rx_ring->adapter, rx_err, rx_ring->netdev,
      "RX L4 checksum error\n");
   skb->ip_summed = CHECKSUM_NONE;
   return;
  }

  if (likely(ena_rx_ctx->l4_csum_checked)) {
   skb->ip_summed = CHECKSUM_UNNECESSARY;
   ena_increase_stat(&rx_ring->rx_stats.csum_good, 1,
       &rx_ring->syncp);
  } else {
   ena_increase_stat(&rx_ring->rx_stats.csum_unchecked, 1,
       &rx_ring->syncp);
   skb->ip_summed = CHECKSUM_NONE;
  }
 } else {
  skb->ip_summed = CHECKSUM_NONE;
  return;
 }

}

static void ena_set_rx_hash(struct ena_ring *rx_ring,
       struct ena_com_rx_ctx *ena_rx_ctx,
       struct sk_buff *skb)
{
 enum pkt_hash_types hash_type;

 if (likely(rx_ring->netdev->features & NETIF_F_RXHASH)) {
  if (likely((ena_rx_ctx->l4_proto == ENA_ETH_IO_L4_PROTO_TCP) ||
      (ena_rx_ctx->l4_proto == ENA_ETH_IO_L4_PROTO_UDP)))

   hash_type = PKT_HASH_TYPE_L4;
  else
   hash_type = PKT_HASH_TYPE_NONE;

  /* Override hash type if the packet is fragmented */
  if (ena_rx_ctx->frag)
   hash_type = PKT_HASH_TYPE_NONE;

  skb_set_hash(skb, ena_rx_ctx->hash, hash_type);
 }
}

static int ena_xdp_handle_buff(struct ena_ring *rx_ring, struct xdp_buff *xdp, u16 num_descs)
{
 struct ena_rx_buffer *rx_info;
 int ret;

 /* XDP multi-buffer packets not supported */
 if (unlikely(num_descs > 1)) {
  netdev_err_once(rx_ring->adapter->netdev,
    "xdp: dropped unsupported multi-buffer packets\n");
  ena_increase_stat(&rx_ring->rx_stats.xdp_drop, 1, &rx_ring->syncp);
  return ENA_XDP_DROP;
 }

 rx_info = &rx_ring->rx_buffer_info[rx_ring->ena_bufs[0].req_id];
 xdp_prepare_buff(xdp, page_address(rx_info->page),
    rx_info->buf_offset,
    rx_ring->ena_bufs[0].len, false);

 ret = ena_xdp_execute(rx_ring, xdp);

 /* The xdp program might expand the headers */
 if (ret == ENA_XDP_PASS) {
  rx_info->buf_offset = xdp->data - xdp->data_hard_start;
  rx_ring->ena_bufs[0].len = xdp->data_end - xdp->data;
 }

 return ret;
}

/* ena_clean_rx_irq - Cleanup RX irq
 * @rx_ring: RX ring to clean
 * @napi: napi handler
 * @budget: how many packets driver is allowed to clean
 *
 * Returns the number of cleaned buffers.
 */

static int ena_clean_rx_irq(struct ena_ring *rx_ring, struct napi_struct *napi,
       u32 budget)
{
 u16 next_to_clean = rx_ring->next_to_clean;
 struct ena_com_rx_ctx ena_rx_ctx;
 struct ena_rx_buffer *rx_info;
 struct ena_adapter *adapter;
 u32 res_budget, work_done;
 int rx_copybreak_pkt = 0;
 int refill_threshold;
 struct sk_buff *skb;
 int refill_required;
 struct xdp_buff xdp;
 int xdp_flags = 0;
 int total_len = 0;
 int xdp_verdict;
 u8 pkt_offset;
 int rc = 0;
 int i;

 netif_dbg(rx_ring->adapter, rx_status, rx_ring->netdev,
    "%s qid %d\n", __func__, rx_ring->qid);
 res_budget = budget;
 xdp_init_buff(&xdp, ENA_PAGE_SIZE, &rx_ring->xdp_rxq);

 do {
  xdp_verdict = ENA_XDP_PASS;
  skb = NULL;
  ena_rx_ctx.ena_bufs = rx_ring->ena_bufs;
  ena_rx_ctx.max_bufs = rx_ring->sgl_size;
  ena_rx_ctx.descs = 0;
  ena_rx_ctx.pkt_offset = 0;
  rc = ena_com_rx_pkt(rx_ring->ena_com_io_cq,
        rx_ring->ena_com_io_sq,
        &ena_rx_ctx);
  if (unlikely(rc))
   goto error;

  if (unlikely(ena_rx_ctx.descs == 0))
   break;

  /* First descriptor might have an offset set by the device */
  rx_info = &rx_ring->rx_buffer_info[rx_ring->ena_bufs[0].req_id];
  pkt_offset = ena_rx_ctx.pkt_offset;
  rx_info->buf_offset += pkt_offset;

  netif_dbg(rx_ring->adapter, rx_status, rx_ring->netdev,
     "rx_poll: q %d got packet from ena. descs #: %d l3 proto %d l4 proto %d hash: %x\n",
     rx_ring->qid, ena_rx_ctx.descs, ena_rx_ctx.l3_proto,
     ena_rx_ctx.l4_proto, ena_rx_ctx.hash);

  dma_sync_single_for_cpu(rx_ring->dev,
     dma_unmap_addr(&rx_info->ena_buf, paddr) + pkt_offset,
     rx_ring->ena_bufs[0].len,
     DMA_FROM_DEVICE);

  if (ena_xdp_present_ring(rx_ring))
   xdp_verdict = ena_xdp_handle_buff(rx_ring, &xdp, ena_rx_ctx.descs);

  /* allocate skb and fill it */
  if (xdp_verdict == ENA_XDP_PASS)
   skb = ena_rx_skb(rx_ring,
      rx_ring->ena_bufs,
      ena_rx_ctx.descs,
      &next_to_clean);

  if (unlikely(!skb)) {
   for (i = 0; i < ena_rx_ctx.descs; i++) {
    int req_id = rx_ring->ena_bufs[i].req_id;

    rx_ring->free_ids[next_to_clean] = req_id;
    next_to_clean =
     ENA_RX_RING_IDX_NEXT(next_to_clean,
            rx_ring->ring_size);

    /* Packets was passed for transmission, unmap it
 * from RX side.
 */

    if (xdp_verdict & ENA_XDP_FORWARDED) {
     ena_unmap_rx_buff_attrs(rx_ring,
        &rx_ring->rx_buffer_info[req_id],
        DMA_ATTR_SKIP_CPU_SYNC);
     rx_ring->rx_buffer_info[req_id].page = NULL;
    }
   }
   if (xdp_verdict != ENA_XDP_PASS) {
    xdp_flags |= xdp_verdict;
    total_len += ena_rx_ctx.ena_bufs[0].len;
    res_budget--;
    continue;
   }
   break;
  }

  ena_rx_checksum(rx_ring, &ena_rx_ctx, skb);

  ena_set_rx_hash(rx_ring, &ena_rx_ctx, skb);

  skb_record_rx_queue(skb, rx_ring->qid);

  if (rx_ring->ena_bufs[0].len <= rx_ring->rx_copybreak)
   rx_copybreak_pkt++;

  total_len += skb->len;

  napi_gro_receive(napi, skb);

  res_budget--;
 } while (likely(res_budget));

 work_done = budget - res_budget;
 rx_ring->per_napi_packets += work_done;
 u64_stats_update_begin(&rx_ring->syncp);
 rx_ring->rx_stats.bytes += total_len;
 rx_ring->rx_stats.cnt += work_done;
 rx_ring->rx_stats.rx_copybreak_pkt += rx_copybreak_pkt;
 u64_stats_update_end(&rx_ring->syncp);

 rx_ring->next_to_clean = next_to_clean;

 refill_required = ena_com_free_q_entries(rx_ring->ena_com_io_sq);
 refill_threshold =
  min_t(int, rx_ring->ring_size / ENA_RX_REFILL_THRESH_DIVIDER,
        ENA_RX_REFILL_THRESH_PACKET);

 /* Optimization, try to batch new rx buffers */
 if (refill_required > refill_threshold)
  ena_refill_rx_bufs(rx_ring, refill_required);

 if (xdp_flags & ENA_XDP_REDIRECT)
  xdp_do_flush();

 return work_done;

error:
 if (xdp_flags & ENA_XDP_REDIRECT)
  xdp_do_flush();

 adapter = netdev_priv(rx_ring->netdev);

 if (rc == -ENOSPC) {
  ena_increase_stat(&rx_ring->rx_stats.bad_desc_num, 1, &rx_ring->syncp);
  ena_reset_device(adapter, ENA_REGS_RESET_TOO_MANY_RX_DESCS);
 } else if (rc == -EFAULT) {
  ena_reset_device(adapter, ENA_REGS_RESET_RX_DESCRIPTOR_MALFORMED);
 } else {
  ena_increase_stat(&rx_ring->rx_stats.bad_req_id, 1,
      &rx_ring->syncp);
  ena_reset_device(adapter, ENA_REGS_RESET_INV_RX_REQ_ID);
 }
 return 0;
}

static void ena_dim_work(struct work_struct *w)
{
 struct dim *dim = container_of(w, struct dim, work);
 struct dim_cq_moder cur_moder =
  net_dim_get_rx_moderation(dim->mode, dim->profile_ix);
 struct ena_napi *ena_napi = container_of(dim, struct ena_napi, dim);

 ena_napi->rx_ring->smoothed_interval = cur_moder.usec;
 dim->state = DIM_START_MEASURE;
}

static void ena_adjust_adaptive_rx_intr_moderation(struct ena_napi *ena_napi)
{
 struct dim_sample dim_sample;
 struct ena_ring *rx_ring = ena_napi->rx_ring;

 if (!rx_ring->per_napi_packets)
  return;

 rx_ring->non_empty_napi_events++;

 dim_update_sample(rx_ring->non_empty_napi_events,
     rx_ring->rx_stats.cnt,
     rx_ring->rx_stats.bytes,
     &dim_sample);

 net_dim(&ena_napi->dim, &dim_sample);

 rx_ring->per_napi_packets = 0;
}

void ena_unmask_interrupt(struct ena_ring *tx_ring,
     struct ena_ring *rx_ring)
{
 u32 rx_interval = tx_ring->smoothed_interval;
 struct ena_eth_io_intr_reg intr_reg;

 /* Rx ring can be NULL when for XDP tx queues which don't have an
 * accompanying rx_ring pair.
 */

 if (rx_ring)
  rx_interval = ena_com_get_adaptive_moderation_enabled(rx_ring->ena_dev) ?
   rx_ring->smoothed_interval :
   ena_com_get_nonadaptive_moderation_interval_rx(rx_ring->ena_dev);

 /* Update intr register: rx intr delay,
 * tx intr delay and interrupt unmask
 */

 ena_com_update_intr_reg(&intr_reg,
    rx_interval,
    tx_ring->smoothed_interval,
    true);

 ena_increase_stat(&tx_ring->tx_stats.unmask_interrupt, 1,
     &tx_ring->syncp);

 /* It is a shared MSI-X.
 * Tx and Rx CQ have pointer to it.
 * So we use one of them to reach the intr reg
 * The Tx ring is used because the rx_ring is NULL for XDP queues
 */

 ena_com_unmask_intr(tx_ring->ena_com_io_cq, &intr_reg);
}

void ena_update_ring_numa_node(struct ena_ring *tx_ring,
          struct ena_ring *rx_ring)
{
 int cpu = get_cpu();
 int numa_node;

 /* Check only one ring since the 2 rings are running on the same cpu */
 if (likely(tx_ring->cpu == cpu))
  goto out;

 tx_ring->cpu = cpu;
 if (rx_ring)
  rx_ring->cpu = cpu;

 numa_node = cpu_to_node(cpu);

 if (likely(tx_ring->numa_node == numa_node))
  goto out;

 put_cpu();

 if (numa_node != NUMA_NO_NODE) {
  ena_com_update_numa_node(tx_ring->ena_com_io_cq, numa_node);
  tx_ring->numa_node = numa_node;
  if (rx_ring) {
   rx_ring->numa_node = numa_node;
   ena_com_update_numa_node(rx_ring->ena_com_io_cq,
       numa_node);
  }
 }

 return;
out:
 put_cpu();
}

static int ena_io_poll(struct napi_struct *napi, int budget)
{
 struct ena_napi *ena_napi = container_of(napi, struct ena_napi, napi);
 struct ena_ring *tx_ring, *rx_ring;
 int tx_work_done;
 int rx_work_done = 0;
 int tx_budget;
 int napi_comp_call = 0;
 int ret;

 tx_ring = ena_napi->tx_ring;
 rx_ring = ena_napi->rx_ring;

 tx_budget = tx_ring->ring_size / ENA_TX_POLL_BUDGET_DIVIDER;

 if (!test_bit(ENA_FLAG_DEV_UP, &tx_ring->adapter->flags) ||
     test_bit(ENA_FLAG_TRIGGER_RESET, &tx_ring->adapter->flags)) {
  napi_complete_done(napi, 0);
  return 0;
 }

 tx_work_done = ena_clean_tx_irq(tx_ring, tx_budget);
 /* On netpoll the budget is zero and the handler should only clean the
 * tx completions.
 */

 if (likely(budget))
  rx_work_done = ena_clean_rx_irq(rx_ring, napi, budget);

 /* If the device is about to reset or down, avoid unmask
 * the interrupt and return 0 so NAPI won't reschedule
 */

 if (unlikely(!test_bit(ENA_FLAG_DEV_UP, &tx_ring->adapter->flags) ||
       test_bit(ENA_FLAG_TRIGGER_RESET, &tx_ring->adapter->flags))) {
  napi_complete_done(napi, 0);
  ret = 0;

 } else if ((budget > rx_work_done) && (tx_budget > tx_work_done)) {
  napi_comp_call = 1;

  /* Update numa and unmask the interrupt only when schedule
 * from the interrupt context (vs from sk_busy_loop)
 */

  if (napi_complete_done(napi, rx_work_done) &&
      READ_ONCE(ena_napi->interrupts_masked)) {
   smp_rmb(); /* make sure interrupts_masked is read */
   WRITE_ONCE(ena_napi->interrupts_masked, false);
   /* We apply adaptive moderation on Rx path only.
 * Tx uses static interrupt moderation.
 */

   if (ena_com_get_adaptive_moderation_enabled(rx_ring->ena_dev))
    ena_adjust_adaptive_rx_intr_moderation(ena_napi);

   ena_update_ring_numa_node(tx_ring, rx_ring);
   ena_unmask_interrupt(tx_ring, rx_ring);
  }

  ret = rx_work_done;
 } else {
  ret = budget;
 }

 u64_stats_update_begin(&tx_ring->syncp);
 tx_ring->tx_stats.napi_comp += napi_comp_call;
 tx_ring->tx_stats.tx_poll++;
 u64_stats_update_end(&tx_ring->syncp);

 tx_ring->tx_stats.last_napi_jiffies = jiffies;

 return ret;
}

static irqreturn_t ena_intr_msix_mgmnt(int irq, void *data)
{
 struct ena_adapter *adapter = (struct ena_adapter *)data;

 ena_com_admin_q_comp_intr_handler(adapter->ena_dev);

 /* Don't call the aenq handler before probe is done */
 if (likely(test_bit(ENA_FLAG_DEVICE_RUNNING, &adapter->flags)))
  ena_com_aenq_intr_handler(adapter->ena_dev, data);

 return IRQ_HANDLED;
}

/* ena_intr_msix_io - MSI-X Interrupt Handler for Tx/Rx
 * @irq: interrupt number
 * @data: pointer to a network interface private napi device structure
 */

static irqreturn_t ena_intr_msix_io(int irq, void *data)
{
 struct ena_napi *ena_napi = data;

 /* Used to check HW health */
 WRITE_ONCE(ena_napi->first_interrupt, true);

 WRITE_ONCE(ena_napi->interrupts_masked, true);
 smp_wmb(); /* write interrupts_masked before calling napi */

 napi_schedule_irqoff(&ena_napi->napi);

 return IRQ_HANDLED;
}

/* Reserve a single MSI-X vector for management (admin + aenq).
 * plus reserve one vector for each potential io queue.
 * the number of potential io queues is the minimum of what the device
 * supports and the number of vCPUs.
 */

static int ena_enable_msix(struct ena_adapter *adapter)
{
 int msix_vecs, irq_cnt;

 if (test_bit(ENA_FLAG_MSIX_ENABLED, &adapter->flags)) {
  netif_err(adapter, probe, adapter->netdev,
     "Error, MSI-X is already enabled\n");
  return -EPERM;
 }

 /* Reserved the max msix vectors we might need */
 msix_vecs = ENA_MAX_MSIX_VEC(adapter->max_num_io_queues);
 netif_dbg(adapter, probe, adapter->netdev,
    "Trying to enable MSI-X, vectors %d\n", msix_vecs);

 irq_cnt = pci_alloc_irq_vectors(adapter->pdev, ENA_MIN_MSIX_VEC,
     msix_vecs, PCI_IRQ_MSIX);

 if (irq_cnt < 0) {
  netif_err(adapter, probe, adapter->netdev,
     "Failed to enable MSI-X. irq_cnt %d\n", irq_cnt);
  return -ENOSPC;
 }

 if (irq_cnt != msix_vecs) {
  netif_notice(adapter, probe, adapter->netdev,
        "Enable only %d MSI-X (out of %d), reduce the number of queues\n",
        irq_cnt, msix_vecs);
  adapter->num_io_queues = irq_cnt - ENA_ADMIN_MSIX_VEC;
 }

 if (netif_enable_cpu_rmap(adapter->netdev, adapter->num_io_queues))
  netif_warn(adapter, probe, adapter->netdev,
      "Failed to map IRQs to CPUs\n");

 adapter->msix_vecs = irq_cnt;
 set_bit(ENA_FLAG_MSIX_ENABLED, &adapter->flags);

 return 0;
}

static void ena_setup_mgmnt_intr(struct ena_adapter *adapter)
{
 u32 cpu;

 snprintf(adapter->irq_tbl[ENA_MGMNT_IRQ_IDX].name,
   ENA_IRQNAME_SIZE, "ena-mgmnt@pci:%s",
   pci_name(adapter->pdev));
 adapter->irq_tbl[ENA_MGMNT_IRQ_IDX].handler =
  ena_intr_msix_mgmnt;
 adapter->irq_tbl[ENA_MGMNT_IRQ_IDX].data = adapter;
 adapter->irq_tbl[ENA_MGMNT_IRQ_IDX].vector =
  pci_irq_vector(adapter->pdev, ENA_MGMNT_IRQ_IDX);
 cpu = cpumask_first(cpu_online_mask);
 adapter->irq_tbl[ENA_MGMNT_IRQ_IDX].cpu = cpu;
 cpumask_set_cpu(cpu,
   &adapter->irq_tbl[ENA_MGMNT_IRQ_IDX].affinity_hint_mask);
}

static void ena_setup_io_intr(struct ena_adapter *adapter)
{
 struct net_device *netdev;
 int irq_idx, i, cpu;
 int io_queue_count;

 netdev = adapter->netdev;
 io_queue_count = adapter->num_io_queues + adapter->xdp_num_queues;

 for (i = 0; i < io_queue_count; i++) {
  irq_idx = ENA_IO_IRQ_IDX(i);
  cpu = i % num_online_cpus();

  snprintf(adapter->irq_tbl[irq_idx].name, ENA_IRQNAME_SIZE,
    "%s-Tx-Rx-%d", netdev->name, i);
  adapter->irq_tbl[irq_idx].handler = ena_intr_msix_io;
  adapter->irq_tbl[irq_idx].data = &adapter->ena_napi[i];
  adapter->irq_tbl[irq_idx].vector =
   pci_irq_vector(adapter->pdev, irq_idx);
  adapter->irq_tbl[irq_idx].cpu = cpu;

  cpumask_set_cpu(cpu,
    &adapter->irq_tbl[irq_idx].affinity_hint_mask);
 }
}

static int ena_request_mgmnt_irq(struct ena_adapter *adapter)
{
 unsigned long flags = 0;
 struct ena_irq *irq;
 int rc;

 irq = &adapter->irq_tbl[ENA_MGMNT_IRQ_IDX];
 rc = request_irq(irq->vector, irq->handler, flags, irq->name,
    irq->data);
 if (rc) {
  netif_err(adapter, probe, adapter->netdev,
     "Failed to request admin irq\n");
  return rc;
 }

 netif_dbg(adapter, probe, adapter->netdev,
    "Set affinity hint of mgmnt irq.to 0x%lx (irq vector: %d)\n",
    irq->affinity_hint_mask.bits[0], irq->vector);

 irq_set_affinity_hint(irq->vector, &irq->affinity_hint_mask);

 return rc;
}

static int ena_request_io_irq(struct ena_adapter *adapter)
{
 u32 io_queue_count = adapter->num_io_queues + adapter->xdp_num_queues;
 int rc = 0, i, k, irq_idx;
 unsigned long flags = 0;
 struct ena_irq *irq;

 if (!test_bit(ENA_FLAG_MSIX_ENABLED, &adapter->flags)) {
  netif_err(adapter, ifup, adapter->netdev,
     "Failed to request I/O IRQ: MSI-X is not enabled\n");
  return -EINVAL;
 }

 for (i = ENA_IO_IRQ_FIRST_IDX; i < ENA_MAX_MSIX_VEC(io_queue_count); i++) {
  irq = &adapter->irq_tbl[i];
  rc = request_irq(irq->vector, irq->handler, flags, irq->name,
     irq->data);
  if (rc) {
   netif_err(adapter, ifup, adapter->netdev,
      "Failed to request I/O IRQ. index %d rc %d\n",
       i, rc);
   goto err;
  }

  netif_dbg(adapter, ifup, adapter->netdev,
     "Set affinity hint of irq. index %d to 0x%lx (irq vector: %d)\n",
     i, irq->affinity_hint_mask.bits[0], irq->vector);

  irq_set_affinity_hint(irq->vector, &irq->affinity_hint_mask);
 }

 /* Now that IO IRQs have been successfully allocated map them to the
 * corresponding IO NAPI instance. Note that the mgmnt IRQ does not
 * have a NAPI, so care must be taken to correctly map IRQs to NAPIs.
 */

 for (i = 0; i < io_queue_count; i++) {
  irq_idx = ENA_IO_IRQ_IDX(i);
  irq = &adapter->irq_tbl[irq_idx];
  netif_napi_set_irq(&adapter->ena_napi[i].napi, irq->vector);
 }

 return rc;

err:
 for (k = ENA_IO_IRQ_FIRST_IDX; k < i; k++) {
  irq = &adapter->irq_tbl[k];
  free_irq(irq->vector, irq->data);
 }

 return rc;
}

static void ena_free_mgmnt_irq(struct ena_adapter *adapter)
{
 struct ena_irq *irq;

 irq = &adapter->irq_tbl[ENA_MGMNT_IRQ_IDX];
 synchronize_irq(irq->vector);
 irq_set_affinity_hint(irq->vector, NULL);
 free_irq(irq->vector, irq->data);
}

static void ena_free_io_irq(struct ena_adapter *adapter)
{
 u32 io_queue_count = adapter->num_io_queues + adapter->xdp_num_queues;
 struct ena_irq *irq;
 int i;

 for (i = ENA_IO_IRQ_FIRST_IDX; i < ENA_MAX_MSIX_VEC(io_queue_count); i++) {
  struct ena_napi *ena_napi;

  irq = &adapter->irq_tbl[i];
  irq_set_affinity_hint(irq->vector, NULL);
  ena_napi = irq->data;
  netif_napi_set_irq(&ena_napi->napi, -1);
  free_irq(irq->vector, irq->data);
 }
}

static void ena_disable_msix(struct ena_adapter *adapter)
{
 if (test_and_clear_bit(ENA_FLAG_MSIX_ENABLED, &adapter->flags))
  pci_free_irq_vectors(adapter->pdev);
}

static void ena_disable_io_intr_sync(struct ena_adapter *adapter)
{
 u32 io_queue_count = adapter->num_io_queues + adapter->xdp_num_queues;
 int i;

 if (!netif_running(adapter->netdev))
  return;

 for (i = ENA_IO_IRQ_FIRST_IDX; i < ENA_MAX_MSIX_VEC(io_queue_count); i++)
  synchronize_irq(adapter->irq_tbl[i].vector);
}

static void ena_del_napi_in_range(struct ena_adapter *adapter,
      int first_index,
      int count)
{
 int i;

 for (i = first_index; i < first_index + count; i++) {
  netif_napi_del(&adapter->ena_napi[i].napi);

  WARN_ON(ENA_IS_XDP_INDEX(adapter, i) &&
   adapter->ena_napi[i].rx_ring);
 }
}

static void ena_init_napi_in_range(struct ena_adapter *adapter,
       int first_index, int count)
{
 int (*napi_handler)(struct napi_struct *napi, int budget);
 int i;

 for (i = first_index; i < first_index + count; i++) {
  struct ena_napi *napi = &adapter->ena_napi[i];
  struct ena_ring *rx_ring, *tx_ring;

  memset(napi, 0, sizeof(*napi));

  rx_ring = &adapter->rx_ring[i];
  tx_ring = &adapter->tx_ring[i];

  napi_handler = ena_io_poll;
  if (ENA_IS_XDP_INDEX(adapter, i))
   napi_handler = ena_xdp_io_poll;

  netif_napi_add_config(adapter->netdev, &napi->napi, napi_handler, i);

  if (!ENA_IS_XDP_INDEX(adapter, i))
   napi->rx_ring = rx_ring;

  napi->tx_ring = tx_ring;
  napi->qid = i;
 }
}

static void ena_napi_disable_in_range(struct ena_adapter *adapter,
          int first_index,
          int count)
{
 struct napi_struct *napi;
 int i;

 for (i = first_index; i < first_index + count; i++) {
  napi = &adapter->ena_napi[i].napi;
  if (!ENA_IS_XDP_INDEX(adapter, i)) {
   /* This API is supported for non-XDP queues only */
   netif_queue_set_napi(adapter->netdev, i,
          NETDEV_QUEUE_TYPE_TX, NULL);
   netif_queue_set_napi(adapter->netdev, i,
          NETDEV_QUEUE_TYPE_RX, NULL);
  }
  napi_disable(napi);
 }
}

static void ena_napi_enable_in_range(struct ena_adapter *adapter,
         int first_index,
         int count)
{
 struct napi_struct *napi;
 int i;

 for (i = first_index; i < first_index + count; i++) {
  napi = &adapter->ena_napi[i].napi;
  napi_enable(napi);
  if (!ENA_IS_XDP_INDEX(adapter, i)) {
   /* This API is supported for non-XDP queues only */
   netif_queue_set_napi(adapter->netdev, i,
          NETDEV_QUEUE_TYPE_RX, napi);
   netif_queue_set_napi(adapter->netdev, i,
          NETDEV_QUEUE_TYPE_TX, napi);
  }
 }
}

/* Configure the Rx forwarding */
static int ena_rss_configure(struct ena_adapter *adapter)
{
 struct ena_com_dev *ena_dev = adapter->ena_dev;
 int rc;

 /* In case the RSS table wasn't initialized by probe */
 if (!ena_dev->rss.tbl_log_size) {
  rc = ena_rss_init_default(adapter);
  if (rc && (rc != -EOPNOTSUPP)) {
   netif_err(adapter, ifup, adapter->netdev, "Failed to init RSS rc: %d\n", rc);
   return rc;
  }
 }

 /* Set indirect table */
 rc = ena_com_indirect_table_set(ena_dev);
 if (unlikely(rc && rc != -EOPNOTSUPP))
  return rc;

 /* Configure hash function (if supported) */
 rc = ena_com_set_hash_function(ena_dev);
 if (unlikely(rc && (rc != -EOPNOTSUPP)))
  return rc;

 /* Configure hash inputs (if supported) */
 rc = ena_com_set_hash_ctrl(ena_dev);
 if (unlikely(rc && (rc != -EOPNOTSUPP)))
  return rc;

 return 0;
}

static int ena_up_complete(struct ena_adapter *adapter)
{
 int rc;

 rc = ena_rss_configure(adapter);
 if (rc)
  return rc;

 ena_change_mtu(adapter->netdev, adapter->netdev->mtu);

 ena_refill_all_rx_bufs(adapter);

 /* enable transmits */
 netif_tx_start_all_queues(adapter->netdev);

 ena_napi_enable_in_range(adapter,
     0,
     adapter->xdp_num_queues + adapter->num_io_queues);

 return 0;
}

static int ena_create_io_tx_queue(struct ena_adapter *adapter, int qid)
{
 struct ena_com_create_io_ctx ctx;
 struct ena_com_dev *ena_dev;
 struct ena_ring *tx_ring;
 u32 msix_vector;
 u16 ena_qid;
 int rc;

 ena_dev = adapter->ena_dev;

 tx_ring = &adapter->tx_ring[qid];
 msix_vector = ENA_IO_IRQ_IDX(qid);
 ena_qid = ENA_IO_TXQ_IDX(qid);

 memset(&ctx, 0x0, sizeof(ctx));

 ctx.direction = ENA_COM_IO_QUEUE_DIRECTION_TX;
 ctx.qid = ena_qid;
 ctx.mem_queue_type = ena_dev->tx_mem_queue_type;
 ctx.msix_vector = msix_vector;
 ctx.queue_size = tx_ring->ring_size;
 ctx.numa_node = tx_ring->numa_node;

 rc = ena_com_create_io_queue(ena_dev, &ctx);
 if (rc) {
  netif_err(adapter, ifup, adapter->netdev,
     "Failed to create I/O TX queue num %d rc: %d\n",
     qid, rc);
  return rc;
 }

 rc = ena_com_get_io_handlers(ena_dev, ena_qid,
         &tx_ring->ena_com_io_sq,
         &tx_ring->ena_com_io_cq);
 if (rc) {
  netif_err(adapter, ifup, adapter->netdev,
     "Failed to get TX queue handlers. TX queue num %d rc: %d\n",
     qid, rc);
  ena_com_destroy_io_queue(ena_dev, ena_qid);
  return rc;
 }

 ena_com_update_numa_node(tx_ring->ena_com_io_cq, ctx.numa_node);
 return rc;
}

int ena_create_io_tx_queues_in_range(struct ena_adapter *adapter,
         int first_index, int count)
{
 struct ena_com_dev *ena_dev = adapter->ena_dev;
 int rc, i;

 for (i = first_index; i < first_index + count; i++) {
  rc = ena_create_io_tx_queue(adapter, i);
  if (rc)
   goto create_err;
 }

 return 0;

create_err:
 while (i-- > first_index)
  ena_com_destroy_io_queue(ena_dev, ENA_IO_TXQ_IDX(i));

 return rc;
}

static int ena_create_io_rx_queue(struct ena_adapter *adapter, int qid)
{
 struct ena_com_dev *ena_dev;
 struct ena_com_create_io_ctx ctx;
 struct ena_ring *rx_ring;
 u32 msix_vector;
 u16 ena_qid;
 int rc;

 ena_dev = adapter->ena_dev;

 rx_ring = &adapter->rx_ring[qid];
 msix_vector = ENA_IO_IRQ_IDX(qid);
 ena_qid = ENA_IO_RXQ_IDX(qid);

 memset(&ctx, 0x0, sizeof(ctx));

 ctx.qid = ena_qid;
 ctx.direction = ENA_COM_IO_QUEUE_DIRECTION_RX;
 ctx.mem_queue_type = ENA_ADMIN_PLACEMENT_POLICY_HOST;
 ctx.msix_vector = msix_vector;
 ctx.queue_size = rx_ring->ring_size;
 ctx.numa_node = rx_ring->numa_node;

 rc = ena_com_create_io_queue(ena_dev, &ctx);
 if (rc) {
  netif_err(adapter, ifup, adapter->netdev,
     "Failed to create I/O RX queue num %d rc: %d\n",
     qid, rc);
  return rc;
 }

 rc = ena_com_get_io_handlers(ena_dev, ena_qid,
         &rx_ring->ena_com_io_sq,
         &rx_ring->ena_com_io_cq);
 if (rc) {
  netif_err(adapter, ifup, adapter->netdev,
     "Failed to get RX queue handlers. RX queue num %d rc: %d\n",
     qid, rc);
  goto err;
 }

 ena_com_update_numa_node(rx_ring->ena_com_io_cq, ctx.numa_node);

 return rc;
err:
 ena_com_destroy_io_queue(ena_dev, ena_qid);
 return rc;
}

static int ena_create_all_io_rx_queues(struct ena_adapter *adapter)
{
 struct ena_com_dev *ena_dev = adapter->ena_dev;
 int rc, i;

 for (i = 0; i < adapter->num_io_queues; i++) {
  rc = ena_create_io_rx_queue(adapter, i);
  if (rc)
   goto create_err;
  INIT_WORK(&adapter->ena_napi[i].dim.work, ena_dim_work);

  ena_xdp_register_rxq_info(&adapter->rx_ring[i]);
 }

 return 0;

create_err:
 while (i--) {
  ena_xdp_unregister_rxq_info(&adapter->rx_ring[i]);
  cancel_work_sync(&adapter->ena_napi[i].dim.work);
  ena_com_destroy_io_queue(ena_dev, ENA_IO_RXQ_IDX(i));
 }

 return rc;
}

static void set_io_rings_size(struct ena_adapter *adapter,
         int new_tx_size,
         int new_rx_size)
{
 int i;

 for (i = 0; i < adapter->num_io_queues; i++) {
  adapter->tx_ring[i].ring_size = new_tx_size;
  adapter->rx_ring[i].ring_size = new_rx_size;
 }
}

/* This function allows queue allocation to backoff when the system is
 * low on memory. If there is not enough memory to allocate io queues
 * the driver will try to allocate smaller queues.
 *
 * The backoff algorithm is as follows:
 *  1. Try to allocate TX and RX and if successful.
 *  1.1. return success
 *
 *  2. Divide by 2 the size of the larger of RX and TX queues (or both if their size is the same).
 *
 *  3. If TX or RX is smaller than 256
 *  3.1. return failure.
 *  4. else
 *  4.1. go back to 1.
 */

static int create_queues_with_size_backoff(struct ena_adapter *adapter)
{
 int rc, cur_rx_ring_size, cur_tx_ring_size;
 int new_rx_ring_size, new_tx_ring_size;

 /* current queue sizes might be set to smaller than the requested
 * ones due to past queue allocation failures.
 */

 set_io_rings_size(adapter, adapter->requested_tx_ring_size,
     adapter->requested_rx_ring_size);

 while (1) {
  if (ena_xdp_present(adapter)) {
   rc = ena_setup_and_create_all_xdp_queues(adapter);

   if (rc)
    goto err_setup_tx;
  }
  rc = ena_setup_tx_resources_in_range(adapter,
           0,
           adapter->num_io_queues);
  if (rc)
   goto err_setup_tx;

  rc = ena_create_io_tx_queues_in_range(adapter,
            0,
            adapter->num_io_queues);
  if (rc)
   goto err_create_tx_queues;

  rc = ena_setup_all_rx_resources(adapter);
  if (rc)
   goto err_setup_rx;

  rc = ena_create_all_io_rx_queues(adapter);
  if (rc)
   goto err_create_rx_queues;

  return 0;

err_create_rx_queues:
  ena_free_all_io_rx_resources(adapter);
err_setup_rx:
  ena_destroy_all_tx_queues(adapter);
err_create_tx_queues:
  ena_free_all_io_tx_resources(adapter);
err_setup_tx:
  if (rc != -ENOMEM) {
   netif_err(adapter, ifup, adapter->netdev,
      "Queue creation failed with error code %d\n",
      rc);
   return rc;
  }

  cur_tx_ring_size = adapter->tx_ring[0].ring_size;
  cur_rx_ring_size = adapter->rx_ring[0].ring_size;

  netif_err(adapter, ifup, adapter->netdev,
     "Not enough memory to create queues with sizes TX=%d, RX=%d\n",
     cur_tx_ring_size, cur_rx_ring_size);

  new_tx_ring_size = cur_tx_ring_size;
  new_rx_ring_size = cur_rx_ring_size;

  /* Decrease the size of the larger queue, or
 * decrease both if they are the same size.
 */

  if (cur_rx_ring_size <= cur_tx_ring_size)
   new_tx_ring_size = cur_tx_ring_size / 2;
  if (cur_rx_ring_size >= cur_tx_ring_size)
   new_rx_ring_size = cur_rx_ring_size / 2;

  if (new_tx_ring_size < ENA_MIN_RING_SIZE ||
      new_rx_ring_size < ENA_MIN_RING_SIZE) {
   netif_err(adapter, ifup, adapter->netdev,
      "Queue creation failed with the smallest possible queue size of %d for both queues. Not retrying with smaller queues\n",
      ENA_MIN_RING_SIZE);
   return rc;
  }

  netif_err(adapter, ifup, adapter->netdev,
     "Retrying queue creation with sizes TX=%d, RX=%d\n",
     new_tx_ring_size,
     new_rx_ring_size);

  set_io_rings_size(adapter, new_tx_ring_size,
      new_rx_ring_size);
 }
}

int ena_up(struct ena_adapter *adapter)
{
 int io_queue_count, rc, i;

 netif_dbg(adapter, ifup, adapter->netdev, "%s\n", __func__);

 io_queue_count = adapter->num_io_queues + adapter->xdp_num_queues;
 ena_setup_io_intr(adapter);

 /* napi poll functions should be initialized before running
 * request_irq(), to handle a rare condition where there is a pending
 * interrupt, causing the ISR to fire immediately while the poll
 * function wasn't set yet, causing a null dereference
 */

 ena_init_napi_in_range(adapter, 0, io_queue_count);

 /* Enabling DIM needs to happen before enabling IRQs since DIM
 * is run from napi routine
 */

 if (ena_com_interrupt_moderation_supported(adapter->ena_dev))
  ena_com_enable_adaptive_moderation(adapter->ena_dev);

 rc = ena_request_io_irq(adapter);
 if (rc)
  goto err_req_irq;

 rc = create_queues_with_size_backoff(adapter);
 if (rc)
  goto err_create_queues_with_backoff;

 rc = ena_up_complete(adapter);
 if (rc)
  goto err_up;

 if (test_bit(ENA_FLAG_LINK_UP, &adapter->flags))
  netif_carrier_on(adapter->netdev);

 ena_increase_stat(&adapter->dev_stats.interface_up, 1,
     &adapter->syncp);

 set_bit(ENA_FLAG_DEV_UP, &adapter->flags);

 /* Enable completion queues interrupt */
 for (i = 0; i < adapter->num_io_queues; i++)
  ena_unmask_interrupt(&adapter->tx_ring[i],
         &adapter->rx_ring[i]);

 /* schedule napi in case we had pending packets
 * from the last time we disable napi
 */

 for (i = 0; i < io_queue_count; i++)
  napi_schedule(&adapter->ena_napi[i].napi);

 return rc;

err_up:
 ena_destroy_all_tx_queues(adapter);
 ena_free_all_io_tx_resources(adapter);
 ena_destroy_all_rx_queues(adapter);
 ena_free_all_io_rx_resources(adapter);
err_create_queues_with_backoff:
 ena_free_io_irq(adapter);
err_req_irq:
 ena_del_napi_in_range(adapter, 0, io_queue_count);

 return rc;
}

void ena_down(struct ena_adapter *adapter)
{
 int io_queue_count = adapter->num_io_queues + adapter->xdp_num_queues;

 netif_dbg(adapter, ifdown, adapter->netdev, "%s\n", __func__);

 clear_bit(ENA_FLAG_DEV_UP, &adapter->flags);

 ena_increase_stat(&adapter->dev_stats.interface_down, 1,
     &adapter->syncp);

 netif_carrier_off(adapter->netdev);
 netif_tx_disable(adapter->netdev);

 /* After this point the napi handler won't enable the tx queue */
 ena_napi_disable_in_range(adapter, 0, io_queue_count);

 if (test_bit(ENA_FLAG_TRIGGER_RESET, &adapter->flags)) {
  int rc;

  rc = ena_com_dev_reset(adapter->ena_dev, adapter->reset_reason);
  if (rc)
   netif_err(adapter, ifdown, adapter->netdev,
      "Device reset failed\n");
  /* stop submitting admin commands on a device that was reset */
  ena_com_set_admin_running_state(adapter->ena_dev, false);
 }

 ena_destroy_all_io_queues(adapter);

 ena_disable_io_intr_sync(adapter);
 ena_free_io_irq(adapter);
 ena_del_napi_in_range(adapter, 0, io_queue_count);

 ena_free_all_tx_bufs(adapter);
 ena_free_all_rx_bufs(adapter);
 ena_free_all_io_tx_resources(adapter);
 ena_free_all_io_rx_resources(adapter);
}

/* ena_open - Called when a network interface is made active
 * @netdev: network interface device structure
 *
 * Returns 0 on success, negative value on failure
 *
 * The open entry point is called when a network interface is made
 * active by the system (IFF_UP).  At this point all resources needed
 * for transmit and receive operations are allocated, the interrupt
 * handler is registered with the OS, the watchdog timer is started,
 * and the stack is notified that the interface is ready.
 */

static int ena_open(struct net_device *netdev)
{
 struct ena_adapter *adapter = netdev_priv(netdev);
 int rc;

 /* Notify the stack of the actual queue counts. */
 rc = netif_set_real_num_tx_queues(netdev, adapter->num_io_queues);
 if (rc) {
  netif_err(adapter, ifup, netdev, "Can't set num tx queues\n");
  return rc;
 }

 rc = netif_set_real_num_rx_queues(netdev, adapter->num_io_queues);
 if (rc) {
  netif_err(adapter, ifup, netdev, "Can't set num rx queues\n");
  return rc;
 }

 rc = ena_up(adapter);
 if (rc)
  return rc;

 return rc;
}

/* ena_close - Disables a network interface
 * @netdev: network interface device structure
 *
 * Returns 0, this is not allowed to fail
 *
 * The close entry point is called when an interface is de-activated
 * by the OS.  The hardware is still under the drivers control, but
 * needs to be disabled.  A global MAC reset is issued to stop the
 * hardware, and all transmit and receive resources are freed.
 */

static int ena_close(struct net_device *netdev)
{
 struct ena_adapter *adapter = netdev_priv(netdev);

 netif_dbg(adapter, ifdown, netdev, "%s\n", __func__);

 if (!test_bit(ENA_FLAG_DEVICE_RUNNING, &adapter->flags))
  return 0;

 if (test_bit(ENA_FLAG_DEV_UP, &adapter->flags))
  ena_down(adapter);

 /* Check for device status and issue reset if needed*/
 check_for_admin_com_state(adapter);
 if (unlikely(test_bit(ENA_FLAG_TRIGGER_RESET, &adapter->flags))) {
  netif_err(adapter, ifdown, adapter->netdev,
     "Destroy failure, restarting device\n");
  ena_dump_stats_to_dmesg(adapter);
  /* rtnl lock already obtained in dev_ioctl() layer */
  ena_destroy_device(adapter, false);
  ena_restore_device(adapter);
 }

 return 0;
}

int ena_update_queue_params(struct ena_adapter *adapter,
       u32 new_tx_size,
       u32 new_rx_size,
       u32 new_llq_header_len)
{
 bool dev_was_up, large_llq_changed = false;
 int rc = 0;

 dev_was_up = test_bit(ENA_FLAG_DEV_UP, &adapter->flags);
 ena_close(adapter->netdev);
 adapter->requested_tx_ring_size = new_tx_size;
 adapter->requested_rx_ring_size = new_rx_size;
 ena_init_io_rings(adapter,
     0,
     adapter->xdp_num_queues +
     adapter->num_io_queues);

 large_llq_changed = adapter->ena_dev->tx_mem_queue_type ==
       ENA_ADMIN_PLACEMENT_POLICY_DEV;
 large_llq_changed &=
  new_llq_header_len != adapter->ena_dev->tx_max_header_size;

 /* a check that the configuration is valid is done by caller */
 if (large_llq_changed) {
  adapter->large_llq_header_enabled = !adapter->large_llq_header_enabled;

  ena_destroy_device(adapter, false);
  rc = ena_restore_device(adapter);
 }

 return dev_was_up && !rc ? ena_up(adapter) : rc;
}

int ena_set_rx_copybreak(struct ena_adapter *adapter, u32 rx_copybreak)
{
 struct ena_ring *rx_ring;
 int i;

 if (rx_copybreak > min_t(u16, adapter->netdev->mtu, ENA_PAGE_SIZE))
  return -EINVAL;

 adapter->rx_copybreak = rx_copybreak;

 for (i = 0; i < adapter->num_io_queues; i++) {
  rx_ring = &adapter->rx_ring[i];
  rx_ring->rx_copybreak = rx_copybreak;
 }

 return 0;
}

int ena_update_queue_count(struct ena_adapter *adapter, u32 new_channel_count)
{
 struct ena_com_dev *ena_dev = adapter->ena_dev;
 int prev_channel_count;
 bool dev_was_up;

 dev_was_up = test_bit(ENA_FLAG_DEV_UP, &adapter->flags);
 ena_close(adapter->netdev);
 prev_channel_count = adapter->num_io_queues;
 adapter->num_io_queues = new_channel_count;
 if (ena_xdp_present(adapter) &&
     ena_xdp_allowed(adapter) == ENA_XDP_ALLOWED) {
  adapter->xdp_first_ring = new_channel_count;
  adapter->xdp_num_queues = new_channel_count;
  if (prev_channel_count > new_channel_count)
   ena_xdp_exchange_program_rx_in_range(adapter,
            NULL,
            new_channel_count,
            prev_channel_count);
  else
   ena_xdp_exchange_program_rx_in_range(adapter,
            adapter->xdp_bpf_prog,
            prev_channel_count,
            new_channel_count);
 }

 /* We need to destroy the rss table so that the indirection
 * table will be reinitialized by ena_up()
 */

 ena_com_rss_destroy(ena_dev);
 ena_init_io_rings(adapter,
     0,
     adapter->xdp_num_queues +
     adapter->num_io_queues);
 return dev_was_up ? ena_open(adapter->netdev) : 0;
}

static void ena_tx_csum(struct ena_com_tx_ctx *ena_tx_ctx,
   struct sk_buff *skb,
   bool disable_meta_caching)
{
 u32 mss = skb_shinfo(skb)->gso_size;
 struct ena_com_tx_meta *ena_meta = &ena_tx_ctx->ena_meta;
 u8 l4_protocol = 0;

 if ((skb->ip_summed == CHECKSUM_PARTIAL) || mss) {
  ena_tx_ctx->l4_csum_enable = 1;
  if (mss) {
   ena_tx_ctx->tso_enable = 1;
   ena_meta->l4_hdr_len = tcp_hdr(skb)->doff;
   ena_tx_ctx->l4_csum_partial = 0;
  } else {
   ena_tx_ctx->tso_enable = 0;
   ena_meta->l4_hdr_len = 0;
   ena_tx_ctx->l4_csum_partial = 1;
  }

  switch (ip_hdr(skb)->version) {
  case IPVERSION:
--> --------------------

--> maximum size reached

--> --------------------

Messung V0.5
C=96 H=90 G=93

¤ Dauer der Verarbeitung: 0.21 Sekunden  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

     Produkte
     Quellcodebibliothek

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....

Besucherstatistik

Besucherstatistik

Monitoring

Montastic status badge