diff options
author | Johannes Berg <johannes@sipsolutions.net> | 2009-08-17 18:16:53 +0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2009-08-20 19:35:58 +0400 |
commit | 3ac64beecd27400d12cc7afb4108eef26c499f6a (patch) | |
tree | da0220085f68e30fe61ba9b8833dc6311d6dc25e /drivers/net/wireless/ath/ar9170/main.c | |
parent | ea416a793d2b611f22b42ba094fd2e5bd30fff43 (diff) | |
download | linux-3ac64beecd27400d12cc7afb4108eef26c499f6a.tar.xz |
mac80211: allow configure_filter callback to sleep
Over time, a whole bunch of drivers have come up
with their own scheme to delay the configure_filter
operation to a workqueue. To be able to simplify
things, allow configure_filter to sleep, and add
a new prepare_multicast callback that drivers that
need the multicast address list implement. This new
callback must be atomic, but most drivers either
don't care or just calculate a hash which can be
done atomically and then uploaded to the hardware
non-atomically.
A cursory look suggests that at76c50x-usb, ar9170,
mwl8k (which is actually very broken now), rt2x00,
wl1251, wl1271 and zd1211 should make use of this
new capability.
Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless/ath/ar9170/main.c')
-rw-r--r-- | drivers/net/wireless/ath/ar9170/main.c | 43 |
1 files changed, 25 insertions, 18 deletions
diff --git a/drivers/net/wireless/ath/ar9170/main.c b/drivers/net/wireless/ath/ar9170/main.c index ea8c9419336d..6a9462e4fd87 100644 --- a/drivers/net/wireless/ath/ar9170/main.c +++ b/drivers/net/wireless/ath/ar9170/main.c @@ -2100,10 +2100,29 @@ unlock: mutex_unlock(&ar->mutex); } +static u64 ar9170_op_prepare_multicast(struct ieee80211_hw *hw, int mc_count, + struct dev_addr_list *mclist) +{ + u64 mchash; + int i; + + /* always get broadcast frames */ + mchash = 1ULL << (0xff >> 2); + + for (i = 0; i < mc_count; i++) { + if (WARN_ON(!mclist)) + break; + mchash |= 1ULL << (mclist->dmi_addr[5] >> 2); + mclist = mclist->next; + } + + return mchash; +} + static void ar9170_op_configure_filter(struct ieee80211_hw *hw, unsigned int changed_flags, unsigned int *new_flags, - int mc_count, struct dev_mc_list *mclist) + u64 multicast) { struct ar9170 *ar = hw->priv; @@ -2116,24 +2135,11 @@ static void ar9170_op_configure_filter(struct ieee80211_hw *hw, * then checking the error flags, later. */ - if (changed_flags & FIF_ALLMULTI) { - if (*new_flags & FIF_ALLMULTI) { - ar->want_mc_hash = ~0ULL; - } else { - u64 mchash; - int i; - - /* always get broadcast frames */ - mchash = 1ULL << (0xff >> 2); + if (changed_flags & FIF_ALLMULTI && *new_flags & FIF_ALLMULTI) + multicast = ~0ULL; - for (i = 0; i < mc_count; i++) { - if (WARN_ON(!mclist)) - break; - mchash |= 1ULL << (mclist->dmi_addr[5] >> 2); - mclist = mclist->next; - } - ar->want_mc_hash = mchash; - } + if (multicast != ar->want_mc_hash) { + ar->want_mc_hash = multicast; set_bit(AR9170_FILTER_CHANGED_MULTICAST, &ar->filter_changed); } @@ -2543,6 +2549,7 @@ static const struct ieee80211_ops ar9170_ops = { .add_interface = ar9170_op_add_interface, .remove_interface = ar9170_op_remove_interface, .config = ar9170_op_config, + .prepare_multicast = ar9170_op_prepare_multicast, .configure_filter = ar9170_op_configure_filter, .conf_tx = ar9170_conf_tx, .bss_info_changed = ar9170_op_bss_info_changed, |