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