diff options
Diffstat (limited to 'drivers/net/wireless')
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-fw.h | 2 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/mvm/fw-api.h | 226 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/mvm/time-event.c | 96 |
3 files changed, 251 insertions, 73 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl-fw.h b/drivers/net/wireless/iwlwifi/iwl-fw.h index bd335f0c40d1..1705d245dbe9 100644 --- a/drivers/net/wireless/iwlwifi/iwl-fw.h +++ b/drivers/net/wireless/iwlwifi/iwl-fw.h | |||
@@ -76,6 +76,7 @@ | |||
76 | * @IWL_UCODE_TLV_FLAGS_DW_BC_TABLE: The SCD byte count table is in DWORDS | 76 | * @IWL_UCODE_TLV_FLAGS_DW_BC_TABLE: The SCD byte count table is in DWORDS |
77 | * @IWL_UCODE_TLV_FLAGS_UAPSD: This uCode image supports uAPSD | 77 | * @IWL_UCODE_TLV_FLAGS_UAPSD: This uCode image supports uAPSD |
78 | * @IWL_UCODE_TLV_FLAGS_RX_ENERGY_API: supports rx signal strength api | 78 | * @IWL_UCODE_TLV_FLAGS_RX_ENERGY_API: supports rx signal strength api |
79 | * @IWL_UCODE_TLV_FLAGS_TIME_EVENT_API_V2: using the new time event API. | ||
79 | * @IWL_UCODE_TLV_FLAGS_D3_6_IPV6_ADDRS: D3 image supports up to six | 80 | * @IWL_UCODE_TLV_FLAGS_D3_6_IPV6_ADDRS: D3 image supports up to six |
80 | * (rather than two) IPv6 addresses | 81 | * (rather than two) IPv6 addresses |
81 | * @IWL_UCODE_TLV_FLAGS_BF_UPDATED: new beacon filtering API | 82 | * @IWL_UCODE_TLV_FLAGS_BF_UPDATED: new beacon filtering API |
@@ -88,6 +89,7 @@ enum iwl_ucode_tlv_flag { | |||
88 | IWL_UCODE_TLV_FLAGS_DW_BC_TABLE = BIT(4), | 89 | IWL_UCODE_TLV_FLAGS_DW_BC_TABLE = BIT(4), |
89 | IWL_UCODE_TLV_FLAGS_UAPSD = BIT(6), | 90 | IWL_UCODE_TLV_FLAGS_UAPSD = BIT(6), |
90 | IWL_UCODE_TLV_FLAGS_RX_ENERGY_API = BIT(8), | 91 | IWL_UCODE_TLV_FLAGS_RX_ENERGY_API = BIT(8), |
92 | IWL_UCODE_TLV_FLAGS_TIME_EVENT_API_V2 = BIT(9), | ||
91 | IWL_UCODE_TLV_FLAGS_D3_6_IPV6_ADDRS = BIT(10), | 93 | IWL_UCODE_TLV_FLAGS_D3_6_IPV6_ADDRS = BIT(10), |
92 | IWL_UCODE_TLV_FLAGS_BF_UPDATED = BIT(11), | 94 | IWL_UCODE_TLV_FLAGS_BF_UPDATED = BIT(11), |
93 | }; | 95 | }; |
diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api.h b/drivers/net/wireless/iwlwifi/mvm/fw-api.h index 55854a309f94..b1047102ea47 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw-api.h +++ b/drivers/net/wireless/iwlwifi/mvm/fw-api.h | |||
@@ -499,71 +499,199 @@ enum iwl_time_event_type { | |||
499 | TE_MAX | 499 | TE_MAX |
500 | }; /* MAC_EVENT_TYPE_API_E_VER_1 */ | 500 | }; /* MAC_EVENT_TYPE_API_E_VER_1 */ |
501 | 501 | ||
502 | |||
503 | |||
504 | /* Time event - defines for command API v1 */ | ||
505 | |||
506 | /* | ||
507 | * @TE_V1_FRAG_NONE: fragmentation of the time event is NOT allowed. | ||
508 | * @TE_V1_FRAG_SINGLE: fragmentation of the time event is allowed, but only | ||
509 | * the first fragment is scheduled. | ||
510 | * @TE_V1_FRAG_DUAL: fragmentation of the time event is allowed, but only | ||
511 | * the first 2 fragments are scheduled. | ||
512 | * @TE_V1_FRAG_ENDLESS: fragmentation of the time event is allowed, and any | ||
513 | * number of fragments are valid. | ||
514 | * | ||
515 | * Other than the constant defined above, specifying a fragmentation value 'x' | ||
516 | * means that the event can be fragmented but only the first 'x' will be | ||
517 | * scheduled. | ||
518 | */ | ||
519 | enum { | ||
520 | TE_V1_FRAG_NONE = 0, | ||
521 | TE_V1_FRAG_SINGLE = 1, | ||
522 | TE_V1_FRAG_DUAL = 2, | ||
523 | TE_V1_FRAG_ENDLESS = 0xffffffff | ||
524 | }; | ||
525 | |||
526 | /* If a Time Event can be fragmented, this is the max number of fragments */ | ||
527 | #define TE_V1_FRAG_MAX_MSK 0x0fffffff | ||
528 | /* Repeat the time event endlessly (until removed) */ | ||
529 | #define TE_V1_REPEAT_ENDLESS 0xffffffff | ||
530 | /* If a Time Event has bounded repetitions, this is the maximal value */ | ||
531 | #define TE_V1_REPEAT_MAX_MSK_V1 0x0fffffff | ||
532 | |||
502 | /* Time Event dependencies: none, on another TE, or in a specific time */ | 533 | /* Time Event dependencies: none, on another TE, or in a specific time */ |
503 | enum { | 534 | enum { |
504 | TE_INDEPENDENT = 0, | 535 | TE_V1_INDEPENDENT = 0, |
505 | TE_DEP_OTHER = 1, | 536 | TE_V1_DEP_OTHER = BIT(0), |
506 | TE_DEP_TSF = 2, | 537 | TE_V1_DEP_TSF = BIT(1), |
507 | TE_EVENT_SOCIOPATHIC = 4, | 538 | TE_V1_EVENT_SOCIOPATHIC = BIT(2), |
508 | }; /* MAC_EVENT_DEPENDENCY_POLICY_API_E_VER_2 */ | 539 | }; /* MAC_EVENT_DEPENDENCY_POLICY_API_E_VER_2 */ |
540 | |||
509 | /* | 541 | /* |
542 | * @TE_V1_NOTIF_NONE: no notifications | ||
543 | * @TE_V1_NOTIF_HOST_EVENT_START: request/receive notification on event start | ||
544 | * @TE_V1_NOTIF_HOST_EVENT_END:request/receive notification on event end | ||
545 | * @TE_V1_NOTIF_INTERNAL_EVENT_START: internal FW use | ||
546 | * @TE_V1_NOTIF_INTERNAL_EVENT_END: internal FW use. | ||
547 | * @TE_V1_NOTIF_HOST_FRAG_START: request/receive notification on frag start | ||
548 | * @TE_V1_NOTIF_HOST_FRAG_END:request/receive notification on frag end | ||
549 | * @TE_V1_NOTIF_INTERNAL_FRAG_START: internal FW use. | ||
550 | * @TE_V1_NOTIF_INTERNAL_FRAG_END: internal FW use. | ||
551 | * | ||
510 | * Supported Time event notifications configuration. | 552 | * Supported Time event notifications configuration. |
511 | * A notification (both event and fragment) includes a status indicating weather | 553 | * A notification (both event and fragment) includes a status indicating weather |
512 | * the FW was able to schedule the event or not. For fragment start/end | 554 | * the FW was able to schedule the event or not. For fragment start/end |
513 | * notification the status is always success. There is no start/end fragment | 555 | * notification the status is always success. There is no start/end fragment |
514 | * notification for monolithic events. | 556 | * notification for monolithic events. |
515 | * | ||
516 | * @TE_NOTIF_NONE: no notifications | ||
517 | * @TE_NOTIF_HOST_EVENT_START: request/receive notification on event start | ||
518 | * @TE_NOTIF_HOST_EVENT_END:request/receive notification on event end | ||
519 | * @TE_NOTIF_INTERNAL_EVENT_START: internal FW use | ||
520 | * @TE_NOTIF_INTERNAL_EVENT_END: internal FW use. | ||
521 | * @TE_NOTIF_HOST_FRAG_START: request/receive notification on frag start | ||
522 | * @TE_NOTIF_HOST_FRAG_END:request/receive notification on frag end | ||
523 | * @TE_NOTIF_INTERNAL_FRAG_START: internal FW use. | ||
524 | * @TE_NOTIF_INTERNAL_FRAG_END: internal FW use. | ||
525 | */ | 557 | */ |
526 | enum { | 558 | enum { |
527 | TE_NOTIF_NONE = 0, | 559 | TE_V1_NOTIF_NONE = 0, |
528 | TE_NOTIF_HOST_EVENT_START = 0x1, | 560 | TE_V1_NOTIF_HOST_EVENT_START = BIT(0), |
529 | TE_NOTIF_HOST_EVENT_END = 0x2, | 561 | TE_V1_NOTIF_HOST_EVENT_END = BIT(1), |
530 | TE_NOTIF_INTERNAL_EVENT_START = 0x4, | 562 | TE_V1_NOTIF_INTERNAL_EVENT_START = BIT(2), |
531 | TE_NOTIF_INTERNAL_EVENT_END = 0x8, | 563 | TE_V1_NOTIF_INTERNAL_EVENT_END = BIT(3), |
532 | TE_NOTIF_HOST_FRAG_START = 0x10, | 564 | TE_V1_NOTIF_HOST_FRAG_START = BIT(4), |
533 | TE_NOTIF_HOST_FRAG_END = 0x20, | 565 | TE_V1_NOTIF_HOST_FRAG_END = BIT(5), |
534 | TE_NOTIF_INTERNAL_FRAG_START = 0x40, | 566 | TE_V1_NOTIF_INTERNAL_FRAG_START = BIT(6), |
535 | TE_NOTIF_INTERNAL_FRAG_END = 0x80 | 567 | TE_V1_NOTIF_INTERNAL_FRAG_END = BIT(7), |
536 | }; /* MAC_EVENT_ACTION_API_E_VER_2 */ | 568 | }; /* MAC_EVENT_ACTION_API_E_VER_2 */ |
537 | 569 | ||
570 | |||
571 | /** | ||
572 | * struct iwl_time_event_cmd_api_v1 - configuring Time Events | ||
573 | * with struct MAC_TIME_EVENT_DATA_API_S_VER_1 (see also | ||
574 | * with version 2. determined by IWL_UCODE_TLV_FLAGS) | ||
575 | * ( TIME_EVENT_CMD = 0x29 ) | ||
576 | * @id_and_color: ID and color of the relevant MAC | ||
577 | * @action: action to perform, one of FW_CTXT_ACTION_* | ||
578 | * @id: this field has two meanings, depending on the action: | ||
579 | * If the action is ADD, then it means the type of event to add. | ||
580 | * For all other actions it is the unique event ID assigned when the | ||
581 | * event was added by the FW. | ||
582 | * @apply_time: When to start the Time Event (in GP2) | ||
583 | * @max_delay: maximum delay to event's start (apply time), in TU | ||
584 | * @depends_on: the unique ID of the event we depend on (if any) | ||
585 | * @interval: interval between repetitions, in TU | ||
586 | * @interval_reciprocal: 2^32 / interval | ||
587 | * @duration: duration of event in TU | ||
588 | * @repeat: how many repetitions to do, can be TE_REPEAT_ENDLESS | ||
589 | * @dep_policy: one of TE_V1_INDEPENDENT, TE_V1_DEP_OTHER, TE_V1_DEP_TSF | ||
590 | * and TE_V1_EVENT_SOCIOPATHIC | ||
591 | * @is_present: 0 or 1, are we present or absent during the Time Event | ||
592 | * @max_frags: maximal number of fragments the Time Event can be divided to | ||
593 | * @notify: notifications using TE_V1_NOTIF_* (whom to notify when) | ||
594 | */ | ||
595 | struct iwl_time_event_cmd_v1 { | ||
596 | /* COMMON_INDEX_HDR_API_S_VER_1 */ | ||
597 | __le32 id_and_color; | ||
598 | __le32 action; | ||
599 | __le32 id; | ||
600 | /* MAC_TIME_EVENT_DATA_API_S_VER_1 */ | ||
601 | __le32 apply_time; | ||
602 | __le32 max_delay; | ||
603 | __le32 dep_policy; | ||
604 | __le32 depends_on; | ||
605 | __le32 is_present; | ||
606 | __le32 max_frags; | ||
607 | __le32 interval; | ||
608 | __le32 interval_reciprocal; | ||
609 | __le32 duration; | ||
610 | __le32 repeat; | ||
611 | __le32 notify; | ||
612 | } __packed; /* MAC_TIME_EVENT_CMD_API_S_VER_1 */ | ||
613 | |||
614 | |||
615 | /* Time event - defines for command API v2 */ | ||
616 | |||
538 | /* | 617 | /* |
539 | * @TE_FRAG_NONE: fragmentation of the time event is NOT allowed. | 618 | * @TE_V2_FRAG_NONE: fragmentation of the time event is NOT allowed. |
540 | * @TE_FRAG_SINGLE: fragmentation of the time event is allowed, but only | 619 | * @TE_V2_FRAG_SINGLE: fragmentation of the time event is allowed, but only |
541 | * the first fragment is scheduled. | 620 | * the first fragment is scheduled. |
542 | * @TE_FRAG_DUAL: fragmentation of the time event is allowed, but only | 621 | * @TE_V2_FRAG_DUAL: fragmentation of the time event is allowed, but only |
543 | * the first 2 fragments are scheduled. | 622 | * the first 2 fragments are scheduled. |
544 | * @TE_FRAG_ENDLESS: fragmentation of the time event is allowed, and any number | 623 | * @TE_V2_FRAG_ENDLESS: fragmentation of the time event is allowed, and any |
545 | * of fragments are valid. | 624 | * number of fragments are valid. |
546 | * | 625 | * |
547 | * Other than the constant defined above, specifying a fragmentation value 'x' | 626 | * Other than the constant defined above, specifying a fragmentation value 'x' |
548 | * means that the event can be fragmented but only the first 'x' will be | 627 | * means that the event can be fragmented but only the first 'x' will be |
549 | * scheduled. | 628 | * scheduled. |
550 | */ | 629 | */ |
551 | enum { | 630 | enum { |
552 | TE_FRAG_NONE = 0, | 631 | TE_V2_FRAG_NONE = 0, |
553 | TE_FRAG_SINGLE = 1, | 632 | TE_V2_FRAG_SINGLE = 1, |
554 | TE_FRAG_DUAL = 2, | 633 | TE_V2_FRAG_DUAL = 2, |
555 | TE_FRAG_ENDLESS = 0xffffffff | 634 | TE_V2_FRAG_MAX = 0xfe, |
635 | TE_V2_FRAG_ENDLESS = 0xff | ||
556 | }; | 636 | }; |
557 | 637 | ||
558 | /* Repeat the time event endlessly (until removed) */ | 638 | /* Repeat the time event endlessly (until removed) */ |
559 | #define TE_REPEAT_ENDLESS (0xffffffff) | 639 | #define TE_V2_REPEAT_ENDLESS 0xff |
560 | /* If a Time Event has bounded repetitions, this is the maximal value */ | 640 | /* If a Time Event has bounded repetitions, this is the maximal value */ |
561 | #define TE_REPEAT_MAX_MSK (0x0fffffff) | 641 | #define TE_V2_REPEAT_MAX 0xfe |
562 | /* If a Time Event can be fragmented, this is the max number of fragments */ | 642 | |
563 | #define TE_FRAG_MAX_MSK (0x0fffffff) | 643 | #define TE_V2_PLACEMENT_POS 12 |
644 | #define TE_V2_ABSENCE_POS 15 | ||
645 | |||
646 | /* Time event policy values (for time event cmd api v2) | ||
647 | * A notification (both event and fragment) includes a status indicating weather | ||
648 | * the FW was able to schedule the event or not. For fragment start/end | ||
649 | * notification the status is always success. There is no start/end fragment | ||
650 | * notification for monolithic events. | ||
651 | * | ||
652 | * @TE_V2_DEFAULT_POLICY: independent, social, present, unoticable | ||
653 | * @TE_V2_NOTIF_HOST_EVENT_START: request/receive notification on event start | ||
654 | * @TE_V2_NOTIF_HOST_EVENT_END:request/receive notification on event end | ||
655 | * @TE_V2_NOTIF_INTERNAL_EVENT_START: internal FW use | ||
656 | * @TE_V2_NOTIF_INTERNAL_EVENT_END: internal FW use. | ||
657 | * @TE_V2_NOTIF_HOST_FRAG_START: request/receive notification on frag start | ||
658 | * @TE_V2_NOTIF_HOST_FRAG_END:request/receive notification on frag end | ||
659 | * @TE_V2_NOTIF_INTERNAL_FRAG_START: internal FW use. | ||
660 | * @TE_V2_NOTIF_INTERNAL_FRAG_END: internal FW use. | ||
661 | * @TE_V2_DEP_OTHER: depends on another time event | ||
662 | * @TE_V2_DEP_TSF: depends on a specific time | ||
663 | * @TE_V2_EVENT_SOCIOPATHIC: can't co-exist with other events of tha same MAC | ||
664 | * @TE_V2_ABSENCE: are we present or absent during the Time Event. | ||
665 | */ | ||
666 | enum { | ||
667 | TE_V2_DEFAULT_POLICY = 0x0, | ||
668 | |||
669 | /* notifications (event start/stop, fragment start/stop) */ | ||
670 | TE_V2_NOTIF_HOST_EVENT_START = BIT(0), | ||
671 | TE_V2_NOTIF_HOST_EVENT_END = BIT(1), | ||
672 | TE_V2_NOTIF_INTERNAL_EVENT_START = BIT(2), | ||
673 | TE_V2_NOTIF_INTERNAL_EVENT_END = BIT(3), | ||
674 | |||
675 | TE_V2_NOTIF_HOST_FRAG_START = BIT(4), | ||
676 | TE_V2_NOTIF_HOST_FRAG_END = BIT(5), | ||
677 | TE_V2_NOTIF_INTERNAL_FRAG_START = BIT(6), | ||
678 | TE_V2_NOTIF_INTERNAL_FRAG_END = BIT(7), | ||
679 | |||
680 | TE_V2_NOTIF_MSK = 0xff, | ||
681 | |||
682 | /* placement characteristics */ | ||
683 | TE_V2_DEP_OTHER = BIT(TE_V2_PLACEMENT_POS), | ||
684 | TE_V2_DEP_TSF = BIT(TE_V2_PLACEMENT_POS + 1), | ||
685 | TE_V2_EVENT_SOCIOPATHIC = BIT(TE_V2_PLACEMENT_POS + 2), | ||
686 | |||
687 | /* are we present or absent during the Time Event. */ | ||
688 | TE_V2_ABSENCE = BIT(TE_V2_ABSENCE_POS), | ||
689 | }; | ||
564 | 690 | ||
565 | /** | 691 | /** |
566 | * struct iwl_time_event_cmd - configuring Time Events | 692 | * struct iwl_time_event_cmd_api_v2 - configuring Time Events |
693 | * with struct MAC_TIME_EVENT_DATA_API_S_VER_2 (see also | ||
694 | * with version 1. determined by IWL_UCODE_TLV_FLAGS) | ||
567 | * ( TIME_EVENT_CMD = 0x29 ) | 695 | * ( TIME_EVENT_CMD = 0x29 ) |
568 | * @id_and_color: ID and color of the relevant MAC | 696 | * @id_and_color: ID and color of the relevant MAC |
569 | * @action: action to perform, one of FW_CTXT_ACTION_* | 697 | * @action: action to perform, one of FW_CTXT_ACTION_* |
@@ -575,32 +703,30 @@ enum { | |||
575 | * @max_delay: maximum delay to event's start (apply time), in TU | 703 | * @max_delay: maximum delay to event's start (apply time), in TU |
576 | * @depends_on: the unique ID of the event we depend on (if any) | 704 | * @depends_on: the unique ID of the event we depend on (if any) |
577 | * @interval: interval between repetitions, in TU | 705 | * @interval: interval between repetitions, in TU |
578 | * @interval_reciprocal: 2^32 / interval | ||
579 | * @duration: duration of event in TU | 706 | * @duration: duration of event in TU |
580 | * @repeat: how many repetitions to do, can be TE_REPEAT_ENDLESS | 707 | * @repeat: how many repetitions to do, can be TE_REPEAT_ENDLESS |
581 | * @dep_policy: one of TE_INDEPENDENT, TE_DEP_OTHER, TE_DEP_TSF | ||
582 | * @is_present: 0 or 1, are we present or absent during the Time Event | ||
583 | * @max_frags: maximal number of fragments the Time Event can be divided to | 708 | * @max_frags: maximal number of fragments the Time Event can be divided to |
584 | * @notify: notifications using TE_NOTIF_* (whom to notify when) | 709 | * @policy: defines whether uCode shall notify the host or other uCode modules |
710 | * on event and/or fragment start and/or end | ||
711 | * using one of TE_INDEPENDENT, TE_DEP_OTHER, TE_DEP_TSF | ||
712 | * TE_EVENT_SOCIOPATHIC | ||
713 | * using TE_ABSENCE and using TE_NOTIF_* | ||
585 | */ | 714 | */ |
586 | struct iwl_time_event_cmd { | 715 | struct iwl_time_event_cmd_v2 { |
587 | /* COMMON_INDEX_HDR_API_S_VER_1 */ | 716 | /* COMMON_INDEX_HDR_API_S_VER_1 */ |
588 | __le32 id_and_color; | 717 | __le32 id_and_color; |
589 | __le32 action; | 718 | __le32 action; |
590 | __le32 id; | 719 | __le32 id; |
591 | /* MAC_TIME_EVENT_DATA_API_S_VER_1 */ | 720 | /* MAC_TIME_EVENT_DATA_API_S_VER_2 */ |
592 | __le32 apply_time; | 721 | __le32 apply_time; |
593 | __le32 max_delay; | 722 | __le32 max_delay; |
594 | __le32 dep_policy; | ||
595 | __le32 depends_on; | 723 | __le32 depends_on; |
596 | __le32 is_present; | ||
597 | __le32 max_frags; | ||
598 | __le32 interval; | 724 | __le32 interval; |
599 | __le32 interval_reciprocal; | ||
600 | __le32 duration; | 725 | __le32 duration; |
601 | __le32 repeat; | 726 | u8 repeat; |
602 | __le32 notify; | 727 | u8 max_frags; |
603 | } __packed; /* MAC_TIME_EVENT_CMD_API_S_VER_1 */ | 728 | __le16 policy; |
729 | } __packed; /* MAC_TIME_EVENT_CMD_API_S_VER_2 */ | ||
604 | 730 | ||
605 | /** | 731 | /** |
606 | * struct iwl_time_event_resp - response structure to iwl_time_event_cmd | 732 | * struct iwl_time_event_resp - response structure to iwl_time_event_cmd |
diff --git a/drivers/net/wireless/iwlwifi/mvm/time-event.c b/drivers/net/wireless/iwlwifi/mvm/time-event.c index ad9bbca99213..7ed94a089d5e 100644 --- a/drivers/net/wireless/iwlwifi/mvm/time-event.c +++ b/drivers/net/wireless/iwlwifi/mvm/time-event.c | |||
@@ -166,7 +166,7 @@ static void iwl_mvm_te_handle_notif(struct iwl_mvm *mvm, | |||
166 | WARN_ONCE(!le32_to_cpu(notif->status), | 166 | WARN_ONCE(!le32_to_cpu(notif->status), |
167 | "Failed to schedule time event\n"); | 167 | "Failed to schedule time event\n"); |
168 | 168 | ||
169 | if (le32_to_cpu(notif->action) & TE_NOTIF_HOST_EVENT_END) { | 169 | if (le32_to_cpu(notif->action) & TE_V2_NOTIF_HOST_EVENT_END) { |
170 | IWL_DEBUG_TE(mvm, | 170 | IWL_DEBUG_TE(mvm, |
171 | "TE ended - current time %lu, estimated end %lu\n", | 171 | "TE ended - current time %lu, estimated end %lu\n", |
172 | jiffies, te_data->end_jiffies); | 172 | jiffies, te_data->end_jiffies); |
@@ -189,7 +189,7 @@ static void iwl_mvm_te_handle_notif(struct iwl_mvm *mvm, | |||
189 | } | 189 | } |
190 | 190 | ||
191 | iwl_mvm_te_clear_data(mvm, te_data); | 191 | iwl_mvm_te_clear_data(mvm, te_data); |
192 | } else if (le32_to_cpu(notif->action) & TE_NOTIF_HOST_EVENT_START) { | 192 | } else if (le32_to_cpu(notif->action) & TE_V2_NOTIF_HOST_EVENT_START) { |
193 | te_data->running = true; | 193 | te_data->running = true; |
194 | te_data->end_jiffies = jiffies + | 194 | te_data->end_jiffies = jiffies + |
195 | TU_TO_JIFFIES(te_data->duration); | 195 | TU_TO_JIFFIES(te_data->duration); |
@@ -257,10 +257,67 @@ static bool iwl_mvm_time_event_response(struct iwl_notif_wait_data *notif_wait, | |||
257 | return true; | 257 | return true; |
258 | } | 258 | } |
259 | 259 | ||
260 | /* used to convert from time event API v2 to v1 */ | ||
261 | #define TE_V2_DEP_POLICY_MSK (TE_V2_DEP_OTHER | TE_V2_DEP_TSF |\ | ||
262 | TE_V2_EVENT_SOCIOPATHIC) | ||
263 | static inline u16 te_v2_get_notify(__le16 policy) | ||
264 | { | ||
265 | return le16_to_cpu(policy) & TE_V2_NOTIF_MSK; | ||
266 | } | ||
267 | |||
268 | static inline u16 te_v2_get_dep_policy(__le16 policy) | ||
269 | { | ||
270 | return (le16_to_cpu(policy) & TE_V2_DEP_POLICY_MSK) >> | ||
271 | TE_V2_PLACEMENT_POS; | ||
272 | } | ||
273 | |||
274 | static inline u16 te_v2_get_absence(__le16 policy) | ||
275 | { | ||
276 | return (le16_to_cpu(policy) & TE_V2_ABSENCE) >> TE_V2_ABSENCE_POS; | ||
277 | } | ||
278 | |||
279 | static void iwl_mvm_te_v2_to_v1(const struct iwl_time_event_cmd_v2 *cmd_v2, | ||
280 | struct iwl_time_event_cmd_v1 *cmd_v1) | ||
281 | { | ||
282 | cmd_v1->id_and_color = cmd_v2->id_and_color; | ||
283 | cmd_v1->action = cmd_v2->action; | ||
284 | cmd_v1->id = cmd_v2->id; | ||
285 | cmd_v1->apply_time = cmd_v2->apply_time; | ||
286 | cmd_v1->max_delay = cmd_v2->max_delay; | ||
287 | cmd_v1->depends_on = cmd_v2->depends_on; | ||
288 | cmd_v1->interval = cmd_v2->interval; | ||
289 | cmd_v1->duration = cmd_v2->duration; | ||
290 | if (cmd_v2->repeat == TE_V2_REPEAT_ENDLESS) | ||
291 | cmd_v1->repeat = cpu_to_le32(TE_V1_REPEAT_ENDLESS); | ||
292 | else | ||
293 | cmd_v1->repeat = cpu_to_le32(cmd_v2->repeat); | ||
294 | cmd_v1->max_frags = cpu_to_le32(cmd_v2->max_frags); | ||
295 | cmd_v1->interval_reciprocal = 0; /* unused */ | ||
296 | |||
297 | cmd_v1->dep_policy = cpu_to_le32(te_v2_get_dep_policy(cmd_v2->policy)); | ||
298 | cmd_v1->is_present = cpu_to_le32(!te_v2_get_absence(cmd_v2->policy)); | ||
299 | cmd_v1->notify = cpu_to_le32(te_v2_get_notify(cmd_v2->policy)); | ||
300 | } | ||
301 | |||
302 | static int iwl_mvm_send_time_event_cmd(struct iwl_mvm *mvm, | ||
303 | const struct iwl_time_event_cmd_v2 *cmd) | ||
304 | { | ||
305 | struct iwl_time_event_cmd_v1 cmd_v1; | ||
306 | |||
307 | if (mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_TIME_EVENT_API_V2) | ||
308 | return iwl_mvm_send_cmd_pdu(mvm, TIME_EVENT_CMD, CMD_SYNC, | ||
309 | sizeof(*cmd), cmd); | ||
310 | |||
311 | iwl_mvm_te_v2_to_v1(cmd, &cmd_v1); | ||
312 | return iwl_mvm_send_cmd_pdu(mvm, TIME_EVENT_CMD, CMD_SYNC, | ||
313 | sizeof(cmd_v1), &cmd_v1); | ||
314 | } | ||
315 | |||
316 | |||
260 | static int iwl_mvm_time_event_send_add(struct iwl_mvm *mvm, | 317 | static int iwl_mvm_time_event_send_add(struct iwl_mvm *mvm, |
261 | struct ieee80211_vif *vif, | 318 | struct ieee80211_vif *vif, |
262 | struct iwl_mvm_time_event_data *te_data, | 319 | struct iwl_mvm_time_event_data *te_data, |
263 | struct iwl_time_event_cmd *te_cmd) | 320 | struct iwl_time_event_cmd_v2 *te_cmd) |
264 | { | 321 | { |
265 | static const u8 time_event_response[] = { TIME_EVENT_CMD }; | 322 | static const u8 time_event_response[] = { TIME_EVENT_CMD }; |
266 | struct iwl_notification_wait wait_time_event; | 323 | struct iwl_notification_wait wait_time_event; |
@@ -296,8 +353,7 @@ static int iwl_mvm_time_event_send_add(struct iwl_mvm *mvm, | |||
296 | ARRAY_SIZE(time_event_response), | 353 | ARRAY_SIZE(time_event_response), |
297 | iwl_mvm_time_event_response, te_data); | 354 | iwl_mvm_time_event_response, te_data); |
298 | 355 | ||
299 | ret = iwl_mvm_send_cmd_pdu(mvm, TIME_EVENT_CMD, CMD_SYNC, | 356 | ret = iwl_mvm_send_time_event_cmd(mvm, te_cmd); |
300 | sizeof(*te_cmd), te_cmd); | ||
301 | if (ret) { | 357 | if (ret) { |
302 | IWL_ERR(mvm, "Couldn't send TIME_EVENT_CMD: %d\n", ret); | 358 | IWL_ERR(mvm, "Couldn't send TIME_EVENT_CMD: %d\n", ret); |
303 | iwl_remove_notification(&mvm->notif_wait, &wait_time_event); | 359 | iwl_remove_notification(&mvm->notif_wait, &wait_time_event); |
@@ -324,7 +380,7 @@ void iwl_mvm_protect_session(struct iwl_mvm *mvm, | |||
324 | { | 380 | { |
325 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); | 381 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); |
326 | struct iwl_mvm_time_event_data *te_data = &mvmvif->time_event_data; | 382 | struct iwl_mvm_time_event_data *te_data = &mvmvif->time_event_data; |
327 | struct iwl_time_event_cmd time_cmd = {}; | 383 | struct iwl_time_event_cmd_v2 time_cmd = {}; |
328 | 384 | ||
329 | lockdep_assert_held(&mvm->mutex); | 385 | lockdep_assert_held(&mvm->mutex); |
330 | 386 | ||
@@ -359,17 +415,14 @@ void iwl_mvm_protect_session(struct iwl_mvm *mvm, | |||
359 | time_cmd.apply_time = | 415 | time_cmd.apply_time = |
360 | cpu_to_le32(iwl_read_prph(mvm->trans, DEVICE_SYSTEM_TIME_REG)); | 416 | cpu_to_le32(iwl_read_prph(mvm->trans, DEVICE_SYSTEM_TIME_REG)); |
361 | 417 | ||
362 | time_cmd.dep_policy = TE_INDEPENDENT; | 418 | time_cmd.max_frags = TE_V2_FRAG_NONE; |
363 | time_cmd.is_present = cpu_to_le32(1); | ||
364 | time_cmd.max_frags = cpu_to_le32(TE_FRAG_NONE); | ||
365 | time_cmd.max_delay = cpu_to_le32(500); | 419 | time_cmd.max_delay = cpu_to_le32(500); |
366 | /* TODO: why do we need to interval = bi if it is not periodic? */ | 420 | /* TODO: why do we need to interval = bi if it is not periodic? */ |
367 | time_cmd.interval = cpu_to_le32(1); | 421 | time_cmd.interval = cpu_to_le32(1); |
368 | time_cmd.interval_reciprocal = cpu_to_le32(iwl_mvm_reciprocal(1)); | ||
369 | time_cmd.duration = cpu_to_le32(duration); | 422 | time_cmd.duration = cpu_to_le32(duration); |
370 | time_cmd.repeat = cpu_to_le32(1); | 423 | time_cmd.repeat = 1; |
371 | time_cmd.notify = cpu_to_le32(TE_NOTIF_HOST_EVENT_START | | 424 | time_cmd.policy = cpu_to_le16(TE_V2_NOTIF_HOST_EVENT_START | |
372 | TE_NOTIF_HOST_EVENT_END); | 425 | TE_V2_NOTIF_HOST_EVENT_END); |
373 | 426 | ||
374 | iwl_mvm_time_event_send_add(mvm, vif, te_data, &time_cmd); | 427 | iwl_mvm_time_event_send_add(mvm, vif, te_data, &time_cmd); |
375 | } | 428 | } |
@@ -383,7 +436,7 @@ void iwl_mvm_remove_time_event(struct iwl_mvm *mvm, | |||
383 | struct iwl_mvm_vif *mvmvif, | 436 | struct iwl_mvm_vif *mvmvif, |
384 | struct iwl_mvm_time_event_data *te_data) | 437 | struct iwl_mvm_time_event_data *te_data) |
385 | { | 438 | { |
386 | struct iwl_time_event_cmd time_cmd = {}; | 439 | struct iwl_time_event_cmd_v2 time_cmd = {}; |
387 | u32 id, uid; | 440 | u32 id, uid; |
388 | int ret; | 441 | int ret; |
389 | 442 | ||
@@ -420,8 +473,7 @@ void iwl_mvm_remove_time_event(struct iwl_mvm *mvm, | |||
420 | cpu_to_le32(FW_CMD_ID_AND_COLOR(mvmvif->id, mvmvif->color)); | 473 | cpu_to_le32(FW_CMD_ID_AND_COLOR(mvmvif->id, mvmvif->color)); |
421 | 474 | ||
422 | IWL_DEBUG_TE(mvm, "Removing TE 0x%x\n", le32_to_cpu(time_cmd.id)); | 475 | IWL_DEBUG_TE(mvm, "Removing TE 0x%x\n", le32_to_cpu(time_cmd.id)); |
423 | ret = iwl_mvm_send_cmd_pdu(mvm, TIME_EVENT_CMD, CMD_SYNC, | 476 | ret = iwl_mvm_send_time_event_cmd(mvm, &time_cmd); |
424 | sizeof(time_cmd), &time_cmd); | ||
425 | if (WARN_ON(ret)) | 477 | if (WARN_ON(ret)) |
426 | return; | 478 | return; |
427 | } | 479 | } |
@@ -441,7 +493,7 @@ int iwl_mvm_start_p2p_roc(struct iwl_mvm *mvm, struct ieee80211_vif *vif, | |||
441 | { | 493 | { |
442 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); | 494 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); |
443 | struct iwl_mvm_time_event_data *te_data = &mvmvif->time_event_data; | 495 | struct iwl_mvm_time_event_data *te_data = &mvmvif->time_event_data; |
444 | struct iwl_time_event_cmd time_cmd = {}; | 496 | struct iwl_time_event_cmd_v2 time_cmd = {}; |
445 | 497 | ||
446 | lockdep_assert_held(&mvm->mutex); | 498 | lockdep_assert_held(&mvm->mutex); |
447 | if (te_data->running) { | 499 | if (te_data->running) { |
@@ -472,8 +524,6 @@ int iwl_mvm_start_p2p_roc(struct iwl_mvm *mvm, struct ieee80211_vif *vif, | |||
472 | } | 524 | } |
473 | 525 | ||
474 | time_cmd.apply_time = cpu_to_le32(0); | 526 | time_cmd.apply_time = cpu_to_le32(0); |
475 | time_cmd.dep_policy = cpu_to_le32(TE_INDEPENDENT); | ||
476 | time_cmd.is_present = cpu_to_le32(1); | ||
477 | time_cmd.interval = cpu_to_le32(1); | 527 | time_cmd.interval = cpu_to_le32(1); |
478 | 528 | ||
479 | /* | 529 | /* |
@@ -482,12 +532,12 @@ int iwl_mvm_start_p2p_roc(struct iwl_mvm *mvm, struct ieee80211_vif *vif, | |||
482 | * scheduled. To improve the chances of it being scheduled, allow them | 532 | * scheduled. To improve the chances of it being scheduled, allow them |
483 | * to be fragmented, and in addition allow them to be delayed. | 533 | * to be fragmented, and in addition allow them to be delayed. |
484 | */ | 534 | */ |
485 | time_cmd.max_frags = cpu_to_le32(MSEC_TO_TU(duration)/20); | 535 | time_cmd.max_frags = min(MSEC_TO_TU(duration)/50, TE_V2_FRAG_ENDLESS); |
486 | time_cmd.max_delay = cpu_to_le32(MSEC_TO_TU(duration/2)); | 536 | time_cmd.max_delay = cpu_to_le32(MSEC_TO_TU(duration/2)); |
487 | time_cmd.duration = cpu_to_le32(MSEC_TO_TU(duration)); | 537 | time_cmd.duration = cpu_to_le32(MSEC_TO_TU(duration)); |
488 | time_cmd.repeat = cpu_to_le32(1); | 538 | time_cmd.repeat = 1; |
489 | time_cmd.notify = cpu_to_le32(TE_NOTIF_HOST_EVENT_START | | 539 | time_cmd.policy = cpu_to_le16(TE_V2_NOTIF_HOST_EVENT_START | |
490 | TE_NOTIF_HOST_EVENT_END); | 540 | TE_V2_NOTIF_HOST_EVENT_END); |
491 | 541 | ||
492 | return iwl_mvm_time_event_send_add(mvm, vif, te_data, &time_cmd); | 542 | return iwl_mvm_time_event_send_add(mvm, vif, te_data, &time_cmd); |
493 | } | 543 | } |