1 /* Ethtool support for Altera Triple-Speed Ethernet MAC driver 2 * Copyright (C) 2008-2014 Altera Corporation. All rights reserved 3 * 4 * Contributors: 5 * Dalon Westergreen 6 * Thomas Chou 7 * Ian Abbott 8 * Yuriy Kozlov 9 * Tobias Klauser 10 * Andriy Smolskyy 11 * Roman Bulgakov 12 * Dmytro Mytarchuk 13 * 14 * Original driver contributed by SLS. 15 * Major updates contributed by GlobalLogic 16 * 17 * This program is free software; you can redistribute it and/or modify it 18 * under the terms and conditions of the GNU General Public License, 19 * version 2, as published by the Free Software Foundation. 20 * 21 * This program is distributed in the hope it will be useful, but WITHOUT 22 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 23 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 24 * more details. 25 * 26 * You should have received a copy of the GNU General Public License along with 27 * this program. If not, see <http://www.gnu.org/licenses/>. 28 */ 29 30 #include <linux/ethtool.h> 31 #include <linux/kernel.h> 32 #include <linux/netdevice.h> 33 #include <linux/phy.h> 34 35 #include "altera_tse.h" 36 37 #define TSE_STATS_LEN 31 38 #define TSE_NUM_REGS 128 39 40 static char const stat_gstrings[][ETH_GSTRING_LEN] = { 41 "tx_packets", 42 "rx_packets", 43 "rx_crc_errors", 44 "rx_align_errors", 45 "tx_bytes", 46 "rx_bytes", 47 "tx_pause", 48 "rx_pause", 49 "rx_errors", 50 "tx_errors", 51 "rx_unicast", 52 "rx_multicast", 53 "rx_broadcast", 54 "tx_discards", 55 "tx_unicast", 56 "tx_multicast", 57 "tx_broadcast", 58 "ether_drops", 59 "rx_total_bytes", 60 "rx_total_packets", 61 "rx_undersize", 62 "rx_oversize", 63 "rx_64_bytes", 64 "rx_65_127_bytes", 65 "rx_128_255_bytes", 66 "rx_256_511_bytes", 67 "rx_512_1023_bytes", 68 "rx_1024_1518_bytes", 69 "rx_gte_1519_bytes", 70 "rx_jabbers", 71 "rx_runts", 72 }; 73 74 static void tse_get_drvinfo(struct net_device *dev, 75 struct ethtool_drvinfo *info) 76 { 77 struct altera_tse_private *priv = netdev_priv(dev); 78 u32 rev = ioread32(&priv->mac_dev->megacore_revision); 79 80 strcpy(info->driver, "altera_tse"); 81 strcpy(info->version, "v8.0"); 82 snprintf(info->fw_version, ETHTOOL_FWVERS_LEN, "v%d.%d", 83 rev & 0xFFFF, (rev & 0xFFFF0000) >> 16); 84 sprintf(info->bus_info, "platform"); 85 } 86 87 /* Fill in a buffer with the strings which correspond to the 88 * stats 89 */ 90 static void tse_gstrings(struct net_device *dev, u32 stringset, u8 *buf) 91 { 92 memcpy(buf, stat_gstrings, TSE_STATS_LEN * ETH_GSTRING_LEN); 93 } 94 95 static void tse_fill_stats(struct net_device *dev, struct ethtool_stats *dummy, 96 u64 *buf) 97 { 98 struct altera_tse_private *priv = netdev_priv(dev); 99 u64 ext; 100 101 buf[0] = csrrd32(priv->mac_dev, 102 tse_csroffs(frames_transmitted_ok)); 103 buf[1] = csrrd32(priv->mac_dev, 104 tse_csroffs(frames_received_ok)); 105 buf[2] = csrrd32(priv->mac_dev, 106 tse_csroffs(frames_check_sequence_errors)); 107 buf[3] = csrrd32(priv->mac_dev, 108 tse_csroffs(alignment_errors)); 109 110 /* Extended aOctetsTransmittedOK counter */ 111 ext = (u64) csrrd32(priv->mac_dev, 112 tse_csroffs(msb_octets_transmitted_ok)) << 32; 113 114 ext |= csrrd32(priv->mac_dev, 115 tse_csroffs(octets_transmitted_ok)); 116 buf[4] = ext; 117 118 /* Extended aOctetsReceivedOK counter */ 119 ext = (u64) csrrd32(priv->mac_dev, 120 tse_csroffs(msb_octets_received_ok)) << 32; 121 122 ext |= csrrd32(priv->mac_dev, 123 tse_csroffs(octets_received_ok)); 124 buf[5] = ext; 125 126 buf[6] = csrrd32(priv->mac_dev, 127 tse_csroffs(tx_pause_mac_ctrl_frames)); 128 buf[7] = csrrd32(priv->mac_dev, 129 tse_csroffs(rx_pause_mac_ctrl_frames)); 130 buf[8] = csrrd32(priv->mac_dev, 131 tse_csroffs(if_in_errors)); 132 buf[9] = csrrd32(priv->mac_dev, 133 tse_csroffs(if_out_errors)); 134 buf[10] = csrrd32(priv->mac_dev, 135 tse_csroffs(if_in_ucast_pkts)); 136 buf[11] = csrrd32(priv->mac_dev, 137 tse_csroffs(if_in_multicast_pkts)); 138 buf[12] = csrrd32(priv->mac_dev, 139 tse_csroffs(if_in_broadcast_pkts)); 140 buf[13] = csrrd32(priv->mac_dev, 141 tse_csroffs(if_out_discards)); 142 buf[14] = csrrd32(priv->mac_dev, 143 tse_csroffs(if_out_ucast_pkts)); 144 buf[15] = csrrd32(priv->mac_dev, 145 tse_csroffs(if_out_multicast_pkts)); 146 buf[16] = csrrd32(priv->mac_dev, 147 tse_csroffs(if_out_broadcast_pkts)); 148 buf[17] = csrrd32(priv->mac_dev, 149 tse_csroffs(ether_stats_drop_events)); 150 151 /* Extended etherStatsOctets counter */ 152 ext = (u64) csrrd32(priv->mac_dev, 153 tse_csroffs(msb_ether_stats_octets)) << 32; 154 ext |= csrrd32(priv->mac_dev, 155 tse_csroffs(ether_stats_octets)); 156 buf[18] = ext; 157 158 buf[19] = csrrd32(priv->mac_dev, 159 tse_csroffs(ether_stats_pkts)); 160 buf[20] = csrrd32(priv->mac_dev, 161 tse_csroffs(ether_stats_undersize_pkts)); 162 buf[21] = csrrd32(priv->mac_dev, 163 tse_csroffs(ether_stats_oversize_pkts)); 164 buf[22] = csrrd32(priv->mac_dev, 165 tse_csroffs(ether_stats_pkts_64_octets)); 166 buf[23] = csrrd32(priv->mac_dev, 167 tse_csroffs(ether_stats_pkts_65to127_octets)); 168 buf[24] = csrrd32(priv->mac_dev, 169 tse_csroffs(ether_stats_pkts_128to255_octets)); 170 buf[25] = csrrd32(priv->mac_dev, 171 tse_csroffs(ether_stats_pkts_256to511_octets)); 172 buf[26] = csrrd32(priv->mac_dev, 173 tse_csroffs(ether_stats_pkts_512to1023_octets)); 174 buf[27] = csrrd32(priv->mac_dev, 175 tse_csroffs(ether_stats_pkts_1024to1518_octets)); 176 buf[28] = csrrd32(priv->mac_dev, 177 tse_csroffs(ether_stats_pkts_1519tox_octets)); 178 buf[29] = csrrd32(priv->mac_dev, 179 tse_csroffs(ether_stats_jabbers)); 180 buf[30] = csrrd32(priv->mac_dev, 181 tse_csroffs(ether_stats_fragments)); 182 } 183 184 static int tse_sset_count(struct net_device *dev, int sset) 185 { 186 switch (sset) { 187 case ETH_SS_STATS: 188 return TSE_STATS_LEN; 189 default: 190 return -EOPNOTSUPP; 191 } 192 } 193 194 static u32 tse_get_msglevel(struct net_device *dev) 195 { 196 struct altera_tse_private *priv = netdev_priv(dev); 197 return priv->msg_enable; 198 } 199 200 static void tse_set_msglevel(struct net_device *dev, uint32_t data) 201 { 202 struct altera_tse_private *priv = netdev_priv(dev); 203 priv->msg_enable = data; 204 } 205 206 static int tse_reglen(struct net_device *dev) 207 { 208 return TSE_NUM_REGS * sizeof(u32); 209 } 210 211 static void tse_get_regs(struct net_device *dev, struct ethtool_regs *regs, 212 void *regbuf) 213 { 214 int i; 215 struct altera_tse_private *priv = netdev_priv(dev); 216 u32 *buf = regbuf; 217 218 /* Set version to a known value, so ethtool knows 219 * how to do any special formatting of this data. 220 * This version number will need to change if and 221 * when this register table is changed. 222 * 223 * version[31:0] = 1: Dump the first 128 TSE Registers 224 * Upper bits are all 0 by default 225 * 226 * Upper 16-bits will indicate feature presence for 227 * Ethtool register decoding in future version. 228 */ 229 230 regs->version = 1; 231 232 for (i = 0; i < TSE_NUM_REGS; i++) 233 buf[i] = csrrd32(priv->mac_dev, i * 4); 234 } 235 236 static int tse_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) 237 { 238 struct altera_tse_private *priv = netdev_priv(dev); 239 struct phy_device *phydev = priv->phydev; 240 241 if (phydev == NULL) 242 return -ENODEV; 243 244 return phy_ethtool_gset(phydev, cmd); 245 } 246 247 static int tse_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) 248 { 249 struct altera_tse_private *priv = netdev_priv(dev); 250 struct phy_device *phydev = priv->phydev; 251 252 if (phydev == NULL) 253 return -ENODEV; 254 255 return phy_ethtool_sset(phydev, cmd); 256 } 257 258 static const struct ethtool_ops tse_ethtool_ops = { 259 .get_drvinfo = tse_get_drvinfo, 260 .get_regs_len = tse_reglen, 261 .get_regs = tse_get_regs, 262 .get_link = ethtool_op_get_link, 263 .get_settings = tse_get_settings, 264 .set_settings = tse_set_settings, 265 .get_strings = tse_gstrings, 266 .get_sset_count = tse_sset_count, 267 .get_ethtool_stats = tse_fill_stats, 268 .get_msglevel = tse_get_msglevel, 269 .set_msglevel = tse_set_msglevel, 270 }; 271 272 void altera_tse_set_ethtool_ops(struct net_device *netdev) 273 { 274 netdev->ethtool_ops = &tse_ethtool_ops; 275 } 276