aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/ssb/pcmcia.c71
-rw-r--r--include/linux/ssb/ssb.h3
2 files changed, 45 insertions, 29 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,
115int ssb_pcmcia_switch_segment(struct ssb_bus *bus, u8 seg) 112int 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;
146out_unlock: 141
147 spin_unlock_irqrestore(&bus->bar_lock, flags); 142 return 0;
148 return err;
149error: 143error:
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
155static int select_core_and_segment(struct ssb_device *dev, 148static int select_core_and_segment(struct ssb_device *dev,
@@ -182,22 +175,33 @@ static int select_core_and_segment(struct ssb_device *dev,
182static u16 ssb_pcmcia_read16(struct ssb_device *dev, u16 offset) 175static 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
192static u32 ssb_pcmcia_read32(struct ssb_device *dev, u16 offset) 191static 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)
205static void ssb_pcmcia_write16(struct ssb_device *dev, u16 offset, u16 value) 209static 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
214static void ssb_pcmcia_write32(struct ssb_device *dev, u16 offset, u32 value) 223static 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>
234int ssb_pcmcia_get_invariants(struct ssb_bus *bus, 248int 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
diff --git a/include/linux/ssb/ssb.h b/include/linux/ssb/ssb.h
index 0eaa98424f0a..cacbae531945 100644
--- a/include/linux/ssb/ssb.h
+++ b/include/linux/ssb/ssb.h
@@ -231,7 +231,8 @@ struct ssb_bus {
231 struct ssb_device *mapped_device; 231 struct ssb_device *mapped_device;
232 /* Currently mapped PCMCIA segment. (bustype == SSB_BUSTYPE_PCMCIA only) */ 232 /* Currently mapped PCMCIA segment. (bustype == SSB_BUSTYPE_PCMCIA only) */
233 u8 mapped_pcmcia_seg; 233 u8 mapped_pcmcia_seg;
234 /* Lock for core and segment switching. */ 234 /* Lock for core and segment switching.
235 * On PCMCIA-host busses this is used to protect the whole MMIO access. */
235 spinlock_t bar_lock; 236 spinlock_t bar_lock;
236 237
237 /* The bus this backplane is running on. */ 238 /* The bus this backplane is running on. */