diff options
| -rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-devtrace.h | 10 | ||||
| -rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-phy-db.c | 16 | ||||
| -rw-r--r-- | drivers/net/wireless/iwlwifi/mvm/d3.c | 104 | ||||
| -rw-r--r-- | drivers/net/wireless/iwlwifi/mvm/mac80211.c | 19 | ||||
| -rw-r--r-- | drivers/net/wireless/iwlwifi/mvm/mvm.h | 4 | ||||
| -rw-r--r-- | drivers/net/wireless/iwlwifi/pcie/internal.h | 9 | ||||
| -rw-r--r-- | drivers/net/wireless/iwlwifi/pcie/tx.c | 75 |
7 files changed, 166 insertions, 71 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl-devtrace.h b/drivers/net/wireless/iwlwifi/iwl-devtrace.h index 9a0f45ec9e01..10f01793d7a6 100644 --- a/drivers/net/wireless/iwlwifi/iwl-devtrace.h +++ b/drivers/net/wireless/iwlwifi/iwl-devtrace.h | |||
| @@ -349,25 +349,23 @@ TRACE_EVENT(iwlwifi_dev_rx_data, | |||
| 349 | TRACE_EVENT(iwlwifi_dev_hcmd, | 349 | TRACE_EVENT(iwlwifi_dev_hcmd, |
| 350 | TP_PROTO(const struct device *dev, | 350 | TP_PROTO(const struct device *dev, |
| 351 | struct iwl_host_cmd *cmd, u16 total_size, | 351 | struct iwl_host_cmd *cmd, u16 total_size, |
| 352 | const void *hdr, size_t hdr_len), | 352 | struct iwl_cmd_header *hdr), |
| 353 | TP_ARGS(dev, cmd, total_size, hdr, hdr_len), | 353 | TP_ARGS(dev, cmd, total_size, hdr), |
| 354 | TP_STRUCT__entry( | 354 | TP_STRUCT__entry( |
| 355 | DEV_ENTRY | 355 | DEV_ENTRY |
| 356 | __dynamic_array(u8, hcmd, total_size) | 356 | __dynamic_array(u8, hcmd, total_size) |
| 357 | __field(u32, flags) | 357 | __field(u32, flags) |
| 358 | ), | 358 | ), |
| 359 | TP_fast_assign( | 359 | TP_fast_assign( |
| 360 | int i, offset = hdr_len; | 360 | int i, offset = sizeof(*hdr); |
| 361 | 361 | ||
| 362 | DEV_ASSIGN; | 362 | DEV_ASSIGN; |
| 363 | __entry->flags = cmd->flags; | 363 | __entry->flags = cmd->flags; |
| 364 | memcpy(__get_dynamic_array(hcmd), hdr, hdr_len); | 364 | memcpy(__get_dynamic_array(hcmd), hdr, sizeof(*hdr)); |
| 365 | 365 | ||
| 366 | for (i = 0; i < IWL_MAX_CMD_TFDS; i++) { | 366 | for (i = 0; i < IWL_MAX_CMD_TFDS; i++) { |
| 367 | if (!cmd->len[i]) | 367 | if (!cmd->len[i]) |
| 368 | continue; | 368 | continue; |
| 369 | if (!(cmd->dataflags[i] & IWL_HCMD_DFL_NOCOPY)) | ||
| 370 | continue; | ||
| 371 | memcpy((u8 *)__get_dynamic_array(hcmd) + offset, | 369 | memcpy((u8 *)__get_dynamic_array(hcmd) + offset, |
| 372 | cmd->data[i], cmd->len[i]); | 370 | cmd->data[i], cmd->len[i]); |
| 373 | offset += cmd->len[i]; | 371 | offset += cmd->len[i]; |
diff --git a/drivers/net/wireless/iwlwifi/iwl-phy-db.c b/drivers/net/wireless/iwlwifi/iwl-phy-db.c index 14fc8d39fc28..3392011a8768 100644 --- a/drivers/net/wireless/iwlwifi/iwl-phy-db.c +++ b/drivers/net/wireless/iwlwifi/iwl-phy-db.c | |||
| @@ -136,12 +136,6 @@ struct iwl_calib_res_notif_phy_db { | |||
| 136 | u8 data[]; | 136 | u8 data[]; |
| 137 | } __packed; | 137 | } __packed; |
| 138 | 138 | ||
| 139 | #define IWL_PHY_DB_STATIC_PIC cpu_to_le32(0x21436587) | ||
| 140 | static inline void iwl_phy_db_test_pic(__le32 pic) | ||
| 141 | { | ||
| 142 | WARN_ON(IWL_PHY_DB_STATIC_PIC != pic); | ||
| 143 | } | ||
| 144 | |||
| 145 | struct iwl_phy_db *iwl_phy_db_init(struct iwl_trans *trans) | 139 | struct iwl_phy_db *iwl_phy_db_init(struct iwl_trans *trans) |
| 146 | { | 140 | { |
| 147 | struct iwl_phy_db *phy_db = kzalloc(sizeof(struct iwl_phy_db), | 141 | struct iwl_phy_db *phy_db = kzalloc(sizeof(struct iwl_phy_db), |
| @@ -260,11 +254,6 @@ int iwl_phy_db_set_section(struct iwl_phy_db *phy_db, struct iwl_rx_packet *pkt, | |||
| 260 | (size - CHANNEL_NUM_SIZE) / phy_db->channel_num; | 254 | (size - CHANNEL_NUM_SIZE) / phy_db->channel_num; |
| 261 | } | 255 | } |
| 262 | 256 | ||
| 263 | /* Test PIC */ | ||
| 264 | if (type != IWL_PHY_DB_CFG) | ||
| 265 | iwl_phy_db_test_pic(*(((__le32 *)phy_db_notif->data) + | ||
| 266 | (size / sizeof(__le32)) - 1)); | ||
| 267 | |||
| 268 | IWL_DEBUG_INFO(phy_db->trans, | 257 | IWL_DEBUG_INFO(phy_db->trans, |
| 269 | "%s(%d): [PHYDB]SET: Type %d , Size: %d\n", | 258 | "%s(%d): [PHYDB]SET: Type %d , Size: %d\n", |
| 270 | __func__, __LINE__, type, size); | 259 | __func__, __LINE__, type, size); |
| @@ -372,11 +361,6 @@ int iwl_phy_db_get_section_data(struct iwl_phy_db *phy_db, | |||
| 372 | *size = entry->size; | 361 | *size = entry->size; |
| 373 | } | 362 | } |
| 374 | 363 | ||
| 375 | /* Test PIC */ | ||
| 376 | if (type != IWL_PHY_DB_CFG) | ||
| 377 | iwl_phy_db_test_pic(*(((__le32 *)*data) + | ||
| 378 | (*size / sizeof(__le32)) - 1)); | ||
| 379 | |||
| 380 | IWL_DEBUG_INFO(phy_db->trans, | 364 | IWL_DEBUG_INFO(phy_db->trans, |
| 381 | "%s(%d): [PHYDB] GET: Type %d , Size: %d\n", | 365 | "%s(%d): [PHYDB] GET: Type %d , Size: %d\n", |
| 382 | __func__, __LINE__, type, *size); | 366 | __func__, __LINE__, type, *size); |
diff --git a/drivers/net/wireless/iwlwifi/mvm/d3.c b/drivers/net/wireless/iwlwifi/mvm/d3.c index c64d864799cd..994c8c263dc0 100644 --- a/drivers/net/wireless/iwlwifi/mvm/d3.c +++ b/drivers/net/wireless/iwlwifi/mvm/d3.c | |||
| @@ -61,6 +61,7 @@ | |||
| 61 | * | 61 | * |
| 62 | *****************************************************************************/ | 62 | *****************************************************************************/ |
| 63 | 63 | ||
| 64 | #include <linux/etherdevice.h> | ||
| 64 | #include <net/cfg80211.h> | 65 | #include <net/cfg80211.h> |
| 65 | #include <net/ipv6.h> | 66 | #include <net/ipv6.h> |
| 66 | #include "iwl-modparams.h" | 67 | #include "iwl-modparams.h" |
| @@ -192,6 +193,11 @@ static void iwl_mvm_wowlan_program_keys(struct ieee80211_hw *hw, | |||
| 192 | sizeof(wkc), &wkc); | 193 | sizeof(wkc), &wkc); |
| 193 | data->error = ret != 0; | 194 | data->error = ret != 0; |
| 194 | 195 | ||
| 196 | mvm->ptk_ivlen = key->iv_len; | ||
| 197 | mvm->ptk_icvlen = key->icv_len; | ||
| 198 | mvm->gtk_ivlen = key->iv_len; | ||
| 199 | mvm->gtk_icvlen = key->icv_len; | ||
| 200 | |||
| 195 | /* don't upload key again */ | 201 | /* don't upload key again */ |
| 196 | goto out_unlock; | 202 | goto out_unlock; |
| 197 | } | 203 | } |
| @@ -304,9 +310,13 @@ static void iwl_mvm_wowlan_program_keys(struct ieee80211_hw *hw, | |||
| 304 | */ | 310 | */ |
| 305 | if (key->flags & IEEE80211_KEY_FLAG_PAIRWISE) { | 311 | if (key->flags & IEEE80211_KEY_FLAG_PAIRWISE) { |
| 306 | key->hw_key_idx = 0; | 312 | key->hw_key_idx = 0; |
| 313 | mvm->ptk_ivlen = key->iv_len; | ||
| 314 | mvm->ptk_icvlen = key->icv_len; | ||
| 307 | } else { | 315 | } else { |
| 308 | data->gtk_key_idx++; | 316 | data->gtk_key_idx++; |
| 309 | key->hw_key_idx = data->gtk_key_idx; | 317 | key->hw_key_idx = data->gtk_key_idx; |
| 318 | mvm->gtk_ivlen = key->iv_len; | ||
| 319 | mvm->gtk_icvlen = key->icv_len; | ||
| 310 | } | 320 | } |
| 311 | 321 | ||
| 312 | ret = iwl_mvm_set_sta_key(mvm, vif, sta, key, true); | 322 | ret = iwl_mvm_set_sta_key(mvm, vif, sta, key, true); |
| @@ -649,6 +659,11 @@ int iwl_mvm_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan) | |||
| 649 | /* We reprogram keys and shouldn't allocate new key indices */ | 659 | /* We reprogram keys and shouldn't allocate new key indices */ |
| 650 | memset(mvm->fw_key_table, 0, sizeof(mvm->fw_key_table)); | 660 | memset(mvm->fw_key_table, 0, sizeof(mvm->fw_key_table)); |
| 651 | 661 | ||
| 662 | mvm->ptk_ivlen = 0; | ||
| 663 | mvm->ptk_icvlen = 0; | ||
| 664 | mvm->ptk_ivlen = 0; | ||
| 665 | mvm->ptk_icvlen = 0; | ||
| 666 | |||
| 652 | /* | 667 | /* |
| 653 | * The D3 firmware still hardcodes the AP station ID for the | 668 | * The D3 firmware still hardcodes the AP station ID for the |
| 654 | * BSS we're associated with as 0. As a result, we have to move | 669 | * BSS we're associated with as 0. As a result, we have to move |
| @@ -783,7 +798,6 @@ static void iwl_mvm_query_wakeup_reasons(struct iwl_mvm *mvm, | |||
| 783 | struct iwl_wowlan_status *status; | 798 | struct iwl_wowlan_status *status; |
| 784 | u32 reasons; | 799 | u32 reasons; |
| 785 | int ret, len; | 800 | int ret, len; |
| 786 | bool pkt8023 = false; | ||
| 787 | struct sk_buff *pkt = NULL; | 801 | struct sk_buff *pkt = NULL; |
| 788 | 802 | ||
| 789 | iwl_trans_read_mem_bytes(mvm->trans, base, | 803 | iwl_trans_read_mem_bytes(mvm->trans, base, |
| @@ -824,7 +838,8 @@ static void iwl_mvm_query_wakeup_reasons(struct iwl_mvm *mvm, | |||
| 824 | status = (void *)cmd.resp_pkt->data; | 838 | status = (void *)cmd.resp_pkt->data; |
| 825 | 839 | ||
| 826 | if (len - sizeof(struct iwl_cmd_header) != | 840 | if (len - sizeof(struct iwl_cmd_header) != |
| 827 | sizeof(*status) + le32_to_cpu(status->wake_packet_bufsize)) { | 841 | sizeof(*status) + |
| 842 | ALIGN(le32_to_cpu(status->wake_packet_bufsize), 4)) { | ||
| 828 | IWL_ERR(mvm, "Invalid WoWLAN status response!\n"); | 843 | IWL_ERR(mvm, "Invalid WoWLAN status response!\n"); |
| 829 | goto out; | 844 | goto out; |
| 830 | } | 845 | } |
| @@ -836,61 +851,96 @@ static void iwl_mvm_query_wakeup_reasons(struct iwl_mvm *mvm, | |||
| 836 | goto report; | 851 | goto report; |
| 837 | } | 852 | } |
| 838 | 853 | ||
| 839 | if (reasons & IWL_WOWLAN_WAKEUP_BY_MAGIC_PACKET) { | 854 | if (reasons & IWL_WOWLAN_WAKEUP_BY_MAGIC_PACKET) |
| 840 | wakeup.magic_pkt = true; | 855 | wakeup.magic_pkt = true; |
| 841 | pkt8023 = true; | ||
| 842 | } | ||
| 843 | 856 | ||
| 844 | if (reasons & IWL_WOWLAN_WAKEUP_BY_PATTERN) { | 857 | if (reasons & IWL_WOWLAN_WAKEUP_BY_PATTERN) |
| 845 | wakeup.pattern_idx = | 858 | wakeup.pattern_idx = |
| 846 | le16_to_cpu(status->pattern_number); | 859 | le16_to_cpu(status->pattern_number); |
| 847 | pkt8023 = true; | ||
| 848 | } | ||
| 849 | 860 | ||
| 850 | if (reasons & (IWL_WOWLAN_WAKEUP_BY_DISCONNECTION_ON_MISSED_BEACON | | 861 | if (reasons & (IWL_WOWLAN_WAKEUP_BY_DISCONNECTION_ON_MISSED_BEACON | |
| 851 | IWL_WOWLAN_WAKEUP_BY_DISCONNECTION_ON_DEAUTH)) | 862 | IWL_WOWLAN_WAKEUP_BY_DISCONNECTION_ON_DEAUTH)) |
| 852 | wakeup.disconnect = true; | 863 | wakeup.disconnect = true; |
| 853 | 864 | ||
| 854 | if (reasons & IWL_WOWLAN_WAKEUP_BY_GTK_REKEY_FAILURE) { | 865 | if (reasons & IWL_WOWLAN_WAKEUP_BY_GTK_REKEY_FAILURE) |
| 855 | wakeup.gtk_rekey_failure = true; | 866 | wakeup.gtk_rekey_failure = true; |
| 856 | pkt8023 = true; | ||
| 857 | } | ||
| 858 | 867 | ||
| 859 | if (reasons & IWL_WOWLAN_WAKEUP_BY_RFKILL_DEASSERTED) { | 868 | if (reasons & IWL_WOWLAN_WAKEUP_BY_RFKILL_DEASSERTED) |
| 860 | wakeup.rfkill_release = true; | 869 | wakeup.rfkill_release = true; |
| 861 | pkt8023 = true; | ||
| 862 | } | ||
| 863 | 870 | ||
| 864 | if (reasons & IWL_WOWLAN_WAKEUP_BY_EAPOL_REQUEST) { | 871 | if (reasons & IWL_WOWLAN_WAKEUP_BY_EAPOL_REQUEST) |
| 865 | wakeup.eap_identity_req = true; | 872 | wakeup.eap_identity_req = true; |
| 866 | pkt8023 = true; | ||
| 867 | } | ||
| 868 | 873 | ||
| 869 | if (reasons & IWL_WOWLAN_WAKEUP_BY_FOUR_WAY_HANDSHAKE) { | 874 | if (reasons & IWL_WOWLAN_WAKEUP_BY_FOUR_WAY_HANDSHAKE) |
| 870 | wakeup.four_way_handshake = true; | 875 | wakeup.four_way_handshake = true; |
| 871 | pkt8023 = true; | ||
| 872 | } | ||
| 873 | 876 | ||
| 874 | if (status->wake_packet_bufsize) { | 877 | if (status->wake_packet_bufsize) { |
| 875 | u32 pktsize = le32_to_cpu(status->wake_packet_bufsize); | 878 | int pktsize = le32_to_cpu(status->wake_packet_bufsize); |
| 876 | u32 pktlen = le32_to_cpu(status->wake_packet_length); | 879 | int pktlen = le32_to_cpu(status->wake_packet_length); |
| 880 | const u8 *pktdata = status->wake_packet; | ||
| 881 | struct ieee80211_hdr *hdr = (void *)pktdata; | ||
| 882 | int truncated = pktlen - pktsize; | ||
| 883 | |||
| 884 | /* this would be a firmware bug */ | ||
| 885 | if (WARN_ON_ONCE(truncated < 0)) | ||
| 886 | truncated = 0; | ||
| 887 | |||
| 888 | if (ieee80211_is_data(hdr->frame_control)) { | ||
| 889 | int hdrlen = ieee80211_hdrlen(hdr->frame_control); | ||
| 890 | int ivlen = 0, icvlen = 4; /* also FCS */ | ||
| 877 | 891 | ||
| 878 | if (pkt8023) { | ||
| 879 | pkt = alloc_skb(pktsize, GFP_KERNEL); | 892 | pkt = alloc_skb(pktsize, GFP_KERNEL); |
| 880 | if (!pkt) | 893 | if (!pkt) |
| 881 | goto report; | 894 | goto report; |
| 882 | memcpy(skb_put(pkt, pktsize), status->wake_packet, | 895 | |
| 883 | pktsize); | 896 | memcpy(skb_put(pkt, hdrlen), pktdata, hdrlen); |
| 897 | pktdata += hdrlen; | ||
| 898 | pktsize -= hdrlen; | ||
| 899 | |||
| 900 | if (ieee80211_has_protected(hdr->frame_control)) { | ||
| 901 | if (is_multicast_ether_addr(hdr->addr1)) { | ||
| 902 | ivlen = mvm->gtk_ivlen; | ||
| 903 | icvlen += mvm->gtk_icvlen; | ||
| 904 | } else { | ||
| 905 | ivlen = mvm->ptk_ivlen; | ||
| 906 | icvlen += mvm->ptk_icvlen; | ||
| 907 | } | ||
| 908 | } | ||
| 909 | |||
| 910 | /* if truncated, FCS/ICV is (partially) gone */ | ||
| 911 | if (truncated >= icvlen) { | ||
| 912 | icvlen = 0; | ||
| 913 | truncated -= icvlen; | ||
| 914 | } else { | ||
| 915 | icvlen -= truncated; | ||
| 916 | truncated = 0; | ||
| 917 | } | ||
| 918 | |||
| 919 | pktsize -= ivlen + icvlen; | ||
| 920 | pktdata += ivlen; | ||
| 921 | |||
| 922 | memcpy(skb_put(pkt, pktsize), pktdata, pktsize); | ||
| 923 | |||
| 884 | if (ieee80211_data_to_8023(pkt, vif->addr, vif->type)) | 924 | if (ieee80211_data_to_8023(pkt, vif->addr, vif->type)) |
| 885 | goto report; | 925 | goto report; |
| 886 | wakeup.packet = pkt->data; | 926 | wakeup.packet = pkt->data; |
| 887 | wakeup.packet_present_len = pkt->len; | 927 | wakeup.packet_present_len = pkt->len; |
| 888 | wakeup.packet_len = pkt->len - (pktlen - pktsize); | 928 | wakeup.packet_len = pkt->len - truncated; |
| 889 | wakeup.packet_80211 = false; | 929 | wakeup.packet_80211 = false; |
| 890 | } else { | 930 | } else { |
| 931 | int fcslen = 4; | ||
| 932 | |||
| 933 | if (truncated >= 4) { | ||
| 934 | truncated -= 4; | ||
| 935 | fcslen = 0; | ||
| 936 | } else { | ||
| 937 | fcslen -= truncated; | ||
| 938 | truncated = 0; | ||
| 939 | } | ||
| 940 | pktsize -= fcslen; | ||
| 891 | wakeup.packet = status->wake_packet; | 941 | wakeup.packet = status->wake_packet; |
| 892 | wakeup.packet_present_len = pktsize; | 942 | wakeup.packet_present_len = pktsize; |
| 893 | wakeup.packet_len = pktlen; | 943 | wakeup.packet_len = pktlen - truncated; |
| 894 | wakeup.packet_80211 = true; | 944 | wakeup.packet_80211 = true; |
| 895 | } | 945 | } |
| 896 | } | 946 | } |
diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c index e8264e11b12d..7e169b085afe 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c | |||
| @@ -557,11 +557,9 @@ static int iwl_mvm_mac_add_interface(struct ieee80211_hw *hw, | |||
| 557 | return ret; | 557 | return ret; |
| 558 | } | 558 | } |
| 559 | 559 | ||
| 560 | static void iwl_mvm_mac_remove_interface(struct ieee80211_hw *hw, | 560 | static void iwl_mvm_prepare_mac_removal(struct iwl_mvm *mvm, |
| 561 | struct ieee80211_vif *vif) | 561 | struct ieee80211_vif *vif) |
| 562 | { | 562 | { |
| 563 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); | ||
| 564 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); | ||
| 565 | u32 tfd_msk = 0, ac; | 563 | u32 tfd_msk = 0, ac; |
| 566 | 564 | ||
| 567 | for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) | 565 | for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) |
| @@ -594,12 +592,21 @@ static void iwl_mvm_mac_remove_interface(struct ieee80211_hw *hw, | |||
| 594 | */ | 592 | */ |
| 595 | flush_work(&mvm->sta_drained_wk); | 593 | flush_work(&mvm->sta_drained_wk); |
| 596 | } | 594 | } |
| 595 | } | ||
| 596 | |||
| 597 | static void iwl_mvm_mac_remove_interface(struct ieee80211_hw *hw, | ||
| 598 | struct ieee80211_vif *vif) | ||
| 599 | { | ||
| 600 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); | ||
| 601 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); | ||
| 602 | |||
| 603 | iwl_mvm_prepare_mac_removal(mvm, vif); | ||
| 597 | 604 | ||
| 598 | mutex_lock(&mvm->mutex); | 605 | mutex_lock(&mvm->mutex); |
| 599 | 606 | ||
| 600 | /* | 607 | /* |
| 601 | * For AP/GO interface, the tear down of the resources allocated to the | 608 | * For AP/GO interface, the tear down of the resources allocated to the |
| 602 | * interface should be handled as part of the bss_info_changed flow. | 609 | * interface is be handled as part of the stop_ap flow. |
| 603 | */ | 610 | */ |
| 604 | if (vif->type == NL80211_IFTYPE_AP) { | 611 | if (vif->type == NL80211_IFTYPE_AP) { |
| 605 | iwl_mvm_dealloc_int_sta(mvm, &mvmvif->bcast_sta); | 612 | iwl_mvm_dealloc_int_sta(mvm, &mvmvif->bcast_sta); |
| @@ -763,6 +770,8 @@ static void iwl_mvm_stop_ap(struct ieee80211_hw *hw, struct ieee80211_vif *vif) | |||
| 763 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); | 770 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); |
| 764 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); | 771 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); |
| 765 | 772 | ||
| 773 | iwl_mvm_prepare_mac_removal(mvm, vif); | ||
| 774 | |||
| 766 | mutex_lock(&mvm->mutex); | 775 | mutex_lock(&mvm->mutex); |
| 767 | 776 | ||
| 768 | mvmvif->ap_active = false; | 777 | mvmvif->ap_active = false; |
diff --git a/drivers/net/wireless/iwlwifi/mvm/mvm.h b/drivers/net/wireless/iwlwifi/mvm/mvm.h index 4e339ccfa800..537711b10478 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/iwlwifi/mvm/mvm.h | |||
| @@ -327,6 +327,10 @@ struct iwl_mvm { | |||
| 327 | struct led_classdev led; | 327 | struct led_classdev led; |
| 328 | 328 | ||
| 329 | struct ieee80211_vif *p2p_device_vif; | 329 | struct ieee80211_vif *p2p_device_vif; |
| 330 | |||
| 331 | #ifdef CONFIG_PM_SLEEP | ||
| 332 | int gtk_ivlen, gtk_icvlen, ptk_ivlen, ptk_icvlen; | ||
| 333 | #endif | ||
| 330 | }; | 334 | }; |
| 331 | 335 | ||
| 332 | /* Extract MVM priv from op_mode and _hw */ | 336 | /* Extract MVM priv from op_mode and _hw */ |
diff --git a/drivers/net/wireless/iwlwifi/pcie/internal.h b/drivers/net/wireless/iwlwifi/pcie/internal.h index aa2a39a637dd..3d62e8055352 100644 --- a/drivers/net/wireless/iwlwifi/pcie/internal.h +++ b/drivers/net/wireless/iwlwifi/pcie/internal.h | |||
| @@ -182,6 +182,15 @@ struct iwl_queue { | |||
| 182 | #define TFD_TX_CMD_SLOTS 256 | 182 | #define TFD_TX_CMD_SLOTS 256 |
| 183 | #define TFD_CMD_SLOTS 32 | 183 | #define TFD_CMD_SLOTS 32 |
| 184 | 184 | ||
| 185 | /* | ||
| 186 | * The FH will write back to the first TB only, so we need | ||
| 187 | * to copy some data into the buffer regardless of whether | ||
| 188 | * it should be mapped or not. This indicates how much to | ||
| 189 | * copy, even for HCMDs it must be big enough to fit the | ||
| 190 | * DRAM scratch from the TX cmd, at least 16 bytes. | ||
| 191 | */ | ||
| 192 | #define IWL_HCMD_MIN_COPY_SIZE 16 | ||
| 193 | |||
| 185 | struct iwl_pcie_txq_entry { | 194 | struct iwl_pcie_txq_entry { |
| 186 | struct iwl_device_cmd *cmd; | 195 | struct iwl_device_cmd *cmd; |
| 187 | struct iwl_device_cmd *copy_cmd; | 196 | struct iwl_device_cmd *copy_cmd; |
diff --git a/drivers/net/wireless/iwlwifi/pcie/tx.c b/drivers/net/wireless/iwlwifi/pcie/tx.c index 8e9e3212fe78..8b625a7f5685 100644 --- a/drivers/net/wireless/iwlwifi/pcie/tx.c +++ b/drivers/net/wireless/iwlwifi/pcie/tx.c | |||
| @@ -1152,10 +1152,12 @@ static int iwl_pcie_enqueue_hcmd(struct iwl_trans *trans, | |||
| 1152 | void *dup_buf = NULL; | 1152 | void *dup_buf = NULL; |
| 1153 | dma_addr_t phys_addr; | 1153 | dma_addr_t phys_addr; |
| 1154 | int idx; | 1154 | int idx; |
| 1155 | u16 copy_size, cmd_size; | 1155 | u16 copy_size, cmd_size, dma_size; |
| 1156 | bool had_nocopy = false; | 1156 | bool had_nocopy = false; |
| 1157 | int i; | 1157 | int i; |
| 1158 | u32 cmd_pos; | 1158 | u32 cmd_pos; |
| 1159 | const u8 *cmddata[IWL_MAX_CMD_TFDS]; | ||
| 1160 | u16 cmdlen[IWL_MAX_CMD_TFDS]; | ||
| 1159 | 1161 | ||
| 1160 | copy_size = sizeof(out_cmd->hdr); | 1162 | copy_size = sizeof(out_cmd->hdr); |
| 1161 | cmd_size = sizeof(out_cmd->hdr); | 1163 | cmd_size = sizeof(out_cmd->hdr); |
| @@ -1164,8 +1166,23 @@ static int iwl_pcie_enqueue_hcmd(struct iwl_trans *trans, | |||
| 1164 | BUILD_BUG_ON(IWL_MAX_CMD_TFDS > IWL_NUM_OF_TBS - 1); | 1166 | BUILD_BUG_ON(IWL_MAX_CMD_TFDS > IWL_NUM_OF_TBS - 1); |
| 1165 | 1167 | ||
| 1166 | for (i = 0; i < IWL_MAX_CMD_TFDS; i++) { | 1168 | for (i = 0; i < IWL_MAX_CMD_TFDS; i++) { |
| 1169 | cmddata[i] = cmd->data[i]; | ||
| 1170 | cmdlen[i] = cmd->len[i]; | ||
| 1171 | |||
| 1167 | if (!cmd->len[i]) | 1172 | if (!cmd->len[i]) |
| 1168 | continue; | 1173 | continue; |
| 1174 | |||
| 1175 | /* need at least IWL_HCMD_MIN_COPY_SIZE copied */ | ||
| 1176 | if (copy_size < IWL_HCMD_MIN_COPY_SIZE) { | ||
| 1177 | int copy = IWL_HCMD_MIN_COPY_SIZE - copy_size; | ||
| 1178 | |||
| 1179 | if (copy > cmdlen[i]) | ||
| 1180 | copy = cmdlen[i]; | ||
| 1181 | cmdlen[i] -= copy; | ||
| 1182 | cmddata[i] += copy; | ||
| 1183 | copy_size += copy; | ||
| 1184 | } | ||
| 1185 | |||
| 1169 | if (cmd->dataflags[i] & IWL_HCMD_DFL_NOCOPY) { | 1186 | if (cmd->dataflags[i] & IWL_HCMD_DFL_NOCOPY) { |
| 1170 | had_nocopy = true; | 1187 | had_nocopy = true; |
| 1171 | if (WARN_ON(cmd->dataflags[i] & IWL_HCMD_DFL_DUP)) { | 1188 | if (WARN_ON(cmd->dataflags[i] & IWL_HCMD_DFL_DUP)) { |
| @@ -1185,7 +1202,7 @@ static int iwl_pcie_enqueue_hcmd(struct iwl_trans *trans, | |||
| 1185 | goto free_dup_buf; | 1202 | goto free_dup_buf; |
| 1186 | } | 1203 | } |
| 1187 | 1204 | ||
| 1188 | dup_buf = kmemdup(cmd->data[i], cmd->len[i], | 1205 | dup_buf = kmemdup(cmddata[i], cmdlen[i], |
| 1189 | GFP_ATOMIC); | 1206 | GFP_ATOMIC); |
| 1190 | if (!dup_buf) | 1207 | if (!dup_buf) |
| 1191 | return -ENOMEM; | 1208 | return -ENOMEM; |
| @@ -1195,7 +1212,7 @@ static int iwl_pcie_enqueue_hcmd(struct iwl_trans *trans, | |||
| 1195 | idx = -EINVAL; | 1212 | idx = -EINVAL; |
| 1196 | goto free_dup_buf; | 1213 | goto free_dup_buf; |
| 1197 | } | 1214 | } |
| 1198 | copy_size += cmd->len[i]; | 1215 | copy_size += cmdlen[i]; |
| 1199 | } | 1216 | } |
| 1200 | cmd_size += cmd->len[i]; | 1217 | cmd_size += cmd->len[i]; |
| 1201 | } | 1218 | } |
| @@ -1242,14 +1259,31 @@ static int iwl_pcie_enqueue_hcmd(struct iwl_trans *trans, | |||
| 1242 | 1259 | ||
| 1243 | /* and copy the data that needs to be copied */ | 1260 | /* and copy the data that needs to be copied */ |
| 1244 | cmd_pos = offsetof(struct iwl_device_cmd, payload); | 1261 | cmd_pos = offsetof(struct iwl_device_cmd, payload); |
| 1262 | copy_size = sizeof(out_cmd->hdr); | ||
| 1245 | for (i = 0; i < IWL_MAX_CMD_TFDS; i++) { | 1263 | for (i = 0; i < IWL_MAX_CMD_TFDS; i++) { |
| 1246 | if (!cmd->len[i]) | 1264 | int copy = 0; |
| 1265 | |||
| 1266 | if (!cmd->len) | ||
| 1247 | continue; | 1267 | continue; |
| 1248 | if (cmd->dataflags[i] & (IWL_HCMD_DFL_NOCOPY | | 1268 | |
| 1249 | IWL_HCMD_DFL_DUP)) | 1269 | /* need at least IWL_HCMD_MIN_COPY_SIZE copied */ |
| 1250 | break; | 1270 | if (copy_size < IWL_HCMD_MIN_COPY_SIZE) { |
| 1251 | memcpy((u8 *)out_cmd + cmd_pos, cmd->data[i], cmd->len[i]); | 1271 | copy = IWL_HCMD_MIN_COPY_SIZE - copy_size; |
| 1252 | cmd_pos += cmd->len[i]; | 1272 | |
| 1273 | if (copy > cmd->len[i]) | ||
| 1274 | copy = cmd->len[i]; | ||
| 1275 | } | ||
| 1276 | |||
| 1277 | /* copy everything if not nocopy/dup */ | ||
| 1278 | if (!(cmd->dataflags[i] & (IWL_HCMD_DFL_NOCOPY | | ||
| 1279 | IWL_HCMD_DFL_DUP))) | ||
| 1280 | copy = cmd->len[i]; | ||
| 1281 | |||
| 1282 | if (copy) { | ||
| 1283 | memcpy((u8 *)out_cmd + cmd_pos, cmd->data[i], copy); | ||
| 1284 | cmd_pos += copy; | ||
| 1285 | copy_size += copy; | ||
| 1286 | } | ||
| 1253 | } | 1287 | } |
| 1254 | 1288 | ||
| 1255 | WARN_ON_ONCE(txq->entries[idx].copy_cmd); | 1289 | WARN_ON_ONCE(txq->entries[idx].copy_cmd); |
| @@ -1275,7 +1309,14 @@ static int iwl_pcie_enqueue_hcmd(struct iwl_trans *trans, | |||
| 1275 | out_cmd->hdr.cmd, le16_to_cpu(out_cmd->hdr.sequence), | 1309 | out_cmd->hdr.cmd, le16_to_cpu(out_cmd->hdr.sequence), |
| 1276 | cmd_size, q->write_ptr, idx, trans_pcie->cmd_queue); | 1310 | cmd_size, q->write_ptr, idx, trans_pcie->cmd_queue); |
| 1277 | 1311 | ||
| 1278 | phys_addr = dma_map_single(trans->dev, &out_cmd->hdr, copy_size, | 1312 | /* |
| 1313 | * If the entire command is smaller than IWL_HCMD_MIN_COPY_SIZE, we must | ||
| 1314 | * still map at least that many bytes for the hardware to write back to. | ||
| 1315 | * We have enough space, so that's not a problem. | ||
| 1316 | */ | ||
| 1317 | dma_size = max_t(u16, copy_size, IWL_HCMD_MIN_COPY_SIZE); | ||
| 1318 | |||
| 1319 | phys_addr = dma_map_single(trans->dev, &out_cmd->hdr, dma_size, | ||
| 1279 | DMA_BIDIRECTIONAL); | 1320 | DMA_BIDIRECTIONAL); |
| 1280 | if (unlikely(dma_mapping_error(trans->dev, phys_addr))) { | 1321 | if (unlikely(dma_mapping_error(trans->dev, phys_addr))) { |
| 1281 | idx = -ENOMEM; | 1322 | idx = -ENOMEM; |
| @@ -1283,14 +1324,15 @@ static int iwl_pcie_enqueue_hcmd(struct iwl_trans *trans, | |||
| 1283 | } | 1324 | } |
| 1284 | 1325 | ||
| 1285 | dma_unmap_addr_set(out_meta, mapping, phys_addr); | 1326 | dma_unmap_addr_set(out_meta, mapping, phys_addr); |
| 1286 | dma_unmap_len_set(out_meta, len, copy_size); | 1327 | dma_unmap_len_set(out_meta, len, dma_size); |
| 1287 | 1328 | ||
| 1288 | iwl_pcie_txq_build_tfd(trans, txq, phys_addr, copy_size, 1); | 1329 | iwl_pcie_txq_build_tfd(trans, txq, phys_addr, copy_size, 1); |
| 1289 | 1330 | ||
| 1331 | /* map the remaining (adjusted) nocopy/dup fragments */ | ||
| 1290 | for (i = 0; i < IWL_MAX_CMD_TFDS; i++) { | 1332 | for (i = 0; i < IWL_MAX_CMD_TFDS; i++) { |
| 1291 | const void *data = cmd->data[i]; | 1333 | const void *data = cmddata[i]; |
| 1292 | 1334 | ||
| 1293 | if (!cmd->len[i]) | 1335 | if (!cmdlen[i]) |
| 1294 | continue; | 1336 | continue; |
| 1295 | if (!(cmd->dataflags[i] & (IWL_HCMD_DFL_NOCOPY | | 1337 | if (!(cmd->dataflags[i] & (IWL_HCMD_DFL_NOCOPY | |
| 1296 | IWL_HCMD_DFL_DUP))) | 1338 | IWL_HCMD_DFL_DUP))) |
| @@ -1298,7 +1340,7 @@ static int iwl_pcie_enqueue_hcmd(struct iwl_trans *trans, | |||
| 1298 | if (cmd->dataflags[i] & IWL_HCMD_DFL_DUP) | 1340 | if (cmd->dataflags[i] & IWL_HCMD_DFL_DUP) |
| 1299 | data = dup_buf; | 1341 | data = dup_buf; |
| 1300 | phys_addr = dma_map_single(trans->dev, (void *)data, | 1342 | phys_addr = dma_map_single(trans->dev, (void *)data, |
| 1301 | cmd->len[i], DMA_BIDIRECTIONAL); | 1343 | cmdlen[i], DMA_BIDIRECTIONAL); |
| 1302 | if (dma_mapping_error(trans->dev, phys_addr)) { | 1344 | if (dma_mapping_error(trans->dev, phys_addr)) { |
| 1303 | iwl_pcie_tfd_unmap(trans, out_meta, | 1345 | iwl_pcie_tfd_unmap(trans, out_meta, |
| 1304 | &txq->tfds[q->write_ptr], | 1346 | &txq->tfds[q->write_ptr], |
| @@ -1307,7 +1349,7 @@ static int iwl_pcie_enqueue_hcmd(struct iwl_trans *trans, | |||
| 1307 | goto out; | 1349 | goto out; |
| 1308 | } | 1350 | } |
| 1309 | 1351 | ||
| 1310 | iwl_pcie_txq_build_tfd(trans, txq, phys_addr, cmd->len[i], 0); | 1352 | iwl_pcie_txq_build_tfd(trans, txq, phys_addr, cmdlen[i], 0); |
| 1311 | } | 1353 | } |
| 1312 | 1354 | ||
| 1313 | out_meta->flags = cmd->flags; | 1355 | out_meta->flags = cmd->flags; |
| @@ -1317,8 +1359,7 @@ static int iwl_pcie_enqueue_hcmd(struct iwl_trans *trans, | |||
| 1317 | 1359 | ||
| 1318 | txq->need_update = 1; | 1360 | txq->need_update = 1; |
| 1319 | 1361 | ||
| 1320 | trace_iwlwifi_dev_hcmd(trans->dev, cmd, cmd_size, | 1362 | trace_iwlwifi_dev_hcmd(trans->dev, cmd, cmd_size, &out_cmd->hdr); |
| 1321 | &out_cmd->hdr, copy_size); | ||
| 1322 | 1363 | ||
| 1323 | /* start timer if queue currently empty */ | 1364 | /* start timer if queue currently empty */ |
| 1324 | if (q->read_ptr == q->write_ptr && trans_pcie->wd_timeout) | 1365 | if (q->read_ptr == q->write_ptr && trans_pcie->wd_timeout) |
