drm/nouveau/secboot: allow to boot multiple falcons

Change the secboot and msgqueue interfaces to take a mask of falcons to
reset instead of a single falcon. The GP10B firmware interface requires
FECS and GPCCS to be booted in a single firmware command.

For firmwares that only support single falcon boot, it is trivial to
loop over the mask and boot each falcons individually.

Signed-off-by: Alexandre Courbot <acourbot@nvidia.com>
Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
This commit is contained in:
Alexandre Courbot 2017-03-29 18:31:09 +09:00 committed by Ben Skeggs
parent e5ffa727e5
commit 598a8148e7
8 changed files with 54 additions and 28 deletions

View File

@ -41,7 +41,6 @@ int nvkm_msgqueue_reinit(struct nvkm_msgqueue *);
void nvkm_msgqueue_write_cmdline(struct nvkm_msgqueue *, void *);
/* interface to ACR unit running on falcon (NVIDIA signed firmware) */
int nvkm_msgqueue_acr_boot_falcon(struct nvkm_msgqueue *,
enum nvkm_secboot_falcon);
int nvkm_msgqueue_acr_boot_falcons(struct nvkm_msgqueue *, unsigned long);
#endif

View File

@ -55,7 +55,7 @@ struct nvkm_secboot {
#define nvkm_secboot(p) container_of((p), struct nvkm_secboot, subdev)
bool nvkm_secboot_is_managed(struct nvkm_secboot *, enum nvkm_secboot_falcon);
int nvkm_secboot_reset(struct nvkm_secboot *, enum nvkm_secboot_falcon);
int nvkm_secboot_reset(struct nvkm_secboot *, unsigned long);
int gm200_secboot_new(struct nvkm_device *, int, struct nvkm_secboot **);
int gm20b_secboot_new(struct nvkm_device *, int, struct nvkm_secboot **);

View File

@ -1463,25 +1463,27 @@ gf100_gr_init_ctxctl_ext(struct gf100_gr *gr)
struct nvkm_subdev *subdev = &gr->base.engine.subdev;
struct nvkm_device *device = subdev->device;
struct nvkm_secboot *sb = device->secboot;
int ret = 0;
u32 secboot_mask = 0;
/* load fuc microcode */
nvkm_mc_unk260(device, 0);
/* securely-managed falcons must be reset using secure boot */
if (nvkm_secboot_is_managed(sb, NVKM_SECBOOT_FALCON_FECS))
ret = nvkm_secboot_reset(sb, NVKM_SECBOOT_FALCON_FECS);
secboot_mask |= BIT(NVKM_SECBOOT_FALCON_FECS);
else
gf100_gr_init_fw(gr->fecs, &gr->fuc409c, &gr->fuc409d);
if (ret)
return ret;
if (nvkm_secboot_is_managed(sb, NVKM_SECBOOT_FALCON_GPCCS))
ret = nvkm_secboot_reset(sb, NVKM_SECBOOT_FALCON_GPCCS);
secboot_mask |= BIT(NVKM_SECBOOT_FALCON_GPCCS);
else
gf100_gr_init_fw(gr->gpccs, &gr->fuc41ac, &gr->fuc41ad);
if (ret)
return ret;
if (secboot_mask != 0) {
int ret = nvkm_secboot_reset(sb, secboot_mask);
if (ret)
return ret;
}
nvkm_mc_unk260(device, 1);

View File

@ -463,12 +463,31 @@ nvkm_msgqueue_write_cmdline(struct nvkm_msgqueue *queue, void *buf)
}
int
nvkm_msgqueue_acr_boot_falcon(struct nvkm_msgqueue *queue, enum nvkm_secboot_falcon falcon)
nvkm_msgqueue_acr_boot_falcons(struct nvkm_msgqueue *queue,
unsigned long falcon_mask)
{
if (!queue || !queue->func->acr_func || !queue->func->acr_func->boot_falcon)
unsigned long falcon;
if (!queue || !queue->func->acr_func)
return -ENODEV;
return queue->func->acr_func->boot_falcon(queue, falcon);
/* Does the firmware support booting multiple falcons? */
if (queue->func->acr_func->boot_multiple_falcons)
return queue->func->acr_func->boot_multiple_falcons(queue,
falcon_mask);
/* Else boot all requested falcons individually */
if (!queue->func->acr_func->boot_falcon)
return -ENODEV;
for_each_set_bit(falcon, &falcon_mask, NVKM_SECBOOT_FALCON_END) {
int ret = queue->func->acr_func->boot_falcon(queue, falcon);
if (ret)
return ret;
}
return 0;
}
int

View File

@ -101,9 +101,11 @@ struct nvkm_msgqueue_init_func {
* struct nvkm_msgqueue_acr_func - msgqueue functions related to ACR
*
* @boot_falcon: build and send the command to reset a given falcon
* @boot_multiple_falcons: build and send the command to reset several falcons
*/
struct nvkm_msgqueue_acr_func {
int (*boot_falcon)(struct nvkm_msgqueue *, enum nvkm_secboot_falcon);
int (*boot_multiple_falcons)(struct nvkm_msgqueue *, unsigned long);
};
struct nvkm_msgqueue_func {

View File

@ -39,8 +39,7 @@ struct nvkm_acr_func {
int (*fini)(struct nvkm_acr *, struct nvkm_secboot *, bool);
int (*load)(struct nvkm_acr *, struct nvkm_falcon *,
struct nvkm_gpuobj *, u64);
int (*reset)(struct nvkm_acr *, struct nvkm_secboot *,
enum nvkm_secboot_falcon);
int (*reset)(struct nvkm_acr *, struct nvkm_secboot *, unsigned long);
};
/**

View File

@ -976,15 +976,16 @@ acr_r352_bootstrap(struct acr_r352 *acr, struct nvkm_secboot *sb)
*/
static int
acr_r352_reset_nopmu(struct acr_r352 *acr, struct nvkm_secboot *sb,
enum nvkm_secboot_falcon falcon)
unsigned long falcon_mask)
{
int falcon;
int ret;
/*
* 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)
if (!(falcon_mask & BIT(NVKM_SECBOOT_FALCON_FECS)))
goto end;
ret = acr_r352_shutdown(acr, sb);
@ -996,7 +997,9 @@ acr_r352_reset_nopmu(struct acr_r352 *acr, struct nvkm_secboot *sb,
return ret;
end:
acr->falcon_state[falcon] = RESET;
for_each_set_bit(falcon, &falcon_mask, NVKM_SECBOOT_FALCON_END) {
acr->falcon_state[falcon] = RESET;
}
return 0;
}
@ -1009,11 +1012,11 @@ end:
*/
static int
acr_r352_reset(struct nvkm_acr *_acr, struct nvkm_secboot *sb,
enum nvkm_secboot_falcon falcon)
unsigned long falcon_mask)
{
struct acr_r352 *acr = acr_r352(_acr);
struct nvkm_msgqueue *queue;
const char *fname = nvkm_secboot_falcon_name[falcon];
int falcon;
bool wpr_already_set = sb->wpr_set;
int ret;
@ -1026,7 +1029,7 @@ acr_r352_reset(struct nvkm_acr *_acr, struct nvkm_secboot *sb,
if (!nvkm_secboot_is_managed(sb, _acr->boot_falcon)) {
/* Redo secure boot entirely if it was already done */
if (wpr_already_set)
return acr_r352_reset_nopmu(acr, sb, falcon);
return acr_r352_reset_nopmu(acr, sb, falcon_mask);
/* Else return the result of the initial invokation */
else
return ret;
@ -1044,13 +1047,15 @@ acr_r352_reset(struct nvkm_acr *_acr, struct nvkm_secboot *sb,
}
/* Otherwise just ask the LS firmware to reset the falcon */
nvkm_debug(&sb->subdev, "resetting %s falcon\n", fname);
ret = nvkm_msgqueue_acr_boot_falcon(queue, falcon);
for_each_set_bit(falcon, &falcon_mask, NVKM_SECBOOT_FALCON_END)
nvkm_debug(&sb->subdev, "resetting %s falcon\n",
nvkm_secboot_falcon_name[falcon]);
ret = nvkm_msgqueue_acr_boot_falcons(queue, falcon_mask);
if (ret) {
nvkm_error(&sb->subdev, "cannot boot %s falcon\n", fname);
nvkm_error(&sb->subdev, "error during falcon reset: %d\n", ret);
return ret;
}
nvkm_debug(&sb->subdev, "falcon %s reset\n", fname);
nvkm_debug(&sb->subdev, "falcon reset done\n");
return 0;
}

View File

@ -102,15 +102,15 @@ nvkm_secboot_falcon_name[] = {
* nvkm_secboot_reset() - reset specified falcon
*/
int
nvkm_secboot_reset(struct nvkm_secboot *sb, enum nvkm_secboot_falcon falcon)
nvkm_secboot_reset(struct nvkm_secboot *sb, unsigned long falcon_mask)
{
/* Unmanaged falcon? */
if (!(BIT(falcon) & sb->acr->managed_falcons)) {
if ((falcon_mask | sb->acr->managed_falcons) != sb->acr->managed_falcons) {
nvkm_error(&sb->subdev, "cannot reset unmanaged falcon!\n");
return -EINVAL;
}
return sb->acr->func->reset(sb->acr, sb, falcon);
return sb->acr->func->reset(sb->acr, sb, falcon_mask);
}
/**