[+cc Arnd] On Thu, Jul 31, 2025 at 07:38:58PM +0200, Gerd Bayer wrote: > Simple pointer-casts to map byte and word reads from PCI config space > into dwords (i.e. u32) produce unintended results on big-endian systems. > Add the necessary adjustments under compile-time switch > CONFIG_CPU_BIG_ENDIAN. > > pci_bus_read_config() was just introduced with > https://lore.kernel.org/all/20250716161203.83823-2-18255117159@xxxxxxx/ > > Signed-off-by: Gerd Bayer <gbayer@xxxxxxxxxxxxx> > --- > > Hi Hans, hi Bjorn, > > Sorry to spill this endianness aware code into drivers/pci, feel free to > suggest a cleaner approach. This has fixed the issues seen on s390 systems > Otherwise it is just compile-tested for x86 and arm64. > > Since this is still sitting in the a pull-request for upstream, I'm not sure if this > warrants a Fixes: tag. > > Thanks, > Gerd > --- > drivers/pci/access.c | 25 +++++++++++++++++-------- > 1 file changed, 17 insertions(+), 8 deletions(-) > > diff --git a/drivers/pci/access.c b/drivers/pci/access.c > index ba66f55d2524..77a73b772a28 100644 > --- a/drivers/pci/access.c > +++ b/drivers/pci/access.c > @@ -89,15 +89,24 @@ int pci_bus_read_config(void *priv, unsigned int devfn, int where, u32 size, > u32 *val) > { > struct pci_bus *bus = priv; > + int rc; > > - if (size == 1) > - return pci_bus_read_config_byte(bus, devfn, where, (u8 *)val); > - else if (size == 2) > - return pci_bus_read_config_word(bus, devfn, where, (u16 *)val); > - else if (size == 4) > - return pci_bus_read_config_dword(bus, devfn, where, val); > - else > - return PCIBIOS_BAD_REGISTER_NUMBER; > + if (size == 1) { > + rc = pci_bus_read_config_byte(bus, devfn, where, (u8 *)val); > +#if (IS_ENABLED(CONFIG_CPU_BIG_ENDIAN)) > + *val = ((*val >> 24) & 0xff); > +#endif Yeah, this is all pretty ugly. Obviously the previous code in __pci_find_next_cap_ttl() didn't need this. My guess is that was because the destination for the read data was always the correct type (u8/u16/u32), but here we always use a u32 and cast it to the appropriate type. Maybe we can use the correct types here instead of the casts? > + } else if (size == 2) { > + rc = pci_bus_read_config_word(bus, devfn, where, (u16 *)val); > +#if (IS_ENABLED(CONFIG_CPU_BIG_ENDIAN)) > + *val = ((*val >> 16) & 0xffff); > +#endif > + } else if (size == 4) { > + rc = pci_bus_read_config_dword(bus, devfn, where, val); > + } else { > + rc = PCIBIOS_BAD_REGISTER_NUMBER; > + } > + return rc; > } > > int pci_generic_config_read(struct pci_bus *bus, unsigned int devfn, > -- > 2.48.1 >