xref: /openbmc/linux/drivers/infiniband/hw/erdma/erdma_cmdq.c (revision 2af541bf8e32ee73f17fb28e2b3766a96b7311e5)
1*2af541bfSCheng Xu // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
2*2af541bfSCheng Xu 
3*2af541bfSCheng Xu /* Authors: Cheng Xu <chengyou@linux.alibaba.com> */
4*2af541bfSCheng Xu /*          Kai Shen <kaishen@linux.alibaba.com> */
5*2af541bfSCheng Xu /* Copyright (c) 2020-2022, Alibaba Group. */
6*2af541bfSCheng Xu 
7*2af541bfSCheng Xu #include <linux/kernel.h>
8*2af541bfSCheng Xu #include <linux/pci.h>
9*2af541bfSCheng Xu #include <linux/types.h>
10*2af541bfSCheng Xu 
11*2af541bfSCheng Xu #include "erdma.h"
12*2af541bfSCheng Xu #include "erdma_hw.h"
13*2af541bfSCheng Xu #include "erdma_verbs.h"
14*2af541bfSCheng Xu 
15*2af541bfSCheng Xu static void arm_cmdq_cq(struct erdma_cmdq *cmdq)
16*2af541bfSCheng Xu {
17*2af541bfSCheng Xu 	struct erdma_dev *dev = container_of(cmdq, struct erdma_dev, cmdq);
18*2af541bfSCheng Xu 	u64 db_data = FIELD_PREP(ERDMA_CQDB_CI_MASK, cmdq->cq.ci) |
19*2af541bfSCheng Xu 		      FIELD_PREP(ERDMA_CQDB_ARM_MASK, 1) |
20*2af541bfSCheng Xu 		      FIELD_PREP(ERDMA_CQDB_CMDSN_MASK, cmdq->cq.cmdsn) |
21*2af541bfSCheng Xu 		      FIELD_PREP(ERDMA_CQDB_IDX_MASK, cmdq->cq.cmdsn);
22*2af541bfSCheng Xu 
23*2af541bfSCheng Xu 	*cmdq->cq.db_record = db_data;
24*2af541bfSCheng Xu 	writeq(db_data, dev->func_bar + ERDMA_CMDQ_CQDB_REG);
25*2af541bfSCheng Xu 
26*2af541bfSCheng Xu 	atomic64_inc(&cmdq->cq.armed_num);
27*2af541bfSCheng Xu }
28*2af541bfSCheng Xu 
29*2af541bfSCheng Xu static void kick_cmdq_db(struct erdma_cmdq *cmdq)
30*2af541bfSCheng Xu {
31*2af541bfSCheng Xu 	struct erdma_dev *dev = container_of(cmdq, struct erdma_dev, cmdq);
32*2af541bfSCheng Xu 	u64 db_data = FIELD_PREP(ERDMA_CMD_HDR_WQEBB_INDEX_MASK, cmdq->sq.pi);
33*2af541bfSCheng Xu 
34*2af541bfSCheng Xu 	*cmdq->sq.db_record = db_data;
35*2af541bfSCheng Xu 	writeq(db_data, dev->func_bar + ERDMA_CMDQ_SQDB_REG);
36*2af541bfSCheng Xu }
37*2af541bfSCheng Xu 
38*2af541bfSCheng Xu static struct erdma_comp_wait *get_comp_wait(struct erdma_cmdq *cmdq)
39*2af541bfSCheng Xu {
40*2af541bfSCheng Xu 	int comp_idx;
41*2af541bfSCheng Xu 
42*2af541bfSCheng Xu 	spin_lock(&cmdq->lock);
43*2af541bfSCheng Xu 	comp_idx = find_first_zero_bit(cmdq->comp_wait_bitmap,
44*2af541bfSCheng Xu 				       cmdq->max_outstandings);
45*2af541bfSCheng Xu 	if (comp_idx == cmdq->max_outstandings) {
46*2af541bfSCheng Xu 		spin_unlock(&cmdq->lock);
47*2af541bfSCheng Xu 		return ERR_PTR(-ENOMEM);
48*2af541bfSCheng Xu 	}
49*2af541bfSCheng Xu 
50*2af541bfSCheng Xu 	__set_bit(comp_idx, cmdq->comp_wait_bitmap);
51*2af541bfSCheng Xu 	spin_unlock(&cmdq->lock);
52*2af541bfSCheng Xu 
53*2af541bfSCheng Xu 	return &cmdq->wait_pool[comp_idx];
54*2af541bfSCheng Xu }
55*2af541bfSCheng Xu 
56*2af541bfSCheng Xu static void put_comp_wait(struct erdma_cmdq *cmdq,
57*2af541bfSCheng Xu 			  struct erdma_comp_wait *comp_wait)
58*2af541bfSCheng Xu {
59*2af541bfSCheng Xu 	int used;
60*2af541bfSCheng Xu 
61*2af541bfSCheng Xu 	cmdq->wait_pool[comp_wait->ctx_id].cmd_status = ERDMA_CMD_STATUS_INIT;
62*2af541bfSCheng Xu 	spin_lock(&cmdq->lock);
63*2af541bfSCheng Xu 	used = __test_and_clear_bit(comp_wait->ctx_id, cmdq->comp_wait_bitmap);
64*2af541bfSCheng Xu 	spin_unlock(&cmdq->lock);
65*2af541bfSCheng Xu 
66*2af541bfSCheng Xu 	WARN_ON(!used);
67*2af541bfSCheng Xu }
68*2af541bfSCheng Xu 
69*2af541bfSCheng Xu static int erdma_cmdq_wait_res_init(struct erdma_dev *dev,
70*2af541bfSCheng Xu 				    struct erdma_cmdq *cmdq)
71*2af541bfSCheng Xu {
72*2af541bfSCheng Xu 	int i;
73*2af541bfSCheng Xu 
74*2af541bfSCheng Xu 	cmdq->wait_pool =
75*2af541bfSCheng Xu 		devm_kcalloc(&dev->pdev->dev, cmdq->max_outstandings,
76*2af541bfSCheng Xu 			     sizeof(struct erdma_comp_wait), GFP_KERNEL);
77*2af541bfSCheng Xu 	if (!cmdq->wait_pool)
78*2af541bfSCheng Xu 		return -ENOMEM;
79*2af541bfSCheng Xu 
80*2af541bfSCheng Xu 	spin_lock_init(&cmdq->lock);
81*2af541bfSCheng Xu 	cmdq->comp_wait_bitmap = devm_bitmap_zalloc(
82*2af541bfSCheng Xu 		&dev->pdev->dev, cmdq->max_outstandings, GFP_KERNEL);
83*2af541bfSCheng Xu 	if (!cmdq->comp_wait_bitmap)
84*2af541bfSCheng Xu 		return -ENOMEM;
85*2af541bfSCheng Xu 
86*2af541bfSCheng Xu 	for (i = 0; i < cmdq->max_outstandings; i++) {
87*2af541bfSCheng Xu 		init_completion(&cmdq->wait_pool[i].wait_event);
88*2af541bfSCheng Xu 		cmdq->wait_pool[i].ctx_id = i;
89*2af541bfSCheng Xu 	}
90*2af541bfSCheng Xu 
91*2af541bfSCheng Xu 	return 0;
92*2af541bfSCheng Xu }
93*2af541bfSCheng Xu 
94*2af541bfSCheng Xu static int erdma_cmdq_sq_init(struct erdma_dev *dev)
95*2af541bfSCheng Xu {
96*2af541bfSCheng Xu 	struct erdma_cmdq *cmdq = &dev->cmdq;
97*2af541bfSCheng Xu 	struct erdma_cmdq_sq *sq = &cmdq->sq;
98*2af541bfSCheng Xu 	u32 buf_size;
99*2af541bfSCheng Xu 
100*2af541bfSCheng Xu 	sq->wqebb_cnt = SQEBB_COUNT(ERDMA_CMDQ_SQE_SIZE);
101*2af541bfSCheng Xu 	sq->depth = cmdq->max_outstandings * sq->wqebb_cnt;
102*2af541bfSCheng Xu 
103*2af541bfSCheng Xu 	buf_size = sq->depth << SQEBB_SHIFT;
104*2af541bfSCheng Xu 
105*2af541bfSCheng Xu 	sq->qbuf =
106*2af541bfSCheng Xu 		dma_alloc_coherent(&dev->pdev->dev, WARPPED_BUFSIZE(buf_size),
107*2af541bfSCheng Xu 				   &sq->qbuf_dma_addr, GFP_KERNEL);
108*2af541bfSCheng Xu 	if (!sq->qbuf)
109*2af541bfSCheng Xu 		return -ENOMEM;
110*2af541bfSCheng Xu 
111*2af541bfSCheng Xu 	sq->db_record = (u64 *)(sq->qbuf + buf_size);
112*2af541bfSCheng Xu 
113*2af541bfSCheng Xu 	spin_lock_init(&sq->lock);
114*2af541bfSCheng Xu 
115*2af541bfSCheng Xu 	erdma_reg_write32(dev, ERDMA_REGS_CMDQ_SQ_ADDR_H_REG,
116*2af541bfSCheng Xu 			  upper_32_bits(sq->qbuf_dma_addr));
117*2af541bfSCheng Xu 	erdma_reg_write32(dev, ERDMA_REGS_CMDQ_SQ_ADDR_L_REG,
118*2af541bfSCheng Xu 			  lower_32_bits(sq->qbuf_dma_addr));
119*2af541bfSCheng Xu 	erdma_reg_write32(dev, ERDMA_REGS_CMDQ_DEPTH_REG, sq->depth);
120*2af541bfSCheng Xu 	erdma_reg_write64(dev, ERDMA_CMDQ_SQ_DB_HOST_ADDR_REG,
121*2af541bfSCheng Xu 			  sq->qbuf_dma_addr + buf_size);
122*2af541bfSCheng Xu 
123*2af541bfSCheng Xu 	return 0;
124*2af541bfSCheng Xu }
125*2af541bfSCheng Xu 
126*2af541bfSCheng Xu static int erdma_cmdq_cq_init(struct erdma_dev *dev)
127*2af541bfSCheng Xu {
128*2af541bfSCheng Xu 	struct erdma_cmdq *cmdq = &dev->cmdq;
129*2af541bfSCheng Xu 	struct erdma_cmdq_cq *cq = &cmdq->cq;
130*2af541bfSCheng Xu 	u32 buf_size;
131*2af541bfSCheng Xu 
132*2af541bfSCheng Xu 	cq->depth = cmdq->sq.depth;
133*2af541bfSCheng Xu 	buf_size = cq->depth << CQE_SHIFT;
134*2af541bfSCheng Xu 
135*2af541bfSCheng Xu 	cq->qbuf =
136*2af541bfSCheng Xu 		dma_alloc_coherent(&dev->pdev->dev, WARPPED_BUFSIZE(buf_size),
137*2af541bfSCheng Xu 				   &cq->qbuf_dma_addr, GFP_KERNEL | __GFP_ZERO);
138*2af541bfSCheng Xu 	if (!cq->qbuf)
139*2af541bfSCheng Xu 		return -ENOMEM;
140*2af541bfSCheng Xu 
141*2af541bfSCheng Xu 	spin_lock_init(&cq->lock);
142*2af541bfSCheng Xu 
143*2af541bfSCheng Xu 	cq->db_record = (u64 *)(cq->qbuf + buf_size);
144*2af541bfSCheng Xu 
145*2af541bfSCheng Xu 	atomic64_set(&cq->armed_num, 0);
146*2af541bfSCheng Xu 
147*2af541bfSCheng Xu 	erdma_reg_write32(dev, ERDMA_REGS_CMDQ_CQ_ADDR_H_REG,
148*2af541bfSCheng Xu 			  upper_32_bits(cq->qbuf_dma_addr));
149*2af541bfSCheng Xu 	erdma_reg_write32(dev, ERDMA_REGS_CMDQ_CQ_ADDR_L_REG,
150*2af541bfSCheng Xu 			  lower_32_bits(cq->qbuf_dma_addr));
151*2af541bfSCheng Xu 	erdma_reg_write64(dev, ERDMA_CMDQ_CQ_DB_HOST_ADDR_REG,
152*2af541bfSCheng Xu 			  cq->qbuf_dma_addr + buf_size);
153*2af541bfSCheng Xu 
154*2af541bfSCheng Xu 	return 0;
155*2af541bfSCheng Xu }
156*2af541bfSCheng Xu 
157*2af541bfSCheng Xu static int erdma_cmdq_eq_init(struct erdma_dev *dev)
158*2af541bfSCheng Xu {
159*2af541bfSCheng Xu 	struct erdma_cmdq *cmdq = &dev->cmdq;
160*2af541bfSCheng Xu 	struct erdma_eq *eq = &cmdq->eq;
161*2af541bfSCheng Xu 	u32 buf_size;
162*2af541bfSCheng Xu 
163*2af541bfSCheng Xu 	eq->depth = cmdq->max_outstandings;
164*2af541bfSCheng Xu 	buf_size = eq->depth << EQE_SHIFT;
165*2af541bfSCheng Xu 
166*2af541bfSCheng Xu 	eq->qbuf =
167*2af541bfSCheng Xu 		dma_alloc_coherent(&dev->pdev->dev, WARPPED_BUFSIZE(buf_size),
168*2af541bfSCheng Xu 				   &eq->qbuf_dma_addr, GFP_KERNEL | __GFP_ZERO);
169*2af541bfSCheng Xu 	if (!eq->qbuf)
170*2af541bfSCheng Xu 		return -ENOMEM;
171*2af541bfSCheng Xu 
172*2af541bfSCheng Xu 	spin_lock_init(&eq->lock);
173*2af541bfSCheng Xu 	atomic64_set(&eq->event_num, 0);
174*2af541bfSCheng Xu 
175*2af541bfSCheng Xu 	eq->db_addr =
176*2af541bfSCheng Xu 		(u64 __iomem *)(dev->func_bar + ERDMA_REGS_CEQ_DB_BASE_REG);
177*2af541bfSCheng Xu 	eq->db_record = (u64 *)(eq->qbuf + buf_size);
178*2af541bfSCheng Xu 
179*2af541bfSCheng Xu 	erdma_reg_write32(dev, ERDMA_REGS_CMDQ_EQ_ADDR_H_REG,
180*2af541bfSCheng Xu 			  upper_32_bits(eq->qbuf_dma_addr));
181*2af541bfSCheng Xu 	erdma_reg_write32(dev, ERDMA_REGS_CMDQ_EQ_ADDR_L_REG,
182*2af541bfSCheng Xu 			  lower_32_bits(eq->qbuf_dma_addr));
183*2af541bfSCheng Xu 	erdma_reg_write32(dev, ERDMA_REGS_CMDQ_EQ_DEPTH_REG, eq->depth);
184*2af541bfSCheng Xu 	erdma_reg_write64(dev, ERDMA_CMDQ_EQ_DB_HOST_ADDR_REG,
185*2af541bfSCheng Xu 			  eq->qbuf_dma_addr + buf_size);
186*2af541bfSCheng Xu 
187*2af541bfSCheng Xu 	return 0;
188*2af541bfSCheng Xu }
189*2af541bfSCheng Xu 
190*2af541bfSCheng Xu int erdma_cmdq_init(struct erdma_dev *dev)
191*2af541bfSCheng Xu {
192*2af541bfSCheng Xu 	int err, i;
193*2af541bfSCheng Xu 	struct erdma_cmdq *cmdq = &dev->cmdq;
194*2af541bfSCheng Xu 	u32 sts, ctrl;
195*2af541bfSCheng Xu 
196*2af541bfSCheng Xu 	cmdq->max_outstandings = ERDMA_CMDQ_MAX_OUTSTANDING;
197*2af541bfSCheng Xu 	cmdq->use_event = false;
198*2af541bfSCheng Xu 
199*2af541bfSCheng Xu 	sema_init(&cmdq->credits, cmdq->max_outstandings);
200*2af541bfSCheng Xu 
201*2af541bfSCheng Xu 	err = erdma_cmdq_wait_res_init(dev, cmdq);
202*2af541bfSCheng Xu 	if (err)
203*2af541bfSCheng Xu 		return err;
204*2af541bfSCheng Xu 
205*2af541bfSCheng Xu 	err = erdma_cmdq_sq_init(dev);
206*2af541bfSCheng Xu 	if (err)
207*2af541bfSCheng Xu 		return err;
208*2af541bfSCheng Xu 
209*2af541bfSCheng Xu 	err = erdma_cmdq_cq_init(dev);
210*2af541bfSCheng Xu 	if (err)
211*2af541bfSCheng Xu 		goto err_destroy_sq;
212*2af541bfSCheng Xu 
213*2af541bfSCheng Xu 	err = erdma_cmdq_eq_init(dev);
214*2af541bfSCheng Xu 	if (err)
215*2af541bfSCheng Xu 		goto err_destroy_cq;
216*2af541bfSCheng Xu 
217*2af541bfSCheng Xu 	ctrl = FIELD_PREP(ERDMA_REG_DEV_CTRL_INIT_MASK, 1);
218*2af541bfSCheng Xu 	erdma_reg_write32(dev, ERDMA_REGS_DEV_CTRL_REG, ctrl);
219*2af541bfSCheng Xu 
220*2af541bfSCheng Xu 	for (i = 0; i < ERDMA_WAIT_DEV_DONE_CNT; i++) {
221*2af541bfSCheng Xu 		sts = erdma_reg_read32_filed(dev, ERDMA_REGS_DEV_ST_REG,
222*2af541bfSCheng Xu 					     ERDMA_REG_DEV_ST_INIT_DONE_MASK);
223*2af541bfSCheng Xu 		if (sts)
224*2af541bfSCheng Xu 			break;
225*2af541bfSCheng Xu 
226*2af541bfSCheng Xu 		msleep(ERDMA_REG_ACCESS_WAIT_MS);
227*2af541bfSCheng Xu 	}
228*2af541bfSCheng Xu 
229*2af541bfSCheng Xu 	if (i == ERDMA_WAIT_DEV_DONE_CNT) {
230*2af541bfSCheng Xu 		dev_err(&dev->pdev->dev, "wait init done failed.\n");
231*2af541bfSCheng Xu 		err = -ETIMEDOUT;
232*2af541bfSCheng Xu 		goto err_destroy_eq;
233*2af541bfSCheng Xu 	}
234*2af541bfSCheng Xu 
235*2af541bfSCheng Xu 	set_bit(ERDMA_CMDQ_STATE_OK_BIT, &cmdq->state);
236*2af541bfSCheng Xu 
237*2af541bfSCheng Xu 	return 0;
238*2af541bfSCheng Xu 
239*2af541bfSCheng Xu err_destroy_eq:
240*2af541bfSCheng Xu 	dma_free_coherent(&dev->pdev->dev,
241*2af541bfSCheng Xu 			  (cmdq->eq.depth << EQE_SHIFT) +
242*2af541bfSCheng Xu 				  ERDMA_EXTRA_BUFFER_SIZE,
243*2af541bfSCheng Xu 			  cmdq->eq.qbuf, cmdq->eq.qbuf_dma_addr);
244*2af541bfSCheng Xu 
245*2af541bfSCheng Xu err_destroy_cq:
246*2af541bfSCheng Xu 	dma_free_coherent(&dev->pdev->dev,
247*2af541bfSCheng Xu 			  (cmdq->cq.depth << CQE_SHIFT) +
248*2af541bfSCheng Xu 				  ERDMA_EXTRA_BUFFER_SIZE,
249*2af541bfSCheng Xu 			  cmdq->cq.qbuf, cmdq->cq.qbuf_dma_addr);
250*2af541bfSCheng Xu 
251*2af541bfSCheng Xu err_destroy_sq:
252*2af541bfSCheng Xu 	dma_free_coherent(&dev->pdev->dev,
253*2af541bfSCheng Xu 			  (cmdq->sq.depth << SQEBB_SHIFT) +
254*2af541bfSCheng Xu 				  ERDMA_EXTRA_BUFFER_SIZE,
255*2af541bfSCheng Xu 			  cmdq->sq.qbuf, cmdq->sq.qbuf_dma_addr);
256*2af541bfSCheng Xu 
257*2af541bfSCheng Xu 	return err;
258*2af541bfSCheng Xu }
259*2af541bfSCheng Xu 
260*2af541bfSCheng Xu void erdma_finish_cmdq_init(struct erdma_dev *dev)
261*2af541bfSCheng Xu {
262*2af541bfSCheng Xu 	/* after device init successfully, change cmdq to event mode. */
263*2af541bfSCheng Xu 	dev->cmdq.use_event = true;
264*2af541bfSCheng Xu 	arm_cmdq_cq(&dev->cmdq);
265*2af541bfSCheng Xu }
266*2af541bfSCheng Xu 
267*2af541bfSCheng Xu void erdma_cmdq_destroy(struct erdma_dev *dev)
268*2af541bfSCheng Xu {
269*2af541bfSCheng Xu 	struct erdma_cmdq *cmdq = &dev->cmdq;
270*2af541bfSCheng Xu 
271*2af541bfSCheng Xu 	clear_bit(ERDMA_CMDQ_STATE_OK_BIT, &cmdq->state);
272*2af541bfSCheng Xu 
273*2af541bfSCheng Xu 	dma_free_coherent(&dev->pdev->dev,
274*2af541bfSCheng Xu 			  (cmdq->eq.depth << EQE_SHIFT) +
275*2af541bfSCheng Xu 				  ERDMA_EXTRA_BUFFER_SIZE,
276*2af541bfSCheng Xu 			  cmdq->eq.qbuf, cmdq->eq.qbuf_dma_addr);
277*2af541bfSCheng Xu 	dma_free_coherent(&dev->pdev->dev,
278*2af541bfSCheng Xu 			  (cmdq->sq.depth << SQEBB_SHIFT) +
279*2af541bfSCheng Xu 				  ERDMA_EXTRA_BUFFER_SIZE,
280*2af541bfSCheng Xu 			  cmdq->sq.qbuf, cmdq->sq.qbuf_dma_addr);
281*2af541bfSCheng Xu 	dma_free_coherent(&dev->pdev->dev,
282*2af541bfSCheng Xu 			  (cmdq->cq.depth << CQE_SHIFT) +
283*2af541bfSCheng Xu 				  ERDMA_EXTRA_BUFFER_SIZE,
284*2af541bfSCheng Xu 			  cmdq->cq.qbuf, cmdq->cq.qbuf_dma_addr);
285*2af541bfSCheng Xu }
286*2af541bfSCheng Xu 
287*2af541bfSCheng Xu static void *get_next_valid_cmdq_cqe(struct erdma_cmdq *cmdq)
288*2af541bfSCheng Xu {
289*2af541bfSCheng Xu 	__be32 *cqe = get_queue_entry(cmdq->cq.qbuf, cmdq->cq.ci,
290*2af541bfSCheng Xu 				      cmdq->cq.depth, CQE_SHIFT);
291*2af541bfSCheng Xu 	u32 owner = FIELD_GET(ERDMA_CQE_HDR_OWNER_MASK,
292*2af541bfSCheng Xu 			      __be32_to_cpu(READ_ONCE(*cqe)));
293*2af541bfSCheng Xu 
294*2af541bfSCheng Xu 	return owner ^ !!(cmdq->cq.ci & cmdq->cq.depth) ? cqe : NULL;
295*2af541bfSCheng Xu }
296*2af541bfSCheng Xu 
297*2af541bfSCheng Xu static void push_cmdq_sqe(struct erdma_cmdq *cmdq, u64 *req, size_t req_len,
298*2af541bfSCheng Xu 			  struct erdma_comp_wait *comp_wait)
299*2af541bfSCheng Xu {
300*2af541bfSCheng Xu 	__le64 *wqe;
301*2af541bfSCheng Xu 	u64 hdr = *req;
302*2af541bfSCheng Xu 
303*2af541bfSCheng Xu 	comp_wait->cmd_status = ERDMA_CMD_STATUS_ISSUED;
304*2af541bfSCheng Xu 	reinit_completion(&comp_wait->wait_event);
305*2af541bfSCheng Xu 	comp_wait->sq_pi = cmdq->sq.pi;
306*2af541bfSCheng Xu 
307*2af541bfSCheng Xu 	wqe = get_queue_entry(cmdq->sq.qbuf, cmdq->sq.pi, cmdq->sq.depth,
308*2af541bfSCheng Xu 			      SQEBB_SHIFT);
309*2af541bfSCheng Xu 	memcpy(wqe, req, req_len);
310*2af541bfSCheng Xu 
311*2af541bfSCheng Xu 	cmdq->sq.pi += cmdq->sq.wqebb_cnt;
312*2af541bfSCheng Xu 	hdr |= FIELD_PREP(ERDMA_CMD_HDR_WQEBB_INDEX_MASK, cmdq->sq.pi) |
313*2af541bfSCheng Xu 	       FIELD_PREP(ERDMA_CMD_HDR_CONTEXT_COOKIE_MASK,
314*2af541bfSCheng Xu 			  comp_wait->ctx_id) |
315*2af541bfSCheng Xu 	       FIELD_PREP(ERDMA_CMD_HDR_WQEBB_CNT_MASK, cmdq->sq.wqebb_cnt - 1);
316*2af541bfSCheng Xu 	*wqe = cpu_to_le64(hdr);
317*2af541bfSCheng Xu 
318*2af541bfSCheng Xu 	kick_cmdq_db(cmdq);
319*2af541bfSCheng Xu }
320*2af541bfSCheng Xu 
321*2af541bfSCheng Xu static int erdma_poll_single_cmd_completion(struct erdma_cmdq *cmdq)
322*2af541bfSCheng Xu {
323*2af541bfSCheng Xu 	struct erdma_comp_wait *comp_wait;
324*2af541bfSCheng Xu 	u32 hdr0, sqe_idx;
325*2af541bfSCheng Xu 	__be32 *cqe;
326*2af541bfSCheng Xu 	u16 ctx_id;
327*2af541bfSCheng Xu 	u64 *sqe;
328*2af541bfSCheng Xu 	int i;
329*2af541bfSCheng Xu 
330*2af541bfSCheng Xu 	cqe = get_next_valid_cmdq_cqe(cmdq);
331*2af541bfSCheng Xu 	if (!cqe)
332*2af541bfSCheng Xu 		return -EAGAIN;
333*2af541bfSCheng Xu 
334*2af541bfSCheng Xu 	cmdq->cq.ci++;
335*2af541bfSCheng Xu 
336*2af541bfSCheng Xu 	dma_rmb();
337*2af541bfSCheng Xu 	hdr0 = __be32_to_cpu(*cqe);
338*2af541bfSCheng Xu 	sqe_idx = __be32_to_cpu(*(cqe + 1));
339*2af541bfSCheng Xu 
340*2af541bfSCheng Xu 	sqe = get_queue_entry(cmdq->sq.qbuf, sqe_idx, cmdq->sq.depth,
341*2af541bfSCheng Xu 			      SQEBB_SHIFT);
342*2af541bfSCheng Xu 	ctx_id = FIELD_GET(ERDMA_CMD_HDR_CONTEXT_COOKIE_MASK, *sqe);
343*2af541bfSCheng Xu 	comp_wait = &cmdq->wait_pool[ctx_id];
344*2af541bfSCheng Xu 	if (comp_wait->cmd_status != ERDMA_CMD_STATUS_ISSUED)
345*2af541bfSCheng Xu 		return -EIO;
346*2af541bfSCheng Xu 
347*2af541bfSCheng Xu 	comp_wait->cmd_status = ERDMA_CMD_STATUS_FINISHED;
348*2af541bfSCheng Xu 	comp_wait->comp_status = FIELD_GET(ERDMA_CQE_HDR_SYNDROME_MASK, hdr0);
349*2af541bfSCheng Xu 	cmdq->sq.ci += cmdq->sq.wqebb_cnt;
350*2af541bfSCheng Xu 
351*2af541bfSCheng Xu 	for (i = 0; i < 4; i++)
352*2af541bfSCheng Xu 		comp_wait->comp_data[i] = __be32_to_cpu(*(cqe + 2 + i));
353*2af541bfSCheng Xu 
354*2af541bfSCheng Xu 	if (cmdq->use_event)
355*2af541bfSCheng Xu 		complete(&comp_wait->wait_event);
356*2af541bfSCheng Xu 
357*2af541bfSCheng Xu 	return 0;
358*2af541bfSCheng Xu }
359*2af541bfSCheng Xu 
360*2af541bfSCheng Xu static void erdma_polling_cmd_completions(struct erdma_cmdq *cmdq)
361*2af541bfSCheng Xu {
362*2af541bfSCheng Xu 	unsigned long flags;
363*2af541bfSCheng Xu 	u16 comp_num;
364*2af541bfSCheng Xu 
365*2af541bfSCheng Xu 	spin_lock_irqsave(&cmdq->cq.lock, flags);
366*2af541bfSCheng Xu 
367*2af541bfSCheng Xu 	/* We must have less than # of max_outstandings
368*2af541bfSCheng Xu 	 * completions at one time.
369*2af541bfSCheng Xu 	 */
370*2af541bfSCheng Xu 	for (comp_num = 0; comp_num < cmdq->max_outstandings; comp_num++)
371*2af541bfSCheng Xu 		if (erdma_poll_single_cmd_completion(cmdq))
372*2af541bfSCheng Xu 			break;
373*2af541bfSCheng Xu 
374*2af541bfSCheng Xu 	if (comp_num && cmdq->use_event)
375*2af541bfSCheng Xu 		arm_cmdq_cq(cmdq);
376*2af541bfSCheng Xu 
377*2af541bfSCheng Xu 	spin_unlock_irqrestore(&cmdq->cq.lock, flags);
378*2af541bfSCheng Xu }
379*2af541bfSCheng Xu 
380*2af541bfSCheng Xu void erdma_cmdq_completion_handler(struct erdma_cmdq *cmdq)
381*2af541bfSCheng Xu {
382*2af541bfSCheng Xu 	int got_event = 0;
383*2af541bfSCheng Xu 
384*2af541bfSCheng Xu 	if (!test_bit(ERDMA_CMDQ_STATE_OK_BIT, &cmdq->state) ||
385*2af541bfSCheng Xu 	    !cmdq->use_event)
386*2af541bfSCheng Xu 		return;
387*2af541bfSCheng Xu 
388*2af541bfSCheng Xu 	while (get_next_valid_eqe(&cmdq->eq)) {
389*2af541bfSCheng Xu 		cmdq->eq.ci++;
390*2af541bfSCheng Xu 		got_event++;
391*2af541bfSCheng Xu 	}
392*2af541bfSCheng Xu 
393*2af541bfSCheng Xu 	if (got_event) {
394*2af541bfSCheng Xu 		cmdq->cq.cmdsn++;
395*2af541bfSCheng Xu 		erdma_polling_cmd_completions(cmdq);
396*2af541bfSCheng Xu 	}
397*2af541bfSCheng Xu 
398*2af541bfSCheng Xu 	notify_eq(&cmdq->eq);
399*2af541bfSCheng Xu }
400*2af541bfSCheng Xu 
401*2af541bfSCheng Xu static int erdma_poll_cmd_completion(struct erdma_comp_wait *comp_ctx,
402*2af541bfSCheng Xu 				     struct erdma_cmdq *cmdq, u32 timeout)
403*2af541bfSCheng Xu {
404*2af541bfSCheng Xu 	unsigned long comp_timeout = jiffies + msecs_to_jiffies(timeout);
405*2af541bfSCheng Xu 
406*2af541bfSCheng Xu 	while (1) {
407*2af541bfSCheng Xu 		erdma_polling_cmd_completions(cmdq);
408*2af541bfSCheng Xu 		if (comp_ctx->cmd_status != ERDMA_CMD_STATUS_ISSUED)
409*2af541bfSCheng Xu 			break;
410*2af541bfSCheng Xu 
411*2af541bfSCheng Xu 		if (time_is_before_jiffies(comp_timeout))
412*2af541bfSCheng Xu 			return -ETIME;
413*2af541bfSCheng Xu 
414*2af541bfSCheng Xu 		msleep(20);
415*2af541bfSCheng Xu 	}
416*2af541bfSCheng Xu 
417*2af541bfSCheng Xu 	return 0;
418*2af541bfSCheng Xu }
419*2af541bfSCheng Xu 
420*2af541bfSCheng Xu static int erdma_wait_cmd_completion(struct erdma_comp_wait *comp_ctx,
421*2af541bfSCheng Xu 				     struct erdma_cmdq *cmdq, u32 timeout)
422*2af541bfSCheng Xu {
423*2af541bfSCheng Xu 	unsigned long flags = 0;
424*2af541bfSCheng Xu 
425*2af541bfSCheng Xu 	wait_for_completion_timeout(&comp_ctx->wait_event,
426*2af541bfSCheng Xu 				    msecs_to_jiffies(timeout));
427*2af541bfSCheng Xu 
428*2af541bfSCheng Xu 	if (unlikely(comp_ctx->cmd_status != ERDMA_CMD_STATUS_FINISHED)) {
429*2af541bfSCheng Xu 		spin_lock_irqsave(&cmdq->cq.lock, flags);
430*2af541bfSCheng Xu 		comp_ctx->cmd_status = ERDMA_CMD_STATUS_TIMEOUT;
431*2af541bfSCheng Xu 		spin_unlock_irqrestore(&cmdq->cq.lock, flags);
432*2af541bfSCheng Xu 		return -ETIME;
433*2af541bfSCheng Xu 	}
434*2af541bfSCheng Xu 
435*2af541bfSCheng Xu 	return 0;
436*2af541bfSCheng Xu }
437*2af541bfSCheng Xu 
438*2af541bfSCheng Xu void erdma_cmdq_build_reqhdr(u64 *hdr, u32 mod, u32 op)
439*2af541bfSCheng Xu {
440*2af541bfSCheng Xu 	*hdr = FIELD_PREP(ERDMA_CMD_HDR_SUB_MOD_MASK, mod) |
441*2af541bfSCheng Xu 	       FIELD_PREP(ERDMA_CMD_HDR_OPCODE_MASK, op);
442*2af541bfSCheng Xu }
443*2af541bfSCheng Xu 
444*2af541bfSCheng Xu int erdma_post_cmd_wait(struct erdma_cmdq *cmdq, u64 *req, u32 req_size,
445*2af541bfSCheng Xu 			u64 *resp0, u64 *resp1)
446*2af541bfSCheng Xu {
447*2af541bfSCheng Xu 	struct erdma_comp_wait *comp_wait;
448*2af541bfSCheng Xu 	int ret;
449*2af541bfSCheng Xu 
450*2af541bfSCheng Xu 	if (!test_bit(ERDMA_CMDQ_STATE_OK_BIT, &cmdq->state))
451*2af541bfSCheng Xu 		return -ENODEV;
452*2af541bfSCheng Xu 
453*2af541bfSCheng Xu 	down(&cmdq->credits);
454*2af541bfSCheng Xu 
455*2af541bfSCheng Xu 	comp_wait = get_comp_wait(cmdq);
456*2af541bfSCheng Xu 	if (IS_ERR(comp_wait)) {
457*2af541bfSCheng Xu 		clear_bit(ERDMA_CMDQ_STATE_OK_BIT, &cmdq->state);
458*2af541bfSCheng Xu 		set_bit(ERDMA_CMDQ_STATE_CTX_ERR_BIT, &cmdq->state);
459*2af541bfSCheng Xu 		up(&cmdq->credits);
460*2af541bfSCheng Xu 		return PTR_ERR(comp_wait);
461*2af541bfSCheng Xu 	}
462*2af541bfSCheng Xu 
463*2af541bfSCheng Xu 	spin_lock(&cmdq->sq.lock);
464*2af541bfSCheng Xu 	push_cmdq_sqe(cmdq, req, req_size, comp_wait);
465*2af541bfSCheng Xu 	spin_unlock(&cmdq->sq.lock);
466*2af541bfSCheng Xu 
467*2af541bfSCheng Xu 	if (cmdq->use_event)
468*2af541bfSCheng Xu 		ret = erdma_wait_cmd_completion(comp_wait, cmdq,
469*2af541bfSCheng Xu 						ERDMA_CMDQ_TIMEOUT_MS);
470*2af541bfSCheng Xu 	else
471*2af541bfSCheng Xu 		ret = erdma_poll_cmd_completion(comp_wait, cmdq,
472*2af541bfSCheng Xu 						ERDMA_CMDQ_TIMEOUT_MS);
473*2af541bfSCheng Xu 
474*2af541bfSCheng Xu 	if (ret) {
475*2af541bfSCheng Xu 		set_bit(ERDMA_CMDQ_STATE_TIMEOUT_BIT, &cmdq->state);
476*2af541bfSCheng Xu 		clear_bit(ERDMA_CMDQ_STATE_OK_BIT, &cmdq->state);
477*2af541bfSCheng Xu 		goto out;
478*2af541bfSCheng Xu 	}
479*2af541bfSCheng Xu 
480*2af541bfSCheng Xu 	if (comp_wait->comp_status)
481*2af541bfSCheng Xu 		ret = -EIO;
482*2af541bfSCheng Xu 
483*2af541bfSCheng Xu 	if (resp0 && resp1) {
484*2af541bfSCheng Xu 		*resp0 = *((u64 *)&comp_wait->comp_data[0]);
485*2af541bfSCheng Xu 		*resp1 = *((u64 *)&comp_wait->comp_data[2]);
486*2af541bfSCheng Xu 	}
487*2af541bfSCheng Xu 	put_comp_wait(cmdq, comp_wait);
488*2af541bfSCheng Xu 
489*2af541bfSCheng Xu out:
490*2af541bfSCheng Xu 	up(&cmdq->credits);
491*2af541bfSCheng Xu 
492*2af541bfSCheng Xu 	return ret;
493*2af541bfSCheng Xu }
494