diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/secboot/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/secboot/base.c index 57c6a58d1141..314be2192b7d 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/secboot/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/secboot/base.c @@ -214,14 +214,7 @@ nvkm_secboot_oneinit(struct nvkm_subdev *subdev) return ret; } - /* - * Build all blobs - the same blobs can be used to perform secure boot - * multiple times - */ - if (sb->func->prepare_blobs) - ret = sb->func->prepare_blobs(sb); - - return ret; + return 0; } static int diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/secboot/gm200.c b/drivers/gpu/drm/nouveau/nvkm/subdev/secboot/gm200.c index c6871127c70d..d26af8967118 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/secboot/gm200.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/secboot/gm200.c @@ -1051,9 +1051,8 @@ gm20x_secboot_prepare_blobs(struct gm200_secboot *gsb) } static int -gm200_secboot_prepare_blobs(struct nvkm_secboot *sb) +gm200_secboot_prepare_blobs(struct gm200_secboot *gsb) { - struct gm200_secboot *gsb = gm200_secboot(sb); int ret; ret = gm20x_secboot_prepare_blobs(gsb); @@ -1072,6 +1071,26 @@ gm200_secboot_prepare_blobs(struct nvkm_secboot *sb) return 0; } +static int +gm200_secboot_blobs_ready(struct gm200_secboot *gsb) +{ + struct nvkm_subdev *subdev = &gsb->base.subdev; + int ret; + + /* firmware already loaded, nothing to do... */ + if (gsb->firmware_ok) + return 0; + + ret = gsb->func->prepare_blobs(gsb); + if (ret) { + nvkm_error(subdev, "failed to load secure firmware\n"); + return ret; + } + + gsb->firmware_ok = true; + + return 0; +} /* @@ -1244,6 +1263,11 @@ gm200_secboot_reset(struct nvkm_secboot *sb, enum nvkm_secboot_falcon falcon) struct gm200_secboot *gsb = gm200_secboot(sb); int ret; + /* Make sure all blobs are ready */ + ret = gm200_secboot_blobs_ready(gsb); + if (ret) + return ret; + /* * Dummy GM200 implementation: perform secure boot each time we are * called on FECS. Since only FECS and GPCCS are managed and started @@ -1383,7 +1407,6 @@ gm200_secboot = { .dtor = gm200_secboot_dtor, .init = gm200_secboot_init, .fini = gm200_secboot_fini, - .prepare_blobs = gm200_secboot_prepare_blobs, .reset = gm200_secboot_reset, .start = gm200_secboot_start, .managed_falcons = BIT(NVKM_SECBOOT_FALCON_FECS) | @@ -1425,6 +1448,7 @@ gm200_secboot_func = { .bl_desc_size = sizeof(struct gm200_flcn_bl_desc), .fixup_bl_desc = gm200_secboot_fixup_bl_desc, .fixup_hs_desc = gm200_secboot_fixup_hs_desc, + .prepare_blobs = gm200_secboot_prepare_blobs, }; int diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/secboot/gm20b.c b/drivers/gpu/drm/nouveau/nvkm/subdev/secboot/gm20b.c index 684320484b70..d5395ebfe8d3 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/secboot/gm20b.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/secboot/gm20b.c @@ -42,6 +42,32 @@ struct gm20b_flcn_bl_desc { u32 data_size; }; +static int +gm20b_secboot_prepare_blobs(struct gm200_secboot *gsb) +{ + struct nvkm_subdev *subdev = &gsb->base.subdev; + int acr_size; + int ret; + + ret = gm20x_secboot_prepare_blobs(gsb); + if (ret) + return ret; + + acr_size = gsb->acr_load_blob->size; + /* + * On Tegra the WPR region is set by the bootloader. It is illegal for + * the HS blob to be larger than this region. + */ + if (acr_size > gsb->wpr_size) { + nvkm_error(subdev, "WPR region too small for FW blob!\n"); + nvkm_error(subdev, "required: %dB\n", acr_size); + nvkm_error(subdev, "WPR size: %dB\n", gsb->wpr_size); + return -ENOSPC; + } + + return 0; +} + /** * gm20b_secboot_fixup_bl_desc - adapt BL descriptor to format used by GM20B FW * @@ -88,6 +114,7 @@ gm20b_secboot_func = { .bl_desc_size = sizeof(struct gm20b_flcn_bl_desc), .fixup_bl_desc = gm20b_secboot_fixup_bl_desc, .fixup_hs_desc = gm20b_secboot_fixup_hs_desc, + .prepare_blobs = gm20b_secboot_prepare_blobs, }; @@ -146,32 +173,6 @@ gm20b_tegra_read_wpr(struct gm200_secboot *gsb) } #endif -static int -gm20b_secboot_prepare_blobs(struct nvkm_secboot *sb) -{ - struct gm200_secboot *gsb = gm200_secboot(sb); - int acr_size; - int ret; - - ret = gm20x_secboot_prepare_blobs(gsb); - if (ret) - return ret; - - acr_size = gsb->acr_load_blob->size; - /* - * On Tegra the WPR region is set by the bootloader. It is illegal for - * the HS blob to be larger than this region. - */ - if (acr_size > gsb->wpr_size) { - nvkm_error(&sb->subdev, "WPR region too small for FW blob!\n"); - nvkm_error(&sb->subdev, "required: %dB\n", acr_size); - nvkm_error(&sb->subdev, "WPR size: %dB\n", gsb->wpr_size); - return -ENOSPC; - } - - return 0; -} - static int gm20b_secboot_init(struct nvkm_secboot *sb) { @@ -189,7 +190,6 @@ static const struct nvkm_secboot_func gm20b_secboot = { .dtor = gm200_secboot_dtor, .init = gm20b_secboot_init, - .prepare_blobs = gm20b_secboot_prepare_blobs, .reset = gm200_secboot_reset, .start = gm200_secboot_start, .managed_falcons = BIT(NVKM_SECBOOT_FALCON_FECS), diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/secboot/priv.h b/drivers/gpu/drm/nouveau/nvkm/subdev/secboot/priv.h index 110ce64888b4..a9a8a0e1017e 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/secboot/priv.h +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/secboot/priv.h @@ -30,7 +30,6 @@ struct nvkm_secboot_func { int (*init)(struct nvkm_secboot *); int (*fini)(struct nvkm_secboot *, bool suspend); void *(*dtor)(struct nvkm_secboot *); - int (*prepare_blobs)(struct nvkm_secboot *); int (*reset)(struct nvkm_secboot *, enum nvkm_secboot_falcon); int (*start)(struct nvkm_secboot *, enum nvkm_secboot_falcon); @@ -148,6 +147,7 @@ struct hsflcn_acr_desc { * @pgd: page directory for the HS falcon * @vm: address space used by the HS falcon * @falcon_state: current state of the managed falcons + * @firmware_ok: whether the firmware blobs have been created */ struct gm200_secboot { struct nvkm_secboot base; @@ -193,6 +193,7 @@ struct gm200_secboot { RUNNING, } falcon_state[NVKM_SECBOOT_FALCON_END]; + bool firmware_ok; }; #define gm200_secboot(sb) container_of(sb, struct gm200_secboot, base) @@ -203,6 +204,7 @@ struct gm200_secboot { * the generic GM200 format into a data array of size * bl_desc_size * @fixup_hs_desc: hook that twiddles the HS descriptor before it is used + * @prepare_blobs: prepares the various blobs needed for secure booting */ struct gm200_secboot_func { /* @@ -219,6 +221,7 @@ struct gm200_secboot_func { * we want the HS FW to set up. */ void (*fixup_hs_desc)(struct gm200_secboot *, struct hsflcn_acr_desc *); + int (*prepare_blobs)(struct gm200_secboot *); }; int gm200_secboot_init(struct nvkm_secboot *);