18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* Copyright (c) 2018, Intel Corporation. */ 38c2ecf20Sopenharmony_ci 48c2ecf20Sopenharmony_ci#include "ice_common.h" 58c2ecf20Sopenharmony_ci 68c2ecf20Sopenharmony_ci#define ICE_CQ_INIT_REGS(qinfo, prefix) \ 78c2ecf20Sopenharmony_cido { \ 88c2ecf20Sopenharmony_ci (qinfo)->sq.head = prefix##_ATQH; \ 98c2ecf20Sopenharmony_ci (qinfo)->sq.tail = prefix##_ATQT; \ 108c2ecf20Sopenharmony_ci (qinfo)->sq.len = prefix##_ATQLEN; \ 118c2ecf20Sopenharmony_ci (qinfo)->sq.bah = prefix##_ATQBAH; \ 128c2ecf20Sopenharmony_ci (qinfo)->sq.bal = prefix##_ATQBAL; \ 138c2ecf20Sopenharmony_ci (qinfo)->sq.len_mask = prefix##_ATQLEN_ATQLEN_M; \ 148c2ecf20Sopenharmony_ci (qinfo)->sq.len_ena_mask = prefix##_ATQLEN_ATQENABLE_M; \ 158c2ecf20Sopenharmony_ci (qinfo)->sq.len_crit_mask = prefix##_ATQLEN_ATQCRIT_M; \ 168c2ecf20Sopenharmony_ci (qinfo)->sq.head_mask = prefix##_ATQH_ATQH_M; \ 178c2ecf20Sopenharmony_ci (qinfo)->rq.head = prefix##_ARQH; \ 188c2ecf20Sopenharmony_ci (qinfo)->rq.tail = prefix##_ARQT; \ 198c2ecf20Sopenharmony_ci (qinfo)->rq.len = prefix##_ARQLEN; \ 208c2ecf20Sopenharmony_ci (qinfo)->rq.bah = prefix##_ARQBAH; \ 218c2ecf20Sopenharmony_ci (qinfo)->rq.bal = prefix##_ARQBAL; \ 228c2ecf20Sopenharmony_ci (qinfo)->rq.len_mask = prefix##_ARQLEN_ARQLEN_M; \ 238c2ecf20Sopenharmony_ci (qinfo)->rq.len_ena_mask = prefix##_ARQLEN_ARQENABLE_M; \ 248c2ecf20Sopenharmony_ci (qinfo)->rq.len_crit_mask = prefix##_ARQLEN_ARQCRIT_M; \ 258c2ecf20Sopenharmony_ci (qinfo)->rq.head_mask = prefix##_ARQH_ARQH_M; \ 268c2ecf20Sopenharmony_ci} while (0) 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_ci/** 298c2ecf20Sopenharmony_ci * ice_adminq_init_regs - Initialize AdminQ registers 308c2ecf20Sopenharmony_ci * @hw: pointer to the hardware structure 318c2ecf20Sopenharmony_ci * 328c2ecf20Sopenharmony_ci * This assumes the alloc_sq and alloc_rq functions have already been called 338c2ecf20Sopenharmony_ci */ 348c2ecf20Sopenharmony_cistatic void ice_adminq_init_regs(struct ice_hw *hw) 358c2ecf20Sopenharmony_ci{ 368c2ecf20Sopenharmony_ci struct ice_ctl_q_info *cq = &hw->adminq; 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_ci ICE_CQ_INIT_REGS(cq, PF_FW); 398c2ecf20Sopenharmony_ci} 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_ci/** 428c2ecf20Sopenharmony_ci * ice_mailbox_init_regs - Initialize Mailbox registers 438c2ecf20Sopenharmony_ci * @hw: pointer to the hardware structure 448c2ecf20Sopenharmony_ci * 458c2ecf20Sopenharmony_ci * This assumes the alloc_sq and alloc_rq functions have already been called 468c2ecf20Sopenharmony_ci */ 478c2ecf20Sopenharmony_cistatic void ice_mailbox_init_regs(struct ice_hw *hw) 488c2ecf20Sopenharmony_ci{ 498c2ecf20Sopenharmony_ci struct ice_ctl_q_info *cq = &hw->mailboxq; 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_ci ICE_CQ_INIT_REGS(cq, PF_MBX); 528c2ecf20Sopenharmony_ci} 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_ci/** 558c2ecf20Sopenharmony_ci * ice_check_sq_alive 568c2ecf20Sopenharmony_ci * @hw: pointer to the HW struct 578c2ecf20Sopenharmony_ci * @cq: pointer to the specific Control queue 588c2ecf20Sopenharmony_ci * 598c2ecf20Sopenharmony_ci * Returns true if Queue is enabled else false. 608c2ecf20Sopenharmony_ci */ 618c2ecf20Sopenharmony_cibool ice_check_sq_alive(struct ice_hw *hw, struct ice_ctl_q_info *cq) 628c2ecf20Sopenharmony_ci{ 638c2ecf20Sopenharmony_ci /* check both queue-length and queue-enable fields */ 648c2ecf20Sopenharmony_ci if (cq->sq.len && cq->sq.len_mask && cq->sq.len_ena_mask) 658c2ecf20Sopenharmony_ci return (rd32(hw, cq->sq.len) & (cq->sq.len_mask | 668c2ecf20Sopenharmony_ci cq->sq.len_ena_mask)) == 678c2ecf20Sopenharmony_ci (cq->num_sq_entries | cq->sq.len_ena_mask); 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_ci return false; 708c2ecf20Sopenharmony_ci} 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_ci/** 738c2ecf20Sopenharmony_ci * ice_alloc_ctrlq_sq_ring - Allocate Control Transmit Queue (ATQ) rings 748c2ecf20Sopenharmony_ci * @hw: pointer to the hardware structure 758c2ecf20Sopenharmony_ci * @cq: pointer to the specific Control queue 768c2ecf20Sopenharmony_ci */ 778c2ecf20Sopenharmony_cistatic enum ice_status 788c2ecf20Sopenharmony_ciice_alloc_ctrlq_sq_ring(struct ice_hw *hw, struct ice_ctl_q_info *cq) 798c2ecf20Sopenharmony_ci{ 808c2ecf20Sopenharmony_ci size_t size = cq->num_sq_entries * sizeof(struct ice_aq_desc); 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_ci cq->sq.desc_buf.va = dmam_alloc_coherent(ice_hw_to_dev(hw), size, 838c2ecf20Sopenharmony_ci &cq->sq.desc_buf.pa, 848c2ecf20Sopenharmony_ci GFP_KERNEL | __GFP_ZERO); 858c2ecf20Sopenharmony_ci if (!cq->sq.desc_buf.va) 868c2ecf20Sopenharmony_ci return ICE_ERR_NO_MEMORY; 878c2ecf20Sopenharmony_ci cq->sq.desc_buf.size = size; 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_ci cq->sq.cmd_buf = devm_kcalloc(ice_hw_to_dev(hw), cq->num_sq_entries, 908c2ecf20Sopenharmony_ci sizeof(struct ice_sq_cd), GFP_KERNEL); 918c2ecf20Sopenharmony_ci if (!cq->sq.cmd_buf) { 928c2ecf20Sopenharmony_ci dmam_free_coherent(ice_hw_to_dev(hw), cq->sq.desc_buf.size, 938c2ecf20Sopenharmony_ci cq->sq.desc_buf.va, cq->sq.desc_buf.pa); 948c2ecf20Sopenharmony_ci cq->sq.desc_buf.va = NULL; 958c2ecf20Sopenharmony_ci cq->sq.desc_buf.pa = 0; 968c2ecf20Sopenharmony_ci cq->sq.desc_buf.size = 0; 978c2ecf20Sopenharmony_ci return ICE_ERR_NO_MEMORY; 988c2ecf20Sopenharmony_ci } 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_ci return 0; 1018c2ecf20Sopenharmony_ci} 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_ci/** 1048c2ecf20Sopenharmony_ci * ice_alloc_ctrlq_rq_ring - Allocate Control Receive Queue (ARQ) rings 1058c2ecf20Sopenharmony_ci * @hw: pointer to the hardware structure 1068c2ecf20Sopenharmony_ci * @cq: pointer to the specific Control queue 1078c2ecf20Sopenharmony_ci */ 1088c2ecf20Sopenharmony_cistatic enum ice_status 1098c2ecf20Sopenharmony_ciice_alloc_ctrlq_rq_ring(struct ice_hw *hw, struct ice_ctl_q_info *cq) 1108c2ecf20Sopenharmony_ci{ 1118c2ecf20Sopenharmony_ci size_t size = cq->num_rq_entries * sizeof(struct ice_aq_desc); 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_ci cq->rq.desc_buf.va = dmam_alloc_coherent(ice_hw_to_dev(hw), size, 1148c2ecf20Sopenharmony_ci &cq->rq.desc_buf.pa, 1158c2ecf20Sopenharmony_ci GFP_KERNEL | __GFP_ZERO); 1168c2ecf20Sopenharmony_ci if (!cq->rq.desc_buf.va) 1178c2ecf20Sopenharmony_ci return ICE_ERR_NO_MEMORY; 1188c2ecf20Sopenharmony_ci cq->rq.desc_buf.size = size; 1198c2ecf20Sopenharmony_ci return 0; 1208c2ecf20Sopenharmony_ci} 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_ci/** 1238c2ecf20Sopenharmony_ci * ice_free_cq_ring - Free control queue ring 1248c2ecf20Sopenharmony_ci * @hw: pointer to the hardware structure 1258c2ecf20Sopenharmony_ci * @ring: pointer to the specific control queue ring 1268c2ecf20Sopenharmony_ci * 1278c2ecf20Sopenharmony_ci * This assumes the posted buffers have already been cleaned 1288c2ecf20Sopenharmony_ci * and de-allocated 1298c2ecf20Sopenharmony_ci */ 1308c2ecf20Sopenharmony_cistatic void ice_free_cq_ring(struct ice_hw *hw, struct ice_ctl_q_ring *ring) 1318c2ecf20Sopenharmony_ci{ 1328c2ecf20Sopenharmony_ci dmam_free_coherent(ice_hw_to_dev(hw), ring->desc_buf.size, 1338c2ecf20Sopenharmony_ci ring->desc_buf.va, ring->desc_buf.pa); 1348c2ecf20Sopenharmony_ci ring->desc_buf.va = NULL; 1358c2ecf20Sopenharmony_ci ring->desc_buf.pa = 0; 1368c2ecf20Sopenharmony_ci ring->desc_buf.size = 0; 1378c2ecf20Sopenharmony_ci} 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_ci/** 1408c2ecf20Sopenharmony_ci * ice_alloc_rq_bufs - Allocate pre-posted buffers for the ARQ 1418c2ecf20Sopenharmony_ci * @hw: pointer to the hardware structure 1428c2ecf20Sopenharmony_ci * @cq: pointer to the specific Control queue 1438c2ecf20Sopenharmony_ci */ 1448c2ecf20Sopenharmony_cistatic enum ice_status 1458c2ecf20Sopenharmony_ciice_alloc_rq_bufs(struct ice_hw *hw, struct ice_ctl_q_info *cq) 1468c2ecf20Sopenharmony_ci{ 1478c2ecf20Sopenharmony_ci int i; 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_ci /* We'll be allocating the buffer info memory first, then we can 1508c2ecf20Sopenharmony_ci * allocate the mapped buffers for the event processing 1518c2ecf20Sopenharmony_ci */ 1528c2ecf20Sopenharmony_ci cq->rq.dma_head = devm_kcalloc(ice_hw_to_dev(hw), cq->num_rq_entries, 1538c2ecf20Sopenharmony_ci sizeof(cq->rq.desc_buf), GFP_KERNEL); 1548c2ecf20Sopenharmony_ci if (!cq->rq.dma_head) 1558c2ecf20Sopenharmony_ci return ICE_ERR_NO_MEMORY; 1568c2ecf20Sopenharmony_ci cq->rq.r.rq_bi = (struct ice_dma_mem *)cq->rq.dma_head; 1578c2ecf20Sopenharmony_ci 1588c2ecf20Sopenharmony_ci /* allocate the mapped buffers */ 1598c2ecf20Sopenharmony_ci for (i = 0; i < cq->num_rq_entries; i++) { 1608c2ecf20Sopenharmony_ci struct ice_aq_desc *desc; 1618c2ecf20Sopenharmony_ci struct ice_dma_mem *bi; 1628c2ecf20Sopenharmony_ci 1638c2ecf20Sopenharmony_ci bi = &cq->rq.r.rq_bi[i]; 1648c2ecf20Sopenharmony_ci bi->va = dmam_alloc_coherent(ice_hw_to_dev(hw), 1658c2ecf20Sopenharmony_ci cq->rq_buf_size, &bi->pa, 1668c2ecf20Sopenharmony_ci GFP_KERNEL | __GFP_ZERO); 1678c2ecf20Sopenharmony_ci if (!bi->va) 1688c2ecf20Sopenharmony_ci goto unwind_alloc_rq_bufs; 1698c2ecf20Sopenharmony_ci bi->size = cq->rq_buf_size; 1708c2ecf20Sopenharmony_ci 1718c2ecf20Sopenharmony_ci /* now configure the descriptors for use */ 1728c2ecf20Sopenharmony_ci desc = ICE_CTL_Q_DESC(cq->rq, i); 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_ci desc->flags = cpu_to_le16(ICE_AQ_FLAG_BUF); 1758c2ecf20Sopenharmony_ci if (cq->rq_buf_size > ICE_AQ_LG_BUF) 1768c2ecf20Sopenharmony_ci desc->flags |= cpu_to_le16(ICE_AQ_FLAG_LB); 1778c2ecf20Sopenharmony_ci desc->opcode = 0; 1788c2ecf20Sopenharmony_ci /* This is in accordance with Admin queue design, there is no 1798c2ecf20Sopenharmony_ci * register for buffer size configuration 1808c2ecf20Sopenharmony_ci */ 1818c2ecf20Sopenharmony_ci desc->datalen = cpu_to_le16(bi->size); 1828c2ecf20Sopenharmony_ci desc->retval = 0; 1838c2ecf20Sopenharmony_ci desc->cookie_high = 0; 1848c2ecf20Sopenharmony_ci desc->cookie_low = 0; 1858c2ecf20Sopenharmony_ci desc->params.generic.addr_high = 1868c2ecf20Sopenharmony_ci cpu_to_le32(upper_32_bits(bi->pa)); 1878c2ecf20Sopenharmony_ci desc->params.generic.addr_low = 1888c2ecf20Sopenharmony_ci cpu_to_le32(lower_32_bits(bi->pa)); 1898c2ecf20Sopenharmony_ci desc->params.generic.param0 = 0; 1908c2ecf20Sopenharmony_ci desc->params.generic.param1 = 0; 1918c2ecf20Sopenharmony_ci } 1928c2ecf20Sopenharmony_ci return 0; 1938c2ecf20Sopenharmony_ci 1948c2ecf20Sopenharmony_ciunwind_alloc_rq_bufs: 1958c2ecf20Sopenharmony_ci /* don't try to free the one that failed... */ 1968c2ecf20Sopenharmony_ci i--; 1978c2ecf20Sopenharmony_ci for (; i >= 0; i--) { 1988c2ecf20Sopenharmony_ci dmam_free_coherent(ice_hw_to_dev(hw), cq->rq.r.rq_bi[i].size, 1998c2ecf20Sopenharmony_ci cq->rq.r.rq_bi[i].va, cq->rq.r.rq_bi[i].pa); 2008c2ecf20Sopenharmony_ci cq->rq.r.rq_bi[i].va = NULL; 2018c2ecf20Sopenharmony_ci cq->rq.r.rq_bi[i].pa = 0; 2028c2ecf20Sopenharmony_ci cq->rq.r.rq_bi[i].size = 0; 2038c2ecf20Sopenharmony_ci } 2048c2ecf20Sopenharmony_ci cq->rq.r.rq_bi = NULL; 2058c2ecf20Sopenharmony_ci devm_kfree(ice_hw_to_dev(hw), cq->rq.dma_head); 2068c2ecf20Sopenharmony_ci cq->rq.dma_head = NULL; 2078c2ecf20Sopenharmony_ci 2088c2ecf20Sopenharmony_ci return ICE_ERR_NO_MEMORY; 2098c2ecf20Sopenharmony_ci} 2108c2ecf20Sopenharmony_ci 2118c2ecf20Sopenharmony_ci/** 2128c2ecf20Sopenharmony_ci * ice_alloc_sq_bufs - Allocate empty buffer structs for the ATQ 2138c2ecf20Sopenharmony_ci * @hw: pointer to the hardware structure 2148c2ecf20Sopenharmony_ci * @cq: pointer to the specific Control queue 2158c2ecf20Sopenharmony_ci */ 2168c2ecf20Sopenharmony_cistatic enum ice_status 2178c2ecf20Sopenharmony_ciice_alloc_sq_bufs(struct ice_hw *hw, struct ice_ctl_q_info *cq) 2188c2ecf20Sopenharmony_ci{ 2198c2ecf20Sopenharmony_ci int i; 2208c2ecf20Sopenharmony_ci 2218c2ecf20Sopenharmony_ci /* No mapped memory needed yet, just the buffer info structures */ 2228c2ecf20Sopenharmony_ci cq->sq.dma_head = devm_kcalloc(ice_hw_to_dev(hw), cq->num_sq_entries, 2238c2ecf20Sopenharmony_ci sizeof(cq->sq.desc_buf), GFP_KERNEL); 2248c2ecf20Sopenharmony_ci if (!cq->sq.dma_head) 2258c2ecf20Sopenharmony_ci return ICE_ERR_NO_MEMORY; 2268c2ecf20Sopenharmony_ci cq->sq.r.sq_bi = (struct ice_dma_mem *)cq->sq.dma_head; 2278c2ecf20Sopenharmony_ci 2288c2ecf20Sopenharmony_ci /* allocate the mapped buffers */ 2298c2ecf20Sopenharmony_ci for (i = 0; i < cq->num_sq_entries; i++) { 2308c2ecf20Sopenharmony_ci struct ice_dma_mem *bi; 2318c2ecf20Sopenharmony_ci 2328c2ecf20Sopenharmony_ci bi = &cq->sq.r.sq_bi[i]; 2338c2ecf20Sopenharmony_ci bi->va = dmam_alloc_coherent(ice_hw_to_dev(hw), 2348c2ecf20Sopenharmony_ci cq->sq_buf_size, &bi->pa, 2358c2ecf20Sopenharmony_ci GFP_KERNEL | __GFP_ZERO); 2368c2ecf20Sopenharmony_ci if (!bi->va) 2378c2ecf20Sopenharmony_ci goto unwind_alloc_sq_bufs; 2388c2ecf20Sopenharmony_ci bi->size = cq->sq_buf_size; 2398c2ecf20Sopenharmony_ci } 2408c2ecf20Sopenharmony_ci return 0; 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_ciunwind_alloc_sq_bufs: 2438c2ecf20Sopenharmony_ci /* don't try to free the one that failed... */ 2448c2ecf20Sopenharmony_ci i--; 2458c2ecf20Sopenharmony_ci for (; i >= 0; i--) { 2468c2ecf20Sopenharmony_ci dmam_free_coherent(ice_hw_to_dev(hw), cq->sq.r.sq_bi[i].size, 2478c2ecf20Sopenharmony_ci cq->sq.r.sq_bi[i].va, cq->sq.r.sq_bi[i].pa); 2488c2ecf20Sopenharmony_ci cq->sq.r.sq_bi[i].va = NULL; 2498c2ecf20Sopenharmony_ci cq->sq.r.sq_bi[i].pa = 0; 2508c2ecf20Sopenharmony_ci cq->sq.r.sq_bi[i].size = 0; 2518c2ecf20Sopenharmony_ci } 2528c2ecf20Sopenharmony_ci cq->sq.r.sq_bi = NULL; 2538c2ecf20Sopenharmony_ci devm_kfree(ice_hw_to_dev(hw), cq->sq.dma_head); 2548c2ecf20Sopenharmony_ci cq->sq.dma_head = NULL; 2558c2ecf20Sopenharmony_ci 2568c2ecf20Sopenharmony_ci return ICE_ERR_NO_MEMORY; 2578c2ecf20Sopenharmony_ci} 2588c2ecf20Sopenharmony_ci 2598c2ecf20Sopenharmony_cistatic enum ice_status 2608c2ecf20Sopenharmony_ciice_cfg_cq_regs(struct ice_hw *hw, struct ice_ctl_q_ring *ring, u16 num_entries) 2618c2ecf20Sopenharmony_ci{ 2628c2ecf20Sopenharmony_ci /* Clear Head and Tail */ 2638c2ecf20Sopenharmony_ci wr32(hw, ring->head, 0); 2648c2ecf20Sopenharmony_ci wr32(hw, ring->tail, 0); 2658c2ecf20Sopenharmony_ci 2668c2ecf20Sopenharmony_ci /* set starting point */ 2678c2ecf20Sopenharmony_ci wr32(hw, ring->len, (num_entries | ring->len_ena_mask)); 2688c2ecf20Sopenharmony_ci wr32(hw, ring->bal, lower_32_bits(ring->desc_buf.pa)); 2698c2ecf20Sopenharmony_ci wr32(hw, ring->bah, upper_32_bits(ring->desc_buf.pa)); 2708c2ecf20Sopenharmony_ci 2718c2ecf20Sopenharmony_ci /* Check one register to verify that config was applied */ 2728c2ecf20Sopenharmony_ci if (rd32(hw, ring->bal) != lower_32_bits(ring->desc_buf.pa)) 2738c2ecf20Sopenharmony_ci return ICE_ERR_AQ_ERROR; 2748c2ecf20Sopenharmony_ci 2758c2ecf20Sopenharmony_ci return 0; 2768c2ecf20Sopenharmony_ci} 2778c2ecf20Sopenharmony_ci 2788c2ecf20Sopenharmony_ci/** 2798c2ecf20Sopenharmony_ci * ice_cfg_sq_regs - configure Control ATQ registers 2808c2ecf20Sopenharmony_ci * @hw: pointer to the hardware structure 2818c2ecf20Sopenharmony_ci * @cq: pointer to the specific Control queue 2828c2ecf20Sopenharmony_ci * 2838c2ecf20Sopenharmony_ci * Configure base address and length registers for the transmit queue 2848c2ecf20Sopenharmony_ci */ 2858c2ecf20Sopenharmony_cistatic enum ice_status 2868c2ecf20Sopenharmony_ciice_cfg_sq_regs(struct ice_hw *hw, struct ice_ctl_q_info *cq) 2878c2ecf20Sopenharmony_ci{ 2888c2ecf20Sopenharmony_ci return ice_cfg_cq_regs(hw, &cq->sq, cq->num_sq_entries); 2898c2ecf20Sopenharmony_ci} 2908c2ecf20Sopenharmony_ci 2918c2ecf20Sopenharmony_ci/** 2928c2ecf20Sopenharmony_ci * ice_cfg_rq_regs - configure Control ARQ register 2938c2ecf20Sopenharmony_ci * @hw: pointer to the hardware structure 2948c2ecf20Sopenharmony_ci * @cq: pointer to the specific Control queue 2958c2ecf20Sopenharmony_ci * 2968c2ecf20Sopenharmony_ci * Configure base address and length registers for the receive (event queue) 2978c2ecf20Sopenharmony_ci */ 2988c2ecf20Sopenharmony_cistatic enum ice_status 2998c2ecf20Sopenharmony_ciice_cfg_rq_regs(struct ice_hw *hw, struct ice_ctl_q_info *cq) 3008c2ecf20Sopenharmony_ci{ 3018c2ecf20Sopenharmony_ci enum ice_status status; 3028c2ecf20Sopenharmony_ci 3038c2ecf20Sopenharmony_ci status = ice_cfg_cq_regs(hw, &cq->rq, cq->num_rq_entries); 3048c2ecf20Sopenharmony_ci if (status) 3058c2ecf20Sopenharmony_ci return status; 3068c2ecf20Sopenharmony_ci 3078c2ecf20Sopenharmony_ci /* Update tail in the HW to post pre-allocated buffers */ 3088c2ecf20Sopenharmony_ci wr32(hw, cq->rq.tail, (u32)(cq->num_rq_entries - 1)); 3098c2ecf20Sopenharmony_ci 3108c2ecf20Sopenharmony_ci return 0; 3118c2ecf20Sopenharmony_ci} 3128c2ecf20Sopenharmony_ci 3138c2ecf20Sopenharmony_ci#define ICE_FREE_CQ_BUFS(hw, qi, ring) \ 3148c2ecf20Sopenharmony_cido { \ 3158c2ecf20Sopenharmony_ci /* free descriptors */ \ 3168c2ecf20Sopenharmony_ci if ((qi)->ring.r.ring##_bi) { \ 3178c2ecf20Sopenharmony_ci int i; \ 3188c2ecf20Sopenharmony_ci \ 3198c2ecf20Sopenharmony_ci for (i = 0; i < (qi)->num_##ring##_entries; i++) \ 3208c2ecf20Sopenharmony_ci if ((qi)->ring.r.ring##_bi[i].pa) { \ 3218c2ecf20Sopenharmony_ci dmam_free_coherent(ice_hw_to_dev(hw), \ 3228c2ecf20Sopenharmony_ci (qi)->ring.r.ring##_bi[i].size, \ 3238c2ecf20Sopenharmony_ci (qi)->ring.r.ring##_bi[i].va, \ 3248c2ecf20Sopenharmony_ci (qi)->ring.r.ring##_bi[i].pa); \ 3258c2ecf20Sopenharmony_ci (qi)->ring.r.ring##_bi[i].va = NULL;\ 3268c2ecf20Sopenharmony_ci (qi)->ring.r.ring##_bi[i].pa = 0;\ 3278c2ecf20Sopenharmony_ci (qi)->ring.r.ring##_bi[i].size = 0;\ 3288c2ecf20Sopenharmony_ci } \ 3298c2ecf20Sopenharmony_ci } \ 3308c2ecf20Sopenharmony_ci /* free the buffer info list */ \ 3318c2ecf20Sopenharmony_ci if ((qi)->ring.cmd_buf) \ 3328c2ecf20Sopenharmony_ci devm_kfree(ice_hw_to_dev(hw), (qi)->ring.cmd_buf); \ 3338c2ecf20Sopenharmony_ci /* free DMA head */ \ 3348c2ecf20Sopenharmony_ci devm_kfree(ice_hw_to_dev(hw), (qi)->ring.dma_head); \ 3358c2ecf20Sopenharmony_ci} while (0) 3368c2ecf20Sopenharmony_ci 3378c2ecf20Sopenharmony_ci/** 3388c2ecf20Sopenharmony_ci * ice_init_sq - main initialization routine for Control ATQ 3398c2ecf20Sopenharmony_ci * @hw: pointer to the hardware structure 3408c2ecf20Sopenharmony_ci * @cq: pointer to the specific Control queue 3418c2ecf20Sopenharmony_ci * 3428c2ecf20Sopenharmony_ci * This is the main initialization routine for the Control Send Queue 3438c2ecf20Sopenharmony_ci * Prior to calling this function, the driver *MUST* set the following fields 3448c2ecf20Sopenharmony_ci * in the cq->structure: 3458c2ecf20Sopenharmony_ci * - cq->num_sq_entries 3468c2ecf20Sopenharmony_ci * - cq->sq_buf_size 3478c2ecf20Sopenharmony_ci * 3488c2ecf20Sopenharmony_ci * Do *NOT* hold the lock when calling this as the memory allocation routines 3498c2ecf20Sopenharmony_ci * called are not going to be atomic context safe 3508c2ecf20Sopenharmony_ci */ 3518c2ecf20Sopenharmony_cistatic enum ice_status ice_init_sq(struct ice_hw *hw, struct ice_ctl_q_info *cq) 3528c2ecf20Sopenharmony_ci{ 3538c2ecf20Sopenharmony_ci enum ice_status ret_code; 3548c2ecf20Sopenharmony_ci 3558c2ecf20Sopenharmony_ci if (cq->sq.count > 0) { 3568c2ecf20Sopenharmony_ci /* queue already initialized */ 3578c2ecf20Sopenharmony_ci ret_code = ICE_ERR_NOT_READY; 3588c2ecf20Sopenharmony_ci goto init_ctrlq_exit; 3598c2ecf20Sopenharmony_ci } 3608c2ecf20Sopenharmony_ci 3618c2ecf20Sopenharmony_ci /* verify input for valid configuration */ 3628c2ecf20Sopenharmony_ci if (!cq->num_sq_entries || !cq->sq_buf_size) { 3638c2ecf20Sopenharmony_ci ret_code = ICE_ERR_CFG; 3648c2ecf20Sopenharmony_ci goto init_ctrlq_exit; 3658c2ecf20Sopenharmony_ci } 3668c2ecf20Sopenharmony_ci 3678c2ecf20Sopenharmony_ci cq->sq.next_to_use = 0; 3688c2ecf20Sopenharmony_ci cq->sq.next_to_clean = 0; 3698c2ecf20Sopenharmony_ci 3708c2ecf20Sopenharmony_ci /* allocate the ring memory */ 3718c2ecf20Sopenharmony_ci ret_code = ice_alloc_ctrlq_sq_ring(hw, cq); 3728c2ecf20Sopenharmony_ci if (ret_code) 3738c2ecf20Sopenharmony_ci goto init_ctrlq_exit; 3748c2ecf20Sopenharmony_ci 3758c2ecf20Sopenharmony_ci /* allocate buffers in the rings */ 3768c2ecf20Sopenharmony_ci ret_code = ice_alloc_sq_bufs(hw, cq); 3778c2ecf20Sopenharmony_ci if (ret_code) 3788c2ecf20Sopenharmony_ci goto init_ctrlq_free_rings; 3798c2ecf20Sopenharmony_ci 3808c2ecf20Sopenharmony_ci /* initialize base registers */ 3818c2ecf20Sopenharmony_ci ret_code = ice_cfg_sq_regs(hw, cq); 3828c2ecf20Sopenharmony_ci if (ret_code) 3838c2ecf20Sopenharmony_ci goto init_ctrlq_free_rings; 3848c2ecf20Sopenharmony_ci 3858c2ecf20Sopenharmony_ci /* success! */ 3868c2ecf20Sopenharmony_ci cq->sq.count = cq->num_sq_entries; 3878c2ecf20Sopenharmony_ci goto init_ctrlq_exit; 3888c2ecf20Sopenharmony_ci 3898c2ecf20Sopenharmony_ciinit_ctrlq_free_rings: 3908c2ecf20Sopenharmony_ci ICE_FREE_CQ_BUFS(hw, cq, sq); 3918c2ecf20Sopenharmony_ci ice_free_cq_ring(hw, &cq->sq); 3928c2ecf20Sopenharmony_ci 3938c2ecf20Sopenharmony_ciinit_ctrlq_exit: 3948c2ecf20Sopenharmony_ci return ret_code; 3958c2ecf20Sopenharmony_ci} 3968c2ecf20Sopenharmony_ci 3978c2ecf20Sopenharmony_ci/** 3988c2ecf20Sopenharmony_ci * ice_init_rq - initialize ARQ 3998c2ecf20Sopenharmony_ci * @hw: pointer to the hardware structure 4008c2ecf20Sopenharmony_ci * @cq: pointer to the specific Control queue 4018c2ecf20Sopenharmony_ci * 4028c2ecf20Sopenharmony_ci * The main initialization routine for the Admin Receive (Event) Queue. 4038c2ecf20Sopenharmony_ci * Prior to calling this function, the driver *MUST* set the following fields 4048c2ecf20Sopenharmony_ci * in the cq->structure: 4058c2ecf20Sopenharmony_ci * - cq->num_rq_entries 4068c2ecf20Sopenharmony_ci * - cq->rq_buf_size 4078c2ecf20Sopenharmony_ci * 4088c2ecf20Sopenharmony_ci * Do *NOT* hold the lock when calling this as the memory allocation routines 4098c2ecf20Sopenharmony_ci * called are not going to be atomic context safe 4108c2ecf20Sopenharmony_ci */ 4118c2ecf20Sopenharmony_cistatic enum ice_status ice_init_rq(struct ice_hw *hw, struct ice_ctl_q_info *cq) 4128c2ecf20Sopenharmony_ci{ 4138c2ecf20Sopenharmony_ci enum ice_status ret_code; 4148c2ecf20Sopenharmony_ci 4158c2ecf20Sopenharmony_ci if (cq->rq.count > 0) { 4168c2ecf20Sopenharmony_ci /* queue already initialized */ 4178c2ecf20Sopenharmony_ci ret_code = ICE_ERR_NOT_READY; 4188c2ecf20Sopenharmony_ci goto init_ctrlq_exit; 4198c2ecf20Sopenharmony_ci } 4208c2ecf20Sopenharmony_ci 4218c2ecf20Sopenharmony_ci /* verify input for valid configuration */ 4228c2ecf20Sopenharmony_ci if (!cq->num_rq_entries || !cq->rq_buf_size) { 4238c2ecf20Sopenharmony_ci ret_code = ICE_ERR_CFG; 4248c2ecf20Sopenharmony_ci goto init_ctrlq_exit; 4258c2ecf20Sopenharmony_ci } 4268c2ecf20Sopenharmony_ci 4278c2ecf20Sopenharmony_ci cq->rq.next_to_use = 0; 4288c2ecf20Sopenharmony_ci cq->rq.next_to_clean = 0; 4298c2ecf20Sopenharmony_ci 4308c2ecf20Sopenharmony_ci /* allocate the ring memory */ 4318c2ecf20Sopenharmony_ci ret_code = ice_alloc_ctrlq_rq_ring(hw, cq); 4328c2ecf20Sopenharmony_ci if (ret_code) 4338c2ecf20Sopenharmony_ci goto init_ctrlq_exit; 4348c2ecf20Sopenharmony_ci 4358c2ecf20Sopenharmony_ci /* allocate buffers in the rings */ 4368c2ecf20Sopenharmony_ci ret_code = ice_alloc_rq_bufs(hw, cq); 4378c2ecf20Sopenharmony_ci if (ret_code) 4388c2ecf20Sopenharmony_ci goto init_ctrlq_free_rings; 4398c2ecf20Sopenharmony_ci 4408c2ecf20Sopenharmony_ci /* initialize base registers */ 4418c2ecf20Sopenharmony_ci ret_code = ice_cfg_rq_regs(hw, cq); 4428c2ecf20Sopenharmony_ci if (ret_code) 4438c2ecf20Sopenharmony_ci goto init_ctrlq_free_rings; 4448c2ecf20Sopenharmony_ci 4458c2ecf20Sopenharmony_ci /* success! */ 4468c2ecf20Sopenharmony_ci cq->rq.count = cq->num_rq_entries; 4478c2ecf20Sopenharmony_ci goto init_ctrlq_exit; 4488c2ecf20Sopenharmony_ci 4498c2ecf20Sopenharmony_ciinit_ctrlq_free_rings: 4508c2ecf20Sopenharmony_ci ICE_FREE_CQ_BUFS(hw, cq, rq); 4518c2ecf20Sopenharmony_ci ice_free_cq_ring(hw, &cq->rq); 4528c2ecf20Sopenharmony_ci 4538c2ecf20Sopenharmony_ciinit_ctrlq_exit: 4548c2ecf20Sopenharmony_ci return ret_code; 4558c2ecf20Sopenharmony_ci} 4568c2ecf20Sopenharmony_ci 4578c2ecf20Sopenharmony_ci/** 4588c2ecf20Sopenharmony_ci * ice_shutdown_sq - shutdown the Control ATQ 4598c2ecf20Sopenharmony_ci * @hw: pointer to the hardware structure 4608c2ecf20Sopenharmony_ci * @cq: pointer to the specific Control queue 4618c2ecf20Sopenharmony_ci * 4628c2ecf20Sopenharmony_ci * The main shutdown routine for the Control Transmit Queue 4638c2ecf20Sopenharmony_ci */ 4648c2ecf20Sopenharmony_cistatic enum ice_status 4658c2ecf20Sopenharmony_ciice_shutdown_sq(struct ice_hw *hw, struct ice_ctl_q_info *cq) 4668c2ecf20Sopenharmony_ci{ 4678c2ecf20Sopenharmony_ci enum ice_status ret_code = 0; 4688c2ecf20Sopenharmony_ci 4698c2ecf20Sopenharmony_ci mutex_lock(&cq->sq_lock); 4708c2ecf20Sopenharmony_ci 4718c2ecf20Sopenharmony_ci if (!cq->sq.count) { 4728c2ecf20Sopenharmony_ci ret_code = ICE_ERR_NOT_READY; 4738c2ecf20Sopenharmony_ci goto shutdown_sq_out; 4748c2ecf20Sopenharmony_ci } 4758c2ecf20Sopenharmony_ci 4768c2ecf20Sopenharmony_ci /* Stop firmware AdminQ processing */ 4778c2ecf20Sopenharmony_ci wr32(hw, cq->sq.head, 0); 4788c2ecf20Sopenharmony_ci wr32(hw, cq->sq.tail, 0); 4798c2ecf20Sopenharmony_ci wr32(hw, cq->sq.len, 0); 4808c2ecf20Sopenharmony_ci wr32(hw, cq->sq.bal, 0); 4818c2ecf20Sopenharmony_ci wr32(hw, cq->sq.bah, 0); 4828c2ecf20Sopenharmony_ci 4838c2ecf20Sopenharmony_ci cq->sq.count = 0; /* to indicate uninitialized queue */ 4848c2ecf20Sopenharmony_ci 4858c2ecf20Sopenharmony_ci /* free ring buffers and the ring itself */ 4868c2ecf20Sopenharmony_ci ICE_FREE_CQ_BUFS(hw, cq, sq); 4878c2ecf20Sopenharmony_ci ice_free_cq_ring(hw, &cq->sq); 4888c2ecf20Sopenharmony_ci 4898c2ecf20Sopenharmony_cishutdown_sq_out: 4908c2ecf20Sopenharmony_ci mutex_unlock(&cq->sq_lock); 4918c2ecf20Sopenharmony_ci return ret_code; 4928c2ecf20Sopenharmony_ci} 4938c2ecf20Sopenharmony_ci 4948c2ecf20Sopenharmony_ci/** 4958c2ecf20Sopenharmony_ci * ice_aq_ver_check - Check the reported AQ API version. 4968c2ecf20Sopenharmony_ci * @hw: pointer to the hardware structure 4978c2ecf20Sopenharmony_ci * 4988c2ecf20Sopenharmony_ci * Checks if the driver should load on a given AQ API version. 4998c2ecf20Sopenharmony_ci * 5008c2ecf20Sopenharmony_ci * Return: 'true' iff the driver should attempt to load. 'false' otherwise. 5018c2ecf20Sopenharmony_ci */ 5028c2ecf20Sopenharmony_cistatic bool ice_aq_ver_check(struct ice_hw *hw) 5038c2ecf20Sopenharmony_ci{ 5048c2ecf20Sopenharmony_ci if (hw->api_maj_ver > EXP_FW_API_VER_MAJOR) { 5058c2ecf20Sopenharmony_ci /* Major API version is newer than expected, don't load */ 5068c2ecf20Sopenharmony_ci dev_warn(ice_hw_to_dev(hw), 5078c2ecf20Sopenharmony_ci "The driver for the device stopped because the NVM image is newer than expected. You must install the most recent version of the network driver.\n"); 5088c2ecf20Sopenharmony_ci return false; 5098c2ecf20Sopenharmony_ci } else if (hw->api_maj_ver == EXP_FW_API_VER_MAJOR) { 5108c2ecf20Sopenharmony_ci if (hw->api_min_ver > (EXP_FW_API_VER_MINOR + 2)) 5118c2ecf20Sopenharmony_ci dev_info(ice_hw_to_dev(hw), 5128c2ecf20Sopenharmony_ci "The driver for the device detected a newer version of the NVM image than expected. Please install the most recent version of the network driver.\n"); 5138c2ecf20Sopenharmony_ci else if ((hw->api_min_ver + 2) < EXP_FW_API_VER_MINOR) 5148c2ecf20Sopenharmony_ci dev_info(ice_hw_to_dev(hw), 5158c2ecf20Sopenharmony_ci "The driver for the device detected an older version of the NVM image than expected. Please update the NVM image.\n"); 5168c2ecf20Sopenharmony_ci } else { 5178c2ecf20Sopenharmony_ci /* Major API version is older than expected, log a warning */ 5188c2ecf20Sopenharmony_ci dev_info(ice_hw_to_dev(hw), 5198c2ecf20Sopenharmony_ci "The driver for the device detected an older version of the NVM image than expected. Please update the NVM image.\n"); 5208c2ecf20Sopenharmony_ci } 5218c2ecf20Sopenharmony_ci return true; 5228c2ecf20Sopenharmony_ci} 5238c2ecf20Sopenharmony_ci 5248c2ecf20Sopenharmony_ci/** 5258c2ecf20Sopenharmony_ci * ice_shutdown_rq - shutdown Control ARQ 5268c2ecf20Sopenharmony_ci * @hw: pointer to the hardware structure 5278c2ecf20Sopenharmony_ci * @cq: pointer to the specific Control queue 5288c2ecf20Sopenharmony_ci * 5298c2ecf20Sopenharmony_ci * The main shutdown routine for the Control Receive Queue 5308c2ecf20Sopenharmony_ci */ 5318c2ecf20Sopenharmony_cistatic enum ice_status 5328c2ecf20Sopenharmony_ciice_shutdown_rq(struct ice_hw *hw, struct ice_ctl_q_info *cq) 5338c2ecf20Sopenharmony_ci{ 5348c2ecf20Sopenharmony_ci enum ice_status ret_code = 0; 5358c2ecf20Sopenharmony_ci 5368c2ecf20Sopenharmony_ci mutex_lock(&cq->rq_lock); 5378c2ecf20Sopenharmony_ci 5388c2ecf20Sopenharmony_ci if (!cq->rq.count) { 5398c2ecf20Sopenharmony_ci ret_code = ICE_ERR_NOT_READY; 5408c2ecf20Sopenharmony_ci goto shutdown_rq_out; 5418c2ecf20Sopenharmony_ci } 5428c2ecf20Sopenharmony_ci 5438c2ecf20Sopenharmony_ci /* Stop Control Queue processing */ 5448c2ecf20Sopenharmony_ci wr32(hw, cq->rq.head, 0); 5458c2ecf20Sopenharmony_ci wr32(hw, cq->rq.tail, 0); 5468c2ecf20Sopenharmony_ci wr32(hw, cq->rq.len, 0); 5478c2ecf20Sopenharmony_ci wr32(hw, cq->rq.bal, 0); 5488c2ecf20Sopenharmony_ci wr32(hw, cq->rq.bah, 0); 5498c2ecf20Sopenharmony_ci 5508c2ecf20Sopenharmony_ci /* set rq.count to 0 to indicate uninitialized queue */ 5518c2ecf20Sopenharmony_ci cq->rq.count = 0; 5528c2ecf20Sopenharmony_ci 5538c2ecf20Sopenharmony_ci /* free ring buffers and the ring itself */ 5548c2ecf20Sopenharmony_ci ICE_FREE_CQ_BUFS(hw, cq, rq); 5558c2ecf20Sopenharmony_ci ice_free_cq_ring(hw, &cq->rq); 5568c2ecf20Sopenharmony_ci 5578c2ecf20Sopenharmony_cishutdown_rq_out: 5588c2ecf20Sopenharmony_ci mutex_unlock(&cq->rq_lock); 5598c2ecf20Sopenharmony_ci return ret_code; 5608c2ecf20Sopenharmony_ci} 5618c2ecf20Sopenharmony_ci 5628c2ecf20Sopenharmony_ci/** 5638c2ecf20Sopenharmony_ci * ice_init_check_adminq - Check version for Admin Queue to know if its alive 5648c2ecf20Sopenharmony_ci * @hw: pointer to the hardware structure 5658c2ecf20Sopenharmony_ci */ 5668c2ecf20Sopenharmony_cistatic enum ice_status ice_init_check_adminq(struct ice_hw *hw) 5678c2ecf20Sopenharmony_ci{ 5688c2ecf20Sopenharmony_ci struct ice_ctl_q_info *cq = &hw->adminq; 5698c2ecf20Sopenharmony_ci enum ice_status status; 5708c2ecf20Sopenharmony_ci 5718c2ecf20Sopenharmony_ci status = ice_aq_get_fw_ver(hw, NULL); 5728c2ecf20Sopenharmony_ci if (status) 5738c2ecf20Sopenharmony_ci goto init_ctrlq_free_rq; 5748c2ecf20Sopenharmony_ci 5758c2ecf20Sopenharmony_ci if (!ice_aq_ver_check(hw)) { 5768c2ecf20Sopenharmony_ci status = ICE_ERR_FW_API_VER; 5778c2ecf20Sopenharmony_ci goto init_ctrlq_free_rq; 5788c2ecf20Sopenharmony_ci } 5798c2ecf20Sopenharmony_ci 5808c2ecf20Sopenharmony_ci return 0; 5818c2ecf20Sopenharmony_ci 5828c2ecf20Sopenharmony_ciinit_ctrlq_free_rq: 5838c2ecf20Sopenharmony_ci ice_shutdown_rq(hw, cq); 5848c2ecf20Sopenharmony_ci ice_shutdown_sq(hw, cq); 5858c2ecf20Sopenharmony_ci return status; 5868c2ecf20Sopenharmony_ci} 5878c2ecf20Sopenharmony_ci 5888c2ecf20Sopenharmony_ci/** 5898c2ecf20Sopenharmony_ci * ice_init_ctrlq - main initialization routine for any control Queue 5908c2ecf20Sopenharmony_ci * @hw: pointer to the hardware structure 5918c2ecf20Sopenharmony_ci * @q_type: specific Control queue type 5928c2ecf20Sopenharmony_ci * 5938c2ecf20Sopenharmony_ci * Prior to calling this function, the driver *MUST* set the following fields 5948c2ecf20Sopenharmony_ci * in the cq->structure: 5958c2ecf20Sopenharmony_ci * - cq->num_sq_entries 5968c2ecf20Sopenharmony_ci * - cq->num_rq_entries 5978c2ecf20Sopenharmony_ci * - cq->rq_buf_size 5988c2ecf20Sopenharmony_ci * - cq->sq_buf_size 5998c2ecf20Sopenharmony_ci * 6008c2ecf20Sopenharmony_ci * NOTE: this function does not initialize the controlq locks 6018c2ecf20Sopenharmony_ci */ 6028c2ecf20Sopenharmony_cistatic enum ice_status ice_init_ctrlq(struct ice_hw *hw, enum ice_ctl_q q_type) 6038c2ecf20Sopenharmony_ci{ 6048c2ecf20Sopenharmony_ci struct ice_ctl_q_info *cq; 6058c2ecf20Sopenharmony_ci enum ice_status ret_code; 6068c2ecf20Sopenharmony_ci 6078c2ecf20Sopenharmony_ci switch (q_type) { 6088c2ecf20Sopenharmony_ci case ICE_CTL_Q_ADMIN: 6098c2ecf20Sopenharmony_ci ice_adminq_init_regs(hw); 6108c2ecf20Sopenharmony_ci cq = &hw->adminq; 6118c2ecf20Sopenharmony_ci break; 6128c2ecf20Sopenharmony_ci case ICE_CTL_Q_MAILBOX: 6138c2ecf20Sopenharmony_ci ice_mailbox_init_regs(hw); 6148c2ecf20Sopenharmony_ci cq = &hw->mailboxq; 6158c2ecf20Sopenharmony_ci break; 6168c2ecf20Sopenharmony_ci default: 6178c2ecf20Sopenharmony_ci return ICE_ERR_PARAM; 6188c2ecf20Sopenharmony_ci } 6198c2ecf20Sopenharmony_ci cq->qtype = q_type; 6208c2ecf20Sopenharmony_ci 6218c2ecf20Sopenharmony_ci /* verify input for valid configuration */ 6228c2ecf20Sopenharmony_ci if (!cq->num_rq_entries || !cq->num_sq_entries || 6238c2ecf20Sopenharmony_ci !cq->rq_buf_size || !cq->sq_buf_size) { 6248c2ecf20Sopenharmony_ci return ICE_ERR_CFG; 6258c2ecf20Sopenharmony_ci } 6268c2ecf20Sopenharmony_ci 6278c2ecf20Sopenharmony_ci /* setup SQ command write back timeout */ 6288c2ecf20Sopenharmony_ci cq->sq_cmd_timeout = ICE_CTL_Q_SQ_CMD_TIMEOUT; 6298c2ecf20Sopenharmony_ci 6308c2ecf20Sopenharmony_ci /* allocate the ATQ */ 6318c2ecf20Sopenharmony_ci ret_code = ice_init_sq(hw, cq); 6328c2ecf20Sopenharmony_ci if (ret_code) 6338c2ecf20Sopenharmony_ci return ret_code; 6348c2ecf20Sopenharmony_ci 6358c2ecf20Sopenharmony_ci /* allocate the ARQ */ 6368c2ecf20Sopenharmony_ci ret_code = ice_init_rq(hw, cq); 6378c2ecf20Sopenharmony_ci if (ret_code) 6388c2ecf20Sopenharmony_ci goto init_ctrlq_free_sq; 6398c2ecf20Sopenharmony_ci 6408c2ecf20Sopenharmony_ci /* success! */ 6418c2ecf20Sopenharmony_ci return 0; 6428c2ecf20Sopenharmony_ci 6438c2ecf20Sopenharmony_ciinit_ctrlq_free_sq: 6448c2ecf20Sopenharmony_ci ice_shutdown_sq(hw, cq); 6458c2ecf20Sopenharmony_ci return ret_code; 6468c2ecf20Sopenharmony_ci} 6478c2ecf20Sopenharmony_ci 6488c2ecf20Sopenharmony_ci/** 6498c2ecf20Sopenharmony_ci * ice_shutdown_ctrlq - shutdown routine for any control queue 6508c2ecf20Sopenharmony_ci * @hw: pointer to the hardware structure 6518c2ecf20Sopenharmony_ci * @q_type: specific Control queue type 6528c2ecf20Sopenharmony_ci * 6538c2ecf20Sopenharmony_ci * NOTE: this function does not destroy the control queue locks. 6548c2ecf20Sopenharmony_ci */ 6558c2ecf20Sopenharmony_cistatic void ice_shutdown_ctrlq(struct ice_hw *hw, enum ice_ctl_q q_type) 6568c2ecf20Sopenharmony_ci{ 6578c2ecf20Sopenharmony_ci struct ice_ctl_q_info *cq; 6588c2ecf20Sopenharmony_ci 6598c2ecf20Sopenharmony_ci switch (q_type) { 6608c2ecf20Sopenharmony_ci case ICE_CTL_Q_ADMIN: 6618c2ecf20Sopenharmony_ci cq = &hw->adminq; 6628c2ecf20Sopenharmony_ci if (ice_check_sq_alive(hw, cq)) 6638c2ecf20Sopenharmony_ci ice_aq_q_shutdown(hw, true); 6648c2ecf20Sopenharmony_ci break; 6658c2ecf20Sopenharmony_ci case ICE_CTL_Q_MAILBOX: 6668c2ecf20Sopenharmony_ci cq = &hw->mailboxq; 6678c2ecf20Sopenharmony_ci break; 6688c2ecf20Sopenharmony_ci default: 6698c2ecf20Sopenharmony_ci return; 6708c2ecf20Sopenharmony_ci } 6718c2ecf20Sopenharmony_ci 6728c2ecf20Sopenharmony_ci ice_shutdown_sq(hw, cq); 6738c2ecf20Sopenharmony_ci ice_shutdown_rq(hw, cq); 6748c2ecf20Sopenharmony_ci} 6758c2ecf20Sopenharmony_ci 6768c2ecf20Sopenharmony_ci/** 6778c2ecf20Sopenharmony_ci * ice_shutdown_all_ctrlq - shutdown routine for all control queues 6788c2ecf20Sopenharmony_ci * @hw: pointer to the hardware structure 6798c2ecf20Sopenharmony_ci * 6808c2ecf20Sopenharmony_ci * NOTE: this function does not destroy the control queue locks. The driver 6818c2ecf20Sopenharmony_ci * may call this at runtime to shutdown and later restart control queues, such 6828c2ecf20Sopenharmony_ci * as in response to a reset event. 6838c2ecf20Sopenharmony_ci */ 6848c2ecf20Sopenharmony_civoid ice_shutdown_all_ctrlq(struct ice_hw *hw) 6858c2ecf20Sopenharmony_ci{ 6868c2ecf20Sopenharmony_ci /* Shutdown FW admin queue */ 6878c2ecf20Sopenharmony_ci ice_shutdown_ctrlq(hw, ICE_CTL_Q_ADMIN); 6888c2ecf20Sopenharmony_ci /* Shutdown PF-VF Mailbox */ 6898c2ecf20Sopenharmony_ci ice_shutdown_ctrlq(hw, ICE_CTL_Q_MAILBOX); 6908c2ecf20Sopenharmony_ci} 6918c2ecf20Sopenharmony_ci 6928c2ecf20Sopenharmony_ci/** 6938c2ecf20Sopenharmony_ci * ice_init_all_ctrlq - main initialization routine for all control queues 6948c2ecf20Sopenharmony_ci * @hw: pointer to the hardware structure 6958c2ecf20Sopenharmony_ci * 6968c2ecf20Sopenharmony_ci * Prior to calling this function, the driver MUST* set the following fields 6978c2ecf20Sopenharmony_ci * in the cq->structure for all control queues: 6988c2ecf20Sopenharmony_ci * - cq->num_sq_entries 6998c2ecf20Sopenharmony_ci * - cq->num_rq_entries 7008c2ecf20Sopenharmony_ci * - cq->rq_buf_size 7018c2ecf20Sopenharmony_ci * - cq->sq_buf_size 7028c2ecf20Sopenharmony_ci * 7038c2ecf20Sopenharmony_ci * NOTE: this function does not initialize the controlq locks. 7048c2ecf20Sopenharmony_ci */ 7058c2ecf20Sopenharmony_cienum ice_status ice_init_all_ctrlq(struct ice_hw *hw) 7068c2ecf20Sopenharmony_ci{ 7078c2ecf20Sopenharmony_ci enum ice_status status; 7088c2ecf20Sopenharmony_ci u32 retry = 0; 7098c2ecf20Sopenharmony_ci 7108c2ecf20Sopenharmony_ci /* Init FW admin queue */ 7118c2ecf20Sopenharmony_ci do { 7128c2ecf20Sopenharmony_ci status = ice_init_ctrlq(hw, ICE_CTL_Q_ADMIN); 7138c2ecf20Sopenharmony_ci if (status) 7148c2ecf20Sopenharmony_ci return status; 7158c2ecf20Sopenharmony_ci 7168c2ecf20Sopenharmony_ci status = ice_init_check_adminq(hw); 7178c2ecf20Sopenharmony_ci if (status != ICE_ERR_AQ_FW_CRITICAL) 7188c2ecf20Sopenharmony_ci break; 7198c2ecf20Sopenharmony_ci 7208c2ecf20Sopenharmony_ci ice_debug(hw, ICE_DBG_AQ_MSG, 7218c2ecf20Sopenharmony_ci "Retry Admin Queue init due to FW critical error\n"); 7228c2ecf20Sopenharmony_ci ice_shutdown_ctrlq(hw, ICE_CTL_Q_ADMIN); 7238c2ecf20Sopenharmony_ci msleep(ICE_CTL_Q_ADMIN_INIT_MSEC); 7248c2ecf20Sopenharmony_ci } while (retry++ < ICE_CTL_Q_ADMIN_INIT_TIMEOUT); 7258c2ecf20Sopenharmony_ci 7268c2ecf20Sopenharmony_ci if (status) 7278c2ecf20Sopenharmony_ci return status; 7288c2ecf20Sopenharmony_ci /* Init Mailbox queue */ 7298c2ecf20Sopenharmony_ci return ice_init_ctrlq(hw, ICE_CTL_Q_MAILBOX); 7308c2ecf20Sopenharmony_ci} 7318c2ecf20Sopenharmony_ci 7328c2ecf20Sopenharmony_ci/** 7338c2ecf20Sopenharmony_ci * ice_init_ctrlq_locks - Initialize locks for a control queue 7348c2ecf20Sopenharmony_ci * @cq: pointer to the control queue 7358c2ecf20Sopenharmony_ci * 7368c2ecf20Sopenharmony_ci * Initializes the send and receive queue locks for a given control queue. 7378c2ecf20Sopenharmony_ci */ 7388c2ecf20Sopenharmony_cistatic void ice_init_ctrlq_locks(struct ice_ctl_q_info *cq) 7398c2ecf20Sopenharmony_ci{ 7408c2ecf20Sopenharmony_ci mutex_init(&cq->sq_lock); 7418c2ecf20Sopenharmony_ci mutex_init(&cq->rq_lock); 7428c2ecf20Sopenharmony_ci} 7438c2ecf20Sopenharmony_ci 7448c2ecf20Sopenharmony_ci/** 7458c2ecf20Sopenharmony_ci * ice_create_all_ctrlq - main initialization routine for all control queues 7468c2ecf20Sopenharmony_ci * @hw: pointer to the hardware structure 7478c2ecf20Sopenharmony_ci * 7488c2ecf20Sopenharmony_ci * Prior to calling this function, the driver *MUST* set the following fields 7498c2ecf20Sopenharmony_ci * in the cq->structure for all control queues: 7508c2ecf20Sopenharmony_ci * - cq->num_sq_entries 7518c2ecf20Sopenharmony_ci * - cq->num_rq_entries 7528c2ecf20Sopenharmony_ci * - cq->rq_buf_size 7538c2ecf20Sopenharmony_ci * - cq->sq_buf_size 7548c2ecf20Sopenharmony_ci * 7558c2ecf20Sopenharmony_ci * This function creates all the control queue locks and then calls 7568c2ecf20Sopenharmony_ci * ice_init_all_ctrlq. It should be called once during driver load. If the 7578c2ecf20Sopenharmony_ci * driver needs to re-initialize control queues at run time it should call 7588c2ecf20Sopenharmony_ci * ice_init_all_ctrlq instead. 7598c2ecf20Sopenharmony_ci */ 7608c2ecf20Sopenharmony_cienum ice_status ice_create_all_ctrlq(struct ice_hw *hw) 7618c2ecf20Sopenharmony_ci{ 7628c2ecf20Sopenharmony_ci ice_init_ctrlq_locks(&hw->adminq); 7638c2ecf20Sopenharmony_ci ice_init_ctrlq_locks(&hw->mailboxq); 7648c2ecf20Sopenharmony_ci 7658c2ecf20Sopenharmony_ci return ice_init_all_ctrlq(hw); 7668c2ecf20Sopenharmony_ci} 7678c2ecf20Sopenharmony_ci 7688c2ecf20Sopenharmony_ci/** 7698c2ecf20Sopenharmony_ci * ice_destroy_ctrlq_locks - Destroy locks for a control queue 7708c2ecf20Sopenharmony_ci * @cq: pointer to the control queue 7718c2ecf20Sopenharmony_ci * 7728c2ecf20Sopenharmony_ci * Destroys the send and receive queue locks for a given control queue. 7738c2ecf20Sopenharmony_ci */ 7748c2ecf20Sopenharmony_cistatic void ice_destroy_ctrlq_locks(struct ice_ctl_q_info *cq) 7758c2ecf20Sopenharmony_ci{ 7768c2ecf20Sopenharmony_ci mutex_destroy(&cq->sq_lock); 7778c2ecf20Sopenharmony_ci mutex_destroy(&cq->rq_lock); 7788c2ecf20Sopenharmony_ci} 7798c2ecf20Sopenharmony_ci 7808c2ecf20Sopenharmony_ci/** 7818c2ecf20Sopenharmony_ci * ice_destroy_all_ctrlq - exit routine for all control queues 7828c2ecf20Sopenharmony_ci * @hw: pointer to the hardware structure 7838c2ecf20Sopenharmony_ci * 7848c2ecf20Sopenharmony_ci * This function shuts down all the control queues and then destroys the 7858c2ecf20Sopenharmony_ci * control queue locks. It should be called once during driver unload. The 7868c2ecf20Sopenharmony_ci * driver should call ice_shutdown_all_ctrlq if it needs to shut down and 7878c2ecf20Sopenharmony_ci * reinitialize control queues, such as in response to a reset event. 7888c2ecf20Sopenharmony_ci */ 7898c2ecf20Sopenharmony_civoid ice_destroy_all_ctrlq(struct ice_hw *hw) 7908c2ecf20Sopenharmony_ci{ 7918c2ecf20Sopenharmony_ci /* shut down all the control queues first */ 7928c2ecf20Sopenharmony_ci ice_shutdown_all_ctrlq(hw); 7938c2ecf20Sopenharmony_ci 7948c2ecf20Sopenharmony_ci ice_destroy_ctrlq_locks(&hw->adminq); 7958c2ecf20Sopenharmony_ci ice_destroy_ctrlq_locks(&hw->mailboxq); 7968c2ecf20Sopenharmony_ci} 7978c2ecf20Sopenharmony_ci 7988c2ecf20Sopenharmony_ci/** 7998c2ecf20Sopenharmony_ci * ice_clean_sq - cleans Admin send queue (ATQ) 8008c2ecf20Sopenharmony_ci * @hw: pointer to the hardware structure 8018c2ecf20Sopenharmony_ci * @cq: pointer to the specific Control queue 8028c2ecf20Sopenharmony_ci * 8038c2ecf20Sopenharmony_ci * returns the number of free desc 8048c2ecf20Sopenharmony_ci */ 8058c2ecf20Sopenharmony_cistatic u16 ice_clean_sq(struct ice_hw *hw, struct ice_ctl_q_info *cq) 8068c2ecf20Sopenharmony_ci{ 8078c2ecf20Sopenharmony_ci struct ice_ctl_q_ring *sq = &cq->sq; 8088c2ecf20Sopenharmony_ci u16 ntc = sq->next_to_clean; 8098c2ecf20Sopenharmony_ci struct ice_sq_cd *details; 8108c2ecf20Sopenharmony_ci struct ice_aq_desc *desc; 8118c2ecf20Sopenharmony_ci 8128c2ecf20Sopenharmony_ci desc = ICE_CTL_Q_DESC(*sq, ntc); 8138c2ecf20Sopenharmony_ci details = ICE_CTL_Q_DETAILS(*sq, ntc); 8148c2ecf20Sopenharmony_ci 8158c2ecf20Sopenharmony_ci while (rd32(hw, cq->sq.head) != ntc) { 8168c2ecf20Sopenharmony_ci ice_debug(hw, ICE_DBG_AQ_MSG, 8178c2ecf20Sopenharmony_ci "ntc %d head %d.\n", ntc, rd32(hw, cq->sq.head)); 8188c2ecf20Sopenharmony_ci memset(desc, 0, sizeof(*desc)); 8198c2ecf20Sopenharmony_ci memset(details, 0, sizeof(*details)); 8208c2ecf20Sopenharmony_ci ntc++; 8218c2ecf20Sopenharmony_ci if (ntc == sq->count) 8228c2ecf20Sopenharmony_ci ntc = 0; 8238c2ecf20Sopenharmony_ci desc = ICE_CTL_Q_DESC(*sq, ntc); 8248c2ecf20Sopenharmony_ci details = ICE_CTL_Q_DETAILS(*sq, ntc); 8258c2ecf20Sopenharmony_ci } 8268c2ecf20Sopenharmony_ci 8278c2ecf20Sopenharmony_ci sq->next_to_clean = ntc; 8288c2ecf20Sopenharmony_ci 8298c2ecf20Sopenharmony_ci return ICE_CTL_Q_DESC_UNUSED(sq); 8308c2ecf20Sopenharmony_ci} 8318c2ecf20Sopenharmony_ci 8328c2ecf20Sopenharmony_ci/** 8338c2ecf20Sopenharmony_ci * ice_debug_cq 8348c2ecf20Sopenharmony_ci * @hw: pointer to the hardware structure 8358c2ecf20Sopenharmony_ci * @desc: pointer to control queue descriptor 8368c2ecf20Sopenharmony_ci * @buf: pointer to command buffer 8378c2ecf20Sopenharmony_ci * @buf_len: max length of buf 8388c2ecf20Sopenharmony_ci * 8398c2ecf20Sopenharmony_ci * Dumps debug log about control command with descriptor contents. 8408c2ecf20Sopenharmony_ci */ 8418c2ecf20Sopenharmony_cistatic void ice_debug_cq(struct ice_hw *hw, void *desc, void *buf, u16 buf_len) 8428c2ecf20Sopenharmony_ci{ 8438c2ecf20Sopenharmony_ci struct ice_aq_desc *cq_desc = (struct ice_aq_desc *)desc; 8448c2ecf20Sopenharmony_ci u16 len; 8458c2ecf20Sopenharmony_ci 8468c2ecf20Sopenharmony_ci if (!IS_ENABLED(CONFIG_DYNAMIC_DEBUG) && 8478c2ecf20Sopenharmony_ci !((ICE_DBG_AQ_DESC | ICE_DBG_AQ_DESC_BUF) & hw->debug_mask)) 8488c2ecf20Sopenharmony_ci return; 8498c2ecf20Sopenharmony_ci 8508c2ecf20Sopenharmony_ci if (!desc) 8518c2ecf20Sopenharmony_ci return; 8528c2ecf20Sopenharmony_ci 8538c2ecf20Sopenharmony_ci len = le16_to_cpu(cq_desc->datalen); 8548c2ecf20Sopenharmony_ci 8558c2ecf20Sopenharmony_ci ice_debug(hw, ICE_DBG_AQ_DESC, 8568c2ecf20Sopenharmony_ci "CQ CMD: opcode 0x%04X, flags 0x%04X, datalen 0x%04X, retval 0x%04X\n", 8578c2ecf20Sopenharmony_ci le16_to_cpu(cq_desc->opcode), 8588c2ecf20Sopenharmony_ci le16_to_cpu(cq_desc->flags), 8598c2ecf20Sopenharmony_ci le16_to_cpu(cq_desc->datalen), le16_to_cpu(cq_desc->retval)); 8608c2ecf20Sopenharmony_ci ice_debug(hw, ICE_DBG_AQ_DESC, "\tcookie (h,l) 0x%08X 0x%08X\n", 8618c2ecf20Sopenharmony_ci le32_to_cpu(cq_desc->cookie_high), 8628c2ecf20Sopenharmony_ci le32_to_cpu(cq_desc->cookie_low)); 8638c2ecf20Sopenharmony_ci ice_debug(hw, ICE_DBG_AQ_DESC, "\tparam (0,1) 0x%08X 0x%08X\n", 8648c2ecf20Sopenharmony_ci le32_to_cpu(cq_desc->params.generic.param0), 8658c2ecf20Sopenharmony_ci le32_to_cpu(cq_desc->params.generic.param1)); 8668c2ecf20Sopenharmony_ci ice_debug(hw, ICE_DBG_AQ_DESC, "\taddr (h,l) 0x%08X 0x%08X\n", 8678c2ecf20Sopenharmony_ci le32_to_cpu(cq_desc->params.generic.addr_high), 8688c2ecf20Sopenharmony_ci le32_to_cpu(cq_desc->params.generic.addr_low)); 8698c2ecf20Sopenharmony_ci if (buf && cq_desc->datalen != 0) { 8708c2ecf20Sopenharmony_ci ice_debug(hw, ICE_DBG_AQ_DESC_BUF, "Buffer:\n"); 8718c2ecf20Sopenharmony_ci if (buf_len < len) 8728c2ecf20Sopenharmony_ci len = buf_len; 8738c2ecf20Sopenharmony_ci 8748c2ecf20Sopenharmony_ci ice_debug_array(hw, ICE_DBG_AQ_DESC_BUF, 16, 1, (u8 *)buf, len); 8758c2ecf20Sopenharmony_ci } 8768c2ecf20Sopenharmony_ci} 8778c2ecf20Sopenharmony_ci 8788c2ecf20Sopenharmony_ci/** 8798c2ecf20Sopenharmony_ci * ice_sq_done - check if FW has processed the Admin Send Queue (ATQ) 8808c2ecf20Sopenharmony_ci * @hw: pointer to the HW struct 8818c2ecf20Sopenharmony_ci * @cq: pointer to the specific Control queue 8828c2ecf20Sopenharmony_ci * 8838c2ecf20Sopenharmony_ci * Returns true if the firmware has processed all descriptors on the 8848c2ecf20Sopenharmony_ci * admin send queue. Returns false if there are still requests pending. 8858c2ecf20Sopenharmony_ci */ 8868c2ecf20Sopenharmony_cistatic bool ice_sq_done(struct ice_hw *hw, struct ice_ctl_q_info *cq) 8878c2ecf20Sopenharmony_ci{ 8888c2ecf20Sopenharmony_ci /* AQ designers suggest use of head for better 8898c2ecf20Sopenharmony_ci * timing reliability than DD bit 8908c2ecf20Sopenharmony_ci */ 8918c2ecf20Sopenharmony_ci return rd32(hw, cq->sq.head) == cq->sq.next_to_use; 8928c2ecf20Sopenharmony_ci} 8938c2ecf20Sopenharmony_ci 8948c2ecf20Sopenharmony_ci/** 8958c2ecf20Sopenharmony_ci * ice_sq_send_cmd - send command to Control Queue (ATQ) 8968c2ecf20Sopenharmony_ci * @hw: pointer to the HW struct 8978c2ecf20Sopenharmony_ci * @cq: pointer to the specific Control queue 8988c2ecf20Sopenharmony_ci * @desc: prefilled descriptor describing the command (non DMA mem) 8998c2ecf20Sopenharmony_ci * @buf: buffer to use for indirect commands (or NULL for direct commands) 9008c2ecf20Sopenharmony_ci * @buf_size: size of buffer for indirect commands (or 0 for direct commands) 9018c2ecf20Sopenharmony_ci * @cd: pointer to command details structure 9028c2ecf20Sopenharmony_ci * 9038c2ecf20Sopenharmony_ci * This is the main send command routine for the ATQ. It runs the queue, 9048c2ecf20Sopenharmony_ci * cleans the queue, etc. 9058c2ecf20Sopenharmony_ci */ 9068c2ecf20Sopenharmony_cienum ice_status 9078c2ecf20Sopenharmony_ciice_sq_send_cmd(struct ice_hw *hw, struct ice_ctl_q_info *cq, 9088c2ecf20Sopenharmony_ci struct ice_aq_desc *desc, void *buf, u16 buf_size, 9098c2ecf20Sopenharmony_ci struct ice_sq_cd *cd) 9108c2ecf20Sopenharmony_ci{ 9118c2ecf20Sopenharmony_ci struct ice_dma_mem *dma_buf = NULL; 9128c2ecf20Sopenharmony_ci struct ice_aq_desc *desc_on_ring; 9138c2ecf20Sopenharmony_ci bool cmd_completed = false; 9148c2ecf20Sopenharmony_ci enum ice_status status = 0; 9158c2ecf20Sopenharmony_ci struct ice_sq_cd *details; 9168c2ecf20Sopenharmony_ci u32 total_delay = 0; 9178c2ecf20Sopenharmony_ci u16 retval = 0; 9188c2ecf20Sopenharmony_ci u32 val = 0; 9198c2ecf20Sopenharmony_ci 9208c2ecf20Sopenharmony_ci /* if reset is in progress return a soft error */ 9218c2ecf20Sopenharmony_ci if (hw->reset_ongoing) 9228c2ecf20Sopenharmony_ci return ICE_ERR_RESET_ONGOING; 9238c2ecf20Sopenharmony_ci mutex_lock(&cq->sq_lock); 9248c2ecf20Sopenharmony_ci 9258c2ecf20Sopenharmony_ci cq->sq_last_status = ICE_AQ_RC_OK; 9268c2ecf20Sopenharmony_ci 9278c2ecf20Sopenharmony_ci if (!cq->sq.count) { 9288c2ecf20Sopenharmony_ci ice_debug(hw, ICE_DBG_AQ_MSG, 9298c2ecf20Sopenharmony_ci "Control Send queue not initialized.\n"); 9308c2ecf20Sopenharmony_ci status = ICE_ERR_AQ_EMPTY; 9318c2ecf20Sopenharmony_ci goto sq_send_command_error; 9328c2ecf20Sopenharmony_ci } 9338c2ecf20Sopenharmony_ci 9348c2ecf20Sopenharmony_ci if ((buf && !buf_size) || (!buf && buf_size)) { 9358c2ecf20Sopenharmony_ci status = ICE_ERR_PARAM; 9368c2ecf20Sopenharmony_ci goto sq_send_command_error; 9378c2ecf20Sopenharmony_ci } 9388c2ecf20Sopenharmony_ci 9398c2ecf20Sopenharmony_ci if (buf) { 9408c2ecf20Sopenharmony_ci if (buf_size > cq->sq_buf_size) { 9418c2ecf20Sopenharmony_ci ice_debug(hw, ICE_DBG_AQ_MSG, 9428c2ecf20Sopenharmony_ci "Invalid buffer size for Control Send queue: %d.\n", 9438c2ecf20Sopenharmony_ci buf_size); 9448c2ecf20Sopenharmony_ci status = ICE_ERR_INVAL_SIZE; 9458c2ecf20Sopenharmony_ci goto sq_send_command_error; 9468c2ecf20Sopenharmony_ci } 9478c2ecf20Sopenharmony_ci 9488c2ecf20Sopenharmony_ci desc->flags |= cpu_to_le16(ICE_AQ_FLAG_BUF); 9498c2ecf20Sopenharmony_ci if (buf_size > ICE_AQ_LG_BUF) 9508c2ecf20Sopenharmony_ci desc->flags |= cpu_to_le16(ICE_AQ_FLAG_LB); 9518c2ecf20Sopenharmony_ci } 9528c2ecf20Sopenharmony_ci 9538c2ecf20Sopenharmony_ci val = rd32(hw, cq->sq.head); 9548c2ecf20Sopenharmony_ci if (val >= cq->num_sq_entries) { 9558c2ecf20Sopenharmony_ci ice_debug(hw, ICE_DBG_AQ_MSG, 9568c2ecf20Sopenharmony_ci "head overrun at %d in the Control Send Queue ring\n", 9578c2ecf20Sopenharmony_ci val); 9588c2ecf20Sopenharmony_ci status = ICE_ERR_AQ_EMPTY; 9598c2ecf20Sopenharmony_ci goto sq_send_command_error; 9608c2ecf20Sopenharmony_ci } 9618c2ecf20Sopenharmony_ci 9628c2ecf20Sopenharmony_ci details = ICE_CTL_Q_DETAILS(cq->sq, cq->sq.next_to_use); 9638c2ecf20Sopenharmony_ci if (cd) 9648c2ecf20Sopenharmony_ci *details = *cd; 9658c2ecf20Sopenharmony_ci else 9668c2ecf20Sopenharmony_ci memset(details, 0, sizeof(*details)); 9678c2ecf20Sopenharmony_ci 9688c2ecf20Sopenharmony_ci /* Call clean and check queue available function to reclaim the 9698c2ecf20Sopenharmony_ci * descriptors that were processed by FW/MBX; the function returns the 9708c2ecf20Sopenharmony_ci * number of desc available. The clean function called here could be 9718c2ecf20Sopenharmony_ci * called in a separate thread in case of asynchronous completions. 9728c2ecf20Sopenharmony_ci */ 9738c2ecf20Sopenharmony_ci if (ice_clean_sq(hw, cq) == 0) { 9748c2ecf20Sopenharmony_ci ice_debug(hw, ICE_DBG_AQ_MSG, 9758c2ecf20Sopenharmony_ci "Error: Control Send Queue is full.\n"); 9768c2ecf20Sopenharmony_ci status = ICE_ERR_AQ_FULL; 9778c2ecf20Sopenharmony_ci goto sq_send_command_error; 9788c2ecf20Sopenharmony_ci } 9798c2ecf20Sopenharmony_ci 9808c2ecf20Sopenharmony_ci /* initialize the temp desc pointer with the right desc */ 9818c2ecf20Sopenharmony_ci desc_on_ring = ICE_CTL_Q_DESC(cq->sq, cq->sq.next_to_use); 9828c2ecf20Sopenharmony_ci 9838c2ecf20Sopenharmony_ci /* if the desc is available copy the temp desc to the right place */ 9848c2ecf20Sopenharmony_ci memcpy(desc_on_ring, desc, sizeof(*desc_on_ring)); 9858c2ecf20Sopenharmony_ci 9868c2ecf20Sopenharmony_ci /* if buf is not NULL assume indirect command */ 9878c2ecf20Sopenharmony_ci if (buf) { 9888c2ecf20Sopenharmony_ci dma_buf = &cq->sq.r.sq_bi[cq->sq.next_to_use]; 9898c2ecf20Sopenharmony_ci /* copy the user buf into the respective DMA buf */ 9908c2ecf20Sopenharmony_ci memcpy(dma_buf->va, buf, buf_size); 9918c2ecf20Sopenharmony_ci desc_on_ring->datalen = cpu_to_le16(buf_size); 9928c2ecf20Sopenharmony_ci 9938c2ecf20Sopenharmony_ci /* Update the address values in the desc with the pa value 9948c2ecf20Sopenharmony_ci * for respective buffer 9958c2ecf20Sopenharmony_ci */ 9968c2ecf20Sopenharmony_ci desc_on_ring->params.generic.addr_high = 9978c2ecf20Sopenharmony_ci cpu_to_le32(upper_32_bits(dma_buf->pa)); 9988c2ecf20Sopenharmony_ci desc_on_ring->params.generic.addr_low = 9998c2ecf20Sopenharmony_ci cpu_to_le32(lower_32_bits(dma_buf->pa)); 10008c2ecf20Sopenharmony_ci } 10018c2ecf20Sopenharmony_ci 10028c2ecf20Sopenharmony_ci /* Debug desc and buffer */ 10038c2ecf20Sopenharmony_ci ice_debug(hw, ICE_DBG_AQ_DESC, 10048c2ecf20Sopenharmony_ci "ATQ: Control Send queue desc and buffer:\n"); 10058c2ecf20Sopenharmony_ci 10068c2ecf20Sopenharmony_ci ice_debug_cq(hw, (void *)desc_on_ring, buf, buf_size); 10078c2ecf20Sopenharmony_ci 10088c2ecf20Sopenharmony_ci (cq->sq.next_to_use)++; 10098c2ecf20Sopenharmony_ci if (cq->sq.next_to_use == cq->sq.count) 10108c2ecf20Sopenharmony_ci cq->sq.next_to_use = 0; 10118c2ecf20Sopenharmony_ci wr32(hw, cq->sq.tail, cq->sq.next_to_use); 10128c2ecf20Sopenharmony_ci 10138c2ecf20Sopenharmony_ci do { 10148c2ecf20Sopenharmony_ci if (ice_sq_done(hw, cq)) 10158c2ecf20Sopenharmony_ci break; 10168c2ecf20Sopenharmony_ci 10178c2ecf20Sopenharmony_ci udelay(ICE_CTL_Q_SQ_CMD_USEC); 10188c2ecf20Sopenharmony_ci total_delay++; 10198c2ecf20Sopenharmony_ci } while (total_delay < cq->sq_cmd_timeout); 10208c2ecf20Sopenharmony_ci 10218c2ecf20Sopenharmony_ci /* if ready, copy the desc back to temp */ 10228c2ecf20Sopenharmony_ci if (ice_sq_done(hw, cq)) { 10238c2ecf20Sopenharmony_ci memcpy(desc, desc_on_ring, sizeof(*desc)); 10248c2ecf20Sopenharmony_ci if (buf) { 10258c2ecf20Sopenharmony_ci /* get returned length to copy */ 10268c2ecf20Sopenharmony_ci u16 copy_size = le16_to_cpu(desc->datalen); 10278c2ecf20Sopenharmony_ci 10288c2ecf20Sopenharmony_ci if (copy_size > buf_size) { 10298c2ecf20Sopenharmony_ci ice_debug(hw, ICE_DBG_AQ_MSG, 10308c2ecf20Sopenharmony_ci "Return len %d > than buf len %d\n", 10318c2ecf20Sopenharmony_ci copy_size, buf_size); 10328c2ecf20Sopenharmony_ci status = ICE_ERR_AQ_ERROR; 10338c2ecf20Sopenharmony_ci } else { 10348c2ecf20Sopenharmony_ci memcpy(buf, dma_buf->va, copy_size); 10358c2ecf20Sopenharmony_ci } 10368c2ecf20Sopenharmony_ci } 10378c2ecf20Sopenharmony_ci retval = le16_to_cpu(desc->retval); 10388c2ecf20Sopenharmony_ci if (retval) { 10398c2ecf20Sopenharmony_ci ice_debug(hw, ICE_DBG_AQ_MSG, 10408c2ecf20Sopenharmony_ci "Control Send Queue command 0x%04X completed with error 0x%X\n", 10418c2ecf20Sopenharmony_ci le16_to_cpu(desc->opcode), 10428c2ecf20Sopenharmony_ci retval); 10438c2ecf20Sopenharmony_ci 10448c2ecf20Sopenharmony_ci /* strip off FW internal code */ 10458c2ecf20Sopenharmony_ci retval &= 0xff; 10468c2ecf20Sopenharmony_ci } 10478c2ecf20Sopenharmony_ci cmd_completed = true; 10488c2ecf20Sopenharmony_ci if (!status && retval != ICE_AQ_RC_OK) 10498c2ecf20Sopenharmony_ci status = ICE_ERR_AQ_ERROR; 10508c2ecf20Sopenharmony_ci cq->sq_last_status = (enum ice_aq_err)retval; 10518c2ecf20Sopenharmony_ci } 10528c2ecf20Sopenharmony_ci 10538c2ecf20Sopenharmony_ci ice_debug(hw, ICE_DBG_AQ_MSG, 10548c2ecf20Sopenharmony_ci "ATQ: desc and buffer writeback:\n"); 10558c2ecf20Sopenharmony_ci 10568c2ecf20Sopenharmony_ci ice_debug_cq(hw, (void *)desc, buf, buf_size); 10578c2ecf20Sopenharmony_ci 10588c2ecf20Sopenharmony_ci /* save writeback AQ if requested */ 10598c2ecf20Sopenharmony_ci if (details->wb_desc) 10608c2ecf20Sopenharmony_ci memcpy(details->wb_desc, desc_on_ring, 10618c2ecf20Sopenharmony_ci sizeof(*details->wb_desc)); 10628c2ecf20Sopenharmony_ci 10638c2ecf20Sopenharmony_ci /* update the error if time out occurred */ 10648c2ecf20Sopenharmony_ci if (!cmd_completed) { 10658c2ecf20Sopenharmony_ci if (rd32(hw, cq->rq.len) & cq->rq.len_crit_mask || 10668c2ecf20Sopenharmony_ci rd32(hw, cq->sq.len) & cq->sq.len_crit_mask) { 10678c2ecf20Sopenharmony_ci ice_debug(hw, ICE_DBG_AQ_MSG, "Critical FW error.\n"); 10688c2ecf20Sopenharmony_ci status = ICE_ERR_AQ_FW_CRITICAL; 10698c2ecf20Sopenharmony_ci } else { 10708c2ecf20Sopenharmony_ci ice_debug(hw, ICE_DBG_AQ_MSG, 10718c2ecf20Sopenharmony_ci "Control Send Queue Writeback timeout.\n"); 10728c2ecf20Sopenharmony_ci status = ICE_ERR_AQ_TIMEOUT; 10738c2ecf20Sopenharmony_ci } 10748c2ecf20Sopenharmony_ci } 10758c2ecf20Sopenharmony_ci 10768c2ecf20Sopenharmony_cisq_send_command_error: 10778c2ecf20Sopenharmony_ci mutex_unlock(&cq->sq_lock); 10788c2ecf20Sopenharmony_ci return status; 10798c2ecf20Sopenharmony_ci} 10808c2ecf20Sopenharmony_ci 10818c2ecf20Sopenharmony_ci/** 10828c2ecf20Sopenharmony_ci * ice_fill_dflt_direct_cmd_desc - AQ descriptor helper function 10838c2ecf20Sopenharmony_ci * @desc: pointer to the temp descriptor (non DMA mem) 10848c2ecf20Sopenharmony_ci * @opcode: the opcode can be used to decide which flags to turn off or on 10858c2ecf20Sopenharmony_ci * 10868c2ecf20Sopenharmony_ci * Fill the desc with default values 10878c2ecf20Sopenharmony_ci */ 10888c2ecf20Sopenharmony_civoid ice_fill_dflt_direct_cmd_desc(struct ice_aq_desc *desc, u16 opcode) 10898c2ecf20Sopenharmony_ci{ 10908c2ecf20Sopenharmony_ci /* zero out the desc */ 10918c2ecf20Sopenharmony_ci memset(desc, 0, sizeof(*desc)); 10928c2ecf20Sopenharmony_ci desc->opcode = cpu_to_le16(opcode); 10938c2ecf20Sopenharmony_ci desc->flags = cpu_to_le16(ICE_AQ_FLAG_SI); 10948c2ecf20Sopenharmony_ci} 10958c2ecf20Sopenharmony_ci 10968c2ecf20Sopenharmony_ci/** 10978c2ecf20Sopenharmony_ci * ice_clean_rq_elem 10988c2ecf20Sopenharmony_ci * @hw: pointer to the HW struct 10998c2ecf20Sopenharmony_ci * @cq: pointer to the specific Control queue 11008c2ecf20Sopenharmony_ci * @e: event info from the receive descriptor, includes any buffers 11018c2ecf20Sopenharmony_ci * @pending: number of events that could be left to process 11028c2ecf20Sopenharmony_ci * 11038c2ecf20Sopenharmony_ci * This function cleans one Admin Receive Queue element and returns 11048c2ecf20Sopenharmony_ci * the contents through e. It can also return how many events are 11058c2ecf20Sopenharmony_ci * left to process through 'pending'. 11068c2ecf20Sopenharmony_ci */ 11078c2ecf20Sopenharmony_cienum ice_status 11088c2ecf20Sopenharmony_ciice_clean_rq_elem(struct ice_hw *hw, struct ice_ctl_q_info *cq, 11098c2ecf20Sopenharmony_ci struct ice_rq_event_info *e, u16 *pending) 11108c2ecf20Sopenharmony_ci{ 11118c2ecf20Sopenharmony_ci u16 ntc = cq->rq.next_to_clean; 11128c2ecf20Sopenharmony_ci enum ice_status ret_code = 0; 11138c2ecf20Sopenharmony_ci struct ice_aq_desc *desc; 11148c2ecf20Sopenharmony_ci struct ice_dma_mem *bi; 11158c2ecf20Sopenharmony_ci u16 desc_idx; 11168c2ecf20Sopenharmony_ci u16 datalen; 11178c2ecf20Sopenharmony_ci u16 flags; 11188c2ecf20Sopenharmony_ci u16 ntu; 11198c2ecf20Sopenharmony_ci 11208c2ecf20Sopenharmony_ci /* pre-clean the event info */ 11218c2ecf20Sopenharmony_ci memset(&e->desc, 0, sizeof(e->desc)); 11228c2ecf20Sopenharmony_ci 11238c2ecf20Sopenharmony_ci /* take the lock before we start messing with the ring */ 11248c2ecf20Sopenharmony_ci mutex_lock(&cq->rq_lock); 11258c2ecf20Sopenharmony_ci 11268c2ecf20Sopenharmony_ci if (!cq->rq.count) { 11278c2ecf20Sopenharmony_ci ice_debug(hw, ICE_DBG_AQ_MSG, 11288c2ecf20Sopenharmony_ci "Control Receive queue not initialized.\n"); 11298c2ecf20Sopenharmony_ci ret_code = ICE_ERR_AQ_EMPTY; 11308c2ecf20Sopenharmony_ci goto clean_rq_elem_err; 11318c2ecf20Sopenharmony_ci } 11328c2ecf20Sopenharmony_ci 11338c2ecf20Sopenharmony_ci /* set next_to_use to head */ 11348c2ecf20Sopenharmony_ci ntu = (u16)(rd32(hw, cq->rq.head) & cq->rq.head_mask); 11358c2ecf20Sopenharmony_ci 11368c2ecf20Sopenharmony_ci if (ntu == ntc) { 11378c2ecf20Sopenharmony_ci /* nothing to do - shouldn't need to update ring's values */ 11388c2ecf20Sopenharmony_ci ret_code = ICE_ERR_AQ_NO_WORK; 11398c2ecf20Sopenharmony_ci goto clean_rq_elem_out; 11408c2ecf20Sopenharmony_ci } 11418c2ecf20Sopenharmony_ci 11428c2ecf20Sopenharmony_ci /* now clean the next descriptor */ 11438c2ecf20Sopenharmony_ci desc = ICE_CTL_Q_DESC(cq->rq, ntc); 11448c2ecf20Sopenharmony_ci desc_idx = ntc; 11458c2ecf20Sopenharmony_ci 11468c2ecf20Sopenharmony_ci cq->rq_last_status = (enum ice_aq_err)le16_to_cpu(desc->retval); 11478c2ecf20Sopenharmony_ci flags = le16_to_cpu(desc->flags); 11488c2ecf20Sopenharmony_ci if (flags & ICE_AQ_FLAG_ERR) { 11498c2ecf20Sopenharmony_ci ret_code = ICE_ERR_AQ_ERROR; 11508c2ecf20Sopenharmony_ci ice_debug(hw, ICE_DBG_AQ_MSG, 11518c2ecf20Sopenharmony_ci "Control Receive Queue Event 0x%04X received with error 0x%X\n", 11528c2ecf20Sopenharmony_ci le16_to_cpu(desc->opcode), 11538c2ecf20Sopenharmony_ci cq->rq_last_status); 11548c2ecf20Sopenharmony_ci } 11558c2ecf20Sopenharmony_ci memcpy(&e->desc, desc, sizeof(e->desc)); 11568c2ecf20Sopenharmony_ci datalen = le16_to_cpu(desc->datalen); 11578c2ecf20Sopenharmony_ci e->msg_len = min_t(u16, datalen, e->buf_len); 11588c2ecf20Sopenharmony_ci if (e->msg_buf && e->msg_len) 11598c2ecf20Sopenharmony_ci memcpy(e->msg_buf, cq->rq.r.rq_bi[desc_idx].va, e->msg_len); 11608c2ecf20Sopenharmony_ci 11618c2ecf20Sopenharmony_ci ice_debug(hw, ICE_DBG_AQ_DESC, "ARQ: desc and buffer:\n"); 11628c2ecf20Sopenharmony_ci 11638c2ecf20Sopenharmony_ci ice_debug_cq(hw, (void *)desc, e->msg_buf, cq->rq_buf_size); 11648c2ecf20Sopenharmony_ci 11658c2ecf20Sopenharmony_ci /* Restore the original datalen and buffer address in the desc, 11668c2ecf20Sopenharmony_ci * FW updates datalen to indicate the event message size 11678c2ecf20Sopenharmony_ci */ 11688c2ecf20Sopenharmony_ci bi = &cq->rq.r.rq_bi[ntc]; 11698c2ecf20Sopenharmony_ci memset(desc, 0, sizeof(*desc)); 11708c2ecf20Sopenharmony_ci 11718c2ecf20Sopenharmony_ci desc->flags = cpu_to_le16(ICE_AQ_FLAG_BUF); 11728c2ecf20Sopenharmony_ci if (cq->rq_buf_size > ICE_AQ_LG_BUF) 11738c2ecf20Sopenharmony_ci desc->flags |= cpu_to_le16(ICE_AQ_FLAG_LB); 11748c2ecf20Sopenharmony_ci desc->datalen = cpu_to_le16(bi->size); 11758c2ecf20Sopenharmony_ci desc->params.generic.addr_high = cpu_to_le32(upper_32_bits(bi->pa)); 11768c2ecf20Sopenharmony_ci desc->params.generic.addr_low = cpu_to_le32(lower_32_bits(bi->pa)); 11778c2ecf20Sopenharmony_ci 11788c2ecf20Sopenharmony_ci /* set tail = the last cleaned desc index. */ 11798c2ecf20Sopenharmony_ci wr32(hw, cq->rq.tail, ntc); 11808c2ecf20Sopenharmony_ci /* ntc is updated to tail + 1 */ 11818c2ecf20Sopenharmony_ci ntc++; 11828c2ecf20Sopenharmony_ci if (ntc == cq->num_rq_entries) 11838c2ecf20Sopenharmony_ci ntc = 0; 11848c2ecf20Sopenharmony_ci cq->rq.next_to_clean = ntc; 11858c2ecf20Sopenharmony_ci cq->rq.next_to_use = ntu; 11868c2ecf20Sopenharmony_ci 11878c2ecf20Sopenharmony_ciclean_rq_elem_out: 11888c2ecf20Sopenharmony_ci /* Set pending if needed, unlock and return */ 11898c2ecf20Sopenharmony_ci if (pending) { 11908c2ecf20Sopenharmony_ci /* re-read HW head to calculate actual pending messages */ 11918c2ecf20Sopenharmony_ci ntu = (u16)(rd32(hw, cq->rq.head) & cq->rq.head_mask); 11928c2ecf20Sopenharmony_ci *pending = (u16)((ntc > ntu ? cq->rq.count : 0) + (ntu - ntc)); 11938c2ecf20Sopenharmony_ci } 11948c2ecf20Sopenharmony_ciclean_rq_elem_err: 11958c2ecf20Sopenharmony_ci mutex_unlock(&cq->rq_lock); 11968c2ecf20Sopenharmony_ci 11978c2ecf20Sopenharmony_ci return ret_code; 11988c2ecf20Sopenharmony_ci} 1199