wl1251: implement hardware ARP filtering
[pandora-kernel.git] / drivers / net / wireless / wl1251 / main.c
index 4706d50..7fcbb79 100644 (file)
@@ -212,12 +212,11 @@ out:
        return ret;
 }
 
-#define WL1251_IRQ_LOOP_COUNT 10
-static void wl1251_irq_work(struct work_struct *work)
+#define WL1251_IRQ_LOOP_COUNT 100
+irqreturn_t wl1251_irq(int irq, void *cookie)
 {
        u32 intr, ctr = WL1251_IRQ_LOOP_COUNT;
-       struct wl1251 *wl =
-               container_of(work, struct wl1251, irq_work);
+       struct wl1251 *wl = cookie;
        int ret;
 
        mutex_lock(&wl->mutex);
@@ -308,6 +307,22 @@ static void wl1251_irq_work(struct work_struct *work)
                        wl1251_debug(DEBUG_IRQ,
                                     "WL1251_ACX_INTR_INIT_COMPLETE");
 
+               while (skb_queue_len(&wl->tx_queue) > 0
+                      && wl1251_tx_path_status(wl) == 0) {
+
+                       struct sk_buff *skb = skb_dequeue(&wl->tx_queue);
+                       if (skb == NULL)
+                               goto out_sleep;
+
+                       ret = wl1251_tx_frame(wl, skb);
+                       if (ret == -EBUSY) {
+                               skb_queue_head(&wl->tx_queue, skb);
+                               break;
+                       } else if (ret < 0) {
+                               dev_kfree_skb(skb);
+                       }
+               }
+
                if (--ctr == 0)
                        break;
 
@@ -320,6 +335,16 @@ out_sleep:
 
 out:
        mutex_unlock(&wl->mutex);
+       return IRQ_HANDLED;
+}
+EXPORT_SYMBOL_GPL(wl1251_irq);
+
+static void wl1251_irq_work(struct work_struct *work)
+{
+       struct wl1251 *wl =
+               container_of(work, struct wl1251, irq_work);
+
+       wl1251_irq(0, wl);
 }
 
 static int wl1251_join(struct wl1251 *wl, u8 bss_type, u8 channel,
@@ -1035,6 +1060,7 @@ static void wl1251_op_bss_info_changed(struct ieee80211_hw *hw,
 {
        struct wl1251 *wl = hw->priv;
        struct sk_buff *beacon, *skb;
+       bool enable;
        int ret;
 
        wl1251_debug(DEBUG_MAC80211, "mac80211 bss info changed");
@@ -1133,6 +1159,17 @@ static void wl1251_op_bss_info_changed(struct ieee80211_hw *hw,
                }
        }
 
+       if (changed & BSS_CHANGED_ARP_FILTER) {
+               __be32 addr = bss_conf->arp_addr_list[0];
+               WARN_ON(wl->bss_type != BSS_TYPE_STA_BSS);
+
+               enable = bss_conf->arp_addr_cnt == 1 && bss_conf->assoc;
+               wl1251_acx_arp_ip_filter(wl, enable, addr);
+
+               if (ret < 0)
+                       goto out_sleep;
+       }
+
        if (changed & BSS_CHANGED_BEACON) {
                beacon = ieee80211_beacon_get(hw, vif);
                if (!beacon)