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