Skip to contentSkip to conversation

nouveau: add secure boot support for dGPU and Tegra

PATCH New Alexandre Courbot 1 participant 12 messages Feb 24, 2016 1 message not in the archive Tegra architecture support

lore
Share & tools
lore
#0 lore raw

v3 cover nouveau: add secure boot support for dGPU and Tegra

New version of the secure boot code that works with the blobs just merged into linux-firmware. Since the required Mesa patches are also merged, this set is the last piece of the puzzle to get out-of-the-box accelerated Maxwell 2.

The basic code remains the same, with a few improvements with respect to how secure falcons are started. Hopefully the patchset is better split too.

I have a work-in-progress to further split the secboot subdev and handle other format differences that future chips are likely to introduce, but this current code should be good for Maxwell 2 chips.

I hope to get this merged in time for 4.6, so please let me know quickly of any required changes!

Changes since v2:
- Works with final firmware in linux-firmware
- Use func structure in secboot to abstract differences between dGPU and Tegra
- Better management of firmware loading in GR
- Abstract the way secure falcons are started
- Add MODULE_FIRMWARE statements
- ... plenty of small fixes

Alexandre Courbot (11):
core: add gpuobj memcpy helper functions gr/gk20a: move firmware bundle release to gf100 gr/gf100: load firmware in outer function gr/gk20a: simplify external bundle loading functions gr/gk20a: share external bundles loading functions gr/gm200: load external firmware and bundles
core: add support for secure boot
gr/gf100: add support for securely-managed falcons gr/gm200: do not load firmware for secure falcons secboot/gm200: add secure-boot support secboot/gm20b: add secure boot support

 drm/nouveau/include/nvkm/core/device.h    |    3 +
 drm/nouveau/include/nvkm/core/gpuobj.h    |    4 +
 drm/nouveau/include/nvkm/subdev/secboot.h |   59 ++
 drm/nouveau/nvkm/core/gpuobj.c            |   20 +
 drm/nouveau/nvkm/core/subdev.c            |    1 +
 drm/nouveau/nvkm/engine/device/base.c     |    5 +
 drm/nouveau/nvkm/engine/device/priv.h     |    1 +
 drm/nouveau/nvkm/engine/gr/gf100.c        |   65 +-
 drm/nouveau/nvkm/engine/gr/gf100.h        |   16 +-
 drm/nouveau/nvkm/engine/gr/gk20a.c        |  181 ++--
 drm/nouveau/nvkm/engine/gr/gm200.c        |   49 +-
 drm/nouveau/nvkm/engine/gr/gm206.c        |    2 +-
 drm/nouveau/nvkm/engine/gr/gm20b.c        |   12 +-
 drm/nouveau/nvkm/subdev/Kbuild            |    1 +
 drm/nouveau/nvkm/subdev/secboot/Kbuild    |    3 +
 drm/nouveau/nvkm/subdev/secboot/base.c    |  296 ++++++
 drm/nouveau/nvkm/subdev/secboot/gm200.c   | 1485 +++++++++++++++++++++++++++++
 drm/nouveau/nvkm/subdev/secboot/gm20b.c   |  233 +++++
 drm/nouveau/nvkm/subdev/secboot/priv.h    |  226 +++++
 19 files changed, 2544 insertions(+), 118 deletions(-)
 create mode 100644 drm/nouveau/include/nvkm/subdev/secboot.h
 create mode 100644 drm/nouveau/nvkm/subdev/secboot/Kbuild
 create mode 100644 drm/nouveau/nvkm/subdev/secboot/base.c
 create mode 100644 drm/nouveau/nvkm/subdev/secboot/gm200.c
 create mode 100644 drm/nouveau/nvkm/subdev/secboot/gm20b.c
 create mode 100644 drm/nouveau/nvkm/subdev/secboot/priv.h
Signature · 1 line
2.7.1

A message that is not in the archive (sent off-list or not yet received): 1456292544-32206-1-git-send-email-acourbot-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org

#2 lore raw

PATCH v3 1/11 core: add gpuobj memcpy helper functions

Add memcpy functions to copy a buffer to a gpuobj and vice-versa. This will be used by the secure boot code.

---
 drm/nouveau/include/nvkm/core/gpuobj.h |  4 ++++
 drm/nouveau/nvkm/core/gpuobj.c         | 20 ++++++++++++++++++++
 2 files changed, 24 insertions(+)
drm/nouveau/include/nvkm/core/gpuobj.h +4 -0
index d4f56eafb073..c23da4f05929 100644
@@ -37,4 +37,8 @@ int nvkm_gpuobj_wrap(struct nvkm_memory *, struct nvkm_gpuobj **);
 int nvkm_gpuobj_map(struct nvkm_gpuobj *, struct nvkm_vm *, u32 access,
 		    struct nvkm_vma *);
 void nvkm_gpuobj_unmap(struct nvkm_vma *);
+void nvkm_gpuobj_memcpy_to(struct nvkm_gpuobj *dst, u32 dstoffset, void *src,
+			   u32 length);
+void nvkm_gpuobj_memcpy_from(void *dst, struct nvkm_gpuobj *src, u32 srcoffset,
+			     u32 length);
 #endif
drm/nouveau/nvkm/core/gpuobj.c +20 -0
index c3a790eb8d6a..a7bd22706b2a 100644
@@ -253,3 +253,23 @@ nvkm_gpuobj_wrap(struct nvkm_memory *memory, struct nvkm_gpuobj **pgpuobj)
 	(*pgpuobj)->size = nvkm_memory_size(memory);
 	return 0;
 }
+
+void
+nvkm_gpuobj_memcpy_to(struct nvkm_gpuobj *dst, u32 dstoffset, void *src,
+		      u32 length)
+{
+	int i;
+
+	for (i = 0; i < length; i += 4)
+		nvkm_wo32(dst, dstoffset + i, *(u32 *)(src + i));
+}
+
+void
+nvkm_gpuobj_memcpy_from(void *dst, struct nvkm_gpuobj *src, u32 srcoffset,
+			u32 length)
+{
+	int i;
+
+	for (i = 0; i < length; i += 4)
+		((u32 *)src)[i / 4] = nvkm_ro32(src, srcoffset + i);
+}
Signature · 1 line
2.7.1
#3 lore raw

PATCH v3 2/11 gr/gk20a: move firmware bundle release to gf100

In reply to a message not in the archive

Some members of gf100_gr were freed by the gk20a driver. That's not where it should be done - free them in gf100 so other chips that use NVIDIA-provided firmware free these structures properly.

This also removes the need for a GK20A-specific destructor.

---
 drm/nouveau/nvkm/engine/gr/gf100.c | 11 +++++++++++
 drm/nouveau/nvkm/engine/gr/gf100.h |  3 +--
 drm/nouveau/nvkm/engine/gr/gk20a.c | 16 ----------------
 drm/nouveau/nvkm/engine/gr/gm20b.c |  1 -
 4 files changed, 12 insertions(+), 19 deletions(-)
drm/nouveau/nvkm/engine/gr/gf100.c +11 -0
index f2410aff07cf..7a8a0c7139e5 100644
@@ -1684,6 +1684,12 @@ gf100_gr_dtor_fw(struct gf100_gr_fuc *fuc)
 	fuc->data = NULL;
 }
 
+static void
+gf100_gr_dtor_init(struct gf100_gr_pack *pack)
+{
+	vfree(pack);
+}
+
 void *
 gf100_gr_dtor(struct nvkm_gr *base)
 {
@@ -1698,6 +1704,11 @@ gf100_gr_dtor(struct nvkm_gr *base)
 	gf100_gr_dtor_fw(&gr->fuc41ac);
 	gf100_gr_dtor_fw(&gr->fuc41ad);
 
+	gf100_gr_dtor_init(gr->fuc_bundle);
+	gf100_gr_dtor_init(gr->fuc_method);
+	gf100_gr_dtor_init(gr->fuc_sw_ctx);
+	gf100_gr_dtor_init(gr->fuc_sw_nonctx);
+
 	nvkm_memory_del(&gr->unk4188b8);
 	nvkm_memory_del(&gr->unk4188b4);
 	return gr;
drm/nouveau/nvkm/engine/gr/gf100.h +1 -2
index 8dca40dde06b..cff4b40d887e 100644
@@ -82,7 +82,7 @@ struct gf100_gr {
 
 	/*
 	 * Used if the register packs are loaded from NVIDIA fw instead of
-	 * using hardcoded arrays.
+	 * using hardcoded arrays. To be allocated with vzalloc().
 	 */
 	struct gf100_gr_pack *fuc_sw_nonctx;
 	struct gf100_gr_pack *fuc_sw_ctx;
@@ -140,7 +140,6 @@ int gk104_gr_init(struct gf100_gr *);
 
 int gk20a_gr_new_(const struct gf100_gr_func *, struct nvkm_device *,
 		  int, struct nvkm_gr **);
-void gk20a_gr_dtor(struct gf100_gr *);
 int gk20a_gr_init(struct gf100_gr *);
 
 int gm200_gr_init(struct gf100_gr *);
drm/nouveau/nvkm/engine/gr/gk20a.c +0 -16
index b8758d3b8b51..a321dd019932 100644
@@ -26,12 +26,6 @@
 
 #include <nvif/class.h>
 
-static void
-gk20a_gr_init_dtor(struct gf100_gr_pack *pack)
-{
-	vfree(pack);
-}
-
 struct gk20a_fw_av
 {
 	u32 addr;
@@ -273,15 +267,6 @@ gk20a_gr_init(struct gf100_gr *gr)
 	return gf100_gr_init_ctxctl(gr);
 }
 
-void
-gk20a_gr_dtor(struct gf100_gr *gr)
-{
-	gk20a_gr_init_dtor(gr->fuc_method);
-	gk20a_gr_init_dtor(gr->fuc_bundle);
-	gk20a_gr_init_dtor(gr->fuc_sw_ctx);
-	gk20a_gr_init_dtor(gr->fuc_sw_nonctx);
-}
-
 int
 gk20a_gr_new_(const struct gf100_gr_func *func, struct nvkm_device *device,
 	      int index, struct nvkm_gr **pgr)
@@ -335,7 +320,6 @@ gk20a_gr_new_(const struct gf100_gr_func *func, struct nvkm_device *device,
 
 static const struct gf100_gr_func
 gk20a_gr = {
-	.dtor = gk20a_gr_dtor,
 	.init = gk20a_gr_init,
 	.set_hww_esr_report_mask = gk20a_gr_set_hww_esr_report_mask,
 	.ppc_nr = 1,
drm/nouveau/nvkm/engine/gr/gm20b.c +0 -1
index 65b6e3d1e90d..443922e46ff9 100644
@@ -61,7 +61,6 @@ gm20b_gr_set_hww_esr_report_mask(struct gf100_gr *gr)
 
 static const struct gf100_gr_func
 gm20b_gr = {
-	.dtor = gk20a_gr_dtor,
 	.init = gk20a_gr_init,
 	.init_gpc_mmu = gm20b_gr_init_gpc_mmu,
 	.set_hww_esr_report_mask = gm20b_gr_set_hww_esr_report_mask,
Signature · 1 line
2.7.1
#4 lore raw

PATCH v3 3/11 gr/gf100: load firmware in outer function

In reply to a message not in the archive

The firmwares required by GR may vary from chip to chip, especially with the introduction of secure boot and NVIDIA-provided firmwares. Move the firmware loading outside of gf100_gr_ctor so other chips may still call it while managing their firmwares themselves.

---
 drm/nouveau/nvkm/engine/gr/gf100.c | 26 ++++++++++++++++----------
 drm/nouveau/nvkm/engine/gr/gk20a.c |  6 ++++++
 2 files changed, 22 insertions(+), 10 deletions(-)
drm/nouveau/nvkm/engine/gr/gf100.c +16 -10
index 7a8a0c7139e5..3fc5f7d962be 100644
@@ -1762,15 +1762,6 @@ gf100_gr_ctor(const struct gf100_gr_func *func, struct nvkm_device *device,
 	if (ret)
 		return ret;
 
-	if (gr->firmware) {
-		nvkm_info(&gr->base.engine.subdev, "using external firmware\n");
-		if (gf100_gr_ctor_fw(gr, "fecs_inst", &gr->fuc409c) ||
-		    gf100_gr_ctor_fw(gr, "fecs_data", &gr->fuc409d) ||
-		    gf100_gr_ctor_fw(gr, "gpccs_inst", &gr->fuc41ac) ||
-		    gf100_gr_ctor_fw(gr, "gpccs_data", &gr->fuc41ad))
-			return -ENODEV;
-	}
-
 	return 0;
 }
 
@@ -1779,10 +1770,25 @@ gf100_gr_new_(const struct gf100_gr_func *func, struct nvkm_device *device,
 	      int index, struct nvkm_gr **pgr)
 {
 	struct gf100_gr *gr;
+	int ret;
+
 	if (!(gr = kzalloc(sizeof(*gr), GFP_KERNEL)))
 		return -ENOMEM;
 	*pgr = &gr->base;
-	return gf100_gr_ctor(func, device, index, gr);
+
+	ret = gf100_gr_ctor(func, device, index, gr);
+	if (ret)
+		return ret;
+
+	if (gr->firmware) {
+		if (gf100_gr_ctor_fw(gr, "fecs_inst", &gr->fuc409c) ||
+		    gf100_gr_ctor_fw(gr, "fecs_data", &gr->fuc409d) ||
+		    gf100_gr_ctor_fw(gr, "gpccs_inst", &gr->fuc41ac) ||
+		    gf100_gr_ctor_fw(gr, "gpccs_data", &gr->fuc41ad))
+			return -ENODEV;
+	}
+
+	return 0;
 }
 
 int
drm/nouveau/nvkm/engine/gr/gk20a.c +6 -0
index a321dd019932..a55331d68ff6 100644
@@ -283,6 +283,12 @@ gk20a_gr_new_(const struct gf100_gr_func *func, struct nvkm_device *device,
 	if (ret)
 		return ret;
 
+	if (gf100_gr_ctor_fw(gr, "fecs_inst", &gr->fuc409c) ||
+	    gf100_gr_ctor_fw(gr, "fecs_data", &gr->fuc409d) ||
+	    gf100_gr_ctor_fw(gr, "gpccs_inst", &gr->fuc41ac) ||
+	    gf100_gr_ctor_fw(gr, "gpccs_data", &gr->fuc41ad))
+		return -ENODEV;
+
 	ret = gf100_gr_ctor_fw(gr, "sw_nonctx", &fuc);
 	if (ret)
 		return ret;
Signature · 1 line
2.7.1
#5 lore raw

PATCH v3 4/11 gr/gk20a: simplify external bundle loading functions

In reply to a message not in the archive

Make these functions easier to use by handling memory management from within.

---
 drm/nouveau/nvkm/engine/gr/gk20a.c | 120 ++++++++++++++++++++++---------------
 1 file changed, 73 insertions(+), 47 deletions(-)
drm/nouveau/nvkm/engine/gr/gk20a.c +73 -47
index a55331d68ff6..66720aba213b 100644
@@ -32,25 +32,34 @@ struct gk20a_fw_av
 	u32 data;
 };
 
-static struct gf100_gr_pack *
-gk20a_gr_av_to_init(struct gf100_gr_fuc *fuc)
+static int
+gk20a_gr_av_to_init(struct gf100_gr *gr, const char *fw_name,
+		    struct gf100_gr_pack **ppack)
 {
+	struct gf100_gr_fuc fuc;
 	struct gf100_gr_init *init;
 	struct gf100_gr_pack *pack;
-	const int nent = (fuc->size / sizeof(struct gk20a_fw_av));
+	int nent;
+	int ret;
 	int i;
 
+	ret = gf100_gr_ctor_fw(gr, fw_name, &fuc);
+	if (ret)
+		return ret;
+
+	nent = (fuc.size / sizeof(struct gk20a_fw_av));
 	pack = vzalloc((sizeof(*pack) * 2) + (sizeof(*init) * (nent + 1)));
-	if (!pack)
-		return ERR_PTR(-ENOMEM);
+	if (!pack) {
+		ret = -ENOMEM;
+		goto end;
+	}
 
 	init = (void *)(pack + 2);
-
 	pack[0].init = init;
 
 	for (i = 0; i < nent; i++) {
 		struct gf100_gr_init *ent = &init[i];
-		struct gk20a_fw_av *av = &((struct gk20a_fw_av *)fuc->data)[i];
+		struct gk20a_fw_av *av = &((struct gk20a_fw_av *)fuc.data)[i];
 
 		ent->addr = av->addr;
 		ent->data = av->data;
@@ -58,7 +67,11 @@ gk20a_gr_av_to_init(struct gf100_gr_fuc *fuc)
 		ent->pitch = 1;
 	}
 
-	return pack;
+	*ppack = pack;
+
+end:
+	gf100_gr_dtor_fw(&fuc);
+	return ret;
 }
 
 struct gk20a_fw_aiv
@@ -68,25 +81,34 @@ struct gk20a_fw_aiv
 	u32 data;
 };
 
-static struct gf100_gr_pack *
-gk20a_gr_aiv_to_init(struct gf100_gr_fuc *fuc)
+static int
+gk20a_gr_aiv_to_init(struct gf100_gr *gr, const char *fw_name,
+		     struct gf100_gr_pack **ppack)
 {
+	struct gf100_gr_fuc fuc;
 	struct gf100_gr_init *init;
 	struct gf100_gr_pack *pack;
-	const int nent = (fuc->size / sizeof(struct gk20a_fw_aiv));
+	int nent;
+	int ret;
 	int i;
 
+	ret = gf100_gr_ctor_fw(gr, fw_name, &fuc);
+	if (ret)
+		return ret;
+
+	nent = (fuc.size / sizeof(struct gk20a_fw_aiv));
 	pack = vzalloc((sizeof(*pack) * 2) + (sizeof(*init) * (nent + 1)));
-	if (!pack)
-		return ERR_PTR(-ENOMEM);
+	if (!pack) {
+		ret = -ENOMEM;
+		goto end;
+	}
 
 	init = (void *)(pack + 2);
-
 	pack[0].init = init;
 
 	for (i = 0; i < nent; i++) {
 		struct gf100_gr_init *ent = &init[i];
-		struct gk20a_fw_aiv *av = &((struct gk20a_fw_aiv *)fuc->data)[i];
+		struct gk20a_fw_aiv *av = &((struct gk20a_fw_aiv *)fuc.data)[i];
 
 		ent->addr = av->addr;
 		ent->data = av->data;
@@ -94,30 +116,45 @@ gk20a_gr_aiv_to_init(struct gf100_gr_fuc *fuc)
 		ent->pitch = 1;
 	}
 
-	return pack;
+	*ppack = pack;
+
+end:
+	gf100_gr_dtor_fw(&fuc);
+	return ret;
 }
 
-static struct gf100_gr_pack *
-gk20a_gr_av_to_method(struct gf100_gr_fuc *fuc)
+static int
+gk20a_gr_av_to_method(struct gf100_gr *gr, const char *fw_name,
+		      struct gf100_gr_pack **ppack)
 {
+	struct gf100_gr_fuc fuc;
 	struct gf100_gr_init *init;
 	struct gf100_gr_pack *pack;
 	/* We don't suppose we will initialize more than 16 classes here... */
 	static const unsigned int max_classes = 16;
-	const int nent = (fuc->size / sizeof(struct gk20a_fw_av));
-	int i, classidx = 0;
-	u32 prevclass = 0;
+	u32 classidx = 0, prevclass = 0;
+	int nent;
+	int ret;
+	int i;
+
+	ret = gf100_gr_ctor_fw(gr, fw_name, &fuc);
+	if (ret)
+		return ret;
+
+	nent = (fuc.size / sizeof(struct gk20a_fw_av));
 
 	pack = vzalloc((sizeof(*pack) * max_classes) +
 		       (sizeof(*init) * (nent + 1)));
-	if (!pack)
-		return ERR_PTR(-ENOMEM);
+	if (!pack) {
+		ret = -ENOMEM;
+		goto end;
+	}
 
 	init = (void *)(pack + max_classes);
 
 	for (i = 0; i < nent; i++) {
 		struct gf100_gr_init *ent = &init[i];
-		struct gk20a_fw_av *av = &((struct gk20a_fw_av *)fuc->data)[i];
+		struct gk20a_fw_av *av = &((struct gk20a_fw_av *)fuc.data)[i];
 		u32 class = av->addr & 0xffff;
 		u32 addr = (av->addr & 0xffff0000) >> 14;
 
@@ -127,7 +164,8 @@ gk20a_gr_av_to_method(struct gf100_gr_fuc *fuc)
 			prevclass = class;
 			if (++classidx >= max_classes) {
 				vfree(pack);
-				return ERR_PTR(-ENOSPC);
+				ret = -ENOSPC;
+				goto end;
 			}
 		}
 
@@ -137,7 +175,11 @@ gk20a_gr_av_to_method(struct gf100_gr_fuc *fuc)
 		ent->pitch = 1;
 	}
 
-	return pack;
+	*ppack = pack;
+
+end:
+	gf100_gr_dtor_fw(&fuc);
+	return ret;
 }
 
 static int
@@ -271,7 +313,6 @@ int
 gk20a_gr_new_(const struct gf100_gr_func *func, struct nvkm_device *device,
 	      int index, struct nvkm_gr **pgr)
 {
-	struct gf100_gr_fuc fuc;
 	struct gf100_gr *gr;
 	int ret;
 
@@ -289,37 +330,22 @@ gk20a_gr_new_(const struct gf100_gr_func *func, struct nvkm_device *device,
 	    gf100_gr_ctor_fw(gr, "gpccs_data", &gr->fuc41ad))
 		return -ENODEV;
 
-	ret = gf100_gr_ctor_fw(gr, "sw_nonctx", &fuc);
+	ret = gk20a_gr_av_to_init(gr, "sw_nonctx", &gr->fuc_sw_nonctx);
 	if (ret)
 		return ret;
-	gr->fuc_sw_nonctx = gk20a_gr_av_to_init(&fuc);
-	gf100_gr_dtor_fw(&fuc);
-	if (IS_ERR(gr->fuc_sw_nonctx))
-		return PTR_ERR(gr->fuc_sw_nonctx);
 
-	ret = gf100_gr_ctor_fw(gr, "sw_ctx", &fuc);
+	ret = gk20a_gr_aiv_to_init(gr, "sw_ctx", &gr->fuc_sw_ctx);
 	if (ret)
 		return ret;
-	gr->fuc_sw_ctx = gk20a_gr_aiv_to_init(&fuc);
-	gf100_gr_dtor_fw(&fuc);
-	if (IS_ERR(gr->fuc_sw_ctx))
-		return PTR_ERR(gr->fuc_sw_ctx);
 
-	ret = gf100_gr_ctor_fw(gr, "sw_bundle_init", &fuc);
+	ret = gk20a_gr_av_to_init(gr, "sw_bundle_init", &gr->fuc_bundle);
 	if (ret)
 		return ret;
-	gr->fuc_bundle = gk20a_gr_av_to_init(&fuc);
-	gf100_gr_dtor_fw(&fuc);
-	if (IS_ERR(gr->fuc_bundle))
-		return PTR_ERR(gr->fuc_bundle);
 
-	ret = gf100_gr_ctor_fw(gr, "sw_method_init", &fuc);
+	ret = gk20a_gr_av_to_method(gr, "sw_method_init", &gr->fuc_method);
 	if (ret)
 		return ret;
-	gr->fuc_method = gk20a_gr_av_to_method(&fuc);
-	gf100_gr_dtor_fw(&fuc);
-	if (IS_ERR(gr->fuc_method))
-		return PTR_ERR(gr->fuc_method);
+
 
 	return 0;
 }
Signature · 1 line
2.7.1
#6 lore raw

PATCH v3 5/11 gr/gk20a: share external bundles loading functions

In reply to a message not in the archive

There functions are going to be used by other chips that rely on NVIDIA-provided firmware. Export them.

---
 drm/nouveau/nvkm/engine/gr/gf100.h | 8 ++++++++
 drm/nouveau/nvkm/engine/gr/gk20a.c | 6 +++---
 2 files changed, 11 insertions(+), 3 deletions(-)
drm/nouveau/nvkm/engine/gr/gf100.h +8 -0
index cff4b40d887e..ea8d2831ff31 100644
@@ -203,6 +203,14 @@ void gf100_gr_icmd(struct gf100_gr *, const struct gf100_gr_pack *);
 void gf100_gr_mthd(struct gf100_gr *, const struct gf100_gr_pack *);
 int  gf100_gr_init_ctxctl(struct gf100_gr *);
 
+/* external bundles loading functions */
+int gk20a_gr_av_to_init(struct gf100_gr *, const char *,
+			struct gf100_gr_pack **);
+int gk20a_gr_aiv_to_init(struct gf100_gr *, const char *,
+			 struct gf100_gr_pack **);
+int gk20a_gr_av_to_method(struct gf100_gr *, const char *,
+			  struct gf100_gr_pack **);
+
 /* register init value lists */
 
 extern const struct gf100_gr_init gf100_gr_init_main_0[];
drm/nouveau/nvkm/engine/gr/gk20a.c +3 -3
index 66720aba213b..297a4d2ed814 100644
@@ -32,7 +32,7 @@ struct gk20a_fw_av
 	u32 data;
 };
 
-static int
+int
 gk20a_gr_av_to_init(struct gf100_gr *gr, const char *fw_name,
 		    struct gf100_gr_pack **ppack)
 {
@@ -81,7 +81,7 @@ struct gk20a_fw_aiv
 	u32 data;
 };
 
-static int
+int
 gk20a_gr_aiv_to_init(struct gf100_gr *gr, const char *fw_name,
 		     struct gf100_gr_pack **ppack)
 {
@@ -123,7 +123,7 @@ end:
 	return ret;
 }
 
-static int
+int
 gk20a_gr_av_to_method(struct gf100_gr *gr, const char *fw_name,
 		      struct gf100_gr_pack **ppack)
 {
Signature · 1 line
2.7.1
#7 lore raw

PATCH v3 6/11 gr/gm200: load external firmware and bundles

In reply to a message not in the archive

Load firmware and bundles in GM200's constructor. The previously called GF100 function did not care about the bundles.

---
 drm/nouveau/nvkm/engine/gr/gf100.h |  5 +++--
 drm/nouveau/nvkm/engine/gr/gk20a.c | 41 ++++++++++++++++----------------------
 drm/nouveau/nvkm/engine/gr/gm200.c | 32 ++++++++++++++++++++++++++++-
 drm/nouveau/nvkm/engine/gr/gm206.c |  2 +-
 drm/nouveau/nvkm/engine/gr/gm20b.c |  2 +-
 5 files changed, 53 insertions(+), 29 deletions(-)
drm/nouveau/nvkm/engine/gr/gf100.h +3 -2
index ea8d2831ff31..5626cae67291 100644
@@ -138,8 +138,6 @@ int gf100_gr_init(struct gf100_gr *);
 
 int gk104_gr_init(struct gf100_gr *);
 
-int gk20a_gr_new_(const struct gf100_gr_func *, struct nvkm_device *,
-		  int, struct nvkm_gr **);
 int gk20a_gr_init(struct gf100_gr *);
 
 int gm200_gr_init(struct gf100_gr *);
@@ -211,6 +209,9 @@ int gk20a_gr_aiv_to_init(struct gf100_gr *, const char *,
 int gk20a_gr_av_to_method(struct gf100_gr *, const char *,
 			  struct gf100_gr_pack **);
 
+int gm200_gr_new_(const struct gf100_gr_func *, struct nvkm_device *, int,
+		  struct nvkm_gr **);
+
 /* register init value lists */
 
 extern const struct gf100_gr_init gf100_gr_init_main_0[];
drm/nouveau/nvkm/engine/gr/gk20a.c +17 -24

57 lines not on this page · raw message

drm/nouveau/nvkm/engine/gr/gm200.c +31 -1
index c76dc67e9406..f0e087a15cd2 100644
@@ -351,6 +351,36 @@ gm200_gr_init(struct gf100_gr *gr)
 	return gm200_gr_init_ctxctl(gr);
 }
 
+int gm200_gr_new_(const struct gf100_gr_func *func, struct nvkm_device *device,
+		  int index, struct nvkm_gr **pgr)
+{
+	struct gf100_gr *gr;
+	int ret;
+
+	if (!(gr = kzalloc(sizeof(*gr), GFP_KERNEL)))
+		return -ENOMEM;
+	*pgr = &gr->base;
+
+	ret = gf100_gr_ctor(func, device, index, gr);
+	if (ret)
+		return ret;
+
+	if ((ret = gf100_gr_ctor_fw(gr, "gr/fecs_inst", &gr->fuc409c)) ||
+	    (ret = gf100_gr_ctor_fw(gr, "gr/fecs_data", &gr->fuc409d)))
+		return ret;
+	if ((ret = gf100_gr_ctor_fw(gr, "gr/gpccs_inst", &gr->fuc41ac)) ||
+	    (ret = gf100_gr_ctor_fw(gr, "gr/gpccs_data", &gr->fuc41ad)))
+		return ret;
+
+	if ((ret = gk20a_gr_av_to_init(gr, "gr/sw_nonctx", &gr->fuc_sw_nonctx)) ||
+	    (ret = gk20a_gr_aiv_to_init(gr, "gr/sw_ctx", &gr->fuc_sw_ctx)) ||
+	    (ret = gk20a_gr_av_to_init(gr, "gr/sw_bundle_init", &gr->fuc_bundle)) ||
+	    (ret = gk20a_gr_av_to_method(gr, "gr/sw_method_init", &gr->fuc_method)))
+		return ret;
+
+	return 0;
+}
+
 static const struct gf100_gr_func
 gm200_gr = {
 	.init = gm200_gr_init,
@@ -369,5 +399,5 @@ gm200_gr = {
 int
 gm200_gr_new(struct nvkm_device *device, int index, struct nvkm_gr **pgr)
 {
-	return gf100_gr_new_(&gm200_gr, device, index, pgr);
+	return gm200_gr_new_(&gm200_gr, device, index, pgr);
 }
drm/nouveau/nvkm/engine/gr/gm206.c +1 -1
index 398e3f52f489..74c4f7384ff6 100644
@@ -44,5 +44,5 @@ gm206_gr = {
 int
 gm206_gr_new(struct nvkm_device *device, int index, struct nvkm_gr **pgr)
 {
-	return gf100_gr_new_(&gm206_gr, device, index, pgr);
+	return gm200_gr_new_(&gm206_gr, device, index, pgr);
 }
drm/nouveau/nvkm/engine/gr/gm20b.c +1 -1
index 443922e46ff9..a440772f8de4 100644
@@ -78,5 +78,5 @@ gm20b_gr = {
 int
 gm20b_gr_new(struct nvkm_device *device, int index, struct nvkm_gr **pgr)
 {
-	return gk20a_gr_new_(&gm20b_gr, device, index, pgr);
+	return gm200_gr_new_(&gm20b_gr, device, index, pgr);
 }
Signature · 1 line
2.7.1
#8 lore raw

PATCH v3 7/11 core: add support for secure boot

In reply to a message not in the archive

On GM200 and later GPUs, firmware for some essential falcons (notably GR ones) must be authenticated by a NVIDIA-produced signature and loaded by a high-secure falcon in order to be able to access privileged registers, in a process known as Secure Boot.

Secure Boot requires building a binary blob containing the firmwares and signatures of the falcons to be loaded. This blob is then given to a high-secure falcon running a signed loader firmware that copies the blob into a write-protected region, checks that the signatures are valid, and finally loads the verified firmware into the managed falcons and switches them to privileged mode.

This patch adds infrastructure code to support this process on chips that require it.

---
 drm/nouveau/include/nvkm/core/device.h    |   3 +
 drm/nouveau/include/nvkm/subdev/secboot.h |  56 ++++++
 drm/nouveau/nvkm/core/subdev.c            |   1 +
 drm/nouveau/nvkm/engine/device/base.c     |   2 +
 drm/nouveau/nvkm/engine/device/priv.h     |   1 +
 drm/nouveau/nvkm/subdev/Kbuild            |   1 +
 drm/nouveau/nvkm/subdev/secboot/Kbuild    |   1 +
 drm/nouveau/nvkm/subdev/secboot/base.c    | 296 ++++++++++++++++++++++++++++++
 drm/nouveau/nvkm/subdev/secboot/priv.h    |  48 +++++
 9 files changed, 409 insertions(+)
 create mode 100644 drm/nouveau/include/nvkm/subdev/secboot.h
 create mode 100644 drm/nouveau/nvkm/subdev/secboot/Kbuild
 create mode 100644 drm/nouveau/nvkm/subdev/secboot/base.c
 create mode 100644 drm/nouveau/nvkm/subdev/secboot/priv.h
drm/nouveau/include/nvkm/core/device.h +3 -0
index 913192c94876..d154a75e93a9 100644
@@ -24,6 +24,7 @@ enum nvkm_devidx {
 	NVKM_SUBDEV_VOLT,
 	NVKM_SUBDEV_THERM,
 	NVKM_SUBDEV_CLK,
+	NVKM_SUBDEV_SECBOOT,
 
 	NVKM_ENGINE_DMAOBJ,
 	NVKM_ENGINE_IFB,
@@ -119,6 +120,7 @@ struct nvkm_device {
 	struct nvkm_therm *therm;
 	struct nvkm_timer *timer;
 	struct nvkm_volt *volt;
+	struct nvkm_secboot *secboot;
 
 	struct nvkm_engine *bsp;
 	struct nvkm_engine *ce[3];
@@ -184,6 +186,7 @@ struct nvkm_device_chip {
 	int (*therm  )(struct nvkm_device *, int idx, struct nvkm_therm **);
 	int (*timer  )(struct nvkm_device *, int idx, struct nvkm_timer **);
 	int (*volt   )(struct nvkm_device *, int idx, struct nvkm_volt **);
+	int (*secboot)(struct nvkm_device *, int idx, struct nvkm_secboot **);
 
 	int (*bsp    )(struct nvkm_device *, int idx, struct nvkm_engine **);
 	int (*ce[3]  )(struct nvkm_device *, int idx, struct nvkm_engine **);
drm/nouveau/include/nvkm/subdev/secboot.h new file +56 -0

56 lines not on this page · raw message

drm/nouveau/nvkm/core/subdev.c +1 -0
index 7de98470a2a0..d8b3d2a362ad 100644
@@ -49,6 +49,7 @@ nvkm_subdev_name[NVKM_SUBDEV_NR] = {
 	[NVKM_SUBDEV_THERM  ] = "therm",
 	[NVKM_SUBDEV_TIMER  ] = "tmr",
 	[NVKM_SUBDEV_VOLT   ] = "volt",
+	[NVKM_SUBDEV_SECBOOT] = "secboot",
 	[NVKM_ENGINE_BSP    ] = "bsp",
 	[NVKM_ENGINE_CE0    ] = "ce0",
 	[NVKM_ENGINE_CE1    ] = "ce1",
drm/nouveau/nvkm/engine/device/base.c +2 -0
index da371b805562..ba44ba925f4b 100644
@@ -2123,6 +2123,7 @@ nvkm_device_subdev(struct nvkm_device *device, int index)
 	_(THERM  , device->therm  , &device->therm->subdev);
 	_(TIMER  , device->timer  , &device->timer->subdev);
 	_(VOLT   , device->volt   , &device->volt->subdev);
+	_(SECBOOT, device->secboot, &device->secboot->subdev);
 #undef _
 	default:
 		engine = nvkm_device_engine(device, index);
@@ -2572,6 +2573,7 @@ nvkm_device_ctor(const struct nvkm_device_func *func,
 		_(NVKM_SUBDEV_THERM  ,   therm);
 		_(NVKM_SUBDEV_TIMER  ,   timer);
 		_(NVKM_SUBDEV_VOLT   ,    volt);
+		_(NVKM_SUBDEV_SECBOOT, secboot);
 		_(NVKM_ENGINE_BSP    ,     bsp);
 		_(NVKM_ENGINE_CE0    ,   ce[0]);
 		_(NVKM_ENGINE_CE1    ,   ce[1]);
drm/nouveau/nvkm/engine/device/priv.h +1 -0
index ed3ad2c30e17..03fe0afbf6bf 100644
@@ -22,6 +22,7 @@
 #include <subdev/therm.h>
 #include <subdev/timer.h>
 #include <subdev/volt.h>
+#include <subdev/secboot.h>
 
 #include <engine/bsp.h>
 #include <engine/ce.h>
drm/nouveau/nvkm/subdev/Kbuild +1 -0
index ee2c38f50ef5..ec8c5eb30653 100644
@@ -15,6 +15,7 @@ include $(src)/nvkm/subdev/mmu/Kbuild
 include $(src)/nvkm/subdev/mxm/Kbuild
 include $(src)/nvkm/subdev/pci/Kbuild
 include $(src)/nvkm/subdev/pmu/Kbuild
+include $(src)/nvkm/subdev/secboot/Kbuild
 include $(src)/nvkm/subdev/therm/Kbuild
 include $(src)/nvkm/subdev/timer/Kbuild
 include $(src)/nvkm/subdev/volt/Kbuild
drm/nouveau/nvkm/subdev/secboot/Kbuild new file +1 -0
new file mode 100644
index 000000000000..e757096b2ff0
@@ -0,0 +1 @@
+nvkm-y += nvkm/subdev/secboot/base.o
drm/nouveau/nvkm/subdev/secboot/base.c new file +296 -0

296 lines not on this page · raw message

drm/nouveau/nvkm/subdev/secboot/priv.h new file +48 -0

48 lines not on this page · raw message

Signature · 1 line
2.7.1
#9 lore raw

PATCH v3 8/11 gr/gf100: add support for securely-managed falcons

In reply to a message not in the archive

Start securely-managed falcons using secboot functions since the process for them is different from just writing CPUCTL.

---
 drm/nouveau/nvkm/engine/gr/gf100.c | 28 ++++++++++++++++++++++++----
 1 file changed, 24 insertions(+), 4 deletions(-)
drm/nouveau/nvkm/engine/gr/gf100.c +24 -4
index 3fc5f7d962be..c56a886229f1 100644
@@ -28,6 +28,7 @@
 #include <core/client.h>
 #include <core/option.h>
 #include <core/firmware.h>
+#include <subdev/secboot.h>
 #include <subdev/fb.h>
 #include <subdev/mc.h>
 #include <subdev/pmu.h>
@@ -1428,21 +1429,40 @@ gf100_gr_init_ctxctl(struct gf100_gr *gr)
 	const struct gf100_grctx_func *grctx = gr->func->grctx;
 	struct nvkm_subdev *subdev = &gr->base.engine.subdev;
 	struct nvkm_device *device = subdev->device;
+	struct nvkm_secboot *sb = device->secboot;
 	int i;
 
 	if (gr->firmware) {
 		/* load fuc microcode */
 		nvkm_mc_unk260(device->mc, 0);
-		gf100_gr_init_fw(gr, 0x409000, &gr->fuc409c, &gr->fuc409d);
-		gf100_gr_init_fw(gr, 0x41a000, &gr->fuc41ac, &gr->fuc41ad);
+
+		/* securely-managed falcons must be reset using secure boot */
+		if (nvkm_secboot_is_managed(sb, NVKM_SECBOOT_FALCON_FECS))
+			nvkm_secboot_reset(sb, NVKM_SECBOOT_FALCON_FECS);
+		else
+			gf100_gr_init_fw(gr, 0x409000, &gr->fuc409c,
+					 &gr->fuc409d);
+		if (nvkm_secboot_is_managed(sb, NVKM_SECBOOT_FALCON_GPCCS))
+			nvkm_secboot_reset(sb, NVKM_SECBOOT_FALCON_GPCCS);
+		else
+			gf100_gr_init_fw(gr, 0x41a000, &gr->fuc41ac,
+					 &gr->fuc41ad);
+
 		nvkm_mc_unk260(device->mc, 1);
 
 		/* start both of them running */
 		nvkm_wr32(device, 0x409840, 0xffffffff);
 		nvkm_wr32(device, 0x41a10c, 0x00000000);
 		nvkm_wr32(device, 0x40910c, 0x00000000);
-		nvkm_wr32(device, 0x41a100, 0x00000002);
-		nvkm_wr32(device, 0x409100, 0x00000002);
+
+		if (nvkm_secboot_is_managed(sb, NVKM_SECBOOT_FALCON_GPCCS))
+			nvkm_secboot_start(sb, NVKM_SECBOOT_FALCON_GPCCS);
+		else
+			nvkm_wr32(device, 0x41a100, 0x00000002);
+		if (nvkm_secboot_is_managed(sb, NVKM_SECBOOT_FALCON_FECS))
+			nvkm_secboot_start(sb, NVKM_SECBOOT_FALCON_FECS);
+		else
+			nvkm_wr32(device, 0x409100, 0x00000002);
 		if (nvkm_msec(device, 2000,
 			if (nvkm_rd32(device, 0x409800) & 0x00000001)
 				break;
Signature · 1 line
2.7.1
#10 lore raw

PATCH v3 9/11 gr/gm200: do not load firmware for secure falcons

In reply to a message not in the archive

Secure falcons' firmware is managed by secboot. Do not load it in GR for them.

---
 drm/nouveau/nvkm/engine/gr/gm200.c | 21 +++++++++++++++------
 1 file changed, 15 insertions(+), 6 deletions(-)
drm/nouveau/nvkm/engine/gr/gm200.c +15 -6
index f0e087a15cd2..038f9b338a85 100644
@@ -24,6 +24,8 @@
 #include "gf100.h"
 #include "ctxgf100.h"
 
+#include <subdev/secboot.h>
+
 #include <nvif/class.h>
 
 /*******************************************************************************
@@ -365,12 +367,19 @@ int gm200_gr_new_(const struct gf100_gr_func *func, struct nvkm_device *device,
 	if (ret)
 		return ret;
 
-	if ((ret = gf100_gr_ctor_fw(gr, "gr/fecs_inst", &gr->fuc409c)) ||
-	    (ret = gf100_gr_ctor_fw(gr, "gr/fecs_data", &gr->fuc409d)))
-		return ret;
-	if ((ret = gf100_gr_ctor_fw(gr, "gr/gpccs_inst", &gr->fuc41ac)) ||
-	    (ret = gf100_gr_ctor_fw(gr, "gr/gpccs_data", &gr->fuc41ad)))
-		return ret;
+	/* Load firmwares for non-secure falcons */
+	if (!nvkm_secboot_is_managed(device->secboot,
+				     NVKM_SECBOOT_FALCON_FECS)) {
+		if ((ret = gf100_gr_ctor_fw(gr, "gr/fecs_inst", &gr->fuc409c)) ||
+		    (ret = gf100_gr_ctor_fw(gr, "gr/fecs_data", &gr->fuc409d)))
+			return ret;
+	}
+	if (!nvkm_secboot_is_managed(device->secboot,
+				     NVKM_SECBOOT_FALCON_GPCCS)) {
+		if ((ret = gf100_gr_ctor_fw(gr, "gr/gpccs_inst", &gr->fuc41ac)) ||
+		    (ret = gf100_gr_ctor_fw(gr, "gr/gpccs_data", &gr->fuc41ad)))
+			return ret;
+	}
 
 	if ((ret = gk20a_gr_av_to_init(gr, "gr/sw_nonctx", &gr->fuc_sw_nonctx)) ||
 	    (ret = gk20a_gr_aiv_to_init(gr, "gr/sw_ctx", &gr->fuc_sw_ctx)) ||
Signature · 1 line
2.7.1
#11 lore raw

PATCH v3 10/11 secboot/gm200: add secure-boot support

In reply to a message not in the archive

Add secure-boot for the dGPU set of GM20X chips, using the PMU as the high-secure falcon.

This work is based on Deepak Goyal's initial port of Secure Boot to Nouveau.

---
 drm/nouveau/include/nvkm/subdev/secboot.h |    2 +
 drm/nouveau/nvkm/engine/device/base.c     |    2 +
 drm/nouveau/nvkm/engine/gr/gm200.c        |    8 +-
 drm/nouveau/nvkm/subdev/secboot/Kbuild    |    1 +
 drm/nouveau/nvkm/subdev/secboot/gm200.c   | 1485 +++++++++++++++++++++++++++++
 drm/nouveau/nvkm/subdev/secboot/priv.h    |  178 ++++
 6 files changed, 1669 insertions(+), 7 deletions(-)
 create mode 100644 drm/nouveau/nvkm/subdev/secboot/gm200.c
drm/nouveau/include/nvkm/subdev/secboot.h +2 -0
index f40b57567676..a509f2b4aa5f 100644
@@ -53,4 +53,6 @@ bool nvkm_secboot_is_managed(struct nvkm_secboot *, enum nvkm_secboot_falcon);
 int nvkm_secboot_reset(struct nvkm_secboot *, u32 falcon);
 int nvkm_secboot_start(struct nvkm_secboot *, u32 falcon);
 
+int gm200_secboot_new(struct nvkm_device *, int, struct nvkm_secboot **);
+
 #endif
drm/nouveau/nvkm/engine/device/base.c +2 -0
index ba44ba925f4b..ab56abac0bc5 100644
@@ -2022,6 +2022,7 @@ nv124_chipset = {
 	.fifo = gm200_fifo_new,
 	.gr = gm200_gr_new,
 	.sw = gf100_sw_new,
+	.secboot = gm200_secboot_new,
 };
 
 static const struct nvkm_device_chip
@@ -2053,6 +2054,7 @@ nv126_chipset = {
 	.fifo = gm200_fifo_new,
 	.gr = gm206_gr_new,
 	.sw = gf100_sw_new,
+	.secboot = gm200_secboot_new,
 };
 
 static const struct nvkm_device_chip
drm/nouveau/nvkm/engine/gr/gm200.c +1 -7
index 038f9b338a85..935360366dc1 100644
@@ -231,12 +231,6 @@ gm200_gr_data[] = {
  * PGRAPH engine/subdev functions
  ******************************************************************************/
 
-static int
-gm200_gr_init_ctxctl(struct gf100_gr *gr)
-{
-	return 0;
-}
-
 int
 gm200_gr_init(struct gf100_gr *gr)
 {
@@ -350,7 +344,7 @@ gm200_gr_init(struct gf100_gr *gr)
 
 	gf100_gr_zbc_init(gr);
 
-	return gm200_gr_init_ctxctl(gr);
+	return gf100_gr_init_ctxctl(gr);
 }
 
 int gm200_gr_new_(const struct gf100_gr_func *func, struct nvkm_device *device,
drm/nouveau/nvkm/subdev/secboot/Kbuild +1 -0
index e757096b2ff0..c1abf59410d1 100644
@@ -1 +1,2 @@
 nvkm-y += nvkm/subdev/secboot/base.o
+nvkm-y += nvkm/subdev/secboot/gm200.o
drm/nouveau/nvkm/subdev/secboot/gm200.c new file +1485 -0

1,485 lines not on this page · raw message

drm/nouveau/nvkm/subdev/secboot/priv.h +178 -0

182 lines not on this page · raw message

Signature · 1 line
2.7.1
#12 lore raw

PATCH v3 11/11 secboot/gm20b: add secure boot support

In reply to a message not in the archive

Add secure boot support for the GM20B chip found in Tegra X1. Secure boot on Tegra works slightly differently from desktop, notably in the way the WPR region is set up.

In addition, the firmware bootloaders use a slightly different header format.

---
 drm/nouveau/include/nvkm/subdev/secboot.h |   1 +
 drm/nouveau/nvkm/engine/device/base.c     |   1 +
 drm/nouveau/nvkm/engine/gr/gm20b.c        |   9 +-
 drm/nouveau/nvkm/subdev/secboot/Kbuild    |   1 +
 drm/nouveau/nvkm/subdev/secboot/gm20b.c   | 233 ++++++++++++++++++++++++++++++
 5 files changed, 242 insertions(+), 3 deletions(-)
 create mode 100644 drm/nouveau/nvkm/subdev/secboot/gm20b.c
drm/nouveau/include/nvkm/subdev/secboot.h +1 -0
index a509f2b4aa5f..c6edd95a5b69 100644
@@ -54,5 +54,6 @@ int nvkm_secboot_reset(struct nvkm_secboot *, u32 falcon);
 int nvkm_secboot_start(struct nvkm_secboot *, u32 falcon);
 
 int gm200_secboot_new(struct nvkm_device *, int, struct nvkm_secboot **);
+int gm20b_secboot_new(struct nvkm_device *, int, struct nvkm_secboot **);
 
 #endif
drm/nouveau/nvkm/engine/device/base.c +1 -0
index ab56abac0bc5..7a315ac8c800 100644
@@ -2075,6 +2075,7 @@ nv12b_chipset = {
 	.fifo = gm20b_fifo_new,
 	.gr = gm20b_gr_new,
 	.sw = gf100_sw_new,
+	.secboot = gm20b_secboot_new,
 };
 
 static int
drm/nouveau/nvkm/engine/gr/gm20b.c +6 -3
index a440772f8de4..29732bc14415 100644
@@ -32,12 +32,15 @@ gm20b_gr_init_gpc_mmu(struct gf100_gr *gr)
 	struct nvkm_device *device = gr->base.engine.subdev.device;
 	u32 val;
 
-	/* TODO this needs to be removed once secure boot works */
-	if (1) {
+	/* Bypass MMU check for non-secure boot */
+	if (!device->secboot) {
 		nvkm_wr32(device, 0x100ce4, 0xffffffff);
+
+		if (nvkm_rd32(device, 0x100ce4) != 0xffffffff)
+			nvdev_warn(device,
+			  "cannot bypass secure boot - expect failure soon!\n");
 	}
 
-	/* TODO update once secure boot works */
 	val = nvkm_rd32(device, 0x100c80);
 	val &= 0xf000087f;
 	nvkm_wr32(device, 0x418880, val);
drm/nouveau/nvkm/subdev/secboot/Kbuild +1 -0
index c1abf59410d1..b02b868a6589 100644
@@ -1,2 +1,3 @@
 nvkm-y += nvkm/subdev/secboot/base.o
 nvkm-y += nvkm/subdev/secboot/gm200.o
+nvkm-y += nvkm/subdev/secboot/gm20b.o
drm/nouveau/nvkm/subdev/secboot/gm20b.c new file +233 -0

233 lines not on this page · raw message

Signature · 1 line
2.7.1