forked from Minki/linux
drm/nouveau/secboot: lazy-load firmware and be more resilient
Defer the loading of firmware files to the chip-specific part of secure boot. This allows implementations to retry loading firmware if the first attempt failed ; for the GM200 implementation, this happens when trying to reset a falcon, typically in reaction to GR init. Firmware loading may fail for a variety of reasons, such as the filesystem where they reside not being ready at init time. This new behavior allows GR to be initialized the next time we try to use it if the firmware has become available. Signed-off-by: Alexandre Courbot <acourbot@nvidia.com> Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
This commit is contained in:
parent
4f3c15569e
commit
20560a9a3c
@ -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
|
||||
|
@ -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
|
||||
|
@ -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),
|
||||
|
@ -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 *);
|
||||
|
Loading…
Reference in New Issue
Block a user