1e6ad7673SIyappan Subramanian /* Applied Micro X-Gene SoC Ethernet Driver
2e6ad7673SIyappan Subramanian  *
3e6ad7673SIyappan Subramanian  * Copyright (c) 2014, Applied Micro Circuits Corporation
4e6ad7673SIyappan Subramanian  * Authors: Iyappan Subramanian <isubramanian@apm.com>
5e6ad7673SIyappan Subramanian  *
6e6ad7673SIyappan Subramanian  * This program is free software; you can redistribute  it and/or modify it
7e6ad7673SIyappan Subramanian  * under  the terms of  the GNU General  Public License as published by the
8e6ad7673SIyappan Subramanian  * Free Software Foundation;  either version 2 of the  License, or (at your
9e6ad7673SIyappan Subramanian  * option) any later version.
10e6ad7673SIyappan Subramanian  *
11e6ad7673SIyappan Subramanian  * This program is distributed in the hope that it will be useful,
12e6ad7673SIyappan Subramanian  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13e6ad7673SIyappan Subramanian  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14e6ad7673SIyappan Subramanian  * GNU General Public License for more details.
15e6ad7673SIyappan Subramanian  *
16e6ad7673SIyappan Subramanian  * You should have received a copy of the GNU General Public License
17e6ad7673SIyappan Subramanian  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
18e6ad7673SIyappan Subramanian  */
19e6ad7673SIyappan Subramanian 
20e6ad7673SIyappan Subramanian #include <linux/ethtool.h>
21e6ad7673SIyappan Subramanian #include "xgene_enet_main.h"
22e6ad7673SIyappan Subramanian 
23e6ad7673SIyappan Subramanian struct xgene_gstrings_stats {
24e6ad7673SIyappan Subramanian 	char name[ETH_GSTRING_LEN];
25e6ad7673SIyappan Subramanian 	int offset;
26e6ad7673SIyappan Subramanian };
27e6ad7673SIyappan Subramanian 
28e6ad7673SIyappan Subramanian #define XGENE_STAT(m) { #m, offsetof(struct xgene_enet_pdata, stats.m) }
29e6ad7673SIyappan Subramanian 
30e6ad7673SIyappan Subramanian static const struct xgene_gstrings_stats gstrings_stats[] = {
31e6ad7673SIyappan Subramanian 	XGENE_STAT(rx_packets),
32e6ad7673SIyappan Subramanian 	XGENE_STAT(tx_packets),
33e6ad7673SIyappan Subramanian 	XGENE_STAT(rx_bytes),
34e6ad7673SIyappan Subramanian 	XGENE_STAT(tx_bytes),
35e6ad7673SIyappan Subramanian 	XGENE_STAT(rx_errors),
36e6ad7673SIyappan Subramanian 	XGENE_STAT(tx_errors),
37e6ad7673SIyappan Subramanian 	XGENE_STAT(rx_length_errors),
38e6ad7673SIyappan Subramanian 	XGENE_STAT(rx_crc_errors),
39e6ad7673SIyappan Subramanian 	XGENE_STAT(rx_frame_errors),
40e6ad7673SIyappan Subramanian 	XGENE_STAT(rx_fifo_errors)
41e6ad7673SIyappan Subramanian };
42e6ad7673SIyappan Subramanian 
43e6ad7673SIyappan Subramanian #define XGENE_STATS_LEN		ARRAY_SIZE(gstrings_stats)
44e6ad7673SIyappan Subramanian 
45e6ad7673SIyappan Subramanian static void xgene_get_drvinfo(struct net_device *ndev,
46e6ad7673SIyappan Subramanian 			      struct ethtool_drvinfo *info)
47e6ad7673SIyappan Subramanian {
48e6ad7673SIyappan Subramanian 	struct xgene_enet_pdata *pdata = netdev_priv(ndev);
49e6ad7673SIyappan Subramanian 	struct platform_device *pdev = pdata->pdev;
50e6ad7673SIyappan Subramanian 
51e6ad7673SIyappan Subramanian 	strcpy(info->driver, "xgene_enet");
52e6ad7673SIyappan Subramanian 	strcpy(info->version, XGENE_DRV_VERSION);
53e6ad7673SIyappan Subramanian 	snprintf(info->fw_version, ETHTOOL_FWVERS_LEN, "N/A");
54e6ad7673SIyappan Subramanian 	sprintf(info->bus_info, "%s", pdev->name);
55e6ad7673SIyappan Subramanian }
56e6ad7673SIyappan Subramanian 
57e6ad7673SIyappan Subramanian static int xgene_get_settings(struct net_device *ndev, struct ethtool_cmd *cmd)
58e6ad7673SIyappan Subramanian {
59e6ad7673SIyappan Subramanian 	struct xgene_enet_pdata *pdata = netdev_priv(ndev);
60e6ad7673SIyappan Subramanian 	struct phy_device *phydev = pdata->phy_dev;
61e6ad7673SIyappan Subramanian 
6241aace6eSIyappan Subramanian 	if (pdata->phy_mode == PHY_INTERFACE_MODE_RGMII) {
63e6ad7673SIyappan Subramanian 		if (phydev == NULL)
64e6ad7673SIyappan Subramanian 			return -ENODEV;
65e6ad7673SIyappan Subramanian 
66e6ad7673SIyappan Subramanian 		return phy_ethtool_gset(phydev, cmd);
675e6a024bSIyappan Subramanian 	} else if (pdata->phy_mode == PHY_INTERFACE_MODE_SGMII) {
685e6a024bSIyappan Subramanian 		cmd->supported = SUPPORTED_1000baseT_Full |
695e6a024bSIyappan Subramanian 				 SUPPORTED_Autoneg | SUPPORTED_MII;
705e6a024bSIyappan Subramanian 		cmd->advertising = cmd->supported;
715e6a024bSIyappan Subramanian 		ethtool_cmd_speed_set(cmd, SPEED_1000);
725e6a024bSIyappan Subramanian 		cmd->duplex = DUPLEX_FULL;
735e6a024bSIyappan Subramanian 		cmd->port = PORT_MII;
745e6a024bSIyappan Subramanian 		cmd->transceiver = XCVR_INTERNAL;
755e6a024bSIyappan Subramanian 		cmd->autoneg = AUTONEG_ENABLE;
765e6a024bSIyappan Subramanian 	} else {
7741aace6eSIyappan Subramanian 		cmd->supported = SUPPORTED_10000baseT_Full | SUPPORTED_FIBRE;
7841aace6eSIyappan Subramanian 		cmd->advertising = cmd->supported;
7941aace6eSIyappan Subramanian 		ethtool_cmd_speed_set(cmd, SPEED_10000);
8041aace6eSIyappan Subramanian 		cmd->duplex = DUPLEX_FULL;
8141aace6eSIyappan Subramanian 		cmd->port = PORT_FIBRE;
825e6a024bSIyappan Subramanian 		cmd->transceiver = XCVR_INTERNAL;
8341aace6eSIyappan Subramanian 		cmd->autoneg = AUTONEG_DISABLE;
845e6a024bSIyappan Subramanian 	}
8541aace6eSIyappan Subramanian 
8641aace6eSIyappan Subramanian 	return 0;
8741aace6eSIyappan Subramanian }
8841aace6eSIyappan Subramanian 
89e6ad7673SIyappan Subramanian static int xgene_set_settings(struct net_device *ndev, struct ethtool_cmd *cmd)
90e6ad7673SIyappan Subramanian {
91e6ad7673SIyappan Subramanian 	struct xgene_enet_pdata *pdata = netdev_priv(ndev);
92e6ad7673SIyappan Subramanian 	struct phy_device *phydev = pdata->phy_dev;
93e6ad7673SIyappan Subramanian 
9441aace6eSIyappan Subramanian 	if (pdata->phy_mode == PHY_INTERFACE_MODE_RGMII) {
95e6ad7673SIyappan Subramanian 		if (phydev == NULL)
96e6ad7673SIyappan Subramanian 			return -ENODEV;
97e6ad7673SIyappan Subramanian 
98e6ad7673SIyappan Subramanian 		return phy_ethtool_sset(phydev, cmd);
99e6ad7673SIyappan Subramanian 	}
100e6ad7673SIyappan Subramanian 
10141aace6eSIyappan Subramanian 	return -EINVAL;
10241aace6eSIyappan Subramanian }
10341aace6eSIyappan Subramanian 
104e6ad7673SIyappan Subramanian static void xgene_get_strings(struct net_device *ndev, u32 stringset, u8 *data)
105e6ad7673SIyappan Subramanian {
106e6ad7673SIyappan Subramanian 	int i;
107e6ad7673SIyappan Subramanian 	u8 *p = data;
108e6ad7673SIyappan Subramanian 
109e6ad7673SIyappan Subramanian 	if (stringset != ETH_SS_STATS)
110e6ad7673SIyappan Subramanian 		return;
111e6ad7673SIyappan Subramanian 
112e6ad7673SIyappan Subramanian 	for (i = 0; i < XGENE_STATS_LEN; i++) {
113e6ad7673SIyappan Subramanian 		memcpy(p, gstrings_stats[i].name, ETH_GSTRING_LEN);
114e6ad7673SIyappan Subramanian 		p += ETH_GSTRING_LEN;
115e6ad7673SIyappan Subramanian 	}
116e6ad7673SIyappan Subramanian }
117e6ad7673SIyappan Subramanian 
118e6ad7673SIyappan Subramanian static int xgene_get_sset_count(struct net_device *ndev, int sset)
119e6ad7673SIyappan Subramanian {
120e6ad7673SIyappan Subramanian 	if (sset != ETH_SS_STATS)
121e6ad7673SIyappan Subramanian 		return -EINVAL;
122e6ad7673SIyappan Subramanian 
123e6ad7673SIyappan Subramanian 	return XGENE_STATS_LEN;
124e6ad7673SIyappan Subramanian }
125e6ad7673SIyappan Subramanian 
126e6ad7673SIyappan Subramanian static void xgene_get_ethtool_stats(struct net_device *ndev,
127e6ad7673SIyappan Subramanian 				    struct ethtool_stats *dummy,
128e6ad7673SIyappan Subramanian 				    u64 *data)
129e6ad7673SIyappan Subramanian {
130e6ad7673SIyappan Subramanian 	void *pdata = netdev_priv(ndev);
131e6ad7673SIyappan Subramanian 	int i;
132e6ad7673SIyappan Subramanian 
133e6ad7673SIyappan Subramanian 	for (i = 0; i < XGENE_STATS_LEN; i++)
134e6ad7673SIyappan Subramanian 		*data++ = *(u64 *)(pdata + gstrings_stats[i].offset);
135e6ad7673SIyappan Subramanian }
136e6ad7673SIyappan Subramanian 
137e6ad7673SIyappan Subramanian static const struct ethtool_ops xgene_ethtool_ops = {
138e6ad7673SIyappan Subramanian 	.get_drvinfo = xgene_get_drvinfo,
139e6ad7673SIyappan Subramanian 	.get_settings = xgene_get_settings,
140e6ad7673SIyappan Subramanian 	.set_settings = xgene_set_settings,
141e6ad7673SIyappan Subramanian 	.get_link = ethtool_op_get_link,
142e6ad7673SIyappan Subramanian 	.get_strings = xgene_get_strings,
143e6ad7673SIyappan Subramanian 	.get_sset_count = xgene_get_sset_count,
144e6ad7673SIyappan Subramanian 	.get_ethtool_stats = xgene_get_ethtool_stats
145e6ad7673SIyappan Subramanian };
146e6ad7673SIyappan Subramanian 
147e6ad7673SIyappan Subramanian void xgene_enet_set_ethtool_ops(struct net_device *ndev)
148e6ad7673SIyappan Subramanian {
149e6ad7673SIyappan Subramanian 	ndev->ethtool_ops = &xgene_ethtool_ops;
150e6ad7673SIyappan Subramanian }
151