162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* Copyright (c) 2018, Intel Corporation. */ 362306a36Sopenharmony_ci 462306a36Sopenharmony_ci#include "ice_common.h" 562306a36Sopenharmony_ci 662306a36Sopenharmony_ci#define ICE_CQ_INIT_REGS(qinfo, prefix) \ 762306a36Sopenharmony_cido { \ 862306a36Sopenharmony_ci (qinfo)->sq.head = prefix##_ATQH; \ 962306a36Sopenharmony_ci (qinfo)->sq.tail = prefix##_ATQT; \ 1062306a36Sopenharmony_ci (qinfo)->sq.len = prefix##_ATQLEN; \ 1162306a36Sopenharmony_ci (qinfo)->sq.bah = prefix##_ATQBAH; \ 1262306a36Sopenharmony_ci (qinfo)->sq.bal = prefix##_ATQBAL; \ 1362306a36Sopenharmony_ci (qinfo)->sq.len_mask = prefix##_ATQLEN_ATQLEN_M; \ 1462306a36Sopenharmony_ci (qinfo)->sq.len_ena_mask = prefix##_ATQLEN_ATQENABLE_M; \ 1562306a36Sopenharmony_ci (qinfo)->sq.len_crit_mask = prefix##_ATQLEN_ATQCRIT_M; \ 1662306a36Sopenharmony_ci (qinfo)->sq.head_mask = prefix##_ATQH_ATQH_M; \ 1762306a36Sopenharmony_ci (qinfo)->rq.head = prefix##_ARQH; \ 1862306a36Sopenharmony_ci (qinfo)->rq.tail = prefix##_ARQT; \ 1962306a36Sopenharmony_ci (qinfo)->rq.len = prefix##_ARQLEN; \ 2062306a36Sopenharmony_ci (qinfo)->rq.bah = prefix##_ARQBAH; \ 2162306a36Sopenharmony_ci (qinfo)->rq.bal = prefix##_ARQBAL; \ 2262306a36Sopenharmony_ci (qinfo)->rq.len_mask = prefix##_ARQLEN_ARQLEN_M; \ 2362306a36Sopenharmony_ci (qinfo)->rq.len_ena_mask = prefix##_ARQLEN_ARQENABLE_M; \ 2462306a36Sopenharmony_ci (qinfo)->rq.len_crit_mask = prefix##_ARQLEN_ARQCRIT_M; \ 2562306a36Sopenharmony_ci (qinfo)->rq.head_mask = prefix##_ARQH_ARQH_M; \ 2662306a36Sopenharmony_ci} while (0) 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_ci/** 2962306a36Sopenharmony_ci * ice_adminq_init_regs - Initialize AdminQ registers 3062306a36Sopenharmony_ci * @hw: pointer to the hardware structure 3162306a36Sopenharmony_ci * 3262306a36Sopenharmony_ci * This assumes the alloc_sq and alloc_rq functions have already been called 3362306a36Sopenharmony_ci */ 3462306a36Sopenharmony_cistatic void ice_adminq_init_regs(struct ice_hw *hw) 3562306a36Sopenharmony_ci{ 3662306a36Sopenharmony_ci struct ice_ctl_q_info *cq = &hw->adminq; 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_ci ICE_CQ_INIT_REGS(cq, PF_FW); 3962306a36Sopenharmony_ci} 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_ci/** 4262306a36Sopenharmony_ci * ice_mailbox_init_regs - Initialize Mailbox registers 4362306a36Sopenharmony_ci * @hw: pointer to the hardware structure 4462306a36Sopenharmony_ci * 4562306a36Sopenharmony_ci * This assumes the alloc_sq and alloc_rq functions have already been called 4662306a36Sopenharmony_ci */ 4762306a36Sopenharmony_cistatic void ice_mailbox_init_regs(struct ice_hw *hw) 4862306a36Sopenharmony_ci{ 4962306a36Sopenharmony_ci struct ice_ctl_q_info *cq = &hw->mailboxq; 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_ci ICE_CQ_INIT_REGS(cq, PF_MBX); 5262306a36Sopenharmony_ci} 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_ci/** 5562306a36Sopenharmony_ci * ice_sb_init_regs - Initialize Sideband registers 5662306a36Sopenharmony_ci * @hw: pointer to the hardware structure 5762306a36Sopenharmony_ci * 5862306a36Sopenharmony_ci * This assumes the alloc_sq and alloc_rq functions have already been called 5962306a36Sopenharmony_ci */ 6062306a36Sopenharmony_cistatic void ice_sb_init_regs(struct ice_hw *hw) 6162306a36Sopenharmony_ci{ 6262306a36Sopenharmony_ci struct ice_ctl_q_info *cq = &hw->sbq; 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_ci ICE_CQ_INIT_REGS(cq, PF_SB); 6562306a36Sopenharmony_ci} 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_ci/** 6862306a36Sopenharmony_ci * ice_check_sq_alive 6962306a36Sopenharmony_ci * @hw: pointer to the HW struct 7062306a36Sopenharmony_ci * @cq: pointer to the specific Control queue 7162306a36Sopenharmony_ci * 7262306a36Sopenharmony_ci * Returns true if Queue is enabled else false. 7362306a36Sopenharmony_ci */ 7462306a36Sopenharmony_cibool ice_check_sq_alive(struct ice_hw *hw, struct ice_ctl_q_info *cq) 7562306a36Sopenharmony_ci{ 7662306a36Sopenharmony_ci /* check both queue-length and queue-enable fields */ 7762306a36Sopenharmony_ci if (cq->sq.len && cq->sq.len_mask && cq->sq.len_ena_mask) 7862306a36Sopenharmony_ci return (rd32(hw, cq->sq.len) & (cq->sq.len_mask | 7962306a36Sopenharmony_ci cq->sq.len_ena_mask)) == 8062306a36Sopenharmony_ci (cq->num_sq_entries | cq->sq.len_ena_mask); 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_ci return false; 8362306a36Sopenharmony_ci} 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_ci/** 8662306a36Sopenharmony_ci * ice_alloc_ctrlq_sq_ring - Allocate Control Transmit Queue (ATQ) rings 8762306a36Sopenharmony_ci * @hw: pointer to the hardware structure 8862306a36Sopenharmony_ci * @cq: pointer to the specific Control queue 8962306a36Sopenharmony_ci */ 9062306a36Sopenharmony_cistatic int 9162306a36Sopenharmony_ciice_alloc_ctrlq_sq_ring(struct ice_hw *hw, struct ice_ctl_q_info *cq) 9262306a36Sopenharmony_ci{ 9362306a36Sopenharmony_ci size_t size = cq->num_sq_entries * sizeof(struct ice_aq_desc); 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_ci cq->sq.desc_buf.va = dmam_alloc_coherent(ice_hw_to_dev(hw), size, 9662306a36Sopenharmony_ci &cq->sq.desc_buf.pa, 9762306a36Sopenharmony_ci GFP_KERNEL | __GFP_ZERO); 9862306a36Sopenharmony_ci if (!cq->sq.desc_buf.va) 9962306a36Sopenharmony_ci return -ENOMEM; 10062306a36Sopenharmony_ci cq->sq.desc_buf.size = size; 10162306a36Sopenharmony_ci 10262306a36Sopenharmony_ci cq->sq.cmd_buf = devm_kcalloc(ice_hw_to_dev(hw), cq->num_sq_entries, 10362306a36Sopenharmony_ci sizeof(struct ice_sq_cd), GFP_KERNEL); 10462306a36Sopenharmony_ci if (!cq->sq.cmd_buf) { 10562306a36Sopenharmony_ci dmam_free_coherent(ice_hw_to_dev(hw), cq->sq.desc_buf.size, 10662306a36Sopenharmony_ci cq->sq.desc_buf.va, cq->sq.desc_buf.pa); 10762306a36Sopenharmony_ci cq->sq.desc_buf.va = NULL; 10862306a36Sopenharmony_ci cq->sq.desc_buf.pa = 0; 10962306a36Sopenharmony_ci cq->sq.desc_buf.size = 0; 11062306a36Sopenharmony_ci return -ENOMEM; 11162306a36Sopenharmony_ci } 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_ci return 0; 11462306a36Sopenharmony_ci} 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_ci/** 11762306a36Sopenharmony_ci * ice_alloc_ctrlq_rq_ring - Allocate Control Receive Queue (ARQ) rings 11862306a36Sopenharmony_ci * @hw: pointer to the hardware structure 11962306a36Sopenharmony_ci * @cq: pointer to the specific Control queue 12062306a36Sopenharmony_ci */ 12162306a36Sopenharmony_cistatic int 12262306a36Sopenharmony_ciice_alloc_ctrlq_rq_ring(struct ice_hw *hw, struct ice_ctl_q_info *cq) 12362306a36Sopenharmony_ci{ 12462306a36Sopenharmony_ci size_t size = cq->num_rq_entries * sizeof(struct ice_aq_desc); 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_ci cq->rq.desc_buf.va = dmam_alloc_coherent(ice_hw_to_dev(hw), size, 12762306a36Sopenharmony_ci &cq->rq.desc_buf.pa, 12862306a36Sopenharmony_ci GFP_KERNEL | __GFP_ZERO); 12962306a36Sopenharmony_ci if (!cq->rq.desc_buf.va) 13062306a36Sopenharmony_ci return -ENOMEM; 13162306a36Sopenharmony_ci cq->rq.desc_buf.size = size; 13262306a36Sopenharmony_ci return 0; 13362306a36Sopenharmony_ci} 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_ci/** 13662306a36Sopenharmony_ci * ice_free_cq_ring - Free control queue ring 13762306a36Sopenharmony_ci * @hw: pointer to the hardware structure 13862306a36Sopenharmony_ci * @ring: pointer to the specific control queue ring 13962306a36Sopenharmony_ci * 14062306a36Sopenharmony_ci * This assumes the posted buffers have already been cleaned 14162306a36Sopenharmony_ci * and de-allocated 14262306a36Sopenharmony_ci */ 14362306a36Sopenharmony_cistatic void ice_free_cq_ring(struct ice_hw *hw, struct ice_ctl_q_ring *ring) 14462306a36Sopenharmony_ci{ 14562306a36Sopenharmony_ci dmam_free_coherent(ice_hw_to_dev(hw), ring->desc_buf.size, 14662306a36Sopenharmony_ci ring->desc_buf.va, ring->desc_buf.pa); 14762306a36Sopenharmony_ci ring->desc_buf.va = NULL; 14862306a36Sopenharmony_ci ring->desc_buf.pa = 0; 14962306a36Sopenharmony_ci ring->desc_buf.size = 0; 15062306a36Sopenharmony_ci} 15162306a36Sopenharmony_ci 15262306a36Sopenharmony_ci/** 15362306a36Sopenharmony_ci * ice_alloc_rq_bufs - Allocate pre-posted buffers for the ARQ 15462306a36Sopenharmony_ci * @hw: pointer to the hardware structure 15562306a36Sopenharmony_ci * @cq: pointer to the specific Control queue 15662306a36Sopenharmony_ci */ 15762306a36Sopenharmony_cistatic int 15862306a36Sopenharmony_ciice_alloc_rq_bufs(struct ice_hw *hw, struct ice_ctl_q_info *cq) 15962306a36Sopenharmony_ci{ 16062306a36Sopenharmony_ci int i; 16162306a36Sopenharmony_ci 16262306a36Sopenharmony_ci /* We'll be allocating the buffer info memory first, then we can 16362306a36Sopenharmony_ci * allocate the mapped buffers for the event processing 16462306a36Sopenharmony_ci */ 16562306a36Sopenharmony_ci cq->rq.dma_head = devm_kcalloc(ice_hw_to_dev(hw), cq->num_rq_entries, 16662306a36Sopenharmony_ci sizeof(cq->rq.desc_buf), GFP_KERNEL); 16762306a36Sopenharmony_ci if (!cq->rq.dma_head) 16862306a36Sopenharmony_ci return -ENOMEM; 16962306a36Sopenharmony_ci cq->rq.r.rq_bi = (struct ice_dma_mem *)cq->rq.dma_head; 17062306a36Sopenharmony_ci 17162306a36Sopenharmony_ci /* allocate the mapped buffers */ 17262306a36Sopenharmony_ci for (i = 0; i < cq->num_rq_entries; i++) { 17362306a36Sopenharmony_ci struct ice_aq_desc *desc; 17462306a36Sopenharmony_ci struct ice_dma_mem *bi; 17562306a36Sopenharmony_ci 17662306a36Sopenharmony_ci bi = &cq->rq.r.rq_bi[i]; 17762306a36Sopenharmony_ci bi->va = dmam_alloc_coherent(ice_hw_to_dev(hw), 17862306a36Sopenharmony_ci cq->rq_buf_size, &bi->pa, 17962306a36Sopenharmony_ci GFP_KERNEL | __GFP_ZERO); 18062306a36Sopenharmony_ci if (!bi->va) 18162306a36Sopenharmony_ci goto unwind_alloc_rq_bufs; 18262306a36Sopenharmony_ci bi->size = cq->rq_buf_size; 18362306a36Sopenharmony_ci 18462306a36Sopenharmony_ci /* now configure the descriptors for use */ 18562306a36Sopenharmony_ci desc = ICE_CTL_Q_DESC(cq->rq, i); 18662306a36Sopenharmony_ci 18762306a36Sopenharmony_ci desc->flags = cpu_to_le16(ICE_AQ_FLAG_BUF); 18862306a36Sopenharmony_ci if (cq->rq_buf_size > ICE_AQ_LG_BUF) 18962306a36Sopenharmony_ci desc->flags |= cpu_to_le16(ICE_AQ_FLAG_LB); 19062306a36Sopenharmony_ci desc->opcode = 0; 19162306a36Sopenharmony_ci /* This is in accordance with Admin queue design, there is no 19262306a36Sopenharmony_ci * register for buffer size configuration 19362306a36Sopenharmony_ci */ 19462306a36Sopenharmony_ci desc->datalen = cpu_to_le16(bi->size); 19562306a36Sopenharmony_ci desc->retval = 0; 19662306a36Sopenharmony_ci desc->cookie_high = 0; 19762306a36Sopenharmony_ci desc->cookie_low = 0; 19862306a36Sopenharmony_ci desc->params.generic.addr_high = 19962306a36Sopenharmony_ci cpu_to_le32(upper_32_bits(bi->pa)); 20062306a36Sopenharmony_ci desc->params.generic.addr_low = 20162306a36Sopenharmony_ci cpu_to_le32(lower_32_bits(bi->pa)); 20262306a36Sopenharmony_ci desc->params.generic.param0 = 0; 20362306a36Sopenharmony_ci desc->params.generic.param1 = 0; 20462306a36Sopenharmony_ci } 20562306a36Sopenharmony_ci return 0; 20662306a36Sopenharmony_ci 20762306a36Sopenharmony_ciunwind_alloc_rq_bufs: 20862306a36Sopenharmony_ci /* don't try to free the one that failed... */ 20962306a36Sopenharmony_ci i--; 21062306a36Sopenharmony_ci for (; i >= 0; i--) { 21162306a36Sopenharmony_ci dmam_free_coherent(ice_hw_to_dev(hw), cq->rq.r.rq_bi[i].size, 21262306a36Sopenharmony_ci cq->rq.r.rq_bi[i].va, cq->rq.r.rq_bi[i].pa); 21362306a36Sopenharmony_ci cq->rq.r.rq_bi[i].va = NULL; 21462306a36Sopenharmony_ci cq->rq.r.rq_bi[i].pa = 0; 21562306a36Sopenharmony_ci cq->rq.r.rq_bi[i].size = 0; 21662306a36Sopenharmony_ci } 21762306a36Sopenharmony_ci cq->rq.r.rq_bi = NULL; 21862306a36Sopenharmony_ci devm_kfree(ice_hw_to_dev(hw), cq->rq.dma_head); 21962306a36Sopenharmony_ci cq->rq.dma_head = NULL; 22062306a36Sopenharmony_ci 22162306a36Sopenharmony_ci return -ENOMEM; 22262306a36Sopenharmony_ci} 22362306a36Sopenharmony_ci 22462306a36Sopenharmony_ci/** 22562306a36Sopenharmony_ci * ice_alloc_sq_bufs - Allocate empty buffer structs for the ATQ 22662306a36Sopenharmony_ci * @hw: pointer to the hardware structure 22762306a36Sopenharmony_ci * @cq: pointer to the specific Control queue 22862306a36Sopenharmony_ci */ 22962306a36Sopenharmony_cistatic int 23062306a36Sopenharmony_ciice_alloc_sq_bufs(struct ice_hw *hw, struct ice_ctl_q_info *cq) 23162306a36Sopenharmony_ci{ 23262306a36Sopenharmony_ci int i; 23362306a36Sopenharmony_ci 23462306a36Sopenharmony_ci /* No mapped memory needed yet, just the buffer info structures */ 23562306a36Sopenharmony_ci cq->sq.dma_head = devm_kcalloc(ice_hw_to_dev(hw), cq->num_sq_entries, 23662306a36Sopenharmony_ci sizeof(cq->sq.desc_buf), GFP_KERNEL); 23762306a36Sopenharmony_ci if (!cq->sq.dma_head) 23862306a36Sopenharmony_ci return -ENOMEM; 23962306a36Sopenharmony_ci cq->sq.r.sq_bi = (struct ice_dma_mem *)cq->sq.dma_head; 24062306a36Sopenharmony_ci 24162306a36Sopenharmony_ci /* allocate the mapped buffers */ 24262306a36Sopenharmony_ci for (i = 0; i < cq->num_sq_entries; i++) { 24362306a36Sopenharmony_ci struct ice_dma_mem *bi; 24462306a36Sopenharmony_ci 24562306a36Sopenharmony_ci bi = &cq->sq.r.sq_bi[i]; 24662306a36Sopenharmony_ci bi->va = dmam_alloc_coherent(ice_hw_to_dev(hw), 24762306a36Sopenharmony_ci cq->sq_buf_size, &bi->pa, 24862306a36Sopenharmony_ci GFP_KERNEL | __GFP_ZERO); 24962306a36Sopenharmony_ci if (!bi->va) 25062306a36Sopenharmony_ci goto unwind_alloc_sq_bufs; 25162306a36Sopenharmony_ci bi->size = cq->sq_buf_size; 25262306a36Sopenharmony_ci } 25362306a36Sopenharmony_ci return 0; 25462306a36Sopenharmony_ci 25562306a36Sopenharmony_ciunwind_alloc_sq_bufs: 25662306a36Sopenharmony_ci /* don't try to free the one that failed... */ 25762306a36Sopenharmony_ci i--; 25862306a36Sopenharmony_ci for (; i >= 0; i--) { 25962306a36Sopenharmony_ci dmam_free_coherent(ice_hw_to_dev(hw), cq->sq.r.sq_bi[i].size, 26062306a36Sopenharmony_ci cq->sq.r.sq_bi[i].va, cq->sq.r.sq_bi[i].pa); 26162306a36Sopenharmony_ci cq->sq.r.sq_bi[i].va = NULL; 26262306a36Sopenharmony_ci cq->sq.r.sq_bi[i].pa = 0; 26362306a36Sopenharmony_ci cq->sq.r.sq_bi[i].size = 0; 26462306a36Sopenharmony_ci } 26562306a36Sopenharmony_ci cq->sq.r.sq_bi = NULL; 26662306a36Sopenharmony_ci devm_kfree(ice_hw_to_dev(hw), cq->sq.dma_head); 26762306a36Sopenharmony_ci cq->sq.dma_head = NULL; 26862306a36Sopenharmony_ci 26962306a36Sopenharmony_ci return -ENOMEM; 27062306a36Sopenharmony_ci} 27162306a36Sopenharmony_ci 27262306a36Sopenharmony_cistatic int 27362306a36Sopenharmony_ciice_cfg_cq_regs(struct ice_hw *hw, struct ice_ctl_q_ring *ring, u16 num_entries) 27462306a36Sopenharmony_ci{ 27562306a36Sopenharmony_ci /* Clear Head and Tail */ 27662306a36Sopenharmony_ci wr32(hw, ring->head, 0); 27762306a36Sopenharmony_ci wr32(hw, ring->tail, 0); 27862306a36Sopenharmony_ci 27962306a36Sopenharmony_ci /* set starting point */ 28062306a36Sopenharmony_ci wr32(hw, ring->len, (num_entries | ring->len_ena_mask)); 28162306a36Sopenharmony_ci wr32(hw, ring->bal, lower_32_bits(ring->desc_buf.pa)); 28262306a36Sopenharmony_ci wr32(hw, ring->bah, upper_32_bits(ring->desc_buf.pa)); 28362306a36Sopenharmony_ci 28462306a36Sopenharmony_ci /* Check one register to verify that config was applied */ 28562306a36Sopenharmony_ci if (rd32(hw, ring->bal) != lower_32_bits(ring->desc_buf.pa)) 28662306a36Sopenharmony_ci return -EIO; 28762306a36Sopenharmony_ci 28862306a36Sopenharmony_ci return 0; 28962306a36Sopenharmony_ci} 29062306a36Sopenharmony_ci 29162306a36Sopenharmony_ci/** 29262306a36Sopenharmony_ci * ice_cfg_sq_regs - configure Control ATQ registers 29362306a36Sopenharmony_ci * @hw: pointer to the hardware structure 29462306a36Sopenharmony_ci * @cq: pointer to the specific Control queue 29562306a36Sopenharmony_ci * 29662306a36Sopenharmony_ci * Configure base address and length registers for the transmit queue 29762306a36Sopenharmony_ci */ 29862306a36Sopenharmony_cistatic int ice_cfg_sq_regs(struct ice_hw *hw, struct ice_ctl_q_info *cq) 29962306a36Sopenharmony_ci{ 30062306a36Sopenharmony_ci return ice_cfg_cq_regs(hw, &cq->sq, cq->num_sq_entries); 30162306a36Sopenharmony_ci} 30262306a36Sopenharmony_ci 30362306a36Sopenharmony_ci/** 30462306a36Sopenharmony_ci * ice_cfg_rq_regs - configure Control ARQ register 30562306a36Sopenharmony_ci * @hw: pointer to the hardware structure 30662306a36Sopenharmony_ci * @cq: pointer to the specific Control queue 30762306a36Sopenharmony_ci * 30862306a36Sopenharmony_ci * Configure base address and length registers for the receive (event queue) 30962306a36Sopenharmony_ci */ 31062306a36Sopenharmony_cistatic int ice_cfg_rq_regs(struct ice_hw *hw, struct ice_ctl_q_info *cq) 31162306a36Sopenharmony_ci{ 31262306a36Sopenharmony_ci int status; 31362306a36Sopenharmony_ci 31462306a36Sopenharmony_ci status = ice_cfg_cq_regs(hw, &cq->rq, cq->num_rq_entries); 31562306a36Sopenharmony_ci if (status) 31662306a36Sopenharmony_ci return status; 31762306a36Sopenharmony_ci 31862306a36Sopenharmony_ci /* Update tail in the HW to post pre-allocated buffers */ 31962306a36Sopenharmony_ci wr32(hw, cq->rq.tail, (u32)(cq->num_rq_entries - 1)); 32062306a36Sopenharmony_ci 32162306a36Sopenharmony_ci return 0; 32262306a36Sopenharmony_ci} 32362306a36Sopenharmony_ci 32462306a36Sopenharmony_ci#define ICE_FREE_CQ_BUFS(hw, qi, ring) \ 32562306a36Sopenharmony_cido { \ 32662306a36Sopenharmony_ci /* free descriptors */ \ 32762306a36Sopenharmony_ci if ((qi)->ring.r.ring##_bi) { \ 32862306a36Sopenharmony_ci int i; \ 32962306a36Sopenharmony_ci \ 33062306a36Sopenharmony_ci for (i = 0; i < (qi)->num_##ring##_entries; i++) \ 33162306a36Sopenharmony_ci if ((qi)->ring.r.ring##_bi[i].pa) { \ 33262306a36Sopenharmony_ci dmam_free_coherent(ice_hw_to_dev(hw), \ 33362306a36Sopenharmony_ci (qi)->ring.r.ring##_bi[i].size, \ 33462306a36Sopenharmony_ci (qi)->ring.r.ring##_bi[i].va, \ 33562306a36Sopenharmony_ci (qi)->ring.r.ring##_bi[i].pa); \ 33662306a36Sopenharmony_ci (qi)->ring.r.ring##_bi[i].va = NULL;\ 33762306a36Sopenharmony_ci (qi)->ring.r.ring##_bi[i].pa = 0;\ 33862306a36Sopenharmony_ci (qi)->ring.r.ring##_bi[i].size = 0;\ 33962306a36Sopenharmony_ci } \ 34062306a36Sopenharmony_ci } \ 34162306a36Sopenharmony_ci /* free the buffer info list */ \ 34262306a36Sopenharmony_ci devm_kfree(ice_hw_to_dev(hw), (qi)->ring.cmd_buf); \ 34362306a36Sopenharmony_ci /* free DMA head */ \ 34462306a36Sopenharmony_ci devm_kfree(ice_hw_to_dev(hw), (qi)->ring.dma_head); \ 34562306a36Sopenharmony_ci} while (0) 34662306a36Sopenharmony_ci 34762306a36Sopenharmony_ci/** 34862306a36Sopenharmony_ci * ice_init_sq - main initialization routine for Control ATQ 34962306a36Sopenharmony_ci * @hw: pointer to the hardware structure 35062306a36Sopenharmony_ci * @cq: pointer to the specific Control queue 35162306a36Sopenharmony_ci * 35262306a36Sopenharmony_ci * This is the main initialization routine for the Control Send Queue 35362306a36Sopenharmony_ci * Prior to calling this function, the driver *MUST* set the following fields 35462306a36Sopenharmony_ci * in the cq->structure: 35562306a36Sopenharmony_ci * - cq->num_sq_entries 35662306a36Sopenharmony_ci * - cq->sq_buf_size 35762306a36Sopenharmony_ci * 35862306a36Sopenharmony_ci * Do *NOT* hold the lock when calling this as the memory allocation routines 35962306a36Sopenharmony_ci * called are not going to be atomic context safe 36062306a36Sopenharmony_ci */ 36162306a36Sopenharmony_cistatic int ice_init_sq(struct ice_hw *hw, struct ice_ctl_q_info *cq) 36262306a36Sopenharmony_ci{ 36362306a36Sopenharmony_ci int ret_code; 36462306a36Sopenharmony_ci 36562306a36Sopenharmony_ci if (cq->sq.count > 0) { 36662306a36Sopenharmony_ci /* queue already initialized */ 36762306a36Sopenharmony_ci ret_code = -EBUSY; 36862306a36Sopenharmony_ci goto init_ctrlq_exit; 36962306a36Sopenharmony_ci } 37062306a36Sopenharmony_ci 37162306a36Sopenharmony_ci /* verify input for valid configuration */ 37262306a36Sopenharmony_ci if (!cq->num_sq_entries || !cq->sq_buf_size) { 37362306a36Sopenharmony_ci ret_code = -EIO; 37462306a36Sopenharmony_ci goto init_ctrlq_exit; 37562306a36Sopenharmony_ci } 37662306a36Sopenharmony_ci 37762306a36Sopenharmony_ci cq->sq.next_to_use = 0; 37862306a36Sopenharmony_ci cq->sq.next_to_clean = 0; 37962306a36Sopenharmony_ci 38062306a36Sopenharmony_ci /* allocate the ring memory */ 38162306a36Sopenharmony_ci ret_code = ice_alloc_ctrlq_sq_ring(hw, cq); 38262306a36Sopenharmony_ci if (ret_code) 38362306a36Sopenharmony_ci goto init_ctrlq_exit; 38462306a36Sopenharmony_ci 38562306a36Sopenharmony_ci /* allocate buffers in the rings */ 38662306a36Sopenharmony_ci ret_code = ice_alloc_sq_bufs(hw, cq); 38762306a36Sopenharmony_ci if (ret_code) 38862306a36Sopenharmony_ci goto init_ctrlq_free_rings; 38962306a36Sopenharmony_ci 39062306a36Sopenharmony_ci /* initialize base registers */ 39162306a36Sopenharmony_ci ret_code = ice_cfg_sq_regs(hw, cq); 39262306a36Sopenharmony_ci if (ret_code) 39362306a36Sopenharmony_ci goto init_ctrlq_free_rings; 39462306a36Sopenharmony_ci 39562306a36Sopenharmony_ci /* success! */ 39662306a36Sopenharmony_ci cq->sq.count = cq->num_sq_entries; 39762306a36Sopenharmony_ci goto init_ctrlq_exit; 39862306a36Sopenharmony_ci 39962306a36Sopenharmony_ciinit_ctrlq_free_rings: 40062306a36Sopenharmony_ci ICE_FREE_CQ_BUFS(hw, cq, sq); 40162306a36Sopenharmony_ci ice_free_cq_ring(hw, &cq->sq); 40262306a36Sopenharmony_ci 40362306a36Sopenharmony_ciinit_ctrlq_exit: 40462306a36Sopenharmony_ci return ret_code; 40562306a36Sopenharmony_ci} 40662306a36Sopenharmony_ci 40762306a36Sopenharmony_ci/** 40862306a36Sopenharmony_ci * ice_init_rq - initialize ARQ 40962306a36Sopenharmony_ci * @hw: pointer to the hardware structure 41062306a36Sopenharmony_ci * @cq: pointer to the specific Control queue 41162306a36Sopenharmony_ci * 41262306a36Sopenharmony_ci * The main initialization routine for the Admin Receive (Event) Queue. 41362306a36Sopenharmony_ci * Prior to calling this function, the driver *MUST* set the following fields 41462306a36Sopenharmony_ci * in the cq->structure: 41562306a36Sopenharmony_ci * - cq->num_rq_entries 41662306a36Sopenharmony_ci * - cq->rq_buf_size 41762306a36Sopenharmony_ci * 41862306a36Sopenharmony_ci * Do *NOT* hold the lock when calling this as the memory allocation routines 41962306a36Sopenharmony_ci * called are not going to be atomic context safe 42062306a36Sopenharmony_ci */ 42162306a36Sopenharmony_cistatic int ice_init_rq(struct ice_hw *hw, struct ice_ctl_q_info *cq) 42262306a36Sopenharmony_ci{ 42362306a36Sopenharmony_ci int ret_code; 42462306a36Sopenharmony_ci 42562306a36Sopenharmony_ci if (cq->rq.count > 0) { 42662306a36Sopenharmony_ci /* queue already initialized */ 42762306a36Sopenharmony_ci ret_code = -EBUSY; 42862306a36Sopenharmony_ci goto init_ctrlq_exit; 42962306a36Sopenharmony_ci } 43062306a36Sopenharmony_ci 43162306a36Sopenharmony_ci /* verify input for valid configuration */ 43262306a36Sopenharmony_ci if (!cq->num_rq_entries || !cq->rq_buf_size) { 43362306a36Sopenharmony_ci ret_code = -EIO; 43462306a36Sopenharmony_ci goto init_ctrlq_exit; 43562306a36Sopenharmony_ci } 43662306a36Sopenharmony_ci 43762306a36Sopenharmony_ci cq->rq.next_to_use = 0; 43862306a36Sopenharmony_ci cq->rq.next_to_clean = 0; 43962306a36Sopenharmony_ci 44062306a36Sopenharmony_ci /* allocate the ring memory */ 44162306a36Sopenharmony_ci ret_code = ice_alloc_ctrlq_rq_ring(hw, cq); 44262306a36Sopenharmony_ci if (ret_code) 44362306a36Sopenharmony_ci goto init_ctrlq_exit; 44462306a36Sopenharmony_ci 44562306a36Sopenharmony_ci /* allocate buffers in the rings */ 44662306a36Sopenharmony_ci ret_code = ice_alloc_rq_bufs(hw, cq); 44762306a36Sopenharmony_ci if (ret_code) 44862306a36Sopenharmony_ci goto init_ctrlq_free_rings; 44962306a36Sopenharmony_ci 45062306a36Sopenharmony_ci /* initialize base registers */ 45162306a36Sopenharmony_ci ret_code = ice_cfg_rq_regs(hw, cq); 45262306a36Sopenharmony_ci if (ret_code) 45362306a36Sopenharmony_ci goto init_ctrlq_free_rings; 45462306a36Sopenharmony_ci 45562306a36Sopenharmony_ci /* success! */ 45662306a36Sopenharmony_ci cq->rq.count = cq->num_rq_entries; 45762306a36Sopenharmony_ci goto init_ctrlq_exit; 45862306a36Sopenharmony_ci 45962306a36Sopenharmony_ciinit_ctrlq_free_rings: 46062306a36Sopenharmony_ci ICE_FREE_CQ_BUFS(hw, cq, rq); 46162306a36Sopenharmony_ci ice_free_cq_ring(hw, &cq->rq); 46262306a36Sopenharmony_ci 46362306a36Sopenharmony_ciinit_ctrlq_exit: 46462306a36Sopenharmony_ci return ret_code; 46562306a36Sopenharmony_ci} 46662306a36Sopenharmony_ci 46762306a36Sopenharmony_ci/** 46862306a36Sopenharmony_ci * ice_shutdown_sq - shutdown the Control ATQ 46962306a36Sopenharmony_ci * @hw: pointer to the hardware structure 47062306a36Sopenharmony_ci * @cq: pointer to the specific Control queue 47162306a36Sopenharmony_ci * 47262306a36Sopenharmony_ci * The main shutdown routine for the Control Transmit Queue 47362306a36Sopenharmony_ci */ 47462306a36Sopenharmony_cistatic int ice_shutdown_sq(struct ice_hw *hw, struct ice_ctl_q_info *cq) 47562306a36Sopenharmony_ci{ 47662306a36Sopenharmony_ci int ret_code = 0; 47762306a36Sopenharmony_ci 47862306a36Sopenharmony_ci mutex_lock(&cq->sq_lock); 47962306a36Sopenharmony_ci 48062306a36Sopenharmony_ci if (!cq->sq.count) { 48162306a36Sopenharmony_ci ret_code = -EBUSY; 48262306a36Sopenharmony_ci goto shutdown_sq_out; 48362306a36Sopenharmony_ci } 48462306a36Sopenharmony_ci 48562306a36Sopenharmony_ci /* Stop firmware AdminQ processing */ 48662306a36Sopenharmony_ci wr32(hw, cq->sq.head, 0); 48762306a36Sopenharmony_ci wr32(hw, cq->sq.tail, 0); 48862306a36Sopenharmony_ci wr32(hw, cq->sq.len, 0); 48962306a36Sopenharmony_ci wr32(hw, cq->sq.bal, 0); 49062306a36Sopenharmony_ci wr32(hw, cq->sq.bah, 0); 49162306a36Sopenharmony_ci 49262306a36Sopenharmony_ci cq->sq.count = 0; /* to indicate uninitialized queue */ 49362306a36Sopenharmony_ci 49462306a36Sopenharmony_ci /* free ring buffers and the ring itself */ 49562306a36Sopenharmony_ci ICE_FREE_CQ_BUFS(hw, cq, sq); 49662306a36Sopenharmony_ci ice_free_cq_ring(hw, &cq->sq); 49762306a36Sopenharmony_ci 49862306a36Sopenharmony_cishutdown_sq_out: 49962306a36Sopenharmony_ci mutex_unlock(&cq->sq_lock); 50062306a36Sopenharmony_ci return ret_code; 50162306a36Sopenharmony_ci} 50262306a36Sopenharmony_ci 50362306a36Sopenharmony_ci/** 50462306a36Sopenharmony_ci * ice_aq_ver_check - Check the reported AQ API version. 50562306a36Sopenharmony_ci * @hw: pointer to the hardware structure 50662306a36Sopenharmony_ci * 50762306a36Sopenharmony_ci * Checks if the driver should load on a given AQ API version. 50862306a36Sopenharmony_ci * 50962306a36Sopenharmony_ci * Return: 'true' iff the driver should attempt to load. 'false' otherwise. 51062306a36Sopenharmony_ci */ 51162306a36Sopenharmony_cistatic bool ice_aq_ver_check(struct ice_hw *hw) 51262306a36Sopenharmony_ci{ 51362306a36Sopenharmony_ci if (hw->api_maj_ver > EXP_FW_API_VER_MAJOR) { 51462306a36Sopenharmony_ci /* Major API version is newer than expected, don't load */ 51562306a36Sopenharmony_ci dev_warn(ice_hw_to_dev(hw), 51662306a36Sopenharmony_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"); 51762306a36Sopenharmony_ci return false; 51862306a36Sopenharmony_ci } else if (hw->api_maj_ver == EXP_FW_API_VER_MAJOR) { 51962306a36Sopenharmony_ci if (hw->api_min_ver > (EXP_FW_API_VER_MINOR + 2)) 52062306a36Sopenharmony_ci dev_info(ice_hw_to_dev(hw), 52162306a36Sopenharmony_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"); 52262306a36Sopenharmony_ci else if ((hw->api_min_ver + 2) < EXP_FW_API_VER_MINOR) 52362306a36Sopenharmony_ci dev_info(ice_hw_to_dev(hw), 52462306a36Sopenharmony_ci "The driver for the device detected an older version of the NVM image than expected. Please update the NVM image.\n"); 52562306a36Sopenharmony_ci } else { 52662306a36Sopenharmony_ci /* Major API version is older than expected, log a warning */ 52762306a36Sopenharmony_ci dev_info(ice_hw_to_dev(hw), 52862306a36Sopenharmony_ci "The driver for the device detected an older version of the NVM image than expected. Please update the NVM image.\n"); 52962306a36Sopenharmony_ci } 53062306a36Sopenharmony_ci return true; 53162306a36Sopenharmony_ci} 53262306a36Sopenharmony_ci 53362306a36Sopenharmony_ci/** 53462306a36Sopenharmony_ci * ice_shutdown_rq - shutdown Control ARQ 53562306a36Sopenharmony_ci * @hw: pointer to the hardware structure 53662306a36Sopenharmony_ci * @cq: pointer to the specific Control queue 53762306a36Sopenharmony_ci * 53862306a36Sopenharmony_ci * The main shutdown routine for the Control Receive Queue 53962306a36Sopenharmony_ci */ 54062306a36Sopenharmony_cistatic int ice_shutdown_rq(struct ice_hw *hw, struct ice_ctl_q_info *cq) 54162306a36Sopenharmony_ci{ 54262306a36Sopenharmony_ci int ret_code = 0; 54362306a36Sopenharmony_ci 54462306a36Sopenharmony_ci mutex_lock(&cq->rq_lock); 54562306a36Sopenharmony_ci 54662306a36Sopenharmony_ci if (!cq->rq.count) { 54762306a36Sopenharmony_ci ret_code = -EBUSY; 54862306a36Sopenharmony_ci goto shutdown_rq_out; 54962306a36Sopenharmony_ci } 55062306a36Sopenharmony_ci 55162306a36Sopenharmony_ci /* Stop Control Queue processing */ 55262306a36Sopenharmony_ci wr32(hw, cq->rq.head, 0); 55362306a36Sopenharmony_ci wr32(hw, cq->rq.tail, 0); 55462306a36Sopenharmony_ci wr32(hw, cq->rq.len, 0); 55562306a36Sopenharmony_ci wr32(hw, cq->rq.bal, 0); 55662306a36Sopenharmony_ci wr32(hw, cq->rq.bah, 0); 55762306a36Sopenharmony_ci 55862306a36Sopenharmony_ci /* set rq.count to 0 to indicate uninitialized queue */ 55962306a36Sopenharmony_ci cq->rq.count = 0; 56062306a36Sopenharmony_ci 56162306a36Sopenharmony_ci /* free ring buffers and the ring itself */ 56262306a36Sopenharmony_ci ICE_FREE_CQ_BUFS(hw, cq, rq); 56362306a36Sopenharmony_ci ice_free_cq_ring(hw, &cq->rq); 56462306a36Sopenharmony_ci 56562306a36Sopenharmony_cishutdown_rq_out: 56662306a36Sopenharmony_ci mutex_unlock(&cq->rq_lock); 56762306a36Sopenharmony_ci return ret_code; 56862306a36Sopenharmony_ci} 56962306a36Sopenharmony_ci 57062306a36Sopenharmony_ci/** 57162306a36Sopenharmony_ci * ice_init_check_adminq - Check version for Admin Queue to know if its alive 57262306a36Sopenharmony_ci * @hw: pointer to the hardware structure 57362306a36Sopenharmony_ci */ 57462306a36Sopenharmony_cistatic int ice_init_check_adminq(struct ice_hw *hw) 57562306a36Sopenharmony_ci{ 57662306a36Sopenharmony_ci struct ice_ctl_q_info *cq = &hw->adminq; 57762306a36Sopenharmony_ci int status; 57862306a36Sopenharmony_ci 57962306a36Sopenharmony_ci status = ice_aq_get_fw_ver(hw, NULL); 58062306a36Sopenharmony_ci if (status) 58162306a36Sopenharmony_ci goto init_ctrlq_free_rq; 58262306a36Sopenharmony_ci 58362306a36Sopenharmony_ci if (!ice_aq_ver_check(hw)) { 58462306a36Sopenharmony_ci status = -EIO; 58562306a36Sopenharmony_ci goto init_ctrlq_free_rq; 58662306a36Sopenharmony_ci } 58762306a36Sopenharmony_ci 58862306a36Sopenharmony_ci return 0; 58962306a36Sopenharmony_ci 59062306a36Sopenharmony_ciinit_ctrlq_free_rq: 59162306a36Sopenharmony_ci ice_shutdown_rq(hw, cq); 59262306a36Sopenharmony_ci ice_shutdown_sq(hw, cq); 59362306a36Sopenharmony_ci return status; 59462306a36Sopenharmony_ci} 59562306a36Sopenharmony_ci 59662306a36Sopenharmony_ci/** 59762306a36Sopenharmony_ci * ice_init_ctrlq - main initialization routine for any control Queue 59862306a36Sopenharmony_ci * @hw: pointer to the hardware structure 59962306a36Sopenharmony_ci * @q_type: specific Control queue type 60062306a36Sopenharmony_ci * 60162306a36Sopenharmony_ci * Prior to calling this function, the driver *MUST* set the following fields 60262306a36Sopenharmony_ci * in the cq->structure: 60362306a36Sopenharmony_ci * - cq->num_sq_entries 60462306a36Sopenharmony_ci * - cq->num_rq_entries 60562306a36Sopenharmony_ci * - cq->rq_buf_size 60662306a36Sopenharmony_ci * - cq->sq_buf_size 60762306a36Sopenharmony_ci * 60862306a36Sopenharmony_ci * NOTE: this function does not initialize the controlq locks 60962306a36Sopenharmony_ci */ 61062306a36Sopenharmony_cistatic int ice_init_ctrlq(struct ice_hw *hw, enum ice_ctl_q q_type) 61162306a36Sopenharmony_ci{ 61262306a36Sopenharmony_ci struct ice_ctl_q_info *cq; 61362306a36Sopenharmony_ci int ret_code; 61462306a36Sopenharmony_ci 61562306a36Sopenharmony_ci switch (q_type) { 61662306a36Sopenharmony_ci case ICE_CTL_Q_ADMIN: 61762306a36Sopenharmony_ci ice_adminq_init_regs(hw); 61862306a36Sopenharmony_ci cq = &hw->adminq; 61962306a36Sopenharmony_ci break; 62062306a36Sopenharmony_ci case ICE_CTL_Q_SB: 62162306a36Sopenharmony_ci ice_sb_init_regs(hw); 62262306a36Sopenharmony_ci cq = &hw->sbq; 62362306a36Sopenharmony_ci break; 62462306a36Sopenharmony_ci case ICE_CTL_Q_MAILBOX: 62562306a36Sopenharmony_ci ice_mailbox_init_regs(hw); 62662306a36Sopenharmony_ci cq = &hw->mailboxq; 62762306a36Sopenharmony_ci break; 62862306a36Sopenharmony_ci default: 62962306a36Sopenharmony_ci return -EINVAL; 63062306a36Sopenharmony_ci } 63162306a36Sopenharmony_ci cq->qtype = q_type; 63262306a36Sopenharmony_ci 63362306a36Sopenharmony_ci /* verify input for valid configuration */ 63462306a36Sopenharmony_ci if (!cq->num_rq_entries || !cq->num_sq_entries || 63562306a36Sopenharmony_ci !cq->rq_buf_size || !cq->sq_buf_size) { 63662306a36Sopenharmony_ci return -EIO; 63762306a36Sopenharmony_ci } 63862306a36Sopenharmony_ci 63962306a36Sopenharmony_ci /* allocate the ATQ */ 64062306a36Sopenharmony_ci ret_code = ice_init_sq(hw, cq); 64162306a36Sopenharmony_ci if (ret_code) 64262306a36Sopenharmony_ci return ret_code; 64362306a36Sopenharmony_ci 64462306a36Sopenharmony_ci /* allocate the ARQ */ 64562306a36Sopenharmony_ci ret_code = ice_init_rq(hw, cq); 64662306a36Sopenharmony_ci if (ret_code) 64762306a36Sopenharmony_ci goto init_ctrlq_free_sq; 64862306a36Sopenharmony_ci 64962306a36Sopenharmony_ci /* success! */ 65062306a36Sopenharmony_ci return 0; 65162306a36Sopenharmony_ci 65262306a36Sopenharmony_ciinit_ctrlq_free_sq: 65362306a36Sopenharmony_ci ice_shutdown_sq(hw, cq); 65462306a36Sopenharmony_ci return ret_code; 65562306a36Sopenharmony_ci} 65662306a36Sopenharmony_ci 65762306a36Sopenharmony_ci/** 65862306a36Sopenharmony_ci * ice_is_sbq_supported - is the sideband queue supported 65962306a36Sopenharmony_ci * @hw: pointer to the hardware structure 66062306a36Sopenharmony_ci * 66162306a36Sopenharmony_ci * Returns true if the sideband control queue interface is 66262306a36Sopenharmony_ci * supported for the device, false otherwise 66362306a36Sopenharmony_ci */ 66462306a36Sopenharmony_cibool ice_is_sbq_supported(struct ice_hw *hw) 66562306a36Sopenharmony_ci{ 66662306a36Sopenharmony_ci /* The device sideband queue is only supported on devices with the 66762306a36Sopenharmony_ci * generic MAC type. 66862306a36Sopenharmony_ci */ 66962306a36Sopenharmony_ci return hw->mac_type == ICE_MAC_GENERIC; 67062306a36Sopenharmony_ci} 67162306a36Sopenharmony_ci 67262306a36Sopenharmony_ci/** 67362306a36Sopenharmony_ci * ice_get_sbq - returns the right control queue to use for sideband 67462306a36Sopenharmony_ci * @hw: pointer to the hardware structure 67562306a36Sopenharmony_ci */ 67662306a36Sopenharmony_cistruct ice_ctl_q_info *ice_get_sbq(struct ice_hw *hw) 67762306a36Sopenharmony_ci{ 67862306a36Sopenharmony_ci if (ice_is_sbq_supported(hw)) 67962306a36Sopenharmony_ci return &hw->sbq; 68062306a36Sopenharmony_ci return &hw->adminq; 68162306a36Sopenharmony_ci} 68262306a36Sopenharmony_ci 68362306a36Sopenharmony_ci/** 68462306a36Sopenharmony_ci * ice_shutdown_ctrlq - shutdown routine for any control queue 68562306a36Sopenharmony_ci * @hw: pointer to the hardware structure 68662306a36Sopenharmony_ci * @q_type: specific Control queue type 68762306a36Sopenharmony_ci * 68862306a36Sopenharmony_ci * NOTE: this function does not destroy the control queue locks. 68962306a36Sopenharmony_ci */ 69062306a36Sopenharmony_cistatic void ice_shutdown_ctrlq(struct ice_hw *hw, enum ice_ctl_q q_type) 69162306a36Sopenharmony_ci{ 69262306a36Sopenharmony_ci struct ice_ctl_q_info *cq; 69362306a36Sopenharmony_ci 69462306a36Sopenharmony_ci switch (q_type) { 69562306a36Sopenharmony_ci case ICE_CTL_Q_ADMIN: 69662306a36Sopenharmony_ci cq = &hw->adminq; 69762306a36Sopenharmony_ci if (ice_check_sq_alive(hw, cq)) 69862306a36Sopenharmony_ci ice_aq_q_shutdown(hw, true); 69962306a36Sopenharmony_ci break; 70062306a36Sopenharmony_ci case ICE_CTL_Q_SB: 70162306a36Sopenharmony_ci cq = &hw->sbq; 70262306a36Sopenharmony_ci break; 70362306a36Sopenharmony_ci case ICE_CTL_Q_MAILBOX: 70462306a36Sopenharmony_ci cq = &hw->mailboxq; 70562306a36Sopenharmony_ci break; 70662306a36Sopenharmony_ci default: 70762306a36Sopenharmony_ci return; 70862306a36Sopenharmony_ci } 70962306a36Sopenharmony_ci 71062306a36Sopenharmony_ci ice_shutdown_sq(hw, cq); 71162306a36Sopenharmony_ci ice_shutdown_rq(hw, cq); 71262306a36Sopenharmony_ci} 71362306a36Sopenharmony_ci 71462306a36Sopenharmony_ci/** 71562306a36Sopenharmony_ci * ice_shutdown_all_ctrlq - shutdown routine for all control queues 71662306a36Sopenharmony_ci * @hw: pointer to the hardware structure 71762306a36Sopenharmony_ci * 71862306a36Sopenharmony_ci * NOTE: this function does not destroy the control queue locks. The driver 71962306a36Sopenharmony_ci * may call this at runtime to shutdown and later restart control queues, such 72062306a36Sopenharmony_ci * as in response to a reset event. 72162306a36Sopenharmony_ci */ 72262306a36Sopenharmony_civoid ice_shutdown_all_ctrlq(struct ice_hw *hw) 72362306a36Sopenharmony_ci{ 72462306a36Sopenharmony_ci /* Shutdown FW admin queue */ 72562306a36Sopenharmony_ci ice_shutdown_ctrlq(hw, ICE_CTL_Q_ADMIN); 72662306a36Sopenharmony_ci /* Shutdown PHY Sideband */ 72762306a36Sopenharmony_ci if (ice_is_sbq_supported(hw)) 72862306a36Sopenharmony_ci ice_shutdown_ctrlq(hw, ICE_CTL_Q_SB); 72962306a36Sopenharmony_ci /* Shutdown PF-VF Mailbox */ 73062306a36Sopenharmony_ci ice_shutdown_ctrlq(hw, ICE_CTL_Q_MAILBOX); 73162306a36Sopenharmony_ci} 73262306a36Sopenharmony_ci 73362306a36Sopenharmony_ci/** 73462306a36Sopenharmony_ci * ice_init_all_ctrlq - main initialization routine for all control queues 73562306a36Sopenharmony_ci * @hw: pointer to the hardware structure 73662306a36Sopenharmony_ci * 73762306a36Sopenharmony_ci * Prior to calling this function, the driver MUST* set the following fields 73862306a36Sopenharmony_ci * in the cq->structure for all control queues: 73962306a36Sopenharmony_ci * - cq->num_sq_entries 74062306a36Sopenharmony_ci * - cq->num_rq_entries 74162306a36Sopenharmony_ci * - cq->rq_buf_size 74262306a36Sopenharmony_ci * - cq->sq_buf_size 74362306a36Sopenharmony_ci * 74462306a36Sopenharmony_ci * NOTE: this function does not initialize the controlq locks. 74562306a36Sopenharmony_ci */ 74662306a36Sopenharmony_ciint ice_init_all_ctrlq(struct ice_hw *hw) 74762306a36Sopenharmony_ci{ 74862306a36Sopenharmony_ci u32 retry = 0; 74962306a36Sopenharmony_ci int status; 75062306a36Sopenharmony_ci 75162306a36Sopenharmony_ci /* Init FW admin queue */ 75262306a36Sopenharmony_ci do { 75362306a36Sopenharmony_ci status = ice_init_ctrlq(hw, ICE_CTL_Q_ADMIN); 75462306a36Sopenharmony_ci if (status) 75562306a36Sopenharmony_ci return status; 75662306a36Sopenharmony_ci 75762306a36Sopenharmony_ci status = ice_init_check_adminq(hw); 75862306a36Sopenharmony_ci if (status != -EIO) 75962306a36Sopenharmony_ci break; 76062306a36Sopenharmony_ci 76162306a36Sopenharmony_ci ice_debug(hw, ICE_DBG_AQ_MSG, "Retry Admin Queue init due to FW critical error\n"); 76262306a36Sopenharmony_ci ice_shutdown_ctrlq(hw, ICE_CTL_Q_ADMIN); 76362306a36Sopenharmony_ci msleep(ICE_CTL_Q_ADMIN_INIT_MSEC); 76462306a36Sopenharmony_ci } while (retry++ < ICE_CTL_Q_ADMIN_INIT_TIMEOUT); 76562306a36Sopenharmony_ci 76662306a36Sopenharmony_ci if (status) 76762306a36Sopenharmony_ci return status; 76862306a36Sopenharmony_ci /* sideband control queue (SBQ) interface is not supported on some 76962306a36Sopenharmony_ci * devices. Initialize if supported, else fallback to the admin queue 77062306a36Sopenharmony_ci * interface 77162306a36Sopenharmony_ci */ 77262306a36Sopenharmony_ci if (ice_is_sbq_supported(hw)) { 77362306a36Sopenharmony_ci status = ice_init_ctrlq(hw, ICE_CTL_Q_SB); 77462306a36Sopenharmony_ci if (status) 77562306a36Sopenharmony_ci return status; 77662306a36Sopenharmony_ci } 77762306a36Sopenharmony_ci /* Init Mailbox queue */ 77862306a36Sopenharmony_ci return ice_init_ctrlq(hw, ICE_CTL_Q_MAILBOX); 77962306a36Sopenharmony_ci} 78062306a36Sopenharmony_ci 78162306a36Sopenharmony_ci/** 78262306a36Sopenharmony_ci * ice_init_ctrlq_locks - Initialize locks for a control queue 78362306a36Sopenharmony_ci * @cq: pointer to the control queue 78462306a36Sopenharmony_ci * 78562306a36Sopenharmony_ci * Initializes the send and receive queue locks for a given control queue. 78662306a36Sopenharmony_ci */ 78762306a36Sopenharmony_cistatic void ice_init_ctrlq_locks(struct ice_ctl_q_info *cq) 78862306a36Sopenharmony_ci{ 78962306a36Sopenharmony_ci mutex_init(&cq->sq_lock); 79062306a36Sopenharmony_ci mutex_init(&cq->rq_lock); 79162306a36Sopenharmony_ci} 79262306a36Sopenharmony_ci 79362306a36Sopenharmony_ci/** 79462306a36Sopenharmony_ci * ice_create_all_ctrlq - main initialization routine for all control queues 79562306a36Sopenharmony_ci * @hw: pointer to the hardware structure 79662306a36Sopenharmony_ci * 79762306a36Sopenharmony_ci * Prior to calling this function, the driver *MUST* set the following fields 79862306a36Sopenharmony_ci * in the cq->structure for all control queues: 79962306a36Sopenharmony_ci * - cq->num_sq_entries 80062306a36Sopenharmony_ci * - cq->num_rq_entries 80162306a36Sopenharmony_ci * - cq->rq_buf_size 80262306a36Sopenharmony_ci * - cq->sq_buf_size 80362306a36Sopenharmony_ci * 80462306a36Sopenharmony_ci * This function creates all the control queue locks and then calls 80562306a36Sopenharmony_ci * ice_init_all_ctrlq. It should be called once during driver load. If the 80662306a36Sopenharmony_ci * driver needs to re-initialize control queues at run time it should call 80762306a36Sopenharmony_ci * ice_init_all_ctrlq instead. 80862306a36Sopenharmony_ci */ 80962306a36Sopenharmony_ciint ice_create_all_ctrlq(struct ice_hw *hw) 81062306a36Sopenharmony_ci{ 81162306a36Sopenharmony_ci ice_init_ctrlq_locks(&hw->adminq); 81262306a36Sopenharmony_ci if (ice_is_sbq_supported(hw)) 81362306a36Sopenharmony_ci ice_init_ctrlq_locks(&hw->sbq); 81462306a36Sopenharmony_ci ice_init_ctrlq_locks(&hw->mailboxq); 81562306a36Sopenharmony_ci 81662306a36Sopenharmony_ci return ice_init_all_ctrlq(hw); 81762306a36Sopenharmony_ci} 81862306a36Sopenharmony_ci 81962306a36Sopenharmony_ci/** 82062306a36Sopenharmony_ci * ice_destroy_ctrlq_locks - Destroy locks for a control queue 82162306a36Sopenharmony_ci * @cq: pointer to the control queue 82262306a36Sopenharmony_ci * 82362306a36Sopenharmony_ci * Destroys the send and receive queue locks for a given control queue. 82462306a36Sopenharmony_ci */ 82562306a36Sopenharmony_cistatic void ice_destroy_ctrlq_locks(struct ice_ctl_q_info *cq) 82662306a36Sopenharmony_ci{ 82762306a36Sopenharmony_ci mutex_destroy(&cq->sq_lock); 82862306a36Sopenharmony_ci mutex_destroy(&cq->rq_lock); 82962306a36Sopenharmony_ci} 83062306a36Sopenharmony_ci 83162306a36Sopenharmony_ci/** 83262306a36Sopenharmony_ci * ice_destroy_all_ctrlq - exit routine for all control queues 83362306a36Sopenharmony_ci * @hw: pointer to the hardware structure 83462306a36Sopenharmony_ci * 83562306a36Sopenharmony_ci * This function shuts down all the control queues and then destroys the 83662306a36Sopenharmony_ci * control queue locks. It should be called once during driver unload. The 83762306a36Sopenharmony_ci * driver should call ice_shutdown_all_ctrlq if it needs to shut down and 83862306a36Sopenharmony_ci * reinitialize control queues, such as in response to a reset event. 83962306a36Sopenharmony_ci */ 84062306a36Sopenharmony_civoid ice_destroy_all_ctrlq(struct ice_hw *hw) 84162306a36Sopenharmony_ci{ 84262306a36Sopenharmony_ci /* shut down all the control queues first */ 84362306a36Sopenharmony_ci ice_shutdown_all_ctrlq(hw); 84462306a36Sopenharmony_ci 84562306a36Sopenharmony_ci ice_destroy_ctrlq_locks(&hw->adminq); 84662306a36Sopenharmony_ci if (ice_is_sbq_supported(hw)) 84762306a36Sopenharmony_ci ice_destroy_ctrlq_locks(&hw->sbq); 84862306a36Sopenharmony_ci ice_destroy_ctrlq_locks(&hw->mailboxq); 84962306a36Sopenharmony_ci} 85062306a36Sopenharmony_ci 85162306a36Sopenharmony_ci/** 85262306a36Sopenharmony_ci * ice_clean_sq - cleans Admin send queue (ATQ) 85362306a36Sopenharmony_ci * @hw: pointer to the hardware structure 85462306a36Sopenharmony_ci * @cq: pointer to the specific Control queue 85562306a36Sopenharmony_ci * 85662306a36Sopenharmony_ci * returns the number of free desc 85762306a36Sopenharmony_ci */ 85862306a36Sopenharmony_cistatic u16 ice_clean_sq(struct ice_hw *hw, struct ice_ctl_q_info *cq) 85962306a36Sopenharmony_ci{ 86062306a36Sopenharmony_ci struct ice_ctl_q_ring *sq = &cq->sq; 86162306a36Sopenharmony_ci u16 ntc = sq->next_to_clean; 86262306a36Sopenharmony_ci struct ice_sq_cd *details; 86362306a36Sopenharmony_ci struct ice_aq_desc *desc; 86462306a36Sopenharmony_ci 86562306a36Sopenharmony_ci desc = ICE_CTL_Q_DESC(*sq, ntc); 86662306a36Sopenharmony_ci details = ICE_CTL_Q_DETAILS(*sq, ntc); 86762306a36Sopenharmony_ci 86862306a36Sopenharmony_ci while (rd32(hw, cq->sq.head) != ntc) { 86962306a36Sopenharmony_ci ice_debug(hw, ICE_DBG_AQ_MSG, "ntc %d head %d.\n", ntc, rd32(hw, cq->sq.head)); 87062306a36Sopenharmony_ci memset(desc, 0, sizeof(*desc)); 87162306a36Sopenharmony_ci memset(details, 0, sizeof(*details)); 87262306a36Sopenharmony_ci ntc++; 87362306a36Sopenharmony_ci if (ntc == sq->count) 87462306a36Sopenharmony_ci ntc = 0; 87562306a36Sopenharmony_ci desc = ICE_CTL_Q_DESC(*sq, ntc); 87662306a36Sopenharmony_ci details = ICE_CTL_Q_DETAILS(*sq, ntc); 87762306a36Sopenharmony_ci } 87862306a36Sopenharmony_ci 87962306a36Sopenharmony_ci sq->next_to_clean = ntc; 88062306a36Sopenharmony_ci 88162306a36Sopenharmony_ci return ICE_CTL_Q_DESC_UNUSED(sq); 88262306a36Sopenharmony_ci} 88362306a36Sopenharmony_ci 88462306a36Sopenharmony_ci/** 88562306a36Sopenharmony_ci * ice_debug_cq 88662306a36Sopenharmony_ci * @hw: pointer to the hardware structure 88762306a36Sopenharmony_ci * @desc: pointer to control queue descriptor 88862306a36Sopenharmony_ci * @buf: pointer to command buffer 88962306a36Sopenharmony_ci * @buf_len: max length of buf 89062306a36Sopenharmony_ci * 89162306a36Sopenharmony_ci * Dumps debug log about control command with descriptor contents. 89262306a36Sopenharmony_ci */ 89362306a36Sopenharmony_cistatic void ice_debug_cq(struct ice_hw *hw, void *desc, void *buf, u16 buf_len) 89462306a36Sopenharmony_ci{ 89562306a36Sopenharmony_ci struct ice_aq_desc *cq_desc = desc; 89662306a36Sopenharmony_ci u16 len; 89762306a36Sopenharmony_ci 89862306a36Sopenharmony_ci if (!IS_ENABLED(CONFIG_DYNAMIC_DEBUG) && 89962306a36Sopenharmony_ci !((ICE_DBG_AQ_DESC | ICE_DBG_AQ_DESC_BUF) & hw->debug_mask)) 90062306a36Sopenharmony_ci return; 90162306a36Sopenharmony_ci 90262306a36Sopenharmony_ci if (!desc) 90362306a36Sopenharmony_ci return; 90462306a36Sopenharmony_ci 90562306a36Sopenharmony_ci len = le16_to_cpu(cq_desc->datalen); 90662306a36Sopenharmony_ci 90762306a36Sopenharmony_ci ice_debug(hw, ICE_DBG_AQ_DESC, "CQ CMD: opcode 0x%04X, flags 0x%04X, datalen 0x%04X, retval 0x%04X\n", 90862306a36Sopenharmony_ci le16_to_cpu(cq_desc->opcode), 90962306a36Sopenharmony_ci le16_to_cpu(cq_desc->flags), 91062306a36Sopenharmony_ci le16_to_cpu(cq_desc->datalen), le16_to_cpu(cq_desc->retval)); 91162306a36Sopenharmony_ci ice_debug(hw, ICE_DBG_AQ_DESC, "\tcookie (h,l) 0x%08X 0x%08X\n", 91262306a36Sopenharmony_ci le32_to_cpu(cq_desc->cookie_high), 91362306a36Sopenharmony_ci le32_to_cpu(cq_desc->cookie_low)); 91462306a36Sopenharmony_ci ice_debug(hw, ICE_DBG_AQ_DESC, "\tparam (0,1) 0x%08X 0x%08X\n", 91562306a36Sopenharmony_ci le32_to_cpu(cq_desc->params.generic.param0), 91662306a36Sopenharmony_ci le32_to_cpu(cq_desc->params.generic.param1)); 91762306a36Sopenharmony_ci ice_debug(hw, ICE_DBG_AQ_DESC, "\taddr (h,l) 0x%08X 0x%08X\n", 91862306a36Sopenharmony_ci le32_to_cpu(cq_desc->params.generic.addr_high), 91962306a36Sopenharmony_ci le32_to_cpu(cq_desc->params.generic.addr_low)); 92062306a36Sopenharmony_ci if (buf && cq_desc->datalen != 0) { 92162306a36Sopenharmony_ci ice_debug(hw, ICE_DBG_AQ_DESC_BUF, "Buffer:\n"); 92262306a36Sopenharmony_ci if (buf_len < len) 92362306a36Sopenharmony_ci len = buf_len; 92462306a36Sopenharmony_ci 92562306a36Sopenharmony_ci ice_debug_array(hw, ICE_DBG_AQ_DESC_BUF, 16, 1, buf, len); 92662306a36Sopenharmony_ci } 92762306a36Sopenharmony_ci} 92862306a36Sopenharmony_ci 92962306a36Sopenharmony_ci/** 93062306a36Sopenharmony_ci * ice_sq_done - check if FW has processed the Admin Send Queue (ATQ) 93162306a36Sopenharmony_ci * @hw: pointer to the HW struct 93262306a36Sopenharmony_ci * @cq: pointer to the specific Control queue 93362306a36Sopenharmony_ci * 93462306a36Sopenharmony_ci * Returns true if the firmware has processed all descriptors on the 93562306a36Sopenharmony_ci * admin send queue. Returns false if there are still requests pending. 93662306a36Sopenharmony_ci */ 93762306a36Sopenharmony_cistatic bool ice_sq_done(struct ice_hw *hw, struct ice_ctl_q_info *cq) 93862306a36Sopenharmony_ci{ 93962306a36Sopenharmony_ci /* AQ designers suggest use of head for better 94062306a36Sopenharmony_ci * timing reliability than DD bit 94162306a36Sopenharmony_ci */ 94262306a36Sopenharmony_ci return rd32(hw, cq->sq.head) == cq->sq.next_to_use; 94362306a36Sopenharmony_ci} 94462306a36Sopenharmony_ci 94562306a36Sopenharmony_ci/** 94662306a36Sopenharmony_ci * ice_sq_send_cmd - send command to Control Queue (ATQ) 94762306a36Sopenharmony_ci * @hw: pointer to the HW struct 94862306a36Sopenharmony_ci * @cq: pointer to the specific Control queue 94962306a36Sopenharmony_ci * @desc: prefilled descriptor describing the command 95062306a36Sopenharmony_ci * @buf: buffer to use for indirect commands (or NULL for direct commands) 95162306a36Sopenharmony_ci * @buf_size: size of buffer for indirect commands (or 0 for direct commands) 95262306a36Sopenharmony_ci * @cd: pointer to command details structure 95362306a36Sopenharmony_ci * 95462306a36Sopenharmony_ci * This is the main send command routine for the ATQ. It runs the queue, 95562306a36Sopenharmony_ci * cleans the queue, etc. 95662306a36Sopenharmony_ci */ 95762306a36Sopenharmony_ciint 95862306a36Sopenharmony_ciice_sq_send_cmd(struct ice_hw *hw, struct ice_ctl_q_info *cq, 95962306a36Sopenharmony_ci struct ice_aq_desc *desc, void *buf, u16 buf_size, 96062306a36Sopenharmony_ci struct ice_sq_cd *cd) 96162306a36Sopenharmony_ci{ 96262306a36Sopenharmony_ci struct ice_dma_mem *dma_buf = NULL; 96362306a36Sopenharmony_ci struct ice_aq_desc *desc_on_ring; 96462306a36Sopenharmony_ci bool cmd_completed = false; 96562306a36Sopenharmony_ci struct ice_sq_cd *details; 96662306a36Sopenharmony_ci unsigned long timeout; 96762306a36Sopenharmony_ci int status = 0; 96862306a36Sopenharmony_ci u16 retval = 0; 96962306a36Sopenharmony_ci u32 val = 0; 97062306a36Sopenharmony_ci 97162306a36Sopenharmony_ci /* if reset is in progress return a soft error */ 97262306a36Sopenharmony_ci if (hw->reset_ongoing) 97362306a36Sopenharmony_ci return -EBUSY; 97462306a36Sopenharmony_ci mutex_lock(&cq->sq_lock); 97562306a36Sopenharmony_ci 97662306a36Sopenharmony_ci cq->sq_last_status = ICE_AQ_RC_OK; 97762306a36Sopenharmony_ci 97862306a36Sopenharmony_ci if (!cq->sq.count) { 97962306a36Sopenharmony_ci ice_debug(hw, ICE_DBG_AQ_MSG, "Control Send queue not initialized.\n"); 98062306a36Sopenharmony_ci status = -EIO; 98162306a36Sopenharmony_ci goto sq_send_command_error; 98262306a36Sopenharmony_ci } 98362306a36Sopenharmony_ci 98462306a36Sopenharmony_ci if ((buf && !buf_size) || (!buf && buf_size)) { 98562306a36Sopenharmony_ci status = -EINVAL; 98662306a36Sopenharmony_ci goto sq_send_command_error; 98762306a36Sopenharmony_ci } 98862306a36Sopenharmony_ci 98962306a36Sopenharmony_ci if (buf) { 99062306a36Sopenharmony_ci if (buf_size > cq->sq_buf_size) { 99162306a36Sopenharmony_ci ice_debug(hw, ICE_DBG_AQ_MSG, "Invalid buffer size for Control Send queue: %d.\n", 99262306a36Sopenharmony_ci buf_size); 99362306a36Sopenharmony_ci status = -EINVAL; 99462306a36Sopenharmony_ci goto sq_send_command_error; 99562306a36Sopenharmony_ci } 99662306a36Sopenharmony_ci 99762306a36Sopenharmony_ci desc->flags |= cpu_to_le16(ICE_AQ_FLAG_BUF); 99862306a36Sopenharmony_ci if (buf_size > ICE_AQ_LG_BUF) 99962306a36Sopenharmony_ci desc->flags |= cpu_to_le16(ICE_AQ_FLAG_LB); 100062306a36Sopenharmony_ci } 100162306a36Sopenharmony_ci 100262306a36Sopenharmony_ci val = rd32(hw, cq->sq.head); 100362306a36Sopenharmony_ci if (val >= cq->num_sq_entries) { 100462306a36Sopenharmony_ci ice_debug(hw, ICE_DBG_AQ_MSG, "head overrun at %d in the Control Send Queue ring\n", 100562306a36Sopenharmony_ci val); 100662306a36Sopenharmony_ci status = -EIO; 100762306a36Sopenharmony_ci goto sq_send_command_error; 100862306a36Sopenharmony_ci } 100962306a36Sopenharmony_ci 101062306a36Sopenharmony_ci details = ICE_CTL_Q_DETAILS(cq->sq, cq->sq.next_to_use); 101162306a36Sopenharmony_ci if (cd) 101262306a36Sopenharmony_ci *details = *cd; 101362306a36Sopenharmony_ci else 101462306a36Sopenharmony_ci memset(details, 0, sizeof(*details)); 101562306a36Sopenharmony_ci 101662306a36Sopenharmony_ci /* Call clean and check queue available function to reclaim the 101762306a36Sopenharmony_ci * descriptors that were processed by FW/MBX; the function returns the 101862306a36Sopenharmony_ci * number of desc available. The clean function called here could be 101962306a36Sopenharmony_ci * called in a separate thread in case of asynchronous completions. 102062306a36Sopenharmony_ci */ 102162306a36Sopenharmony_ci if (ice_clean_sq(hw, cq) == 0) { 102262306a36Sopenharmony_ci ice_debug(hw, ICE_DBG_AQ_MSG, "Error: Control Send Queue is full.\n"); 102362306a36Sopenharmony_ci status = -ENOSPC; 102462306a36Sopenharmony_ci goto sq_send_command_error; 102562306a36Sopenharmony_ci } 102662306a36Sopenharmony_ci 102762306a36Sopenharmony_ci /* initialize the temp desc pointer with the right desc */ 102862306a36Sopenharmony_ci desc_on_ring = ICE_CTL_Q_DESC(cq->sq, cq->sq.next_to_use); 102962306a36Sopenharmony_ci 103062306a36Sopenharmony_ci /* if the desc is available copy the temp desc to the right place */ 103162306a36Sopenharmony_ci memcpy(desc_on_ring, desc, sizeof(*desc_on_ring)); 103262306a36Sopenharmony_ci 103362306a36Sopenharmony_ci /* if buf is not NULL assume indirect command */ 103462306a36Sopenharmony_ci if (buf) { 103562306a36Sopenharmony_ci dma_buf = &cq->sq.r.sq_bi[cq->sq.next_to_use]; 103662306a36Sopenharmony_ci /* copy the user buf into the respective DMA buf */ 103762306a36Sopenharmony_ci memcpy(dma_buf->va, buf, buf_size); 103862306a36Sopenharmony_ci desc_on_ring->datalen = cpu_to_le16(buf_size); 103962306a36Sopenharmony_ci 104062306a36Sopenharmony_ci /* Update the address values in the desc with the pa value 104162306a36Sopenharmony_ci * for respective buffer 104262306a36Sopenharmony_ci */ 104362306a36Sopenharmony_ci desc_on_ring->params.generic.addr_high = 104462306a36Sopenharmony_ci cpu_to_le32(upper_32_bits(dma_buf->pa)); 104562306a36Sopenharmony_ci desc_on_ring->params.generic.addr_low = 104662306a36Sopenharmony_ci cpu_to_le32(lower_32_bits(dma_buf->pa)); 104762306a36Sopenharmony_ci } 104862306a36Sopenharmony_ci 104962306a36Sopenharmony_ci /* Debug desc and buffer */ 105062306a36Sopenharmony_ci ice_debug(hw, ICE_DBG_AQ_DESC, "ATQ: Control Send queue desc and buffer:\n"); 105162306a36Sopenharmony_ci 105262306a36Sopenharmony_ci ice_debug_cq(hw, (void *)desc_on_ring, buf, buf_size); 105362306a36Sopenharmony_ci 105462306a36Sopenharmony_ci (cq->sq.next_to_use)++; 105562306a36Sopenharmony_ci if (cq->sq.next_to_use == cq->sq.count) 105662306a36Sopenharmony_ci cq->sq.next_to_use = 0; 105762306a36Sopenharmony_ci wr32(hw, cq->sq.tail, cq->sq.next_to_use); 105862306a36Sopenharmony_ci ice_flush(hw); 105962306a36Sopenharmony_ci 106062306a36Sopenharmony_ci /* Wait a short time before initial ice_sq_done() check, to allow 106162306a36Sopenharmony_ci * hardware time for completion. 106262306a36Sopenharmony_ci */ 106362306a36Sopenharmony_ci udelay(5); 106462306a36Sopenharmony_ci 106562306a36Sopenharmony_ci timeout = jiffies + ICE_CTL_Q_SQ_CMD_TIMEOUT; 106662306a36Sopenharmony_ci do { 106762306a36Sopenharmony_ci if (ice_sq_done(hw, cq)) 106862306a36Sopenharmony_ci break; 106962306a36Sopenharmony_ci 107062306a36Sopenharmony_ci usleep_range(100, 150); 107162306a36Sopenharmony_ci } while (time_before(jiffies, timeout)); 107262306a36Sopenharmony_ci 107362306a36Sopenharmony_ci /* if ready, copy the desc back to temp */ 107462306a36Sopenharmony_ci if (ice_sq_done(hw, cq)) { 107562306a36Sopenharmony_ci memcpy(desc, desc_on_ring, sizeof(*desc)); 107662306a36Sopenharmony_ci if (buf) { 107762306a36Sopenharmony_ci /* get returned length to copy */ 107862306a36Sopenharmony_ci u16 copy_size = le16_to_cpu(desc->datalen); 107962306a36Sopenharmony_ci 108062306a36Sopenharmony_ci if (copy_size > buf_size) { 108162306a36Sopenharmony_ci ice_debug(hw, ICE_DBG_AQ_MSG, "Return len %d > than buf len %d\n", 108262306a36Sopenharmony_ci copy_size, buf_size); 108362306a36Sopenharmony_ci status = -EIO; 108462306a36Sopenharmony_ci } else { 108562306a36Sopenharmony_ci memcpy(buf, dma_buf->va, copy_size); 108662306a36Sopenharmony_ci } 108762306a36Sopenharmony_ci } 108862306a36Sopenharmony_ci retval = le16_to_cpu(desc->retval); 108962306a36Sopenharmony_ci if (retval) { 109062306a36Sopenharmony_ci ice_debug(hw, ICE_DBG_AQ_MSG, "Control Send Queue command 0x%04X completed with error 0x%X\n", 109162306a36Sopenharmony_ci le16_to_cpu(desc->opcode), 109262306a36Sopenharmony_ci retval); 109362306a36Sopenharmony_ci 109462306a36Sopenharmony_ci /* strip off FW internal code */ 109562306a36Sopenharmony_ci retval &= 0xff; 109662306a36Sopenharmony_ci } 109762306a36Sopenharmony_ci cmd_completed = true; 109862306a36Sopenharmony_ci if (!status && retval != ICE_AQ_RC_OK) 109962306a36Sopenharmony_ci status = -EIO; 110062306a36Sopenharmony_ci cq->sq_last_status = (enum ice_aq_err)retval; 110162306a36Sopenharmony_ci } 110262306a36Sopenharmony_ci 110362306a36Sopenharmony_ci ice_debug(hw, ICE_DBG_AQ_MSG, "ATQ: desc and buffer writeback:\n"); 110462306a36Sopenharmony_ci 110562306a36Sopenharmony_ci ice_debug_cq(hw, (void *)desc, buf, buf_size); 110662306a36Sopenharmony_ci 110762306a36Sopenharmony_ci /* save writeback AQ if requested */ 110862306a36Sopenharmony_ci if (details->wb_desc) 110962306a36Sopenharmony_ci memcpy(details->wb_desc, desc_on_ring, 111062306a36Sopenharmony_ci sizeof(*details->wb_desc)); 111162306a36Sopenharmony_ci 111262306a36Sopenharmony_ci /* update the error if time out occurred */ 111362306a36Sopenharmony_ci if (!cmd_completed) { 111462306a36Sopenharmony_ci if (rd32(hw, cq->rq.len) & cq->rq.len_crit_mask || 111562306a36Sopenharmony_ci rd32(hw, cq->sq.len) & cq->sq.len_crit_mask) { 111662306a36Sopenharmony_ci ice_debug(hw, ICE_DBG_AQ_MSG, "Critical FW error.\n"); 111762306a36Sopenharmony_ci status = -EIO; 111862306a36Sopenharmony_ci } else { 111962306a36Sopenharmony_ci ice_debug(hw, ICE_DBG_AQ_MSG, "Control Send Queue Writeback timeout.\n"); 112062306a36Sopenharmony_ci status = -EIO; 112162306a36Sopenharmony_ci } 112262306a36Sopenharmony_ci } 112362306a36Sopenharmony_ci 112462306a36Sopenharmony_cisq_send_command_error: 112562306a36Sopenharmony_ci mutex_unlock(&cq->sq_lock); 112662306a36Sopenharmony_ci return status; 112762306a36Sopenharmony_ci} 112862306a36Sopenharmony_ci 112962306a36Sopenharmony_ci/** 113062306a36Sopenharmony_ci * ice_fill_dflt_direct_cmd_desc - AQ descriptor helper function 113162306a36Sopenharmony_ci * @desc: pointer to the temp descriptor (non DMA mem) 113262306a36Sopenharmony_ci * @opcode: the opcode can be used to decide which flags to turn off or on 113362306a36Sopenharmony_ci * 113462306a36Sopenharmony_ci * Fill the desc with default values 113562306a36Sopenharmony_ci */ 113662306a36Sopenharmony_civoid ice_fill_dflt_direct_cmd_desc(struct ice_aq_desc *desc, u16 opcode) 113762306a36Sopenharmony_ci{ 113862306a36Sopenharmony_ci /* zero out the desc */ 113962306a36Sopenharmony_ci memset(desc, 0, sizeof(*desc)); 114062306a36Sopenharmony_ci desc->opcode = cpu_to_le16(opcode); 114162306a36Sopenharmony_ci desc->flags = cpu_to_le16(ICE_AQ_FLAG_SI); 114262306a36Sopenharmony_ci} 114362306a36Sopenharmony_ci 114462306a36Sopenharmony_ci/** 114562306a36Sopenharmony_ci * ice_clean_rq_elem 114662306a36Sopenharmony_ci * @hw: pointer to the HW struct 114762306a36Sopenharmony_ci * @cq: pointer to the specific Control queue 114862306a36Sopenharmony_ci * @e: event info from the receive descriptor, includes any buffers 114962306a36Sopenharmony_ci * @pending: number of events that could be left to process 115062306a36Sopenharmony_ci * 115162306a36Sopenharmony_ci * This function cleans one Admin Receive Queue element and returns 115262306a36Sopenharmony_ci * the contents through e. It can also return how many events are 115362306a36Sopenharmony_ci * left to process through 'pending'. 115462306a36Sopenharmony_ci */ 115562306a36Sopenharmony_ciint 115662306a36Sopenharmony_ciice_clean_rq_elem(struct ice_hw *hw, struct ice_ctl_q_info *cq, 115762306a36Sopenharmony_ci struct ice_rq_event_info *e, u16 *pending) 115862306a36Sopenharmony_ci{ 115962306a36Sopenharmony_ci u16 ntc = cq->rq.next_to_clean; 116062306a36Sopenharmony_ci enum ice_aq_err rq_last_status; 116162306a36Sopenharmony_ci struct ice_aq_desc *desc; 116262306a36Sopenharmony_ci struct ice_dma_mem *bi; 116362306a36Sopenharmony_ci int ret_code = 0; 116462306a36Sopenharmony_ci u16 desc_idx; 116562306a36Sopenharmony_ci u16 datalen; 116662306a36Sopenharmony_ci u16 flags; 116762306a36Sopenharmony_ci u16 ntu; 116862306a36Sopenharmony_ci 116962306a36Sopenharmony_ci /* pre-clean the event info */ 117062306a36Sopenharmony_ci memset(&e->desc, 0, sizeof(e->desc)); 117162306a36Sopenharmony_ci 117262306a36Sopenharmony_ci /* take the lock before we start messing with the ring */ 117362306a36Sopenharmony_ci mutex_lock(&cq->rq_lock); 117462306a36Sopenharmony_ci 117562306a36Sopenharmony_ci if (!cq->rq.count) { 117662306a36Sopenharmony_ci ice_debug(hw, ICE_DBG_AQ_MSG, "Control Receive queue not initialized.\n"); 117762306a36Sopenharmony_ci ret_code = -EIO; 117862306a36Sopenharmony_ci goto clean_rq_elem_err; 117962306a36Sopenharmony_ci } 118062306a36Sopenharmony_ci 118162306a36Sopenharmony_ci /* set next_to_use to head */ 118262306a36Sopenharmony_ci ntu = (u16)(rd32(hw, cq->rq.head) & cq->rq.head_mask); 118362306a36Sopenharmony_ci 118462306a36Sopenharmony_ci if (ntu == ntc) { 118562306a36Sopenharmony_ci /* nothing to do - shouldn't need to update ring's values */ 118662306a36Sopenharmony_ci ret_code = -EALREADY; 118762306a36Sopenharmony_ci goto clean_rq_elem_out; 118862306a36Sopenharmony_ci } 118962306a36Sopenharmony_ci 119062306a36Sopenharmony_ci /* now clean the next descriptor */ 119162306a36Sopenharmony_ci desc = ICE_CTL_Q_DESC(cq->rq, ntc); 119262306a36Sopenharmony_ci desc_idx = ntc; 119362306a36Sopenharmony_ci 119462306a36Sopenharmony_ci rq_last_status = (enum ice_aq_err)le16_to_cpu(desc->retval); 119562306a36Sopenharmony_ci flags = le16_to_cpu(desc->flags); 119662306a36Sopenharmony_ci if (flags & ICE_AQ_FLAG_ERR) { 119762306a36Sopenharmony_ci ret_code = -EIO; 119862306a36Sopenharmony_ci ice_debug(hw, ICE_DBG_AQ_MSG, "Control Receive Queue Event 0x%04X received with error 0x%X\n", 119962306a36Sopenharmony_ci le16_to_cpu(desc->opcode), rq_last_status); 120062306a36Sopenharmony_ci } 120162306a36Sopenharmony_ci memcpy(&e->desc, desc, sizeof(e->desc)); 120262306a36Sopenharmony_ci datalen = le16_to_cpu(desc->datalen); 120362306a36Sopenharmony_ci e->msg_len = min_t(u16, datalen, e->buf_len); 120462306a36Sopenharmony_ci if (e->msg_buf && e->msg_len) 120562306a36Sopenharmony_ci memcpy(e->msg_buf, cq->rq.r.rq_bi[desc_idx].va, e->msg_len); 120662306a36Sopenharmony_ci 120762306a36Sopenharmony_ci ice_debug(hw, ICE_DBG_AQ_DESC, "ARQ: desc and buffer:\n"); 120862306a36Sopenharmony_ci 120962306a36Sopenharmony_ci ice_debug_cq(hw, (void *)desc, e->msg_buf, cq->rq_buf_size); 121062306a36Sopenharmony_ci 121162306a36Sopenharmony_ci /* Restore the original datalen and buffer address in the desc, 121262306a36Sopenharmony_ci * FW updates datalen to indicate the event message size 121362306a36Sopenharmony_ci */ 121462306a36Sopenharmony_ci bi = &cq->rq.r.rq_bi[ntc]; 121562306a36Sopenharmony_ci memset(desc, 0, sizeof(*desc)); 121662306a36Sopenharmony_ci 121762306a36Sopenharmony_ci desc->flags = cpu_to_le16(ICE_AQ_FLAG_BUF); 121862306a36Sopenharmony_ci if (cq->rq_buf_size > ICE_AQ_LG_BUF) 121962306a36Sopenharmony_ci desc->flags |= cpu_to_le16(ICE_AQ_FLAG_LB); 122062306a36Sopenharmony_ci desc->datalen = cpu_to_le16(bi->size); 122162306a36Sopenharmony_ci desc->params.generic.addr_high = cpu_to_le32(upper_32_bits(bi->pa)); 122262306a36Sopenharmony_ci desc->params.generic.addr_low = cpu_to_le32(lower_32_bits(bi->pa)); 122362306a36Sopenharmony_ci 122462306a36Sopenharmony_ci /* set tail = the last cleaned desc index. */ 122562306a36Sopenharmony_ci wr32(hw, cq->rq.tail, ntc); 122662306a36Sopenharmony_ci /* ntc is updated to tail + 1 */ 122762306a36Sopenharmony_ci ntc++; 122862306a36Sopenharmony_ci if (ntc == cq->num_rq_entries) 122962306a36Sopenharmony_ci ntc = 0; 123062306a36Sopenharmony_ci cq->rq.next_to_clean = ntc; 123162306a36Sopenharmony_ci cq->rq.next_to_use = ntu; 123262306a36Sopenharmony_ci 123362306a36Sopenharmony_ciclean_rq_elem_out: 123462306a36Sopenharmony_ci /* Set pending if needed, unlock and return */ 123562306a36Sopenharmony_ci if (pending) { 123662306a36Sopenharmony_ci /* re-read HW head to calculate actual pending messages */ 123762306a36Sopenharmony_ci ntu = (u16)(rd32(hw, cq->rq.head) & cq->rq.head_mask); 123862306a36Sopenharmony_ci *pending = (u16)((ntc > ntu ? cq->rq.count : 0) + (ntu - ntc)); 123962306a36Sopenharmony_ci } 124062306a36Sopenharmony_ciclean_rq_elem_err: 124162306a36Sopenharmony_ci mutex_unlock(&cq->rq_lock); 124262306a36Sopenharmony_ci 124362306a36Sopenharmony_ci return ret_code; 124462306a36Sopenharmony_ci} 1245