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.c103
1 files changed, 75 insertions, 28 deletions
diff --git a/drivers/net/wireless/iwlwifi/mvm/time-event.c b/drivers/net/wireless/iwlwifi/mvm/time-event.c
index 7fd6fbfbc1b3..c17b74c31398 100644
--- a/drivers/net/wireless/iwlwifi/mvm/time-event.c
+++ b/drivers/net/wireless/iwlwifi/mvm/time-event.c
@@ -73,7 +73,6 @@
73#include "iwl-prph.h" 73#include "iwl-prph.h"
74 74
75/* A TimeUnit is 1024 microsecond */ 75/* A TimeUnit is 1024 microsecond */
76#define TU_TO_JIFFIES(_tu) (usecs_to_jiffies((_tu) * 1024))
77#define MSEC_TO_TU(_msec) (_msec*1000/1024) 76#define MSEC_TO_TU(_msec) (_msec*1000/1024)
78 77
79/* 78/*
@@ -185,7 +184,7 @@ static void iwl_mvm_te_handle_notif(struct iwl_mvm *mvm,
185 } 184 }
186 } 185 }
187 186
188 if (le32_to_cpu(notif->action) & TE_NOTIF_HOST_EVENT_END) { 187 if (le32_to_cpu(notif->action) & TE_V2_NOTIF_HOST_EVENT_END) {
189 IWL_DEBUG_TE(mvm, 188 IWL_DEBUG_TE(mvm,
190 "TE ended - current time %lu, estimated end %lu\n", 189 "TE ended - current time %lu, estimated end %lu\n",
191 jiffies, te_data->end_jiffies); 190 jiffies, te_data->end_jiffies);
@@ -202,10 +201,9 @@ static void iwl_mvm_te_handle_notif(struct iwl_mvm *mvm,
202 iwl_mvm_te_check_disconnect(mvm, te_data->vif, 201 iwl_mvm_te_check_disconnect(mvm, te_data->vif,
203 "No assocation and the time event is over already..."); 202 "No assocation and the time event is over already...");
204 iwl_mvm_te_clear_data(mvm, te_data); 203 iwl_mvm_te_clear_data(mvm, te_data);
205 } else if (le32_to_cpu(notif->action) & TE_NOTIF_HOST_EVENT_START) { 204 } else if (le32_to_cpu(notif->action) & TE_V2_NOTIF_HOST_EVENT_START) {
206 te_data->running = true; 205 te_data->running = true;
207 te_data->end_jiffies = jiffies + 206 te_data->end_jiffies = TU_TO_EXP_TIME(te_data->duration);
208 TU_TO_JIFFIES(te_data->duration);
209 207
210 if (te_data->vif->type == NL80211_IFTYPE_P2P_DEVICE) { 208 if (te_data->vif->type == NL80211_IFTYPE_P2P_DEVICE) {
211 set_bit(IWL_MVM_STATUS_ROC_RUNNING, &mvm->status); 209 set_bit(IWL_MVM_STATUS_ROC_RUNNING, &mvm->status);
@@ -270,10 +268,67 @@ static bool iwl_mvm_time_event_response(struct iwl_notif_wait_data *notif_wait,
270 return true; 268 return true;
271} 269}
272 270
271/* used to convert from time event API v2 to v1 */
272#define TE_V2_DEP_POLICY_MSK (TE_V2_DEP_OTHER | TE_V2_DEP_TSF |\
273 TE_V2_EVENT_SOCIOPATHIC)
274static inline u16 te_v2_get_notify(__le16 policy)
275{
276 return le16_to_cpu(policy) & TE_V2_NOTIF_MSK;
277}
278
279static inline u16 te_v2_get_dep_policy(__le16 policy)
280{
281 return (le16_to_cpu(policy) & TE_V2_DEP_POLICY_MSK) >>
282 TE_V2_PLACEMENT_POS;
283}
284
285static inline u16 te_v2_get_absence(__le16 policy)
286{
287 return (le16_to_cpu(policy) & TE_V2_ABSENCE) >> TE_V2_ABSENCE_POS;
288}
289
290static void iwl_mvm_te_v2_to_v1(const struct iwl_time_event_cmd_v2 *cmd_v2,
291 struct iwl_time_event_cmd_v1 *cmd_v1)
292{
293 cmd_v1->id_and_color = cmd_v2->id_and_color;
294 cmd_v1->action = cmd_v2->action;
295 cmd_v1->id = cmd_v2->id;
296 cmd_v1->apply_time = cmd_v2->apply_time;
297 cmd_v1->max_delay = cmd_v2->max_delay;
298 cmd_v1->depends_on = cmd_v2->depends_on;
299 cmd_v1->interval = cmd_v2->interval;
300 cmd_v1->duration = cmd_v2->duration;
301 if (cmd_v2->repeat == TE_V2_REPEAT_ENDLESS)
302 cmd_v1->repeat = cpu_to_le32(TE_V1_REPEAT_ENDLESS);
303 else
304 cmd_v1->repeat = cpu_to_le32(cmd_v2->repeat);
305 cmd_v1->max_frags = cpu_to_le32(cmd_v2->max_frags);
306 cmd_v1->interval_reciprocal = 0; /* unused */
307
308 cmd_v1->dep_policy = cpu_to_le32(te_v2_get_dep_policy(cmd_v2->policy));
309 cmd_v1->is_present = cpu_to_le32(!te_v2_get_absence(cmd_v2->policy));
310 cmd_v1->notify = cpu_to_le32(te_v2_get_notify(cmd_v2->policy));
311}
312
313static int iwl_mvm_send_time_event_cmd(struct iwl_mvm *mvm,
314 const struct iwl_time_event_cmd_v2 *cmd)
315{
316 struct iwl_time_event_cmd_v1 cmd_v1;
317
318 if (mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_TIME_EVENT_API_V2)
319 return iwl_mvm_send_cmd_pdu(mvm, TIME_EVENT_CMD, CMD_SYNC,
320 sizeof(*cmd), cmd);
321
322 iwl_mvm_te_v2_to_v1(cmd, &cmd_v1);
323 return iwl_mvm_send_cmd_pdu(mvm, TIME_EVENT_CMD, CMD_SYNC,
324 sizeof(cmd_v1), &cmd_v1);
325}
326
327
273static int iwl_mvm_time_event_send_add(struct iwl_mvm *mvm, 328static int iwl_mvm_time_event_send_add(struct iwl_mvm *mvm,
274 struct ieee80211_vif *vif, 329 struct ieee80211_vif *vif,
275 struct iwl_mvm_time_event_data *te_data, 330 struct iwl_mvm_time_event_data *te_data,
276 struct iwl_time_event_cmd *te_cmd) 331 struct iwl_time_event_cmd_v2 *te_cmd)
277{ 332{
278 static const u8 time_event_response[] = { TIME_EVENT_CMD }; 333 static const u8 time_event_response[] = { TIME_EVENT_CMD };
279 struct iwl_notification_wait wait_time_event; 334 struct iwl_notification_wait wait_time_event;
@@ -309,8 +364,7 @@ static int iwl_mvm_time_event_send_add(struct iwl_mvm *mvm,
309 ARRAY_SIZE(time_event_response), 364 ARRAY_SIZE(time_event_response),
310 iwl_mvm_time_event_response, te_data); 365 iwl_mvm_time_event_response, te_data);
311 366
312 ret = iwl_mvm_send_cmd_pdu(mvm, TIME_EVENT_CMD, CMD_SYNC, 367 ret = iwl_mvm_send_time_event_cmd(mvm, te_cmd);
313 sizeof(*te_cmd), te_cmd);
314 if (ret) { 368 if (ret) {
315 IWL_ERR(mvm, "Couldn't send TIME_EVENT_CMD: %d\n", ret); 369 IWL_ERR(mvm, "Couldn't send TIME_EVENT_CMD: %d\n", ret);
316 iwl_remove_notification(&mvm->notif_wait, &wait_time_event); 370 iwl_remove_notification(&mvm->notif_wait, &wait_time_event);
@@ -337,13 +391,12 @@ void iwl_mvm_protect_session(struct iwl_mvm *mvm,
337{ 391{
338 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); 392 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
339 struct iwl_mvm_time_event_data *te_data = &mvmvif->time_event_data; 393 struct iwl_mvm_time_event_data *te_data = &mvmvif->time_event_data;
340 struct iwl_time_event_cmd time_cmd = {}; 394 struct iwl_time_event_cmd_v2 time_cmd = {};
341 395
342 lockdep_assert_held(&mvm->mutex); 396 lockdep_assert_held(&mvm->mutex);
343 397
344 if (te_data->running && 398 if (te_data->running &&
345 time_after(te_data->end_jiffies, 399 time_after(te_data->end_jiffies, TU_TO_EXP_TIME(min_duration))) {
346 jiffies + TU_TO_JIFFIES(min_duration))) {
347 IWL_DEBUG_TE(mvm, "We have enough time in the current TE: %u\n", 400 IWL_DEBUG_TE(mvm, "We have enough time in the current TE: %u\n",
348 jiffies_to_msecs(te_data->end_jiffies - jiffies)); 401 jiffies_to_msecs(te_data->end_jiffies - jiffies));
349 return; 402 return;
@@ -372,17 +425,14 @@ void iwl_mvm_protect_session(struct iwl_mvm *mvm,
372 time_cmd.apply_time = 425 time_cmd.apply_time =
373 cpu_to_le32(iwl_read_prph(mvm->trans, DEVICE_SYSTEM_TIME_REG)); 426 cpu_to_le32(iwl_read_prph(mvm->trans, DEVICE_SYSTEM_TIME_REG));
374 427
375 time_cmd.dep_policy = TE_INDEPENDENT; 428 time_cmd.max_frags = TE_V2_FRAG_NONE;
376 time_cmd.is_present = cpu_to_le32(1);
377 time_cmd.max_frags = cpu_to_le32(TE_FRAG_NONE);
378 time_cmd.max_delay = cpu_to_le32(500); 429 time_cmd.max_delay = cpu_to_le32(500);
379 /* TODO: why do we need to interval = bi if it is not periodic? */ 430 /* TODO: why do we need to interval = bi if it is not periodic? */
380 time_cmd.interval = cpu_to_le32(1); 431 time_cmd.interval = cpu_to_le32(1);
381 time_cmd.interval_reciprocal = cpu_to_le32(iwl_mvm_reciprocal(1));
382 time_cmd.duration = cpu_to_le32(duration); 432 time_cmd.duration = cpu_to_le32(duration);
383 time_cmd.repeat = cpu_to_le32(1); 433 time_cmd.repeat = 1;
384 time_cmd.notify = cpu_to_le32(TE_NOTIF_HOST_EVENT_START | 434 time_cmd.policy = cpu_to_le16(TE_V2_NOTIF_HOST_EVENT_START |
385 TE_NOTIF_HOST_EVENT_END); 435 TE_V2_NOTIF_HOST_EVENT_END);
386 436
387 iwl_mvm_time_event_send_add(mvm, vif, te_data, &time_cmd); 437 iwl_mvm_time_event_send_add(mvm, vif, te_data, &time_cmd);
388} 438}
@@ -396,7 +446,7 @@ void iwl_mvm_remove_time_event(struct iwl_mvm *mvm,
396 struct iwl_mvm_vif *mvmvif, 446 struct iwl_mvm_vif *mvmvif,
397 struct iwl_mvm_time_event_data *te_data) 447 struct iwl_mvm_time_event_data *te_data)
398{ 448{
399 struct iwl_time_event_cmd time_cmd = {}; 449 struct iwl_time_event_cmd_v2 time_cmd = {};
400 u32 id, uid; 450 u32 id, uid;
401 int ret; 451 int ret;
402 452
@@ -433,8 +483,7 @@ void iwl_mvm_remove_time_event(struct iwl_mvm *mvm,
433 cpu_to_le32(FW_CMD_ID_AND_COLOR(mvmvif->id, mvmvif->color)); 483 cpu_to_le32(FW_CMD_ID_AND_COLOR(mvmvif->id, mvmvif->color));
434 484
435 IWL_DEBUG_TE(mvm, "Removing TE 0x%x\n", le32_to_cpu(time_cmd.id)); 485 IWL_DEBUG_TE(mvm, "Removing TE 0x%x\n", le32_to_cpu(time_cmd.id));
436 ret = iwl_mvm_send_cmd_pdu(mvm, TIME_EVENT_CMD, CMD_SYNC, 486 ret = iwl_mvm_send_time_event_cmd(mvm, &time_cmd);
437 sizeof(time_cmd), &time_cmd);
438 if (WARN_ON(ret)) 487 if (WARN_ON(ret))
439 return; 488 return;
440} 489}
@@ -454,7 +503,7 @@ int iwl_mvm_start_p2p_roc(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
454{ 503{
455 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); 504 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
456 struct iwl_mvm_time_event_data *te_data = &mvmvif->time_event_data; 505 struct iwl_mvm_time_event_data *te_data = &mvmvif->time_event_data;
457 struct iwl_time_event_cmd time_cmd = {}; 506 struct iwl_time_event_cmd_v2 time_cmd = {};
458 507
459 lockdep_assert_held(&mvm->mutex); 508 lockdep_assert_held(&mvm->mutex);
460 if (te_data->running) { 509 if (te_data->running) {
@@ -485,8 +534,6 @@ int iwl_mvm_start_p2p_roc(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
485 } 534 }
486 535
487 time_cmd.apply_time = cpu_to_le32(0); 536 time_cmd.apply_time = cpu_to_le32(0);
488 time_cmd.dep_policy = cpu_to_le32(TE_INDEPENDENT);
489 time_cmd.is_present = cpu_to_le32(1);
490 time_cmd.interval = cpu_to_le32(1); 537 time_cmd.interval = cpu_to_le32(1);
491 538
492 /* 539 /*
@@ -495,12 +542,12 @@ int iwl_mvm_start_p2p_roc(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
495 * scheduled. To improve the chances of it being scheduled, allow them 542 * scheduled. To improve the chances of it being scheduled, allow them
496 * to be fragmented, and in addition allow them to be delayed. 543 * to be fragmented, and in addition allow them to be delayed.
497 */ 544 */
498 time_cmd.max_frags = cpu_to_le32(MSEC_TO_TU(duration)/20); 545 time_cmd.max_frags = min(MSEC_TO_TU(duration)/50, TE_V2_FRAG_ENDLESS);
499 time_cmd.max_delay = cpu_to_le32(MSEC_TO_TU(duration/2)); 546 time_cmd.max_delay = cpu_to_le32(MSEC_TO_TU(duration/2));
500 time_cmd.duration = cpu_to_le32(MSEC_TO_TU(duration)); 547 time_cmd.duration = cpu_to_le32(MSEC_TO_TU(duration));
501 time_cmd.repeat = cpu_to_le32(1); 548 time_cmd.repeat = 1;
502 time_cmd.notify = cpu_to_le32(TE_NOTIF_HOST_EVENT_START | 549 time_cmd.policy = cpu_to_le16(TE_V2_NOTIF_HOST_EVENT_START |
503 TE_NOTIF_HOST_EVENT_END); 550 TE_V2_NOTIF_HOST_EVENT_END);
504 551
505 return iwl_mvm_time_event_send_add(mvm, vif, te_data, &time_cmd); 552 return iwl_mvm_time_event_send_add(mvm, vif, te_data, &time_cmd);
506} 553}