aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJohannes Berg <johannes.berg@intel.com>2013-01-22 07:02:09 -0500
committerJohannes Berg <johannes.berg@intel.com>2013-02-12 10:52:25 -0500
commit9b26b5002937850846046a99de8c6065ff86fa6d (patch)
tree068c55f80755b4c2e7a75fc0ffe89f5309f3acb0
parent5718d27fc9a076ca397ea8c3d70e29969be24b9b (diff)
iwlwifi: mvm: report wakeup reasons
Query the wakeup reasons properly and then report them to mac80211. Reviewed-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com> Signed-off-by: Johannes Berg <johannes.berg@intel.com>
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/d3.c168
1 files changed, 141 insertions, 27 deletions
diff --git a/drivers/net/wireless/iwlwifi/mvm/d3.c b/drivers/net/wireless/iwlwifi/mvm/d3.c
index 5b2c675a8752..a00267f6bc05 100644
--- a/drivers/net/wireless/iwlwifi/mvm/d3.c
+++ b/drivers/net/wireless/iwlwifi/mvm/d3.c
@@ -763,6 +763,146 @@ int iwl_mvm_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan)
763 return ret; 763 return ret;
764} 764}
765 765
766static void iwl_mvm_query_wakeup_reasons(struct iwl_mvm *mvm,
767 struct ieee80211_vif *vif)
768{
769 u32 base = mvm->error_event_table;
770 struct error_table_start {
771 /* cf. struct iwl_error_event_table */
772 u32 valid;
773 u32 error_id;
774 } err_info;
775 struct cfg80211_wowlan_wakeup wakeup = {
776 .pattern_idx = -1,
777 };
778 struct cfg80211_wowlan_wakeup *wakeup_report = &wakeup;
779 struct iwl_host_cmd cmd = {
780 .id = WOWLAN_GET_STATUSES,
781 .flags = CMD_SYNC | CMD_WANT_SKB,
782 };
783 struct iwl_wowlan_status *status;
784 u32 reasons;
785 int ret, len;
786 bool pkt8023 = false;
787 struct sk_buff *pkt = NULL;
788
789 iwl_trans_read_mem_bytes(mvm->trans, base,
790 &err_info, sizeof(err_info));
791
792 if (err_info.valid) {
793 IWL_INFO(mvm, "error table is valid (%d)\n",
794 err_info.valid);
795 if (err_info.error_id == RF_KILL_INDICATOR_FOR_WOWLAN) {
796 wakeup.rfkill_release = true;
797 ieee80211_report_wowlan_wakeup(vif, &wakeup,
798 GFP_KERNEL);
799 }
800 return;
801 }
802
803 /* only for tracing for now */
804 ret = iwl_mvm_send_cmd_pdu(mvm, OFFLOADS_QUERY_CMD, CMD_SYNC, 0, NULL);
805 if (ret)
806 IWL_ERR(mvm, "failed to query offload statistics (%d)\n", ret);
807
808 ret = iwl_mvm_send_cmd(mvm, &cmd);
809 if (ret) {
810 IWL_ERR(mvm, "failed to query status (%d)\n", ret);
811 return;
812 }
813
814 /* RF-kill already asserted again... */
815 if (!cmd.resp_pkt)
816 return;
817
818 len = le32_to_cpu(cmd.resp_pkt->len_n_flags) & FH_RSCSR_FRAME_SIZE_MSK;
819 if (len - sizeof(struct iwl_cmd_header) < sizeof(*status)) {
820 IWL_ERR(mvm, "Invalid WoWLAN status response!\n");
821 goto out;
822 }
823
824 status = (void *)cmd.resp_pkt->data;
825
826 if (len - sizeof(struct iwl_cmd_header) !=
827 sizeof(*status) + le32_to_cpu(status->wake_packet_bufsize)) {
828 IWL_ERR(mvm, "Invalid WoWLAN status response!\n");
829 goto out;
830 }
831
832 reasons = le32_to_cpu(status->wakeup_reasons);
833
834 if (reasons == IWL_WOWLAN_WAKEUP_BY_NON_WIRELESS) {
835 wakeup_report = NULL;
836 goto report;
837 }
838
839 if (reasons & IWL_WOWLAN_WAKEUP_BY_MAGIC_PACKET) {
840 wakeup.magic_pkt = true;
841 pkt8023 = true;
842 }
843
844 if (reasons & IWL_WOWLAN_WAKEUP_BY_PATTERN) {
845 wakeup.pattern_idx =
846 le16_to_cpu(status->pattern_number);
847 pkt8023 = true;
848 }
849
850 if (reasons & (IWL_WOWLAN_WAKEUP_BY_DISCONNECTION_ON_MISSED_BEACON |
851 IWL_WOWLAN_WAKEUP_BY_DISCONNECTION_ON_DEAUTH))
852 wakeup.disconnect = true;
853
854 if (reasons & IWL_WOWLAN_WAKEUP_BY_GTK_REKEY_FAILURE) {
855 wakeup.gtk_rekey_failure = true;
856 pkt8023 = true;
857 }
858
859 if (reasons & IWL_WOWLAN_WAKEUP_BY_RFKILL_DEASSERTED) {
860 wakeup.rfkill_release = true;
861 pkt8023 = true;
862 }
863
864 if (reasons & IWL_WOWLAN_WAKEUP_BY_EAPOL_REQUEST) {
865 wakeup.eap_identity_req = true;
866 pkt8023 = true;
867 }
868
869 if (reasons & IWL_WOWLAN_WAKEUP_BY_FOUR_WAY_HANDSHAKE) {
870 wakeup.four_way_handshake = true;
871 pkt8023 = true;
872 }
873
874 if (status->wake_packet_bufsize) {
875 u32 pktsize = le32_to_cpu(status->wake_packet_bufsize);
876 u32 pktlen = le32_to_cpu(status->wake_packet_length);
877
878 if (pkt8023) {
879 pkt = alloc_skb(pktsize, GFP_KERNEL);
880 if (!pkt)
881 goto report;
882 memcpy(skb_put(pkt, pktsize), status->wake_packet,
883 pktsize);
884 if (ieee80211_data_to_8023(pkt, vif->addr, vif->type))
885 goto report;
886 wakeup.packet = pkt->data;
887 wakeup.packet_present_len = pkt->len;
888 wakeup.packet_len = pkt->len - (pktlen - pktsize);
889 wakeup.packet_80211 = false;
890 } else {
891 wakeup.packet = status->wake_packet;
892 wakeup.packet_present_len = pktsize;
893 wakeup.packet_len = pktlen;
894 wakeup.packet_80211 = true;
895 }
896 }
897
898 report:
899 ieee80211_report_wowlan_wakeup(vif, wakeup_report, GFP_KERNEL);
900 kfree_skb(pkt);
901
902 out:
903 iwl_free_resp(&cmd);
904}
905
766int iwl_mvm_resume(struct ieee80211_hw *hw) 906int iwl_mvm_resume(struct ieee80211_hw *hw)
767{ 907{
768 struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); 908 struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
@@ -770,14 +910,8 @@ int iwl_mvm_resume(struct ieee80211_hw *hw)
770 .mvm = mvm, 910 .mvm = mvm,
771 }; 911 };
772 struct ieee80211_vif *vif = NULL; 912 struct ieee80211_vif *vif = NULL;
773 u32 base;
774 int ret; 913 int ret;
775 enum iwl_d3_status d3_status; 914 enum iwl_d3_status d3_status;
776 struct error_table_start {
777 /* cf. struct iwl_error_event_table */
778 u32 valid;
779 u32 error_id;
780 } err_info;
781 915
782 mutex_lock(&mvm->mutex); 916 mutex_lock(&mvm->mutex);
783 917
@@ -800,27 +934,7 @@ int iwl_mvm_resume(struct ieee80211_hw *hw)
800 goto out_unlock; 934 goto out_unlock;
801 } 935 }
802 936
803 base = mvm->error_event_table; 937 iwl_mvm_query_wakeup_reasons(mvm, vif);
804
805 iwl_trans_read_mem_bytes(mvm->trans, base,
806 &err_info, sizeof(err_info));
807
808 if (err_info.valid) {
809 IWL_INFO(mvm, "error table is valid (%d)\n",
810 err_info.valid);
811 if (err_info.error_id == RF_KILL_INDICATOR_FOR_WOWLAN)
812 IWL_ERR(mvm, "this was due to RF-kill\n");
813 goto out_unlock;
814 }
815
816 /* TODO: get status and whatever else ... */
817 ret = iwl_mvm_send_cmd_pdu(mvm, WOWLAN_GET_STATUSES, CMD_SYNC, 0, NULL);
818 if (ret)
819 IWL_ERR(mvm, "failed to query status (%d)\n", ret);
820
821 ret = iwl_mvm_send_cmd_pdu(mvm, OFFLOADS_QUERY_CMD, CMD_SYNC, 0, NULL);
822 if (ret)
823 IWL_ERR(mvm, "failed to query offloads (%d)\n", ret);
824 938
825 out_unlock: 939 out_unlock:
826 mutex_unlock(&mvm->mutex); 940 mutex_unlock(&mvm->mutex);