diff options
Diffstat (limited to 'drivers/net/wireless/ath/ath5k/base.c')
-rw-r--r-- | drivers/net/wireless/ath/ath5k/base.c | 64 |
1 files changed, 39 insertions, 25 deletions
diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c index 2b3cf39dd4b1..3951b5b13424 100644 --- a/drivers/net/wireless/ath/ath5k/base.c +++ b/drivers/net/wireless/ath/ath5k/base.c | |||
@@ -229,10 +229,12 @@ static int ath5k_add_interface(struct ieee80211_hw *hw, | |||
229 | static void ath5k_remove_interface(struct ieee80211_hw *hw, | 229 | static void ath5k_remove_interface(struct ieee80211_hw *hw, |
230 | struct ieee80211_if_init_conf *conf); | 230 | struct ieee80211_if_init_conf *conf); |
231 | static int ath5k_config(struct ieee80211_hw *hw, u32 changed); | 231 | static int ath5k_config(struct ieee80211_hw *hw, u32 changed); |
232 | static u64 ath5k_prepare_multicast(struct ieee80211_hw *hw, | ||
233 | int mc_count, struct dev_addr_list *mc_list); | ||
232 | static void ath5k_configure_filter(struct ieee80211_hw *hw, | 234 | static void ath5k_configure_filter(struct ieee80211_hw *hw, |
233 | unsigned int changed_flags, | 235 | unsigned int changed_flags, |
234 | unsigned int *new_flags, | 236 | unsigned int *new_flags, |
235 | int mc_count, struct dev_mc_list *mclist); | 237 | u64 multicast); |
236 | static int ath5k_set_key(struct ieee80211_hw *hw, | 238 | static int ath5k_set_key(struct ieee80211_hw *hw, |
237 | enum set_key_cmd cmd, | 239 | enum set_key_cmd cmd, |
238 | struct ieee80211_vif *vif, struct ieee80211_sta *sta, | 240 | struct ieee80211_vif *vif, struct ieee80211_sta *sta, |
@@ -260,6 +262,7 @@ static const struct ieee80211_ops ath5k_hw_ops = { | |||
260 | .add_interface = ath5k_add_interface, | 262 | .add_interface = ath5k_add_interface, |
261 | .remove_interface = ath5k_remove_interface, | 263 | .remove_interface = ath5k_remove_interface, |
262 | .config = ath5k_config, | 264 | .config = ath5k_config, |
265 | .prepare_multicast = ath5k_prepare_multicast, | ||
263 | .configure_filter = ath5k_configure_filter, | 266 | .configure_filter = ath5k_configure_filter, |
264 | .set_key = ath5k_set_key, | 267 | .set_key = ath5k_set_key, |
265 | .get_stats = ath5k_get_stats, | 268 | .get_stats = ath5k_get_stats, |
@@ -2853,6 +2856,37 @@ unlock: | |||
2853 | return ret; | 2856 | return ret; |
2854 | } | 2857 | } |
2855 | 2858 | ||
2859 | static u64 ath5k_prepare_multicast(struct ieee80211_hw *hw, | ||
2860 | int mc_count, struct dev_addr_list *mclist) | ||
2861 | { | ||
2862 | u32 mfilt[2], val; | ||
2863 | int i; | ||
2864 | u8 pos; | ||
2865 | |||
2866 | mfilt[0] = 0; | ||
2867 | mfilt[1] = 1; | ||
2868 | |||
2869 | for (i = 0; i < mc_count; i++) { | ||
2870 | if (!mclist) | ||
2871 | break; | ||
2872 | /* calculate XOR of eight 6-bit values */ | ||
2873 | val = get_unaligned_le32(mclist->dmi_addr + 0); | ||
2874 | pos = (val >> 18) ^ (val >> 12) ^ (val >> 6) ^ val; | ||
2875 | val = get_unaligned_le32(mclist->dmi_addr + 3); | ||
2876 | pos ^= (val >> 18) ^ (val >> 12) ^ (val >> 6) ^ val; | ||
2877 | pos &= 0x3f; | ||
2878 | mfilt[pos / 32] |= (1 << (pos % 32)); | ||
2879 | /* XXX: we might be able to just do this instead, | ||
2880 | * but not sure, needs testing, if we do use this we'd | ||
2881 | * neet to inform below to not reset the mcast */ | ||
2882 | /* ath5k_hw_set_mcast_filterindex(ah, | ||
2883 | * mclist->dmi_addr[5]); */ | ||
2884 | mclist = mclist->next; | ||
2885 | } | ||
2886 | |||
2887 | return ((u64)(mfilt[1]) << 32) | mfilt[0]; | ||
2888 | } | ||
2889 | |||
2856 | #define SUPPORTED_FIF_FLAGS \ | 2890 | #define SUPPORTED_FIF_FLAGS \ |
2857 | FIF_PROMISC_IN_BSS | FIF_ALLMULTI | FIF_FCSFAIL | \ | 2891 | FIF_PROMISC_IN_BSS | FIF_ALLMULTI | FIF_FCSFAIL | \ |
2858 | FIF_PLCPFAIL | FIF_CONTROL | FIF_OTHER_BSS | \ | 2892 | FIF_PLCPFAIL | FIF_CONTROL | FIF_OTHER_BSS | \ |
@@ -2878,16 +2912,14 @@ unlock: | |||
2878 | static void ath5k_configure_filter(struct ieee80211_hw *hw, | 2912 | static void ath5k_configure_filter(struct ieee80211_hw *hw, |
2879 | unsigned int changed_flags, | 2913 | unsigned int changed_flags, |
2880 | unsigned int *new_flags, | 2914 | unsigned int *new_flags, |
2881 | int mc_count, struct dev_mc_list *mclist) | 2915 | u64 multicast) |
2882 | { | 2916 | { |
2883 | struct ath5k_softc *sc = hw->priv; | 2917 | struct ath5k_softc *sc = hw->priv; |
2884 | struct ath5k_hw *ah = sc->ah; | 2918 | struct ath5k_hw *ah = sc->ah; |
2885 | u32 mfilt[2], val, rfilt; | 2919 | u32 mfilt[2], rfilt; |
2886 | u8 pos; | ||
2887 | int i; | ||
2888 | 2920 | ||
2889 | mfilt[0] = 0; | 2921 | mfilt[0] = multicast; |
2890 | mfilt[1] = 0; | 2922 | mfilt[1] = multicast >> 32; |
2891 | 2923 | ||
2892 | /* Only deal with supported flags */ | 2924 | /* Only deal with supported flags */ |
2893 | changed_flags &= SUPPORTED_FIF_FLAGS; | 2925 | changed_flags &= SUPPORTED_FIF_FLAGS; |
@@ -2913,24 +2945,6 @@ static void ath5k_configure_filter(struct ieee80211_hw *hw, | |||
2913 | if (*new_flags & FIF_ALLMULTI) { | 2945 | if (*new_flags & FIF_ALLMULTI) { |
2914 | mfilt[0] = ~0; | 2946 | mfilt[0] = ~0; |
2915 | mfilt[1] = ~0; | 2947 | mfilt[1] = ~0; |
2916 | } else { | ||
2917 | for (i = 0; i < mc_count; i++) { | ||
2918 | if (!mclist) | ||
2919 | break; | ||
2920 | /* calculate XOR of eight 6-bit values */ | ||
2921 | val = get_unaligned_le32(mclist->dmi_addr + 0); | ||
2922 | pos = (val >> 18) ^ (val >> 12) ^ (val >> 6) ^ val; | ||
2923 | val = get_unaligned_le32(mclist->dmi_addr + 3); | ||
2924 | pos ^= (val >> 18) ^ (val >> 12) ^ (val >> 6) ^ val; | ||
2925 | pos &= 0x3f; | ||
2926 | mfilt[pos / 32] |= (1 << (pos % 32)); | ||
2927 | /* XXX: we might be able to just do this instead, | ||
2928 | * but not sure, needs testing, if we do use this we'd | ||
2929 | * neet to inform below to not reset the mcast */ | ||
2930 | /* ath5k_hw_set_mcast_filterindex(ah, | ||
2931 | * mclist->dmi_addr[5]); */ | ||
2932 | mclist = mclist->next; | ||
2933 | } | ||
2934 | } | 2948 | } |
2935 | 2949 | ||
2936 | /* This is the best we can do */ | 2950 | /* This is the best we can do */ |