[PATCH net-next v10 4/5] net: rnpgbe: Add receive mode support
From: Dong Yibo
Date: Mon Aug 31 2026 - 03:40:22 EST
Add chip-level receive filtering and the ndo_set_rx_mode callback.
Program the primary and additional unicast addresses into the available
RAR entries, and use the 4096-bit multicast hash table for multicast
addresses. Fall back to accepting all unicast addresses when the RAR
table is exhausted, and handle IFF_PROMISC and IFF_ALLMULTI through the
chip-level filter control register.
Signed-off-by: Dong Yibo <dong100@xxxxxxxxx>
---
drivers/net/ethernet/mucse/rnpgbe/rnpgbe.h | 1 +
.../net/ethernet/mucse/rnpgbe/rnpgbe_chip.c | 73 +++++++++++++++++++
drivers/net/ethernet/mucse/rnpgbe/rnpgbe_hw.h | 15 ++++
.../net/ethernet/mucse/rnpgbe/rnpgbe_main.c | 14 +++-
4 files changed, 99 insertions(+), 4 deletions(-)
diff --git a/drivers/net/ethernet/mucse/rnpgbe/rnpgbe.h b/drivers/net/ethernet/mucse/rnpgbe/rnpgbe.h
index 8c3d8bbfcc1a..8d7c6f8301cd 100644
--- a/drivers/net/ethernet/mucse/rnpgbe/rnpgbe.h
+++ b/drivers/net/ethernet/mucse/rnpgbe/rnpgbe.h
@@ -233,6 +233,7 @@ int rnpgbe_send_notify(struct mucse_hw *hw,
bool enable,
int mode);
int rnpgbe_init_hw(struct mucse_hw *hw, int board_type);
+void rnpgbe_set_rx_mode(struct net_device *netdev);
/* Device IDs */
#define PCI_VENDOR_ID_MUCSE 0x8848
diff --git a/drivers/net/ethernet/mucse/rnpgbe/rnpgbe_chip.c b/drivers/net/ethernet/mucse/rnpgbe/rnpgbe_chip.c
index 291e77d573fe..c7d5b53f6209 100644
--- a/drivers/net/ethernet/mucse/rnpgbe/rnpgbe_chip.c
+++ b/drivers/net/ethernet/mucse/rnpgbe/rnpgbe_chip.c
@@ -149,3 +149,76 @@ int rnpgbe_init_hw(struct mucse_hw *hw, int board_type)
return 0;
}
+
+static void rnpgbe_set_rar(struct mucse_hw *hw, u32 index, const u8 *addr)
+{
+ u32 rar_low, rar_high;
+
+ /* The RAR stores the Ethernet address in reverse byte order. */
+ rar_low = (u32)addr[5] | ((u32)addr[4] << 8) |
+ ((u32)addr[3] << 16) | ((u32)addr[2] << 24);
+ rar_high = (u32)addr[1] | ((u32)addr[0] << 8) |
+ RNPGBE_RX_RAR_VALID;
+ mucse_hw_wr32(hw, RNPGBE_RX_RAR_LOW(index), rar_low);
+ mucse_hw_wr32(hw, RNPGBE_RX_RAR_HIGH(index), rar_high);
+}
+
+static void rnpgbe_clear_rar(struct mucse_hw *hw, u32 index)
+{
+ mucse_hw_wr32(hw, RNPGBE_RX_RAR_LOW(index), 0);
+ mucse_hw_wr32(hw, RNPGBE_RX_RAR_HIGH(index), 0);
+}
+
+void rnpgbe_set_rx_mode(struct net_device *netdev)
+{
+ u32 mcast_hash[RNPGBE_RX_MCAST_HASH_ENTRIES] = {};
+ u32 mcast_ctrl = RNPGBE_RX_UCAST_TABLE_EN;
+ u32 filter_ctrl = RNPGBE_RX_FILTER_BCAST;
+ struct netdev_hw_addr *ha;
+ struct mucse_hw *hw;
+ struct mucse *mucse;
+ int rar = 1;
+ u16 hash;
+ int i;
+
+ mucse = netdev_priv(netdev);
+ hw = &mucse->hw;
+
+ /* RAR 0 always holds the interface's primary unicast address. */
+ rnpgbe_set_rar(hw, 0, netdev->dev_addr);
+
+ netdev_for_each_uc_addr(ha, netdev) {
+ if (rar == RNPGBE_RX_RAR_ENTRIES) {
+ filter_ctrl |= RNPGBE_RX_FILTER_UCAST_ALL;
+ break;
+ }
+
+ rnpgbe_set_rar(hw, rar, ha->addr);
+ rar++;
+ }
+
+ for (; rar < RNPGBE_RX_RAR_ENTRIES; rar++)
+ rnpgbe_clear_rar(hw, rar);
+
+ if (netdev->flags & IFF_PROMISC) {
+ filter_ctrl |= RNPGBE_RX_FILTER_UCAST_ALL |
+ RNPGBE_RX_FILTER_MCAST_ALL;
+ } else if (netdev->flags & IFF_ALLMULTI) {
+ filter_ctrl |= RNPGBE_RX_FILTER_MCAST_ALL;
+ } else {
+ /* The MTA index is the 12 address bits from 36 through 47. */
+ netdev_for_each_mc_addr(ha, netdev) {
+ hash = ((ha->addr[4] & 0xf) << 8) | ha->addr[5];
+ mcast_hash[hash >> 5] |= BIT(hash & 0x1f);
+ }
+
+ if (!netdev_mc_empty(netdev))
+ mcast_ctrl |= RNPGBE_RX_MCAST_HASH_EN;
+ }
+
+ for (i = 0; i < RNPGBE_RX_MCAST_HASH_ENTRIES; i++)
+ mucse_hw_wr32(hw, RNPGBE_RX_MCAST_HASH(i), mcast_hash[i]);
+
+ mucse_hw_wr32(hw, RNPGBE_RX_MCAST_CTRL, mcast_ctrl);
+ mucse_hw_wr32(hw, RNPGBE_RX_FILTER_CTRL, filter_ctrl);
+}
diff --git a/drivers/net/ethernet/mucse/rnpgbe/rnpgbe_hw.h b/drivers/net/ethernet/mucse/rnpgbe/rnpgbe_hw.h
index 1d87edfba3d7..feb84704d602 100644
--- a/drivers/net/ethernet/mucse/rnpgbe/rnpgbe_hw.h
+++ b/drivers/net/ethernet/mucse/rnpgbe/rnpgbe_hw.h
@@ -24,5 +24,20 @@
#define RNPGBE_DMA_AXI_EN 0x0010
#define RNPGBE_TX_MIN_PKT_LEN 33
+#define MUCSE_ETH_OFF(_n) (0x10000 + (_n))
+#define RNPGBE_RX_RAR_LOW(_n) MUCSE_ETH_OFF(0xa000 + 4 * (_n))
+#define RNPGBE_RX_RAR_HIGH(_n) MUCSE_ETH_OFF(0xa400 + 4 * (_n))
+#define RNPGBE_RX_MCAST_HASH(_n) MUCSE_ETH_OFF(0xac00 + 4 * (_n))
+#define RNPGBE_RX_FILTER_CTRL MUCSE_ETH_OFF(0x9110)
+#define RNPGBE_RX_MCAST_CTRL MUCSE_ETH_OFF(0x9114)
+#define RNPGBE_RX_RAR_VALID BIT(31)
+#define RNPGBE_RX_FILTER_BCAST BIT(10)
+#define RNPGBE_RX_FILTER_UCAST_ALL BIT(9)
+#define RNPGBE_RX_FILTER_MCAST_ALL BIT(8)
+#define RNPGBE_RX_MCAST_HASH_EN BIT(4)
+#define RNPGBE_RX_UCAST_TABLE_EN BIT(3)
+/* The final two of the 32 hardware RAR entries are reserved for NCSI. */
+#define RNPGBE_RX_RAR_ENTRIES 30
+#define RNPGBE_RX_MCAST_HASH_ENTRIES 128
#define RNPGBE_MAX_QUEUES 8
#endif /* _RNPGBE_HW_H */
diff --git a/drivers/net/ethernet/mucse/rnpgbe/rnpgbe_main.c b/drivers/net/ethernet/mucse/rnpgbe/rnpgbe_main.c
index e62366291b2a..817081e24bb5 100644
--- a/drivers/net/ethernet/mucse/rnpgbe/rnpgbe_main.c
+++ b/drivers/net/ethernet/mucse/rnpgbe/rnpgbe_main.c
@@ -43,7 +43,12 @@ static int rnpgbe_configure(struct mucse *mucse)
if (err)
return err;
- return rnpgbe_configure_rx(mucse);
+ err = rnpgbe_configure_rx(mucse);
+ if (err)
+ return err;
+
+ rnpgbe_set_rx_mode(mucse->netdev);
+ return 0;
}
/**
@@ -142,9 +147,10 @@ static netdev_tx_t rnpgbe_xmit_frame(struct sk_buff *skb,
}
static const struct net_device_ops rnpgbe_netdev_ops = {
- .ndo_open = rnpgbe_open,
- .ndo_stop = rnpgbe_close,
- .ndo_start_xmit = rnpgbe_xmit_frame,
+ .ndo_open = rnpgbe_open,
+ .ndo_stop = rnpgbe_close,
+ .ndo_start_xmit = rnpgbe_xmit_frame,
+ .ndo_set_rx_mode = rnpgbe_set_rx_mode,
.ndo_get_stats64 = rnpgbe_get_stats64,
};
--
2.50.1