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_get_nic_feature_from_hw(struct hinic3_nic_dev *nic_dev) 43 { 44 return hinic3_feature_nego(nic_dev->hwdev, MGMT_MSG_CMD_OP_GET, 45 &nic_dev->nic_io->feature_cap, 1); 46 } 47 48 int hinic3_set_nic_feature_to_hw(struct hinic3_nic_dev *nic_dev) 49 { 50 return hinic3_feature_nego(nic_dev->hwdev, MGMT_MSG_CMD_OP_SET, 51 &nic_dev->nic_io->feature_cap, 1); 52 } 53 54 bool hinic3_test_support(struct hinic3_nic_dev *nic_dev, 55 enum hinic3_nic_feature_cap feature_bits) 56 { 57 return (nic_dev->nic_io->feature_cap & feature_bits) == feature_bits; 58 } 59 60 void hinic3_update_nic_feature(struct hinic3_nic_dev *nic_dev, u64 feature_cap) 61 { 62 nic_dev->nic_io->feature_cap = feature_cap; 63 } 64 65 static int hinic3_set_function_table(struct hinic3_hwdev *hwdev, u32 cfg_bitmap, 66 const struct l2nic_func_tbl_cfg *cfg) 67 { 68 struct l2nic_cmd_set_func_tbl cmd_func_tbl = {}; 69 struct mgmt_msg_params msg_params = {}; 70 int err; 71 72 cmd_func_tbl.func_id = hinic3_global_func_id(hwdev); 73 cmd_func_tbl.cfg_bitmap = cfg_bitmap; 74 cmd_func_tbl.tbl_cfg = *cfg; 75 76 mgmt_msg_params_init_default(&msg_params, &cmd_func_tbl, 77 sizeof(cmd_func_tbl)); 78 79 err = hinic3_send_mbox_to_mgmt(hwdev, MGMT_MOD_L2NIC, 80 L2NIC_CMD_SET_FUNC_TBL, &msg_params); 81 if (err || cmd_func_tbl.msg_head.status) { 82 dev_err(hwdev->dev, 83 "Failed to set func table, bitmap: 0x%x, err: %d, status: 0x%x\n", 84 cfg_bitmap, err, cmd_func_tbl.msg_head.status); 85 return -EFAULT; 86 } 87 88 return 0; 89 } 90 91 int hinic3_init_function_table(struct hinic3_nic_dev *nic_dev) 92 { 93 struct hinic3_nic_io *nic_io = nic_dev->nic_io; 94 struct l2nic_func_tbl_cfg func_tbl_cfg = {}; 95 u32 cfg_bitmap; 96 97 func_tbl_cfg.mtu = 0x3FFF; /* default, max mtu */ 98 func_tbl_cfg.rx_wqe_buf_size = nic_io->rx_buf_len; 99 100 cfg_bitmap = BIT(L2NIC_FUNC_TBL_CFG_INIT) | 101 BIT(L2NIC_FUNC_TBL_CFG_MTU) | 102 BIT(L2NIC_FUNC_TBL_CFG_RX_BUF_SIZE); 103 104 return hinic3_set_function_table(nic_dev->hwdev, cfg_bitmap, 105 &func_tbl_cfg); 106 } 107 108 int hinic3_set_port_mtu(struct net_device *netdev, u16 new_mtu) 109 { 110 struct hinic3_nic_dev *nic_dev = netdev_priv(netdev); 111 struct l2nic_func_tbl_cfg func_tbl_cfg = {}; 112 struct hinic3_hwdev *hwdev = nic_dev->hwdev; 113 114 func_tbl_cfg.mtu = new_mtu; 115 116 return hinic3_set_function_table(hwdev, BIT(L2NIC_FUNC_TBL_CFG_MTU), 117 &func_tbl_cfg); 118 } 119 120 static int hinic3_check_mac_info(struct hinic3_hwdev *hwdev, u8 status, 121 u16 vlan_id) 122 { 123 if ((status && status != MGMT_STATUS_EXIST) || 124 ((vlan_id & BIT(15)) && status == MGMT_STATUS_EXIST)) { 125 return -EINVAL; 126 } 127 128 return 0; 129 } 130 131 int hinic3_set_mac(struct hinic3_hwdev *hwdev, const u8 *mac_addr, u16 vlan_id, 132 u16 func_id) 133 { 134 struct l2nic_cmd_set_mac mac_info = {}; 135 struct mgmt_msg_params msg_params = {}; 136 int err; 137 138 if ((vlan_id & HINIC3_VLAN_ID_MASK) >= VLAN_N_VID) { 139 dev_err(hwdev->dev, "Invalid VLAN number: %d\n", 140 (vlan_id & HINIC3_VLAN_ID_MASK)); 141 return -EINVAL; 142 } 143 144 mac_info.func_id = func_id; 145 mac_info.vlan_id = vlan_id; 146 ether_addr_copy(mac_info.mac, mac_addr); 147 148 mgmt_msg_params_init_default(&msg_params, &mac_info, sizeof(mac_info)); 149 150 err = hinic3_send_mbox_to_mgmt(hwdev, MGMT_MOD_L2NIC, 151 L2NIC_CMD_SET_MAC, &msg_params); 152 if (err || hinic3_check_mac_info(hwdev, mac_info.msg_head.status, 153 mac_info.vlan_id)) { 154 dev_err(hwdev->dev, 155 "Failed to update MAC, err: %d, status: 0x%x\n", 156 err, mac_info.msg_head.status); 157 return -EIO; 158 } 159 160 if (mac_info.msg_head.status == MGMT_STATUS_PF_SET_VF_ALREADY) { 161 dev_warn(hwdev->dev, "PF has already set VF mac, Ignore set operation\n"); 162 return 0; 163 } 164 165 if (mac_info.msg_head.status == MGMT_STATUS_EXIST) { 166 dev_warn(hwdev->dev, "MAC is repeated. Ignore update operation\n"); 167 return 0; 168 } 169 170 return 0; 171 } 172 173 int hinic3_del_mac(struct hinic3_hwdev *hwdev, const u8 *mac_addr, u16 vlan_id, 174 u16 func_id) 175 { 176 struct l2nic_cmd_set_mac mac_info = {}; 177 struct mgmt_msg_params msg_params = {}; 178 int err; 179 180 if ((vlan_id & HINIC3_VLAN_ID_MASK) >= VLAN_N_VID) { 181 dev_err(hwdev->dev, "Invalid VLAN number: %d\n", 182 (vlan_id & HINIC3_VLAN_ID_MASK)); 183 return -EINVAL; 184 } 185 186 mac_info.func_id = func_id; 187 mac_info.vlan_id = vlan_id; 188 ether_addr_copy(mac_info.mac, mac_addr); 189 190 mgmt_msg_params_init_default(&msg_params, &mac_info, sizeof(mac_info)); 191 192 err = hinic3_send_mbox_to_mgmt(hwdev, MGMT_MOD_L2NIC, 193 L2NIC_CMD_DEL_MAC, &msg_params); 194 if (err) { 195 dev_err(hwdev->dev, 196 "Failed to delete MAC, err: %d, status: 0x%x\n", 197 err, mac_info.msg_head.status); 198 return err; 199 } 200 201 return 0; 202 } 203 204 int hinic3_update_mac(struct hinic3_hwdev *hwdev, const u8 *old_mac, 205 u8 *new_mac, u16 vlan_id, u16 func_id) 206 { 207 struct l2nic_cmd_update_mac mac_info = {}; 208 struct mgmt_msg_params msg_params = {}; 209 int err; 210 211 if ((vlan_id & HINIC3_VLAN_ID_MASK) >= VLAN_N_VID) { 212 dev_err(hwdev->dev, "Invalid VLAN number: %d\n", 213 (vlan_id & HINIC3_VLAN_ID_MASK)); 214 return -EINVAL; 215 } 216 217 mac_info.func_id = func_id; 218 mac_info.vlan_id = vlan_id; 219 ether_addr_copy(mac_info.old_mac, old_mac); 220 ether_addr_copy(mac_info.new_mac, new_mac); 221 222 mgmt_msg_params_init_default(&msg_params, &mac_info, sizeof(mac_info)); 223 224 err = hinic3_send_mbox_to_mgmt(hwdev, MGMT_MOD_L2NIC, 225 L2NIC_CMD_UPDATE_MAC, &msg_params); 226 if (err || hinic3_check_mac_info(hwdev, mac_info.msg_head.status, 227 mac_info.vlan_id)) { 228 dev_err(hwdev->dev, 229 "Failed to update MAC, err: %d, status: 0x%x\n", 230 err, mac_info.msg_head.status); 231 return -EIO; 232 } 233 234 return 0; 235 } 236 237 int hinic3_set_ci_table(struct hinic3_hwdev *hwdev, struct hinic3_sq_attr *attr) 238 { 239 struct l2nic_cmd_set_ci_attr cons_idx_attr = {}; 240 struct mgmt_msg_params msg_params = {}; 241 int err; 242 243 cons_idx_attr.func_idx = hinic3_global_func_id(hwdev); 244 cons_idx_attr.dma_attr_off = attr->dma_attr_off; 245 cons_idx_attr.pending_limit = attr->pending_limit; 246 cons_idx_attr.coalescing_time = attr->coalescing_time; 247 248 if (attr->intr_en) { 249 cons_idx_attr.intr_en = attr->intr_en; 250 cons_idx_attr.intr_idx = attr->intr_idx; 251 } 252 253 cons_idx_attr.l2nic_sqn = attr->l2nic_sqn; 254 cons_idx_attr.ci_addr = attr->ci_dma_base; 255 256 mgmt_msg_params_init_default(&msg_params, &cons_idx_attr, 257 sizeof(cons_idx_attr)); 258 259 err = hinic3_send_mbox_to_mgmt(hwdev, MGMT_MOD_L2NIC, 260 L2NIC_CMD_SET_SQ_CI_ATTR, &msg_params); 261 if (err || cons_idx_attr.msg_head.status) { 262 dev_err(hwdev->dev, 263 "Failed to set ci attribute table, err: %d, status: 0x%x\n", 264 err, cons_idx_attr.msg_head.status); 265 return -EFAULT; 266 } 267 268 return 0; 269 } 270 271 int hinic3_flush_qps_res(struct hinic3_hwdev *hwdev) 272 { 273 struct l2nic_cmd_clear_qp_resource sq_res = {}; 274 struct mgmt_msg_params msg_params = {}; 275 int err; 276 277 sq_res.func_id = hinic3_global_func_id(hwdev); 278 279 mgmt_msg_params_init_default(&msg_params, &sq_res, sizeof(sq_res)); 280 281 err = hinic3_send_mbox_to_mgmt(hwdev, MGMT_MOD_L2NIC, 282 L2NIC_CMD_CLEAR_QP_RESOURCE, 283 &msg_params); 284 if (err || sq_res.msg_head.status) { 285 dev_err(hwdev->dev, "Failed to clear sq resources, err: %d, status: 0x%x\n", 286 err, sq_res.msg_head.status); 287 return -EINVAL; 288 } 289 290 return 0; 291 } 292 293 int hinic3_force_drop_tx_pkt(struct hinic3_hwdev *hwdev) 294 { 295 struct l2nic_cmd_force_pkt_drop pkt_drop = {}; 296 struct mgmt_msg_params msg_params = {}; 297 int err; 298 299 pkt_drop.port = hinic3_physical_port_id(hwdev); 300 301 mgmt_msg_params_init_default(&msg_params, &pkt_drop, sizeof(pkt_drop)); 302 303 err = hinic3_send_mbox_to_mgmt(hwdev, MGMT_MOD_L2NIC, 304 L2NIC_CMD_FORCE_PKT_DROP, &msg_params); 305 if ((pkt_drop.msg_head.status != MGMT_STATUS_CMD_UNSUPPORTED && 306 pkt_drop.msg_head.status) || err) { 307 dev_err(hwdev->dev, 308 "Failed to set force tx packets drop, err: %d, status: 0x%x\n", 309 err, pkt_drop.msg_head.status); 310 return -EFAULT; 311 } 312 313 return pkt_drop.msg_head.status; 314 } 315 316 int hinic3_sync_dcb_state(struct hinic3_hwdev *hwdev, u8 op_code, u8 state) 317 { 318 struct l2nic_cmd_set_dcb_state dcb_state = {}; 319 struct mgmt_msg_params msg_params = {}; 320 int err; 321 322 dcb_state.op_code = op_code; 323 dcb_state.state = state; 324 dcb_state.func_id = hinic3_global_func_id(hwdev); 325 326 mgmt_msg_params_init_default(&msg_params, &dcb_state, 327 sizeof(dcb_state)); 328 329 err = hinic3_send_mbox_to_mgmt(hwdev, MGMT_MOD_L2NIC, 330 L2NIC_CMD_QOS_DCB_STATE, &msg_params); 331 if (err || dcb_state.head.status) { 332 dev_err(hwdev->dev, 333 "Failed to set dcb state, err: %d, status: 0x%x\n", 334 err, dcb_state.head.status); 335 return -EFAULT; 336 } 337 338 return 0; 339 } 340 341 int hinic3_get_link_status(struct hinic3_hwdev *hwdev, bool *link_status_up) 342 { 343 struct mag_cmd_get_link_status get_link = {}; 344 struct mgmt_msg_params msg_params = {}; 345 int err; 346 347 get_link.port_id = hinic3_physical_port_id(hwdev); 348 349 mgmt_msg_params_init_default(&msg_params, &get_link, sizeof(get_link)); 350 351 err = hinic3_send_mbox_to_mgmt(hwdev, MGMT_MOD_HILINK, 352 MAG_CMD_GET_LINK_STATUS, &msg_params); 353 if (err || get_link.head.status) { 354 dev_err(hwdev->dev, "Failed to get link state, err: %d, status: 0x%x\n", 355 err, get_link.head.status); 356 return -EIO; 357 } 358 359 *link_status_up = !!get_link.status; 360 361 return 0; 362 } 363 364 int hinic3_set_vport_enable(struct hinic3_hwdev *hwdev, u16 func_id, 365 bool enable) 366 { 367 struct l2nic_cmd_set_vport_state en_state = {}; 368 struct mgmt_msg_params msg_params = {}; 369 int err; 370 371 en_state.func_id = func_id; 372 en_state.state = enable ? 1 : 0; 373 374 mgmt_msg_params_init_default(&msg_params, &en_state, sizeof(en_state)); 375 376 err = hinic3_send_mbox_to_mgmt(hwdev, MGMT_MOD_L2NIC, 377 L2NIC_CMD_SET_VPORT_ENABLE, &msg_params); 378 if (err || en_state.msg_head.status) { 379 dev_err(hwdev->dev, "Failed to set vport state, err: %d, status: 0x%x\n", 380 err, en_state.msg_head.status); 381 return -EINVAL; 382 } 383 384 return 0; 385 } 386