if (!is_valid_ether_addr(addr->sa_data))
                return -EADDRNOTAVAIL;
 
-       DPRINTK(INFO, "valid ether addr\n");
        memcpy(netdev->dev_addr, addr->sa_data, netdev->addr_len);
 
        if (adapter->macaddr_set)
        return 0;
 }
 
+#define NETXEN_UNICAST_ADDR(port, index) \
+       (NETXEN_UNICAST_ADDR_BASE+(port*32)+(index*8))
+#define NETXEN_MCAST_ADDR(port, index) \
+       (NETXEN_MULTICAST_ADDR_BASE+(port*0x80)+(index*8))
+#define MAC_HI(addr) \
+       ((addr[2] << 16) | (addr[1] << 8) | (addr[0]))
+#define MAC_LO(addr) \
+       ((addr[5] << 16) | (addr[4] << 8) | (addr[3]))
+
+static int
+netxen_nic_enable_mcast_filter(struct netxen_adapter *adapter)
+{
+       u32     val = 0;
+       u16 port = adapter->physical_port;
+       u8 *addr = adapter->netdev->dev_addr;
+
+       if (adapter->mc_enabled)
+               return 0;
+
+       netxen_nic_hw_read_wx(adapter, NETXEN_MAC_ADDR_CNTL_REG, &val, 4);
+       val |= (1UL << (28+port));
+       netxen_nic_hw_write_wx(adapter, NETXEN_MAC_ADDR_CNTL_REG, &val, 4);
+
+       /* add broadcast addr to filter */
+       val = 0xffffff;
+       netxen_crb_writelit_adapter(adapter, NETXEN_UNICAST_ADDR(port, 0), val);
+       netxen_crb_writelit_adapter(adapter,
+                       NETXEN_UNICAST_ADDR(port, 0)+4, val);
+
+       /* add station addr to filter */
+       val = MAC_HI(addr);
+       netxen_crb_writelit_adapter(adapter, NETXEN_UNICAST_ADDR(port, 1), val);
+       val = MAC_LO(addr);
+       netxen_crb_writelit_adapter(adapter,
+                       NETXEN_UNICAST_ADDR(port, 1)+4, val);
+
+       adapter->mc_enabled = 1;
+       return 0;
+}
+
+static int
+netxen_nic_disable_mcast_filter(struct netxen_adapter *adapter)
+{
+       u32     val = 0;
+       u16 port = adapter->physical_port;
+       u8 *addr = adapter->netdev->dev_addr;
+
+       if (!adapter->mc_enabled)
+               return 0;
+
+       netxen_nic_hw_read_wx(adapter, NETXEN_MAC_ADDR_CNTL_REG, &val, 4);
+       val &= ~(1UL << (28+port));
+       netxen_nic_hw_write_wx(adapter, NETXEN_MAC_ADDR_CNTL_REG, &val, 4);
+
+       val = MAC_HI(addr);
+       netxen_crb_writelit_adapter(adapter, NETXEN_UNICAST_ADDR(port, 0), val);
+       val = MAC_LO(addr);
+       netxen_crb_writelit_adapter(adapter,
+                       NETXEN_UNICAST_ADDR(port, 0)+4, val);
+
+       netxen_crb_writelit_adapter(adapter, NETXEN_UNICAST_ADDR(port, 1), 0);
+       netxen_crb_writelit_adapter(adapter, NETXEN_UNICAST_ADDR(port, 1)+4, 0);
+
+       adapter->mc_enabled = 0;
+       return 0;
+}
+
+static int
+netxen_nic_set_mcast_addr(struct netxen_adapter *adapter,
+               int index, u8 *addr)
+{
+       u32 hi = 0, lo = 0;
+       u16 port = adapter->physical_port;
+
+       lo = MAC_LO(addr);
+       hi = MAC_HI(addr);
+
+       netxen_crb_writelit_adapter(adapter,
+                       NETXEN_MCAST_ADDR(port, index), hi);
+       netxen_crb_writelit_adapter(adapter,
+                       NETXEN_MCAST_ADDR(port, index)+4, lo);
+
+       return 0;
+}
+
 /*
  * netxen_nic_set_multi - Multicast
  */
 {
        struct netxen_adapter *adapter = netdev_priv(netdev);
        struct dev_mc_list *mc_ptr;
+       u8 null_addr[6];
+       int index = 0;
+
+       memset(null_addr, 0, 6);
 
-       mc_ptr = netdev->mc_list;
        if (netdev->flags & IFF_PROMISC) {
-               if (adapter->set_promisc)
-                       adapter->set_promisc(adapter,
-                                            NETXEN_NIU_PROMISC_MODE);
-       } else {
-               if (adapter->unset_promisc)
-                       adapter->unset_promisc(adapter,
-                                              NETXEN_NIU_NON_PROMISC_MODE);
+
+               adapter->set_promisc(adapter,
+                               NETXEN_NIU_PROMISC_MODE);
+
+               /* Full promiscuous mode */
+               netxen_nic_disable_mcast_filter(adapter);
+
+               return;
+       }
+
+       if (netdev->mc_count == 0) {
+               adapter->set_promisc(adapter,
+                               NETXEN_NIU_NON_PROMISC_MODE);
+               netxen_nic_disable_mcast_filter(adapter);
+               return;
+       }
+
+       adapter->set_promisc(adapter, NETXEN_NIU_ALLMULTI_MODE);
+       if (netdev->flags & IFF_ALLMULTI ||
+                       netdev->mc_count > adapter->max_mc_count) {
+               netxen_nic_disable_mcast_filter(adapter);
+               return;
        }
+
+       netxen_nic_enable_mcast_filter(adapter);
+
+       for (mc_ptr = netdev->mc_list; mc_ptr; mc_ptr = mc_ptr->next, index++)
+               netxen_nic_set_mcast_addr(adapter, index, mc_ptr->dmi_addr);
+
+       if (index != netdev->mc_count)
+               printk(KERN_WARNING "%s: %s multicast address count mismatch\n",
+                       netxen_nic_driver_name, netdev->name);
+
+       /* Clear out remaining addresses */
+       for (; index < adapter->max_mc_count; index++)
+               netxen_nic_set_mcast_addr(adapter, index, null_addr);
 }
 
 /*
 
 /* Promiscous mode options (GbE mode only) */
 typedef enum {
        NETXEN_NIU_PROMISC_MODE = 0,
-       NETXEN_NIU_NON_PROMISC_MODE
+       NETXEN_NIU_NON_PROMISC_MODE,
+       NETXEN_NIU_ALLMULTI_MODE
 } netxen_niu_prom_mode_t;
 
 /*
 #define netxen_xg_soft_reset(config_word)      \
                ((config_word) |= 1 << 4)
 
-/*
- * MAC Control Register
- *
- * Bit 0-1   : id_pool0
- * Bit 2     : enable_xtnd0
- * Bit 4-5   : id_pool1
- * Bit 6     : enable_xtnd1
- * Bit 8-9   : id_pool2
- * Bit 10    : enable_xtnd2
- * Bit 12-13 : id_pool3
- * Bit 14    : enable_xtnd3
- * Bit 24-25 : mode_select
- * Bit 28-31 : enable_pool
- */
-
-#define netxen_nic_mcr_set_id_pool0(config, val)       \
-               ((config) |= ((val) &0x03))
-#define netxen_nic_mcr_set_enable_xtnd0(config)        \
-               ((config) |= 1 << 3)
-#define netxen_nic_mcr_set_id_pool1(config, val)       \
-               ((config) |= (((val) & 0x03) << 4))
-#define netxen_nic_mcr_set_enable_xtnd1(config)        \
-               ((config) |= 1 << 6)
-#define netxen_nic_mcr_set_id_pool2(config, val)       \
-               ((config) |= (((val) & 0x03) << 8))
-#define netxen_nic_mcr_set_enable_xtnd2(config)        \
-               ((config) |= 1 << 10)
-#define netxen_nic_mcr_set_id_pool3(config, val)       \
-               ((config) |= (((val) & 0x03) << 12))
-#define netxen_nic_mcr_set_enable_xtnd3(config)        \
-               ((config) |= 1 << 14)
-#define netxen_nic_mcr_set_mode_select(config, val)    \
-               ((config) |= (((val) & 0x03) << 24))
-#define netxen_nic_mcr_set_enable_pool(config, val)    \
-               ((config) |= (((val) & 0x0f) << 28))
-
 /* Set promiscuous mode for a GbE interface */
 int netxen_niu_set_promiscuous_mode(struct netxen_adapter *adapter,
                                    netxen_niu_prom_mode_t mode);