aboutsummaryrefslogtreecommitdiffstats
path: root/arch/ppc
diff options
context:
space:
mode:
authorSylvain Munaut <tnt@246tNt.com>2006-01-06 03:11:36 -0500
committerLinus Torvalds <torvalds@g5.osdl.org>2006-01-06 11:33:31 -0500
commitdb674ed450f113518285f410c93abecd93e71a2f (patch)
treea4262285a9cab5ff5da39ec3c9372d14ec7143e6 /arch/ppc
parentdbeb198d9366eb3d3ad64444ceecb5b1d5b5d7ef (diff)
[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>
Diffstat (limited to 'arch/ppc')
-rw-r--r--arch/ppc/syslib/mpc52xx_pci.c83
1 files changed, 69 insertions, 14 deletions
diff --git a/arch/ppc/syslib/mpc52xx_pci.c b/arch/ppc/syslib/mpc52xx_pci.c
index e6cb3e26615a..2c5e6ddaf2c5 100644
--- a/arch/ppc/syslib/mpc52xx_pci.c
+++ b/arch/ppc/syslib/mpc52xx_pci.c
@@ -24,6 +24,12 @@
24#include <asm/machdep.h> 24#include <asm/machdep.h>
25 25
26 26
27/* This macro is defined to activate the workaround for the bug
28 435 of the MPC5200 (L25R). With it activated, we don't do any
29 32 bits configuration access during type-1 cycles */
30#define MPC5200_BUG_435_WORKAROUND
31
32
27static int 33static int
28mpc52xx_pci_read_config(struct pci_bus *bus, unsigned int devfn, 34mpc52xx_pci_read_config(struct pci_bus *bus, unsigned int devfn,
29 int offset, int len, u32 *val) 35 int offset, int len, u32 *val)
@@ -40,17 +46,39 @@ mpc52xx_pci_read_config(struct pci_bus *bus, unsigned int devfn,
40 ((bus->number - hose->bus_offset) << 16) | 46 ((bus->number - hose->bus_offset) << 16) |
41 (devfn << 8) | 47 (devfn << 8) |
42 (offset & 0xfc)); 48 (offset & 0xfc));
49 mb();
50
51#ifdef MPC5200_BUG_435_WORKAROUND
52 if (bus->number != hose->bus_offset) {
53 switch (len) {
54 case 1:
55 value = in_8(((u8 __iomem *)hose->cfg_data) + (offset & 3));
56 break;
57 case 2:
58 value = in_le16(((u16 __iomem *)hose->cfg_data) + ((offset>>1) & 1));
59 break;
60
61 default:
62 value = in_le16((u16 __iomem *)hose->cfg_data) |
63 (in_le16(((u16 __iomem *)hose->cfg_data) + 1) << 16);
64 break;
65 }
66 }
67 else
68#endif
69 {
70 value = in_le32(hose->cfg_data);
43 71
44 value = in_le32(hose->cfg_data); 72 if (len != 4) {
45 73 value >>= ((offset & 0x3) << 3);
46 if (len != 4) { 74 value &= 0xffffffff >> (32 - (len << 3));
47 value >>= ((offset & 0x3) << 3); 75 }
48 value &= 0xffffffff >> (32 - (len << 3));
49 } 76 }
50 77
51 *val = value; 78 *val = value;
52 79
53 out_be32(hose->cfg_addr, 0); 80 out_be32(hose->cfg_addr, 0);
81 mb();
54 82
55 return PCIBIOS_SUCCESSFUL; 83 return PCIBIOS_SUCCESSFUL;
56} 84}
@@ -71,21 +99,48 @@ mpc52xx_pci_write_config(struct pci_bus *bus, unsigned int devfn,
71 ((bus->number - hose->bus_offset) << 16) | 99 ((bus->number - hose->bus_offset) << 16) |
72 (devfn << 8) | 100 (devfn << 8) |
73 (offset & 0xfc)); 101 (offset & 0xfc));
102 mb();
103
104#ifdef MPC5200_BUG_435_WORKAROUND
105 if (bus->number != hose->bus_offset) {
106 switch (len) {
107 case 1:
108 out_8(((u8 __iomem *)hose->cfg_data) +
109 (offset & 3), val);
110 break;
111 case 2:
112 out_le16(((u16 __iomem *)hose->cfg_data) +
113 ((offset>>1) & 1), val);
114 break;
115
116 default:
117 out_le16((u16 __iomem *)hose->cfg_data,
118 (u16)val);
119 out_le16(((u16 __iomem *)hose->cfg_data) + 1,
120 (u16)(val>>16));
121 break;
122 }
123 }
124 else
125#endif
126 {
127 if (len != 4) {
128 value = in_le32(hose->cfg_data);
74 129
75 if (len != 4) { 130 offset = (offset & 0x3) << 3;
76 value = in_le32(hose->cfg_data); 131 mask = (0xffffffff >> (32 - (len << 3)));
132 mask <<= offset;
77 133
78 offset = (offset & 0x3) << 3; 134 value &= ~mask;
79 mask = (0xffffffff >> (32 - (len << 3))); 135 val = value | ((val << offset) & mask);
80 mask <<= offset; 136 }
81 137
82 value &= ~mask; 138 out_le32(hose->cfg_data, val);
83 val = value | ((val << offset) & mask);
84 } 139 }
85 140 mb();
86 out_le32(hose->cfg_data, val);
87 141
88 out_be32(hose->cfg_addr, 0); 142 out_be32(hose->cfg_addr, 0);
143 mb();
89 144
90 return PCIBIOS_SUCCESSFUL; 145 return PCIBIOS_SUCCESSFUL;
91} 146}