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