From 1e450285281bdf766272c181ecd43d4f2f0711ce Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Wed, 20 Oct 2010 16:07:03 -0700 Subject: [PATCH 01/12] ath9k: add locking for stopping RX ath9k locks for starting RX but not for stopping RX. We could potentially run into a situation where tried to stop RX but immediately started RX. This allows for races on the the RX engine deciding what buffer we last left off on and could potentially cause ath9k to DMA into already free'd memory or in the worst case at a later time to already given memory to other drivers. Fix this by locking stopping RX. This is part of a series that will help resolve the bug: https://bugzilla.kernel.org/show_bug.cgi?id=14624 For more details about this issue refer to: http://marc.info/?l=linux-wireless&m=128629803703756&w=2 Cc: stable@kernel.org Cc: Ben Greear Cc: Kyungwan Nam Signed-off-by: Luis R. Rodriguez Tested-by: Ben Greear Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/recv.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c index fe73fc50082a..e581b1f6c40c 100644 --- a/drivers/net/wireless/ath/ath9k/recv.c +++ b/drivers/net/wireless/ath/ath9k/recv.c @@ -306,10 +306,8 @@ static void ath_edma_start_recv(struct ath_softc *sc) static void ath_edma_stop_recv(struct ath_softc *sc) { - spin_lock_bh(&sc->rx.rxbuflock); ath_rx_remove_buffer(sc, ATH9K_RX_QUEUE_HP); ath_rx_remove_buffer(sc, ATH9K_RX_QUEUE_LP); - spin_unlock_bh(&sc->rx.rxbuflock); } int ath_rx_init(struct ath_softc *sc, int nbufs) @@ -518,6 +516,7 @@ bool ath_stoprecv(struct ath_softc *sc) struct ath_hw *ah = sc->sc_ah; bool stopped; + spin_lock_bh(&sc->rx.rxbuflock); ath9k_hw_stoppcurecv(ah); ath9k_hw_setrxfilter(ah, 0); stopped = ath9k_hw_stopdmarecv(ah); @@ -526,6 +525,7 @@ bool ath_stoprecv(struct ath_softc *sc) ath_edma_stop_recv(sc); else sc->rx.rxlink = NULL; + spin_unlock_bh(&sc->rx.rxbuflock); return stopped; } From 7583c550c3e635dcc61ab127c36ecefd59fb8dc8 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Wed, 20 Oct 2010 16:07:04 -0700 Subject: [PATCH 02/12] ath9k: add locking for starting the PCU on RX There was some locking for starting some parts of RX but not for starting the PCU. Include this otherwise we can content against stopping the PCU. This can potentially lead to races against different buffers on the PCU which can lead to to the DMA RX engine writing to buffers which are already freed. This is part of a series that will help resolve the bug: https://bugzilla.kernel.org/show_bug.cgi?id=14624 For more details about this issue refer to: http://marc.info/?l=linux-wireless&m=128629803703756&w=2 Cc: stable@kernel.org Cc: Ben Greear Cc: Kyungwan Nam Signed-off-by: Luis R. Rodriguez Tested-by: Ben Greear Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/recv.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c index e581b1f6c40c..b3c9baf855c4 100644 --- a/drivers/net/wireless/ath/ath9k/recv.c +++ b/drivers/net/wireless/ath/ath9k/recv.c @@ -297,11 +297,11 @@ static void ath_edma_start_recv(struct ath_softc *sc) ath_rx_addbuffer_edma(sc, ATH9K_RX_QUEUE_LP, sc->rx.rx_edma[ATH9K_RX_QUEUE_LP].rx_fifo_hwsize); - spin_unlock_bh(&sc->rx.rxbuflock); - ath_opmode_init(sc); ath9k_hw_startpcureceive(sc->sc_ah, (sc->sc_flags & SC_OP_OFFCHANNEL)); + + spin_unlock_bh(&sc->rx.rxbuflock); } static void ath_edma_stop_recv(struct ath_softc *sc) @@ -504,10 +504,11 @@ int ath_startrecv(struct ath_softc *sc) ath9k_hw_rxena(ah); start_recv: - spin_unlock_bh(&sc->rx.rxbuflock); ath_opmode_init(sc); ath9k_hw_startpcureceive(ah, (sc->sc_flags & SC_OP_OFFCHANNEL)); + spin_unlock_bh(&sc->rx.rxbuflock); + return 0; } From b79b33c4baf2532aac2c0924dce5a738099b888c Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Wed, 20 Oct 2010 16:07:05 -0700 Subject: [PATCH 03/12] ath9k: rename rxflushlock to pcu_lock The real way to lock RX is to contend on the PCU and reset, this will be fixed in the next patch but for now just do the renames so that the next patch which changes the locking order is crystal clear. This is part of a series that will help resolve the bug: https://bugzilla.kernel.org/show_bug.cgi?id=14624 For more details about this issue refer to: http://marc.info/?l=linux-wireless&m=128629803703756&w=2 Cc: stable@kernel.org Cc: Ben Greear Cc: Kyungwan Nam Signed-off-by: Luis R. Rodriguez Tested-by: Ben Greear Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ath9k.h | 2 +- drivers/net/wireless/ath/ath9k/main.c | 4 ++-- drivers/net/wireless/ath/ath9k/recv.c | 6 +++--- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index 973c919fdd27..9b8e7e3fcebd 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -310,7 +310,7 @@ struct ath_rx { u8 rxotherant; u32 *rxlink; unsigned int rxfilter; - spinlock_t rxflushlock; + spinlock_t pcu_lock; spinlock_t rxbuflock; struct list_head rxbuf; struct ath_descdma rxdma; diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index c6ec800d7a6b..47df22b14cf8 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -613,7 +613,7 @@ void ath9k_tasklet(unsigned long data) rxmask = (ATH9K_INT_RX | ATH9K_INT_RXEOL | ATH9K_INT_RXORN); if (status & rxmask) { - spin_lock_bh(&sc->rx.rxflushlock); + spin_lock_bh(&sc->rx.pcu_lock); /* Check for high priority Rx first */ if ((ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) && @@ -621,7 +621,7 @@ void ath9k_tasklet(unsigned long data) ath_rx_tasklet(sc, 0, true); ath_rx_tasklet(sc, 0, false); - spin_unlock_bh(&sc->rx.rxflushlock); + spin_unlock_bh(&sc->rx.pcu_lock); } if (status & ATH9K_INT_TX) { diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c index b3c9baf855c4..67fe1f8a6439 100644 --- a/drivers/net/wireless/ath/ath9k/recv.c +++ b/drivers/net/wireless/ath/ath9k/recv.c @@ -317,7 +317,7 @@ int ath_rx_init(struct ath_softc *sc, int nbufs) struct ath_buf *bf; int error = 0; - spin_lock_init(&sc->rx.rxflushlock); + spin_lock_init(&sc->rx.pcu_lock); sc->sc_flags &= ~SC_OP_RXFLUSH; spin_lock_init(&sc->rx.rxbuflock); @@ -533,13 +533,13 @@ bool ath_stoprecv(struct ath_softc *sc) void ath_flushrecv(struct ath_softc *sc) { - spin_lock_bh(&sc->rx.rxflushlock); + spin_lock_bh(&sc->rx.pcu_lock); sc->sc_flags |= SC_OP_RXFLUSH; if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) ath_rx_tasklet(sc, 1, true); ath_rx_tasklet(sc, 1, false); sc->sc_flags &= ~SC_OP_RXFLUSH; - spin_unlock_bh(&sc->rx.rxflushlock); + spin_unlock_bh(&sc->rx.pcu_lock); } static bool ath_beacon_dtim_pending_cab(struct sk_buff *skb) From 5e848f789d60000d39d9a5f26ab02dbdd963f6cd Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Wed, 20 Oct 2010 16:07:06 -0700 Subject: [PATCH 04/12] ath9k: lock reset and PCU start/stopping Apart from locking the start and stop PCU we need to ensure we also content starting and stopping the PCU between hardware resets. This is part of a series that will help resolve the bug: https://bugzilla.kernel.org/show_bug.cgi?id=14624 For more details about this issue refer to: http://marc.info/?l=linux-wireless&m=128629803703756&w=2 Cc: stable@kernel.org Cc: Ben Greear Cc: Kyungwan Nam Signed-off-by: Luis R. Rodriguez Tested-by: Ben Greear Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/main.c | 27 +++++++++++++++++++++++++++ drivers/net/wireless/ath/ath9k/recv.c | 2 -- 2 files changed, 27 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 47df22b14cf8..b52f1cf8a603 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -241,6 +241,9 @@ int ath_set_channel(struct ath_softc *sc, struct ieee80211_hw *hw, */ ath9k_hw_set_interrupts(ah, 0); ath_drain_all_txq(sc, false); + + spin_lock_bh(&sc->rx.pcu_lock); + stopped = ath_stoprecv(sc); /* XXX: do not flush receive queue here. We don't want @@ -268,6 +271,7 @@ int ath_set_channel(struct ath_softc *sc, struct ieee80211_hw *hw, "reset status %d\n", channel->center_freq, r); spin_unlock_bh(&sc->sc_resetlock); + spin_unlock_bh(&sc->rx.pcu_lock); goto ps_restore; } spin_unlock_bh(&sc->sc_resetlock); @@ -276,9 +280,12 @@ int ath_set_channel(struct ath_softc *sc, struct ieee80211_hw *hw, ath_print(common, ATH_DBG_FATAL, "Unable to restart recv logic\n"); r = -EIO; + spin_unlock_bh(&sc->rx.pcu_lock); goto ps_restore; } + spin_unlock_bh(&sc->rx.pcu_lock); + ath_update_txpow(sc); ath9k_hw_set_interrupts(ah, ah->imask); @@ -876,6 +883,7 @@ void ath_radio_enable(struct ath_softc *sc, struct ieee80211_hw *hw) if (!ah->curchan) ah->curchan = ath_get_curchannel(sc, sc->hw); + spin_lock_bh(&sc->rx.pcu_lock); spin_lock_bh(&sc->sc_resetlock); r = ath9k_hw_reset(ah, ah->curchan, ah->caldata, false); if (r) { @@ -890,8 +898,10 @@ void ath_radio_enable(struct ath_softc *sc, struct ieee80211_hw *hw) if (ath_startrecv(sc) != 0) { ath_print(common, ATH_DBG_FATAL, "Unable to restart recv logic\n"); + spin_unlock_bh(&sc->rx.pcu_lock); return; } + spin_unlock_bh(&sc->rx.pcu_lock); if (sc->sc_flags & SC_OP_BEACONS) ath_beacon_config(sc, NULL); /* restart beacons */ @@ -930,6 +940,9 @@ void ath_radio_disable(struct ath_softc *sc, struct ieee80211_hw *hw) ath9k_hw_set_interrupts(ah, 0); ath_drain_all_txq(sc, false); /* clear pending tx frames */ + + spin_lock_bh(&sc->rx.pcu_lock); + ath_stoprecv(sc); /* turn off frame recv */ ath_flushrecv(sc); /* flush recv queue */ @@ -947,6 +960,9 @@ void ath_radio_disable(struct ath_softc *sc, struct ieee80211_hw *hw) spin_unlock_bh(&sc->sc_resetlock); ath9k_hw_phy_disable(ah); + + spin_unlock_bh(&sc->rx.pcu_lock); + ath9k_hw_configpcipowersave(ah, 1, 1); ath9k_ps_restore(sc); ath9k_setpower(sc, ATH9K_PM_FULL_SLEEP); @@ -966,6 +982,9 @@ int ath_reset(struct ath_softc *sc, bool retry_tx) ath9k_hw_set_interrupts(ah, 0); ath_drain_all_txq(sc, retry_tx); + + spin_lock_bh(&sc->rx.pcu_lock); + ath_stoprecv(sc); ath_flushrecv(sc); @@ -980,6 +999,8 @@ int ath_reset(struct ath_softc *sc, bool retry_tx) ath_print(common, ATH_DBG_FATAL, "Unable to start recv logic\n"); + spin_unlock_bh(&sc->rx.pcu_lock); + /* * We may be doing a reset in response to a request * that changes the channel so update any state that @@ -1142,6 +1163,7 @@ static int ath9k_start(struct ieee80211_hw *hw) * be followed by initialization of the appropriate bits * and then setup of the interrupt mask. */ + spin_lock_bh(&sc->rx.pcu_lock); spin_lock_bh(&sc->sc_resetlock); r = ath9k_hw_reset(ah, init_channel, ah->caldata, false); if (r) { @@ -1150,6 +1172,7 @@ static int ath9k_start(struct ieee80211_hw *hw) "(freq %u MHz)\n", r, curchan->center_freq); spin_unlock_bh(&sc->sc_resetlock); + spin_unlock_bh(&sc->rx.pcu_lock); goto mutex_unlock; } spin_unlock_bh(&sc->sc_resetlock); @@ -1171,8 +1194,10 @@ static int ath9k_start(struct ieee80211_hw *hw) ath_print(common, ATH_DBG_FATAL, "Unable to start recv logic\n"); r = -EIO; + spin_unlock_bh(&sc->rx.pcu_lock); goto mutex_unlock; } + spin_unlock_bh(&sc->rx.pcu_lock); /* Setup our intr mask. */ ah->imask = ATH9K_INT_TX | ATH9K_INT_RXEOL | @@ -1371,12 +1396,14 @@ static void ath9k_stop(struct ieee80211_hw *hw) * before setting the invalid flag. */ ath9k_hw_set_interrupts(ah, 0); + spin_lock_bh(&sc->rx.pcu_lock); if (!(sc->sc_flags & SC_OP_INVALID)) { ath_drain_all_txq(sc, false); ath_stoprecv(sc); ath9k_hw_phy_disable(ah); } else sc->rx.rxlink = NULL; + spin_unlock_bh(&sc->rx.pcu_lock); /* disable HAL and put h/w to sleep */ ath9k_hw_disable(ah); diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c index 67fe1f8a6439..fddb0129bb57 100644 --- a/drivers/net/wireless/ath/ath9k/recv.c +++ b/drivers/net/wireless/ath/ath9k/recv.c @@ -533,13 +533,11 @@ bool ath_stoprecv(struct ath_softc *sc) void ath_flushrecv(struct ath_softc *sc) { - spin_lock_bh(&sc->rx.pcu_lock); sc->sc_flags |= SC_OP_RXFLUSH; if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) ath_rx_tasklet(sc, 1, true); ath_rx_tasklet(sc, 1, false); sc->sc_flags &= ~SC_OP_RXFLUSH; - spin_unlock_bh(&sc->rx.pcu_lock); } static bool ath_beacon_dtim_pending_cab(struct sk_buff *skb) From e609e2ea2cdb3448e7849703179cd792a28dcc55 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Wed, 27 Oct 2010 02:15:05 +0200 Subject: [PATCH 05/12] ath9k: fix tx aggregation flush on AR9003 Completing aggregate frames can lead to new buffers being pushed into the tid queues due to software retransmission. When the tx queues are being drained, all pending aggregates must be completed before the tid queues get drained, otherwise buffers might be leaked. Signed-off-by: Felix Fietkau Cc: stable@kernel.org Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/xmit.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c index 30ef2dfc1ed2..f2ade2402ce2 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c @@ -1089,15 +1089,6 @@ void ath_draintxq(struct ath_softc *sc, struct ath_txq *txq, bool retry_tx) txq->axq_tx_inprogress = false; spin_unlock_bh(&txq->axq_lock); - /* flush any pending frames if aggregation is enabled */ - if (sc->sc_flags & SC_OP_TXAGGR) { - if (!retry_tx) { - spin_lock_bh(&txq->axq_lock); - ath_txq_drain_pending_buffers(sc, txq); - spin_unlock_bh(&txq->axq_lock); - } - } - if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) { spin_lock_bh(&txq->axq_lock); while (!list_empty(&txq->txq_fifo_pending)) { @@ -1118,6 +1109,15 @@ void ath_draintxq(struct ath_softc *sc, struct ath_txq *txq, bool retry_tx) } spin_unlock_bh(&txq->axq_lock); } + + /* flush any pending frames if aggregation is enabled */ + if (sc->sc_flags & SC_OP_TXAGGR) { + if (!retry_tx) { + spin_lock_bh(&txq->axq_lock); + ath_txq_drain_pending_buffers(sc, txq); + spin_unlock_bh(&txq->axq_lock); + } + } } void ath_drain_all_txq(struct ath_softc *sc, bool retry_tx) From d654567dec75782d6fd9add4b7b9c50e0926d369 Mon Sep 17 00:00:00 2001 From: Rajkumar Manoharan Date: Wed, 27 Oct 2010 12:02:54 +0530 Subject: [PATCH 06/12] ath9k_htc: Set proper firmware offset for Netgear WNDA3200 Netgear WNDA3200 device uses ar7010 firmware but it is failed to set correct firmware offset on firmware download which causes device initialization failure. Cc: stable@kernel.org Signed-off-by: Rajkumar Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/hif_usb.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/hif_usb.c b/drivers/net/wireless/ath/ath9k/hif_usb.c index 728d904c74d7..6576f683dba0 100644 --- a/drivers/net/wireless/ath/ath9k/hif_usb.c +++ b/drivers/net/wireless/ath/ath9k/hif_usb.c @@ -801,10 +801,16 @@ static int ath9k_hif_usb_download_fw(struct hif_device_usb *hif_dev) } kfree(buf); - if ((hif_dev->device_id == 0x7010) || (hif_dev->device_id == 0x7015)) + switch (hif_dev->device_id) { + case 0x7010: + case 0x7015: + case 0x9018: firm_offset = AR7010_FIRMWARE_TEXT; - else + break; + default: firm_offset = AR9271_FIRMWARE_TEXT; + break; + } /* * Issue FW download complete command to firmware. From dc9f48ce7c7d345be31208def51572a8250a4a03 Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Wed, 27 Oct 2010 13:40:33 +0300 Subject: [PATCH 07/12] mac80211: Fix scan_ies_len to include DS Params Commit 651b52254fc061f02d965524e71de4333a009a5a added DS Parameter Set information into Probe Request frames that are transmitted on 2.4 GHz band, but it failed to increment local->scan_ies_len to cover this new information. This variable needs to be updated to match the maximum IE data length so that the extra buffer need gets reduced from the driver limit. Signed-off-by: Jouni Malinen Signed-off-by: John W. Linville --- net/mac80211/main.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/net/mac80211/main.c b/net/mac80211/main.c index 6b322fa681f5..107a0cbe52ac 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c @@ -677,10 +677,11 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) /* * Calculate scan IE length -- we need this to alloc * memory and to subtract from the driver limit. It - * includes the (extended) supported rates and HT + * includes the DS Params, (extended) supported rates, and HT * information -- SSID is the driver's responsibility. */ - local->scan_ies_len = 4 + max_bitrates; /* (ext) supp rates */ + local->scan_ies_len = 4 + max_bitrates /* (ext) supp rates */ + + 3 /* DS Params */; if (supp_ht) local->scan_ies_len += 2 + sizeof(struct ieee80211_ht_cap); From 3d435ad7218ff58c846d7e52d87c2daf115f50cd Mon Sep 17 00:00:00 2001 From: Jones Desougi Date: Wed, 27 Oct 2010 19:38:34 +0200 Subject: [PATCH 08/12] ath5k: Fix double free on hw attach error path If ath5k_hw_attach fails it will free sc->ah (local variable ah) before returning. However, when it reports failure the caller (ath5k_pci_probe) will also free sc->ah. Let the caller handle the deallocation, it does so on further errors as well. Signed-off-by: Jones Desougi Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath5k/attach.c | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/drivers/net/wireless/ath/ath5k/attach.c b/drivers/net/wireless/ath/ath5k/attach.c index cd0b14a0a93a..fbe8aca975d8 100644 --- a/drivers/net/wireless/ath/ath5k/attach.c +++ b/drivers/net/wireless/ath/ath5k/attach.c @@ -139,12 +139,12 @@ int ath5k_hw_attach(struct ath5k_softc *sc) /* Fill the ath5k_hw struct with the needed functions */ ret = ath5k_hw_init_desc_functions(ah); if (ret) - goto err_free; + goto err; /* Bring device out of sleep and reset its units */ ret = ath5k_hw_nic_wakeup(ah, 0, true); if (ret) - goto err_free; + goto err; /* Get MAC, PHY and RADIO revisions */ ah->ah_mac_srev = srev; @@ -234,7 +234,7 @@ int ath5k_hw_attach(struct ath5k_softc *sc) } else { ATH5K_ERR(sc, "Couldn't identify radio revision.\n"); ret = -ENODEV; - goto err_free; + goto err; } } @@ -244,7 +244,7 @@ int ath5k_hw_attach(struct ath5k_softc *sc) (srev < AR5K_SREV_AR2425)) { ATH5K_ERR(sc, "Device not yet supported.\n"); ret = -ENODEV; - goto err_free; + goto err; } /* @@ -252,7 +252,7 @@ int ath5k_hw_attach(struct ath5k_softc *sc) */ ret = ath5k_hw_post(ah); if (ret) - goto err_free; + goto err; /* Enable pci core retry fix on Hainan (5213A) and later chips */ if (srev >= AR5K_SREV_AR5213A) @@ -265,7 +265,7 @@ int ath5k_hw_attach(struct ath5k_softc *sc) ret = ath5k_eeprom_init(ah); if (ret) { ATH5K_ERR(sc, "unable to init EEPROM\n"); - goto err_free; + goto err; } ee = &ah->ah_capabilities.cap_eeprom; @@ -307,7 +307,7 @@ int ath5k_hw_attach(struct ath5k_softc *sc) if (ret) { ATH5K_ERR(sc, "unable to get device capabilities: 0x%04x\n", sc->pdev->device); - goto err_free; + goto err; } /* Crypto settings */ @@ -341,8 +341,7 @@ int ath5k_hw_attach(struct ath5k_softc *sc) ath5k_hw_set_ledstate(ah, AR5K_LED_INIT); return 0; -err_free: - kfree(ah); +err: return ret; } From 4fc4fbd1d9a05fa4f348b499aca3a6f8d3c9bbe6 Mon Sep 17 00:00:00 2001 From: Mohammed Shafi Shajakhan Date: Thu, 28 Oct 2010 19:51:47 +0530 Subject: [PATCH 09/12] ath9k: Fix incorrect access of rate flags in RC The index variable to access the rate flags should be obtained from the inner loop counter which corresponds to the rate table structure.This fixes the invalid rate selection i.e when the supported basic rate is invalid on a particular band and also the following warning message. Thanks to Raj for finding this out. Call Trace: [] warn_slowpath_common+0x7a/0xb0 [] warn_slowpath_null+0x15/0x20 [] ath_get_rate+0x595/0x5b0 [ath9k] [] ? cpumask_next_and+0x36/0x50 [] rate_control_get_rate+0x86/0x160 [mac80211] [] invoke_tx_handlers+0x81c/0x12d0 [mac80211] [] ieee80211_tx+0x89/0x2b0 [mac80211] [] ? pskb_expand_head+0x1cc/0x1f0 [] ieee80211_xmit+0xb5/0x1c0 [mac80211] [] ieee80211_tx_skb+0x4f/0x60 [mac80211] [] ieee80211_send_nullfunc+0x46/0x60 [mac80211] [] ieee80211_offchannel_stop_station+0x107/0x150 [mac80211] [] ? pskb_expand_head+0x1cc/0x1f0 [] ieee80211_xmit+0xb5/0x1c0 [mac80211] [] ieee80211_tx_skb+0x4f/0x60 [mac80211] [] ieee80211_send_nullfunc+0x46/0x60 [mac80211] [] ieee80211_offchannel_stop_station+0x107/0x150 [mac80211] [] ieee80211_scan_work+0x146/0x600 [mac80211] [] ? schedule+0x2f5/0x8e0 [] ? ieee80211_scan_work+0x0/0x600 [mac80211] [] process_one_work+0x10f/0x380 [] worker_thread+0x162/0x340 [] ? worker_thread+0x0/0x340 Cc: stable@kernel.org Signed-off-by: Mohammed Shafi Shajakhan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/rc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath9k/rc.c b/drivers/net/wireless/ath/ath9k/rc.c index 0cee90cf8dc9..89978d71617f 100644 --- a/drivers/net/wireless/ath/ath9k/rc.c +++ b/drivers/net/wireless/ath/ath9k/rc.c @@ -527,7 +527,7 @@ static u8 ath_rc_setvalid_rates(struct ath_rate_priv *ath_rc_priv, for (i = 0; i < rateset->rs_nrates; i++) { for (j = 0; j < rate_table->rate_cnt; j++) { u32 phy = rate_table->info[j].phy; - u16 rate_flags = rate_table->info[i].rate_flags; + u16 rate_flags = rate_table->info[j].rate_flags; u8 rate = rateset->rs_rates[i]; u8 dot11rate = rate_table->info[j].dot11rate; From 731b2034999bbfe86c9074f1b0d611940bf7c323 Mon Sep 17 00:00:00 2001 From: Paul Fox Date: Fri, 29 Oct 2010 14:57:28 +0100 Subject: [PATCH 10/12] libertas: Fix sd8686 firmware reload For the SD8686, we cannot rely on the scratch register to read the firmware load status, because the same register is used for storing RX packet length. Broaden the check to account for this. The module can now be unloaded/reloaded successfully. Based on the implementation from libertas_tf. Signed-off-by: Daniel Drake Acked-by: Dan Williams Signed-off-by: Steve deRosier Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/if_sdio.c | 32 ++++++++++++++++++++++--- 1 file changed, 29 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/libertas/if_sdio.c b/drivers/net/wireless/libertas/if_sdio.c index 296fd00a5129..e5685dc317a8 100644 --- a/drivers/net/wireless/libertas/if_sdio.c +++ b/drivers/net/wireless/libertas/if_sdio.c @@ -684,18 +684,40 @@ static int if_sdio_prog_firmware(struct if_sdio_card *card) lbs_deb_enter(LBS_DEB_SDIO); + /* + * Disable interrupts + */ + sdio_claim_host(card->func); + sdio_writeb(card->func, 0x00, IF_SDIO_H_INT_MASK, &ret); + sdio_release_host(card->func); + sdio_claim_host(card->func); scratch = if_sdio_read_scratch(card, &ret); sdio_release_host(card->func); + lbs_deb_sdio("firmware status = %#x\n", scratch); + lbs_deb_sdio("scratch ret = %d\n", ret); + if (ret) goto out; - lbs_deb_sdio("firmware status = %#x\n", scratch); + /* + * The manual clearly describes that FEDC is the right code to use + * to detect firmware presence, but for SD8686 it is not that simple. + * Scratch is also used to store the RX packet length, so we lose + * the FEDC value early on. So we use a non-zero check in order + * to validate firmware presence. + * Additionally, the SD8686 in the Gumstix always has the high scratch + * bit set, even when the firmware is not loaded. So we have to + * exclude that from the test. + */ if (scratch == IF_SDIO_FIRMWARE_OK) { lbs_deb_sdio("firmware already loaded\n"); goto success; + } else if ((card->model == MODEL_8686) && (scratch & 0x7fff)) { + lbs_deb_sdio("firmware may be running\n"); + goto success; } ret = lbs_get_firmware(&card->func->dev, lbs_helper_name, lbs_fw_name, @@ -709,10 +731,14 @@ static int if_sdio_prog_firmware(struct if_sdio_card *card) if (ret) goto out; + lbs_deb_sdio("Helper firmware loaded\n"); + ret = if_sdio_prog_real(card, mainfw); if (ret) goto out; + lbs_deb_sdio("Firmware loaded\n"); + success: sdio_claim_host(card->func); sdio_set_block_size(card->func, IF_SDIO_BLOCK_SIZE); @@ -1042,8 +1068,6 @@ static int if_sdio_probe(struct sdio_func *func, priv->exit_deep_sleep = if_sdio_exit_deep_sleep; priv->reset_deep_sleep_wakeup = if_sdio_reset_deep_sleep_wakeup; - priv->fw_ready = 1; - sdio_claim_host(func); /* @@ -1064,6 +1088,8 @@ static int if_sdio_probe(struct sdio_func *func, if (ret) goto reclaim; + priv->fw_ready = 1; + /* * FUNC_INIT is required for SD8688 WLAN/BT multiple functions */ From 520efd1ace3f826120482e57a95d649b4e1c1684 Mon Sep 17 00:00:00 2001 From: Jesper Juhl Date: Fri, 29 Oct 2010 16:10:26 +0200 Subject: [PATCH 11/12] mac80211: fix failure to check kmalloc return value in key_key_read I noticed two small issues in mac80211/debugfs_key.c::key_key_read while reading through the code. Patch below. The key_key_read() function returns ssize_t and the value that's actually returned is the return value of simple_read_from_buffer() which also returns ssize_t, so let's hold the return value in a ssize_t local variable rather than a int one. Also, memory is allocated dynamically with kmalloc() which can fail, but the return value of kmalloc() is not checked, so we may end up operating on a null pointer further on. So check for a NULL return and bail out with -ENOMEM in that case. Signed-off-by: Jesper Juhl Signed-off-by: John W. Linville --- net/mac80211/debugfs_key.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/net/mac80211/debugfs_key.c b/net/mac80211/debugfs_key.c index 4aa47d074a79..1243d1db5c59 100644 --- a/net/mac80211/debugfs_key.c +++ b/net/mac80211/debugfs_key.c @@ -203,9 +203,13 @@ static ssize_t key_key_read(struct file *file, char __user *userbuf, size_t count, loff_t *ppos) { struct ieee80211_key *key = file->private_data; - int i, res, bufsize = 2 * key->conf.keylen + 2; + int i, bufsize = 2 * key->conf.keylen + 2; char *buf = kmalloc(bufsize, GFP_KERNEL); char *p = buf; + ssize_t res; + + if (!buf) + return -ENOMEM; for (i = 0; i < key->conf.keylen; i++) p += scnprintf(p, bufsize + buf - p, "%02x", key->conf.key[i]); From 9f2a0fac625bcef9c579bcf0b0c904ab1a56e7c4 Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Thu, 28 Oct 2010 10:43:26 -0500 Subject: [PATCH 12/12] b43: Fix warning at drivers/mmc/core/core.c:237 in mmc_wait_for_cmd On module removal, the sdio version of b43 generates the following warning: [ 851.560519] ------------[ cut here ]------------ [ 851.560531] WARNING: at drivers/mmc/core/core.c:237 mmc_wait_for_cmd+0x88/0x90() [ 851.560534] Hardware name: 20552PG [ 851.560536] Modules linked in: b43(-) ssb mmc_block binfmt_misc rfcomm sco bnep ppdev l2cap ipt_MASQUERADE iptable_nat nf_nat nf_conntrack_ipv4 nf_defrag_ipv4 xt_state nf_conntrack ipt_REJECT xt_tcpudp iptable_filter ip_tables x_tables bridge stp kvm_intel kvm arc4 iwlagn snd_hda_codec_conexant snd_hda_intel snd_hda_codec iwlcore snd_hwdep snd_pcm thinkpad_acpi mac80211 snd_seq_midi snd_rawmidi snd_seq_midi_event snd_seq r852 joydev snd_timer sm_common pcmcia nand snd_seq_device cfg80211 sdhci_pci btusb psmouse tpm_tis yenta_socket nand_ids lp snd pcmcia_rsrc nand_ecc bluetooth sdhci tpm pcmcia_core parport mtd snd_page_alloc serio_raw tpm_bios soundcore nvram led_class sha256_generic aes_i586 aes_generic dm_crypt i915 drm_kms_helper drm ahci intel_agp i2c_algo_bit intel_gtt e1000e libahci video agpgart output [ 851.560620] Pid: 2504, comm: rmmod Not tainted 2.6.36-titan0+ #1 [ 851.560622] Call Trace: [ 851.560631] [] warn_slowpath_common+0x72/0xa0 [ 851.560636] [] ? mmc_wait_for_cmd+0x88/0x90 [ 851.560641] [] ? mmc_wait_for_cmd+0x88/0x90 [ 851.560645] [] warn_slowpath_null+0x22/0x30 [ 851.560649] [] mmc_wait_for_cmd+0x88/0x90 [ 851.560655] [] ? device_release+0x25/0x80 [ 851.560660] [] mmc_io_rw_direct_host+0xa0/0x150 [ 851.560665] [] mmc_io_rw_direct+0x30/0x40 [ 851.560669] [] sdio_disable_func+0x37/0xa0 [ 851.560683] [] b43_sdio_remove+0x30/0x50 [b43] [ 851.560687] [] sdio_bus_remove+0x1c/0x60 [ 851.560692] [] ? blocking_notifier_call_chain+0x1f/0x30 [ 851.560697] [] __device_release_driver+0x51/0xb0 [ 851.560701] [] driver_detach+0x8f/0xa0 [ 851.560705] [] bus_remove_driver+0x63/0xa0 [ 851.560709] [] driver_unregister+0x49/0x80 [ 851.560713] [] ? driver_unregister+0x49/0x80 [ 851.560718] [] sdio_unregister_driver+0x17/0x20 [ 851.560727] [] b43_sdio_exit+0x12/0x20 [b43] [ 851.560734] [] b43_exit+0x17/0x3c [b43] [ 851.560740] [] sys_delete_module+0x13d/0x200 [ 851.560747] [] ? do_munmap+0x212/0x300 [ 851.560752] [] sysenter_do_call+0x12/0x28 [ 851.560757] ---[ end trace 31e14488072d2f7d ]--- [ 851.560759] ------------[ cut here ]------------ The warning is caused by b43 not claiming the device before calling sdio_disable_func(). Signed-off-by: Larry Finger Reported-by: Arnd Hannemann Tested-by: Arnd Hannemann Cc: Stable Signed-off-by: John W. Linville --- drivers/net/wireless/b43/sdio.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/net/wireless/b43/sdio.c b/drivers/net/wireless/b43/sdio.c index 45933cf8e8c2..9a55338d957f 100644 --- a/drivers/net/wireless/b43/sdio.c +++ b/drivers/net/wireless/b43/sdio.c @@ -175,7 +175,9 @@ static void b43_sdio_remove(struct sdio_func *func) struct b43_sdio *sdio = sdio_get_drvdata(func); ssb_bus_unregister(&sdio->ssb); + sdio_claim_host(func); sdio_disable_func(func); + sdio_release_host(func); kfree(sdio); sdio_set_drvdata(func, NULL); }