From ae023b2795d36f0f077e157428eb7eafa29ee412 Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Mon, 21 Jan 2013 13:12:57 +0200 Subject: Revert "iwlwifi: fix the reclaimed packet tracking upon flush queue" This reverts commit f590dcec944552f9a4a61155810f3abd17d6465d which has been reported to cause issues. See https://lkml.org/lkml/2013/1/20/4 for further details. Cc: stable@vger.kernel.org [3.7] Signed-off-by: Emmanuel Grumbach Signed-off-by: Johannes Berg diff --git a/drivers/net/wireless/iwlwifi/dvm/tx.c b/drivers/net/wireless/iwlwifi/dvm/tx.c index 31534f7..2797964 100644 --- a/drivers/net/wireless/iwlwifi/dvm/tx.c +++ b/drivers/net/wireless/iwlwifi/dvm/tx.c @@ -1153,6 +1153,13 @@ int iwlagn_rx_reply_tx(struct iwl_priv *priv, struct iwl_rx_cmd_buffer *rxb, next_reclaimed = ssn; } + if (tid != IWL_TID_NON_QOS) { + priv->tid_data[sta_id][tid].next_reclaimed = + next_reclaimed; + IWL_DEBUG_TX_REPLY(priv, "Next reclaimed packet:%d\n", + next_reclaimed); + } + iwl_trans_reclaim(priv->trans, txq_id, ssn, &skbs); iwlagn_check_ratid_empty(priv, sta_id, tid); @@ -1203,28 +1210,11 @@ int iwlagn_rx_reply_tx(struct iwl_priv *priv, struct iwl_rx_cmd_buffer *rxb, if (!is_agg) iwlagn_non_agg_tx_status(priv, ctx, hdr->addr1); - /* - * W/A for FW bug - the seq_ctl isn't updated when the - * queues are flushed. Fetch it from the packet itself - */ - if (!is_agg && status == TX_STATUS_FAIL_FIFO_FLUSHED) { - next_reclaimed = le16_to_cpu(hdr->seq_ctrl); - next_reclaimed = - SEQ_TO_SN(next_reclaimed + 0x10); - } - is_offchannel_skb = (info->flags & IEEE80211_TX_CTL_TX_OFFCHAN); freed++; } - if (tid != IWL_TID_NON_QOS) { - priv->tid_data[sta_id][tid].next_reclaimed = - next_reclaimed; - IWL_DEBUG_TX_REPLY(priv, "Next reclaimed packet:%d\n", - next_reclaimed); - } - WARN_ON(!is_agg && freed != 1); /* -- cgit v0.10.2 From c49dc9008b1c641a86837297df7c90cef070571b Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Thu, 24 Jan 2013 09:40:00 +0300 Subject: cfg80211: off by one in ieee80211_bss() We do a: sprintf(buf, " Last beacon: %ums ago", elapsed_jiffies_msecs(bss->ts)); elapsed_jiffies_msecs() can return a 10 digit number so "buf" needs to be 31 characters long. Signed-off-by: Dan Carpenter Signed-off-by: Johannes Berg diff --git a/net/wireless/scan.c b/net/wireless/scan.c index 01592d7..45f1618 100644 --- a/net/wireless/scan.c +++ b/net/wireless/scan.c @@ -1358,7 +1358,7 @@ ieee80211_bss(struct wiphy *wiphy, struct iw_request_info *info, &iwe, IW_EV_UINT_LEN); } - buf = kmalloc(30, GFP_ATOMIC); + buf = kmalloc(31, GFP_ATOMIC); if (buf) { memset(&iwe, 0, sizeof(iwe)); iwe.cmd = IWEVCUSTOM; -- cgit v0.10.2 From 0e33e48ddc4402e890aaeeeacc95f730bf522098 Mon Sep 17 00:00:00 2001 From: Arend van Spriel Date: Tue, 22 Jan 2013 22:47:40 +0100 Subject: brcmsmac: fix tx status processing This issue was reported on the wireless list (see [1]) in which brcmsmac ran into a fatal error: [ 588.284074] brcmsmac bcma0:0: frameid != txh->TxFrameID [ 588.284098] brcmsmac bcma0:0: MI_TFS: fatal [ 588.284103] brcmsmac bcma0:0: wl0: fatal error, reinitializing [ 588.286208] ieee80211 phy0: Hardware restart was requested The tx status feedback is processed in a loop limiting the number of frames processed in one run. The code terminate processing when the limit is reached regardless the txstatus value read from the device register. When that status is is flagged as being valid it must be processed as the hardware will clear it after is has been read. Bisecting was done by Seth Forshee and showed following commit as the culprit: commit 57fe504817ccec9b6ac23e973d2925343bf1e3b6 Author: Piotr Haber Date: Wed Nov 28 21:44:07 2012 +0100 brcmsmac: fix bounds checking in tx/rx [1] http://www.spinics.net/lists/linux-wireless/msg101293.html Reported-by: Linus Torvalds Tested-by: Seth Forshee Reviewed-by: Hante Meuleman Reviewed-by: Pieter-Paul Giesberts Signed-off-by: Arend van Spriel Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/brcm80211/brcmsmac/main.c b/drivers/net/wireless/brcm80211/brcmsmac/main.c index 17594de..9f3d7e9 100644 --- a/drivers/net/wireless/brcm80211/brcmsmac/main.c +++ b/drivers/net/wireless/brcm80211/brcmsmac/main.c @@ -1027,7 +1027,6 @@ brcms_c_dotxstatus(struct brcms_c_info *wlc, struct tx_status *txs) static bool brcms_b_txstatus(struct brcms_hardware *wlc_hw, bool bound, bool *fatal) { - bool morepending = false; struct bcma_device *core; struct tx_status txstatus, *txs; u32 s1, s2; @@ -1041,23 +1040,20 @@ brcms_b_txstatus(struct brcms_hardware *wlc_hw, bool bound, bool *fatal) txs = &txstatus; core = wlc_hw->d11core; *fatal = false; - s1 = bcma_read32(core, D11REGOFFS(frmtxstatus)); - while (!(*fatal) - && (s1 & TXS_V)) { - /* !give others some time to run! */ - if (n >= max_tx_num) { - morepending = true; - break; - } + while (n < max_tx_num) { + s1 = bcma_read32(core, D11REGOFFS(frmtxstatus)); if (s1 == 0xffffffff) { brcms_err(core, "wl%d: %s: dead chip\n", wlc_hw->unit, __func__); *fatal = true; return false; } - s2 = bcma_read32(core, D11REGOFFS(frmtxstatus2)); + /* only process when valid */ + if (!(s1 & TXS_V)) + break; + s2 = bcma_read32(core, D11REGOFFS(frmtxstatus2)); txs->status = s1 & TXS_STATUS_MASK; txs->frameid = (s1 & TXS_FID_MASK) >> TXS_FID_SHIFT; txs->sequence = s2 & TXS_SEQ_MASK; @@ -1065,15 +1061,12 @@ brcms_b_txstatus(struct brcms_hardware *wlc_hw, bool bound, bool *fatal) txs->lasttxtime = 0; *fatal = brcms_c_dotxstatus(wlc_hw->wlc, txs); - - s1 = bcma_read32(core, D11REGOFFS(frmtxstatus)); + if (*fatal == true) + return false; n++; } - if (*fatal) - return false; - - return morepending; + return n >= max_tx_num; } static void brcms_c_tbtt(struct brcms_c_info *wlc) -- cgit v0.10.2 From 6b112decb777884e37d308554e22e0a4f5cdf44f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Sun, 27 Jan 2013 14:30:29 +0100 Subject: bcma: fix NAND flash validation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Rafał Miłecki Signed-off-by: John W. Linville diff --git a/drivers/bcma/driver_chipcommon_nflash.c b/drivers/bcma/driver_chipcommon_nflash.c index dbda91e..1f0b83e 100644 --- a/drivers/bcma/driver_chipcommon_nflash.c +++ b/drivers/bcma/driver_chipcommon_nflash.c @@ -21,7 +21,7 @@ int bcma_nflash_init(struct bcma_drv_cc *cc) struct bcma_bus *bus = cc->core->bus; if (bus->chipinfo.id != BCMA_CHIP_ID_BCM4706 && - cc->core->id.rev != 0x38) { + cc->core->id.rev != 38) { bcma_err(bus, "NAND flash on unsupported board!\n"); return -ENOTSUPP; } -- cgit v0.10.2 From 0a06ad8e3a1cb5311b7dbafde45410aa1bce9d40 Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Sun, 27 Jan 2013 16:24:25 -0600 Subject: rtlwifi: Fix the usage of the wrong variable in usb.c In routine _rtl_rx_pre_process(), skb_dequeue() is called to get an skb; however, the wrong variable name is used in subsequent calls. Reported-by: Guenter Roeck Signed-off-by: Larry Finger Cc: Guenter Roeck Cc: Stable Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rtlwifi/usb.c b/drivers/net/wireless/rtlwifi/usb.c index f2ecdeb..1535efd 100644 --- a/drivers/net/wireless/rtlwifi/usb.c +++ b/drivers/net/wireless/rtlwifi/usb.c @@ -542,8 +542,8 @@ static void _rtl_rx_pre_process(struct ieee80211_hw *hw, struct sk_buff *skb) WARN_ON(skb_queue_empty(&rx_queue)); while (!skb_queue_empty(&rx_queue)) { _skb = skb_dequeue(&rx_queue); - _rtl_usb_rx_process_agg(hw, skb); - ieee80211_rx_irqsafe(hw, skb); + _rtl_usb_rx_process_agg(hw, _skb); + ieee80211_rx_irqsafe(hw, _skb); } } -- cgit v0.10.2 From 8a7d7cbf7b5ff9912ef50b3e94c9ad9f37b1c75f Mon Sep 17 00:00:00 2001 From: Bing Zhao Date: Tue, 29 Jan 2013 14:38:02 -0800 Subject: mwifiex: fix incomplete scan in case of IE parsing error A scan request is split into multiple scan commands queued in scan_pending_q. Each scan command will be sent to firmware and its response is handlded one after another. If any error is detected while parsing IE in command response buffer the remaining data will be ignored and error is returned. We should check if there is any more scan commands pending in the queue before returning error. This ensures that we will call cfg80211_scan_done if this is the last scan command, or send next scan command in scan_pending_q to firmware. Cc: "3.6+" Signed-off-by: Bing Zhao Signed-off-by: Amitkumar Karwar Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/mwifiex/scan.c b/drivers/net/wireless/mwifiex/scan.c index 9189a32..973a9d9 100644 --- a/drivers/net/wireless/mwifiex/scan.c +++ b/drivers/net/wireless/mwifiex/scan.c @@ -1563,7 +1563,7 @@ int mwifiex_ret_802_11_scan(struct mwifiex_private *priv, dev_err(adapter->dev, "SCAN_RESP: too many AP returned (%d)\n", scan_rsp->number_of_sets); ret = -1; - goto done; + goto check_next_scan; } bytes_left = le16_to_cpu(scan_rsp->bss_descript_size); @@ -1634,7 +1634,8 @@ int mwifiex_ret_802_11_scan(struct mwifiex_private *priv, if (!beacon_size || beacon_size > bytes_left) { bss_info += bytes_left; bytes_left = 0; - return -1; + ret = -1; + goto check_next_scan; } /* Initialize the current working beacon pointer for this BSS @@ -1690,7 +1691,7 @@ int mwifiex_ret_802_11_scan(struct mwifiex_private *priv, dev_err(priv->adapter->dev, "%s: bytes left < IE length\n", __func__); - goto done; + goto check_next_scan; } if (element_id == WLAN_EID_DS_PARAMS) { channel = *(current_ptr + sizeof(struct ieee_types_header)); @@ -1753,6 +1754,7 @@ int mwifiex_ret_802_11_scan(struct mwifiex_private *priv, } } +check_next_scan: spin_lock_irqsave(&adapter->scan_pending_q_lock, flags); if (list_empty(&adapter->scan_pending_q)) { spin_unlock_irqrestore(&adapter->scan_pending_q_lock, flags); @@ -1813,7 +1815,6 @@ int mwifiex_ret_802_11_scan(struct mwifiex_private *priv, } } -done: return ret; } -- cgit v0.10.2 From 8cf9fa1240229cbdd888236c0c43fcbad680cf00 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Tue, 29 Jan 2013 10:44:23 -0600 Subject: Bluetooth: Fix handling of unexpected SMP PDUs The conn->smp_chan pointer can be NULL if SMP PDUs arrive at unexpected moments. To avoid NULL pointer dereferences the code should be checking for this and disconnect if an unexpected SMP PDU arrives. This patch fixes the issue by adding a check for conn->smp_chan for all other PDUs except pairing request and security request (which are are the first PDUs to come to initialize the SMP context). Signed-off-by: Johan Hedberg CC: stable@vger.kernel.org Acked-by: Marcel Holtmann Signed-off-by: Gustavo Padovan diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index 68a9587..5abefb1 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -859,6 +859,19 @@ int smp_sig_channel(struct l2cap_conn *conn, struct sk_buff *skb) skb_pull(skb, sizeof(code)); + /* + * The SMP context must be initialized for all other PDUs except + * pairing and security requests. If we get any other PDU when + * not initialized simply disconnect (done if this function + * returns an error). + */ + if (code != SMP_CMD_PAIRING_REQ && code != SMP_CMD_SECURITY_REQ && + !conn->smp_chan) { + BT_ERR("Unexpected SMP command 0x%02x. Disconnecting.", code); + kfree_skb(skb); + return -ENOTSUPP; + } + switch (code) { case SMP_CMD_PAIRING_REQ: reason = smp_cmd_pairing_req(conn, skb); -- cgit v0.10.2 From 4c02e2d444595200d0b18b889994aac3611cd288 Mon Sep 17 00:00:00 2001 From: Andre Guedes Date: Wed, 30 Jan 2013 11:50:55 -0300 Subject: Bluetooth: Fix hci_conn timeout routine If occurs a LE or SCO hci_conn timeout and the connection is already established (BT_CONNECTED state), the connection is not terminated as expected. This bug can be reproduced using l2test or scotest tool. Once the connection is established, kill l2test/scotest and the connection won't be terminated. This patch fixes hci_conn_disconnect helper so it is able to terminate LE and SCO connections, as well as ACL. Signed-off-by: Andre Guedes Signed-off-by: Gustavo Padovan diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index 25bfce0..4925a02 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c @@ -249,12 +249,12 @@ static void hci_conn_disconnect(struct hci_conn *conn) __u8 reason = hci_proto_disconn_ind(conn); switch (conn->type) { - case ACL_LINK: - hci_acl_disconn(conn, reason); - break; case AMP_LINK: hci_amp_disconn(conn, reason); break; + default: + hci_acl_disconn(conn, reason); + break; } } -- cgit v0.10.2 From a5ffbe0a1993a27072742ef7db6cf9839956fce9 Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Sat, 2 Feb 2013 15:55:00 -0600 Subject: rtlwifi: Fix scheduling while atomic bug Kernel commits 41affd5 and 6539306 changed the locking in rtl_lps_leave() from a spinlock to a mutex by doing the calls indirectly from a work queue to reduce the time that interrupts were disabled. This change was fine for most systems; however a scheduling while atomic bug was reported in https://bugzilla.redhat.com/show_bug.cgi?id=903881. The backtrace indicates that routine rtl_is_special(), which calls rtl_lps_leave() in three places was entered in atomic context. These direct calls are replaced by putting a request on the appropriate work queue. Signed-off-by: Larry Finger Reported-and-tested-by: Nathaniel Doherty Cc: Nathaniel Doherty Cc: Stanislaw Gruszka Cc: Stable Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rtlwifi/base.c b/drivers/net/wireless/rtlwifi/base.c index 4494d13..0f8b051 100644 --- a/drivers/net/wireless/rtlwifi/base.c +++ b/drivers/net/wireless/rtlwifi/base.c @@ -1004,7 +1004,8 @@ u8 rtl_is_special_data(struct ieee80211_hw *hw, struct sk_buff *skb, u8 is_tx) is_tx ? "Tx" : "Rx"); if (is_tx) { - rtl_lps_leave(hw); + schedule_work(&rtlpriv-> + works.lps_leave_work); ppsc->last_delaylps_stamp_jiffies = jiffies; } @@ -1014,7 +1015,7 @@ u8 rtl_is_special_data(struct ieee80211_hw *hw, struct sk_buff *skb, u8 is_tx) } } else if (ETH_P_ARP == ether_type) { if (is_tx) { - rtl_lps_leave(hw); + schedule_work(&rtlpriv->works.lps_leave_work); ppsc->last_delaylps_stamp_jiffies = jiffies; } @@ -1024,7 +1025,7 @@ u8 rtl_is_special_data(struct ieee80211_hw *hw, struct sk_buff *skb, u8 is_tx) "802.1X %s EAPOL pkt!!\n", is_tx ? "Tx" : "Rx"); if (is_tx) { - rtl_lps_leave(hw); + schedule_work(&rtlpriv->works.lps_leave_work); ppsc->last_delaylps_stamp_jiffies = jiffies; } -- cgit v0.10.2 From c50ae9470e542862f782e2d9c106270152bbf3ce Mon Sep 17 00:00:00 2001 From: Hauke Mehrtens Date: Sun, 3 Feb 2013 23:25:33 +0100 Subject: bcma: unregister gpios before unloading bcma This patch unregisters the gpio chip before bcma gets unloaded. Signed-off-by: Hauke Mehrtens Reported-by: Piotr Haber Signed-off-by: John W. Linville diff --git a/drivers/bcma/bcma_private.h b/drivers/bcma/bcma_private.h index 4a2d72e..966ce4d 100644 --- a/drivers/bcma/bcma_private.h +++ b/drivers/bcma/bcma_private.h @@ -94,11 +94,16 @@ void __devinit bcma_core_pci_hostmode_init(struct bcma_drv_pci *pc); #ifdef CONFIG_BCMA_DRIVER_GPIO /* driver_gpio.c */ int bcma_gpio_init(struct bcma_drv_cc *cc); +int bcma_gpio_unregister(struct bcma_drv_cc *cc); #else static inline int bcma_gpio_init(struct bcma_drv_cc *cc) { return -ENOTSUPP; } +static inline int bcma_gpio_unregister(struct bcma_drv_cc *cc) +{ + return 0; +} #endif /* CONFIG_BCMA_DRIVER_GPIO */ #endif diff --git a/drivers/bcma/driver_gpio.c b/drivers/bcma/driver_gpio.c index 9a6f585..71f755c 100644 --- a/drivers/bcma/driver_gpio.c +++ b/drivers/bcma/driver_gpio.c @@ -96,3 +96,8 @@ int bcma_gpio_init(struct bcma_drv_cc *cc) return gpiochip_add(chip); } + +int bcma_gpio_unregister(struct bcma_drv_cc *cc) +{ + return gpiochip_remove(&cc->gpio); +} diff --git a/drivers/bcma/main.c b/drivers/bcma/main.c index 53ba20c..e08b9c6 100644 --- a/drivers/bcma/main.c +++ b/drivers/bcma/main.c @@ -268,6 +268,13 @@ int __devinit bcma_bus_register(struct bcma_bus *bus) void bcma_bus_unregister(struct bcma_bus *bus) { struct bcma_device *cores[3]; + int err; + + err = bcma_gpio_unregister(&bus->drv_cc); + if (err == -EBUSY) + bcma_err(bus, "Some GPIOs are still in use.\n"); + else if (err) + bcma_err(bus, "Can not unregister GPIO driver: %i\n", err); cores[0] = bcma_find_core(bus, BCMA_CORE_MIPS_74K); cores[1] = bcma_find_core(bus, BCMA_CORE_PCIE); -- cgit v0.10.2 From 600485edaef65d89f5c44ce62baa7cac961cd50d Mon Sep 17 00:00:00 2001 From: Hauke Mehrtens Date: Sun, 3 Feb 2013 23:25:34 +0100 Subject: ssb: unregister gpios before unloading ssb This patch unregisters the gpio chip before ssb gets unloaded. Signed-off-by: Hauke Mehrtens Signed-off-by: John W. Linville diff --git a/drivers/ssb/driver_gpio.c b/drivers/ssb/driver_gpio.c index 97ac0a3..eb27530 100644 --- a/drivers/ssb/driver_gpio.c +++ b/drivers/ssb/driver_gpio.c @@ -174,3 +174,15 @@ int ssb_gpio_init(struct ssb_bus *bus) return -1; } + +int ssb_gpio_unregister(struct ssb_bus *bus) +{ + if (ssb_chipco_available(&bus->chipco) || + ssb_extif_available(&bus->extif)) { + return gpiochip_remove(&bus->gpio); + } else { + SSB_WARN_ON(1); + } + + return -1; +} diff --git a/drivers/ssb/main.c b/drivers/ssb/main.c index c82c5c9..7140c88 100644 --- a/drivers/ssb/main.c +++ b/drivers/ssb/main.c @@ -443,6 +443,15 @@ static void ssb_devices_unregister(struct ssb_bus *bus) void ssb_bus_unregister(struct ssb_bus *bus) { + int err; + + err = ssb_gpio_unregister(bus); + if (err == -EBUSY) + ssb_dprintk(KERN_ERR PFX "Some GPIOs are still in use.\n"); + else if (err) + ssb_dprintk(KERN_ERR PFX + "Can not unregister GPIO driver: %i\n", err); + ssb_buses_lock(); ssb_devices_unregister(bus); list_del(&bus->list); diff --git a/drivers/ssb/ssb_private.h b/drivers/ssb/ssb_private.h index 6c10b66..da38305 100644 --- a/drivers/ssb/ssb_private.h +++ b/drivers/ssb/ssb_private.h @@ -252,11 +252,16 @@ static inline void ssb_extif_init(struct ssb_extif *extif) #ifdef CONFIG_SSB_DRIVER_GPIO extern int ssb_gpio_init(struct ssb_bus *bus); +extern int ssb_gpio_unregister(struct ssb_bus *bus); #else /* CONFIG_SSB_DRIVER_GPIO */ static inline int ssb_gpio_init(struct ssb_bus *bus) { return -ENOTSUPP; } +static inline int ssb_gpio_unregister(struct ssb_bus *bus) +{ + return 0; +} #endif /* CONFIG_SSB_DRIVER_GPIO */ #endif /* LINUX_SSB_PRIVATE_H_ */ -- cgit v0.10.2 From 7b2385b95363c9ff49801c19cba2489a05bd6672 Mon Sep 17 00:00:00 2001 From: Arend van Spriel Date: Sat, 2 Feb 2013 14:36:50 +0100 Subject: brcmsmac: rework of mac80211 .flush() callback operation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch addresses a long standing issue of the driver with the mac80211 .flush() callback. Since implementing the .flush() callback a number of issues have been fixed, but a WARN_ON_ONCE() was still triggered because the timeout on the flush could still occur. This patch changes the awkward design using msleep() into one using a waitqueue. The waiting flush() context will kick the transmit dma when it is idle and the timeout used waiting for the event is set to 500 ms. Worst case there can be 64 frames outstanding for transmit in the driver. At a rate of 1Mbps that would take 1.5 seconds assuming MTU is 1500 bytes and ignoring retries. The WARN_ON_ONCE() is also removed as this was put in to indicate the flush timeout as a reason for the driver to stall. That was not happening since fixing endless AMPDU retries with following upstream commit: commit 85091fc0a75653e239dc8379658515e577544927 Author: Arend van Spriel Date: Thu Feb 23 18:38:22 2012 +0100 brcm80211: smac: fix endless retry of A-MPDU transmissions bugzilla: 42840 bugzilla@redhat: bugzilla@redhat: Cc: Jonathan Nieder Cc: Stanislaw Gruszka Cc: Camaleón Cc: Milan Bouchet-Valat Cc: Seth Forshee Reviewed-by: Pieter-Paul Giesberts Reviewed-by: Hante Meuleman Reviewed-by: Piotr Haber Signed-off-by: Arend van Spriel Acked-by: Seth Forshee Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c b/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c index 0f71d1d..e5fd209 100644 --- a/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c +++ b/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c @@ -36,6 +36,7 @@ #include "debug.h" #define N_TX_QUEUES 4 /* #tx queues on mac80211<->driver interface */ +#define BRCMS_FLUSH_TIMEOUT 500 /* msec */ /* Flags we support */ #define MAC_FILTERS (FIF_PROMISC_IN_BSS | \ @@ -708,16 +709,29 @@ static void brcms_ops_rfkill_poll(struct ieee80211_hw *hw) wiphy_rfkill_set_hw_state(wl->pub->ieee_hw->wiphy, blocked); } +static bool brcms_tx_flush_completed(struct brcms_info *wl) +{ + bool result; + + spin_lock_bh(&wl->lock); + result = brcms_c_tx_flush_completed(wl->wlc); + spin_unlock_bh(&wl->lock); + return result; +} + static void brcms_ops_flush(struct ieee80211_hw *hw, bool drop) { struct brcms_info *wl = hw->priv; + int ret; no_printk("%s: drop = %s\n", __func__, drop ? "true" : "false"); - /* wait for packet queue and dma fifos to run empty */ - spin_lock_bh(&wl->lock); - brcms_c_wait_for_tx_completion(wl->wlc, drop); - spin_unlock_bh(&wl->lock); + ret = wait_event_timeout(wl->tx_flush_wq, + brcms_tx_flush_completed(wl), + msecs_to_jiffies(BRCMS_FLUSH_TIMEOUT)); + + brcms_dbg_mac80211(wl->wlc->hw->d11core, + "ret=%d\n", jiffies_to_msecs(ret)); } static const struct ieee80211_ops brcms_ops = { @@ -772,6 +786,7 @@ void brcms_dpc(unsigned long data) done: spin_unlock_bh(&wl->lock); + wake_up(&wl->tx_flush_wq); } /* @@ -1020,6 +1035,8 @@ static struct brcms_info *brcms_attach(struct bcma_device *pdev) atomic_set(&wl->callbacks, 0); + init_waitqueue_head(&wl->tx_flush_wq); + /* setup the bottom half handler */ tasklet_init(&wl->tasklet, brcms_dpc, (unsigned long) wl); @@ -1609,13 +1626,3 @@ bool brcms_rfkill_set_hw_state(struct brcms_info *wl) spin_lock_bh(&wl->lock); return blocked; } - -/* - * precondition: perimeter lock has been acquired - */ -void brcms_msleep(struct brcms_info *wl, uint ms) -{ - spin_unlock_bh(&wl->lock); - msleep(ms); - spin_lock_bh(&wl->lock); -} diff --git a/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.h b/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.h index 9358bd5..947ccac 100644 --- a/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.h +++ b/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.h @@ -68,6 +68,8 @@ struct brcms_info { spinlock_t lock; /* per-device perimeter lock */ spinlock_t isr_lock; /* per-device ISR synchronization lock */ + /* tx flush */ + wait_queue_head_t tx_flush_wq; /* timer related fields */ atomic_t callbacks; /* # outstanding callback functions */ @@ -100,7 +102,6 @@ extern struct brcms_timer *brcms_init_timer(struct brcms_info *wl, extern void brcms_free_timer(struct brcms_timer *timer); extern void brcms_add_timer(struct brcms_timer *timer, uint ms, int periodic); extern bool brcms_del_timer(struct brcms_timer *timer); -extern void brcms_msleep(struct brcms_info *wl, uint ms); extern void brcms_dpc(unsigned long data); extern void brcms_timer(struct brcms_timer *t); extern void brcms_fatal_error(struct brcms_info *wl); diff --git a/drivers/net/wireless/brcm80211/brcmsmac/main.c b/drivers/net/wireless/brcm80211/brcmsmac/main.c index 9f3d7e9..8b58390 100644 --- a/drivers/net/wireless/brcm80211/brcmsmac/main.c +++ b/drivers/net/wireless/brcm80211/brcmsmac/main.c @@ -7511,25 +7511,16 @@ int brcms_c_get_curband(struct brcms_c_info *wlc) return wlc->band->bandunit; } -void brcms_c_wait_for_tx_completion(struct brcms_c_info *wlc, bool drop) +bool brcms_c_tx_flush_completed(struct brcms_c_info *wlc) { - int timeout = 20; int i; /* Kick DMA to send any pending AMPDU */ for (i = 0; i < ARRAY_SIZE(wlc->hw->di); i++) if (wlc->hw->di[i]) - dma_txflush(wlc->hw->di[i]); + dma_kick_tx(wlc->hw->di[i]); - /* wait for queue and DMA fifos to run dry */ - while (brcms_txpktpendtot(wlc) > 0) { - brcms_msleep(wlc->wl, 1); - - if (--timeout == 0) - break; - } - - WARN_ON_ONCE(timeout == 0); + return !brcms_txpktpendtot(wlc); } void brcms_c_set_beacon_listen_interval(struct brcms_c_info *wlc, u8 interval) diff --git a/drivers/net/wireless/brcm80211/brcmsmac/pub.h b/drivers/net/wireless/brcm80211/brcmsmac/pub.h index 4fb2834..b0f14b7 100644 --- a/drivers/net/wireless/brcm80211/brcmsmac/pub.h +++ b/drivers/net/wireless/brcm80211/brcmsmac/pub.h @@ -314,8 +314,6 @@ extern void brcms_c_associate_upd(struct brcms_c_info *wlc, bool state); extern void brcms_c_scan_start(struct brcms_c_info *wlc); extern void brcms_c_scan_stop(struct brcms_c_info *wlc); extern int brcms_c_get_curband(struct brcms_c_info *wlc); -extern void brcms_c_wait_for_tx_completion(struct brcms_c_info *wlc, - bool drop); extern int brcms_c_set_channel(struct brcms_c_info *wlc, u16 channel); extern int brcms_c_set_rate_limit(struct brcms_c_info *wlc, u16 srl, u16 lrl); extern void brcms_c_get_current_rateset(struct brcms_c_info *wlc, @@ -332,5 +330,6 @@ extern int brcms_c_set_tx_power(struct brcms_c_info *wlc, int txpwr); extern int brcms_c_get_tx_power(struct brcms_c_info *wlc); extern bool brcms_c_check_radio_disabled(struct brcms_c_info *wlc); extern void brcms_c_mute(struct brcms_c_info *wlc, bool on); +extern bool brcms_c_tx_flush_completed(struct brcms_c_info *wlc); #endif /* _BRCM_PUB_H_ */ -- cgit v0.10.2 From 9887dbf5b2163bcf69cd4456c21352e9a81c6003 Mon Sep 17 00:00:00 2001 From: Cong Ding Date: Wed, 6 Feb 2013 17:23:45 +0100 Subject: mac80211: fix error in sizeof() usage Using 'sizeof' on array given as function argument returns size of a pointer rather than the size of array. Cc: stable@vger.kernel.org Signed-off-by: Cong Ding Signed-off-by: Johannes Berg diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 516fbc9..0479c64 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -2004,7 +2004,8 @@ static int ieee80211_set_mcast_rate(struct wiphy *wiphy, struct net_device *dev, { struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); - memcpy(sdata->vif.bss_conf.mcast_rate, rate, sizeof(rate)); + memcpy(sdata->vif.bss_conf.mcast_rate, rate, + sizeof(int) * IEEE80211_NUM_BANDS); return 0; } -- cgit v0.10.2 From d601cd8d950c85032cefdcda162b8cd2cda363bb Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 7 Feb 2013 20:54:51 +0100 Subject: mac80211: fix managed mode channel context use My commit f2d9d270c15ae0139b54a7e7466d738327e97e03 ("mac80211: support VHT association") introduced a very stupid bug: the loop to downgrade the channel width never attempted to actually use it again so it would downgrade all the way to 20_NOHT. Fix it. Signed-off-by: Johannes Berg diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index a355292..3b9cb51 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -3529,8 +3529,11 @@ static int ieee80211_prep_channel(struct ieee80211_sub_if_data *sdata, */ ret = ieee80211_vif_use_channel(sdata, &chandef, IEEE80211_CHANCTX_SHARED); - while (ret && chandef.width != NL80211_CHAN_WIDTH_20_NOHT) + while (ret && chandef.width != NL80211_CHAN_WIDTH_20_NOHT) { ifmgd->flags |= chandef_downgrade(&chandef); + ret = ieee80211_vif_use_channel(sdata, &chandef, + IEEE80211_CHANCTX_SHARED); + } return ret; } -- cgit v0.10.2 From 3d9646d0abd02c552f6f15c302b31aa321c2fa8b Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Sat, 9 Feb 2013 21:46:34 +0100 Subject: mac80211: fix channel selection bug When trying to connect to an AP that advertises HT but not VHT, the mac80211 code erroneously uses the configuration from the AP as is instead of checking it against regulatory and local capabilities. This can lead to using an invalid or even inexistent channel (like 11/HT40+). Additionally, the return flags from downgrading must be ORed together, to collect them from all of the downgrades. Also clarify the message. Signed-off-by: Johannes Berg diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 3b9cb51..5107248 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -3400,6 +3400,7 @@ ieee80211_determine_chantype(struct ieee80211_sub_if_data *sdata, ret = 0; +out: while (!cfg80211_chandef_usable(sdata->local->hw.wiphy, chandef, IEEE80211_CHAN_DISABLED)) { if (WARN_ON(chandef->width == NL80211_CHAN_WIDTH_20_NOHT)) { @@ -3408,14 +3409,13 @@ ieee80211_determine_chantype(struct ieee80211_sub_if_data *sdata, goto out; } - ret = chandef_downgrade(chandef); + ret |= chandef_downgrade(chandef); } if (chandef->width != vht_chandef.width) sdata_info(sdata, - "local regulatory prevented using AP HT/VHT configuration, downgraded\n"); + "capabilities/regulatory prevented using AP HT/VHT configuration, downgraded\n"); -out: WARN_ON_ONCE(!cfg80211_chandef_valid(chandef)); return ret; } -- cgit v0.10.2 From d786f67e5c587a4de8245336cb64cf4dd06871a7 Mon Sep 17 00:00:00 2001 From: Jonas Gorski Date: Fri, 8 Feb 2013 16:07:25 +0100 Subject: mwl8k: fix band for supported channels The band field for the supported channels were left unpopulated, making them default to 0 == IEEE80211_BAND_2GHZ, even for the 5GHz channels. This resulted in null pointer accesses if anything tries to access wiphy->bands[channel->band] of a 5GHz channel on 5GHz only cards, since wiphy->bands[2GHZ] is NULL for them (e.g. cfg80211_chandef_usable does). Example kernel OOPS: [ 665.669993] Unable to handle kernel NULL pointer dereference at virtual address 00000016 [ 665.678194] pgd = c6d58000 [ 665.680941] [00000016] *pgd=06f8a831, *pte=00000000, *ppte=00000000 [ 665.687303] Internal error: Oops: 17 [#1] (...) [ 666.116373] Backtrace: [ 666.118866] [] (cfg80211_chandef_usable+0x0/0x1bc [cfg80211]) from [] (nl80211_leave_mesh+0x244/0x264 [cfg80211]) [ 666.130919] r7:c6d12100 r6:0000143c r5:c0611c48 r4:c0611b98 [ 666.136668] [] (nl80211_leave_mesh+0x164/0x264 [cfg80211]) from [] (nl80211_remain_on_channel+0x2a0/0x358 [cfg80211]) [ 666.149074] r7:c6d12000 r6:c6d12000 r5:c6f4f368 r4:00000003 [ 666.154814] [] (nl80211_remain_on_channel+0x240/0x358 [cfg80211]) from [] (nl80211_set_wiphy+0x264/0x560 [cfg80211]) [ 666.167150] [] (nl80211_set_wiphy+0x0/0x560 [cfg80211]) from [] (genl_rcv_msg+0x1b8/0x1f8) [ 666.177205] [] (genl_rcv_msg+0x0/0x1f8) from [] (netlink_rcv_skb+0x58/0xb4) [ 666.185949] [] (netlink_rcv_skb+0x0/0xb4) from [] (genl_rcv+0x20/0x2c) [ 666.194251] r6:c6f70780 r5:0000002c r4:c6f70780 r3:00000001 [ 666.199973] [] (genl_rcv+0x0/0x2c) from [] (netlink_unicast+0x154/0x1f4) [ 666.208449] r4:c785ea00 r3:c01f92fc [ 666.212057] [] (netlink_unicast+0x0/0x1f4) from [] (netlink_sendmsg+0x230/0x2b0) [ 666.221240] [] (netlink_sendmsg+0x0/0x2b0) from [] (sock_sendmsg+0x90/0xa4) [ 666.229986] [] (sock_sendmsg+0x0/0xa4) from [] (__sys_sendmsg+0x290/0x298) [ 666.238637] r9:00000000 r8:c0611ec8 r6:0000002c r5:c0610000 r4:c0611f64 [ 666.245411] [] (__sys_sendmsg+0x0/0x298) from [] (sys_sendmsg+0x44/0x6c) [ 666.253897] [] (sys_sendmsg+0x0/0x6c) from [] (ret_fast_syscall+0x0/0x2c) [ 666.262460] r6:00000000 r5:beeff96c r4:00000005 Signed-off-by: Jonas Gorski Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c index 83564d3..a00a03e 100644 --- a/drivers/net/wireless/mwl8k.c +++ b/drivers/net/wireless/mwl8k.c @@ -318,20 +318,20 @@ struct mwl8k_sta { #define MWL8K_STA(_sta) ((struct mwl8k_sta *)&((_sta)->drv_priv)) static const struct ieee80211_channel mwl8k_channels_24[] = { - { .center_freq = 2412, .hw_value = 1, }, - { .center_freq = 2417, .hw_value = 2, }, - { .center_freq = 2422, .hw_value = 3, }, - { .center_freq = 2427, .hw_value = 4, }, - { .center_freq = 2432, .hw_value = 5, }, - { .center_freq = 2437, .hw_value = 6, }, - { .center_freq = 2442, .hw_value = 7, }, - { .center_freq = 2447, .hw_value = 8, }, - { .center_freq = 2452, .hw_value = 9, }, - { .center_freq = 2457, .hw_value = 10, }, - { .center_freq = 2462, .hw_value = 11, }, - { .center_freq = 2467, .hw_value = 12, }, - { .center_freq = 2472, .hw_value = 13, }, - { .center_freq = 2484, .hw_value = 14, }, + { .band = IEEE80211_BAND_2GHZ, .center_freq = 2412, .hw_value = 1, }, + { .band = IEEE80211_BAND_2GHZ, .center_freq = 2417, .hw_value = 2, }, + { .band = IEEE80211_BAND_2GHZ, .center_freq = 2422, .hw_value = 3, }, + { .band = IEEE80211_BAND_2GHZ, .center_freq = 2427, .hw_value = 4, }, + { .band = IEEE80211_BAND_2GHZ, .center_freq = 2432, .hw_value = 5, }, + { .band = IEEE80211_BAND_2GHZ, .center_freq = 2437, .hw_value = 6, }, + { .band = IEEE80211_BAND_2GHZ, .center_freq = 2442, .hw_value = 7, }, + { .band = IEEE80211_BAND_2GHZ, .center_freq = 2447, .hw_value = 8, }, + { .band = IEEE80211_BAND_2GHZ, .center_freq = 2452, .hw_value = 9, }, + { .band = IEEE80211_BAND_2GHZ, .center_freq = 2457, .hw_value = 10, }, + { .band = IEEE80211_BAND_2GHZ, .center_freq = 2462, .hw_value = 11, }, + { .band = IEEE80211_BAND_2GHZ, .center_freq = 2467, .hw_value = 12, }, + { .band = IEEE80211_BAND_2GHZ, .center_freq = 2472, .hw_value = 13, }, + { .band = IEEE80211_BAND_2GHZ, .center_freq = 2484, .hw_value = 14, }, }; static const struct ieee80211_rate mwl8k_rates_24[] = { @@ -352,10 +352,10 @@ static const struct ieee80211_rate mwl8k_rates_24[] = { }; static const struct ieee80211_channel mwl8k_channels_50[] = { - { .center_freq = 5180, .hw_value = 36, }, - { .center_freq = 5200, .hw_value = 40, }, - { .center_freq = 5220, .hw_value = 44, }, - { .center_freq = 5240, .hw_value = 48, }, + { .band = IEEE80211_BAND_5GHZ, .center_freq = 5180, .hw_value = 36, }, + { .band = IEEE80211_BAND_5GHZ, .center_freq = 5200, .hw_value = 40, }, + { .band = IEEE80211_BAND_5GHZ, .center_freq = 5220, .hw_value = 44, }, + { .band = IEEE80211_BAND_5GHZ, .center_freq = 5240, .hw_value = 48, }, }; static const struct ieee80211_rate mwl8k_rates_50[] = { -- cgit v0.10.2