Implement following callback function: .ndo_vlan_rx_add_vid .ndo_vlan_rx_kill_vid .ndo_validate_addr Co-developed-by: Zhu Yikai Signed-off-by: Zhu Yikai Signed-off-by: Fan Gong --- .../net/ethernet/huawei/hinic3/hinic3_main.c | 7 +++ .../huawei/hinic3/hinic3_mgmt_interface.h | 10 +++ .../huawei/hinic3/hinic3_netdev_ops.c | 62 +++++++++++++++++++ .../ethernet/huawei/hinic3/hinic3_nic_cfg.c | 41 ++++++++++++ .../ethernet/huawei/hinic3/hinic3_nic_cfg.h | 2 + .../ethernet/huawei/hinic3/hinic3_nic_dev.h | 6 ++ 6 files changed, 128 insertions(+) diff --git a/drivers/net/ethernet/huawei/hinic3/hinic3_main.c b/drivers/net/ethernet/huawei/hinic3/hinic3_main.c index 704afd3189ee..f0f347c6b6ba 100644 --- a/drivers/net/ethernet/huawei/hinic3/hinic3_main.c +++ b/drivers/net/ethernet/huawei/hinic3/hinic3_main.c @@ -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, diff --git a/drivers/net/ethernet/huawei/hinic3/hinic3_mgmt_interface.h b/drivers/net/ethernet/huawei/hinic3/hinic3_mgmt_interface.h index 69405715e734..60f47152c01d 100644 --- a/drivers/net/ethernet/huawei/hinic3/hinic3_mgmt_interface.h +++ b/drivers/net/ethernet/huawei/hinic3/hinic3_mgmt_interface.h @@ -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, diff --git a/drivers/net/ethernet/huawei/hinic3/hinic3_netdev_ops.c b/drivers/net/ethernet/huawei/hinic3/hinic3_netdev_ops.c index f7e6fbdec40b..1e298be6e0d1 100644 --- a/drivers/net/ethernet/huawei/hinic3/hinic3_netdev_ops.c +++ b/drivers/net/ethernet/huawei/hinic3/hinic3_netdev_ops.c @@ -15,6 +15,12 @@ #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. */ @@ -676,6 +682,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); @@ -758,6 +817,9 @@ static const struct net_device_ops hinic3_netdev_ops = { .ndo_fix_features = hinic3_fix_features, .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, diff --git a/drivers/net/ethernet/huawei/hinic3/hinic3_nic_cfg.c b/drivers/net/ethernet/huawei/hinic3/hinic3_nic_cfg.c index c8944c51e6bf..4a5356cf51a5 100644 --- a/drivers/net/ethernet/huawei/hinic3/hinic3_nic_cfg.c +++ b/drivers/net/ethernet/huawei/hinic3/hinic3_nic_cfg.c @@ -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 = {}; diff --git a/drivers/net/ethernet/huawei/hinic3/hinic3_nic_cfg.h b/drivers/net/ethernet/huawei/hinic3/hinic3_nic_cfg.h index a17cd56bce71..84831c87507b 100644 --- a/drivers/net/ethernet/huawei/hinic3/hinic3_nic_cfg.h +++ b/drivers/net/ethernet/huawei/hinic3/hinic3_nic_cfg.h @@ -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 diff --git a/drivers/net/ethernet/huawei/hinic3/hinic3_nic_dev.h b/drivers/net/ethernet/huawei/hinic3/hinic3_nic_dev.h index a8e92e070d9e..6e48c29566e1 100644 --- a/drivers/net/ethernet/huawei/hinic3/hinic3_nic_dev.h +++ b/drivers/net/ethernet/huawei/hinic3/hinic3_nic_dev.h @@ -4,12 +4,17 @@ #ifndef _HINIC3_NIC_DEV_H_ #define _HINIC3_NIC_DEV_H_ +#include #include #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; -- 2.43.0