18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* Marvell OcteonTX CPT driver 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * Copyright (C) 2019 Marvell International Ltd. 58c2ecf20Sopenharmony_ci * 68c2ecf20Sopenharmony_ci * This program is free software; you can redistribute it and/or modify 78c2ecf20Sopenharmony_ci * it under the terms of the GNU General Public License version 2 as 88c2ecf20Sopenharmony_ci * published by the Free Software Foundation. 98c2ecf20Sopenharmony_ci */ 108c2ecf20Sopenharmony_ci 118c2ecf20Sopenharmony_ci#include "otx_cpt_common.h" 128c2ecf20Sopenharmony_ci#include "otx_cptpf.h" 138c2ecf20Sopenharmony_ci 148c2ecf20Sopenharmony_cistatic char *get_mbox_opcode_str(int msg_opcode) 158c2ecf20Sopenharmony_ci{ 168c2ecf20Sopenharmony_ci char *str = "Unknown"; 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_ci switch (msg_opcode) { 198c2ecf20Sopenharmony_ci case OTX_CPT_MSG_VF_UP: 208c2ecf20Sopenharmony_ci str = "UP"; 218c2ecf20Sopenharmony_ci break; 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_ci case OTX_CPT_MSG_VF_DOWN: 248c2ecf20Sopenharmony_ci str = "DOWN"; 258c2ecf20Sopenharmony_ci break; 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_ci case OTX_CPT_MSG_READY: 288c2ecf20Sopenharmony_ci str = "READY"; 298c2ecf20Sopenharmony_ci break; 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ci case OTX_CPT_MSG_QLEN: 328c2ecf20Sopenharmony_ci str = "QLEN"; 338c2ecf20Sopenharmony_ci break; 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_ci case OTX_CPT_MSG_QBIND_GRP: 368c2ecf20Sopenharmony_ci str = "QBIND_GRP"; 378c2ecf20Sopenharmony_ci break; 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_ci case OTX_CPT_MSG_VQ_PRIORITY: 408c2ecf20Sopenharmony_ci str = "VQ_PRIORITY"; 418c2ecf20Sopenharmony_ci break; 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_ci case OTX_CPT_MSG_PF_TYPE: 448c2ecf20Sopenharmony_ci str = "PF_TYPE"; 458c2ecf20Sopenharmony_ci break; 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_ci case OTX_CPT_MSG_ACK: 488c2ecf20Sopenharmony_ci str = "ACK"; 498c2ecf20Sopenharmony_ci break; 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_ci case OTX_CPT_MSG_NACK: 528c2ecf20Sopenharmony_ci str = "NACK"; 538c2ecf20Sopenharmony_ci break; 548c2ecf20Sopenharmony_ci } 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_ci return str; 578c2ecf20Sopenharmony_ci} 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_cistatic void dump_mbox_msg(struct otx_cpt_mbox *mbox_msg, int vf_id) 608c2ecf20Sopenharmony_ci{ 618c2ecf20Sopenharmony_ci char raw_data_str[OTX_CPT_MAX_MBOX_DATA_STR_SIZE]; 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_ci hex_dump_to_buffer(mbox_msg, sizeof(struct otx_cpt_mbox), 16, 8, 648c2ecf20Sopenharmony_ci raw_data_str, OTX_CPT_MAX_MBOX_DATA_STR_SIZE, false); 658c2ecf20Sopenharmony_ci if (vf_id >= 0) 668c2ecf20Sopenharmony_ci pr_debug("MBOX opcode %s received from VF%d raw_data %s\n", 678c2ecf20Sopenharmony_ci get_mbox_opcode_str(mbox_msg->msg), vf_id, 688c2ecf20Sopenharmony_ci raw_data_str); 698c2ecf20Sopenharmony_ci else 708c2ecf20Sopenharmony_ci pr_debug("MBOX opcode %s received from PF raw_data %s\n", 718c2ecf20Sopenharmony_ci get_mbox_opcode_str(mbox_msg->msg), raw_data_str); 728c2ecf20Sopenharmony_ci} 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_cistatic void otx_cpt_send_msg_to_vf(struct otx_cpt_device *cpt, int vf, 758c2ecf20Sopenharmony_ci struct otx_cpt_mbox *mbx) 768c2ecf20Sopenharmony_ci{ 778c2ecf20Sopenharmony_ci /* Writing mbox(0) causes interrupt */ 788c2ecf20Sopenharmony_ci writeq(mbx->data, cpt->reg_base + OTX_CPT_PF_VFX_MBOXX(vf, 1)); 798c2ecf20Sopenharmony_ci writeq(mbx->msg, cpt->reg_base + OTX_CPT_PF_VFX_MBOXX(vf, 0)); 808c2ecf20Sopenharmony_ci} 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_ci/* 838c2ecf20Sopenharmony_ci * ACKs VF's mailbox message 848c2ecf20Sopenharmony_ci * @vf: VF to which ACK to be sent 858c2ecf20Sopenharmony_ci */ 868c2ecf20Sopenharmony_cistatic void otx_cpt_mbox_send_ack(struct otx_cpt_device *cpt, int vf, 878c2ecf20Sopenharmony_ci struct otx_cpt_mbox *mbx) 888c2ecf20Sopenharmony_ci{ 898c2ecf20Sopenharmony_ci mbx->data = 0ull; 908c2ecf20Sopenharmony_ci mbx->msg = OTX_CPT_MSG_ACK; 918c2ecf20Sopenharmony_ci otx_cpt_send_msg_to_vf(cpt, vf, mbx); 928c2ecf20Sopenharmony_ci} 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_ci/* NACKs VF's mailbox message that PF is not able to complete the action */ 958c2ecf20Sopenharmony_cistatic void otx_cptpf_mbox_send_nack(struct otx_cpt_device *cpt, int vf, 968c2ecf20Sopenharmony_ci struct otx_cpt_mbox *mbx) 978c2ecf20Sopenharmony_ci{ 988c2ecf20Sopenharmony_ci mbx->data = 0ull; 998c2ecf20Sopenharmony_ci mbx->msg = OTX_CPT_MSG_NACK; 1008c2ecf20Sopenharmony_ci otx_cpt_send_msg_to_vf(cpt, vf, mbx); 1018c2ecf20Sopenharmony_ci} 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_cistatic void otx_cpt_clear_mbox_intr(struct otx_cpt_device *cpt, u32 vf) 1048c2ecf20Sopenharmony_ci{ 1058c2ecf20Sopenharmony_ci /* W1C for the VF */ 1068c2ecf20Sopenharmony_ci writeq(1ull << vf, cpt->reg_base + OTX_CPT_PF_MBOX_INTX(0)); 1078c2ecf20Sopenharmony_ci} 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_ci/* 1108c2ecf20Sopenharmony_ci * Configure QLEN/Chunk sizes for VF 1118c2ecf20Sopenharmony_ci */ 1128c2ecf20Sopenharmony_cistatic void otx_cpt_cfg_qlen_for_vf(struct otx_cpt_device *cpt, int vf, 1138c2ecf20Sopenharmony_ci u32 size) 1148c2ecf20Sopenharmony_ci{ 1158c2ecf20Sopenharmony_ci union otx_cptx_pf_qx_ctl pf_qx_ctl; 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_ci pf_qx_ctl.u = readq(cpt->reg_base + OTX_CPT_PF_QX_CTL(vf)); 1188c2ecf20Sopenharmony_ci pf_qx_ctl.s.size = size; 1198c2ecf20Sopenharmony_ci pf_qx_ctl.s.cont_err = true; 1208c2ecf20Sopenharmony_ci writeq(pf_qx_ctl.u, cpt->reg_base + OTX_CPT_PF_QX_CTL(vf)); 1218c2ecf20Sopenharmony_ci} 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_ci/* 1248c2ecf20Sopenharmony_ci * Configure VQ priority 1258c2ecf20Sopenharmony_ci */ 1268c2ecf20Sopenharmony_cistatic void otx_cpt_cfg_vq_priority(struct otx_cpt_device *cpt, int vf, u32 pri) 1278c2ecf20Sopenharmony_ci{ 1288c2ecf20Sopenharmony_ci union otx_cptx_pf_qx_ctl pf_qx_ctl; 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_ci pf_qx_ctl.u = readq(cpt->reg_base + OTX_CPT_PF_QX_CTL(vf)); 1318c2ecf20Sopenharmony_ci pf_qx_ctl.s.pri = pri; 1328c2ecf20Sopenharmony_ci writeq(pf_qx_ctl.u, cpt->reg_base + OTX_CPT_PF_QX_CTL(vf)); 1338c2ecf20Sopenharmony_ci} 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_cistatic int otx_cpt_bind_vq_to_grp(struct otx_cpt_device *cpt, u8 q, u8 grp) 1368c2ecf20Sopenharmony_ci{ 1378c2ecf20Sopenharmony_ci struct device *dev = &cpt->pdev->dev; 1388c2ecf20Sopenharmony_ci struct otx_cpt_eng_grp_info *eng_grp; 1398c2ecf20Sopenharmony_ci union otx_cptx_pf_qx_ctl pf_qx_ctl; 1408c2ecf20Sopenharmony_ci struct otx_cpt_ucode *ucode; 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_ci if (q >= cpt->max_vfs) { 1438c2ecf20Sopenharmony_ci dev_err(dev, "Requested queue %d is > than maximum avail %d\n", 1448c2ecf20Sopenharmony_ci q, cpt->max_vfs); 1458c2ecf20Sopenharmony_ci return -EINVAL; 1468c2ecf20Sopenharmony_ci } 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_ci if (grp >= OTX_CPT_MAX_ENGINE_GROUPS) { 1498c2ecf20Sopenharmony_ci dev_err(dev, "Requested group %d is > than maximum avail %d\n", 1508c2ecf20Sopenharmony_ci grp, OTX_CPT_MAX_ENGINE_GROUPS); 1518c2ecf20Sopenharmony_ci return -EINVAL; 1528c2ecf20Sopenharmony_ci } 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_ci eng_grp = &cpt->eng_grps.grp[grp]; 1558c2ecf20Sopenharmony_ci if (!eng_grp->is_enabled) { 1568c2ecf20Sopenharmony_ci dev_err(dev, "Requested engine group %d is disabled\n", grp); 1578c2ecf20Sopenharmony_ci return -EINVAL; 1588c2ecf20Sopenharmony_ci } 1598c2ecf20Sopenharmony_ci 1608c2ecf20Sopenharmony_ci pf_qx_ctl.u = readq(cpt->reg_base + OTX_CPT_PF_QX_CTL(q)); 1618c2ecf20Sopenharmony_ci pf_qx_ctl.s.grp = grp; 1628c2ecf20Sopenharmony_ci writeq(pf_qx_ctl.u, cpt->reg_base + OTX_CPT_PF_QX_CTL(q)); 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_ci if (eng_grp->mirror.is_ena) 1658c2ecf20Sopenharmony_ci ucode = &eng_grp->g->grp[eng_grp->mirror.idx].ucode[0]; 1668c2ecf20Sopenharmony_ci else 1678c2ecf20Sopenharmony_ci ucode = &eng_grp->ucode[0]; 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_ci if (otx_cpt_uc_supports_eng_type(ucode, OTX_CPT_SE_TYPES)) 1708c2ecf20Sopenharmony_ci return OTX_CPT_SE_TYPES; 1718c2ecf20Sopenharmony_ci else if (otx_cpt_uc_supports_eng_type(ucode, OTX_CPT_AE_TYPES)) 1728c2ecf20Sopenharmony_ci return OTX_CPT_AE_TYPES; 1738c2ecf20Sopenharmony_ci else 1748c2ecf20Sopenharmony_ci return BAD_OTX_CPTVF_TYPE; 1758c2ecf20Sopenharmony_ci} 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_ci/* Interrupt handler to handle mailbox messages from VFs */ 1788c2ecf20Sopenharmony_cistatic void otx_cpt_handle_mbox_intr(struct otx_cpt_device *cpt, int vf) 1798c2ecf20Sopenharmony_ci{ 1808c2ecf20Sopenharmony_ci int vftype = 0; 1818c2ecf20Sopenharmony_ci struct otx_cpt_mbox mbx = {}; 1828c2ecf20Sopenharmony_ci struct device *dev = &cpt->pdev->dev; 1838c2ecf20Sopenharmony_ci /* 1848c2ecf20Sopenharmony_ci * MBOX[0] contains msg 1858c2ecf20Sopenharmony_ci * MBOX[1] contains data 1868c2ecf20Sopenharmony_ci */ 1878c2ecf20Sopenharmony_ci mbx.msg = readq(cpt->reg_base + OTX_CPT_PF_VFX_MBOXX(vf, 0)); 1888c2ecf20Sopenharmony_ci mbx.data = readq(cpt->reg_base + OTX_CPT_PF_VFX_MBOXX(vf, 1)); 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_ci dump_mbox_msg(&mbx, vf); 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_ci switch (mbx.msg) { 1938c2ecf20Sopenharmony_ci case OTX_CPT_MSG_VF_UP: 1948c2ecf20Sopenharmony_ci mbx.msg = OTX_CPT_MSG_VF_UP; 1958c2ecf20Sopenharmony_ci mbx.data = cpt->vfs_enabled; 1968c2ecf20Sopenharmony_ci otx_cpt_send_msg_to_vf(cpt, vf, &mbx); 1978c2ecf20Sopenharmony_ci break; 1988c2ecf20Sopenharmony_ci case OTX_CPT_MSG_READY: 1998c2ecf20Sopenharmony_ci mbx.msg = OTX_CPT_MSG_READY; 2008c2ecf20Sopenharmony_ci mbx.data = vf; 2018c2ecf20Sopenharmony_ci otx_cpt_send_msg_to_vf(cpt, vf, &mbx); 2028c2ecf20Sopenharmony_ci break; 2038c2ecf20Sopenharmony_ci case OTX_CPT_MSG_VF_DOWN: 2048c2ecf20Sopenharmony_ci /* First msg in VF teardown sequence */ 2058c2ecf20Sopenharmony_ci otx_cpt_mbox_send_ack(cpt, vf, &mbx); 2068c2ecf20Sopenharmony_ci break; 2078c2ecf20Sopenharmony_ci case OTX_CPT_MSG_QLEN: 2088c2ecf20Sopenharmony_ci otx_cpt_cfg_qlen_for_vf(cpt, vf, mbx.data); 2098c2ecf20Sopenharmony_ci otx_cpt_mbox_send_ack(cpt, vf, &mbx); 2108c2ecf20Sopenharmony_ci break; 2118c2ecf20Sopenharmony_ci case OTX_CPT_MSG_QBIND_GRP: 2128c2ecf20Sopenharmony_ci vftype = otx_cpt_bind_vq_to_grp(cpt, vf, (u8)mbx.data); 2138c2ecf20Sopenharmony_ci if ((vftype != OTX_CPT_AE_TYPES) && 2148c2ecf20Sopenharmony_ci (vftype != OTX_CPT_SE_TYPES)) { 2158c2ecf20Sopenharmony_ci dev_err(dev, "VF%d binding to eng group %llu failed\n", 2168c2ecf20Sopenharmony_ci vf, mbx.data); 2178c2ecf20Sopenharmony_ci otx_cptpf_mbox_send_nack(cpt, vf, &mbx); 2188c2ecf20Sopenharmony_ci } else { 2198c2ecf20Sopenharmony_ci mbx.msg = OTX_CPT_MSG_QBIND_GRP; 2208c2ecf20Sopenharmony_ci mbx.data = vftype; 2218c2ecf20Sopenharmony_ci otx_cpt_send_msg_to_vf(cpt, vf, &mbx); 2228c2ecf20Sopenharmony_ci } 2238c2ecf20Sopenharmony_ci break; 2248c2ecf20Sopenharmony_ci case OTX_CPT_MSG_PF_TYPE: 2258c2ecf20Sopenharmony_ci mbx.msg = OTX_CPT_MSG_PF_TYPE; 2268c2ecf20Sopenharmony_ci mbx.data = cpt->pf_type; 2278c2ecf20Sopenharmony_ci otx_cpt_send_msg_to_vf(cpt, vf, &mbx); 2288c2ecf20Sopenharmony_ci break; 2298c2ecf20Sopenharmony_ci case OTX_CPT_MSG_VQ_PRIORITY: 2308c2ecf20Sopenharmony_ci otx_cpt_cfg_vq_priority(cpt, vf, mbx.data); 2318c2ecf20Sopenharmony_ci otx_cpt_mbox_send_ack(cpt, vf, &mbx); 2328c2ecf20Sopenharmony_ci break; 2338c2ecf20Sopenharmony_ci default: 2348c2ecf20Sopenharmony_ci dev_err(&cpt->pdev->dev, "Invalid msg from VF%d, msg 0x%llx\n", 2358c2ecf20Sopenharmony_ci vf, mbx.msg); 2368c2ecf20Sopenharmony_ci break; 2378c2ecf20Sopenharmony_ci } 2388c2ecf20Sopenharmony_ci} 2398c2ecf20Sopenharmony_ci 2408c2ecf20Sopenharmony_civoid otx_cpt_mbox_intr_handler (struct otx_cpt_device *cpt, int mbx) 2418c2ecf20Sopenharmony_ci{ 2428c2ecf20Sopenharmony_ci u64 intr; 2438c2ecf20Sopenharmony_ci u8 vf; 2448c2ecf20Sopenharmony_ci 2458c2ecf20Sopenharmony_ci intr = readq(cpt->reg_base + OTX_CPT_PF_MBOX_INTX(0)); 2468c2ecf20Sopenharmony_ci pr_debug("PF interrupt mbox%d mask 0x%llx\n", mbx, intr); 2478c2ecf20Sopenharmony_ci for (vf = 0; vf < cpt->max_vfs; vf++) { 2488c2ecf20Sopenharmony_ci if (intr & (1ULL << vf)) { 2498c2ecf20Sopenharmony_ci otx_cpt_handle_mbox_intr(cpt, vf); 2508c2ecf20Sopenharmony_ci otx_cpt_clear_mbox_intr(cpt, vf); 2518c2ecf20Sopenharmony_ci } 2528c2ecf20Sopenharmony_ci } 2538c2ecf20Sopenharmony_ci} 254