Merge branch 'drm-patches' of git://git.kernel.org/pub/scm/linux/kernel/git/airlied...
[pandora-kernel.git] / drivers / net / wireless / zd1211rw / zd_mac.c
index bd1593e..00ca704 100644 (file)
 
 static void ieee_init(struct ieee80211_device *ieee);
 static void softmac_init(struct ieee80211softmac_device *sm);
-static void set_rts_cts_work(void *d);
-static void set_basic_rates_work(void *d);
+static void set_rts_cts_work(struct work_struct *work);
+static void set_basic_rates_work(struct work_struct *work);
 
 static void housekeeping_init(struct zd_mac *mac);
 static void housekeeping_enable(struct zd_mac *mac);
 static void housekeeping_disable(struct zd_mac *mac);
 
+static void set_multicast_hash_handler(struct work_struct *work);
+
 int zd_mac_init(struct zd_mac *mac,
                struct net_device *netdev,
                struct usb_interface *intf)
@@ -48,13 +50,14 @@ int zd_mac_init(struct zd_mac *mac,
        memset(mac, 0, sizeof(*mac));
        spin_lock_init(&mac->lock);
        mac->netdev = netdev;
-       INIT_WORK(&mac->set_rts_cts_work, set_rts_cts_work, mac);
-       INIT_WORK(&mac->set_basic_rates_work, set_basic_rates_work, mac);
+       INIT_DELAYED_WORK(&mac->set_rts_cts_work, set_rts_cts_work);
+       INIT_DELAYED_WORK(&mac->set_basic_rates_work, set_basic_rates_work);
 
        ieee_init(ieee);
        softmac_init(ieee80211_priv(netdev));
        zd_chip_init(&mac->chip, netdev, intf);
        housekeeping_init(mac);
+       INIT_WORK(&mac->set_multicast_hash_work, set_multicast_hash_handler);
        return 0;
 }
 
@@ -136,6 +139,7 @@ out:
 
 void zd_mac_clear(struct zd_mac *mac)
 {
+       flush_workqueue(zd_workqueue);
        zd_chip_clear(&mac->chip);
        ZD_ASSERT(!spin_is_locked(&mac->lock));
        ZD_MEMCLEAR(mac, sizeof(struct zd_mac));
@@ -256,6 +260,43 @@ int zd_mac_set_mac_address(struct net_device *netdev, void *p)
        return 0;
 }
 
+static void set_multicast_hash_handler(struct work_struct *work)
+{
+       struct zd_mac *mac = container_of(work, struct zd_mac,
+                                         set_multicast_hash_work);
+       struct zd_mc_hash hash;
+
+       spin_lock_irq(&mac->lock);
+       hash = mac->multicast_hash;
+       spin_unlock_irq(&mac->lock);
+
+       zd_chip_set_multicast_hash(&mac->chip, &hash);
+}
+
+void zd_mac_set_multicast_list(struct net_device *dev)
+{
+       struct zd_mc_hash hash;
+       struct zd_mac *mac = zd_netdev_mac(dev);
+       struct dev_mc_list *mc;
+       unsigned long flags;
+
+       if (dev->flags & (IFF_PROMISC|IFF_ALLMULTI)) {
+               zd_mc_add_all(&hash);
+       } else {
+               zd_mc_clear(&hash);
+               for (mc = dev->mc_list; mc; mc = mc->next) {
+                       dev_dbg_f(zd_mac_dev(mac), "mc addr " MAC_FMT "\n",
+                                 MAC_ARG(mc->dmi_addr));
+                       zd_mc_add_addr(&hash, mc->dmi_addr);
+               }
+       }
+
+       spin_lock_irqsave(&mac->lock, flags);
+       mac->multicast_hash = hash;
+       spin_unlock_irqrestore(&mac->lock, flags);
+       queue_work(zd_workqueue, &mac->set_multicast_hash_work);
+}
+
 int zd_mac_set_regdomain(struct zd_mac *mac, u8 regdomain)
 {
        int r;
@@ -366,9 +407,10 @@ static void try_enable_tx(struct zd_mac *mac)
        spin_unlock_irqrestore(&mac->lock, flags);
 }
 
-static void set_rts_cts_work(void *d)
+static void set_rts_cts_work(struct work_struct *work)
 {
-       struct zd_mac *mac = d;
+       struct zd_mac *mac =
+               container_of(work, struct zd_mac, set_rts_cts_work.work);
        unsigned long flags;
        u8 rts_rate;
        unsigned int short_preamble;
@@ -387,9 +429,10 @@ static void set_rts_cts_work(void *d)
        try_enable_tx(mac);
 }
 
-static void set_basic_rates_work(void *d)
+static void set_basic_rates_work(struct work_struct *work)
 {
-       struct zd_mac *mac = d;
+       struct zd_mac *mac =
+               container_of(work, struct zd_mac, set_basic_rates_work.work);
        unsigned long flags;
        u16 basic_rates;
 
@@ -467,12 +510,13 @@ static void bssinfo_change(struct net_device *netdev, u32 changes)
        if (need_set_rts_cts && !mac->updating_rts_rate) {
                mac->updating_rts_rate = 1;
                netif_stop_queue(mac->netdev);
-               queue_work(zd_workqueue, &mac->set_rts_cts_work);
+               queue_delayed_work(zd_workqueue, &mac->set_rts_cts_work, 0);
        }
        if (need_set_rates && !mac->updating_basic_rates) {
                mac->updating_basic_rates = 1;
                netif_stop_queue(mac->netdev);
-               queue_work(zd_workqueue, &mac->set_basic_rates_work);
+               queue_delayed_work(zd_workqueue, &mac->set_basic_rates_work,
+                                  0);
        }
        spin_unlock_irqrestore(&mac->lock, flags);
 }
@@ -930,7 +974,8 @@ static int is_data_packet_for_us(struct ieee80211_device *ieee,
        }
 
        return memcmp(hdr->addr1, netdev->dev_addr, ETH_ALEN) == 0 ||
-              is_multicast_ether_addr(hdr->addr1) ||
+              (is_multicast_ether_addr(hdr->addr1) &&
+               memcmp(hdr->addr3, netdev->dev_addr, ETH_ALEN) != 0) ||
               (netdev->flags & IFF_PROMISC);
 }
 
@@ -1183,9 +1228,10 @@ struct iw_statistics *zd_mac_get_wireless_stats(struct net_device *ndev)
 
 #define LINK_LED_WORK_DELAY HZ
 
-static void link_led_handler(void *p)
+static void link_led_handler(struct work_struct *work)
 {
-       struct zd_mac *mac = p;
+       struct zd_mac *mac =
+               container_of(work, struct zd_mac, housekeeping.link_led_work.work);
        struct zd_chip *chip = &mac->chip;
        struct ieee80211softmac_device *sm = ieee80211_priv(mac->netdev);
        int is_associated;
@@ -1206,7 +1252,7 @@ static void link_led_handler(void *p)
 
 static void housekeeping_init(struct zd_mac *mac)
 {
-       INIT_WORK(&mac->housekeeping.link_led_work, link_led_handler, mac);
+       INIT_DELAYED_WORK(&mac->housekeeping.link_led_work, link_led_handler);
 }
 
 static void housekeeping_enable(struct zd_mac *mac)