diff options
author | Roopa Prabhu <roprabhu@cisco.com> | 2010-12-08 14:19:58 +0100 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2010-12-11 00:39:42 +0100 |
commit | 319d7e847355ec7e03d3c865917b2b0e2e592fb8 (patch) | |
tree | a900c8007e8060e03e5d26939051716d0543921a /drivers/net/enic/enic_main.c | |
parent | pktgen: adding prefetchw() call (diff) | |
download | linux-319d7e847355ec7e03d3c865917b2b0e2e592fb8.tar.xz linux-319d7e847355ec7e03d3c865917b2b0e2e592fb8.zip |
enic: Add ndo_set_rx_mode support for enic vnics
Add ndo_set_rx_mode support to register unicast and multicast
address filters for enic devices
Signed-off-by: Roopa Prabhu <roprabhu@cisco.com>
Signed-off-by: Vasanthy Kolluri <vkolluri@cisco.com>
Signed-off-by: David Wang <dwang2@cisco.com>
Signed-off-by: Christian Benvenuti <benve@cisco.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/enic/enic_main.c')
-rw-r--r-- | drivers/net/enic/enic_main.c | 121 |
1 files changed, 98 insertions, 23 deletions
diff --git a/drivers/net/enic/enic_main.c b/drivers/net/enic/enic_main.c index 9f293fa24768..1931f156777c 100644 --- a/drivers/net/enic/enic_main.c +++ b/drivers/net/enic/enic_main.c @@ -1002,7 +1002,7 @@ static int enic_dev_packet_filter(struct enic *enic, int directed, return err; } -static int enic_dev_add_multicast_addr(struct enic *enic, u8 *addr) +static int enic_dev_add_addr(struct enic *enic, u8 *addr) { int err; @@ -1013,7 +1013,7 @@ static int enic_dev_add_multicast_addr(struct enic *enic, u8 *addr) return err; } -static int enic_dev_del_multicast_addr(struct enic *enic, u8 *addr) +static int enic_dev_del_addr(struct enic *enic, u8 *addr) { int err; @@ -1024,29 +1024,19 @@ static int enic_dev_del_multicast_addr(struct enic *enic, u8 *addr) return err; } -/* netif_tx_lock held, BHs disabled */ -static void enic_set_multicast_list(struct net_device *netdev) +static void enic_add_multicast_addr_list(struct enic *enic) { - struct enic *enic = netdev_priv(netdev); + struct net_device *netdev = enic->netdev; struct netdev_hw_addr *ha; - int directed = 1; - int multicast = (netdev->flags & IFF_MULTICAST) ? 1 : 0; - int broadcast = (netdev->flags & IFF_BROADCAST) ? 1 : 0; - int promisc = (netdev->flags & IFF_PROMISC) ? 1 : 0; unsigned int mc_count = netdev_mc_count(netdev); - int allmulti = (netdev->flags & IFF_ALLMULTI) || - mc_count > ENIC_MULTICAST_PERFECT_FILTERS; - unsigned int flags = netdev->flags | (allmulti ? IFF_ALLMULTI : 0); u8 mc_addr[ENIC_MULTICAST_PERFECT_FILTERS][ETH_ALEN]; unsigned int i, j; - if (mc_count > ENIC_MULTICAST_PERFECT_FILTERS) + if (mc_count > ENIC_MULTICAST_PERFECT_FILTERS) { + netdev_warn(netdev, "Registering only %d out of %d " + "multicast addresses\n", + ENIC_MULTICAST_PERFECT_FILTERS, mc_count); mc_count = ENIC_MULTICAST_PERFECT_FILTERS; - - if (enic->flags != flags) { - enic->flags = flags; - enic_dev_packet_filter(enic, directed, - multicast, broadcast, promisc, allmulti); } /* Is there an easier way? Trying to minimize to @@ -1068,7 +1058,7 @@ static void enic_set_multicast_list(struct net_device *netdev) mc_addr[j]) == 0) break; if (j == mc_count) - enic_dev_del_multicast_addr(enic, enic->mc_addr[i]); + enic_dev_del_addr(enic, enic->mc_addr[i]); } for (i = 0; i < mc_count; i++) { @@ -1077,7 +1067,7 @@ static void enic_set_multicast_list(struct net_device *netdev) enic->mc_addr[j]) == 0) break; if (j == enic->mc_count) - enic_dev_add_multicast_addr(enic, mc_addr[i]); + enic_dev_add_addr(enic, mc_addr[i]); } /* Save the list to compare against next time @@ -1089,6 +1079,89 @@ static void enic_set_multicast_list(struct net_device *netdev) enic->mc_count = mc_count; } +static void enic_add_unicast_addr_list(struct enic *enic) +{ + struct net_device *netdev = enic->netdev; + struct netdev_hw_addr *ha; + unsigned int uc_count = netdev_uc_count(netdev); + u8 uc_addr[ENIC_UNICAST_PERFECT_FILTERS][ETH_ALEN]; + unsigned int i, j; + + if (uc_count > ENIC_UNICAST_PERFECT_FILTERS) { + netdev_warn(netdev, "Registering only %d out of %d " + "unicast addresses\n", + ENIC_UNICAST_PERFECT_FILTERS, uc_count); + uc_count = ENIC_UNICAST_PERFECT_FILTERS; + } + + /* Is there an easier way? Trying to minimize to + * calls to add/del unicast addrs. We keep the + * addrs from the last call in enic->uc_addr and + * look for changes to add/del. + */ + + i = 0; + netdev_for_each_uc_addr(ha, netdev) { + if (i == uc_count) + break; + memcpy(uc_addr[i++], ha->addr, ETH_ALEN); + } + + for (i = 0; i < enic->uc_count; i++) { + for (j = 0; j < uc_count; j++) + if (compare_ether_addr(enic->uc_addr[i], + uc_addr[j]) == 0) + break; + if (j == uc_count) + enic_dev_del_addr(enic, enic->uc_addr[i]); + } + + for (i = 0; i < uc_count; i++) { + for (j = 0; j < enic->uc_count; j++) + if (compare_ether_addr(uc_addr[i], + enic->uc_addr[j]) == 0) + break; + if (j == enic->uc_count) + enic_dev_add_addr(enic, uc_addr[i]); + } + + /* Save the list to compare against next time + */ + + for (i = 0; i < uc_count; i++) + memcpy(enic->uc_addr[i], uc_addr[i], ETH_ALEN); + + enic->uc_count = uc_count; +} + +/* netif_tx_lock held, BHs disabled */ +static void enic_set_rx_mode(struct net_device *netdev) +{ + struct enic *enic = netdev_priv(netdev); + int directed = 1; + int multicast = (netdev->flags & IFF_MULTICAST) ? 1 : 0; + int broadcast = (netdev->flags & IFF_BROADCAST) ? 1 : 0; + int promisc = (netdev->flags & IFF_PROMISC) || + netdev_uc_count(netdev) > ENIC_UNICAST_PERFECT_FILTERS; + int allmulti = (netdev->flags & IFF_ALLMULTI) || + netdev_mc_count(netdev) > ENIC_MULTICAST_PERFECT_FILTERS; + unsigned int flags = netdev->flags | + (allmulti ? IFF_ALLMULTI : 0) | + (promisc ? IFF_PROMISC : 0); + + if (enic->flags != flags) { + enic->flags = flags; + enic_dev_packet_filter(enic, directed, + multicast, broadcast, promisc, allmulti); + } + + if (!promisc) { + enic_add_unicast_addr_list(enic); + if (!allmulti) + enic_add_multicast_addr_list(enic); + } +} + /* rtnl lock is held */ static void enic_vlan_rx_register(struct net_device *netdev, struct vlan_group *vlan_group) @@ -1852,7 +1925,7 @@ static int enic_open(struct net_device *netdev) vnic_rq_enable(&enic->rq[i]); enic_dev_add_station_addr(enic); - enic_set_multicast_list(netdev); + enic_set_rx_mode(netdev); netif_wake_queue(netdev); @@ -2328,7 +2401,8 @@ static const struct net_device_ops enic_netdev_dynamic_ops = { .ndo_start_xmit = enic_hard_start_xmit, .ndo_get_stats = enic_get_stats, .ndo_validate_addr = eth_validate_addr, - .ndo_set_multicast_list = enic_set_multicast_list, + .ndo_set_rx_mode = enic_set_rx_mode, + .ndo_set_multicast_list = enic_set_rx_mode, .ndo_set_mac_address = enic_set_mac_address_dynamic, .ndo_change_mtu = enic_change_mtu, .ndo_vlan_rx_register = enic_vlan_rx_register, @@ -2349,7 +2423,8 @@ static const struct net_device_ops enic_netdev_ops = { .ndo_get_stats = enic_get_stats, .ndo_validate_addr = eth_validate_addr, .ndo_set_mac_address = enic_set_mac_address, - .ndo_set_multicast_list = enic_set_multicast_list, + .ndo_set_rx_mode = enic_set_rx_mode, + .ndo_set_multicast_list = enic_set_rx_mode, .ndo_change_mtu = enic_change_mtu, .ndo_vlan_rx_register = enic_vlan_rx_register, .ndo_vlan_rx_add_vid = enic_vlan_rx_add_vid, |