diff options
Diffstat (limited to 'drivers/gpu/drm/nouveau/nvkm/subdev/secboot')
-rw-r--r-- | drivers/gpu/drm/nouveau/nvkm/subdev/secboot/base.c | 28 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nvkm/subdev/secboot/gm200.c | 88 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nvkm/subdev/secboot/gm20b.c | 54 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nvkm/subdev/secboot/priv.h | 18 |
4 files changed, 118 insertions, 70 deletions
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/secboot/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/secboot/base.c index 213fdba6cfa0..314be2192b7d 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/secboot/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/secboot/base.c @@ -19,8 +19,9 @@ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ - #include "priv.h" + +#include <subdev/mc.h> #include <subdev/timer.h> static const char * @@ -70,12 +71,11 @@ nvkm_secboot_falcon_enable(struct nvkm_secboot *sb) int ret; /* enable engine */ - nvkm_mask(device, 0x200, sb->enable_mask, sb->enable_mask); - nvkm_rd32(device, 0x200); + nvkm_mc_enable(device, sb->devidx); ret = nvkm_wait_msec(device, 10, sb->base + 0x10c, 0x6, 0x0); if (ret < 0) { - nvkm_mask(device, 0x200, sb->enable_mask, 0x0); nvkm_error(&sb->subdev, "Falcon mem scrubbing timeout\n"); + nvkm_mc_disable(device, sb->devidx); return ret; } @@ -85,8 +85,7 @@ nvkm_secboot_falcon_enable(struct nvkm_secboot *sb) /* enable IRQs */ nvkm_wr32(device, sb->base + 0x010, 0xff); - nvkm_mask(device, 0x640, sb->irq_mask, sb->irq_mask); - nvkm_mask(device, 0x644, sb->irq_mask, sb->irq_mask); + nvkm_mc_intr_mask(device, sb->devidx, true); return 0; } @@ -97,14 +96,13 @@ nvkm_secboot_falcon_disable(struct nvkm_secboot *sb) struct nvkm_device *device = sb->subdev.device; /* disable IRQs and wait for any previous code to complete */ - nvkm_mask(device, 0x644, sb->irq_mask, 0x0); - nvkm_mask(device, 0x640, sb->irq_mask, 0x0); + nvkm_mc_intr_mask(device, sb->devidx, false); nvkm_wr32(device, sb->base + 0x014, 0xff); falcon_wait_idle(device, sb->base); /* disable engine */ - nvkm_mask(device, 0x200, sb->enable_mask, 0x0); + nvkm_mc_disable(device, sb->devidx); return 0; } @@ -216,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 @@ -270,9 +261,8 @@ nvkm_secboot_ctor(const struct nvkm_secboot_func *func, /* setup the performing falcon's base address and masks */ switch (func->boot_falcon) { case NVKM_SECBOOT_FALCON_PMU: + sb->devidx = NVKM_SUBDEV_PMU; sb->base = 0x10a000; - sb->irq_mask = 0x1000000; - sb->enable_mask = 0x2000; break; default: nvkm_error(&sb->subdev, "invalid secure boot falcon\n"); diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/secboot/gm200.c b/drivers/gpu/drm/nouveau/nvkm/subdev/secboot/gm200.c index cc100dc940ea..f1e2dc914366 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/secboot/gm200.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/secboot/gm200.c @@ -860,6 +860,8 @@ gm200_secboot_prepare_ls_blob(struct gm200_secboot *gsb) /* Write LS blob */ ret = ls_ucode_mgr_write_wpr(gsb, &mgr, gsb->ls_blob); + if (ret) + nvkm_gpuobj_del(&gsb->ls_blob); cleanup: ls_ucode_mgr_cleanup(&mgr); @@ -1023,29 +1025,34 @@ gm20x_secboot_prepare_blobs(struct gm200_secboot *gsb) int ret; /* Load and prepare the managed falcon's firmwares */ - ret = gm200_secboot_prepare_ls_blob(gsb); - if (ret) - return ret; + if (!gsb->ls_blob) { + ret = gm200_secboot_prepare_ls_blob(gsb); + if (ret) + return ret; + } /* Load the HS firmware that will load the LS firmwares */ - ret = gm200_secboot_prepare_hs_blob(gsb, "acr/ucode_load", - &gsb->acr_load_blob, - &gsb->acr_load_bl_desc, true); - if (ret) - return ret; + if (!gsb->acr_load_blob) { + ret = gm200_secboot_prepare_hs_blob(gsb, "acr/ucode_load", + &gsb->acr_load_blob, + &gsb->acr_load_bl_desc, true); + if (ret) + return ret; + } /* Load the HS firmware bootloader */ - ret = gm200_secboot_prepare_hsbl_blob(gsb); - if (ret) - return ret; + if (!gsb->hsbl_blob) { + ret = gm200_secboot_prepare_hsbl_blob(gsb); + if (ret) + return ret; + } return 0; } 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); @@ -1053,15 +1060,37 @@ gm200_secboot_prepare_blobs(struct nvkm_secboot *sb) return ret; /* dGPU only: load the HS firmware that unprotects the WPR region */ - ret = gm200_secboot_prepare_hs_blob(gsb, "acr/ucode_unload", - &gsb->acr_unload_blob, - &gsb->acr_unload_bl_desc, false); - if (ret) - return ret; + if (!gsb->acr_unload_blob) { + ret = gm200_secboot_prepare_hs_blob(gsb, "acr/ucode_unload", + &gsb->acr_unload_blob, + &gsb->acr_unload_bl_desc, false); + if (ret) + return ret; + } 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; +} /* @@ -1234,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 @@ -1373,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) | @@ -1415,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 @@ -1487,3 +1521,19 @@ MODULE_FIRMWARE("nvidia/gm206/gr/sw_ctx.bin"); MODULE_FIRMWARE("nvidia/gm206/gr/sw_nonctx.bin"); MODULE_FIRMWARE("nvidia/gm206/gr/sw_bundle_init.bin"); MODULE_FIRMWARE("nvidia/gm206/gr/sw_method_init.bin"); + +MODULE_FIRMWARE("nvidia/gp100/acr/bl.bin"); +MODULE_FIRMWARE("nvidia/gp100/acr/ucode_load.bin"); +MODULE_FIRMWARE("nvidia/gp100/acr/ucode_unload.bin"); +MODULE_FIRMWARE("nvidia/gp100/gr/fecs_bl.bin"); +MODULE_FIRMWARE("nvidia/gp100/gr/fecs_inst.bin"); +MODULE_FIRMWARE("nvidia/gp100/gr/fecs_data.bin"); +MODULE_FIRMWARE("nvidia/gp100/gr/fecs_sig.bin"); +MODULE_FIRMWARE("nvidia/gp100/gr/gpccs_bl.bin"); +MODULE_FIRMWARE("nvidia/gp100/gr/gpccs_inst.bin"); +MODULE_FIRMWARE("nvidia/gp100/gr/gpccs_data.bin"); +MODULE_FIRMWARE("nvidia/gp100/gr/gpccs_sig.bin"); +MODULE_FIRMWARE("nvidia/gp100/gr/sw_ctx.bin"); +MODULE_FIRMWARE("nvidia/gp100/gr/sw_nonctx.bin"); +MODULE_FIRMWARE("nvidia/gp100/gr/sw_bundle_init.bin"); +MODULE_FIRMWARE("nvidia/gp100/gr/sw_method_init.bin"); 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, }; @@ -147,32 +174,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) { struct gm200_secboot *gsb = gm200_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 f2b09dee7c5d..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); @@ -147,10 +146,8 @@ struct hsflcn_acr_desc { * @inst: instance block for HS falcon * @pgd: page directory for the HS falcon * @vm: address space used by the HS falcon - * @bl_desc_size: size of the BL descriptor used by this chip. - * @fixup_bl_desc: hook that generates the proper BL descriptor format from - * the generic GM200 format into a data array of size - * bl_desc_size + * @falcon_state: current state of the managed falcons + * @firmware_ok: whether the firmware blobs have been created */ struct gm200_secboot { struct nvkm_secboot base; @@ -196,9 +193,19 @@ struct gm200_secboot { RUNNING, } falcon_state[NVKM_SECBOOT_FALCON_END]; + bool firmware_ok; }; #define gm200_secboot(sb) container_of(sb, struct gm200_secboot, base) +/** + * Contains functions we wish to abstract between GM200-like implementations + * @bl_desc_size: size of the BL descriptor used by this chip. + * @fixup_bl_desc: hook that generates the proper BL descriptor format from + * 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 { /* * Size of the bootloader descriptor for this chip. A block of this @@ -214,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 *); |