Commit 5d16250b authored by Harman Kalra's avatar Harman Kalra Committed by Jakub Kicinski

octeontx2-af: load NPC profile via firmware database

Currently NPC profile (KPU + MKEX) can be loaded using firmware
binary in filesystem scheme. Enhancing the functionality to load
NPC profile image from system firmware database. It uses the same
technique as used for loading MKEX profile. Firstly firmware binary
in kernel is checked for a valid image else tries to load NPC profile
from firmware database and at last uses default profile if no proper
image found.
Signed-off-by: default avatarHarman Kalra <hkalra@marvell.com>
Signed-off-by: default avatarSunil Kovvuri Goutham <Sunil.Goutham@marvell.com>
Signed-off-by: default avatarGeorge Cherian <george.cherian@marvell.com>
Signed-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parent 3a724415
...@@ -442,6 +442,7 @@ struct rvu { ...@@ -442,6 +442,7 @@ struct rvu {
struct rvu_fwdata *fwdata; struct rvu_fwdata *fwdata;
void *kpu_fwdata; void *kpu_fwdata;
size_t kpu_fwdata_sz; size_t kpu_fwdata_sz;
void __iomem *kpu_prfl_addr;
/* NPC KPU data */ /* NPC KPU data */
struct npc_kpu_profile_adapter kpu; struct npc_kpu_profile_adapter kpu;
......
...@@ -1134,6 +1134,30 @@ static void npc_program_mkex_profile(struct rvu *rvu, int blkaddr, ...@@ -1134,6 +1134,30 @@ static void npc_program_mkex_profile(struct rvu *rvu, int blkaddr,
} }
} }
static int npc_fwdb_prfl_img_map(struct rvu *rvu, void __iomem **prfl_img_addr,
u64 *size)
{
u64 prfl_addr, prfl_sz;
if (!rvu->fwdata)
return -EINVAL;
prfl_addr = rvu->fwdata->mcam_addr;
prfl_sz = rvu->fwdata->mcam_sz;
if (!prfl_addr || !prfl_sz)
return -EINVAL;
*prfl_img_addr = ioremap_wc(prfl_addr, prfl_sz);
if (!(*prfl_img_addr))
return -ENOMEM;
*size = prfl_sz;
return 0;
}
/* strtoull of "mkexprof" with base:36 */
#define MKEX_END_SIGN 0xdeadbeef #define MKEX_END_SIGN 0xdeadbeef
static void npc_load_mkex_profile(struct rvu *rvu, int blkaddr, static void npc_load_mkex_profile(struct rvu *rvu, int blkaddr,
...@@ -1141,27 +1165,21 @@ static void npc_load_mkex_profile(struct rvu *rvu, int blkaddr, ...@@ -1141,27 +1165,21 @@ static void npc_load_mkex_profile(struct rvu *rvu, int blkaddr,
{ {
struct device *dev = &rvu->pdev->dev; struct device *dev = &rvu->pdev->dev;
struct npc_mcam_kex *mcam_kex; struct npc_mcam_kex *mcam_kex;
void *mkex_prfl_addr = NULL; void __iomem *mkex_prfl_addr = NULL;
u64 prfl_addr, prfl_sz; u64 prfl_sz;
int ret;
/* If user not selected mkex profile */ /* If user not selected mkex profile */
if (rvu->kpu_fwdata_sz || if (rvu->kpu_fwdata_sz ||
!strncmp(mkex_profile, def_pfl_name, MKEX_NAME_LEN)) !strncmp(mkex_profile, def_pfl_name, MKEX_NAME_LEN))
goto program_mkex; goto program_mkex;
if (!rvu->fwdata) /* Setting up the mapping for mkex profile image */
goto program_mkex; ret = npc_fwdb_prfl_img_map(rvu, &mkex_prfl_addr, &prfl_sz);
prfl_addr = rvu->fwdata->mcam_addr; if (ret < 0)
prfl_sz = rvu->fwdata->mcam_sz;
if (!prfl_addr || !prfl_sz)
goto program_mkex;
mkex_prfl_addr = memremap(prfl_addr, prfl_sz, MEMREMAP_WC);
if (!mkex_prfl_addr)
goto program_mkex; goto program_mkex;
mcam_kex = (struct npc_mcam_kex *)mkex_prfl_addr; mcam_kex = (struct npc_mcam_kex __force *)mkex_prfl_addr;
while (((s64)prfl_sz > 0) && (mcam_kex->mkex_sign != MKEX_END_SIGN)) { while (((s64)prfl_sz > 0) && (mcam_kex->mkex_sign != MKEX_END_SIGN)) {
/* Compare with mkex mod_param name string */ /* Compare with mkex mod_param name string */
...@@ -1187,7 +1205,7 @@ static void npc_load_mkex_profile(struct rvu *rvu, int blkaddr, ...@@ -1187,7 +1205,7 @@ static void npc_load_mkex_profile(struct rvu *rvu, int blkaddr,
/* Program selected mkex profile */ /* Program selected mkex profile */
npc_program_mkex_profile(rvu, blkaddr, rvu->kpu.mkex); npc_program_mkex_profile(rvu, blkaddr, rvu->kpu.mkex);
if (mkex_prfl_addr) if (mkex_prfl_addr)
memunmap(mkex_prfl_addr); iounmap(mkex_prfl_addr);
} }
static void npc_config_kpuaction(struct rvu *rvu, int blkaddr, static void npc_config_kpuaction(struct rvu *rvu, int blkaddr,
...@@ -1386,6 +1404,40 @@ static int npc_apply_custom_kpu(struct rvu *rvu, ...@@ -1386,6 +1404,40 @@ static int npc_apply_custom_kpu(struct rvu *rvu,
return 0; return 0;
} }
static int npc_load_kpu_profile_fwdb(struct rvu *rvu, const char *kpu_profile)
{
struct npc_kpu_profile_fwdata *kpu_fw = NULL;
u64 prfl_sz;
int ret;
/* Setting up the mapping for NPC profile image */
ret = npc_fwdb_prfl_img_map(rvu, &rvu->kpu_prfl_addr, &prfl_sz);
if (ret < 0)
return ret;
rvu->kpu_fwdata =
(struct npc_kpu_profile_fwdata __force *)rvu->kpu_prfl_addr;
rvu->kpu_fwdata_sz = prfl_sz;
kpu_fw = rvu->kpu_fwdata;
if (le64_to_cpu(kpu_fw->signature) == KPU_SIGN &&
!strncmp(kpu_fw->name, kpu_profile, KPU_NAME_LEN)) {
dev_info(rvu->dev, "Loading KPU profile from firmware db: %s\n",
kpu_profile);
return 0;
}
/* Cleaning up if KPU profile image from fwdata is not valid. */
if (rvu->kpu_prfl_addr) {
iounmap(rvu->kpu_prfl_addr);
rvu->kpu_prfl_addr = NULL;
rvu->kpu_fwdata_sz = 0;
rvu->kpu_fwdata = NULL;
}
return -EINVAL;
}
static void npc_load_kpu_profile(struct rvu *rvu) static void npc_load_kpu_profile(struct rvu *rvu)
{ {
struct npc_kpu_profile_adapter *profile = &rvu->kpu; struct npc_kpu_profile_adapter *profile = &rvu->kpu;
...@@ -1398,19 +1450,47 @@ static void npc_load_kpu_profile(struct rvu *rvu) ...@@ -1398,19 +1450,47 @@ static void npc_load_kpu_profile(struct rvu *rvu)
/* First prepare default KPU, then we'll customize top entries. */ /* First prepare default KPU, then we'll customize top entries. */
npc_prepare_default_kpu(profile); npc_prepare_default_kpu(profile);
dev_info(rvu->dev, "Loading KPU profile from firmware: %s\n", /* Order of preceedence for load loading NPC profile (high to low)
kpu_profile); * Firmware binary in filesystem.
* Firmware database method.
* Default KPU profile.
*/
if (!request_firmware(&fw, kpu_profile, rvu->dev)) { if (!request_firmware(&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); rvu->kpu_fwdata = kzalloc(fw->size, GFP_KERNEL);
if (rvu->kpu_fwdata) { if (rvu->kpu_fwdata) {
memcpy(rvu->kpu_fwdata, fw->data, fw->size); memcpy(rvu->kpu_fwdata, fw->data, fw->size);
rvu->kpu_fwdata_sz = fw->size; rvu->kpu_fwdata_sz = fw->size;
} }
release_firmware(fw); release_firmware(fw);
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;
program_kpu:
/* Apply profile customization if firmware was loaded. */ /* 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)) {
/* If image from firmware filesystem fails to load or invalid
* retry with firmware database method.
*/
if (rvu->kpu_fwdata || rvu->kpu_fwdata_sz) {
/* Loading image from firmware database failed. */
if (rvu->kpu_prfl_addr) {
iounmap(rvu->kpu_prfl_addr);
rvu->kpu_prfl_addr = NULL;
} else {
kfree(rvu->kpu_fwdata);
}
rvu->kpu_fwdata = NULL;
rvu->kpu_fwdata_sz = 0;
goto load_image_fwdb;
}
dev_warn(rvu->dev, dev_warn(rvu->dev,
"Can't load KPU profile %s. Using default.\n", "Can't load KPU profile %s. Using default.\n",
kpu_profile); kpu_profile);
...@@ -1765,7 +1845,10 @@ void rvu_npc_freemem(struct rvu *rvu) ...@@ -1765,7 +1845,10 @@ void rvu_npc_freemem(struct rvu *rvu)
kfree(pkind->rsrc.bmap); kfree(pkind->rsrc.bmap);
kfree(mcam->counters.bmap); kfree(mcam->counters.bmap);
kfree(rvu->kpu_fwdata); if (rvu->kpu_prfl_addr)
iounmap(rvu->kpu_prfl_addr);
else
kfree(rvu->kpu_fwdata);
mutex_destroy(&mcam->lock); mutex_destroy(&mcam->lock);
} }
......
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