[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
|
@ -24,6 +24,12 @@
|
||||||
#include <asm/machdep.h>
|
#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
|
static int
|
||||||
mpc52xx_pci_read_config(struct pci_bus *bus, unsigned int devfn,
|
mpc52xx_pci_read_config(struct pci_bus *bus, unsigned int devfn,
|
||||||
int offset, int len, u32 *val)
|
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) |
|
((bus->number - hose->bus_offset) << 16) |
|
||||||
(devfn << 8) |
|
(devfn << 8) |
|
||||||
(offset & 0xfc));
|
(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) {
|
default:
|
||||||
value >>= ((offset & 0x3) << 3);
|
value = in_le16((u16 __iomem *)hose->cfg_data) |
|
||||||
value &= 0xffffffff >> (32 - (len << 3));
|
(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;
|
*val = value;
|
||||||
|
|
||||||
out_be32(hose->cfg_addr, 0);
|
out_be32(hose->cfg_addr, 0);
|
||||||
|
mb();
|
||||||
|
|
||||||
return PCIBIOS_SUCCESSFUL;
|
return PCIBIOS_SUCCESSFUL;
|
||||||
}
|
}
|
||||||
|
@ -71,21 +99,48 @@ mpc52xx_pci_write_config(struct pci_bus *bus, unsigned int devfn,
|
||||||
((bus->number - hose->bus_offset) << 16) |
|
((bus->number - hose->bus_offset) << 16) |
|
||||||
(devfn << 8) |
|
(devfn << 8) |
|
||||||
(offset & 0xfc));
|
(offset & 0xfc));
|
||||||
|
mb();
|
||||||
|
|
||||||
if (len != 4) {
|
#ifdef MPC5200_BUG_435_WORKAROUND
|
||||||
value = in_le32(hose->cfg_data);
|
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;
|
default:
|
||||||
mask = (0xffffffff >> (32 - (len << 3)));
|
out_le16((u16 __iomem *)hose->cfg_data,
|
||||||
mask <<= offset;
|
(u16)val);
|
||||||
|
out_le16(((u16 __iomem *)hose->cfg_data) + 1,
|
||||||
value &= ~mask;
|
(u16)(val>>16));
|
||||||
val = value | ((val << offset) & mask);
|
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);
|
out_be32(hose->cfg_addr, 0);
|
||||||
|
mb();
|
||||||
|
|
||||||
return PCIBIOS_SUCCESSFUL;
|
return PCIBIOS_SUCCESSFUL;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue