[v2,11/15] secboot: use falcon library

Submitted by Alexandre Courbot on Dec. 13, 2016, 8:11 a.m.

Details

Message ID 6dc892f3fb42e9c9bbb9a86277ab233b6fbe2ca2.1481616662.git-series.acourbot@nvidia.com
State New
Headers show
Series "Falcon library" ( rev: 3 ) in Nouveau

Not browsing as part of any series.

Commit Message

Alexandre Courbot Dec. 13, 2016, 8:11 a.m.
Use the falcon library functions in secure boot. This removes a lot of
code and makes the secure boot flow easier to understand as no register
is directly accessed.

Signed-off-by: Alexandre Courbot <acourbot@nvidia.com>
---
 drm/nouveau/include/nvkm/subdev/secboot.h |   4 +-
 drm/nouveau/nvkm/subdev/secboot/base.c    | 146 +----------------------
 drm/nouveau/nvkm/subdev/secboot/gm200.c   | 125 ++++++--------------
 drm/nouveau/nvkm/subdev/secboot/priv.h    |   2 +-
 4 files changed, 51 insertions(+), 226 deletions(-)

Patch hide | download patch | download mbox

diff --git a/drm/nouveau/include/nvkm/subdev/secboot.h b/drm/nouveau/include/nvkm/subdev/secboot.h
index 781586b8cc34..2a2f651ccceb 100644
--- a/drm/nouveau/include/nvkm/subdev/secboot.h
+++ b/drm/nouveau/include/nvkm/subdev/secboot.h
@@ -42,9 +42,7 @@  enum nvkm_secboot_falcon {
 struct nvkm_secboot {
 	const struct nvkm_secboot_func *func;
 	struct nvkm_subdev subdev;
-
-	enum nvkm_devidx devidx;
-	u32 base;
+	struct nvkm_falcon *boot_falcon;
 };
 #define nvkm_secboot(p) container_of((p), struct nvkm_secboot, subdev)
 
diff --git a/drm/nouveau/nvkm/subdev/secboot/base.c b/drm/nouveau/nvkm/subdev/secboot/base.c
index 6ee140ee4415..633dee87ac98 100644
--- a/drm/nouveau/nvkm/subdev/secboot/base.c
+++ b/drm/nouveau/nvkm/subdev/secboot/base.c
@@ -23,6 +23,7 @@ 
 
 #include <subdev/mc.h>
 #include <subdev/timer.h>
+#include <subdev/pmu.h>
 
 static const char *
 managed_falcons_names[] = {
@@ -32,130 +33,6 @@  managed_falcons_names[] = {
 	[NVKM_SECBOOT_FALCON_GPCCS] = "GPCCS",
 	[NVKM_SECBOOT_FALCON_END] = "<invalid>",
 };
-
-/*
- * Helper falcon functions
- */
-
-static int
-falcon_clear_halt_interrupt(struct nvkm_device *device, u32 base)
-{
-	int ret;
-
-	/* clear halt interrupt */
-	nvkm_mask(device, base + 0x004, 0x10, 0x10);
-	/* wait until halt interrupt is cleared */
-	ret = nvkm_wait_msec(device, 10, base + 0x008, 0x10, 0x0);
-	if (ret < 0)
-		return ret;
-
-	return 0;
-}
-
-static int
-falcon_wait_idle(struct nvkm_device *device, u32 base)
-{
-	int ret;
-
-	ret = nvkm_wait_msec(device, 10, base + 0x04c, 0xffff, 0x0);
-	if (ret < 0)
-		return ret;
-
-	return 0;
-}
-
-static int
-nvkm_secboot_falcon_enable(struct nvkm_secboot *sb)
-{
-	struct nvkm_device *device = sb->subdev.device;
-	int ret;
-
-	/* enable engine */
-	nvkm_mc_enable(device, sb->devidx);
-	ret = nvkm_wait_msec(device, 10, sb->base + 0x10c, 0x6, 0x0);
-	if (ret < 0) {
-		nvkm_error(&sb->subdev, "Falcon mem scrubbing timeout\n");
-		nvkm_mc_disable(device, sb->devidx);
-		return ret;
-	}
-
-	ret = falcon_wait_idle(device, sb->base);
-	if (ret)
-		return ret;
-
-	/* enable IRQs */
-	nvkm_wr32(device, sb->base + 0x010, 0xff);
-	nvkm_mc_intr_mask(device, sb->devidx, true);
-
-	return 0;
-}
-
-static int
-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_mc_intr_mask(device, sb->devidx, false);
-	nvkm_wr32(device, sb->base + 0x014, 0xff);
-
-	falcon_wait_idle(device, sb->base);
-
-	/* disable engine */
-	nvkm_mc_disable(device, sb->devidx);
-
-	return 0;
-}
-
-int
-nvkm_secboot_falcon_reset(struct nvkm_secboot *sb)
-{
-	int ret;
-
-	ret = nvkm_secboot_falcon_disable(sb);
-	if (ret)
-		return ret;
-
-	ret = nvkm_secboot_falcon_enable(sb);
-	if (ret)
-		return ret;
-
-	return 0;
-}
-
-/**
- * nvkm_secboot_falcon_run - run the falcon that will perform secure boot
- *
- * This function is to be called after all chip-specific preparations have
- * been completed. It will start the falcon to perform secure boot, wait for
- * it to halt, and report if an error occurred.
- */
-int
-nvkm_secboot_falcon_run(struct nvkm_secboot *sb)
-{
-	struct nvkm_device *device = sb->subdev.device;
-	int ret;
-
-	/* Start falcon */
-	nvkm_wr32(device, sb->base + 0x100, 0x2);
-
-	/* Wait for falcon halt */
-	ret = nvkm_wait_msec(device, 100, sb->base + 0x100, 0x10, 0x10);
-	if (ret < 0)
-		return ret;
-
-	/* If mailbox register contains an error code, then ACR has failed */
-	ret = nvkm_rd32(device, sb->base + 0x040);
-	if (ret) {
-		nvkm_error(&sb->subdev, "ACR boot failed, ret 0x%08x", ret);
-		falcon_clear_halt_interrupt(device, sb->base);
-		return -EINVAL;
-	}
-
-	return 0;
-}
-
-
 /**
  * nvkm_secboot_reset() - reset specified falcon
  */
@@ -205,6 +82,16 @@  nvkm_secboot_oneinit(struct nvkm_subdev *subdev)
 	struct nvkm_secboot *sb = nvkm_secboot(subdev);
 	int ret = 0;
 
+	switch (sb->func->boot_falcon) {
+	case NVKM_SECBOOT_FALCON_PMU:
+		sb->boot_falcon = &subdev->device->pmu->falcon;
+		break;
+	default:
+		nvkm_error(subdev, "Unmanaged boot falcon %s!\n",
+			   managed_falcons_names[sb->func->boot_falcon]);
+		return -EINVAL;
+	}
+
 	/* Call chip-specific init function */
 	if (sb->func->init)
 		ret = sb->func->init(sb);
@@ -258,17 +145,6 @@  nvkm_secboot_ctor(const struct nvkm_secboot_func *func,
 	nvkm_subdev_ctor(&nvkm_secboot, device, index, &sb->subdev);
 	sb->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;
-		break;
-	default:
-		nvkm_error(&sb->subdev, "invalid secure boot falcon\n");
-		return -EINVAL;
-	};
-
 	nvkm_debug(&sb->subdev, "securely managed falcons:\n");
 	for_each_set_bit(fid, &sb->func->managed_falcons,
 			 NVKM_SECBOOT_FALCON_END)
diff --git a/drm/nouveau/nvkm/subdev/secboot/gm200.c b/drm/nouveau/nvkm/subdev/secboot/gm200.c
index ec48e4ace37a..667582a92d77 100644
--- a/drm/nouveau/nvkm/subdev/secboot/gm200.c
+++ b/drm/nouveau/nvkm/subdev/secboot/gm200.c
@@ -86,14 +86,7 @@ 
 #include <core/gpuobj.h>
 #include <core/firmware.h>
 #include <subdev/fb.h>
-
-enum {
-	FALCON_DMAIDX_UCODE		= 0,
-	FALCON_DMAIDX_VIRT		= 1,
-	FALCON_DMAIDX_PHYS_VID		= 2,
-	FALCON_DMAIDX_PHYS_SYS_COH	= 3,
-	FALCON_DMAIDX_PHYS_SYS_NCOH	= 4,
-};
+#include <engine/falcon.h>
 
 /**
  * struct fw_bin_header - header of firmware files
@@ -887,7 +880,7 @@  gm200_secboot_hsf_patch_signature(struct gm200_secboot *gsb, void *acr_image)
 	u32 sig_size;
 
 	/* Falcon in debug or production mode? */
-	if ((nvkm_rd32(sb->subdev.device, sb->base + 0xc08) >> 20) & 0x1) {
+	if (sb->boot_falcon->debug) {
 		sig = acr_image + fw_hdr->sig_dbg_offset;
 		sig_size = fw_hdr->sig_dbg_size;
 	} else {
@@ -1101,96 +1094,33 @@  gm200_secboot_blobs_ready(struct gm200_secboot *gsb)
  * gm200_secboot_load_hs_bl() - load HS bootloader into DMEM and IMEM
  */
 static void
-gm200_secboot_load_hs_bl(struct gm200_secboot *gsb, void *data, u32 data_size)
+gm200_secboot_load_hs_bl(struct gm200_secboot *gsb, struct nvkm_falcon *falcon,
+			 void *data, u32 data_size)
 {
-	struct nvkm_device *device = gsb->base.subdev.device;
 	struct fw_bin_header *hdr = gsb->hsbl_blob;
 	struct fw_bl_desc *hsbl_desc = gsb->hsbl_blob + hdr->header_offset;
 	void *blob_data = gsb->hsbl_blob + hdr->data_offset;
 	void *hsbl_code = blob_data + hsbl_desc->code_off;
 	void *hsbl_data = blob_data + hsbl_desc->data_off;
 	u32 code_size = ALIGN(hsbl_desc->code_size, 256);
-	const u32 base = gsb->base.base;
-	u32 blk;
 	u32 tag;
-	int i;
 
 	/*
 	 * Copy HS bootloader data
 	 */
-	nvkm_wr32(device, base + 0x1c0, (0x00000000 | (0x1 << 24)));
-	for (i = 0; i < hsbl_desc->data_size / 4; i++)
-		nvkm_wr32(device, base + 0x1c4, ((u32 *)hsbl_data)[i]);
+	nvkm_falcon_load_dmem(falcon, hsbl_data, 0x0, hsbl_desc->data_size, 0);
 
 	/*
 	 * Copy HS bootloader interface structure where the HS descriptor
 	 * expects it to be
 	 */
-	nvkm_wr32(device, base + 0x1c0,
-		  (hsbl_desc->dmem_load_off | (0x1 << 24)));
-	for (i = 0; i < data_size / 4; i++)
-		nvkm_wr32(device, base + 0x1c4, ((u32 *)data)[i]);
+	nvkm_falcon_load_dmem(falcon, data, hsbl_desc->dmem_load_off, data_size,
+			      0);
 
 	/* Copy HS bootloader code to end of IMEM */
-	blk = (nvkm_rd32(device, base + 0x108) & 0x1ff) - (code_size >> 8);
 	tag = hsbl_desc->start_tag;
-	nvkm_wr32(device, base + 0x180, ((blk & 0xff) << 8) | (0x1 << 24));
-	for (i = 0; i < code_size / 4; i++) {
-		/* write new tag every 256B */
-		if ((i & 0x3f) == 0) {
-			nvkm_wr32(device, base + 0x188, tag & 0xffff);
-			tag++;
-		}
-		nvkm_wr32(device, base + 0x184, ((u32 *)hsbl_code)[i]);
-	}
-	nvkm_wr32(device, base + 0x188, 0);
-}
-
-/**
- * gm200_secboot_setup_falcon() - set up the secure falcon for secure boot
- */
-static int
-gm200_secboot_setup_falcon(struct gm200_secboot *gsb)
-{
-	struct nvkm_device *device = gsb->base.subdev.device;
-	struct fw_bin_header *hdr = gsb->hsbl_blob;
-	struct fw_bl_desc *hsbl_desc = gsb->hsbl_blob + hdr->header_offset;
-	/* virtual start address for boot vector */
-	u32 virt_addr = hsbl_desc->start_tag << 8;
-	const u32 base = gsb->base.base;
-	const u32 reg_base = base + 0xe00;
-	u32 inst_loc;
-	int ret;
-
-	ret = nvkm_secboot_falcon_reset(&gsb->base);
-	if (ret)
-		return ret;
-
-	/* setup apertures - virtual */
-	nvkm_wr32(device, reg_base + 4 * (FALCON_DMAIDX_UCODE), 0x4);
-	nvkm_wr32(device, reg_base + 4 * (FALCON_DMAIDX_VIRT), 0x0);
-	/* setup apertures - physical */
-	nvkm_wr32(device, reg_base + 4 * (FALCON_DMAIDX_PHYS_VID), 0x4);
-	nvkm_wr32(device, reg_base + 4 * (FALCON_DMAIDX_PHYS_SYS_COH),
-		  0x4 | 0x1);
-	nvkm_wr32(device, reg_base + 4 * (FALCON_DMAIDX_PHYS_SYS_NCOH),
-		  0x4 | 0x2);
-
-	/* Set context */
-	if (nvkm_memory_target(gsb->inst->memory) == NVKM_MEM_TARGET_VRAM)
-		inst_loc = 0x0; /* FB */
-	else
-		inst_loc = 0x3; /* Non-coherent sysmem */
-
-	nvkm_mask(device, base + 0x048, 0x1, 0x1);
-	nvkm_wr32(device, base + 0x480,
-		  ((gsb->inst->addr >> 12) & 0xfffffff) |
-		  (inst_loc << 28) | (1 << 30));
-
-	/* Set boot vector to code's starting virtual address */
-	nvkm_wr32(device, base + 0x104, virt_addr);
-
-	return 0;
+	nvkm_falcon_load_imem(falcon, hsbl_code, falcon->code.limit - code_size,
+			      code_size, tag, 0, false);
 }
 
 /**
@@ -1200,16 +1130,27 @@  static int
 gm200_secboot_run_hs_blob(struct gm200_secboot *gsb, struct nvkm_gpuobj *blob,
 			  struct gm200_flcn_bl_desc *desc)
 {
-	struct nvkm_vma vma;
-	u64 vma_addr;
+	struct nvkm_subdev *subdev = &gsb->base.subdev;
+	struct fw_bin_header *hdr = gsb->hsbl_blob;
+	struct fw_bl_desc *hsbl_desc = gsb->hsbl_blob + hdr->header_offset;
+	struct nvkm_falcon *falcon = gsb->base.boot_falcon;
+	const u32 virt_addr = hsbl_desc->start_tag << 8;
 	const u32 bl_desc_size = gsb->func->bl_desc_size;
 	u8 bl_desc[bl_desc_size];
+	struct nvkm_vma vma;
+	u64 vma_addr;
 	int ret;
 
+	ret = nvkm_falcon_get(falcon, subdev);
+	if (ret)
+		return ret;
+
 	/* Map the HS firmware so the HS bootloader can see it */
 	ret = nvkm_gpuobj_map(blob, gsb->vm, NV_MEM_ACCESS_RW, &vma);
-	if (ret)
+	if (ret) {
+		nvkm_falcon_put(falcon);
 		return ret;
+	}
 
 	/* Add the mapping address to the DMA bases */
 	vma_addr = flcn64_to_u64(desc->code_dma_base) + vma.offset;
@@ -1222,19 +1163,30 @@  gm200_secboot_run_hs_blob(struct gm200_secboot *gsb, struct nvkm_gpuobj *blob,
 	/* Fixup the BL header */
 	gsb->func->fixup_bl_desc(desc, &bl_desc);
 
-	/* Reset the falcon and make it ready to run the HS bootloader */
-	ret = gm200_secboot_setup_falcon(gsb);
+	/* Reset and set the falcon up */
+	ret = nvkm_falcon_reset(falcon);
 	if (ret)
 		goto done;
+	nvkm_falcon_bind_context(falcon, gsb->inst);
 
 	/* Load the HS bootloader into the falcon's IMEM/DMEM */
-	gm200_secboot_load_hs_bl(gsb, &bl_desc, bl_desc_size);
+	gm200_secboot_load_hs_bl(gsb, falcon, &bl_desc, bl_desc_size);
 
 	/* Start the HS bootloader */
-	ret = nvkm_secboot_falcon_run(&gsb->base);
+	nvkm_falcon_set_start_addr(falcon, virt_addr);
+	nvkm_falcon_start(falcon);
+	ret = nvkm_falcon_wait_for_halt(falcon, 100);
 	if (ret)
 		goto done;
 
+	/* If mailbox register contains an error code, then ACR has failed */
+	ret = nvkm_falcon_rd32(falcon, 0x040);
+	if (ret) {
+		nvkm_error(subdev, "ACR boot failed, ret 0x%08x", ret);
+		ret = -EINVAL;
+		goto done;
+	}
+
 done:
 	/* Restore the original DMA addresses */
 	vma_addr = flcn64_to_u64(desc->code_dma_base) - vma.offset;
@@ -1246,6 +1198,7 @@  done:
 
 	/* We don't need the ACR firmware anymore */
 	nvkm_gpuobj_unmap(&vma);
+	nvkm_falcon_put(falcon);
 
 	return ret;
 }
diff --git a/drm/nouveau/nvkm/subdev/secboot/priv.h b/drm/nouveau/nvkm/subdev/secboot/priv.h
index 2ad6d622e7e5..4b090d23c289 100644
--- a/drm/nouveau/nvkm/subdev/secboot/priv.h
+++ b/drm/nouveau/nvkm/subdev/secboot/priv.h
@@ -41,8 +41,6 @@  struct nvkm_secboot_func {
 
 int nvkm_secboot_ctor(const struct nvkm_secboot_func *, struct nvkm_device *,
 		      int index, struct nvkm_secboot *);
-int nvkm_secboot_falcon_reset(struct nvkm_secboot *);
-int nvkm_secboot_falcon_run(struct nvkm_secboot *);
 
 struct flcn_u64 {
 	u32 lo;