162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright 2018-2021 Amazon.com, Inc. or its affiliates. All rights reserved. 462306a36Sopenharmony_ci */ 562306a36Sopenharmony_ci 662306a36Sopenharmony_ci#include "efa_com.h" 762306a36Sopenharmony_ci#include "efa_regs_defs.h" 862306a36Sopenharmony_ci 962306a36Sopenharmony_ci#define ADMIN_CMD_TIMEOUT_US 30000000 /* usecs */ 1062306a36Sopenharmony_ci 1162306a36Sopenharmony_ci#define EFA_REG_READ_TIMEOUT_US 50000 /* usecs */ 1262306a36Sopenharmony_ci#define EFA_MMIO_READ_INVALID 0xffffffff 1362306a36Sopenharmony_ci 1462306a36Sopenharmony_ci#define EFA_POLL_INTERVAL_MS 100 /* msecs */ 1562306a36Sopenharmony_ci 1662306a36Sopenharmony_ci#define EFA_ASYNC_QUEUE_DEPTH 16 1762306a36Sopenharmony_ci#define EFA_ADMIN_QUEUE_DEPTH 32 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_ci#define EFA_CTRL_MAJOR 0 2062306a36Sopenharmony_ci#define EFA_CTRL_MINOR 0 2162306a36Sopenharmony_ci#define EFA_CTRL_SUB_MINOR 1 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_cienum efa_cmd_status { 2462306a36Sopenharmony_ci EFA_CMD_SUBMITTED, 2562306a36Sopenharmony_ci EFA_CMD_COMPLETED, 2662306a36Sopenharmony_ci}; 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_cistruct efa_comp_ctx { 2962306a36Sopenharmony_ci struct completion wait_event; 3062306a36Sopenharmony_ci struct efa_admin_acq_entry *user_cqe; 3162306a36Sopenharmony_ci u32 comp_size; 3262306a36Sopenharmony_ci enum efa_cmd_status status; 3362306a36Sopenharmony_ci u8 cmd_opcode; 3462306a36Sopenharmony_ci u8 occupied; 3562306a36Sopenharmony_ci}; 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_cistatic const char *efa_com_cmd_str(u8 cmd) 3862306a36Sopenharmony_ci{ 3962306a36Sopenharmony_ci#define EFA_CMD_STR_CASE(_cmd) case EFA_ADMIN_##_cmd: return #_cmd 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_ci switch (cmd) { 4262306a36Sopenharmony_ci EFA_CMD_STR_CASE(CREATE_QP); 4362306a36Sopenharmony_ci EFA_CMD_STR_CASE(MODIFY_QP); 4462306a36Sopenharmony_ci EFA_CMD_STR_CASE(QUERY_QP); 4562306a36Sopenharmony_ci EFA_CMD_STR_CASE(DESTROY_QP); 4662306a36Sopenharmony_ci EFA_CMD_STR_CASE(CREATE_AH); 4762306a36Sopenharmony_ci EFA_CMD_STR_CASE(DESTROY_AH); 4862306a36Sopenharmony_ci EFA_CMD_STR_CASE(REG_MR); 4962306a36Sopenharmony_ci EFA_CMD_STR_CASE(DEREG_MR); 5062306a36Sopenharmony_ci EFA_CMD_STR_CASE(CREATE_CQ); 5162306a36Sopenharmony_ci EFA_CMD_STR_CASE(DESTROY_CQ); 5262306a36Sopenharmony_ci EFA_CMD_STR_CASE(GET_FEATURE); 5362306a36Sopenharmony_ci EFA_CMD_STR_CASE(SET_FEATURE); 5462306a36Sopenharmony_ci EFA_CMD_STR_CASE(GET_STATS); 5562306a36Sopenharmony_ci EFA_CMD_STR_CASE(ALLOC_PD); 5662306a36Sopenharmony_ci EFA_CMD_STR_CASE(DEALLOC_PD); 5762306a36Sopenharmony_ci EFA_CMD_STR_CASE(ALLOC_UAR); 5862306a36Sopenharmony_ci EFA_CMD_STR_CASE(DEALLOC_UAR); 5962306a36Sopenharmony_ci EFA_CMD_STR_CASE(CREATE_EQ); 6062306a36Sopenharmony_ci EFA_CMD_STR_CASE(DESTROY_EQ); 6162306a36Sopenharmony_ci default: return "unknown command opcode"; 6262306a36Sopenharmony_ci } 6362306a36Sopenharmony_ci#undef EFA_CMD_STR_CASE 6462306a36Sopenharmony_ci} 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_civoid efa_com_set_dma_addr(dma_addr_t addr, u32 *addr_high, u32 *addr_low) 6762306a36Sopenharmony_ci{ 6862306a36Sopenharmony_ci *addr_low = lower_32_bits(addr); 6962306a36Sopenharmony_ci *addr_high = upper_32_bits(addr); 7062306a36Sopenharmony_ci} 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_cistatic u32 efa_com_reg_read32(struct efa_com_dev *edev, u16 offset) 7362306a36Sopenharmony_ci{ 7462306a36Sopenharmony_ci struct efa_com_mmio_read *mmio_read = &edev->mmio_read; 7562306a36Sopenharmony_ci struct efa_admin_mmio_req_read_less_resp *read_resp; 7662306a36Sopenharmony_ci unsigned long exp_time; 7762306a36Sopenharmony_ci u32 mmio_read_reg = 0; 7862306a36Sopenharmony_ci u32 err; 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_ci read_resp = mmio_read->read_resp; 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_ci spin_lock(&mmio_read->lock); 8362306a36Sopenharmony_ci mmio_read->seq_num++; 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_ci /* trash DMA req_id to identify when hardware is done */ 8662306a36Sopenharmony_ci read_resp->req_id = mmio_read->seq_num + 0x9aL; 8762306a36Sopenharmony_ci EFA_SET(&mmio_read_reg, EFA_REGS_MMIO_REG_READ_REG_OFF, offset); 8862306a36Sopenharmony_ci EFA_SET(&mmio_read_reg, EFA_REGS_MMIO_REG_READ_REQ_ID, 8962306a36Sopenharmony_ci mmio_read->seq_num); 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_ci writel(mmio_read_reg, edev->reg_bar + EFA_REGS_MMIO_REG_READ_OFF); 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_ci exp_time = jiffies + usecs_to_jiffies(mmio_read->mmio_read_timeout); 9462306a36Sopenharmony_ci do { 9562306a36Sopenharmony_ci if (READ_ONCE(read_resp->req_id) == mmio_read->seq_num) 9662306a36Sopenharmony_ci break; 9762306a36Sopenharmony_ci udelay(1); 9862306a36Sopenharmony_ci } while (time_is_after_jiffies(exp_time)); 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_ci if (read_resp->req_id != mmio_read->seq_num) { 10162306a36Sopenharmony_ci ibdev_err_ratelimited( 10262306a36Sopenharmony_ci edev->efa_dev, 10362306a36Sopenharmony_ci "Reading register timed out. expected: req id[%u] offset[%#x] actual: req id[%u] offset[%#x]\n", 10462306a36Sopenharmony_ci mmio_read->seq_num, offset, read_resp->req_id, 10562306a36Sopenharmony_ci read_resp->reg_off); 10662306a36Sopenharmony_ci err = EFA_MMIO_READ_INVALID; 10762306a36Sopenharmony_ci goto out; 10862306a36Sopenharmony_ci } 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_ci if (read_resp->reg_off != offset) { 11162306a36Sopenharmony_ci ibdev_err_ratelimited( 11262306a36Sopenharmony_ci edev->efa_dev, 11362306a36Sopenharmony_ci "Reading register failed: wrong offset provided\n"); 11462306a36Sopenharmony_ci err = EFA_MMIO_READ_INVALID; 11562306a36Sopenharmony_ci goto out; 11662306a36Sopenharmony_ci } 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_ci err = read_resp->reg_val; 11962306a36Sopenharmony_ciout: 12062306a36Sopenharmony_ci spin_unlock(&mmio_read->lock); 12162306a36Sopenharmony_ci return err; 12262306a36Sopenharmony_ci} 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_cistatic int efa_com_admin_init_sq(struct efa_com_dev *edev) 12562306a36Sopenharmony_ci{ 12662306a36Sopenharmony_ci struct efa_com_admin_queue *aq = &edev->aq; 12762306a36Sopenharmony_ci struct efa_com_admin_sq *sq = &aq->sq; 12862306a36Sopenharmony_ci u16 size = aq->depth * sizeof(*sq->entries); 12962306a36Sopenharmony_ci u32 aq_caps = 0; 13062306a36Sopenharmony_ci u32 addr_high; 13162306a36Sopenharmony_ci u32 addr_low; 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_ci sq->entries = 13462306a36Sopenharmony_ci dma_alloc_coherent(aq->dmadev, size, &sq->dma_addr, GFP_KERNEL); 13562306a36Sopenharmony_ci if (!sq->entries) 13662306a36Sopenharmony_ci return -ENOMEM; 13762306a36Sopenharmony_ci 13862306a36Sopenharmony_ci spin_lock_init(&sq->lock); 13962306a36Sopenharmony_ci 14062306a36Sopenharmony_ci sq->cc = 0; 14162306a36Sopenharmony_ci sq->pc = 0; 14262306a36Sopenharmony_ci sq->phase = 1; 14362306a36Sopenharmony_ci 14462306a36Sopenharmony_ci sq->db_addr = (u32 __iomem *)(edev->reg_bar + EFA_REGS_AQ_PROD_DB_OFF); 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_ci addr_high = upper_32_bits(sq->dma_addr); 14762306a36Sopenharmony_ci addr_low = lower_32_bits(sq->dma_addr); 14862306a36Sopenharmony_ci 14962306a36Sopenharmony_ci writel(addr_low, edev->reg_bar + EFA_REGS_AQ_BASE_LO_OFF); 15062306a36Sopenharmony_ci writel(addr_high, edev->reg_bar + EFA_REGS_AQ_BASE_HI_OFF); 15162306a36Sopenharmony_ci 15262306a36Sopenharmony_ci EFA_SET(&aq_caps, EFA_REGS_AQ_CAPS_AQ_DEPTH, aq->depth); 15362306a36Sopenharmony_ci EFA_SET(&aq_caps, EFA_REGS_AQ_CAPS_AQ_ENTRY_SIZE, 15462306a36Sopenharmony_ci sizeof(struct efa_admin_aq_entry)); 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_ci writel(aq_caps, edev->reg_bar + EFA_REGS_AQ_CAPS_OFF); 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_ci return 0; 15962306a36Sopenharmony_ci} 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_cistatic int efa_com_admin_init_cq(struct efa_com_dev *edev) 16262306a36Sopenharmony_ci{ 16362306a36Sopenharmony_ci struct efa_com_admin_queue *aq = &edev->aq; 16462306a36Sopenharmony_ci struct efa_com_admin_cq *cq = &aq->cq; 16562306a36Sopenharmony_ci u16 size = aq->depth * sizeof(*cq->entries); 16662306a36Sopenharmony_ci u32 acq_caps = 0; 16762306a36Sopenharmony_ci u32 addr_high; 16862306a36Sopenharmony_ci u32 addr_low; 16962306a36Sopenharmony_ci 17062306a36Sopenharmony_ci cq->entries = 17162306a36Sopenharmony_ci dma_alloc_coherent(aq->dmadev, size, &cq->dma_addr, GFP_KERNEL); 17262306a36Sopenharmony_ci if (!cq->entries) 17362306a36Sopenharmony_ci return -ENOMEM; 17462306a36Sopenharmony_ci 17562306a36Sopenharmony_ci spin_lock_init(&cq->lock); 17662306a36Sopenharmony_ci 17762306a36Sopenharmony_ci cq->cc = 0; 17862306a36Sopenharmony_ci cq->phase = 1; 17962306a36Sopenharmony_ci 18062306a36Sopenharmony_ci addr_high = upper_32_bits(cq->dma_addr); 18162306a36Sopenharmony_ci addr_low = lower_32_bits(cq->dma_addr); 18262306a36Sopenharmony_ci 18362306a36Sopenharmony_ci writel(addr_low, edev->reg_bar + EFA_REGS_ACQ_BASE_LO_OFF); 18462306a36Sopenharmony_ci writel(addr_high, edev->reg_bar + EFA_REGS_ACQ_BASE_HI_OFF); 18562306a36Sopenharmony_ci 18662306a36Sopenharmony_ci EFA_SET(&acq_caps, EFA_REGS_ACQ_CAPS_ACQ_DEPTH, aq->depth); 18762306a36Sopenharmony_ci EFA_SET(&acq_caps, EFA_REGS_ACQ_CAPS_ACQ_ENTRY_SIZE, 18862306a36Sopenharmony_ci sizeof(struct efa_admin_acq_entry)); 18962306a36Sopenharmony_ci EFA_SET(&acq_caps, EFA_REGS_ACQ_CAPS_ACQ_MSIX_VECTOR, 19062306a36Sopenharmony_ci aq->msix_vector_idx); 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_ci writel(acq_caps, edev->reg_bar + EFA_REGS_ACQ_CAPS_OFF); 19362306a36Sopenharmony_ci 19462306a36Sopenharmony_ci return 0; 19562306a36Sopenharmony_ci} 19662306a36Sopenharmony_ci 19762306a36Sopenharmony_cistatic int efa_com_admin_init_aenq(struct efa_com_dev *edev, 19862306a36Sopenharmony_ci struct efa_aenq_handlers *aenq_handlers) 19962306a36Sopenharmony_ci{ 20062306a36Sopenharmony_ci struct efa_com_aenq *aenq = &edev->aenq; 20162306a36Sopenharmony_ci u32 addr_low, addr_high; 20262306a36Sopenharmony_ci u32 aenq_caps = 0; 20362306a36Sopenharmony_ci u16 size; 20462306a36Sopenharmony_ci 20562306a36Sopenharmony_ci if (!aenq_handlers) { 20662306a36Sopenharmony_ci ibdev_err(edev->efa_dev, "aenq handlers pointer is NULL\n"); 20762306a36Sopenharmony_ci return -EINVAL; 20862306a36Sopenharmony_ci } 20962306a36Sopenharmony_ci 21062306a36Sopenharmony_ci size = EFA_ASYNC_QUEUE_DEPTH * sizeof(*aenq->entries); 21162306a36Sopenharmony_ci aenq->entries = dma_alloc_coherent(edev->dmadev, size, &aenq->dma_addr, 21262306a36Sopenharmony_ci GFP_KERNEL); 21362306a36Sopenharmony_ci if (!aenq->entries) 21462306a36Sopenharmony_ci return -ENOMEM; 21562306a36Sopenharmony_ci 21662306a36Sopenharmony_ci aenq->aenq_handlers = aenq_handlers; 21762306a36Sopenharmony_ci aenq->depth = EFA_ASYNC_QUEUE_DEPTH; 21862306a36Sopenharmony_ci aenq->cc = 0; 21962306a36Sopenharmony_ci aenq->phase = 1; 22062306a36Sopenharmony_ci 22162306a36Sopenharmony_ci addr_low = lower_32_bits(aenq->dma_addr); 22262306a36Sopenharmony_ci addr_high = upper_32_bits(aenq->dma_addr); 22362306a36Sopenharmony_ci 22462306a36Sopenharmony_ci writel(addr_low, edev->reg_bar + EFA_REGS_AENQ_BASE_LO_OFF); 22562306a36Sopenharmony_ci writel(addr_high, edev->reg_bar + EFA_REGS_AENQ_BASE_HI_OFF); 22662306a36Sopenharmony_ci 22762306a36Sopenharmony_ci EFA_SET(&aenq_caps, EFA_REGS_AENQ_CAPS_AENQ_DEPTH, aenq->depth); 22862306a36Sopenharmony_ci EFA_SET(&aenq_caps, EFA_REGS_AENQ_CAPS_AENQ_ENTRY_SIZE, 22962306a36Sopenharmony_ci sizeof(struct efa_admin_aenq_entry)); 23062306a36Sopenharmony_ci EFA_SET(&aenq_caps, EFA_REGS_AENQ_CAPS_AENQ_MSIX_VECTOR, 23162306a36Sopenharmony_ci aenq->msix_vector_idx); 23262306a36Sopenharmony_ci writel(aenq_caps, edev->reg_bar + EFA_REGS_AENQ_CAPS_OFF); 23362306a36Sopenharmony_ci 23462306a36Sopenharmony_ci /* 23562306a36Sopenharmony_ci * Init cons_db to mark that all entries in the queue 23662306a36Sopenharmony_ci * are initially available 23762306a36Sopenharmony_ci */ 23862306a36Sopenharmony_ci writel(edev->aenq.cc, edev->reg_bar + EFA_REGS_AENQ_CONS_DB_OFF); 23962306a36Sopenharmony_ci 24062306a36Sopenharmony_ci return 0; 24162306a36Sopenharmony_ci} 24262306a36Sopenharmony_ci 24362306a36Sopenharmony_ci/* ID to be used with efa_com_get_comp_ctx */ 24462306a36Sopenharmony_cistatic u16 efa_com_alloc_ctx_id(struct efa_com_admin_queue *aq) 24562306a36Sopenharmony_ci{ 24662306a36Sopenharmony_ci u16 ctx_id; 24762306a36Sopenharmony_ci 24862306a36Sopenharmony_ci spin_lock(&aq->comp_ctx_lock); 24962306a36Sopenharmony_ci ctx_id = aq->comp_ctx_pool[aq->comp_ctx_pool_next]; 25062306a36Sopenharmony_ci aq->comp_ctx_pool_next++; 25162306a36Sopenharmony_ci spin_unlock(&aq->comp_ctx_lock); 25262306a36Sopenharmony_ci 25362306a36Sopenharmony_ci return ctx_id; 25462306a36Sopenharmony_ci} 25562306a36Sopenharmony_ci 25662306a36Sopenharmony_cistatic void efa_com_dealloc_ctx_id(struct efa_com_admin_queue *aq, 25762306a36Sopenharmony_ci u16 ctx_id) 25862306a36Sopenharmony_ci{ 25962306a36Sopenharmony_ci spin_lock(&aq->comp_ctx_lock); 26062306a36Sopenharmony_ci aq->comp_ctx_pool_next--; 26162306a36Sopenharmony_ci aq->comp_ctx_pool[aq->comp_ctx_pool_next] = ctx_id; 26262306a36Sopenharmony_ci spin_unlock(&aq->comp_ctx_lock); 26362306a36Sopenharmony_ci} 26462306a36Sopenharmony_ci 26562306a36Sopenharmony_cistatic inline void efa_com_put_comp_ctx(struct efa_com_admin_queue *aq, 26662306a36Sopenharmony_ci struct efa_comp_ctx *comp_ctx) 26762306a36Sopenharmony_ci{ 26862306a36Sopenharmony_ci u16 cmd_id = EFA_GET(&comp_ctx->user_cqe->acq_common_descriptor.command, 26962306a36Sopenharmony_ci EFA_ADMIN_ACQ_COMMON_DESC_COMMAND_ID); 27062306a36Sopenharmony_ci u16 ctx_id = cmd_id & (aq->depth - 1); 27162306a36Sopenharmony_ci 27262306a36Sopenharmony_ci ibdev_dbg(aq->efa_dev, "Put completion command_id %#x\n", cmd_id); 27362306a36Sopenharmony_ci comp_ctx->occupied = 0; 27462306a36Sopenharmony_ci efa_com_dealloc_ctx_id(aq, ctx_id); 27562306a36Sopenharmony_ci} 27662306a36Sopenharmony_ci 27762306a36Sopenharmony_cistatic struct efa_comp_ctx *efa_com_get_comp_ctx(struct efa_com_admin_queue *aq, 27862306a36Sopenharmony_ci u16 cmd_id, bool capture) 27962306a36Sopenharmony_ci{ 28062306a36Sopenharmony_ci u16 ctx_id = cmd_id & (aq->depth - 1); 28162306a36Sopenharmony_ci 28262306a36Sopenharmony_ci if (aq->comp_ctx[ctx_id].occupied && capture) { 28362306a36Sopenharmony_ci ibdev_err_ratelimited( 28462306a36Sopenharmony_ci aq->efa_dev, 28562306a36Sopenharmony_ci "Completion context for command_id %#x is occupied\n", 28662306a36Sopenharmony_ci cmd_id); 28762306a36Sopenharmony_ci return NULL; 28862306a36Sopenharmony_ci } 28962306a36Sopenharmony_ci 29062306a36Sopenharmony_ci if (capture) { 29162306a36Sopenharmony_ci aq->comp_ctx[ctx_id].occupied = 1; 29262306a36Sopenharmony_ci ibdev_dbg(aq->efa_dev, 29362306a36Sopenharmony_ci "Take completion ctxt for command_id %#x\n", cmd_id); 29462306a36Sopenharmony_ci } 29562306a36Sopenharmony_ci 29662306a36Sopenharmony_ci return &aq->comp_ctx[ctx_id]; 29762306a36Sopenharmony_ci} 29862306a36Sopenharmony_ci 29962306a36Sopenharmony_cistatic struct efa_comp_ctx *__efa_com_submit_admin_cmd(struct efa_com_admin_queue *aq, 30062306a36Sopenharmony_ci struct efa_admin_aq_entry *cmd, 30162306a36Sopenharmony_ci size_t cmd_size_in_bytes, 30262306a36Sopenharmony_ci struct efa_admin_acq_entry *comp, 30362306a36Sopenharmony_ci size_t comp_size_in_bytes) 30462306a36Sopenharmony_ci{ 30562306a36Sopenharmony_ci struct efa_admin_aq_entry *aqe; 30662306a36Sopenharmony_ci struct efa_comp_ctx *comp_ctx; 30762306a36Sopenharmony_ci u16 queue_size_mask; 30862306a36Sopenharmony_ci u16 cmd_id; 30962306a36Sopenharmony_ci u16 ctx_id; 31062306a36Sopenharmony_ci u16 pi; 31162306a36Sopenharmony_ci 31262306a36Sopenharmony_ci queue_size_mask = aq->depth - 1; 31362306a36Sopenharmony_ci pi = aq->sq.pc & queue_size_mask; 31462306a36Sopenharmony_ci 31562306a36Sopenharmony_ci ctx_id = efa_com_alloc_ctx_id(aq); 31662306a36Sopenharmony_ci 31762306a36Sopenharmony_ci /* cmd_id LSBs are the ctx_id and MSBs are entropy bits from pc */ 31862306a36Sopenharmony_ci cmd_id = ctx_id & queue_size_mask; 31962306a36Sopenharmony_ci cmd_id |= aq->sq.pc & ~queue_size_mask; 32062306a36Sopenharmony_ci cmd_id &= EFA_ADMIN_AQ_COMMON_DESC_COMMAND_ID_MASK; 32162306a36Sopenharmony_ci 32262306a36Sopenharmony_ci cmd->aq_common_descriptor.command_id = cmd_id; 32362306a36Sopenharmony_ci EFA_SET(&cmd->aq_common_descriptor.flags, 32462306a36Sopenharmony_ci EFA_ADMIN_AQ_COMMON_DESC_PHASE, aq->sq.phase); 32562306a36Sopenharmony_ci 32662306a36Sopenharmony_ci comp_ctx = efa_com_get_comp_ctx(aq, cmd_id, true); 32762306a36Sopenharmony_ci if (!comp_ctx) { 32862306a36Sopenharmony_ci efa_com_dealloc_ctx_id(aq, ctx_id); 32962306a36Sopenharmony_ci return ERR_PTR(-EINVAL); 33062306a36Sopenharmony_ci } 33162306a36Sopenharmony_ci 33262306a36Sopenharmony_ci comp_ctx->status = EFA_CMD_SUBMITTED; 33362306a36Sopenharmony_ci comp_ctx->comp_size = comp_size_in_bytes; 33462306a36Sopenharmony_ci comp_ctx->user_cqe = comp; 33562306a36Sopenharmony_ci comp_ctx->cmd_opcode = cmd->aq_common_descriptor.opcode; 33662306a36Sopenharmony_ci 33762306a36Sopenharmony_ci reinit_completion(&comp_ctx->wait_event); 33862306a36Sopenharmony_ci 33962306a36Sopenharmony_ci aqe = &aq->sq.entries[pi]; 34062306a36Sopenharmony_ci memset(aqe, 0, sizeof(*aqe)); 34162306a36Sopenharmony_ci memcpy(aqe, cmd, cmd_size_in_bytes); 34262306a36Sopenharmony_ci 34362306a36Sopenharmony_ci aq->sq.pc++; 34462306a36Sopenharmony_ci atomic64_inc(&aq->stats.submitted_cmd); 34562306a36Sopenharmony_ci 34662306a36Sopenharmony_ci if ((aq->sq.pc & queue_size_mask) == 0) 34762306a36Sopenharmony_ci aq->sq.phase = !aq->sq.phase; 34862306a36Sopenharmony_ci 34962306a36Sopenharmony_ci /* barrier not needed in case of writel */ 35062306a36Sopenharmony_ci writel(aq->sq.pc, aq->sq.db_addr); 35162306a36Sopenharmony_ci 35262306a36Sopenharmony_ci return comp_ctx; 35362306a36Sopenharmony_ci} 35462306a36Sopenharmony_ci 35562306a36Sopenharmony_cistatic inline int efa_com_init_comp_ctxt(struct efa_com_admin_queue *aq) 35662306a36Sopenharmony_ci{ 35762306a36Sopenharmony_ci size_t pool_size = aq->depth * sizeof(*aq->comp_ctx_pool); 35862306a36Sopenharmony_ci size_t size = aq->depth * sizeof(struct efa_comp_ctx); 35962306a36Sopenharmony_ci struct efa_comp_ctx *comp_ctx; 36062306a36Sopenharmony_ci u16 i; 36162306a36Sopenharmony_ci 36262306a36Sopenharmony_ci aq->comp_ctx = devm_kzalloc(aq->dmadev, size, GFP_KERNEL); 36362306a36Sopenharmony_ci aq->comp_ctx_pool = devm_kzalloc(aq->dmadev, pool_size, GFP_KERNEL); 36462306a36Sopenharmony_ci if (!aq->comp_ctx || !aq->comp_ctx_pool) { 36562306a36Sopenharmony_ci devm_kfree(aq->dmadev, aq->comp_ctx_pool); 36662306a36Sopenharmony_ci devm_kfree(aq->dmadev, aq->comp_ctx); 36762306a36Sopenharmony_ci return -ENOMEM; 36862306a36Sopenharmony_ci } 36962306a36Sopenharmony_ci 37062306a36Sopenharmony_ci for (i = 0; i < aq->depth; i++) { 37162306a36Sopenharmony_ci comp_ctx = efa_com_get_comp_ctx(aq, i, false); 37262306a36Sopenharmony_ci if (comp_ctx) 37362306a36Sopenharmony_ci init_completion(&comp_ctx->wait_event); 37462306a36Sopenharmony_ci 37562306a36Sopenharmony_ci aq->comp_ctx_pool[i] = i; 37662306a36Sopenharmony_ci } 37762306a36Sopenharmony_ci 37862306a36Sopenharmony_ci spin_lock_init(&aq->comp_ctx_lock); 37962306a36Sopenharmony_ci 38062306a36Sopenharmony_ci aq->comp_ctx_pool_next = 0; 38162306a36Sopenharmony_ci 38262306a36Sopenharmony_ci return 0; 38362306a36Sopenharmony_ci} 38462306a36Sopenharmony_ci 38562306a36Sopenharmony_cistatic struct efa_comp_ctx *efa_com_submit_admin_cmd(struct efa_com_admin_queue *aq, 38662306a36Sopenharmony_ci struct efa_admin_aq_entry *cmd, 38762306a36Sopenharmony_ci size_t cmd_size_in_bytes, 38862306a36Sopenharmony_ci struct efa_admin_acq_entry *comp, 38962306a36Sopenharmony_ci size_t comp_size_in_bytes) 39062306a36Sopenharmony_ci{ 39162306a36Sopenharmony_ci struct efa_comp_ctx *comp_ctx; 39262306a36Sopenharmony_ci 39362306a36Sopenharmony_ci spin_lock(&aq->sq.lock); 39462306a36Sopenharmony_ci if (!test_bit(EFA_AQ_STATE_RUNNING_BIT, &aq->state)) { 39562306a36Sopenharmony_ci ibdev_err_ratelimited(aq->efa_dev, "Admin queue is closed\n"); 39662306a36Sopenharmony_ci spin_unlock(&aq->sq.lock); 39762306a36Sopenharmony_ci return ERR_PTR(-ENODEV); 39862306a36Sopenharmony_ci } 39962306a36Sopenharmony_ci 40062306a36Sopenharmony_ci comp_ctx = __efa_com_submit_admin_cmd(aq, cmd, cmd_size_in_bytes, comp, 40162306a36Sopenharmony_ci comp_size_in_bytes); 40262306a36Sopenharmony_ci spin_unlock(&aq->sq.lock); 40362306a36Sopenharmony_ci if (IS_ERR(comp_ctx)) 40462306a36Sopenharmony_ci clear_bit(EFA_AQ_STATE_RUNNING_BIT, &aq->state); 40562306a36Sopenharmony_ci 40662306a36Sopenharmony_ci return comp_ctx; 40762306a36Sopenharmony_ci} 40862306a36Sopenharmony_ci 40962306a36Sopenharmony_cistatic void efa_com_handle_single_admin_completion(struct efa_com_admin_queue *aq, 41062306a36Sopenharmony_ci struct efa_admin_acq_entry *cqe) 41162306a36Sopenharmony_ci{ 41262306a36Sopenharmony_ci struct efa_comp_ctx *comp_ctx; 41362306a36Sopenharmony_ci u16 cmd_id; 41462306a36Sopenharmony_ci 41562306a36Sopenharmony_ci cmd_id = EFA_GET(&cqe->acq_common_descriptor.command, 41662306a36Sopenharmony_ci EFA_ADMIN_ACQ_COMMON_DESC_COMMAND_ID); 41762306a36Sopenharmony_ci 41862306a36Sopenharmony_ci comp_ctx = efa_com_get_comp_ctx(aq, cmd_id, false); 41962306a36Sopenharmony_ci if (!comp_ctx) { 42062306a36Sopenharmony_ci ibdev_err(aq->efa_dev, 42162306a36Sopenharmony_ci "comp_ctx is NULL. Changing the admin queue running state\n"); 42262306a36Sopenharmony_ci clear_bit(EFA_AQ_STATE_RUNNING_BIT, &aq->state); 42362306a36Sopenharmony_ci return; 42462306a36Sopenharmony_ci } 42562306a36Sopenharmony_ci 42662306a36Sopenharmony_ci comp_ctx->status = EFA_CMD_COMPLETED; 42762306a36Sopenharmony_ci memcpy(comp_ctx->user_cqe, cqe, comp_ctx->comp_size); 42862306a36Sopenharmony_ci 42962306a36Sopenharmony_ci if (!test_bit(EFA_AQ_STATE_POLLING_BIT, &aq->state)) 43062306a36Sopenharmony_ci complete(&comp_ctx->wait_event); 43162306a36Sopenharmony_ci} 43262306a36Sopenharmony_ci 43362306a36Sopenharmony_cistatic void efa_com_handle_admin_completion(struct efa_com_admin_queue *aq) 43462306a36Sopenharmony_ci{ 43562306a36Sopenharmony_ci struct efa_admin_acq_entry *cqe; 43662306a36Sopenharmony_ci u16 queue_size_mask; 43762306a36Sopenharmony_ci u16 comp_num = 0; 43862306a36Sopenharmony_ci u8 phase; 43962306a36Sopenharmony_ci u16 ci; 44062306a36Sopenharmony_ci 44162306a36Sopenharmony_ci queue_size_mask = aq->depth - 1; 44262306a36Sopenharmony_ci 44362306a36Sopenharmony_ci ci = aq->cq.cc & queue_size_mask; 44462306a36Sopenharmony_ci phase = aq->cq.phase; 44562306a36Sopenharmony_ci 44662306a36Sopenharmony_ci cqe = &aq->cq.entries[ci]; 44762306a36Sopenharmony_ci 44862306a36Sopenharmony_ci /* Go over all the completions */ 44962306a36Sopenharmony_ci while ((READ_ONCE(cqe->acq_common_descriptor.flags) & 45062306a36Sopenharmony_ci EFA_ADMIN_ACQ_COMMON_DESC_PHASE_MASK) == phase) { 45162306a36Sopenharmony_ci /* 45262306a36Sopenharmony_ci * Do not read the rest of the completion entry before the 45362306a36Sopenharmony_ci * phase bit was validated 45462306a36Sopenharmony_ci */ 45562306a36Sopenharmony_ci dma_rmb(); 45662306a36Sopenharmony_ci efa_com_handle_single_admin_completion(aq, cqe); 45762306a36Sopenharmony_ci 45862306a36Sopenharmony_ci ci++; 45962306a36Sopenharmony_ci comp_num++; 46062306a36Sopenharmony_ci if (ci == aq->depth) { 46162306a36Sopenharmony_ci ci = 0; 46262306a36Sopenharmony_ci phase = !phase; 46362306a36Sopenharmony_ci } 46462306a36Sopenharmony_ci 46562306a36Sopenharmony_ci cqe = &aq->cq.entries[ci]; 46662306a36Sopenharmony_ci } 46762306a36Sopenharmony_ci 46862306a36Sopenharmony_ci aq->cq.cc += comp_num; 46962306a36Sopenharmony_ci aq->cq.phase = phase; 47062306a36Sopenharmony_ci aq->sq.cc += comp_num; 47162306a36Sopenharmony_ci atomic64_add(comp_num, &aq->stats.completed_cmd); 47262306a36Sopenharmony_ci} 47362306a36Sopenharmony_ci 47462306a36Sopenharmony_cistatic int efa_com_comp_status_to_errno(u8 comp_status) 47562306a36Sopenharmony_ci{ 47662306a36Sopenharmony_ci switch (comp_status) { 47762306a36Sopenharmony_ci case EFA_ADMIN_SUCCESS: 47862306a36Sopenharmony_ci return 0; 47962306a36Sopenharmony_ci case EFA_ADMIN_RESOURCE_ALLOCATION_FAILURE: 48062306a36Sopenharmony_ci return -ENOMEM; 48162306a36Sopenharmony_ci case EFA_ADMIN_UNSUPPORTED_OPCODE: 48262306a36Sopenharmony_ci return -EOPNOTSUPP; 48362306a36Sopenharmony_ci case EFA_ADMIN_BAD_OPCODE: 48462306a36Sopenharmony_ci case EFA_ADMIN_MALFORMED_REQUEST: 48562306a36Sopenharmony_ci case EFA_ADMIN_ILLEGAL_PARAMETER: 48662306a36Sopenharmony_ci case EFA_ADMIN_UNKNOWN_ERROR: 48762306a36Sopenharmony_ci return -EINVAL; 48862306a36Sopenharmony_ci default: 48962306a36Sopenharmony_ci return -EINVAL; 49062306a36Sopenharmony_ci } 49162306a36Sopenharmony_ci} 49262306a36Sopenharmony_ci 49362306a36Sopenharmony_cistatic int efa_com_wait_and_process_admin_cq_polling(struct efa_comp_ctx *comp_ctx, 49462306a36Sopenharmony_ci struct efa_com_admin_queue *aq) 49562306a36Sopenharmony_ci{ 49662306a36Sopenharmony_ci unsigned long timeout; 49762306a36Sopenharmony_ci unsigned long flags; 49862306a36Sopenharmony_ci int err; 49962306a36Sopenharmony_ci 50062306a36Sopenharmony_ci timeout = jiffies + usecs_to_jiffies(aq->completion_timeout); 50162306a36Sopenharmony_ci 50262306a36Sopenharmony_ci while (1) { 50362306a36Sopenharmony_ci spin_lock_irqsave(&aq->cq.lock, flags); 50462306a36Sopenharmony_ci efa_com_handle_admin_completion(aq); 50562306a36Sopenharmony_ci spin_unlock_irqrestore(&aq->cq.lock, flags); 50662306a36Sopenharmony_ci 50762306a36Sopenharmony_ci if (comp_ctx->status != EFA_CMD_SUBMITTED) 50862306a36Sopenharmony_ci break; 50962306a36Sopenharmony_ci 51062306a36Sopenharmony_ci if (time_is_before_jiffies(timeout)) { 51162306a36Sopenharmony_ci ibdev_err_ratelimited( 51262306a36Sopenharmony_ci aq->efa_dev, 51362306a36Sopenharmony_ci "Wait for completion (polling) timeout\n"); 51462306a36Sopenharmony_ci /* EFA didn't have any completion */ 51562306a36Sopenharmony_ci atomic64_inc(&aq->stats.no_completion); 51662306a36Sopenharmony_ci 51762306a36Sopenharmony_ci clear_bit(EFA_AQ_STATE_RUNNING_BIT, &aq->state); 51862306a36Sopenharmony_ci err = -ETIME; 51962306a36Sopenharmony_ci goto out; 52062306a36Sopenharmony_ci } 52162306a36Sopenharmony_ci 52262306a36Sopenharmony_ci msleep(aq->poll_interval); 52362306a36Sopenharmony_ci } 52462306a36Sopenharmony_ci 52562306a36Sopenharmony_ci err = efa_com_comp_status_to_errno(comp_ctx->user_cqe->acq_common_descriptor.status); 52662306a36Sopenharmony_ciout: 52762306a36Sopenharmony_ci efa_com_put_comp_ctx(aq, comp_ctx); 52862306a36Sopenharmony_ci return err; 52962306a36Sopenharmony_ci} 53062306a36Sopenharmony_ci 53162306a36Sopenharmony_cistatic int efa_com_wait_and_process_admin_cq_interrupts(struct efa_comp_ctx *comp_ctx, 53262306a36Sopenharmony_ci struct efa_com_admin_queue *aq) 53362306a36Sopenharmony_ci{ 53462306a36Sopenharmony_ci unsigned long flags; 53562306a36Sopenharmony_ci int err; 53662306a36Sopenharmony_ci 53762306a36Sopenharmony_ci wait_for_completion_timeout(&comp_ctx->wait_event, 53862306a36Sopenharmony_ci usecs_to_jiffies(aq->completion_timeout)); 53962306a36Sopenharmony_ci 54062306a36Sopenharmony_ci /* 54162306a36Sopenharmony_ci * In case the command wasn't completed find out the root cause. 54262306a36Sopenharmony_ci * There might be 2 kinds of errors 54362306a36Sopenharmony_ci * 1) No completion (timeout reached) 54462306a36Sopenharmony_ci * 2) There is completion but the device didn't get any msi-x interrupt. 54562306a36Sopenharmony_ci */ 54662306a36Sopenharmony_ci if (comp_ctx->status == EFA_CMD_SUBMITTED) { 54762306a36Sopenharmony_ci spin_lock_irqsave(&aq->cq.lock, flags); 54862306a36Sopenharmony_ci efa_com_handle_admin_completion(aq); 54962306a36Sopenharmony_ci spin_unlock_irqrestore(&aq->cq.lock, flags); 55062306a36Sopenharmony_ci 55162306a36Sopenharmony_ci atomic64_inc(&aq->stats.no_completion); 55262306a36Sopenharmony_ci 55362306a36Sopenharmony_ci if (comp_ctx->status == EFA_CMD_COMPLETED) 55462306a36Sopenharmony_ci ibdev_err_ratelimited( 55562306a36Sopenharmony_ci aq->efa_dev, 55662306a36Sopenharmony_ci "The device sent a completion but the driver didn't receive any MSI-X interrupt for admin cmd %s(%d) status %d (ctx: 0x%p, sq producer: %d, sq consumer: %d, cq consumer: %d)\n", 55762306a36Sopenharmony_ci efa_com_cmd_str(comp_ctx->cmd_opcode), 55862306a36Sopenharmony_ci comp_ctx->cmd_opcode, comp_ctx->status, 55962306a36Sopenharmony_ci comp_ctx, aq->sq.pc, aq->sq.cc, aq->cq.cc); 56062306a36Sopenharmony_ci else 56162306a36Sopenharmony_ci ibdev_err_ratelimited( 56262306a36Sopenharmony_ci aq->efa_dev, 56362306a36Sopenharmony_ci "The device didn't send any completion for admin cmd %s(%d) status %d (ctx 0x%p, sq producer: %d, sq consumer: %d, cq consumer: %d)\n", 56462306a36Sopenharmony_ci efa_com_cmd_str(comp_ctx->cmd_opcode), 56562306a36Sopenharmony_ci comp_ctx->cmd_opcode, comp_ctx->status, 56662306a36Sopenharmony_ci comp_ctx, aq->sq.pc, aq->sq.cc, aq->cq.cc); 56762306a36Sopenharmony_ci 56862306a36Sopenharmony_ci clear_bit(EFA_AQ_STATE_RUNNING_BIT, &aq->state); 56962306a36Sopenharmony_ci err = -ETIME; 57062306a36Sopenharmony_ci goto out; 57162306a36Sopenharmony_ci } 57262306a36Sopenharmony_ci 57362306a36Sopenharmony_ci err = efa_com_comp_status_to_errno(comp_ctx->user_cqe->acq_common_descriptor.status); 57462306a36Sopenharmony_ciout: 57562306a36Sopenharmony_ci efa_com_put_comp_ctx(aq, comp_ctx); 57662306a36Sopenharmony_ci return err; 57762306a36Sopenharmony_ci} 57862306a36Sopenharmony_ci 57962306a36Sopenharmony_ci/* 58062306a36Sopenharmony_ci * There are two types to wait for completion. 58162306a36Sopenharmony_ci * Polling mode - wait until the completion is available. 58262306a36Sopenharmony_ci * Async mode - wait on wait queue until the completion is ready 58362306a36Sopenharmony_ci * (or the timeout expired). 58462306a36Sopenharmony_ci * It is expected that the IRQ called efa_com_handle_admin_completion 58562306a36Sopenharmony_ci * to mark the completions. 58662306a36Sopenharmony_ci */ 58762306a36Sopenharmony_cistatic int efa_com_wait_and_process_admin_cq(struct efa_comp_ctx *comp_ctx, 58862306a36Sopenharmony_ci struct efa_com_admin_queue *aq) 58962306a36Sopenharmony_ci{ 59062306a36Sopenharmony_ci if (test_bit(EFA_AQ_STATE_POLLING_BIT, &aq->state)) 59162306a36Sopenharmony_ci return efa_com_wait_and_process_admin_cq_polling(comp_ctx, aq); 59262306a36Sopenharmony_ci 59362306a36Sopenharmony_ci return efa_com_wait_and_process_admin_cq_interrupts(comp_ctx, aq); 59462306a36Sopenharmony_ci} 59562306a36Sopenharmony_ci 59662306a36Sopenharmony_ci/** 59762306a36Sopenharmony_ci * efa_com_cmd_exec - Execute admin command 59862306a36Sopenharmony_ci * @aq: admin queue. 59962306a36Sopenharmony_ci * @cmd: the admin command to execute. 60062306a36Sopenharmony_ci * @cmd_size: the command size. 60162306a36Sopenharmony_ci * @comp: command completion return entry. 60262306a36Sopenharmony_ci * @comp_size: command completion size. 60362306a36Sopenharmony_ci * Submit an admin command and then wait until the device will return a 60462306a36Sopenharmony_ci * completion. 60562306a36Sopenharmony_ci * The completion will be copied into comp. 60662306a36Sopenharmony_ci * 60762306a36Sopenharmony_ci * @return - 0 on success, negative value on failure. 60862306a36Sopenharmony_ci */ 60962306a36Sopenharmony_ciint efa_com_cmd_exec(struct efa_com_admin_queue *aq, 61062306a36Sopenharmony_ci struct efa_admin_aq_entry *cmd, 61162306a36Sopenharmony_ci size_t cmd_size, 61262306a36Sopenharmony_ci struct efa_admin_acq_entry *comp, 61362306a36Sopenharmony_ci size_t comp_size) 61462306a36Sopenharmony_ci{ 61562306a36Sopenharmony_ci struct efa_comp_ctx *comp_ctx; 61662306a36Sopenharmony_ci int err; 61762306a36Sopenharmony_ci 61862306a36Sopenharmony_ci might_sleep(); 61962306a36Sopenharmony_ci 62062306a36Sopenharmony_ci /* In case of queue FULL */ 62162306a36Sopenharmony_ci down(&aq->avail_cmds); 62262306a36Sopenharmony_ci 62362306a36Sopenharmony_ci ibdev_dbg(aq->efa_dev, "%s (opcode %d)\n", 62462306a36Sopenharmony_ci efa_com_cmd_str(cmd->aq_common_descriptor.opcode), 62562306a36Sopenharmony_ci cmd->aq_common_descriptor.opcode); 62662306a36Sopenharmony_ci comp_ctx = efa_com_submit_admin_cmd(aq, cmd, cmd_size, comp, comp_size); 62762306a36Sopenharmony_ci if (IS_ERR(comp_ctx)) { 62862306a36Sopenharmony_ci ibdev_err_ratelimited( 62962306a36Sopenharmony_ci aq->efa_dev, 63062306a36Sopenharmony_ci "Failed to submit command %s (opcode %u) err %ld\n", 63162306a36Sopenharmony_ci efa_com_cmd_str(cmd->aq_common_descriptor.opcode), 63262306a36Sopenharmony_ci cmd->aq_common_descriptor.opcode, PTR_ERR(comp_ctx)); 63362306a36Sopenharmony_ci 63462306a36Sopenharmony_ci up(&aq->avail_cmds); 63562306a36Sopenharmony_ci atomic64_inc(&aq->stats.cmd_err); 63662306a36Sopenharmony_ci return PTR_ERR(comp_ctx); 63762306a36Sopenharmony_ci } 63862306a36Sopenharmony_ci 63962306a36Sopenharmony_ci err = efa_com_wait_and_process_admin_cq(comp_ctx, aq); 64062306a36Sopenharmony_ci if (err) { 64162306a36Sopenharmony_ci ibdev_err_ratelimited( 64262306a36Sopenharmony_ci aq->efa_dev, 64362306a36Sopenharmony_ci "Failed to process command %s (opcode %u) comp_status %d err %d\n", 64462306a36Sopenharmony_ci efa_com_cmd_str(cmd->aq_common_descriptor.opcode), 64562306a36Sopenharmony_ci cmd->aq_common_descriptor.opcode, 64662306a36Sopenharmony_ci comp_ctx->user_cqe->acq_common_descriptor.status, err); 64762306a36Sopenharmony_ci atomic64_inc(&aq->stats.cmd_err); 64862306a36Sopenharmony_ci } 64962306a36Sopenharmony_ci 65062306a36Sopenharmony_ci up(&aq->avail_cmds); 65162306a36Sopenharmony_ci 65262306a36Sopenharmony_ci return err; 65362306a36Sopenharmony_ci} 65462306a36Sopenharmony_ci 65562306a36Sopenharmony_ci/** 65662306a36Sopenharmony_ci * efa_com_admin_destroy - Destroy the admin and the async events queues. 65762306a36Sopenharmony_ci * @edev: EFA communication layer struct 65862306a36Sopenharmony_ci */ 65962306a36Sopenharmony_civoid efa_com_admin_destroy(struct efa_com_dev *edev) 66062306a36Sopenharmony_ci{ 66162306a36Sopenharmony_ci struct efa_com_admin_queue *aq = &edev->aq; 66262306a36Sopenharmony_ci struct efa_com_aenq *aenq = &edev->aenq; 66362306a36Sopenharmony_ci struct efa_com_admin_cq *cq = &aq->cq; 66462306a36Sopenharmony_ci struct efa_com_admin_sq *sq = &aq->sq; 66562306a36Sopenharmony_ci u16 size; 66662306a36Sopenharmony_ci 66762306a36Sopenharmony_ci clear_bit(EFA_AQ_STATE_RUNNING_BIT, &aq->state); 66862306a36Sopenharmony_ci 66962306a36Sopenharmony_ci devm_kfree(edev->dmadev, aq->comp_ctx_pool); 67062306a36Sopenharmony_ci devm_kfree(edev->dmadev, aq->comp_ctx); 67162306a36Sopenharmony_ci 67262306a36Sopenharmony_ci size = aq->depth * sizeof(*sq->entries); 67362306a36Sopenharmony_ci dma_free_coherent(edev->dmadev, size, sq->entries, sq->dma_addr); 67462306a36Sopenharmony_ci 67562306a36Sopenharmony_ci size = aq->depth * sizeof(*cq->entries); 67662306a36Sopenharmony_ci dma_free_coherent(edev->dmadev, size, cq->entries, cq->dma_addr); 67762306a36Sopenharmony_ci 67862306a36Sopenharmony_ci size = aenq->depth * sizeof(*aenq->entries); 67962306a36Sopenharmony_ci dma_free_coherent(edev->dmadev, size, aenq->entries, aenq->dma_addr); 68062306a36Sopenharmony_ci} 68162306a36Sopenharmony_ci 68262306a36Sopenharmony_ci/** 68362306a36Sopenharmony_ci * efa_com_set_admin_polling_mode - Set the admin completion queue polling mode 68462306a36Sopenharmony_ci * @edev: EFA communication layer struct 68562306a36Sopenharmony_ci * @polling: Enable/Disable polling mode 68662306a36Sopenharmony_ci * 68762306a36Sopenharmony_ci * Set the admin completion mode. 68862306a36Sopenharmony_ci */ 68962306a36Sopenharmony_civoid efa_com_set_admin_polling_mode(struct efa_com_dev *edev, bool polling) 69062306a36Sopenharmony_ci{ 69162306a36Sopenharmony_ci u32 mask_value = 0; 69262306a36Sopenharmony_ci 69362306a36Sopenharmony_ci if (polling) 69462306a36Sopenharmony_ci EFA_SET(&mask_value, EFA_REGS_INTR_MASK_EN, 1); 69562306a36Sopenharmony_ci 69662306a36Sopenharmony_ci writel(mask_value, edev->reg_bar + EFA_REGS_INTR_MASK_OFF); 69762306a36Sopenharmony_ci if (polling) 69862306a36Sopenharmony_ci set_bit(EFA_AQ_STATE_POLLING_BIT, &edev->aq.state); 69962306a36Sopenharmony_ci else 70062306a36Sopenharmony_ci clear_bit(EFA_AQ_STATE_POLLING_BIT, &edev->aq.state); 70162306a36Sopenharmony_ci} 70262306a36Sopenharmony_ci 70362306a36Sopenharmony_cistatic void efa_com_stats_init(struct efa_com_dev *edev) 70462306a36Sopenharmony_ci{ 70562306a36Sopenharmony_ci atomic64_t *s = (atomic64_t *)&edev->aq.stats; 70662306a36Sopenharmony_ci int i; 70762306a36Sopenharmony_ci 70862306a36Sopenharmony_ci for (i = 0; i < sizeof(edev->aq.stats) / sizeof(*s); i++, s++) 70962306a36Sopenharmony_ci atomic64_set(s, 0); 71062306a36Sopenharmony_ci} 71162306a36Sopenharmony_ci 71262306a36Sopenharmony_ci/** 71362306a36Sopenharmony_ci * efa_com_admin_init - Init the admin and the async queues 71462306a36Sopenharmony_ci * @edev: EFA communication layer struct 71562306a36Sopenharmony_ci * @aenq_handlers: Those handlers to be called upon event. 71662306a36Sopenharmony_ci * 71762306a36Sopenharmony_ci * Initialize the admin submission and completion queues. 71862306a36Sopenharmony_ci * Initialize the asynchronous events notification queues. 71962306a36Sopenharmony_ci * 72062306a36Sopenharmony_ci * @return - 0 on success, negative value on failure. 72162306a36Sopenharmony_ci */ 72262306a36Sopenharmony_ciint efa_com_admin_init(struct efa_com_dev *edev, 72362306a36Sopenharmony_ci struct efa_aenq_handlers *aenq_handlers) 72462306a36Sopenharmony_ci{ 72562306a36Sopenharmony_ci struct efa_com_admin_queue *aq = &edev->aq; 72662306a36Sopenharmony_ci u32 timeout; 72762306a36Sopenharmony_ci u32 dev_sts; 72862306a36Sopenharmony_ci u32 cap; 72962306a36Sopenharmony_ci int err; 73062306a36Sopenharmony_ci 73162306a36Sopenharmony_ci dev_sts = efa_com_reg_read32(edev, EFA_REGS_DEV_STS_OFF); 73262306a36Sopenharmony_ci if (!EFA_GET(&dev_sts, EFA_REGS_DEV_STS_READY)) { 73362306a36Sopenharmony_ci ibdev_err(edev->efa_dev, 73462306a36Sopenharmony_ci "Device isn't ready, abort com init %#x\n", dev_sts); 73562306a36Sopenharmony_ci return -ENODEV; 73662306a36Sopenharmony_ci } 73762306a36Sopenharmony_ci 73862306a36Sopenharmony_ci aq->depth = EFA_ADMIN_QUEUE_DEPTH; 73962306a36Sopenharmony_ci 74062306a36Sopenharmony_ci aq->dmadev = edev->dmadev; 74162306a36Sopenharmony_ci aq->efa_dev = edev->efa_dev; 74262306a36Sopenharmony_ci set_bit(EFA_AQ_STATE_POLLING_BIT, &aq->state); 74362306a36Sopenharmony_ci 74462306a36Sopenharmony_ci sema_init(&aq->avail_cmds, aq->depth); 74562306a36Sopenharmony_ci 74662306a36Sopenharmony_ci efa_com_stats_init(edev); 74762306a36Sopenharmony_ci 74862306a36Sopenharmony_ci err = efa_com_init_comp_ctxt(aq); 74962306a36Sopenharmony_ci if (err) 75062306a36Sopenharmony_ci return err; 75162306a36Sopenharmony_ci 75262306a36Sopenharmony_ci err = efa_com_admin_init_sq(edev); 75362306a36Sopenharmony_ci if (err) 75462306a36Sopenharmony_ci goto err_destroy_comp_ctxt; 75562306a36Sopenharmony_ci 75662306a36Sopenharmony_ci err = efa_com_admin_init_cq(edev); 75762306a36Sopenharmony_ci if (err) 75862306a36Sopenharmony_ci goto err_destroy_sq; 75962306a36Sopenharmony_ci 76062306a36Sopenharmony_ci efa_com_set_admin_polling_mode(edev, false); 76162306a36Sopenharmony_ci 76262306a36Sopenharmony_ci err = efa_com_admin_init_aenq(edev, aenq_handlers); 76362306a36Sopenharmony_ci if (err) 76462306a36Sopenharmony_ci goto err_destroy_cq; 76562306a36Sopenharmony_ci 76662306a36Sopenharmony_ci cap = efa_com_reg_read32(edev, EFA_REGS_CAPS_OFF); 76762306a36Sopenharmony_ci timeout = EFA_GET(&cap, EFA_REGS_CAPS_ADMIN_CMD_TO); 76862306a36Sopenharmony_ci if (timeout) 76962306a36Sopenharmony_ci /* the resolution of timeout reg is 100ms */ 77062306a36Sopenharmony_ci aq->completion_timeout = timeout * 100000; 77162306a36Sopenharmony_ci else 77262306a36Sopenharmony_ci aq->completion_timeout = ADMIN_CMD_TIMEOUT_US; 77362306a36Sopenharmony_ci 77462306a36Sopenharmony_ci aq->poll_interval = EFA_POLL_INTERVAL_MS; 77562306a36Sopenharmony_ci 77662306a36Sopenharmony_ci set_bit(EFA_AQ_STATE_RUNNING_BIT, &aq->state); 77762306a36Sopenharmony_ci 77862306a36Sopenharmony_ci return 0; 77962306a36Sopenharmony_ci 78062306a36Sopenharmony_cierr_destroy_cq: 78162306a36Sopenharmony_ci dma_free_coherent(edev->dmadev, aq->depth * sizeof(*aq->cq.entries), 78262306a36Sopenharmony_ci aq->cq.entries, aq->cq.dma_addr); 78362306a36Sopenharmony_cierr_destroy_sq: 78462306a36Sopenharmony_ci dma_free_coherent(edev->dmadev, aq->depth * sizeof(*aq->sq.entries), 78562306a36Sopenharmony_ci aq->sq.entries, aq->sq.dma_addr); 78662306a36Sopenharmony_cierr_destroy_comp_ctxt: 78762306a36Sopenharmony_ci devm_kfree(edev->dmadev, aq->comp_ctx); 78862306a36Sopenharmony_ci 78962306a36Sopenharmony_ci return err; 79062306a36Sopenharmony_ci} 79162306a36Sopenharmony_ci 79262306a36Sopenharmony_ci/** 79362306a36Sopenharmony_ci * efa_com_admin_q_comp_intr_handler - admin queue interrupt handler 79462306a36Sopenharmony_ci * @edev: EFA communication layer struct 79562306a36Sopenharmony_ci * 79662306a36Sopenharmony_ci * This method goes over the admin completion queue and wakes up 79762306a36Sopenharmony_ci * all the pending threads that wait on the commands wait event. 79862306a36Sopenharmony_ci * 79962306a36Sopenharmony_ci * Note: Should be called after MSI-X interrupt. 80062306a36Sopenharmony_ci */ 80162306a36Sopenharmony_civoid efa_com_admin_q_comp_intr_handler(struct efa_com_dev *edev) 80262306a36Sopenharmony_ci{ 80362306a36Sopenharmony_ci unsigned long flags; 80462306a36Sopenharmony_ci 80562306a36Sopenharmony_ci spin_lock_irqsave(&edev->aq.cq.lock, flags); 80662306a36Sopenharmony_ci efa_com_handle_admin_completion(&edev->aq); 80762306a36Sopenharmony_ci spin_unlock_irqrestore(&edev->aq.cq.lock, flags); 80862306a36Sopenharmony_ci} 80962306a36Sopenharmony_ci 81062306a36Sopenharmony_ci/* 81162306a36Sopenharmony_ci * efa_handle_specific_aenq_event: 81262306a36Sopenharmony_ci * return the handler that is relevant to the specific event group 81362306a36Sopenharmony_ci */ 81462306a36Sopenharmony_cistatic efa_aenq_handler efa_com_get_specific_aenq_cb(struct efa_com_dev *edev, 81562306a36Sopenharmony_ci u16 group) 81662306a36Sopenharmony_ci{ 81762306a36Sopenharmony_ci struct efa_aenq_handlers *aenq_handlers = edev->aenq.aenq_handlers; 81862306a36Sopenharmony_ci 81962306a36Sopenharmony_ci if (group < EFA_MAX_HANDLERS && aenq_handlers->handlers[group]) 82062306a36Sopenharmony_ci return aenq_handlers->handlers[group]; 82162306a36Sopenharmony_ci 82262306a36Sopenharmony_ci return aenq_handlers->unimplemented_handler; 82362306a36Sopenharmony_ci} 82462306a36Sopenharmony_ci 82562306a36Sopenharmony_ci/** 82662306a36Sopenharmony_ci * efa_com_aenq_intr_handler - AENQ interrupt handler 82762306a36Sopenharmony_ci * @edev: EFA communication layer struct 82862306a36Sopenharmony_ci * @data: Data of interrupt handler. 82962306a36Sopenharmony_ci * 83062306a36Sopenharmony_ci * Go over the async event notification queue and call the proper aenq handler. 83162306a36Sopenharmony_ci */ 83262306a36Sopenharmony_civoid efa_com_aenq_intr_handler(struct efa_com_dev *edev, void *data) 83362306a36Sopenharmony_ci{ 83462306a36Sopenharmony_ci struct efa_admin_aenq_common_desc *aenq_common; 83562306a36Sopenharmony_ci struct efa_com_aenq *aenq = &edev->aenq; 83662306a36Sopenharmony_ci struct efa_admin_aenq_entry *aenq_e; 83762306a36Sopenharmony_ci efa_aenq_handler handler_cb; 83862306a36Sopenharmony_ci u32 processed = 0; 83962306a36Sopenharmony_ci u8 phase; 84062306a36Sopenharmony_ci u32 ci; 84162306a36Sopenharmony_ci 84262306a36Sopenharmony_ci ci = aenq->cc & (aenq->depth - 1); 84362306a36Sopenharmony_ci phase = aenq->phase; 84462306a36Sopenharmony_ci aenq_e = &aenq->entries[ci]; /* Get first entry */ 84562306a36Sopenharmony_ci aenq_common = &aenq_e->aenq_common_desc; 84662306a36Sopenharmony_ci 84762306a36Sopenharmony_ci /* Go over all the events */ 84862306a36Sopenharmony_ci while ((READ_ONCE(aenq_common->flags) & 84962306a36Sopenharmony_ci EFA_ADMIN_AENQ_COMMON_DESC_PHASE_MASK) == phase) { 85062306a36Sopenharmony_ci /* 85162306a36Sopenharmony_ci * Do not read the rest of the completion entry before the 85262306a36Sopenharmony_ci * phase bit was validated 85362306a36Sopenharmony_ci */ 85462306a36Sopenharmony_ci dma_rmb(); 85562306a36Sopenharmony_ci 85662306a36Sopenharmony_ci /* Handle specific event*/ 85762306a36Sopenharmony_ci handler_cb = efa_com_get_specific_aenq_cb(edev, 85862306a36Sopenharmony_ci aenq_common->group); 85962306a36Sopenharmony_ci handler_cb(data, aenq_e); /* call the actual event handler*/ 86062306a36Sopenharmony_ci 86162306a36Sopenharmony_ci /* Get next event entry */ 86262306a36Sopenharmony_ci ci++; 86362306a36Sopenharmony_ci processed++; 86462306a36Sopenharmony_ci 86562306a36Sopenharmony_ci if (ci == aenq->depth) { 86662306a36Sopenharmony_ci ci = 0; 86762306a36Sopenharmony_ci phase = !phase; 86862306a36Sopenharmony_ci } 86962306a36Sopenharmony_ci aenq_e = &aenq->entries[ci]; 87062306a36Sopenharmony_ci aenq_common = &aenq_e->aenq_common_desc; 87162306a36Sopenharmony_ci } 87262306a36Sopenharmony_ci 87362306a36Sopenharmony_ci aenq->cc += processed; 87462306a36Sopenharmony_ci aenq->phase = phase; 87562306a36Sopenharmony_ci 87662306a36Sopenharmony_ci /* Don't update aenq doorbell if there weren't any processed events */ 87762306a36Sopenharmony_ci if (!processed) 87862306a36Sopenharmony_ci return; 87962306a36Sopenharmony_ci 88062306a36Sopenharmony_ci /* barrier not needed in case of writel */ 88162306a36Sopenharmony_ci writel(aenq->cc, edev->reg_bar + EFA_REGS_AENQ_CONS_DB_OFF); 88262306a36Sopenharmony_ci} 88362306a36Sopenharmony_ci 88462306a36Sopenharmony_cistatic void efa_com_mmio_reg_read_resp_addr_init(struct efa_com_dev *edev) 88562306a36Sopenharmony_ci{ 88662306a36Sopenharmony_ci struct efa_com_mmio_read *mmio_read = &edev->mmio_read; 88762306a36Sopenharmony_ci u32 addr_high; 88862306a36Sopenharmony_ci u32 addr_low; 88962306a36Sopenharmony_ci 89062306a36Sopenharmony_ci /* dma_addr_bits is unknown at this point */ 89162306a36Sopenharmony_ci addr_high = (mmio_read->read_resp_dma_addr >> 32) & GENMASK(31, 0); 89262306a36Sopenharmony_ci addr_low = mmio_read->read_resp_dma_addr & GENMASK(31, 0); 89362306a36Sopenharmony_ci 89462306a36Sopenharmony_ci writel(addr_high, edev->reg_bar + EFA_REGS_MMIO_RESP_HI_OFF); 89562306a36Sopenharmony_ci writel(addr_low, edev->reg_bar + EFA_REGS_MMIO_RESP_LO_OFF); 89662306a36Sopenharmony_ci} 89762306a36Sopenharmony_ci 89862306a36Sopenharmony_ciint efa_com_mmio_reg_read_init(struct efa_com_dev *edev) 89962306a36Sopenharmony_ci{ 90062306a36Sopenharmony_ci struct efa_com_mmio_read *mmio_read = &edev->mmio_read; 90162306a36Sopenharmony_ci 90262306a36Sopenharmony_ci spin_lock_init(&mmio_read->lock); 90362306a36Sopenharmony_ci mmio_read->read_resp = 90462306a36Sopenharmony_ci dma_alloc_coherent(edev->dmadev, sizeof(*mmio_read->read_resp), 90562306a36Sopenharmony_ci &mmio_read->read_resp_dma_addr, GFP_KERNEL); 90662306a36Sopenharmony_ci if (!mmio_read->read_resp) 90762306a36Sopenharmony_ci return -ENOMEM; 90862306a36Sopenharmony_ci 90962306a36Sopenharmony_ci efa_com_mmio_reg_read_resp_addr_init(edev); 91062306a36Sopenharmony_ci 91162306a36Sopenharmony_ci mmio_read->read_resp->req_id = 0; 91262306a36Sopenharmony_ci mmio_read->seq_num = 0; 91362306a36Sopenharmony_ci mmio_read->mmio_read_timeout = EFA_REG_READ_TIMEOUT_US; 91462306a36Sopenharmony_ci 91562306a36Sopenharmony_ci return 0; 91662306a36Sopenharmony_ci} 91762306a36Sopenharmony_ci 91862306a36Sopenharmony_civoid efa_com_mmio_reg_read_destroy(struct efa_com_dev *edev) 91962306a36Sopenharmony_ci{ 92062306a36Sopenharmony_ci struct efa_com_mmio_read *mmio_read = &edev->mmio_read; 92162306a36Sopenharmony_ci 92262306a36Sopenharmony_ci dma_free_coherent(edev->dmadev, sizeof(*mmio_read->read_resp), 92362306a36Sopenharmony_ci mmio_read->read_resp, mmio_read->read_resp_dma_addr); 92462306a36Sopenharmony_ci} 92562306a36Sopenharmony_ci 92662306a36Sopenharmony_ciint efa_com_validate_version(struct efa_com_dev *edev) 92762306a36Sopenharmony_ci{ 92862306a36Sopenharmony_ci u32 min_ctrl_ver = 0; 92962306a36Sopenharmony_ci u32 ctrl_ver_masked; 93062306a36Sopenharmony_ci u32 min_ver = 0; 93162306a36Sopenharmony_ci u32 ctrl_ver; 93262306a36Sopenharmony_ci u32 ver; 93362306a36Sopenharmony_ci 93462306a36Sopenharmony_ci /* 93562306a36Sopenharmony_ci * Make sure the EFA version and the controller version are at least 93662306a36Sopenharmony_ci * as the driver expects 93762306a36Sopenharmony_ci */ 93862306a36Sopenharmony_ci ver = efa_com_reg_read32(edev, EFA_REGS_VERSION_OFF); 93962306a36Sopenharmony_ci ctrl_ver = efa_com_reg_read32(edev, 94062306a36Sopenharmony_ci EFA_REGS_CONTROLLER_VERSION_OFF); 94162306a36Sopenharmony_ci 94262306a36Sopenharmony_ci ibdev_dbg(edev->efa_dev, "efa device version: %d.%d\n", 94362306a36Sopenharmony_ci EFA_GET(&ver, EFA_REGS_VERSION_MAJOR_VERSION), 94462306a36Sopenharmony_ci EFA_GET(&ver, EFA_REGS_VERSION_MINOR_VERSION)); 94562306a36Sopenharmony_ci 94662306a36Sopenharmony_ci EFA_SET(&min_ver, EFA_REGS_VERSION_MAJOR_VERSION, 94762306a36Sopenharmony_ci EFA_ADMIN_API_VERSION_MAJOR); 94862306a36Sopenharmony_ci EFA_SET(&min_ver, EFA_REGS_VERSION_MINOR_VERSION, 94962306a36Sopenharmony_ci EFA_ADMIN_API_VERSION_MINOR); 95062306a36Sopenharmony_ci if (ver < min_ver) { 95162306a36Sopenharmony_ci ibdev_err(edev->efa_dev, 95262306a36Sopenharmony_ci "EFA version is lower than the minimal version the driver supports\n"); 95362306a36Sopenharmony_ci return -EOPNOTSUPP; 95462306a36Sopenharmony_ci } 95562306a36Sopenharmony_ci 95662306a36Sopenharmony_ci ibdev_dbg( 95762306a36Sopenharmony_ci edev->efa_dev, 95862306a36Sopenharmony_ci "efa controller version: %d.%d.%d implementation version %d\n", 95962306a36Sopenharmony_ci EFA_GET(&ctrl_ver, EFA_REGS_CONTROLLER_VERSION_MAJOR_VERSION), 96062306a36Sopenharmony_ci EFA_GET(&ctrl_ver, EFA_REGS_CONTROLLER_VERSION_MINOR_VERSION), 96162306a36Sopenharmony_ci EFA_GET(&ctrl_ver, 96262306a36Sopenharmony_ci EFA_REGS_CONTROLLER_VERSION_SUBMINOR_VERSION), 96362306a36Sopenharmony_ci EFA_GET(&ctrl_ver, EFA_REGS_CONTROLLER_VERSION_IMPL_ID)); 96462306a36Sopenharmony_ci 96562306a36Sopenharmony_ci ctrl_ver_masked = 96662306a36Sopenharmony_ci EFA_GET(&ctrl_ver, EFA_REGS_CONTROLLER_VERSION_MAJOR_VERSION) | 96762306a36Sopenharmony_ci EFA_GET(&ctrl_ver, EFA_REGS_CONTROLLER_VERSION_MINOR_VERSION) | 96862306a36Sopenharmony_ci EFA_GET(&ctrl_ver, 96962306a36Sopenharmony_ci EFA_REGS_CONTROLLER_VERSION_SUBMINOR_VERSION); 97062306a36Sopenharmony_ci 97162306a36Sopenharmony_ci EFA_SET(&min_ctrl_ver, EFA_REGS_CONTROLLER_VERSION_MAJOR_VERSION, 97262306a36Sopenharmony_ci EFA_CTRL_MAJOR); 97362306a36Sopenharmony_ci EFA_SET(&min_ctrl_ver, EFA_REGS_CONTROLLER_VERSION_MINOR_VERSION, 97462306a36Sopenharmony_ci EFA_CTRL_MINOR); 97562306a36Sopenharmony_ci EFA_SET(&min_ctrl_ver, EFA_REGS_CONTROLLER_VERSION_SUBMINOR_VERSION, 97662306a36Sopenharmony_ci EFA_CTRL_SUB_MINOR); 97762306a36Sopenharmony_ci /* Validate the ctrl version without the implementation ID */ 97862306a36Sopenharmony_ci if (ctrl_ver_masked < min_ctrl_ver) { 97962306a36Sopenharmony_ci ibdev_err(edev->efa_dev, 98062306a36Sopenharmony_ci "EFA ctrl version is lower than the minimal ctrl version the driver supports\n"); 98162306a36Sopenharmony_ci return -EOPNOTSUPP; 98262306a36Sopenharmony_ci } 98362306a36Sopenharmony_ci 98462306a36Sopenharmony_ci return 0; 98562306a36Sopenharmony_ci} 98662306a36Sopenharmony_ci 98762306a36Sopenharmony_ci/** 98862306a36Sopenharmony_ci * efa_com_get_dma_width - Retrieve physical dma address width the device 98962306a36Sopenharmony_ci * supports. 99062306a36Sopenharmony_ci * @edev: EFA communication layer struct 99162306a36Sopenharmony_ci * 99262306a36Sopenharmony_ci * Retrieve the maximum physical address bits the device can handle. 99362306a36Sopenharmony_ci * 99462306a36Sopenharmony_ci * @return: > 0 on Success and negative value otherwise. 99562306a36Sopenharmony_ci */ 99662306a36Sopenharmony_ciint efa_com_get_dma_width(struct efa_com_dev *edev) 99762306a36Sopenharmony_ci{ 99862306a36Sopenharmony_ci u32 caps = efa_com_reg_read32(edev, EFA_REGS_CAPS_OFF); 99962306a36Sopenharmony_ci int width; 100062306a36Sopenharmony_ci 100162306a36Sopenharmony_ci width = EFA_GET(&caps, EFA_REGS_CAPS_DMA_ADDR_WIDTH); 100262306a36Sopenharmony_ci 100362306a36Sopenharmony_ci ibdev_dbg(edev->efa_dev, "DMA width: %d\n", width); 100462306a36Sopenharmony_ci 100562306a36Sopenharmony_ci if (width < 32 || width > 64) { 100662306a36Sopenharmony_ci ibdev_err(edev->efa_dev, "DMA width illegal value: %d\n", width); 100762306a36Sopenharmony_ci return -EINVAL; 100862306a36Sopenharmony_ci } 100962306a36Sopenharmony_ci 101062306a36Sopenharmony_ci edev->dma_addr_bits = width; 101162306a36Sopenharmony_ci 101262306a36Sopenharmony_ci return width; 101362306a36Sopenharmony_ci} 101462306a36Sopenharmony_ci 101562306a36Sopenharmony_cistatic int wait_for_reset_state(struct efa_com_dev *edev, u32 timeout, int on) 101662306a36Sopenharmony_ci{ 101762306a36Sopenharmony_ci u32 val, i; 101862306a36Sopenharmony_ci 101962306a36Sopenharmony_ci for (i = 0; i < timeout; i++) { 102062306a36Sopenharmony_ci val = efa_com_reg_read32(edev, EFA_REGS_DEV_STS_OFF); 102162306a36Sopenharmony_ci 102262306a36Sopenharmony_ci if (EFA_GET(&val, EFA_REGS_DEV_STS_RESET_IN_PROGRESS) == on) 102362306a36Sopenharmony_ci return 0; 102462306a36Sopenharmony_ci 102562306a36Sopenharmony_ci ibdev_dbg(edev->efa_dev, "Reset indication val %d\n", val); 102662306a36Sopenharmony_ci msleep(EFA_POLL_INTERVAL_MS); 102762306a36Sopenharmony_ci } 102862306a36Sopenharmony_ci 102962306a36Sopenharmony_ci return -ETIME; 103062306a36Sopenharmony_ci} 103162306a36Sopenharmony_ci 103262306a36Sopenharmony_ci/** 103362306a36Sopenharmony_ci * efa_com_dev_reset - Perform device FLR to the device. 103462306a36Sopenharmony_ci * @edev: EFA communication layer struct 103562306a36Sopenharmony_ci * @reset_reason: Specify what is the trigger for the reset in case of an error. 103662306a36Sopenharmony_ci * 103762306a36Sopenharmony_ci * @return - 0 on success, negative value on failure. 103862306a36Sopenharmony_ci */ 103962306a36Sopenharmony_ciint efa_com_dev_reset(struct efa_com_dev *edev, 104062306a36Sopenharmony_ci enum efa_regs_reset_reason_types reset_reason) 104162306a36Sopenharmony_ci{ 104262306a36Sopenharmony_ci u32 stat, timeout, cap; 104362306a36Sopenharmony_ci u32 reset_val = 0; 104462306a36Sopenharmony_ci int err; 104562306a36Sopenharmony_ci 104662306a36Sopenharmony_ci stat = efa_com_reg_read32(edev, EFA_REGS_DEV_STS_OFF); 104762306a36Sopenharmony_ci cap = efa_com_reg_read32(edev, EFA_REGS_CAPS_OFF); 104862306a36Sopenharmony_ci 104962306a36Sopenharmony_ci if (!EFA_GET(&stat, EFA_REGS_DEV_STS_READY)) { 105062306a36Sopenharmony_ci ibdev_err(edev->efa_dev, 105162306a36Sopenharmony_ci "Device isn't ready, can't reset device\n"); 105262306a36Sopenharmony_ci return -EINVAL; 105362306a36Sopenharmony_ci } 105462306a36Sopenharmony_ci 105562306a36Sopenharmony_ci timeout = EFA_GET(&cap, EFA_REGS_CAPS_RESET_TIMEOUT); 105662306a36Sopenharmony_ci if (!timeout) { 105762306a36Sopenharmony_ci ibdev_err(edev->efa_dev, "Invalid timeout value\n"); 105862306a36Sopenharmony_ci return -EINVAL; 105962306a36Sopenharmony_ci } 106062306a36Sopenharmony_ci 106162306a36Sopenharmony_ci /* start reset */ 106262306a36Sopenharmony_ci EFA_SET(&reset_val, EFA_REGS_DEV_CTL_DEV_RESET, 1); 106362306a36Sopenharmony_ci EFA_SET(&reset_val, EFA_REGS_DEV_CTL_RESET_REASON, reset_reason); 106462306a36Sopenharmony_ci writel(reset_val, edev->reg_bar + EFA_REGS_DEV_CTL_OFF); 106562306a36Sopenharmony_ci 106662306a36Sopenharmony_ci /* reset clears the mmio readless address, restore it */ 106762306a36Sopenharmony_ci efa_com_mmio_reg_read_resp_addr_init(edev); 106862306a36Sopenharmony_ci 106962306a36Sopenharmony_ci err = wait_for_reset_state(edev, timeout, 1); 107062306a36Sopenharmony_ci if (err) { 107162306a36Sopenharmony_ci ibdev_err(edev->efa_dev, "Reset indication didn't turn on\n"); 107262306a36Sopenharmony_ci return err; 107362306a36Sopenharmony_ci } 107462306a36Sopenharmony_ci 107562306a36Sopenharmony_ci /* reset done */ 107662306a36Sopenharmony_ci writel(0, edev->reg_bar + EFA_REGS_DEV_CTL_OFF); 107762306a36Sopenharmony_ci err = wait_for_reset_state(edev, timeout, 0); 107862306a36Sopenharmony_ci if (err) { 107962306a36Sopenharmony_ci ibdev_err(edev->efa_dev, "Reset indication didn't turn off\n"); 108062306a36Sopenharmony_ci return err; 108162306a36Sopenharmony_ci } 108262306a36Sopenharmony_ci 108362306a36Sopenharmony_ci timeout = EFA_GET(&cap, EFA_REGS_CAPS_ADMIN_CMD_TO); 108462306a36Sopenharmony_ci if (timeout) 108562306a36Sopenharmony_ci /* the resolution of timeout reg is 100ms */ 108662306a36Sopenharmony_ci edev->aq.completion_timeout = timeout * 100000; 108762306a36Sopenharmony_ci else 108862306a36Sopenharmony_ci edev->aq.completion_timeout = ADMIN_CMD_TIMEOUT_US; 108962306a36Sopenharmony_ci 109062306a36Sopenharmony_ci return 0; 109162306a36Sopenharmony_ci} 109262306a36Sopenharmony_ci 109362306a36Sopenharmony_cistatic int efa_com_create_eq(struct efa_com_dev *edev, 109462306a36Sopenharmony_ci struct efa_com_create_eq_params *params, 109562306a36Sopenharmony_ci struct efa_com_create_eq_result *result) 109662306a36Sopenharmony_ci{ 109762306a36Sopenharmony_ci struct efa_com_admin_queue *aq = &edev->aq; 109862306a36Sopenharmony_ci struct efa_admin_create_eq_resp resp = {}; 109962306a36Sopenharmony_ci struct efa_admin_create_eq_cmd cmd = {}; 110062306a36Sopenharmony_ci int err; 110162306a36Sopenharmony_ci 110262306a36Sopenharmony_ci cmd.aq_common_descriptor.opcode = EFA_ADMIN_CREATE_EQ; 110362306a36Sopenharmony_ci EFA_SET(&cmd.caps, EFA_ADMIN_CREATE_EQ_CMD_ENTRY_SIZE_WORDS, 110462306a36Sopenharmony_ci params->entry_size_in_bytes / 4); 110562306a36Sopenharmony_ci cmd.depth = params->depth; 110662306a36Sopenharmony_ci cmd.event_bitmask = params->event_bitmask; 110762306a36Sopenharmony_ci cmd.msix_vec = params->msix_vec; 110862306a36Sopenharmony_ci 110962306a36Sopenharmony_ci efa_com_set_dma_addr(params->dma_addr, &cmd.ba.mem_addr_high, 111062306a36Sopenharmony_ci &cmd.ba.mem_addr_low); 111162306a36Sopenharmony_ci 111262306a36Sopenharmony_ci err = efa_com_cmd_exec(aq, 111362306a36Sopenharmony_ci (struct efa_admin_aq_entry *)&cmd, 111462306a36Sopenharmony_ci sizeof(cmd), 111562306a36Sopenharmony_ci (struct efa_admin_acq_entry *)&resp, 111662306a36Sopenharmony_ci sizeof(resp)); 111762306a36Sopenharmony_ci if (err) { 111862306a36Sopenharmony_ci ibdev_err_ratelimited(edev->efa_dev, 111962306a36Sopenharmony_ci "Failed to create eq[%d]\n", err); 112062306a36Sopenharmony_ci return err; 112162306a36Sopenharmony_ci } 112262306a36Sopenharmony_ci 112362306a36Sopenharmony_ci result->eqn = resp.eqn; 112462306a36Sopenharmony_ci 112562306a36Sopenharmony_ci return 0; 112662306a36Sopenharmony_ci} 112762306a36Sopenharmony_ci 112862306a36Sopenharmony_cistatic void efa_com_destroy_eq(struct efa_com_dev *edev, 112962306a36Sopenharmony_ci struct efa_com_destroy_eq_params *params) 113062306a36Sopenharmony_ci{ 113162306a36Sopenharmony_ci struct efa_com_admin_queue *aq = &edev->aq; 113262306a36Sopenharmony_ci struct efa_admin_destroy_eq_resp resp = {}; 113362306a36Sopenharmony_ci struct efa_admin_destroy_eq_cmd cmd = {}; 113462306a36Sopenharmony_ci int err; 113562306a36Sopenharmony_ci 113662306a36Sopenharmony_ci cmd.aq_common_descriptor.opcode = EFA_ADMIN_DESTROY_EQ; 113762306a36Sopenharmony_ci cmd.eqn = params->eqn; 113862306a36Sopenharmony_ci 113962306a36Sopenharmony_ci err = efa_com_cmd_exec(aq, 114062306a36Sopenharmony_ci (struct efa_admin_aq_entry *)&cmd, 114162306a36Sopenharmony_ci sizeof(cmd), 114262306a36Sopenharmony_ci (struct efa_admin_acq_entry *)&resp, 114362306a36Sopenharmony_ci sizeof(resp)); 114462306a36Sopenharmony_ci if (err) 114562306a36Sopenharmony_ci ibdev_err_ratelimited(edev->efa_dev, 114662306a36Sopenharmony_ci "Failed to destroy EQ-%u [%d]\n", cmd.eqn, 114762306a36Sopenharmony_ci err); 114862306a36Sopenharmony_ci} 114962306a36Sopenharmony_ci 115062306a36Sopenharmony_cistatic void efa_com_arm_eq(struct efa_com_dev *edev, struct efa_com_eq *eeq) 115162306a36Sopenharmony_ci{ 115262306a36Sopenharmony_ci u32 val = 0; 115362306a36Sopenharmony_ci 115462306a36Sopenharmony_ci EFA_SET(&val, EFA_REGS_EQ_DB_EQN, eeq->eqn); 115562306a36Sopenharmony_ci EFA_SET(&val, EFA_REGS_EQ_DB_ARM, 1); 115662306a36Sopenharmony_ci 115762306a36Sopenharmony_ci writel(val, edev->reg_bar + EFA_REGS_EQ_DB_OFF); 115862306a36Sopenharmony_ci} 115962306a36Sopenharmony_ci 116062306a36Sopenharmony_civoid efa_com_eq_comp_intr_handler(struct efa_com_dev *edev, 116162306a36Sopenharmony_ci struct efa_com_eq *eeq) 116262306a36Sopenharmony_ci{ 116362306a36Sopenharmony_ci struct efa_admin_eqe *eqe; 116462306a36Sopenharmony_ci u32 processed = 0; 116562306a36Sopenharmony_ci u8 phase; 116662306a36Sopenharmony_ci u32 ci; 116762306a36Sopenharmony_ci 116862306a36Sopenharmony_ci ci = eeq->cc & (eeq->depth - 1); 116962306a36Sopenharmony_ci phase = eeq->phase; 117062306a36Sopenharmony_ci eqe = &eeq->eqes[ci]; 117162306a36Sopenharmony_ci 117262306a36Sopenharmony_ci /* Go over all the events */ 117362306a36Sopenharmony_ci while ((READ_ONCE(eqe->common) & EFA_ADMIN_EQE_PHASE_MASK) == phase) { 117462306a36Sopenharmony_ci /* 117562306a36Sopenharmony_ci * Do not read the rest of the completion entry before the 117662306a36Sopenharmony_ci * phase bit was validated 117762306a36Sopenharmony_ci */ 117862306a36Sopenharmony_ci dma_rmb(); 117962306a36Sopenharmony_ci 118062306a36Sopenharmony_ci eeq->cb(eeq, eqe); 118162306a36Sopenharmony_ci 118262306a36Sopenharmony_ci /* Get next event entry */ 118362306a36Sopenharmony_ci ci++; 118462306a36Sopenharmony_ci processed++; 118562306a36Sopenharmony_ci 118662306a36Sopenharmony_ci if (ci == eeq->depth) { 118762306a36Sopenharmony_ci ci = 0; 118862306a36Sopenharmony_ci phase = !phase; 118962306a36Sopenharmony_ci } 119062306a36Sopenharmony_ci 119162306a36Sopenharmony_ci eqe = &eeq->eqes[ci]; 119262306a36Sopenharmony_ci } 119362306a36Sopenharmony_ci 119462306a36Sopenharmony_ci eeq->cc += processed; 119562306a36Sopenharmony_ci eeq->phase = phase; 119662306a36Sopenharmony_ci efa_com_arm_eq(eeq->edev, eeq); 119762306a36Sopenharmony_ci} 119862306a36Sopenharmony_ci 119962306a36Sopenharmony_civoid efa_com_eq_destroy(struct efa_com_dev *edev, struct efa_com_eq *eeq) 120062306a36Sopenharmony_ci{ 120162306a36Sopenharmony_ci struct efa_com_destroy_eq_params params = { 120262306a36Sopenharmony_ci .eqn = eeq->eqn, 120362306a36Sopenharmony_ci }; 120462306a36Sopenharmony_ci 120562306a36Sopenharmony_ci efa_com_destroy_eq(edev, ¶ms); 120662306a36Sopenharmony_ci dma_free_coherent(edev->dmadev, eeq->depth * sizeof(*eeq->eqes), 120762306a36Sopenharmony_ci eeq->eqes, eeq->dma_addr); 120862306a36Sopenharmony_ci} 120962306a36Sopenharmony_ci 121062306a36Sopenharmony_ciint efa_com_eq_init(struct efa_com_dev *edev, struct efa_com_eq *eeq, 121162306a36Sopenharmony_ci efa_eqe_handler cb, u16 depth, u8 msix_vec) 121262306a36Sopenharmony_ci{ 121362306a36Sopenharmony_ci struct efa_com_create_eq_params params = {}; 121462306a36Sopenharmony_ci struct efa_com_create_eq_result result = {}; 121562306a36Sopenharmony_ci int err; 121662306a36Sopenharmony_ci 121762306a36Sopenharmony_ci params.depth = depth; 121862306a36Sopenharmony_ci params.entry_size_in_bytes = sizeof(*eeq->eqes); 121962306a36Sopenharmony_ci EFA_SET(¶ms.event_bitmask, 122062306a36Sopenharmony_ci EFA_ADMIN_CREATE_EQ_CMD_COMPLETION_EVENTS, 1); 122162306a36Sopenharmony_ci params.msix_vec = msix_vec; 122262306a36Sopenharmony_ci 122362306a36Sopenharmony_ci eeq->eqes = dma_alloc_coherent(edev->dmadev, 122462306a36Sopenharmony_ci params.depth * sizeof(*eeq->eqes), 122562306a36Sopenharmony_ci ¶ms.dma_addr, GFP_KERNEL); 122662306a36Sopenharmony_ci if (!eeq->eqes) 122762306a36Sopenharmony_ci return -ENOMEM; 122862306a36Sopenharmony_ci 122962306a36Sopenharmony_ci err = efa_com_create_eq(edev, ¶ms, &result); 123062306a36Sopenharmony_ci if (err) 123162306a36Sopenharmony_ci goto err_free_coherent; 123262306a36Sopenharmony_ci 123362306a36Sopenharmony_ci eeq->eqn = result.eqn; 123462306a36Sopenharmony_ci eeq->edev = edev; 123562306a36Sopenharmony_ci eeq->dma_addr = params.dma_addr; 123662306a36Sopenharmony_ci eeq->phase = 1; 123762306a36Sopenharmony_ci eeq->depth = params.depth; 123862306a36Sopenharmony_ci eeq->cb = cb; 123962306a36Sopenharmony_ci efa_com_arm_eq(edev, eeq); 124062306a36Sopenharmony_ci 124162306a36Sopenharmony_ci return 0; 124262306a36Sopenharmony_ci 124362306a36Sopenharmony_cierr_free_coherent: 124462306a36Sopenharmony_ci dma_free_coherent(edev->dmadev, params.depth * sizeof(*eeq->eqes), 124562306a36Sopenharmony_ci eeq->eqes, params.dma_addr); 124662306a36Sopenharmony_ci return err; 124762306a36Sopenharmony_ci} 1248