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);