From 6158425be398936af1fd04451f78ffad01529cb0 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Thu, 12 Mar 2009 18:18:49 -0400 Subject: ath9k: implement IO serialization All 802.11n PCI devices (Cardbus, PCI, mini-PCI) require serialization of IO when on non-uniprocessor systems. PCI express devices not not require this. This should fix our only last standing open ath9k kernel.org bugzilla bug report: http://bugzilla.kernel.org/show_bug.cgi?id=12110 A port is probably required to older kernels and I can work on that. Cc: stable@kernel.org Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/ath9k/ath9k.h | 4 ++-- drivers/net/wireless/ath9k/core.h | 33 +++++++++++++++++++++++++++++++++ drivers/net/wireless/ath9k/hw.c | 19 +++++++++++++++++++ drivers/net/wireless/ath9k/main.c | 1 + 4 files changed, 55 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath9k/ath9k.h b/drivers/net/wireless/ath9k/ath9k.h index d278135..6650f60 100644 --- a/drivers/net/wireless/ath9k/ath9k.h +++ b/drivers/net/wireless/ath9k/ath9k.h @@ -587,8 +587,8 @@ struct ath9k_country_entry { u8 iso[3]; }; -#define REG_WRITE(_ah, _reg, _val) iowrite32(_val, _ah->ah_sh + _reg) -#define REG_READ(_ah, _reg) ioread32(_ah->ah_sh + _reg) +#define REG_WRITE(_ah, _reg, _val) ath9k_iowrite32((_ah), (_reg), (_val)) +#define REG_READ(_ah, _reg) ath9k_ioread32((_ah), (_reg)) #define SM(_v, _f) (((_v) << _f##_S) & _f) #define MS(_v, _f) (((_v) & _f) >> _f##_S) diff --git a/drivers/net/wireless/ath9k/core.h b/drivers/net/wireless/ath9k/core.h index 4ca2aed..139566c 100644 --- a/drivers/net/wireless/ath9k/core.h +++ b/drivers/net/wireless/ath9k/core.h @@ -701,6 +701,7 @@ struct ath_softc { struct ath_hal *sc_ah; void __iomem *mem; spinlock_t sc_resetlock; + spinlock_t sc_serial_rw; struct mutex mutex; u8 sc_curbssid[ETH_ALEN]; @@ -751,4 +752,36 @@ int ath_get_hal_qnum(u16 queue, struct ath_softc *sc); int ath_get_mac80211_qnum(u32 queue, struct ath_softc *sc); int ath_cabq_update(struct ath_softc *); +/* + * Read and write, they both share the same lock. We do this to serialize + * reads and writes on Atheros 802.11n PCI devices only. This is required + * as the FIFO on these devices can only accept sanely 2 requests. After + * that the device goes bananas. Serializing the reads/writes prevents this + * from happening. + */ + +static inline void ath9k_iowrite32(struct ath_hal *ah, u32 reg_offset, u32 val) +{ + if (ah->ah_config.serialize_regmode == SER_REG_MODE_ON) { + unsigned long flags; + spin_lock_irqsave(&ah->ah_sc->sc_serial_rw, flags); + iowrite32(val, ah->ah_sc->mem + reg_offset); + spin_unlock_irqrestore(&ah->ah_sc->sc_serial_rw, flags); + } else + iowrite32(val, ah->ah_sc->mem + reg_offset); +} + +static inline unsigned int ath9k_ioread32(struct ath_hal *ah, u32 reg_offset) +{ + u32 val; + if (ah->ah_config.serialize_regmode == SER_REG_MODE_ON) { + unsigned long flags; + spin_lock_irqsave(&ah->ah_sc->sc_serial_rw, flags); + val = ioread32(ah->ah_sc->mem + reg_offset); + spin_unlock_irqrestore(&ah->ah_sc->sc_serial_rw, flags); + } else + val = ioread32(ah->ah_sc->mem + reg_offset); + return val; +} + #endif /* CORE_H */ diff --git a/drivers/net/wireless/ath9k/hw.c b/drivers/net/wireless/ath9k/hw.c index 34474ed..5c87043 100644 --- a/drivers/net/wireless/ath9k/hw.c +++ b/drivers/net/wireless/ath9k/hw.c @@ -437,6 +437,25 @@ static void ath9k_hw_set_defaults(struct ath_hal *ah) } ah->ah_config.intr_mitigation = 1; + + /* + * We need this for PCI devices only (Cardbus, PCI, miniPCI) + * _and_ if on non-uniprocessor systems (Multiprocessor/HT). + * This means we use it for all AR5416 devices, and the few + * minor PCI AR9280 devices out there. + * + * Serialization is required because these devices do not handle + * well the case of two concurrent reads/writes due to the latency + * involved. During one read/write another read/write can be issued + * on another CPU while the previous read/write may still be working + * on our hardware, if we hit this case the hardware poops in a loop. + * We prevent this by serializing reads and writes. + * + * This issue is not present on PCI-Express devices or pre-AR5416 + * devices (legacy, 802.11abg). + */ + if (num_possible_cpus() > 1) + ah->ah_config.serialize_regmode = SER_REG_MODE_AUTO; } static struct ath_hal_5416 *ath9k_hw_newstate(u16 devid, diff --git a/drivers/net/wireless/ath9k/main.c b/drivers/net/wireless/ath9k/main.c index 0e80990..3c04044 100644 --- a/drivers/net/wireless/ath9k/main.c +++ b/drivers/net/wireless/ath9k/main.c @@ -1336,6 +1336,7 @@ static int ath_init(u16 devid, struct ath_softc *sc) printk(KERN_ERR "Unable to create debugfs files\n"); spin_lock_init(&sc->sc_resetlock); + spin_lock_init(&sc->sc_serial_rw); mutex_init(&sc->mutex); tasklet_init(&sc->intr_tq, ath9k_tasklet, (unsigned long)sc); tasklet_init(&sc->bcon_tasklet, ath9k_beacon_tasklet, -- cgit v1.1 From 5ec905a8df3fa877566ba98298433fbfb3d688cc Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Thu, 12 Mar 2009 18:18:50 -0400 Subject: ath9k: AR9280 PCI devices must serialize IO as well Cc: stable@kernel.org Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/ath9k/hw.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath9k/hw.c b/drivers/net/wireless/ath9k/hw.c index 5c87043..c38a00b 100644 --- a/drivers/net/wireless/ath9k/hw.c +++ b/drivers/net/wireless/ath9k/hw.c @@ -687,7 +687,8 @@ static struct ath_hal *ath9k_hw_do_attach(u16 devid, struct ath_softc *sc, } if (ah->ah_config.serialize_regmode == SER_REG_MODE_AUTO) { - if (ah->ah_macVersion == AR_SREV_VERSION_5416_PCI) { + if (ah->ah_macVersion == AR_SREV_VERSION_5416_PCI || + (AR_SREV_9280(ah) && !ah->ah_isPciExpress)) { ah->ah_config.serialize_regmode = SER_REG_MODE_ON; } else { -- cgit v1.1 From 640c65eae673d2caf6e7bf61c1eb4e9513b88fda Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Mon, 16 Mar 2009 21:47:33 +0200 Subject: zd1211rw: Do not panic on device eject when associated zd_op_tx() must not return an arbitrary error value since that can leave mac80211 trying to retransmit the frame and with the extra data pushed into the beginning of the skb on every attempt, this will end up causing a kernel panic (skb_under_panic from skb_push call). This can happen, e.g., when ejecting the device when associated. Signed-off-by: Jouni Malinen Signed-off-by: John W. Linville --- drivers/net/wireless/zd1211rw/zd_mac.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/zd1211rw/zd_mac.c b/drivers/net/wireless/zd1211rw/zd_mac.c index a611ad8..847057d 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) r = fill_ctrlset(mac, skb); if (r) - return r; + goto fail; info->rate_driver_data[0] = hw; r = zd_usb_tx(&mac->chip.usb, skb); if (r) - return r; + goto fail; + return 0; + +fail: + dev_kfree_skb(skb); return 0; } -- cgit v1.1