aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/iwlwifi/mvm/time-event.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/wireless/iwlwifi/mvm/time-event.c')
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/time-event.c215
1 files changed, 73 insertions, 142 deletions
diff --git a/drivers/net/wireless/iwlwifi/mvm/time-event.c b/drivers/net/wireless/iwlwifi/mvm/time-event.c
index 194bfb7a7d7f..c09b71f23759 100644
--- a/drivers/net/wireless/iwlwifi/mvm/time-event.c
+++ b/drivers/net/wireless/iwlwifi/mvm/time-event.c
@@ -230,57 +230,86 @@ int iwl_mvm_rx_time_event_notif(struct iwl_mvm *mvm,
230 return 0; 230 return 0;
231} 231}
232 232
233static bool iwl_mvm_time_event_notif(struct iwl_notif_wait_data *notif_wait, 233static bool iwl_mvm_time_event_response(struct iwl_notif_wait_data *notif_wait,
234 struct iwl_rx_packet *pkt, void *data) 234 struct iwl_rx_packet *pkt, void *data)
235{ 235{
236 struct iwl_mvm *mvm = 236 struct iwl_mvm *mvm =
237 container_of(notif_wait, struct iwl_mvm, notif_wait); 237 container_of(notif_wait, struct iwl_mvm, notif_wait);
238 struct iwl_mvm_time_event_data *te_data = data; 238 struct iwl_mvm_time_event_data *te_data = data;
239 struct ieee80211_vif *vif = te_data->vif;
240 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
241 struct iwl_time_event_notif *notif;
242 struct iwl_time_event_resp *resp; 239 struct iwl_time_event_resp *resp;
240 int resp_len = le32_to_cpu(pkt->len_n_flags) & FH_RSCSR_FRAME_SIZE_MSK;
243 241
244 u32 mac_id_n_color = FW_CMD_ID_AND_COLOR(mvmvif->id, mvmvif->color); 242 if (WARN_ON(pkt->hdr.cmd != TIME_EVENT_CMD))
243 return true;
245 244
246 /* until we do something else */ 245 if (WARN_ON_ONCE(resp_len != sizeof(pkt->hdr) + sizeof(*resp))) {
247 WARN_ON(te_data->id != TE_BSS_STA_AGGRESSIVE_ASSOC); 246 IWL_ERR(mvm, "Invalid TIME_EVENT_CMD response\n");
247 return true;
248 }
248 249
249 switch (pkt->hdr.cmd) { 250 resp = (void *)pkt->data;
250 case TIME_EVENT_CMD: 251 te_data->uid = le32_to_cpu(resp->unique_id);
251 resp = (void *)pkt->data; 252 IWL_DEBUG_TE(mvm, "TIME_EVENT_CMD response - UID = 0x%x\n",
252 /* TODO: I can't check that since the fw is buggy - it doesn't 253 te_data->uid);
253 * put the right values when we remove a TE. We can be here 254 return true;
254 * when we remove a TE because the remove TE command is sent in 255}
255 * ASYNC...
256 * WARN_ON(mac_id_n_color != le32_to_cpu(resp->id_and_color));
257 */
258 te_data->uid = le32_to_cpu(resp->unique_id);
259 IWL_DEBUG_TE(mvm, "Got response - UID = 0x%x\n", te_data->uid);
260 return false;
261
262 case TIME_EVENT_NOTIFICATION:
263 notif = (void *)pkt->data;
264 WARN_ON(le32_to_cpu(notif->status) != 1);
265 WARN_ON(mac_id_n_color != le32_to_cpu(notif->id_and_color));
266 /* check if this is our Time Event that is starting */
267 if (le32_to_cpu(notif->unique_id) != te_data->uid)
268 return false;
269 IWL_DEBUG_TE(mvm, "Event %d is starting - time is %d\n",
270 te_data->uid, le32_to_cpu(notif->timestamp));
271
272 WARN_ONCE(!le32_to_cpu(notif->status),
273 "Failed to schedule protected session TE\n");
274 256
275 te_data->running = true; 257static int iwl_mvm_time_event_send_add(struct iwl_mvm *mvm,
276 te_data->end_jiffies = jiffies + 258 struct ieee80211_vif *vif,
277 TU_TO_JIFFIES(te_data->duration); 259 struct iwl_mvm_time_event_data *te_data,
278 return true; 260 struct iwl_time_event_cmd *te_cmd)
261{
262 static const u8 time_event_response[] = { TIME_EVENT_CMD };
263 struct iwl_notification_wait wait_time_event;
264 int ret;
265
266 lockdep_assert_held(&mvm->mutex);
267
268 spin_lock_bh(&mvm->time_event_lock);
269 if (WARN_ON(te_data->id != TE_MAX)) {
270 spin_unlock_bh(&mvm->time_event_lock);
271 return -EIO;
272 }
273 te_data->vif = vif;
274 te_data->duration = le32_to_cpu(te_cmd->duration);
275 te_data->id = le32_to_cpu(te_cmd->id);
276 list_add_tail(&te_data->list, &mvm->time_event_list);
277 spin_unlock_bh(&mvm->time_event_lock);
278
279 /*
280 * Use a notification wait, which really just processes the
281 * command response and doesn't wait for anything, in order
282 * to be able to process the response and get the UID inside
283 * the RX path. Using CMD_WANT_SKB doesn't work because it
284 * stores the buffer and then wakes up this thread, by which
285 * time another notification (that the time event started)
286 * might already be processed unsuccessfully.
287 */
288 iwl_init_notification_wait(&mvm->notif_wait, &wait_time_event,
289 time_event_response,
290 ARRAY_SIZE(time_event_response),
291 iwl_mvm_time_event_response, te_data);
292
293 ret = iwl_mvm_send_cmd_pdu(mvm, TIME_EVENT_CMD, CMD_SYNC,
294 sizeof(*te_cmd), te_cmd);
295 if (ret) {
296 IWL_ERR(mvm, "Couldn't send TIME_EVENT_CMD: %d\n", ret);
297 iwl_remove_notification(&mvm->notif_wait, &wait_time_event);
298 goto out_clear_te;
299 }
279 300
280 default: 301 /* No need to wait for anything, so just pass 1 (0 isn't valid) */
281 WARN_ON(1); 302 ret = iwl_wait_notification(&mvm->notif_wait, &wait_time_event, 1);
282 return false; 303 /* should never fail */
283 }; 304 WARN_ON_ONCE(ret);
305
306 if (ret) {
307 out_clear_te:
308 spin_lock_bh(&mvm->time_event_lock);
309 iwl_mvm_te_clear_data(mvm, te_data);
310 spin_unlock_bh(&mvm->time_event_lock);
311 }
312 return ret;
284} 313}
285 314
286void iwl_mvm_protect_session(struct iwl_mvm *mvm, 315void iwl_mvm_protect_session(struct iwl_mvm *mvm,
@@ -289,11 +318,7 @@ void iwl_mvm_protect_session(struct iwl_mvm *mvm,
289{ 318{
290 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); 319 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
291 struct iwl_mvm_time_event_data *te_data = &mvmvif->time_event_data; 320 struct iwl_mvm_time_event_data *te_data = &mvmvif->time_event_data;
292 static const u8 time_event_notif[] = { TIME_EVENT_CMD,
293 TIME_EVENT_NOTIFICATION };
294 struct iwl_notification_wait wait_time_event;
295 struct iwl_time_event_cmd time_cmd = {}; 321 struct iwl_time_event_cmd time_cmd = {};
296 int ret;
297 322
298 lockdep_assert_held(&mvm->mutex); 323 lockdep_assert_held(&mvm->mutex);
299 324
@@ -320,12 +345,6 @@ void iwl_mvm_protect_session(struct iwl_mvm *mvm,
320 iwl_mvm_stop_session_protection(mvm, vif); 345 iwl_mvm_stop_session_protection(mvm, vif);
321 } 346 }
322 347
323 iwl_init_notification_wait(&mvm->notif_wait, &wait_time_event,
324 time_event_notif,
325 ARRAY_SIZE(time_event_notif),
326 iwl_mvm_time_event_notif,
327 &mvmvif->time_event_data);
328
329 time_cmd.action = cpu_to_le32(FW_CTXT_ACTION_ADD); 348 time_cmd.action = cpu_to_le32(FW_CTXT_ACTION_ADD);
330 time_cmd.id_and_color = 349 time_cmd.id_and_color =
331 cpu_to_le32(FW_CMD_ID_AND_COLOR(mvmvif->id, mvmvif->color)); 350 cpu_to_le32(FW_CMD_ID_AND_COLOR(mvmvif->id, mvmvif->color));
@@ -333,6 +352,7 @@ void iwl_mvm_protect_session(struct iwl_mvm *mvm,
333 352
334 time_cmd.apply_time = 353 time_cmd.apply_time =
335 cpu_to_le32(iwl_read_prph(mvm->trans, DEVICE_SYSTEM_TIME_REG)); 354 cpu_to_le32(iwl_read_prph(mvm->trans, DEVICE_SYSTEM_TIME_REG));
355
336 time_cmd.dep_policy = TE_INDEPENDENT; 356 time_cmd.dep_policy = TE_INDEPENDENT;
337 time_cmd.is_present = cpu_to_le32(1); 357 time_cmd.is_present = cpu_to_le32(1);
338 time_cmd.max_frags = cpu_to_le32(TE_FRAG_NONE); 358 time_cmd.max_frags = cpu_to_le32(TE_FRAG_NONE);
@@ -344,33 +364,7 @@ void iwl_mvm_protect_session(struct iwl_mvm *mvm,
344 time_cmd.repeat = cpu_to_le32(1); 364 time_cmd.repeat = cpu_to_le32(1);
345 time_cmd.notify = cpu_to_le32(TE_NOTIF_HOST_START | TE_NOTIF_HOST_END); 365 time_cmd.notify = cpu_to_le32(TE_NOTIF_HOST_START | TE_NOTIF_HOST_END);
346 366
347 te_data->vif = vif; 367 iwl_mvm_time_event_send_add(mvm, vif, te_data, &time_cmd);
348 te_data->duration = duration;
349
350 spin_lock_bh(&mvm->time_event_lock);
351 te_data->id = le32_to_cpu(time_cmd.id);
352 list_add_tail(&te_data->list, &mvm->time_event_list);
353 spin_unlock_bh(&mvm->time_event_lock);
354
355 ret = iwl_mvm_send_cmd_pdu(mvm, TIME_EVENT_CMD, CMD_SYNC,
356 sizeof(time_cmd), &time_cmd);
357 if (ret) {
358 IWL_ERR(mvm, "Couldn't send TIME_EVENT_CMD: %d\n", ret);
359 goto out_remove_notif;
360 }
361
362 ret = iwl_wait_notification(&mvm->notif_wait, &wait_time_event, 1 * HZ);
363 if (ret) {
364 IWL_ERR(mvm, "%s - failed on timeout\n", __func__);
365 spin_lock_bh(&mvm->time_event_lock);
366 iwl_mvm_te_clear_data(mvm, te_data);
367 spin_unlock_bh(&mvm->time_event_lock);
368 }
369
370 return;
371
372out_remove_notif:
373 iwl_remove_notification(&mvm->notif_wait, &wait_time_event);
374} 368}
375 369
376/* 370/*
@@ -435,43 +429,12 @@ void iwl_mvm_stop_session_protection(struct iwl_mvm *mvm,
435 iwl_mvm_remove_time_event(mvm, mvmvif, te_data); 429 iwl_mvm_remove_time_event(mvm, mvmvif, te_data);
436} 430}
437 431
438static bool iwl_mvm_roc_te_notif(struct iwl_notif_wait_data *notif_wait,
439 struct iwl_rx_packet *pkt, void *data)
440{
441 struct iwl_mvm *mvm =
442 container_of(notif_wait, struct iwl_mvm, notif_wait);
443 struct iwl_mvm_time_event_data *te_data = data;
444 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(te_data->vif);
445 struct iwl_time_event_resp *resp;
446
447 u32 mac_id_n_color = FW_CMD_ID_AND_COLOR(mvmvif->id, mvmvif->color);
448
449 /* until we do something else */
450 WARN_ON(te_data->id != IWL_MVM_ROC_TE_TYPE);
451
452 switch (pkt->hdr.cmd) {
453 case TIME_EVENT_CMD:
454 resp = (void *)pkt->data;
455 WARN_ON(mac_id_n_color != le32_to_cpu(resp->id_and_color));
456 te_data->uid = le32_to_cpu(resp->unique_id);
457 IWL_DEBUG_TE(mvm, "Got response - UID = 0x%x\n", te_data->uid);
458 return true;
459
460 default:
461 WARN_ON(1);
462 return false;
463 };
464}
465
466int iwl_mvm_start_p2p_roc(struct iwl_mvm *mvm, struct ieee80211_vif *vif, 432int iwl_mvm_start_p2p_roc(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
467 int duration) 433 int duration)
468{ 434{
469 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); 435 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
470 struct iwl_mvm_time_event_data *te_data = &mvmvif->time_event_data; 436 struct iwl_mvm_time_event_data *te_data = &mvmvif->time_event_data;
471 static const u8 roc_te_notif[] = { TIME_EVENT_CMD };
472 struct iwl_notification_wait wait_time_event;
473 struct iwl_time_event_cmd time_cmd = {}; 437 struct iwl_time_event_cmd time_cmd = {};
474 int ret;
475 438
476 lockdep_assert_held(&mvm->mutex); 439 lockdep_assert_held(&mvm->mutex);
477 if (te_data->running) { 440 if (te_data->running) {
@@ -485,12 +448,6 @@ int iwl_mvm_start_p2p_roc(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
485 */ 448 */
486 flush_work(&mvm->roc_done_wk); 449 flush_work(&mvm->roc_done_wk);
487 450
488 iwl_init_notification_wait(&mvm->notif_wait, &wait_time_event,
489 roc_te_notif,
490 ARRAY_SIZE(roc_te_notif),
491 iwl_mvm_roc_te_notif,
492 &mvmvif->time_event_data);
493
494 time_cmd.action = cpu_to_le32(FW_CTXT_ACTION_ADD); 451 time_cmd.action = cpu_to_le32(FW_CTXT_ACTION_ADD);
495 time_cmd.id_and_color = 452 time_cmd.id_and_color =
496 cpu_to_le32(FW_CMD_ID_AND_COLOR(mvmvif->id, mvmvif->color)); 453 cpu_to_le32(FW_CMD_ID_AND_COLOR(mvmvif->id, mvmvif->color));
@@ -516,33 +473,7 @@ int iwl_mvm_start_p2p_roc(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
516 time_cmd.repeat = cpu_to_le32(1); 473 time_cmd.repeat = cpu_to_le32(1);
517 time_cmd.notify = cpu_to_le32(TE_NOTIF_HOST_START | TE_NOTIF_HOST_END); 474 time_cmd.notify = cpu_to_le32(TE_NOTIF_HOST_START | TE_NOTIF_HOST_END);
518 475
519 /* Push the te data to the tracked te list */ 476 return iwl_mvm_time_event_send_add(mvm, vif, te_data, &time_cmd);
520 te_data->vif = vif;
521 te_data->duration = MSEC_TO_TU(duration);
522
523 spin_lock_bh(&mvm->time_event_lock);
524 te_data->id = le32_to_cpu(time_cmd.id);
525 list_add_tail(&te_data->list, &mvm->time_event_list);
526 spin_unlock_bh(&mvm->time_event_lock);
527
528 ret = iwl_mvm_send_cmd_pdu(mvm, TIME_EVENT_CMD, CMD_SYNC,
529 sizeof(time_cmd), &time_cmd);
530 if (ret) {
531 IWL_ERR(mvm, "Couldn't send TIME_EVENT_CMD: %d\n", ret);
532 goto out_remove_notif;
533 }
534
535 ret = iwl_wait_notification(&mvm->notif_wait, &wait_time_event, 1 * HZ);
536 if (ret) {
537 IWL_ERR(mvm, "%s - failed on timeout\n", __func__);
538 iwl_mvm_te_clear_data(mvm, te_data);
539 }
540
541 return ret;
542
543out_remove_notif:
544 iwl_remove_notification(&mvm->notif_wait, &wait_time_event);
545 return ret;
546} 477}
547 478
548void iwl_mvm_stop_p2p_roc(struct iwl_mvm *mvm) 479void iwl_mvm_stop_p2p_roc(struct iwl_mvm *mvm)