All of lore.kernel.org
 help / color / mirror / Atom feed
From: ALOK TIWARI <alok.a.tiwari@oracle.com>
To: Fan Gong <gongfan1@huawei.com>,
	Zhu Yikai <zhuyikai1@h-partners.com>,
	netdev@vger.kernel.org, "David S. Miller" <davem@davemloft.net>,
	Eric Dumazet <edumazet@google.com>,
	Jakub Kicinski <kuba@kernel.org>, Paolo Abeni <pabeni@redhat.com>,
	Simon Horman <horms@kernel.org>,
	Andrew Lunn <andrew+netdev@lunn.ch>,
	Markus.Elfring@web.de, pavan.chebbi@broadcom.com
Cc: linux-kernel@vger.kernel.org, linux-doc@vger.kernel.org,
	luosifu <luosifu@huawei.com>, Xin Guo <guoxin09@huawei.com>,
	Shen Chenyang <shenchenyang1@hisilicon.com>,
	Zhou Shuai <zhoushuai28@huawei.com>, Wu Like <wulike1@huawei.com>,
	Shi Jing <shijing34@huawei.com>,
	Luo Yang <luoyang82@h-partners.com>,
	Meny Yossefi <meny.yossefi@huawei.com>,
	Gur Stavi <gur.stavi@huawei.com>
Subject: Re: [External] : [PATCH net-next v05 4/5] hinic3: Add mac filter ops
Date: Fri, 7 Nov 2025 01:14:33 +0530	[thread overview]
Message-ID: <01ac3610-02eb-4a0e-b463-67548d2e02c2@oracle.com> (raw)
In-Reply-To: <02644ad18839feb50582ec8cd05830a4882517d4.1762414088.git.zhuyikai1@h-partners.com>



On 11/6/2025 4:45 PM, Fan Gong wrote:
> Add ops to support unicast and multicast to filter mac address and
> forward packages.

packages ->

> 
> Co-developed-by: Zhu Yikai <zhuyikai1@h-partners.com>
> Signed-off-by: Zhu Yikai <zhuyikai1@h-partners.com>
> Signed-off-by: Fan Gong <gongfan1@huawei.com>
> ---
>   drivers/net/ethernet/huawei/hinic3/Makefile   |   1 +
>   .../ethernet/huawei/hinic3/hinic3_filter.c    | 418 ++++++++++++++++++
>   .../net/ethernet/huawei/hinic3/hinic3_main.c  |   6 +
>   .../huawei/hinic3/hinic3_mgmt_interface.h     |  17 +
>   .../huawei/hinic3/hinic3_netdev_ops.c         |  15 +
>   .../ethernet/huawei/hinic3/hinic3_nic_cfg.c   |  24 +
>   .../ethernet/huawei/hinic3/hinic3_nic_cfg.h   |   1 +
>   .../ethernet/huawei/hinic3/hinic3_nic_dev.h   |  33 ++
>   8 files changed, 515 insertions(+)
> +
> +void hinic3_clean_mac_list_filter(struct net_device *netdev)
> +{
> +	struct hinic3_nic_dev *nic_dev = netdev_priv(netdev);
> +	struct hinic3_mac_filter *ftmp;
> +	struct hinic3_mac_filter *f;
> +
> +	list_for_each_entry_safe(f, ftmp, &nic_dev->uc_filter_list, list) {
> +		if (f->state == HINIC3_MAC_HW_SYNCED)
> +			hinic3_uc_unsync(netdev, f->addr);
> +		list_del(&f->list);
> +		kfree(f);
> +	}
> +
> +	list_for_each_entry_safe(f, ftmp, &nic_dev->mc_filter_list, list) {

hinic3_uc_unsync() for both UC and MC lists.

> +		if (f->state == HINIC3_MAC_HW_SYNCED)
> +			hinic3_uc_unsync(netdev, f->addr);
> +		list_del(&f->list);
> +		kfree(f);
> +	}
> +}
> +
> +static struct hinic3_mac_filter *
> +hinic3_find_mac(const struct list_head *filter_list, u8 *addr)
> +{
> +	struct hinic3_mac_filter *f;
> +
> +	list_for_each_entry(f, filter_list, list) {
> +		if (ether_addr_equal(addr, f->addr))
> +			return f;
> +	}
> +	return NULL;
> +}
> +
> +static int hinic3_mac_filter_sync(struct net_device *netdev,
> +				  struct list_head *mac_filter_list, bool uc)
> +{
> +	struct hinic3_nic_dev *nic_dev = netdev_priv(netdev);
> +	struct list_head tmp_del_list, tmp_add_list;
> +	int err = 0, add_list_len = 0, add_count;
> +	struct hinic3_mac_filter *fclone;
> +	struct hinic3_mac_filter *ftmp;
> +	struct hinic3_mac_filter *f;
> +
> +	INIT_LIST_HEAD(&tmp_del_list);
> +	INIT_LIST_HEAD(&tmp_add_list);
> +
> +	list_for_each_entry_safe(f, ftmp, mac_filter_list, list) {
> +		if (f->state != HINIC3_MAC_WAIT_HW_UNSYNC)
> +			continue;
> +
> +		f->state = HINIC3_MAC_HW_UNSYNCED;
> +		list_move_tail(&f->list, &tmp_del_list);
> +	}
> +
> +	list_for_each_entry_safe(f, ftmp, mac_filter_list, list) {
> +		if (f->state != HINIC3_MAC_WAIT_HW_SYNC)
> +			continue;
> +
> +		fclone = hinic3_mac_filter_entry_clone(f);
> +		if (!fclone) {
> +			hinic3_undo_del_filter_entries(mac_filter_list,
> +						       &tmp_del_list);
> +			hinic3_undo_add_filter_entries(mac_filter_list,
> +						       &tmp_add_list);
> +
> +			netdev_err(netdev,
> +				   "Failed to clone mac_filter_entry\n");
> +			err = -ENOMEM;
> +			goto cleanup_tmp_filter_list;
> +		}
> +
> +		f->state = HINIC3_MAC_HW_SYNCING;
> +		list_add_tail(&fclone->list, &tmp_add_list);
> +		add_list_len++;
> +	}
> +
> +	add_count = hinic3_mac_filter_sync_hw(netdev, &tmp_del_list,
> +					      &tmp_add_list);

this could return a -error; if hinic3_set_mac fail

> +	if (add_count < add_list_len) {
> +		/* there were errors, delete all mac in hw */
> +		hinic3_undo_add_filter_entries(mac_filter_list, &tmp_add_list);
> +		/* VF does not support promiscuous mode,
> +		 * don't delete any other uc mac.
> +		 */
> +		if (!HINIC3_IS_VF(nic_dev->hwdev) || !uc) {
> +			list_for_each_entry_safe(f, ftmp, mac_filter_list,
> +						 list) {
> +				if (f->state != HINIC3_MAC_HW_SYNCED)
> +					continue;
> +
> +				fclone = hinic3_mac_filter_entry_clone(f);
> +				if (!fclone)
> +					break;
> +
> +				f->state = HINIC3_MAC_HW_SYNCING;
> +				list_add_tail(&fclone->list, &tmp_del_list);
> +			}
> +		}
> +
> +		hinic3_mac_filter_sync_hw(netdev, &tmp_del_list, &tmp_add_list);
> +
> +		/* need to enter promiscuous/allmulti mode */
> +		err = -ENOMEM;
> +	}
> +
> +cleanup_tmp_filter_list:
> +	hinic3_cleanup_filter_list(&tmp_del_list);
> +	hinic3_cleanup_filter_list(&tmp_add_list);
> +
> +	return err ? err : add_count;
> +}
> +
> +static void hinic3_mac_filter_sync_all(struct net_device *netdev)
> +{
> +	struct hinic3_nic_dev *nic_dev = netdev_priv(netdev);
> +	int add_count;
> +
> +	if (test_bit(HINIC3_MAC_FILTER_CHANGED, &nic_dev->flags)) {
> +		clear_bit(HINIC3_MAC_FILTER_CHANGED, &nic_dev->flags);
> +		add_count = hinic3_mac_filter_sync(netdev,
> +						   &nic_dev->uc_filter_list,
> +						   true);
> +		if (add_count < 0 &&
> +		    hinic3_test_support(nic_dev, HINIC3_NIC_F_PROMISC))
> +			set_bit(HINIC3_PROMISC_FORCE_ON,
> +				&nic_dev->rx_mod_state);
> +		else if (add_count)
> +			clear_bit(HINIC3_PROMISC_FORCE_ON,
> +				  &nic_dev->rx_mod_state);
> +
> +		add_count = hinic3_mac_filter_sync(netdev,
> +						   &nic_dev->mc_filter_list,
> +						   false);
> +		if (add_count < 0 &&
> +		    hinic3_test_support(nic_dev, HINIC3_NIC_F_ALLMULTI))
> +			set_bit(HINIC3_ALLMULTI_FORCE_ON,
> +				&nic_dev->rx_mod_state);
> +		else if (add_count)
> +			clear_bit(HINIC3_ALLMULTI_FORCE_ON,
> +				  &nic_dev->rx_mod_state);
> +	}
> +}
> +
> +#define HINIC3_DEFAULT_RX_MODE \
> +	(L2NIC_RX_MODE_UC | L2NIC_RX_MODE_MC | L2NIC_RX_MODE_BC)
> +
> +static void hinic3_update_mac_filter(struct net_device *netdev,
> +				     const struct netdev_hw_addr_list *src_list,
> +				     struct list_head *filter_list)
> +{
> +	struct hinic3_mac_filter *filter;
> +	struct hinic3_mac_filter *ftmp;
> +	struct hinic3_mac_filter *f;
> +	struct netdev_hw_addr *ha;
> +
> +	/* add addr if not already in the filter list */
> +	netif_addr_lock_bh(netdev);
> +	netdev_hw_addr_list_for_each(ha, src_list) {
> +		filter = hinic3_find_mac(filter_list, ha->addr);
> +		if (!filter)
> +			hinic3_add_filter(netdev, filter_list, ha->addr);
> +		else if (filter->state == HINIC3_MAC_WAIT_HW_UNSYNC)
> +			filter->state = HINIC3_MAC_HW_SYNCED;
> +	}
> +	netif_addr_unlock_bh(netdev);
> +
> +	/* delete addr if not in netdev list */
> +	list_for_each_entry_safe(f, ftmp, filter_list, list) {
> +		bool found = false;
> +
> +		netif_addr_lock_bh(netdev);
> +		netdev_hw_addr_list_for_each(ha, src_list)
> +			if (ether_addr_equal(ha->addr, f->addr)) {
> +				found = true;
> +				break;
> +			}
> +		netif_addr_unlock_bh(netdev);
> +
> +		if (found)
> +			continue;
> +
> +		hinic3_del_filter(netdev, f);
> +	}
> +}
> +
> +static void hinic3_sync_rx_mode_to_hw(struct net_device *netdev, int promisc_en,
> +				      int allmulti_en)
> +{
> +	struct hinic3_nic_dev *nic_dev = netdev_priv(netdev);
> +	u32 rx_mod = HINIC3_DEFAULT_RX_MODE;
> +	int err;
> +
> +	rx_mod |= (promisc_en ? L2NIC_RX_MODE_PROMISC : 0);
> +	rx_mod |= (allmulti_en ? L2NIC_RX_MODE_MC_ALL : 0);
> +
> +	if (promisc_en != test_bit(HINIC3_HW_PROMISC_ON,
> +				   &nic_dev->rx_mod_state))
> +		netdev_dbg(netdev, "%s promisc mode\n",
> +			   promisc_en ? "Enter" : "Left");
> +	if (allmulti_en !=
> +	    test_bit(HINIC3_HW_ALLMULTI_ON, &nic_dev->rx_mod_state))
> +		netdev_dbg(netdev, "%s all_multi mode\n",
> +			   allmulti_en ? "Enter" : "Left");
> +
> +	err = hinic3_set_rx_mode(nic_dev->hwdev, rx_mod);
> +	if (err) {
> +		netdev_err(netdev, "Failed to set rx_mode\n");
> +		return;
> +	}
> +
> +	promisc_en ? set_bit(HINIC3_HW_PROMISC_ON, &nic_dev->rx_mod_state) :
> +		clear_bit(HINIC3_HW_PROMISC_ON, &nic_dev->rx_mod_state);
> +
> +	allmulti_en ? set_bit(HINIC3_HW_ALLMULTI_ON, &nic_dev->rx_mod_state) :
> +		clear_bit(HINIC3_HW_ALLMULTI_ON, &nic_dev->rx_mod_state);
> +}
> +
> +void hinic3_set_rx_mode_work(struct work_struct *work)
> +{
> +	int promisc_en = 0, allmulti_en = 0;
> +	struct hinic3_nic_dev *nic_dev;
> +	struct net_device *netdev;
> +
> +	nic_dev = container_of(work, struct hinic3_nic_dev, rx_mode_work);
> +	netdev = nic_dev->netdev;
> +
> +	if (test_and_clear_bit(HINIC3_UPDATE_MAC_FILTER, &nic_dev->flags)) {
> +		hinic3_update_mac_filter(netdev, &netdev->uc,
> +					 &nic_dev->uc_filter_list);
> +		hinic3_update_mac_filter(netdev, &netdev->mc,
> +					 &nic_dev->mc_filter_list);
> +	}
> +
> +	hinic3_mac_filter_sync_all(netdev);
> +
> +	if (hinic3_test_support(nic_dev, HINIC3_NIC_F_PROMISC))
> +		promisc_en = !!(netdev->flags & IFF_PROMISC) ||
> +			test_bit(HINIC3_PROMISC_FORCE_ON,
> +				 &nic_dev->rx_mod_state);
> +
> +	if (hinic3_test_support(nic_dev, HINIC3_NIC_F_ALLMULTI))
> +		allmulti_en = !!(netdev->flags & IFF_ALLMULTI) ||
> +			test_bit(HINIC3_ALLMULTI_FORCE_ON,
> +				 &nic_dev->rx_mod_state);
> +
> +	if (promisc_en != test_bit(HINIC3_HW_PROMISC_ON,
> +				   &nic_dev->rx_mod_state) ||
> +	    allmulti_en != test_bit(HINIC3_HW_ALLMULTI_ON,
> +				    &nic_dev->rx_mod_state))
> +		hinic3_sync_rx_mode_to_hw(netdev, promisc_en, allmulti_en);
> +}
> diff --git a/drivers/net/ethernet/huawei/hinic3/hinic3_main.c b/drivers/net/ethernet/huawei/hinic3/hinic3_main.c
> index 4a47dac1c4b4..e43597937da5 100644
> --- a/drivers/net/ethernet/huawei/hinic3/hinic3_main.c
> +++ b/drivers/net/ethernet/huawei/hinic3/hinic3_main.c
> @@ -154,6 +154,10 @@ static int hinic3_init_nic_dev(struct net_device *netdev,
>   	INIT_DELAYED_WORK(&nic_dev->periodic_work,
>   			  hinic3_periodic_work_handler);
>   
> +	INIT_LIST_HEAD(&nic_dev->uc_filter_list);
> +	INIT_LIST_HEAD(&nic_dev->mc_filter_list);
> +	INIT_WORK(&nic_dev->rx_mode_work, hinic3_set_rx_mode_work);
> +
>   	return 0;
>   }
>   
> @@ -220,6 +224,7 @@ static void hinic3_sw_uninit(struct net_device *netdev)
>   	struct hinic3_nic_dev *nic_dev = netdev_priv(netdev);
>   
>   	hinic3_free_txrxqs(netdev);
> +	hinic3_clean_mac_list_filter(netdev);
>   	hinic3_del_mac(nic_dev->hwdev, netdev->dev_addr, 0,
>   		       hinic3_global_func_id(nic_dev->hwdev));
>   	hinic3_clear_rss_config(netdev);
> @@ -408,6 +413,7 @@ static void hinic3_nic_remove(struct auxiliary_device *adev)
>   	unregister_netdev(netdev);
>   
>   	disable_delayed_work_sync(&nic_dev->periodic_work);
> +	cancel_work_sync(&nic_dev->rx_mode_work);
>   	destroy_workqueue(nic_dev->workq);
>   
>   	hinic3_update_nic_feature(nic_dev, 0);
> diff --git a/drivers/net/ethernet/huawei/hinic3/hinic3_mgmt_interface.h b/drivers/net/ethernet/huawei/hinic3/hinic3_mgmt_interface.h
> index 68dfdfa1b1ba..a69778b09c83 100644
> --- a/drivers/net/ethernet/huawei/hinic3/hinic3_mgmt_interface.h
> +++ b/drivers/net/ethernet/huawei/hinic3/hinic3_mgmt_interface.h
> @@ -115,6 +115,22 @@ struct l2nic_cmd_set_vport_state {
>   	u8                   rsvd2[3];
>   };
>   
> +/* *
> + * Definition of the NIC receiving mode
> + */
> +#define L2NIC_RX_MODE_UC       0x01
> +#define L2NIC_RX_MODE_MC       0x02
> +#define L2NIC_RX_MODE_BC       0x04
> +#define L2NIC_RX_MODE_MC_ALL   0x08
> +#define L2NIC_RX_MODE_PROMISC  0x10
> +
> +struct l2nic_rx_mode_config {
> +	struct mgmt_msg_head msg_head;
> +	u16                  func_id;
> +	u16                  rsvd1;
> +	u32                  rx_mode;
> +};
> +
>   struct l2nic_cmd_set_dcb_state {
>   	struct mgmt_msg_head head;
>   	u16                  func_id;
> @@ -205,6 +221,7 @@ enum l2nic_cmd {
>   	/* FUNC CFG */
>   	L2NIC_CMD_SET_FUNC_TBL        = 5,
>   	L2NIC_CMD_SET_VPORT_ENABLE    = 6,
> +	L2NIC_CMD_SET_RX_MODE         = 7,
>   	L2NIC_CMD_SET_SQ_CI_ATTR      = 8,
>   	L2NIC_CMD_CLEAR_QP_RESOURCE   = 11,
>   	L2NIC_CMD_CFG_RX_LRO          = 13,
> diff --git a/drivers/net/ethernet/huawei/hinic3/hinic3_netdev_ops.c b/drivers/net/ethernet/huawei/hinic3/hinic3_netdev_ops.c
> index ad50128f3d76..335de3093382 100644
> --- a/drivers/net/ethernet/huawei/hinic3/hinic3_netdev_ops.c
> +++ b/drivers/net/ethernet/huawei/hinic3/hinic3_netdev_ops.c
> @@ -828,6 +828,20 @@ static void hinic3_get_stats64(struct net_device *netdev,
>   	stats->rx_dropped = dropped;
>   }
>   
> +static void hinic3_nic_set_rx_mode(struct net_device *netdev)
> +{
> +	struct hinic3_nic_dev *nic_dev = netdev_priv(netdev);
> +
> +	if (netdev_uc_count(netdev) != nic_dev->netdev_uc_cnt ||
> +	    netdev_mc_count(netdev) != nic_dev->netdev_mc_cnt) {
> +		set_bit(HINIC3_UPDATE_MAC_FILTER, &nic_dev->flags);
> +		nic_dev->netdev_uc_cnt = netdev_uc_count(netdev);
> +		nic_dev->netdev_mc_cnt = netdev_mc_count(netdev);
> +	}
> +
> +	queue_work(nic_dev->workq, &nic_dev->rx_mode_work);
> +}
> +
>   static const struct net_device_ops hinic3_netdev_ops = {
>   	.ndo_open             = hinic3_open,
>   	.ndo_stop             = hinic3_close,
> @@ -840,6 +854,7 @@ static const struct net_device_ops hinic3_netdev_ops = {
>   	.ndo_vlan_rx_kill_vid = hinic3_vlan_rx_kill_vid,
>   	.ndo_tx_timeout       = hinic3_tx_timeout,
>   	.ndo_get_stats64      = hinic3_get_stats64,
> +	.ndo_set_rx_mode      = hinic3_nic_set_rx_mode,
>   	.ndo_start_xmit       = hinic3_xmit_frame,
>   };
>   
> diff --git a/drivers/net/ethernet/huawei/hinic3/hinic3_nic_cfg.c b/drivers/net/ethernet/huawei/hinic3/hinic3_nic_cfg.c
> index 72e09402841a..92afab46309c 100644
> --- a/drivers/net/ethernet/huawei/hinic3/hinic3_nic_cfg.c
> +++ b/drivers/net/ethernet/huawei/hinic3/hinic3_nic_cfg.c
> @@ -499,6 +499,30 @@ int hinic3_force_drop_tx_pkt(struct hinic3_hwdev *hwdev)
>   	return pkt_drop.msg_head.status;
>   }
>   
> +int hinic3_set_rx_mode(struct hinic3_hwdev *hwdev, u32 enable)

u32 enable -> u32 rx_mode

> +{
> +	struct l2nic_rx_mode_config rx_mode_cfg = {};
> +	struct mgmt_msg_params msg_params = {};
> +	int err;
> +
> +	rx_mode_cfg.func_id = hinic3_global_func_id(hwdev);
> +	rx_mode_cfg.rx_mode = enable;
> +
> +	mgmt_msg_params_init_default(&msg_params, &rx_mode_cfg,
> +				     sizeof(rx_mode_cfg));
> +
> +	err = hinic3_send_mbox_to_mgmt(hwdev, MGMT_MOD_L2NIC,
> +				       L2NIC_CMD_SET_RX_MODE, &msg_params);
> +
> +	if (err || rx_mode_cfg.msg_head.status) {
> +		dev_err(hwdev->dev, "Failed to set rx mode, err: %d, status: 0x%x\n",
> +			err, rx_mode_cfg.msg_head.status);
> +		return -EFAULT;
> +	}
> +
> +	return 0;
> +}
> +
>   static int hinic3_config_vlan(struct hinic3_hwdev *hwdev,


Thanks,
Alok

  reply	other threads:[~2025-11-06 19:45 UTC|newest]

Thread overview: 11+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2025-11-06 11:15 [PATCH net-next v05 0/5] net: hinic3: PF initialization Fan Gong
2025-11-06 11:15 ` [PATCH net-next v05 1/5] hinic3: Add PF framework Fan Gong
2025-11-06 14:19   ` [External] : " ALOK TIWARI
2025-11-07  8:26     ` Fan Gong
2025-11-06 11:15 ` [PATCH net-next v05 2/5] hinic3: Add PF management interfaces Fan Gong
2025-11-06 14:33   ` [External] : " ALOK TIWARI
2025-11-06 11:15 ` [PATCH net-next v05 3/5] hinic3: Add NIC configuration ops Fan Gong
2025-11-06 19:14   ` [External] : " ALOK TIWARI
2025-11-06 11:15 ` [PATCH net-next v05 4/5] hinic3: Add mac filter ops Fan Gong
2025-11-06 19:44   ` ALOK TIWARI [this message]
2025-11-06 11:15 ` [PATCH net-next v05 5/5] hinic3: Add netdev register interfaces Fan Gong

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=01ac3610-02eb-4a0e-b463-67548d2e02c2@oracle.com \
    --to=alok.a.tiwari@oracle.com \
    --cc=Markus.Elfring@web.de \
    --cc=andrew+netdev@lunn.ch \
    --cc=davem@davemloft.net \
    --cc=edumazet@google.com \
    --cc=gongfan1@huawei.com \
    --cc=guoxin09@huawei.com \
    --cc=gur.stavi@huawei.com \
    --cc=horms@kernel.org \
    --cc=kuba@kernel.org \
    --cc=linux-doc@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=luosifu@huawei.com \
    --cc=luoyang82@h-partners.com \
    --cc=meny.yossefi@huawei.com \
    --cc=netdev@vger.kernel.org \
    --cc=pabeni@redhat.com \
    --cc=pavan.chebbi@broadcom.com \
    --cc=shenchenyang1@hisilicon.com \
    --cc=shijing34@huawei.com \
    --cc=wulike1@huawei.com \
    --cc=zhoushuai28@huawei.com \
    --cc=zhuyikai1@h-partners.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
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.