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