Karol Herbst
2020-Oct-13 12:01 UTC
[Nouveau] [PATCH] drm/nouveau/device: fix changing endianess code to work on older GPUs
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
Karol Herbst
2020-Oct-13 12:02 UTC
[Nouveau] [PATCH] drm/nouveau/device: fix changing endianess code to work on older GPUs
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 >
Ilia Mirkin
2020-Oct-13 13:54 UTC
[Nouveau] [PATCH] drm/nouveau/device: fix changing endianess code to work on older GPUs
On Tue, Oct 13, 2020 at 8:01 AM 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)Are you sure there are no other bits in there, esp on newer GPUs?> + 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 > > _______________________________________________ > Nouveau mailing list > Nouveau at lists.freedesktop.org > https://lists.freedesktop.org/mailman/listinfo/nouveau
Karol Herbst
2020-Oct-13 13:56 UTC
[Nouveau] [PATCH] drm/nouveau/device: fix changing endianess code to work on older GPUs
On Tue, Oct 13, 2020 at 3:55 PM Ilia Mirkin <imirkin at alum.mit.edu> wrote:> > On Tue, Oct 13, 2020 at 8:01 AM 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) > > Are you sure there are no other bits in there, esp on newer GPUs? >Fairly. Checked on GP107 today, which is nearly the last gen to even support it. I think it's gone with volta or turing.> > + 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 > > > > _______________________________________________ > > Nouveau mailing list > > Nouveau at lists.freedesktop.org > > https://lists.freedesktop.org/mailman/listinfo/nouveau > _______________________________________________ > Nouveau mailing list > Nouveau at lists.freedesktop.org > https://lists.freedesktop.org/mailman/listinfo/nouveau >
Seemingly Similar Threads
- [PATCH] drm/nouveau/device: fix changing endianess code to work on older GPUs
- [PATCH 1/3] device: use the correct mmio size when mapping
- [PATCH v2 1/3] device: use the correct mmio size when mapping
- [PATCH v3 1/3] device: rework mmio mapping code to get rid of second map
- [PATCH v3 2/3] device: detect if changing endianness failed