Commit fe16ecea authored by Srujana Challa's avatar Srujana Challa Committed by Herbert Xu

crypto: octeontx2 - enable SR-IOV and mailbox communication with VF

Adds 'sriov_configure' to enable/disable virtual functions (VFs).
Also Initializes VF<=>PF mailbox IRQs, register handlers for
processing these mailbox messages.

Admin function (AF) handles resource allocation and configuration for
PFs and their VFs. PFs request the AF directly, via mailboxes.
Unlike PFs, VFs cannot send a mailbox request directly. A VF sends
mailbox messages to its parent PF, with which it shares a mailbox
region. The PF then forwards these messages to the AF. After handling
the request, the AF sends a response back to the VF, through the PF.

This patch adds support for this 'VF <=> PF <=> AF' mailbox
communication.
Signed-off-by: default avatarSuheil Chandran <schandran@marvell.com>
Signed-off-by: default avatarLukasz Bartosik <lbartosik@marvell.com>
Signed-off-by: default avatarSrujana Challa <schalla@marvell.com>
Signed-off-by: default avatarHerbert Xu <herbert@gondor.apana.org.au>
parent 83ffcf78
......@@ -14,6 +14,7 @@
#include "rvu.h"
#include "mbox.h"
#define OTX2_CPT_MAX_VFS_NUM 128
#define OTX2_CPT_RVU_FUNC_ADDR_S(blk, slot, offs) \
(((blk) << 20) | ((slot) << 12) | (offs))
......
......@@ -7,19 +7,46 @@
#include "otx2_cpt_common.h"
struct otx2_cptpf_dev;
struct otx2_cptvf_info {
struct otx2_cptpf_dev *cptpf; /* PF pointer this VF belongs to */
struct work_struct vfpf_mbox_work;
struct pci_dev *vf_dev;
int vf_id;
int intr_idx;
};
struct cptpf_flr_work {
struct work_struct work;
struct otx2_cptpf_dev *pf;
};
struct otx2_cptpf_dev {
void __iomem *reg_base; /* CPT PF registers start address */
void __iomem *afpf_mbox_base; /* PF-AF mbox start address */
void __iomem *vfpf_mbox_base; /* VF-PF mbox start address */
struct pci_dev *pdev; /* PCI device handle */
struct otx2_cptvf_info vf[OTX2_CPT_MAX_VFS_NUM];
/* AF <=> PF mbox */
struct otx2_mbox afpf_mbox;
struct work_struct afpf_mbox_work;
struct workqueue_struct *afpf_mbox_wq;
/* VF <=> PF mbox */
struct otx2_mbox vfpf_mbox;
struct workqueue_struct *vfpf_mbox_wq;
struct workqueue_struct *flr_wq;
struct cptpf_flr_work *flr_work;
u8 pf_id; /* RVU PF number */
u8 max_vfs; /* Maximum number of VFs supported by CPT */
u8 enabled_vfs; /* Number of enabled VFs */
};
irqreturn_t otx2_cptpf_afpf_mbox_intr(int irq, void *arg);
void otx2_cptpf_afpf_mbox_handler(struct work_struct *work);
irqreturn_t otx2_cptpf_vfpf_mbox_intr(int irq, void *arg);
void otx2_cptpf_vfpf_mbox_handler(struct work_struct *work);
#endif /* __OTX2_CPTPF_H */
......@@ -5,6 +5,127 @@
#include "otx2_cptpf.h"
#include "rvu_reg.h"
static int forward_to_af(struct otx2_cptpf_dev *cptpf,
struct otx2_cptvf_info *vf,
struct mbox_msghdr *req, int size)
{
struct mbox_msghdr *msg;
int ret;
msg = otx2_mbox_alloc_msg(&cptpf->afpf_mbox, 0, size);
if (msg == NULL)
return -ENOMEM;
memcpy((uint8_t *)msg + sizeof(struct mbox_msghdr),
(uint8_t *)req + sizeof(struct mbox_msghdr), size);
msg->id = req->id;
msg->pcifunc = req->pcifunc;
msg->sig = req->sig;
msg->ver = req->ver;
otx2_mbox_msg_send(&cptpf->afpf_mbox, 0);
ret = otx2_mbox_wait_for_rsp(&cptpf->afpf_mbox, 0);
if (ret == -EIO) {
dev_err(&cptpf->pdev->dev, "RVU MBOX timeout.\n");
return ret;
} else if (ret) {
dev_err(&cptpf->pdev->dev, "RVU MBOX error: %d.\n", ret);
return -EFAULT;
}
return 0;
}
static int cptpf_handle_vf_req(struct otx2_cptpf_dev *cptpf,
struct otx2_cptvf_info *vf,
struct mbox_msghdr *req, int size)
{
int err = 0;
/* Check if msg is valid, if not reply with an invalid msg */
if (req->sig != OTX2_MBOX_REQ_SIG)
goto inval_msg;
return forward_to_af(cptpf, vf, req, size);
inval_msg:
otx2_reply_invalid_msg(&cptpf->vfpf_mbox, vf->vf_id, 0, req->id);
otx2_mbox_msg_send(&cptpf->vfpf_mbox, vf->vf_id);
return err;
}
irqreturn_t otx2_cptpf_vfpf_mbox_intr(int __always_unused irq, void *arg)
{
struct otx2_cptpf_dev *cptpf = arg;
struct otx2_cptvf_info *vf;
int i, vf_idx;
u64 intr;
/*
* Check which VF has raised an interrupt and schedule
* corresponding work queue to process the messages
*/
for (i = 0; i < 2; i++) {
/* Read the interrupt bits */
intr = otx2_cpt_read64(cptpf->reg_base, BLKADDR_RVUM, 0,
RVU_PF_VFPF_MBOX_INTX(i));
for (vf_idx = i * 64; vf_idx < cptpf->enabled_vfs; vf_idx++) {
vf = &cptpf->vf[vf_idx];
if (intr & (1ULL << vf->intr_idx)) {
queue_work(cptpf->vfpf_mbox_wq,
&vf->vfpf_mbox_work);
/* Clear the interrupt */
otx2_cpt_write64(cptpf->reg_base, BLKADDR_RVUM,
0, RVU_PF_VFPF_MBOX_INTX(i),
BIT_ULL(vf->intr_idx));
}
}
}
return IRQ_HANDLED;
}
void otx2_cptpf_vfpf_mbox_handler(struct work_struct *work)
{
struct otx2_cptpf_dev *cptpf;
struct otx2_cptvf_info *vf;
struct otx2_mbox_dev *mdev;
struct mbox_hdr *req_hdr;
struct mbox_msghdr *msg;
struct otx2_mbox *mbox;
int offset, i, err;
vf = container_of(work, struct otx2_cptvf_info, vfpf_mbox_work);
cptpf = vf->cptpf;
mbox = &cptpf->vfpf_mbox;
/* sync with mbox memory region */
smp_rmb();
mdev = &mbox->dev[vf->vf_id];
/* Process received mbox messages */
req_hdr = (struct mbox_hdr *)(mdev->mbase + mbox->rx_start);
offset = mbox->rx_start + ALIGN(sizeof(*req_hdr), MBOX_MSG_ALIGN);
for (i = 0; i < req_hdr->num_msgs; i++) {
msg = (struct mbox_msghdr *)(mdev->mbase + offset);
/* Set which VF sent this message based on mbox IRQ */
msg->pcifunc = ((u16)cptpf->pf_id << RVU_PFVF_PF_SHIFT) |
((vf->vf_id + 1) & RVU_PFVF_FUNC_MASK);
err = cptpf_handle_vf_req(cptpf, vf, msg,
msg->next_msgoff - offset);
/*
* Behave as the AF, drop the msg if there is
* no memory, timeout handling also goes here
*/
if (err == -ENOMEM || err == -EIO)
break;
offset = msg->next_msgoff;
}
/* Send mbox responses to VF */
if (mdev->num_msgs)
otx2_mbox_msg_send(mbox, vf->vf_id);
}
irqreturn_t otx2_cptpf_afpf_mbox_intr(int __always_unused irq, void *arg)
{
struct otx2_cptpf_dev *cptpf = arg;
......@@ -50,6 +171,49 @@ static void process_afpf_mbox_msg(struct otx2_cptpf_dev *cptpf,
}
}
static void forward_to_vf(struct otx2_cptpf_dev *cptpf, struct mbox_msghdr *msg,
int vf_id, int size)
{
struct otx2_mbox *vfpf_mbox;
struct mbox_msghdr *fwd;
if (msg->id >= MBOX_MSG_MAX) {
dev_err(&cptpf->pdev->dev,
"MBOX msg with unknown ID %d\n", msg->id);
return;
}
if (msg->sig != OTX2_MBOX_RSP_SIG) {
dev_err(&cptpf->pdev->dev,
"MBOX msg with wrong signature %x, ID %d\n",
msg->sig, msg->id);
return;
}
vfpf_mbox = &cptpf->vfpf_mbox;
vf_id--;
if (vf_id >= cptpf->enabled_vfs) {
dev_err(&cptpf->pdev->dev,
"MBOX msg to unknown VF: %d >= %d\n",
vf_id, cptpf->enabled_vfs);
return;
}
if (msg->id == MBOX_MSG_VF_FLR)
return;
fwd = otx2_mbox_alloc_msg(vfpf_mbox, vf_id, size);
if (!fwd) {
dev_err(&cptpf->pdev->dev,
"Forwarding to VF%d failed.\n", vf_id);
return;
}
memcpy((uint8_t *)fwd + sizeof(struct mbox_msghdr),
(uint8_t *)msg + sizeof(struct mbox_msghdr), size);
fwd->id = msg->id;
fwd->pcifunc = msg->pcifunc;
fwd->sig = msg->sig;
fwd->ver = msg->ver;
fwd->rc = msg->rc;
}
/* Handle mailbox messages received from AF */
void otx2_cptpf_afpf_mbox_handler(struct work_struct *work)
{
......@@ -58,7 +222,7 @@ void otx2_cptpf_afpf_mbox_handler(struct work_struct *work)
struct otx2_mbox_dev *mdev;
struct mbox_hdr *rsp_hdr;
struct mbox_msghdr *msg;
int offset, i;
int offset, vf_id, i;
cptpf = container_of(work, struct otx2_cptpf_dev, afpf_mbox_work);
afpf_mbox = &cptpf->afpf_mbox;
......@@ -72,7 +236,14 @@ void otx2_cptpf_afpf_mbox_handler(struct work_struct *work)
for (i = 0; i < rsp_hdr->num_msgs; i++) {
msg = (struct mbox_msghdr *)(mdev->mbase + afpf_mbox->rx_start +
offset);
vf_id = (msg->pcifunc >> RVU_PFVF_FUNC_SHIFT) &
RVU_PFVF_FUNC_MASK;
if (vf_id > 0)
forward_to_vf(cptpf, msg, vf_id,
msg->next_msgoff - offset);
else
process_afpf_mbox_msg(cptpf, msg);
offset = msg->next_msgoff;
mdev->msgs_acked++;
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment