162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* Marvell OcteonTX CPT driver 362306a36Sopenharmony_ci * 462306a36Sopenharmony_ci * Copyright (C) 2019 Marvell International Ltd. 562306a36Sopenharmony_ci * 662306a36Sopenharmony_ci * This program is free software; you can redistribute it and/or modify 762306a36Sopenharmony_ci * it under the terms of the GNU General Public License version 2 as 862306a36Sopenharmony_ci * published by the Free Software Foundation. 962306a36Sopenharmony_ci */ 1062306a36Sopenharmony_ci 1162306a36Sopenharmony_ci#include "otx_cpt_common.h" 1262306a36Sopenharmony_ci#include "otx_cptpf.h" 1362306a36Sopenharmony_ci 1462306a36Sopenharmony_cistatic char *get_mbox_opcode_str(int msg_opcode) 1562306a36Sopenharmony_ci{ 1662306a36Sopenharmony_ci char *str = "Unknown"; 1762306a36Sopenharmony_ci 1862306a36Sopenharmony_ci switch (msg_opcode) { 1962306a36Sopenharmony_ci case OTX_CPT_MSG_VF_UP: 2062306a36Sopenharmony_ci str = "UP"; 2162306a36Sopenharmony_ci break; 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_ci case OTX_CPT_MSG_VF_DOWN: 2462306a36Sopenharmony_ci str = "DOWN"; 2562306a36Sopenharmony_ci break; 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_ci case OTX_CPT_MSG_READY: 2862306a36Sopenharmony_ci str = "READY"; 2962306a36Sopenharmony_ci break; 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_ci case OTX_CPT_MSG_QLEN: 3262306a36Sopenharmony_ci str = "QLEN"; 3362306a36Sopenharmony_ci break; 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_ci case OTX_CPT_MSG_QBIND_GRP: 3662306a36Sopenharmony_ci str = "QBIND_GRP"; 3762306a36Sopenharmony_ci break; 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_ci case OTX_CPT_MSG_VQ_PRIORITY: 4062306a36Sopenharmony_ci str = "VQ_PRIORITY"; 4162306a36Sopenharmony_ci break; 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_ci case OTX_CPT_MSG_PF_TYPE: 4462306a36Sopenharmony_ci str = "PF_TYPE"; 4562306a36Sopenharmony_ci break; 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_ci case OTX_CPT_MSG_ACK: 4862306a36Sopenharmony_ci str = "ACK"; 4962306a36Sopenharmony_ci break; 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_ci case OTX_CPT_MSG_NACK: 5262306a36Sopenharmony_ci str = "NACK"; 5362306a36Sopenharmony_ci break; 5462306a36Sopenharmony_ci } 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_ci return str; 5762306a36Sopenharmony_ci} 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_cistatic void dump_mbox_msg(struct otx_cpt_mbox *mbox_msg, int vf_id) 6062306a36Sopenharmony_ci{ 6162306a36Sopenharmony_ci char raw_data_str[OTX_CPT_MAX_MBOX_DATA_STR_SIZE]; 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_ci hex_dump_to_buffer(mbox_msg, sizeof(struct otx_cpt_mbox), 16, 8, 6462306a36Sopenharmony_ci raw_data_str, OTX_CPT_MAX_MBOX_DATA_STR_SIZE, false); 6562306a36Sopenharmony_ci if (vf_id >= 0) 6662306a36Sopenharmony_ci pr_debug("MBOX opcode %s received from VF%d raw_data %s\n", 6762306a36Sopenharmony_ci get_mbox_opcode_str(mbox_msg->msg), vf_id, 6862306a36Sopenharmony_ci raw_data_str); 6962306a36Sopenharmony_ci else 7062306a36Sopenharmony_ci pr_debug("MBOX opcode %s received from PF raw_data %s\n", 7162306a36Sopenharmony_ci get_mbox_opcode_str(mbox_msg->msg), raw_data_str); 7262306a36Sopenharmony_ci} 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_cistatic void otx_cpt_send_msg_to_vf(struct otx_cpt_device *cpt, int vf, 7562306a36Sopenharmony_ci struct otx_cpt_mbox *mbx) 7662306a36Sopenharmony_ci{ 7762306a36Sopenharmony_ci /* Writing mbox(0) causes interrupt */ 7862306a36Sopenharmony_ci writeq(mbx->data, cpt->reg_base + OTX_CPT_PF_VFX_MBOXX(vf, 1)); 7962306a36Sopenharmony_ci writeq(mbx->msg, cpt->reg_base + OTX_CPT_PF_VFX_MBOXX(vf, 0)); 8062306a36Sopenharmony_ci} 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_ci/* 8362306a36Sopenharmony_ci * ACKs VF's mailbox message 8462306a36Sopenharmony_ci * @vf: VF to which ACK to be sent 8562306a36Sopenharmony_ci */ 8662306a36Sopenharmony_cistatic void otx_cpt_mbox_send_ack(struct otx_cpt_device *cpt, int vf, 8762306a36Sopenharmony_ci struct otx_cpt_mbox *mbx) 8862306a36Sopenharmony_ci{ 8962306a36Sopenharmony_ci mbx->data = 0ull; 9062306a36Sopenharmony_ci mbx->msg = OTX_CPT_MSG_ACK; 9162306a36Sopenharmony_ci otx_cpt_send_msg_to_vf(cpt, vf, mbx); 9262306a36Sopenharmony_ci} 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_ci/* NACKs VF's mailbox message that PF is not able to complete the action */ 9562306a36Sopenharmony_cistatic void otx_cptpf_mbox_send_nack(struct otx_cpt_device *cpt, int vf, 9662306a36Sopenharmony_ci struct otx_cpt_mbox *mbx) 9762306a36Sopenharmony_ci{ 9862306a36Sopenharmony_ci mbx->data = 0ull; 9962306a36Sopenharmony_ci mbx->msg = OTX_CPT_MSG_NACK; 10062306a36Sopenharmony_ci otx_cpt_send_msg_to_vf(cpt, vf, mbx); 10162306a36Sopenharmony_ci} 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_cistatic void otx_cpt_clear_mbox_intr(struct otx_cpt_device *cpt, u32 vf) 10462306a36Sopenharmony_ci{ 10562306a36Sopenharmony_ci /* W1C for the VF */ 10662306a36Sopenharmony_ci writeq(1ull << vf, cpt->reg_base + OTX_CPT_PF_MBOX_INTX(0)); 10762306a36Sopenharmony_ci} 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_ci/* 11062306a36Sopenharmony_ci * Configure QLEN/Chunk sizes for VF 11162306a36Sopenharmony_ci */ 11262306a36Sopenharmony_cistatic void otx_cpt_cfg_qlen_for_vf(struct otx_cpt_device *cpt, int vf, 11362306a36Sopenharmony_ci u32 size) 11462306a36Sopenharmony_ci{ 11562306a36Sopenharmony_ci union otx_cptx_pf_qx_ctl pf_qx_ctl; 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_ci pf_qx_ctl.u = readq(cpt->reg_base + OTX_CPT_PF_QX_CTL(vf)); 11862306a36Sopenharmony_ci pf_qx_ctl.s.size = size; 11962306a36Sopenharmony_ci pf_qx_ctl.s.cont_err = true; 12062306a36Sopenharmony_ci writeq(pf_qx_ctl.u, cpt->reg_base + OTX_CPT_PF_QX_CTL(vf)); 12162306a36Sopenharmony_ci} 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_ci/* 12462306a36Sopenharmony_ci * Configure VQ priority 12562306a36Sopenharmony_ci */ 12662306a36Sopenharmony_cistatic void otx_cpt_cfg_vq_priority(struct otx_cpt_device *cpt, int vf, u32 pri) 12762306a36Sopenharmony_ci{ 12862306a36Sopenharmony_ci union otx_cptx_pf_qx_ctl pf_qx_ctl; 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_ci pf_qx_ctl.u = readq(cpt->reg_base + OTX_CPT_PF_QX_CTL(vf)); 13162306a36Sopenharmony_ci pf_qx_ctl.s.pri = pri; 13262306a36Sopenharmony_ci writeq(pf_qx_ctl.u, cpt->reg_base + OTX_CPT_PF_QX_CTL(vf)); 13362306a36Sopenharmony_ci} 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_cistatic int otx_cpt_bind_vq_to_grp(struct otx_cpt_device *cpt, u8 q, u8 grp) 13662306a36Sopenharmony_ci{ 13762306a36Sopenharmony_ci struct device *dev = &cpt->pdev->dev; 13862306a36Sopenharmony_ci struct otx_cpt_eng_grp_info *eng_grp; 13962306a36Sopenharmony_ci union otx_cptx_pf_qx_ctl pf_qx_ctl; 14062306a36Sopenharmony_ci struct otx_cpt_ucode *ucode; 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_ci if (q >= cpt->max_vfs) { 14362306a36Sopenharmony_ci dev_err(dev, "Requested queue %d is > than maximum avail %d\n", 14462306a36Sopenharmony_ci q, cpt->max_vfs); 14562306a36Sopenharmony_ci return -EINVAL; 14662306a36Sopenharmony_ci } 14762306a36Sopenharmony_ci 14862306a36Sopenharmony_ci if (grp >= OTX_CPT_MAX_ENGINE_GROUPS) { 14962306a36Sopenharmony_ci dev_err(dev, "Requested group %d is > than maximum avail %d\n", 15062306a36Sopenharmony_ci grp, OTX_CPT_MAX_ENGINE_GROUPS); 15162306a36Sopenharmony_ci return -EINVAL; 15262306a36Sopenharmony_ci } 15362306a36Sopenharmony_ci 15462306a36Sopenharmony_ci eng_grp = &cpt->eng_grps.grp[grp]; 15562306a36Sopenharmony_ci if (!eng_grp->is_enabled) { 15662306a36Sopenharmony_ci dev_err(dev, "Requested engine group %d is disabled\n", grp); 15762306a36Sopenharmony_ci return -EINVAL; 15862306a36Sopenharmony_ci } 15962306a36Sopenharmony_ci 16062306a36Sopenharmony_ci pf_qx_ctl.u = readq(cpt->reg_base + OTX_CPT_PF_QX_CTL(q)); 16162306a36Sopenharmony_ci pf_qx_ctl.s.grp = grp; 16262306a36Sopenharmony_ci writeq(pf_qx_ctl.u, cpt->reg_base + OTX_CPT_PF_QX_CTL(q)); 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_ci if (eng_grp->mirror.is_ena) 16562306a36Sopenharmony_ci ucode = &eng_grp->g->grp[eng_grp->mirror.idx].ucode[0]; 16662306a36Sopenharmony_ci else 16762306a36Sopenharmony_ci ucode = &eng_grp->ucode[0]; 16862306a36Sopenharmony_ci 16962306a36Sopenharmony_ci if (otx_cpt_uc_supports_eng_type(ucode, OTX_CPT_SE_TYPES)) 17062306a36Sopenharmony_ci return OTX_CPT_SE_TYPES; 17162306a36Sopenharmony_ci else if (otx_cpt_uc_supports_eng_type(ucode, OTX_CPT_AE_TYPES)) 17262306a36Sopenharmony_ci return OTX_CPT_AE_TYPES; 17362306a36Sopenharmony_ci else 17462306a36Sopenharmony_ci return BAD_OTX_CPTVF_TYPE; 17562306a36Sopenharmony_ci} 17662306a36Sopenharmony_ci 17762306a36Sopenharmony_ci/* Interrupt handler to handle mailbox messages from VFs */ 17862306a36Sopenharmony_cistatic void otx_cpt_handle_mbox_intr(struct otx_cpt_device *cpt, int vf) 17962306a36Sopenharmony_ci{ 18062306a36Sopenharmony_ci int vftype = 0; 18162306a36Sopenharmony_ci struct otx_cpt_mbox mbx = {}; 18262306a36Sopenharmony_ci struct device *dev = &cpt->pdev->dev; 18362306a36Sopenharmony_ci /* 18462306a36Sopenharmony_ci * MBOX[0] contains msg 18562306a36Sopenharmony_ci * MBOX[1] contains data 18662306a36Sopenharmony_ci */ 18762306a36Sopenharmony_ci mbx.msg = readq(cpt->reg_base + OTX_CPT_PF_VFX_MBOXX(vf, 0)); 18862306a36Sopenharmony_ci mbx.data = readq(cpt->reg_base + OTX_CPT_PF_VFX_MBOXX(vf, 1)); 18962306a36Sopenharmony_ci 19062306a36Sopenharmony_ci dump_mbox_msg(&mbx, vf); 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_ci switch (mbx.msg) { 19362306a36Sopenharmony_ci case OTX_CPT_MSG_VF_UP: 19462306a36Sopenharmony_ci mbx.msg = OTX_CPT_MSG_VF_UP; 19562306a36Sopenharmony_ci mbx.data = cpt->vfs_enabled; 19662306a36Sopenharmony_ci otx_cpt_send_msg_to_vf(cpt, vf, &mbx); 19762306a36Sopenharmony_ci break; 19862306a36Sopenharmony_ci case OTX_CPT_MSG_READY: 19962306a36Sopenharmony_ci mbx.msg = OTX_CPT_MSG_READY; 20062306a36Sopenharmony_ci mbx.data = vf; 20162306a36Sopenharmony_ci otx_cpt_send_msg_to_vf(cpt, vf, &mbx); 20262306a36Sopenharmony_ci break; 20362306a36Sopenharmony_ci case OTX_CPT_MSG_VF_DOWN: 20462306a36Sopenharmony_ci /* First msg in VF teardown sequence */ 20562306a36Sopenharmony_ci otx_cpt_mbox_send_ack(cpt, vf, &mbx); 20662306a36Sopenharmony_ci break; 20762306a36Sopenharmony_ci case OTX_CPT_MSG_QLEN: 20862306a36Sopenharmony_ci otx_cpt_cfg_qlen_for_vf(cpt, vf, mbx.data); 20962306a36Sopenharmony_ci otx_cpt_mbox_send_ack(cpt, vf, &mbx); 21062306a36Sopenharmony_ci break; 21162306a36Sopenharmony_ci case OTX_CPT_MSG_QBIND_GRP: 21262306a36Sopenharmony_ci vftype = otx_cpt_bind_vq_to_grp(cpt, vf, (u8)mbx.data); 21362306a36Sopenharmony_ci if ((vftype != OTX_CPT_AE_TYPES) && 21462306a36Sopenharmony_ci (vftype != OTX_CPT_SE_TYPES)) { 21562306a36Sopenharmony_ci dev_err(dev, "VF%d binding to eng group %llu failed\n", 21662306a36Sopenharmony_ci vf, mbx.data); 21762306a36Sopenharmony_ci otx_cptpf_mbox_send_nack(cpt, vf, &mbx); 21862306a36Sopenharmony_ci } else { 21962306a36Sopenharmony_ci mbx.msg = OTX_CPT_MSG_QBIND_GRP; 22062306a36Sopenharmony_ci mbx.data = vftype; 22162306a36Sopenharmony_ci otx_cpt_send_msg_to_vf(cpt, vf, &mbx); 22262306a36Sopenharmony_ci } 22362306a36Sopenharmony_ci break; 22462306a36Sopenharmony_ci case OTX_CPT_MSG_PF_TYPE: 22562306a36Sopenharmony_ci mbx.msg = OTX_CPT_MSG_PF_TYPE; 22662306a36Sopenharmony_ci mbx.data = cpt->pf_type; 22762306a36Sopenharmony_ci otx_cpt_send_msg_to_vf(cpt, vf, &mbx); 22862306a36Sopenharmony_ci break; 22962306a36Sopenharmony_ci case OTX_CPT_MSG_VQ_PRIORITY: 23062306a36Sopenharmony_ci otx_cpt_cfg_vq_priority(cpt, vf, mbx.data); 23162306a36Sopenharmony_ci otx_cpt_mbox_send_ack(cpt, vf, &mbx); 23262306a36Sopenharmony_ci break; 23362306a36Sopenharmony_ci default: 23462306a36Sopenharmony_ci dev_err(&cpt->pdev->dev, "Invalid msg from VF%d, msg 0x%llx\n", 23562306a36Sopenharmony_ci vf, mbx.msg); 23662306a36Sopenharmony_ci break; 23762306a36Sopenharmony_ci } 23862306a36Sopenharmony_ci} 23962306a36Sopenharmony_ci 24062306a36Sopenharmony_civoid otx_cpt_mbox_intr_handler (struct otx_cpt_device *cpt, int mbx) 24162306a36Sopenharmony_ci{ 24262306a36Sopenharmony_ci u64 intr; 24362306a36Sopenharmony_ci u8 vf; 24462306a36Sopenharmony_ci 24562306a36Sopenharmony_ci intr = readq(cpt->reg_base + OTX_CPT_PF_MBOX_INTX(0)); 24662306a36Sopenharmony_ci pr_debug("PF interrupt mbox%d mask 0x%llx\n", mbx, intr); 24762306a36Sopenharmony_ci for (vf = 0; vf < cpt->max_vfs; vf++) { 24862306a36Sopenharmony_ci if (intr & (1ULL << vf)) { 24962306a36Sopenharmony_ci otx_cpt_handle_mbox_intr(cpt, vf); 25062306a36Sopenharmony_ci otx_cpt_clear_mbox_intr(cpt, vf); 25162306a36Sopenharmony_ci } 25262306a36Sopenharmony_ci } 25362306a36Sopenharmony_ci} 254