diff options
Diffstat (limited to 'drivers/net/wireless/iwlwifi/mvm/time-event.c')
-rw-r--r-- | drivers/net/wireless/iwlwifi/mvm/time-event.c | 215 |
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 | ||
233 | static bool iwl_mvm_time_event_notif(struct iwl_notif_wait_data *notif_wait, | 233 | static 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; | 257 | static 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 | ||
286 | void iwl_mvm_protect_session(struct iwl_mvm *mvm, | 315 | void 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 | |||
372 | out_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 | ||
438 | static 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 | |||
466 | int iwl_mvm_start_p2p_roc(struct iwl_mvm *mvm, struct ieee80211_vif *vif, | 432 | int 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 | |||
543 | out_remove_notif: | ||
544 | iwl_remove_notification(&mvm->notif_wait, &wait_time_event); | ||
545 | return ret; | ||
546 | } | 477 | } |
547 | 478 | ||
548 | void iwl_mvm_stop_p2p_roc(struct iwl_mvm *mvm) | 479 | void iwl_mvm_stop_p2p_roc(struct iwl_mvm *mvm) |