hc
2024-01-05 071106ecf68c401173c58808b1cf5f68cc50d390
kernel/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c
....@@ -5,10 +5,9 @@
55 *
66 * GPL LICENSE SUMMARY
77 *
8
- * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
98 * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
109 * Copyright(c) 2017 Intel Deutschland GmbH
11
- * Copyright(c) 2018 Intel Corporation
10
+ * Copyright(c) 2012 - 2014, 2018 - 2020 Intel Corporation
1211 *
1312 * This program is free software; you can redistribute it and/or modify
1413 * it under the terms of version 2 of the GNU General Public License as
....@@ -28,10 +27,9 @@
2827 *
2928 * BSD LICENSE
3029 *
31
- * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
3230 * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
3331 * Copyright(c) 2017 Intel Deutschland GmbH
34
- * Copyright(c) 2018 Intel Corporation
32
+ * Copyright(c) 2012 - 2014, 2018 - 2020 Intel Corporation
3533 * All rights reserved.
3634 *
3735 * Redistribution and use in source and binary forms, with or without
....@@ -85,7 +83,7 @@
8583 {
8684 lockdep_assert_held(&mvm->time_event_lock);
8785
88
- if (!te_data->vif)
86
+ if (!te_data || !te_data->vif)
8987 return;
9088
9189 list_del(&te_data->list);
....@@ -100,16 +98,13 @@
10098 struct iwl_mvm *mvm = container_of(wk, struct iwl_mvm, roc_done_wk);
10199
102100 /*
103
- * Clear the ROC_RUNNING /ROC_AUX_RUNNING status bit.
101
+ * Clear the ROC_RUNNING status bit.
104102 * This will cause the TX path to drop offchannel transmissions.
105103 * That would also be done by mac80211, but it is racy, in particular
106104 * in the case that the time event actually completed in the firmware
107105 * (which is handled in iwl_mvm_te_handle_notif).
108106 */
109
- if (test_and_clear_bit(IWL_MVM_STATUS_ROC_RUNNING, &mvm->status))
110
- iwl_mvm_unref(mvm, IWL_MVM_REF_ROC);
111
- if (test_and_clear_bit(IWL_MVM_STATUS_ROC_AUX_RUNNING, &mvm->status))
112
- iwl_mvm_unref(mvm, IWL_MVM_REF_ROC_AUX);
107
+ clear_bit(IWL_MVM_STATUS_ROC_RUNNING, &mvm->status);
113108
114109 synchronize_net();
115110
....@@ -118,14 +113,9 @@
118113 * event finishes or is canceled, so that frames queued for it
119114 * won't get stuck on the queue and be transmitted in the next
120115 * time event.
121
- * We have to send the command asynchronously since this cannot
122
- * be under the mutex for locking reasons, but that's not an
123
- * issue as it will have to complete before the next command is
124
- * executed, and a new time event means a new command.
125116 */
126
- iwl_mvm_flush_sta(mvm, &mvm->aux_sta, true, CMD_ASYNC);
127117
128
- /* Do the same for the P2P device queue (STA) */
118
+ mutex_lock(&mvm->mutex);
129119 if (test_and_clear_bit(IWL_MVM_STATUS_NEED_FLUSH_P2P, &mvm->status)) {
130120 struct iwl_mvm_vif *mvmvif;
131121
....@@ -138,10 +128,30 @@
138128
139129 if (!WARN_ON(!mvm->p2p_device_vif)) {
140130 mvmvif = iwl_mvm_vif_from_mac80211(mvm->p2p_device_vif);
141
- iwl_mvm_flush_sta(mvm, &mvmvif->bcast_sta, true,
142
- CMD_ASYNC);
131
+ iwl_mvm_flush_sta(mvm, &mvmvif->bcast_sta, true);
143132 }
144133 }
134
+
135
+ /*
136
+ * Clear the ROC_AUX_RUNNING status bit.
137
+ * This will cause the TX path to drop offchannel transmissions.
138
+ * That would also be done by mac80211, but it is racy, in particular
139
+ * in the case that the time event actually completed in the firmware
140
+ * (which is handled in iwl_mvm_te_handle_notif).
141
+ */
142
+ if (test_and_clear_bit(IWL_MVM_STATUS_ROC_AUX_RUNNING, &mvm->status)) {
143
+ /* do the same in case of hot spot 2.0 */
144
+ iwl_mvm_flush_sta(mvm, &mvm->aux_sta, true);
145
+
146
+ /* In newer version of this command an aux station is added only
147
+ * in cases of dedicated tx queue and need to be removed in end
148
+ * of use */
149
+ if (iwl_fw_lookup_cmd_ver(mvm->fw, LONG_GROUP,
150
+ ADD_STA, 0) >= 12)
151
+ iwl_mvm_rm_aux_sta(mvm);
152
+ }
153
+
154
+ mutex_unlock(&mvm->mutex);
145155 }
146156
147157 static void iwl_mvm_roc_finished(struct iwl_mvm *mvm)
....@@ -174,7 +184,7 @@
174184 * So we just do nothing here and the switch
175185 * will be performed on the last TBTT.
176186 */
177
- if (!ieee80211_csa_is_complete(csa_vif)) {
187
+ if (!ieee80211_beacon_cntdwn_is_complete(csa_vif)) {
178188 IWL_WARN(mvm, "CSA NOA started too early\n");
179189 goto out_unlock;
180190 }
....@@ -234,6 +244,7 @@
234244 break;
235245 }
236246 iwl_mvm_csa_client_absent(mvm, te_data->vif);
247
+ cancel_delayed_work(&mvmvif->csa_work);
237248 ieee80211_chswitch_done(te_data->vif, true);
238249 break;
239250 default:
....@@ -254,16 +265,13 @@
254265 struct iwl_fw_dbg_trigger_time_event *te_trig;
255266 int i;
256267
257
- if (!iwl_fw_dbg_trigger_enabled(mvm->fw, FW_DBG_TRIGGER_TIME_EVENT))
268
+ trig = iwl_fw_dbg_trigger_on(&mvm->fwrt,
269
+ ieee80211_vif_to_wdev(te_data->vif),
270
+ FW_DBG_TRIGGER_TIME_EVENT);
271
+ if (!trig)
258272 return;
259273
260
- trig = iwl_fw_dbg_get_trigger(mvm->fw, FW_DBG_TRIGGER_TIME_EVENT);
261274 te_trig = (void *)trig->data;
262
-
263
- if (!iwl_fw_dbg_trigger_check_stop(&mvm->fwrt,
264
- ieee80211_vif_to_wdev(te_data->vif),
265
- trig))
266
- return;
267275
268276 for (i = 0; i < ARRAY_SIZE(te_trig->time_events); i++) {
269277 u32 trig_te_id = le32_to_cpu(te_trig->time_events[i].id);
....@@ -337,6 +345,7 @@
337345 switch (te_data->vif->type) {
338346 case NL80211_IFTYPE_P2P_DEVICE:
339347 ieee80211_remain_on_channel_expired(mvm->hw);
348
+ set_bit(IWL_MVM_STATUS_NEED_FLUSH_P2P, &mvm->status);
340349 iwl_mvm_roc_finished(mvm);
341350 break;
342351 case NL80211_IFTYPE_STATION:
....@@ -345,6 +354,8 @@
345354 * and know the dtim period.
346355 */
347356 iwl_mvm_te_check_disconnect(mvm, te_data->vif,
357
+ !te_data->vif->bss_conf.assoc ?
358
+ "Not associated and the time event is over already..." :
348359 "No beacon heard and the time event is over already...");
349360 break;
350361 default:
....@@ -358,7 +369,6 @@
358369
359370 if (te_data->vif->type == NL80211_IFTYPE_P2P_DEVICE) {
360371 set_bit(IWL_MVM_STATUS_ROC_RUNNING, &mvm->status);
361
- iwl_mvm_ref(mvm, IWL_MVM_REF_ROC);
362372 ieee80211_ready_on_channel(mvm->hw);
363373 } else if (te_data->id == TE_CHANNEL_SWITCH_PERIOD) {
364374 iwl_mvm_te_handle_notify_csa(mvm, te_data, notif);
....@@ -406,7 +416,6 @@
406416 } else if (le32_to_cpu(notif->action) == TE_V2_NOTIF_HOST_EVENT_START) {
407417 set_bit(IWL_MVM_STATUS_ROC_AUX_RUNNING, &mvm->status);
408418 te_data->running = true;
409
- iwl_mvm_ref(mvm, IWL_MVM_REF_ROC_AUX);
410419 ieee80211_ready_on_channel(mvm->hw); /* Start TE */
411420 } else {
412421 IWL_DEBUG_TE(mvm,
....@@ -643,11 +652,32 @@
643652 }
644653 }
645654
655
+static void iwl_mvm_cancel_session_protection(struct iwl_mvm *mvm,
656
+ struct iwl_mvm_vif *mvmvif)
657
+{
658
+ struct iwl_mvm_session_prot_cmd cmd = {
659
+ .id_and_color =
660
+ cpu_to_le32(FW_CMD_ID_AND_COLOR(mvmvif->id,
661
+ mvmvif->color)),
662
+ .action = cpu_to_le32(FW_CTXT_ACTION_REMOVE),
663
+ .conf_id = cpu_to_le32(mvmvif->time_event_data.id),
664
+ };
665
+ int ret;
666
+
667
+ ret = iwl_mvm_send_cmd_pdu(mvm, iwl_cmd_id(SESSION_PROTECTION_CMD,
668
+ MAC_CONF_GROUP, 0),
669
+ 0, sizeof(cmd), &cmd);
670
+ if (ret)
671
+ IWL_ERR(mvm,
672
+ "Couldn't send the SESSION_PROTECTION_CMD: %d\n", ret);
673
+}
674
+
646675 static bool __iwl_mvm_remove_time_event(struct iwl_mvm *mvm,
647676 struct iwl_mvm_time_event_data *te_data,
648677 u32 *uid)
649678 {
650679 u32 id;
680
+ struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(te_data->vif);
651681
652682 /*
653683 * It is possible that by the time we got to this point the time
....@@ -665,14 +695,29 @@
665695 iwl_mvm_te_clear_data(mvm, te_data);
666696 spin_unlock_bh(&mvm->time_event_lock);
667697
668
- /*
669
- * It is possible that by the time we try to remove it, the time event
670
- * has already ended and removed. In such a case there is no need to
671
- * send a removal command.
698
+ /* When session protection is supported, the te_data->id field
699
+ * is reused to save session protection's configuration.
672700 */
673
- if (id == TE_MAX) {
674
- IWL_DEBUG_TE(mvm, "TE 0x%x has already ended\n", *uid);
701
+ if (fw_has_capa(&mvm->fw->ucode_capa,
702
+ IWL_UCODE_TLV_CAPA_SESSION_PROT_CMD)) {
703
+ if (mvmvif && id < SESSION_PROTECT_CONF_MAX_ID) {
704
+ /* Session protection is still ongoing. Cancel it */
705
+ iwl_mvm_cancel_session_protection(mvm, mvmvif);
706
+ if (te_data->vif->type == NL80211_IFTYPE_P2P_DEVICE) {
707
+ set_bit(IWL_MVM_STATUS_NEED_FLUSH_P2P, &mvm->status);
708
+ iwl_mvm_roc_finished(mvm);
709
+ }
710
+ }
675711 return false;
712
+ } else {
713
+ /* It is possible that by the time we try to remove it, the
714
+ * time event has already ended and removed. In such a case
715
+ * there is no need to send a removal command.
716
+ */
717
+ if (id == TE_MAX) {
718
+ IWL_DEBUG_TE(mvm, "TE 0x%x has already ended\n", *uid);
719
+ return false;
720
+ }
676721 }
677722
678723 return true;
....@@ -689,6 +734,8 @@
689734 struct iwl_mvm_time_event_data *te_data)
690735 {
691736 struct iwl_hs20_roc_req aux_cmd = {};
737
+ u16 len = sizeof(aux_cmd) - iwl_mvm_chan_info_padding(mvm);
738
+
692739 u32 uid;
693740 int ret;
694741
....@@ -702,7 +749,7 @@
702749 IWL_DEBUG_TE(mvm, "Removing BSS AUX ROC TE 0x%x\n",
703750 le32_to_cpu(aux_cmd.event_unique_id));
704751 ret = iwl_mvm_send_cmd_pdu(mvm, HOT_SPOT_CMD, 0,
705
- sizeof(aux_cmd), &aux_cmd);
752
+ len, &aux_cmd);
706753
707754 if (WARN_ON(ret))
708755 return;
....@@ -737,6 +784,11 @@
737784 return;
738785 }
739786
787
+/*
788
+ * When the firmware supports the session protection API,
789
+ * this is not needed since it'll automatically remove the
790
+ * session protection after association + beacon reception.
791
+ */
740792 void iwl_mvm_stop_session_protection(struct iwl_mvm *mvm,
741793 struct ieee80211_vif *vif)
742794 {
....@@ -760,6 +812,117 @@
760812 iwl_mvm_remove_time_event(mvm, mvmvif, te_data);
761813 }
762814
815
+void iwl_mvm_rx_session_protect_notif(struct iwl_mvm *mvm,
816
+ struct iwl_rx_cmd_buffer *rxb)
817
+{
818
+ struct iwl_rx_packet *pkt = rxb_addr(rxb);
819
+ struct iwl_mvm_session_prot_notif *notif = (void *)pkt->data;
820
+ struct ieee80211_vif *vif;
821
+ struct iwl_mvm_vif *mvmvif;
822
+
823
+ rcu_read_lock();
824
+ vif = iwl_mvm_rcu_dereference_vif_id(mvm, le32_to_cpu(notif->mac_id),
825
+ true);
826
+
827
+ if (!vif)
828
+ goto out_unlock;
829
+
830
+ mvmvif = iwl_mvm_vif_from_mac80211(vif);
831
+
832
+ /* The vif is not a P2P_DEVICE, maintain its time_event_data */
833
+ if (vif->type != NL80211_IFTYPE_P2P_DEVICE) {
834
+ struct iwl_mvm_time_event_data *te_data =
835
+ &mvmvif->time_event_data;
836
+
837
+ if (!le32_to_cpu(notif->status)) {
838
+ iwl_mvm_te_check_disconnect(mvm, vif,
839
+ "Session protection failure");
840
+ spin_lock_bh(&mvm->time_event_lock);
841
+ iwl_mvm_te_clear_data(mvm, te_data);
842
+ spin_unlock_bh(&mvm->time_event_lock);
843
+ }
844
+
845
+ if (le32_to_cpu(notif->start)) {
846
+ spin_lock_bh(&mvm->time_event_lock);
847
+ te_data->running = le32_to_cpu(notif->start);
848
+ te_data->end_jiffies =
849
+ TU_TO_EXP_TIME(te_data->duration);
850
+ spin_unlock_bh(&mvm->time_event_lock);
851
+ } else {
852
+ /*
853
+ * By now, we should have finished association
854
+ * and know the dtim period.
855
+ */
856
+ iwl_mvm_te_check_disconnect(mvm, vif,
857
+ !vif->bss_conf.assoc ?
858
+ "Not associated and the session protection is over already..." :
859
+ "No beacon heard and the session protection is over already...");
860
+ spin_lock_bh(&mvm->time_event_lock);
861
+ iwl_mvm_te_clear_data(mvm, te_data);
862
+ spin_unlock_bh(&mvm->time_event_lock);
863
+ }
864
+
865
+ goto out_unlock;
866
+ }
867
+
868
+ if (!le32_to_cpu(notif->status) || !le32_to_cpu(notif->start)) {
869
+ /* End TE, notify mac80211 */
870
+ mvmvif->time_event_data.id = SESSION_PROTECT_CONF_MAX_ID;
871
+ ieee80211_remain_on_channel_expired(mvm->hw);
872
+ set_bit(IWL_MVM_STATUS_NEED_FLUSH_P2P, &mvm->status);
873
+ iwl_mvm_roc_finished(mvm);
874
+ } else if (le32_to_cpu(notif->start)) {
875
+ if (WARN_ON(mvmvif->time_event_data.id !=
876
+ le32_to_cpu(notif->conf_id)))
877
+ goto out_unlock;
878
+ set_bit(IWL_MVM_STATUS_ROC_RUNNING, &mvm->status);
879
+ ieee80211_ready_on_channel(mvm->hw); /* Start TE */
880
+ }
881
+
882
+ out_unlock:
883
+ rcu_read_unlock();
884
+}
885
+
886
+static int
887
+iwl_mvm_start_p2p_roc_session_protection(struct iwl_mvm *mvm,
888
+ struct ieee80211_vif *vif,
889
+ int duration,
890
+ enum ieee80211_roc_type type)
891
+{
892
+ struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
893
+ struct iwl_mvm_session_prot_cmd cmd = {
894
+ .id_and_color =
895
+ cpu_to_le32(FW_CMD_ID_AND_COLOR(mvmvif->id,
896
+ mvmvif->color)),
897
+ .action = cpu_to_le32(FW_CTXT_ACTION_ADD),
898
+ .duration_tu = cpu_to_le32(MSEC_TO_TU(duration)),
899
+ };
900
+
901
+ lockdep_assert_held(&mvm->mutex);
902
+
903
+ /* The time_event_data.id field is reused to save session
904
+ * protection's configuration.
905
+ */
906
+ switch (type) {
907
+ case IEEE80211_ROC_TYPE_NORMAL:
908
+ mvmvif->time_event_data.id =
909
+ SESSION_PROTECT_CONF_P2P_DEVICE_DISCOV;
910
+ break;
911
+ case IEEE80211_ROC_TYPE_MGMT_TX:
912
+ mvmvif->time_event_data.id =
913
+ SESSION_PROTECT_CONF_P2P_GO_NEGOTIATION;
914
+ break;
915
+ default:
916
+ WARN_ONCE(1, "Got an invalid ROC type\n");
917
+ return -EINVAL;
918
+ }
919
+
920
+ cmd.conf_id = cpu_to_le32(mvmvif->time_event_data.id);
921
+ return iwl_mvm_send_cmd_pdu(mvm, iwl_cmd_id(SESSION_PROTECTION_CMD,
922
+ MAC_CONF_GROUP, 0),
923
+ 0, sizeof(cmd), &cmd);
924
+}
925
+
763926 int iwl_mvm_start_p2p_roc(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
764927 int duration, enum ieee80211_roc_type type)
765928 {
....@@ -772,6 +935,12 @@
772935 IWL_WARN(mvm, "P2P_DEVICE remain on channel already running\n");
773936 return -EBUSY;
774937 }
938
+
939
+ if (fw_has_capa(&mvm->fw->ucode_capa,
940
+ IWL_UCODE_TLV_CAPA_SESSION_PROT_CMD))
941
+ return iwl_mvm_start_p2p_roc_session_protection(mvm, vif,
942
+ duration,
943
+ type);
775944
776945 time_cmd.action = cpu_to_le32(FW_CTXT_ACTION_ADD);
777946 time_cmd.id_and_color =
....@@ -850,10 +1019,27 @@
8501019 __iwl_mvm_remove_time_event(mvm, te_data, &uid);
8511020 }
8521021
853
-void iwl_mvm_stop_roc(struct iwl_mvm *mvm)
1022
+void iwl_mvm_stop_roc(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
8541023 {
8551024 struct iwl_mvm_vif *mvmvif;
8561025 struct iwl_mvm_time_event_data *te_data;
1026
+
1027
+ if (fw_has_capa(&mvm->fw->ucode_capa,
1028
+ IWL_UCODE_TLV_CAPA_SESSION_PROT_CMD)) {
1029
+ mvmvif = iwl_mvm_vif_from_mac80211(vif);
1030
+
1031
+ if (vif->type == NL80211_IFTYPE_P2P_DEVICE) {
1032
+ iwl_mvm_cancel_session_protection(mvm, mvmvif);
1033
+ set_bit(IWL_MVM_STATUS_NEED_FLUSH_P2P, &mvm->status);
1034
+ } else {
1035
+ iwl_mvm_remove_aux_roc_te(mvm, mvmvif,
1036
+ &mvmvif->time_event_data);
1037
+ }
1038
+
1039
+ iwl_mvm_roc_finished(mvm);
1040
+
1041
+ return;
1042
+ }
8571043
8581044 te_data = iwl_mvm_get_roc_te(mvm);
8591045 if (!te_data) {
....@@ -871,6 +1057,25 @@
8711057 }
8721058
8731059 iwl_mvm_roc_finished(mvm);
1060
+}
1061
+
1062
+void iwl_mvm_remove_csa_period(struct iwl_mvm *mvm,
1063
+ struct ieee80211_vif *vif)
1064
+{
1065
+ struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
1066
+ struct iwl_mvm_time_event_data *te_data = &mvmvif->time_event_data;
1067
+ u32 id;
1068
+
1069
+ lockdep_assert_held(&mvm->mutex);
1070
+
1071
+ spin_lock_bh(&mvm->time_event_lock);
1072
+ id = te_data->id;
1073
+ spin_unlock_bh(&mvm->time_event_lock);
1074
+
1075
+ if (id != TE_CHANNEL_SWITCH_PERIOD)
1076
+ return;
1077
+
1078
+ iwl_mvm_remove_time_event(mvm, mvmvif, te_data);
8741079 }
8751080
8761081 int iwl_mvm_schedule_csa_period(struct iwl_mvm *mvm,
....@@ -919,3 +1124,105 @@
9191124
9201125 return iwl_mvm_time_event_send_add(mvm, vif, te_data, &time_cmd);
9211126 }
1127
+
1128
+static bool iwl_mvm_session_prot_notif(struct iwl_notif_wait_data *notif_wait,
1129
+ struct iwl_rx_packet *pkt, void *data)
1130
+{
1131
+ struct iwl_mvm *mvm =
1132
+ container_of(notif_wait, struct iwl_mvm, notif_wait);
1133
+ struct iwl_mvm_session_prot_notif *resp;
1134
+ int resp_len = iwl_rx_packet_payload_len(pkt);
1135
+
1136
+ if (WARN_ON(pkt->hdr.cmd != SESSION_PROTECTION_NOTIF ||
1137
+ pkt->hdr.group_id != MAC_CONF_GROUP))
1138
+ return true;
1139
+
1140
+ if (WARN_ON_ONCE(resp_len != sizeof(*resp))) {
1141
+ IWL_ERR(mvm, "Invalid SESSION_PROTECTION_NOTIF response\n");
1142
+ return true;
1143
+ }
1144
+
1145
+ resp = (void *)pkt->data;
1146
+
1147
+ if (!resp->status)
1148
+ IWL_ERR(mvm,
1149
+ "TIME_EVENT_NOTIFICATION received but not executed\n");
1150
+
1151
+ return true;
1152
+}
1153
+
1154
+void iwl_mvm_schedule_session_protection(struct iwl_mvm *mvm,
1155
+ struct ieee80211_vif *vif,
1156
+ u32 duration, u32 min_duration,
1157
+ bool wait_for_notif)
1158
+{
1159
+ struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
1160
+ struct iwl_mvm_time_event_data *te_data = &mvmvif->time_event_data;
1161
+ const u16 notif[] = { iwl_cmd_id(SESSION_PROTECTION_NOTIF,
1162
+ MAC_CONF_GROUP, 0) };
1163
+ struct iwl_notification_wait wait_notif;
1164
+ struct iwl_mvm_session_prot_cmd cmd = {
1165
+ .id_and_color =
1166
+ cpu_to_le32(FW_CMD_ID_AND_COLOR(mvmvif->id,
1167
+ mvmvif->color)),
1168
+ .action = cpu_to_le32(FW_CTXT_ACTION_ADD),
1169
+ .conf_id = cpu_to_le32(SESSION_PROTECT_CONF_ASSOC),
1170
+ .duration_tu = cpu_to_le32(MSEC_TO_TU(duration)),
1171
+ };
1172
+
1173
+ lockdep_assert_held(&mvm->mutex);
1174
+
1175
+ spin_lock_bh(&mvm->time_event_lock);
1176
+ if (te_data->running &&
1177
+ time_after(te_data->end_jiffies, TU_TO_EXP_TIME(min_duration))) {
1178
+ IWL_DEBUG_TE(mvm, "We have enough time in the current TE: %u\n",
1179
+ jiffies_to_msecs(te_data->end_jiffies - jiffies));
1180
+ spin_unlock_bh(&mvm->time_event_lock);
1181
+
1182
+ return;
1183
+ }
1184
+
1185
+ iwl_mvm_te_clear_data(mvm, te_data);
1186
+ /*
1187
+ * The time_event_data.id field is reused to save session
1188
+ * protection's configuration.
1189
+ */
1190
+ te_data->id = le32_to_cpu(cmd.conf_id);
1191
+ te_data->duration = le32_to_cpu(cmd.duration_tu);
1192
+ spin_unlock_bh(&mvm->time_event_lock);
1193
+
1194
+ IWL_DEBUG_TE(mvm, "Add new session protection, duration %d TU\n",
1195
+ le32_to_cpu(cmd.duration_tu));
1196
+
1197
+ if (!wait_for_notif) {
1198
+ if (iwl_mvm_send_cmd_pdu(mvm,
1199
+ iwl_cmd_id(SESSION_PROTECTION_CMD,
1200
+ MAC_CONF_GROUP, 0),
1201
+ 0, sizeof(cmd), &cmd)) {
1202
+ IWL_ERR(mvm,
1203
+ "Couldn't send the SESSION_PROTECTION_CMD\n");
1204
+ spin_lock_bh(&mvm->time_event_lock);
1205
+ iwl_mvm_te_clear_data(mvm, te_data);
1206
+ spin_unlock_bh(&mvm->time_event_lock);
1207
+ }
1208
+
1209
+ return;
1210
+ }
1211
+
1212
+ iwl_init_notification_wait(&mvm->notif_wait, &wait_notif,
1213
+ notif, ARRAY_SIZE(notif),
1214
+ iwl_mvm_session_prot_notif, NULL);
1215
+
1216
+ if (iwl_mvm_send_cmd_pdu(mvm,
1217
+ iwl_cmd_id(SESSION_PROTECTION_CMD,
1218
+ MAC_CONF_GROUP, 0),
1219
+ 0, sizeof(cmd), &cmd)) {
1220
+ IWL_ERR(mvm,
1221
+ "Couldn't send the SESSION_PROTECTION_CMD\n");
1222
+ iwl_remove_notification(&mvm->notif_wait, &wait_notif);
1223
+ } else if (iwl_wait_notification(&mvm->notif_wait, &wait_notif,
1224
+ TU_TO_JIFFIES(100))) {
1225
+ IWL_ERR(mvm,
1226
+ "Failed to protect session until session protection\n");
1227
+ }
1228
+}