xref: /linux/drivers/net/ethernet/huawei/hinic/hinic_hw_cmdq.c (revision 7ae9fb1b7ecbb5d85d07857943f677fd1a559b18)
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