diff options
author | Naveen Gangadharan <ngangadh@qca.qualcomm.com> | 2012-04-20 15:46:56 -0400 |
---|---|---|
committer | Kalle Valo <kvalo@qca.qualcomm.com> | 2012-04-26 08:01:30 -0400 |
commit | 6251d8012dbc49869f2453942089c4df82de0c80 (patch) | |
tree | 95f835e55cc3cf35874c55a2a1ed0140c9b3c573 /drivers/net/wireless/ath/ath6kl | |
parent | 03e2084a843a700089a479e0ffdf5876c7059411 (diff) |
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/ath6kl')
-rw-r--r-- | drivers/net/wireless/ath/ath6kl/cfg80211.c | 14 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath6kl/core.h | 2 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath6kl/main.c | 37 |
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) | |||
2076 | if (wow && (wow->n_patterns > WOW_MAX_FILTERS_PER_LIST)) | 2076 | if (wow && (wow->n_patterns > WOW_MAX_FILTERS_PER_LIST)) |
2077 | return -EINVAL; | 2077 | return -EINVAL; |
2078 | 2078 | ||
2079 | if (!test_bit(NETDEV_MCAST_ALL_ON, &vif->flags)) { | ||
2080 | ret = ath6kl_wmi_mcast_filter_cmd(vif->ar->wmi, | ||
2081 | vif->fw_vif_idx, false); | ||
2082 | if (ret) | ||
2083 | return ret; | ||
2084 | } | ||
2085 | |||
2079 | /* Clear existing WOW patterns */ | 2086 | /* Clear existing WOW patterns */ |
2080 | for (i = 0; i < WOW_MAX_FILTERS_PER_LIST; i++) | 2087 | for (i = 0; i < WOW_MAX_FILTERS_PER_LIST; i++) |
2081 | ath6kl_wmi_del_wow_pattern_cmd(ar->wmi, vif->fw_vif_idx, | 2088 | ath6kl_wmi_del_wow_pattern_cmd(ar->wmi, vif->fw_vif_idx, |
@@ -2204,6 +2211,13 @@ static int ath6kl_wow_resume(struct ath6kl *ar) | |||
2204 | 2211 | ||
2205 | ar->state = ATH6KL_STATE_ON; | 2212 | ar->state = ATH6KL_STATE_ON; |
2206 | 2213 | ||
2214 | if (!test_bit(NETDEV_MCAST_ALL_OFF, &vif->flags)) { | ||
2215 | ret = ath6kl_wmi_mcast_filter_cmd(vif->ar->wmi, | ||
2216 | vif->fw_vif_idx, true); | ||
2217 | if (ret) | ||
2218 | return ret; | ||
2219 | } | ||
2220 | |||
2207 | netif_wake_queue(vif->ndev); | 2221 | netif_wake_queue(vif->ndev); |
2208 | 2222 | ||
2209 | return 0; | 2223 | 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 { | |||
510 | WLAN_ENABLED, | 510 | WLAN_ENABLED, |
511 | STATS_UPDATE_PEND, | 511 | STATS_UPDATE_PEND, |
512 | HOST_SLEEP_MODE_CMD_PROCESSED, | 512 | HOST_SLEEP_MODE_CMD_PROCESSED, |
513 | NETDEV_MCAST_ALL_ON, | ||
514 | NETDEV_MCAST_ALL_OFF, | ||
513 | }; | 515 | }; |
514 | 516 | ||
515 | struct ath6kl_vif { | 517 | 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, | |||
1145 | static void ath6kl_set_multicast_list(struct net_device *ndev) | 1145 | static void ath6kl_set_multicast_list(struct net_device *ndev) |
1146 | { | 1146 | { |
1147 | struct ath6kl_vif *vif = netdev_priv(ndev); | 1147 | struct ath6kl_vif *vif = netdev_priv(ndev); |
1148 | bool mc_all_on = false, mc_all_off = false; | 1148 | bool mc_all_on = false; |
1149 | int mc_count = netdev_mc_count(ndev); | 1149 | int mc_count = netdev_mc_count(ndev); |
1150 | struct netdev_hw_addr *ha; | 1150 | struct netdev_hw_addr *ha; |
1151 | bool found; | 1151 | bool found; |
@@ -1157,24 +1157,41 @@ static void ath6kl_set_multicast_list(struct net_device *ndev) | |||
1157 | !test_bit(WLAN_ENABLED, &vif->flags)) | 1157 | !test_bit(WLAN_ENABLED, &vif->flags)) |
1158 | return; | 1158 | return; |
1159 | 1159 | ||
1160 | /* Enable multicast-all filter. */ | ||
1160 | mc_all_on = !!(ndev->flags & IFF_PROMISC) || | 1161 | mc_all_on = !!(ndev->flags & IFF_PROMISC) || |
1161 | !!(ndev->flags & IFF_ALLMULTI) || | 1162 | !!(ndev->flags & IFF_ALLMULTI) || |
1162 | !!(mc_count > ATH6K_MAX_MC_FILTERS_PER_LIST); | 1163 | !!(mc_count > ATH6K_MAX_MC_FILTERS_PER_LIST); |
1163 | 1164 | ||
1164 | mc_all_off = !(ndev->flags & IFF_MULTICAST) || mc_count == 0; | 1165 | if (mc_all_on) |
1166 | set_bit(NETDEV_MCAST_ALL_ON, &vif->flags); | ||
1167 | else | ||
1168 | clear_bit(NETDEV_MCAST_ALL_ON, &vif->flags); | ||
1165 | 1169 | ||
1166 | if (mc_all_on || mc_all_off) { | 1170 | mc_all_on = mc_all_on || (vif->ar->state == ATH6KL_STATE_ON); |
1167 | /* Enable/disable all multicast */ | 1171 | |
1168 | ath6kl_dbg(ATH6KL_DBG_TRC, "%s multicast filter\n", | 1172 | if (!(ndev->flags & IFF_MULTICAST)) { |
1169 | mc_all_on ? "enabling" : "disabling"); | 1173 | mc_all_on = false; |
1170 | ret = ath6kl_wmi_mcast_filter_cmd(vif->ar->wmi, vif->fw_vif_idx, | 1174 | set_bit(NETDEV_MCAST_ALL_OFF, &vif->flags); |
1175 | } else { | ||
1176 | clear_bit(NETDEV_MCAST_ALL_OFF, &vif->flags); | ||
1177 | } | ||
1178 | |||
1179 | /* Enable/disable "multicast-all" filter*/ | ||
1180 | ath6kl_dbg(ATH6KL_DBG_TRC, "%s multicast-all filter\n", | ||
1181 | mc_all_on ? "enabling" : "disabling"); | ||
1182 | |||
1183 | ret = ath6kl_wmi_mcast_filter_cmd(vif->ar->wmi, vif->fw_vif_idx, | ||
1171 | mc_all_on); | 1184 | mc_all_on); |
1172 | if (ret) | 1185 | if (ret) { |
1173 | ath6kl_warn("Failed to %s multicast receive\n", | 1186 | ath6kl_warn("Failed to %s multicast-all receive\n", |
1174 | mc_all_on ? "enable" : "disable"); | 1187 | mc_all_on ? "enable" : "disable"); |
1175 | return; | 1188 | return; |
1176 | } | 1189 | } |
1177 | 1190 | ||
1191 | if (test_bit(NETDEV_MCAST_ALL_ON, &vif->flags)) | ||
1192 | return; | ||
1193 | |||
1194 | /* Keep the driver and firmware mcast list in sync. */ | ||
1178 | list_for_each_entry_safe(mc_filter, tmp, &vif->mc_filter, list) { | 1195 | list_for_each_entry_safe(mc_filter, tmp, &vif->mc_filter, list) { |
1179 | found = false; | 1196 | found = false; |
1180 | netdev_for_each_mc_addr(ha, ndev) { | 1197 | netdev_for_each_mc_addr(ha, ndev) { |