summaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/ath
diff options
context:
space:
mode:
authorNaveen Gangadharan2012-04-20 21:46:56 +0200
committerKalle Valo2012-04-26 14:01:30 +0200
commit6251d8012dbc49869f2453942089c4df82de0c80 (patch)
tree95f835e55cc3cf35874c55a2a1ed0140c9b3c573 /drivers/net/wireless/ath
parentath6kl: check for sband existence when creating scan cmd (diff)
downloadkernel-qcow2-linux-6251d8012dbc49869f2453942089c4df82de0c80.tar.gz
kernel-qcow2-linux-6251d8012dbc49869f2453942089c4df82de0c80.tar.xz
kernel-qcow2-linux-6251d8012dbc49869f2453942089c4df82de0c80.zip
ath6kl: Multicast filter support in wow suspend and non-suspend
This patch enables all multicast packets in non suspend mode and enable multicast filtering in wow suspend mode. This also fixes a bug in multicast where the driver assumed disable multicast-all command disabled/filtered all multicast packets, which was wrong assumption, because firmware will apply the programmed filter. Multicast requirements - Enable forward all multicast packets(no filtering) in non suspend mode. - Enable multicast filtering in wow suspend mode for both AP and CLIENT. kvalo: fix a checkpatch warning and drop unrelated newline removal Signed-off-by: Naveen Gangadharan <ngangadh@qca.qualcomm.com> Signed-off-by: Kalle Valo <kvalo@qca.qualcomm.com>
Diffstat (limited to 'drivers/net/wireless/ath')
-rw-r--r--drivers/net/wireless/ath/ath6kl/cfg80211.c14
-rw-r--r--drivers/net/wireless/ath/ath6kl/core.h2
-rw-r--r--drivers/net/wireless/ath/ath6kl/main.c37
3 files changed, 43 insertions, 10 deletions
diff --git a/drivers/net/wireless/ath/ath6kl/cfg80211.c b/drivers/net/wireless/ath/ath6kl/cfg80211.c
index d4172137499a..f4467733ff5b 100644
--- a/drivers/net/wireless/ath/ath6kl/cfg80211.c
+++ b/drivers/net/wireless/ath/ath6kl/cfg80211.c
@@ -2076,6 +2076,13 @@ static int ath6kl_wow_suspend(struct ath6kl *ar, struct cfg80211_wowlan *wow)
if (wow && (wow->n_patterns > WOW_MAX_FILTERS_PER_LIST))
return -EINVAL;
+ if (!test_bit(NETDEV_MCAST_ALL_ON, &vif->flags)) {
+ ret = ath6kl_wmi_mcast_filter_cmd(vif->ar->wmi,
+ vif->fw_vif_idx, false);
+ if (ret)
+ return ret;
+ }
+
/* Clear existing WOW patterns */
for (i = 0; i < WOW_MAX_FILTERS_PER_LIST; i++)
ath6kl_wmi_del_wow_pattern_cmd(ar->wmi, vif->fw_vif_idx,
@@ -2204,6 +2211,13 @@ static int ath6kl_wow_resume(struct ath6kl *ar)
ar->state = ATH6KL_STATE_ON;
+ if (!test_bit(NETDEV_MCAST_ALL_OFF, &vif->flags)) {
+ ret = ath6kl_wmi_mcast_filter_cmd(vif->ar->wmi,
+ vif->fw_vif_idx, true);
+ if (ret)
+ return ret;
+ }
+
netif_wake_queue(vif->ndev);
return 0;
diff --git a/drivers/net/wireless/ath/ath6kl/core.h b/drivers/net/wireless/ath/ath6kl/core.h
index c26f0a269168..4d9c6f142698 100644
--- a/drivers/net/wireless/ath/ath6kl/core.h
+++ b/drivers/net/wireless/ath/ath6kl/core.h
@@ -510,6 +510,8 @@ enum ath6kl_vif_state {
WLAN_ENABLED,
STATS_UPDATE_PEND,
HOST_SLEEP_MODE_CMD_PROCESSED,
+ NETDEV_MCAST_ALL_ON,
+ NETDEV_MCAST_ALL_OFF,
};
struct ath6kl_vif {
diff --git a/drivers/net/wireless/ath/ath6kl/main.c b/drivers/net/wireless/ath/ath6kl/main.c
index ff0b999f6f66..e5524470529c 100644
--- a/drivers/net/wireless/ath/ath6kl/main.c
+++ b/drivers/net/wireless/ath/ath6kl/main.c
@@ -1145,7 +1145,7 @@ static int ath6kl_set_features(struct net_device *dev,
static void ath6kl_set_multicast_list(struct net_device *ndev)
{
struct ath6kl_vif *vif = netdev_priv(ndev);
- bool mc_all_on = false, mc_all_off = false;
+ bool mc_all_on = false;
int mc_count = netdev_mc_count(ndev);
struct netdev_hw_addr *ha;
bool found;
@@ -1157,24 +1157,41 @@ static void ath6kl_set_multicast_list(struct net_device *ndev)
!test_bit(WLAN_ENABLED, &vif->flags))
return;
+ /* Enable multicast-all filter. */
mc_all_on = !!(ndev->flags & IFF_PROMISC) ||
!!(ndev->flags & IFF_ALLMULTI) ||
!!(mc_count > ATH6K_MAX_MC_FILTERS_PER_LIST);
- mc_all_off = !(ndev->flags & IFF_MULTICAST) || mc_count == 0;
+ if (mc_all_on)
+ set_bit(NETDEV_MCAST_ALL_ON, &vif->flags);
+ else
+ clear_bit(NETDEV_MCAST_ALL_ON, &vif->flags);
- if (mc_all_on || mc_all_off) {
- /* Enable/disable all multicast */
- ath6kl_dbg(ATH6KL_DBG_TRC, "%s multicast filter\n",
- mc_all_on ? "enabling" : "disabling");
- ret = ath6kl_wmi_mcast_filter_cmd(vif->ar->wmi, vif->fw_vif_idx,
+ mc_all_on = mc_all_on || (vif->ar->state == ATH6KL_STATE_ON);
+
+ if (!(ndev->flags & IFF_MULTICAST)) {
+ mc_all_on = false;
+ set_bit(NETDEV_MCAST_ALL_OFF, &vif->flags);
+ } else {
+ clear_bit(NETDEV_MCAST_ALL_OFF, &vif->flags);
+ }
+
+ /* Enable/disable "multicast-all" filter*/
+ ath6kl_dbg(ATH6KL_DBG_TRC, "%s multicast-all filter\n",
+ mc_all_on ? "enabling" : "disabling");
+
+ ret = ath6kl_wmi_mcast_filter_cmd(vif->ar->wmi, vif->fw_vif_idx,
mc_all_on);
- if (ret)
- ath6kl_warn("Failed to %s multicast receive\n",
- mc_all_on ? "enable" : "disable");
+ if (ret) {
+ ath6kl_warn("Failed to %s multicast-all receive\n",
+ mc_all_on ? "enable" : "disable");
return;
}
+ if (test_bit(NETDEV_MCAST_ALL_ON, &vif->flags))
+ return;
+
+ /* Keep the driver and firmware mcast list in sync. */
list_for_each_entry_safe(mc_filter, tmp, &vif->mc_filter, list) {
found = false;
netdev_for_each_mc_addr(ha, ndev) {