xref: /linux/drivers/net/ethernet/altera/altera_tse_ethtool.c (revision 898305806ad56ae11dc2c80931062e6a2c7bba48)
16c3324a9SVince Bridgers /* Ethtool support for Altera Triple-Speed Ethernet MAC driver
26c3324a9SVince Bridgers  * Copyright (C) 2008-2014 Altera Corporation. All rights reserved
36c3324a9SVince Bridgers  *
46c3324a9SVince Bridgers  * Contributors:
56c3324a9SVince Bridgers  *   Dalon Westergreen
66c3324a9SVince Bridgers  *   Thomas Chou
76c3324a9SVince Bridgers  *   Ian Abbott
86c3324a9SVince Bridgers  *   Yuriy Kozlov
96c3324a9SVince Bridgers  *   Tobias Klauser
106c3324a9SVince Bridgers  *   Andriy Smolskyy
116c3324a9SVince Bridgers  *   Roman Bulgakov
126c3324a9SVince Bridgers  *   Dmytro Mytarchuk
136c3324a9SVince Bridgers  *
146c3324a9SVince Bridgers  * Original driver contributed by SLS.
156c3324a9SVince Bridgers  * Major updates contributed by GlobalLogic
166c3324a9SVince Bridgers  *
176c3324a9SVince Bridgers  * This program is free software; you can redistribute it and/or modify it
186c3324a9SVince Bridgers  * under the terms and conditions of the GNU General Public License,
196c3324a9SVince Bridgers  * version 2, as published by the Free Software Foundation.
206c3324a9SVince Bridgers  *
216c3324a9SVince Bridgers  * This program is distributed in the hope it will be useful, but WITHOUT
226c3324a9SVince Bridgers  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
236c3324a9SVince Bridgers  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
246c3324a9SVince Bridgers  * more details.
256c3324a9SVince Bridgers  *
266c3324a9SVince Bridgers  * You should have received a copy of the GNU General Public License along with
276c3324a9SVince Bridgers  * this program.  If not, see <http://www.gnu.org/licenses/>.
286c3324a9SVince Bridgers  */
296c3324a9SVince Bridgers 
306c3324a9SVince Bridgers #include <linux/ethtool.h>
316c3324a9SVince Bridgers #include <linux/kernel.h>
326c3324a9SVince Bridgers #include <linux/netdevice.h>
336c3324a9SVince Bridgers #include <linux/phy.h>
346c3324a9SVince Bridgers 
356c3324a9SVince Bridgers #include "altera_tse.h"
366c3324a9SVince Bridgers 
376c3324a9SVince Bridgers #define TSE_STATS_LEN	31
386c3324a9SVince Bridgers #define TSE_NUM_REGS	128
396c3324a9SVince Bridgers 
406c3324a9SVince Bridgers static char const stat_gstrings[][ETH_GSTRING_LEN] = {
416c3324a9SVince Bridgers 	"tx_packets",
426c3324a9SVince Bridgers 	"rx_packets",
436c3324a9SVince Bridgers 	"rx_crc_errors",
446c3324a9SVince Bridgers 	"rx_align_errors",
456c3324a9SVince Bridgers 	"tx_bytes",
466c3324a9SVince Bridgers 	"rx_bytes",
476c3324a9SVince Bridgers 	"tx_pause",
486c3324a9SVince Bridgers 	"rx_pause",
496c3324a9SVince Bridgers 	"rx_errors",
506c3324a9SVince Bridgers 	"tx_errors",
516c3324a9SVince Bridgers 	"rx_unicast",
526c3324a9SVince Bridgers 	"rx_multicast",
536c3324a9SVince Bridgers 	"rx_broadcast",
546c3324a9SVince Bridgers 	"tx_discards",
556c3324a9SVince Bridgers 	"tx_unicast",
566c3324a9SVince Bridgers 	"tx_multicast",
576c3324a9SVince Bridgers 	"tx_broadcast",
586c3324a9SVince Bridgers 	"ether_drops",
596c3324a9SVince Bridgers 	"rx_total_bytes",
606c3324a9SVince Bridgers 	"rx_total_packets",
616c3324a9SVince Bridgers 	"rx_undersize",
626c3324a9SVince Bridgers 	"rx_oversize",
636c3324a9SVince Bridgers 	"rx_64_bytes",
646c3324a9SVince Bridgers 	"rx_65_127_bytes",
656c3324a9SVince Bridgers 	"rx_128_255_bytes",
666c3324a9SVince Bridgers 	"rx_256_511_bytes",
676c3324a9SVince Bridgers 	"rx_512_1023_bytes",
686c3324a9SVince Bridgers 	"rx_1024_1518_bytes",
696c3324a9SVince Bridgers 	"rx_gte_1519_bytes",
706c3324a9SVince Bridgers 	"rx_jabbers",
716c3324a9SVince Bridgers 	"rx_runts",
726c3324a9SVince Bridgers };
736c3324a9SVince Bridgers 
746c3324a9SVince Bridgers static void tse_get_drvinfo(struct net_device *dev,
756c3324a9SVince Bridgers 			    struct ethtool_drvinfo *info)
766c3324a9SVince Bridgers {
776c3324a9SVince Bridgers 	struct altera_tse_private *priv = netdev_priv(dev);
786c3324a9SVince Bridgers 	u32 rev = ioread32(&priv->mac_dev->megacore_revision);
796c3324a9SVince Bridgers 
8099514e11SVince Bridgers 	strcpy(info->driver, "altera_tse");
816c3324a9SVince Bridgers 	strcpy(info->version, "v8.0");
826c3324a9SVince Bridgers 	snprintf(info->fw_version, ETHTOOL_FWVERS_LEN, "v%d.%d",
836c3324a9SVince Bridgers 		 rev & 0xFFFF, (rev & 0xFFFF0000) >> 16);
846c3324a9SVince Bridgers 	sprintf(info->bus_info, "platform");
856c3324a9SVince Bridgers }
866c3324a9SVince Bridgers 
876c3324a9SVince Bridgers /* Fill in a buffer with the strings which correspond to the
886c3324a9SVince Bridgers  * stats
896c3324a9SVince Bridgers  */
906c3324a9SVince Bridgers static void tse_gstrings(struct net_device *dev, u32 stringset, u8 *buf)
916c3324a9SVince Bridgers {
926c3324a9SVince Bridgers 	memcpy(buf, stat_gstrings, TSE_STATS_LEN * ETH_GSTRING_LEN);
936c3324a9SVince Bridgers }
946c3324a9SVince Bridgers 
956c3324a9SVince Bridgers static void tse_fill_stats(struct net_device *dev, struct ethtool_stats *dummy,
966c3324a9SVince Bridgers 			   u64 *buf)
976c3324a9SVince Bridgers {
986c3324a9SVince Bridgers 	struct altera_tse_private *priv = netdev_priv(dev);
996c3324a9SVince Bridgers 	u64 ext;
1006c3324a9SVince Bridgers 
101*89830580SVince Bridgers 	buf[0] = csrrd32(priv->mac_dev,
102*89830580SVince Bridgers 			 tse_csroffs(frames_transmitted_ok));
103*89830580SVince Bridgers 	buf[1] = csrrd32(priv->mac_dev,
104*89830580SVince Bridgers 			 tse_csroffs(frames_received_ok));
105*89830580SVince Bridgers 	buf[2] = csrrd32(priv->mac_dev,
106*89830580SVince Bridgers 			 tse_csroffs(frames_check_sequence_errors));
107*89830580SVince Bridgers 	buf[3] = csrrd32(priv->mac_dev,
108*89830580SVince Bridgers 			 tse_csroffs(alignment_errors));
1096c3324a9SVince Bridgers 
1106c3324a9SVince Bridgers 	/* Extended aOctetsTransmittedOK counter */
111*89830580SVince Bridgers 	ext = (u64) csrrd32(priv->mac_dev,
112*89830580SVince Bridgers 			    tse_csroffs(msb_octets_transmitted_ok)) << 32;
113*89830580SVince Bridgers 
114*89830580SVince Bridgers 	ext |= csrrd32(priv->mac_dev,
115*89830580SVince Bridgers 		       tse_csroffs(octets_transmitted_ok));
1166c3324a9SVince Bridgers 	buf[4] = ext;
1176c3324a9SVince Bridgers 
1186c3324a9SVince Bridgers 	/* Extended aOctetsReceivedOK counter */
119*89830580SVince Bridgers 	ext = (u64) csrrd32(priv->mac_dev,
120*89830580SVince Bridgers 			    tse_csroffs(msb_octets_received_ok)) << 32;
121*89830580SVince Bridgers 
122*89830580SVince Bridgers 	ext |= csrrd32(priv->mac_dev,
123*89830580SVince Bridgers 		       tse_csroffs(octets_received_ok));
1246c3324a9SVince Bridgers 	buf[5] = ext;
1256c3324a9SVince Bridgers 
126*89830580SVince Bridgers 	buf[6] = csrrd32(priv->mac_dev,
127*89830580SVince Bridgers 			 tse_csroffs(tx_pause_mac_ctrl_frames));
128*89830580SVince Bridgers 	buf[7] = csrrd32(priv->mac_dev,
129*89830580SVince Bridgers 			 tse_csroffs(rx_pause_mac_ctrl_frames));
130*89830580SVince Bridgers 	buf[8] = csrrd32(priv->mac_dev,
131*89830580SVince Bridgers 			 tse_csroffs(if_in_errors));
132*89830580SVince Bridgers 	buf[9] = csrrd32(priv->mac_dev,
133*89830580SVince Bridgers 			 tse_csroffs(if_out_errors));
134*89830580SVince Bridgers 	buf[10] = csrrd32(priv->mac_dev,
135*89830580SVince Bridgers 			  tse_csroffs(if_in_ucast_pkts));
136*89830580SVince Bridgers 	buf[11] = csrrd32(priv->mac_dev,
137*89830580SVince Bridgers 			  tse_csroffs(if_in_multicast_pkts));
138*89830580SVince Bridgers 	buf[12] = csrrd32(priv->mac_dev,
139*89830580SVince Bridgers 			  tse_csroffs(if_in_broadcast_pkts));
140*89830580SVince Bridgers 	buf[13] = csrrd32(priv->mac_dev,
141*89830580SVince Bridgers 			  tse_csroffs(if_out_discards));
142*89830580SVince Bridgers 	buf[14] = csrrd32(priv->mac_dev,
143*89830580SVince Bridgers 			  tse_csroffs(if_out_ucast_pkts));
144*89830580SVince Bridgers 	buf[15] = csrrd32(priv->mac_dev,
145*89830580SVince Bridgers 			  tse_csroffs(if_out_multicast_pkts));
146*89830580SVince Bridgers 	buf[16] = csrrd32(priv->mac_dev,
147*89830580SVince Bridgers 			  tse_csroffs(if_out_broadcast_pkts));
148*89830580SVince Bridgers 	buf[17] = csrrd32(priv->mac_dev,
149*89830580SVince Bridgers 			  tse_csroffs(ether_stats_drop_events));
1506c3324a9SVince Bridgers 
1516c3324a9SVince Bridgers 	/* Extended etherStatsOctets counter */
152*89830580SVince Bridgers 	ext = (u64) csrrd32(priv->mac_dev,
153*89830580SVince Bridgers 			    tse_csroffs(msb_ether_stats_octets)) << 32;
154*89830580SVince Bridgers 	ext |= csrrd32(priv->mac_dev,
155*89830580SVince Bridgers 		       tse_csroffs(ether_stats_octets));
1566c3324a9SVince Bridgers 	buf[18] = ext;
1576c3324a9SVince Bridgers 
158*89830580SVince Bridgers 	buf[19] = csrrd32(priv->mac_dev,
159*89830580SVince Bridgers 			  tse_csroffs(ether_stats_pkts));
160*89830580SVince Bridgers 	buf[20] = csrrd32(priv->mac_dev,
161*89830580SVince Bridgers 			  tse_csroffs(ether_stats_undersize_pkts));
162*89830580SVince Bridgers 	buf[21] = csrrd32(priv->mac_dev,
163*89830580SVince Bridgers 			  tse_csroffs(ether_stats_oversize_pkts));
164*89830580SVince Bridgers 	buf[22] = csrrd32(priv->mac_dev,
165*89830580SVince Bridgers 			  tse_csroffs(ether_stats_pkts_64_octets));
166*89830580SVince Bridgers 	buf[23] = csrrd32(priv->mac_dev,
167*89830580SVince Bridgers 			  tse_csroffs(ether_stats_pkts_65to127_octets));
168*89830580SVince Bridgers 	buf[24] = csrrd32(priv->mac_dev,
169*89830580SVince Bridgers 			  tse_csroffs(ether_stats_pkts_128to255_octets));
170*89830580SVince Bridgers 	buf[25] = csrrd32(priv->mac_dev,
171*89830580SVince Bridgers 			  tse_csroffs(ether_stats_pkts_256to511_octets));
172*89830580SVince Bridgers 	buf[26] = csrrd32(priv->mac_dev,
173*89830580SVince Bridgers 			  tse_csroffs(ether_stats_pkts_512to1023_octets));
174*89830580SVince Bridgers 	buf[27] = csrrd32(priv->mac_dev,
175*89830580SVince Bridgers 			  tse_csroffs(ether_stats_pkts_1024to1518_octets));
176*89830580SVince Bridgers 	buf[28] = csrrd32(priv->mac_dev,
177*89830580SVince Bridgers 			  tse_csroffs(ether_stats_pkts_1519tox_octets));
178*89830580SVince Bridgers 	buf[29] = csrrd32(priv->mac_dev,
179*89830580SVince Bridgers 			  tse_csroffs(ether_stats_jabbers));
180*89830580SVince Bridgers 	buf[30] = csrrd32(priv->mac_dev,
181*89830580SVince Bridgers 			  tse_csroffs(ether_stats_fragments));
1826c3324a9SVince Bridgers }
1836c3324a9SVince Bridgers 
1846c3324a9SVince Bridgers static int tse_sset_count(struct net_device *dev, int sset)
1856c3324a9SVince Bridgers {
1866c3324a9SVince Bridgers 	switch (sset) {
1876c3324a9SVince Bridgers 	case ETH_SS_STATS:
1886c3324a9SVince Bridgers 		return TSE_STATS_LEN;
1896c3324a9SVince Bridgers 	default:
1906c3324a9SVince Bridgers 		return -EOPNOTSUPP;
1916c3324a9SVince Bridgers 	}
1926c3324a9SVince Bridgers }
1936c3324a9SVince Bridgers 
1946c3324a9SVince Bridgers static u32 tse_get_msglevel(struct net_device *dev)
1956c3324a9SVince Bridgers {
1966c3324a9SVince Bridgers 	struct altera_tse_private *priv = netdev_priv(dev);
1976c3324a9SVince Bridgers 	return priv->msg_enable;
1986c3324a9SVince Bridgers }
1996c3324a9SVince Bridgers 
2006c3324a9SVince Bridgers static void tse_set_msglevel(struct net_device *dev, uint32_t data)
2016c3324a9SVince Bridgers {
2026c3324a9SVince Bridgers 	struct altera_tse_private *priv = netdev_priv(dev);
2036c3324a9SVince Bridgers 	priv->msg_enable = data;
2046c3324a9SVince Bridgers }
2056c3324a9SVince Bridgers 
2066c3324a9SVince Bridgers static int tse_reglen(struct net_device *dev)
2076c3324a9SVince Bridgers {
2086c3324a9SVince Bridgers 	return TSE_NUM_REGS * sizeof(u32);
2096c3324a9SVince Bridgers }
2106c3324a9SVince Bridgers 
2116c3324a9SVince Bridgers static void tse_get_regs(struct net_device *dev, struct ethtool_regs *regs,
2126c3324a9SVince Bridgers 			 void *regbuf)
2136c3324a9SVince Bridgers {
2146c3324a9SVince Bridgers 	int i;
2156c3324a9SVince Bridgers 	struct altera_tse_private *priv = netdev_priv(dev);
2166c3324a9SVince Bridgers 	u32 *buf = regbuf;
2176c3324a9SVince Bridgers 
2188adfc3aeSVince Bridgers 	/* Set version to a known value, so ethtool knows
2198adfc3aeSVince Bridgers 	 * how to do any special formatting of this data.
2208adfc3aeSVince Bridgers 	 * This version number will need to change if and
2218adfc3aeSVince Bridgers 	 * when this register table is changed.
22299514e11SVince Bridgers 	 *
22399514e11SVince Bridgers 	 * version[31:0] = 1: Dump the first 128 TSE Registers
22499514e11SVince Bridgers 	 *      Upper bits are all 0 by default
22599514e11SVince Bridgers 	 *
22699514e11SVince Bridgers 	 * Upper 16-bits will indicate feature presence for
22799514e11SVince Bridgers 	 * Ethtool register decoding in future version.
2288adfc3aeSVince Bridgers 	 */
2298adfc3aeSVince Bridgers 
2308adfc3aeSVince Bridgers 	regs->version = 1;
2318adfc3aeSVince Bridgers 
2326c3324a9SVince Bridgers 	for (i = 0; i < TSE_NUM_REGS; i++)
233*89830580SVince Bridgers 		buf[i] = csrrd32(priv->mac_dev, i * 4);
2346c3324a9SVince Bridgers }
2356c3324a9SVince Bridgers 
2366c3324a9SVince Bridgers static int tse_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
2376c3324a9SVince Bridgers {
2386c3324a9SVince Bridgers 	struct altera_tse_private *priv = netdev_priv(dev);
2396c3324a9SVince Bridgers 	struct phy_device *phydev = priv->phydev;
2406c3324a9SVince Bridgers 
2416c3324a9SVince Bridgers 	if (phydev == NULL)
2426c3324a9SVince Bridgers 		return -ENODEV;
2436c3324a9SVince Bridgers 
2446c3324a9SVince Bridgers 	return phy_ethtool_gset(phydev, cmd);
2456c3324a9SVince Bridgers }
2466c3324a9SVince Bridgers 
2476c3324a9SVince Bridgers static int tse_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
2486c3324a9SVince Bridgers {
2496c3324a9SVince Bridgers 	struct altera_tse_private *priv = netdev_priv(dev);
2506c3324a9SVince Bridgers 	struct phy_device *phydev = priv->phydev;
2516c3324a9SVince Bridgers 
2526c3324a9SVince Bridgers 	if (phydev == NULL)
2536c3324a9SVince Bridgers 		return -ENODEV;
2546c3324a9SVince Bridgers 
2556c3324a9SVince Bridgers 	return phy_ethtool_sset(phydev, cmd);
2566c3324a9SVince Bridgers }
2576c3324a9SVince Bridgers 
2586c3324a9SVince Bridgers static const struct ethtool_ops tse_ethtool_ops = {
2596c3324a9SVince Bridgers 	.get_drvinfo = tse_get_drvinfo,
2606c3324a9SVince Bridgers 	.get_regs_len = tse_reglen,
2616c3324a9SVince Bridgers 	.get_regs = tse_get_regs,
2626c3324a9SVince Bridgers 	.get_link = ethtool_op_get_link,
2636c3324a9SVince Bridgers 	.get_settings = tse_get_settings,
2646c3324a9SVince Bridgers 	.set_settings = tse_set_settings,
2656c3324a9SVince Bridgers 	.get_strings = tse_gstrings,
2666c3324a9SVince Bridgers 	.get_sset_count = tse_sset_count,
2676c3324a9SVince Bridgers 	.get_ethtool_stats = tse_fill_stats,
2686c3324a9SVince Bridgers 	.get_msglevel = tse_get_msglevel,
2696c3324a9SVince Bridgers 	.set_msglevel = tse_set_msglevel,
2706c3324a9SVince Bridgers };
2716c3324a9SVince Bridgers 
2726c3324a9SVince Bridgers void altera_tse_set_ethtool_ops(struct net_device *netdev)
2736c3324a9SVince Bridgers {
2746c3324a9SVince Bridgers 	SET_ETHTOOL_OPS(netdev, &tse_ethtool_ops);
2756c3324a9SVince Bridgers }
276