diff options
author | Juuso Oikarinen <juuso.oikarinen@nokia.com> | 2009-10-13 05:47:59 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2009-10-27 16:48:16 -0400 |
commit | b54853f1b157a173fe5ac9145623670c66a9e7b9 (patch) | |
tree | b21f5bfa76ebb939e3345420953a7df1aca64fd6 /drivers/net/wireless/wl12xx/wl1271_main.c | |
parent | bd5ea18f7b47b5397233301920180128793295a2 (diff) |
wl1271: Fix filter configuration
Fix the filter configuration to properly work with the two phase filter
configuration (prepare_multicast/configure_filter.)
Signed-off-by: Juuso Oikarinen <juuso.oikarinen@nokia.com>
Reviewed-by: Luciano Coelho <luciano.coelho@nokia.com>
Signed-off-by: Luciano Coelho <luciano.coelho@nokia.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless/wl12xx/wl1271_main.c')
-rw-r--r-- | drivers/net/wireless/wl12xx/wl1271_main.c | 157 |
1 files changed, 51 insertions, 106 deletions
diff --git a/drivers/net/wireless/wl12xx/wl1271_main.c b/drivers/net/wireless/wl12xx/wl1271_main.c index 7b8d2799f23e..ee7ffafaa274 100644 --- a/drivers/net/wireless/wl12xx/wl1271_main.c +++ b/drivers/net/wireless/wl12xx/wl1271_main.c | |||
@@ -675,74 +675,6 @@ out: | |||
675 | return ret; | 675 | return ret; |
676 | } | 676 | } |
677 | 677 | ||
678 | struct wl1271_filter_params { | ||
679 | unsigned int filters; | ||
680 | unsigned int changed; | ||
681 | int mc_list_length; | ||
682 | u8 mc_list[ACX_MC_ADDRESS_GROUP_MAX][ETH_ALEN]; | ||
683 | }; | ||
684 | |||
685 | #define WL1271_SUPPORTED_FILTERS (FIF_PROMISC_IN_BSS | \ | ||
686 | FIF_ALLMULTI | \ | ||
687 | FIF_FCSFAIL | \ | ||
688 | FIF_BCN_PRBRESP_PROMISC | \ | ||
689 | FIF_CONTROL | \ | ||
690 | FIF_OTHER_BSS) | ||
691 | |||
692 | static void wl1271_filter_work(struct work_struct *work) | ||
693 | { | ||
694 | struct wl1271 *wl = | ||
695 | container_of(work, struct wl1271, filter_work); | ||
696 | struct wl1271_filter_params *fp; | ||
697 | unsigned long flags; | ||
698 | bool enabled = true; | ||
699 | int ret; | ||
700 | |||
701 | /* first, get the filter parameters */ | ||
702 | spin_lock_irqsave(&wl->wl_lock, flags); | ||
703 | fp = wl->filter_params; | ||
704 | wl->filter_params = NULL; | ||
705 | spin_unlock_irqrestore(&wl->wl_lock, flags); | ||
706 | |||
707 | if (!fp) | ||
708 | return; | ||
709 | |||
710 | /* then, lock the mutex without risk of lock-up */ | ||
711 | mutex_lock(&wl->mutex); | ||
712 | |||
713 | if (wl->state == WL1271_STATE_OFF) | ||
714 | goto out; | ||
715 | |||
716 | ret = wl1271_ps_elp_wakeup(wl, false); | ||
717 | if (ret < 0) | ||
718 | goto out; | ||
719 | |||
720 | /* configure the mc filter regardless of the changed flags */ | ||
721 | if (fp->filters & FIF_ALLMULTI) | ||
722 | enabled = false; | ||
723 | |||
724 | ret = wl1271_acx_group_address_tbl(wl, enabled, | ||
725 | fp->mc_list, fp->mc_list_length); | ||
726 | if (ret < 0) | ||
727 | goto out_sleep; | ||
728 | |||
729 | /* determine, whether supported filter values have changed */ | ||
730 | if (fp->changed == 0) | ||
731 | goto out; | ||
732 | |||
733 | /* apply configured filters */ | ||
734 | ret = wl1271_acx_rx_config(wl, wl->rx_config, wl->rx_filter); | ||
735 | if (ret < 0) | ||
736 | goto out_sleep; | ||
737 | |||
738 | out_sleep: | ||
739 | wl1271_ps_elp_sleep(wl); | ||
740 | |||
741 | out: | ||
742 | mutex_unlock(&wl->mutex); | ||
743 | kfree(fp); | ||
744 | } | ||
745 | |||
746 | int wl1271_plt_start(struct wl1271 *wl) | 678 | int wl1271_plt_start(struct wl1271 *wl) |
747 | { | 679 | { |
748 | int ret; | 680 | int ret; |
@@ -993,20 +925,12 @@ out: | |||
993 | static void wl1271_op_stop(struct ieee80211_hw *hw) | 925 | static void wl1271_op_stop(struct ieee80211_hw *hw) |
994 | { | 926 | { |
995 | struct wl1271 *wl = hw->priv; | 927 | struct wl1271 *wl = hw->priv; |
996 | unsigned long flags; | ||
997 | int i; | 928 | int i; |
998 | 929 | ||
999 | wl1271_info("down"); | 930 | wl1271_info("down"); |
1000 | 931 | ||
1001 | wl1271_debug(DEBUG_MAC80211, "mac80211 stop"); | 932 | wl1271_debug(DEBUG_MAC80211, "mac80211 stop"); |
1002 | 933 | ||
1003 | /* complete/cancel ongoing work */ | ||
1004 | cancel_work_sync(&wl->filter_work); | ||
1005 | spin_lock_irqsave(&wl->wl_lock, flags); | ||
1006 | kfree(wl->filter_params); | ||
1007 | wl->filter_params = NULL; | ||
1008 | spin_unlock_irqrestore(&wl->wl_lock, flags); | ||
1009 | |||
1010 | unregister_inetaddr_notifier(&wl1271_dev_notifier); | 934 | unregister_inetaddr_notifier(&wl1271_dev_notifier); |
1011 | list_del(&wl->list); | 935 | list_del(&wl->list); |
1012 | 936 | ||
@@ -1029,7 +953,6 @@ static void wl1271_op_stop(struct ieee80211_hw *hw) | |||
1029 | 953 | ||
1030 | cancel_work_sync(&wl->irq_work); | 954 | cancel_work_sync(&wl->irq_work); |
1031 | cancel_work_sync(&wl->tx_work); | 955 | cancel_work_sync(&wl->tx_work); |
1032 | cancel_work_sync(&wl->filter_work); | ||
1033 | 956 | ||
1034 | mutex_lock(&wl->mutex); | 957 | mutex_lock(&wl->mutex); |
1035 | 958 | ||
@@ -1252,19 +1175,18 @@ out: | |||
1252 | return ret; | 1175 | return ret; |
1253 | } | 1176 | } |
1254 | 1177 | ||
1178 | struct wl1271_filter_params { | ||
1179 | bool enabled; | ||
1180 | int mc_list_length; | ||
1181 | u8 mc_list[ACX_MC_ADDRESS_GROUP_MAX][ETH_ALEN]; | ||
1182 | }; | ||
1183 | |||
1255 | static u64 wl1271_op_prepare_multicast(struct ieee80211_hw *hw, int mc_count, | 1184 | static u64 wl1271_op_prepare_multicast(struct ieee80211_hw *hw, int mc_count, |
1256 | struct dev_addr_list *mc_list) | 1185 | struct dev_addr_list *mc_list) |
1257 | { | 1186 | { |
1258 | struct wl1271 *wl = hw->priv; | ||
1259 | struct wl1271_filter_params *fp; | 1187 | struct wl1271_filter_params *fp; |
1260 | unsigned long flags; | ||
1261 | int i; | 1188 | int i; |
1262 | 1189 | ||
1263 | /* | ||
1264 | * FIXME: we should return a hash that will be passed to | ||
1265 | * configure_filter() instead of saving everything in the context. | ||
1266 | */ | ||
1267 | |||
1268 | fp = kzalloc(sizeof(*fp), GFP_ATOMIC); | 1190 | fp = kzalloc(sizeof(*fp), GFP_ATOMIC); |
1269 | if (!fp) { | 1191 | if (!fp) { |
1270 | wl1271_error("Out of memory setting filters."); | 1192 | wl1271_error("Out of memory setting filters."); |
@@ -1272,9 +1194,10 @@ static u64 wl1271_op_prepare_multicast(struct ieee80211_hw *hw, int mc_count, | |||
1272 | } | 1194 | } |
1273 | 1195 | ||
1274 | /* update multicast filtering parameters */ | 1196 | /* update multicast filtering parameters */ |
1197 | fp->enabled = true; | ||
1275 | if (mc_count > ACX_MC_ADDRESS_GROUP_MAX) { | 1198 | if (mc_count > ACX_MC_ADDRESS_GROUP_MAX) { |
1276 | mc_count = 0; | 1199 | mc_count = 0; |
1277 | fp->filters |= FIF_ALLMULTI; | 1200 | fp->enabled = false; |
1278 | } | 1201 | } |
1279 | 1202 | ||
1280 | fp->mc_list_length = 0; | 1203 | fp->mc_list_length = 0; |
@@ -1288,42 +1211,65 @@ static u64 wl1271_op_prepare_multicast(struct ieee80211_hw *hw, int mc_count, | |||
1288 | mc_list = mc_list->next; | 1211 | mc_list = mc_list->next; |
1289 | } | 1212 | } |
1290 | 1213 | ||
1291 | /* FIXME: We still need to set our filters properly */ | 1214 | return (u64)(unsigned long)fp; |
1292 | |||
1293 | spin_lock_irqsave(&wl->wl_lock, flags); | ||
1294 | kfree(wl->filter_params); | ||
1295 | wl->filter_params = fp; | ||
1296 | spin_unlock_irqrestore(&wl->wl_lock, flags); | ||
1297 | |||
1298 | return 1; | ||
1299 | } | 1215 | } |
1300 | 1216 | ||
1217 | #define WL1271_SUPPORTED_FILTERS (FIF_PROMISC_IN_BSS | \ | ||
1218 | FIF_ALLMULTI | \ | ||
1219 | FIF_FCSFAIL | \ | ||
1220 | FIF_BCN_PRBRESP_PROMISC | \ | ||
1221 | FIF_CONTROL | \ | ||
1222 | FIF_OTHER_BSS) | ||
1223 | |||
1301 | static void wl1271_op_configure_filter(struct ieee80211_hw *hw, | 1224 | static void wl1271_op_configure_filter(struct ieee80211_hw *hw, |
1302 | unsigned int changed, | 1225 | unsigned int changed, |
1303 | unsigned int *total, u64 multicast) | 1226 | unsigned int *total, u64 multicast) |
1304 | { | 1227 | { |
1228 | struct wl1271_filter_params *fp = (void *)(unsigned long)multicast; | ||
1305 | struct wl1271 *wl = hw->priv; | 1229 | struct wl1271 *wl = hw->priv; |
1230 | int ret; | ||
1306 | 1231 | ||
1307 | wl1271_debug(DEBUG_MAC80211, "mac80211 configure filter"); | 1232 | wl1271_debug(DEBUG_MAC80211, "mac80211 configure filter"); |
1308 | 1233 | ||
1234 | mutex_lock(&wl->mutex); | ||
1235 | |||
1236 | if (wl->state == WL1271_STATE_OFF) | ||
1237 | goto out; | ||
1238 | |||
1239 | ret = wl1271_ps_elp_wakeup(wl, false); | ||
1240 | if (ret < 0) | ||
1241 | goto out; | ||
1242 | |||
1309 | *total &= WL1271_SUPPORTED_FILTERS; | 1243 | *total &= WL1271_SUPPORTED_FILTERS; |
1310 | changed &= WL1271_SUPPORTED_FILTERS; | 1244 | changed &= WL1271_SUPPORTED_FILTERS; |
1311 | 1245 | ||
1312 | if (!multicast) | 1246 | if (*total & FIF_ALLMULTI) |
1313 | return; | 1247 | ret = wl1271_acx_group_address_tbl(wl, false, NULL, 0); |
1248 | else if (fp) | ||
1249 | ret = wl1271_acx_group_address_tbl(wl, fp->enabled, | ||
1250 | fp->mc_list, | ||
1251 | fp->mc_list_length); | ||
1252 | if (ret < 0) | ||
1253 | goto out_sleep; | ||
1314 | 1254 | ||
1315 | /* | 1255 | kfree(fp); |
1316 | * FIXME: for now we are still using a workqueue for filter | 1256 | |
1317 | * configuration, but with the new mac80211, this is not needed, | 1257 | /* FIXME: We still need to set our filters properly */ |
1318 | * since configure_filter can now sleep. We now have | ||
1319 | * prepare_multicast, which needs to be atomic instead. | ||
1320 | */ | ||
1321 | 1258 | ||
1322 | /* store current filter config */ | 1259 | /* determine, whether supported filter values have changed */ |
1323 | wl->filter_params->filters = *total; | 1260 | if (changed == 0) |
1324 | wl->filter_params->changed = changed; | 1261 | goto out_sleep; |
1325 | 1262 | ||
1326 | ieee80211_queue_work(wl->hw, &wl->filter_work); | 1263 | /* apply configured filters */ |
1264 | ret = wl1271_acx_rx_config(wl, wl->rx_config, wl->rx_filter); | ||
1265 | if (ret < 0) | ||
1266 | goto out_sleep; | ||
1267 | |||
1268 | out_sleep: | ||
1269 | wl1271_ps_elp_sleep(wl); | ||
1270 | |||
1271 | out: | ||
1272 | mutex_unlock(&wl->mutex); | ||
1327 | } | 1273 | } |
1328 | 1274 | ||
1329 | static int wl1271_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, | 1275 | static int wl1271_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, |
@@ -1866,7 +1812,6 @@ static int __devinit wl1271_probe(struct spi_device *spi) | |||
1866 | 1812 | ||
1867 | skb_queue_head_init(&wl->tx_queue); | 1813 | skb_queue_head_init(&wl->tx_queue); |
1868 | 1814 | ||
1869 | INIT_WORK(&wl->filter_work, wl1271_filter_work); | ||
1870 | INIT_DELAYED_WORK(&wl->elp_work, wl1271_elp_work); | 1815 | INIT_DELAYED_WORK(&wl->elp_work, wl1271_elp_work); |
1871 | wl->channel = WL1271_DEFAULT_CHANNEL; | 1816 | wl->channel = WL1271_DEFAULT_CHANNEL; |
1872 | wl->scanning = false; | 1817 | wl->scanning = false; |