|
@@ -1002,7 +1002,7 @@ static int enic_dev_packet_filter(struct enic *enic, int directed,
|
|
return err;
|
|
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;
|
|
int err;
|
|
|
|
|
|
@@ -1013,7 +1013,7 @@ static int enic_dev_add_multicast_addr(struct enic *enic, u8 *addr)
|
|
return err;
|
|
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;
|
|
int err;
|
|
|
|
|
|
@@ -1024,29 +1024,19 @@ static int enic_dev_del_multicast_addr(struct enic *enic, u8 *addr)
|
|
return err;
|
|
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;
|
|
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);
|
|
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];
|
|
u8 mc_addr[ENIC_MULTICAST_PERFECT_FILTERS][ETH_ALEN];
|
|
unsigned int i, j;
|
|
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;
|
|
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
|
|
/* 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)
|
|
mc_addr[j]) == 0)
|
|
break;
|
|
break;
|
|
if (j == mc_count)
|
|
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++) {
|
|
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)
|
|
enic->mc_addr[j]) == 0)
|
|
break;
|
|
break;
|
|
if (j == enic->mc_count)
|
|
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
|
|
/* 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;
|
|
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 */
|
|
/* rtnl lock is held */
|
|
static void enic_vlan_rx_register(struct net_device *netdev,
|
|
static void enic_vlan_rx_register(struct net_device *netdev,
|
|
struct vlan_group *vlan_group)
|
|
struct vlan_group *vlan_group)
|
|
@@ -1852,7 +1925,7 @@ static int enic_open(struct net_device *netdev)
|
|
vnic_rq_enable(&enic->rq[i]);
|
|
vnic_rq_enable(&enic->rq[i]);
|
|
|
|
|
|
enic_dev_add_station_addr(enic);
|
|
enic_dev_add_station_addr(enic);
|
|
- enic_set_multicast_list(netdev);
|
|
|
|
|
|
+ enic_set_rx_mode(netdev);
|
|
|
|
|
|
netif_wake_queue(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_start_xmit = enic_hard_start_xmit,
|
|
.ndo_get_stats = enic_get_stats,
|
|
.ndo_get_stats = enic_get_stats,
|
|
.ndo_validate_addr = eth_validate_addr,
|
|
.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_set_mac_address = enic_set_mac_address_dynamic,
|
|
.ndo_change_mtu = enic_change_mtu,
|
|
.ndo_change_mtu = enic_change_mtu,
|
|
.ndo_vlan_rx_register = enic_vlan_rx_register,
|
|
.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_get_stats = enic_get_stats,
|
|
.ndo_validate_addr = eth_validate_addr,
|
|
.ndo_validate_addr = eth_validate_addr,
|
|
.ndo_set_mac_address = enic_set_mac_address,
|
|
.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_change_mtu = enic_change_mtu,
|
|
.ndo_vlan_rx_register = enic_vlan_rx_register,
|
|
.ndo_vlan_rx_register = enic_vlan_rx_register,
|
|
.ndo_vlan_rx_add_vid = enic_vlan_rx_add_vid,
|
|
.ndo_vlan_rx_add_vid = enic_vlan_rx_add_vid,
|