aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLuciano Coelho <luciano.coelho@intel.com>2014-11-21 15:08:01 -0500
committerEmmanuel Grumbach <emmanuel.grumbach@intel.com>2014-12-01 05:04:42 -0500
commit8ed4e659f34c963f7398ca1c92a1ab9593afba83 (patch)
tree4edc07a14dd4db79f1aa30a9a4b5c9379eb82f2b
parentd9718da82f595eeac0cd42d849f7c3adc02da5e3 (diff)
iwlwifi: mvm: add channel information to the netdetect notifications
Add the channels on which there was a match for every match reported by the firmware. The firmware reports the channels as indices to the array of channels that was passed in the scheduled scan request, so we need to save the array when entering D3 to make sure it is available when we resume. Signed-off-by: Luciano Coelho <luciano.coelho@intel.com> Reviewed-by: Johannes Berg <johannes.berg@intel.com> Signed-off-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/d3.c63
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/mvm.h2
2 files changed, 54 insertions, 11 deletions
diff --git a/drivers/net/wireless/iwlwifi/mvm/d3.c b/drivers/net/wireless/iwlwifi/mvm/d3.c
index c20d8de40fcd..744de262373e 100644
--- a/drivers/net/wireless/iwlwifi/mvm/d3.c
+++ b/drivers/net/wireless/iwlwifi/mvm/d3.c
@@ -982,10 +982,10 @@ iwl_mvm_netdetect_config(struct iwl_mvm *mvm,
982 if (ret) 982 if (ret)
983 return ret; 983 return ret;
984 984
985 if (WARN_ON(mvm->nd_match_sets)) 985 if (WARN_ON(mvm->nd_match_sets || mvm->nd_channels))
986 return -EBUSY; 986 return -EBUSY;
987 987
988 /* save the sched scan matchsets for later reporting */ 988 /* save the sched scan matchsets... */
989 if (nd_config->n_match_sets) { 989 if (nd_config->n_match_sets) {
990 mvm->nd_match_sets = kmemdup(nd_config->match_sets, 990 mvm->nd_match_sets = kmemdup(nd_config->match_sets,
991 sizeof(*nd_config->match_sets) * 991 sizeof(*nd_config->match_sets) *
@@ -995,6 +995,14 @@ iwl_mvm_netdetect_config(struct iwl_mvm *mvm,
995 mvm->n_nd_match_sets = nd_config->n_match_sets; 995 mvm->n_nd_match_sets = nd_config->n_match_sets;
996 } 996 }
997 997
998 /* ...and the sched scan channels for later reporting */
999 mvm->nd_channels = kmemdup(nd_config->channels,
1000 sizeof(*nd_config->channels) *
1001 nd_config->n_channels,
1002 GFP_KERNEL);
1003 if (mvm->nd_channels)
1004 mvm->n_nd_channels = nd_config->n_channels;
1005
998 return 0; 1006 return 0;
999} 1007}
1000 1008
@@ -1003,6 +1011,9 @@ static void iwl_mvm_free_nd(struct iwl_mvm *mvm)
1003 kfree(mvm->nd_match_sets); 1011 kfree(mvm->nd_match_sets);
1004 mvm->nd_match_sets = NULL; 1012 mvm->nd_match_sets = NULL;
1005 mvm->n_nd_match_sets = 0; 1013 mvm->n_nd_match_sets = 0;
1014 kfree(mvm->nd_channels);
1015 mvm->nd_channels = NULL;
1016 mvm->n_nd_channels = 0;
1006} 1017}
1007 1018
1008static int __iwl_mvm_suspend(struct ieee80211_hw *hw, 1019static int __iwl_mvm_suspend(struct ieee80211_hw *hw,
@@ -1640,7 +1651,14 @@ out_unlock:
1640 return false; 1651 return false;
1641} 1652}
1642 1653
1643static u32 iwl_mvm_netdetect_query_results(struct iwl_mvm *mvm) 1654struct iwl_mvm_nd_query_results {
1655 u32 matched_profiles;
1656 struct iwl_scan_offload_profile_match matches[IWL_SCAN_MAX_PROFILES];
1657};
1658
1659static int
1660iwl_mvm_netdetect_query_results(struct iwl_mvm *mvm,
1661 struct iwl_mvm_nd_query_results *results)
1644{ 1662{
1645 struct iwl_scan_offload_profiles_query *query; 1663 struct iwl_scan_offload_profiles_query *query;
1646 struct iwl_host_cmd cmd = { 1664 struct iwl_host_cmd cmd = {
@@ -1652,22 +1670,26 @@ static u32 iwl_mvm_netdetect_query_results(struct iwl_mvm *mvm)
1652 ret = iwl_mvm_send_cmd(mvm, &cmd); 1670 ret = iwl_mvm_send_cmd(mvm, &cmd);
1653 if (ret) { 1671 if (ret) {
1654 IWL_ERR(mvm, "failed to query matched profiles (%d)\n", ret); 1672 IWL_ERR(mvm, "failed to query matched profiles (%d)\n", ret);
1655 return 0; 1673 return ret;
1656 } 1674 }
1657 1675
1658 /* RF-kill already asserted again... */ 1676 /* RF-kill already asserted again... */
1659 if (!cmd.resp_pkt) 1677 if (!cmd.resp_pkt) {
1678 ret = -ERFKILL;
1660 goto out_free_resp; 1679 goto out_free_resp;
1680 }
1661 1681
1662 len = iwl_rx_packet_payload_len(cmd.resp_pkt); 1682 len = iwl_rx_packet_payload_len(cmd.resp_pkt);
1663 if (len < sizeof(*query)) { 1683 if (len < sizeof(*query)) {
1664 IWL_ERR(mvm, "Invalid scan offload profiles query response!\n"); 1684 IWL_ERR(mvm, "Invalid scan offload profiles query response!\n");
1685 ret = -EIO;
1665 goto out_free_resp; 1686 goto out_free_resp;
1666 } 1687 }
1667 1688
1668 query = (void *)cmd.resp_pkt->data; 1689 query = (void *)cmd.resp_pkt->data;
1669 1690
1670 ret = le32_to_cpu(query->matched_profiles); 1691 results->matched_profiles = le32_to_cpu(query->matched_profiles);
1692 memcpy(results->matches, query->matches, sizeof(results->matches));
1671 1693
1672out_free_resp: 1694out_free_resp:
1673 iwl_free_resp(&cmd); 1695 iwl_free_resp(&cmd);
@@ -1682,10 +1704,11 @@ static void iwl_mvm_query_netdetect_reasons(struct iwl_mvm *mvm,
1682 .pattern_idx = -1, 1704 .pattern_idx = -1,
1683 }; 1705 };
1684 struct cfg80211_wowlan_wakeup *wakeup_report = &wakeup; 1706 struct cfg80211_wowlan_wakeup *wakeup_report = &wakeup;
1707 struct iwl_mvm_nd_query_results query;
1685 struct iwl_wowlan_status *fw_status; 1708 struct iwl_wowlan_status *fw_status;
1686 unsigned long matched_profiles; 1709 unsigned long matched_profiles;
1687 u32 reasons = 0; 1710 u32 reasons = 0;
1688 int i, n_matches; 1711 int i, j, n_matches, ret;
1689 1712
1690 fw_status = iwl_mvm_get_wakeup_status(mvm, vif); 1713 fw_status = iwl_mvm_get_wakeup_status(mvm, vif);
1691 if (!IS_ERR_OR_NULL(fw_status)) 1714 if (!IS_ERR_OR_NULL(fw_status))
@@ -1697,12 +1720,13 @@ static void iwl_mvm_query_netdetect_reasons(struct iwl_mvm *mvm,
1697 if (reasons != IWL_WOWLAN_WAKEUP_BY_NON_WIRELESS) 1720 if (reasons != IWL_WOWLAN_WAKEUP_BY_NON_WIRELESS)
1698 goto out; 1721 goto out;
1699 1722
1700 matched_profiles = iwl_mvm_netdetect_query_results(mvm); 1723 ret = iwl_mvm_netdetect_query_results(mvm, &query);
1701 if (!matched_profiles) { 1724 if (ret || !query.matched_profiles) {
1702 wakeup_report = NULL; 1725 wakeup_report = NULL;
1703 goto out; 1726 goto out;
1704 } 1727 }
1705 1728
1729 matched_profiles = query.matched_profiles;
1706 if (mvm->n_nd_match_sets) { 1730 if (mvm->n_nd_match_sets) {
1707 n_matches = hweight_long(matched_profiles); 1731 n_matches = hweight_long(matched_profiles);
1708 } else { 1732 } else {
@@ -1717,17 +1741,34 @@ static void iwl_mvm_query_netdetect_reasons(struct iwl_mvm *mvm,
1717 goto out_report_nd; 1741 goto out_report_nd;
1718 1742
1719 for_each_set_bit(i, &matched_profiles, mvm->n_nd_match_sets) { 1743 for_each_set_bit(i, &matched_profiles, mvm->n_nd_match_sets) {
1744 struct iwl_scan_offload_profile_match *fw_match;
1720 struct cfg80211_wowlan_nd_match *match; 1745 struct cfg80211_wowlan_nd_match *match;
1746 int n_channels = 0;
1747
1748 fw_match = &query.matches[i];
1749
1750 for (j = 0; j < SCAN_OFFLOAD_MATCHING_CHANNELS_LEN; j++)
1751 n_channels += hweight8(fw_match->matching_channels[j]);
1721 1752
1722 match = kzalloc(sizeof(*match), GFP_KERNEL); 1753 match = kzalloc(sizeof(*match) +
1754 (n_channels * sizeof(*match->channels)),
1755 GFP_KERNEL);
1723 if (!match) 1756 if (!match)
1724 goto out_report_nd; 1757 goto out_report_nd;
1725 1758
1759 net_detect->matches[net_detect->n_matches++] = match;
1760
1726 match->ssid.ssid_len = mvm->nd_match_sets[i].ssid.ssid_len; 1761 match->ssid.ssid_len = mvm->nd_match_sets[i].ssid.ssid_len;
1727 memcpy(match->ssid.ssid, mvm->nd_match_sets[i].ssid.ssid, 1762 memcpy(match->ssid.ssid, mvm->nd_match_sets[i].ssid.ssid,
1728 match->ssid.ssid_len); 1763 match->ssid.ssid_len);
1729 1764
1730 net_detect->matches[net_detect->n_matches++] = match; 1765 if (mvm->n_nd_channels < n_channels)
1766 continue;
1767
1768 for (j = 0; j < SCAN_OFFLOAD_MATCHING_CHANNELS_LEN * 8; j++)
1769 if (fw_match->matching_channels[j / 8] & (BIT(j % 8)))
1770 match->channels[match->n_channels++] =
1771 mvm->nd_channels[j]->center_freq;
1731 } 1772 }
1732 1773
1733out_report_nd: 1774out_report_nd:
diff --git a/drivers/net/wireless/iwlwifi/mvm/mvm.h b/drivers/net/wireless/iwlwifi/mvm/mvm.h
index d69cc862234a..bb7953bf3375 100644
--- a/drivers/net/wireless/iwlwifi/mvm/mvm.h
+++ b/drivers/net/wireless/iwlwifi/mvm/mvm.h
@@ -687,6 +687,8 @@ struct iwl_mvm {
687 struct ieee80211_scan_ies nd_ies; 687 struct ieee80211_scan_ies nd_ies;
688 struct cfg80211_match_set *nd_match_sets; 688 struct cfg80211_match_set *nd_match_sets;
689 int n_nd_match_sets; 689 int n_nd_match_sets;
690 struct ieee80211_channel **nd_channels;
691 int n_nd_channels;
690 bool net_detect; 692 bool net_detect;
691#ifdef CONFIG_IWLWIFI_DEBUGFS 693#ifdef CONFIG_IWLWIFI_DEBUGFS
692 u32 d3_wake_sysassert; /* must be u32 for debugfs_create_bool */ 694 u32 d3_wake_sysassert; /* must be u32 for debugfs_create_bool */