diff mbox series

drm/nouveau: Add correct turing page kinds

Message ID 20191217005805.2931-1-jajones@nvidia.com (mailing list archive)
State New, archived
Headers show
Series drm/nouveau: Add correct turing page kinds | expand

Commit Message

James Jones Dec. 17, 2019, 12:58 a.m. UTC
Turing introduced a new simplified page kind
scheme, reducing the number of possible page
kinds from 256 to 16.  It also is the first
NVIDIA GPU in which the highest possible page
kind value is not reserved as an "invalid" page
kind.

To address this, the invalid page kind is made
an explicit property of the MMU HAL, and a new
table of page kinds is added to the tu102 MMU
HAL.

One hardware change not addressed here is that
0x00 is technically no longer a supported page
kind, and pitch surfaces are instead intended to
share the block-linear generic page kind 0x06.
However, because that will be a rather invasive
change to nouveau and 0x00 still works fine in
practice on Turing hardware, addressing this new
behavior is deferred.

Signed-off-by: James Jones <jajones@nvidia.com>
---
 drivers/gpu/drm/nouveau/include/nvif/if0008.h    |  2 +-
 drivers/gpu/drm/nouveau/include/nvif/mmu.h       |  4 ++--
 drivers/gpu/drm/nouveau/nvif/mmu.c               |  1 +
 drivers/gpu/drm/nouveau/nvkm/subdev/mmu/gf100.c  |  3 ++-
 drivers/gpu/drm/nouveau/nvkm/subdev/mmu/gm200.c  |  3 ++-
 drivers/gpu/drm/nouveau/nvkm/subdev/mmu/nv50.c   |  3 ++-
 drivers/gpu/drm/nouveau/nvkm/subdev/mmu/priv.h   |  8 ++++----
 drivers/gpu/drm/nouveau/nvkm/subdev/mmu/tu102.c  | 16 +++++++++++++++-
 drivers/gpu/drm/nouveau/nvkm/subdev/mmu/ummu.c   |  7 +++++--
 .../gpu/drm/nouveau/nvkm/subdev/mmu/vmmgf100.c   |  6 +++---
 .../gpu/drm/nouveau/nvkm/subdev/mmu/vmmgp100.c   |  6 +++---
 .../gpu/drm/nouveau/nvkm/subdev/mmu/vmmnv50.c    |  6 +++---
 12 files changed, 43 insertions(+), 22 deletions(-)

Comments

Ben Skeggs Jan. 6, 2020, 1:16 a.m. UTC | #1
On Tue, 17 Dec 2019 at 10:57, James Jones <jajones@nvidia.com> wrote:
>
> Turing introduced a new simplified page kind
> scheme, reducing the number of possible page
> kinds from 256 to 16.  It also is the first
> NVIDIA GPU in which the highest possible page
> kind value is not reserved as an "invalid" page
> kind.
>
> To address this, the invalid page kind is made
> an explicit property of the MMU HAL, and a new
> table of page kinds is added to the tu102 MMU
> HAL.
>
> One hardware change not addressed here is that
> 0x00 is technically no longer a supported page
> kind, and pitch surfaces are instead intended to
> share the block-linear generic page kind 0x06.
> However, because that will be a rather invasive
> change to nouveau and 0x00 still works fine in
> practice on Turing hardware, addressing this new
> behavior is deferred.
Thanks James, I've merged this and the BO move fix into my tree.

>
> Signed-off-by: James Jones <jajones@nvidia.com>
> ---
>  drivers/gpu/drm/nouveau/include/nvif/if0008.h    |  2 +-
>  drivers/gpu/drm/nouveau/include/nvif/mmu.h       |  4 ++--
>  drivers/gpu/drm/nouveau/nvif/mmu.c               |  1 +
>  drivers/gpu/drm/nouveau/nvkm/subdev/mmu/gf100.c  |  3 ++-
>  drivers/gpu/drm/nouveau/nvkm/subdev/mmu/gm200.c  |  3 ++-
>  drivers/gpu/drm/nouveau/nvkm/subdev/mmu/nv50.c   |  3 ++-
>  drivers/gpu/drm/nouveau/nvkm/subdev/mmu/priv.h   |  8 ++++----
>  drivers/gpu/drm/nouveau/nvkm/subdev/mmu/tu102.c  | 16 +++++++++++++++-
>  drivers/gpu/drm/nouveau/nvkm/subdev/mmu/ummu.c   |  7 +++++--
>  .../gpu/drm/nouveau/nvkm/subdev/mmu/vmmgf100.c   |  6 +++---
>  .../gpu/drm/nouveau/nvkm/subdev/mmu/vmmgp100.c   |  6 +++---
>  .../gpu/drm/nouveau/nvkm/subdev/mmu/vmmnv50.c    |  6 +++---
>  12 files changed, 43 insertions(+), 22 deletions(-)
>
> diff --git a/drivers/gpu/drm/nouveau/include/nvif/if0008.h b/drivers/gpu/drm/nouveau/include/nvif/if0008.h
> index 8450127420f5..c21d09f04f1d 100644
> --- a/drivers/gpu/drm/nouveau/include/nvif/if0008.h
> +++ b/drivers/gpu/drm/nouveau/include/nvif/if0008.h
> @@ -35,7 +35,7 @@ struct nvif_mmu_type_v0 {
>
>  struct nvif_mmu_kind_v0 {
>         __u8  version;
> -       __u8  pad01[1];
> +       __u8  kind_inv;
>         __u16 count;
>         __u8  data[];
>  };
> diff --git a/drivers/gpu/drm/nouveau/include/nvif/mmu.h b/drivers/gpu/drm/nouveau/include/nvif/mmu.h
> index 747ecf67e403..cec1e88a0a05 100644
> --- a/drivers/gpu/drm/nouveau/include/nvif/mmu.h
> +++ b/drivers/gpu/drm/nouveau/include/nvif/mmu.h
> @@ -7,6 +7,7 @@ struct nvif_mmu {
>         u8  dmabits;
>         u8  heap_nr;
>         u8  type_nr;
> +       u8  kind_inv;
>         u16 kind_nr;
>         s32 mem;
>
> @@ -36,9 +37,8 @@ void nvif_mmu_fini(struct nvif_mmu *);
>  static inline bool
>  nvif_mmu_kind_valid(struct nvif_mmu *mmu, u8 kind)
>  {
> -       const u8 invalid = mmu->kind_nr - 1;
>         if (kind) {
> -               if (kind >= mmu->kind_nr || mmu->kind[kind] == invalid)
> +               if (kind >= mmu->kind_nr || mmu->kind[kind] == mmu->kind_inv)
>                         return false;
>         }
>         return true;
> diff --git a/drivers/gpu/drm/nouveau/nvif/mmu.c b/drivers/gpu/drm/nouveau/nvif/mmu.c
> index 5641bda2046d..47efc408efa6 100644
> --- a/drivers/gpu/drm/nouveau/nvif/mmu.c
> +++ b/drivers/gpu/drm/nouveau/nvif/mmu.c
> @@ -121,6 +121,7 @@ nvif_mmu_init(struct nvif_object *parent, s32 oclass, struct nvif_mmu *mmu)
>                                        kind, argc);
>                 if (ret == 0)
>                         memcpy(mmu->kind, kind->data, kind->count);
> +               mmu->kind_inv = kind->kind_inv;
>                 kfree(kind);
>         }
>
> diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/gf100.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/gf100.c
> index 2d075246dc46..2cd5ec81c0d0 100644
> --- a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/gf100.c
> +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/gf100.c
> @@ -30,7 +30,7 @@
>   * The value 0xff represents an invalid storage type.
>   */
>  const u8 *
> -gf100_mmu_kind(struct nvkm_mmu *mmu, int *count)
> +gf100_mmu_kind(struct nvkm_mmu *mmu, int *count, u8 *invalid)
>  {
>         static const u8
>         kind[256] = {
> @@ -69,6 +69,7 @@ gf100_mmu_kind(struct nvkm_mmu *mmu, int *count)
>         };
>
>         *count = ARRAY_SIZE(kind);
> +       *invalid = 0xff;
>         return kind;
>  }
>
> diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/gm200.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/gm200.c
> index dbf644ebac97..83990c83f9f8 100644
> --- a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/gm200.c
> +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/gm200.c
> @@ -27,7 +27,7 @@
>  #include <nvif/class.h>
>
>  const u8 *
> -gm200_mmu_kind(struct nvkm_mmu *mmu, int *count)
> +gm200_mmu_kind(struct nvkm_mmu *mmu, int *count, u8 *invalid)
>  {
>         static const u8
>         kind[256] = {
> @@ -65,6 +65,7 @@ gm200_mmu_kind(struct nvkm_mmu *mmu, int *count)
>                 0xfe, 0xfe, 0xfe, 0xfe, 0xff, 0xfd, 0xfe, 0xff
>         };
>         *count = ARRAY_SIZE(kind);
> +       *invalid = 0xff;
>         return kind;
>  }
>
> diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/nv50.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/nv50.c
> index db3dfbbb2aa0..c0083ddda65a 100644
> --- a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/nv50.c
> +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/nv50.c
> @@ -27,7 +27,7 @@
>  #include <nvif/class.h>
>
>  const u8 *
> -nv50_mmu_kind(struct nvkm_mmu *base, int *count)
> +nv50_mmu_kind(struct nvkm_mmu *base, int *count, u8 *invalid)
>  {
>         /* 0x01: no bank swizzle
>          * 0x02: bank swizzled
> @@ -57,6 +57,7 @@ nv50_mmu_kind(struct nvkm_mmu *base, int *count)
>                 0x01, 0x01, 0x02, 0x02, 0x01, 0x01, 0x7f, 0x7f
>         };
>         *count = ARRAY_SIZE(kind);
> +       *invalid = 0x7f;
>         return kind;
>  }
>
> diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/priv.h b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/priv.h
> index 07f2fcd18f3d..479b02344271 100644
> --- a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/priv.h
> +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/priv.h
> @@ -35,17 +35,17 @@ struct nvkm_mmu_func {
>                 u32 pd_offset;
>         } vmm;
>
> -       const u8 *(*kind)(struct nvkm_mmu *, int *count);
> +       const u8 *(*kind)(struct nvkm_mmu *, int *count, u8 *invalid);
>         bool kind_sys;
>  };
>
>  extern const struct nvkm_mmu_func nv04_mmu;
>
> -const u8 *nv50_mmu_kind(struct nvkm_mmu *, int *count);
> +const u8 *nv50_mmu_kind(struct nvkm_mmu *, int *count, u8 *invalid);
>
> -const u8 *gf100_mmu_kind(struct nvkm_mmu *, int *count);
> +const u8 *gf100_mmu_kind(struct nvkm_mmu *, int *count, u8 *invalid);
>
> -const u8 *gm200_mmu_kind(struct nvkm_mmu *, int *);
> +const u8 *gm200_mmu_kind(struct nvkm_mmu *, int *, u8 *);
>
>  struct nvkm_mmu_pt {
>         union {
> diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/tu102.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/tu102.c
> index c0db0ce10cba..b21e82eb0916 100644
> --- a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/tu102.c
> +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/tu102.c
> @@ -1,5 +1,6 @@
>  /*
>   * Copyright 2018 Red Hat Inc.
> + * Copyright 2019 NVIDIA Corporation.
>   *
>   * Permission is hereby granted, free of charge, to any person obtaining a
>   * copy of this software and associated documentation files (the "Software"),
> @@ -26,13 +27,26 @@
>
>  #include <nvif/class.h>
>
> +const u8 *
> +tu102_mmu_kind(struct nvkm_mmu *mmu, int *count, u8 *invalid)
> +{
> +       static const u8
> +       kind[16] = {
> +               0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00 */
> +               0x06, 0x06, 0x02, 0x01, 0x03, 0x04, 0x05, 0x07,
> +       };
> +       *count = ARRAY_SIZE(kind);
> +       *invalid = 0x07;
> +       return kind;
> +}
> +
>  static const struct nvkm_mmu_func
>  tu102_mmu = {
>         .dma_bits = 47,
>         .mmu = {{ -1, -1, NVIF_CLASS_MMU_GF100}},
>         .mem = {{ -1,  0, NVIF_CLASS_MEM_GF100}, gf100_mem_new, gf100_mem_map },
>         .vmm = {{ -1,  0, NVIF_CLASS_VMM_GP100}, tu102_vmm_new },
> -       .kind = gm200_mmu_kind,
> +       .kind = tu102_mmu_kind,
>         .kind_sys = true,
>  };
>
> diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/ummu.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/ummu.c
> index 353f10f92b77..0e4b8941da37 100644
> --- a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/ummu.c
> +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/ummu.c
> @@ -111,15 +111,17 @@ nvkm_ummu_kind(struct nvkm_ummu *ummu, void *argv, u32 argc)
>         } *args = argv;
>         const u8 *kind = NULL;
>         int ret = -ENOSYS, count = 0;
> +       u8 kind_inv = 0;
>
>         if (mmu->func->kind)
> -               kind = mmu->func->kind(mmu, &count);
> +               kind = mmu->func->kind(mmu, &count, &kind_inv);
>
>         if (!(ret = nvif_unpack(ret, &argv, &argc, args->v0, 0, 0, true))) {
>                 if (argc != args->v0.count * sizeof(*args->v0.data))
>                         return -EINVAL;
>                 if (args->v0.count > count)
>                         return -EINVAL;
> +               args->v0.kind_inv = kind_inv;
>                 memcpy(args->v0.data, kind, args->v0.count);
>         } else
>                 return ret;
> @@ -157,9 +159,10 @@ nvkm_ummu_new(struct nvkm_device *device, const struct nvkm_oclass *oclass,
>         struct nvkm_mmu *mmu = device->mmu;
>         struct nvkm_ummu *ummu;
>         int ret = -ENOSYS, kinds = 0;
> +       u8 unused = 0;
>
>         if (mmu->func->kind)
> -               mmu->func->kind(mmu, &kinds);
> +               mmu->func->kind(mmu, &kinds, &unused);
>
>         if (!(ret = nvif_unpack(ret, &argv, &argc, args->v0, 0, 0, false))) {
>                 args->v0.dmabits = mmu->dma_bits;
> diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/vmmgf100.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/vmmgf100.c
> index ab6424faf84c..6a2d9eb8e1ea 100644
> --- a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/vmmgf100.c
> +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/vmmgf100.c
> @@ -247,7 +247,7 @@ gf100_vmm_valid(struct nvkm_vmm *vmm, void *argv, u32 argc,
>         } *args = argv;
>         struct nvkm_device *device = vmm->mmu->subdev.device;
>         struct nvkm_memory *memory = map->memory;
> -       u8  kind, priv, ro, vol;
> +       u8  kind, kind_inv, priv, ro, vol;
>         int kindn, aper, ret = -ENOSYS;
>         const u8 *kindm;
>
> @@ -274,8 +274,8 @@ gf100_vmm_valid(struct nvkm_vmm *vmm, void *argv, u32 argc,
>         if (WARN_ON(aper < 0))
>                 return aper;
>
> -       kindm = vmm->mmu->func->kind(vmm->mmu, &kindn);
> -       if (kind >= kindn || kindm[kind] == 0xff) {
> +       kindm = vmm->mmu->func->kind(vmm->mmu, &kindn, &kind_inv);
> +       if (kind >= kindn || kindm[kind] == kind_inv) {
>                 VMM_DEBUG(vmm, "kind %02x", kind);
>                 return -EINVAL;
>         }
> diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/vmmgp100.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/vmmgp100.c
> index b4f519768d5e..d86287565542 100644
> --- a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/vmmgp100.c
> +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/vmmgp100.c
> @@ -320,7 +320,7 @@ gp100_vmm_valid(struct nvkm_vmm *vmm, void *argv, u32 argc,
>         } *args = argv;
>         struct nvkm_device *device = vmm->mmu->subdev.device;
>         struct nvkm_memory *memory = map->memory;
> -       u8  kind, priv, ro, vol;
> +       u8  kind, kind_inv, priv, ro, vol;
>         int kindn, aper, ret = -ENOSYS;
>         const u8 *kindm;
>
> @@ -347,8 +347,8 @@ gp100_vmm_valid(struct nvkm_vmm *vmm, void *argv, u32 argc,
>         if (WARN_ON(aper < 0))
>                 return aper;
>
> -       kindm = vmm->mmu->func->kind(vmm->mmu, &kindn);
> -       if (kind >= kindn || kindm[kind] == 0xff) {
> +       kindm = vmm->mmu->func->kind(vmm->mmu, &kindn, &kind_inv);
> +       if (kind >= kindn || kindm[kind] == kind_inv) {
>                 VMM_DEBUG(vmm, "kind %02x", kind);
>                 return -EINVAL;
>         }
> diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/vmmnv50.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/vmmnv50.c
> index c98afe3134ee..2d89e27e8e9e 100644
> --- a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/vmmnv50.c
> +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/vmmnv50.c
> @@ -235,7 +235,7 @@ nv50_vmm_valid(struct nvkm_vmm *vmm, void *argv, u32 argc,
>         struct nvkm_device *device = vmm->mmu->subdev.device;
>         struct nvkm_ram *ram = device->fb->ram;
>         struct nvkm_memory *memory = map->memory;
> -       u8  aper, kind, comp, priv, ro;
> +       u8  aper, kind, kind_inv, comp, priv, ro;
>         int kindn, ret = -ENOSYS;
>         const u8 *kindm;
>
> @@ -278,8 +278,8 @@ nv50_vmm_valid(struct nvkm_vmm *vmm, void *argv, u32 argc,
>                 return -EINVAL;
>         }
>
> -       kindm = vmm->mmu->func->kind(vmm->mmu, &kindn);
> -       if (kind >= kindn || kindm[kind] == 0x7f) {
> +       kindm = vmm->mmu->func->kind(vmm->mmu, &kindn, &kind_inv);
> +       if (kind >= kindn || kindm[kind] == kind_inv) {
>                 VMM_DEBUG(vmm, "kind %02x", kind);
>                 return -EINVAL;
>         }
> --
> 2.17.1
>
> _______________________________________________
> Nouveau mailing list
> Nouveau@lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/nouveau
diff mbox series

Patch

diff --git a/drivers/gpu/drm/nouveau/include/nvif/if0008.h b/drivers/gpu/drm/nouveau/include/nvif/if0008.h
index 8450127420f5..c21d09f04f1d 100644
--- a/drivers/gpu/drm/nouveau/include/nvif/if0008.h
+++ b/drivers/gpu/drm/nouveau/include/nvif/if0008.h
@@ -35,7 +35,7 @@  struct nvif_mmu_type_v0 {
 
 struct nvif_mmu_kind_v0 {
 	__u8  version;
-	__u8  pad01[1];
+	__u8  kind_inv;
 	__u16 count;
 	__u8  data[];
 };
diff --git a/drivers/gpu/drm/nouveau/include/nvif/mmu.h b/drivers/gpu/drm/nouveau/include/nvif/mmu.h
index 747ecf67e403..cec1e88a0a05 100644
--- a/drivers/gpu/drm/nouveau/include/nvif/mmu.h
+++ b/drivers/gpu/drm/nouveau/include/nvif/mmu.h
@@ -7,6 +7,7 @@  struct nvif_mmu {
 	u8  dmabits;
 	u8  heap_nr;
 	u8  type_nr;
+	u8  kind_inv;
 	u16 kind_nr;
 	s32 mem;
 
@@ -36,9 +37,8 @@  void nvif_mmu_fini(struct nvif_mmu *);
 static inline bool
 nvif_mmu_kind_valid(struct nvif_mmu *mmu, u8 kind)
 {
-	const u8 invalid = mmu->kind_nr - 1;
 	if (kind) {
-		if (kind >= mmu->kind_nr || mmu->kind[kind] == invalid)
+		if (kind >= mmu->kind_nr || mmu->kind[kind] == mmu->kind_inv)
 			return false;
 	}
 	return true;
diff --git a/drivers/gpu/drm/nouveau/nvif/mmu.c b/drivers/gpu/drm/nouveau/nvif/mmu.c
index 5641bda2046d..47efc408efa6 100644
--- a/drivers/gpu/drm/nouveau/nvif/mmu.c
+++ b/drivers/gpu/drm/nouveau/nvif/mmu.c
@@ -121,6 +121,7 @@  nvif_mmu_init(struct nvif_object *parent, s32 oclass, struct nvif_mmu *mmu)
 				       kind, argc);
 		if (ret == 0)
 			memcpy(mmu->kind, kind->data, kind->count);
+		mmu->kind_inv = kind->kind_inv;
 		kfree(kind);
 	}
 
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/gf100.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/gf100.c
index 2d075246dc46..2cd5ec81c0d0 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/gf100.c
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/gf100.c
@@ -30,7 +30,7 @@ 
  * The value 0xff represents an invalid storage type.
  */
 const u8 *
-gf100_mmu_kind(struct nvkm_mmu *mmu, int *count)
+gf100_mmu_kind(struct nvkm_mmu *mmu, int *count, u8 *invalid)
 {
 	static const u8
 	kind[256] = {
@@ -69,6 +69,7 @@  gf100_mmu_kind(struct nvkm_mmu *mmu, int *count)
 	};
 
 	*count = ARRAY_SIZE(kind);
+	*invalid = 0xff;
 	return kind;
 }
 
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/gm200.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/gm200.c
index dbf644ebac97..83990c83f9f8 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/gm200.c
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/gm200.c
@@ -27,7 +27,7 @@ 
 #include <nvif/class.h>
 
 const u8 *
-gm200_mmu_kind(struct nvkm_mmu *mmu, int *count)
+gm200_mmu_kind(struct nvkm_mmu *mmu, int *count, u8 *invalid)
 {
 	static const u8
 	kind[256] = {
@@ -65,6 +65,7 @@  gm200_mmu_kind(struct nvkm_mmu *mmu, int *count)
 		0xfe, 0xfe, 0xfe, 0xfe, 0xff, 0xfd, 0xfe, 0xff
 	};
 	*count = ARRAY_SIZE(kind);
+	*invalid = 0xff;
 	return kind;
 }
 
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/nv50.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/nv50.c
index db3dfbbb2aa0..c0083ddda65a 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/nv50.c
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/nv50.c
@@ -27,7 +27,7 @@ 
 #include <nvif/class.h>
 
 const u8 *
-nv50_mmu_kind(struct nvkm_mmu *base, int *count)
+nv50_mmu_kind(struct nvkm_mmu *base, int *count, u8 *invalid)
 {
 	/* 0x01: no bank swizzle
 	 * 0x02: bank swizzled
@@ -57,6 +57,7 @@  nv50_mmu_kind(struct nvkm_mmu *base, int *count)
 		0x01, 0x01, 0x02, 0x02, 0x01, 0x01, 0x7f, 0x7f
 	};
 	*count = ARRAY_SIZE(kind);
+	*invalid = 0x7f;
 	return kind;
 }
 
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/priv.h b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/priv.h
index 07f2fcd18f3d..479b02344271 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/priv.h
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/priv.h
@@ -35,17 +35,17 @@  struct nvkm_mmu_func {
 		u32 pd_offset;
 	} vmm;
 
-	const u8 *(*kind)(struct nvkm_mmu *, int *count);
+	const u8 *(*kind)(struct nvkm_mmu *, int *count, u8 *invalid);
 	bool kind_sys;
 };
 
 extern const struct nvkm_mmu_func nv04_mmu;
 
-const u8 *nv50_mmu_kind(struct nvkm_mmu *, int *count);
+const u8 *nv50_mmu_kind(struct nvkm_mmu *, int *count, u8 *invalid);
 
-const u8 *gf100_mmu_kind(struct nvkm_mmu *, int *count);
+const u8 *gf100_mmu_kind(struct nvkm_mmu *, int *count, u8 *invalid);
 
-const u8 *gm200_mmu_kind(struct nvkm_mmu *, int *);
+const u8 *gm200_mmu_kind(struct nvkm_mmu *, int *, u8 *);
 
 struct nvkm_mmu_pt {
 	union {
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/tu102.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/tu102.c
index c0db0ce10cba..b21e82eb0916 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/tu102.c
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/tu102.c
@@ -1,5 +1,6 @@ 
 /*
  * Copyright 2018 Red Hat Inc.
+ * Copyright 2019 NVIDIA Corporation.
  *
  * Permission is hereby granted, free of charge, to any person obtaining a
  * copy of this software and associated documentation files (the "Software"),
@@ -26,13 +27,26 @@ 
 
 #include <nvif/class.h>
 
+const u8 *
+tu102_mmu_kind(struct nvkm_mmu *mmu, int *count, u8 *invalid)
+{
+	static const u8
+	kind[16] = {
+		0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00 */
+		0x06, 0x06, 0x02, 0x01, 0x03, 0x04, 0x05, 0x07,
+	};
+	*count = ARRAY_SIZE(kind);
+	*invalid = 0x07;
+	return kind;
+}
+
 static const struct nvkm_mmu_func
 tu102_mmu = {
 	.dma_bits = 47,
 	.mmu = {{ -1, -1, NVIF_CLASS_MMU_GF100}},
 	.mem = {{ -1,  0, NVIF_CLASS_MEM_GF100}, gf100_mem_new, gf100_mem_map },
 	.vmm = {{ -1,  0, NVIF_CLASS_VMM_GP100}, tu102_vmm_new },
-	.kind = gm200_mmu_kind,
+	.kind = tu102_mmu_kind,
 	.kind_sys = true,
 };
 
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/ummu.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/ummu.c
index 353f10f92b77..0e4b8941da37 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/ummu.c
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/ummu.c
@@ -111,15 +111,17 @@  nvkm_ummu_kind(struct nvkm_ummu *ummu, void *argv, u32 argc)
 	} *args = argv;
 	const u8 *kind = NULL;
 	int ret = -ENOSYS, count = 0;
+	u8 kind_inv = 0;
 
 	if (mmu->func->kind)
-		kind = mmu->func->kind(mmu, &count);
+		kind = mmu->func->kind(mmu, &count, &kind_inv);
 
 	if (!(ret = nvif_unpack(ret, &argv, &argc, args->v0, 0, 0, true))) {
 		if (argc != args->v0.count * sizeof(*args->v0.data))
 			return -EINVAL;
 		if (args->v0.count > count)
 			return -EINVAL;
+		args->v0.kind_inv = kind_inv;
 		memcpy(args->v0.data, kind, args->v0.count);
 	} else
 		return ret;
@@ -157,9 +159,10 @@  nvkm_ummu_new(struct nvkm_device *device, const struct nvkm_oclass *oclass,
 	struct nvkm_mmu *mmu = device->mmu;
 	struct nvkm_ummu *ummu;
 	int ret = -ENOSYS, kinds = 0;
+	u8 unused = 0;
 
 	if (mmu->func->kind)
-		mmu->func->kind(mmu, &kinds);
+		mmu->func->kind(mmu, &kinds, &unused);
 
 	if (!(ret = nvif_unpack(ret, &argv, &argc, args->v0, 0, 0, false))) {
 		args->v0.dmabits = mmu->dma_bits;
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/vmmgf100.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/vmmgf100.c
index ab6424faf84c..6a2d9eb8e1ea 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/vmmgf100.c
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/vmmgf100.c
@@ -247,7 +247,7 @@  gf100_vmm_valid(struct nvkm_vmm *vmm, void *argv, u32 argc,
 	} *args = argv;
 	struct nvkm_device *device = vmm->mmu->subdev.device;
 	struct nvkm_memory *memory = map->memory;
-	u8  kind, priv, ro, vol;
+	u8  kind, kind_inv, priv, ro, vol;
 	int kindn, aper, ret = -ENOSYS;
 	const u8 *kindm;
 
@@ -274,8 +274,8 @@  gf100_vmm_valid(struct nvkm_vmm *vmm, void *argv, u32 argc,
 	if (WARN_ON(aper < 0))
 		return aper;
 
-	kindm = vmm->mmu->func->kind(vmm->mmu, &kindn);
-	if (kind >= kindn || kindm[kind] == 0xff) {
+	kindm = vmm->mmu->func->kind(vmm->mmu, &kindn, &kind_inv);
+	if (kind >= kindn || kindm[kind] == kind_inv) {
 		VMM_DEBUG(vmm, "kind %02x", kind);
 		return -EINVAL;
 	}
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/vmmgp100.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/vmmgp100.c
index b4f519768d5e..d86287565542 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/vmmgp100.c
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/vmmgp100.c
@@ -320,7 +320,7 @@  gp100_vmm_valid(struct nvkm_vmm *vmm, void *argv, u32 argc,
 	} *args = argv;
 	struct nvkm_device *device = vmm->mmu->subdev.device;
 	struct nvkm_memory *memory = map->memory;
-	u8  kind, priv, ro, vol;
+	u8  kind, kind_inv, priv, ro, vol;
 	int kindn, aper, ret = -ENOSYS;
 	const u8 *kindm;
 
@@ -347,8 +347,8 @@  gp100_vmm_valid(struct nvkm_vmm *vmm, void *argv, u32 argc,
 	if (WARN_ON(aper < 0))
 		return aper;
 
-	kindm = vmm->mmu->func->kind(vmm->mmu, &kindn);
-	if (kind >= kindn || kindm[kind] == 0xff) {
+	kindm = vmm->mmu->func->kind(vmm->mmu, &kindn, &kind_inv);
+	if (kind >= kindn || kindm[kind] == kind_inv) {
 		VMM_DEBUG(vmm, "kind %02x", kind);
 		return -EINVAL;
 	}
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/vmmnv50.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/vmmnv50.c
index c98afe3134ee..2d89e27e8e9e 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/vmmnv50.c
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/vmmnv50.c
@@ -235,7 +235,7 @@  nv50_vmm_valid(struct nvkm_vmm *vmm, void *argv, u32 argc,
 	struct nvkm_device *device = vmm->mmu->subdev.device;
 	struct nvkm_ram *ram = device->fb->ram;
 	struct nvkm_memory *memory = map->memory;
-	u8  aper, kind, comp, priv, ro;
+	u8  aper, kind, kind_inv, comp, priv, ro;
 	int kindn, ret = -ENOSYS;
 	const u8 *kindm;
 
@@ -278,8 +278,8 @@  nv50_vmm_valid(struct nvkm_vmm *vmm, void *argv, u32 argc,
 		return -EINVAL;
 	}
 
-	kindm = vmm->mmu->func->kind(vmm->mmu, &kindn);
-	if (kind >= kindn || kindm[kind] == 0x7f) {
+	kindm = vmm->mmu->func->kind(vmm->mmu, &kindn, &kind_inv);
+	if (kind >= kindn || kindm[kind] == kind_inv) {
 		VMM_DEBUG(vmm, "kind %02x", kind);
 		return -EINVAL;
 	}