Add chip-level receive filtering and the ndo_set_rx_mode_async callback. Program the primary and additional unicast addresses into the available RAR entries, and use the 4096-bit multicast hash table for multicast addresses. Advertise RAR-based secondary unicast filtering to the networking core, so it does not force promiscuous mode for a non-empty secondary unicast list. Fall back to accepting all unicast addresses if the RAR table is exhausted, and handle IFF_PROMISC and IFF_ALLMULTI through the chip-level filter control register. Signed-off-by: Dong Yibo --- drivers/net/ethernet/mucse/rnpgbe/rnpgbe.h | 3 + .../net/ethernet/mucse/rnpgbe/rnpgbe_chip.c | 96 +++++++++++++++++++ drivers/net/ethernet/mucse/rnpgbe/rnpgbe_hw.h | 15 +++ .../net/ethernet/mucse/rnpgbe/rnpgbe_main.c | 17 +++- 4 files changed, 127 insertions(+), 4 deletions(-) diff --git a/drivers/net/ethernet/mucse/rnpgbe/rnpgbe.h b/drivers/net/ethernet/mucse/rnpgbe/rnpgbe.h index 8032fa261df6..561048f0564e 100644 --- a/drivers/net/ethernet/mucse/rnpgbe/rnpgbe.h +++ b/drivers/net/ethernet/mucse/rnpgbe/rnpgbe.h @@ -234,6 +234,9 @@ int rnpgbe_send_notify(struct mucse_hw *hw, bool enable, int mode); int rnpgbe_init_hw(struct mucse_hw *hw, int board_type); +int rnpgbe_set_rx_mode(struct net_device *netdev, + struct netdev_hw_addr_list *uc, + struct netdev_hw_addr_list *mc); /* 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..79d66187d044 100644 --- a/drivers/net/ethernet/mucse/rnpgbe/rnpgbe_chip.c +++ b/drivers/net/ethernet/mucse/rnpgbe/rnpgbe_chip.c @@ -149,3 +149,99 @@ 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 old_low, old_high; + 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; + old_low = mucse_hw_rd32(hw, RNPGBE_RX_RAR_LOW(index)); + old_high = mucse_hw_rd32(hw, RNPGBE_RX_RAR_HIGH(index)); + if (old_low == rar_low && old_high == rar_high) + return; + + mucse_hw_wr32(hw, RNPGBE_RX_RAR_HIGH(index), + rar_high & ~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) +{ + u32 rar_high; + + rar_high = mucse_hw_rd32(hw, RNPGBE_RX_RAR_HIGH(index)); + if (!(rar_high & RNPGBE_RX_RAR_VALID)) + return; + + mucse_hw_wr32(hw, RNPGBE_RX_RAR_HIGH(index), 0); + mucse_hw_wr32(hw, RNPGBE_RX_RAR_LOW(index), 0); +} + +int rnpgbe_set_rx_mode(struct net_device *netdev, + struct netdev_hw_addr_list *uc, + struct netdev_hw_addr_list *mc) +{ + 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_hw_addr_list_for_each(ha, uc) { + 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 { + /* MTA type 0 uses ((addr[4] << 8) | addr[5]) & 0xfff. */ + netdev_hw_addr_list_for_each(ha, mc) { + hash = ((ha->addr[4] & 0xf) << 8) | ha->addr[5]; + mcast_hash[hash >> 5] |= BIT(hash & 0x1f); + } + + if (!netdev_hw_addr_list_empty(mc)) + mcast_ctrl |= RNPGBE_RX_MCAST_HASH_EN; + } + + /* Widen multicast filtering before invalidating hash entries. */ + if (filter_ctrl & RNPGBE_RX_FILTER_MCAST_ALL) + mucse_hw_wr32(hw, RNPGBE_RX_FILTER_CTRL, filter_ctrl); + + 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); + if (!(filter_ctrl & RNPGBE_RX_FILTER_MCAST_ALL)) + mucse_hw_wr32(hw, RNPGBE_RX_FILTER_CTRL, filter_ctrl); + + return 0; +} diff --git a/drivers/net/ethernet/mucse/rnpgbe/rnpgbe_hw.h b/drivers/net/ethernet/mucse/rnpgbe/rnpgbe_hw.h index dc869051c8fa..3f103f93ac30 100644 --- a/drivers/net/ethernet/mucse/rnpgbe/rnpgbe_hw.h +++ b/drivers/net/ethernet/mucse/rnpgbe/rnpgbe_hw.h @@ -26,5 +26,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 21fa78c59e5b..8e1eebf32723 100644 --- a/drivers/net/ethernet/mucse/rnpgbe/rnpgbe_main.c +++ b/drivers/net/ethernet/mucse/rnpgbe/rnpgbe_main.c @@ -43,6 +43,13 @@ static int rnpgbe_configure(struct mucse *mucse) if (err) return err; + netif_addr_lock_bh(mucse->netdev); + err = rnpgbe_set_rx_mode(mucse->netdev, &mucse->netdev->uc, + &mucse->netdev->mc); + netif_addr_unlock_bh(mucse->netdev); + if (err) + return err; + return rnpgbe_configure_rx(mucse); } @@ -140,10 +147,11 @@ 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_get_stats64 = rnpgbe_get_stats64, + .ndo_open = rnpgbe_open, + .ndo_stop = rnpgbe_close, + .ndo_start_xmit = rnpgbe_xmit_frame, + .ndo_set_rx_mode_async = rnpgbe_set_rx_mode, + .ndo_get_stats64 = rnpgbe_get_stats64, }; static void rnpgbe_sw_init(struct mucse *mucse) @@ -234,6 +242,7 @@ static int rnpgbe_add_adapter(struct pci_dev *pdev, } netdev->netdev_ops = &rnpgbe_netdev_ops; + netdev->priv_flags |= IFF_UNICAST_FLT; rnpgbe_sw_init(mucse); err = rnpgbe_reset_hw(hw); if (err) { -- 2.50.1