18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright (C) 2016 Cavium, Inc. 48c2ecf20Sopenharmony_ci */ 58c2ecf20Sopenharmony_ci#include <linux/module.h> 68c2ecf20Sopenharmony_ci#include "cptpf.h" 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_cistatic void cpt_send_msg_to_vf(struct cpt_device *cpt, int vf, 98c2ecf20Sopenharmony_ci struct cpt_mbox *mbx) 108c2ecf20Sopenharmony_ci{ 118c2ecf20Sopenharmony_ci /* Writing mbox(0) causes interrupt */ 128c2ecf20Sopenharmony_ci cpt_write_csr64(cpt->reg_base, CPTX_PF_VFX_MBOXX(0, vf, 1), 138c2ecf20Sopenharmony_ci mbx->data); 148c2ecf20Sopenharmony_ci cpt_write_csr64(cpt->reg_base, CPTX_PF_VFX_MBOXX(0, vf, 0), mbx->msg); 158c2ecf20Sopenharmony_ci} 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_ci/* ACKs VF's mailbox message 188c2ecf20Sopenharmony_ci * @vf: VF to which ACK to be sent 198c2ecf20Sopenharmony_ci */ 208c2ecf20Sopenharmony_cistatic void cpt_mbox_send_ack(struct cpt_device *cpt, int vf, 218c2ecf20Sopenharmony_ci struct cpt_mbox *mbx) 228c2ecf20Sopenharmony_ci{ 238c2ecf20Sopenharmony_ci mbx->data = 0ull; 248c2ecf20Sopenharmony_ci mbx->msg = CPT_MBOX_MSG_TYPE_ACK; 258c2ecf20Sopenharmony_ci cpt_send_msg_to_vf(cpt, vf, mbx); 268c2ecf20Sopenharmony_ci} 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_cistatic void cpt_clear_mbox_intr(struct cpt_device *cpt, u32 vf) 298c2ecf20Sopenharmony_ci{ 308c2ecf20Sopenharmony_ci /* W1C for the VF */ 318c2ecf20Sopenharmony_ci cpt_write_csr64(cpt->reg_base, CPTX_PF_MBOX_INTX(0, 0), (1 << vf)); 328c2ecf20Sopenharmony_ci} 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_ci/* 358c2ecf20Sopenharmony_ci * Configure QLEN/Chunk sizes for VF 368c2ecf20Sopenharmony_ci */ 378c2ecf20Sopenharmony_cistatic void cpt_cfg_qlen_for_vf(struct cpt_device *cpt, int vf, u32 size) 388c2ecf20Sopenharmony_ci{ 398c2ecf20Sopenharmony_ci union cptx_pf_qx_ctl pf_qx_ctl; 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_ci pf_qx_ctl.u = cpt_read_csr64(cpt->reg_base, CPTX_PF_QX_CTL(0, vf)); 428c2ecf20Sopenharmony_ci pf_qx_ctl.s.size = size; 438c2ecf20Sopenharmony_ci pf_qx_ctl.s.cont_err = true; 448c2ecf20Sopenharmony_ci cpt_write_csr64(cpt->reg_base, CPTX_PF_QX_CTL(0, vf), pf_qx_ctl.u); 458c2ecf20Sopenharmony_ci} 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_ci/* 488c2ecf20Sopenharmony_ci * Configure VQ priority 498c2ecf20Sopenharmony_ci */ 508c2ecf20Sopenharmony_cistatic void cpt_cfg_vq_priority(struct cpt_device *cpt, int vf, u32 pri) 518c2ecf20Sopenharmony_ci{ 528c2ecf20Sopenharmony_ci union cptx_pf_qx_ctl pf_qx_ctl; 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_ci pf_qx_ctl.u = cpt_read_csr64(cpt->reg_base, CPTX_PF_QX_CTL(0, vf)); 558c2ecf20Sopenharmony_ci pf_qx_ctl.s.pri = pri; 568c2ecf20Sopenharmony_ci cpt_write_csr64(cpt->reg_base, CPTX_PF_QX_CTL(0, vf), pf_qx_ctl.u); 578c2ecf20Sopenharmony_ci} 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_cistatic int cpt_bind_vq_to_grp(struct cpt_device *cpt, u8 q, u8 grp) 608c2ecf20Sopenharmony_ci{ 618c2ecf20Sopenharmony_ci struct microcode *mcode = cpt->mcode; 628c2ecf20Sopenharmony_ci union cptx_pf_qx_ctl pf_qx_ctl; 638c2ecf20Sopenharmony_ci struct device *dev = &cpt->pdev->dev; 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_ci if (q >= CPT_MAX_VF_NUM) { 668c2ecf20Sopenharmony_ci dev_err(dev, "Queues are more than cores in the group"); 678c2ecf20Sopenharmony_ci return -EINVAL; 688c2ecf20Sopenharmony_ci } 698c2ecf20Sopenharmony_ci if (grp >= CPT_MAX_CORE_GROUPS) { 708c2ecf20Sopenharmony_ci dev_err(dev, "Request group is more than possible groups"); 718c2ecf20Sopenharmony_ci return -EINVAL; 728c2ecf20Sopenharmony_ci } 738c2ecf20Sopenharmony_ci if (grp >= cpt->next_mc_idx) { 748c2ecf20Sopenharmony_ci dev_err(dev, "Request group is higher than available functional groups"); 758c2ecf20Sopenharmony_ci return -EINVAL; 768c2ecf20Sopenharmony_ci } 778c2ecf20Sopenharmony_ci pf_qx_ctl.u = cpt_read_csr64(cpt->reg_base, CPTX_PF_QX_CTL(0, q)); 788c2ecf20Sopenharmony_ci pf_qx_ctl.s.grp = mcode[grp].group; 798c2ecf20Sopenharmony_ci cpt_write_csr64(cpt->reg_base, CPTX_PF_QX_CTL(0, q), pf_qx_ctl.u); 808c2ecf20Sopenharmony_ci dev_dbg(dev, "VF %d TYPE %s", q, (mcode[grp].is_ae ? "AE" : "SE")); 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_ci return mcode[grp].is_ae ? AE_TYPES : SE_TYPES; 838c2ecf20Sopenharmony_ci} 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_ci/* Interrupt handler to handle mailbox messages from VFs */ 868c2ecf20Sopenharmony_cistatic void cpt_handle_mbox_intr(struct cpt_device *cpt, int vf) 878c2ecf20Sopenharmony_ci{ 888c2ecf20Sopenharmony_ci struct cpt_vf_info *vfx = &cpt->vfinfo[vf]; 898c2ecf20Sopenharmony_ci struct cpt_mbox mbx = {}; 908c2ecf20Sopenharmony_ci int vftype; 918c2ecf20Sopenharmony_ci struct device *dev = &cpt->pdev->dev; 928c2ecf20Sopenharmony_ci /* 938c2ecf20Sopenharmony_ci * MBOX[0] contains msg 948c2ecf20Sopenharmony_ci * MBOX[1] contains data 958c2ecf20Sopenharmony_ci */ 968c2ecf20Sopenharmony_ci mbx.msg = cpt_read_csr64(cpt->reg_base, CPTX_PF_VFX_MBOXX(0, vf, 0)); 978c2ecf20Sopenharmony_ci mbx.data = cpt_read_csr64(cpt->reg_base, CPTX_PF_VFX_MBOXX(0, vf, 1)); 988c2ecf20Sopenharmony_ci dev_dbg(dev, "%s: Mailbox msg 0x%llx from VF%d", __func__, mbx.msg, vf); 998c2ecf20Sopenharmony_ci switch (mbx.msg) { 1008c2ecf20Sopenharmony_ci case CPT_MSG_VF_UP: 1018c2ecf20Sopenharmony_ci vfx->state = VF_STATE_UP; 1028c2ecf20Sopenharmony_ci try_module_get(THIS_MODULE); 1038c2ecf20Sopenharmony_ci cpt_mbox_send_ack(cpt, vf, &mbx); 1048c2ecf20Sopenharmony_ci break; 1058c2ecf20Sopenharmony_ci case CPT_MSG_READY: 1068c2ecf20Sopenharmony_ci mbx.msg = CPT_MSG_READY; 1078c2ecf20Sopenharmony_ci mbx.data = vf; 1088c2ecf20Sopenharmony_ci cpt_send_msg_to_vf(cpt, vf, &mbx); 1098c2ecf20Sopenharmony_ci break; 1108c2ecf20Sopenharmony_ci case CPT_MSG_VF_DOWN: 1118c2ecf20Sopenharmony_ci /* First msg in VF teardown sequence */ 1128c2ecf20Sopenharmony_ci vfx->state = VF_STATE_DOWN; 1138c2ecf20Sopenharmony_ci module_put(THIS_MODULE); 1148c2ecf20Sopenharmony_ci cpt_mbox_send_ack(cpt, vf, &mbx); 1158c2ecf20Sopenharmony_ci break; 1168c2ecf20Sopenharmony_ci case CPT_MSG_QLEN: 1178c2ecf20Sopenharmony_ci vfx->qlen = mbx.data; 1188c2ecf20Sopenharmony_ci cpt_cfg_qlen_for_vf(cpt, vf, vfx->qlen); 1198c2ecf20Sopenharmony_ci cpt_mbox_send_ack(cpt, vf, &mbx); 1208c2ecf20Sopenharmony_ci break; 1218c2ecf20Sopenharmony_ci case CPT_MSG_QBIND_GRP: 1228c2ecf20Sopenharmony_ci vftype = cpt_bind_vq_to_grp(cpt, vf, (u8)mbx.data); 1238c2ecf20Sopenharmony_ci if ((vftype != AE_TYPES) && (vftype != SE_TYPES)) 1248c2ecf20Sopenharmony_ci dev_err(dev, "Queue %d binding to group %llu failed", 1258c2ecf20Sopenharmony_ci vf, mbx.data); 1268c2ecf20Sopenharmony_ci else { 1278c2ecf20Sopenharmony_ci dev_dbg(dev, "Queue %d binding to group %llu successful", 1288c2ecf20Sopenharmony_ci vf, mbx.data); 1298c2ecf20Sopenharmony_ci mbx.msg = CPT_MSG_QBIND_GRP; 1308c2ecf20Sopenharmony_ci mbx.data = vftype; 1318c2ecf20Sopenharmony_ci cpt_send_msg_to_vf(cpt, vf, &mbx); 1328c2ecf20Sopenharmony_ci } 1338c2ecf20Sopenharmony_ci break; 1348c2ecf20Sopenharmony_ci case CPT_MSG_VQ_PRIORITY: 1358c2ecf20Sopenharmony_ci vfx->priority = mbx.data; 1368c2ecf20Sopenharmony_ci cpt_cfg_vq_priority(cpt, vf, vfx->priority); 1378c2ecf20Sopenharmony_ci cpt_mbox_send_ack(cpt, vf, &mbx); 1388c2ecf20Sopenharmony_ci break; 1398c2ecf20Sopenharmony_ci default: 1408c2ecf20Sopenharmony_ci dev_err(&cpt->pdev->dev, "Invalid msg from VF%d, msg 0x%llx\n", 1418c2ecf20Sopenharmony_ci vf, mbx.msg); 1428c2ecf20Sopenharmony_ci break; 1438c2ecf20Sopenharmony_ci } 1448c2ecf20Sopenharmony_ci} 1458c2ecf20Sopenharmony_ci 1468c2ecf20Sopenharmony_civoid cpt_mbox_intr_handler (struct cpt_device *cpt, int mbx) 1478c2ecf20Sopenharmony_ci{ 1488c2ecf20Sopenharmony_ci u64 intr; 1498c2ecf20Sopenharmony_ci u8 vf; 1508c2ecf20Sopenharmony_ci 1518c2ecf20Sopenharmony_ci intr = cpt_read_csr64(cpt->reg_base, CPTX_PF_MBOX_INTX(0, 0)); 1528c2ecf20Sopenharmony_ci dev_dbg(&cpt->pdev->dev, "PF interrupt Mbox%d 0x%llx\n", mbx, intr); 1538c2ecf20Sopenharmony_ci for (vf = 0; vf < CPT_MAX_VF_NUM; vf++) { 1548c2ecf20Sopenharmony_ci if (intr & (1ULL << vf)) { 1558c2ecf20Sopenharmony_ci dev_dbg(&cpt->pdev->dev, "Intr from VF %d\n", vf); 1568c2ecf20Sopenharmony_ci cpt_handle_mbox_intr(cpt, vf); 1578c2ecf20Sopenharmony_ci cpt_clear_mbox_intr(cpt, vf); 1588c2ecf20Sopenharmony_ci } 1598c2ecf20Sopenharmony_ci } 1608c2ecf20Sopenharmony_ci} 161