162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Linux network driver for QLogic BR-series Converged Network Adapter.
462306a36Sopenharmony_ci */
562306a36Sopenharmony_ci/*
662306a36Sopenharmony_ci * Copyright (c) 2005-2014 Brocade Communications Systems, Inc.
762306a36Sopenharmony_ci * Copyright (c) 2014-2015 QLogic Corporation
862306a36Sopenharmony_ci * All rights reserved
962306a36Sopenharmony_ci * www.qlogic.com
1062306a36Sopenharmony_ci */
1162306a36Sopenharmony_ci
1262306a36Sopenharmony_ci/* MSGQ module source file. */
1362306a36Sopenharmony_ci
1462306a36Sopenharmony_ci#include "bfi.h"
1562306a36Sopenharmony_ci#include "bfa_msgq.h"
1662306a36Sopenharmony_ci#include "bfa_ioc.h"
1762306a36Sopenharmony_ci
1862306a36Sopenharmony_ci#define call_cmdq_ent_cbfn(_cmdq_ent, _status)				\
1962306a36Sopenharmony_ci{									\
2062306a36Sopenharmony_ci	bfa_msgq_cmdcbfn_t cbfn;					\
2162306a36Sopenharmony_ci	void *cbarg;							\
2262306a36Sopenharmony_ci	cbfn = (_cmdq_ent)->cbfn;					\
2362306a36Sopenharmony_ci	cbarg = (_cmdq_ent)->cbarg;					\
2462306a36Sopenharmony_ci	(_cmdq_ent)->cbfn = NULL;					\
2562306a36Sopenharmony_ci	(_cmdq_ent)->cbarg = NULL;					\
2662306a36Sopenharmony_ci	if (cbfn) {							\
2762306a36Sopenharmony_ci		cbfn(cbarg, (_status));					\
2862306a36Sopenharmony_ci	}								\
2962306a36Sopenharmony_ci}
3062306a36Sopenharmony_ci
3162306a36Sopenharmony_cistatic void bfa_msgq_cmdq_dbell(struct bfa_msgq_cmdq *cmdq);
3262306a36Sopenharmony_cistatic void bfa_msgq_cmdq_copy_rsp(struct bfa_msgq_cmdq *cmdq);
3362306a36Sopenharmony_ci
3462306a36Sopenharmony_cienum cmdq_event {
3562306a36Sopenharmony_ci	CMDQ_E_START			= 1,
3662306a36Sopenharmony_ci	CMDQ_E_STOP			= 2,
3762306a36Sopenharmony_ci	CMDQ_E_FAIL			= 3,
3862306a36Sopenharmony_ci	CMDQ_E_POST			= 4,
3962306a36Sopenharmony_ci	CMDQ_E_INIT_RESP		= 5,
4062306a36Sopenharmony_ci	CMDQ_E_DB_READY			= 6,
4162306a36Sopenharmony_ci};
4262306a36Sopenharmony_ci
4362306a36Sopenharmony_cibfa_fsm_state_decl(cmdq, stopped, struct bfa_msgq_cmdq, enum cmdq_event);
4462306a36Sopenharmony_cibfa_fsm_state_decl(cmdq, init_wait, struct bfa_msgq_cmdq, enum cmdq_event);
4562306a36Sopenharmony_cibfa_fsm_state_decl(cmdq, ready, struct bfa_msgq_cmdq, enum cmdq_event);
4662306a36Sopenharmony_cibfa_fsm_state_decl(cmdq, dbell_wait, struct bfa_msgq_cmdq,
4762306a36Sopenharmony_ci			enum cmdq_event);
4862306a36Sopenharmony_ci
4962306a36Sopenharmony_cistatic void
5062306a36Sopenharmony_cicmdq_sm_stopped_entry(struct bfa_msgq_cmdq *cmdq)
5162306a36Sopenharmony_ci{
5262306a36Sopenharmony_ci	struct bfa_msgq_cmd_entry *cmdq_ent;
5362306a36Sopenharmony_ci
5462306a36Sopenharmony_ci	cmdq->producer_index = 0;
5562306a36Sopenharmony_ci	cmdq->consumer_index = 0;
5662306a36Sopenharmony_ci	cmdq->flags = 0;
5762306a36Sopenharmony_ci	cmdq->token = 0;
5862306a36Sopenharmony_ci	cmdq->offset = 0;
5962306a36Sopenharmony_ci	cmdq->bytes_to_copy = 0;
6062306a36Sopenharmony_ci	while (!list_empty(&cmdq->pending_q)) {
6162306a36Sopenharmony_ci		cmdq_ent = list_first_entry(&cmdq->pending_q,
6262306a36Sopenharmony_ci					    struct bfa_msgq_cmd_entry, qe);
6362306a36Sopenharmony_ci		list_del(&cmdq_ent->qe);
6462306a36Sopenharmony_ci		call_cmdq_ent_cbfn(cmdq_ent, BFA_STATUS_FAILED);
6562306a36Sopenharmony_ci	}
6662306a36Sopenharmony_ci}
6762306a36Sopenharmony_ci
6862306a36Sopenharmony_cistatic void
6962306a36Sopenharmony_cicmdq_sm_stopped(struct bfa_msgq_cmdq *cmdq, enum cmdq_event event)
7062306a36Sopenharmony_ci{
7162306a36Sopenharmony_ci	switch (event) {
7262306a36Sopenharmony_ci	case CMDQ_E_START:
7362306a36Sopenharmony_ci		bfa_fsm_set_state(cmdq, cmdq_sm_init_wait);
7462306a36Sopenharmony_ci		break;
7562306a36Sopenharmony_ci
7662306a36Sopenharmony_ci	case CMDQ_E_STOP:
7762306a36Sopenharmony_ci	case CMDQ_E_FAIL:
7862306a36Sopenharmony_ci		/* No-op */
7962306a36Sopenharmony_ci		break;
8062306a36Sopenharmony_ci
8162306a36Sopenharmony_ci	case CMDQ_E_POST:
8262306a36Sopenharmony_ci		cmdq->flags |= BFA_MSGQ_CMDQ_F_DB_UPDATE;
8362306a36Sopenharmony_ci		break;
8462306a36Sopenharmony_ci
8562306a36Sopenharmony_ci	default:
8662306a36Sopenharmony_ci		bfa_sm_fault(event);
8762306a36Sopenharmony_ci	}
8862306a36Sopenharmony_ci}
8962306a36Sopenharmony_ci
9062306a36Sopenharmony_cistatic void
9162306a36Sopenharmony_cicmdq_sm_init_wait_entry(struct bfa_msgq_cmdq *cmdq)
9262306a36Sopenharmony_ci{
9362306a36Sopenharmony_ci	bfa_wc_down(&cmdq->msgq->init_wc);
9462306a36Sopenharmony_ci}
9562306a36Sopenharmony_ci
9662306a36Sopenharmony_cistatic void
9762306a36Sopenharmony_cicmdq_sm_init_wait(struct bfa_msgq_cmdq *cmdq, enum cmdq_event event)
9862306a36Sopenharmony_ci{
9962306a36Sopenharmony_ci	switch (event) {
10062306a36Sopenharmony_ci	case CMDQ_E_STOP:
10162306a36Sopenharmony_ci	case CMDQ_E_FAIL:
10262306a36Sopenharmony_ci		bfa_fsm_set_state(cmdq, cmdq_sm_stopped);
10362306a36Sopenharmony_ci		break;
10462306a36Sopenharmony_ci
10562306a36Sopenharmony_ci	case CMDQ_E_POST:
10662306a36Sopenharmony_ci		cmdq->flags |= BFA_MSGQ_CMDQ_F_DB_UPDATE;
10762306a36Sopenharmony_ci		break;
10862306a36Sopenharmony_ci
10962306a36Sopenharmony_ci	case CMDQ_E_INIT_RESP:
11062306a36Sopenharmony_ci		if (cmdq->flags & BFA_MSGQ_CMDQ_F_DB_UPDATE) {
11162306a36Sopenharmony_ci			cmdq->flags &= ~BFA_MSGQ_CMDQ_F_DB_UPDATE;
11262306a36Sopenharmony_ci			bfa_fsm_set_state(cmdq, cmdq_sm_dbell_wait);
11362306a36Sopenharmony_ci		} else
11462306a36Sopenharmony_ci			bfa_fsm_set_state(cmdq, cmdq_sm_ready);
11562306a36Sopenharmony_ci		break;
11662306a36Sopenharmony_ci
11762306a36Sopenharmony_ci	default:
11862306a36Sopenharmony_ci		bfa_sm_fault(event);
11962306a36Sopenharmony_ci	}
12062306a36Sopenharmony_ci}
12162306a36Sopenharmony_ci
12262306a36Sopenharmony_cistatic void
12362306a36Sopenharmony_cicmdq_sm_ready_entry(struct bfa_msgq_cmdq *cmdq)
12462306a36Sopenharmony_ci{
12562306a36Sopenharmony_ci}
12662306a36Sopenharmony_ci
12762306a36Sopenharmony_cistatic void
12862306a36Sopenharmony_cicmdq_sm_ready(struct bfa_msgq_cmdq *cmdq, enum cmdq_event event)
12962306a36Sopenharmony_ci{
13062306a36Sopenharmony_ci	switch (event) {
13162306a36Sopenharmony_ci	case CMDQ_E_STOP:
13262306a36Sopenharmony_ci	case CMDQ_E_FAIL:
13362306a36Sopenharmony_ci		bfa_fsm_set_state(cmdq, cmdq_sm_stopped);
13462306a36Sopenharmony_ci		break;
13562306a36Sopenharmony_ci
13662306a36Sopenharmony_ci	case CMDQ_E_POST:
13762306a36Sopenharmony_ci		bfa_fsm_set_state(cmdq, cmdq_sm_dbell_wait);
13862306a36Sopenharmony_ci		break;
13962306a36Sopenharmony_ci
14062306a36Sopenharmony_ci	default:
14162306a36Sopenharmony_ci		bfa_sm_fault(event);
14262306a36Sopenharmony_ci	}
14362306a36Sopenharmony_ci}
14462306a36Sopenharmony_ci
14562306a36Sopenharmony_cistatic void
14662306a36Sopenharmony_cicmdq_sm_dbell_wait_entry(struct bfa_msgq_cmdq *cmdq)
14762306a36Sopenharmony_ci{
14862306a36Sopenharmony_ci	bfa_msgq_cmdq_dbell(cmdq);
14962306a36Sopenharmony_ci}
15062306a36Sopenharmony_ci
15162306a36Sopenharmony_cistatic void
15262306a36Sopenharmony_cicmdq_sm_dbell_wait(struct bfa_msgq_cmdq *cmdq, enum cmdq_event event)
15362306a36Sopenharmony_ci{
15462306a36Sopenharmony_ci	switch (event) {
15562306a36Sopenharmony_ci	case CMDQ_E_STOP:
15662306a36Sopenharmony_ci	case CMDQ_E_FAIL:
15762306a36Sopenharmony_ci		bfa_fsm_set_state(cmdq, cmdq_sm_stopped);
15862306a36Sopenharmony_ci		break;
15962306a36Sopenharmony_ci
16062306a36Sopenharmony_ci	case CMDQ_E_POST:
16162306a36Sopenharmony_ci		cmdq->flags |= BFA_MSGQ_CMDQ_F_DB_UPDATE;
16262306a36Sopenharmony_ci		break;
16362306a36Sopenharmony_ci
16462306a36Sopenharmony_ci	case CMDQ_E_DB_READY:
16562306a36Sopenharmony_ci		if (cmdq->flags & BFA_MSGQ_CMDQ_F_DB_UPDATE) {
16662306a36Sopenharmony_ci			cmdq->flags &= ~BFA_MSGQ_CMDQ_F_DB_UPDATE;
16762306a36Sopenharmony_ci			bfa_fsm_set_state(cmdq, cmdq_sm_dbell_wait);
16862306a36Sopenharmony_ci		} else
16962306a36Sopenharmony_ci			bfa_fsm_set_state(cmdq, cmdq_sm_ready);
17062306a36Sopenharmony_ci		break;
17162306a36Sopenharmony_ci
17262306a36Sopenharmony_ci	default:
17362306a36Sopenharmony_ci		bfa_sm_fault(event);
17462306a36Sopenharmony_ci	}
17562306a36Sopenharmony_ci}
17662306a36Sopenharmony_ci
17762306a36Sopenharmony_cistatic void
17862306a36Sopenharmony_cibfa_msgq_cmdq_dbell_ready(void *arg)
17962306a36Sopenharmony_ci{
18062306a36Sopenharmony_ci	struct bfa_msgq_cmdq *cmdq = (struct bfa_msgq_cmdq *)arg;
18162306a36Sopenharmony_ci	bfa_fsm_send_event(cmdq, CMDQ_E_DB_READY);
18262306a36Sopenharmony_ci}
18362306a36Sopenharmony_ci
18462306a36Sopenharmony_cistatic void
18562306a36Sopenharmony_cibfa_msgq_cmdq_dbell(struct bfa_msgq_cmdq *cmdq)
18662306a36Sopenharmony_ci{
18762306a36Sopenharmony_ci	struct bfi_msgq_h2i_db *dbell =
18862306a36Sopenharmony_ci		(struct bfi_msgq_h2i_db *)(&cmdq->dbell_mb.msg[0]);
18962306a36Sopenharmony_ci
19062306a36Sopenharmony_ci	memset(dbell, 0, sizeof(struct bfi_msgq_h2i_db));
19162306a36Sopenharmony_ci	bfi_h2i_set(dbell->mh, BFI_MC_MSGQ, BFI_MSGQ_H2I_DOORBELL_PI, 0);
19262306a36Sopenharmony_ci	dbell->mh.mtag.i2htok = 0;
19362306a36Sopenharmony_ci	dbell->idx.cmdq_pi = htons(cmdq->producer_index);
19462306a36Sopenharmony_ci
19562306a36Sopenharmony_ci	if (!bfa_nw_ioc_mbox_queue(cmdq->msgq->ioc, &cmdq->dbell_mb,
19662306a36Sopenharmony_ci				bfa_msgq_cmdq_dbell_ready, cmdq)) {
19762306a36Sopenharmony_ci		bfa_msgq_cmdq_dbell_ready(cmdq);
19862306a36Sopenharmony_ci	}
19962306a36Sopenharmony_ci}
20062306a36Sopenharmony_ci
20162306a36Sopenharmony_cistatic void
20262306a36Sopenharmony_ci__cmd_copy(struct bfa_msgq_cmdq *cmdq, struct bfa_msgq_cmd_entry *cmd)
20362306a36Sopenharmony_ci{
20462306a36Sopenharmony_ci	size_t len = cmd->msg_size;
20562306a36Sopenharmony_ci	size_t to_copy;
20662306a36Sopenharmony_ci	u8 *src, *dst;
20762306a36Sopenharmony_ci
20862306a36Sopenharmony_ci	src = (u8 *)cmd->msg_hdr;
20962306a36Sopenharmony_ci	dst = (u8 *)cmdq->addr.kva;
21062306a36Sopenharmony_ci	dst += (cmdq->producer_index * BFI_MSGQ_CMD_ENTRY_SIZE);
21162306a36Sopenharmony_ci
21262306a36Sopenharmony_ci	while (len) {
21362306a36Sopenharmony_ci		to_copy = (len < BFI_MSGQ_CMD_ENTRY_SIZE) ?
21462306a36Sopenharmony_ci				len : BFI_MSGQ_CMD_ENTRY_SIZE;
21562306a36Sopenharmony_ci		memcpy(dst, src, to_copy);
21662306a36Sopenharmony_ci		len -= to_copy;
21762306a36Sopenharmony_ci		src += BFI_MSGQ_CMD_ENTRY_SIZE;
21862306a36Sopenharmony_ci		BFA_MSGQ_INDX_ADD(cmdq->producer_index, 1, cmdq->depth);
21962306a36Sopenharmony_ci		dst = (u8 *)cmdq->addr.kva;
22062306a36Sopenharmony_ci		dst += (cmdq->producer_index * BFI_MSGQ_CMD_ENTRY_SIZE);
22162306a36Sopenharmony_ci	}
22262306a36Sopenharmony_ci
22362306a36Sopenharmony_ci}
22462306a36Sopenharmony_ci
22562306a36Sopenharmony_cistatic void
22662306a36Sopenharmony_cibfa_msgq_cmdq_ci_update(struct bfa_msgq_cmdq *cmdq, struct bfi_mbmsg *mb)
22762306a36Sopenharmony_ci{
22862306a36Sopenharmony_ci	struct bfi_msgq_i2h_db *dbell = (struct bfi_msgq_i2h_db *)mb;
22962306a36Sopenharmony_ci	struct bfa_msgq_cmd_entry *cmd;
23062306a36Sopenharmony_ci	int posted = 0;
23162306a36Sopenharmony_ci
23262306a36Sopenharmony_ci	cmdq->consumer_index = ntohs(dbell->idx.cmdq_ci);
23362306a36Sopenharmony_ci
23462306a36Sopenharmony_ci	/* Walk through pending list to see if the command can be posted */
23562306a36Sopenharmony_ci	while (!list_empty(&cmdq->pending_q)) {
23662306a36Sopenharmony_ci		cmd = list_first_entry(&cmdq->pending_q,
23762306a36Sopenharmony_ci				       struct bfa_msgq_cmd_entry, qe);
23862306a36Sopenharmony_ci		if (ntohs(cmd->msg_hdr->num_entries) <=
23962306a36Sopenharmony_ci			BFA_MSGQ_FREE_CNT(cmdq)) {
24062306a36Sopenharmony_ci			list_del(&cmd->qe);
24162306a36Sopenharmony_ci			__cmd_copy(cmdq, cmd);
24262306a36Sopenharmony_ci			posted = 1;
24362306a36Sopenharmony_ci			call_cmdq_ent_cbfn(cmd, BFA_STATUS_OK);
24462306a36Sopenharmony_ci		} else {
24562306a36Sopenharmony_ci			break;
24662306a36Sopenharmony_ci		}
24762306a36Sopenharmony_ci	}
24862306a36Sopenharmony_ci
24962306a36Sopenharmony_ci	if (posted)
25062306a36Sopenharmony_ci		bfa_fsm_send_event(cmdq, CMDQ_E_POST);
25162306a36Sopenharmony_ci}
25262306a36Sopenharmony_ci
25362306a36Sopenharmony_cistatic void
25462306a36Sopenharmony_cibfa_msgq_cmdq_copy_next(void *arg)
25562306a36Sopenharmony_ci{
25662306a36Sopenharmony_ci	struct bfa_msgq_cmdq *cmdq = (struct bfa_msgq_cmdq *)arg;
25762306a36Sopenharmony_ci
25862306a36Sopenharmony_ci	if (cmdq->bytes_to_copy)
25962306a36Sopenharmony_ci		bfa_msgq_cmdq_copy_rsp(cmdq);
26062306a36Sopenharmony_ci}
26162306a36Sopenharmony_ci
26262306a36Sopenharmony_cistatic void
26362306a36Sopenharmony_cibfa_msgq_cmdq_copy_req(struct bfa_msgq_cmdq *cmdq, struct bfi_mbmsg *mb)
26462306a36Sopenharmony_ci{
26562306a36Sopenharmony_ci	struct bfi_msgq_i2h_cmdq_copy_req *req =
26662306a36Sopenharmony_ci		(struct bfi_msgq_i2h_cmdq_copy_req *)mb;
26762306a36Sopenharmony_ci
26862306a36Sopenharmony_ci	cmdq->token = 0;
26962306a36Sopenharmony_ci	cmdq->offset = ntohs(req->offset);
27062306a36Sopenharmony_ci	cmdq->bytes_to_copy = ntohs(req->len);
27162306a36Sopenharmony_ci	bfa_msgq_cmdq_copy_rsp(cmdq);
27262306a36Sopenharmony_ci}
27362306a36Sopenharmony_ci
27462306a36Sopenharmony_cistatic void
27562306a36Sopenharmony_cibfa_msgq_cmdq_copy_rsp(struct bfa_msgq_cmdq *cmdq)
27662306a36Sopenharmony_ci{
27762306a36Sopenharmony_ci	struct bfi_msgq_h2i_cmdq_copy_rsp *rsp =
27862306a36Sopenharmony_ci		(struct bfi_msgq_h2i_cmdq_copy_rsp *)&cmdq->copy_mb.msg[0];
27962306a36Sopenharmony_ci	int copied;
28062306a36Sopenharmony_ci	u8 *addr = (u8 *)cmdq->addr.kva;
28162306a36Sopenharmony_ci
28262306a36Sopenharmony_ci	memset(rsp, 0, sizeof(struct bfi_msgq_h2i_cmdq_copy_rsp));
28362306a36Sopenharmony_ci	bfi_h2i_set(rsp->mh, BFI_MC_MSGQ, BFI_MSGQ_H2I_CMDQ_COPY_RSP, 0);
28462306a36Sopenharmony_ci	rsp->mh.mtag.i2htok = htons(cmdq->token);
28562306a36Sopenharmony_ci	copied = (cmdq->bytes_to_copy >= BFI_CMD_COPY_SZ) ? BFI_CMD_COPY_SZ :
28662306a36Sopenharmony_ci		cmdq->bytes_to_copy;
28762306a36Sopenharmony_ci	addr += cmdq->offset;
28862306a36Sopenharmony_ci	memcpy(rsp->data, addr, copied);
28962306a36Sopenharmony_ci
29062306a36Sopenharmony_ci	cmdq->token++;
29162306a36Sopenharmony_ci	cmdq->offset += copied;
29262306a36Sopenharmony_ci	cmdq->bytes_to_copy -= copied;
29362306a36Sopenharmony_ci
29462306a36Sopenharmony_ci	if (!bfa_nw_ioc_mbox_queue(cmdq->msgq->ioc, &cmdq->copy_mb,
29562306a36Sopenharmony_ci				bfa_msgq_cmdq_copy_next, cmdq)) {
29662306a36Sopenharmony_ci		bfa_msgq_cmdq_copy_next(cmdq);
29762306a36Sopenharmony_ci	}
29862306a36Sopenharmony_ci}
29962306a36Sopenharmony_ci
30062306a36Sopenharmony_cistatic void
30162306a36Sopenharmony_cibfa_msgq_cmdq_attach(struct bfa_msgq_cmdq *cmdq, struct bfa_msgq *msgq)
30262306a36Sopenharmony_ci{
30362306a36Sopenharmony_ci	cmdq->depth = BFA_MSGQ_CMDQ_NUM_ENTRY;
30462306a36Sopenharmony_ci	INIT_LIST_HEAD(&cmdq->pending_q);
30562306a36Sopenharmony_ci	cmdq->msgq = msgq;
30662306a36Sopenharmony_ci	bfa_fsm_set_state(cmdq, cmdq_sm_stopped);
30762306a36Sopenharmony_ci}
30862306a36Sopenharmony_ci
30962306a36Sopenharmony_cistatic void bfa_msgq_rspq_dbell(struct bfa_msgq_rspq *rspq);
31062306a36Sopenharmony_ci
31162306a36Sopenharmony_cienum rspq_event {
31262306a36Sopenharmony_ci	RSPQ_E_START			= 1,
31362306a36Sopenharmony_ci	RSPQ_E_STOP			= 2,
31462306a36Sopenharmony_ci	RSPQ_E_FAIL			= 3,
31562306a36Sopenharmony_ci	RSPQ_E_RESP			= 4,
31662306a36Sopenharmony_ci	RSPQ_E_INIT_RESP		= 5,
31762306a36Sopenharmony_ci	RSPQ_E_DB_READY			= 6,
31862306a36Sopenharmony_ci};
31962306a36Sopenharmony_ci
32062306a36Sopenharmony_cibfa_fsm_state_decl(rspq, stopped, struct bfa_msgq_rspq, enum rspq_event);
32162306a36Sopenharmony_cibfa_fsm_state_decl(rspq, init_wait, struct bfa_msgq_rspq,
32262306a36Sopenharmony_ci			enum rspq_event);
32362306a36Sopenharmony_cibfa_fsm_state_decl(rspq, ready, struct bfa_msgq_rspq, enum rspq_event);
32462306a36Sopenharmony_cibfa_fsm_state_decl(rspq, dbell_wait, struct bfa_msgq_rspq,
32562306a36Sopenharmony_ci			enum rspq_event);
32662306a36Sopenharmony_ci
32762306a36Sopenharmony_cistatic void
32862306a36Sopenharmony_cirspq_sm_stopped_entry(struct bfa_msgq_rspq *rspq)
32962306a36Sopenharmony_ci{
33062306a36Sopenharmony_ci	rspq->producer_index = 0;
33162306a36Sopenharmony_ci	rspq->consumer_index = 0;
33262306a36Sopenharmony_ci	rspq->flags = 0;
33362306a36Sopenharmony_ci}
33462306a36Sopenharmony_ci
33562306a36Sopenharmony_cistatic void
33662306a36Sopenharmony_cirspq_sm_stopped(struct bfa_msgq_rspq *rspq, enum rspq_event event)
33762306a36Sopenharmony_ci{
33862306a36Sopenharmony_ci	switch (event) {
33962306a36Sopenharmony_ci	case RSPQ_E_START:
34062306a36Sopenharmony_ci		bfa_fsm_set_state(rspq, rspq_sm_init_wait);
34162306a36Sopenharmony_ci		break;
34262306a36Sopenharmony_ci
34362306a36Sopenharmony_ci	case RSPQ_E_STOP:
34462306a36Sopenharmony_ci	case RSPQ_E_FAIL:
34562306a36Sopenharmony_ci		/* No-op */
34662306a36Sopenharmony_ci		break;
34762306a36Sopenharmony_ci
34862306a36Sopenharmony_ci	default:
34962306a36Sopenharmony_ci		bfa_sm_fault(event);
35062306a36Sopenharmony_ci	}
35162306a36Sopenharmony_ci}
35262306a36Sopenharmony_ci
35362306a36Sopenharmony_cistatic void
35462306a36Sopenharmony_cirspq_sm_init_wait_entry(struct bfa_msgq_rspq *rspq)
35562306a36Sopenharmony_ci{
35662306a36Sopenharmony_ci	bfa_wc_down(&rspq->msgq->init_wc);
35762306a36Sopenharmony_ci}
35862306a36Sopenharmony_ci
35962306a36Sopenharmony_cistatic void
36062306a36Sopenharmony_cirspq_sm_init_wait(struct bfa_msgq_rspq *rspq, enum rspq_event event)
36162306a36Sopenharmony_ci{
36262306a36Sopenharmony_ci	switch (event) {
36362306a36Sopenharmony_ci	case RSPQ_E_FAIL:
36462306a36Sopenharmony_ci	case RSPQ_E_STOP:
36562306a36Sopenharmony_ci		bfa_fsm_set_state(rspq, rspq_sm_stopped);
36662306a36Sopenharmony_ci		break;
36762306a36Sopenharmony_ci
36862306a36Sopenharmony_ci	case RSPQ_E_INIT_RESP:
36962306a36Sopenharmony_ci		bfa_fsm_set_state(rspq, rspq_sm_ready);
37062306a36Sopenharmony_ci		break;
37162306a36Sopenharmony_ci
37262306a36Sopenharmony_ci	default:
37362306a36Sopenharmony_ci		bfa_sm_fault(event);
37462306a36Sopenharmony_ci	}
37562306a36Sopenharmony_ci}
37662306a36Sopenharmony_ci
37762306a36Sopenharmony_cistatic void
37862306a36Sopenharmony_cirspq_sm_ready_entry(struct bfa_msgq_rspq *rspq)
37962306a36Sopenharmony_ci{
38062306a36Sopenharmony_ci}
38162306a36Sopenharmony_ci
38262306a36Sopenharmony_cistatic void
38362306a36Sopenharmony_cirspq_sm_ready(struct bfa_msgq_rspq *rspq, enum rspq_event event)
38462306a36Sopenharmony_ci{
38562306a36Sopenharmony_ci	switch (event) {
38662306a36Sopenharmony_ci	case RSPQ_E_STOP:
38762306a36Sopenharmony_ci	case RSPQ_E_FAIL:
38862306a36Sopenharmony_ci		bfa_fsm_set_state(rspq, rspq_sm_stopped);
38962306a36Sopenharmony_ci		break;
39062306a36Sopenharmony_ci
39162306a36Sopenharmony_ci	case RSPQ_E_RESP:
39262306a36Sopenharmony_ci		bfa_fsm_set_state(rspq, rspq_sm_dbell_wait);
39362306a36Sopenharmony_ci		break;
39462306a36Sopenharmony_ci
39562306a36Sopenharmony_ci	default:
39662306a36Sopenharmony_ci		bfa_sm_fault(event);
39762306a36Sopenharmony_ci	}
39862306a36Sopenharmony_ci}
39962306a36Sopenharmony_ci
40062306a36Sopenharmony_cistatic void
40162306a36Sopenharmony_cirspq_sm_dbell_wait_entry(struct bfa_msgq_rspq *rspq)
40262306a36Sopenharmony_ci{
40362306a36Sopenharmony_ci	if (!bfa_nw_ioc_is_disabled(rspq->msgq->ioc))
40462306a36Sopenharmony_ci		bfa_msgq_rspq_dbell(rspq);
40562306a36Sopenharmony_ci}
40662306a36Sopenharmony_ci
40762306a36Sopenharmony_cistatic void
40862306a36Sopenharmony_cirspq_sm_dbell_wait(struct bfa_msgq_rspq *rspq, enum rspq_event event)
40962306a36Sopenharmony_ci{
41062306a36Sopenharmony_ci	switch (event) {
41162306a36Sopenharmony_ci	case RSPQ_E_STOP:
41262306a36Sopenharmony_ci	case RSPQ_E_FAIL:
41362306a36Sopenharmony_ci		bfa_fsm_set_state(rspq, rspq_sm_stopped);
41462306a36Sopenharmony_ci		break;
41562306a36Sopenharmony_ci
41662306a36Sopenharmony_ci	case RSPQ_E_RESP:
41762306a36Sopenharmony_ci		rspq->flags |= BFA_MSGQ_RSPQ_F_DB_UPDATE;
41862306a36Sopenharmony_ci		break;
41962306a36Sopenharmony_ci
42062306a36Sopenharmony_ci	case RSPQ_E_DB_READY:
42162306a36Sopenharmony_ci		if (rspq->flags & BFA_MSGQ_RSPQ_F_DB_UPDATE) {
42262306a36Sopenharmony_ci			rspq->flags &= ~BFA_MSGQ_RSPQ_F_DB_UPDATE;
42362306a36Sopenharmony_ci			bfa_fsm_set_state(rspq, rspq_sm_dbell_wait);
42462306a36Sopenharmony_ci		} else
42562306a36Sopenharmony_ci			bfa_fsm_set_state(rspq, rspq_sm_ready);
42662306a36Sopenharmony_ci		break;
42762306a36Sopenharmony_ci
42862306a36Sopenharmony_ci	default:
42962306a36Sopenharmony_ci		bfa_sm_fault(event);
43062306a36Sopenharmony_ci	}
43162306a36Sopenharmony_ci}
43262306a36Sopenharmony_ci
43362306a36Sopenharmony_cistatic void
43462306a36Sopenharmony_cibfa_msgq_rspq_dbell_ready(void *arg)
43562306a36Sopenharmony_ci{
43662306a36Sopenharmony_ci	struct bfa_msgq_rspq *rspq = (struct bfa_msgq_rspq *)arg;
43762306a36Sopenharmony_ci	bfa_fsm_send_event(rspq, RSPQ_E_DB_READY);
43862306a36Sopenharmony_ci}
43962306a36Sopenharmony_ci
44062306a36Sopenharmony_cistatic void
44162306a36Sopenharmony_cibfa_msgq_rspq_dbell(struct bfa_msgq_rspq *rspq)
44262306a36Sopenharmony_ci{
44362306a36Sopenharmony_ci	struct bfi_msgq_h2i_db *dbell =
44462306a36Sopenharmony_ci		(struct bfi_msgq_h2i_db *)(&rspq->dbell_mb.msg[0]);
44562306a36Sopenharmony_ci
44662306a36Sopenharmony_ci	memset(dbell, 0, sizeof(struct bfi_msgq_h2i_db));
44762306a36Sopenharmony_ci	bfi_h2i_set(dbell->mh, BFI_MC_MSGQ, BFI_MSGQ_H2I_DOORBELL_CI, 0);
44862306a36Sopenharmony_ci	dbell->mh.mtag.i2htok = 0;
44962306a36Sopenharmony_ci	dbell->idx.rspq_ci = htons(rspq->consumer_index);
45062306a36Sopenharmony_ci
45162306a36Sopenharmony_ci	if (!bfa_nw_ioc_mbox_queue(rspq->msgq->ioc, &rspq->dbell_mb,
45262306a36Sopenharmony_ci				bfa_msgq_rspq_dbell_ready, rspq)) {
45362306a36Sopenharmony_ci		bfa_msgq_rspq_dbell_ready(rspq);
45462306a36Sopenharmony_ci	}
45562306a36Sopenharmony_ci}
45662306a36Sopenharmony_ci
45762306a36Sopenharmony_cistatic void
45862306a36Sopenharmony_cibfa_msgq_rspq_pi_update(struct bfa_msgq_rspq *rspq, struct bfi_mbmsg *mb)
45962306a36Sopenharmony_ci{
46062306a36Sopenharmony_ci	struct bfi_msgq_i2h_db *dbell = (struct bfi_msgq_i2h_db *)mb;
46162306a36Sopenharmony_ci	struct bfi_msgq_mhdr *msghdr;
46262306a36Sopenharmony_ci	int num_entries;
46362306a36Sopenharmony_ci	int mc;
46462306a36Sopenharmony_ci	u8 *rspq_qe;
46562306a36Sopenharmony_ci
46662306a36Sopenharmony_ci	rspq->producer_index = ntohs(dbell->idx.rspq_pi);
46762306a36Sopenharmony_ci
46862306a36Sopenharmony_ci	while (rspq->consumer_index != rspq->producer_index) {
46962306a36Sopenharmony_ci		rspq_qe = (u8 *)rspq->addr.kva;
47062306a36Sopenharmony_ci		rspq_qe += (rspq->consumer_index * BFI_MSGQ_RSP_ENTRY_SIZE);
47162306a36Sopenharmony_ci		msghdr = (struct bfi_msgq_mhdr *)rspq_qe;
47262306a36Sopenharmony_ci
47362306a36Sopenharmony_ci		mc = msghdr->msg_class;
47462306a36Sopenharmony_ci		num_entries = ntohs(msghdr->num_entries);
47562306a36Sopenharmony_ci
47662306a36Sopenharmony_ci		if ((mc >= BFI_MC_MAX) || (rspq->rsphdlr[mc].cbfn == NULL))
47762306a36Sopenharmony_ci			break;
47862306a36Sopenharmony_ci
47962306a36Sopenharmony_ci		(rspq->rsphdlr[mc].cbfn)(rspq->rsphdlr[mc].cbarg, msghdr);
48062306a36Sopenharmony_ci
48162306a36Sopenharmony_ci		BFA_MSGQ_INDX_ADD(rspq->consumer_index, num_entries,
48262306a36Sopenharmony_ci				rspq->depth);
48362306a36Sopenharmony_ci	}
48462306a36Sopenharmony_ci
48562306a36Sopenharmony_ci	bfa_fsm_send_event(rspq, RSPQ_E_RESP);
48662306a36Sopenharmony_ci}
48762306a36Sopenharmony_ci
48862306a36Sopenharmony_cistatic void
48962306a36Sopenharmony_cibfa_msgq_rspq_attach(struct bfa_msgq_rspq *rspq, struct bfa_msgq *msgq)
49062306a36Sopenharmony_ci{
49162306a36Sopenharmony_ci	rspq->depth = BFA_MSGQ_RSPQ_NUM_ENTRY;
49262306a36Sopenharmony_ci	rspq->msgq = msgq;
49362306a36Sopenharmony_ci	bfa_fsm_set_state(rspq, rspq_sm_stopped);
49462306a36Sopenharmony_ci}
49562306a36Sopenharmony_ci
49662306a36Sopenharmony_cistatic void
49762306a36Sopenharmony_cibfa_msgq_init_rsp(struct bfa_msgq *msgq,
49862306a36Sopenharmony_ci		 struct bfi_mbmsg *mb)
49962306a36Sopenharmony_ci{
50062306a36Sopenharmony_ci	bfa_fsm_send_event(&msgq->cmdq, CMDQ_E_INIT_RESP);
50162306a36Sopenharmony_ci	bfa_fsm_send_event(&msgq->rspq, RSPQ_E_INIT_RESP);
50262306a36Sopenharmony_ci}
50362306a36Sopenharmony_ci
50462306a36Sopenharmony_cistatic void
50562306a36Sopenharmony_cibfa_msgq_init(void *arg)
50662306a36Sopenharmony_ci{
50762306a36Sopenharmony_ci	struct bfa_msgq *msgq = (struct bfa_msgq *)arg;
50862306a36Sopenharmony_ci	struct bfi_msgq_cfg_req *msgq_cfg =
50962306a36Sopenharmony_ci		(struct bfi_msgq_cfg_req *)&msgq->init_mb.msg[0];
51062306a36Sopenharmony_ci
51162306a36Sopenharmony_ci	memset(msgq_cfg, 0, sizeof(struct bfi_msgq_cfg_req));
51262306a36Sopenharmony_ci	bfi_h2i_set(msgq_cfg->mh, BFI_MC_MSGQ, BFI_MSGQ_H2I_INIT_REQ, 0);
51362306a36Sopenharmony_ci	msgq_cfg->mh.mtag.i2htok = 0;
51462306a36Sopenharmony_ci
51562306a36Sopenharmony_ci	bfa_dma_be_addr_set(msgq_cfg->cmdq.addr, msgq->cmdq.addr.pa);
51662306a36Sopenharmony_ci	msgq_cfg->cmdq.q_depth = htons(msgq->cmdq.depth);
51762306a36Sopenharmony_ci	bfa_dma_be_addr_set(msgq_cfg->rspq.addr, msgq->rspq.addr.pa);
51862306a36Sopenharmony_ci	msgq_cfg->rspq.q_depth = htons(msgq->rspq.depth);
51962306a36Sopenharmony_ci
52062306a36Sopenharmony_ci	bfa_nw_ioc_mbox_queue(msgq->ioc, &msgq->init_mb, NULL, NULL);
52162306a36Sopenharmony_ci}
52262306a36Sopenharmony_ci
52362306a36Sopenharmony_cistatic void
52462306a36Sopenharmony_cibfa_msgq_isr(void *cbarg, struct bfi_mbmsg *msg)
52562306a36Sopenharmony_ci{
52662306a36Sopenharmony_ci	struct bfa_msgq *msgq = (struct bfa_msgq *)cbarg;
52762306a36Sopenharmony_ci
52862306a36Sopenharmony_ci	switch (msg->mh.msg_id) {
52962306a36Sopenharmony_ci	case BFI_MSGQ_I2H_INIT_RSP:
53062306a36Sopenharmony_ci		bfa_msgq_init_rsp(msgq, msg);
53162306a36Sopenharmony_ci		break;
53262306a36Sopenharmony_ci
53362306a36Sopenharmony_ci	case BFI_MSGQ_I2H_DOORBELL_PI:
53462306a36Sopenharmony_ci		bfa_msgq_rspq_pi_update(&msgq->rspq, msg);
53562306a36Sopenharmony_ci		break;
53662306a36Sopenharmony_ci
53762306a36Sopenharmony_ci	case BFI_MSGQ_I2H_DOORBELL_CI:
53862306a36Sopenharmony_ci		bfa_msgq_cmdq_ci_update(&msgq->cmdq, msg);
53962306a36Sopenharmony_ci		break;
54062306a36Sopenharmony_ci
54162306a36Sopenharmony_ci	case BFI_MSGQ_I2H_CMDQ_COPY_REQ:
54262306a36Sopenharmony_ci		bfa_msgq_cmdq_copy_req(&msgq->cmdq, msg);
54362306a36Sopenharmony_ci		break;
54462306a36Sopenharmony_ci
54562306a36Sopenharmony_ci	default:
54662306a36Sopenharmony_ci		BUG_ON(1);
54762306a36Sopenharmony_ci	}
54862306a36Sopenharmony_ci}
54962306a36Sopenharmony_ci
55062306a36Sopenharmony_cistatic void
55162306a36Sopenharmony_cibfa_msgq_notify(void *cbarg, enum bfa_ioc_event event)
55262306a36Sopenharmony_ci{
55362306a36Sopenharmony_ci	struct bfa_msgq *msgq = (struct bfa_msgq *)cbarg;
55462306a36Sopenharmony_ci
55562306a36Sopenharmony_ci	switch (event) {
55662306a36Sopenharmony_ci	case BFA_IOC_E_ENABLED:
55762306a36Sopenharmony_ci		bfa_wc_init(&msgq->init_wc, bfa_msgq_init, msgq);
55862306a36Sopenharmony_ci		bfa_wc_up(&msgq->init_wc);
55962306a36Sopenharmony_ci		bfa_fsm_send_event(&msgq->cmdq, CMDQ_E_START);
56062306a36Sopenharmony_ci		bfa_wc_up(&msgq->init_wc);
56162306a36Sopenharmony_ci		bfa_fsm_send_event(&msgq->rspq, RSPQ_E_START);
56262306a36Sopenharmony_ci		bfa_wc_wait(&msgq->init_wc);
56362306a36Sopenharmony_ci		break;
56462306a36Sopenharmony_ci
56562306a36Sopenharmony_ci	case BFA_IOC_E_DISABLED:
56662306a36Sopenharmony_ci		bfa_fsm_send_event(&msgq->cmdq, CMDQ_E_STOP);
56762306a36Sopenharmony_ci		bfa_fsm_send_event(&msgq->rspq, RSPQ_E_STOP);
56862306a36Sopenharmony_ci		break;
56962306a36Sopenharmony_ci
57062306a36Sopenharmony_ci	case BFA_IOC_E_FAILED:
57162306a36Sopenharmony_ci		bfa_fsm_send_event(&msgq->cmdq, CMDQ_E_FAIL);
57262306a36Sopenharmony_ci		bfa_fsm_send_event(&msgq->rspq, RSPQ_E_FAIL);
57362306a36Sopenharmony_ci		break;
57462306a36Sopenharmony_ci
57562306a36Sopenharmony_ci	default:
57662306a36Sopenharmony_ci		break;
57762306a36Sopenharmony_ci	}
57862306a36Sopenharmony_ci}
57962306a36Sopenharmony_ci
58062306a36Sopenharmony_ciu32
58162306a36Sopenharmony_cibfa_msgq_meminfo(void)
58262306a36Sopenharmony_ci{
58362306a36Sopenharmony_ci	return roundup(BFA_MSGQ_CMDQ_SIZE, BFA_DMA_ALIGN_SZ) +
58462306a36Sopenharmony_ci		roundup(BFA_MSGQ_RSPQ_SIZE, BFA_DMA_ALIGN_SZ);
58562306a36Sopenharmony_ci}
58662306a36Sopenharmony_ci
58762306a36Sopenharmony_civoid
58862306a36Sopenharmony_cibfa_msgq_memclaim(struct bfa_msgq *msgq, u8 *kva, u64 pa)
58962306a36Sopenharmony_ci{
59062306a36Sopenharmony_ci	msgq->cmdq.addr.kva = kva;
59162306a36Sopenharmony_ci	msgq->cmdq.addr.pa  = pa;
59262306a36Sopenharmony_ci
59362306a36Sopenharmony_ci	kva += roundup(BFA_MSGQ_CMDQ_SIZE, BFA_DMA_ALIGN_SZ);
59462306a36Sopenharmony_ci	pa += roundup(BFA_MSGQ_CMDQ_SIZE, BFA_DMA_ALIGN_SZ);
59562306a36Sopenharmony_ci
59662306a36Sopenharmony_ci	msgq->rspq.addr.kva = kva;
59762306a36Sopenharmony_ci	msgq->rspq.addr.pa = pa;
59862306a36Sopenharmony_ci}
59962306a36Sopenharmony_ci
60062306a36Sopenharmony_civoid
60162306a36Sopenharmony_cibfa_msgq_attach(struct bfa_msgq *msgq, struct bfa_ioc *ioc)
60262306a36Sopenharmony_ci{
60362306a36Sopenharmony_ci	msgq->ioc    = ioc;
60462306a36Sopenharmony_ci
60562306a36Sopenharmony_ci	bfa_msgq_cmdq_attach(&msgq->cmdq, msgq);
60662306a36Sopenharmony_ci	bfa_msgq_rspq_attach(&msgq->rspq, msgq);
60762306a36Sopenharmony_ci
60862306a36Sopenharmony_ci	bfa_nw_ioc_mbox_regisr(msgq->ioc, BFI_MC_MSGQ, bfa_msgq_isr, msgq);
60962306a36Sopenharmony_ci	bfa_ioc_notify_init(&msgq->ioc_notify, bfa_msgq_notify, msgq);
61062306a36Sopenharmony_ci	bfa_nw_ioc_notify_register(msgq->ioc, &msgq->ioc_notify);
61162306a36Sopenharmony_ci}
61262306a36Sopenharmony_ci
61362306a36Sopenharmony_civoid
61462306a36Sopenharmony_cibfa_msgq_regisr(struct bfa_msgq *msgq, enum bfi_mclass mc,
61562306a36Sopenharmony_ci		bfa_msgq_mcfunc_t cbfn, void *cbarg)
61662306a36Sopenharmony_ci{
61762306a36Sopenharmony_ci	msgq->rspq.rsphdlr[mc].cbfn	= cbfn;
61862306a36Sopenharmony_ci	msgq->rspq.rsphdlr[mc].cbarg	= cbarg;
61962306a36Sopenharmony_ci}
62062306a36Sopenharmony_ci
62162306a36Sopenharmony_civoid
62262306a36Sopenharmony_cibfa_msgq_cmd_post(struct bfa_msgq *msgq,  struct bfa_msgq_cmd_entry *cmd)
62362306a36Sopenharmony_ci{
62462306a36Sopenharmony_ci	if (ntohs(cmd->msg_hdr->num_entries) <=
62562306a36Sopenharmony_ci		BFA_MSGQ_FREE_CNT(&msgq->cmdq)) {
62662306a36Sopenharmony_ci		__cmd_copy(&msgq->cmdq, cmd);
62762306a36Sopenharmony_ci		call_cmdq_ent_cbfn(cmd, BFA_STATUS_OK);
62862306a36Sopenharmony_ci		bfa_fsm_send_event(&msgq->cmdq, CMDQ_E_POST);
62962306a36Sopenharmony_ci	} else {
63062306a36Sopenharmony_ci		list_add_tail(&cmd->qe, &msgq->cmdq.pending_q);
63162306a36Sopenharmony_ci	}
63262306a36Sopenharmony_ci}
63362306a36Sopenharmony_ci
63462306a36Sopenharmony_civoid
63562306a36Sopenharmony_cibfa_msgq_rsp_copy(struct bfa_msgq *msgq, u8 *buf, size_t buf_len)
63662306a36Sopenharmony_ci{
63762306a36Sopenharmony_ci	struct bfa_msgq_rspq *rspq = &msgq->rspq;
63862306a36Sopenharmony_ci	size_t len = buf_len;
63962306a36Sopenharmony_ci	size_t to_copy;
64062306a36Sopenharmony_ci	int ci;
64162306a36Sopenharmony_ci	u8 *src, *dst;
64262306a36Sopenharmony_ci
64362306a36Sopenharmony_ci	ci = rspq->consumer_index;
64462306a36Sopenharmony_ci	src = (u8 *)rspq->addr.kva;
64562306a36Sopenharmony_ci	src += (ci * BFI_MSGQ_RSP_ENTRY_SIZE);
64662306a36Sopenharmony_ci	dst = buf;
64762306a36Sopenharmony_ci
64862306a36Sopenharmony_ci	while (len) {
64962306a36Sopenharmony_ci		to_copy = (len < BFI_MSGQ_RSP_ENTRY_SIZE) ?
65062306a36Sopenharmony_ci				len : BFI_MSGQ_RSP_ENTRY_SIZE;
65162306a36Sopenharmony_ci		memcpy(dst, src, to_copy);
65262306a36Sopenharmony_ci		len -= to_copy;
65362306a36Sopenharmony_ci		dst += BFI_MSGQ_RSP_ENTRY_SIZE;
65462306a36Sopenharmony_ci		BFA_MSGQ_INDX_ADD(ci, 1, rspq->depth);
65562306a36Sopenharmony_ci		src = (u8 *)rspq->addr.kva;
65662306a36Sopenharmony_ci		src += (ci * BFI_MSGQ_RSP_ENTRY_SIZE);
65762306a36Sopenharmony_ci	}
65862306a36Sopenharmony_ci}
659