[PATCH] ppc32: Fix MPC52xx configuration space access
This patch takes care of an errata of the MPC5200 by avoiding 32 bits access in type 1 configuration accesses. All others accesses are still 32 bits wide. It also adds some mb() since the simple out_be(...) are not sufficient in this case. Signed-off-by: Sylvain Munaut <tnt@246tNt.com> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
This commit is contained in:
parent
dbeb198d93
commit
db674ed450
arch/ppc/syslib
|
@ -24,6 +24,12 @@
|
|||
#include <asm/machdep.h>
|
||||
|
||||
|
||||
/* This macro is defined to activate the workaround for the bug
|
||||
435 of the MPC5200 (L25R). With it activated, we don't do any
|
||||
32 bits configuration access during type-1 cycles */
|
||||
#define MPC5200_BUG_435_WORKAROUND
|
||||
|
||||
|
||||
static int
|
||||
mpc52xx_pci_read_config(struct pci_bus *bus, unsigned int devfn,
|
||||
int offset, int len, u32 *val)
|
||||
|
@ -40,17 +46,39 @@ mpc52xx_pci_read_config(struct pci_bus *bus, unsigned int devfn,
|
|||
((bus->number - hose->bus_offset) << 16) |
|
||||
(devfn << 8) |
|
||||
(offset & 0xfc));
|
||||
mb();
|
||||
|
||||
value = in_le32(hose->cfg_data);
|
||||
#ifdef MPC5200_BUG_435_WORKAROUND
|
||||
if (bus->number != hose->bus_offset) {
|
||||
switch (len) {
|
||||
case 1:
|
||||
value = in_8(((u8 __iomem *)hose->cfg_data) + (offset & 3));
|
||||
break;
|
||||
case 2:
|
||||
value = in_le16(((u16 __iomem *)hose->cfg_data) + ((offset>>1) & 1));
|
||||
break;
|
||||
|
||||
if (len != 4) {
|
||||
value >>= ((offset & 0x3) << 3);
|
||||
value &= 0xffffffff >> (32 - (len << 3));
|
||||
default:
|
||||
value = in_le16((u16 __iomem *)hose->cfg_data) |
|
||||
(in_le16(((u16 __iomem *)hose->cfg_data) + 1) << 16);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
value = in_le32(hose->cfg_data);
|
||||
|
||||
if (len != 4) {
|
||||
value >>= ((offset & 0x3) << 3);
|
||||
value &= 0xffffffff >> (32 - (len << 3));
|
||||
}
|
||||
}
|
||||
|
||||
*val = value;
|
||||
|
||||
out_be32(hose->cfg_addr, 0);
|
||||
mb();
|
||||
|
||||
return PCIBIOS_SUCCESSFUL;
|
||||
}
|
||||
|
@ -71,21 +99,48 @@ mpc52xx_pci_write_config(struct pci_bus *bus, unsigned int devfn,
|
|||
((bus->number - hose->bus_offset) << 16) |
|
||||
(devfn << 8) |
|
||||
(offset & 0xfc));
|
||||
mb();
|
||||
|
||||
if (len != 4) {
|
||||
value = in_le32(hose->cfg_data);
|
||||
#ifdef MPC5200_BUG_435_WORKAROUND
|
||||
if (bus->number != hose->bus_offset) {
|
||||
switch (len) {
|
||||
case 1:
|
||||
out_8(((u8 __iomem *)hose->cfg_data) +
|
||||
(offset & 3), val);
|
||||
break;
|
||||
case 2:
|
||||
out_le16(((u16 __iomem *)hose->cfg_data) +
|
||||
((offset>>1) & 1), val);
|
||||
break;
|
||||
|
||||
offset = (offset & 0x3) << 3;
|
||||
mask = (0xffffffff >> (32 - (len << 3)));
|
||||
mask <<= offset;
|
||||
|
||||
value &= ~mask;
|
||||
val = value | ((val << offset) & mask);
|
||||
default:
|
||||
out_le16((u16 __iomem *)hose->cfg_data,
|
||||
(u16)val);
|
||||
out_le16(((u16 __iomem *)hose->cfg_data) + 1,
|
||||
(u16)(val>>16));
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
if (len != 4) {
|
||||
value = in_le32(hose->cfg_data);
|
||||
|
||||
out_le32(hose->cfg_data, val);
|
||||
offset = (offset & 0x3) << 3;
|
||||
mask = (0xffffffff >> (32 - (len << 3)));
|
||||
mask <<= offset;
|
||||
|
||||
value &= ~mask;
|
||||
val = value | ((val << offset) & mask);
|
||||
}
|
||||
|
||||
out_le32(hose->cfg_data, val);
|
||||
}
|
||||
mb();
|
||||
|
||||
out_be32(hose->cfg_addr, 0);
|
||||
mb();
|
||||
|
||||
return PCIBIOS_SUCCESSFUL;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue