]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
hinic3: Add .ndo_vlan_rx_add/kill_vid and .ndo_validate_addr
authorFan Gong <gongfan1@huawei.com>
Wed, 14 Jan 2026 08:38:25 +0000 (16:38 +0800)
committerPaolo Abeni <pabeni@redhat.com>
Tue, 20 Jan 2026 09:34:31 +0000 (10:34 +0100)
Implement following callback function:
.ndo_vlan_rx_add_vid
.ndo_vlan_rx_kill_vid
.ndo_validate_addr

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>
Link: https://patch.msgid.link/70be187afcaa7b38981d114c088ffdc2cba0b4f1.1768375903.git.zhuyikai1@h-partners.com
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
drivers/net/ethernet/huawei/hinic3/hinic3_main.c
drivers/net/ethernet/huawei/hinic3/hinic3_mgmt_interface.h
drivers/net/ethernet/huawei/hinic3/hinic3_netdev_ops.c
drivers/net/ethernet/huawei/hinic3/hinic3_nic_cfg.c
drivers/net/ethernet/huawei/hinic3/hinic3_nic_cfg.h
drivers/net/ethernet/huawei/hinic3/hinic3_nic_dev.h

index 6071d2023a5d744f2d18da0c0e78e85dedb1d95e..1f6bf7be9c1ee42fb8632086c70caed6b4860a93 100644 (file)
@@ -137,11 +137,17 @@ static int hinic3_init_nic_dev(struct net_device *netdev,
 
        nic_dev->rx_buf_len = HINIC3_RX_BUF_LEN;
        nic_dev->lro_replenish_thld = HINIC3_LRO_REPLENISH_THLD;
+       nic_dev->vlan_bitmap = kzalloc(HINIC3_VLAN_BITMAP_SIZE(nic_dev),
+                                      GFP_KERNEL);
+       if (!nic_dev->vlan_bitmap)
+               return -ENOMEM;
+
        nic_dev->nic_svc_cap = hwdev->cfg_mgmt->cap.nic_svc_cap;
 
        nic_dev->workq = create_singlethread_workqueue(HINIC3_NIC_DEV_WQ_NAME);
        if (!nic_dev->workq) {
                dev_err(hwdev->dev, "Failed to initialize nic workqueue\n");
+               kfree(nic_dev->vlan_bitmap);
                return -ENOMEM;
        }
 
@@ -335,6 +341,7 @@ static void hinic3_nic_event(struct auxiliary_device *adev,
 static void hinic3_free_nic_dev(struct hinic3_nic_dev *nic_dev)
 {
        destroy_workqueue(nic_dev->workq);
+       kfree(nic_dev->vlan_bitmap);
 }
 
 static int hinic3_nic_probe(struct auxiliary_device *adev,
index 69405715e734b5a95d13851dddaa20672e58151c..60f47152c01d1651616ba912e062be1d297d6e33 100644 (file)
@@ -56,6 +56,15 @@ struct l2nic_cmd_update_mac {
        u8                   new_mac[ETH_ALEN];
 };
 
+struct l2nic_cmd_vlan_config {
+       struct mgmt_msg_head msg_head;
+       u16                  func_id;
+       u8                   opcode;
+       u8                   rsvd1;
+       u16                  vlan_id;
+       u16                  rsvd2;
+};
+
 struct l2nic_cmd_vlan_offload {
        struct mgmt_msg_head msg_head;
        u16                  func_id;
@@ -205,6 +214,7 @@ enum l2nic_cmd {
        L2NIC_CMD_SET_MAC             = 21,
        L2NIC_CMD_DEL_MAC             = 22,
        L2NIC_CMD_UPDATE_MAC          = 23,
+       L2NIC_CMD_CFG_FUNC_VLAN       = 25,
        L2NIC_CMD_SET_VLAN_FILTER_EN  = 26,
        L2NIC_CMD_SET_RX_VLAN_OFFLOAD = 27,
        L2NIC_CMD_CFG_RSS             = 60,
index 87ada13b8f96f87d8dfaf315b3627cecb87e1fdb..74b2ce9e3a0a30ea1325e11e46a4a45990fa320f 100644 (file)
 #define HINIC3_LRO_DEFAULT_COAL_PKT_SIZE  32
 #define HINIC3_LRO_DEFAULT_TIME_LIMIT     16
 
+#define VLAN_BITMAP_BITS_SIZE(nic_dev)    (sizeof(*(nic_dev)->vlan_bitmap) * 8)
+#define VID_LINE(nic_dev, vid)  \
+       ((vid) / VLAN_BITMAP_BITS_SIZE(nic_dev))
+#define VID_COL(nic_dev, vid)  \
+       ((vid) & (VLAN_BITMAP_BITS_SIZE(nic_dev) - 1))
+
 /* try to modify the number of irq to the target number,
  * and return the actual number of irq.
  */
@@ -688,6 +694,59 @@ static int hinic3_set_mac_addr(struct net_device *netdev, void *addr)
        return 0;
 }
 
+static int hinic3_vlan_rx_add_vid(struct net_device *netdev,
+                                 __be16 proto, u16 vid)
+{
+       struct hinic3_nic_dev *nic_dev = netdev_priv(netdev);
+       unsigned long *vlan_bitmap = nic_dev->vlan_bitmap;
+       u32 column, row;
+       u16 func_id;
+       int err;
+
+       column = VID_COL(nic_dev, vid);
+       row = VID_LINE(nic_dev, vid);
+
+       func_id = hinic3_global_func_id(nic_dev->hwdev);
+
+       err = hinic3_add_vlan(nic_dev->hwdev, vid, func_id);
+       if (err) {
+               netdev_err(netdev, "Failed to add vlan %u\n", vid);
+               goto out;
+       }
+
+       set_bit(column, &vlan_bitmap[row]);
+       netdev_dbg(netdev, "Add vlan %u\n", vid);
+
+out:
+       return err;
+}
+
+static int hinic3_vlan_rx_kill_vid(struct net_device *netdev,
+                                  __be16 proto, u16 vid)
+{
+       struct hinic3_nic_dev *nic_dev = netdev_priv(netdev);
+       unsigned long *vlan_bitmap = nic_dev->vlan_bitmap;
+       u32 column, row;
+       u16 func_id;
+       int err;
+
+       column  = VID_COL(nic_dev, vid);
+       row = VID_LINE(nic_dev, vid);
+
+       func_id = hinic3_global_func_id(nic_dev->hwdev);
+       err = hinic3_del_vlan(nic_dev->hwdev, vid, func_id);
+       if (err) {
+               netdev_err(netdev, "Failed to delete vlan %u\n", vid);
+               goto out;
+       }
+
+       clear_bit(column, &vlan_bitmap[row]);
+       netdev_dbg(netdev, "Remove vlan %u\n", vid);
+
+out:
+       return err;
+}
+
 static void hinic3_tx_timeout(struct net_device *netdev, unsigned int txqueue)
 {
        struct hinic3_nic_dev *nic_dev = netdev_priv(netdev);
@@ -771,6 +830,9 @@ static const struct net_device_ops hinic3_netdev_ops = {
        .ndo_features_check   = hinic3_features_check,
        .ndo_change_mtu       = hinic3_change_mtu,
        .ndo_set_mac_address  = hinic3_set_mac_addr,
+       .ndo_validate_addr    = eth_validate_addr,
+       .ndo_vlan_rx_add_vid  = hinic3_vlan_rx_add_vid,
+       .ndo_vlan_rx_kill_vid = hinic3_vlan_rx_kill_vid,
        .ndo_tx_timeout       = hinic3_tx_timeout,
        .ndo_get_stats64      = hinic3_get_stats64,
        .ndo_start_xmit       = hinic3_xmit_frame,
index 79494ac8f39550fb91c11d8d174934553185fbc9..918882deea87f0dcdb497424ab45c3c3a16cec82 100644 (file)
@@ -10,6 +10,9 @@
 #include "hinic3_nic_dev.h"
 #include "hinic3_nic_io.h"
 
+#define MGMT_MSG_CMD_OP_ADD  1
+#define MGMT_MSG_CMD_OP_DEL  0
+
 static int hinic3_feature_nego(struct hinic3_hwdev *hwdev, u8 opcode,
                               u64 *s_feature, u16 size)
 {
@@ -496,6 +499,44 @@ int hinic3_force_drop_tx_pkt(struct hinic3_hwdev *hwdev)
        return pkt_drop.msg_head.status;
 }
 
+static int hinic3_config_vlan(struct hinic3_hwdev *hwdev,
+                             u8 opcode, u16 vlan_id, u16 func_id)
+{
+       struct l2nic_cmd_vlan_config vlan_info = {};
+       struct mgmt_msg_params msg_params = {};
+       int err;
+
+       vlan_info.opcode = opcode;
+       vlan_info.func_id = func_id;
+       vlan_info.vlan_id = vlan_id;
+
+       mgmt_msg_params_init_default(&msg_params, &vlan_info,
+                                    sizeof(vlan_info));
+
+       err = hinic3_send_mbox_to_mgmt(hwdev, MGMT_MOD_L2NIC,
+                                      L2NIC_CMD_CFG_FUNC_VLAN, &msg_params);
+
+       if (err || vlan_info.msg_head.status) {
+               dev_err(hwdev->dev,
+                       "Failed to %s vlan, err: %d, status: 0x%x\n",
+                       opcode == MGMT_MSG_CMD_OP_ADD ? "add" : "delete",
+                       err, vlan_info.msg_head.status);
+               return -EFAULT;
+       }
+
+       return 0;
+}
+
+int hinic3_add_vlan(struct hinic3_hwdev *hwdev, u16 vlan_id, u16 func_id)
+{
+       return hinic3_config_vlan(hwdev, MGMT_MSG_CMD_OP_ADD, vlan_id, func_id);
+}
+
+int hinic3_del_vlan(struct hinic3_hwdev *hwdev, u16 vlan_id, u16 func_id)
+{
+       return hinic3_config_vlan(hwdev, MGMT_MSG_CMD_OP_DEL, vlan_id, func_id);
+}
+
 int hinic3_set_port_enable(struct hinic3_hwdev *hwdev, bool enable)
 {
        struct mag_cmd_set_port_enable en_state = {};
index a17cd56bce7105f0c913f429a0484cbec72aff77..84831c87507b0770bacb7d59f59f3a7ceef765f9 100644 (file)
@@ -83,5 +83,7 @@ int hinic3_set_port_enable(struct hinic3_hwdev *hwdev, bool enable);
 int hinic3_get_link_status(struct hinic3_hwdev *hwdev, bool *link_status_up);
 int hinic3_set_vport_enable(struct hinic3_hwdev *hwdev, u16 func_id,
                            bool enable);
+int hinic3_add_vlan(struct hinic3_hwdev *hwdev, u16 vlan_id, u16 func_id);
+int hinic3_del_vlan(struct hinic3_hwdev *hwdev, u16 vlan_id, u16 func_id);
 
 #endif
index a8e92e070d9e081f1d9149f3ebdb1109fb52ef88..6e48c29566e10a98898234a97c9a970a381bce2b 100644 (file)
@@ -4,12 +4,17 @@
 #ifndef _HINIC3_NIC_DEV_H_
 #define _HINIC3_NIC_DEV_H_
 
+#include <linux/if_vlan.h>
 #include <linux/netdevice.h>
 
 #include "hinic3_hw_cfg.h"
 #include "hinic3_hwdev.h"
 #include "hinic3_mgmt_interface.h"
 
+#define HINIC3_VLAN_BITMAP_BYTE_SIZE(nic_dev)  (sizeof(*(nic_dev)->vlan_bitmap))
+#define HINIC3_VLAN_BITMAP_SIZE(nic_dev)  \
+       (VLAN_N_VID / HINIC3_VLAN_BITMAP_BYTE_SIZE(nic_dev))
+
 enum hinic3_flags {
        HINIC3_RSS_ENABLE,
 };
@@ -71,6 +76,7 @@ struct hinic3_nic_dev {
        u16                             max_qps;
        u16                             rx_buf_len;
        u32                             lro_replenish_thld;
+       unsigned long                   *vlan_bitmap;
        unsigned long                   flags;
        struct hinic3_nic_service_cap   nic_svc_cap;