linux/drivers/net/ethernet/marvell/octeontx2/af/rvu_cpt.c
Srujana Challa ae454086e3 octeontx2-af: add mailbox interface for CPT
On OcteonTX2 SoC, the admin function (AF) is the only one with all
priviliges to configure HW and alloc resources, PFs and it's VFs
have to request AF via mailbox for all their needs. This patch adds
a mailbox interface for CPT PFs and VFs to allocate resources
for cryptography. It also adds hardware CPT AF register defines.

Signed-off-by: Suheil Chandran <schandran@marvell.com>
Signed-off-by: Lukasz Bartosik <lbartosik@marvell.com>
Signed-off-by: Srujana Challa <schalla@marvell.com>
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
2020-11-20 11:01:13 -08:00

234 lines
5.5 KiB
C

// SPDX-License-Identifier: GPL-2.0-only
/* Copyright (C) 2020 Marvell. */
#include <linux/pci.h>
#include "rvu_struct.h"
#include "rvu_reg.h"
#include "mbox.h"
#include "rvu.h"
/* CPT PF device id */
#define PCI_DEVID_OTX2_CPT_PF 0xA0FD
static int get_cpt_pf_num(struct rvu *rvu)
{
int i, domain_nr, cpt_pf_num = -1;
struct pci_dev *pdev;
domain_nr = pci_domain_nr(rvu->pdev->bus);
for (i = 0; i < rvu->hw->total_pfs; i++) {
pdev = pci_get_domain_bus_and_slot(domain_nr, i + 1, 0);
if (!pdev)
continue;
if (pdev->device == PCI_DEVID_OTX2_CPT_PF) {
cpt_pf_num = i;
put_device(&pdev->dev);
break;
}
put_device(&pdev->dev);
}
return cpt_pf_num;
}
static bool is_cpt_pf(struct rvu *rvu, u16 pcifunc)
{
int cpt_pf_num = get_cpt_pf_num(rvu);
if (rvu_get_pf(pcifunc) != cpt_pf_num)
return false;
if (pcifunc & RVU_PFVF_FUNC_MASK)
return false;
return true;
}
static bool is_cpt_vf(struct rvu *rvu, u16 pcifunc)
{
int cpt_pf_num = get_cpt_pf_num(rvu);
if (rvu_get_pf(pcifunc) != cpt_pf_num)
return false;
if (!(pcifunc & RVU_PFVF_FUNC_MASK))
return false;
return true;
}
int rvu_mbox_handler_cpt_lf_alloc(struct rvu *rvu,
struct cpt_lf_alloc_req_msg *req,
struct msg_rsp *rsp)
{
u16 pcifunc = req->hdr.pcifunc;
struct rvu_block *block;
int cptlf, blkaddr;
int num_lfs, slot;
u64 val;
if (req->eng_grpmsk == 0x0)
return CPT_AF_ERR_GRP_INVALID;
blkaddr = rvu_get_blkaddr(rvu, BLKTYPE_CPT, 0);
if (blkaddr < 0)
return blkaddr;
block = &rvu->hw->block[blkaddr];
num_lfs = rvu_get_rsrc_mapcount(rvu_get_pfvf(rvu, pcifunc),
block->addr);
if (!num_lfs)
return CPT_AF_ERR_LF_INVALID;
/* Check if requested 'CPTLF <=> NIXLF' mapping is valid */
if (req->nix_pf_func) {
/* If default, use 'this' CPTLF's PFFUNC */
if (req->nix_pf_func == RVU_DEFAULT_PF_FUNC)
req->nix_pf_func = pcifunc;
if (!is_pffunc_map_valid(rvu, req->nix_pf_func, BLKTYPE_NIX))
return CPT_AF_ERR_NIX_PF_FUNC_INVALID;
}
/* Check if requested 'CPTLF <=> SSOLF' mapping is valid */
if (req->sso_pf_func) {
/* If default, use 'this' CPTLF's PFFUNC */
if (req->sso_pf_func == RVU_DEFAULT_PF_FUNC)
req->sso_pf_func = pcifunc;
if (!is_pffunc_map_valid(rvu, req->sso_pf_func, BLKTYPE_SSO))
return CPT_AF_ERR_SSO_PF_FUNC_INVALID;
}
for (slot = 0; slot < num_lfs; slot++) {
cptlf = rvu_get_lf(rvu, block, pcifunc, slot);
if (cptlf < 0)
return CPT_AF_ERR_LF_INVALID;
/* Set CPT LF group and priority */
val = (u64)req->eng_grpmsk << 48 | 1;
rvu_write64(rvu, blkaddr, CPT_AF_LFX_CTL(cptlf), val);
/* Set CPT LF NIX_PF_FUNC and SSO_PF_FUNC */
val = (u64)req->nix_pf_func << 48 |
(u64)req->sso_pf_func << 32;
rvu_write64(rvu, blkaddr, CPT_AF_LFX_CTL2(cptlf), val);
}
return 0;
}
int rvu_mbox_handler_cpt_lf_free(struct rvu *rvu, struct msg_req *req,
struct msg_rsp *rsp)
{
u16 pcifunc = req->hdr.pcifunc;
struct rvu_block *block;
int cptlf, blkaddr;
int num_lfs, slot;
blkaddr = rvu_get_blkaddr(rvu, BLKTYPE_CPT, 0);
if (blkaddr < 0)
return blkaddr;
block = &rvu->hw->block[blkaddr];
num_lfs = rvu_get_rsrc_mapcount(rvu_get_pfvf(rvu, pcifunc),
block->addr);
if (!num_lfs)
return CPT_AF_ERR_LF_INVALID;
for (slot = 0; slot < num_lfs; slot++) {
cptlf = rvu_get_lf(rvu, block, pcifunc, slot);
if (cptlf < 0)
return CPT_AF_ERR_LF_INVALID;
/* Reset CPT LF group and priority */
rvu_write64(rvu, blkaddr, CPT_AF_LFX_CTL(cptlf), 0x0);
/* Reset CPT LF NIX_PF_FUNC and SSO_PF_FUNC */
rvu_write64(rvu, blkaddr, CPT_AF_LFX_CTL2(cptlf), 0x0);
}
return 0;
}
static bool is_valid_offset(struct rvu *rvu, struct cpt_rd_wr_reg_msg *req)
{
u64 offset = req->reg_offset;
int blkaddr, num_lfs, lf;
struct rvu_block *block;
struct rvu_pfvf *pfvf;
blkaddr = rvu_get_blkaddr(rvu, BLKTYPE_CPT, 0);
/* Registers that can be accessed from PF/VF */
if ((offset & 0xFF000) == CPT_AF_LFX_CTL(0) ||
(offset & 0xFF000) == CPT_AF_LFX_CTL2(0)) {
if (offset & 7)
return false;
lf = (offset & 0xFFF) >> 3;
block = &rvu->hw->block[blkaddr];
pfvf = rvu_get_pfvf(rvu, req->hdr.pcifunc);
num_lfs = rvu_get_rsrc_mapcount(pfvf, block->addr);
if (lf >= num_lfs)
/* Slot is not valid for that PF/VF */
return false;
/* Translate local LF used by VFs to global CPT LF */
lf = rvu_get_lf(rvu, &rvu->hw->block[blkaddr],
req->hdr.pcifunc, lf);
if (lf < 0)
return false;
return true;
} else if (!(req->hdr.pcifunc & RVU_PFVF_FUNC_MASK)) {
/* Registers that can be accessed from PF */
switch (offset) {
case CPT_AF_CTL:
case CPT_AF_PF_FUNC:
case CPT_AF_BLK_RST:
case CPT_AF_CONSTANTS1:
return true;
}
switch (offset & 0xFF000) {
case CPT_AF_EXEX_STS(0):
case CPT_AF_EXEX_CTL(0):
case CPT_AF_EXEX_CTL2(0):
case CPT_AF_EXEX_UCODE_BASE(0):
if (offset & 7)
return false;
break;
default:
return false;
}
return true;
}
return false;
}
int rvu_mbox_handler_cpt_rd_wr_register(struct rvu *rvu,
struct cpt_rd_wr_reg_msg *req,
struct cpt_rd_wr_reg_msg *rsp)
{
int blkaddr;
blkaddr = rvu_get_blkaddr(rvu, BLKTYPE_CPT, 0);
if (blkaddr < 0)
return blkaddr;
/* This message is accepted only if sent from CPT PF/VF */
if (!is_cpt_pf(rvu, req->hdr.pcifunc) &&
!is_cpt_vf(rvu, req->hdr.pcifunc))
return CPT_AF_ERR_ACCESS_DENIED;
rsp->reg_offset = req->reg_offset;
rsp->ret_val = req->ret_val;
rsp->is_write = req->is_write;
if (!is_valid_offset(rvu, req))
return CPT_AF_ERR_ACCESS_DENIED;
if (req->is_write)
rvu_write64(rvu, blkaddr, req->reg_offset, req->val);
else
rsp->val = rvu_read64(rvu, blkaddr, req->reg_offset);
return 0;
}