18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0 28c2ecf20Sopenharmony_ci/* Copyright (c) 2019-2020 Marvell International Ltd. All rights reserved */ 38c2ecf20Sopenharmony_ci 48c2ecf20Sopenharmony_ci#include <linux/ethtool.h> 58c2ecf20Sopenharmony_ci#include <linux/kernel.h> 68c2ecf20Sopenharmony_ci#include <linux/netdevice.h> 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci#include "prestera_ethtool.h" 98c2ecf20Sopenharmony_ci#include "prestera.h" 108c2ecf20Sopenharmony_ci#include "prestera_hw.h" 118c2ecf20Sopenharmony_ci 128c2ecf20Sopenharmony_ci#define PRESTERA_STATS_CNT \ 138c2ecf20Sopenharmony_ci (sizeof(struct prestera_port_stats) / sizeof(u64)) 148c2ecf20Sopenharmony_ci#define PRESTERA_STATS_IDX(name) \ 158c2ecf20Sopenharmony_ci (offsetof(struct prestera_port_stats, name) / sizeof(u64)) 168c2ecf20Sopenharmony_ci#define PRESTERA_STATS_FIELD(name) \ 178c2ecf20Sopenharmony_ci [PRESTERA_STATS_IDX(name)] = __stringify(name) 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_cistatic const char driver_kind[] = "prestera"; 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_cistatic const struct prestera_link_mode { 228c2ecf20Sopenharmony_ci enum ethtool_link_mode_bit_indices eth_mode; 238c2ecf20Sopenharmony_ci u32 speed; 248c2ecf20Sopenharmony_ci u64 pr_mask; 258c2ecf20Sopenharmony_ci u8 duplex; 268c2ecf20Sopenharmony_ci u8 port_type; 278c2ecf20Sopenharmony_ci} port_link_modes[PRESTERA_LINK_MODE_MAX] = { 288c2ecf20Sopenharmony_ci [PRESTERA_LINK_MODE_10baseT_Half] = { 298c2ecf20Sopenharmony_ci .eth_mode = ETHTOOL_LINK_MODE_10baseT_Half_BIT, 308c2ecf20Sopenharmony_ci .speed = 10, 318c2ecf20Sopenharmony_ci .pr_mask = 1 << PRESTERA_LINK_MODE_10baseT_Half, 328c2ecf20Sopenharmony_ci .duplex = PRESTERA_PORT_DUPLEX_HALF, 338c2ecf20Sopenharmony_ci .port_type = PRESTERA_PORT_TYPE_TP, 348c2ecf20Sopenharmony_ci }, 358c2ecf20Sopenharmony_ci [PRESTERA_LINK_MODE_10baseT_Full] = { 368c2ecf20Sopenharmony_ci .eth_mode = ETHTOOL_LINK_MODE_10baseT_Full_BIT, 378c2ecf20Sopenharmony_ci .speed = 10, 388c2ecf20Sopenharmony_ci .pr_mask = 1 << PRESTERA_LINK_MODE_10baseT_Full, 398c2ecf20Sopenharmony_ci .duplex = PRESTERA_PORT_DUPLEX_FULL, 408c2ecf20Sopenharmony_ci .port_type = PRESTERA_PORT_TYPE_TP, 418c2ecf20Sopenharmony_ci }, 428c2ecf20Sopenharmony_ci [PRESTERA_LINK_MODE_100baseT_Half] = { 438c2ecf20Sopenharmony_ci .eth_mode = ETHTOOL_LINK_MODE_100baseT_Half_BIT, 448c2ecf20Sopenharmony_ci .speed = 100, 458c2ecf20Sopenharmony_ci .pr_mask = 1 << PRESTERA_LINK_MODE_100baseT_Half, 468c2ecf20Sopenharmony_ci .duplex = PRESTERA_PORT_DUPLEX_HALF, 478c2ecf20Sopenharmony_ci .port_type = PRESTERA_PORT_TYPE_TP, 488c2ecf20Sopenharmony_ci }, 498c2ecf20Sopenharmony_ci [PRESTERA_LINK_MODE_100baseT_Full] = { 508c2ecf20Sopenharmony_ci .eth_mode = ETHTOOL_LINK_MODE_100baseT_Full_BIT, 518c2ecf20Sopenharmony_ci .speed = 100, 528c2ecf20Sopenharmony_ci .pr_mask = 1 << PRESTERA_LINK_MODE_100baseT_Full, 538c2ecf20Sopenharmony_ci .duplex = PRESTERA_PORT_DUPLEX_FULL, 548c2ecf20Sopenharmony_ci .port_type = PRESTERA_PORT_TYPE_TP, 558c2ecf20Sopenharmony_ci }, 568c2ecf20Sopenharmony_ci [PRESTERA_LINK_MODE_1000baseT_Half] = { 578c2ecf20Sopenharmony_ci .eth_mode = ETHTOOL_LINK_MODE_1000baseT_Half_BIT, 588c2ecf20Sopenharmony_ci .speed = 1000, 598c2ecf20Sopenharmony_ci .pr_mask = 1 << PRESTERA_LINK_MODE_1000baseT_Half, 608c2ecf20Sopenharmony_ci .duplex = PRESTERA_PORT_DUPLEX_HALF, 618c2ecf20Sopenharmony_ci .port_type = PRESTERA_PORT_TYPE_TP, 628c2ecf20Sopenharmony_ci }, 638c2ecf20Sopenharmony_ci [PRESTERA_LINK_MODE_1000baseT_Full] = { 648c2ecf20Sopenharmony_ci .eth_mode = ETHTOOL_LINK_MODE_1000baseT_Full_BIT, 658c2ecf20Sopenharmony_ci .speed = 1000, 668c2ecf20Sopenharmony_ci .pr_mask = 1 << PRESTERA_LINK_MODE_1000baseT_Full, 678c2ecf20Sopenharmony_ci .duplex = PRESTERA_PORT_DUPLEX_FULL, 688c2ecf20Sopenharmony_ci .port_type = PRESTERA_PORT_TYPE_TP, 698c2ecf20Sopenharmony_ci }, 708c2ecf20Sopenharmony_ci [PRESTERA_LINK_MODE_1000baseX_Full] = { 718c2ecf20Sopenharmony_ci .eth_mode = ETHTOOL_LINK_MODE_1000baseX_Full_BIT, 728c2ecf20Sopenharmony_ci .speed = 1000, 738c2ecf20Sopenharmony_ci .pr_mask = 1 << PRESTERA_LINK_MODE_1000baseX_Full, 748c2ecf20Sopenharmony_ci .duplex = PRESTERA_PORT_DUPLEX_FULL, 758c2ecf20Sopenharmony_ci .port_type = PRESTERA_PORT_TYPE_FIBRE, 768c2ecf20Sopenharmony_ci }, 778c2ecf20Sopenharmony_ci [PRESTERA_LINK_MODE_1000baseKX_Full] = { 788c2ecf20Sopenharmony_ci .eth_mode = ETHTOOL_LINK_MODE_1000baseKX_Full_BIT, 798c2ecf20Sopenharmony_ci .speed = 1000, 808c2ecf20Sopenharmony_ci .pr_mask = 1 << PRESTERA_LINK_MODE_1000baseKX_Full, 818c2ecf20Sopenharmony_ci .duplex = PRESTERA_PORT_DUPLEX_FULL, 828c2ecf20Sopenharmony_ci .port_type = PRESTERA_PORT_TYPE_TP, 838c2ecf20Sopenharmony_ci }, 848c2ecf20Sopenharmony_ci [PRESTERA_LINK_MODE_2500baseX_Full] = { 858c2ecf20Sopenharmony_ci .eth_mode = ETHTOOL_LINK_MODE_2500baseX_Full_BIT, 868c2ecf20Sopenharmony_ci .speed = 2500, 878c2ecf20Sopenharmony_ci .pr_mask = 1 << PRESTERA_LINK_MODE_2500baseX_Full, 888c2ecf20Sopenharmony_ci .duplex = PRESTERA_PORT_DUPLEX_FULL, 898c2ecf20Sopenharmony_ci }, 908c2ecf20Sopenharmony_ci [PRESTERA_LINK_MODE_10GbaseKR_Full] = { 918c2ecf20Sopenharmony_ci .eth_mode = ETHTOOL_LINK_MODE_10000baseKR_Full_BIT, 928c2ecf20Sopenharmony_ci .speed = 10000, 938c2ecf20Sopenharmony_ci .pr_mask = 1 << PRESTERA_LINK_MODE_10GbaseKR_Full, 948c2ecf20Sopenharmony_ci .duplex = PRESTERA_PORT_DUPLEX_FULL, 958c2ecf20Sopenharmony_ci .port_type = PRESTERA_PORT_TYPE_TP, 968c2ecf20Sopenharmony_ci }, 978c2ecf20Sopenharmony_ci [PRESTERA_LINK_MODE_10GbaseSR_Full] = { 988c2ecf20Sopenharmony_ci .eth_mode = ETHTOOL_LINK_MODE_10000baseSR_Full_BIT, 998c2ecf20Sopenharmony_ci .speed = 10000, 1008c2ecf20Sopenharmony_ci .pr_mask = 1 << PRESTERA_LINK_MODE_10GbaseSR_Full, 1018c2ecf20Sopenharmony_ci .duplex = PRESTERA_PORT_DUPLEX_FULL, 1028c2ecf20Sopenharmony_ci .port_type = PRESTERA_PORT_TYPE_FIBRE, 1038c2ecf20Sopenharmony_ci }, 1048c2ecf20Sopenharmony_ci [PRESTERA_LINK_MODE_10GbaseLR_Full] = { 1058c2ecf20Sopenharmony_ci .eth_mode = ETHTOOL_LINK_MODE_10000baseLR_Full_BIT, 1068c2ecf20Sopenharmony_ci .speed = 10000, 1078c2ecf20Sopenharmony_ci .pr_mask = 1 << PRESTERA_LINK_MODE_10GbaseLR_Full, 1088c2ecf20Sopenharmony_ci .duplex = PRESTERA_PORT_DUPLEX_FULL, 1098c2ecf20Sopenharmony_ci .port_type = PRESTERA_PORT_TYPE_FIBRE, 1108c2ecf20Sopenharmony_ci }, 1118c2ecf20Sopenharmony_ci [PRESTERA_LINK_MODE_20GbaseKR2_Full] = { 1128c2ecf20Sopenharmony_ci .eth_mode = ETHTOOL_LINK_MODE_20000baseKR2_Full_BIT, 1138c2ecf20Sopenharmony_ci .speed = 20000, 1148c2ecf20Sopenharmony_ci .pr_mask = 1 << PRESTERA_LINK_MODE_20GbaseKR2_Full, 1158c2ecf20Sopenharmony_ci .duplex = PRESTERA_PORT_DUPLEX_FULL, 1168c2ecf20Sopenharmony_ci .port_type = PRESTERA_PORT_TYPE_TP, 1178c2ecf20Sopenharmony_ci }, 1188c2ecf20Sopenharmony_ci [PRESTERA_LINK_MODE_25GbaseCR_Full] = { 1198c2ecf20Sopenharmony_ci .eth_mode = ETHTOOL_LINK_MODE_25000baseCR_Full_BIT, 1208c2ecf20Sopenharmony_ci .speed = 25000, 1218c2ecf20Sopenharmony_ci .pr_mask = 1 << PRESTERA_LINK_MODE_25GbaseCR_Full, 1228c2ecf20Sopenharmony_ci .duplex = PRESTERA_PORT_DUPLEX_FULL, 1238c2ecf20Sopenharmony_ci .port_type = PRESTERA_PORT_TYPE_DA, 1248c2ecf20Sopenharmony_ci }, 1258c2ecf20Sopenharmony_ci [PRESTERA_LINK_MODE_25GbaseKR_Full] = { 1268c2ecf20Sopenharmony_ci .eth_mode = ETHTOOL_LINK_MODE_25000baseKR_Full_BIT, 1278c2ecf20Sopenharmony_ci .speed = 25000, 1288c2ecf20Sopenharmony_ci .pr_mask = 1 << PRESTERA_LINK_MODE_25GbaseKR_Full, 1298c2ecf20Sopenharmony_ci .duplex = PRESTERA_PORT_DUPLEX_FULL, 1308c2ecf20Sopenharmony_ci .port_type = PRESTERA_PORT_TYPE_TP, 1318c2ecf20Sopenharmony_ci }, 1328c2ecf20Sopenharmony_ci [PRESTERA_LINK_MODE_25GbaseSR_Full] = { 1338c2ecf20Sopenharmony_ci .eth_mode = ETHTOOL_LINK_MODE_25000baseSR_Full_BIT, 1348c2ecf20Sopenharmony_ci .speed = 25000, 1358c2ecf20Sopenharmony_ci .pr_mask = 1 << PRESTERA_LINK_MODE_25GbaseSR_Full, 1368c2ecf20Sopenharmony_ci .duplex = PRESTERA_PORT_DUPLEX_FULL, 1378c2ecf20Sopenharmony_ci .port_type = PRESTERA_PORT_TYPE_FIBRE, 1388c2ecf20Sopenharmony_ci }, 1398c2ecf20Sopenharmony_ci [PRESTERA_LINK_MODE_40GbaseKR4_Full] = { 1408c2ecf20Sopenharmony_ci .eth_mode = ETHTOOL_LINK_MODE_40000baseKR4_Full_BIT, 1418c2ecf20Sopenharmony_ci .speed = 40000, 1428c2ecf20Sopenharmony_ci .pr_mask = 1 << PRESTERA_LINK_MODE_40GbaseKR4_Full, 1438c2ecf20Sopenharmony_ci .duplex = PRESTERA_PORT_DUPLEX_FULL, 1448c2ecf20Sopenharmony_ci .port_type = PRESTERA_PORT_TYPE_TP, 1458c2ecf20Sopenharmony_ci }, 1468c2ecf20Sopenharmony_ci [PRESTERA_LINK_MODE_40GbaseCR4_Full] = { 1478c2ecf20Sopenharmony_ci .eth_mode = ETHTOOL_LINK_MODE_40000baseCR4_Full_BIT, 1488c2ecf20Sopenharmony_ci .speed = 40000, 1498c2ecf20Sopenharmony_ci .pr_mask = 1 << PRESTERA_LINK_MODE_40GbaseCR4_Full, 1508c2ecf20Sopenharmony_ci .duplex = PRESTERA_PORT_DUPLEX_FULL, 1518c2ecf20Sopenharmony_ci .port_type = PRESTERA_PORT_TYPE_DA, 1528c2ecf20Sopenharmony_ci }, 1538c2ecf20Sopenharmony_ci [PRESTERA_LINK_MODE_40GbaseSR4_Full] = { 1548c2ecf20Sopenharmony_ci .eth_mode = ETHTOOL_LINK_MODE_40000baseSR4_Full_BIT, 1558c2ecf20Sopenharmony_ci .speed = 40000, 1568c2ecf20Sopenharmony_ci .pr_mask = 1 << PRESTERA_LINK_MODE_40GbaseSR4_Full, 1578c2ecf20Sopenharmony_ci .duplex = PRESTERA_PORT_DUPLEX_FULL, 1588c2ecf20Sopenharmony_ci .port_type = PRESTERA_PORT_TYPE_FIBRE, 1598c2ecf20Sopenharmony_ci }, 1608c2ecf20Sopenharmony_ci [PRESTERA_LINK_MODE_50GbaseCR2_Full] = { 1618c2ecf20Sopenharmony_ci .eth_mode = ETHTOOL_LINK_MODE_50000baseCR2_Full_BIT, 1628c2ecf20Sopenharmony_ci .speed = 50000, 1638c2ecf20Sopenharmony_ci .pr_mask = 1 << PRESTERA_LINK_MODE_50GbaseCR2_Full, 1648c2ecf20Sopenharmony_ci .duplex = PRESTERA_PORT_DUPLEX_FULL, 1658c2ecf20Sopenharmony_ci .port_type = PRESTERA_PORT_TYPE_DA, 1668c2ecf20Sopenharmony_ci }, 1678c2ecf20Sopenharmony_ci [PRESTERA_LINK_MODE_50GbaseKR2_Full] = { 1688c2ecf20Sopenharmony_ci .eth_mode = ETHTOOL_LINK_MODE_50000baseKR2_Full_BIT, 1698c2ecf20Sopenharmony_ci .speed = 50000, 1708c2ecf20Sopenharmony_ci .pr_mask = 1 << PRESTERA_LINK_MODE_50GbaseKR2_Full, 1718c2ecf20Sopenharmony_ci .duplex = PRESTERA_PORT_DUPLEX_FULL, 1728c2ecf20Sopenharmony_ci .port_type = PRESTERA_PORT_TYPE_TP, 1738c2ecf20Sopenharmony_ci }, 1748c2ecf20Sopenharmony_ci [PRESTERA_LINK_MODE_50GbaseSR2_Full] = { 1758c2ecf20Sopenharmony_ci .eth_mode = ETHTOOL_LINK_MODE_50000baseSR2_Full_BIT, 1768c2ecf20Sopenharmony_ci .speed = 50000, 1778c2ecf20Sopenharmony_ci .pr_mask = 1 << PRESTERA_LINK_MODE_50GbaseSR2_Full, 1788c2ecf20Sopenharmony_ci .duplex = PRESTERA_PORT_DUPLEX_FULL, 1798c2ecf20Sopenharmony_ci .port_type = PRESTERA_PORT_TYPE_FIBRE, 1808c2ecf20Sopenharmony_ci }, 1818c2ecf20Sopenharmony_ci [PRESTERA_LINK_MODE_100GbaseKR4_Full] = { 1828c2ecf20Sopenharmony_ci .eth_mode = ETHTOOL_LINK_MODE_100000baseKR4_Full_BIT, 1838c2ecf20Sopenharmony_ci .speed = 100000, 1848c2ecf20Sopenharmony_ci .pr_mask = 1 << PRESTERA_LINK_MODE_100GbaseKR4_Full, 1858c2ecf20Sopenharmony_ci .duplex = PRESTERA_PORT_DUPLEX_FULL, 1868c2ecf20Sopenharmony_ci .port_type = PRESTERA_PORT_TYPE_TP, 1878c2ecf20Sopenharmony_ci }, 1888c2ecf20Sopenharmony_ci [PRESTERA_LINK_MODE_100GbaseSR4_Full] = { 1898c2ecf20Sopenharmony_ci .eth_mode = ETHTOOL_LINK_MODE_100000baseSR4_Full_BIT, 1908c2ecf20Sopenharmony_ci .speed = 100000, 1918c2ecf20Sopenharmony_ci .pr_mask = 1 << PRESTERA_LINK_MODE_100GbaseSR4_Full, 1928c2ecf20Sopenharmony_ci .duplex = PRESTERA_PORT_DUPLEX_FULL, 1938c2ecf20Sopenharmony_ci .port_type = PRESTERA_PORT_TYPE_FIBRE, 1948c2ecf20Sopenharmony_ci }, 1958c2ecf20Sopenharmony_ci [PRESTERA_LINK_MODE_100GbaseCR4_Full] = { 1968c2ecf20Sopenharmony_ci .eth_mode = ETHTOOL_LINK_MODE_100000baseCR4_Full_BIT, 1978c2ecf20Sopenharmony_ci .speed = 100000, 1988c2ecf20Sopenharmony_ci .pr_mask = 1 << PRESTERA_LINK_MODE_100GbaseCR4_Full, 1998c2ecf20Sopenharmony_ci .duplex = PRESTERA_PORT_DUPLEX_FULL, 2008c2ecf20Sopenharmony_ci .port_type = PRESTERA_PORT_TYPE_DA, 2018c2ecf20Sopenharmony_ci } 2028c2ecf20Sopenharmony_ci}; 2038c2ecf20Sopenharmony_ci 2048c2ecf20Sopenharmony_cistatic const struct prestera_fec { 2058c2ecf20Sopenharmony_ci u32 eth_fec; 2068c2ecf20Sopenharmony_ci enum ethtool_link_mode_bit_indices eth_mode; 2078c2ecf20Sopenharmony_ci u8 pr_fec; 2088c2ecf20Sopenharmony_ci} port_fec_caps[PRESTERA_PORT_FEC_MAX] = { 2098c2ecf20Sopenharmony_ci [PRESTERA_PORT_FEC_OFF] = { 2108c2ecf20Sopenharmony_ci .eth_fec = ETHTOOL_FEC_OFF, 2118c2ecf20Sopenharmony_ci .eth_mode = ETHTOOL_LINK_MODE_FEC_NONE_BIT, 2128c2ecf20Sopenharmony_ci .pr_fec = 1 << PRESTERA_PORT_FEC_OFF, 2138c2ecf20Sopenharmony_ci }, 2148c2ecf20Sopenharmony_ci [PRESTERA_PORT_FEC_BASER] = { 2158c2ecf20Sopenharmony_ci .eth_fec = ETHTOOL_FEC_BASER, 2168c2ecf20Sopenharmony_ci .eth_mode = ETHTOOL_LINK_MODE_FEC_BASER_BIT, 2178c2ecf20Sopenharmony_ci .pr_fec = 1 << PRESTERA_PORT_FEC_BASER, 2188c2ecf20Sopenharmony_ci }, 2198c2ecf20Sopenharmony_ci [PRESTERA_PORT_FEC_RS] = { 2208c2ecf20Sopenharmony_ci .eth_fec = ETHTOOL_FEC_RS, 2218c2ecf20Sopenharmony_ci .eth_mode = ETHTOOL_LINK_MODE_FEC_RS_BIT, 2228c2ecf20Sopenharmony_ci .pr_fec = 1 << PRESTERA_PORT_FEC_RS, 2238c2ecf20Sopenharmony_ci } 2248c2ecf20Sopenharmony_ci}; 2258c2ecf20Sopenharmony_ci 2268c2ecf20Sopenharmony_cistatic const struct prestera_port_type { 2278c2ecf20Sopenharmony_ci enum ethtool_link_mode_bit_indices eth_mode; 2288c2ecf20Sopenharmony_ci u8 eth_type; 2298c2ecf20Sopenharmony_ci} port_types[PRESTERA_PORT_TYPE_MAX] = { 2308c2ecf20Sopenharmony_ci [PRESTERA_PORT_TYPE_NONE] = { 2318c2ecf20Sopenharmony_ci .eth_mode = __ETHTOOL_LINK_MODE_MASK_NBITS, 2328c2ecf20Sopenharmony_ci .eth_type = PORT_NONE, 2338c2ecf20Sopenharmony_ci }, 2348c2ecf20Sopenharmony_ci [PRESTERA_PORT_TYPE_TP] = { 2358c2ecf20Sopenharmony_ci .eth_mode = ETHTOOL_LINK_MODE_TP_BIT, 2368c2ecf20Sopenharmony_ci .eth_type = PORT_TP, 2378c2ecf20Sopenharmony_ci }, 2388c2ecf20Sopenharmony_ci [PRESTERA_PORT_TYPE_AUI] = { 2398c2ecf20Sopenharmony_ci .eth_mode = ETHTOOL_LINK_MODE_AUI_BIT, 2408c2ecf20Sopenharmony_ci .eth_type = PORT_AUI, 2418c2ecf20Sopenharmony_ci }, 2428c2ecf20Sopenharmony_ci [PRESTERA_PORT_TYPE_MII] = { 2438c2ecf20Sopenharmony_ci .eth_mode = ETHTOOL_LINK_MODE_MII_BIT, 2448c2ecf20Sopenharmony_ci .eth_type = PORT_MII, 2458c2ecf20Sopenharmony_ci }, 2468c2ecf20Sopenharmony_ci [PRESTERA_PORT_TYPE_FIBRE] = { 2478c2ecf20Sopenharmony_ci .eth_mode = ETHTOOL_LINK_MODE_FIBRE_BIT, 2488c2ecf20Sopenharmony_ci .eth_type = PORT_FIBRE, 2498c2ecf20Sopenharmony_ci }, 2508c2ecf20Sopenharmony_ci [PRESTERA_PORT_TYPE_BNC] = { 2518c2ecf20Sopenharmony_ci .eth_mode = ETHTOOL_LINK_MODE_BNC_BIT, 2528c2ecf20Sopenharmony_ci .eth_type = PORT_BNC, 2538c2ecf20Sopenharmony_ci }, 2548c2ecf20Sopenharmony_ci [PRESTERA_PORT_TYPE_DA] = { 2558c2ecf20Sopenharmony_ci .eth_mode = ETHTOOL_LINK_MODE_TP_BIT, 2568c2ecf20Sopenharmony_ci .eth_type = PORT_TP, 2578c2ecf20Sopenharmony_ci }, 2588c2ecf20Sopenharmony_ci [PRESTERA_PORT_TYPE_OTHER] = { 2598c2ecf20Sopenharmony_ci .eth_mode = __ETHTOOL_LINK_MODE_MASK_NBITS, 2608c2ecf20Sopenharmony_ci .eth_type = PORT_OTHER, 2618c2ecf20Sopenharmony_ci } 2628c2ecf20Sopenharmony_ci}; 2638c2ecf20Sopenharmony_ci 2648c2ecf20Sopenharmony_cistatic const char prestera_cnt_name[PRESTERA_STATS_CNT][ETH_GSTRING_LEN] = { 2658c2ecf20Sopenharmony_ci PRESTERA_STATS_FIELD(good_octets_received), 2668c2ecf20Sopenharmony_ci PRESTERA_STATS_FIELD(bad_octets_received), 2678c2ecf20Sopenharmony_ci PRESTERA_STATS_FIELD(mac_trans_error), 2688c2ecf20Sopenharmony_ci PRESTERA_STATS_FIELD(broadcast_frames_received), 2698c2ecf20Sopenharmony_ci PRESTERA_STATS_FIELD(multicast_frames_received), 2708c2ecf20Sopenharmony_ci PRESTERA_STATS_FIELD(frames_64_octets), 2718c2ecf20Sopenharmony_ci PRESTERA_STATS_FIELD(frames_65_to_127_octets), 2728c2ecf20Sopenharmony_ci PRESTERA_STATS_FIELD(frames_128_to_255_octets), 2738c2ecf20Sopenharmony_ci PRESTERA_STATS_FIELD(frames_256_to_511_octets), 2748c2ecf20Sopenharmony_ci PRESTERA_STATS_FIELD(frames_512_to_1023_octets), 2758c2ecf20Sopenharmony_ci PRESTERA_STATS_FIELD(frames_1024_to_max_octets), 2768c2ecf20Sopenharmony_ci PRESTERA_STATS_FIELD(excessive_collision), 2778c2ecf20Sopenharmony_ci PRESTERA_STATS_FIELD(multicast_frames_sent), 2788c2ecf20Sopenharmony_ci PRESTERA_STATS_FIELD(broadcast_frames_sent), 2798c2ecf20Sopenharmony_ci PRESTERA_STATS_FIELD(fc_sent), 2808c2ecf20Sopenharmony_ci PRESTERA_STATS_FIELD(fc_received), 2818c2ecf20Sopenharmony_ci PRESTERA_STATS_FIELD(buffer_overrun), 2828c2ecf20Sopenharmony_ci PRESTERA_STATS_FIELD(undersize), 2838c2ecf20Sopenharmony_ci PRESTERA_STATS_FIELD(fragments), 2848c2ecf20Sopenharmony_ci PRESTERA_STATS_FIELD(oversize), 2858c2ecf20Sopenharmony_ci PRESTERA_STATS_FIELD(jabber), 2868c2ecf20Sopenharmony_ci PRESTERA_STATS_FIELD(rx_error_frame_received), 2878c2ecf20Sopenharmony_ci PRESTERA_STATS_FIELD(bad_crc), 2888c2ecf20Sopenharmony_ci PRESTERA_STATS_FIELD(collisions), 2898c2ecf20Sopenharmony_ci PRESTERA_STATS_FIELD(late_collision), 2908c2ecf20Sopenharmony_ci PRESTERA_STATS_FIELD(unicast_frames_received), 2918c2ecf20Sopenharmony_ci PRESTERA_STATS_FIELD(unicast_frames_sent), 2928c2ecf20Sopenharmony_ci PRESTERA_STATS_FIELD(sent_multiple), 2938c2ecf20Sopenharmony_ci PRESTERA_STATS_FIELD(sent_deferred), 2948c2ecf20Sopenharmony_ci PRESTERA_STATS_FIELD(good_octets_sent), 2958c2ecf20Sopenharmony_ci}; 2968c2ecf20Sopenharmony_ci 2978c2ecf20Sopenharmony_cistatic void prestera_ethtool_get_drvinfo(struct net_device *dev, 2988c2ecf20Sopenharmony_ci struct ethtool_drvinfo *drvinfo) 2998c2ecf20Sopenharmony_ci{ 3008c2ecf20Sopenharmony_ci struct prestera_port *port = netdev_priv(dev); 3018c2ecf20Sopenharmony_ci struct prestera_switch *sw = port->sw; 3028c2ecf20Sopenharmony_ci 3038c2ecf20Sopenharmony_ci strlcpy(drvinfo->driver, driver_kind, sizeof(drvinfo->driver)); 3048c2ecf20Sopenharmony_ci strlcpy(drvinfo->bus_info, dev_name(prestera_dev(sw)), 3058c2ecf20Sopenharmony_ci sizeof(drvinfo->bus_info)); 3068c2ecf20Sopenharmony_ci snprintf(drvinfo->fw_version, sizeof(drvinfo->fw_version), 3078c2ecf20Sopenharmony_ci "%d.%d.%d", 3088c2ecf20Sopenharmony_ci sw->dev->fw_rev.maj, 3098c2ecf20Sopenharmony_ci sw->dev->fw_rev.min, 3108c2ecf20Sopenharmony_ci sw->dev->fw_rev.sub); 3118c2ecf20Sopenharmony_ci} 3128c2ecf20Sopenharmony_ci 3138c2ecf20Sopenharmony_cistatic u8 prestera_port_type_get(struct prestera_port *port) 3148c2ecf20Sopenharmony_ci{ 3158c2ecf20Sopenharmony_ci if (port->caps.type < PRESTERA_PORT_TYPE_MAX) 3168c2ecf20Sopenharmony_ci return port_types[port->caps.type].eth_type; 3178c2ecf20Sopenharmony_ci 3188c2ecf20Sopenharmony_ci return PORT_OTHER; 3198c2ecf20Sopenharmony_ci} 3208c2ecf20Sopenharmony_ci 3218c2ecf20Sopenharmony_cistatic int prestera_port_type_set(const struct ethtool_link_ksettings *ecmd, 3228c2ecf20Sopenharmony_ci struct prestera_port *port) 3238c2ecf20Sopenharmony_ci{ 3248c2ecf20Sopenharmony_ci u32 new_mode = PRESTERA_LINK_MODE_MAX; 3258c2ecf20Sopenharmony_ci u32 type, mode; 3268c2ecf20Sopenharmony_ci int err; 3278c2ecf20Sopenharmony_ci 3288c2ecf20Sopenharmony_ci for (type = 0; type < PRESTERA_PORT_TYPE_MAX; type++) { 3298c2ecf20Sopenharmony_ci if (port_types[type].eth_type == ecmd->base.port && 3308c2ecf20Sopenharmony_ci test_bit(port_types[type].eth_mode, 3318c2ecf20Sopenharmony_ci ecmd->link_modes.supported)) { 3328c2ecf20Sopenharmony_ci break; 3338c2ecf20Sopenharmony_ci } 3348c2ecf20Sopenharmony_ci } 3358c2ecf20Sopenharmony_ci 3368c2ecf20Sopenharmony_ci if (type == port->caps.type) 3378c2ecf20Sopenharmony_ci return 0; 3388c2ecf20Sopenharmony_ci if (type != port->caps.type && ecmd->base.autoneg == AUTONEG_ENABLE) 3398c2ecf20Sopenharmony_ci return -EINVAL; 3408c2ecf20Sopenharmony_ci if (type == PRESTERA_PORT_TYPE_MAX) 3418c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 3428c2ecf20Sopenharmony_ci 3438c2ecf20Sopenharmony_ci for (mode = 0; mode < PRESTERA_LINK_MODE_MAX; mode++) { 3448c2ecf20Sopenharmony_ci if ((port_link_modes[mode].pr_mask & 3458c2ecf20Sopenharmony_ci port->caps.supp_link_modes) && 3468c2ecf20Sopenharmony_ci type == port_link_modes[mode].port_type) { 3478c2ecf20Sopenharmony_ci new_mode = mode; 3488c2ecf20Sopenharmony_ci } 3498c2ecf20Sopenharmony_ci } 3508c2ecf20Sopenharmony_ci 3518c2ecf20Sopenharmony_ci if (new_mode < PRESTERA_LINK_MODE_MAX) 3528c2ecf20Sopenharmony_ci err = prestera_hw_port_link_mode_set(port, new_mode); 3538c2ecf20Sopenharmony_ci else 3548c2ecf20Sopenharmony_ci err = -EINVAL; 3558c2ecf20Sopenharmony_ci 3568c2ecf20Sopenharmony_ci if (err) 3578c2ecf20Sopenharmony_ci return err; 3588c2ecf20Sopenharmony_ci 3598c2ecf20Sopenharmony_ci port->caps.type = type; 3608c2ecf20Sopenharmony_ci port->autoneg = false; 3618c2ecf20Sopenharmony_ci 3628c2ecf20Sopenharmony_ci return 0; 3638c2ecf20Sopenharmony_ci} 3648c2ecf20Sopenharmony_ci 3658c2ecf20Sopenharmony_cistatic void prestera_modes_to_eth(unsigned long *eth_modes, u64 link_modes, 3668c2ecf20Sopenharmony_ci u8 fec, u8 type) 3678c2ecf20Sopenharmony_ci{ 3688c2ecf20Sopenharmony_ci u32 mode; 3698c2ecf20Sopenharmony_ci 3708c2ecf20Sopenharmony_ci for (mode = 0; mode < PRESTERA_LINK_MODE_MAX; mode++) { 3718c2ecf20Sopenharmony_ci if ((port_link_modes[mode].pr_mask & link_modes) == 0) 3728c2ecf20Sopenharmony_ci continue; 3738c2ecf20Sopenharmony_ci 3748c2ecf20Sopenharmony_ci if (type != PRESTERA_PORT_TYPE_NONE && 3758c2ecf20Sopenharmony_ci port_link_modes[mode].port_type != type) 3768c2ecf20Sopenharmony_ci continue; 3778c2ecf20Sopenharmony_ci 3788c2ecf20Sopenharmony_ci __set_bit(port_link_modes[mode].eth_mode, eth_modes); 3798c2ecf20Sopenharmony_ci } 3808c2ecf20Sopenharmony_ci 3818c2ecf20Sopenharmony_ci for (mode = 0; mode < PRESTERA_PORT_FEC_MAX; mode++) { 3828c2ecf20Sopenharmony_ci if ((port_fec_caps[mode].pr_fec & fec) == 0) 3838c2ecf20Sopenharmony_ci continue; 3848c2ecf20Sopenharmony_ci 3858c2ecf20Sopenharmony_ci __set_bit(port_fec_caps[mode].eth_mode, eth_modes); 3868c2ecf20Sopenharmony_ci } 3878c2ecf20Sopenharmony_ci} 3888c2ecf20Sopenharmony_ci 3898c2ecf20Sopenharmony_cistatic void prestera_modes_from_eth(const unsigned long *eth_modes, 3908c2ecf20Sopenharmony_ci u64 *link_modes, u8 *fec, u8 type) 3918c2ecf20Sopenharmony_ci{ 3928c2ecf20Sopenharmony_ci u64 adver_modes = 0; 3938c2ecf20Sopenharmony_ci u32 fec_modes = 0; 3948c2ecf20Sopenharmony_ci u32 mode; 3958c2ecf20Sopenharmony_ci 3968c2ecf20Sopenharmony_ci for (mode = 0; mode < PRESTERA_LINK_MODE_MAX; mode++) { 3978c2ecf20Sopenharmony_ci if (!test_bit(port_link_modes[mode].eth_mode, eth_modes)) 3988c2ecf20Sopenharmony_ci continue; 3998c2ecf20Sopenharmony_ci 4008c2ecf20Sopenharmony_ci if (port_link_modes[mode].port_type != type) 4018c2ecf20Sopenharmony_ci continue; 4028c2ecf20Sopenharmony_ci 4038c2ecf20Sopenharmony_ci adver_modes |= port_link_modes[mode].pr_mask; 4048c2ecf20Sopenharmony_ci } 4058c2ecf20Sopenharmony_ci 4068c2ecf20Sopenharmony_ci for (mode = 0; mode < PRESTERA_PORT_FEC_MAX; mode++) { 4078c2ecf20Sopenharmony_ci if (!test_bit(port_fec_caps[mode].eth_mode, eth_modes)) 4088c2ecf20Sopenharmony_ci continue; 4098c2ecf20Sopenharmony_ci 4108c2ecf20Sopenharmony_ci fec_modes |= port_fec_caps[mode].pr_fec; 4118c2ecf20Sopenharmony_ci } 4128c2ecf20Sopenharmony_ci 4138c2ecf20Sopenharmony_ci *link_modes = adver_modes; 4148c2ecf20Sopenharmony_ci *fec = fec_modes; 4158c2ecf20Sopenharmony_ci} 4168c2ecf20Sopenharmony_ci 4178c2ecf20Sopenharmony_cistatic void prestera_port_supp_types_get(struct ethtool_link_ksettings *ecmd, 4188c2ecf20Sopenharmony_ci struct prestera_port *port) 4198c2ecf20Sopenharmony_ci{ 4208c2ecf20Sopenharmony_ci u32 mode; 4218c2ecf20Sopenharmony_ci u8 ptype; 4228c2ecf20Sopenharmony_ci 4238c2ecf20Sopenharmony_ci for (mode = 0; mode < PRESTERA_LINK_MODE_MAX; mode++) { 4248c2ecf20Sopenharmony_ci if ((port_link_modes[mode].pr_mask & 4258c2ecf20Sopenharmony_ci port->caps.supp_link_modes) == 0) 4268c2ecf20Sopenharmony_ci continue; 4278c2ecf20Sopenharmony_ci 4288c2ecf20Sopenharmony_ci ptype = port_link_modes[mode].port_type; 4298c2ecf20Sopenharmony_ci __set_bit(port_types[ptype].eth_mode, 4308c2ecf20Sopenharmony_ci ecmd->link_modes.supported); 4318c2ecf20Sopenharmony_ci } 4328c2ecf20Sopenharmony_ci} 4338c2ecf20Sopenharmony_ci 4348c2ecf20Sopenharmony_cistatic void prestera_port_remote_cap_get(struct ethtool_link_ksettings *ecmd, 4358c2ecf20Sopenharmony_ci struct prestera_port *port) 4368c2ecf20Sopenharmony_ci{ 4378c2ecf20Sopenharmony_ci bool asym_pause; 4388c2ecf20Sopenharmony_ci bool pause; 4398c2ecf20Sopenharmony_ci u64 bitmap; 4408c2ecf20Sopenharmony_ci int err; 4418c2ecf20Sopenharmony_ci 4428c2ecf20Sopenharmony_ci err = prestera_hw_port_remote_cap_get(port, &bitmap); 4438c2ecf20Sopenharmony_ci if (!err) { 4448c2ecf20Sopenharmony_ci prestera_modes_to_eth(ecmd->link_modes.lp_advertising, 4458c2ecf20Sopenharmony_ci bitmap, 0, PRESTERA_PORT_TYPE_NONE); 4468c2ecf20Sopenharmony_ci 4478c2ecf20Sopenharmony_ci if (!bitmap_empty(ecmd->link_modes.lp_advertising, 4488c2ecf20Sopenharmony_ci __ETHTOOL_LINK_MODE_MASK_NBITS)) { 4498c2ecf20Sopenharmony_ci ethtool_link_ksettings_add_link_mode(ecmd, 4508c2ecf20Sopenharmony_ci lp_advertising, 4518c2ecf20Sopenharmony_ci Autoneg); 4528c2ecf20Sopenharmony_ci } 4538c2ecf20Sopenharmony_ci } 4548c2ecf20Sopenharmony_ci 4558c2ecf20Sopenharmony_ci err = prestera_hw_port_remote_fc_get(port, &pause, &asym_pause); 4568c2ecf20Sopenharmony_ci if (err) 4578c2ecf20Sopenharmony_ci return; 4588c2ecf20Sopenharmony_ci 4598c2ecf20Sopenharmony_ci if (pause) 4608c2ecf20Sopenharmony_ci ethtool_link_ksettings_add_link_mode(ecmd, 4618c2ecf20Sopenharmony_ci lp_advertising, 4628c2ecf20Sopenharmony_ci Pause); 4638c2ecf20Sopenharmony_ci if (asym_pause) 4648c2ecf20Sopenharmony_ci ethtool_link_ksettings_add_link_mode(ecmd, 4658c2ecf20Sopenharmony_ci lp_advertising, 4668c2ecf20Sopenharmony_ci Asym_Pause); 4678c2ecf20Sopenharmony_ci} 4688c2ecf20Sopenharmony_ci 4698c2ecf20Sopenharmony_cistatic void prestera_port_speed_get(struct ethtool_link_ksettings *ecmd, 4708c2ecf20Sopenharmony_ci struct prestera_port *port) 4718c2ecf20Sopenharmony_ci{ 4728c2ecf20Sopenharmony_ci u32 speed; 4738c2ecf20Sopenharmony_ci int err; 4748c2ecf20Sopenharmony_ci 4758c2ecf20Sopenharmony_ci err = prestera_hw_port_speed_get(port, &speed); 4768c2ecf20Sopenharmony_ci ecmd->base.speed = err ? SPEED_UNKNOWN : speed; 4778c2ecf20Sopenharmony_ci} 4788c2ecf20Sopenharmony_ci 4798c2ecf20Sopenharmony_cistatic void prestera_port_duplex_get(struct ethtool_link_ksettings *ecmd, 4808c2ecf20Sopenharmony_ci struct prestera_port *port) 4818c2ecf20Sopenharmony_ci{ 4828c2ecf20Sopenharmony_ci u8 duplex; 4838c2ecf20Sopenharmony_ci int err; 4848c2ecf20Sopenharmony_ci 4858c2ecf20Sopenharmony_ci err = prestera_hw_port_duplex_get(port, &duplex); 4868c2ecf20Sopenharmony_ci if (err) { 4878c2ecf20Sopenharmony_ci ecmd->base.duplex = DUPLEX_UNKNOWN; 4888c2ecf20Sopenharmony_ci return; 4898c2ecf20Sopenharmony_ci } 4908c2ecf20Sopenharmony_ci 4918c2ecf20Sopenharmony_ci ecmd->base.duplex = duplex == PRESTERA_PORT_DUPLEX_FULL ? 4928c2ecf20Sopenharmony_ci DUPLEX_FULL : DUPLEX_HALF; 4938c2ecf20Sopenharmony_ci} 4948c2ecf20Sopenharmony_ci 4958c2ecf20Sopenharmony_cistatic int 4968c2ecf20Sopenharmony_ciprestera_ethtool_get_link_ksettings(struct net_device *dev, 4978c2ecf20Sopenharmony_ci struct ethtool_link_ksettings *ecmd) 4988c2ecf20Sopenharmony_ci{ 4998c2ecf20Sopenharmony_ci struct prestera_port *port = netdev_priv(dev); 5008c2ecf20Sopenharmony_ci 5018c2ecf20Sopenharmony_ci ethtool_link_ksettings_zero_link_mode(ecmd, supported); 5028c2ecf20Sopenharmony_ci ethtool_link_ksettings_zero_link_mode(ecmd, advertising); 5038c2ecf20Sopenharmony_ci ethtool_link_ksettings_zero_link_mode(ecmd, lp_advertising); 5048c2ecf20Sopenharmony_ci 5058c2ecf20Sopenharmony_ci ecmd->base.autoneg = port->autoneg ? AUTONEG_ENABLE : AUTONEG_DISABLE; 5068c2ecf20Sopenharmony_ci 5078c2ecf20Sopenharmony_ci if (port->caps.type == PRESTERA_PORT_TYPE_TP) { 5088c2ecf20Sopenharmony_ci ethtool_link_ksettings_add_link_mode(ecmd, supported, Autoneg); 5098c2ecf20Sopenharmony_ci 5108c2ecf20Sopenharmony_ci if (netif_running(dev) && 5118c2ecf20Sopenharmony_ci (port->autoneg || 5128c2ecf20Sopenharmony_ci port->caps.transceiver == PRESTERA_PORT_TCVR_COPPER)) 5138c2ecf20Sopenharmony_ci ethtool_link_ksettings_add_link_mode(ecmd, advertising, 5148c2ecf20Sopenharmony_ci Autoneg); 5158c2ecf20Sopenharmony_ci } 5168c2ecf20Sopenharmony_ci 5178c2ecf20Sopenharmony_ci prestera_modes_to_eth(ecmd->link_modes.supported, 5188c2ecf20Sopenharmony_ci port->caps.supp_link_modes, 5198c2ecf20Sopenharmony_ci port->caps.supp_fec, 5208c2ecf20Sopenharmony_ci port->caps.type); 5218c2ecf20Sopenharmony_ci 5228c2ecf20Sopenharmony_ci prestera_port_supp_types_get(ecmd, port); 5238c2ecf20Sopenharmony_ci 5248c2ecf20Sopenharmony_ci if (netif_carrier_ok(dev)) { 5258c2ecf20Sopenharmony_ci prestera_port_speed_get(ecmd, port); 5268c2ecf20Sopenharmony_ci prestera_port_duplex_get(ecmd, port); 5278c2ecf20Sopenharmony_ci } else { 5288c2ecf20Sopenharmony_ci ecmd->base.speed = SPEED_UNKNOWN; 5298c2ecf20Sopenharmony_ci ecmd->base.duplex = DUPLEX_UNKNOWN; 5308c2ecf20Sopenharmony_ci } 5318c2ecf20Sopenharmony_ci 5328c2ecf20Sopenharmony_ci ecmd->base.port = prestera_port_type_get(port); 5338c2ecf20Sopenharmony_ci 5348c2ecf20Sopenharmony_ci if (port->autoneg) { 5358c2ecf20Sopenharmony_ci if (netif_running(dev)) 5368c2ecf20Sopenharmony_ci prestera_modes_to_eth(ecmd->link_modes.advertising, 5378c2ecf20Sopenharmony_ci port->adver_link_modes, 5388c2ecf20Sopenharmony_ci port->adver_fec, 5398c2ecf20Sopenharmony_ci port->caps.type); 5408c2ecf20Sopenharmony_ci 5418c2ecf20Sopenharmony_ci if (netif_carrier_ok(dev) && 5428c2ecf20Sopenharmony_ci port->caps.transceiver == PRESTERA_PORT_TCVR_COPPER) 5438c2ecf20Sopenharmony_ci prestera_port_remote_cap_get(ecmd, port); 5448c2ecf20Sopenharmony_ci } 5458c2ecf20Sopenharmony_ci 5468c2ecf20Sopenharmony_ci if (port->caps.type == PRESTERA_PORT_TYPE_TP && 5478c2ecf20Sopenharmony_ci port->caps.transceiver == PRESTERA_PORT_TCVR_COPPER) 5488c2ecf20Sopenharmony_ci prestera_hw_port_mdix_get(port, &ecmd->base.eth_tp_mdix, 5498c2ecf20Sopenharmony_ci &ecmd->base.eth_tp_mdix_ctrl); 5508c2ecf20Sopenharmony_ci 5518c2ecf20Sopenharmony_ci return 0; 5528c2ecf20Sopenharmony_ci} 5538c2ecf20Sopenharmony_ci 5548c2ecf20Sopenharmony_cistatic int prestera_port_mdix_set(const struct ethtool_link_ksettings *ecmd, 5558c2ecf20Sopenharmony_ci struct prestera_port *port) 5568c2ecf20Sopenharmony_ci{ 5578c2ecf20Sopenharmony_ci if (ecmd->base.eth_tp_mdix_ctrl != ETH_TP_MDI_INVALID && 5588c2ecf20Sopenharmony_ci port->caps.transceiver == PRESTERA_PORT_TCVR_COPPER && 5598c2ecf20Sopenharmony_ci port->caps.type == PRESTERA_PORT_TYPE_TP) 5608c2ecf20Sopenharmony_ci return prestera_hw_port_mdix_set(port, 5618c2ecf20Sopenharmony_ci ecmd->base.eth_tp_mdix_ctrl); 5628c2ecf20Sopenharmony_ci 5638c2ecf20Sopenharmony_ci return 0; 5648c2ecf20Sopenharmony_ci} 5658c2ecf20Sopenharmony_ci 5668c2ecf20Sopenharmony_cistatic int prestera_port_link_mode_set(struct prestera_port *port, 5678c2ecf20Sopenharmony_ci u32 speed, u8 duplex, u8 type) 5688c2ecf20Sopenharmony_ci{ 5698c2ecf20Sopenharmony_ci u32 new_mode = PRESTERA_LINK_MODE_MAX; 5708c2ecf20Sopenharmony_ci u32 mode; 5718c2ecf20Sopenharmony_ci 5728c2ecf20Sopenharmony_ci for (mode = 0; mode < PRESTERA_LINK_MODE_MAX; mode++) { 5738c2ecf20Sopenharmony_ci if (speed != port_link_modes[mode].speed) 5748c2ecf20Sopenharmony_ci continue; 5758c2ecf20Sopenharmony_ci 5768c2ecf20Sopenharmony_ci if (duplex != port_link_modes[mode].duplex) 5778c2ecf20Sopenharmony_ci continue; 5788c2ecf20Sopenharmony_ci 5798c2ecf20Sopenharmony_ci if (!(port_link_modes[mode].pr_mask & 5808c2ecf20Sopenharmony_ci port->caps.supp_link_modes)) 5818c2ecf20Sopenharmony_ci continue; 5828c2ecf20Sopenharmony_ci 5838c2ecf20Sopenharmony_ci if (type != port_link_modes[mode].port_type) 5848c2ecf20Sopenharmony_ci continue; 5858c2ecf20Sopenharmony_ci 5868c2ecf20Sopenharmony_ci new_mode = mode; 5878c2ecf20Sopenharmony_ci break; 5888c2ecf20Sopenharmony_ci } 5898c2ecf20Sopenharmony_ci 5908c2ecf20Sopenharmony_ci if (new_mode == PRESTERA_LINK_MODE_MAX) 5918c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 5928c2ecf20Sopenharmony_ci 5938c2ecf20Sopenharmony_ci return prestera_hw_port_link_mode_set(port, new_mode); 5948c2ecf20Sopenharmony_ci} 5958c2ecf20Sopenharmony_ci 5968c2ecf20Sopenharmony_cistatic int 5978c2ecf20Sopenharmony_ciprestera_port_speed_duplex_set(const struct ethtool_link_ksettings *ecmd, 5988c2ecf20Sopenharmony_ci struct prestera_port *port) 5998c2ecf20Sopenharmony_ci{ 6008c2ecf20Sopenharmony_ci u32 curr_mode; 6018c2ecf20Sopenharmony_ci u8 duplex; 6028c2ecf20Sopenharmony_ci u32 speed; 6038c2ecf20Sopenharmony_ci int err; 6048c2ecf20Sopenharmony_ci 6058c2ecf20Sopenharmony_ci err = prestera_hw_port_link_mode_get(port, &curr_mode); 6068c2ecf20Sopenharmony_ci if (err) 6078c2ecf20Sopenharmony_ci return err; 6088c2ecf20Sopenharmony_ci if (curr_mode >= PRESTERA_LINK_MODE_MAX) 6098c2ecf20Sopenharmony_ci return -EINVAL; 6108c2ecf20Sopenharmony_ci 6118c2ecf20Sopenharmony_ci if (ecmd->base.duplex != DUPLEX_UNKNOWN) 6128c2ecf20Sopenharmony_ci duplex = ecmd->base.duplex == DUPLEX_FULL ? 6138c2ecf20Sopenharmony_ci PRESTERA_PORT_DUPLEX_FULL : PRESTERA_PORT_DUPLEX_HALF; 6148c2ecf20Sopenharmony_ci else 6158c2ecf20Sopenharmony_ci duplex = port_link_modes[curr_mode].duplex; 6168c2ecf20Sopenharmony_ci 6178c2ecf20Sopenharmony_ci if (ecmd->base.speed != SPEED_UNKNOWN) 6188c2ecf20Sopenharmony_ci speed = ecmd->base.speed; 6198c2ecf20Sopenharmony_ci else 6208c2ecf20Sopenharmony_ci speed = port_link_modes[curr_mode].speed; 6218c2ecf20Sopenharmony_ci 6228c2ecf20Sopenharmony_ci return prestera_port_link_mode_set(port, speed, duplex, 6238c2ecf20Sopenharmony_ci port->caps.type); 6248c2ecf20Sopenharmony_ci} 6258c2ecf20Sopenharmony_ci 6268c2ecf20Sopenharmony_cistatic int 6278c2ecf20Sopenharmony_ciprestera_ethtool_set_link_ksettings(struct net_device *dev, 6288c2ecf20Sopenharmony_ci const struct ethtool_link_ksettings *ecmd) 6298c2ecf20Sopenharmony_ci{ 6308c2ecf20Sopenharmony_ci struct prestera_port *port = netdev_priv(dev); 6318c2ecf20Sopenharmony_ci u64 adver_modes; 6328c2ecf20Sopenharmony_ci u8 adver_fec; 6338c2ecf20Sopenharmony_ci int err; 6348c2ecf20Sopenharmony_ci 6358c2ecf20Sopenharmony_ci err = prestera_port_type_set(ecmd, port); 6368c2ecf20Sopenharmony_ci if (err) 6378c2ecf20Sopenharmony_ci return err; 6388c2ecf20Sopenharmony_ci 6398c2ecf20Sopenharmony_ci if (port->caps.transceiver == PRESTERA_PORT_TCVR_COPPER) { 6408c2ecf20Sopenharmony_ci err = prestera_port_mdix_set(ecmd, port); 6418c2ecf20Sopenharmony_ci if (err) 6428c2ecf20Sopenharmony_ci return err; 6438c2ecf20Sopenharmony_ci } 6448c2ecf20Sopenharmony_ci 6458c2ecf20Sopenharmony_ci prestera_modes_from_eth(ecmd->link_modes.advertising, &adver_modes, 6468c2ecf20Sopenharmony_ci &adver_fec, port->caps.type); 6478c2ecf20Sopenharmony_ci 6488c2ecf20Sopenharmony_ci err = prestera_port_autoneg_set(port, 6498c2ecf20Sopenharmony_ci ecmd->base.autoneg == AUTONEG_ENABLE, 6508c2ecf20Sopenharmony_ci adver_modes, adver_fec); 6518c2ecf20Sopenharmony_ci if (err) 6528c2ecf20Sopenharmony_ci return err; 6538c2ecf20Sopenharmony_ci 6548c2ecf20Sopenharmony_ci if (ecmd->base.autoneg == AUTONEG_DISABLE) { 6558c2ecf20Sopenharmony_ci err = prestera_port_speed_duplex_set(ecmd, port); 6568c2ecf20Sopenharmony_ci if (err) 6578c2ecf20Sopenharmony_ci return err; 6588c2ecf20Sopenharmony_ci } 6598c2ecf20Sopenharmony_ci 6608c2ecf20Sopenharmony_ci return 0; 6618c2ecf20Sopenharmony_ci} 6628c2ecf20Sopenharmony_ci 6638c2ecf20Sopenharmony_cistatic int prestera_ethtool_get_fecparam(struct net_device *dev, 6648c2ecf20Sopenharmony_ci struct ethtool_fecparam *fecparam) 6658c2ecf20Sopenharmony_ci{ 6668c2ecf20Sopenharmony_ci struct prestera_port *port = netdev_priv(dev); 6678c2ecf20Sopenharmony_ci u8 active; 6688c2ecf20Sopenharmony_ci u32 mode; 6698c2ecf20Sopenharmony_ci int err; 6708c2ecf20Sopenharmony_ci 6718c2ecf20Sopenharmony_ci err = prestera_hw_port_fec_get(port, &active); 6728c2ecf20Sopenharmony_ci if (err) 6738c2ecf20Sopenharmony_ci return err; 6748c2ecf20Sopenharmony_ci 6758c2ecf20Sopenharmony_ci fecparam->fec = 0; 6768c2ecf20Sopenharmony_ci 6778c2ecf20Sopenharmony_ci for (mode = 0; mode < PRESTERA_PORT_FEC_MAX; mode++) { 6788c2ecf20Sopenharmony_ci if ((port_fec_caps[mode].pr_fec & port->caps.supp_fec) == 0) 6798c2ecf20Sopenharmony_ci continue; 6808c2ecf20Sopenharmony_ci 6818c2ecf20Sopenharmony_ci fecparam->fec |= port_fec_caps[mode].eth_fec; 6828c2ecf20Sopenharmony_ci } 6838c2ecf20Sopenharmony_ci 6848c2ecf20Sopenharmony_ci if (active < PRESTERA_PORT_FEC_MAX) 6858c2ecf20Sopenharmony_ci fecparam->active_fec = port_fec_caps[active].eth_fec; 6868c2ecf20Sopenharmony_ci else 6878c2ecf20Sopenharmony_ci fecparam->active_fec = ETHTOOL_FEC_AUTO; 6888c2ecf20Sopenharmony_ci 6898c2ecf20Sopenharmony_ci return 0; 6908c2ecf20Sopenharmony_ci} 6918c2ecf20Sopenharmony_ci 6928c2ecf20Sopenharmony_cistatic int prestera_ethtool_set_fecparam(struct net_device *dev, 6938c2ecf20Sopenharmony_ci struct ethtool_fecparam *fecparam) 6948c2ecf20Sopenharmony_ci{ 6958c2ecf20Sopenharmony_ci struct prestera_port *port = netdev_priv(dev); 6968c2ecf20Sopenharmony_ci u8 fec, active; 6978c2ecf20Sopenharmony_ci u32 mode; 6988c2ecf20Sopenharmony_ci int err; 6998c2ecf20Sopenharmony_ci 7008c2ecf20Sopenharmony_ci if (port->autoneg) { 7018c2ecf20Sopenharmony_ci netdev_err(dev, "FEC set is not allowed while autoneg is on\n"); 7028c2ecf20Sopenharmony_ci return -EINVAL; 7038c2ecf20Sopenharmony_ci } 7048c2ecf20Sopenharmony_ci 7058c2ecf20Sopenharmony_ci err = prestera_hw_port_fec_get(port, &active); 7068c2ecf20Sopenharmony_ci if (err) 7078c2ecf20Sopenharmony_ci return err; 7088c2ecf20Sopenharmony_ci 7098c2ecf20Sopenharmony_ci fec = PRESTERA_PORT_FEC_MAX; 7108c2ecf20Sopenharmony_ci for (mode = 0; mode < PRESTERA_PORT_FEC_MAX; mode++) { 7118c2ecf20Sopenharmony_ci if ((port_fec_caps[mode].eth_fec & fecparam->fec) && 7128c2ecf20Sopenharmony_ci (port_fec_caps[mode].pr_fec & port->caps.supp_fec)) { 7138c2ecf20Sopenharmony_ci fec = mode; 7148c2ecf20Sopenharmony_ci break; 7158c2ecf20Sopenharmony_ci } 7168c2ecf20Sopenharmony_ci } 7178c2ecf20Sopenharmony_ci 7188c2ecf20Sopenharmony_ci if (fec == active) 7198c2ecf20Sopenharmony_ci return 0; 7208c2ecf20Sopenharmony_ci 7218c2ecf20Sopenharmony_ci if (fec == PRESTERA_PORT_FEC_MAX) 7228c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 7238c2ecf20Sopenharmony_ci 7248c2ecf20Sopenharmony_ci return prestera_hw_port_fec_set(port, fec); 7258c2ecf20Sopenharmony_ci} 7268c2ecf20Sopenharmony_ci 7278c2ecf20Sopenharmony_cistatic int prestera_ethtool_get_sset_count(struct net_device *dev, int sset) 7288c2ecf20Sopenharmony_ci{ 7298c2ecf20Sopenharmony_ci switch (sset) { 7308c2ecf20Sopenharmony_ci case ETH_SS_STATS: 7318c2ecf20Sopenharmony_ci return PRESTERA_STATS_CNT; 7328c2ecf20Sopenharmony_ci default: 7338c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 7348c2ecf20Sopenharmony_ci } 7358c2ecf20Sopenharmony_ci} 7368c2ecf20Sopenharmony_ci 7378c2ecf20Sopenharmony_cistatic void prestera_ethtool_get_strings(struct net_device *dev, 7388c2ecf20Sopenharmony_ci u32 stringset, u8 *data) 7398c2ecf20Sopenharmony_ci{ 7408c2ecf20Sopenharmony_ci if (stringset != ETH_SS_STATS) 7418c2ecf20Sopenharmony_ci return; 7428c2ecf20Sopenharmony_ci 7438c2ecf20Sopenharmony_ci memcpy(data, prestera_cnt_name, sizeof(prestera_cnt_name)); 7448c2ecf20Sopenharmony_ci} 7458c2ecf20Sopenharmony_ci 7468c2ecf20Sopenharmony_cistatic void prestera_ethtool_get_stats(struct net_device *dev, 7478c2ecf20Sopenharmony_ci struct ethtool_stats *stats, u64 *data) 7488c2ecf20Sopenharmony_ci{ 7498c2ecf20Sopenharmony_ci struct prestera_port *port = netdev_priv(dev); 7508c2ecf20Sopenharmony_ci struct prestera_port_stats *port_stats; 7518c2ecf20Sopenharmony_ci 7528c2ecf20Sopenharmony_ci port_stats = &port->cached_hw_stats.stats; 7538c2ecf20Sopenharmony_ci 7548c2ecf20Sopenharmony_ci memcpy(data, port_stats, sizeof(*port_stats)); 7558c2ecf20Sopenharmony_ci} 7568c2ecf20Sopenharmony_ci 7578c2ecf20Sopenharmony_cistatic int prestera_ethtool_nway_reset(struct net_device *dev) 7588c2ecf20Sopenharmony_ci{ 7598c2ecf20Sopenharmony_ci struct prestera_port *port = netdev_priv(dev); 7608c2ecf20Sopenharmony_ci 7618c2ecf20Sopenharmony_ci if (netif_running(dev) && 7628c2ecf20Sopenharmony_ci port->caps.transceiver == PRESTERA_PORT_TCVR_COPPER && 7638c2ecf20Sopenharmony_ci port->caps.type == PRESTERA_PORT_TYPE_TP) 7648c2ecf20Sopenharmony_ci return prestera_hw_port_autoneg_restart(port); 7658c2ecf20Sopenharmony_ci 7668c2ecf20Sopenharmony_ci return -EINVAL; 7678c2ecf20Sopenharmony_ci} 7688c2ecf20Sopenharmony_ci 7698c2ecf20Sopenharmony_ciconst struct ethtool_ops prestera_ethtool_ops = { 7708c2ecf20Sopenharmony_ci .get_drvinfo = prestera_ethtool_get_drvinfo, 7718c2ecf20Sopenharmony_ci .get_link_ksettings = prestera_ethtool_get_link_ksettings, 7728c2ecf20Sopenharmony_ci .set_link_ksettings = prestera_ethtool_set_link_ksettings, 7738c2ecf20Sopenharmony_ci .get_fecparam = prestera_ethtool_get_fecparam, 7748c2ecf20Sopenharmony_ci .set_fecparam = prestera_ethtool_set_fecparam, 7758c2ecf20Sopenharmony_ci .get_sset_count = prestera_ethtool_get_sset_count, 7768c2ecf20Sopenharmony_ci .get_strings = prestera_ethtool_get_strings, 7778c2ecf20Sopenharmony_ci .get_ethtool_stats = prestera_ethtool_get_stats, 7788c2ecf20Sopenharmony_ci .get_link = ethtool_op_get_link, 7798c2ecf20Sopenharmony_ci .nway_reset = prestera_ethtool_nway_reset 7808c2ecf20Sopenharmony_ci}; 781