Merge tag 'mac80211-next-for-net-next-2021-06-25' of git://git.kernel.org/pub/scm...
[linux-2.6-microblaze.git] / drivers / net / wireless / intel / iwlwifi / mvm / time-event.c
1 // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
2 /*
3  * Copyright (C) 2012-2014, 2018-2021 Intel Corporation
4  * Copyright (C) 2013-2015 Intel Mobile Communications GmbH
5  * Copyright (C) 2017 Intel Deutschland GmbH
6  */
7 #include <linux/jiffies.h>
8 #include <net/mac80211.h>
9
10 #include "fw/notif-wait.h"
11 #include "iwl-trans.h"
12 #include "fw-api.h"
13 #include "time-event.h"
14 #include "mvm.h"
15 #include "iwl-io.h"
16 #include "iwl-prph.h"
17
18 /*
19  * For the high priority TE use a time event type that has similar priority to
20  * the FW's action scan priority.
21  */
22 #define IWL_MVM_ROC_TE_TYPE_NORMAL TE_P2P_DEVICE_DISCOVERABLE
23 #define IWL_MVM_ROC_TE_TYPE_MGMT_TX TE_P2P_CLIENT_ASSOC
24
25 void iwl_mvm_te_clear_data(struct iwl_mvm *mvm,
26                            struct iwl_mvm_time_event_data *te_data)
27 {
28         lockdep_assert_held(&mvm->time_event_lock);
29
30         if (!te_data || !te_data->vif)
31                 return;
32
33         list_del(&te_data->list);
34
35         /*
36          * the list is only used for AUX ROC events so make sure it is always
37          * initialized
38          */
39         INIT_LIST_HEAD(&te_data->list);
40
41         te_data->running = false;
42         te_data->uid = 0;
43         te_data->id = TE_MAX;
44         te_data->vif = NULL;
45 }
46
47 void iwl_mvm_roc_done_wk(struct work_struct *wk)
48 {
49         struct iwl_mvm *mvm = container_of(wk, struct iwl_mvm, roc_done_wk);
50
51         /*
52          * Clear the ROC_RUNNING /ROC_AUX_RUNNING status bit.
53          * This will cause the TX path to drop offchannel transmissions.
54          * That would also be done by mac80211, but it is racy, in particular
55          * in the case that the time event actually completed in the firmware
56          * (which is handled in iwl_mvm_te_handle_notif).
57          */
58         clear_bit(IWL_MVM_STATUS_ROC_RUNNING, &mvm->status);
59         clear_bit(IWL_MVM_STATUS_ROC_AUX_RUNNING, &mvm->status);
60
61         synchronize_net();
62
63         /*
64          * Flush the offchannel queue -- this is called when the time
65          * event finishes or is canceled, so that frames queued for it
66          * won't get stuck on the queue and be transmitted in the next
67          * time event.
68          */
69
70         mutex_lock(&mvm->mutex);
71         if (test_and_clear_bit(IWL_MVM_STATUS_NEED_FLUSH_P2P, &mvm->status)) {
72                 struct iwl_mvm_vif *mvmvif;
73
74                 /*
75                  * NB: access to this pointer would be racy, but the flush bit
76                  * can only be set when we had a P2P-Device VIF, and we have a
77                  * flush of this work in iwl_mvm_prepare_mac_removal() so it's
78                  * not really racy.
79                  */
80
81                 if (!WARN_ON(!mvm->p2p_device_vif)) {
82                         mvmvif = iwl_mvm_vif_from_mac80211(mvm->p2p_device_vif);
83                         iwl_mvm_flush_sta(mvm, &mvmvif->bcast_sta, true);
84                 }
85         } else {
86                 /* do the same in case of hot spot 2.0 */
87                 iwl_mvm_flush_sta(mvm, &mvm->aux_sta, true);
88                 /* In newer version of this command an aux station is added only
89                  * in cases of dedicated tx queue and need to be removed in end
90                  * of use */
91                 if (iwl_fw_lookup_cmd_ver(mvm->fw, LONG_GROUP,
92                                           ADD_STA, 0) >= 12)
93                         iwl_mvm_rm_aux_sta(mvm);
94         }
95
96         mutex_unlock(&mvm->mutex);
97 }
98
99 static void iwl_mvm_roc_finished(struct iwl_mvm *mvm)
100 {
101         /*
102          * Of course, our status bit is just as racy as mac80211, so in
103          * addition, fire off the work struct which will drop all frames
104          * from the hardware queues that made it through the race. First
105          * it will of course synchronize the TX path to make sure that
106          * any *new* TX will be rejected.
107          */
108         schedule_work(&mvm->roc_done_wk);
109 }
110
111 static void iwl_mvm_csa_noa_start(struct iwl_mvm *mvm)
112 {
113         struct ieee80211_vif *csa_vif;
114
115         rcu_read_lock();
116
117         csa_vif = rcu_dereference(mvm->csa_vif);
118         if (!csa_vif || !csa_vif->csa_active)
119                 goto out_unlock;
120
121         IWL_DEBUG_TE(mvm, "CSA NOA started\n");
122
123         /*
124          * CSA NoA is started but we still have beacons to
125          * transmit on the current channel.
126          * So we just do nothing here and the switch
127          * will be performed on the last TBTT.
128          */
129         if (!ieee80211_beacon_cntdwn_is_complete(csa_vif)) {
130                 IWL_WARN(mvm, "CSA NOA started too early\n");
131                 goto out_unlock;
132         }
133
134         ieee80211_csa_finish(csa_vif);
135
136         rcu_read_unlock();
137
138         RCU_INIT_POINTER(mvm->csa_vif, NULL);
139
140         return;
141
142 out_unlock:
143         rcu_read_unlock();
144 }
145
146 static bool iwl_mvm_te_check_disconnect(struct iwl_mvm *mvm,
147                                         struct ieee80211_vif *vif,
148                                         const char *errmsg)
149 {
150         struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
151
152         if (vif->type != NL80211_IFTYPE_STATION)
153                 return false;
154
155         if (!mvmvif->csa_bcn_pending && vif->bss_conf.assoc &&
156             vif->bss_conf.dtim_period)
157                 return false;
158         if (errmsg)
159                 IWL_ERR(mvm, "%s\n", errmsg);
160
161         if (mvmvif->csa_bcn_pending) {
162                 struct iwl_mvm_sta *mvmsta;
163
164                 rcu_read_lock();
165                 mvmsta = iwl_mvm_sta_from_staid_rcu(mvm, mvmvif->ap_sta_id);
166                 if (!WARN_ON(!mvmsta))
167                         iwl_mvm_sta_modify_disable_tx(mvm, mvmsta, false);
168                 rcu_read_unlock();
169         }
170
171         iwl_mvm_connection_loss(mvm, vif, errmsg);
172         return true;
173 }
174
175 static void
176 iwl_mvm_te_handle_notify_csa(struct iwl_mvm *mvm,
177                              struct iwl_mvm_time_event_data *te_data,
178                              struct iwl_time_event_notif *notif)
179 {
180         struct ieee80211_vif *vif = te_data->vif;
181         struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
182
183         if (!notif->status)
184                 IWL_DEBUG_TE(mvm, "CSA time event failed to start\n");
185
186         switch (te_data->vif->type) {
187         case NL80211_IFTYPE_AP:
188                 if (!notif->status)
189                         mvmvif->csa_failed = true;
190                 iwl_mvm_csa_noa_start(mvm);
191                 break;
192         case NL80211_IFTYPE_STATION:
193                 if (!notif->status) {
194                         iwl_mvm_connection_loss(mvm, vif,
195                                                 "CSA TE failed to start");
196                         break;
197                 }
198                 iwl_mvm_csa_client_absent(mvm, te_data->vif);
199                 cancel_delayed_work(&mvmvif->csa_work);
200                 ieee80211_chswitch_done(te_data->vif, true);
201                 break;
202         default:
203                 /* should never happen */
204                 WARN_ON_ONCE(1);
205                 break;
206         }
207
208         /* we don't need it anymore */
209         iwl_mvm_te_clear_data(mvm, te_data);
210 }
211
212 static void iwl_mvm_te_check_trigger(struct iwl_mvm *mvm,
213                                      struct iwl_time_event_notif *notif,
214                                      struct iwl_mvm_time_event_data *te_data)
215 {
216         struct iwl_fw_dbg_trigger_tlv *trig;
217         struct iwl_fw_dbg_trigger_time_event *te_trig;
218         int i;
219
220         trig = iwl_fw_dbg_trigger_on(&mvm->fwrt,
221                                      ieee80211_vif_to_wdev(te_data->vif),
222                                      FW_DBG_TRIGGER_TIME_EVENT);
223         if (!trig)
224                 return;
225
226         te_trig = (void *)trig->data;
227
228         for (i = 0; i < ARRAY_SIZE(te_trig->time_events); i++) {
229                 u32 trig_te_id = le32_to_cpu(te_trig->time_events[i].id);
230                 u32 trig_action_bitmap =
231                         le32_to_cpu(te_trig->time_events[i].action_bitmap);
232                 u32 trig_status_bitmap =
233                         le32_to_cpu(te_trig->time_events[i].status_bitmap);
234
235                 if (trig_te_id != te_data->id ||
236                     !(trig_action_bitmap & le32_to_cpu(notif->action)) ||
237                     !(trig_status_bitmap & BIT(le32_to_cpu(notif->status))))
238                         continue;
239
240                 iwl_fw_dbg_collect_trig(&mvm->fwrt, trig,
241                                         "Time event %d Action 0x%x received status: %d",
242                                         te_data->id,
243                                         le32_to_cpu(notif->action),
244                                         le32_to_cpu(notif->status));
245                 break;
246         }
247 }
248
249 /*
250  * Handles a FW notification for an event that is known to the driver.
251  *
252  * @mvm: the mvm component
253  * @te_data: the time event data
254  * @notif: the notification data corresponding the time event data.
255  */
256 static void iwl_mvm_te_handle_notif(struct iwl_mvm *mvm,
257                                     struct iwl_mvm_time_event_data *te_data,
258                                     struct iwl_time_event_notif *notif)
259 {
260         lockdep_assert_held(&mvm->time_event_lock);
261
262         IWL_DEBUG_TE(mvm, "Handle time event notif - UID = 0x%x action %d\n",
263                      le32_to_cpu(notif->unique_id),
264                      le32_to_cpu(notif->action));
265
266         iwl_mvm_te_check_trigger(mvm, notif, te_data);
267
268         /*
269          * The FW sends the start/end time event notifications even for events
270          * that it fails to schedule. This is indicated in the status field of
271          * the notification. This happens in cases that the scheduler cannot
272          * find a schedule that can handle the event (for example requesting a
273          * P2P Device discoveribility, while there are other higher priority
274          * events in the system).
275          */
276         if (!le32_to_cpu(notif->status)) {
277                 const char *msg;
278
279                 if (notif->action & cpu_to_le32(TE_V2_NOTIF_HOST_EVENT_START))
280                         msg = "Time Event start notification failure";
281                 else
282                         msg = "Time Event end notification failure";
283
284                 IWL_DEBUG_TE(mvm, "%s\n", msg);
285
286                 if (iwl_mvm_te_check_disconnect(mvm, te_data->vif, msg)) {
287                         iwl_mvm_te_clear_data(mvm, te_data);
288                         return;
289                 }
290         }
291
292         if (le32_to_cpu(notif->action) & TE_V2_NOTIF_HOST_EVENT_END) {
293                 IWL_DEBUG_TE(mvm,
294                              "TE ended - current time %lu, estimated end %lu\n",
295                              jiffies, te_data->end_jiffies);
296
297                 switch (te_data->vif->type) {
298                 case NL80211_IFTYPE_P2P_DEVICE:
299                         ieee80211_remain_on_channel_expired(mvm->hw);
300                         set_bit(IWL_MVM_STATUS_NEED_FLUSH_P2P, &mvm->status);
301                         iwl_mvm_roc_finished(mvm);
302                         break;
303                 case NL80211_IFTYPE_STATION:
304                         /*
305                          * If we are switching channel, don't disconnect
306                          * if the time event is already done. Beacons can
307                          * be delayed a bit after the switch.
308                          */
309                         if (te_data->id == TE_CHANNEL_SWITCH_PERIOD) {
310                                 IWL_DEBUG_TE(mvm,
311                                              "No beacon heard and the CS time event is over, don't disconnect\n");
312                                 break;
313                         }
314
315                         /*
316                          * By now, we should have finished association
317                          * and know the dtim period.
318                          */
319                         iwl_mvm_te_check_disconnect(mvm, te_data->vif,
320                                 !te_data->vif->bss_conf.assoc ?
321                                 "Not associated and the time event is over already..." :
322                                 "No beacon heard and the time event is over already...");
323                         break;
324                 default:
325                         break;
326                 }
327
328                 iwl_mvm_te_clear_data(mvm, te_data);
329         } else if (le32_to_cpu(notif->action) & TE_V2_NOTIF_HOST_EVENT_START) {
330                 te_data->running = true;
331                 te_data->end_jiffies = TU_TO_EXP_TIME(te_data->duration);
332
333                 if (te_data->vif->type == NL80211_IFTYPE_P2P_DEVICE) {
334                         set_bit(IWL_MVM_STATUS_ROC_RUNNING, &mvm->status);
335                         ieee80211_ready_on_channel(mvm->hw);
336                 } else if (te_data->id == TE_CHANNEL_SWITCH_PERIOD) {
337                         iwl_mvm_te_handle_notify_csa(mvm, te_data, notif);
338                 }
339         } else {
340                 IWL_WARN(mvm, "Got TE with unknown action\n");
341         }
342 }
343
344 /*
345  * Handle A Aux ROC time event
346  */
347 static int iwl_mvm_aux_roc_te_handle_notif(struct iwl_mvm *mvm,
348                                            struct iwl_time_event_notif *notif)
349 {
350         struct iwl_mvm_time_event_data *te_data, *tmp;
351         bool aux_roc_te = false;
352
353         list_for_each_entry_safe(te_data, tmp, &mvm->aux_roc_te_list, list) {
354                 if (le32_to_cpu(notif->unique_id) == te_data->uid) {
355                         aux_roc_te = true;
356                         break;
357                 }
358         }
359         if (!aux_roc_te) /* Not a Aux ROC time event */
360                 return -EINVAL;
361
362         iwl_mvm_te_check_trigger(mvm, notif, te_data);
363
364         IWL_DEBUG_TE(mvm,
365                      "Aux ROC time event notification  - UID = 0x%x action %d (error = %d)\n",
366                      le32_to_cpu(notif->unique_id),
367                      le32_to_cpu(notif->action), le32_to_cpu(notif->status));
368
369         if (!le32_to_cpu(notif->status) ||
370             le32_to_cpu(notif->action) == TE_V2_NOTIF_HOST_EVENT_END) {
371                 /* End TE, notify mac80211 */
372                 ieee80211_remain_on_channel_expired(mvm->hw);
373                 iwl_mvm_roc_finished(mvm); /* flush aux queue */
374                 list_del(&te_data->list); /* remove from list */
375                 te_data->running = false;
376                 te_data->vif = NULL;
377                 te_data->uid = 0;
378                 te_data->id = TE_MAX;
379         } else if (le32_to_cpu(notif->action) == TE_V2_NOTIF_HOST_EVENT_START) {
380                 set_bit(IWL_MVM_STATUS_ROC_AUX_RUNNING, &mvm->status);
381                 te_data->running = true;
382                 ieee80211_ready_on_channel(mvm->hw); /* Start TE */
383         } else {
384                 IWL_DEBUG_TE(mvm,
385                              "ERROR: Unknown Aux ROC Time Event (action = %d)\n",
386                              le32_to_cpu(notif->action));
387                 return -EINVAL;
388         }
389
390         return 0;
391 }
392
393 /*
394  * The Rx handler for time event notifications
395  */
396 void iwl_mvm_rx_time_event_notif(struct iwl_mvm *mvm,
397                                  struct iwl_rx_cmd_buffer *rxb)
398 {
399         struct iwl_rx_packet *pkt = rxb_addr(rxb);
400         struct iwl_time_event_notif *notif = (void *)pkt->data;
401         struct iwl_mvm_time_event_data *te_data, *tmp;
402
403         IWL_DEBUG_TE(mvm, "Time event notification - UID = 0x%x action %d\n",
404                      le32_to_cpu(notif->unique_id),
405                      le32_to_cpu(notif->action));
406
407         spin_lock_bh(&mvm->time_event_lock);
408         /* This time event is triggered for Aux ROC request */
409         if (!iwl_mvm_aux_roc_te_handle_notif(mvm, notif))
410                 goto unlock;
411
412         list_for_each_entry_safe(te_data, tmp, &mvm->time_event_list, list) {
413                 if (le32_to_cpu(notif->unique_id) == te_data->uid)
414                         iwl_mvm_te_handle_notif(mvm, te_data, notif);
415         }
416 unlock:
417         spin_unlock_bh(&mvm->time_event_lock);
418 }
419
420 static bool iwl_mvm_te_notif(struct iwl_notif_wait_data *notif_wait,
421                              struct iwl_rx_packet *pkt, void *data)
422 {
423         struct iwl_mvm *mvm =
424                 container_of(notif_wait, struct iwl_mvm, notif_wait);
425         struct iwl_mvm_time_event_data *te_data = data;
426         struct iwl_time_event_notif *resp;
427         int resp_len = iwl_rx_packet_payload_len(pkt);
428
429         if (WARN_ON(pkt->hdr.cmd != TIME_EVENT_NOTIFICATION))
430                 return true;
431
432         if (WARN_ON_ONCE(resp_len != sizeof(*resp))) {
433                 IWL_ERR(mvm, "Invalid TIME_EVENT_NOTIFICATION response\n");
434                 return true;
435         }
436
437         resp = (void *)pkt->data;
438
439         /* te_data->uid is already set in the TIME_EVENT_CMD response */
440         if (le32_to_cpu(resp->unique_id) != te_data->uid)
441                 return false;
442
443         IWL_DEBUG_TE(mvm, "TIME_EVENT_NOTIFICATION response - UID = 0x%x\n",
444                      te_data->uid);
445         if (!resp->status)
446                 IWL_ERR(mvm,
447                         "TIME_EVENT_NOTIFICATION received but not executed\n");
448
449         return true;
450 }
451
452 static bool iwl_mvm_time_event_response(struct iwl_notif_wait_data *notif_wait,
453                                         struct iwl_rx_packet *pkt, void *data)
454 {
455         struct iwl_mvm *mvm =
456                 container_of(notif_wait, struct iwl_mvm, notif_wait);
457         struct iwl_mvm_time_event_data *te_data = data;
458         struct iwl_time_event_resp *resp;
459         int resp_len = iwl_rx_packet_payload_len(pkt);
460
461         if (WARN_ON(pkt->hdr.cmd != TIME_EVENT_CMD))
462                 return true;
463
464         if (WARN_ON_ONCE(resp_len != sizeof(*resp))) {
465                 IWL_ERR(mvm, "Invalid TIME_EVENT_CMD response\n");
466                 return true;
467         }
468
469         resp = (void *)pkt->data;
470
471         /* we should never get a response to another TIME_EVENT_CMD here */
472         if (WARN_ON_ONCE(le32_to_cpu(resp->id) != te_data->id))
473                 return false;
474
475         te_data->uid = le32_to_cpu(resp->unique_id);
476         IWL_DEBUG_TE(mvm, "TIME_EVENT_CMD response - UID = 0x%x\n",
477                      te_data->uid);
478         return true;
479 }
480
481 static int iwl_mvm_time_event_send_add(struct iwl_mvm *mvm,
482                                        struct ieee80211_vif *vif,
483                                        struct iwl_mvm_time_event_data *te_data,
484                                        struct iwl_time_event_cmd *te_cmd)
485 {
486         static const u16 time_event_response[] = { TIME_EVENT_CMD };
487         struct iwl_notification_wait wait_time_event;
488         int ret;
489
490         lockdep_assert_held(&mvm->mutex);
491
492         IWL_DEBUG_TE(mvm, "Add new TE, duration %d TU\n",
493                      le32_to_cpu(te_cmd->duration));
494
495         spin_lock_bh(&mvm->time_event_lock);
496         if (WARN_ON(te_data->id != TE_MAX)) {
497                 spin_unlock_bh(&mvm->time_event_lock);
498                 return -EIO;
499         }
500         te_data->vif = vif;
501         te_data->duration = le32_to_cpu(te_cmd->duration);
502         te_data->id = le32_to_cpu(te_cmd->id);
503         list_add_tail(&te_data->list, &mvm->time_event_list);
504         spin_unlock_bh(&mvm->time_event_lock);
505
506         /*
507          * Use a notification wait, which really just processes the
508          * command response and doesn't wait for anything, in order
509          * to be able to process the response and get the UID inside
510          * the RX path. Using CMD_WANT_SKB doesn't work because it
511          * stores the buffer and then wakes up this thread, by which
512          * time another notification (that the time event started)
513          * might already be processed unsuccessfully.
514          */
515         iwl_init_notification_wait(&mvm->notif_wait, &wait_time_event,
516                                    time_event_response,
517                                    ARRAY_SIZE(time_event_response),
518                                    iwl_mvm_time_event_response, te_data);
519
520         ret = iwl_mvm_send_cmd_pdu(mvm, TIME_EVENT_CMD, 0,
521                                             sizeof(*te_cmd), te_cmd);
522         if (ret) {
523                 IWL_ERR(mvm, "Couldn't send TIME_EVENT_CMD: %d\n", ret);
524                 iwl_remove_notification(&mvm->notif_wait, &wait_time_event);
525                 goto out_clear_te;
526         }
527
528         /* No need to wait for anything, so just pass 1 (0 isn't valid) */
529         ret = iwl_wait_notification(&mvm->notif_wait, &wait_time_event, 1);
530         /* should never fail */
531         WARN_ON_ONCE(ret);
532
533         if (ret) {
534  out_clear_te:
535                 spin_lock_bh(&mvm->time_event_lock);
536                 iwl_mvm_te_clear_data(mvm, te_data);
537                 spin_unlock_bh(&mvm->time_event_lock);
538         }
539         return ret;
540 }
541
542 void iwl_mvm_protect_session(struct iwl_mvm *mvm,
543                              struct ieee80211_vif *vif,
544                              u32 duration, u32 min_duration,
545                              u32 max_delay, bool wait_for_notif)
546 {
547         struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
548         struct iwl_mvm_time_event_data *te_data = &mvmvif->time_event_data;
549         const u16 te_notif_response[] = { TIME_EVENT_NOTIFICATION };
550         struct iwl_notification_wait wait_te_notif;
551         struct iwl_time_event_cmd time_cmd = {};
552
553         lockdep_assert_held(&mvm->mutex);
554
555         if (te_data->running &&
556             time_after(te_data->end_jiffies, TU_TO_EXP_TIME(min_duration))) {
557                 IWL_DEBUG_TE(mvm, "We have enough time in the current TE: %u\n",
558                              jiffies_to_msecs(te_data->end_jiffies - jiffies));
559                 return;
560         }
561
562         if (te_data->running) {
563                 IWL_DEBUG_TE(mvm, "extend 0x%x: only %u ms left\n",
564                              te_data->uid,
565                              jiffies_to_msecs(te_data->end_jiffies - jiffies));
566                 /*
567                  * we don't have enough time
568                  * cancel the current TE and issue a new one
569                  * Of course it would be better to remove the old one only
570                  * when the new one is added, but we don't care if we are off
571                  * channel for a bit. All we need to do, is not to return
572                  * before we actually begin to be on the channel.
573                  */
574                 iwl_mvm_stop_session_protection(mvm, vif);
575         }
576
577         time_cmd.action = cpu_to_le32(FW_CTXT_ACTION_ADD);
578         time_cmd.id_and_color =
579                 cpu_to_le32(FW_CMD_ID_AND_COLOR(mvmvif->id, mvmvif->color));
580         time_cmd.id = cpu_to_le32(TE_BSS_STA_AGGRESSIVE_ASSOC);
581
582         time_cmd.apply_time = cpu_to_le32(0);
583
584         time_cmd.max_frags = TE_V2_FRAG_NONE;
585         time_cmd.max_delay = cpu_to_le32(max_delay);
586         /* TODO: why do we need to interval = bi if it is not periodic? */
587         time_cmd.interval = cpu_to_le32(1);
588         time_cmd.duration = cpu_to_le32(duration);
589         time_cmd.repeat = 1;
590         time_cmd.policy = cpu_to_le16(TE_V2_NOTIF_HOST_EVENT_START |
591                                       TE_V2_NOTIF_HOST_EVENT_END |
592                                       TE_V2_START_IMMEDIATELY);
593
594         if (!wait_for_notif) {
595                 iwl_mvm_time_event_send_add(mvm, vif, te_data, &time_cmd);
596                 return;
597         }
598
599         /*
600          * Create notification_wait for the TIME_EVENT_NOTIFICATION to use
601          * right after we send the time event
602          */
603         iwl_init_notification_wait(&mvm->notif_wait, &wait_te_notif,
604                                    te_notif_response,
605                                    ARRAY_SIZE(te_notif_response),
606                                    iwl_mvm_te_notif, te_data);
607
608         /* If TE was sent OK - wait for the notification that started */
609         if (iwl_mvm_time_event_send_add(mvm, vif, te_data, &time_cmd)) {
610                 IWL_ERR(mvm, "Failed to add TE to protect session\n");
611                 iwl_remove_notification(&mvm->notif_wait, &wait_te_notif);
612         } else if (iwl_wait_notification(&mvm->notif_wait, &wait_te_notif,
613                                          TU_TO_JIFFIES(max_delay))) {
614                 IWL_ERR(mvm, "Failed to protect session until TE\n");
615         }
616 }
617
618 static void iwl_mvm_cancel_session_protection(struct iwl_mvm *mvm,
619                                               struct iwl_mvm_vif *mvmvif,
620                                               u32 id)
621 {
622         struct iwl_mvm_session_prot_cmd cmd = {
623                 .id_and_color =
624                         cpu_to_le32(FW_CMD_ID_AND_COLOR(mvmvif->id,
625                                                         mvmvif->color)),
626                 .action = cpu_to_le32(FW_CTXT_ACTION_REMOVE),
627                 .conf_id = cpu_to_le32(id),
628         };
629         int ret;
630
631         ret = iwl_mvm_send_cmd_pdu(mvm, iwl_cmd_id(SESSION_PROTECTION_CMD,
632                                                    MAC_CONF_GROUP, 0),
633                                    0, sizeof(cmd), &cmd);
634         if (ret)
635                 IWL_ERR(mvm,
636                         "Couldn't send the SESSION_PROTECTION_CMD: %d\n", ret);
637 }
638
639 static bool __iwl_mvm_remove_time_event(struct iwl_mvm *mvm,
640                                         struct iwl_mvm_time_event_data *te_data,
641                                         u32 *uid)
642 {
643         u32 id;
644         struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(te_data->vif);
645         enum nl80211_iftype iftype;
646
647         if (!te_data->vif)
648                 return false;
649
650         iftype = te_data->vif->type;
651
652         /*
653          * It is possible that by the time we got to this point the time
654          * event was already removed.
655          */
656         spin_lock_bh(&mvm->time_event_lock);
657
658         /* Save time event uid before clearing its data */
659         *uid = te_data->uid;
660         id = te_data->id;
661
662         /*
663          * The clear_data function handles time events that were already removed
664          */
665         iwl_mvm_te_clear_data(mvm, te_data);
666         spin_unlock_bh(&mvm->time_event_lock);
667
668         /* When session protection is supported, the te_data->id field
669          * is reused to save session protection's configuration.
670          */
671         if (fw_has_capa(&mvm->fw->ucode_capa,
672                         IWL_UCODE_TLV_CAPA_SESSION_PROT_CMD)) {
673                 if (mvmvif && id < SESSION_PROTECT_CONF_MAX_ID) {
674                         /* Session protection is still ongoing. Cancel it */
675                         iwl_mvm_cancel_session_protection(mvm, mvmvif, id);
676                         if (iftype == NL80211_IFTYPE_P2P_DEVICE) {
677                                 set_bit(IWL_MVM_STATUS_NEED_FLUSH_P2P, &mvm->status);
678                                 iwl_mvm_roc_finished(mvm);
679                         }
680                 }
681                 return false;
682         } else {
683                 /* It is possible that by the time we try to remove it, the
684                  * time event has already ended and removed. In such a case
685                  * there is no need to send a removal command.
686                  */
687                 if (id == TE_MAX) {
688                         IWL_DEBUG_TE(mvm, "TE 0x%x has already ended\n", *uid);
689                         return false;
690                 }
691         }
692
693         return true;
694 }
695
696 /*
697  * Explicit request to remove a aux roc time event. The removal of a time
698  * event needs to be synchronized with the flow of a time event's end
699  * notification, which also removes the time event from the op mode
700  * data structures.
701  */
702 static void iwl_mvm_remove_aux_roc_te(struct iwl_mvm *mvm,
703                                       struct iwl_mvm_vif *mvmvif,
704                                       struct iwl_mvm_time_event_data *te_data)
705 {
706         struct iwl_hs20_roc_req aux_cmd = {};
707         u16 len = sizeof(aux_cmd) - iwl_mvm_chan_info_padding(mvm);
708
709         u32 uid;
710         int ret;
711
712         if (!__iwl_mvm_remove_time_event(mvm, te_data, &uid))
713                 return;
714
715         aux_cmd.event_unique_id = cpu_to_le32(uid);
716         aux_cmd.action = cpu_to_le32(FW_CTXT_ACTION_REMOVE);
717         aux_cmd.id_and_color =
718                 cpu_to_le32(FW_CMD_ID_AND_COLOR(mvmvif->id, mvmvif->color));
719         IWL_DEBUG_TE(mvm, "Removing BSS AUX ROC TE 0x%x\n",
720                      le32_to_cpu(aux_cmd.event_unique_id));
721         ret = iwl_mvm_send_cmd_pdu(mvm, HOT_SPOT_CMD, 0,
722                                    len, &aux_cmd);
723
724         if (WARN_ON(ret))
725                 return;
726 }
727
728 /*
729  * Explicit request to remove a time event. The removal of a time event needs to
730  * be synchronized with the flow of a time event's end notification, which also
731  * removes the time event from the op mode data structures.
732  */
733 void iwl_mvm_remove_time_event(struct iwl_mvm *mvm,
734                                struct iwl_mvm_vif *mvmvif,
735                                struct iwl_mvm_time_event_data *te_data)
736 {
737         struct iwl_time_event_cmd time_cmd = {};
738         u32 uid;
739         int ret;
740
741         if (!__iwl_mvm_remove_time_event(mvm, te_data, &uid))
742                 return;
743
744         /* When we remove a TE, the UID is to be set in the id field */
745         time_cmd.id = cpu_to_le32(uid);
746         time_cmd.action = cpu_to_le32(FW_CTXT_ACTION_REMOVE);
747         time_cmd.id_and_color =
748                 cpu_to_le32(FW_CMD_ID_AND_COLOR(mvmvif->id, mvmvif->color));
749
750         IWL_DEBUG_TE(mvm, "Removing TE 0x%x\n", le32_to_cpu(time_cmd.id));
751         ret = iwl_mvm_send_cmd_pdu(mvm, TIME_EVENT_CMD, 0,
752                                    sizeof(time_cmd), &time_cmd);
753         if (ret)
754                 IWL_ERR(mvm, "Couldn't remove the time event\n");
755 }
756
757 void iwl_mvm_stop_session_protection(struct iwl_mvm *mvm,
758                                      struct ieee80211_vif *vif)
759 {
760         struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
761         struct iwl_mvm_time_event_data *te_data = &mvmvif->time_event_data;
762         u32 id;
763
764         lockdep_assert_held(&mvm->mutex);
765
766         spin_lock_bh(&mvm->time_event_lock);
767         id = te_data->id;
768         spin_unlock_bh(&mvm->time_event_lock);
769
770         if (fw_has_capa(&mvm->fw->ucode_capa,
771                         IWL_UCODE_TLV_CAPA_SESSION_PROT_CMD)) {
772                 if (id != SESSION_PROTECT_CONF_ASSOC) {
773                         IWL_DEBUG_TE(mvm,
774                                      "don't remove session protection id=%u\n",
775                                      id);
776                         return;
777                 }
778         } else if (id != TE_BSS_STA_AGGRESSIVE_ASSOC) {
779                 IWL_DEBUG_TE(mvm,
780                              "don't remove TE with id=%u (not session protection)\n",
781                              id);
782                 return;
783         }
784
785         iwl_mvm_remove_time_event(mvm, mvmvif, te_data);
786 }
787
788 void iwl_mvm_rx_session_protect_notif(struct iwl_mvm *mvm,
789                                       struct iwl_rx_cmd_buffer *rxb)
790 {
791         struct iwl_rx_packet *pkt = rxb_addr(rxb);
792         struct iwl_mvm_session_prot_notif *notif = (void *)pkt->data;
793         struct ieee80211_vif *vif;
794         struct iwl_mvm_vif *mvmvif;
795
796         rcu_read_lock();
797         vif = iwl_mvm_rcu_dereference_vif_id(mvm, le32_to_cpu(notif->mac_id),
798                                              true);
799
800         if (!vif)
801                 goto out_unlock;
802
803         mvmvif = iwl_mvm_vif_from_mac80211(vif);
804
805         /* The vif is not a P2P_DEVICE, maintain its time_event_data */
806         if (vif->type != NL80211_IFTYPE_P2P_DEVICE) {
807                 struct iwl_mvm_time_event_data *te_data =
808                         &mvmvif->time_event_data;
809
810                 if (!le32_to_cpu(notif->status)) {
811                         iwl_mvm_te_check_disconnect(mvm, vif,
812                                                     "Session protection failure");
813                         spin_lock_bh(&mvm->time_event_lock);
814                         iwl_mvm_te_clear_data(mvm, te_data);
815                         spin_unlock_bh(&mvm->time_event_lock);
816                 }
817
818                 if (le32_to_cpu(notif->start)) {
819                         spin_lock_bh(&mvm->time_event_lock);
820                         te_data->running = le32_to_cpu(notif->start);
821                         te_data->end_jiffies =
822                                 TU_TO_EXP_TIME(te_data->duration);
823                         spin_unlock_bh(&mvm->time_event_lock);
824                 } else {
825                         /*
826                          * By now, we should have finished association
827                          * and know the dtim period.
828                          */
829                         iwl_mvm_te_check_disconnect(mvm, vif,
830                                                     !vif->bss_conf.assoc ?
831                                                     "Not associated and the session protection is over already..." :
832                                                     "No beacon heard and the session protection is over already...");
833                         spin_lock_bh(&mvm->time_event_lock);
834                         iwl_mvm_te_clear_data(mvm, te_data);
835                         spin_unlock_bh(&mvm->time_event_lock);
836                 }
837
838                 goto out_unlock;
839         }
840
841         if (!le32_to_cpu(notif->status) || !le32_to_cpu(notif->start)) {
842                 /* End TE, notify mac80211 */
843                 mvmvif->time_event_data.id = SESSION_PROTECT_CONF_MAX_ID;
844                 ieee80211_remain_on_channel_expired(mvm->hw);
845                 set_bit(IWL_MVM_STATUS_NEED_FLUSH_P2P, &mvm->status);
846                 iwl_mvm_roc_finished(mvm);
847         } else if (le32_to_cpu(notif->start)) {
848                 if (WARN_ON(mvmvif->time_event_data.id !=
849                                 le32_to_cpu(notif->conf_id)))
850                         goto out_unlock;
851                 set_bit(IWL_MVM_STATUS_ROC_RUNNING, &mvm->status);
852                 ieee80211_ready_on_channel(mvm->hw); /* Start TE */
853         }
854
855  out_unlock:
856         rcu_read_unlock();
857 }
858
859 static int
860 iwl_mvm_start_p2p_roc_session_protection(struct iwl_mvm *mvm,
861                                          struct ieee80211_vif *vif,
862                                          int duration,
863                                          enum ieee80211_roc_type type)
864 {
865         struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
866         struct iwl_mvm_session_prot_cmd cmd = {
867                 .id_and_color =
868                         cpu_to_le32(FW_CMD_ID_AND_COLOR(mvmvif->id,
869                                                         mvmvif->color)),
870                 .action = cpu_to_le32(FW_CTXT_ACTION_ADD),
871                 .duration_tu = cpu_to_le32(MSEC_TO_TU(duration)),
872         };
873
874         lockdep_assert_held(&mvm->mutex);
875
876         /* The time_event_data.id field is reused to save session
877          * protection's configuration.
878          */
879         switch (type) {
880         case IEEE80211_ROC_TYPE_NORMAL:
881                 mvmvif->time_event_data.id =
882                         SESSION_PROTECT_CONF_P2P_DEVICE_DISCOV;
883                 break;
884         case IEEE80211_ROC_TYPE_MGMT_TX:
885                 mvmvif->time_event_data.id =
886                         SESSION_PROTECT_CONF_P2P_GO_NEGOTIATION;
887                 break;
888         default:
889                 WARN_ONCE(1, "Got an invalid ROC type\n");
890                 return -EINVAL;
891         }
892
893         cmd.conf_id = cpu_to_le32(mvmvif->time_event_data.id);
894         return iwl_mvm_send_cmd_pdu(mvm, iwl_cmd_id(SESSION_PROTECTION_CMD,
895                                                     MAC_CONF_GROUP, 0),
896                                     0, sizeof(cmd), &cmd);
897 }
898
899 int iwl_mvm_start_p2p_roc(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
900                           int duration, enum ieee80211_roc_type type)
901 {
902         struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
903         struct iwl_mvm_time_event_data *te_data = &mvmvif->time_event_data;
904         struct iwl_time_event_cmd time_cmd = {};
905
906         lockdep_assert_held(&mvm->mutex);
907         if (te_data->running) {
908                 IWL_WARN(mvm, "P2P_DEVICE remain on channel already running\n");
909                 return -EBUSY;
910         }
911
912         if (fw_has_capa(&mvm->fw->ucode_capa,
913                         IWL_UCODE_TLV_CAPA_SESSION_PROT_CMD))
914                 return iwl_mvm_start_p2p_roc_session_protection(mvm, vif,
915                                                                 duration,
916                                                                 type);
917
918         time_cmd.action = cpu_to_le32(FW_CTXT_ACTION_ADD);
919         time_cmd.id_and_color =
920                 cpu_to_le32(FW_CMD_ID_AND_COLOR(mvmvif->id, mvmvif->color));
921
922         switch (type) {
923         case IEEE80211_ROC_TYPE_NORMAL:
924                 time_cmd.id = cpu_to_le32(IWL_MVM_ROC_TE_TYPE_NORMAL);
925                 break;
926         case IEEE80211_ROC_TYPE_MGMT_TX:
927                 time_cmd.id = cpu_to_le32(IWL_MVM_ROC_TE_TYPE_MGMT_TX);
928                 break;
929         default:
930                 WARN_ONCE(1, "Got an invalid ROC type\n");
931                 return -EINVAL;
932         }
933
934         time_cmd.apply_time = cpu_to_le32(0);
935         time_cmd.interval = cpu_to_le32(1);
936
937         /*
938          * The P2P Device TEs can have lower priority than other events
939          * that are being scheduled by the driver/fw, and thus it might not be
940          * scheduled. To improve the chances of it being scheduled, allow them
941          * to be fragmented, and in addition allow them to be delayed.
942          */
943         time_cmd.max_frags = min(MSEC_TO_TU(duration)/50, TE_V2_FRAG_ENDLESS);
944         time_cmd.max_delay = cpu_to_le32(MSEC_TO_TU(duration/2));
945         time_cmd.duration = cpu_to_le32(MSEC_TO_TU(duration));
946         time_cmd.repeat = 1;
947         time_cmd.policy = cpu_to_le16(TE_V2_NOTIF_HOST_EVENT_START |
948                                       TE_V2_NOTIF_HOST_EVENT_END |
949                                       TE_V2_START_IMMEDIATELY);
950
951         return iwl_mvm_time_event_send_add(mvm, vif, te_data, &time_cmd);
952 }
953
954 static struct iwl_mvm_time_event_data *iwl_mvm_get_roc_te(struct iwl_mvm *mvm)
955 {
956         struct iwl_mvm_time_event_data *te_data;
957
958         lockdep_assert_held(&mvm->mutex);
959
960         spin_lock_bh(&mvm->time_event_lock);
961
962         /*
963          * Iterate over the list of time events and find the time event that is
964          * associated with a P2P_DEVICE interface.
965          * This assumes that a P2P_DEVICE interface can have only a single time
966          * event at any given time and this time event coresponds to a ROC
967          * request
968          */
969         list_for_each_entry(te_data, &mvm->time_event_list, list) {
970                 if (te_data->vif->type == NL80211_IFTYPE_P2P_DEVICE)
971                         goto out;
972         }
973
974         /* There can only be at most one AUX ROC time event, we just use the
975          * list to simplify/unify code. Remove it if it exists.
976          */
977         te_data = list_first_entry_or_null(&mvm->aux_roc_te_list,
978                                            struct iwl_mvm_time_event_data,
979                                            list);
980 out:
981         spin_unlock_bh(&mvm->time_event_lock);
982         return te_data;
983 }
984
985 void iwl_mvm_cleanup_roc_te(struct iwl_mvm *mvm)
986 {
987         struct iwl_mvm_time_event_data *te_data;
988         u32 uid;
989
990         te_data = iwl_mvm_get_roc_te(mvm);
991         if (te_data)
992                 __iwl_mvm_remove_time_event(mvm, te_data, &uid);
993 }
994
995 void iwl_mvm_stop_roc(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
996 {
997         struct iwl_mvm_vif *mvmvif;
998         struct iwl_mvm_time_event_data *te_data;
999
1000         if (fw_has_capa(&mvm->fw->ucode_capa,
1001                         IWL_UCODE_TLV_CAPA_SESSION_PROT_CMD)) {
1002                 mvmvif = iwl_mvm_vif_from_mac80211(vif);
1003
1004                 if (vif->type == NL80211_IFTYPE_P2P_DEVICE) {
1005                         iwl_mvm_cancel_session_protection(mvm, mvmvif,
1006                                                           mvmvif->time_event_data.id);
1007                         set_bit(IWL_MVM_STATUS_NEED_FLUSH_P2P, &mvm->status);
1008                 } else {
1009                         iwl_mvm_remove_aux_roc_te(mvm, mvmvif,
1010                                                   &mvmvif->time_event_data);
1011                 }
1012
1013                 iwl_mvm_roc_finished(mvm);
1014
1015                 return;
1016         }
1017
1018         te_data = iwl_mvm_get_roc_te(mvm);
1019         if (!te_data) {
1020                 IWL_WARN(mvm, "No remain on channel event\n");
1021                 return;
1022         }
1023
1024         mvmvif = iwl_mvm_vif_from_mac80211(te_data->vif);
1025
1026         if (te_data->vif->type == NL80211_IFTYPE_P2P_DEVICE) {
1027                 iwl_mvm_remove_time_event(mvm, mvmvif, te_data);
1028                 set_bit(IWL_MVM_STATUS_NEED_FLUSH_P2P, &mvm->status);
1029         } else {
1030                 iwl_mvm_remove_aux_roc_te(mvm, mvmvif, te_data);
1031         }
1032
1033         iwl_mvm_roc_finished(mvm);
1034 }
1035
1036 void iwl_mvm_remove_csa_period(struct iwl_mvm *mvm,
1037                                struct ieee80211_vif *vif)
1038 {
1039         struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
1040         struct iwl_mvm_time_event_data *te_data = &mvmvif->time_event_data;
1041         u32 id;
1042
1043         lockdep_assert_held(&mvm->mutex);
1044
1045         spin_lock_bh(&mvm->time_event_lock);
1046         id = te_data->id;
1047         spin_unlock_bh(&mvm->time_event_lock);
1048
1049         if (id != TE_CHANNEL_SWITCH_PERIOD)
1050                 return;
1051
1052         iwl_mvm_remove_time_event(mvm, mvmvif, te_data);
1053 }
1054
1055 int iwl_mvm_schedule_csa_period(struct iwl_mvm *mvm,
1056                                 struct ieee80211_vif *vif,
1057                                 u32 duration, u32 apply_time)
1058 {
1059         struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
1060         struct iwl_mvm_time_event_data *te_data = &mvmvif->time_event_data;
1061         struct iwl_time_event_cmd time_cmd = {};
1062
1063         lockdep_assert_held(&mvm->mutex);
1064
1065         if (te_data->running) {
1066                 u32 id;
1067
1068                 spin_lock_bh(&mvm->time_event_lock);
1069                 id = te_data->id;
1070                 spin_unlock_bh(&mvm->time_event_lock);
1071
1072                 if (id == TE_CHANNEL_SWITCH_PERIOD) {
1073                         IWL_DEBUG_TE(mvm, "CS period is already scheduled\n");
1074                         return -EBUSY;
1075                 }
1076
1077                 /*
1078                  * Remove the session protection time event to allow the
1079                  * channel switch. If we got here, we just heard a beacon so
1080                  * the session protection is not needed anymore anyway.
1081                  */
1082                 iwl_mvm_remove_time_event(mvm, mvmvif, te_data);
1083         }
1084
1085         time_cmd.action = cpu_to_le32(FW_CTXT_ACTION_ADD);
1086         time_cmd.id_and_color =
1087                 cpu_to_le32(FW_CMD_ID_AND_COLOR(mvmvif->id, mvmvif->color));
1088         time_cmd.id = cpu_to_le32(TE_CHANNEL_SWITCH_PERIOD);
1089         time_cmd.apply_time = cpu_to_le32(apply_time);
1090         time_cmd.max_frags = TE_V2_FRAG_NONE;
1091         time_cmd.duration = cpu_to_le32(duration);
1092         time_cmd.repeat = 1;
1093         time_cmd.interval = cpu_to_le32(1);
1094         time_cmd.policy = cpu_to_le16(TE_V2_NOTIF_HOST_EVENT_START |
1095                                       TE_V2_ABSENCE);
1096         if (!apply_time)
1097                 time_cmd.policy |= cpu_to_le16(TE_V2_START_IMMEDIATELY);
1098
1099         return iwl_mvm_time_event_send_add(mvm, vif, te_data, &time_cmd);
1100 }
1101
1102 static bool iwl_mvm_session_prot_notif(struct iwl_notif_wait_data *notif_wait,
1103                                        struct iwl_rx_packet *pkt, void *data)
1104 {
1105         struct iwl_mvm *mvm =
1106                 container_of(notif_wait, struct iwl_mvm, notif_wait);
1107         struct iwl_mvm_session_prot_notif *resp;
1108         int resp_len = iwl_rx_packet_payload_len(pkt);
1109
1110         if (WARN_ON(pkt->hdr.cmd != SESSION_PROTECTION_NOTIF ||
1111                     pkt->hdr.group_id != MAC_CONF_GROUP))
1112                 return true;
1113
1114         if (WARN_ON_ONCE(resp_len != sizeof(*resp))) {
1115                 IWL_ERR(mvm, "Invalid SESSION_PROTECTION_NOTIF response\n");
1116                 return true;
1117         }
1118
1119         resp = (void *)pkt->data;
1120
1121         if (!resp->status)
1122                 IWL_ERR(mvm,
1123                         "TIME_EVENT_NOTIFICATION received but not executed\n");
1124
1125         return true;
1126 }
1127
1128 void iwl_mvm_schedule_session_protection(struct iwl_mvm *mvm,
1129                                          struct ieee80211_vif *vif,
1130                                          u32 duration, u32 min_duration,
1131                                          bool wait_for_notif)
1132 {
1133         struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
1134         struct iwl_mvm_time_event_data *te_data = &mvmvif->time_event_data;
1135         const u16 notif[] = { iwl_cmd_id(SESSION_PROTECTION_NOTIF,
1136                                          MAC_CONF_GROUP, 0) };
1137         struct iwl_notification_wait wait_notif;
1138         struct iwl_mvm_session_prot_cmd cmd = {
1139                 .id_and_color =
1140                         cpu_to_le32(FW_CMD_ID_AND_COLOR(mvmvif->id,
1141                                                         mvmvif->color)),
1142                 .action = cpu_to_le32(FW_CTXT_ACTION_ADD),
1143                 .duration_tu = cpu_to_le32(MSEC_TO_TU(duration)),
1144         };
1145
1146         /* The time_event_data.id field is reused to save session
1147          * protection's configuration.
1148          */
1149         mvmvif->time_event_data.id = SESSION_PROTECT_CONF_ASSOC;
1150         cmd.conf_id = cpu_to_le32(mvmvif->time_event_data.id);
1151
1152         lockdep_assert_held(&mvm->mutex);
1153
1154         spin_lock_bh(&mvm->time_event_lock);
1155         if (te_data->running &&
1156             time_after(te_data->end_jiffies, TU_TO_EXP_TIME(min_duration))) {
1157                 IWL_DEBUG_TE(mvm, "We have enough time in the current TE: %u\n",
1158                              jiffies_to_msecs(te_data->end_jiffies - jiffies));
1159                 spin_unlock_bh(&mvm->time_event_lock);
1160
1161                 return;
1162         }
1163
1164         iwl_mvm_te_clear_data(mvm, te_data);
1165         te_data->duration = le32_to_cpu(cmd.duration_tu);
1166         te_data->vif = vif;
1167         spin_unlock_bh(&mvm->time_event_lock);
1168
1169         IWL_DEBUG_TE(mvm, "Add new session protection, duration %d TU\n",
1170                      le32_to_cpu(cmd.duration_tu));
1171
1172         if (!wait_for_notif) {
1173                 if (iwl_mvm_send_cmd_pdu(mvm,
1174                                          iwl_cmd_id(SESSION_PROTECTION_CMD,
1175                                                     MAC_CONF_GROUP, 0),
1176                                          0, sizeof(cmd), &cmd)) {
1177                         IWL_ERR(mvm,
1178                                 "Couldn't send the SESSION_PROTECTION_CMD\n");
1179                         spin_lock_bh(&mvm->time_event_lock);
1180                         iwl_mvm_te_clear_data(mvm, te_data);
1181                         spin_unlock_bh(&mvm->time_event_lock);
1182                 }
1183
1184                 return;
1185         }
1186
1187         iwl_init_notification_wait(&mvm->notif_wait, &wait_notif,
1188                                    notif, ARRAY_SIZE(notif),
1189                                    iwl_mvm_session_prot_notif, NULL);
1190
1191         if (iwl_mvm_send_cmd_pdu(mvm,
1192                                  iwl_cmd_id(SESSION_PROTECTION_CMD,
1193                                             MAC_CONF_GROUP, 0),
1194                                  0, sizeof(cmd), &cmd)) {
1195                 IWL_ERR(mvm,
1196                         "Couldn't send the SESSION_PROTECTION_CMD\n");
1197                 iwl_remove_notification(&mvm->notif_wait, &wait_notif);
1198         } else if (iwl_wait_notification(&mvm->notif_wait, &wait_notif,
1199                                          TU_TO_JIFFIES(100))) {
1200                 IWL_ERR(mvm,
1201                         "Failed to protect session until session protection\n");
1202         }
1203 }