274 lines · c
1// SPDX-License-Identifier: GPL-2.02/* Marvell Octeon EP (EndPoint) VF 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_vf_config.h"13#include "octep_vf_main.h"14 15static const char octep_vf_gstrings_global_stats[][ETH_GSTRING_LEN] = {16 "rx_alloc_errors",17 "tx_busy_errors",18 "tx_hw_pkts",19 "tx_hw_octs",20 "tx_hw_bcast",21 "tx_hw_mcast",22 "rx_hw_pkts",23 "rx_hw_bytes",24 "rx_hw_bcast",25 "rx_dropped_bytes_fifo_full",26};27 28#define OCTEP_VF_GLOBAL_STATS_CNT (sizeof(octep_vf_gstrings_global_stats) / ETH_GSTRING_LEN)29 30static const char octep_vf_gstrings_tx_q_stats[][ETH_GSTRING_LEN] = {31 "tx_packets_posted[Q-%u]",32 "tx_packets_completed[Q-%u]",33 "tx_bytes[Q-%u]",34 "tx_busy[Q-%u]",35};36 37#define OCTEP_VF_TX_Q_STATS_CNT (sizeof(octep_vf_gstrings_tx_q_stats) / ETH_GSTRING_LEN)38 39static const char octep_vf_gstrings_rx_q_stats[][ETH_GSTRING_LEN] = {40 "rx_packets[Q-%u]",41 "rx_bytes[Q-%u]",42 "rx_alloc_errors[Q-%u]",43};44 45#define OCTEP_VF_RX_Q_STATS_CNT (sizeof(octep_vf_gstrings_rx_q_stats) / ETH_GSTRING_LEN)46 47static void octep_vf_get_drvinfo(struct net_device *netdev,48 struct ethtool_drvinfo *info)49{50 struct octep_vf_device *oct = netdev_priv(netdev);51 52 strscpy(info->driver, OCTEP_VF_DRV_NAME, sizeof(info->driver));53 strscpy(info->bus_info, pci_name(oct->pdev), sizeof(info->bus_info));54}55 56static void octep_vf_get_strings(struct net_device *netdev,57 u32 stringset, u8 *data)58{59 struct octep_vf_device *oct = netdev_priv(netdev);60 u16 num_queues = CFG_GET_PORTS_ACTIVE_IO_RINGS(oct->conf);61 char *strings = (char *)data;62 int i, j;63 64 switch (stringset) {65 case ETH_SS_STATS:66 for (i = 0; i < OCTEP_VF_GLOBAL_STATS_CNT; i++) {67 snprintf(strings, ETH_GSTRING_LEN,68 octep_vf_gstrings_global_stats[i]);69 strings += ETH_GSTRING_LEN;70 }71 72 for (i = 0; i < num_queues; i++) {73 for (j = 0; j < OCTEP_VF_TX_Q_STATS_CNT; j++) {74 snprintf(strings, ETH_GSTRING_LEN,75 octep_vf_gstrings_tx_q_stats[j], i);76 strings += ETH_GSTRING_LEN;77 }78 }79 80 for (i = 0; i < num_queues; i++) {81 for (j = 0; j < OCTEP_VF_RX_Q_STATS_CNT; j++) {82 snprintf(strings, ETH_GSTRING_LEN,83 octep_vf_gstrings_rx_q_stats[j], i);84 strings += ETH_GSTRING_LEN;85 }86 }87 break;88 default:89 break;90 }91}92 93static int octep_vf_get_sset_count(struct net_device *netdev, int sset)94{95 struct octep_vf_device *oct = netdev_priv(netdev);96 u16 num_queues = CFG_GET_PORTS_ACTIVE_IO_RINGS(oct->conf);97 98 switch (sset) {99 case ETH_SS_STATS:100 return OCTEP_VF_GLOBAL_STATS_CNT + (num_queues *101 (OCTEP_VF_TX_Q_STATS_CNT + OCTEP_VF_RX_Q_STATS_CNT));102 break;103 default:104 return -EOPNOTSUPP;105 }106}107 108static void octep_vf_get_ethtool_stats(struct net_device *netdev,109 struct ethtool_stats *stats, u64 *data)110{111 struct octep_vf_device *oct = netdev_priv(netdev);112 struct octep_vf_iface_tx_stats *iface_tx_stats;113 struct octep_vf_iface_rx_stats *iface_rx_stats;114 u64 rx_alloc_errors, tx_busy_errors;115 int q, i;116 117 rx_alloc_errors = 0;118 tx_busy_errors = 0;119 120 octep_vf_get_if_stats(oct);121 iface_tx_stats = &oct->iface_tx_stats;122 iface_rx_stats = &oct->iface_rx_stats;123 124 for (q = 0; q < oct->num_oqs; q++) {125 struct octep_vf_iq *iq = oct->iq[q];126 struct octep_vf_oq *oq = oct->oq[q];127 128 tx_busy_errors += iq->stats.tx_busy;129 rx_alloc_errors += oq->stats.alloc_failures;130 }131 i = 0;132 data[i++] = rx_alloc_errors;133 data[i++] = tx_busy_errors;134 data[i++] = iface_tx_stats->pkts;135 data[i++] = iface_tx_stats->octs;136 data[i++] = iface_tx_stats->bcst;137 data[i++] = iface_tx_stats->mcst;138 data[i++] = iface_rx_stats->pkts;139 data[i++] = iface_rx_stats->octets;140 data[i++] = iface_rx_stats->bcast_pkts;141 data[i++] = iface_rx_stats->dropped_octets_fifo_full;142 143 /* Per Tx Queue stats */144 for (q = 0; q < oct->num_iqs; q++) {145 struct octep_vf_iq *iq = oct->iq[q];146 147 data[i++] = iq->stats.instr_posted;148 data[i++] = iq->stats.instr_completed;149 data[i++] = iq->stats.bytes_sent;150 data[i++] = iq->stats.tx_busy;151 }152 153 /* Per Rx Queue stats */154 for (q = 0; q < oct->num_oqs; q++) {155 struct octep_vf_oq *oq = oct->oq[q];156 157 data[i++] = oq->stats.packets;158 data[i++] = oq->stats.bytes;159 data[i++] = oq->stats.alloc_failures;160 }161}162 163#define OCTEP_VF_SET_ETHTOOL_LINK_MODES_BITMAP(octep_vf_speeds, ksettings, name) \164{ \165 if ((octep_vf_speeds) & BIT(OCTEP_VF_LINK_MODE_10GBASE_T)) \166 ethtool_link_ksettings_add_link_mode(ksettings, name, 10000baseT_Full); \167 if ((octep_vf_speeds) & BIT(OCTEP_VF_LINK_MODE_10GBASE_R)) \168 ethtool_link_ksettings_add_link_mode(ksettings, name, 10000baseR_FEC); \169 if ((octep_vf_speeds) & BIT(OCTEP_VF_LINK_MODE_10GBASE_CR)) \170 ethtool_link_ksettings_add_link_mode(ksettings, name, 10000baseCR_Full); \171 if ((octep_vf_speeds) & BIT(OCTEP_VF_LINK_MODE_10GBASE_KR)) \172 ethtool_link_ksettings_add_link_mode(ksettings, name, 10000baseKR_Full); \173 if ((octep_vf_speeds) & BIT(OCTEP_VF_LINK_MODE_10GBASE_LR)) \174 ethtool_link_ksettings_add_link_mode(ksettings, name, 10000baseLR_Full); \175 if ((octep_vf_speeds) & BIT(OCTEP_VF_LINK_MODE_10GBASE_SR)) \176 ethtool_link_ksettings_add_link_mode(ksettings, name, 10000baseSR_Full); \177 if ((octep_vf_speeds) & BIT(OCTEP_VF_LINK_MODE_25GBASE_CR)) \178 ethtool_link_ksettings_add_link_mode(ksettings, name, 25000baseCR_Full); \179 if ((octep_vf_speeds) & BIT(OCTEP_VF_LINK_MODE_25GBASE_KR)) \180 ethtool_link_ksettings_add_link_mode(ksettings, name, 25000baseKR_Full); \181 if ((octep_vf_speeds) & BIT(OCTEP_VF_LINK_MODE_25GBASE_SR)) \182 ethtool_link_ksettings_add_link_mode(ksettings, name, 25000baseSR_Full); \183 if ((octep_vf_speeds) & BIT(OCTEP_VF_LINK_MODE_40GBASE_CR4)) \184 ethtool_link_ksettings_add_link_mode(ksettings, name, 40000baseCR4_Full); \185 if ((octep_vf_speeds) & BIT(OCTEP_VF_LINK_MODE_40GBASE_KR4)) \186 ethtool_link_ksettings_add_link_mode(ksettings, name, 40000baseKR4_Full); \187 if ((octep_vf_speeds) & BIT(OCTEP_VF_LINK_MODE_40GBASE_LR4)) \188 ethtool_link_ksettings_add_link_mode(ksettings, name, 40000baseLR4_Full); \189 if ((octep_vf_speeds) & BIT(OCTEP_VF_LINK_MODE_40GBASE_SR4)) \190 ethtool_link_ksettings_add_link_mode(ksettings, name, 40000baseSR4_Full); \191 if ((octep_vf_speeds) & BIT(OCTEP_VF_LINK_MODE_50GBASE_CR2)) \192 ethtool_link_ksettings_add_link_mode(ksettings, name, 50000baseCR2_Full); \193 if ((octep_vf_speeds) & BIT(OCTEP_VF_LINK_MODE_50GBASE_KR2)) \194 ethtool_link_ksettings_add_link_mode(ksettings, name, 50000baseKR2_Full); \195 if ((octep_vf_speeds) & BIT(OCTEP_VF_LINK_MODE_50GBASE_SR2)) \196 ethtool_link_ksettings_add_link_mode(ksettings, name, 50000baseSR2_Full); \197 if ((octep_vf_speeds) & BIT(OCTEP_VF_LINK_MODE_50GBASE_CR)) \198 ethtool_link_ksettings_add_link_mode(ksettings, name, 50000baseCR_Full); \199 if ((octep_vf_speeds) & BIT(OCTEP_VF_LINK_MODE_50GBASE_KR)) \200 ethtool_link_ksettings_add_link_mode(ksettings, name, 50000baseKR_Full); \201 if ((octep_vf_speeds) & BIT(OCTEP_VF_LINK_MODE_50GBASE_LR)) \202 ethtool_link_ksettings_add_link_mode(ksettings, name, 50000baseLR_ER_FR_Full); \203 if ((octep_vf_speeds) & BIT(OCTEP_VF_LINK_MODE_50GBASE_SR)) \204 ethtool_link_ksettings_add_link_mode(ksettings, name, 50000baseSR_Full); \205 if ((octep_vf_speeds) & BIT(OCTEP_VF_LINK_MODE_100GBASE_CR4)) \206 ethtool_link_ksettings_add_link_mode(ksettings, name, 100000baseCR4_Full); \207 if ((octep_vf_speeds) & BIT(OCTEP_VF_LINK_MODE_100GBASE_KR4)) \208 ethtool_link_ksettings_add_link_mode(ksettings, name, 100000baseKR4_Full); \209 if ((octep_vf_speeds) & BIT(OCTEP_VF_LINK_MODE_100GBASE_LR4)) \210 ethtool_link_ksettings_add_link_mode(ksettings, name, 100000baseLR4_ER4_Full); \211 if ((octep_vf_speeds) & BIT(OCTEP_VF_LINK_MODE_100GBASE_SR4)) \212 ethtool_link_ksettings_add_link_mode(ksettings, name, 100000baseSR4_Full); \213}214 215static int octep_vf_get_link_ksettings(struct net_device *netdev,216 struct ethtool_link_ksettings *cmd)217{218 struct octep_vf_device *oct = netdev_priv(netdev);219 struct octep_vf_iface_link_info *link_info;220 u32 advertised_modes, supported_modes;221 222 ethtool_link_ksettings_zero_link_mode(cmd, supported);223 ethtool_link_ksettings_zero_link_mode(cmd, advertising);224 225 octep_vf_get_link_info(oct);226 227 advertised_modes = oct->link_info.advertised_modes;228 supported_modes = oct->link_info.supported_modes;229 link_info = &oct->link_info;230 231 OCTEP_VF_SET_ETHTOOL_LINK_MODES_BITMAP(supported_modes, cmd, supported);232 OCTEP_VF_SET_ETHTOOL_LINK_MODES_BITMAP(advertised_modes, cmd, advertising);233 234 if (link_info->autoneg) {235 if (link_info->autoneg & OCTEP_VF_LINK_MODE_AUTONEG_SUPPORTED)236 ethtool_link_ksettings_add_link_mode(cmd, supported, Autoneg);237 if (link_info->autoneg & OCTEP_VF_LINK_MODE_AUTONEG_ADVERTISED) {238 ethtool_link_ksettings_add_link_mode(cmd, advertising, Autoneg);239 cmd->base.autoneg = AUTONEG_ENABLE;240 } else {241 cmd->base.autoneg = AUTONEG_DISABLE;242 }243 } else {244 cmd->base.autoneg = AUTONEG_DISABLE;245 }246 247 cmd->base.port = PORT_FIBRE;248 ethtool_link_ksettings_add_link_mode(cmd, supported, FIBRE);249 ethtool_link_ksettings_add_link_mode(cmd, advertising, FIBRE);250 251 if (netif_carrier_ok(netdev)) {252 cmd->base.speed = link_info->speed;253 cmd->base.duplex = DUPLEX_FULL;254 } else {255 cmd->base.speed = SPEED_UNKNOWN;256 cmd->base.duplex = DUPLEX_UNKNOWN;257 }258 return 0;259}260 261static const struct ethtool_ops octep_vf_ethtool_ops = {262 .get_drvinfo = octep_vf_get_drvinfo,263 .get_link = ethtool_op_get_link,264 .get_strings = octep_vf_get_strings,265 .get_sset_count = octep_vf_get_sset_count,266 .get_ethtool_stats = octep_vf_get_ethtool_stats,267 .get_link_ksettings = octep_vf_get_link_ksettings,268};269 270void octep_vf_set_ethtool_ops(struct net_device *netdev)271{272 netdev->ethtool_ops = &octep_vf_ethtool_ops;273}274