From d65a93b80c60bb677fbc13b7180e0f31b7f97f84 Mon Sep 17 00:00:00 2001 From: Vijayakumar Date: Thu, 9 Apr 2015 16:47:13 +0530 Subject: 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 Reviewed-on: http://git-master/r/729622 Reviewed-by: Automatic_Commit_Validation_User Reviewed-by: Terje Bergstrom --- drivers/gpu/nvgpu/gm20b/acr_gm20b.c | 112 ++++++++++++++++++++++++++++++++---- drivers/gpu/nvgpu/gm20b/acr_gm20b.h | 4 +- drivers/gpu/nvgpu/gm20b/gr_gm20b.c | 86 ++++++++++++++++----------- drivers/gpu/nvgpu/gm20b/hal_gm20b.c | 1 + drivers/gpu/nvgpu/gm20b/pmu_gm20b.c | 11 ++-- 5 files changed, 165 insertions(+), 49 deletions(-) (limited to 'drivers/gpu/nvgpu/gm20b') diff --git a/drivers/gpu/nvgpu/gm20b/acr_gm20b.c b/drivers/gpu/nvgpu/gm20b/acr_gm20b.c index 2e33c3f0..ba47d235 100644 --- a/drivers/gpu/nvgpu/gm20b/acr_gm20b.c +++ b/drivers/gpu/nvgpu/gm20b/acr_gm20b.c @@ -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; diff --git a/drivers/gpu/nvgpu/gm20b/acr_gm20b.h b/drivers/gpu/nvgpu/gm20b/acr_gm20b.h index c279d797..3a5fa7d0 100644 --- a/drivers/gpu/nvgpu/gm20b/acr_gm20b.h +++ b/drivers/gpu/nvgpu/gm20b/acr_gm20b.h @@ -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 diff --git a/drivers/gpu/nvgpu/gm20b/gr_gm20b.c b/drivers/gpu/nvgpu/gm20b/gr_gm20b.c index 55a21c98..1fa1eb24 100644 --- a/drivers/gpu/nvgpu/gm20b/gr_gm20b.c +++ b/drivers/gpu/nvgpu/gm20b/gr_gm20b.c @@ -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)); + } } - } - - - if (!g->ops.pmu.fecsbootstrapdone) { + } else { 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(), + 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)); - - 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; diff --git a/drivers/gpu/nvgpu/gm20b/hal_gm20b.c b/drivers/gpu/nvgpu/gm20b/hal_gm20b.c index d5a6e422..1ab65836 100644 --- a/drivers/gpu/nvgpu/gm20b/hal_gm20b.c +++ b/drivers/gpu/nvgpu/gm20b/hal_gm20b.c @@ -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; diff --git a/drivers/gpu/nvgpu/gm20b/pmu_gm20b.c b/drivers/gpu/nvgpu/gm20b/pmu_gm20b.c index c25d2d56..28b40b1c 100644 --- a/drivers/gpu/nvgpu/gm20b/pmu_gm20b.c +++ b/drivers/gpu/nvgpu/gm20b/pmu_gm20b.c @@ -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; } -- cgit v1.2.2