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