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