Commit dcd292c1 authored by Karol Herbst's avatar Karol Herbst Committed by Ben Skeggs
Browse files

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: 51c05340 ("drm/nouveau/device: detect if changing endianness failed")
Signed-off-by: default avatarKarol Herbst <kherbst@redhat.com>
Cc: <stable@vger.kernel.org> # v5.8+
Signed-off-by: default avatarBen Skeggs <bskeggs@redhat.com>
parent 92568145
Loading
Loading
Loading
Loading
+26 −13
Original line number Diff line number Diff line
@@ -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;
}

@@ -2986,16 +3003,12 @@ nvkm_device_ctor(const struct nvkm_device_func *func,
	/* identify the chipset, and determine classes of subdev/engines */
	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");
				    "Couldn't switch GPU to CPUs endianess\n");
			ret = -ENOSYS;
			goto done;
		}
		}

		boot0 = nvkm_rd32(device, 0x000000);