mirror of
git://nv-tegra.nvidia.com/linux-nvgpu.git
synced 2025-12-23 01:50:07 +03:00
gpu: nvgpu: add secure gpccs boot support
bug 200080684 keeping it disabled by default also trimming the code by removing redundant variable to check recovery. pmu quick wait now checks only for irqs which are serviced by kernel. requests pmu to bit bang gpccs ucode. Change-Id: I12ef23d6d59b507e86a129b69eab65b21d0438c6 Signed-off-by: Vijayakumar <vsubbu@nvidia.com> Reviewed-on: http://git-master/r/729622 Reviewed-by: Automatic_Commit_Validation_User Reviewed-by: Terje Bergstrom <tbergstrom@nvidia.com>
This commit is contained in:
committed by
Ishan Mittal
parent
6a5cc11171
commit
d65a93b80c
@@ -377,15 +377,15 @@ struct gpu_ops {
|
||||
int (*pmu_setup_hw_and_bootstrap)(struct gk20a *g);
|
||||
int (*pmu_setup_elpg)(struct gk20a *g);
|
||||
int (*init_wpr_region)(struct gk20a *g);
|
||||
bool lspmuwprinitdone;
|
||||
u32 lspmuwprinitdone;
|
||||
bool fecsbootstrapdone;
|
||||
u32 fecsrecoveryinprogress;
|
||||
} pmu;
|
||||
struct {
|
||||
int (*init_clk_support)(struct gk20a *g);
|
||||
int (*suspend_clk_support)(struct gk20a *g);
|
||||
} clk;
|
||||
bool privsecurity;
|
||||
bool securegpccs;
|
||||
struct {
|
||||
const struct regop_offset_range* (
|
||||
*get_global_whitelist_ranges)(void);
|
||||
|
||||
@@ -52,6 +52,7 @@ int gk20a_init_hal(struct gk20a *g)
|
||||
|
||||
*gops = gk20a_ops;
|
||||
gops->privsecurity = 0;
|
||||
gops->securegpccs = 0;
|
||||
gk20a_init_mc(gops);
|
||||
gk20a_init_ltc(gops);
|
||||
gk20a_init_gr_ops(gops);
|
||||
|
||||
@@ -3333,12 +3333,16 @@ int pmu_wait_message_cond(struct pmu_gk20a *pmu, u32 timeout,
|
||||
struct gk20a *g = gk20a_from_pmu(pmu);
|
||||
unsigned long end_jiffies = jiffies + msecs_to_jiffies(timeout);
|
||||
unsigned long delay = GR_IDLE_CHECK_DEFAULT;
|
||||
u32 servicedpmuint;
|
||||
|
||||
servicedpmuint = pwr_falcon_irqstat_halt_true_f() |
|
||||
pwr_falcon_irqstat_exterr_true_f() |
|
||||
pwr_falcon_irqstat_swgen0_true_f();
|
||||
do {
|
||||
if (*var == val)
|
||||
return 0;
|
||||
|
||||
if (gk20a_readl(g, pwr_falcon_irqstat_r()))
|
||||
if (gk20a_readl(g, pwr_falcon_irqstat_r()) & servicedpmuint)
|
||||
gk20a_pmu_isr(g);
|
||||
|
||||
usleep_range(delay, delay * 2);
|
||||
@@ -4042,8 +4046,6 @@ int gk20a_pmu_destroy(struct gk20a *g)
|
||||
pmu->zbc_ready = false;
|
||||
g->ops.pmu.lspmuwprinitdone = false;
|
||||
g->ops.pmu.fecsbootstrapdone = false;
|
||||
g->ops.pmu.fecsrecoveryinprogress = 0;
|
||||
|
||||
|
||||
gk20a_dbg_fn("done");
|
||||
return 0;
|
||||
|
||||
@@ -57,6 +57,7 @@ static void free_acr_resources(struct gk20a *g, struct ls_flcn_mgr *plsfm);
|
||||
static get_ucode_details pmu_acr_supp_ucode_list[] = {
|
||||
pmu_ucode_details,
|
||||
fecs_ucode_details,
|
||||
gpccs_ucode_details,
|
||||
};
|
||||
|
||||
/*Once is LS mode, cpuctl_alias is only accessible*/
|
||||
@@ -209,6 +210,77 @@ rel_sig:
|
||||
release_firmware(fecs_sig);
|
||||
return err;
|
||||
}
|
||||
int gpccs_ucode_details(struct gk20a *g, struct flcn_ucode_img *p_img)
|
||||
{
|
||||
struct lsf_ucode_desc *lsf_desc;
|
||||
const struct firmware *gpccs_sig;
|
||||
int err;
|
||||
|
||||
if (g->ops.securegpccs == false)
|
||||
return -ENOENT;
|
||||
|
||||
gpccs_sig = gk20a_request_firmware(g, GM20B_FECS_UCODE_SIG);
|
||||
if (!gpccs_sig) {
|
||||
gk20a_err(dev_from_gk20a(g), "failed to load gpccs sig");
|
||||
return -ENOENT;
|
||||
}
|
||||
lsf_desc = kzalloc(sizeof(struct lsf_ucode_desc), GFP_KERNEL);
|
||||
if (!lsf_desc) {
|
||||
err = -ENOMEM;
|
||||
goto rel_sig;
|
||||
}
|
||||
memcpy(lsf_desc, (void *)gpccs_sig->data,
|
||||
sizeof(struct lsf_ucode_desc));
|
||||
lsf_desc->falcon_id = LSF_FALCON_ID_GPCCS;
|
||||
|
||||
p_img->desc = kzalloc(sizeof(struct pmu_ucode_desc), GFP_KERNEL);
|
||||
if (p_img->desc == NULL) {
|
||||
err = -ENOMEM;
|
||||
goto free_lsf_desc;
|
||||
}
|
||||
|
||||
p_img->desc->bootloader_start_offset =
|
||||
0;
|
||||
p_img->desc->bootloader_size =
|
||||
ALIGN(g->ctxsw_ucode_info.gpccs.boot.size, 256);
|
||||
p_img->desc->bootloader_imem_offset =
|
||||
g->ctxsw_ucode_info.gpccs.boot_imem_offset;
|
||||
p_img->desc->bootloader_entry_point =
|
||||
g->ctxsw_ucode_info.gpccs.boot_entry;
|
||||
|
||||
p_img->desc->image_size =
|
||||
ALIGN(g->ctxsw_ucode_info.gpccs.boot.size, 256) +
|
||||
ALIGN(g->ctxsw_ucode_info.gpccs.code.size, 256) +
|
||||
ALIGN(g->ctxsw_ucode_info.gpccs.data.size, 256);
|
||||
p_img->desc->app_size = ALIGN(g->ctxsw_ucode_info.gpccs.code.size, 256)
|
||||
+ ALIGN(g->ctxsw_ucode_info.gpccs.data.size, 256);
|
||||
p_img->desc->app_start_offset = p_img->desc->bootloader_size;
|
||||
p_img->desc->app_imem_offset = 0;
|
||||
p_img->desc->app_imem_entry = 0;
|
||||
p_img->desc->app_dmem_offset = 0;
|
||||
p_img->desc->app_resident_code_offset = 0;
|
||||
p_img->desc->app_resident_code_size =
|
||||
ALIGN(g->ctxsw_ucode_info.gpccs.code.size, 256);
|
||||
p_img->desc->app_resident_data_offset =
|
||||
ALIGN(g->ctxsw_ucode_info.gpccs.data.offset, 256) -
|
||||
ALIGN(g->ctxsw_ucode_info.gpccs.code.offset, 256);
|
||||
p_img->desc->app_resident_data_size =
|
||||
ALIGN(g->ctxsw_ucode_info.gpccs.data.size, 256);
|
||||
p_img->data = (u32 *)((u8 *)g->ctxsw_ucode_info.surface_desc.cpu_va +
|
||||
g->ctxsw_ucode_info.gpccs.boot.offset);
|
||||
p_img->data_size = ALIGN(p_img->desc->image_size, 256);
|
||||
p_img->fw_ver = NULL;
|
||||
p_img->header = NULL;
|
||||
p_img->lsf_desc = (struct lsf_ucode_desc *)lsf_desc;
|
||||
gm20b_dbg_pmu("gpccs fw loaded\n");
|
||||
release_firmware(gpccs_sig);
|
||||
return 0;
|
||||
free_lsf_desc:
|
||||
kfree(lsf_desc);
|
||||
rel_sig:
|
||||
release_firmware(gpccs_sig);
|
||||
return err;
|
||||
}
|
||||
|
||||
int prepare_ucode_blob(struct gk20a *g)
|
||||
{
|
||||
@@ -571,6 +643,18 @@ static int lsfm_init_wpr_contents(struct gk20a *g, struct ls_flcn_mgr *plsfm,
|
||||
gm20b_dbg_pmu("bl_data_size :%x %x\n",
|
||||
pnode->lsb_header.bl_data_size,
|
||||
lsb_hdr->bl_data_size);
|
||||
gm20b_dbg_pmu("app_code_off :%x %x\n",
|
||||
pnode->lsb_header.app_code_off,
|
||||
lsb_hdr->app_code_off);
|
||||
gm20b_dbg_pmu("app_code_size :%x %x\n",
|
||||
pnode->lsb_header.app_code_size,
|
||||
lsb_hdr->app_code_size);
|
||||
gm20b_dbg_pmu("app_data_off :%x %x\n",
|
||||
pnode->lsb_header.app_data_off,
|
||||
lsb_hdr->app_data_off);
|
||||
gm20b_dbg_pmu("app_data_size :%x %x\n",
|
||||
pnode->lsb_header.app_data_size,
|
||||
lsb_hdr->app_data_size);
|
||||
gm20b_dbg_pmu("flags :%x %x\n",
|
||||
pnode->lsb_header.flags, lsb_hdr->flags);
|
||||
|
||||
@@ -702,16 +786,6 @@ static void lsfm_fill_static_lsb_hdr_info(struct gk20a *g,
|
||||
VA range */
|
||||
pnode->lsb_header.bl_imem_off =
|
||||
pnode->ucode_img.desc->bootloader_imem_offset;
|
||||
pnode->lsb_header.app_code_off =
|
||||
pnode->ucode_img.desc->app_start_offset +
|
||||
pnode->ucode_img.desc->app_resident_code_offset;
|
||||
pnode->lsb_header.app_code_size =
|
||||
pnode->ucode_img.desc->app_resident_code_size;
|
||||
pnode->lsb_header.app_data_off =
|
||||
pnode->ucode_img.desc->app_start_offset +
|
||||
pnode->ucode_img.desc->app_resident_data_offset;
|
||||
pnode->lsb_header.app_data_size =
|
||||
pnode->ucode_img.desc->app_resident_data_size;
|
||||
|
||||
/* TODO: OBJFLCN should export properties using which the below
|
||||
flags should be populated.*/
|
||||
@@ -721,6 +795,10 @@ static void lsfm_fill_static_lsb_hdr_info(struct gk20a *g,
|
||||
data = NV_FLCN_ACR_LSF_FLAG_DMACTL_REQ_CTX_TRUE;
|
||||
pnode->lsb_header.flags = data;
|
||||
}
|
||||
if (falcon_id == LSF_FALCON_ID_GPCCS) {
|
||||
pnode->lsb_header.flags |=
|
||||
NV_FLCN_ACR_LSF_FLAG_FORCE_PRIV_LOAD_TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -742,6 +820,9 @@ static int lsfm_add_ucode_img(struct gk20a *g, struct ls_flcn_mgr *plsfm,
|
||||
pnode->wpr_header.bootstrap_owner = LSF_BOOTSTRAP_OWNER_DEFAULT;
|
||||
pnode->wpr_header.status = LSF_IMAGE_STATUS_COPY;
|
||||
|
||||
if (falcon_id == LSF_FALCON_ID_GPCCS)
|
||||
pnode->wpr_header.lazy_bootstrap = 1;
|
||||
|
||||
/*TODO to check if PDB_PROP_FLCN_LAZY_BOOTSTRAP is to be supported by
|
||||
Android */
|
||||
/* Fill in static LSB header info elsewhere */
|
||||
@@ -854,6 +935,17 @@ static int lsf_gen_wpr_requirements(struct gk20a *g, struct ls_flcn_mgr *plsfm)
|
||||
/* 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 != LSF_FALCON_ID_PMU) {
|
||||
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;
|
||||
}
|
||||
pnode = pnode->next;
|
||||
}
|
||||
plsfm->wpr_size = wpr_offset;
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
/*Defines*/
|
||||
|
||||
/*chip specific defines*/
|
||||
#define MAX_SUPPORTED_LSFM 2 /*PMU, FECS, GPCCS*/
|
||||
#define MAX_SUPPORTED_LSFM 3 /*PMU, FECS, GPCCS*/
|
||||
#define LSF_UCODE_DATA_ALIGNMENT 4096
|
||||
|
||||
#define GM20B_PMU_UCODE_IMAGE "gpmu_ucode_image.bin"
|
||||
@@ -75,6 +75,8 @@
|
||||
#define NV_FLCN_ACR_LSF_FLAG_LOAD_CODE_AT_0_TRUE 1
|
||||
#define NV_FLCN_ACR_LSF_FLAG_DMACTL_REQ_CTX_FALSE 0
|
||||
#define NV_FLCN_ACR_LSF_FLAG_DMACTL_REQ_CTX_TRUE 4
|
||||
#define NV_FLCN_ACR_LSF_FLAG_FORCE_PRIV_LOAD_TRUE 8
|
||||
#define NV_FLCN_ACR_LSF_FLAG_FORCE_PRIV_LOAD_FALSE 0
|
||||
|
||||
/*!
|
||||
* Light Secure WPR Content Alignments
|
||||
|
||||
@@ -710,6 +710,10 @@ static int gr_gm20b_ctx_wait_lsf_ready(struct gk20a *g, u32 timeout, u32 val)
|
||||
static int gr_gm20b_load_ctxsw_ucode(struct gk20a *g)
|
||||
{
|
||||
u32 err;
|
||||
unsigned long timeout = gk20a_get_gr_idle_timeout(g);
|
||||
u32 reg_offset = gr_gpcs_gpccs_falcon_hwcfg_r() -
|
||||
gr_fecs_falcon_hwcfg_r();
|
||||
|
||||
gk20a_dbg_fn("");
|
||||
|
||||
if (tegra_platform_is_linsim()) {
|
||||
@@ -719,50 +723,68 @@ static int gr_gm20b_load_ctxsw_ucode(struct gk20a *g)
|
||||
gr_gpccs_ctxsw_mailbox_value_f(0xc0de7777));
|
||||
}
|
||||
|
||||
gk20a_writel(g, gr_fecs_ctxsw_mailbox_clear_r(0), ~0x0);
|
||||
gm20b_pmu_load_lsf(g, LSF_FALCON_ID_FECS);
|
||||
|
||||
gr_gm20b_load_gpccs_with_bootloader(g);
|
||||
|
||||
if (g->ops.pmu.fecsrecoveryinprogress) {
|
||||
unsigned long timeout = gk20a_get_gr_idle_timeout(g);
|
||||
if (g->ops.pmu.fecsbootstrapdone) {
|
||||
gk20a_writel(g, gr_fecs_ctxsw_mailbox_clear_r(0), ~0x0);
|
||||
gm20b_pmu_load_lsf(g, LSF_FALCON_ID_FECS);
|
||||
err = gr_gm20b_ctx_wait_lsf_ready(g, timeout, 0x55AA55AA);
|
||||
if (err) {
|
||||
gk20a_err(dev_from_gk20a(g), "Unable to recover FECS");
|
||||
return err;
|
||||
} else {
|
||||
g->ops.pmu.fecsrecoveryinprogress = 0;
|
||||
gk20a_writel(g, gr_fecs_ctxsw_mailbox_clear_r(0), ~0x0);
|
||||
gk20a_writel(g, gr_fecs_ctxsw_mailbox_r(1), 0x1);
|
||||
gk20a_writel(g, gr_fecs_ctxsw_mailbox_clear_r(6),
|
||||
0xffffffff);
|
||||
|
||||
gk20a_writel(g, gr_gpccs_dmactl_r(),
|
||||
if (!g->ops.securegpccs) {
|
||||
gr_gm20b_load_gpccs_with_bootloader(g);
|
||||
gk20a_writel(g, gr_gpccs_dmactl_r(),
|
||||
gr_gpccs_dmactl_require_ctx_f(0));
|
||||
gk20a_writel(g, gr_gpccs_cpuctl_r(),
|
||||
gk20a_writel(g, gr_gpccs_cpuctl_r(),
|
||||
gr_gpccs_cpuctl_startcpu_f(1));
|
||||
|
||||
gk20a_writel(g, gr_fecs_cpuctl_alias_r(),
|
||||
gr_fecs_cpuctl_startcpu_f(1));
|
||||
} else {
|
||||
gk20a_writel(g,
|
||||
gr_fecs_ctxsw_mailbox_clear_r(0), ~0x0);
|
||||
gm20b_pmu_load_lsf(g, LSF_FALCON_ID_GPCCS);
|
||||
err = gr_gm20b_ctx_wait_lsf_ready(g, timeout,
|
||||
0x55AA55AA);
|
||||
gk20a_writel(g, reg_offset +
|
||||
gr_fecs_cpuctl_alias_r(),
|
||||
gr_gpccs_cpuctl_startcpu_f(1));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
g->ops.pmu.fecsbootstrapdone = true;
|
||||
if (!g->ops.securegpccs) {
|
||||
gr_gm20b_load_gpccs_with_bootloader(g);
|
||||
gk20a_writel(g, gr_gpccs_dmactl_r(),
|
||||
gr_gpccs_dmactl_require_ctx_f(0));
|
||||
gk20a_writel(g, gr_gpccs_cpuctl_r(),
|
||||
gr_gpccs_cpuctl_startcpu_f(1));
|
||||
} else {
|
||||
pmu_wait_message_cond(&g->pmu,
|
||||
gk20a_get_gr_idle_timeout(g),
|
||||
&g->ops.pmu.lspmuwprinitdone, 1);
|
||||
if (!g->ops.pmu.lspmuwprinitdone) {
|
||||
gk20a_err(dev_from_gk20a(g),
|
||||
"PMU WPR needed but not ready yet");
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
gk20a_writel(g, gr_fecs_ctxsw_mailbox_clear_r(0), ~0x0);
|
||||
gm20b_pmu_load_lsf(g, LSF_FALCON_ID_GPCCS);
|
||||
err = gr_gm20b_ctx_wait_lsf_ready(g, timeout,
|
||||
0x55AA55AA);
|
||||
if (err) {
|
||||
gk20a_err(dev_from_gk20a(g),
|
||||
"Unable to boot GPCCS\n");
|
||||
return err;
|
||||
}
|
||||
gk20a_writel(g, reg_offset +
|
||||
gr_fecs_cpuctl_alias_r(),
|
||||
gr_gpccs_cpuctl_startcpu_f(1));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (!g->ops.pmu.fecsbootstrapdone) {
|
||||
g->ops.pmu.fecsbootstrapdone = true;
|
||||
gk20a_writel(g, gr_fecs_ctxsw_mailbox_clear_r(0), ~0x0);
|
||||
gk20a_writel(g, gr_fecs_ctxsw_mailbox_r(1), 0x1);
|
||||
gk20a_writel(g, gr_fecs_ctxsw_mailbox_clear_r(6), 0xffffffff);
|
||||
|
||||
gk20a_writel(g, gr_gpccs_dmactl_r(),
|
||||
gr_gpccs_dmactl_require_ctx_f(0));
|
||||
gk20a_writel(g, gr_gpccs_cpuctl_r(),
|
||||
gr_gpccs_cpuctl_startcpu_f(1));
|
||||
|
||||
gk20a_writel(g, gr_fecs_cpuctl_alias_r(),
|
||||
gr_fecs_cpuctl_startcpu_f(1));
|
||||
}
|
||||
|
||||
gk20a_writel(g, gr_fecs_ctxsw_mailbox_clear_r(0), ~0x0);
|
||||
gk20a_writel(g, gr_fecs_ctxsw_mailbox_r(1), 0x1);
|
||||
gk20a_writel(g, gr_fecs_ctxsw_mailbox_clear_r(6), 0xffffffff);
|
||||
gk20a_writel(g, gr_fecs_cpuctl_alias_r(),
|
||||
gr_fecs_cpuctl_startcpu_f(1));
|
||||
gk20a_dbg_fn("done");
|
||||
|
||||
return 0;
|
||||
|
||||
@@ -91,6 +91,7 @@ int gm20b_init_hal(struct gk20a *g)
|
||||
struct nvgpu_gpu_characteristics *c = &g->gpu_characteristics;
|
||||
|
||||
*gops = gm20b_ops;
|
||||
gops->securegpccs = false;
|
||||
#ifdef CONFIG_TEGRA_ACR
|
||||
if (tegra_platform_is_linsim()) {
|
||||
gops->privsecurity = 1;
|
||||
|
||||
@@ -161,7 +161,7 @@ static void pmu_handle_acr_init_wpr_msg(struct gk20a *g, struct pmu_msg *msg,
|
||||
gm20b_dbg_pmu("reply PMU_ACR_CMD_ID_INIT_WPR_REGION");
|
||||
|
||||
if (msg->msg.acr.acrmsg.errorcode == PMU_ACR_SUCCESS)
|
||||
g->ops.pmu.lspmuwprinitdone = true;
|
||||
g->ops.pmu.lspmuwprinitdone = 1;
|
||||
gk20a_dbg_fn("done");
|
||||
}
|
||||
|
||||
@@ -213,7 +213,7 @@ void gm20b_pmu_load_lsf(struct gk20a *g, u8 falcon_id)
|
||||
gk20a_dbg_fn("");
|
||||
|
||||
gm20b_dbg_pmu("wprinit status = %x\n", g->ops.pmu.lspmuwprinitdone);
|
||||
if (g->ops.pmu.lspmuwprinitdone && g->ops.pmu.fecsbootstrapdone) {
|
||||
if (g->ops.pmu.lspmuwprinitdone) {
|
||||
/* send message to load FECS falcon */
|
||||
memset(&cmd, 0, sizeof(struct pmu_cmd));
|
||||
cmd.hdr.unit_id = PMU_UNIT_ACR;
|
||||
@@ -224,8 +224,8 @@ void gm20b_pmu_load_lsf(struct gk20a *g, u8 falcon_id)
|
||||
cmd.cmd.acr.bootstrap_falcon.flags =
|
||||
PMU_ACR_CMD_BOOTSTRAP_FALCON_FLAGS_RESET_YES;
|
||||
cmd.cmd.acr.bootstrap_falcon.falconid = falcon_id;
|
||||
gm20b_dbg_pmu("cmd post PMU_ACR_CMD_ID_BOOTSTRAP_FALCON");
|
||||
g->ops.pmu.fecsrecoveryinprogress = 1;
|
||||
gm20b_dbg_pmu("cmd post PMU_ACR_CMD_ID_BOOTSTRAP_FALCON: %x\n",
|
||||
falcon_id);
|
||||
gk20a_pmu_cmd_post(g, &cmd, NULL, NULL, PMU_COMMAND_QUEUE_HPQ,
|
||||
pmu_handle_fecs_boot_acr_msg, pmu, &seq, ~0);
|
||||
}
|
||||
@@ -244,7 +244,6 @@ void gm20b_init_pmu_ops(struct gpu_ops *gops)
|
||||
gops->pmu.init_wpr_region = NULL;
|
||||
}
|
||||
gops->pmu.pmu_setup_elpg = gm20b_pmu_setup_elpg;
|
||||
gops->pmu.lspmuwprinitdone = false;
|
||||
gops->pmu.lspmuwprinitdone = 0;
|
||||
gops->pmu.fecsbootstrapdone = false;
|
||||
gops->pmu.fecsrecoveryinprogress = 0;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user