diff options
author | Michael Buesch <mb@bu3sch.de> | 2007-12-22 16:01:36 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2008-01-28 18:09:16 -0500 |
commit | 993e1c780b323736a2cdc24564f35e80ce8d3337 (patch) | |
tree | 6dd8e11093bc3820351fd83bebfecc6f0ae33fa6 /drivers/ssb/pcmcia.c | |
parent | f3dd3fcc2c79b950801641075b33b86acc372d9b (diff) |
ssb: Fix PCMCIA lowlevel register access
This fixes lowlevel register access for PCMCIA based devices.
The patch also adds a temporary workaround for the device mac address.
It simply adds generation of a random address. The real SPROM extraction
will follow in another patch.
The temporary workaround will be removed then, but for now it's OK.
Signed-off-by: Michael Buesch <mb@bu3sch.de>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/ssb/pcmcia.c')
-rw-r--r-- | drivers/ssb/pcmcia.c | 71 |
1 files changed, 43 insertions, 28 deletions
diff --git a/drivers/ssb/pcmcia.c b/drivers/ssb/pcmcia.c index bb44a76b3eb5..46816cda8b98 100644 --- a/drivers/ssb/pcmcia.c +++ b/drivers/ssb/pcmcia.c | |||
@@ -94,7 +94,6 @@ int ssb_pcmcia_switch_core(struct ssb_bus *bus, | |||
94 | struct ssb_device *dev) | 94 | struct ssb_device *dev) |
95 | { | 95 | { |
96 | int err; | 96 | int err; |
97 | unsigned long flags; | ||
98 | 97 | ||
99 | #if SSB_VERBOSE_PCMCIACORESWITCH_DEBUG | 98 | #if SSB_VERBOSE_PCMCIACORESWITCH_DEBUG |
100 | ssb_printk(KERN_INFO PFX | 99 | ssb_printk(KERN_INFO PFX |
@@ -103,11 +102,9 @@ int ssb_pcmcia_switch_core(struct ssb_bus *bus, | |||
103 | dev->core_index); | 102 | dev->core_index); |
104 | #endif | 103 | #endif |
105 | 104 | ||
106 | spin_lock_irqsave(&bus->bar_lock, flags); | ||
107 | err = ssb_pcmcia_switch_coreidx(bus, dev->core_index); | 105 | err = ssb_pcmcia_switch_coreidx(bus, dev->core_index); |
108 | if (!err) | 106 | if (!err) |
109 | bus->mapped_device = dev; | 107 | bus->mapped_device = dev; |
110 | spin_unlock_irqrestore(&bus->bar_lock, flags); | ||
111 | 108 | ||
112 | return err; | 109 | return err; |
113 | } | 110 | } |
@@ -115,14 +112,12 @@ int ssb_pcmcia_switch_core(struct ssb_bus *bus, | |||
115 | int ssb_pcmcia_switch_segment(struct ssb_bus *bus, u8 seg) | 112 | int ssb_pcmcia_switch_segment(struct ssb_bus *bus, u8 seg) |
116 | { | 113 | { |
117 | int attempts = 0; | 114 | int attempts = 0; |
118 | unsigned long flags; | ||
119 | conf_reg_t reg; | 115 | conf_reg_t reg; |
120 | int res, err = 0; | 116 | int res; |
121 | 117 | ||
122 | SSB_WARN_ON((seg != 0) && (seg != 1)); | 118 | SSB_WARN_ON((seg != 0) && (seg != 1)); |
123 | reg.Offset = 0x34; | 119 | reg.Offset = 0x34; |
124 | reg.Function = 0; | 120 | reg.Function = 0; |
125 | spin_lock_irqsave(&bus->bar_lock, flags); | ||
126 | while (1) { | 121 | while (1) { |
127 | reg.Action = CS_WRITE; | 122 | reg.Action = CS_WRITE; |
128 | reg.Value = seg; | 123 | reg.Value = seg; |
@@ -143,13 +138,11 @@ int ssb_pcmcia_switch_segment(struct ssb_bus *bus, u8 seg) | |||
143 | udelay(10); | 138 | udelay(10); |
144 | } | 139 | } |
145 | bus->mapped_pcmcia_seg = seg; | 140 | bus->mapped_pcmcia_seg = seg; |
146 | out_unlock: | 141 | |
147 | spin_unlock_irqrestore(&bus->bar_lock, flags); | 142 | return 0; |
148 | return err; | ||
149 | error: | 143 | error: |
150 | ssb_printk(KERN_ERR PFX "Failed to switch pcmcia segment\n"); | 144 | ssb_printk(KERN_ERR PFX "Failed to switch pcmcia segment\n"); |
151 | err = -ENODEV; | 145 | return -ENODEV; |
152 | goto out_unlock; | ||
153 | } | 146 | } |
154 | 147 | ||
155 | static int select_core_and_segment(struct ssb_device *dev, | 148 | static int select_core_and_segment(struct ssb_device *dev, |
@@ -182,22 +175,33 @@ static int select_core_and_segment(struct ssb_device *dev, | |||
182 | static u16 ssb_pcmcia_read16(struct ssb_device *dev, u16 offset) | 175 | static u16 ssb_pcmcia_read16(struct ssb_device *dev, u16 offset) |
183 | { | 176 | { |
184 | struct ssb_bus *bus = dev->bus; | 177 | struct ssb_bus *bus = dev->bus; |
178 | unsigned long flags; | ||
179 | int err; | ||
180 | u16 value = 0xFFFF; | ||
185 | 181 | ||
186 | if (unlikely(select_core_and_segment(dev, &offset))) | 182 | spin_lock_irqsave(&bus->bar_lock, flags); |
187 | return 0xFFFF; | 183 | err = select_core_and_segment(dev, &offset); |
184 | if (likely(!err)) | ||
185 | value = readw(bus->mmio + offset); | ||
186 | spin_unlock_irqrestore(&bus->bar_lock, flags); | ||
188 | 187 | ||
189 | return readw(bus->mmio + offset); | 188 | return value; |
190 | } | 189 | } |
191 | 190 | ||
192 | static u32 ssb_pcmcia_read32(struct ssb_device *dev, u16 offset) | 191 | static u32 ssb_pcmcia_read32(struct ssb_device *dev, u16 offset) |
193 | { | 192 | { |
194 | struct ssb_bus *bus = dev->bus; | 193 | struct ssb_bus *bus = dev->bus; |
195 | u32 lo, hi; | 194 | unsigned long flags; |
195 | int err; | ||
196 | u32 lo = 0xFFFFFFFF, hi = 0xFFFFFFFF; | ||
196 | 197 | ||
197 | if (unlikely(select_core_and_segment(dev, &offset))) | 198 | spin_lock_irqsave(&bus->bar_lock, flags); |
198 | return 0xFFFFFFFF; | 199 | err = select_core_and_segment(dev, &offset); |
199 | lo = readw(bus->mmio + offset); | 200 | if (likely(!err)) { |
200 | hi = readw(bus->mmio + offset + 2); | 201 | lo = readw(bus->mmio + offset); |
202 | hi = readw(bus->mmio + offset + 2); | ||
203 | } | ||
204 | spin_unlock_irqrestore(&bus->bar_lock, flags); | ||
201 | 205 | ||
202 | return (lo | (hi << 16)); | 206 | return (lo | (hi << 16)); |
203 | } | 207 | } |
@@ -205,22 +209,31 @@ static u32 ssb_pcmcia_read32(struct ssb_device *dev, u16 offset) | |||
205 | static void ssb_pcmcia_write16(struct ssb_device *dev, u16 offset, u16 value) | 209 | static void ssb_pcmcia_write16(struct ssb_device *dev, u16 offset, u16 value) |
206 | { | 210 | { |
207 | struct ssb_bus *bus = dev->bus; | 211 | struct ssb_bus *bus = dev->bus; |
212 | unsigned long flags; | ||
213 | int err; | ||
208 | 214 | ||
209 | if (unlikely(select_core_and_segment(dev, &offset))) | 215 | spin_lock_irqsave(&bus->bar_lock, flags); |
210 | return; | 216 | err = select_core_and_segment(dev, &offset); |
211 | writew(value, bus->mmio + offset); | 217 | if (likely(!err)) |
218 | writew(value, bus->mmio + offset); | ||
219 | mmiowb(); | ||
220 | spin_unlock_irqrestore(&bus->bar_lock, flags); | ||
212 | } | 221 | } |
213 | 222 | ||
214 | static void ssb_pcmcia_write32(struct ssb_device *dev, u16 offset, u32 value) | 223 | static void ssb_pcmcia_write32(struct ssb_device *dev, u16 offset, u32 value) |
215 | { | 224 | { |
216 | struct ssb_bus *bus = dev->bus; | 225 | struct ssb_bus *bus = dev->bus; |
226 | unsigned long flags; | ||
227 | int err; | ||
217 | 228 | ||
218 | if (unlikely(select_core_and_segment(dev, &offset))) | 229 | spin_lock_irqsave(&bus->bar_lock, flags); |
219 | return; | 230 | err = select_core_and_segment(dev, &offset); |
220 | writeb((value & 0xFF000000) >> 24, bus->mmio + offset + 3); | 231 | if (likely(!err)) { |
221 | writeb((value & 0x00FF0000) >> 16, bus->mmio + offset + 2); | 232 | writew((value & 0x0000FFFF), bus->mmio + offset); |
222 | writeb((value & 0x0000FF00) >> 8, bus->mmio + offset + 1); | 233 | writew(((value & 0xFFFF0000) >> 16), bus->mmio + offset + 2); |
223 | writeb((value & 0x000000FF) >> 0, bus->mmio + offset + 0); | 234 | } |
235 | mmiowb(); | ||
236 | spin_unlock_irqrestore(&bus->bar_lock, flags); | ||
224 | } | 237 | } |
225 | 238 | ||
226 | /* Not "static", as it's used in main.c */ | 239 | /* Not "static", as it's used in main.c */ |
@@ -231,10 +244,12 @@ const struct ssb_bus_ops ssb_pcmcia_ops = { | |||
231 | .write32 = ssb_pcmcia_write32, | 244 | .write32 = ssb_pcmcia_write32, |
232 | }; | 245 | }; |
233 | 246 | ||
247 | #include <linux/etherdevice.h> | ||
234 | int ssb_pcmcia_get_invariants(struct ssb_bus *bus, | 248 | int ssb_pcmcia_get_invariants(struct ssb_bus *bus, |
235 | struct ssb_init_invariants *iv) | 249 | struct ssb_init_invariants *iv) |
236 | { | 250 | { |
237 | //TODO | 251 | //TODO |
252 | random_ether_addr(iv->sprom.il0mac); | ||
238 | return 0; | 253 | return 0; |
239 | } | 254 | } |
240 | 255 | ||