wl1271: Fix filter configuration
authorJuuso Oikarinen <juuso.oikarinen@nokia.com>
Tue, 13 Oct 2009 09:47:59 +0000 (12:47 +0300)
committerJohn W. Linville <linville@tuxdriver.com>
Tue, 27 Oct 2009 20:48:16 +0000 (16:48 -0400)
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>
drivers/net/wireless/wl12xx/wl1271.h
drivers/net/wireless/wl12xx/wl1271_main.c

index fca5968..1309b20 100644 (file)
@@ -363,9 +363,6 @@ struct wl1271 {
 
        struct work_struct tx_work;
 
-       struct work_struct filter_work;
-       struct wl1271_filter_params *filter_params;
-
        /* Pending TX frames */
        struct sk_buff *tx_frames[ACX_TX_DESCRIPTORS];
 
index 7b8d279..ee7ffaf 100644 (file)
@@ -675,74 +675,6 @@ out:
        return ret;
 }
 
-struct wl1271_filter_params {
-       unsigned int filters;
-       unsigned int changed;
-       int mc_list_length;
-       u8 mc_list[ACX_MC_ADDRESS_GROUP_MAX][ETH_ALEN];
-};
-
-#define WL1271_SUPPORTED_FILTERS (FIF_PROMISC_IN_BSS | \
-                                 FIF_ALLMULTI | \
-                                 FIF_FCSFAIL | \
-                                 FIF_BCN_PRBRESP_PROMISC | \
-                                 FIF_CONTROL | \
-                                 FIF_OTHER_BSS)
-
-static void wl1271_filter_work(struct work_struct *work)
-{
-       struct wl1271 *wl =
-               container_of(work, struct wl1271, filter_work);
-       struct wl1271_filter_params *fp;
-       unsigned long flags;
-       bool enabled = true;
-       int ret;
-
-       /* first, get the filter parameters */
-       spin_lock_irqsave(&wl->wl_lock, flags);
-       fp = wl->filter_params;
-       wl->filter_params = NULL;
-       spin_unlock_irqrestore(&wl->wl_lock, flags);
-
-       if (!fp)
-               return;
-
-       /* then, lock the mutex without risk of lock-up */
-       mutex_lock(&wl->mutex);
-
-       if (wl->state == WL1271_STATE_OFF)
-               goto out;
-
-       ret = wl1271_ps_elp_wakeup(wl, false);
-       if (ret < 0)
-               goto out;
-
-       /* configure the mc filter regardless of the changed flags */
-       if (fp->filters & FIF_ALLMULTI)
-               enabled = false;
-
-       ret = wl1271_acx_group_address_tbl(wl, enabled,
-                                          fp->mc_list, fp->mc_list_length);
-       if (ret < 0)
-               goto out_sleep;
-
-       /* determine, whether supported filter values have changed */
-       if (fp->changed == 0)
-               goto out;
-
-       /* apply configured filters */
-       ret = wl1271_acx_rx_config(wl, wl->rx_config, wl->rx_filter);
-       if (ret < 0)
-               goto out_sleep;
-
-out_sleep:
-       wl1271_ps_elp_sleep(wl);
-
-out:
-       mutex_unlock(&wl->mutex);
-       kfree(fp);
-}
-
 int wl1271_plt_start(struct wl1271 *wl)
 {
        int ret;
@@ -993,20 +925,12 @@ out:
 static void wl1271_op_stop(struct ieee80211_hw *hw)
 {
        struct wl1271 *wl = hw->priv;
-       unsigned long flags;
        int i;
 
        wl1271_info("down");
 
        wl1271_debug(DEBUG_MAC80211, "mac80211 stop");
 
-       /* complete/cancel ongoing work */
-       cancel_work_sync(&wl->filter_work);
-       spin_lock_irqsave(&wl->wl_lock, flags);
-       kfree(wl->filter_params);
-       wl->filter_params = NULL;
-       spin_unlock_irqrestore(&wl->wl_lock, flags);
-
        unregister_inetaddr_notifier(&wl1271_dev_notifier);
        list_del(&wl->list);
 
@@ -1029,7 +953,6 @@ static void wl1271_op_stop(struct ieee80211_hw *hw)
 
        cancel_work_sync(&wl->irq_work);
        cancel_work_sync(&wl->tx_work);
-       cancel_work_sync(&wl->filter_work);
 
        mutex_lock(&wl->mutex);
 
@@ -1252,19 +1175,18 @@ out:
        return ret;
 }
 
+struct wl1271_filter_params {
+       bool enabled;
+       int mc_list_length;
+       u8 mc_list[ACX_MC_ADDRESS_GROUP_MAX][ETH_ALEN];
+};
+
 static u64 wl1271_op_prepare_multicast(struct ieee80211_hw *hw, int mc_count,
                                       struct dev_addr_list *mc_list)
 {
-       struct wl1271 *wl = hw->priv;
        struct wl1271_filter_params *fp;
-       unsigned long flags;
        int i;
 
-       /*
-        * FIXME: we should return a hash that will be passed to
-        * configure_filter() instead of saving everything in the context.
-        */
-
        fp = kzalloc(sizeof(*fp), GFP_ATOMIC);
        if (!fp) {
                wl1271_error("Out of memory setting filters.");
@@ -1272,9 +1194,10 @@ static u64 wl1271_op_prepare_multicast(struct ieee80211_hw *hw, int mc_count,
        }
 
        /* update multicast filtering parameters */
+       fp->enabled = true;
        if (mc_count > ACX_MC_ADDRESS_GROUP_MAX) {
                mc_count = 0;
-               fp->filters |= FIF_ALLMULTI;
+               fp->enabled = false;
        }
 
        fp->mc_list_length = 0;
@@ -1288,42 +1211,65 @@ static u64 wl1271_op_prepare_multicast(struct ieee80211_hw *hw, int mc_count,
                mc_list = mc_list->next;
        }
 
-       /* FIXME: We still need to set our filters properly */
-
-       spin_lock_irqsave(&wl->wl_lock, flags);
-       kfree(wl->filter_params);
-       wl->filter_params = fp;
-       spin_unlock_irqrestore(&wl->wl_lock, flags);
-
-       return 1;
+       return (u64)(unsigned long)fp;
 }
 
+#define WL1271_SUPPORTED_FILTERS (FIF_PROMISC_IN_BSS | \
+                                 FIF_ALLMULTI | \
+                                 FIF_FCSFAIL | \
+                                 FIF_BCN_PRBRESP_PROMISC | \
+                                 FIF_CONTROL | \
+                                 FIF_OTHER_BSS)
+
 static void wl1271_op_configure_filter(struct ieee80211_hw *hw,
                                       unsigned int changed,
                                       unsigned int *total, u64 multicast)
 {
+       struct wl1271_filter_params *fp = (void *)(unsigned long)multicast;
        struct wl1271 *wl = hw->priv;
+       int ret;
 
        wl1271_debug(DEBUG_MAC80211, "mac80211 configure filter");
 
+       mutex_lock(&wl->mutex);
+
+       if (wl->state == WL1271_STATE_OFF)
+               goto out;
+
+       ret = wl1271_ps_elp_wakeup(wl, false);
+       if (ret < 0)
+               goto out;
+
        *total &= WL1271_SUPPORTED_FILTERS;
        changed &= WL1271_SUPPORTED_FILTERS;
 
-       if (!multicast)
-               return;
+       if (*total & FIF_ALLMULTI)
+               ret = wl1271_acx_group_address_tbl(wl, false, NULL, 0);
+       else if (fp)
+               ret = wl1271_acx_group_address_tbl(wl, fp->enabled,
+                                                  fp->mc_list,
+                                                  fp->mc_list_length);
+       if (ret < 0)
+               goto out_sleep;
 
-       /*
-        * FIXME: for now we are still using a workqueue for filter
-        * configuration, but with the new mac80211, this is not needed,
-        * since configure_filter can now sleep.  We now have
-        * prepare_multicast, which needs to be atomic instead.
-        */
+       kfree(fp);
+
+       /* FIXME: We still need to set our filters properly */
 
-       /* store current filter config */
-       wl->filter_params->filters = *total;
-       wl->filter_params->changed = changed;
+       /* determine, whether supported filter values have changed */
+       if (changed == 0)
+               goto out_sleep;
 
-       ieee80211_queue_work(wl->hw, &wl->filter_work);
+       /* apply configured filters */
+       ret = wl1271_acx_rx_config(wl, wl->rx_config, wl->rx_filter);
+       if (ret < 0)
+               goto out_sleep;
+
+out_sleep:
+       wl1271_ps_elp_sleep(wl);
+
+out:
+       mutex_unlock(&wl->mutex);
 }
 
 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)
 
        skb_queue_head_init(&wl->tx_queue);
 
-       INIT_WORK(&wl->filter_work, wl1271_filter_work);
        INIT_DELAYED_WORK(&wl->elp_work, wl1271_elp_work);
        wl->channel = WL1271_DEFAULT_CHANNEL;
        wl->scanning = false;