12246cbc2SShay Agroskin // SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
21738cd3eSNetanel Belgazal /*
32246cbc2SShay Agroskin * Copyright 2015-2020 Amazon.com, Inc. or its affiliates. All rights reserved.
41738cd3eSNetanel Belgazal */
51738cd3eSNetanel Belgazal
61738cd3eSNetanel Belgazal #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
71738cd3eSNetanel Belgazal
81738cd3eSNetanel Belgazal #ifdef CONFIG_RFS_ACCEL
91738cd3eSNetanel Belgazal #include <linux/cpu_rmap.h>
101738cd3eSNetanel Belgazal #endif /* CONFIG_RFS_ACCEL */
111738cd3eSNetanel Belgazal #include <linux/ethtool.h>
121738cd3eSNetanel Belgazal #include <linux/kernel.h>
131738cd3eSNetanel Belgazal #include <linux/module.h>
141738cd3eSNetanel Belgazal #include <linux/numa.h>
151738cd3eSNetanel Belgazal #include <linux/pci.h>
161738cd3eSNetanel Belgazal #include <linux/utsname.h>
171738cd3eSNetanel Belgazal #include <linux/version.h>
181738cd3eSNetanel Belgazal #include <linux/vmalloc.h>
191738cd3eSNetanel Belgazal #include <net/ip.h>
201738cd3eSNetanel Belgazal
211738cd3eSNetanel Belgazal #include "ena_netdev.h"
221738cd3eSNetanel Belgazal #include "ena_pci_id_tbl.h"
23c891d767SDavid Arinzon #include "ena_xdp.h"
241738cd3eSNetanel Belgazal
251738cd3eSNetanel Belgazal MODULE_AUTHOR("Amazon.com, Inc. or its affiliates");
261738cd3eSNetanel Belgazal MODULE_DESCRIPTION(DEVICE_NAME);
271738cd3eSNetanel Belgazal MODULE_LICENSE("GPL");
281738cd3eSNetanel Belgazal
291738cd3eSNetanel Belgazal /* Time in jiffies before concluding the transmitter is hung. */
301738cd3eSNetanel Belgazal #define TX_TIMEOUT (5 * HZ)
311738cd3eSNetanel Belgazal
32ce74496aSShay Agroskin #define ENA_MAX_RINGS min_t(unsigned int, ENA_MAX_NUM_IO_QUEUES, num_possible_cpus())
33ce74496aSShay Agroskin
341738cd3eSNetanel Belgazal #define DEFAULT_MSG_ENABLE (NETIF_MSG_DRV | NETIF_MSG_PROBE | NETIF_MSG_IFUP | \
351738cd3eSNetanel Belgazal NETIF_MSG_TX_DONE | NETIF_MSG_TX_ERR | NETIF_MSG_RX_ERR)
361738cd3eSNetanel Belgazal
371738cd3eSNetanel Belgazal static struct ena_aenq_handlers aenq_handlers;
381738cd3eSNetanel Belgazal
391738cd3eSNetanel Belgazal static struct workqueue_struct *ena_wq;
401738cd3eSNetanel Belgazal
411738cd3eSNetanel Belgazal MODULE_DEVICE_TABLE(pci, ena_pci_tbl);
421738cd3eSNetanel Belgazal
431738cd3eSNetanel Belgazal static int ena_rss_init_default(struct ena_adapter *adapter);
44ee4552aaSNetanel Belgazal static void check_for_admin_com_state(struct ena_adapter *adapter);
45cfa324a5SNetanel Belgazal static void ena_destroy_device(struct ena_adapter *adapter, bool graceful);
46ee4552aaSNetanel Belgazal static int ena_restore_device(struct ena_adapter *adapter);
47548c4940SSameeh Jubran
ena_tx_timeout(struct net_device * dev,unsigned int txqueue)480290bd29SMichael S. Tsirkin static void ena_tx_timeout(struct net_device *dev, unsigned int txqueue)
491738cd3eSNetanel Belgazal {
501738cd3eSNetanel Belgazal struct ena_adapter *adapter = netdev_priv(dev);
511738cd3eSNetanel Belgazal
523f6159dbSNetanel Belgazal /* Change the state of the device to trigger reset
533f6159dbSNetanel Belgazal * Check that we are not in the middle or a trigger already
543f6159dbSNetanel Belgazal */
553f6159dbSNetanel Belgazal
563f6159dbSNetanel Belgazal if (test_and_set_bit(ENA_FLAG_TRIGGER_RESET, &adapter->flags))
573f6159dbSNetanel Belgazal return;
583f6159dbSNetanel Belgazal
599fe890ccSArthur Kiyanovski ena_reset_device(adapter, ENA_REGS_RESET_OS_NETDEV_WD);
6089dd735eSShay Agroskin ena_increase_stat(&adapter->dev_stats.tx_timeout, 1, &adapter->syncp);
611738cd3eSNetanel Belgazal
621738cd3eSNetanel Belgazal netif_err(adapter, tx_err, dev, "Transmit time out\n");
631738cd3eSNetanel Belgazal }
641738cd3eSNetanel Belgazal
update_rx_ring_mtu(struct ena_adapter * adapter,int mtu)651738cd3eSNetanel Belgazal static void update_rx_ring_mtu(struct ena_adapter *adapter, int mtu)
661738cd3eSNetanel Belgazal {
671738cd3eSNetanel Belgazal int i;
681738cd3eSNetanel Belgazal
69faa615f9SSameeh Jubran for (i = 0; i < adapter->num_io_queues; i++)
701738cd3eSNetanel Belgazal adapter->rx_ring[i].mtu = mtu;
711738cd3eSNetanel Belgazal }
721738cd3eSNetanel Belgazal
ena_change_mtu(struct net_device * dev,int new_mtu)731738cd3eSNetanel Belgazal static int ena_change_mtu(struct net_device *dev, int new_mtu)
741738cd3eSNetanel Belgazal {
751738cd3eSNetanel Belgazal struct ena_adapter *adapter = netdev_priv(dev);
761738cd3eSNetanel Belgazal int ret;
771738cd3eSNetanel Belgazal
781738cd3eSNetanel Belgazal ret = ena_com_set_dev_mtu(adapter->ena_dev, new_mtu);
791738cd3eSNetanel Belgazal if (!ret) {
80bf2746e8SShay Agroskin netif_dbg(adapter, drv, dev, "Set MTU to %d\n", new_mtu);
811738cd3eSNetanel Belgazal update_rx_ring_mtu(adapter, new_mtu);
821738cd3eSNetanel Belgazal dev->mtu = new_mtu;
831738cd3eSNetanel Belgazal } else {
841738cd3eSNetanel Belgazal netif_err(adapter, drv, dev, "Failed to set MTU to %d\n",
851738cd3eSNetanel Belgazal new_mtu);
861738cd3eSNetanel Belgazal }
871738cd3eSNetanel Belgazal
881738cd3eSNetanel Belgazal return ret;
891738cd3eSNetanel Belgazal }
901738cd3eSNetanel Belgazal
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)91bc0ad685SDavid Arinzon int ena_xmit_common(struct ena_adapter *adapter,
92548c4940SSameeh Jubran struct ena_ring *ring,
93548c4940SSameeh Jubran struct ena_tx_buffer *tx_info,
94548c4940SSameeh Jubran struct ena_com_tx_ctx *ena_tx_ctx,
95548c4940SSameeh Jubran u16 next_to_use,
96548c4940SSameeh Jubran u32 bytes)
97548c4940SSameeh Jubran {
98548c4940SSameeh Jubran int rc, nb_hw_desc;
99548c4940SSameeh Jubran
100548c4940SSameeh Jubran if (unlikely(ena_com_is_doorbell_needed(ring->ena_com_io_sq,
101548c4940SSameeh Jubran ena_tx_ctx))) {
102bc0ad685SDavid Arinzon netif_dbg(adapter, tx_queued, adapter->netdev,
103548c4940SSameeh Jubran "llq tx max burst size of queue %d achieved, writing doorbell to send burst\n",
104548c4940SSameeh Jubran ring->qid);
1059e8afb05SShay Agroskin ena_ring_tx_doorbell(ring);
106548c4940SSameeh Jubran }
107548c4940SSameeh Jubran
108548c4940SSameeh Jubran /* prepare the packet's descriptors to dma engine */
109548c4940SSameeh Jubran rc = ena_com_prepare_tx(ring->ena_com_io_sq, ena_tx_ctx,
110548c4940SSameeh Jubran &nb_hw_desc);
111548c4940SSameeh Jubran
112548c4940SSameeh Jubran /* In case there isn't enough space in the queue for the packet,
113548c4940SSameeh Jubran * we simply drop it. All other failure reasons of
114548c4940SSameeh Jubran * ena_com_prepare_tx() are fatal and therefore require a device reset.
115548c4940SSameeh Jubran */
116548c4940SSameeh Jubran if (unlikely(rc)) {
117bc0ad685SDavid Arinzon netif_err(adapter, tx_queued, adapter->netdev,
118bf2746e8SShay Agroskin "Failed to prepare tx bufs\n");
119*26668c2dSDavid Arinzon ena_increase_stat(&ring->tx_stats.prepare_ctx_err, 1, &ring->syncp);
1209fe890ccSArthur Kiyanovski if (rc != -ENOMEM)
121*26668c2dSDavid Arinzon ena_reset_device(adapter, ENA_REGS_RESET_DRIVER_INVALID_STATE);
122548c4940SSameeh Jubran return rc;
123548c4940SSameeh Jubran }
124548c4940SSameeh Jubran
125548c4940SSameeh Jubran u64_stats_update_begin(&ring->syncp);
126548c4940SSameeh Jubran ring->tx_stats.cnt++;
127548c4940SSameeh Jubran ring->tx_stats.bytes += bytes;
128548c4940SSameeh Jubran u64_stats_update_end(&ring->syncp);
129548c4940SSameeh Jubran
130548c4940SSameeh Jubran tx_info->tx_descs = nb_hw_desc;
131548c4940SSameeh Jubran tx_info->last_jiffies = jiffies;
132548c4940SSameeh Jubran tx_info->print_once = 0;
133548c4940SSameeh Jubran
134548c4940SSameeh Jubran ring->next_to_use = ENA_TX_RING_IDX_NEXT(next_to_use,
135548c4940SSameeh Jubran ring->ring_size);
136548c4940SSameeh Jubran return 0;
137548c4940SSameeh Jubran }
138548c4940SSameeh Jubran
ena_init_rx_cpu_rmap(struct ena_adapter * adapter)1391738cd3eSNetanel Belgazal static int ena_init_rx_cpu_rmap(struct ena_adapter *adapter)
1401738cd3eSNetanel Belgazal {
1411738cd3eSNetanel Belgazal #ifdef CONFIG_RFS_ACCEL
1421738cd3eSNetanel Belgazal u32 i;
1431738cd3eSNetanel Belgazal int rc;
1441738cd3eSNetanel Belgazal
145faa615f9SSameeh Jubran adapter->netdev->rx_cpu_rmap = alloc_irq_cpu_rmap(adapter->num_io_queues);
1461738cd3eSNetanel Belgazal if (!adapter->netdev->rx_cpu_rmap)
1471738cd3eSNetanel Belgazal return -ENOMEM;
148faa615f9SSameeh Jubran for (i = 0; i < adapter->num_io_queues; i++) {
1491738cd3eSNetanel Belgazal int irq_idx = ENA_IO_IRQ_IDX(i);
1501738cd3eSNetanel Belgazal
1511738cd3eSNetanel Belgazal rc = irq_cpu_rmap_add(adapter->netdev->rx_cpu_rmap,
152da6f4cf5SChristoph Hellwig pci_irq_vector(adapter->pdev, irq_idx));
1531738cd3eSNetanel Belgazal if (rc) {
1541738cd3eSNetanel Belgazal free_irq_cpu_rmap(adapter->netdev->rx_cpu_rmap);
1551738cd3eSNetanel Belgazal adapter->netdev->rx_cpu_rmap = NULL;
1561738cd3eSNetanel Belgazal return rc;
1571738cd3eSNetanel Belgazal }
1581738cd3eSNetanel Belgazal }
1591738cd3eSNetanel Belgazal #endif /* CONFIG_RFS_ACCEL */
1601738cd3eSNetanel Belgazal return 0;
1611738cd3eSNetanel Belgazal }
1621738cd3eSNetanel Belgazal
ena_init_io_rings_common(struct ena_adapter * adapter,struct ena_ring * ring,u16 qid)1631738cd3eSNetanel Belgazal static void ena_init_io_rings_common(struct ena_adapter *adapter,
1641738cd3eSNetanel Belgazal struct ena_ring *ring, u16 qid)
1651738cd3eSNetanel Belgazal {
1661738cd3eSNetanel Belgazal ring->qid = qid;
1671738cd3eSNetanel Belgazal ring->pdev = adapter->pdev;
1681738cd3eSNetanel Belgazal ring->dev = &adapter->pdev->dev;
1691738cd3eSNetanel Belgazal ring->netdev = adapter->netdev;
1701738cd3eSNetanel Belgazal ring->napi = &adapter->ena_napi[qid].napi;
1711738cd3eSNetanel Belgazal ring->adapter = adapter;
1721738cd3eSNetanel Belgazal ring->ena_dev = adapter->ena_dev;
1731738cd3eSNetanel Belgazal ring->per_napi_packets = 0;
1741738cd3eSNetanel Belgazal ring->cpu = 0;
175a8ee104fSDavid Arinzon ring->numa_node = 0;
1768510e1a3SNetanel Belgazal ring->no_interrupt_event_cnt = 0;
1771738cd3eSNetanel Belgazal u64_stats_init(&ring->syncp);
1781738cd3eSNetanel Belgazal }
1791738cd3eSNetanel Belgazal
ena_init_io_rings(struct ena_adapter * adapter,int first_index,int count)180c891d767SDavid Arinzon void ena_init_io_rings(struct ena_adapter *adapter,
181548c4940SSameeh Jubran int first_index, int count)
1821738cd3eSNetanel Belgazal {
1831738cd3eSNetanel Belgazal struct ena_com_dev *ena_dev;
1841738cd3eSNetanel Belgazal struct ena_ring *txr, *rxr;
1851738cd3eSNetanel Belgazal int i;
1861738cd3eSNetanel Belgazal
1871738cd3eSNetanel Belgazal ena_dev = adapter->ena_dev;
1881738cd3eSNetanel Belgazal
189548c4940SSameeh Jubran for (i = first_index; i < first_index + count; i++) {
1901738cd3eSNetanel Belgazal txr = &adapter->tx_ring[i];
1911738cd3eSNetanel Belgazal rxr = &adapter->rx_ring[i];
1921738cd3eSNetanel Belgazal
193548c4940SSameeh Jubran /* TX common ring state */
1941738cd3eSNetanel Belgazal ena_init_io_rings_common(adapter, txr, i);
1951738cd3eSNetanel Belgazal
1961738cd3eSNetanel Belgazal /* TX specific ring state */
19713ca32a6SSameeh Jubran txr->ring_size = adapter->requested_tx_ring_size;
1981738cd3eSNetanel Belgazal txr->tx_max_header_size = ena_dev->tx_max_header_size;
1991738cd3eSNetanel Belgazal txr->tx_mem_queue_type = ena_dev->tx_mem_queue_type;
2001738cd3eSNetanel Belgazal txr->sgl_size = adapter->max_tx_sgl_size;
2011738cd3eSNetanel Belgazal txr->smoothed_interval =
2021738cd3eSNetanel Belgazal ena_com_get_nonadaptive_moderation_interval_tx(ena_dev);
2030e3a3f6dSArthur Kiyanovski txr->disable_meta_caching = adapter->disable_meta_caching;
204f1a25589SShay Agroskin spin_lock_init(&txr->xdp_tx_lock);
2051738cd3eSNetanel Belgazal
206548c4940SSameeh Jubran /* Don't init RX queues for xdp queues */
207548c4940SSameeh Jubran if (!ENA_IS_XDP_INDEX(adapter, i)) {
208548c4940SSameeh Jubran /* RX common ring state */
209548c4940SSameeh Jubran ena_init_io_rings_common(adapter, rxr, i);
210548c4940SSameeh Jubran
2111738cd3eSNetanel Belgazal /* RX specific ring state */
21213ca32a6SSameeh Jubran rxr->ring_size = adapter->requested_rx_ring_size;
2131738cd3eSNetanel Belgazal rxr->rx_copybreak = adapter->rx_copybreak;
2141738cd3eSNetanel Belgazal rxr->sgl_size = adapter->max_rx_sgl_size;
2151738cd3eSNetanel Belgazal rxr->smoothed_interval =
2161738cd3eSNetanel Belgazal ena_com_get_nonadaptive_moderation_interval_rx(ena_dev);
217a3af7c18SNetanel Belgazal rxr->empty_rx_queue = 0;
2189e5269a9SShay Agroskin rxr->rx_headroom = NET_SKB_PAD;
219282faf61SArthur Kiyanovski adapter->ena_napi[i].dim.mode = DIM_CQ_PERIOD_MODE_START_FROM_EQE;
220e4ac382eSShay Agroskin rxr->xdp_ring = &adapter->tx_ring[i + adapter->num_io_queues];
2211738cd3eSNetanel Belgazal }
2221738cd3eSNetanel Belgazal }
223548c4940SSameeh Jubran }
2241738cd3eSNetanel Belgazal
2251738cd3eSNetanel Belgazal /* ena_setup_tx_resources - allocate I/O Tx resources (Descriptors)
2261738cd3eSNetanel Belgazal * @adapter: network interface device structure
2271738cd3eSNetanel Belgazal * @qid: queue index
2281738cd3eSNetanel Belgazal *
2291738cd3eSNetanel Belgazal * Return 0 on success, negative on failure
2301738cd3eSNetanel Belgazal */
ena_setup_tx_resources(struct ena_adapter * adapter,int qid)2311738cd3eSNetanel Belgazal static int ena_setup_tx_resources(struct ena_adapter *adapter, int qid)
2321738cd3eSNetanel Belgazal {
2331738cd3eSNetanel Belgazal struct ena_ring *tx_ring = &adapter->tx_ring[qid];
2341738cd3eSNetanel Belgazal struct ena_irq *ena_irq = &adapter->irq_tbl[ENA_IO_IRQ_IDX(qid)];
2351738cd3eSNetanel Belgazal int size, i, node;
2361738cd3eSNetanel Belgazal
2371738cd3eSNetanel Belgazal if (tx_ring->tx_buffer_info) {
2381738cd3eSNetanel Belgazal netif_err(adapter, ifup,
2391738cd3eSNetanel Belgazal adapter->netdev, "tx_buffer_info info is not NULL");
2401738cd3eSNetanel Belgazal return -EEXIST;
2411738cd3eSNetanel Belgazal }
2421738cd3eSNetanel Belgazal
2431738cd3eSNetanel Belgazal size = sizeof(struct ena_tx_buffer) * tx_ring->ring_size;
2441738cd3eSNetanel Belgazal node = cpu_to_node(ena_irq->cpu);
2451738cd3eSNetanel Belgazal
2461738cd3eSNetanel Belgazal tx_ring->tx_buffer_info = vzalloc_node(size, node);
2471738cd3eSNetanel Belgazal if (!tx_ring->tx_buffer_info) {
2481738cd3eSNetanel Belgazal tx_ring->tx_buffer_info = vzalloc(size);
2491738cd3eSNetanel Belgazal if (!tx_ring->tx_buffer_info)
2508ee8ee7fSSameeh Jubran goto err_tx_buffer_info;
2511738cd3eSNetanel Belgazal }
2521738cd3eSNetanel Belgazal
2531738cd3eSNetanel Belgazal size = sizeof(u16) * tx_ring->ring_size;
254f9172498SSameeh Jubran tx_ring->free_ids = vzalloc_node(size, node);
255f9172498SSameeh Jubran if (!tx_ring->free_ids) {
256f9172498SSameeh Jubran tx_ring->free_ids = vzalloc(size);
257f9172498SSameeh Jubran if (!tx_ring->free_ids)
258f9172498SSameeh Jubran goto err_tx_free_ids;
2591738cd3eSNetanel Belgazal }
2601738cd3eSNetanel Belgazal
26138005ca8SArthur Kiyanovski size = tx_ring->tx_max_header_size;
26238005ca8SArthur Kiyanovski tx_ring->push_buf_intermediate_buf = vzalloc_node(size, node);
26338005ca8SArthur Kiyanovski if (!tx_ring->push_buf_intermediate_buf) {
26438005ca8SArthur Kiyanovski tx_ring->push_buf_intermediate_buf = vzalloc(size);
2658ee8ee7fSSameeh Jubran if (!tx_ring->push_buf_intermediate_buf)
2668ee8ee7fSSameeh Jubran goto err_push_buf_intermediate_buf;
26738005ca8SArthur Kiyanovski }
26838005ca8SArthur Kiyanovski
2691738cd3eSNetanel Belgazal /* Req id ring for TX out of order completions */
2701738cd3eSNetanel Belgazal for (i = 0; i < tx_ring->ring_size; i++)
271f9172498SSameeh Jubran tx_ring->free_ids[i] = i;
2721738cd3eSNetanel Belgazal
2731738cd3eSNetanel Belgazal /* Reset tx statistics */
2741738cd3eSNetanel Belgazal memset(&tx_ring->tx_stats, 0x0, sizeof(tx_ring->tx_stats));
2751738cd3eSNetanel Belgazal
2761738cd3eSNetanel Belgazal tx_ring->next_to_use = 0;
2771738cd3eSNetanel Belgazal tx_ring->next_to_clean = 0;
2781738cd3eSNetanel Belgazal tx_ring->cpu = ena_irq->cpu;
279a8ee104fSDavid Arinzon tx_ring->numa_node = node;
2801738cd3eSNetanel Belgazal return 0;
2818ee8ee7fSSameeh Jubran
2828ee8ee7fSSameeh Jubran err_push_buf_intermediate_buf:
283f9172498SSameeh Jubran vfree(tx_ring->free_ids);
284f9172498SSameeh Jubran tx_ring->free_ids = NULL;
285f9172498SSameeh Jubran err_tx_free_ids:
2868ee8ee7fSSameeh Jubran vfree(tx_ring->tx_buffer_info);
2878ee8ee7fSSameeh Jubran tx_ring->tx_buffer_info = NULL;
2888ee8ee7fSSameeh Jubran err_tx_buffer_info:
2898ee8ee7fSSameeh Jubran return -ENOMEM;
2901738cd3eSNetanel Belgazal }
2911738cd3eSNetanel Belgazal
2921738cd3eSNetanel Belgazal /* ena_free_tx_resources - Free I/O Tx Resources per Queue
2931738cd3eSNetanel Belgazal * @adapter: network interface device structure
2941738cd3eSNetanel Belgazal * @qid: queue index
2951738cd3eSNetanel Belgazal *
2961738cd3eSNetanel Belgazal * Free all transmit software resources
2971738cd3eSNetanel Belgazal */
ena_free_tx_resources(struct ena_adapter * adapter,int qid)2981738cd3eSNetanel Belgazal static void ena_free_tx_resources(struct ena_adapter *adapter, int qid)
2991738cd3eSNetanel Belgazal {
3001738cd3eSNetanel Belgazal struct ena_ring *tx_ring = &adapter->tx_ring[qid];
3011738cd3eSNetanel Belgazal
3021738cd3eSNetanel Belgazal vfree(tx_ring->tx_buffer_info);
3031738cd3eSNetanel Belgazal tx_ring->tx_buffer_info = NULL;
3041738cd3eSNetanel Belgazal
305f9172498SSameeh Jubran vfree(tx_ring->free_ids);
306f9172498SSameeh Jubran tx_ring->free_ids = NULL;
30738005ca8SArthur Kiyanovski
30838005ca8SArthur Kiyanovski vfree(tx_ring->push_buf_intermediate_buf);
30938005ca8SArthur Kiyanovski tx_ring->push_buf_intermediate_buf = NULL;
3101738cd3eSNetanel Belgazal }
3111738cd3eSNetanel Belgazal
ena_setup_tx_resources_in_range(struct ena_adapter * adapter,int first_index,int count)312c891d767SDavid Arinzon int ena_setup_tx_resources_in_range(struct ena_adapter *adapter,
313c891d767SDavid Arinzon int first_index, int count)
3141738cd3eSNetanel Belgazal {
3151738cd3eSNetanel Belgazal int i, rc = 0;
3161738cd3eSNetanel Belgazal
317548c4940SSameeh Jubran for (i = first_index; i < first_index + count; i++) {
3181738cd3eSNetanel Belgazal rc = ena_setup_tx_resources(adapter, i);
3191738cd3eSNetanel Belgazal if (rc)
3201738cd3eSNetanel Belgazal goto err_setup_tx;
3211738cd3eSNetanel Belgazal }
3221738cd3eSNetanel Belgazal
3231738cd3eSNetanel Belgazal return 0;
3241738cd3eSNetanel Belgazal
3251738cd3eSNetanel Belgazal err_setup_tx:
3261738cd3eSNetanel Belgazal
3271738cd3eSNetanel Belgazal netif_err(adapter, ifup, adapter->netdev,
3281738cd3eSNetanel Belgazal "Tx queue %d: allocation failed\n", i);
3291738cd3eSNetanel Belgazal
3301738cd3eSNetanel Belgazal /* rewind the index freeing the rings as we go */
331548c4940SSameeh Jubran while (first_index < i--)
3321738cd3eSNetanel Belgazal ena_free_tx_resources(adapter, i);
3331738cd3eSNetanel Belgazal return rc;
3341738cd3eSNetanel Belgazal }
3351738cd3eSNetanel Belgazal
ena_free_all_io_tx_resources_in_range(struct ena_adapter * adapter,int first_index,int count)336c891d767SDavid Arinzon void ena_free_all_io_tx_resources_in_range(struct ena_adapter *adapter,
337548c4940SSameeh Jubran int first_index, int count)
338548c4940SSameeh Jubran {
339548c4940SSameeh Jubran int i;
340548c4940SSameeh Jubran
341548c4940SSameeh Jubran for (i = first_index; i < first_index + count; i++)
342548c4940SSameeh Jubran ena_free_tx_resources(adapter, i);
343548c4940SSameeh Jubran }
344548c4940SSameeh Jubran
3451738cd3eSNetanel Belgazal /* ena_free_all_io_tx_resources - Free I/O Tx Resources for All Queues
3461738cd3eSNetanel Belgazal * @adapter: board private structure
3471738cd3eSNetanel Belgazal *
3481738cd3eSNetanel Belgazal * Free all transmit software resources
3491738cd3eSNetanel Belgazal */
ena_free_all_io_tx_resources(struct ena_adapter * adapter)350c891d767SDavid Arinzon void ena_free_all_io_tx_resources(struct ena_adapter *adapter)
3511738cd3eSNetanel Belgazal {
352548c4940SSameeh Jubran ena_free_all_io_tx_resources_in_range(adapter,
353548c4940SSameeh Jubran 0,
354548c4940SSameeh Jubran adapter->xdp_num_queues +
355548c4940SSameeh Jubran adapter->num_io_queues);
3561738cd3eSNetanel Belgazal }
3571738cd3eSNetanel Belgazal
3581738cd3eSNetanel Belgazal /* ena_setup_rx_resources - allocate I/O Rx resources (Descriptors)
3591738cd3eSNetanel Belgazal * @adapter: network interface device structure
3601738cd3eSNetanel Belgazal * @qid: queue index
3611738cd3eSNetanel Belgazal *
3621738cd3eSNetanel Belgazal * Returns 0 on success, negative on failure
3631738cd3eSNetanel Belgazal */
ena_setup_rx_resources(struct ena_adapter * adapter,u32 qid)3641738cd3eSNetanel Belgazal static int ena_setup_rx_resources(struct ena_adapter *adapter,
3651738cd3eSNetanel Belgazal u32 qid)
3661738cd3eSNetanel Belgazal {
3671738cd3eSNetanel Belgazal struct ena_ring *rx_ring = &adapter->rx_ring[qid];
3681738cd3eSNetanel Belgazal struct ena_irq *ena_irq = &adapter->irq_tbl[ENA_IO_IRQ_IDX(qid)];
369ad974baeSNetanel Belgazal int size, node, i;
3701738cd3eSNetanel Belgazal
3711738cd3eSNetanel Belgazal if (rx_ring->rx_buffer_info) {
3721738cd3eSNetanel Belgazal netif_err(adapter, ifup, adapter->netdev,
3731738cd3eSNetanel Belgazal "rx_buffer_info is not NULL");
3741738cd3eSNetanel Belgazal return -EEXIST;
3751738cd3eSNetanel Belgazal }
3761738cd3eSNetanel Belgazal
3771738cd3eSNetanel Belgazal /* alloc extra element so in rx path
3781738cd3eSNetanel Belgazal * we can always prefetch rx_info + 1
3791738cd3eSNetanel Belgazal */
3801738cd3eSNetanel Belgazal size = sizeof(struct ena_rx_buffer) * (rx_ring->ring_size + 1);
3811738cd3eSNetanel Belgazal node = cpu_to_node(ena_irq->cpu);
3821738cd3eSNetanel Belgazal
3831738cd3eSNetanel Belgazal rx_ring->rx_buffer_info = vzalloc_node(size, node);
3841738cd3eSNetanel Belgazal if (!rx_ring->rx_buffer_info) {
3851738cd3eSNetanel Belgazal rx_ring->rx_buffer_info = vzalloc(size);
3861738cd3eSNetanel Belgazal if (!rx_ring->rx_buffer_info)
3871738cd3eSNetanel Belgazal return -ENOMEM;
3881738cd3eSNetanel Belgazal }
3891738cd3eSNetanel Belgazal
390ad974baeSNetanel Belgazal size = sizeof(u16) * rx_ring->ring_size;
391f9172498SSameeh Jubran rx_ring->free_ids = vzalloc_node(size, node);
392f9172498SSameeh Jubran if (!rx_ring->free_ids) {
393f9172498SSameeh Jubran rx_ring->free_ids = vzalloc(size);
394f9172498SSameeh Jubran if (!rx_ring->free_ids) {
395ad974baeSNetanel Belgazal vfree(rx_ring->rx_buffer_info);
3968ee8ee7fSSameeh Jubran rx_ring->rx_buffer_info = NULL;
397ad974baeSNetanel Belgazal return -ENOMEM;
398ad974baeSNetanel Belgazal }
399ad974baeSNetanel Belgazal }
400ad974baeSNetanel Belgazal
401ad974baeSNetanel Belgazal /* Req id ring for receiving RX pkts out of order */
402ad974baeSNetanel Belgazal for (i = 0; i < rx_ring->ring_size; i++)
403f9172498SSameeh Jubran rx_ring->free_ids[i] = i;
404ad974baeSNetanel Belgazal
4051738cd3eSNetanel Belgazal /* Reset rx statistics */
4061738cd3eSNetanel Belgazal memset(&rx_ring->rx_stats, 0x0, sizeof(rx_ring->rx_stats));
4071738cd3eSNetanel Belgazal
4081738cd3eSNetanel Belgazal rx_ring->next_to_clean = 0;
4091738cd3eSNetanel Belgazal rx_ring->next_to_use = 0;
4101738cd3eSNetanel Belgazal rx_ring->cpu = ena_irq->cpu;
411a8ee104fSDavid Arinzon rx_ring->numa_node = node;
4121738cd3eSNetanel Belgazal
4131738cd3eSNetanel Belgazal return 0;
4141738cd3eSNetanel Belgazal }
4151738cd3eSNetanel Belgazal
4161738cd3eSNetanel Belgazal /* ena_free_rx_resources - Free I/O Rx Resources
4171738cd3eSNetanel Belgazal * @adapter: network interface device structure
4181738cd3eSNetanel Belgazal * @qid: queue index
4191738cd3eSNetanel Belgazal *
4201738cd3eSNetanel Belgazal * Free all receive software resources
4211738cd3eSNetanel Belgazal */
ena_free_rx_resources(struct ena_adapter * adapter,u32 qid)4221738cd3eSNetanel Belgazal static void ena_free_rx_resources(struct ena_adapter *adapter,
4231738cd3eSNetanel Belgazal u32 qid)
4241738cd3eSNetanel Belgazal {
4251738cd3eSNetanel Belgazal struct ena_ring *rx_ring = &adapter->rx_ring[qid];
4261738cd3eSNetanel Belgazal
4271738cd3eSNetanel Belgazal vfree(rx_ring->rx_buffer_info);
4281738cd3eSNetanel Belgazal rx_ring->rx_buffer_info = NULL;
429ad974baeSNetanel Belgazal
430f9172498SSameeh Jubran vfree(rx_ring->free_ids);
431f9172498SSameeh Jubran rx_ring->free_ids = NULL;
4321738cd3eSNetanel Belgazal }
4331738cd3eSNetanel Belgazal
4341738cd3eSNetanel Belgazal /* ena_setup_all_rx_resources - allocate I/O Rx queues resources for all queues
4351738cd3eSNetanel Belgazal * @adapter: board private structure
4361738cd3eSNetanel Belgazal *
4371738cd3eSNetanel Belgazal * Return 0 on success, negative on failure
4381738cd3eSNetanel Belgazal */
ena_setup_all_rx_resources(struct ena_adapter * adapter)4391738cd3eSNetanel Belgazal static int ena_setup_all_rx_resources(struct ena_adapter *adapter)
4401738cd3eSNetanel Belgazal {
4411738cd3eSNetanel Belgazal int i, rc = 0;
4421738cd3eSNetanel Belgazal
443faa615f9SSameeh Jubran for (i = 0; i < adapter->num_io_queues; i++) {
4441738cd3eSNetanel Belgazal rc = ena_setup_rx_resources(adapter, i);
4451738cd3eSNetanel Belgazal if (rc)
4461738cd3eSNetanel Belgazal goto err_setup_rx;
4471738cd3eSNetanel Belgazal }
4481738cd3eSNetanel Belgazal
4491738cd3eSNetanel Belgazal return 0;
4501738cd3eSNetanel Belgazal
4511738cd3eSNetanel Belgazal err_setup_rx:
4521738cd3eSNetanel Belgazal
4531738cd3eSNetanel Belgazal netif_err(adapter, ifup, adapter->netdev,
4541738cd3eSNetanel Belgazal "Rx queue %d: allocation failed\n", i);
4551738cd3eSNetanel Belgazal
4561738cd3eSNetanel Belgazal /* rewind the index freeing the rings as we go */
4571738cd3eSNetanel Belgazal while (i--)
4581738cd3eSNetanel Belgazal ena_free_rx_resources(adapter, i);
4591738cd3eSNetanel Belgazal return rc;
4601738cd3eSNetanel Belgazal }
4611738cd3eSNetanel Belgazal
4621738cd3eSNetanel Belgazal /* ena_free_all_io_rx_resources - Free I/O Rx Resources for All Queues
4631738cd3eSNetanel Belgazal * @adapter: board private structure
4641738cd3eSNetanel Belgazal *
4651738cd3eSNetanel Belgazal * Free all receive software resources
4661738cd3eSNetanel Belgazal */
ena_free_all_io_rx_resources(struct ena_adapter * adapter)4671738cd3eSNetanel Belgazal static void ena_free_all_io_rx_resources(struct ena_adapter *adapter)
4681738cd3eSNetanel Belgazal {
4691738cd3eSNetanel Belgazal int i;
4701738cd3eSNetanel Belgazal
471faa615f9SSameeh Jubran for (i = 0; i < adapter->num_io_queues; i++)
4721738cd3eSNetanel Belgazal ena_free_rx_resources(adapter, i);
4731738cd3eSNetanel Belgazal }
4741738cd3eSNetanel Belgazal
ena_alloc_map_page(struct ena_ring * rx_ring,dma_addr_t * dma)4756fb566c9SWei Yongjun static struct page *ena_alloc_map_page(struct ena_ring *rx_ring,
4766fb566c9SWei Yongjun dma_addr_t *dma)
477947c54c3SShay Agroskin {
478947c54c3SShay Agroskin struct page *page;
479947c54c3SShay Agroskin
480947c54c3SShay Agroskin /* This would allocate the page on the same NUMA node the executing code
481947c54c3SShay Agroskin * is running on.
482947c54c3SShay Agroskin */
483947c54c3SShay Agroskin page = dev_alloc_page();
484947c54c3SShay Agroskin if (!page) {
485*26668c2dSDavid Arinzon ena_increase_stat(&rx_ring->rx_stats.page_alloc_fail, 1, &rx_ring->syncp);
486947c54c3SShay Agroskin return ERR_PTR(-ENOSPC);
487947c54c3SShay Agroskin }
488947c54c3SShay Agroskin
489947c54c3SShay Agroskin /* To enable NIC-side port-mirroring, AKA SPAN port,
490947c54c3SShay Agroskin * we make the buffer readable from the nic as well
491947c54c3SShay Agroskin */
492947c54c3SShay Agroskin *dma = dma_map_page(rx_ring->dev, page, 0, ENA_PAGE_SIZE,
493947c54c3SShay Agroskin DMA_BIDIRECTIONAL);
494947c54c3SShay Agroskin if (unlikely(dma_mapping_error(rx_ring->dev, *dma))) {
495947c54c3SShay Agroskin ena_increase_stat(&rx_ring->rx_stats.dma_mapping_err, 1,
496947c54c3SShay Agroskin &rx_ring->syncp);
497947c54c3SShay Agroskin __free_page(page);
498947c54c3SShay Agroskin return ERR_PTR(-EIO);
499947c54c3SShay Agroskin }
500947c54c3SShay Agroskin
501947c54c3SShay Agroskin return page;
502947c54c3SShay Agroskin }
503947c54c3SShay Agroskin
ena_alloc_rx_buffer(struct ena_ring * rx_ring,struct ena_rx_buffer * rx_info)504947c54c3SShay Agroskin static int ena_alloc_rx_buffer(struct ena_ring *rx_ring,
505947c54c3SShay Agroskin struct ena_rx_buffer *rx_info)
5061738cd3eSNetanel Belgazal {
5071396d314SShay Agroskin int headroom = rx_ring->rx_headroom;
5081738cd3eSNetanel Belgazal struct ena_com_buf *ena_buf;
5091738cd3eSNetanel Belgazal struct page *page;
5101738cd3eSNetanel Belgazal dma_addr_t dma;
5119e5269a9SShay Agroskin int tailroom;
5121738cd3eSNetanel Belgazal
5131396d314SShay Agroskin /* restore page offset value in case it has been changed by device */
514f7d625adSDavid Arinzon rx_info->buf_offset = headroom;
5151396d314SShay Agroskin
5161738cd3eSNetanel Belgazal /* if previous allocated page is not used */
5171738cd3eSNetanel Belgazal if (unlikely(rx_info->page))
5181738cd3eSNetanel Belgazal return 0;
5191738cd3eSNetanel Belgazal
520947c54c3SShay Agroskin /* We handle DMA here */
521947c54c3SShay Agroskin page = ena_alloc_map_page(rx_ring, &dma);
522947c54c3SShay Agroskin if (unlikely(IS_ERR(page)))
523947c54c3SShay Agroskin return PTR_ERR(page);
5241738cd3eSNetanel Belgazal
5251738cd3eSNetanel Belgazal netif_dbg(rx_ring->adapter, rx_status, rx_ring->netdev,
526bf2746e8SShay Agroskin "Allocate page %p, rx_info %p\n", page, rx_info);
5271738cd3eSNetanel Belgazal
5289e5269a9SShay Agroskin tailroom = SKB_DATA_ALIGN(sizeof(struct skb_shared_info));
5299e5269a9SShay Agroskin
5301738cd3eSNetanel Belgazal rx_info->page = page;
531f7d625adSDavid Arinzon rx_info->dma_addr = dma;
532f7d625adSDavid Arinzon rx_info->page_offset = 0;
5331738cd3eSNetanel Belgazal ena_buf = &rx_info->ena_buf;
5341396d314SShay Agroskin ena_buf->paddr = dma + headroom;
5359e5269a9SShay Agroskin ena_buf->len = ENA_PAGE_SIZE - headroom - tailroom;
5361738cd3eSNetanel Belgazal
5371738cd3eSNetanel Belgazal return 0;
5381738cd3eSNetanel Belgazal }
5391738cd3eSNetanel Belgazal
ena_unmap_rx_buff_attrs(struct ena_ring * rx_ring,struct ena_rx_buffer * rx_info,unsigned long attrs)540f7d625adSDavid Arinzon static void ena_unmap_rx_buff_attrs(struct ena_ring *rx_ring,
541f7d625adSDavid Arinzon struct ena_rx_buffer *rx_info,
542f7d625adSDavid Arinzon unsigned long attrs)
543a318c70aSShay Agroskin {
544*26668c2dSDavid Arinzon dma_unmap_page_attrs(rx_ring->dev, rx_info->dma_addr, ENA_PAGE_SIZE, DMA_BIDIRECTIONAL,
545*26668c2dSDavid Arinzon attrs);
546a318c70aSShay Agroskin }
547a318c70aSShay Agroskin
ena_free_rx_page(struct ena_ring * rx_ring,struct ena_rx_buffer * rx_info)5481738cd3eSNetanel Belgazal static void ena_free_rx_page(struct ena_ring *rx_ring,
5491738cd3eSNetanel Belgazal struct ena_rx_buffer *rx_info)
5501738cd3eSNetanel Belgazal {
5511738cd3eSNetanel Belgazal struct page *page = rx_info->page;
5521738cd3eSNetanel Belgazal
5531738cd3eSNetanel Belgazal if (unlikely(!page)) {
5541738cd3eSNetanel Belgazal netif_warn(rx_ring->adapter, rx_err, rx_ring->netdev,
5551738cd3eSNetanel Belgazal "Trying to free unallocated buffer\n");
5561738cd3eSNetanel Belgazal return;
5571738cd3eSNetanel Belgazal }
5581738cd3eSNetanel Belgazal
559f7d625adSDavid Arinzon ena_unmap_rx_buff_attrs(rx_ring, rx_info, 0);
5601738cd3eSNetanel Belgazal
5611738cd3eSNetanel Belgazal __free_page(page);
5621738cd3eSNetanel Belgazal rx_info->page = NULL;
5631738cd3eSNetanel Belgazal }
5641738cd3eSNetanel Belgazal
ena_refill_rx_bufs(struct ena_ring * rx_ring,u32 num)5651738cd3eSNetanel Belgazal static int ena_refill_rx_bufs(struct ena_ring *rx_ring, u32 num)
5661738cd3eSNetanel Belgazal {
567ad974baeSNetanel Belgazal u16 next_to_use, req_id;
5681738cd3eSNetanel Belgazal u32 i;
5691738cd3eSNetanel Belgazal int rc;
5701738cd3eSNetanel Belgazal
5711738cd3eSNetanel Belgazal next_to_use = rx_ring->next_to_use;
5721738cd3eSNetanel Belgazal
5731738cd3eSNetanel Belgazal for (i = 0; i < num; i++) {
574ad974baeSNetanel Belgazal struct ena_rx_buffer *rx_info;
575ad974baeSNetanel Belgazal
576f9172498SSameeh Jubran req_id = rx_ring->free_ids[next_to_use];
577ad974baeSNetanel Belgazal
578ad974baeSNetanel Belgazal rx_info = &rx_ring->rx_buffer_info[req_id];
579ad974baeSNetanel Belgazal
580947c54c3SShay Agroskin rc = ena_alloc_rx_buffer(rx_ring, rx_info);
5811738cd3eSNetanel Belgazal if (unlikely(rc < 0)) {
5821738cd3eSNetanel Belgazal netif_warn(rx_ring->adapter, rx_err, rx_ring->netdev,
583bf2746e8SShay Agroskin "Failed to allocate buffer for rx queue %d\n",
5841738cd3eSNetanel Belgazal rx_ring->qid);
5851738cd3eSNetanel Belgazal break;
5861738cd3eSNetanel Belgazal }
5871738cd3eSNetanel Belgazal rc = ena_com_add_single_rx_desc(rx_ring->ena_com_io_sq,
5881738cd3eSNetanel Belgazal &rx_info->ena_buf,
589ad974baeSNetanel Belgazal req_id);
5901738cd3eSNetanel Belgazal if (unlikely(rc)) {
5911738cd3eSNetanel Belgazal netif_warn(rx_ring->adapter, rx_status, rx_ring->netdev,
592bf2746e8SShay Agroskin "Failed to add buffer for rx queue %d\n",
5931738cd3eSNetanel Belgazal rx_ring->qid);
5941738cd3eSNetanel Belgazal break;
5951738cd3eSNetanel Belgazal }
5961738cd3eSNetanel Belgazal next_to_use = ENA_RX_RING_IDX_NEXT(next_to_use,
5971738cd3eSNetanel Belgazal rx_ring->ring_size);
5981738cd3eSNetanel Belgazal }
5991738cd3eSNetanel Belgazal
6001738cd3eSNetanel Belgazal if (unlikely(i < num)) {
60189dd735eSShay Agroskin ena_increase_stat(&rx_ring->rx_stats.refil_partial, 1,
60289dd735eSShay Agroskin &rx_ring->syncp);
603f0525298SShay Agroskin netif_warn(rx_ring->adapter, rx_err, rx_ring->netdev,
604bf2746e8SShay Agroskin "Refilled rx qid %d with only %d buffers (from %d)\n",
6051738cd3eSNetanel Belgazal rx_ring->qid, i, num);
6061738cd3eSNetanel Belgazal }
6071738cd3eSNetanel Belgazal
60837dff155SNetanel Belgazal /* ena_com_write_sq_doorbell issues a wmb() */
60937dff155SNetanel Belgazal if (likely(i))
61037dff155SNetanel Belgazal ena_com_write_sq_doorbell(rx_ring->ena_com_io_sq);
6111738cd3eSNetanel Belgazal
6121738cd3eSNetanel Belgazal rx_ring->next_to_use = next_to_use;
6131738cd3eSNetanel Belgazal
6141738cd3eSNetanel Belgazal return i;
6151738cd3eSNetanel Belgazal }
6161738cd3eSNetanel Belgazal
ena_free_rx_bufs(struct ena_adapter * adapter,u32 qid)6171738cd3eSNetanel Belgazal static void ena_free_rx_bufs(struct ena_adapter *adapter,
6181738cd3eSNetanel Belgazal u32 qid)
6191738cd3eSNetanel Belgazal {
6201738cd3eSNetanel Belgazal struct ena_ring *rx_ring = &adapter->rx_ring[qid];
6211738cd3eSNetanel Belgazal u32 i;
6221738cd3eSNetanel Belgazal
6231738cd3eSNetanel Belgazal for (i = 0; i < rx_ring->ring_size; i++) {
6241738cd3eSNetanel Belgazal struct ena_rx_buffer *rx_info = &rx_ring->rx_buffer_info[i];
6251738cd3eSNetanel Belgazal
6261738cd3eSNetanel Belgazal if (rx_info->page)
6271738cd3eSNetanel Belgazal ena_free_rx_page(rx_ring, rx_info);
6281738cd3eSNetanel Belgazal }
6291738cd3eSNetanel Belgazal }
6301738cd3eSNetanel Belgazal
6311738cd3eSNetanel Belgazal /* ena_refill_all_rx_bufs - allocate all queues Rx buffers
6321738cd3eSNetanel Belgazal * @adapter: board private structure
6331738cd3eSNetanel Belgazal */
ena_refill_all_rx_bufs(struct ena_adapter * adapter)6341738cd3eSNetanel Belgazal static void ena_refill_all_rx_bufs(struct ena_adapter *adapter)
6351738cd3eSNetanel Belgazal {
6361738cd3eSNetanel Belgazal struct ena_ring *rx_ring;
6371738cd3eSNetanel Belgazal int i, rc, bufs_num;
6381738cd3eSNetanel Belgazal
639faa615f9SSameeh Jubran for (i = 0; i < adapter->num_io_queues; i++) {
6401738cd3eSNetanel Belgazal rx_ring = &adapter->rx_ring[i];
6411738cd3eSNetanel Belgazal bufs_num = rx_ring->ring_size - 1;
6421738cd3eSNetanel Belgazal rc = ena_refill_rx_bufs(rx_ring, bufs_num);
6431738cd3eSNetanel Belgazal
6441738cd3eSNetanel Belgazal if (unlikely(rc != bufs_num))
6451738cd3eSNetanel Belgazal netif_warn(rx_ring->adapter, rx_status, rx_ring->netdev,
646bf2746e8SShay Agroskin "Refilling Queue %d failed. allocated %d buffers from: %d\n",
6471738cd3eSNetanel Belgazal i, rc, bufs_num);
6481738cd3eSNetanel Belgazal }
6491738cd3eSNetanel Belgazal }
6501738cd3eSNetanel Belgazal
ena_free_all_rx_bufs(struct ena_adapter * adapter)6511738cd3eSNetanel Belgazal static void ena_free_all_rx_bufs(struct ena_adapter *adapter)
6521738cd3eSNetanel Belgazal {
6531738cd3eSNetanel Belgazal int i;
6541738cd3eSNetanel Belgazal
655faa615f9SSameeh Jubran for (i = 0; i < adapter->num_io_queues; i++)
6561738cd3eSNetanel Belgazal ena_free_rx_bufs(adapter, i);
6571738cd3eSNetanel Belgazal }
6581738cd3eSNetanel Belgazal
ena_unmap_tx_buff(struct ena_ring * tx_ring,struct ena_tx_buffer * tx_info)659c891d767SDavid Arinzon void ena_unmap_tx_buff(struct ena_ring *tx_ring,
66038005ca8SArthur Kiyanovski struct ena_tx_buffer *tx_info)
66138005ca8SArthur Kiyanovski {
66238005ca8SArthur Kiyanovski struct ena_com_buf *ena_buf;
66338005ca8SArthur Kiyanovski u32 cnt;
66438005ca8SArthur Kiyanovski int i;
66538005ca8SArthur Kiyanovski
66638005ca8SArthur Kiyanovski ena_buf = tx_info->bufs;
66738005ca8SArthur Kiyanovski cnt = tx_info->num_of_bufs;
66838005ca8SArthur Kiyanovski
66938005ca8SArthur Kiyanovski if (unlikely(!cnt))
67038005ca8SArthur Kiyanovski return;
67138005ca8SArthur Kiyanovski
67238005ca8SArthur Kiyanovski if (tx_info->map_linear_data) {
67338005ca8SArthur Kiyanovski dma_unmap_single(tx_ring->dev,
67438005ca8SArthur Kiyanovski dma_unmap_addr(ena_buf, paddr),
67538005ca8SArthur Kiyanovski dma_unmap_len(ena_buf, len),
67638005ca8SArthur Kiyanovski DMA_TO_DEVICE);
67738005ca8SArthur Kiyanovski ena_buf++;
67838005ca8SArthur Kiyanovski cnt--;
67938005ca8SArthur Kiyanovski }
68038005ca8SArthur Kiyanovski
68138005ca8SArthur Kiyanovski /* unmap remaining mapped pages */
68238005ca8SArthur Kiyanovski for (i = 0; i < cnt; i++) {
68338005ca8SArthur Kiyanovski dma_unmap_page(tx_ring->dev, dma_unmap_addr(ena_buf, paddr),
68438005ca8SArthur Kiyanovski dma_unmap_len(ena_buf, len), DMA_TO_DEVICE);
68538005ca8SArthur Kiyanovski ena_buf++;
68638005ca8SArthur Kiyanovski }
68738005ca8SArthur Kiyanovski }
68838005ca8SArthur Kiyanovski
6891738cd3eSNetanel Belgazal /* ena_free_tx_bufs - Free Tx Buffers per Queue
6901738cd3eSNetanel Belgazal * @tx_ring: TX ring for which buffers be freed
6911738cd3eSNetanel Belgazal */
ena_free_tx_bufs(struct ena_ring * tx_ring)6921738cd3eSNetanel Belgazal static void ena_free_tx_bufs(struct ena_ring *tx_ring)
6931738cd3eSNetanel Belgazal {
6945add6e4aSNetanel Belgazal bool print_once = true;
6955c7f2240SDavid Arinzon bool is_xdp_ring;
6961738cd3eSNetanel Belgazal u32 i;
6971738cd3eSNetanel Belgazal
6985c7f2240SDavid Arinzon is_xdp_ring = ENA_IS_XDP_INDEX(tx_ring->adapter, tx_ring->qid);
6995c7f2240SDavid Arinzon
7001738cd3eSNetanel Belgazal for (i = 0; i < tx_ring->ring_size; i++) {
7011738cd3eSNetanel Belgazal struct ena_tx_buffer *tx_info = &tx_ring->tx_buffer_info[i];
7021738cd3eSNetanel Belgazal
7031738cd3eSNetanel Belgazal if (!tx_info->skb)
7041738cd3eSNetanel Belgazal continue;
7051738cd3eSNetanel Belgazal
7065add6e4aSNetanel Belgazal if (print_once) {
707f0525298SShay Agroskin netif_notice(tx_ring->adapter, ifdown, tx_ring->netdev,
708bf2746e8SShay Agroskin "Free uncompleted tx skb qid %d idx 0x%x\n",
7091738cd3eSNetanel Belgazal tx_ring->qid, i);
7105add6e4aSNetanel Belgazal print_once = false;
7115add6e4aSNetanel Belgazal } else {
712f0525298SShay Agroskin netif_dbg(tx_ring->adapter, ifdown, tx_ring->netdev,
713bf2746e8SShay Agroskin "Free uncompleted tx skb qid %d idx 0x%x\n",
7145add6e4aSNetanel Belgazal tx_ring->qid, i);
7155add6e4aSNetanel Belgazal }
7161738cd3eSNetanel Belgazal
717548c4940SSameeh Jubran ena_unmap_tx_buff(tx_ring, tx_info);
7181738cd3eSNetanel Belgazal
7195c7f2240SDavid Arinzon if (is_xdp_ring)
7205c7f2240SDavid Arinzon xdp_return_frame(tx_info->xdpf);
7215c7f2240SDavid Arinzon else
7221738cd3eSNetanel Belgazal dev_kfree_skb_any(tx_info->skb);
7231738cd3eSNetanel Belgazal }
7245c7f2240SDavid Arinzon
7255c7f2240SDavid Arinzon if (!is_xdp_ring)
7261738cd3eSNetanel Belgazal netdev_tx_reset_queue(netdev_get_tx_queue(tx_ring->netdev,
7271738cd3eSNetanel Belgazal tx_ring->qid));
7281738cd3eSNetanel Belgazal }
7291738cd3eSNetanel Belgazal
ena_free_all_tx_bufs(struct ena_adapter * adapter)7301738cd3eSNetanel Belgazal static void ena_free_all_tx_bufs(struct ena_adapter *adapter)
7311738cd3eSNetanel Belgazal {
7321738cd3eSNetanel Belgazal struct ena_ring *tx_ring;
7331738cd3eSNetanel Belgazal int i;
7341738cd3eSNetanel Belgazal
735548c4940SSameeh Jubran for (i = 0; i < adapter->num_io_queues + adapter->xdp_num_queues; i++) {
7361738cd3eSNetanel Belgazal tx_ring = &adapter->tx_ring[i];
7371738cd3eSNetanel Belgazal ena_free_tx_bufs(tx_ring);
7381738cd3eSNetanel Belgazal }
7391738cd3eSNetanel Belgazal }
7401738cd3eSNetanel Belgazal
ena_destroy_all_tx_queues(struct ena_adapter * adapter)7411738cd3eSNetanel Belgazal static void ena_destroy_all_tx_queues(struct ena_adapter *adapter)
7421738cd3eSNetanel Belgazal {
7431738cd3eSNetanel Belgazal u16 ena_qid;
7441738cd3eSNetanel Belgazal int i;
7451738cd3eSNetanel Belgazal
746548c4940SSameeh Jubran for (i = 0; i < adapter->num_io_queues + adapter->xdp_num_queues; i++) {
7471738cd3eSNetanel Belgazal ena_qid = ENA_IO_TXQ_IDX(i);
7481738cd3eSNetanel Belgazal ena_com_destroy_io_queue(adapter->ena_dev, ena_qid);
7491738cd3eSNetanel Belgazal }
7501738cd3eSNetanel Belgazal }
7511738cd3eSNetanel Belgazal
ena_destroy_all_rx_queues(struct ena_adapter * adapter)7521738cd3eSNetanel Belgazal static void ena_destroy_all_rx_queues(struct ena_adapter *adapter)
7531738cd3eSNetanel Belgazal {
7541738cd3eSNetanel Belgazal u16 ena_qid;
7551738cd3eSNetanel Belgazal int i;
7561738cd3eSNetanel Belgazal
757faa615f9SSameeh Jubran for (i = 0; i < adapter->num_io_queues; i++) {
7581738cd3eSNetanel Belgazal ena_qid = ENA_IO_RXQ_IDX(i);
759282faf61SArthur Kiyanovski cancel_work_sync(&adapter->ena_napi[i].dim.work);
7601738cd3eSNetanel Belgazal ena_com_destroy_io_queue(adapter->ena_dev, ena_qid);
7611738cd3eSNetanel Belgazal }
7621738cd3eSNetanel Belgazal }
7631738cd3eSNetanel Belgazal
ena_destroy_all_io_queues(struct ena_adapter * adapter)7641738cd3eSNetanel Belgazal static void ena_destroy_all_io_queues(struct ena_adapter *adapter)
7651738cd3eSNetanel Belgazal {
7661738cd3eSNetanel Belgazal ena_destroy_all_tx_queues(adapter);
7671738cd3eSNetanel Belgazal ena_destroy_all_rx_queues(adapter);
7681738cd3eSNetanel Belgazal }
7691738cd3eSNetanel Belgazal
handle_invalid_req_id(struct ena_ring * ring,u16 req_id,struct ena_tx_buffer * tx_info,bool is_xdp)770c891d767SDavid Arinzon int handle_invalid_req_id(struct ena_ring *ring, u16 req_id,
771548c4940SSameeh Jubran struct ena_tx_buffer *tx_info, bool is_xdp)
772548c4940SSameeh Jubran {
773548c4940SSameeh Jubran if (tx_info)
774548c4940SSameeh Jubran netif_err(ring->adapter,
775548c4940SSameeh Jubran tx_done,
776548c4940SSameeh Jubran ring->netdev,
7779b648bb1SArthur Kiyanovski "tx_info doesn't have valid %s. qid %u req_id %u",
7789b648bb1SArthur Kiyanovski is_xdp ? "xdp frame" : "skb", ring->qid, req_id);
779548c4940SSameeh Jubran else
780548c4940SSameeh Jubran netif_err(ring->adapter,
781548c4940SSameeh Jubran tx_done,
782548c4940SSameeh Jubran ring->netdev,
7839b648bb1SArthur Kiyanovski "Invalid req_id %u in qid %u\n",
7849b648bb1SArthur Kiyanovski req_id, ring->qid);
785548c4940SSameeh Jubran
78689dd735eSShay Agroskin ena_increase_stat(&ring->tx_stats.bad_req_id, 1, &ring->syncp);
7879fe890ccSArthur Kiyanovski ena_reset_device(ring->adapter, ENA_REGS_RESET_INV_TX_REQ_ID);
788548c4940SSameeh Jubran
789548c4940SSameeh Jubran return -EFAULT;
790548c4940SSameeh Jubran }
791548c4940SSameeh Jubran
validate_tx_req_id(struct ena_ring * tx_ring,u16 req_id)7921738cd3eSNetanel Belgazal static int validate_tx_req_id(struct ena_ring *tx_ring, u16 req_id)
7931738cd3eSNetanel Belgazal {
794c255a34eSArthur Kiyanovski struct ena_tx_buffer *tx_info;
7951738cd3eSNetanel Belgazal
7961738cd3eSNetanel Belgazal tx_info = &tx_ring->tx_buffer_info[req_id];
7971738cd3eSNetanel Belgazal if (likely(tx_info->skb))
7981738cd3eSNetanel Belgazal return 0;
7991738cd3eSNetanel Belgazal
800548c4940SSameeh Jubran return handle_invalid_req_id(tx_ring, req_id, tx_info, false);
801548c4940SSameeh Jubran }
8021738cd3eSNetanel Belgazal
ena_clean_tx_irq(struct ena_ring * tx_ring,u32 budget)8031738cd3eSNetanel Belgazal static int ena_clean_tx_irq(struct ena_ring *tx_ring, u32 budget)
8041738cd3eSNetanel Belgazal {
8051738cd3eSNetanel Belgazal struct netdev_queue *txq;
8061738cd3eSNetanel Belgazal bool above_thresh;
8071738cd3eSNetanel Belgazal u32 tx_bytes = 0;
8081738cd3eSNetanel Belgazal u32 total_done = 0;
8091738cd3eSNetanel Belgazal u16 next_to_clean;
8101738cd3eSNetanel Belgazal u16 req_id;
8111738cd3eSNetanel Belgazal int tx_pkts = 0;
8121738cd3eSNetanel Belgazal int rc;
8131738cd3eSNetanel Belgazal
8141738cd3eSNetanel Belgazal next_to_clean = tx_ring->next_to_clean;
8151738cd3eSNetanel Belgazal txq = netdev_get_tx_queue(tx_ring->netdev, tx_ring->qid);
8161738cd3eSNetanel Belgazal
8171738cd3eSNetanel Belgazal while (tx_pkts < budget) {
8181738cd3eSNetanel Belgazal struct ena_tx_buffer *tx_info;
8191738cd3eSNetanel Belgazal struct sk_buff *skb;
8201738cd3eSNetanel Belgazal
8211738cd3eSNetanel Belgazal rc = ena_com_tx_comp_req_id_get(tx_ring->ena_com_io_cq,
8221738cd3eSNetanel Belgazal &req_id);
823c255a34eSArthur Kiyanovski if (rc) {
824c255a34eSArthur Kiyanovski if (unlikely(rc == -EINVAL))
825*26668c2dSDavid Arinzon handle_invalid_req_id(tx_ring, req_id, NULL, false);
8261738cd3eSNetanel Belgazal break;
827c255a34eSArthur Kiyanovski }
8281738cd3eSNetanel Belgazal
829c255a34eSArthur Kiyanovski /* validate that the request id points to a valid skb */
8301738cd3eSNetanel Belgazal rc = validate_tx_req_id(tx_ring, req_id);
8311738cd3eSNetanel Belgazal if (rc)
8321738cd3eSNetanel Belgazal break;
8331738cd3eSNetanel Belgazal
8341738cd3eSNetanel Belgazal tx_info = &tx_ring->tx_buffer_info[req_id];
8351738cd3eSNetanel Belgazal skb = tx_info->skb;
8361738cd3eSNetanel Belgazal
8371738cd3eSNetanel Belgazal /* prefetch skb_end_pointer() to speedup skb_shinfo(skb) */
8381738cd3eSNetanel Belgazal prefetch(&skb->end);
8391738cd3eSNetanel Belgazal
8401738cd3eSNetanel Belgazal tx_info->skb = NULL;
8411738cd3eSNetanel Belgazal tx_info->last_jiffies = 0;
8421738cd3eSNetanel Belgazal
843548c4940SSameeh Jubran ena_unmap_tx_buff(tx_ring, tx_info);
8441738cd3eSNetanel Belgazal
8451738cd3eSNetanel Belgazal netif_dbg(tx_ring->adapter, tx_done, tx_ring->netdev,
8461738cd3eSNetanel Belgazal "tx_poll: q %d skb %p completed\n", tx_ring->qid,
8471738cd3eSNetanel Belgazal skb);
8481738cd3eSNetanel Belgazal
8491738cd3eSNetanel Belgazal tx_bytes += skb->len;
8501738cd3eSNetanel Belgazal dev_kfree_skb(skb);
8511738cd3eSNetanel Belgazal tx_pkts++;
8521738cd3eSNetanel Belgazal total_done += tx_info->tx_descs;
8531738cd3eSNetanel Belgazal
854f9172498SSameeh Jubran tx_ring->free_ids[next_to_clean] = req_id;
8551738cd3eSNetanel Belgazal next_to_clean = ENA_TX_RING_IDX_NEXT(next_to_clean,
8561738cd3eSNetanel Belgazal tx_ring->ring_size);
8571738cd3eSNetanel Belgazal }
8581738cd3eSNetanel Belgazal
8591738cd3eSNetanel Belgazal tx_ring->next_to_clean = next_to_clean;
8601738cd3eSNetanel Belgazal ena_com_comp_ack(tx_ring->ena_com_io_sq, total_done);
8611738cd3eSNetanel Belgazal ena_com_update_dev_comp_head(tx_ring->ena_com_io_cq);
8621738cd3eSNetanel Belgazal
8631738cd3eSNetanel Belgazal netdev_tx_completed_queue(txq, tx_pkts, tx_bytes);
8641738cd3eSNetanel Belgazal
8651738cd3eSNetanel Belgazal netif_dbg(tx_ring->adapter, tx_done, tx_ring->netdev,
8661738cd3eSNetanel Belgazal "tx_poll: q %d done. total pkts: %d\n",
8671738cd3eSNetanel Belgazal tx_ring->qid, tx_pkts);
8681738cd3eSNetanel Belgazal
8691738cd3eSNetanel Belgazal /* need to make the rings circular update visible to
8701738cd3eSNetanel Belgazal * ena_start_xmit() before checking for netif_queue_stopped().
8711738cd3eSNetanel Belgazal */
8721738cd3eSNetanel Belgazal smp_mb();
8731738cd3eSNetanel Belgazal
874689b2bdaSArthur Kiyanovski above_thresh = ena_com_sq_have_enough_space(tx_ring->ena_com_io_sq,
875689b2bdaSArthur Kiyanovski ENA_TX_WAKEUP_THRESH);
8761738cd3eSNetanel Belgazal if (unlikely(netif_tx_queue_stopped(txq) && above_thresh)) {
8771738cd3eSNetanel Belgazal __netif_tx_lock(txq, smp_processor_id());
878689b2bdaSArthur Kiyanovski above_thresh =
879689b2bdaSArthur Kiyanovski ena_com_sq_have_enough_space(tx_ring->ena_com_io_sq,
880689b2bdaSArthur Kiyanovski ENA_TX_WAKEUP_THRESH);
881a53651ecSSameeh Jubran if (netif_tx_queue_stopped(txq) && above_thresh &&
882a53651ecSSameeh Jubran test_bit(ENA_FLAG_DEV_UP, &tx_ring->adapter->flags)) {
8831738cd3eSNetanel Belgazal netif_tx_wake_queue(txq);
88489dd735eSShay Agroskin ena_increase_stat(&tx_ring->tx_stats.queue_wakeup, 1,
88589dd735eSShay Agroskin &tx_ring->syncp);
8861738cd3eSNetanel Belgazal }
8871738cd3eSNetanel Belgazal __netif_tx_unlock(txq);
8881738cd3eSNetanel Belgazal }
8891738cd3eSNetanel Belgazal
8901738cd3eSNetanel Belgazal return tx_pkts;
8911738cd3eSNetanel Belgazal }
8921738cd3eSNetanel Belgazal
ena_alloc_skb(struct ena_ring * rx_ring,void * first_frag,u16 len)893f7d625adSDavid Arinzon static struct sk_buff *ena_alloc_skb(struct ena_ring *rx_ring, void *first_frag, u16 len)
8944265114dSNetanel Belgazal {
8954265114dSNetanel Belgazal struct sk_buff *skb;
8964265114dSNetanel Belgazal
8979e5269a9SShay Agroskin if (!first_frag)
898f7d625adSDavid Arinzon skb = napi_alloc_skb(rx_ring->napi, len);
8999e5269a9SShay Agroskin else
900f7d625adSDavid Arinzon skb = napi_build_skb(first_frag, len);
9014265114dSNetanel Belgazal
9024265114dSNetanel Belgazal if (unlikely(!skb)) {
90389dd735eSShay Agroskin ena_increase_stat(&rx_ring->rx_stats.skb_alloc_fail, 1,
90489dd735eSShay Agroskin &rx_ring->syncp);
9059e5269a9SShay Agroskin
9064265114dSNetanel Belgazal netif_dbg(rx_ring->adapter, rx_err, rx_ring->netdev,
9079e5269a9SShay Agroskin "Failed to allocate skb. first_frag %s\n",
9089e5269a9SShay Agroskin first_frag ? "provided" : "not provided");
9094265114dSNetanel Belgazal }
9104265114dSNetanel Belgazal
9114265114dSNetanel Belgazal return skb;
9124265114dSNetanel Belgazal }
9134265114dSNetanel Belgazal
ena_try_rx_buf_page_reuse(struct ena_rx_buffer * rx_info,u16 buf_len,u16 len,int pkt_offset)914f7d625adSDavid Arinzon static bool ena_try_rx_buf_page_reuse(struct ena_rx_buffer *rx_info, u16 buf_len,
915f7d625adSDavid Arinzon u16 len, int pkt_offset)
916f7d625adSDavid Arinzon {
917f7d625adSDavid Arinzon struct ena_com_buf *ena_buf = &rx_info->ena_buf;
918f7d625adSDavid Arinzon
919f7d625adSDavid Arinzon /* More than ENA_MIN_RX_BUF_SIZE left in the reused buffer
920f7d625adSDavid Arinzon * for data + headroom + tailroom.
921f7d625adSDavid Arinzon */
922f7d625adSDavid Arinzon if (SKB_DATA_ALIGN(len + pkt_offset) + ENA_MIN_RX_BUF_SIZE <= ena_buf->len) {
923f7d625adSDavid Arinzon page_ref_inc(rx_info->page);
924f7d625adSDavid Arinzon rx_info->page_offset += buf_len;
925f7d625adSDavid Arinzon ena_buf->paddr += buf_len;
926f7d625adSDavid Arinzon ena_buf->len -= buf_len;
927f7d625adSDavid Arinzon return true;
928f7d625adSDavid Arinzon }
929f7d625adSDavid Arinzon
930f7d625adSDavid Arinzon return false;
931f7d625adSDavid Arinzon }
932f7d625adSDavid Arinzon
ena_rx_skb(struct ena_ring * rx_ring,struct ena_com_rx_buf_info * ena_bufs,u32 descs,u16 * next_to_clean)9331738cd3eSNetanel Belgazal static struct sk_buff *ena_rx_skb(struct ena_ring *rx_ring,
9341738cd3eSNetanel Belgazal struct ena_com_rx_buf_info *ena_bufs,
9351738cd3eSNetanel Belgazal u32 descs,
9361738cd3eSNetanel Belgazal u16 *next_to_clean)
9371738cd3eSNetanel Belgazal {
938f7d625adSDavid Arinzon int tailroom = SKB_DATA_ALIGN(sizeof(struct skb_shared_info));
939f7d625adSDavid Arinzon bool is_xdp_loaded = ena_xdp_present_ring(rx_ring);
940ad974baeSNetanel Belgazal struct ena_rx_buffer *rx_info;
941cb3d4f98SArthur Kiyanovski struct ena_adapter *adapter;
942f7d625adSDavid Arinzon int page_offset, pkt_offset;
943f7d625adSDavid Arinzon dma_addr_t pre_reuse_paddr;
944ad974baeSNetanel Belgazal u16 len, req_id, buf = 0;
945f7d625adSDavid Arinzon bool reuse_rx_buf_page;
946a01f2cd0SShay Agroskin struct sk_buff *skb;
947f7d625adSDavid Arinzon void *buf_addr;
948f7d625adSDavid Arinzon int buf_offset;
949f7d625adSDavid Arinzon u16 buf_len;
9501738cd3eSNetanel Belgazal
951ad974baeSNetanel Belgazal len = ena_bufs[buf].len;
952ad974baeSNetanel Belgazal req_id = ena_bufs[buf].req_id;
95330623e1eSArthur Kiyanovski
954ad974baeSNetanel Belgazal rx_info = &rx_ring->rx_buffer_info[req_id];
955ad974baeSNetanel Belgazal
9561738cd3eSNetanel Belgazal if (unlikely(!rx_info->page)) {
957cb3d4f98SArthur Kiyanovski adapter = rx_ring->adapter;
958cb3d4f98SArthur Kiyanovski netif_err(adapter, rx_err, rx_ring->netdev,
959cb3d4f98SArthur Kiyanovski "Page is NULL. qid %u req_id %u\n", rx_ring->qid, req_id);
960cb3d4f98SArthur Kiyanovski ena_increase_stat(&rx_ring->rx_stats.bad_req_id, 1, &rx_ring->syncp);
9619fe890ccSArthur Kiyanovski ena_reset_device(adapter, ENA_REGS_RESET_INV_RX_REQ_ID);
9621738cd3eSNetanel Belgazal return NULL;
9631738cd3eSNetanel Belgazal }
9641738cd3eSNetanel Belgazal
9651738cd3eSNetanel Belgazal netif_dbg(rx_ring->adapter, rx_status, rx_ring->netdev,
9661738cd3eSNetanel Belgazal "rx_info %p page %p\n",
9671738cd3eSNetanel Belgazal rx_info, rx_info->page);
9681738cd3eSNetanel Belgazal
969f7d625adSDavid Arinzon buf_offset = rx_info->buf_offset;
970f7d625adSDavid Arinzon pkt_offset = buf_offset - rx_ring->rx_headroom;
9719e5269a9SShay Agroskin page_offset = rx_info->page_offset;
972f7d625adSDavid Arinzon buf_addr = page_address(rx_info->page) + page_offset;
9731738cd3eSNetanel Belgazal
9741738cd3eSNetanel Belgazal if (len <= rx_ring->rx_copybreak) {
975f7d625adSDavid Arinzon skb = ena_alloc_skb(rx_ring, NULL, len);
9764265114dSNetanel Belgazal if (unlikely(!skb))
9771738cd3eSNetanel Belgazal return NULL;
9781738cd3eSNetanel Belgazal
979f7d625adSDavid Arinzon skb_copy_to_linear_data(skb, buf_addr + buf_offset, len);
9801738cd3eSNetanel Belgazal dma_sync_single_for_device(rx_ring->dev,
981f7d625adSDavid Arinzon dma_unmap_addr(&rx_info->ena_buf, paddr) + pkt_offset,
9821738cd3eSNetanel Belgazal len,
9831738cd3eSNetanel Belgazal DMA_FROM_DEVICE);
9841738cd3eSNetanel Belgazal
9851738cd3eSNetanel Belgazal skb_put(skb, len);
986f7d625adSDavid Arinzon netif_dbg(rx_ring->adapter, rx_status, rx_ring->netdev,
987f7d625adSDavid Arinzon "RX allocated small packet. len %d.\n", skb->len);
9881738cd3eSNetanel Belgazal skb->protocol = eth_type_trans(skb, rx_ring->netdev);
989f9172498SSameeh Jubran rx_ring->free_ids[*next_to_clean] = req_id;
9901738cd3eSNetanel Belgazal *next_to_clean = ENA_RX_RING_IDX_ADD(*next_to_clean, descs,
9911738cd3eSNetanel Belgazal rx_ring->ring_size);
9921738cd3eSNetanel Belgazal return skb;
9931738cd3eSNetanel Belgazal }
9941738cd3eSNetanel Belgazal
995f7d625adSDavid Arinzon buf_len = SKB_DATA_ALIGN(len + buf_offset + tailroom);
9969e5269a9SShay Agroskin
997f7d625adSDavid Arinzon /* If XDP isn't loaded try to reuse part of the RX buffer */
998f7d625adSDavid Arinzon reuse_rx_buf_page = !is_xdp_loaded &&
999f7d625adSDavid Arinzon ena_try_rx_buf_page_reuse(rx_info, buf_len, len, pkt_offset);
1000f7d625adSDavid Arinzon
1001f7d625adSDavid Arinzon if (!reuse_rx_buf_page)
1002f7d625adSDavid Arinzon ena_unmap_rx_buff_attrs(rx_ring, rx_info, DMA_ATTR_SKIP_CPU_SYNC);
1003f7d625adSDavid Arinzon
1004f7d625adSDavid Arinzon skb = ena_alloc_skb(rx_ring, buf_addr, buf_len);
10054265114dSNetanel Belgazal if (unlikely(!skb))
10061738cd3eSNetanel Belgazal return NULL;
10071738cd3eSNetanel Belgazal
10089e5269a9SShay Agroskin /* Populate skb's linear part */
1009f7d625adSDavid Arinzon skb_reserve(skb, buf_offset);
10109e5269a9SShay Agroskin skb_put(skb, len);
10119e5269a9SShay Agroskin skb->protocol = eth_type_trans(skb, rx_ring->netdev);
10129e5269a9SShay Agroskin
10131738cd3eSNetanel Belgazal do {
10141738cd3eSNetanel Belgazal netif_dbg(rx_ring->adapter, rx_status, rx_ring->netdev,
1015bf2746e8SShay Agroskin "RX skb updated. len %d. data_len %d\n",
10161738cd3eSNetanel Belgazal skb->len, skb->data_len);
10171738cd3eSNetanel Belgazal
1018f7d625adSDavid Arinzon if (!reuse_rx_buf_page)
10191738cd3eSNetanel Belgazal rx_info->page = NULL;
1020ad974baeSNetanel Belgazal
1021f9172498SSameeh Jubran rx_ring->free_ids[*next_to_clean] = req_id;
10221738cd3eSNetanel Belgazal *next_to_clean =
10231738cd3eSNetanel Belgazal ENA_RX_RING_IDX_NEXT(*next_to_clean,
10241738cd3eSNetanel Belgazal rx_ring->ring_size);
10251738cd3eSNetanel Belgazal if (likely(--descs == 0))
10261738cd3eSNetanel Belgazal break;
1027ad974baeSNetanel Belgazal
1028ad974baeSNetanel Belgazal buf++;
1029ad974baeSNetanel Belgazal len = ena_bufs[buf].len;
1030ad974baeSNetanel Belgazal req_id = ena_bufs[buf].req_id;
103130623e1eSArthur Kiyanovski
1032ad974baeSNetanel Belgazal rx_info = &rx_ring->rx_buffer_info[req_id];
10339e5269a9SShay Agroskin
1034f7d625adSDavid Arinzon /* rx_info->buf_offset includes rx_ring->rx_headroom */
1035f7d625adSDavid Arinzon buf_offset = rx_info->buf_offset;
1036f7d625adSDavid Arinzon pkt_offset = buf_offset - rx_ring->rx_headroom;
1037f7d625adSDavid Arinzon buf_len = SKB_DATA_ALIGN(len + buf_offset + tailroom);
1038f7d625adSDavid Arinzon page_offset = rx_info->page_offset;
1039f7d625adSDavid Arinzon
1040f7d625adSDavid Arinzon pre_reuse_paddr = dma_unmap_addr(&rx_info->ena_buf, paddr);
1041f7d625adSDavid Arinzon
1042f7d625adSDavid Arinzon reuse_rx_buf_page = !is_xdp_loaded &&
1043f7d625adSDavid Arinzon ena_try_rx_buf_page_reuse(rx_info, buf_len, len, pkt_offset);
1044f7d625adSDavid Arinzon
1045f7d625adSDavid Arinzon dma_sync_single_for_cpu(rx_ring->dev,
1046f7d625adSDavid Arinzon pre_reuse_paddr + pkt_offset,
1047f7d625adSDavid Arinzon len,
1048f7d625adSDavid Arinzon DMA_FROM_DEVICE);
1049f7d625adSDavid Arinzon
1050f7d625adSDavid Arinzon if (!reuse_rx_buf_page)
1051*26668c2dSDavid Arinzon ena_unmap_rx_buff_attrs(rx_ring, rx_info, DMA_ATTR_SKIP_CPU_SYNC);
10529e5269a9SShay Agroskin
10539e5269a9SShay Agroskin skb_add_rx_frag(skb, skb_shinfo(skb)->nr_frags, rx_info->page,
1054f7d625adSDavid Arinzon page_offset + buf_offset, len, buf_len);
10559e5269a9SShay Agroskin
10561738cd3eSNetanel Belgazal } while (1);
10571738cd3eSNetanel Belgazal
10581738cd3eSNetanel Belgazal return skb;
10591738cd3eSNetanel Belgazal }
10601738cd3eSNetanel Belgazal
10611738cd3eSNetanel Belgazal /* ena_rx_checksum - indicate in skb if hw indicated a good cksum
10621738cd3eSNetanel Belgazal * @adapter: structure containing adapter specific data
10631738cd3eSNetanel Belgazal * @ena_rx_ctx: received packet context/metadata
10641738cd3eSNetanel Belgazal * @skb: skb currently being received and modified
10651738cd3eSNetanel Belgazal */
ena_rx_checksum(struct ena_ring * rx_ring,struct ena_com_rx_ctx * ena_rx_ctx,struct sk_buff * skb)1066c2b54204SSameeh Jubran static void ena_rx_checksum(struct ena_ring *rx_ring,
10671738cd3eSNetanel Belgazal struct ena_com_rx_ctx *ena_rx_ctx,
10681738cd3eSNetanel Belgazal struct sk_buff *skb)
10691738cd3eSNetanel Belgazal {
10701738cd3eSNetanel Belgazal /* Rx csum disabled */
10711738cd3eSNetanel Belgazal if (unlikely(!(rx_ring->netdev->features & NETIF_F_RXCSUM))) {
10721738cd3eSNetanel Belgazal skb->ip_summed = CHECKSUM_NONE;
10731738cd3eSNetanel Belgazal return;
10741738cd3eSNetanel Belgazal }
10751738cd3eSNetanel Belgazal
10761738cd3eSNetanel Belgazal /* For fragmented packets the checksum isn't valid */
10771738cd3eSNetanel Belgazal if (ena_rx_ctx->frag) {
10781738cd3eSNetanel Belgazal skb->ip_summed = CHECKSUM_NONE;
10791738cd3eSNetanel Belgazal return;
10801738cd3eSNetanel Belgazal }
10811738cd3eSNetanel Belgazal
10821738cd3eSNetanel Belgazal /* if IP and error */
10831738cd3eSNetanel Belgazal if (unlikely((ena_rx_ctx->l3_proto == ENA_ETH_IO_L3_PROTO_IPV4) &&
10841738cd3eSNetanel Belgazal (ena_rx_ctx->l3_csum_err))) {
10851738cd3eSNetanel Belgazal /* ipv4 checksum error */
10861738cd3eSNetanel Belgazal skb->ip_summed = CHECKSUM_NONE;
1087d0e8831dSArthur Kiyanovski ena_increase_stat(&rx_ring->rx_stats.csum_bad, 1,
108889dd735eSShay Agroskin &rx_ring->syncp);
1089cd7aea18SNetanel Belgazal netif_dbg(rx_ring->adapter, rx_err, rx_ring->netdev,
10901738cd3eSNetanel Belgazal "RX IPv4 header checksum error\n");
10911738cd3eSNetanel Belgazal return;
10921738cd3eSNetanel Belgazal }
10931738cd3eSNetanel Belgazal
10941738cd3eSNetanel Belgazal /* if TCP/UDP */
10951738cd3eSNetanel Belgazal if (likely((ena_rx_ctx->l4_proto == ENA_ETH_IO_L4_PROTO_TCP) ||
10961738cd3eSNetanel Belgazal (ena_rx_ctx->l4_proto == ENA_ETH_IO_L4_PROTO_UDP))) {
10971738cd3eSNetanel Belgazal if (unlikely(ena_rx_ctx->l4_csum_err)) {
10981738cd3eSNetanel Belgazal /* TCP/UDP checksum error */
1099d0e8831dSArthur Kiyanovski ena_increase_stat(&rx_ring->rx_stats.csum_bad, 1,
110089dd735eSShay Agroskin &rx_ring->syncp);
1101cd7aea18SNetanel Belgazal netif_dbg(rx_ring->adapter, rx_err, rx_ring->netdev,
11021738cd3eSNetanel Belgazal "RX L4 checksum error\n");
11031738cd3eSNetanel Belgazal skb->ip_summed = CHECKSUM_NONE;
11041738cd3eSNetanel Belgazal return;
11051738cd3eSNetanel Belgazal }
11061738cd3eSNetanel Belgazal
1107cb36bb36SArthur Kiyanovski if (likely(ena_rx_ctx->l4_csum_checked)) {
11081738cd3eSNetanel Belgazal skb->ip_summed = CHECKSUM_UNNECESSARY;
110989dd735eSShay Agroskin ena_increase_stat(&rx_ring->rx_stats.csum_good, 1,
111089dd735eSShay Agroskin &rx_ring->syncp);
1111cb36bb36SArthur Kiyanovski } else {
111289dd735eSShay Agroskin ena_increase_stat(&rx_ring->rx_stats.csum_unchecked, 1,
111389dd735eSShay Agroskin &rx_ring->syncp);
1114cb36bb36SArthur Kiyanovski skb->ip_summed = CHECKSUM_NONE;
11151738cd3eSNetanel Belgazal }
1116cb36bb36SArthur Kiyanovski } else {
1117cb36bb36SArthur Kiyanovski skb->ip_summed = CHECKSUM_NONE;
1118cb36bb36SArthur Kiyanovski return;
1119cb36bb36SArthur Kiyanovski }
1120cb36bb36SArthur Kiyanovski
11211738cd3eSNetanel Belgazal }
11221738cd3eSNetanel Belgazal
ena_set_rx_hash(struct ena_ring * rx_ring,struct ena_com_rx_ctx * ena_rx_ctx,struct sk_buff * skb)11231738cd3eSNetanel Belgazal static void ena_set_rx_hash(struct ena_ring *rx_ring,
11241738cd3eSNetanel Belgazal struct ena_com_rx_ctx *ena_rx_ctx,
11251738cd3eSNetanel Belgazal struct sk_buff *skb)
11261738cd3eSNetanel Belgazal {
11271738cd3eSNetanel Belgazal enum pkt_hash_types hash_type;
11281738cd3eSNetanel Belgazal
11291738cd3eSNetanel Belgazal if (likely(rx_ring->netdev->features & NETIF_F_RXHASH)) {
11301738cd3eSNetanel Belgazal if (likely((ena_rx_ctx->l4_proto == ENA_ETH_IO_L4_PROTO_TCP) ||
11311738cd3eSNetanel Belgazal (ena_rx_ctx->l4_proto == ENA_ETH_IO_L4_PROTO_UDP)))
11321738cd3eSNetanel Belgazal
11331738cd3eSNetanel Belgazal hash_type = PKT_HASH_TYPE_L4;
11341738cd3eSNetanel Belgazal else
11351738cd3eSNetanel Belgazal hash_type = PKT_HASH_TYPE_NONE;
11361738cd3eSNetanel Belgazal
11371738cd3eSNetanel Belgazal /* Override hash type if the packet is fragmented */
11381738cd3eSNetanel Belgazal if (ena_rx_ctx->frag)
11391738cd3eSNetanel Belgazal hash_type = PKT_HASH_TYPE_NONE;
11401738cd3eSNetanel Belgazal
11411738cd3eSNetanel Belgazal skb_set_hash(skb, ena_rx_ctx->hash, hash_type);
11421738cd3eSNetanel Belgazal }
11431738cd3eSNetanel Belgazal }
11441738cd3eSNetanel Belgazal
ena_xdp_handle_buff(struct ena_ring * rx_ring,struct xdp_buff * xdp,u16 num_descs)11450cb2021bSDavid Arinzon static int ena_xdp_handle_buff(struct ena_ring *rx_ring, struct xdp_buff *xdp, u16 num_descs)
1146838c93dcSSameeh Jubran {
1147838c93dcSSameeh Jubran struct ena_rx_buffer *rx_info;
1148838c93dcSSameeh Jubran int ret;
1149838c93dcSSameeh Jubran
11500cb2021bSDavid Arinzon /* XDP multi-buffer packets not supported */
11510cb2021bSDavid Arinzon if (unlikely(num_descs > 1)) {
11520cb2021bSDavid Arinzon netdev_err_once(rx_ring->adapter->netdev,
11530cb2021bSDavid Arinzon "xdp: dropped unsupported multi-buffer packets\n");
11540cb2021bSDavid Arinzon ena_increase_stat(&rx_ring->rx_stats.xdp_drop, 1, &rx_ring->syncp);
11550cb2021bSDavid Arinzon return ENA_XDP_DROP;
11560cb2021bSDavid Arinzon }
11570cb2021bSDavid Arinzon
1158838c93dcSSameeh Jubran rx_info = &rx_ring->rx_buffer_info[rx_ring->ena_bufs[0].req_id];
1159be9df4afSLorenzo Bianconi xdp_prepare_buff(xdp, page_address(rx_info->page),
1160f7d625adSDavid Arinzon rx_info->buf_offset,
1161be9df4afSLorenzo Bianconi rx_ring->ena_bufs[0].len, false);
1162838c93dcSSameeh Jubran
1163e8223eefSShay Agroskin ret = ena_xdp_execute(rx_ring, xdp);
1164838c93dcSSameeh Jubran
1165838c93dcSSameeh Jubran /* The xdp program might expand the headers */
116659811faaSDavid Arinzon if (ret == ENA_XDP_PASS) {
1167f7d625adSDavid Arinzon rx_info->buf_offset = xdp->data - xdp->data_hard_start;
1168838c93dcSSameeh Jubran rx_ring->ena_bufs[0].len = xdp->data_end - xdp->data;
1169838c93dcSSameeh Jubran }
1170838c93dcSSameeh Jubran
1171838c93dcSSameeh Jubran return ret;
1172838c93dcSSameeh Jubran }
1173c891d767SDavid Arinzon
11741738cd3eSNetanel Belgazal /* ena_clean_rx_irq - Cleanup RX irq
11751738cd3eSNetanel Belgazal * @rx_ring: RX ring to clean
11761738cd3eSNetanel Belgazal * @napi: napi handler
11771738cd3eSNetanel Belgazal * @budget: how many packets driver is allowed to clean
11781738cd3eSNetanel Belgazal *
11791738cd3eSNetanel Belgazal * Returns the number of cleaned buffers.
11801738cd3eSNetanel Belgazal */
ena_clean_rx_irq(struct ena_ring * rx_ring,struct napi_struct * napi,u32 budget)11811738cd3eSNetanel Belgazal static int ena_clean_rx_irq(struct ena_ring *rx_ring, struct napi_struct *napi,
11821738cd3eSNetanel Belgazal u32 budget)
11831738cd3eSNetanel Belgazal {
11841738cd3eSNetanel Belgazal u16 next_to_clean = rx_ring->next_to_clean;
11851738cd3eSNetanel Belgazal struct ena_com_rx_ctx ena_rx_ctx;
118668f236dfSArthur Kiyanovski struct ena_rx_buffer *rx_info;
11871738cd3eSNetanel Belgazal struct ena_adapter *adapter;
1188548c4940SSameeh Jubran u32 res_budget, work_done;
1189838c93dcSSameeh Jubran int rx_copybreak_pkt = 0;
1190838c93dcSSameeh Jubran int refill_threshold;
11911738cd3eSNetanel Belgazal struct sk_buff *skb;
11921738cd3eSNetanel Belgazal int refill_required;
1193838c93dcSSameeh Jubran struct xdp_buff xdp;
1194a318c70aSShay Agroskin int xdp_flags = 0;
11951738cd3eSNetanel Belgazal int total_len = 0;
1196838c93dcSSameeh Jubran int xdp_verdict;
11970116e02cSDavid Arinzon u8 pkt_offset;
1198838c93dcSSameeh Jubran int rc = 0;
1199ad974baeSNetanel Belgazal int i;
12001738cd3eSNetanel Belgazal
12011738cd3eSNetanel Belgazal netif_dbg(rx_ring->adapter, rx_status, rx_ring->netdev,
12021738cd3eSNetanel Belgazal "%s qid %d\n", __func__, rx_ring->qid);
12031738cd3eSNetanel Belgazal res_budget = budget;
120443b5169dSLorenzo Bianconi xdp_init_buff(&xdp, ENA_PAGE_SIZE, &rx_ring->xdp_rxq);
1205548c4940SSameeh Jubran
12061738cd3eSNetanel Belgazal do {
120759811faaSDavid Arinzon xdp_verdict = ENA_XDP_PASS;
1208838c93dcSSameeh Jubran skb = NULL;
12091738cd3eSNetanel Belgazal ena_rx_ctx.ena_bufs = rx_ring->ena_bufs;
12101738cd3eSNetanel Belgazal ena_rx_ctx.max_bufs = rx_ring->sgl_size;
12111738cd3eSNetanel Belgazal ena_rx_ctx.descs = 0;
121268f236dfSArthur Kiyanovski ena_rx_ctx.pkt_offset = 0;
12131738cd3eSNetanel Belgazal rc = ena_com_rx_pkt(rx_ring->ena_com_io_cq,
12141738cd3eSNetanel Belgazal rx_ring->ena_com_io_sq,
12151738cd3eSNetanel Belgazal &ena_rx_ctx);
12161738cd3eSNetanel Belgazal if (unlikely(rc))
12171738cd3eSNetanel Belgazal goto error;
12181738cd3eSNetanel Belgazal
12191738cd3eSNetanel Belgazal if (unlikely(ena_rx_ctx.descs == 0))
12201738cd3eSNetanel Belgazal break;
12211738cd3eSNetanel Belgazal
12221396d314SShay Agroskin /* First descriptor might have an offset set by the device */
122368f236dfSArthur Kiyanovski rx_info = &rx_ring->rx_buffer_info[rx_ring->ena_bufs[0].req_id];
12240116e02cSDavid Arinzon pkt_offset = ena_rx_ctx.pkt_offset;
12250116e02cSDavid Arinzon rx_info->buf_offset += pkt_offset;
122668f236dfSArthur Kiyanovski
12271738cd3eSNetanel Belgazal netif_dbg(rx_ring->adapter, rx_status, rx_ring->netdev,
12281738cd3eSNetanel Belgazal "rx_poll: q %d got packet from ena. descs #: %d l3 proto %d l4 proto %d hash: %x\n",
12291738cd3eSNetanel Belgazal rx_ring->qid, ena_rx_ctx.descs, ena_rx_ctx.l3_proto,
12301738cd3eSNetanel Belgazal ena_rx_ctx.l4_proto, ena_rx_ctx.hash);
12311738cd3eSNetanel Belgazal
12320116e02cSDavid Arinzon dma_sync_single_for_cpu(rx_ring->dev,
12330116e02cSDavid Arinzon dma_unmap_addr(&rx_info->ena_buf, paddr) + pkt_offset,
12340116e02cSDavid Arinzon rx_ring->ena_bufs[0].len,
12350116e02cSDavid Arinzon DMA_FROM_DEVICE);
12360116e02cSDavid Arinzon
1237838c93dcSSameeh Jubran if (ena_xdp_present_ring(rx_ring))
12380cb2021bSDavid Arinzon xdp_verdict = ena_xdp_handle_buff(rx_ring, &xdp, ena_rx_ctx.descs);
1239838c93dcSSameeh Jubran
12401738cd3eSNetanel Belgazal /* allocate skb and fill it */
124159811faaSDavid Arinzon if (xdp_verdict == ENA_XDP_PASS)
1242838c93dcSSameeh Jubran skb = ena_rx_skb(rx_ring,
1243838c93dcSSameeh Jubran rx_ring->ena_bufs,
1244838c93dcSSameeh Jubran ena_rx_ctx.descs,
12451738cd3eSNetanel Belgazal &next_to_clean);
12461738cd3eSNetanel Belgazal
12471738cd3eSNetanel Belgazal if (unlikely(!skb)) {
1248ad974baeSNetanel Belgazal for (i = 0; i < ena_rx_ctx.descs; i++) {
1249a318c70aSShay Agroskin int req_id = rx_ring->ena_bufs[i].req_id;
1250a318c70aSShay Agroskin
1251a318c70aSShay Agroskin rx_ring->free_ids[next_to_clean] = req_id;
1252ad974baeSNetanel Belgazal next_to_clean =
1253ad974baeSNetanel Belgazal ENA_RX_RING_IDX_NEXT(next_to_clean,
12541738cd3eSNetanel Belgazal rx_ring->ring_size);
1255a318c70aSShay Agroskin
1256a318c70aSShay Agroskin /* Packets was passed for transmission, unmap it
1257a318c70aSShay Agroskin * from RX side.
1258a318c70aSShay Agroskin */
125959811faaSDavid Arinzon if (xdp_verdict & ENA_XDP_FORWARDED) {
1260f7d625adSDavid Arinzon ena_unmap_rx_buff_attrs(rx_ring,
1261f7d625adSDavid Arinzon &rx_ring->rx_buffer_info[req_id],
12620116e02cSDavid Arinzon DMA_ATTR_SKIP_CPU_SYNC);
1263a318c70aSShay Agroskin rx_ring->rx_buffer_info[req_id].page = NULL;
1264a318c70aSShay Agroskin }
1265ad974baeSNetanel Belgazal }
126659811faaSDavid Arinzon if (xdp_verdict != ENA_XDP_PASS) {
1267a318c70aSShay Agroskin xdp_flags |= xdp_verdict;
1268c7f5e34dSDavid Arinzon total_len += ena_rx_ctx.ena_bufs[0].len;
12693921a81cSSameeh Jubran res_budget--;
1270838c93dcSSameeh Jubran continue;
12713921a81cSSameeh Jubran }
12721738cd3eSNetanel Belgazal break;
12731738cd3eSNetanel Belgazal }
12741738cd3eSNetanel Belgazal
12751738cd3eSNetanel Belgazal ena_rx_checksum(rx_ring, &ena_rx_ctx, skb);
12761738cd3eSNetanel Belgazal
12771738cd3eSNetanel Belgazal ena_set_rx_hash(rx_ring, &ena_rx_ctx, skb);
12781738cd3eSNetanel Belgazal
12791738cd3eSNetanel Belgazal skb_record_rx_queue(skb, rx_ring->qid);
12801738cd3eSNetanel Belgazal
12819e5269a9SShay Agroskin if (rx_ring->ena_bufs[0].len <= rx_ring->rx_copybreak)
12821738cd3eSNetanel Belgazal rx_copybreak_pkt++;
12839e5269a9SShay Agroskin
12841738cd3eSNetanel Belgazal total_len += skb->len;
12859e5269a9SShay Agroskin
12869e5269a9SShay Agroskin napi_gro_receive(napi, skb);
12871738cd3eSNetanel Belgazal
12881738cd3eSNetanel Belgazal res_budget--;
12891738cd3eSNetanel Belgazal } while (likely(res_budget));
12901738cd3eSNetanel Belgazal
12911738cd3eSNetanel Belgazal work_done = budget - res_budget;
12921738cd3eSNetanel Belgazal rx_ring->per_napi_packets += work_done;
12931738cd3eSNetanel Belgazal u64_stats_update_begin(&rx_ring->syncp);
12941738cd3eSNetanel Belgazal rx_ring->rx_stats.bytes += total_len;
12951738cd3eSNetanel Belgazal rx_ring->rx_stats.cnt += work_done;
12961738cd3eSNetanel Belgazal rx_ring->rx_stats.rx_copybreak_pkt += rx_copybreak_pkt;
12971738cd3eSNetanel Belgazal u64_stats_update_end(&rx_ring->syncp);
12981738cd3eSNetanel Belgazal
12991738cd3eSNetanel Belgazal rx_ring->next_to_clean = next_to_clean;
13001738cd3eSNetanel Belgazal
13017cfe9a55SArthur Kiyanovski refill_required = ena_com_free_q_entries(rx_ring->ena_com_io_sq);
13020574bb80SArthur Kiyanovski refill_threshold =
13030574bb80SArthur Kiyanovski min_t(int, rx_ring->ring_size / ENA_RX_REFILL_THRESH_DIVIDER,
13040574bb80SArthur Kiyanovski ENA_RX_REFILL_THRESH_PACKET);
13051738cd3eSNetanel Belgazal
13061738cd3eSNetanel Belgazal /* Optimization, try to batch new rx buffers */
13071738cd3eSNetanel Belgazal if (refill_required > refill_threshold) {
13081738cd3eSNetanel Belgazal ena_com_update_dev_comp_head(rx_ring->ena_com_io_cq);
13091738cd3eSNetanel Belgazal ena_refill_rx_bufs(rx_ring, refill_required);
13101738cd3eSNetanel Belgazal }
13111738cd3eSNetanel Belgazal
131259811faaSDavid Arinzon if (xdp_flags & ENA_XDP_REDIRECT)
1313a318c70aSShay Agroskin xdp_do_flush_map();
1314a318c70aSShay Agroskin
13151738cd3eSNetanel Belgazal return work_done;
13161738cd3eSNetanel Belgazal
13171738cd3eSNetanel Belgazal error:
13186f411fb5SSebastian Andrzej Siewior if (xdp_flags & ENA_XDP_REDIRECT)
13196f411fb5SSebastian Andrzej Siewior xdp_do_flush();
13206f411fb5SSebastian Andrzej Siewior
13211738cd3eSNetanel Belgazal adapter = netdev_priv(rx_ring->netdev);
13221738cd3eSNetanel Belgazal
13235b7022cfSShay Agroskin if (rc == -ENOSPC) {
1324*26668c2dSDavid Arinzon ena_increase_stat(&rx_ring->rx_stats.bad_desc_num, 1, &rx_ring->syncp);
13259fe890ccSArthur Kiyanovski ena_reset_device(adapter, ENA_REGS_RESET_TOO_MANY_RX_DESCS);
13265b7022cfSShay Agroskin } else {
132789dd735eSShay Agroskin ena_increase_stat(&rx_ring->rx_stats.bad_req_id, 1,
132889dd735eSShay Agroskin &rx_ring->syncp);
13299fe890ccSArthur Kiyanovski ena_reset_device(adapter, ENA_REGS_RESET_INV_RX_REQ_ID);
13305b7022cfSShay Agroskin }
13311738cd3eSNetanel Belgazal return 0;
13321738cd3eSNetanel Belgazal }
13331738cd3eSNetanel Belgazal
ena_dim_work(struct work_struct * w)1334282faf61SArthur Kiyanovski static void ena_dim_work(struct work_struct *w)
13351738cd3eSNetanel Belgazal {
1336282faf61SArthur Kiyanovski struct dim *dim = container_of(w, struct dim, work);
1337282faf61SArthur Kiyanovski struct dim_cq_moder cur_moder =
1338282faf61SArthur Kiyanovski net_dim_get_rx_moderation(dim->mode, dim->profile_ix);
1339282faf61SArthur Kiyanovski struct ena_napi *ena_napi = container_of(dim, struct ena_napi, dim);
13401738cd3eSNetanel Belgazal
1341282faf61SArthur Kiyanovski ena_napi->rx_ring->smoothed_interval = cur_moder.usec;
1342282faf61SArthur Kiyanovski dim->state = DIM_START_MEASURE;
1343282faf61SArthur Kiyanovski }
1344282faf61SArthur Kiyanovski
ena_adjust_adaptive_rx_intr_moderation(struct ena_napi * ena_napi)1345282faf61SArthur Kiyanovski static void ena_adjust_adaptive_rx_intr_moderation(struct ena_napi *ena_napi)
1346282faf61SArthur Kiyanovski {
1347282faf61SArthur Kiyanovski struct dim_sample dim_sample;
1348282faf61SArthur Kiyanovski struct ena_ring *rx_ring = ena_napi->rx_ring;
1349282faf61SArthur Kiyanovski
1350282faf61SArthur Kiyanovski if (!rx_ring->per_napi_packets)
1351282faf61SArthur Kiyanovski return;
1352282faf61SArthur Kiyanovski
1353282faf61SArthur Kiyanovski rx_ring->non_empty_napi_events++;
1354282faf61SArthur Kiyanovski
1355282faf61SArthur Kiyanovski dim_update_sample(rx_ring->non_empty_napi_events,
1356282faf61SArthur Kiyanovski rx_ring->rx_stats.cnt,
1357282faf61SArthur Kiyanovski rx_ring->rx_stats.bytes,
1358282faf61SArthur Kiyanovski &dim_sample);
1359282faf61SArthur Kiyanovski
1360282faf61SArthur Kiyanovski net_dim(&ena_napi->dim, dim_sample);
1361282faf61SArthur Kiyanovski
13621738cd3eSNetanel Belgazal rx_ring->per_napi_packets = 0;
13631738cd3eSNetanel Belgazal }
13641738cd3eSNetanel Belgazal
ena_unmask_interrupt(struct ena_ring * tx_ring,struct ena_ring * rx_ring)1365c891d767SDavid Arinzon void ena_unmask_interrupt(struct ena_ring *tx_ring,
1366418df30fSNetanel Belgazal struct ena_ring *rx_ring)
1367418df30fSNetanel Belgazal {
1368e712f3e4SDavid Arinzon u32 rx_interval = tx_ring->smoothed_interval;
1369418df30fSNetanel Belgazal struct ena_eth_io_intr_reg intr_reg;
1370e712f3e4SDavid Arinzon
1371548c4940SSameeh Jubran /* Rx ring can be NULL when for XDP tx queues which don't have an
1372548c4940SSameeh Jubran * accompanying rx_ring pair.
1373548c4940SSameeh Jubran */
1374548c4940SSameeh Jubran if (rx_ring)
1375548c4940SSameeh Jubran rx_interval = ena_com_get_adaptive_moderation_enabled(rx_ring->ena_dev) ?
13767b8a2878SArthur Kiyanovski rx_ring->smoothed_interval :
13777b8a2878SArthur Kiyanovski ena_com_get_nonadaptive_moderation_interval_rx(rx_ring->ena_dev);
1378418df30fSNetanel Belgazal
1379418df30fSNetanel Belgazal /* Update intr register: rx intr delay,
1380418df30fSNetanel Belgazal * tx intr delay and interrupt unmask
1381418df30fSNetanel Belgazal */
1382418df30fSNetanel Belgazal ena_com_update_intr_reg(&intr_reg,
13837b8a2878SArthur Kiyanovski rx_interval,
1384418df30fSNetanel Belgazal tx_ring->smoothed_interval,
1385418df30fSNetanel Belgazal true);
1386418df30fSNetanel Belgazal
138789dd735eSShay Agroskin ena_increase_stat(&tx_ring->tx_stats.unmask_interrupt, 1,
138889dd735eSShay Agroskin &tx_ring->syncp);
1389bf2746e8SShay Agroskin
1390418df30fSNetanel Belgazal /* It is a shared MSI-X.
1391418df30fSNetanel Belgazal * Tx and Rx CQ have pointer to it.
1392418df30fSNetanel Belgazal * So we use one of them to reach the intr reg
1393548c4940SSameeh Jubran * The Tx ring is used because the rx_ring is NULL for XDP queues
1394418df30fSNetanel Belgazal */
1395548c4940SSameeh Jubran ena_com_unmask_intr(tx_ring->ena_com_io_cq, &intr_reg);
1396418df30fSNetanel Belgazal }
1397418df30fSNetanel Belgazal
ena_update_ring_numa_node(struct ena_ring * tx_ring,struct ena_ring * rx_ring)1398c891d767SDavid Arinzon void ena_update_ring_numa_node(struct ena_ring *tx_ring,
13991738cd3eSNetanel Belgazal struct ena_ring *rx_ring)
14001738cd3eSNetanel Belgazal {
14011738cd3eSNetanel Belgazal int cpu = get_cpu();
14021738cd3eSNetanel Belgazal int numa_node;
14031738cd3eSNetanel Belgazal
14041738cd3eSNetanel Belgazal /* Check only one ring since the 2 rings are running on the same cpu */
14051738cd3eSNetanel Belgazal if (likely(tx_ring->cpu == cpu))
14061738cd3eSNetanel Belgazal goto out;
14071738cd3eSNetanel Belgazal
1408a8ee104fSDavid Arinzon tx_ring->cpu = cpu;
1409a8ee104fSDavid Arinzon if (rx_ring)
1410a8ee104fSDavid Arinzon rx_ring->cpu = cpu;
1411a8ee104fSDavid Arinzon
14121738cd3eSNetanel Belgazal numa_node = cpu_to_node(cpu);
1413a8ee104fSDavid Arinzon
1414a8ee104fSDavid Arinzon if (likely(tx_ring->numa_node == numa_node))
1415a8ee104fSDavid Arinzon goto out;
1416a8ee104fSDavid Arinzon
14171738cd3eSNetanel Belgazal put_cpu();
14181738cd3eSNetanel Belgazal
14191738cd3eSNetanel Belgazal if (numa_node != NUMA_NO_NODE) {
14201738cd3eSNetanel Belgazal ena_com_update_numa_node(tx_ring->ena_com_io_cq, numa_node);
1421a8ee104fSDavid Arinzon tx_ring->numa_node = numa_node;
1422a8ee104fSDavid Arinzon if (rx_ring) {
1423a8ee104fSDavid Arinzon rx_ring->numa_node = numa_node;
1424548c4940SSameeh Jubran ena_com_update_numa_node(rx_ring->ena_com_io_cq,
1425548c4940SSameeh Jubran numa_node);
14261738cd3eSNetanel Belgazal }
1427a8ee104fSDavid Arinzon }
14281738cd3eSNetanel Belgazal
14291738cd3eSNetanel Belgazal return;
14301738cd3eSNetanel Belgazal out:
14311738cd3eSNetanel Belgazal put_cpu();
14321738cd3eSNetanel Belgazal }
14331738cd3eSNetanel Belgazal
ena_io_poll(struct napi_struct * napi,int budget)14341738cd3eSNetanel Belgazal static int ena_io_poll(struct napi_struct *napi, int budget)
14351738cd3eSNetanel Belgazal {
14361738cd3eSNetanel Belgazal struct ena_napi *ena_napi = container_of(napi, struct ena_napi, napi);
14371738cd3eSNetanel Belgazal struct ena_ring *tx_ring, *rx_ring;
143824dee0c7SNetanel Belgazal int tx_work_done;
143924dee0c7SNetanel Belgazal int rx_work_done = 0;
14401738cd3eSNetanel Belgazal int tx_budget;
14411738cd3eSNetanel Belgazal int napi_comp_call = 0;
14421738cd3eSNetanel Belgazal int ret;
14431738cd3eSNetanel Belgazal
14441738cd3eSNetanel Belgazal tx_ring = ena_napi->tx_ring;
14451738cd3eSNetanel Belgazal rx_ring = ena_napi->rx_ring;
14461738cd3eSNetanel Belgazal
14471738cd3eSNetanel Belgazal tx_budget = tx_ring->ring_size / ENA_TX_POLL_BUDGET_DIVIDER;
14481738cd3eSNetanel Belgazal
14493f6159dbSNetanel Belgazal if (!test_bit(ENA_FLAG_DEV_UP, &tx_ring->adapter->flags) ||
14503f6159dbSNetanel Belgazal test_bit(ENA_FLAG_TRIGGER_RESET, &tx_ring->adapter->flags)) {
14511738cd3eSNetanel Belgazal napi_complete_done(napi, 0);
14521738cd3eSNetanel Belgazal return 0;
14531738cd3eSNetanel Belgazal }
14541738cd3eSNetanel Belgazal
14551738cd3eSNetanel Belgazal tx_work_done = ena_clean_tx_irq(tx_ring, tx_budget);
145624dee0c7SNetanel Belgazal /* On netpoll the budget is zero and the handler should only clean the
145724dee0c7SNetanel Belgazal * tx completions.
145824dee0c7SNetanel Belgazal */
145924dee0c7SNetanel Belgazal if (likely(budget))
14601738cd3eSNetanel Belgazal rx_work_done = ena_clean_rx_irq(rx_ring, napi, budget);
14611738cd3eSNetanel Belgazal
1462b1669c9fSNetanel Belgazal /* If the device is about to reset or down, avoid unmask
1463b1669c9fSNetanel Belgazal * the interrupt and return 0 so NAPI won't reschedule
1464b1669c9fSNetanel Belgazal */
1465b1669c9fSNetanel Belgazal if (unlikely(!test_bit(ENA_FLAG_DEV_UP, &tx_ring->adapter->flags) ||
1466b1669c9fSNetanel Belgazal test_bit(ENA_FLAG_TRIGGER_RESET, &tx_ring->adapter->flags))) {
1467b1669c9fSNetanel Belgazal napi_complete_done(napi, 0);
1468b1669c9fSNetanel Belgazal ret = 0;
14691738cd3eSNetanel Belgazal
1470b1669c9fSNetanel Belgazal } else if ((budget > rx_work_done) && (tx_budget > tx_work_done)) {
14711738cd3eSNetanel Belgazal napi_comp_call = 1;
1472b1669c9fSNetanel Belgazal
1473b1669c9fSNetanel Belgazal /* Update numa and unmask the interrupt only when schedule
1474b1669c9fSNetanel Belgazal * from the interrupt context (vs from sk_busy_loop)
1475b1669c9fSNetanel Belgazal */
14761e5ae350SArthur Kiyanovski if (napi_complete_done(napi, rx_work_done) &&
14771e5ae350SArthur Kiyanovski READ_ONCE(ena_napi->interrupts_masked)) {
14781e5ae350SArthur Kiyanovski smp_rmb(); /* make sure interrupts_masked is read */
14791e5ae350SArthur Kiyanovski WRITE_ONCE(ena_napi->interrupts_masked, false);
1480282faf61SArthur Kiyanovski /* We apply adaptive moderation on Rx path only.
1481282faf61SArthur Kiyanovski * Tx uses static interrupt moderation.
1482282faf61SArthur Kiyanovski */
14831738cd3eSNetanel Belgazal if (ena_com_get_adaptive_moderation_enabled(rx_ring->ena_dev))
1484282faf61SArthur Kiyanovski ena_adjust_adaptive_rx_intr_moderation(ena_napi);
14851738cd3eSNetanel Belgazal
1486a8ee104fSDavid Arinzon ena_update_ring_numa_node(tx_ring, rx_ring);
1487418df30fSNetanel Belgazal ena_unmask_interrupt(tx_ring, rx_ring);
1488b1669c9fSNetanel Belgazal }
1489b1669c9fSNetanel Belgazal
14901738cd3eSNetanel Belgazal ret = rx_work_done;
14911738cd3eSNetanel Belgazal } else {
14921738cd3eSNetanel Belgazal ret = budget;
14931738cd3eSNetanel Belgazal }
14941738cd3eSNetanel Belgazal
14951738cd3eSNetanel Belgazal u64_stats_update_begin(&tx_ring->syncp);
14961738cd3eSNetanel Belgazal tx_ring->tx_stats.napi_comp += napi_comp_call;
14971738cd3eSNetanel Belgazal tx_ring->tx_stats.tx_poll++;
14981738cd3eSNetanel Belgazal u64_stats_update_end(&tx_ring->syncp);
14991738cd3eSNetanel Belgazal
15000ee251cdSShay Agroskin tx_ring->tx_stats.last_napi_jiffies = jiffies;
15010ee251cdSShay Agroskin
15021738cd3eSNetanel Belgazal return ret;
15031738cd3eSNetanel Belgazal }
15041738cd3eSNetanel Belgazal
ena_intr_msix_mgmnt(int irq,void * data)15051738cd3eSNetanel Belgazal static irqreturn_t ena_intr_msix_mgmnt(int irq, void *data)
15061738cd3eSNetanel Belgazal {
15071738cd3eSNetanel Belgazal struct ena_adapter *adapter = (struct ena_adapter *)data;
15081738cd3eSNetanel Belgazal
15091738cd3eSNetanel Belgazal ena_com_admin_q_comp_intr_handler(adapter->ena_dev);
15101738cd3eSNetanel Belgazal
15111738cd3eSNetanel Belgazal /* Don't call the aenq handler before probe is done */
15121738cd3eSNetanel Belgazal if (likely(test_bit(ENA_FLAG_DEVICE_RUNNING, &adapter->flags)))
15131738cd3eSNetanel Belgazal ena_com_aenq_intr_handler(adapter->ena_dev, data);
15141738cd3eSNetanel Belgazal
15151738cd3eSNetanel Belgazal return IRQ_HANDLED;
15161738cd3eSNetanel Belgazal }
15171738cd3eSNetanel Belgazal
15181738cd3eSNetanel Belgazal /* ena_intr_msix_io - MSI-X Interrupt Handler for Tx/Rx
15191738cd3eSNetanel Belgazal * @irq: interrupt number
15201738cd3eSNetanel Belgazal * @data: pointer to a network interface private napi device structure
15211738cd3eSNetanel Belgazal */
ena_intr_msix_io(int irq,void * data)15221738cd3eSNetanel Belgazal static irqreturn_t ena_intr_msix_io(int irq, void *data)
15231738cd3eSNetanel Belgazal {
15241738cd3eSNetanel Belgazal struct ena_napi *ena_napi = data;
15251738cd3eSNetanel Belgazal
1526e4ac382eSShay Agroskin /* Used to check HW health */
1527e4ac382eSShay Agroskin WRITE_ONCE(ena_napi->first_interrupt, true);
15288510e1a3SNetanel Belgazal
15291e5ae350SArthur Kiyanovski WRITE_ONCE(ena_napi->interrupts_masked, true);
15301e5ae350SArthur Kiyanovski smp_wmb(); /* write interrupts_masked before calling napi */
15311e5ae350SArthur Kiyanovski
1532e745dafaSNetanel Belgazal napi_schedule_irqoff(&ena_napi->napi);
15331738cd3eSNetanel Belgazal
15341738cd3eSNetanel Belgazal return IRQ_HANDLED;
15351738cd3eSNetanel Belgazal }
15361738cd3eSNetanel Belgazal
153706443684SNetanel Belgazal /* Reserve a single MSI-X vector for management (admin + aenq).
153806443684SNetanel Belgazal * plus reserve one vector for each potential io queue.
153906443684SNetanel Belgazal * the number of potential io queues is the minimum of what the device
154006443684SNetanel Belgazal * supports and the number of vCPUs.
154106443684SNetanel Belgazal */
ena_enable_msix(struct ena_adapter * adapter)15424d192660SSameeh Jubran static int ena_enable_msix(struct ena_adapter *adapter)
15431738cd3eSNetanel Belgazal {
154406443684SNetanel Belgazal int msix_vecs, irq_cnt;
154506443684SNetanel Belgazal
154606443684SNetanel Belgazal if (test_bit(ENA_FLAG_MSIX_ENABLED, &adapter->flags)) {
154706443684SNetanel Belgazal netif_err(adapter, probe, adapter->netdev,
154806443684SNetanel Belgazal "Error, MSI-X is already enabled\n");
154906443684SNetanel Belgazal return -EPERM;
155006443684SNetanel Belgazal }
15511738cd3eSNetanel Belgazal
15521738cd3eSNetanel Belgazal /* Reserved the max msix vectors we might need */
1553ce1f3521SArthur Kiyanovski msix_vecs = ENA_MAX_MSIX_VEC(adapter->max_num_io_queues);
15541738cd3eSNetanel Belgazal netif_dbg(adapter, probe, adapter->netdev,
1555bf2746e8SShay Agroskin "Trying to enable MSI-X, vectors %d\n", msix_vecs);
15561738cd3eSNetanel Belgazal
155706443684SNetanel Belgazal irq_cnt = pci_alloc_irq_vectors(adapter->pdev, ENA_MIN_MSIX_VEC,
155806443684SNetanel Belgazal msix_vecs, PCI_IRQ_MSIX);
155906443684SNetanel Belgazal
156006443684SNetanel Belgazal if (irq_cnt < 0) {
15611738cd3eSNetanel Belgazal netif_err(adapter, probe, adapter->netdev,
156206443684SNetanel Belgazal "Failed to enable MSI-X. irq_cnt %d\n", irq_cnt);
15631738cd3eSNetanel Belgazal return -ENOSPC;
15641738cd3eSNetanel Belgazal }
15651738cd3eSNetanel Belgazal
156606443684SNetanel Belgazal if (irq_cnt != msix_vecs) {
156706443684SNetanel Belgazal netif_notice(adapter, probe, adapter->netdev,
1568bf2746e8SShay Agroskin "Enable only %d MSI-X (out of %d), reduce the number of queues\n",
156906443684SNetanel Belgazal irq_cnt, msix_vecs);
1570faa615f9SSameeh Jubran adapter->num_io_queues = irq_cnt - ENA_ADMIN_MSIX_VEC;
157106443684SNetanel Belgazal }
15721738cd3eSNetanel Belgazal
15731738cd3eSNetanel Belgazal if (ena_init_rx_cpu_rmap(adapter))
15741738cd3eSNetanel Belgazal netif_warn(adapter, probe, adapter->netdev,
15751738cd3eSNetanel Belgazal "Failed to map IRQs to CPUs\n");
15761738cd3eSNetanel Belgazal
157706443684SNetanel Belgazal adapter->msix_vecs = irq_cnt;
157806443684SNetanel Belgazal set_bit(ENA_FLAG_MSIX_ENABLED, &adapter->flags);
15791738cd3eSNetanel Belgazal
15801738cd3eSNetanel Belgazal return 0;
15811738cd3eSNetanel Belgazal }
15821738cd3eSNetanel Belgazal
ena_setup_mgmnt_intr(struct ena_adapter * adapter)15831738cd3eSNetanel Belgazal static void ena_setup_mgmnt_intr(struct ena_adapter *adapter)
15841738cd3eSNetanel Belgazal {
15851738cd3eSNetanel Belgazal u32 cpu;
15861738cd3eSNetanel Belgazal
15871738cd3eSNetanel Belgazal snprintf(adapter->irq_tbl[ENA_MGMNT_IRQ_IDX].name,
15881738cd3eSNetanel Belgazal ENA_IRQNAME_SIZE, "ena-mgmnt@pci:%s",
15891738cd3eSNetanel Belgazal pci_name(adapter->pdev));
15901738cd3eSNetanel Belgazal adapter->irq_tbl[ENA_MGMNT_IRQ_IDX].handler =
15911738cd3eSNetanel Belgazal ena_intr_msix_mgmnt;
15921738cd3eSNetanel Belgazal adapter->irq_tbl[ENA_MGMNT_IRQ_IDX].data = adapter;
15931738cd3eSNetanel Belgazal adapter->irq_tbl[ENA_MGMNT_IRQ_IDX].vector =
1594da6f4cf5SChristoph Hellwig pci_irq_vector(adapter->pdev, ENA_MGMNT_IRQ_IDX);
15951738cd3eSNetanel Belgazal cpu = cpumask_first(cpu_online_mask);
15961738cd3eSNetanel Belgazal adapter->irq_tbl[ENA_MGMNT_IRQ_IDX].cpu = cpu;
15971738cd3eSNetanel Belgazal cpumask_set_cpu(cpu,
15981738cd3eSNetanel Belgazal &adapter->irq_tbl[ENA_MGMNT_IRQ_IDX].affinity_hint_mask);
15991738cd3eSNetanel Belgazal }
16001738cd3eSNetanel Belgazal
ena_setup_io_intr(struct ena_adapter * adapter)16011738cd3eSNetanel Belgazal static void ena_setup_io_intr(struct ena_adapter *adapter)
16021738cd3eSNetanel Belgazal {
16031738cd3eSNetanel Belgazal struct net_device *netdev;
16041738cd3eSNetanel Belgazal int irq_idx, i, cpu;
1605548c4940SSameeh Jubran int io_queue_count;
16061738cd3eSNetanel Belgazal
16071738cd3eSNetanel Belgazal netdev = adapter->netdev;
1608548c4940SSameeh Jubran io_queue_count = adapter->num_io_queues + adapter->xdp_num_queues;
16091738cd3eSNetanel Belgazal
1610548c4940SSameeh Jubran for (i = 0; i < io_queue_count; i++) {
16111738cd3eSNetanel Belgazal irq_idx = ENA_IO_IRQ_IDX(i);
16121738cd3eSNetanel Belgazal cpu = i % num_online_cpus();
16131738cd3eSNetanel Belgazal
16141738cd3eSNetanel Belgazal snprintf(adapter->irq_tbl[irq_idx].name, ENA_IRQNAME_SIZE,
16151738cd3eSNetanel Belgazal "%s-Tx-Rx-%d", netdev->name, i);
16161738cd3eSNetanel Belgazal adapter->irq_tbl[irq_idx].handler = ena_intr_msix_io;
16171738cd3eSNetanel Belgazal adapter->irq_tbl[irq_idx].data = &adapter->ena_napi[i];
16181738cd3eSNetanel Belgazal adapter->irq_tbl[irq_idx].vector =
1619da6f4cf5SChristoph Hellwig pci_irq_vector(adapter->pdev, irq_idx);
16201738cd3eSNetanel Belgazal adapter->irq_tbl[irq_idx].cpu = cpu;
16211738cd3eSNetanel Belgazal
16221738cd3eSNetanel Belgazal cpumask_set_cpu(cpu,
16231738cd3eSNetanel Belgazal &adapter->irq_tbl[irq_idx].affinity_hint_mask);
16241738cd3eSNetanel Belgazal }
16251738cd3eSNetanel Belgazal }
16261738cd3eSNetanel Belgazal
ena_request_mgmnt_irq(struct ena_adapter * adapter)16271738cd3eSNetanel Belgazal static int ena_request_mgmnt_irq(struct ena_adapter *adapter)
16281738cd3eSNetanel Belgazal {
16291738cd3eSNetanel Belgazal unsigned long flags = 0;
16301738cd3eSNetanel Belgazal struct ena_irq *irq;
16311738cd3eSNetanel Belgazal int rc;
16321738cd3eSNetanel Belgazal
16331738cd3eSNetanel Belgazal irq = &adapter->irq_tbl[ENA_MGMNT_IRQ_IDX];
16341738cd3eSNetanel Belgazal rc = request_irq(irq->vector, irq->handler, flags, irq->name,
16351738cd3eSNetanel Belgazal irq->data);
16361738cd3eSNetanel Belgazal if (rc) {
16371738cd3eSNetanel Belgazal netif_err(adapter, probe, adapter->netdev,
1638bf2746e8SShay Agroskin "Failed to request admin irq\n");
16391738cd3eSNetanel Belgazal return rc;
16401738cd3eSNetanel Belgazal }
16411738cd3eSNetanel Belgazal
16421738cd3eSNetanel Belgazal netif_dbg(adapter, probe, adapter->netdev,
1643bf2746e8SShay Agroskin "Set affinity hint of mgmnt irq.to 0x%lx (irq vector: %d)\n",
16441738cd3eSNetanel Belgazal irq->affinity_hint_mask.bits[0], irq->vector);
16451738cd3eSNetanel Belgazal
16461738cd3eSNetanel Belgazal irq_set_affinity_hint(irq->vector, &irq->affinity_hint_mask);
16471738cd3eSNetanel Belgazal
16481738cd3eSNetanel Belgazal return rc;
16491738cd3eSNetanel Belgazal }
16501738cd3eSNetanel Belgazal
ena_request_io_irq(struct ena_adapter * adapter)16511738cd3eSNetanel Belgazal static int ena_request_io_irq(struct ena_adapter *adapter)
16521738cd3eSNetanel Belgazal {
1653e02ae6edSArthur Kiyanovski u32 io_queue_count = adapter->num_io_queues + adapter->xdp_num_queues;
16541738cd3eSNetanel Belgazal unsigned long flags = 0;
16551738cd3eSNetanel Belgazal struct ena_irq *irq;
16561738cd3eSNetanel Belgazal int rc = 0, i, k;
16571738cd3eSNetanel Belgazal
165806443684SNetanel Belgazal if (!test_bit(ENA_FLAG_MSIX_ENABLED, &adapter->flags)) {
165906443684SNetanel Belgazal netif_err(adapter, ifup, adapter->netdev,
166006443684SNetanel Belgazal "Failed to request I/O IRQ: MSI-X is not enabled\n");
166106443684SNetanel Belgazal return -EINVAL;
166206443684SNetanel Belgazal }
166306443684SNetanel Belgazal
1664e02ae6edSArthur Kiyanovski for (i = ENA_IO_IRQ_FIRST_IDX; i < ENA_MAX_MSIX_VEC(io_queue_count); i++) {
16651738cd3eSNetanel Belgazal irq = &adapter->irq_tbl[i];
16661738cd3eSNetanel Belgazal rc = request_irq(irq->vector, irq->handler, flags, irq->name,
16671738cd3eSNetanel Belgazal irq->data);
16681738cd3eSNetanel Belgazal if (rc) {
16691738cd3eSNetanel Belgazal netif_err(adapter, ifup, adapter->netdev,
16701738cd3eSNetanel Belgazal "Failed to request I/O IRQ. index %d rc %d\n",
16711738cd3eSNetanel Belgazal i, rc);
16721738cd3eSNetanel Belgazal goto err;
16731738cd3eSNetanel Belgazal }
16741738cd3eSNetanel Belgazal
16751738cd3eSNetanel Belgazal netif_dbg(adapter, ifup, adapter->netdev,
1676bf2746e8SShay Agroskin "Set affinity hint of irq. index %d to 0x%lx (irq vector: %d)\n",
16771738cd3eSNetanel Belgazal i, irq->affinity_hint_mask.bits[0], irq->vector);
16781738cd3eSNetanel Belgazal
16791738cd3eSNetanel Belgazal irq_set_affinity_hint(irq->vector, &irq->affinity_hint_mask);
16801738cd3eSNetanel Belgazal }
16811738cd3eSNetanel Belgazal
16821738cd3eSNetanel Belgazal return rc;
16831738cd3eSNetanel Belgazal
16841738cd3eSNetanel Belgazal err:
16851738cd3eSNetanel Belgazal for (k = ENA_IO_IRQ_FIRST_IDX; k < i; k++) {
16861738cd3eSNetanel Belgazal irq = &adapter->irq_tbl[k];
16871738cd3eSNetanel Belgazal free_irq(irq->vector, irq->data);
16881738cd3eSNetanel Belgazal }
16891738cd3eSNetanel Belgazal
16901738cd3eSNetanel Belgazal return rc;
16911738cd3eSNetanel Belgazal }
16921738cd3eSNetanel Belgazal
ena_free_mgmnt_irq(struct ena_adapter * adapter)16931738cd3eSNetanel Belgazal static void ena_free_mgmnt_irq(struct ena_adapter *adapter)
16941738cd3eSNetanel Belgazal {
16951738cd3eSNetanel Belgazal struct ena_irq *irq;
16961738cd3eSNetanel Belgazal
16971738cd3eSNetanel Belgazal irq = &adapter->irq_tbl[ENA_MGMNT_IRQ_IDX];
16981738cd3eSNetanel Belgazal synchronize_irq(irq->vector);
16991738cd3eSNetanel Belgazal irq_set_affinity_hint(irq->vector, NULL);
17001738cd3eSNetanel Belgazal free_irq(irq->vector, irq->data);
17011738cd3eSNetanel Belgazal }
17021738cd3eSNetanel Belgazal
ena_free_io_irq(struct ena_adapter * adapter)17031738cd3eSNetanel Belgazal static void ena_free_io_irq(struct ena_adapter *adapter)
17041738cd3eSNetanel Belgazal {
1705e02ae6edSArthur Kiyanovski u32 io_queue_count = adapter->num_io_queues + adapter->xdp_num_queues;
17061738cd3eSNetanel Belgazal struct ena_irq *irq;
17071738cd3eSNetanel Belgazal int i;
17081738cd3eSNetanel Belgazal
17091738cd3eSNetanel Belgazal #ifdef CONFIG_RFS_ACCEL
17101738cd3eSNetanel Belgazal if (adapter->msix_vecs >= 1) {
17111738cd3eSNetanel Belgazal free_irq_cpu_rmap(adapter->netdev->rx_cpu_rmap);
17121738cd3eSNetanel Belgazal adapter->netdev->rx_cpu_rmap = NULL;
17131738cd3eSNetanel Belgazal }
17141738cd3eSNetanel Belgazal #endif /* CONFIG_RFS_ACCEL */
17151738cd3eSNetanel Belgazal
1716e02ae6edSArthur Kiyanovski for (i = ENA_IO_IRQ_FIRST_IDX; i < ENA_MAX_MSIX_VEC(io_queue_count); i++) {
17171738cd3eSNetanel Belgazal irq = &adapter->irq_tbl[i];
17181738cd3eSNetanel Belgazal irq_set_affinity_hint(irq->vector, NULL);
17191738cd3eSNetanel Belgazal free_irq(irq->vector, irq->data);
17201738cd3eSNetanel Belgazal }
17211738cd3eSNetanel Belgazal }
17221738cd3eSNetanel Belgazal
ena_disable_msix(struct ena_adapter * adapter)172306443684SNetanel Belgazal static void ena_disable_msix(struct ena_adapter *adapter)
172406443684SNetanel Belgazal {
172506443684SNetanel Belgazal if (test_and_clear_bit(ENA_FLAG_MSIX_ENABLED, &adapter->flags))
172606443684SNetanel Belgazal pci_free_irq_vectors(adapter->pdev);
172706443684SNetanel Belgazal }
172806443684SNetanel Belgazal
ena_disable_io_intr_sync(struct ena_adapter * adapter)17291738cd3eSNetanel Belgazal static void ena_disable_io_intr_sync(struct ena_adapter *adapter)
17301738cd3eSNetanel Belgazal {
1731e02ae6edSArthur Kiyanovski u32 io_queue_count = adapter->num_io_queues + adapter->xdp_num_queues;
17321738cd3eSNetanel Belgazal int i;
17331738cd3eSNetanel Belgazal
17341738cd3eSNetanel Belgazal if (!netif_running(adapter->netdev))
17351738cd3eSNetanel Belgazal return;
17361738cd3eSNetanel Belgazal
1737e02ae6edSArthur Kiyanovski for (i = ENA_IO_IRQ_FIRST_IDX; i < ENA_MAX_MSIX_VEC(io_queue_count); i++)
17381738cd3eSNetanel Belgazal synchronize_irq(adapter->irq_tbl[i].vector);
17391738cd3eSNetanel Belgazal }
17401738cd3eSNetanel Belgazal
ena_del_napi_in_range(struct ena_adapter * adapter,int first_index,int count)1741548c4940SSameeh Jubran static void ena_del_napi_in_range(struct ena_adapter *adapter,
1742548c4940SSameeh Jubran int first_index,
1743548c4940SSameeh Jubran int count)
17441738cd3eSNetanel Belgazal {
17451738cd3eSNetanel Belgazal int i;
17461738cd3eSNetanel Belgazal
1747548c4940SSameeh Jubran for (i = first_index; i < first_index + count; i++) {
17481738cd3eSNetanel Belgazal netif_napi_del(&adapter->ena_napi[i].napi);
17498b147f6fSShay Agroskin
1750354627f9SDavid Arinzon WARN_ON(ENA_IS_XDP_INDEX(adapter, i) &&
1751354627f9SDavid Arinzon adapter->ena_napi[i].rx_ring);
1752548c4940SSameeh Jubran }
17531738cd3eSNetanel Belgazal }
17541738cd3eSNetanel Belgazal
ena_init_napi_in_range(struct ena_adapter * adapter,int first_index,int count)1755548c4940SSameeh Jubran static void ena_init_napi_in_range(struct ena_adapter *adapter,
1756548c4940SSameeh Jubran int first_index, int count)
17571738cd3eSNetanel Belgazal {
17581738cd3eSNetanel Belgazal int i;
17591738cd3eSNetanel Belgazal
1760548c4940SSameeh Jubran for (i = first_index; i < first_index + count; i++) {
1761d89d8d4dSWang Hai struct ena_napi *napi = &adapter->ena_napi[i];
17621738cd3eSNetanel Belgazal
1763b48b89f9SJakub Kicinski netif_napi_add(adapter->netdev, &napi->napi,
1764b48b89f9SJakub Kicinski ENA_IS_XDP_INDEX(adapter, i) ? ena_xdp_io_poll : ena_io_poll);
1765548c4940SSameeh Jubran
1766354627f9SDavid Arinzon if (!ENA_IS_XDP_INDEX(adapter, i))
17671738cd3eSNetanel Belgazal napi->rx_ring = &adapter->rx_ring[i];
1768354627f9SDavid Arinzon
17691738cd3eSNetanel Belgazal napi->tx_ring = &adapter->tx_ring[i];
17701738cd3eSNetanel Belgazal napi->qid = i;
17711738cd3eSNetanel Belgazal }
17721738cd3eSNetanel Belgazal }
17731738cd3eSNetanel Belgazal
ena_napi_disable_in_range(struct ena_adapter * adapter,int first_index,int count)1774548c4940SSameeh Jubran static void ena_napi_disable_in_range(struct ena_adapter *adapter,
1775548c4940SSameeh Jubran int first_index,
1776548c4940SSameeh Jubran int count)
17771738cd3eSNetanel Belgazal {
17781738cd3eSNetanel Belgazal int i;
17791738cd3eSNetanel Belgazal
1780548c4940SSameeh Jubran for (i = first_index; i < first_index + count; i++)
17811738cd3eSNetanel Belgazal napi_disable(&adapter->ena_napi[i].napi);
17821738cd3eSNetanel Belgazal }
17831738cd3eSNetanel Belgazal
ena_napi_enable_in_range(struct ena_adapter * adapter,int first_index,int count)1784548c4940SSameeh Jubran static void ena_napi_enable_in_range(struct ena_adapter *adapter,
1785548c4940SSameeh Jubran int first_index,
1786548c4940SSameeh Jubran int count)
17871738cd3eSNetanel Belgazal {
17881738cd3eSNetanel Belgazal int i;
17891738cd3eSNetanel Belgazal
1790548c4940SSameeh Jubran for (i = first_index; i < first_index + count; i++)
17911738cd3eSNetanel Belgazal napi_enable(&adapter->ena_napi[i].napi);
17921738cd3eSNetanel Belgazal }
17931738cd3eSNetanel Belgazal
17941738cd3eSNetanel Belgazal /* Configure the Rx forwarding */
ena_rss_configure(struct ena_adapter * adapter)17951738cd3eSNetanel Belgazal static int ena_rss_configure(struct ena_adapter *adapter)
17961738cd3eSNetanel Belgazal {
17971738cd3eSNetanel Belgazal struct ena_com_dev *ena_dev = adapter->ena_dev;
17981738cd3eSNetanel Belgazal int rc;
17991738cd3eSNetanel Belgazal
18001738cd3eSNetanel Belgazal /* In case the RSS table wasn't initialized by probe */
18011738cd3eSNetanel Belgazal if (!ena_dev->rss.tbl_log_size) {
18021738cd3eSNetanel Belgazal rc = ena_rss_init_default(adapter);
1803d1497638SNetanel Belgazal if (rc && (rc != -EOPNOTSUPP)) {
1804*26668c2dSDavid Arinzon netif_err(adapter, ifup, adapter->netdev, "Failed to init RSS rc: %d\n", rc);
18051738cd3eSNetanel Belgazal return rc;
18061738cd3eSNetanel Belgazal }
18071738cd3eSNetanel Belgazal }
18081738cd3eSNetanel Belgazal
18091738cd3eSNetanel Belgazal /* Set indirect table */
18101738cd3eSNetanel Belgazal rc = ena_com_indirect_table_set(ena_dev);
1811d1497638SNetanel Belgazal if (unlikely(rc && rc != -EOPNOTSUPP))
18121738cd3eSNetanel Belgazal return rc;
18131738cd3eSNetanel Belgazal
18141738cd3eSNetanel Belgazal /* Configure hash function (if supported) */
18151738cd3eSNetanel Belgazal rc = ena_com_set_hash_function(ena_dev);
1816d1497638SNetanel Belgazal if (unlikely(rc && (rc != -EOPNOTSUPP)))
18171738cd3eSNetanel Belgazal return rc;
18181738cd3eSNetanel Belgazal
18191738cd3eSNetanel Belgazal /* Configure hash inputs (if supported) */
18201738cd3eSNetanel Belgazal rc = ena_com_set_hash_ctrl(ena_dev);
1821d1497638SNetanel Belgazal if (unlikely(rc && (rc != -EOPNOTSUPP)))
18221738cd3eSNetanel Belgazal return rc;
18231738cd3eSNetanel Belgazal
18241738cd3eSNetanel Belgazal return 0;
18251738cd3eSNetanel Belgazal }
18261738cd3eSNetanel Belgazal
ena_up_complete(struct ena_adapter * adapter)18271738cd3eSNetanel Belgazal static int ena_up_complete(struct ena_adapter *adapter)
18281738cd3eSNetanel Belgazal {
18297853b49cSNetanel Belgazal int rc;
18301738cd3eSNetanel Belgazal
18311738cd3eSNetanel Belgazal rc = ena_rss_configure(adapter);
18321738cd3eSNetanel Belgazal if (rc)
18331738cd3eSNetanel Belgazal return rc;
18341738cd3eSNetanel Belgazal
18351738cd3eSNetanel Belgazal ena_change_mtu(adapter->netdev, adapter->netdev->mtu);
18361738cd3eSNetanel Belgazal
18371738cd3eSNetanel Belgazal ena_refill_all_rx_bufs(adapter);
18381738cd3eSNetanel Belgazal
18391738cd3eSNetanel Belgazal /* enable transmits */
18401738cd3eSNetanel Belgazal netif_tx_start_all_queues(adapter->netdev);
18411738cd3eSNetanel Belgazal
1842548c4940SSameeh Jubran ena_napi_enable_in_range(adapter,
1843548c4940SSameeh Jubran 0,
1844548c4940SSameeh Jubran adapter->xdp_num_queues + adapter->num_io_queues);
18451738cd3eSNetanel Belgazal
18461738cd3eSNetanel Belgazal return 0;
18471738cd3eSNetanel Belgazal }
18481738cd3eSNetanel Belgazal
ena_create_io_tx_queue(struct ena_adapter * adapter,int qid)18491738cd3eSNetanel Belgazal static int ena_create_io_tx_queue(struct ena_adapter *adapter, int qid)
18501738cd3eSNetanel Belgazal {
185138005ca8SArthur Kiyanovski struct ena_com_create_io_ctx ctx;
18521738cd3eSNetanel Belgazal struct ena_com_dev *ena_dev;
18531738cd3eSNetanel Belgazal struct ena_ring *tx_ring;
18541738cd3eSNetanel Belgazal u32 msix_vector;
18551738cd3eSNetanel Belgazal u16 ena_qid;
18561738cd3eSNetanel Belgazal int rc;
18571738cd3eSNetanel Belgazal
18581738cd3eSNetanel Belgazal ena_dev = adapter->ena_dev;
18591738cd3eSNetanel Belgazal
18601738cd3eSNetanel Belgazal tx_ring = &adapter->tx_ring[qid];
18611738cd3eSNetanel Belgazal msix_vector = ENA_IO_IRQ_IDX(qid);
18621738cd3eSNetanel Belgazal ena_qid = ENA_IO_TXQ_IDX(qid);
18631738cd3eSNetanel Belgazal
186438005ca8SArthur Kiyanovski memset(&ctx, 0x0, sizeof(ctx));
186538005ca8SArthur Kiyanovski
18661738cd3eSNetanel Belgazal ctx.direction = ENA_COM_IO_QUEUE_DIRECTION_TX;
18671738cd3eSNetanel Belgazal ctx.qid = ena_qid;
18681738cd3eSNetanel Belgazal ctx.mem_queue_type = ena_dev->tx_mem_queue_type;
18691738cd3eSNetanel Belgazal ctx.msix_vector = msix_vector;
187013ca32a6SSameeh Jubran ctx.queue_size = tx_ring->ring_size;
1871a8ee104fSDavid Arinzon ctx.numa_node = tx_ring->numa_node;
18721738cd3eSNetanel Belgazal
18731738cd3eSNetanel Belgazal rc = ena_com_create_io_queue(ena_dev, &ctx);
18741738cd3eSNetanel Belgazal if (rc) {
18751738cd3eSNetanel Belgazal netif_err(adapter, ifup, adapter->netdev,
18761738cd3eSNetanel Belgazal "Failed to create I/O TX queue num %d rc: %d\n",
18771738cd3eSNetanel Belgazal qid, rc);
18781738cd3eSNetanel Belgazal return rc;
18791738cd3eSNetanel Belgazal }
18801738cd3eSNetanel Belgazal
18811738cd3eSNetanel Belgazal rc = ena_com_get_io_handlers(ena_dev, ena_qid,
18821738cd3eSNetanel Belgazal &tx_ring->ena_com_io_sq,
18831738cd3eSNetanel Belgazal &tx_ring->ena_com_io_cq);
18841738cd3eSNetanel Belgazal if (rc) {
18851738cd3eSNetanel Belgazal netif_err(adapter, ifup, adapter->netdev,
18861738cd3eSNetanel Belgazal "Failed to get TX queue handlers. TX queue num %d rc: %d\n",
18871738cd3eSNetanel Belgazal qid, rc);
18881738cd3eSNetanel Belgazal ena_com_destroy_io_queue(ena_dev, ena_qid);
18892d2c600aSNetanel Belgazal return rc;
18901738cd3eSNetanel Belgazal }
18911738cd3eSNetanel Belgazal
18921738cd3eSNetanel Belgazal ena_com_update_numa_node(tx_ring->ena_com_io_cq, ctx.numa_node);
18931738cd3eSNetanel Belgazal return rc;
18941738cd3eSNetanel Belgazal }
18951738cd3eSNetanel Belgazal
ena_create_io_tx_queues_in_range(struct ena_adapter * adapter,int first_index,int count)1896c891d767SDavid Arinzon int ena_create_io_tx_queues_in_range(struct ena_adapter *adapter,
1897548c4940SSameeh Jubran int first_index, int count)
18981738cd3eSNetanel Belgazal {
18991738cd3eSNetanel Belgazal struct ena_com_dev *ena_dev = adapter->ena_dev;
19001738cd3eSNetanel Belgazal int rc, i;
19011738cd3eSNetanel Belgazal
1902548c4940SSameeh Jubran for (i = first_index; i < first_index + count; i++) {
19031738cd3eSNetanel Belgazal rc = ena_create_io_tx_queue(adapter, i);
19041738cd3eSNetanel Belgazal if (rc)
19051738cd3eSNetanel Belgazal goto create_err;
19061738cd3eSNetanel Belgazal }
19071738cd3eSNetanel Belgazal
19081738cd3eSNetanel Belgazal return 0;
19091738cd3eSNetanel Belgazal
19101738cd3eSNetanel Belgazal create_err:
1911548c4940SSameeh Jubran while (i-- > first_index)
19121738cd3eSNetanel Belgazal ena_com_destroy_io_queue(ena_dev, ENA_IO_TXQ_IDX(i));
19131738cd3eSNetanel Belgazal
19141738cd3eSNetanel Belgazal return rc;
19151738cd3eSNetanel Belgazal }
19161738cd3eSNetanel Belgazal
ena_create_io_rx_queue(struct ena_adapter * adapter,int qid)19171738cd3eSNetanel Belgazal static int ena_create_io_rx_queue(struct ena_adapter *adapter, int qid)
19181738cd3eSNetanel Belgazal {
19191738cd3eSNetanel Belgazal struct ena_com_dev *ena_dev;
192038005ca8SArthur Kiyanovski struct ena_com_create_io_ctx ctx;
19211738cd3eSNetanel Belgazal struct ena_ring *rx_ring;
19221738cd3eSNetanel Belgazal u32 msix_vector;
19231738cd3eSNetanel Belgazal u16 ena_qid;
19241738cd3eSNetanel Belgazal int rc;
19251738cd3eSNetanel Belgazal
19261738cd3eSNetanel Belgazal ena_dev = adapter->ena_dev;
19271738cd3eSNetanel Belgazal
19281738cd3eSNetanel Belgazal rx_ring = &adapter->rx_ring[qid];
19291738cd3eSNetanel Belgazal msix_vector = ENA_IO_IRQ_IDX(qid);
19301738cd3eSNetanel Belgazal ena_qid = ENA_IO_RXQ_IDX(qid);
19311738cd3eSNetanel Belgazal
193238005ca8SArthur Kiyanovski memset(&ctx, 0x0, sizeof(ctx));
193338005ca8SArthur Kiyanovski
19341738cd3eSNetanel Belgazal ctx.qid = ena_qid;
19351738cd3eSNetanel Belgazal ctx.direction = ENA_COM_IO_QUEUE_DIRECTION_RX;
19361738cd3eSNetanel Belgazal ctx.mem_queue_type = ENA_ADMIN_PLACEMENT_POLICY_HOST;
19371738cd3eSNetanel Belgazal ctx.msix_vector = msix_vector;
193813ca32a6SSameeh Jubran ctx.queue_size = rx_ring->ring_size;
1939a8ee104fSDavid Arinzon ctx.numa_node = rx_ring->numa_node;
19401738cd3eSNetanel Belgazal
19411738cd3eSNetanel Belgazal rc = ena_com_create_io_queue(ena_dev, &ctx);
19421738cd3eSNetanel Belgazal if (rc) {
19431738cd3eSNetanel Belgazal netif_err(adapter, ifup, adapter->netdev,
19441738cd3eSNetanel Belgazal "Failed to create I/O RX queue num %d rc: %d\n",
19451738cd3eSNetanel Belgazal qid, rc);
19461738cd3eSNetanel Belgazal return rc;
19471738cd3eSNetanel Belgazal }
19481738cd3eSNetanel Belgazal
19491738cd3eSNetanel Belgazal rc = ena_com_get_io_handlers(ena_dev, ena_qid,
19501738cd3eSNetanel Belgazal &rx_ring->ena_com_io_sq,
19511738cd3eSNetanel Belgazal &rx_ring->ena_com_io_cq);
19521738cd3eSNetanel Belgazal if (rc) {
19531738cd3eSNetanel Belgazal netif_err(adapter, ifup, adapter->netdev,
19541738cd3eSNetanel Belgazal "Failed to get RX queue handlers. RX queue num %d rc: %d\n",
19551738cd3eSNetanel Belgazal qid, rc);
1956838c93dcSSameeh Jubran goto err;
19571738cd3eSNetanel Belgazal }
19581738cd3eSNetanel Belgazal
19591738cd3eSNetanel Belgazal ena_com_update_numa_node(rx_ring->ena_com_io_cq, ctx.numa_node);
19601738cd3eSNetanel Belgazal
1961838c93dcSSameeh Jubran return rc;
1962838c93dcSSameeh Jubran err:
1963838c93dcSSameeh Jubran ena_com_destroy_io_queue(ena_dev, ena_qid);
19641738cd3eSNetanel Belgazal return rc;
19651738cd3eSNetanel Belgazal }
19661738cd3eSNetanel Belgazal
ena_create_all_io_rx_queues(struct ena_adapter * adapter)19671738cd3eSNetanel Belgazal static int ena_create_all_io_rx_queues(struct ena_adapter *adapter)
19681738cd3eSNetanel Belgazal {
19691738cd3eSNetanel Belgazal struct ena_com_dev *ena_dev = adapter->ena_dev;
19701738cd3eSNetanel Belgazal int rc, i;
19711738cd3eSNetanel Belgazal
1972faa615f9SSameeh Jubran for (i = 0; i < adapter->num_io_queues; i++) {
19731738cd3eSNetanel Belgazal rc = ena_create_io_rx_queue(adapter, i);
19741738cd3eSNetanel Belgazal if (rc)
19751738cd3eSNetanel Belgazal goto create_err;
1976282faf61SArthur Kiyanovski INIT_WORK(&adapter->ena_napi[i].dim.work, ena_dim_work);
19771738cd3eSNetanel Belgazal }
19781738cd3eSNetanel Belgazal
19791738cd3eSNetanel Belgazal return 0;
19801738cd3eSNetanel Belgazal
19811738cd3eSNetanel Belgazal create_err:
1982282faf61SArthur Kiyanovski while (i--) {
1983282faf61SArthur Kiyanovski cancel_work_sync(&adapter->ena_napi[i].dim.work);
19841738cd3eSNetanel Belgazal ena_com_destroy_io_queue(ena_dev, ENA_IO_RXQ_IDX(i));
1985282faf61SArthur Kiyanovski }
19861738cd3eSNetanel Belgazal
19871738cd3eSNetanel Belgazal return rc;
19881738cd3eSNetanel Belgazal }
19891738cd3eSNetanel Belgazal
set_io_rings_size(struct ena_adapter * adapter,int new_tx_size,int new_rx_size)199013ca32a6SSameeh Jubran static void set_io_rings_size(struct ena_adapter *adapter,
1991548c4940SSameeh Jubran int new_tx_size,
1992548c4940SSameeh Jubran int new_rx_size)
199313ca32a6SSameeh Jubran {
199413ca32a6SSameeh Jubran int i;
199513ca32a6SSameeh Jubran
1996faa615f9SSameeh Jubran for (i = 0; i < adapter->num_io_queues; i++) {
199713ca32a6SSameeh Jubran adapter->tx_ring[i].ring_size = new_tx_size;
199813ca32a6SSameeh Jubran adapter->rx_ring[i].ring_size = new_rx_size;
199913ca32a6SSameeh Jubran }
200013ca32a6SSameeh Jubran }
200113ca32a6SSameeh Jubran
200213ca32a6SSameeh Jubran /* This function allows queue allocation to backoff when the system is
200313ca32a6SSameeh Jubran * low on memory. If there is not enough memory to allocate io queues
200413ca32a6SSameeh Jubran * the driver will try to allocate smaller queues.
200513ca32a6SSameeh Jubran *
200613ca32a6SSameeh Jubran * The backoff algorithm is as follows:
200713ca32a6SSameeh Jubran * 1. Try to allocate TX and RX and if successful.
200813ca32a6SSameeh Jubran * 1.1. return success
200913ca32a6SSameeh Jubran *
201013ca32a6SSameeh Jubran * 2. Divide by 2 the size of the larger of RX and TX queues (or both if their size is the same).
201113ca32a6SSameeh Jubran *
201213ca32a6SSameeh Jubran * 3. If TX or RX is smaller than 256
201313ca32a6SSameeh Jubran * 3.1. return failure.
201413ca32a6SSameeh Jubran * 4. else
201513ca32a6SSameeh Jubran * 4.1. go back to 1.
201613ca32a6SSameeh Jubran */
create_queues_with_size_backoff(struct ena_adapter * adapter)201713ca32a6SSameeh Jubran static int create_queues_with_size_backoff(struct ena_adapter *adapter)
201813ca32a6SSameeh Jubran {
201913ca32a6SSameeh Jubran int rc, cur_rx_ring_size, cur_tx_ring_size;
202013ca32a6SSameeh Jubran int new_rx_ring_size, new_tx_ring_size;
202113ca32a6SSameeh Jubran
202213ca32a6SSameeh Jubran /* current queue sizes might be set to smaller than the requested
202313ca32a6SSameeh Jubran * ones due to past queue allocation failures.
202413ca32a6SSameeh Jubran */
202513ca32a6SSameeh Jubran set_io_rings_size(adapter, adapter->requested_tx_ring_size,
202613ca32a6SSameeh Jubran adapter->requested_rx_ring_size);
202713ca32a6SSameeh Jubran
202813ca32a6SSameeh Jubran while (1) {
2029548c4940SSameeh Jubran if (ena_xdp_present(adapter)) {
2030548c4940SSameeh Jubran rc = ena_setup_and_create_all_xdp_queues(adapter);
2031548c4940SSameeh Jubran
2032548c4940SSameeh Jubran if (rc)
2033548c4940SSameeh Jubran goto err_setup_tx;
2034548c4940SSameeh Jubran }
2035548c4940SSameeh Jubran rc = ena_setup_tx_resources_in_range(adapter,
2036548c4940SSameeh Jubran 0,
2037548c4940SSameeh Jubran adapter->num_io_queues);
203813ca32a6SSameeh Jubran if (rc)
203913ca32a6SSameeh Jubran goto err_setup_tx;
204013ca32a6SSameeh Jubran
2041548c4940SSameeh Jubran rc = ena_create_io_tx_queues_in_range(adapter,
2042548c4940SSameeh Jubran 0,
2043548c4940SSameeh Jubran adapter->num_io_queues);
204413ca32a6SSameeh Jubran if (rc)
204513ca32a6SSameeh Jubran goto err_create_tx_queues;
204613ca32a6SSameeh Jubran
204713ca32a6SSameeh Jubran rc = ena_setup_all_rx_resources(adapter);
204813ca32a6SSameeh Jubran if (rc)
204913ca32a6SSameeh Jubran goto err_setup_rx;
205013ca32a6SSameeh Jubran
205113ca32a6SSameeh Jubran rc = ena_create_all_io_rx_queues(adapter);
205213ca32a6SSameeh Jubran if (rc)
205313ca32a6SSameeh Jubran goto err_create_rx_queues;
205413ca32a6SSameeh Jubran
205513ca32a6SSameeh Jubran return 0;
205613ca32a6SSameeh Jubran
205713ca32a6SSameeh Jubran err_create_rx_queues:
205813ca32a6SSameeh Jubran ena_free_all_io_rx_resources(adapter);
205913ca32a6SSameeh Jubran err_setup_rx:
206013ca32a6SSameeh Jubran ena_destroy_all_tx_queues(adapter);
206113ca32a6SSameeh Jubran err_create_tx_queues:
206213ca32a6SSameeh Jubran ena_free_all_io_tx_resources(adapter);
206313ca32a6SSameeh Jubran err_setup_tx:
206413ca32a6SSameeh Jubran if (rc != -ENOMEM) {
206513ca32a6SSameeh Jubran netif_err(adapter, ifup, adapter->netdev,
206613ca32a6SSameeh Jubran "Queue creation failed with error code %d\n",
206713ca32a6SSameeh Jubran rc);
206813ca32a6SSameeh Jubran return rc;
206913ca32a6SSameeh Jubran }
207013ca32a6SSameeh Jubran
207113ca32a6SSameeh Jubran cur_tx_ring_size = adapter->tx_ring[0].ring_size;
207213ca32a6SSameeh Jubran cur_rx_ring_size = adapter->rx_ring[0].ring_size;
207313ca32a6SSameeh Jubran
207413ca32a6SSameeh Jubran netif_err(adapter, ifup, adapter->netdev,
207513ca32a6SSameeh Jubran "Not enough memory to create queues with sizes TX=%d, RX=%d\n",
207613ca32a6SSameeh Jubran cur_tx_ring_size, cur_rx_ring_size);
207713ca32a6SSameeh Jubran
207813ca32a6SSameeh Jubran new_tx_ring_size = cur_tx_ring_size;
207913ca32a6SSameeh Jubran new_rx_ring_size = cur_rx_ring_size;
208013ca32a6SSameeh Jubran
208113ca32a6SSameeh Jubran /* Decrease the size of the larger queue, or
208213ca32a6SSameeh Jubran * decrease both if they are the same size.
208313ca32a6SSameeh Jubran */
208413ca32a6SSameeh Jubran if (cur_rx_ring_size <= cur_tx_ring_size)
208513ca32a6SSameeh Jubran new_tx_ring_size = cur_tx_ring_size / 2;
208613ca32a6SSameeh Jubran if (cur_rx_ring_size >= cur_tx_ring_size)
208713ca32a6SSameeh Jubran new_rx_ring_size = cur_rx_ring_size / 2;
208813ca32a6SSameeh Jubran
20893e5bfb18SSameeh Jubran if (new_tx_ring_size < ENA_MIN_RING_SIZE ||
20903e5bfb18SSameeh Jubran new_rx_ring_size < ENA_MIN_RING_SIZE) {
209113ca32a6SSameeh Jubran netif_err(adapter, ifup, adapter->netdev,
209213ca32a6SSameeh Jubran "Queue creation failed with the smallest possible queue size of %d for both queues. Not retrying with smaller queues\n",
209313ca32a6SSameeh Jubran ENA_MIN_RING_SIZE);
209413ca32a6SSameeh Jubran return rc;
209513ca32a6SSameeh Jubran }
209613ca32a6SSameeh Jubran
209713ca32a6SSameeh Jubran netif_err(adapter, ifup, adapter->netdev,
209813ca32a6SSameeh Jubran "Retrying queue creation with sizes TX=%d, RX=%d\n",
209913ca32a6SSameeh Jubran new_tx_ring_size,
210013ca32a6SSameeh Jubran new_rx_ring_size);
210113ca32a6SSameeh Jubran
210213ca32a6SSameeh Jubran set_io_rings_size(adapter, new_tx_ring_size,
210313ca32a6SSameeh Jubran new_rx_ring_size);
210413ca32a6SSameeh Jubran }
210513ca32a6SSameeh Jubran }
210613ca32a6SSameeh Jubran
ena_up(struct ena_adapter * adapter)2107c891d767SDavid Arinzon int ena_up(struct ena_adapter *adapter)
21081738cd3eSNetanel Belgazal {
2109548c4940SSameeh Jubran int io_queue_count, rc, i;
21101738cd3eSNetanel Belgazal
2111f0525298SShay Agroskin netif_dbg(adapter, ifup, adapter->netdev, "%s\n", __func__);
21121738cd3eSNetanel Belgazal
2113548c4940SSameeh Jubran io_queue_count = adapter->num_io_queues + adapter->xdp_num_queues;
21141738cd3eSNetanel Belgazal ena_setup_io_intr(adapter);
21151738cd3eSNetanel Belgazal
211678a55d05SArthur Kiyanovski /* napi poll functions should be initialized before running
211778a55d05SArthur Kiyanovski * request_irq(), to handle a rare condition where there is a pending
211878a55d05SArthur Kiyanovski * interrupt, causing the ISR to fire immediately while the poll
211978a55d05SArthur Kiyanovski * function wasn't set yet, causing a null dereference
212078a55d05SArthur Kiyanovski */
2121548c4940SSameeh Jubran ena_init_napi_in_range(adapter, 0, io_queue_count);
212278a55d05SArthur Kiyanovski
21231738cd3eSNetanel Belgazal rc = ena_request_io_irq(adapter);
21241738cd3eSNetanel Belgazal if (rc)
21251738cd3eSNetanel Belgazal goto err_req_irq;
21261738cd3eSNetanel Belgazal
212713ca32a6SSameeh Jubran rc = create_queues_with_size_backoff(adapter);
21281738cd3eSNetanel Belgazal if (rc)
212913ca32a6SSameeh Jubran goto err_create_queues_with_backoff;
21301738cd3eSNetanel Belgazal
21311738cd3eSNetanel Belgazal rc = ena_up_complete(adapter);
21321738cd3eSNetanel Belgazal if (rc)
21331738cd3eSNetanel Belgazal goto err_up;
21341738cd3eSNetanel Belgazal
21351738cd3eSNetanel Belgazal if (test_bit(ENA_FLAG_LINK_UP, &adapter->flags))
21361738cd3eSNetanel Belgazal netif_carrier_on(adapter->netdev);
21371738cd3eSNetanel Belgazal
213889dd735eSShay Agroskin ena_increase_stat(&adapter->dev_stats.interface_up, 1,
213989dd735eSShay Agroskin &adapter->syncp);
21401738cd3eSNetanel Belgazal
21411738cd3eSNetanel Belgazal set_bit(ENA_FLAG_DEV_UP, &adapter->flags);
21421738cd3eSNetanel Belgazal
21437853b49cSNetanel Belgazal /* Enable completion queues interrupt */
2144faa615f9SSameeh Jubran for (i = 0; i < adapter->num_io_queues; i++)
21457853b49cSNetanel Belgazal ena_unmask_interrupt(&adapter->tx_ring[i],
21467853b49cSNetanel Belgazal &adapter->rx_ring[i]);
21477853b49cSNetanel Belgazal
21487853b49cSNetanel Belgazal /* schedule napi in case we had pending packets
21497853b49cSNetanel Belgazal * from the last time we disable napi
21507853b49cSNetanel Belgazal */
2151548c4940SSameeh Jubran for (i = 0; i < io_queue_count; i++)
21527853b49cSNetanel Belgazal napi_schedule(&adapter->ena_napi[i].napi);
21537853b49cSNetanel Belgazal
21541738cd3eSNetanel Belgazal return rc;
21551738cd3eSNetanel Belgazal
21561738cd3eSNetanel Belgazal err_up:
21571738cd3eSNetanel Belgazal ena_destroy_all_tx_queues(adapter);
21581738cd3eSNetanel Belgazal ena_free_all_io_tx_resources(adapter);
215913ca32a6SSameeh Jubran ena_destroy_all_rx_queues(adapter);
216013ca32a6SSameeh Jubran ena_free_all_io_rx_resources(adapter);
216113ca32a6SSameeh Jubran err_create_queues_with_backoff:
21621738cd3eSNetanel Belgazal ena_free_io_irq(adapter);
21631738cd3eSNetanel Belgazal err_req_irq:
2164548c4940SSameeh Jubran ena_del_napi_in_range(adapter, 0, io_queue_count);
21651738cd3eSNetanel Belgazal
21661738cd3eSNetanel Belgazal return rc;
21671738cd3eSNetanel Belgazal }
21681738cd3eSNetanel Belgazal
ena_down(struct ena_adapter * adapter)2169c891d767SDavid Arinzon void ena_down(struct ena_adapter *adapter)
21701738cd3eSNetanel Belgazal {
2171548c4940SSameeh Jubran int io_queue_count = adapter->num_io_queues + adapter->xdp_num_queues;
2172548c4940SSameeh Jubran
21731738cd3eSNetanel Belgazal netif_info(adapter, ifdown, adapter->netdev, "%s\n", __func__);
21741738cd3eSNetanel Belgazal
21751738cd3eSNetanel Belgazal clear_bit(ENA_FLAG_DEV_UP, &adapter->flags);
21761738cd3eSNetanel Belgazal
217789dd735eSShay Agroskin ena_increase_stat(&adapter->dev_stats.interface_down, 1,
217889dd735eSShay Agroskin &adapter->syncp);
21791738cd3eSNetanel Belgazal
21801738cd3eSNetanel Belgazal netif_carrier_off(adapter->netdev);
21811738cd3eSNetanel Belgazal netif_tx_disable(adapter->netdev);
21821738cd3eSNetanel Belgazal
21833f6159dbSNetanel Belgazal /* After this point the napi handler won't enable the tx queue */
2184548c4940SSameeh Jubran ena_napi_disable_in_range(adapter, 0, io_queue_count);
21853f6159dbSNetanel Belgazal
21861738cd3eSNetanel Belgazal /* After destroy the queue there won't be any new interrupts */
21873f6159dbSNetanel Belgazal
21883f6159dbSNetanel Belgazal if (test_bit(ENA_FLAG_TRIGGER_RESET, &adapter->flags)) {
21893f6159dbSNetanel Belgazal int rc;
21903f6159dbSNetanel Belgazal
2191e2eed0e3SNetanel Belgazal rc = ena_com_dev_reset(adapter->ena_dev, adapter->reset_reason);
21923f6159dbSNetanel Belgazal if (rc)
2193f0525298SShay Agroskin netif_err(adapter, ifdown, adapter->netdev,
2194f0525298SShay Agroskin "Device reset failed\n");
219558a54b9cSArthur Kiyanovski /* stop submitting admin commands on a device that was reset */
219658a54b9cSArthur Kiyanovski ena_com_set_admin_running_state(adapter->ena_dev, false);
21973f6159dbSNetanel Belgazal }
21983f6159dbSNetanel Belgazal
21991738cd3eSNetanel Belgazal ena_destroy_all_io_queues(adapter);
22001738cd3eSNetanel Belgazal
22011738cd3eSNetanel Belgazal ena_disable_io_intr_sync(adapter);
22021738cd3eSNetanel Belgazal ena_free_io_irq(adapter);
2203548c4940SSameeh Jubran ena_del_napi_in_range(adapter, 0, io_queue_count);
22041738cd3eSNetanel Belgazal
22051738cd3eSNetanel Belgazal ena_free_all_tx_bufs(adapter);
22061738cd3eSNetanel Belgazal ena_free_all_rx_bufs(adapter);
22071738cd3eSNetanel Belgazal ena_free_all_io_tx_resources(adapter);
22081738cd3eSNetanel Belgazal ena_free_all_io_rx_resources(adapter);
22091738cd3eSNetanel Belgazal }
22101738cd3eSNetanel Belgazal
22111738cd3eSNetanel Belgazal /* ena_open - Called when a network interface is made active
22121738cd3eSNetanel Belgazal * @netdev: network interface device structure
22131738cd3eSNetanel Belgazal *
22141738cd3eSNetanel Belgazal * Returns 0 on success, negative value on failure
22151738cd3eSNetanel Belgazal *
22161738cd3eSNetanel Belgazal * The open entry point is called when a network interface is made
22171738cd3eSNetanel Belgazal * active by the system (IFF_UP). At this point all resources needed
22181738cd3eSNetanel Belgazal * for transmit and receive operations are allocated, the interrupt
22191738cd3eSNetanel Belgazal * handler is registered with the OS, the watchdog timer is started,
22201738cd3eSNetanel Belgazal * and the stack is notified that the interface is ready.
22211738cd3eSNetanel Belgazal */
ena_open(struct net_device * netdev)22221738cd3eSNetanel Belgazal static int ena_open(struct net_device *netdev)
22231738cd3eSNetanel Belgazal {
22241738cd3eSNetanel Belgazal struct ena_adapter *adapter = netdev_priv(netdev);
22251738cd3eSNetanel Belgazal int rc;
22261738cd3eSNetanel Belgazal
22271738cd3eSNetanel Belgazal /* Notify the stack of the actual queue counts. */
2228faa615f9SSameeh Jubran rc = netif_set_real_num_tx_queues(netdev, adapter->num_io_queues);
22291738cd3eSNetanel Belgazal if (rc) {
22301738cd3eSNetanel Belgazal netif_err(adapter, ifup, netdev, "Can't set num tx queues\n");
22311738cd3eSNetanel Belgazal return rc;
22321738cd3eSNetanel Belgazal }
22331738cd3eSNetanel Belgazal
2234faa615f9SSameeh Jubran rc = netif_set_real_num_rx_queues(netdev, adapter->num_io_queues);
22351738cd3eSNetanel Belgazal if (rc) {
22361738cd3eSNetanel Belgazal netif_err(adapter, ifup, netdev, "Can't set num rx queues\n");
22371738cd3eSNetanel Belgazal return rc;
22381738cd3eSNetanel Belgazal }
22391738cd3eSNetanel Belgazal
22401738cd3eSNetanel Belgazal rc = ena_up(adapter);
22411738cd3eSNetanel Belgazal if (rc)
22421738cd3eSNetanel Belgazal return rc;
22431738cd3eSNetanel Belgazal
22441738cd3eSNetanel Belgazal return rc;
22451738cd3eSNetanel Belgazal }
22461738cd3eSNetanel Belgazal
22471738cd3eSNetanel Belgazal /* ena_close - Disables a network interface
22481738cd3eSNetanel Belgazal * @netdev: network interface device structure
22491738cd3eSNetanel Belgazal *
22501738cd3eSNetanel Belgazal * Returns 0, this is not allowed to fail
22511738cd3eSNetanel Belgazal *
22521738cd3eSNetanel Belgazal * The close entry point is called when an interface is de-activated
22531738cd3eSNetanel Belgazal * by the OS. The hardware is still under the drivers control, but
22541738cd3eSNetanel Belgazal * needs to be disabled. A global MAC reset is issued to stop the
22551738cd3eSNetanel Belgazal * hardware, and all transmit and receive resources are freed.
22561738cd3eSNetanel Belgazal */
ena_close(struct net_device * netdev)22571738cd3eSNetanel Belgazal static int ena_close(struct net_device *netdev)
22581738cd3eSNetanel Belgazal {
22591738cd3eSNetanel Belgazal struct ena_adapter *adapter = netdev_priv(netdev);
22601738cd3eSNetanel Belgazal
22611738cd3eSNetanel Belgazal netif_dbg(adapter, ifdown, netdev, "%s\n", __func__);
22621738cd3eSNetanel Belgazal
226358a54b9cSArthur Kiyanovski if (!test_bit(ENA_FLAG_DEVICE_RUNNING, &adapter->flags))
226458a54b9cSArthur Kiyanovski return 0;
226558a54b9cSArthur Kiyanovski
22661738cd3eSNetanel Belgazal if (test_bit(ENA_FLAG_DEV_UP, &adapter->flags))
22671738cd3eSNetanel Belgazal ena_down(adapter);
22681738cd3eSNetanel Belgazal
2269ee4552aaSNetanel Belgazal /* Check for device status and issue reset if needed*/
2270ee4552aaSNetanel Belgazal check_for_admin_com_state(adapter);
2271ee4552aaSNetanel Belgazal if (unlikely(test_bit(ENA_FLAG_TRIGGER_RESET, &adapter->flags))) {
2272ee4552aaSNetanel Belgazal netif_err(adapter, ifdown, adapter->netdev,
2273ee4552aaSNetanel Belgazal "Destroy failure, restarting device\n");
2274ee4552aaSNetanel Belgazal ena_dump_stats_to_dmesg(adapter);
2275ee4552aaSNetanel Belgazal /* rtnl lock already obtained in dev_ioctl() layer */
2276cfa324a5SNetanel Belgazal ena_destroy_device(adapter, false);
2277ee4552aaSNetanel Belgazal ena_restore_device(adapter);
2278ee4552aaSNetanel Belgazal }
2279ee4552aaSNetanel Belgazal
22801738cd3eSNetanel Belgazal return 0;
22811738cd3eSNetanel Belgazal }
22821738cd3eSNetanel Belgazal
ena_update_queue_params(struct ena_adapter * adapter,u32 new_tx_size,u32 new_rx_size,u32 new_llq_header_len)2283b0c59e53SShay Agroskin int ena_update_queue_params(struct ena_adapter *adapter,
2284eece4d2aSSameeh Jubran u32 new_tx_size,
2285b0c59e53SShay Agroskin u32 new_rx_size,
2286b0c59e53SShay Agroskin u32 new_llq_header_len)
2287eece4d2aSSameeh Jubran {
2288b0c59e53SShay Agroskin bool dev_was_up, large_llq_changed = false;
2289b0c59e53SShay Agroskin int rc = 0;
2290eece4d2aSSameeh Jubran
22912413ea97SSameeh Jubran dev_was_up = test_bit(ENA_FLAG_DEV_UP, &adapter->flags);
2292eece4d2aSSameeh Jubran ena_close(adapter->netdev);
2293eece4d2aSSameeh Jubran adapter->requested_tx_ring_size = new_tx_size;
2294eece4d2aSSameeh Jubran adapter->requested_rx_ring_size = new_rx_size;
2295548c4940SSameeh Jubran ena_init_io_rings(adapter,
2296548c4940SSameeh Jubran 0,
2297548c4940SSameeh Jubran adapter->xdp_num_queues +
2298548c4940SSameeh Jubran adapter->num_io_queues);
2299b0c59e53SShay Agroskin
2300b0c59e53SShay Agroskin large_llq_changed = adapter->ena_dev->tx_mem_queue_type ==
2301b0c59e53SShay Agroskin ENA_ADMIN_PLACEMENT_POLICY_DEV;
2302b0c59e53SShay Agroskin large_llq_changed &=
2303b0c59e53SShay Agroskin new_llq_header_len != adapter->ena_dev->tx_max_header_size;
2304b0c59e53SShay Agroskin
2305b0c59e53SShay Agroskin /* a check that the configuration is valid is done by caller */
2306b0c59e53SShay Agroskin if (large_llq_changed) {
2307b0c59e53SShay Agroskin adapter->large_llq_header_enabled = !adapter->large_llq_header_enabled;
2308b0c59e53SShay Agroskin
2309b0c59e53SShay Agroskin ena_destroy_device(adapter, false);
2310b0c59e53SShay Agroskin rc = ena_restore_device(adapter);
2311b0c59e53SShay Agroskin }
2312b0c59e53SShay Agroskin
2313b0c59e53SShay Agroskin return dev_was_up && !rc ? ena_up(adapter) : rc;
23142413ea97SSameeh Jubran }
23152413ea97SSameeh Jubran
ena_set_rx_copybreak(struct ena_adapter * adapter,u32 rx_copybreak)2316c7062aaeSDavid Arinzon int ena_set_rx_copybreak(struct ena_adapter *adapter, u32 rx_copybreak)
2317c7062aaeSDavid Arinzon {
2318c7062aaeSDavid Arinzon struct ena_ring *rx_ring;
2319c7062aaeSDavid Arinzon int i;
2320c7062aaeSDavid Arinzon
2321c7062aaeSDavid Arinzon if (rx_copybreak > min_t(u16, adapter->netdev->mtu, ENA_PAGE_SIZE))
2322c7062aaeSDavid Arinzon return -EINVAL;
2323c7062aaeSDavid Arinzon
2324c7062aaeSDavid Arinzon adapter->rx_copybreak = rx_copybreak;
2325c7062aaeSDavid Arinzon
2326c7062aaeSDavid Arinzon for (i = 0; i < adapter->num_io_queues; i++) {
2327c7062aaeSDavid Arinzon rx_ring = &adapter->rx_ring[i];
2328c7062aaeSDavid Arinzon rx_ring->rx_copybreak = rx_copybreak;
2329c7062aaeSDavid Arinzon }
2330c7062aaeSDavid Arinzon
2331c7062aaeSDavid Arinzon return 0;
2332c7062aaeSDavid Arinzon }
2333c7062aaeSDavid Arinzon
ena_update_queue_count(struct ena_adapter * adapter,u32 new_channel_count)23342413ea97SSameeh Jubran int ena_update_queue_count(struct ena_adapter *adapter, u32 new_channel_count)
23352413ea97SSameeh Jubran {
23362413ea97SSameeh Jubran struct ena_com_dev *ena_dev = adapter->ena_dev;
2337838c93dcSSameeh Jubran int prev_channel_count;
23382413ea97SSameeh Jubran bool dev_was_up;
23392413ea97SSameeh Jubran
23402413ea97SSameeh Jubran dev_was_up = test_bit(ENA_FLAG_DEV_UP, &adapter->flags);
23412413ea97SSameeh Jubran ena_close(adapter->netdev);
2342838c93dcSSameeh Jubran prev_channel_count = adapter->num_io_queues;
23432413ea97SSameeh Jubran adapter->num_io_queues = new_channel_count;
2344548c4940SSameeh Jubran if (ena_xdp_present(adapter) &&
2345548c4940SSameeh Jubran ena_xdp_allowed(adapter) == ENA_XDP_ALLOWED) {
2346548c4940SSameeh Jubran adapter->xdp_first_ring = new_channel_count;
2347548c4940SSameeh Jubran adapter->xdp_num_queues = new_channel_count;
2348838c93dcSSameeh Jubran if (prev_channel_count > new_channel_count)
2349838c93dcSSameeh Jubran ena_xdp_exchange_program_rx_in_range(adapter,
2350838c93dcSSameeh Jubran NULL,
2351838c93dcSSameeh Jubran new_channel_count,
2352838c93dcSSameeh Jubran prev_channel_count);
2353838c93dcSSameeh Jubran else
2354838c93dcSSameeh Jubran ena_xdp_exchange_program_rx_in_range(adapter,
2355838c93dcSSameeh Jubran adapter->xdp_bpf_prog,
2356838c93dcSSameeh Jubran prev_channel_count,
2357838c93dcSSameeh Jubran new_channel_count);
2358838c93dcSSameeh Jubran }
2359838c93dcSSameeh Jubran
23602413ea97SSameeh Jubran /* We need to destroy the rss table so that the indirection
23612413ea97SSameeh Jubran * table will be reinitialized by ena_up()
23622413ea97SSameeh Jubran */
23632413ea97SSameeh Jubran ena_com_rss_destroy(ena_dev);
2364548c4940SSameeh Jubran ena_init_io_rings(adapter,
2365548c4940SSameeh Jubran 0,
2366548c4940SSameeh Jubran adapter->xdp_num_queues +
2367548c4940SSameeh Jubran adapter->num_io_queues);
23682413ea97SSameeh Jubran return dev_was_up ? ena_open(adapter->netdev) : 0;
2369eece4d2aSSameeh Jubran }
2370eece4d2aSSameeh Jubran
ena_tx_csum(struct ena_com_tx_ctx * ena_tx_ctx,struct sk_buff * skb,bool disable_meta_caching)23710e3a3f6dSArthur Kiyanovski static void ena_tx_csum(struct ena_com_tx_ctx *ena_tx_ctx,
23720e3a3f6dSArthur Kiyanovski struct sk_buff *skb,
23730e3a3f6dSArthur Kiyanovski bool disable_meta_caching)
23741738cd3eSNetanel Belgazal {
23751738cd3eSNetanel Belgazal u32 mss = skb_shinfo(skb)->gso_size;
23761738cd3eSNetanel Belgazal struct ena_com_tx_meta *ena_meta = &ena_tx_ctx->ena_meta;
23771738cd3eSNetanel Belgazal u8 l4_protocol = 0;
23781738cd3eSNetanel Belgazal
23791738cd3eSNetanel Belgazal if ((skb->ip_summed == CHECKSUM_PARTIAL) || mss) {
23801738cd3eSNetanel Belgazal ena_tx_ctx->l4_csum_enable = 1;
23811738cd3eSNetanel Belgazal if (mss) {
23821738cd3eSNetanel Belgazal ena_tx_ctx->tso_enable = 1;
23831738cd3eSNetanel Belgazal ena_meta->l4_hdr_len = tcp_hdr(skb)->doff;
23841738cd3eSNetanel Belgazal ena_tx_ctx->l4_csum_partial = 0;
23851738cd3eSNetanel Belgazal } else {
23861738cd3eSNetanel Belgazal ena_tx_ctx->tso_enable = 0;
23871738cd3eSNetanel Belgazal ena_meta->l4_hdr_len = 0;
23881738cd3eSNetanel Belgazal ena_tx_ctx->l4_csum_partial = 1;
23891738cd3eSNetanel Belgazal }
23901738cd3eSNetanel Belgazal
23911738cd3eSNetanel Belgazal switch (ip_hdr(skb)->version) {
23921738cd3eSNetanel Belgazal case IPVERSION:
23931738cd3eSNetanel Belgazal ena_tx_ctx->l3_proto = ENA_ETH_IO_L3_PROTO_IPV4;
23941738cd3eSNetanel Belgazal if (ip_hdr(skb)->frag_off & htons(IP_DF))
23951738cd3eSNetanel Belgazal ena_tx_ctx->df = 1;
23961738cd3eSNetanel Belgazal if (mss)
23971738cd3eSNetanel Belgazal ena_tx_ctx->l3_csum_enable = 1;
23981738cd3eSNetanel Belgazal l4_protocol = ip_hdr(skb)->protocol;
23991738cd3eSNetanel Belgazal break;
24001738cd3eSNetanel Belgazal case 6:
24011738cd3eSNetanel Belgazal ena_tx_ctx->l3_proto = ENA_ETH_IO_L3_PROTO_IPV6;
24021738cd3eSNetanel Belgazal l4_protocol = ipv6_hdr(skb)->nexthdr;
24031738cd3eSNetanel Belgazal break;
24041738cd3eSNetanel Belgazal default:
24051738cd3eSNetanel Belgazal break;
24061738cd3eSNetanel Belgazal }
24071738cd3eSNetanel Belgazal
24081738cd3eSNetanel Belgazal if (l4_protocol == IPPROTO_TCP)
24091738cd3eSNetanel Belgazal ena_tx_ctx->l4_proto = ENA_ETH_IO_L4_PROTO_TCP;
24101738cd3eSNetanel Belgazal else
24111738cd3eSNetanel Belgazal ena_tx_ctx->l4_proto = ENA_ETH_IO_L4_PROTO_UDP;
24121738cd3eSNetanel Belgazal
24131738cd3eSNetanel Belgazal ena_meta->mss = mss;
24141738cd3eSNetanel Belgazal ena_meta->l3_hdr_len = skb_network_header_len(skb);
24151738cd3eSNetanel Belgazal ena_meta->l3_hdr_offset = skb_network_offset(skb);
24161738cd3eSNetanel Belgazal ena_tx_ctx->meta_valid = 1;
24170e3a3f6dSArthur Kiyanovski } else if (disable_meta_caching) {
24180e3a3f6dSArthur Kiyanovski memset(ena_meta, 0, sizeof(*ena_meta));
24190e3a3f6dSArthur Kiyanovski ena_tx_ctx->meta_valid = 1;
24201738cd3eSNetanel Belgazal } else {
24211738cd3eSNetanel Belgazal ena_tx_ctx->meta_valid = 0;
24221738cd3eSNetanel Belgazal }
24231738cd3eSNetanel Belgazal }
24241738cd3eSNetanel Belgazal
ena_check_and_linearize_skb(struct ena_ring * tx_ring,struct sk_buff * skb)24251738cd3eSNetanel Belgazal static int ena_check_and_linearize_skb(struct ena_ring *tx_ring,
24261738cd3eSNetanel Belgazal struct sk_buff *skb)
24271738cd3eSNetanel Belgazal {
24281738cd3eSNetanel Belgazal int num_frags, header_len, rc;
24291738cd3eSNetanel Belgazal
24301738cd3eSNetanel Belgazal num_frags = skb_shinfo(skb)->nr_frags;
24311738cd3eSNetanel Belgazal header_len = skb_headlen(skb);
24321738cd3eSNetanel Belgazal
24331738cd3eSNetanel Belgazal if (num_frags < tx_ring->sgl_size)
24341738cd3eSNetanel Belgazal return 0;
24351738cd3eSNetanel Belgazal
24361738cd3eSNetanel Belgazal if ((num_frags == tx_ring->sgl_size) &&
24371738cd3eSNetanel Belgazal (header_len < tx_ring->tx_max_header_size))
24381738cd3eSNetanel Belgazal return 0;
24391738cd3eSNetanel Belgazal
244089dd735eSShay Agroskin ena_increase_stat(&tx_ring->tx_stats.linearize, 1, &tx_ring->syncp);
24411738cd3eSNetanel Belgazal
24421738cd3eSNetanel Belgazal rc = skb_linearize(skb);
24431738cd3eSNetanel Belgazal if (unlikely(rc)) {
244489dd735eSShay Agroskin ena_increase_stat(&tx_ring->tx_stats.linearize_failed, 1,
244589dd735eSShay Agroskin &tx_ring->syncp);
24461738cd3eSNetanel Belgazal }
24471738cd3eSNetanel Belgazal
24481738cd3eSNetanel Belgazal return rc;
24491738cd3eSNetanel Belgazal }
24501738cd3eSNetanel Belgazal
ena_tx_map_skb(struct ena_ring * tx_ring,struct ena_tx_buffer * tx_info,struct sk_buff * skb,void ** push_hdr,u16 * header_len)245138005ca8SArthur Kiyanovski static int ena_tx_map_skb(struct ena_ring *tx_ring,
245238005ca8SArthur Kiyanovski struct ena_tx_buffer *tx_info,
245338005ca8SArthur Kiyanovski struct sk_buff *skb,
245438005ca8SArthur Kiyanovski void **push_hdr,
245538005ca8SArthur Kiyanovski u16 *header_len)
245638005ca8SArthur Kiyanovski {
245738005ca8SArthur Kiyanovski struct ena_adapter *adapter = tx_ring->adapter;
245838005ca8SArthur Kiyanovski struct ena_com_buf *ena_buf;
245938005ca8SArthur Kiyanovski dma_addr_t dma;
246038005ca8SArthur Kiyanovski u32 skb_head_len, frag_len, last_frag;
246138005ca8SArthur Kiyanovski u16 push_len = 0;
246238005ca8SArthur Kiyanovski u16 delta = 0;
246338005ca8SArthur Kiyanovski int i = 0;
246438005ca8SArthur Kiyanovski
246538005ca8SArthur Kiyanovski skb_head_len = skb_headlen(skb);
246638005ca8SArthur Kiyanovski tx_info->skb = skb;
246738005ca8SArthur Kiyanovski ena_buf = tx_info->bufs;
246838005ca8SArthur Kiyanovski
246938005ca8SArthur Kiyanovski if (tx_ring->tx_mem_queue_type == ENA_ADMIN_PLACEMENT_POLICY_DEV) {
247038005ca8SArthur Kiyanovski /* When the device is LLQ mode, the driver will copy
247138005ca8SArthur Kiyanovski * the header into the device memory space.
247238005ca8SArthur Kiyanovski * the ena_com layer assume the header is in a linear
247338005ca8SArthur Kiyanovski * memory space.
247438005ca8SArthur Kiyanovski * This assumption might be wrong since part of the header
247538005ca8SArthur Kiyanovski * can be in the fragmented buffers.
247638005ca8SArthur Kiyanovski * Use skb_header_pointer to make sure the header is in a
247738005ca8SArthur Kiyanovski * linear memory space.
247838005ca8SArthur Kiyanovski */
247938005ca8SArthur Kiyanovski
248038005ca8SArthur Kiyanovski push_len = min_t(u32, skb->len, tx_ring->tx_max_header_size);
248138005ca8SArthur Kiyanovski *push_hdr = skb_header_pointer(skb, 0, push_len,
248238005ca8SArthur Kiyanovski tx_ring->push_buf_intermediate_buf);
248338005ca8SArthur Kiyanovski *header_len = push_len;
248438005ca8SArthur Kiyanovski if (unlikely(skb->data != *push_hdr)) {
248589dd735eSShay Agroskin ena_increase_stat(&tx_ring->tx_stats.llq_buffer_copy, 1,
248689dd735eSShay Agroskin &tx_ring->syncp);
248738005ca8SArthur Kiyanovski
248838005ca8SArthur Kiyanovski delta = push_len - skb_head_len;
248938005ca8SArthur Kiyanovski }
249038005ca8SArthur Kiyanovski } else {
249138005ca8SArthur Kiyanovski *push_hdr = NULL;
249238005ca8SArthur Kiyanovski *header_len = min_t(u32, skb_head_len,
249338005ca8SArthur Kiyanovski tx_ring->tx_max_header_size);
249438005ca8SArthur Kiyanovski }
249538005ca8SArthur Kiyanovski
249638005ca8SArthur Kiyanovski netif_dbg(adapter, tx_queued, adapter->netdev,
249738005ca8SArthur Kiyanovski "skb: %p header_buf->vaddr: %p push_len: %d\n", skb,
249838005ca8SArthur Kiyanovski *push_hdr, push_len);
249938005ca8SArthur Kiyanovski
250038005ca8SArthur Kiyanovski if (skb_head_len > push_len) {
250138005ca8SArthur Kiyanovski dma = dma_map_single(tx_ring->dev, skb->data + push_len,
250238005ca8SArthur Kiyanovski skb_head_len - push_len, DMA_TO_DEVICE);
250338005ca8SArthur Kiyanovski if (unlikely(dma_mapping_error(tx_ring->dev, dma)))
250438005ca8SArthur Kiyanovski goto error_report_dma_error;
250538005ca8SArthur Kiyanovski
250638005ca8SArthur Kiyanovski ena_buf->paddr = dma;
250738005ca8SArthur Kiyanovski ena_buf->len = skb_head_len - push_len;
250838005ca8SArthur Kiyanovski
250938005ca8SArthur Kiyanovski ena_buf++;
251038005ca8SArthur Kiyanovski tx_info->num_of_bufs++;
251138005ca8SArthur Kiyanovski tx_info->map_linear_data = 1;
251238005ca8SArthur Kiyanovski } else {
251338005ca8SArthur Kiyanovski tx_info->map_linear_data = 0;
251438005ca8SArthur Kiyanovski }
251538005ca8SArthur Kiyanovski
251638005ca8SArthur Kiyanovski last_frag = skb_shinfo(skb)->nr_frags;
251738005ca8SArthur Kiyanovski
251838005ca8SArthur Kiyanovski for (i = 0; i < last_frag; i++) {
251938005ca8SArthur Kiyanovski const skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
252038005ca8SArthur Kiyanovski
252138005ca8SArthur Kiyanovski frag_len = skb_frag_size(frag);
252238005ca8SArthur Kiyanovski
252338005ca8SArthur Kiyanovski if (unlikely(delta >= frag_len)) {
252438005ca8SArthur Kiyanovski delta -= frag_len;
252538005ca8SArthur Kiyanovski continue;
252638005ca8SArthur Kiyanovski }
252738005ca8SArthur Kiyanovski
252838005ca8SArthur Kiyanovski dma = skb_frag_dma_map(tx_ring->dev, frag, delta,
252938005ca8SArthur Kiyanovski frag_len - delta, DMA_TO_DEVICE);
253038005ca8SArthur Kiyanovski if (unlikely(dma_mapping_error(tx_ring->dev, dma)))
253138005ca8SArthur Kiyanovski goto error_report_dma_error;
253238005ca8SArthur Kiyanovski
253338005ca8SArthur Kiyanovski ena_buf->paddr = dma;
253438005ca8SArthur Kiyanovski ena_buf->len = frag_len - delta;
253538005ca8SArthur Kiyanovski ena_buf++;
253638005ca8SArthur Kiyanovski tx_info->num_of_bufs++;
253738005ca8SArthur Kiyanovski delta = 0;
253838005ca8SArthur Kiyanovski }
253938005ca8SArthur Kiyanovski
254038005ca8SArthur Kiyanovski return 0;
254138005ca8SArthur Kiyanovski
254238005ca8SArthur Kiyanovski error_report_dma_error:
254389dd735eSShay Agroskin ena_increase_stat(&tx_ring->tx_stats.dma_mapping_err, 1,
254489dd735eSShay Agroskin &tx_ring->syncp);
2545bf2746e8SShay Agroskin netif_warn(adapter, tx_queued, adapter->netdev, "Failed to map skb\n");
254638005ca8SArthur Kiyanovski
254738005ca8SArthur Kiyanovski tx_info->skb = NULL;
254838005ca8SArthur Kiyanovski
254938005ca8SArthur Kiyanovski tx_info->num_of_bufs += i;
2550548c4940SSameeh Jubran ena_unmap_tx_buff(tx_ring, tx_info);
255138005ca8SArthur Kiyanovski
255238005ca8SArthur Kiyanovski return -EINVAL;
255338005ca8SArthur Kiyanovski }
255438005ca8SArthur Kiyanovski
25551738cd3eSNetanel Belgazal /* Called with netif_tx_lock. */
ena_start_xmit(struct sk_buff * skb,struct net_device * dev)25561738cd3eSNetanel Belgazal static netdev_tx_t ena_start_xmit(struct sk_buff *skb, struct net_device *dev)
25571738cd3eSNetanel Belgazal {
25581738cd3eSNetanel Belgazal struct ena_adapter *adapter = netdev_priv(dev);
25591738cd3eSNetanel Belgazal struct ena_tx_buffer *tx_info;
25601738cd3eSNetanel Belgazal struct ena_com_tx_ctx ena_tx_ctx;
25611738cd3eSNetanel Belgazal struct ena_ring *tx_ring;
25621738cd3eSNetanel Belgazal struct netdev_queue *txq;
25631738cd3eSNetanel Belgazal void *push_hdr;
256438005ca8SArthur Kiyanovski u16 next_to_use, req_id, header_len;
2565548c4940SSameeh Jubran int qid, rc;
25661738cd3eSNetanel Belgazal
25671738cd3eSNetanel Belgazal netif_dbg(adapter, tx_queued, dev, "%s skb %p\n", __func__, skb);
25681738cd3eSNetanel Belgazal /* Determine which tx ring we will be placed on */
25691738cd3eSNetanel Belgazal qid = skb_get_queue_mapping(skb);
25701738cd3eSNetanel Belgazal tx_ring = &adapter->tx_ring[qid];
25711738cd3eSNetanel Belgazal txq = netdev_get_tx_queue(dev, qid);
25721738cd3eSNetanel Belgazal
25731738cd3eSNetanel Belgazal rc = ena_check_and_linearize_skb(tx_ring, skb);
25741738cd3eSNetanel Belgazal if (unlikely(rc))
25751738cd3eSNetanel Belgazal goto error_drop_packet;
25761738cd3eSNetanel Belgazal
25771738cd3eSNetanel Belgazal skb_tx_timestamp(skb);
25781738cd3eSNetanel Belgazal
25791738cd3eSNetanel Belgazal next_to_use = tx_ring->next_to_use;
2580f9172498SSameeh Jubran req_id = tx_ring->free_ids[next_to_use];
25811738cd3eSNetanel Belgazal tx_info = &tx_ring->tx_buffer_info[req_id];
25821738cd3eSNetanel Belgazal tx_info->num_of_bufs = 0;
25831738cd3eSNetanel Belgazal
25841738cd3eSNetanel Belgazal WARN(tx_info->skb, "SKB isn't NULL req_id %d\n", req_id);
25851738cd3eSNetanel Belgazal
258638005ca8SArthur Kiyanovski rc = ena_tx_map_skb(tx_ring, tx_info, skb, &push_hdr, &header_len);
258738005ca8SArthur Kiyanovski if (unlikely(rc))
258838005ca8SArthur Kiyanovski goto error_drop_packet;
25891738cd3eSNetanel Belgazal
25901738cd3eSNetanel Belgazal memset(&ena_tx_ctx, 0x0, sizeof(struct ena_com_tx_ctx));
25911738cd3eSNetanel Belgazal ena_tx_ctx.ena_bufs = tx_info->bufs;
25921738cd3eSNetanel Belgazal ena_tx_ctx.push_header = push_hdr;
25931738cd3eSNetanel Belgazal ena_tx_ctx.num_bufs = tx_info->num_of_bufs;
25941738cd3eSNetanel Belgazal ena_tx_ctx.req_id = req_id;
25951738cd3eSNetanel Belgazal ena_tx_ctx.header_len = header_len;
25961738cd3eSNetanel Belgazal
25971738cd3eSNetanel Belgazal /* set flags and meta data */
25980e3a3f6dSArthur Kiyanovski ena_tx_csum(&ena_tx_ctx, skb, tx_ring->disable_meta_caching);
25991738cd3eSNetanel Belgazal
2600bc0ad685SDavid Arinzon rc = ena_xmit_common(adapter,
2601548c4940SSameeh Jubran tx_ring,
2602548c4940SSameeh Jubran tx_info,
2603548c4940SSameeh Jubran &ena_tx_ctx,
2604548c4940SSameeh Jubran next_to_use,
2605548c4940SSameeh Jubran skb->len);
2606548c4940SSameeh Jubran if (rc)
26071738cd3eSNetanel Belgazal goto error_unmap_dma;
26081738cd3eSNetanel Belgazal
26091738cd3eSNetanel Belgazal netdev_tx_sent_queue(txq, skb->len);
26101738cd3eSNetanel Belgazal
26111738cd3eSNetanel Belgazal /* stop the queue when no more space available, the packet can have up
26121738cd3eSNetanel Belgazal * to sgl_size + 2. one for the meta descriptor and one for header
26131738cd3eSNetanel Belgazal * (if the header is larger than tx_max_header_size).
26141738cd3eSNetanel Belgazal */
2615689b2bdaSArthur Kiyanovski if (unlikely(!ena_com_sq_have_enough_space(tx_ring->ena_com_io_sq,
2616689b2bdaSArthur Kiyanovski tx_ring->sgl_size + 2))) {
26171738cd3eSNetanel Belgazal netif_dbg(adapter, tx_queued, dev, "%s stop queue %d\n",
26181738cd3eSNetanel Belgazal __func__, qid);
26191738cd3eSNetanel Belgazal
26201738cd3eSNetanel Belgazal netif_tx_stop_queue(txq);
262189dd735eSShay Agroskin ena_increase_stat(&tx_ring->tx_stats.queue_stop, 1,
262289dd735eSShay Agroskin &tx_ring->syncp);
26231738cd3eSNetanel Belgazal
26241738cd3eSNetanel Belgazal /* There is a rare condition where this function decide to
26251738cd3eSNetanel Belgazal * stop the queue but meanwhile clean_tx_irq updates
26261738cd3eSNetanel Belgazal * next_to_completion and terminates.
26271738cd3eSNetanel Belgazal * The queue will remain stopped forever.
262837dff155SNetanel Belgazal * To solve this issue add a mb() to make sure that
262937dff155SNetanel Belgazal * netif_tx_stop_queue() write is vissible before checking if
263037dff155SNetanel Belgazal * there is additional space in the queue.
26311738cd3eSNetanel Belgazal */
263237dff155SNetanel Belgazal smp_mb();
26331738cd3eSNetanel Belgazal
2634689b2bdaSArthur Kiyanovski if (ena_com_sq_have_enough_space(tx_ring->ena_com_io_sq,
2635689b2bdaSArthur Kiyanovski ENA_TX_WAKEUP_THRESH)) {
26361738cd3eSNetanel Belgazal netif_tx_wake_queue(txq);
263789dd735eSShay Agroskin ena_increase_stat(&tx_ring->tx_stats.queue_wakeup, 1,
263889dd735eSShay Agroskin &tx_ring->syncp);
26391738cd3eSNetanel Belgazal }
26401738cd3eSNetanel Belgazal }
26411738cd3eSNetanel Belgazal
26429e8afb05SShay Agroskin if (netif_xmit_stopped(txq) || !netdev_xmit_more())
26439e8afb05SShay Agroskin /* trigger the dma engine. ena_ring_tx_doorbell()
26449e8afb05SShay Agroskin * calls a memory barrier inside it.
264537dff155SNetanel Belgazal */
26469e8afb05SShay Agroskin ena_ring_tx_doorbell(tx_ring);
26471738cd3eSNetanel Belgazal
26481738cd3eSNetanel Belgazal return NETDEV_TX_OK;
26491738cd3eSNetanel Belgazal
26501738cd3eSNetanel Belgazal error_unmap_dma:
2651548c4940SSameeh Jubran ena_unmap_tx_buff(tx_ring, tx_info);
26521738cd3eSNetanel Belgazal tx_info->skb = NULL;
26531738cd3eSNetanel Belgazal
26541738cd3eSNetanel Belgazal error_drop_packet:
26551738cd3eSNetanel Belgazal dev_kfree_skb(skb);
26561738cd3eSNetanel Belgazal return NETDEV_TX_OK;
26571738cd3eSNetanel Belgazal }
26581738cd3eSNetanel Belgazal
ena_config_host_info(struct ena_com_dev * ena_dev,struct pci_dev * pdev)265946143e58SArthur Kiyanovski static void ena_config_host_info(struct ena_com_dev *ena_dev, struct pci_dev *pdev)
26601738cd3eSNetanel Belgazal {
2661f0525298SShay Agroskin struct device *dev = &pdev->dev;
26621738cd3eSNetanel Belgazal struct ena_admin_host_info *host_info;
26631738cd3eSNetanel Belgazal int rc;
26641738cd3eSNetanel Belgazal
26651738cd3eSNetanel Belgazal /* Allocate only the host info */
26661738cd3eSNetanel Belgazal rc = ena_com_allocate_host_info(ena_dev);
26671738cd3eSNetanel Belgazal if (rc) {
2668f0525298SShay Agroskin dev_err(dev, "Cannot allocate host info\n");
26691738cd3eSNetanel Belgazal return;
26701738cd3eSNetanel Belgazal }
26711738cd3eSNetanel Belgazal
26721738cd3eSNetanel Belgazal host_info = ena_dev->host_attr.host_info;
26731738cd3eSNetanel Belgazal
2674a5e5b2cdSJialin Zhang host_info->bdf = pci_dev_id(pdev);
26751738cd3eSNetanel Belgazal host_info->os_type = ENA_ADMIN_OS_LINUX;
26761738cd3eSNetanel Belgazal host_info->kernel_ver = LINUX_VERSION_CODE;
2677f029c781SWolfram Sang strscpy(host_info->kernel_ver_str, utsname()->version,
26781738cd3eSNetanel Belgazal sizeof(host_info->kernel_ver_str) - 1);
26791738cd3eSNetanel Belgazal host_info->os_dist = 0;
26801738cd3eSNetanel Belgazal strncpy(host_info->os_dist_str, utsname()->release,
26811738cd3eSNetanel Belgazal sizeof(host_info->os_dist_str) - 1);
268292040c6dSArthur Kiyanovski host_info->driver_version =
268392040c6dSArthur Kiyanovski (DRV_MODULE_GEN_MAJOR) |
268492040c6dSArthur Kiyanovski (DRV_MODULE_GEN_MINOR << ENA_ADMIN_HOST_INFO_MINOR_SHIFT) |
268592040c6dSArthur Kiyanovski (DRV_MODULE_GEN_SUBMINOR << ENA_ADMIN_HOST_INFO_SUB_MINOR_SHIFT) |
268692040c6dSArthur Kiyanovski ("K"[0] << ENA_ADMIN_HOST_INFO_MODULE_TYPE_SHIFT);
2687095f2f1fSArthur Kiyanovski host_info->num_cpus = num_online_cpus();
26881738cd3eSNetanel Belgazal
2689bd21b0ccSArthur Kiyanovski host_info->driver_supported_features =
269068f236dfSArthur Kiyanovski ENA_ADMIN_HOST_INFO_RX_OFFSET_MASK |
26910f505c60SArthur Kiyanovski ENA_ADMIN_HOST_INFO_INTERRUPT_MODERATION_MASK |
26920ee60edfSArthur Kiyanovski ENA_ADMIN_HOST_INFO_RX_BUF_MIRRORING_MASK |
2693f7d625adSDavid Arinzon ENA_ADMIN_HOST_INFO_RSS_CONFIGURABLE_FUNCTION_KEY_MASK |
2694f7d625adSDavid Arinzon ENA_ADMIN_HOST_INFO_RX_PAGE_REUSE_MASK;
2695bd21b0ccSArthur Kiyanovski
26961738cd3eSNetanel Belgazal rc = ena_com_set_host_attributes(ena_dev);
26971738cd3eSNetanel Belgazal if (rc) {
2698d1497638SNetanel Belgazal if (rc == -EOPNOTSUPP)
2699f0525298SShay Agroskin dev_warn(dev, "Cannot set host attributes\n");
27001738cd3eSNetanel Belgazal else
2701f0525298SShay Agroskin dev_err(dev, "Cannot set host attributes\n");
27021738cd3eSNetanel Belgazal
27031738cd3eSNetanel Belgazal goto err;
27041738cd3eSNetanel Belgazal }
27051738cd3eSNetanel Belgazal
27061738cd3eSNetanel Belgazal return;
27071738cd3eSNetanel Belgazal
27081738cd3eSNetanel Belgazal err:
27091738cd3eSNetanel Belgazal ena_com_delete_host_info(ena_dev);
27101738cd3eSNetanel Belgazal }
27111738cd3eSNetanel Belgazal
ena_config_debug_area(struct ena_adapter * adapter)27121738cd3eSNetanel Belgazal static void ena_config_debug_area(struct ena_adapter *adapter)
27131738cd3eSNetanel Belgazal {
27141738cd3eSNetanel Belgazal u32 debug_area_size;
27151738cd3eSNetanel Belgazal int rc, ss_count;
27161738cd3eSNetanel Belgazal
27171738cd3eSNetanel Belgazal ss_count = ena_get_sset_count(adapter->netdev, ETH_SS_STATS);
27181738cd3eSNetanel Belgazal if (ss_count <= 0) {
27191738cd3eSNetanel Belgazal netif_err(adapter, drv, adapter->netdev,
27201738cd3eSNetanel Belgazal "SS count is negative\n");
27211738cd3eSNetanel Belgazal return;
27221738cd3eSNetanel Belgazal }
27231738cd3eSNetanel Belgazal
27241738cd3eSNetanel Belgazal /* allocate 32 bytes for each string and 64bit for the value */
27251738cd3eSNetanel Belgazal debug_area_size = ss_count * ETH_GSTRING_LEN + sizeof(u64) * ss_count;
27261738cd3eSNetanel Belgazal
27271738cd3eSNetanel Belgazal rc = ena_com_allocate_debug_area(adapter->ena_dev, debug_area_size);
27281738cd3eSNetanel Belgazal if (rc) {
2729f0525298SShay Agroskin netif_err(adapter, drv, adapter->netdev,
2730f0525298SShay Agroskin "Cannot allocate debug area\n");
27311738cd3eSNetanel Belgazal return;
27321738cd3eSNetanel Belgazal }
27331738cd3eSNetanel Belgazal
27341738cd3eSNetanel Belgazal rc = ena_com_set_host_attributes(adapter->ena_dev);
27351738cd3eSNetanel Belgazal if (rc) {
2736d1497638SNetanel Belgazal if (rc == -EOPNOTSUPP)
2737*26668c2dSDavid Arinzon netif_warn(adapter, drv, adapter->netdev, "Cannot set host attributes\n");
27381738cd3eSNetanel Belgazal else
27391738cd3eSNetanel Belgazal netif_err(adapter, drv, adapter->netdev,
27401738cd3eSNetanel Belgazal "Cannot set host attributes\n");
27411738cd3eSNetanel Belgazal goto err;
27421738cd3eSNetanel Belgazal }
27431738cd3eSNetanel Belgazal
27441738cd3eSNetanel Belgazal return;
27451738cd3eSNetanel Belgazal err:
27461738cd3eSNetanel Belgazal ena_com_delete_debug_area(adapter->ena_dev);
27471738cd3eSNetanel Belgazal }
27481738cd3eSNetanel Belgazal
ena_update_hw_stats(struct ena_adapter * adapter)2749713865daSSameeh Jubran int ena_update_hw_stats(struct ena_adapter *adapter)
2750713865daSSameeh Jubran {
2751394c48e0SArthur Kiyanovski int rc;
2752713865daSSameeh Jubran
2753713865daSSameeh Jubran rc = ena_com_get_eni_stats(adapter->ena_dev, &adapter->eni_stats);
2754713865daSSameeh Jubran if (rc) {
2755394c48e0SArthur Kiyanovski netdev_err(adapter->netdev, "Failed to get ENI stats\n");
2756713865daSSameeh Jubran return rc;
2757713865daSSameeh Jubran }
2758713865daSSameeh Jubran
2759713865daSSameeh Jubran return 0;
2760713865daSSameeh Jubran }
2761713865daSSameeh Jubran
ena_get_stats64(struct net_device * netdev,struct rtnl_link_stats64 * stats)2762bc1f4470Sstephen hemminger static void ena_get_stats64(struct net_device *netdev,
27631738cd3eSNetanel Belgazal struct rtnl_link_stats64 *stats)
27641738cd3eSNetanel Belgazal {
27651738cd3eSNetanel Belgazal struct ena_adapter *adapter = netdev_priv(netdev);
2766d81db240SNetanel Belgazal struct ena_ring *rx_ring, *tx_ring;
2767d81db240SNetanel Belgazal unsigned int start;
2768d81db240SNetanel Belgazal u64 rx_drops;
27695c665f8cSSameeh Jubran u64 tx_drops;
2770d81db240SNetanel Belgazal int i;
27711738cd3eSNetanel Belgazal
27721738cd3eSNetanel Belgazal if (!test_bit(ENA_FLAG_DEV_UP, &adapter->flags))
2773bc1f4470Sstephen hemminger return;
27741738cd3eSNetanel Belgazal
2775faa615f9SSameeh Jubran for (i = 0; i < adapter->num_io_queues; i++) {
2776d81db240SNetanel Belgazal u64 bytes, packets;
27771738cd3eSNetanel Belgazal
2778d81db240SNetanel Belgazal tx_ring = &adapter->tx_ring[i];
27791738cd3eSNetanel Belgazal
2780d81db240SNetanel Belgazal do {
2781068c38adSThomas Gleixner start = u64_stats_fetch_begin(&tx_ring->syncp);
2782d81db240SNetanel Belgazal packets = tx_ring->tx_stats.cnt;
2783d81db240SNetanel Belgazal bytes = tx_ring->tx_stats.bytes;
2784068c38adSThomas Gleixner } while (u64_stats_fetch_retry(&tx_ring->syncp, start));
27851738cd3eSNetanel Belgazal
2786d81db240SNetanel Belgazal stats->tx_packets += packets;
2787d81db240SNetanel Belgazal stats->tx_bytes += bytes;
2788d81db240SNetanel Belgazal
2789d81db240SNetanel Belgazal rx_ring = &adapter->rx_ring[i];
2790d81db240SNetanel Belgazal
2791d81db240SNetanel Belgazal do {
2792068c38adSThomas Gleixner start = u64_stats_fetch_begin(&rx_ring->syncp);
2793d81db240SNetanel Belgazal packets = rx_ring->rx_stats.cnt;
2794d81db240SNetanel Belgazal bytes = rx_ring->rx_stats.bytes;
2795068c38adSThomas Gleixner } while (u64_stats_fetch_retry(&rx_ring->syncp, start));
2796d81db240SNetanel Belgazal
2797d81db240SNetanel Belgazal stats->rx_packets += packets;
2798d81db240SNetanel Belgazal stats->rx_bytes += bytes;
2799d81db240SNetanel Belgazal }
2800d81db240SNetanel Belgazal
2801d81db240SNetanel Belgazal do {
2802068c38adSThomas Gleixner start = u64_stats_fetch_begin(&adapter->syncp);
2803d81db240SNetanel Belgazal rx_drops = adapter->dev_stats.rx_drops;
28045c665f8cSSameeh Jubran tx_drops = adapter->dev_stats.tx_drops;
2805068c38adSThomas Gleixner } while (u64_stats_fetch_retry(&adapter->syncp, start));
2806d81db240SNetanel Belgazal
2807d81db240SNetanel Belgazal stats->rx_dropped = rx_drops;
28085c665f8cSSameeh Jubran stats->tx_dropped = tx_drops;
28091738cd3eSNetanel Belgazal
28101738cd3eSNetanel Belgazal stats->multicast = 0;
28111738cd3eSNetanel Belgazal stats->collisions = 0;
28121738cd3eSNetanel Belgazal
28131738cd3eSNetanel Belgazal stats->rx_length_errors = 0;
28141738cd3eSNetanel Belgazal stats->rx_crc_errors = 0;
28151738cd3eSNetanel Belgazal stats->rx_frame_errors = 0;
28161738cd3eSNetanel Belgazal stats->rx_fifo_errors = 0;
28171738cd3eSNetanel Belgazal stats->rx_missed_errors = 0;
28181738cd3eSNetanel Belgazal stats->tx_window_errors = 0;
28191738cd3eSNetanel Belgazal
28201738cd3eSNetanel Belgazal stats->rx_errors = 0;
28211738cd3eSNetanel Belgazal stats->tx_errors = 0;
28221738cd3eSNetanel Belgazal }
28231738cd3eSNetanel Belgazal
28241738cd3eSNetanel Belgazal static const struct net_device_ops ena_netdev_ops = {
28251738cd3eSNetanel Belgazal .ndo_open = ena_open,
28261738cd3eSNetanel Belgazal .ndo_stop = ena_close,
28271738cd3eSNetanel Belgazal .ndo_start_xmit = ena_start_xmit,
28281738cd3eSNetanel Belgazal .ndo_get_stats64 = ena_get_stats64,
28291738cd3eSNetanel Belgazal .ndo_tx_timeout = ena_tx_timeout,
28301738cd3eSNetanel Belgazal .ndo_change_mtu = ena_change_mtu,
28311738cd3eSNetanel Belgazal .ndo_set_mac_address = NULL,
28321738cd3eSNetanel Belgazal .ndo_validate_addr = eth_validate_addr,
2833838c93dcSSameeh Jubran .ndo_bpf = ena_xdp,
2834f1a25589SShay Agroskin .ndo_xdp_xmit = ena_xdp_xmit,
28351738cd3eSNetanel Belgazal };
28361738cd3eSNetanel Belgazal
ena_calc_io_queue_size(struct ena_adapter * adapter,struct ena_com_dev_get_features_ctx * get_feat_ctx)28373a091084SShay Agroskin static void ena_calc_io_queue_size(struct ena_adapter *adapter,
28383a091084SShay Agroskin struct ena_com_dev_get_features_ctx *get_feat_ctx)
28393a091084SShay Agroskin {
28403a091084SShay Agroskin struct ena_admin_feature_llq_desc *llq = &get_feat_ctx->llq;
28413a091084SShay Agroskin struct ena_com_dev *ena_dev = adapter->ena_dev;
28423a091084SShay Agroskin u32 tx_queue_size = ENA_DEFAULT_RING_SIZE;
28433a091084SShay Agroskin u32 rx_queue_size = ENA_DEFAULT_RING_SIZE;
28443a091084SShay Agroskin u32 max_tx_queue_size;
28453a091084SShay Agroskin u32 max_rx_queue_size;
28463a091084SShay Agroskin
28471e366688SDavid Arinzon /* If this function is called after driver load, the ring sizes have already
28481e366688SDavid Arinzon * been configured. Take it into account when recalculating ring size.
28491e366688SDavid Arinzon */
28501e366688SDavid Arinzon if (adapter->tx_ring->ring_size)
28511e366688SDavid Arinzon tx_queue_size = adapter->tx_ring->ring_size;
28521e366688SDavid Arinzon
28531e366688SDavid Arinzon if (adapter->rx_ring->ring_size)
28541e366688SDavid Arinzon rx_queue_size = adapter->rx_ring->ring_size;
28551e366688SDavid Arinzon
28563a091084SShay Agroskin if (ena_dev->supported_features & BIT(ENA_ADMIN_MAX_QUEUES_EXT)) {
28573a091084SShay Agroskin struct ena_admin_queue_ext_feature_fields *max_queue_ext =
28583a091084SShay Agroskin &get_feat_ctx->max_queue_ext.max_queue_ext;
28593a091084SShay Agroskin max_rx_queue_size = min_t(u32, max_queue_ext->max_rx_cq_depth,
28603a091084SShay Agroskin max_queue_ext->max_rx_sq_depth);
28613a091084SShay Agroskin max_tx_queue_size = max_queue_ext->max_tx_cq_depth;
28623a091084SShay Agroskin
28633a091084SShay Agroskin if (ena_dev->tx_mem_queue_type == ENA_ADMIN_PLACEMENT_POLICY_DEV)
28643a091084SShay Agroskin max_tx_queue_size = min_t(u32, max_tx_queue_size,
28653a091084SShay Agroskin llq->max_llq_depth);
28663a091084SShay Agroskin else
28673a091084SShay Agroskin max_tx_queue_size = min_t(u32, max_tx_queue_size,
28683a091084SShay Agroskin max_queue_ext->max_tx_sq_depth);
28693a091084SShay Agroskin
28703a091084SShay Agroskin adapter->max_tx_sgl_size = min_t(u16, ENA_PKT_MAX_BUFS,
28713a091084SShay Agroskin max_queue_ext->max_per_packet_tx_descs);
28723a091084SShay Agroskin adapter->max_rx_sgl_size = min_t(u16, ENA_PKT_MAX_BUFS,
28733a091084SShay Agroskin max_queue_ext->max_per_packet_rx_descs);
28743a091084SShay Agroskin } else {
28753a091084SShay Agroskin struct ena_admin_queue_feature_desc *max_queues =
28763a091084SShay Agroskin &get_feat_ctx->max_queues;
28773a091084SShay Agroskin max_rx_queue_size = min_t(u32, max_queues->max_cq_depth,
28783a091084SShay Agroskin max_queues->max_sq_depth);
28793a091084SShay Agroskin max_tx_queue_size = max_queues->max_cq_depth;
28803a091084SShay Agroskin
28813a091084SShay Agroskin if (ena_dev->tx_mem_queue_type == ENA_ADMIN_PLACEMENT_POLICY_DEV)
28823a091084SShay Agroskin max_tx_queue_size = min_t(u32, max_tx_queue_size,
28833a091084SShay Agroskin llq->max_llq_depth);
28843a091084SShay Agroskin else
28853a091084SShay Agroskin max_tx_queue_size = min_t(u32, max_tx_queue_size,
28863a091084SShay Agroskin max_queues->max_sq_depth);
28873a091084SShay Agroskin
28883a091084SShay Agroskin adapter->max_tx_sgl_size = min_t(u16, ENA_PKT_MAX_BUFS,
28893a091084SShay Agroskin max_queues->max_packet_tx_descs);
28903a091084SShay Agroskin adapter->max_rx_sgl_size = min_t(u16, ENA_PKT_MAX_BUFS,
28913a091084SShay Agroskin max_queues->max_packet_rx_descs);
28923a091084SShay Agroskin }
28933a091084SShay Agroskin
28943a091084SShay Agroskin max_tx_queue_size = rounddown_pow_of_two(max_tx_queue_size);
28953a091084SShay Agroskin max_rx_queue_size = rounddown_pow_of_two(max_rx_queue_size);
28963a091084SShay Agroskin
28971e366688SDavid Arinzon /* When forcing large headers, we multiply the entry size by 2, and therefore divide
28981e366688SDavid Arinzon * the queue size by 2, leaving the amount of memory used by the queues unchanged.
28991e366688SDavid Arinzon */
29001e366688SDavid Arinzon if (adapter->large_llq_header_enabled) {
29011e366688SDavid Arinzon if ((llq->entry_size_ctrl_supported & ENA_ADMIN_LIST_ENTRY_SIZE_256B) &&
29021e366688SDavid Arinzon ena_dev->tx_mem_queue_type == ENA_ADMIN_PLACEMENT_POLICY_DEV) {
29031e366688SDavid Arinzon max_tx_queue_size /= 2;
29041e366688SDavid Arinzon dev_info(&adapter->pdev->dev,
29051e366688SDavid Arinzon "Forcing large headers and decreasing maximum TX queue size to %d\n",
29061e366688SDavid Arinzon max_tx_queue_size);
29071e366688SDavid Arinzon } else {
29081e366688SDavid Arinzon dev_err(&adapter->pdev->dev,
29091e366688SDavid Arinzon "Forcing large headers failed: LLQ is disabled or device does not support large headers\n");
29101e366688SDavid Arinzon
29111e366688SDavid Arinzon adapter->large_llq_header_enabled = false;
29121e366688SDavid Arinzon }
29131e366688SDavid Arinzon }
29141e366688SDavid Arinzon
29153a091084SShay Agroskin tx_queue_size = clamp_val(tx_queue_size, ENA_MIN_RING_SIZE,
29163a091084SShay Agroskin max_tx_queue_size);
29173a091084SShay Agroskin rx_queue_size = clamp_val(rx_queue_size, ENA_MIN_RING_SIZE,
29183a091084SShay Agroskin max_rx_queue_size);
29193a091084SShay Agroskin
29203a091084SShay Agroskin tx_queue_size = rounddown_pow_of_two(tx_queue_size);
29213a091084SShay Agroskin rx_queue_size = rounddown_pow_of_two(rx_queue_size);
29223a091084SShay Agroskin
29233a091084SShay Agroskin adapter->max_tx_ring_size = max_tx_queue_size;
29243a091084SShay Agroskin adapter->max_rx_ring_size = max_rx_queue_size;
29253a091084SShay Agroskin adapter->requested_tx_ring_size = tx_queue_size;
29263a091084SShay Agroskin adapter->requested_rx_ring_size = rx_queue_size;
29273a091084SShay Agroskin }
29283a091084SShay Agroskin
ena_device_validate_params(struct ena_adapter * adapter,struct ena_com_dev_get_features_ctx * get_feat_ctx)29291738cd3eSNetanel Belgazal static int ena_device_validate_params(struct ena_adapter *adapter,
29301738cd3eSNetanel Belgazal struct ena_com_dev_get_features_ctx *get_feat_ctx)
29311738cd3eSNetanel Belgazal {
29321738cd3eSNetanel Belgazal struct net_device *netdev = adapter->netdev;
29331738cd3eSNetanel Belgazal int rc;
29341738cd3eSNetanel Belgazal
29351738cd3eSNetanel Belgazal rc = ether_addr_equal(get_feat_ctx->dev_attr.mac_addr,
29361738cd3eSNetanel Belgazal adapter->mac_addr);
29371738cd3eSNetanel Belgazal if (!rc) {
29381738cd3eSNetanel Belgazal netif_err(adapter, drv, netdev,
29391738cd3eSNetanel Belgazal "Error, mac address are different\n");
29401738cd3eSNetanel Belgazal return -EINVAL;
29411738cd3eSNetanel Belgazal }
29421738cd3eSNetanel Belgazal
29431738cd3eSNetanel Belgazal if (get_feat_ctx->dev_attr.max_mtu < netdev->mtu) {
29441738cd3eSNetanel Belgazal netif_err(adapter, drv, netdev,
29451738cd3eSNetanel Belgazal "Error, device max mtu is smaller than netdev MTU\n");
29461738cd3eSNetanel Belgazal return -EINVAL;
29471738cd3eSNetanel Belgazal }
29481738cd3eSNetanel Belgazal
29491738cd3eSNetanel Belgazal return 0;
29501738cd3eSNetanel Belgazal }
29511738cd3eSNetanel Belgazal
set_default_llq_configurations(struct ena_adapter * adapter,struct ena_llq_configurations * llq_config,struct ena_admin_feature_llq_desc * llq)29521e366688SDavid Arinzon static void set_default_llq_configurations(struct ena_adapter *adapter,
29531e366688SDavid Arinzon struct ena_llq_configurations *llq_config,
29541e366688SDavid Arinzon struct ena_admin_feature_llq_desc *llq)
2955c29efeaeSArthur Kiyanovski {
29561e366688SDavid Arinzon struct ena_com_dev *ena_dev = adapter->ena_dev;
29571e366688SDavid Arinzon
2958c29efeaeSArthur Kiyanovski llq_config->llq_header_location = ENA_ADMIN_INLINE_HEADER;
2959c29efeaeSArthur Kiyanovski llq_config->llq_stride_ctrl = ENA_ADMIN_MULTIPLE_DESCS_PER_ENTRY;
2960c29efeaeSArthur Kiyanovski llq_config->llq_num_decs_before_header = ENA_ADMIN_LLQ_NUM_DESCS_BEFORE_HEADER_2;
29611e366688SDavid Arinzon
29621e366688SDavid Arinzon adapter->large_llq_header_supported =
29631e366688SDavid Arinzon !!(ena_dev->supported_features & BIT(ENA_ADMIN_LLQ));
29641e366688SDavid Arinzon adapter->large_llq_header_supported &=
29651e366688SDavid Arinzon !!(llq->entry_size_ctrl_supported &
29661e366688SDavid Arinzon ENA_ADMIN_LIST_ENTRY_SIZE_256B);
29671e366688SDavid Arinzon
29681e366688SDavid Arinzon if ((llq->entry_size_ctrl_supported & ENA_ADMIN_LIST_ENTRY_SIZE_256B) &&
29691e366688SDavid Arinzon adapter->large_llq_header_enabled) {
29701e366688SDavid Arinzon llq_config->llq_ring_entry_size = ENA_ADMIN_LIST_ENTRY_SIZE_256B;
29711e366688SDavid Arinzon llq_config->llq_ring_entry_size_value = 256;
29721e366688SDavid Arinzon } else {
2973c29efeaeSArthur Kiyanovski llq_config->llq_ring_entry_size = ENA_ADMIN_LIST_ENTRY_SIZE_128B;
2974c29efeaeSArthur Kiyanovski llq_config->llq_ring_entry_size_value = 128;
2975c29efeaeSArthur Kiyanovski }
29761e366688SDavid Arinzon }
2977c29efeaeSArthur Kiyanovski
ena_set_queues_placement_policy(struct pci_dev * pdev,struct ena_com_dev * ena_dev,struct ena_admin_feature_llq_desc * llq,struct ena_llq_configurations * llq_default_configurations)2978c29efeaeSArthur Kiyanovski static int ena_set_queues_placement_policy(struct pci_dev *pdev,
2979c29efeaeSArthur Kiyanovski struct ena_com_dev *ena_dev,
2980c29efeaeSArthur Kiyanovski struct ena_admin_feature_llq_desc *llq,
2981c29efeaeSArthur Kiyanovski struct ena_llq_configurations *llq_default_configurations)
2982c29efeaeSArthur Kiyanovski {
2983c29efeaeSArthur Kiyanovski int rc;
2984c29efeaeSArthur Kiyanovski u32 llq_feature_mask;
2985c29efeaeSArthur Kiyanovski
2986c29efeaeSArthur Kiyanovski llq_feature_mask = 1 << ENA_ADMIN_LLQ;
2987c29efeaeSArthur Kiyanovski if (!(ena_dev->supported_features & llq_feature_mask)) {
298815efff76SShay Agroskin dev_warn(&pdev->dev,
2989c29efeaeSArthur Kiyanovski "LLQ is not supported Fallback to host mode policy.\n");
2990c29efeaeSArthur Kiyanovski ena_dev->tx_mem_queue_type = ENA_ADMIN_PLACEMENT_POLICY_HOST;
2991c29efeaeSArthur Kiyanovski return 0;
2992c29efeaeSArthur Kiyanovski }
2993c29efeaeSArthur Kiyanovski
29941e366688SDavid Arinzon if (!ena_dev->mem_bar) {
29951e366688SDavid Arinzon netdev_err(ena_dev->net_device,
29961e366688SDavid Arinzon "LLQ is advertised as supported but device doesn't expose mem bar\n");
29971e366688SDavid Arinzon ena_dev->tx_mem_queue_type = ENA_ADMIN_PLACEMENT_POLICY_HOST;
29981e366688SDavid Arinzon return 0;
29991e366688SDavid Arinzon }
30001e366688SDavid Arinzon
3001c29efeaeSArthur Kiyanovski rc = ena_com_config_dev_mode(ena_dev, llq, llq_default_configurations);
3002c29efeaeSArthur Kiyanovski if (unlikely(rc)) {
3003c29efeaeSArthur Kiyanovski dev_err(&pdev->dev,
3004c29efeaeSArthur Kiyanovski "Failed to configure the device mode. Fallback to host mode policy.\n");
3005c29efeaeSArthur Kiyanovski ena_dev->tx_mem_queue_type = ENA_ADMIN_PLACEMENT_POLICY_HOST;
3006c29efeaeSArthur Kiyanovski }
3007c29efeaeSArthur Kiyanovski
3008c29efeaeSArthur Kiyanovski return 0;
3009c29efeaeSArthur Kiyanovski }
3010c29efeaeSArthur Kiyanovski
ena_map_llq_mem_bar(struct pci_dev * pdev,struct ena_com_dev * ena_dev,int bars)3011c29efeaeSArthur Kiyanovski static int ena_map_llq_mem_bar(struct pci_dev *pdev, struct ena_com_dev *ena_dev,
3012c29efeaeSArthur Kiyanovski int bars)
3013c29efeaeSArthur Kiyanovski {
3014c29efeaeSArthur Kiyanovski bool has_mem_bar = !!(bars & BIT(ENA_MEM_BAR));
3015c29efeaeSArthur Kiyanovski
30161e366688SDavid Arinzon if (!has_mem_bar)
3017c29efeaeSArthur Kiyanovski return 0;
3018c29efeaeSArthur Kiyanovski
3019c29efeaeSArthur Kiyanovski ena_dev->mem_bar = devm_ioremap_wc(&pdev->dev,
3020c29efeaeSArthur Kiyanovski pci_resource_start(pdev, ENA_MEM_BAR),
3021c29efeaeSArthur Kiyanovski pci_resource_len(pdev, ENA_MEM_BAR));
3022c29efeaeSArthur Kiyanovski
3023c29efeaeSArthur Kiyanovski if (!ena_dev->mem_bar)
3024c29efeaeSArthur Kiyanovski return -EFAULT;
3025c29efeaeSArthur Kiyanovski
3026c29efeaeSArthur Kiyanovski return 0;
3027c29efeaeSArthur Kiyanovski }
3028c29efeaeSArthur Kiyanovski
ena_device_init(struct ena_adapter * adapter,struct pci_dev * pdev,struct ena_com_dev_get_features_ctx * get_feat_ctx,bool * wd_state)30291e366688SDavid Arinzon static int ena_device_init(struct ena_adapter *adapter, struct pci_dev *pdev,
30301738cd3eSNetanel Belgazal struct ena_com_dev_get_features_ctx *get_feat_ctx,
30311738cd3eSNetanel Belgazal bool *wd_state)
30321738cd3eSNetanel Belgazal {
30331e366688SDavid Arinzon struct ena_com_dev *ena_dev = adapter->ena_dev;
3034c29efeaeSArthur Kiyanovski struct ena_llq_configurations llq_config;
30351738cd3eSNetanel Belgazal struct device *dev = &pdev->dev;
30361738cd3eSNetanel Belgazal bool readless_supported;
30371738cd3eSNetanel Belgazal u32 aenq_groups;
30381738cd3eSNetanel Belgazal int dma_width;
30391738cd3eSNetanel Belgazal int rc;
30401738cd3eSNetanel Belgazal
30411738cd3eSNetanel Belgazal rc = ena_com_mmio_reg_read_request_init(ena_dev);
30421738cd3eSNetanel Belgazal if (rc) {
3043bf2746e8SShay Agroskin dev_err(dev, "Failed to init mmio read less\n");
30441738cd3eSNetanel Belgazal return rc;
30451738cd3eSNetanel Belgazal }
30461738cd3eSNetanel Belgazal
30471738cd3eSNetanel Belgazal /* The PCIe configuration space revision id indicate if mmio reg
30481738cd3eSNetanel Belgazal * read is disabled
30491738cd3eSNetanel Belgazal */
30501738cd3eSNetanel Belgazal readless_supported = !(pdev->revision & ENA_MMIO_DISABLE_REG_READ);
30511738cd3eSNetanel Belgazal ena_com_set_mmio_read_mode(ena_dev, readless_supported);
30521738cd3eSNetanel Belgazal
3053e2eed0e3SNetanel Belgazal rc = ena_com_dev_reset(ena_dev, ENA_REGS_RESET_NORMAL);
30541738cd3eSNetanel Belgazal if (rc) {
30551738cd3eSNetanel Belgazal dev_err(dev, "Can not reset device\n");
30561738cd3eSNetanel Belgazal goto err_mmio_read_less;
30571738cd3eSNetanel Belgazal }
30581738cd3eSNetanel Belgazal
30591738cd3eSNetanel Belgazal rc = ena_com_validate_version(ena_dev);
30601738cd3eSNetanel Belgazal if (rc) {
3061bf2746e8SShay Agroskin dev_err(dev, "Device version is too low\n");
30621738cd3eSNetanel Belgazal goto err_mmio_read_less;
30631738cd3eSNetanel Belgazal }
30641738cd3eSNetanel Belgazal
30651738cd3eSNetanel Belgazal dma_width = ena_com_get_dma_width(ena_dev);
30661738cd3eSNetanel Belgazal if (dma_width < 0) {
30671738cd3eSNetanel Belgazal dev_err(dev, "Invalid dma width value %d", dma_width);
30686e22066fSWei Yongjun rc = dma_width;
30691738cd3eSNetanel Belgazal goto err_mmio_read_less;
30701738cd3eSNetanel Belgazal }
30711738cd3eSNetanel Belgazal
307209323b3bSShay Agroskin rc = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(dma_width));
30731738cd3eSNetanel Belgazal if (rc) {
307409323b3bSShay Agroskin dev_err(dev, "dma_set_mask_and_coherent failed %d\n", rc);
30751738cd3eSNetanel Belgazal goto err_mmio_read_less;
30761738cd3eSNetanel Belgazal }
30771738cd3eSNetanel Belgazal
30781738cd3eSNetanel Belgazal /* ENA admin level init */
3079f1e90f6eSArthur Kiyanovski rc = ena_com_admin_init(ena_dev, &aenq_handlers);
30801738cd3eSNetanel Belgazal if (rc) {
30811738cd3eSNetanel Belgazal dev_err(dev,
30821738cd3eSNetanel Belgazal "Can not initialize ena admin queue with device\n");
30831738cd3eSNetanel Belgazal goto err_mmio_read_less;
30841738cd3eSNetanel Belgazal }
30851738cd3eSNetanel Belgazal
30861738cd3eSNetanel Belgazal /* To enable the msix interrupts the driver needs to know the number
30871738cd3eSNetanel Belgazal * of queues. So the driver uses polling mode to retrieve this
30881738cd3eSNetanel Belgazal * information
30891738cd3eSNetanel Belgazal */
30901738cd3eSNetanel Belgazal ena_com_set_admin_polling_mode(ena_dev, true);
30911738cd3eSNetanel Belgazal
3092095f2f1fSArthur Kiyanovski ena_config_host_info(ena_dev, pdev);
3093dd8427a7SNetanel Belgazal
30941738cd3eSNetanel Belgazal /* Get Device Attributes*/
30951738cd3eSNetanel Belgazal rc = ena_com_get_dev_attr_feat(ena_dev, get_feat_ctx);
30961738cd3eSNetanel Belgazal if (rc) {
30971738cd3eSNetanel Belgazal dev_err(dev, "Cannot get attribute for ena device rc=%d\n", rc);
30981738cd3eSNetanel Belgazal goto err_admin_init;
30991738cd3eSNetanel Belgazal }
31001738cd3eSNetanel Belgazal
31011738cd3eSNetanel Belgazal /* Try to turn all the available aenq groups */
31021738cd3eSNetanel Belgazal aenq_groups = BIT(ENA_ADMIN_LINK_CHANGE) |
31031738cd3eSNetanel Belgazal BIT(ENA_ADMIN_FATAL_ERROR) |
31041738cd3eSNetanel Belgazal BIT(ENA_ADMIN_WARNING) |
31051738cd3eSNetanel Belgazal BIT(ENA_ADMIN_NOTIFICATION) |
31061738cd3eSNetanel Belgazal BIT(ENA_ADMIN_KEEP_ALIVE);
31071738cd3eSNetanel Belgazal
31081738cd3eSNetanel Belgazal aenq_groups &= get_feat_ctx->aenq.supported_groups;
31091738cd3eSNetanel Belgazal
31101738cd3eSNetanel Belgazal rc = ena_com_set_aenq_config(ena_dev, aenq_groups);
31111738cd3eSNetanel Belgazal if (rc) {
31121738cd3eSNetanel Belgazal dev_err(dev, "Cannot configure aenq groups rc= %d\n", rc);
31131738cd3eSNetanel Belgazal goto err_admin_init;
31141738cd3eSNetanel Belgazal }
31151738cd3eSNetanel Belgazal
31161738cd3eSNetanel Belgazal *wd_state = !!(aenq_groups & BIT(ENA_ADMIN_KEEP_ALIVE));
31171738cd3eSNetanel Belgazal
31181e366688SDavid Arinzon set_default_llq_configurations(adapter, &llq_config, &get_feat_ctx->llq);
3119c29efeaeSArthur Kiyanovski
3120c29efeaeSArthur Kiyanovski rc = ena_set_queues_placement_policy(pdev, ena_dev, &get_feat_ctx->llq,
3121c29efeaeSArthur Kiyanovski &llq_config);
3122c29efeaeSArthur Kiyanovski if (rc) {
3123bf2746e8SShay Agroskin dev_err(dev, "ENA device init failed\n");
3124c29efeaeSArthur Kiyanovski goto err_admin_init;
3125c29efeaeSArthur Kiyanovski }
3126c29efeaeSArthur Kiyanovski
31271e366688SDavid Arinzon ena_calc_io_queue_size(adapter, get_feat_ctx);
31281e366688SDavid Arinzon
31291738cd3eSNetanel Belgazal return 0;
31301738cd3eSNetanel Belgazal
31311738cd3eSNetanel Belgazal err_admin_init:
3132dd8427a7SNetanel Belgazal ena_com_delete_host_info(ena_dev);
31331738cd3eSNetanel Belgazal ena_com_admin_destroy(ena_dev);
31341738cd3eSNetanel Belgazal err_mmio_read_less:
31351738cd3eSNetanel Belgazal ena_com_mmio_reg_read_request_destroy(ena_dev);
31361738cd3eSNetanel Belgazal
31371738cd3eSNetanel Belgazal return rc;
31381738cd3eSNetanel Belgazal }
31391738cd3eSNetanel Belgazal
ena_enable_msix_and_set_admin_interrupts(struct ena_adapter * adapter)31404d192660SSameeh Jubran static int ena_enable_msix_and_set_admin_interrupts(struct ena_adapter *adapter)
31411738cd3eSNetanel Belgazal {
31421738cd3eSNetanel Belgazal struct ena_com_dev *ena_dev = adapter->ena_dev;
31431738cd3eSNetanel Belgazal struct device *dev = &adapter->pdev->dev;
31441738cd3eSNetanel Belgazal int rc;
31451738cd3eSNetanel Belgazal
31464d192660SSameeh Jubran rc = ena_enable_msix(adapter);
31471738cd3eSNetanel Belgazal if (rc) {
31481738cd3eSNetanel Belgazal dev_err(dev, "Can not reserve msix vectors\n");
31491738cd3eSNetanel Belgazal return rc;
31501738cd3eSNetanel Belgazal }
31511738cd3eSNetanel Belgazal
31521738cd3eSNetanel Belgazal ena_setup_mgmnt_intr(adapter);
31531738cd3eSNetanel Belgazal
31541738cd3eSNetanel Belgazal rc = ena_request_mgmnt_irq(adapter);
31551738cd3eSNetanel Belgazal if (rc) {
31561738cd3eSNetanel Belgazal dev_err(dev, "Can not setup management interrupts\n");
31571738cd3eSNetanel Belgazal goto err_disable_msix;
31581738cd3eSNetanel Belgazal }
31591738cd3eSNetanel Belgazal
31601738cd3eSNetanel Belgazal ena_com_set_admin_polling_mode(ena_dev, false);
31611738cd3eSNetanel Belgazal
31621738cd3eSNetanel Belgazal ena_com_admin_aenq_enable(ena_dev);
31631738cd3eSNetanel Belgazal
31641738cd3eSNetanel Belgazal return 0;
31651738cd3eSNetanel Belgazal
31661738cd3eSNetanel Belgazal err_disable_msix:
316706443684SNetanel Belgazal ena_disable_msix(adapter);
316806443684SNetanel Belgazal
31691738cd3eSNetanel Belgazal return rc;
31701738cd3eSNetanel Belgazal }
31711738cd3eSNetanel Belgazal
ena_destroy_device(struct ena_adapter * adapter,bool graceful)3172cfa324a5SNetanel Belgazal static void ena_destroy_device(struct ena_adapter *adapter, bool graceful)
31731738cd3eSNetanel Belgazal {
31741738cd3eSNetanel Belgazal struct net_device *netdev = adapter->netdev;
31751738cd3eSNetanel Belgazal struct ena_com_dev *ena_dev = adapter->ena_dev;
31768c5c7abdSNetanel Belgazal bool dev_up;
31773f6159dbSNetanel Belgazal
3178fe870c77SNetanel Belgazal if (!test_bit(ENA_FLAG_DEVICE_RUNNING, &adapter->flags))
3179fe870c77SNetanel Belgazal return;
3180fe870c77SNetanel Belgazal
31813f6159dbSNetanel Belgazal netif_carrier_off(netdev);
31823f6159dbSNetanel Belgazal
31831738cd3eSNetanel Belgazal del_timer_sync(&adapter->timer_service);
31841738cd3eSNetanel Belgazal
31851738cd3eSNetanel Belgazal dev_up = test_bit(ENA_FLAG_DEV_UP, &adapter->flags);
31868c5c7abdSNetanel Belgazal adapter->dev_up_before_reset = dev_up;
3187cfa324a5SNetanel Belgazal if (!graceful)
31881738cd3eSNetanel Belgazal ena_com_set_admin_running_state(ena_dev, false);
31891738cd3eSNetanel Belgazal
3190ee4552aaSNetanel Belgazal if (test_bit(ENA_FLAG_DEV_UP, &adapter->flags))
3191ee4552aaSNetanel Belgazal ena_down(adapter);
31921738cd3eSNetanel Belgazal
3193bd791175SArthur Kiyanovski /* Stop the device from sending AENQ events (in case reset flag is set
319458a54b9cSArthur Kiyanovski * and device is up, ena_down() already reset the device.
31958c5c7abdSNetanel Belgazal */
31968c5c7abdSNetanel Belgazal if (!(test_bit(ENA_FLAG_TRIGGER_RESET, &adapter->flags) && dev_up))
31978c5c7abdSNetanel Belgazal ena_com_dev_reset(adapter->ena_dev, adapter->reset_reason);
31988c5c7abdSNetanel Belgazal
31991738cd3eSNetanel Belgazal ena_free_mgmnt_irq(adapter);
32001738cd3eSNetanel Belgazal
320106443684SNetanel Belgazal ena_disable_msix(adapter);
32021738cd3eSNetanel Belgazal
32031738cd3eSNetanel Belgazal ena_com_abort_admin_commands(ena_dev);
32041738cd3eSNetanel Belgazal
32051738cd3eSNetanel Belgazal ena_com_wait_for_abort_completion(ena_dev);
32061738cd3eSNetanel Belgazal
32071738cd3eSNetanel Belgazal ena_com_admin_destroy(ena_dev);
32081738cd3eSNetanel Belgazal
32091738cd3eSNetanel Belgazal ena_com_mmio_reg_read_request_destroy(ena_dev);
32101738cd3eSNetanel Belgazal
3211c1c0e40bSSameeh Jubran /* return reset reason to default value */
3212e2eed0e3SNetanel Belgazal adapter->reset_reason = ENA_REGS_RESET_NORMAL;
32133f6159dbSNetanel Belgazal
32148c5c7abdSNetanel Belgazal clear_bit(ENA_FLAG_TRIGGER_RESET, &adapter->flags);
3215fe870c77SNetanel Belgazal clear_bit(ENA_FLAG_DEVICE_RUNNING, &adapter->flags);
32168c5c7abdSNetanel Belgazal }
32178c5c7abdSNetanel Belgazal
ena_restore_device(struct ena_adapter * adapter)32188c5c7abdSNetanel Belgazal static int ena_restore_device(struct ena_adapter *adapter)
32198c5c7abdSNetanel Belgazal {
32208c5c7abdSNetanel Belgazal struct ena_com_dev_get_features_ctx get_feat_ctx;
32218c5c7abdSNetanel Belgazal struct ena_com_dev *ena_dev = adapter->ena_dev;
32228c5c7abdSNetanel Belgazal struct pci_dev *pdev = adapter->pdev;
3223a416cb25SShay Agroskin struct ena_ring *txr;
3224a416cb25SShay Agroskin int rc, count, i;
32258c5c7abdSNetanel Belgazal bool wd_state;
32261738cd3eSNetanel Belgazal
3227d18e4f68SNetanel Belgazal set_bit(ENA_FLAG_ONGOING_RESET, &adapter->flags);
32281e366688SDavid Arinzon rc = ena_device_init(adapter, adapter->pdev, &get_feat_ctx, &wd_state);
32291738cd3eSNetanel Belgazal if (rc) {
32301738cd3eSNetanel Belgazal dev_err(&pdev->dev, "Can not initialize device\n");
32311738cd3eSNetanel Belgazal goto err;
32321738cd3eSNetanel Belgazal }
32331738cd3eSNetanel Belgazal adapter->wd_state = wd_state;
32341738cd3eSNetanel Belgazal
3235a416cb25SShay Agroskin count = adapter->xdp_num_queues + adapter->num_io_queues;
3236a416cb25SShay Agroskin for (i = 0 ; i < count; i++) {
3237a416cb25SShay Agroskin txr = &adapter->tx_ring[i];
3238a416cb25SShay Agroskin txr->tx_mem_queue_type = ena_dev->tx_mem_queue_type;
3239a416cb25SShay Agroskin txr->tx_max_header_size = ena_dev->tx_max_header_size;
3240a416cb25SShay Agroskin }
3241a416cb25SShay Agroskin
32421738cd3eSNetanel Belgazal rc = ena_device_validate_params(adapter, &get_feat_ctx);
32431738cd3eSNetanel Belgazal if (rc) {
32441738cd3eSNetanel Belgazal dev_err(&pdev->dev, "Validation of device parameters failed\n");
32451738cd3eSNetanel Belgazal goto err_device_destroy;
32461738cd3eSNetanel Belgazal }
32471738cd3eSNetanel Belgazal
32484d192660SSameeh Jubran rc = ena_enable_msix_and_set_admin_interrupts(adapter);
32491738cd3eSNetanel Belgazal if (rc) {
32501738cd3eSNetanel Belgazal dev_err(&pdev->dev, "Enable MSI-X failed\n");
32511738cd3eSNetanel Belgazal goto err_device_destroy;
32521738cd3eSNetanel Belgazal }
32531738cd3eSNetanel Belgazal /* If the interface was up before the reset bring it up */
32548c5c7abdSNetanel Belgazal if (adapter->dev_up_before_reset) {
32551738cd3eSNetanel Belgazal rc = ena_up(adapter);
32561738cd3eSNetanel Belgazal if (rc) {
32571738cd3eSNetanel Belgazal dev_err(&pdev->dev, "Failed to create I/O queues\n");
32581738cd3eSNetanel Belgazal goto err_disable_msix;
32591738cd3eSNetanel Belgazal }
32601738cd3eSNetanel Belgazal }
32611738cd3eSNetanel Belgazal
3262fe870c77SNetanel Belgazal set_bit(ENA_FLAG_DEVICE_RUNNING, &adapter->flags);
3263e1f1bd9bSArthur Kiyanovski
3264e1f1bd9bSArthur Kiyanovski clear_bit(ENA_FLAG_ONGOING_RESET, &adapter->flags);
3265e1f1bd9bSArthur Kiyanovski if (test_bit(ENA_FLAG_LINK_UP, &adapter->flags))
3266e1f1bd9bSArthur Kiyanovski netif_carrier_on(adapter->netdev);
3267e1f1bd9bSArthur Kiyanovski
32681738cd3eSNetanel Belgazal mod_timer(&adapter->timer_service, round_jiffies(jiffies + HZ));
3269dfdde134SArthur Kiyanovski adapter->last_keep_alive_jiffies = jiffies;
32701738cd3eSNetanel Belgazal
32718c5c7abdSNetanel Belgazal return rc;
32721738cd3eSNetanel Belgazal err_disable_msix:
32731738cd3eSNetanel Belgazal ena_free_mgmnt_irq(adapter);
327406443684SNetanel Belgazal ena_disable_msix(adapter);
32751738cd3eSNetanel Belgazal err_device_destroy:
3276d7703ddbSArthur Kiyanovski ena_com_abort_admin_commands(ena_dev);
3277d7703ddbSArthur Kiyanovski ena_com_wait_for_abort_completion(ena_dev);
32781738cd3eSNetanel Belgazal ena_com_admin_destroy(ena_dev);
3279d7703ddbSArthur Kiyanovski ena_com_dev_reset(ena_dev, ENA_REGS_RESET_DRIVER_INVALID_STATE);
3280e76ad21dSArthur Kiyanovski ena_com_mmio_reg_read_request_destroy(ena_dev);
32811738cd3eSNetanel Belgazal err:
328222b331c9SNetanel Belgazal clear_bit(ENA_FLAG_DEVICE_RUNNING, &adapter->flags);
3283d18e4f68SNetanel Belgazal clear_bit(ENA_FLAG_ONGOING_RESET, &adapter->flags);
32841738cd3eSNetanel Belgazal dev_err(&pdev->dev,
32851738cd3eSNetanel Belgazal "Reset attempt failed. Can not reset the device\n");
32868c5c7abdSNetanel Belgazal
32878c5c7abdSNetanel Belgazal return rc;
32888c5c7abdSNetanel Belgazal }
32898c5c7abdSNetanel Belgazal
ena_fw_reset_device(struct work_struct * work)32908c5c7abdSNetanel Belgazal static void ena_fw_reset_device(struct work_struct *work)
32918c5c7abdSNetanel Belgazal {
32928c5c7abdSNetanel Belgazal struct ena_adapter *adapter =
32938c5c7abdSNetanel Belgazal container_of(work, struct ena_adapter, reset_task);
32948c5c7abdSNetanel Belgazal
32958c5c7abdSNetanel Belgazal rtnl_lock();
329663d4a4c1SShay Agroskin
329763d4a4c1SShay Agroskin if (likely(test_bit(ENA_FLAG_TRIGGER_RESET, &adapter->flags))) {
3298cfa324a5SNetanel Belgazal ena_destroy_device(adapter, false);
32998c5c7abdSNetanel Belgazal ena_restore_device(adapter);
3300e3445469SArthur Kiyanovski
3301e3445469SArthur Kiyanovski dev_err(&adapter->pdev->dev, "Device reset completed successfully\n");
330263d4a4c1SShay Agroskin }
330363d4a4c1SShay Agroskin
33048c5c7abdSNetanel Belgazal rtnl_unlock();
33051738cd3eSNetanel Belgazal }
33061738cd3eSNetanel Belgazal
check_for_rx_interrupt_queue(struct ena_adapter * adapter,struct ena_ring * rx_ring)33078510e1a3SNetanel Belgazal static int check_for_rx_interrupt_queue(struct ena_adapter *adapter,
33088510e1a3SNetanel Belgazal struct ena_ring *rx_ring)
33098510e1a3SNetanel Belgazal {
3310e4ac382eSShay Agroskin struct ena_napi *ena_napi = container_of(rx_ring->napi, struct ena_napi, napi);
3311e4ac382eSShay Agroskin
3312e4ac382eSShay Agroskin if (likely(READ_ONCE(ena_napi->first_interrupt)))
33138510e1a3SNetanel Belgazal return 0;
33148510e1a3SNetanel Belgazal
33158510e1a3SNetanel Belgazal if (ena_com_cq_empty(rx_ring->ena_com_io_cq))
33168510e1a3SNetanel Belgazal return 0;
33178510e1a3SNetanel Belgazal
33188510e1a3SNetanel Belgazal rx_ring->no_interrupt_event_cnt++;
33198510e1a3SNetanel Belgazal
33208510e1a3SNetanel Belgazal if (rx_ring->no_interrupt_event_cnt == ENA_MAX_NO_INTERRUPT_ITERATIONS) {
33218510e1a3SNetanel Belgazal netif_err(adapter, rx_err, adapter->netdev,
33228510e1a3SNetanel Belgazal "Potential MSIX issue on Rx side Queue = %d. Reset the device\n",
33238510e1a3SNetanel Belgazal rx_ring->qid);
33249fe890ccSArthur Kiyanovski
33259fe890ccSArthur Kiyanovski ena_reset_device(adapter, ENA_REGS_RESET_MISS_INTERRUPT);
33268510e1a3SNetanel Belgazal return -EIO;
33278510e1a3SNetanel Belgazal }
33288510e1a3SNetanel Belgazal
33298510e1a3SNetanel Belgazal return 0;
33308510e1a3SNetanel Belgazal }
33318510e1a3SNetanel Belgazal
check_missing_comp_in_tx_queue(struct ena_adapter * adapter,struct ena_ring * tx_ring)33328510e1a3SNetanel Belgazal static int check_missing_comp_in_tx_queue(struct ena_adapter *adapter,
3333800c55cbSNetanel Belgazal struct ena_ring *tx_ring)
33341738cd3eSNetanel Belgazal {
3335e4ac382eSShay Agroskin struct ena_napi *ena_napi = container_of(tx_ring->napi, struct ena_napi, napi);
33360ee251cdSShay Agroskin unsigned int time_since_last_napi;
33370ee251cdSShay Agroskin unsigned int missing_tx_comp_to;
33380ee251cdSShay Agroskin bool is_tx_comp_time_expired;
33391738cd3eSNetanel Belgazal struct ena_tx_buffer *tx_buf;
33401738cd3eSNetanel Belgazal unsigned long last_jiffies;
3341800c55cbSNetanel Belgazal u32 missed_tx = 0;
334211095fdbSNetanel Belgazal int i, rc = 0;
3343800c55cbSNetanel Belgazal
3344800c55cbSNetanel Belgazal for (i = 0; i < tx_ring->ring_size; i++) {
3345800c55cbSNetanel Belgazal tx_buf = &tx_ring->tx_buffer_info[i];
3346800c55cbSNetanel Belgazal last_jiffies = tx_buf->last_jiffies;
33478510e1a3SNetanel Belgazal
33488510e1a3SNetanel Belgazal if (last_jiffies == 0)
33498510e1a3SNetanel Belgazal /* no pending Tx at this location */
33508510e1a3SNetanel Belgazal continue;
33518510e1a3SNetanel Belgazal
33520ee251cdSShay Agroskin is_tx_comp_time_expired = time_is_before_jiffies(last_jiffies +
33530ee251cdSShay Agroskin 2 * adapter->missing_tx_completion_to);
33540ee251cdSShay Agroskin
33550ee251cdSShay Agroskin if (unlikely(!READ_ONCE(ena_napi->first_interrupt) && is_tx_comp_time_expired)) {
33568510e1a3SNetanel Belgazal /* If after graceful period interrupt is still not
33578510e1a3SNetanel Belgazal * received, we schedule a reset
33588510e1a3SNetanel Belgazal */
33598510e1a3SNetanel Belgazal netif_err(adapter, tx_err, adapter->netdev,
33608510e1a3SNetanel Belgazal "Potential MSIX issue on Tx side Queue = %d. Reset the device\n",
33618510e1a3SNetanel Belgazal tx_ring->qid);
33629fe890ccSArthur Kiyanovski ena_reset_device(adapter, ENA_REGS_RESET_MISS_INTERRUPT);
33638510e1a3SNetanel Belgazal return -EIO;
33648510e1a3SNetanel Belgazal }
33658510e1a3SNetanel Belgazal
33660ee251cdSShay Agroskin is_tx_comp_time_expired = time_is_before_jiffies(last_jiffies +
33670ee251cdSShay Agroskin adapter->missing_tx_completion_to);
33680ee251cdSShay Agroskin
33690ee251cdSShay Agroskin if (unlikely(is_tx_comp_time_expired)) {
33700ee251cdSShay Agroskin if (!tx_buf->print_once) {
33710ee251cdSShay Agroskin time_since_last_napi = jiffies_to_usecs(jiffies - tx_ring->tx_stats.last_napi_jiffies);
33720ee251cdSShay Agroskin missing_tx_comp_to = jiffies_to_msecs(adapter->missing_tx_completion_to);
3373800c55cbSNetanel Belgazal netif_notice(adapter, tx_err, adapter->netdev,
33740ee251cdSShay Agroskin "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",
33750ee251cdSShay Agroskin tx_ring->qid, i, time_since_last_napi, missing_tx_comp_to);
33760ee251cdSShay Agroskin }
3377800c55cbSNetanel Belgazal
3378800c55cbSNetanel Belgazal tx_buf->print_once = 1;
3379800c55cbSNetanel Belgazal missed_tx++;
338011095fdbSNetanel Belgazal }
338111095fdbSNetanel Belgazal }
3382800c55cbSNetanel Belgazal
338382ef30f1SNetanel Belgazal if (unlikely(missed_tx > adapter->missing_tx_completion_threshold)) {
3384800c55cbSNetanel Belgazal netif_err(adapter, tx_err, adapter->netdev,
3385800c55cbSNetanel Belgazal "The number of lost tx completions is above the threshold (%d > %d). Reset the device\n",
338682ef30f1SNetanel Belgazal missed_tx,
338782ef30f1SNetanel Belgazal adapter->missing_tx_completion_threshold);
33889fe890ccSArthur Kiyanovski ena_reset_device(adapter, ENA_REGS_RESET_MISS_TX_CMPL);
338911095fdbSNetanel Belgazal rc = -EIO;
3390800c55cbSNetanel Belgazal }
3391800c55cbSNetanel Belgazal
339289dd735eSShay Agroskin ena_increase_stat(&tx_ring->tx_stats.missed_tx, missed_tx,
339389dd735eSShay Agroskin &tx_ring->syncp);
339411095fdbSNetanel Belgazal
339511095fdbSNetanel Belgazal return rc;
3396800c55cbSNetanel Belgazal }
3397800c55cbSNetanel Belgazal
check_for_missing_completions(struct ena_adapter * adapter)33988510e1a3SNetanel Belgazal static void check_for_missing_completions(struct ena_adapter *adapter)
3399800c55cbSNetanel Belgazal {
34001738cd3eSNetanel Belgazal struct ena_ring *tx_ring;
34018510e1a3SNetanel Belgazal struct ena_ring *rx_ring;
3402dc1d1e35SDavid Arinzon int qid, budget, rc;
3403548c4940SSameeh Jubran int io_queue_count;
34041738cd3eSNetanel Belgazal
3405548c4940SSameeh Jubran io_queue_count = adapter->xdp_num_queues + adapter->num_io_queues;
3406dc1d1e35SDavid Arinzon
34071738cd3eSNetanel Belgazal /* Make sure the driver doesn't turn the device in other process */
34081738cd3eSNetanel Belgazal smp_rmb();
34091738cd3eSNetanel Belgazal
34101738cd3eSNetanel Belgazal if (!test_bit(ENA_FLAG_DEV_UP, &adapter->flags))
34111738cd3eSNetanel Belgazal return;
34121738cd3eSNetanel Belgazal
34133f6159dbSNetanel Belgazal if (test_bit(ENA_FLAG_TRIGGER_RESET, &adapter->flags))
34143f6159dbSNetanel Belgazal return;
34153f6159dbSNetanel Belgazal
341682ef30f1SNetanel Belgazal if (adapter->missing_tx_completion_to == ENA_HW_HINTS_NO_TIMEOUT)
341782ef30f1SNetanel Belgazal return;
341882ef30f1SNetanel Belgazal
3419dc1d1e35SDavid Arinzon budget = min_t(u32, io_queue_count, ENA_MONITORED_TX_QUEUES);
34201738cd3eSNetanel Belgazal
3421dc1d1e35SDavid Arinzon qid = adapter->last_monitored_tx_qid;
3422dc1d1e35SDavid Arinzon
3423dc1d1e35SDavid Arinzon while (budget) {
3424dc1d1e35SDavid Arinzon qid = (qid + 1) % io_queue_count;
3425dc1d1e35SDavid Arinzon
3426dc1d1e35SDavid Arinzon tx_ring = &adapter->tx_ring[qid];
3427dc1d1e35SDavid Arinzon rx_ring = &adapter->rx_ring[qid];
34281738cd3eSNetanel Belgazal
34298510e1a3SNetanel Belgazal rc = check_missing_comp_in_tx_queue(adapter, tx_ring);
34308510e1a3SNetanel Belgazal if (unlikely(rc))
34318510e1a3SNetanel Belgazal return;
34328510e1a3SNetanel Belgazal
3433dc1d1e35SDavid Arinzon rc = !ENA_IS_XDP_INDEX(adapter, qid) ?
3434548c4940SSameeh Jubran check_for_rx_interrupt_queue(adapter, rx_ring) : 0;
3435800c55cbSNetanel Belgazal if (unlikely(rc))
3436800c55cbSNetanel Belgazal return;
34371738cd3eSNetanel Belgazal
34381738cd3eSNetanel Belgazal budget--;
34391738cd3eSNetanel Belgazal }
34401738cd3eSNetanel Belgazal
3441dc1d1e35SDavid Arinzon adapter->last_monitored_tx_qid = qid;
34421738cd3eSNetanel Belgazal }
34431738cd3eSNetanel Belgazal
3444a3af7c18SNetanel Belgazal /* trigger napi schedule after 2 consecutive detections */
3445a3af7c18SNetanel Belgazal #define EMPTY_RX_REFILL 2
3446a3af7c18SNetanel Belgazal /* For the rare case where the device runs out of Rx descriptors and the
3447a3af7c18SNetanel Belgazal * napi handler failed to refill new Rx descriptors (due to a lack of memory
3448a3af7c18SNetanel Belgazal * for example).
3449a3af7c18SNetanel Belgazal * This case will lead to a deadlock:
3450a3af7c18SNetanel Belgazal * The device won't send interrupts since all the new Rx packets will be dropped
3451a3af7c18SNetanel Belgazal * The napi handler won't allocate new Rx descriptors so the device will be
3452a3af7c18SNetanel Belgazal * able to send new packets.
3453a3af7c18SNetanel Belgazal *
3454a3af7c18SNetanel Belgazal * This scenario can happen when the kernel's vm.min_free_kbytes is too small.
3455a3af7c18SNetanel Belgazal * It is recommended to have at least 512MB, with a minimum of 128MB for
3456a3af7c18SNetanel Belgazal * constrained environment).
3457a3af7c18SNetanel Belgazal *
3458a3af7c18SNetanel Belgazal * When such a situation is detected - Reschedule napi
3459a3af7c18SNetanel Belgazal */
check_for_empty_rx_ring(struct ena_adapter * adapter)3460a3af7c18SNetanel Belgazal static void check_for_empty_rx_ring(struct ena_adapter *adapter)
3461a3af7c18SNetanel Belgazal {
3462a3af7c18SNetanel Belgazal struct ena_ring *rx_ring;
3463a3af7c18SNetanel Belgazal int i, refill_required;
3464a3af7c18SNetanel Belgazal
3465a3af7c18SNetanel Belgazal if (!test_bit(ENA_FLAG_DEV_UP, &adapter->flags))
3466a3af7c18SNetanel Belgazal return;
3467a3af7c18SNetanel Belgazal
3468a3af7c18SNetanel Belgazal if (test_bit(ENA_FLAG_TRIGGER_RESET, &adapter->flags))
3469a3af7c18SNetanel Belgazal return;
3470a3af7c18SNetanel Belgazal
3471faa615f9SSameeh Jubran for (i = 0; i < adapter->num_io_queues; i++) {
3472a3af7c18SNetanel Belgazal rx_ring = &adapter->rx_ring[i];
3473a3af7c18SNetanel Belgazal
34747cfe9a55SArthur Kiyanovski refill_required = ena_com_free_q_entries(rx_ring->ena_com_io_sq);
3475a3af7c18SNetanel Belgazal if (unlikely(refill_required == (rx_ring->ring_size - 1))) {
3476a3af7c18SNetanel Belgazal rx_ring->empty_rx_queue++;
3477a3af7c18SNetanel Belgazal
3478a3af7c18SNetanel Belgazal if (rx_ring->empty_rx_queue >= EMPTY_RX_REFILL) {
347989dd735eSShay Agroskin ena_increase_stat(&rx_ring->rx_stats.empty_rx_ring, 1,
348089dd735eSShay Agroskin &rx_ring->syncp);
3481a3af7c18SNetanel Belgazal
3482a3af7c18SNetanel Belgazal netif_err(adapter, drv, adapter->netdev,
3483bf2746e8SShay Agroskin "Trigger refill for ring %d\n", i);
3484a3af7c18SNetanel Belgazal
3485a3af7c18SNetanel Belgazal napi_schedule(rx_ring->napi);
3486a3af7c18SNetanel Belgazal rx_ring->empty_rx_queue = 0;
3487a3af7c18SNetanel Belgazal }
3488a3af7c18SNetanel Belgazal } else {
3489a3af7c18SNetanel Belgazal rx_ring->empty_rx_queue = 0;
3490a3af7c18SNetanel Belgazal }
3491a3af7c18SNetanel Belgazal }
3492a3af7c18SNetanel Belgazal }
3493a3af7c18SNetanel Belgazal
34941738cd3eSNetanel Belgazal /* Check for keep alive expiration */
check_for_missing_keep_alive(struct ena_adapter * adapter)34951738cd3eSNetanel Belgazal static void check_for_missing_keep_alive(struct ena_adapter *adapter)
34961738cd3eSNetanel Belgazal {
34971738cd3eSNetanel Belgazal unsigned long keep_alive_expired;
34981738cd3eSNetanel Belgazal
34991738cd3eSNetanel Belgazal if (!adapter->wd_state)
35001738cd3eSNetanel Belgazal return;
35011738cd3eSNetanel Belgazal
350282ef30f1SNetanel Belgazal if (adapter->keep_alive_timeout == ENA_HW_HINTS_NO_TIMEOUT)
350382ef30f1SNetanel Belgazal return;
350482ef30f1SNetanel Belgazal
35052a6e5fa2SArthur Kiyanovski keep_alive_expired = adapter->last_keep_alive_jiffies +
35062a6e5fa2SArthur Kiyanovski adapter->keep_alive_timeout;
35071738cd3eSNetanel Belgazal if (unlikely(time_is_before_jiffies(keep_alive_expired))) {
35081738cd3eSNetanel Belgazal netif_err(adapter, drv, adapter->netdev,
35091738cd3eSNetanel Belgazal "Keep alive watchdog timeout.\n");
351089dd735eSShay Agroskin ena_increase_stat(&adapter->dev_stats.wd_expired, 1,
351189dd735eSShay Agroskin &adapter->syncp);
35129fe890ccSArthur Kiyanovski ena_reset_device(adapter, ENA_REGS_RESET_KEEP_ALIVE_TO);
35131738cd3eSNetanel Belgazal }
35141738cd3eSNetanel Belgazal }
35151738cd3eSNetanel Belgazal
check_for_admin_com_state(struct ena_adapter * adapter)35161738cd3eSNetanel Belgazal static void check_for_admin_com_state(struct ena_adapter *adapter)
35171738cd3eSNetanel Belgazal {
35181738cd3eSNetanel Belgazal if (unlikely(!ena_com_get_admin_running_state(adapter->ena_dev))) {
35191738cd3eSNetanel Belgazal netif_err(adapter, drv, adapter->netdev,
35201738cd3eSNetanel Belgazal "ENA admin queue is not in running state!\n");
352189dd735eSShay Agroskin ena_increase_stat(&adapter->dev_stats.admin_q_pause, 1,
352289dd735eSShay Agroskin &adapter->syncp);
35239fe890ccSArthur Kiyanovski ena_reset_device(adapter, ENA_REGS_RESET_ADMIN_TO);
35241738cd3eSNetanel Belgazal }
35251738cd3eSNetanel Belgazal }
35261738cd3eSNetanel Belgazal
ena_update_hints(struct ena_adapter * adapter,struct ena_admin_ena_hw_hints * hints)352782ef30f1SNetanel Belgazal static void ena_update_hints(struct ena_adapter *adapter,
352882ef30f1SNetanel Belgazal struct ena_admin_ena_hw_hints *hints)
352982ef30f1SNetanel Belgazal {
353082ef30f1SNetanel Belgazal struct net_device *netdev = adapter->netdev;
353182ef30f1SNetanel Belgazal
353282ef30f1SNetanel Belgazal if (hints->admin_completion_tx_timeout)
353382ef30f1SNetanel Belgazal adapter->ena_dev->admin_queue.completion_timeout =
353482ef30f1SNetanel Belgazal hints->admin_completion_tx_timeout * 1000;
353582ef30f1SNetanel Belgazal
353682ef30f1SNetanel Belgazal if (hints->mmio_read_timeout)
353782ef30f1SNetanel Belgazal /* convert to usec */
353882ef30f1SNetanel Belgazal adapter->ena_dev->mmio_read.reg_read_to =
353982ef30f1SNetanel Belgazal hints->mmio_read_timeout * 1000;
354082ef30f1SNetanel Belgazal
354182ef30f1SNetanel Belgazal if (hints->missed_tx_completion_count_threshold_to_reset)
354282ef30f1SNetanel Belgazal adapter->missing_tx_completion_threshold =
354382ef30f1SNetanel Belgazal hints->missed_tx_completion_count_threshold_to_reset;
354482ef30f1SNetanel Belgazal
354582ef30f1SNetanel Belgazal if (hints->missing_tx_completion_timeout) {
354682ef30f1SNetanel Belgazal if (hints->missing_tx_completion_timeout == ENA_HW_HINTS_NO_TIMEOUT)
354782ef30f1SNetanel Belgazal adapter->missing_tx_completion_to = ENA_HW_HINTS_NO_TIMEOUT;
354882ef30f1SNetanel Belgazal else
354982ef30f1SNetanel Belgazal adapter->missing_tx_completion_to =
355082ef30f1SNetanel Belgazal msecs_to_jiffies(hints->missing_tx_completion_timeout);
355182ef30f1SNetanel Belgazal }
355282ef30f1SNetanel Belgazal
355382ef30f1SNetanel Belgazal if (hints->netdev_wd_timeout)
355482ef30f1SNetanel Belgazal netdev->watchdog_timeo = msecs_to_jiffies(hints->netdev_wd_timeout);
355582ef30f1SNetanel Belgazal
355682ef30f1SNetanel Belgazal if (hints->driver_watchdog_timeout) {
355782ef30f1SNetanel Belgazal if (hints->driver_watchdog_timeout == ENA_HW_HINTS_NO_TIMEOUT)
355882ef30f1SNetanel Belgazal adapter->keep_alive_timeout = ENA_HW_HINTS_NO_TIMEOUT;
355982ef30f1SNetanel Belgazal else
356082ef30f1SNetanel Belgazal adapter->keep_alive_timeout =
356182ef30f1SNetanel Belgazal msecs_to_jiffies(hints->driver_watchdog_timeout);
356282ef30f1SNetanel Belgazal }
356382ef30f1SNetanel Belgazal }
356482ef30f1SNetanel Belgazal
ena_update_host_info(struct ena_admin_host_info * host_info,struct net_device * netdev)35651738cd3eSNetanel Belgazal static void ena_update_host_info(struct ena_admin_host_info *host_info,
35661738cd3eSNetanel Belgazal struct net_device *netdev)
35671738cd3eSNetanel Belgazal {
35681738cd3eSNetanel Belgazal host_info->supported_network_features[0] =
35691738cd3eSNetanel Belgazal netdev->features & GENMASK_ULL(31, 0);
35701738cd3eSNetanel Belgazal host_info->supported_network_features[1] =
35711738cd3eSNetanel Belgazal (netdev->features & GENMASK_ULL(63, 32)) >> 32;
35721738cd3eSNetanel Belgazal }
35731738cd3eSNetanel Belgazal
ena_timer_service(struct timer_list * t)3574e99e88a9SKees Cook static void ena_timer_service(struct timer_list *t)
35751738cd3eSNetanel Belgazal {
3576e99e88a9SKees Cook struct ena_adapter *adapter = from_timer(adapter, t, timer_service);
35771738cd3eSNetanel Belgazal u8 *debug_area = adapter->ena_dev->host_attr.debug_area_virt_addr;
35781738cd3eSNetanel Belgazal struct ena_admin_host_info *host_info =
35791738cd3eSNetanel Belgazal adapter->ena_dev->host_attr.host_info;
35801738cd3eSNetanel Belgazal
35811738cd3eSNetanel Belgazal check_for_missing_keep_alive(adapter);
35821738cd3eSNetanel Belgazal
35831738cd3eSNetanel Belgazal check_for_admin_com_state(adapter);
35841738cd3eSNetanel Belgazal
35858510e1a3SNetanel Belgazal check_for_missing_completions(adapter);
35861738cd3eSNetanel Belgazal
3587a3af7c18SNetanel Belgazal check_for_empty_rx_ring(adapter);
3588a3af7c18SNetanel Belgazal
35891738cd3eSNetanel Belgazal if (debug_area)
35901738cd3eSNetanel Belgazal ena_dump_stats_to_buf(adapter, debug_area);
35911738cd3eSNetanel Belgazal
35921738cd3eSNetanel Belgazal if (host_info)
35931738cd3eSNetanel Belgazal ena_update_host_info(host_info, adapter->netdev);
35941738cd3eSNetanel Belgazal
35953f6159dbSNetanel Belgazal if (unlikely(test_bit(ENA_FLAG_TRIGGER_RESET, &adapter->flags))) {
35961738cd3eSNetanel Belgazal netif_err(adapter, drv, adapter->netdev,
35971738cd3eSNetanel Belgazal "Trigger reset is on\n");
35981738cd3eSNetanel Belgazal ena_dump_stats_to_dmesg(adapter);
35991738cd3eSNetanel Belgazal queue_work(ena_wq, &adapter->reset_task);
36001738cd3eSNetanel Belgazal return;
36011738cd3eSNetanel Belgazal }
36021738cd3eSNetanel Belgazal
36031738cd3eSNetanel Belgazal /* Reset the timer */
36042a6e5fa2SArthur Kiyanovski mod_timer(&adapter->timer_service, round_jiffies(jiffies + HZ));
36051738cd3eSNetanel Belgazal }
36061738cd3eSNetanel Belgazal
ena_calc_max_io_queue_num(struct pci_dev * pdev,struct ena_com_dev * ena_dev,struct ena_com_dev_get_features_ctx * get_feat_ctx)3607ba6f6b41SArthur Kiyanovski static u32 ena_calc_max_io_queue_num(struct pci_dev *pdev,
36081738cd3eSNetanel Belgazal struct ena_com_dev *ena_dev,
36091738cd3eSNetanel Belgazal struct ena_com_dev_get_features_ctx *get_feat_ctx)
36101738cd3eSNetanel Belgazal {
3611ba6f6b41SArthur Kiyanovski u32 io_tx_sq_num, io_tx_cq_num, io_rx_num, max_num_io_queues;
36121738cd3eSNetanel Belgazal
361331aa9857SSameeh Jubran if (ena_dev->supported_features & BIT(ENA_ADMIN_MAX_QUEUES_EXT)) {
361431aa9857SSameeh Jubran struct ena_admin_queue_ext_feature_fields *max_queue_ext =
361531aa9857SSameeh Jubran &get_feat_ctx->max_queue_ext.max_queue_ext;
3616736ce3f4SSameeh Jubran io_rx_num = min_t(u32, max_queue_ext->max_rx_sq_num,
361731aa9857SSameeh Jubran max_queue_ext->max_rx_cq_num);
361831aa9857SSameeh Jubran
361931aa9857SSameeh Jubran io_tx_sq_num = max_queue_ext->max_tx_sq_num;
362031aa9857SSameeh Jubran io_tx_cq_num = max_queue_ext->max_tx_cq_num;
362131aa9857SSameeh Jubran } else {
362231aa9857SSameeh Jubran struct ena_admin_queue_feature_desc *max_queues =
362331aa9857SSameeh Jubran &get_feat_ctx->max_queues;
362431aa9857SSameeh Jubran io_tx_sq_num = max_queues->max_sq_num;
362531aa9857SSameeh Jubran io_tx_cq_num = max_queues->max_cq_num;
3626736ce3f4SSameeh Jubran io_rx_num = min_t(u32, io_tx_sq_num, io_tx_cq_num);
362731aa9857SSameeh Jubran }
362831aa9857SSameeh Jubran
362931aa9857SSameeh Jubran /* In case of LLQ use the llq fields for the tx SQ/CQ */
36309fd25592SArthur Kiyanovski if (ena_dev->tx_mem_queue_type == ENA_ADMIN_PLACEMENT_POLICY_DEV)
363131aa9857SSameeh Jubran io_tx_sq_num = get_feat_ctx->llq.max_llq_num;
36321738cd3eSNetanel Belgazal
3633736ce3f4SSameeh Jubran max_num_io_queues = min_t(u32, num_online_cpus(), ENA_MAX_NUM_IO_QUEUES);
3634736ce3f4SSameeh Jubran max_num_io_queues = min_t(u32, max_num_io_queues, io_rx_num);
3635736ce3f4SSameeh Jubran max_num_io_queues = min_t(u32, max_num_io_queues, io_tx_sq_num);
3636736ce3f4SSameeh Jubran max_num_io_queues = min_t(u32, max_num_io_queues, io_tx_cq_num);
3637e355fa6aSYixing Liu /* 1 IRQ for mgmnt and 1 IRQs for each IO direction */
3638736ce3f4SSameeh Jubran max_num_io_queues = min_t(u32, max_num_io_queues, pci_msix_vec_count(pdev) - 1);
36391738cd3eSNetanel Belgazal
3640736ce3f4SSameeh Jubran return max_num_io_queues;
36411738cd3eSNetanel Belgazal }
36421738cd3eSNetanel Belgazal
ena_set_dev_offloads(struct ena_com_dev_get_features_ctx * feat,struct net_device * netdev)36431738cd3eSNetanel Belgazal static void ena_set_dev_offloads(struct ena_com_dev_get_features_ctx *feat,
36441738cd3eSNetanel Belgazal struct net_device *netdev)
36451738cd3eSNetanel Belgazal {
36461738cd3eSNetanel Belgazal netdev_features_t dev_features = 0;
36471738cd3eSNetanel Belgazal
36481738cd3eSNetanel Belgazal /* Set offload features */
36491738cd3eSNetanel Belgazal if (feat->offload.tx &
36501738cd3eSNetanel Belgazal ENA_ADMIN_FEATURE_OFFLOAD_DESC_TX_L4_IPV4_CSUM_PART_MASK)
36511738cd3eSNetanel Belgazal dev_features |= NETIF_F_IP_CSUM;
36521738cd3eSNetanel Belgazal
36531738cd3eSNetanel Belgazal if (feat->offload.tx &
36541738cd3eSNetanel Belgazal ENA_ADMIN_FEATURE_OFFLOAD_DESC_TX_L4_IPV6_CSUM_PART_MASK)
36551738cd3eSNetanel Belgazal dev_features |= NETIF_F_IPV6_CSUM;
36561738cd3eSNetanel Belgazal
36571738cd3eSNetanel Belgazal if (feat->offload.tx & ENA_ADMIN_FEATURE_OFFLOAD_DESC_TSO_IPV4_MASK)
36581738cd3eSNetanel Belgazal dev_features |= NETIF_F_TSO;
36591738cd3eSNetanel Belgazal
36601738cd3eSNetanel Belgazal if (feat->offload.tx & ENA_ADMIN_FEATURE_OFFLOAD_DESC_TSO_IPV6_MASK)
36611738cd3eSNetanel Belgazal dev_features |= NETIF_F_TSO6;
36621738cd3eSNetanel Belgazal
36631738cd3eSNetanel Belgazal if (feat->offload.tx & ENA_ADMIN_FEATURE_OFFLOAD_DESC_TSO_ECN_MASK)
36641738cd3eSNetanel Belgazal dev_features |= NETIF_F_TSO_ECN;
36651738cd3eSNetanel Belgazal
36661738cd3eSNetanel Belgazal if (feat->offload.rx_supported &
36671738cd3eSNetanel Belgazal ENA_ADMIN_FEATURE_OFFLOAD_DESC_RX_L4_IPV4_CSUM_MASK)
36681738cd3eSNetanel Belgazal dev_features |= NETIF_F_RXCSUM;
36691738cd3eSNetanel Belgazal
36701738cd3eSNetanel Belgazal if (feat->offload.rx_supported &
36711738cd3eSNetanel Belgazal ENA_ADMIN_FEATURE_OFFLOAD_DESC_RX_L4_IPV6_CSUM_MASK)
36721738cd3eSNetanel Belgazal dev_features |= NETIF_F_RXCSUM;
36731738cd3eSNetanel Belgazal
36741738cd3eSNetanel Belgazal netdev->features =
36751738cd3eSNetanel Belgazal dev_features |
36761738cd3eSNetanel Belgazal NETIF_F_SG |
36771738cd3eSNetanel Belgazal NETIF_F_RXHASH |
36781738cd3eSNetanel Belgazal NETIF_F_HIGHDMA;
36791738cd3eSNetanel Belgazal
36801738cd3eSNetanel Belgazal netdev->hw_features |= netdev->features;
36811738cd3eSNetanel Belgazal netdev->vlan_features |= netdev->features;
36821738cd3eSNetanel Belgazal }
36831738cd3eSNetanel Belgazal
ena_set_conf_feat_params(struct ena_adapter * adapter,struct ena_com_dev_get_features_ctx * feat)36841738cd3eSNetanel Belgazal static void ena_set_conf_feat_params(struct ena_adapter *adapter,
36851738cd3eSNetanel Belgazal struct ena_com_dev_get_features_ctx *feat)
36861738cd3eSNetanel Belgazal {
36871738cd3eSNetanel Belgazal struct net_device *netdev = adapter->netdev;
36881738cd3eSNetanel Belgazal
36891738cd3eSNetanel Belgazal /* Copy mac address */
36901738cd3eSNetanel Belgazal if (!is_valid_ether_addr(feat->dev_attr.mac_addr)) {
36911738cd3eSNetanel Belgazal eth_hw_addr_random(netdev);
36921738cd3eSNetanel Belgazal ether_addr_copy(adapter->mac_addr, netdev->dev_addr);
36931738cd3eSNetanel Belgazal } else {
36941738cd3eSNetanel Belgazal ether_addr_copy(adapter->mac_addr, feat->dev_attr.mac_addr);
3695f3956ebbSJakub Kicinski eth_hw_addr_set(netdev, adapter->mac_addr);
36961738cd3eSNetanel Belgazal }
36971738cd3eSNetanel Belgazal
36981738cd3eSNetanel Belgazal /* Set offload features */
36991738cd3eSNetanel Belgazal ena_set_dev_offloads(feat, netdev);
37001738cd3eSNetanel Belgazal
37011738cd3eSNetanel Belgazal adapter->max_mtu = feat->dev_attr.max_mtu;
3702d894be57SJarod Wilson netdev->max_mtu = adapter->max_mtu;
3703d894be57SJarod Wilson netdev->min_mtu = ENA_MIN_MTU;
37041738cd3eSNetanel Belgazal }
37051738cd3eSNetanel Belgazal
ena_rss_init_default(struct ena_adapter * adapter)37061738cd3eSNetanel Belgazal static int ena_rss_init_default(struct ena_adapter *adapter)
37071738cd3eSNetanel Belgazal {
37081738cd3eSNetanel Belgazal struct ena_com_dev *ena_dev = adapter->ena_dev;
37091738cd3eSNetanel Belgazal struct device *dev = &adapter->pdev->dev;
37101738cd3eSNetanel Belgazal int rc, i;
37111738cd3eSNetanel Belgazal u32 val;
37121738cd3eSNetanel Belgazal
37131738cd3eSNetanel Belgazal rc = ena_com_rss_init(ena_dev, ENA_RX_RSS_TABLE_LOG_SIZE);
37141738cd3eSNetanel Belgazal if (unlikely(rc)) {
37151738cd3eSNetanel Belgazal dev_err(dev, "Cannot init indirect table\n");
37161738cd3eSNetanel Belgazal goto err_rss_init;
37171738cd3eSNetanel Belgazal }
37181738cd3eSNetanel Belgazal
37191738cd3eSNetanel Belgazal for (i = 0; i < ENA_RX_RSS_TABLE_SIZE; i++) {
3720faa615f9SSameeh Jubran val = ethtool_rxfh_indir_default(i, adapter->num_io_queues);
37211738cd3eSNetanel Belgazal rc = ena_com_indirect_table_fill_entry(ena_dev, i,
37221738cd3eSNetanel Belgazal ENA_IO_RXQ_IDX(val));
372309f8676eSArthur Kiyanovski if (unlikely(rc)) {
37241738cd3eSNetanel Belgazal dev_err(dev, "Cannot fill indirect table\n");
37251738cd3eSNetanel Belgazal goto err_fill_indir;
37261738cd3eSNetanel Belgazal }
37271738cd3eSNetanel Belgazal }
37281738cd3eSNetanel Belgazal
3729*26668c2dSDavid Arinzon rc = ena_com_fill_hash_function(ena_dev, ENA_ADMIN_TOEPLITZ, NULL, ENA_HASH_KEY_SIZE,
3730*26668c2dSDavid Arinzon 0xFFFFFFFF);
3731d1497638SNetanel Belgazal if (unlikely(rc && (rc != -EOPNOTSUPP))) {
37321738cd3eSNetanel Belgazal dev_err(dev, "Cannot fill hash function\n");
37331738cd3eSNetanel Belgazal goto err_fill_indir;
37341738cd3eSNetanel Belgazal }
37351738cd3eSNetanel Belgazal
37361738cd3eSNetanel Belgazal rc = ena_com_set_default_hash_ctrl(ena_dev);
3737d1497638SNetanel Belgazal if (unlikely(rc && (rc != -EOPNOTSUPP))) {
37381738cd3eSNetanel Belgazal dev_err(dev, "Cannot fill hash control\n");
37391738cd3eSNetanel Belgazal goto err_fill_indir;
37401738cd3eSNetanel Belgazal }
37411738cd3eSNetanel Belgazal
37421738cd3eSNetanel Belgazal return 0;
37431738cd3eSNetanel Belgazal
37441738cd3eSNetanel Belgazal err_fill_indir:
37451738cd3eSNetanel Belgazal ena_com_rss_destroy(ena_dev);
37461738cd3eSNetanel Belgazal err_rss_init:
37471738cd3eSNetanel Belgazal
37481738cd3eSNetanel Belgazal return rc;
37491738cd3eSNetanel Belgazal }
37501738cd3eSNetanel Belgazal
ena_release_bars(struct ena_com_dev * ena_dev,struct pci_dev * pdev)37511738cd3eSNetanel Belgazal static void ena_release_bars(struct ena_com_dev *ena_dev, struct pci_dev *pdev)
37521738cd3eSNetanel Belgazal {
3753d79c3888SArthur Kiyanovski int release_bars = pci_select_bars(pdev, IORESOURCE_MEM) & ENA_BAR_MASK;
37541738cd3eSNetanel Belgazal
37551738cd3eSNetanel Belgazal pci_release_selected_regions(pdev, release_bars);
37561738cd3eSNetanel Belgazal }
37571738cd3eSNetanel Belgazal
37581738cd3eSNetanel Belgazal /* ena_probe - Device Initialization Routine
37591738cd3eSNetanel Belgazal * @pdev: PCI device information struct
37601738cd3eSNetanel Belgazal * @ent: entry in ena_pci_tbl
37611738cd3eSNetanel Belgazal *
37621738cd3eSNetanel Belgazal * Returns 0 on success, negative on failure
37631738cd3eSNetanel Belgazal *
37641738cd3eSNetanel Belgazal * ena_probe initializes an adapter identified by a pci_dev structure.
37651738cd3eSNetanel Belgazal * The OS initialization, configuring of the adapter private structure,
37661738cd3eSNetanel Belgazal * and a hardware reset occur.
37671738cd3eSNetanel Belgazal */
ena_probe(struct pci_dev * pdev,const struct pci_device_id * ent)37681738cd3eSNetanel Belgazal static int ena_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
37691738cd3eSNetanel Belgazal {
37700a39a35fSArthur Kiyanovski struct ena_com_dev_get_features_ctx get_feat_ctx;
37711738cd3eSNetanel Belgazal struct ena_com_dev *ena_dev = NULL;
377283b92404SSameeh Jubran struct ena_adapter *adapter;
377383b92404SSameeh Jubran struct net_device *netdev;
377483b92404SSameeh Jubran static int adapters_found;
3775736ce3f4SSameeh Jubran u32 max_num_io_queues;
37761738cd3eSNetanel Belgazal bool wd_state;
3777736ce3f4SSameeh Jubran int bars, rc;
37781738cd3eSNetanel Belgazal
37791738cd3eSNetanel Belgazal dev_dbg(&pdev->dev, "%s\n", __func__);
37801738cd3eSNetanel Belgazal
37811738cd3eSNetanel Belgazal rc = pci_enable_device_mem(pdev);
37821738cd3eSNetanel Belgazal if (rc) {
37831738cd3eSNetanel Belgazal dev_err(&pdev->dev, "pci_enable_device_mem() failed!\n");
37841738cd3eSNetanel Belgazal return rc;
37851738cd3eSNetanel Belgazal }
37861738cd3eSNetanel Belgazal
378709323b3bSShay Agroskin rc = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(ENA_MAX_PHYS_ADDR_SIZE_BITS));
378809323b3bSShay Agroskin if (rc) {
378909323b3bSShay Agroskin dev_err(&pdev->dev, "dma_set_mask_and_coherent failed %d\n", rc);
379009323b3bSShay Agroskin goto err_disable_device;
379109323b3bSShay Agroskin }
379209323b3bSShay Agroskin
37931738cd3eSNetanel Belgazal pci_set_master(pdev);
37941738cd3eSNetanel Belgazal
37951738cd3eSNetanel Belgazal ena_dev = vzalloc(sizeof(*ena_dev));
37961738cd3eSNetanel Belgazal if (!ena_dev) {
37971738cd3eSNetanel Belgazal rc = -ENOMEM;
37981738cd3eSNetanel Belgazal goto err_disable_device;
37991738cd3eSNetanel Belgazal }
38001738cd3eSNetanel Belgazal
38011738cd3eSNetanel Belgazal bars = pci_select_bars(pdev, IORESOURCE_MEM) & ENA_BAR_MASK;
38021738cd3eSNetanel Belgazal rc = pci_request_selected_regions(pdev, bars, DRV_MODULE_NAME);
38031738cd3eSNetanel Belgazal if (rc) {
38041738cd3eSNetanel Belgazal dev_err(&pdev->dev, "pci_request_selected_regions failed %d\n",
38051738cd3eSNetanel Belgazal rc);
38061738cd3eSNetanel Belgazal goto err_free_ena_dev;
38071738cd3eSNetanel Belgazal }
38081738cd3eSNetanel Belgazal
38090857d92fSNetanel Belgazal ena_dev->reg_bar = devm_ioremap(&pdev->dev,
38100857d92fSNetanel Belgazal pci_resource_start(pdev, ENA_REG_BAR),
38111738cd3eSNetanel Belgazal pci_resource_len(pdev, ENA_REG_BAR));
38121738cd3eSNetanel Belgazal if (!ena_dev->reg_bar) {
3813bf2746e8SShay Agroskin dev_err(&pdev->dev, "Failed to remap regs bar\n");
38141738cd3eSNetanel Belgazal rc = -EFAULT;
38151738cd3eSNetanel Belgazal goto err_free_region;
38161738cd3eSNetanel Belgazal }
38171738cd3eSNetanel Belgazal
38184bb7f4cfSArthur Kiyanovski ena_dev->ena_min_poll_delay_us = ENA_ADMIN_POLL_DELAY_US;
38194bb7f4cfSArthur Kiyanovski
38201738cd3eSNetanel Belgazal ena_dev->dmadev = &pdev->dev;
38211738cd3eSNetanel Belgazal
3822ce74496aSShay Agroskin netdev = alloc_etherdev_mq(sizeof(struct ena_adapter), ENA_MAX_RINGS);
3823ce74496aSShay Agroskin if (!netdev) {
3824ce74496aSShay Agroskin dev_err(&pdev->dev, "alloc_etherdev_mq failed\n");
3825ce74496aSShay Agroskin rc = -ENOMEM;
3826ce74496aSShay Agroskin goto err_free_region;
3827ce74496aSShay Agroskin }
3828ce74496aSShay Agroskin
3829ce74496aSShay Agroskin SET_NETDEV_DEV(netdev, &pdev->dev);
3830ce74496aSShay Agroskin adapter = netdev_priv(netdev);
3831ce74496aSShay Agroskin adapter->ena_dev = ena_dev;
3832ce74496aSShay Agroskin adapter->netdev = netdev;
3833ce74496aSShay Agroskin adapter->pdev = pdev;
383415efff76SShay Agroskin adapter->msg_enable = DEFAULT_MSG_ENABLE;
3835ce74496aSShay Agroskin
3836da580ca8SShay Agroskin ena_dev->net_device = netdev;
3837da580ca8SShay Agroskin
3838ce74496aSShay Agroskin pci_set_drvdata(pdev, adapter);
3839ce74496aSShay Agroskin
38401e366688SDavid Arinzon rc = ena_map_llq_mem_bar(pdev, ena_dev, bars);
38411e366688SDavid Arinzon if (rc) {
38421e366688SDavid Arinzon dev_err(&pdev->dev, "ENA LLQ bar mapping failed\n");
38431e366688SDavid Arinzon goto err_netdev_destroy;
38441e366688SDavid Arinzon }
38451e366688SDavid Arinzon
38461e366688SDavid Arinzon rc = ena_device_init(adapter, pdev, &get_feat_ctx, &wd_state);
38471738cd3eSNetanel Belgazal if (rc) {
3848bf2746e8SShay Agroskin dev_err(&pdev->dev, "ENA device init failed\n");
38491738cd3eSNetanel Belgazal if (rc == -ETIME)
38501738cd3eSNetanel Belgazal rc = -EPROBE_DEFER;
3851ce74496aSShay Agroskin goto err_netdev_destroy;
38521738cd3eSNetanel Belgazal }
38531738cd3eSNetanel Belgazal
385413830937SArthur Kiyanovski /* Initial TX and RX interrupt delay. Assumes 1 usec granularity.
38551738cd3eSNetanel Belgazal * Updated during device initialization with the real granularity
38561738cd3eSNetanel Belgazal */
38571738cd3eSNetanel Belgazal ena_dev->intr_moder_tx_interval = ENA_INTR_INITIAL_TX_INTERVAL_USECS;
385815619e72SArthur Kiyanovski ena_dev->intr_moder_rx_interval = ENA_INTR_INITIAL_RX_INTERVAL_USECS;
385979226ceaSArthur Kiyanovski ena_dev->intr_delay_resolution = ENA_DEFAULT_INTR_DELAY_RESOLUTION;
3860736ce3f4SSameeh Jubran max_num_io_queues = ena_calc_max_io_queue_num(pdev, ena_dev, &get_feat_ctx);
38617dcf9221SArthur Kiyanovski if (unlikely(!max_num_io_queues)) {
38621738cd3eSNetanel Belgazal rc = -EFAULT;
38631738cd3eSNetanel Belgazal goto err_device_destroy;
38641738cd3eSNetanel Belgazal }
38651738cd3eSNetanel Belgazal
38661738cd3eSNetanel Belgazal ena_set_conf_feat_params(adapter, &get_feat_ctx);
38671738cd3eSNetanel Belgazal
3868e2eed0e3SNetanel Belgazal adapter->reset_reason = ENA_REGS_RESET_NORMAL;
38691738cd3eSNetanel Belgazal
3870736ce3f4SSameeh Jubran adapter->num_io_queues = max_num_io_queues;
3871736ce3f4SSameeh Jubran adapter->max_num_io_queues = max_num_io_queues;
38720a39a35fSArthur Kiyanovski adapter->last_monitored_tx_qid = 0;
3873736ce3f4SSameeh Jubran
3874548c4940SSameeh Jubran adapter->xdp_first_ring = 0;
3875548c4940SSameeh Jubran adapter->xdp_num_queues = 0;
3876548c4940SSameeh Jubran
38771738cd3eSNetanel Belgazal adapter->rx_copybreak = ENA_DEFAULT_RX_COPYBREAK;
38780e3a3f6dSArthur Kiyanovski if (ena_dev->tx_mem_queue_type == ENA_ADMIN_PLACEMENT_POLICY_DEV)
38790e3a3f6dSArthur Kiyanovski adapter->disable_meta_caching =
38800e3a3f6dSArthur Kiyanovski !!(get_feat_ctx.llq.accel_mode.u.get.supported_flags &
38810e3a3f6dSArthur Kiyanovski BIT(ENA_ADMIN_DISABLE_META_CACHING));
38820e3a3f6dSArthur Kiyanovski
38831738cd3eSNetanel Belgazal adapter->wd_state = wd_state;
38841738cd3eSNetanel Belgazal
38851738cd3eSNetanel Belgazal snprintf(adapter->name, ENA_NAME_MAX_LEN, "ena_%d", adapters_found);
38861738cd3eSNetanel Belgazal
38871738cd3eSNetanel Belgazal rc = ena_com_init_interrupt_moderation(adapter->ena_dev);
38881738cd3eSNetanel Belgazal if (rc) {
38891738cd3eSNetanel Belgazal dev_err(&pdev->dev,
38901738cd3eSNetanel Belgazal "Failed to query interrupt moderation feature\n");
3891ce74496aSShay Agroskin goto err_device_destroy;
38921738cd3eSNetanel Belgazal }
38933a091084SShay Agroskin
3894548c4940SSameeh Jubran ena_init_io_rings(adapter,
3895548c4940SSameeh Jubran 0,
3896548c4940SSameeh Jubran adapter->xdp_num_queues +
3897548c4940SSameeh Jubran adapter->num_io_queues);
38981738cd3eSNetanel Belgazal
38991738cd3eSNetanel Belgazal netdev->netdev_ops = &ena_netdev_ops;
39001738cd3eSNetanel Belgazal netdev->watchdog_timeo = TX_TIMEOUT;
39011738cd3eSNetanel Belgazal ena_set_ethtool_ops(netdev);
39021738cd3eSNetanel Belgazal
39031738cd3eSNetanel Belgazal netdev->priv_flags |= IFF_UNICAST_FLT;
39041738cd3eSNetanel Belgazal
39051738cd3eSNetanel Belgazal u64_stats_init(&adapter->syncp);
39061738cd3eSNetanel Belgazal
39074d192660SSameeh Jubran rc = ena_enable_msix_and_set_admin_interrupts(adapter);
39081738cd3eSNetanel Belgazal if (rc) {
39091738cd3eSNetanel Belgazal dev_err(&pdev->dev,
39101738cd3eSNetanel Belgazal "Failed to enable and set the admin interrupts\n");
39111738cd3eSNetanel Belgazal goto err_worker_destroy;
39121738cd3eSNetanel Belgazal }
39131738cd3eSNetanel Belgazal rc = ena_rss_init_default(adapter);
3914d1497638SNetanel Belgazal if (rc && (rc != -EOPNOTSUPP)) {
39151738cd3eSNetanel Belgazal dev_err(&pdev->dev, "Cannot init RSS rc: %d\n", rc);
39161738cd3eSNetanel Belgazal goto err_free_msix;
39171738cd3eSNetanel Belgazal }
39181738cd3eSNetanel Belgazal
39191738cd3eSNetanel Belgazal ena_config_debug_area(adapter);
39201738cd3eSNetanel Belgazal
39217aa6dc35SLorenzo Bianconi if (ena_xdp_legal_queue_count(adapter, adapter->num_io_queues))
39227aa6dc35SLorenzo Bianconi netdev->xdp_features = NETDEV_XDP_ACT_BASIC |
39237aa6dc35SLorenzo Bianconi NETDEV_XDP_ACT_REDIRECT;
39247aa6dc35SLorenzo Bianconi
39251738cd3eSNetanel Belgazal memcpy(adapter->netdev->perm_addr, adapter->mac_addr, netdev->addr_len);
39261738cd3eSNetanel Belgazal
39271738cd3eSNetanel Belgazal netif_carrier_off(netdev);
39281738cd3eSNetanel Belgazal
39291738cd3eSNetanel Belgazal rc = register_netdev(netdev);
39301738cd3eSNetanel Belgazal if (rc) {
39311738cd3eSNetanel Belgazal dev_err(&pdev->dev, "Cannot register net device\n");
39321738cd3eSNetanel Belgazal goto err_rss;
39331738cd3eSNetanel Belgazal }
39341738cd3eSNetanel Belgazal
39351738cd3eSNetanel Belgazal INIT_WORK(&adapter->reset_task, ena_fw_reset_device);
39361738cd3eSNetanel Belgazal
39371738cd3eSNetanel Belgazal adapter->last_keep_alive_jiffies = jiffies;
393882ef30f1SNetanel Belgazal adapter->keep_alive_timeout = ENA_DEVICE_KALIVE_TIMEOUT;
393982ef30f1SNetanel Belgazal adapter->missing_tx_completion_to = TX_TIMEOUT;
394082ef30f1SNetanel Belgazal adapter->missing_tx_completion_threshold = MAX_NUM_OF_TIMEOUTED_PACKETS;
394182ef30f1SNetanel Belgazal
394282ef30f1SNetanel Belgazal ena_update_hints(adapter, &get_feat_ctx.hw_hints);
39431738cd3eSNetanel Belgazal
3944e99e88a9SKees Cook timer_setup(&adapter->timer_service, ena_timer_service, 0);
3945f850b4a7SWei Yongjun mod_timer(&adapter->timer_service, round_jiffies(jiffies + HZ));
39461738cd3eSNetanel Belgazal
394738005ca8SArthur Kiyanovski dev_info(&pdev->dev,
3948a8aea849SShay Agroskin "%s found at mem %lx, mac addr %pM\n",
39491738cd3eSNetanel Belgazal DEVICE_NAME, (long)pci_resource_start(pdev, 0),
3950a8aea849SShay Agroskin netdev->dev_addr);
39511738cd3eSNetanel Belgazal
39521738cd3eSNetanel Belgazal set_bit(ENA_FLAG_DEVICE_RUNNING, &adapter->flags);
39531738cd3eSNetanel Belgazal
39541738cd3eSNetanel Belgazal adapters_found++;
39551738cd3eSNetanel Belgazal
39561738cd3eSNetanel Belgazal return 0;
39571738cd3eSNetanel Belgazal
39581738cd3eSNetanel Belgazal err_rss:
39591738cd3eSNetanel Belgazal ena_com_delete_debug_area(ena_dev);
39601738cd3eSNetanel Belgazal ena_com_rss_destroy(ena_dev);
39611738cd3eSNetanel Belgazal err_free_msix:
3962e2eed0e3SNetanel Belgazal ena_com_dev_reset(ena_dev, ENA_REGS_RESET_INIT_ERR);
396358a54b9cSArthur Kiyanovski /* stop submitting admin commands on a device that was reset */
396458a54b9cSArthur Kiyanovski ena_com_set_admin_running_state(ena_dev, false);
39651738cd3eSNetanel Belgazal ena_free_mgmnt_irq(adapter);
396606443684SNetanel Belgazal ena_disable_msix(adapter);
39671738cd3eSNetanel Belgazal err_worker_destroy:
39681738cd3eSNetanel Belgazal del_timer(&adapter->timer_service);
39691738cd3eSNetanel Belgazal err_device_destroy:
39701738cd3eSNetanel Belgazal ena_com_delete_host_info(ena_dev);
39711738cd3eSNetanel Belgazal ena_com_admin_destroy(ena_dev);
3972ce74496aSShay Agroskin err_netdev_destroy:
3973ce74496aSShay Agroskin free_netdev(netdev);
39741738cd3eSNetanel Belgazal err_free_region:
39751738cd3eSNetanel Belgazal ena_release_bars(ena_dev, pdev);
39761738cd3eSNetanel Belgazal err_free_ena_dev:
39771738cd3eSNetanel Belgazal vfree(ena_dev);
39781738cd3eSNetanel Belgazal err_disable_device:
39791738cd3eSNetanel Belgazal pci_disable_device(pdev);
39801738cd3eSNetanel Belgazal return rc;
39811738cd3eSNetanel Belgazal }
39821738cd3eSNetanel Belgazal
39831738cd3eSNetanel Belgazal /*****************************************************************************/
39841738cd3eSNetanel Belgazal
3985428c4913SGuilherme G. Piccoli /* __ena_shutoff - Helper used in both PCI remove/shutdown routines
39861738cd3eSNetanel Belgazal * @pdev: PCI device information struct
3987428c4913SGuilherme G. Piccoli * @shutdown: Is it a shutdown operation? If false, means it is a removal
39881738cd3eSNetanel Belgazal *
3989428c4913SGuilherme G. Piccoli * __ena_shutoff is a helper routine that does the real work on shutdown and
3990428c4913SGuilherme G. Piccoli * removal paths; the difference between those paths is with regards to whether
3991428c4913SGuilherme G. Piccoli * dettach or unregister the netdevice.
39921738cd3eSNetanel Belgazal */
__ena_shutoff(struct pci_dev * pdev,bool shutdown)3993428c4913SGuilherme G. Piccoli static void __ena_shutoff(struct pci_dev *pdev, bool shutdown)
39941738cd3eSNetanel Belgazal {
39951738cd3eSNetanel Belgazal struct ena_adapter *adapter = pci_get_drvdata(pdev);
39961738cd3eSNetanel Belgazal struct ena_com_dev *ena_dev;
39971738cd3eSNetanel Belgazal struct net_device *netdev;
39981738cd3eSNetanel Belgazal
39991738cd3eSNetanel Belgazal ena_dev = adapter->ena_dev;
40001738cd3eSNetanel Belgazal netdev = adapter->netdev;
40011738cd3eSNetanel Belgazal
40021738cd3eSNetanel Belgazal #ifdef CONFIG_RFS_ACCEL
40031738cd3eSNetanel Belgazal if ((adapter->msix_vecs >= 1) && (netdev->rx_cpu_rmap)) {
40041738cd3eSNetanel Belgazal free_irq_cpu_rmap(netdev->rx_cpu_rmap);
40051738cd3eSNetanel Belgazal netdev->rx_cpu_rmap = NULL;
40061738cd3eSNetanel Belgazal }
40071738cd3eSNetanel Belgazal #endif /* CONFIG_RFS_ACCEL */
40081738cd3eSNetanel Belgazal
400963d4a4c1SShay Agroskin /* Make sure timer and reset routine won't be called after
401063d4a4c1SShay Agroskin * freeing device resources.
401163d4a4c1SShay Agroskin */
401263d4a4c1SShay Agroskin del_timer_sync(&adapter->timer_service);
40131738cd3eSNetanel Belgazal cancel_work_sync(&adapter->reset_task);
40141738cd3eSNetanel Belgazal
4015428c4913SGuilherme G. Piccoli rtnl_lock(); /* lock released inside the below if-else block */
4016c1c0e40bSSameeh Jubran adapter->reset_reason = ENA_REGS_RESET_SHUTDOWN;
4017944b28aaSNetanel Belgazal ena_destroy_device(adapter, true);
40183a091084SShay Agroskin
4019428c4913SGuilherme G. Piccoli if (shutdown) {
4020428c4913SGuilherme G. Piccoli netif_device_detach(netdev);
4021428c4913SGuilherme G. Piccoli dev_close(netdev);
4022944b28aaSNetanel Belgazal rtnl_unlock();
4023428c4913SGuilherme G. Piccoli } else {
4024428c4913SGuilherme G. Piccoli rtnl_unlock();
402558a54b9cSArthur Kiyanovski unregister_netdev(netdev);
40261738cd3eSNetanel Belgazal free_netdev(netdev);
4027428c4913SGuilherme G. Piccoli }
40281738cd3eSNetanel Belgazal
40291738cd3eSNetanel Belgazal ena_com_rss_destroy(ena_dev);
40301738cd3eSNetanel Belgazal
40311738cd3eSNetanel Belgazal ena_com_delete_debug_area(ena_dev);
40321738cd3eSNetanel Belgazal
40331738cd3eSNetanel Belgazal ena_com_delete_host_info(ena_dev);
40341738cd3eSNetanel Belgazal
40351738cd3eSNetanel Belgazal ena_release_bars(ena_dev, pdev);
40361738cd3eSNetanel Belgazal
40371738cd3eSNetanel Belgazal pci_disable_device(pdev);
40381738cd3eSNetanel Belgazal
40391738cd3eSNetanel Belgazal vfree(ena_dev);
40401738cd3eSNetanel Belgazal }
40411738cd3eSNetanel Belgazal
4042428c4913SGuilherme G. Piccoli /* ena_remove - Device Removal Routine
4043428c4913SGuilherme G. Piccoli * @pdev: PCI device information struct
4044428c4913SGuilherme G. Piccoli *
4045428c4913SGuilherme G. Piccoli * ena_remove is called by the PCI subsystem to alert the driver
4046428c4913SGuilherme G. Piccoli * that it should release a PCI device.
4047428c4913SGuilherme G. Piccoli */
4048428c4913SGuilherme G. Piccoli
ena_remove(struct pci_dev * pdev)4049428c4913SGuilherme G. Piccoli static void ena_remove(struct pci_dev *pdev)
4050428c4913SGuilherme G. Piccoli {
4051428c4913SGuilherme G. Piccoli __ena_shutoff(pdev, false);
4052428c4913SGuilherme G. Piccoli }
4053428c4913SGuilherme G. Piccoli
4054428c4913SGuilherme G. Piccoli /* ena_shutdown - Device Shutdown Routine
4055428c4913SGuilherme G. Piccoli * @pdev: PCI device information struct
4056428c4913SGuilherme G. Piccoli *
4057428c4913SGuilherme G. Piccoli * ena_shutdown is called by the PCI subsystem to alert the driver that
4058428c4913SGuilherme G. Piccoli * a shutdown/reboot (or kexec) is happening and device must be disabled.
4059428c4913SGuilherme G. Piccoli */
4060428c4913SGuilherme G. Piccoli
ena_shutdown(struct pci_dev * pdev)4061428c4913SGuilherme G. Piccoli static void ena_shutdown(struct pci_dev *pdev)
4062428c4913SGuilherme G. Piccoli {
4063428c4913SGuilherme G. Piccoli __ena_shutoff(pdev, true);
4064428c4913SGuilherme G. Piccoli }
4065428c4913SGuilherme G. Piccoli
40668c5c7abdSNetanel Belgazal /* ena_suspend - PM suspend callback
4067817a89aeSVaibhav Gupta * @dev_d: Device information struct
40688c5c7abdSNetanel Belgazal */
ena_suspend(struct device * dev_d)4069817a89aeSVaibhav Gupta static int __maybe_unused ena_suspend(struct device *dev_d)
40708c5c7abdSNetanel Belgazal {
4071817a89aeSVaibhav Gupta struct pci_dev *pdev = to_pci_dev(dev_d);
40728c5c7abdSNetanel Belgazal struct ena_adapter *adapter = pci_get_drvdata(pdev);
40738c5c7abdSNetanel Belgazal
407489dd735eSShay Agroskin ena_increase_stat(&adapter->dev_stats.suspend, 1, &adapter->syncp);
40758c5c7abdSNetanel Belgazal
40768c5c7abdSNetanel Belgazal rtnl_lock();
40778c5c7abdSNetanel Belgazal if (unlikely(test_bit(ENA_FLAG_TRIGGER_RESET, &adapter->flags))) {
40788c5c7abdSNetanel Belgazal dev_err(&pdev->dev,
4079bf2746e8SShay Agroskin "Ignoring device reset request as the device is being suspended\n");
40808c5c7abdSNetanel Belgazal clear_bit(ENA_FLAG_TRIGGER_RESET, &adapter->flags);
40818c5c7abdSNetanel Belgazal }
4082cfa324a5SNetanel Belgazal ena_destroy_device(adapter, true);
40838c5c7abdSNetanel Belgazal rtnl_unlock();
40848c5c7abdSNetanel Belgazal return 0;
40858c5c7abdSNetanel Belgazal }
40868c5c7abdSNetanel Belgazal
40878c5c7abdSNetanel Belgazal /* ena_resume - PM resume callback
4088817a89aeSVaibhav Gupta * @dev_d: Device information struct
40898c5c7abdSNetanel Belgazal */
ena_resume(struct device * dev_d)4090817a89aeSVaibhav Gupta static int __maybe_unused ena_resume(struct device *dev_d)
40918c5c7abdSNetanel Belgazal {
4092817a89aeSVaibhav Gupta struct ena_adapter *adapter = dev_get_drvdata(dev_d);
40938c5c7abdSNetanel Belgazal int rc;
40948c5c7abdSNetanel Belgazal
409589dd735eSShay Agroskin ena_increase_stat(&adapter->dev_stats.resume, 1, &adapter->syncp);
40968c5c7abdSNetanel Belgazal
40978c5c7abdSNetanel Belgazal rtnl_lock();
40988c5c7abdSNetanel Belgazal rc = ena_restore_device(adapter);
40998c5c7abdSNetanel Belgazal rtnl_unlock();
41008c5c7abdSNetanel Belgazal return rc;
41018c5c7abdSNetanel Belgazal }
4102817a89aeSVaibhav Gupta
4103817a89aeSVaibhav Gupta static SIMPLE_DEV_PM_OPS(ena_pm_ops, ena_suspend, ena_resume);
41048c5c7abdSNetanel Belgazal
41051738cd3eSNetanel Belgazal static struct pci_driver ena_pci_driver = {
41061738cd3eSNetanel Belgazal .name = DRV_MODULE_NAME,
41071738cd3eSNetanel Belgazal .id_table = ena_pci_tbl,
41081738cd3eSNetanel Belgazal .probe = ena_probe,
41091738cd3eSNetanel Belgazal .remove = ena_remove,
4110428c4913SGuilherme G. Piccoli .shutdown = ena_shutdown,
4111817a89aeSVaibhav Gupta .driver.pm = &ena_pm_ops,
4112115ddc49SAlexander Duyck .sriov_configure = pci_sriov_configure_simple,
41131738cd3eSNetanel Belgazal };
41141738cd3eSNetanel Belgazal
ena_init(void)41151738cd3eSNetanel Belgazal static int __init ena_init(void)
41161738cd3eSNetanel Belgazal {
4117d349e9beSYuan Can int ret;
4118d349e9beSYuan Can
41191738cd3eSNetanel Belgazal ena_wq = create_singlethread_workqueue(DRV_MODULE_NAME);
41201738cd3eSNetanel Belgazal if (!ena_wq) {
41211738cd3eSNetanel Belgazal pr_err("Failed to create workqueue\n");
41221738cd3eSNetanel Belgazal return -ENOMEM;
41231738cd3eSNetanel Belgazal }
41241738cd3eSNetanel Belgazal
4125d349e9beSYuan Can ret = pci_register_driver(&ena_pci_driver);
4126d349e9beSYuan Can if (ret)
4127d349e9beSYuan Can destroy_workqueue(ena_wq);
4128d349e9beSYuan Can
4129d349e9beSYuan Can return ret;
41301738cd3eSNetanel Belgazal }
41311738cd3eSNetanel Belgazal
ena_cleanup(void)41321738cd3eSNetanel Belgazal static void __exit ena_cleanup(void)
41331738cd3eSNetanel Belgazal {
41341738cd3eSNetanel Belgazal pci_unregister_driver(&ena_pci_driver);
41351738cd3eSNetanel Belgazal
41361738cd3eSNetanel Belgazal if (ena_wq) {
41371738cd3eSNetanel Belgazal destroy_workqueue(ena_wq);
41381738cd3eSNetanel Belgazal ena_wq = NULL;
41391738cd3eSNetanel Belgazal }
41401738cd3eSNetanel Belgazal }
41411738cd3eSNetanel Belgazal
41421738cd3eSNetanel Belgazal /******************************************************************************
41431738cd3eSNetanel Belgazal ******************************** AENQ Handlers *******************************
41441738cd3eSNetanel Belgazal *****************************************************************************/
41451738cd3eSNetanel Belgazal /* ena_update_on_link_change:
41461738cd3eSNetanel Belgazal * Notify the network interface about the change in link status
41471738cd3eSNetanel Belgazal */
ena_update_on_link_change(void * adapter_data,struct ena_admin_aenq_entry * aenq_e)41481738cd3eSNetanel Belgazal static void ena_update_on_link_change(void *adapter_data,
41491738cd3eSNetanel Belgazal struct ena_admin_aenq_entry *aenq_e)
41501738cd3eSNetanel Belgazal {
41511738cd3eSNetanel Belgazal struct ena_adapter *adapter = (struct ena_adapter *)adapter_data;
41521738cd3eSNetanel Belgazal struct ena_admin_aenq_link_change_desc *aenq_desc =
41531738cd3eSNetanel Belgazal (struct ena_admin_aenq_link_change_desc *)aenq_e;
41541738cd3eSNetanel Belgazal int status = aenq_desc->flags &
41551738cd3eSNetanel Belgazal ENA_ADMIN_AENQ_LINK_CHANGE_DESC_LINK_STATUS_MASK;
41561738cd3eSNetanel Belgazal
41571738cd3eSNetanel Belgazal if (status) {
4158f0525298SShay Agroskin netif_dbg(adapter, ifup, adapter->netdev, "%s\n", __func__);
41591738cd3eSNetanel Belgazal set_bit(ENA_FLAG_LINK_UP, &adapter->flags);
4160d18e4f68SNetanel Belgazal if (!test_bit(ENA_FLAG_ONGOING_RESET, &adapter->flags))
41611738cd3eSNetanel Belgazal netif_carrier_on(adapter->netdev);
41621738cd3eSNetanel Belgazal } else {
41631738cd3eSNetanel Belgazal clear_bit(ENA_FLAG_LINK_UP, &adapter->flags);
41641738cd3eSNetanel Belgazal netif_carrier_off(adapter->netdev);
41651738cd3eSNetanel Belgazal }
41661738cd3eSNetanel Belgazal }
41671738cd3eSNetanel Belgazal
ena_keep_alive_wd(void * adapter_data,struct ena_admin_aenq_entry * aenq_e)41681738cd3eSNetanel Belgazal static void ena_keep_alive_wd(void *adapter_data,
41691738cd3eSNetanel Belgazal struct ena_admin_aenq_entry *aenq_e)
41701738cd3eSNetanel Belgazal {
41711738cd3eSNetanel Belgazal struct ena_adapter *adapter = (struct ena_adapter *)adapter_data;
417211a9a460SNetanel Belgazal struct ena_admin_aenq_keep_alive_desc *desc;
417311a9a460SNetanel Belgazal u64 rx_drops;
41745c665f8cSSameeh Jubran u64 tx_drops;
41751738cd3eSNetanel Belgazal
417611a9a460SNetanel Belgazal desc = (struct ena_admin_aenq_keep_alive_desc *)aenq_e;
41771738cd3eSNetanel Belgazal adapter->last_keep_alive_jiffies = jiffies;
417811a9a460SNetanel Belgazal
417911a9a460SNetanel Belgazal rx_drops = ((u64)desc->rx_drops_high << 32) | desc->rx_drops_low;
41805c665f8cSSameeh Jubran tx_drops = ((u64)desc->tx_drops_high << 32) | desc->tx_drops_low;
418111a9a460SNetanel Belgazal
418211a9a460SNetanel Belgazal u64_stats_update_begin(&adapter->syncp);
4183ccd143e5SShay Agroskin /* These stats are accumulated by the device, so the counters indicate
4184ccd143e5SShay Agroskin * all drops since last reset.
4185ccd143e5SShay Agroskin */
418611a9a460SNetanel Belgazal adapter->dev_stats.rx_drops = rx_drops;
41875c665f8cSSameeh Jubran adapter->dev_stats.tx_drops = tx_drops;
418811a9a460SNetanel Belgazal u64_stats_update_end(&adapter->syncp);
41891738cd3eSNetanel Belgazal }
41901738cd3eSNetanel Belgazal
ena_notification(void * adapter_data,struct ena_admin_aenq_entry * aenq_e)41911738cd3eSNetanel Belgazal static void ena_notification(void *adapter_data,
41921738cd3eSNetanel Belgazal struct ena_admin_aenq_entry *aenq_e)
41931738cd3eSNetanel Belgazal {
41941738cd3eSNetanel Belgazal struct ena_adapter *adapter = (struct ena_adapter *)adapter_data;
419582ef30f1SNetanel Belgazal struct ena_admin_ena_hw_hints *hints;
41961738cd3eSNetanel Belgazal
41971738cd3eSNetanel Belgazal WARN(aenq_e->aenq_common_desc.group != ENA_ADMIN_NOTIFICATION,
41981738cd3eSNetanel Belgazal "Invalid group(%x) expected %x\n",
41991738cd3eSNetanel Belgazal aenq_e->aenq_common_desc.group,
42001738cd3eSNetanel Belgazal ENA_ADMIN_NOTIFICATION);
42011738cd3eSNetanel Belgazal
4202bf2746e8SShay Agroskin switch (aenq_e->aenq_common_desc.syndrome) {
420382ef30f1SNetanel Belgazal case ENA_ADMIN_UPDATE_HINTS:
420482ef30f1SNetanel Belgazal hints = (struct ena_admin_ena_hw_hints *)
420582ef30f1SNetanel Belgazal (&aenq_e->inline_data_w4);
420682ef30f1SNetanel Belgazal ena_update_hints(adapter, hints);
420782ef30f1SNetanel Belgazal break;
42081738cd3eSNetanel Belgazal default:
42091738cd3eSNetanel Belgazal netif_err(adapter, drv, adapter->netdev,
42101738cd3eSNetanel Belgazal "Invalid aenq notification link state %d\n",
4211bf2746e8SShay Agroskin aenq_e->aenq_common_desc.syndrome);
42121738cd3eSNetanel Belgazal }
42131738cd3eSNetanel Belgazal }
42141738cd3eSNetanel Belgazal
42151738cd3eSNetanel Belgazal /* This handler will called for unknown event group or unimplemented handlers*/
unimplemented_aenq_handler(void * data,struct ena_admin_aenq_entry * aenq_e)42161738cd3eSNetanel Belgazal static void unimplemented_aenq_handler(void *data,
42171738cd3eSNetanel Belgazal struct ena_admin_aenq_entry *aenq_e)
42181738cd3eSNetanel Belgazal {
42191738cd3eSNetanel Belgazal struct ena_adapter *adapter = (struct ena_adapter *)data;
42201738cd3eSNetanel Belgazal
42211738cd3eSNetanel Belgazal netif_err(adapter, drv, adapter->netdev,
42221738cd3eSNetanel Belgazal "Unknown event was received or event with unimplemented handler\n");
42231738cd3eSNetanel Belgazal }
42241738cd3eSNetanel Belgazal
42251738cd3eSNetanel Belgazal static struct ena_aenq_handlers aenq_handlers = {
42261738cd3eSNetanel Belgazal .handlers = {
42271738cd3eSNetanel Belgazal [ENA_ADMIN_LINK_CHANGE] = ena_update_on_link_change,
42281738cd3eSNetanel Belgazal [ENA_ADMIN_NOTIFICATION] = ena_notification,
42291738cd3eSNetanel Belgazal [ENA_ADMIN_KEEP_ALIVE] = ena_keep_alive_wd,
42301738cd3eSNetanel Belgazal },
42311738cd3eSNetanel Belgazal .unimplemented_handler = unimplemented_aenq_handler
42321738cd3eSNetanel Belgazal };
42331738cd3eSNetanel Belgazal
42341738cd3eSNetanel Belgazal module_init(ena_init);
42351738cd3eSNetanel Belgazal module_exit(ena_cleanup);
4236