Commit db674ed4 authored by Sylvain Munaut's avatar Sylvain Munaut Committed by Linus Torvalds

[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: default avatarSylvain Munaut <tnt@246tNt.com>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent dbeb198d
......@@ -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();
#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;
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);
value = in_le32(hose->cfg_data);
if (len != 4) {
value >>= ((offset & 0x3) << 3);
value &= 0xffffffff >> (32 - (len << 3));
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();
#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;
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);
if (len != 4) {
value = in_le32(hose->cfg_data);
offset = (offset & 0x3) << 3;
mask = (0xffffffff >> (32 - (len << 3)));
mask <<= offset;
offset = (offset & 0x3) << 3;
mask = (0xffffffff >> (32 - (len << 3)));
mask <<= offset;
value &= ~mask;
val = value | ((val << offset) & mask);
}
value &= ~mask;
val = value | ((val << offset) & mask);
out_le32(hose->cfg_data, val);
}
out_le32(hose->cfg_data, val);
mb();
out_be32(hose->cfg_addr, 0);
mb();
return PCIBIOS_SUCCESSFUL;
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment