Merge tag 'wireless-drivers-next-for-davem-2015-12-07' of git://git.kernel.org/pub...
[linux-drm-fsl-dcu.git] / drivers / net / wireless / ath / ath10k / mac.c
index a7411fe90cc43ebcef7590538cb3d6cb73a6a13a..bcb364d5d49fd07a6a185800c9968b82073a8e7f 100644 (file)
@@ -90,7 +90,7 @@ static u8 ath10k_mac_bitrate_to_rate(int bitrate)
 }
 
 u8 ath10k_mac_hw_rate_to_idx(const struct ieee80211_supported_band *sband,
-                            u8 hw_rate)
+                            u8 hw_rate, bool cck)
 {
        const struct ieee80211_rate *rate;
        int i;
@@ -98,6 +98,9 @@ u8 ath10k_mac_hw_rate_to_idx(const struct ieee80211_supported_band *sband,
        for (i = 0; i < sband->n_bitrates; i++) {
                rate = &sband->bitrates[i];
 
+               if (ath10k_mac_bitrate_is_cck(rate->bitrate) != cck)
+                       continue;
+
                if (rate->hw_value == hw_rate)
                        return i;
                else if (rate->flags & IEEE80211_RATE_SHORT_PREAMBLE &&
@@ -1960,7 +1963,7 @@ static void ath10k_peer_assoc_h_basic(struct ath10k *ar,
        ether_addr_copy(arg->addr, sta->addr);
        arg->vdev_id = arvif->vdev_id;
        arg->peer_aid = aid;
-       arg->peer_flags |= WMI_PEER_AUTH;
+       arg->peer_flags |= arvif->ar->wmi.peer_flags->auth;
        arg->peer_listen_intval = ath10k_peer_assoc_h_listen_intval(ar, vif);
        arg->peer_num_spatial_streams = 1;
        arg->peer_caps = vif->bss_conf.assoc_capability;
@@ -1968,6 +1971,7 @@ static void ath10k_peer_assoc_h_basic(struct ath10k *ar,
 
 static void ath10k_peer_assoc_h_crypto(struct ath10k *ar,
                                       struct ieee80211_vif *vif,
+                                      struct ieee80211_sta *sta,
                                       struct wmi_peer_assoc_complete_arg *arg)
 {
        struct ieee80211_bss_conf *info = &vif->bss_conf;
@@ -2002,12 +2006,17 @@ static void ath10k_peer_assoc_h_crypto(struct ath10k *ar,
        /* FIXME: base on RSN IE/WPA IE is a correct idea? */
        if (rsnie || wpaie) {
                ath10k_dbg(ar, ATH10K_DBG_WMI, "%s: rsn ie found\n", __func__);
-               arg->peer_flags |= WMI_PEER_NEED_PTK_4_WAY;
+               arg->peer_flags |= ar->wmi.peer_flags->need_ptk_4_way;
        }
 
        if (wpaie) {
                ath10k_dbg(ar, ATH10K_DBG_WMI, "%s: wpa ie found\n", __func__);
-               arg->peer_flags |= WMI_PEER_NEED_GTK_2_WAY;
+               arg->peer_flags |= ar->wmi.peer_flags->need_gtk_2_way;
+       }
+
+       if (sta->mfp &&
+           test_bit(ATH10K_FW_FEATURE_MFP_SUPPORT, ar->fw_features)) {
+               arg->peer_flags |= ar->wmi.peer_flags->pmf;
        }
 }
 
@@ -2104,7 +2113,7 @@ static void ath10k_peer_assoc_h_ht(struct ath10k *ar,
            ath10k_peer_assoc_h_vht_masked(vht_mcs_mask))
                return;
 
-       arg->peer_flags |= WMI_PEER_HT;
+       arg->peer_flags |= ar->wmi.peer_flags->ht;
        arg->peer_max_mpdu = (1 << (IEEE80211_HT_MAX_AMPDU_FACTOR +
                                    ht_cap->ampdu_factor)) - 1;
 
@@ -2115,10 +2124,10 @@ static void ath10k_peer_assoc_h_ht(struct ath10k *ar,
        arg->peer_rate_caps |= WMI_RC_HT_FLAG;
 
        if (ht_cap->cap & IEEE80211_HT_CAP_LDPC_CODING)
-               arg->peer_flags |= WMI_PEER_LDPC;
+               arg->peer_flags |= ar->wmi.peer_flags->ldbc;
 
        if (sta->bandwidth >= IEEE80211_STA_RX_BW_40) {
-               arg->peer_flags |= WMI_PEER_40MHZ;
+               arg->peer_flags |= ar->wmi.peer_flags->bw40;
                arg->peer_rate_caps |= WMI_RC_CW40_FLAG;
        }
 
@@ -2132,7 +2141,7 @@ static void ath10k_peer_assoc_h_ht(struct ath10k *ar,
 
        if (ht_cap->cap & IEEE80211_HT_CAP_TX_STBC) {
                arg->peer_rate_caps |= WMI_RC_TX_STBC_FLAG;
-               arg->peer_flags |= WMI_PEER_STBC;
+               arg->peer_flags |= ar->wmi.peer_flags->stbc;
        }
 
        if (ht_cap->cap & IEEE80211_HT_CAP_RX_STBC) {
@@ -2140,7 +2149,7 @@ static void ath10k_peer_assoc_h_ht(struct ath10k *ar,
                stbc = stbc >> IEEE80211_HT_CAP_RX_STBC_SHIFT;
                stbc = stbc << WMI_RC_RX_STBC_FLAG_S;
                arg->peer_rate_caps |= stbc;
-               arg->peer_flags |= WMI_PEER_STBC;
+               arg->peer_flags |= ar->wmi.peer_flags->stbc;
        }
 
        if (ht_cap->mcs.rx_mask[1] && ht_cap->mcs.rx_mask[2])
@@ -2321,10 +2330,10 @@ static void ath10k_peer_assoc_h_vht(struct ath10k *ar,
        if (ath10k_peer_assoc_h_vht_masked(vht_mcs_mask))
                return;
 
-       arg->peer_flags |= WMI_PEER_VHT;
+       arg->peer_flags |= ar->wmi.peer_flags->vht;
 
        if (def.chan->band == IEEE80211_BAND_2GHZ)
-               arg->peer_flags |= WMI_PEER_VHT_2G;
+               arg->peer_flags |= ar->wmi.peer_flags->vht_2g;
 
        arg->peer_vht_caps = vht_cap->cap;
 
@@ -2341,7 +2350,7 @@ static void ath10k_peer_assoc_h_vht(struct ath10k *ar,
                                        ampdu_factor)) - 1);
 
        if (sta->bandwidth == IEEE80211_STA_RX_BW_80)
-               arg->peer_flags |= WMI_PEER_80MHZ;
+               arg->peer_flags |= ar->wmi.peer_flags->bw80;
 
        arg->peer_vht_rates.rx_max_rate =
                __le16_to_cpu(vht_cap->vht_mcs.rx_highest);
@@ -2366,27 +2375,28 @@ static void ath10k_peer_assoc_h_qos(struct ath10k *ar,
        switch (arvif->vdev_type) {
        case WMI_VDEV_TYPE_AP:
                if (sta->wme)
-                       arg->peer_flags |= WMI_PEER_QOS;
+                       arg->peer_flags |= arvif->ar->wmi.peer_flags->qos;
 
                if (sta->wme && sta->uapsd_queues) {
-                       arg->peer_flags |= WMI_PEER_APSD;
+                       arg->peer_flags |= arvif->ar->wmi.peer_flags->apsd;
                        arg->peer_rate_caps |= WMI_RC_UAPSD_FLAG;
                }
                break;
        case WMI_VDEV_TYPE_STA:
                if (vif->bss_conf.qos)
-                       arg->peer_flags |= WMI_PEER_QOS;
+                       arg->peer_flags |= arvif->ar->wmi.peer_flags->qos;
                break;
        case WMI_VDEV_TYPE_IBSS:
                if (sta->wme)
-                       arg->peer_flags |= WMI_PEER_QOS;
+                       arg->peer_flags |= arvif->ar->wmi.peer_flags->qos;
                break;
        default:
                break;
        }
 
        ath10k_dbg(ar, ATH10K_DBG_MAC, "mac peer %pM qos %d\n",
-                  sta->addr, !!(arg->peer_flags & WMI_PEER_QOS));
+                  sta->addr, !!(arg->peer_flags &
+                  arvif->ar->wmi.peer_flags->qos));
 }
 
 static bool ath10k_mac_sta_has_ofdm_only(struct ieee80211_sta *sta)
@@ -2479,7 +2489,7 @@ static int ath10k_peer_assoc_prepare(struct ath10k *ar,
        memset(arg, 0, sizeof(*arg));
 
        ath10k_peer_assoc_h_basic(ar, vif, sta, arg);
-       ath10k_peer_assoc_h_crypto(ar, vif, arg);
+       ath10k_peer_assoc_h_crypto(ar, vif, sta, arg);
        ath10k_peer_assoc_h_rates(ar, vif, sta, arg);
        ath10k_peer_assoc_h_ht(ar, vif, sta, arg);
        ath10k_peer_assoc_h_vht(ar, vif, sta, arg);
@@ -3112,35 +3122,11 @@ void ath10k_mac_handle_tx_pause_vdev(struct ath10k *ar, u32 vdev_id,
        spin_unlock_bh(&ar->htt.tx_lock);
 }
 
-static u8 ath10k_tx_h_get_tid(struct ieee80211_hdr *hdr)
-{
-       if (ieee80211_is_mgmt(hdr->frame_control))
-               return HTT_DATA_TX_EXT_TID_MGMT;
-
-       if (!ieee80211_is_data_qos(hdr->frame_control))
-               return HTT_DATA_TX_EXT_TID_NON_QOS_MCAST_BCAST;
-
-       if (!is_unicast_ether_addr(ieee80211_get_DA(hdr)))
-               return HTT_DATA_TX_EXT_TID_NON_QOS_MCAST_BCAST;
-
-       return ieee80211_get_qos_ctl(hdr)[0] & IEEE80211_QOS_CTL_TID_MASK;
-}
-
-static u8 ath10k_tx_h_get_vdev_id(struct ath10k *ar, struct ieee80211_vif *vif)
-{
-       if (vif)
-               return ath10k_vif_to_arvif(vif)->vdev_id;
-
-       if (ar->monitor_started)
-               return ar->monitor_vdev_id;
-
-       ath10k_warn(ar, "failed to resolve vdev id\n");
-       return 0;
-}
-
 static enum ath10k_hw_txrx_mode
-ath10k_tx_h_get_txmode(struct ath10k *ar, struct ieee80211_vif *vif,
-                      struct ieee80211_sta *sta, struct sk_buff *skb)
+ath10k_mac_tx_h_get_txmode(struct ath10k *ar,
+                          struct ieee80211_vif *vif,
+                          struct ieee80211_sta *sta,
+                          struct sk_buff *skb)
 {
        const struct ieee80211_hdr *hdr = (void *)skb->data;
        __le16 fc = hdr->frame_control;
@@ -3190,14 +3176,22 @@ ath10k_tx_h_get_txmode(struct ath10k *ar, struct ieee80211_vif *vif,
 }
 
 static bool ath10k_tx_h_use_hwcrypto(struct ieee80211_vif *vif,
-                                    struct sk_buff *skb) {
-       struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+                                    struct sk_buff *skb)
+{
+       const struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+       const struct ieee80211_hdr *hdr = (void *)skb->data;
        const u32 mask = IEEE80211_TX_INTFL_DONT_ENCRYPT |
                         IEEE80211_TX_CTL_INJECTED;
+
+       if (!ieee80211_has_protected(hdr->frame_control))
+               return false;
+
        if ((info->flags & mask) == mask)
                return false;
+
        if (vif)
                return !ath10k_vif_to_arvif(vif)->nohwcrypt;
+
        return true;
 }
 
@@ -3224,7 +3218,7 @@ static void ath10k_tx_h_nwifi(struct ieee80211_hw *hw, struct sk_buff *skb)
         */
        hdr = (void *)skb->data;
        if (ieee80211_is_qos_nullfunc(hdr->frame_control))
-               cb->htt.tid = HTT_DATA_TX_EXT_TID_NON_QOS_MCAST_BCAST;
+               cb->flags &= ~ATH10K_SKB_F_QOS;
 
        hdr->frame_control &= ~__cpu_to_le16(IEEE80211_STYPE_QOS_DATA);
 }
@@ -3280,7 +3274,7 @@ static void ath10k_tx_h_add_p2p_noa_ie(struct ath10k *ar,
        }
 }
 
-static bool ath10k_mac_need_offchan_tx_work(struct ath10k *ar)
+bool ath10k_mac_tx_frm_has_freq(struct ath10k *ar)
 {
        /* FIXME: Not really sure since when the behaviour changed. At some
         * point new firmware stopped requiring creation of peer entries for
@@ -3288,8 +3282,9 @@ static bool ath10k_mac_need_offchan_tx_work(struct ath10k *ar)
         * tx credit replenishment and reliability). Assuming it's at least 3.4
         * because that's when the `freq` was introduced to TX_FRM HTT command.
         */
-       return !(ar->htt.target_version_major >= 3 &&
-                ar->htt.target_version_minor >= 4);
+       return (ar->htt.target_version_major >= 3 &&
+               ar->htt.target_version_minor >= 4 &&
+               ar->htt.op_version == ATH10K_FW_HTT_OP_VERSION_TLV);
 }
 
 static int ath10k_mac_tx_wmi_mgmt(struct ath10k *ar, struct sk_buff *skb)
@@ -3314,24 +3309,24 @@ unlock:
        return ret;
 }
 
-static void ath10k_mac_tx(struct ath10k *ar, struct sk_buff *skb)
+static void ath10k_mac_tx(struct ath10k *ar, enum ath10k_hw_txrx_mode txmode,
+                         struct sk_buff *skb)
 {
-       struct ath10k_skb_cb *cb = ATH10K_SKB_CB(skb);
        struct ath10k_htt *htt = &ar->htt;
        int ret = 0;
 
-       switch (cb->txmode) {
+       switch (txmode) {
        case ATH10K_HW_TXRX_RAW:
        case ATH10K_HW_TXRX_NATIVE_WIFI:
        case ATH10K_HW_TXRX_ETHERNET:
-               ret = ath10k_htt_tx(htt, skb);
+               ret = ath10k_htt_tx(htt, txmode, skb);
                break;
        case ATH10K_HW_TXRX_MGMT:
                if (test_bit(ATH10K_FW_FEATURE_HAS_WMI_MGMT_TX,
                             ar->fw_features))
                        ret = ath10k_mac_tx_wmi_mgmt(ar, skb);
                else if (ar->htt.target_version_major >= 3)
-                       ret = ath10k_htt_tx(htt, skb);
+                       ret = ath10k_htt_tx(htt, txmode, skb);
                else
                        ret = ath10k_htt_mgmt_tx(htt, skb);
                break;
@@ -3361,9 +3356,13 @@ void ath10k_offchan_tx_work(struct work_struct *work)
 {
        struct ath10k *ar = container_of(work, struct ath10k, offchan_tx_work);
        struct ath10k_peer *peer;
+       struct ath10k_vif *arvif;
        struct ieee80211_hdr *hdr;
+       struct ieee80211_vif *vif;
+       struct ieee80211_sta *sta;
        struct sk_buff *skb;
        const u8 *peer_addr;
+       enum ath10k_hw_txrx_mode txmode;
        int vdev_id;
        int ret;
        unsigned long time_left;
@@ -3388,9 +3387,9 @@ void ath10k_offchan_tx_work(struct work_struct *work)
 
                hdr = (struct ieee80211_hdr *)skb->data;
                peer_addr = ieee80211_get_DA(hdr);
-               vdev_id = ATH10K_SKB_CB(skb)->vdev_id;
 
                spin_lock_bh(&ar->data_lock);
+               vdev_id = ar->scan.vdev_id;
                peer = ath10k_peer_find(ar, vdev_id, peer_addr);
                spin_unlock_bh(&ar->data_lock);
 
@@ -3413,7 +3412,22 @@ void ath10k_offchan_tx_work(struct work_struct *work)
                ar->offchan_tx_skb = skb;
                spin_unlock_bh(&ar->data_lock);
 
-               ath10k_mac_tx(ar, skb);
+               /* It's safe to access vif and sta - conf_mutex guarantees that
+                * sta_state() and remove_interface() are locked exclusively
+                * out wrt to this offchannel worker.
+                */
+               arvif = ath10k_get_arvif(ar, vdev_id);
+               if (arvif) {
+                       vif = arvif->vif;
+                       sta = ieee80211_find_sta(vif, peer_addr);
+               } else {
+                       vif = NULL;
+                       sta = NULL;
+               }
+
+               txmode = ath10k_mac_tx_h_get_txmode(ar, vif, sta, skb);
+
+               ath10k_mac_tx(ar, txmode, skb);
 
                time_left =
                wait_for_completion_timeout(&ar->offchan_tx_completed, 3 * HZ);
@@ -3488,6 +3502,7 @@ void __ath10k_scan_finish(struct ath10k *ar)
        case ATH10K_SCAN_STARTING:
                ar->scan.state = ATH10K_SCAN_IDLE;
                ar->scan_channel = NULL;
+               ar->scan.roc_freq = 0;
                ath10k_offchan_tx_purge(ar);
                cancel_delayed_work(&ar->scan.timeout);
                complete_all(&ar->scan.completed);
@@ -3631,25 +3646,32 @@ static void ath10k_tx(struct ieee80211_hw *hw,
                      struct sk_buff *skb)
 {
        struct ath10k *ar = hw->priv;
+       struct ath10k_skb_cb *skb_cb = ATH10K_SKB_CB(skb);
        struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
        struct ieee80211_vif *vif = info->control.vif;
        struct ieee80211_sta *sta = control->sta;
        struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
-       __le16 fc = hdr->frame_control;
+       enum ath10k_hw_txrx_mode txmode;
 
        /* We should disable CCK RATE due to P2P */
        if (info->flags & IEEE80211_TX_CTL_NO_CCK_RATE)
                ath10k_dbg(ar, ATH10K_DBG_MAC, "IEEE80211_TX_CTL_NO_CCK_RATE\n");
 
-       ATH10K_SKB_CB(skb)->htt.is_offchan = false;
-       ATH10K_SKB_CB(skb)->htt.freq = 0;
-       ATH10K_SKB_CB(skb)->htt.tid = ath10k_tx_h_get_tid(hdr);
-       ATH10K_SKB_CB(skb)->htt.nohwcrypt = !ath10k_tx_h_use_hwcrypto(vif, skb);
-       ATH10K_SKB_CB(skb)->vdev_id = ath10k_tx_h_get_vdev_id(ar, vif);
-       ATH10K_SKB_CB(skb)->txmode = ath10k_tx_h_get_txmode(ar, vif, sta, skb);
-       ATH10K_SKB_CB(skb)->is_protected = ieee80211_has_protected(fc);
+       txmode = ath10k_mac_tx_h_get_txmode(ar, vif, sta, skb);
+
+       skb_cb->flags = 0;
+       if (!ath10k_tx_h_use_hwcrypto(vif, skb))
+               skb_cb->flags |= ATH10K_SKB_F_NO_HWCRYPT;
+
+       if (ieee80211_is_mgmt(hdr->frame_control))
+               skb_cb->flags |= ATH10K_SKB_F_MGMT;
 
-       switch (ATH10K_SKB_CB(skb)->txmode) {
+       if (ieee80211_is_data_qos(hdr->frame_control))
+               skb_cb->flags |= ATH10K_SKB_F_QOS;
+
+       skb_cb->vif = vif;
+
+       switch (txmode) {
        case ATH10K_HW_TXRX_MGMT:
        case ATH10K_HW_TXRX_NATIVE_WIFI:
                ath10k_tx_h_nwifi(hw, skb);
@@ -3668,15 +3690,7 @@ static void ath10k_tx(struct ieee80211_hw *hw,
        }
 
        if (info->flags & IEEE80211_TX_CTL_TX_OFFCHAN) {
-               spin_lock_bh(&ar->data_lock);
-               ATH10K_SKB_CB(skb)->htt.freq = ar->scan.roc_freq;
-               ATH10K_SKB_CB(skb)->vdev_id = ar->scan.vdev_id;
-               spin_unlock_bh(&ar->data_lock);
-
-               if (ath10k_mac_need_offchan_tx_work(ar)) {
-                       ATH10K_SKB_CB(skb)->htt.freq = 0;
-                       ATH10K_SKB_CB(skb)->htt.is_offchan = true;
-
+               if (!ath10k_mac_tx_frm_has_freq(ar)) {
                        ath10k_dbg(ar, ATH10K_DBG_MAC, "queued offchannel skb %p\n",
                                   skb);
 
@@ -3686,7 +3700,7 @@ static void ath10k_tx(struct ieee80211_hw *hw,
                }
        }
 
-       ath10k_mac_tx(ar, skb);
+       ath10k_mac_tx(ar, txmode, skb);
 }
 
 /* Must not be called with conf_mutex held as workers can use that also. */
@@ -4225,7 +4239,7 @@ static int ath10k_config(struct ieee80211_hw *hw, u32 changed)
 
 static u32 get_nss_from_chainmask(u16 chain_mask)
 {
-       if ((chain_mask & 0x15) == 0x15)
+       if ((chain_mask & 0xf) == 0xf)
                return 4;
        else if ((chain_mask & 0x7) == 0x7)
                return 3;
@@ -4350,7 +4364,9 @@ static int ath10k_add_interface(struct ieee80211_hw *hw,
                arvif->vdev_type = WMI_VDEV_TYPE_IBSS;
                break;
        case NL80211_IFTYPE_MESH_POINT:
-               if (!test_bit(ATH10K_FLAG_RAW_MODE, &ar->dev_flags)) {
+               if (test_bit(WMI_SERVICE_MESH, ar->wmi.svc_map)) {
+                       arvif->vdev_subtype = WMI_VDEV_SUBTYPE_MESH;
+               } else if (!test_bit(ATH10K_FLAG_RAW_MODE, &ar->dev_flags)) {
                        ret = -EINVAL;
                        ath10k_warn(ar, "must load driver with rawmode=1 to add mesh interfaces\n");
                        goto err;
@@ -6907,35 +6923,39 @@ void ath10k_mac_destroy(struct ath10k *ar)
 
 static const struct ieee80211_iface_limit ath10k_if_limits[] = {
        {
-       .max    = 8,
-       .types  = BIT(NL80211_IFTYPE_STATION)
-               | BIT(NL80211_IFTYPE_P2P_CLIENT)
+               .max    = 8,
+               .types  = BIT(NL80211_IFTYPE_STATION)
+                       | BIT(NL80211_IFTYPE_P2P_CLIENT)
        },
        {
-       .max    = 3,
-       .types  = BIT(NL80211_IFTYPE_P2P_GO)
+               .max    = 3,
+               .types  = BIT(NL80211_IFTYPE_P2P_GO)
        },
        {
-       .max    = 1,
-       .types  = BIT(NL80211_IFTYPE_P2P_DEVICE)
+               .max    = 1,
+               .types  = BIT(NL80211_IFTYPE_P2P_DEVICE)
        },
        {
-       .max    = 7,
-       .types  = BIT(NL80211_IFTYPE_AP)
+               .max    = 7,
+               .types  = BIT(NL80211_IFTYPE_AP)
 #ifdef CONFIG_MAC80211_MESH
-               | BIT(NL80211_IFTYPE_MESH_POINT)
+                       | BIT(NL80211_IFTYPE_MESH_POINT)
 #endif
        },
 };
 
 static const struct ieee80211_iface_limit ath10k_10x_if_limits[] = {
        {
-       .max    = 8,
-       .types  = BIT(NL80211_IFTYPE_AP)
+               .max    = 8,
+               .types  = BIT(NL80211_IFTYPE_AP)
 #ifdef CONFIG_MAC80211_MESH
-               | BIT(NL80211_IFTYPE_MESH_POINT)
+                       | BIT(NL80211_IFTYPE_MESH_POINT)
 #endif
        },
+       {
+               .max    = 1,
+               .types  = BIT(NL80211_IFTYPE_STATION)
+       },
 };
 
 static const struct ieee80211_iface_combination ath10k_if_comb[] = {