[Nouveau] [PATCH] drm/nouveau/device: fix changing endianess code to work on older GPUs

Karol Herbst kherbst at redhat.com
Tue Oct 13 12:02:50 UTC 2020


ehh.. messed up sending it against the other thread, but mind testing
this patch and verify it fixes your issue? Thanks.

On Tue, Oct 13, 2020 at 2:01 PM Karol Herbst <kherbst at redhat.com> wrote:
>
> With this we try to detect if the endianess switch works and assume LE if
> not. Suggested by Ben.
>
> Fixes: 51c05340e407 ("drm/nouveau/device: detect if changing endianness failed")
> ---
>  .../gpu/drm/nouveau/nvkm/engine/device/base.c | 39 ++++++++++++-------
>  1 file changed, 26 insertions(+), 13 deletions(-)
>
> diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c
> index dcb70677d0acc..7851bec5f0e5f 100644
> --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c
> +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c
> @@ -2924,17 +2924,34 @@ nvkm_device_del(struct nvkm_device **pdevice)
>         }
>  }
>
> +/* returns true if the GPU is in the CPU native byte order */
>  static inline bool
>  nvkm_device_endianness(struct nvkm_device *device)
>  {
> -       u32 boot1 = nvkm_rd32(device, 0x000004) & 0x01000001;
>  #ifdef __BIG_ENDIAN
> -       if (!boot1)
> -               return false;
> +       const bool big_endian = true;
>  #else
> -       if (boot1)
> -               return false;
> +       const bool big_endian = false;
>  #endif
> +
> +       /* Read NV_PMC_BOOT_1, and assume non-functional endian switch if it
> +        * doesn't contain the expected values.
> +        */
> +       u32 pmc_boot_1 = nvkm_rd32(device, 0x000004);
> +       if (pmc_boot_1 && pmc_boot_1 != 0x01000001)
> +               return !big_endian; /* Assume GPU is LE in this case. */
> +
> +       /* 0 means LE and 0x01000001 means BE GPU. Condition is true when
> +        * GPU/CPU endianness don't match.
> +        */
> +       if (big_endian == !pmc_boot_1) {
> +               nvkm_wr32(device, 0x000004, 0x01000001);
> +               nvkm_rd32(device, 0x000000);
> +               if (nvkm_rd32(device, 0x000004) != (big_endian ? 0x01000001 : 0x00000000))
> +                       return !big_endian; /* Assume GPU is LE on any unexpected read-back. */
> +       }
> +
> +       /* CPU/GPU endianness should (hopefully) match. */
>         return true;
>  }
>
> @@ -2987,14 +3004,10 @@ nvkm_device_ctor(const struct nvkm_device_func *func,
>         if (detect) {
>                 /* switch mmio to cpu's native endianness */
>                 if (!nvkm_device_endianness(device)) {
> -                       nvkm_wr32(device, 0x000004, 0x01000001);
> -                       nvkm_rd32(device, 0x000000);
> -                       if (!nvkm_device_endianness(device)) {
> -                               nvdev_error(device,
> -                                           "GPU not supported on big-endian\n");
> -                               ret = -ENOSYS;
> -                               goto done;
> -                       }
> +                       nvdev_error(device,
> +                                   "Couldn't switch GPU to CPUs endianess\n");
> +                       ret = -ENOSYS;
> +                       goto done;
>                 }
>
>                 boot0 = nvkm_rd32(device, 0x000000);
> --
> 2.26.2
>



More information about the Nouveau mailing list