|
@@ -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;
|
|
|
}
|