All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH net-next v2 0/9] net/mlx4_en: Add support for unicast MAC filtering and FDB operations
@ 2013-02-07 12:25 Amir Vadai
  2013-02-07 12:25 ` [PATCH net-next v2 1/9] net/mlx4_en: Optimize loopback related checks in data path Amir Vadai
                   ` (9 more replies)
  0 siblings, 10 replies; 11+ messages in thread
From: Amir Vadai @ 2013-02-07 12:25 UTC (permalink / raw)
  To: David S. Miller; +Cc: Amir Vadai, Or Gerlitz, Yan Burman, netdev

This series from Yan Burman adds support for unicast MAC address filtering and
ndo FDB operations.  It also includes some optimizations to loopback related
decisions and checks in the TX/RX fast path and one cleanup, all in separate
patches.

Today, when adding macvlan devices, the NIC goes into promiscuous mode, since
unicast MAC filtering is not supported. With these changes, macvlan devices can
be added without the penalty of promiscuous mode.

If for some reason adding a unicast address filter fails e.g as of missing space in
the HW mac table, the device forces itself into promiscuous mode (and out of this
forced state when enough space is available).

Also, now it is possible to have bridge under multi-function configuration that include
PF and VFs.  In order to use bridge over PF/VFs, VM MAC fdb entries must be added e.g.
using 'bridge fdb add' command.

Changes from v1 - based on more comments from Eric Dumazet:
* added failure handling when adding unicast address filter

Changes from v0 - based on comments from Eric Dumazet:
* Removed unneeded synchronize_rcu()
* Use kfree_rcu() instead of synchronize_rcu() + kfree()

Yan Burman (9):
  net/mlx4_en: Optimize loopback related checks in data path
  net/mlx4_en: Optimize Rx fast path filter checks
  net/mlx4_en: Cleanup multiline strings
  net/mlx4: Move Ethernet related functionality from mlx4_core to
    mlx4_en
  net/mlx4_en: Re-arrange ndo_set_rx_mode related code
  net/mlx4_en: Save previous MAC address of the port so we can replace
    it later
  net/mlx4_en: Manage hash of MAC addresses per port
  net/mlx4_en: Add unicast MAC filtering
  net/mlx4_en: Implement ndo fdb functionality

 drivers/net/ethernet/mellanox/mlx4/en_ethtool.c  |    9 +-
 drivers/net/ethernet/mellanox/mlx4/en_main.c     |   22 +
 drivers/net/ethernet/mellanox/mlx4/en_netdev.c   |  765 +++++++++++++++++-----
 drivers/net/ethernet/mellanox/mlx4/en_rx.c       |   53 +-
 drivers/net/ethernet/mellanox/mlx4/en_selftest.c |    3 +
 drivers/net/ethernet/mellanox/mlx4/en_tx.c       |    2 +-
 drivers/net/ethernet/mellanox/mlx4/main.c        |    5 +-
 drivers/net/ethernet/mellanox/mlx4/mlx4.h        |    7 -
 drivers/net/ethernet/mellanox/mlx4/mlx4_en.h     |   33 +-
 drivers/net/ethernet/mellanox/mlx4/port.c        |  193 +------
 include/linux/mlx4/device.h                      |    5 +-
 11 files changed, 709 insertions(+), 388 deletions(-)

-- 
1.7.8.2

^ permalink raw reply	[flat|nested] 11+ messages in thread

* [PATCH net-next v2 1/9] net/mlx4_en: Optimize loopback related checks in data path
  2013-02-07 12:25 [PATCH net-next v2 0/9] net/mlx4_en: Add support for unicast MAC filtering and FDB operations Amir Vadai
@ 2013-02-07 12:25 ` Amir Vadai
  2013-02-07 12:25 ` [PATCH net-next v2 2/9] net/mlx4_en: Optimize Rx fast path filter checks Amir Vadai
                   ` (8 subsequent siblings)
  9 siblings, 0 replies; 11+ messages in thread
From: Amir Vadai @ 2013-02-07 12:25 UTC (permalink / raw)
  To: David S. Miller; +Cc: Amir Vadai, Or Gerlitz, Yan Burman, netdev

From: Yan Burman <yanb@mellanox.com>

Currently there are relatively complex conditional checks in the fast path,
for TX loopback enabling and resulting RX filter logic.
Move elaborate if's out of data path, replace them with a single flag
for each state and update that state from appropriate places.
Also, in native (non SRIOV) mode and not in loopback or in selftest,
there is no need to try and filter out packets that HW loopback-ed,
as in native mode we do not loopback packets anymore.

Signed-off-by: Yan Burman <yanb@mellanox.com>
Signed-off-by: Amir Vadai <amirv@mellanox.com>
---
 drivers/net/ethernet/mellanox/mlx4/en_main.c     |   22 ++++++++++++
 drivers/net/ethernet/mellanox/mlx4/en_netdev.c   |    4 ++
 drivers/net/ethernet/mellanox/mlx4/en_rx.c       |   39 ++++++++++++----------
 drivers/net/ethernet/mellanox/mlx4/en_selftest.c |    3 ++
 drivers/net/ethernet/mellanox/mlx4/en_tx.c       |    2 +-
 drivers/net/ethernet/mellanox/mlx4/mlx4_en.h     |   16 ++++++++-
 6 files changed, 65 insertions(+), 21 deletions(-)

diff --git a/drivers/net/ethernet/mellanox/mlx4/en_main.c b/drivers/net/ethernet/mellanox/mlx4/en_main.c
index f3c7961..e3c3d12 100644
--- a/drivers/net/ethernet/mellanox/mlx4/en_main.c
+++ b/drivers/net/ethernet/mellanox/mlx4/en_main.c
@@ -95,6 +95,28 @@ int en_print(const char *level, const struct mlx4_en_priv *priv,
 	return i;
 }
 
+void mlx4_en_update_loopback_state(struct net_device *dev,
+				   netdev_features_t features)
+{
+	struct mlx4_en_priv *priv = netdev_priv(dev);
+
+	priv->flags &= ~(MLX4_EN_FLAG_RX_FILTER_NEEDED|
+			MLX4_EN_FLAG_ENABLE_HW_LOOPBACK);
+
+	/* Drop the packet if SRIOV is not enabled
+	 * and not performing the selftest or flb disabled
+	 */
+	if (mlx4_is_mfunc(priv->mdev->dev) &&
+	    !(features & NETIF_F_LOOPBACK) && !priv->validate_loopback)
+		priv->flags |= MLX4_EN_FLAG_RX_FILTER_NEEDED;
+
+	/* Set dmac in Tx WQE if we are in SRIOV mode or if loopback selftest
+	 * is requested
+	 */
+	if (mlx4_is_mfunc(priv->mdev->dev) || priv->validate_loopback)
+		priv->flags |= MLX4_EN_FLAG_ENABLE_HW_LOOPBACK;
+}
+
 static int mlx4_en_get_profile(struct mlx4_en_dev *mdev)
 {
 	struct mlx4_en_profile *params = &mdev->profile;
diff --git a/drivers/net/ethernet/mellanox/mlx4/en_netdev.c b/drivers/net/ethernet/mellanox/mlx4/en_netdev.c
index ac1c14f..551ef68 100644
--- a/drivers/net/ethernet/mellanox/mlx4/en_netdev.c
+++ b/drivers/net/ethernet/mellanox/mlx4/en_netdev.c
@@ -1563,6 +1563,8 @@ static int mlx4_en_set_features(struct net_device *netdev,
 		priv->ctrl_flags &=
 			cpu_to_be32(~MLX4_WQE_CTRL_FORCE_LOOPBACK);
 
+	mlx4_en_update_loopback_state(netdev, features);
+
 	return 0;
 
 }
@@ -1731,6 +1733,8 @@ int mlx4_en_init_netdev(struct mlx4_en_dev *mdev, int port,
 	en_warn(priv, "Using %d TX rings\n", prof->tx_ring_num);
 	en_warn(priv, "Using %d RX rings\n", prof->rx_ring_num);
 
+	mlx4_en_update_loopback_state(priv->dev, priv->dev->features);
+
 	/* Configure port */
 	mlx4_en_calc_rx_buf(dev);
 	err = mlx4_SET_PORT_general(mdev->dev, priv->port,
diff --git a/drivers/net/ethernet/mellanox/mlx4/en_rx.c b/drivers/net/ethernet/mellanox/mlx4/en_rx.c
index fed26d8..ed214d0 100644
--- a/drivers/net/ethernet/mellanox/mlx4/en_rx.c
+++ b/drivers/net/ethernet/mellanox/mlx4/en_rx.c
@@ -563,9 +563,6 @@ int mlx4_en_process_rx_cq(struct net_device *dev, struct mlx4_en_cq *cq, int bud
 	unsigned int length;
 	int polled = 0;
 	int ip_summed;
-	struct ethhdr *ethh;
-	dma_addr_t dma;
-	u64 s_mac;
 	int factor = priv->cqe_factor;
 
 	if (!priv->port_up)
@@ -603,21 +600,27 @@ int mlx4_en_process_rx_cq(struct net_device *dev, struct mlx4_en_cq *cq, int bud
 			goto next;
 		}
 
-		/* Get pointer to first fragment since we haven't skb yet and
-		 * cast it to ethhdr struct */
-		dma = be64_to_cpu(rx_desc->data[0].addr);
-		dma_sync_single_for_cpu(priv->ddev, dma, sizeof(*ethh),
-					DMA_FROM_DEVICE);
-		ethh = (struct ethhdr *)(page_address(frags[0].page) +
-					 frags[0].offset);
-		s_mac = mlx4_en_mac_to_u64(ethh->h_source);
-
-		/* If source MAC is equal to our own MAC and not performing
-		 * the selftest or flb disabled - drop the packet */
-		if (s_mac == priv->mac &&
-		    !((dev->features & NETIF_F_LOOPBACK) ||
-		      priv->validate_loopback))
-			goto next;
+		/* Check if we need to drop the packet if SRIOV is not enabled
+		 * and not performing the selftest or flb disabled
+		 */
+		if (priv->flags & MLX4_EN_FLAG_RX_FILTER_NEEDED) {
+			struct ethhdr *ethh;
+			dma_addr_t dma;
+			u64 s_mac;
+			/* Get pointer to first fragment since we haven't
+			 * skb yet and cast it to ethhdr struct
+			 */
+			dma = be64_to_cpu(rx_desc->data[0].addr);
+			dma_sync_single_for_cpu(priv->ddev, dma, sizeof(*ethh),
+						DMA_FROM_DEVICE);
+			ethh = (struct ethhdr *)(page_address(frags[0].page) +
+						 frags[0].offset);
+
+			/* Drop the packet, since HW loopback-ed it */
+			s_mac = mlx4_en_mac_to_u64(ethh->h_source);
+			if (s_mac == priv->mac)
+				goto next;
+		}
 
 		/*
 		 * Packet is OK - process it.
diff --git a/drivers/net/ethernet/mellanox/mlx4/en_selftest.c b/drivers/net/ethernet/mellanox/mlx4/en_selftest.c
index bf2e5d3..3488c6d 100644
--- a/drivers/net/ethernet/mellanox/mlx4/en_selftest.c
+++ b/drivers/net/ethernet/mellanox/mlx4/en_selftest.c
@@ -87,6 +87,8 @@ static int mlx4_en_test_loopback(struct mlx4_en_priv *priv)
         priv->loopback_ok = 0;
 	priv->validate_loopback = 1;
 
+	mlx4_en_update_loopback_state(priv->dev, priv->dev->features);
+
 	/* xmit */
 	if (mlx4_en_test_loopback_xmit(priv)) {
 		en_err(priv, "Transmitting loopback packet failed\n");
@@ -107,6 +109,7 @@ static int mlx4_en_test_loopback(struct mlx4_en_priv *priv)
 mlx4_en_test_loopback_exit:
 
 	priv->validate_loopback = 0;
+	mlx4_en_update_loopback_state(priv->dev, priv->dev->features);
 	return !loopback_ok;
 }
 
diff --git a/drivers/net/ethernet/mellanox/mlx4/en_tx.c b/drivers/net/ethernet/mellanox/mlx4/en_tx.c
index 30724d8..3b28e16 100644
--- a/drivers/net/ethernet/mellanox/mlx4/en_tx.c
+++ b/drivers/net/ethernet/mellanox/mlx4/en_tx.c
@@ -640,7 +640,7 @@ netdev_tx_t mlx4_en_xmit(struct sk_buff *skb, struct net_device *dev)
 		ring->tx_csum++;
 	}
 
-	if (mlx4_is_mfunc(mdev->dev) || priv->validate_loopback) {
+	if (priv->flags & MLX4_EN_FLAG_ENABLE_HW_LOOPBACK) {
 		/* Copy dst mac address to wqe. This allows loopback in eSwitch,
 		 * so that VFs and PF can communicate with each other
 		 */
diff --git a/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h b/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h
index 43f0165..696dcf3 100644
--- a/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h
+++ b/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h
@@ -432,6 +432,17 @@ struct ethtool_flow_id {
 	u64 id;
 };
 
+enum {
+	MLX4_EN_FLAG_PROMISC		= (1 << 0),
+	MLX4_EN_FLAG_MC_PROMISC		= (1 << 1),
+	/* whether we need to enable hardware loopback by putting dmac
+	 * in Tx WQE
+	 */
+	MLX4_EN_FLAG_ENABLE_HW_LOOPBACK	= (1 << 2),
+	/* whether we need to drop packets that hardware loopback-ed */
+	MLX4_EN_FLAG_RX_FILTER_NEEDED	= (1 << 3)
+};
+
 struct mlx4_en_priv {
 	struct mlx4_en_dev *mdev;
 	struct mlx4_en_port_profile *prof;
@@ -481,8 +492,6 @@ struct mlx4_en_priv {
 	struct mlx4_en_rss_map rss_map;
 	__be32 ctrl_flags;
 	u32 flags;
-#define MLX4_EN_FLAG_PROMISC	0x1
-#define MLX4_EN_FLAG_MC_PROMISC	0x2
 	u8 num_tx_rings_p_up;
 	u32 tx_ring_num;
 	u32 rx_ring_num;
@@ -534,6 +543,9 @@ enum mlx4_en_wol {
 
 #define MLX4_EN_WOL_DO_MODIFY (1ULL << 63)
 
+void mlx4_en_update_loopback_state(struct net_device *dev,
+				   netdev_features_t features);
+
 void mlx4_en_destroy_netdev(struct net_device *dev);
 int mlx4_en_init_netdev(struct mlx4_en_dev *mdev, int port,
 			struct mlx4_en_port_profile *prof);
-- 
1.7.8.2

^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH net-next v2 2/9] net/mlx4_en: Optimize Rx fast path filter checks
  2013-02-07 12:25 [PATCH net-next v2 0/9] net/mlx4_en: Add support for unicast MAC filtering and FDB operations Amir Vadai
  2013-02-07 12:25 ` [PATCH net-next v2 1/9] net/mlx4_en: Optimize loopback related checks in data path Amir Vadai
@ 2013-02-07 12:25 ` Amir Vadai
  2013-02-07 12:25 ` [PATCH net-next v2 3/9] net/mlx4_en: Cleanup multiline strings Amir Vadai
                   ` (7 subsequent siblings)
  9 siblings, 0 replies; 11+ messages in thread
From: Amir Vadai @ 2013-02-07 12:25 UTC (permalink / raw)
  To: David S. Miller; +Cc: Amir Vadai, Or Gerlitz, Yan Burman, netdev

From: Yan Burman <yanb@mellanox.com>

Currently, RX path code that does RX filtering is not optimized
and does an expensive conversion. In order to use ether_addr_equal_64bits
which is optimized for such cases, we need the MAC address kept by the device
to be in the form of unsigned char array instead of u64. Store the MAC address
as unsigned char array and convert to/from u64 out of the fast path when needed.
Side effect of this is that we no longer need priv->mac, since it's the same
as dev->dev_addr.

This optimization was suggested by Eric Dumazet <eric.dumazet@gmail.com>

Signed-off-by: Yan Burman <yanb@mellanox.com>
Signed-off-by: Amir Vadai <amirv@mellanox.com>
---
 drivers/net/ethernet/mellanox/mlx4/en_ethtool.c |    9 +---
 drivers/net/ethernet/mellanox/mlx4/en_netdev.c  |   48 ++++++++++++++---------
 drivers/net/ethernet/mellanox/mlx4/en_rx.c      |    5 +-
 drivers/net/ethernet/mellanox/mlx4/mlx4_en.h    |    3 +-
 4 files changed, 35 insertions(+), 30 deletions(-)

diff --git a/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c b/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c
index f523f02..8a08c5e 100644
--- a/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c
+++ b/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c
@@ -712,16 +712,13 @@ static int mlx4_en_ethtool_add_mac_rule_by_ipv4(struct mlx4_en_priv *priv,
 						__be32 ipv4_dst)
 {
 #ifdef CONFIG_INET
-	__be64 be_mac = 0;
 	unsigned char mac[ETH_ALEN];
 
 	if (!ipv4_is_multicast(ipv4_dst)) {
-		if (cmd->fs.flow_type & FLOW_MAC_EXT) {
+		if (cmd->fs.flow_type & FLOW_MAC_EXT)
 			memcpy(&mac, cmd->fs.h_ext.h_dest, ETH_ALEN);
-		} else {
-			be_mac = cpu_to_be64((priv->mac & MLX4_MAC_MASK) << 16);
-			memcpy(&mac, &be_mac, ETH_ALEN);
-		}
+		else
+			memcpy(&mac, priv->dev->dev_addr, ETH_ALEN);
 	} else {
 		ip_eth_mc_map(ipv4_dst, mac);
 	}
diff --git a/drivers/net/ethernet/mellanox/mlx4/en_netdev.c b/drivers/net/ethernet/mellanox/mlx4/en_netdev.c
index 551ef68..f7338cb 100644
--- a/drivers/net/ethernet/mellanox/mlx4/en_netdev.c
+++ b/drivers/net/ethernet/mellanox/mlx4/en_netdev.c
@@ -132,17 +132,14 @@ static void mlx4_en_filter_work(struct work_struct *work)
 		.priority = MLX4_DOMAIN_RFS,
 	};
 	int rc;
-	__be64 mac;
 	__be64 mac_mask = cpu_to_be64(MLX4_MAC_MASK << 16);
 
 	list_add_tail(&spec_eth.list, &rule.list);
 	list_add_tail(&spec_ip.list, &rule.list);
 	list_add_tail(&spec_tcp.list, &rule.list);
 
-	mac = cpu_to_be64((priv->mac & MLX4_MAC_MASK) << 16);
-
 	rule.qpn = priv->rss_map.qps[filter->rxq_index].qpn;
-	memcpy(spec_eth.eth.dst_mac, &mac, ETH_ALEN);
+	memcpy(spec_eth.eth.dst_mac, priv->dev->dev_addr, ETH_ALEN);
 	memcpy(spec_eth.eth.dst_mac_msk, &mac_mask, ETH_ALEN);
 
 	filter->activated = 0;
@@ -413,6 +410,16 @@ static int mlx4_en_vlan_rx_kill_vid(struct net_device *dev, unsigned short vid)
 	return 0;
 }
 
+static void mlx4_en_u64_to_mac(unsigned char dst_mac[ETH_ALEN + 2], u64 src_mac)
+{
+	unsigned int i;
+	for (i = ETH_ALEN - 1; i; --i) {
+		dst_mac[i] = src_mac & 0xff;
+		src_mac >>= 8;
+	}
+	memset(&dst_mac[ETH_ALEN], 0, 2);
+}
+
 u64 mlx4_en_mac_to_u64(u8 *addr)
 {
 	u64 mac = 0;
@@ -435,7 +442,6 @@ static int mlx4_en_set_mac(struct net_device *dev, void *addr)
 		return -EADDRNOTAVAIL;
 
 	memcpy(dev->dev_addr, saddr->sa_data, ETH_ALEN);
-	priv->mac = mlx4_en_mac_to_u64(dev->dev_addr);
 	queue_work(mdev->workqueue, &priv->mac_task);
 	return 0;
 }
@@ -450,10 +456,13 @@ static void mlx4_en_do_set_mac(struct work_struct *work)
 	mutex_lock(&mdev->state_lock);
 	if (priv->port_up) {
 		/* Remove old MAC and insert the new one */
+		u64 mac = mlx4_en_mac_to_u64(priv->dev->dev_addr);
 		err = mlx4_replace_mac(mdev->dev, priv->port,
-				       priv->base_qpn, priv->mac);
+				       priv->base_qpn, mac);
 		if (err)
 			en_err(priv, "Failed changing HW MAC address\n");
+		memcpy(priv->prev_mac, priv->dev->dev_addr,
+		       sizeof(priv->prev_mac));
 	} else
 		en_dbg(HW, priv, "Port is down while "
 				 "registering mac, exiting...\n");
@@ -1031,6 +1040,7 @@ int mlx4_en_start_port(struct net_device *dev)
 	int i;
 	int j;
 	u8 mc_list[16] = {0};
+	u64 mac = mlx4_en_mac_to_u64(dev->dev_addr);
 
 	if (priv->port_up) {
 		en_dbg(DRV, priv, "start port called while port already up\n");
@@ -1078,7 +1088,7 @@ int mlx4_en_start_port(struct net_device *dev)
 	/* Set qp number */
 	en_dbg(DRV, priv, "Getting qp number for port %d\n", priv->port);
 	err = mlx4_get_eth_qp(mdev->dev, priv->port,
-				priv->mac, &priv->base_qpn);
+			      mac, &priv->base_qpn);
 	if (err) {
 		en_err(priv, "Failed getting eth qp\n");
 		goto cq_err;
@@ -1191,7 +1201,7 @@ tx_err:
 rss_err:
 	mlx4_en_release_rss_steer(priv);
 mac_err:
-	mlx4_put_eth_qp(mdev->dev, priv->port, priv->mac, priv->base_qpn);
+	mlx4_put_eth_qp(mdev->dev, priv->port, mac, priv->base_qpn);
 cq_err:
 	while (rx_index--)
 		mlx4_en_deactivate_cq(priv, &priv->rx_cq[rx_index]);
@@ -1210,6 +1220,7 @@ void mlx4_en_stop_port(struct net_device *dev, int detach)
 	struct ethtool_flow_id *flow, *tmp_flow;
 	int i;
 	u8 mc_list[16] = {0};
+	u64 mac = mlx4_en_mac_to_u64(dev->dev_addr);
 
 	if (!priv->port_up) {
 		en_dbg(DRV, priv, "stop port called while port already down\n");
@@ -1290,7 +1301,7 @@ void mlx4_en_stop_port(struct net_device *dev, int detach)
 	mlx4_en_release_rss_steer(priv);
 
 	/* Unregister Mac address for the port */
-	mlx4_put_eth_qp(mdev->dev, priv->port, priv->mac, priv->base_qpn);
+	mlx4_put_eth_qp(mdev->dev, priv->port, mac, priv->base_qpn);
 	if (!(mdev->dev->caps.flags2 & MLX4_DEV_CAP_FLAGS2_REASSIGN_MAC_EN))
 		mdev->mac_removed[priv->port] = 1;
 
@@ -1597,7 +1608,6 @@ int mlx4_en_init_netdev(struct mlx4_en_dev *mdev, int port,
 {
 	struct net_device *dev;
 	struct mlx4_en_priv *priv;
-	int i;
 	int err;
 
 	dev = alloc_etherdev_mqs(sizeof(struct mlx4_en_priv),
@@ -1658,14 +1668,19 @@ int mlx4_en_init_netdev(struct mlx4_en_dev *mdev, int port,
 
 	/* Query for default mac and max mtu */
 	priv->max_mtu = mdev->dev->caps.eth_mtu_cap[priv->port];
-	priv->mac = mdev->dev->caps.def_mac[priv->port];
-	if (ILLEGAL_MAC(priv->mac)) {
-		en_err(priv, "Port: %d, invalid mac burned: 0x%llx, quiting\n",
-			 priv->port, priv->mac);
+
+	/* Set default MAC */
+	dev->addr_len = ETH_ALEN;
+	mlx4_en_u64_to_mac(dev->dev_addr, mdev->dev->caps.def_mac[priv->port]);
+	if (!is_valid_ether_addr(dev->dev_addr)) {
+		en_err(priv, "Port: %d, invalid mac burned: %pM, quiting\n",
+		       priv->port, dev->dev_addr);
 		err = -EINVAL;
 		goto out;
 	}
 
+	memcpy(priv->prev_mac, dev->dev_addr, sizeof(priv->prev_mac));
+
 	priv->stride = roundup_pow_of_two(sizeof(struct mlx4_en_rx_desc) +
 					  DS_SIZE * MLX4_EN_MAX_RX_FRAGS);
 	err = mlx4_en_alloc_resources(priv);
@@ -1696,11 +1711,6 @@ int mlx4_en_init_netdev(struct mlx4_en_dev *mdev, int port,
 
 	SET_ETHTOOL_OPS(dev, &mlx4_en_ethtool_ops);
 
-	/* Set defualt MAC */
-	dev->addr_len = ETH_ALEN;
-	for (i = 0; i < ETH_ALEN; i++)
-		dev->dev_addr[ETH_ALEN - 1 - i] = (u8) (priv->mac >> (8 * i));
-
 	/*
 	 * Set driver features
 	 */
diff --git a/drivers/net/ethernet/mellanox/mlx4/en_rx.c b/drivers/net/ethernet/mellanox/mlx4/en_rx.c
index ed214d0..2e7f5bb 100644
--- a/drivers/net/ethernet/mellanox/mlx4/en_rx.c
+++ b/drivers/net/ethernet/mellanox/mlx4/en_rx.c
@@ -606,7 +606,6 @@ int mlx4_en_process_rx_cq(struct net_device *dev, struct mlx4_en_cq *cq, int bud
 		if (priv->flags & MLX4_EN_FLAG_RX_FILTER_NEEDED) {
 			struct ethhdr *ethh;
 			dma_addr_t dma;
-			u64 s_mac;
 			/* Get pointer to first fragment since we haven't
 			 * skb yet and cast it to ethhdr struct
 			 */
@@ -617,8 +616,8 @@ int mlx4_en_process_rx_cq(struct net_device *dev, struct mlx4_en_cq *cq, int bud
 						 frags[0].offset);
 
 			/* Drop the packet, since HW loopback-ed it */
-			s_mac = mlx4_en_mac_to_u64(ethh->h_source);
-			if (s_mac == priv->mac)
+			if (ether_addr_equal_64bits(dev->dev_addr,
+						    ethh->h_source))
 				goto next;
 		}
 
diff --git a/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h b/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h
index 696dcf3..9d0105d 100644
--- a/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h
+++ b/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h
@@ -198,7 +198,6 @@ enum cq_type {
  */
 #define ROUNDUP_LOG2(x)		ilog2(roundup_pow_of_two(x))
 #define XNOR(x, y)		(!(x) == !(y))
-#define ILLEGAL_MAC(addr)	(addr == 0xffffffffffffULL || addr == 0x0)
 
 
 struct mlx4_en_tx_info {
@@ -483,7 +482,7 @@ struct mlx4_en_priv {
 	int registered;
 	int allocated;
 	int stride;
-	u64 mac;
+	unsigned char prev_mac[ETH_ALEN + 2];
 	int mac_index;
 	unsigned max_mtu;
 	int base_qpn;
-- 
1.7.8.2

^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH net-next v2 3/9] net/mlx4_en: Cleanup multiline strings
  2013-02-07 12:25 [PATCH net-next v2 0/9] net/mlx4_en: Add support for unicast MAC filtering and FDB operations Amir Vadai
  2013-02-07 12:25 ` [PATCH net-next v2 1/9] net/mlx4_en: Optimize loopback related checks in data path Amir Vadai
  2013-02-07 12:25 ` [PATCH net-next v2 2/9] net/mlx4_en: Optimize Rx fast path filter checks Amir Vadai
@ 2013-02-07 12:25 ` Amir Vadai
  2013-02-07 12:25 ` [PATCH net-next v2 4/9] net/mlx4: Move Ethernet related functionality from mlx4_core to mlx4_en Amir Vadai
                   ` (6 subsequent siblings)
  9 siblings, 0 replies; 11+ messages in thread
From: Amir Vadai @ 2013-02-07 12:25 UTC (permalink / raw)
  To: David S. Miller; +Cc: Amir Vadai, Or Gerlitz, Yan Burman, netdev

From: Yan Burman <yanb@mellanox.com>

Make the code consistent in regard to error messages
not spanning multiple lines.

Signed-off-by: Yan Burman <yanb@mellanox.com>
Signed-off-by: Amir Vadai <amirv@mellanox.com>
---
 drivers/net/ethernet/mellanox/mlx4/en_netdev.c |   25 +++++++++--------------
 1 files changed, 10 insertions(+), 15 deletions(-)

diff --git a/drivers/net/ethernet/mellanox/mlx4/en_netdev.c b/drivers/net/ethernet/mellanox/mlx4/en_netdev.c
index f7338cb..0843dd7 100644
--- a/drivers/net/ethernet/mellanox/mlx4/en_netdev.c
+++ b/drivers/net/ethernet/mellanox/mlx4/en_netdev.c
@@ -464,8 +464,7 @@ static void mlx4_en_do_set_mac(struct work_struct *work)
 		memcpy(priv->prev_mac, priv->dev->dev_addr,
 		       sizeof(priv->prev_mac));
 	} else
-		en_dbg(HW, priv, "Port is down while "
-				 "registering mac, exiting...\n");
+		en_dbg(HW, priv, "Port is down while registering mac, exiting...\n");
 
 	mutex_unlock(&mdev->state_lock);
 }
@@ -572,13 +571,11 @@ static void mlx4_en_do_set_multicast(struct work_struct *work)
 
 	mutex_lock(&mdev->state_lock);
 	if (!mdev->device_up) {
-		en_dbg(HW, priv, "Card is not up, "
-				 "ignoring multicast change.\n");
+		en_dbg(HW, priv, "Card is not up, ignoring multicast change.\n");
 		goto out;
 	}
 	if (!priv->port_up) {
-		en_dbg(HW, priv, "Port is down, "
-				 "ignoring  multicast change.\n");
+		en_dbg(HW, priv, "Port is down, ignoring  multicast change.\n");
 		goto out;
 	}
 
@@ -648,8 +645,7 @@ static void mlx4_en_do_set_multicast(struct work_struct *work)
 			err = mlx4_SET_MCAST_FLTR(mdev->dev, priv->port, 0,
 						  0, MLX4_MCAST_DISABLE);
 			if (err)
-				en_err(priv, "Failed disabling "
-					     "multicast filter\n");
+				en_err(priv, "Failed disabling multicast filter\n");
 
 			/* Disable port VLAN filter */
 			err = mlx4_SET_VLAN_FLTR(mdev->dev, priv);
@@ -885,9 +881,8 @@ static void mlx4_en_set_default_moderation(struct mlx4_en_priv *priv)
 	priv->rx_usecs = MLX4_EN_RX_COAL_TIME;
 	priv->tx_frames = MLX4_EN_TX_COAL_PKTS;
 	priv->tx_usecs = MLX4_EN_TX_COAL_TIME;
-	en_dbg(INTR, priv, "Default coalesing params for mtu:%d - "
-			   "rx_frames:%d rx_usecs:%d\n",
-		 priv->dev->mtu, priv->rx_frames, priv->rx_usecs);
+	en_dbg(INTR, priv, "Default coalesing params for mtu:%d - rx_frames:%d rx_usecs:%d\n",
+	       priv->dev->mtu, priv->rx_frames, priv->rx_usecs);
 
 	/* Setup cq moderation params */
 	for (i = 0; i < priv->rx_ring_num; i++) {
@@ -968,8 +963,8 @@ static void mlx4_en_auto_moderation(struct mlx4_en_priv *priv)
 			cq->moder_time = moder_time;
 			err = mlx4_en_set_cq_moder(priv, cq);
 			if (err)
-				en_err(priv, "Failed modifying moderation "
-					     "for cq:%d\n", ring);
+				en_err(priv, "Failed modifying moderation for cq:%d\n",
+				       ring);
 		}
 		priv->last_moder_packets[ring] = rx_packets;
 		priv->last_moder_bytes[ring] = rx_bytes;
@@ -1151,8 +1146,8 @@ int mlx4_en_start_port(struct net_device *dev)
 				    priv->prof->rx_pause,
 				    priv->prof->rx_ppp);
 	if (err) {
-		en_err(priv, "Failed setting port general configurations "
-			     "for port %d, with error %d\n", priv->port, err);
+		en_err(priv, "Failed setting port general configurations for port %d, with error %d\n",
+		       priv->port, err);
 		goto tx_err;
 	}
 	/* Set default qp number */
-- 
1.7.8.2

^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH net-next v2 4/9] net/mlx4: Move Ethernet related functionality from mlx4_core to mlx4_en
  2013-02-07 12:25 [PATCH net-next v2 0/9] net/mlx4_en: Add support for unicast MAC filtering and FDB operations Amir Vadai
                   ` (2 preceding siblings ...)
  2013-02-07 12:25 ` [PATCH net-next v2 3/9] net/mlx4_en: Cleanup multiline strings Amir Vadai
@ 2013-02-07 12:25 ` Amir Vadai
  2013-02-07 12:25 ` [PATCH net-next v2 5/9] net/mlx4_en: Re-arrange ndo_set_rx_mode related code Amir Vadai
                   ` (5 subsequent siblings)
  9 siblings, 0 replies; 11+ messages in thread
From: Amir Vadai @ 2013-02-07 12:25 UTC (permalink / raw)
  To: David S. Miller; +Cc: Amir Vadai, Or Gerlitz, Yan Burman, netdev

From: Yan Burman <yanb@mellanox.com>

Move low level code that deals with management of Ethernet MACs and QPs from mlx4_core to mlx4_en.
Also convert the new functions to deal with MACs in form of char array instead of u64.

Actual functions moved:
mlx4_replace_mac
mlx4_get_eth_qp
mlx4_put_eth_qp

To conduct this change, some functionality had to be exported from the core,
the following functions were added:
mlx4_get_base_qp
__mlx4_replace_mac (low level function for CX1/A0 compatibility)

Signed-off-by: Yan Burman <yanb@mellanox.com>
Signed-off-by: Amir Vadai <amirv@mellanox.com>
---
 drivers/net/ethernet/mellanox/mlx4/en_netdev.c |  216 +++++++++++++++++++++++-
 drivers/net/ethernet/mellanox/mlx4/main.c      |    5 +-
 drivers/net/ethernet/mellanox/mlx4/mlx4.h      |    7 -
 drivers/net/ethernet/mellanox/mlx4/mlx4_en.h   |    6 +
 drivers/net/ethernet/mellanox/mlx4/port.c      |  193 +--------------------
 include/linux/mlx4/device.h                    |    5 +-
 6 files changed, 224 insertions(+), 208 deletions(-)

diff --git a/drivers/net/ethernet/mellanox/mlx4/en_netdev.c b/drivers/net/ethernet/mellanox/mlx4/en_netdev.c
index 0843dd7..63a1ef3 100644
--- a/drivers/net/ethernet/mellanox/mlx4/en_netdev.c
+++ b/drivers/net/ethernet/mellanox/mlx4/en_netdev.c
@@ -420,6 +420,206 @@ static void mlx4_en_u64_to_mac(unsigned char dst_mac[ETH_ALEN + 2], u64 src_mac)
 	memset(&dst_mac[ETH_ALEN], 0, 2);
 }
 
+static int mlx4_en_uc_steer_add(struct mlx4_en_priv *priv,
+				unsigned char *mac, int *qpn, u64 *reg_id)
+{
+	struct mlx4_en_dev *mdev = priv->mdev;
+	struct mlx4_dev *dev = mdev->dev;
+	int err;
+
+	switch (dev->caps.steering_mode) {
+	case MLX4_STEERING_MODE_B0: {
+		struct mlx4_qp qp;
+		u8 gid[16] = {0};
+
+		qp.qpn = *qpn;
+		memcpy(&gid[10], mac, ETH_ALEN);
+		gid[5] = priv->port;
+
+		err = mlx4_unicast_attach(dev, &qp, gid, 0, MLX4_PROT_ETH);
+		break;
+	}
+	case MLX4_STEERING_MODE_DEVICE_MANAGED: {
+		struct mlx4_spec_list spec_eth = { {NULL} };
+		__be64 mac_mask = cpu_to_be64(MLX4_MAC_MASK << 16);
+
+		struct mlx4_net_trans_rule rule = {
+			.queue_mode = MLX4_NET_TRANS_Q_FIFO,
+			.exclusive = 0,
+			.allow_loopback = 1,
+			.promisc_mode = MLX4_FS_PROMISC_NONE,
+			.priority = MLX4_DOMAIN_NIC,
+		};
+
+		rule.port = priv->port;
+		rule.qpn = *qpn;
+		INIT_LIST_HEAD(&rule.list);
+
+		spec_eth.id = MLX4_NET_TRANS_RULE_ID_ETH;
+		memcpy(spec_eth.eth.dst_mac, mac, ETH_ALEN);
+		memcpy(spec_eth.eth.dst_mac_msk, &mac_mask, ETH_ALEN);
+		list_add_tail(&spec_eth.list, &rule.list);
+
+		err = mlx4_flow_attach(dev, &rule, reg_id);
+		break;
+	}
+	default:
+		return -EINVAL;
+	}
+	if (err)
+		en_warn(priv, "Failed Attaching Unicast\n");
+
+	return err;
+}
+
+static void mlx4_en_uc_steer_release(struct mlx4_en_priv *priv,
+				     unsigned char *mac, int qpn, u64 reg_id)
+{
+	struct mlx4_en_dev *mdev = priv->mdev;
+	struct mlx4_dev *dev = mdev->dev;
+
+	switch (dev->caps.steering_mode) {
+	case MLX4_STEERING_MODE_B0: {
+		struct mlx4_qp qp;
+		u8 gid[16] = {0};
+
+		qp.qpn = qpn;
+		memcpy(&gid[10], mac, ETH_ALEN);
+		gid[5] = priv->port;
+
+		mlx4_unicast_detach(dev, &qp, gid, MLX4_PROT_ETH);
+		break;
+	}
+	case MLX4_STEERING_MODE_DEVICE_MANAGED: {
+		mlx4_flow_detach(dev, reg_id);
+		break;
+	}
+	default:
+		en_err(priv, "Invalid steering mode.\n");
+	}
+}
+
+static int mlx4_en_get_qp(struct mlx4_en_priv *priv)
+{
+	struct mlx4_en_dev *mdev = priv->mdev;
+	struct mlx4_dev *dev = mdev->dev;
+	struct mlx4_mac_entry *entry;
+	int index = 0;
+	int err = 0;
+	u64 reg_id;
+	int *qpn = &priv->base_qpn;
+	u64 mac = mlx4_en_mac_to_u64(priv->dev->dev_addr);
+
+	en_dbg(DRV, priv, "Registering MAC: %pM for adding\n",
+	       priv->dev->dev_addr);
+	index = mlx4_register_mac(dev, priv->port, mac);
+	if (index < 0) {
+		err = index;
+		en_err(priv, "Failed adding MAC: %pM\n",
+		       priv->dev->dev_addr);
+		return err;
+	}
+
+	if (dev->caps.steering_mode == MLX4_STEERING_MODE_A0) {
+		int base_qpn = mlx4_get_base_qpn(dev, priv->port);
+		*qpn = base_qpn + index;
+		return 0;
+	}
+
+	err = mlx4_qp_reserve_range(dev, 1, 1, qpn);
+	en_dbg(DRV, priv, "Reserved qp %d\n", *qpn);
+	if (err) {
+		en_err(priv, "Failed to reserve qp for mac registration\n");
+		goto qp_err;
+	}
+
+	err = mlx4_en_uc_steer_add(priv, priv->dev->dev_addr, qpn, &reg_id);
+	if (err)
+		goto steer_err;
+
+	entry = kmalloc(sizeof(*entry), GFP_KERNEL);
+	if (!entry) {
+		err = -ENOMEM;
+		goto alloc_err;
+	}
+	memcpy(entry->mac, priv->dev->dev_addr, sizeof(entry->mac));
+	entry->reg_id = reg_id;
+
+	err = radix_tree_insert(&priv->mac_tree, *qpn, entry);
+	if (err)
+		goto insert_err;
+	return 0;
+
+insert_err:
+	kfree(entry);
+
+alloc_err:
+	mlx4_en_uc_steer_release(priv, priv->dev->dev_addr, *qpn, reg_id);
+
+steer_err:
+	mlx4_qp_release_range(dev, *qpn, 1);
+
+qp_err:
+	mlx4_unregister_mac(dev, priv->port, mac);
+	return err;
+}
+
+static void mlx4_en_put_qp(struct mlx4_en_priv *priv)
+{
+	struct mlx4_en_dev *mdev = priv->mdev;
+	struct mlx4_dev *dev = mdev->dev;
+	struct mlx4_mac_entry *entry;
+	int qpn = priv->base_qpn;
+	u64 mac = mlx4_en_mac_to_u64(priv->dev->dev_addr);
+
+	en_dbg(DRV, priv, "Registering MAC: %pM for deleting\n",
+	       priv->dev->dev_addr);
+	mlx4_unregister_mac(dev, priv->port, mac);
+
+	if (dev->caps.steering_mode != MLX4_STEERING_MODE_A0) {
+		entry = radix_tree_lookup(&priv->mac_tree, qpn);
+		if (entry) {
+			en_dbg(DRV, priv, "Releasing qp: port %d, MAC %pM, qpn %d\n",
+			       priv->port, entry->mac, qpn);
+			mlx4_en_uc_steer_release(priv, entry->mac,
+						 qpn, entry->reg_id);
+			mlx4_qp_release_range(dev, qpn, 1);
+			radix_tree_delete(&priv->mac_tree, qpn);
+			kfree(entry);
+		}
+	}
+}
+
+static int mlx4_en_replace_mac(struct mlx4_en_priv *priv, int qpn,
+			       unsigned char *new_mac)
+{
+	struct mlx4_en_dev *mdev = priv->mdev;
+	struct mlx4_dev *dev = mdev->dev;
+	struct mlx4_mac_entry *entry;
+	int err = 0;
+	u64 new_mac_u64 = mlx4_en_mac_to_u64(new_mac);
+
+	if (dev->caps.steering_mode != MLX4_STEERING_MODE_A0) {
+		u64 prev_mac_u64;
+
+		entry = radix_tree_lookup(&priv->mac_tree, qpn);
+		if (!entry)
+			return -EINVAL;
+		prev_mac_u64 = mlx4_en_mac_to_u64(entry->mac);
+		mlx4_en_uc_steer_release(priv, entry->mac,
+					 qpn, entry->reg_id);
+		mlx4_unregister_mac(dev, priv->port, prev_mac_u64);
+		memcpy(entry->mac, new_mac, ETH_ALEN);
+		entry->reg_id = 0;
+		mlx4_register_mac(dev, priv->port, new_mac_u64);
+		err = mlx4_en_uc_steer_add(priv, new_mac,
+					   &qpn, &entry->reg_id);
+		return err;
+	}
+
+	return __mlx4_replace_mac(dev, priv->port, qpn, new_mac_u64);
+}
+
 u64 mlx4_en_mac_to_u64(u8 *addr)
 {
 	u64 mac = 0;
@@ -456,9 +656,8 @@ static void mlx4_en_do_set_mac(struct work_struct *work)
 	mutex_lock(&mdev->state_lock);
 	if (priv->port_up) {
 		/* Remove old MAC and insert the new one */
-		u64 mac = mlx4_en_mac_to_u64(priv->dev->dev_addr);
-		err = mlx4_replace_mac(mdev->dev, priv->port,
-				       priv->base_qpn, mac);
+		err = mlx4_en_replace_mac(priv, priv->base_qpn,
+					  priv->dev->dev_addr);
 		if (err)
 			en_err(priv, "Failed changing HW MAC address\n");
 		memcpy(priv->prev_mac, priv->dev->dev_addr,
@@ -1035,7 +1234,6 @@ int mlx4_en_start_port(struct net_device *dev)
 	int i;
 	int j;
 	u8 mc_list[16] = {0};
-	u64 mac = mlx4_en_mac_to_u64(dev->dev_addr);
 
 	if (priv->port_up) {
 		en_dbg(DRV, priv, "start port called while port already up\n");
@@ -1082,8 +1280,7 @@ int mlx4_en_start_port(struct net_device *dev)
 
 	/* Set qp number */
 	en_dbg(DRV, priv, "Getting qp number for port %d\n", priv->port);
-	err = mlx4_get_eth_qp(mdev->dev, priv->port,
-			      mac, &priv->base_qpn);
+	err = mlx4_en_get_qp(priv);
 	if (err) {
 		en_err(priv, "Failed getting eth qp\n");
 		goto cq_err;
@@ -1196,7 +1393,7 @@ tx_err:
 rss_err:
 	mlx4_en_release_rss_steer(priv);
 mac_err:
-	mlx4_put_eth_qp(mdev->dev, priv->port, mac, priv->base_qpn);
+	mlx4_en_put_qp(priv);
 cq_err:
 	while (rx_index--)
 		mlx4_en_deactivate_cq(priv, &priv->rx_cq[rx_index]);
@@ -1215,7 +1412,6 @@ void mlx4_en_stop_port(struct net_device *dev, int detach)
 	struct ethtool_flow_id *flow, *tmp_flow;
 	int i;
 	u8 mc_list[16] = {0};
-	u64 mac = mlx4_en_mac_to_u64(dev->dev_addr);
 
 	if (!priv->port_up) {
 		en_dbg(DRV, priv, "stop port called while port already down\n");
@@ -1296,7 +1492,7 @@ void mlx4_en_stop_port(struct net_device *dev, int detach)
 	mlx4_en_release_rss_steer(priv);
 
 	/* Unregister Mac address for the port */
-	mlx4_put_eth_qp(mdev->dev, priv->port, mac, priv->base_qpn);
+	mlx4_en_put_qp(priv);
 	if (!(mdev->dev->caps.flags2 & MLX4_DEV_CAP_FLAGS2_REASSIGN_MAC_EN))
 		mdev->mac_removed[priv->port] = 1;
 
@@ -1661,6 +1857,8 @@ int mlx4_en_init_netdev(struct mlx4_en_dev *mdev, int port,
 		dev->dcbnl_ops = &mlx4_en_dcbnl_ops;
 #endif
 
+	INIT_RADIX_TREE(&priv->mac_tree, GFP_KERNEL);
+
 	/* Query for default mac and max mtu */
 	priv->max_mtu = mdev->dev->caps.eth_mtu_cap[priv->port];
 
diff --git a/drivers/net/ethernet/mellanox/mlx4/main.c b/drivers/net/ethernet/mellanox/mlx4/main.c
index 12ddae6..2d7b937 100644
--- a/drivers/net/ethernet/mellanox/mlx4/main.c
+++ b/drivers/net/ethernet/mellanox/mlx4/main.c
@@ -1833,12 +1833,9 @@ static int mlx4_init_port_info(struct mlx4_dev *dev, int port)
 	info->dev = dev;
 	info->port = port;
 	if (!mlx4_is_slave(dev)) {
-		INIT_RADIX_TREE(&info->mac_tree, GFP_KERNEL);
 		mlx4_init_mac_table(dev, &info->mac_table);
 		mlx4_init_vlan_table(dev, &info->vlan_table);
-		info->base_qpn =
-			dev->caps.reserved_qps_base[MLX4_QP_REGION_ETH_ADDR] +
-			(port - 1) * (1 << log_num_mac);
+		info->base_qpn = mlx4_get_base_qpn(dev, port);
 	}
 
 	sprintf(info->dev_name, "mlx4_port%d", port);
diff --git a/drivers/net/ethernet/mellanox/mlx4/mlx4.h b/drivers/net/ethernet/mellanox/mlx4/mlx4.h
index 172daaa..ed4a695 100644
--- a/drivers/net/ethernet/mellanox/mlx4/mlx4.h
+++ b/drivers/net/ethernet/mellanox/mlx4/mlx4.h
@@ -653,11 +653,6 @@ struct mlx4_set_port_rqp_calc_context {
 	__be32 mcast;
 };
 
-struct mlx4_mac_entry {
-	u64 mac;
-	u64 reg_id;
-};
-
 struct mlx4_port_info {
 	struct mlx4_dev	       *dev;
 	int			port;
@@ -667,7 +662,6 @@ struct mlx4_port_info {
 	char			dev_mtu_name[16];
 	struct device_attribute port_mtu_attr;
 	struct mlx4_mac_table	mac_table;
-	struct radix_tree_root	mac_tree;
 	struct mlx4_vlan_table	vlan_table;
 	int			base_qpn;
 };
@@ -916,7 +910,6 @@ int __mlx4_qp_reserve_range(struct mlx4_dev *dev, int cnt, int align,
 void __mlx4_qp_release_range(struct mlx4_dev *dev, int base_qpn, int cnt);
 int __mlx4_register_mac(struct mlx4_dev *dev, u8 port, u64 mac);
 void __mlx4_unregister_mac(struct mlx4_dev *dev, u8 port, u64 mac);
-int __mlx4_replace_mac(struct mlx4_dev *dev, u8 port, int qpn, u64 new_mac);
 int __mlx4_write_mtt(struct mlx4_dev *dev, struct mlx4_mtt *mtt,
 		     int start_index, int npages, u64 *page_list);
 int __mlx4_counter_alloc(struct mlx4_dev *dev, u32 *idx);
diff --git a/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h b/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h
index 9d0105d..84ed3285 100644
--- a/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h
+++ b/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h
@@ -521,6 +521,7 @@ struct mlx4_en_priv {
 	bool wol;
 	struct device *ddev;
 	int base_tx_qpn;
+	struct radix_tree_root mac_tree;
 
 #ifdef CONFIG_MLX4_EN_DCB
 	struct ieee_ets ets;
@@ -540,6 +541,11 @@ enum mlx4_en_wol {
 	MLX4_EN_WOL_ENABLED = (1ULL << 62),
 };
 
+struct mlx4_mac_entry {
+	unsigned char mac[ETH_ALEN + 2];
+	u64 reg_id;
+};
+
 #define MLX4_EN_WOL_DO_MODIFY (1ULL << 63)
 
 void mlx4_en_update_loopback_state(struct net_device *dev,
diff --git a/drivers/net/ethernet/mellanox/mlx4/port.c b/drivers/net/ethernet/mellanox/mlx4/port.c
index 4c51b05..719ead1 100644
--- a/drivers/net/ethernet/mellanox/mlx4/port.c
+++ b/drivers/net/ethernet/mellanox/mlx4/port.c
@@ -74,87 +74,6 @@ void mlx4_init_vlan_table(struct mlx4_dev *dev, struct mlx4_vlan_table *table)
 	table->total = 0;
 }
 
-static int mlx4_uc_steer_add(struct mlx4_dev *dev, u8 port,
-			     u64 mac, int *qpn, u64 *reg_id)
-{
-	__be64 be_mac;
-	int err;
-
-	mac &= MLX4_MAC_MASK;
-	be_mac = cpu_to_be64(mac << 16);
-
-	switch (dev->caps.steering_mode) {
-	case MLX4_STEERING_MODE_B0: {
-		struct mlx4_qp qp;
-		u8 gid[16] = {0};
-
-		qp.qpn = *qpn;
-		memcpy(&gid[10], &be_mac, ETH_ALEN);
-		gid[5] = port;
-
-		err = mlx4_unicast_attach(dev, &qp, gid, 0, MLX4_PROT_ETH);
-		break;
-	}
-	case MLX4_STEERING_MODE_DEVICE_MANAGED: {
-		struct mlx4_spec_list spec_eth = { {NULL} };
-		__be64 mac_mask = cpu_to_be64(MLX4_MAC_MASK << 16);
-
-		struct mlx4_net_trans_rule rule = {
-			.queue_mode = MLX4_NET_TRANS_Q_FIFO,
-			.exclusive = 0,
-			.allow_loopback = 1,
-			.promisc_mode = MLX4_FS_PROMISC_NONE,
-			.priority = MLX4_DOMAIN_NIC,
-		};
-
-		rule.port = port;
-		rule.qpn = *qpn;
-		INIT_LIST_HEAD(&rule.list);
-
-		spec_eth.id = MLX4_NET_TRANS_RULE_ID_ETH;
-		memcpy(spec_eth.eth.dst_mac, &be_mac, ETH_ALEN);
-		memcpy(spec_eth.eth.dst_mac_msk, &mac_mask, ETH_ALEN);
-		list_add_tail(&spec_eth.list, &rule.list);
-
-		err = mlx4_flow_attach(dev, &rule, reg_id);
-		break;
-	}
-	default:
-		return -EINVAL;
-	}
-	if (err)
-		mlx4_warn(dev, "Failed Attaching Unicast\n");
-
-	return err;
-}
-
-static void mlx4_uc_steer_release(struct mlx4_dev *dev, u8 port,
-				  u64 mac, int qpn, u64 reg_id)
-{
-	switch (dev->caps.steering_mode) {
-	case MLX4_STEERING_MODE_B0: {
-		struct mlx4_qp qp;
-		u8 gid[16] = {0};
-		__be64 be_mac;
-
-		qp.qpn = qpn;
-		mac &= MLX4_MAC_MASK;
-		be_mac = cpu_to_be64(mac << 16);
-		memcpy(&gid[10], &be_mac, ETH_ALEN);
-		gid[5] = port;
-
-		mlx4_unicast_detach(dev, &qp, gid, MLX4_PROT_ETH);
-		break;
-	}
-	case MLX4_STEERING_MODE_DEVICE_MANAGED: {
-		mlx4_flow_detach(dev, reg_id);
-		break;
-	}
-	default:
-		mlx4_err(dev, "Invalid steering mode.\n");
-	}
-}
-
 static int validate_index(struct mlx4_dev *dev,
 			  struct mlx4_mac_table *table, int index)
 {
@@ -181,92 +100,6 @@ static int find_index(struct mlx4_dev *dev,
 	return -EINVAL;
 }
 
-int mlx4_get_eth_qp(struct mlx4_dev *dev, u8 port, u64 mac, int *qpn)
-{
-	struct mlx4_port_info *info = &mlx4_priv(dev)->port[port];
-	struct mlx4_mac_entry *entry;
-	int index = 0;
-	int err = 0;
-	u64 reg_id;
-
-	mlx4_dbg(dev, "Registering MAC: 0x%llx for adding\n",
-			(unsigned long long) mac);
-	index = mlx4_register_mac(dev, port, mac);
-	if (index < 0) {
-		err = index;
-		mlx4_err(dev, "Failed adding MAC: 0x%llx\n",
-			 (unsigned long long) mac);
-		return err;
-	}
-
-	if (dev->caps.steering_mode == MLX4_STEERING_MODE_A0) {
-		*qpn = info->base_qpn + index;
-		return 0;
-	}
-
-	err = mlx4_qp_reserve_range(dev, 1, 1, qpn);
-	mlx4_dbg(dev, "Reserved qp %d\n", *qpn);
-	if (err) {
-		mlx4_err(dev, "Failed to reserve qp for mac registration\n");
-		goto qp_err;
-	}
-
-	err = mlx4_uc_steer_add(dev, port, mac, qpn, &reg_id);
-	if (err)
-		goto steer_err;
-
-	entry = kmalloc(sizeof *entry, GFP_KERNEL);
-	if (!entry) {
-		err = -ENOMEM;
-		goto alloc_err;
-	}
-	entry->mac = mac;
-	entry->reg_id = reg_id;
-	err = radix_tree_insert(&info->mac_tree, *qpn, entry);
-	if (err)
-		goto insert_err;
-	return 0;
-
-insert_err:
-	kfree(entry);
-
-alloc_err:
-	mlx4_uc_steer_release(dev, port, mac, *qpn, reg_id);
-
-steer_err:
-	mlx4_qp_release_range(dev, *qpn, 1);
-
-qp_err:
-	mlx4_unregister_mac(dev, port, mac);
-	return err;
-}
-EXPORT_SYMBOL_GPL(mlx4_get_eth_qp);
-
-void mlx4_put_eth_qp(struct mlx4_dev *dev, u8 port, u64 mac, int qpn)
-{
-	struct mlx4_port_info *info = &mlx4_priv(dev)->port[port];
-	struct mlx4_mac_entry *entry;
-
-	mlx4_dbg(dev, "Registering MAC: 0x%llx for deleting\n",
-		 (unsigned long long) mac);
-	mlx4_unregister_mac(dev, port, mac);
-
-	if (dev->caps.steering_mode != MLX4_STEERING_MODE_A0) {
-		entry = radix_tree_lookup(&info->mac_tree, qpn);
-		if (entry) {
-			mlx4_dbg(dev, "Releasing qp: port %d, mac 0x%llx,"
-				 " qpn %d\n", port,
-				 (unsigned long long) mac, qpn);
-			mlx4_uc_steer_release(dev, port, entry->mac,
-					      qpn, entry->reg_id);
-			mlx4_qp_release_range(dev, qpn, 1);
-			radix_tree_delete(&info->mac_tree, qpn);
-			kfree(entry);
-		}
-	}
-}
-EXPORT_SYMBOL_GPL(mlx4_put_eth_qp);
-
 static int mlx4_set_port_mac_table(struct mlx4_dev *dev, u8 port,
 				   __be64 *entries)
 {
@@ -359,6 +192,12 @@ int mlx4_register_mac(struct mlx4_dev *dev, u8 port, u64 mac)
 }
 EXPORT_SYMBOL_GPL(mlx4_register_mac);
 
+int mlx4_get_base_qpn(struct mlx4_dev *dev, u8 port)
+{
+	return dev->caps.reserved_qps_base[MLX4_QP_REGION_ETH_ADDR] +
+			(port - 1) * (1 << dev->caps.log_num_macs);
+}
+EXPORT_SYMBOL_GPL(mlx4_get_base_qpn);
 
 void __mlx4_unregister_mac(struct mlx4_dev *dev, u8 port, u64 mac)
 {
@@ -397,29 +236,13 @@ void mlx4_unregister_mac(struct mlx4_dev *dev, u8 port, u64 mac)
 }
 EXPORT_SYMBOL_GPL(mlx4_unregister_mac);
 
-int mlx4_replace_mac(struct mlx4_dev *dev, u8 port, int qpn, u64 new_mac)
+int __mlx4_replace_mac(struct mlx4_dev *dev, u8 port, int qpn, u64 new_mac)
 {
 	struct mlx4_port_info *info = &mlx4_priv(dev)->port[port];
 	struct mlx4_mac_table *table = &info->mac_table;
-	struct mlx4_mac_entry *entry;
 	int index = qpn - info->base_qpn;
 	int err = 0;
 
-	if (dev->caps.steering_mode != MLX4_STEERING_MODE_A0) {
-		entry = radix_tree_lookup(&info->mac_tree, qpn);
-		if (!entry)
-			return -EINVAL;
-		mlx4_uc_steer_release(dev, port, entry->mac,
-				      qpn, entry->reg_id);
-		mlx4_unregister_mac(dev, port, entry->mac);
-		entry->mac = new_mac;
-		entry->reg_id = 0;
-		mlx4_register_mac(dev, port, new_mac);
-		err = mlx4_uc_steer_add(dev, port, entry->mac,
-					&qpn, &entry->reg_id);
-		return err;
-	}
-
 	/* CX1 doesn't support multi-functions */
 	mutex_lock(&table->mutex);
 
@@ -439,7 +262,7 @@ out:
 	mutex_unlock(&table->mutex);
 	return err;
 }
-EXPORT_SYMBOL_GPL(mlx4_replace_mac);
+EXPORT_SYMBOL_GPL(__mlx4_replace_mac);
 
 static int mlx4_set_port_vlan_table(struct mlx4_dev *dev, u8 port,
 				    __be32 *entries)
diff --git a/include/linux/mlx4/device.h b/include/linux/mlx4/device.h
index 1883e8e..6d48fce 100644
--- a/include/linux/mlx4/device.h
+++ b/include/linux/mlx4/device.h
@@ -956,9 +956,8 @@ int mlx4_SET_MCAST_FLTR(struct mlx4_dev *dev, u8 port, u64 mac, u64 clear, u8 mo
 
 int mlx4_register_mac(struct mlx4_dev *dev, u8 port, u64 mac);
 void mlx4_unregister_mac(struct mlx4_dev *dev, u8 port, u64 mac);
-int mlx4_replace_mac(struct mlx4_dev *dev, u8 port, int qpn, u64 new_mac);
-int mlx4_get_eth_qp(struct mlx4_dev *dev, u8 port, u64 mac, int *qpn);
-void mlx4_put_eth_qp(struct mlx4_dev *dev, u8 port, u64 mac, int qpn);
+int mlx4_get_base_qpn(struct mlx4_dev *dev, u8 port);
+int __mlx4_replace_mac(struct mlx4_dev *dev, u8 port, int qpn, u64 new_mac);
 void mlx4_set_stats_bitmap(struct mlx4_dev *dev, u64 *stats_bitmap);
 int mlx4_SET_PORT_general(struct mlx4_dev *dev, u8 port, int mtu,
 			  u8 pptx, u8 pfctx, u8 pprx, u8 pfcrx);
-- 
1.7.8.2

^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH net-next v2 5/9] net/mlx4_en: Re-arrange ndo_set_rx_mode related code
  2013-02-07 12:25 [PATCH net-next v2 0/9] net/mlx4_en: Add support for unicast MAC filtering and FDB operations Amir Vadai
                   ` (3 preceding siblings ...)
  2013-02-07 12:25 ` [PATCH net-next v2 4/9] net/mlx4: Move Ethernet related functionality from mlx4_core to mlx4_en Amir Vadai
@ 2013-02-07 12:25 ` Amir Vadai
  2013-02-07 12:25 ` [PATCH net-next v2 6/9] net/mlx4_en: Save previous MAC address of the port so we can replace it later Amir Vadai
                   ` (4 subsequent siblings)
  9 siblings, 0 replies; 11+ messages in thread
From: Amir Vadai @ 2013-02-07 12:25 UTC (permalink / raw)
  To: David S. Miller; +Cc: Amir Vadai, Or Gerlitz, Yan Burman, netdev

From: Yan Burman <yanb@mellanox.com>

Currently, mlx4_en_do_set_multicast serves as the ndo_set_rx_mode entry for mlx4_en,
doing all related work. Split it to few calls, one per required functionality
(e.g multicast, promiscuous, etc) and rename some structures and calls
to use rx_mode notation instead of multicast.

Signed-off-by: Yan Burman <yanb@mellanox.com>
Signed-off-by: Amir Vadai <amirv@mellanox.com>
---
 drivers/net/ethernet/mellanox/mlx4/en_netdev.c |  271 +++++++++++++-----------
 drivers/net/ethernet/mellanox/mlx4/mlx4_en.h   |    2 +-
 2 files changed, 145 insertions(+), 128 deletions(-)

diff --git a/drivers/net/ethernet/mellanox/mlx4/en_netdev.c b/drivers/net/ethernet/mellanox/mlx4/en_netdev.c
index 63a1ef3..80067d5 100644
--- a/drivers/net/ethernet/mellanox/mlx4/en_netdev.c
+++ b/drivers/net/ethernet/mellanox/mlx4/en_netdev.c
@@ -747,165 +747,142 @@ static void update_mclist_flags(struct mlx4_en_priv *priv,
 	}
 }
 
-static void mlx4_en_set_multicast(struct net_device *dev)
+static void mlx4_en_set_rx_mode(struct net_device *dev)
 {
 	struct mlx4_en_priv *priv = netdev_priv(dev);
 
 	if (!priv->port_up)
 		return;
 
-	queue_work(priv->mdev->workqueue, &priv->mcast_task);
+	queue_work(priv->mdev->workqueue, &priv->rx_mode_task);
 }
 
-static void mlx4_en_do_set_multicast(struct work_struct *work)
+static void mlx4_en_set_promisc_mode(struct mlx4_en_priv *priv,
+				     struct mlx4_en_dev *mdev)
 {
-	struct mlx4_en_priv *priv = container_of(work, struct mlx4_en_priv,
-						 mcast_task);
-	struct mlx4_en_dev *mdev = priv->mdev;
-	struct net_device *dev = priv->dev;
-	struct mlx4_en_mc_list *mclist, *tmp;
-	u64 mcast_addr = 0;
-	u8 mc_list[16] = {0};
 	int err = 0;
 
-	mutex_lock(&mdev->state_lock);
-	if (!mdev->device_up) {
-		en_dbg(HW, priv, "Card is not up, ignoring multicast change.\n");
-		goto out;
-	}
-	if (!priv->port_up) {
-		en_dbg(HW, priv, "Port is down, ignoring  multicast change.\n");
-		goto out;
-	}
-
-	if (!netif_carrier_ok(dev)) {
-		if (!mlx4_en_QUERY_PORT(mdev, priv->port)) {
-			if (priv->port_state.link_state) {
-				priv->last_link_state = MLX4_DEV_EVENT_PORT_UP;
-				netif_carrier_on(dev);
-				en_dbg(LINK, priv, "Link Up\n");
-			}
-		}
-	}
-
-	/*
-	 * Promsicuous mode: disable all filters
-	 */
-
-	if (dev->flags & IFF_PROMISC) {
-		if (!(priv->flags & MLX4_EN_FLAG_PROMISC)) {
-			if (netif_msg_rx_status(priv))
-				en_warn(priv, "Entering promiscuous mode\n");
-			priv->flags |= MLX4_EN_FLAG_PROMISC;
-
-			/* Enable promiscouos mode */
-			switch (mdev->dev->caps.steering_mode) {
-			case MLX4_STEERING_MODE_DEVICE_MANAGED:
-				err = mlx4_flow_steer_promisc_add(mdev->dev,
-								  priv->port,
-								  priv->base_qpn,
-								  MLX4_FS_PROMISC_UPLINK);
-				if (err)
-					en_err(priv, "Failed enabling promiscuous mode\n");
-				priv->flags |= MLX4_EN_FLAG_MC_PROMISC;
-				break;
-
-			case MLX4_STEERING_MODE_B0:
-				err = mlx4_unicast_promisc_add(mdev->dev,
-							       priv->base_qpn,
-							       priv->port);
-				if (err)
-					en_err(priv, "Failed enabling unicast promiscuous mode\n");
-
-				/* Add the default qp number as multicast
-				 * promisc
-				 */
-				if (!(priv->flags & MLX4_EN_FLAG_MC_PROMISC)) {
-					err = mlx4_multicast_promisc_add(mdev->dev,
-									 priv->base_qpn,
-									 priv->port);
-					if (err)
-						en_err(priv, "Failed enabling multicast promiscuous mode\n");
-					priv->flags |= MLX4_EN_FLAG_MC_PROMISC;
-				}
-				break;
-
-			case MLX4_STEERING_MODE_A0:
-				err = mlx4_SET_PORT_qpn_calc(mdev->dev,
-							     priv->port,
-							     priv->base_qpn,
-							     1);
-				if (err)
-					en_err(priv, "Failed enabling promiscuous mode\n");
-				break;
-			}
-
-			/* Disable port multicast filter (unconditionally) */
-			err = mlx4_SET_MCAST_FLTR(mdev->dev, priv->port, 0,
-						  0, MLX4_MCAST_DISABLE);
-			if (err)
-				en_err(priv, "Failed disabling multicast filter\n");
-
-			/* Disable port VLAN filter */
-			err = mlx4_SET_VLAN_FLTR(mdev->dev, priv);
-			if (err)
-				en_err(priv, "Failed disabling VLAN filter\n");
-		}
-		goto out;
-	}
-
-	/*
-	 * Not in promiscuous mode
-	 */
-
-	if (priv->flags & MLX4_EN_FLAG_PROMISC) {
+	if (!(priv->flags & MLX4_EN_FLAG_PROMISC)) {
 		if (netif_msg_rx_status(priv))
-			en_warn(priv, "Leaving promiscuous mode\n");
-		priv->flags &= ~MLX4_EN_FLAG_PROMISC;
+			en_warn(priv, "Entering promiscuous mode\n");
+		priv->flags |= MLX4_EN_FLAG_PROMISC;
 
-		/* Disable promiscouos mode */
+		/* Enable promiscouos mode */
 		switch (mdev->dev->caps.steering_mode) {
 		case MLX4_STEERING_MODE_DEVICE_MANAGED:
-			err = mlx4_flow_steer_promisc_remove(mdev->dev,
-							     priv->port,
-							     MLX4_FS_PROMISC_UPLINK);
+			err = mlx4_flow_steer_promisc_add(mdev->dev,
+							  priv->port,
+							  priv->base_qpn,
+							  MLX4_FS_PROMISC_UPLINK);
 			if (err)
-				en_err(priv, "Failed disabling promiscuous mode\n");
-			priv->flags &= ~MLX4_EN_FLAG_MC_PROMISC;
+				en_err(priv, "Failed enabling promiscuous mode\n");
+			priv->flags |= MLX4_EN_FLAG_MC_PROMISC;
 			break;
 
 		case MLX4_STEERING_MODE_B0:
-			err = mlx4_unicast_promisc_remove(mdev->dev,
-							  priv->base_qpn,
-							  priv->port);
+			err = mlx4_unicast_promisc_add(mdev->dev,
+						       priv->base_qpn,
+						       priv->port);
 			if (err)
-				en_err(priv, "Failed disabling unicast promiscuous mode\n");
-			/* Disable Multicast promisc */
-			if (priv->flags & MLX4_EN_FLAG_MC_PROMISC) {
-				err = mlx4_multicast_promisc_remove(mdev->dev,
-								    priv->base_qpn,
-								    priv->port);
+				en_err(priv, "Failed enabling unicast promiscuous mode\n");
+
+			/* Add the default qp number as multicast
+			 * promisc
+			 */
+			if (!(priv->flags & MLX4_EN_FLAG_MC_PROMISC)) {
+				err = mlx4_multicast_promisc_add(mdev->dev,
+								 priv->base_qpn,
+								 priv->port);
 				if (err)
-					en_err(priv, "Failed disabling multicast promiscuous mode\n");
-				priv->flags &= ~MLX4_EN_FLAG_MC_PROMISC;
+					en_err(priv, "Failed enabling multicast promiscuous mode\n");
+				priv->flags |= MLX4_EN_FLAG_MC_PROMISC;
 			}
 			break;
 
 		case MLX4_STEERING_MODE_A0:
 			err = mlx4_SET_PORT_qpn_calc(mdev->dev,
 						     priv->port,
-						     priv->base_qpn, 0);
+						     priv->base_qpn,
+						     1);
 			if (err)
-				en_err(priv, "Failed disabling promiscuous mode\n");
+				en_err(priv, "Failed enabling promiscuous mode\n");
 			break;
 		}
 
-		/* Enable port VLAN filter */
+		/* Disable port multicast filter (unconditionally) */
+		err = mlx4_SET_MCAST_FLTR(mdev->dev, priv->port, 0,
+					  0, MLX4_MCAST_DISABLE);
+		if (err)
+			en_err(priv, "Failed disabling multicast filter\n");
+
+		/* Disable port VLAN filter */
 		err = mlx4_SET_VLAN_FLTR(mdev->dev, priv);
 		if (err)
-			en_err(priv, "Failed enabling VLAN filter\n");
+			en_err(priv, "Failed disabling VLAN filter\n");
+	}
+}
+
+static void mlx4_en_clear_promisc_mode(struct mlx4_en_priv *priv,
+				       struct mlx4_en_dev *mdev)
+{
+	int err = 0;
+
+	if (netif_msg_rx_status(priv))
+		en_warn(priv, "Leaving promiscuous mode\n");
+	priv->flags &= ~MLX4_EN_FLAG_PROMISC;
+
+	/* Disable promiscouos mode */
+	switch (mdev->dev->caps.steering_mode) {
+	case MLX4_STEERING_MODE_DEVICE_MANAGED:
+		err = mlx4_flow_steer_promisc_remove(mdev->dev,
+						     priv->port,
+						     MLX4_FS_PROMISC_UPLINK);
+		if (err)
+			en_err(priv, "Failed disabling promiscuous mode\n");
+		priv->flags &= ~MLX4_EN_FLAG_MC_PROMISC;
+		break;
+
+	case MLX4_STEERING_MODE_B0:
+		err = mlx4_unicast_promisc_remove(mdev->dev,
+						  priv->base_qpn,
+						  priv->port);
+		if (err)
+			en_err(priv, "Failed disabling unicast promiscuous mode\n");
+		/* Disable Multicast promisc */
+		if (priv->flags & MLX4_EN_FLAG_MC_PROMISC) {
+			err = mlx4_multicast_promisc_remove(mdev->dev,
+							    priv->base_qpn,
+							    priv->port);
+			if (err)
+				en_err(priv, "Failed disabling multicast promiscuous mode\n");
+			priv->flags &= ~MLX4_EN_FLAG_MC_PROMISC;
+		}
+		break;
+
+	case MLX4_STEERING_MODE_A0:
+		err = mlx4_SET_PORT_qpn_calc(mdev->dev,
+					     priv->port,
+					     priv->base_qpn, 0);
+		if (err)
+			en_err(priv, "Failed disabling promiscuous mode\n");
+		break;
 	}
 
+	/* Enable port VLAN filter */
+	err = mlx4_SET_VLAN_FLTR(mdev->dev, priv);
+	if (err)
+		en_err(priv, "Failed enabling VLAN filter\n");
+}
+
+static void mlx4_en_do_multicast(struct mlx4_en_priv *priv,
+				 struct net_device *dev,
+				 struct mlx4_en_dev *mdev)
+{
+	struct mlx4_en_mc_list *mclist, *tmp;
+	u64 mcast_addr = 0;
+	u8 mc_list[16] = {0};
+	int err = 0;
+
 	/* Enable/disable the multicast filter according to IFF_ALLMULTI */
 	if (dev->flags & IFF_ALLMULTI) {
 		err = mlx4_SET_MCAST_FLTR(mdev->dev, priv->port, 0,
@@ -1018,6 +995,46 @@ static void mlx4_en_do_set_multicast(struct work_struct *work)
 			}
 		}
 	}
+}
+
+static void mlx4_en_do_set_rx_mode(struct work_struct *work)
+{
+	struct mlx4_en_priv *priv = container_of(work, struct mlx4_en_priv,
+						 rx_mode_task);
+	struct mlx4_en_dev *mdev = priv->mdev;
+	struct net_device *dev = priv->dev;
+
+	mutex_lock(&mdev->state_lock);
+	if (!mdev->device_up) {
+		en_dbg(HW, priv, "Card is not up, ignoring rx mode change.\n");
+		goto out;
+	}
+	if (!priv->port_up) {
+		en_dbg(HW, priv, "Port is down, ignoring rx mode change.\n");
+		goto out;
+	}
+
+	if (!netif_carrier_ok(dev)) {
+		if (!mlx4_en_QUERY_PORT(mdev, priv->port)) {
+			if (priv->port_state.link_state) {
+				priv->last_link_state = MLX4_DEV_EVENT_PORT_UP;
+				netif_carrier_on(dev);
+				en_dbg(LINK, priv, "Link Up\n");
+			}
+		}
+	}
+
+	/* Promsicuous mode: disable all filters */
+	if (dev->flags & IFF_PROMISC) {
+		mlx4_en_set_promisc_mode(priv, mdev);
+		goto out;
+	}
+
+	/* Not in promiscuous mode */
+	if (priv->flags & MLX4_EN_FLAG_PROMISC)
+		mlx4_en_clear_promisc_mode(priv, mdev);
+
+	mlx4_en_do_multicast(priv, dev, mdev);
 out:
 	mutex_unlock(&mdev->state_lock);
 }
@@ -1374,7 +1391,7 @@ int mlx4_en_start_port(struct net_device *dev)
 	priv->flags &= ~(MLX4_EN_FLAG_PROMISC | MLX4_EN_FLAG_MC_PROMISC);
 
 	/* Schedule multicast task to populate multicast list */
-	queue_work(mdev->workqueue, &priv->mcast_task);
+	queue_work(mdev->workqueue, &priv->rx_mode_task);
 
 	mlx4_set_stats_bitmap(mdev->dev, &priv->stats_bitmap);
 
@@ -1777,7 +1794,7 @@ static const struct net_device_ops mlx4_netdev_ops = {
 	.ndo_start_xmit		= mlx4_en_xmit,
 	.ndo_select_queue	= mlx4_en_select_queue,
 	.ndo_get_stats		= mlx4_en_get_stats,
-	.ndo_set_rx_mode	= mlx4_en_set_multicast,
+	.ndo_set_rx_mode	= mlx4_en_set_rx_mode,
 	.ndo_set_mac_address	= mlx4_en_set_mac,
 	.ndo_validate_addr	= eth_validate_addr,
 	.ndo_change_mtu		= mlx4_en_change_mtu,
@@ -1847,7 +1864,7 @@ int mlx4_en_init_netdev(struct mlx4_en_dev *mdev, int port,
 	priv->mac_index = -1;
 	priv->msg_enable = MLX4_EN_MSG_LEVEL;
 	spin_lock_init(&priv->stats_lock);
-	INIT_WORK(&priv->mcast_task, mlx4_en_do_set_multicast);
+	INIT_WORK(&priv->rx_mode_task, mlx4_en_do_set_rx_mode);
 	INIT_WORK(&priv->mac_task, mlx4_en_do_set_mac);
 	INIT_WORK(&priv->watchdog_task, mlx4_en_restart);
 	INIT_WORK(&priv->linkstate_task, mlx4_en_linkstate);
diff --git a/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h b/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h
index 84ed3285..47c9876 100644
--- a/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h
+++ b/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h
@@ -504,7 +504,7 @@ struct mlx4_en_priv {
 	struct mlx4_en_cq *tx_cq;
 	struct mlx4_en_cq rx_cq[MAX_RX_RINGS];
 	struct mlx4_qp drop_qp;
-	struct work_struct mcast_task;
+	struct work_struct rx_mode_task;
 	struct work_struct mac_task;
 	struct work_struct watchdog_task;
 	struct work_struct linkstate_task;
-- 
1.7.8.2

^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH net-next v2 6/9] net/mlx4_en: Save previous MAC address of the port so we can replace it later
  2013-02-07 12:25 [PATCH net-next v2 0/9] net/mlx4_en: Add support for unicast MAC filtering and FDB operations Amir Vadai
                   ` (4 preceding siblings ...)
  2013-02-07 12:25 ` [PATCH net-next v2 5/9] net/mlx4_en: Re-arrange ndo_set_rx_mode related code Amir Vadai
@ 2013-02-07 12:25 ` Amir Vadai
  2013-02-07 12:25 ` [PATCH net-next v2 7/9] net/mlx4_en: Manage hash of MAC addresses per port Amir Vadai
                   ` (3 subsequent siblings)
  9 siblings, 0 replies; 11+ messages in thread
From: Amir Vadai @ 2013-02-07 12:25 UTC (permalink / raw)
  To: David S. Miller; +Cc: Amir Vadai, Or Gerlitz, Yan Burman, netdev

From: Yan Burman <yanb@mellanox.com>

In preparation to having more than one unicast MAC per port, we need to keep track
of the previous MAC address in the flow of ndo_set_mac_address,
so that mlx4_en_replace_mac will know what to replace.

Signed-off-by: Yan Burman <yanb@mellanox.com>
Signed-off-by: Amir Vadai <amirv@mellanox.com>
---
 drivers/net/ethernet/mellanox/mlx4/en_netdev.c |    4 ++--
 1 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/net/ethernet/mellanox/mlx4/en_netdev.c b/drivers/net/ethernet/mellanox/mlx4/en_netdev.c
index 80067d5..72a3fe5 100644
--- a/drivers/net/ethernet/mellanox/mlx4/en_netdev.c
+++ b/drivers/net/ethernet/mellanox/mlx4/en_netdev.c
@@ -591,7 +591,7 @@ static void mlx4_en_put_qp(struct mlx4_en_priv *priv)
 }
 
 static int mlx4_en_replace_mac(struct mlx4_en_priv *priv, int qpn,
-			       unsigned char *new_mac)
+			       unsigned char *new_mac, unsigned char *prev_mac)
 {
 	struct mlx4_en_dev *mdev = priv->mdev;
 	struct mlx4_dev *dev = mdev->dev;
@@ -657,7 +657,7 @@ static void mlx4_en_do_set_mac(struct work_struct *work)
 	if (priv->port_up) {
 		/* Remove old MAC and insert the new one */
 		err = mlx4_en_replace_mac(priv, priv->base_qpn,
-					  priv->dev->dev_addr);
+					  priv->dev->dev_addr, priv->prev_mac);
 		if (err)
 			en_err(priv, "Failed changing HW MAC address\n");
 		memcpy(priv->prev_mac, priv->dev->dev_addr,
-- 
1.7.8.2

^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH net-next v2 7/9] net/mlx4_en: Manage hash of MAC addresses per port
  2013-02-07 12:25 [PATCH net-next v2 0/9] net/mlx4_en: Add support for unicast MAC filtering and FDB operations Amir Vadai
                   ` (5 preceding siblings ...)
  2013-02-07 12:25 ` [PATCH net-next v2 6/9] net/mlx4_en: Save previous MAC address of the port so we can replace it later Amir Vadai
@ 2013-02-07 12:25 ` Amir Vadai
  2013-02-07 12:25 ` [PATCH net-next v2 8/9] net/mlx4_en: Add unicast MAC filtering Amir Vadai
                   ` (2 subsequent siblings)
  9 siblings, 0 replies; 11+ messages in thread
From: Amir Vadai @ 2013-02-07 12:25 UTC (permalink / raw)
  To: David S. Miller; +Cc: Amir Vadai, Or Gerlitz, Yan Burman, netdev

From: Yan Burman <yanb@mellanox.com>

As a preparation step for supporting multiple unicast addresses, store MAC addresses in hash table.
Remove the radix tree for MAC addresses per QP, as it's not in use.

Signed-off-by: Yan Burman <yanb@mellanox.com>
Signed-off-by: Amir Vadai <amirv@mellanox.com>
---
 drivers/net/ethernet/mellanox/mlx4/en_netdev.c |   87 +++++++++++++++---------
 drivers/net/ethernet/mellanox/mlx4/en_rx.c     |   23 +++++-
 drivers/net/ethernet/mellanox/mlx4/mlx4_en.h   |    7 ++-
 3 files changed, 79 insertions(+), 38 deletions(-)

diff --git a/drivers/net/ethernet/mellanox/mlx4/en_netdev.c b/drivers/net/ethernet/mellanox/mlx4/en_netdev.c
index 72a3fe5..8eb24ee 100644
--- a/drivers/net/ethernet/mellanox/mlx4/en_netdev.c
+++ b/drivers/net/ethernet/mellanox/mlx4/en_netdev.c
@@ -545,13 +545,10 @@ static int mlx4_en_get_qp(struct mlx4_en_priv *priv)
 	memcpy(entry->mac, priv->dev->dev_addr, sizeof(entry->mac));
 	entry->reg_id = reg_id;
 
-	err = radix_tree_insert(&priv->mac_tree, *qpn, entry);
-	if (err)
-		goto insert_err;
-	return 0;
+	hlist_add_head_rcu(&entry->hlist,
+			   &priv->mac_hash[entry->mac[MLX4_EN_MAC_HASH_IDX]]);
 
-insert_err:
-	kfree(entry);
+	return 0;
 
 alloc_err:
 	mlx4_en_uc_steer_release(priv, priv->dev->dev_addr, *qpn, reg_id);
@@ -568,7 +565,6 @@ static void mlx4_en_put_qp(struct mlx4_en_priv *priv)
 {
 	struct mlx4_en_dev *mdev = priv->mdev;
 	struct mlx4_dev *dev = mdev->dev;
-	struct mlx4_mac_entry *entry;
 	int qpn = priv->base_qpn;
 	u64 mac = mlx4_en_mac_to_u64(priv->dev->dev_addr);
 
@@ -577,15 +573,26 @@ static void mlx4_en_put_qp(struct mlx4_en_priv *priv)
 	mlx4_unregister_mac(dev, priv->port, mac);
 
 	if (dev->caps.steering_mode != MLX4_STEERING_MODE_A0) {
-		entry = radix_tree_lookup(&priv->mac_tree, qpn);
-		if (entry) {
-			en_dbg(DRV, priv, "Releasing qp: port %d, MAC %pM, qpn %d\n",
-			       priv->port, entry->mac, qpn);
-			mlx4_en_uc_steer_release(priv, entry->mac,
-						 qpn, entry->reg_id);
-			mlx4_qp_release_range(dev, qpn, 1);
-			radix_tree_delete(&priv->mac_tree, qpn);
-			kfree(entry);
+		struct mlx4_mac_entry *entry;
+		struct hlist_node *n, *tmp;
+		struct hlist_head *bucket;
+		unsigned int mac_hash;
+
+		mac_hash = priv->dev->dev_addr[MLX4_EN_MAC_HASH_IDX];
+		bucket = &priv->mac_hash[mac_hash];
+		hlist_for_each_entry_safe(entry, n, tmp, bucket, hlist) {
+			if (ether_addr_equal_64bits(entry->mac,
+						    priv->dev->dev_addr)) {
+				en_dbg(DRV, priv, "Releasing qp: port %d, MAC %pM, qpn %d\n",
+				       priv->port, priv->dev->dev_addr, qpn);
+				mlx4_en_uc_steer_release(priv, entry->mac,
+							 qpn, entry->reg_id);
+				mlx4_qp_release_range(dev, qpn, 1);
+
+				hlist_del_rcu(&entry->hlist);
+				kfree_rcu(entry, rcu);
+				break;
+			}
 		}
 	}
 }
@@ -595,26 +602,38 @@ static int mlx4_en_replace_mac(struct mlx4_en_priv *priv, int qpn,
 {
 	struct mlx4_en_dev *mdev = priv->mdev;
 	struct mlx4_dev *dev = mdev->dev;
-	struct mlx4_mac_entry *entry;
 	int err = 0;
 	u64 new_mac_u64 = mlx4_en_mac_to_u64(new_mac);
 
 	if (dev->caps.steering_mode != MLX4_STEERING_MODE_A0) {
-		u64 prev_mac_u64;
-
-		entry = radix_tree_lookup(&priv->mac_tree, qpn);
-		if (!entry)
-			return -EINVAL;
-		prev_mac_u64 = mlx4_en_mac_to_u64(entry->mac);
-		mlx4_en_uc_steer_release(priv, entry->mac,
-					 qpn, entry->reg_id);
-		mlx4_unregister_mac(dev, priv->port, prev_mac_u64);
-		memcpy(entry->mac, new_mac, ETH_ALEN);
-		entry->reg_id = 0;
-		mlx4_register_mac(dev, priv->port, new_mac_u64);
-		err = mlx4_en_uc_steer_add(priv, new_mac,
-					   &qpn, &entry->reg_id);
-		return err;
+		struct hlist_head *bucket;
+		unsigned int mac_hash;
+		struct mlx4_mac_entry *entry;
+		struct hlist_node *n, *tmp;
+		u64 prev_mac_u64 = mlx4_en_mac_to_u64(prev_mac);
+
+		bucket = &priv->mac_hash[prev_mac[MLX4_EN_MAC_HASH_IDX]];
+		hlist_for_each_entry_safe(entry, n, tmp, bucket, hlist) {
+			if (ether_addr_equal_64bits(entry->mac, prev_mac)) {
+				mlx4_en_uc_steer_release(priv, entry->mac,
+							 qpn, entry->reg_id);
+				mlx4_unregister_mac(dev, priv->port,
+						    prev_mac_u64);
+				hlist_del_rcu(&entry->hlist);
+				synchronize_rcu();
+				memcpy(entry->mac, new_mac, ETH_ALEN);
+				entry->reg_id = 0;
+				mac_hash = new_mac[MLX4_EN_MAC_HASH_IDX];
+				hlist_add_head_rcu(&entry->hlist,
+						   &priv->mac_hash[mac_hash]);
+				mlx4_register_mac(dev, priv->port, new_mac_u64);
+				err = mlx4_en_uc_steer_add(priv, new_mac,
+							   &qpn,
+							   &entry->reg_id);
+				return err;
+			}
+		}
+		return -EINVAL;
 	}
 
 	return __mlx4_replace_mac(dev, priv->port, qpn, new_mac_u64);
@@ -1816,6 +1835,7 @@ int mlx4_en_init_netdev(struct mlx4_en_dev *mdev, int port,
 {
 	struct net_device *dev;
 	struct mlx4_en_priv *priv;
+	int i;
 	int err;
 
 	dev = alloc_etherdev_mqs(sizeof(struct mlx4_en_priv),
@@ -1874,7 +1894,8 @@ int mlx4_en_init_netdev(struct mlx4_en_dev *mdev, int port,
 		dev->dcbnl_ops = &mlx4_en_dcbnl_ops;
 #endif
 
-	INIT_RADIX_TREE(&priv->mac_tree, GFP_KERNEL);
+	for (i = 0; i < MLX4_EN_MAC_HASH_SIZE; ++i)
+		INIT_HLIST_HEAD(&priv->mac_hash[i]);
 
 	/* Query for default mac and max mtu */
 	priv->max_mtu = mdev->dev->caps.eth_mtu_cap[priv->port];
diff --git a/drivers/net/ethernet/mellanox/mlx4/en_rx.c b/drivers/net/ethernet/mellanox/mlx4/en_rx.c
index 2e7f5bb..91bb8e1 100644
--- a/drivers/net/ethernet/mellanox/mlx4/en_rx.c
+++ b/drivers/net/ethernet/mellanox/mlx4/en_rx.c
@@ -615,10 +615,25 @@ int mlx4_en_process_rx_cq(struct net_device *dev, struct mlx4_en_cq *cq, int bud
 			ethh = (struct ethhdr *)(page_address(frags[0].page) +
 						 frags[0].offset);
 
-			/* Drop the packet, since HW loopback-ed it */
-			if (ether_addr_equal_64bits(dev->dev_addr,
-						    ethh->h_source))
-				goto next;
+			if (is_multicast_ether_addr(ethh->h_dest)) {
+				struct mlx4_mac_entry *entry;
+				struct hlist_node *n;
+				struct hlist_head *bucket;
+				unsigned int mac_hash;
+
+				/* Drop the packet, since HW loopback-ed it */
+				mac_hash = ethh->h_source[MLX4_EN_MAC_HASH_IDX];
+				bucket = &priv->mac_hash[mac_hash];
+				rcu_read_lock();
+				hlist_for_each_entry_rcu(entry, n, bucket, hlist) {
+					if (ether_addr_equal_64bits(entry->mac,
+								    ethh->h_source)) {
+						rcu_read_unlock();
+						goto next;
+					}
+				}
+				rcu_read_unlock();
+			}
 		}
 
 		/*
diff --git a/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h b/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h
index 47c9876..0ff99e0 100644
--- a/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h
+++ b/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h
@@ -442,6 +442,9 @@ enum {
 	MLX4_EN_FLAG_RX_FILTER_NEEDED	= (1 << 3)
 };
 
+#define MLX4_EN_MAC_HASH_SIZE (1 << BITS_PER_BYTE)
+#define MLX4_EN_MAC_HASH_IDX 5
+
 struct mlx4_en_priv {
 	struct mlx4_en_dev *mdev;
 	struct mlx4_en_port_profile *prof;
@@ -521,7 +524,7 @@ struct mlx4_en_priv {
 	bool wol;
 	struct device *ddev;
 	int base_tx_qpn;
-	struct radix_tree_root mac_tree;
+	struct hlist_head mac_hash[MLX4_EN_MAC_HASH_SIZE];
 
 #ifdef CONFIG_MLX4_EN_DCB
 	struct ieee_ets ets;
@@ -542,8 +545,10 @@ enum mlx4_en_wol {
 };
 
 struct mlx4_mac_entry {
+	struct hlist_node hlist;
 	unsigned char mac[ETH_ALEN + 2];
 	u64 reg_id;
+	struct rcu_head rcu;
 };
 
 #define MLX4_EN_WOL_DO_MODIFY (1ULL << 63)
-- 
1.7.8.2

^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH net-next v2 8/9] net/mlx4_en: Add unicast MAC filtering
  2013-02-07 12:25 [PATCH net-next v2 0/9] net/mlx4_en: Add support for unicast MAC filtering and FDB operations Amir Vadai
                   ` (6 preceding siblings ...)
  2013-02-07 12:25 ` [PATCH net-next v2 7/9] net/mlx4_en: Manage hash of MAC addresses per port Amir Vadai
@ 2013-02-07 12:25 ` Amir Vadai
  2013-02-07 12:25 ` [PATCH net-next v2 9/9] net/mlx4_en: Implement ndo fdb functionality Amir Vadai
  2013-02-08  4:27 ` [PATCH net-next v2 0/9] net/mlx4_en: Add support for unicast MAC filtering and FDB operations David Miller
  9 siblings, 0 replies; 11+ messages in thread
From: Amir Vadai @ 2013-02-07 12:25 UTC (permalink / raw)
  To: David S. Miller; +Cc: Amir Vadai, Or Gerlitz, Yan Burman, netdev

From: Yan Burman <yanb@mellanox.com>

Implement and advertise unicast MAC filtering, such that setting macvlan
instance over mlx4_en interfaces will not require the networking core
to put mlx4_en devices in promiscuous mode.

If for some reason adding a unicast address filter fails e.g as of missing space in
the HW mac table, the device forces itself into promiscuous mode (and out of this
forced state when enough space is available).

Signed-off-by: Yan Burman <yanb@mellanox.com>
Signed-off-by: Amir Vadai <amirv@mellanox.com>
---
 drivers/net/ethernet/mellanox/mlx4/en_netdev.c |  129 +++++++++++++++++++++++-
 drivers/net/ethernet/mellanox/mlx4/mlx4_en.h   |    3 +-
 2 files changed, 130 insertions(+), 2 deletions(-)

diff --git a/drivers/net/ethernet/mellanox/mlx4/en_netdev.c b/drivers/net/ethernet/mellanox/mlx4/en_netdev.c
index 8eb24ee..2c19dab 100644
--- a/drivers/net/ethernet/mellanox/mlx4/en_netdev.c
+++ b/drivers/net/ethernet/mellanox/mlx4/en_netdev.c
@@ -1016,6 +1016,126 @@ static void mlx4_en_do_multicast(struct mlx4_en_priv *priv,
 	}
 }
 
+static void mlx4_en_do_uc_filter(struct mlx4_en_priv *priv,
+				 struct net_device *dev,
+				 struct mlx4_en_dev *mdev)
+{
+	struct netdev_hw_addr *ha;
+	struct mlx4_mac_entry *entry;
+	struct hlist_node *n, *tmp;
+	bool found;
+	u64 mac;
+	int err = 0;
+	struct hlist_head *bucket;
+	unsigned int i;
+	int removed = 0;
+	u32 prev_flags;
+
+	/* Note that we do not need to protect our mac_hash traversal with rcu,
+	 * since all modification code is protected by mdev->state_lock
+	 */
+
+	/* find what to remove */
+	for (i = 0; i < MLX4_EN_MAC_HASH_SIZE; ++i) {
+		bucket = &priv->mac_hash[i];
+		hlist_for_each_entry_safe(entry, n, tmp, bucket, hlist) {
+			found = false;
+			netdev_for_each_uc_addr(ha, dev) {
+				if (ether_addr_equal_64bits(entry->mac,
+							    ha->addr)) {
+					found = true;
+					break;
+				}
+			}
+
+			/* MAC address of the port is not in uc list */
+			if (ether_addr_equal_64bits(entry->mac, dev->dev_addr))
+				found = true;
+
+			if (!found) {
+				mac = mlx4_en_mac_to_u64(entry->mac);
+				mlx4_en_uc_steer_release(priv, entry->mac,
+							 priv->base_qpn,
+							 entry->reg_id);
+				mlx4_unregister_mac(mdev->dev, priv->port, mac);
+
+				hlist_del_rcu(&entry->hlist);
+				kfree_rcu(entry, rcu);
+				en_dbg(DRV, priv, "Removed MAC %pM on port:%d\n",
+				       entry->mac, priv->port);
+				++removed;
+			}
+		}
+	}
+
+	/* if we didn't remove anything, there is no use in trying to add
+	 * again once we are in a forced promisc mode state
+	 */
+	if ((priv->flags & MLX4_EN_FLAG_FORCE_PROMISC) && 0 == removed)
+		return;
+
+	prev_flags = priv->flags;
+	priv->flags &= ~MLX4_EN_FLAG_FORCE_PROMISC;
+
+	/* find what to add */
+	netdev_for_each_uc_addr(ha, dev) {
+		found = false;
+		bucket = &priv->mac_hash[ha->addr[MLX4_EN_MAC_HASH_IDX]];
+		hlist_for_each_entry(entry, n, bucket, hlist) {
+			if (ether_addr_equal_64bits(entry->mac, ha->addr)) {
+				found = true;
+				break;
+			}
+		}
+
+		if (!found) {
+			entry = kmalloc(sizeof(*entry), GFP_KERNEL);
+			if (!entry) {
+				en_err(priv, "Failed adding MAC %pM on port:%d (out of memory)\n",
+				       ha->addr, priv->port);
+				priv->flags |= MLX4_EN_FLAG_FORCE_PROMISC;
+				break;
+			}
+			mac = mlx4_en_mac_to_u64(ha->addr);
+			memcpy(entry->mac, ha->addr, ETH_ALEN);
+			err = mlx4_register_mac(mdev->dev, priv->port, mac);
+			if (err < 0) {
+				en_err(priv, "Failed registering MAC %pM on port %d: %d\n",
+				       ha->addr, priv->port, err);
+				kfree(entry);
+				priv->flags |= MLX4_EN_FLAG_FORCE_PROMISC;
+				break;
+			}
+			err = mlx4_en_uc_steer_add(priv, ha->addr,
+						   &priv->base_qpn,
+						   &entry->reg_id);
+			if (err) {
+				en_err(priv, "Failed adding MAC %pM on port %d: %d\n",
+				       ha->addr, priv->port, err);
+				mlx4_unregister_mac(mdev->dev, priv->port, mac);
+				kfree(entry);
+				priv->flags |= MLX4_EN_FLAG_FORCE_PROMISC;
+				break;
+			} else {
+				unsigned int mac_hash;
+				en_dbg(DRV, priv, "Added MAC %pM on port:%d\n",
+				       ha->addr, priv->port);
+				mac_hash = ha->addr[MLX4_EN_MAC_HASH_IDX];
+				bucket = &priv->mac_hash[mac_hash];
+				hlist_add_head_rcu(&entry->hlist, bucket);
+			}
+		}
+	}
+
+	if (priv->flags & MLX4_EN_FLAG_FORCE_PROMISC) {
+		en_warn(priv, "Forcing promiscuous mode on port:%d\n",
+			priv->port);
+	} else if (prev_flags & MLX4_EN_FLAG_FORCE_PROMISC) {
+		en_warn(priv, "Stop forcing promiscuous mode on port:%d\n",
+			priv->port);
+	}
+}
+
 static void mlx4_en_do_set_rx_mode(struct work_struct *work)
 {
 	struct mlx4_en_priv *priv = container_of(work, struct mlx4_en_priv,
@@ -1043,8 +1163,12 @@ static void mlx4_en_do_set_rx_mode(struct work_struct *work)
 		}
 	}
 
+	if (dev->priv_flags & IFF_UNICAST_FLT)
+		mlx4_en_do_uc_filter(priv, dev, mdev);
+
 	/* Promsicuous mode: disable all filters */
-	if (dev->flags & IFF_PROMISC) {
+	if ((dev->flags & IFF_PROMISC) ||
+	    (priv->flags & MLX4_EN_FLAG_FORCE_PROMISC)) {
 		mlx4_en_set_promisc_mode(priv, mdev);
 		goto out;
 	}
@@ -1961,6 +2085,9 @@ int mlx4_en_init_netdev(struct mlx4_en_dev *mdev, int port,
 	    MLX4_STEERING_MODE_DEVICE_MANAGED)
 		dev->hw_features |= NETIF_F_NTUPLE;
 
+	if (mdev->dev->caps.steering_mode != MLX4_STEERING_MODE_A0)
+		dev->priv_flags |= IFF_UNICAST_FLT;
+
 	mdev->pndev[port] = dev;
 
 	netif_carrier_off(dev);
diff --git a/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h b/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h
index 0ff99e0..c313d7e 100644
--- a/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h
+++ b/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h
@@ -439,7 +439,8 @@ enum {
 	 */
 	MLX4_EN_FLAG_ENABLE_HW_LOOPBACK	= (1 << 2),
 	/* whether we need to drop packets that hardware loopback-ed */
-	MLX4_EN_FLAG_RX_FILTER_NEEDED	= (1 << 3)
+	MLX4_EN_FLAG_RX_FILTER_NEEDED	= (1 << 3),
+	MLX4_EN_FLAG_FORCE_PROMISC	= (1 << 4)
 };
 
 #define MLX4_EN_MAC_HASH_SIZE (1 << BITS_PER_BYTE)
-- 
1.7.8.2

^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH net-next v2 9/9] net/mlx4_en: Implement ndo fdb functionality
  2013-02-07 12:25 [PATCH net-next v2 0/9] net/mlx4_en: Add support for unicast MAC filtering and FDB operations Amir Vadai
                   ` (7 preceding siblings ...)
  2013-02-07 12:25 ` [PATCH net-next v2 8/9] net/mlx4_en: Add unicast MAC filtering Amir Vadai
@ 2013-02-07 12:25 ` Amir Vadai
  2013-02-08  4:27 ` [PATCH net-next v2 0/9] net/mlx4_en: Add support for unicast MAC filtering and FDB operations David Miller
  9 siblings, 0 replies; 11+ messages in thread
From: Amir Vadai @ 2013-02-07 12:25 UTC (permalink / raw)
  To: David S. Miller; +Cc: Amir Vadai, Or Gerlitz, Yan Burman, netdev

From: Yan Burman <yanb@mellanox.com>

Add support for setting embedded switch fdb in case of SRIOV, by
implementing ndo_fdb_{add, del, dump}. This will allow to use
bridged configuration with multi-function. In order to add VM MAC
to the eSwitch fdb, the following command may be used over the relevant function interface:
bridge fdb add <MAC> permanent self dev <IFACE>

Signed-off-by: Yan Burman <yanb@mellanox.com>
Signed-off-by: Amir Vadai <amirv@mellanox.com>
---
 drivers/net/ethernet/mellanox/mlx4/en_netdev.c |   75 ++++++++++++++++++++++++
 1 files changed, 75 insertions(+), 0 deletions(-)

diff --git a/drivers/net/ethernet/mellanox/mlx4/en_netdev.c b/drivers/net/ethernet/mellanox/mlx4/en_netdev.c
index 2c19dab..4671fa5 100644
--- a/drivers/net/ethernet/mellanox/mlx4/en_netdev.c
+++ b/drivers/net/ethernet/mellanox/mlx4/en_netdev.c
@@ -1931,6 +1931,78 @@ static int mlx4_en_set_features(struct net_device *netdev,
 
 }
 
+static int mlx4_en_fdb_add(struct ndmsg *ndm, struct nlattr *tb[],
+			   struct net_device *dev,
+			   const unsigned char *addr, u16 flags)
+{
+	struct mlx4_en_priv *priv = netdev_priv(dev);
+	struct mlx4_dev *mdev = priv->mdev->dev;
+	int err;
+
+	if (!mlx4_is_mfunc(mdev))
+		return -EOPNOTSUPP;
+
+	/* Hardware does not support aging addresses, allow only
+	 * permanent addresses if ndm_state is given
+	 */
+	if (ndm->ndm_state && !(ndm->ndm_state & NUD_PERMANENT)) {
+		en_info(priv, "Add FDB only supports static addresses\n");
+		return -EINVAL;
+	}
+
+	if (is_unicast_ether_addr(addr) || is_link_local_ether_addr(addr))
+		err = dev_uc_add_excl(dev, addr);
+	else if (is_multicast_ether_addr(addr))
+		err = dev_mc_add_excl(dev, addr);
+	else
+		err = -EINVAL;
+
+	/* Only return duplicate errors if NLM_F_EXCL is set */
+	if (err == -EEXIST && !(flags & NLM_F_EXCL))
+		err = 0;
+
+	return err;
+}
+
+static int mlx4_en_fdb_del(struct ndmsg *ndm,
+			   struct net_device *dev,
+			   const unsigned char *addr)
+{
+	struct mlx4_en_priv *priv = netdev_priv(dev);
+	struct mlx4_dev *mdev = priv->mdev->dev;
+	int err;
+
+	if (!mlx4_is_mfunc(mdev))
+		return -EOPNOTSUPP;
+
+	if (ndm->ndm_state && !(ndm->ndm_state & NUD_PERMANENT)) {
+		en_info(priv, "Del FDB only supports static addresses\n");
+		return -EINVAL;
+	}
+
+	if (is_unicast_ether_addr(addr) || is_link_local_ether_addr(addr))
+		err = dev_uc_del(dev, addr);
+	else if (is_multicast_ether_addr(addr))
+		err = dev_mc_del(dev, addr);
+	else
+		err = -EINVAL;
+
+	return err;
+}
+
+static int mlx4_en_fdb_dump(struct sk_buff *skb,
+			    struct netlink_callback *cb,
+			    struct net_device *dev, int idx)
+{
+	struct mlx4_en_priv *priv = netdev_priv(dev);
+	struct mlx4_dev *mdev = priv->mdev->dev;
+
+	if (mlx4_is_mfunc(mdev))
+		idx = ndo_dflt_fdb_dump(skb, cb, dev, idx);
+
+	return idx;
+}
+
 static const struct net_device_ops mlx4_netdev_ops = {
 	.ndo_open		= mlx4_en_open,
 	.ndo_stop		= mlx4_en_close,
@@ -1952,6 +2024,9 @@ static const struct net_device_ops mlx4_netdev_ops = {
 #ifdef CONFIG_RFS_ACCEL
 	.ndo_rx_flow_steer	= mlx4_en_filter_rfs,
 #endif
+	.ndo_fdb_add		= mlx4_en_fdb_add,
+	.ndo_fdb_del		= mlx4_en_fdb_del,
+	.ndo_fdb_dump		= mlx4_en_fdb_dump,
 };
 
 int mlx4_en_init_netdev(struct mlx4_en_dev *mdev, int port,
-- 
1.7.8.2

^ permalink raw reply related	[flat|nested] 11+ messages in thread

* Re: [PATCH net-next v2 0/9] net/mlx4_en: Add support for unicast MAC filtering and FDB operations
  2013-02-07 12:25 [PATCH net-next v2 0/9] net/mlx4_en: Add support for unicast MAC filtering and FDB operations Amir Vadai
                   ` (8 preceding siblings ...)
  2013-02-07 12:25 ` [PATCH net-next v2 9/9] net/mlx4_en: Implement ndo fdb functionality Amir Vadai
@ 2013-02-08  4:27 ` David Miller
  9 siblings, 0 replies; 11+ messages in thread
From: David Miller @ 2013-02-08  4:27 UTC (permalink / raw)
  To: amirv; +Cc: ogerlitz, yanb, netdev

From: Amir Vadai <amirv@mellanox.com>
Date: Thu,  7 Feb 2013 14:25:18 +0200

> This series from Yan Burman adds support for unicast MAC address filtering and
> ndo FDB operations.  It also includes some optimizations to loopback related
> decisions and checks in the TX/RX fast path and one cleanup, all in separate
> patches.
> 
> Today, when adding macvlan devices, the NIC goes into promiscuous mode, since
> unicast MAC filtering is not supported. With these changes, macvlan devices can
> be added without the penalty of promiscuous mode.
> 
> If for some reason adding a unicast address filter fails e.g as of missing space in
> the HW mac table, the device forces itself into promiscuous mode (and out of this
> forced state when enough space is available).
> 
> Also, now it is possible to have bridge under multi-function configuration that include
> PF and VFs.  In order to use bridge over PF/VFs, VM MAC fdb entries must be added e.g.
> using 'bridge fdb add' command.

Series applied, thanks.

^ permalink raw reply	[flat|nested] 11+ messages in thread

end of thread, other threads:[~2013-02-08  4:27 UTC | newest]

Thread overview: 11+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2013-02-07 12:25 [PATCH net-next v2 0/9] net/mlx4_en: Add support for unicast MAC filtering and FDB operations Amir Vadai
2013-02-07 12:25 ` [PATCH net-next v2 1/9] net/mlx4_en: Optimize loopback related checks in data path Amir Vadai
2013-02-07 12:25 ` [PATCH net-next v2 2/9] net/mlx4_en: Optimize Rx fast path filter checks Amir Vadai
2013-02-07 12:25 ` [PATCH net-next v2 3/9] net/mlx4_en: Cleanup multiline strings Amir Vadai
2013-02-07 12:25 ` [PATCH net-next v2 4/9] net/mlx4: Move Ethernet related functionality from mlx4_core to mlx4_en Amir Vadai
2013-02-07 12:25 ` [PATCH net-next v2 5/9] net/mlx4_en: Re-arrange ndo_set_rx_mode related code Amir Vadai
2013-02-07 12:25 ` [PATCH net-next v2 6/9] net/mlx4_en: Save previous MAC address of the port so we can replace it later Amir Vadai
2013-02-07 12:25 ` [PATCH net-next v2 7/9] net/mlx4_en: Manage hash of MAC addresses per port Amir Vadai
2013-02-07 12:25 ` [PATCH net-next v2 8/9] net/mlx4_en: Add unicast MAC filtering Amir Vadai
2013-02-07 12:25 ` [PATCH net-next v2 9/9] net/mlx4_en: Implement ndo fdb functionality Amir Vadai
2013-02-08  4:27 ` [PATCH net-next v2 0/9] net/mlx4_en: Add support for unicast MAC filtering and FDB operations David Miller

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.