summaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/nouveau/nvkm
diff options
context:
space:
mode:
authorAlexandre Courbot <acourbot@nvidia.com>2016-11-15 16:26:09 +0900
committerBen Skeggs <bskeggs@redhat.com>2017-03-07 17:05:12 +1000
commitfc12745717392b5a4421a72c98cfce2c1f287d70 (patch)
treeabc27a119cdcd33d9047b84d8c17ca5bd663f488 /drivers/gpu/drm/nouveau/nvkm
parent7775d0dcb215ce0eb639940d201fb9f557823bd7 (diff)
downloadop-kernel-dev-fc12745717392b5a4421a72c98cfce2c1f287d70.zip
op-kernel-dev-fc12745717392b5a4421a72c98cfce2c1f287d70.tar.gz
drm/nouveau/secboot: check that WPR region is properly set
The ACR firmware may return no error but fail nonetheless. Such cases can be detected by verifying that the WPR region has been properly set in FB. If this is not the case, this is an error, but the unload firmware should still not be run. Signed-off-by: Alexandre Courbot <acourbot@nvidia.com> Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
Diffstat (limited to 'drivers/gpu/drm/nouveau/nvkm')
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/secboot/acr_r352.c41
1 files changed, 39 insertions, 2 deletions
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/secboot/acr_r352.c b/drivers/gpu/drm/nouveau/nvkm/subdev/secboot/acr_r352.c
index 40c6568..9e64b7c 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/secboot/acr_r352.c
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/secboot/acr_r352.c
@@ -876,6 +876,37 @@ acr_r352_shutdown(struct acr_r352 *acr, struct nvkm_secboot *sb)
return 0;
}
+/**
+ * Check if the WPR region has been indeed set by the ACR firmware, and
+ * matches where it should be.
+ */
+static bool
+acr_r352_wpr_is_set(const struct acr_r352 *acr, const struct nvkm_secboot *sb)
+{
+ const struct nvkm_subdev *subdev = &sb->subdev;
+ const struct nvkm_device *device = subdev->device;
+ u64 wpr_lo, wpr_hi;
+ u64 wpr_range_lo, wpr_range_hi;
+
+ nvkm_wr32(device, 0x100cd4, 0x2);
+ wpr_lo = (nvkm_rd32(device, 0x100cd4) & ~0xff);
+ wpr_lo <<= 8;
+ nvkm_wr32(device, 0x100cd4, 0x3);
+ wpr_hi = (nvkm_rd32(device, 0x100cd4) & ~0xff);
+ wpr_hi <<= 8;
+
+ if (sb->wpr_size != 0) {
+ wpr_range_lo = sb->wpr_addr;
+ wpr_range_hi = wpr_range_lo + sb->wpr_size;
+ } else {
+ wpr_range_lo = acr->ls_blob->addr;
+ wpr_range_hi = wpr_range_lo + acr->ls_blob->size;
+ }
+
+ return (wpr_lo >= wpr_range_lo && wpr_lo < wpr_range_hi &&
+ wpr_hi > wpr_range_lo && wpr_hi <= wpr_range_hi);
+}
+
static int
acr_r352_bootstrap(struct acr_r352 *acr, struct nvkm_secboot *sb)
{
@@ -896,11 +927,17 @@ acr_r352_bootstrap(struct acr_r352 *acr, struct nvkm_secboot *sb)
ret = sb->func->run_blob(sb, acr->load_blob);
/* clear halt interrupt */
nvkm_falcon_clear_interrupt(sb->boot_falcon, 0x10);
+ sb->wpr_set = acr_r352_wpr_is_set(acr, sb);
if (ret)
return ret;
nvkm_debug(subdev, "HS load blob completed\n");
-
- sb->wpr_set = true;
+ if (ret)
+ return ret;
+ /* WPR must be set at this point */
+ if (!sb->wpr_set) {
+ nvkm_error(subdev, "ACR blob completed but WPR not set!\n");
+ return -EINVAL;
+ }
/* Run LS firmwares post_run hooks */
for_each_set_bit(falcon_id, &managed_falcons, NVKM_SECBOOT_FALCON_END) {
OpenPOWER on IntegriCloud