Commit 598a8148 authored by Alexandre Courbot's avatar Alexandre Courbot Committed by Ben Skeggs

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: default avatarAlexandre Courbot <acourbot@nvidia.com>
Signed-off-by: default avatarBen Skeggs <bskeggs@redhat.com>
parent e5ffa727
...@@ -41,7 +41,6 @@ int nvkm_msgqueue_reinit(struct nvkm_msgqueue *); ...@@ -41,7 +41,6 @@ int nvkm_msgqueue_reinit(struct nvkm_msgqueue *);
void nvkm_msgqueue_write_cmdline(struct nvkm_msgqueue *, void *); void nvkm_msgqueue_write_cmdline(struct nvkm_msgqueue *, void *);
/* interface to ACR unit running on falcon (NVIDIA signed firmware) */ /* interface to ACR unit running on falcon (NVIDIA signed firmware) */
int nvkm_msgqueue_acr_boot_falcon(struct nvkm_msgqueue *, int nvkm_msgqueue_acr_boot_falcons(struct nvkm_msgqueue *, unsigned long);
enum nvkm_secboot_falcon);
#endif #endif
...@@ -55,7 +55,7 @@ struct nvkm_secboot { ...@@ -55,7 +55,7 @@ struct nvkm_secboot {
#define nvkm_secboot(p) container_of((p), struct nvkm_secboot, subdev) #define nvkm_secboot(p) container_of((p), struct nvkm_secboot, subdev)
bool nvkm_secboot_is_managed(struct nvkm_secboot *, enum nvkm_secboot_falcon); 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 gm200_secboot_new(struct nvkm_device *, int, struct nvkm_secboot **);
int gm20b_secboot_new(struct nvkm_device *, int, struct nvkm_secboot **); int gm20b_secboot_new(struct nvkm_device *, int, struct nvkm_secboot **);
......
...@@ -1463,25 +1463,27 @@ gf100_gr_init_ctxctl_ext(struct gf100_gr *gr) ...@@ -1463,25 +1463,27 @@ gf100_gr_init_ctxctl_ext(struct gf100_gr *gr)
struct nvkm_subdev *subdev = &gr->base.engine.subdev; struct nvkm_subdev *subdev = &gr->base.engine.subdev;
struct nvkm_device *device = subdev->device; struct nvkm_device *device = subdev->device;
struct nvkm_secboot *sb = device->secboot; struct nvkm_secboot *sb = device->secboot;
int ret = 0; u32 secboot_mask = 0;
/* load fuc microcode */ /* load fuc microcode */
nvkm_mc_unk260(device, 0); nvkm_mc_unk260(device, 0);
/* securely-managed falcons must be reset using secure boot */ /* securely-managed falcons must be reset using secure boot */
if (nvkm_secboot_is_managed(sb, NVKM_SECBOOT_FALCON_FECS)) 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 else
gf100_gr_init_fw(gr->fecs, &gr->fuc409c, &gr->fuc409d); gf100_gr_init_fw(gr->fecs, &gr->fuc409c, &gr->fuc409d);
if (ret)
return ret;
if (nvkm_secboot_is_managed(sb, NVKM_SECBOOT_FALCON_GPCCS)) 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 else
gf100_gr_init_fw(gr->gpccs, &gr->fuc41ac, &gr->fuc41ad); 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); nvkm_mc_unk260(device, 1);
......
...@@ -463,12 +463,31 @@ nvkm_msgqueue_write_cmdline(struct nvkm_msgqueue *queue, void *buf) ...@@ -463,12 +463,31 @@ nvkm_msgqueue_write_cmdline(struct nvkm_msgqueue *queue, void *buf)
} }
int 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;
/* 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; return -ENODEV;
return queue->func->acr_func->boot_falcon(queue, falcon); 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 int
......
...@@ -101,9 +101,11 @@ struct nvkm_msgqueue_init_func { ...@@ -101,9 +101,11 @@ struct nvkm_msgqueue_init_func {
* struct nvkm_msgqueue_acr_func - msgqueue functions related to ACR * struct nvkm_msgqueue_acr_func - msgqueue functions related to ACR
* *
* @boot_falcon: build and send the command to reset a given falcon * @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 { struct nvkm_msgqueue_acr_func {
int (*boot_falcon)(struct nvkm_msgqueue *, enum nvkm_secboot_falcon); int (*boot_falcon)(struct nvkm_msgqueue *, enum nvkm_secboot_falcon);
int (*boot_multiple_falcons)(struct nvkm_msgqueue *, unsigned long);
}; };
struct nvkm_msgqueue_func { struct nvkm_msgqueue_func {
......
...@@ -39,8 +39,7 @@ struct nvkm_acr_func { ...@@ -39,8 +39,7 @@ struct nvkm_acr_func {
int (*fini)(struct nvkm_acr *, struct nvkm_secboot *, bool); int (*fini)(struct nvkm_acr *, struct nvkm_secboot *, bool);
int (*load)(struct nvkm_acr *, struct nvkm_falcon *, int (*load)(struct nvkm_acr *, struct nvkm_falcon *,
struct nvkm_gpuobj *, u64); struct nvkm_gpuobj *, u64);
int (*reset)(struct nvkm_acr *, struct nvkm_secboot *, int (*reset)(struct nvkm_acr *, struct nvkm_secboot *, unsigned long);
enum nvkm_secboot_falcon);
}; };
/** /**
......
...@@ -976,15 +976,16 @@ acr_r352_bootstrap(struct acr_r352 *acr, struct nvkm_secboot *sb) ...@@ -976,15 +976,16 @@ acr_r352_bootstrap(struct acr_r352 *acr, struct nvkm_secboot *sb)
*/ */
static int static int
acr_r352_reset_nopmu(struct acr_r352 *acr, struct nvkm_secboot *sb, 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; int ret;
/* /*
* Perform secure boot each time we are called on FECS. Since only FECS * 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. * 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; goto end;
ret = acr_r352_shutdown(acr, sb); ret = acr_r352_shutdown(acr, sb);
...@@ -996,7 +997,9 @@ acr_r352_reset_nopmu(struct acr_r352 *acr, struct nvkm_secboot *sb, ...@@ -996,7 +997,9 @@ acr_r352_reset_nopmu(struct acr_r352 *acr, struct nvkm_secboot *sb,
return ret; return ret;
end: end:
acr->falcon_state[falcon] = RESET; for_each_set_bit(falcon, &falcon_mask, NVKM_SECBOOT_FALCON_END) {
acr->falcon_state[falcon] = RESET;
}
return 0; return 0;
} }
...@@ -1009,11 +1012,11 @@ acr_r352_reset_nopmu(struct acr_r352 *acr, struct nvkm_secboot *sb, ...@@ -1009,11 +1012,11 @@ acr_r352_reset_nopmu(struct acr_r352 *acr, struct nvkm_secboot *sb,
*/ */
static int static int
acr_r352_reset(struct nvkm_acr *_acr, struct nvkm_secboot *sb, 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 acr_r352 *acr = acr_r352(_acr);
struct nvkm_msgqueue *queue; struct nvkm_msgqueue *queue;
const char *fname = nvkm_secboot_falcon_name[falcon]; int falcon;
bool wpr_already_set = sb->wpr_set; bool wpr_already_set = sb->wpr_set;
int ret; int ret;
...@@ -1026,7 +1029,7 @@ acr_r352_reset(struct nvkm_acr *_acr, struct nvkm_secboot *sb, ...@@ -1026,7 +1029,7 @@ acr_r352_reset(struct nvkm_acr *_acr, struct nvkm_secboot *sb,
if (!nvkm_secboot_is_managed(sb, _acr->boot_falcon)) { if (!nvkm_secboot_is_managed(sb, _acr->boot_falcon)) {
/* Redo secure boot entirely if it was already done */ /* Redo secure boot entirely if it was already done */
if (wpr_already_set) 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 the result of the initial invokation */
else else
return ret; return ret;
...@@ -1044,13 +1047,15 @@ acr_r352_reset(struct nvkm_acr *_acr, struct nvkm_secboot *sb, ...@@ -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 */ /* Otherwise just ask the LS firmware to reset the falcon */
nvkm_debug(&sb->subdev, "resetting %s falcon\n", fname); for_each_set_bit(falcon, &falcon_mask, NVKM_SECBOOT_FALCON_END)
ret = nvkm_msgqueue_acr_boot_falcon(queue, falcon); nvkm_debug(&sb->subdev, "resetting %s falcon\n",
nvkm_secboot_falcon_name[falcon]);
ret = nvkm_msgqueue_acr_boot_falcons(queue, falcon_mask);
if (ret) { 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; return ret;
} }
nvkm_debug(&sb->subdev, "falcon %s reset\n", fname); nvkm_debug(&sb->subdev, "falcon reset done\n");
return 0; return 0;
} }
......
...@@ -102,15 +102,15 @@ nvkm_secboot_falcon_name[] = { ...@@ -102,15 +102,15 @@ nvkm_secboot_falcon_name[] = {
* nvkm_secboot_reset() - reset specified falcon * nvkm_secboot_reset() - reset specified falcon
*/ */
int 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? */ /* 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"); nvkm_error(&sb->subdev, "cannot reset unmanaged falcon!\n");
return -EINVAL; return -EINVAL;
} }
return sb->acr->func->reset(sb->acr, sb, falcon); return sb->acr->func->reset(sb->acr, sb, falcon_mask);
} }
/** /**
......
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