diff options
Diffstat (limited to 'drivers/net/wireless')
-rw-r--r-- | drivers/net/wireless/ath9k/ath9k.h | 33 | ||||
-rw-r--r-- | drivers/net/wireless/ath9k/hw.c | 22 | ||||
-rw-r--r-- | drivers/net/wireless/ath9k/hw.h | 4 | ||||
-rw-r--r-- | drivers/net/wireless/ath9k/main.c | 1 | ||||
-rw-r--r-- | drivers/net/wireless/zd1211rw/zd_mac.c | 8 |
5 files changed, 63 insertions, 5 deletions
diff --git a/drivers/net/wireless/ath9k/ath9k.h b/drivers/net/wireless/ath9k/ath9k.h index f0b105a11ae2..b64be8e9a690 100644 --- a/drivers/net/wireless/ath9k/ath9k.h +++ b/drivers/net/wireless/ath9k/ath9k.h | |||
@@ -579,6 +579,7 @@ struct ath_softc { | |||
579 | void __iomem *mem; | 579 | void __iomem *mem; |
580 | int irq; | 580 | int irq; |
581 | spinlock_t sc_resetlock; | 581 | spinlock_t sc_resetlock; |
582 | spinlock_t sc_serial_rw; | ||
582 | struct mutex mutex; | 583 | struct mutex mutex; |
583 | 584 | ||
584 | u8 curbssid[ETH_ALEN]; | 585 | u8 curbssid[ETH_ALEN]; |
@@ -724,4 +725,36 @@ void ath9k_wiphy_pause_all_forced(struct ath_softc *sc, | |||
724 | bool ath9k_wiphy_scanning(struct ath_softc *sc); | 725 | bool ath9k_wiphy_scanning(struct ath_softc *sc); |
725 | void ath9k_wiphy_work(struct work_struct *work); | 726 | void ath9k_wiphy_work(struct work_struct *work); |
726 | 727 | ||
728 | /* | ||
729 | * Read and write, they both share the same lock. We do this to serialize | ||
730 | * reads and writes on Atheros 802.11n PCI devices only. This is required | ||
731 | * as the FIFO on these devices can only accept sanely 2 requests. After | ||
732 | * that the device goes bananas. Serializing the reads/writes prevents this | ||
733 | * from happening. | ||
734 | */ | ||
735 | |||
736 | static inline void ath9k_iowrite32(struct ath_hw *ah, u32 reg_offset, u32 val) | ||
737 | { | ||
738 | if (ah->config.serialize_regmode == SER_REG_MODE_ON) { | ||
739 | unsigned long flags; | ||
740 | spin_lock_irqsave(&ah->ah_sc->sc_serial_rw, flags); | ||
741 | iowrite32(val, ah->ah_sc->mem + reg_offset); | ||
742 | spin_unlock_irqrestore(&ah->ah_sc->sc_serial_rw, flags); | ||
743 | } else | ||
744 | iowrite32(val, ah->ah_sc->mem + reg_offset); | ||
745 | } | ||
746 | |||
747 | static inline unsigned int ath9k_ioread32(struct ath_hw *ah, u32 reg_offset) | ||
748 | { | ||
749 | u32 val; | ||
750 | if (ah->config.serialize_regmode == SER_REG_MODE_ON) { | ||
751 | unsigned long flags; | ||
752 | spin_lock_irqsave(&ah->ah_sc->sc_serial_rw, flags); | ||
753 | val = ioread32(ah->ah_sc->mem + reg_offset); | ||
754 | spin_unlock_irqrestore(&ah->ah_sc->sc_serial_rw, flags); | ||
755 | } else | ||
756 | val = ioread32(ah->ah_sc->mem + reg_offset); | ||
757 | return val; | ||
758 | } | ||
759 | |||
727 | #endif /* ATH9K_H */ | 760 | #endif /* ATH9K_H */ |
diff --git a/drivers/net/wireless/ath9k/hw.c b/drivers/net/wireless/ath9k/hw.c index eb750a503999..60e55d8c510b 100644 --- a/drivers/net/wireless/ath9k/hw.c +++ b/drivers/net/wireless/ath9k/hw.c | |||
@@ -391,6 +391,25 @@ static void ath9k_hw_set_defaults(struct ath_hw *ah) | |||
391 | } | 391 | } |
392 | 392 | ||
393 | ah->config.intr_mitigation = 1; | 393 | ah->config.intr_mitigation = 1; |
394 | |||
395 | /* | ||
396 | * We need this for PCI devices only (Cardbus, PCI, miniPCI) | ||
397 | * _and_ if on non-uniprocessor systems (Multiprocessor/HT). | ||
398 | * This means we use it for all AR5416 devices, and the few | ||
399 | * minor PCI AR9280 devices out there. | ||
400 | * | ||
401 | * Serialization is required because these devices do not handle | ||
402 | * well the case of two concurrent reads/writes due to the latency | ||
403 | * involved. During one read/write another read/write can be issued | ||
404 | * on another CPU while the previous read/write may still be working | ||
405 | * on our hardware, if we hit this case the hardware poops in a loop. | ||
406 | * We prevent this by serializing reads and writes. | ||
407 | * | ||
408 | * This issue is not present on PCI-Express devices or pre-AR5416 | ||
409 | * devices (legacy, 802.11abg). | ||
410 | */ | ||
411 | if (num_possible_cpus() > 1) | ||
412 | ah->config.serialize_regmode = SER_REG_MODE_AUTO; | ||
394 | } | 413 | } |
395 | 414 | ||
396 | static struct ath_hw *ath9k_hw_newstate(u16 devid, struct ath_softc *sc, | 415 | static struct ath_hw *ath9k_hw_newstate(u16 devid, struct ath_softc *sc, |
@@ -610,7 +629,8 @@ static struct ath_hw *ath9k_hw_do_attach(u16 devid, struct ath_softc *sc, | |||
610 | } | 629 | } |
611 | 630 | ||
612 | if (ah->config.serialize_regmode == SER_REG_MODE_AUTO) { | 631 | if (ah->config.serialize_regmode == SER_REG_MODE_AUTO) { |
613 | if (ah->hw_version.macVersion == AR_SREV_VERSION_5416_PCI) { | 632 | if (ah->hw_version.macVersion == AR_SREV_VERSION_5416_PCI || |
633 | (AR_SREV_9280(ah) && !ah->is_pciexpress)) { | ||
614 | ah->config.serialize_regmode = | 634 | ah->config.serialize_regmode = |
615 | SER_REG_MODE_ON; | 635 | SER_REG_MODE_ON; |
616 | } else { | 636 | } else { |
diff --git a/drivers/net/wireless/ath9k/hw.h b/drivers/net/wireless/ath9k/hw.h index 89936a038da3..dc681f011fdf 100644 --- a/drivers/net/wireless/ath9k/hw.h +++ b/drivers/net/wireless/ath9k/hw.h | |||
@@ -42,8 +42,8 @@ | |||
42 | #define AR5416_MAGIC 0x19641014 | 42 | #define AR5416_MAGIC 0x19641014 |
43 | 43 | ||
44 | /* Register read/write primitives */ | 44 | /* Register read/write primitives */ |
45 | #define REG_WRITE(_ah, _reg, _val) iowrite32(_val, _ah->ah_sc->mem + _reg) | 45 | #define REG_WRITE(_ah, _reg, _val) ath9k_iowrite32((_ah), (_reg), (_val)) |
46 | #define REG_READ(_ah, _reg) ioread32(_ah->ah_sc->mem + _reg) | 46 | #define REG_READ(_ah, _reg) ath9k_ioread32((_ah), (_reg)) |
47 | 47 | ||
48 | #define SM(_v, _f) (((_v) << _f##_S) & _f) | 48 | #define SM(_v, _f) (((_v) << _f##_S) & _f) |
49 | #define MS(_v, _f) (((_v) & _f) >> _f##_S) | 49 | #define MS(_v, _f) (((_v) & _f) >> _f##_S) |
diff --git a/drivers/net/wireless/ath9k/main.c b/drivers/net/wireless/ath9k/main.c index f473fee72a2e..a9715f5b0af6 100644 --- a/drivers/net/wireless/ath9k/main.c +++ b/drivers/net/wireless/ath9k/main.c | |||
@@ -1370,6 +1370,7 @@ static int ath_init(u16 devid, struct ath_softc *sc) | |||
1370 | 1370 | ||
1371 | spin_lock_init(&sc->wiphy_lock); | 1371 | spin_lock_init(&sc->wiphy_lock); |
1372 | spin_lock_init(&sc->sc_resetlock); | 1372 | spin_lock_init(&sc->sc_resetlock); |
1373 | spin_lock_init(&sc->sc_serial_rw); | ||
1373 | mutex_init(&sc->mutex); | 1374 | mutex_init(&sc->mutex); |
1374 | tasklet_init(&sc->intr_tq, ath9k_tasklet, (unsigned long)sc); | 1375 | tasklet_init(&sc->intr_tq, ath9k_tasklet, (unsigned long)sc); |
1375 | tasklet_init(&sc->bcon_tasklet, ath_beacon_tasklet, | 1376 | tasklet_init(&sc->bcon_tasklet, ath_beacon_tasklet, |
diff --git a/drivers/net/wireless/zd1211rw/zd_mac.c b/drivers/net/wireless/zd1211rw/zd_mac.c index 0b01ff036aac..c3a51266de20 100644 --- a/drivers/net/wireless/zd1211rw/zd_mac.c +++ b/drivers/net/wireless/zd1211rw/zd_mac.c | |||
@@ -575,13 +575,17 @@ static int zd_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb) | |||
575 | 575 | ||
576 | r = fill_ctrlset(mac, skb); | 576 | r = fill_ctrlset(mac, skb); |
577 | if (r) | 577 | if (r) |
578 | return r; | 578 | goto fail; |
579 | 579 | ||
580 | info->rate_driver_data[0] = hw; | 580 | info->rate_driver_data[0] = hw; |
581 | 581 | ||
582 | r = zd_usb_tx(&mac->chip.usb, skb); | 582 | r = zd_usb_tx(&mac->chip.usb, skb); |
583 | if (r) | 583 | if (r) |
584 | return r; | 584 | goto fail; |
585 | return 0; | ||
586 | |||
587 | fail: | ||
588 | dev_kfree_skb(skb); | ||
585 | return 0; | 589 | return 0; |
586 | } | 590 | } |
587 | 591 | ||