12025cf9eSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
253e7d6feSAviad Krawczyk /*
353e7d6feSAviad Krawczyk * Huawei HiNIC PCI Express Linux driver
453e7d6feSAviad Krawczyk * Copyright(c) 2017 Huawei Technologies Co., Ltd
553e7d6feSAviad Krawczyk */
653e7d6feSAviad Krawczyk
7d0b9805eSAviad Krawczyk #include <linux/kernel.h>
853e7d6feSAviad Krawczyk #include <linux/types.h>
953e7d6feSAviad Krawczyk #include <linux/errno.h>
10d0b9805eSAviad Krawczyk #include <linux/pci.h>
11d0b9805eSAviad Krawczyk #include <linux/device.h>
12d0b9805eSAviad Krawczyk #include <linux/slab.h>
13d0b9805eSAviad Krawczyk #include <linux/vmalloc.h>
14d0b9805eSAviad Krawczyk #include <linux/spinlock.h>
15d0b9805eSAviad Krawczyk #include <linux/sizes.h>
16d0b9805eSAviad Krawczyk #include <linux/atomic.h>
17d0b9805eSAviad Krawczyk #include <linux/log2.h>
1876baca2eSAviad Krawczyk #include <linux/io.h>
1976baca2eSAviad Krawczyk #include <linux/completion.h>
2076baca2eSAviad Krawczyk #include <linux/err.h>
21d0b9805eSAviad Krawczyk #include <asm/byteorder.h>
2276baca2eSAviad Krawczyk #include <asm/barrier.h>
2353e7d6feSAviad Krawczyk
2476baca2eSAviad Krawczyk #include "hinic_common.h"
2553e7d6feSAviad Krawczyk #include "hinic_hw_if.h"
26fc9319e4SAviad Krawczyk #include "hinic_hw_eqs.h"
27d0b9805eSAviad Krawczyk #include "hinic_hw_mgmt.h"
2876baca2eSAviad Krawczyk #include "hinic_hw_wqe.h"
29d0b9805eSAviad Krawczyk #include "hinic_hw_wq.h"
3053e7d6feSAviad Krawczyk #include "hinic_hw_cmdq.h"
31d0b9805eSAviad Krawczyk #include "hinic_hw_io.h"
32d0b9805eSAviad Krawczyk #include "hinic_hw_dev.h"
33d0b9805eSAviad Krawczyk
347ef37fe4SAviad Krawczyk #define CMDQ_CEQE_TYPE_SHIFT 0
357ef37fe4SAviad Krawczyk
367ef37fe4SAviad Krawczyk #define CMDQ_CEQE_TYPE_MASK 0x7
377ef37fe4SAviad Krawczyk
387ef37fe4SAviad Krawczyk #define CMDQ_CEQE_GET(val, member) \
397ef37fe4SAviad Krawczyk (((val) >> CMDQ_CEQE_##member##_SHIFT) \
407ef37fe4SAviad Krawczyk & CMDQ_CEQE_##member##_MASK)
417ef37fe4SAviad Krawczyk
427ef37fe4SAviad Krawczyk #define CMDQ_WQE_ERRCODE_VAL_SHIFT 20
437ef37fe4SAviad Krawczyk
447ef37fe4SAviad Krawczyk #define CMDQ_WQE_ERRCODE_VAL_MASK 0xF
457ef37fe4SAviad Krawczyk
467ef37fe4SAviad Krawczyk #define CMDQ_WQE_ERRCODE_GET(val, member) \
477ef37fe4SAviad Krawczyk (((val) >> CMDQ_WQE_ERRCODE_##member##_SHIFT) \
487ef37fe4SAviad Krawczyk & CMDQ_WQE_ERRCODE_##member##_MASK)
497ef37fe4SAviad Krawczyk
5076baca2eSAviad Krawczyk #define CMDQ_DB_PI_OFF(pi) (((u16)LOWER_8_BITS(pi)) << 3)
5176baca2eSAviad Krawczyk
5276baca2eSAviad Krawczyk #define CMDQ_DB_ADDR(db_base, pi) ((db_base) + CMDQ_DB_PI_OFF(pi))
5376baca2eSAviad Krawczyk
5476baca2eSAviad Krawczyk #define CMDQ_WQE_HEADER(wqe) ((struct hinic_cmdq_header *)(wqe))
5576baca2eSAviad Krawczyk
567ef37fe4SAviad Krawczyk #define CMDQ_WQE_COMPLETED(ctrl_info) \
577ef37fe4SAviad Krawczyk HINIC_CMDQ_CTRL_GET(ctrl_info, HW_BUSY_BIT)
587ef37fe4SAviad Krawczyk
5976baca2eSAviad Krawczyk #define FIRST_DATA_TO_WRITE_LAST sizeof(u64)
6076baca2eSAviad Krawczyk
61d0b9805eSAviad Krawczyk #define CMDQ_DB_OFF SZ_2K
62d0b9805eSAviad Krawczyk
63d0b9805eSAviad Krawczyk #define CMDQ_WQEBB_SIZE 64
6476baca2eSAviad Krawczyk #define CMDQ_WQE_SIZE 64
65d0b9805eSAviad Krawczyk #define CMDQ_DEPTH SZ_4K
66d0b9805eSAviad Krawczyk
677dd29ee1SLuo bin #define CMDQ_WQ_PAGE_SIZE SZ_256K
68d0b9805eSAviad Krawczyk
69d0b9805eSAviad Krawczyk #define WQE_LCMD_SIZE 64
70d0b9805eSAviad Krawczyk #define WQE_SCMD_SIZE 64
71d0b9805eSAviad Krawczyk
7276baca2eSAviad Krawczyk #define COMPLETE_LEN 3
7376baca2eSAviad Krawczyk
7476baca2eSAviad Krawczyk #define CMDQ_TIMEOUT 1000
7576baca2eSAviad Krawczyk
76d0b9805eSAviad Krawczyk #define CMDQ_PFN(addr, page_size) ((addr) >> (ilog2(page_size)))
77d0b9805eSAviad Krawczyk
78d0b9805eSAviad Krawczyk #define cmdq_to_cmdqs(cmdq) container_of((cmdq) - (cmdq)->cmdq_type, \
79d0b9805eSAviad Krawczyk struct hinic_cmdqs, cmdq[0])
80d0b9805eSAviad Krawczyk
81d0b9805eSAviad Krawczyk #define cmdqs_to_func_to_io(cmdqs) container_of(cmdqs, \
82d0b9805eSAviad Krawczyk struct hinic_func_to_io, \
83d0b9805eSAviad Krawczyk cmdqs)
84d0b9805eSAviad Krawczyk
8576baca2eSAviad Krawczyk enum completion_format {
8676baca2eSAviad Krawczyk COMPLETE_DIRECT = 0,
8776baca2eSAviad Krawczyk COMPLETE_SGE = 1,
8876baca2eSAviad Krawczyk };
8976baca2eSAviad Krawczyk
9076baca2eSAviad Krawczyk enum data_format {
9176baca2eSAviad Krawczyk DATA_SGE = 0,
9276baca2eSAviad Krawczyk DATA_DIRECT = 1,
9376baca2eSAviad Krawczyk };
9476baca2eSAviad Krawczyk
9576baca2eSAviad Krawczyk enum bufdesc_len {
9676baca2eSAviad Krawczyk BUFDESC_LCMD_LEN = 2, /* 16 bytes - 2(8 byte unit) */
9776baca2eSAviad Krawczyk BUFDESC_SCMD_LEN = 3, /* 24 bytes - 3(8 byte unit) */
9876baca2eSAviad Krawczyk };
9976baca2eSAviad Krawczyk
10076baca2eSAviad Krawczyk enum ctrl_sect_len {
10176baca2eSAviad Krawczyk CTRL_SECT_LEN = 1, /* 4 bytes (ctrl) - 1(8 byte unit) */
10276baca2eSAviad Krawczyk CTRL_DIRECT_SECT_LEN = 2, /* 12 bytes (ctrl + rsvd) - 2(8 byte unit) */
10376baca2eSAviad Krawczyk };
10476baca2eSAviad Krawczyk
10576baca2eSAviad Krawczyk enum cmdq_scmd_type {
10676baca2eSAviad Krawczyk CMDQ_SET_ARM_CMD = 2,
10776baca2eSAviad Krawczyk };
10876baca2eSAviad Krawczyk
10976baca2eSAviad Krawczyk enum cmdq_cmd_type {
11076baca2eSAviad Krawczyk CMDQ_CMD_SYNC_DIRECT_RESP = 0,
11176baca2eSAviad Krawczyk CMDQ_CMD_SYNC_SGE_RESP = 1,
11276baca2eSAviad Krawczyk };
11376baca2eSAviad Krawczyk
11476baca2eSAviad Krawczyk enum completion_request {
11576baca2eSAviad Krawczyk NO_CEQ = 0,
11676baca2eSAviad Krawczyk CEQ_SET = 1,
11776baca2eSAviad Krawczyk };
11876baca2eSAviad Krawczyk
11953e7d6feSAviad Krawczyk /**
12053e7d6feSAviad Krawczyk * hinic_alloc_cmdq_buf - alloc buffer for sending command
12153e7d6feSAviad Krawczyk * @cmdqs: the cmdqs
12253e7d6feSAviad Krawczyk * @cmdq_buf: the buffer returned in this struct
12353e7d6feSAviad Krawczyk *
12453e7d6feSAviad Krawczyk * Return 0 - Success, negative - Failure
12553e7d6feSAviad Krawczyk **/
hinic_alloc_cmdq_buf(struct hinic_cmdqs * cmdqs,struct hinic_cmdq_buf * cmdq_buf)12653e7d6feSAviad Krawczyk int hinic_alloc_cmdq_buf(struct hinic_cmdqs *cmdqs,
12753e7d6feSAviad Krawczyk struct hinic_cmdq_buf *cmdq_buf)
12853e7d6feSAviad Krawczyk {
129d0b9805eSAviad Krawczyk struct hinic_hwif *hwif = cmdqs->hwif;
130d0b9805eSAviad Krawczyk struct pci_dev *pdev = hwif->pdev;
131d0b9805eSAviad Krawczyk
1323203e1d9SRomain Perier cmdq_buf->buf = dma_pool_alloc(cmdqs->cmdq_buf_pool, GFP_KERNEL,
133d0b9805eSAviad Krawczyk &cmdq_buf->dma_addr);
134d0b9805eSAviad Krawczyk if (!cmdq_buf->buf) {
135d0b9805eSAviad Krawczyk dev_err(&pdev->dev, "Failed to allocate cmd from the pool\n");
13653e7d6feSAviad Krawczyk return -ENOMEM;
13753e7d6feSAviad Krawczyk }
13853e7d6feSAviad Krawczyk
139d0b9805eSAviad Krawczyk return 0;
140d0b9805eSAviad Krawczyk }
141d0b9805eSAviad Krawczyk
14253e7d6feSAviad Krawczyk /**
14353e7d6feSAviad Krawczyk * hinic_free_cmdq_buf - free buffer
14453e7d6feSAviad Krawczyk * @cmdqs: the cmdqs
14553e7d6feSAviad Krawczyk * @cmdq_buf: the buffer to free that is in this struct
14653e7d6feSAviad Krawczyk **/
hinic_free_cmdq_buf(struct hinic_cmdqs * cmdqs,struct hinic_cmdq_buf * cmdq_buf)14753e7d6feSAviad Krawczyk void hinic_free_cmdq_buf(struct hinic_cmdqs *cmdqs,
14853e7d6feSAviad Krawczyk struct hinic_cmdq_buf *cmdq_buf)
14953e7d6feSAviad Krawczyk {
1503203e1d9SRomain Perier dma_pool_free(cmdqs->cmdq_buf_pool, cmdq_buf->buf, cmdq_buf->dma_addr);
15153e7d6feSAviad Krawczyk }
15253e7d6feSAviad Krawczyk
cmdq_wqe_size_from_bdlen(enum bufdesc_len len)1537ef37fe4SAviad Krawczyk static unsigned int cmdq_wqe_size_from_bdlen(enum bufdesc_len len)
1547ef37fe4SAviad Krawczyk {
1557ef37fe4SAviad Krawczyk unsigned int wqe_size = 0;
1567ef37fe4SAviad Krawczyk
1577ef37fe4SAviad Krawczyk switch (len) {
1587ef37fe4SAviad Krawczyk case BUFDESC_LCMD_LEN:
1597ef37fe4SAviad Krawczyk wqe_size = WQE_LCMD_SIZE;
1607ef37fe4SAviad Krawczyk break;
1617ef37fe4SAviad Krawczyk case BUFDESC_SCMD_LEN:
1627ef37fe4SAviad Krawczyk wqe_size = WQE_SCMD_SIZE;
1637ef37fe4SAviad Krawczyk break;
1647ef37fe4SAviad Krawczyk }
1657ef37fe4SAviad Krawczyk
1667ef37fe4SAviad Krawczyk return wqe_size;
1677ef37fe4SAviad Krawczyk }
1687ef37fe4SAviad Krawczyk
cmdq_set_sge_completion(struct hinic_cmdq_completion * completion,struct hinic_cmdq_buf * buf_out)16976baca2eSAviad Krawczyk static void cmdq_set_sge_completion(struct hinic_cmdq_completion *completion,
17076baca2eSAviad Krawczyk struct hinic_cmdq_buf *buf_out)
17176baca2eSAviad Krawczyk {
17276baca2eSAviad Krawczyk struct hinic_sge_resp *sge_resp = &completion->sge_resp;
17376baca2eSAviad Krawczyk
17476baca2eSAviad Krawczyk hinic_set_sge(&sge_resp->sge, buf_out->dma_addr, buf_out->size);
17576baca2eSAviad Krawczyk }
17676baca2eSAviad Krawczyk
cmdq_prepare_wqe_ctrl(struct hinic_cmdq_wqe * wqe,int wrapped,enum hinic_cmd_ack_type ack_type,enum hinic_mod_type mod,u8 cmd,u16 prod_idx,enum completion_format complete_format,enum data_format data_format,enum bufdesc_len buf_len)17776baca2eSAviad Krawczyk static void cmdq_prepare_wqe_ctrl(struct hinic_cmdq_wqe *wqe, int wrapped,
17876baca2eSAviad Krawczyk enum hinic_cmd_ack_type ack_type,
17976baca2eSAviad Krawczyk enum hinic_mod_type mod, u8 cmd, u16 prod_idx,
18076baca2eSAviad Krawczyk enum completion_format complete_format,
18176baca2eSAviad Krawczyk enum data_format data_format,
18276baca2eSAviad Krawczyk enum bufdesc_len buf_len)
18376baca2eSAviad Krawczyk {
18476baca2eSAviad Krawczyk struct hinic_cmdq_wqe_lcmd *wqe_lcmd;
18576baca2eSAviad Krawczyk struct hinic_cmdq_wqe_scmd *wqe_scmd;
18676baca2eSAviad Krawczyk enum ctrl_sect_len ctrl_len;
18776baca2eSAviad Krawczyk struct hinic_ctrl *ctrl;
18876baca2eSAviad Krawczyk u32 saved_data;
18976baca2eSAviad Krawczyk
19076baca2eSAviad Krawczyk if (data_format == DATA_SGE) {
19176baca2eSAviad Krawczyk wqe_lcmd = &wqe->wqe_lcmd;
19276baca2eSAviad Krawczyk
19376baca2eSAviad Krawczyk wqe_lcmd->status.status_info = 0;
19476baca2eSAviad Krawczyk ctrl = &wqe_lcmd->ctrl;
19576baca2eSAviad Krawczyk ctrl_len = CTRL_SECT_LEN;
19676baca2eSAviad Krawczyk } else {
19776baca2eSAviad Krawczyk wqe_scmd = &wqe->direct_wqe.wqe_scmd;
19876baca2eSAviad Krawczyk
19976baca2eSAviad Krawczyk wqe_scmd->status.status_info = 0;
20076baca2eSAviad Krawczyk ctrl = &wqe_scmd->ctrl;
20176baca2eSAviad Krawczyk ctrl_len = CTRL_DIRECT_SECT_LEN;
20276baca2eSAviad Krawczyk }
20376baca2eSAviad Krawczyk
20476baca2eSAviad Krawczyk ctrl->ctrl_info = HINIC_CMDQ_CTRL_SET(prod_idx, PI) |
20576baca2eSAviad Krawczyk HINIC_CMDQ_CTRL_SET(cmd, CMD) |
20676baca2eSAviad Krawczyk HINIC_CMDQ_CTRL_SET(mod, MOD) |
20776baca2eSAviad Krawczyk HINIC_CMDQ_CTRL_SET(ack_type, ACK_TYPE);
20876baca2eSAviad Krawczyk
20976baca2eSAviad Krawczyk CMDQ_WQE_HEADER(wqe)->header_info =
21076baca2eSAviad Krawczyk HINIC_CMDQ_WQE_HEADER_SET(buf_len, BUFDESC_LEN) |
21176baca2eSAviad Krawczyk HINIC_CMDQ_WQE_HEADER_SET(complete_format, COMPLETE_FMT) |
21276baca2eSAviad Krawczyk HINIC_CMDQ_WQE_HEADER_SET(data_format, DATA_FMT) |
21376baca2eSAviad Krawczyk HINIC_CMDQ_WQE_HEADER_SET(CEQ_SET, COMPLETE_REQ) |
21476baca2eSAviad Krawczyk HINIC_CMDQ_WQE_HEADER_SET(COMPLETE_LEN, COMPLETE_SECT_LEN) |
21576baca2eSAviad Krawczyk HINIC_CMDQ_WQE_HEADER_SET(ctrl_len, CTRL_LEN) |
21676baca2eSAviad Krawczyk HINIC_CMDQ_WQE_HEADER_SET(wrapped, TOGGLED_WRAPPED);
21776baca2eSAviad Krawczyk
21876baca2eSAviad Krawczyk saved_data = CMDQ_WQE_HEADER(wqe)->saved_data;
21976baca2eSAviad Krawczyk saved_data = HINIC_SAVED_DATA_CLEAR(saved_data, ARM);
22076baca2eSAviad Krawczyk
221c8ad5df6SGuangbin Huang if (cmd == CMDQ_SET_ARM_CMD && mod == HINIC_MOD_COMM)
22276baca2eSAviad Krawczyk CMDQ_WQE_HEADER(wqe)->saved_data |=
22376baca2eSAviad Krawczyk HINIC_SAVED_DATA_SET(1, ARM);
22476baca2eSAviad Krawczyk else
22576baca2eSAviad Krawczyk CMDQ_WQE_HEADER(wqe)->saved_data = saved_data;
22676baca2eSAviad Krawczyk }
22776baca2eSAviad Krawczyk
cmdq_set_lcmd_bufdesc(struct hinic_cmdq_wqe_lcmd * wqe_lcmd,struct hinic_cmdq_buf * buf_in)22876baca2eSAviad Krawczyk static void cmdq_set_lcmd_bufdesc(struct hinic_cmdq_wqe_lcmd *wqe_lcmd,
22976baca2eSAviad Krawczyk struct hinic_cmdq_buf *buf_in)
23076baca2eSAviad Krawczyk {
23176baca2eSAviad Krawczyk hinic_set_sge(&wqe_lcmd->buf_desc.sge, buf_in->dma_addr, buf_in->size);
23276baca2eSAviad Krawczyk }
23376baca2eSAviad Krawczyk
cmdq_set_direct_wqe_data(struct hinic_cmdq_direct_wqe * wqe,void * buf_in,u32 in_size)2347ef37fe4SAviad Krawczyk static void cmdq_set_direct_wqe_data(struct hinic_cmdq_direct_wqe *wqe,
2357ef37fe4SAviad Krawczyk void *buf_in, u32 in_size)
2367ef37fe4SAviad Krawczyk {
2377ef37fe4SAviad Krawczyk struct hinic_cmdq_wqe_scmd *wqe_scmd = &wqe->wqe_scmd;
2387ef37fe4SAviad Krawczyk
2397ef37fe4SAviad Krawczyk wqe_scmd->buf_desc.buf_len = in_size;
2407ef37fe4SAviad Krawczyk memcpy(wqe_scmd->buf_desc.data, buf_in, in_size);
2417ef37fe4SAviad Krawczyk }
2427ef37fe4SAviad Krawczyk
cmdq_set_lcmd_wqe(struct hinic_cmdq_wqe * wqe,enum cmdq_cmd_type cmd_type,struct hinic_cmdq_buf * buf_in,struct hinic_cmdq_buf * buf_out,int wrapped,enum hinic_cmd_ack_type ack_type,enum hinic_mod_type mod,u8 cmd,u16 prod_idx)24376baca2eSAviad Krawczyk static void cmdq_set_lcmd_wqe(struct hinic_cmdq_wqe *wqe,
24476baca2eSAviad Krawczyk enum cmdq_cmd_type cmd_type,
24576baca2eSAviad Krawczyk struct hinic_cmdq_buf *buf_in,
24676baca2eSAviad Krawczyk struct hinic_cmdq_buf *buf_out, int wrapped,
24776baca2eSAviad Krawczyk enum hinic_cmd_ack_type ack_type,
24876baca2eSAviad Krawczyk enum hinic_mod_type mod, u8 cmd, u16 prod_idx)
24976baca2eSAviad Krawczyk {
25076baca2eSAviad Krawczyk struct hinic_cmdq_wqe_lcmd *wqe_lcmd = &wqe->wqe_lcmd;
25176baca2eSAviad Krawczyk enum completion_format complete_format;
25276baca2eSAviad Krawczyk
25376baca2eSAviad Krawczyk switch (cmd_type) {
25476baca2eSAviad Krawczyk case CMDQ_CMD_SYNC_SGE_RESP:
25576baca2eSAviad Krawczyk complete_format = COMPLETE_SGE;
25676baca2eSAviad Krawczyk cmdq_set_sge_completion(&wqe_lcmd->completion, buf_out);
25776baca2eSAviad Krawczyk break;
25876baca2eSAviad Krawczyk case CMDQ_CMD_SYNC_DIRECT_RESP:
25976baca2eSAviad Krawczyk complete_format = COMPLETE_DIRECT;
26076baca2eSAviad Krawczyk wqe_lcmd->completion.direct_resp = 0;
26176baca2eSAviad Krawczyk break;
26276baca2eSAviad Krawczyk }
26376baca2eSAviad Krawczyk
26476baca2eSAviad Krawczyk cmdq_prepare_wqe_ctrl(wqe, wrapped, ack_type, mod, cmd,
26576baca2eSAviad Krawczyk prod_idx, complete_format, DATA_SGE,
26676baca2eSAviad Krawczyk BUFDESC_LCMD_LEN);
26776baca2eSAviad Krawczyk
26876baca2eSAviad Krawczyk cmdq_set_lcmd_bufdesc(wqe_lcmd, buf_in);
26976baca2eSAviad Krawczyk }
27076baca2eSAviad Krawczyk
cmdq_set_direct_wqe(struct hinic_cmdq_wqe * wqe,enum cmdq_cmd_type cmd_type,void * buf_in,u16 in_size,struct hinic_cmdq_buf * buf_out,int wrapped,enum hinic_cmd_ack_type ack_type,enum hinic_mod_type mod,u8 cmd,u16 prod_idx)2717ef37fe4SAviad Krawczyk static void cmdq_set_direct_wqe(struct hinic_cmdq_wqe *wqe,
2727ef37fe4SAviad Krawczyk enum cmdq_cmd_type cmd_type,
2737ef37fe4SAviad Krawczyk void *buf_in, u16 in_size,
2747ef37fe4SAviad Krawczyk struct hinic_cmdq_buf *buf_out, int wrapped,
2757ef37fe4SAviad Krawczyk enum hinic_cmd_ack_type ack_type,
2767ef37fe4SAviad Krawczyk enum hinic_mod_type mod, u8 cmd, u16 prod_idx)
2777ef37fe4SAviad Krawczyk {
2787ef37fe4SAviad Krawczyk struct hinic_cmdq_direct_wqe *direct_wqe = &wqe->direct_wqe;
2797ef37fe4SAviad Krawczyk enum completion_format complete_format;
2807ef37fe4SAviad Krawczyk struct hinic_cmdq_wqe_scmd *wqe_scmd;
2817ef37fe4SAviad Krawczyk
2827ef37fe4SAviad Krawczyk wqe_scmd = &direct_wqe->wqe_scmd;
2837ef37fe4SAviad Krawczyk
2847ef37fe4SAviad Krawczyk switch (cmd_type) {
2857ef37fe4SAviad Krawczyk case CMDQ_CMD_SYNC_SGE_RESP:
2867ef37fe4SAviad Krawczyk complete_format = COMPLETE_SGE;
2877ef37fe4SAviad Krawczyk cmdq_set_sge_completion(&wqe_scmd->completion, buf_out);
2887ef37fe4SAviad Krawczyk break;
2897ef37fe4SAviad Krawczyk case CMDQ_CMD_SYNC_DIRECT_RESP:
2907ef37fe4SAviad Krawczyk complete_format = COMPLETE_DIRECT;
2917ef37fe4SAviad Krawczyk wqe_scmd->completion.direct_resp = 0;
2927ef37fe4SAviad Krawczyk break;
2937ef37fe4SAviad Krawczyk }
2947ef37fe4SAviad Krawczyk
2957ef37fe4SAviad Krawczyk cmdq_prepare_wqe_ctrl(wqe, wrapped, ack_type, mod, cmd, prod_idx,
2967ef37fe4SAviad Krawczyk complete_format, DATA_DIRECT, BUFDESC_SCMD_LEN);
2977ef37fe4SAviad Krawczyk
2987ef37fe4SAviad Krawczyk cmdq_set_direct_wqe_data(direct_wqe, buf_in, in_size);
2997ef37fe4SAviad Krawczyk }
3007ef37fe4SAviad Krawczyk
cmdq_wqe_fill(void * dst,void * src)30176baca2eSAviad Krawczyk static void cmdq_wqe_fill(void *dst, void *src)
30276baca2eSAviad Krawczyk {
30376baca2eSAviad Krawczyk memcpy(dst + FIRST_DATA_TO_WRITE_LAST, src + FIRST_DATA_TO_WRITE_LAST,
30476baca2eSAviad Krawczyk CMDQ_WQE_SIZE - FIRST_DATA_TO_WRITE_LAST);
30576baca2eSAviad Krawczyk
30676baca2eSAviad Krawczyk wmb(); /* The first 8 bytes should be written last */
30776baca2eSAviad Krawczyk
30876baca2eSAviad Krawczyk *(u64 *)dst = *(u64 *)src;
30976baca2eSAviad Krawczyk }
31076baca2eSAviad Krawczyk
cmdq_fill_db(u32 * db_info,enum hinic_cmdq_type cmdq_type,u16 prod_idx)31176baca2eSAviad Krawczyk static void cmdq_fill_db(u32 *db_info,
31276baca2eSAviad Krawczyk enum hinic_cmdq_type cmdq_type, u16 prod_idx)
31376baca2eSAviad Krawczyk {
31476baca2eSAviad Krawczyk *db_info = HINIC_CMDQ_DB_INFO_SET(UPPER_8_BITS(prod_idx), HI_PROD_IDX) |
31576baca2eSAviad Krawczyk HINIC_CMDQ_DB_INFO_SET(HINIC_CTRL_PATH, PATH) |
31676baca2eSAviad Krawczyk HINIC_CMDQ_DB_INFO_SET(cmdq_type, CMDQ_TYPE) |
31776baca2eSAviad Krawczyk HINIC_CMDQ_DB_INFO_SET(HINIC_DB_CMDQ_TYPE, DB_TYPE);
31876baca2eSAviad Krawczyk }
31976baca2eSAviad Krawczyk
cmdq_set_db(struct hinic_cmdq * cmdq,enum hinic_cmdq_type cmdq_type,u16 prod_idx)32076baca2eSAviad Krawczyk static void cmdq_set_db(struct hinic_cmdq *cmdq,
32176baca2eSAviad Krawczyk enum hinic_cmdq_type cmdq_type, u16 prod_idx)
32276baca2eSAviad Krawczyk {
32376baca2eSAviad Krawczyk u32 db_info;
32476baca2eSAviad Krawczyk
32576baca2eSAviad Krawczyk cmdq_fill_db(&db_info, cmdq_type, prod_idx);
32676baca2eSAviad Krawczyk
32776baca2eSAviad Krawczyk /* The data that is written to HW should be in Big Endian Format */
32876baca2eSAviad Krawczyk db_info = cpu_to_be32(db_info);
32976baca2eSAviad Krawczyk
33076baca2eSAviad Krawczyk wmb(); /* write all before the doorbell */
33176baca2eSAviad Krawczyk
33276baca2eSAviad Krawczyk writel(db_info, CMDQ_DB_ADDR(cmdq->db_base, prod_idx));
33376baca2eSAviad Krawczyk }
33476baca2eSAviad Krawczyk
cmdq_sync_cmd_direct_resp(struct hinic_cmdq * cmdq,enum hinic_mod_type mod,u8 cmd,struct hinic_cmdq_buf * buf_in,u64 * resp)33576baca2eSAviad Krawczyk static int cmdq_sync_cmd_direct_resp(struct hinic_cmdq *cmdq,
33676baca2eSAviad Krawczyk enum hinic_mod_type mod, u8 cmd,
33776baca2eSAviad Krawczyk struct hinic_cmdq_buf *buf_in,
33876baca2eSAviad Krawczyk u64 *resp)
33976baca2eSAviad Krawczyk {
34076baca2eSAviad Krawczyk struct hinic_cmdq_wqe *curr_cmdq_wqe, cmdq_wqe;
34176baca2eSAviad Krawczyk u16 curr_prod_idx, next_prod_idx;
34276baca2eSAviad Krawczyk int errcode, wrapped, num_wqebbs;
34376baca2eSAviad Krawczyk struct hinic_wq *wq = cmdq->wq;
34476baca2eSAviad Krawczyk struct hinic_hw_wqe *hw_wqe;
34576baca2eSAviad Krawczyk struct completion done;
34676baca2eSAviad Krawczyk
34776baca2eSAviad Krawczyk /* Keep doorbell index correct. bh - for tasklet(ceq). */
34876baca2eSAviad Krawczyk spin_lock_bh(&cmdq->cmdq_lock);
34976baca2eSAviad Krawczyk
35076baca2eSAviad Krawczyk /* WQE_SIZE = WQEBB_SIZE, we will get the wq element and not shadow*/
35176baca2eSAviad Krawczyk hw_wqe = hinic_get_wqe(wq, WQE_LCMD_SIZE, &curr_prod_idx);
35276baca2eSAviad Krawczyk if (IS_ERR(hw_wqe)) {
35376baca2eSAviad Krawczyk spin_unlock_bh(&cmdq->cmdq_lock);
35476baca2eSAviad Krawczyk return -EBUSY;
35576baca2eSAviad Krawczyk }
35676baca2eSAviad Krawczyk
35776baca2eSAviad Krawczyk curr_cmdq_wqe = &hw_wqe->cmdq_wqe;
35876baca2eSAviad Krawczyk
35976baca2eSAviad Krawczyk wrapped = cmdq->wrapped;
36076baca2eSAviad Krawczyk
36176baca2eSAviad Krawczyk num_wqebbs = ALIGN(WQE_LCMD_SIZE, wq->wqebb_size) / wq->wqebb_size;
36276baca2eSAviad Krawczyk next_prod_idx = curr_prod_idx + num_wqebbs;
36376baca2eSAviad Krawczyk if (next_prod_idx >= wq->q_depth) {
36476baca2eSAviad Krawczyk cmdq->wrapped = !cmdq->wrapped;
36576baca2eSAviad Krawczyk next_prod_idx -= wq->q_depth;
36676baca2eSAviad Krawczyk }
36776baca2eSAviad Krawczyk
36876baca2eSAviad Krawczyk cmdq->errcode[curr_prod_idx] = &errcode;
36976baca2eSAviad Krawczyk
37076baca2eSAviad Krawczyk init_completion(&done);
37176baca2eSAviad Krawczyk cmdq->done[curr_prod_idx] = &done;
37276baca2eSAviad Krawczyk
37376baca2eSAviad Krawczyk cmdq_set_lcmd_wqe(&cmdq_wqe, CMDQ_CMD_SYNC_DIRECT_RESP, buf_in, NULL,
37476baca2eSAviad Krawczyk wrapped, HINIC_CMD_ACK_TYPE_CMDQ, mod, cmd,
37576baca2eSAviad Krawczyk curr_prod_idx);
37676baca2eSAviad Krawczyk
37776baca2eSAviad Krawczyk /* The data that is written to HW should be in Big Endian Format */
37876baca2eSAviad Krawczyk hinic_cpu_to_be32(&cmdq_wqe, WQE_LCMD_SIZE);
37976baca2eSAviad Krawczyk
38076baca2eSAviad Krawczyk /* CMDQ WQE is not shadow, therefore wqe will be written to wq */
38176baca2eSAviad Krawczyk cmdq_wqe_fill(curr_cmdq_wqe, &cmdq_wqe);
38276baca2eSAviad Krawczyk
38376baca2eSAviad Krawczyk cmdq_set_db(cmdq, HINIC_CMDQ_SYNC, next_prod_idx);
38476baca2eSAviad Krawczyk
38576baca2eSAviad Krawczyk spin_unlock_bh(&cmdq->cmdq_lock);
38676baca2eSAviad Krawczyk
3870da7c322SLuo bin if (!wait_for_completion_timeout(&done,
3880da7c322SLuo bin msecs_to_jiffies(CMDQ_TIMEOUT))) {
38976baca2eSAviad Krawczyk spin_lock_bh(&cmdq->cmdq_lock);
39076baca2eSAviad Krawczyk
39176baca2eSAviad Krawczyk if (cmdq->errcode[curr_prod_idx] == &errcode)
39276baca2eSAviad Krawczyk cmdq->errcode[curr_prod_idx] = NULL;
39376baca2eSAviad Krawczyk
39476baca2eSAviad Krawczyk if (cmdq->done[curr_prod_idx] == &done)
39576baca2eSAviad Krawczyk cmdq->done[curr_prod_idx] = NULL;
39676baca2eSAviad Krawczyk
39776baca2eSAviad Krawczyk spin_unlock_bh(&cmdq->cmdq_lock);
39876baca2eSAviad Krawczyk
39990f86b8aSLuo bin hinic_dump_ceq_info(cmdq->hwdev);
40076baca2eSAviad Krawczyk return -ETIMEDOUT;
40176baca2eSAviad Krawczyk }
40276baca2eSAviad Krawczyk
40376baca2eSAviad Krawczyk smp_rmb(); /* read error code after completion */
40476baca2eSAviad Krawczyk
40576baca2eSAviad Krawczyk if (resp) {
40676baca2eSAviad Krawczyk struct hinic_cmdq_wqe_lcmd *wqe_lcmd = &curr_cmdq_wqe->wqe_lcmd;
40776baca2eSAviad Krawczyk
40876baca2eSAviad Krawczyk *resp = cpu_to_be64(wqe_lcmd->completion.direct_resp);
40976baca2eSAviad Krawczyk }
41076baca2eSAviad Krawczyk
41176baca2eSAviad Krawczyk if (errcode != 0)
41276baca2eSAviad Krawczyk return -EFAULT;
41376baca2eSAviad Krawczyk
41476baca2eSAviad Krawczyk return 0;
41576baca2eSAviad Krawczyk }
41676baca2eSAviad Krawczyk
cmdq_set_arm_bit(struct hinic_cmdq * cmdq,void * buf_in,u16 in_size)4177ef37fe4SAviad Krawczyk static int cmdq_set_arm_bit(struct hinic_cmdq *cmdq, void *buf_in,
4187ef37fe4SAviad Krawczyk u16 in_size)
4197ef37fe4SAviad Krawczyk {
4207ef37fe4SAviad Krawczyk struct hinic_cmdq_wqe *curr_cmdq_wqe, cmdq_wqe;
4217ef37fe4SAviad Krawczyk u16 curr_prod_idx, next_prod_idx;
4227ef37fe4SAviad Krawczyk struct hinic_wq *wq = cmdq->wq;
4237ef37fe4SAviad Krawczyk struct hinic_hw_wqe *hw_wqe;
4247ef37fe4SAviad Krawczyk int wrapped, num_wqebbs;
4257ef37fe4SAviad Krawczyk
4267ef37fe4SAviad Krawczyk /* Keep doorbell index correct */
4277ef37fe4SAviad Krawczyk spin_lock(&cmdq->cmdq_lock);
4287ef37fe4SAviad Krawczyk
4297ef37fe4SAviad Krawczyk /* WQE_SIZE = WQEBB_SIZE, we will get the wq element and not shadow*/
4307ef37fe4SAviad Krawczyk hw_wqe = hinic_get_wqe(wq, WQE_SCMD_SIZE, &curr_prod_idx);
4317ef37fe4SAviad Krawczyk if (IS_ERR(hw_wqe)) {
4327ef37fe4SAviad Krawczyk spin_unlock(&cmdq->cmdq_lock);
4337ef37fe4SAviad Krawczyk return -EBUSY;
4347ef37fe4SAviad Krawczyk }
4357ef37fe4SAviad Krawczyk
4367ef37fe4SAviad Krawczyk curr_cmdq_wqe = &hw_wqe->cmdq_wqe;
4377ef37fe4SAviad Krawczyk
4387ef37fe4SAviad Krawczyk wrapped = cmdq->wrapped;
4397ef37fe4SAviad Krawczyk
4407ef37fe4SAviad Krawczyk num_wqebbs = ALIGN(WQE_SCMD_SIZE, wq->wqebb_size) / wq->wqebb_size;
4417ef37fe4SAviad Krawczyk next_prod_idx = curr_prod_idx + num_wqebbs;
4427ef37fe4SAviad Krawczyk if (next_prod_idx >= wq->q_depth) {
4437ef37fe4SAviad Krawczyk cmdq->wrapped = !cmdq->wrapped;
4447ef37fe4SAviad Krawczyk next_prod_idx -= wq->q_depth;
4457ef37fe4SAviad Krawczyk }
4467ef37fe4SAviad Krawczyk
4477ef37fe4SAviad Krawczyk cmdq_set_direct_wqe(&cmdq_wqe, CMDQ_CMD_SYNC_DIRECT_RESP, buf_in,
4487ef37fe4SAviad Krawczyk in_size, NULL, wrapped, HINIC_CMD_ACK_TYPE_CMDQ,
4497ef37fe4SAviad Krawczyk HINIC_MOD_COMM, CMDQ_SET_ARM_CMD, curr_prod_idx);
4507ef37fe4SAviad Krawczyk
4517ef37fe4SAviad Krawczyk /* The data that is written to HW should be in Big Endian Format */
4527ef37fe4SAviad Krawczyk hinic_cpu_to_be32(&cmdq_wqe, WQE_SCMD_SIZE);
4537ef37fe4SAviad Krawczyk
4547ef37fe4SAviad Krawczyk /* cmdq wqe is not shadow, therefore wqe will be written to wq */
4557ef37fe4SAviad Krawczyk cmdq_wqe_fill(curr_cmdq_wqe, &cmdq_wqe);
4567ef37fe4SAviad Krawczyk
4577ef37fe4SAviad Krawczyk cmdq_set_db(cmdq, HINIC_CMDQ_SYNC, next_prod_idx);
4587ef37fe4SAviad Krawczyk
4597ef37fe4SAviad Krawczyk spin_unlock(&cmdq->cmdq_lock);
4607ef37fe4SAviad Krawczyk return 0;
4617ef37fe4SAviad Krawczyk }
4627ef37fe4SAviad Krawczyk
cmdq_params_valid(struct hinic_cmdq_buf * buf_in)46376baca2eSAviad Krawczyk static int cmdq_params_valid(struct hinic_cmdq_buf *buf_in)
46476baca2eSAviad Krawczyk {
46576baca2eSAviad Krawczyk if (buf_in->size > HINIC_CMDQ_MAX_DATA_SIZE)
46676baca2eSAviad Krawczyk return -EINVAL;
46776baca2eSAviad Krawczyk
46876baca2eSAviad Krawczyk return 0;
46976baca2eSAviad Krawczyk }
47076baca2eSAviad Krawczyk
47153e7d6feSAviad Krawczyk /**
47253e7d6feSAviad Krawczyk * hinic_cmdq_direct_resp - send command with direct data as resp
47353e7d6feSAviad Krawczyk * @cmdqs: the cmdqs
47453e7d6feSAviad Krawczyk * @mod: module on the card that will handle the command
47553e7d6feSAviad Krawczyk * @cmd: the command
47653e7d6feSAviad Krawczyk * @buf_in: the buffer for the command
47753e7d6feSAviad Krawczyk * @resp: the response to return
47853e7d6feSAviad Krawczyk *
47953e7d6feSAviad Krawczyk * Return 0 - Success, negative - Failure
48053e7d6feSAviad Krawczyk **/
hinic_cmdq_direct_resp(struct hinic_cmdqs * cmdqs,enum hinic_mod_type mod,u8 cmd,struct hinic_cmdq_buf * buf_in,u64 * resp)48153e7d6feSAviad Krawczyk int hinic_cmdq_direct_resp(struct hinic_cmdqs *cmdqs,
48253e7d6feSAviad Krawczyk enum hinic_mod_type mod, u8 cmd,
48353e7d6feSAviad Krawczyk struct hinic_cmdq_buf *buf_in, u64 *resp)
48453e7d6feSAviad Krawczyk {
48576baca2eSAviad Krawczyk struct hinic_hwif *hwif = cmdqs->hwif;
48676baca2eSAviad Krawczyk struct pci_dev *pdev = hwif->pdev;
48776baca2eSAviad Krawczyk int err;
48876baca2eSAviad Krawczyk
48976baca2eSAviad Krawczyk err = cmdq_params_valid(buf_in);
49076baca2eSAviad Krawczyk if (err) {
49176baca2eSAviad Krawczyk dev_err(&pdev->dev, "Invalid CMDQ parameters\n");
49276baca2eSAviad Krawczyk return err;
49376baca2eSAviad Krawczyk }
49476baca2eSAviad Krawczyk
49576baca2eSAviad Krawczyk return cmdq_sync_cmd_direct_resp(&cmdqs->cmdq[HINIC_CMDQ_SYNC],
49676baca2eSAviad Krawczyk mod, cmd, buf_in, resp);
49753e7d6feSAviad Krawczyk }
49853e7d6feSAviad Krawczyk
49953e7d6feSAviad Krawczyk /**
5007ef37fe4SAviad Krawczyk * hinic_set_arm_bit - set arm bit for enable interrupt again
5017ef37fe4SAviad Krawczyk * @cmdqs: the cmdqs
5027ef37fe4SAviad Krawczyk * @q_type: type of queue to set the arm bit for
5037ef37fe4SAviad Krawczyk * @q_id: the queue number
5047ef37fe4SAviad Krawczyk *
5057ef37fe4SAviad Krawczyk * Return 0 - Success, negative - Failure
5067ef37fe4SAviad Krawczyk **/
hinic_set_arm_bit(struct hinic_cmdqs * cmdqs,enum hinic_set_arm_qtype q_type,u32 q_id)50773f25f16SZhengchao Shao static int hinic_set_arm_bit(struct hinic_cmdqs *cmdqs,
5087ef37fe4SAviad Krawczyk enum hinic_set_arm_qtype q_type, u32 q_id)
5097ef37fe4SAviad Krawczyk {
5107ef37fe4SAviad Krawczyk struct hinic_cmdq *cmdq = &cmdqs->cmdq[HINIC_CMDQ_SYNC];
5117ef37fe4SAviad Krawczyk struct hinic_hwif *hwif = cmdqs->hwif;
5127ef37fe4SAviad Krawczyk struct pci_dev *pdev = hwif->pdev;
5137ef37fe4SAviad Krawczyk struct hinic_cmdq_arm_bit arm_bit;
5147ef37fe4SAviad Krawczyk int err;
5157ef37fe4SAviad Krawczyk
5167ef37fe4SAviad Krawczyk arm_bit.q_type = q_type;
5177ef37fe4SAviad Krawczyk arm_bit.q_id = q_id;
5187ef37fe4SAviad Krawczyk
5197ef37fe4SAviad Krawczyk err = cmdq_set_arm_bit(cmdq, &arm_bit, sizeof(arm_bit));
5207ef37fe4SAviad Krawczyk if (err) {
5217ef37fe4SAviad Krawczyk dev_err(&pdev->dev, "Failed to set arm for qid %d\n", q_id);
5227ef37fe4SAviad Krawczyk return err;
5237ef37fe4SAviad Krawczyk }
5247ef37fe4SAviad Krawczyk
5257ef37fe4SAviad Krawczyk return 0;
5267ef37fe4SAviad Krawczyk }
5277ef37fe4SAviad Krawczyk
clear_wqe_complete_bit(struct hinic_cmdq * cmdq,struct hinic_cmdq_wqe * wqe)5287ef37fe4SAviad Krawczyk static void clear_wqe_complete_bit(struct hinic_cmdq *cmdq,
5297ef37fe4SAviad Krawczyk struct hinic_cmdq_wqe *wqe)
5307ef37fe4SAviad Krawczyk {
5317ef37fe4SAviad Krawczyk u32 header_info = be32_to_cpu(CMDQ_WQE_HEADER(wqe)->header_info);
5327ef37fe4SAviad Krawczyk unsigned int bufdesc_len, wqe_size;
5337ef37fe4SAviad Krawczyk struct hinic_ctrl *ctrl;
5347ef37fe4SAviad Krawczyk
5357ef37fe4SAviad Krawczyk bufdesc_len = HINIC_CMDQ_WQE_HEADER_GET(header_info, BUFDESC_LEN);
5367ef37fe4SAviad Krawczyk wqe_size = cmdq_wqe_size_from_bdlen(bufdesc_len);
5377ef37fe4SAviad Krawczyk if (wqe_size == WQE_LCMD_SIZE) {
5387ef37fe4SAviad Krawczyk struct hinic_cmdq_wqe_lcmd *wqe_lcmd = &wqe->wqe_lcmd;
5397ef37fe4SAviad Krawczyk
5407ef37fe4SAviad Krawczyk ctrl = &wqe_lcmd->ctrl;
5417ef37fe4SAviad Krawczyk } else {
5427ef37fe4SAviad Krawczyk struct hinic_cmdq_direct_wqe *direct_wqe = &wqe->direct_wqe;
5437ef37fe4SAviad Krawczyk struct hinic_cmdq_wqe_scmd *wqe_scmd;
5447ef37fe4SAviad Krawczyk
5457ef37fe4SAviad Krawczyk wqe_scmd = &direct_wqe->wqe_scmd;
5467ef37fe4SAviad Krawczyk ctrl = &wqe_scmd->ctrl;
5477ef37fe4SAviad Krawczyk }
5487ef37fe4SAviad Krawczyk
5497ef37fe4SAviad Krawczyk /* clear HW busy bit */
5507ef37fe4SAviad Krawczyk ctrl->ctrl_info = 0;
5517ef37fe4SAviad Krawczyk
5527ef37fe4SAviad Krawczyk wmb(); /* verify wqe is clear */
5537ef37fe4SAviad Krawczyk }
5547ef37fe4SAviad Krawczyk
5557ef37fe4SAviad Krawczyk /**
5567ef37fe4SAviad Krawczyk * cmdq_arm_ceq_handler - cmdq completion event handler for arm command
5577ef37fe4SAviad Krawczyk * @cmdq: the cmdq of the arm command
5587ef37fe4SAviad Krawczyk * @wqe: the wqe of the arm command
5597ef37fe4SAviad Krawczyk *
5607ef37fe4SAviad Krawczyk * Return 0 - Success, negative - Failure
5617ef37fe4SAviad Krawczyk **/
cmdq_arm_ceq_handler(struct hinic_cmdq * cmdq,struct hinic_cmdq_wqe * wqe)5627ef37fe4SAviad Krawczyk static int cmdq_arm_ceq_handler(struct hinic_cmdq *cmdq,
5637ef37fe4SAviad Krawczyk struct hinic_cmdq_wqe *wqe)
5647ef37fe4SAviad Krawczyk {
5657ef37fe4SAviad Krawczyk struct hinic_cmdq_direct_wqe *direct_wqe = &wqe->direct_wqe;
5667ef37fe4SAviad Krawczyk struct hinic_cmdq_wqe_scmd *wqe_scmd;
5677ef37fe4SAviad Krawczyk struct hinic_ctrl *ctrl;
5687ef37fe4SAviad Krawczyk u32 ctrl_info;
5697ef37fe4SAviad Krawczyk
5707ef37fe4SAviad Krawczyk wqe_scmd = &direct_wqe->wqe_scmd;
5717ef37fe4SAviad Krawczyk ctrl = &wqe_scmd->ctrl;
5727ef37fe4SAviad Krawczyk ctrl_info = be32_to_cpu(ctrl->ctrl_info);
5737ef37fe4SAviad Krawczyk
5747ef37fe4SAviad Krawczyk /* HW should toggle the HW BUSY BIT */
5757ef37fe4SAviad Krawczyk if (!CMDQ_WQE_COMPLETED(ctrl_info))
5767ef37fe4SAviad Krawczyk return -EBUSY;
5777ef37fe4SAviad Krawczyk
5787ef37fe4SAviad Krawczyk clear_wqe_complete_bit(cmdq, wqe);
5797ef37fe4SAviad Krawczyk
5807ef37fe4SAviad Krawczyk hinic_put_wqe(cmdq->wq, WQE_SCMD_SIZE);
5817ef37fe4SAviad Krawczyk return 0;
5827ef37fe4SAviad Krawczyk }
5837ef37fe4SAviad Krawczyk
cmdq_update_errcode(struct hinic_cmdq * cmdq,u16 prod_idx,int errcode)5847ef37fe4SAviad Krawczyk static void cmdq_update_errcode(struct hinic_cmdq *cmdq, u16 prod_idx,
5857ef37fe4SAviad Krawczyk int errcode)
5867ef37fe4SAviad Krawczyk {
5877ef37fe4SAviad Krawczyk if (cmdq->errcode[prod_idx])
5887ef37fe4SAviad Krawczyk *cmdq->errcode[prod_idx] = errcode;
5897ef37fe4SAviad Krawczyk }
5907ef37fe4SAviad Krawczyk
5917ef37fe4SAviad Krawczyk /**
592d6174870SYang Shen * cmdq_sync_cmd_handler - cmdq completion event handler for sync command
5937ef37fe4SAviad Krawczyk * @cmdq: the cmdq of the command
5947ef37fe4SAviad Krawczyk * @cons_idx: the consumer index to update the error code for
5957ef37fe4SAviad Krawczyk * @errcode: the error code
5967ef37fe4SAviad Krawczyk **/
cmdq_sync_cmd_handler(struct hinic_cmdq * cmdq,u16 cons_idx,int errcode)5977ef37fe4SAviad Krawczyk static void cmdq_sync_cmd_handler(struct hinic_cmdq *cmdq, u16 cons_idx,
5987ef37fe4SAviad Krawczyk int errcode)
5997ef37fe4SAviad Krawczyk {
6007ef37fe4SAviad Krawczyk u16 prod_idx = cons_idx;
6017ef37fe4SAviad Krawczyk
6027ef37fe4SAviad Krawczyk spin_lock(&cmdq->cmdq_lock);
6037ef37fe4SAviad Krawczyk cmdq_update_errcode(cmdq, prod_idx, errcode);
6047ef37fe4SAviad Krawczyk
6057ef37fe4SAviad Krawczyk wmb(); /* write all before update for the command request */
6067ef37fe4SAviad Krawczyk
6077ef37fe4SAviad Krawczyk if (cmdq->done[prod_idx])
6087ef37fe4SAviad Krawczyk complete(cmdq->done[prod_idx]);
6097ef37fe4SAviad Krawczyk spin_unlock(&cmdq->cmdq_lock);
6107ef37fe4SAviad Krawczyk }
6117ef37fe4SAviad Krawczyk
cmdq_cmd_ceq_handler(struct hinic_cmdq * cmdq,u16 ci,struct hinic_cmdq_wqe * cmdq_wqe)6127ef37fe4SAviad Krawczyk static int cmdq_cmd_ceq_handler(struct hinic_cmdq *cmdq, u16 ci,
6137ef37fe4SAviad Krawczyk struct hinic_cmdq_wqe *cmdq_wqe)
6147ef37fe4SAviad Krawczyk {
6157ef37fe4SAviad Krawczyk struct hinic_cmdq_wqe_lcmd *wqe_lcmd = &cmdq_wqe->wqe_lcmd;
6167ef37fe4SAviad Krawczyk struct hinic_status *status = &wqe_lcmd->status;
6177ef37fe4SAviad Krawczyk struct hinic_ctrl *ctrl = &wqe_lcmd->ctrl;
6187ef37fe4SAviad Krawczyk int errcode;
6197ef37fe4SAviad Krawczyk
6207ef37fe4SAviad Krawczyk if (!CMDQ_WQE_COMPLETED(be32_to_cpu(ctrl->ctrl_info)))
6217ef37fe4SAviad Krawczyk return -EBUSY;
6227ef37fe4SAviad Krawczyk
62333f15da2SLuo bin dma_rmb();
62433f15da2SLuo bin
6257ef37fe4SAviad Krawczyk errcode = CMDQ_WQE_ERRCODE_GET(be32_to_cpu(status->status_info), VAL);
6267ef37fe4SAviad Krawczyk
6277ef37fe4SAviad Krawczyk cmdq_sync_cmd_handler(cmdq, ci, errcode);
6287ef37fe4SAviad Krawczyk
6297ef37fe4SAviad Krawczyk clear_wqe_complete_bit(cmdq, cmdq_wqe);
6307ef37fe4SAviad Krawczyk hinic_put_wqe(cmdq->wq, WQE_LCMD_SIZE);
6317ef37fe4SAviad Krawczyk return 0;
6327ef37fe4SAviad Krawczyk }
6337ef37fe4SAviad Krawczyk
6347ef37fe4SAviad Krawczyk /**
635fc9319e4SAviad Krawczyk * cmdq_ceq_handler - cmdq completion event handler
636fc9319e4SAviad Krawczyk * @handle: private data for the handler(cmdqs)
637fc9319e4SAviad Krawczyk * @ceqe_data: ceq element data
638fc9319e4SAviad Krawczyk **/
cmdq_ceq_handler(void * handle,u32 ceqe_data)639fc9319e4SAviad Krawczyk static void cmdq_ceq_handler(void *handle, u32 ceqe_data)
640fc9319e4SAviad Krawczyk {
6417ef37fe4SAviad Krawczyk enum hinic_cmdq_type cmdq_type = CMDQ_CEQE_GET(ceqe_data, TYPE);
6427ef37fe4SAviad Krawczyk struct hinic_cmdqs *cmdqs = (struct hinic_cmdqs *)handle;
6437ef37fe4SAviad Krawczyk struct hinic_cmdq *cmdq = &cmdqs->cmdq[cmdq_type];
6447ef37fe4SAviad Krawczyk struct hinic_cmdq_header *header;
6457ef37fe4SAviad Krawczyk struct hinic_hw_wqe *hw_wqe;
6467ef37fe4SAviad Krawczyk int err, set_arm = 0;
6477ef37fe4SAviad Krawczyk u32 saved_data;
6487ef37fe4SAviad Krawczyk u16 ci;
6497ef37fe4SAviad Krawczyk
6507ef37fe4SAviad Krawczyk /* Read the smallest wqe size for getting wqe size */
6517ef37fe4SAviad Krawczyk while ((hw_wqe = hinic_read_wqe(cmdq->wq, WQE_SCMD_SIZE, &ci))) {
6527ef37fe4SAviad Krawczyk if (IS_ERR(hw_wqe))
6537ef37fe4SAviad Krawczyk break;
6547ef37fe4SAviad Krawczyk
6557ef37fe4SAviad Krawczyk header = CMDQ_WQE_HEADER(&hw_wqe->cmdq_wqe);
6567ef37fe4SAviad Krawczyk saved_data = be32_to_cpu(header->saved_data);
6577ef37fe4SAviad Krawczyk
6587ef37fe4SAviad Krawczyk if (HINIC_SAVED_DATA_GET(saved_data, ARM)) {
6597ef37fe4SAviad Krawczyk /* arm_bit was set until here */
6607ef37fe4SAviad Krawczyk set_arm = 0;
6617ef37fe4SAviad Krawczyk
6627ef37fe4SAviad Krawczyk if (cmdq_arm_ceq_handler(cmdq, &hw_wqe->cmdq_wqe))
6637ef37fe4SAviad Krawczyk break;
6647ef37fe4SAviad Krawczyk } else {
6657ef37fe4SAviad Krawczyk set_arm = 1;
6667ef37fe4SAviad Krawczyk
6677ef37fe4SAviad Krawczyk hw_wqe = hinic_read_wqe(cmdq->wq, WQE_LCMD_SIZE, &ci);
6687ef37fe4SAviad Krawczyk if (IS_ERR(hw_wqe))
6697ef37fe4SAviad Krawczyk break;
6707ef37fe4SAviad Krawczyk
6717ef37fe4SAviad Krawczyk if (cmdq_cmd_ceq_handler(cmdq, ci, &hw_wqe->cmdq_wqe))
6727ef37fe4SAviad Krawczyk break;
6737ef37fe4SAviad Krawczyk }
6747ef37fe4SAviad Krawczyk }
6757ef37fe4SAviad Krawczyk
6767ef37fe4SAviad Krawczyk if (set_arm) {
6777ef37fe4SAviad Krawczyk struct hinic_hwif *hwif = cmdqs->hwif;
6787ef37fe4SAviad Krawczyk struct pci_dev *pdev = hwif->pdev;
6797ef37fe4SAviad Krawczyk
6807ef37fe4SAviad Krawczyk err = hinic_set_arm_bit(cmdqs, HINIC_SET_ARM_CMDQ, cmdq_type);
6817ef37fe4SAviad Krawczyk if (err)
6827ef37fe4SAviad Krawczyk dev_err(&pdev->dev, "Failed to set arm for CMDQ\n");
6837ef37fe4SAviad Krawczyk }
684fc9319e4SAviad Krawczyk }
685fc9319e4SAviad Krawczyk
686fc9319e4SAviad Krawczyk /**
687d0b9805eSAviad Krawczyk * cmdq_init_queue_ctxt - init the queue ctxt of a cmdq
688d0b9805eSAviad Krawczyk * @cmdq_ctxt: cmdq ctxt to initialize
689d0b9805eSAviad Krawczyk * @cmdq: the cmdq
690d0b9805eSAviad Krawczyk * @cmdq_pages: the memory of the queue
691d0b9805eSAviad Krawczyk **/
cmdq_init_queue_ctxt(struct hinic_cmdq_ctxt * cmdq_ctxt,struct hinic_cmdq * cmdq,struct hinic_cmdq_pages * cmdq_pages)692d0b9805eSAviad Krawczyk static void cmdq_init_queue_ctxt(struct hinic_cmdq_ctxt *cmdq_ctxt,
693d0b9805eSAviad Krawczyk struct hinic_cmdq *cmdq,
694d0b9805eSAviad Krawczyk struct hinic_cmdq_pages *cmdq_pages)
695d0b9805eSAviad Krawczyk {
696d0b9805eSAviad Krawczyk struct hinic_cmdq_ctxt_info *ctxt_info = &cmdq_ctxt->ctxt_info;
697d0b9805eSAviad Krawczyk u64 wq_first_page_paddr, cmdq_first_block_paddr, pfn;
698d0b9805eSAviad Krawczyk struct hinic_cmdqs *cmdqs = cmdq_to_cmdqs(cmdq);
699d0b9805eSAviad Krawczyk struct hinic_wq *wq = cmdq->wq;
700d0b9805eSAviad Krawczyk
701d0b9805eSAviad Krawczyk /* The data in the HW is in Big Endian Format */
702d0b9805eSAviad Krawczyk wq_first_page_paddr = be64_to_cpu(*wq->block_vaddr);
703d0b9805eSAviad Krawczyk
7047dd29ee1SLuo bin pfn = CMDQ_PFN(wq_first_page_paddr, SZ_4K);
705d0b9805eSAviad Krawczyk
706d0b9805eSAviad Krawczyk ctxt_info->curr_wqe_page_pfn =
707d0b9805eSAviad Krawczyk HINIC_CMDQ_CTXT_PAGE_INFO_SET(pfn, CURR_WQE_PAGE_PFN) |
708d0b9805eSAviad Krawczyk HINIC_CMDQ_CTXT_PAGE_INFO_SET(HINIC_CEQ_ID_CMDQ, EQ_ID) |
709d0b9805eSAviad Krawczyk HINIC_CMDQ_CTXT_PAGE_INFO_SET(1, CEQ_ARM) |
710d0b9805eSAviad Krawczyk HINIC_CMDQ_CTXT_PAGE_INFO_SET(1, CEQ_EN) |
711d0b9805eSAviad Krawczyk HINIC_CMDQ_CTXT_PAGE_INFO_SET(cmdq->wrapped, WRAPPED);
712d0b9805eSAviad Krawczyk
7137dd29ee1SLuo bin if (wq->num_q_pages != 1) {
714d0b9805eSAviad Krawczyk /* block PFN - Read Modify Write */
715d0b9805eSAviad Krawczyk cmdq_first_block_paddr = cmdq_pages->page_paddr;
716d0b9805eSAviad Krawczyk
717d0b9805eSAviad Krawczyk pfn = CMDQ_PFN(cmdq_first_block_paddr, wq->wq_page_size);
7187dd29ee1SLuo bin }
719d0b9805eSAviad Krawczyk
720d0b9805eSAviad Krawczyk ctxt_info->wq_block_pfn =
721d0b9805eSAviad Krawczyk HINIC_CMDQ_CTXT_BLOCK_INFO_SET(pfn, WQ_BLOCK_PFN) |
722d0b9805eSAviad Krawczyk HINIC_CMDQ_CTXT_BLOCK_INFO_SET(atomic_read(&wq->cons_idx), CI);
723d0b9805eSAviad Krawczyk
724d0b9805eSAviad Krawczyk cmdq_ctxt->func_idx = HINIC_HWIF_FUNC_IDX(cmdqs->hwif);
7257dd29ee1SLuo bin cmdq_ctxt->ppf_idx = HINIC_HWIF_PPF_IDX(cmdqs->hwif);
726d0b9805eSAviad Krawczyk cmdq_ctxt->cmdq_type = cmdq->cmdq_type;
727d0b9805eSAviad Krawczyk }
728d0b9805eSAviad Krawczyk
729d0b9805eSAviad Krawczyk /**
730d0b9805eSAviad Krawczyk * init_cmdq - initialize cmdq
731d0b9805eSAviad Krawczyk * @cmdq: the cmdq
732d0b9805eSAviad Krawczyk * @wq: the wq attaced to the cmdq
733d0b9805eSAviad Krawczyk * @q_type: the cmdq type of the cmdq
734d0b9805eSAviad Krawczyk * @db_area: doorbell area for the cmdq
735d0b9805eSAviad Krawczyk *
736d0b9805eSAviad Krawczyk * Return 0 - Success, negative - Failure
737d0b9805eSAviad Krawczyk **/
init_cmdq(struct hinic_cmdq * cmdq,struct hinic_wq * wq,enum hinic_cmdq_type q_type,void __iomem * db_area)738d0b9805eSAviad Krawczyk static int init_cmdq(struct hinic_cmdq *cmdq, struct hinic_wq *wq,
739d0b9805eSAviad Krawczyk enum hinic_cmdq_type q_type, void __iomem *db_area)
740d0b9805eSAviad Krawczyk {
741d0b9805eSAviad Krawczyk int err;
742d0b9805eSAviad Krawczyk
743d0b9805eSAviad Krawczyk cmdq->wq = wq;
744d0b9805eSAviad Krawczyk cmdq->cmdq_type = q_type;
745d0b9805eSAviad Krawczyk cmdq->wrapped = 1;
746d0b9805eSAviad Krawczyk
747d0b9805eSAviad Krawczyk spin_lock_init(&cmdq->cmdq_lock);
748d0b9805eSAviad Krawczyk
749fad953ceSKees Cook cmdq->done = vzalloc(array_size(sizeof(*cmdq->done), wq->q_depth));
750d0b9805eSAviad Krawczyk if (!cmdq->done)
751d0b9805eSAviad Krawczyk return -ENOMEM;
752d0b9805eSAviad Krawczyk
753fad953ceSKees Cook cmdq->errcode = vzalloc(array_size(sizeof(*cmdq->errcode),
754fad953ceSKees Cook wq->q_depth));
755d0b9805eSAviad Krawczyk if (!cmdq->errcode) {
756d0b9805eSAviad Krawczyk err = -ENOMEM;
757d0b9805eSAviad Krawczyk goto err_errcode;
758d0b9805eSAviad Krawczyk }
759d0b9805eSAviad Krawczyk
760d0b9805eSAviad Krawczyk cmdq->db_base = db_area + CMDQ_DB_OFF;
761d0b9805eSAviad Krawczyk return 0;
762d0b9805eSAviad Krawczyk
763d0b9805eSAviad Krawczyk err_errcode:
764d0b9805eSAviad Krawczyk vfree(cmdq->done);
765d0b9805eSAviad Krawczyk return err;
766d0b9805eSAviad Krawczyk }
767d0b9805eSAviad Krawczyk
768d0b9805eSAviad Krawczyk /**
769d0b9805eSAviad Krawczyk * free_cmdq - Free cmdq
770d0b9805eSAviad Krawczyk * @cmdq: the cmdq to free
771d0b9805eSAviad Krawczyk **/
free_cmdq(struct hinic_cmdq * cmdq)772d0b9805eSAviad Krawczyk static void free_cmdq(struct hinic_cmdq *cmdq)
773d0b9805eSAviad Krawczyk {
774d0b9805eSAviad Krawczyk vfree(cmdq->errcode);
775d0b9805eSAviad Krawczyk vfree(cmdq->done);
776d0b9805eSAviad Krawczyk }
777d0b9805eSAviad Krawczyk
778d0b9805eSAviad Krawczyk /**
779d0b9805eSAviad Krawczyk * init_cmdqs_ctxt - write the cmdq ctxt to HW after init all cmdq
780d0b9805eSAviad Krawczyk * @hwdev: the NIC HW device
781d0b9805eSAviad Krawczyk * @cmdqs: cmdqs to write the ctxts for
782b1b6c110SLuo bin * @db_area: db_area for all the cmdqs
783d0b9805eSAviad Krawczyk *
784d0b9805eSAviad Krawczyk * Return 0 - Success, negative - Failure
785d0b9805eSAviad Krawczyk **/
init_cmdqs_ctxt(struct hinic_hwdev * hwdev,struct hinic_cmdqs * cmdqs,void __iomem ** db_area)786d0b9805eSAviad Krawczyk static int init_cmdqs_ctxt(struct hinic_hwdev *hwdev,
787d0b9805eSAviad Krawczyk struct hinic_cmdqs *cmdqs, void __iomem **db_area)
788d0b9805eSAviad Krawczyk {
789d0b9805eSAviad Krawczyk struct hinic_hwif *hwif = hwdev->hwif;
790d0b9805eSAviad Krawczyk enum hinic_cmdq_type type, cmdq_type;
791d0b9805eSAviad Krawczyk struct hinic_cmdq_ctxt *cmdq_ctxts;
792d0b9805eSAviad Krawczyk struct pci_dev *pdev = hwif->pdev;
793d0b9805eSAviad Krawczyk struct hinic_pfhwdev *pfhwdev;
794d0b9805eSAviad Krawczyk int err;
795d0b9805eSAviad Krawczyk
7969d922f5dSGustavo A. R. Silva cmdq_ctxts = devm_kcalloc(&pdev->dev, HINIC_MAX_CMDQ_TYPES,
7979d922f5dSGustavo A. R. Silva sizeof(*cmdq_ctxts), GFP_KERNEL);
798d0b9805eSAviad Krawczyk if (!cmdq_ctxts)
799d0b9805eSAviad Krawczyk return -ENOMEM;
800d0b9805eSAviad Krawczyk
801d0b9805eSAviad Krawczyk pfhwdev = container_of(hwdev, struct hinic_pfhwdev, hwdev);
802d0b9805eSAviad Krawczyk
803d0b9805eSAviad Krawczyk cmdq_type = HINIC_CMDQ_SYNC;
804d0b9805eSAviad Krawczyk for (; cmdq_type < HINIC_MAX_CMDQ_TYPES; cmdq_type++) {
80590f86b8aSLuo bin cmdqs->cmdq[cmdq_type].hwdev = hwdev;
806d0b9805eSAviad Krawczyk err = init_cmdq(&cmdqs->cmdq[cmdq_type],
807d0b9805eSAviad Krawczyk &cmdqs->saved_wqs[cmdq_type], cmdq_type,
808d0b9805eSAviad Krawczyk db_area[cmdq_type]);
809d0b9805eSAviad Krawczyk if (err) {
810d0b9805eSAviad Krawczyk dev_err(&pdev->dev, "Failed to initialize cmdq\n");
811d0b9805eSAviad Krawczyk goto err_init_cmdq;
812d0b9805eSAviad Krawczyk }
813d0b9805eSAviad Krawczyk
814d0b9805eSAviad Krawczyk cmdq_init_queue_ctxt(&cmdq_ctxts[cmdq_type],
815d0b9805eSAviad Krawczyk &cmdqs->cmdq[cmdq_type],
816d0b9805eSAviad Krawczyk &cmdqs->cmdq_pages);
817d0b9805eSAviad Krawczyk }
818d0b9805eSAviad Krawczyk
819d0b9805eSAviad Krawczyk /* Write the CMDQ ctxts */
820d0b9805eSAviad Krawczyk cmdq_type = HINIC_CMDQ_SYNC;
821d0b9805eSAviad Krawczyk for (; cmdq_type < HINIC_MAX_CMDQ_TYPES; cmdq_type++) {
822d0b9805eSAviad Krawczyk err = hinic_msg_to_mgmt(&pfhwdev->pf_to_mgmt, HINIC_MOD_COMM,
823d0b9805eSAviad Krawczyk HINIC_COMM_CMD_CMDQ_CTXT_SET,
824d0b9805eSAviad Krawczyk &cmdq_ctxts[cmdq_type],
825d0b9805eSAviad Krawczyk sizeof(cmdq_ctxts[cmdq_type]),
826d0b9805eSAviad Krawczyk NULL, NULL, HINIC_MGMT_MSG_SYNC);
827d0b9805eSAviad Krawczyk if (err) {
828d0b9805eSAviad Krawczyk dev_err(&pdev->dev, "Failed to set CMDQ CTXT type = %d\n",
829d0b9805eSAviad Krawczyk cmdq_type);
830d0b9805eSAviad Krawczyk goto err_write_cmdq_ctxt;
831d0b9805eSAviad Krawczyk }
832d0b9805eSAviad Krawczyk }
833d0b9805eSAviad Krawczyk
834d0b9805eSAviad Krawczyk devm_kfree(&pdev->dev, cmdq_ctxts);
835d0b9805eSAviad Krawczyk return 0;
836d0b9805eSAviad Krawczyk
837d0b9805eSAviad Krawczyk err_write_cmdq_ctxt:
838d0b9805eSAviad Krawczyk cmdq_type = HINIC_MAX_CMDQ_TYPES;
839d0b9805eSAviad Krawczyk
840d0b9805eSAviad Krawczyk err_init_cmdq:
841d0b9805eSAviad Krawczyk for (type = HINIC_CMDQ_SYNC; type < cmdq_type; type++)
842d0b9805eSAviad Krawczyk free_cmdq(&cmdqs->cmdq[type]);
843d0b9805eSAviad Krawczyk
844d0b9805eSAviad Krawczyk devm_kfree(&pdev->dev, cmdq_ctxts);
845d0b9805eSAviad Krawczyk return err;
846d0b9805eSAviad Krawczyk }
847d0b9805eSAviad Krawczyk
hinic_set_cmdq_depth(struct hinic_hwdev * hwdev,u16 cmdq_depth)84872ef908bSLuo bin static int hinic_set_cmdq_depth(struct hinic_hwdev *hwdev, u16 cmdq_depth)
84972ef908bSLuo bin {
85072ef908bSLuo bin struct hinic_cmd_hw_ioctxt hw_ioctxt = { 0 };
85172ef908bSLuo bin struct hinic_pfhwdev *pfhwdev;
85272ef908bSLuo bin
85372ef908bSLuo bin pfhwdev = container_of(hwdev, struct hinic_pfhwdev, hwdev);
85472ef908bSLuo bin
85572ef908bSLuo bin hw_ioctxt.func_idx = HINIC_HWIF_FUNC_IDX(hwdev->hwif);
85672ef908bSLuo bin hw_ioctxt.ppf_idx = HINIC_HWIF_PPF_IDX(hwdev->hwif);
85772ef908bSLuo bin
85872ef908bSLuo bin hw_ioctxt.set_cmdq_depth = HW_IOCTXT_SET_CMDQ_DEPTH_ENABLE;
85972ef908bSLuo bin hw_ioctxt.cmdq_depth = (u8)ilog2(cmdq_depth);
86072ef908bSLuo bin
86172ef908bSLuo bin return hinic_msg_to_mgmt(&pfhwdev->pf_to_mgmt, HINIC_MOD_COMM,
86272ef908bSLuo bin HINIC_COMM_CMD_HWCTXT_SET,
86372ef908bSLuo bin &hw_ioctxt, sizeof(hw_ioctxt), NULL,
86472ef908bSLuo bin NULL, HINIC_MGMT_MSG_SYNC);
86572ef908bSLuo bin }
86672ef908bSLuo bin
867d0b9805eSAviad Krawczyk /**
86853e7d6feSAviad Krawczyk * hinic_init_cmdqs - init all cmdqs
86953e7d6feSAviad Krawczyk * @cmdqs: cmdqs to init
87053e7d6feSAviad Krawczyk * @hwif: HW interface for accessing cmdqs
87153e7d6feSAviad Krawczyk * @db_area: doorbell areas for all the cmdqs
87253e7d6feSAviad Krawczyk *
87353e7d6feSAviad Krawczyk * Return 0 - Success, negative - Failure
87453e7d6feSAviad Krawczyk **/
hinic_init_cmdqs(struct hinic_cmdqs * cmdqs,struct hinic_hwif * hwif,void __iomem ** db_area)87553e7d6feSAviad Krawczyk int hinic_init_cmdqs(struct hinic_cmdqs *cmdqs, struct hinic_hwif *hwif,
87653e7d6feSAviad Krawczyk void __iomem **db_area)
87753e7d6feSAviad Krawczyk {
878d0b9805eSAviad Krawczyk struct hinic_func_to_io *func_to_io = cmdqs_to_func_to_io(cmdqs);
879d0b9805eSAviad Krawczyk struct pci_dev *pdev = hwif->pdev;
880d0b9805eSAviad Krawczyk struct hinic_hwdev *hwdev;
881d0b9805eSAviad Krawczyk u16 max_wqe_size;
882d0b9805eSAviad Krawczyk int err;
883d0b9805eSAviad Krawczyk
884d0b9805eSAviad Krawczyk cmdqs->hwif = hwif;
8853203e1d9SRomain Perier cmdqs->cmdq_buf_pool = dma_pool_create("hinic_cmdq", &pdev->dev,
886d0b9805eSAviad Krawczyk HINIC_CMDQ_BUF_SIZE,
887d0b9805eSAviad Krawczyk HINIC_CMDQ_BUF_SIZE, 0);
888d0b9805eSAviad Krawczyk if (!cmdqs->cmdq_buf_pool)
889d0b9805eSAviad Krawczyk return -ENOMEM;
890d0b9805eSAviad Krawczyk
8919d922f5dSGustavo A. R. Silva cmdqs->saved_wqs = devm_kcalloc(&pdev->dev, HINIC_MAX_CMDQ_TYPES,
8929d922f5dSGustavo A. R. Silva sizeof(*cmdqs->saved_wqs), GFP_KERNEL);
893d0b9805eSAviad Krawczyk if (!cmdqs->saved_wqs) {
894d0b9805eSAviad Krawczyk err = -ENOMEM;
895d0b9805eSAviad Krawczyk goto err_saved_wqs;
896d0b9805eSAviad Krawczyk }
897d0b9805eSAviad Krawczyk
898d0b9805eSAviad Krawczyk max_wqe_size = WQE_LCMD_SIZE;
899d0b9805eSAviad Krawczyk err = hinic_wqs_cmdq_alloc(&cmdqs->cmdq_pages, cmdqs->saved_wqs, hwif,
900d0b9805eSAviad Krawczyk HINIC_MAX_CMDQ_TYPES, CMDQ_WQEBB_SIZE,
901d0b9805eSAviad Krawczyk CMDQ_WQ_PAGE_SIZE, CMDQ_DEPTH, max_wqe_size);
902d0b9805eSAviad Krawczyk if (err) {
903d0b9805eSAviad Krawczyk dev_err(&pdev->dev, "Failed to allocate CMDQ wqs\n");
904d0b9805eSAviad Krawczyk goto err_cmdq_wqs;
905d0b9805eSAviad Krawczyk }
906d0b9805eSAviad Krawczyk
907d0b9805eSAviad Krawczyk hwdev = container_of(func_to_io, struct hinic_hwdev, func_to_io);
908d0b9805eSAviad Krawczyk err = init_cmdqs_ctxt(hwdev, cmdqs, db_area);
909d0b9805eSAviad Krawczyk if (err) {
910d0b9805eSAviad Krawczyk dev_err(&pdev->dev, "Failed to write cmdq ctxt\n");
911d0b9805eSAviad Krawczyk goto err_cmdq_ctxt;
912d0b9805eSAviad Krawczyk }
913d0b9805eSAviad Krawczyk
914fc9319e4SAviad Krawczyk hinic_ceq_register_cb(&func_to_io->ceqs, HINIC_CEQ_CMDQ, cmdqs,
915fc9319e4SAviad Krawczyk cmdq_ceq_handler);
91672ef908bSLuo bin
91772ef908bSLuo bin err = hinic_set_cmdq_depth(hwdev, CMDQ_DEPTH);
91872ef908bSLuo bin if (err) {
91972ef908bSLuo bin dev_err(&hwif->pdev->dev, "Failed to set cmdq depth\n");
92072ef908bSLuo bin goto err_set_cmdq_depth;
92172ef908bSLuo bin }
92272ef908bSLuo bin
923d0b9805eSAviad Krawczyk return 0;
924d0b9805eSAviad Krawczyk
92572ef908bSLuo bin err_set_cmdq_depth:
92672ef908bSLuo bin hinic_ceq_unregister_cb(&func_to_io->ceqs, HINIC_CEQ_CMDQ);
927*363cc877SZhengchao Shao free_cmdq(&cmdqs->cmdq[HINIC_CMDQ_SYNC]);
928d0b9805eSAviad Krawczyk err_cmdq_ctxt:
929d0b9805eSAviad Krawczyk hinic_wqs_cmdq_free(&cmdqs->cmdq_pages, cmdqs->saved_wqs,
930d0b9805eSAviad Krawczyk HINIC_MAX_CMDQ_TYPES);
931d0b9805eSAviad Krawczyk
932d0b9805eSAviad Krawczyk err_cmdq_wqs:
933d0b9805eSAviad Krawczyk devm_kfree(&pdev->dev, cmdqs->saved_wqs);
934d0b9805eSAviad Krawczyk
935d0b9805eSAviad Krawczyk err_saved_wqs:
9363203e1d9SRomain Perier dma_pool_destroy(cmdqs->cmdq_buf_pool);
937d0b9805eSAviad Krawczyk return err;
93853e7d6feSAviad Krawczyk }
93953e7d6feSAviad Krawczyk
94053e7d6feSAviad Krawczyk /**
94153e7d6feSAviad Krawczyk * hinic_free_cmdqs - free all cmdqs
94253e7d6feSAviad Krawczyk * @cmdqs: cmdqs to free
94353e7d6feSAviad Krawczyk **/
hinic_free_cmdqs(struct hinic_cmdqs * cmdqs)94453e7d6feSAviad Krawczyk void hinic_free_cmdqs(struct hinic_cmdqs *cmdqs)
94553e7d6feSAviad Krawczyk {
946fc9319e4SAviad Krawczyk struct hinic_func_to_io *func_to_io = cmdqs_to_func_to_io(cmdqs);
947d0b9805eSAviad Krawczyk struct hinic_hwif *hwif = cmdqs->hwif;
948d0b9805eSAviad Krawczyk struct pci_dev *pdev = hwif->pdev;
949d0b9805eSAviad Krawczyk enum hinic_cmdq_type cmdq_type;
950d0b9805eSAviad Krawczyk
951fc9319e4SAviad Krawczyk hinic_ceq_unregister_cb(&func_to_io->ceqs, HINIC_CEQ_CMDQ);
952fc9319e4SAviad Krawczyk
953d0b9805eSAviad Krawczyk cmdq_type = HINIC_CMDQ_SYNC;
954d0b9805eSAviad Krawczyk for (; cmdq_type < HINIC_MAX_CMDQ_TYPES; cmdq_type++)
955d0b9805eSAviad Krawczyk free_cmdq(&cmdqs->cmdq[cmdq_type]);
956d0b9805eSAviad Krawczyk
957d0b9805eSAviad Krawczyk hinic_wqs_cmdq_free(&cmdqs->cmdq_pages, cmdqs->saved_wqs,
958d0b9805eSAviad Krawczyk HINIC_MAX_CMDQ_TYPES);
959d0b9805eSAviad Krawczyk
960d0b9805eSAviad Krawczyk devm_kfree(&pdev->dev, cmdqs->saved_wqs);
961d0b9805eSAviad Krawczyk
9623203e1d9SRomain Perier dma_pool_destroy(cmdqs->cmdq_buf_pool);
96353e7d6feSAviad Krawczyk }
964