Files
linux-nvgpu/drivers/gpu/nvgpu/common/acr/acr_blob_construct.c
Sagar Kadamati dd9b4364aa gpu: nvgpu: add nvgpu-next infrastructure
* As of now, working on multiple chip bringup in nvgpu-next repo has
   an issue because we end with losing control on source code (hard to
   find which part of the code belongs to which chip) and it's valuable
   history this affects chip migration on release.

 * To support multiple chip bringup simultaneously, we need new
   guidelines to avoid losing control on source code and make migration
   easier. This change adds links to nvgpu-next repo.

 * Updated return code to ENODEV for consistency
 * Updated ACR unittest to work with ENODEV return code

NOTE:
     These are the initial set of infrastructure changes, guidelines
     will evolve, and source code will get updated accordingly.

     Based on future chip features, Which part of the source code falls
     under nvgpu-next repo is decided.

JIRA NVGPU-6574

Change-Id: I81827e35d189c55554df00e255b527a4473e0338
Signed-off-by: Sagar Kadamati <skadamati@nvidia.com>
Reviewed-on: https://git-master.nvidia.com/r/c/linux-nvgpu/+/2556793
Tested-by: mobile promotions <svcmobile_promotions@nvidia.com>
Reviewed-by: svc-mobile-coverity <svc-mobile-coverity@nvidia.com>
Reviewed-by: svc-mobile-cert <svc-mobile-cert@nvidia.com>
Reviewed-by: svc_kernel_abi <svc_kernel_abi@nvidia.com>
Reviewed-by: Deepak Nibade <dnibade@nvidia.com>
Reviewed-by: mobile promotions <svcmobile_promotions@nvidia.com>
GVS: Gerrit_Virtual_Submit
2021-09-08 06:50:38 -07:00

1500 lines
44 KiB
C

/*
* Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#include <nvgpu/firmware.h>
#include <nvgpu/pmu.h>
#include <nvgpu/gk20a.h>
#include <nvgpu/string.h>
#include <nvgpu/bug.h>
#include <nvgpu/gr/gr_falcon.h>
#include <nvgpu/gr/gr_utils.h>
#include "nvgpu_acr_interface.h"
#include "acr_blob_construct.h"
#include "acr_wpr.h"
#include "acr_priv.h"
#if defined(CONFIG_NVGPU_NON_FUSA) && defined(CONFIG_NVGPU_NEXT)
#include <nvgpu_next_firmware.h>
#endif
#define APP_IMEM_OFFSET (0)
#define APP_IMEM_ENTRY (0)
#define APP_DMEM_OFFSET (0)
#define APP_RESIDENT_CODE_OFFSET (0)
#define MEMSET_VALUE (0)
#define LSB_HDR_DATA_SIZE (0)
#define BL_START_OFFSET (0)
#if defined(CONFIG_NVGPU_DGPU) || defined(CONFIG_NVGPU_LS_PMU)
#define UCODE_PARAMS (1)
#define UCODE_DESC_TOOL_VERSION 0x4U
#else
#define UCODE_PARAMS (0)
#endif
#ifdef CONFIG_NVGPU_LS_PMU
#if defined(CONFIG_NVGPU_NON_FUSA)
#define PMU_NVRISCV_WPR_RSVD_BYTES (0x8000)
#endif
int nvgpu_acr_lsf_pmu_ucode_details(struct gk20a *g, void *lsf_ucode_img)
{
struct lsf_ucode_desc *lsf_desc;
struct nvgpu_firmware *fw_sig;
struct nvgpu_firmware *fw_desc;
struct nvgpu_firmware *fw_image;
struct flcn_ucode_img *p_img =
(struct flcn_ucode_img *)lsf_ucode_img;
struct ls_falcon_ucode_desc_v1 tmp_desc_v1;
int err = 0;
lsf_desc = nvgpu_kzalloc(g, sizeof(struct lsf_ucode_desc));
if (lsf_desc == NULL) {
err = -ENOMEM;
goto exit;
}
fw_sig = nvgpu_pmu_fw_sig_desc(g, g->pmu);
fw_desc = nvgpu_pmu_fw_desc_desc(g, g->pmu);
fw_image = nvgpu_pmu_fw_image_desc(g, g->pmu);
nvgpu_memcpy((u8 *)lsf_desc, (u8 *)fw_sig->data,
min_t(size_t, sizeof(*lsf_desc), fw_sig->size));
lsf_desc->falcon_id = FALCON_ID_PMU;
p_img->desc = (struct ls_falcon_ucode_desc *)(void *)fw_desc->data;
if (p_img->desc->tools_version >= UCODE_DESC_TOOL_VERSION) {
(void) memset((u8 *)&tmp_desc_v1, 0,
sizeof(struct ls_falcon_ucode_desc_v1));
nvgpu_memcpy((u8 *)&tmp_desc_v1, (u8 *)fw_desc->data,
sizeof(struct ls_falcon_ucode_desc_v1));
nvgpu_memcpy((u8 *)&p_img->desc->bootloader_start_offset,
(u8 *)&tmp_desc_v1.bootloader_start_offset,
sizeof(struct ls_falcon_ucode_desc) -
offsetof(struct ls_falcon_ucode_desc,
bootloader_start_offset));
}
p_img->data = (u32 *)(void *)fw_image->data;
p_img->data_size = p_img->desc->app_start_offset + p_img->desc->app_size;
p_img->lsf_desc = (struct lsf_ucode_desc *)lsf_desc;
exit:
return err;
}
#if defined(CONFIG_NVGPU_NON_FUSA)
s32 nvgpu_acr_lsf_pmu_ncore_ucode_details(struct gk20a *g, void *lsf_ucode_img)
{
struct lsf_ucode_desc *lsf_desc = NULL;
struct lsf_ucode_desc_wrapper *lsf_desc_wrapper = NULL;
struct nvgpu_firmware *fw_sig;
struct nvgpu_firmware *fw_desc;
struct nvgpu_firmware *fw_image;
struct flcn_ucode_img *p_img =
(struct flcn_ucode_img *)lsf_ucode_img;
s32 err = 0;
if (!nvgpu_is_enabled(g, NVGPU_PKC_LS_SIG_ENABLED)) {
lsf_desc = nvgpu_kzalloc(g, sizeof(struct lsf_ucode_desc));
if (lsf_desc == NULL) {
err = -ENOMEM;
goto exit;
}
} else {
lsf_desc_wrapper =
nvgpu_kzalloc(g, sizeof(struct lsf_ucode_desc_wrapper));
if (lsf_desc_wrapper == NULL) {
err = -ENOMEM;
goto exit;
}
}
fw_sig = nvgpu_pmu_fw_sig_desc(g, g->pmu);
fw_desc = nvgpu_pmu_fw_desc_desc(g, g->pmu);
fw_image = nvgpu_pmu_fw_image_desc(g, g->pmu);
if (!nvgpu_is_enabled(g, NVGPU_PKC_LS_SIG_ENABLED)) {
nvgpu_memcpy((u8 *)lsf_desc, (u8 *)fw_sig->data,
min_t(size_t, sizeof(*lsf_desc), fw_sig->size));
lsf_desc->falcon_id = FALCON_ID_PMU_NEXT_CORE;
} else {
nvgpu_memcpy((u8 *)lsf_desc_wrapper, (u8 *)fw_sig->data,
min_t(size_t, sizeof(*lsf_desc_wrapper), fw_sig->size));
lsf_desc_wrapper->lsf_ucode_desc_v2.falcon_id = FALCON_ID_PMU_NEXT_CORE;
}
p_img->ndesc = (struct falcon_next_core_ucode_desc *)(void *)fw_desc->data;
p_img->data = (u32 *)(void *)fw_image->data;
p_img->data_size = U32(fw_image->size);
if (!nvgpu_is_enabled(g, NVGPU_PKC_LS_SIG_ENABLED)) {
p_img->lsf_desc = (struct lsf_ucode_desc *)lsf_desc;
} else {
p_img->lsf_desc_wrapper =
(struct lsf_ucode_desc_wrapper *)lsf_desc_wrapper;
}
p_img->is_next_core_img = true;
exit:
return err;
}
#endif
#endif
int nvgpu_acr_lsf_fecs_ucode_details(struct gk20a *g, void *lsf_ucode_img)
{
u32 tmp_size;
u32 ver = nvgpu_safe_add_u32(g->params.gpu_arch,
g->params.gpu_impl);
struct lsf_ucode_desc *lsf_desc = NULL;
#if defined(CONFIG_NVGPU_NON_FUSA)
struct lsf_ucode_desc_wrapper *lsf_desc_wrapper = NULL;
#endif
struct nvgpu_firmware *fecs_sig = NULL;
struct flcn_ucode_img *p_img =
(struct flcn_ucode_img *)lsf_ucode_img;
struct nvgpu_gr_falcon *gr_falcon = nvgpu_gr_get_falcon_ptr(g);
struct nvgpu_ctxsw_ucode_segments *fecs =
nvgpu_gr_falcon_get_fecs_ucode_segments(gr_falcon);
int err;
switch (ver) {
case NVGPU_GPUID_GV11B:
fecs_sig = nvgpu_request_firmware(g, GM20B_FECS_UCODE_SIG,
NVGPU_REQUEST_FIRMWARE_NO_WARN);
break;
#if defined(CONFIG_NVGPU_NON_FUSA)
case NVGPU_GPUID_GA10B:
if (!nvgpu_is_enabled(g, NVGPU_PKC_LS_SIG_ENABLED)) {
fecs_sig = nvgpu_request_firmware(g,
GM20B_FECS_UCODE_SIG,
NVGPU_REQUEST_FIRMWARE_NO_WARN);
} else {
fecs_sig = nvgpu_request_firmware(g,
GA10B_FECS_UCODE_PKC_SIG,
NVGPU_REQUEST_FIRMWARE_NO_WARN);
}
break;
#endif
#ifdef CONFIG_NVGPU_DGPU
case NVGPU_GPUID_TU104:
fecs_sig = nvgpu_request_firmware(g, TU104_FECS_UCODE_SIG,
NVGPU_REQUEST_FIRMWARE_NO_SOC);
break;
#endif
#if defined(CONFIG_NVGPU_NON_FUSA)
case NVGPU_GPUID_GA100:
fecs_sig = nvgpu_request_firmware(g, GA100_FECS_UCODE_SIG,
NVGPU_REQUEST_FIRMWARE_NO_SOC);
break;
#endif
default:
#if defined(CONFIG_NVGPU_NON_FUSA) && defined(CONFIG_NVGPU_NEXT)
fecs_sig = nvgpu_next_request_fecs_firmware(g);
#endif
break;
}
if (fecs_sig == NULL) {
nvgpu_err(g, "failed to load fecs sig");
return -ENOENT;
}
if (!nvgpu_is_enabled(g, NVGPU_PKC_LS_SIG_ENABLED)) {
lsf_desc = nvgpu_kzalloc(g, sizeof(struct lsf_ucode_desc));
if (lsf_desc == NULL) {
err = -ENOMEM;
goto rel_sig;
}
nvgpu_memcpy((u8 *)lsf_desc, (u8 *)fecs_sig->data,
min_t(size_t, sizeof(*lsf_desc), fecs_sig->size));
lsf_desc->falcon_id = FALCON_ID_FECS;
#if defined(CONFIG_NVGPU_NON_FUSA)
} else {
lsf_desc_wrapper =
nvgpu_kzalloc(g, sizeof(struct lsf_ucode_desc_wrapper));
if (lsf_desc_wrapper == NULL) {
err = -ENOMEM;
goto rel_sig;
}
nvgpu_memcpy((u8 *)lsf_desc_wrapper, (u8 *)fecs_sig->data,
min_t(size_t, sizeof(*lsf_desc_wrapper), fecs_sig->size));
lsf_desc_wrapper->lsf_ucode_desc_v2.falcon_id = FALCON_ID_FECS;
#endif
}
p_img->desc = nvgpu_kzalloc(g, sizeof(struct ls_falcon_ucode_desc));
if (p_img->desc == NULL) {
err = -ENOMEM;
goto free_lsf_desc;
}
p_img->desc->bootloader_start_offset = fecs->boot.offset;
p_img->desc->bootloader_size = NVGPU_ALIGN(fecs->boot.size,
LSF_DATA_SIZE_ALIGNMENT);
p_img->desc->bootloader_imem_offset = fecs->boot_imem_offset;
p_img->desc->bootloader_entry_point = fecs->boot_entry;
tmp_size = nvgpu_safe_add_u32(NVGPU_ALIGN(fecs->boot.size,
LSF_DATA_SIZE_ALIGNMENT),
NVGPU_ALIGN(fecs->code.size,
LSF_DATA_SIZE_ALIGNMENT));
p_img->desc->image_size = nvgpu_safe_add_u32(tmp_size,
NVGPU_ALIGN(fecs->data.size,
LSF_DATA_SIZE_ALIGNMENT));
p_img->desc->app_size = nvgpu_safe_add_u32(NVGPU_ALIGN(fecs->code.size,
LSF_DATA_SIZE_ALIGNMENT),
NVGPU_ALIGN(fecs->data.size,
LSF_DATA_SIZE_ALIGNMENT));
p_img->desc->app_start_offset = fecs->code.offset;
p_img->desc->app_imem_offset = APP_IMEM_OFFSET;
p_img->desc->app_imem_entry = APP_IMEM_ENTRY;
p_img->desc->app_dmem_offset = APP_DMEM_OFFSET;
p_img->desc->app_resident_code_offset = APP_RESIDENT_CODE_OFFSET;
p_img->desc->app_resident_code_size = fecs->code.size;
p_img->desc->app_resident_data_offset =
nvgpu_safe_sub_u32(fecs->data.offset, fecs->code.offset);
p_img->desc->app_resident_data_size = fecs->data.size;
p_img->data = nvgpu_gr_falcon_get_surface_desc_cpu_va(gr_falcon);
p_img->data_size = p_img->desc->image_size;
if (!nvgpu_is_enabled(g, NVGPU_PKC_LS_SIG_ENABLED)) {
p_img->lsf_desc = (struct lsf_ucode_desc *)lsf_desc;
#if defined(CONFIG_NVGPU_NON_FUSA)
} else {
p_img->lsf_desc_wrapper =
(struct lsf_ucode_desc_wrapper *)lsf_desc_wrapper;
#endif
}
nvgpu_acr_dbg(g, "fecs fw loaded\n");
nvgpu_release_firmware(g, fecs_sig);
return 0;
free_lsf_desc:
if (!nvgpu_is_enabled(g, NVGPU_PKC_LS_SIG_ENABLED)) {
nvgpu_kfree(g, lsf_desc);
#if defined(CONFIG_NVGPU_NON_FUSA)
} else {
nvgpu_kfree(g, lsf_desc_wrapper);
#endif
}
rel_sig:
nvgpu_release_firmware(g, fecs_sig);
return err;
}
int nvgpu_acr_lsf_gpccs_ucode_details(struct gk20a *g, void *lsf_ucode_img)
{
u32 tmp_size;
u32 ver = nvgpu_safe_add_u32(g->params.gpu_arch, g->params.gpu_impl);
struct lsf_ucode_desc *lsf_desc = NULL;
#if defined(CONFIG_NVGPU_NON_FUSA)
struct lsf_ucode_desc_wrapper *lsf_desc_wrapper = NULL;
#endif
struct nvgpu_firmware *gpccs_sig = NULL;
struct flcn_ucode_img *p_img =
(struct flcn_ucode_img *)lsf_ucode_img;
struct nvgpu_gr_falcon *gr_falcon = nvgpu_gr_get_falcon_ptr(g);
struct nvgpu_ctxsw_ucode_segments *gpccs =
nvgpu_gr_falcon_get_gpccs_ucode_segments(gr_falcon);
int err;
if ((gpccs == NULL) || (gr_falcon == NULL)) {
return -EINVAL;
}
if (!nvgpu_is_enabled(g, NVGPU_SEC_SECUREGPCCS)) {
return -ENOENT;
}
switch (ver) {
case NVGPU_GPUID_GV11B:
gpccs_sig = nvgpu_request_firmware(g, T18x_GPCCS_UCODE_SIG,
NVGPU_REQUEST_FIRMWARE_NO_WARN);
break;
#if defined(CONFIG_NVGPU_NON_FUSA)
case NVGPU_GPUID_GA10B:
if (!nvgpu_is_enabled(g, NVGPU_PKC_LS_SIG_ENABLED)) {
gpccs_sig = nvgpu_request_firmware(g,
T18x_GPCCS_UCODE_SIG,
NVGPU_REQUEST_FIRMWARE_NO_WARN);
} else {
gpccs_sig = nvgpu_request_firmware(g,
GA10B_GPCCS_UCODE_PKC_SIG,
NVGPU_REQUEST_FIRMWARE_NO_WARN);
}
break;
#endif
#ifdef CONFIG_NVGPU_DGPU
case NVGPU_GPUID_TU104:
gpccs_sig = nvgpu_request_firmware(g, TU104_GPCCS_UCODE_SIG,
NVGPU_REQUEST_FIRMWARE_NO_SOC);
break;
#endif
#if defined(CONFIG_NVGPU_NON_FUSA)
case NVGPU_GPUID_GA100:
gpccs_sig = nvgpu_request_firmware(g, GA100_GPCCS_UCODE_SIG,
NVGPU_REQUEST_FIRMWARE_NO_SOC);
break;
#endif
default:
#if defined(CONFIG_NVGPU_NON_FUSA) && defined(CONFIG_NVGPU_NEXT)
gpccs_sig = nvgpu_next_request_gpccs_firmware(g);
#endif
break;
}
nvgpu_acr_dbg(g, "gpccs fw fetched from FS\n");
if (gpccs_sig == NULL) {
nvgpu_err(g, "failed to load gpccs sig");
return -ENOENT;
}
if (!nvgpu_is_enabled(g, NVGPU_PKC_LS_SIG_ENABLED)) {
lsf_desc = nvgpu_kzalloc(g, sizeof(struct lsf_ucode_desc));
if (lsf_desc == NULL) {
err = -ENOMEM;
goto rel_sig;
}
nvgpu_memcpy((u8 *)lsf_desc, gpccs_sig->data,
min_t(size_t, sizeof(*lsf_desc), gpccs_sig->size));
lsf_desc->falcon_id = FALCON_ID_GPCCS;
#if defined(CONFIG_NVGPU_NON_FUSA)
} else {
lsf_desc_wrapper =
nvgpu_kzalloc(g, sizeof(struct lsf_ucode_desc_wrapper));
if (lsf_desc_wrapper == NULL) {
err = -ENOMEM;
goto rel_sig;
}
nvgpu_memcpy((u8 *)lsf_desc_wrapper, gpccs_sig->data,
min_t(size_t, sizeof(*lsf_desc_wrapper), gpccs_sig->size));
lsf_desc_wrapper->lsf_ucode_desc_v2.falcon_id = FALCON_ID_GPCCS;
#endif
}
nvgpu_acr_dbg(g, "gpccs fw copied to desc buffer\n");
p_img->desc = nvgpu_kzalloc(g, sizeof(struct ls_falcon_ucode_desc));
if (p_img->desc == NULL) {
err = -ENOMEM;
goto free_lsf_desc;
}
p_img->desc->bootloader_start_offset = BL_START_OFFSET;
p_img->desc->bootloader_size = NVGPU_ALIGN(gpccs->boot.size,
LSF_DATA_SIZE_ALIGNMENT);
p_img->desc->bootloader_imem_offset = gpccs->boot_imem_offset;
p_img->desc->bootloader_entry_point = gpccs->boot_entry;
tmp_size = nvgpu_safe_add_u32(NVGPU_ALIGN(gpccs->boot.size,
LSF_DATA_SIZE_ALIGNMENT),
NVGPU_ALIGN(gpccs->code.size,
LSF_DATA_SIZE_ALIGNMENT));
p_img->desc->image_size = nvgpu_safe_add_u32(tmp_size,
NVGPU_ALIGN(gpccs->data.size,
LSF_DATA_SIZE_ALIGNMENT));
p_img->desc->app_size =
nvgpu_safe_add_u32(NVGPU_ALIGN(gpccs->code.size,
LSF_DATA_SIZE_ALIGNMENT),
NVGPU_ALIGN(gpccs->data.size,
LSF_DATA_SIZE_ALIGNMENT));
p_img->desc->app_start_offset = p_img->desc->bootloader_size;
p_img->desc->app_imem_offset = APP_IMEM_OFFSET;
p_img->desc->app_imem_entry = APP_IMEM_ENTRY;
p_img->desc->app_dmem_offset = APP_DMEM_OFFSET;
p_img->desc->app_resident_code_offset = APP_RESIDENT_CODE_OFFSET;
p_img->desc->app_resident_code_size = NVGPU_ALIGN(gpccs->code.size,
LSF_DATA_SIZE_ALIGNMENT);
p_img->desc->app_resident_data_offset =
nvgpu_safe_sub_u32(NVGPU_ALIGN(gpccs->data.offset,
LSF_DATA_SIZE_ALIGNMENT),
NVGPU_ALIGN(gpccs->code.offset,
LSF_DATA_SIZE_ALIGNMENT));
p_img->desc->app_resident_data_size = NVGPU_ALIGN(gpccs->data.size,
LSF_DATA_SIZE_ALIGNMENT);
p_img->data = (u32 *)
(void *)((u8 *)nvgpu_gr_falcon_get_surface_desc_cpu_va(gr_falcon)
+ gpccs->boot.offset);
p_img->data_size = NVGPU_ALIGN(p_img->desc->image_size,
LSF_DATA_SIZE_ALIGNMENT);
if (!nvgpu_is_enabled(g, NVGPU_PKC_LS_SIG_ENABLED)) {
p_img->lsf_desc = (struct lsf_ucode_desc *)lsf_desc;
#if defined(CONFIG_NVGPU_NON_FUSA)
} else {
p_img->lsf_desc_wrapper =
(struct lsf_ucode_desc_wrapper *)lsf_desc_wrapper;
#endif
}
nvgpu_acr_dbg(g, "gpccs fw loaded\n");
nvgpu_release_firmware(g, gpccs_sig);
return 0;
free_lsf_desc:
if (!nvgpu_is_enabled(g, NVGPU_PKC_LS_SIG_ENABLED)) {
nvgpu_kfree(g, lsf_desc);
#if defined(CONFIG_NVGPU_NON_FUSA)
} else {
nvgpu_kfree(g, lsf_desc_wrapper);
#endif
}
rel_sig:
nvgpu_release_firmware(g, gpccs_sig);
return err;
}
#ifdef CONFIG_NVGPU_DGPU
int nvgpu_acr_lsf_sec2_ucode_details(struct gk20a *g, void *lsf_ucode_img)
{
struct nvgpu_firmware *sec2_fw, *sec2_desc, *sec2_sig;
struct ls_falcon_ucode_desc *desc;
struct lsf_ucode_desc *lsf_desc;
struct flcn_ucode_img *p_img =
(struct flcn_ucode_img *)lsf_ucode_img;
u32 *ucode_image;
int err = 0;
nvgpu_acr_dbg(g, "requesting SEC2 ucode in %s", g->name);
if (g->is_fusa_sku) {
sec2_fw = nvgpu_request_firmware(g,
LSF_SEC2_UCODE_IMAGE_FUSA_BIN,
NVGPU_REQUEST_FIRMWARE_NO_SOC);
} else {
sec2_fw = nvgpu_request_firmware(g,
LSF_SEC2_UCODE_IMAGE_BIN,
NVGPU_REQUEST_FIRMWARE_NO_SOC);
}
if (sec2_fw == NULL) {
nvgpu_err(g, "failed to load sec2 ucode!!");
return -ENOENT;
}
ucode_image = (u32 *)sec2_fw->data;
nvgpu_acr_dbg(g, "requesting SEC2 ucode desc in %s", g->name);
if (g->is_fusa_sku) {
sec2_desc = nvgpu_request_firmware(g,
LSF_SEC2_UCODE_DESC_FUSA_BIN,
NVGPU_REQUEST_FIRMWARE_NO_SOC);
} else {
sec2_desc = nvgpu_request_firmware(g,
LSF_SEC2_UCODE_DESC_BIN,
NVGPU_REQUEST_FIRMWARE_NO_SOC);
}
if (sec2_desc == NULL) {
nvgpu_err(g, "failed to load SEC2 ucode desc!!");
err = -ENOENT;
goto release_img_fw;
}
desc = (struct ls_falcon_ucode_desc *)sec2_desc->data;
if (g->is_fusa_sku) {
sec2_sig = nvgpu_request_firmware(g,
LSF_SEC2_UCODE_SIG_FUSA_BIN,
NVGPU_REQUEST_FIRMWARE_NO_SOC);
} else {
sec2_sig = nvgpu_request_firmware(g,
LSF_SEC2_UCODE_SIG_BIN,
NVGPU_REQUEST_FIRMWARE_NO_SOC);
}
if (sec2_sig == NULL) {
nvgpu_err(g, "failed to load SEC2 sig!!");
err = -ENOENT;
goto release_desc;
}
lsf_desc = nvgpu_kzalloc(g, sizeof(struct lsf_ucode_desc));
if (lsf_desc == NULL) {
err = -ENOMEM;
goto release_sig;
}
nvgpu_memcpy((u8 *)lsf_desc, (u8 *)sec2_sig->data,
min_t(size_t, sizeof(*lsf_desc), sec2_sig->size));
lsf_desc->falcon_id = FALCON_ID_SEC2;
p_img->desc = desc;
p_img->data = ucode_image;
p_img->data_size = desc->app_start_offset + desc->app_size;
p_img->lsf_desc = (struct lsf_ucode_desc *)lsf_desc;
nvgpu_acr_dbg(g, "requesting SEC2 ucode in %s done", g->name);
return err;
release_sig:
nvgpu_release_firmware(g, sec2_sig);
release_desc:
nvgpu_release_firmware(g, sec2_desc);
release_img_fw:
nvgpu_release_firmware(g, sec2_fw);
return err;
}
#endif
static void lsfm_fill_static_lsb_hdr_info_aes(struct gk20a *g,
u32 falcon_id, struct lsfm_managed_ucode_img *pnode)
{
u32 full_app_size = 0;
u32 data = 0;
if (pnode->ucode_img.lsf_desc != NULL) {
nvgpu_memcpy((u8 *)&pnode->lsb_header.signature,
(u8 *)pnode->ucode_img.lsf_desc,
sizeof(struct lsf_ucode_desc));
}
pnode->lsb_header.ucode_size = pnode->ucode_img.data_size;
/* Uses a loader. that is has a desc */
pnode->lsb_header.data_size = LSB_HDR_DATA_SIZE;
/*
* The loader code size is already aligned (padded) such that
* the code following it is aligned, but the size in the image
* desc is not, bloat it up to be on a 256 byte alignment.
*/
pnode->lsb_header.bl_code_size = NVGPU_ALIGN(
pnode->ucode_img.desc->bootloader_size,
LSF_BL_CODE_SIZE_ALIGNMENT);
full_app_size = nvgpu_safe_add_u32(
NVGPU_ALIGN(pnode->ucode_img.desc->app_size,
LSF_BL_CODE_SIZE_ALIGNMENT),
pnode->lsb_header.bl_code_size);
pnode->lsb_header.ucode_size = nvgpu_safe_add_u32(NVGPU_ALIGN(
pnode->ucode_img.desc->app_resident_data_offset,
LSF_BL_CODE_SIZE_ALIGNMENT),
pnode->lsb_header.bl_code_size);
pnode->lsb_header.data_size = nvgpu_safe_sub_u32(full_app_size,
pnode->lsb_header.ucode_size);
/*
* Though the BL is located at 0th offset of the image, the VA
* is different to make sure that it doesn't collide the actual OS
* VA range
*/
pnode->lsb_header.bl_imem_off =
pnode->ucode_img.desc->bootloader_imem_offset;
pnode->lsb_header.flags = NV_FLCN_ACR_LSF_FLAG_FORCE_PRIV_LOAD_FALSE;
if (falcon_id == FALCON_ID_PMU) {
data = NV_FLCN_ACR_LSF_FLAG_DMACTL_REQ_CTX_TRUE;
pnode->lsb_header.flags = data;
}
if (g->acr->lsf[falcon_id].is_priv_load) {
pnode->lsb_header.flags |=
NV_FLCN_ACR_LSF_FLAG_FORCE_PRIV_LOAD_TRUE;
}
}
#if defined(CONFIG_NVGPU_NON_FUSA)
static void lsfm_fill_static_lsb_hdr_info_pkc(struct gk20a *g,
u32 falcon_id, struct lsfm_managed_ucode_img *pnode)
{
u32 full_app_size = 0;
if (pnode->ucode_img.lsf_desc_wrapper != NULL) {
nvgpu_memcpy((u8 *)&pnode->lsb_header_v2.signature,
(u8 *)pnode->ucode_img.lsf_desc_wrapper,
sizeof(struct lsf_ucode_desc_wrapper));
}
pnode->lsb_header_v2.ucode_size = pnode->ucode_img.data_size;
pnode->lsb_header_v2.data_size = LSB_HDR_DATA_SIZE;
pnode->lsb_header_v2.bl_code_size = NVGPU_ALIGN(
pnode->ucode_img.desc->bootloader_size,
LSF_BL_CODE_SIZE_ALIGNMENT);
full_app_size = nvgpu_safe_add_u32(
NVGPU_ALIGN(pnode->ucode_img.desc->app_size,
LSF_BL_CODE_SIZE_ALIGNMENT),
pnode->lsb_header_v2.bl_code_size);
pnode->lsb_header_v2.ucode_size = nvgpu_safe_add_u32(NVGPU_ALIGN(
pnode->ucode_img.desc->app_resident_data_offset,
LSF_BL_CODE_SIZE_ALIGNMENT),
pnode->lsb_header_v2.bl_code_size);
pnode->lsb_header_v2.data_size = nvgpu_safe_sub_u32(full_app_size,
pnode->lsb_header_v2.ucode_size);
pnode->lsb_header_v2.bl_imem_off =
pnode->ucode_img.desc->bootloader_imem_offset;
pnode->lsb_header_v2.flags = NV_FLCN_ACR_LSF_FLAG_FORCE_PRIV_LOAD_FALSE;
if (g->acr->lsf[falcon_id].is_priv_load) {
pnode->lsb_header_v2.flags |=
NV_FLCN_ACR_LSF_FLAG_FORCE_PRIV_LOAD_TRUE;
}
}
#endif
/* Populate static LSB header information using the provided ucode image */
static void lsfm_fill_static_lsb_hdr_info(struct gk20a *g,
u32 falcon_id, struct lsfm_managed_ucode_img *pnode)
{
#if defined(CONFIG_NVGPU_NON_FUSA)
u32 base_size = 0;
u32 image_padding_size = 0;
struct falcon_next_core_ucode_desc *ndesc = pnode->ucode_img.ndesc;
#endif
if (!nvgpu_is_enabled(g, NVGPU_PKC_LS_SIG_ENABLED)
&& (!pnode->ucode_img.is_next_core_img)) {
lsfm_fill_static_lsb_hdr_info_aes(g, falcon_id, pnode);
#if defined(CONFIG_NVGPU_NON_FUSA)
} else if (nvgpu_is_enabled(g, NVGPU_PKC_LS_SIG_ENABLED)
&& (!pnode->ucode_img.is_next_core_img)) {
lsfm_fill_static_lsb_hdr_info_pkc(g, falcon_id, pnode);
} else if (!nvgpu_is_enabled(g, NVGPU_PKC_LS_SIG_ENABLED)
&& (pnode->ucode_img.is_next_core_img)) {
pnode->lsb_header.ucode_size = 0;
pnode->lsb_header.data_size = 0;
pnode->lsb_header.bl_code_size = 0;
pnode->lsb_header.bl_imem_off = 0;
pnode->lsb_header.bl_data_size = 0;
pnode->lsb_header.bl_data_off = 0;
} else {
if (pnode->ucode_img.lsf_desc_wrapper != NULL) {
nvgpu_memcpy((u8 *)&pnode->lsb_header_v2.signature,
(u8 *)pnode->ucode_img.lsf_desc_wrapper,
sizeof(struct lsf_ucode_desc_wrapper));
}
pnode->lsb_header_v2.ucode_size = ndesc->bootloader_offset +
ndesc->bootloader_size +
ndesc->bootloader_param_size;
base_size = pnode->lsb_header_v2.ucode_size +
ndesc->next_core_elf_size;
image_padding_size = PAGE_ALIGN(base_size) - base_size;
pnode->lsb_header_v2.data_size = ndesc->next_core_elf_size +
image_padding_size;
pnode->lsb_header_v2.bl_code_size = 0;
pnode->lsb_header_v2.bl_imem_off = 0;
pnode->lsb_header_v2.bl_data_size = 0;
pnode->lsb_header_v2.bl_data_off = 0;
#endif
}
}
/* Adds a ucode image to the list of managed ucode images managed. */
static int lsfm_add_ucode_img(struct gk20a *g, struct ls_flcn_mgr *plsfm,
struct flcn_ucode_img *ucode_image, u32 falcon_id)
{
struct lsfm_managed_ucode_img *pnode;
pnode = nvgpu_kzalloc(g, sizeof(struct lsfm_managed_ucode_img));
if (pnode == NULL) {
return -ENOMEM;
}
/* Keep a copy of the ucode image info locally */
nvgpu_memcpy((u8 *)&pnode->ucode_img, (u8 *)ucode_image,
sizeof(struct flcn_ucode_img));
/* Fill in static WPR header info*/
pnode->wpr_header.falcon_id = falcon_id;
pnode->wpr_header.bootstrap_owner = g->acr->bootstrap_owner;
pnode->wpr_header.status = LSF_IMAGE_STATUS_COPY;
pnode->wpr_header.lazy_bootstrap =
nvgpu_safe_cast_bool_to_u32(
g->acr->lsf[falcon_id].is_lazy_bootstrap);
/* Fill in static LSB header info elsewhere */
lsfm_fill_static_lsb_hdr_info(g, falcon_id, pnode);
if (!nvgpu_is_enabled(g, NVGPU_PKC_LS_SIG_ENABLED)) {
pnode->wpr_header.bin_version =
pnode->lsb_header.signature.version;
#if defined(CONFIG_NVGPU_NON_FUSA)
} else {
pnode->wpr_header.bin_version =
pnode->lsb_header_v2.signature.lsf_ucode_desc_v2.ls_ucode_version;
#endif
}
pnode->next = plsfm->ucode_img_list;
plsfm->ucode_img_list = pnode;
return 0;
}
static int lsfm_check_and_add_ucode_image(struct gk20a *g,
struct ls_flcn_mgr *plsfm, u32 lsf_index)
{
struct flcn_ucode_img ucode_img;
struct nvgpu_acr *acr = g->acr;
u32 falcon_id = 0U;
int err = 0;
if (!nvgpu_test_bit(lsf_index, (void *)&acr->lsf_enable_mask)) {
return err;
}
if (acr->lsf[lsf_index].get_lsf_ucode_details == NULL) {
nvgpu_err(g, "LS falcon-%d ucode fetch details not initialized",
lsf_index);
return -ENOENT;
}
(void) memset(&ucode_img, MEMSET_VALUE, sizeof(ucode_img));
err = acr->lsf[lsf_index].get_lsf_ucode_details(g,
(void *)&ucode_img);
if (err != 0) {
nvgpu_err(g, "LS falcon-%d ucode get failed", lsf_index);
return err;
}
if (!nvgpu_is_enabled(g, NVGPU_PKC_LS_SIG_ENABLED)) {
falcon_id = ucode_img.lsf_desc->falcon_id;
#if defined(CONFIG_NVGPU_NON_FUSA)
} else {
falcon_id = ucode_img.lsf_desc_wrapper->lsf_ucode_desc_v2.falcon_id;
#endif
}
err = lsfm_add_ucode_img(g, plsfm, &ucode_img, falcon_id);
if (err != 0) {
nvgpu_err(g, " Failed to add falcon-%d to LSFM ", falcon_id);
return err;
}
plsfm->managed_flcn_cnt++;
return err;
}
/* Discover all managed falcon ucode images */
static int lsfm_discover_ucode_images(struct gk20a *g,
struct ls_flcn_mgr *plsfm)
{
u32 i;
int err = 0;
#ifdef CONFIG_NVGPU_DGPU
err = lsfm_check_and_add_ucode_image(g, plsfm, FALCON_ID_SEC2);
if (err != 0) {
return err;
}
#endif
/*
* Enumerate all constructed falcon objects, as we need the ucode
* image info and total falcon count
*/
for (i = 0U; i < FALCON_ID_END; i++) {
#ifdef CONFIG_NVGPU_DGPU
if (i == FALCON_ID_SEC2) {
continue;
}
#endif
err = lsfm_check_and_add_ucode_image(g, plsfm, i);
if (err != 0) {
return err;
}
}
return err;
}
#ifdef CONFIG_NVGPU_DGPU
/* Discover all supported shared data falcon SUB WPRs */
static int lsfm_discover_and_add_sub_wprs(struct gk20a *g,
struct ls_flcn_mgr *plsfm)
{
struct lsfm_sub_wpr *pnode;
u32 size_4K = 0;
u32 sub_wpr_index;
for (sub_wpr_index = 1;
sub_wpr_index <= (u32) LSF_SHARED_DATA_SUB_WPR_USE_CASE_ID_MAX;
sub_wpr_index++) {
switch (sub_wpr_index) {
case LSF_SHARED_DATA_SUB_WPR_USE_CASE_ID_PLAYREADY_SHARED_DATA:
size_4K = LSF_SHARED_DATA_SUB_WPR_PLAYREADY_SHARED_DATA_SIZE_IN_4K;
break;
default:
size_4K = 0; /* subWpr not supported */
break;
}
if (size_4K != 0U) {
pnode = nvgpu_kzalloc(g, sizeof(struct lsfm_sub_wpr));
if (pnode == NULL) {
return -ENOMEM;
}
pnode->sub_wpr_header.use_case_id = sub_wpr_index;
pnode->sub_wpr_header.size_4K = size_4K;
pnode->pnext = plsfm->psub_wpr_list;
plsfm->psub_wpr_list = pnode;
plsfm->managed_sub_wpr_count =
nvgpu_safe_cast_u32_to_u16(nvgpu_safe_add_u32(
plsfm->managed_sub_wpr_count, 1U));
}
}
return 0;
}
#endif
static void lsf_calc_wpr_size_aes(struct lsfm_managed_ucode_img *pnode,
u32 *wpr_off)
{
u32 wpr_offset = *wpr_off;
/* Align, save off and include an LSB header size */
wpr_offset = NVGPU_ALIGN(wpr_offset, LSF_LSB_HEADER_ALIGNMENT);
pnode->wpr_header.lsb_offset = wpr_offset;
wpr_offset = nvgpu_safe_add_u32(wpr_offset,
(u32)sizeof(struct lsf_lsb_header));
/*
* Align, save off and include the original (static)ucode
* image size
*/
wpr_offset = NVGPU_ALIGN(wpr_offset, LSF_UCODE_DATA_ALIGNMENT);
pnode->lsb_header.ucode_off = wpr_offset;
wpr_offset = nvgpu_safe_add_u32(wpr_offset,
pnode->ucode_img.data_size);
/*
* For falcons that use a boot loader (BL), we append a loader
* desc structure on the end of the ucode image and consider this
* the boot loader data. The host will then copy the loader desc
* args to this space within the WPR region (before locking down)
* and the HS bin will then copy them to DMEM 0 for the loader.
*/
/*
* Track the size for LSB details filled in later
* Note that at this point we don't know what kind of
* boot loader desc, so we just take the size of the
* generic one, which is the largest it will ever be.
*/
/* Align (size bloat) and save off generic descriptor size*/
pnode->lsb_header.bl_data_size = NVGPU_ALIGN(
nvgpu_safe_cast_u64_to_u32(
sizeof(pnode->bl_gen_desc)),
LSF_BL_DATA_SIZE_ALIGNMENT);
/*Align, save off, and include the additional BL data*/
wpr_offset = NVGPU_ALIGN(wpr_offset, LSF_BL_DATA_ALIGNMENT);
pnode->lsb_header.bl_data_off = wpr_offset;
wpr_offset = nvgpu_safe_add_u32(wpr_offset,
pnode->lsb_header.bl_data_size);
/* Finally, update ucode surface size to include updates */
pnode->full_ucode_size = wpr_offset -
pnode->lsb_header.ucode_off;
if (pnode->wpr_header.falcon_id != FALCON_ID_PMU &&
pnode->wpr_header.falcon_id != FALCON_ID_PMU_NEXT_CORE) {
pnode->lsb_header.app_code_off =
pnode->lsb_header.bl_code_size;
pnode->lsb_header.app_code_size =
pnode->lsb_header.ucode_size -
pnode->lsb_header.bl_code_size;
pnode->lsb_header.app_data_off =
pnode->lsb_header.ucode_size;
pnode->lsb_header.app_data_size =
pnode->lsb_header.data_size;
}
*wpr_off = wpr_offset;
}
#if defined(CONFIG_NVGPU_NON_FUSA)
static void lsf_calc_wpr_size_pkc(struct lsfm_managed_ucode_img *pnode,
u32 *wpr_off)
{
u32 wpr_offset = *wpr_off;
/* Align, save off, and include an LSB header size */
wpr_offset = NVGPU_ALIGN(wpr_offset, LSF_LSB_HEADER_ALIGNMENT);
pnode->wpr_header.lsb_offset = wpr_offset;
wpr_offset = nvgpu_safe_add_u32(wpr_offset,
(u32)sizeof(struct lsf_lsb_header_v2));
wpr_offset = NVGPU_ALIGN(wpr_offset, LSF_UCODE_DATA_ALIGNMENT);
pnode->lsb_header_v2.ucode_off = wpr_offset;
wpr_offset = nvgpu_safe_add_u32(wpr_offset,
pnode->ucode_img.data_size);
pnode->lsb_header_v2.bl_data_size = NVGPU_ALIGN(
nvgpu_safe_cast_u64_to_u32(
sizeof(pnode->bl_gen_desc)),
LSF_BL_DATA_SIZE_ALIGNMENT);
wpr_offset = NVGPU_ALIGN(wpr_offset, LSF_BL_DATA_ALIGNMENT);
pnode->lsb_header_v2.bl_data_off = wpr_offset;
wpr_offset = nvgpu_safe_add_u32(wpr_offset,
pnode->lsb_header_v2.bl_data_size);
pnode->full_ucode_size = wpr_offset -
pnode->lsb_header_v2.ucode_off;
if (pnode->wpr_header.falcon_id != FALCON_ID_PMU &&
pnode->wpr_header.falcon_id != FALCON_ID_PMU_NEXT_CORE) {
pnode->lsb_header_v2.app_code_off =
pnode->lsb_header_v2.bl_code_size;
pnode->lsb_header_v2.app_code_size =
pnode->lsb_header_v2.ucode_size -
pnode->lsb_header_v2.bl_code_size;
pnode->lsb_header_v2.app_data_off =
pnode->lsb_header_v2.ucode_size;
pnode->lsb_header_v2.app_data_size =
pnode->lsb_header_v2.data_size;
}
*wpr_off = wpr_offset;
}
#endif
/* Generate WPR requirements for ACR allocation request */
static int lsf_gen_wpr_requirements(struct gk20a *g,
struct ls_flcn_mgr *plsfm)
{
struct lsfm_managed_ucode_img *pnode = plsfm->ucode_img_list;
#ifdef CONFIG_NVGPU_DGPU
struct lsfm_sub_wpr *pnode_sub_wpr = plsfm->psub_wpr_list;
u32 sub_wpr_header;
#endif
u32 wpr_offset;
u32 flcn_cnt;
/*
* Start with an array of WPR headers at the base of the WPR.
* The expectation here is that the secure falcon will do a single DMA
* read of this array and cache it internally so it's OK to pack these.
* Also, we add 1 to the falcon count to indicate the end of the array.
*/
flcn_cnt = U32(plsfm->managed_flcn_cnt);
wpr_offset = nvgpu_safe_mult_u32(U32(sizeof(struct lsf_wpr_header)),
nvgpu_safe_add_u32(flcn_cnt, U32(1)));
#ifdef CONFIG_NVGPU_DGPU
if (nvgpu_is_enabled(g, NVGPU_SUPPORT_MULTIPLE_WPR)) {
wpr_offset = ALIGN_UP(wpr_offset, LSF_WPR_HEADERS_TOTAL_SIZE_MAX);
/*
* SUB WPR header is appended after lsf_wpr_header_v0 in WPR blob.
* The size is allocated as per the managed SUB WPR count.
*/
wpr_offset = ALIGN_UP(wpr_offset, LSF_SUB_WPR_HEADER_ALIGNMENT);
sub_wpr_header = nvgpu_safe_mult_u32(
U32(sizeof(struct lsf_shared_sub_wpr_header)),
nvgpu_safe_add_u32(U32(plsfm->managed_sub_wpr_count),
U32(1)));
wpr_offset = nvgpu_safe_add_u32(wpr_offset, sub_wpr_header);
}
#endif
/*
* Walk the managed falcons, accounting for the LSB structs
* as well as the ucode images.
*/
while (pnode != NULL) {
if (!nvgpu_is_enabled(g, NVGPU_PKC_LS_SIG_ENABLED)) {
lsf_calc_wpr_size_aes(pnode, &wpr_offset);
#if defined(CONFIG_NVGPU_NON_FUSA)
} else {
lsf_calc_wpr_size_pkc(pnode, &wpr_offset);
#endif
}
#if defined(CONFIG_NVGPU_NON_FUSA)
/* Falcon image is cleanly partitioned between a code and
* data section where we don't need extra reserved space.
* NVRISCV image has no clear partition for code and data
* section, so need to reserve wpr space.
*/
if (pnode->wpr_header.falcon_id == FALCON_ID_PMU_NEXT_CORE) {
wpr_offset = nvgpu_safe_add_u32(wpr_offset,
(u32)PMU_NVRISCV_WPR_RSVD_BYTES);
}
#endif
pnode = pnode->next;
}
#ifdef CONFIG_NVGPU_DGPU
if (nvgpu_is_enabled(g, NVGPU_SUPPORT_MULTIPLE_WPR)) {
/*
* Walk through the sub wpr headers to accommodate
* sub wprs in WPR request
*/
while (pnode_sub_wpr != NULL) {
wpr_offset = ALIGN_UP(wpr_offset,
SUB_WPR_SIZE_ALIGNMENT);
pnode_sub_wpr->sub_wpr_header.start_addr = wpr_offset;
wpr_offset = wpr_offset +
(pnode_sub_wpr->sub_wpr_header.size_4K
<< SHIFT_4KB);
pnode_sub_wpr = pnode_sub_wpr->pnext;
}
wpr_offset = ALIGN_UP(wpr_offset, SUB_WPR_SIZE_ALIGNMENT);
}
#endif
plsfm->wpr_size = wpr_offset;
return 0;
}
/* Initialize WPR contents */
static int lsfm_populate_flcn_bl_dmem_desc(struct gk20a *g,
void *lsfm, u32 *p_bl_gen_desc_size, u32 falconid)
{
struct wpr_carveout_info wpr_inf;
struct lsfm_managed_ucode_img *p_lsfm =
(struct lsfm_managed_ucode_img *)lsfm;
struct flcn_ucode_img *p_img = &(p_lsfm->ucode_img);
struct flcn_bl_dmem_desc *ldr_cfg =
&(p_lsfm->bl_gen_desc);
u64 addr_base = 0;
struct ls_falcon_ucode_desc *desc;
u64 addr_code, addr_data;
if (p_img->desc == NULL) {
/*
* This means its a header based ucode,
* and so we do not fill BL gen desc structure
*/
return -EINVAL;
}
desc = p_img->desc;
/*
* Calculate physical and virtual addresses for various portions of
* the PMU ucode image
* Calculate the 32-bit addresses for the application code, application
* data, and bootloader code. These values are all based on IM_BASE.
* The 32-bit addresses will be the upper 32-bits of the virtual or
* physical addresses of each respective segment.
*/
if (!nvgpu_is_enabled(g, NVGPU_PKC_LS_SIG_ENABLED)) {
addr_base = p_lsfm->lsb_header.ucode_off;
#if defined(CONFIG_NVGPU_NON_FUSA)
} else {
addr_base = p_lsfm->lsb_header_v2.ucode_off;
#endif
}
g->acr->get_wpr_info(g, &wpr_inf);
addr_base = nvgpu_safe_add_u64(addr_base, wpr_inf.wpr_base);
nvgpu_acr_dbg(g, "falcon ID %x", p_lsfm->wpr_header.falcon_id);
nvgpu_acr_dbg(g, "gen loader cfg addrbase %llx ", addr_base);
addr_code = nvgpu_safe_add_u64(addr_base, desc->app_start_offset);
addr_data = nvgpu_safe_add_u64(addr_code,
desc->app_resident_data_offset);
nvgpu_acr_dbg(g, "gen cfg addrcode %llx data %llx load offset %x",
addr_code, addr_data, desc->bootloader_start_offset);
/* Populate the LOADER_CONFIG state */
(void) memset((void *) ldr_cfg, MEMSET_VALUE,
sizeof(struct flcn_bl_dmem_desc));
ldr_cfg->ctx_dma = g->acr->lsf[falconid].falcon_dma_idx;
flcn64_set_dma(&ldr_cfg->code_dma_base, addr_code);
ldr_cfg->non_sec_code_off = desc->app_resident_code_offset;
ldr_cfg->non_sec_code_size = desc->app_resident_code_size;
flcn64_set_dma(&ldr_cfg->data_dma_base, addr_data);
ldr_cfg->data_size = desc->app_resident_data_size;
ldr_cfg->code_entry_point = desc->app_imem_entry;
#if defined(CONFIG_NVGPU_DGPU) || defined(CONFIG_NVGPU_LS_PMU)
/* Update the argc/argv members*/
ldr_cfg->argc = UCODE_PARAMS;
if (g->acr->lsf[falconid].get_cmd_line_args_offset != NULL) {
g->acr->lsf[falconid].get_cmd_line_args_offset(g,
&ldr_cfg->argv);
}
#else
/* Update the argc/argv members*/
ldr_cfg->argc = UCODE_PARAMS;
#endif
*p_bl_gen_desc_size = (u32)sizeof(struct flcn_bl_dmem_desc);
return 0;
}
/* Populate falcon boot loader generic desc.*/
static int lsfm_fill_flcn_bl_gen_desc(struct gk20a *g,
struct lsfm_managed_ucode_img *pnode)
{
return lsfm_populate_flcn_bl_dmem_desc(g, pnode,
&pnode->bl_gen_desc_size,
pnode->wpr_header.falcon_id);
}
#ifdef CONFIG_NVGPU_DGPU
static void lsfm_init_sub_wpr_contents(struct gk20a *g,
struct ls_flcn_mgr *plsfm, struct nvgpu_mem *ucode)
{
struct lsfm_sub_wpr *psub_wpr_node;
struct lsf_shared_sub_wpr_header last_sub_wpr_header;
u32 temp_size = (u32)sizeof(struct lsf_shared_sub_wpr_header);
u32 sub_wpr_header_offset = 0;
u32 i = 0;
/* SubWpr headers are placed after WPR headers */
sub_wpr_header_offset = LSF_WPR_HEADERS_TOTAL_SIZE_MAX;
/*
* Walk through the managed shared subWPRs headers
* and flush them to FB
*/
psub_wpr_node = plsfm->psub_wpr_list;
i = 0;
while (psub_wpr_node != NULL) {
nvgpu_mem_wr_n(g, ucode,
nvgpu_safe_add_u32(sub_wpr_header_offset,
nvgpu_safe_mult_u32(i, temp_size)),
&psub_wpr_node->sub_wpr_header, temp_size);
psub_wpr_node = psub_wpr_node->pnext;
i = nvgpu_safe_add_u32(i, 1U);
}
last_sub_wpr_header.use_case_id =
LSF_SHARED_DATA_SUB_WPR_USE_CASE_ID_INVALID;
nvgpu_mem_wr_n(g, ucode, nvgpu_safe_add_u32(sub_wpr_header_offset,
nvgpu_safe_mult_u32(plsfm->managed_sub_wpr_count, temp_size)),
&last_sub_wpr_header, temp_size);
}
#endif
static int lsfm_init_wpr_contents(struct gk20a *g,
struct ls_flcn_mgr *plsfm, struct nvgpu_mem *ucode)
{
struct lsfm_managed_ucode_img *pnode = plsfm->ucode_img_list;
struct lsf_wpr_header last_wpr_hdr;
u32 i = 0;
u64 tmp;
int err = 0;
/* The WPR array is at the base of the WPR */
pnode = plsfm->ucode_img_list;
(void) memset(&last_wpr_hdr, MEMSET_VALUE, sizeof(struct lsf_wpr_header));
#ifdef CONFIG_NVGPU_DGPU
if (nvgpu_is_enabled(g, NVGPU_SUPPORT_MULTIPLE_WPR)) {
lsfm_init_sub_wpr_contents(g, plsfm, ucode);
}
#endif
/*
* Walk the managed falcons, flush WPR and LSB headers to FB.
* flush any bl args to the storage area relative to the
* ucode image (appended on the end as a DMEM area).
*/
while (pnode != NULL) {
/* Flush WPR header to memory*/
nvgpu_mem_wr_n(g, ucode,
nvgpu_safe_mult_u32(i,
nvgpu_safe_cast_u64_to_u32(sizeof(
pnode->wpr_header))), &pnode->wpr_header,
nvgpu_safe_cast_u64_to_u32(sizeof(pnode->wpr_header)));
nvgpu_acr_dbg(g, "wpr header");
nvgpu_acr_dbg(g, "falconid :%d",
pnode->wpr_header.falcon_id);
nvgpu_acr_dbg(g, "lsb_offset :%x",
pnode->wpr_header.lsb_offset);
nvgpu_acr_dbg(g, "bootstrap_owner :%d",
pnode->wpr_header.bootstrap_owner);
nvgpu_acr_dbg(g, "lazy_bootstrap :%d",
pnode->wpr_header.lazy_bootstrap);
nvgpu_acr_dbg(g, "status :%d",
pnode->wpr_header.status);
/*Flush LSB header to memory*/
if (!nvgpu_is_enabled(g, NVGPU_PKC_LS_SIG_ENABLED)) {
nvgpu_mem_wr_n(g, ucode, pnode->wpr_header.lsb_offset,
&pnode->lsb_header,
nvgpu_safe_cast_u64_to_u32(
sizeof(pnode->lsb_header)));
#if defined(CONFIG_NVGPU_NON_FUSA)
} else {
nvgpu_mem_wr_n(g, ucode, pnode->wpr_header.lsb_offset,
&pnode->lsb_header_v2,
nvgpu_safe_cast_u64_to_u32(
sizeof(pnode->lsb_header_v2)));
#endif
}
nvgpu_acr_dbg(g, "lsb header");
if (!nvgpu_is_enabled(g, NVGPU_PKC_LS_SIG_ENABLED)) {
nvgpu_acr_dbg(g, "ucode_off :%x",
pnode->lsb_header.ucode_off);
nvgpu_acr_dbg(g, "ucode_size :%x",
pnode->lsb_header.ucode_size);
nvgpu_acr_dbg(g, "data_size :%x",
pnode->lsb_header.data_size);
nvgpu_acr_dbg(g, "bl_code_size :%x",
pnode->lsb_header.bl_code_size);
nvgpu_acr_dbg(g, "bl_imem_off :%x",
pnode->lsb_header.bl_imem_off);
nvgpu_acr_dbg(g, "bl_data_off :%x",
pnode->lsb_header.bl_data_off);
nvgpu_acr_dbg(g, "bl_data_size :%x",
pnode->lsb_header.bl_data_size);
nvgpu_acr_dbg(g, "app_code_off :%x",
pnode->lsb_header.app_code_off);
nvgpu_acr_dbg(g, "app_code_size :%x",
pnode->lsb_header.app_code_size);
nvgpu_acr_dbg(g, "app_data_off :%x",
pnode->lsb_header.app_data_off);
nvgpu_acr_dbg(g, "app_data_size :%x",
pnode->lsb_header.app_data_size);
nvgpu_acr_dbg(g, "flags :%x",
pnode->lsb_header.flags);
#if defined(CONFIG_NVGPU_NON_FUSA)
} else {
nvgpu_acr_dbg(g, "ucode_off :%x",
pnode->lsb_header_v2.ucode_off);
nvgpu_acr_dbg(g, "ucode_size :%x",
pnode->lsb_header_v2.ucode_size);
nvgpu_acr_dbg(g, "data_size :%x",
pnode->lsb_header_v2.data_size);
nvgpu_acr_dbg(g, "bl_code_size :%x",
pnode->lsb_header_v2.bl_code_size);
nvgpu_acr_dbg(g, "bl_imem_off :%x",
pnode->lsb_header_v2.bl_imem_off);
nvgpu_acr_dbg(g, "bl_data_off :%x",
pnode->lsb_header_v2.bl_data_off);
nvgpu_acr_dbg(g, "bl_data_size :%x",
pnode->lsb_header_v2.bl_data_size);
nvgpu_acr_dbg(g, "app_code_off :%x",
pnode->lsb_header_v2.app_code_off);
nvgpu_acr_dbg(g, "app_code_size :%x",
pnode->lsb_header_v2.app_code_size);
nvgpu_acr_dbg(g, "app_data_off :%x",
pnode->lsb_header_v2.app_data_off);
nvgpu_acr_dbg(g, "app_data_size :%x",
pnode->lsb_header_v2.app_data_size);
nvgpu_acr_dbg(g, "flags :%x",
pnode->lsb_header_v2.flags);
#endif
}
if (!pnode->ucode_img.is_next_core_img) {
/*
* If this falcon has a boot loader and related args,
* flush them.
*/
/* Populate gen bl and flush to memory */
err = lsfm_fill_flcn_bl_gen_desc(g, pnode);
if (err != 0) {
nvgpu_err(g, "bl_gen_desc failed err=%d", err);
return err;
}
if (!nvgpu_is_enabled(g, NVGPU_PKC_LS_SIG_ENABLED)) {
nvgpu_mem_wr_n(g, ucode,
pnode->lsb_header.bl_data_off,
&pnode->bl_gen_desc,
pnode->bl_gen_desc_size);
#if defined(CONFIG_NVGPU_NON_FUSA)
} else {
nvgpu_mem_wr_n(g, ucode,
pnode->lsb_header_v2.bl_data_off,
&pnode->bl_gen_desc,
pnode->bl_gen_desc_size);
#endif
}
}
/* Copying of ucode */
if (!nvgpu_is_enabled(g, NVGPU_PKC_LS_SIG_ENABLED)) {
nvgpu_mem_wr_n(g, ucode, pnode->lsb_header.ucode_off,
pnode->ucode_img.data,
pnode->ucode_img.data_size);
#if defined(CONFIG_NVGPU_NON_FUSA)
} else {
nvgpu_mem_wr_n(g, ucode, pnode->lsb_header_v2.ucode_off,
pnode->ucode_img.data,
pnode->ucode_img.data_size);
#endif
}
pnode = pnode->next;
i = nvgpu_safe_add_u32(i, 1U);
}
/* Tag the terminator WPR header with an invalid falcon ID. */
last_wpr_hdr.falcon_id = FALCON_ID_INVALID;
tmp = nvgpu_safe_mult_u32(plsfm->managed_flcn_cnt,
(u32)sizeof(struct lsf_wpr_header));
nvgpu_assert(tmp <= U32_MAX);
nvgpu_mem_wr_n(g, ucode, (u32)tmp, &last_wpr_hdr,
(u32)sizeof(struct lsf_wpr_header));
return err;
}
/* Free any ucode image structure resources. */
static void lsfm_free_ucode_img_res(struct gk20a *g,
struct flcn_ucode_img *p_img)
{
if (p_img->lsf_desc != NULL) {
nvgpu_kfree(g, p_img->lsf_desc);
p_img->lsf_desc = NULL;
}
#if defined(CONFIG_NVGPU_NON_FUSA)
if (p_img->lsf_desc_wrapper != NULL) {
nvgpu_kfree(g, p_img->lsf_desc_wrapper);
p_img->lsf_desc_wrapper = NULL;
}
#endif
}
static void lsfm_free_nonpmu_ucode_img_res(struct gk20a *g,
struct flcn_ucode_img *p_img)
{
if (p_img->lsf_desc != NULL) {
nvgpu_kfree(g, p_img->lsf_desc);
p_img->lsf_desc = NULL;
}
#if defined(CONFIG_NVGPU_NON_FUSA)
if (p_img->lsf_desc_wrapper != NULL) {
nvgpu_kfree(g, p_img->lsf_desc_wrapper);
p_img->lsf_desc_wrapper = NULL;
}
#endif
if (p_img->desc != NULL) {
nvgpu_kfree(g, p_img->desc);
p_img->desc = NULL;
}
}
static void free_acr_resources(struct gk20a *g, struct ls_flcn_mgr *plsfm)
{
u32 cnt = plsfm->managed_flcn_cnt;
struct lsfm_managed_ucode_img *mg_ucode_img;
while (cnt != 0U) {
mg_ucode_img = plsfm->ucode_img_list;
if (mg_ucode_img->ucode_img.lsf_desc != NULL &&
mg_ucode_img->ucode_img.lsf_desc->falcon_id == FALCON_ID_PMU) {
lsfm_free_ucode_img_res(g, &mg_ucode_img->ucode_img);
} else {
lsfm_free_nonpmu_ucode_img_res(g,
&mg_ucode_img->ucode_img);
}
plsfm->ucode_img_list = mg_ucode_img->next;
nvgpu_kfree(g, mg_ucode_img);
cnt--;
}
}
int nvgpu_acr_prepare_ucode_blob(struct gk20a *g)
{
int err = 0;
struct ls_flcn_mgr lsfm_l, *plsfm;
struct wpr_carveout_info wpr_inf;
struct nvgpu_gr_falcon *gr_falcon = nvgpu_gr_get_falcon_ptr(g);
/* Recovery case, we do not need to form non WPR blob of ucodes */
if (g->acr->ucode_blob.cpu_va != NULL) {
return err;
}
plsfm = &lsfm_l;
(void) memset((void *)plsfm, MEMSET_VALUE, sizeof(struct ls_flcn_mgr));
err = nvgpu_gr_falcon_init_ctxsw_ucode(g, gr_falcon);
if (err != 0) {
nvgpu_err(g, "gr_falcon_init_ctxsw_ucode failed err=%d", err);
return err;
}
g->acr->get_wpr_info(g, &wpr_inf);
nvgpu_acr_dbg(g, "wpr carveout base:%llx\n", (wpr_inf.wpr_base));
nvgpu_acr_dbg(g, "wpr carveout size :%llx\n", wpr_inf.size);
/* Discover all managed falcons */
err = lsfm_discover_ucode_images(g, plsfm);
nvgpu_acr_dbg(g, " Managed Falcon cnt %d\n", plsfm->managed_flcn_cnt);
if (err != 0) {
goto cleanup_exit;
}
#ifdef CONFIG_NVGPU_DGPU
if (nvgpu_is_enabled(g, NVGPU_SUPPORT_MULTIPLE_WPR)) {
err = lsfm_discover_and_add_sub_wprs(g, plsfm);
if (err != 0) {
goto cleanup_exit;
}
}
#endif
if ((plsfm->managed_flcn_cnt != 0U) &&
(g->acr->ucode_blob.cpu_va == NULL)) {
/* Generate WPR requirements */
err = lsf_gen_wpr_requirements(g, plsfm);
if (err != 0) {
goto cleanup_exit;
}
/* Alloc memory to hold ucode blob contents */
err = g->acr->alloc_blob_space(g, plsfm->wpr_size,
&g->acr->ucode_blob);
if (err != 0) {
goto cleanup_exit;
}
nvgpu_acr_dbg(g, "managed LS falcon %d, WPR size %d bytes.\n",
plsfm->managed_flcn_cnt, plsfm->wpr_size);
err = lsfm_init_wpr_contents(g, plsfm, &g->acr->ucode_blob);
if (err != 0) {
nvgpu_kfree(g, &g->acr->ucode_blob);
goto cleanup_exit;
}
} else {
nvgpu_acr_dbg(g, "LSFM is managing no falcons.\n");
}
nvgpu_acr_dbg(g, "prepare ucode blob return 0\n");
cleanup_exit:
free_acr_resources(g, plsfm);
return err;
}