162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* Copyright(c) 2013 - 2018 Intel Corporation. */ 362306a36Sopenharmony_ci 462306a36Sopenharmony_ci#include "iavf_status.h" 562306a36Sopenharmony_ci#include "iavf_type.h" 662306a36Sopenharmony_ci#include "iavf_register.h" 762306a36Sopenharmony_ci#include "iavf_adminq.h" 862306a36Sopenharmony_ci#include "iavf_prototype.h" 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci/** 1162306a36Sopenharmony_ci * iavf_adminq_init_regs - Initialize AdminQ registers 1262306a36Sopenharmony_ci * @hw: pointer to the hardware structure 1362306a36Sopenharmony_ci * 1462306a36Sopenharmony_ci * This assumes the alloc_asq and alloc_arq functions have already been called 1562306a36Sopenharmony_ci **/ 1662306a36Sopenharmony_cistatic void iavf_adminq_init_regs(struct iavf_hw *hw) 1762306a36Sopenharmony_ci{ 1862306a36Sopenharmony_ci /* set head and tail registers in our local struct */ 1962306a36Sopenharmony_ci hw->aq.asq.tail = IAVF_VF_ATQT1; 2062306a36Sopenharmony_ci hw->aq.asq.head = IAVF_VF_ATQH1; 2162306a36Sopenharmony_ci hw->aq.asq.len = IAVF_VF_ATQLEN1; 2262306a36Sopenharmony_ci hw->aq.asq.bal = IAVF_VF_ATQBAL1; 2362306a36Sopenharmony_ci hw->aq.asq.bah = IAVF_VF_ATQBAH1; 2462306a36Sopenharmony_ci hw->aq.arq.tail = IAVF_VF_ARQT1; 2562306a36Sopenharmony_ci hw->aq.arq.head = IAVF_VF_ARQH1; 2662306a36Sopenharmony_ci hw->aq.arq.len = IAVF_VF_ARQLEN1; 2762306a36Sopenharmony_ci hw->aq.arq.bal = IAVF_VF_ARQBAL1; 2862306a36Sopenharmony_ci hw->aq.arq.bah = IAVF_VF_ARQBAH1; 2962306a36Sopenharmony_ci} 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_ci/** 3262306a36Sopenharmony_ci * iavf_alloc_adminq_asq_ring - Allocate Admin Queue send rings 3362306a36Sopenharmony_ci * @hw: pointer to the hardware structure 3462306a36Sopenharmony_ci **/ 3562306a36Sopenharmony_cistatic enum iavf_status iavf_alloc_adminq_asq_ring(struct iavf_hw *hw) 3662306a36Sopenharmony_ci{ 3762306a36Sopenharmony_ci enum iavf_status ret_code; 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_ci ret_code = iavf_allocate_dma_mem(hw, &hw->aq.asq.desc_buf, 4062306a36Sopenharmony_ci iavf_mem_atq_ring, 4162306a36Sopenharmony_ci (hw->aq.num_asq_entries * 4262306a36Sopenharmony_ci sizeof(struct iavf_aq_desc)), 4362306a36Sopenharmony_ci IAVF_ADMINQ_DESC_ALIGNMENT); 4462306a36Sopenharmony_ci if (ret_code) 4562306a36Sopenharmony_ci return ret_code; 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_ci ret_code = iavf_allocate_virt_mem(hw, &hw->aq.asq.cmd_buf, 4862306a36Sopenharmony_ci (hw->aq.num_asq_entries * 4962306a36Sopenharmony_ci sizeof(struct iavf_asq_cmd_details))); 5062306a36Sopenharmony_ci if (ret_code) { 5162306a36Sopenharmony_ci iavf_free_dma_mem(hw, &hw->aq.asq.desc_buf); 5262306a36Sopenharmony_ci return ret_code; 5362306a36Sopenharmony_ci } 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_ci return ret_code; 5662306a36Sopenharmony_ci} 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_ci/** 5962306a36Sopenharmony_ci * iavf_alloc_adminq_arq_ring - Allocate Admin Queue receive rings 6062306a36Sopenharmony_ci * @hw: pointer to the hardware structure 6162306a36Sopenharmony_ci **/ 6262306a36Sopenharmony_cistatic enum iavf_status iavf_alloc_adminq_arq_ring(struct iavf_hw *hw) 6362306a36Sopenharmony_ci{ 6462306a36Sopenharmony_ci enum iavf_status ret_code; 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_ci ret_code = iavf_allocate_dma_mem(hw, &hw->aq.arq.desc_buf, 6762306a36Sopenharmony_ci iavf_mem_arq_ring, 6862306a36Sopenharmony_ci (hw->aq.num_arq_entries * 6962306a36Sopenharmony_ci sizeof(struct iavf_aq_desc)), 7062306a36Sopenharmony_ci IAVF_ADMINQ_DESC_ALIGNMENT); 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_ci return ret_code; 7362306a36Sopenharmony_ci} 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_ci/** 7662306a36Sopenharmony_ci * iavf_free_adminq_asq - Free Admin Queue send rings 7762306a36Sopenharmony_ci * @hw: pointer to the hardware structure 7862306a36Sopenharmony_ci * 7962306a36Sopenharmony_ci * This assumes the posted send buffers have already been cleaned 8062306a36Sopenharmony_ci * and de-allocated 8162306a36Sopenharmony_ci **/ 8262306a36Sopenharmony_cistatic void iavf_free_adminq_asq(struct iavf_hw *hw) 8362306a36Sopenharmony_ci{ 8462306a36Sopenharmony_ci iavf_free_dma_mem(hw, &hw->aq.asq.desc_buf); 8562306a36Sopenharmony_ci} 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_ci/** 8862306a36Sopenharmony_ci * iavf_free_adminq_arq - Free Admin Queue receive rings 8962306a36Sopenharmony_ci * @hw: pointer to the hardware structure 9062306a36Sopenharmony_ci * 9162306a36Sopenharmony_ci * This assumes the posted receive buffers have already been cleaned 9262306a36Sopenharmony_ci * and de-allocated 9362306a36Sopenharmony_ci **/ 9462306a36Sopenharmony_cistatic void iavf_free_adminq_arq(struct iavf_hw *hw) 9562306a36Sopenharmony_ci{ 9662306a36Sopenharmony_ci iavf_free_dma_mem(hw, &hw->aq.arq.desc_buf); 9762306a36Sopenharmony_ci} 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_ci/** 10062306a36Sopenharmony_ci * iavf_alloc_arq_bufs - Allocate pre-posted buffers for the receive queue 10162306a36Sopenharmony_ci * @hw: pointer to the hardware structure 10262306a36Sopenharmony_ci **/ 10362306a36Sopenharmony_cistatic enum iavf_status iavf_alloc_arq_bufs(struct iavf_hw *hw) 10462306a36Sopenharmony_ci{ 10562306a36Sopenharmony_ci struct iavf_aq_desc *desc; 10662306a36Sopenharmony_ci struct iavf_dma_mem *bi; 10762306a36Sopenharmony_ci enum iavf_status ret_code; 10862306a36Sopenharmony_ci int i; 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_ci /* We'll be allocating the buffer info memory first, then we can 11162306a36Sopenharmony_ci * allocate the mapped buffers for the event processing 11262306a36Sopenharmony_ci */ 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_ci /* buffer_info structures do not need alignment */ 11562306a36Sopenharmony_ci ret_code = iavf_allocate_virt_mem(hw, &hw->aq.arq.dma_head, 11662306a36Sopenharmony_ci (hw->aq.num_arq_entries * 11762306a36Sopenharmony_ci sizeof(struct iavf_dma_mem))); 11862306a36Sopenharmony_ci if (ret_code) 11962306a36Sopenharmony_ci goto alloc_arq_bufs; 12062306a36Sopenharmony_ci hw->aq.arq.r.arq_bi = (struct iavf_dma_mem *)hw->aq.arq.dma_head.va; 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_ci /* allocate the mapped buffers */ 12362306a36Sopenharmony_ci for (i = 0; i < hw->aq.num_arq_entries; i++) { 12462306a36Sopenharmony_ci bi = &hw->aq.arq.r.arq_bi[i]; 12562306a36Sopenharmony_ci ret_code = iavf_allocate_dma_mem(hw, bi, 12662306a36Sopenharmony_ci iavf_mem_arq_buf, 12762306a36Sopenharmony_ci hw->aq.arq_buf_size, 12862306a36Sopenharmony_ci IAVF_ADMINQ_DESC_ALIGNMENT); 12962306a36Sopenharmony_ci if (ret_code) 13062306a36Sopenharmony_ci goto unwind_alloc_arq_bufs; 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_ci /* now configure the descriptors for use */ 13362306a36Sopenharmony_ci desc = IAVF_ADMINQ_DESC(hw->aq.arq, i); 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_ci desc->flags = cpu_to_le16(IAVF_AQ_FLAG_BUF); 13662306a36Sopenharmony_ci if (hw->aq.arq_buf_size > IAVF_AQ_LARGE_BUF) 13762306a36Sopenharmony_ci desc->flags |= cpu_to_le16(IAVF_AQ_FLAG_LB); 13862306a36Sopenharmony_ci desc->opcode = 0; 13962306a36Sopenharmony_ci /* This is in accordance with Admin queue design, there is no 14062306a36Sopenharmony_ci * register for buffer size configuration 14162306a36Sopenharmony_ci */ 14262306a36Sopenharmony_ci desc->datalen = cpu_to_le16((u16)bi->size); 14362306a36Sopenharmony_ci desc->retval = 0; 14462306a36Sopenharmony_ci desc->cookie_high = 0; 14562306a36Sopenharmony_ci desc->cookie_low = 0; 14662306a36Sopenharmony_ci desc->params.external.addr_high = 14762306a36Sopenharmony_ci cpu_to_le32(upper_32_bits(bi->pa)); 14862306a36Sopenharmony_ci desc->params.external.addr_low = 14962306a36Sopenharmony_ci cpu_to_le32(lower_32_bits(bi->pa)); 15062306a36Sopenharmony_ci desc->params.external.param0 = 0; 15162306a36Sopenharmony_ci desc->params.external.param1 = 0; 15262306a36Sopenharmony_ci } 15362306a36Sopenharmony_ci 15462306a36Sopenharmony_cialloc_arq_bufs: 15562306a36Sopenharmony_ci return ret_code; 15662306a36Sopenharmony_ci 15762306a36Sopenharmony_ciunwind_alloc_arq_bufs: 15862306a36Sopenharmony_ci /* don't try to free the one that failed... */ 15962306a36Sopenharmony_ci i--; 16062306a36Sopenharmony_ci for (; i >= 0; i--) 16162306a36Sopenharmony_ci iavf_free_dma_mem(hw, &hw->aq.arq.r.arq_bi[i]); 16262306a36Sopenharmony_ci iavf_free_virt_mem(hw, &hw->aq.arq.dma_head); 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_ci return ret_code; 16562306a36Sopenharmony_ci} 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_ci/** 16862306a36Sopenharmony_ci * iavf_alloc_asq_bufs - Allocate empty buffer structs for the send queue 16962306a36Sopenharmony_ci * @hw: pointer to the hardware structure 17062306a36Sopenharmony_ci **/ 17162306a36Sopenharmony_cistatic enum iavf_status iavf_alloc_asq_bufs(struct iavf_hw *hw) 17262306a36Sopenharmony_ci{ 17362306a36Sopenharmony_ci struct iavf_dma_mem *bi; 17462306a36Sopenharmony_ci enum iavf_status ret_code; 17562306a36Sopenharmony_ci int i; 17662306a36Sopenharmony_ci 17762306a36Sopenharmony_ci /* No mapped memory needed yet, just the buffer info structures */ 17862306a36Sopenharmony_ci ret_code = iavf_allocate_virt_mem(hw, &hw->aq.asq.dma_head, 17962306a36Sopenharmony_ci (hw->aq.num_asq_entries * 18062306a36Sopenharmony_ci sizeof(struct iavf_dma_mem))); 18162306a36Sopenharmony_ci if (ret_code) 18262306a36Sopenharmony_ci goto alloc_asq_bufs; 18362306a36Sopenharmony_ci hw->aq.asq.r.asq_bi = (struct iavf_dma_mem *)hw->aq.asq.dma_head.va; 18462306a36Sopenharmony_ci 18562306a36Sopenharmony_ci /* allocate the mapped buffers */ 18662306a36Sopenharmony_ci for (i = 0; i < hw->aq.num_asq_entries; i++) { 18762306a36Sopenharmony_ci bi = &hw->aq.asq.r.asq_bi[i]; 18862306a36Sopenharmony_ci ret_code = iavf_allocate_dma_mem(hw, bi, 18962306a36Sopenharmony_ci iavf_mem_asq_buf, 19062306a36Sopenharmony_ci hw->aq.asq_buf_size, 19162306a36Sopenharmony_ci IAVF_ADMINQ_DESC_ALIGNMENT); 19262306a36Sopenharmony_ci if (ret_code) 19362306a36Sopenharmony_ci goto unwind_alloc_asq_bufs; 19462306a36Sopenharmony_ci } 19562306a36Sopenharmony_cialloc_asq_bufs: 19662306a36Sopenharmony_ci return ret_code; 19762306a36Sopenharmony_ci 19862306a36Sopenharmony_ciunwind_alloc_asq_bufs: 19962306a36Sopenharmony_ci /* don't try to free the one that failed... */ 20062306a36Sopenharmony_ci i--; 20162306a36Sopenharmony_ci for (; i >= 0; i--) 20262306a36Sopenharmony_ci iavf_free_dma_mem(hw, &hw->aq.asq.r.asq_bi[i]); 20362306a36Sopenharmony_ci iavf_free_virt_mem(hw, &hw->aq.asq.dma_head); 20462306a36Sopenharmony_ci 20562306a36Sopenharmony_ci return ret_code; 20662306a36Sopenharmony_ci} 20762306a36Sopenharmony_ci 20862306a36Sopenharmony_ci/** 20962306a36Sopenharmony_ci * iavf_free_arq_bufs - Free receive queue buffer info elements 21062306a36Sopenharmony_ci * @hw: pointer to the hardware structure 21162306a36Sopenharmony_ci **/ 21262306a36Sopenharmony_cistatic void iavf_free_arq_bufs(struct iavf_hw *hw) 21362306a36Sopenharmony_ci{ 21462306a36Sopenharmony_ci int i; 21562306a36Sopenharmony_ci 21662306a36Sopenharmony_ci /* free descriptors */ 21762306a36Sopenharmony_ci for (i = 0; i < hw->aq.num_arq_entries; i++) 21862306a36Sopenharmony_ci iavf_free_dma_mem(hw, &hw->aq.arq.r.arq_bi[i]); 21962306a36Sopenharmony_ci 22062306a36Sopenharmony_ci /* free the descriptor memory */ 22162306a36Sopenharmony_ci iavf_free_dma_mem(hw, &hw->aq.arq.desc_buf); 22262306a36Sopenharmony_ci 22362306a36Sopenharmony_ci /* free the dma header */ 22462306a36Sopenharmony_ci iavf_free_virt_mem(hw, &hw->aq.arq.dma_head); 22562306a36Sopenharmony_ci} 22662306a36Sopenharmony_ci 22762306a36Sopenharmony_ci/** 22862306a36Sopenharmony_ci * iavf_free_asq_bufs - Free send queue buffer info elements 22962306a36Sopenharmony_ci * @hw: pointer to the hardware structure 23062306a36Sopenharmony_ci **/ 23162306a36Sopenharmony_cistatic void iavf_free_asq_bufs(struct iavf_hw *hw) 23262306a36Sopenharmony_ci{ 23362306a36Sopenharmony_ci int i; 23462306a36Sopenharmony_ci 23562306a36Sopenharmony_ci /* only unmap if the address is non-NULL */ 23662306a36Sopenharmony_ci for (i = 0; i < hw->aq.num_asq_entries; i++) 23762306a36Sopenharmony_ci if (hw->aq.asq.r.asq_bi[i].pa) 23862306a36Sopenharmony_ci iavf_free_dma_mem(hw, &hw->aq.asq.r.asq_bi[i]); 23962306a36Sopenharmony_ci 24062306a36Sopenharmony_ci /* free the buffer info list */ 24162306a36Sopenharmony_ci iavf_free_virt_mem(hw, &hw->aq.asq.cmd_buf); 24262306a36Sopenharmony_ci 24362306a36Sopenharmony_ci /* free the descriptor memory */ 24462306a36Sopenharmony_ci iavf_free_dma_mem(hw, &hw->aq.asq.desc_buf); 24562306a36Sopenharmony_ci 24662306a36Sopenharmony_ci /* free the dma header */ 24762306a36Sopenharmony_ci iavf_free_virt_mem(hw, &hw->aq.asq.dma_head); 24862306a36Sopenharmony_ci} 24962306a36Sopenharmony_ci 25062306a36Sopenharmony_ci/** 25162306a36Sopenharmony_ci * iavf_config_asq_regs - configure ASQ registers 25262306a36Sopenharmony_ci * @hw: pointer to the hardware structure 25362306a36Sopenharmony_ci * 25462306a36Sopenharmony_ci * Configure base address and length registers for the transmit queue 25562306a36Sopenharmony_ci **/ 25662306a36Sopenharmony_cistatic enum iavf_status iavf_config_asq_regs(struct iavf_hw *hw) 25762306a36Sopenharmony_ci{ 25862306a36Sopenharmony_ci enum iavf_status ret_code = 0; 25962306a36Sopenharmony_ci u32 reg = 0; 26062306a36Sopenharmony_ci 26162306a36Sopenharmony_ci /* Clear Head and Tail */ 26262306a36Sopenharmony_ci wr32(hw, hw->aq.asq.head, 0); 26362306a36Sopenharmony_ci wr32(hw, hw->aq.asq.tail, 0); 26462306a36Sopenharmony_ci 26562306a36Sopenharmony_ci /* set starting point */ 26662306a36Sopenharmony_ci wr32(hw, hw->aq.asq.len, (hw->aq.num_asq_entries | 26762306a36Sopenharmony_ci IAVF_VF_ATQLEN1_ATQENABLE_MASK)); 26862306a36Sopenharmony_ci wr32(hw, hw->aq.asq.bal, lower_32_bits(hw->aq.asq.desc_buf.pa)); 26962306a36Sopenharmony_ci wr32(hw, hw->aq.asq.bah, upper_32_bits(hw->aq.asq.desc_buf.pa)); 27062306a36Sopenharmony_ci 27162306a36Sopenharmony_ci /* Check one register to verify that config was applied */ 27262306a36Sopenharmony_ci reg = rd32(hw, hw->aq.asq.bal); 27362306a36Sopenharmony_ci if (reg != lower_32_bits(hw->aq.asq.desc_buf.pa)) 27462306a36Sopenharmony_ci ret_code = IAVF_ERR_ADMIN_QUEUE_ERROR; 27562306a36Sopenharmony_ci 27662306a36Sopenharmony_ci return ret_code; 27762306a36Sopenharmony_ci} 27862306a36Sopenharmony_ci 27962306a36Sopenharmony_ci/** 28062306a36Sopenharmony_ci * iavf_config_arq_regs - ARQ register configuration 28162306a36Sopenharmony_ci * @hw: pointer to the hardware structure 28262306a36Sopenharmony_ci * 28362306a36Sopenharmony_ci * Configure base address and length registers for the receive (event queue) 28462306a36Sopenharmony_ci **/ 28562306a36Sopenharmony_cistatic enum iavf_status iavf_config_arq_regs(struct iavf_hw *hw) 28662306a36Sopenharmony_ci{ 28762306a36Sopenharmony_ci enum iavf_status ret_code = 0; 28862306a36Sopenharmony_ci u32 reg = 0; 28962306a36Sopenharmony_ci 29062306a36Sopenharmony_ci /* Clear Head and Tail */ 29162306a36Sopenharmony_ci wr32(hw, hw->aq.arq.head, 0); 29262306a36Sopenharmony_ci wr32(hw, hw->aq.arq.tail, 0); 29362306a36Sopenharmony_ci 29462306a36Sopenharmony_ci /* set starting point */ 29562306a36Sopenharmony_ci wr32(hw, hw->aq.arq.len, (hw->aq.num_arq_entries | 29662306a36Sopenharmony_ci IAVF_VF_ARQLEN1_ARQENABLE_MASK)); 29762306a36Sopenharmony_ci wr32(hw, hw->aq.arq.bal, lower_32_bits(hw->aq.arq.desc_buf.pa)); 29862306a36Sopenharmony_ci wr32(hw, hw->aq.arq.bah, upper_32_bits(hw->aq.arq.desc_buf.pa)); 29962306a36Sopenharmony_ci 30062306a36Sopenharmony_ci /* Update tail in the HW to post pre-allocated buffers */ 30162306a36Sopenharmony_ci wr32(hw, hw->aq.arq.tail, hw->aq.num_arq_entries - 1); 30262306a36Sopenharmony_ci 30362306a36Sopenharmony_ci /* Check one register to verify that config was applied */ 30462306a36Sopenharmony_ci reg = rd32(hw, hw->aq.arq.bal); 30562306a36Sopenharmony_ci if (reg != lower_32_bits(hw->aq.arq.desc_buf.pa)) 30662306a36Sopenharmony_ci ret_code = IAVF_ERR_ADMIN_QUEUE_ERROR; 30762306a36Sopenharmony_ci 30862306a36Sopenharmony_ci return ret_code; 30962306a36Sopenharmony_ci} 31062306a36Sopenharmony_ci 31162306a36Sopenharmony_ci/** 31262306a36Sopenharmony_ci * iavf_init_asq - main initialization routine for ASQ 31362306a36Sopenharmony_ci * @hw: pointer to the hardware structure 31462306a36Sopenharmony_ci * 31562306a36Sopenharmony_ci * This is the main initialization routine for the Admin Send Queue 31662306a36Sopenharmony_ci * Prior to calling this function, drivers *MUST* set the following fields 31762306a36Sopenharmony_ci * in the hw->aq structure: 31862306a36Sopenharmony_ci * - hw->aq.num_asq_entries 31962306a36Sopenharmony_ci * - hw->aq.arq_buf_size 32062306a36Sopenharmony_ci * 32162306a36Sopenharmony_ci * Do *NOT* hold the lock when calling this as the memory allocation routines 32262306a36Sopenharmony_ci * called are not going to be atomic context safe 32362306a36Sopenharmony_ci **/ 32462306a36Sopenharmony_cistatic enum iavf_status iavf_init_asq(struct iavf_hw *hw) 32562306a36Sopenharmony_ci{ 32662306a36Sopenharmony_ci enum iavf_status ret_code = 0; 32762306a36Sopenharmony_ci int i; 32862306a36Sopenharmony_ci 32962306a36Sopenharmony_ci if (hw->aq.asq.count > 0) { 33062306a36Sopenharmony_ci /* queue already initialized */ 33162306a36Sopenharmony_ci ret_code = IAVF_ERR_NOT_READY; 33262306a36Sopenharmony_ci goto init_adminq_exit; 33362306a36Sopenharmony_ci } 33462306a36Sopenharmony_ci 33562306a36Sopenharmony_ci /* verify input for valid configuration */ 33662306a36Sopenharmony_ci if ((hw->aq.num_asq_entries == 0) || 33762306a36Sopenharmony_ci (hw->aq.asq_buf_size == 0)) { 33862306a36Sopenharmony_ci ret_code = IAVF_ERR_CONFIG; 33962306a36Sopenharmony_ci goto init_adminq_exit; 34062306a36Sopenharmony_ci } 34162306a36Sopenharmony_ci 34262306a36Sopenharmony_ci hw->aq.asq.next_to_use = 0; 34362306a36Sopenharmony_ci hw->aq.asq.next_to_clean = 0; 34462306a36Sopenharmony_ci 34562306a36Sopenharmony_ci /* allocate the ring memory */ 34662306a36Sopenharmony_ci ret_code = iavf_alloc_adminq_asq_ring(hw); 34762306a36Sopenharmony_ci if (ret_code) 34862306a36Sopenharmony_ci goto init_adminq_exit; 34962306a36Sopenharmony_ci 35062306a36Sopenharmony_ci /* allocate buffers in the rings */ 35162306a36Sopenharmony_ci ret_code = iavf_alloc_asq_bufs(hw); 35262306a36Sopenharmony_ci if (ret_code) 35362306a36Sopenharmony_ci goto init_adminq_free_rings; 35462306a36Sopenharmony_ci 35562306a36Sopenharmony_ci /* initialize base registers */ 35662306a36Sopenharmony_ci ret_code = iavf_config_asq_regs(hw); 35762306a36Sopenharmony_ci if (ret_code) 35862306a36Sopenharmony_ci goto init_free_asq_bufs; 35962306a36Sopenharmony_ci 36062306a36Sopenharmony_ci /* success! */ 36162306a36Sopenharmony_ci hw->aq.asq.count = hw->aq.num_asq_entries; 36262306a36Sopenharmony_ci goto init_adminq_exit; 36362306a36Sopenharmony_ci 36462306a36Sopenharmony_ciinit_free_asq_bufs: 36562306a36Sopenharmony_ci for (i = 0; i < hw->aq.num_asq_entries; i++) 36662306a36Sopenharmony_ci iavf_free_dma_mem(hw, &hw->aq.asq.r.asq_bi[i]); 36762306a36Sopenharmony_ci iavf_free_virt_mem(hw, &hw->aq.asq.dma_head); 36862306a36Sopenharmony_ci 36962306a36Sopenharmony_ciinit_adminq_free_rings: 37062306a36Sopenharmony_ci iavf_free_adminq_asq(hw); 37162306a36Sopenharmony_ci 37262306a36Sopenharmony_ciinit_adminq_exit: 37362306a36Sopenharmony_ci return ret_code; 37462306a36Sopenharmony_ci} 37562306a36Sopenharmony_ci 37662306a36Sopenharmony_ci/** 37762306a36Sopenharmony_ci * iavf_init_arq - initialize ARQ 37862306a36Sopenharmony_ci * @hw: pointer to the hardware structure 37962306a36Sopenharmony_ci * 38062306a36Sopenharmony_ci * The main initialization routine for the Admin Receive (Event) Queue. 38162306a36Sopenharmony_ci * Prior to calling this function, drivers *MUST* set the following fields 38262306a36Sopenharmony_ci * in the hw->aq structure: 38362306a36Sopenharmony_ci * - hw->aq.num_asq_entries 38462306a36Sopenharmony_ci * - hw->aq.arq_buf_size 38562306a36Sopenharmony_ci * 38662306a36Sopenharmony_ci * Do *NOT* hold the lock when calling this as the memory allocation routines 38762306a36Sopenharmony_ci * called are not going to be atomic context safe 38862306a36Sopenharmony_ci **/ 38962306a36Sopenharmony_cistatic enum iavf_status iavf_init_arq(struct iavf_hw *hw) 39062306a36Sopenharmony_ci{ 39162306a36Sopenharmony_ci enum iavf_status ret_code = 0; 39262306a36Sopenharmony_ci int i; 39362306a36Sopenharmony_ci 39462306a36Sopenharmony_ci if (hw->aq.arq.count > 0) { 39562306a36Sopenharmony_ci /* queue already initialized */ 39662306a36Sopenharmony_ci ret_code = IAVF_ERR_NOT_READY; 39762306a36Sopenharmony_ci goto init_adminq_exit; 39862306a36Sopenharmony_ci } 39962306a36Sopenharmony_ci 40062306a36Sopenharmony_ci /* verify input for valid configuration */ 40162306a36Sopenharmony_ci if ((hw->aq.num_arq_entries == 0) || 40262306a36Sopenharmony_ci (hw->aq.arq_buf_size == 0)) { 40362306a36Sopenharmony_ci ret_code = IAVF_ERR_CONFIG; 40462306a36Sopenharmony_ci goto init_adminq_exit; 40562306a36Sopenharmony_ci } 40662306a36Sopenharmony_ci 40762306a36Sopenharmony_ci hw->aq.arq.next_to_use = 0; 40862306a36Sopenharmony_ci hw->aq.arq.next_to_clean = 0; 40962306a36Sopenharmony_ci 41062306a36Sopenharmony_ci /* allocate the ring memory */ 41162306a36Sopenharmony_ci ret_code = iavf_alloc_adminq_arq_ring(hw); 41262306a36Sopenharmony_ci if (ret_code) 41362306a36Sopenharmony_ci goto init_adminq_exit; 41462306a36Sopenharmony_ci 41562306a36Sopenharmony_ci /* allocate buffers in the rings */ 41662306a36Sopenharmony_ci ret_code = iavf_alloc_arq_bufs(hw); 41762306a36Sopenharmony_ci if (ret_code) 41862306a36Sopenharmony_ci goto init_adminq_free_rings; 41962306a36Sopenharmony_ci 42062306a36Sopenharmony_ci /* initialize base registers */ 42162306a36Sopenharmony_ci ret_code = iavf_config_arq_regs(hw); 42262306a36Sopenharmony_ci if (ret_code) 42362306a36Sopenharmony_ci goto init_free_arq_bufs; 42462306a36Sopenharmony_ci 42562306a36Sopenharmony_ci /* success! */ 42662306a36Sopenharmony_ci hw->aq.arq.count = hw->aq.num_arq_entries; 42762306a36Sopenharmony_ci goto init_adminq_exit; 42862306a36Sopenharmony_ci 42962306a36Sopenharmony_ciinit_free_arq_bufs: 43062306a36Sopenharmony_ci for (i = 0; i < hw->aq.num_arq_entries; i++) 43162306a36Sopenharmony_ci iavf_free_dma_mem(hw, &hw->aq.arq.r.arq_bi[i]); 43262306a36Sopenharmony_ci iavf_free_virt_mem(hw, &hw->aq.arq.dma_head); 43362306a36Sopenharmony_ciinit_adminq_free_rings: 43462306a36Sopenharmony_ci iavf_free_adminq_arq(hw); 43562306a36Sopenharmony_ci 43662306a36Sopenharmony_ciinit_adminq_exit: 43762306a36Sopenharmony_ci return ret_code; 43862306a36Sopenharmony_ci} 43962306a36Sopenharmony_ci 44062306a36Sopenharmony_ci/** 44162306a36Sopenharmony_ci * iavf_shutdown_asq - shutdown the ASQ 44262306a36Sopenharmony_ci * @hw: pointer to the hardware structure 44362306a36Sopenharmony_ci * 44462306a36Sopenharmony_ci * The main shutdown routine for the Admin Send Queue 44562306a36Sopenharmony_ci **/ 44662306a36Sopenharmony_cistatic enum iavf_status iavf_shutdown_asq(struct iavf_hw *hw) 44762306a36Sopenharmony_ci{ 44862306a36Sopenharmony_ci enum iavf_status ret_code = 0; 44962306a36Sopenharmony_ci 45062306a36Sopenharmony_ci mutex_lock(&hw->aq.asq_mutex); 45162306a36Sopenharmony_ci 45262306a36Sopenharmony_ci if (hw->aq.asq.count == 0) { 45362306a36Sopenharmony_ci ret_code = IAVF_ERR_NOT_READY; 45462306a36Sopenharmony_ci goto shutdown_asq_out; 45562306a36Sopenharmony_ci } 45662306a36Sopenharmony_ci 45762306a36Sopenharmony_ci /* Stop firmware AdminQ processing */ 45862306a36Sopenharmony_ci wr32(hw, hw->aq.asq.head, 0); 45962306a36Sopenharmony_ci wr32(hw, hw->aq.asq.tail, 0); 46062306a36Sopenharmony_ci wr32(hw, hw->aq.asq.len, 0); 46162306a36Sopenharmony_ci wr32(hw, hw->aq.asq.bal, 0); 46262306a36Sopenharmony_ci wr32(hw, hw->aq.asq.bah, 0); 46362306a36Sopenharmony_ci 46462306a36Sopenharmony_ci hw->aq.asq.count = 0; /* to indicate uninitialized queue */ 46562306a36Sopenharmony_ci 46662306a36Sopenharmony_ci /* free ring buffers */ 46762306a36Sopenharmony_ci iavf_free_asq_bufs(hw); 46862306a36Sopenharmony_ci 46962306a36Sopenharmony_cishutdown_asq_out: 47062306a36Sopenharmony_ci mutex_unlock(&hw->aq.asq_mutex); 47162306a36Sopenharmony_ci return ret_code; 47262306a36Sopenharmony_ci} 47362306a36Sopenharmony_ci 47462306a36Sopenharmony_ci/** 47562306a36Sopenharmony_ci * iavf_shutdown_arq - shutdown ARQ 47662306a36Sopenharmony_ci * @hw: pointer to the hardware structure 47762306a36Sopenharmony_ci * 47862306a36Sopenharmony_ci * The main shutdown routine for the Admin Receive Queue 47962306a36Sopenharmony_ci **/ 48062306a36Sopenharmony_cistatic enum iavf_status iavf_shutdown_arq(struct iavf_hw *hw) 48162306a36Sopenharmony_ci{ 48262306a36Sopenharmony_ci enum iavf_status ret_code = 0; 48362306a36Sopenharmony_ci 48462306a36Sopenharmony_ci mutex_lock(&hw->aq.arq_mutex); 48562306a36Sopenharmony_ci 48662306a36Sopenharmony_ci if (hw->aq.arq.count == 0) { 48762306a36Sopenharmony_ci ret_code = IAVF_ERR_NOT_READY; 48862306a36Sopenharmony_ci goto shutdown_arq_out; 48962306a36Sopenharmony_ci } 49062306a36Sopenharmony_ci 49162306a36Sopenharmony_ci /* Stop firmware AdminQ processing */ 49262306a36Sopenharmony_ci wr32(hw, hw->aq.arq.head, 0); 49362306a36Sopenharmony_ci wr32(hw, hw->aq.arq.tail, 0); 49462306a36Sopenharmony_ci wr32(hw, hw->aq.arq.len, 0); 49562306a36Sopenharmony_ci wr32(hw, hw->aq.arq.bal, 0); 49662306a36Sopenharmony_ci wr32(hw, hw->aq.arq.bah, 0); 49762306a36Sopenharmony_ci 49862306a36Sopenharmony_ci hw->aq.arq.count = 0; /* to indicate uninitialized queue */ 49962306a36Sopenharmony_ci 50062306a36Sopenharmony_ci /* free ring buffers */ 50162306a36Sopenharmony_ci iavf_free_arq_bufs(hw); 50262306a36Sopenharmony_ci 50362306a36Sopenharmony_cishutdown_arq_out: 50462306a36Sopenharmony_ci mutex_unlock(&hw->aq.arq_mutex); 50562306a36Sopenharmony_ci return ret_code; 50662306a36Sopenharmony_ci} 50762306a36Sopenharmony_ci 50862306a36Sopenharmony_ci/** 50962306a36Sopenharmony_ci * iavf_init_adminq - main initialization routine for Admin Queue 51062306a36Sopenharmony_ci * @hw: pointer to the hardware structure 51162306a36Sopenharmony_ci * 51262306a36Sopenharmony_ci * Prior to calling this function, drivers *MUST* set the following fields 51362306a36Sopenharmony_ci * in the hw->aq structure: 51462306a36Sopenharmony_ci * - hw->aq.num_asq_entries 51562306a36Sopenharmony_ci * - hw->aq.num_arq_entries 51662306a36Sopenharmony_ci * - hw->aq.arq_buf_size 51762306a36Sopenharmony_ci * - hw->aq.asq_buf_size 51862306a36Sopenharmony_ci **/ 51962306a36Sopenharmony_cienum iavf_status iavf_init_adminq(struct iavf_hw *hw) 52062306a36Sopenharmony_ci{ 52162306a36Sopenharmony_ci enum iavf_status ret_code; 52262306a36Sopenharmony_ci 52362306a36Sopenharmony_ci /* verify input for valid configuration */ 52462306a36Sopenharmony_ci if ((hw->aq.num_arq_entries == 0) || 52562306a36Sopenharmony_ci (hw->aq.num_asq_entries == 0) || 52662306a36Sopenharmony_ci (hw->aq.arq_buf_size == 0) || 52762306a36Sopenharmony_ci (hw->aq.asq_buf_size == 0)) { 52862306a36Sopenharmony_ci ret_code = IAVF_ERR_CONFIG; 52962306a36Sopenharmony_ci goto init_adminq_exit; 53062306a36Sopenharmony_ci } 53162306a36Sopenharmony_ci 53262306a36Sopenharmony_ci /* Set up register offsets */ 53362306a36Sopenharmony_ci iavf_adminq_init_regs(hw); 53462306a36Sopenharmony_ci 53562306a36Sopenharmony_ci /* setup ASQ command write back timeout */ 53662306a36Sopenharmony_ci hw->aq.asq_cmd_timeout = IAVF_ASQ_CMD_TIMEOUT; 53762306a36Sopenharmony_ci 53862306a36Sopenharmony_ci /* allocate the ASQ */ 53962306a36Sopenharmony_ci ret_code = iavf_init_asq(hw); 54062306a36Sopenharmony_ci if (ret_code) 54162306a36Sopenharmony_ci goto init_adminq_destroy_locks; 54262306a36Sopenharmony_ci 54362306a36Sopenharmony_ci /* allocate the ARQ */ 54462306a36Sopenharmony_ci ret_code = iavf_init_arq(hw); 54562306a36Sopenharmony_ci if (ret_code) 54662306a36Sopenharmony_ci goto init_adminq_free_asq; 54762306a36Sopenharmony_ci 54862306a36Sopenharmony_ci /* success! */ 54962306a36Sopenharmony_ci goto init_adminq_exit; 55062306a36Sopenharmony_ci 55162306a36Sopenharmony_ciinit_adminq_free_asq: 55262306a36Sopenharmony_ci iavf_shutdown_asq(hw); 55362306a36Sopenharmony_ciinit_adminq_destroy_locks: 55462306a36Sopenharmony_ci 55562306a36Sopenharmony_ciinit_adminq_exit: 55662306a36Sopenharmony_ci return ret_code; 55762306a36Sopenharmony_ci} 55862306a36Sopenharmony_ci 55962306a36Sopenharmony_ci/** 56062306a36Sopenharmony_ci * iavf_shutdown_adminq - shutdown routine for the Admin Queue 56162306a36Sopenharmony_ci * @hw: pointer to the hardware structure 56262306a36Sopenharmony_ci **/ 56362306a36Sopenharmony_cienum iavf_status iavf_shutdown_adminq(struct iavf_hw *hw) 56462306a36Sopenharmony_ci{ 56562306a36Sopenharmony_ci if (iavf_check_asq_alive(hw)) 56662306a36Sopenharmony_ci iavf_aq_queue_shutdown(hw, true); 56762306a36Sopenharmony_ci 56862306a36Sopenharmony_ci iavf_shutdown_asq(hw); 56962306a36Sopenharmony_ci iavf_shutdown_arq(hw); 57062306a36Sopenharmony_ci 57162306a36Sopenharmony_ci return 0; 57262306a36Sopenharmony_ci} 57362306a36Sopenharmony_ci 57462306a36Sopenharmony_ci/** 57562306a36Sopenharmony_ci * iavf_clean_asq - cleans Admin send queue 57662306a36Sopenharmony_ci * @hw: pointer to the hardware structure 57762306a36Sopenharmony_ci * 57862306a36Sopenharmony_ci * returns the number of free desc 57962306a36Sopenharmony_ci **/ 58062306a36Sopenharmony_cistatic u16 iavf_clean_asq(struct iavf_hw *hw) 58162306a36Sopenharmony_ci{ 58262306a36Sopenharmony_ci struct iavf_adminq_ring *asq = &hw->aq.asq; 58362306a36Sopenharmony_ci struct iavf_asq_cmd_details *details; 58462306a36Sopenharmony_ci u16 ntc = asq->next_to_clean; 58562306a36Sopenharmony_ci struct iavf_aq_desc desc_cb; 58662306a36Sopenharmony_ci struct iavf_aq_desc *desc; 58762306a36Sopenharmony_ci 58862306a36Sopenharmony_ci desc = IAVF_ADMINQ_DESC(*asq, ntc); 58962306a36Sopenharmony_ci details = IAVF_ADMINQ_DETAILS(*asq, ntc); 59062306a36Sopenharmony_ci while (rd32(hw, hw->aq.asq.head) != ntc) { 59162306a36Sopenharmony_ci iavf_debug(hw, IAVF_DEBUG_AQ_MESSAGE, 59262306a36Sopenharmony_ci "ntc %d head %d.\n", ntc, rd32(hw, hw->aq.asq.head)); 59362306a36Sopenharmony_ci 59462306a36Sopenharmony_ci if (details->callback) { 59562306a36Sopenharmony_ci IAVF_ADMINQ_CALLBACK cb_func = 59662306a36Sopenharmony_ci (IAVF_ADMINQ_CALLBACK)details->callback; 59762306a36Sopenharmony_ci desc_cb = *desc; 59862306a36Sopenharmony_ci cb_func(hw, &desc_cb); 59962306a36Sopenharmony_ci } 60062306a36Sopenharmony_ci memset((void *)desc, 0, sizeof(struct iavf_aq_desc)); 60162306a36Sopenharmony_ci memset((void *)details, 0, 60262306a36Sopenharmony_ci sizeof(struct iavf_asq_cmd_details)); 60362306a36Sopenharmony_ci ntc++; 60462306a36Sopenharmony_ci if (ntc == asq->count) 60562306a36Sopenharmony_ci ntc = 0; 60662306a36Sopenharmony_ci desc = IAVF_ADMINQ_DESC(*asq, ntc); 60762306a36Sopenharmony_ci details = IAVF_ADMINQ_DETAILS(*asq, ntc); 60862306a36Sopenharmony_ci } 60962306a36Sopenharmony_ci 61062306a36Sopenharmony_ci asq->next_to_clean = ntc; 61162306a36Sopenharmony_ci 61262306a36Sopenharmony_ci return IAVF_DESC_UNUSED(asq); 61362306a36Sopenharmony_ci} 61462306a36Sopenharmony_ci 61562306a36Sopenharmony_ci/** 61662306a36Sopenharmony_ci * iavf_asq_done - check if FW has processed the Admin Send Queue 61762306a36Sopenharmony_ci * @hw: pointer to the hw struct 61862306a36Sopenharmony_ci * 61962306a36Sopenharmony_ci * Returns true if the firmware has processed all descriptors on the 62062306a36Sopenharmony_ci * admin send queue. Returns false if there are still requests pending. 62162306a36Sopenharmony_ci **/ 62262306a36Sopenharmony_cibool iavf_asq_done(struct iavf_hw *hw) 62362306a36Sopenharmony_ci{ 62462306a36Sopenharmony_ci /* AQ designers suggest use of head for better 62562306a36Sopenharmony_ci * timing reliability than DD bit 62662306a36Sopenharmony_ci */ 62762306a36Sopenharmony_ci return rd32(hw, hw->aq.asq.head) == hw->aq.asq.next_to_use; 62862306a36Sopenharmony_ci} 62962306a36Sopenharmony_ci 63062306a36Sopenharmony_ci/** 63162306a36Sopenharmony_ci * iavf_asq_send_command - send command to Admin Queue 63262306a36Sopenharmony_ci * @hw: pointer to the hw struct 63362306a36Sopenharmony_ci * @desc: prefilled descriptor describing the command (non DMA mem) 63462306a36Sopenharmony_ci * @buff: buffer to use for indirect commands 63562306a36Sopenharmony_ci * @buff_size: size of buffer for indirect commands 63662306a36Sopenharmony_ci * @cmd_details: pointer to command details structure 63762306a36Sopenharmony_ci * 63862306a36Sopenharmony_ci * This is the main send command driver routine for the Admin Queue send 63962306a36Sopenharmony_ci * queue. It runs the queue, cleans the queue, etc 64062306a36Sopenharmony_ci **/ 64162306a36Sopenharmony_cienum iavf_status iavf_asq_send_command(struct iavf_hw *hw, 64262306a36Sopenharmony_ci struct iavf_aq_desc *desc, 64362306a36Sopenharmony_ci void *buff, /* can be NULL */ 64462306a36Sopenharmony_ci u16 buff_size, 64562306a36Sopenharmony_ci struct iavf_asq_cmd_details *cmd_details) 64662306a36Sopenharmony_ci{ 64762306a36Sopenharmony_ci struct iavf_dma_mem *dma_buff = NULL; 64862306a36Sopenharmony_ci struct iavf_asq_cmd_details *details; 64962306a36Sopenharmony_ci struct iavf_aq_desc *desc_on_ring; 65062306a36Sopenharmony_ci bool cmd_completed = false; 65162306a36Sopenharmony_ci enum iavf_status status = 0; 65262306a36Sopenharmony_ci u16 retval = 0; 65362306a36Sopenharmony_ci u32 val = 0; 65462306a36Sopenharmony_ci 65562306a36Sopenharmony_ci mutex_lock(&hw->aq.asq_mutex); 65662306a36Sopenharmony_ci 65762306a36Sopenharmony_ci if (hw->aq.asq.count == 0) { 65862306a36Sopenharmony_ci iavf_debug(hw, IAVF_DEBUG_AQ_MESSAGE, 65962306a36Sopenharmony_ci "AQTX: Admin queue not initialized.\n"); 66062306a36Sopenharmony_ci status = IAVF_ERR_QUEUE_EMPTY; 66162306a36Sopenharmony_ci goto asq_send_command_error; 66262306a36Sopenharmony_ci } 66362306a36Sopenharmony_ci 66462306a36Sopenharmony_ci hw->aq.asq_last_status = IAVF_AQ_RC_OK; 66562306a36Sopenharmony_ci 66662306a36Sopenharmony_ci val = rd32(hw, hw->aq.asq.head); 66762306a36Sopenharmony_ci if (val >= hw->aq.num_asq_entries) { 66862306a36Sopenharmony_ci iavf_debug(hw, IAVF_DEBUG_AQ_MESSAGE, 66962306a36Sopenharmony_ci "AQTX: head overrun at %d\n", val); 67062306a36Sopenharmony_ci status = IAVF_ERR_QUEUE_EMPTY; 67162306a36Sopenharmony_ci goto asq_send_command_error; 67262306a36Sopenharmony_ci } 67362306a36Sopenharmony_ci 67462306a36Sopenharmony_ci details = IAVF_ADMINQ_DETAILS(hw->aq.asq, hw->aq.asq.next_to_use); 67562306a36Sopenharmony_ci if (cmd_details) { 67662306a36Sopenharmony_ci *details = *cmd_details; 67762306a36Sopenharmony_ci 67862306a36Sopenharmony_ci /* If the cmd_details are defined copy the cookie. The 67962306a36Sopenharmony_ci * cpu_to_le32 is not needed here because the data is ignored 68062306a36Sopenharmony_ci * by the FW, only used by the driver 68162306a36Sopenharmony_ci */ 68262306a36Sopenharmony_ci if (details->cookie) { 68362306a36Sopenharmony_ci desc->cookie_high = 68462306a36Sopenharmony_ci cpu_to_le32(upper_32_bits(details->cookie)); 68562306a36Sopenharmony_ci desc->cookie_low = 68662306a36Sopenharmony_ci cpu_to_le32(lower_32_bits(details->cookie)); 68762306a36Sopenharmony_ci } 68862306a36Sopenharmony_ci } else { 68962306a36Sopenharmony_ci memset(details, 0, sizeof(struct iavf_asq_cmd_details)); 69062306a36Sopenharmony_ci } 69162306a36Sopenharmony_ci 69262306a36Sopenharmony_ci /* clear requested flags and then set additional flags if defined */ 69362306a36Sopenharmony_ci desc->flags &= ~cpu_to_le16(details->flags_dis); 69462306a36Sopenharmony_ci desc->flags |= cpu_to_le16(details->flags_ena); 69562306a36Sopenharmony_ci 69662306a36Sopenharmony_ci if (buff_size > hw->aq.asq_buf_size) { 69762306a36Sopenharmony_ci iavf_debug(hw, 69862306a36Sopenharmony_ci IAVF_DEBUG_AQ_MESSAGE, 69962306a36Sopenharmony_ci "AQTX: Invalid buffer size: %d.\n", 70062306a36Sopenharmony_ci buff_size); 70162306a36Sopenharmony_ci status = IAVF_ERR_INVALID_SIZE; 70262306a36Sopenharmony_ci goto asq_send_command_error; 70362306a36Sopenharmony_ci } 70462306a36Sopenharmony_ci 70562306a36Sopenharmony_ci if (details->postpone && !details->async) { 70662306a36Sopenharmony_ci iavf_debug(hw, 70762306a36Sopenharmony_ci IAVF_DEBUG_AQ_MESSAGE, 70862306a36Sopenharmony_ci "AQTX: Async flag not set along with postpone flag"); 70962306a36Sopenharmony_ci status = IAVF_ERR_PARAM; 71062306a36Sopenharmony_ci goto asq_send_command_error; 71162306a36Sopenharmony_ci } 71262306a36Sopenharmony_ci 71362306a36Sopenharmony_ci /* call clean and check queue available function to reclaim the 71462306a36Sopenharmony_ci * descriptors that were processed by FW, the function returns the 71562306a36Sopenharmony_ci * number of desc available 71662306a36Sopenharmony_ci */ 71762306a36Sopenharmony_ci /* the clean function called here could be called in a separate thread 71862306a36Sopenharmony_ci * in case of asynchronous completions 71962306a36Sopenharmony_ci */ 72062306a36Sopenharmony_ci if (iavf_clean_asq(hw) == 0) { 72162306a36Sopenharmony_ci iavf_debug(hw, 72262306a36Sopenharmony_ci IAVF_DEBUG_AQ_MESSAGE, 72362306a36Sopenharmony_ci "AQTX: Error queue is full.\n"); 72462306a36Sopenharmony_ci status = IAVF_ERR_ADMIN_QUEUE_FULL; 72562306a36Sopenharmony_ci goto asq_send_command_error; 72662306a36Sopenharmony_ci } 72762306a36Sopenharmony_ci 72862306a36Sopenharmony_ci /* initialize the temp desc pointer with the right desc */ 72962306a36Sopenharmony_ci desc_on_ring = IAVF_ADMINQ_DESC(hw->aq.asq, hw->aq.asq.next_to_use); 73062306a36Sopenharmony_ci 73162306a36Sopenharmony_ci /* if the desc is available copy the temp desc to the right place */ 73262306a36Sopenharmony_ci *desc_on_ring = *desc; 73362306a36Sopenharmony_ci 73462306a36Sopenharmony_ci /* if buff is not NULL assume indirect command */ 73562306a36Sopenharmony_ci if (buff) { 73662306a36Sopenharmony_ci dma_buff = &hw->aq.asq.r.asq_bi[hw->aq.asq.next_to_use]; 73762306a36Sopenharmony_ci /* copy the user buff into the respective DMA buff */ 73862306a36Sopenharmony_ci memcpy(dma_buff->va, buff, buff_size); 73962306a36Sopenharmony_ci desc_on_ring->datalen = cpu_to_le16(buff_size); 74062306a36Sopenharmony_ci 74162306a36Sopenharmony_ci /* Update the address values in the desc with the pa value 74262306a36Sopenharmony_ci * for respective buffer 74362306a36Sopenharmony_ci */ 74462306a36Sopenharmony_ci desc_on_ring->params.external.addr_high = 74562306a36Sopenharmony_ci cpu_to_le32(upper_32_bits(dma_buff->pa)); 74662306a36Sopenharmony_ci desc_on_ring->params.external.addr_low = 74762306a36Sopenharmony_ci cpu_to_le32(lower_32_bits(dma_buff->pa)); 74862306a36Sopenharmony_ci } 74962306a36Sopenharmony_ci 75062306a36Sopenharmony_ci /* bump the tail */ 75162306a36Sopenharmony_ci iavf_debug(hw, IAVF_DEBUG_AQ_MESSAGE, "AQTX: desc and buffer:\n"); 75262306a36Sopenharmony_ci iavf_debug_aq(hw, IAVF_DEBUG_AQ_COMMAND, (void *)desc_on_ring, 75362306a36Sopenharmony_ci buff, buff_size); 75462306a36Sopenharmony_ci (hw->aq.asq.next_to_use)++; 75562306a36Sopenharmony_ci if (hw->aq.asq.next_to_use == hw->aq.asq.count) 75662306a36Sopenharmony_ci hw->aq.asq.next_to_use = 0; 75762306a36Sopenharmony_ci if (!details->postpone) 75862306a36Sopenharmony_ci wr32(hw, hw->aq.asq.tail, hw->aq.asq.next_to_use); 75962306a36Sopenharmony_ci 76062306a36Sopenharmony_ci /* if cmd_details are not defined or async flag is not set, 76162306a36Sopenharmony_ci * we need to wait for desc write back 76262306a36Sopenharmony_ci */ 76362306a36Sopenharmony_ci if (!details->async && !details->postpone) { 76462306a36Sopenharmony_ci u32 total_delay = 0; 76562306a36Sopenharmony_ci 76662306a36Sopenharmony_ci do { 76762306a36Sopenharmony_ci /* AQ designers suggest use of head for better 76862306a36Sopenharmony_ci * timing reliability than DD bit 76962306a36Sopenharmony_ci */ 77062306a36Sopenharmony_ci if (iavf_asq_done(hw)) 77162306a36Sopenharmony_ci break; 77262306a36Sopenharmony_ci udelay(50); 77362306a36Sopenharmony_ci total_delay += 50; 77462306a36Sopenharmony_ci } while (total_delay < hw->aq.asq_cmd_timeout); 77562306a36Sopenharmony_ci } 77662306a36Sopenharmony_ci 77762306a36Sopenharmony_ci /* if ready, copy the desc back to temp */ 77862306a36Sopenharmony_ci if (iavf_asq_done(hw)) { 77962306a36Sopenharmony_ci *desc = *desc_on_ring; 78062306a36Sopenharmony_ci if (buff) 78162306a36Sopenharmony_ci memcpy(buff, dma_buff->va, buff_size); 78262306a36Sopenharmony_ci retval = le16_to_cpu(desc->retval); 78362306a36Sopenharmony_ci if (retval != 0) { 78462306a36Sopenharmony_ci iavf_debug(hw, 78562306a36Sopenharmony_ci IAVF_DEBUG_AQ_MESSAGE, 78662306a36Sopenharmony_ci "AQTX: Command completed with error 0x%X.\n", 78762306a36Sopenharmony_ci retval); 78862306a36Sopenharmony_ci 78962306a36Sopenharmony_ci /* strip off FW internal code */ 79062306a36Sopenharmony_ci retval &= 0xff; 79162306a36Sopenharmony_ci } 79262306a36Sopenharmony_ci cmd_completed = true; 79362306a36Sopenharmony_ci if ((enum iavf_admin_queue_err)retval == IAVF_AQ_RC_OK) 79462306a36Sopenharmony_ci status = 0; 79562306a36Sopenharmony_ci else if ((enum iavf_admin_queue_err)retval == IAVF_AQ_RC_EBUSY) 79662306a36Sopenharmony_ci status = IAVF_ERR_NOT_READY; 79762306a36Sopenharmony_ci else 79862306a36Sopenharmony_ci status = IAVF_ERR_ADMIN_QUEUE_ERROR; 79962306a36Sopenharmony_ci hw->aq.asq_last_status = (enum iavf_admin_queue_err)retval; 80062306a36Sopenharmony_ci } 80162306a36Sopenharmony_ci 80262306a36Sopenharmony_ci iavf_debug(hw, IAVF_DEBUG_AQ_MESSAGE, 80362306a36Sopenharmony_ci "AQTX: desc and buffer writeback:\n"); 80462306a36Sopenharmony_ci iavf_debug_aq(hw, IAVF_DEBUG_AQ_COMMAND, (void *)desc, buff, buff_size); 80562306a36Sopenharmony_ci 80662306a36Sopenharmony_ci /* save writeback aq if requested */ 80762306a36Sopenharmony_ci if (details->wb_desc) 80862306a36Sopenharmony_ci *details->wb_desc = *desc_on_ring; 80962306a36Sopenharmony_ci 81062306a36Sopenharmony_ci /* update the error if time out occurred */ 81162306a36Sopenharmony_ci if ((!cmd_completed) && 81262306a36Sopenharmony_ci (!details->async && !details->postpone)) { 81362306a36Sopenharmony_ci if (rd32(hw, hw->aq.asq.len) & IAVF_VF_ATQLEN1_ATQCRIT_MASK) { 81462306a36Sopenharmony_ci iavf_debug(hw, IAVF_DEBUG_AQ_MESSAGE, 81562306a36Sopenharmony_ci "AQTX: AQ Critical error.\n"); 81662306a36Sopenharmony_ci status = IAVF_ERR_ADMIN_QUEUE_CRITICAL_ERROR; 81762306a36Sopenharmony_ci } else { 81862306a36Sopenharmony_ci iavf_debug(hw, IAVF_DEBUG_AQ_MESSAGE, 81962306a36Sopenharmony_ci "AQTX: Writeback timeout.\n"); 82062306a36Sopenharmony_ci status = IAVF_ERR_ADMIN_QUEUE_TIMEOUT; 82162306a36Sopenharmony_ci } 82262306a36Sopenharmony_ci } 82362306a36Sopenharmony_ci 82462306a36Sopenharmony_ciasq_send_command_error: 82562306a36Sopenharmony_ci mutex_unlock(&hw->aq.asq_mutex); 82662306a36Sopenharmony_ci return status; 82762306a36Sopenharmony_ci} 82862306a36Sopenharmony_ci 82962306a36Sopenharmony_ci/** 83062306a36Sopenharmony_ci * iavf_fill_default_direct_cmd_desc - AQ descriptor helper function 83162306a36Sopenharmony_ci * @desc: pointer to the temp descriptor (non DMA mem) 83262306a36Sopenharmony_ci * @opcode: the opcode can be used to decide which flags to turn off or on 83362306a36Sopenharmony_ci * 83462306a36Sopenharmony_ci * Fill the desc with default values 83562306a36Sopenharmony_ci **/ 83662306a36Sopenharmony_civoid iavf_fill_default_direct_cmd_desc(struct iavf_aq_desc *desc, u16 opcode) 83762306a36Sopenharmony_ci{ 83862306a36Sopenharmony_ci /* zero out the desc */ 83962306a36Sopenharmony_ci memset((void *)desc, 0, sizeof(struct iavf_aq_desc)); 84062306a36Sopenharmony_ci desc->opcode = cpu_to_le16(opcode); 84162306a36Sopenharmony_ci desc->flags = cpu_to_le16(IAVF_AQ_FLAG_SI); 84262306a36Sopenharmony_ci} 84362306a36Sopenharmony_ci 84462306a36Sopenharmony_ci/** 84562306a36Sopenharmony_ci * iavf_clean_arq_element 84662306a36Sopenharmony_ci * @hw: pointer to the hw struct 84762306a36Sopenharmony_ci * @e: event info from the receive descriptor, includes any buffers 84862306a36Sopenharmony_ci * @pending: number of events that could be left to process 84962306a36Sopenharmony_ci * 85062306a36Sopenharmony_ci * This function cleans one Admin Receive Queue element and returns 85162306a36Sopenharmony_ci * the contents through e. It can also return how many events are 85262306a36Sopenharmony_ci * left to process through 'pending' 85362306a36Sopenharmony_ci **/ 85462306a36Sopenharmony_cienum iavf_status iavf_clean_arq_element(struct iavf_hw *hw, 85562306a36Sopenharmony_ci struct iavf_arq_event_info *e, 85662306a36Sopenharmony_ci u16 *pending) 85762306a36Sopenharmony_ci{ 85862306a36Sopenharmony_ci u16 ntc = hw->aq.arq.next_to_clean; 85962306a36Sopenharmony_ci struct iavf_aq_desc *desc; 86062306a36Sopenharmony_ci enum iavf_status ret_code = 0; 86162306a36Sopenharmony_ci struct iavf_dma_mem *bi; 86262306a36Sopenharmony_ci u16 desc_idx; 86362306a36Sopenharmony_ci u16 datalen; 86462306a36Sopenharmony_ci u16 flags; 86562306a36Sopenharmony_ci u16 ntu; 86662306a36Sopenharmony_ci 86762306a36Sopenharmony_ci /* pre-clean the event info */ 86862306a36Sopenharmony_ci memset(&e->desc, 0, sizeof(e->desc)); 86962306a36Sopenharmony_ci 87062306a36Sopenharmony_ci /* take the lock before we start messing with the ring */ 87162306a36Sopenharmony_ci mutex_lock(&hw->aq.arq_mutex); 87262306a36Sopenharmony_ci 87362306a36Sopenharmony_ci if (hw->aq.arq.count == 0) { 87462306a36Sopenharmony_ci iavf_debug(hw, IAVF_DEBUG_AQ_MESSAGE, 87562306a36Sopenharmony_ci "AQRX: Admin queue not initialized.\n"); 87662306a36Sopenharmony_ci ret_code = IAVF_ERR_QUEUE_EMPTY; 87762306a36Sopenharmony_ci goto clean_arq_element_err; 87862306a36Sopenharmony_ci } 87962306a36Sopenharmony_ci 88062306a36Sopenharmony_ci /* set next_to_use to head */ 88162306a36Sopenharmony_ci ntu = rd32(hw, hw->aq.arq.head) & IAVF_VF_ARQH1_ARQH_MASK; 88262306a36Sopenharmony_ci if (ntu == ntc) { 88362306a36Sopenharmony_ci /* nothing to do - shouldn't need to update ring's values */ 88462306a36Sopenharmony_ci ret_code = IAVF_ERR_ADMIN_QUEUE_NO_WORK; 88562306a36Sopenharmony_ci goto clean_arq_element_out; 88662306a36Sopenharmony_ci } 88762306a36Sopenharmony_ci 88862306a36Sopenharmony_ci /* now clean the next descriptor */ 88962306a36Sopenharmony_ci desc = IAVF_ADMINQ_DESC(hw->aq.arq, ntc); 89062306a36Sopenharmony_ci desc_idx = ntc; 89162306a36Sopenharmony_ci 89262306a36Sopenharmony_ci hw->aq.arq_last_status = 89362306a36Sopenharmony_ci (enum iavf_admin_queue_err)le16_to_cpu(desc->retval); 89462306a36Sopenharmony_ci flags = le16_to_cpu(desc->flags); 89562306a36Sopenharmony_ci if (flags & IAVF_AQ_FLAG_ERR) { 89662306a36Sopenharmony_ci ret_code = IAVF_ERR_ADMIN_QUEUE_ERROR; 89762306a36Sopenharmony_ci iavf_debug(hw, 89862306a36Sopenharmony_ci IAVF_DEBUG_AQ_MESSAGE, 89962306a36Sopenharmony_ci "AQRX: Event received with error 0x%X.\n", 90062306a36Sopenharmony_ci hw->aq.arq_last_status); 90162306a36Sopenharmony_ci } 90262306a36Sopenharmony_ci 90362306a36Sopenharmony_ci e->desc = *desc; 90462306a36Sopenharmony_ci datalen = le16_to_cpu(desc->datalen); 90562306a36Sopenharmony_ci e->msg_len = min(datalen, e->buf_len); 90662306a36Sopenharmony_ci if (e->msg_buf && (e->msg_len != 0)) 90762306a36Sopenharmony_ci memcpy(e->msg_buf, hw->aq.arq.r.arq_bi[desc_idx].va, 90862306a36Sopenharmony_ci e->msg_len); 90962306a36Sopenharmony_ci 91062306a36Sopenharmony_ci iavf_debug(hw, IAVF_DEBUG_AQ_MESSAGE, "AQRX: desc and buffer:\n"); 91162306a36Sopenharmony_ci iavf_debug_aq(hw, IAVF_DEBUG_AQ_COMMAND, (void *)desc, e->msg_buf, 91262306a36Sopenharmony_ci hw->aq.arq_buf_size); 91362306a36Sopenharmony_ci 91462306a36Sopenharmony_ci /* Restore the original datalen and buffer address in the desc, 91562306a36Sopenharmony_ci * FW updates datalen to indicate the event message 91662306a36Sopenharmony_ci * size 91762306a36Sopenharmony_ci */ 91862306a36Sopenharmony_ci bi = &hw->aq.arq.r.arq_bi[ntc]; 91962306a36Sopenharmony_ci memset((void *)desc, 0, sizeof(struct iavf_aq_desc)); 92062306a36Sopenharmony_ci 92162306a36Sopenharmony_ci desc->flags = cpu_to_le16(IAVF_AQ_FLAG_BUF); 92262306a36Sopenharmony_ci if (hw->aq.arq_buf_size > IAVF_AQ_LARGE_BUF) 92362306a36Sopenharmony_ci desc->flags |= cpu_to_le16(IAVF_AQ_FLAG_LB); 92462306a36Sopenharmony_ci desc->datalen = cpu_to_le16((u16)bi->size); 92562306a36Sopenharmony_ci desc->params.external.addr_high = cpu_to_le32(upper_32_bits(bi->pa)); 92662306a36Sopenharmony_ci desc->params.external.addr_low = cpu_to_le32(lower_32_bits(bi->pa)); 92762306a36Sopenharmony_ci 92862306a36Sopenharmony_ci /* set tail = the last cleaned desc index. */ 92962306a36Sopenharmony_ci wr32(hw, hw->aq.arq.tail, ntc); 93062306a36Sopenharmony_ci /* ntc is updated to tail + 1 */ 93162306a36Sopenharmony_ci ntc++; 93262306a36Sopenharmony_ci if (ntc == hw->aq.num_arq_entries) 93362306a36Sopenharmony_ci ntc = 0; 93462306a36Sopenharmony_ci hw->aq.arq.next_to_clean = ntc; 93562306a36Sopenharmony_ci hw->aq.arq.next_to_use = ntu; 93662306a36Sopenharmony_ci 93762306a36Sopenharmony_ciclean_arq_element_out: 93862306a36Sopenharmony_ci /* Set pending if needed, unlock and return */ 93962306a36Sopenharmony_ci if (pending) 94062306a36Sopenharmony_ci *pending = (ntc > ntu ? hw->aq.arq.count : 0) + (ntu - ntc); 94162306a36Sopenharmony_ci 94262306a36Sopenharmony_ciclean_arq_element_err: 94362306a36Sopenharmony_ci mutex_unlock(&hw->aq.arq_mutex); 94462306a36Sopenharmony_ci 94562306a36Sopenharmony_ci return ret_code; 94662306a36Sopenharmony_ci} 947