162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright (C) 2016 Cavium, Inc. 462306a36Sopenharmony_ci */ 562306a36Sopenharmony_ci#include <linux/module.h> 662306a36Sopenharmony_ci#include "cptpf.h" 762306a36Sopenharmony_ci 862306a36Sopenharmony_cistatic void cpt_send_msg_to_vf(struct cpt_device *cpt, int vf, 962306a36Sopenharmony_ci struct cpt_mbox *mbx) 1062306a36Sopenharmony_ci{ 1162306a36Sopenharmony_ci /* Writing mbox(0) causes interrupt */ 1262306a36Sopenharmony_ci cpt_write_csr64(cpt->reg_base, CPTX_PF_VFX_MBOXX(0, vf, 1), 1362306a36Sopenharmony_ci mbx->data); 1462306a36Sopenharmony_ci cpt_write_csr64(cpt->reg_base, CPTX_PF_VFX_MBOXX(0, vf, 0), mbx->msg); 1562306a36Sopenharmony_ci} 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_ci/* ACKs VF's mailbox message 1862306a36Sopenharmony_ci * @vf: VF to which ACK to be sent 1962306a36Sopenharmony_ci */ 2062306a36Sopenharmony_cistatic void cpt_mbox_send_ack(struct cpt_device *cpt, int vf, 2162306a36Sopenharmony_ci struct cpt_mbox *mbx) 2262306a36Sopenharmony_ci{ 2362306a36Sopenharmony_ci mbx->data = 0ull; 2462306a36Sopenharmony_ci mbx->msg = CPT_MBOX_MSG_TYPE_ACK; 2562306a36Sopenharmony_ci cpt_send_msg_to_vf(cpt, vf, mbx); 2662306a36Sopenharmony_ci} 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_cistatic void cpt_clear_mbox_intr(struct cpt_device *cpt, u32 vf) 2962306a36Sopenharmony_ci{ 3062306a36Sopenharmony_ci /* W1C for the VF */ 3162306a36Sopenharmony_ci cpt_write_csr64(cpt->reg_base, CPTX_PF_MBOX_INTX(0, 0), (1 << vf)); 3262306a36Sopenharmony_ci} 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_ci/* 3562306a36Sopenharmony_ci * Configure QLEN/Chunk sizes for VF 3662306a36Sopenharmony_ci */ 3762306a36Sopenharmony_cistatic void cpt_cfg_qlen_for_vf(struct cpt_device *cpt, int vf, u32 size) 3862306a36Sopenharmony_ci{ 3962306a36Sopenharmony_ci union cptx_pf_qx_ctl pf_qx_ctl; 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_ci pf_qx_ctl.u = cpt_read_csr64(cpt->reg_base, CPTX_PF_QX_CTL(0, vf)); 4262306a36Sopenharmony_ci pf_qx_ctl.s.size = size; 4362306a36Sopenharmony_ci pf_qx_ctl.s.cont_err = true; 4462306a36Sopenharmony_ci cpt_write_csr64(cpt->reg_base, CPTX_PF_QX_CTL(0, vf), pf_qx_ctl.u); 4562306a36Sopenharmony_ci} 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_ci/* 4862306a36Sopenharmony_ci * Configure VQ priority 4962306a36Sopenharmony_ci */ 5062306a36Sopenharmony_cistatic void cpt_cfg_vq_priority(struct cpt_device *cpt, int vf, u32 pri) 5162306a36Sopenharmony_ci{ 5262306a36Sopenharmony_ci union cptx_pf_qx_ctl pf_qx_ctl; 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_ci pf_qx_ctl.u = cpt_read_csr64(cpt->reg_base, CPTX_PF_QX_CTL(0, vf)); 5562306a36Sopenharmony_ci pf_qx_ctl.s.pri = pri; 5662306a36Sopenharmony_ci cpt_write_csr64(cpt->reg_base, CPTX_PF_QX_CTL(0, vf), pf_qx_ctl.u); 5762306a36Sopenharmony_ci} 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_cistatic int cpt_bind_vq_to_grp(struct cpt_device *cpt, u8 q, u8 grp) 6062306a36Sopenharmony_ci{ 6162306a36Sopenharmony_ci struct microcode *mcode = cpt->mcode; 6262306a36Sopenharmony_ci union cptx_pf_qx_ctl pf_qx_ctl; 6362306a36Sopenharmony_ci struct device *dev = &cpt->pdev->dev; 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_ci if (q >= CPT_MAX_VF_NUM) { 6662306a36Sopenharmony_ci dev_err(dev, "Queues are more than cores in the group"); 6762306a36Sopenharmony_ci return -EINVAL; 6862306a36Sopenharmony_ci } 6962306a36Sopenharmony_ci if (grp >= CPT_MAX_CORE_GROUPS) { 7062306a36Sopenharmony_ci dev_err(dev, "Request group is more than possible groups"); 7162306a36Sopenharmony_ci return -EINVAL; 7262306a36Sopenharmony_ci } 7362306a36Sopenharmony_ci if (grp >= cpt->next_mc_idx) { 7462306a36Sopenharmony_ci dev_err(dev, "Request group is higher than available functional groups"); 7562306a36Sopenharmony_ci return -EINVAL; 7662306a36Sopenharmony_ci } 7762306a36Sopenharmony_ci pf_qx_ctl.u = cpt_read_csr64(cpt->reg_base, CPTX_PF_QX_CTL(0, q)); 7862306a36Sopenharmony_ci pf_qx_ctl.s.grp = mcode[grp].group; 7962306a36Sopenharmony_ci cpt_write_csr64(cpt->reg_base, CPTX_PF_QX_CTL(0, q), pf_qx_ctl.u); 8062306a36Sopenharmony_ci dev_dbg(dev, "VF %d TYPE %s", q, (mcode[grp].is_ae ? "AE" : "SE")); 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_ci return mcode[grp].is_ae ? AE_TYPES : SE_TYPES; 8362306a36Sopenharmony_ci} 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_ci/* Interrupt handler to handle mailbox messages from VFs */ 8662306a36Sopenharmony_cistatic void cpt_handle_mbox_intr(struct cpt_device *cpt, int vf) 8762306a36Sopenharmony_ci{ 8862306a36Sopenharmony_ci struct cpt_vf_info *vfx = &cpt->vfinfo[vf]; 8962306a36Sopenharmony_ci struct cpt_mbox mbx = {}; 9062306a36Sopenharmony_ci int vftype; 9162306a36Sopenharmony_ci struct device *dev = &cpt->pdev->dev; 9262306a36Sopenharmony_ci /* 9362306a36Sopenharmony_ci * MBOX[0] contains msg 9462306a36Sopenharmony_ci * MBOX[1] contains data 9562306a36Sopenharmony_ci */ 9662306a36Sopenharmony_ci mbx.msg = cpt_read_csr64(cpt->reg_base, CPTX_PF_VFX_MBOXX(0, vf, 0)); 9762306a36Sopenharmony_ci mbx.data = cpt_read_csr64(cpt->reg_base, CPTX_PF_VFX_MBOXX(0, vf, 1)); 9862306a36Sopenharmony_ci dev_dbg(dev, "%s: Mailbox msg 0x%llx from VF%d", __func__, mbx.msg, vf); 9962306a36Sopenharmony_ci switch (mbx.msg) { 10062306a36Sopenharmony_ci case CPT_MSG_VF_UP: 10162306a36Sopenharmony_ci vfx->state = VF_STATE_UP; 10262306a36Sopenharmony_ci try_module_get(THIS_MODULE); 10362306a36Sopenharmony_ci cpt_mbox_send_ack(cpt, vf, &mbx); 10462306a36Sopenharmony_ci break; 10562306a36Sopenharmony_ci case CPT_MSG_READY: 10662306a36Sopenharmony_ci mbx.msg = CPT_MSG_READY; 10762306a36Sopenharmony_ci mbx.data = vf; 10862306a36Sopenharmony_ci cpt_send_msg_to_vf(cpt, vf, &mbx); 10962306a36Sopenharmony_ci break; 11062306a36Sopenharmony_ci case CPT_MSG_VF_DOWN: 11162306a36Sopenharmony_ci /* First msg in VF teardown sequence */ 11262306a36Sopenharmony_ci vfx->state = VF_STATE_DOWN; 11362306a36Sopenharmony_ci module_put(THIS_MODULE); 11462306a36Sopenharmony_ci cpt_mbox_send_ack(cpt, vf, &mbx); 11562306a36Sopenharmony_ci break; 11662306a36Sopenharmony_ci case CPT_MSG_QLEN: 11762306a36Sopenharmony_ci vfx->qlen = mbx.data; 11862306a36Sopenharmony_ci cpt_cfg_qlen_for_vf(cpt, vf, vfx->qlen); 11962306a36Sopenharmony_ci cpt_mbox_send_ack(cpt, vf, &mbx); 12062306a36Sopenharmony_ci break; 12162306a36Sopenharmony_ci case CPT_MSG_QBIND_GRP: 12262306a36Sopenharmony_ci vftype = cpt_bind_vq_to_grp(cpt, vf, (u8)mbx.data); 12362306a36Sopenharmony_ci if ((vftype != AE_TYPES) && (vftype != SE_TYPES)) 12462306a36Sopenharmony_ci dev_err(dev, "Queue %d binding to group %llu failed", 12562306a36Sopenharmony_ci vf, mbx.data); 12662306a36Sopenharmony_ci else { 12762306a36Sopenharmony_ci dev_dbg(dev, "Queue %d binding to group %llu successful", 12862306a36Sopenharmony_ci vf, mbx.data); 12962306a36Sopenharmony_ci mbx.msg = CPT_MSG_QBIND_GRP; 13062306a36Sopenharmony_ci mbx.data = vftype; 13162306a36Sopenharmony_ci cpt_send_msg_to_vf(cpt, vf, &mbx); 13262306a36Sopenharmony_ci } 13362306a36Sopenharmony_ci break; 13462306a36Sopenharmony_ci case CPT_MSG_VQ_PRIORITY: 13562306a36Sopenharmony_ci vfx->priority = mbx.data; 13662306a36Sopenharmony_ci cpt_cfg_vq_priority(cpt, vf, vfx->priority); 13762306a36Sopenharmony_ci cpt_mbox_send_ack(cpt, vf, &mbx); 13862306a36Sopenharmony_ci break; 13962306a36Sopenharmony_ci default: 14062306a36Sopenharmony_ci dev_err(&cpt->pdev->dev, "Invalid msg from VF%d, msg 0x%llx\n", 14162306a36Sopenharmony_ci vf, mbx.msg); 14262306a36Sopenharmony_ci break; 14362306a36Sopenharmony_ci } 14462306a36Sopenharmony_ci} 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_civoid cpt_mbox_intr_handler (struct cpt_device *cpt, int mbx) 14762306a36Sopenharmony_ci{ 14862306a36Sopenharmony_ci u64 intr; 14962306a36Sopenharmony_ci u8 vf; 15062306a36Sopenharmony_ci 15162306a36Sopenharmony_ci intr = cpt_read_csr64(cpt->reg_base, CPTX_PF_MBOX_INTX(0, 0)); 15262306a36Sopenharmony_ci dev_dbg(&cpt->pdev->dev, "PF interrupt Mbox%d 0x%llx\n", mbx, intr); 15362306a36Sopenharmony_ci for (vf = 0; vf < CPT_MAX_VF_NUM; vf++) { 15462306a36Sopenharmony_ci if (intr & (1ULL << vf)) { 15562306a36Sopenharmony_ci dev_dbg(&cpt->pdev->dev, "Intr from VF %d\n", vf); 15662306a36Sopenharmony_ci cpt_handle_mbox_intr(cpt, vf); 15762306a36Sopenharmony_ci cpt_clear_mbox_intr(cpt, vf); 15862306a36Sopenharmony_ci } 15962306a36Sopenharmony_ci } 16062306a36Sopenharmony_ci} 161