PCI: pci-bridge-emul: Fix big-endian support

commit e0d9d30b73548fbfe5c024ed630169bdc9a08aee upstream.

Perform conversion to little-endian before every write to configuration
space and convert it back to CPU endianness on reads.

Additionally, initialise every multiple byte field of config space with
the cpu_to_le* macro, which is required since the structure describing
config space of emulated bridge assumes little-endian convention.

Signed-off-by: Grzegorz Jaszczyk <jaz@semihalf.com>
Signed-off-by: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
Grzegorz Jaszczyk 2019-07-16 14:13:46 +02:00 committed by Greg Kroah-Hartman
parent 07e5f23d3f
commit 2fcb7b7a1d
2 changed files with 52 additions and 51 deletions

View File

@ -270,10 +270,10 @@ static const struct pci_bridge_reg_behavior pcie_cap_regs_behavior[] = {
int pci_bridge_emul_init(struct pci_bridge_emul *bridge, int pci_bridge_emul_init(struct pci_bridge_emul *bridge,
unsigned int flags) unsigned int flags)
{ {
bridge->conf.class_revision |= PCI_CLASS_BRIDGE_PCI << 16; bridge->conf.class_revision |= cpu_to_le32(PCI_CLASS_BRIDGE_PCI << 16);
bridge->conf.header_type = PCI_HEADER_TYPE_BRIDGE; bridge->conf.header_type = PCI_HEADER_TYPE_BRIDGE;
bridge->conf.cache_line_size = 0x10; bridge->conf.cache_line_size = 0x10;
bridge->conf.status = PCI_STATUS_CAP_LIST; bridge->conf.status = cpu_to_le16(PCI_STATUS_CAP_LIST);
bridge->pci_regs_behavior = kmemdup(pci_regs_behavior, bridge->pci_regs_behavior = kmemdup(pci_regs_behavior,
sizeof(pci_regs_behavior), sizeof(pci_regs_behavior),
GFP_KERNEL); GFP_KERNEL);
@ -284,8 +284,9 @@ int pci_bridge_emul_init(struct pci_bridge_emul *bridge,
bridge->conf.capabilities_pointer = PCI_CAP_PCIE_START; bridge->conf.capabilities_pointer = PCI_CAP_PCIE_START;
bridge->pcie_conf.cap_id = PCI_CAP_ID_EXP; bridge->pcie_conf.cap_id = PCI_CAP_ID_EXP;
/* Set PCIe v2, root port, slot support */ /* Set PCIe v2, root port, slot support */
bridge->pcie_conf.cap = PCI_EXP_TYPE_ROOT_PORT << 4 | 2 | bridge->pcie_conf.cap =
PCI_EXP_FLAGS_SLOT; cpu_to_le16(PCI_EXP_TYPE_ROOT_PORT << 4 | 2 |
PCI_EXP_FLAGS_SLOT);
bridge->pcie_cap_regs_behavior = bridge->pcie_cap_regs_behavior =
kmemdup(pcie_cap_regs_behavior, kmemdup(pcie_cap_regs_behavior,
sizeof(pcie_cap_regs_behavior), sizeof(pcie_cap_regs_behavior),
@ -327,7 +328,7 @@ int pci_bridge_emul_conf_read(struct pci_bridge_emul *bridge, int where,
int reg = where & ~3; int reg = where & ~3;
pci_bridge_emul_read_status_t (*read_op)(struct pci_bridge_emul *bridge, pci_bridge_emul_read_status_t (*read_op)(struct pci_bridge_emul *bridge,
int reg, u32 *value); int reg, u32 *value);
u32 *cfgspace; __le32 *cfgspace;
const struct pci_bridge_reg_behavior *behavior; const struct pci_bridge_reg_behavior *behavior;
if (bridge->has_pcie && reg >= PCI_CAP_PCIE_END) { if (bridge->has_pcie && reg >= PCI_CAP_PCIE_END) {
@ -343,11 +344,11 @@ int pci_bridge_emul_conf_read(struct pci_bridge_emul *bridge, int where,
if (bridge->has_pcie && reg >= PCI_CAP_PCIE_START) { if (bridge->has_pcie && reg >= PCI_CAP_PCIE_START) {
reg -= PCI_CAP_PCIE_START; reg -= PCI_CAP_PCIE_START;
read_op = bridge->ops->read_pcie; read_op = bridge->ops->read_pcie;
cfgspace = (u32 *) &bridge->pcie_conf; cfgspace = (__le32 *) &bridge->pcie_conf;
behavior = bridge->pcie_cap_regs_behavior; behavior = bridge->pcie_cap_regs_behavior;
} else { } else {
read_op = bridge->ops->read_base; read_op = bridge->ops->read_base;
cfgspace = (u32 *) &bridge->conf; cfgspace = (__le32 *) &bridge->conf;
behavior = bridge->pci_regs_behavior; behavior = bridge->pci_regs_behavior;
} }
@ -357,7 +358,7 @@ int pci_bridge_emul_conf_read(struct pci_bridge_emul *bridge, int where,
ret = PCI_BRIDGE_EMUL_NOT_HANDLED; ret = PCI_BRIDGE_EMUL_NOT_HANDLED;
if (ret == PCI_BRIDGE_EMUL_NOT_HANDLED) if (ret == PCI_BRIDGE_EMUL_NOT_HANDLED)
*value = cfgspace[reg / 4]; *value = le32_to_cpu(cfgspace[reg / 4]);
/* /*
* Make sure we never return any reserved bit with a value * Make sure we never return any reserved bit with a value
@ -387,7 +388,7 @@ int pci_bridge_emul_conf_write(struct pci_bridge_emul *bridge, int where,
int mask, ret, old, new, shift; int mask, ret, old, new, shift;
void (*write_op)(struct pci_bridge_emul *bridge, int reg, void (*write_op)(struct pci_bridge_emul *bridge, int reg,
u32 old, u32 new, u32 mask); u32 old, u32 new, u32 mask);
u32 *cfgspace; __le32 *cfgspace;
const struct pci_bridge_reg_behavior *behavior; const struct pci_bridge_reg_behavior *behavior;
if (bridge->has_pcie && reg >= PCI_CAP_PCIE_END) if (bridge->has_pcie && reg >= PCI_CAP_PCIE_END)
@ -414,11 +415,11 @@ int pci_bridge_emul_conf_write(struct pci_bridge_emul *bridge, int where,
if (bridge->has_pcie && reg >= PCI_CAP_PCIE_START) { if (bridge->has_pcie && reg >= PCI_CAP_PCIE_START) {
reg -= PCI_CAP_PCIE_START; reg -= PCI_CAP_PCIE_START;
write_op = bridge->ops->write_pcie; write_op = bridge->ops->write_pcie;
cfgspace = (u32 *) &bridge->pcie_conf; cfgspace = (__le32 *) &bridge->pcie_conf;
behavior = bridge->pcie_cap_regs_behavior; behavior = bridge->pcie_cap_regs_behavior;
} else { } else {
write_op = bridge->ops->write_base; write_op = bridge->ops->write_base;
cfgspace = (u32 *) &bridge->conf; cfgspace = (__le32 *) &bridge->conf;
behavior = bridge->pci_regs_behavior; behavior = bridge->pci_regs_behavior;
} }
@ -431,7 +432,7 @@ int pci_bridge_emul_conf_write(struct pci_bridge_emul *bridge, int where,
/* Clear the W1C bits */ /* Clear the W1C bits */
new &= ~((value << shift) & (behavior[reg / 4].w1c & mask)); new &= ~((value << shift) & (behavior[reg / 4].w1c & mask));
cfgspace[reg / 4] = new; cfgspace[reg / 4] = cpu_to_le32(new);
if (write_op) if (write_op)
write_op(bridge, reg, old, new, mask); write_op(bridge, reg, old, new, mask);

View File

@ -6,65 +6,65 @@
/* PCI configuration space of a PCI-to-PCI bridge. */ /* PCI configuration space of a PCI-to-PCI bridge. */
struct pci_bridge_emul_conf { struct pci_bridge_emul_conf {
u16 vendor; __le16 vendor;
u16 device; __le16 device;
u16 command; __le16 command;
u16 status; __le16 status;
u32 class_revision; __le32 class_revision;
u8 cache_line_size; u8 cache_line_size;
u8 latency_timer; u8 latency_timer;
u8 header_type; u8 header_type;
u8 bist; u8 bist;
u32 bar[2]; __le32 bar[2];
u8 primary_bus; u8 primary_bus;
u8 secondary_bus; u8 secondary_bus;
u8 subordinate_bus; u8 subordinate_bus;
u8 secondary_latency_timer; u8 secondary_latency_timer;
u8 iobase; u8 iobase;
u8 iolimit; u8 iolimit;
u16 secondary_status; __le16 secondary_status;
u16 membase; __le16 membase;
u16 memlimit; __le16 memlimit;
u16 pref_mem_base; __le16 pref_mem_base;
u16 pref_mem_limit; __le16 pref_mem_limit;
u32 prefbaseupper; __le32 prefbaseupper;
u32 preflimitupper; __le32 preflimitupper;
u16 iobaseupper; __le16 iobaseupper;
u16 iolimitupper; __le16 iolimitupper;
u8 capabilities_pointer; u8 capabilities_pointer;
u8 reserve[3]; u8 reserve[3];
u32 romaddr; __le32 romaddr;
u8 intline; u8 intline;
u8 intpin; u8 intpin;
u16 bridgectrl; __le16 bridgectrl;
}; };
/* PCI configuration space of the PCIe capabilities */ /* PCI configuration space of the PCIe capabilities */
struct pci_bridge_emul_pcie_conf { struct pci_bridge_emul_pcie_conf {
u8 cap_id; u8 cap_id;
u8 next; u8 next;
u16 cap; __le16 cap;
u32 devcap; __le32 devcap;
u16 devctl; __le16 devctl;
u16 devsta; __le16 devsta;
u32 lnkcap; __le32 lnkcap;
u16 lnkctl; __le16 lnkctl;
u16 lnksta; __le16 lnksta;
u32 slotcap; __le32 slotcap;
u16 slotctl; __le16 slotctl;
u16 slotsta; __le16 slotsta;
u16 rootctl; __le16 rootctl;
u16 rsvd; __le16 rsvd;
u32 rootsta; __le32 rootsta;
u32 devcap2; __le32 devcap2;
u16 devctl2; __le16 devctl2;
u16 devsta2; __le16 devsta2;
u32 lnkcap2; __le32 lnkcap2;
u16 lnkctl2; __le16 lnkctl2;
u16 lnksta2; __le16 lnksta2;
u32 slotcap2; __le32 slotcap2;
u16 slotctl2; __le16 slotctl2;
u16 slotsta2; __le16 slotsta2;
}; };
struct pci_bridge_emul; struct pci_bridge_emul;