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 "otx_cpt_common.h"
0012 #include "otx_cptpf.h"
0013 
0014 static char *get_mbox_opcode_str(int msg_opcode)
0015 {
0016     char *str = "Unknown";
0017 
0018     switch (msg_opcode) {
0019     case OTX_CPT_MSG_VF_UP:
0020         str = "UP";
0021         break;
0022 
0023     case OTX_CPT_MSG_VF_DOWN:
0024         str = "DOWN";
0025         break;
0026 
0027     case OTX_CPT_MSG_READY:
0028         str = "READY";
0029         break;
0030 
0031     case OTX_CPT_MSG_QLEN:
0032         str = "QLEN";
0033         break;
0034 
0035     case OTX_CPT_MSG_QBIND_GRP:
0036         str = "QBIND_GRP";
0037         break;
0038 
0039     case OTX_CPT_MSG_VQ_PRIORITY:
0040         str = "VQ_PRIORITY";
0041         break;
0042 
0043     case OTX_CPT_MSG_PF_TYPE:
0044         str = "PF_TYPE";
0045         break;
0046 
0047     case OTX_CPT_MSG_ACK:
0048         str = "ACK";
0049         break;
0050 
0051     case OTX_CPT_MSG_NACK:
0052         str = "NACK";
0053         break;
0054     }
0055 
0056     return str;
0057 }
0058 
0059 static void dump_mbox_msg(struct otx_cpt_mbox *mbox_msg, int vf_id)
0060 {
0061     char raw_data_str[OTX_CPT_MAX_MBOX_DATA_STR_SIZE];
0062 
0063     hex_dump_to_buffer(mbox_msg, sizeof(struct otx_cpt_mbox), 16, 8,
0064                raw_data_str, OTX_CPT_MAX_MBOX_DATA_STR_SIZE, false);
0065     if (vf_id >= 0)
0066         pr_debug("MBOX opcode %s received from VF%d raw_data %s\n",
0067              get_mbox_opcode_str(mbox_msg->msg), vf_id,
0068              raw_data_str);
0069     else
0070         pr_debug("MBOX opcode %s received from PF raw_data %s\n",
0071              get_mbox_opcode_str(mbox_msg->msg), raw_data_str);
0072 }
0073 
0074 static void otx_cpt_send_msg_to_vf(struct otx_cpt_device *cpt, int vf,
0075                    struct otx_cpt_mbox *mbx)
0076 {
0077     /* Writing mbox(0) causes interrupt */
0078     writeq(mbx->data, cpt->reg_base + OTX_CPT_PF_VFX_MBOXX(vf, 1));
0079     writeq(mbx->msg, cpt->reg_base + OTX_CPT_PF_VFX_MBOXX(vf, 0));
0080 }
0081 
0082 /*
0083  * ACKs VF's mailbox message
0084  * @vf: VF to which ACK to be sent
0085  */
0086 static void otx_cpt_mbox_send_ack(struct otx_cpt_device *cpt, int vf,
0087                   struct otx_cpt_mbox *mbx)
0088 {
0089     mbx->data = 0ull;
0090     mbx->msg = OTX_CPT_MSG_ACK;
0091     otx_cpt_send_msg_to_vf(cpt, vf, mbx);
0092 }
0093 
0094 /* NACKs VF's mailbox message that PF is not able to complete the action */
0095 static void otx_cptpf_mbox_send_nack(struct otx_cpt_device *cpt, int vf,
0096                      struct otx_cpt_mbox *mbx)
0097 {
0098     mbx->data = 0ull;
0099     mbx->msg = OTX_CPT_MSG_NACK;
0100     otx_cpt_send_msg_to_vf(cpt, vf, mbx);
0101 }
0102 
0103 static void otx_cpt_clear_mbox_intr(struct otx_cpt_device *cpt, u32 vf)
0104 {
0105     /* W1C for the VF */
0106     writeq(1ull << vf, cpt->reg_base + OTX_CPT_PF_MBOX_INTX(0));
0107 }
0108 
0109 /*
0110  * Configure QLEN/Chunk sizes for VF
0111  */
0112 static void otx_cpt_cfg_qlen_for_vf(struct otx_cpt_device *cpt, int vf,
0113                     u32 size)
0114 {
0115     union otx_cptx_pf_qx_ctl pf_qx_ctl;
0116 
0117     pf_qx_ctl.u = readq(cpt->reg_base + OTX_CPT_PF_QX_CTL(vf));
0118     pf_qx_ctl.s.size = size;
0119     pf_qx_ctl.s.cont_err = true;
0120     writeq(pf_qx_ctl.u, cpt->reg_base + OTX_CPT_PF_QX_CTL(vf));
0121 }
0122 
0123 /*
0124  * Configure VQ priority
0125  */
0126 static void otx_cpt_cfg_vq_priority(struct otx_cpt_device *cpt, int vf, u32 pri)
0127 {
0128     union otx_cptx_pf_qx_ctl pf_qx_ctl;
0129 
0130     pf_qx_ctl.u = readq(cpt->reg_base + OTX_CPT_PF_QX_CTL(vf));
0131     pf_qx_ctl.s.pri = pri;
0132     writeq(pf_qx_ctl.u, cpt->reg_base + OTX_CPT_PF_QX_CTL(vf));
0133 }
0134 
0135 static int otx_cpt_bind_vq_to_grp(struct otx_cpt_device *cpt, u8 q, u8 grp)
0136 {
0137     struct device *dev = &cpt->pdev->dev;
0138     struct otx_cpt_eng_grp_info *eng_grp;
0139     union otx_cptx_pf_qx_ctl pf_qx_ctl;
0140     struct otx_cpt_ucode *ucode;
0141 
0142     if (q >= cpt->max_vfs) {
0143         dev_err(dev, "Requested queue %d is > than maximum avail %d\n",
0144             q, cpt->max_vfs);
0145         return -EINVAL;
0146     }
0147 
0148     if (grp >= OTX_CPT_MAX_ENGINE_GROUPS) {
0149         dev_err(dev, "Requested group %d is > than maximum avail %d\n",
0150             grp, OTX_CPT_MAX_ENGINE_GROUPS);
0151         return -EINVAL;
0152     }
0153 
0154     eng_grp = &cpt->eng_grps.grp[grp];
0155     if (!eng_grp->is_enabled) {
0156         dev_err(dev, "Requested engine group %d is disabled\n", grp);
0157         return -EINVAL;
0158     }
0159 
0160     pf_qx_ctl.u = readq(cpt->reg_base + OTX_CPT_PF_QX_CTL(q));
0161     pf_qx_ctl.s.grp = grp;
0162     writeq(pf_qx_ctl.u, cpt->reg_base + OTX_CPT_PF_QX_CTL(q));
0163 
0164     if (eng_grp->mirror.is_ena)
0165         ucode = &eng_grp->g->grp[eng_grp->mirror.idx].ucode[0];
0166     else
0167         ucode = &eng_grp->ucode[0];
0168 
0169     if (otx_cpt_uc_supports_eng_type(ucode, OTX_CPT_SE_TYPES))
0170         return OTX_CPT_SE_TYPES;
0171     else if (otx_cpt_uc_supports_eng_type(ucode, OTX_CPT_AE_TYPES))
0172         return OTX_CPT_AE_TYPES;
0173     else
0174         return BAD_OTX_CPTVF_TYPE;
0175 }
0176 
0177 /* Interrupt handler to handle mailbox messages from VFs */
0178 static void otx_cpt_handle_mbox_intr(struct otx_cpt_device *cpt, int vf)
0179 {
0180     int vftype = 0;
0181     struct otx_cpt_mbox mbx = {};
0182     struct device *dev = &cpt->pdev->dev;
0183     /*
0184      * MBOX[0] contains msg
0185      * MBOX[1] contains data
0186      */
0187     mbx.msg  = readq(cpt->reg_base + OTX_CPT_PF_VFX_MBOXX(vf, 0));
0188     mbx.data = readq(cpt->reg_base + OTX_CPT_PF_VFX_MBOXX(vf, 1));
0189 
0190     dump_mbox_msg(&mbx, vf);
0191 
0192     switch (mbx.msg) {
0193     case OTX_CPT_MSG_VF_UP:
0194         mbx.msg  = OTX_CPT_MSG_VF_UP;
0195         mbx.data = cpt->vfs_enabled;
0196         otx_cpt_send_msg_to_vf(cpt, vf, &mbx);
0197         break;
0198     case OTX_CPT_MSG_READY:
0199         mbx.msg  = OTX_CPT_MSG_READY;
0200         mbx.data = vf;
0201         otx_cpt_send_msg_to_vf(cpt, vf, &mbx);
0202         break;
0203     case OTX_CPT_MSG_VF_DOWN:
0204         /* First msg in VF teardown sequence */
0205         otx_cpt_mbox_send_ack(cpt, vf, &mbx);
0206         break;
0207     case OTX_CPT_MSG_QLEN:
0208         otx_cpt_cfg_qlen_for_vf(cpt, vf, mbx.data);
0209         otx_cpt_mbox_send_ack(cpt, vf, &mbx);
0210         break;
0211     case OTX_CPT_MSG_QBIND_GRP:
0212         vftype = otx_cpt_bind_vq_to_grp(cpt, vf, (u8)mbx.data);
0213         if ((vftype != OTX_CPT_AE_TYPES) &&
0214             (vftype != OTX_CPT_SE_TYPES)) {
0215             dev_err(dev, "VF%d binding to eng group %llu failed\n",
0216                 vf, mbx.data);
0217             otx_cptpf_mbox_send_nack(cpt, vf, &mbx);
0218         } else {
0219             mbx.msg = OTX_CPT_MSG_QBIND_GRP;
0220             mbx.data = vftype;
0221             otx_cpt_send_msg_to_vf(cpt, vf, &mbx);
0222         }
0223         break;
0224     case OTX_CPT_MSG_PF_TYPE:
0225         mbx.msg = OTX_CPT_MSG_PF_TYPE;
0226         mbx.data = cpt->pf_type;
0227         otx_cpt_send_msg_to_vf(cpt, vf, &mbx);
0228         break;
0229     case OTX_CPT_MSG_VQ_PRIORITY:
0230         otx_cpt_cfg_vq_priority(cpt, vf, mbx.data);
0231         otx_cpt_mbox_send_ack(cpt, vf, &mbx);
0232         break;
0233     default:
0234         dev_err(&cpt->pdev->dev, "Invalid msg from VF%d, msg 0x%llx\n",
0235             vf, mbx.msg);
0236         break;
0237     }
0238 }
0239 
0240 void otx_cpt_mbox_intr_handler (struct otx_cpt_device *cpt, int mbx)
0241 {
0242     u64 intr;
0243     u8  vf;
0244 
0245     intr = readq(cpt->reg_base + OTX_CPT_PF_MBOX_INTX(0));
0246     pr_debug("PF interrupt mbox%d mask 0x%llx\n", mbx, intr);
0247     for (vf = 0; vf < cpt->max_vfs; vf++) {
0248         if (intr & (1ULL << vf)) {
0249             otx_cpt_handle_mbox_intr(cpt, vf);
0250             otx_cpt_clear_mbox_intr(cpt, vf);
0251         }
0252     }
0253 }