From 5b95212de6dcd7e0275cea7f894fe7226c7d9f29 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysztof=20Wilczy=C5=84ski?= Date: Tue, 16 Jun 2026 16:31:31 +0000 Subject: [PATCH] PCI/sysfs: Fix read byte order in pci_read_legacy_io() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit pci_read_legacy_io() passes the sysfs buffer directly to pci_legacy_read(): return pci_legacy_read(bus, off, (u32 *)buf, count); The PowerPC implementation stores the result as a native-endian integer: *((u16 *)val) = in_le16(addr); On big-endian PowerPC this stores the bytes in the wrong order, so a 2-byte read of a device register returns different bytes than two 1-byte reads at the same addresses. The same applies to 4-byte reads. On little-endian the native byte order already matches PCI I/O port byte order, so the conversion is a no-op. Thus, let pci_legacy_read() store into a local u32 variable, then copy the I/O port value to the sysfs buffer using put_unaligned_le16() and put_unaligned_le32() for the 2 and 4 byte cases, converting from the native integer to little-endian byte order matching PCI I/O port space. No changes are needed for the Alpha platform. The legacy_io file is root-only and exists only on Alpha and PowerPC, the two architectures that define HAVE_PCI_LEGACY. Cc: stable@vger.kernel.org Link: https://patch.msgid.link/20260616163131.2763281-2-kwilczynski@kernel.org Signed-off-by: Krzysztof WilczyƄski --- drivers/pci/pci-sysfs.c | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/drivers/pci/pci-sysfs.c b/drivers/pci/pci-sysfs.c index 2970ad502b78..e985a3854f8d 100644 --- a/drivers/pci/pci-sysfs.c +++ b/drivers/pci/pci-sysfs.c @@ -888,12 +888,30 @@ static ssize_t pci_read_legacy_io(struct file *filp, struct kobject *kobj, char *buf, loff_t off, size_t count) { struct pci_bus *bus = to_pci_bus(kobj_to_dev(kobj)); + u32 val = 0; + int ret; /* Only support 1, 2 or 4 byte accesses */ if (count != 1 && count != 2 && count != 4) return -EINVAL; - return pci_legacy_read(bus, off, (u32 *)buf, count); + ret = pci_legacy_read(bus, off, &val, count); + if (ret < 0) + return ret; + + switch (count) { + case 1: + buf[0] = *(u8 *)&val; + break; + case 2: + put_unaligned_le16(*(u16 *)&val, buf); + break; + case 4: + put_unaligned_le32(val, buf); + break; + } + + return ret; } /**