18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* Copyright(c) 2013 - 2018 Intel Corporation. */ 38c2ecf20Sopenharmony_ci 48c2ecf20Sopenharmony_ci#include "iavf_status.h" 58c2ecf20Sopenharmony_ci#include "iavf_type.h" 68c2ecf20Sopenharmony_ci#include "iavf_register.h" 78c2ecf20Sopenharmony_ci#include "iavf_adminq.h" 88c2ecf20Sopenharmony_ci#include "iavf_prototype.h" 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_ci/** 118c2ecf20Sopenharmony_ci * iavf_adminq_init_regs - Initialize AdminQ registers 128c2ecf20Sopenharmony_ci * @hw: pointer to the hardware structure 138c2ecf20Sopenharmony_ci * 148c2ecf20Sopenharmony_ci * This assumes the alloc_asq and alloc_arq functions have already been called 158c2ecf20Sopenharmony_ci **/ 168c2ecf20Sopenharmony_cistatic void iavf_adminq_init_regs(struct iavf_hw *hw) 178c2ecf20Sopenharmony_ci{ 188c2ecf20Sopenharmony_ci /* set head and tail registers in our local struct */ 198c2ecf20Sopenharmony_ci hw->aq.asq.tail = IAVF_VF_ATQT1; 208c2ecf20Sopenharmony_ci hw->aq.asq.head = IAVF_VF_ATQH1; 218c2ecf20Sopenharmony_ci hw->aq.asq.len = IAVF_VF_ATQLEN1; 228c2ecf20Sopenharmony_ci hw->aq.asq.bal = IAVF_VF_ATQBAL1; 238c2ecf20Sopenharmony_ci hw->aq.asq.bah = IAVF_VF_ATQBAH1; 248c2ecf20Sopenharmony_ci hw->aq.arq.tail = IAVF_VF_ARQT1; 258c2ecf20Sopenharmony_ci hw->aq.arq.head = IAVF_VF_ARQH1; 268c2ecf20Sopenharmony_ci hw->aq.arq.len = IAVF_VF_ARQLEN1; 278c2ecf20Sopenharmony_ci hw->aq.arq.bal = IAVF_VF_ARQBAL1; 288c2ecf20Sopenharmony_ci hw->aq.arq.bah = IAVF_VF_ARQBAH1; 298c2ecf20Sopenharmony_ci} 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ci/** 328c2ecf20Sopenharmony_ci * iavf_alloc_adminq_asq_ring - Allocate Admin Queue send rings 338c2ecf20Sopenharmony_ci * @hw: pointer to the hardware structure 348c2ecf20Sopenharmony_ci **/ 358c2ecf20Sopenharmony_cistatic enum iavf_status iavf_alloc_adminq_asq_ring(struct iavf_hw *hw) 368c2ecf20Sopenharmony_ci{ 378c2ecf20Sopenharmony_ci enum iavf_status ret_code; 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_ci ret_code = iavf_allocate_dma_mem(hw, &hw->aq.asq.desc_buf, 408c2ecf20Sopenharmony_ci iavf_mem_atq_ring, 418c2ecf20Sopenharmony_ci (hw->aq.num_asq_entries * 428c2ecf20Sopenharmony_ci sizeof(struct iavf_aq_desc)), 438c2ecf20Sopenharmony_ci IAVF_ADMINQ_DESC_ALIGNMENT); 448c2ecf20Sopenharmony_ci if (ret_code) 458c2ecf20Sopenharmony_ci return ret_code; 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_ci ret_code = iavf_allocate_virt_mem(hw, &hw->aq.asq.cmd_buf, 488c2ecf20Sopenharmony_ci (hw->aq.num_asq_entries * 498c2ecf20Sopenharmony_ci sizeof(struct iavf_asq_cmd_details))); 508c2ecf20Sopenharmony_ci if (ret_code) { 518c2ecf20Sopenharmony_ci iavf_free_dma_mem(hw, &hw->aq.asq.desc_buf); 528c2ecf20Sopenharmony_ci return ret_code; 538c2ecf20Sopenharmony_ci } 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_ci return ret_code; 568c2ecf20Sopenharmony_ci} 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_ci/** 598c2ecf20Sopenharmony_ci * iavf_alloc_adminq_arq_ring - Allocate Admin Queue receive rings 608c2ecf20Sopenharmony_ci * @hw: pointer to the hardware structure 618c2ecf20Sopenharmony_ci **/ 628c2ecf20Sopenharmony_cistatic enum iavf_status iavf_alloc_adminq_arq_ring(struct iavf_hw *hw) 638c2ecf20Sopenharmony_ci{ 648c2ecf20Sopenharmony_ci enum iavf_status ret_code; 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_ci ret_code = iavf_allocate_dma_mem(hw, &hw->aq.arq.desc_buf, 678c2ecf20Sopenharmony_ci iavf_mem_arq_ring, 688c2ecf20Sopenharmony_ci (hw->aq.num_arq_entries * 698c2ecf20Sopenharmony_ci sizeof(struct iavf_aq_desc)), 708c2ecf20Sopenharmony_ci IAVF_ADMINQ_DESC_ALIGNMENT); 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_ci return ret_code; 738c2ecf20Sopenharmony_ci} 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_ci/** 768c2ecf20Sopenharmony_ci * iavf_free_adminq_asq - Free Admin Queue send rings 778c2ecf20Sopenharmony_ci * @hw: pointer to the hardware structure 788c2ecf20Sopenharmony_ci * 798c2ecf20Sopenharmony_ci * This assumes the posted send buffers have already been cleaned 808c2ecf20Sopenharmony_ci * and de-allocated 818c2ecf20Sopenharmony_ci **/ 828c2ecf20Sopenharmony_cistatic void iavf_free_adminq_asq(struct iavf_hw *hw) 838c2ecf20Sopenharmony_ci{ 848c2ecf20Sopenharmony_ci iavf_free_dma_mem(hw, &hw->aq.asq.desc_buf); 858c2ecf20Sopenharmony_ci} 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_ci/** 888c2ecf20Sopenharmony_ci * iavf_free_adminq_arq - Free Admin Queue receive rings 898c2ecf20Sopenharmony_ci * @hw: pointer to the hardware structure 908c2ecf20Sopenharmony_ci * 918c2ecf20Sopenharmony_ci * This assumes the posted receive buffers have already been cleaned 928c2ecf20Sopenharmony_ci * and de-allocated 938c2ecf20Sopenharmony_ci **/ 948c2ecf20Sopenharmony_cistatic void iavf_free_adminq_arq(struct iavf_hw *hw) 958c2ecf20Sopenharmony_ci{ 968c2ecf20Sopenharmony_ci iavf_free_dma_mem(hw, &hw->aq.arq.desc_buf); 978c2ecf20Sopenharmony_ci} 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_ci/** 1008c2ecf20Sopenharmony_ci * iavf_alloc_arq_bufs - Allocate pre-posted buffers for the receive queue 1018c2ecf20Sopenharmony_ci * @hw: pointer to the hardware structure 1028c2ecf20Sopenharmony_ci **/ 1038c2ecf20Sopenharmony_cistatic enum iavf_status iavf_alloc_arq_bufs(struct iavf_hw *hw) 1048c2ecf20Sopenharmony_ci{ 1058c2ecf20Sopenharmony_ci struct iavf_aq_desc *desc; 1068c2ecf20Sopenharmony_ci struct iavf_dma_mem *bi; 1078c2ecf20Sopenharmony_ci enum iavf_status ret_code; 1088c2ecf20Sopenharmony_ci int i; 1098c2ecf20Sopenharmony_ci 1108c2ecf20Sopenharmony_ci /* We'll be allocating the buffer info memory first, then we can 1118c2ecf20Sopenharmony_ci * allocate the mapped buffers for the event processing 1128c2ecf20Sopenharmony_ci */ 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_ci /* buffer_info structures do not need alignment */ 1158c2ecf20Sopenharmony_ci ret_code = iavf_allocate_virt_mem(hw, &hw->aq.arq.dma_head, 1168c2ecf20Sopenharmony_ci (hw->aq.num_arq_entries * 1178c2ecf20Sopenharmony_ci sizeof(struct iavf_dma_mem))); 1188c2ecf20Sopenharmony_ci if (ret_code) 1198c2ecf20Sopenharmony_ci goto alloc_arq_bufs; 1208c2ecf20Sopenharmony_ci hw->aq.arq.r.arq_bi = (struct iavf_dma_mem *)hw->aq.arq.dma_head.va; 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_ci /* allocate the mapped buffers */ 1238c2ecf20Sopenharmony_ci for (i = 0; i < hw->aq.num_arq_entries; i++) { 1248c2ecf20Sopenharmony_ci bi = &hw->aq.arq.r.arq_bi[i]; 1258c2ecf20Sopenharmony_ci ret_code = iavf_allocate_dma_mem(hw, bi, 1268c2ecf20Sopenharmony_ci iavf_mem_arq_buf, 1278c2ecf20Sopenharmony_ci hw->aq.arq_buf_size, 1288c2ecf20Sopenharmony_ci IAVF_ADMINQ_DESC_ALIGNMENT); 1298c2ecf20Sopenharmony_ci if (ret_code) 1308c2ecf20Sopenharmony_ci goto unwind_alloc_arq_bufs; 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_ci /* now configure the descriptors for use */ 1338c2ecf20Sopenharmony_ci desc = IAVF_ADMINQ_DESC(hw->aq.arq, i); 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_ci desc->flags = cpu_to_le16(IAVF_AQ_FLAG_BUF); 1368c2ecf20Sopenharmony_ci if (hw->aq.arq_buf_size > IAVF_AQ_LARGE_BUF) 1378c2ecf20Sopenharmony_ci desc->flags |= cpu_to_le16(IAVF_AQ_FLAG_LB); 1388c2ecf20Sopenharmony_ci desc->opcode = 0; 1398c2ecf20Sopenharmony_ci /* This is in accordance with Admin queue design, there is no 1408c2ecf20Sopenharmony_ci * register for buffer size configuration 1418c2ecf20Sopenharmony_ci */ 1428c2ecf20Sopenharmony_ci desc->datalen = cpu_to_le16((u16)bi->size); 1438c2ecf20Sopenharmony_ci desc->retval = 0; 1448c2ecf20Sopenharmony_ci desc->cookie_high = 0; 1458c2ecf20Sopenharmony_ci desc->cookie_low = 0; 1468c2ecf20Sopenharmony_ci desc->params.external.addr_high = 1478c2ecf20Sopenharmony_ci cpu_to_le32(upper_32_bits(bi->pa)); 1488c2ecf20Sopenharmony_ci desc->params.external.addr_low = 1498c2ecf20Sopenharmony_ci cpu_to_le32(lower_32_bits(bi->pa)); 1508c2ecf20Sopenharmony_ci desc->params.external.param0 = 0; 1518c2ecf20Sopenharmony_ci desc->params.external.param1 = 0; 1528c2ecf20Sopenharmony_ci } 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_cialloc_arq_bufs: 1558c2ecf20Sopenharmony_ci return ret_code; 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_ciunwind_alloc_arq_bufs: 1588c2ecf20Sopenharmony_ci /* don't try to free the one that failed... */ 1598c2ecf20Sopenharmony_ci i--; 1608c2ecf20Sopenharmony_ci for (; i >= 0; i--) 1618c2ecf20Sopenharmony_ci iavf_free_dma_mem(hw, &hw->aq.arq.r.arq_bi[i]); 1628c2ecf20Sopenharmony_ci iavf_free_virt_mem(hw, &hw->aq.arq.dma_head); 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_ci return ret_code; 1658c2ecf20Sopenharmony_ci} 1668c2ecf20Sopenharmony_ci 1678c2ecf20Sopenharmony_ci/** 1688c2ecf20Sopenharmony_ci * iavf_alloc_asq_bufs - Allocate empty buffer structs for the send queue 1698c2ecf20Sopenharmony_ci * @hw: pointer to the hardware structure 1708c2ecf20Sopenharmony_ci **/ 1718c2ecf20Sopenharmony_cistatic enum iavf_status iavf_alloc_asq_bufs(struct iavf_hw *hw) 1728c2ecf20Sopenharmony_ci{ 1738c2ecf20Sopenharmony_ci struct iavf_dma_mem *bi; 1748c2ecf20Sopenharmony_ci enum iavf_status ret_code; 1758c2ecf20Sopenharmony_ci int i; 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_ci /* No mapped memory needed yet, just the buffer info structures */ 1788c2ecf20Sopenharmony_ci ret_code = iavf_allocate_virt_mem(hw, &hw->aq.asq.dma_head, 1798c2ecf20Sopenharmony_ci (hw->aq.num_asq_entries * 1808c2ecf20Sopenharmony_ci sizeof(struct iavf_dma_mem))); 1818c2ecf20Sopenharmony_ci if (ret_code) 1828c2ecf20Sopenharmony_ci goto alloc_asq_bufs; 1838c2ecf20Sopenharmony_ci hw->aq.asq.r.asq_bi = (struct iavf_dma_mem *)hw->aq.asq.dma_head.va; 1848c2ecf20Sopenharmony_ci 1858c2ecf20Sopenharmony_ci /* allocate the mapped buffers */ 1868c2ecf20Sopenharmony_ci for (i = 0; i < hw->aq.num_asq_entries; i++) { 1878c2ecf20Sopenharmony_ci bi = &hw->aq.asq.r.asq_bi[i]; 1888c2ecf20Sopenharmony_ci ret_code = iavf_allocate_dma_mem(hw, bi, 1898c2ecf20Sopenharmony_ci iavf_mem_asq_buf, 1908c2ecf20Sopenharmony_ci hw->aq.asq_buf_size, 1918c2ecf20Sopenharmony_ci IAVF_ADMINQ_DESC_ALIGNMENT); 1928c2ecf20Sopenharmony_ci if (ret_code) 1938c2ecf20Sopenharmony_ci goto unwind_alloc_asq_bufs; 1948c2ecf20Sopenharmony_ci } 1958c2ecf20Sopenharmony_cialloc_asq_bufs: 1968c2ecf20Sopenharmony_ci return ret_code; 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_ciunwind_alloc_asq_bufs: 1998c2ecf20Sopenharmony_ci /* don't try to free the one that failed... */ 2008c2ecf20Sopenharmony_ci i--; 2018c2ecf20Sopenharmony_ci for (; i >= 0; i--) 2028c2ecf20Sopenharmony_ci iavf_free_dma_mem(hw, &hw->aq.asq.r.asq_bi[i]); 2038c2ecf20Sopenharmony_ci iavf_free_virt_mem(hw, &hw->aq.asq.dma_head); 2048c2ecf20Sopenharmony_ci 2058c2ecf20Sopenharmony_ci return ret_code; 2068c2ecf20Sopenharmony_ci} 2078c2ecf20Sopenharmony_ci 2088c2ecf20Sopenharmony_ci/** 2098c2ecf20Sopenharmony_ci * iavf_free_arq_bufs - Free receive queue buffer info elements 2108c2ecf20Sopenharmony_ci * @hw: pointer to the hardware structure 2118c2ecf20Sopenharmony_ci **/ 2128c2ecf20Sopenharmony_cistatic void iavf_free_arq_bufs(struct iavf_hw *hw) 2138c2ecf20Sopenharmony_ci{ 2148c2ecf20Sopenharmony_ci int i; 2158c2ecf20Sopenharmony_ci 2168c2ecf20Sopenharmony_ci /* free descriptors */ 2178c2ecf20Sopenharmony_ci for (i = 0; i < hw->aq.num_arq_entries; i++) 2188c2ecf20Sopenharmony_ci iavf_free_dma_mem(hw, &hw->aq.arq.r.arq_bi[i]); 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_ci /* free the descriptor memory */ 2218c2ecf20Sopenharmony_ci iavf_free_dma_mem(hw, &hw->aq.arq.desc_buf); 2228c2ecf20Sopenharmony_ci 2238c2ecf20Sopenharmony_ci /* free the dma header */ 2248c2ecf20Sopenharmony_ci iavf_free_virt_mem(hw, &hw->aq.arq.dma_head); 2258c2ecf20Sopenharmony_ci} 2268c2ecf20Sopenharmony_ci 2278c2ecf20Sopenharmony_ci/** 2288c2ecf20Sopenharmony_ci * iavf_free_asq_bufs - Free send queue buffer info elements 2298c2ecf20Sopenharmony_ci * @hw: pointer to the hardware structure 2308c2ecf20Sopenharmony_ci **/ 2318c2ecf20Sopenharmony_cistatic void iavf_free_asq_bufs(struct iavf_hw *hw) 2328c2ecf20Sopenharmony_ci{ 2338c2ecf20Sopenharmony_ci int i; 2348c2ecf20Sopenharmony_ci 2358c2ecf20Sopenharmony_ci /* only unmap if the address is non-NULL */ 2368c2ecf20Sopenharmony_ci for (i = 0; i < hw->aq.num_asq_entries; i++) 2378c2ecf20Sopenharmony_ci if (hw->aq.asq.r.asq_bi[i].pa) 2388c2ecf20Sopenharmony_ci iavf_free_dma_mem(hw, &hw->aq.asq.r.asq_bi[i]); 2398c2ecf20Sopenharmony_ci 2408c2ecf20Sopenharmony_ci /* free the buffer info list */ 2418c2ecf20Sopenharmony_ci iavf_free_virt_mem(hw, &hw->aq.asq.cmd_buf); 2428c2ecf20Sopenharmony_ci 2438c2ecf20Sopenharmony_ci /* free the descriptor memory */ 2448c2ecf20Sopenharmony_ci iavf_free_dma_mem(hw, &hw->aq.asq.desc_buf); 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_ci /* free the dma header */ 2478c2ecf20Sopenharmony_ci iavf_free_virt_mem(hw, &hw->aq.asq.dma_head); 2488c2ecf20Sopenharmony_ci} 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_ci/** 2518c2ecf20Sopenharmony_ci * iavf_config_asq_regs - configure ASQ registers 2528c2ecf20Sopenharmony_ci * @hw: pointer to the hardware structure 2538c2ecf20Sopenharmony_ci * 2548c2ecf20Sopenharmony_ci * Configure base address and length registers for the transmit queue 2558c2ecf20Sopenharmony_ci **/ 2568c2ecf20Sopenharmony_cistatic enum iavf_status iavf_config_asq_regs(struct iavf_hw *hw) 2578c2ecf20Sopenharmony_ci{ 2588c2ecf20Sopenharmony_ci enum iavf_status ret_code = 0; 2598c2ecf20Sopenharmony_ci u32 reg = 0; 2608c2ecf20Sopenharmony_ci 2618c2ecf20Sopenharmony_ci /* Clear Head and Tail */ 2628c2ecf20Sopenharmony_ci wr32(hw, hw->aq.asq.head, 0); 2638c2ecf20Sopenharmony_ci wr32(hw, hw->aq.asq.tail, 0); 2648c2ecf20Sopenharmony_ci 2658c2ecf20Sopenharmony_ci /* set starting point */ 2668c2ecf20Sopenharmony_ci wr32(hw, hw->aq.asq.len, (hw->aq.num_asq_entries | 2678c2ecf20Sopenharmony_ci IAVF_VF_ATQLEN1_ATQENABLE_MASK)); 2688c2ecf20Sopenharmony_ci wr32(hw, hw->aq.asq.bal, lower_32_bits(hw->aq.asq.desc_buf.pa)); 2698c2ecf20Sopenharmony_ci wr32(hw, hw->aq.asq.bah, upper_32_bits(hw->aq.asq.desc_buf.pa)); 2708c2ecf20Sopenharmony_ci 2718c2ecf20Sopenharmony_ci /* Check one register to verify that config was applied */ 2728c2ecf20Sopenharmony_ci reg = rd32(hw, hw->aq.asq.bal); 2738c2ecf20Sopenharmony_ci if (reg != lower_32_bits(hw->aq.asq.desc_buf.pa)) 2748c2ecf20Sopenharmony_ci ret_code = IAVF_ERR_ADMIN_QUEUE_ERROR; 2758c2ecf20Sopenharmony_ci 2768c2ecf20Sopenharmony_ci return ret_code; 2778c2ecf20Sopenharmony_ci} 2788c2ecf20Sopenharmony_ci 2798c2ecf20Sopenharmony_ci/** 2808c2ecf20Sopenharmony_ci * iavf_config_arq_regs - ARQ register configuration 2818c2ecf20Sopenharmony_ci * @hw: pointer to the hardware structure 2828c2ecf20Sopenharmony_ci * 2838c2ecf20Sopenharmony_ci * Configure base address and length registers for the receive (event queue) 2848c2ecf20Sopenharmony_ci **/ 2858c2ecf20Sopenharmony_cistatic enum iavf_status iavf_config_arq_regs(struct iavf_hw *hw) 2868c2ecf20Sopenharmony_ci{ 2878c2ecf20Sopenharmony_ci enum iavf_status ret_code = 0; 2888c2ecf20Sopenharmony_ci u32 reg = 0; 2898c2ecf20Sopenharmony_ci 2908c2ecf20Sopenharmony_ci /* Clear Head and Tail */ 2918c2ecf20Sopenharmony_ci wr32(hw, hw->aq.arq.head, 0); 2928c2ecf20Sopenharmony_ci wr32(hw, hw->aq.arq.tail, 0); 2938c2ecf20Sopenharmony_ci 2948c2ecf20Sopenharmony_ci /* set starting point */ 2958c2ecf20Sopenharmony_ci wr32(hw, hw->aq.arq.len, (hw->aq.num_arq_entries | 2968c2ecf20Sopenharmony_ci IAVF_VF_ARQLEN1_ARQENABLE_MASK)); 2978c2ecf20Sopenharmony_ci wr32(hw, hw->aq.arq.bal, lower_32_bits(hw->aq.arq.desc_buf.pa)); 2988c2ecf20Sopenharmony_ci wr32(hw, hw->aq.arq.bah, upper_32_bits(hw->aq.arq.desc_buf.pa)); 2998c2ecf20Sopenharmony_ci 3008c2ecf20Sopenharmony_ci /* Update tail in the HW to post pre-allocated buffers */ 3018c2ecf20Sopenharmony_ci wr32(hw, hw->aq.arq.tail, hw->aq.num_arq_entries - 1); 3028c2ecf20Sopenharmony_ci 3038c2ecf20Sopenharmony_ci /* Check one register to verify that config was applied */ 3048c2ecf20Sopenharmony_ci reg = rd32(hw, hw->aq.arq.bal); 3058c2ecf20Sopenharmony_ci if (reg != lower_32_bits(hw->aq.arq.desc_buf.pa)) 3068c2ecf20Sopenharmony_ci ret_code = IAVF_ERR_ADMIN_QUEUE_ERROR; 3078c2ecf20Sopenharmony_ci 3088c2ecf20Sopenharmony_ci return ret_code; 3098c2ecf20Sopenharmony_ci} 3108c2ecf20Sopenharmony_ci 3118c2ecf20Sopenharmony_ci/** 3128c2ecf20Sopenharmony_ci * iavf_init_asq - main initialization routine for ASQ 3138c2ecf20Sopenharmony_ci * @hw: pointer to the hardware structure 3148c2ecf20Sopenharmony_ci * 3158c2ecf20Sopenharmony_ci * This is the main initialization routine for the Admin Send Queue 3168c2ecf20Sopenharmony_ci * Prior to calling this function, drivers *MUST* set the following fields 3178c2ecf20Sopenharmony_ci * in the hw->aq structure: 3188c2ecf20Sopenharmony_ci * - hw->aq.num_asq_entries 3198c2ecf20Sopenharmony_ci * - hw->aq.arq_buf_size 3208c2ecf20Sopenharmony_ci * 3218c2ecf20Sopenharmony_ci * Do *NOT* hold the lock when calling this as the memory allocation routines 3228c2ecf20Sopenharmony_ci * called are not going to be atomic context safe 3238c2ecf20Sopenharmony_ci **/ 3248c2ecf20Sopenharmony_cistatic enum iavf_status iavf_init_asq(struct iavf_hw *hw) 3258c2ecf20Sopenharmony_ci{ 3268c2ecf20Sopenharmony_ci enum iavf_status ret_code = 0; 3278c2ecf20Sopenharmony_ci int i; 3288c2ecf20Sopenharmony_ci 3298c2ecf20Sopenharmony_ci if (hw->aq.asq.count > 0) { 3308c2ecf20Sopenharmony_ci /* queue already initialized */ 3318c2ecf20Sopenharmony_ci ret_code = IAVF_ERR_NOT_READY; 3328c2ecf20Sopenharmony_ci goto init_adminq_exit; 3338c2ecf20Sopenharmony_ci } 3348c2ecf20Sopenharmony_ci 3358c2ecf20Sopenharmony_ci /* verify input for valid configuration */ 3368c2ecf20Sopenharmony_ci if ((hw->aq.num_asq_entries == 0) || 3378c2ecf20Sopenharmony_ci (hw->aq.asq_buf_size == 0)) { 3388c2ecf20Sopenharmony_ci ret_code = IAVF_ERR_CONFIG; 3398c2ecf20Sopenharmony_ci goto init_adminq_exit; 3408c2ecf20Sopenharmony_ci } 3418c2ecf20Sopenharmony_ci 3428c2ecf20Sopenharmony_ci hw->aq.asq.next_to_use = 0; 3438c2ecf20Sopenharmony_ci hw->aq.asq.next_to_clean = 0; 3448c2ecf20Sopenharmony_ci 3458c2ecf20Sopenharmony_ci /* allocate the ring memory */ 3468c2ecf20Sopenharmony_ci ret_code = iavf_alloc_adminq_asq_ring(hw); 3478c2ecf20Sopenharmony_ci if (ret_code) 3488c2ecf20Sopenharmony_ci goto init_adminq_exit; 3498c2ecf20Sopenharmony_ci 3508c2ecf20Sopenharmony_ci /* allocate buffers in the rings */ 3518c2ecf20Sopenharmony_ci ret_code = iavf_alloc_asq_bufs(hw); 3528c2ecf20Sopenharmony_ci if (ret_code) 3538c2ecf20Sopenharmony_ci goto init_adminq_free_rings; 3548c2ecf20Sopenharmony_ci 3558c2ecf20Sopenharmony_ci /* initialize base registers */ 3568c2ecf20Sopenharmony_ci ret_code = iavf_config_asq_regs(hw); 3578c2ecf20Sopenharmony_ci if (ret_code) 3588c2ecf20Sopenharmony_ci goto init_free_asq_bufs; 3598c2ecf20Sopenharmony_ci 3608c2ecf20Sopenharmony_ci /* success! */ 3618c2ecf20Sopenharmony_ci hw->aq.asq.count = hw->aq.num_asq_entries; 3628c2ecf20Sopenharmony_ci goto init_adminq_exit; 3638c2ecf20Sopenharmony_ci 3648c2ecf20Sopenharmony_ciinit_free_asq_bufs: 3658c2ecf20Sopenharmony_ci for (i = 0; i < hw->aq.num_asq_entries; i++) 3668c2ecf20Sopenharmony_ci iavf_free_dma_mem(hw, &hw->aq.asq.r.asq_bi[i]); 3678c2ecf20Sopenharmony_ci iavf_free_virt_mem(hw, &hw->aq.asq.dma_head); 3688c2ecf20Sopenharmony_ci 3698c2ecf20Sopenharmony_ciinit_adminq_free_rings: 3708c2ecf20Sopenharmony_ci iavf_free_adminq_asq(hw); 3718c2ecf20Sopenharmony_ci 3728c2ecf20Sopenharmony_ciinit_adminq_exit: 3738c2ecf20Sopenharmony_ci return ret_code; 3748c2ecf20Sopenharmony_ci} 3758c2ecf20Sopenharmony_ci 3768c2ecf20Sopenharmony_ci/** 3778c2ecf20Sopenharmony_ci * iavf_init_arq - initialize ARQ 3788c2ecf20Sopenharmony_ci * @hw: pointer to the hardware structure 3798c2ecf20Sopenharmony_ci * 3808c2ecf20Sopenharmony_ci * The main initialization routine for the Admin Receive (Event) Queue. 3818c2ecf20Sopenharmony_ci * Prior to calling this function, drivers *MUST* set the following fields 3828c2ecf20Sopenharmony_ci * in the hw->aq structure: 3838c2ecf20Sopenharmony_ci * - hw->aq.num_asq_entries 3848c2ecf20Sopenharmony_ci * - hw->aq.arq_buf_size 3858c2ecf20Sopenharmony_ci * 3868c2ecf20Sopenharmony_ci * Do *NOT* hold the lock when calling this as the memory allocation routines 3878c2ecf20Sopenharmony_ci * called are not going to be atomic context safe 3888c2ecf20Sopenharmony_ci **/ 3898c2ecf20Sopenharmony_cistatic enum iavf_status iavf_init_arq(struct iavf_hw *hw) 3908c2ecf20Sopenharmony_ci{ 3918c2ecf20Sopenharmony_ci enum iavf_status ret_code = 0; 3928c2ecf20Sopenharmony_ci int i; 3938c2ecf20Sopenharmony_ci 3948c2ecf20Sopenharmony_ci if (hw->aq.arq.count > 0) { 3958c2ecf20Sopenharmony_ci /* queue already initialized */ 3968c2ecf20Sopenharmony_ci ret_code = IAVF_ERR_NOT_READY; 3978c2ecf20Sopenharmony_ci goto init_adminq_exit; 3988c2ecf20Sopenharmony_ci } 3998c2ecf20Sopenharmony_ci 4008c2ecf20Sopenharmony_ci /* verify input for valid configuration */ 4018c2ecf20Sopenharmony_ci if ((hw->aq.num_arq_entries == 0) || 4028c2ecf20Sopenharmony_ci (hw->aq.arq_buf_size == 0)) { 4038c2ecf20Sopenharmony_ci ret_code = IAVF_ERR_CONFIG; 4048c2ecf20Sopenharmony_ci goto init_adminq_exit; 4058c2ecf20Sopenharmony_ci } 4068c2ecf20Sopenharmony_ci 4078c2ecf20Sopenharmony_ci hw->aq.arq.next_to_use = 0; 4088c2ecf20Sopenharmony_ci hw->aq.arq.next_to_clean = 0; 4098c2ecf20Sopenharmony_ci 4108c2ecf20Sopenharmony_ci /* allocate the ring memory */ 4118c2ecf20Sopenharmony_ci ret_code = iavf_alloc_adminq_arq_ring(hw); 4128c2ecf20Sopenharmony_ci if (ret_code) 4138c2ecf20Sopenharmony_ci goto init_adminq_exit; 4148c2ecf20Sopenharmony_ci 4158c2ecf20Sopenharmony_ci /* allocate buffers in the rings */ 4168c2ecf20Sopenharmony_ci ret_code = iavf_alloc_arq_bufs(hw); 4178c2ecf20Sopenharmony_ci if (ret_code) 4188c2ecf20Sopenharmony_ci goto init_adminq_free_rings; 4198c2ecf20Sopenharmony_ci 4208c2ecf20Sopenharmony_ci /* initialize base registers */ 4218c2ecf20Sopenharmony_ci ret_code = iavf_config_arq_regs(hw); 4228c2ecf20Sopenharmony_ci if (ret_code) 4238c2ecf20Sopenharmony_ci goto init_free_arq_bufs; 4248c2ecf20Sopenharmony_ci 4258c2ecf20Sopenharmony_ci /* success! */ 4268c2ecf20Sopenharmony_ci hw->aq.arq.count = hw->aq.num_arq_entries; 4278c2ecf20Sopenharmony_ci goto init_adminq_exit; 4288c2ecf20Sopenharmony_ci 4298c2ecf20Sopenharmony_ciinit_free_arq_bufs: 4308c2ecf20Sopenharmony_ci for (i = 0; i < hw->aq.num_arq_entries; i++) 4318c2ecf20Sopenharmony_ci iavf_free_dma_mem(hw, &hw->aq.arq.r.arq_bi[i]); 4328c2ecf20Sopenharmony_ci iavf_free_virt_mem(hw, &hw->aq.arq.dma_head); 4338c2ecf20Sopenharmony_ciinit_adminq_free_rings: 4348c2ecf20Sopenharmony_ci iavf_free_adminq_arq(hw); 4358c2ecf20Sopenharmony_ci 4368c2ecf20Sopenharmony_ciinit_adminq_exit: 4378c2ecf20Sopenharmony_ci return ret_code; 4388c2ecf20Sopenharmony_ci} 4398c2ecf20Sopenharmony_ci 4408c2ecf20Sopenharmony_ci/** 4418c2ecf20Sopenharmony_ci * iavf_shutdown_asq - shutdown the ASQ 4428c2ecf20Sopenharmony_ci * @hw: pointer to the hardware structure 4438c2ecf20Sopenharmony_ci * 4448c2ecf20Sopenharmony_ci * The main shutdown routine for the Admin Send Queue 4458c2ecf20Sopenharmony_ci **/ 4468c2ecf20Sopenharmony_cistatic enum iavf_status iavf_shutdown_asq(struct iavf_hw *hw) 4478c2ecf20Sopenharmony_ci{ 4488c2ecf20Sopenharmony_ci enum iavf_status ret_code = 0; 4498c2ecf20Sopenharmony_ci 4508c2ecf20Sopenharmony_ci mutex_lock(&hw->aq.asq_mutex); 4518c2ecf20Sopenharmony_ci 4528c2ecf20Sopenharmony_ci if (hw->aq.asq.count == 0) { 4538c2ecf20Sopenharmony_ci ret_code = IAVF_ERR_NOT_READY; 4548c2ecf20Sopenharmony_ci goto shutdown_asq_out; 4558c2ecf20Sopenharmony_ci } 4568c2ecf20Sopenharmony_ci 4578c2ecf20Sopenharmony_ci /* Stop firmware AdminQ processing */ 4588c2ecf20Sopenharmony_ci wr32(hw, hw->aq.asq.head, 0); 4598c2ecf20Sopenharmony_ci wr32(hw, hw->aq.asq.tail, 0); 4608c2ecf20Sopenharmony_ci wr32(hw, hw->aq.asq.len, 0); 4618c2ecf20Sopenharmony_ci wr32(hw, hw->aq.asq.bal, 0); 4628c2ecf20Sopenharmony_ci wr32(hw, hw->aq.asq.bah, 0); 4638c2ecf20Sopenharmony_ci 4648c2ecf20Sopenharmony_ci hw->aq.asq.count = 0; /* to indicate uninitialized queue */ 4658c2ecf20Sopenharmony_ci 4668c2ecf20Sopenharmony_ci /* free ring buffers */ 4678c2ecf20Sopenharmony_ci iavf_free_asq_bufs(hw); 4688c2ecf20Sopenharmony_ci 4698c2ecf20Sopenharmony_cishutdown_asq_out: 4708c2ecf20Sopenharmony_ci mutex_unlock(&hw->aq.asq_mutex); 4718c2ecf20Sopenharmony_ci return ret_code; 4728c2ecf20Sopenharmony_ci} 4738c2ecf20Sopenharmony_ci 4748c2ecf20Sopenharmony_ci/** 4758c2ecf20Sopenharmony_ci * iavf_shutdown_arq - shutdown ARQ 4768c2ecf20Sopenharmony_ci * @hw: pointer to the hardware structure 4778c2ecf20Sopenharmony_ci * 4788c2ecf20Sopenharmony_ci * The main shutdown routine for the Admin Receive Queue 4798c2ecf20Sopenharmony_ci **/ 4808c2ecf20Sopenharmony_cistatic enum iavf_status iavf_shutdown_arq(struct iavf_hw *hw) 4818c2ecf20Sopenharmony_ci{ 4828c2ecf20Sopenharmony_ci enum iavf_status ret_code = 0; 4838c2ecf20Sopenharmony_ci 4848c2ecf20Sopenharmony_ci mutex_lock(&hw->aq.arq_mutex); 4858c2ecf20Sopenharmony_ci 4868c2ecf20Sopenharmony_ci if (hw->aq.arq.count == 0) { 4878c2ecf20Sopenharmony_ci ret_code = IAVF_ERR_NOT_READY; 4888c2ecf20Sopenharmony_ci goto shutdown_arq_out; 4898c2ecf20Sopenharmony_ci } 4908c2ecf20Sopenharmony_ci 4918c2ecf20Sopenharmony_ci /* Stop firmware AdminQ processing */ 4928c2ecf20Sopenharmony_ci wr32(hw, hw->aq.arq.head, 0); 4938c2ecf20Sopenharmony_ci wr32(hw, hw->aq.arq.tail, 0); 4948c2ecf20Sopenharmony_ci wr32(hw, hw->aq.arq.len, 0); 4958c2ecf20Sopenharmony_ci wr32(hw, hw->aq.arq.bal, 0); 4968c2ecf20Sopenharmony_ci wr32(hw, hw->aq.arq.bah, 0); 4978c2ecf20Sopenharmony_ci 4988c2ecf20Sopenharmony_ci hw->aq.arq.count = 0; /* to indicate uninitialized queue */ 4998c2ecf20Sopenharmony_ci 5008c2ecf20Sopenharmony_ci /* free ring buffers */ 5018c2ecf20Sopenharmony_ci iavf_free_arq_bufs(hw); 5028c2ecf20Sopenharmony_ci 5038c2ecf20Sopenharmony_cishutdown_arq_out: 5048c2ecf20Sopenharmony_ci mutex_unlock(&hw->aq.arq_mutex); 5058c2ecf20Sopenharmony_ci return ret_code; 5068c2ecf20Sopenharmony_ci} 5078c2ecf20Sopenharmony_ci 5088c2ecf20Sopenharmony_ci/** 5098c2ecf20Sopenharmony_ci * iavf_init_adminq - main initialization routine for Admin Queue 5108c2ecf20Sopenharmony_ci * @hw: pointer to the hardware structure 5118c2ecf20Sopenharmony_ci * 5128c2ecf20Sopenharmony_ci * Prior to calling this function, drivers *MUST* set the following fields 5138c2ecf20Sopenharmony_ci * in the hw->aq structure: 5148c2ecf20Sopenharmony_ci * - hw->aq.num_asq_entries 5158c2ecf20Sopenharmony_ci * - hw->aq.num_arq_entries 5168c2ecf20Sopenharmony_ci * - hw->aq.arq_buf_size 5178c2ecf20Sopenharmony_ci * - hw->aq.asq_buf_size 5188c2ecf20Sopenharmony_ci **/ 5198c2ecf20Sopenharmony_cienum iavf_status iavf_init_adminq(struct iavf_hw *hw) 5208c2ecf20Sopenharmony_ci{ 5218c2ecf20Sopenharmony_ci enum iavf_status ret_code; 5228c2ecf20Sopenharmony_ci 5238c2ecf20Sopenharmony_ci /* verify input for valid configuration */ 5248c2ecf20Sopenharmony_ci if ((hw->aq.num_arq_entries == 0) || 5258c2ecf20Sopenharmony_ci (hw->aq.num_asq_entries == 0) || 5268c2ecf20Sopenharmony_ci (hw->aq.arq_buf_size == 0) || 5278c2ecf20Sopenharmony_ci (hw->aq.asq_buf_size == 0)) { 5288c2ecf20Sopenharmony_ci ret_code = IAVF_ERR_CONFIG; 5298c2ecf20Sopenharmony_ci goto init_adminq_exit; 5308c2ecf20Sopenharmony_ci } 5318c2ecf20Sopenharmony_ci 5328c2ecf20Sopenharmony_ci /* Set up register offsets */ 5338c2ecf20Sopenharmony_ci iavf_adminq_init_regs(hw); 5348c2ecf20Sopenharmony_ci 5358c2ecf20Sopenharmony_ci /* setup ASQ command write back timeout */ 5368c2ecf20Sopenharmony_ci hw->aq.asq_cmd_timeout = IAVF_ASQ_CMD_TIMEOUT; 5378c2ecf20Sopenharmony_ci 5388c2ecf20Sopenharmony_ci /* allocate the ASQ */ 5398c2ecf20Sopenharmony_ci ret_code = iavf_init_asq(hw); 5408c2ecf20Sopenharmony_ci if (ret_code) 5418c2ecf20Sopenharmony_ci goto init_adminq_destroy_locks; 5428c2ecf20Sopenharmony_ci 5438c2ecf20Sopenharmony_ci /* allocate the ARQ */ 5448c2ecf20Sopenharmony_ci ret_code = iavf_init_arq(hw); 5458c2ecf20Sopenharmony_ci if (ret_code) 5468c2ecf20Sopenharmony_ci goto init_adminq_free_asq; 5478c2ecf20Sopenharmony_ci 5488c2ecf20Sopenharmony_ci /* success! */ 5498c2ecf20Sopenharmony_ci goto init_adminq_exit; 5508c2ecf20Sopenharmony_ci 5518c2ecf20Sopenharmony_ciinit_adminq_free_asq: 5528c2ecf20Sopenharmony_ci iavf_shutdown_asq(hw); 5538c2ecf20Sopenharmony_ciinit_adminq_destroy_locks: 5548c2ecf20Sopenharmony_ci 5558c2ecf20Sopenharmony_ciinit_adminq_exit: 5568c2ecf20Sopenharmony_ci return ret_code; 5578c2ecf20Sopenharmony_ci} 5588c2ecf20Sopenharmony_ci 5598c2ecf20Sopenharmony_ci/** 5608c2ecf20Sopenharmony_ci * iavf_shutdown_adminq - shutdown routine for the Admin Queue 5618c2ecf20Sopenharmony_ci * @hw: pointer to the hardware structure 5628c2ecf20Sopenharmony_ci **/ 5638c2ecf20Sopenharmony_cienum iavf_status iavf_shutdown_adminq(struct iavf_hw *hw) 5648c2ecf20Sopenharmony_ci{ 5658c2ecf20Sopenharmony_ci enum iavf_status ret_code = 0; 5668c2ecf20Sopenharmony_ci 5678c2ecf20Sopenharmony_ci if (iavf_check_asq_alive(hw)) 5688c2ecf20Sopenharmony_ci iavf_aq_queue_shutdown(hw, true); 5698c2ecf20Sopenharmony_ci 5708c2ecf20Sopenharmony_ci iavf_shutdown_asq(hw); 5718c2ecf20Sopenharmony_ci iavf_shutdown_arq(hw); 5728c2ecf20Sopenharmony_ci 5738c2ecf20Sopenharmony_ci return ret_code; 5748c2ecf20Sopenharmony_ci} 5758c2ecf20Sopenharmony_ci 5768c2ecf20Sopenharmony_ci/** 5778c2ecf20Sopenharmony_ci * iavf_clean_asq - cleans Admin send queue 5788c2ecf20Sopenharmony_ci * @hw: pointer to the hardware structure 5798c2ecf20Sopenharmony_ci * 5808c2ecf20Sopenharmony_ci * returns the number of free desc 5818c2ecf20Sopenharmony_ci **/ 5828c2ecf20Sopenharmony_cistatic u16 iavf_clean_asq(struct iavf_hw *hw) 5838c2ecf20Sopenharmony_ci{ 5848c2ecf20Sopenharmony_ci struct iavf_adminq_ring *asq = &hw->aq.asq; 5858c2ecf20Sopenharmony_ci struct iavf_asq_cmd_details *details; 5868c2ecf20Sopenharmony_ci u16 ntc = asq->next_to_clean; 5878c2ecf20Sopenharmony_ci struct iavf_aq_desc desc_cb; 5888c2ecf20Sopenharmony_ci struct iavf_aq_desc *desc; 5898c2ecf20Sopenharmony_ci 5908c2ecf20Sopenharmony_ci desc = IAVF_ADMINQ_DESC(*asq, ntc); 5918c2ecf20Sopenharmony_ci details = IAVF_ADMINQ_DETAILS(*asq, ntc); 5928c2ecf20Sopenharmony_ci while (rd32(hw, hw->aq.asq.head) != ntc) { 5938c2ecf20Sopenharmony_ci iavf_debug(hw, IAVF_DEBUG_AQ_MESSAGE, 5948c2ecf20Sopenharmony_ci "ntc %d head %d.\n", ntc, rd32(hw, hw->aq.asq.head)); 5958c2ecf20Sopenharmony_ci 5968c2ecf20Sopenharmony_ci if (details->callback) { 5978c2ecf20Sopenharmony_ci IAVF_ADMINQ_CALLBACK cb_func = 5988c2ecf20Sopenharmony_ci (IAVF_ADMINQ_CALLBACK)details->callback; 5998c2ecf20Sopenharmony_ci desc_cb = *desc; 6008c2ecf20Sopenharmony_ci cb_func(hw, &desc_cb); 6018c2ecf20Sopenharmony_ci } 6028c2ecf20Sopenharmony_ci memset((void *)desc, 0, sizeof(struct iavf_aq_desc)); 6038c2ecf20Sopenharmony_ci memset((void *)details, 0, 6048c2ecf20Sopenharmony_ci sizeof(struct iavf_asq_cmd_details)); 6058c2ecf20Sopenharmony_ci ntc++; 6068c2ecf20Sopenharmony_ci if (ntc == asq->count) 6078c2ecf20Sopenharmony_ci ntc = 0; 6088c2ecf20Sopenharmony_ci desc = IAVF_ADMINQ_DESC(*asq, ntc); 6098c2ecf20Sopenharmony_ci details = IAVF_ADMINQ_DETAILS(*asq, ntc); 6108c2ecf20Sopenharmony_ci } 6118c2ecf20Sopenharmony_ci 6128c2ecf20Sopenharmony_ci asq->next_to_clean = ntc; 6138c2ecf20Sopenharmony_ci 6148c2ecf20Sopenharmony_ci return IAVF_DESC_UNUSED(asq); 6158c2ecf20Sopenharmony_ci} 6168c2ecf20Sopenharmony_ci 6178c2ecf20Sopenharmony_ci/** 6188c2ecf20Sopenharmony_ci * iavf_asq_done - check if FW has processed the Admin Send Queue 6198c2ecf20Sopenharmony_ci * @hw: pointer to the hw struct 6208c2ecf20Sopenharmony_ci * 6218c2ecf20Sopenharmony_ci * Returns true if the firmware has processed all descriptors on the 6228c2ecf20Sopenharmony_ci * admin send queue. Returns false if there are still requests pending. 6238c2ecf20Sopenharmony_ci **/ 6248c2ecf20Sopenharmony_cibool iavf_asq_done(struct iavf_hw *hw) 6258c2ecf20Sopenharmony_ci{ 6268c2ecf20Sopenharmony_ci /* AQ designers suggest use of head for better 6278c2ecf20Sopenharmony_ci * timing reliability than DD bit 6288c2ecf20Sopenharmony_ci */ 6298c2ecf20Sopenharmony_ci return rd32(hw, hw->aq.asq.head) == hw->aq.asq.next_to_use; 6308c2ecf20Sopenharmony_ci} 6318c2ecf20Sopenharmony_ci 6328c2ecf20Sopenharmony_ci/** 6338c2ecf20Sopenharmony_ci * iavf_asq_send_command - send command to Admin Queue 6348c2ecf20Sopenharmony_ci * @hw: pointer to the hw struct 6358c2ecf20Sopenharmony_ci * @desc: prefilled descriptor describing the command (non DMA mem) 6368c2ecf20Sopenharmony_ci * @buff: buffer to use for indirect commands 6378c2ecf20Sopenharmony_ci * @buff_size: size of buffer for indirect commands 6388c2ecf20Sopenharmony_ci * @cmd_details: pointer to command details structure 6398c2ecf20Sopenharmony_ci * 6408c2ecf20Sopenharmony_ci * This is the main send command driver routine for the Admin Queue send 6418c2ecf20Sopenharmony_ci * queue. It runs the queue, cleans the queue, etc 6428c2ecf20Sopenharmony_ci **/ 6438c2ecf20Sopenharmony_cienum iavf_status iavf_asq_send_command(struct iavf_hw *hw, 6448c2ecf20Sopenharmony_ci struct iavf_aq_desc *desc, 6458c2ecf20Sopenharmony_ci void *buff, /* can be NULL */ 6468c2ecf20Sopenharmony_ci u16 buff_size, 6478c2ecf20Sopenharmony_ci struct iavf_asq_cmd_details *cmd_details) 6488c2ecf20Sopenharmony_ci{ 6498c2ecf20Sopenharmony_ci struct iavf_dma_mem *dma_buff = NULL; 6508c2ecf20Sopenharmony_ci struct iavf_asq_cmd_details *details; 6518c2ecf20Sopenharmony_ci struct iavf_aq_desc *desc_on_ring; 6528c2ecf20Sopenharmony_ci bool cmd_completed = false; 6538c2ecf20Sopenharmony_ci enum iavf_status status = 0; 6548c2ecf20Sopenharmony_ci u16 retval = 0; 6558c2ecf20Sopenharmony_ci u32 val = 0; 6568c2ecf20Sopenharmony_ci 6578c2ecf20Sopenharmony_ci mutex_lock(&hw->aq.asq_mutex); 6588c2ecf20Sopenharmony_ci 6598c2ecf20Sopenharmony_ci if (hw->aq.asq.count == 0) { 6608c2ecf20Sopenharmony_ci iavf_debug(hw, IAVF_DEBUG_AQ_MESSAGE, 6618c2ecf20Sopenharmony_ci "AQTX: Admin queue not initialized.\n"); 6628c2ecf20Sopenharmony_ci status = IAVF_ERR_QUEUE_EMPTY; 6638c2ecf20Sopenharmony_ci goto asq_send_command_error; 6648c2ecf20Sopenharmony_ci } 6658c2ecf20Sopenharmony_ci 6668c2ecf20Sopenharmony_ci hw->aq.asq_last_status = IAVF_AQ_RC_OK; 6678c2ecf20Sopenharmony_ci 6688c2ecf20Sopenharmony_ci val = rd32(hw, hw->aq.asq.head); 6698c2ecf20Sopenharmony_ci if (val >= hw->aq.num_asq_entries) { 6708c2ecf20Sopenharmony_ci iavf_debug(hw, IAVF_DEBUG_AQ_MESSAGE, 6718c2ecf20Sopenharmony_ci "AQTX: head overrun at %d\n", val); 6728c2ecf20Sopenharmony_ci status = IAVF_ERR_QUEUE_EMPTY; 6738c2ecf20Sopenharmony_ci goto asq_send_command_error; 6748c2ecf20Sopenharmony_ci } 6758c2ecf20Sopenharmony_ci 6768c2ecf20Sopenharmony_ci details = IAVF_ADMINQ_DETAILS(hw->aq.asq, hw->aq.asq.next_to_use); 6778c2ecf20Sopenharmony_ci if (cmd_details) { 6788c2ecf20Sopenharmony_ci *details = *cmd_details; 6798c2ecf20Sopenharmony_ci 6808c2ecf20Sopenharmony_ci /* If the cmd_details are defined copy the cookie. The 6818c2ecf20Sopenharmony_ci * cpu_to_le32 is not needed here because the data is ignored 6828c2ecf20Sopenharmony_ci * by the FW, only used by the driver 6838c2ecf20Sopenharmony_ci */ 6848c2ecf20Sopenharmony_ci if (details->cookie) { 6858c2ecf20Sopenharmony_ci desc->cookie_high = 6868c2ecf20Sopenharmony_ci cpu_to_le32(upper_32_bits(details->cookie)); 6878c2ecf20Sopenharmony_ci desc->cookie_low = 6888c2ecf20Sopenharmony_ci cpu_to_le32(lower_32_bits(details->cookie)); 6898c2ecf20Sopenharmony_ci } 6908c2ecf20Sopenharmony_ci } else { 6918c2ecf20Sopenharmony_ci memset(details, 0, sizeof(struct iavf_asq_cmd_details)); 6928c2ecf20Sopenharmony_ci } 6938c2ecf20Sopenharmony_ci 6948c2ecf20Sopenharmony_ci /* clear requested flags and then set additional flags if defined */ 6958c2ecf20Sopenharmony_ci desc->flags &= ~cpu_to_le16(details->flags_dis); 6968c2ecf20Sopenharmony_ci desc->flags |= cpu_to_le16(details->flags_ena); 6978c2ecf20Sopenharmony_ci 6988c2ecf20Sopenharmony_ci if (buff_size > hw->aq.asq_buf_size) { 6998c2ecf20Sopenharmony_ci iavf_debug(hw, 7008c2ecf20Sopenharmony_ci IAVF_DEBUG_AQ_MESSAGE, 7018c2ecf20Sopenharmony_ci "AQTX: Invalid buffer size: %d.\n", 7028c2ecf20Sopenharmony_ci buff_size); 7038c2ecf20Sopenharmony_ci status = IAVF_ERR_INVALID_SIZE; 7048c2ecf20Sopenharmony_ci goto asq_send_command_error; 7058c2ecf20Sopenharmony_ci } 7068c2ecf20Sopenharmony_ci 7078c2ecf20Sopenharmony_ci if (details->postpone && !details->async) { 7088c2ecf20Sopenharmony_ci iavf_debug(hw, 7098c2ecf20Sopenharmony_ci IAVF_DEBUG_AQ_MESSAGE, 7108c2ecf20Sopenharmony_ci "AQTX: Async flag not set along with postpone flag"); 7118c2ecf20Sopenharmony_ci status = IAVF_ERR_PARAM; 7128c2ecf20Sopenharmony_ci goto asq_send_command_error; 7138c2ecf20Sopenharmony_ci } 7148c2ecf20Sopenharmony_ci 7158c2ecf20Sopenharmony_ci /* call clean and check queue available function to reclaim the 7168c2ecf20Sopenharmony_ci * descriptors that were processed by FW, the function returns the 7178c2ecf20Sopenharmony_ci * number of desc available 7188c2ecf20Sopenharmony_ci */ 7198c2ecf20Sopenharmony_ci /* the clean function called here could be called in a separate thread 7208c2ecf20Sopenharmony_ci * in case of asynchronous completions 7218c2ecf20Sopenharmony_ci */ 7228c2ecf20Sopenharmony_ci if (iavf_clean_asq(hw) == 0) { 7238c2ecf20Sopenharmony_ci iavf_debug(hw, 7248c2ecf20Sopenharmony_ci IAVF_DEBUG_AQ_MESSAGE, 7258c2ecf20Sopenharmony_ci "AQTX: Error queue is full.\n"); 7268c2ecf20Sopenharmony_ci status = IAVF_ERR_ADMIN_QUEUE_FULL; 7278c2ecf20Sopenharmony_ci goto asq_send_command_error; 7288c2ecf20Sopenharmony_ci } 7298c2ecf20Sopenharmony_ci 7308c2ecf20Sopenharmony_ci /* initialize the temp desc pointer with the right desc */ 7318c2ecf20Sopenharmony_ci desc_on_ring = IAVF_ADMINQ_DESC(hw->aq.asq, hw->aq.asq.next_to_use); 7328c2ecf20Sopenharmony_ci 7338c2ecf20Sopenharmony_ci /* if the desc is available copy the temp desc to the right place */ 7348c2ecf20Sopenharmony_ci *desc_on_ring = *desc; 7358c2ecf20Sopenharmony_ci 7368c2ecf20Sopenharmony_ci /* if buff is not NULL assume indirect command */ 7378c2ecf20Sopenharmony_ci if (buff) { 7388c2ecf20Sopenharmony_ci dma_buff = &hw->aq.asq.r.asq_bi[hw->aq.asq.next_to_use]; 7398c2ecf20Sopenharmony_ci /* copy the user buff into the respective DMA buff */ 7408c2ecf20Sopenharmony_ci memcpy(dma_buff->va, buff, buff_size); 7418c2ecf20Sopenharmony_ci desc_on_ring->datalen = cpu_to_le16(buff_size); 7428c2ecf20Sopenharmony_ci 7438c2ecf20Sopenharmony_ci /* Update the address values in the desc with the pa value 7448c2ecf20Sopenharmony_ci * for respective buffer 7458c2ecf20Sopenharmony_ci */ 7468c2ecf20Sopenharmony_ci desc_on_ring->params.external.addr_high = 7478c2ecf20Sopenharmony_ci cpu_to_le32(upper_32_bits(dma_buff->pa)); 7488c2ecf20Sopenharmony_ci desc_on_ring->params.external.addr_low = 7498c2ecf20Sopenharmony_ci cpu_to_le32(lower_32_bits(dma_buff->pa)); 7508c2ecf20Sopenharmony_ci } 7518c2ecf20Sopenharmony_ci 7528c2ecf20Sopenharmony_ci /* bump the tail */ 7538c2ecf20Sopenharmony_ci iavf_debug(hw, IAVF_DEBUG_AQ_MESSAGE, "AQTX: desc and buffer:\n"); 7548c2ecf20Sopenharmony_ci iavf_debug_aq(hw, IAVF_DEBUG_AQ_COMMAND, (void *)desc_on_ring, 7558c2ecf20Sopenharmony_ci buff, buff_size); 7568c2ecf20Sopenharmony_ci (hw->aq.asq.next_to_use)++; 7578c2ecf20Sopenharmony_ci if (hw->aq.asq.next_to_use == hw->aq.asq.count) 7588c2ecf20Sopenharmony_ci hw->aq.asq.next_to_use = 0; 7598c2ecf20Sopenharmony_ci if (!details->postpone) 7608c2ecf20Sopenharmony_ci wr32(hw, hw->aq.asq.tail, hw->aq.asq.next_to_use); 7618c2ecf20Sopenharmony_ci 7628c2ecf20Sopenharmony_ci /* if cmd_details are not defined or async flag is not set, 7638c2ecf20Sopenharmony_ci * we need to wait for desc write back 7648c2ecf20Sopenharmony_ci */ 7658c2ecf20Sopenharmony_ci if (!details->async && !details->postpone) { 7668c2ecf20Sopenharmony_ci u32 total_delay = 0; 7678c2ecf20Sopenharmony_ci 7688c2ecf20Sopenharmony_ci do { 7698c2ecf20Sopenharmony_ci /* AQ designers suggest use of head for better 7708c2ecf20Sopenharmony_ci * timing reliability than DD bit 7718c2ecf20Sopenharmony_ci */ 7728c2ecf20Sopenharmony_ci if (iavf_asq_done(hw)) 7738c2ecf20Sopenharmony_ci break; 7748c2ecf20Sopenharmony_ci udelay(50); 7758c2ecf20Sopenharmony_ci total_delay += 50; 7768c2ecf20Sopenharmony_ci } while (total_delay < hw->aq.asq_cmd_timeout); 7778c2ecf20Sopenharmony_ci } 7788c2ecf20Sopenharmony_ci 7798c2ecf20Sopenharmony_ci /* if ready, copy the desc back to temp */ 7808c2ecf20Sopenharmony_ci if (iavf_asq_done(hw)) { 7818c2ecf20Sopenharmony_ci *desc = *desc_on_ring; 7828c2ecf20Sopenharmony_ci if (buff) 7838c2ecf20Sopenharmony_ci memcpy(buff, dma_buff->va, buff_size); 7848c2ecf20Sopenharmony_ci retval = le16_to_cpu(desc->retval); 7858c2ecf20Sopenharmony_ci if (retval != 0) { 7868c2ecf20Sopenharmony_ci iavf_debug(hw, 7878c2ecf20Sopenharmony_ci IAVF_DEBUG_AQ_MESSAGE, 7888c2ecf20Sopenharmony_ci "AQTX: Command completed with error 0x%X.\n", 7898c2ecf20Sopenharmony_ci retval); 7908c2ecf20Sopenharmony_ci 7918c2ecf20Sopenharmony_ci /* strip off FW internal code */ 7928c2ecf20Sopenharmony_ci retval &= 0xff; 7938c2ecf20Sopenharmony_ci } 7948c2ecf20Sopenharmony_ci cmd_completed = true; 7958c2ecf20Sopenharmony_ci if ((enum iavf_admin_queue_err)retval == IAVF_AQ_RC_OK) 7968c2ecf20Sopenharmony_ci status = 0; 7978c2ecf20Sopenharmony_ci else if ((enum iavf_admin_queue_err)retval == IAVF_AQ_RC_EBUSY) 7988c2ecf20Sopenharmony_ci status = IAVF_ERR_NOT_READY; 7998c2ecf20Sopenharmony_ci else 8008c2ecf20Sopenharmony_ci status = IAVF_ERR_ADMIN_QUEUE_ERROR; 8018c2ecf20Sopenharmony_ci hw->aq.asq_last_status = (enum iavf_admin_queue_err)retval; 8028c2ecf20Sopenharmony_ci } 8038c2ecf20Sopenharmony_ci 8048c2ecf20Sopenharmony_ci iavf_debug(hw, IAVF_DEBUG_AQ_MESSAGE, 8058c2ecf20Sopenharmony_ci "AQTX: desc and buffer writeback:\n"); 8068c2ecf20Sopenharmony_ci iavf_debug_aq(hw, IAVF_DEBUG_AQ_COMMAND, (void *)desc, buff, buff_size); 8078c2ecf20Sopenharmony_ci 8088c2ecf20Sopenharmony_ci /* save writeback aq if requested */ 8098c2ecf20Sopenharmony_ci if (details->wb_desc) 8108c2ecf20Sopenharmony_ci *details->wb_desc = *desc_on_ring; 8118c2ecf20Sopenharmony_ci 8128c2ecf20Sopenharmony_ci /* update the error if time out occurred */ 8138c2ecf20Sopenharmony_ci if ((!cmd_completed) && 8148c2ecf20Sopenharmony_ci (!details->async && !details->postpone)) { 8158c2ecf20Sopenharmony_ci if (rd32(hw, hw->aq.asq.len) & IAVF_VF_ATQLEN1_ATQCRIT_MASK) { 8168c2ecf20Sopenharmony_ci iavf_debug(hw, IAVF_DEBUG_AQ_MESSAGE, 8178c2ecf20Sopenharmony_ci "AQTX: AQ Critical error.\n"); 8188c2ecf20Sopenharmony_ci status = IAVF_ERR_ADMIN_QUEUE_CRITICAL_ERROR; 8198c2ecf20Sopenharmony_ci } else { 8208c2ecf20Sopenharmony_ci iavf_debug(hw, IAVF_DEBUG_AQ_MESSAGE, 8218c2ecf20Sopenharmony_ci "AQTX: Writeback timeout.\n"); 8228c2ecf20Sopenharmony_ci status = IAVF_ERR_ADMIN_QUEUE_TIMEOUT; 8238c2ecf20Sopenharmony_ci } 8248c2ecf20Sopenharmony_ci } 8258c2ecf20Sopenharmony_ci 8268c2ecf20Sopenharmony_ciasq_send_command_error: 8278c2ecf20Sopenharmony_ci mutex_unlock(&hw->aq.asq_mutex); 8288c2ecf20Sopenharmony_ci return status; 8298c2ecf20Sopenharmony_ci} 8308c2ecf20Sopenharmony_ci 8318c2ecf20Sopenharmony_ci/** 8328c2ecf20Sopenharmony_ci * iavf_fill_default_direct_cmd_desc - AQ descriptor helper function 8338c2ecf20Sopenharmony_ci * @desc: pointer to the temp descriptor (non DMA mem) 8348c2ecf20Sopenharmony_ci * @opcode: the opcode can be used to decide which flags to turn off or on 8358c2ecf20Sopenharmony_ci * 8368c2ecf20Sopenharmony_ci * Fill the desc with default values 8378c2ecf20Sopenharmony_ci **/ 8388c2ecf20Sopenharmony_civoid iavf_fill_default_direct_cmd_desc(struct iavf_aq_desc *desc, u16 opcode) 8398c2ecf20Sopenharmony_ci{ 8408c2ecf20Sopenharmony_ci /* zero out the desc */ 8418c2ecf20Sopenharmony_ci memset((void *)desc, 0, sizeof(struct iavf_aq_desc)); 8428c2ecf20Sopenharmony_ci desc->opcode = cpu_to_le16(opcode); 8438c2ecf20Sopenharmony_ci desc->flags = cpu_to_le16(IAVF_AQ_FLAG_SI); 8448c2ecf20Sopenharmony_ci} 8458c2ecf20Sopenharmony_ci 8468c2ecf20Sopenharmony_ci/** 8478c2ecf20Sopenharmony_ci * iavf_clean_arq_element 8488c2ecf20Sopenharmony_ci * @hw: pointer to the hw struct 8498c2ecf20Sopenharmony_ci * @e: event info from the receive descriptor, includes any buffers 8508c2ecf20Sopenharmony_ci * @pending: number of events that could be left to process 8518c2ecf20Sopenharmony_ci * 8528c2ecf20Sopenharmony_ci * This function cleans one Admin Receive Queue element and returns 8538c2ecf20Sopenharmony_ci * the contents through e. It can also return how many events are 8548c2ecf20Sopenharmony_ci * left to process through 'pending' 8558c2ecf20Sopenharmony_ci **/ 8568c2ecf20Sopenharmony_cienum iavf_status iavf_clean_arq_element(struct iavf_hw *hw, 8578c2ecf20Sopenharmony_ci struct iavf_arq_event_info *e, 8588c2ecf20Sopenharmony_ci u16 *pending) 8598c2ecf20Sopenharmony_ci{ 8608c2ecf20Sopenharmony_ci u16 ntc = hw->aq.arq.next_to_clean; 8618c2ecf20Sopenharmony_ci struct iavf_aq_desc *desc; 8628c2ecf20Sopenharmony_ci enum iavf_status ret_code = 0; 8638c2ecf20Sopenharmony_ci struct iavf_dma_mem *bi; 8648c2ecf20Sopenharmony_ci u16 desc_idx; 8658c2ecf20Sopenharmony_ci u16 datalen; 8668c2ecf20Sopenharmony_ci u16 flags; 8678c2ecf20Sopenharmony_ci u16 ntu; 8688c2ecf20Sopenharmony_ci 8698c2ecf20Sopenharmony_ci /* pre-clean the event info */ 8708c2ecf20Sopenharmony_ci memset(&e->desc, 0, sizeof(e->desc)); 8718c2ecf20Sopenharmony_ci 8728c2ecf20Sopenharmony_ci /* take the lock before we start messing with the ring */ 8738c2ecf20Sopenharmony_ci mutex_lock(&hw->aq.arq_mutex); 8748c2ecf20Sopenharmony_ci 8758c2ecf20Sopenharmony_ci if (hw->aq.arq.count == 0) { 8768c2ecf20Sopenharmony_ci iavf_debug(hw, IAVF_DEBUG_AQ_MESSAGE, 8778c2ecf20Sopenharmony_ci "AQRX: Admin queue not initialized.\n"); 8788c2ecf20Sopenharmony_ci ret_code = IAVF_ERR_QUEUE_EMPTY; 8798c2ecf20Sopenharmony_ci goto clean_arq_element_err; 8808c2ecf20Sopenharmony_ci } 8818c2ecf20Sopenharmony_ci 8828c2ecf20Sopenharmony_ci /* set next_to_use to head */ 8838c2ecf20Sopenharmony_ci ntu = rd32(hw, hw->aq.arq.head) & IAVF_VF_ARQH1_ARQH_MASK; 8848c2ecf20Sopenharmony_ci if (ntu == ntc) { 8858c2ecf20Sopenharmony_ci /* nothing to do - shouldn't need to update ring's values */ 8868c2ecf20Sopenharmony_ci ret_code = IAVF_ERR_ADMIN_QUEUE_NO_WORK; 8878c2ecf20Sopenharmony_ci goto clean_arq_element_out; 8888c2ecf20Sopenharmony_ci } 8898c2ecf20Sopenharmony_ci 8908c2ecf20Sopenharmony_ci /* now clean the next descriptor */ 8918c2ecf20Sopenharmony_ci desc = IAVF_ADMINQ_DESC(hw->aq.arq, ntc); 8928c2ecf20Sopenharmony_ci desc_idx = ntc; 8938c2ecf20Sopenharmony_ci 8948c2ecf20Sopenharmony_ci hw->aq.arq_last_status = 8958c2ecf20Sopenharmony_ci (enum iavf_admin_queue_err)le16_to_cpu(desc->retval); 8968c2ecf20Sopenharmony_ci flags = le16_to_cpu(desc->flags); 8978c2ecf20Sopenharmony_ci if (flags & IAVF_AQ_FLAG_ERR) { 8988c2ecf20Sopenharmony_ci ret_code = IAVF_ERR_ADMIN_QUEUE_ERROR; 8998c2ecf20Sopenharmony_ci iavf_debug(hw, 9008c2ecf20Sopenharmony_ci IAVF_DEBUG_AQ_MESSAGE, 9018c2ecf20Sopenharmony_ci "AQRX: Event received with error 0x%X.\n", 9028c2ecf20Sopenharmony_ci hw->aq.arq_last_status); 9038c2ecf20Sopenharmony_ci } 9048c2ecf20Sopenharmony_ci 9058c2ecf20Sopenharmony_ci e->desc = *desc; 9068c2ecf20Sopenharmony_ci datalen = le16_to_cpu(desc->datalen); 9078c2ecf20Sopenharmony_ci e->msg_len = min(datalen, e->buf_len); 9088c2ecf20Sopenharmony_ci if (e->msg_buf && (e->msg_len != 0)) 9098c2ecf20Sopenharmony_ci memcpy(e->msg_buf, hw->aq.arq.r.arq_bi[desc_idx].va, 9108c2ecf20Sopenharmony_ci e->msg_len); 9118c2ecf20Sopenharmony_ci 9128c2ecf20Sopenharmony_ci iavf_debug(hw, IAVF_DEBUG_AQ_MESSAGE, "AQRX: desc and buffer:\n"); 9138c2ecf20Sopenharmony_ci iavf_debug_aq(hw, IAVF_DEBUG_AQ_COMMAND, (void *)desc, e->msg_buf, 9148c2ecf20Sopenharmony_ci hw->aq.arq_buf_size); 9158c2ecf20Sopenharmony_ci 9168c2ecf20Sopenharmony_ci /* Restore the original datalen and buffer address in the desc, 9178c2ecf20Sopenharmony_ci * FW updates datalen to indicate the event message 9188c2ecf20Sopenharmony_ci * size 9198c2ecf20Sopenharmony_ci */ 9208c2ecf20Sopenharmony_ci bi = &hw->aq.arq.r.arq_bi[ntc]; 9218c2ecf20Sopenharmony_ci memset((void *)desc, 0, sizeof(struct iavf_aq_desc)); 9228c2ecf20Sopenharmony_ci 9238c2ecf20Sopenharmony_ci desc->flags = cpu_to_le16(IAVF_AQ_FLAG_BUF); 9248c2ecf20Sopenharmony_ci if (hw->aq.arq_buf_size > IAVF_AQ_LARGE_BUF) 9258c2ecf20Sopenharmony_ci desc->flags |= cpu_to_le16(IAVF_AQ_FLAG_LB); 9268c2ecf20Sopenharmony_ci desc->datalen = cpu_to_le16((u16)bi->size); 9278c2ecf20Sopenharmony_ci desc->params.external.addr_high = cpu_to_le32(upper_32_bits(bi->pa)); 9288c2ecf20Sopenharmony_ci desc->params.external.addr_low = cpu_to_le32(lower_32_bits(bi->pa)); 9298c2ecf20Sopenharmony_ci 9308c2ecf20Sopenharmony_ci /* set tail = the last cleaned desc index. */ 9318c2ecf20Sopenharmony_ci wr32(hw, hw->aq.arq.tail, ntc); 9328c2ecf20Sopenharmony_ci /* ntc is updated to tail + 1 */ 9338c2ecf20Sopenharmony_ci ntc++; 9348c2ecf20Sopenharmony_ci if (ntc == hw->aq.num_arq_entries) 9358c2ecf20Sopenharmony_ci ntc = 0; 9368c2ecf20Sopenharmony_ci hw->aq.arq.next_to_clean = ntc; 9378c2ecf20Sopenharmony_ci hw->aq.arq.next_to_use = ntu; 9388c2ecf20Sopenharmony_ci 9398c2ecf20Sopenharmony_ciclean_arq_element_out: 9408c2ecf20Sopenharmony_ci /* Set pending if needed, unlock and return */ 9418c2ecf20Sopenharmony_ci if (pending) 9428c2ecf20Sopenharmony_ci *pending = (ntc > ntu ? hw->aq.arq.count : 0) + (ntu - ntc); 9438c2ecf20Sopenharmony_ci 9448c2ecf20Sopenharmony_ciclean_arq_element_err: 9458c2ecf20Sopenharmony_ci mutex_unlock(&hw->aq.arq_mutex); 9468c2ecf20Sopenharmony_ci 9478c2ecf20Sopenharmony_ci return ret_code; 9488c2ecf20Sopenharmony_ci} 949