diff options
-rw-r--r-- | drivers/net/wireless/b43/b43.h | 10 | ||||
-rw-r--r-- | drivers/net/wireless/b43/dma.c | 82 | ||||
-rw-r--r-- | drivers/net/wireless/b43/main.c | 42 |
3 files changed, 92 insertions, 42 deletions
diff --git a/drivers/net/wireless/b43/b43.h b/drivers/net/wireless/b43/b43.h index c8295b35999a..c7eea30aa949 100644 --- a/drivers/net/wireless/b43/b43.h +++ b/drivers/net/wireless/b43/b43.h | |||
@@ -170,14 +170,17 @@ enum { | |||
170 | #define B43_SHM_SH_SLOTT 0x0010 /* Slot time */ | 170 | #define B43_SHM_SH_SLOTT 0x0010 /* Slot time */ |
171 | #define B43_SHM_SH_DTIMPER 0x0012 /* DTIM period */ | 171 | #define B43_SHM_SH_DTIMPER 0x0012 /* DTIM period */ |
172 | #define B43_SHM_SH_NOSLPZNATDTIM 0x004C /* NOSLPZNAT DTIM */ | 172 | #define B43_SHM_SH_NOSLPZNATDTIM 0x004C /* NOSLPZNAT DTIM */ |
173 | /* SHM_SHARED beacon variables */ | 173 | /* SHM_SHARED beacon/AP variables */ |
174 | #define B43_SHM_SH_BTL0 0x0018 /* Beacon template length 0 */ | 174 | #define B43_SHM_SH_BTL0 0x0018 /* Beacon template length 0 */ |
175 | #define B43_SHM_SH_BTL1 0x001A /* Beacon template length 1 */ | 175 | #define B43_SHM_SH_BTL1 0x001A /* Beacon template length 1 */ |
176 | #define B43_SHM_SH_BTSFOFF 0x001C /* Beacon TSF offset */ | 176 | #define B43_SHM_SH_BTSFOFF 0x001C /* Beacon TSF offset */ |
177 | #define B43_SHM_SH_TIMBPOS 0x001E /* TIM B position in beacon */ | 177 | #define B43_SHM_SH_TIMBPOS 0x001E /* TIM B position in beacon */ |
178 | #define B43_SHM_SH_DTIMP 0x0012 /* DTIP period */ | ||
179 | #define B43_SHM_SH_MCASTCOOKIE 0x00A8 /* Last bcast/mcast frame ID */ | ||
178 | #define B43_SHM_SH_SFFBLIM 0x0044 /* Short frame fallback retry limit */ | 180 | #define B43_SHM_SH_SFFBLIM 0x0044 /* Short frame fallback retry limit */ |
179 | #define B43_SHM_SH_LFFBLIM 0x0046 /* Long frame fallback retry limit */ | 181 | #define B43_SHM_SH_LFFBLIM 0x0046 /* Long frame fallback retry limit */ |
180 | #define B43_SHM_SH_BEACPHYCTL 0x0054 /* Beacon PHY TX control word (see PHY TX control) */ | 182 | #define B43_SHM_SH_BEACPHYCTL 0x0054 /* Beacon PHY TX control word (see PHY TX control) */ |
183 | #define B43_SHM_SH_EXTNPHYCTL 0x00B0 /* Extended bytes for beacon PHY control (N) */ | ||
181 | /* SHM_SHARED ACK/CTS control */ | 184 | /* SHM_SHARED ACK/CTS control */ |
182 | #define B43_SHM_SH_ACKCTSPHYCTL 0x0022 /* ACK/CTS PHY control word (see PHY TX control) */ | 185 | #define B43_SHM_SH_ACKCTSPHYCTL 0x0022 /* ACK/CTS PHY control word (see PHY TX control) */ |
183 | /* SHM_SHARED probe response variables */ | 186 | /* SHM_SHARED probe response variables */ |
@@ -617,9 +620,12 @@ struct b43_wl { | |||
617 | /* Pointer to the ieee80211 hardware data structure */ | 620 | /* Pointer to the ieee80211 hardware data structure */ |
618 | struct ieee80211_hw *hw; | 621 | struct ieee80211_hw *hw; |
619 | 622 | ||
620 | spinlock_t irq_lock; | ||
621 | struct mutex mutex; | 623 | struct mutex mutex; |
624 | spinlock_t irq_lock; | ||
625 | /* Lock for LEDs access. */ | ||
622 | spinlock_t leds_lock; | 626 | spinlock_t leds_lock; |
627 | /* Lock for SHM access. */ | ||
628 | spinlock_t shm_lock; | ||
623 | 629 | ||
624 | /* We can only have one operating interface (802.11 core) | 630 | /* We can only have one operating interface (802.11 core) |
625 | * at a time. General information about this interface follows. | 631 | * at a time. General information about this interface follows. |
diff --git a/drivers/net/wireless/b43/dma.c b/drivers/net/wireless/b43/dma.c index 63217b1e312d..cf92853a2180 100644 --- a/drivers/net/wireless/b43/dma.c +++ b/drivers/net/wireless/b43/dma.c | |||
@@ -37,6 +37,8 @@ | |||
37 | #include <linux/pci.h> | 37 | #include <linux/pci.h> |
38 | #include <linux/delay.h> | 38 | #include <linux/delay.h> |
39 | #include <linux/skbuff.h> | 39 | #include <linux/skbuff.h> |
40 | #include <linux/etherdevice.h> | ||
41 | |||
40 | 42 | ||
41 | /* 32bit DMA ops. */ | 43 | /* 32bit DMA ops. */ |
42 | static | 44 | static |
@@ -315,26 +317,24 @@ static struct b43_dmaring *priority_to_txring(struct b43_wldev *dev, | |||
315 | case 3: | 317 | case 3: |
316 | ring = dev->dma.tx_ring0; | 318 | ring = dev->dma.tx_ring0; |
317 | break; | 319 | break; |
318 | case 4: | ||
319 | ring = dev->dma.tx_ring4; | ||
320 | break; | ||
321 | case 5: | ||
322 | ring = dev->dma.tx_ring5; | ||
323 | break; | ||
324 | } | 320 | } |
325 | 321 | ||
326 | return ring; | 322 | return ring; |
327 | } | 323 | } |
328 | 324 | ||
329 | /* Bcm43xx-ring to mac80211-queue mapping */ | 325 | /* b43-ring to mac80211-queue mapping */ |
330 | static inline int txring_to_priority(struct b43_dmaring *ring) | 326 | static inline int txring_to_priority(struct b43_dmaring *ring) |
331 | { | 327 | { |
332 | static const u8 idx_to_prio[] = { 3, 2, 1, 0, 4, 5, }; | 328 | static const u8 idx_to_prio[] = { 3, 2, 1, 0, }; |
329 | unsigned int index; | ||
333 | 330 | ||
334 | /*FIXME: have only one queue, for now */ | 331 | /*FIXME: have only one queue, for now */ |
335 | return 0; | 332 | return 0; |
336 | 333 | ||
337 | return idx_to_prio[ring->index]; | 334 | index = ring->index; |
335 | if (B43_WARN_ON(index >= ARRAY_SIZE(idx_to_prio))) | ||
336 | index = 0; | ||
337 | return idx_to_prio[index]; | ||
338 | } | 338 | } |
339 | 339 | ||
340 | u16 b43_dmacontroller_base(int dma64bit, int controller_idx) | 340 | u16 b43_dmacontroller_base(int dma64bit, int controller_idx) |
@@ -1043,26 +1043,30 @@ static u16 generate_cookie(struct b43_dmaring *ring, int slot) | |||
1043 | * in the lower 12 bits. | 1043 | * in the lower 12 bits. |
1044 | * Note that the cookie must never be 0, as this | 1044 | * Note that the cookie must never be 0, as this |
1045 | * is a special value used in RX path. | 1045 | * is a special value used in RX path. |
1046 | * It can also not be 0xFFFF because that is special | ||
1047 | * for multicast frames. | ||
1046 | */ | 1048 | */ |
1047 | switch (ring->index) { | 1049 | switch (ring->index) { |
1048 | case 0: | 1050 | case 0: |
1049 | cookie = 0xA000; | 1051 | cookie = 0x1000; |
1050 | break; | 1052 | break; |
1051 | case 1: | 1053 | case 1: |
1052 | cookie = 0xB000; | 1054 | cookie = 0x2000; |
1053 | break; | 1055 | break; |
1054 | case 2: | 1056 | case 2: |
1055 | cookie = 0xC000; | 1057 | cookie = 0x3000; |
1056 | break; | 1058 | break; |
1057 | case 3: | 1059 | case 3: |
1058 | cookie = 0xD000; | 1060 | cookie = 0x4000; |
1059 | break; | 1061 | break; |
1060 | case 4: | 1062 | case 4: |
1061 | cookie = 0xE000; | 1063 | cookie = 0x5000; |
1062 | break; | 1064 | break; |
1063 | case 5: | 1065 | case 5: |
1064 | cookie = 0xF000; | 1066 | cookie = 0x6000; |
1065 | break; | 1067 | break; |
1068 | default: | ||
1069 | B43_WARN_ON(1); | ||
1066 | } | 1070 | } |
1067 | B43_WARN_ON(slot & ~0x0FFF); | 1071 | B43_WARN_ON(slot & ~0x0FFF); |
1068 | cookie |= (u16) slot; | 1072 | cookie |= (u16) slot; |
@@ -1078,22 +1082,22 @@ struct b43_dmaring *parse_cookie(struct b43_wldev *dev, u16 cookie, int *slot) | |||
1078 | struct b43_dmaring *ring = NULL; | 1082 | struct b43_dmaring *ring = NULL; |
1079 | 1083 | ||
1080 | switch (cookie & 0xF000) { | 1084 | switch (cookie & 0xF000) { |
1081 | case 0xA000: | 1085 | case 0x1000: |
1082 | ring = dma->tx_ring0; | 1086 | ring = dma->tx_ring0; |
1083 | break; | 1087 | break; |
1084 | case 0xB000: | 1088 | case 0x2000: |
1085 | ring = dma->tx_ring1; | 1089 | ring = dma->tx_ring1; |
1086 | break; | 1090 | break; |
1087 | case 0xC000: | 1091 | case 0x3000: |
1088 | ring = dma->tx_ring2; | 1092 | ring = dma->tx_ring2; |
1089 | break; | 1093 | break; |
1090 | case 0xD000: | 1094 | case 0x4000: |
1091 | ring = dma->tx_ring3; | 1095 | ring = dma->tx_ring3; |
1092 | break; | 1096 | break; |
1093 | case 0xE000: | 1097 | case 0x5000: |
1094 | ring = dma->tx_ring4; | 1098 | ring = dma->tx_ring4; |
1095 | break; | 1099 | break; |
1096 | case 0xF000: | 1100 | case 0x6000: |
1097 | ring = dma->tx_ring5; | 1101 | ring = dma->tx_ring5; |
1098 | break; | 1102 | break; |
1099 | default: | 1103 | default: |
@@ -1117,6 +1121,7 @@ static int dma_tx_fragment(struct b43_dmaring *ring, | |||
1117 | struct b43_dmadesc_meta *meta; | 1121 | struct b43_dmadesc_meta *meta; |
1118 | struct b43_dmadesc_meta *meta_hdr; | 1122 | struct b43_dmadesc_meta *meta_hdr; |
1119 | struct sk_buff *bounce_skb; | 1123 | struct sk_buff *bounce_skb; |
1124 | u16 cookie; | ||
1120 | 1125 | ||
1121 | #define SLOTS_PER_PACKET 2 | 1126 | #define SLOTS_PER_PACKET 2 |
1122 | B43_WARN_ON(skb_shinfo(skb)->nr_frags); | 1127 | B43_WARN_ON(skb_shinfo(skb)->nr_frags); |
@@ -1127,9 +1132,9 @@ static int dma_tx_fragment(struct b43_dmaring *ring, | |||
1127 | memset(meta_hdr, 0, sizeof(*meta_hdr)); | 1132 | memset(meta_hdr, 0, sizeof(*meta_hdr)); |
1128 | 1133 | ||
1129 | header = &(ring->txhdr_cache[slot * sizeof(struct b43_txhdr_fw4)]); | 1134 | header = &(ring->txhdr_cache[slot * sizeof(struct b43_txhdr_fw4)]); |
1135 | cookie = generate_cookie(ring, slot); | ||
1130 | b43_generate_txhdr(ring->dev, header, | 1136 | b43_generate_txhdr(ring->dev, header, |
1131 | skb->data, skb->len, ctl, | 1137 | skb->data, skb->len, ctl, cookie); |
1132 | generate_cookie(ring, slot)); | ||
1133 | 1138 | ||
1134 | meta_hdr->dmaaddr = map_descbuffer(ring, (unsigned char *)header, | 1139 | meta_hdr->dmaaddr = map_descbuffer(ring, (unsigned char *)header, |
1135 | sizeof(struct b43_txhdr_fw4), 1); | 1140 | sizeof(struct b43_txhdr_fw4), 1); |
@@ -1169,14 +1174,20 @@ static int dma_tx_fragment(struct b43_dmaring *ring, | |||
1169 | 1174 | ||
1170 | ops->fill_descriptor(ring, desc, meta->dmaaddr, skb->len, 0, 1, 1); | 1175 | ops->fill_descriptor(ring, desc, meta->dmaaddr, skb->len, 0, 1, 1); |
1171 | 1176 | ||
1177 | if (ctl->flags & IEEE80211_TXCTL_SEND_AFTER_DTIM) { | ||
1178 | /* Tell the firmware about the cookie of the last | ||
1179 | * mcast frame, so it can clear the more-data bit in it. */ | ||
1180 | b43_shm_write16(ring->dev, B43_SHM_SHARED, | ||
1181 | B43_SHM_SH_MCASTCOOKIE, cookie); | ||
1182 | } | ||
1172 | /* Now transfer the whole frame. */ | 1183 | /* Now transfer the whole frame. */ |
1173 | wmb(); | 1184 | wmb(); |
1174 | ops->poke_tx(ring, next_slot(ring, slot)); | 1185 | ops->poke_tx(ring, next_slot(ring, slot)); |
1175 | return 0; | 1186 | return 0; |
1176 | 1187 | ||
1177 | out_free_bounce: | 1188 | out_free_bounce: |
1178 | dev_kfree_skb_any(skb); | 1189 | dev_kfree_skb_any(skb); |
1179 | out_unmap_hdr: | 1190 | out_unmap_hdr: |
1180 | unmap_descbuffer(ring, meta_hdr->dmaaddr, | 1191 | unmap_descbuffer(ring, meta_hdr->dmaaddr, |
1181 | sizeof(struct b43_txhdr_fw4), 1); | 1192 | sizeof(struct b43_txhdr_fw4), 1); |
1182 | return err; | 1193 | return err; |
@@ -1207,10 +1218,27 @@ int b43_dma_tx(struct b43_wldev *dev, | |||
1207 | struct sk_buff *skb, struct ieee80211_tx_control *ctl) | 1218 | struct sk_buff *skb, struct ieee80211_tx_control *ctl) |
1208 | { | 1219 | { |
1209 | struct b43_dmaring *ring; | 1220 | struct b43_dmaring *ring; |
1221 | struct ieee80211_hdr *hdr; | ||
1210 | int err = 0; | 1222 | int err = 0; |
1211 | unsigned long flags; | 1223 | unsigned long flags; |
1212 | 1224 | ||
1213 | ring = priority_to_txring(dev, ctl->queue); | 1225 | if (unlikely(skb->len < 2 + 2 + 6)) { |
1226 | /* Too short, this can't be a valid frame. */ | ||
1227 | return -EINVAL; | ||
1228 | } | ||
1229 | |||
1230 | hdr = (struct ieee80211_hdr *)skb->data; | ||
1231 | if (ctl->flags & IEEE80211_TXCTL_SEND_AFTER_DTIM) { | ||
1232 | /* The multicast ring will be sent after the DTIM */ | ||
1233 | ring = dev->dma.tx_ring4; | ||
1234 | /* Set the more-data bit. Ucode will clear it on | ||
1235 | * the last frame for us. */ | ||
1236 | hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_MOREDATA); | ||
1237 | } else { | ||
1238 | /* Decide by priority where to put this frame. */ | ||
1239 | ring = priority_to_txring(dev, ctl->queue); | ||
1240 | } | ||
1241 | |||
1214 | spin_lock_irqsave(&ring->lock, flags); | 1242 | spin_lock_irqsave(&ring->lock, flags); |
1215 | B43_WARN_ON(!ring->tx); | 1243 | B43_WARN_ON(!ring->tx); |
1216 | if (unlikely(free_slots(ring) < SLOTS_PER_PACKET)) { | 1244 | if (unlikely(free_slots(ring) < SLOTS_PER_PACKET)) { |
@@ -1238,7 +1266,7 @@ int b43_dma_tx(struct b43_wldev *dev, | |||
1238 | b43dbg(dev->wl, "Stopped TX ring %d\n", ring->index); | 1266 | b43dbg(dev->wl, "Stopped TX ring %d\n", ring->index); |
1239 | } | 1267 | } |
1240 | } | 1268 | } |
1241 | out_unlock: | 1269 | out_unlock: |
1242 | spin_unlock_irqrestore(&ring->lock, flags); | 1270 | spin_unlock_irqrestore(&ring->lock, flags); |
1243 | 1271 | ||
1244 | return err; | 1272 | return err; |
diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index 84b291144c37..345ac3862e11 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c | |||
@@ -252,13 +252,12 @@ static void b43_ram_write(struct b43_wldev *dev, u16 offset, u32 val) | |||
252 | b43_write32(dev, B43_MMIO_RAM_DATA, val); | 252 | b43_write32(dev, B43_MMIO_RAM_DATA, val); |
253 | } | 253 | } |
254 | 254 | ||
255 | static inline | 255 | static inline void b43_shm_control_word(struct b43_wldev *dev, |
256 | void b43_shm_control_word(struct b43_wldev *dev, u16 routing, u16 offset) | 256 | u16 routing, u16 offset) |
257 | { | 257 | { |
258 | u32 control; | 258 | u32 control; |
259 | 259 | ||
260 | /* "offset" is the WORD offset. */ | 260 | /* "offset" is the WORD offset. */ |
261 | |||
262 | control = routing; | 261 | control = routing; |
263 | control <<= 16; | 262 | control <<= 16; |
264 | control |= offset; | 263 | control |= offset; |
@@ -267,8 +266,11 @@ static inline | |||
267 | 266 | ||
268 | u32 b43_shm_read32(struct b43_wldev *dev, u16 routing, u16 offset) | 267 | u32 b43_shm_read32(struct b43_wldev *dev, u16 routing, u16 offset) |
269 | { | 268 | { |
269 | struct b43_wl *wl = dev->wl; | ||
270 | unsigned long flags; | ||
270 | u32 ret; | 271 | u32 ret; |
271 | 272 | ||
273 | spin_lock_irqsave(&wl->shm_lock, flags); | ||
272 | if (routing == B43_SHM_SHARED) { | 274 | if (routing == B43_SHM_SHARED) { |
273 | B43_WARN_ON(offset & 0x0001); | 275 | B43_WARN_ON(offset & 0x0001); |
274 | if (offset & 0x0003) { | 276 | if (offset & 0x0003) { |
@@ -279,20 +281,25 @@ u32 b43_shm_read32(struct b43_wldev *dev, u16 routing, u16 offset) | |||
279 | b43_shm_control_word(dev, routing, (offset >> 2) + 1); | 281 | b43_shm_control_word(dev, routing, (offset >> 2) + 1); |
280 | ret |= b43_read16(dev, B43_MMIO_SHM_DATA); | 282 | ret |= b43_read16(dev, B43_MMIO_SHM_DATA); |
281 | 283 | ||
282 | return ret; | 284 | goto out; |
283 | } | 285 | } |
284 | offset >>= 2; | 286 | offset >>= 2; |
285 | } | 287 | } |
286 | b43_shm_control_word(dev, routing, offset); | 288 | b43_shm_control_word(dev, routing, offset); |
287 | ret = b43_read32(dev, B43_MMIO_SHM_DATA); | 289 | ret = b43_read32(dev, B43_MMIO_SHM_DATA); |
290 | out: | ||
291 | spin_unlock_irqrestore(&wl->shm_lock, flags); | ||
288 | 292 | ||
289 | return ret; | 293 | return ret; |
290 | } | 294 | } |
291 | 295 | ||
292 | u16 b43_shm_read16(struct b43_wldev * dev, u16 routing, u16 offset) | 296 | u16 b43_shm_read16(struct b43_wldev * dev, u16 routing, u16 offset) |
293 | { | 297 | { |
298 | struct b43_wl *wl = dev->wl; | ||
299 | unsigned long flags; | ||
294 | u16 ret; | 300 | u16 ret; |
295 | 301 | ||
302 | spin_lock_irqsave(&wl->shm_lock, flags); | ||
296 | if (routing == B43_SHM_SHARED) { | 303 | if (routing == B43_SHM_SHARED) { |
297 | B43_WARN_ON(offset & 0x0001); | 304 | B43_WARN_ON(offset & 0x0001); |
298 | if (offset & 0x0003) { | 305 | if (offset & 0x0003) { |
@@ -300,55 +307,63 @@ u16 b43_shm_read16(struct b43_wldev * dev, u16 routing, u16 offset) | |||
300 | b43_shm_control_word(dev, routing, offset >> 2); | 307 | b43_shm_control_word(dev, routing, offset >> 2); |
301 | ret = b43_read16(dev, B43_MMIO_SHM_DATA_UNALIGNED); | 308 | ret = b43_read16(dev, B43_MMIO_SHM_DATA_UNALIGNED); |
302 | 309 | ||
303 | return ret; | 310 | goto out; |
304 | } | 311 | } |
305 | offset >>= 2; | 312 | offset >>= 2; |
306 | } | 313 | } |
307 | b43_shm_control_word(dev, routing, offset); | 314 | b43_shm_control_word(dev, routing, offset); |
308 | ret = b43_read16(dev, B43_MMIO_SHM_DATA); | 315 | ret = b43_read16(dev, B43_MMIO_SHM_DATA); |
316 | out: | ||
317 | spin_unlock_irqrestore(&wl->shm_lock, flags); | ||
309 | 318 | ||
310 | return ret; | 319 | return ret; |
311 | } | 320 | } |
312 | 321 | ||
313 | void b43_shm_write32(struct b43_wldev *dev, u16 routing, u16 offset, u32 value) | 322 | void b43_shm_write32(struct b43_wldev *dev, u16 routing, u16 offset, u32 value) |
314 | { | 323 | { |
324 | struct b43_wl *wl = dev->wl; | ||
325 | unsigned long flags; | ||
326 | |||
327 | spin_lock_irqsave(&wl->shm_lock, flags); | ||
315 | if (routing == B43_SHM_SHARED) { | 328 | if (routing == B43_SHM_SHARED) { |
316 | B43_WARN_ON(offset & 0x0001); | 329 | B43_WARN_ON(offset & 0x0001); |
317 | if (offset & 0x0003) { | 330 | if (offset & 0x0003) { |
318 | /* Unaligned access */ | 331 | /* Unaligned access */ |
319 | b43_shm_control_word(dev, routing, offset >> 2); | 332 | b43_shm_control_word(dev, routing, offset >> 2); |
320 | mmiowb(); | ||
321 | b43_write16(dev, B43_MMIO_SHM_DATA_UNALIGNED, | 333 | b43_write16(dev, B43_MMIO_SHM_DATA_UNALIGNED, |
322 | (value >> 16) & 0xffff); | 334 | (value >> 16) & 0xffff); |
323 | mmiowb(); | ||
324 | b43_shm_control_word(dev, routing, (offset >> 2) + 1); | 335 | b43_shm_control_word(dev, routing, (offset >> 2) + 1); |
325 | mmiowb(); | ||
326 | b43_write16(dev, B43_MMIO_SHM_DATA, value & 0xffff); | 336 | b43_write16(dev, B43_MMIO_SHM_DATA, value & 0xffff); |
327 | return; | 337 | goto out; |
328 | } | 338 | } |
329 | offset >>= 2; | 339 | offset >>= 2; |
330 | } | 340 | } |
331 | b43_shm_control_word(dev, routing, offset); | 341 | b43_shm_control_word(dev, routing, offset); |
332 | mmiowb(); | ||
333 | b43_write32(dev, B43_MMIO_SHM_DATA, value); | 342 | b43_write32(dev, B43_MMIO_SHM_DATA, value); |
343 | out: | ||
344 | spin_unlock_irqrestore(&wl->shm_lock, flags); | ||
334 | } | 345 | } |
335 | 346 | ||
336 | void b43_shm_write16(struct b43_wldev *dev, u16 routing, u16 offset, u16 value) | 347 | void b43_shm_write16(struct b43_wldev *dev, u16 routing, u16 offset, u16 value) |
337 | { | 348 | { |
349 | struct b43_wl *wl = dev->wl; | ||
350 | unsigned long flags; | ||
351 | |||
352 | spin_lock_irqsave(&wl->shm_lock, flags); | ||
338 | if (routing == B43_SHM_SHARED) { | 353 | if (routing == B43_SHM_SHARED) { |
339 | B43_WARN_ON(offset & 0x0001); | 354 | B43_WARN_ON(offset & 0x0001); |
340 | if (offset & 0x0003) { | 355 | if (offset & 0x0003) { |
341 | /* Unaligned access */ | 356 | /* Unaligned access */ |
342 | b43_shm_control_word(dev, routing, offset >> 2); | 357 | b43_shm_control_word(dev, routing, offset >> 2); |
343 | mmiowb(); | ||
344 | b43_write16(dev, B43_MMIO_SHM_DATA_UNALIGNED, value); | 358 | b43_write16(dev, B43_MMIO_SHM_DATA_UNALIGNED, value); |
345 | return; | 359 | goto out; |
346 | } | 360 | } |
347 | offset >>= 2; | 361 | offset >>= 2; |
348 | } | 362 | } |
349 | b43_shm_control_word(dev, routing, offset); | 363 | b43_shm_control_word(dev, routing, offset); |
350 | mmiowb(); | ||
351 | b43_write16(dev, B43_MMIO_SHM_DATA, value); | 364 | b43_write16(dev, B43_MMIO_SHM_DATA, value); |
365 | out: | ||
366 | spin_unlock_irqrestore(&wl->shm_lock, flags); | ||
352 | } | 367 | } |
353 | 368 | ||
354 | /* Read HostFlags */ | 369 | /* Read HostFlags */ |
@@ -3931,6 +3946,7 @@ static int b43_wireless_init(struct ssb_device *dev) | |||
3931 | wl->hw = hw; | 3946 | wl->hw = hw; |
3932 | spin_lock_init(&wl->irq_lock); | 3947 | spin_lock_init(&wl->irq_lock); |
3933 | spin_lock_init(&wl->leds_lock); | 3948 | spin_lock_init(&wl->leds_lock); |
3949 | spin_lock_init(&wl->shm_lock); | ||
3934 | mutex_init(&wl->mutex); | 3950 | mutex_init(&wl->mutex); |
3935 | INIT_LIST_HEAD(&wl->devlist); | 3951 | INIT_LIST_HEAD(&wl->devlist); |
3936 | 3952 | ||