259 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/* Ethtool support for Altera Triple-Speed Ethernet MAC driver3 * Copyright (C) 2008-2014 Altera Corporation. All rights reserved4 *5 * Contributors:6 * Dalon Westergreen7 * Thomas Chou8 * Ian Abbott9 * Yuriy Kozlov10 * Tobias Klauser11 * Andriy Smolskyy12 * Roman Bulgakov13 * Dmytro Mytarchuk14 *15 * Original driver contributed by SLS.16 * Major updates contributed by GlobalLogic17 */18 19#include <linux/ethtool.h>20#include <linux/kernel.h>21#include <linux/netdevice.h>22#include <linux/phy.h>23 24#include "altera_tse.h"25 26#define TSE_STATS_LEN 3127#define TSE_NUM_REGS 12828 29static char const stat_gstrings[][ETH_GSTRING_LEN] = {30 "tx_packets",31 "rx_packets",32 "rx_crc_errors",33 "rx_align_errors",34 "tx_bytes",35 "rx_bytes",36 "tx_pause",37 "rx_pause",38 "rx_errors",39 "tx_errors",40 "rx_unicast",41 "rx_multicast",42 "rx_broadcast",43 "tx_discards",44 "tx_unicast",45 "tx_multicast",46 "tx_broadcast",47 "ether_drops",48 "rx_total_bytes",49 "rx_total_packets",50 "rx_undersize",51 "rx_oversize",52 "rx_64_bytes",53 "rx_65_127_bytes",54 "rx_128_255_bytes",55 "rx_256_511_bytes",56 "rx_512_1023_bytes",57 "rx_1024_1518_bytes",58 "rx_gte_1519_bytes",59 "rx_jabbers",60 "rx_runts",61};62 63static void tse_get_drvinfo(struct net_device *dev,64 struct ethtool_drvinfo *info)65{66 struct altera_tse_private *priv = netdev_priv(dev);67 u32 rev = ioread32(&priv->mac_dev->megacore_revision);68 69 strcpy(info->driver, "altera_tse");70 snprintf(info->fw_version, ETHTOOL_FWVERS_LEN, "v%d.%d",71 rev & 0xFFFF, (rev & 0xFFFF0000) >> 16);72 sprintf(info->bus_info, "platform");73}74 75/* Fill in a buffer with the strings which correspond to the76 * stats77 */78static void tse_gstrings(struct net_device *dev, u32 stringset, u8 *buf)79{80 memcpy(buf, stat_gstrings, TSE_STATS_LEN * ETH_GSTRING_LEN);81}82 83static void tse_fill_stats(struct net_device *dev, struct ethtool_stats *dummy,84 u64 *buf)85{86 struct altera_tse_private *priv = netdev_priv(dev);87 u64 ext;88 89 buf[0] = csrrd32(priv->mac_dev,90 tse_csroffs(frames_transmitted_ok));91 buf[1] = csrrd32(priv->mac_dev,92 tse_csroffs(frames_received_ok));93 buf[2] = csrrd32(priv->mac_dev,94 tse_csroffs(frames_check_sequence_errors));95 buf[3] = csrrd32(priv->mac_dev,96 tse_csroffs(alignment_errors));97 98 /* Extended aOctetsTransmittedOK counter */99 ext = (u64) csrrd32(priv->mac_dev,100 tse_csroffs(msb_octets_transmitted_ok)) << 32;101 102 ext |= csrrd32(priv->mac_dev,103 tse_csroffs(octets_transmitted_ok));104 buf[4] = ext;105 106 /* Extended aOctetsReceivedOK counter */107 ext = (u64) csrrd32(priv->mac_dev,108 tse_csroffs(msb_octets_received_ok)) << 32;109 110 ext |= csrrd32(priv->mac_dev,111 tse_csroffs(octets_received_ok));112 buf[5] = ext;113 114 buf[6] = csrrd32(priv->mac_dev,115 tse_csroffs(tx_pause_mac_ctrl_frames));116 buf[7] = csrrd32(priv->mac_dev,117 tse_csroffs(rx_pause_mac_ctrl_frames));118 buf[8] = csrrd32(priv->mac_dev,119 tse_csroffs(if_in_errors));120 buf[9] = csrrd32(priv->mac_dev,121 tse_csroffs(if_out_errors));122 buf[10] = csrrd32(priv->mac_dev,123 tse_csroffs(if_in_ucast_pkts));124 buf[11] = csrrd32(priv->mac_dev,125 tse_csroffs(if_in_multicast_pkts));126 buf[12] = csrrd32(priv->mac_dev,127 tse_csroffs(if_in_broadcast_pkts));128 buf[13] = csrrd32(priv->mac_dev,129 tse_csroffs(if_out_discards));130 buf[14] = csrrd32(priv->mac_dev,131 tse_csroffs(if_out_ucast_pkts));132 buf[15] = csrrd32(priv->mac_dev,133 tse_csroffs(if_out_multicast_pkts));134 buf[16] = csrrd32(priv->mac_dev,135 tse_csroffs(if_out_broadcast_pkts));136 buf[17] = csrrd32(priv->mac_dev,137 tse_csroffs(ether_stats_drop_events));138 139 /* Extended etherStatsOctets counter */140 ext = (u64) csrrd32(priv->mac_dev,141 tse_csroffs(msb_ether_stats_octets)) << 32;142 ext |= csrrd32(priv->mac_dev,143 tse_csroffs(ether_stats_octets));144 buf[18] = ext;145 146 buf[19] = csrrd32(priv->mac_dev,147 tse_csroffs(ether_stats_pkts));148 buf[20] = csrrd32(priv->mac_dev,149 tse_csroffs(ether_stats_undersize_pkts));150 buf[21] = csrrd32(priv->mac_dev,151 tse_csroffs(ether_stats_oversize_pkts));152 buf[22] = csrrd32(priv->mac_dev,153 tse_csroffs(ether_stats_pkts_64_octets));154 buf[23] = csrrd32(priv->mac_dev,155 tse_csroffs(ether_stats_pkts_65to127_octets));156 buf[24] = csrrd32(priv->mac_dev,157 tse_csroffs(ether_stats_pkts_128to255_octets));158 buf[25] = csrrd32(priv->mac_dev,159 tse_csroffs(ether_stats_pkts_256to511_octets));160 buf[26] = csrrd32(priv->mac_dev,161 tse_csroffs(ether_stats_pkts_512to1023_octets));162 buf[27] = csrrd32(priv->mac_dev,163 tse_csroffs(ether_stats_pkts_1024to1518_octets));164 buf[28] = csrrd32(priv->mac_dev,165 tse_csroffs(ether_stats_pkts_1519tox_octets));166 buf[29] = csrrd32(priv->mac_dev,167 tse_csroffs(ether_stats_jabbers));168 buf[30] = csrrd32(priv->mac_dev,169 tse_csroffs(ether_stats_fragments));170}171 172static int tse_sset_count(struct net_device *dev, int sset)173{174 switch (sset) {175 case ETH_SS_STATS:176 return TSE_STATS_LEN;177 default:178 return -EOPNOTSUPP;179 }180}181 182static u32 tse_get_msglevel(struct net_device *dev)183{184 struct altera_tse_private *priv = netdev_priv(dev);185 return priv->msg_enable;186}187 188static void tse_set_msglevel(struct net_device *dev, uint32_t data)189{190 struct altera_tse_private *priv = netdev_priv(dev);191 priv->msg_enable = data;192}193 194static int tse_reglen(struct net_device *dev)195{196 return TSE_NUM_REGS * sizeof(u32);197}198 199static void tse_get_regs(struct net_device *dev, struct ethtool_regs *regs,200 void *regbuf)201{202 struct altera_tse_private *priv = netdev_priv(dev);203 u32 *buf = regbuf;204 int i;205 206 /* Set version to a known value, so ethtool knows207 * how to do any special formatting of this data.208 * This version number will need to change if and209 * when this register table is changed.210 *211 * version[31:0] = 1: Dump the first 128 TSE Registers212 * Upper bits are all 0 by default213 *214 * Upper 16-bits will indicate feature presence for215 * Ethtool register decoding in future version.216 */217 218 regs->version = 1;219 220 for (i = 0; i < TSE_NUM_REGS; i++)221 buf[i] = csrrd32(priv->mac_dev, i * 4);222}223 224static int tse_ethtool_set_link_ksettings(struct net_device *dev,225 const struct ethtool_link_ksettings *cmd)226{227 struct altera_tse_private *priv = netdev_priv(dev);228 229 return phylink_ethtool_ksettings_set(priv->phylink, cmd);230}231 232static int tse_ethtool_get_link_ksettings(struct net_device *dev,233 struct ethtool_link_ksettings *cmd)234{235 struct altera_tse_private *priv = netdev_priv(dev);236 237 return phylink_ethtool_ksettings_get(priv->phylink, cmd);238}239 240static const struct ethtool_ops tse_ethtool_ops = {241 .get_drvinfo = tse_get_drvinfo,242 .get_regs_len = tse_reglen,243 .get_regs = tse_get_regs,244 .get_link = ethtool_op_get_link,245 .get_strings = tse_gstrings,246 .get_sset_count = tse_sset_count,247 .get_ethtool_stats = tse_fill_stats,248 .get_msglevel = tse_get_msglevel,249 .set_msglevel = tse_set_msglevel,250 .get_link_ksettings = tse_ethtool_get_link_ksettings,251 .set_link_ksettings = tse_ethtool_set_link_ksettings,252 .get_ts_info = ethtool_op_get_ts_info,253};254 255void altera_tse_set_ethtool_ops(struct net_device *netdev)256{257 netdev->ethtool_ops = &tse_ethtool_ops;258}259