From 1e450285281bdf766272c181ecd43d4f2f0711ce Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Wed, 20 Oct 2010 16:07:03 -0700 Subject: 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; } -- cgit v1.2.3 From 7583c550c3e635dcc61ab127c36ecefd59fb8dc8 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Wed, 20 Oct 2010 16:07:04 -0700 Subject: 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; } -- cgit v1.2.3 From b79b33c4baf2532aac2c0924dce5a738099b888c Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Wed, 20 Oct 2010 16:07:05 -0700 Subject: 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) -- cgit v1.2.3 From 5e848f789d60000d39d9a5f26ab02dbdd963f6cd Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Wed, 20 Oct 2010 16:07:06 -0700 Subject: 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) -- cgit v1.2.3 From e609e2ea2cdb3448e7849703179cd792a28dcc55 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Wed, 27 Oct 2010 02:15:05 +0200 Subject: 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) -- cgit v1.2.3 From d654567dec75782d6fd9add4b7b9c50e0926d369 Mon Sep 17 00:00:00 2001 From: Rajkumar Manoharan Date: Wed, 27 Oct 2010 12:02:54 +0530 Subject: 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. -- cgit v1.2.3 From dc9f48ce7c7d345be31208def51572a8250a4a03 Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Wed, 27 Oct 2010 13:40:33 +0300 Subject: 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); -- cgit v1.2.3 From 3d435ad7218ff58c846d7e52d87c2daf115f50cd Mon Sep 17 00:00:00 2001 From: Jones Desougi Date: Wed, 27 Oct 2010 19:38:34 +0200 Subject: 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; } -- cgit v1.2.3 From c1758012971e0410790b2bc96a77e26d7b286593 Mon Sep 17 00:00:00 2001 From: Jesse Gross Date: Tue, 26 Oct 2010 14:56:03 +0000 Subject: igb: Fix unused variable warning. Commit eab6d18d "vlan: Don't check for vlan group before vlan_tx_tag_present" removed the need for the adapter variable in igb_xmit_frame_ring_adv(). This removes the variable as well to avoid the compiler warning. Reported-by: Stephen Rothwell Signed-off-by: Jesse Gross Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller --- drivers/net/igb/igb_main.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/net/igb/igb_main.c b/drivers/net/igb/igb_main.c index 14db09e2fa8b..892d196f17ac 100644 --- a/drivers/net/igb/igb_main.c +++ b/drivers/net/igb/igb_main.c @@ -4107,7 +4107,6 @@ static inline int igb_maybe_stop_tx(struct igb_ring *tx_ring, int size) netdev_tx_t igb_xmit_frame_ring_adv(struct sk_buff *skb, struct igb_ring *tx_ring) { - struct igb_adapter *adapter = netdev_priv(tx_ring->netdev); int tso = 0, count; u32 tx_flags = 0; u16 first; -- cgit v1.2.3 From 116c1ea0aa871a2d6554e7fae124fc2880a596c1 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Thu, 28 Oct 2010 10:15:43 -0700 Subject: pch_gbe: Select MII. Reported-by: Steven Rostedt Signed-off-by: David S. Miller --- drivers/net/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index 77c1fab7d774..f24179d98db9 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -2520,6 +2520,7 @@ source "drivers/net/stmmac/Kconfig" config PCH_GBE tristate "PCH Gigabit Ethernet" depends on PCI + select MII ---help--- This is a gigabit ethernet driver for Topcliff PCH. Topcliff PCH is the platform controller hub that is used in Intel's -- cgit v1.2.3 From ff10e13cd06f3dbe90e9fffc3c2dd2057a116e4b Mon Sep 17 00:00:00 2001 From: Carolyn Wyborny Date: Thu, 28 Oct 2010 00:59:53 +0000 Subject: e1000e: reset PHY after errors detected Some errors can be induced in the PHY via environmental testing (specifically extreme temperature changes and electro static discharge testing), and in the case of the PHY hanging due to this input, this detects the problem and resets to continue. This issue only applies to 82574 silicon. Signed-off-by: Jesse Brandeburg Signed-off-by: Carolyn Wyborny Tested-by: Emil Tantilov Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller --- drivers/net/e1000e/82571.c | 38 ++++++++++++++++++++++++++++++++++++++ drivers/net/e1000e/e1000.h | 3 +++ drivers/net/e1000e/netdev.c | 22 ++++++++++++++++++++++ 3 files changed, 63 insertions(+) diff --git a/drivers/net/e1000e/82571.c b/drivers/net/e1000e/82571.c index ca663f19d7df..7236f1a53ba0 100644 --- a/drivers/net/e1000e/82571.c +++ b/drivers/net/e1000e/82571.c @@ -52,6 +52,10 @@ (ID_LED_DEF1_DEF2)) #define E1000_GCR_L1_ACT_WITHOUT_L0S_RX 0x08000000 +#define E1000_BASE1000T_STATUS 10 +#define E1000_IDLE_ERROR_COUNT_MASK 0xFF +#define E1000_RECEIVE_ERROR_COUNTER 21 +#define E1000_RECEIVE_ERROR_MAX 0xFFFF #define E1000_NVM_INIT_CTRL2_MNGM 0x6000 /* Manageability Operation Mode mask */ @@ -1242,6 +1246,39 @@ static s32 e1000_led_on_82574(struct e1000_hw *hw) return 0; } +/** + * e1000_check_phy_82574 - check 82574 phy hung state + * @hw: pointer to the HW structure + * + * Returns whether phy is hung or not + **/ +bool e1000_check_phy_82574(struct e1000_hw *hw) +{ + u16 status_1kbt = 0; + u16 receive_errors = 0; + bool phy_hung = false; + s32 ret_val = 0; + + /* + * Read PHY Receive Error counter first, if its is max - all F's then + * read the Base1000T status register If both are max then PHY is hung. + */ + ret_val = e1e_rphy(hw, E1000_RECEIVE_ERROR_COUNTER, &receive_errors); + + if (ret_val) + goto out; + if (receive_errors == E1000_RECEIVE_ERROR_MAX) { + ret_val = e1e_rphy(hw, E1000_BASE1000T_STATUS, &status_1kbt); + if (ret_val) + goto out; + if ((status_1kbt & E1000_IDLE_ERROR_COUNT_MASK) == + E1000_IDLE_ERROR_COUNT_MASK) + phy_hung = true; + } +out: + return phy_hung; +} + /** * e1000_setup_link_82571 - Setup flow control and link settings * @hw: pointer to the HW structure @@ -1859,6 +1896,7 @@ struct e1000_info e1000_82574_info = { | FLAG_HAS_SMART_POWER_DOWN | FLAG_HAS_AMT | FLAG_HAS_CTRLEXT_ON_LOAD, + .flags2 = FLAG2_CHECK_PHY_HANG, .pba = 36, .max_hw_frame_size = DEFAULT_JUMBO, .get_variants = e1000_get_variants_82571, diff --git a/drivers/net/e1000e/e1000.h b/drivers/net/e1000e/e1000.h index cee882dd67bf..fdc67fead4ea 100644 --- a/drivers/net/e1000e/e1000.h +++ b/drivers/net/e1000e/e1000.h @@ -397,6 +397,7 @@ struct e1000_adapter { struct work_struct print_hang_task; bool idle_check; + int phy_hang_count; }; struct e1000_info { @@ -454,6 +455,7 @@ struct e1000_info { #define FLAG2_HAS_EEE (1 << 5) #define FLAG2_DMA_BURST (1 << 6) #define FLAG2_DISABLE_AIM (1 << 8) +#define FLAG2_CHECK_PHY_HANG (1 << 9) #define E1000_RX_DESC_PS(R, i) \ (&(((union e1000_rx_desc_packet_split *)((R).desc))[i])) @@ -631,6 +633,7 @@ extern s32 e1000_get_phy_info_ife(struct e1000_hw *hw); extern s32 e1000_check_polarity_ife(struct e1000_hw *hw); extern s32 e1000_phy_force_speed_duplex_ife(struct e1000_hw *hw); extern s32 e1000_check_polarity_igp(struct e1000_hw *hw); +extern bool e1000_check_phy_82574(struct e1000_hw *hw); static inline s32 e1000_phy_hw_reset(struct e1000_hw *hw) { diff --git a/drivers/net/e1000e/netdev.c b/drivers/net/e1000e/netdev.c index ec8cf3f51423..35a9dd4353d7 100644 --- a/drivers/net/e1000e/netdev.c +++ b/drivers/net/e1000e/netdev.c @@ -4098,6 +4098,25 @@ static void e1000e_enable_receives(struct e1000_adapter *adapter) } } +static void e1000e_check_82574_phy_workaround(struct e1000_adapter *adapter) +{ + struct e1000_hw *hw = &adapter->hw; + + /* + * With 82574 controllers, PHY needs to be checked periodically + * for hung state and reset, if two calls return true + */ + if (e1000_check_phy_82574(hw)) + adapter->phy_hang_count++; + else + adapter->phy_hang_count = 0; + + if (adapter->phy_hang_count > 1) { + adapter->phy_hang_count = 0; + schedule_work(&adapter->reset_task); + } +} + /** * e1000_watchdog - Timer Call-back * @data: pointer to adapter cast into an unsigned long @@ -4333,6 +4352,9 @@ link_up: if (e1000e_get_laa_state_82571(hw)) e1000e_rar_set(hw, adapter->hw.mac.addr, 0); + if (adapter->flags2 & FLAG2_CHECK_PHY_HANG) + e1000e_check_82574_phy_workaround(adapter); + /* Reset the timer */ if (!test_bit(__E1000_DOWN, &adapter->state)) mod_timer(&adapter->watchdog_timer, -- cgit v1.2.3 From affa9dfb04b7e2e3a0b0e6d844ea0c9ed97505f9 Mon Sep 17 00:00:00 2001 From: Carolyn Wyborny Date: Thu, 28 Oct 2010 00:59:55 +0000 Subject: e1000e: Add check for reset flags before displaying reset message Some parts need to execute resets during normal operation. This flag check ensures that those parts reset without needlessly alarming the user. Other unexpected resets by other parts will dump debug info and message the reset action to the user, as originally intended. Signed-off-by: Carolyn Wyborny Acked-by: Bruce Allan Tested-by: Emil Tantilov Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller --- drivers/net/e1000e/netdev.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/net/e1000e/netdev.c b/drivers/net/e1000e/netdev.c index 35a9dd4353d7..c4ca1629f532 100644 --- a/drivers/net/e1000e/netdev.c +++ b/drivers/net/e1000e/netdev.c @@ -4882,8 +4882,11 @@ static void e1000_reset_task(struct work_struct *work) struct e1000_adapter *adapter; adapter = container_of(work, struct e1000_adapter, reset_task); - e1000e_dump(adapter); - e_err("Reset adapter\n"); + if (!((adapter->flags & FLAG_RX_NEEDS_RESTART) && + (adapter->flags & FLAG_RX_RESTART_NOW))) { + e1000e_dump(adapter); + e_err("Reset adapter\n"); + } e1000e_reinit_locked(adapter); } -- cgit v1.2.3 From 9806307a1c5a2a79e268ae4e78b437d38c8adf7f Mon Sep 17 00:00:00 2001 From: John Fastabend Date: Thu, 28 Oct 2010 00:59:57 +0000 Subject: ixgbe: DCB, fix TX hang occurring in stress condition with PFC The DCB credits refill quantum _must_ be greater than half the max packet size. This is needed to guarantee that TX DMA operations are not attempted during a pause state. Additionally, the min IFG must be set correctly for DCB mode. If a DMA operation is requested unexpectedly during the pause state the HW data store may be corrupted leading to a DMA hang. The DMA hang requires a reset to correct. This fixes the HW configuration to avoid this condition. Signed-off-by: John Fastabend Tested-by: Ross Brattain Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller --- drivers/net/ixgbe/ixgbe_dcb.c | 39 ++++++++++++++++++++++++++++++++----- drivers/net/ixgbe/ixgbe_dcb.h | 5 ++--- drivers/net/ixgbe/ixgbe_dcb_82599.c | 5 +++++ drivers/net/ixgbe/ixgbe_dcb_82599.h | 3 +++ drivers/net/ixgbe/ixgbe_main.c | 12 ++++++++++-- 5 files changed, 54 insertions(+), 10 deletions(-) diff --git a/drivers/net/ixgbe/ixgbe_dcb.c b/drivers/net/ixgbe/ixgbe_dcb.c index 8bb9ddb6dffe..0d44c6470ca3 100644 --- a/drivers/net/ixgbe/ixgbe_dcb.c +++ b/drivers/net/ixgbe/ixgbe_dcb.c @@ -43,9 +43,12 @@ * ixgbe_dcb_check_config(). */ s32 ixgbe_dcb_calculate_tc_credits(struct ixgbe_dcb_config *dcb_config, - u8 direction) + int max_frame, u8 direction) { struct tc_bw_alloc *p; + int min_credit; + int min_multiplier; + int min_percent = 100; s32 ret_val = 0; /* Initialization values default for Tx settings */ u32 credit_refill = 0; @@ -59,6 +62,31 @@ s32 ixgbe_dcb_calculate_tc_credits(struct ixgbe_dcb_config *dcb_config, goto out; } + min_credit = ((max_frame / 2) + DCB_CREDIT_QUANTUM - 1) / + DCB_CREDIT_QUANTUM; + + /* Find smallest link percentage */ + for (i = 0; i < MAX_TRAFFIC_CLASS; i++) { + p = &dcb_config->tc_config[i].path[direction]; + bw_percent = dcb_config->bw_percentage[direction][p->bwg_id]; + link_percentage = p->bwg_percent; + + link_percentage = (link_percentage * bw_percent) / 100; + + if (link_percentage && link_percentage < min_percent) + min_percent = link_percentage; + } + + /* + * The ratio between traffic classes will control the bandwidth + * percentages seen on the wire. To calculate this ratio we use + * a multiplier. It is required that the refill credits must be + * larger than the max frame size so here we find the smallest + * multiplier that will allow all bandwidth percentages to be + * greater than the max frame size. + */ + min_multiplier = (min_credit / min_percent) + 1; + /* Find out the link percentage for each TC first */ for (i = 0; i < MAX_TRAFFIC_CLASS; i++) { p = &dcb_config->tc_config[i].path[direction]; @@ -73,8 +101,9 @@ s32 ixgbe_dcb_calculate_tc_credits(struct ixgbe_dcb_config *dcb_config, /* Save link_percentage for reference */ p->link_percent = (u8)link_percentage; - /* Calculate credit refill and save it */ - credit_refill = link_percentage * MINIMUM_CREDIT_REFILL; + /* Calculate credit refill ratio using multiplier */ + credit_refill = min(link_percentage * min_multiplier, + MAX_CREDIT_REFILL); p->data_credits_refill = (u16)credit_refill; /* Calculate maximum credit for the TC */ @@ -85,8 +114,8 @@ s32 ixgbe_dcb_calculate_tc_credits(struct ixgbe_dcb_config *dcb_config, * of a TC is too small, the maximum credit may not be * enough to send out a jumbo frame in data plane arbitration. */ - if (credit_max && (credit_max < MINIMUM_CREDIT_FOR_JUMBO)) - credit_max = MINIMUM_CREDIT_FOR_JUMBO; + if (credit_max && (credit_max < min_credit)) + credit_max = min_credit; if (direction == DCB_TX_CONFIG) { /* diff --git a/drivers/net/ixgbe/ixgbe_dcb.h b/drivers/net/ixgbe/ixgbe_dcb.h index eb1059f09da0..0208a87b129e 100644 --- a/drivers/net/ixgbe/ixgbe_dcb.h +++ b/drivers/net/ixgbe/ixgbe_dcb.h @@ -150,15 +150,14 @@ struct ixgbe_dcb_config { /* DCB driver APIs */ /* DCB credits calculation */ -s32 ixgbe_dcb_calculate_tc_credits(struct ixgbe_dcb_config *, u8); +s32 ixgbe_dcb_calculate_tc_credits(struct ixgbe_dcb_config *, int, u8); /* DCB hw initialization */ s32 ixgbe_dcb_hw_config(struct ixgbe_hw *, struct ixgbe_dcb_config *); /* DCB definitions for credit calculation */ +#define DCB_CREDIT_QUANTUM 64 /* DCB Quantum */ #define MAX_CREDIT_REFILL 511 /* 0x1FF * 64B = 32704B */ -#define MINIMUM_CREDIT_REFILL 5 /* 5*64B = 320B */ -#define MINIMUM_CREDIT_FOR_JUMBO 145 /* 145= UpperBound((9*1024+54)/64B) for 9KB jumbo frame */ #define DCB_MAX_TSO_SIZE (32*1024) /* MAX TSO packet size supported in DCB mode */ #define MINIMUM_CREDIT_FOR_TSO (DCB_MAX_TSO_SIZE/64 + 1) /* 513 for 32KB TSO packet */ #define MAX_CREDIT 4095 /* Maximum credit supported: 256KB * 1204 / 64B */ diff --git a/drivers/net/ixgbe/ixgbe_dcb_82599.c b/drivers/net/ixgbe/ixgbe_dcb_82599.c index 67c219f86c3a..05f224715073 100644 --- a/drivers/net/ixgbe/ixgbe_dcb_82599.c +++ b/drivers/net/ixgbe/ixgbe_dcb_82599.c @@ -397,6 +397,11 @@ static s32 ixgbe_dcb_config_82599(struct ixgbe_hw *hw) reg &= ~IXGBE_RTTDCS_ARBDIS; IXGBE_WRITE_REG(hw, IXGBE_RTTDCS, reg); + /* Enable Security TX Buffer IFG for DCB */ + reg = IXGBE_READ_REG(hw, IXGBE_SECTXMINIFG); + reg |= IXGBE_SECTX_DCB; + IXGBE_WRITE_REG(hw, IXGBE_SECTXMINIFG, reg); + return 0; } diff --git a/drivers/net/ixgbe/ixgbe_dcb_82599.h b/drivers/net/ixgbe/ixgbe_dcb_82599.h index 18d7fbf6c292..3841649fb954 100644 --- a/drivers/net/ixgbe/ixgbe_dcb_82599.h +++ b/drivers/net/ixgbe/ixgbe_dcb_82599.h @@ -95,6 +95,9 @@ #define IXGBE_TXPBTHRESH_DCB 0xA /* THRESH value for DCB mode */ +/* SECTXMINIFG DCB */ +#define IXGBE_SECTX_DCB 0x00001F00 /* DCB TX Buffer IFG */ + /* DCB hardware-specific driver APIs */ diff --git a/drivers/net/ixgbe/ixgbe_main.c b/drivers/net/ixgbe/ixgbe_main.c index f85631263af8..2bd3eb4ee5a1 100644 --- a/drivers/net/ixgbe/ixgbe_main.c +++ b/drivers/net/ixgbe/ixgbe_main.c @@ -3347,6 +3347,7 @@ static void ixgbe_napi_disable_all(struct ixgbe_adapter *adapter) static void ixgbe_configure_dcb(struct ixgbe_adapter *adapter) { struct ixgbe_hw *hw = &adapter->hw; + int max_frame = adapter->netdev->mtu + ETH_HLEN + ETH_FCS_LEN; u32 txdctl; int i, j; @@ -3359,8 +3360,15 @@ static void ixgbe_configure_dcb(struct ixgbe_adapter *adapter) if (hw->mac.type == ixgbe_mac_82598EB) netif_set_gso_max_size(adapter->netdev, 32768); - ixgbe_dcb_calculate_tc_credits(&adapter->dcb_cfg, DCB_TX_CONFIG); - ixgbe_dcb_calculate_tc_credits(&adapter->dcb_cfg, DCB_RX_CONFIG); +#ifdef CONFIG_FCOE + if (adapter->netdev->features & NETIF_F_FCOE_MTU) + max_frame = max(max_frame, IXGBE_FCOE_JUMBO_FRAME_SIZE); +#endif + + ixgbe_dcb_calculate_tc_credits(&adapter->dcb_cfg, max_frame, + DCB_TX_CONFIG); + ixgbe_dcb_calculate_tc_credits(&adapter->dcb_cfg, max_frame, + DCB_RX_CONFIG); /* reconfigure the hardware */ ixgbe_dcb_hw_config(&adapter->hw, &adapter->dcb_cfg); -- cgit v1.2.3 From ec43a81cfa85b1ba0c9ac1aa995fe652f30fd4d6 Mon Sep 17 00:00:00 2001 From: Emil Tantilov Date: Thu, 28 Oct 2010 00:59:49 +0000 Subject: ixgb: call pci_disable_device in ixgb_remove ixgb fails to work after reload on recent kernels: rmmod ixgb (dev->current_state = PCI_UNKNOWN) modprobe ixgb (pci_enable_device will bail leaving current_state to PCI_UNKNOWN) ifup eth0 do_IRQ: 2.82 No irq handler for vector (irq -1) The issue was exposed by commit fcd097f31a6ee207cc0c3da9cccd2a86d4334785 PCI: MSI: Remove unsafe and unnecessary hardware access which avoids HW writes for power states != PCI_D0 CC: Ben Hutchings Signed-off-by: Emil Tantilov Tested-by: Jeff Pieper Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller --- drivers/net/ixgb/ixgb_main.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/ixgb/ixgb_main.c b/drivers/net/ixgb/ixgb_main.c index 666207a9c039..caa8192fff2a 100644 --- a/drivers/net/ixgb/ixgb_main.c +++ b/drivers/net/ixgb/ixgb_main.c @@ -533,6 +533,7 @@ ixgb_remove(struct pci_dev *pdev) pci_release_regions(pdev); free_netdev(netdev); + pci_disable_device(pdev); } /** -- cgit v1.2.3 From de7fe7874dc55e8226245c50f07dec3c7b285044 Mon Sep 17 00:00:00 2001 From: Emil Tantilov Date: Thu, 28 Oct 2010 00:59:51 +0000 Subject: igbvf: fix panic on load Introduced by commit:e6484930d7c73d324bccda7d43d131088da697b9 net: allocate tx queues in register_netdevice Signed-off-by: Emil Tantilov Acked-by: Greg Rose Tested-by: Jeff Pieper Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller --- drivers/net/igbvf/netdev.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/net/igbvf/netdev.c b/drivers/net/igbvf/netdev.c index ebfaa68ee630..28af019c97bb 100644 --- a/drivers/net/igbvf/netdev.c +++ b/drivers/net/igbvf/netdev.c @@ -2783,15 +2783,15 @@ static int __devinit igbvf_probe(struct pci_dev *pdev, /* reset the hardware with the new settings */ igbvf_reset(adapter); - /* tell the stack to leave us alone until igbvf_open() is called */ - netif_carrier_off(netdev); - netif_stop_queue(netdev); - strcpy(netdev->name, "eth%d"); err = register_netdev(netdev); if (err) goto err_hw_init; + /* tell the stack to leave us alone until igbvf_open() is called */ + netif_carrier_off(netdev); + netif_stop_queue(netdev); + igbvf_print_device_info(adapter); igbvf_initialize_last_counter_stats(adapter); -- cgit v1.2.3 From fe84f4140f0d24deca8591e38926b95cfd097e62 Mon Sep 17 00:00:00 2001 From: Gerrit Renker Date: Wed, 27 Oct 2010 19:16:25 +0000 Subject: dccp: Return-value convention of hc_tx_send_packet() This patch reorganises the return value convention of the CCID TX sending function, to permit more flexible schemes, as required by subsequent patches. Currently the convention is * values < 0 mean error, * a value == 0 means "send now", and * a value x > 0 means "send in x milliseconds". The patch provides symbolic constants and a function to interpret return values. In addition, it caps the maximum positive return value to 0xFFFF milliseconds, corresponding to 65.535 seconds. This is possible since in CCID-3/4 the maximum possible inter-packet gap is fixed at t_mbi = 64 sec. Signed-off-by: Gerrit Renker Signed-off-by: David S. Miller --- net/dccp/ccid.h | 34 +++++++++++++++++++++++++++++++--- net/dccp/ccids/ccid3.c | 12 ++++++------ 2 files changed, 37 insertions(+), 9 deletions(-) diff --git a/net/dccp/ccid.h b/net/dccp/ccid.h index 117fb093dcaf..75c3582a7678 100644 --- a/net/dccp/ccid.h +++ b/net/dccp/ccid.h @@ -134,13 +134,41 @@ static inline int ccid_get_current_tx_ccid(struct dccp_sock *dp) extern void ccid_hc_rx_delete(struct ccid *ccid, struct sock *sk); extern void ccid_hc_tx_delete(struct ccid *ccid, struct sock *sk); +/* + * Congestion control of queued data packets via CCID decision. + * + * The TX CCID performs its congestion-control by indicating whether and when a + * queued packet may be sent, using the return code of ccid_hc_tx_send_packet(). + * The following modes are supported via the symbolic constants below: + * - timer-based pacing (CCID returns a delay value in milliseconds); + * - autonomous dequeueing (CCID internally schedules dccps_xmitlet). + */ + +enum ccid_dequeueing_decision { + CCID_PACKET_SEND_AT_ONCE = 0x00000, /* "green light": no delay */ + CCID_PACKET_DELAY_MAX = 0x0FFFF, /* maximum delay in msecs */ + CCID_PACKET_DELAY = 0x10000, /* CCID msec-delay mode */ + CCID_PACKET_WILL_DEQUEUE_LATER = 0x20000, /* CCID autonomous mode */ + CCID_PACKET_ERR = 0xF0000, /* error condition */ +}; + +static inline int ccid_packet_dequeue_eval(const int return_code) +{ + if (return_code < 0) + return CCID_PACKET_ERR; + if (return_code == 0) + return CCID_PACKET_SEND_AT_ONCE; + if (return_code <= CCID_PACKET_DELAY_MAX) + return CCID_PACKET_DELAY; + return return_code; +} + static inline int ccid_hc_tx_send_packet(struct ccid *ccid, struct sock *sk, struct sk_buff *skb) { - int rc = 0; if (ccid->ccid_ops->ccid_hc_tx_send_packet != NULL) - rc = ccid->ccid_ops->ccid_hc_tx_send_packet(sk, skb); - return rc; + return ccid->ccid_ops->ccid_hc_tx_send_packet(sk, skb); + return CCID_PACKET_SEND_AT_ONCE; } static inline void ccid_hc_tx_packet_sent(struct ccid *ccid, struct sock *sk, diff --git a/net/dccp/ccids/ccid3.c b/net/dccp/ccids/ccid3.c index 3060a60ed5ab..3d604e1349c0 100644 --- a/net/dccp/ccids/ccid3.c +++ b/net/dccp/ccids/ccid3.c @@ -268,11 +268,11 @@ out: sock_put(sk); } -/* - * returns - * > 0: delay (in msecs) that should pass before actually sending - * = 0: can send immediately - * < 0: error condition; do not send packet +/** + * ccid3_hc_tx_send_packet - Delay-based dequeueing of TX packets + * @skb: next packet candidate to send on @sk + * This function uses the convention of ccid_packet_dequeue_eval() and + * returns a millisecond-delay value between 0 and t_mbi = 64000 msec. */ static int ccid3_hc_tx_send_packet(struct sock *sk, struct sk_buff *skb) { @@ -348,7 +348,7 @@ static int ccid3_hc_tx_send_packet(struct sock *sk, struct sk_buff *skb) /* set the nominal send time for the next following packet */ hc->tx_t_nom = ktime_add_us(hc->tx_t_nom, hc->tx_t_ipi); - return 0; + return CCID_PACKET_SEND_AT_ONCE; } static void ccid3_hc_tx_packet_sent(struct sock *sk, unsigned int len) -- cgit v1.2.3 From dc841e30eaea9f9f83c9ab1ee0b3ef9e5c95ce8a Mon Sep 17 00:00:00 2001 From: Gerrit Renker Date: Wed, 27 Oct 2010 19:16:26 +0000 Subject: dccp: Extend CCID packet dequeueing interface This extends the packet dequeuing interface of dccp_write_xmit() to allow 1. CCIDs to take care of timing when the next packet may be sent; 2. delayed sending (as before, with an inter-packet gap up to 65.535 seconds). The main purpose is to take CCID-2 out of its polling mode (when it is network- limited, it tries every millisecond to send, without interruption). The mode of operation for (2) is as follows: * new packet is enqueued via dccp_sendmsg() => dccp_write_xmit(), * ccid_hc_tx_send_packet() detects that it may not send (e.g. window full), * it signals this condition via `CCID_PACKET_WILL_DEQUEUE_LATER', * dccp_write_xmit() returns without further action; * after some time the wait-condition for CCID becomes true, * that CCID schedules the tasklet, * tasklet function calls ccid_hc_tx_send_packet() via dccp_write_xmit(), * since the wait-condition is now true, ccid_hc_tx_packet() returns "send now", * packet is sent, and possibly more (since dccp_write_xmit() loops). Code reuse: the taskled function calls dccp_write_xmit(), the timer function reduces to a wrapper around the same code. Signed-off-by: Gerrit Renker Signed-off-by: David S. Miller --- include/linux/dccp.h | 4 +- net/dccp/output.c | 118 +++++++++++++++++++++++++++++++-------------------- net/dccp/timer.c | 25 ++++++----- 3 files changed, 89 insertions(+), 58 deletions(-) diff --git a/include/linux/dccp.h b/include/linux/dccp.h index 7187bd8a75f6..749f01ccd26e 100644 --- a/include/linux/dccp.h +++ b/include/linux/dccp.h @@ -462,7 +462,8 @@ struct dccp_ackvec; * @dccps_hc_rx_insert_options - receiver wants to add options when acking * @dccps_hc_tx_insert_options - sender wants to add options when sending * @dccps_server_timewait - server holds timewait state on close (RFC 4340, 8.3) - * @dccps_xmit_timer - timer for when CCID is not ready to send + * @dccps_xmitlet - tasklet scheduled by the TX CCID to dequeue data packets + * @dccps_xmit_timer - used by the TX CCID to delay sending (rate-based pacing) * @dccps_syn_rtt - RTT sample from Request/Response exchange (in usecs) */ struct dccp_sock { @@ -502,6 +503,7 @@ struct dccp_sock { __u8 dccps_hc_rx_insert_options:1; __u8 dccps_hc_tx_insert_options:1; __u8 dccps_server_timewait:1; + struct tasklet_struct dccps_xmitlet; struct timer_list dccps_xmit_timer; }; diff --git a/net/dccp/output.c b/net/dccp/output.c index a988fe9ffcba..11418a9a389d 100644 --- a/net/dccp/output.c +++ b/net/dccp/output.c @@ -254,63 +254,89 @@ do_interrupted: goto out; } +/** + * dccp_xmit_packet - Send data packet under control of CCID + * Transmits next-queued payload and informs CCID to account for the packet. + */ +static void dccp_xmit_packet(struct sock *sk) +{ + int err, len; + struct dccp_sock *dp = dccp_sk(sk); + struct sk_buff *skb = skb_dequeue(&sk->sk_write_queue); + + if (unlikely(skb == NULL)) + return; + len = skb->len; + + if (sk->sk_state == DCCP_PARTOPEN) { + const u32 cur_mps = dp->dccps_mss_cache - DCCP_FEATNEG_OVERHEAD; + /* + * See 8.1.5 - Handshake Completion. + * + * For robustness we resend Confirm options until the client has + * entered OPEN. During the initial feature negotiation, the MPS + * is smaller than usual, reduced by the Change/Confirm options. + */ + if (!list_empty(&dp->dccps_featneg) && len > cur_mps) { + DCCP_WARN("Payload too large (%d) for featneg.\n", len); + dccp_send_ack(sk); + dccp_feat_list_purge(&dp->dccps_featneg); + } + + inet_csk_schedule_ack(sk); + inet_csk_reset_xmit_timer(sk, ICSK_TIME_DACK, + inet_csk(sk)->icsk_rto, + DCCP_RTO_MAX); + DCCP_SKB_CB(skb)->dccpd_type = DCCP_PKT_DATAACK; + } else if (dccp_ack_pending(sk)) { + DCCP_SKB_CB(skb)->dccpd_type = DCCP_PKT_DATAACK; + } else { + DCCP_SKB_CB(skb)->dccpd_type = DCCP_PKT_DATA; + } + + err = dccp_transmit_skb(sk, skb); + if (err) + dccp_pr_debug("transmit_skb() returned err=%d\n", err); + /* + * Register this one as sent even if an error occurred. To the remote + * end a local packet drop is indistinguishable from network loss, i.e. + * any local drop will eventually be reported via receiver feedback. + */ + ccid_hc_tx_packet_sent(dp->dccps_hc_tx_ccid, sk, len); +} + void dccp_write_xmit(struct sock *sk, int block) { struct dccp_sock *dp = dccp_sk(sk); struct sk_buff *skb; while ((skb = skb_peek(&sk->sk_write_queue))) { - int err = ccid_hc_tx_send_packet(dp->dccps_hc_tx_ccid, sk, skb); + int rc = ccid_hc_tx_send_packet(dp->dccps_hc_tx_ccid, sk, skb); - if (err > 0) { + switch (ccid_packet_dequeue_eval(rc)) { + case CCID_PACKET_WILL_DEQUEUE_LATER: + return; + case CCID_PACKET_DELAY: if (!block) { sk_reset_timer(sk, &dp->dccps_xmit_timer, - msecs_to_jiffies(err)+jiffies); + msecs_to_jiffies(rc)+jiffies); + return; + } + rc = dccp_wait_for_ccid(sk, skb, rc); + if (rc && rc != -EINTR) { + DCCP_BUG("err=%d after dccp_wait_for_ccid", rc); + skb_dequeue(&sk->sk_write_queue); + kfree_skb(skb); break; - } else - err = dccp_wait_for_ccid(sk, skb, err); - if (err && err != -EINTR) - DCCP_BUG("err=%d after dccp_wait_for_ccid", err); - } - - skb_dequeue(&sk->sk_write_queue); - if (err == 0) { - struct dccp_skb_cb *dcb = DCCP_SKB_CB(skb); - const int len = skb->len; - - if (sk->sk_state == DCCP_PARTOPEN) { - const u32 cur_mps = dp->dccps_mss_cache - DCCP_FEATNEG_OVERHEAD; - /* - * See 8.1.5 - Handshake Completion. - * - * For robustness we resend Confirm options until the client has - * entered OPEN. During the initial feature negotiation, the MPS - * is smaller than usual, reduced by the Change/Confirm options. - */ - if (!list_empty(&dp->dccps_featneg) && len > cur_mps) { - DCCP_WARN("Payload too large (%d) for featneg.\n", len); - dccp_send_ack(sk); - dccp_feat_list_purge(&dp->dccps_featneg); - } - - inet_csk_schedule_ack(sk); - inet_csk_reset_xmit_timer(sk, ICSK_TIME_DACK, - inet_csk(sk)->icsk_rto, - DCCP_RTO_MAX); - dcb->dccpd_type = DCCP_PKT_DATAACK; - } else if (dccp_ack_pending(sk)) - dcb->dccpd_type = DCCP_PKT_DATAACK; - else - dcb->dccpd_type = DCCP_PKT_DATA; - - err = dccp_transmit_skb(sk, skb); - ccid_hc_tx_packet_sent(dp->dccps_hc_tx_ccid, sk, len); - if (err) - DCCP_BUG("err=%d after ccid_hc_tx_packet_sent", - err); - } else { - dccp_pr_debug("packet discarded due to err=%d\n", err); + } + /* fall through */ + case CCID_PACKET_SEND_AT_ONCE: + dccp_xmit_packet(sk); + break; + case CCID_PACKET_ERR: + skb_dequeue(&sk->sk_write_queue); kfree_skb(skb); + dccp_pr_debug("packet discarded due to err=%d\n", rc); } } } diff --git a/net/dccp/timer.c b/net/dccp/timer.c index 1a9aa05d4dc4..916f9d1dab36 100644 --- a/net/dccp/timer.c +++ b/net/dccp/timer.c @@ -237,32 +237,35 @@ out: sock_put(sk); } -/* Transmit-delay timer: used by the CCIDs to delay actual send time */ -static void dccp_write_xmit_timer(unsigned long data) +/** + * dccp_write_xmitlet - Workhorse for CCID packet dequeueing interface + * See the comments above %ccid_dequeueing_decision for supported modes. + */ +static void dccp_write_xmitlet(unsigned long data) { struct sock *sk = (struct sock *)data; - struct dccp_sock *dp = dccp_sk(sk); bh_lock_sock(sk); if (sock_owned_by_user(sk)) - sk_reset_timer(sk, &dp->dccps_xmit_timer, jiffies+1); + sk_reset_timer(sk, &dccp_sk(sk)->dccps_xmit_timer, jiffies + 1); else dccp_write_xmit(sk, 0); bh_unlock_sock(sk); - sock_put(sk); } -static void dccp_init_write_xmit_timer(struct sock *sk) +static void dccp_write_xmit_timer(unsigned long data) { - struct dccp_sock *dp = dccp_sk(sk); - - setup_timer(&dp->dccps_xmit_timer, dccp_write_xmit_timer, - (unsigned long)sk); + dccp_write_xmitlet(data); + sock_put((struct sock *)data); } void dccp_init_xmit_timers(struct sock *sk) { - dccp_init_write_xmit_timer(sk); + struct dccp_sock *dp = dccp_sk(sk); + + tasklet_init(&dp->dccps_xmitlet, dccp_write_xmitlet, (unsigned long)sk); + setup_timer(&dp->dccps_xmit_timer, dccp_write_xmit_timer, + (unsigned long)sk); inet_csk_init_xmit_timers(sk, &dccp_write_timer, &dccp_delack_timer, &dccp_keepalive_timer); } -- cgit v1.2.3 From b1fcf55eea541af9efa5d39f5a0d1aec8ceca55d Mon Sep 17 00:00:00 2001 From: Gerrit Renker Date: Wed, 27 Oct 2010 19:16:27 +0000 Subject: dccp: Refine the wait-for-ccid mechanism This extends the existing wait-for-ccid routine so that it may be used with different types of CCID, addressing the following problems: 1) The queue-drain mechanism only works with rate-based CCIDs. If CCID-2 for example has a full TX queue and becomes network-limited just as the application wants to close, then waiting for CCID-2 to become unblocked could lead to an indefinite delay (i.e., application "hangs"). 2) Since each TX CCID in turn uses a feedback mechanism, there may be changes in its sending policy while the queue is being drained. This can lead to further delays during which the application will not be able to terminate. 3) The minimum wait time for CCID-3/4 can be expected to be the queue length times the current inter-packet delay. For example if tx_qlen=100 and a delay of 15 ms is used for each packet, then the application would have to wait for a minimum of 1.5 seconds before being allowed to exit. 4) There is no way for the user/application to control this behaviour. It would be good to use the timeout argument of dccp_close() as an upper bound. Then the maximum time that an application is willing to wait for its CCIDs to can be set via the SO_LINGER option. These problems are addressed by giving the CCID a grace period of up to the `timeout' value. The wait-for-ccid function is, as before, used when the application (a) has read all the data in its receive buffer and (b) if SO_LINGER was set with a non-zero linger time, or (c) the socket is either in the OPEN (active close) or in the PASSIVE_CLOSEREQ state (client application closes after receiving CloseReq). In addition, there is a catch-all case of __skb_queue_purge() after waiting for the CCID. This is necessary since the write queue may still have data when (a) the host has been passively-closed, (b) abnormal termination (unread data, zero linger time), (c) wait-for-ccid could not finish within the given time limit. Signed-off-by: Gerrit Renker Signed-off-by: David S. Miller --- net/dccp/dccp.h | 5 ++- net/dccp/output.c | 115 ++++++++++++++++++++++++++++++------------------------ net/dccp/proto.c | 21 +++++++++- net/dccp/timer.c | 2 +- 4 files changed, 89 insertions(+), 54 deletions(-) diff --git a/net/dccp/dccp.h b/net/dccp/dccp.h index 3eb264b60823..a8ed459508b2 100644 --- a/net/dccp/dccp.h +++ b/net/dccp/dccp.h @@ -243,8 +243,9 @@ extern void dccp_reqsk_send_ack(struct sock *sk, struct sk_buff *skb, extern void dccp_send_sync(struct sock *sk, const u64 seq, const enum dccp_pkt_type pkt_type); -extern void dccp_write_xmit(struct sock *sk, int block); -extern void dccp_write_space(struct sock *sk); +extern void dccp_write_xmit(struct sock *sk); +extern void dccp_write_space(struct sock *sk); +extern void dccp_flush_write_queue(struct sock *sk, long *time_budget); extern void dccp_init_xmit_timers(struct sock *sk); static inline void dccp_clear_xmit_timers(struct sock *sk) diff --git a/net/dccp/output.c b/net/dccp/output.c index 11418a9a389d..45b91853f5ae 100644 --- a/net/dccp/output.c +++ b/net/dccp/output.c @@ -209,49 +209,29 @@ void dccp_write_space(struct sock *sk) } /** - * dccp_wait_for_ccid - Wait for ccid to tell us we can send a packet + * dccp_wait_for_ccid - Await CCID send permission * @sk: socket to wait for - * @skb: current skb to pass on for waiting - * @delay: sleep timeout in milliseconds (> 0) - * This function is called by default when the socket is closed, and - * when a non-zero linger time is set on the socket. For consistency + * @delay: timeout in jiffies + * This is used by CCIDs which need to delay the send time in process context. */ -static int dccp_wait_for_ccid(struct sock *sk, struct sk_buff *skb, int delay) +static int dccp_wait_for_ccid(struct sock *sk, unsigned long delay) { - struct dccp_sock *dp = dccp_sk(sk); DEFINE_WAIT(wait); - unsigned long jiffdelay; - int rc; - - do { - dccp_pr_debug("delayed send by %d msec\n", delay); - jiffdelay = msecs_to_jiffies(delay); - - prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE); + long remaining; - sk->sk_write_pending++; - release_sock(sk); - schedule_timeout(jiffdelay); - lock_sock(sk); - sk->sk_write_pending--; + prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE); + sk->sk_write_pending++; + release_sock(sk); - if (sk->sk_err) - goto do_error; - if (signal_pending(current)) - goto do_interrupted; + remaining = schedule_timeout(delay); - rc = ccid_hc_tx_send_packet(dp->dccps_hc_tx_ccid, sk, skb); - } while ((delay = rc) > 0); -out: + lock_sock(sk); + sk->sk_write_pending--; finish_wait(sk_sleep(sk), &wait); - return rc; - -do_error: - rc = -EPIPE; - goto out; -do_interrupted: - rc = -EINTR; - goto out; + + if (signal_pending(current) || sk->sk_err) + return -1; + return remaining; } /** @@ -305,7 +285,53 @@ static void dccp_xmit_packet(struct sock *sk) ccid_hc_tx_packet_sent(dp->dccps_hc_tx_ccid, sk, len); } -void dccp_write_xmit(struct sock *sk, int block) +/** + * dccp_flush_write_queue - Drain queue at end of connection + * Since dccp_sendmsg queues packets without waiting for them to be sent, it may + * happen that the TX queue is not empty at the end of a connection. We give the + * HC-sender CCID a grace period of up to @time_budget jiffies. If this function + * returns with a non-empty write queue, it will be purged later. + */ +void dccp_flush_write_queue(struct sock *sk, long *time_budget) +{ + struct dccp_sock *dp = dccp_sk(sk); + struct sk_buff *skb; + long delay, rc; + + while (*time_budget > 0 && (skb = skb_peek(&sk->sk_write_queue))) { + rc = ccid_hc_tx_send_packet(dp->dccps_hc_tx_ccid, sk, skb); + + switch (ccid_packet_dequeue_eval(rc)) { + case CCID_PACKET_WILL_DEQUEUE_LATER: + /* + * If the CCID determines when to send, the next sending + * time is unknown or the CCID may not even send again + * (e.g. remote host crashes or lost Ack packets). + */ + DCCP_WARN("CCID did not manage to send all packets\n"); + return; + case CCID_PACKET_DELAY: + delay = msecs_to_jiffies(rc); + if (delay > *time_budget) + return; + rc = dccp_wait_for_ccid(sk, delay); + if (rc < 0) + return; + *time_budget -= (delay - rc); + /* check again if we can send now */ + break; + case CCID_PACKET_SEND_AT_ONCE: + dccp_xmit_packet(sk); + break; + case CCID_PACKET_ERR: + skb_dequeue(&sk->sk_write_queue); + kfree_skb(skb); + dccp_pr_debug("packet discarded due to err=%ld\n", rc); + } + } +} + +void dccp_write_xmit(struct sock *sk) { struct dccp_sock *dp = dccp_sk(sk); struct sk_buff *skb; @@ -317,19 +343,9 @@ void dccp_write_xmit(struct sock *sk, int block) case CCID_PACKET_WILL_DEQUEUE_LATER: return; case CCID_PACKET_DELAY: - if (!block) { - sk_reset_timer(sk, &dp->dccps_xmit_timer, - msecs_to_jiffies(rc)+jiffies); - return; - } - rc = dccp_wait_for_ccid(sk, skb, rc); - if (rc && rc != -EINTR) { - DCCP_BUG("err=%d after dccp_wait_for_ccid", rc); - skb_dequeue(&sk->sk_write_queue); - kfree_skb(skb); - break; - } - /* fall through */ + sk_reset_timer(sk, &dp->dccps_xmit_timer, + jiffies + msecs_to_jiffies(rc)); + return; case CCID_PACKET_SEND_AT_ONCE: dccp_xmit_packet(sk); break; @@ -648,7 +664,6 @@ void dccp_send_close(struct sock *sk, const int active) DCCP_SKB_CB(skb)->dccpd_type = DCCP_PKT_CLOSE; if (active) { - dccp_write_xmit(sk, 1); dccp_skb_entail(sk, skb); dccp_transmit_skb(sk, skb_clone(skb, prio)); /* diff --git a/net/dccp/proto.c b/net/dccp/proto.c index 7e5fc04eb6d1..ef343d53fcea 100644 --- a/net/dccp/proto.c +++ b/net/dccp/proto.c @@ -726,7 +726,13 @@ int dccp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, goto out_discard; skb_queue_tail(&sk->sk_write_queue, skb); - dccp_write_xmit(sk,0); + /* + * The xmit_timer is set if the TX CCID is rate-based and will expire + * when congestion control permits to release further packets into the + * network. Window-based CCIDs do not use this timer. + */ + if (!timer_pending(&dp->dccps_xmit_timer)) + dccp_write_xmit(sk); out_release: release_sock(sk); return rc ? : len; @@ -951,9 +957,22 @@ void dccp_close(struct sock *sk, long timeout) /* Check zero linger _after_ checking for unread data. */ sk->sk_prot->disconnect(sk, 0); } else if (sk->sk_state != DCCP_CLOSED) { + /* + * Normal connection termination. May need to wait if there are + * still packets in the TX queue that are delayed by the CCID. + */ + dccp_flush_write_queue(sk, &timeout); dccp_terminate_connection(sk); } + /* + * Flush write queue. This may be necessary in several cases: + * - we have been closed by the peer but still have application data; + * - abortive termination (unread data or zero linger time), + * - normal termination but queue could not be flushed within time limit + */ + __skb_queue_purge(&sk->sk_write_queue); + sk_stream_wait_close(sk, timeout); adjudge_to_death: diff --git a/net/dccp/timer.c b/net/dccp/timer.c index 916f9d1dab36..7587870b7040 100644 --- a/net/dccp/timer.c +++ b/net/dccp/timer.c @@ -249,7 +249,7 @@ static void dccp_write_xmitlet(unsigned long data) if (sock_owned_by_user(sk)) sk_reset_timer(sk, &dccp_sk(sk)->dccps_xmit_timer, jiffies + 1); else - dccp_write_xmit(sk, 0); + dccp_write_xmit(sk); bh_unlock_sock(sk); } -- cgit v1.2.3 From 1c0e0a0569e925220c2948ea9b92fc013895917f Mon Sep 17 00:00:00 2001 From: Gerrit Renker Date: Wed, 27 Oct 2010 19:16:28 +0000 Subject: dccp ccid-2: Stop polling This updates CCID-2 to use the CCID dequeuing mechanism, converting from previous continuous-polling to a now event-driven mechanism. Signed-off-by: Gerrit Renker Signed-off-by: David S. Miller --- net/dccp/ccids/ccid2.c | 23 +++++++++++++++-------- net/dccp/ccids/ccid2.h | 5 +++++ 2 files changed, 20 insertions(+), 8 deletions(-) diff --git a/net/dccp/ccids/ccid2.c b/net/dccp/ccids/ccid2.c index d850e291f87c..6576eae9e779 100644 --- a/net/dccp/ccids/ccid2.c +++ b/net/dccp/ccids/ccid2.c @@ -78,12 +78,9 @@ static int ccid2_hc_tx_alloc_seq(struct ccid2_hc_tx_sock *hc) static int ccid2_hc_tx_send_packet(struct sock *sk, struct sk_buff *skb) { - struct ccid2_hc_tx_sock *hc = ccid2_hc_tx_sk(sk); - - if (hc->tx_pipe < hc->tx_cwnd) - return 0; - - return 1; /* XXX CCID should dequeue when ready instead of polling */ + if (ccid2_cwnd_network_limited(ccid2_hc_tx_sk(sk))) + return CCID_PACKET_WILL_DEQUEUE_LATER; + return CCID_PACKET_SEND_AT_ONCE; } static void ccid2_change_l_ack_ratio(struct sock *sk, u32 val) @@ -115,6 +112,7 @@ static void ccid2_hc_tx_rto_expire(unsigned long data) { struct sock *sk = (struct sock *)data; struct ccid2_hc_tx_sock *hc = ccid2_hc_tx_sk(sk); + const bool sender_was_blocked = ccid2_cwnd_network_limited(hc); bh_lock_sock(sk); if (sock_owned_by_user(sk)) { @@ -129,8 +127,6 @@ static void ccid2_hc_tx_rto_expire(unsigned long data) if (hc->tx_rto > DCCP_RTO_MAX) hc->tx_rto = DCCP_RTO_MAX; - sk_reset_timer(sk, &hc->tx_rtotimer, jiffies + hc->tx_rto); - /* adjust pipe, cwnd etc */ hc->tx_ssthresh = hc->tx_cwnd / 2; if (hc->tx_ssthresh < 2) @@ -146,6 +142,12 @@ static void ccid2_hc_tx_rto_expire(unsigned long data) hc->tx_rpseq = 0; hc->tx_rpdupack = -1; ccid2_change_l_ack_ratio(sk, 1); + + /* if we were blocked before, we may now send cwnd=1 packet */ + if (sender_was_blocked) + tasklet_schedule(&dccp_sk(sk)->dccps_xmitlet); + /* restart backed-off timer */ + sk_reset_timer(sk, &hc->tx_rtotimer, jiffies + hc->tx_rto); out: bh_unlock_sock(sk); sock_put(sk); @@ -434,6 +436,7 @@ static void ccid2_hc_tx_packet_recv(struct sock *sk, struct sk_buff *skb) { struct dccp_sock *dp = dccp_sk(sk); struct ccid2_hc_tx_sock *hc = ccid2_hc_tx_sk(sk); + const bool sender_was_blocked = ccid2_cwnd_network_limited(hc); u64 ackno, seqno; struct ccid2_seq *seqp; unsigned char *vector; @@ -631,6 +634,10 @@ static void ccid2_hc_tx_packet_recv(struct sock *sk, struct sk_buff *skb) sk_stop_timer(sk, &hc->tx_rtotimer); else sk_reset_timer(sk, &hc->tx_rtotimer, jiffies + hc->tx_rto); + + /* check if incoming Acks allow pending packets to be sent */ + if (sender_was_blocked && !ccid2_cwnd_network_limited(hc)) + tasklet_schedule(&dccp_sk(sk)->dccps_xmitlet); } static int ccid2_hc_tx_init(struct ccid *ccid, struct sock *sk) diff --git a/net/dccp/ccids/ccid2.h b/net/dccp/ccids/ccid2.h index 9731c2dc1487..25cb6b216eda 100644 --- a/net/dccp/ccids/ccid2.h +++ b/net/dccp/ccids/ccid2.h @@ -81,6 +81,11 @@ struct ccid2_hc_tx_sock { u64 tx_high_ack; }; +static inline bool ccid2_cwnd_network_limited(struct ccid2_hc_tx_sock *hc) +{ + return hc->tx_pipe >= hc->tx_cwnd; +} + struct ccid2_hc_rx_sock { int rx_data; }; -- cgit v1.2.3 From b7126d8c70a1d4656f1c351de8528df22dfd2d46 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Wed, 27 Oct 2010 23:01:02 +0000 Subject: 8390: Don't oops on starting dev queue The __NS8390_init tries to start the device queue before the device is registered. This results in an oops (snipped): [ 2.865493] BUG: unable to handle kernel NULL pointer dereference at 0000000000000010 [ 2.866106] IP: [] netif_start_queue+0xb/0x12 [8390] [ 2.881267] Call Trace: [ 2.881437] [] __NS8390_init+0x102/0x15a [8390] [ 2.881999] [] NS8390_init+0x9/0xb [8390] [ 2.882237] [] ne2k_pci_init_one+0x297/0x354 [ne2k_pci] [ 2.882955] [] local_pci_probe+0x12/0x16 [ 2.883308] [] pci_device_probe+0xc3/0xef [ 2.884049] [] driver_probe_device+0xbe/0x14b [ 2.884937] [] __driver_attach+0x46/0x62 [ 2.885170] [] bus_for_each_dev+0x49/0x78 [ 2.885781] [] driver_attach+0x1c/0x1e [ 2.886089] [] bus_add_driver+0xba/0x227 [ 2.886330] [] driver_register+0x9e/0x115 [ 2.886933] [] __pci_register_driver+0x50/0xac [ 2.887785] [] ne2k_pci_init+0x2c/0x2e [ne2k_pci] [ 2.888093] [] do_one_initcall+0x7c/0x130 [ 2.888693] [] sys_init_module+0x99/0x1da [ 2.888946] [] system_call_fastpath+0x16/0x1b This happens because the netif_start_queue sets respective bit on the dev->_tx array which is not yet allocated. As far as I understand the code removing the netif_start_queue from __NS8390_init is OK, since queue will be started later on device open. Plz, correct me if I'm wrong. Found in the Dave's current tree, so he's in Cc. Signed-off-by: Pavel Emelyanov Signed-off-by: David S. Miller --- drivers/net/lib8390.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/net/lib8390.c b/drivers/net/lib8390.c index 316bb70775b1..e7030ceb178b 100644 --- a/drivers/net/lib8390.c +++ b/drivers/net/lib8390.c @@ -1077,7 +1077,6 @@ static void __NS8390_init(struct net_device *dev, int startp) ei_outb_p(ei_local->rx_start_page, e8390_base + EN1_CURPAG); ei_outb_p(E8390_NODMA+E8390_PAGE0+E8390_STOP, e8390_base+E8390_CMD); - netif_start_queue(dev); ei_local->tx1 = ei_local->tx2 = 0; ei_local->txing = 0; -- cgit v1.2.3 From 69dcfc8aad24fa95ae0a0ad1405cf6847e3ec14a Mon Sep 17 00:00:00 2001 From: Nishanth Aravamudan Date: Wed, 27 Oct 2010 19:06:30 +0000 Subject: cxgb3: fix crash due to manipulating queues before registration Along the same lines as "cxgb4: fix crash due to manipulating queues before registration" (8f6d9f40476895571df039b6f1f5230ec7faebad), before commit "net: allocate tx queues in register_netdevice" netif_tx_stop_all_queues and related functions could be used between device allocation and registration but now only after registration. cxgb4 has such a call before registration and crashes now. Move it after register_netdev. Signed-off-by: Nishanth Aravamudan Cc: eric.dumazet@gmail.com Cc: sonnyrao@us.ibm.com Cc: Divy Le Ray Cc: Dimitris Michailidis Cc: netdev@vger.kernel.org Cc: linux-kernel@vger.kernel.org Tested-by: Nishanth Aravamudan Acked-by: Divy Le Ray Signed-off-by: David S. Miller --- drivers/net/cxgb3/cxgb3_main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/cxgb3/cxgb3_main.c b/drivers/net/cxgb3/cxgb3_main.c index 4e3c12371aae..407d4e272075 100644 --- a/drivers/net/cxgb3/cxgb3_main.c +++ b/drivers/net/cxgb3/cxgb3_main.c @@ -3301,7 +3301,6 @@ static int __devinit init_one(struct pci_dev *pdev, pi->rx_offload = T3_RX_CSUM | T3_LRO; pi->port_id = i; netif_carrier_off(netdev); - netif_tx_stop_all_queues(netdev); netdev->irq = pdev->irq; netdev->mem_start = mmio_start; netdev->mem_end = mmio_start + mmio_len - 1; @@ -3342,6 +3341,7 @@ static int __devinit init_one(struct pci_dev *pdev, adapter->name = adapter->port[i]->name; __set_bit(i, &adapter->registered_device_map); + netif_tx_stop_all_queues(adapter->port[i]); } } if (!adapter->registered_device_map) { -- cgit v1.2.3 From b1424ed91076db0b19ba4141856150df9b717dde Mon Sep 17 00:00:00 2001 From: Krishna Kumar Date: Wed, 27 Oct 2010 19:10:31 +0000 Subject: cxgb3: Fix panic in free_tx_desc() I got a few of these panics (on 2.6.36-rc7) when running high number of netperf sessions: BUG: unable to handle kernel paging request at 0000100000000000 IP: [] skb_release_data+0xa0/0xd0 Oops: 0000 [#1] SMP Pid: 2155, comm: vhost-2115 Not tainted 2.6.36-rc7-ORG #1 49Y6512 /System x3650 M2 -[7947AC1]- RIP: 0010:[] [] skb_release_data+0xa0/0xd0 RSP: 0018:ffff880001803738 EFLAGS: 00010206 RAX: ffff880179b0fc00 RBX: ffff880178b441c0 RCX: 0000000000000000 RSP: 0018:ffff880001803738 EFLAGS: 00010206 RAX: ffff880179b0fc00 RBX: ffff880178b441c0 RCX: 0000000000000000 RDX: ffff880179b0fd40 RSI: 0000000000000000 RDI: 0000100000000000 RBP: ffff880001803748 R08: 0000000000000001 R09: ffff88017f117000 R10: ffff88017b990608 R11: ffff88017f117090 R12: ffff880178b441c0 R13: ffff88017f117090 R14: 0000000000000000 R15: ffff880178b441c0 FS: 0000000000000000(0000) GS:ffff880001800000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 000000008005003b CR2: 0000100000000000 CR3: 000000017ea64000 CR4: 00000000000026e0 DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 DR3: 0000000000000000 DR6: 00000000ffff0ff0 DR7: 0000000000000400 Process vhost-2115 (pid: 2155, threadinfo ffff88017d872000, task ffff88017e954680) Stack: ffff880178b441c0 0000000000000007 ffff880001803768 ffffffff81312119 <0> 0000000000000000 0000000000000002 ffff880001803778 ffffffff813121f9 <0> ffff880001803818 ffffffffa012d14c ffffffffa02de076 ffff880001803700 Call Trace: [] __kfree_skb+0x19/0xa0 [] kfree_skb+0x19/0x40 [] free_tx_desc+0x2fc/0x350 [cxgb3] [] ? vhost_poll_wakeup+0x16/0x20 [vhost_net] [] t3_eth_xmit+0x28b/0x380 [cxgb3] [] dev_hard_start_xmit+0x377/0x5a0 [] sch_direct_xmit+0xfa/0x1d0 [] dev_queue_xmit+0x139/0x450 [] neigh_resolve_output+0x125/0x340 [] ip_finish_output+0x14c/0x320 [] ip_output+0xae/0xc0 [] ip_forward_finish+0x3f/0x50 [] ip_forward+0x1ff/0x400 [] ip_rcv_finish+0x119/0x3e0 [] ip_rcv+0x22d/0x300 [] __netif_receive_skb+0x29b/0x570 [] ? netif_receive_skb+0x0/0x80 [] netif_receive_skb+0x78/0x80 [] br_handle_frame_finish+0x198/0x260 [bridge] [] br_nf_pre_routing_finish+0x238/0x380 [bridge] [] ? nf_hook_slow+0x6c/0x100 [] ? br_nf_pre_routing_finish+0x0/0x380 [bridge] [] br_nf_pre_routing+0x698/0x7a0 [bridge] [] nf_iterate+0x64/0xa0 [] ? br_handle_frame_finish+0x0/0x260 [bridge] [] nf_hook_slow+0x6c/0x100 [] ? br_handle_frame_finish+0x0/0x260 [bridge] [] br_handle_frame+0x191/0x240 [bridge] [] ? br_handle_frame+0x0/0x240 [bridge] [] __netif_receive_skb+0x1a3/0x570 [] ? dma_issue_pending_all+0x76/0xa0 [] process_backlog+0x102/0x200 [] net_rx_action+0x100/0x220 [] __do_softirq+0xaf/0x140 [] call_softirq+0x1c/0x30 [] ? do_softirq+0x65/0xa0 [] netif_rx_ni+0x28/0x30 [] tun_sendmsg+0x2cd/0x4b0 [tun] [] handle_tx+0x1df/0x340 [vhost_net] [] handle_tx_kick+0x10/0x20 [vhost_net] [] vhost_worker+0xbb/0x130 [vhost_net] [] ? vhost_worker+0x0/0x130 [vhost_net] [] ? vhost_worker+0x0/0x130 [vhost_net] [] kthread+0x96/0xa0 [] kernel_thread_helper+0x4/0x10 [] ? kthread+0x0/0xa0 [] ? kernel_thread_helper+0x0/0x10 Code: 8b 94 24 d0 00 00 00 49 8b 84 24 d8 00 00 00 48 8d 14 10 0f b7 0a 39 d9 7f d1 48 8b 7a 10 48 85 ff 74 20 48 c7 42 10 00 00 00 00 <48> 8b 1f e8 e8 fb ff ff 48 85 db 48 89 df 75 f0 49 8b 84 24 d8 Patch below fixes the panic. cxgb4 and cxgb4vf already have this fix. Signed-off-by: Krishna Kumar Signed-off-by: David S. Miller --- drivers/net/cxgb3/sge.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/net/cxgb3/sge.c b/drivers/net/cxgb3/sge.c index 5d72bda54389..f9f6645b2e61 100644 --- a/drivers/net/cxgb3/sge.c +++ b/drivers/net/cxgb3/sge.c @@ -296,8 +296,10 @@ static void free_tx_desc(struct adapter *adapter, struct sge_txq *q, if (d->skb) { /* an SGL is present */ if (need_unmap) unmap_skb(d->skb, q, cidx, pdev); - if (d->eop) + if (d->eop) { kfree_skb(d->skb); + d->skb = NULL; + } } ++d; if (++cidx == q->size) { -- cgit v1.2.3 From 4aa2c466a7733af093a526e9d1cdd0b3b90d47e9 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Thu, 28 Oct 2010 02:00:43 +0000 Subject: fib: Fix fib zone and its hash leak on namespace stop When we stop a namespace we flush the table and free one, but the added fn_zone-s (and their hashes if grown) are leaked. Need to free. Tries releases all its stuff in the flushing code. Shame on us - this bug exists since the very first make-fib-per-net patches in 2.6.27 :( Signed-off-by: Pavel Emelyanov Signed-off-by: David S. Miller --- include/net/ip_fib.h | 2 ++ net/ipv4/fib_frontend.c | 2 +- net/ipv4/fib_hash.c | 18 ++++++++++++++++++ net/ipv4/fib_trie.c | 5 +++++ 4 files changed, 26 insertions(+), 1 deletion(-) diff --git a/include/net/ip_fib.h b/include/net/ip_fib.h index ba3666d31766..07bdb5e9e8ac 100644 --- a/include/net/ip_fib.h +++ b/include/net/ip_fib.h @@ -158,6 +158,8 @@ extern int fib_table_flush(struct fib_table *table); extern void fib_table_select_default(struct fib_table *table, const struct flowi *flp, struct fib_result *res); +extern void fib_free_table(struct fib_table *tb); + #ifndef CONFIG_IP_MULTIPLE_TABLES diff --git a/net/ipv4/fib_frontend.c b/net/ipv4/fib_frontend.c index 36e27c2107de..eb6f69a8f27a 100644 --- a/net/ipv4/fib_frontend.c +++ b/net/ipv4/fib_frontend.c @@ -1052,7 +1052,7 @@ static void ip_fib_net_exit(struct net *net) hlist_for_each_entry_safe(tb, node, tmp, head, tb_hlist) { hlist_del(node); fib_table_flush(tb); - kfree(tb); + fib_free_table(tb); } } kfree(net->ipv4.fib_table_hash); diff --git a/net/ipv4/fib_hash.c b/net/ipv4/fib_hash.c index b232375a0b75..b3acb0417b21 100644 --- a/net/ipv4/fib_hash.c +++ b/net/ipv4/fib_hash.c @@ -716,6 +716,24 @@ int fib_table_flush(struct fib_table *tb) return found; } +void fib_free_table(struct fib_table *tb) +{ + struct fn_hash *table = (struct fn_hash *) tb->tb_data; + struct fn_zone *fz, *next; + + next = table->fn_zone_list; + while (next != NULL) { + fz = next; + next = fz->fz_next; + + if (fz->fz_hash != fz->fz_embedded_hash) + fz_hash_free(fz->fz_hash, fz->fz_divisor); + + kfree(fz); + } + + kfree(tb); +} static inline int fn_hash_dump_bucket(struct sk_buff *skb, struct netlink_callback *cb, diff --git a/net/ipv4/fib_trie.c b/net/ipv4/fib_trie.c index b14450895102..200eb538fbb3 100644 --- a/net/ipv4/fib_trie.c +++ b/net/ipv4/fib_trie.c @@ -1797,6 +1797,11 @@ int fib_table_flush(struct fib_table *tb) return found; } +void fib_free_table(struct fib_table *tb) +{ + kfree(tb); +} + void fib_table_select_default(struct fib_table *tb, const struct flowi *flp, struct fib_result *res) -- cgit v1.2.3 From 349f6c5c5d827db909a69e5b9e844e8623c8e881 Mon Sep 17 00:00:00 2001 From: Dmitry Artamonow Date: Thu, 28 Oct 2010 10:31:58 -0700 Subject: USB: gadget: fix ethernet gadget crash in gether_setup Crash is triggered by commit e6484930d7 ("net: allocate tx queues in register_netdevice"), which moved tx netqueue creation into register_netdev. So now calling netif_stop_queue() before register_netdev causes an oops. Move netif_stop_queue() after net device registration to fix crash. Signed-off-by: Dmitry Artamonow Signed-off-by: David S. Miller --- drivers/usb/gadget/u_ether.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/gadget/u_ether.c b/drivers/usb/gadget/u_ether.c index 6bb876d65252..cb23355f52d3 100644 --- a/drivers/usb/gadget/u_ether.c +++ b/drivers/usb/gadget/u_ether.c @@ -797,7 +797,6 @@ int gether_setup(struct usb_gadget *g, u8 ethaddr[ETH_ALEN]) * - iff DATA transfer is active, carrier is "on" * - tx queueing enabled if open *and* carrier is "on" */ - netif_stop_queue(net); netif_carrier_off(net); dev->gadget = g; @@ -812,6 +811,7 @@ int gether_setup(struct usb_gadget *g, u8 ethaddr[ETH_ALEN]) INFO(dev, "MAC %pM\n", net->dev_addr); INFO(dev, "HOST MAC %pM\n", dev->host_mac); + netif_stop_queue(net); the_dev = dev; } -- cgit v1.2.3 From 8acfe468b0384e834a303f08ebc4953d72fb690a Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Thu, 28 Oct 2010 11:41:55 -0700 Subject: net: Limit socket I/O iovec total length to INT_MAX. This helps protect us from overflow issues down in the individual protocol sendmsg/recvmsg handlers. Once we hit INT_MAX we truncate out the rest of the iovec by setting the iov_len members to zero. This works because: 1) For SOCK_STREAM and SOCK_SEQPACKET sockets, partial writes are allowed and the application will just continue with another write to send the rest of the data. 2) For datagram oriented sockets, where there must be a one-to-one correspondance between write() calls and packets on the wire, INT_MAX is going to be far larger than the packet size limit the protocol is going to check for and signal with -EMSGSIZE. Based upon a patch by Linus Torvalds. Signed-off-by: David S. Miller --- include/linux/socket.h | 2 +- net/compat.c | 10 ++++++---- net/core/iovec.c | 20 +++++++++----------- 3 files changed, 16 insertions(+), 16 deletions(-) diff --git a/include/linux/socket.h b/include/linux/socket.h index 5146b50202ce..86b652fabf6e 100644 --- a/include/linux/socket.h +++ b/include/linux/socket.h @@ -322,7 +322,7 @@ extern int csum_partial_copy_fromiovecend(unsigned char *kdata, int offset, unsigned int len, __wsum *csump); -extern long verify_iovec(struct msghdr *m, struct iovec *iov, struct sockaddr *address, int mode); +extern int verify_iovec(struct msghdr *m, struct iovec *iov, struct sockaddr *address, int mode); extern int memcpy_toiovec(struct iovec *v, unsigned char *kdata, int len); extern int memcpy_toiovecend(const struct iovec *v, unsigned char *kdata, int offset, int len); diff --git a/net/compat.c b/net/compat.c index 63d260e81472..3649d5895361 100644 --- a/net/compat.c +++ b/net/compat.c @@ -41,10 +41,12 @@ static inline int iov_from_user_compat_to_kern(struct iovec *kiov, compat_size_t len; if (get_user(len, &uiov32->iov_len) || - get_user(buf, &uiov32->iov_base)) { - tot_len = -EFAULT; - break; - } + get_user(buf, &uiov32->iov_base)) + return -EFAULT; + + if (len > INT_MAX - tot_len) + len = INT_MAX - tot_len; + tot_len += len; kiov->iov_base = compat_ptr(buf); kiov->iov_len = (__kernel_size_t) len; diff --git a/net/core/iovec.c b/net/core/iovec.c index 72aceb1fe4fa..c40f27e7d208 100644 --- a/net/core/iovec.c +++ b/net/core/iovec.c @@ -35,10 +35,9 @@ * in any case. */ -long verify_iovec(struct msghdr *m, struct iovec *iov, struct sockaddr *address, int mode) +int verify_iovec(struct msghdr *m, struct iovec *iov, struct sockaddr *address, int mode) { - int size, ct; - long err; + int size, ct, err; if (m->msg_namelen) { if (mode == VERIFY_READ) { @@ -62,14 +61,13 @@ long verify_iovec(struct msghdr *m, struct iovec *iov, struct sockaddr *address, err = 0; for (ct = 0; ct < m->msg_iovlen; ct++) { - err += iov[ct].iov_len; - /* - * Goal is not to verify user data, but to prevent returning - * negative value, which is interpreted as errno. - * Overflow is still possible, but it is harmless. - */ - if (err < 0) - return -EMSGSIZE; + size_t len = iov[ct].iov_len; + + if (len > INT_MAX - err) { + len = INT_MAX - err; + iov[ct].iov_len = len; + } + err += len; } return err; -- cgit v1.2.3 From 448d7b5daf043d109df98e3e8f8deb165c2e8896 Mon Sep 17 00:00:00 2001 From: Nelson Elhage Date: Thu, 28 Oct 2010 11:31:07 -0700 Subject: pktgen: Limit how much data we copy onto the stack. A program that accidentally writes too much data to the pktgen file can overflow the kernel stack and oops the machine. This is only triggerable by root, so there's no security issue, but it's still an unfortunate bug. printk() won't print more than 1024 bytes in a single call, anyways, so let's just never copy more than that much data. We're on a fairly shallow stack, so that should be safe even with CONFIG_4KSTACKS. Signed-off-by: Nelson Elhage Signed-off-by: David S. Miller --- net/core/pktgen.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/net/core/pktgen.c b/net/core/pktgen.c index 679b797d06b1..fbce4b05a53e 100644 --- a/net/core/pktgen.c +++ b/net/core/pktgen.c @@ -887,10 +887,11 @@ static ssize_t pktgen_if_write(struct file *file, i += len; if (debug) { - char tb[count + 1]; - if (copy_from_user(tb, user_buffer, count)) + size_t copy = min(count, 1023); + char tb[copy + 1]; + if (copy_from_user(tb, user_buffer, copy)) return -EFAULT; - tb[count] = 0; + tb[copy] = 0; printk(KERN_DEBUG "pktgen: %s,%lu buffer -:%s:-\n", name, (unsigned long)count, tb); } -- cgit v1.2.3 From 683b65f89a7c26d9a9180d25066815ef5a31bd71 Mon Sep 17 00:00:00 2001 From: Rajesh Borundia Date: Tue, 26 Oct 2010 22:51:50 +0000 Subject: netxen: fix kdump Reset the whole hw instead of freeing hw resources consumed by each pci function. Signed-off-by: Rajesh Borundia Signed-off-by: Amit Kumar Salecha Signed-off-by: David S. Miller --- drivers/net/netxen/netxen_nic_ctx.c | 15 --------------- drivers/net/netxen/netxen_nic_main.c | 7 +++++++ 2 files changed, 7 insertions(+), 15 deletions(-) diff --git a/drivers/net/netxen/netxen_nic_ctx.c b/drivers/net/netxen/netxen_nic_ctx.c index 12612127a087..f7d06cbc70ae 100644 --- a/drivers/net/netxen/netxen_nic_ctx.c +++ b/drivers/net/netxen/netxen_nic_ctx.c @@ -254,19 +254,6 @@ out_free_rq: return err; } -static void -nx_fw_cmd_reset_ctx(struct netxen_adapter *adapter) -{ - - netxen_issue_cmd(adapter, adapter->ahw.pci_func, NXHAL_VERSION, - adapter->ahw.pci_func, NX_DESTROY_CTX_RESET, 0, - NX_CDRP_CMD_DESTROY_RX_CTX); - - netxen_issue_cmd(adapter, adapter->ahw.pci_func, NXHAL_VERSION, - adapter->ahw.pci_func, NX_DESTROY_CTX_RESET, 0, - NX_CDRP_CMD_DESTROY_TX_CTX); -} - static void nx_fw_cmd_destroy_rx_ctx(struct netxen_adapter *adapter) { @@ -698,8 +685,6 @@ int netxen_alloc_hw_resources(struct netxen_adapter *adapter) if (!NX_IS_REVISION_P2(adapter->ahw.revision_id)) { if (test_and_set_bit(__NX_FW_ATTACHED, &adapter->state)) goto done; - if (reset_devices) - nx_fw_cmd_reset_ctx(adapter); err = nx_fw_cmd_create_rx_ctx(adapter); if (err) goto err_out_free; diff --git a/drivers/net/netxen/netxen_nic_main.c b/drivers/net/netxen/netxen_nic_main.c index 50820beac3aa..35ae1aa12896 100644 --- a/drivers/net/netxen/netxen_nic_main.c +++ b/drivers/net/netxen/netxen_nic_main.c @@ -1356,6 +1356,13 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) break; } + if (reset_devices) { + if (adapter->portnum == 0) { + NXWR32(adapter, NX_CRB_DEV_REF_COUNT, 0); + adapter->need_fw_reset = 1; + } + } + err = netxen_start_firmware(adapter); if (err) goto err_out_decr_ref; -- cgit v1.2.3 From d1abc9a9aca06ceb795eb5405264eaafe016ec5c Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Thu, 28 Oct 2010 11:34:58 -0700 Subject: net: atarilance - flags should be unsigned long MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit drivers/net/atarilance.c: In function ‘addr_accessible’: drivers/net/atarilance.c:413: warning: comparison of distinct pointer types lacks a cast drivers/net/atarilance.c:450: warning: comparison of distinct pointer types lacks a cast Signed-off-by: Geert Uytterhoeven Signed-off-by: David S. Miller --- drivers/net/atarilance.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/atarilance.c b/drivers/net/atarilance.c index 3134e5326231..8cb27cb7bca1 100644 --- a/drivers/net/atarilance.c +++ b/drivers/net/atarilance.c @@ -407,7 +407,7 @@ static noinline int __init addr_accessible(volatile void *regp, int wordflag, int writeflag) { int ret; - long flags; + unsigned long flags; long *vbr, save_berr; local_irq_save(flags); -- cgit v1.2.3 From 19449bfc10d163f0024dd5ae5808e28cda32e7b4 Mon Sep 17 00:00:00 2001 From: avisconti Date: Mon, 25 Oct 2010 18:58:14 +0000 Subject: stmmac: enable/disable rx/tx in the core with a single write. This patch enables and disables the rx and tx bits in the MAC control reg by using a single write operation. This also solves a possible problem (spotted on SPEAr platforms) at 10Mbps where two consecutive writes to a MAC control register can take more than 4 phy_clk cycles. Signed-off-by: Armando Visconti Acked-by: Giuseppe Cavallaro Signed-off-by: David S. Miller --- drivers/net/stmmac/stmmac_main.c | 40 ++++++++++------------------------------ 1 file changed, 10 insertions(+), 30 deletions(-) diff --git a/drivers/net/stmmac/stmmac_main.c b/drivers/net/stmmac/stmmac_main.c index 823b9e6431d5..06bc6034ce81 100644 --- a/drivers/net/stmmac/stmmac_main.c +++ b/drivers/net/stmmac/stmmac_main.c @@ -337,33 +337,19 @@ static int stmmac_init_phy(struct net_device *dev) return 0; } -static inline void stmmac_mac_enable_rx(void __iomem *ioaddr) +static inline void stmmac_enable_mac(void __iomem *ioaddr) { u32 value = readl(ioaddr + MAC_CTRL_REG); - value |= MAC_RNABLE_RX; - /* Set the RE (receive enable bit into the MAC CTRL register). */ - writel(value, ioaddr + MAC_CTRL_REG); -} -static inline void stmmac_mac_enable_tx(void __iomem *ioaddr) -{ - u32 value = readl(ioaddr + MAC_CTRL_REG); - value |= MAC_ENABLE_TX; - /* Set the TE (transmit enable bit into the MAC CTRL register). */ + value |= MAC_RNABLE_RX | MAC_ENABLE_TX; writel(value, ioaddr + MAC_CTRL_REG); } -static inline void stmmac_mac_disable_rx(void __iomem *ioaddr) +static inline void stmmac_disable_mac(void __iomem *ioaddr) { u32 value = readl(ioaddr + MAC_CTRL_REG); - value &= ~MAC_RNABLE_RX; - writel(value, ioaddr + MAC_CTRL_REG); -} -static inline void stmmac_mac_disable_tx(void __iomem *ioaddr) -{ - u32 value = readl(ioaddr + MAC_CTRL_REG); - value &= ~MAC_ENABLE_TX; + value &= ~(MAC_ENABLE_TX | MAC_RNABLE_RX); writel(value, ioaddr + MAC_CTRL_REG); } @@ -857,8 +843,7 @@ static int stmmac_open(struct net_device *dev) writel(0xffffffff, priv->ioaddr + MMC_LOW_INTR_MASK); /* Enable the MAC Rx/Tx */ - stmmac_mac_enable_rx(priv->ioaddr); - stmmac_mac_enable_tx(priv->ioaddr); + stmmac_enable_mac(priv->ioaddr); /* Set the HW DMA mode and the COE */ stmmac_dma_operation_mode(priv); @@ -928,9 +913,8 @@ static int stmmac_release(struct net_device *dev) /* Release and free the Rx/Tx resources */ free_dma_desc_resources(priv); - /* Disable the MAC core */ - stmmac_mac_disable_tx(priv->ioaddr); - stmmac_mac_disable_rx(priv->ioaddr); + /* Disable the MAC Rx/Tx */ + stmmac_disable_mac(priv->ioaddr); netif_carrier_off(dev); @@ -1787,8 +1771,7 @@ static int stmmac_dvr_remove(struct platform_device *pdev) priv->hw->dma->stop_rx(priv->ioaddr); priv->hw->dma->stop_tx(priv->ioaddr); - stmmac_mac_disable_rx(priv->ioaddr); - stmmac_mac_disable_tx(priv->ioaddr); + stmmac_disable_mac(priv->ioaddr); netif_carrier_off(ndev); @@ -1839,13 +1822,11 @@ static int stmmac_suspend(struct platform_device *pdev, pm_message_t state) dis_ic); priv->hw->desc->init_tx_desc(priv->dma_tx, priv->dma_tx_size); - stmmac_mac_disable_tx(priv->ioaddr); - /* Enable Power down mode by programming the PMT regs */ if (device_can_wakeup(priv->device)) priv->hw->mac->pmt(priv->ioaddr, priv->wolopts); else - stmmac_mac_disable_rx(priv->ioaddr); + stmmac_disable_mac(priv->ioaddr); } else { priv->shutdown = 1; /* Although this can appear slightly redundant it actually @@ -1886,8 +1867,7 @@ static int stmmac_resume(struct platform_device *pdev) netif_device_attach(dev); /* Enable the MAC and DMA */ - stmmac_mac_enable_rx(priv->ioaddr); - stmmac_mac_enable_tx(priv->ioaddr); + stmmac_enable_mac(priv->ioaddr); priv->hw->dma->start_tx(priv->ioaddr); priv->hw->dma->start_rx(priv->ioaddr); -- cgit v1.2.3 From 089282fb028198169a0f62f8f833ab6d06bdbb3c Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Thu, 28 Oct 2010 12:59:53 -0700 Subject: netfilter: xt_socket: Make tproto signed in socket_mt6_v1(). Otherwise error indications from ipv6_find_hdr() won't be noticed. This required making the protocol argument to extract_icmp6_fields() signed too. Reported-by: Geert Uytterhoeven Signed-off-by: David S. Miller --- net/netfilter/xt_socket.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/net/netfilter/xt_socket.c b/net/netfilter/xt_socket.c index d94a858dc52a..00d6ae838303 100644 --- a/net/netfilter/xt_socket.c +++ b/net/netfilter/xt_socket.c @@ -195,7 +195,7 @@ socket_mt4_v1(const struct sk_buff *skb, struct xt_action_param *par) static int extract_icmp6_fields(const struct sk_buff *skb, unsigned int outside_hdrlen, - u8 *protocol, + int *protocol, struct in6_addr **raddr, struct in6_addr **laddr, __be16 *rport, @@ -252,8 +252,7 @@ socket_mt6_v1(const struct sk_buff *skb, struct xt_action_param *par) struct sock *sk; struct in6_addr *daddr, *saddr; __be16 dport, sport; - int thoff; - u8 tproto; + int thoff, tproto; const struct xt_socket_mtinfo1 *info = (struct xt_socket_mtinfo1 *) par->matchinfo; tproto = ipv6_find_hdr(skb, &thoff, -1, NULL); @@ -305,7 +304,7 @@ socket_mt6_v1(const struct sk_buff *skb, struct xt_action_param *par) sk = NULL; } - pr_debug("proto %hhu %pI6:%hu -> %pI6:%hu " + pr_debug("proto %hhd %pI6:%hu -> %pI6:%hu " "(orig %pI6:%hu) sock %p\n", tproto, saddr, ntohs(sport), daddr, ntohs(dport), -- cgit v1.2.3 From 4fc4fbd1d9a05fa4f348b499aca3a6f8d3c9bbe6 Mon Sep 17 00:00:00 2001 From: Mohammed Shafi Shajakhan Date: Thu, 28 Oct 2010 19:51:47 +0530 Subject: 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; -- cgit v1.2.3 From 731b2034999bbfe86c9074f1b0d611940bf7c323 Mon Sep 17 00:00:00 2001 From: Paul Fox Date: Fri, 29 Oct 2010 14:57:28 +0100 Subject: 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 */ -- cgit v1.2.3 From 520efd1ace3f826120482e57a95d649b4e1c1684 Mon Sep 17 00:00:00 2001 From: Jesper Juhl Date: Fri, 29 Oct 2010 16:10:26 +0200 Subject: 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]); -- cgit v1.2.3 From 9f2a0fac625bcef9c579bcf0b0c904ab1a56e7c4 Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Thu, 28 Oct 2010 10:43:26 -0500 Subject: 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); } -- cgit v1.2.3