xref: /linux/drivers/net/ethernet/altera/altera_tse_ethtool.c (revision 7ad24ea4bf620a32631d7b3069c3e30c078b0c3e)
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 	struct altera_tse_mac *mac = priv->mac_dev;
1006c3324a9SVince Bridgers 	u64 ext;
1016c3324a9SVince Bridgers 
1026c3324a9SVince Bridgers 	buf[0] = ioread32(&mac->frames_transmitted_ok);
1036c3324a9SVince Bridgers 	buf[1] = ioread32(&mac->frames_received_ok);
1046c3324a9SVince Bridgers 	buf[2] = ioread32(&mac->frames_check_sequence_errors);
1056c3324a9SVince Bridgers 	buf[3] = ioread32(&mac->alignment_errors);
1066c3324a9SVince Bridgers 
1076c3324a9SVince Bridgers 	/* Extended aOctetsTransmittedOK counter */
1086c3324a9SVince Bridgers 	ext = (u64) ioread32(&mac->msb_octets_transmitted_ok) << 32;
1096c3324a9SVince Bridgers 	ext |= ioread32(&mac->octets_transmitted_ok);
1106c3324a9SVince Bridgers 	buf[4] = ext;
1116c3324a9SVince Bridgers 
1126c3324a9SVince Bridgers 	/* Extended aOctetsReceivedOK counter */
1136c3324a9SVince Bridgers 	ext = (u64) ioread32(&mac->msb_octets_received_ok) << 32;
1146c3324a9SVince Bridgers 	ext |= ioread32(&mac->octets_received_ok);
1156c3324a9SVince Bridgers 	buf[5] = ext;
1166c3324a9SVince Bridgers 
1176c3324a9SVince Bridgers 	buf[6] = ioread32(&mac->tx_pause_mac_ctrl_frames);
1186c3324a9SVince Bridgers 	buf[7] = ioread32(&mac->rx_pause_mac_ctrl_frames);
1196c3324a9SVince Bridgers 	buf[8] = ioread32(&mac->if_in_errors);
1206c3324a9SVince Bridgers 	buf[9] = ioread32(&mac->if_out_errors);
1216c3324a9SVince Bridgers 	buf[10] = ioread32(&mac->if_in_ucast_pkts);
1226c3324a9SVince Bridgers 	buf[11] = ioread32(&mac->if_in_multicast_pkts);
1236c3324a9SVince Bridgers 	buf[12] = ioread32(&mac->if_in_broadcast_pkts);
1246c3324a9SVince Bridgers 	buf[13] = ioread32(&mac->if_out_discards);
1256c3324a9SVince Bridgers 	buf[14] = ioread32(&mac->if_out_ucast_pkts);
1266c3324a9SVince Bridgers 	buf[15] = ioread32(&mac->if_out_multicast_pkts);
1276c3324a9SVince Bridgers 	buf[16] = ioread32(&mac->if_out_broadcast_pkts);
1286c3324a9SVince Bridgers 	buf[17] = ioread32(&mac->ether_stats_drop_events);
1296c3324a9SVince Bridgers 
1306c3324a9SVince Bridgers 	/* Extended etherStatsOctets counter */
1316c3324a9SVince Bridgers 	ext = (u64) ioread32(&mac->msb_ether_stats_octets) << 32;
1326c3324a9SVince Bridgers 	ext |= ioread32(&mac->ether_stats_octets);
1336c3324a9SVince Bridgers 	buf[18] = ext;
1346c3324a9SVince Bridgers 
1356c3324a9SVince Bridgers 	buf[19] = ioread32(&mac->ether_stats_pkts);
1366c3324a9SVince Bridgers 	buf[20] = ioread32(&mac->ether_stats_undersize_pkts);
1376c3324a9SVince Bridgers 	buf[21] = ioread32(&mac->ether_stats_oversize_pkts);
1386c3324a9SVince Bridgers 	buf[22] = ioread32(&mac->ether_stats_pkts_64_octets);
1396c3324a9SVince Bridgers 	buf[23] = ioread32(&mac->ether_stats_pkts_65to127_octets);
1406c3324a9SVince Bridgers 	buf[24] = ioread32(&mac->ether_stats_pkts_128to255_octets);
1416c3324a9SVince Bridgers 	buf[25] = ioread32(&mac->ether_stats_pkts_256to511_octets);
1426c3324a9SVince Bridgers 	buf[26] = ioread32(&mac->ether_stats_pkts_512to1023_octets);
1436c3324a9SVince Bridgers 	buf[27] = ioread32(&mac->ether_stats_pkts_1024to1518_octets);
1446c3324a9SVince Bridgers 	buf[28] = ioread32(&mac->ether_stats_pkts_1519tox_octets);
1456c3324a9SVince Bridgers 	buf[29] = ioread32(&mac->ether_stats_jabbers);
1466c3324a9SVince Bridgers 	buf[30] = ioread32(&mac->ether_stats_fragments);
1476c3324a9SVince Bridgers }
1486c3324a9SVince Bridgers 
1496c3324a9SVince Bridgers static int tse_sset_count(struct net_device *dev, int sset)
1506c3324a9SVince Bridgers {
1516c3324a9SVince Bridgers 	switch (sset) {
1526c3324a9SVince Bridgers 	case ETH_SS_STATS:
1536c3324a9SVince Bridgers 		return TSE_STATS_LEN;
1546c3324a9SVince Bridgers 	default:
1556c3324a9SVince Bridgers 		return -EOPNOTSUPP;
1566c3324a9SVince Bridgers 	}
1576c3324a9SVince Bridgers }
1586c3324a9SVince Bridgers 
1596c3324a9SVince Bridgers static u32 tse_get_msglevel(struct net_device *dev)
1606c3324a9SVince Bridgers {
1616c3324a9SVince Bridgers 	struct altera_tse_private *priv = netdev_priv(dev);
1626c3324a9SVince Bridgers 	return priv->msg_enable;
1636c3324a9SVince Bridgers }
1646c3324a9SVince Bridgers 
1656c3324a9SVince Bridgers static void tse_set_msglevel(struct net_device *dev, uint32_t data)
1666c3324a9SVince Bridgers {
1676c3324a9SVince Bridgers 	struct altera_tse_private *priv = netdev_priv(dev);
1686c3324a9SVince Bridgers 	priv->msg_enable = data;
1696c3324a9SVince Bridgers }
1706c3324a9SVince Bridgers 
1716c3324a9SVince Bridgers static int tse_reglen(struct net_device *dev)
1726c3324a9SVince Bridgers {
1736c3324a9SVince Bridgers 	return TSE_NUM_REGS * sizeof(u32);
1746c3324a9SVince Bridgers }
1756c3324a9SVince Bridgers 
1766c3324a9SVince Bridgers static void tse_get_regs(struct net_device *dev, struct ethtool_regs *regs,
1776c3324a9SVince Bridgers 			 void *regbuf)
1786c3324a9SVince Bridgers {
1796c3324a9SVince Bridgers 	int i;
1806c3324a9SVince Bridgers 	struct altera_tse_private *priv = netdev_priv(dev);
1816c3324a9SVince Bridgers 	u32 *tse_mac_regs = (u32 *)priv->mac_dev;
1826c3324a9SVince Bridgers 	u32 *buf = regbuf;
1836c3324a9SVince Bridgers 
1848adfc3aeSVince Bridgers 	/* Set version to a known value, so ethtool knows
1858adfc3aeSVince Bridgers 	 * how to do any special formatting of this data.
1868adfc3aeSVince Bridgers 	 * This version number will need to change if and
1878adfc3aeSVince Bridgers 	 * when this register table is changed.
18899514e11SVince Bridgers 	 *
18999514e11SVince Bridgers 	 * version[31:0] = 1: Dump the first 128 TSE Registers
19099514e11SVince Bridgers 	 *      Upper bits are all 0 by default
19199514e11SVince Bridgers 	 *
19299514e11SVince Bridgers 	 * Upper 16-bits will indicate feature presence for
19399514e11SVince Bridgers 	 * Ethtool register decoding in future version.
1948adfc3aeSVince Bridgers 	 */
1958adfc3aeSVince Bridgers 
1968adfc3aeSVince Bridgers 	regs->version = 1;
1978adfc3aeSVince Bridgers 
1986c3324a9SVince Bridgers 	for (i = 0; i < TSE_NUM_REGS; i++)
1996c3324a9SVince Bridgers 		buf[i] = ioread32(&tse_mac_regs[i]);
2006c3324a9SVince Bridgers }
2016c3324a9SVince Bridgers 
2026c3324a9SVince Bridgers static int tse_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
2036c3324a9SVince Bridgers {
2046c3324a9SVince Bridgers 	struct altera_tse_private *priv = netdev_priv(dev);
2056c3324a9SVince Bridgers 	struct phy_device *phydev = priv->phydev;
2066c3324a9SVince Bridgers 
2076c3324a9SVince Bridgers 	if (phydev == NULL)
2086c3324a9SVince Bridgers 		return -ENODEV;
2096c3324a9SVince Bridgers 
2106c3324a9SVince Bridgers 	return phy_ethtool_gset(phydev, cmd);
2116c3324a9SVince Bridgers }
2126c3324a9SVince Bridgers 
2136c3324a9SVince Bridgers static int tse_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
2146c3324a9SVince Bridgers {
2156c3324a9SVince Bridgers 	struct altera_tse_private *priv = netdev_priv(dev);
2166c3324a9SVince Bridgers 	struct phy_device *phydev = priv->phydev;
2176c3324a9SVince Bridgers 
2186c3324a9SVince Bridgers 	if (phydev == NULL)
2196c3324a9SVince Bridgers 		return -ENODEV;
2206c3324a9SVince Bridgers 
2216c3324a9SVince Bridgers 	return phy_ethtool_sset(phydev, cmd);
2226c3324a9SVince Bridgers }
2236c3324a9SVince Bridgers 
2246c3324a9SVince Bridgers static const struct ethtool_ops tse_ethtool_ops = {
2256c3324a9SVince Bridgers 	.get_drvinfo = tse_get_drvinfo,
2266c3324a9SVince Bridgers 	.get_regs_len = tse_reglen,
2276c3324a9SVince Bridgers 	.get_regs = tse_get_regs,
2286c3324a9SVince Bridgers 	.get_link = ethtool_op_get_link,
2296c3324a9SVince Bridgers 	.get_settings = tse_get_settings,
2306c3324a9SVince Bridgers 	.set_settings = tse_set_settings,
2316c3324a9SVince Bridgers 	.get_strings = tse_gstrings,
2326c3324a9SVince Bridgers 	.get_sset_count = tse_sset_count,
2336c3324a9SVince Bridgers 	.get_ethtool_stats = tse_fill_stats,
2346c3324a9SVince Bridgers 	.get_msglevel = tse_get_msglevel,
2356c3324a9SVince Bridgers 	.set_msglevel = tse_set_msglevel,
2366c3324a9SVince Bridgers };
2376c3324a9SVince Bridgers 
2386c3324a9SVince Bridgers void altera_tse_set_ethtool_ops(struct net_device *netdev)
2396c3324a9SVince Bridgers {
240*7ad24ea4SWilfried Klaebe 	netdev->ethtool_ops = &tse_ethtool_ops;
2416c3324a9SVince Bridgers }
242