1 // SPDX-License-Identifier: GPL-2.0 2 // Copyright (c) Huawei Technologies Co., Ltd. 2025. All rights reserved. 3 4 #include <linux/if_vlan.h> 5 6 #include "hinic3_hwdev.h" 7 #include "hinic3_hwif.h" 8 #include "hinic3_mbox.h" 9 #include "hinic3_nic_cfg.h" 10 #include "hinic3_nic_dev.h" 11 #include "hinic3_nic_io.h" 12 13 static int hinic3_feature_nego(struct hinic3_hwdev *hwdev, u8 opcode, 14 u64 *s_feature, u16 size) 15 { 16 struct l2nic_cmd_feature_nego feature_nego = {}; 17 struct mgmt_msg_params msg_params = {}; 18 int err; 19 20 feature_nego.func_id = hinic3_global_func_id(hwdev); 21 feature_nego.opcode = opcode; 22 if (opcode == MGMT_MSG_CMD_OP_SET) 23 memcpy(feature_nego.s_feature, s_feature, size * sizeof(u64)); 24 25 mgmt_msg_params_init_default(&msg_params, &feature_nego, 26 sizeof(feature_nego)); 27 28 err = hinic3_send_mbox_to_mgmt(hwdev, MGMT_MOD_L2NIC, 29 L2NIC_CMD_FEATURE_NEGO, &msg_params); 30 if (err || feature_nego.msg_head.status) { 31 dev_err(hwdev->dev, "Failed to negotiate nic feature, err:%d, status: 0x%x\n", 32 err, feature_nego.msg_head.status); 33 return -EIO; 34 } 35 36 if (opcode == MGMT_MSG_CMD_OP_GET) 37 memcpy(s_feature, feature_nego.s_feature, size * sizeof(u64)); 38 39 return 0; 40 } 41 42 int hinic3_set_nic_feature_to_hw(struct hinic3_nic_dev *nic_dev) 43 { 44 return hinic3_feature_nego(nic_dev->hwdev, MGMT_MSG_CMD_OP_SET, 45 &nic_dev->nic_io->feature_cap, 1); 46 } 47 48 bool hinic3_test_support(struct hinic3_nic_dev *nic_dev, 49 enum hinic3_nic_feature_cap feature_bits) 50 { 51 return (nic_dev->nic_io->feature_cap & feature_bits) == feature_bits; 52 } 53 54 void hinic3_update_nic_feature(struct hinic3_nic_dev *nic_dev, u64 feature_cap) 55 { 56 nic_dev->nic_io->feature_cap = feature_cap; 57 } 58 59 static int hinic3_set_function_table(struct hinic3_hwdev *hwdev, u32 cfg_bitmap, 60 const struct l2nic_func_tbl_cfg *cfg) 61 { 62 struct l2nic_cmd_set_func_tbl cmd_func_tbl = {}; 63 struct mgmt_msg_params msg_params = {}; 64 int err; 65 66 cmd_func_tbl.func_id = hinic3_global_func_id(hwdev); 67 cmd_func_tbl.cfg_bitmap = cfg_bitmap; 68 cmd_func_tbl.tbl_cfg = *cfg; 69 70 mgmt_msg_params_init_default(&msg_params, &cmd_func_tbl, 71 sizeof(cmd_func_tbl)); 72 73 err = hinic3_send_mbox_to_mgmt(hwdev, MGMT_MOD_L2NIC, 74 L2NIC_CMD_SET_FUNC_TBL, &msg_params); 75 if (err || cmd_func_tbl.msg_head.status) { 76 dev_err(hwdev->dev, 77 "Failed to set func table, bitmap: 0x%x, err: %d, status: 0x%x\n", 78 cfg_bitmap, err, cmd_func_tbl.msg_head.status); 79 return -EFAULT; 80 } 81 82 return 0; 83 } 84 85 int hinic3_set_port_mtu(struct net_device *netdev, u16 new_mtu) 86 { 87 struct hinic3_nic_dev *nic_dev = netdev_priv(netdev); 88 struct l2nic_func_tbl_cfg func_tbl_cfg = {}; 89 struct hinic3_hwdev *hwdev = nic_dev->hwdev; 90 91 func_tbl_cfg.mtu = new_mtu; 92 return hinic3_set_function_table(hwdev, BIT(L2NIC_FUNC_TBL_CFG_MTU), 93 &func_tbl_cfg); 94 } 95 96 static int hinic3_check_mac_info(struct hinic3_hwdev *hwdev, u8 status, 97 u16 vlan_id) 98 { 99 if ((status && status != MGMT_STATUS_EXIST) || 100 ((vlan_id & BIT(15)) && status == MGMT_STATUS_EXIST)) { 101 return -EINVAL; 102 } 103 104 return 0; 105 } 106 107 int hinic3_set_mac(struct hinic3_hwdev *hwdev, const u8 *mac_addr, u16 vlan_id, 108 u16 func_id) 109 { 110 struct l2nic_cmd_set_mac mac_info = {}; 111 struct mgmt_msg_params msg_params = {}; 112 int err; 113 114 if ((vlan_id & HINIC3_VLAN_ID_MASK) >= VLAN_N_VID) { 115 dev_err(hwdev->dev, "Invalid VLAN number: %d\n", 116 (vlan_id & HINIC3_VLAN_ID_MASK)); 117 return -EINVAL; 118 } 119 120 mac_info.func_id = func_id; 121 mac_info.vlan_id = vlan_id; 122 ether_addr_copy(mac_info.mac, mac_addr); 123 124 mgmt_msg_params_init_default(&msg_params, &mac_info, sizeof(mac_info)); 125 126 err = hinic3_send_mbox_to_mgmt(hwdev, MGMT_MOD_L2NIC, 127 L2NIC_CMD_SET_MAC, &msg_params); 128 if (err || hinic3_check_mac_info(hwdev, mac_info.msg_head.status, 129 mac_info.vlan_id)) { 130 dev_err(hwdev->dev, 131 "Failed to update MAC, err: %d, status: 0x%x\n", 132 err, mac_info.msg_head.status); 133 return -EIO; 134 } 135 136 if (mac_info.msg_head.status == MGMT_STATUS_PF_SET_VF_ALREADY) { 137 dev_warn(hwdev->dev, "PF has already set VF mac, Ignore set operation\n"); 138 return 0; 139 } 140 141 if (mac_info.msg_head.status == MGMT_STATUS_EXIST) { 142 dev_warn(hwdev->dev, "MAC is repeated. Ignore update operation\n"); 143 return 0; 144 } 145 146 return 0; 147 } 148 149 int hinic3_del_mac(struct hinic3_hwdev *hwdev, const u8 *mac_addr, u16 vlan_id, 150 u16 func_id) 151 { 152 struct l2nic_cmd_set_mac mac_info = {}; 153 struct mgmt_msg_params msg_params = {}; 154 int err; 155 156 if ((vlan_id & HINIC3_VLAN_ID_MASK) >= VLAN_N_VID) { 157 dev_err(hwdev->dev, "Invalid VLAN number: %d\n", 158 (vlan_id & HINIC3_VLAN_ID_MASK)); 159 return -EINVAL; 160 } 161 162 mac_info.func_id = func_id; 163 mac_info.vlan_id = vlan_id; 164 ether_addr_copy(mac_info.mac, mac_addr); 165 166 mgmt_msg_params_init_default(&msg_params, &mac_info, sizeof(mac_info)); 167 168 err = hinic3_send_mbox_to_mgmt(hwdev, MGMT_MOD_L2NIC, 169 L2NIC_CMD_DEL_MAC, &msg_params); 170 if (err) { 171 dev_err(hwdev->dev, 172 "Failed to delete MAC, err: %d, status: 0x%x\n", 173 err, mac_info.msg_head.status); 174 return err; 175 } 176 177 return 0; 178 } 179 180 int hinic3_update_mac(struct hinic3_hwdev *hwdev, const u8 *old_mac, 181 u8 *new_mac, u16 vlan_id, u16 func_id) 182 { 183 struct l2nic_cmd_update_mac mac_info = {}; 184 struct mgmt_msg_params msg_params = {}; 185 int err; 186 187 if ((vlan_id & HINIC3_VLAN_ID_MASK) >= VLAN_N_VID) { 188 dev_err(hwdev->dev, "Invalid VLAN number: %d\n", 189 (vlan_id & HINIC3_VLAN_ID_MASK)); 190 return -EINVAL; 191 } 192 193 mac_info.func_id = func_id; 194 mac_info.vlan_id = vlan_id; 195 ether_addr_copy(mac_info.old_mac, old_mac); 196 ether_addr_copy(mac_info.new_mac, new_mac); 197 198 mgmt_msg_params_init_default(&msg_params, &mac_info, sizeof(mac_info)); 199 200 err = hinic3_send_mbox_to_mgmt(hwdev, MGMT_MOD_L2NIC, 201 L2NIC_CMD_UPDATE_MAC, &msg_params); 202 if (err || hinic3_check_mac_info(hwdev, mac_info.msg_head.status, 203 mac_info.vlan_id)) { 204 dev_err(hwdev->dev, 205 "Failed to update MAC, err: %d, status: 0x%x\n", 206 err, mac_info.msg_head.status); 207 return -EIO; 208 } 209 return 0; 210 } 211 212 int hinic3_force_drop_tx_pkt(struct hinic3_hwdev *hwdev) 213 { 214 struct l2nic_cmd_force_pkt_drop pkt_drop = {}; 215 struct mgmt_msg_params msg_params = {}; 216 int err; 217 218 pkt_drop.port = hinic3_physical_port_id(hwdev); 219 220 mgmt_msg_params_init_default(&msg_params, &pkt_drop, sizeof(pkt_drop)); 221 222 err = hinic3_send_mbox_to_mgmt(hwdev, MGMT_MOD_L2NIC, 223 L2NIC_CMD_FORCE_PKT_DROP, &msg_params); 224 if ((pkt_drop.msg_head.status != MGMT_STATUS_CMD_UNSUPPORTED && 225 pkt_drop.msg_head.status) || err) { 226 dev_err(hwdev->dev, 227 "Failed to set force tx packets drop, err: %d, status: 0x%x\n", 228 err, pkt_drop.msg_head.status); 229 return -EFAULT; 230 } 231 232 return pkt_drop.msg_head.status; 233 } 234