]> git.karo-electronics.de Git - karo-tx-linux.git/commitdiff
Merge remote-tracking branch 'wireless/master'
authorThierry Reding <treding@nvidia.com>
Thu, 24 Oct 2013 12:32:12 +0000 (14:32 +0200)
committerThierry Reding <treding@nvidia.com>
Thu, 24 Oct 2013 12:32:12 +0000 (14:32 +0200)
12 files changed:
drivers/net/wireless/ath/ath5k/base.c
drivers/net/wireless/b43/phy_n.c
drivers/net/wireless/iwlwifi/dvm/tx.c
drivers/net/wireless/iwlwifi/iwl-trans.h
drivers/net/wireless/iwlwifi/mvm/scan.c
drivers/net/wireless/iwlwifi/pcie/tx.c
drivers/net/wireless/rt2x00/rt2400pci.c
drivers/net/wireless/rt2x00/rt2800usb.c
drivers/net/wireless/rt2x00/rt2x00mac.c
net/mac80211/ieee80211_i.h
net/mac80211/mlme.c
net/mac80211/rate.c

index 48161edec8de84769fd9f3db92fa1c4aa165d70b..69f58b073e85ff1a183ec1f06e803ff9da00806c 100644 (file)
@@ -1663,15 +1663,15 @@ ath5k_tx_frame_completed(struct ath5k_hw *ah, struct sk_buff *skb,
        ah->stats.tx_bytes_count += skb->len;
        info = IEEE80211_SKB_CB(skb);
 
+       size = min_t(int, sizeof(info->status.rates), sizeof(bf->rates));
+       memcpy(info->status.rates, bf->rates, size);
+
        tries[0] = info->status.rates[0].count;
        tries[1] = info->status.rates[1].count;
        tries[2] = info->status.rates[2].count;
 
        ieee80211_tx_info_clear_status(info);
 
-       size = min_t(int, sizeof(info->status.rates), sizeof(bf->rates));
-       memcpy(info->status.rates, bf->rates, size);
-
        for (i = 0; i < ts->ts_final_idx; i++) {
                struct ieee80211_tx_rate *r =
                        &info->status.rates[i];
index 7c970d3ae358834a4230f35826d6c598661ee323..05ee7f10cc8f577532e9180ac9874adcf9343d0f 100644 (file)
@@ -164,7 +164,8 @@ static void b43_nphy_rf_ctl_override_rev7(struct b43_wldev *dev, u16 field,
                }
                en_addr = en_addrs[override][i];
 
-               val_addr = (i == 0) ? e->val_addr_core0 : e->val_addr_core1;
+               if (e)
+                       val_addr = (i == 0) ? e->val_addr_core0 : e->val_addr_core1;
 
                if (off) {
                        b43_phy_mask(dev, en_addr, ~en_mask);
index da442b81370a769054b4b77a946daa4bbd856ed8..1fef5240e6adc07317b7128bf7d7617385fa9aa8 100644 (file)
@@ -433,27 +433,19 @@ int iwlagn_tx_skb(struct iwl_priv *priv,
        /* Copy MAC header from skb into command buffer */
        memcpy(tx_cmd->hdr, hdr, hdr_len);
 
+       txq_id = info->hw_queue;
+
        if (is_agg)
                txq_id = priv->tid_data[sta_id][tid].agg.txq_id;
        else if (info->flags & IEEE80211_TX_CTL_SEND_AFTER_DTIM) {
-               /*
-                * Send this frame after DTIM -- there's a special queue
-                * reserved for this for contexts that support AP mode.
-                */
-               txq_id = ctx->mcast_queue;
-
                /*
                 * The microcode will clear the more data
                 * bit in the last frame it transmits.
                 */
                hdr->frame_control |=
                        cpu_to_le16(IEEE80211_FCTL_MOREDATA);
-       } else if (info->flags & IEEE80211_TX_CTL_TX_OFFCHAN)
-               txq_id = IWL_AUX_QUEUE;
-       else
-               txq_id = ctx->ac_to_queue[skb_get_queue_mapping(skb)];
+       }
 
-       WARN_ON_ONCE(!is_agg && txq_id != info->hw_queue);
        WARN_ON_ONCE(is_agg &&
                     priv->queue_to_mac80211[txq_id] != info->hw_queue);
 
index 80b47508647ca8d5861f4b4c8dc8e8ec879d34c3..c6bac7c90b00bf458b17a829ec2895c2acaa065d 100644 (file)
@@ -601,7 +601,7 @@ static inline int iwl_trans_send_cmd(struct iwl_trans *trans,
 {
        int ret;
 
-       if (trans->state != IWL_TRANS_FW_ALIVE) {
+       if (unlikely(trans->state != IWL_TRANS_FW_ALIVE)) {
                IWL_ERR(trans, "%s bad state = %d", __func__, trans->state);
                return -EIO;
        }
@@ -640,8 +640,8 @@ static inline void iwl_trans_free_tx_cmd(struct iwl_trans *trans,
 static inline int iwl_trans_tx(struct iwl_trans *trans, struct sk_buff *skb,
                               struct iwl_device_cmd *dev_cmd, int queue)
 {
-       WARN_ONCE(trans->state != IWL_TRANS_FW_ALIVE,
-                 "%s bad state = %d", __func__, trans->state);
+       if (unlikely(trans->state != IWL_TRANS_FW_ALIVE))
+               IWL_ERR(trans, "%s bad state = %d", __func__, trans->state);
 
        return trans->ops->tx(trans, skb, dev_cmd, queue);
 }
@@ -649,16 +649,16 @@ static inline int iwl_trans_tx(struct iwl_trans *trans, struct sk_buff *skb,
 static inline void iwl_trans_reclaim(struct iwl_trans *trans, int queue,
                                     int ssn, struct sk_buff_head *skbs)
 {
-       WARN_ONCE(trans->state != IWL_TRANS_FW_ALIVE,
-                 "%s bad state = %d", __func__, trans->state);
+       if (unlikely(trans->state != IWL_TRANS_FW_ALIVE))
+               IWL_ERR(trans, "%s bad state = %d", __func__, trans->state);
 
        trans->ops->reclaim(trans, queue, ssn, skbs);
 }
 
 static inline void iwl_trans_txq_disable(struct iwl_trans *trans, int queue)
 {
-       WARN_ONCE(trans->state != IWL_TRANS_FW_ALIVE,
-                 "%s bad state = %d", __func__, trans->state);
+       if (unlikely(trans->state != IWL_TRANS_FW_ALIVE))
+               IWL_ERR(trans, "%s bad state = %d", __func__, trans->state);
 
        trans->ops->txq_disable(trans, queue);
 }
@@ -669,8 +669,8 @@ static inline void iwl_trans_txq_enable(struct iwl_trans *trans, int queue,
 {
        might_sleep();
 
-       WARN_ONCE(trans->state != IWL_TRANS_FW_ALIVE,
-                 "%s bad state = %d", __func__, trans->state);
+       if (unlikely((trans->state != IWL_TRANS_FW_ALIVE)))
+               IWL_ERR(trans, "%s bad state = %d", __func__, trans->state);
 
        trans->ops->txq_enable(trans, queue, fifo, sta_id, tid,
                                 frame_limit, ssn);
@@ -685,8 +685,8 @@ static inline void iwl_trans_ac_txq_enable(struct iwl_trans *trans, int queue,
 
 static inline int iwl_trans_wait_tx_queue_empty(struct iwl_trans *trans)
 {
-       WARN_ONCE(trans->state != IWL_TRANS_FW_ALIVE,
-                 "%s bad state = %d", __func__, trans->state);
+       if (unlikely(trans->state != IWL_TRANS_FW_ALIVE))
+               IWL_ERR(trans, "%s bad state = %d", __func__, trans->state);
 
        return trans->ops->wait_tx_queue_empty(trans);
 }
index 621fb71f282a88e9a285bb3d4b2b26a1b2fef275..3a06832e8e90200390b05e22944531caa9ac1bab 100644 (file)
@@ -93,10 +93,10 @@ static inline __le32 iwl_mvm_scan_max_out_time(struct ieee80211_vif *vif)
 
 static inline __le32 iwl_mvm_scan_suspend_time(struct ieee80211_vif *vif)
 {
-       if (vif->bss_conf.assoc)
-               return cpu_to_le32(vif->bss_conf.beacon_int);
-       else
+       if (!vif->bss_conf.assoc)
                return 0;
+
+       return cpu_to_le32(ieee80211_tu_to_usec(vif->bss_conf.beacon_int));
 }
 
 static inline __le32
index 1424335163b97e4d6625a8fca7ec7c19a1d07c9c..80f1956b3be330f18da98b1e1b65ecc16890695e 100644 (file)
@@ -1465,7 +1465,8 @@ void iwl_pcie_hcmd_complete(struct iwl_trans *trans,
        spin_unlock_bh(&txq->lock);
 }
 
-#define HOST_COMPLETE_TIMEOUT (2 * HZ)
+#define HOST_COMPLETE_TIMEOUT  (2 * HZ)
+#define COMMAND_POKE_TIMEOUT   (HZ / 10)
 
 static int iwl_pcie_send_hcmd_async(struct iwl_trans *trans,
                                    struct iwl_host_cmd *cmd)
@@ -1493,6 +1494,7 @@ static int iwl_pcie_send_hcmd_sync(struct iwl_trans *trans,
        struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
        int cmd_idx;
        int ret;
+       int timeout = HOST_COMPLETE_TIMEOUT;
 
        IWL_DEBUG_INFO(trans, "Attempting to send sync command %s\n",
                       get_cmd_string(trans_pcie, cmd->id));
@@ -1517,10 +1519,29 @@ static int iwl_pcie_send_hcmd_sync(struct iwl_trans *trans,
                return ret;
        }
 
-       ret = wait_event_timeout(trans_pcie->wait_command_queue,
-                                !test_bit(STATUS_HCMD_ACTIVE,
-                                          &trans_pcie->status),
-                                HOST_COMPLETE_TIMEOUT);
+       while (timeout > 0) {
+               unsigned long flags;
+
+               timeout -= COMMAND_POKE_TIMEOUT;
+               ret = wait_event_timeout(trans_pcie->wait_command_queue,
+                                        !test_bit(STATUS_HCMD_ACTIVE,
+                                                  &trans_pcie->status),
+                                        COMMAND_POKE_TIMEOUT);
+               if (ret)
+                       break;
+               /* poke the device - it may have lost the command */
+               if (iwl_trans_grab_nic_access(trans, true, &flags)) {
+                       iwl_trans_release_nic_access(trans, &flags);
+                       IWL_DEBUG_INFO(trans,
+                                      "Tried to wake NIC for command %s\n",
+                                      get_cmd_string(trans_pcie, cmd->id));
+               } else {
+                       IWL_ERR(trans, "Failed to poke NIC for command %s\n",
+                               get_cmd_string(trans_pcie, cmd->id));
+                       break;
+               }
+       }
+
        if (!ret) {
                if (test_bit(STATUS_HCMD_ACTIVE, &trans_pcie->status)) {
                        struct iwl_txq *txq =
index 3d53a09da5a12da22f2697c9a22b7dfb49daaff0..38ed9a3e44c8c00c06ea8f1cdd9ae1a68bbe2d60 100644 (file)
@@ -1261,7 +1261,7 @@ static void rt2400pci_fill_rxdone(struct queue_entry *entry,
         */
        rxdesc->timestamp = ((u64)rx_high << 32) | rx_low;
        rxdesc->signal = rt2x00_get_field32(word2, RXD_W2_SIGNAL) & ~0x08;
-       rxdesc->rssi = rt2x00_get_field32(word2, RXD_W3_RSSI) -
+       rxdesc->rssi = rt2x00_get_field32(word3, RXD_W3_RSSI) -
            entry->queue->rt2x00dev->rssi_offset;
        rxdesc->size = rt2x00_get_field32(word0, RXD_W0_DATABYTE_COUNT);
 
index 96961b9a395cf0d2e01c32449c4e9bcc55e7828c..4feb35aef99001df8d74595dcdc4420d1653a28f 100644 (file)
@@ -148,6 +148,8 @@ static bool rt2800usb_txstatus_timeout(struct rt2x00_dev *rt2x00dev)
        return false;
 }
 
+#define TXSTATUS_READ_INTERVAL 1000000
+
 static bool rt2800usb_tx_sta_fifo_read_completed(struct rt2x00_dev *rt2x00dev,
                                                 int urb_status, u32 tx_status)
 {
@@ -176,8 +178,9 @@ static bool rt2800usb_tx_sta_fifo_read_completed(struct rt2x00_dev *rt2x00dev,
                queue_work(rt2x00dev->workqueue, &rt2x00dev->txdone_work);
 
        if (rt2800usb_txstatus_pending(rt2x00dev)) {
-               /* Read register after 250 us */
-               hrtimer_start(&rt2x00dev->txstatus_timer, ktime_set(0, 250000),
+               /* Read register after 1 ms */
+               hrtimer_start(&rt2x00dev->txstatus_timer,
+                             ktime_set(0, TXSTATUS_READ_INTERVAL),
                              HRTIMER_MODE_REL);
                return false;
        }
@@ -202,8 +205,9 @@ static void rt2800usb_async_read_tx_status(struct rt2x00_dev *rt2x00dev)
        if (test_and_set_bit(TX_STATUS_READING, &rt2x00dev->flags))
                return;
 
-       /* Read TX_STA_FIFO register after 500 us */
-       hrtimer_start(&rt2x00dev->txstatus_timer, ktime_set(0, 500000),
+       /* Read TX_STA_FIFO register after 2 ms */
+       hrtimer_start(&rt2x00dev->txstatus_timer,
+                     ktime_set(0, 2*TXSTATUS_READ_INTERVAL),
                      HRTIMER_MODE_REL);
 }
 
index f883802f350585322338ed7683e065bb85349ff3..ba1de865c8920861664c8acce7a666a985fc82a8 100644 (file)
@@ -754,6 +754,9 @@ void rt2x00mac_flush(struct ieee80211_hw *hw, u32 queues, bool drop)
        struct rt2x00_dev *rt2x00dev = hw->priv;
        struct data_queue *queue;
 
+       if (!test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags))
+               return;
+
        tx_queue_for_each(rt2x00dev, queue)
                rt2x00queue_flush_queue(queue, drop);
 }
index 611abfcfb5ebba3c135edbcf8b2efb4a47f38374..076409526bcb5b4a3e01157bb719ab1edbaa8918 100644 (file)
@@ -335,6 +335,7 @@ enum ieee80211_sta_flags {
        IEEE80211_STA_DISABLE_VHT       = BIT(11),
        IEEE80211_STA_DISABLE_80P80MHZ  = BIT(12),
        IEEE80211_STA_DISABLE_160MHZ    = BIT(13),
+       IEEE80211_STA_DISABLE_WMM       = BIT(14),
 };
 
 struct ieee80211_mgd_auth_data {
index 86e4ad56b573df27779831e17dce835f67396836..54ebc8155b492d2534958d6035cb149de43c7766 100644 (file)
@@ -2717,7 +2717,7 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata,
         */
        ifmgd->wmm_last_param_set = -1;
 
-       if (elems.wmm_param)
+       if (!(ifmgd->flags & IEEE80211_STA_DISABLE_WMM) && elems.wmm_param)
                ieee80211_sta_wmm_params(local, sdata, elems.wmm_param,
                                         elems.wmm_param_len);
        else
@@ -3152,7 +3152,8 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
        ieee80211_sta_process_chanswitch(sdata, rx_status->mactime,
                                         &elems, true);
 
-       if (ieee80211_sta_wmm_params(local, sdata, elems.wmm_param,
+       if (!(ifmgd->flags & IEEE80211_STA_DISABLE_WMM) &&
+           ieee80211_sta_wmm_params(local, sdata, elems.wmm_param,
                                     elems.wmm_param_len))
                changed |= BSS_CHANGED_QOS;
 
@@ -4135,6 +4136,44 @@ int ieee80211_mgd_auth(struct ieee80211_sub_if_data *sdata,
        return err;
 }
 
+static bool ieee80211_usable_wmm_params(struct ieee80211_sub_if_data *sdata,
+                                       const u8 *wmm_param, int len)
+{
+       const u8 *pos;
+       size_t left;
+
+       if (len < 8)
+               return false;
+
+       if (wmm_param[5] != 1 /* version */)
+               return false;
+
+       pos = wmm_param + 8;
+       left = len - 8;
+
+       for (; left >= 4; left -= 4, pos += 4) {
+               u8 aifsn = pos[0] & 0x0f;
+               u8 ecwmin = pos[1] & 0x0f;
+               u8 ecwmax = (pos[1] & 0xf0) >> 4;
+               int aci = (pos[0] >> 5) & 0x03;
+
+               if (aifsn < 2) {
+                       sdata_info(sdata,
+                                  "AP has invalid WMM params (AIFSN=%d for ACI %d), disabling WMM\n",
+                                  aifsn, aci);
+                       return false;
+               }
+               if (ecwmin > ecwmax) {
+                       sdata_info(sdata,
+                                  "AP has invalid WMM params (ECWmin/max=%d/%d for ACI %d), disabling WMM\n",
+                                  ecwmin, ecwmax, aci);
+                       return false;
+               }
+       }
+
+       return true;
+}
+
 int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata,
                        struct cfg80211_assoc_request *req)
 {
@@ -4192,9 +4231,45 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata,
        }
 
        /* prepare assoc data */
-       
+
        ifmgd->beacon_crc_valid = false;
 
+       assoc_data->wmm = bss->wmm_used &&
+                         (local->hw.queues >= IEEE80211_NUM_ACS);
+       if (assoc_data->wmm) {
+               /* try to check validity of WMM params IE */
+               const struct cfg80211_bss_ies *ies;
+               const u8 *wp, *start, *end;
+
+               rcu_read_lock();
+               ies = rcu_dereference(req->bss->ies);
+               start = ies->data;
+               end = start + ies->len;
+
+               while (true) {
+                       wp = cfg80211_find_vendor_ie(
+                               WLAN_OUI_MICROSOFT,
+                               WLAN_OUI_TYPE_MICROSOFT_WMM,
+                               start, end - start);
+                       if (!wp)
+                               break;
+                       start = wp + wp[1] + 2;
+                       /* if this IE is too short, try the next */
+                       if (wp[1] <= 4)
+                               continue;
+                       /* if this IE is WMM params, we found what we wanted */
+                       if (wp[6] == 1)
+                               break;
+               }
+
+               if (!wp || !ieee80211_usable_wmm_params(sdata, wp + 2,
+                                                       wp[1] - 2)) {
+                       assoc_data->wmm = false;
+                       ifmgd->flags |= IEEE80211_STA_DISABLE_WMM;
+               }
+               rcu_read_unlock();
+       }
+
        /*
         * IEEE802.11n does not allow TKIP/WEP as pairwise ciphers in HT mode.
         * We still associate in non-HT mode (11a/b/g) if any one of these
@@ -4224,18 +4299,22 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata,
        /* Also disable HT if we don't support it or the AP doesn't use WMM */
        sband = local->hw.wiphy->bands[req->bss->channel->band];
        if (!sband->ht_cap.ht_supported ||
-           local->hw.queues < IEEE80211_NUM_ACS || !bss->wmm_used) {
+           local->hw.queues < IEEE80211_NUM_ACS || !bss->wmm_used ||
+           ifmgd->flags & IEEE80211_STA_DISABLE_WMM) {
                ifmgd->flags |= IEEE80211_STA_DISABLE_HT;
-               if (!bss->wmm_used)
+               if (!bss->wmm_used &&
+                   !(ifmgd->flags & IEEE80211_STA_DISABLE_WMM))
                        netdev_info(sdata->dev,
                                    "disabling HT as WMM/QoS is not supported by the AP\n");
        }
 
        /* disable VHT if we don't support it or the AP doesn't use WMM */
        if (!sband->vht_cap.vht_supported ||
-           local->hw.queues < IEEE80211_NUM_ACS || !bss->wmm_used) {
+           local->hw.queues < IEEE80211_NUM_ACS || !bss->wmm_used ||
+           ifmgd->flags & IEEE80211_STA_DISABLE_WMM) {
                ifmgd->flags |= IEEE80211_STA_DISABLE_VHT;
-               if (!bss->wmm_used)
+               if (!bss->wmm_used &&
+                   !(ifmgd->flags & IEEE80211_STA_DISABLE_WMM))
                        netdev_info(sdata->dev,
                                    "disabling VHT as WMM/QoS is not supported by the AP\n");
        }
@@ -4264,8 +4343,6 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata,
                sdata->smps_mode = ifmgd->req_smps;
 
        assoc_data->capability = req->bss->capability;
-       assoc_data->wmm = bss->wmm_used &&
-                         (local->hw.queues >= IEEE80211_NUM_ACS);
        assoc_data->supp_rates = bss->supp_rates;
        assoc_data->supp_rates_len = bss->supp_rates_len;
 
index e126605cec66baf82aadb835856110d74105795f..22b223f13c9fa22994eba6f68769a27b2cfe4eb3 100644 (file)
@@ -235,7 +235,8 @@ static void rc_send_low_basicrate(s8 *idx, u32 basic_rates,
 static void __rate_control_send_low(struct ieee80211_hw *hw,
                                    struct ieee80211_supported_band *sband,
                                    struct ieee80211_sta *sta,
-                                   struct ieee80211_tx_info *info)
+                                   struct ieee80211_tx_info *info,
+                                   u32 rate_mask)
 {
        int i;
        u32 rate_flags =
@@ -247,6 +248,12 @@ static void __rate_control_send_low(struct ieee80211_hw *hw,
 
        info->control.rates[0].idx = 0;
        for (i = 0; i < sband->n_bitrates; i++) {
+               if (!(rate_mask & BIT(i)))
+                       continue;
+
+               if ((rate_flags & sband->bitrates[i].flags) != rate_flags)
+                       continue;
+
                if (!rate_supported(sta, sband->band, i))
                        continue;
 
@@ -274,7 +281,8 @@ bool rate_control_send_low(struct ieee80211_sta *pubsta,
        bool use_basicrate = false;
 
        if (!pubsta || !priv_sta || rc_no_data_or_no_ack_use_min(txrc)) {
-               __rate_control_send_low(txrc->hw, sband, pubsta, info);
+               __rate_control_send_low(txrc->hw, sband, pubsta, info,
+                                       txrc->rate_idx_mask);
 
                if (!pubsta && txrc->bss) {
                        mcast_rate = txrc->bss_conf->mcast_rate[sband->band];
@@ -656,7 +664,8 @@ void ieee80211_get_tx_rates(struct ieee80211_vif *vif,
                rate_control_apply_mask(sdata, sta, sband, info, dest, max_rates);
 
        if (dest[0].idx < 0)
-               __rate_control_send_low(&sdata->local->hw, sband, sta, info);
+               __rate_control_send_low(&sdata->local->hw, sband, sta, info,
+                                       sdata->rc_rateidx_mask[info->band]);
 
        if (sta)
                rate_fixup_ratelist(vif, sband, info, dest, max_rates);