mirror of
https://github.com/torvalds/linux.git
synced 2026-09-23 13:14:02 +02:00
PCI/sysfs: Fix read byte order in pci_read_legacy_io()
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 <kwilczynski@kernel.org>
This commit is contained in:
parent
dc76258d01
commit
5b95212de6
|
|
@ -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;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user