aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless
diff options
context:
space:
mode:
authorEliad Peller <eliad@wizery.com>2015-11-11 10:23:59 -0500
committerEmmanuel Grumbach <emmanuel.grumbach@intel.com>2015-12-20 16:27:43 -0500
commita3f7ba5c8825879cc76110bc8dcadf92a6d5fa8e (patch)
tree258c7100deaba4702c3b85b0477d794890c0aefd /drivers/net/wireless
parent8be30c13ebafdf743ab638a83095715a01bc1071 (diff)
iwlwifi: update key params on d0i3 entrance/exit
In order to let the fw do offloading properly, we need to provide various key data (e.g. PN). Configure the params on d0i3 entrance, and update them back on d0i3 exit. Since d3 code is now called in d0i3 which requires runtime pm only, make d3.0 depend on CONFIG_PM (rather than CONFIG_PM_SLEEP), and add required #ifdefs and wrappers where needed, so both CONFIG_PM=n and CONFIG_PM_RUNTIME=n configurations will build correctly. Signed-off-by: Eliad Peller <eliadx.peller@intel.com> Signed-off-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
Diffstat (limited to 'drivers/net/wireless')
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/Makefile2
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/d3.c84
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/mvm.h31
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/ops.c64
4 files changed, 136 insertions, 45 deletions
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/Makefile b/drivers/net/wireless/intel/iwlwifi/mvm/Makefile
index 80c2f88386a5..23e7e2937566 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/Makefile
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/Makefile
@@ -7,6 +7,6 @@ iwlmvm-y += tt.o offloading.o tdls.o
7iwlmvm-$(CONFIG_IWLWIFI_DEBUGFS) += debugfs.o debugfs-vif.o 7iwlmvm-$(CONFIG_IWLWIFI_DEBUGFS) += debugfs.o debugfs-vif.o
8iwlmvm-$(CONFIG_IWLWIFI_LEDS) += led.o 8iwlmvm-$(CONFIG_IWLWIFI_LEDS) += led.o
9iwlmvm-y += tof.o fw-dbg.o 9iwlmvm-y += tof.o fw-dbg.o
10iwlmvm-$(CONFIG_PM_SLEEP) += d3.o 10iwlmvm-$(CONFIG_PM) += d3.o
11 11
12ccflags-y += -D__CHECK_ENDIAN__ -I$(src)/../ 12ccflags-y += -D__CHECK_ENDIAN__ -I$(src)/../
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c
index 3e6b6d626c25..6ac40727541e 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c
@@ -855,15 +855,38 @@ iwl_mvm_get_wowlan_config(struct iwl_mvm *mvm,
855 return 0; 855 return 0;
856} 856}
857 857
858static void
859iwl_mvm_iter_d0i3_ap_keys(struct iwl_mvm *mvm,
860 struct ieee80211_vif *vif,
861 void (*iter)(struct ieee80211_hw *hw,
862 struct ieee80211_vif *vif,
863 struct ieee80211_sta *sta,
864 struct ieee80211_key_conf *key,
865 void *data),
866 void *data)
867{
868 struct ieee80211_sta *ap_sta;
869
870 rcu_read_lock();
871
872 ap_sta = rcu_dereference(mvm->fw_id_to_mac_id[mvm->d0i3_ap_sta_id]);
873 if (IS_ERR_OR_NULL(ap_sta))
874 goto out;
875
876 ieee80211_iter_keys_rcu(mvm->hw, vif, iter, data);
877out:
878 rcu_read_unlock();
879}
880
858int iwl_mvm_wowlan_config_key_params(struct iwl_mvm *mvm, 881int iwl_mvm_wowlan_config_key_params(struct iwl_mvm *mvm,
859 struct ieee80211_vif *vif, 882 struct ieee80211_vif *vif,
860 bool configure_keys, 883 bool d0i3,
861 u32 cmd_flags) 884 u32 cmd_flags)
862{ 885{
863 struct iwl_wowlan_kek_kck_material_cmd kek_kck_cmd = {}; 886 struct iwl_wowlan_kek_kck_material_cmd kek_kck_cmd = {};
864 struct iwl_wowlan_tkip_params_cmd tkip_cmd = {}; 887 struct iwl_wowlan_tkip_params_cmd tkip_cmd = {};
865 struct wowlan_key_data key_data = { 888 struct wowlan_key_data key_data = {
866 .configure_keys = configure_keys, 889 .configure_keys = !d0i3,
867 .use_rsc_tsc = false, 890 .use_rsc_tsc = false,
868 .tkip = &tkip_cmd, 891 .tkip = &tkip_cmd,
869 .use_tkip = false, 892 .use_tkip = false,
@@ -876,15 +899,28 @@ int iwl_mvm_wowlan_config_key_params(struct iwl_mvm *mvm,
876 return -ENOMEM; 899 return -ENOMEM;
877 900
878 /* 901 /*
879 * Note that currently we don't propagate cmd_flags 902 * if we have to configure keys, call ieee80211_iter_keys(),
880 * to the iterator. In case of key_data.configure_keys, 903 * as we need non-atomic context in order to take the
881 * all the configured commands are SYNC, and 904 * required locks.
882 * iwl_mvm_wowlan_program_keys() will take care of 905 * for the d0i3 we can't use ieee80211_iter_keys(), as
883 * locking/unlocking mvm->mutex. 906 * taking (almost) any mutex might result in deadlock.
884 */ 907 */
885 ieee80211_iter_keys(mvm->hw, vif, 908 if (!d0i3) {
886 iwl_mvm_wowlan_program_keys, 909 /*
887 &key_data); 910 * Note that currently we don't propagate cmd_flags
911 * to the iterator. In case of key_data.configure_keys,
912 * all the configured commands are SYNC, and
913 * iwl_mvm_wowlan_program_keys() will take care of
914 * locking/unlocking mvm->mutex.
915 */
916 ieee80211_iter_keys(mvm->hw, vif,
917 iwl_mvm_wowlan_program_keys,
918 &key_data);
919 } else {
920 iwl_mvm_iter_d0i3_ap_keys(mvm, vif,
921 iwl_mvm_wowlan_program_keys,
922 &key_data);
923 }
888 924
889 if (key_data.error) { 925 if (key_data.error) {
890 ret = -EIO; 926 ret = -EIO;
@@ -909,7 +945,8 @@ int iwl_mvm_wowlan_config_key_params(struct iwl_mvm *mvm,
909 goto out; 945 goto out;
910 } 946 }
911 947
912 if (mvmvif->rekey_data.valid) { 948 /* configure rekey data only if offloaded rekey is supported (d3) */
949 if (mvmvif->rekey_data.valid && !d0i3) {
913 memset(&kek_kck_cmd, 0, sizeof(kek_kck_cmd)); 950 memset(&kek_kck_cmd, 0, sizeof(kek_kck_cmd));
914 memcpy(kek_kck_cmd.kck, mvmvif->rekey_data.kck, 951 memcpy(kek_kck_cmd.kck, mvmvif->rekey_data.kck,
915 NL80211_KCK_LEN); 952 NL80211_KCK_LEN);
@@ -956,7 +993,7 @@ iwl_mvm_wowlan_config(struct iwl_mvm *mvm,
956 * that isn't really a problem though. 993 * that isn't really a problem though.
957 */ 994 */
958 mutex_unlock(&mvm->mutex); 995 mutex_unlock(&mvm->mutex);
959 ret = iwl_mvm_wowlan_config_key_params(mvm, vif, true, 996 ret = iwl_mvm_wowlan_config_key_params(mvm, vif, false,
960 CMD_ASYNC); 997 CMD_ASYNC);
961 mutex_lock(&mvm->mutex); 998 mutex_lock(&mvm->mutex);
962 if (ret) 999 if (ret)
@@ -1727,6 +1764,29 @@ out_unlock:
1727 return false; 1764 return false;
1728} 1765}
1729 1766
1767void iwl_mvm_d0i3_update_keys(struct iwl_mvm *mvm,
1768 struct ieee80211_vif *vif,
1769 struct iwl_wowlan_status *status)
1770{
1771 struct iwl_mvm_d3_gtk_iter_data gtkdata = {
1772 .status = status,
1773 };
1774
1775 /*
1776 * rekey handling requires taking locks that can't be taken now.
1777 * however, d0i3 doesn't offload rekey, so we're fine.
1778 */
1779 if (WARN_ON_ONCE(status->num_of_gtk_rekeys))
1780 return;
1781
1782 /* find last GTK that we used initially, if any */
1783 gtkdata.find_phase = true;
1784 iwl_mvm_iter_d0i3_ap_keys(mvm, vif, iwl_mvm_d3_update_keys, &gtkdata);
1785
1786 gtkdata.find_phase = false;
1787 iwl_mvm_iter_d0i3_ap_keys(mvm, vif, iwl_mvm_d3_update_keys, &gtkdata);
1788}
1789
1730struct iwl_mvm_nd_query_results { 1790struct iwl_mvm_nd_query_results {
1731 u32 matched_profiles; 1791 u32 matched_profiles;
1732 struct iwl_scan_offload_profile_match matches[IWL_SCAN_MAX_PROFILES]; 1792 struct iwl_scan_offload_profile_match matches[IWL_SCAN_MAX_PROFILES];
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h
index 86409c5964cc..287c16250570 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h
@@ -405,7 +405,7 @@ struct iwl_mvm_vif {
405 */ 405 */
406 struct iwl_mvm_phy_ctxt *phy_ctxt; 406 struct iwl_mvm_phy_ctxt *phy_ctxt;
407 407
408#ifdef CONFIG_PM_SLEEP 408#ifdef CONFIG_PM
409 /* WoWLAN GTK rekey data */ 409 /* WoWLAN GTK rekey data */
410 struct { 410 struct {
411 u8 kck[NL80211_KCK_LEN], kek[NL80211_KEK_LEN]; 411 u8 kck[NL80211_KCK_LEN], kek[NL80211_KEK_LEN];
@@ -738,7 +738,7 @@ struct iwl_mvm {
738 738
739 struct ieee80211_vif *p2p_device_vif; 739 struct ieee80211_vif *p2p_device_vif;
740 740
741#ifdef CONFIG_PM_SLEEP 741#ifdef CONFIG_PM
742 struct wiphy_wowlan_support wowlan; 742 struct wiphy_wowlan_support wowlan;
743 int gtk_ivlen, gtk_icvlen, ptk_ivlen, ptk_icvlen; 743 int gtk_ivlen, gtk_icvlen, ptk_ivlen, ptk_icvlen;
744 744
@@ -1278,10 +1278,6 @@ static inline void iwl_mvm_leds_exit(struct iwl_mvm *mvm)
1278/* D3 (WoWLAN, NetDetect) */ 1278/* D3 (WoWLAN, NetDetect) */
1279int iwl_mvm_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan); 1279int iwl_mvm_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan);
1280int iwl_mvm_resume(struct ieee80211_hw *hw); 1280int iwl_mvm_resume(struct ieee80211_hw *hw);
1281int iwl_mvm_wowlan_config_key_params(struct iwl_mvm *mvm,
1282 struct ieee80211_vif *vif,
1283 bool configure_keys,
1284 u32 cmd_flags);
1285void iwl_mvm_set_wakeup(struct ieee80211_hw *hw, bool enabled); 1281void iwl_mvm_set_wakeup(struct ieee80211_hw *hw, bool enabled);
1286void iwl_mvm_set_rekey_data(struct ieee80211_hw *hw, 1282void iwl_mvm_set_rekey_data(struct ieee80211_hw *hw,
1287 struct ieee80211_vif *vif, 1283 struct ieee80211_vif *vif,
@@ -1292,10 +1288,31 @@ void iwl_mvm_ipv6_addr_change(struct ieee80211_hw *hw,
1292void iwl_mvm_set_default_unicast_key(struct ieee80211_hw *hw, 1288void iwl_mvm_set_default_unicast_key(struct ieee80211_hw *hw,
1293 struct ieee80211_vif *vif, int idx); 1289 struct ieee80211_vif *vif, int idx);
1294extern const struct file_operations iwl_dbgfs_d3_test_ops; 1290extern const struct file_operations iwl_dbgfs_d3_test_ops;
1295#ifdef CONFIG_PM_SLEEP 1291#ifdef CONFIG_PM
1292int iwl_mvm_wowlan_config_key_params(struct iwl_mvm *mvm,
1293 struct ieee80211_vif *vif,
1294 bool host_awake,
1295 u32 cmd_flags);
1296void iwl_mvm_d0i3_update_keys(struct iwl_mvm *mvm,
1297 struct ieee80211_vif *vif,
1298 struct iwl_wowlan_status *status);
1296void iwl_mvm_set_last_nonqos_seq(struct iwl_mvm *mvm, 1299void iwl_mvm_set_last_nonqos_seq(struct iwl_mvm *mvm,
1297 struct ieee80211_vif *vif); 1300 struct ieee80211_vif *vif);
1298#else 1301#else
1302static inline int iwl_mvm_wowlan_config_key_params(struct iwl_mvm *mvm,
1303 struct ieee80211_vif *vif,
1304 bool host_awake,
1305 u32 cmd_flags)
1306{
1307 return 0;
1308}
1309
1310static inline void iwl_mvm_d0i3_update_keys(struct iwl_mvm *mvm,
1311 struct ieee80211_vif *vif,
1312 struct iwl_wowlan_status *status)
1313{
1314}
1315
1299static inline void 1316static inline void
1300iwl_mvm_set_last_nonqos_seq(struct iwl_mvm *mvm, struct ieee80211_vif *vif) 1317iwl_mvm_set_last_nonqos_seq(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
1301{ 1318{
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c
index 2debce3b839b..89ea70deeb84 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c
@@ -1076,6 +1076,7 @@ static void iwl_mvm_cmd_queue_full(struct iwl_op_mode *op_mode)
1076 1076
1077struct iwl_d0i3_iter_data { 1077struct iwl_d0i3_iter_data {
1078 struct iwl_mvm *mvm; 1078 struct iwl_mvm *mvm;
1079 struct ieee80211_vif *connected_vif;
1079 u8 ap_sta_id; 1080 u8 ap_sta_id;
1080 u8 vif_count; 1081 u8 vif_count;
1081 u8 offloading_tid; 1082 u8 offloading_tid;
@@ -1167,6 +1168,12 @@ static void iwl_mvm_enter_d0i3_iterator(void *_data, u8 *mac,
1167 */ 1168 */
1168 data->ap_sta_id = mvmvif->ap_sta_id; 1169 data->ap_sta_id = mvmvif->ap_sta_id;
1169 data->vif_count++; 1170 data->vif_count++;
1171
1172 /*
1173 * no new commands can be sent at this stage, so it's safe
1174 * to save the vif pointer during d0i3 entrance.
1175 */
1176 data->connected_vif = vif;
1170} 1177}
1171 1178
1172static void iwl_mvm_set_wowlan_data(struct iwl_mvm *mvm, 1179static void iwl_mvm_set_wowlan_data(struct iwl_mvm *mvm,
@@ -1261,6 +1268,10 @@ int iwl_mvm_enter_d0i3(struct iwl_op_mode *op_mode)
1261 1268
1262 /* configure wowlan configuration only if needed */ 1269 /* configure wowlan configuration only if needed */
1263 if (mvm->d0i3_ap_sta_id != IWL_MVM_STATION_COUNT) { 1270 if (mvm->d0i3_ap_sta_id != IWL_MVM_STATION_COUNT) {
1271 iwl_mvm_wowlan_config_key_params(mvm,
1272 d0i3_iter_data.connected_vif,
1273 true, flags);
1274
1264 iwl_mvm_set_wowlan_data(mvm, &wowlan_config_cmd, 1275 iwl_mvm_set_wowlan_data(mvm, &wowlan_config_cmd,
1265 &d0i3_iter_data); 1276 &d0i3_iter_data);
1266 1277
@@ -1290,25 +1301,30 @@ static void iwl_mvm_exit_d0i3_iterator(void *_data, u8 *mac,
1290 iwl_mvm_update_d0i3_power_mode(mvm, vif, false, flags); 1301 iwl_mvm_update_d0i3_power_mode(mvm, vif, false, flags);
1291} 1302}
1292 1303
1293struct iwl_mvm_wakeup_reason_iter_data { 1304struct iwl_mvm_d0i3_exit_work_iter_data {
1294 struct iwl_mvm *mvm; 1305 struct iwl_mvm *mvm;
1306 struct iwl_wowlan_status *status;
1295 u32 wakeup_reasons; 1307 u32 wakeup_reasons;
1296}; 1308};
1297 1309
1298static void iwl_mvm_d0i3_wakeup_reason_iter(void *_data, u8 *mac, 1310static void iwl_mvm_d0i3_exit_work_iter(void *_data, u8 *mac,
1299 struct ieee80211_vif *vif) 1311 struct ieee80211_vif *vif)
1300{ 1312{
1301 struct iwl_mvm_wakeup_reason_iter_data *data = _data; 1313 struct iwl_mvm_d0i3_exit_work_iter_data *data = _data;
1302 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); 1314 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
1315 u32 reasons = data->wakeup_reasons;
1303 1316
1304 if (vif->type == NL80211_IFTYPE_STATION && vif->bss_conf.assoc && 1317 /* consider only the relevant station interface */
1305 data->mvm->d0i3_ap_sta_id == mvmvif->ap_sta_id) { 1318 if (vif->type != NL80211_IFTYPE_STATION || !vif->bss_conf.assoc ||
1306 if (data->wakeup_reasons & 1319 data->mvm->d0i3_ap_sta_id != mvmvif->ap_sta_id)
1307 IWL_WOWLAN_WAKEUP_BY_DISCONNECTION_ON_DEAUTH) 1320 return;
1308 iwl_mvm_connection_loss(data->mvm, vif, "D0i3"); 1321
1309 else 1322 if (reasons & IWL_WOWLAN_WAKEUP_BY_DISCONNECTION_ON_DEAUTH)
1310 ieee80211_beacon_loss(vif); 1323 iwl_mvm_connection_loss(data->mvm, vif, "D0i3");
1311 } 1324 else if (reasons & IWL_WOWLAN_WAKEUP_BY_DISCONNECTION_ON_MISSED_BEACON)
1325 ieee80211_beacon_loss(vif);
1326 else
1327 iwl_mvm_d0i3_update_keys(data->mvm, vif, data->status);
1312} 1328}
1313 1329
1314void iwl_mvm_d0i3_enable_tx(struct iwl_mvm *mvm, __le16 *qos_seq) 1330void iwl_mvm_d0i3_enable_tx(struct iwl_mvm *mvm, __le16 *qos_seq)
@@ -1374,9 +1390,13 @@ static void iwl_mvm_d0i3_exit_work(struct work_struct *wk)
1374 .id = WOWLAN_GET_STATUSES, 1390 .id = WOWLAN_GET_STATUSES,
1375 .flags = CMD_HIGH_PRIO | CMD_WANT_SKB, 1391 .flags = CMD_HIGH_PRIO | CMD_WANT_SKB,
1376 }; 1392 };
1393 struct iwl_mvm_d0i3_exit_work_iter_data iter_data = {
1394 .mvm = mvm,
1395 };
1396
1377 struct iwl_wowlan_status *status; 1397 struct iwl_wowlan_status *status;
1378 int ret; 1398 int ret;
1379 u32 handled_reasons, wakeup_reasons = 0; 1399 u32 wakeup_reasons = 0;
1380 __le16 *qos_seq = NULL; 1400 __le16 *qos_seq = NULL;
1381 1401
1382 mutex_lock(&mvm->mutex); 1402 mutex_lock(&mvm->mutex);
@@ -1393,18 +1413,12 @@ static void iwl_mvm_d0i3_exit_work(struct work_struct *wk)
1393 1413
1394 IWL_DEBUG_RPM(mvm, "wakeup reasons: 0x%x\n", wakeup_reasons); 1414 IWL_DEBUG_RPM(mvm, "wakeup reasons: 0x%x\n", wakeup_reasons);
1395 1415
1396 handled_reasons = IWL_WOWLAN_WAKEUP_BY_DISCONNECTION_ON_MISSED_BEACON | 1416 iter_data.wakeup_reasons = wakeup_reasons;
1397 IWL_WOWLAN_WAKEUP_BY_DISCONNECTION_ON_DEAUTH; 1417 iter_data.status = status;
1398 if (wakeup_reasons & handled_reasons) { 1418 ieee80211_iterate_active_interfaces(mvm->hw,
1399 struct iwl_mvm_wakeup_reason_iter_data data = { 1419 IEEE80211_IFACE_ITER_NORMAL,
1400 .mvm = mvm, 1420 iwl_mvm_d0i3_exit_work_iter,
1401 .wakeup_reasons = wakeup_reasons, 1421 &iter_data);
1402 };
1403
1404 ieee80211_iterate_active_interfaces(
1405 mvm->hw, IEEE80211_IFACE_ITER_NORMAL,
1406 iwl_mvm_d0i3_wakeup_reason_iter, &data);
1407 }
1408out: 1422out:
1409 iwl_mvm_d0i3_enable_tx(mvm, qos_seq); 1423 iwl_mvm_d0i3_enable_tx(mvm, qos_seq);
1410 1424