From c1cb92fc1ecd2159b7fb148ed8d5f09d511ae030 Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Tue, 28 Jan 2014 10:17:18 +0200 Subject: iwlwifi: mvm: remove support for legacy power API If the driver detects old firmware, we disable support for power management. This greatly simplifies the code. Reviewed-by: Alexander Bondar Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/d3.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless/iwlwifi/mvm/d3.c') diff --git a/drivers/net/wireless/iwlwifi/mvm/d3.c b/drivers/net/wireless/iwlwifi/mvm/d3.c index f36a7ee0267f..a9850aa909d8 100644 --- a/drivers/net/wireless/iwlwifi/mvm/d3.c +++ b/drivers/net/wireless/iwlwifi/mvm/d3.c @@ -1191,11 +1191,11 @@ static int __iwl_mvm_suspend(struct ieee80211_hw *hw, if (ret) goto out; - ret = iwl_mvm_power_update_device_mode(mvm); + ret = iwl_mvm_power_update_device(mvm); if (ret) goto out; - ret = iwl_mvm_power_update_mode(mvm, vif); + ret = iwl_mvm_power_mac_update_mode(mvm, vif); if (ret) goto out; -- cgit v1.2.3 From e5e7aa8e2561019fb3f417041d50e1c0df8f5e42 Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Mon, 27 Jan 2014 16:57:33 +0200 Subject: iwlwifi: mvm: refactor power code The main complexity of the power code is that it needs to take into account the firmware limitations. These limitations state that we need to have a global picture of the vifs present in the system to be able to decide if we can enable power management on a specific vif. Even device power save (as opposed to vif power management) must be disabled in certain circumstances (monitor vif). Refactor the current code to make this clearer by defining a function that explicitely computes these constraints. Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/d3.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/wireless/iwlwifi/mvm/d3.c') diff --git a/drivers/net/wireless/iwlwifi/mvm/d3.c b/drivers/net/wireless/iwlwifi/mvm/d3.c index a9850aa909d8..e3a9cec45566 100644 --- a/drivers/net/wireless/iwlwifi/mvm/d3.c +++ b/drivers/net/wireless/iwlwifi/mvm/d3.c @@ -1195,7 +1195,7 @@ static int __iwl_mvm_suspend(struct ieee80211_hw *hw, if (ret) goto out; - ret = iwl_mvm_power_mac_update_mode(mvm, vif); + ret = iwl_mvm_power_update_mac(mvm, vif); if (ret) goto out; -- cgit v1.2.3 From b92e661b401897928040d89b3a9d0cd74ce6e9a1 Mon Sep 17 00:00:00 2001 From: Eliad Peller Date: Thu, 23 Jan 2014 17:58:23 +0200 Subject: iwlwifi: mvm: reserve sta_id 0 to station The d3/d0i3 fw code requires the sta_id to be 0 (this is used to determine the rates and keys to use in arp offloading). Reserve sta_id 0 to station interface in order to comply with this requirement. Change some functions prototypes in order to make the allocation function know about the interface type. Signed-off-by: Eliad Peller Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/d3.c | 27 --------------------------- 1 file changed, 27 deletions(-) (limited to 'drivers/net/wireless/iwlwifi/mvm/d3.c') diff --git a/drivers/net/wireless/iwlwifi/mvm/d3.c b/drivers/net/wireless/iwlwifi/mvm/d3.c index e3a9cec45566..b956e2f0b631 100644 --- a/drivers/net/wireless/iwlwifi/mvm/d3.c +++ b/drivers/net/wireless/iwlwifi/mvm/d3.c @@ -963,7 +963,6 @@ static int __iwl_mvm_suspend(struct ieee80211_hw *hw, }; int ret, i; int len __maybe_unused; - u8 old_aux_sta_id, old_ap_sta_id = IWL_MVM_STATION_COUNT; if (!wowlan) { /* @@ -980,8 +979,6 @@ static int __iwl_mvm_suspend(struct ieee80211_hw *hw, mutex_lock(&mvm->mutex); - old_aux_sta_id = mvm->aux_sta.sta_id; - /* see if there's only a single BSS vif and it's associated */ ieee80211_iterate_active_interfaces_atomic( mvm->hw, IEEE80211_IFACE_ITER_NORMAL, @@ -1066,16 +1063,6 @@ static int __iwl_mvm_suspend(struct ieee80211_hw *hw, iwl_trans_stop_device(mvm->trans); - /* - * The D3 firmware still hardcodes the AP station ID for the - * BSS we're associated with as 0. Store the real STA ID here - * and assign 0. When we leave this function, we'll restore - * the original value for the resume code. - */ - old_ap_sta_id = mvm_ap_sta->sta_id; - mvm_ap_sta->sta_id = 0; - mvmvif->ap_sta_id = 0; - /* * Set the HW restart bit -- this is mostly true as we're * going to load new firmware and reprogram that, though @@ -1096,16 +1083,6 @@ static int __iwl_mvm_suspend(struct ieee80211_hw *hw, mvm->ptk_ivlen = 0; mvm->ptk_icvlen = 0; - /* - * The D3 firmware still hardcodes the AP station ID for the - * BSS we're associated with as 0. As a result, we have to move - * the auxiliary station to ID 1 so the ID 0 remains free for - * the AP station for later. - * We set the sta_id to 1 here, and reset it to its previous - * value (that we stored above) later. - */ - mvm->aux_sta.sta_id = 1; - ret = iwl_mvm_load_d3_fw(mvm); if (ret) goto out; @@ -1222,10 +1199,6 @@ static int __iwl_mvm_suspend(struct ieee80211_hw *hw, iwl_trans_d3_suspend(mvm->trans, test); out: - mvm->aux_sta.sta_id = old_aux_sta_id; - mvm_ap_sta->sta_id = old_ap_sta_id; - mvmvif->ap_sta_id = old_ap_sta_id; - if (ret < 0) ieee80211_restart_hw(mvm->hw); out_noreset: -- cgit v1.2.3 From 9a3daf820166d835ef9f83019184abb3f2a15826 Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Wed, 5 Mar 2014 10:00:44 +0200 Subject: iwlwifi: mvm: fix quota for D3 image New firmware enforce valid values for the quota in D3. The values given to the firmware when suspending and using WoWLAN where dummy - change them to realistics values. Tested-by: Luciano Coelho Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/d3.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless/iwlwifi/mvm/d3.c') diff --git a/drivers/net/wireless/iwlwifi/mvm/d3.c b/drivers/net/wireless/iwlwifi/mvm/d3.c index b956e2f0b631..a08756456e10 100644 --- a/drivers/net/wireless/iwlwifi/mvm/d3.c +++ b/drivers/net/wireless/iwlwifi/mvm/d3.c @@ -846,8 +846,8 @@ static int iwl_mvm_d3_reprogram(struct iwl_mvm *mvm, struct ieee80211_vif *vif, quota_cmd.quotas[0].id_and_color = cpu_to_le32(FW_CMD_ID_AND_COLOR(mvmvif->phy_ctxt->id, mvmvif->phy_ctxt->color)); - quota_cmd.quotas[0].quota = cpu_to_le32(100); - quota_cmd.quotas[0].max_duration = cpu_to_le32(1000); + quota_cmd.quotas[0].quota = cpu_to_le32(IWL_MVM_MAX_QUOTA); + quota_cmd.quotas[0].max_duration = cpu_to_le32(IWL_MVM_MAX_QUOTA); for (i = 1; i < MAX_BINDINGS; i++) quota_cmd.quotas[i].id_and_color = cpu_to_le32(FW_CTXT_INVALID); -- cgit v1.2.3 From 1a95c8df7ed1ddf5e1d732a594f5a1b09da9a8c5 Mon Sep 17 00:00:00 2001 From: Eliad Peller Date: Thu, 21 Nov 2013 19:19:52 +0200 Subject: iwlwifi: mvm: configure seq_num to D0i3 Configure the QoS counters when entering D0i3. The fw might use them later when performing protocol offloading (we'll update the the counters back on d0i3 exit in a following patch). Non-QoS counter is handled internally in the fw, so no need to configure it. Also, add support for a new version of WOWLAN_CONFIG_CMD Signed-off-by: Eliad Peller Reviewed-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/d3.c | 189 ++++++---------------------------- 1 file changed, 30 insertions(+), 159 deletions(-) (limited to 'drivers/net/wireless/iwlwifi/mvm/d3.c') diff --git a/drivers/net/wireless/iwlwifi/mvm/d3.c b/drivers/net/wireless/iwlwifi/mvm/d3.c index a08756456e10..02fb950c031c 100644 --- a/drivers/net/wireless/iwlwifi/mvm/d3.c +++ b/drivers/net/wireless/iwlwifi/mvm/d3.c @@ -376,139 +376,6 @@ static int iwl_mvm_send_patterns(struct iwl_mvm *mvm, return err; } -static int iwl_mvm_send_proto_offload(struct iwl_mvm *mvm, - struct ieee80211_vif *vif) -{ - union { - struct iwl_proto_offload_cmd_v1 v1; - struct iwl_proto_offload_cmd_v2 v2; - struct iwl_proto_offload_cmd_v3_small v3s; - struct iwl_proto_offload_cmd_v3_large v3l; - } cmd = {}; - struct iwl_host_cmd hcmd = { - .id = PROT_OFFLOAD_CONFIG_CMD, - .flags = CMD_SYNC, - .data[0] = &cmd, - .dataflags[0] = IWL_HCMD_DFL_DUP, - }; - struct iwl_proto_offload_cmd_common *common; - u32 enabled = 0, size; - u32 capa_flags = mvm->fw->ucode_capa.flags; -#if IS_ENABLED(CONFIG_IPV6) - struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); - int i; - - if (capa_flags & IWL_UCODE_TLV_FLAGS_NEW_NSOFFL_SMALL || - capa_flags & IWL_UCODE_TLV_FLAGS_NEW_NSOFFL_LARGE) { - struct iwl_ns_config *nsc; - struct iwl_targ_addr *addrs; - int n_nsc, n_addrs; - int c; - - if (capa_flags & IWL_UCODE_TLV_FLAGS_NEW_NSOFFL_SMALL) { - nsc = cmd.v3s.ns_config; - n_nsc = IWL_PROTO_OFFLOAD_NUM_NS_CONFIG_V3S; - addrs = cmd.v3s.targ_addrs; - n_addrs = IWL_PROTO_OFFLOAD_NUM_IPV6_ADDRS_V3S; - } else { - nsc = cmd.v3l.ns_config; - n_nsc = IWL_PROTO_OFFLOAD_NUM_NS_CONFIG_V3L; - addrs = cmd.v3l.targ_addrs; - n_addrs = IWL_PROTO_OFFLOAD_NUM_IPV6_ADDRS_V3L; - } - - if (mvmvif->num_target_ipv6_addrs) - enabled |= IWL_D3_PROTO_OFFLOAD_NS; - - /* - * For each address we have (and that will fit) fill a target - * address struct and combine for NS offload structs with the - * solicited node addresses. - */ - for (i = 0, c = 0; - i < mvmvif->num_target_ipv6_addrs && - i < n_addrs && c < n_nsc; i++) { - struct in6_addr solicited_addr; - int j; - - addrconf_addr_solict_mult(&mvmvif->target_ipv6_addrs[i], - &solicited_addr); - for (j = 0; j < c; j++) - if (ipv6_addr_cmp(&nsc[j].dest_ipv6_addr, - &solicited_addr) == 0) - break; - if (j == c) - c++; - addrs[i].addr = mvmvif->target_ipv6_addrs[i]; - addrs[i].config_num = cpu_to_le32(j); - nsc[j].dest_ipv6_addr = solicited_addr; - memcpy(nsc[j].target_mac_addr, vif->addr, ETH_ALEN); - } - - if (capa_flags & IWL_UCODE_TLV_FLAGS_NEW_NSOFFL_SMALL) - cmd.v3s.num_valid_ipv6_addrs = cpu_to_le32(i); - else - cmd.v3l.num_valid_ipv6_addrs = cpu_to_le32(i); - } else if (capa_flags & IWL_UCODE_TLV_FLAGS_D3_6_IPV6_ADDRS) { - if (mvmvif->num_target_ipv6_addrs) { - enabled |= IWL_D3_PROTO_OFFLOAD_NS; - memcpy(cmd.v2.ndp_mac_addr, vif->addr, ETH_ALEN); - } - - BUILD_BUG_ON(sizeof(cmd.v2.target_ipv6_addr[0]) != - sizeof(mvmvif->target_ipv6_addrs[0])); - - for (i = 0; i < min(mvmvif->num_target_ipv6_addrs, - IWL_PROTO_OFFLOAD_NUM_IPV6_ADDRS_V2); i++) - memcpy(cmd.v2.target_ipv6_addr[i], - &mvmvif->target_ipv6_addrs[i], - sizeof(cmd.v2.target_ipv6_addr[i])); - } else { - if (mvmvif->num_target_ipv6_addrs) { - enabled |= IWL_D3_PROTO_OFFLOAD_NS; - memcpy(cmd.v1.ndp_mac_addr, vif->addr, ETH_ALEN); - } - - BUILD_BUG_ON(sizeof(cmd.v1.target_ipv6_addr[0]) != - sizeof(mvmvif->target_ipv6_addrs[0])); - - for (i = 0; i < min(mvmvif->num_target_ipv6_addrs, - IWL_PROTO_OFFLOAD_NUM_IPV6_ADDRS_V1); i++) - memcpy(cmd.v1.target_ipv6_addr[i], - &mvmvif->target_ipv6_addrs[i], - sizeof(cmd.v1.target_ipv6_addr[i])); - } -#endif - - if (capa_flags & IWL_UCODE_TLV_FLAGS_NEW_NSOFFL_SMALL) { - common = &cmd.v3s.common; - size = sizeof(cmd.v3s); - } else if (capa_flags & IWL_UCODE_TLV_FLAGS_NEW_NSOFFL_LARGE) { - common = &cmd.v3l.common; - size = sizeof(cmd.v3l); - } else if (capa_flags & IWL_UCODE_TLV_FLAGS_D3_6_IPV6_ADDRS) { - common = &cmd.v2.common; - size = sizeof(cmd.v2); - } else { - common = &cmd.v1.common; - size = sizeof(cmd.v1); - } - - if (vif->bss_conf.arp_addr_cnt) { - enabled |= IWL_D3_PROTO_OFFLOAD_ARP; - common->host_ipv4_addr = vif->bss_conf.arp_addr_list[0]; - memcpy(common->arp_mac_addr, vif->addr, ETH_ALEN); - } - - if (!enabled) - return 0; - - common->enabled = cpu_to_le32(enabled); - - hcmd.len[0] = size; - return iwl_mvm_send_cmd(mvm, &hcmd); -} - enum iwl_mvm_tcp_packet_type { MVM_TCP_TX_SYN, MVM_TCP_RX_SYNACK, @@ -927,6 +794,20 @@ void iwl_mvm_set_last_nonqos_seq(struct iwl_mvm *mvm, struct ieee80211_vif *vif) IWL_ERR(mvm, "failed to set non-QoS seqno\n"); } +static int +iwl_mvm_send_wowlan_config_cmd(struct iwl_mvm *mvm, + const struct iwl_wowlan_config_cmd_v3 *cmd) +{ + /* start only with the v2 part of the command */ + u16 cmd_len = sizeof(cmd->common); + + if (mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_WOWLAN_CONFIG_TID) + cmd_len = sizeof(*cmd); + + return iwl_mvm_send_cmd_pdu(mvm, WOWLAN_CONFIGURATION, CMD_SYNC, + cmd_len, cmd); +} + static int __iwl_mvm_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan, bool test) @@ -939,7 +820,7 @@ static int __iwl_mvm_suspend(struct ieee80211_hw *hw, struct iwl_mvm_vif *mvmvif; struct ieee80211_sta *ap_sta; struct iwl_mvm_sta *mvm_ap_sta; - struct iwl_wowlan_config_cmd wowlan_config_cmd = {}; + struct iwl_wowlan_config_cmd_v3 wowlan_config_cmd = {}; struct iwl_wowlan_kek_kck_material_cmd kek_kck_cmd = {}; struct iwl_wowlan_tkip_params_cmd tkip_cmd = {}; struct iwl_d3_manager_config d3_cfg_cmd_data = { @@ -961,7 +842,7 @@ static int __iwl_mvm_suspend(struct ieee80211_hw *hw, .tkip = &tkip_cmd, .use_tkip = false, }; - int ret, i; + int ret; int len __maybe_unused; if (!wowlan) { @@ -1002,49 +883,41 @@ static int __iwl_mvm_suspend(struct ieee80211_hw *hw, mvm_ap_sta = (struct iwl_mvm_sta *)ap_sta->drv_priv; - /* TODO: wowlan_config_cmd.wowlan_ba_teardown_tids */ + /* TODO: wowlan_config_cmd.common.wowlan_ba_teardown_tids */ - wowlan_config_cmd.is_11n_connection = ap_sta->ht_cap.ht_supported; + wowlan_config_cmd.common.is_11n_connection = + ap_sta->ht_cap.ht_supported; /* Query the last used seqno and set it */ ret = iwl_mvm_get_last_nonqos_seq(mvm, vif); if (ret < 0) goto out_noreset; - wowlan_config_cmd.non_qos_seq = cpu_to_le16(ret); + wowlan_config_cmd.common.non_qos_seq = cpu_to_le16(ret); - /* - * For QoS counters, we store the one to use next, so subtract 0x10 - * since the uCode will add 0x10 *before* using the value while we - * increment after using the value (i.e. store the next value to use). - */ - for (i = 0; i < IWL_MAX_TID_COUNT; i++) { - u16 seq = mvm_ap_sta->tid_data[i].seq_number; - seq -= 0x10; - wowlan_config_cmd.qos_seq[i] = cpu_to_le16(seq); - } + iwl_mvm_set_wowlan_qos_seq(mvm_ap_sta, &wowlan_config_cmd.common); if (wowlan->disconnect) - wowlan_config_cmd.wakeup_filter |= + wowlan_config_cmd.common.wakeup_filter |= cpu_to_le32(IWL_WOWLAN_WAKEUP_BEACON_MISS | IWL_WOWLAN_WAKEUP_LINK_CHANGE); if (wowlan->magic_pkt) - wowlan_config_cmd.wakeup_filter |= + wowlan_config_cmd.common.wakeup_filter |= cpu_to_le32(IWL_WOWLAN_WAKEUP_MAGIC_PACKET); if (wowlan->gtk_rekey_failure) - wowlan_config_cmd.wakeup_filter |= + wowlan_config_cmd.common.wakeup_filter |= cpu_to_le32(IWL_WOWLAN_WAKEUP_GTK_REKEY_FAIL); if (wowlan->eap_identity_req) - wowlan_config_cmd.wakeup_filter |= + wowlan_config_cmd.common.wakeup_filter |= cpu_to_le32(IWL_WOWLAN_WAKEUP_EAP_IDENT_REQ); if (wowlan->four_way_handshake) - wowlan_config_cmd.wakeup_filter |= + wowlan_config_cmd.common.wakeup_filter |= cpu_to_le32(IWL_WOWLAN_WAKEUP_4WAY_HANDSHAKE); if (wowlan->n_patterns) - wowlan_config_cmd.wakeup_filter |= + wowlan_config_cmd.common.wakeup_filter |= cpu_to_le32(IWL_WOWLAN_WAKEUP_PATTERN_MATCH); if (wowlan->rfkill_release) - wowlan_config_cmd.wakeup_filter |= + wowlan_config_cmd.common.wakeup_filter |= cpu_to_le32(IWL_WOWLAN_WAKEUP_RF_KILL_DEASSERT); if (wowlan->tcp) { @@ -1052,7 +925,7 @@ static int __iwl_mvm_suspend(struct ieee80211_hw *hw, * Set the "link change" (really "link lost") flag as well * since that implies losing the TCP connection. */ - wowlan_config_cmd.wakeup_filter |= + wowlan_config_cmd.common.wakeup_filter |= cpu_to_le32(IWL_WOWLAN_WAKEUP_REMOTE_LINK_LOSS | IWL_WOWLAN_WAKEUP_REMOTE_SIGNATURE_TABLE | IWL_WOWLAN_WAKEUP_REMOTE_WAKEUP_PACKET | @@ -1150,9 +1023,7 @@ static int __iwl_mvm_suspend(struct ieee80211_hw *hw, } } - ret = iwl_mvm_send_cmd_pdu(mvm, WOWLAN_CONFIGURATION, - CMD_SYNC, sizeof(wowlan_config_cmd), - &wowlan_config_cmd); + ret = iwl_mvm_send_wowlan_config_cmd(mvm, &wowlan_config_cmd); if (ret) goto out; -- cgit v1.2.3 From 8bd22e7bb0b02c24b3c9997670bbb65e0e0a7371 Mon Sep 17 00:00:00 2001 From: Eliad Peller Date: Sun, 3 Nov 2013 19:48:50 +0200 Subject: iwlwifi: mvm: configure protocol offloading on D0i3 Enable protocol offloading (arp and NS) on D0i3. The offloading allows the fw answer NS and arp requests without waking up the host. Since protocol offloading is saved between D0i3 entries, we have to explicitly disable it in case we don't want it. Signed-off-by: Eliad Peller Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/d3.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/wireless/iwlwifi/mvm/d3.c') diff --git a/drivers/net/wireless/iwlwifi/mvm/d3.c b/drivers/net/wireless/iwlwifi/mvm/d3.c index 02fb950c031c..e56f5a0edf85 100644 --- a/drivers/net/wireless/iwlwifi/mvm/d3.c +++ b/drivers/net/wireless/iwlwifi/mvm/d3.c @@ -1031,7 +1031,7 @@ static int __iwl_mvm_suspend(struct ieee80211_hw *hw, if (ret) goto out; - ret = iwl_mvm_send_proto_offload(mvm, vif); + ret = iwl_mvm_send_proto_offload(mvm, vif, false, CMD_SYNC); if (ret) goto out; -- cgit v1.2.3