[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-Id: <20201109125031.740570960@linuxfoundation.org>
Date: Mon, 9 Nov 2020 13:54:43 +0100
From: Greg Kroah-Hartman <gregkh@...uxfoundation.org>
To: linux-kernel@...r.kernel.org
Cc: Greg Kroah-Hartman <gregkh@...uxfoundation.org>,
stable@...r.kernel.org, Karol Herbst <kherbst@...hat.com>,
Ben Skeggs <bskeggs@...hat.com>
Subject: [PATCH 5.9 021/133] drm/nouveau/device: fix changing endianess code to work on older GPUs
From: Karol Herbst <kherbst@...hat.com>
commit dcd292c172493067a72672b245a3dd1bcf7268dd upstream.
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")
Signed-off-by: Karol Herbst <kherbst@...hat.com>
Cc: <stable@...r.kernel.org> # v5.8+
Signed-off-by: Ben Skeggs <bskeggs@...hat.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@...uxfoundation.org>
---
drivers/gpu/drm/nouveau/nvkm/engine/device/base.c | 39 ++++++++++++++--------
1 file changed, 26 insertions(+), 13 deletions(-)
--- 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 **pde
}
}
+/* 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_devic
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);
Powered by blists - more mailing lists