468 lines · c
1// SPDX-License-Identifier: GPL-2.02/* Marvell Octeon EP (EndPoint) Ethernet Driver3 *4 * Copyright (C) 2020 Marvell.5 *6 */7 8#include <linux/pci.h>9#include <linux/netdevice.h>10#include <linux/ethtool.h>11 12#include "octep_config.h"13#include "octep_main.h"14#include "octep_ctrl_net.h"15 16static const char octep_gstrings_global_stats[][ETH_GSTRING_LEN] = {17 "rx_packets",18 "tx_packets",19 "rx_bytes",20 "tx_bytes",21 "rx_alloc_errors",22 "tx_busy_errors",23 "rx_dropped",24 "tx_dropped",25 "tx_hw_pkts",26 "tx_hw_octs",27 "tx_hw_bcast",28 "tx_hw_mcast",29 "tx_hw_underflow",30 "tx_hw_control",31 "tx_less_than_64",32 "tx_equal_64",33 "tx_equal_65_to_127",34 "tx_equal_128_to_255",35 "tx_equal_256_to_511",36 "tx_equal_512_to_1023",37 "tx_equal_1024_to_1518",38 "tx_greater_than_1518",39 "rx_hw_pkts",40 "rx_hw_bytes",41 "rx_hw_bcast",42 "rx_hw_mcast",43 "rx_pause_pkts",44 "rx_pause_bytes",45 "rx_dropped_pkts_fifo_full",46 "rx_dropped_bytes_fifo_full",47 "rx_err_pkts",48};49 50#define OCTEP_GLOBAL_STATS_CNT (sizeof(octep_gstrings_global_stats) / ETH_GSTRING_LEN)51 52static const char octep_gstrings_tx_q_stats[][ETH_GSTRING_LEN] = {53 "tx_packets_posted[Q-%u]",54 "tx_packets_completed[Q-%u]",55 "tx_bytes[Q-%u]",56 "tx_busy[Q-%u]",57};58 59#define OCTEP_TX_Q_STATS_CNT (sizeof(octep_gstrings_tx_q_stats) / ETH_GSTRING_LEN)60 61static const char octep_gstrings_rx_q_stats[][ETH_GSTRING_LEN] = {62 "rx_packets[Q-%u]",63 "rx_bytes[Q-%u]",64 "rx_alloc_errors[Q-%u]",65};66 67#define OCTEP_RX_Q_STATS_CNT (sizeof(octep_gstrings_rx_q_stats) / ETH_GSTRING_LEN)68 69static void octep_get_drvinfo(struct net_device *netdev,70 struct ethtool_drvinfo *info)71{72 struct octep_device *oct = netdev_priv(netdev);73 74 strscpy(info->driver, OCTEP_DRV_NAME, sizeof(info->driver));75 strscpy(info->bus_info, pci_name(oct->pdev), sizeof(info->bus_info));76}77 78static void octep_get_strings(struct net_device *netdev,79 u32 stringset, u8 *data)80{81 struct octep_device *oct = netdev_priv(netdev);82 u16 num_queues = CFG_GET_PORTS_ACTIVE_IO_RINGS(oct->conf);83 char *strings = (char *)data;84 int i, j;85 86 switch (stringset) {87 case ETH_SS_STATS:88 for (i = 0; i < OCTEP_GLOBAL_STATS_CNT; i++) {89 snprintf(strings, ETH_GSTRING_LEN,90 octep_gstrings_global_stats[i]);91 strings += ETH_GSTRING_LEN;92 }93 94 for (i = 0; i < num_queues; i++) {95 for (j = 0; j < OCTEP_TX_Q_STATS_CNT; j++) {96 snprintf(strings, ETH_GSTRING_LEN,97 octep_gstrings_tx_q_stats[j], i);98 strings += ETH_GSTRING_LEN;99 }100 }101 102 for (i = 0; i < num_queues; i++) {103 for (j = 0; j < OCTEP_RX_Q_STATS_CNT; j++) {104 snprintf(strings, ETH_GSTRING_LEN,105 octep_gstrings_rx_q_stats[j], i);106 strings += ETH_GSTRING_LEN;107 }108 }109 break;110 default:111 break;112 }113}114 115static int octep_get_sset_count(struct net_device *netdev, int sset)116{117 struct octep_device *oct = netdev_priv(netdev);118 u16 num_queues = CFG_GET_PORTS_ACTIVE_IO_RINGS(oct->conf);119 120 switch (sset) {121 case ETH_SS_STATS:122 return OCTEP_GLOBAL_STATS_CNT + (num_queues *123 (OCTEP_TX_Q_STATS_CNT + OCTEP_RX_Q_STATS_CNT));124 break;125 default:126 return -EOPNOTSUPP;127 }128}129 130static void131octep_get_ethtool_stats(struct net_device *netdev,132 struct ethtool_stats *stats, u64 *data)133{134 struct octep_device *oct = netdev_priv(netdev);135 struct octep_iface_tx_stats *iface_tx_stats;136 struct octep_iface_rx_stats *iface_rx_stats;137 u64 rx_packets, rx_bytes;138 u64 tx_packets, tx_bytes;139 u64 rx_alloc_errors, tx_busy_errors;140 int q, i;141 142 rx_packets = 0;143 rx_bytes = 0;144 tx_packets = 0;145 tx_bytes = 0;146 rx_alloc_errors = 0;147 tx_busy_errors = 0;148 tx_packets = 0;149 tx_bytes = 0;150 rx_packets = 0;151 rx_bytes = 0;152 153 iface_tx_stats = &oct->iface_tx_stats;154 iface_rx_stats = &oct->iface_rx_stats;155 octep_ctrl_net_get_if_stats(oct,156 OCTEP_CTRL_NET_INVALID_VFID,157 iface_rx_stats,158 iface_tx_stats);159 160 for (q = 0; q < oct->num_oqs; q++) {161 struct octep_iq *iq = oct->iq[q];162 struct octep_oq *oq = oct->oq[q];163 164 tx_packets += iq->stats.instr_completed;165 tx_bytes += iq->stats.bytes_sent;166 tx_busy_errors += iq->stats.tx_busy;167 168 rx_packets += oq->stats.packets;169 rx_bytes += oq->stats.bytes;170 rx_alloc_errors += oq->stats.alloc_failures;171 }172 i = 0;173 data[i++] = rx_packets;174 data[i++] = tx_packets;175 data[i++] = rx_bytes;176 data[i++] = tx_bytes;177 data[i++] = rx_alloc_errors;178 data[i++] = tx_busy_errors;179 data[i++] = iface_rx_stats->dropped_pkts_fifo_full +180 iface_rx_stats->err_pkts;181 data[i++] = iface_tx_stats->xscol +182 iface_tx_stats->xsdef;183 data[i++] = iface_tx_stats->pkts;184 data[i++] = iface_tx_stats->octs;185 data[i++] = iface_tx_stats->bcst;186 data[i++] = iface_tx_stats->mcst;187 data[i++] = iface_tx_stats->undflw;188 data[i++] = iface_tx_stats->ctl;189 data[i++] = iface_tx_stats->hist_lt64;190 data[i++] = iface_tx_stats->hist_eq64;191 data[i++] = iface_tx_stats->hist_65to127;192 data[i++] = iface_tx_stats->hist_128to255;193 data[i++] = iface_tx_stats->hist_256to511;194 data[i++] = iface_tx_stats->hist_512to1023;195 data[i++] = iface_tx_stats->hist_1024to1518;196 data[i++] = iface_tx_stats->hist_gt1518;197 data[i++] = iface_rx_stats->pkts;198 data[i++] = iface_rx_stats->octets;199 data[i++] = iface_rx_stats->mcast_pkts;200 data[i++] = iface_rx_stats->bcast_pkts;201 data[i++] = iface_rx_stats->pause_pkts;202 data[i++] = iface_rx_stats->pause_octets;203 data[i++] = iface_rx_stats->dropped_pkts_fifo_full;204 data[i++] = iface_rx_stats->dropped_octets_fifo_full;205 data[i++] = iface_rx_stats->err_pkts;206 207 /* Per Tx Queue stats */208 for (q = 0; q < oct->num_iqs; q++) {209 struct octep_iq *iq = oct->iq[q];210 211 data[i++] = iq->stats.instr_posted;212 data[i++] = iq->stats.instr_completed;213 data[i++] = iq->stats.bytes_sent;214 data[i++] = iq->stats.tx_busy;215 }216 217 /* Per Rx Queue stats */218 for (q = 0; q < oct->num_oqs; q++) {219 struct octep_oq *oq = oct->oq[q];220 221 data[i++] = oq->stats.packets;222 data[i++] = oq->stats.bytes;223 data[i++] = oq->stats.alloc_failures;224 }225}226 227#define OCTEP_SET_ETHTOOL_LINK_MODES_BITMAP(octep_speeds, ksettings, name) \228{ \229 if ((octep_speeds) & BIT(OCTEP_LINK_MODE_10GBASE_T)) \230 ethtool_link_ksettings_add_link_mode(ksettings, name, 10000baseT_Full); \231 if ((octep_speeds) & BIT(OCTEP_LINK_MODE_10GBASE_R)) \232 ethtool_link_ksettings_add_link_mode(ksettings, name, 10000baseR_FEC); \233 if ((octep_speeds) & BIT(OCTEP_LINK_MODE_10GBASE_CR)) \234 ethtool_link_ksettings_add_link_mode(ksettings, name, 10000baseCR_Full); \235 if ((octep_speeds) & BIT(OCTEP_LINK_MODE_10GBASE_KR)) \236 ethtool_link_ksettings_add_link_mode(ksettings, name, 10000baseKR_Full); \237 if ((octep_speeds) & BIT(OCTEP_LINK_MODE_10GBASE_LR)) \238 ethtool_link_ksettings_add_link_mode(ksettings, name, 10000baseLR_Full); \239 if ((octep_speeds) & BIT(OCTEP_LINK_MODE_10GBASE_SR)) \240 ethtool_link_ksettings_add_link_mode(ksettings, name, 10000baseSR_Full); \241 if ((octep_speeds) & BIT(OCTEP_LINK_MODE_25GBASE_CR)) \242 ethtool_link_ksettings_add_link_mode(ksettings, name, 25000baseCR_Full); \243 if ((octep_speeds) & BIT(OCTEP_LINK_MODE_25GBASE_KR)) \244 ethtool_link_ksettings_add_link_mode(ksettings, name, 25000baseKR_Full); \245 if ((octep_speeds) & BIT(OCTEP_LINK_MODE_25GBASE_SR)) \246 ethtool_link_ksettings_add_link_mode(ksettings, name, 25000baseSR_Full); \247 if ((octep_speeds) & BIT(OCTEP_LINK_MODE_40GBASE_CR4)) \248 ethtool_link_ksettings_add_link_mode(ksettings, name, 40000baseCR4_Full); \249 if ((octep_speeds) & BIT(OCTEP_LINK_MODE_40GBASE_KR4)) \250 ethtool_link_ksettings_add_link_mode(ksettings, name, 40000baseKR4_Full); \251 if ((octep_speeds) & BIT(OCTEP_LINK_MODE_40GBASE_LR4)) \252 ethtool_link_ksettings_add_link_mode(ksettings, name, 40000baseLR4_Full); \253 if ((octep_speeds) & BIT(OCTEP_LINK_MODE_40GBASE_SR4)) \254 ethtool_link_ksettings_add_link_mode(ksettings, name, 40000baseSR4_Full); \255 if ((octep_speeds) & BIT(OCTEP_LINK_MODE_50GBASE_CR2)) \256 ethtool_link_ksettings_add_link_mode(ksettings, name, 50000baseCR2_Full); \257 if ((octep_speeds) & BIT(OCTEP_LINK_MODE_50GBASE_KR2)) \258 ethtool_link_ksettings_add_link_mode(ksettings, name, 50000baseKR2_Full); \259 if ((octep_speeds) & BIT(OCTEP_LINK_MODE_50GBASE_SR2)) \260 ethtool_link_ksettings_add_link_mode(ksettings, name, 50000baseSR2_Full); \261 if ((octep_speeds) & BIT(OCTEP_LINK_MODE_50GBASE_CR)) \262 ethtool_link_ksettings_add_link_mode(ksettings, name, 50000baseCR_Full); \263 if ((octep_speeds) & BIT(OCTEP_LINK_MODE_50GBASE_KR)) \264 ethtool_link_ksettings_add_link_mode(ksettings, name, 50000baseKR_Full); \265 if ((octep_speeds) & BIT(OCTEP_LINK_MODE_50GBASE_LR)) \266 ethtool_link_ksettings_add_link_mode(ksettings, name, 50000baseLR_ER_FR_Full); \267 if ((octep_speeds) & BIT(OCTEP_LINK_MODE_50GBASE_SR)) \268 ethtool_link_ksettings_add_link_mode(ksettings, name, 50000baseSR_Full); \269 if ((octep_speeds) & BIT(OCTEP_LINK_MODE_100GBASE_CR4)) \270 ethtool_link_ksettings_add_link_mode(ksettings, name, 100000baseCR4_Full); \271 if ((octep_speeds) & BIT(OCTEP_LINK_MODE_100GBASE_KR4)) \272 ethtool_link_ksettings_add_link_mode(ksettings, name, 100000baseKR4_Full); \273 if ((octep_speeds) & BIT(OCTEP_LINK_MODE_100GBASE_LR4)) \274 ethtool_link_ksettings_add_link_mode(ksettings, name, 100000baseLR4_ER4_Full); \275 if ((octep_speeds) & BIT(OCTEP_LINK_MODE_100GBASE_SR4)) \276 ethtool_link_ksettings_add_link_mode(ksettings, name, 100000baseSR4_Full); \277}278 279static int octep_get_link_ksettings(struct net_device *netdev,280 struct ethtool_link_ksettings *cmd)281{282 struct octep_device *oct = netdev_priv(netdev);283 struct octep_iface_link_info *link_info;284 u32 advertised_modes, supported_modes;285 286 ethtool_link_ksettings_zero_link_mode(cmd, supported);287 ethtool_link_ksettings_zero_link_mode(cmd, advertising);288 289 link_info = &oct->link_info;290 octep_ctrl_net_get_link_info(oct, OCTEP_CTRL_NET_INVALID_VFID, link_info);291 292 advertised_modes = oct->link_info.advertised_modes;293 supported_modes = oct->link_info.supported_modes;294 295 OCTEP_SET_ETHTOOL_LINK_MODES_BITMAP(supported_modes, cmd, supported);296 OCTEP_SET_ETHTOOL_LINK_MODES_BITMAP(advertised_modes, cmd, advertising);297 298 if (link_info->autoneg) {299 if (link_info->autoneg & OCTEP_LINK_MODE_AUTONEG_SUPPORTED)300 ethtool_link_ksettings_add_link_mode(cmd, supported, Autoneg);301 if (link_info->autoneg & OCTEP_LINK_MODE_AUTONEG_ADVERTISED) {302 ethtool_link_ksettings_add_link_mode(cmd, advertising, Autoneg);303 cmd->base.autoneg = AUTONEG_ENABLE;304 } else {305 cmd->base.autoneg = AUTONEG_DISABLE;306 }307 } else {308 cmd->base.autoneg = AUTONEG_DISABLE;309 }310 311 if (link_info->pause) {312 if (link_info->pause & OCTEP_LINK_MODE_PAUSE_SUPPORTED)313 ethtool_link_ksettings_add_link_mode(cmd, supported, Pause);314 if (link_info->pause & OCTEP_LINK_MODE_PAUSE_ADVERTISED)315 ethtool_link_ksettings_add_link_mode(cmd, advertising, Pause);316 }317 318 cmd->base.port = PORT_FIBRE;319 ethtool_link_ksettings_add_link_mode(cmd, supported, FIBRE);320 ethtool_link_ksettings_add_link_mode(cmd, advertising, FIBRE);321 322 if (netif_carrier_ok(netdev)) {323 cmd->base.speed = link_info->speed;324 cmd->base.duplex = DUPLEX_FULL;325 } else {326 cmd->base.speed = SPEED_UNKNOWN;327 cmd->base.duplex = DUPLEX_UNKNOWN;328 }329 return 0;330}331 332static int octep_set_link_ksettings(struct net_device *netdev,333 const struct ethtool_link_ksettings *cmd)334{335 struct octep_device *oct = netdev_priv(netdev);336 struct octep_iface_link_info link_info_new;337 struct octep_iface_link_info *link_info;338 u64 advertised = 0;339 u8 autoneg = 0;340 int err;341 342 link_info = &oct->link_info;343 memcpy(&link_info_new, link_info, sizeof(struct octep_iface_link_info));344 345 /* Only Full duplex is supported;346 * Assume full duplex when duplex is unknown.347 */348 if (cmd->base.duplex != DUPLEX_FULL &&349 cmd->base.duplex != DUPLEX_UNKNOWN)350 return -EOPNOTSUPP;351 352 if (cmd->base.autoneg == AUTONEG_ENABLE) {353 if (!(link_info->autoneg & OCTEP_LINK_MODE_AUTONEG_SUPPORTED))354 return -EOPNOTSUPP;355 autoneg = 1;356 }357 358 if (!bitmap_subset(cmd->link_modes.advertising,359 cmd->link_modes.supported,360 __ETHTOOL_LINK_MODE_MASK_NBITS))361 return -EINVAL;362 363 if (ethtool_link_ksettings_test_link_mode(cmd, advertising,364 10000baseT_Full))365 advertised |= BIT(OCTEP_LINK_MODE_10GBASE_T);366 if (ethtool_link_ksettings_test_link_mode(cmd, advertising,367 10000baseR_FEC))368 advertised |= BIT(OCTEP_LINK_MODE_10GBASE_R);369 if (ethtool_link_ksettings_test_link_mode(cmd, advertising,370 10000baseCR_Full))371 advertised |= BIT(OCTEP_LINK_MODE_10GBASE_CR);372 if (ethtool_link_ksettings_test_link_mode(cmd, advertising,373 10000baseKR_Full))374 advertised |= BIT(OCTEP_LINK_MODE_10GBASE_KR);375 if (ethtool_link_ksettings_test_link_mode(cmd, advertising,376 10000baseLR_Full))377 advertised |= BIT(OCTEP_LINK_MODE_10GBASE_LR);378 if (ethtool_link_ksettings_test_link_mode(cmd, advertising,379 10000baseSR_Full))380 advertised |= BIT(OCTEP_LINK_MODE_10GBASE_SR);381 if (ethtool_link_ksettings_test_link_mode(cmd, advertising,382 25000baseCR_Full))383 advertised |= BIT(OCTEP_LINK_MODE_25GBASE_CR);384 if (ethtool_link_ksettings_test_link_mode(cmd, advertising,385 25000baseKR_Full))386 advertised |= BIT(OCTEP_LINK_MODE_25GBASE_KR);387 if (ethtool_link_ksettings_test_link_mode(cmd, advertising,388 25000baseSR_Full))389 advertised |= BIT(OCTEP_LINK_MODE_25GBASE_SR);390 if (ethtool_link_ksettings_test_link_mode(cmd, advertising,391 40000baseCR4_Full))392 advertised |= BIT(OCTEP_LINK_MODE_40GBASE_CR4);393 if (ethtool_link_ksettings_test_link_mode(cmd, advertising,394 40000baseKR4_Full))395 advertised |= BIT(OCTEP_LINK_MODE_40GBASE_KR4);396 if (ethtool_link_ksettings_test_link_mode(cmd, advertising,397 40000baseLR4_Full))398 advertised |= BIT(OCTEP_LINK_MODE_40GBASE_LR4);399 if (ethtool_link_ksettings_test_link_mode(cmd, advertising,400 40000baseSR4_Full))401 advertised |= BIT(OCTEP_LINK_MODE_40GBASE_SR4);402 if (ethtool_link_ksettings_test_link_mode(cmd, advertising,403 50000baseCR2_Full))404 advertised |= BIT(OCTEP_LINK_MODE_50GBASE_CR2);405 if (ethtool_link_ksettings_test_link_mode(cmd, advertising,406 50000baseKR2_Full))407 advertised |= BIT(OCTEP_LINK_MODE_50GBASE_KR2);408 if (ethtool_link_ksettings_test_link_mode(cmd, advertising,409 50000baseSR2_Full))410 advertised |= BIT(OCTEP_LINK_MODE_50GBASE_SR2);411 if (ethtool_link_ksettings_test_link_mode(cmd, advertising,412 50000baseCR_Full))413 advertised |= BIT(OCTEP_LINK_MODE_50GBASE_CR);414 if (ethtool_link_ksettings_test_link_mode(cmd, advertising,415 50000baseKR_Full))416 advertised |= BIT(OCTEP_LINK_MODE_50GBASE_KR);417 if (ethtool_link_ksettings_test_link_mode(cmd, advertising,418 50000baseLR_ER_FR_Full))419 advertised |= BIT(OCTEP_LINK_MODE_50GBASE_LR);420 if (ethtool_link_ksettings_test_link_mode(cmd, advertising,421 50000baseSR_Full))422 advertised |= BIT(OCTEP_LINK_MODE_50GBASE_SR);423 if (ethtool_link_ksettings_test_link_mode(cmd, advertising,424 100000baseCR4_Full))425 advertised |= BIT(OCTEP_LINK_MODE_100GBASE_CR4);426 if (ethtool_link_ksettings_test_link_mode(cmd, advertising,427 100000baseKR4_Full))428 advertised |= BIT(OCTEP_LINK_MODE_100GBASE_KR4);429 if (ethtool_link_ksettings_test_link_mode(cmd, advertising,430 100000baseLR4_ER4_Full))431 advertised |= BIT(OCTEP_LINK_MODE_100GBASE_LR4);432 if (ethtool_link_ksettings_test_link_mode(cmd, advertising,433 100000baseSR4_Full))434 advertised |= BIT(OCTEP_LINK_MODE_100GBASE_SR4);435 436 if (advertised == link_info->advertised_modes &&437 cmd->base.speed == link_info->speed &&438 cmd->base.autoneg == link_info->autoneg)439 return 0;440 441 link_info_new.advertised_modes = advertised;442 link_info_new.speed = cmd->base.speed;443 link_info_new.autoneg = autoneg;444 445 err = octep_ctrl_net_set_link_info(oct, OCTEP_CTRL_NET_INVALID_VFID,446 &link_info_new, true);447 if (err)448 return err;449 450 memcpy(link_info, &link_info_new, sizeof(struct octep_iface_link_info));451 return 0;452}453 454static const struct ethtool_ops octep_ethtool_ops = {455 .get_drvinfo = octep_get_drvinfo,456 .get_link = ethtool_op_get_link,457 .get_strings = octep_get_strings,458 .get_sset_count = octep_get_sset_count,459 .get_ethtool_stats = octep_get_ethtool_stats,460 .get_link_ksettings = octep_get_link_ksettings,461 .set_link_ksettings = octep_set_link_ksettings,462};463 464void octep_set_ethtool_ops(struct net_device *netdev)465{466 netdev->ethtool_ops = &octep_ethtool_ops;467}468