xref: /linux/drivers/net/ethernet/huawei/hinic3/hinic3_ethtool.c (revision 0fc8f6200d2313278fbf4539bbab74677c685531)
1*00608d02SFan Gong // SPDX-License-Identifier: GPL-2.0
2*00608d02SFan Gong // Copyright (c) Huawei Technologies Co., Ltd. 2026. All rights reserved.
3*00608d02SFan Gong 
4*00608d02SFan Gong #include <linux/kernel.h>
5*00608d02SFan Gong #include <linux/pci.h>
6*00608d02SFan Gong #include <linux/device.h>
7*00608d02SFan Gong #include <linux/module.h>
8*00608d02SFan Gong #include <linux/types.h>
9*00608d02SFan Gong #include <linux/errno.h>
10*00608d02SFan Gong #include <linux/etherdevice.h>
11*00608d02SFan Gong #include <linux/netdevice.h>
12*00608d02SFan Gong #include <linux/ethtool.h>
13*00608d02SFan Gong 
14*00608d02SFan Gong #include "hinic3_lld.h"
15*00608d02SFan Gong #include "hinic3_hw_comm.h"
16*00608d02SFan Gong #include "hinic3_nic_dev.h"
17*00608d02SFan Gong #include "hinic3_nic_cfg.h"
18*00608d02SFan Gong 
19*00608d02SFan Gong #define HINIC3_MGMT_VERSION_MAX_LEN     32
20*00608d02SFan Gong 
21*00608d02SFan Gong static void hinic3_get_drvinfo(struct net_device *netdev,
22*00608d02SFan Gong 			       struct ethtool_drvinfo *info)
23*00608d02SFan Gong {
24*00608d02SFan Gong 	struct hinic3_nic_dev *nic_dev = netdev_priv(netdev);
25*00608d02SFan Gong 	u8 mgmt_ver[HINIC3_MGMT_VERSION_MAX_LEN];
26*00608d02SFan Gong 	struct pci_dev *pdev = nic_dev->pdev;
27*00608d02SFan Gong 	int err;
28*00608d02SFan Gong 
29*00608d02SFan Gong 	strscpy(info->driver, HINIC3_NIC_DRV_NAME, sizeof(info->driver));
30*00608d02SFan Gong 	strscpy(info->bus_info, pci_name(pdev), sizeof(info->bus_info));
31*00608d02SFan Gong 
32*00608d02SFan Gong 	err = hinic3_get_mgmt_version(nic_dev->hwdev, mgmt_ver,
33*00608d02SFan Gong 				      HINIC3_MGMT_VERSION_MAX_LEN);
34*00608d02SFan Gong 	if (err) {
35*00608d02SFan Gong 		netdev_err(netdev, "Failed to get fw version\n");
36*00608d02SFan Gong 		return;
37*00608d02SFan Gong 	}
38*00608d02SFan Gong 
39*00608d02SFan Gong 	snprintf(info->fw_version, sizeof(info->fw_version), "%s", mgmt_ver);
40*00608d02SFan Gong }
41*00608d02SFan Gong 
42*00608d02SFan Gong static u32 hinic3_get_msglevel(struct net_device *netdev)
43*00608d02SFan Gong {
44*00608d02SFan Gong 	struct hinic3_nic_dev *nic_dev = netdev_priv(netdev);
45*00608d02SFan Gong 
46*00608d02SFan Gong 	return nic_dev->msg_enable;
47*00608d02SFan Gong }
48*00608d02SFan Gong 
49*00608d02SFan Gong static void hinic3_set_msglevel(struct net_device *netdev, u32 data)
50*00608d02SFan Gong {
51*00608d02SFan Gong 	struct hinic3_nic_dev *nic_dev = netdev_priv(netdev);
52*00608d02SFan Gong 
53*00608d02SFan Gong 	nic_dev->msg_enable = data;
54*00608d02SFan Gong 
55*00608d02SFan Gong 	netdev_dbg(netdev, "Set message level: 0x%x\n", data);
56*00608d02SFan Gong }
57*00608d02SFan Gong 
58*00608d02SFan Gong static const u32 hinic3_link_mode_ge[] = {
59*00608d02SFan Gong 	ETHTOOL_LINK_MODE_1000baseT_Full_BIT,
60*00608d02SFan Gong 	ETHTOOL_LINK_MODE_1000baseKX_Full_BIT,
61*00608d02SFan Gong 	ETHTOOL_LINK_MODE_1000baseX_Full_BIT,
62*00608d02SFan Gong };
63*00608d02SFan Gong 
64*00608d02SFan Gong static const u32 hinic3_link_mode_10ge_base_r[] = {
65*00608d02SFan Gong 	ETHTOOL_LINK_MODE_10000baseKR_Full_BIT,
66*00608d02SFan Gong 	ETHTOOL_LINK_MODE_10000baseR_FEC_BIT,
67*00608d02SFan Gong 	ETHTOOL_LINK_MODE_10000baseCR_Full_BIT,
68*00608d02SFan Gong 	ETHTOOL_LINK_MODE_10000baseSR_Full_BIT,
69*00608d02SFan Gong 	ETHTOOL_LINK_MODE_10000baseLR_Full_BIT,
70*00608d02SFan Gong 	ETHTOOL_LINK_MODE_10000baseLRM_Full_BIT,
71*00608d02SFan Gong };
72*00608d02SFan Gong 
73*00608d02SFan Gong static const u32 hinic3_link_mode_25ge_base_r[] = {
74*00608d02SFan Gong 	ETHTOOL_LINK_MODE_25000baseCR_Full_BIT,
75*00608d02SFan Gong 	ETHTOOL_LINK_MODE_25000baseKR_Full_BIT,
76*00608d02SFan Gong 	ETHTOOL_LINK_MODE_25000baseSR_Full_BIT,
77*00608d02SFan Gong };
78*00608d02SFan Gong 
79*00608d02SFan Gong static const u32 hinic3_link_mode_40ge_base_r4[] = {
80*00608d02SFan Gong 	ETHTOOL_LINK_MODE_40000baseKR4_Full_BIT,
81*00608d02SFan Gong 	ETHTOOL_LINK_MODE_40000baseCR4_Full_BIT,
82*00608d02SFan Gong 	ETHTOOL_LINK_MODE_40000baseSR4_Full_BIT,
83*00608d02SFan Gong 	ETHTOOL_LINK_MODE_40000baseLR4_Full_BIT,
84*00608d02SFan Gong };
85*00608d02SFan Gong 
86*00608d02SFan Gong static const u32 hinic3_link_mode_50ge_base_r[] = {
87*00608d02SFan Gong 	ETHTOOL_LINK_MODE_50000baseKR_Full_BIT,
88*00608d02SFan Gong 	ETHTOOL_LINK_MODE_50000baseSR_Full_BIT,
89*00608d02SFan Gong 	ETHTOOL_LINK_MODE_50000baseCR_Full_BIT,
90*00608d02SFan Gong };
91*00608d02SFan Gong 
92*00608d02SFan Gong static const u32 hinic3_link_mode_50ge_base_r2[] = {
93*00608d02SFan Gong 	ETHTOOL_LINK_MODE_50000baseCR2_Full_BIT,
94*00608d02SFan Gong 	ETHTOOL_LINK_MODE_50000baseKR2_Full_BIT,
95*00608d02SFan Gong 	ETHTOOL_LINK_MODE_50000baseSR2_Full_BIT,
96*00608d02SFan Gong };
97*00608d02SFan Gong 
98*00608d02SFan Gong static const u32 hinic3_link_mode_100ge_base_r[] = {
99*00608d02SFan Gong 	ETHTOOL_LINK_MODE_100000baseKR_Full_BIT,
100*00608d02SFan Gong 	ETHTOOL_LINK_MODE_100000baseSR_Full_BIT,
101*00608d02SFan Gong 	ETHTOOL_LINK_MODE_100000baseCR_Full_BIT,
102*00608d02SFan Gong };
103*00608d02SFan Gong 
104*00608d02SFan Gong static const u32 hinic3_link_mode_100ge_base_r2[] = {
105*00608d02SFan Gong 	ETHTOOL_LINK_MODE_100000baseKR2_Full_BIT,
106*00608d02SFan Gong 	ETHTOOL_LINK_MODE_100000baseSR2_Full_BIT,
107*00608d02SFan Gong 	ETHTOOL_LINK_MODE_100000baseCR2_Full_BIT,
108*00608d02SFan Gong };
109*00608d02SFan Gong 
110*00608d02SFan Gong static const u32 hinic3_link_mode_100ge_base_r4[] = {
111*00608d02SFan Gong 	ETHTOOL_LINK_MODE_100000baseKR4_Full_BIT,
112*00608d02SFan Gong 	ETHTOOL_LINK_MODE_100000baseSR4_Full_BIT,
113*00608d02SFan Gong 	ETHTOOL_LINK_MODE_100000baseCR4_Full_BIT,
114*00608d02SFan Gong 	ETHTOOL_LINK_MODE_100000baseLR4_ER4_Full_BIT,
115*00608d02SFan Gong };
116*00608d02SFan Gong 
117*00608d02SFan Gong static const u32 hinic3_link_mode_200ge_base_r2[] = {
118*00608d02SFan Gong 	ETHTOOL_LINK_MODE_200000baseKR2_Full_BIT,
119*00608d02SFan Gong 	ETHTOOL_LINK_MODE_200000baseSR2_Full_BIT,
120*00608d02SFan Gong 	ETHTOOL_LINK_MODE_200000baseCR2_Full_BIT,
121*00608d02SFan Gong };
122*00608d02SFan Gong 
123*00608d02SFan Gong static const u32 hinic3_link_mode_200ge_base_r4[] = {
124*00608d02SFan Gong 	ETHTOOL_LINK_MODE_200000baseKR4_Full_BIT,
125*00608d02SFan Gong 	ETHTOOL_LINK_MODE_200000baseSR4_Full_BIT,
126*00608d02SFan Gong 	ETHTOOL_LINK_MODE_200000baseCR4_Full_BIT,
127*00608d02SFan Gong };
128*00608d02SFan Gong 
129*00608d02SFan Gong struct hw2ethtool_link_mode {
130*00608d02SFan Gong 	const u32 *link_mode_bit_arr;
131*00608d02SFan Gong 	u32       arr_size;
132*00608d02SFan Gong 	u32       speed;
133*00608d02SFan Gong };
134*00608d02SFan Gong 
135*00608d02SFan Gong static const struct hw2ethtool_link_mode
136*00608d02SFan Gong 	hw2ethtool_link_mode_table[LINK_MODE_MAX_NUMBERS] = {
137*00608d02SFan Gong 	[LINK_MODE_GE] = {
138*00608d02SFan Gong 		.link_mode_bit_arr = hinic3_link_mode_ge,
139*00608d02SFan Gong 		.arr_size          = ARRAY_SIZE(hinic3_link_mode_ge),
140*00608d02SFan Gong 		.speed             = SPEED_1000,
141*00608d02SFan Gong 	},
142*00608d02SFan Gong 	[LINK_MODE_10GE_BASE_R] = {
143*00608d02SFan Gong 		.link_mode_bit_arr = hinic3_link_mode_10ge_base_r,
144*00608d02SFan Gong 		.arr_size          = ARRAY_SIZE(hinic3_link_mode_10ge_base_r),
145*00608d02SFan Gong 		.speed             = SPEED_10000,
146*00608d02SFan Gong 	},
147*00608d02SFan Gong 	[LINK_MODE_25GE_BASE_R] = {
148*00608d02SFan Gong 		.link_mode_bit_arr = hinic3_link_mode_25ge_base_r,
149*00608d02SFan Gong 		.arr_size          = ARRAY_SIZE(hinic3_link_mode_25ge_base_r),
150*00608d02SFan Gong 		.speed             = SPEED_25000,
151*00608d02SFan Gong 	},
152*00608d02SFan Gong 	[LINK_MODE_40GE_BASE_R4] = {
153*00608d02SFan Gong 		.link_mode_bit_arr = hinic3_link_mode_40ge_base_r4,
154*00608d02SFan Gong 		.arr_size          = ARRAY_SIZE(hinic3_link_mode_40ge_base_r4),
155*00608d02SFan Gong 		.speed             = SPEED_40000,
156*00608d02SFan Gong 	},
157*00608d02SFan Gong 	[LINK_MODE_50GE_BASE_R] = {
158*00608d02SFan Gong 		.link_mode_bit_arr = hinic3_link_mode_50ge_base_r,
159*00608d02SFan Gong 		.arr_size          = ARRAY_SIZE(hinic3_link_mode_50ge_base_r),
160*00608d02SFan Gong 		.speed             = SPEED_50000,
161*00608d02SFan Gong 	},
162*00608d02SFan Gong 	[LINK_MODE_50GE_BASE_R2] = {
163*00608d02SFan Gong 		.link_mode_bit_arr = hinic3_link_mode_50ge_base_r2,
164*00608d02SFan Gong 		.arr_size          = ARRAY_SIZE(hinic3_link_mode_50ge_base_r2),
165*00608d02SFan Gong 		.speed             = SPEED_50000,
166*00608d02SFan Gong 	},
167*00608d02SFan Gong 	[LINK_MODE_100GE_BASE_R] = {
168*00608d02SFan Gong 		.link_mode_bit_arr = hinic3_link_mode_100ge_base_r,
169*00608d02SFan Gong 		.arr_size          = ARRAY_SIZE(hinic3_link_mode_100ge_base_r),
170*00608d02SFan Gong 		.speed             = SPEED_100000,
171*00608d02SFan Gong 	},
172*00608d02SFan Gong 	[LINK_MODE_100GE_BASE_R2] = {
173*00608d02SFan Gong 		.link_mode_bit_arr = hinic3_link_mode_100ge_base_r2,
174*00608d02SFan Gong 		.arr_size          = ARRAY_SIZE(hinic3_link_mode_100ge_base_r2),
175*00608d02SFan Gong 		.speed             = SPEED_100000,
176*00608d02SFan Gong 	},
177*00608d02SFan Gong 	[LINK_MODE_100GE_BASE_R4] = {
178*00608d02SFan Gong 		.link_mode_bit_arr = hinic3_link_mode_100ge_base_r4,
179*00608d02SFan Gong 		.arr_size          = ARRAY_SIZE(hinic3_link_mode_100ge_base_r4),
180*00608d02SFan Gong 		.speed             = SPEED_100000,
181*00608d02SFan Gong 	},
182*00608d02SFan Gong 	[LINK_MODE_200GE_BASE_R2] = {
183*00608d02SFan Gong 		.link_mode_bit_arr = hinic3_link_mode_200ge_base_r2,
184*00608d02SFan Gong 		.arr_size          = ARRAY_SIZE(hinic3_link_mode_200ge_base_r2),
185*00608d02SFan Gong 		.speed             = SPEED_200000,
186*00608d02SFan Gong 	},
187*00608d02SFan Gong 	[LINK_MODE_200GE_BASE_R4] = {
188*00608d02SFan Gong 		.link_mode_bit_arr = hinic3_link_mode_200ge_base_r4,
189*00608d02SFan Gong 		.arr_size          = ARRAY_SIZE(hinic3_link_mode_200ge_base_r4),
190*00608d02SFan Gong 		.speed             = SPEED_200000,
191*00608d02SFan Gong 	},
192*00608d02SFan Gong };
193*00608d02SFan Gong 
194*00608d02SFan Gong #define GET_SUPPORTED_MODE     0
195*00608d02SFan Gong #define GET_ADVERTISED_MODE    1
196*00608d02SFan Gong 
197*00608d02SFan Gong struct hinic3_link_settings {
198*00608d02SFan Gong 	__ETHTOOL_DECLARE_LINK_MODE_MASK(supported);
199*00608d02SFan Gong 	__ETHTOOL_DECLARE_LINK_MODE_MASK(advertising);
200*00608d02SFan Gong 
201*00608d02SFan Gong 	u32 speed;
202*00608d02SFan Gong 	u8  duplex;
203*00608d02SFan Gong 	u8  port;
204*00608d02SFan Gong 	u8  autoneg;
205*00608d02SFan Gong };
206*00608d02SFan Gong 
207*00608d02SFan Gong #define HINIC3_ADD_SUPPORTED_LINK_MODE(ecmd, mode) \
208*00608d02SFan Gong 	set_bit(ETHTOOL_LINK_##mode##_BIT, (ecmd)->supported)
209*00608d02SFan Gong #define HINIC3_ADD_ADVERTISED_LINK_MODE(ecmd, mode) \
210*00608d02SFan Gong 	set_bit(ETHTOOL_LINK_##mode##_BIT, (ecmd)->advertising)
211*00608d02SFan Gong 
212*00608d02SFan Gong static void hinic3_add_speed_link_mode(unsigned long *bitmap, u32 mode)
213*00608d02SFan Gong {
214*00608d02SFan Gong 	u32 i;
215*00608d02SFan Gong 
216*00608d02SFan Gong 	for (i = 0; i < hw2ethtool_link_mode_table[mode].arr_size; i++) {
217*00608d02SFan Gong 		if (hw2ethtool_link_mode_table[mode].link_mode_bit_arr[i] >=
218*00608d02SFan Gong 		    __ETHTOOL_LINK_MODE_MASK_NBITS)
219*00608d02SFan Gong 			continue;
220*00608d02SFan Gong 
221*00608d02SFan Gong 		set_bit(hw2ethtool_link_mode_table[mode].link_mode_bit_arr[i],
222*00608d02SFan Gong 			bitmap);
223*00608d02SFan Gong 	}
224*00608d02SFan Gong }
225*00608d02SFan Gong 
226*00608d02SFan Gong /* Related to enum mag_cmd_port_speed */
227*00608d02SFan Gong static const u32 hw_to_ethtool_speed[] = {
228*00608d02SFan Gong 	(u32)SPEED_UNKNOWN, SPEED_10,    SPEED_100,   SPEED_1000,   SPEED_10000,
229*00608d02SFan Gong 	SPEED_25000,        SPEED_40000, SPEED_50000, SPEED_100000, SPEED_200000
230*00608d02SFan Gong };
231*00608d02SFan Gong 
232*00608d02SFan Gong static void
233*00608d02SFan Gong hinic3_add_ethtool_link_mode(struct hinic3_link_settings *link_settings,
234*00608d02SFan Gong 			     u32 hw_link_mode, u32 name)
235*00608d02SFan Gong {
236*00608d02SFan Gong 	unsigned long *advertising_mask = link_settings->advertising;
237*00608d02SFan Gong 	unsigned long *supported_mask = link_settings->supported;
238*00608d02SFan Gong 	u32 link_mode;
239*00608d02SFan Gong 
240*00608d02SFan Gong 	for (link_mode = 0; link_mode < LINK_MODE_MAX_NUMBERS; link_mode++) {
241*00608d02SFan Gong 		if (hw_link_mode & BIT(link_mode)) {
242*00608d02SFan Gong 			if (name == GET_SUPPORTED_MODE)
243*00608d02SFan Gong 				hinic3_add_speed_link_mode(supported_mask,
244*00608d02SFan Gong 							   link_mode);
245*00608d02SFan Gong 			else
246*00608d02SFan Gong 				hinic3_add_speed_link_mode(advertising_mask,
247*00608d02SFan Gong 							   link_mode);
248*00608d02SFan Gong 		}
249*00608d02SFan Gong 	}
250*00608d02SFan Gong }
251*00608d02SFan Gong 
252*00608d02SFan Gong static void
253*00608d02SFan Gong hinic3_link_speed_set(struct net_device *netdev,
254*00608d02SFan Gong 		      struct hinic3_link_settings *link_settings,
255*00608d02SFan Gong 		      struct hinic3_nic_port_info *port_info)
256*00608d02SFan Gong {
257*00608d02SFan Gong 	struct hinic3_nic_dev *nic_dev = netdev_priv(netdev);
258*00608d02SFan Gong 	bool link_status_up;
259*00608d02SFan Gong 	int err;
260*00608d02SFan Gong 
261*00608d02SFan Gong 	if (port_info->supported_mode != LINK_MODE_UNKNOWN)
262*00608d02SFan Gong 		hinic3_add_ethtool_link_mode(link_settings,
263*00608d02SFan Gong 					     port_info->supported_mode,
264*00608d02SFan Gong 					     GET_SUPPORTED_MODE);
265*00608d02SFan Gong 	if (port_info->advertised_mode != LINK_MODE_UNKNOWN)
266*00608d02SFan Gong 		hinic3_add_ethtool_link_mode(link_settings,
267*00608d02SFan Gong 					     port_info->advertised_mode,
268*00608d02SFan Gong 					     GET_ADVERTISED_MODE);
269*00608d02SFan Gong 
270*00608d02SFan Gong 	err = hinic3_get_link_status(nic_dev->hwdev, &link_status_up);
271*00608d02SFan Gong 	if (!err && link_status_up) {
272*00608d02SFan Gong 		link_settings->speed =
273*00608d02SFan Gong 			port_info->speed < ARRAY_SIZE(hw_to_ethtool_speed) ?
274*00608d02SFan Gong 			hw_to_ethtool_speed[port_info->speed] :
275*00608d02SFan Gong 			(u32)SPEED_UNKNOWN;
276*00608d02SFan Gong 
277*00608d02SFan Gong 		link_settings->duplex = port_info->duplex;
278*00608d02SFan Gong 	} else {
279*00608d02SFan Gong 		link_settings->speed = (u32)SPEED_UNKNOWN;
280*00608d02SFan Gong 		link_settings->duplex = DUPLEX_UNKNOWN;
281*00608d02SFan Gong 	}
282*00608d02SFan Gong }
283*00608d02SFan Gong 
284*00608d02SFan Gong static void
285*00608d02SFan Gong hinic3_link_port_type_set(struct hinic3_link_settings *link_settings,
286*00608d02SFan Gong 			  u8 port_type)
287*00608d02SFan Gong {
288*00608d02SFan Gong 	switch (port_type) {
289*00608d02SFan Gong 	case MAG_CMD_WIRE_TYPE_ELECTRIC:
290*00608d02SFan Gong 		HINIC3_ADD_SUPPORTED_LINK_MODE(link_settings, MODE_TP);
291*00608d02SFan Gong 		HINIC3_ADD_ADVERTISED_LINK_MODE(link_settings, MODE_TP);
292*00608d02SFan Gong 		link_settings->port = PORT_TP;
293*00608d02SFan Gong 		break;
294*00608d02SFan Gong 
295*00608d02SFan Gong 	case MAG_CMD_WIRE_TYPE_AOC:
296*00608d02SFan Gong 	case MAG_CMD_WIRE_TYPE_MM:
297*00608d02SFan Gong 	case MAG_CMD_WIRE_TYPE_SM:
298*00608d02SFan Gong 		HINIC3_ADD_SUPPORTED_LINK_MODE(link_settings, MODE_FIBRE);
299*00608d02SFan Gong 		HINIC3_ADD_ADVERTISED_LINK_MODE(link_settings, MODE_FIBRE);
300*00608d02SFan Gong 		link_settings->port = PORT_FIBRE;
301*00608d02SFan Gong 		break;
302*00608d02SFan Gong 
303*00608d02SFan Gong 	case MAG_CMD_WIRE_TYPE_COPPER:
304*00608d02SFan Gong 		HINIC3_ADD_SUPPORTED_LINK_MODE(link_settings, MODE_FIBRE);
305*00608d02SFan Gong 		HINIC3_ADD_ADVERTISED_LINK_MODE(link_settings, MODE_FIBRE);
306*00608d02SFan Gong 		link_settings->port = PORT_DA;
307*00608d02SFan Gong 		break;
308*00608d02SFan Gong 
309*00608d02SFan Gong 	case MAG_CMD_WIRE_TYPE_BACKPLANE:
310*00608d02SFan Gong 		HINIC3_ADD_SUPPORTED_LINK_MODE(link_settings, MODE_Backplane);
311*00608d02SFan Gong 		HINIC3_ADD_ADVERTISED_LINK_MODE(link_settings, MODE_Backplane);
312*00608d02SFan Gong 		link_settings->port = PORT_NONE;
313*00608d02SFan Gong 		break;
314*00608d02SFan Gong 
315*00608d02SFan Gong 	default:
316*00608d02SFan Gong 		link_settings->port = PORT_OTHER;
317*00608d02SFan Gong 		break;
318*00608d02SFan Gong 	}
319*00608d02SFan Gong }
320*00608d02SFan Gong 
321*00608d02SFan Gong static int
322*00608d02SFan Gong hinic3_get_link_pause_settings(struct net_device *netdev,
323*00608d02SFan Gong 			       struct hinic3_link_settings *link_settings)
324*00608d02SFan Gong {
325*00608d02SFan Gong 	struct hinic3_nic_dev *nic_dev = netdev_priv(netdev);
326*00608d02SFan Gong 	struct hinic3_nic_pause_config nic_pause = {};
327*00608d02SFan Gong 	int err;
328*00608d02SFan Gong 
329*00608d02SFan Gong 	err = hinic3_get_pause_info(nic_dev, &nic_pause);
330*00608d02SFan Gong 	if (err) {
331*00608d02SFan Gong 		netdev_err(netdev, "Failed to get pause param from hw\n");
332*00608d02SFan Gong 		return err;
333*00608d02SFan Gong 	}
334*00608d02SFan Gong 
335*00608d02SFan Gong 	HINIC3_ADD_SUPPORTED_LINK_MODE(link_settings, MODE_Pause);
336*00608d02SFan Gong 	if (nic_pause.rx_pause && nic_pause.tx_pause) {
337*00608d02SFan Gong 		HINIC3_ADD_ADVERTISED_LINK_MODE(link_settings, MODE_Pause);
338*00608d02SFan Gong 	} else if (nic_pause.tx_pause) {
339*00608d02SFan Gong 		HINIC3_ADD_ADVERTISED_LINK_MODE(link_settings,
340*00608d02SFan Gong 						MODE_Asym_Pause);
341*00608d02SFan Gong 	} else if (nic_pause.rx_pause) {
342*00608d02SFan Gong 		HINIC3_ADD_ADVERTISED_LINK_MODE(link_settings, MODE_Pause);
343*00608d02SFan Gong 		HINIC3_ADD_ADVERTISED_LINK_MODE(link_settings,
344*00608d02SFan Gong 						MODE_Asym_Pause);
345*00608d02SFan Gong 	}
346*00608d02SFan Gong 
347*00608d02SFan Gong 	return 0;
348*00608d02SFan Gong }
349*00608d02SFan Gong 
350*00608d02SFan Gong static int
351*00608d02SFan Gong hinic3_get_link_settings(struct net_device *netdev,
352*00608d02SFan Gong 			 struct hinic3_link_settings *link_settings)
353*00608d02SFan Gong {
354*00608d02SFan Gong 	struct hinic3_nic_dev *nic_dev = netdev_priv(netdev);
355*00608d02SFan Gong 	struct hinic3_nic_port_info port_info = {};
356*00608d02SFan Gong 	int err;
357*00608d02SFan Gong 
358*00608d02SFan Gong 	err = hinic3_get_port_info(nic_dev->hwdev, &port_info);
359*00608d02SFan Gong 	if (err) {
360*00608d02SFan Gong 		netdev_err(netdev, "Failed to get port info\n");
361*00608d02SFan Gong 		return err;
362*00608d02SFan Gong 	}
363*00608d02SFan Gong 
364*00608d02SFan Gong 	hinic3_link_speed_set(netdev, link_settings, &port_info);
365*00608d02SFan Gong 
366*00608d02SFan Gong 	hinic3_link_port_type_set(link_settings, port_info.port_type);
367*00608d02SFan Gong 
368*00608d02SFan Gong 	link_settings->autoneg = port_info.autoneg_state == PORT_CFG_AN_ON ?
369*00608d02SFan Gong 				 AUTONEG_ENABLE : AUTONEG_DISABLE;
370*00608d02SFan Gong 	if (port_info.autoneg_cap)
371*00608d02SFan Gong 		HINIC3_ADD_SUPPORTED_LINK_MODE(link_settings, MODE_Autoneg);
372*00608d02SFan Gong 	if (port_info.autoneg_state == PORT_CFG_AN_ON)
373*00608d02SFan Gong 		HINIC3_ADD_ADVERTISED_LINK_MODE(link_settings, MODE_Autoneg);
374*00608d02SFan Gong 
375*00608d02SFan Gong 	if (!HINIC3_IS_VF(nic_dev->hwdev)) {
376*00608d02SFan Gong 		err = hinic3_get_link_pause_settings(netdev, link_settings);
377*00608d02SFan Gong 		if (err)
378*00608d02SFan Gong 			return err;
379*00608d02SFan Gong 	}
380*00608d02SFan Gong 
381*00608d02SFan Gong 	return 0;
382*00608d02SFan Gong }
383*00608d02SFan Gong 
384*00608d02SFan Gong static int
385*00608d02SFan Gong hinic3_get_link_ksettings(struct net_device *netdev,
386*00608d02SFan Gong 			  struct ethtool_link_ksettings *link_settings)
387*00608d02SFan Gong {
388*00608d02SFan Gong 	struct ethtool_link_settings *base = &link_settings->base;
389*00608d02SFan Gong 	struct hinic3_link_settings settings = {};
390*00608d02SFan Gong 	int err;
391*00608d02SFan Gong 
392*00608d02SFan Gong 	ethtool_link_ksettings_zero_link_mode(link_settings, supported);
393*00608d02SFan Gong 	ethtool_link_ksettings_zero_link_mode(link_settings, advertising);
394*00608d02SFan Gong 
395*00608d02SFan Gong 	err = hinic3_get_link_settings(netdev, &settings);
396*00608d02SFan Gong 	if (err)
397*00608d02SFan Gong 		return err;
398*00608d02SFan Gong 
399*00608d02SFan Gong 	bitmap_copy(link_settings->link_modes.supported, settings.supported,
400*00608d02SFan Gong 		    __ETHTOOL_LINK_MODE_MASK_NBITS);
401*00608d02SFan Gong 	bitmap_copy(link_settings->link_modes.advertising, settings.advertising,
402*00608d02SFan Gong 		    __ETHTOOL_LINK_MODE_MASK_NBITS);
403*00608d02SFan Gong 
404*00608d02SFan Gong 	base->autoneg = settings.autoneg;
405*00608d02SFan Gong 	base->speed = settings.speed;
406*00608d02SFan Gong 	base->duplex = settings.duplex;
407*00608d02SFan Gong 	base->port = settings.port;
408*00608d02SFan Gong 
409*00608d02SFan Gong 	return 0;
410*00608d02SFan Gong }
411*00608d02SFan Gong 
412*00608d02SFan Gong static const struct ethtool_ops hinic3_ethtool_ops = {
413*00608d02SFan Gong 	.supported_coalesce_params      = ETHTOOL_COALESCE_USECS |
414*00608d02SFan Gong 					  ETHTOOL_COALESCE_PKT_RATE_RX_USECS,
415*00608d02SFan Gong 	.get_link_ksettings             = hinic3_get_link_ksettings,
416*00608d02SFan Gong 	.get_drvinfo                    = hinic3_get_drvinfo,
417*00608d02SFan Gong 	.get_msglevel                   = hinic3_get_msglevel,
418*00608d02SFan Gong 	.set_msglevel                   = hinic3_set_msglevel,
419*00608d02SFan Gong 	.get_link                       = ethtool_op_get_link,
420*00608d02SFan Gong };
421*00608d02SFan Gong 
422*00608d02SFan Gong void hinic3_set_ethtool_ops(struct net_device *netdev)
423*00608d02SFan Gong {
424*00608d02SFan Gong 	netdev->ethtool_ops = &hinic3_ethtool_ops;
425*00608d02SFan Gong }
426