xref: /linux/drivers/net/ethernet/huawei/hinic3/hinic3_cmdq.c (revision ec2e0fb07d789976c601bec19ecced7a501c3705)
1db03a1ceSFan Gong // SPDX-License-Identifier: GPL-2.0
2db03a1ceSFan Gong // Copyright (c) Huawei Technologies Co., Ltd. 2025. All rights reserved.
3db03a1ceSFan Gong 
4db03a1ceSFan Gong #include <linux/bitfield.h>
5*16a6fce0SFan Gong #include <linux/delay.h>
6db03a1ceSFan Gong #include <linux/dma-mapping.h>
7db03a1ceSFan Gong 
8db03a1ceSFan Gong #include "hinic3_cmdq.h"
9db03a1ceSFan Gong #include "hinic3_hwdev.h"
10db03a1ceSFan Gong #include "hinic3_hwif.h"
11db03a1ceSFan Gong #include "hinic3_mbox.h"
12db03a1ceSFan Gong 
13db03a1ceSFan Gong #define CMDQ_BUF_SIZE             2048
14db03a1ceSFan Gong #define CMDQ_WQEBB_SIZE           64
15db03a1ceSFan Gong 
16*16a6fce0SFan Gong #define CMDQ_CMD_TIMEOUT          5000
17*16a6fce0SFan Gong #define CMDQ_ENABLE_WAIT_TIMEOUT  300
18*16a6fce0SFan Gong 
19db03a1ceSFan Gong #define CMDQ_CTXT_CURR_WQE_PAGE_PFN_MASK  GENMASK_ULL(51, 0)
20db03a1ceSFan Gong #define CMDQ_CTXT_EQ_ID_MASK              GENMASK_ULL(60, 53)
21db03a1ceSFan Gong #define CMDQ_CTXT_CEQ_ARM_MASK            BIT_ULL(61)
22db03a1ceSFan Gong #define CMDQ_CTXT_CEQ_EN_MASK             BIT_ULL(62)
23db03a1ceSFan Gong #define CMDQ_CTXT_HW_BUSY_BIT_MASK        BIT_ULL(63)
24db03a1ceSFan Gong 
25db03a1ceSFan Gong #define CMDQ_CTXT_WQ_BLOCK_PFN_MASK       GENMASK_ULL(51, 0)
26db03a1ceSFan Gong #define CMDQ_CTXT_CI_MASK                 GENMASK_ULL(63, 52)
27db03a1ceSFan Gong #define CMDQ_CTXT_SET(val, member)  \
28db03a1ceSFan Gong 	FIELD_PREP(CMDQ_CTXT_##member##_MASK, val)
29db03a1ceSFan Gong 
30*16a6fce0SFan Gong #define CMDQ_WQE_HDR_BUFDESC_LEN_MASK        GENMASK(7, 0)
31*16a6fce0SFan Gong #define CMDQ_WQE_HDR_COMPLETE_FMT_MASK       BIT(15)
32*16a6fce0SFan Gong #define CMDQ_WQE_HDR_DATA_FMT_MASK           BIT(22)
33*16a6fce0SFan Gong #define CMDQ_WQE_HDR_COMPLETE_REQ_MASK       BIT(23)
34*16a6fce0SFan Gong #define CMDQ_WQE_HDR_COMPLETE_SECT_LEN_MASK  GENMASK(28, 27)
35*16a6fce0SFan Gong #define CMDQ_WQE_HDR_CTRL_LEN_MASK           GENMASK(30, 29)
36*16a6fce0SFan Gong #define CMDQ_WQE_HDR_HW_BUSY_BIT_MASK        BIT(31)
37*16a6fce0SFan Gong #define CMDQ_WQE_HDR_SET(val, member)  \
38*16a6fce0SFan Gong 	FIELD_PREP(CMDQ_WQE_HDR_##member##_MASK, val)
39*16a6fce0SFan Gong #define CMDQ_WQE_HDR_GET(val, member)  \
40*16a6fce0SFan Gong 	FIELD_GET(CMDQ_WQE_HDR_##member##_MASK, le32_to_cpu(val))
41*16a6fce0SFan Gong 
42*16a6fce0SFan Gong #define CMDQ_CTRL_PI_MASK              GENMASK(15, 0)
43*16a6fce0SFan Gong #define CMDQ_CTRL_CMD_MASK             GENMASK(23, 16)
44*16a6fce0SFan Gong #define CMDQ_CTRL_MOD_MASK             GENMASK(28, 24)
45*16a6fce0SFan Gong #define CMDQ_CTRL_HW_BUSY_BIT_MASK     BIT(31)
46*16a6fce0SFan Gong #define CMDQ_CTRL_SET(val, member)  \
47*16a6fce0SFan Gong 	FIELD_PREP(CMDQ_CTRL_##member##_MASK, val)
48*16a6fce0SFan Gong #define CMDQ_CTRL_GET(val, member)  \
49*16a6fce0SFan Gong 	FIELD_GET(CMDQ_CTRL_##member##_MASK, val)
50*16a6fce0SFan Gong 
51*16a6fce0SFan Gong #define CMDQ_WQE_ERRCODE_VAL_MASK      GENMASK(30, 0)
52*16a6fce0SFan Gong #define CMDQ_WQE_ERRCODE_GET(val, member)  \
53*16a6fce0SFan Gong 	FIELD_GET(CMDQ_WQE_ERRCODE_##member##_MASK, le32_to_cpu(val))
54*16a6fce0SFan Gong 
55*16a6fce0SFan Gong #define CMDQ_DB_INFO_HI_PROD_IDX_MASK  GENMASK(7, 0)
56*16a6fce0SFan Gong #define CMDQ_DB_INFO_SET(val, member)  \
57*16a6fce0SFan Gong 	FIELD_PREP(CMDQ_DB_INFO_##member##_MASK, val)
58*16a6fce0SFan Gong 
59*16a6fce0SFan Gong #define CMDQ_DB_HEAD_QUEUE_TYPE_MASK   BIT(23)
60*16a6fce0SFan Gong #define CMDQ_DB_HEAD_CMDQ_TYPE_MASK    GENMASK(26, 24)
61*16a6fce0SFan Gong #define CMDQ_DB_HEAD_SET(val, member)  \
62*16a6fce0SFan Gong 	FIELD_PREP(CMDQ_DB_HEAD_##member##_MASK, val)
63*16a6fce0SFan Gong 
64*16a6fce0SFan Gong #define CMDQ_CEQE_TYPE_MASK            GENMASK(2, 0)
65*16a6fce0SFan Gong #define CMDQ_CEQE_GET(val, member)  \
66*16a6fce0SFan Gong 	FIELD_GET(CMDQ_CEQE_##member##_MASK, le32_to_cpu(val))
67*16a6fce0SFan Gong 
68*16a6fce0SFan Gong #define CMDQ_WQE_HEADER(wqe)           ((struct cmdq_header *)(wqe))
69*16a6fce0SFan Gong #define CMDQ_WQE_COMPLETED(ctrl_info)  \
70*16a6fce0SFan Gong 	CMDQ_CTRL_GET(le32_to_cpu(ctrl_info), HW_BUSY_BIT)
71*16a6fce0SFan Gong 
72db03a1ceSFan Gong #define CMDQ_PFN(addr)  ((addr) >> 12)
73db03a1ceSFan Gong 
74db03a1ceSFan Gong /* cmdq work queue's chip logical address table is up to 512B */
75db03a1ceSFan Gong #define CMDQ_WQ_CLA_SIZE  512
76db03a1ceSFan Gong 
77db03a1ceSFan Gong /* Completion codes: send, direct sync, force stop */
78db03a1ceSFan Gong #define CMDQ_SEND_CMPT_CODE         10
79db03a1ceSFan Gong #define CMDQ_DIRECT_SYNC_CMPT_CODE  11
80db03a1ceSFan Gong #define CMDQ_FORCE_STOP_CMPT_CODE   12
81db03a1ceSFan Gong 
82*16a6fce0SFan Gong enum cmdq_data_format {
83*16a6fce0SFan Gong 	CMDQ_DATA_SGE    = 0,
84*16a6fce0SFan Gong 	CMDQ_DATA_DIRECT = 1,
85*16a6fce0SFan Gong };
86*16a6fce0SFan Gong 
87*16a6fce0SFan Gong enum cmdq_ctrl_sect_len {
88*16a6fce0SFan Gong 	CMDQ_CTRL_SECT_LEN        = 1,
89*16a6fce0SFan Gong 	CMDQ_CTRL_DIRECT_SECT_LEN = 2,
90*16a6fce0SFan Gong };
91*16a6fce0SFan Gong 
92*16a6fce0SFan Gong enum cmdq_bufdesc_len {
93*16a6fce0SFan Gong 	CMDQ_BUFDESC_LCMD_LEN = 2,
94*16a6fce0SFan Gong 	CMDQ_BUFDESC_SCMD_LEN = 3,
95*16a6fce0SFan Gong };
96*16a6fce0SFan Gong 
97*16a6fce0SFan Gong enum cmdq_completion_format {
98*16a6fce0SFan Gong 	CMDQ_COMPLETE_DIRECT = 0,
99*16a6fce0SFan Gong 	CMDQ_COMPLETE_SGE    = 1,
100*16a6fce0SFan Gong };
101*16a6fce0SFan Gong 
102*16a6fce0SFan Gong enum cmdq_cmd_type {
103*16a6fce0SFan Gong 	CMDQ_CMD_DIRECT_RESP,
104*16a6fce0SFan Gong 	CMDQ_CMD_SGE_RESP,
105*16a6fce0SFan Gong };
106*16a6fce0SFan Gong 
107db03a1ceSFan Gong #define CMDQ_WQE_NUM_WQEBBS  1
108db03a1ceSFan Gong 
109db03a1ceSFan Gong static struct cmdq_wqe *cmdq_read_wqe(struct hinic3_wq *wq, u16 *ci)
110db03a1ceSFan Gong {
111db03a1ceSFan Gong 	if (hinic3_wq_get_used(wq) == 0)
112db03a1ceSFan Gong 		return NULL;
113db03a1ceSFan Gong 
114db03a1ceSFan Gong 	*ci = wq->cons_idx & wq->idx_mask;
115db03a1ceSFan Gong 
116db03a1ceSFan Gong 	return get_q_element(&wq->qpages, wq->cons_idx, NULL);
117db03a1ceSFan Gong }
118db03a1ceSFan Gong 
119*16a6fce0SFan Gong struct hinic3_cmd_buf *hinic3_alloc_cmd_buf(struct hinic3_hwdev *hwdev)
120*16a6fce0SFan Gong {
121*16a6fce0SFan Gong 	struct hinic3_cmd_buf *cmd_buf;
122*16a6fce0SFan Gong 	struct hinic3_cmdqs *cmdqs;
123*16a6fce0SFan Gong 
124*16a6fce0SFan Gong 	cmdqs = hwdev->cmdqs;
125*16a6fce0SFan Gong 
126*16a6fce0SFan Gong 	cmd_buf = kmalloc(sizeof(*cmd_buf), GFP_ATOMIC);
127*16a6fce0SFan Gong 	if (!cmd_buf)
128*16a6fce0SFan Gong 		return NULL;
129*16a6fce0SFan Gong 
130*16a6fce0SFan Gong 	cmd_buf->buf = dma_pool_alloc(cmdqs->cmd_buf_pool, GFP_ATOMIC,
131*16a6fce0SFan Gong 				      &cmd_buf->dma_addr);
132*16a6fce0SFan Gong 	if (!cmd_buf->buf) {
133*16a6fce0SFan Gong 		dev_err(hwdev->dev, "Failed to allocate cmdq cmd buf from the pool\n");
134*16a6fce0SFan Gong 		goto err_free_cmd_buf;
135*16a6fce0SFan Gong 	}
136*16a6fce0SFan Gong 
137*16a6fce0SFan Gong 	cmd_buf->size = cpu_to_le16(CMDQ_BUF_SIZE);
138*16a6fce0SFan Gong 	refcount_set(&cmd_buf->ref_cnt, 1);
139*16a6fce0SFan Gong 
140*16a6fce0SFan Gong 	return cmd_buf;
141*16a6fce0SFan Gong 
142*16a6fce0SFan Gong err_free_cmd_buf:
143*16a6fce0SFan Gong 	kfree(cmd_buf);
144*16a6fce0SFan Gong 
145*16a6fce0SFan Gong 	return NULL;
146*16a6fce0SFan Gong }
147*16a6fce0SFan Gong 
148db03a1ceSFan Gong void hinic3_free_cmd_buf(struct hinic3_hwdev *hwdev,
149db03a1ceSFan Gong 			 struct hinic3_cmd_buf *cmd_buf)
150db03a1ceSFan Gong {
151db03a1ceSFan Gong 	struct hinic3_cmdqs *cmdqs;
152db03a1ceSFan Gong 
153db03a1ceSFan Gong 	if (!refcount_dec_and_test(&cmd_buf->ref_cnt))
154db03a1ceSFan Gong 		return;
155db03a1ceSFan Gong 
156db03a1ceSFan Gong 	cmdqs = hwdev->cmdqs;
157db03a1ceSFan Gong 
158db03a1ceSFan Gong 	dma_pool_free(cmdqs->cmd_buf_pool, cmd_buf->buf, cmd_buf->dma_addr);
159db03a1ceSFan Gong 	kfree(cmd_buf);
160db03a1ceSFan Gong }
161db03a1ceSFan Gong 
162db03a1ceSFan Gong static void cmdq_clear_cmd_buf(struct hinic3_cmdq_cmd_info *cmd_info,
163db03a1ceSFan Gong 			       struct hinic3_hwdev *hwdev)
164db03a1ceSFan Gong {
165db03a1ceSFan Gong 	if (cmd_info->buf_in) {
166db03a1ceSFan Gong 		hinic3_free_cmd_buf(hwdev, cmd_info->buf_in);
167db03a1ceSFan Gong 		cmd_info->buf_in = NULL;
168db03a1ceSFan Gong 	}
169db03a1ceSFan Gong }
170db03a1ceSFan Gong 
171*16a6fce0SFan Gong static void clear_wqe_complete_bit(struct hinic3_cmdq *cmdq,
172*16a6fce0SFan Gong 				   struct cmdq_wqe *wqe, u16 ci)
173*16a6fce0SFan Gong {
174*16a6fce0SFan Gong 	struct cmdq_header *hdr = CMDQ_WQE_HEADER(wqe);
175*16a6fce0SFan Gong 	__le32 header_info = hdr->header_info;
176*16a6fce0SFan Gong 	enum cmdq_data_format df;
177*16a6fce0SFan Gong 	struct cmdq_ctrl *ctrl;
178*16a6fce0SFan Gong 
179*16a6fce0SFan Gong 	df = CMDQ_WQE_HDR_GET(header_info, DATA_FMT);
180*16a6fce0SFan Gong 	if (df == CMDQ_DATA_SGE)
181*16a6fce0SFan Gong 		ctrl = &wqe->wqe_lcmd.ctrl;
182*16a6fce0SFan Gong 	else
183*16a6fce0SFan Gong 		ctrl = &wqe->wqe_scmd.ctrl;
184*16a6fce0SFan Gong 
185*16a6fce0SFan Gong 	/* clear HW busy bit */
186*16a6fce0SFan Gong 	ctrl->ctrl_info = 0;
187*16a6fce0SFan Gong 	cmdq->cmd_infos[ci].cmd_type = HINIC3_CMD_TYPE_NONE;
188*16a6fce0SFan Gong 	wmb(); /* verify wqe is clear before updating ci */
189*16a6fce0SFan Gong 	hinic3_wq_put_wqebbs(&cmdq->wq, CMDQ_WQE_NUM_WQEBBS);
190*16a6fce0SFan Gong }
191*16a6fce0SFan Gong 
192*16a6fce0SFan Gong static void cmdq_update_cmd_status(struct hinic3_cmdq *cmdq, u16 prod_idx,
193*16a6fce0SFan Gong 				   struct cmdq_wqe *wqe)
194*16a6fce0SFan Gong {
195*16a6fce0SFan Gong 	struct hinic3_cmdq_cmd_info *cmd_info;
196*16a6fce0SFan Gong 	struct cmdq_wqe_lcmd *wqe_lcmd;
197*16a6fce0SFan Gong 	__le32 status_info;
198*16a6fce0SFan Gong 
199*16a6fce0SFan Gong 	wqe_lcmd = &wqe->wqe_lcmd;
200*16a6fce0SFan Gong 	cmd_info = &cmdq->cmd_infos[prod_idx];
201*16a6fce0SFan Gong 	if (cmd_info->errcode) {
202*16a6fce0SFan Gong 		status_info = wqe_lcmd->status.status_info;
203*16a6fce0SFan Gong 		*cmd_info->errcode = CMDQ_WQE_ERRCODE_GET(status_info, VAL);
204*16a6fce0SFan Gong 	}
205*16a6fce0SFan Gong 
206*16a6fce0SFan Gong 	if (cmd_info->direct_resp)
207*16a6fce0SFan Gong 		*cmd_info->direct_resp = wqe_lcmd->completion.resp.direct.val;
208*16a6fce0SFan Gong }
209*16a6fce0SFan Gong 
210*16a6fce0SFan Gong static void cmdq_sync_cmd_handler(struct hinic3_cmdq *cmdq,
211*16a6fce0SFan Gong 				  struct cmdq_wqe *wqe, u16 ci)
212*16a6fce0SFan Gong {
213*16a6fce0SFan Gong 	spin_lock(&cmdq->cmdq_lock);
214*16a6fce0SFan Gong 	cmdq_update_cmd_status(cmdq, ci, wqe);
215*16a6fce0SFan Gong 	if (cmdq->cmd_infos[ci].cmpt_code) {
216*16a6fce0SFan Gong 		*cmdq->cmd_infos[ci].cmpt_code = CMDQ_DIRECT_SYNC_CMPT_CODE;
217*16a6fce0SFan Gong 		cmdq->cmd_infos[ci].cmpt_code = NULL;
218*16a6fce0SFan Gong 	}
219*16a6fce0SFan Gong 
220*16a6fce0SFan Gong 	/* Ensure that completion code has been updated before updating done */
221*16a6fce0SFan Gong 	smp_wmb();
222*16a6fce0SFan Gong 	if (cmdq->cmd_infos[ci].done) {
223*16a6fce0SFan Gong 		complete(cmdq->cmd_infos[ci].done);
224*16a6fce0SFan Gong 		cmdq->cmd_infos[ci].done = NULL;
225*16a6fce0SFan Gong 	}
226*16a6fce0SFan Gong 	spin_unlock(&cmdq->cmdq_lock);
227*16a6fce0SFan Gong 
228*16a6fce0SFan Gong 	cmdq_clear_cmd_buf(&cmdq->cmd_infos[ci], cmdq->hwdev);
229*16a6fce0SFan Gong 	clear_wqe_complete_bit(cmdq, wqe, ci);
230*16a6fce0SFan Gong }
231*16a6fce0SFan Gong 
232*16a6fce0SFan Gong void hinic3_cmdq_ceq_handler(struct hinic3_hwdev *hwdev, __le32 ceqe_data)
233*16a6fce0SFan Gong {
234*16a6fce0SFan Gong 	enum hinic3_cmdq_type cmdq_type = CMDQ_CEQE_GET(ceqe_data, TYPE);
235*16a6fce0SFan Gong 	struct hinic3_cmdqs *cmdqs = hwdev->cmdqs;
236*16a6fce0SFan Gong 	struct hinic3_cmdq_cmd_info *cmd_info;
237*16a6fce0SFan Gong 	struct cmdq_wqe_lcmd *wqe_lcmd;
238*16a6fce0SFan Gong 	struct hinic3_cmdq *cmdq;
239*16a6fce0SFan Gong 	struct cmdq_wqe *wqe;
240*16a6fce0SFan Gong 	__le32 ctrl_info;
241*16a6fce0SFan Gong 	u16 ci;
242*16a6fce0SFan Gong 
243*16a6fce0SFan Gong 	if (unlikely(cmdq_type >= ARRAY_SIZE(cmdqs->cmdq)))
244*16a6fce0SFan Gong 		return;
245*16a6fce0SFan Gong 
246*16a6fce0SFan Gong 	cmdq = &cmdqs->cmdq[cmdq_type];
247*16a6fce0SFan Gong 	while ((wqe = cmdq_read_wqe(&cmdq->wq, &ci)) != NULL) {
248*16a6fce0SFan Gong 		cmd_info = &cmdq->cmd_infos[ci];
249*16a6fce0SFan Gong 		switch (cmd_info->cmd_type) {
250*16a6fce0SFan Gong 		case HINIC3_CMD_TYPE_NONE:
251*16a6fce0SFan Gong 			return;
252*16a6fce0SFan Gong 		case HINIC3_CMD_TYPE_TIMEOUT:
253*16a6fce0SFan Gong 			dev_warn(hwdev->dev, "Cmdq timeout, q_id: %u, ci: %u\n",
254*16a6fce0SFan Gong 				 cmdq_type, ci);
255*16a6fce0SFan Gong 			fallthrough;
256*16a6fce0SFan Gong 		case HINIC3_CMD_TYPE_FAKE_TIMEOUT:
257*16a6fce0SFan Gong 			cmdq_clear_cmd_buf(cmd_info, hwdev);
258*16a6fce0SFan Gong 			clear_wqe_complete_bit(cmdq, wqe, ci);
259*16a6fce0SFan Gong 			break;
260*16a6fce0SFan Gong 		default:
261*16a6fce0SFan Gong 			/* only arm bit is using scmd wqe,
262*16a6fce0SFan Gong 			 * the other wqe is lcmd
263*16a6fce0SFan Gong 			 */
264*16a6fce0SFan Gong 			wqe_lcmd = &wqe->wqe_lcmd;
265*16a6fce0SFan Gong 			ctrl_info = wqe_lcmd->ctrl.ctrl_info;
266*16a6fce0SFan Gong 			if (!CMDQ_WQE_COMPLETED(ctrl_info))
267*16a6fce0SFan Gong 				return;
268*16a6fce0SFan Gong 
269*16a6fce0SFan Gong 			dma_rmb();
270*16a6fce0SFan Gong 			/* For FORCE_STOP cmd_type, we also need to wait for
271*16a6fce0SFan Gong 			 * the firmware processing to complete to prevent the
272*16a6fce0SFan Gong 			 * firmware from accessing the released cmd_buf
273*16a6fce0SFan Gong 			 */
274*16a6fce0SFan Gong 			if (cmd_info->cmd_type == HINIC3_CMD_TYPE_FORCE_STOP) {
275*16a6fce0SFan Gong 				cmdq_clear_cmd_buf(cmd_info, hwdev);
276*16a6fce0SFan Gong 				clear_wqe_complete_bit(cmdq, wqe, ci);
277*16a6fce0SFan Gong 			} else {
278*16a6fce0SFan Gong 				cmdq_sync_cmd_handler(cmdq, wqe, ci);
279*16a6fce0SFan Gong 			}
280*16a6fce0SFan Gong 
281*16a6fce0SFan Gong 			break;
282*16a6fce0SFan Gong 		}
283*16a6fce0SFan Gong 	}
284*16a6fce0SFan Gong }
285*16a6fce0SFan Gong 
286*16a6fce0SFan Gong static int wait_cmdqs_enable(struct hinic3_cmdqs *cmdqs)
287*16a6fce0SFan Gong {
288*16a6fce0SFan Gong 	unsigned long end;
289*16a6fce0SFan Gong 
290*16a6fce0SFan Gong 	end = jiffies + msecs_to_jiffies(CMDQ_ENABLE_WAIT_TIMEOUT);
291*16a6fce0SFan Gong 	do {
292*16a6fce0SFan Gong 		if (cmdqs->status & HINIC3_CMDQ_ENABLE)
293*16a6fce0SFan Gong 			return 0;
294*16a6fce0SFan Gong 		usleep_range(1000, 2000);
295*16a6fce0SFan Gong 	} while (time_before(jiffies, end) && !cmdqs->disable_flag);
296*16a6fce0SFan Gong 
297*16a6fce0SFan Gong 	cmdqs->disable_flag = 1;
298*16a6fce0SFan Gong 
299*16a6fce0SFan Gong 	return -EBUSY;
300*16a6fce0SFan Gong }
301*16a6fce0SFan Gong 
302*16a6fce0SFan Gong static void cmdq_set_completion(struct cmdq_completion *complete,
303*16a6fce0SFan Gong 				struct hinic3_cmd_buf *buf_out)
304*16a6fce0SFan Gong {
305*16a6fce0SFan Gong 	struct hinic3_sge *sge = &complete->resp.sge;
306*16a6fce0SFan Gong 
307*16a6fce0SFan Gong 	hinic3_set_sge(sge, buf_out->dma_addr, cpu_to_le32(CMDQ_BUF_SIZE));
308*16a6fce0SFan Gong }
309*16a6fce0SFan Gong 
310*16a6fce0SFan Gong static struct cmdq_wqe *cmdq_get_wqe(struct hinic3_wq *wq, u16 *pi)
311*16a6fce0SFan Gong {
312*16a6fce0SFan Gong 	if (!hinic3_wq_free_wqebbs(wq))
313*16a6fce0SFan Gong 		return NULL;
314*16a6fce0SFan Gong 
315*16a6fce0SFan Gong 	return hinic3_wq_get_one_wqebb(wq, pi);
316*16a6fce0SFan Gong }
317*16a6fce0SFan Gong 
318*16a6fce0SFan Gong static void cmdq_set_lcmd_bufdesc(struct cmdq_wqe_lcmd *wqe,
319*16a6fce0SFan Gong 				  struct hinic3_cmd_buf *buf_in)
320*16a6fce0SFan Gong {
321*16a6fce0SFan Gong 	hinic3_set_sge(&wqe->buf_desc.sge, buf_in->dma_addr,
322*16a6fce0SFan Gong 		       (__force __le32)buf_in->size);
323*16a6fce0SFan Gong }
324*16a6fce0SFan Gong 
325*16a6fce0SFan Gong static void cmdq_set_db(struct hinic3_cmdq *cmdq,
326*16a6fce0SFan Gong 			enum hinic3_cmdq_type cmdq_type, u16 prod_idx)
327*16a6fce0SFan Gong {
328*16a6fce0SFan Gong 	u8 __iomem *db_base = cmdq->hwdev->cmdqs->cmdqs_db_base;
329*16a6fce0SFan Gong 	u16 db_ofs = (prod_idx & 0xFF) << 3;
330*16a6fce0SFan Gong 	struct cmdq_db db;
331*16a6fce0SFan Gong 
332*16a6fce0SFan Gong 	db.db_info = cpu_to_le32(CMDQ_DB_INFO_SET(prod_idx >> 8, HI_PROD_IDX));
333*16a6fce0SFan Gong 	db.db_head = cpu_to_le32(CMDQ_DB_HEAD_SET(1, QUEUE_TYPE) |
334*16a6fce0SFan Gong 				 CMDQ_DB_HEAD_SET(cmdq_type, CMDQ_TYPE));
335*16a6fce0SFan Gong 	writeq(*(u64 *)&db, db_base + db_ofs);
336*16a6fce0SFan Gong }
337*16a6fce0SFan Gong 
338*16a6fce0SFan Gong static void cmdq_wqe_fill(struct cmdq_wqe *hw_wqe,
339*16a6fce0SFan Gong 			  const struct cmdq_wqe *shadow_wqe)
340*16a6fce0SFan Gong {
341*16a6fce0SFan Gong 	const struct cmdq_header *src = (struct cmdq_header *)shadow_wqe;
342*16a6fce0SFan Gong 	struct cmdq_header *dst = (struct cmdq_header *)hw_wqe;
343*16a6fce0SFan Gong 	size_t len;
344*16a6fce0SFan Gong 
345*16a6fce0SFan Gong 	len = sizeof(struct cmdq_wqe) - sizeof(struct cmdq_header);
346*16a6fce0SFan Gong 	memcpy(dst + 1, src + 1, len);
347*16a6fce0SFan Gong 	/* Ensure buffer len before updating header */
348*16a6fce0SFan Gong 	wmb();
349*16a6fce0SFan Gong 	WRITE_ONCE(*dst, *src);
350*16a6fce0SFan Gong }
351*16a6fce0SFan Gong 
352*16a6fce0SFan Gong static void cmdq_prepare_wqe_ctrl(struct cmdq_wqe *wqe, u8 wrapped,
353*16a6fce0SFan Gong 				  u8 mod, u8 cmd, u16 prod_idx,
354*16a6fce0SFan Gong 				  enum cmdq_completion_format complete_format,
355*16a6fce0SFan Gong 				  enum cmdq_data_format data_format,
356*16a6fce0SFan Gong 				  enum cmdq_bufdesc_len buf_len)
357*16a6fce0SFan Gong {
358*16a6fce0SFan Gong 	struct cmdq_header *hdr = CMDQ_WQE_HEADER(wqe);
359*16a6fce0SFan Gong 	enum cmdq_ctrl_sect_len ctrl_len;
360*16a6fce0SFan Gong 	struct cmdq_wqe_lcmd *wqe_lcmd;
361*16a6fce0SFan Gong 	struct cmdq_wqe_scmd *wqe_scmd;
362*16a6fce0SFan Gong 	struct cmdq_ctrl *ctrl;
363*16a6fce0SFan Gong 
364*16a6fce0SFan Gong 	if (data_format == CMDQ_DATA_SGE) {
365*16a6fce0SFan Gong 		wqe_lcmd = &wqe->wqe_lcmd;
366*16a6fce0SFan Gong 		wqe_lcmd->status.status_info = 0;
367*16a6fce0SFan Gong 		ctrl = &wqe_lcmd->ctrl;
368*16a6fce0SFan Gong 		ctrl_len = CMDQ_CTRL_SECT_LEN;
369*16a6fce0SFan Gong 	} else {
370*16a6fce0SFan Gong 		wqe_scmd = &wqe->wqe_scmd;
371*16a6fce0SFan Gong 		wqe_scmd->status.status_info = 0;
372*16a6fce0SFan Gong 		ctrl = &wqe_scmd->ctrl;
373*16a6fce0SFan Gong 		ctrl_len = CMDQ_CTRL_DIRECT_SECT_LEN;
374*16a6fce0SFan Gong 	}
375*16a6fce0SFan Gong 
376*16a6fce0SFan Gong 	ctrl->ctrl_info =
377*16a6fce0SFan Gong 		cpu_to_le32(CMDQ_CTRL_SET(prod_idx, PI) |
378*16a6fce0SFan Gong 			    CMDQ_CTRL_SET(cmd, CMD) |
379*16a6fce0SFan Gong 			    CMDQ_CTRL_SET(mod, MOD));
380*16a6fce0SFan Gong 
381*16a6fce0SFan Gong 	hdr->header_info =
382*16a6fce0SFan Gong 		cpu_to_le32(CMDQ_WQE_HDR_SET(buf_len, BUFDESC_LEN) |
383*16a6fce0SFan Gong 			    CMDQ_WQE_HDR_SET(complete_format, COMPLETE_FMT) |
384*16a6fce0SFan Gong 			    CMDQ_WQE_HDR_SET(data_format, DATA_FMT) |
385*16a6fce0SFan Gong 			    CMDQ_WQE_HDR_SET(1, COMPLETE_REQ) |
386*16a6fce0SFan Gong 			    CMDQ_WQE_HDR_SET(3, COMPLETE_SECT_LEN) |
387*16a6fce0SFan Gong 			    CMDQ_WQE_HDR_SET(ctrl_len, CTRL_LEN) |
388*16a6fce0SFan Gong 			    CMDQ_WQE_HDR_SET(wrapped, HW_BUSY_BIT));
389*16a6fce0SFan Gong }
390*16a6fce0SFan Gong 
391*16a6fce0SFan Gong static void cmdq_set_lcmd_wqe(struct cmdq_wqe *wqe,
392*16a6fce0SFan Gong 			      enum cmdq_cmd_type cmd_type,
393*16a6fce0SFan Gong 			      struct hinic3_cmd_buf *buf_in,
394*16a6fce0SFan Gong 			      struct hinic3_cmd_buf *buf_out,
395*16a6fce0SFan Gong 			      u8 wrapped, u8 mod, u8 cmd, u16 prod_idx)
396*16a6fce0SFan Gong {
397*16a6fce0SFan Gong 	enum cmdq_completion_format complete_format = CMDQ_COMPLETE_DIRECT;
398*16a6fce0SFan Gong 	struct cmdq_wqe_lcmd *wqe_lcmd = &wqe->wqe_lcmd;
399*16a6fce0SFan Gong 
400*16a6fce0SFan Gong 	switch (cmd_type) {
401*16a6fce0SFan Gong 	case CMDQ_CMD_DIRECT_RESP:
402*16a6fce0SFan Gong 		wqe_lcmd->completion.resp.direct.val = 0;
403*16a6fce0SFan Gong 		break;
404*16a6fce0SFan Gong 	case CMDQ_CMD_SGE_RESP:
405*16a6fce0SFan Gong 		if (buf_out) {
406*16a6fce0SFan Gong 			complete_format = CMDQ_COMPLETE_SGE;
407*16a6fce0SFan Gong 			cmdq_set_completion(&wqe_lcmd->completion, buf_out);
408*16a6fce0SFan Gong 		}
409*16a6fce0SFan Gong 		break;
410*16a6fce0SFan Gong 	}
411*16a6fce0SFan Gong 
412*16a6fce0SFan Gong 	cmdq_prepare_wqe_ctrl(wqe, wrapped, mod, cmd, prod_idx, complete_format,
413*16a6fce0SFan Gong 			      CMDQ_DATA_SGE, CMDQ_BUFDESC_LCMD_LEN);
414*16a6fce0SFan Gong 	cmdq_set_lcmd_bufdesc(wqe_lcmd, buf_in);
415*16a6fce0SFan Gong }
416*16a6fce0SFan Gong 
417*16a6fce0SFan Gong static int hinic3_cmdq_sync_timeout_check(struct hinic3_cmdq *cmdq,
418*16a6fce0SFan Gong 					  struct cmdq_wqe *wqe, u16 pi)
419*16a6fce0SFan Gong {
420*16a6fce0SFan Gong 	struct cmdq_wqe_lcmd *wqe_lcmd;
421*16a6fce0SFan Gong 	struct cmdq_ctrl *ctrl;
422*16a6fce0SFan Gong 	__le32 ctrl_info;
423*16a6fce0SFan Gong 
424*16a6fce0SFan Gong 	wqe_lcmd = &wqe->wqe_lcmd;
425*16a6fce0SFan Gong 	ctrl = &wqe_lcmd->ctrl;
426*16a6fce0SFan Gong 	ctrl_info = ctrl->ctrl_info;
427*16a6fce0SFan Gong 	if (!CMDQ_WQE_COMPLETED(ctrl_info)) {
428*16a6fce0SFan Gong 		dev_dbg(cmdq->hwdev->dev, "Cmdq sync command check busy bit not set\n");
429*16a6fce0SFan Gong 		return -EFAULT;
430*16a6fce0SFan Gong 	}
431*16a6fce0SFan Gong 	cmdq_update_cmd_status(cmdq, pi, wqe);
432*16a6fce0SFan Gong 
433*16a6fce0SFan Gong 	return 0;
434*16a6fce0SFan Gong }
435*16a6fce0SFan Gong 
436*16a6fce0SFan Gong static void clear_cmd_info(struct hinic3_cmdq_cmd_info *cmd_info,
437*16a6fce0SFan Gong 			   const struct hinic3_cmdq_cmd_info *saved_cmd_info)
438*16a6fce0SFan Gong {
439*16a6fce0SFan Gong 	if (cmd_info->errcode == saved_cmd_info->errcode)
440*16a6fce0SFan Gong 		cmd_info->errcode = NULL;
441*16a6fce0SFan Gong 
442*16a6fce0SFan Gong 	if (cmd_info->done == saved_cmd_info->done)
443*16a6fce0SFan Gong 		cmd_info->done = NULL;
444*16a6fce0SFan Gong 
445*16a6fce0SFan Gong 	if (cmd_info->direct_resp == saved_cmd_info->direct_resp)
446*16a6fce0SFan Gong 		cmd_info->direct_resp = NULL;
447*16a6fce0SFan Gong }
448*16a6fce0SFan Gong 
449*16a6fce0SFan Gong static int wait_cmdq_sync_cmd_completion(struct hinic3_cmdq *cmdq,
450*16a6fce0SFan Gong 					 struct hinic3_cmdq_cmd_info *cmd_info,
451*16a6fce0SFan Gong 					 struct hinic3_cmdq_cmd_info *saved_cmd_info,
452*16a6fce0SFan Gong 					 u64 curr_msg_id, u16 curr_prod_idx,
453*16a6fce0SFan Gong 					 struct cmdq_wqe *curr_wqe,
454*16a6fce0SFan Gong 					 u32 timeout)
455*16a6fce0SFan Gong {
456*16a6fce0SFan Gong 	ulong timeo = msecs_to_jiffies(timeout);
457*16a6fce0SFan Gong 	int err;
458*16a6fce0SFan Gong 
459*16a6fce0SFan Gong 	if (wait_for_completion_timeout(saved_cmd_info->done, timeo))
460*16a6fce0SFan Gong 		return 0;
461*16a6fce0SFan Gong 
462*16a6fce0SFan Gong 	spin_lock_bh(&cmdq->cmdq_lock);
463*16a6fce0SFan Gong 	if (cmd_info->cmpt_code == saved_cmd_info->cmpt_code)
464*16a6fce0SFan Gong 		cmd_info->cmpt_code = NULL;
465*16a6fce0SFan Gong 
466*16a6fce0SFan Gong 	if (*saved_cmd_info->cmpt_code == CMDQ_DIRECT_SYNC_CMPT_CODE) {
467*16a6fce0SFan Gong 		dev_dbg(cmdq->hwdev->dev, "Cmdq direct sync command has been completed\n");
468*16a6fce0SFan Gong 		spin_unlock_bh(&cmdq->cmdq_lock);
469*16a6fce0SFan Gong 		return 0;
470*16a6fce0SFan Gong 	}
471*16a6fce0SFan Gong 
472*16a6fce0SFan Gong 	if (curr_msg_id == cmd_info->cmdq_msg_id) {
473*16a6fce0SFan Gong 		err = hinic3_cmdq_sync_timeout_check(cmdq, curr_wqe,
474*16a6fce0SFan Gong 						     curr_prod_idx);
475*16a6fce0SFan Gong 		if (err)
476*16a6fce0SFan Gong 			cmd_info->cmd_type = HINIC3_CMD_TYPE_TIMEOUT;
477*16a6fce0SFan Gong 		else
478*16a6fce0SFan Gong 			cmd_info->cmd_type = HINIC3_CMD_TYPE_FAKE_TIMEOUT;
479*16a6fce0SFan Gong 	} else {
480*16a6fce0SFan Gong 		err = -ETIMEDOUT;
481*16a6fce0SFan Gong 		dev_err(cmdq->hwdev->dev,
482*16a6fce0SFan Gong 			"Cmdq sync command current msg id mismatch cmd_info msg id\n");
483*16a6fce0SFan Gong 	}
484*16a6fce0SFan Gong 
485*16a6fce0SFan Gong 	clear_cmd_info(cmd_info, saved_cmd_info);
486*16a6fce0SFan Gong 	spin_unlock_bh(&cmdq->cmdq_lock);
487*16a6fce0SFan Gong 
488*16a6fce0SFan Gong 	return err;
489*16a6fce0SFan Gong }
490*16a6fce0SFan Gong 
491*16a6fce0SFan Gong static int cmdq_sync_cmd_direct_resp(struct hinic3_cmdq *cmdq, u8 mod, u8 cmd,
492*16a6fce0SFan Gong 				     struct hinic3_cmd_buf *buf_in,
493*16a6fce0SFan Gong 				     __le64 *out_param)
494*16a6fce0SFan Gong {
495*16a6fce0SFan Gong 	struct hinic3_cmdq_cmd_info *cmd_info, saved_cmd_info;
496*16a6fce0SFan Gong 	int cmpt_code = CMDQ_SEND_CMPT_CODE;
497*16a6fce0SFan Gong 	struct cmdq_wqe *curr_wqe, wqe = {};
498*16a6fce0SFan Gong 	struct hinic3_wq *wq = &cmdq->wq;
499*16a6fce0SFan Gong 	u16 curr_prod_idx, next_prod_idx;
500*16a6fce0SFan Gong 	struct completion done;
501*16a6fce0SFan Gong 	u64 curr_msg_id;
502*16a6fce0SFan Gong 	int errcode;
503*16a6fce0SFan Gong 	u8 wrapped;
504*16a6fce0SFan Gong 	int err;
505*16a6fce0SFan Gong 
506*16a6fce0SFan Gong 	spin_lock_bh(&cmdq->cmdq_lock);
507*16a6fce0SFan Gong 	curr_wqe = cmdq_get_wqe(wq, &curr_prod_idx);
508*16a6fce0SFan Gong 	if (!curr_wqe) {
509*16a6fce0SFan Gong 		spin_unlock_bh(&cmdq->cmdq_lock);
510*16a6fce0SFan Gong 		return -EBUSY;
511*16a6fce0SFan Gong 	}
512*16a6fce0SFan Gong 
513*16a6fce0SFan Gong 	wrapped = cmdq->wrapped;
514*16a6fce0SFan Gong 	next_prod_idx = curr_prod_idx + CMDQ_WQE_NUM_WQEBBS;
515*16a6fce0SFan Gong 	if (next_prod_idx >= wq->q_depth) {
516*16a6fce0SFan Gong 		cmdq->wrapped ^= 1;
517*16a6fce0SFan Gong 		next_prod_idx -= wq->q_depth;
518*16a6fce0SFan Gong 	}
519*16a6fce0SFan Gong 
520*16a6fce0SFan Gong 	cmd_info = &cmdq->cmd_infos[curr_prod_idx];
521*16a6fce0SFan Gong 	init_completion(&done);
522*16a6fce0SFan Gong 	refcount_inc(&buf_in->ref_cnt);
523*16a6fce0SFan Gong 	cmd_info->cmd_type = HINIC3_CMD_TYPE_DIRECT_RESP;
524*16a6fce0SFan Gong 	cmd_info->done = &done;
525*16a6fce0SFan Gong 	cmd_info->errcode = &errcode;
526*16a6fce0SFan Gong 	cmd_info->direct_resp = out_param;
527*16a6fce0SFan Gong 	cmd_info->cmpt_code = &cmpt_code;
528*16a6fce0SFan Gong 	cmd_info->buf_in = buf_in;
529*16a6fce0SFan Gong 	saved_cmd_info = *cmd_info;
530*16a6fce0SFan Gong 	cmdq_set_lcmd_wqe(&wqe, CMDQ_CMD_DIRECT_RESP, buf_in, NULL,
531*16a6fce0SFan Gong 			  wrapped, mod, cmd, curr_prod_idx);
532*16a6fce0SFan Gong 
533*16a6fce0SFan Gong 	cmdq_wqe_fill(curr_wqe, &wqe);
534*16a6fce0SFan Gong 	(cmd_info->cmdq_msg_id)++;
535*16a6fce0SFan Gong 	curr_msg_id = cmd_info->cmdq_msg_id;
536*16a6fce0SFan Gong 	cmdq_set_db(cmdq, HINIC3_CMDQ_SYNC, next_prod_idx);
537*16a6fce0SFan Gong 	spin_unlock_bh(&cmdq->cmdq_lock);
538*16a6fce0SFan Gong 
539*16a6fce0SFan Gong 	err = wait_cmdq_sync_cmd_completion(cmdq, cmd_info, &saved_cmd_info,
540*16a6fce0SFan Gong 					    curr_msg_id, curr_prod_idx,
541*16a6fce0SFan Gong 					    curr_wqe, CMDQ_CMD_TIMEOUT);
542*16a6fce0SFan Gong 	if (err) {
543*16a6fce0SFan Gong 		dev_err(cmdq->hwdev->dev,
544*16a6fce0SFan Gong 			"Cmdq sync command timeout, mod: %u, cmd: %u, prod idx: 0x%x\n",
545*16a6fce0SFan Gong 			mod, cmd, curr_prod_idx);
546*16a6fce0SFan Gong 		err = -ETIMEDOUT;
547*16a6fce0SFan Gong 	}
548*16a6fce0SFan Gong 
549*16a6fce0SFan Gong 	if (cmpt_code == CMDQ_FORCE_STOP_CMPT_CODE) {
550*16a6fce0SFan Gong 		dev_dbg(cmdq->hwdev->dev,
551*16a6fce0SFan Gong 			"Force stop cmdq cmd, mod: %u, cmd: %u\n", mod, cmd);
552*16a6fce0SFan Gong 		err = -EAGAIN;
553*16a6fce0SFan Gong 	}
554*16a6fce0SFan Gong 
555*16a6fce0SFan Gong 	smp_rmb(); /* read error code after completion */
556*16a6fce0SFan Gong 
557*16a6fce0SFan Gong 	return err ? err : errcode;
558*16a6fce0SFan Gong }
559*16a6fce0SFan Gong 
560*16a6fce0SFan Gong int hinic3_cmdq_direct_resp(struct hinic3_hwdev *hwdev, u8 mod, u8 cmd,
561*16a6fce0SFan Gong 			    struct hinic3_cmd_buf *buf_in, __le64 *out_param)
562*16a6fce0SFan Gong {
563*16a6fce0SFan Gong 	struct hinic3_cmdqs *cmdqs;
564*16a6fce0SFan Gong 	int err;
565*16a6fce0SFan Gong 
566*16a6fce0SFan Gong 	cmdqs = hwdev->cmdqs;
567*16a6fce0SFan Gong 	err = wait_cmdqs_enable(cmdqs);
568*16a6fce0SFan Gong 	if (err) {
569*16a6fce0SFan Gong 		dev_err(hwdev->dev, "Cmdq is disabled\n");
570*16a6fce0SFan Gong 		return err;
571*16a6fce0SFan Gong 	}
572*16a6fce0SFan Gong 
573*16a6fce0SFan Gong 	err = cmdq_sync_cmd_direct_resp(&cmdqs->cmdq[HINIC3_CMDQ_SYNC],
574*16a6fce0SFan Gong 					mod, cmd, buf_in, out_param);
575*16a6fce0SFan Gong 
576*16a6fce0SFan Gong 	return err;
577*16a6fce0SFan Gong }
578*16a6fce0SFan Gong 
579db03a1ceSFan Gong static void cmdq_init_queue_ctxt(struct hinic3_hwdev *hwdev, u8 cmdq_id,
580db03a1ceSFan Gong 				 struct comm_cmdq_ctxt_info *ctxt_info)
581db03a1ceSFan Gong {
582db03a1ceSFan Gong 	const struct hinic3_cmdqs *cmdqs;
583db03a1ceSFan Gong 	u64 cmdq_first_block_paddr, pfn;
584db03a1ceSFan Gong 	const struct hinic3_wq *wq;
585db03a1ceSFan Gong 
586db03a1ceSFan Gong 	cmdqs = hwdev->cmdqs;
587db03a1ceSFan Gong 	wq = &cmdqs->cmdq[cmdq_id].wq;
588db03a1ceSFan Gong 	pfn = CMDQ_PFN(hinic3_wq_get_first_wqe_page_addr(wq));
589db03a1ceSFan Gong 
590db03a1ceSFan Gong 	ctxt_info->curr_wqe_page_pfn =
591db03a1ceSFan Gong 		cpu_to_le64(CMDQ_CTXT_SET(1, HW_BUSY_BIT) |
592db03a1ceSFan Gong 			    CMDQ_CTXT_SET(1, CEQ_EN)	|
593db03a1ceSFan Gong 			    CMDQ_CTXT_SET(1, CEQ_ARM)	|
594db03a1ceSFan Gong 			    CMDQ_CTXT_SET(0, EQ_ID) |
595db03a1ceSFan Gong 			    CMDQ_CTXT_SET(pfn, CURR_WQE_PAGE_PFN));
596db03a1ceSFan Gong 
597db03a1ceSFan Gong 	if (!hinic3_wq_is_0_level_cla(wq)) {
598db03a1ceSFan Gong 		cmdq_first_block_paddr = cmdqs->wq_block_paddr;
599db03a1ceSFan Gong 		pfn = CMDQ_PFN(cmdq_first_block_paddr);
600db03a1ceSFan Gong 	}
601db03a1ceSFan Gong 
602db03a1ceSFan Gong 	ctxt_info->wq_block_pfn = cpu_to_le64(CMDQ_CTXT_SET(wq->cons_idx, CI) |
603db03a1ceSFan Gong 					      CMDQ_CTXT_SET(pfn, WQ_BLOCK_PFN));
604db03a1ceSFan Gong }
605db03a1ceSFan Gong 
606db03a1ceSFan Gong static int init_cmdq(struct hinic3_cmdq *cmdq, struct hinic3_hwdev *hwdev,
607db03a1ceSFan Gong 		     enum hinic3_cmdq_type q_type)
608db03a1ceSFan Gong {
609db03a1ceSFan Gong 	int err;
610db03a1ceSFan Gong 
611db03a1ceSFan Gong 	cmdq->cmdq_type = q_type;
612db03a1ceSFan Gong 	cmdq->wrapped = 1;
613db03a1ceSFan Gong 	cmdq->hwdev = hwdev;
614db03a1ceSFan Gong 
615db03a1ceSFan Gong 	spin_lock_init(&cmdq->cmdq_lock);
616db03a1ceSFan Gong 
617db03a1ceSFan Gong 	cmdq->cmd_infos = kcalloc(cmdq->wq.q_depth, sizeof(*cmdq->cmd_infos),
618db03a1ceSFan Gong 				  GFP_KERNEL);
619db03a1ceSFan Gong 	if (!cmdq->cmd_infos) {
620db03a1ceSFan Gong 		err = -ENOMEM;
621db03a1ceSFan Gong 		return err;
622db03a1ceSFan Gong 	}
623db03a1ceSFan Gong 
624db03a1ceSFan Gong 	return 0;
625db03a1ceSFan Gong }
626db03a1ceSFan Gong 
627db03a1ceSFan Gong static int hinic3_set_cmdq_ctxt(struct hinic3_hwdev *hwdev, u8 cmdq_id)
628db03a1ceSFan Gong {
629db03a1ceSFan Gong 	struct comm_cmd_set_cmdq_ctxt cmdq_ctxt = {};
630db03a1ceSFan Gong 	struct mgmt_msg_params msg_params = {};
631db03a1ceSFan Gong 	int err;
632db03a1ceSFan Gong 
633db03a1ceSFan Gong 	cmdq_init_queue_ctxt(hwdev, cmdq_id, &cmdq_ctxt.ctxt);
634db03a1ceSFan Gong 	cmdq_ctxt.func_id = hinic3_global_func_id(hwdev);
635db03a1ceSFan Gong 	cmdq_ctxt.cmdq_id = cmdq_id;
636db03a1ceSFan Gong 
637db03a1ceSFan Gong 	mgmt_msg_params_init_default(&msg_params, &cmdq_ctxt,
638db03a1ceSFan Gong 				     sizeof(cmdq_ctxt));
639db03a1ceSFan Gong 
640db03a1ceSFan Gong 	err = hinic3_send_mbox_to_mgmt(hwdev, MGMT_MOD_COMM,
641db03a1ceSFan Gong 				       COMM_CMD_SET_CMDQ_CTXT, &msg_params);
642db03a1ceSFan Gong 	if (err || cmdq_ctxt.head.status) {
643db03a1ceSFan Gong 		dev_err(hwdev->dev, "Failed to set cmdq ctxt, err: %d, status: 0x%x\n",
644db03a1ceSFan Gong 			err, cmdq_ctxt.head.status);
645db03a1ceSFan Gong 		return -EFAULT;
646db03a1ceSFan Gong 	}
647db03a1ceSFan Gong 
648db03a1ceSFan Gong 	return 0;
649db03a1ceSFan Gong }
650db03a1ceSFan Gong 
651db03a1ceSFan Gong static int hinic3_set_cmdq_ctxts(struct hinic3_hwdev *hwdev)
652db03a1ceSFan Gong {
653db03a1ceSFan Gong 	struct hinic3_cmdqs *cmdqs = hwdev->cmdqs;
654db03a1ceSFan Gong 	u8 cmdq_type;
655db03a1ceSFan Gong 	int err;
656db03a1ceSFan Gong 
657db03a1ceSFan Gong 	for (cmdq_type = 0; cmdq_type < cmdqs->cmdq_num; cmdq_type++) {
658db03a1ceSFan Gong 		err = hinic3_set_cmdq_ctxt(hwdev, cmdq_type);
659db03a1ceSFan Gong 		if (err)
660db03a1ceSFan Gong 			return err;
661db03a1ceSFan Gong 	}
662db03a1ceSFan Gong 
663db03a1ceSFan Gong 	cmdqs->status |= HINIC3_CMDQ_ENABLE;
664db03a1ceSFan Gong 	cmdqs->disable_flag = 0;
665db03a1ceSFan Gong 
666db03a1ceSFan Gong 	return 0;
667db03a1ceSFan Gong }
668db03a1ceSFan Gong 
669db03a1ceSFan Gong static int create_cmdq_wq(struct hinic3_hwdev *hwdev,
670db03a1ceSFan Gong 			  struct hinic3_cmdqs *cmdqs)
671db03a1ceSFan Gong {
672db03a1ceSFan Gong 	u8 cmdq_type;
673db03a1ceSFan Gong 	int err;
674db03a1ceSFan Gong 
675db03a1ceSFan Gong 	for (cmdq_type = 0; cmdq_type < cmdqs->cmdq_num; cmdq_type++) {
676db03a1ceSFan Gong 		err = hinic3_wq_create(hwdev, &cmdqs->cmdq[cmdq_type].wq,
677db03a1ceSFan Gong 				       CMDQ_DEPTH, CMDQ_WQEBB_SIZE);
678db03a1ceSFan Gong 		if (err) {
679db03a1ceSFan Gong 			dev_err(hwdev->dev, "Failed to create cmdq wq\n");
680db03a1ceSFan Gong 			goto err_destroy_wq;
681db03a1ceSFan Gong 		}
682db03a1ceSFan Gong 	}
683db03a1ceSFan Gong 
684db03a1ceSFan Gong 	/* 1-level Chip Logical Address (CLA) must put all
685db03a1ceSFan Gong 	 * cmdq's wq page addr in one wq block
686db03a1ceSFan Gong 	 */
687db03a1ceSFan Gong 	if (!hinic3_wq_is_0_level_cla(&cmdqs->cmdq[HINIC3_CMDQ_SYNC].wq)) {
688db03a1ceSFan Gong 		if (cmdqs->cmdq[HINIC3_CMDQ_SYNC].wq.qpages.num_pages >
689db03a1ceSFan Gong 		    CMDQ_WQ_CLA_SIZE / sizeof(u64)) {
690db03a1ceSFan Gong 			err = -EINVAL;
691db03a1ceSFan Gong 			dev_err(hwdev->dev,
692db03a1ceSFan Gong 				"Cmdq number of wq pages exceeds limit: %lu\n",
693db03a1ceSFan Gong 				CMDQ_WQ_CLA_SIZE / sizeof(u64));
694db03a1ceSFan Gong 			goto err_destroy_wq;
695db03a1ceSFan Gong 		}
696db03a1ceSFan Gong 
697db03a1ceSFan Gong 		cmdqs->wq_block_vaddr =
698db03a1ceSFan Gong 			dma_alloc_coherent(hwdev->dev, HINIC3_MIN_PAGE_SIZE,
699db03a1ceSFan Gong 					   &cmdqs->wq_block_paddr, GFP_KERNEL);
700db03a1ceSFan Gong 		if (!cmdqs->wq_block_vaddr) {
701db03a1ceSFan Gong 			err = -ENOMEM;
702db03a1ceSFan Gong 			goto err_destroy_wq;
703db03a1ceSFan Gong 		}
704db03a1ceSFan Gong 
705db03a1ceSFan Gong 		for (cmdq_type = 0; cmdq_type < cmdqs->cmdq_num; cmdq_type++)
706db03a1ceSFan Gong 			memcpy((u8 *)cmdqs->wq_block_vaddr +
707db03a1ceSFan Gong 			       CMDQ_WQ_CLA_SIZE * cmdq_type,
708db03a1ceSFan Gong 			       cmdqs->cmdq[cmdq_type].wq.wq_block_vaddr,
709db03a1ceSFan Gong 			       cmdqs->cmdq[cmdq_type].wq.qpages.num_pages *
710db03a1ceSFan Gong 			       sizeof(__be64));
711db03a1ceSFan Gong 	}
712db03a1ceSFan Gong 
713db03a1ceSFan Gong 	return 0;
714db03a1ceSFan Gong 
715db03a1ceSFan Gong err_destroy_wq:
716db03a1ceSFan Gong 	while (cmdq_type > 0) {
717db03a1ceSFan Gong 		cmdq_type--;
718db03a1ceSFan Gong 		hinic3_wq_destroy(hwdev, &cmdqs->cmdq[cmdq_type].wq);
719db03a1ceSFan Gong 	}
720db03a1ceSFan Gong 
721db03a1ceSFan Gong 	return err;
722db03a1ceSFan Gong }
723db03a1ceSFan Gong 
724db03a1ceSFan Gong static void destroy_cmdq_wq(struct hinic3_hwdev *hwdev,
725db03a1ceSFan Gong 			    struct hinic3_cmdqs *cmdqs)
726db03a1ceSFan Gong {
727db03a1ceSFan Gong 	u8 cmdq_type;
728db03a1ceSFan Gong 
729db03a1ceSFan Gong 	if (cmdqs->wq_block_vaddr)
730db03a1ceSFan Gong 		dma_free_coherent(hwdev->dev, HINIC3_MIN_PAGE_SIZE,
731db03a1ceSFan Gong 				  cmdqs->wq_block_vaddr, cmdqs->wq_block_paddr);
732db03a1ceSFan Gong 
733db03a1ceSFan Gong 	for (cmdq_type = 0; cmdq_type < cmdqs->cmdq_num; cmdq_type++)
734db03a1ceSFan Gong 		hinic3_wq_destroy(hwdev, &cmdqs->cmdq[cmdq_type].wq);
735db03a1ceSFan Gong }
736db03a1ceSFan Gong 
737db03a1ceSFan Gong static int init_cmdqs(struct hinic3_hwdev *hwdev)
738db03a1ceSFan Gong {
739db03a1ceSFan Gong 	struct hinic3_cmdqs *cmdqs;
740db03a1ceSFan Gong 
741db03a1ceSFan Gong 	cmdqs = kzalloc(sizeof(*cmdqs), GFP_KERNEL);
742db03a1ceSFan Gong 	if (!cmdqs)
743db03a1ceSFan Gong 		return -ENOMEM;
744db03a1ceSFan Gong 
745db03a1ceSFan Gong 	hwdev->cmdqs = cmdqs;
746db03a1ceSFan Gong 	cmdqs->hwdev = hwdev;
747db03a1ceSFan Gong 	cmdqs->cmdq_num = hwdev->max_cmdq;
748db03a1ceSFan Gong 
749db03a1ceSFan Gong 	cmdqs->cmd_buf_pool = dma_pool_create("hinic3_cmdq", hwdev->dev,
750db03a1ceSFan Gong 					      CMDQ_BUF_SIZE, CMDQ_BUF_SIZE, 0);
751db03a1ceSFan Gong 	if (!cmdqs->cmd_buf_pool) {
752db03a1ceSFan Gong 		dev_err(hwdev->dev, "Failed to create cmdq buffer pool\n");
753db03a1ceSFan Gong 		kfree(cmdqs);
754db03a1ceSFan Gong 		return -ENOMEM;
755db03a1ceSFan Gong 	}
756db03a1ceSFan Gong 
757db03a1ceSFan Gong 	return 0;
758db03a1ceSFan Gong }
759db03a1ceSFan Gong 
760db03a1ceSFan Gong static void cmdq_flush_sync_cmd(struct hinic3_cmdq_cmd_info *cmd_info)
761db03a1ceSFan Gong {
762db03a1ceSFan Gong 	if (cmd_info->cmd_type != HINIC3_CMD_TYPE_DIRECT_RESP)
763db03a1ceSFan Gong 		return;
764db03a1ceSFan Gong 
765db03a1ceSFan Gong 	cmd_info->cmd_type = HINIC3_CMD_TYPE_FORCE_STOP;
766db03a1ceSFan Gong 
767db03a1ceSFan Gong 	if (cmd_info->cmpt_code &&
768db03a1ceSFan Gong 	    *cmd_info->cmpt_code == CMDQ_SEND_CMPT_CODE)
769db03a1ceSFan Gong 		*cmd_info->cmpt_code = CMDQ_FORCE_STOP_CMPT_CODE;
770db03a1ceSFan Gong 
771db03a1ceSFan Gong 	if (cmd_info->done) {
772db03a1ceSFan Gong 		complete(cmd_info->done);
773db03a1ceSFan Gong 		cmd_info->done = NULL;
774db03a1ceSFan Gong 		cmd_info->cmpt_code = NULL;
775db03a1ceSFan Gong 		cmd_info->direct_resp = NULL;
776db03a1ceSFan Gong 		cmd_info->errcode = NULL;
777db03a1ceSFan Gong 	}
778db03a1ceSFan Gong }
779db03a1ceSFan Gong 
780db03a1ceSFan Gong static void hinic3_cmdq_flush_cmd(struct hinic3_cmdq *cmdq)
781db03a1ceSFan Gong {
782db03a1ceSFan Gong 	struct hinic3_cmdq_cmd_info *cmd_info;
783db03a1ceSFan Gong 	u16 ci;
784db03a1ceSFan Gong 
785db03a1ceSFan Gong 	spin_lock_bh(&cmdq->cmdq_lock);
786db03a1ceSFan Gong 	while (cmdq_read_wqe(&cmdq->wq, &ci)) {
787db03a1ceSFan Gong 		hinic3_wq_put_wqebbs(&cmdq->wq, CMDQ_WQE_NUM_WQEBBS);
788db03a1ceSFan Gong 		cmd_info = &cmdq->cmd_infos[ci];
789db03a1ceSFan Gong 		if (cmd_info->cmd_type == HINIC3_CMD_TYPE_DIRECT_RESP)
790db03a1ceSFan Gong 			cmdq_flush_sync_cmd(cmd_info);
791db03a1ceSFan Gong 	}
792db03a1ceSFan Gong 	spin_unlock_bh(&cmdq->cmdq_lock);
793db03a1ceSFan Gong }
794db03a1ceSFan Gong 
795db03a1ceSFan Gong void hinic3_cmdq_flush_sync_cmd(struct hinic3_hwdev *hwdev)
796db03a1ceSFan Gong {
797db03a1ceSFan Gong 	struct hinic3_cmdq *cmdq;
798db03a1ceSFan Gong 	u16 wqe_cnt, wqe_idx, i;
799db03a1ceSFan Gong 	struct hinic3_wq *wq;
800db03a1ceSFan Gong 
801db03a1ceSFan Gong 	cmdq = &hwdev->cmdqs->cmdq[HINIC3_CMDQ_SYNC];
802db03a1ceSFan Gong 	spin_lock_bh(&cmdq->cmdq_lock);
803db03a1ceSFan Gong 	wq = &cmdq->wq;
804db03a1ceSFan Gong 	wqe_cnt = hinic3_wq_get_used(wq);
805db03a1ceSFan Gong 	for (i = 0; i < wqe_cnt; i++) {
806db03a1ceSFan Gong 		wqe_idx = (wq->cons_idx + i) & wq->idx_mask;
807db03a1ceSFan Gong 		cmdq_flush_sync_cmd(cmdq->cmd_infos + wqe_idx);
808db03a1ceSFan Gong 	}
809db03a1ceSFan Gong 	spin_unlock_bh(&cmdq->cmdq_lock);
810db03a1ceSFan Gong }
811db03a1ceSFan Gong 
812db03a1ceSFan Gong static void hinic3_cmdq_reset_all_cmd_buf(struct hinic3_cmdq *cmdq)
813db03a1ceSFan Gong {
814db03a1ceSFan Gong 	u16 i;
815db03a1ceSFan Gong 
816db03a1ceSFan Gong 	for (i = 0; i < cmdq->wq.q_depth; i++)
817db03a1ceSFan Gong 		cmdq_clear_cmd_buf(&cmdq->cmd_infos[i], cmdq->hwdev);
818db03a1ceSFan Gong }
819db03a1ceSFan Gong 
820db03a1ceSFan Gong int hinic3_reinit_cmdq_ctxts(struct hinic3_hwdev *hwdev)
821db03a1ceSFan Gong {
822db03a1ceSFan Gong 	struct hinic3_cmdqs *cmdqs = hwdev->cmdqs;
823db03a1ceSFan Gong 	u8 cmdq_type;
824db03a1ceSFan Gong 
825db03a1ceSFan Gong 	for (cmdq_type = 0; cmdq_type < cmdqs->cmdq_num; cmdq_type++) {
826db03a1ceSFan Gong 		hinic3_cmdq_flush_cmd(&cmdqs->cmdq[cmdq_type]);
827db03a1ceSFan Gong 		hinic3_cmdq_reset_all_cmd_buf(&cmdqs->cmdq[cmdq_type]);
828db03a1ceSFan Gong 		cmdqs->cmdq[cmdq_type].wrapped = 1;
829db03a1ceSFan Gong 		hinic3_wq_reset(&cmdqs->cmdq[cmdq_type].wq);
830db03a1ceSFan Gong 	}
831db03a1ceSFan Gong 
832db03a1ceSFan Gong 	return hinic3_set_cmdq_ctxts(hwdev);
833db03a1ceSFan Gong }
834db03a1ceSFan Gong 
835db03a1ceSFan Gong int hinic3_cmdqs_init(struct hinic3_hwdev *hwdev)
836db03a1ceSFan Gong {
837db03a1ceSFan Gong 	struct hinic3_cmdqs *cmdqs;
838db03a1ceSFan Gong 	void __iomem *db_base;
839db03a1ceSFan Gong 	u8 cmdq_type;
840db03a1ceSFan Gong 	int err;
841db03a1ceSFan Gong 
842db03a1ceSFan Gong 	err = init_cmdqs(hwdev);
843db03a1ceSFan Gong 	if (err)
844db03a1ceSFan Gong 		goto err_out;
845db03a1ceSFan Gong 
846db03a1ceSFan Gong 	cmdqs = hwdev->cmdqs;
847db03a1ceSFan Gong 	err = create_cmdq_wq(hwdev, cmdqs);
848db03a1ceSFan Gong 	if (err)
849db03a1ceSFan Gong 		goto err_free_cmdqs;
850db03a1ceSFan Gong 
851db03a1ceSFan Gong 	err = hinic3_alloc_db_addr(hwdev, &db_base, NULL);
852db03a1ceSFan Gong 	if (err) {
853db03a1ceSFan Gong 		dev_err(hwdev->dev, "Failed to allocate doorbell address\n");
854db03a1ceSFan Gong 		goto err_destroy_cmdq_wq;
855db03a1ceSFan Gong 	}
856db03a1ceSFan Gong 	cmdqs->cmdqs_db_base = db_base;
857db03a1ceSFan Gong 
858db03a1ceSFan Gong 	for (cmdq_type = 0; cmdq_type < cmdqs->cmdq_num; cmdq_type++) {
859db03a1ceSFan Gong 		err = init_cmdq(&cmdqs->cmdq[cmdq_type], hwdev, cmdq_type);
860db03a1ceSFan Gong 		if (err) {
861db03a1ceSFan Gong 			dev_err(hwdev->dev,
862db03a1ceSFan Gong 				"Failed to initialize cmdq type : %d\n",
863db03a1ceSFan Gong 				cmdq_type);
864db03a1ceSFan Gong 			goto err_free_cmd_infos;
865db03a1ceSFan Gong 		}
866db03a1ceSFan Gong 	}
867db03a1ceSFan Gong 
868db03a1ceSFan Gong 	err = hinic3_set_cmdq_ctxts(hwdev);
869db03a1ceSFan Gong 	if (err)
870db03a1ceSFan Gong 		goto err_free_cmd_infos;
871db03a1ceSFan Gong 
872db03a1ceSFan Gong 	return 0;
873db03a1ceSFan Gong 
874db03a1ceSFan Gong err_free_cmd_infos:
875db03a1ceSFan Gong 	while (cmdq_type > 0) {
876db03a1ceSFan Gong 		cmdq_type--;
877db03a1ceSFan Gong 		kfree(cmdqs->cmdq[cmdq_type].cmd_infos);
878db03a1ceSFan Gong 	}
879db03a1ceSFan Gong 
880db03a1ceSFan Gong 	hinic3_free_db_addr(hwdev, cmdqs->cmdqs_db_base);
881db03a1ceSFan Gong 
882db03a1ceSFan Gong err_destroy_cmdq_wq:
883db03a1ceSFan Gong 	destroy_cmdq_wq(hwdev, cmdqs);
884db03a1ceSFan Gong 
885db03a1ceSFan Gong err_free_cmdqs:
886db03a1ceSFan Gong 	dma_pool_destroy(cmdqs->cmd_buf_pool);
887db03a1ceSFan Gong 	kfree(cmdqs);
888db03a1ceSFan Gong 
889db03a1ceSFan Gong err_out:
890db03a1ceSFan Gong 	return err;
891db03a1ceSFan Gong }
892db03a1ceSFan Gong 
893db03a1ceSFan Gong void hinic3_cmdqs_free(struct hinic3_hwdev *hwdev)
894db03a1ceSFan Gong {
895db03a1ceSFan Gong 	struct hinic3_cmdqs *cmdqs = hwdev->cmdqs;
896db03a1ceSFan Gong 	u8 cmdq_type;
897db03a1ceSFan Gong 
898db03a1ceSFan Gong 	cmdqs->status &= ~HINIC3_CMDQ_ENABLE;
899db03a1ceSFan Gong 
900db03a1ceSFan Gong 	for (cmdq_type = 0; cmdq_type < cmdqs->cmdq_num; cmdq_type++) {
901db03a1ceSFan Gong 		hinic3_cmdq_flush_cmd(&cmdqs->cmdq[cmdq_type]);
902db03a1ceSFan Gong 		hinic3_cmdq_reset_all_cmd_buf(&cmdqs->cmdq[cmdq_type]);
903db03a1ceSFan Gong 		kfree(cmdqs->cmdq[cmdq_type].cmd_infos);
904db03a1ceSFan Gong 	}
905db03a1ceSFan Gong 
906db03a1ceSFan Gong 	hinic3_free_db_addr(hwdev, cmdqs->cmdqs_db_base);
907db03a1ceSFan Gong 	destroy_cmdq_wq(hwdev, cmdqs);
908db03a1ceSFan Gong 	dma_pool_destroy(cmdqs->cmd_buf_pool);
909db03a1ceSFan Gong 	kfree(cmdqs);
910db03a1ceSFan Gong }
911db03a1ceSFan Gong 
912db03a1ceSFan Gong bool hinic3_cmdq_idle(struct hinic3_cmdq *cmdq)
913db03a1ceSFan Gong {
914db03a1ceSFan Gong 	return hinic3_wq_get_used(&cmdq->wq) == 0;
915db03a1ceSFan Gong }
916