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