Commit 7579e22f authored by Alexandre Courbot's avatar Alexandre Courbot Committed by Ben Skeggs

drm/nouveau/secboot: base support for PMU falcon

Adapt secboot's behavior if a PMU firmware is present, in particular
the way LS falcons are reset. Without PMU firmware, secboot needs to be
performed again from scratch so all LS falcons are reset. With PMU
firmware, we can ask the PMU's ACR unit to reset a specific falcon
through a PMU message.

As we must preserve the old behavior to avoid breaking user-space, add a
few conditionals to the way falcons are reset.
Signed-off-by: default avatarAlexandre Courbot <acourbot@nvidia.com>
Signed-off-by: default avatarBen Skeggs <bskeggs@redhat.com>
parent eabe4ea6
......@@ -25,6 +25,9 @@
#include <core/gpuobj.h>
#include <core/firmware.h>
#include <engine/falcon.h>
#include <subdev/mc.h>
#include <subdev/pmu.h>
#include <core/msgqueue.h>
/**
* struct hsf_fw_header - HS firmware descriptor
......@@ -852,6 +855,7 @@ acr_r352_shutdown(struct acr_r352 *acr, struct nvkm_secboot *sb)
static int
acr_r352_bootstrap(struct acr_r352 *acr, struct nvkm_secboot *sb)
{
const struct nvkm_subdev *subdev = &sb->subdev;
unsigned long managed_falcons = acr->base.managed_falcons;
int falcon_id;
int ret;
......@@ -864,13 +868,13 @@ acr_r352_bootstrap(struct acr_r352 *acr, struct nvkm_secboot *sb)
if (ret)
return ret;
nvkm_debug(&sb->subdev, "running HS load blob\n");
nvkm_debug(subdev, "running HS load blob\n");
ret = sb->func->run_blob(sb, acr->load_blob);
/* clear halt interrupt */
nvkm_falcon_clear_interrupt(sb->boot_falcon, 0x10);
if (ret)
return ret;
nvkm_debug(&sb->subdev, "HS load blob completed\n");
nvkm_debug(subdev, "HS load blob completed\n");
sb->wpr_set = true;
......@@ -883,30 +887,36 @@ acr_r352_bootstrap(struct acr_r352 *acr, struct nvkm_secboot *sb)
func->post_run(&acr->base, sb);
}
/* Re-start ourselves if we are managed */
if (!nvkm_secboot_is_managed(sb, acr->base.boot_falcon))
return 0;
/* Enable interrupts */
nvkm_falcon_wr32(sb->boot_falcon, 0x10, 0xff);
nvkm_mc_intr_mask(subdev->device, sb->boot_falcon->owner->index, true);
/* Start PMU */
nvkm_falcon_start(sb->boot_falcon);
nvkm_debug(subdev, "PMU started\n");
return 0;
}
/*
* acr_r352_reset() - execute secure boot from the prepared state
/**
* acr_r352_reset_nopmu - dummy reset method when no PMU firmware is loaded
*
* Load the HS bootloader and ask the falcon to run it. This will in turn
* load the HS firmware and run it, so once the falcon stops all the managed
* falcons should have their LS firmware loaded and be ready to run.
* Reset is done by re-executing secure boot from scratch, with lazy bootstrap
* disabled. This has the effect of making all managed falcons ready-to-run.
*/
static int
acr_r352_reset(struct nvkm_acr *_acr, struct nvkm_secboot *sb,
acr_r352_reset_nopmu(struct acr_r352 *acr, struct nvkm_secboot *sb,
enum nvkm_secboot_falcon falcon)
{
struct acr_r352 *acr = acr_r352(_acr);
int ret;
/*
* Dummy GM200 implementation: perform secure boot each time we are
* called on FECS. Since only FECS and GPCCS are managed and started
* together, this ought to be safe.
*
* Once we have proper PMU firmware and support, this will be changed
* to a proper call to the PMU method.
* Perform secure boot each time we are called on FECS. Since only FECS
* and GPCCS are managed and started together, this ought to be safe.
*/
if (falcon != NVKM_SECBOOT_FALCON_FECS)
goto end;
......@@ -915,7 +925,7 @@ acr_r352_reset(struct nvkm_acr *_acr, struct nvkm_secboot *sb,
if (ret)
return ret;
acr_r352_bootstrap(acr, sb);
ret = acr_r352_bootstrap(acr, sb);
if (ret)
return ret;
......@@ -924,6 +934,45 @@ acr_r352_reset(struct nvkm_acr *_acr, struct nvkm_secboot *sb,
return 0;
}
/*
* acr_r352_reset() - execute secure boot from the prepared state
*
* Load the HS bootloader and ask the falcon to run it. This will in turn
* load the HS firmware and run it, so once the falcon stops all the managed
* falcons should have their LS firmware loaded and be ready to run.
*/
static int
acr_r352_reset(struct nvkm_acr *_acr, struct nvkm_secboot *sb,
enum nvkm_secboot_falcon falcon)
{
struct acr_r352 *acr = acr_r352(_acr);
struct nvkm_pmu *pmu = sb->subdev.device->pmu;
const char *fname = nvkm_secboot_falcon_name[falcon];
int ret;
/* Not self-managed? Redo secure boot entirely */
if (!nvkm_secboot_is_managed(sb, _acr->boot_falcon))
return acr_r352_reset_nopmu(acr, sb, falcon);
/*
* Otherwise ensure secure boot is done, and command the PMU to reset
* the desired falcon.
*/
ret = acr_r352_bootstrap(acr, sb);
if (ret)
return ret;
nvkm_debug(&sb->subdev, "resetting %s falcon\n", fname);
ret = nvkm_msgqueue_acr_boot_falcon(pmu->queue, falcon);
if (ret) {
nvkm_error(&sb->subdev, "cannot boot %s falcon\n", fname);
return ret;
}
nvkm_debug(&sb->subdev, "falcon %s reset\n", fname);
return 0;
}
static int
acr_r352_fini(struct nvkm_acr *_acr, struct nvkm_secboot *sb, bool suspend)
{
......@@ -1007,6 +1056,23 @@ acr_r352_new_(const struct acr_r352_func *func,
acr->base.func = &acr_r352_base_func;
acr->func = func;
/*
* If we have a PMU firmware, let it manage the bootstrap of other
* falcons.
*/
if (func->ls_func[NVKM_SECBOOT_FALCON_PMU] &&
(managed_falcons & BIT(NVKM_SECBOOT_FALCON_PMU))) {
int i;
for (i = 0; i < NVKM_SECBOOT_FALCON_END; i++) {
if (i == NVKM_SECBOOT_FALCON_PMU)
continue;
if (func->ls_func[i])
acr->lazy_bootstrap |= BIT(i);
}
}
return &acr->base;
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment