[SRU][J/N:linux-bluefield][PATCH v1 1/1] UBUNTU: SAUCE: mlxbf_gige: update hardware receive filter config for multicast MACs

David Thompson davthompson at nvidia.com
Wed May 6 14:20:57 UTC 2026


BugLink: https://bugs.launchpad.net/bugs/2151223

This patch updates the hardware receive filter configuration for
multicast MAC address handling. Today, the driver's "open()" routine
calls "enable_multicast_rx()" and leaves the OOB_RX_MAC_FILTER_MULTICAST
register (offset 0x0570) at its default data/mask values. In this
default state, the GIGE interface operates in ALLMULTI mode, so all
frames with a destination multicast MAC address pass through the
hardware receive filter.

The fix updates the logic in the driver's "ndo_set_rx_mode()", which
now programs the hardware receive filters based on the multicast MAC
addresses configured by the stack. The new implementation can support
up to three multicast MAC addresses using two direct-match RX filters
and a 48-bit start/end range. If the stack attempts to configure more
than 3 multicast MAC addresses, then the interface will be programmed
in ALLMULTI mode.

In addition, this patch extends "ndo_set_rx_mode()" to support enabling
and disabling of ALLMULTI mode [ifconfig oob_net0 [-]allmulti], as well
as enabling and disabling of multicast reception in general
[ifconfig oob_net0 [-]multicast].

Reviewed-by: Penghe Geng <pgeng at nvidia.com>
Signed-off-by: David Thompson <davthompson at nvidia.com>
---
 .../ethernet/mellanox/mlxbf_gige/mlxbf_gige.h |  14 ++-
 .../mellanox/mlxbf_gige/mlxbf_gige_main.c     |   3 +-
 .../mellanox/mlxbf_gige/mlxbf_gige_regs.h     |   2 +
 .../mellanox/mlxbf_gige/mlxbf_gige_rx.c       | 104 ++++++++++++++++--
 4 files changed, 108 insertions(+), 15 deletions(-)

diff --git a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige.h b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige.h
index e7777700ee18..eb8d807501ef 100644
--- a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige.h
+++ b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige.h
@@ -34,13 +34,14 @@
 #define MLXBF_GIGE_DMA_PAGE_SZ    4096
 #define MLXBF_GIGE_DMA_PAGE_SHIFT 12
 
-/* There are four individual MAC RX filters. Currently
- * two of them are being used: one for the broadcast MAC
- * (index 0) and one for local MAC (index 1)
+/* There are four individual MAC RX filters. In use: broadcast (0),
+ * local/unicast (1), and up to two exact multicast (2, 3).
  */
 #define MLXBF_GIGE_BCAST_MAC_FILTER_IDX 0
 #define MLXBF_GIGE_LOCAL_MAC_FILTER_IDX 1
-#define MLXBF_GIGE_MAX_FILTER_IDX       3
+#define MLXBF_GIGE_MCAST_MAC_FILTER_IDX0 2
+#define MLXBF_GIGE_MCAST_MAC_FILTER_IDX1 3
+#define MLXBF_GIGE_MAX_FILTER_IDX        3
 
 /* Define for broadcast MAC literal */
 #define BCAST_MAC_ADDR 0xFFFFFFFFFFFF
@@ -187,8 +188,13 @@ void mlxbf_gige_set_mac_rx_filter(struct mlxbf_gige *priv,
 				  unsigned int index, u64 dmac);
 void mlxbf_gige_get_mac_rx_filter(struct mlxbf_gige *priv,
 				  unsigned int index, u64 *dmac);
+void mlxbf_gige_enable_mac_rx_range(struct mlxbf_gige *priv,
+				    u64 start_mac, u64 end_mac);
+void mlxbf_gige_disable_mac_rx_range(struct mlxbf_gige *priv);
 void mlxbf_gige_enable_promisc(struct mlxbf_gige *priv);
 void mlxbf_gige_disable_promisc(struct mlxbf_gige *priv);
+void mlxbf_gige_set_rx_mode_multicast(struct mlxbf_gige *priv,
+				      struct net_device *netdev);
 int mlxbf_gige_rx_init(struct mlxbf_gige *priv);
 void mlxbf_gige_rx_deinit(struct mlxbf_gige *priv);
 int mlxbf_gige_tx_init(struct mlxbf_gige *priv);
diff --git a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_main.c b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_main.c
index f19c2172f145..ab9adc0a5a0c 100644
--- a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_main.c
+++ b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_main.c
@@ -178,7 +178,6 @@ static int mlxbf_gige_open(struct net_device *netdev)
 
 	mlxbf_gige_enable_mac_rx_filter(priv, MLXBF_GIGE_BCAST_MAC_FILTER_IDX);
 	mlxbf_gige_enable_mac_rx_filter(priv, MLXBF_GIGE_LOCAL_MAC_FILTER_IDX);
-	mlxbf_gige_enable_multicast_rx(priv);
 
 	/* Set bits in INT_EN that we care about */
 	int_en = MLXBF_GIGE_INT_EN_HW_ACCESS_ERROR |
@@ -257,6 +256,8 @@ static void mlxbf_gige_set_rx_mode(struct net_device *netdev)
 		else
 			mlxbf_gige_disable_promisc(priv);
 	}
+
+	mlxbf_gige_set_rx_mode_multicast(priv, netdev);
 }
 
 static void mlxbf_gige_get_stats64(struct net_device *netdev,
diff --git a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_regs.h b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_regs.h
index 4d14cb13fd64..2f3abf31ec66 100644
--- a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_regs.h
+++ b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_regs.h
@@ -70,6 +70,8 @@
 #define MLXBF_GIGE_RX_MAC_FILTER_COUNT_PASS_EN        BIT(0)
 #define MLXBF_GIGE_RX_PASS_COUNTER_ALL                0x0550
 #define MLXBF_GIGE_RX_DISC_COUNTER_ALL                0x0560
+#define MLXBF_GIGE_RX_MAC_FILTER_MULTICAST            0x0570
+#define MLXBF_GIGE_RX_MAC_FILTER_MULTICAST_DATA_SHIFT 24
 #define MLXBF_GIGE_RX                                 0x0578
 #define MLXBF_GIGE_RX_STRIP_CRC_EN                    BIT(1)
 #define MLXBF_GIGE_RX_DMA                             0x0580
diff --git a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_rx.c b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_rx.c
index eb62620b63c7..84e323925ce0 100644
--- a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_rx.c
+++ b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_rx.c
@@ -6,6 +6,7 @@
  */
 
 #include <linux/etherdevice.h>
+#include <linux/if.h>
 #include <linux/skbuff.h>
 
 #include "mlxbf_gige.h"
@@ -75,26 +76,22 @@ void mlxbf_gige_get_mac_rx_filter(struct mlxbf_gige *priv,
 		      (index * MLXBF_GIGE_RX_MAC_FILTER_STRIDE));
 }
 
-void mlxbf_gige_enable_promisc(struct mlxbf_gige *priv)
+void mlxbf_gige_enable_mac_rx_range(struct mlxbf_gige *priv,
+				    u64 start_mac, u64 end_mac)
 {
 	void __iomem *base = priv->base;
 	u64 control;
-	u64 end_mac;
+
+	writeq(start_mac, base + MLXBF_GIGE_RX_MAC_FILTER_DMAC_RANGE_START);
+	writeq(end_mac, base + MLXBF_GIGE_RX_MAC_FILTER_DMAC_RANGE_END);
 
 	/* Enable MAC_ID_RANGE match functionality */
 	control = readq(base + MLXBF_GIGE_CONTROL);
 	control |= MLXBF_GIGE_CONTROL_MAC_ID_RANGE_EN;
 	writeq(control, base + MLXBF_GIGE_CONTROL);
-
-	/* Set start of destination MAC range check to 0 */
-	writeq(0, base + MLXBF_GIGE_RX_MAC_FILTER_DMAC_RANGE_START);
-
-	/* Set end of destination MAC range check to all FFs */
-	end_mac = BCAST_MAC_ADDR;
-	writeq(end_mac, base + MLXBF_GIGE_RX_MAC_FILTER_DMAC_RANGE_END);
 }
 
-void mlxbf_gige_disable_promisc(struct mlxbf_gige *priv)
+void mlxbf_gige_disable_mac_rx_range(struct mlxbf_gige *priv)
 {
 	void __iomem *base = priv->base;
 	u64 control;
@@ -109,6 +106,93 @@ void mlxbf_gige_disable_promisc(struct mlxbf_gige *priv)
 	 */
 }
 
+void mlxbf_gige_enable_promisc(struct mlxbf_gige *priv)
+{
+	mlxbf_gige_enable_mac_rx_range(priv, 0, BCAST_MAC_ADDR);
+}
+
+void mlxbf_gige_disable_promisc(struct mlxbf_gige *priv)
+{
+	mlxbf_gige_disable_mac_rx_range(priv);
+}
+
+/* Configure data & mask filter to match upper 24-bits of multicast MAC */
+static void mlxbf_gige_write_rx_mcast(struct mlxbf_gige *priv, u32 data, u32 mask)
+{
+	u64 v;
+
+	v = ((u64)(data & 0xffffff) << MLXBF_GIGE_RX_MAC_FILTER_MULTICAST_DATA_SHIFT) |
+	    (mask & 0xffffff);
+	writeq(v, priv->base + MLXBF_GIGE_RX_MAC_FILTER_MULTICAST);
+}
+
+void mlxbf_gige_set_rx_mode_multicast(struct mlxbf_gige *priv,
+				      struct net_device *netdev)
+{
+	const u8 *addr0 = NULL, *addr1 = NULL, *addr2 = NULL;
+	struct netdev_hw_addr *ha;
+	unsigned int mc_count = 0;
+	u64 addr2_u64;
+
+	/* Promiscuous mode: no need to configure multicast filters */
+	if (netdev->flags & IFF_PROMISC)
+		return;
+
+	netdev_for_each_mc_addr(ha, netdev) {
+		if (mc_count == 0)
+			addr0 = ha->addr;
+		else if (mc_count == 1)
+			addr1 = ha->addr;
+		else if (mc_count == 2)
+			addr2 = ha->addr;
+		mc_count++;
+	}
+
+	/* ALLMULTI mode or 4+ multicast MACs: allow all packets with multicast bit set */
+	if ((netdev->flags & IFF_MULTICAST) &&
+	    ((netdev->flags & IFF_ALLMULTI) || mc_count > 3)) {
+		mlxbf_gige_write_rx_mcast(priv, BIT_ULL(40) >> 24, BIT_ULL(40) >> 24);
+		mlxbf_gige_enable_multicast_rx(priv);
+		return;
+	}
+
+	/* No multicast mode: turn off all multicast filter mechanisms */
+	if (((netdev->flags & IFF_MULTICAST) == 0) ||
+	    mc_count == 0) {
+		mlxbf_gige_disable_mac_rx_filter(priv, MLXBF_GIGE_MCAST_MAC_FILTER_IDX0);
+		mlxbf_gige_disable_mac_rx_filter(priv, MLXBF_GIGE_MCAST_MAC_FILTER_IDX1);
+		mlxbf_gige_disable_mac_rx_range(priv);
+		mlxbf_gige_disable_multicast_rx(priv);
+		return;
+	}
+
+	/* Disable ALLMULTI mode for 1-3 multicast MACs */
+	mlxbf_gige_disable_multicast_rx(priv);
+
+	/* Configure up to 2 multicast MACs in direct-match MAC filter slots 2 and 3 */
+	if (addr0) {
+		mlxbf_gige_set_mac_rx_filter(priv, MLXBF_GIGE_MCAST_MAC_FILTER_IDX0,
+					     ether_addr_to_u64(addr0));
+		mlxbf_gige_enable_mac_rx_filter(priv, MLXBF_GIGE_MCAST_MAC_FILTER_IDX0);
+	} else {
+		mlxbf_gige_disable_mac_rx_filter(priv, MLXBF_GIGE_MCAST_MAC_FILTER_IDX0);
+	}
+	if (mc_count > 1 && addr1) {
+		mlxbf_gige_set_mac_rx_filter(priv, MLXBF_GIGE_MCAST_MAC_FILTER_IDX1,
+					     ether_addr_to_u64(addr1));
+		mlxbf_gige_enable_mac_rx_filter(priv, MLXBF_GIGE_MCAST_MAC_FILTER_IDX1);
+	} else {
+		mlxbf_gige_disable_mac_rx_filter(priv, MLXBF_GIGE_MCAST_MAC_FILTER_IDX1);
+	}
+	/* Configure 3rd multicast MAC (if any) into 48-bit range compare */
+	if (mc_count > 2 && addr2) {
+		addr2_u64 = ether_addr_to_u64(addr2);
+		mlxbf_gige_enable_mac_rx_range(priv, addr2_u64, addr2_u64);
+	} else {
+		mlxbf_gige_disable_mac_rx_range(priv);
+	}
+}
+
 /* Receive Initialization
  * 1) Configures RX MAC filters via MMIO registers
  * 2) Allocates RX WQE array using coherent DMA mapping
-- 
2.43.0




More information about the kernel-team mailing list