diff options
author | Johannes Berg <johannes@sipsolutions.net> | 2009-08-17 10:16:53 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2009-08-20 11:35:58 -0400 |
commit | 3ac64beecd27400d12cc7afb4108eef26c499f6a (patch) | |
tree | da0220085f68e30fe61ba9b8833dc6311d6dc25e /drivers/net/wireless/zd1211rw | |
parent | ea416a793d2b611f22b42ba094fd2e5bd30fff43 (diff) |
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/zd1211rw')
-rw-r--r-- | drivers/net/wireless/zd1211rw/zd_mac.c | 44 |
1 files changed, 29 insertions, 15 deletions
diff --git a/drivers/net/wireless/zd1211rw/zd_mac.c b/drivers/net/wireless/zd1211rw/zd_mac.c index 55b7fbdc85dc..6d666359a42f 100644 --- a/drivers/net/wireless/zd1211rw/zd_mac.c +++ b/drivers/net/wireless/zd1211rw/zd_mac.c | |||
@@ -796,18 +796,40 @@ static void set_rx_filter_handler(struct work_struct *work) | |||
796 | dev_err(zd_mac_dev(mac), "set_rx_filter_handler error %d\n", r); | 796 | dev_err(zd_mac_dev(mac), "set_rx_filter_handler error %d\n", r); |
797 | } | 797 | } |
798 | 798 | ||
799 | static u64 zd_op_prepare_multicast(struct ieee80211_hw *hw, | ||
800 | int mc_count, struct dev_addr_list *mclist) | ||
801 | { | ||
802 | struct zd_mac *mac = zd_hw_mac(hw); | ||
803 | struct zd_mc_hash hash; | ||
804 | int i; | ||
805 | |||
806 | zd_mc_clear(&hash); | ||
807 | |||
808 | for (i = 0; i < mc_count; i++) { | ||
809 | if (!mclist) | ||
810 | break; | ||
811 | dev_dbg_f(zd_mac_dev(mac), "mc addr %pM\n", mclist->dmi_addr); | ||
812 | zd_mc_add_addr(&hash, mclist->dmi_addr); | ||
813 | mclist = mclist->next; | ||
814 | } | ||
815 | |||
816 | return hash.low | ((u64)hash.high << 32); | ||
817 | } | ||
818 | |||
799 | #define SUPPORTED_FIF_FLAGS \ | 819 | #define SUPPORTED_FIF_FLAGS \ |
800 | (FIF_PROMISC_IN_BSS | FIF_ALLMULTI | FIF_FCSFAIL | FIF_CONTROL | \ | 820 | (FIF_PROMISC_IN_BSS | FIF_ALLMULTI | FIF_FCSFAIL | FIF_CONTROL | \ |
801 | FIF_OTHER_BSS | FIF_BCN_PRBRESP_PROMISC) | 821 | FIF_OTHER_BSS | FIF_BCN_PRBRESP_PROMISC) |
802 | static void zd_op_configure_filter(struct ieee80211_hw *hw, | 822 | static void zd_op_configure_filter(struct ieee80211_hw *hw, |
803 | unsigned int changed_flags, | 823 | unsigned int changed_flags, |
804 | unsigned int *new_flags, | 824 | unsigned int *new_flags, |
805 | int mc_count, struct dev_mc_list *mclist) | 825 | u64 multicast) |
806 | { | 826 | { |
807 | struct zd_mc_hash hash; | 827 | struct zd_mc_hash hash = { |
828 | .low = multicast, | ||
829 | .high = multicast >> 32, | ||
830 | }; | ||
808 | struct zd_mac *mac = zd_hw_mac(hw); | 831 | struct zd_mac *mac = zd_hw_mac(hw); |
809 | unsigned long flags; | 832 | unsigned long flags; |
810 | int i; | ||
811 | 833 | ||
812 | /* Only deal with supported flags */ | 834 | /* Only deal with supported flags */ |
813 | changed_flags &= SUPPORTED_FIF_FLAGS; | 835 | changed_flags &= SUPPORTED_FIF_FLAGS; |
@@ -819,25 +841,16 @@ static void zd_op_configure_filter(struct ieee80211_hw *hw, | |||
819 | if (!changed_flags) | 841 | if (!changed_flags) |
820 | return; | 842 | return; |
821 | 843 | ||
822 | if (*new_flags & (FIF_PROMISC_IN_BSS | FIF_ALLMULTI)) { | 844 | if (*new_flags & (FIF_PROMISC_IN_BSS | FIF_ALLMULTI)) |
823 | zd_mc_add_all(&hash); | 845 | zd_mc_add_all(&hash); |
824 | } else { | ||
825 | zd_mc_clear(&hash); | ||
826 | for (i = 0; i < mc_count; i++) { | ||
827 | if (!mclist) | ||
828 | break; | ||
829 | dev_dbg_f(zd_mac_dev(mac), "mc addr %pM\n", | ||
830 | mclist->dmi_addr); | ||
831 | zd_mc_add_addr(&hash, mclist->dmi_addr); | ||
832 | mclist = mclist->next; | ||
833 | } | ||
834 | } | ||
835 | 846 | ||
836 | spin_lock_irqsave(&mac->lock, flags); | 847 | spin_lock_irqsave(&mac->lock, flags); |
837 | mac->pass_failed_fcs = !!(*new_flags & FIF_FCSFAIL); | 848 | mac->pass_failed_fcs = !!(*new_flags & FIF_FCSFAIL); |
838 | mac->pass_ctrl = !!(*new_flags & FIF_CONTROL); | 849 | mac->pass_ctrl = !!(*new_flags & FIF_CONTROL); |
839 | mac->multicast_hash = hash; | 850 | mac->multicast_hash = hash; |
840 | spin_unlock_irqrestore(&mac->lock, flags); | 851 | spin_unlock_irqrestore(&mac->lock, flags); |
852 | |||
853 | /* XXX: these can be called here now, can sleep now! */ | ||
841 | queue_work(zd_workqueue, &mac->set_multicast_hash_work); | 854 | queue_work(zd_workqueue, &mac->set_multicast_hash_work); |
842 | 855 | ||
843 | if (changed_flags & FIF_CONTROL) | 856 | if (changed_flags & FIF_CONTROL) |
@@ -940,6 +953,7 @@ static const struct ieee80211_ops zd_ops = { | |||
940 | .add_interface = zd_op_add_interface, | 953 | .add_interface = zd_op_add_interface, |
941 | .remove_interface = zd_op_remove_interface, | 954 | .remove_interface = zd_op_remove_interface, |
942 | .config = zd_op_config, | 955 | .config = zd_op_config, |
956 | .prepare_multicast = zd_op_prepare_multicast, | ||
943 | .configure_filter = zd_op_configure_filter, | 957 | .configure_filter = zd_op_configure_filter, |
944 | .bss_info_changed = zd_op_bss_info_changed, | 958 | .bss_info_changed = zd_op_bss_info_changed, |
945 | .get_tsf = zd_op_get_tsf, | 959 | .get_tsf = zd_op_get_tsf, |