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 MAC IP Driver"); 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 struct altera_tse_mac *mac = priv->mac_dev; 100 u64 ext; 101 102 buf[0] = ioread32(&mac->frames_transmitted_ok); 103 buf[1] = ioread32(&mac->frames_received_ok); 104 buf[2] = ioread32(&mac->frames_check_sequence_errors); 105 buf[3] = ioread32(&mac->alignment_errors); 106 107 /* Extended aOctetsTransmittedOK counter */ 108 ext = (u64) ioread32(&mac->msb_octets_transmitted_ok) << 32; 109 ext |= ioread32(&mac->octets_transmitted_ok); 110 buf[4] = ext; 111 112 /* Extended aOctetsReceivedOK counter */ 113 ext = (u64) ioread32(&mac->msb_octets_received_ok) << 32; 114 ext |= ioread32(&mac->octets_received_ok); 115 buf[5] = ext; 116 117 buf[6] = ioread32(&mac->tx_pause_mac_ctrl_frames); 118 buf[7] = ioread32(&mac->rx_pause_mac_ctrl_frames); 119 buf[8] = ioread32(&mac->if_in_errors); 120 buf[9] = ioread32(&mac->if_out_errors); 121 buf[10] = ioread32(&mac->if_in_ucast_pkts); 122 buf[11] = ioread32(&mac->if_in_multicast_pkts); 123 buf[12] = ioread32(&mac->if_in_broadcast_pkts); 124 buf[13] = ioread32(&mac->if_out_discards); 125 buf[14] = ioread32(&mac->if_out_ucast_pkts); 126 buf[15] = ioread32(&mac->if_out_multicast_pkts); 127 buf[16] = ioread32(&mac->if_out_broadcast_pkts); 128 buf[17] = ioread32(&mac->ether_stats_drop_events); 129 130 /* Extended etherStatsOctets counter */ 131 ext = (u64) ioread32(&mac->msb_ether_stats_octets) << 32; 132 ext |= ioread32(&mac->ether_stats_octets); 133 buf[18] = ext; 134 135 buf[19] = ioread32(&mac->ether_stats_pkts); 136 buf[20] = ioread32(&mac->ether_stats_undersize_pkts); 137 buf[21] = ioread32(&mac->ether_stats_oversize_pkts); 138 buf[22] = ioread32(&mac->ether_stats_pkts_64_octets); 139 buf[23] = ioread32(&mac->ether_stats_pkts_65to127_octets); 140 buf[24] = ioread32(&mac->ether_stats_pkts_128to255_octets); 141 buf[25] = ioread32(&mac->ether_stats_pkts_256to511_octets); 142 buf[26] = ioread32(&mac->ether_stats_pkts_512to1023_octets); 143 buf[27] = ioread32(&mac->ether_stats_pkts_1024to1518_octets); 144 buf[28] = ioread32(&mac->ether_stats_pkts_1519tox_octets); 145 buf[29] = ioread32(&mac->ether_stats_jabbers); 146 buf[30] = ioread32(&mac->ether_stats_fragments); 147 } 148 149 static int tse_sset_count(struct net_device *dev, int sset) 150 { 151 switch (sset) { 152 case ETH_SS_STATS: 153 return TSE_STATS_LEN; 154 default: 155 return -EOPNOTSUPP; 156 } 157 } 158 159 static u32 tse_get_msglevel(struct net_device *dev) 160 { 161 struct altera_tse_private *priv = netdev_priv(dev); 162 return priv->msg_enable; 163 } 164 165 static void tse_set_msglevel(struct net_device *dev, uint32_t data) 166 { 167 struct altera_tse_private *priv = netdev_priv(dev); 168 priv->msg_enable = data; 169 } 170 171 static int tse_reglen(struct net_device *dev) 172 { 173 return TSE_NUM_REGS * sizeof(u32); 174 } 175 176 static void tse_get_regs(struct net_device *dev, struct ethtool_regs *regs, 177 void *regbuf) 178 { 179 int i; 180 struct altera_tse_private *priv = netdev_priv(dev); 181 u32 *tse_mac_regs = (u32 *)priv->mac_dev; 182 u32 *buf = regbuf; 183 184 /* Set version to a known value, so ethtool knows 185 * how to do any special formatting of this data. 186 * This version number will need to change if and 187 * when this register table is changed. 188 */ 189 190 regs->version = 1; 191 192 for (i = 0; i < TSE_NUM_REGS; i++) 193 buf[i] = ioread32(&tse_mac_regs[i]); 194 } 195 196 static int tse_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) 197 { 198 struct altera_tse_private *priv = netdev_priv(dev); 199 struct phy_device *phydev = priv->phydev; 200 201 if (phydev == NULL) 202 return -ENODEV; 203 204 return phy_ethtool_gset(phydev, cmd); 205 } 206 207 static int tse_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) 208 { 209 struct altera_tse_private *priv = netdev_priv(dev); 210 struct phy_device *phydev = priv->phydev; 211 212 if (phydev == NULL) 213 return -ENODEV; 214 215 return phy_ethtool_sset(phydev, cmd); 216 } 217 218 static const struct ethtool_ops tse_ethtool_ops = { 219 .get_drvinfo = tse_get_drvinfo, 220 .get_regs_len = tse_reglen, 221 .get_regs = tse_get_regs, 222 .get_link = ethtool_op_get_link, 223 .get_settings = tse_get_settings, 224 .set_settings = tse_set_settings, 225 .get_strings = tse_gstrings, 226 .get_sset_count = tse_sset_count, 227 .get_ethtool_stats = tse_fill_stats, 228 .get_msglevel = tse_get_msglevel, 229 .set_msglevel = tse_set_msglevel, 230 }; 231 232 void altera_tse_set_ethtool_ops(struct net_device *netdev) 233 { 234 SET_ETHTOOL_OPS(netdev, &tse_ethtool_ops); 235 } 236