mirror of
https://github.com/torvalds/linux.git
synced 2024-12-29 14:21:47 +00:00
PCI: pci-bridge-emul: Fix big-endian support
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>
This commit is contained in:
parent
e078723f9c
commit
e0d9d30b73
@ -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);
|
||||||
|
@ -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;
|
||||||
|
Loading…
Reference in New Issue
Block a user