Loading...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 | // SPDX-License-Identifier: GPL-2.0-only /* Copyright (C) 2020 Marvell. */ #include "otx2_cpt_common.h" #include "otx2_cptvf.h" #include <rvu_reg.h> int otx2_cpt_mbox_bbuf_init(struct otx2_cptvf_dev *cptvf, struct pci_dev *pdev) { struct otx2_mbox_dev *mdev; struct otx2_mbox *otx2_mbox; cptvf->bbuf_base = devm_kmalloc(&pdev->dev, MBOX_SIZE, GFP_KERNEL); if (!cptvf->bbuf_base) return -ENOMEM; /* * Overwrite mbox mbase to point to bounce buffer, so that PF/VF * prepare all mbox messages in bounce buffer instead of directly * in hw mbox memory. */ otx2_mbox = &cptvf->pfvf_mbox; mdev = &otx2_mbox->dev[0]; mdev->mbase = cptvf->bbuf_base; return 0; } static void otx2_cpt_sync_mbox_bbuf(struct otx2_mbox *mbox, int devid) { u16 msgs_offset = ALIGN(sizeof(struct mbox_hdr), MBOX_MSG_ALIGN); void *hw_mbase = mbox->hwbase + (devid * MBOX_SIZE); struct otx2_mbox_dev *mdev = &mbox->dev[devid]; struct mbox_hdr *hdr; u64 msg_size; if (mdev->mbase == hw_mbase) return; hdr = hw_mbase + mbox->rx_start; msg_size = hdr->msg_size; if (msg_size > mbox->rx_size - msgs_offset) msg_size = mbox->rx_size - msgs_offset; /* Copy mbox messages from mbox memory to bounce buffer */ memcpy(mdev->mbase + mbox->rx_start, hw_mbase + mbox->rx_start, msg_size + msgs_offset); } irqreturn_t otx2_cptvf_pfvf_mbox_intr(int __always_unused irq, void *arg) { struct otx2_cptvf_dev *cptvf = arg; u64 intr; /* Read the interrupt bits */ intr = otx2_cpt_read64(cptvf->reg_base, BLKADDR_RVUM, 0, OTX2_RVU_VF_INT); if (intr & 0x1ULL) { /* Schedule work queue function to process the MBOX request */ queue_work(cptvf->pfvf_mbox_wq, &cptvf->pfvf_mbox_work); /* Clear and ack the interrupt */ otx2_cpt_write64(cptvf->reg_base, BLKADDR_RVUM, 0, OTX2_RVU_VF_INT, 0x1ULL); } return IRQ_HANDLED; } static void process_pfvf_mbox_mbox_msg(struct otx2_cptvf_dev *cptvf, struct mbox_msghdr *msg) { struct otx2_cptlfs_info *lfs = &cptvf->lfs; struct otx2_cpt_kvf_limits_rsp *rsp_limits; struct otx2_cpt_egrp_num_rsp *rsp_grp; struct otx2_cpt_caps_rsp *eng_caps; struct cpt_rd_wr_reg_msg *rsp_reg; struct msix_offset_rsp *rsp_msix; int i; if (msg->id >= MBOX_MSG_MAX) { dev_err(&cptvf->pdev->dev, "MBOX msg with unknown ID %d\n", msg->id); return; } if (msg->sig != OTX2_MBOX_RSP_SIG) { dev_err(&cptvf->pdev->dev, "MBOX msg with wrong signature %x, ID %d\n", msg->sig, msg->id); return; } switch (msg->id) { case MBOX_MSG_READY: cptvf->vf_id = ((msg->pcifunc >> RVU_PFVF_FUNC_SHIFT) & RVU_PFVF_FUNC_MASK) - 1; break; case MBOX_MSG_ATTACH_RESOURCES: /* Check if resources were successfully attached */ if (!msg->rc) lfs->are_lfs_attached = 1; break; case MBOX_MSG_DETACH_RESOURCES: /* Check if resources were successfully detached */ if (!msg->rc) lfs->are_lfs_attached = 0; break; case MBOX_MSG_MSIX_OFFSET: rsp_msix = (struct msix_offset_rsp *) msg; for (i = 0; i < rsp_msix->cptlfs; i++) lfs->lf[i].msix_offset = rsp_msix->cptlf_msixoff[i]; break; case MBOX_MSG_CPT_RD_WR_REGISTER: rsp_reg = (struct cpt_rd_wr_reg_msg *) msg; if (msg->rc) { dev_err(&cptvf->pdev->dev, "Reg %llx rd/wr(%d) failed %d\n", rsp_reg->reg_offset, rsp_reg->is_write, msg->rc); return; } if (!rsp_reg->is_write) *rsp_reg->ret_val = rsp_reg->val; break; case MBOX_MSG_GET_ENG_GRP_NUM: rsp_grp = (struct otx2_cpt_egrp_num_rsp *) msg; cptvf->lfs.kcrypto_eng_grp_num = rsp_grp->eng_grp_num; break; case MBOX_MSG_GET_KVF_LIMITS: rsp_limits = (struct otx2_cpt_kvf_limits_rsp *) msg; cptvf->lfs.kvf_limits = rsp_limits->kvf_limits; break; case MBOX_MSG_GET_CAPS: eng_caps = (struct otx2_cpt_caps_rsp *)msg; memcpy(cptvf->eng_caps, eng_caps->eng_caps, sizeof(cptvf->eng_caps)); break; case MBOX_MSG_CPT_LF_RESET: break; default: dev_err(&cptvf->pdev->dev, "Unsupported msg %d received.\n", msg->id); break; } } void otx2_cptvf_pfvf_mbox_handler(struct work_struct *work) { struct otx2_cptvf_dev *cptvf; struct otx2_mbox *pfvf_mbox; struct otx2_mbox_dev *mdev; struct mbox_hdr *rsp_hdr; struct mbox_msghdr *msg; int offset, i; /* sync with mbox memory region */ smp_rmb(); cptvf = container_of(work, struct otx2_cptvf_dev, pfvf_mbox_work); pfvf_mbox = &cptvf->pfvf_mbox; otx2_cpt_sync_mbox_bbuf(pfvf_mbox, 0); mdev = &pfvf_mbox->dev[0]; rsp_hdr = (struct mbox_hdr *)(mdev->mbase + pfvf_mbox->rx_start); if (rsp_hdr->num_msgs == 0) return; offset = ALIGN(sizeof(struct mbox_hdr), MBOX_MSG_ALIGN); for (i = 0; i < rsp_hdr->num_msgs; i++) { msg = (struct mbox_msghdr *)(mdev->mbase + pfvf_mbox->rx_start + offset); process_pfvf_mbox_mbox_msg(cptvf, msg); offset = msg->next_msgoff; mdev->msgs_acked++; } otx2_mbox_reset(pfvf_mbox, 0); } int otx2_cptvf_send_eng_grp_num_msg(struct otx2_cptvf_dev *cptvf, int eng_type) { struct otx2_mbox *mbox = &cptvf->pfvf_mbox; struct pci_dev *pdev = cptvf->pdev; struct otx2_cpt_egrp_num_msg *req; req = (struct otx2_cpt_egrp_num_msg *) otx2_mbox_alloc_msg_rsp(mbox, 0, sizeof(*req), sizeof(struct otx2_cpt_egrp_num_rsp)); if (req == NULL) { dev_err(&pdev->dev, "RVU MBOX failed to get message.\n"); return -EFAULT; } req->hdr.id = MBOX_MSG_GET_ENG_GRP_NUM; req->hdr.sig = OTX2_MBOX_REQ_SIG; req->hdr.pcifunc = OTX2_CPT_RVU_PFFUNC(cptvf->vf_id, 0); req->eng_type = eng_type; return otx2_cpt_send_mbox_msg(mbox, pdev); } int otx2_cptvf_send_kvf_limits_msg(struct otx2_cptvf_dev *cptvf) { struct otx2_mbox *mbox = &cptvf->pfvf_mbox; struct pci_dev *pdev = cptvf->pdev; struct mbox_msghdr *req; req = (struct mbox_msghdr *) otx2_mbox_alloc_msg_rsp(mbox, 0, sizeof(*req), sizeof(struct otx2_cpt_kvf_limits_rsp)); if (req == NULL) { dev_err(&pdev->dev, "RVU MBOX failed to get message.\n"); return -EFAULT; } req->id = MBOX_MSG_GET_KVF_LIMITS; req->sig = OTX2_MBOX_REQ_SIG; req->pcifunc = OTX2_CPT_RVU_PFFUNC(cptvf->vf_id, 0); return otx2_cpt_send_mbox_msg(mbox, pdev); } int otx2_cptvf_send_caps_msg(struct otx2_cptvf_dev *cptvf) { struct otx2_mbox *mbox = &cptvf->pfvf_mbox; struct pci_dev *pdev = cptvf->pdev; struct mbox_msghdr *req; req = (struct mbox_msghdr *) otx2_mbox_alloc_msg_rsp(mbox, 0, sizeof(*req), sizeof(struct otx2_cpt_caps_rsp)); if (!req) { dev_err(&pdev->dev, "RVU MBOX failed to get message.\n"); return -EFAULT; } req->id = MBOX_MSG_GET_CAPS; req->sig = OTX2_MBOX_REQ_SIG; req->pcifunc = OTX2_CPT_RVU_PFFUNC(cptvf->vf_id, 0); return otx2_cpt_send_mbox_msg(mbox, pdev); } |