Commit 23705adb authored by Vamsi Attunuru's avatar Vamsi Attunuru Committed by David S. Miller

octeontx2-af: Enable mkex profile

The following set of NPC registers allow the driver to configure NPC
to generate different key value schemes to compare against packet
payload in MCAM search.

NPC_AF_INTF(0..1)_KEX_CFG
NPC_AF_KEX_LDATA(0..1)_FLAGS_CFG
NPC_AF_INTF(0..1)_LID(0..7)_LT(0..15)_LD(0..1)_CFG
NPC_AF_INTF(0..1)_LDATA(0..1)_FLAGS(0..15)_CFG

Currently, the AF driver populates these registers to
configure the default values to address the most common
use cases such as key generation for channel number + DMAC.

The secure firmware stores different configuration
value of these registers to enable different NPC use case
along with the name for the lookup.

Patch loads profile binary from secure firmware over
the exiting CGX mailbox interface and apply the profile.

AF driver shall fall back to the default configuration
in case of any errors.

The AF consumer driver can know the selected profile
on response to NPC_GET_KEX_CFG mailbox by introducing
mkex_pfl_name in the struct npc_get_kex_cfg_rsp.
Signed-off-by: default avatarVamsi Attunuru <vamsi.attunuru@marvell.com>
Signed-off-by: default avatarJerin Jacob <jerinj@marvell.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent da5d32e1
......@@ -498,6 +498,60 @@ static inline bool cgx_event_is_linkevent(u64 event)
return false;
}
static inline int cgx_fwi_get_mkex_prfl_sz(u64 *prfl_sz,
struct cgx *cgx)
{
u64 req = 0;
u64 resp;
int err;
req = FIELD_SET(CMDREG_ID, CGX_CMD_GET_MKEX_PRFL_SIZE, req);
err = cgx_fwi_cmd_generic(req, &resp, cgx, 0);
if (!err)
*prfl_sz = FIELD_GET(RESP_MKEX_PRFL_SIZE, resp);
return err;
}
static inline int cgx_fwi_get_mkex_prfl_addr(u64 *prfl_addr,
struct cgx *cgx)
{
u64 req = 0;
u64 resp;
int err;
req = FIELD_SET(CMDREG_ID, CGX_CMD_GET_MKEX_PRFL_ADDR, req);
err = cgx_fwi_cmd_generic(req, &resp, cgx, 0);
if (!err)
*prfl_addr = FIELD_GET(RESP_MKEX_PRFL_ADDR, resp);
return err;
}
int cgx_get_mkex_prfl_info(u64 *addr, u64 *size)
{
struct cgx *cgx_dev;
int err;
if (!addr || !size)
return -EINVAL;
cgx_dev = list_first_entry(&cgx_list, struct cgx, cgx_list);
if (!cgx_dev)
return -ENXIO;
err = cgx_fwi_get_mkex_prfl_sz(size, cgx_dev);
if (err)
return -EIO;
err = cgx_fwi_get_mkex_prfl_addr(addr, cgx_dev);
if (err)
return -EIO;
return 0;
}
EXPORT_SYMBOL(cgx_get_mkex_prfl_info);
static irqreturn_t cgx_fwi_event_handler(int irq, void *data)
{
struct lmac *lmac = data;
......
......@@ -111,4 +111,5 @@ int cgx_lmac_internal_loopback(void *cgxd, int lmac_id, bool enable);
int cgx_get_link_info(void *cgxd, int lmac_id,
struct cgx_link_user_info *linfo);
int cgx_lmac_linkup_start(void *cgxd);
int cgx_get_mkex_prfl_info(u64 *addr, u64 *size);
#endif /* CGX_H */
......@@ -78,6 +78,8 @@ enum cgx_cmd_id {
CGX_CMD_LINK_STATE_CHANGE,
CGX_CMD_MODE_CHANGE, /* hot plug support */
CGX_CMD_INTF_SHUTDOWN,
CGX_CMD_GET_MKEX_PRFL_SIZE,
CGX_CMD_GET_MKEX_PRFL_ADDR
};
/* async event ids */
......@@ -137,6 +139,16 @@ enum cgx_cmd_own {
*/
#define RESP_MAC_ADDR GENMASK_ULL(56, 9)
/* Response to cmd ID as CGX_CMD_GET_MKEX_PRFL_SIZE with cmd status as
* CGX_STAT_SUCCESS
*/
#define RESP_MKEX_PRFL_SIZE GENMASK_ULL(63, 9)
/* Response to cmd ID as CGX_CMD_GET_MKEX_PRFL_ADDR with cmd status as
* CGX_STAT_SUCCESS
*/
#define RESP_MKEX_PRFL_ADDR GENMASK_ULL(63, 9)
/* Response to cmd ID - CGX_CMD_LINK_BRING_UP/DOWN, event ID CGX_EVT_LINK_CHANGE
* status can be either CGX_STAT_FAIL or CGX_STAT_SUCCESS
*
......
......@@ -788,6 +788,8 @@ struct npc_get_kex_cfg_rsp {
u64 intf_lid_lt_ld[NPC_MAX_INTF][NPC_MAX_LID][NPC_MAX_LT][NPC_MAX_LD];
/* NPC_AF_INTF(0..1)_LDATA(0..1)_FLAGS(0..15)_CFG */
u64 intf_ld_flags[NPC_MAX_INTF][NPC_MAX_LD][NPC_MAX_LFL];
#define MKEX_NAME_LEN 128
u8 mkex_pfl_name[MKEX_NAME_LEN];
};
#endif /* MBOX_H */
......@@ -265,4 +265,22 @@ struct nix_rx_action {
#define VTAG0_LID_MASK GENMASK_ULL(10, 8)
#define VTAG0_RELPTR_MASK GENMASK_ULL(7, 0)
struct npc_mcam_kex {
/* MKEX Profle Header */
u64 mkex_sign; /* "mcam-kex-profile" (8 bytes/ASCII characters) */
u8 name[MKEX_NAME_LEN]; /* MKEX Profile name */
u64 cpu_model; /* Format as profiled by CPU hardware */
u64 kpu_version; /* KPU firmware/profile version */
u64 reserved; /* Reserved for extension */
/* MKEX Profle Data */
u64 keyx_cfg[NPC_MAX_INTF]; /* NPC_AF_INTF(0..1)_KEX_CFG */
/* NPC_AF_KEX_LDATA(0..1)_FLAGS_CFG */
u64 kex_ld_flags[NPC_MAX_LD];
/* NPC_AF_INTF(0..1)_LID(0..7)_LT(0..15)_LD(0..1)_CFG */
u64 intf_lid_lt_ld[NPC_MAX_INTF][NPC_MAX_LID][NPC_MAX_LT][NPC_MAX_LD];
/* NPC_AF_INTF(0..1)_LDATA(0..1)_FLAGS(0..15)_CFG */
u64 intf_ld_flags[NPC_MAX_INTF][NPC_MAX_LD][NPC_MAX_LFL];
} __packed;
#endif /* NPC_H */
......@@ -52,6 +52,10 @@ MODULE_LICENSE("GPL v2");
MODULE_VERSION(DRV_VERSION);
MODULE_DEVICE_TABLE(pci, rvu_id_table);
static char *mkex_profile; /* MKEX profile name */
module_param(mkex_profile, charp, 0000);
MODULE_PARM_DESC(mkex_profile, "MKEX profile name string");
/* Poll a RVU block's register 'offset', for a 'zero'
* or 'nonzero' at bits specified by 'mask'
*/
......@@ -2359,6 +2363,14 @@ static void rvu_disable_sriov(struct rvu *rvu)
pci_disable_sriov(rvu->pdev);
}
static void rvu_update_module_params(struct rvu *rvu)
{
const char *default_pfl_name = "default";
strscpy(rvu->mkex_pfl_name,
mkex_profile ? mkex_profile : default_pfl_name, MKEX_NAME_LEN);
}
static int rvu_probe(struct pci_dev *pdev, const struct pci_device_id *id)
{
struct device *dev = &pdev->dev;
......@@ -2412,6 +2424,9 @@ static int rvu_probe(struct pci_dev *pdev, const struct pci_device_id *id)
goto err_release_regions;
}
/* Store module params in rvu structure */
rvu_update_module_params(rvu);
/* Check which blocks the HW supports */
rvu_check_block_implemented(rvu);
......
......@@ -261,6 +261,8 @@ struct rvu {
struct workqueue_struct *cgx_evh_wq;
spinlock_t cgx_evq_lock; /* cgx event queue lock */
struct list_head cgx_evq_head; /* cgx event queue head */
char mkex_pfl_name[MKEX_NAME_LEN]; /* Configured MKEX profile name */
};
static inline void rvu_write64(struct rvu *rvu, u64 block, u64 offset, u64 val)
......
......@@ -16,6 +16,7 @@
#include "rvu_reg.h"
#include "rvu.h"
#include "npc.h"
#include "cgx.h"
#include "npc_profile.h"
#define RSVD_MCAM_ENTRIES_PER_PF 2 /* Bcast & Promisc */
......@@ -731,6 +732,111 @@ static void npc_config_ldata_extract(struct rvu *rvu, int blkaddr)
SET_KEX_LD(NIX_INTF_RX, NPC_LID_LD, NPC_LT_LD_TCP, 1, cfg);
}
static void npc_program_mkex_profile(struct rvu *rvu, int blkaddr,
struct npc_mcam_kex *mkex)
{
int lid, lt, ld, fl;
rvu_write64(rvu, blkaddr, NPC_AF_INTFX_KEX_CFG(NIX_INTF_RX),
mkex->keyx_cfg[NIX_INTF_RX]);
rvu_write64(rvu, blkaddr, NPC_AF_INTFX_KEX_CFG(NIX_INTF_TX),
mkex->keyx_cfg[NIX_INTF_TX]);
for (ld = 0; ld < NPC_MAX_LD; ld++)
rvu_write64(rvu, blkaddr, NPC_AF_KEX_LDATAX_FLAGS_CFG(ld),
mkex->kex_ld_flags[ld]);
for (lid = 0; lid < NPC_MAX_LID; lid++) {
for (lt = 0; lt < NPC_MAX_LT; lt++) {
for (ld = 0; ld < NPC_MAX_LD; ld++) {
SET_KEX_LD(NIX_INTF_RX, lid, lt, ld,
mkex->intf_lid_lt_ld[NIX_INTF_RX]
[lid][lt][ld]);
SET_KEX_LD(NIX_INTF_TX, lid, lt, ld,
mkex->intf_lid_lt_ld[NIX_INTF_TX]
[lid][lt][ld]);
}
}
}
for (ld = 0; ld < NPC_MAX_LD; ld++) {
for (fl = 0; fl < NPC_MAX_LFL; fl++) {
SET_KEX_LDFLAGS(NIX_INTF_RX, ld, fl,
mkex->intf_ld_flags[NIX_INTF_RX]
[ld][fl]);
SET_KEX_LDFLAGS(NIX_INTF_TX, ld, fl,
mkex->intf_ld_flags[NIX_INTF_TX]
[ld][fl]);
}
}
}
/* strtoull of "mkexprof" with base:36 */
#define MKEX_SIGN 0x19bbfdbd15f
#define MKEX_END_SIGN 0xdeadbeef
static void npc_load_mkex_profile(struct rvu *rvu, int blkaddr)
{
const char *mkex_profile = rvu->mkex_pfl_name;
struct device *dev = &rvu->pdev->dev;
void __iomem *mkex_prfl_addr = NULL;
struct npc_mcam_kex *mcam_kex;
u64 prfl_addr;
u64 prfl_sz;
/* If user not selected mkex profile */
if (!strncmp(mkex_profile, "default", MKEX_NAME_LEN))
goto load_default;
if (cgx_get_mkex_prfl_info(&prfl_addr, &prfl_sz))
goto load_default;
if (!prfl_addr || !prfl_sz)
goto load_default;
mkex_prfl_addr = ioremap_wc(prfl_addr, prfl_sz);
if (!mkex_prfl_addr)
goto load_default;
mcam_kex = (struct npc_mcam_kex *)mkex_prfl_addr;
while (((s64)prfl_sz > 0) && (mcam_kex->mkex_sign != MKEX_END_SIGN)) {
/* Compare with mkex mod_param name string */
if (mcam_kex->mkex_sign == MKEX_SIGN &&
!strncmp(mcam_kex->name, mkex_profile, MKEX_NAME_LEN)) {
/* Due to an errata (35786) in A0 pass silicon,
* parse nibble enable configuration has to be
* identical for both Rx and Tx interfaces.
*/
if (is_rvu_9xxx_A0(rvu) &&
mcam_kex->keyx_cfg[NIX_INTF_RX] !=
mcam_kex->keyx_cfg[NIX_INTF_TX])
goto load_default;
/* Program selected mkex profile */
npc_program_mkex_profile(rvu, blkaddr, mcam_kex);
goto unmap;
}
mcam_kex++;
prfl_sz -= sizeof(struct npc_mcam_kex);
}
dev_warn(dev, "Failed to load requested profile: %s\n",
rvu->mkex_pfl_name);
load_default:
dev_info(rvu->dev, "Using default mkex profile\n");
/* Config packet data and flags extraction into PARSE result */
npc_config_ldata_extract(rvu, blkaddr);
unmap:
if (mkex_prfl_addr)
iounmap(mkex_prfl_addr);
}
static void npc_config_kpuaction(struct rvu *rvu, int blkaddr,
struct npc_kpu_profile_action *kpuaction,
int kpu, int entry, bool pkind)
......@@ -1068,8 +1174,8 @@ int rvu_npc_init(struct rvu *rvu)
if (err)
return err;
/* Config packet data and flags extraction into PARSE result */
npc_config_ldata_extract(rvu, blkaddr);
/* Configure MKEX profile */
npc_load_mkex_profile(rvu, blkaddr);
/* Set TX miss action to UCAST_DEFAULT i.e
* transmit the packet on NIX LF SQ's default channel.
......@@ -2077,6 +2183,7 @@ int rvu_mbox_handler_npc_get_kex_cfg(struct rvu *rvu, struct msg_req *req,
GET_KEX_LDFLAGS(NIX_INTF_TX, ld, fl);
}
}
memcpy(rsp->mkex_pfl_name, rvu->mkex_pfl_name, MKEX_NAME_LEN);
return 0;
}
......
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