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/adm8211.c | |
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/adm8211.c')
-rw-r--r-- | drivers/net/wireless/adm8211.c | 42 |
1 files changed, 28 insertions, 14 deletions
diff --git a/drivers/net/wireless/adm8211.c b/drivers/net/wireless/adm8211.c index 5695911bc602..b80f514877d8 100644 --- a/drivers/net/wireless/adm8211.c +++ b/drivers/net/wireless/adm8211.c | |||
@@ -1328,16 +1328,39 @@ static void adm8211_bss_info_changed(struct ieee80211_hw *dev, | |||
1328 | } | 1328 | } |
1329 | } | 1329 | } |
1330 | 1330 | ||
1331 | static u64 adm8211_prepare_multicast(struct ieee80211_hw *hw, | ||
1332 | int mc_count, struct dev_addr_list *mclist) | ||
1333 | { | ||
1334 | unsigned int bit_nr, i; | ||
1335 | u32 mc_filter[2]; | ||
1336 | |||
1337 | mc_filter[1] = mc_filter[0] = 0; | ||
1338 | |||
1339 | for (i = 0; i < mc_count; i++) { | ||
1340 | if (!mclist) | ||
1341 | break; | ||
1342 | bit_nr = ether_crc(ETH_ALEN, mclist->dmi_addr) >> 26; | ||
1343 | |||
1344 | bit_nr &= 0x3F; | ||
1345 | mc_filter[bit_nr >> 5] |= 1 << (bit_nr & 31); | ||
1346 | mclist = mclist->next; | ||
1347 | } | ||
1348 | |||
1349 | return mc_filter[0] | ((u64)(mc_filter[1]) << 32); | ||
1350 | } | ||
1351 | |||
1331 | static void adm8211_configure_filter(struct ieee80211_hw *dev, | 1352 | static void adm8211_configure_filter(struct ieee80211_hw *dev, |
1332 | unsigned int changed_flags, | 1353 | unsigned int changed_flags, |
1333 | unsigned int *total_flags, | 1354 | unsigned int *total_flags, |
1334 | int mc_count, struct dev_mc_list *mclist) | 1355 | u64 multicast) |
1335 | { | 1356 | { |
1336 | static const u8 bcast[ETH_ALEN] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; | 1357 | static const u8 bcast[ETH_ALEN] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; |
1337 | struct adm8211_priv *priv = dev->priv; | 1358 | struct adm8211_priv *priv = dev->priv; |
1338 | unsigned int bit_nr, new_flags; | 1359 | unsigned int new_flags; |
1339 | u32 mc_filter[2]; | 1360 | u32 mc_filter[2]; |
1340 | int i; | 1361 | |
1362 | mc_filter[0] = multicast; | ||
1363 | mc_filter[1] = multicast >> 32; | ||
1341 | 1364 | ||
1342 | new_flags = 0; | 1365 | new_flags = 0; |
1343 | 1366 | ||
@@ -1346,23 +1369,13 @@ static void adm8211_configure_filter(struct ieee80211_hw *dev, | |||
1346 | priv->nar |= ADM8211_NAR_PR; | 1369 | priv->nar |= ADM8211_NAR_PR; |
1347 | priv->nar &= ~ADM8211_NAR_MM; | 1370 | priv->nar &= ~ADM8211_NAR_MM; |
1348 | mc_filter[1] = mc_filter[0] = ~0; | 1371 | mc_filter[1] = mc_filter[0] = ~0; |
1349 | } else if ((*total_flags & FIF_ALLMULTI) || (mc_count > 32)) { | 1372 | } else if (*total_flags & FIF_ALLMULTI || multicast == ~(0ULL)) { |
1350 | new_flags |= FIF_ALLMULTI; | 1373 | new_flags |= FIF_ALLMULTI; |
1351 | priv->nar &= ~ADM8211_NAR_PR; | 1374 | priv->nar &= ~ADM8211_NAR_PR; |
1352 | priv->nar |= ADM8211_NAR_MM; | 1375 | priv->nar |= ADM8211_NAR_MM; |
1353 | mc_filter[1] = mc_filter[0] = ~0; | 1376 | mc_filter[1] = mc_filter[0] = ~0; |
1354 | } else { | 1377 | } else { |
1355 | priv->nar &= ~(ADM8211_NAR_MM | ADM8211_NAR_PR); | 1378 | priv->nar &= ~(ADM8211_NAR_MM | ADM8211_NAR_PR); |
1356 | mc_filter[1] = mc_filter[0] = 0; | ||
1357 | for (i = 0; i < mc_count; i++) { | ||
1358 | if (!mclist) | ||
1359 | break; | ||
1360 | bit_nr = ether_crc(ETH_ALEN, mclist->dmi_addr) >> 26; | ||
1361 | |||
1362 | bit_nr &= 0x3F; | ||
1363 | mc_filter[bit_nr >> 5] |= 1 << (bit_nr & 31); | ||
1364 | mclist = mclist->next; | ||
1365 | } | ||
1366 | } | 1379 | } |
1367 | 1380 | ||
1368 | ADM8211_IDLE_RX(); | 1381 | ADM8211_IDLE_RX(); |
@@ -1757,6 +1770,7 @@ static const struct ieee80211_ops adm8211_ops = { | |||
1757 | .remove_interface = adm8211_remove_interface, | 1770 | .remove_interface = adm8211_remove_interface, |
1758 | .config = adm8211_config, | 1771 | .config = adm8211_config, |
1759 | .bss_info_changed = adm8211_bss_info_changed, | 1772 | .bss_info_changed = adm8211_bss_info_changed, |
1773 | .prepare_multicast = adm8211_prepare_multicast, | ||
1760 | .configure_filter = adm8211_configure_filter, | 1774 | .configure_filter = adm8211_configure_filter, |
1761 | .get_stats = adm8211_get_stats, | 1775 | .get_stats = adm8211_get_stats, |
1762 | .get_tx_stats = adm8211_get_tx_stats, | 1776 | .get_tx_stats = adm8211_get_tx_stats, |