mirror of
https://github.com/torvalds/linux.git
synced 2026-07-28 10:09:10 +02:00
octeontx2-af: npc: Support for custom KPU profile from filesystem
Flashing updated firmware on deployed devices is cumbersome. Provide a mechanism to load a custom KPU (Key Parse Unit) profile directly from the filesystem at module load time. When the rvu_af module is loaded with the kpu_profile parameter, the specified profile is read from /lib/firmware/kpu and programmed into the KPU registers. Add npc_kpu_profile_cam2 for the extended cam format used by filesystem-loaded profiles and support ptype/ptype_mask in npc_config_kpucam when profile->from_fs is set. Usage: 1. Copy the KPU profile file to /lib/firmware/kpu. 2. Build OCTEONTX2_AF as a module. 3. Load: insmod rvu_af.ko kpu_profile=<profile_name> Signed-off-by: Ratheesh Kannoth <rkannoth@marvell.com> Link: https://patch.msgid.link/20260609040453.711932-8-rkannoth@marvell.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
parent
aac055dbc0
commit
c0c9ac8815
|
|
@ -521,13 +521,17 @@ npc_program_single_kpm_profile(struct rvu *rvu, int blkaddr,
|
|||
int kpm, int start_entry,
|
||||
const struct npc_kpu_profile *profile)
|
||||
{
|
||||
int num_cam_entries, num_action_entries;
|
||||
int entry, num_entries, max_entries;
|
||||
u64 idx;
|
||||
|
||||
if (profile->cam_entries != profile->action_entries) {
|
||||
num_cam_entries = npc_get_num_kpu_cam_entries(rvu, profile);
|
||||
num_action_entries = npc_get_num_kpu_action_entries(rvu, profile);
|
||||
|
||||
if (num_cam_entries != num_action_entries) {
|
||||
dev_err(rvu->dev,
|
||||
"kpm%d: CAM and action entries [%d != %d] not equal\n",
|
||||
kpm, profile->cam_entries, profile->action_entries);
|
||||
kpm, num_cam_entries, num_action_entries);
|
||||
|
||||
WARN(1, "Fatal error\n");
|
||||
return;
|
||||
|
|
@ -536,16 +540,18 @@ npc_program_single_kpm_profile(struct rvu *rvu, int blkaddr,
|
|||
max_entries = rvu->hw->npc_kpu_entries / 2;
|
||||
entry = start_entry;
|
||||
/* Program CAM match entries for previous kpm extracted data */
|
||||
num_entries = min_t(int, profile->cam_entries, max_entries);
|
||||
num_entries = min_t(int, num_cam_entries, max_entries);
|
||||
for (idx = 0; entry < num_entries + start_entry; entry++, idx++)
|
||||
npc_config_kpmcam(rvu, blkaddr, &profile->cam[idx],
|
||||
npc_config_kpmcam(rvu, blkaddr,
|
||||
npc_get_kpu_cam_nth_entry(rvu, profile, idx),
|
||||
kpm, entry);
|
||||
|
||||
entry = start_entry;
|
||||
/* Program this kpm's actions */
|
||||
num_entries = min_t(int, profile->action_entries, max_entries);
|
||||
num_entries = min_t(int, num_action_entries, max_entries);
|
||||
for (idx = 0; entry < num_entries + start_entry; entry++, idx++)
|
||||
npc_config_kpmaction(rvu, blkaddr, &profile->action[idx],
|
||||
npc_config_kpmaction(rvu, blkaddr,
|
||||
npc_get_kpu_action_nth_entry(rvu, profile, idx),
|
||||
kpm, entry, false);
|
||||
}
|
||||
|
||||
|
|
@ -611,20 +617,23 @@ npc_enable_kpm_entry(struct rvu *rvu, int blkaddr, int kpm, int num_entries)
|
|||
static void npc_program_kpm_profile(struct rvu *rvu, int blkaddr, int num_kpms)
|
||||
{
|
||||
const struct npc_kpu_profile *profile1, *profile2;
|
||||
int pfl1_num_cam_entries, pfl2_num_cam_entries;
|
||||
int idx, total_cam_entries;
|
||||
|
||||
for (idx = 0; idx < num_kpms; idx++) {
|
||||
profile1 = &rvu->kpu.kpu[idx];
|
||||
pfl1_num_cam_entries = npc_get_num_kpu_cam_entries(rvu, profile1);
|
||||
npc_program_single_kpm_profile(rvu, blkaddr, idx, 0, profile1);
|
||||
profile2 = &rvu->kpu.kpu[idx + KPU_OFFSET];
|
||||
pfl2_num_cam_entries = npc_get_num_kpu_cam_entries(rvu, profile2);
|
||||
|
||||
npc_program_single_kpm_profile(rvu, blkaddr, idx,
|
||||
profile1->cam_entries,
|
||||
pfl1_num_cam_entries,
|
||||
profile2);
|
||||
total_cam_entries = profile1->cam_entries +
|
||||
profile2->cam_entries;
|
||||
total_cam_entries = pfl1_num_cam_entries + pfl2_num_cam_entries;
|
||||
npc_enable_kpm_entry(rvu, blkaddr, idx, total_cam_entries);
|
||||
rvu_write64(rvu, blkaddr, NPC_AF_KPMX_PASS2_OFFSET(idx),
|
||||
profile1->cam_entries);
|
||||
pfl1_num_cam_entries);
|
||||
/* Enable the KPUs associated with this KPM */
|
||||
rvu_write64(rvu, blkaddr, NPC_AF_KPUX_CFG(idx), 0x01);
|
||||
rvu_write64(rvu, blkaddr, NPC_AF_KPUX_CFG(idx + KPU_OFFSET),
|
||||
|
|
@ -634,6 +643,7 @@ static void npc_program_kpm_profile(struct rvu *rvu, int blkaddr, int num_kpms)
|
|||
|
||||
void npc_cn20k_parser_profile_init(struct rvu *rvu, int blkaddr)
|
||||
{
|
||||
struct npc_kpu_profile_action *act;
|
||||
struct rvu_hwinfo *hw = rvu->hw;
|
||||
int num_pkinds, idx;
|
||||
|
||||
|
|
@ -665,9 +675,15 @@ void npc_cn20k_parser_profile_init(struct rvu *rvu, int blkaddr)
|
|||
num_pkinds = rvu->kpu.pkinds;
|
||||
num_pkinds = min_t(int, hw->npc_pkinds, num_pkinds);
|
||||
|
||||
for (idx = 0; idx < num_pkinds; idx++)
|
||||
npc_config_kpmaction(rvu, blkaddr, &rvu->kpu.ikpu[idx],
|
||||
/* Cn20k does not support Custom profile from filesystem */
|
||||
for (idx = 0; idx < num_pkinds; idx++) {
|
||||
act = npc_get_ikpu_nth_entry(rvu, idx);
|
||||
if (!act)
|
||||
continue;
|
||||
|
||||
npc_config_kpmaction(rvu, blkaddr, act,
|
||||
0, idx, true);
|
||||
}
|
||||
|
||||
/* Program KPM CAM and Action profiles */
|
||||
npc_program_kpm_profile(rvu, blkaddr, hw->npc_kpms);
|
||||
|
|
@ -679,7 +695,7 @@ struct npc_priv_t *npc_priv_get(void)
|
|||
}
|
||||
|
||||
static void npc_program_mkex_rx(struct rvu *rvu, int blkaddr,
|
||||
struct npc_mcam_kex_extr *mkex_extr,
|
||||
const struct npc_mcam_kex_extr *mkex_extr,
|
||||
u8 intf)
|
||||
{
|
||||
u8 num_extr = rvu->hw->npc_kex_extr;
|
||||
|
|
@ -708,7 +724,7 @@ static void npc_program_mkex_rx(struct rvu *rvu, int blkaddr,
|
|||
}
|
||||
|
||||
static void npc_program_mkex_tx(struct rvu *rvu, int blkaddr,
|
||||
struct npc_mcam_kex_extr *mkex_extr,
|
||||
const struct npc_mcam_kex_extr *mkex_extr,
|
||||
u8 intf)
|
||||
{
|
||||
u8 num_extr = rvu->hw->npc_kex_extr;
|
||||
|
|
@ -737,7 +753,7 @@ static void npc_program_mkex_tx(struct rvu *rvu, int blkaddr,
|
|||
}
|
||||
|
||||
static void npc_program_mkex_profile(struct rvu *rvu, int blkaddr,
|
||||
struct npc_mcam_kex_extr *mkex_extr)
|
||||
const struct npc_mcam_kex_extr *mkex_extr)
|
||||
{
|
||||
struct rvu_hwinfo *hw = rvu->hw;
|
||||
u8 intf;
|
||||
|
|
@ -1626,8 +1642,8 @@ npc_cn20k_update_action_entries_n_flags(struct rvu *rvu,
|
|||
int npc_cn20k_apply_custom_kpu(struct rvu *rvu,
|
||||
struct npc_kpu_profile_adapter *profile)
|
||||
{
|
||||
const struct npc_cn20k_kpu_profile_fwdata *fw = rvu->kpu_fwdata;
|
||||
size_t hdr_sz = sizeof(struct npc_cn20k_kpu_profile_fwdata);
|
||||
struct npc_cn20k_kpu_profile_fwdata *fw = rvu->kpu_fwdata;
|
||||
struct npc_kpu_profile_action *action;
|
||||
struct npc_kpu_profile_cam *cam;
|
||||
struct npc_kpu_fwdata *fw_kpu;
|
||||
|
|
@ -1672,8 +1688,15 @@ int npc_cn20k_apply_custom_kpu(struct rvu *rvu,
|
|||
}
|
||||
|
||||
/* Verify if profile fits the HW */
|
||||
if (fw->kpus > rvu->hw->npc_kpus) {
|
||||
dev_warn(rvu->dev, "Not enough KPUs: %d > %d\n", fw->kpus,
|
||||
rvu->hw->npc_kpus);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Check if there is enough memory */
|
||||
if (fw->kpus > profile->kpus) {
|
||||
dev_warn(rvu->dev, "Not enough KPUs: %d > %ld\n", fw->kpus,
|
||||
dev_warn(rvu->dev, "Not enough KPUs: %d > %zu\n", fw->kpus,
|
||||
profile->kpus);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -267,6 +267,19 @@ struct npc_kpu_profile_cam {
|
|||
u16 dp2_mask;
|
||||
} __packed;
|
||||
|
||||
struct npc_kpu_profile_cam2 {
|
||||
u8 state;
|
||||
u8 state_mask;
|
||||
u16 dp0;
|
||||
u16 dp0_mask;
|
||||
u16 dp1;
|
||||
u16 dp1_mask;
|
||||
u16 dp2;
|
||||
u16 dp2_mask;
|
||||
u8 ptype;
|
||||
u8 ptype_mask;
|
||||
} __packed;
|
||||
|
||||
struct npc_kpu_profile_action {
|
||||
u8 errlev;
|
||||
u8 errcode;
|
||||
|
|
@ -292,6 +305,10 @@ struct npc_kpu_profile {
|
|||
int action_entries;
|
||||
struct npc_kpu_profile_cam *cam;
|
||||
struct npc_kpu_profile_action *action;
|
||||
int cam_entries2;
|
||||
int action_entries2;
|
||||
struct npc_kpu_profile_action *action2;
|
||||
struct npc_kpu_profile_cam2 *cam2;
|
||||
};
|
||||
|
||||
/* NPC KPU register formats */
|
||||
|
|
|
|||
|
|
@ -553,17 +553,19 @@ struct npc_kpu_profile_adapter {
|
|||
const char *name;
|
||||
u64 version;
|
||||
const struct npc_lt_def_cfg *lt_def;
|
||||
const struct npc_kpu_profile_action *ikpu; /* array[pkinds] */
|
||||
const struct npc_kpu_profile *kpu; /* array[kpus] */
|
||||
struct npc_kpu_profile_action *ikpu; /* array[pkinds] */
|
||||
struct npc_kpu_profile_action *ikpu2; /* array[pkinds] */
|
||||
struct npc_kpu_profile *kpu; /* array[kpus] */
|
||||
union npc_mcam_key_prfl {
|
||||
struct npc_mcam_kex *mkex;
|
||||
const struct npc_mcam_kex *mkex;
|
||||
/* used for cn9k and cn10k */
|
||||
struct npc_mcam_kex_extr *mkex_extr; /* used for cn20k */
|
||||
const struct npc_mcam_kex_extr *mkex_extr; /* used for cn20k */
|
||||
} mcam_kex_prfl;
|
||||
struct npc_mcam_kex_hash *mkex_hash;
|
||||
bool custom;
|
||||
size_t pkinds;
|
||||
size_t kpus;
|
||||
bool from_fs;
|
||||
};
|
||||
|
||||
#define RVU_SWITCH_LBK_CHAN 63
|
||||
|
|
@ -634,7 +636,7 @@ struct rvu {
|
|||
|
||||
/* Firmware data */
|
||||
struct rvu_fwdata *fwdata;
|
||||
void *kpu_fwdata;
|
||||
const void *kpu_fwdata;
|
||||
size_t kpu_fwdata_sz;
|
||||
void __iomem *kpu_prfl_addr;
|
||||
|
||||
|
|
|
|||
|
|
@ -1495,7 +1495,8 @@ void rvu_npc_free_mcam_entries(struct rvu *rvu, u16 pcifunc, int nixlf)
|
|||
}
|
||||
|
||||
static void npc_program_mkex_rx(struct rvu *rvu, int blkaddr,
|
||||
struct npc_mcam_kex *mkex, u8 intf)
|
||||
const struct npc_mcam_kex *mkex,
|
||||
u8 intf)
|
||||
{
|
||||
int lid, lt, ld, fl;
|
||||
|
||||
|
|
@ -1524,7 +1525,8 @@ static void npc_program_mkex_rx(struct rvu *rvu, int blkaddr,
|
|||
}
|
||||
|
||||
static void npc_program_mkex_tx(struct rvu *rvu, int blkaddr,
|
||||
struct npc_mcam_kex *mkex, u8 intf)
|
||||
const struct npc_mcam_kex *mkex,
|
||||
u8 intf)
|
||||
{
|
||||
int lid, lt, ld, fl;
|
||||
|
||||
|
|
@ -1553,7 +1555,7 @@ static void npc_program_mkex_tx(struct rvu *rvu, int blkaddr,
|
|||
}
|
||||
|
||||
static void npc_program_mkex_profile(struct rvu *rvu, int blkaddr,
|
||||
struct npc_mcam_kex *mkex)
|
||||
const struct npc_mcam_kex *mkex)
|
||||
{
|
||||
struct rvu_hwinfo *hw = rvu->hw;
|
||||
u8 intf;
|
||||
|
|
@ -1693,8 +1695,12 @@ static void npc_config_kpucam(struct rvu *rvu, int blkaddr,
|
|||
const struct npc_kpu_profile_cam *kpucam,
|
||||
int kpu, int entry)
|
||||
{
|
||||
const struct npc_kpu_profile_cam2 *kpucam2 = (void *)kpucam;
|
||||
struct npc_kpu_profile_adapter *profile = &rvu->kpu;
|
||||
struct npc_kpu_cam cam0 = {0};
|
||||
struct npc_kpu_cam cam1 = {0};
|
||||
u64 *val = (u64 *)&cam1;
|
||||
u64 *mask = (u64 *)&cam0;
|
||||
|
||||
cam1.state = kpucam->state & kpucam->state_mask;
|
||||
cam1.dp0_data = kpucam->dp0 & kpucam->dp0_mask;
|
||||
|
|
@ -1706,6 +1712,14 @@ static void npc_config_kpucam(struct rvu *rvu, int blkaddr,
|
|||
cam0.dp1_data = ~kpucam->dp1 & kpucam->dp1_mask;
|
||||
cam0.dp2_data = ~kpucam->dp2 & kpucam->dp2_mask;
|
||||
|
||||
if (profile->from_fs) {
|
||||
u8 ptype = kpucam2->ptype;
|
||||
u8 pmask = kpucam2->ptype_mask;
|
||||
|
||||
*val |= FIELD_PREP(GENMASK_ULL(57, 56), ptype & pmask);
|
||||
*mask |= FIELD_PREP(GENMASK_ULL(57, 56), ~ptype & pmask);
|
||||
}
|
||||
|
||||
rvu_write64(rvu, blkaddr,
|
||||
NPC_AF_KPUX_ENTRYX_CAMX(kpu, entry, 0), *(u64 *)&cam0);
|
||||
rvu_write64(rvu, blkaddr,
|
||||
|
|
@ -1717,34 +1731,104 @@ u64 npc_enable_mask(int count)
|
|||
return (((count) < 64) ? ~(BIT_ULL(count) - 1) : (0x00ULL));
|
||||
}
|
||||
|
||||
struct npc_kpu_profile_action *
|
||||
npc_get_ikpu_nth_entry(struct rvu *rvu, int n)
|
||||
{
|
||||
struct npc_kpu_profile_adapter *profile = &rvu->kpu;
|
||||
|
||||
if (profile->from_fs)
|
||||
return &profile->ikpu2[n];
|
||||
|
||||
return &profile->ikpu[n];
|
||||
}
|
||||
|
||||
int
|
||||
npc_get_num_kpu_cam_entries(struct rvu *rvu,
|
||||
const struct npc_kpu_profile *kpu_pfl)
|
||||
{
|
||||
struct npc_kpu_profile_adapter *profile = &rvu->kpu;
|
||||
|
||||
if (profile->from_fs)
|
||||
return kpu_pfl->cam_entries2;
|
||||
|
||||
return kpu_pfl->cam_entries;
|
||||
}
|
||||
|
||||
struct npc_kpu_profile_cam *
|
||||
npc_get_kpu_cam_nth_entry(struct rvu *rvu,
|
||||
const struct npc_kpu_profile *kpu_pfl, int n)
|
||||
{
|
||||
struct npc_kpu_profile_adapter *profile = &rvu->kpu;
|
||||
|
||||
if (profile->from_fs)
|
||||
return (void *)&kpu_pfl->cam2[n];
|
||||
|
||||
return (void *)&kpu_pfl->cam[n];
|
||||
}
|
||||
|
||||
int
|
||||
npc_get_num_kpu_action_entries(struct rvu *rvu,
|
||||
const struct npc_kpu_profile *kpu_pfl)
|
||||
{
|
||||
struct npc_kpu_profile_adapter *profile = &rvu->kpu;
|
||||
|
||||
if (profile->from_fs)
|
||||
return kpu_pfl->action_entries2;
|
||||
|
||||
return kpu_pfl->action_entries;
|
||||
}
|
||||
|
||||
struct npc_kpu_profile_action *
|
||||
npc_get_kpu_action_nth_entry(struct rvu *rvu,
|
||||
const struct npc_kpu_profile *kpu_pfl,
|
||||
int n)
|
||||
{
|
||||
struct npc_kpu_profile_adapter *profile = &rvu->kpu;
|
||||
|
||||
if (profile->from_fs)
|
||||
return (void *)&kpu_pfl->action2[n];
|
||||
|
||||
return (void *)&kpu_pfl->action[n];
|
||||
}
|
||||
|
||||
static void npc_program_kpu_profile(struct rvu *rvu, int blkaddr, int kpu,
|
||||
const struct npc_kpu_profile *profile)
|
||||
{
|
||||
int num_cam_entries, num_action_entries;
|
||||
int entry, num_entries, max_entries;
|
||||
u64 entry_mask;
|
||||
|
||||
if (profile->cam_entries != profile->action_entries) {
|
||||
num_cam_entries = npc_get_num_kpu_cam_entries(rvu, profile);
|
||||
num_action_entries = npc_get_num_kpu_action_entries(rvu, profile);
|
||||
|
||||
if (num_cam_entries != num_action_entries) {
|
||||
dev_err(rvu->dev,
|
||||
"KPU%d: CAM and action entries [%d != %d] not equal\n",
|
||||
kpu, profile->cam_entries, profile->action_entries);
|
||||
kpu, num_cam_entries, num_action_entries);
|
||||
}
|
||||
|
||||
max_entries = rvu->hw->npc_kpu_entries;
|
||||
|
||||
WARN(num_cam_entries > max_entries,
|
||||
"KPU%u: err: hw max entries=%u, input entries=%u\n",
|
||||
kpu, rvu->hw->npc_kpu_entries, num_cam_entries);
|
||||
|
||||
/* Program CAM match entries for previous KPU extracted data */
|
||||
num_entries = min_t(int, profile->cam_entries, max_entries);
|
||||
num_entries = min_t(int, num_cam_entries, max_entries);
|
||||
for (entry = 0; entry < num_entries; entry++)
|
||||
npc_config_kpucam(rvu, blkaddr,
|
||||
&profile->cam[entry], kpu, entry);
|
||||
(void *)npc_get_kpu_cam_nth_entry(rvu, profile, entry),
|
||||
kpu, entry);
|
||||
|
||||
/* Program this KPU's actions */
|
||||
num_entries = min_t(int, profile->action_entries, max_entries);
|
||||
num_entries = min_t(int, num_action_entries, max_entries);
|
||||
for (entry = 0; entry < num_entries; entry++)
|
||||
npc_config_kpuaction(rvu, blkaddr, &profile->action[entry],
|
||||
npc_config_kpuaction(rvu, blkaddr,
|
||||
(void *)npc_get_kpu_action_nth_entry(rvu, profile, entry),
|
||||
kpu, entry, false);
|
||||
|
||||
/* Enable all programmed entries */
|
||||
num_entries = min_t(int, profile->action_entries, profile->cam_entries);
|
||||
num_entries = min_t(int, num_action_entries, num_cam_entries);
|
||||
entry_mask = npc_enable_mask(num_entries);
|
||||
/* Disable first KPU_MAX_CST_ENT entries for built-in profile */
|
||||
if (!rvu->kpu.custom)
|
||||
|
|
@ -1788,26 +1872,175 @@ static void npc_prepare_default_kpu(struct rvu *rvu,
|
|||
npc_cn20k_update_action_entries_n_flags(rvu, profile);
|
||||
}
|
||||
|
||||
static int npc_apply_custom_kpu(struct rvu *rvu,
|
||||
struct npc_kpu_profile_adapter *profile)
|
||||
static int npc_alloc_kpu_cam2_n_action2(struct rvu *rvu, int kpu_num,
|
||||
int num_entries)
|
||||
{
|
||||
struct npc_kpu_profile_adapter *adapter = &rvu->kpu;
|
||||
struct npc_kpu_profile *kpu;
|
||||
|
||||
kpu = &adapter->kpu[kpu_num];
|
||||
|
||||
kpu->cam2 = devm_kcalloc(rvu->dev, num_entries,
|
||||
sizeof(*kpu->cam2), GFP_KERNEL);
|
||||
if (!kpu->cam2)
|
||||
return -ENOMEM;
|
||||
|
||||
kpu->action2 = devm_kcalloc(rvu->dev, num_entries,
|
||||
sizeof(*kpu->action2), GFP_KERNEL);
|
||||
if (!kpu->action2)
|
||||
return -ENOMEM;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int npc_apply_custom_kpu_from_fw(struct rvu *rvu,
|
||||
struct npc_kpu_profile_adapter *profile)
|
||||
{
|
||||
size_t hdr_sz = sizeof(struct npc_kpu_profile_fwdata), offset = 0;
|
||||
const struct npc_kpu_profile_fwdata *fw;
|
||||
struct npc_kpu_profile_action *action;
|
||||
struct npc_kpu_profile_fwdata *fw;
|
||||
struct npc_kpu_profile_cam *cam;
|
||||
struct npc_kpu_fwdata *fw_kpu;
|
||||
int entries;
|
||||
u16 kpu, entry;
|
||||
int entries, entry, kpu;
|
||||
|
||||
fw = rvu->kpu_fwdata;
|
||||
|
||||
for (kpu = 0; kpu < fw->kpus; kpu++) {
|
||||
if (rvu->kpu_fwdata_sz < hdr_sz + offset) {
|
||||
dev_warn(rvu->dev,
|
||||
"Profile size mismatch on KPU%i parsing\n",
|
||||
kpu + 1);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
fw_kpu = (struct npc_kpu_fwdata *)(fw->data + offset);
|
||||
if (fw_kpu->entries < 0) {
|
||||
dev_warn(rvu->dev,
|
||||
"Profile entries is negative on KPU%i parsing\n",
|
||||
kpu + 1);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (fw_kpu->entries > KPU_MAX_CST_ENT)
|
||||
dev_warn(rvu->dev,
|
||||
"Too many custom entries on KPU%d: %d > %d\n",
|
||||
kpu, fw_kpu->entries, KPU_MAX_CST_ENT);
|
||||
entries = min_t(int, fw_kpu->entries, KPU_MAX_CST_ENT);
|
||||
cam = (struct npc_kpu_profile_cam *)fw_kpu->data;
|
||||
offset += sizeof(*fw_kpu) + fw_kpu->entries * sizeof(*cam);
|
||||
action = (struct npc_kpu_profile_action *)(fw->data + offset);
|
||||
offset += fw_kpu->entries * sizeof(*action);
|
||||
if (rvu->kpu_fwdata_sz < hdr_sz + offset) {
|
||||
dev_warn(rvu->dev,
|
||||
"Profile size mismatch on KPU%i parsing.\n",
|
||||
kpu + 1);
|
||||
return -EINVAL;
|
||||
}
|
||||
for (entry = 0; entry < entries; entry++) {
|
||||
profile->kpu[kpu].cam[entry] = cam[entry];
|
||||
profile->kpu[kpu].action[entry] = action[entry];
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int npc_apply_custom_kpu_from_fs(struct rvu *rvu,
|
||||
struct npc_kpu_profile_adapter *profile)
|
||||
{
|
||||
size_t hdr_sz = sizeof(struct npc_kpu_profile_fwdata), offset = 0;
|
||||
const struct npc_kpu_profile_fwdata *fw;
|
||||
struct npc_kpu_profile_action *action;
|
||||
struct npc_kpu_profile_cam2 *cam2;
|
||||
struct npc_kpu_fwdata *fw_kpu;
|
||||
int entries, ret, entry, kpu;
|
||||
|
||||
fw = rvu->kpu_fwdata;
|
||||
|
||||
/* Binary blob contains ikpu actions entries at start of data[0] */
|
||||
profile->ikpu2 = devm_kcalloc(rvu->dev, 1,
|
||||
sizeof(ikpu_action_entries),
|
||||
GFP_KERNEL);
|
||||
if (!profile->ikpu2)
|
||||
return -ENOMEM;
|
||||
|
||||
action = (struct npc_kpu_profile_action *)(fw->data + offset);
|
||||
|
||||
if (rvu->kpu_fwdata_sz < hdr_sz + sizeof(ikpu_action_entries))
|
||||
return -EINVAL;
|
||||
|
||||
/* The firmware layout does dependent on the internal size of
|
||||
* ikpu_action_entries.
|
||||
*/
|
||||
memcpy((void *)profile->ikpu2, action, sizeof(ikpu_action_entries));
|
||||
offset += sizeof(ikpu_action_entries);
|
||||
|
||||
for (kpu = 0; kpu < fw->kpus; kpu++) {
|
||||
if (rvu->kpu_fwdata_sz < hdr_sz + offset + sizeof(*fw_kpu)) {
|
||||
dev_warn(rvu->dev,
|
||||
"profile size mismatch on kpu%i parsing\n",
|
||||
kpu + 1);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
fw_kpu = (struct npc_kpu_fwdata *)(fw->data + offset);
|
||||
if (fw_kpu->entries <= 0) {
|
||||
dev_warn(rvu->dev,
|
||||
"Invalid kpu entries on KPU%d\n", kpu);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
entries = min_t(int, fw_kpu->entries, rvu->hw->npc_kpu_entries);
|
||||
dev_info(rvu->dev,
|
||||
"Loading %u entries on KPU%d\n", entries, kpu);
|
||||
|
||||
cam2 = (struct npc_kpu_profile_cam2 *)fw_kpu->data;
|
||||
offset += sizeof(*fw_kpu) + fw_kpu->entries * sizeof(*cam2);
|
||||
action = (struct npc_kpu_profile_action *)(fw->data + offset);
|
||||
offset += fw_kpu->entries * sizeof(*action);
|
||||
if (rvu->kpu_fwdata_sz < hdr_sz + offset) {
|
||||
dev_warn(rvu->dev,
|
||||
"profile size mismatch on kpu%i parsing.\n",
|
||||
kpu + 1);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
profile->kpu[kpu].cam_entries2 = entries;
|
||||
profile->kpu[kpu].action_entries2 = entries;
|
||||
ret = npc_alloc_kpu_cam2_n_action2(rvu, kpu, entries);
|
||||
if (ret) {
|
||||
dev_warn(rvu->dev,
|
||||
"profile entry allocation failed for kpu=%d for %d entries\n",
|
||||
kpu, entries);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
for (entry = 0; entry < entries; entry++) {
|
||||
profile->kpu[kpu].cam2[entry] = cam2[entry];
|
||||
profile->kpu[kpu].action2[entry] = action[entry];
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int npc_apply_custom_kpu(struct rvu *rvu,
|
||||
struct npc_kpu_profile_adapter *profile,
|
||||
bool from_fs, int *fw_kpus)
|
||||
{
|
||||
size_t hdr_sz = sizeof(struct npc_kpu_profile_fwdata);
|
||||
const struct npc_kpu_profile_fwdata *fw;
|
||||
struct npc_kpu_profile_fwdata *sfw;
|
||||
|
||||
if (is_cn20k(rvu->pdev))
|
||||
return npc_cn20k_apply_custom_kpu(rvu, profile);
|
||||
|
||||
fw = rvu->kpu_fwdata;
|
||||
|
||||
if (rvu->kpu_fwdata_sz < hdr_sz) {
|
||||
dev_warn(rvu->dev, "Invalid KPU profile size\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
fw = rvu->kpu_fwdata;
|
||||
if (le64_to_cpu(fw->signature) != KPU_SIGN) {
|
||||
dev_warn(rvu->dev, "Invalid KPU profile signature %llx\n",
|
||||
fw->signature);
|
||||
|
|
@ -1835,42 +2068,38 @@ static int npc_apply_custom_kpu(struct rvu *rvu,
|
|||
return -EINVAL;
|
||||
}
|
||||
/* Verify if profile fits the HW */
|
||||
if (fw->kpus > rvu->hw->npc_kpus) {
|
||||
dev_warn(rvu->dev, "Not enough KPUs: %d > %d\n", fw->kpus,
|
||||
rvu->hw->npc_kpus);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Check if there is enough memory for fw loading.
|
||||
* Check if there is enough entries for profile->kpu[] to
|
||||
* set cam_entries2 and action_entries2
|
||||
*/
|
||||
if (fw->kpus > profile->kpus) {
|
||||
dev_warn(rvu->dev, "Not enough KPUs: %d > %ld\n", fw->kpus,
|
||||
dev_warn(rvu->dev, "Not enough KPUs: %d > %zu\n", fw->kpus,
|
||||
profile->kpus);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
*fw_kpus = fw->kpus;
|
||||
|
||||
sfw = devm_kcalloc(rvu->dev, 1, sizeof(*sfw), GFP_KERNEL);
|
||||
if (!sfw)
|
||||
return -ENOMEM;
|
||||
|
||||
memcpy(sfw, fw, sizeof(*sfw));
|
||||
|
||||
profile->custom = 1;
|
||||
profile->name = fw->name;
|
||||
profile->name = sfw->name;
|
||||
profile->version = le64_to_cpu(fw->version);
|
||||
profile->mcam_kex_prfl.mkex = &fw->mkex;
|
||||
profile->lt_def = &fw->lt_def;
|
||||
profile->mcam_kex_prfl.mkex = &sfw->mkex;
|
||||
profile->lt_def = &sfw->lt_def;
|
||||
|
||||
for (kpu = 0; kpu < fw->kpus; kpu++) {
|
||||
fw_kpu = (struct npc_kpu_fwdata *)(fw->data + offset);
|
||||
if (fw_kpu->entries > KPU_MAX_CST_ENT)
|
||||
dev_warn(rvu->dev,
|
||||
"Too many custom entries on KPU%d: %d > %d\n",
|
||||
kpu, fw_kpu->entries, KPU_MAX_CST_ENT);
|
||||
entries = min(fw_kpu->entries, KPU_MAX_CST_ENT);
|
||||
cam = (struct npc_kpu_profile_cam *)fw_kpu->data;
|
||||
offset += sizeof(*fw_kpu) + fw_kpu->entries * sizeof(*cam);
|
||||
action = (struct npc_kpu_profile_action *)(fw->data + offset);
|
||||
offset += fw_kpu->entries * sizeof(*action);
|
||||
if (rvu->kpu_fwdata_sz < hdr_sz + offset) {
|
||||
dev_warn(rvu->dev,
|
||||
"Profile size mismatch on KPU%i parsing.\n",
|
||||
kpu + 1);
|
||||
return -EINVAL;
|
||||
}
|
||||
for (entry = 0; entry < entries; entry++) {
|
||||
profile->kpu[kpu].cam[entry] = cam[entry];
|
||||
profile->kpu[kpu].action[entry] = action[entry];
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
return from_fs ? npc_apply_custom_kpu_from_fs(rvu, profile) :
|
||||
npc_apply_custom_kpu_from_fw(rvu, profile);
|
||||
}
|
||||
|
||||
static int npc_load_kpu_prfl_img(struct rvu *rvu, void __iomem *prfl_addr,
|
||||
|
|
@ -1958,45 +2187,19 @@ static int npc_load_kpu_profile_fwdb(struct rvu *rvu, const char *kpu_profile)
|
|||
return ret;
|
||||
}
|
||||
|
||||
void npc_load_kpu_profile(struct rvu *rvu)
|
||||
static int npc_load_kpu_profile_from_fw(struct rvu *rvu)
|
||||
{
|
||||
struct npc_kpu_profile_adapter *profile = &rvu->kpu;
|
||||
const char *kpu_profile = rvu->kpu_pfl_name;
|
||||
const struct firmware *fw = NULL;
|
||||
bool retry_fwdb = false;
|
||||
int fw_kpus = 0;
|
||||
|
||||
/* If user not specified profile customization */
|
||||
if (!strncmp(kpu_profile, def_pfl_name, KPU_NAME_LEN))
|
||||
goto revert_to_default;
|
||||
/* First prepare default KPU, then we'll customize top entries. */
|
||||
npc_prepare_default_kpu(rvu, profile);
|
||||
|
||||
/* Order of preceedence for load loading NPC profile (high to low)
|
||||
* Firmware binary in filesystem.
|
||||
* Firmware database method.
|
||||
* Default KPU profile.
|
||||
*/
|
||||
if (!request_firmware_direct(&fw, kpu_profile, rvu->dev)) {
|
||||
dev_info(rvu->dev, "Loading KPU profile from firmware: %s\n",
|
||||
kpu_profile);
|
||||
rvu->kpu_fwdata = kzalloc(fw->size, GFP_KERNEL);
|
||||
if (rvu->kpu_fwdata) {
|
||||
memcpy(rvu->kpu_fwdata, fw->data, fw->size);
|
||||
rvu->kpu_fwdata_sz = fw->size;
|
||||
}
|
||||
release_firmware(fw);
|
||||
retry_fwdb = true;
|
||||
goto program_kpu;
|
||||
}
|
||||
|
||||
load_image_fwdb:
|
||||
/* Loading the KPU profile using firmware database */
|
||||
if (npc_load_kpu_profile_fwdb(rvu, kpu_profile))
|
||||
goto revert_to_default;
|
||||
return -EFAULT;
|
||||
|
||||
program_kpu:
|
||||
/* Apply profile customization if firmware was loaded. */
|
||||
if (!rvu->kpu_fwdata_sz || npc_apply_custom_kpu(rvu, profile)) {
|
||||
if (!rvu->kpu_fwdata_sz ||
|
||||
npc_apply_custom_kpu(rvu, profile, false, &fw_kpus)) {
|
||||
/* If image from firmware filesystem fails to load or invalid
|
||||
* retry with firmware database method.
|
||||
*/
|
||||
|
|
@ -2010,10 +2213,6 @@ void npc_load_kpu_profile(struct rvu *rvu)
|
|||
}
|
||||
rvu->kpu_fwdata = NULL;
|
||||
rvu->kpu_fwdata_sz = 0;
|
||||
if (retry_fwdb) {
|
||||
retry_fwdb = false;
|
||||
goto load_image_fwdb;
|
||||
}
|
||||
}
|
||||
|
||||
dev_warn(rvu->dev,
|
||||
|
|
@ -2021,22 +2220,101 @@ void npc_load_kpu_profile(struct rvu *rvu)
|
|||
kpu_profile);
|
||||
kfree(rvu->kpu_fwdata);
|
||||
rvu->kpu_fwdata = NULL;
|
||||
goto revert_to_default;
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
dev_info(rvu->dev, "Using custom profile '%s', version %d.%d.%d\n",
|
||||
dev_info(rvu->dev, "Using custom profile '%.32s', version %d.%d.%d\n",
|
||||
profile->name, NPC_KPU_VER_MAJ(profile->version),
|
||||
NPC_KPU_VER_MIN(profile->version),
|
||||
NPC_KPU_VER_PATCH(profile->version));
|
||||
|
||||
return;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int npc_load_kpu_profile_from_fs(struct rvu *rvu)
|
||||
{
|
||||
struct npc_kpu_profile_adapter *profile = &rvu->kpu;
|
||||
const char *kpu_profile = rvu->kpu_pfl_name;
|
||||
const struct firmware *fw = NULL;
|
||||
int ret, fw_kpus = 0;
|
||||
char path[512] = "kpu/";
|
||||
|
||||
if (strlen(kpu_profile) > sizeof(path) - strlen("kpu/") - 1) {
|
||||
dev_err(rvu->dev, "kpu profile name is too big\n");
|
||||
return -ENOSPC;
|
||||
}
|
||||
|
||||
strcat(path, kpu_profile);
|
||||
|
||||
if (request_firmware_direct(&fw, path, rvu->dev))
|
||||
return -ENOENT;
|
||||
|
||||
dev_info(rvu->dev, "Loading KPU profile from filesystem: %s\n",
|
||||
path);
|
||||
|
||||
rvu->kpu_fwdata = fw->data;
|
||||
rvu->kpu_fwdata_sz = fw->size;
|
||||
|
||||
ret = npc_apply_custom_kpu(rvu, profile, true, &fw_kpus);
|
||||
release_firmware(fw);
|
||||
rvu->kpu_fwdata = NULL;
|
||||
|
||||
if (ret) {
|
||||
rvu->kpu_fwdata_sz = 0;
|
||||
dev_err(rvu->dev,
|
||||
"Loading KPU profile from filesystem failed\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* In firmware loading from filesystem method, all entries are from
|
||||
* same binary blob.
|
||||
*/
|
||||
rvu->kpu.kpus = fw_kpus;
|
||||
profile->kpus = fw_kpus;
|
||||
profile->from_fs = true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void npc_load_kpu_profile(struct rvu *rvu)
|
||||
{
|
||||
struct npc_kpu_profile_adapter *profile = &rvu->kpu;
|
||||
const char *kpu_profile = rvu->kpu_pfl_name;
|
||||
|
||||
profile->from_fs = false;
|
||||
|
||||
npc_prepare_default_kpu(rvu, profile);
|
||||
|
||||
/* If user not specified profile customization */
|
||||
if (!strncmp(kpu_profile, def_pfl_name, KPU_NAME_LEN))
|
||||
return;
|
||||
|
||||
/* Order of preceedence for load loading NPC profile (high to low)
|
||||
* Firmware binary in filesystem.
|
||||
* Firmware database method.
|
||||
* Default KPU profile.
|
||||
*/
|
||||
|
||||
/* Filesystem-based KPU loading is not supported on cn20k.
|
||||
* npc_prepare_default_kpu() was invoked earlier, but control
|
||||
* reached this point because the default profile was not selected.
|
||||
* No need to call it again.
|
||||
*/
|
||||
if (!is_cn20k(rvu->pdev)) {
|
||||
if (!npc_load_kpu_profile_from_fs(rvu))
|
||||
return;
|
||||
}
|
||||
|
||||
/* First prepare default KPU, then we'll customize top entries. */
|
||||
npc_prepare_default_kpu(rvu, profile);
|
||||
if (!npc_load_kpu_profile_from_fw(rvu))
|
||||
return;
|
||||
|
||||
revert_to_default:
|
||||
npc_prepare_default_kpu(rvu, profile);
|
||||
}
|
||||
|
||||
static void npc_parser_profile_init(struct rvu *rvu, int blkaddr)
|
||||
{
|
||||
struct npc_kpu_profile_adapter *profile = &rvu->kpu;
|
||||
struct rvu_hwinfo *hw = rvu->hw;
|
||||
int num_pkinds, num_kpus, idx;
|
||||
|
||||
|
|
@ -2060,7 +2338,9 @@ static void npc_parser_profile_init(struct rvu *rvu, int blkaddr)
|
|||
num_pkinds = min_t(int, hw->npc_pkinds, num_pkinds);
|
||||
|
||||
for (idx = 0; idx < num_pkinds; idx++)
|
||||
npc_config_kpuaction(rvu, blkaddr, &rvu->kpu.ikpu[idx], 0, idx, true);
|
||||
npc_config_kpuaction(rvu, blkaddr,
|
||||
npc_get_ikpu_nth_entry(rvu, idx),
|
||||
0, idx, true);
|
||||
|
||||
/* Program KPU CAM and Action profiles */
|
||||
num_kpus = rvu->kpu.kpus;
|
||||
|
|
@ -2068,6 +2348,11 @@ static void npc_parser_profile_init(struct rvu *rvu, int blkaddr)
|
|||
|
||||
for (idx = 0; idx < num_kpus; idx++)
|
||||
npc_program_kpu_profile(rvu, blkaddr, idx, &rvu->kpu.kpu[idx]);
|
||||
|
||||
if (profile->from_fs) {
|
||||
rvu_write64(rvu, blkaddr, NPC_AF_PKINDX_TYPE(54), 0x03);
|
||||
rvu_write64(rvu, blkaddr, NPC_AF_PKINDX_TYPE(58), 0x03);
|
||||
}
|
||||
}
|
||||
|
||||
void npc_mcam_rsrcs_deinit(struct rvu *rvu)
|
||||
|
|
@ -2297,18 +2582,21 @@ static void rvu_npc_hw_init(struct rvu *rvu, int blkaddr)
|
|||
|
||||
static void rvu_npc_setup_interfaces(struct rvu *rvu, int blkaddr)
|
||||
{
|
||||
struct npc_mcam_kex_extr *mkex_extr = rvu->kpu.mcam_kex_prfl.mkex_extr;
|
||||
struct npc_mcam_kex *mkex = rvu->kpu.mcam_kex_prfl.mkex;
|
||||
const struct npc_mcam_kex_extr *mkex_extr;
|
||||
struct npc_mcam *mcam = &rvu->hw->mcam;
|
||||
struct rvu_hwinfo *hw = rvu->hw;
|
||||
const struct npc_mcam_kex *mkex;
|
||||
u64 nibble_ena, rx_kex, tx_kex;
|
||||
u64 *keyx_cfg, reg;
|
||||
u8 intf;
|
||||
|
||||
mkex_extr = rvu->kpu.mcam_kex_prfl.mkex_extr;
|
||||
mkex = rvu->kpu.mcam_kex_prfl.mkex;
|
||||
|
||||
if (is_cn20k(rvu->pdev)) {
|
||||
keyx_cfg = mkex_extr->keyx_cfg;
|
||||
keyx_cfg = (u64 *)mkex_extr->keyx_cfg;
|
||||
} else {
|
||||
keyx_cfg = mkex->keyx_cfg;
|
||||
keyx_cfg = (u64 *)mkex->keyx_cfg;
|
||||
/* Reserve last counter for MCAM RX miss action which is set to
|
||||
* drop packet. This way we will know how many pkts didn't
|
||||
* match any MCAM entry.
|
||||
|
|
|
|||
|
|
@ -18,4 +18,21 @@ int npc_fwdb_prfl_img_map(struct rvu *rvu, void __iomem **prfl_img_addr,
|
|||
|
||||
void npc_mcam_clear_bit(struct npc_mcam *mcam, u16 index);
|
||||
void npc_mcam_set_bit(struct npc_mcam *mcam, u16 index);
|
||||
|
||||
struct npc_kpu_profile_action *
|
||||
npc_get_ikpu_nth_entry(struct rvu *rvu, int n);
|
||||
|
||||
int
|
||||
npc_get_num_kpu_cam_entries(struct rvu *rvu,
|
||||
const struct npc_kpu_profile *kpu_pfl);
|
||||
struct npc_kpu_profile_cam *
|
||||
npc_get_kpu_cam_nth_entry(struct rvu *rvu,
|
||||
const struct npc_kpu_profile *kpu_pfl, int n);
|
||||
|
||||
int
|
||||
npc_get_num_kpu_action_entries(struct rvu *rvu,
|
||||
const struct npc_kpu_profile *kpu_pfl);
|
||||
struct npc_kpu_profile_action *
|
||||
npc_get_kpu_action_nth_entry(struct rvu *rvu,
|
||||
const struct npc_kpu_profile *kpu_pfl, int n);
|
||||
#endif /* RVU_NPC_H */
|
||||
|
|
|
|||
|
|
@ -596,6 +596,7 @@
|
|||
#define NPC_AF_INTFX_KEX_CFG(a) (0x01010 | (a) << 8)
|
||||
#define NPC_AF_PKINDX_ACTION0(a) (0x80000ull | (a) << 6)
|
||||
#define NPC_AF_PKINDX_ACTION1(a) (0x80008ull | (a) << 6)
|
||||
#define NPC_AF_PKINDX_TYPE(a) (0x80010ull | (a) << 6)
|
||||
#define NPC_AF_PKINDX_CPI_DEFX(a, b) (0x80020ull | (a) << 6 | (b) << 3)
|
||||
#define NPC_AF_KPUX_ENTRYX_CAMX(a, b, c) \
|
||||
(0x100000 | (a) << 14 | (b) << 6 | (c) << 3)
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user