xref: /linux/drivers/net/ethernet/huawei/hinic3/hinic3_nic_cfg.c (revision ab93e0dd72c37d378dd936f031ffb83ff2bd87ce)
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