netxen: hw multicast filtering

Enable multicast address filtering capabilities in the hardware.
Upto 16 multicast addresses can be programmed for each physical
port. Support "allmulti" mode, if enabled.

Signed-off-by: Dhananjay Phadke <dhananjay@netxen.com>
Signed-off-by: Jeff Garzik <jgarzik@redhat.com>
This commit is contained in:
Dhananjay Phadke
2008-07-21 19:44:01 -07:00
committed by Jeff Garzik
parent 7830b22cbc
commit 623621b07e
7 changed files with 147 additions and 49 deletions

View File

@@ -154,7 +154,6 @@ int netxen_nic_set_mac(struct net_device *netdev, void *p)
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)
@@ -163,6 +162,91 @@ int netxen_nic_set_mac(struct net_device *netdev, void *p)
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
*/
@@ -170,17 +254,48 @@ void netxen_nic_set_multi(struct net_device *netdev)
{
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);
}
/*