162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright (C) 2016 Cavium, Inc. 462306a36Sopenharmony_ci */ 562306a36Sopenharmony_ci 662306a36Sopenharmony_ci#include "cptvf.h" 762306a36Sopenharmony_ci 862306a36Sopenharmony_cistatic void cptvf_send_msg_to_pf(struct cpt_vf *cptvf, struct cpt_mbox *mbx) 962306a36Sopenharmony_ci{ 1062306a36Sopenharmony_ci /* Writing mbox(1) causes interrupt */ 1162306a36Sopenharmony_ci cpt_write_csr64(cptvf->reg_base, CPTX_VFX_PF_MBOXX(0, 0, 0), 1262306a36Sopenharmony_ci mbx->msg); 1362306a36Sopenharmony_ci cpt_write_csr64(cptvf->reg_base, CPTX_VFX_PF_MBOXX(0, 0, 1), 1462306a36Sopenharmony_ci mbx->data); 1562306a36Sopenharmony_ci} 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_ci/* Interrupt handler to handle mailbox messages from VFs */ 1862306a36Sopenharmony_civoid cptvf_handle_mbox_intr(struct cpt_vf *cptvf) 1962306a36Sopenharmony_ci{ 2062306a36Sopenharmony_ci struct cpt_mbox mbx = {}; 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_ci /* 2362306a36Sopenharmony_ci * MBOX[0] contains msg 2462306a36Sopenharmony_ci * MBOX[1] contains data 2562306a36Sopenharmony_ci */ 2662306a36Sopenharmony_ci mbx.msg = cpt_read_csr64(cptvf->reg_base, CPTX_VFX_PF_MBOXX(0, 0, 0)); 2762306a36Sopenharmony_ci mbx.data = cpt_read_csr64(cptvf->reg_base, CPTX_VFX_PF_MBOXX(0, 0, 1)); 2862306a36Sopenharmony_ci dev_dbg(&cptvf->pdev->dev, "%s: Mailbox msg 0x%llx from PF\n", 2962306a36Sopenharmony_ci __func__, mbx.msg); 3062306a36Sopenharmony_ci switch (mbx.msg) { 3162306a36Sopenharmony_ci case CPT_MSG_READY: 3262306a36Sopenharmony_ci { 3362306a36Sopenharmony_ci cptvf->pf_acked = true; 3462306a36Sopenharmony_ci cptvf->vfid = mbx.data; 3562306a36Sopenharmony_ci dev_dbg(&cptvf->pdev->dev, "Received VFID %d\n", cptvf->vfid); 3662306a36Sopenharmony_ci break; 3762306a36Sopenharmony_ci } 3862306a36Sopenharmony_ci case CPT_MSG_QBIND_GRP: 3962306a36Sopenharmony_ci cptvf->pf_acked = true; 4062306a36Sopenharmony_ci cptvf->vftype = mbx.data; 4162306a36Sopenharmony_ci dev_dbg(&cptvf->pdev->dev, "VF %d type %s group %d\n", 4262306a36Sopenharmony_ci cptvf->vfid, ((mbx.data == SE_TYPES) ? "SE" : "AE"), 4362306a36Sopenharmony_ci cptvf->vfgrp); 4462306a36Sopenharmony_ci break; 4562306a36Sopenharmony_ci case CPT_MBOX_MSG_TYPE_ACK: 4662306a36Sopenharmony_ci cptvf->pf_acked = true; 4762306a36Sopenharmony_ci break; 4862306a36Sopenharmony_ci case CPT_MBOX_MSG_TYPE_NACK: 4962306a36Sopenharmony_ci cptvf->pf_nacked = true; 5062306a36Sopenharmony_ci break; 5162306a36Sopenharmony_ci default: 5262306a36Sopenharmony_ci dev_err(&cptvf->pdev->dev, "Invalid msg from PF, msg 0x%llx\n", 5362306a36Sopenharmony_ci mbx.msg); 5462306a36Sopenharmony_ci break; 5562306a36Sopenharmony_ci } 5662306a36Sopenharmony_ci} 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_cistatic int cptvf_send_msg_to_pf_timeout(struct cpt_vf *cptvf, 5962306a36Sopenharmony_ci struct cpt_mbox *mbx) 6062306a36Sopenharmony_ci{ 6162306a36Sopenharmony_ci int timeout = CPT_MBOX_MSG_TIMEOUT; 6262306a36Sopenharmony_ci int sleep = 10; 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_ci cptvf->pf_acked = false; 6562306a36Sopenharmony_ci cptvf->pf_nacked = false; 6662306a36Sopenharmony_ci cptvf_send_msg_to_pf(cptvf, mbx); 6762306a36Sopenharmony_ci /* Wait for previous message to be acked, timeout 2sec */ 6862306a36Sopenharmony_ci while (!cptvf->pf_acked) { 6962306a36Sopenharmony_ci if (cptvf->pf_nacked) 7062306a36Sopenharmony_ci return -EINVAL; 7162306a36Sopenharmony_ci msleep(sleep); 7262306a36Sopenharmony_ci if (cptvf->pf_acked) 7362306a36Sopenharmony_ci break; 7462306a36Sopenharmony_ci timeout -= sleep; 7562306a36Sopenharmony_ci if (!timeout) { 7662306a36Sopenharmony_ci dev_err(&cptvf->pdev->dev, "PF didn't ack to mbox msg %llx from VF%u\n", 7762306a36Sopenharmony_ci (mbx->msg & 0xFF), cptvf->vfid); 7862306a36Sopenharmony_ci return -EBUSY; 7962306a36Sopenharmony_ci } 8062306a36Sopenharmony_ci } 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_ci return 0; 8362306a36Sopenharmony_ci} 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_ci/* 8662306a36Sopenharmony_ci * Checks if VF is able to comminicate with PF 8762306a36Sopenharmony_ci * and also gets the CPT number this VF is associated to. 8862306a36Sopenharmony_ci */ 8962306a36Sopenharmony_ciint cptvf_check_pf_ready(struct cpt_vf *cptvf) 9062306a36Sopenharmony_ci{ 9162306a36Sopenharmony_ci struct pci_dev *pdev = cptvf->pdev; 9262306a36Sopenharmony_ci struct cpt_mbox mbx = {}; 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_ci mbx.msg = CPT_MSG_READY; 9562306a36Sopenharmony_ci if (cptvf_send_msg_to_pf_timeout(cptvf, &mbx)) { 9662306a36Sopenharmony_ci dev_err(&pdev->dev, "PF didn't respond to READY msg\n"); 9762306a36Sopenharmony_ci return -EBUSY; 9862306a36Sopenharmony_ci } 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_ci return 0; 10162306a36Sopenharmony_ci} 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_ci/* 10462306a36Sopenharmony_ci * Communicate VQs size to PF to program CPT(0)_PF_Q(0-15)_CTL of the VF. 10562306a36Sopenharmony_ci * Must be ACKed. 10662306a36Sopenharmony_ci */ 10762306a36Sopenharmony_ciint cptvf_send_vq_size_msg(struct cpt_vf *cptvf) 10862306a36Sopenharmony_ci{ 10962306a36Sopenharmony_ci struct pci_dev *pdev = cptvf->pdev; 11062306a36Sopenharmony_ci struct cpt_mbox mbx = {}; 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_ci mbx.msg = CPT_MSG_QLEN; 11362306a36Sopenharmony_ci mbx.data = cptvf->qsize; 11462306a36Sopenharmony_ci if (cptvf_send_msg_to_pf_timeout(cptvf, &mbx)) { 11562306a36Sopenharmony_ci dev_err(&pdev->dev, "PF didn't respond to vq_size msg\n"); 11662306a36Sopenharmony_ci return -EBUSY; 11762306a36Sopenharmony_ci } 11862306a36Sopenharmony_ci 11962306a36Sopenharmony_ci return 0; 12062306a36Sopenharmony_ci} 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_ci/* 12362306a36Sopenharmony_ci * Communicate VF group required to PF and get the VQ binded to that group 12462306a36Sopenharmony_ci */ 12562306a36Sopenharmony_ciint cptvf_send_vf_to_grp_msg(struct cpt_vf *cptvf) 12662306a36Sopenharmony_ci{ 12762306a36Sopenharmony_ci struct pci_dev *pdev = cptvf->pdev; 12862306a36Sopenharmony_ci struct cpt_mbox mbx = {}; 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_ci mbx.msg = CPT_MSG_QBIND_GRP; 13162306a36Sopenharmony_ci /* Convey group of the VF */ 13262306a36Sopenharmony_ci mbx.data = cptvf->vfgrp; 13362306a36Sopenharmony_ci if (cptvf_send_msg_to_pf_timeout(cptvf, &mbx)) { 13462306a36Sopenharmony_ci dev_err(&pdev->dev, "PF didn't respond to vf_type msg\n"); 13562306a36Sopenharmony_ci return -EBUSY; 13662306a36Sopenharmony_ci } 13762306a36Sopenharmony_ci 13862306a36Sopenharmony_ci return 0; 13962306a36Sopenharmony_ci} 14062306a36Sopenharmony_ci 14162306a36Sopenharmony_ci/* 14262306a36Sopenharmony_ci * Communicate VF group required to PF and get the VQ binded to that group 14362306a36Sopenharmony_ci */ 14462306a36Sopenharmony_ciint cptvf_send_vf_priority_msg(struct cpt_vf *cptvf) 14562306a36Sopenharmony_ci{ 14662306a36Sopenharmony_ci struct pci_dev *pdev = cptvf->pdev; 14762306a36Sopenharmony_ci struct cpt_mbox mbx = {}; 14862306a36Sopenharmony_ci 14962306a36Sopenharmony_ci mbx.msg = CPT_MSG_VQ_PRIORITY; 15062306a36Sopenharmony_ci /* Convey group of the VF */ 15162306a36Sopenharmony_ci mbx.data = cptvf->priority; 15262306a36Sopenharmony_ci if (cptvf_send_msg_to_pf_timeout(cptvf, &mbx)) { 15362306a36Sopenharmony_ci dev_err(&pdev->dev, "PF didn't respond to vf_type msg\n"); 15462306a36Sopenharmony_ci return -EBUSY; 15562306a36Sopenharmony_ci } 15662306a36Sopenharmony_ci return 0; 15762306a36Sopenharmony_ci} 15862306a36Sopenharmony_ci 15962306a36Sopenharmony_ci/* 16062306a36Sopenharmony_ci * Communicate to PF that VF is UP and running 16162306a36Sopenharmony_ci */ 16262306a36Sopenharmony_ciint cptvf_send_vf_up(struct cpt_vf *cptvf) 16362306a36Sopenharmony_ci{ 16462306a36Sopenharmony_ci struct pci_dev *pdev = cptvf->pdev; 16562306a36Sopenharmony_ci struct cpt_mbox mbx = {}; 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_ci mbx.msg = CPT_MSG_VF_UP; 16862306a36Sopenharmony_ci if (cptvf_send_msg_to_pf_timeout(cptvf, &mbx)) { 16962306a36Sopenharmony_ci dev_err(&pdev->dev, "PF didn't respond to UP msg\n"); 17062306a36Sopenharmony_ci return -EBUSY; 17162306a36Sopenharmony_ci } 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_ci return 0; 17462306a36Sopenharmony_ci} 17562306a36Sopenharmony_ci 17662306a36Sopenharmony_ci/* 17762306a36Sopenharmony_ci * Communicate to PF that VF is DOWN and running 17862306a36Sopenharmony_ci */ 17962306a36Sopenharmony_ciint cptvf_send_vf_down(struct cpt_vf *cptvf) 18062306a36Sopenharmony_ci{ 18162306a36Sopenharmony_ci struct pci_dev *pdev = cptvf->pdev; 18262306a36Sopenharmony_ci struct cpt_mbox mbx = {}; 18362306a36Sopenharmony_ci 18462306a36Sopenharmony_ci mbx.msg = CPT_MSG_VF_DOWN; 18562306a36Sopenharmony_ci if (cptvf_send_msg_to_pf_timeout(cptvf, &mbx)) { 18662306a36Sopenharmony_ci dev_err(&pdev->dev, "PF didn't respond to DOWN msg\n"); 18762306a36Sopenharmony_ci return -EBUSY; 18862306a36Sopenharmony_ci } 18962306a36Sopenharmony_ci 19062306a36Sopenharmony_ci return 0; 19162306a36Sopenharmony_ci} 192