aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/wl12xx/wl1271_main.c
diff options
context:
space:
mode:
authorJuuso Oikarinen <juuso.oikarinen@nokia.com>2009-10-13 05:47:59 -0400
committerJohn W. Linville <linville@tuxdriver.com>2009-10-27 16:48:16 -0400
commitb54853f1b157a173fe5ac9145623670c66a9e7b9 (patch)
treeb21f5bfa76ebb939e3345420953a7df1aca64fd6 /drivers/net/wireless/wl12xx/wl1271_main.c
parentbd5ea18f7b47b5397233301920180128793295a2 (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.c157
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
678struct 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
692static 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
738out_sleep:
739 wl1271_ps_elp_sleep(wl);
740
741out:
742 mutex_unlock(&wl->mutex);
743 kfree(fp);
744}
745
746int wl1271_plt_start(struct wl1271 *wl) 678int wl1271_plt_start(struct wl1271 *wl)
747{ 679{
748 int ret; 680 int ret;
@@ -993,20 +925,12 @@ out:
993static void wl1271_op_stop(struct ieee80211_hw *hw) 925static 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
1178struct wl1271_filter_params {
1179 bool enabled;
1180 int mc_list_length;
1181 u8 mc_list[ACX_MC_ADDRESS_GROUP_MAX][ETH_ALEN];
1182};
1183
1255static u64 wl1271_op_prepare_multicast(struct ieee80211_hw *hw, int mc_count, 1184static 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
1301static void wl1271_op_configure_filter(struct ieee80211_hw *hw, 1224static 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
1268out_sleep:
1269 wl1271_ps_elp_sleep(wl);
1270
1271out:
1272 mutex_unlock(&wl->mutex);
1327} 1273}
1328 1274
1329static int wl1271_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, 1275static 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;