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#include "ena_com.h" 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci/*****************************************************************************/ 962306a36Sopenharmony_ci/*****************************************************************************/ 1062306a36Sopenharmony_ci 1162306a36Sopenharmony_ci/* Timeout in micro-sec */ 1262306a36Sopenharmony_ci#define ADMIN_CMD_TIMEOUT_US (3000000) 1362306a36Sopenharmony_ci 1462306a36Sopenharmony_ci#define ENA_ASYNC_QUEUE_DEPTH 16 1562306a36Sopenharmony_ci#define ENA_ADMIN_QUEUE_DEPTH 32 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_ci 1862306a36Sopenharmony_ci#define ENA_CTRL_MAJOR 0 1962306a36Sopenharmony_ci#define ENA_CTRL_MINOR 0 2062306a36Sopenharmony_ci#define ENA_CTRL_SUB_MINOR 1 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_ci#define MIN_ENA_CTRL_VER \ 2362306a36Sopenharmony_ci (((ENA_CTRL_MAJOR) << \ 2462306a36Sopenharmony_ci (ENA_REGS_CONTROLLER_VERSION_MAJOR_VERSION_SHIFT)) | \ 2562306a36Sopenharmony_ci ((ENA_CTRL_MINOR) << \ 2662306a36Sopenharmony_ci (ENA_REGS_CONTROLLER_VERSION_MINOR_VERSION_SHIFT)) | \ 2762306a36Sopenharmony_ci (ENA_CTRL_SUB_MINOR)) 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_ci#define ENA_DMA_ADDR_TO_UINT32_LOW(x) ((u32)((u64)(x))) 3062306a36Sopenharmony_ci#define ENA_DMA_ADDR_TO_UINT32_HIGH(x) ((u32)(((u64)(x)) >> 32)) 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_ci#define ENA_MMIO_READ_TIMEOUT 0xFFFFFFFF 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_ci#define ENA_COM_BOUNCE_BUFFER_CNTRL_CNT 4 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_ci#define ENA_REGS_ADMIN_INTR_MASK 1 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_ci#define ENA_MAX_BACKOFF_DELAY_EXP 16U 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_ci#define ENA_MIN_ADMIN_POLL_US 100 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_ci#define ENA_MAX_ADMIN_POLL_US 5000 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_ci/*****************************************************************************/ 4562306a36Sopenharmony_ci/*****************************************************************************/ 4662306a36Sopenharmony_ci/*****************************************************************************/ 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_cienum ena_cmd_status { 4962306a36Sopenharmony_ci ENA_CMD_SUBMITTED, 5062306a36Sopenharmony_ci ENA_CMD_COMPLETED, 5162306a36Sopenharmony_ci /* Abort - canceled by the driver */ 5262306a36Sopenharmony_ci ENA_CMD_ABORTED, 5362306a36Sopenharmony_ci}; 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_cistruct ena_comp_ctx { 5662306a36Sopenharmony_ci struct completion wait_event; 5762306a36Sopenharmony_ci struct ena_admin_acq_entry *user_cqe; 5862306a36Sopenharmony_ci u32 comp_size; 5962306a36Sopenharmony_ci enum ena_cmd_status status; 6062306a36Sopenharmony_ci /* status from the device */ 6162306a36Sopenharmony_ci u8 comp_status; 6262306a36Sopenharmony_ci u8 cmd_opcode; 6362306a36Sopenharmony_ci bool occupied; 6462306a36Sopenharmony_ci}; 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_cistruct ena_com_stats_ctx { 6762306a36Sopenharmony_ci struct ena_admin_aq_get_stats_cmd get_cmd; 6862306a36Sopenharmony_ci struct ena_admin_acq_get_stats_resp get_resp; 6962306a36Sopenharmony_ci}; 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_cistatic int ena_com_mem_addr_set(struct ena_com_dev *ena_dev, 7262306a36Sopenharmony_ci struct ena_common_mem_addr *ena_addr, 7362306a36Sopenharmony_ci dma_addr_t addr) 7462306a36Sopenharmony_ci{ 7562306a36Sopenharmony_ci if ((addr & GENMASK_ULL(ena_dev->dma_addr_bits - 1, 0)) != addr) { 7662306a36Sopenharmony_ci netdev_err(ena_dev->net_device, 7762306a36Sopenharmony_ci "DMA address has more bits that the device supports\n"); 7862306a36Sopenharmony_ci return -EINVAL; 7962306a36Sopenharmony_ci } 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_ci ena_addr->mem_addr_low = lower_32_bits(addr); 8262306a36Sopenharmony_ci ena_addr->mem_addr_high = (u16)upper_32_bits(addr); 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_ci return 0; 8562306a36Sopenharmony_ci} 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_cistatic int ena_com_admin_init_sq(struct ena_com_admin_queue *admin_queue) 8862306a36Sopenharmony_ci{ 8962306a36Sopenharmony_ci struct ena_com_dev *ena_dev = admin_queue->ena_dev; 9062306a36Sopenharmony_ci struct ena_com_admin_sq *sq = &admin_queue->sq; 9162306a36Sopenharmony_ci u16 size = ADMIN_SQ_SIZE(admin_queue->q_depth); 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_ci sq->entries = dma_alloc_coherent(admin_queue->q_dmadev, size, 9462306a36Sopenharmony_ci &sq->dma_addr, GFP_KERNEL); 9562306a36Sopenharmony_ci 9662306a36Sopenharmony_ci if (!sq->entries) { 9762306a36Sopenharmony_ci netdev_err(ena_dev->net_device, "Memory allocation failed\n"); 9862306a36Sopenharmony_ci return -ENOMEM; 9962306a36Sopenharmony_ci } 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_ci sq->head = 0; 10262306a36Sopenharmony_ci sq->tail = 0; 10362306a36Sopenharmony_ci sq->phase = 1; 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_ci sq->db_addr = NULL; 10662306a36Sopenharmony_ci 10762306a36Sopenharmony_ci return 0; 10862306a36Sopenharmony_ci} 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_cistatic int ena_com_admin_init_cq(struct ena_com_admin_queue *admin_queue) 11162306a36Sopenharmony_ci{ 11262306a36Sopenharmony_ci struct ena_com_dev *ena_dev = admin_queue->ena_dev; 11362306a36Sopenharmony_ci struct ena_com_admin_cq *cq = &admin_queue->cq; 11462306a36Sopenharmony_ci u16 size = ADMIN_CQ_SIZE(admin_queue->q_depth); 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_ci cq->entries = dma_alloc_coherent(admin_queue->q_dmadev, size, 11762306a36Sopenharmony_ci &cq->dma_addr, GFP_KERNEL); 11862306a36Sopenharmony_ci 11962306a36Sopenharmony_ci if (!cq->entries) { 12062306a36Sopenharmony_ci netdev_err(ena_dev->net_device, "Memory allocation failed\n"); 12162306a36Sopenharmony_ci return -ENOMEM; 12262306a36Sopenharmony_ci } 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_ci cq->head = 0; 12562306a36Sopenharmony_ci cq->phase = 1; 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_ci return 0; 12862306a36Sopenharmony_ci} 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_cistatic int ena_com_admin_init_aenq(struct ena_com_dev *ena_dev, 13162306a36Sopenharmony_ci struct ena_aenq_handlers *aenq_handlers) 13262306a36Sopenharmony_ci{ 13362306a36Sopenharmony_ci struct ena_com_aenq *aenq = &ena_dev->aenq; 13462306a36Sopenharmony_ci u32 addr_low, addr_high, aenq_caps; 13562306a36Sopenharmony_ci u16 size; 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_ci ena_dev->aenq.q_depth = ENA_ASYNC_QUEUE_DEPTH; 13862306a36Sopenharmony_ci size = ADMIN_AENQ_SIZE(ENA_ASYNC_QUEUE_DEPTH); 13962306a36Sopenharmony_ci aenq->entries = dma_alloc_coherent(ena_dev->dmadev, size, 14062306a36Sopenharmony_ci &aenq->dma_addr, GFP_KERNEL); 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_ci if (!aenq->entries) { 14362306a36Sopenharmony_ci netdev_err(ena_dev->net_device, "Memory allocation failed\n"); 14462306a36Sopenharmony_ci return -ENOMEM; 14562306a36Sopenharmony_ci } 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_ci aenq->head = aenq->q_depth; 14862306a36Sopenharmony_ci aenq->phase = 1; 14962306a36Sopenharmony_ci 15062306a36Sopenharmony_ci addr_low = ENA_DMA_ADDR_TO_UINT32_LOW(aenq->dma_addr); 15162306a36Sopenharmony_ci addr_high = ENA_DMA_ADDR_TO_UINT32_HIGH(aenq->dma_addr); 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_ci writel(addr_low, ena_dev->reg_bar + ENA_REGS_AENQ_BASE_LO_OFF); 15462306a36Sopenharmony_ci writel(addr_high, ena_dev->reg_bar + ENA_REGS_AENQ_BASE_HI_OFF); 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_ci aenq_caps = 0; 15762306a36Sopenharmony_ci aenq_caps |= ena_dev->aenq.q_depth & ENA_REGS_AENQ_CAPS_AENQ_DEPTH_MASK; 15862306a36Sopenharmony_ci aenq_caps |= (sizeof(struct ena_admin_aenq_entry) 15962306a36Sopenharmony_ci << ENA_REGS_AENQ_CAPS_AENQ_ENTRY_SIZE_SHIFT) & 16062306a36Sopenharmony_ci ENA_REGS_AENQ_CAPS_AENQ_ENTRY_SIZE_MASK; 16162306a36Sopenharmony_ci writel(aenq_caps, ena_dev->reg_bar + ENA_REGS_AENQ_CAPS_OFF); 16262306a36Sopenharmony_ci 16362306a36Sopenharmony_ci if (unlikely(!aenq_handlers)) { 16462306a36Sopenharmony_ci netdev_err(ena_dev->net_device, 16562306a36Sopenharmony_ci "AENQ handlers pointer is NULL\n"); 16662306a36Sopenharmony_ci return -EINVAL; 16762306a36Sopenharmony_ci } 16862306a36Sopenharmony_ci 16962306a36Sopenharmony_ci aenq->aenq_handlers = aenq_handlers; 17062306a36Sopenharmony_ci 17162306a36Sopenharmony_ci return 0; 17262306a36Sopenharmony_ci} 17362306a36Sopenharmony_ci 17462306a36Sopenharmony_cistatic void comp_ctxt_release(struct ena_com_admin_queue *queue, 17562306a36Sopenharmony_ci struct ena_comp_ctx *comp_ctx) 17662306a36Sopenharmony_ci{ 17762306a36Sopenharmony_ci comp_ctx->occupied = false; 17862306a36Sopenharmony_ci atomic_dec(&queue->outstanding_cmds); 17962306a36Sopenharmony_ci} 18062306a36Sopenharmony_ci 18162306a36Sopenharmony_cistatic struct ena_comp_ctx *get_comp_ctxt(struct ena_com_admin_queue *admin_queue, 18262306a36Sopenharmony_ci u16 command_id, bool capture) 18362306a36Sopenharmony_ci{ 18462306a36Sopenharmony_ci if (unlikely(command_id >= admin_queue->q_depth)) { 18562306a36Sopenharmony_ci netdev_err(admin_queue->ena_dev->net_device, 18662306a36Sopenharmony_ci "Command id is larger than the queue size. cmd_id: %u queue size %d\n", 18762306a36Sopenharmony_ci command_id, admin_queue->q_depth); 18862306a36Sopenharmony_ci return NULL; 18962306a36Sopenharmony_ci } 19062306a36Sopenharmony_ci 19162306a36Sopenharmony_ci if (unlikely(!admin_queue->comp_ctx)) { 19262306a36Sopenharmony_ci netdev_err(admin_queue->ena_dev->net_device, 19362306a36Sopenharmony_ci "Completion context is NULL\n"); 19462306a36Sopenharmony_ci return NULL; 19562306a36Sopenharmony_ci } 19662306a36Sopenharmony_ci 19762306a36Sopenharmony_ci if (unlikely(admin_queue->comp_ctx[command_id].occupied && capture)) { 19862306a36Sopenharmony_ci netdev_err(admin_queue->ena_dev->net_device, 19962306a36Sopenharmony_ci "Completion context is occupied\n"); 20062306a36Sopenharmony_ci return NULL; 20162306a36Sopenharmony_ci } 20262306a36Sopenharmony_ci 20362306a36Sopenharmony_ci if (capture) { 20462306a36Sopenharmony_ci atomic_inc(&admin_queue->outstanding_cmds); 20562306a36Sopenharmony_ci admin_queue->comp_ctx[command_id].occupied = true; 20662306a36Sopenharmony_ci } 20762306a36Sopenharmony_ci 20862306a36Sopenharmony_ci return &admin_queue->comp_ctx[command_id]; 20962306a36Sopenharmony_ci} 21062306a36Sopenharmony_ci 21162306a36Sopenharmony_cistatic struct ena_comp_ctx *__ena_com_submit_admin_cmd(struct ena_com_admin_queue *admin_queue, 21262306a36Sopenharmony_ci struct ena_admin_aq_entry *cmd, 21362306a36Sopenharmony_ci size_t cmd_size_in_bytes, 21462306a36Sopenharmony_ci struct ena_admin_acq_entry *comp, 21562306a36Sopenharmony_ci size_t comp_size_in_bytes) 21662306a36Sopenharmony_ci{ 21762306a36Sopenharmony_ci struct ena_comp_ctx *comp_ctx; 21862306a36Sopenharmony_ci u16 tail_masked, cmd_id; 21962306a36Sopenharmony_ci u16 queue_size_mask; 22062306a36Sopenharmony_ci u16 cnt; 22162306a36Sopenharmony_ci 22262306a36Sopenharmony_ci queue_size_mask = admin_queue->q_depth - 1; 22362306a36Sopenharmony_ci 22462306a36Sopenharmony_ci tail_masked = admin_queue->sq.tail & queue_size_mask; 22562306a36Sopenharmony_ci 22662306a36Sopenharmony_ci /* In case of queue FULL */ 22762306a36Sopenharmony_ci cnt = (u16)atomic_read(&admin_queue->outstanding_cmds); 22862306a36Sopenharmony_ci if (cnt >= admin_queue->q_depth) { 22962306a36Sopenharmony_ci netdev_dbg(admin_queue->ena_dev->net_device, 23062306a36Sopenharmony_ci "Admin queue is full.\n"); 23162306a36Sopenharmony_ci admin_queue->stats.out_of_space++; 23262306a36Sopenharmony_ci return ERR_PTR(-ENOSPC); 23362306a36Sopenharmony_ci } 23462306a36Sopenharmony_ci 23562306a36Sopenharmony_ci cmd_id = admin_queue->curr_cmd_id; 23662306a36Sopenharmony_ci 23762306a36Sopenharmony_ci cmd->aq_common_descriptor.flags |= admin_queue->sq.phase & 23862306a36Sopenharmony_ci ENA_ADMIN_AQ_COMMON_DESC_PHASE_MASK; 23962306a36Sopenharmony_ci 24062306a36Sopenharmony_ci cmd->aq_common_descriptor.command_id |= cmd_id & 24162306a36Sopenharmony_ci ENA_ADMIN_AQ_COMMON_DESC_COMMAND_ID_MASK; 24262306a36Sopenharmony_ci 24362306a36Sopenharmony_ci comp_ctx = get_comp_ctxt(admin_queue, cmd_id, true); 24462306a36Sopenharmony_ci if (unlikely(!comp_ctx)) 24562306a36Sopenharmony_ci return ERR_PTR(-EINVAL); 24662306a36Sopenharmony_ci 24762306a36Sopenharmony_ci comp_ctx->status = ENA_CMD_SUBMITTED; 24862306a36Sopenharmony_ci comp_ctx->comp_size = (u32)comp_size_in_bytes; 24962306a36Sopenharmony_ci comp_ctx->user_cqe = comp; 25062306a36Sopenharmony_ci comp_ctx->cmd_opcode = cmd->aq_common_descriptor.opcode; 25162306a36Sopenharmony_ci 25262306a36Sopenharmony_ci reinit_completion(&comp_ctx->wait_event); 25362306a36Sopenharmony_ci 25462306a36Sopenharmony_ci memcpy(&admin_queue->sq.entries[tail_masked], cmd, cmd_size_in_bytes); 25562306a36Sopenharmony_ci 25662306a36Sopenharmony_ci admin_queue->curr_cmd_id = (admin_queue->curr_cmd_id + 1) & 25762306a36Sopenharmony_ci queue_size_mask; 25862306a36Sopenharmony_ci 25962306a36Sopenharmony_ci admin_queue->sq.tail++; 26062306a36Sopenharmony_ci admin_queue->stats.submitted_cmd++; 26162306a36Sopenharmony_ci 26262306a36Sopenharmony_ci if (unlikely((admin_queue->sq.tail & queue_size_mask) == 0)) 26362306a36Sopenharmony_ci admin_queue->sq.phase = !admin_queue->sq.phase; 26462306a36Sopenharmony_ci 26562306a36Sopenharmony_ci writel(admin_queue->sq.tail, admin_queue->sq.db_addr); 26662306a36Sopenharmony_ci 26762306a36Sopenharmony_ci return comp_ctx; 26862306a36Sopenharmony_ci} 26962306a36Sopenharmony_ci 27062306a36Sopenharmony_cistatic int ena_com_init_comp_ctxt(struct ena_com_admin_queue *admin_queue) 27162306a36Sopenharmony_ci{ 27262306a36Sopenharmony_ci struct ena_com_dev *ena_dev = admin_queue->ena_dev; 27362306a36Sopenharmony_ci size_t size = admin_queue->q_depth * sizeof(struct ena_comp_ctx); 27462306a36Sopenharmony_ci struct ena_comp_ctx *comp_ctx; 27562306a36Sopenharmony_ci u16 i; 27662306a36Sopenharmony_ci 27762306a36Sopenharmony_ci admin_queue->comp_ctx = 27862306a36Sopenharmony_ci devm_kzalloc(admin_queue->q_dmadev, size, GFP_KERNEL); 27962306a36Sopenharmony_ci if (unlikely(!admin_queue->comp_ctx)) { 28062306a36Sopenharmony_ci netdev_err(ena_dev->net_device, "Memory allocation failed\n"); 28162306a36Sopenharmony_ci return -ENOMEM; 28262306a36Sopenharmony_ci } 28362306a36Sopenharmony_ci 28462306a36Sopenharmony_ci for (i = 0; i < admin_queue->q_depth; i++) { 28562306a36Sopenharmony_ci comp_ctx = get_comp_ctxt(admin_queue, i, false); 28662306a36Sopenharmony_ci if (comp_ctx) 28762306a36Sopenharmony_ci init_completion(&comp_ctx->wait_event); 28862306a36Sopenharmony_ci } 28962306a36Sopenharmony_ci 29062306a36Sopenharmony_ci return 0; 29162306a36Sopenharmony_ci} 29262306a36Sopenharmony_ci 29362306a36Sopenharmony_cistatic struct ena_comp_ctx *ena_com_submit_admin_cmd(struct ena_com_admin_queue *admin_queue, 29462306a36Sopenharmony_ci struct ena_admin_aq_entry *cmd, 29562306a36Sopenharmony_ci size_t cmd_size_in_bytes, 29662306a36Sopenharmony_ci struct ena_admin_acq_entry *comp, 29762306a36Sopenharmony_ci size_t comp_size_in_bytes) 29862306a36Sopenharmony_ci{ 29962306a36Sopenharmony_ci unsigned long flags = 0; 30062306a36Sopenharmony_ci struct ena_comp_ctx *comp_ctx; 30162306a36Sopenharmony_ci 30262306a36Sopenharmony_ci spin_lock_irqsave(&admin_queue->q_lock, flags); 30362306a36Sopenharmony_ci if (unlikely(!admin_queue->running_state)) { 30462306a36Sopenharmony_ci spin_unlock_irqrestore(&admin_queue->q_lock, flags); 30562306a36Sopenharmony_ci return ERR_PTR(-ENODEV); 30662306a36Sopenharmony_ci } 30762306a36Sopenharmony_ci comp_ctx = __ena_com_submit_admin_cmd(admin_queue, cmd, 30862306a36Sopenharmony_ci cmd_size_in_bytes, 30962306a36Sopenharmony_ci comp, 31062306a36Sopenharmony_ci comp_size_in_bytes); 31162306a36Sopenharmony_ci if (IS_ERR(comp_ctx)) 31262306a36Sopenharmony_ci admin_queue->running_state = false; 31362306a36Sopenharmony_ci spin_unlock_irqrestore(&admin_queue->q_lock, flags); 31462306a36Sopenharmony_ci 31562306a36Sopenharmony_ci return comp_ctx; 31662306a36Sopenharmony_ci} 31762306a36Sopenharmony_ci 31862306a36Sopenharmony_cistatic int ena_com_init_io_sq(struct ena_com_dev *ena_dev, 31962306a36Sopenharmony_ci struct ena_com_create_io_ctx *ctx, 32062306a36Sopenharmony_ci struct ena_com_io_sq *io_sq) 32162306a36Sopenharmony_ci{ 32262306a36Sopenharmony_ci size_t size; 32362306a36Sopenharmony_ci int dev_node = 0; 32462306a36Sopenharmony_ci 32562306a36Sopenharmony_ci memset(&io_sq->desc_addr, 0x0, sizeof(io_sq->desc_addr)); 32662306a36Sopenharmony_ci 32762306a36Sopenharmony_ci io_sq->dma_addr_bits = (u8)ena_dev->dma_addr_bits; 32862306a36Sopenharmony_ci io_sq->desc_entry_size = 32962306a36Sopenharmony_ci (io_sq->direction == ENA_COM_IO_QUEUE_DIRECTION_TX) ? 33062306a36Sopenharmony_ci sizeof(struct ena_eth_io_tx_desc) : 33162306a36Sopenharmony_ci sizeof(struct ena_eth_io_rx_desc); 33262306a36Sopenharmony_ci 33362306a36Sopenharmony_ci size = io_sq->desc_entry_size * io_sq->q_depth; 33462306a36Sopenharmony_ci 33562306a36Sopenharmony_ci if (io_sq->mem_queue_type == ENA_ADMIN_PLACEMENT_POLICY_HOST) { 33662306a36Sopenharmony_ci dev_node = dev_to_node(ena_dev->dmadev); 33762306a36Sopenharmony_ci set_dev_node(ena_dev->dmadev, ctx->numa_node); 33862306a36Sopenharmony_ci io_sq->desc_addr.virt_addr = 33962306a36Sopenharmony_ci dma_alloc_coherent(ena_dev->dmadev, size, 34062306a36Sopenharmony_ci &io_sq->desc_addr.phys_addr, 34162306a36Sopenharmony_ci GFP_KERNEL); 34262306a36Sopenharmony_ci set_dev_node(ena_dev->dmadev, dev_node); 34362306a36Sopenharmony_ci if (!io_sq->desc_addr.virt_addr) { 34462306a36Sopenharmony_ci io_sq->desc_addr.virt_addr = 34562306a36Sopenharmony_ci dma_alloc_coherent(ena_dev->dmadev, size, 34662306a36Sopenharmony_ci &io_sq->desc_addr.phys_addr, 34762306a36Sopenharmony_ci GFP_KERNEL); 34862306a36Sopenharmony_ci } 34962306a36Sopenharmony_ci 35062306a36Sopenharmony_ci if (!io_sq->desc_addr.virt_addr) { 35162306a36Sopenharmony_ci netdev_err(ena_dev->net_device, 35262306a36Sopenharmony_ci "Memory allocation failed\n"); 35362306a36Sopenharmony_ci return -ENOMEM; 35462306a36Sopenharmony_ci } 35562306a36Sopenharmony_ci } 35662306a36Sopenharmony_ci 35762306a36Sopenharmony_ci if (io_sq->mem_queue_type == ENA_ADMIN_PLACEMENT_POLICY_DEV) { 35862306a36Sopenharmony_ci /* Allocate bounce buffers */ 35962306a36Sopenharmony_ci io_sq->bounce_buf_ctrl.buffer_size = 36062306a36Sopenharmony_ci ena_dev->llq_info.desc_list_entry_size; 36162306a36Sopenharmony_ci io_sq->bounce_buf_ctrl.buffers_num = 36262306a36Sopenharmony_ci ENA_COM_BOUNCE_BUFFER_CNTRL_CNT; 36362306a36Sopenharmony_ci io_sq->bounce_buf_ctrl.next_to_use = 0; 36462306a36Sopenharmony_ci 36562306a36Sopenharmony_ci size = io_sq->bounce_buf_ctrl.buffer_size * 36662306a36Sopenharmony_ci io_sq->bounce_buf_ctrl.buffers_num; 36762306a36Sopenharmony_ci 36862306a36Sopenharmony_ci dev_node = dev_to_node(ena_dev->dmadev); 36962306a36Sopenharmony_ci set_dev_node(ena_dev->dmadev, ctx->numa_node); 37062306a36Sopenharmony_ci io_sq->bounce_buf_ctrl.base_buffer = 37162306a36Sopenharmony_ci devm_kzalloc(ena_dev->dmadev, size, GFP_KERNEL); 37262306a36Sopenharmony_ci set_dev_node(ena_dev->dmadev, dev_node); 37362306a36Sopenharmony_ci if (!io_sq->bounce_buf_ctrl.base_buffer) 37462306a36Sopenharmony_ci io_sq->bounce_buf_ctrl.base_buffer = 37562306a36Sopenharmony_ci devm_kzalloc(ena_dev->dmadev, size, GFP_KERNEL); 37662306a36Sopenharmony_ci 37762306a36Sopenharmony_ci if (!io_sq->bounce_buf_ctrl.base_buffer) { 37862306a36Sopenharmony_ci netdev_err(ena_dev->net_device, 37962306a36Sopenharmony_ci "Bounce buffer memory allocation failed\n"); 38062306a36Sopenharmony_ci return -ENOMEM; 38162306a36Sopenharmony_ci } 38262306a36Sopenharmony_ci 38362306a36Sopenharmony_ci memcpy(&io_sq->llq_info, &ena_dev->llq_info, 38462306a36Sopenharmony_ci sizeof(io_sq->llq_info)); 38562306a36Sopenharmony_ci 38662306a36Sopenharmony_ci /* Initiate the first bounce buffer */ 38762306a36Sopenharmony_ci io_sq->llq_buf_ctrl.curr_bounce_buf = 38862306a36Sopenharmony_ci ena_com_get_next_bounce_buffer(&io_sq->bounce_buf_ctrl); 38962306a36Sopenharmony_ci memset(io_sq->llq_buf_ctrl.curr_bounce_buf, 39062306a36Sopenharmony_ci 0x0, io_sq->llq_info.desc_list_entry_size); 39162306a36Sopenharmony_ci io_sq->llq_buf_ctrl.descs_left_in_line = 39262306a36Sopenharmony_ci io_sq->llq_info.descs_num_before_header; 39362306a36Sopenharmony_ci io_sq->disable_meta_caching = 39462306a36Sopenharmony_ci io_sq->llq_info.disable_meta_caching; 39562306a36Sopenharmony_ci 39662306a36Sopenharmony_ci if (io_sq->llq_info.max_entries_in_tx_burst > 0) 39762306a36Sopenharmony_ci io_sq->entries_in_tx_burst_left = 39862306a36Sopenharmony_ci io_sq->llq_info.max_entries_in_tx_burst; 39962306a36Sopenharmony_ci } 40062306a36Sopenharmony_ci 40162306a36Sopenharmony_ci io_sq->tail = 0; 40262306a36Sopenharmony_ci io_sq->next_to_comp = 0; 40362306a36Sopenharmony_ci io_sq->phase = 1; 40462306a36Sopenharmony_ci 40562306a36Sopenharmony_ci return 0; 40662306a36Sopenharmony_ci} 40762306a36Sopenharmony_ci 40862306a36Sopenharmony_cistatic int ena_com_init_io_cq(struct ena_com_dev *ena_dev, 40962306a36Sopenharmony_ci struct ena_com_create_io_ctx *ctx, 41062306a36Sopenharmony_ci struct ena_com_io_cq *io_cq) 41162306a36Sopenharmony_ci{ 41262306a36Sopenharmony_ci size_t size; 41362306a36Sopenharmony_ci int prev_node = 0; 41462306a36Sopenharmony_ci 41562306a36Sopenharmony_ci memset(&io_cq->cdesc_addr, 0x0, sizeof(io_cq->cdesc_addr)); 41662306a36Sopenharmony_ci 41762306a36Sopenharmony_ci /* Use the basic completion descriptor for Rx */ 41862306a36Sopenharmony_ci io_cq->cdesc_entry_size_in_bytes = 41962306a36Sopenharmony_ci (io_cq->direction == ENA_COM_IO_QUEUE_DIRECTION_TX) ? 42062306a36Sopenharmony_ci sizeof(struct ena_eth_io_tx_cdesc) : 42162306a36Sopenharmony_ci sizeof(struct ena_eth_io_rx_cdesc_base); 42262306a36Sopenharmony_ci 42362306a36Sopenharmony_ci size = io_cq->cdesc_entry_size_in_bytes * io_cq->q_depth; 42462306a36Sopenharmony_ci 42562306a36Sopenharmony_ci prev_node = dev_to_node(ena_dev->dmadev); 42662306a36Sopenharmony_ci set_dev_node(ena_dev->dmadev, ctx->numa_node); 42762306a36Sopenharmony_ci io_cq->cdesc_addr.virt_addr = 42862306a36Sopenharmony_ci dma_alloc_coherent(ena_dev->dmadev, size, 42962306a36Sopenharmony_ci &io_cq->cdesc_addr.phys_addr, GFP_KERNEL); 43062306a36Sopenharmony_ci set_dev_node(ena_dev->dmadev, prev_node); 43162306a36Sopenharmony_ci if (!io_cq->cdesc_addr.virt_addr) { 43262306a36Sopenharmony_ci io_cq->cdesc_addr.virt_addr = 43362306a36Sopenharmony_ci dma_alloc_coherent(ena_dev->dmadev, size, 43462306a36Sopenharmony_ci &io_cq->cdesc_addr.phys_addr, 43562306a36Sopenharmony_ci GFP_KERNEL); 43662306a36Sopenharmony_ci } 43762306a36Sopenharmony_ci 43862306a36Sopenharmony_ci if (!io_cq->cdesc_addr.virt_addr) { 43962306a36Sopenharmony_ci netdev_err(ena_dev->net_device, "Memory allocation failed\n"); 44062306a36Sopenharmony_ci return -ENOMEM; 44162306a36Sopenharmony_ci } 44262306a36Sopenharmony_ci 44362306a36Sopenharmony_ci io_cq->phase = 1; 44462306a36Sopenharmony_ci io_cq->head = 0; 44562306a36Sopenharmony_ci 44662306a36Sopenharmony_ci return 0; 44762306a36Sopenharmony_ci} 44862306a36Sopenharmony_ci 44962306a36Sopenharmony_cistatic void ena_com_handle_single_admin_completion(struct ena_com_admin_queue *admin_queue, 45062306a36Sopenharmony_ci struct ena_admin_acq_entry *cqe) 45162306a36Sopenharmony_ci{ 45262306a36Sopenharmony_ci struct ena_comp_ctx *comp_ctx; 45362306a36Sopenharmony_ci u16 cmd_id; 45462306a36Sopenharmony_ci 45562306a36Sopenharmony_ci cmd_id = cqe->acq_common_descriptor.command & 45662306a36Sopenharmony_ci ENA_ADMIN_ACQ_COMMON_DESC_COMMAND_ID_MASK; 45762306a36Sopenharmony_ci 45862306a36Sopenharmony_ci comp_ctx = get_comp_ctxt(admin_queue, cmd_id, false); 45962306a36Sopenharmony_ci if (unlikely(!comp_ctx)) { 46062306a36Sopenharmony_ci netdev_err(admin_queue->ena_dev->net_device, 46162306a36Sopenharmony_ci "comp_ctx is NULL. Changing the admin queue running state\n"); 46262306a36Sopenharmony_ci admin_queue->running_state = false; 46362306a36Sopenharmony_ci return; 46462306a36Sopenharmony_ci } 46562306a36Sopenharmony_ci 46662306a36Sopenharmony_ci comp_ctx->status = ENA_CMD_COMPLETED; 46762306a36Sopenharmony_ci comp_ctx->comp_status = cqe->acq_common_descriptor.status; 46862306a36Sopenharmony_ci 46962306a36Sopenharmony_ci if (comp_ctx->user_cqe) 47062306a36Sopenharmony_ci memcpy(comp_ctx->user_cqe, (void *)cqe, comp_ctx->comp_size); 47162306a36Sopenharmony_ci 47262306a36Sopenharmony_ci if (!admin_queue->polling) 47362306a36Sopenharmony_ci complete(&comp_ctx->wait_event); 47462306a36Sopenharmony_ci} 47562306a36Sopenharmony_ci 47662306a36Sopenharmony_cistatic void ena_com_handle_admin_completion(struct ena_com_admin_queue *admin_queue) 47762306a36Sopenharmony_ci{ 47862306a36Sopenharmony_ci struct ena_admin_acq_entry *cqe = NULL; 47962306a36Sopenharmony_ci u16 comp_num = 0; 48062306a36Sopenharmony_ci u16 head_masked; 48162306a36Sopenharmony_ci u8 phase; 48262306a36Sopenharmony_ci 48362306a36Sopenharmony_ci head_masked = admin_queue->cq.head & (admin_queue->q_depth - 1); 48462306a36Sopenharmony_ci phase = admin_queue->cq.phase; 48562306a36Sopenharmony_ci 48662306a36Sopenharmony_ci cqe = &admin_queue->cq.entries[head_masked]; 48762306a36Sopenharmony_ci 48862306a36Sopenharmony_ci /* Go over all the completions */ 48962306a36Sopenharmony_ci while ((READ_ONCE(cqe->acq_common_descriptor.flags) & 49062306a36Sopenharmony_ci ENA_ADMIN_ACQ_COMMON_DESC_PHASE_MASK) == phase) { 49162306a36Sopenharmony_ci /* Do not read the rest of the completion entry before the 49262306a36Sopenharmony_ci * phase bit was validated 49362306a36Sopenharmony_ci */ 49462306a36Sopenharmony_ci dma_rmb(); 49562306a36Sopenharmony_ci ena_com_handle_single_admin_completion(admin_queue, cqe); 49662306a36Sopenharmony_ci 49762306a36Sopenharmony_ci head_masked++; 49862306a36Sopenharmony_ci comp_num++; 49962306a36Sopenharmony_ci if (unlikely(head_masked == admin_queue->q_depth)) { 50062306a36Sopenharmony_ci head_masked = 0; 50162306a36Sopenharmony_ci phase = !phase; 50262306a36Sopenharmony_ci } 50362306a36Sopenharmony_ci 50462306a36Sopenharmony_ci cqe = &admin_queue->cq.entries[head_masked]; 50562306a36Sopenharmony_ci } 50662306a36Sopenharmony_ci 50762306a36Sopenharmony_ci admin_queue->cq.head += comp_num; 50862306a36Sopenharmony_ci admin_queue->cq.phase = phase; 50962306a36Sopenharmony_ci admin_queue->sq.head += comp_num; 51062306a36Sopenharmony_ci admin_queue->stats.completed_cmd += comp_num; 51162306a36Sopenharmony_ci} 51262306a36Sopenharmony_ci 51362306a36Sopenharmony_cistatic int ena_com_comp_status_to_errno(struct ena_com_admin_queue *admin_queue, 51462306a36Sopenharmony_ci u8 comp_status) 51562306a36Sopenharmony_ci{ 51662306a36Sopenharmony_ci if (unlikely(comp_status != 0)) 51762306a36Sopenharmony_ci netdev_err(admin_queue->ena_dev->net_device, 51862306a36Sopenharmony_ci "Admin command failed[%u]\n", comp_status); 51962306a36Sopenharmony_ci 52062306a36Sopenharmony_ci switch (comp_status) { 52162306a36Sopenharmony_ci case ENA_ADMIN_SUCCESS: 52262306a36Sopenharmony_ci return 0; 52362306a36Sopenharmony_ci case ENA_ADMIN_RESOURCE_ALLOCATION_FAILURE: 52462306a36Sopenharmony_ci return -ENOMEM; 52562306a36Sopenharmony_ci case ENA_ADMIN_UNSUPPORTED_OPCODE: 52662306a36Sopenharmony_ci return -EOPNOTSUPP; 52762306a36Sopenharmony_ci case ENA_ADMIN_BAD_OPCODE: 52862306a36Sopenharmony_ci case ENA_ADMIN_MALFORMED_REQUEST: 52962306a36Sopenharmony_ci case ENA_ADMIN_ILLEGAL_PARAMETER: 53062306a36Sopenharmony_ci case ENA_ADMIN_UNKNOWN_ERROR: 53162306a36Sopenharmony_ci return -EINVAL; 53262306a36Sopenharmony_ci case ENA_ADMIN_RESOURCE_BUSY: 53362306a36Sopenharmony_ci return -EAGAIN; 53462306a36Sopenharmony_ci } 53562306a36Sopenharmony_ci 53662306a36Sopenharmony_ci return -EINVAL; 53762306a36Sopenharmony_ci} 53862306a36Sopenharmony_ci 53962306a36Sopenharmony_cistatic void ena_delay_exponential_backoff_us(u32 exp, u32 delay_us) 54062306a36Sopenharmony_ci{ 54162306a36Sopenharmony_ci exp = min_t(u32, exp, ENA_MAX_BACKOFF_DELAY_EXP); 54262306a36Sopenharmony_ci delay_us = max_t(u32, ENA_MIN_ADMIN_POLL_US, delay_us); 54362306a36Sopenharmony_ci delay_us = min_t(u32, delay_us * (1U << exp), ENA_MAX_ADMIN_POLL_US); 54462306a36Sopenharmony_ci usleep_range(delay_us, 2 * delay_us); 54562306a36Sopenharmony_ci} 54662306a36Sopenharmony_ci 54762306a36Sopenharmony_cistatic int ena_com_wait_and_process_admin_cq_polling(struct ena_comp_ctx *comp_ctx, 54862306a36Sopenharmony_ci struct ena_com_admin_queue *admin_queue) 54962306a36Sopenharmony_ci{ 55062306a36Sopenharmony_ci unsigned long flags = 0; 55162306a36Sopenharmony_ci unsigned long timeout; 55262306a36Sopenharmony_ci int ret; 55362306a36Sopenharmony_ci u32 exp = 0; 55462306a36Sopenharmony_ci 55562306a36Sopenharmony_ci timeout = jiffies + usecs_to_jiffies(admin_queue->completion_timeout); 55662306a36Sopenharmony_ci 55762306a36Sopenharmony_ci while (1) { 55862306a36Sopenharmony_ci spin_lock_irqsave(&admin_queue->q_lock, flags); 55962306a36Sopenharmony_ci ena_com_handle_admin_completion(admin_queue); 56062306a36Sopenharmony_ci spin_unlock_irqrestore(&admin_queue->q_lock, flags); 56162306a36Sopenharmony_ci 56262306a36Sopenharmony_ci if (comp_ctx->status != ENA_CMD_SUBMITTED) 56362306a36Sopenharmony_ci break; 56462306a36Sopenharmony_ci 56562306a36Sopenharmony_ci if (time_is_before_jiffies(timeout)) { 56662306a36Sopenharmony_ci netdev_err(admin_queue->ena_dev->net_device, 56762306a36Sopenharmony_ci "Wait for completion (polling) timeout\n"); 56862306a36Sopenharmony_ci /* ENA didn't have any completion */ 56962306a36Sopenharmony_ci spin_lock_irqsave(&admin_queue->q_lock, flags); 57062306a36Sopenharmony_ci admin_queue->stats.no_completion++; 57162306a36Sopenharmony_ci admin_queue->running_state = false; 57262306a36Sopenharmony_ci spin_unlock_irqrestore(&admin_queue->q_lock, flags); 57362306a36Sopenharmony_ci 57462306a36Sopenharmony_ci ret = -ETIME; 57562306a36Sopenharmony_ci goto err; 57662306a36Sopenharmony_ci } 57762306a36Sopenharmony_ci 57862306a36Sopenharmony_ci ena_delay_exponential_backoff_us(exp++, 57962306a36Sopenharmony_ci admin_queue->ena_dev->ena_min_poll_delay_us); 58062306a36Sopenharmony_ci } 58162306a36Sopenharmony_ci 58262306a36Sopenharmony_ci if (unlikely(comp_ctx->status == ENA_CMD_ABORTED)) { 58362306a36Sopenharmony_ci netdev_err(admin_queue->ena_dev->net_device, 58462306a36Sopenharmony_ci "Command was aborted\n"); 58562306a36Sopenharmony_ci spin_lock_irqsave(&admin_queue->q_lock, flags); 58662306a36Sopenharmony_ci admin_queue->stats.aborted_cmd++; 58762306a36Sopenharmony_ci spin_unlock_irqrestore(&admin_queue->q_lock, flags); 58862306a36Sopenharmony_ci ret = -ENODEV; 58962306a36Sopenharmony_ci goto err; 59062306a36Sopenharmony_ci } 59162306a36Sopenharmony_ci 59262306a36Sopenharmony_ci WARN(comp_ctx->status != ENA_CMD_COMPLETED, "Invalid comp status %d\n", 59362306a36Sopenharmony_ci comp_ctx->status); 59462306a36Sopenharmony_ci 59562306a36Sopenharmony_ci ret = ena_com_comp_status_to_errno(admin_queue, comp_ctx->comp_status); 59662306a36Sopenharmony_cierr: 59762306a36Sopenharmony_ci comp_ctxt_release(admin_queue, comp_ctx); 59862306a36Sopenharmony_ci return ret; 59962306a36Sopenharmony_ci} 60062306a36Sopenharmony_ci 60162306a36Sopenharmony_ci/* 60262306a36Sopenharmony_ci * Set the LLQ configurations of the firmware 60362306a36Sopenharmony_ci * 60462306a36Sopenharmony_ci * The driver provides only the enabled feature values to the device, 60562306a36Sopenharmony_ci * which in turn, checks if they are supported. 60662306a36Sopenharmony_ci */ 60762306a36Sopenharmony_cistatic int ena_com_set_llq(struct ena_com_dev *ena_dev) 60862306a36Sopenharmony_ci{ 60962306a36Sopenharmony_ci struct ena_com_admin_queue *admin_queue; 61062306a36Sopenharmony_ci struct ena_admin_set_feat_cmd cmd; 61162306a36Sopenharmony_ci struct ena_admin_set_feat_resp resp; 61262306a36Sopenharmony_ci struct ena_com_llq_info *llq_info = &ena_dev->llq_info; 61362306a36Sopenharmony_ci int ret; 61462306a36Sopenharmony_ci 61562306a36Sopenharmony_ci memset(&cmd, 0x0, sizeof(cmd)); 61662306a36Sopenharmony_ci admin_queue = &ena_dev->admin_queue; 61762306a36Sopenharmony_ci 61862306a36Sopenharmony_ci cmd.aq_common_descriptor.opcode = ENA_ADMIN_SET_FEATURE; 61962306a36Sopenharmony_ci cmd.feat_common.feature_id = ENA_ADMIN_LLQ; 62062306a36Sopenharmony_ci 62162306a36Sopenharmony_ci cmd.u.llq.header_location_ctrl_enabled = llq_info->header_location_ctrl; 62262306a36Sopenharmony_ci cmd.u.llq.entry_size_ctrl_enabled = llq_info->desc_list_entry_size_ctrl; 62362306a36Sopenharmony_ci cmd.u.llq.desc_num_before_header_enabled = llq_info->descs_num_before_header; 62462306a36Sopenharmony_ci cmd.u.llq.descriptors_stride_ctrl_enabled = llq_info->desc_stride_ctrl; 62562306a36Sopenharmony_ci 62662306a36Sopenharmony_ci cmd.u.llq.accel_mode.u.set.enabled_flags = 62762306a36Sopenharmony_ci BIT(ENA_ADMIN_DISABLE_META_CACHING) | 62862306a36Sopenharmony_ci BIT(ENA_ADMIN_LIMIT_TX_BURST); 62962306a36Sopenharmony_ci 63062306a36Sopenharmony_ci ret = ena_com_execute_admin_command(admin_queue, 63162306a36Sopenharmony_ci (struct ena_admin_aq_entry *)&cmd, 63262306a36Sopenharmony_ci sizeof(cmd), 63362306a36Sopenharmony_ci (struct ena_admin_acq_entry *)&resp, 63462306a36Sopenharmony_ci sizeof(resp)); 63562306a36Sopenharmony_ci 63662306a36Sopenharmony_ci if (unlikely(ret)) 63762306a36Sopenharmony_ci netdev_err(ena_dev->net_device, 63862306a36Sopenharmony_ci "Failed to set LLQ configurations: %d\n", ret); 63962306a36Sopenharmony_ci 64062306a36Sopenharmony_ci return ret; 64162306a36Sopenharmony_ci} 64262306a36Sopenharmony_ci 64362306a36Sopenharmony_cistatic int ena_com_config_llq_info(struct ena_com_dev *ena_dev, 64462306a36Sopenharmony_ci struct ena_admin_feature_llq_desc *llq_features, 64562306a36Sopenharmony_ci struct ena_llq_configurations *llq_default_cfg) 64662306a36Sopenharmony_ci{ 64762306a36Sopenharmony_ci struct ena_com_llq_info *llq_info = &ena_dev->llq_info; 64862306a36Sopenharmony_ci struct ena_admin_accel_mode_get llq_accel_mode_get; 64962306a36Sopenharmony_ci u16 supported_feat; 65062306a36Sopenharmony_ci int rc; 65162306a36Sopenharmony_ci 65262306a36Sopenharmony_ci memset(llq_info, 0, sizeof(*llq_info)); 65362306a36Sopenharmony_ci 65462306a36Sopenharmony_ci supported_feat = llq_features->header_location_ctrl_supported; 65562306a36Sopenharmony_ci 65662306a36Sopenharmony_ci if (likely(supported_feat & llq_default_cfg->llq_header_location)) { 65762306a36Sopenharmony_ci llq_info->header_location_ctrl = 65862306a36Sopenharmony_ci llq_default_cfg->llq_header_location; 65962306a36Sopenharmony_ci } else { 66062306a36Sopenharmony_ci netdev_err(ena_dev->net_device, 66162306a36Sopenharmony_ci "Invalid header location control, supported: 0x%x\n", 66262306a36Sopenharmony_ci supported_feat); 66362306a36Sopenharmony_ci return -EINVAL; 66462306a36Sopenharmony_ci } 66562306a36Sopenharmony_ci 66662306a36Sopenharmony_ci if (likely(llq_info->header_location_ctrl == ENA_ADMIN_INLINE_HEADER)) { 66762306a36Sopenharmony_ci supported_feat = llq_features->descriptors_stride_ctrl_supported; 66862306a36Sopenharmony_ci if (likely(supported_feat & llq_default_cfg->llq_stride_ctrl)) { 66962306a36Sopenharmony_ci llq_info->desc_stride_ctrl = llq_default_cfg->llq_stride_ctrl; 67062306a36Sopenharmony_ci } else { 67162306a36Sopenharmony_ci if (supported_feat & ENA_ADMIN_MULTIPLE_DESCS_PER_ENTRY) { 67262306a36Sopenharmony_ci llq_info->desc_stride_ctrl = ENA_ADMIN_MULTIPLE_DESCS_PER_ENTRY; 67362306a36Sopenharmony_ci } else if (supported_feat & ENA_ADMIN_SINGLE_DESC_PER_ENTRY) { 67462306a36Sopenharmony_ci llq_info->desc_stride_ctrl = ENA_ADMIN_SINGLE_DESC_PER_ENTRY; 67562306a36Sopenharmony_ci } else { 67662306a36Sopenharmony_ci netdev_err(ena_dev->net_device, 67762306a36Sopenharmony_ci "Invalid desc_stride_ctrl, supported: 0x%x\n", 67862306a36Sopenharmony_ci supported_feat); 67962306a36Sopenharmony_ci return -EINVAL; 68062306a36Sopenharmony_ci } 68162306a36Sopenharmony_ci 68262306a36Sopenharmony_ci netdev_err(ena_dev->net_device, 68362306a36Sopenharmony_ci "Default llq stride ctrl is not supported, performing fallback, default: 0x%x, supported: 0x%x, used: 0x%x\n", 68462306a36Sopenharmony_ci llq_default_cfg->llq_stride_ctrl, 68562306a36Sopenharmony_ci supported_feat, llq_info->desc_stride_ctrl); 68662306a36Sopenharmony_ci } 68762306a36Sopenharmony_ci } else { 68862306a36Sopenharmony_ci llq_info->desc_stride_ctrl = 0; 68962306a36Sopenharmony_ci } 69062306a36Sopenharmony_ci 69162306a36Sopenharmony_ci supported_feat = llq_features->entry_size_ctrl_supported; 69262306a36Sopenharmony_ci if (likely(supported_feat & llq_default_cfg->llq_ring_entry_size)) { 69362306a36Sopenharmony_ci llq_info->desc_list_entry_size_ctrl = llq_default_cfg->llq_ring_entry_size; 69462306a36Sopenharmony_ci llq_info->desc_list_entry_size = llq_default_cfg->llq_ring_entry_size_value; 69562306a36Sopenharmony_ci } else { 69662306a36Sopenharmony_ci if (supported_feat & ENA_ADMIN_LIST_ENTRY_SIZE_128B) { 69762306a36Sopenharmony_ci llq_info->desc_list_entry_size_ctrl = ENA_ADMIN_LIST_ENTRY_SIZE_128B; 69862306a36Sopenharmony_ci llq_info->desc_list_entry_size = 128; 69962306a36Sopenharmony_ci } else if (supported_feat & ENA_ADMIN_LIST_ENTRY_SIZE_192B) { 70062306a36Sopenharmony_ci llq_info->desc_list_entry_size_ctrl = ENA_ADMIN_LIST_ENTRY_SIZE_192B; 70162306a36Sopenharmony_ci llq_info->desc_list_entry_size = 192; 70262306a36Sopenharmony_ci } else if (supported_feat & ENA_ADMIN_LIST_ENTRY_SIZE_256B) { 70362306a36Sopenharmony_ci llq_info->desc_list_entry_size_ctrl = ENA_ADMIN_LIST_ENTRY_SIZE_256B; 70462306a36Sopenharmony_ci llq_info->desc_list_entry_size = 256; 70562306a36Sopenharmony_ci } else { 70662306a36Sopenharmony_ci netdev_err(ena_dev->net_device, 70762306a36Sopenharmony_ci "Invalid entry_size_ctrl, supported: 0x%x\n", 70862306a36Sopenharmony_ci supported_feat); 70962306a36Sopenharmony_ci return -EINVAL; 71062306a36Sopenharmony_ci } 71162306a36Sopenharmony_ci 71262306a36Sopenharmony_ci netdev_err(ena_dev->net_device, 71362306a36Sopenharmony_ci "Default llq ring entry size is not supported, performing fallback, default: 0x%x, supported: 0x%x, used: 0x%x\n", 71462306a36Sopenharmony_ci llq_default_cfg->llq_ring_entry_size, supported_feat, 71562306a36Sopenharmony_ci llq_info->desc_list_entry_size); 71662306a36Sopenharmony_ci } 71762306a36Sopenharmony_ci if (unlikely(llq_info->desc_list_entry_size & 0x7)) { 71862306a36Sopenharmony_ci /* The desc list entry size should be whole multiply of 8 71962306a36Sopenharmony_ci * This requirement comes from __iowrite64_copy() 72062306a36Sopenharmony_ci */ 72162306a36Sopenharmony_ci netdev_err(ena_dev->net_device, "Illegal entry size %d\n", 72262306a36Sopenharmony_ci llq_info->desc_list_entry_size); 72362306a36Sopenharmony_ci return -EINVAL; 72462306a36Sopenharmony_ci } 72562306a36Sopenharmony_ci 72662306a36Sopenharmony_ci if (llq_info->desc_stride_ctrl == ENA_ADMIN_MULTIPLE_DESCS_PER_ENTRY) 72762306a36Sopenharmony_ci llq_info->descs_per_entry = llq_info->desc_list_entry_size / 72862306a36Sopenharmony_ci sizeof(struct ena_eth_io_tx_desc); 72962306a36Sopenharmony_ci else 73062306a36Sopenharmony_ci llq_info->descs_per_entry = 1; 73162306a36Sopenharmony_ci 73262306a36Sopenharmony_ci supported_feat = llq_features->desc_num_before_header_supported; 73362306a36Sopenharmony_ci if (likely(supported_feat & llq_default_cfg->llq_num_decs_before_header)) { 73462306a36Sopenharmony_ci llq_info->descs_num_before_header = llq_default_cfg->llq_num_decs_before_header; 73562306a36Sopenharmony_ci } else { 73662306a36Sopenharmony_ci if (supported_feat & ENA_ADMIN_LLQ_NUM_DESCS_BEFORE_HEADER_2) { 73762306a36Sopenharmony_ci llq_info->descs_num_before_header = ENA_ADMIN_LLQ_NUM_DESCS_BEFORE_HEADER_2; 73862306a36Sopenharmony_ci } else if (supported_feat & ENA_ADMIN_LLQ_NUM_DESCS_BEFORE_HEADER_1) { 73962306a36Sopenharmony_ci llq_info->descs_num_before_header = ENA_ADMIN_LLQ_NUM_DESCS_BEFORE_HEADER_1; 74062306a36Sopenharmony_ci } else if (supported_feat & ENA_ADMIN_LLQ_NUM_DESCS_BEFORE_HEADER_4) { 74162306a36Sopenharmony_ci llq_info->descs_num_before_header = ENA_ADMIN_LLQ_NUM_DESCS_BEFORE_HEADER_4; 74262306a36Sopenharmony_ci } else if (supported_feat & ENA_ADMIN_LLQ_NUM_DESCS_BEFORE_HEADER_8) { 74362306a36Sopenharmony_ci llq_info->descs_num_before_header = ENA_ADMIN_LLQ_NUM_DESCS_BEFORE_HEADER_8; 74462306a36Sopenharmony_ci } else { 74562306a36Sopenharmony_ci netdev_err(ena_dev->net_device, 74662306a36Sopenharmony_ci "Invalid descs_num_before_header, supported: 0x%x\n", 74762306a36Sopenharmony_ci supported_feat); 74862306a36Sopenharmony_ci return -EINVAL; 74962306a36Sopenharmony_ci } 75062306a36Sopenharmony_ci 75162306a36Sopenharmony_ci netdev_err(ena_dev->net_device, 75262306a36Sopenharmony_ci "Default llq num descs before header is not supported, performing fallback, default: 0x%x, supported: 0x%x, used: 0x%x\n", 75362306a36Sopenharmony_ci llq_default_cfg->llq_num_decs_before_header, 75462306a36Sopenharmony_ci supported_feat, llq_info->descs_num_before_header); 75562306a36Sopenharmony_ci } 75662306a36Sopenharmony_ci /* Check for accelerated queue supported */ 75762306a36Sopenharmony_ci llq_accel_mode_get = llq_features->accel_mode.u.get; 75862306a36Sopenharmony_ci 75962306a36Sopenharmony_ci llq_info->disable_meta_caching = 76062306a36Sopenharmony_ci !!(llq_accel_mode_get.supported_flags & 76162306a36Sopenharmony_ci BIT(ENA_ADMIN_DISABLE_META_CACHING)); 76262306a36Sopenharmony_ci 76362306a36Sopenharmony_ci if (llq_accel_mode_get.supported_flags & BIT(ENA_ADMIN_LIMIT_TX_BURST)) 76462306a36Sopenharmony_ci llq_info->max_entries_in_tx_burst = 76562306a36Sopenharmony_ci llq_accel_mode_get.max_tx_burst_size / 76662306a36Sopenharmony_ci llq_default_cfg->llq_ring_entry_size_value; 76762306a36Sopenharmony_ci 76862306a36Sopenharmony_ci rc = ena_com_set_llq(ena_dev); 76962306a36Sopenharmony_ci if (rc) 77062306a36Sopenharmony_ci netdev_err(ena_dev->net_device, 77162306a36Sopenharmony_ci "Cannot set LLQ configuration: %d\n", rc); 77262306a36Sopenharmony_ci 77362306a36Sopenharmony_ci return rc; 77462306a36Sopenharmony_ci} 77562306a36Sopenharmony_ci 77662306a36Sopenharmony_cistatic int ena_com_wait_and_process_admin_cq_interrupts(struct ena_comp_ctx *comp_ctx, 77762306a36Sopenharmony_ci struct ena_com_admin_queue *admin_queue) 77862306a36Sopenharmony_ci{ 77962306a36Sopenharmony_ci unsigned long flags = 0; 78062306a36Sopenharmony_ci int ret; 78162306a36Sopenharmony_ci 78262306a36Sopenharmony_ci wait_for_completion_timeout(&comp_ctx->wait_event, 78362306a36Sopenharmony_ci usecs_to_jiffies( 78462306a36Sopenharmony_ci admin_queue->completion_timeout)); 78562306a36Sopenharmony_ci 78662306a36Sopenharmony_ci /* In case the command wasn't completed find out the root cause. 78762306a36Sopenharmony_ci * There might be 2 kinds of errors 78862306a36Sopenharmony_ci * 1) No completion (timeout reached) 78962306a36Sopenharmony_ci * 2) There is completion but the device didn't get any msi-x interrupt. 79062306a36Sopenharmony_ci */ 79162306a36Sopenharmony_ci if (unlikely(comp_ctx->status == ENA_CMD_SUBMITTED)) { 79262306a36Sopenharmony_ci spin_lock_irqsave(&admin_queue->q_lock, flags); 79362306a36Sopenharmony_ci ena_com_handle_admin_completion(admin_queue); 79462306a36Sopenharmony_ci admin_queue->stats.no_completion++; 79562306a36Sopenharmony_ci spin_unlock_irqrestore(&admin_queue->q_lock, flags); 79662306a36Sopenharmony_ci 79762306a36Sopenharmony_ci if (comp_ctx->status == ENA_CMD_COMPLETED) { 79862306a36Sopenharmony_ci netdev_err(admin_queue->ena_dev->net_device, 79962306a36Sopenharmony_ci "The ena device sent a completion but the driver didn't receive a MSI-X interrupt (cmd %d), autopolling mode is %s\n", 80062306a36Sopenharmony_ci comp_ctx->cmd_opcode, 80162306a36Sopenharmony_ci admin_queue->auto_polling ? "ON" : "OFF"); 80262306a36Sopenharmony_ci /* Check if fallback to polling is enabled */ 80362306a36Sopenharmony_ci if (admin_queue->auto_polling) 80462306a36Sopenharmony_ci admin_queue->polling = true; 80562306a36Sopenharmony_ci } else { 80662306a36Sopenharmony_ci netdev_err(admin_queue->ena_dev->net_device, 80762306a36Sopenharmony_ci "The ena device didn't send a completion for the admin cmd %d status %d\n", 80862306a36Sopenharmony_ci comp_ctx->cmd_opcode, comp_ctx->status); 80962306a36Sopenharmony_ci } 81062306a36Sopenharmony_ci /* Check if shifted to polling mode. 81162306a36Sopenharmony_ci * This will happen if there is a completion without an interrupt 81262306a36Sopenharmony_ci * and autopolling mode is enabled. Continuing normal execution in such case 81362306a36Sopenharmony_ci */ 81462306a36Sopenharmony_ci if (!admin_queue->polling) { 81562306a36Sopenharmony_ci admin_queue->running_state = false; 81662306a36Sopenharmony_ci ret = -ETIME; 81762306a36Sopenharmony_ci goto err; 81862306a36Sopenharmony_ci } 81962306a36Sopenharmony_ci } 82062306a36Sopenharmony_ci 82162306a36Sopenharmony_ci ret = ena_com_comp_status_to_errno(admin_queue, comp_ctx->comp_status); 82262306a36Sopenharmony_cierr: 82362306a36Sopenharmony_ci comp_ctxt_release(admin_queue, comp_ctx); 82462306a36Sopenharmony_ci return ret; 82562306a36Sopenharmony_ci} 82662306a36Sopenharmony_ci 82762306a36Sopenharmony_ci/* This method read the hardware device register through posting writes 82862306a36Sopenharmony_ci * and waiting for response 82962306a36Sopenharmony_ci * On timeout the function will return ENA_MMIO_READ_TIMEOUT 83062306a36Sopenharmony_ci */ 83162306a36Sopenharmony_cistatic u32 ena_com_reg_bar_read32(struct ena_com_dev *ena_dev, u16 offset) 83262306a36Sopenharmony_ci{ 83362306a36Sopenharmony_ci struct ena_com_mmio_read *mmio_read = &ena_dev->mmio_read; 83462306a36Sopenharmony_ci volatile struct ena_admin_ena_mmio_req_read_less_resp *read_resp = 83562306a36Sopenharmony_ci mmio_read->read_resp; 83662306a36Sopenharmony_ci u32 mmio_read_reg, ret, i; 83762306a36Sopenharmony_ci unsigned long flags = 0; 83862306a36Sopenharmony_ci u32 timeout = mmio_read->reg_read_to; 83962306a36Sopenharmony_ci 84062306a36Sopenharmony_ci might_sleep(); 84162306a36Sopenharmony_ci 84262306a36Sopenharmony_ci if (timeout == 0) 84362306a36Sopenharmony_ci timeout = ENA_REG_READ_TIMEOUT; 84462306a36Sopenharmony_ci 84562306a36Sopenharmony_ci /* If readless is disabled, perform regular read */ 84662306a36Sopenharmony_ci if (!mmio_read->readless_supported) 84762306a36Sopenharmony_ci return readl(ena_dev->reg_bar + offset); 84862306a36Sopenharmony_ci 84962306a36Sopenharmony_ci spin_lock_irqsave(&mmio_read->lock, flags); 85062306a36Sopenharmony_ci mmio_read->seq_num++; 85162306a36Sopenharmony_ci 85262306a36Sopenharmony_ci read_resp->req_id = mmio_read->seq_num + 0xDEAD; 85362306a36Sopenharmony_ci mmio_read_reg = (offset << ENA_REGS_MMIO_REG_READ_REG_OFF_SHIFT) & 85462306a36Sopenharmony_ci ENA_REGS_MMIO_REG_READ_REG_OFF_MASK; 85562306a36Sopenharmony_ci mmio_read_reg |= mmio_read->seq_num & 85662306a36Sopenharmony_ci ENA_REGS_MMIO_REG_READ_REQ_ID_MASK; 85762306a36Sopenharmony_ci 85862306a36Sopenharmony_ci writel(mmio_read_reg, ena_dev->reg_bar + ENA_REGS_MMIO_REG_READ_OFF); 85962306a36Sopenharmony_ci 86062306a36Sopenharmony_ci for (i = 0; i < timeout; i++) { 86162306a36Sopenharmony_ci if (READ_ONCE(read_resp->req_id) == mmio_read->seq_num) 86262306a36Sopenharmony_ci break; 86362306a36Sopenharmony_ci 86462306a36Sopenharmony_ci udelay(1); 86562306a36Sopenharmony_ci } 86662306a36Sopenharmony_ci 86762306a36Sopenharmony_ci if (unlikely(i == timeout)) { 86862306a36Sopenharmony_ci netdev_err(ena_dev->net_device, 86962306a36Sopenharmony_ci "Reading reg failed for timeout. expected: req id[%u] offset[%u] actual: req id[%u] offset[%u]\n", 87062306a36Sopenharmony_ci mmio_read->seq_num, offset, read_resp->req_id, 87162306a36Sopenharmony_ci read_resp->reg_off); 87262306a36Sopenharmony_ci ret = ENA_MMIO_READ_TIMEOUT; 87362306a36Sopenharmony_ci goto err; 87462306a36Sopenharmony_ci } 87562306a36Sopenharmony_ci 87662306a36Sopenharmony_ci if (read_resp->reg_off != offset) { 87762306a36Sopenharmony_ci netdev_err(ena_dev->net_device, 87862306a36Sopenharmony_ci "Read failure: wrong offset provided\n"); 87962306a36Sopenharmony_ci ret = ENA_MMIO_READ_TIMEOUT; 88062306a36Sopenharmony_ci } else { 88162306a36Sopenharmony_ci ret = read_resp->reg_val; 88262306a36Sopenharmony_ci } 88362306a36Sopenharmony_cierr: 88462306a36Sopenharmony_ci spin_unlock_irqrestore(&mmio_read->lock, flags); 88562306a36Sopenharmony_ci 88662306a36Sopenharmony_ci return ret; 88762306a36Sopenharmony_ci} 88862306a36Sopenharmony_ci 88962306a36Sopenharmony_ci/* There are two types to wait for completion. 89062306a36Sopenharmony_ci * Polling mode - wait until the completion is available. 89162306a36Sopenharmony_ci * Async mode - wait on wait queue until the completion is ready 89262306a36Sopenharmony_ci * (or the timeout expired). 89362306a36Sopenharmony_ci * It is expected that the IRQ called ena_com_handle_admin_completion 89462306a36Sopenharmony_ci * to mark the completions. 89562306a36Sopenharmony_ci */ 89662306a36Sopenharmony_cistatic int ena_com_wait_and_process_admin_cq(struct ena_comp_ctx *comp_ctx, 89762306a36Sopenharmony_ci struct ena_com_admin_queue *admin_queue) 89862306a36Sopenharmony_ci{ 89962306a36Sopenharmony_ci if (admin_queue->polling) 90062306a36Sopenharmony_ci return ena_com_wait_and_process_admin_cq_polling(comp_ctx, 90162306a36Sopenharmony_ci admin_queue); 90262306a36Sopenharmony_ci 90362306a36Sopenharmony_ci return ena_com_wait_and_process_admin_cq_interrupts(comp_ctx, 90462306a36Sopenharmony_ci admin_queue); 90562306a36Sopenharmony_ci} 90662306a36Sopenharmony_ci 90762306a36Sopenharmony_cistatic int ena_com_destroy_io_sq(struct ena_com_dev *ena_dev, 90862306a36Sopenharmony_ci struct ena_com_io_sq *io_sq) 90962306a36Sopenharmony_ci{ 91062306a36Sopenharmony_ci struct ena_com_admin_queue *admin_queue = &ena_dev->admin_queue; 91162306a36Sopenharmony_ci struct ena_admin_aq_destroy_sq_cmd destroy_cmd; 91262306a36Sopenharmony_ci struct ena_admin_acq_destroy_sq_resp_desc destroy_resp; 91362306a36Sopenharmony_ci u8 direction; 91462306a36Sopenharmony_ci int ret; 91562306a36Sopenharmony_ci 91662306a36Sopenharmony_ci memset(&destroy_cmd, 0x0, sizeof(destroy_cmd)); 91762306a36Sopenharmony_ci 91862306a36Sopenharmony_ci if (io_sq->direction == ENA_COM_IO_QUEUE_DIRECTION_TX) 91962306a36Sopenharmony_ci direction = ENA_ADMIN_SQ_DIRECTION_TX; 92062306a36Sopenharmony_ci else 92162306a36Sopenharmony_ci direction = ENA_ADMIN_SQ_DIRECTION_RX; 92262306a36Sopenharmony_ci 92362306a36Sopenharmony_ci destroy_cmd.sq.sq_identity |= (direction << 92462306a36Sopenharmony_ci ENA_ADMIN_SQ_SQ_DIRECTION_SHIFT) & 92562306a36Sopenharmony_ci ENA_ADMIN_SQ_SQ_DIRECTION_MASK; 92662306a36Sopenharmony_ci 92762306a36Sopenharmony_ci destroy_cmd.sq.sq_idx = io_sq->idx; 92862306a36Sopenharmony_ci destroy_cmd.aq_common_descriptor.opcode = ENA_ADMIN_DESTROY_SQ; 92962306a36Sopenharmony_ci 93062306a36Sopenharmony_ci ret = ena_com_execute_admin_command(admin_queue, 93162306a36Sopenharmony_ci (struct ena_admin_aq_entry *)&destroy_cmd, 93262306a36Sopenharmony_ci sizeof(destroy_cmd), 93362306a36Sopenharmony_ci (struct ena_admin_acq_entry *)&destroy_resp, 93462306a36Sopenharmony_ci sizeof(destroy_resp)); 93562306a36Sopenharmony_ci 93662306a36Sopenharmony_ci if (unlikely(ret && (ret != -ENODEV))) 93762306a36Sopenharmony_ci netdev_err(ena_dev->net_device, 93862306a36Sopenharmony_ci "Failed to destroy io sq error: %d\n", ret); 93962306a36Sopenharmony_ci 94062306a36Sopenharmony_ci return ret; 94162306a36Sopenharmony_ci} 94262306a36Sopenharmony_ci 94362306a36Sopenharmony_cistatic void ena_com_io_queue_free(struct ena_com_dev *ena_dev, 94462306a36Sopenharmony_ci struct ena_com_io_sq *io_sq, 94562306a36Sopenharmony_ci struct ena_com_io_cq *io_cq) 94662306a36Sopenharmony_ci{ 94762306a36Sopenharmony_ci size_t size; 94862306a36Sopenharmony_ci 94962306a36Sopenharmony_ci if (io_cq->cdesc_addr.virt_addr) { 95062306a36Sopenharmony_ci size = io_cq->cdesc_entry_size_in_bytes * io_cq->q_depth; 95162306a36Sopenharmony_ci 95262306a36Sopenharmony_ci dma_free_coherent(ena_dev->dmadev, size, 95362306a36Sopenharmony_ci io_cq->cdesc_addr.virt_addr, 95462306a36Sopenharmony_ci io_cq->cdesc_addr.phys_addr); 95562306a36Sopenharmony_ci 95662306a36Sopenharmony_ci io_cq->cdesc_addr.virt_addr = NULL; 95762306a36Sopenharmony_ci } 95862306a36Sopenharmony_ci 95962306a36Sopenharmony_ci if (io_sq->desc_addr.virt_addr) { 96062306a36Sopenharmony_ci size = io_sq->desc_entry_size * io_sq->q_depth; 96162306a36Sopenharmony_ci 96262306a36Sopenharmony_ci dma_free_coherent(ena_dev->dmadev, size, 96362306a36Sopenharmony_ci io_sq->desc_addr.virt_addr, 96462306a36Sopenharmony_ci io_sq->desc_addr.phys_addr); 96562306a36Sopenharmony_ci 96662306a36Sopenharmony_ci io_sq->desc_addr.virt_addr = NULL; 96762306a36Sopenharmony_ci } 96862306a36Sopenharmony_ci 96962306a36Sopenharmony_ci if (io_sq->bounce_buf_ctrl.base_buffer) { 97062306a36Sopenharmony_ci devm_kfree(ena_dev->dmadev, io_sq->bounce_buf_ctrl.base_buffer); 97162306a36Sopenharmony_ci io_sq->bounce_buf_ctrl.base_buffer = NULL; 97262306a36Sopenharmony_ci } 97362306a36Sopenharmony_ci} 97462306a36Sopenharmony_ci 97562306a36Sopenharmony_cistatic int wait_for_reset_state(struct ena_com_dev *ena_dev, u32 timeout, 97662306a36Sopenharmony_ci u16 exp_state) 97762306a36Sopenharmony_ci{ 97862306a36Sopenharmony_ci u32 val, exp = 0; 97962306a36Sopenharmony_ci unsigned long timeout_stamp; 98062306a36Sopenharmony_ci 98162306a36Sopenharmony_ci /* Convert timeout from resolution of 100ms to us resolution. */ 98262306a36Sopenharmony_ci timeout_stamp = jiffies + usecs_to_jiffies(100 * 1000 * timeout); 98362306a36Sopenharmony_ci 98462306a36Sopenharmony_ci while (1) { 98562306a36Sopenharmony_ci val = ena_com_reg_bar_read32(ena_dev, ENA_REGS_DEV_STS_OFF); 98662306a36Sopenharmony_ci 98762306a36Sopenharmony_ci if (unlikely(val == ENA_MMIO_READ_TIMEOUT)) { 98862306a36Sopenharmony_ci netdev_err(ena_dev->net_device, 98962306a36Sopenharmony_ci "Reg read timeout occurred\n"); 99062306a36Sopenharmony_ci return -ETIME; 99162306a36Sopenharmony_ci } 99262306a36Sopenharmony_ci 99362306a36Sopenharmony_ci if ((val & ENA_REGS_DEV_STS_RESET_IN_PROGRESS_MASK) == 99462306a36Sopenharmony_ci exp_state) 99562306a36Sopenharmony_ci return 0; 99662306a36Sopenharmony_ci 99762306a36Sopenharmony_ci if (time_is_before_jiffies(timeout_stamp)) 99862306a36Sopenharmony_ci return -ETIME; 99962306a36Sopenharmony_ci 100062306a36Sopenharmony_ci ena_delay_exponential_backoff_us(exp++, ena_dev->ena_min_poll_delay_us); 100162306a36Sopenharmony_ci } 100262306a36Sopenharmony_ci} 100362306a36Sopenharmony_ci 100462306a36Sopenharmony_cistatic bool ena_com_check_supported_feature_id(struct ena_com_dev *ena_dev, 100562306a36Sopenharmony_ci enum ena_admin_aq_feature_id feature_id) 100662306a36Sopenharmony_ci{ 100762306a36Sopenharmony_ci u32 feature_mask = 1 << feature_id; 100862306a36Sopenharmony_ci 100962306a36Sopenharmony_ci /* Device attributes is always supported */ 101062306a36Sopenharmony_ci if ((feature_id != ENA_ADMIN_DEVICE_ATTRIBUTES) && 101162306a36Sopenharmony_ci !(ena_dev->supported_features & feature_mask)) 101262306a36Sopenharmony_ci return false; 101362306a36Sopenharmony_ci 101462306a36Sopenharmony_ci return true; 101562306a36Sopenharmony_ci} 101662306a36Sopenharmony_ci 101762306a36Sopenharmony_cistatic int ena_com_get_feature_ex(struct ena_com_dev *ena_dev, 101862306a36Sopenharmony_ci struct ena_admin_get_feat_resp *get_resp, 101962306a36Sopenharmony_ci enum ena_admin_aq_feature_id feature_id, 102062306a36Sopenharmony_ci dma_addr_t control_buf_dma_addr, 102162306a36Sopenharmony_ci u32 control_buff_size, 102262306a36Sopenharmony_ci u8 feature_ver) 102362306a36Sopenharmony_ci{ 102462306a36Sopenharmony_ci struct ena_com_admin_queue *admin_queue; 102562306a36Sopenharmony_ci struct ena_admin_get_feat_cmd get_cmd; 102662306a36Sopenharmony_ci int ret; 102762306a36Sopenharmony_ci 102862306a36Sopenharmony_ci if (!ena_com_check_supported_feature_id(ena_dev, feature_id)) { 102962306a36Sopenharmony_ci netdev_dbg(ena_dev->net_device, "Feature %d isn't supported\n", 103062306a36Sopenharmony_ci feature_id); 103162306a36Sopenharmony_ci return -EOPNOTSUPP; 103262306a36Sopenharmony_ci } 103362306a36Sopenharmony_ci 103462306a36Sopenharmony_ci memset(&get_cmd, 0x0, sizeof(get_cmd)); 103562306a36Sopenharmony_ci admin_queue = &ena_dev->admin_queue; 103662306a36Sopenharmony_ci 103762306a36Sopenharmony_ci get_cmd.aq_common_descriptor.opcode = ENA_ADMIN_GET_FEATURE; 103862306a36Sopenharmony_ci 103962306a36Sopenharmony_ci if (control_buff_size) 104062306a36Sopenharmony_ci get_cmd.aq_common_descriptor.flags = 104162306a36Sopenharmony_ci ENA_ADMIN_AQ_COMMON_DESC_CTRL_DATA_INDIRECT_MASK; 104262306a36Sopenharmony_ci else 104362306a36Sopenharmony_ci get_cmd.aq_common_descriptor.flags = 0; 104462306a36Sopenharmony_ci 104562306a36Sopenharmony_ci ret = ena_com_mem_addr_set(ena_dev, 104662306a36Sopenharmony_ci &get_cmd.control_buffer.address, 104762306a36Sopenharmony_ci control_buf_dma_addr); 104862306a36Sopenharmony_ci if (unlikely(ret)) { 104962306a36Sopenharmony_ci netdev_err(ena_dev->net_device, "Memory address set failed\n"); 105062306a36Sopenharmony_ci return ret; 105162306a36Sopenharmony_ci } 105262306a36Sopenharmony_ci 105362306a36Sopenharmony_ci get_cmd.control_buffer.length = control_buff_size; 105462306a36Sopenharmony_ci get_cmd.feat_common.feature_version = feature_ver; 105562306a36Sopenharmony_ci get_cmd.feat_common.feature_id = feature_id; 105662306a36Sopenharmony_ci 105762306a36Sopenharmony_ci ret = ena_com_execute_admin_command(admin_queue, 105862306a36Sopenharmony_ci (struct ena_admin_aq_entry *) 105962306a36Sopenharmony_ci &get_cmd, 106062306a36Sopenharmony_ci sizeof(get_cmd), 106162306a36Sopenharmony_ci (struct ena_admin_acq_entry *) 106262306a36Sopenharmony_ci get_resp, 106362306a36Sopenharmony_ci sizeof(*get_resp)); 106462306a36Sopenharmony_ci 106562306a36Sopenharmony_ci if (unlikely(ret)) 106662306a36Sopenharmony_ci netdev_err(ena_dev->net_device, 106762306a36Sopenharmony_ci "Failed to submit get_feature command %d error: %d\n", 106862306a36Sopenharmony_ci feature_id, ret); 106962306a36Sopenharmony_ci 107062306a36Sopenharmony_ci return ret; 107162306a36Sopenharmony_ci} 107262306a36Sopenharmony_ci 107362306a36Sopenharmony_cistatic int ena_com_get_feature(struct ena_com_dev *ena_dev, 107462306a36Sopenharmony_ci struct ena_admin_get_feat_resp *get_resp, 107562306a36Sopenharmony_ci enum ena_admin_aq_feature_id feature_id, 107662306a36Sopenharmony_ci u8 feature_ver) 107762306a36Sopenharmony_ci{ 107862306a36Sopenharmony_ci return ena_com_get_feature_ex(ena_dev, 107962306a36Sopenharmony_ci get_resp, 108062306a36Sopenharmony_ci feature_id, 108162306a36Sopenharmony_ci 0, 108262306a36Sopenharmony_ci 0, 108362306a36Sopenharmony_ci feature_ver); 108462306a36Sopenharmony_ci} 108562306a36Sopenharmony_ci 108662306a36Sopenharmony_ciint ena_com_get_current_hash_function(struct ena_com_dev *ena_dev) 108762306a36Sopenharmony_ci{ 108862306a36Sopenharmony_ci return ena_dev->rss.hash_func; 108962306a36Sopenharmony_ci} 109062306a36Sopenharmony_ci 109162306a36Sopenharmony_cistatic void ena_com_hash_key_fill_default_key(struct ena_com_dev *ena_dev) 109262306a36Sopenharmony_ci{ 109362306a36Sopenharmony_ci struct ena_admin_feature_rss_flow_hash_control *hash_key = 109462306a36Sopenharmony_ci (ena_dev->rss).hash_key; 109562306a36Sopenharmony_ci 109662306a36Sopenharmony_ci netdev_rss_key_fill(&hash_key->key, sizeof(hash_key->key)); 109762306a36Sopenharmony_ci /* The key buffer is stored in the device in an array of 109862306a36Sopenharmony_ci * uint32 elements. 109962306a36Sopenharmony_ci */ 110062306a36Sopenharmony_ci hash_key->key_parts = ENA_ADMIN_RSS_KEY_PARTS; 110162306a36Sopenharmony_ci} 110262306a36Sopenharmony_ci 110362306a36Sopenharmony_cistatic int ena_com_hash_key_allocate(struct ena_com_dev *ena_dev) 110462306a36Sopenharmony_ci{ 110562306a36Sopenharmony_ci struct ena_rss *rss = &ena_dev->rss; 110662306a36Sopenharmony_ci 110762306a36Sopenharmony_ci if (!ena_com_check_supported_feature_id(ena_dev, 110862306a36Sopenharmony_ci ENA_ADMIN_RSS_HASH_FUNCTION)) 110962306a36Sopenharmony_ci return -EOPNOTSUPP; 111062306a36Sopenharmony_ci 111162306a36Sopenharmony_ci rss->hash_key = 111262306a36Sopenharmony_ci dma_alloc_coherent(ena_dev->dmadev, sizeof(*rss->hash_key), 111362306a36Sopenharmony_ci &rss->hash_key_dma_addr, GFP_KERNEL); 111462306a36Sopenharmony_ci 111562306a36Sopenharmony_ci if (unlikely(!rss->hash_key)) 111662306a36Sopenharmony_ci return -ENOMEM; 111762306a36Sopenharmony_ci 111862306a36Sopenharmony_ci return 0; 111962306a36Sopenharmony_ci} 112062306a36Sopenharmony_ci 112162306a36Sopenharmony_cistatic void ena_com_hash_key_destroy(struct ena_com_dev *ena_dev) 112262306a36Sopenharmony_ci{ 112362306a36Sopenharmony_ci struct ena_rss *rss = &ena_dev->rss; 112462306a36Sopenharmony_ci 112562306a36Sopenharmony_ci if (rss->hash_key) 112662306a36Sopenharmony_ci dma_free_coherent(ena_dev->dmadev, sizeof(*rss->hash_key), 112762306a36Sopenharmony_ci rss->hash_key, rss->hash_key_dma_addr); 112862306a36Sopenharmony_ci rss->hash_key = NULL; 112962306a36Sopenharmony_ci} 113062306a36Sopenharmony_ci 113162306a36Sopenharmony_cistatic int ena_com_hash_ctrl_init(struct ena_com_dev *ena_dev) 113262306a36Sopenharmony_ci{ 113362306a36Sopenharmony_ci struct ena_rss *rss = &ena_dev->rss; 113462306a36Sopenharmony_ci 113562306a36Sopenharmony_ci rss->hash_ctrl = 113662306a36Sopenharmony_ci dma_alloc_coherent(ena_dev->dmadev, sizeof(*rss->hash_ctrl), 113762306a36Sopenharmony_ci &rss->hash_ctrl_dma_addr, GFP_KERNEL); 113862306a36Sopenharmony_ci 113962306a36Sopenharmony_ci if (unlikely(!rss->hash_ctrl)) 114062306a36Sopenharmony_ci return -ENOMEM; 114162306a36Sopenharmony_ci 114262306a36Sopenharmony_ci return 0; 114362306a36Sopenharmony_ci} 114462306a36Sopenharmony_ci 114562306a36Sopenharmony_cistatic void ena_com_hash_ctrl_destroy(struct ena_com_dev *ena_dev) 114662306a36Sopenharmony_ci{ 114762306a36Sopenharmony_ci struct ena_rss *rss = &ena_dev->rss; 114862306a36Sopenharmony_ci 114962306a36Sopenharmony_ci if (rss->hash_ctrl) 115062306a36Sopenharmony_ci dma_free_coherent(ena_dev->dmadev, sizeof(*rss->hash_ctrl), 115162306a36Sopenharmony_ci rss->hash_ctrl, rss->hash_ctrl_dma_addr); 115262306a36Sopenharmony_ci rss->hash_ctrl = NULL; 115362306a36Sopenharmony_ci} 115462306a36Sopenharmony_ci 115562306a36Sopenharmony_cistatic int ena_com_indirect_table_allocate(struct ena_com_dev *ena_dev, 115662306a36Sopenharmony_ci u16 log_size) 115762306a36Sopenharmony_ci{ 115862306a36Sopenharmony_ci struct ena_rss *rss = &ena_dev->rss; 115962306a36Sopenharmony_ci struct ena_admin_get_feat_resp get_resp; 116062306a36Sopenharmony_ci size_t tbl_size; 116162306a36Sopenharmony_ci int ret; 116262306a36Sopenharmony_ci 116362306a36Sopenharmony_ci ret = ena_com_get_feature(ena_dev, &get_resp, 116462306a36Sopenharmony_ci ENA_ADMIN_RSS_INDIRECTION_TABLE_CONFIG, 0); 116562306a36Sopenharmony_ci if (unlikely(ret)) 116662306a36Sopenharmony_ci return ret; 116762306a36Sopenharmony_ci 116862306a36Sopenharmony_ci if ((get_resp.u.ind_table.min_size > log_size) || 116962306a36Sopenharmony_ci (get_resp.u.ind_table.max_size < log_size)) { 117062306a36Sopenharmony_ci netdev_err(ena_dev->net_device, 117162306a36Sopenharmony_ci "Indirect table size doesn't fit. requested size: %d while min is:%d and max %d\n", 117262306a36Sopenharmony_ci 1 << log_size, 1 << get_resp.u.ind_table.min_size, 117362306a36Sopenharmony_ci 1 << get_resp.u.ind_table.max_size); 117462306a36Sopenharmony_ci return -EINVAL; 117562306a36Sopenharmony_ci } 117662306a36Sopenharmony_ci 117762306a36Sopenharmony_ci tbl_size = (1ULL << log_size) * 117862306a36Sopenharmony_ci sizeof(struct ena_admin_rss_ind_table_entry); 117962306a36Sopenharmony_ci 118062306a36Sopenharmony_ci rss->rss_ind_tbl = 118162306a36Sopenharmony_ci dma_alloc_coherent(ena_dev->dmadev, tbl_size, 118262306a36Sopenharmony_ci &rss->rss_ind_tbl_dma_addr, GFP_KERNEL); 118362306a36Sopenharmony_ci if (unlikely(!rss->rss_ind_tbl)) 118462306a36Sopenharmony_ci goto mem_err1; 118562306a36Sopenharmony_ci 118662306a36Sopenharmony_ci tbl_size = (1ULL << log_size) * sizeof(u16); 118762306a36Sopenharmony_ci rss->host_rss_ind_tbl = 118862306a36Sopenharmony_ci devm_kzalloc(ena_dev->dmadev, tbl_size, GFP_KERNEL); 118962306a36Sopenharmony_ci if (unlikely(!rss->host_rss_ind_tbl)) 119062306a36Sopenharmony_ci goto mem_err2; 119162306a36Sopenharmony_ci 119262306a36Sopenharmony_ci rss->tbl_log_size = log_size; 119362306a36Sopenharmony_ci 119462306a36Sopenharmony_ci return 0; 119562306a36Sopenharmony_ci 119662306a36Sopenharmony_cimem_err2: 119762306a36Sopenharmony_ci tbl_size = (1ULL << log_size) * 119862306a36Sopenharmony_ci sizeof(struct ena_admin_rss_ind_table_entry); 119962306a36Sopenharmony_ci 120062306a36Sopenharmony_ci dma_free_coherent(ena_dev->dmadev, tbl_size, rss->rss_ind_tbl, 120162306a36Sopenharmony_ci rss->rss_ind_tbl_dma_addr); 120262306a36Sopenharmony_ci rss->rss_ind_tbl = NULL; 120362306a36Sopenharmony_cimem_err1: 120462306a36Sopenharmony_ci rss->tbl_log_size = 0; 120562306a36Sopenharmony_ci return -ENOMEM; 120662306a36Sopenharmony_ci} 120762306a36Sopenharmony_ci 120862306a36Sopenharmony_cistatic void ena_com_indirect_table_destroy(struct ena_com_dev *ena_dev) 120962306a36Sopenharmony_ci{ 121062306a36Sopenharmony_ci struct ena_rss *rss = &ena_dev->rss; 121162306a36Sopenharmony_ci size_t tbl_size = (1ULL << rss->tbl_log_size) * 121262306a36Sopenharmony_ci sizeof(struct ena_admin_rss_ind_table_entry); 121362306a36Sopenharmony_ci 121462306a36Sopenharmony_ci if (rss->rss_ind_tbl) 121562306a36Sopenharmony_ci dma_free_coherent(ena_dev->dmadev, tbl_size, rss->rss_ind_tbl, 121662306a36Sopenharmony_ci rss->rss_ind_tbl_dma_addr); 121762306a36Sopenharmony_ci rss->rss_ind_tbl = NULL; 121862306a36Sopenharmony_ci 121962306a36Sopenharmony_ci if (rss->host_rss_ind_tbl) 122062306a36Sopenharmony_ci devm_kfree(ena_dev->dmadev, rss->host_rss_ind_tbl); 122162306a36Sopenharmony_ci rss->host_rss_ind_tbl = NULL; 122262306a36Sopenharmony_ci} 122362306a36Sopenharmony_ci 122462306a36Sopenharmony_cistatic int ena_com_create_io_sq(struct ena_com_dev *ena_dev, 122562306a36Sopenharmony_ci struct ena_com_io_sq *io_sq, u16 cq_idx) 122662306a36Sopenharmony_ci{ 122762306a36Sopenharmony_ci struct ena_com_admin_queue *admin_queue = &ena_dev->admin_queue; 122862306a36Sopenharmony_ci struct ena_admin_aq_create_sq_cmd create_cmd; 122962306a36Sopenharmony_ci struct ena_admin_acq_create_sq_resp_desc cmd_completion; 123062306a36Sopenharmony_ci u8 direction; 123162306a36Sopenharmony_ci int ret; 123262306a36Sopenharmony_ci 123362306a36Sopenharmony_ci memset(&create_cmd, 0x0, sizeof(create_cmd)); 123462306a36Sopenharmony_ci 123562306a36Sopenharmony_ci create_cmd.aq_common_descriptor.opcode = ENA_ADMIN_CREATE_SQ; 123662306a36Sopenharmony_ci 123762306a36Sopenharmony_ci if (io_sq->direction == ENA_COM_IO_QUEUE_DIRECTION_TX) 123862306a36Sopenharmony_ci direction = ENA_ADMIN_SQ_DIRECTION_TX; 123962306a36Sopenharmony_ci else 124062306a36Sopenharmony_ci direction = ENA_ADMIN_SQ_DIRECTION_RX; 124162306a36Sopenharmony_ci 124262306a36Sopenharmony_ci create_cmd.sq_identity |= (direction << 124362306a36Sopenharmony_ci ENA_ADMIN_AQ_CREATE_SQ_CMD_SQ_DIRECTION_SHIFT) & 124462306a36Sopenharmony_ci ENA_ADMIN_AQ_CREATE_SQ_CMD_SQ_DIRECTION_MASK; 124562306a36Sopenharmony_ci 124662306a36Sopenharmony_ci create_cmd.sq_caps_2 |= io_sq->mem_queue_type & 124762306a36Sopenharmony_ci ENA_ADMIN_AQ_CREATE_SQ_CMD_PLACEMENT_POLICY_MASK; 124862306a36Sopenharmony_ci 124962306a36Sopenharmony_ci create_cmd.sq_caps_2 |= (ENA_ADMIN_COMPLETION_POLICY_DESC << 125062306a36Sopenharmony_ci ENA_ADMIN_AQ_CREATE_SQ_CMD_COMPLETION_POLICY_SHIFT) & 125162306a36Sopenharmony_ci ENA_ADMIN_AQ_CREATE_SQ_CMD_COMPLETION_POLICY_MASK; 125262306a36Sopenharmony_ci 125362306a36Sopenharmony_ci create_cmd.sq_caps_3 |= 125462306a36Sopenharmony_ci ENA_ADMIN_AQ_CREATE_SQ_CMD_IS_PHYSICALLY_CONTIGUOUS_MASK; 125562306a36Sopenharmony_ci 125662306a36Sopenharmony_ci create_cmd.cq_idx = cq_idx; 125762306a36Sopenharmony_ci create_cmd.sq_depth = io_sq->q_depth; 125862306a36Sopenharmony_ci 125962306a36Sopenharmony_ci if (io_sq->mem_queue_type == ENA_ADMIN_PLACEMENT_POLICY_HOST) { 126062306a36Sopenharmony_ci ret = ena_com_mem_addr_set(ena_dev, 126162306a36Sopenharmony_ci &create_cmd.sq_ba, 126262306a36Sopenharmony_ci io_sq->desc_addr.phys_addr); 126362306a36Sopenharmony_ci if (unlikely(ret)) { 126462306a36Sopenharmony_ci netdev_err(ena_dev->net_device, 126562306a36Sopenharmony_ci "Memory address set failed\n"); 126662306a36Sopenharmony_ci return ret; 126762306a36Sopenharmony_ci } 126862306a36Sopenharmony_ci } 126962306a36Sopenharmony_ci 127062306a36Sopenharmony_ci ret = ena_com_execute_admin_command(admin_queue, 127162306a36Sopenharmony_ci (struct ena_admin_aq_entry *)&create_cmd, 127262306a36Sopenharmony_ci sizeof(create_cmd), 127362306a36Sopenharmony_ci (struct ena_admin_acq_entry *)&cmd_completion, 127462306a36Sopenharmony_ci sizeof(cmd_completion)); 127562306a36Sopenharmony_ci if (unlikely(ret)) { 127662306a36Sopenharmony_ci netdev_err(ena_dev->net_device, 127762306a36Sopenharmony_ci "Failed to create IO SQ. error: %d\n", ret); 127862306a36Sopenharmony_ci return ret; 127962306a36Sopenharmony_ci } 128062306a36Sopenharmony_ci 128162306a36Sopenharmony_ci io_sq->idx = cmd_completion.sq_idx; 128262306a36Sopenharmony_ci 128362306a36Sopenharmony_ci io_sq->db_addr = (u32 __iomem *)((uintptr_t)ena_dev->reg_bar + 128462306a36Sopenharmony_ci (uintptr_t)cmd_completion.sq_doorbell_offset); 128562306a36Sopenharmony_ci 128662306a36Sopenharmony_ci if (io_sq->mem_queue_type == ENA_ADMIN_PLACEMENT_POLICY_DEV) { 128762306a36Sopenharmony_ci io_sq->header_addr = (u8 __iomem *)((uintptr_t)ena_dev->mem_bar 128862306a36Sopenharmony_ci + cmd_completion.llq_headers_offset); 128962306a36Sopenharmony_ci 129062306a36Sopenharmony_ci io_sq->desc_addr.pbuf_dev_addr = 129162306a36Sopenharmony_ci (u8 __iomem *)((uintptr_t)ena_dev->mem_bar + 129262306a36Sopenharmony_ci cmd_completion.llq_descriptors_offset); 129362306a36Sopenharmony_ci } 129462306a36Sopenharmony_ci 129562306a36Sopenharmony_ci netdev_dbg(ena_dev->net_device, "Created sq[%u], depth[%u]\n", 129662306a36Sopenharmony_ci io_sq->idx, io_sq->q_depth); 129762306a36Sopenharmony_ci 129862306a36Sopenharmony_ci return ret; 129962306a36Sopenharmony_ci} 130062306a36Sopenharmony_ci 130162306a36Sopenharmony_cistatic int ena_com_ind_tbl_convert_to_device(struct ena_com_dev *ena_dev) 130262306a36Sopenharmony_ci{ 130362306a36Sopenharmony_ci struct ena_rss *rss = &ena_dev->rss; 130462306a36Sopenharmony_ci struct ena_com_io_sq *io_sq; 130562306a36Sopenharmony_ci u16 qid; 130662306a36Sopenharmony_ci int i; 130762306a36Sopenharmony_ci 130862306a36Sopenharmony_ci for (i = 0; i < 1 << rss->tbl_log_size; i++) { 130962306a36Sopenharmony_ci qid = rss->host_rss_ind_tbl[i]; 131062306a36Sopenharmony_ci if (qid >= ENA_TOTAL_NUM_QUEUES) 131162306a36Sopenharmony_ci return -EINVAL; 131262306a36Sopenharmony_ci 131362306a36Sopenharmony_ci io_sq = &ena_dev->io_sq_queues[qid]; 131462306a36Sopenharmony_ci 131562306a36Sopenharmony_ci if (io_sq->direction != ENA_COM_IO_QUEUE_DIRECTION_RX) 131662306a36Sopenharmony_ci return -EINVAL; 131762306a36Sopenharmony_ci 131862306a36Sopenharmony_ci rss->rss_ind_tbl[i].cq_idx = io_sq->idx; 131962306a36Sopenharmony_ci } 132062306a36Sopenharmony_ci 132162306a36Sopenharmony_ci return 0; 132262306a36Sopenharmony_ci} 132362306a36Sopenharmony_ci 132462306a36Sopenharmony_cistatic void ena_com_update_intr_delay_resolution(struct ena_com_dev *ena_dev, 132562306a36Sopenharmony_ci u16 intr_delay_resolution) 132662306a36Sopenharmony_ci{ 132762306a36Sopenharmony_ci u16 prev_intr_delay_resolution = ena_dev->intr_delay_resolution; 132862306a36Sopenharmony_ci 132962306a36Sopenharmony_ci if (unlikely(!intr_delay_resolution)) { 133062306a36Sopenharmony_ci netdev_err(ena_dev->net_device, 133162306a36Sopenharmony_ci "Illegal intr_delay_resolution provided. Going to use default 1 usec resolution\n"); 133262306a36Sopenharmony_ci intr_delay_resolution = ENA_DEFAULT_INTR_DELAY_RESOLUTION; 133362306a36Sopenharmony_ci } 133462306a36Sopenharmony_ci 133562306a36Sopenharmony_ci /* update Rx */ 133662306a36Sopenharmony_ci ena_dev->intr_moder_rx_interval = 133762306a36Sopenharmony_ci ena_dev->intr_moder_rx_interval * 133862306a36Sopenharmony_ci prev_intr_delay_resolution / 133962306a36Sopenharmony_ci intr_delay_resolution; 134062306a36Sopenharmony_ci 134162306a36Sopenharmony_ci /* update Tx */ 134262306a36Sopenharmony_ci ena_dev->intr_moder_tx_interval = 134362306a36Sopenharmony_ci ena_dev->intr_moder_tx_interval * 134462306a36Sopenharmony_ci prev_intr_delay_resolution / 134562306a36Sopenharmony_ci intr_delay_resolution; 134662306a36Sopenharmony_ci 134762306a36Sopenharmony_ci ena_dev->intr_delay_resolution = intr_delay_resolution; 134862306a36Sopenharmony_ci} 134962306a36Sopenharmony_ci 135062306a36Sopenharmony_ci/*****************************************************************************/ 135162306a36Sopenharmony_ci/******************************* API ******************************/ 135262306a36Sopenharmony_ci/*****************************************************************************/ 135362306a36Sopenharmony_ci 135462306a36Sopenharmony_ciint ena_com_execute_admin_command(struct ena_com_admin_queue *admin_queue, 135562306a36Sopenharmony_ci struct ena_admin_aq_entry *cmd, 135662306a36Sopenharmony_ci size_t cmd_size, 135762306a36Sopenharmony_ci struct ena_admin_acq_entry *comp, 135862306a36Sopenharmony_ci size_t comp_size) 135962306a36Sopenharmony_ci{ 136062306a36Sopenharmony_ci struct ena_comp_ctx *comp_ctx; 136162306a36Sopenharmony_ci int ret; 136262306a36Sopenharmony_ci 136362306a36Sopenharmony_ci comp_ctx = ena_com_submit_admin_cmd(admin_queue, cmd, cmd_size, 136462306a36Sopenharmony_ci comp, comp_size); 136562306a36Sopenharmony_ci if (IS_ERR(comp_ctx)) { 136662306a36Sopenharmony_ci ret = PTR_ERR(comp_ctx); 136762306a36Sopenharmony_ci if (ret == -ENODEV) 136862306a36Sopenharmony_ci netdev_dbg(admin_queue->ena_dev->net_device, 136962306a36Sopenharmony_ci "Failed to submit command [%d]\n", ret); 137062306a36Sopenharmony_ci else 137162306a36Sopenharmony_ci netdev_err(admin_queue->ena_dev->net_device, 137262306a36Sopenharmony_ci "Failed to submit command [%d]\n", ret); 137362306a36Sopenharmony_ci 137462306a36Sopenharmony_ci return ret; 137562306a36Sopenharmony_ci } 137662306a36Sopenharmony_ci 137762306a36Sopenharmony_ci ret = ena_com_wait_and_process_admin_cq(comp_ctx, admin_queue); 137862306a36Sopenharmony_ci if (unlikely(ret)) { 137962306a36Sopenharmony_ci if (admin_queue->running_state) 138062306a36Sopenharmony_ci netdev_err(admin_queue->ena_dev->net_device, 138162306a36Sopenharmony_ci "Failed to process command. ret = %d\n", ret); 138262306a36Sopenharmony_ci else 138362306a36Sopenharmony_ci netdev_dbg(admin_queue->ena_dev->net_device, 138462306a36Sopenharmony_ci "Failed to process command. ret = %d\n", ret); 138562306a36Sopenharmony_ci } 138662306a36Sopenharmony_ci return ret; 138762306a36Sopenharmony_ci} 138862306a36Sopenharmony_ci 138962306a36Sopenharmony_ciint ena_com_create_io_cq(struct ena_com_dev *ena_dev, 139062306a36Sopenharmony_ci struct ena_com_io_cq *io_cq) 139162306a36Sopenharmony_ci{ 139262306a36Sopenharmony_ci struct ena_com_admin_queue *admin_queue = &ena_dev->admin_queue; 139362306a36Sopenharmony_ci struct ena_admin_aq_create_cq_cmd create_cmd; 139462306a36Sopenharmony_ci struct ena_admin_acq_create_cq_resp_desc cmd_completion; 139562306a36Sopenharmony_ci int ret; 139662306a36Sopenharmony_ci 139762306a36Sopenharmony_ci memset(&create_cmd, 0x0, sizeof(create_cmd)); 139862306a36Sopenharmony_ci 139962306a36Sopenharmony_ci create_cmd.aq_common_descriptor.opcode = ENA_ADMIN_CREATE_CQ; 140062306a36Sopenharmony_ci 140162306a36Sopenharmony_ci create_cmd.cq_caps_2 |= (io_cq->cdesc_entry_size_in_bytes / 4) & 140262306a36Sopenharmony_ci ENA_ADMIN_AQ_CREATE_CQ_CMD_CQ_ENTRY_SIZE_WORDS_MASK; 140362306a36Sopenharmony_ci create_cmd.cq_caps_1 |= 140462306a36Sopenharmony_ci ENA_ADMIN_AQ_CREATE_CQ_CMD_INTERRUPT_MODE_ENABLED_MASK; 140562306a36Sopenharmony_ci 140662306a36Sopenharmony_ci create_cmd.msix_vector = io_cq->msix_vector; 140762306a36Sopenharmony_ci create_cmd.cq_depth = io_cq->q_depth; 140862306a36Sopenharmony_ci 140962306a36Sopenharmony_ci ret = ena_com_mem_addr_set(ena_dev, 141062306a36Sopenharmony_ci &create_cmd.cq_ba, 141162306a36Sopenharmony_ci io_cq->cdesc_addr.phys_addr); 141262306a36Sopenharmony_ci if (unlikely(ret)) { 141362306a36Sopenharmony_ci netdev_err(ena_dev->net_device, "Memory address set failed\n"); 141462306a36Sopenharmony_ci return ret; 141562306a36Sopenharmony_ci } 141662306a36Sopenharmony_ci 141762306a36Sopenharmony_ci ret = ena_com_execute_admin_command(admin_queue, 141862306a36Sopenharmony_ci (struct ena_admin_aq_entry *)&create_cmd, 141962306a36Sopenharmony_ci sizeof(create_cmd), 142062306a36Sopenharmony_ci (struct ena_admin_acq_entry *)&cmd_completion, 142162306a36Sopenharmony_ci sizeof(cmd_completion)); 142262306a36Sopenharmony_ci if (unlikely(ret)) { 142362306a36Sopenharmony_ci netdev_err(ena_dev->net_device, 142462306a36Sopenharmony_ci "Failed to create IO CQ. error: %d\n", ret); 142562306a36Sopenharmony_ci return ret; 142662306a36Sopenharmony_ci } 142762306a36Sopenharmony_ci 142862306a36Sopenharmony_ci io_cq->idx = cmd_completion.cq_idx; 142962306a36Sopenharmony_ci 143062306a36Sopenharmony_ci io_cq->unmask_reg = (u32 __iomem *)((uintptr_t)ena_dev->reg_bar + 143162306a36Sopenharmony_ci cmd_completion.cq_interrupt_unmask_register_offset); 143262306a36Sopenharmony_ci 143362306a36Sopenharmony_ci if (cmd_completion.cq_head_db_register_offset) 143462306a36Sopenharmony_ci io_cq->cq_head_db_reg = 143562306a36Sopenharmony_ci (u32 __iomem *)((uintptr_t)ena_dev->reg_bar + 143662306a36Sopenharmony_ci cmd_completion.cq_head_db_register_offset); 143762306a36Sopenharmony_ci 143862306a36Sopenharmony_ci if (cmd_completion.numa_node_register_offset) 143962306a36Sopenharmony_ci io_cq->numa_node_cfg_reg = 144062306a36Sopenharmony_ci (u32 __iomem *)((uintptr_t)ena_dev->reg_bar + 144162306a36Sopenharmony_ci cmd_completion.numa_node_register_offset); 144262306a36Sopenharmony_ci 144362306a36Sopenharmony_ci netdev_dbg(ena_dev->net_device, "Created cq[%u], depth[%u]\n", 144462306a36Sopenharmony_ci io_cq->idx, io_cq->q_depth); 144562306a36Sopenharmony_ci 144662306a36Sopenharmony_ci return ret; 144762306a36Sopenharmony_ci} 144862306a36Sopenharmony_ci 144962306a36Sopenharmony_ciint ena_com_get_io_handlers(struct ena_com_dev *ena_dev, u16 qid, 145062306a36Sopenharmony_ci struct ena_com_io_sq **io_sq, 145162306a36Sopenharmony_ci struct ena_com_io_cq **io_cq) 145262306a36Sopenharmony_ci{ 145362306a36Sopenharmony_ci if (qid >= ENA_TOTAL_NUM_QUEUES) { 145462306a36Sopenharmony_ci netdev_err(ena_dev->net_device, 145562306a36Sopenharmony_ci "Invalid queue number %d but the max is %d\n", qid, 145662306a36Sopenharmony_ci ENA_TOTAL_NUM_QUEUES); 145762306a36Sopenharmony_ci return -EINVAL; 145862306a36Sopenharmony_ci } 145962306a36Sopenharmony_ci 146062306a36Sopenharmony_ci *io_sq = &ena_dev->io_sq_queues[qid]; 146162306a36Sopenharmony_ci *io_cq = &ena_dev->io_cq_queues[qid]; 146262306a36Sopenharmony_ci 146362306a36Sopenharmony_ci return 0; 146462306a36Sopenharmony_ci} 146562306a36Sopenharmony_ci 146662306a36Sopenharmony_civoid ena_com_abort_admin_commands(struct ena_com_dev *ena_dev) 146762306a36Sopenharmony_ci{ 146862306a36Sopenharmony_ci struct ena_com_admin_queue *admin_queue = &ena_dev->admin_queue; 146962306a36Sopenharmony_ci struct ena_comp_ctx *comp_ctx; 147062306a36Sopenharmony_ci u16 i; 147162306a36Sopenharmony_ci 147262306a36Sopenharmony_ci if (!admin_queue->comp_ctx) 147362306a36Sopenharmony_ci return; 147462306a36Sopenharmony_ci 147562306a36Sopenharmony_ci for (i = 0; i < admin_queue->q_depth; i++) { 147662306a36Sopenharmony_ci comp_ctx = get_comp_ctxt(admin_queue, i, false); 147762306a36Sopenharmony_ci if (unlikely(!comp_ctx)) 147862306a36Sopenharmony_ci break; 147962306a36Sopenharmony_ci 148062306a36Sopenharmony_ci comp_ctx->status = ENA_CMD_ABORTED; 148162306a36Sopenharmony_ci 148262306a36Sopenharmony_ci complete(&comp_ctx->wait_event); 148362306a36Sopenharmony_ci } 148462306a36Sopenharmony_ci} 148562306a36Sopenharmony_ci 148662306a36Sopenharmony_civoid ena_com_wait_for_abort_completion(struct ena_com_dev *ena_dev) 148762306a36Sopenharmony_ci{ 148862306a36Sopenharmony_ci struct ena_com_admin_queue *admin_queue = &ena_dev->admin_queue; 148962306a36Sopenharmony_ci unsigned long flags = 0; 149062306a36Sopenharmony_ci u32 exp = 0; 149162306a36Sopenharmony_ci 149262306a36Sopenharmony_ci spin_lock_irqsave(&admin_queue->q_lock, flags); 149362306a36Sopenharmony_ci while (atomic_read(&admin_queue->outstanding_cmds) != 0) { 149462306a36Sopenharmony_ci spin_unlock_irqrestore(&admin_queue->q_lock, flags); 149562306a36Sopenharmony_ci ena_delay_exponential_backoff_us(exp++, 149662306a36Sopenharmony_ci ena_dev->ena_min_poll_delay_us); 149762306a36Sopenharmony_ci spin_lock_irqsave(&admin_queue->q_lock, flags); 149862306a36Sopenharmony_ci } 149962306a36Sopenharmony_ci spin_unlock_irqrestore(&admin_queue->q_lock, flags); 150062306a36Sopenharmony_ci} 150162306a36Sopenharmony_ci 150262306a36Sopenharmony_ciint ena_com_destroy_io_cq(struct ena_com_dev *ena_dev, 150362306a36Sopenharmony_ci struct ena_com_io_cq *io_cq) 150462306a36Sopenharmony_ci{ 150562306a36Sopenharmony_ci struct ena_com_admin_queue *admin_queue = &ena_dev->admin_queue; 150662306a36Sopenharmony_ci struct ena_admin_aq_destroy_cq_cmd destroy_cmd; 150762306a36Sopenharmony_ci struct ena_admin_acq_destroy_cq_resp_desc destroy_resp; 150862306a36Sopenharmony_ci int ret; 150962306a36Sopenharmony_ci 151062306a36Sopenharmony_ci memset(&destroy_cmd, 0x0, sizeof(destroy_cmd)); 151162306a36Sopenharmony_ci 151262306a36Sopenharmony_ci destroy_cmd.cq_idx = io_cq->idx; 151362306a36Sopenharmony_ci destroy_cmd.aq_common_descriptor.opcode = ENA_ADMIN_DESTROY_CQ; 151462306a36Sopenharmony_ci 151562306a36Sopenharmony_ci ret = ena_com_execute_admin_command(admin_queue, 151662306a36Sopenharmony_ci (struct ena_admin_aq_entry *)&destroy_cmd, 151762306a36Sopenharmony_ci sizeof(destroy_cmd), 151862306a36Sopenharmony_ci (struct ena_admin_acq_entry *)&destroy_resp, 151962306a36Sopenharmony_ci sizeof(destroy_resp)); 152062306a36Sopenharmony_ci 152162306a36Sopenharmony_ci if (unlikely(ret && (ret != -ENODEV))) 152262306a36Sopenharmony_ci netdev_err(ena_dev->net_device, 152362306a36Sopenharmony_ci "Failed to destroy IO CQ. error: %d\n", ret); 152462306a36Sopenharmony_ci 152562306a36Sopenharmony_ci return ret; 152662306a36Sopenharmony_ci} 152762306a36Sopenharmony_ci 152862306a36Sopenharmony_cibool ena_com_get_admin_running_state(struct ena_com_dev *ena_dev) 152962306a36Sopenharmony_ci{ 153062306a36Sopenharmony_ci return ena_dev->admin_queue.running_state; 153162306a36Sopenharmony_ci} 153262306a36Sopenharmony_ci 153362306a36Sopenharmony_civoid ena_com_set_admin_running_state(struct ena_com_dev *ena_dev, bool state) 153462306a36Sopenharmony_ci{ 153562306a36Sopenharmony_ci struct ena_com_admin_queue *admin_queue = &ena_dev->admin_queue; 153662306a36Sopenharmony_ci unsigned long flags = 0; 153762306a36Sopenharmony_ci 153862306a36Sopenharmony_ci spin_lock_irqsave(&admin_queue->q_lock, flags); 153962306a36Sopenharmony_ci ena_dev->admin_queue.running_state = state; 154062306a36Sopenharmony_ci spin_unlock_irqrestore(&admin_queue->q_lock, flags); 154162306a36Sopenharmony_ci} 154262306a36Sopenharmony_ci 154362306a36Sopenharmony_civoid ena_com_admin_aenq_enable(struct ena_com_dev *ena_dev) 154462306a36Sopenharmony_ci{ 154562306a36Sopenharmony_ci u16 depth = ena_dev->aenq.q_depth; 154662306a36Sopenharmony_ci 154762306a36Sopenharmony_ci WARN(ena_dev->aenq.head != depth, "Invalid AENQ state\n"); 154862306a36Sopenharmony_ci 154962306a36Sopenharmony_ci /* Init head_db to mark that all entries in the queue 155062306a36Sopenharmony_ci * are initially available 155162306a36Sopenharmony_ci */ 155262306a36Sopenharmony_ci writel(depth, ena_dev->reg_bar + ENA_REGS_AENQ_HEAD_DB_OFF); 155362306a36Sopenharmony_ci} 155462306a36Sopenharmony_ci 155562306a36Sopenharmony_ciint ena_com_set_aenq_config(struct ena_com_dev *ena_dev, u32 groups_flag) 155662306a36Sopenharmony_ci{ 155762306a36Sopenharmony_ci struct ena_com_admin_queue *admin_queue; 155862306a36Sopenharmony_ci struct ena_admin_set_feat_cmd cmd; 155962306a36Sopenharmony_ci struct ena_admin_set_feat_resp resp; 156062306a36Sopenharmony_ci struct ena_admin_get_feat_resp get_resp; 156162306a36Sopenharmony_ci int ret; 156262306a36Sopenharmony_ci 156362306a36Sopenharmony_ci ret = ena_com_get_feature(ena_dev, &get_resp, ENA_ADMIN_AENQ_CONFIG, 0); 156462306a36Sopenharmony_ci if (ret) { 156562306a36Sopenharmony_ci dev_info(ena_dev->dmadev, "Can't get aenq configuration\n"); 156662306a36Sopenharmony_ci return ret; 156762306a36Sopenharmony_ci } 156862306a36Sopenharmony_ci 156962306a36Sopenharmony_ci if ((get_resp.u.aenq.supported_groups & groups_flag) != groups_flag) { 157062306a36Sopenharmony_ci netdev_warn(ena_dev->net_device, 157162306a36Sopenharmony_ci "Trying to set unsupported aenq events. supported flag: 0x%x asked flag: 0x%x\n", 157262306a36Sopenharmony_ci get_resp.u.aenq.supported_groups, groups_flag); 157362306a36Sopenharmony_ci return -EOPNOTSUPP; 157462306a36Sopenharmony_ci } 157562306a36Sopenharmony_ci 157662306a36Sopenharmony_ci memset(&cmd, 0x0, sizeof(cmd)); 157762306a36Sopenharmony_ci admin_queue = &ena_dev->admin_queue; 157862306a36Sopenharmony_ci 157962306a36Sopenharmony_ci cmd.aq_common_descriptor.opcode = ENA_ADMIN_SET_FEATURE; 158062306a36Sopenharmony_ci cmd.aq_common_descriptor.flags = 0; 158162306a36Sopenharmony_ci cmd.feat_common.feature_id = ENA_ADMIN_AENQ_CONFIG; 158262306a36Sopenharmony_ci cmd.u.aenq.enabled_groups = groups_flag; 158362306a36Sopenharmony_ci 158462306a36Sopenharmony_ci ret = ena_com_execute_admin_command(admin_queue, 158562306a36Sopenharmony_ci (struct ena_admin_aq_entry *)&cmd, 158662306a36Sopenharmony_ci sizeof(cmd), 158762306a36Sopenharmony_ci (struct ena_admin_acq_entry *)&resp, 158862306a36Sopenharmony_ci sizeof(resp)); 158962306a36Sopenharmony_ci 159062306a36Sopenharmony_ci if (unlikely(ret)) 159162306a36Sopenharmony_ci netdev_err(ena_dev->net_device, 159262306a36Sopenharmony_ci "Failed to config AENQ ret: %d\n", ret); 159362306a36Sopenharmony_ci 159462306a36Sopenharmony_ci return ret; 159562306a36Sopenharmony_ci} 159662306a36Sopenharmony_ci 159762306a36Sopenharmony_ciint ena_com_get_dma_width(struct ena_com_dev *ena_dev) 159862306a36Sopenharmony_ci{ 159962306a36Sopenharmony_ci u32 caps = ena_com_reg_bar_read32(ena_dev, ENA_REGS_CAPS_OFF); 160062306a36Sopenharmony_ci u32 width; 160162306a36Sopenharmony_ci 160262306a36Sopenharmony_ci if (unlikely(caps == ENA_MMIO_READ_TIMEOUT)) { 160362306a36Sopenharmony_ci netdev_err(ena_dev->net_device, "Reg read timeout occurred\n"); 160462306a36Sopenharmony_ci return -ETIME; 160562306a36Sopenharmony_ci } 160662306a36Sopenharmony_ci 160762306a36Sopenharmony_ci width = (caps & ENA_REGS_CAPS_DMA_ADDR_WIDTH_MASK) >> 160862306a36Sopenharmony_ci ENA_REGS_CAPS_DMA_ADDR_WIDTH_SHIFT; 160962306a36Sopenharmony_ci 161062306a36Sopenharmony_ci netdev_dbg(ena_dev->net_device, "ENA dma width: %d\n", width); 161162306a36Sopenharmony_ci 161262306a36Sopenharmony_ci if ((width < 32) || width > ENA_MAX_PHYS_ADDR_SIZE_BITS) { 161362306a36Sopenharmony_ci netdev_err(ena_dev->net_device, "DMA width illegal value: %d\n", 161462306a36Sopenharmony_ci width); 161562306a36Sopenharmony_ci return -EINVAL; 161662306a36Sopenharmony_ci } 161762306a36Sopenharmony_ci 161862306a36Sopenharmony_ci ena_dev->dma_addr_bits = width; 161962306a36Sopenharmony_ci 162062306a36Sopenharmony_ci return width; 162162306a36Sopenharmony_ci} 162262306a36Sopenharmony_ci 162362306a36Sopenharmony_ciint ena_com_validate_version(struct ena_com_dev *ena_dev) 162462306a36Sopenharmony_ci{ 162562306a36Sopenharmony_ci u32 ver; 162662306a36Sopenharmony_ci u32 ctrl_ver; 162762306a36Sopenharmony_ci u32 ctrl_ver_masked; 162862306a36Sopenharmony_ci 162962306a36Sopenharmony_ci /* Make sure the ENA version and the controller version are at least 163062306a36Sopenharmony_ci * as the driver expects 163162306a36Sopenharmony_ci */ 163262306a36Sopenharmony_ci ver = ena_com_reg_bar_read32(ena_dev, ENA_REGS_VERSION_OFF); 163362306a36Sopenharmony_ci ctrl_ver = ena_com_reg_bar_read32(ena_dev, 163462306a36Sopenharmony_ci ENA_REGS_CONTROLLER_VERSION_OFF); 163562306a36Sopenharmony_ci 163662306a36Sopenharmony_ci if (unlikely((ver == ENA_MMIO_READ_TIMEOUT) || 163762306a36Sopenharmony_ci (ctrl_ver == ENA_MMIO_READ_TIMEOUT))) { 163862306a36Sopenharmony_ci netdev_err(ena_dev->net_device, "Reg read timeout occurred\n"); 163962306a36Sopenharmony_ci return -ETIME; 164062306a36Sopenharmony_ci } 164162306a36Sopenharmony_ci 164262306a36Sopenharmony_ci dev_info(ena_dev->dmadev, "ENA device version: %d.%d\n", 164362306a36Sopenharmony_ci (ver & ENA_REGS_VERSION_MAJOR_VERSION_MASK) >> 164462306a36Sopenharmony_ci ENA_REGS_VERSION_MAJOR_VERSION_SHIFT, 164562306a36Sopenharmony_ci ver & ENA_REGS_VERSION_MINOR_VERSION_MASK); 164662306a36Sopenharmony_ci 164762306a36Sopenharmony_ci dev_info(ena_dev->dmadev, 164862306a36Sopenharmony_ci "ENA controller version: %d.%d.%d implementation version %d\n", 164962306a36Sopenharmony_ci (ctrl_ver & ENA_REGS_CONTROLLER_VERSION_MAJOR_VERSION_MASK) >> 165062306a36Sopenharmony_ci ENA_REGS_CONTROLLER_VERSION_MAJOR_VERSION_SHIFT, 165162306a36Sopenharmony_ci (ctrl_ver & ENA_REGS_CONTROLLER_VERSION_MINOR_VERSION_MASK) >> 165262306a36Sopenharmony_ci ENA_REGS_CONTROLLER_VERSION_MINOR_VERSION_SHIFT, 165362306a36Sopenharmony_ci (ctrl_ver & ENA_REGS_CONTROLLER_VERSION_SUBMINOR_VERSION_MASK), 165462306a36Sopenharmony_ci (ctrl_ver & ENA_REGS_CONTROLLER_VERSION_IMPL_ID_MASK) >> 165562306a36Sopenharmony_ci ENA_REGS_CONTROLLER_VERSION_IMPL_ID_SHIFT); 165662306a36Sopenharmony_ci 165762306a36Sopenharmony_ci ctrl_ver_masked = 165862306a36Sopenharmony_ci (ctrl_ver & ENA_REGS_CONTROLLER_VERSION_MAJOR_VERSION_MASK) | 165962306a36Sopenharmony_ci (ctrl_ver & ENA_REGS_CONTROLLER_VERSION_MINOR_VERSION_MASK) | 166062306a36Sopenharmony_ci (ctrl_ver & ENA_REGS_CONTROLLER_VERSION_SUBMINOR_VERSION_MASK); 166162306a36Sopenharmony_ci 166262306a36Sopenharmony_ci /* Validate the ctrl version without the implementation ID */ 166362306a36Sopenharmony_ci if (ctrl_ver_masked < MIN_ENA_CTRL_VER) { 166462306a36Sopenharmony_ci netdev_err(ena_dev->net_device, 166562306a36Sopenharmony_ci "ENA ctrl version is lower than the minimal ctrl version the driver supports\n"); 166662306a36Sopenharmony_ci return -1; 166762306a36Sopenharmony_ci } 166862306a36Sopenharmony_ci 166962306a36Sopenharmony_ci return 0; 167062306a36Sopenharmony_ci} 167162306a36Sopenharmony_ci 167262306a36Sopenharmony_cistatic void 167362306a36Sopenharmony_ciena_com_free_ena_admin_queue_comp_ctx(struct ena_com_dev *ena_dev, 167462306a36Sopenharmony_ci struct ena_com_admin_queue *admin_queue) 167562306a36Sopenharmony_ci 167662306a36Sopenharmony_ci{ 167762306a36Sopenharmony_ci if (!admin_queue->comp_ctx) 167862306a36Sopenharmony_ci return; 167962306a36Sopenharmony_ci 168062306a36Sopenharmony_ci devm_kfree(ena_dev->dmadev, admin_queue->comp_ctx); 168162306a36Sopenharmony_ci 168262306a36Sopenharmony_ci admin_queue->comp_ctx = NULL; 168362306a36Sopenharmony_ci} 168462306a36Sopenharmony_ci 168562306a36Sopenharmony_civoid ena_com_admin_destroy(struct ena_com_dev *ena_dev) 168662306a36Sopenharmony_ci{ 168762306a36Sopenharmony_ci struct ena_com_admin_queue *admin_queue = &ena_dev->admin_queue; 168862306a36Sopenharmony_ci struct ena_com_admin_cq *cq = &admin_queue->cq; 168962306a36Sopenharmony_ci struct ena_com_admin_sq *sq = &admin_queue->sq; 169062306a36Sopenharmony_ci struct ena_com_aenq *aenq = &ena_dev->aenq; 169162306a36Sopenharmony_ci u16 size; 169262306a36Sopenharmony_ci 169362306a36Sopenharmony_ci ena_com_free_ena_admin_queue_comp_ctx(ena_dev, admin_queue); 169462306a36Sopenharmony_ci 169562306a36Sopenharmony_ci size = ADMIN_SQ_SIZE(admin_queue->q_depth); 169662306a36Sopenharmony_ci if (sq->entries) 169762306a36Sopenharmony_ci dma_free_coherent(ena_dev->dmadev, size, sq->entries, 169862306a36Sopenharmony_ci sq->dma_addr); 169962306a36Sopenharmony_ci sq->entries = NULL; 170062306a36Sopenharmony_ci 170162306a36Sopenharmony_ci size = ADMIN_CQ_SIZE(admin_queue->q_depth); 170262306a36Sopenharmony_ci if (cq->entries) 170362306a36Sopenharmony_ci dma_free_coherent(ena_dev->dmadev, size, cq->entries, 170462306a36Sopenharmony_ci cq->dma_addr); 170562306a36Sopenharmony_ci cq->entries = NULL; 170662306a36Sopenharmony_ci 170762306a36Sopenharmony_ci size = ADMIN_AENQ_SIZE(aenq->q_depth); 170862306a36Sopenharmony_ci if (ena_dev->aenq.entries) 170962306a36Sopenharmony_ci dma_free_coherent(ena_dev->dmadev, size, aenq->entries, 171062306a36Sopenharmony_ci aenq->dma_addr); 171162306a36Sopenharmony_ci aenq->entries = NULL; 171262306a36Sopenharmony_ci} 171362306a36Sopenharmony_ci 171462306a36Sopenharmony_civoid ena_com_set_admin_polling_mode(struct ena_com_dev *ena_dev, bool polling) 171562306a36Sopenharmony_ci{ 171662306a36Sopenharmony_ci u32 mask_value = 0; 171762306a36Sopenharmony_ci 171862306a36Sopenharmony_ci if (polling) 171962306a36Sopenharmony_ci mask_value = ENA_REGS_ADMIN_INTR_MASK; 172062306a36Sopenharmony_ci 172162306a36Sopenharmony_ci writel(mask_value, ena_dev->reg_bar + ENA_REGS_INTR_MASK_OFF); 172262306a36Sopenharmony_ci ena_dev->admin_queue.polling = polling; 172362306a36Sopenharmony_ci} 172462306a36Sopenharmony_ci 172562306a36Sopenharmony_civoid ena_com_set_admin_auto_polling_mode(struct ena_com_dev *ena_dev, 172662306a36Sopenharmony_ci bool polling) 172762306a36Sopenharmony_ci{ 172862306a36Sopenharmony_ci ena_dev->admin_queue.auto_polling = polling; 172962306a36Sopenharmony_ci} 173062306a36Sopenharmony_ci 173162306a36Sopenharmony_ciint ena_com_mmio_reg_read_request_init(struct ena_com_dev *ena_dev) 173262306a36Sopenharmony_ci{ 173362306a36Sopenharmony_ci struct ena_com_mmio_read *mmio_read = &ena_dev->mmio_read; 173462306a36Sopenharmony_ci 173562306a36Sopenharmony_ci spin_lock_init(&mmio_read->lock); 173662306a36Sopenharmony_ci mmio_read->read_resp = 173762306a36Sopenharmony_ci dma_alloc_coherent(ena_dev->dmadev, 173862306a36Sopenharmony_ci sizeof(*mmio_read->read_resp), 173962306a36Sopenharmony_ci &mmio_read->read_resp_dma_addr, GFP_KERNEL); 174062306a36Sopenharmony_ci if (unlikely(!mmio_read->read_resp)) 174162306a36Sopenharmony_ci goto err; 174262306a36Sopenharmony_ci 174362306a36Sopenharmony_ci ena_com_mmio_reg_read_request_write_dev_addr(ena_dev); 174462306a36Sopenharmony_ci 174562306a36Sopenharmony_ci mmio_read->read_resp->req_id = 0x0; 174662306a36Sopenharmony_ci mmio_read->seq_num = 0x0; 174762306a36Sopenharmony_ci mmio_read->readless_supported = true; 174862306a36Sopenharmony_ci 174962306a36Sopenharmony_ci return 0; 175062306a36Sopenharmony_ci 175162306a36Sopenharmony_cierr: 175262306a36Sopenharmony_ci 175362306a36Sopenharmony_ci return -ENOMEM; 175462306a36Sopenharmony_ci} 175562306a36Sopenharmony_ci 175662306a36Sopenharmony_civoid ena_com_set_mmio_read_mode(struct ena_com_dev *ena_dev, bool readless_supported) 175762306a36Sopenharmony_ci{ 175862306a36Sopenharmony_ci struct ena_com_mmio_read *mmio_read = &ena_dev->mmio_read; 175962306a36Sopenharmony_ci 176062306a36Sopenharmony_ci mmio_read->readless_supported = readless_supported; 176162306a36Sopenharmony_ci} 176262306a36Sopenharmony_ci 176362306a36Sopenharmony_civoid ena_com_mmio_reg_read_request_destroy(struct ena_com_dev *ena_dev) 176462306a36Sopenharmony_ci{ 176562306a36Sopenharmony_ci struct ena_com_mmio_read *mmio_read = &ena_dev->mmio_read; 176662306a36Sopenharmony_ci 176762306a36Sopenharmony_ci writel(0x0, ena_dev->reg_bar + ENA_REGS_MMIO_RESP_LO_OFF); 176862306a36Sopenharmony_ci writel(0x0, ena_dev->reg_bar + ENA_REGS_MMIO_RESP_HI_OFF); 176962306a36Sopenharmony_ci 177062306a36Sopenharmony_ci dma_free_coherent(ena_dev->dmadev, sizeof(*mmio_read->read_resp), 177162306a36Sopenharmony_ci mmio_read->read_resp, mmio_read->read_resp_dma_addr); 177262306a36Sopenharmony_ci 177362306a36Sopenharmony_ci mmio_read->read_resp = NULL; 177462306a36Sopenharmony_ci} 177562306a36Sopenharmony_ci 177662306a36Sopenharmony_civoid ena_com_mmio_reg_read_request_write_dev_addr(struct ena_com_dev *ena_dev) 177762306a36Sopenharmony_ci{ 177862306a36Sopenharmony_ci struct ena_com_mmio_read *mmio_read = &ena_dev->mmio_read; 177962306a36Sopenharmony_ci u32 addr_low, addr_high; 178062306a36Sopenharmony_ci 178162306a36Sopenharmony_ci addr_low = ENA_DMA_ADDR_TO_UINT32_LOW(mmio_read->read_resp_dma_addr); 178262306a36Sopenharmony_ci addr_high = ENA_DMA_ADDR_TO_UINT32_HIGH(mmio_read->read_resp_dma_addr); 178362306a36Sopenharmony_ci 178462306a36Sopenharmony_ci writel(addr_low, ena_dev->reg_bar + ENA_REGS_MMIO_RESP_LO_OFF); 178562306a36Sopenharmony_ci writel(addr_high, ena_dev->reg_bar + ENA_REGS_MMIO_RESP_HI_OFF); 178662306a36Sopenharmony_ci} 178762306a36Sopenharmony_ci 178862306a36Sopenharmony_ciint ena_com_admin_init(struct ena_com_dev *ena_dev, 178962306a36Sopenharmony_ci struct ena_aenq_handlers *aenq_handlers) 179062306a36Sopenharmony_ci{ 179162306a36Sopenharmony_ci struct ena_com_admin_queue *admin_queue = &ena_dev->admin_queue; 179262306a36Sopenharmony_ci u32 aq_caps, acq_caps, dev_sts, addr_low, addr_high; 179362306a36Sopenharmony_ci int ret; 179462306a36Sopenharmony_ci 179562306a36Sopenharmony_ci dev_sts = ena_com_reg_bar_read32(ena_dev, ENA_REGS_DEV_STS_OFF); 179662306a36Sopenharmony_ci 179762306a36Sopenharmony_ci if (unlikely(dev_sts == ENA_MMIO_READ_TIMEOUT)) { 179862306a36Sopenharmony_ci netdev_err(ena_dev->net_device, "Reg read timeout occurred\n"); 179962306a36Sopenharmony_ci return -ETIME; 180062306a36Sopenharmony_ci } 180162306a36Sopenharmony_ci 180262306a36Sopenharmony_ci if (!(dev_sts & ENA_REGS_DEV_STS_READY_MASK)) { 180362306a36Sopenharmony_ci netdev_err(ena_dev->net_device, 180462306a36Sopenharmony_ci "Device isn't ready, abort com init\n"); 180562306a36Sopenharmony_ci return -ENODEV; 180662306a36Sopenharmony_ci } 180762306a36Sopenharmony_ci 180862306a36Sopenharmony_ci admin_queue->q_depth = ENA_ADMIN_QUEUE_DEPTH; 180962306a36Sopenharmony_ci 181062306a36Sopenharmony_ci admin_queue->q_dmadev = ena_dev->dmadev; 181162306a36Sopenharmony_ci admin_queue->polling = false; 181262306a36Sopenharmony_ci admin_queue->curr_cmd_id = 0; 181362306a36Sopenharmony_ci 181462306a36Sopenharmony_ci atomic_set(&admin_queue->outstanding_cmds, 0); 181562306a36Sopenharmony_ci 181662306a36Sopenharmony_ci spin_lock_init(&admin_queue->q_lock); 181762306a36Sopenharmony_ci 181862306a36Sopenharmony_ci ret = ena_com_init_comp_ctxt(admin_queue); 181962306a36Sopenharmony_ci if (ret) 182062306a36Sopenharmony_ci goto error; 182162306a36Sopenharmony_ci 182262306a36Sopenharmony_ci ret = ena_com_admin_init_sq(admin_queue); 182362306a36Sopenharmony_ci if (ret) 182462306a36Sopenharmony_ci goto error; 182562306a36Sopenharmony_ci 182662306a36Sopenharmony_ci ret = ena_com_admin_init_cq(admin_queue); 182762306a36Sopenharmony_ci if (ret) 182862306a36Sopenharmony_ci goto error; 182962306a36Sopenharmony_ci 183062306a36Sopenharmony_ci admin_queue->sq.db_addr = (u32 __iomem *)((uintptr_t)ena_dev->reg_bar + 183162306a36Sopenharmony_ci ENA_REGS_AQ_DB_OFF); 183262306a36Sopenharmony_ci 183362306a36Sopenharmony_ci addr_low = ENA_DMA_ADDR_TO_UINT32_LOW(admin_queue->sq.dma_addr); 183462306a36Sopenharmony_ci addr_high = ENA_DMA_ADDR_TO_UINT32_HIGH(admin_queue->sq.dma_addr); 183562306a36Sopenharmony_ci 183662306a36Sopenharmony_ci writel(addr_low, ena_dev->reg_bar + ENA_REGS_AQ_BASE_LO_OFF); 183762306a36Sopenharmony_ci writel(addr_high, ena_dev->reg_bar + ENA_REGS_AQ_BASE_HI_OFF); 183862306a36Sopenharmony_ci 183962306a36Sopenharmony_ci addr_low = ENA_DMA_ADDR_TO_UINT32_LOW(admin_queue->cq.dma_addr); 184062306a36Sopenharmony_ci addr_high = ENA_DMA_ADDR_TO_UINT32_HIGH(admin_queue->cq.dma_addr); 184162306a36Sopenharmony_ci 184262306a36Sopenharmony_ci writel(addr_low, ena_dev->reg_bar + ENA_REGS_ACQ_BASE_LO_OFF); 184362306a36Sopenharmony_ci writel(addr_high, ena_dev->reg_bar + ENA_REGS_ACQ_BASE_HI_OFF); 184462306a36Sopenharmony_ci 184562306a36Sopenharmony_ci aq_caps = 0; 184662306a36Sopenharmony_ci aq_caps |= admin_queue->q_depth & ENA_REGS_AQ_CAPS_AQ_DEPTH_MASK; 184762306a36Sopenharmony_ci aq_caps |= (sizeof(struct ena_admin_aq_entry) << 184862306a36Sopenharmony_ci ENA_REGS_AQ_CAPS_AQ_ENTRY_SIZE_SHIFT) & 184962306a36Sopenharmony_ci ENA_REGS_AQ_CAPS_AQ_ENTRY_SIZE_MASK; 185062306a36Sopenharmony_ci 185162306a36Sopenharmony_ci acq_caps = 0; 185262306a36Sopenharmony_ci acq_caps |= admin_queue->q_depth & ENA_REGS_ACQ_CAPS_ACQ_DEPTH_MASK; 185362306a36Sopenharmony_ci acq_caps |= (sizeof(struct ena_admin_acq_entry) << 185462306a36Sopenharmony_ci ENA_REGS_ACQ_CAPS_ACQ_ENTRY_SIZE_SHIFT) & 185562306a36Sopenharmony_ci ENA_REGS_ACQ_CAPS_ACQ_ENTRY_SIZE_MASK; 185662306a36Sopenharmony_ci 185762306a36Sopenharmony_ci writel(aq_caps, ena_dev->reg_bar + ENA_REGS_AQ_CAPS_OFF); 185862306a36Sopenharmony_ci writel(acq_caps, ena_dev->reg_bar + ENA_REGS_ACQ_CAPS_OFF); 185962306a36Sopenharmony_ci ret = ena_com_admin_init_aenq(ena_dev, aenq_handlers); 186062306a36Sopenharmony_ci if (ret) 186162306a36Sopenharmony_ci goto error; 186262306a36Sopenharmony_ci 186362306a36Sopenharmony_ci admin_queue->ena_dev = ena_dev; 186462306a36Sopenharmony_ci admin_queue->running_state = true; 186562306a36Sopenharmony_ci 186662306a36Sopenharmony_ci return 0; 186762306a36Sopenharmony_cierror: 186862306a36Sopenharmony_ci ena_com_admin_destroy(ena_dev); 186962306a36Sopenharmony_ci 187062306a36Sopenharmony_ci return ret; 187162306a36Sopenharmony_ci} 187262306a36Sopenharmony_ci 187362306a36Sopenharmony_ciint ena_com_create_io_queue(struct ena_com_dev *ena_dev, 187462306a36Sopenharmony_ci struct ena_com_create_io_ctx *ctx) 187562306a36Sopenharmony_ci{ 187662306a36Sopenharmony_ci struct ena_com_io_sq *io_sq; 187762306a36Sopenharmony_ci struct ena_com_io_cq *io_cq; 187862306a36Sopenharmony_ci int ret; 187962306a36Sopenharmony_ci 188062306a36Sopenharmony_ci if (ctx->qid >= ENA_TOTAL_NUM_QUEUES) { 188162306a36Sopenharmony_ci netdev_err(ena_dev->net_device, 188262306a36Sopenharmony_ci "Qid (%d) is bigger than max num of queues (%d)\n", 188362306a36Sopenharmony_ci ctx->qid, ENA_TOTAL_NUM_QUEUES); 188462306a36Sopenharmony_ci return -EINVAL; 188562306a36Sopenharmony_ci } 188662306a36Sopenharmony_ci 188762306a36Sopenharmony_ci io_sq = &ena_dev->io_sq_queues[ctx->qid]; 188862306a36Sopenharmony_ci io_cq = &ena_dev->io_cq_queues[ctx->qid]; 188962306a36Sopenharmony_ci 189062306a36Sopenharmony_ci memset(io_sq, 0x0, sizeof(*io_sq)); 189162306a36Sopenharmony_ci memset(io_cq, 0x0, sizeof(*io_cq)); 189262306a36Sopenharmony_ci 189362306a36Sopenharmony_ci /* Init CQ */ 189462306a36Sopenharmony_ci io_cq->q_depth = ctx->queue_size; 189562306a36Sopenharmony_ci io_cq->direction = ctx->direction; 189662306a36Sopenharmony_ci io_cq->qid = ctx->qid; 189762306a36Sopenharmony_ci 189862306a36Sopenharmony_ci io_cq->msix_vector = ctx->msix_vector; 189962306a36Sopenharmony_ci 190062306a36Sopenharmony_ci io_sq->q_depth = ctx->queue_size; 190162306a36Sopenharmony_ci io_sq->direction = ctx->direction; 190262306a36Sopenharmony_ci io_sq->qid = ctx->qid; 190362306a36Sopenharmony_ci 190462306a36Sopenharmony_ci io_sq->mem_queue_type = ctx->mem_queue_type; 190562306a36Sopenharmony_ci 190662306a36Sopenharmony_ci if (ctx->direction == ENA_COM_IO_QUEUE_DIRECTION_TX) 190762306a36Sopenharmony_ci /* header length is limited to 8 bits */ 190862306a36Sopenharmony_ci io_sq->tx_max_header_size = 190962306a36Sopenharmony_ci min_t(u32, ena_dev->tx_max_header_size, SZ_256); 191062306a36Sopenharmony_ci 191162306a36Sopenharmony_ci ret = ena_com_init_io_sq(ena_dev, ctx, io_sq); 191262306a36Sopenharmony_ci if (ret) 191362306a36Sopenharmony_ci goto error; 191462306a36Sopenharmony_ci ret = ena_com_init_io_cq(ena_dev, ctx, io_cq); 191562306a36Sopenharmony_ci if (ret) 191662306a36Sopenharmony_ci goto error; 191762306a36Sopenharmony_ci 191862306a36Sopenharmony_ci ret = ena_com_create_io_cq(ena_dev, io_cq); 191962306a36Sopenharmony_ci if (ret) 192062306a36Sopenharmony_ci goto error; 192162306a36Sopenharmony_ci 192262306a36Sopenharmony_ci ret = ena_com_create_io_sq(ena_dev, io_sq, io_cq->idx); 192362306a36Sopenharmony_ci if (ret) 192462306a36Sopenharmony_ci goto destroy_io_cq; 192562306a36Sopenharmony_ci 192662306a36Sopenharmony_ci return 0; 192762306a36Sopenharmony_ci 192862306a36Sopenharmony_cidestroy_io_cq: 192962306a36Sopenharmony_ci ena_com_destroy_io_cq(ena_dev, io_cq); 193062306a36Sopenharmony_cierror: 193162306a36Sopenharmony_ci ena_com_io_queue_free(ena_dev, io_sq, io_cq); 193262306a36Sopenharmony_ci return ret; 193362306a36Sopenharmony_ci} 193462306a36Sopenharmony_ci 193562306a36Sopenharmony_civoid ena_com_destroy_io_queue(struct ena_com_dev *ena_dev, u16 qid) 193662306a36Sopenharmony_ci{ 193762306a36Sopenharmony_ci struct ena_com_io_sq *io_sq; 193862306a36Sopenharmony_ci struct ena_com_io_cq *io_cq; 193962306a36Sopenharmony_ci 194062306a36Sopenharmony_ci if (qid >= ENA_TOTAL_NUM_QUEUES) { 194162306a36Sopenharmony_ci netdev_err(ena_dev->net_device, 194262306a36Sopenharmony_ci "Qid (%d) is bigger than max num of queues (%d)\n", 194362306a36Sopenharmony_ci qid, ENA_TOTAL_NUM_QUEUES); 194462306a36Sopenharmony_ci return; 194562306a36Sopenharmony_ci } 194662306a36Sopenharmony_ci 194762306a36Sopenharmony_ci io_sq = &ena_dev->io_sq_queues[qid]; 194862306a36Sopenharmony_ci io_cq = &ena_dev->io_cq_queues[qid]; 194962306a36Sopenharmony_ci 195062306a36Sopenharmony_ci ena_com_destroy_io_sq(ena_dev, io_sq); 195162306a36Sopenharmony_ci ena_com_destroy_io_cq(ena_dev, io_cq); 195262306a36Sopenharmony_ci 195362306a36Sopenharmony_ci ena_com_io_queue_free(ena_dev, io_sq, io_cq); 195462306a36Sopenharmony_ci} 195562306a36Sopenharmony_ci 195662306a36Sopenharmony_ciint ena_com_get_link_params(struct ena_com_dev *ena_dev, 195762306a36Sopenharmony_ci struct ena_admin_get_feat_resp *resp) 195862306a36Sopenharmony_ci{ 195962306a36Sopenharmony_ci return ena_com_get_feature(ena_dev, resp, ENA_ADMIN_LINK_CONFIG, 0); 196062306a36Sopenharmony_ci} 196162306a36Sopenharmony_ci 196262306a36Sopenharmony_ciint ena_com_get_dev_attr_feat(struct ena_com_dev *ena_dev, 196362306a36Sopenharmony_ci struct ena_com_dev_get_features_ctx *get_feat_ctx) 196462306a36Sopenharmony_ci{ 196562306a36Sopenharmony_ci struct ena_admin_get_feat_resp get_resp; 196662306a36Sopenharmony_ci int rc; 196762306a36Sopenharmony_ci 196862306a36Sopenharmony_ci rc = ena_com_get_feature(ena_dev, &get_resp, 196962306a36Sopenharmony_ci ENA_ADMIN_DEVICE_ATTRIBUTES, 0); 197062306a36Sopenharmony_ci if (rc) 197162306a36Sopenharmony_ci return rc; 197262306a36Sopenharmony_ci 197362306a36Sopenharmony_ci memcpy(&get_feat_ctx->dev_attr, &get_resp.u.dev_attr, 197462306a36Sopenharmony_ci sizeof(get_resp.u.dev_attr)); 197562306a36Sopenharmony_ci 197662306a36Sopenharmony_ci ena_dev->supported_features = get_resp.u.dev_attr.supported_features; 197762306a36Sopenharmony_ci ena_dev->capabilities = get_resp.u.dev_attr.capabilities; 197862306a36Sopenharmony_ci 197962306a36Sopenharmony_ci if (ena_dev->supported_features & BIT(ENA_ADMIN_MAX_QUEUES_EXT)) { 198062306a36Sopenharmony_ci rc = ena_com_get_feature(ena_dev, &get_resp, 198162306a36Sopenharmony_ci ENA_ADMIN_MAX_QUEUES_EXT, 198262306a36Sopenharmony_ci ENA_FEATURE_MAX_QUEUE_EXT_VER); 198362306a36Sopenharmony_ci if (rc) 198462306a36Sopenharmony_ci return rc; 198562306a36Sopenharmony_ci 198662306a36Sopenharmony_ci if (get_resp.u.max_queue_ext.version != 198762306a36Sopenharmony_ci ENA_FEATURE_MAX_QUEUE_EXT_VER) 198862306a36Sopenharmony_ci return -EINVAL; 198962306a36Sopenharmony_ci 199062306a36Sopenharmony_ci memcpy(&get_feat_ctx->max_queue_ext, &get_resp.u.max_queue_ext, 199162306a36Sopenharmony_ci sizeof(get_resp.u.max_queue_ext)); 199262306a36Sopenharmony_ci ena_dev->tx_max_header_size = 199362306a36Sopenharmony_ci get_resp.u.max_queue_ext.max_queue_ext.max_tx_header_size; 199462306a36Sopenharmony_ci } else { 199562306a36Sopenharmony_ci rc = ena_com_get_feature(ena_dev, &get_resp, 199662306a36Sopenharmony_ci ENA_ADMIN_MAX_QUEUES_NUM, 0); 199762306a36Sopenharmony_ci memcpy(&get_feat_ctx->max_queues, &get_resp.u.max_queue, 199862306a36Sopenharmony_ci sizeof(get_resp.u.max_queue)); 199962306a36Sopenharmony_ci ena_dev->tx_max_header_size = 200062306a36Sopenharmony_ci get_resp.u.max_queue.max_header_size; 200162306a36Sopenharmony_ci 200262306a36Sopenharmony_ci if (rc) 200362306a36Sopenharmony_ci return rc; 200462306a36Sopenharmony_ci } 200562306a36Sopenharmony_ci 200662306a36Sopenharmony_ci rc = ena_com_get_feature(ena_dev, &get_resp, 200762306a36Sopenharmony_ci ENA_ADMIN_AENQ_CONFIG, 0); 200862306a36Sopenharmony_ci if (rc) 200962306a36Sopenharmony_ci return rc; 201062306a36Sopenharmony_ci 201162306a36Sopenharmony_ci memcpy(&get_feat_ctx->aenq, &get_resp.u.aenq, 201262306a36Sopenharmony_ci sizeof(get_resp.u.aenq)); 201362306a36Sopenharmony_ci 201462306a36Sopenharmony_ci rc = ena_com_get_feature(ena_dev, &get_resp, 201562306a36Sopenharmony_ci ENA_ADMIN_STATELESS_OFFLOAD_CONFIG, 0); 201662306a36Sopenharmony_ci if (rc) 201762306a36Sopenharmony_ci return rc; 201862306a36Sopenharmony_ci 201962306a36Sopenharmony_ci memcpy(&get_feat_ctx->offload, &get_resp.u.offload, 202062306a36Sopenharmony_ci sizeof(get_resp.u.offload)); 202162306a36Sopenharmony_ci 202262306a36Sopenharmony_ci /* Driver hints isn't mandatory admin command. So in case the 202362306a36Sopenharmony_ci * command isn't supported set driver hints to 0 202462306a36Sopenharmony_ci */ 202562306a36Sopenharmony_ci rc = ena_com_get_feature(ena_dev, &get_resp, ENA_ADMIN_HW_HINTS, 0); 202662306a36Sopenharmony_ci 202762306a36Sopenharmony_ci if (!rc) 202862306a36Sopenharmony_ci memcpy(&get_feat_ctx->hw_hints, &get_resp.u.hw_hints, 202962306a36Sopenharmony_ci sizeof(get_resp.u.hw_hints)); 203062306a36Sopenharmony_ci else if (rc == -EOPNOTSUPP) 203162306a36Sopenharmony_ci memset(&get_feat_ctx->hw_hints, 0x0, 203262306a36Sopenharmony_ci sizeof(get_feat_ctx->hw_hints)); 203362306a36Sopenharmony_ci else 203462306a36Sopenharmony_ci return rc; 203562306a36Sopenharmony_ci 203662306a36Sopenharmony_ci rc = ena_com_get_feature(ena_dev, &get_resp, ENA_ADMIN_LLQ, 0); 203762306a36Sopenharmony_ci if (!rc) 203862306a36Sopenharmony_ci memcpy(&get_feat_ctx->llq, &get_resp.u.llq, 203962306a36Sopenharmony_ci sizeof(get_resp.u.llq)); 204062306a36Sopenharmony_ci else if (rc == -EOPNOTSUPP) 204162306a36Sopenharmony_ci memset(&get_feat_ctx->llq, 0x0, sizeof(get_feat_ctx->llq)); 204262306a36Sopenharmony_ci else 204362306a36Sopenharmony_ci return rc; 204462306a36Sopenharmony_ci 204562306a36Sopenharmony_ci return 0; 204662306a36Sopenharmony_ci} 204762306a36Sopenharmony_ci 204862306a36Sopenharmony_civoid ena_com_admin_q_comp_intr_handler(struct ena_com_dev *ena_dev) 204962306a36Sopenharmony_ci{ 205062306a36Sopenharmony_ci ena_com_handle_admin_completion(&ena_dev->admin_queue); 205162306a36Sopenharmony_ci} 205262306a36Sopenharmony_ci 205362306a36Sopenharmony_ci/* ena_handle_specific_aenq_event: 205462306a36Sopenharmony_ci * return the handler that is relevant to the specific event group 205562306a36Sopenharmony_ci */ 205662306a36Sopenharmony_cistatic ena_aenq_handler ena_com_get_specific_aenq_cb(struct ena_com_dev *ena_dev, 205762306a36Sopenharmony_ci u16 group) 205862306a36Sopenharmony_ci{ 205962306a36Sopenharmony_ci struct ena_aenq_handlers *aenq_handlers = ena_dev->aenq.aenq_handlers; 206062306a36Sopenharmony_ci 206162306a36Sopenharmony_ci if ((group < ENA_MAX_HANDLERS) && aenq_handlers->handlers[group]) 206262306a36Sopenharmony_ci return aenq_handlers->handlers[group]; 206362306a36Sopenharmony_ci 206462306a36Sopenharmony_ci return aenq_handlers->unimplemented_handler; 206562306a36Sopenharmony_ci} 206662306a36Sopenharmony_ci 206762306a36Sopenharmony_ci/* ena_aenq_intr_handler: 206862306a36Sopenharmony_ci * handles the aenq incoming events. 206962306a36Sopenharmony_ci * pop events from the queue and apply the specific handler 207062306a36Sopenharmony_ci */ 207162306a36Sopenharmony_civoid ena_com_aenq_intr_handler(struct ena_com_dev *ena_dev, void *data) 207262306a36Sopenharmony_ci{ 207362306a36Sopenharmony_ci struct ena_admin_aenq_entry *aenq_e; 207462306a36Sopenharmony_ci struct ena_admin_aenq_common_desc *aenq_common; 207562306a36Sopenharmony_ci struct ena_com_aenq *aenq = &ena_dev->aenq; 207662306a36Sopenharmony_ci u64 timestamp; 207762306a36Sopenharmony_ci ena_aenq_handler handler_cb; 207862306a36Sopenharmony_ci u16 masked_head, processed = 0; 207962306a36Sopenharmony_ci u8 phase; 208062306a36Sopenharmony_ci 208162306a36Sopenharmony_ci masked_head = aenq->head & (aenq->q_depth - 1); 208262306a36Sopenharmony_ci phase = aenq->phase; 208362306a36Sopenharmony_ci aenq_e = &aenq->entries[masked_head]; /* Get first entry */ 208462306a36Sopenharmony_ci aenq_common = &aenq_e->aenq_common_desc; 208562306a36Sopenharmony_ci 208662306a36Sopenharmony_ci /* Go over all the events */ 208762306a36Sopenharmony_ci while ((READ_ONCE(aenq_common->flags) & 208862306a36Sopenharmony_ci ENA_ADMIN_AENQ_COMMON_DESC_PHASE_MASK) == phase) { 208962306a36Sopenharmony_ci /* Make sure the phase bit (ownership) is as expected before 209062306a36Sopenharmony_ci * reading the rest of the descriptor. 209162306a36Sopenharmony_ci */ 209262306a36Sopenharmony_ci dma_rmb(); 209362306a36Sopenharmony_ci 209462306a36Sopenharmony_ci timestamp = (u64)aenq_common->timestamp_low | 209562306a36Sopenharmony_ci ((u64)aenq_common->timestamp_high << 32); 209662306a36Sopenharmony_ci 209762306a36Sopenharmony_ci netdev_dbg(ena_dev->net_device, 209862306a36Sopenharmony_ci "AENQ! Group[%x] Syndrome[%x] timestamp: [%llus]\n", 209962306a36Sopenharmony_ci aenq_common->group, aenq_common->syndrome, timestamp); 210062306a36Sopenharmony_ci 210162306a36Sopenharmony_ci /* Handle specific event*/ 210262306a36Sopenharmony_ci handler_cb = ena_com_get_specific_aenq_cb(ena_dev, 210362306a36Sopenharmony_ci aenq_common->group); 210462306a36Sopenharmony_ci handler_cb(data, aenq_e); /* call the actual event handler*/ 210562306a36Sopenharmony_ci 210662306a36Sopenharmony_ci /* Get next event entry */ 210762306a36Sopenharmony_ci masked_head++; 210862306a36Sopenharmony_ci processed++; 210962306a36Sopenharmony_ci 211062306a36Sopenharmony_ci if (unlikely(masked_head == aenq->q_depth)) { 211162306a36Sopenharmony_ci masked_head = 0; 211262306a36Sopenharmony_ci phase = !phase; 211362306a36Sopenharmony_ci } 211462306a36Sopenharmony_ci aenq_e = &aenq->entries[masked_head]; 211562306a36Sopenharmony_ci aenq_common = &aenq_e->aenq_common_desc; 211662306a36Sopenharmony_ci } 211762306a36Sopenharmony_ci 211862306a36Sopenharmony_ci aenq->head += processed; 211962306a36Sopenharmony_ci aenq->phase = phase; 212062306a36Sopenharmony_ci 212162306a36Sopenharmony_ci /* Don't update aenq doorbell if there weren't any processed events */ 212262306a36Sopenharmony_ci if (!processed) 212362306a36Sopenharmony_ci return; 212462306a36Sopenharmony_ci 212562306a36Sopenharmony_ci /* write the aenq doorbell after all AENQ descriptors were read */ 212662306a36Sopenharmony_ci mb(); 212762306a36Sopenharmony_ci writel_relaxed((u32)aenq->head, 212862306a36Sopenharmony_ci ena_dev->reg_bar + ENA_REGS_AENQ_HEAD_DB_OFF); 212962306a36Sopenharmony_ci} 213062306a36Sopenharmony_ci 213162306a36Sopenharmony_ciint ena_com_dev_reset(struct ena_com_dev *ena_dev, 213262306a36Sopenharmony_ci enum ena_regs_reset_reason_types reset_reason) 213362306a36Sopenharmony_ci{ 213462306a36Sopenharmony_ci u32 stat, timeout, cap, reset_val; 213562306a36Sopenharmony_ci int rc; 213662306a36Sopenharmony_ci 213762306a36Sopenharmony_ci stat = ena_com_reg_bar_read32(ena_dev, ENA_REGS_DEV_STS_OFF); 213862306a36Sopenharmony_ci cap = ena_com_reg_bar_read32(ena_dev, ENA_REGS_CAPS_OFF); 213962306a36Sopenharmony_ci 214062306a36Sopenharmony_ci if (unlikely((stat == ENA_MMIO_READ_TIMEOUT) || 214162306a36Sopenharmony_ci (cap == ENA_MMIO_READ_TIMEOUT))) { 214262306a36Sopenharmony_ci netdev_err(ena_dev->net_device, "Reg read32 timeout occurred\n"); 214362306a36Sopenharmony_ci return -ETIME; 214462306a36Sopenharmony_ci } 214562306a36Sopenharmony_ci 214662306a36Sopenharmony_ci if ((stat & ENA_REGS_DEV_STS_READY_MASK) == 0) { 214762306a36Sopenharmony_ci netdev_err(ena_dev->net_device, 214862306a36Sopenharmony_ci "Device isn't ready, can't reset device\n"); 214962306a36Sopenharmony_ci return -EINVAL; 215062306a36Sopenharmony_ci } 215162306a36Sopenharmony_ci 215262306a36Sopenharmony_ci timeout = (cap & ENA_REGS_CAPS_RESET_TIMEOUT_MASK) >> 215362306a36Sopenharmony_ci ENA_REGS_CAPS_RESET_TIMEOUT_SHIFT; 215462306a36Sopenharmony_ci if (timeout == 0) { 215562306a36Sopenharmony_ci netdev_err(ena_dev->net_device, "Invalid timeout value\n"); 215662306a36Sopenharmony_ci return -EINVAL; 215762306a36Sopenharmony_ci } 215862306a36Sopenharmony_ci 215962306a36Sopenharmony_ci /* start reset */ 216062306a36Sopenharmony_ci reset_val = ENA_REGS_DEV_CTL_DEV_RESET_MASK; 216162306a36Sopenharmony_ci reset_val |= (reset_reason << ENA_REGS_DEV_CTL_RESET_REASON_SHIFT) & 216262306a36Sopenharmony_ci ENA_REGS_DEV_CTL_RESET_REASON_MASK; 216362306a36Sopenharmony_ci writel(reset_val, ena_dev->reg_bar + ENA_REGS_DEV_CTL_OFF); 216462306a36Sopenharmony_ci 216562306a36Sopenharmony_ci /* Write again the MMIO read request address */ 216662306a36Sopenharmony_ci ena_com_mmio_reg_read_request_write_dev_addr(ena_dev); 216762306a36Sopenharmony_ci 216862306a36Sopenharmony_ci rc = wait_for_reset_state(ena_dev, timeout, 216962306a36Sopenharmony_ci ENA_REGS_DEV_STS_RESET_IN_PROGRESS_MASK); 217062306a36Sopenharmony_ci if (rc != 0) { 217162306a36Sopenharmony_ci netdev_err(ena_dev->net_device, 217262306a36Sopenharmony_ci "Reset indication didn't turn on\n"); 217362306a36Sopenharmony_ci return rc; 217462306a36Sopenharmony_ci } 217562306a36Sopenharmony_ci 217662306a36Sopenharmony_ci /* reset done */ 217762306a36Sopenharmony_ci writel(0, ena_dev->reg_bar + ENA_REGS_DEV_CTL_OFF); 217862306a36Sopenharmony_ci rc = wait_for_reset_state(ena_dev, timeout, 0); 217962306a36Sopenharmony_ci if (rc != 0) { 218062306a36Sopenharmony_ci netdev_err(ena_dev->net_device, 218162306a36Sopenharmony_ci "Reset indication didn't turn off\n"); 218262306a36Sopenharmony_ci return rc; 218362306a36Sopenharmony_ci } 218462306a36Sopenharmony_ci 218562306a36Sopenharmony_ci timeout = (cap & ENA_REGS_CAPS_ADMIN_CMD_TO_MASK) >> 218662306a36Sopenharmony_ci ENA_REGS_CAPS_ADMIN_CMD_TO_SHIFT; 218762306a36Sopenharmony_ci if (timeout) 218862306a36Sopenharmony_ci /* the resolution of timeout reg is 100ms */ 218962306a36Sopenharmony_ci ena_dev->admin_queue.completion_timeout = timeout * 100000; 219062306a36Sopenharmony_ci else 219162306a36Sopenharmony_ci ena_dev->admin_queue.completion_timeout = ADMIN_CMD_TIMEOUT_US; 219262306a36Sopenharmony_ci 219362306a36Sopenharmony_ci return 0; 219462306a36Sopenharmony_ci} 219562306a36Sopenharmony_ci 219662306a36Sopenharmony_cistatic int ena_get_dev_stats(struct ena_com_dev *ena_dev, 219762306a36Sopenharmony_ci struct ena_com_stats_ctx *ctx, 219862306a36Sopenharmony_ci enum ena_admin_get_stats_type type) 219962306a36Sopenharmony_ci{ 220062306a36Sopenharmony_ci struct ena_admin_aq_get_stats_cmd *get_cmd = &ctx->get_cmd; 220162306a36Sopenharmony_ci struct ena_admin_acq_get_stats_resp *get_resp = &ctx->get_resp; 220262306a36Sopenharmony_ci struct ena_com_admin_queue *admin_queue; 220362306a36Sopenharmony_ci int ret; 220462306a36Sopenharmony_ci 220562306a36Sopenharmony_ci admin_queue = &ena_dev->admin_queue; 220662306a36Sopenharmony_ci 220762306a36Sopenharmony_ci get_cmd->aq_common_descriptor.opcode = ENA_ADMIN_GET_STATS; 220862306a36Sopenharmony_ci get_cmd->aq_common_descriptor.flags = 0; 220962306a36Sopenharmony_ci get_cmd->type = type; 221062306a36Sopenharmony_ci 221162306a36Sopenharmony_ci ret = ena_com_execute_admin_command(admin_queue, 221262306a36Sopenharmony_ci (struct ena_admin_aq_entry *)get_cmd, 221362306a36Sopenharmony_ci sizeof(*get_cmd), 221462306a36Sopenharmony_ci (struct ena_admin_acq_entry *)get_resp, 221562306a36Sopenharmony_ci sizeof(*get_resp)); 221662306a36Sopenharmony_ci 221762306a36Sopenharmony_ci if (unlikely(ret)) 221862306a36Sopenharmony_ci netdev_err(ena_dev->net_device, 221962306a36Sopenharmony_ci "Failed to get stats. error: %d\n", ret); 222062306a36Sopenharmony_ci 222162306a36Sopenharmony_ci return ret; 222262306a36Sopenharmony_ci} 222362306a36Sopenharmony_ci 222462306a36Sopenharmony_ciint ena_com_get_eni_stats(struct ena_com_dev *ena_dev, 222562306a36Sopenharmony_ci struct ena_admin_eni_stats *stats) 222662306a36Sopenharmony_ci{ 222762306a36Sopenharmony_ci struct ena_com_stats_ctx ctx; 222862306a36Sopenharmony_ci int ret; 222962306a36Sopenharmony_ci 223062306a36Sopenharmony_ci if (!ena_com_get_cap(ena_dev, ENA_ADMIN_ENI_STATS)) { 223162306a36Sopenharmony_ci netdev_err(ena_dev->net_device, 223262306a36Sopenharmony_ci "Capability %d isn't supported\n", 223362306a36Sopenharmony_ci ENA_ADMIN_ENI_STATS); 223462306a36Sopenharmony_ci return -EOPNOTSUPP; 223562306a36Sopenharmony_ci } 223662306a36Sopenharmony_ci 223762306a36Sopenharmony_ci memset(&ctx, 0x0, sizeof(ctx)); 223862306a36Sopenharmony_ci ret = ena_get_dev_stats(ena_dev, &ctx, ENA_ADMIN_GET_STATS_TYPE_ENI); 223962306a36Sopenharmony_ci if (likely(ret == 0)) 224062306a36Sopenharmony_ci memcpy(stats, &ctx.get_resp.u.eni_stats, 224162306a36Sopenharmony_ci sizeof(ctx.get_resp.u.eni_stats)); 224262306a36Sopenharmony_ci 224362306a36Sopenharmony_ci return ret; 224462306a36Sopenharmony_ci} 224562306a36Sopenharmony_ci 224662306a36Sopenharmony_ciint ena_com_get_dev_basic_stats(struct ena_com_dev *ena_dev, 224762306a36Sopenharmony_ci struct ena_admin_basic_stats *stats) 224862306a36Sopenharmony_ci{ 224962306a36Sopenharmony_ci struct ena_com_stats_ctx ctx; 225062306a36Sopenharmony_ci int ret; 225162306a36Sopenharmony_ci 225262306a36Sopenharmony_ci memset(&ctx, 0x0, sizeof(ctx)); 225362306a36Sopenharmony_ci ret = ena_get_dev_stats(ena_dev, &ctx, ENA_ADMIN_GET_STATS_TYPE_BASIC); 225462306a36Sopenharmony_ci if (likely(ret == 0)) 225562306a36Sopenharmony_ci memcpy(stats, &ctx.get_resp.u.basic_stats, 225662306a36Sopenharmony_ci sizeof(ctx.get_resp.u.basic_stats)); 225762306a36Sopenharmony_ci 225862306a36Sopenharmony_ci return ret; 225962306a36Sopenharmony_ci} 226062306a36Sopenharmony_ci 226162306a36Sopenharmony_ciint ena_com_set_dev_mtu(struct ena_com_dev *ena_dev, u32 mtu) 226262306a36Sopenharmony_ci{ 226362306a36Sopenharmony_ci struct ena_com_admin_queue *admin_queue; 226462306a36Sopenharmony_ci struct ena_admin_set_feat_cmd cmd; 226562306a36Sopenharmony_ci struct ena_admin_set_feat_resp resp; 226662306a36Sopenharmony_ci int ret; 226762306a36Sopenharmony_ci 226862306a36Sopenharmony_ci if (!ena_com_check_supported_feature_id(ena_dev, ENA_ADMIN_MTU)) { 226962306a36Sopenharmony_ci netdev_dbg(ena_dev->net_device, "Feature %d isn't supported\n", 227062306a36Sopenharmony_ci ENA_ADMIN_MTU); 227162306a36Sopenharmony_ci return -EOPNOTSUPP; 227262306a36Sopenharmony_ci } 227362306a36Sopenharmony_ci 227462306a36Sopenharmony_ci memset(&cmd, 0x0, sizeof(cmd)); 227562306a36Sopenharmony_ci admin_queue = &ena_dev->admin_queue; 227662306a36Sopenharmony_ci 227762306a36Sopenharmony_ci cmd.aq_common_descriptor.opcode = ENA_ADMIN_SET_FEATURE; 227862306a36Sopenharmony_ci cmd.aq_common_descriptor.flags = 0; 227962306a36Sopenharmony_ci cmd.feat_common.feature_id = ENA_ADMIN_MTU; 228062306a36Sopenharmony_ci cmd.u.mtu.mtu = mtu; 228162306a36Sopenharmony_ci 228262306a36Sopenharmony_ci ret = ena_com_execute_admin_command(admin_queue, 228362306a36Sopenharmony_ci (struct ena_admin_aq_entry *)&cmd, 228462306a36Sopenharmony_ci sizeof(cmd), 228562306a36Sopenharmony_ci (struct ena_admin_acq_entry *)&resp, 228662306a36Sopenharmony_ci sizeof(resp)); 228762306a36Sopenharmony_ci 228862306a36Sopenharmony_ci if (unlikely(ret)) 228962306a36Sopenharmony_ci netdev_err(ena_dev->net_device, 229062306a36Sopenharmony_ci "Failed to set mtu %d. error: %d\n", mtu, ret); 229162306a36Sopenharmony_ci 229262306a36Sopenharmony_ci return ret; 229362306a36Sopenharmony_ci} 229462306a36Sopenharmony_ci 229562306a36Sopenharmony_ciint ena_com_get_offload_settings(struct ena_com_dev *ena_dev, 229662306a36Sopenharmony_ci struct ena_admin_feature_offload_desc *offload) 229762306a36Sopenharmony_ci{ 229862306a36Sopenharmony_ci int ret; 229962306a36Sopenharmony_ci struct ena_admin_get_feat_resp resp; 230062306a36Sopenharmony_ci 230162306a36Sopenharmony_ci ret = ena_com_get_feature(ena_dev, &resp, 230262306a36Sopenharmony_ci ENA_ADMIN_STATELESS_OFFLOAD_CONFIG, 0); 230362306a36Sopenharmony_ci if (unlikely(ret)) { 230462306a36Sopenharmony_ci netdev_err(ena_dev->net_device, 230562306a36Sopenharmony_ci "Failed to get offload capabilities %d\n", ret); 230662306a36Sopenharmony_ci return ret; 230762306a36Sopenharmony_ci } 230862306a36Sopenharmony_ci 230962306a36Sopenharmony_ci memcpy(offload, &resp.u.offload, sizeof(resp.u.offload)); 231062306a36Sopenharmony_ci 231162306a36Sopenharmony_ci return 0; 231262306a36Sopenharmony_ci} 231362306a36Sopenharmony_ci 231462306a36Sopenharmony_ciint ena_com_set_hash_function(struct ena_com_dev *ena_dev) 231562306a36Sopenharmony_ci{ 231662306a36Sopenharmony_ci struct ena_com_admin_queue *admin_queue = &ena_dev->admin_queue; 231762306a36Sopenharmony_ci struct ena_rss *rss = &ena_dev->rss; 231862306a36Sopenharmony_ci struct ena_admin_set_feat_cmd cmd; 231962306a36Sopenharmony_ci struct ena_admin_set_feat_resp resp; 232062306a36Sopenharmony_ci struct ena_admin_get_feat_resp get_resp; 232162306a36Sopenharmony_ci int ret; 232262306a36Sopenharmony_ci 232362306a36Sopenharmony_ci if (!ena_com_check_supported_feature_id(ena_dev, 232462306a36Sopenharmony_ci ENA_ADMIN_RSS_HASH_FUNCTION)) { 232562306a36Sopenharmony_ci netdev_dbg(ena_dev->net_device, "Feature %d isn't supported\n", 232662306a36Sopenharmony_ci ENA_ADMIN_RSS_HASH_FUNCTION); 232762306a36Sopenharmony_ci return -EOPNOTSUPP; 232862306a36Sopenharmony_ci } 232962306a36Sopenharmony_ci 233062306a36Sopenharmony_ci /* Validate hash function is supported */ 233162306a36Sopenharmony_ci ret = ena_com_get_feature(ena_dev, &get_resp, 233262306a36Sopenharmony_ci ENA_ADMIN_RSS_HASH_FUNCTION, 0); 233362306a36Sopenharmony_ci if (unlikely(ret)) 233462306a36Sopenharmony_ci return ret; 233562306a36Sopenharmony_ci 233662306a36Sopenharmony_ci if (!(get_resp.u.flow_hash_func.supported_func & BIT(rss->hash_func))) { 233762306a36Sopenharmony_ci netdev_err(ena_dev->net_device, 233862306a36Sopenharmony_ci "Func hash %d isn't supported by device, abort\n", 233962306a36Sopenharmony_ci rss->hash_func); 234062306a36Sopenharmony_ci return -EOPNOTSUPP; 234162306a36Sopenharmony_ci } 234262306a36Sopenharmony_ci 234362306a36Sopenharmony_ci memset(&cmd, 0x0, sizeof(cmd)); 234462306a36Sopenharmony_ci 234562306a36Sopenharmony_ci cmd.aq_common_descriptor.opcode = ENA_ADMIN_SET_FEATURE; 234662306a36Sopenharmony_ci cmd.aq_common_descriptor.flags = 234762306a36Sopenharmony_ci ENA_ADMIN_AQ_COMMON_DESC_CTRL_DATA_INDIRECT_MASK; 234862306a36Sopenharmony_ci cmd.feat_common.feature_id = ENA_ADMIN_RSS_HASH_FUNCTION; 234962306a36Sopenharmony_ci cmd.u.flow_hash_func.init_val = rss->hash_init_val; 235062306a36Sopenharmony_ci cmd.u.flow_hash_func.selected_func = 1 << rss->hash_func; 235162306a36Sopenharmony_ci 235262306a36Sopenharmony_ci ret = ena_com_mem_addr_set(ena_dev, 235362306a36Sopenharmony_ci &cmd.control_buffer.address, 235462306a36Sopenharmony_ci rss->hash_key_dma_addr); 235562306a36Sopenharmony_ci if (unlikely(ret)) { 235662306a36Sopenharmony_ci netdev_err(ena_dev->net_device, "Memory address set failed\n"); 235762306a36Sopenharmony_ci return ret; 235862306a36Sopenharmony_ci } 235962306a36Sopenharmony_ci 236062306a36Sopenharmony_ci cmd.control_buffer.length = sizeof(*rss->hash_key); 236162306a36Sopenharmony_ci 236262306a36Sopenharmony_ci ret = ena_com_execute_admin_command(admin_queue, 236362306a36Sopenharmony_ci (struct ena_admin_aq_entry *)&cmd, 236462306a36Sopenharmony_ci sizeof(cmd), 236562306a36Sopenharmony_ci (struct ena_admin_acq_entry *)&resp, 236662306a36Sopenharmony_ci sizeof(resp)); 236762306a36Sopenharmony_ci if (unlikely(ret)) { 236862306a36Sopenharmony_ci netdev_err(ena_dev->net_device, 236962306a36Sopenharmony_ci "Failed to set hash function %d. error: %d\n", 237062306a36Sopenharmony_ci rss->hash_func, ret); 237162306a36Sopenharmony_ci return -EINVAL; 237262306a36Sopenharmony_ci } 237362306a36Sopenharmony_ci 237462306a36Sopenharmony_ci return 0; 237562306a36Sopenharmony_ci} 237662306a36Sopenharmony_ci 237762306a36Sopenharmony_ciint ena_com_fill_hash_function(struct ena_com_dev *ena_dev, 237862306a36Sopenharmony_ci enum ena_admin_hash_functions func, 237962306a36Sopenharmony_ci const u8 *key, u16 key_len, u32 init_val) 238062306a36Sopenharmony_ci{ 238162306a36Sopenharmony_ci struct ena_admin_feature_rss_flow_hash_control *hash_key; 238262306a36Sopenharmony_ci struct ena_admin_get_feat_resp get_resp; 238362306a36Sopenharmony_ci enum ena_admin_hash_functions old_func; 238462306a36Sopenharmony_ci struct ena_rss *rss = &ena_dev->rss; 238562306a36Sopenharmony_ci int rc; 238662306a36Sopenharmony_ci 238762306a36Sopenharmony_ci hash_key = rss->hash_key; 238862306a36Sopenharmony_ci 238962306a36Sopenharmony_ci /* Make sure size is a mult of DWs */ 239062306a36Sopenharmony_ci if (unlikely(key_len & 0x3)) 239162306a36Sopenharmony_ci return -EINVAL; 239262306a36Sopenharmony_ci 239362306a36Sopenharmony_ci rc = ena_com_get_feature_ex(ena_dev, &get_resp, 239462306a36Sopenharmony_ci ENA_ADMIN_RSS_HASH_FUNCTION, 239562306a36Sopenharmony_ci rss->hash_key_dma_addr, 239662306a36Sopenharmony_ci sizeof(*rss->hash_key), 0); 239762306a36Sopenharmony_ci if (unlikely(rc)) 239862306a36Sopenharmony_ci return rc; 239962306a36Sopenharmony_ci 240062306a36Sopenharmony_ci if (!(BIT(func) & get_resp.u.flow_hash_func.supported_func)) { 240162306a36Sopenharmony_ci netdev_err(ena_dev->net_device, 240262306a36Sopenharmony_ci "Flow hash function %d isn't supported\n", func); 240362306a36Sopenharmony_ci return -EOPNOTSUPP; 240462306a36Sopenharmony_ci } 240562306a36Sopenharmony_ci 240662306a36Sopenharmony_ci if ((func == ENA_ADMIN_TOEPLITZ) && key) { 240762306a36Sopenharmony_ci if (key_len != sizeof(hash_key->key)) { 240862306a36Sopenharmony_ci netdev_err(ena_dev->net_device, 240962306a36Sopenharmony_ci "key len (%u) doesn't equal the supported size (%zu)\n", 241062306a36Sopenharmony_ci key_len, sizeof(hash_key->key)); 241162306a36Sopenharmony_ci return -EINVAL; 241262306a36Sopenharmony_ci } 241362306a36Sopenharmony_ci memcpy(hash_key->key, key, key_len); 241462306a36Sopenharmony_ci hash_key->key_parts = key_len / sizeof(hash_key->key[0]); 241562306a36Sopenharmony_ci } 241662306a36Sopenharmony_ci 241762306a36Sopenharmony_ci rss->hash_init_val = init_val; 241862306a36Sopenharmony_ci old_func = rss->hash_func; 241962306a36Sopenharmony_ci rss->hash_func = func; 242062306a36Sopenharmony_ci rc = ena_com_set_hash_function(ena_dev); 242162306a36Sopenharmony_ci 242262306a36Sopenharmony_ci /* Restore the old function */ 242362306a36Sopenharmony_ci if (unlikely(rc)) 242462306a36Sopenharmony_ci rss->hash_func = old_func; 242562306a36Sopenharmony_ci 242662306a36Sopenharmony_ci return rc; 242762306a36Sopenharmony_ci} 242862306a36Sopenharmony_ci 242962306a36Sopenharmony_ciint ena_com_get_hash_function(struct ena_com_dev *ena_dev, 243062306a36Sopenharmony_ci enum ena_admin_hash_functions *func) 243162306a36Sopenharmony_ci{ 243262306a36Sopenharmony_ci struct ena_rss *rss = &ena_dev->rss; 243362306a36Sopenharmony_ci struct ena_admin_get_feat_resp get_resp; 243462306a36Sopenharmony_ci int rc; 243562306a36Sopenharmony_ci 243662306a36Sopenharmony_ci if (unlikely(!func)) 243762306a36Sopenharmony_ci return -EINVAL; 243862306a36Sopenharmony_ci 243962306a36Sopenharmony_ci rc = ena_com_get_feature_ex(ena_dev, &get_resp, 244062306a36Sopenharmony_ci ENA_ADMIN_RSS_HASH_FUNCTION, 244162306a36Sopenharmony_ci rss->hash_key_dma_addr, 244262306a36Sopenharmony_ci sizeof(*rss->hash_key), 0); 244362306a36Sopenharmony_ci if (unlikely(rc)) 244462306a36Sopenharmony_ci return rc; 244562306a36Sopenharmony_ci 244662306a36Sopenharmony_ci /* ffs() returns 1 in case the lsb is set */ 244762306a36Sopenharmony_ci rss->hash_func = ffs(get_resp.u.flow_hash_func.selected_func); 244862306a36Sopenharmony_ci if (rss->hash_func) 244962306a36Sopenharmony_ci rss->hash_func--; 245062306a36Sopenharmony_ci 245162306a36Sopenharmony_ci *func = rss->hash_func; 245262306a36Sopenharmony_ci 245362306a36Sopenharmony_ci return 0; 245462306a36Sopenharmony_ci} 245562306a36Sopenharmony_ci 245662306a36Sopenharmony_ciint ena_com_get_hash_key(struct ena_com_dev *ena_dev, u8 *key) 245762306a36Sopenharmony_ci{ 245862306a36Sopenharmony_ci struct ena_admin_feature_rss_flow_hash_control *hash_key = 245962306a36Sopenharmony_ci ena_dev->rss.hash_key; 246062306a36Sopenharmony_ci 246162306a36Sopenharmony_ci if (key) 246262306a36Sopenharmony_ci memcpy(key, hash_key->key, 246362306a36Sopenharmony_ci (size_t)(hash_key->key_parts) * sizeof(hash_key->key[0])); 246462306a36Sopenharmony_ci 246562306a36Sopenharmony_ci return 0; 246662306a36Sopenharmony_ci} 246762306a36Sopenharmony_ci 246862306a36Sopenharmony_ciint ena_com_get_hash_ctrl(struct ena_com_dev *ena_dev, 246962306a36Sopenharmony_ci enum ena_admin_flow_hash_proto proto, 247062306a36Sopenharmony_ci u16 *fields) 247162306a36Sopenharmony_ci{ 247262306a36Sopenharmony_ci struct ena_rss *rss = &ena_dev->rss; 247362306a36Sopenharmony_ci struct ena_admin_get_feat_resp get_resp; 247462306a36Sopenharmony_ci int rc; 247562306a36Sopenharmony_ci 247662306a36Sopenharmony_ci rc = ena_com_get_feature_ex(ena_dev, &get_resp, 247762306a36Sopenharmony_ci ENA_ADMIN_RSS_HASH_INPUT, 247862306a36Sopenharmony_ci rss->hash_ctrl_dma_addr, 247962306a36Sopenharmony_ci sizeof(*rss->hash_ctrl), 0); 248062306a36Sopenharmony_ci if (unlikely(rc)) 248162306a36Sopenharmony_ci return rc; 248262306a36Sopenharmony_ci 248362306a36Sopenharmony_ci if (fields) 248462306a36Sopenharmony_ci *fields = rss->hash_ctrl->selected_fields[proto].fields; 248562306a36Sopenharmony_ci 248662306a36Sopenharmony_ci return 0; 248762306a36Sopenharmony_ci} 248862306a36Sopenharmony_ci 248962306a36Sopenharmony_ciint ena_com_set_hash_ctrl(struct ena_com_dev *ena_dev) 249062306a36Sopenharmony_ci{ 249162306a36Sopenharmony_ci struct ena_com_admin_queue *admin_queue = &ena_dev->admin_queue; 249262306a36Sopenharmony_ci struct ena_rss *rss = &ena_dev->rss; 249362306a36Sopenharmony_ci struct ena_admin_feature_rss_hash_control *hash_ctrl = rss->hash_ctrl; 249462306a36Sopenharmony_ci struct ena_admin_set_feat_cmd cmd; 249562306a36Sopenharmony_ci struct ena_admin_set_feat_resp resp; 249662306a36Sopenharmony_ci int ret; 249762306a36Sopenharmony_ci 249862306a36Sopenharmony_ci if (!ena_com_check_supported_feature_id(ena_dev, 249962306a36Sopenharmony_ci ENA_ADMIN_RSS_HASH_INPUT)) { 250062306a36Sopenharmony_ci netdev_dbg(ena_dev->net_device, "Feature %d isn't supported\n", 250162306a36Sopenharmony_ci ENA_ADMIN_RSS_HASH_INPUT); 250262306a36Sopenharmony_ci return -EOPNOTSUPP; 250362306a36Sopenharmony_ci } 250462306a36Sopenharmony_ci 250562306a36Sopenharmony_ci memset(&cmd, 0x0, sizeof(cmd)); 250662306a36Sopenharmony_ci 250762306a36Sopenharmony_ci cmd.aq_common_descriptor.opcode = ENA_ADMIN_SET_FEATURE; 250862306a36Sopenharmony_ci cmd.aq_common_descriptor.flags = 250962306a36Sopenharmony_ci ENA_ADMIN_AQ_COMMON_DESC_CTRL_DATA_INDIRECT_MASK; 251062306a36Sopenharmony_ci cmd.feat_common.feature_id = ENA_ADMIN_RSS_HASH_INPUT; 251162306a36Sopenharmony_ci cmd.u.flow_hash_input.enabled_input_sort = 251262306a36Sopenharmony_ci ENA_ADMIN_FEATURE_RSS_FLOW_HASH_INPUT_L3_SORT_MASK | 251362306a36Sopenharmony_ci ENA_ADMIN_FEATURE_RSS_FLOW_HASH_INPUT_L4_SORT_MASK; 251462306a36Sopenharmony_ci 251562306a36Sopenharmony_ci ret = ena_com_mem_addr_set(ena_dev, 251662306a36Sopenharmony_ci &cmd.control_buffer.address, 251762306a36Sopenharmony_ci rss->hash_ctrl_dma_addr); 251862306a36Sopenharmony_ci if (unlikely(ret)) { 251962306a36Sopenharmony_ci netdev_err(ena_dev->net_device, "Memory address set failed\n"); 252062306a36Sopenharmony_ci return ret; 252162306a36Sopenharmony_ci } 252262306a36Sopenharmony_ci cmd.control_buffer.length = sizeof(*hash_ctrl); 252362306a36Sopenharmony_ci 252462306a36Sopenharmony_ci ret = ena_com_execute_admin_command(admin_queue, 252562306a36Sopenharmony_ci (struct ena_admin_aq_entry *)&cmd, 252662306a36Sopenharmony_ci sizeof(cmd), 252762306a36Sopenharmony_ci (struct ena_admin_acq_entry *)&resp, 252862306a36Sopenharmony_ci sizeof(resp)); 252962306a36Sopenharmony_ci if (unlikely(ret)) 253062306a36Sopenharmony_ci netdev_err(ena_dev->net_device, 253162306a36Sopenharmony_ci "Failed to set hash input. error: %d\n", ret); 253262306a36Sopenharmony_ci 253362306a36Sopenharmony_ci return ret; 253462306a36Sopenharmony_ci} 253562306a36Sopenharmony_ci 253662306a36Sopenharmony_ciint ena_com_set_default_hash_ctrl(struct ena_com_dev *ena_dev) 253762306a36Sopenharmony_ci{ 253862306a36Sopenharmony_ci struct ena_rss *rss = &ena_dev->rss; 253962306a36Sopenharmony_ci struct ena_admin_feature_rss_hash_control *hash_ctrl = 254062306a36Sopenharmony_ci rss->hash_ctrl; 254162306a36Sopenharmony_ci u16 available_fields = 0; 254262306a36Sopenharmony_ci int rc, i; 254362306a36Sopenharmony_ci 254462306a36Sopenharmony_ci /* Get the supported hash input */ 254562306a36Sopenharmony_ci rc = ena_com_get_hash_ctrl(ena_dev, 0, NULL); 254662306a36Sopenharmony_ci if (unlikely(rc)) 254762306a36Sopenharmony_ci return rc; 254862306a36Sopenharmony_ci 254962306a36Sopenharmony_ci hash_ctrl->selected_fields[ENA_ADMIN_RSS_TCP4].fields = 255062306a36Sopenharmony_ci ENA_ADMIN_RSS_L3_SA | ENA_ADMIN_RSS_L3_DA | 255162306a36Sopenharmony_ci ENA_ADMIN_RSS_L4_DP | ENA_ADMIN_RSS_L4_SP; 255262306a36Sopenharmony_ci 255362306a36Sopenharmony_ci hash_ctrl->selected_fields[ENA_ADMIN_RSS_UDP4].fields = 255462306a36Sopenharmony_ci ENA_ADMIN_RSS_L3_SA | ENA_ADMIN_RSS_L3_DA | 255562306a36Sopenharmony_ci ENA_ADMIN_RSS_L4_DP | ENA_ADMIN_RSS_L4_SP; 255662306a36Sopenharmony_ci 255762306a36Sopenharmony_ci hash_ctrl->selected_fields[ENA_ADMIN_RSS_TCP6].fields = 255862306a36Sopenharmony_ci ENA_ADMIN_RSS_L3_SA | ENA_ADMIN_RSS_L3_DA | 255962306a36Sopenharmony_ci ENA_ADMIN_RSS_L4_DP | ENA_ADMIN_RSS_L4_SP; 256062306a36Sopenharmony_ci 256162306a36Sopenharmony_ci hash_ctrl->selected_fields[ENA_ADMIN_RSS_UDP6].fields = 256262306a36Sopenharmony_ci ENA_ADMIN_RSS_L3_SA | ENA_ADMIN_RSS_L3_DA | 256362306a36Sopenharmony_ci ENA_ADMIN_RSS_L4_DP | ENA_ADMIN_RSS_L4_SP; 256462306a36Sopenharmony_ci 256562306a36Sopenharmony_ci hash_ctrl->selected_fields[ENA_ADMIN_RSS_IP4].fields = 256662306a36Sopenharmony_ci ENA_ADMIN_RSS_L3_SA | ENA_ADMIN_RSS_L3_DA; 256762306a36Sopenharmony_ci 256862306a36Sopenharmony_ci hash_ctrl->selected_fields[ENA_ADMIN_RSS_IP6].fields = 256962306a36Sopenharmony_ci ENA_ADMIN_RSS_L3_SA | ENA_ADMIN_RSS_L3_DA; 257062306a36Sopenharmony_ci 257162306a36Sopenharmony_ci hash_ctrl->selected_fields[ENA_ADMIN_RSS_IP4_FRAG].fields = 257262306a36Sopenharmony_ci ENA_ADMIN_RSS_L3_SA | ENA_ADMIN_RSS_L3_DA; 257362306a36Sopenharmony_ci 257462306a36Sopenharmony_ci hash_ctrl->selected_fields[ENA_ADMIN_RSS_NOT_IP].fields = 257562306a36Sopenharmony_ci ENA_ADMIN_RSS_L2_DA | ENA_ADMIN_RSS_L2_SA; 257662306a36Sopenharmony_ci 257762306a36Sopenharmony_ci for (i = 0; i < ENA_ADMIN_RSS_PROTO_NUM; i++) { 257862306a36Sopenharmony_ci available_fields = hash_ctrl->selected_fields[i].fields & 257962306a36Sopenharmony_ci hash_ctrl->supported_fields[i].fields; 258062306a36Sopenharmony_ci if (available_fields != hash_ctrl->selected_fields[i].fields) { 258162306a36Sopenharmony_ci netdev_err(ena_dev->net_device, 258262306a36Sopenharmony_ci "Hash control doesn't support all the desire configuration. proto %x supported %x selected %x\n", 258362306a36Sopenharmony_ci i, hash_ctrl->supported_fields[i].fields, 258462306a36Sopenharmony_ci hash_ctrl->selected_fields[i].fields); 258562306a36Sopenharmony_ci return -EOPNOTSUPP; 258662306a36Sopenharmony_ci } 258762306a36Sopenharmony_ci } 258862306a36Sopenharmony_ci 258962306a36Sopenharmony_ci rc = ena_com_set_hash_ctrl(ena_dev); 259062306a36Sopenharmony_ci 259162306a36Sopenharmony_ci /* In case of failure, restore the old hash ctrl */ 259262306a36Sopenharmony_ci if (unlikely(rc)) 259362306a36Sopenharmony_ci ena_com_get_hash_ctrl(ena_dev, 0, NULL); 259462306a36Sopenharmony_ci 259562306a36Sopenharmony_ci return rc; 259662306a36Sopenharmony_ci} 259762306a36Sopenharmony_ci 259862306a36Sopenharmony_ciint ena_com_fill_hash_ctrl(struct ena_com_dev *ena_dev, 259962306a36Sopenharmony_ci enum ena_admin_flow_hash_proto proto, 260062306a36Sopenharmony_ci u16 hash_fields) 260162306a36Sopenharmony_ci{ 260262306a36Sopenharmony_ci struct ena_rss *rss = &ena_dev->rss; 260362306a36Sopenharmony_ci struct ena_admin_feature_rss_hash_control *hash_ctrl = rss->hash_ctrl; 260462306a36Sopenharmony_ci u16 supported_fields; 260562306a36Sopenharmony_ci int rc; 260662306a36Sopenharmony_ci 260762306a36Sopenharmony_ci if (proto >= ENA_ADMIN_RSS_PROTO_NUM) { 260862306a36Sopenharmony_ci netdev_err(ena_dev->net_device, "Invalid proto num (%u)\n", 260962306a36Sopenharmony_ci proto); 261062306a36Sopenharmony_ci return -EINVAL; 261162306a36Sopenharmony_ci } 261262306a36Sopenharmony_ci 261362306a36Sopenharmony_ci /* Get the ctrl table */ 261462306a36Sopenharmony_ci rc = ena_com_get_hash_ctrl(ena_dev, proto, NULL); 261562306a36Sopenharmony_ci if (unlikely(rc)) 261662306a36Sopenharmony_ci return rc; 261762306a36Sopenharmony_ci 261862306a36Sopenharmony_ci /* Make sure all the fields are supported */ 261962306a36Sopenharmony_ci supported_fields = hash_ctrl->supported_fields[proto].fields; 262062306a36Sopenharmony_ci if ((hash_fields & supported_fields) != hash_fields) { 262162306a36Sopenharmony_ci netdev_err(ena_dev->net_device, 262262306a36Sopenharmony_ci "Proto %d doesn't support the required fields %x. supports only: %x\n", 262362306a36Sopenharmony_ci proto, hash_fields, supported_fields); 262462306a36Sopenharmony_ci } 262562306a36Sopenharmony_ci 262662306a36Sopenharmony_ci hash_ctrl->selected_fields[proto].fields = hash_fields; 262762306a36Sopenharmony_ci 262862306a36Sopenharmony_ci rc = ena_com_set_hash_ctrl(ena_dev); 262962306a36Sopenharmony_ci 263062306a36Sopenharmony_ci /* In case of failure, restore the old hash ctrl */ 263162306a36Sopenharmony_ci if (unlikely(rc)) 263262306a36Sopenharmony_ci ena_com_get_hash_ctrl(ena_dev, 0, NULL); 263362306a36Sopenharmony_ci 263462306a36Sopenharmony_ci return 0; 263562306a36Sopenharmony_ci} 263662306a36Sopenharmony_ci 263762306a36Sopenharmony_ciint ena_com_indirect_table_fill_entry(struct ena_com_dev *ena_dev, 263862306a36Sopenharmony_ci u16 entry_idx, u16 entry_value) 263962306a36Sopenharmony_ci{ 264062306a36Sopenharmony_ci struct ena_rss *rss = &ena_dev->rss; 264162306a36Sopenharmony_ci 264262306a36Sopenharmony_ci if (unlikely(entry_idx >= (1 << rss->tbl_log_size))) 264362306a36Sopenharmony_ci return -EINVAL; 264462306a36Sopenharmony_ci 264562306a36Sopenharmony_ci if (unlikely((entry_value > ENA_TOTAL_NUM_QUEUES))) 264662306a36Sopenharmony_ci return -EINVAL; 264762306a36Sopenharmony_ci 264862306a36Sopenharmony_ci rss->host_rss_ind_tbl[entry_idx] = entry_value; 264962306a36Sopenharmony_ci 265062306a36Sopenharmony_ci return 0; 265162306a36Sopenharmony_ci} 265262306a36Sopenharmony_ci 265362306a36Sopenharmony_ciint ena_com_indirect_table_set(struct ena_com_dev *ena_dev) 265462306a36Sopenharmony_ci{ 265562306a36Sopenharmony_ci struct ena_com_admin_queue *admin_queue = &ena_dev->admin_queue; 265662306a36Sopenharmony_ci struct ena_rss *rss = &ena_dev->rss; 265762306a36Sopenharmony_ci struct ena_admin_set_feat_cmd cmd; 265862306a36Sopenharmony_ci struct ena_admin_set_feat_resp resp; 265962306a36Sopenharmony_ci int ret; 266062306a36Sopenharmony_ci 266162306a36Sopenharmony_ci if (!ena_com_check_supported_feature_id( 266262306a36Sopenharmony_ci ena_dev, ENA_ADMIN_RSS_INDIRECTION_TABLE_CONFIG)) { 266362306a36Sopenharmony_ci netdev_dbg(ena_dev->net_device, "Feature %d isn't supported\n", 266462306a36Sopenharmony_ci ENA_ADMIN_RSS_INDIRECTION_TABLE_CONFIG); 266562306a36Sopenharmony_ci return -EOPNOTSUPP; 266662306a36Sopenharmony_ci } 266762306a36Sopenharmony_ci 266862306a36Sopenharmony_ci ret = ena_com_ind_tbl_convert_to_device(ena_dev); 266962306a36Sopenharmony_ci if (ret) { 267062306a36Sopenharmony_ci netdev_err(ena_dev->net_device, 267162306a36Sopenharmony_ci "Failed to convert host indirection table to device table\n"); 267262306a36Sopenharmony_ci return ret; 267362306a36Sopenharmony_ci } 267462306a36Sopenharmony_ci 267562306a36Sopenharmony_ci memset(&cmd, 0x0, sizeof(cmd)); 267662306a36Sopenharmony_ci 267762306a36Sopenharmony_ci cmd.aq_common_descriptor.opcode = ENA_ADMIN_SET_FEATURE; 267862306a36Sopenharmony_ci cmd.aq_common_descriptor.flags = 267962306a36Sopenharmony_ci ENA_ADMIN_AQ_COMMON_DESC_CTRL_DATA_INDIRECT_MASK; 268062306a36Sopenharmony_ci cmd.feat_common.feature_id = ENA_ADMIN_RSS_INDIRECTION_TABLE_CONFIG; 268162306a36Sopenharmony_ci cmd.u.ind_table.size = rss->tbl_log_size; 268262306a36Sopenharmony_ci cmd.u.ind_table.inline_index = 0xFFFFFFFF; 268362306a36Sopenharmony_ci 268462306a36Sopenharmony_ci ret = ena_com_mem_addr_set(ena_dev, 268562306a36Sopenharmony_ci &cmd.control_buffer.address, 268662306a36Sopenharmony_ci rss->rss_ind_tbl_dma_addr); 268762306a36Sopenharmony_ci if (unlikely(ret)) { 268862306a36Sopenharmony_ci netdev_err(ena_dev->net_device, "Memory address set failed\n"); 268962306a36Sopenharmony_ci return ret; 269062306a36Sopenharmony_ci } 269162306a36Sopenharmony_ci 269262306a36Sopenharmony_ci cmd.control_buffer.length = (1ULL << rss->tbl_log_size) * 269362306a36Sopenharmony_ci sizeof(struct ena_admin_rss_ind_table_entry); 269462306a36Sopenharmony_ci 269562306a36Sopenharmony_ci ret = ena_com_execute_admin_command(admin_queue, 269662306a36Sopenharmony_ci (struct ena_admin_aq_entry *)&cmd, 269762306a36Sopenharmony_ci sizeof(cmd), 269862306a36Sopenharmony_ci (struct ena_admin_acq_entry *)&resp, 269962306a36Sopenharmony_ci sizeof(resp)); 270062306a36Sopenharmony_ci 270162306a36Sopenharmony_ci if (unlikely(ret)) 270262306a36Sopenharmony_ci netdev_err(ena_dev->net_device, 270362306a36Sopenharmony_ci "Failed to set indirect table. error: %d\n", ret); 270462306a36Sopenharmony_ci 270562306a36Sopenharmony_ci return ret; 270662306a36Sopenharmony_ci} 270762306a36Sopenharmony_ci 270862306a36Sopenharmony_ciint ena_com_indirect_table_get(struct ena_com_dev *ena_dev, u32 *ind_tbl) 270962306a36Sopenharmony_ci{ 271062306a36Sopenharmony_ci struct ena_rss *rss = &ena_dev->rss; 271162306a36Sopenharmony_ci struct ena_admin_get_feat_resp get_resp; 271262306a36Sopenharmony_ci u32 tbl_size; 271362306a36Sopenharmony_ci int i, rc; 271462306a36Sopenharmony_ci 271562306a36Sopenharmony_ci tbl_size = (1ULL << rss->tbl_log_size) * 271662306a36Sopenharmony_ci sizeof(struct ena_admin_rss_ind_table_entry); 271762306a36Sopenharmony_ci 271862306a36Sopenharmony_ci rc = ena_com_get_feature_ex(ena_dev, &get_resp, 271962306a36Sopenharmony_ci ENA_ADMIN_RSS_INDIRECTION_TABLE_CONFIG, 272062306a36Sopenharmony_ci rss->rss_ind_tbl_dma_addr, 272162306a36Sopenharmony_ci tbl_size, 0); 272262306a36Sopenharmony_ci if (unlikely(rc)) 272362306a36Sopenharmony_ci return rc; 272462306a36Sopenharmony_ci 272562306a36Sopenharmony_ci if (!ind_tbl) 272662306a36Sopenharmony_ci return 0; 272762306a36Sopenharmony_ci 272862306a36Sopenharmony_ci for (i = 0; i < (1 << rss->tbl_log_size); i++) 272962306a36Sopenharmony_ci ind_tbl[i] = rss->host_rss_ind_tbl[i]; 273062306a36Sopenharmony_ci 273162306a36Sopenharmony_ci return 0; 273262306a36Sopenharmony_ci} 273362306a36Sopenharmony_ci 273462306a36Sopenharmony_ciint ena_com_rss_init(struct ena_com_dev *ena_dev, u16 indr_tbl_log_size) 273562306a36Sopenharmony_ci{ 273662306a36Sopenharmony_ci int rc; 273762306a36Sopenharmony_ci 273862306a36Sopenharmony_ci memset(&ena_dev->rss, 0x0, sizeof(ena_dev->rss)); 273962306a36Sopenharmony_ci 274062306a36Sopenharmony_ci rc = ena_com_indirect_table_allocate(ena_dev, indr_tbl_log_size); 274162306a36Sopenharmony_ci if (unlikely(rc)) 274262306a36Sopenharmony_ci goto err_indr_tbl; 274362306a36Sopenharmony_ci 274462306a36Sopenharmony_ci /* The following function might return unsupported in case the 274562306a36Sopenharmony_ci * device doesn't support setting the key / hash function. We can safely 274662306a36Sopenharmony_ci * ignore this error and have indirection table support only. 274762306a36Sopenharmony_ci */ 274862306a36Sopenharmony_ci rc = ena_com_hash_key_allocate(ena_dev); 274962306a36Sopenharmony_ci if (likely(!rc)) 275062306a36Sopenharmony_ci ena_com_hash_key_fill_default_key(ena_dev); 275162306a36Sopenharmony_ci else if (rc != -EOPNOTSUPP) 275262306a36Sopenharmony_ci goto err_hash_key; 275362306a36Sopenharmony_ci 275462306a36Sopenharmony_ci rc = ena_com_hash_ctrl_init(ena_dev); 275562306a36Sopenharmony_ci if (unlikely(rc)) 275662306a36Sopenharmony_ci goto err_hash_ctrl; 275762306a36Sopenharmony_ci 275862306a36Sopenharmony_ci return 0; 275962306a36Sopenharmony_ci 276062306a36Sopenharmony_cierr_hash_ctrl: 276162306a36Sopenharmony_ci ena_com_hash_key_destroy(ena_dev); 276262306a36Sopenharmony_cierr_hash_key: 276362306a36Sopenharmony_ci ena_com_indirect_table_destroy(ena_dev); 276462306a36Sopenharmony_cierr_indr_tbl: 276562306a36Sopenharmony_ci 276662306a36Sopenharmony_ci return rc; 276762306a36Sopenharmony_ci} 276862306a36Sopenharmony_ci 276962306a36Sopenharmony_civoid ena_com_rss_destroy(struct ena_com_dev *ena_dev) 277062306a36Sopenharmony_ci{ 277162306a36Sopenharmony_ci ena_com_indirect_table_destroy(ena_dev); 277262306a36Sopenharmony_ci ena_com_hash_key_destroy(ena_dev); 277362306a36Sopenharmony_ci ena_com_hash_ctrl_destroy(ena_dev); 277462306a36Sopenharmony_ci 277562306a36Sopenharmony_ci memset(&ena_dev->rss, 0x0, sizeof(ena_dev->rss)); 277662306a36Sopenharmony_ci} 277762306a36Sopenharmony_ci 277862306a36Sopenharmony_ciint ena_com_allocate_host_info(struct ena_com_dev *ena_dev) 277962306a36Sopenharmony_ci{ 278062306a36Sopenharmony_ci struct ena_host_attribute *host_attr = &ena_dev->host_attr; 278162306a36Sopenharmony_ci 278262306a36Sopenharmony_ci host_attr->host_info = 278362306a36Sopenharmony_ci dma_alloc_coherent(ena_dev->dmadev, SZ_4K, 278462306a36Sopenharmony_ci &host_attr->host_info_dma_addr, GFP_KERNEL); 278562306a36Sopenharmony_ci if (unlikely(!host_attr->host_info)) 278662306a36Sopenharmony_ci return -ENOMEM; 278762306a36Sopenharmony_ci 278862306a36Sopenharmony_ci host_attr->host_info->ena_spec_version = ((ENA_COMMON_SPEC_VERSION_MAJOR << 278962306a36Sopenharmony_ci ENA_REGS_VERSION_MAJOR_VERSION_SHIFT) | 279062306a36Sopenharmony_ci (ENA_COMMON_SPEC_VERSION_MINOR)); 279162306a36Sopenharmony_ci 279262306a36Sopenharmony_ci return 0; 279362306a36Sopenharmony_ci} 279462306a36Sopenharmony_ci 279562306a36Sopenharmony_ciint ena_com_allocate_debug_area(struct ena_com_dev *ena_dev, 279662306a36Sopenharmony_ci u32 debug_area_size) 279762306a36Sopenharmony_ci{ 279862306a36Sopenharmony_ci struct ena_host_attribute *host_attr = &ena_dev->host_attr; 279962306a36Sopenharmony_ci 280062306a36Sopenharmony_ci host_attr->debug_area_virt_addr = 280162306a36Sopenharmony_ci dma_alloc_coherent(ena_dev->dmadev, debug_area_size, 280262306a36Sopenharmony_ci &host_attr->debug_area_dma_addr, GFP_KERNEL); 280362306a36Sopenharmony_ci if (unlikely(!host_attr->debug_area_virt_addr)) { 280462306a36Sopenharmony_ci host_attr->debug_area_size = 0; 280562306a36Sopenharmony_ci return -ENOMEM; 280662306a36Sopenharmony_ci } 280762306a36Sopenharmony_ci 280862306a36Sopenharmony_ci host_attr->debug_area_size = debug_area_size; 280962306a36Sopenharmony_ci 281062306a36Sopenharmony_ci return 0; 281162306a36Sopenharmony_ci} 281262306a36Sopenharmony_ci 281362306a36Sopenharmony_civoid ena_com_delete_host_info(struct ena_com_dev *ena_dev) 281462306a36Sopenharmony_ci{ 281562306a36Sopenharmony_ci struct ena_host_attribute *host_attr = &ena_dev->host_attr; 281662306a36Sopenharmony_ci 281762306a36Sopenharmony_ci if (host_attr->host_info) { 281862306a36Sopenharmony_ci dma_free_coherent(ena_dev->dmadev, SZ_4K, host_attr->host_info, 281962306a36Sopenharmony_ci host_attr->host_info_dma_addr); 282062306a36Sopenharmony_ci host_attr->host_info = NULL; 282162306a36Sopenharmony_ci } 282262306a36Sopenharmony_ci} 282362306a36Sopenharmony_ci 282462306a36Sopenharmony_civoid ena_com_delete_debug_area(struct ena_com_dev *ena_dev) 282562306a36Sopenharmony_ci{ 282662306a36Sopenharmony_ci struct ena_host_attribute *host_attr = &ena_dev->host_attr; 282762306a36Sopenharmony_ci 282862306a36Sopenharmony_ci if (host_attr->debug_area_virt_addr) { 282962306a36Sopenharmony_ci dma_free_coherent(ena_dev->dmadev, host_attr->debug_area_size, 283062306a36Sopenharmony_ci host_attr->debug_area_virt_addr, 283162306a36Sopenharmony_ci host_attr->debug_area_dma_addr); 283262306a36Sopenharmony_ci host_attr->debug_area_virt_addr = NULL; 283362306a36Sopenharmony_ci } 283462306a36Sopenharmony_ci} 283562306a36Sopenharmony_ci 283662306a36Sopenharmony_ciint ena_com_set_host_attributes(struct ena_com_dev *ena_dev) 283762306a36Sopenharmony_ci{ 283862306a36Sopenharmony_ci struct ena_host_attribute *host_attr = &ena_dev->host_attr; 283962306a36Sopenharmony_ci struct ena_com_admin_queue *admin_queue; 284062306a36Sopenharmony_ci struct ena_admin_set_feat_cmd cmd; 284162306a36Sopenharmony_ci struct ena_admin_set_feat_resp resp; 284262306a36Sopenharmony_ci 284362306a36Sopenharmony_ci int ret; 284462306a36Sopenharmony_ci 284562306a36Sopenharmony_ci /* Host attribute config is called before ena_com_get_dev_attr_feat 284662306a36Sopenharmony_ci * so ena_com can't check if the feature is supported. 284762306a36Sopenharmony_ci */ 284862306a36Sopenharmony_ci 284962306a36Sopenharmony_ci memset(&cmd, 0x0, sizeof(cmd)); 285062306a36Sopenharmony_ci admin_queue = &ena_dev->admin_queue; 285162306a36Sopenharmony_ci 285262306a36Sopenharmony_ci cmd.aq_common_descriptor.opcode = ENA_ADMIN_SET_FEATURE; 285362306a36Sopenharmony_ci cmd.feat_common.feature_id = ENA_ADMIN_HOST_ATTR_CONFIG; 285462306a36Sopenharmony_ci 285562306a36Sopenharmony_ci ret = ena_com_mem_addr_set(ena_dev, 285662306a36Sopenharmony_ci &cmd.u.host_attr.debug_ba, 285762306a36Sopenharmony_ci host_attr->debug_area_dma_addr); 285862306a36Sopenharmony_ci if (unlikely(ret)) { 285962306a36Sopenharmony_ci netdev_err(ena_dev->net_device, "Memory address set failed\n"); 286062306a36Sopenharmony_ci return ret; 286162306a36Sopenharmony_ci } 286262306a36Sopenharmony_ci 286362306a36Sopenharmony_ci ret = ena_com_mem_addr_set(ena_dev, 286462306a36Sopenharmony_ci &cmd.u.host_attr.os_info_ba, 286562306a36Sopenharmony_ci host_attr->host_info_dma_addr); 286662306a36Sopenharmony_ci if (unlikely(ret)) { 286762306a36Sopenharmony_ci netdev_err(ena_dev->net_device, "Memory address set failed\n"); 286862306a36Sopenharmony_ci return ret; 286962306a36Sopenharmony_ci } 287062306a36Sopenharmony_ci 287162306a36Sopenharmony_ci cmd.u.host_attr.debug_area_size = host_attr->debug_area_size; 287262306a36Sopenharmony_ci 287362306a36Sopenharmony_ci ret = ena_com_execute_admin_command(admin_queue, 287462306a36Sopenharmony_ci (struct ena_admin_aq_entry *)&cmd, 287562306a36Sopenharmony_ci sizeof(cmd), 287662306a36Sopenharmony_ci (struct ena_admin_acq_entry *)&resp, 287762306a36Sopenharmony_ci sizeof(resp)); 287862306a36Sopenharmony_ci 287962306a36Sopenharmony_ci if (unlikely(ret)) 288062306a36Sopenharmony_ci netdev_err(ena_dev->net_device, 288162306a36Sopenharmony_ci "Failed to set host attributes: %d\n", ret); 288262306a36Sopenharmony_ci 288362306a36Sopenharmony_ci return ret; 288462306a36Sopenharmony_ci} 288562306a36Sopenharmony_ci 288662306a36Sopenharmony_ci/* Interrupt moderation */ 288762306a36Sopenharmony_cibool ena_com_interrupt_moderation_supported(struct ena_com_dev *ena_dev) 288862306a36Sopenharmony_ci{ 288962306a36Sopenharmony_ci return ena_com_check_supported_feature_id(ena_dev, 289062306a36Sopenharmony_ci ENA_ADMIN_INTERRUPT_MODERATION); 289162306a36Sopenharmony_ci} 289262306a36Sopenharmony_ci 289362306a36Sopenharmony_cistatic int ena_com_update_nonadaptive_moderation_interval(struct ena_com_dev *ena_dev, 289462306a36Sopenharmony_ci u32 coalesce_usecs, 289562306a36Sopenharmony_ci u32 intr_delay_resolution, 289662306a36Sopenharmony_ci u32 *intr_moder_interval) 289762306a36Sopenharmony_ci{ 289862306a36Sopenharmony_ci if (!intr_delay_resolution) { 289962306a36Sopenharmony_ci netdev_err(ena_dev->net_device, 290062306a36Sopenharmony_ci "Illegal interrupt delay granularity value\n"); 290162306a36Sopenharmony_ci return -EFAULT; 290262306a36Sopenharmony_ci } 290362306a36Sopenharmony_ci 290462306a36Sopenharmony_ci *intr_moder_interval = coalesce_usecs / intr_delay_resolution; 290562306a36Sopenharmony_ci 290662306a36Sopenharmony_ci return 0; 290762306a36Sopenharmony_ci} 290862306a36Sopenharmony_ci 290962306a36Sopenharmony_ciint ena_com_update_nonadaptive_moderation_interval_tx(struct ena_com_dev *ena_dev, 291062306a36Sopenharmony_ci u32 tx_coalesce_usecs) 291162306a36Sopenharmony_ci{ 291262306a36Sopenharmony_ci return ena_com_update_nonadaptive_moderation_interval(ena_dev, 291362306a36Sopenharmony_ci tx_coalesce_usecs, 291462306a36Sopenharmony_ci ena_dev->intr_delay_resolution, 291562306a36Sopenharmony_ci &ena_dev->intr_moder_tx_interval); 291662306a36Sopenharmony_ci} 291762306a36Sopenharmony_ci 291862306a36Sopenharmony_ciint ena_com_update_nonadaptive_moderation_interval_rx(struct ena_com_dev *ena_dev, 291962306a36Sopenharmony_ci u32 rx_coalesce_usecs) 292062306a36Sopenharmony_ci{ 292162306a36Sopenharmony_ci return ena_com_update_nonadaptive_moderation_interval(ena_dev, 292262306a36Sopenharmony_ci rx_coalesce_usecs, 292362306a36Sopenharmony_ci ena_dev->intr_delay_resolution, 292462306a36Sopenharmony_ci &ena_dev->intr_moder_rx_interval); 292562306a36Sopenharmony_ci} 292662306a36Sopenharmony_ci 292762306a36Sopenharmony_ciint ena_com_init_interrupt_moderation(struct ena_com_dev *ena_dev) 292862306a36Sopenharmony_ci{ 292962306a36Sopenharmony_ci struct ena_admin_get_feat_resp get_resp; 293062306a36Sopenharmony_ci u16 delay_resolution; 293162306a36Sopenharmony_ci int rc; 293262306a36Sopenharmony_ci 293362306a36Sopenharmony_ci rc = ena_com_get_feature(ena_dev, &get_resp, 293462306a36Sopenharmony_ci ENA_ADMIN_INTERRUPT_MODERATION, 0); 293562306a36Sopenharmony_ci 293662306a36Sopenharmony_ci if (rc) { 293762306a36Sopenharmony_ci if (rc == -EOPNOTSUPP) { 293862306a36Sopenharmony_ci netdev_dbg(ena_dev->net_device, 293962306a36Sopenharmony_ci "Feature %d isn't supported\n", 294062306a36Sopenharmony_ci ENA_ADMIN_INTERRUPT_MODERATION); 294162306a36Sopenharmony_ci rc = 0; 294262306a36Sopenharmony_ci } else { 294362306a36Sopenharmony_ci netdev_err(ena_dev->net_device, 294462306a36Sopenharmony_ci "Failed to get interrupt moderation admin cmd. rc: %d\n", 294562306a36Sopenharmony_ci rc); 294662306a36Sopenharmony_ci } 294762306a36Sopenharmony_ci 294862306a36Sopenharmony_ci /* no moderation supported, disable adaptive support */ 294962306a36Sopenharmony_ci ena_com_disable_adaptive_moderation(ena_dev); 295062306a36Sopenharmony_ci return rc; 295162306a36Sopenharmony_ci } 295262306a36Sopenharmony_ci 295362306a36Sopenharmony_ci /* if moderation is supported by device we set adaptive moderation */ 295462306a36Sopenharmony_ci delay_resolution = get_resp.u.intr_moderation.intr_delay_resolution; 295562306a36Sopenharmony_ci ena_com_update_intr_delay_resolution(ena_dev, delay_resolution); 295662306a36Sopenharmony_ci 295762306a36Sopenharmony_ci /* Disable adaptive moderation by default - can be enabled later */ 295862306a36Sopenharmony_ci ena_com_disable_adaptive_moderation(ena_dev); 295962306a36Sopenharmony_ci 296062306a36Sopenharmony_ci return 0; 296162306a36Sopenharmony_ci} 296262306a36Sopenharmony_ci 296362306a36Sopenharmony_ciunsigned int ena_com_get_nonadaptive_moderation_interval_tx(struct ena_com_dev *ena_dev) 296462306a36Sopenharmony_ci{ 296562306a36Sopenharmony_ci return ena_dev->intr_moder_tx_interval; 296662306a36Sopenharmony_ci} 296762306a36Sopenharmony_ci 296862306a36Sopenharmony_ciunsigned int ena_com_get_nonadaptive_moderation_interval_rx(struct ena_com_dev *ena_dev) 296962306a36Sopenharmony_ci{ 297062306a36Sopenharmony_ci return ena_dev->intr_moder_rx_interval; 297162306a36Sopenharmony_ci} 297262306a36Sopenharmony_ci 297362306a36Sopenharmony_ciint ena_com_config_dev_mode(struct ena_com_dev *ena_dev, 297462306a36Sopenharmony_ci struct ena_admin_feature_llq_desc *llq_features, 297562306a36Sopenharmony_ci struct ena_llq_configurations *llq_default_cfg) 297662306a36Sopenharmony_ci{ 297762306a36Sopenharmony_ci struct ena_com_llq_info *llq_info = &ena_dev->llq_info; 297862306a36Sopenharmony_ci int rc; 297962306a36Sopenharmony_ci 298062306a36Sopenharmony_ci if (!llq_features->max_llq_num) { 298162306a36Sopenharmony_ci ena_dev->tx_mem_queue_type = ENA_ADMIN_PLACEMENT_POLICY_HOST; 298262306a36Sopenharmony_ci return 0; 298362306a36Sopenharmony_ci } 298462306a36Sopenharmony_ci 298562306a36Sopenharmony_ci rc = ena_com_config_llq_info(ena_dev, llq_features, llq_default_cfg); 298662306a36Sopenharmony_ci if (rc) 298762306a36Sopenharmony_ci return rc; 298862306a36Sopenharmony_ci 298962306a36Sopenharmony_ci ena_dev->tx_max_header_size = llq_info->desc_list_entry_size - 299062306a36Sopenharmony_ci (llq_info->descs_num_before_header * sizeof(struct ena_eth_io_tx_desc)); 299162306a36Sopenharmony_ci 299262306a36Sopenharmony_ci if (unlikely(ena_dev->tx_max_header_size == 0)) { 299362306a36Sopenharmony_ci netdev_err(ena_dev->net_device, 299462306a36Sopenharmony_ci "The size of the LLQ entry is smaller than needed\n"); 299562306a36Sopenharmony_ci return -EINVAL; 299662306a36Sopenharmony_ci } 299762306a36Sopenharmony_ci 299862306a36Sopenharmony_ci ena_dev->tx_mem_queue_type = ENA_ADMIN_PLACEMENT_POLICY_DEV; 299962306a36Sopenharmony_ci 300062306a36Sopenharmony_ci return 0; 300162306a36Sopenharmony_ci} 3002