lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <7c2ab3be-3b7b-49a5-82d2-99c8001ef635@linux.dev>
Date: Sat, 28 Jun 2025 14:03:57 +0100
From: Vadim Fedorenko <vadim.fedorenko@...ux.dev>
To: Fan Gong <gongfan1@...wei.com>, Zhu Yikai <zhuyikai1@...artners.com>
Cc: netdev@...r.kernel.org, linux-kernel@...r.kernel.org,
 "David S. Miller" <davem@...emloft.net>, Eric Dumazet <edumazet@...gle.com>,
 Jakub Kicinski <kuba@...nel.org>, Paolo Abeni <pabeni@...hat.com>,
 Simon Horman <horms@...nel.org>, Andrew Lunn <andrew+netdev@...n.ch>,
 linux-doc@...r.kernel.org, Jonathan Corbet <corbet@....net>,
 Bjorn Helgaas <helgaas@...nel.org>, luosifu <luosifu@...wei.com>,
 Xin Guo <guoxin09@...wei.com>, Shen Chenyang <shenchenyang1@...ilicon.com>,
 Zhou Shuai <zhoushuai28@...wei.com>, Wu Like <wulike1@...wei.com>,
 Shi Jing <shijing34@...wei.com>, Meny Yossefi <meny.yossefi@...wei.com>,
 Gur Stavi <gur.stavi@...wei.com>, Lee Trager <lee@...ger.us>,
 Michael Ellerman <mpe@...erman.id.au>, Suman Ghosh <sumang@...vell.com>,
 Przemek Kitszel <przemyslaw.kitszel@...el.com>,
 Joe Damato <jdamato@...tly.com>,
 Christophe JAILLET <christophe.jaillet@...adoo.fr>
Subject: Re: [PATCH net-next v06 6/8] hinic3: Mailbox framework

On 27/06/2025 07:12, Fan Gong wrote:
> Add mailbox framework initialization.
> It allows driver to send commands to HW.
> 
> Co-developed-by: Xin Guo <guoxin09@...wei.com>
> Signed-off-by: Xin Guo <guoxin09@...wei.com>
> Co-developed-by: Zhu Yikai <zhuyikai1@...artners.com>
> Signed-off-by: Zhu Yikai <zhuyikai1@...artners.com>
> Signed-off-by: Fan Gong <gongfan1@...wei.com>
> ---
>   .../ethernet/huawei/hinic3/hinic3_common.c    |  14 +
>   .../ethernet/huawei/hinic3/hinic3_common.h    |   9 +
>   .../net/ethernet/huawei/hinic3/hinic3_eqs.c   |   9 +-
>   .../net/ethernet/huawei/hinic3/hinic3_mbox.c  | 403 ++++++++++++++++++
>   .../net/ethernet/huawei/hinic3/hinic3_mbox.h  | 105 +++++
>   5 files changed, 537 insertions(+), 3 deletions(-)
> 
> diff --git a/drivers/net/ethernet/huawei/hinic3/hinic3_common.c b/drivers/net/ethernet/huawei/hinic3/hinic3_common.c
> index d3a69d67b4c1..016da1911072 100644
> --- a/drivers/net/ethernet/huawei/hinic3/hinic3_common.c
> +++ b/drivers/net/ethernet/huawei/hinic3/hinic3_common.c
> @@ -3,6 +3,7 @@
>   
>   #include <linux/delay.h>
>   #include <linux/dma-mapping.h>
> +#include <linux/iopoll.h>
>   
>   #include "hinic3_common.h"
>   
> @@ -52,6 +53,19 @@ void hinic3_dma_free_coherent_align(struct device *dev,
>   			  mem_align->ori_vaddr, mem_align->ori_paddr);
>   }
>   
> +int hinic3_wait_for_timeout(void *priv_data, wait_cpl_handler handler,
> +			    u32 wait_total_ms, u32 wait_once_us)
> +{
> +	enum hinic3_wait_return ret;
> +	int err;
> +
> +	err = read_poll_timeout(handler, ret, ret == HINIC3_WAIT_PROCESS_CPL,
> +				wait_once_us, wait_total_ms * USEC_PER_MSEC,
> +				false, priv_data);
> +
> +	return err;
> +}
> +
>   /* Data provided to/by cmdq is arranged in structs with little endian fields but
>    * every dword (32bits) should be swapped since HW swaps it again when it
>    * copies it from/to host memory. This is a mandatory swap regardless of the
> diff --git a/drivers/net/ethernet/huawei/hinic3/hinic3_common.h b/drivers/net/ethernet/huawei/hinic3/hinic3_common.h
> index 52d6cb2515c8..50d1fd038b48 100644
> --- a/drivers/net/ethernet/huawei/hinic3/hinic3_common.h
> +++ b/drivers/net/ethernet/huawei/hinic3/hinic3_common.h
> @@ -18,6 +18,11 @@ struct hinic3_dma_addr_align {
>   	dma_addr_t align_paddr;
>   };
>   
> +enum hinic3_wait_return {
> +	HINIC3_WAIT_PROCESS_CPL     = 0,
> +	HINIC3_WAIT_PROCESS_WAITING = 1,
> +};
> +
>   struct hinic3_sge {
>   	u32 hi_addr;
>   	u32 lo_addr;
> @@ -40,6 +45,10 @@ int hinic3_dma_zalloc_coherent_align(struct device *dev, u32 size, u32 align,
>   void hinic3_dma_free_coherent_align(struct device *dev,
>   				    struct hinic3_dma_addr_align *mem_align);
>   
> +typedef enum hinic3_wait_return (*wait_cpl_handler)(void *priv_data);
> +int hinic3_wait_for_timeout(void *priv_data, wait_cpl_handler handler,
> +			    u32 wait_total_ms, u32 wait_once_us);
> +
>   void hinic3_cmdq_buf_swab32(void *data, int len);
>   
>   #endif
> diff --git a/drivers/net/ethernet/huawei/hinic3/hinic3_eqs.c b/drivers/net/ethernet/huawei/hinic3/hinic3_eqs.c
> index 0d1f1b406064..fec82ce42939 100644
> --- a/drivers/net/ethernet/huawei/hinic3/hinic3_eqs.c
> +++ b/drivers/net/ethernet/huawei/hinic3/hinic3_eqs.c
> @@ -361,10 +361,13 @@ static void ceq_tasklet(ulong ceq_data)
>   
>   static irqreturn_t aeq_interrupt(int irq, void *data)
>   {
> -	struct hinic3_eq *aeq = data;
> -	struct hinic3_aeqs *aeqs = aeq_to_aeqs(aeq);
> -	struct hinic3_hwdev *hwdev = aeq->hwdev;
>   	struct workqueue_struct *workq;
> +	struct hinic3_eq *aeq = data;
> +	struct hinic3_hwdev *hwdev;
> +	struct hinic3_aeqs *aeqs;
> +
> +	aeqs = aeq_to_aeqs(aeq);
> +	hwdev = aeq->hwdev;
>   
>   	/* clear resend timer cnt register */
>   	workq = aeqs->workq;
> diff --git a/drivers/net/ethernet/huawei/hinic3/hinic3_mbox.c b/drivers/net/ethernet/huawei/hinic3/hinic3_mbox.c
> index e74d1eb09730..2967bc29408f 100644
> --- a/drivers/net/ethernet/huawei/hinic3/hinic3_mbox.c
> +++ b/drivers/net/ethernet/huawei/hinic3/hinic3_mbox.c
> @@ -4,10 +4,413 @@
>   #include <linux/dma-mapping.h>
>   
>   #include "hinic3_common.h"
> +#include "hinic3_csr.h"
>   #include "hinic3_hwdev.h"
>   #include "hinic3_hwif.h"
>   #include "hinic3_mbox.h"
>   
> +#define MBOX_MSG_POLLING_TIMEOUT_MS  8000 // send msg seg timeout
> +#define MBOX_COMP_POLLING_TIMEOUT_MS 40000 // response
> +
> +#define MBOX_MAX_BUF_SZ           2048
> +#define MBOX_HEADER_SZ            8
> +
> +/* MBOX size is 64B, 8B for mbox_header, 8B reserved */
> +#define MBOX_SEG_LEN              48
> +#define MBOX_SEG_LEN_ALIGN        4
> +#define MBOX_WB_STATUS_LEN        16
> +
> +#define MBOX_SEQ_ID_START_VAL     0
> +#define MBOX_SEQ_ID_MAX_VAL       42
> +#define MBOX_LAST_SEG_MAX_LEN  \
> +	(MBOX_MAX_BUF_SZ - MBOX_SEQ_ID_MAX_VAL * MBOX_SEG_LEN)
> +
> +#define MBOX_DMA_MSG_QUEUE_DEPTH    32
> +#define MBOX_BODY_FROM_HDR(header)  ((u8 *)(header) + MBOX_HEADER_SZ)
> +#define MBOX_AREA(hwif)  \
> +	((hwif)->cfg_regs_base + HINIC3_FUNC_CSR_MAILBOX_DATA_OFF)
> +
> +#define MBOX_MQ_CI_OFFSET  \
> +	(HINIC3_CFG_REGS_FLAG + HINIC3_FUNC_CSR_MAILBOX_DATA_OFF + \
> +	 MBOX_HEADER_SZ + MBOX_SEG_LEN)
> +
> +#define MBOX_MQ_SYNC_CI_MASK   GENMASK(7, 0)
> +#define MBOX_MQ_ASYNC_CI_MASK  GENMASK(15, 8)
> +#define MBOX_MQ_CI_GET(val, field)  \
> +	FIELD_GET(MBOX_MQ_##field##_CI_MASK, val)
> +
> +#define MBOX_MGMT_FUNC_ID         0x1FFF
> +#define MBOX_COMM_F_MBOX_SEGMENT  BIT(3)
> +
> +static struct hinic3_msg_desc *get_mbox_msg_desc(struct hinic3_mbox *mbox,
> +						 enum mbox_msg_direction_type dir,
> +						 u16 src_func_id)
> +{
> +	struct hinic3_msg_channel *msg_ch;
> +
> +	msg_ch = (src_func_id == MBOX_MGMT_FUNC_ID) ?
> +		&mbox->mgmt_msg : mbox->func_msg;
> +
> +	return (dir == MBOX_MSG_SEND) ?
> +		&msg_ch->recv_msg : &msg_ch->resp_msg;
> +}
> +
> +static void resp_mbox_handler(struct hinic3_mbox *mbox,
> +			      const struct hinic3_msg_desc *msg_desc)
> +{
> +	spin_lock(&mbox->mbox_lock);
> +	if (msg_desc->msg_info.msg_id == mbox->send_msg_id &&
> +	    mbox->event_flag == MBOX_EVENT_START)
> +		mbox->event_flag = MBOX_EVENT_SUCCESS;
> +	spin_unlock(&mbox->mbox_lock);
> +}
> +
> +static bool mbox_segment_valid(struct hinic3_mbox *mbox,
> +			       struct hinic3_msg_desc *msg_desc,
> +			       u64 mbox_header)
> +{
> +	u8 seq_id, seg_len, msg_id, mod;
> +	u16 src_func_idx, cmd;
> +
> +	seq_id = MBOX_MSG_HEADER_GET(mbox_header, SEQID);
> +	seg_len = MBOX_MSG_HEADER_GET(mbox_header, SEG_LEN);
> +	msg_id = MBOX_MSG_HEADER_GET(mbox_header, MSG_ID);
> +	mod = MBOX_MSG_HEADER_GET(mbox_header, MODULE);
> +	cmd = MBOX_MSG_HEADER_GET(mbox_header, CMD);
> +	src_func_idx = MBOX_MSG_HEADER_GET(mbox_header, SRC_GLB_FUNC_IDX);
> +
> +	if (seq_id > MBOX_SEQ_ID_MAX_VAL || seg_len > MBOX_SEG_LEN ||
> +	    (seq_id == MBOX_SEQ_ID_MAX_VAL && seg_len > MBOX_LAST_SEG_MAX_LEN))
> +		goto err_seg;
> +
> +	if (seq_id == 0) {
> +		msg_desc->seq_id = seq_id;
> +		msg_desc->msg_info.msg_id = msg_id;
> +		msg_desc->mod = mod;
> +		msg_desc->cmd = cmd;
> +	} else {
> +		if (seq_id != msg_desc->seq_id + 1 ||
> +		    msg_id != msg_desc->msg_info.msg_id ||
> +		    mod != msg_desc->mod || cmd != msg_desc->cmd)
> +			goto err_seg;
> +
> +		msg_desc->seq_id = seq_id;
> +	}
> +
> +	return true;
> +
> +err_seg:
> +	dev_err(mbox->hwdev->dev,
> +		"Mailbox segment check failed, src func id: 0x%x, front seg info: seq id: 0x%x, msg id: 0x%x, mod: 0x%x, cmd: 0x%x\n",
> +		src_func_idx, msg_desc->seq_id, msg_desc->msg_info.msg_id,
> +		msg_desc->mod, msg_desc->cmd);
> +	dev_err(mbox->hwdev->dev,
> +		"Current seg info: seg len: 0x%x, seq id: 0x%x, msg id: 0x%x, mod: 0x%x, cmd: 0x%x\n",
> +		seg_len, seq_id, msg_id, mod, cmd);
> +
> +	return false;
> +}
> +
> +static void recv_mbox_handler(struct hinic3_mbox *mbox,
> +			      u64 *header, struct hinic3_msg_desc *msg_desc)
> +{
> +	void *mbox_body = MBOX_BODY_FROM_HDR(((void *)header));
> +	u64 mbox_header = *header;
> +	u8 seq_id, seg_len;
> +	int pos;
> +
> +	if (!mbox_segment_valid(mbox, msg_desc, mbox_header)) {
> +		msg_desc->seq_id = MBOX_SEQ_ID_MAX_VAL;
> +		return;
> +	}
> +
> +	seq_id = MBOX_MSG_HEADER_GET(mbox_header, SEQID);
> +	seg_len = MBOX_MSG_HEADER_GET(mbox_header, SEG_LEN);
> +
> +	pos = seq_id * MBOX_SEG_LEN;
> +	memcpy((u8 *)msg_desc->msg + pos, mbox_body, seg_len);
> +
> +	if (!MBOX_MSG_HEADER_GET(mbox_header, LAST))
> +		return;
> +
> +	msg_desc->msg_len = MBOX_MSG_HEADER_GET(mbox_header, MSG_LEN);
> +	msg_desc->msg_info.status = MBOX_MSG_HEADER_GET(mbox_header, STATUS);
> +
> +	if (MBOX_MSG_HEADER_GET(mbox_header, DIRECTION) == MBOX_MSG_RESP)
> +		resp_mbox_handler(mbox, msg_desc);
> +}
> +
> +void hinic3_mbox_func_aeqe_handler(struct hinic3_hwdev *hwdev, u8 *header,
> +				   u8 size)
> +{
> +	u64 mbox_header = *((u64 *)header);

The question here is how will it work with different endianess? AFAIU,
u8 *header is a buffer filled in by FW with device's endianess, which
you directly  convert into host's endianess into u64 value. If the 
endianess doesn't match, this conversion will fail.

> +	enum mbox_msg_direction_type dir;
> +	struct hinic3_msg_desc *msg_desc;
> +	struct hinic3_mbox *mbox;
> +	u16 src_func_id;
> +
> +	mbox = hwdev->mbox;
> +	dir = MBOX_MSG_HEADER_GET(mbox_header, DIRECTION);
> +	src_func_id = MBOX_MSG_HEADER_GET(mbox_header, SRC_GLB_FUNC_IDX);
> +	msg_desc = get_mbox_msg_desc(mbox, dir, src_func_id);
> +	recv_mbox_handler(mbox, (u64 *)header, msg_desc);
> +}

I cannot find any code which calls hinic3_mbox_func_aeqe_handler(),
neither in this patch, nor further in the patchset. What is the reason
to have it in this series?

> +
> +static int init_mbox_dma_queue(struct hinic3_hwdev *hwdev,
> +			       struct mbox_dma_queue *mq)
> +{
> +	u32 size;
> +
> +	mq->depth = MBOX_DMA_MSG_QUEUE_DEPTH;
> +	mq->prod_idx = 0;
> +	mq->cons_idx = 0;
> +
> +	size = mq->depth * MBOX_MAX_BUF_SZ;
> +	mq->dma_buf_vaddr = dma_alloc_coherent(hwdev->dev, size,
> +					       &mq->dma_buf_paddr,
> +					       GFP_KERNEL);
> +	if (!mq->dma_buf_vaddr)
> +		return -ENOMEM;
> +
> +	return 0;
> +}
> +
> +static void uninit_mbox_dma_queue(struct hinic3_hwdev *hwdev,
> +				  struct mbox_dma_queue *mq)
> +{
> +	dma_free_coherent(hwdev->dev, mq->depth * MBOX_MAX_BUF_SZ,
> +			  mq->dma_buf_vaddr, mq->dma_buf_paddr);
> +}
> +
> +static int hinic3_init_mbox_dma_queue(struct hinic3_mbox *mbox)
> +{
> +	u32 val;
> +	int err;
> +
> +	err = init_mbox_dma_queue(mbox->hwdev, &mbox->sync_msg_queue);
> +	if (err)
> +		return err;
> +
> +	err = init_mbox_dma_queue(mbox->hwdev, &mbox->async_msg_queue);
> +	if (err) {
> +		uninit_mbox_dma_queue(mbox->hwdev, &mbox->sync_msg_queue);
> +		return err;
> +	}
> +
> +	val = hinic3_hwif_read_reg(mbox->hwdev->hwif, MBOX_MQ_CI_OFFSET);
> +	val &= ~MBOX_MQ_SYNC_CI_MASK;
> +	val &= ~MBOX_MQ_ASYNC_CI_MASK;
> +	hinic3_hwif_write_reg(mbox->hwdev->hwif, MBOX_MQ_CI_OFFSET, val);
> +
> +	return 0;
> +}
> +
> +static void hinic3_uninit_mbox_dma_queue(struct hinic3_mbox *mbox)
> +{
> +	uninit_mbox_dma_queue(mbox->hwdev, &mbox->sync_msg_queue);
> +	uninit_mbox_dma_queue(mbox->hwdev, &mbox->async_msg_queue);
> +}
> +
> +static int alloc_mbox_msg_channel(struct hinic3_msg_channel *msg_ch)
> +{
> +	msg_ch->resp_msg.msg = kzalloc(MBOX_MAX_BUF_SZ, GFP_KERNEL);
> +	if (!msg_ch->resp_msg.msg)
> +		return -ENOMEM;
> +
> +	msg_ch->recv_msg.msg = kzalloc(MBOX_MAX_BUF_SZ, GFP_KERNEL);
> +	if (!msg_ch->recv_msg.msg) {
> +		kfree(msg_ch->resp_msg.msg);
> +		return -ENOMEM;
> +	}
> +
> +	msg_ch->resp_msg.seq_id = MBOX_SEQ_ID_MAX_VAL;
> +	msg_ch->recv_msg.seq_id = MBOX_SEQ_ID_MAX_VAL;
> +
> +	return 0;
> +}
> +
> +static void free_mbox_msg_channel(struct hinic3_msg_channel *msg_ch)
> +{
> +	kfree(msg_ch->recv_msg.msg);
> +	kfree(msg_ch->resp_msg.msg);
> +}
> +
> +static int init_mgmt_msg_channel(struct hinic3_mbox *mbox)
> +{
> +	int err;
> +
> +	err = alloc_mbox_msg_channel(&mbox->mgmt_msg);
> +	if (err) {
> +		dev_err(mbox->hwdev->dev, "Failed to alloc mgmt message channel\n");
> +		return err;
> +	}
> +
> +	err = hinic3_init_mbox_dma_queue(mbox);
> +	if (err) {
> +		dev_err(mbox->hwdev->dev, "Failed to init mbox dma queue\n");
> +		free_mbox_msg_channel(&mbox->mgmt_msg);
> +		return err;
> +	}
> +
> +	return 0;
> +}
> +
> +static void uninit_mgmt_msg_channel(struct hinic3_mbox *mbox)
> +{
> +	hinic3_uninit_mbox_dma_queue(mbox);
> +	free_mbox_msg_channel(&mbox->mgmt_msg);
> +}
> +
> +static int hinic3_init_func_mbox_msg_channel(struct hinic3_hwdev *hwdev)
> +{
> +	struct hinic3_mbox *mbox;
> +	int err;
> +
> +	mbox = hwdev->mbox;
> +	mbox->func_msg = kzalloc(sizeof(*mbox->func_msg), GFP_KERNEL);
> +	if (!mbox->func_msg)
> +		return -ENOMEM;
> +
> +	err = alloc_mbox_msg_channel(mbox->func_msg);
> +	if (err)
> +		goto err_free_func_msg;
> +
> +	return 0;
> +
> +err_free_func_msg:
> +	kfree(mbox->func_msg);
> +	mbox->func_msg = NULL;
> +
> +	return err;
> +}
> +
> +static void hinic3_uninit_func_mbox_msg_channel(struct hinic3_hwdev *hwdev)
> +{
> +	struct hinic3_mbox *mbox = hwdev->mbox;
> +
> +	free_mbox_msg_channel(mbox->func_msg);
> +	kfree(mbox->func_msg);
> +	mbox->func_msg = NULL;
> +}
> +
> +static void prepare_send_mbox(struct hinic3_mbox *mbox)
> +{
> +	struct hinic3_send_mbox *send_mbox = &mbox->send_mbox;
> +
> +	send_mbox->data = MBOX_AREA(mbox->hwdev->hwif);
> +}
> +
> +static int alloc_mbox_wb_status(struct hinic3_mbox *mbox)
> +{
> +	struct hinic3_send_mbox *send_mbox = &mbox->send_mbox;
> +	struct hinic3_hwdev *hwdev = mbox->hwdev;
> +	u32 addr_h, addr_l;
> +
> +	send_mbox->wb_vaddr = dma_alloc_coherent(hwdev->dev,
> +						 MBOX_WB_STATUS_LEN,
> +						 &send_mbox->wb_paddr,
> +						 GFP_KERNEL);
> +	if (!send_mbox->wb_vaddr)
> +		return -ENOMEM;
> +
> +	addr_h = upper_32_bits(send_mbox->wb_paddr);
> +	addr_l = lower_32_bits(send_mbox->wb_paddr);
> +	hinic3_hwif_write_reg(hwdev->hwif, HINIC3_FUNC_CSR_MAILBOX_RESULT_H_OFF,
> +			      addr_h);
> +	hinic3_hwif_write_reg(hwdev->hwif, HINIC3_FUNC_CSR_MAILBOX_RESULT_L_OFF,
> +			      addr_l);
> +
> +	return 0;
> +}
> +
> +static void free_mbox_wb_status(struct hinic3_mbox *mbox)
> +{
> +	struct hinic3_send_mbox *send_mbox = &mbox->send_mbox;
> +	struct hinic3_hwdev *hwdev = mbox->hwdev;
> +
> +	hinic3_hwif_write_reg(hwdev->hwif, HINIC3_FUNC_CSR_MAILBOX_RESULT_H_OFF,
> +			      0);
> +	hinic3_hwif_write_reg(hwdev->hwif, HINIC3_FUNC_CSR_MAILBOX_RESULT_L_OFF,
> +			      0);
> +
> +	dma_free_coherent(hwdev->dev, MBOX_WB_STATUS_LEN,
> +			  send_mbox->wb_vaddr, send_mbox->wb_paddr);
> +}
> +
> +static int hinic3_mbox_pre_init(struct hinic3_hwdev *hwdev,
> +				struct hinic3_mbox *mbox)
> +{
> +	mbox->hwdev = hwdev;
> +	mutex_init(&mbox->mbox_send_lock);
> +	mutex_init(&mbox->msg_send_lock);
> +	spin_lock_init(&mbox->mbox_lock);
> +
> +	mbox->workq = create_singlethread_workqueue(HINIC3_MBOX_WQ_NAME);
> +	if (!mbox->workq) {
> +		dev_err(hwdev->dev, "Failed to initialize MBOX workqueue\n");
> +		kfree(mbox);
> +		return -ENOMEM;
> +	}
> +	hwdev->mbox = mbox;
> +
> +	return 0;
> +}
> +
> +int hinic3_init_mbox(struct hinic3_hwdev *hwdev)
> +{
> +	struct hinic3_mbox *mbox;
> +	int err;
> +
> +	mbox = kzalloc(sizeof(*mbox), GFP_KERNEL);
> +	if (!mbox)
> +		return -ENOMEM;
> +
> +	err = hinic3_mbox_pre_init(hwdev, mbox);
> +	if (err)
> +		return err;
> +
> +	err = init_mgmt_msg_channel(mbox);
> +	if (err)
> +		goto err_destroy_workqueue;
> +
> +	err = hinic3_init_func_mbox_msg_channel(hwdev);
> +	if (err)
> +		goto err_uninit_mgmt_msg_ch;
> +
> +	err = alloc_mbox_wb_status(mbox);
> +	if (err) {
> +		dev_err(hwdev->dev, "Failed to alloc mbox write back status\n");
> +		goto err_uninit_func_mbox_msg_ch;
> +	}
> +
> +	prepare_send_mbox(mbox);
> +
> +	return 0;
> +
> +err_uninit_func_mbox_msg_ch:
> +	hinic3_uninit_func_mbox_msg_channel(hwdev);
> +
> +err_uninit_mgmt_msg_ch:
> +	uninit_mgmt_msg_channel(mbox);
> +
> +err_destroy_workqueue:
> +	destroy_workqueue(mbox->workq);
> +	kfree(mbox);
> +
> +	return err;
> +}
> +
> +void hinic3_free_mbox(struct hinic3_hwdev *hwdev)
> +{
> +	struct hinic3_mbox *mbox = hwdev->mbox;
> +
> +	destroy_workqueue(mbox->workq);
> +	free_mbox_wb_status(mbox);
> +	hinic3_uninit_func_mbox_msg_channel(hwdev);
> +	uninit_mgmt_msg_channel(mbox);
> +	kfree(mbox);
> +}
> +
>   int hinic3_send_mbox_to_mgmt(struct hinic3_hwdev *hwdev, u8 mod, u16 cmd,
>   			     const struct mgmt_msg_params *msg_params)
>   {
> diff --git a/drivers/net/ethernet/huawei/hinic3/hinic3_mbox.h b/drivers/net/ethernet/huawei/hinic3/hinic3_mbox.h
> index d7a6c37b7eff..730795b66a86 100644
> --- a/drivers/net/ethernet/huawei/hinic3/hinic3_mbox.h
> +++ b/drivers/net/ethernet/huawei/hinic3/hinic3_mbox.h
> @@ -9,6 +9,111 @@
>   
>   struct hinic3_hwdev;
>   
> +#define MBOX_MSG_HEADER_SRC_GLB_FUNC_IDX_MASK  GENMASK_ULL(12, 0)
> +#define MBOX_MSG_HEADER_STATUS_MASK            BIT_ULL(13)
> +#define MBOX_MSG_HEADER_SOURCE_MASK            BIT_ULL(15)
> +#define MBOX_MSG_HEADER_AEQ_ID_MASK            GENMASK_ULL(17, 16)
> +#define MBOX_MSG_HEADER_MSG_ID_MASK            GENMASK_ULL(21, 18)
> +#define MBOX_MSG_HEADER_CMD_MASK               GENMASK_ULL(31, 22)
> +#define MBOX_MSG_HEADER_MSG_LEN_MASK           GENMASK_ULL(42, 32)
> +#define MBOX_MSG_HEADER_MODULE_MASK            GENMASK_ULL(47, 43)
> +#define MBOX_MSG_HEADER_SEG_LEN_MASK           GENMASK_ULL(53, 48)
> +#define MBOX_MSG_HEADER_NO_ACK_MASK            BIT_ULL(54)
> +#define MBOX_MSG_HEADER_DATA_TYPE_MASK         BIT_ULL(55)
> +#define MBOX_MSG_HEADER_SEQID_MASK             GENMASK_ULL(61, 56)
> +#define MBOX_MSG_HEADER_LAST_MASK              BIT_ULL(62)
> +#define MBOX_MSG_HEADER_DIRECTION_MASK         BIT_ULL(63)
> +
> +#define MBOX_MSG_HEADER_SET(val, member) \
> +	FIELD_PREP(MBOX_MSG_HEADER_##member##_MASK, val)
> +#define MBOX_MSG_HEADER_GET(val, member) \
> +	FIELD_GET(MBOX_MSG_HEADER_##member##_MASK, val)
> +
> +/* identifies if a segment belongs to a message or to a response. A VF is only
> + * expected to send messages and receive responses. PF driver could receive
> + * messages and send responses.
> + */
> +enum mbox_msg_direction_type {
> +	MBOX_MSG_SEND = 0,
> +	MBOX_MSG_RESP = 1,
> +};
> +
> +#define HINIC3_MBOX_WQ_NAME  "hinic3_mbox"
> +
> +struct mbox_msg_info {
> +	u8 msg_id;
> +	u8 status;
> +};
> +
> +struct hinic3_msg_desc {
> +	void                 *msg;
> +	u16                  msg_len;
> +	u8                   seq_id;
> +	u8                   mod;
> +	u16                  cmd;
> +	struct mbox_msg_info msg_info;
> +};
> +
> +struct hinic3_msg_channel {
> +	struct   hinic3_msg_desc resp_msg;
> +	struct   hinic3_msg_desc recv_msg;
> +};
> +
> +struct hinic3_send_mbox {
> +	u8 __iomem *data;
> +	void       *wb_vaddr;
> +	dma_addr_t wb_paddr;
> +};
> +
> +enum mbox_event_state {
> +	MBOX_EVENT_START   = 0,
> +	MBOX_EVENT_FAIL    = 1,
> +	MBOX_EVENT_SUCCESS = 2,
> +	MBOX_EVENT_TIMEOUT = 3,
> +	MBOX_EVENT_END     = 4,
> +};
> +
> +struct mbox_dma_msg {
> +	u32 xor;
> +	u32 dma_addr_high;
> +	u32 dma_addr_low;
> +	u32 msg_len;
> +	u64 rsvd;
> +};
> +
> +struct mbox_dma_queue {
> +	void       *dma_buf_vaddr;
> +	dma_addr_t dma_buf_paddr;
> +	u16        depth;
> +	u16        prod_idx;
> +	u16        cons_idx;
> +};
> +
> +struct hinic3_mbox {
> +	struct hinic3_hwdev       *hwdev;
> +	/* lock for send mbox message and ack message */
> +	struct mutex              mbox_send_lock;
> +	/* lock for send mbox message */
> +	struct mutex              msg_send_lock;
> +	struct hinic3_send_mbox   send_mbox;
> +	struct mbox_dma_queue     sync_msg_queue;
> +	struct mbox_dma_queue     async_msg_queue;
> +	struct workqueue_struct   *workq;
> +	/* driver and MGMT CPU */
> +	struct hinic3_msg_channel mgmt_msg;
> +	/* VF to PF */
> +	struct hinic3_msg_channel *func_msg;
> +	u8                        send_msg_id;
> +	enum mbox_event_state     event_flag;
> +	/* lock for mbox event flag */
> +	spinlock_t                mbox_lock;
> +};
> +
> +void hinic3_mbox_func_aeqe_handler(struct hinic3_hwdev *hwdev, u8 *header,
> +				   u8 size);
> +int hinic3_init_mbox(struct hinic3_hwdev *hwdev);
> +void hinic3_free_mbox(struct hinic3_hwdev *hwdev);
> +
>   int hinic3_send_mbox_to_mgmt(struct hinic3_hwdev *hwdev, u8 mod, u16 cmd,
>   			     const struct mgmt_msg_params *msg_params);
>   


Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ