Merge branch 'for-3.19' of git://git.kernel.org/pub/scm/linux/kernel/git/tj/cgroup
[cascardo/linux.git] / drivers / net / wireless / iwlwifi / mvm / time-event.c
1 /******************************************************************************
2  *
3  * This file is provided under a dual BSD/GPLv2 license.  When using or
4  * redistributing this file, you may do so under either license.
5  *
6  * GPL LICENSE SUMMARY
7  *
8  * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
9  * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
10  *
11  * This program is free software; you can redistribute it and/or modify
12  * it under the terms of version 2 of the GNU General Public License as
13  * published by the Free Software Foundation.
14  *
15  * This program is distributed in the hope that it will be useful, but
16  * WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18  * General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, write to the Free Software
22  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110,
23  * USA
24  *
25  * The full GNU General Public License is included in this distribution
26  * in the file called COPYING.
27  *
28  * Contact Information:
29  *  Intel Linux Wireless <ilw@linux.intel.com>
30  * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
31  *
32  * BSD LICENSE
33  *
34  * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
35  * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
36  * All rights reserved.
37  *
38  * Redistribution and use in source and binary forms, with or without
39  * modification, are permitted provided that the following conditions
40  * are met:
41  *
42  *  * Redistributions of source code must retain the above copyright
43  *    notice, this list of conditions and the following disclaimer.
44  *  * Redistributions in binary form must reproduce the above copyright
45  *    notice, this list of conditions and the following disclaimer in
46  *    the documentation and/or other materials provided with the
47  *    distribution.
48  *  * Neither the name Intel Corporation nor the names of its
49  *    contributors may be used to endorse or promote products derived
50  *    from this software without specific prior written permission.
51  *
52  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
53  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
54  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
55  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
56  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
57  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
58  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
59  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
60  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
61  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
62  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
63  *
64  *****************************************************************************/
65
66 #include <linux/jiffies.h>
67 #include <net/mac80211.h>
68
69 #include "iwl-notif-wait.h"
70 #include "iwl-trans.h"
71 #include "fw-api.h"
72 #include "time-event.h"
73 #include "mvm.h"
74 #include "iwl-io.h"
75 #include "iwl-prph.h"
76
77 /*
78  * For the high priority TE use a time event type that has similar priority to
79  * the FW's action scan priority.
80  */
81 #define IWL_MVM_ROC_TE_TYPE_NORMAL TE_P2P_DEVICE_DISCOVERABLE
82 #define IWL_MVM_ROC_TE_TYPE_MGMT_TX TE_P2P_CLIENT_ASSOC
83
84 void iwl_mvm_te_clear_data(struct iwl_mvm *mvm,
85                            struct iwl_mvm_time_event_data *te_data)
86 {
87         lockdep_assert_held(&mvm->time_event_lock);
88
89         if (te_data->id == TE_MAX)
90                 return;
91
92         list_del(&te_data->list);
93         te_data->running = false;
94         te_data->uid = 0;
95         te_data->id = TE_MAX;
96         te_data->vif = NULL;
97 }
98
99 void iwl_mvm_roc_done_wk(struct work_struct *wk)
100 {
101         struct iwl_mvm *mvm = container_of(wk, struct iwl_mvm, roc_done_wk);
102         u32 queues = 0;
103
104         /*
105          * Clear the ROC_RUNNING /ROC_AUX_RUNNING status bit.
106          * This will cause the TX path to drop offchannel transmissions.
107          * That would also be done by mac80211, but it is racy, in particular
108          * in the case that the time event actually completed in the firmware
109          * (which is handled in iwl_mvm_te_handle_notif).
110          */
111         if (test_and_clear_bit(IWL_MVM_STATUS_ROC_RUNNING, &mvm->status))
112                 queues |= BIT(IWL_MVM_OFFCHANNEL_QUEUE);
113         if (test_and_clear_bit(IWL_MVM_STATUS_ROC_AUX_RUNNING, &mvm->status))
114                 queues |= BIT(mvm->aux_queue);
115
116         iwl_mvm_unref(mvm, IWL_MVM_REF_ROC);
117
118         synchronize_net();
119
120         /*
121          * Flush the offchannel queue -- this is called when the time
122          * event finishes or is cancelled, so that frames queued for it
123          * won't get stuck on the queue and be transmitted in the next
124          * time event.
125          * We have to send the command asynchronously since this cannot
126          * be under the mutex for locking reasons, but that's not an
127          * issue as it will have to complete before the next command is
128          * executed, and a new time event means a new command.
129          */
130         iwl_mvm_flush_tx_path(mvm, queues, false);
131 }
132
133 static void iwl_mvm_roc_finished(struct iwl_mvm *mvm)
134 {
135         /*
136          * Of course, our status bit is just as racy as mac80211, so in
137          * addition, fire off the work struct which will drop all frames
138          * from the hardware queues that made it through the race. First
139          * it will of course synchronize the TX path to make sure that
140          * any *new* TX will be rejected.
141          */
142         schedule_work(&mvm->roc_done_wk);
143 }
144
145 static void iwl_mvm_csa_noa_start(struct iwl_mvm *mvm)
146 {
147         struct ieee80211_vif *csa_vif;
148
149         rcu_read_lock();
150
151         csa_vif = rcu_dereference(mvm->csa_vif);
152         if (!csa_vif || !csa_vif->csa_active)
153                 goto out_unlock;
154
155         IWL_DEBUG_TE(mvm, "CSA NOA started\n");
156
157         /*
158          * CSA NoA is started but we still have beacons to
159          * transmit on the current channel.
160          * So we just do nothing here and the switch
161          * will be performed on the last TBTT.
162          */
163         if (!ieee80211_csa_is_complete(csa_vif)) {
164                 IWL_WARN(mvm, "CSA NOA started too early\n");
165                 goto out_unlock;
166         }
167
168         ieee80211_csa_finish(csa_vif);
169
170         rcu_read_unlock();
171
172         RCU_INIT_POINTER(mvm->csa_vif, NULL);
173
174         return;
175
176 out_unlock:
177         rcu_read_unlock();
178 }
179
180 static bool iwl_mvm_te_check_disconnect(struct iwl_mvm *mvm,
181                                         struct ieee80211_vif *vif,
182                                         const char *errmsg)
183 {
184         if (vif->type != NL80211_IFTYPE_STATION)
185                 return false;
186         if (vif->bss_conf.assoc && vif->bss_conf.dtim_period)
187                 return false;
188         if (errmsg)
189                 IWL_ERR(mvm, "%s\n", errmsg);
190         ieee80211_connection_loss(vif);
191         return true;
192 }
193
194 static void
195 iwl_mvm_te_handle_notify_csa(struct iwl_mvm *mvm,
196                              struct iwl_mvm_time_event_data *te_data,
197                              struct iwl_time_event_notif *notif)
198 {
199         if (!le32_to_cpu(notif->status)) {
200                 IWL_DEBUG_TE(mvm, "CSA time event failed to start\n");
201                 iwl_mvm_te_clear_data(mvm, te_data);
202                 return;
203         }
204
205         switch (te_data->vif->type) {
206         case NL80211_IFTYPE_AP:
207                 iwl_mvm_csa_noa_start(mvm);
208                 break;
209         case NL80211_IFTYPE_STATION:
210                 iwl_mvm_csa_client_absent(mvm, te_data->vif);
211                 ieee80211_chswitch_done(te_data->vif, true);
212                 break;
213         default:
214                 /* should never happen */
215                 WARN_ON_ONCE(1);
216                 break;
217         }
218
219         /* we don't need it anymore */
220         iwl_mvm_te_clear_data(mvm, te_data);
221 }
222
223 /*
224  * Handles a FW notification for an event that is known to the driver.
225  *
226  * @mvm: the mvm component
227  * @te_data: the time event data
228  * @notif: the notification data corresponding the time event data.
229  */
230 static void iwl_mvm_te_handle_notif(struct iwl_mvm *mvm,
231                                     struct iwl_mvm_time_event_data *te_data,
232                                     struct iwl_time_event_notif *notif)
233 {
234         lockdep_assert_held(&mvm->time_event_lock);
235
236         IWL_DEBUG_TE(mvm, "Handle time event notif - UID = 0x%x action %d\n",
237                      le32_to_cpu(notif->unique_id),
238                      le32_to_cpu(notif->action));
239
240         /*
241          * The FW sends the start/end time event notifications even for events
242          * that it fails to schedule. This is indicated in the status field of
243          * the notification. This happens in cases that the scheduler cannot
244          * find a schedule that can handle the event (for example requesting a
245          * P2P Device discoveribility, while there are other higher priority
246          * events in the system).
247          */
248         if (!le32_to_cpu(notif->status)) {
249                 bool start = le32_to_cpu(notif->action) &
250                                 TE_V2_NOTIF_HOST_EVENT_START;
251                 IWL_WARN(mvm, "Time Event %s notification failure\n",
252                          start ? "start" : "end");
253                 if (iwl_mvm_te_check_disconnect(mvm, te_data->vif, NULL)) {
254                         iwl_mvm_te_clear_data(mvm, te_data);
255                         return;
256                 }
257         }
258
259         if (le32_to_cpu(notif->action) & TE_V2_NOTIF_HOST_EVENT_END) {
260                 IWL_DEBUG_TE(mvm,
261                              "TE ended - current time %lu, estimated end %lu\n",
262                              jiffies, te_data->end_jiffies);
263
264                 if (te_data->vif->type == NL80211_IFTYPE_P2P_DEVICE) {
265                         ieee80211_remain_on_channel_expired(mvm->hw);
266                         iwl_mvm_roc_finished(mvm);
267                 }
268
269                 /*
270                  * By now, we should have finished association
271                  * and know the dtim period.
272                  */
273                 iwl_mvm_te_check_disconnect(mvm, te_data->vif,
274                         "No association and the time event is over already...");
275                 iwl_mvm_te_clear_data(mvm, te_data);
276         } else if (le32_to_cpu(notif->action) & TE_V2_NOTIF_HOST_EVENT_START) {
277                 te_data->running = true;
278                 te_data->end_jiffies = TU_TO_EXP_TIME(te_data->duration);
279
280                 if (te_data->vif->type == NL80211_IFTYPE_P2P_DEVICE) {
281                         set_bit(IWL_MVM_STATUS_ROC_RUNNING, &mvm->status);
282                         iwl_mvm_ref(mvm, IWL_MVM_REF_ROC);
283                         ieee80211_ready_on_channel(mvm->hw);
284                 } else if (te_data->id == TE_CHANNEL_SWITCH_PERIOD) {
285                         iwl_mvm_te_handle_notify_csa(mvm, te_data, notif);
286                 }
287         } else {
288                 IWL_WARN(mvm, "Got TE with unknown action\n");
289         }
290 }
291
292 /*
293  * Handle A Aux ROC time event
294  */
295 static int iwl_mvm_aux_roc_te_handle_notif(struct iwl_mvm *mvm,
296                                            struct iwl_time_event_notif *notif)
297 {
298         struct iwl_mvm_time_event_data *te_data, *tmp;
299         bool aux_roc_te = false;
300
301         list_for_each_entry_safe(te_data, tmp, &mvm->aux_roc_te_list, list) {
302                 if (le32_to_cpu(notif->unique_id) == te_data->uid) {
303                         aux_roc_te = true;
304                         break;
305                 }
306         }
307         if (!aux_roc_te) /* Not a Aux ROC time event */
308                 return -EINVAL;
309
310         if (!le32_to_cpu(notif->status)) {
311                 IWL_DEBUG_TE(mvm,
312                              "ERROR: Aux ROC Time Event %s notification failure\n",
313                              (le32_to_cpu(notif->action) &
314                               TE_V2_NOTIF_HOST_EVENT_START) ? "start" : "end");
315                 return -EINVAL;
316         }
317
318         IWL_DEBUG_TE(mvm,
319                      "Aux ROC time event notification  - UID = 0x%x action %d\n",
320                      le32_to_cpu(notif->unique_id),
321                      le32_to_cpu(notif->action));
322
323         if (le32_to_cpu(notif->action) == TE_V2_NOTIF_HOST_EVENT_END) {
324                 /* End TE, notify mac80211 */
325                 ieee80211_remain_on_channel_expired(mvm->hw);
326                 iwl_mvm_roc_finished(mvm); /* flush aux queue */
327                 list_del(&te_data->list); /* remove from list */
328                 te_data->running = false;
329                 te_data->vif = NULL;
330                 te_data->uid = 0;
331                 te_data->id = TE_MAX;
332         } else if (le32_to_cpu(notif->action) == TE_V2_NOTIF_HOST_EVENT_START) {
333                 set_bit(IWL_MVM_STATUS_ROC_AUX_RUNNING, &mvm->status);
334                 te_data->running = true;
335                 ieee80211_ready_on_channel(mvm->hw); /* Start TE */
336         } else {
337                 IWL_DEBUG_TE(mvm,
338                              "ERROR: Unknown Aux ROC Time Event (action = %d)\n",
339                              le32_to_cpu(notif->action));
340                 return -EINVAL;
341         }
342
343         return 0;
344 }
345
346 /*
347  * The Rx handler for time event notifications
348  */
349 int iwl_mvm_rx_time_event_notif(struct iwl_mvm *mvm,
350                                 struct iwl_rx_cmd_buffer *rxb,
351                                 struct iwl_device_cmd *cmd)
352 {
353         struct iwl_rx_packet *pkt = rxb_addr(rxb);
354         struct iwl_time_event_notif *notif = (void *)pkt->data;
355         struct iwl_mvm_time_event_data *te_data, *tmp;
356
357         IWL_DEBUG_TE(mvm, "Time event notification - UID = 0x%x action %d\n",
358                      le32_to_cpu(notif->unique_id),
359                      le32_to_cpu(notif->action));
360
361         spin_lock_bh(&mvm->time_event_lock);
362         /* This time event is triggered for Aux ROC request */
363         if (!iwl_mvm_aux_roc_te_handle_notif(mvm, notif))
364                 goto unlock;
365
366         list_for_each_entry_safe(te_data, tmp, &mvm->time_event_list, list) {
367                 if (le32_to_cpu(notif->unique_id) == te_data->uid)
368                         iwl_mvm_te_handle_notif(mvm, te_data, notif);
369         }
370 unlock:
371         spin_unlock_bh(&mvm->time_event_lock);
372
373         return 0;
374 }
375
376 static bool iwl_mvm_te_notif(struct iwl_notif_wait_data *notif_wait,
377                              struct iwl_rx_packet *pkt, void *data)
378 {
379         struct iwl_mvm *mvm =
380                 container_of(notif_wait, struct iwl_mvm, notif_wait);
381         struct iwl_mvm_time_event_data *te_data = data;
382         struct iwl_time_event_notif *resp;
383         int resp_len = iwl_rx_packet_payload_len(pkt);
384
385         if (WARN_ON(pkt->hdr.cmd != TIME_EVENT_NOTIFICATION))
386                 return true;
387
388         if (WARN_ON_ONCE(resp_len != sizeof(*resp))) {
389                 IWL_ERR(mvm, "Invalid TIME_EVENT_NOTIFICATION response\n");
390                 return true;
391         }
392
393         resp = (void *)pkt->data;
394
395         /* te_data->uid is already set in the TIME_EVENT_CMD response */
396         if (le32_to_cpu(resp->unique_id) != te_data->uid)
397                 return false;
398
399         IWL_DEBUG_TE(mvm, "TIME_EVENT_NOTIFICATION response - UID = 0x%x\n",
400                      te_data->uid);
401         if (!resp->status)
402                 IWL_ERR(mvm,
403                         "TIME_EVENT_NOTIFICATION received but not executed\n");
404
405         return true;
406 }
407
408 static bool iwl_mvm_time_event_response(struct iwl_notif_wait_data *notif_wait,
409                                         struct iwl_rx_packet *pkt, void *data)
410 {
411         struct iwl_mvm *mvm =
412                 container_of(notif_wait, struct iwl_mvm, notif_wait);
413         struct iwl_mvm_time_event_data *te_data = data;
414         struct iwl_time_event_resp *resp;
415         int resp_len = iwl_rx_packet_payload_len(pkt);
416
417         if (WARN_ON(pkt->hdr.cmd != TIME_EVENT_CMD))
418                 return true;
419
420         if (WARN_ON_ONCE(resp_len != sizeof(*resp))) {
421                 IWL_ERR(mvm, "Invalid TIME_EVENT_CMD response\n");
422                 return true;
423         }
424
425         resp = (void *)pkt->data;
426
427         /* we should never get a response to another TIME_EVENT_CMD here */
428         if (WARN_ON_ONCE(le32_to_cpu(resp->id) != te_data->id))
429                 return false;
430
431         te_data->uid = le32_to_cpu(resp->unique_id);
432         IWL_DEBUG_TE(mvm, "TIME_EVENT_CMD response - UID = 0x%x\n",
433                      te_data->uid);
434         return true;
435 }
436
437 static int iwl_mvm_time_event_send_add(struct iwl_mvm *mvm,
438                                        struct ieee80211_vif *vif,
439                                        struct iwl_mvm_time_event_data *te_data,
440                                        struct iwl_time_event_cmd *te_cmd)
441 {
442         static const u8 time_event_response[] = { TIME_EVENT_CMD };
443         struct iwl_notification_wait wait_time_event;
444         int ret;
445
446         lockdep_assert_held(&mvm->mutex);
447
448         IWL_DEBUG_TE(mvm, "Add new TE, duration %d TU\n",
449                      le32_to_cpu(te_cmd->duration));
450
451         spin_lock_bh(&mvm->time_event_lock);
452         if (WARN_ON(te_data->id != TE_MAX)) {
453                 spin_unlock_bh(&mvm->time_event_lock);
454                 return -EIO;
455         }
456         te_data->vif = vif;
457         te_data->duration = le32_to_cpu(te_cmd->duration);
458         te_data->id = le32_to_cpu(te_cmd->id);
459         list_add_tail(&te_data->list, &mvm->time_event_list);
460         spin_unlock_bh(&mvm->time_event_lock);
461
462         /*
463          * Use a notification wait, which really just processes the
464          * command response and doesn't wait for anything, in order
465          * to be able to process the response and get the UID inside
466          * the RX path. Using CMD_WANT_SKB doesn't work because it
467          * stores the buffer and then wakes up this thread, by which
468          * time another notification (that the time event started)
469          * might already be processed unsuccessfully.
470          */
471         iwl_init_notification_wait(&mvm->notif_wait, &wait_time_event,
472                                    time_event_response,
473                                    ARRAY_SIZE(time_event_response),
474                                    iwl_mvm_time_event_response, te_data);
475
476         ret = iwl_mvm_send_cmd_pdu(mvm, TIME_EVENT_CMD, 0,
477                                             sizeof(*te_cmd), te_cmd);
478         if (ret) {
479                 IWL_ERR(mvm, "Couldn't send TIME_EVENT_CMD: %d\n", ret);
480                 iwl_remove_notification(&mvm->notif_wait, &wait_time_event);
481                 goto out_clear_te;
482         }
483
484         /* No need to wait for anything, so just pass 1 (0 isn't valid) */
485         ret = iwl_wait_notification(&mvm->notif_wait, &wait_time_event, 1);
486         /* should never fail */
487         WARN_ON_ONCE(ret);
488
489         if (ret) {
490  out_clear_te:
491                 spin_lock_bh(&mvm->time_event_lock);
492                 iwl_mvm_te_clear_data(mvm, te_data);
493                 spin_unlock_bh(&mvm->time_event_lock);
494         }
495         return ret;
496 }
497
498 void iwl_mvm_protect_session(struct iwl_mvm *mvm,
499                              struct ieee80211_vif *vif,
500                              u32 duration, u32 min_duration,
501                              u32 max_delay, bool wait_for_notif)
502 {
503         struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
504         struct iwl_mvm_time_event_data *te_data = &mvmvif->time_event_data;
505         const u8 te_notif_response[] = { TIME_EVENT_NOTIFICATION };
506         struct iwl_notification_wait wait_te_notif;
507         struct iwl_time_event_cmd time_cmd = {};
508
509         lockdep_assert_held(&mvm->mutex);
510
511         if (te_data->running &&
512             time_after(te_data->end_jiffies, TU_TO_EXP_TIME(min_duration))) {
513                 IWL_DEBUG_TE(mvm, "We have enough time in the current TE: %u\n",
514                              jiffies_to_msecs(te_data->end_jiffies - jiffies));
515                 return;
516         }
517
518         if (te_data->running) {
519                 IWL_DEBUG_TE(mvm, "extend 0x%x: only %u ms left\n",
520                              te_data->uid,
521                              jiffies_to_msecs(te_data->end_jiffies - jiffies));
522                 /*
523                  * we don't have enough time
524                  * cancel the current TE and issue a new one
525                  * Of course it would be better to remove the old one only
526                  * when the new one is added, but we don't care if we are off
527                  * channel for a bit. All we need to do, is not to return
528                  * before we actually begin to be on the channel.
529                  */
530                 iwl_mvm_stop_session_protection(mvm, vif);
531         }
532
533         time_cmd.action = cpu_to_le32(FW_CTXT_ACTION_ADD);
534         time_cmd.id_and_color =
535                 cpu_to_le32(FW_CMD_ID_AND_COLOR(mvmvif->id, mvmvif->color));
536         time_cmd.id = cpu_to_le32(TE_BSS_STA_AGGRESSIVE_ASSOC);
537
538         time_cmd.apply_time =
539                 cpu_to_le32(iwl_read_prph(mvm->trans, DEVICE_SYSTEM_TIME_REG));
540
541         time_cmd.max_frags = TE_V2_FRAG_NONE;
542         time_cmd.max_delay = cpu_to_le32(max_delay);
543         /* TODO: why do we need to interval = bi if it is not periodic? */
544         time_cmd.interval = cpu_to_le32(1);
545         time_cmd.duration = cpu_to_le32(duration);
546         time_cmd.repeat = 1;
547         time_cmd.policy = cpu_to_le16(TE_V2_NOTIF_HOST_EVENT_START |
548                                       TE_V2_NOTIF_HOST_EVENT_END |
549                                       T2_V2_START_IMMEDIATELY);
550
551         if (!wait_for_notif) {
552                 iwl_mvm_time_event_send_add(mvm, vif, te_data, &time_cmd);
553                 return;
554         }
555
556         /*
557          * Create notification_wait for the TIME_EVENT_NOTIFICATION to use
558          * right after we send the time event
559          */
560         iwl_init_notification_wait(&mvm->notif_wait, &wait_te_notif,
561                                    te_notif_response,
562                                    ARRAY_SIZE(te_notif_response),
563                                    iwl_mvm_te_notif, te_data);
564
565         /* If TE was sent OK - wait for the notification that started */
566         if (iwl_mvm_time_event_send_add(mvm, vif, te_data, &time_cmd)) {
567                 IWL_ERR(mvm, "Failed to add TE to protect session\n");
568                 iwl_remove_notification(&mvm->notif_wait, &wait_te_notif);
569         } else if (iwl_wait_notification(&mvm->notif_wait, &wait_te_notif,
570                                          TU_TO_JIFFIES(max_delay))) {
571                 IWL_ERR(mvm, "Failed to protect session until TE\n");
572         }
573 }
574
575 static bool __iwl_mvm_remove_time_event(struct iwl_mvm *mvm,
576                                         struct iwl_mvm_time_event_data *te_data,
577                                         u32 *uid)
578 {
579         u32 id;
580
581         /*
582          * It is possible that by the time we got to this point the time
583          * event was already removed.
584          */
585         spin_lock_bh(&mvm->time_event_lock);
586
587         /* Save time event uid before clearing its data */
588         *uid = te_data->uid;
589         id = te_data->id;
590
591         /*
592          * The clear_data function handles time events that were already removed
593          */
594         iwl_mvm_te_clear_data(mvm, te_data);
595         spin_unlock_bh(&mvm->time_event_lock);
596
597         /*
598          * It is possible that by the time we try to remove it, the time event
599          * has already ended and removed. In such a case there is no need to
600          * send a removal command.
601          */
602         if (id == TE_MAX) {
603                 IWL_DEBUG_TE(mvm, "TE 0x%x has already ended\n", *uid);
604                 return false;
605         }
606
607         return true;
608 }
609
610 /*
611  * Explicit request to remove a aux roc time event. The removal of a time
612  * event needs to be synchronized with the flow of a time event's end
613  * notification, which also removes the time event from the op mode
614  * data structures.
615  */
616 static void iwl_mvm_remove_aux_roc_te(struct iwl_mvm *mvm,
617                                       struct iwl_mvm_vif *mvmvif,
618                                       struct iwl_mvm_time_event_data *te_data)
619 {
620         struct iwl_hs20_roc_req aux_cmd = {};
621         u32 uid;
622         int ret;
623
624         if (!__iwl_mvm_remove_time_event(mvm, te_data, &uid))
625                 return;
626
627         aux_cmd.event_unique_id = cpu_to_le32(uid);
628         aux_cmd.action = cpu_to_le32(FW_CTXT_ACTION_REMOVE);
629         aux_cmd.id_and_color =
630                 cpu_to_le32(FW_CMD_ID_AND_COLOR(mvmvif->id, mvmvif->color));
631         IWL_DEBUG_TE(mvm, "Removing BSS AUX ROC TE 0x%x\n",
632                      le32_to_cpu(aux_cmd.event_unique_id));
633         ret = iwl_mvm_send_cmd_pdu(mvm, HOT_SPOT_CMD, 0,
634                                    sizeof(aux_cmd), &aux_cmd);
635
636         if (WARN_ON(ret))
637                 return;
638 }
639
640 /*
641  * Explicit request to remove a time event. The removal of a time event needs to
642  * be synchronized with the flow of a time event's end notification, which also
643  * removes the time event from the op mode data structures.
644  */
645 void iwl_mvm_remove_time_event(struct iwl_mvm *mvm,
646                                struct iwl_mvm_vif *mvmvif,
647                                struct iwl_mvm_time_event_data *te_data)
648 {
649         struct iwl_time_event_cmd time_cmd = {};
650         u32 uid;
651         int ret;
652
653         if (!__iwl_mvm_remove_time_event(mvm, te_data, &uid))
654                 return;
655
656         /* When we remove a TE, the UID is to be set in the id field */
657         time_cmd.id = cpu_to_le32(uid);
658         time_cmd.action = cpu_to_le32(FW_CTXT_ACTION_REMOVE);
659         time_cmd.id_and_color =
660                 cpu_to_le32(FW_CMD_ID_AND_COLOR(mvmvif->id, mvmvif->color));
661
662         IWL_DEBUG_TE(mvm, "Removing TE 0x%x\n", le32_to_cpu(time_cmd.id));
663         ret = iwl_mvm_send_cmd_pdu(mvm, TIME_EVENT_CMD, 0,
664                                    sizeof(time_cmd), &time_cmd);
665         if (WARN_ON(ret))
666                 return;
667 }
668
669 void iwl_mvm_stop_session_protection(struct iwl_mvm *mvm,
670                                      struct ieee80211_vif *vif)
671 {
672         struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
673         struct iwl_mvm_time_event_data *te_data = &mvmvif->time_event_data;
674
675         lockdep_assert_held(&mvm->mutex);
676         iwl_mvm_remove_time_event(mvm, mvmvif, te_data);
677 }
678
679 int iwl_mvm_start_p2p_roc(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
680                           int duration, enum ieee80211_roc_type type)
681 {
682         struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
683         struct iwl_mvm_time_event_data *te_data = &mvmvif->time_event_data;
684         struct iwl_time_event_cmd time_cmd = {};
685
686         lockdep_assert_held(&mvm->mutex);
687         if (te_data->running) {
688                 IWL_WARN(mvm, "P2P_DEVICE remain on channel already running\n");
689                 return -EBUSY;
690         }
691
692         /*
693          * Flush the done work, just in case it's still pending, so that
694          * the work it does can complete and we can accept new frames.
695          */
696         flush_work(&mvm->roc_done_wk);
697
698         time_cmd.action = cpu_to_le32(FW_CTXT_ACTION_ADD);
699         time_cmd.id_and_color =
700                 cpu_to_le32(FW_CMD_ID_AND_COLOR(mvmvif->id, mvmvif->color));
701
702         switch (type) {
703         case IEEE80211_ROC_TYPE_NORMAL:
704                 time_cmd.id = cpu_to_le32(IWL_MVM_ROC_TE_TYPE_NORMAL);
705                 break;
706         case IEEE80211_ROC_TYPE_MGMT_TX:
707                 time_cmd.id = cpu_to_le32(IWL_MVM_ROC_TE_TYPE_MGMT_TX);
708                 break;
709         default:
710                 WARN_ONCE(1, "Got an invalid ROC type\n");
711                 return -EINVAL;
712         }
713
714         time_cmd.apply_time = cpu_to_le32(0);
715         time_cmd.interval = cpu_to_le32(1);
716
717         /*
718          * The P2P Device TEs can have lower priority than other events
719          * that are being scheduled by the driver/fw, and thus it might not be
720          * scheduled. To improve the chances of it being scheduled, allow them
721          * to be fragmented, and in addition allow them to be delayed.
722          */
723         time_cmd.max_frags = min(MSEC_TO_TU(duration)/50, TE_V2_FRAG_ENDLESS);
724         time_cmd.max_delay = cpu_to_le32(MSEC_TO_TU(duration/2));
725         time_cmd.duration = cpu_to_le32(MSEC_TO_TU(duration));
726         time_cmd.repeat = 1;
727         time_cmd.policy = cpu_to_le16(TE_V2_NOTIF_HOST_EVENT_START |
728                                       TE_V2_NOTIF_HOST_EVENT_END |
729                                       T2_V2_START_IMMEDIATELY);
730
731         return iwl_mvm_time_event_send_add(mvm, vif, te_data, &time_cmd);
732 }
733
734 void iwl_mvm_stop_roc(struct iwl_mvm *mvm)
735 {
736         struct iwl_mvm_vif *mvmvif;
737         struct iwl_mvm_time_event_data *te_data;
738         bool is_p2p = false;
739
740         lockdep_assert_held(&mvm->mutex);
741
742         mvmvif = NULL;
743         spin_lock_bh(&mvm->time_event_lock);
744
745         /*
746          * Iterate over the list of time events and find the time event that is
747          * associated with a P2P_DEVICE interface.
748          * This assumes that a P2P_DEVICE interface can have only a single time
749          * event at any given time and this time event coresponds to a ROC
750          * request
751          */
752         list_for_each_entry(te_data, &mvm->time_event_list, list) {
753                 if (te_data->vif->type == NL80211_IFTYPE_P2P_DEVICE &&
754                     te_data->running) {
755                         mvmvif = iwl_mvm_vif_from_mac80211(te_data->vif);
756                         is_p2p = true;
757                         goto remove_te;
758                 }
759         }
760
761         /*
762          * Iterate over the list of aux roc time events and find the time
763          * event that is associated with a BSS interface.
764          * This assumes that a BSS interface can have only a single time
765          * event at any given time and this time event coresponds to a ROC
766          * request
767          */
768         list_for_each_entry(te_data, &mvm->aux_roc_te_list, list) {
769                 if (te_data->running) {
770                         mvmvif = iwl_mvm_vif_from_mac80211(te_data->vif);
771                         goto remove_te;
772                 }
773         }
774
775 remove_te:
776         spin_unlock_bh(&mvm->time_event_lock);
777
778         if (!mvmvif) {
779                 IWL_WARN(mvm, "No remain on channel event\n");
780                 return;
781         }
782
783         if (is_p2p)
784                 iwl_mvm_remove_time_event(mvm, mvmvif, te_data);
785         else
786                 iwl_mvm_remove_aux_roc_te(mvm, mvmvif, te_data);
787
788         iwl_mvm_roc_finished(mvm);
789 }
790
791 int iwl_mvm_schedule_csa_period(struct iwl_mvm *mvm,
792                                 struct ieee80211_vif *vif,
793                                 u32 duration, u32 apply_time)
794 {
795         struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
796         struct iwl_mvm_time_event_data *te_data = &mvmvif->time_event_data;
797         struct iwl_time_event_cmd time_cmd = {};
798
799         lockdep_assert_held(&mvm->mutex);
800
801         if (te_data->running) {
802                 IWL_DEBUG_TE(mvm, "CS period is already scheduled\n");
803                 return -EBUSY;
804         }
805
806         time_cmd.action = cpu_to_le32(FW_CTXT_ACTION_ADD);
807         time_cmd.id_and_color =
808                 cpu_to_le32(FW_CMD_ID_AND_COLOR(mvmvif->id, mvmvif->color));
809         time_cmd.id = cpu_to_le32(TE_CHANNEL_SWITCH_PERIOD);
810         time_cmd.apply_time = cpu_to_le32(apply_time);
811         time_cmd.max_frags = TE_V2_FRAG_NONE;
812         time_cmd.duration = cpu_to_le32(duration);
813         time_cmd.repeat = 1;
814         time_cmd.interval = cpu_to_le32(1);
815         time_cmd.policy = cpu_to_le16(TE_V2_NOTIF_HOST_EVENT_START |
816                                       TE_V2_ABSENCE);
817
818         return iwl_mvm_time_event_send_add(mvm, vif, te_data, &time_cmd);
819 }