Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /* Marvell OcteonTX CPT driver
0003  *
0004  * Copyright (C) 2019 Marvell International Ltd.
0005  *
0006  * This program is free software; you can redistribute it and/or modify
0007  * it under the terms of the GNU General Public License version 2 as
0008  * published by the Free Software Foundation.
0009  */
0010 
0011 #include <linux/delay.h>
0012 #include "otx_cptvf.h"
0013 
0014 #define CPT_MBOX_MSG_TIMEOUT 2000
0015 
0016 static char *get_mbox_opcode_str(int msg_opcode)
0017 {
0018     char *str = "Unknown";
0019 
0020     switch (msg_opcode) {
0021     case OTX_CPT_MSG_VF_UP:
0022         str = "UP";
0023         break;
0024 
0025     case OTX_CPT_MSG_VF_DOWN:
0026         str = "DOWN";
0027         break;
0028 
0029     case OTX_CPT_MSG_READY:
0030         str = "READY";
0031         break;
0032 
0033     case OTX_CPT_MSG_QLEN:
0034         str = "QLEN";
0035         break;
0036 
0037     case OTX_CPT_MSG_QBIND_GRP:
0038         str = "QBIND_GRP";
0039         break;
0040 
0041     case OTX_CPT_MSG_VQ_PRIORITY:
0042         str = "VQ_PRIORITY";
0043         break;
0044 
0045     case OTX_CPT_MSG_PF_TYPE:
0046         str = "PF_TYPE";
0047         break;
0048 
0049     case OTX_CPT_MSG_ACK:
0050         str = "ACK";
0051         break;
0052 
0053     case OTX_CPT_MSG_NACK:
0054         str = "NACK";
0055         break;
0056     }
0057     return str;
0058 }
0059 
0060 static void dump_mbox_msg(struct otx_cpt_mbox *mbox_msg, int vf_id)
0061 {
0062     char raw_data_str[OTX_CPT_MAX_MBOX_DATA_STR_SIZE];
0063 
0064     hex_dump_to_buffer(mbox_msg, sizeof(struct otx_cpt_mbox), 16, 8,
0065                raw_data_str, OTX_CPT_MAX_MBOX_DATA_STR_SIZE, false);
0066     if (vf_id >= 0)
0067         pr_debug("MBOX msg %s received from VF%d raw_data %s",
0068              get_mbox_opcode_str(mbox_msg->msg), vf_id,
0069              raw_data_str);
0070     else
0071         pr_debug("MBOX msg %s received from PF raw_data %s",
0072              get_mbox_opcode_str(mbox_msg->msg), raw_data_str);
0073 }
0074 
0075 static void cptvf_send_msg_to_pf(struct otx_cptvf *cptvf,
0076                      struct otx_cpt_mbox *mbx)
0077 {
0078     /* Writing mbox(1) causes interrupt */
0079     writeq(mbx->msg, cptvf->reg_base + OTX_CPT_VFX_PF_MBOXX(0, 0));
0080     writeq(mbx->data, cptvf->reg_base + OTX_CPT_VFX_PF_MBOXX(0, 1));
0081 }
0082 
0083 /* Interrupt handler to handle mailbox messages from VFs */
0084 void otx_cptvf_handle_mbox_intr(struct otx_cptvf *cptvf)
0085 {
0086     struct otx_cpt_mbox mbx = {};
0087 
0088     /*
0089      * MBOX[0] contains msg
0090      * MBOX[1] contains data
0091      */
0092     mbx.msg  = readq(cptvf->reg_base + OTX_CPT_VFX_PF_MBOXX(0, 0));
0093     mbx.data = readq(cptvf->reg_base + OTX_CPT_VFX_PF_MBOXX(0, 1));
0094 
0095     dump_mbox_msg(&mbx, -1);
0096 
0097     switch (mbx.msg) {
0098     case OTX_CPT_MSG_VF_UP:
0099         cptvf->pf_acked = true;
0100         cptvf->num_vfs = mbx.data;
0101         break;
0102     case OTX_CPT_MSG_READY:
0103         cptvf->pf_acked = true;
0104         cptvf->vfid = mbx.data;
0105         dev_dbg(&cptvf->pdev->dev, "Received VFID %d\n", cptvf->vfid);
0106         break;
0107     case OTX_CPT_MSG_QBIND_GRP:
0108         cptvf->pf_acked = true;
0109         cptvf->vftype = mbx.data;
0110         dev_dbg(&cptvf->pdev->dev, "VF %d type %s group %d\n",
0111             cptvf->vfid,
0112             ((mbx.data == OTX_CPT_SE_TYPES) ? "SE" : "AE"),
0113             cptvf->vfgrp);
0114         break;
0115     case OTX_CPT_MSG_ACK:
0116         cptvf->pf_acked = true;
0117         break;
0118     case OTX_CPT_MSG_NACK:
0119         cptvf->pf_nacked = true;
0120         break;
0121     default:
0122         dev_err(&cptvf->pdev->dev, "Invalid msg from PF, msg 0x%llx\n",
0123             mbx.msg);
0124         break;
0125     }
0126 }
0127 
0128 static int cptvf_send_msg_to_pf_timeout(struct otx_cptvf *cptvf,
0129                     struct otx_cpt_mbox *mbx)
0130 {
0131     int timeout = CPT_MBOX_MSG_TIMEOUT;
0132     int sleep = 10;
0133 
0134     cptvf->pf_acked = false;
0135     cptvf->pf_nacked = false;
0136     cptvf_send_msg_to_pf(cptvf, mbx);
0137     /* Wait for previous message to be acked, timeout 2sec */
0138     while (!cptvf->pf_acked) {
0139         if (cptvf->pf_nacked)
0140             return -EINVAL;
0141         msleep(sleep);
0142         if (cptvf->pf_acked)
0143             break;
0144         timeout -= sleep;
0145         if (!timeout) {
0146             dev_err(&cptvf->pdev->dev,
0147                 "PF didn't ack to mbox msg %llx from VF%u\n",
0148                 mbx->msg, cptvf->vfid);
0149             return -EBUSY;
0150         }
0151     }
0152     return 0;
0153 }
0154 
0155 /*
0156  * Checks if VF is able to comminicate with PF
0157  * and also gets the CPT number this VF is associated to.
0158  */
0159 int otx_cptvf_check_pf_ready(struct otx_cptvf *cptvf)
0160 {
0161     struct otx_cpt_mbox mbx = {};
0162     int ret;
0163 
0164     mbx.msg = OTX_CPT_MSG_READY;
0165     ret = cptvf_send_msg_to_pf_timeout(cptvf, &mbx);
0166 
0167     return ret;
0168 }
0169 
0170 /*
0171  * Communicate VQs size to PF to program CPT(0)_PF_Q(0-15)_CTL of the VF.
0172  * Must be ACKed.
0173  */
0174 int otx_cptvf_send_vq_size_msg(struct otx_cptvf *cptvf)
0175 {
0176     struct otx_cpt_mbox mbx = {};
0177     int ret;
0178 
0179     mbx.msg = OTX_CPT_MSG_QLEN;
0180     mbx.data = cptvf->qsize;
0181     ret = cptvf_send_msg_to_pf_timeout(cptvf, &mbx);
0182 
0183     return ret;
0184 }
0185 
0186 /*
0187  * Communicate VF group required to PF and get the VQ binded to that group
0188  */
0189 int otx_cptvf_send_vf_to_grp_msg(struct otx_cptvf *cptvf, int group)
0190 {
0191     struct otx_cpt_mbox mbx = {};
0192     int ret;
0193 
0194     mbx.msg = OTX_CPT_MSG_QBIND_GRP;
0195     /* Convey group of the VF */
0196     mbx.data = group;
0197     ret = cptvf_send_msg_to_pf_timeout(cptvf, &mbx);
0198     if (ret)
0199         return ret;
0200     cptvf->vfgrp = group;
0201 
0202     return 0;
0203 }
0204 
0205 /*
0206  * Communicate VF group required to PF and get the VQ binded to that group
0207  */
0208 int otx_cptvf_send_vf_priority_msg(struct otx_cptvf *cptvf)
0209 {
0210     struct otx_cpt_mbox mbx = {};
0211     int ret;
0212 
0213     mbx.msg = OTX_CPT_MSG_VQ_PRIORITY;
0214     /* Convey group of the VF */
0215     mbx.data = cptvf->priority;
0216     ret = cptvf_send_msg_to_pf_timeout(cptvf, &mbx);
0217 
0218     return ret;
0219 }
0220 
0221 /*
0222  * Communicate to PF that VF is UP and running
0223  */
0224 int otx_cptvf_send_vf_up(struct otx_cptvf *cptvf)
0225 {
0226     struct otx_cpt_mbox mbx = {};
0227     int ret;
0228 
0229     mbx.msg = OTX_CPT_MSG_VF_UP;
0230     ret = cptvf_send_msg_to_pf_timeout(cptvf, &mbx);
0231 
0232     return ret;
0233 }
0234 
0235 /*
0236  * Communicate to PF that VF is DOWN and running
0237  */
0238 int otx_cptvf_send_vf_down(struct otx_cptvf *cptvf)
0239 {
0240     struct otx_cpt_mbox mbx = {};
0241     int ret;
0242 
0243     mbx.msg = OTX_CPT_MSG_VF_DOWN;
0244     ret = cptvf_send_msg_to_pf_timeout(cptvf, &mbx);
0245 
0246     return ret;
0247 }