xref: /openbmc/linux/drivers/infiniband/hw/erdma/erdma_cmdq.c (revision 72769dba6dc0b8ac5793f94a83add4ce0108c44c)
12af541bfSCheng Xu // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
22af541bfSCheng Xu 
32af541bfSCheng Xu /* Authors: Cheng Xu <chengyou@linux.alibaba.com> */
42af541bfSCheng Xu /*          Kai Shen <kaishen@linux.alibaba.com> */
52af541bfSCheng Xu /* Copyright (c) 2020-2022, Alibaba Group. */
62af541bfSCheng Xu 
72af541bfSCheng Xu #include "erdma.h"
82af541bfSCheng Xu 
92af541bfSCheng Xu static void arm_cmdq_cq(struct erdma_cmdq *cmdq)
102af541bfSCheng Xu {
112af541bfSCheng Xu 	struct erdma_dev *dev = container_of(cmdq, struct erdma_dev, cmdq);
122af541bfSCheng Xu 	u64 db_data = FIELD_PREP(ERDMA_CQDB_CI_MASK, cmdq->cq.ci) |
132af541bfSCheng Xu 		      FIELD_PREP(ERDMA_CQDB_ARM_MASK, 1) |
142af541bfSCheng Xu 		      FIELD_PREP(ERDMA_CQDB_CMDSN_MASK, cmdq->cq.cmdsn) |
152af541bfSCheng Xu 		      FIELD_PREP(ERDMA_CQDB_IDX_MASK, cmdq->cq.cmdsn);
162af541bfSCheng Xu 
172af541bfSCheng Xu 	*cmdq->cq.db_record = db_data;
182af541bfSCheng Xu 	writeq(db_data, dev->func_bar + ERDMA_CMDQ_CQDB_REG);
192af541bfSCheng Xu 
202af541bfSCheng Xu 	atomic64_inc(&cmdq->cq.armed_num);
212af541bfSCheng Xu }
222af541bfSCheng Xu 
232af541bfSCheng Xu static void kick_cmdq_db(struct erdma_cmdq *cmdq)
242af541bfSCheng Xu {
252af541bfSCheng Xu 	struct erdma_dev *dev = container_of(cmdq, struct erdma_dev, cmdq);
262af541bfSCheng Xu 	u64 db_data = FIELD_PREP(ERDMA_CMD_HDR_WQEBB_INDEX_MASK, cmdq->sq.pi);
272af541bfSCheng Xu 
282af541bfSCheng Xu 	*cmdq->sq.db_record = db_data;
292af541bfSCheng Xu 	writeq(db_data, dev->func_bar + ERDMA_CMDQ_SQDB_REG);
302af541bfSCheng Xu }
312af541bfSCheng Xu 
322af541bfSCheng Xu static struct erdma_comp_wait *get_comp_wait(struct erdma_cmdq *cmdq)
332af541bfSCheng Xu {
342af541bfSCheng Xu 	int comp_idx;
352af541bfSCheng Xu 
362af541bfSCheng Xu 	spin_lock(&cmdq->lock);
372af541bfSCheng Xu 	comp_idx = find_first_zero_bit(cmdq->comp_wait_bitmap,
382af541bfSCheng Xu 				       cmdq->max_outstandings);
392af541bfSCheng Xu 	if (comp_idx == cmdq->max_outstandings) {
402af541bfSCheng Xu 		spin_unlock(&cmdq->lock);
412af541bfSCheng Xu 		return ERR_PTR(-ENOMEM);
422af541bfSCheng Xu 	}
432af541bfSCheng Xu 
442af541bfSCheng Xu 	__set_bit(comp_idx, cmdq->comp_wait_bitmap);
452af541bfSCheng Xu 	spin_unlock(&cmdq->lock);
462af541bfSCheng Xu 
472af541bfSCheng Xu 	return &cmdq->wait_pool[comp_idx];
482af541bfSCheng Xu }
492af541bfSCheng Xu 
502af541bfSCheng Xu static void put_comp_wait(struct erdma_cmdq *cmdq,
512af541bfSCheng Xu 			  struct erdma_comp_wait *comp_wait)
522af541bfSCheng Xu {
532af541bfSCheng Xu 	int used;
542af541bfSCheng Xu 
552af541bfSCheng Xu 	cmdq->wait_pool[comp_wait->ctx_id].cmd_status = ERDMA_CMD_STATUS_INIT;
562af541bfSCheng Xu 	spin_lock(&cmdq->lock);
572af541bfSCheng Xu 	used = __test_and_clear_bit(comp_wait->ctx_id, cmdq->comp_wait_bitmap);
582af541bfSCheng Xu 	spin_unlock(&cmdq->lock);
592af541bfSCheng Xu 
602af541bfSCheng Xu 	WARN_ON(!used);
612af541bfSCheng Xu }
622af541bfSCheng Xu 
632af541bfSCheng Xu static int erdma_cmdq_wait_res_init(struct erdma_dev *dev,
642af541bfSCheng Xu 				    struct erdma_cmdq *cmdq)
652af541bfSCheng Xu {
662af541bfSCheng Xu 	int i;
672af541bfSCheng Xu 
682af541bfSCheng Xu 	cmdq->wait_pool =
692af541bfSCheng Xu 		devm_kcalloc(&dev->pdev->dev, cmdq->max_outstandings,
702af541bfSCheng Xu 			     sizeof(struct erdma_comp_wait), GFP_KERNEL);
712af541bfSCheng Xu 	if (!cmdq->wait_pool)
722af541bfSCheng Xu 		return -ENOMEM;
732af541bfSCheng Xu 
742af541bfSCheng Xu 	spin_lock_init(&cmdq->lock);
752af541bfSCheng Xu 	cmdq->comp_wait_bitmap = devm_bitmap_zalloc(
762af541bfSCheng Xu 		&dev->pdev->dev, cmdq->max_outstandings, GFP_KERNEL);
772af541bfSCheng Xu 	if (!cmdq->comp_wait_bitmap)
782af541bfSCheng Xu 		return -ENOMEM;
792af541bfSCheng Xu 
802af541bfSCheng Xu 	for (i = 0; i < cmdq->max_outstandings; i++) {
812af541bfSCheng Xu 		init_completion(&cmdq->wait_pool[i].wait_event);
822af541bfSCheng Xu 		cmdq->wait_pool[i].ctx_id = i;
832af541bfSCheng Xu 	}
842af541bfSCheng Xu 
852af541bfSCheng Xu 	return 0;
862af541bfSCheng Xu }
872af541bfSCheng Xu 
882af541bfSCheng Xu static int erdma_cmdq_sq_init(struct erdma_dev *dev)
892af541bfSCheng Xu {
902af541bfSCheng Xu 	struct erdma_cmdq *cmdq = &dev->cmdq;
912af541bfSCheng Xu 	struct erdma_cmdq_sq *sq = &cmdq->sq;
922af541bfSCheng Xu 	u32 buf_size;
932af541bfSCheng Xu 
942af541bfSCheng Xu 	sq->wqebb_cnt = SQEBB_COUNT(ERDMA_CMDQ_SQE_SIZE);
952af541bfSCheng Xu 	sq->depth = cmdq->max_outstandings * sq->wqebb_cnt;
962af541bfSCheng Xu 
972af541bfSCheng Xu 	buf_size = sq->depth << SQEBB_SHIFT;
982af541bfSCheng Xu 
992af541bfSCheng Xu 	sq->qbuf =
1002af541bfSCheng Xu 		dma_alloc_coherent(&dev->pdev->dev, WARPPED_BUFSIZE(buf_size),
1012af541bfSCheng Xu 				   &sq->qbuf_dma_addr, GFP_KERNEL);
1022af541bfSCheng Xu 	if (!sq->qbuf)
1032af541bfSCheng Xu 		return -ENOMEM;
1042af541bfSCheng Xu 
1052af541bfSCheng Xu 	sq->db_record = (u64 *)(sq->qbuf + buf_size);
1062af541bfSCheng Xu 
1072af541bfSCheng Xu 	spin_lock_init(&sq->lock);
1082af541bfSCheng Xu 
1092af541bfSCheng Xu 	erdma_reg_write32(dev, ERDMA_REGS_CMDQ_SQ_ADDR_H_REG,
1102af541bfSCheng Xu 			  upper_32_bits(sq->qbuf_dma_addr));
1112af541bfSCheng Xu 	erdma_reg_write32(dev, ERDMA_REGS_CMDQ_SQ_ADDR_L_REG,
1122af541bfSCheng Xu 			  lower_32_bits(sq->qbuf_dma_addr));
1132af541bfSCheng Xu 	erdma_reg_write32(dev, ERDMA_REGS_CMDQ_DEPTH_REG, sq->depth);
1142af541bfSCheng Xu 	erdma_reg_write64(dev, ERDMA_CMDQ_SQ_DB_HOST_ADDR_REG,
1152af541bfSCheng Xu 			  sq->qbuf_dma_addr + buf_size);
1162af541bfSCheng Xu 
1172af541bfSCheng Xu 	return 0;
1182af541bfSCheng Xu }
1192af541bfSCheng Xu 
1202af541bfSCheng Xu static int erdma_cmdq_cq_init(struct erdma_dev *dev)
1212af541bfSCheng Xu {
1222af541bfSCheng Xu 	struct erdma_cmdq *cmdq = &dev->cmdq;
1232af541bfSCheng Xu 	struct erdma_cmdq_cq *cq = &cmdq->cq;
1242af541bfSCheng Xu 	u32 buf_size;
1252af541bfSCheng Xu 
1262af541bfSCheng Xu 	cq->depth = cmdq->sq.depth;
1272af541bfSCheng Xu 	buf_size = cq->depth << CQE_SHIFT;
1282af541bfSCheng Xu 
1292af541bfSCheng Xu 	cq->qbuf =
1302af541bfSCheng Xu 		dma_alloc_coherent(&dev->pdev->dev, WARPPED_BUFSIZE(buf_size),
1312af541bfSCheng Xu 				   &cq->qbuf_dma_addr, GFP_KERNEL | __GFP_ZERO);
1322af541bfSCheng Xu 	if (!cq->qbuf)
1332af541bfSCheng Xu 		return -ENOMEM;
1342af541bfSCheng Xu 
1352af541bfSCheng Xu 	spin_lock_init(&cq->lock);
1362af541bfSCheng Xu 
1372af541bfSCheng Xu 	cq->db_record = (u64 *)(cq->qbuf + buf_size);
1382af541bfSCheng Xu 
1392af541bfSCheng Xu 	atomic64_set(&cq->armed_num, 0);
1402af541bfSCheng Xu 
1412af541bfSCheng Xu 	erdma_reg_write32(dev, ERDMA_REGS_CMDQ_CQ_ADDR_H_REG,
1422af541bfSCheng Xu 			  upper_32_bits(cq->qbuf_dma_addr));
1432af541bfSCheng Xu 	erdma_reg_write32(dev, ERDMA_REGS_CMDQ_CQ_ADDR_L_REG,
1442af541bfSCheng Xu 			  lower_32_bits(cq->qbuf_dma_addr));
1452af541bfSCheng Xu 	erdma_reg_write64(dev, ERDMA_CMDQ_CQ_DB_HOST_ADDR_REG,
1462af541bfSCheng Xu 			  cq->qbuf_dma_addr + buf_size);
1472af541bfSCheng Xu 
1482af541bfSCheng Xu 	return 0;
1492af541bfSCheng Xu }
1502af541bfSCheng Xu 
1512af541bfSCheng Xu static int erdma_cmdq_eq_init(struct erdma_dev *dev)
1522af541bfSCheng Xu {
1532af541bfSCheng Xu 	struct erdma_cmdq *cmdq = &dev->cmdq;
1542af541bfSCheng Xu 	struct erdma_eq *eq = &cmdq->eq;
1552af541bfSCheng Xu 	u32 buf_size;
1562af541bfSCheng Xu 
1572af541bfSCheng Xu 	eq->depth = cmdq->max_outstandings;
1582af541bfSCheng Xu 	buf_size = eq->depth << EQE_SHIFT;
1592af541bfSCheng Xu 
1602af541bfSCheng Xu 	eq->qbuf =
1612af541bfSCheng Xu 		dma_alloc_coherent(&dev->pdev->dev, WARPPED_BUFSIZE(buf_size),
1622af541bfSCheng Xu 				   &eq->qbuf_dma_addr, GFP_KERNEL | __GFP_ZERO);
1632af541bfSCheng Xu 	if (!eq->qbuf)
1642af541bfSCheng Xu 		return -ENOMEM;
1652af541bfSCheng Xu 
1662af541bfSCheng Xu 	spin_lock_init(&eq->lock);
1672af541bfSCheng Xu 	atomic64_set(&eq->event_num, 0);
1682af541bfSCheng Xu 
169*72769dbaSCheng Xu 	eq->db = dev->func_bar + ERDMA_REGS_CEQ_DB_BASE_REG;
1702af541bfSCheng Xu 	eq->db_record = (u64 *)(eq->qbuf + buf_size);
1712af541bfSCheng Xu 
1722af541bfSCheng Xu 	erdma_reg_write32(dev, ERDMA_REGS_CMDQ_EQ_ADDR_H_REG,
1732af541bfSCheng Xu 			  upper_32_bits(eq->qbuf_dma_addr));
1742af541bfSCheng Xu 	erdma_reg_write32(dev, ERDMA_REGS_CMDQ_EQ_ADDR_L_REG,
1752af541bfSCheng Xu 			  lower_32_bits(eq->qbuf_dma_addr));
1762af541bfSCheng Xu 	erdma_reg_write32(dev, ERDMA_REGS_CMDQ_EQ_DEPTH_REG, eq->depth);
1772af541bfSCheng Xu 	erdma_reg_write64(dev, ERDMA_CMDQ_EQ_DB_HOST_ADDR_REG,
1782af541bfSCheng Xu 			  eq->qbuf_dma_addr + buf_size);
1792af541bfSCheng Xu 
1802af541bfSCheng Xu 	return 0;
1812af541bfSCheng Xu }
1822af541bfSCheng Xu 
1832af541bfSCheng Xu int erdma_cmdq_init(struct erdma_dev *dev)
1842af541bfSCheng Xu {
1852af541bfSCheng Xu 	int err, i;
1862af541bfSCheng Xu 	struct erdma_cmdq *cmdq = &dev->cmdq;
1872af541bfSCheng Xu 	u32 sts, ctrl;
1882af541bfSCheng Xu 
1892af541bfSCheng Xu 	cmdq->max_outstandings = ERDMA_CMDQ_MAX_OUTSTANDING;
1902af541bfSCheng Xu 	cmdq->use_event = false;
1912af541bfSCheng Xu 
1922af541bfSCheng Xu 	sema_init(&cmdq->credits, cmdq->max_outstandings);
1932af541bfSCheng Xu 
1942af541bfSCheng Xu 	err = erdma_cmdq_wait_res_init(dev, cmdq);
1952af541bfSCheng Xu 	if (err)
1962af541bfSCheng Xu 		return err;
1972af541bfSCheng Xu 
1982af541bfSCheng Xu 	err = erdma_cmdq_sq_init(dev);
1992af541bfSCheng Xu 	if (err)
2002af541bfSCheng Xu 		return err;
2012af541bfSCheng Xu 
2022af541bfSCheng Xu 	err = erdma_cmdq_cq_init(dev);
2032af541bfSCheng Xu 	if (err)
2042af541bfSCheng Xu 		goto err_destroy_sq;
2052af541bfSCheng Xu 
2062af541bfSCheng Xu 	err = erdma_cmdq_eq_init(dev);
2072af541bfSCheng Xu 	if (err)
2082af541bfSCheng Xu 		goto err_destroy_cq;
2092af541bfSCheng Xu 
2102af541bfSCheng Xu 	ctrl = FIELD_PREP(ERDMA_REG_DEV_CTRL_INIT_MASK, 1);
2112af541bfSCheng Xu 	erdma_reg_write32(dev, ERDMA_REGS_DEV_CTRL_REG, ctrl);
2122af541bfSCheng Xu 
2132af541bfSCheng Xu 	for (i = 0; i < ERDMA_WAIT_DEV_DONE_CNT; i++) {
2142af541bfSCheng Xu 		sts = erdma_reg_read32_filed(dev, ERDMA_REGS_DEV_ST_REG,
2152af541bfSCheng Xu 					     ERDMA_REG_DEV_ST_INIT_DONE_MASK);
2162af541bfSCheng Xu 		if (sts)
2172af541bfSCheng Xu 			break;
2182af541bfSCheng Xu 
2192af541bfSCheng Xu 		msleep(ERDMA_REG_ACCESS_WAIT_MS);
2202af541bfSCheng Xu 	}
2212af541bfSCheng Xu 
2222af541bfSCheng Xu 	if (i == ERDMA_WAIT_DEV_DONE_CNT) {
2232af541bfSCheng Xu 		dev_err(&dev->pdev->dev, "wait init done failed.\n");
2242af541bfSCheng Xu 		err = -ETIMEDOUT;
2252af541bfSCheng Xu 		goto err_destroy_eq;
2262af541bfSCheng Xu 	}
2272af541bfSCheng Xu 
2282af541bfSCheng Xu 	set_bit(ERDMA_CMDQ_STATE_OK_BIT, &cmdq->state);
2292af541bfSCheng Xu 
2302af541bfSCheng Xu 	return 0;
2312af541bfSCheng Xu 
2322af541bfSCheng Xu err_destroy_eq:
2332af541bfSCheng Xu 	dma_free_coherent(&dev->pdev->dev,
2342af541bfSCheng Xu 			  (cmdq->eq.depth << EQE_SHIFT) +
2352af541bfSCheng Xu 				  ERDMA_EXTRA_BUFFER_SIZE,
2362af541bfSCheng Xu 			  cmdq->eq.qbuf, cmdq->eq.qbuf_dma_addr);
2372af541bfSCheng Xu 
2382af541bfSCheng Xu err_destroy_cq:
2392af541bfSCheng Xu 	dma_free_coherent(&dev->pdev->dev,
2402af541bfSCheng Xu 			  (cmdq->cq.depth << CQE_SHIFT) +
2412af541bfSCheng Xu 				  ERDMA_EXTRA_BUFFER_SIZE,
2422af541bfSCheng Xu 			  cmdq->cq.qbuf, cmdq->cq.qbuf_dma_addr);
2432af541bfSCheng Xu 
2442af541bfSCheng Xu err_destroy_sq:
2452af541bfSCheng Xu 	dma_free_coherent(&dev->pdev->dev,
2462af541bfSCheng Xu 			  (cmdq->sq.depth << SQEBB_SHIFT) +
2472af541bfSCheng Xu 				  ERDMA_EXTRA_BUFFER_SIZE,
2482af541bfSCheng Xu 			  cmdq->sq.qbuf, cmdq->sq.qbuf_dma_addr);
2492af541bfSCheng Xu 
2502af541bfSCheng Xu 	return err;
2512af541bfSCheng Xu }
2522af541bfSCheng Xu 
2532af541bfSCheng Xu void erdma_finish_cmdq_init(struct erdma_dev *dev)
2542af541bfSCheng Xu {
2552af541bfSCheng Xu 	/* after device init successfully, change cmdq to event mode. */
2562af541bfSCheng Xu 	dev->cmdq.use_event = true;
2572af541bfSCheng Xu 	arm_cmdq_cq(&dev->cmdq);
2582af541bfSCheng Xu }
2592af541bfSCheng Xu 
2602af541bfSCheng Xu void erdma_cmdq_destroy(struct erdma_dev *dev)
2612af541bfSCheng Xu {
2622af541bfSCheng Xu 	struct erdma_cmdq *cmdq = &dev->cmdq;
2632af541bfSCheng Xu 
2642af541bfSCheng Xu 	clear_bit(ERDMA_CMDQ_STATE_OK_BIT, &cmdq->state);
2652af541bfSCheng Xu 
2662af541bfSCheng Xu 	dma_free_coherent(&dev->pdev->dev,
2672af541bfSCheng Xu 			  (cmdq->eq.depth << EQE_SHIFT) +
2682af541bfSCheng Xu 				  ERDMA_EXTRA_BUFFER_SIZE,
2692af541bfSCheng Xu 			  cmdq->eq.qbuf, cmdq->eq.qbuf_dma_addr);
2702af541bfSCheng Xu 	dma_free_coherent(&dev->pdev->dev,
2712af541bfSCheng Xu 			  (cmdq->sq.depth << SQEBB_SHIFT) +
2722af541bfSCheng Xu 				  ERDMA_EXTRA_BUFFER_SIZE,
2732af541bfSCheng Xu 			  cmdq->sq.qbuf, cmdq->sq.qbuf_dma_addr);
2742af541bfSCheng Xu 	dma_free_coherent(&dev->pdev->dev,
2752af541bfSCheng Xu 			  (cmdq->cq.depth << CQE_SHIFT) +
2762af541bfSCheng Xu 				  ERDMA_EXTRA_BUFFER_SIZE,
2772af541bfSCheng Xu 			  cmdq->cq.qbuf, cmdq->cq.qbuf_dma_addr);
2782af541bfSCheng Xu }
2792af541bfSCheng Xu 
2802af541bfSCheng Xu static void *get_next_valid_cmdq_cqe(struct erdma_cmdq *cmdq)
2812af541bfSCheng Xu {
2822af541bfSCheng Xu 	__be32 *cqe = get_queue_entry(cmdq->cq.qbuf, cmdq->cq.ci,
2832af541bfSCheng Xu 				      cmdq->cq.depth, CQE_SHIFT);
2842af541bfSCheng Xu 	u32 owner = FIELD_GET(ERDMA_CQE_HDR_OWNER_MASK,
285de19ec77SCheng Xu 			      be32_to_cpu(READ_ONCE(*cqe)));
2862af541bfSCheng Xu 
2872af541bfSCheng Xu 	return owner ^ !!(cmdq->cq.ci & cmdq->cq.depth) ? cqe : NULL;
2882af541bfSCheng Xu }
2892af541bfSCheng Xu 
2902af541bfSCheng Xu static void push_cmdq_sqe(struct erdma_cmdq *cmdq, u64 *req, size_t req_len,
2912af541bfSCheng Xu 			  struct erdma_comp_wait *comp_wait)
2922af541bfSCheng Xu {
2932af541bfSCheng Xu 	__le64 *wqe;
2942af541bfSCheng Xu 	u64 hdr = *req;
2952af541bfSCheng Xu 
2962af541bfSCheng Xu 	comp_wait->cmd_status = ERDMA_CMD_STATUS_ISSUED;
2972af541bfSCheng Xu 	reinit_completion(&comp_wait->wait_event);
2982af541bfSCheng Xu 	comp_wait->sq_pi = cmdq->sq.pi;
2992af541bfSCheng Xu 
3002af541bfSCheng Xu 	wqe = get_queue_entry(cmdq->sq.qbuf, cmdq->sq.pi, cmdq->sq.depth,
3012af541bfSCheng Xu 			      SQEBB_SHIFT);
3022af541bfSCheng Xu 	memcpy(wqe, req, req_len);
3032af541bfSCheng Xu 
3042af541bfSCheng Xu 	cmdq->sq.pi += cmdq->sq.wqebb_cnt;
3052af541bfSCheng Xu 	hdr |= FIELD_PREP(ERDMA_CMD_HDR_WQEBB_INDEX_MASK, cmdq->sq.pi) |
3062af541bfSCheng Xu 	       FIELD_PREP(ERDMA_CMD_HDR_CONTEXT_COOKIE_MASK,
3072af541bfSCheng Xu 			  comp_wait->ctx_id) |
3082af541bfSCheng Xu 	       FIELD_PREP(ERDMA_CMD_HDR_WQEBB_CNT_MASK, cmdq->sq.wqebb_cnt - 1);
3092af541bfSCheng Xu 	*wqe = cpu_to_le64(hdr);
3102af541bfSCheng Xu 
3112af541bfSCheng Xu 	kick_cmdq_db(cmdq);
3122af541bfSCheng Xu }
3132af541bfSCheng Xu 
3142af541bfSCheng Xu static int erdma_poll_single_cmd_completion(struct erdma_cmdq *cmdq)
3152af541bfSCheng Xu {
3162af541bfSCheng Xu 	struct erdma_comp_wait *comp_wait;
3172af541bfSCheng Xu 	u32 hdr0, sqe_idx;
3182af541bfSCheng Xu 	__be32 *cqe;
3192af541bfSCheng Xu 	u16 ctx_id;
3202af541bfSCheng Xu 	u64 *sqe;
3212af541bfSCheng Xu 
3222af541bfSCheng Xu 	cqe = get_next_valid_cmdq_cqe(cmdq);
3232af541bfSCheng Xu 	if (!cqe)
3242af541bfSCheng Xu 		return -EAGAIN;
3252af541bfSCheng Xu 
3262af541bfSCheng Xu 	cmdq->cq.ci++;
3272af541bfSCheng Xu 
3282af541bfSCheng Xu 	dma_rmb();
329de19ec77SCheng Xu 	hdr0 = be32_to_cpu(*cqe);
330de19ec77SCheng Xu 	sqe_idx = be32_to_cpu(*(cqe + 1));
3312af541bfSCheng Xu 
3322af541bfSCheng Xu 	sqe = get_queue_entry(cmdq->sq.qbuf, sqe_idx, cmdq->sq.depth,
3332af541bfSCheng Xu 			      SQEBB_SHIFT);
3342af541bfSCheng Xu 	ctx_id = FIELD_GET(ERDMA_CMD_HDR_CONTEXT_COOKIE_MASK, *sqe);
3352af541bfSCheng Xu 	comp_wait = &cmdq->wait_pool[ctx_id];
3362af541bfSCheng Xu 	if (comp_wait->cmd_status != ERDMA_CMD_STATUS_ISSUED)
3372af541bfSCheng Xu 		return -EIO;
3382af541bfSCheng Xu 
3392af541bfSCheng Xu 	comp_wait->cmd_status = ERDMA_CMD_STATUS_FINISHED;
3402af541bfSCheng Xu 	comp_wait->comp_status = FIELD_GET(ERDMA_CQE_HDR_SYNDROME_MASK, hdr0);
3412af541bfSCheng Xu 	cmdq->sq.ci += cmdq->sq.wqebb_cnt;
342de19ec77SCheng Xu 	/* Copy 16B comp data after cqe hdr to outer */
343de19ec77SCheng Xu 	be32_to_cpu_array(comp_wait->comp_data, cqe + 2, 4);
3442af541bfSCheng Xu 
3452af541bfSCheng Xu 	if (cmdq->use_event)
3462af541bfSCheng Xu 		complete(&comp_wait->wait_event);
3472af541bfSCheng Xu 
3482af541bfSCheng Xu 	return 0;
3492af541bfSCheng Xu }
3502af541bfSCheng Xu 
3512af541bfSCheng Xu static void erdma_polling_cmd_completions(struct erdma_cmdq *cmdq)
3522af541bfSCheng Xu {
3532af541bfSCheng Xu 	unsigned long flags;
3542af541bfSCheng Xu 	u16 comp_num;
3552af541bfSCheng Xu 
3562af541bfSCheng Xu 	spin_lock_irqsave(&cmdq->cq.lock, flags);
3572af541bfSCheng Xu 
3582af541bfSCheng Xu 	/* We must have less than # of max_outstandings
3592af541bfSCheng Xu 	 * completions at one time.
3602af541bfSCheng Xu 	 */
3612af541bfSCheng Xu 	for (comp_num = 0; comp_num < cmdq->max_outstandings; comp_num++)
3622af541bfSCheng Xu 		if (erdma_poll_single_cmd_completion(cmdq))
3632af541bfSCheng Xu 			break;
3642af541bfSCheng Xu 
3652af541bfSCheng Xu 	if (comp_num && cmdq->use_event)
3662af541bfSCheng Xu 		arm_cmdq_cq(cmdq);
3672af541bfSCheng Xu 
3682af541bfSCheng Xu 	spin_unlock_irqrestore(&cmdq->cq.lock, flags);
3692af541bfSCheng Xu }
3702af541bfSCheng Xu 
3712af541bfSCheng Xu void erdma_cmdq_completion_handler(struct erdma_cmdq *cmdq)
3722af541bfSCheng Xu {
3732af541bfSCheng Xu 	int got_event = 0;
3742af541bfSCheng Xu 
3752af541bfSCheng Xu 	if (!test_bit(ERDMA_CMDQ_STATE_OK_BIT, &cmdq->state) ||
3762af541bfSCheng Xu 	    !cmdq->use_event)
3772af541bfSCheng Xu 		return;
3782af541bfSCheng Xu 
3792af541bfSCheng Xu 	while (get_next_valid_eqe(&cmdq->eq)) {
3802af541bfSCheng Xu 		cmdq->eq.ci++;
3812af541bfSCheng Xu 		got_event++;
3822af541bfSCheng Xu 	}
3832af541bfSCheng Xu 
3842af541bfSCheng Xu 	if (got_event) {
3852af541bfSCheng Xu 		cmdq->cq.cmdsn++;
3862af541bfSCheng Xu 		erdma_polling_cmd_completions(cmdq);
3872af541bfSCheng Xu 	}
3882af541bfSCheng Xu 
3892af541bfSCheng Xu 	notify_eq(&cmdq->eq);
3902af541bfSCheng Xu }
3912af541bfSCheng Xu 
3922af541bfSCheng Xu static int erdma_poll_cmd_completion(struct erdma_comp_wait *comp_ctx,
3932af541bfSCheng Xu 				     struct erdma_cmdq *cmdq, u32 timeout)
3942af541bfSCheng Xu {
3952af541bfSCheng Xu 	unsigned long comp_timeout = jiffies + msecs_to_jiffies(timeout);
3962af541bfSCheng Xu 
3972af541bfSCheng Xu 	while (1) {
3982af541bfSCheng Xu 		erdma_polling_cmd_completions(cmdq);
3992af541bfSCheng Xu 		if (comp_ctx->cmd_status != ERDMA_CMD_STATUS_ISSUED)
4002af541bfSCheng Xu 			break;
4012af541bfSCheng Xu 
4022af541bfSCheng Xu 		if (time_is_before_jiffies(comp_timeout))
4032af541bfSCheng Xu 			return -ETIME;
4042af541bfSCheng Xu 
4052af541bfSCheng Xu 		msleep(20);
4062af541bfSCheng Xu 	}
4072af541bfSCheng Xu 
4082af541bfSCheng Xu 	return 0;
4092af541bfSCheng Xu }
4102af541bfSCheng Xu 
4112af541bfSCheng Xu static int erdma_wait_cmd_completion(struct erdma_comp_wait *comp_ctx,
4122af541bfSCheng Xu 				     struct erdma_cmdq *cmdq, u32 timeout)
4132af541bfSCheng Xu {
4142af541bfSCheng Xu 	unsigned long flags = 0;
4152af541bfSCheng Xu 
4162af541bfSCheng Xu 	wait_for_completion_timeout(&comp_ctx->wait_event,
4172af541bfSCheng Xu 				    msecs_to_jiffies(timeout));
4182af541bfSCheng Xu 
4192af541bfSCheng Xu 	if (unlikely(comp_ctx->cmd_status != ERDMA_CMD_STATUS_FINISHED)) {
4202af541bfSCheng Xu 		spin_lock_irqsave(&cmdq->cq.lock, flags);
4212af541bfSCheng Xu 		comp_ctx->cmd_status = ERDMA_CMD_STATUS_TIMEOUT;
4222af541bfSCheng Xu 		spin_unlock_irqrestore(&cmdq->cq.lock, flags);
4232af541bfSCheng Xu 		return -ETIME;
4242af541bfSCheng Xu 	}
4252af541bfSCheng Xu 
4262af541bfSCheng Xu 	return 0;
4272af541bfSCheng Xu }
4282af541bfSCheng Xu 
4292af541bfSCheng Xu void erdma_cmdq_build_reqhdr(u64 *hdr, u32 mod, u32 op)
4302af541bfSCheng Xu {
4312af541bfSCheng Xu 	*hdr = FIELD_PREP(ERDMA_CMD_HDR_SUB_MOD_MASK, mod) |
4322af541bfSCheng Xu 	       FIELD_PREP(ERDMA_CMD_HDR_OPCODE_MASK, op);
4332af541bfSCheng Xu }
4342af541bfSCheng Xu 
43595f911d9SCheng Xu int erdma_post_cmd_wait(struct erdma_cmdq *cmdq, void *req, u32 req_size,
4362af541bfSCheng Xu 			u64 *resp0, u64 *resp1)
4372af541bfSCheng Xu {
4382af541bfSCheng Xu 	struct erdma_comp_wait *comp_wait;
4392af541bfSCheng Xu 	int ret;
4402af541bfSCheng Xu 
4412af541bfSCheng Xu 	if (!test_bit(ERDMA_CMDQ_STATE_OK_BIT, &cmdq->state))
4422af541bfSCheng Xu 		return -ENODEV;
4432af541bfSCheng Xu 
4442af541bfSCheng Xu 	down(&cmdq->credits);
4452af541bfSCheng Xu 
4462af541bfSCheng Xu 	comp_wait = get_comp_wait(cmdq);
4472af541bfSCheng Xu 	if (IS_ERR(comp_wait)) {
4482af541bfSCheng Xu 		clear_bit(ERDMA_CMDQ_STATE_OK_BIT, &cmdq->state);
4492af541bfSCheng Xu 		set_bit(ERDMA_CMDQ_STATE_CTX_ERR_BIT, &cmdq->state);
4502af541bfSCheng Xu 		up(&cmdq->credits);
4512af541bfSCheng Xu 		return PTR_ERR(comp_wait);
4522af541bfSCheng Xu 	}
4532af541bfSCheng Xu 
4542af541bfSCheng Xu 	spin_lock(&cmdq->sq.lock);
4552af541bfSCheng Xu 	push_cmdq_sqe(cmdq, req, req_size, comp_wait);
4562af541bfSCheng Xu 	spin_unlock(&cmdq->sq.lock);
4572af541bfSCheng Xu 
4582af541bfSCheng Xu 	if (cmdq->use_event)
4592af541bfSCheng Xu 		ret = erdma_wait_cmd_completion(comp_wait, cmdq,
4602af541bfSCheng Xu 						ERDMA_CMDQ_TIMEOUT_MS);
4612af541bfSCheng Xu 	else
4622af541bfSCheng Xu 		ret = erdma_poll_cmd_completion(comp_wait, cmdq,
4632af541bfSCheng Xu 						ERDMA_CMDQ_TIMEOUT_MS);
4642af541bfSCheng Xu 
4652af541bfSCheng Xu 	if (ret) {
4662af541bfSCheng Xu 		set_bit(ERDMA_CMDQ_STATE_TIMEOUT_BIT, &cmdq->state);
4672af541bfSCheng Xu 		clear_bit(ERDMA_CMDQ_STATE_OK_BIT, &cmdq->state);
4682af541bfSCheng Xu 		goto out;
4692af541bfSCheng Xu 	}
4702af541bfSCheng Xu 
4712af541bfSCheng Xu 	if (comp_wait->comp_status)
4722af541bfSCheng Xu 		ret = -EIO;
4732af541bfSCheng Xu 
4742af541bfSCheng Xu 	if (resp0 && resp1) {
4752af541bfSCheng Xu 		*resp0 = *((u64 *)&comp_wait->comp_data[0]);
4762af541bfSCheng Xu 		*resp1 = *((u64 *)&comp_wait->comp_data[2]);
4772af541bfSCheng Xu 	}
4782af541bfSCheng Xu 	put_comp_wait(cmdq, comp_wait);
4792af541bfSCheng Xu 
4802af541bfSCheng Xu out:
4812af541bfSCheng Xu 	up(&cmdq->credits);
4822af541bfSCheng Xu 
4832af541bfSCheng Xu 	return ret;
4842af541bfSCheng Xu }
485