ath6kl: Multicast filter support in wow suspend and non-suspend
authorNaveen Gangadharan <ngangadh@qca.qualcomm.com>
Fri, 20 Apr 2012 19:46:56 +0000 (12:46 -0700)
committerKalle Valo <kvalo@qca.qualcomm.com>
Thu, 26 Apr 2012 12:01:30 +0000 (15:01 +0300)
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>
drivers/net/wireless/ath/ath6kl/cfg80211.c
drivers/net/wireless/ath/ath6kl/core.h
drivers/net/wireless/ath/ath6kl/main.c

index d4172137499aa1fd3a417a06886fee05fef1dcb1..f4467733ff5b89854c60310959c05b5d060ef9f8 100644 (file)
@@ -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;
index c26f0a269168ed7aa5496f16f7245347f2e8c319..4d9c6f1426987aab4b9cb419dbb101438dee9027 100644 (file)
@@ -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 {
index ff0b999f6f668cc23ded2bf22b627126e3ff9743..e5524470529c9d8a77034855fec8d3e3fa9d6a86 100644 (file)
@@ -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) {