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 
5736a19b29SPhilippe Reynes static int xgene_get_link_ksettings(struct net_device *ndev,
5836a19b29SPhilippe Reynes 				    struct ethtool_link_ksettings *cmd)
59e6ad7673SIyappan Subramanian {
60e6ad7673SIyappan Subramanian 	struct xgene_enet_pdata *pdata = netdev_priv(ndev);
61971d3a44SPhilippe Reynes 	struct phy_device *phydev = ndev->phydev;
6236a19b29SPhilippe Reynes 	u32 supported;
63e6ad7673SIyappan Subramanian 
6441aace6eSIyappan Subramanian 	if (pdata->phy_mode == PHY_INTERFACE_MODE_RGMII) {
65e6ad7673SIyappan Subramanian 		if (phydev == NULL)
66e6ad7673SIyappan Subramanian 			return -ENODEV;
67e6ad7673SIyappan Subramanian 
6836a19b29SPhilippe Reynes 		return phy_ethtool_ksettings_get(phydev, cmd);
695e6a024bSIyappan Subramanian 	} else if (pdata->phy_mode == PHY_INTERFACE_MODE_SGMII) {
7052d1fd99SIyappan Subramanian 		if (pdata->mdio_driver) {
7152d1fd99SIyappan Subramanian 			if (!phydev)
7252d1fd99SIyappan Subramanian 				return -ENODEV;
7352d1fd99SIyappan Subramanian 
7436a19b29SPhilippe Reynes 			return phy_ethtool_ksettings_get(phydev, cmd);
7552d1fd99SIyappan Subramanian 		}
7652d1fd99SIyappan Subramanian 
7736a19b29SPhilippe Reynes 		supported = SUPPORTED_1000baseT_Full | SUPPORTED_Autoneg |
7852d1fd99SIyappan Subramanian 			SUPPORTED_MII;
7936a19b29SPhilippe Reynes 		ethtool_convert_legacy_u32_to_link_mode(
8036a19b29SPhilippe Reynes 			cmd->link_modes.supported,
8136a19b29SPhilippe Reynes 			supported);
8236a19b29SPhilippe Reynes 		ethtool_convert_legacy_u32_to_link_mode(
8336a19b29SPhilippe Reynes 			cmd->link_modes.advertising,
8436a19b29SPhilippe Reynes 			supported);
8536a19b29SPhilippe Reynes 
8636a19b29SPhilippe Reynes 		cmd->base.speed = SPEED_1000;
8736a19b29SPhilippe Reynes 		cmd->base.duplex = DUPLEX_FULL;
8836a19b29SPhilippe Reynes 		cmd->base.port = PORT_MII;
8936a19b29SPhilippe Reynes 		cmd->base.autoneg = AUTONEG_ENABLE;
905e6a024bSIyappan Subramanian 	} else {
9136a19b29SPhilippe Reynes 		supported = SUPPORTED_10000baseT_Full | SUPPORTED_FIBRE;
9236a19b29SPhilippe Reynes 		ethtool_convert_legacy_u32_to_link_mode(
9336a19b29SPhilippe Reynes 			cmd->link_modes.supported,
9436a19b29SPhilippe Reynes 			supported);
9536a19b29SPhilippe Reynes 		ethtool_convert_legacy_u32_to_link_mode(
9636a19b29SPhilippe Reynes 			cmd->link_modes.advertising,
9736a19b29SPhilippe Reynes 			supported);
9836a19b29SPhilippe Reynes 
9936a19b29SPhilippe Reynes 		cmd->base.speed = SPEED_10000;
10036a19b29SPhilippe Reynes 		cmd->base.duplex = DUPLEX_FULL;
10136a19b29SPhilippe Reynes 		cmd->base.port = PORT_FIBRE;
10236a19b29SPhilippe Reynes 		cmd->base.autoneg = AUTONEG_DISABLE;
1035e6a024bSIyappan Subramanian 	}
10441aace6eSIyappan Subramanian 
10541aace6eSIyappan Subramanian 	return 0;
10641aace6eSIyappan Subramanian }
10741aace6eSIyappan Subramanian 
10836a19b29SPhilippe Reynes static int xgene_set_link_ksettings(struct net_device *ndev,
10936a19b29SPhilippe Reynes 				    const struct ethtool_link_ksettings *cmd)
110e6ad7673SIyappan Subramanian {
111e6ad7673SIyappan Subramanian 	struct xgene_enet_pdata *pdata = netdev_priv(ndev);
112971d3a44SPhilippe Reynes 	struct phy_device *phydev = ndev->phydev;
113e6ad7673SIyappan Subramanian 
11441aace6eSIyappan Subramanian 	if (pdata->phy_mode == PHY_INTERFACE_MODE_RGMII) {
11552d1fd99SIyappan Subramanian 		if (!phydev)
116e6ad7673SIyappan Subramanian 			return -ENODEV;
117e6ad7673SIyappan Subramanian 
11836a19b29SPhilippe Reynes 		return phy_ethtool_ksettings_set(phydev, cmd);
119e6ad7673SIyappan Subramanian 	}
120e6ad7673SIyappan Subramanian 
12152d1fd99SIyappan Subramanian 	if (pdata->phy_mode == PHY_INTERFACE_MODE_SGMII) {
12252d1fd99SIyappan Subramanian 		if (pdata->mdio_driver) {
12352d1fd99SIyappan Subramanian 			if (!phydev)
12452d1fd99SIyappan Subramanian 				return -ENODEV;
12552d1fd99SIyappan Subramanian 
12636a19b29SPhilippe Reynes 			return phy_ethtool_ksettings_set(phydev, cmd);
12752d1fd99SIyappan Subramanian 		}
12852d1fd99SIyappan Subramanian 	}
12952d1fd99SIyappan Subramanian 
13041aace6eSIyappan Subramanian 	return -EINVAL;
13141aace6eSIyappan Subramanian }
13241aace6eSIyappan Subramanian 
133e6ad7673SIyappan Subramanian static void xgene_get_strings(struct net_device *ndev, u32 stringset, u8 *data)
134e6ad7673SIyappan Subramanian {
135e6ad7673SIyappan Subramanian 	int i;
136e6ad7673SIyappan Subramanian 	u8 *p = data;
137e6ad7673SIyappan Subramanian 
138e6ad7673SIyappan Subramanian 	if (stringset != ETH_SS_STATS)
139e6ad7673SIyappan Subramanian 		return;
140e6ad7673SIyappan Subramanian 
141e6ad7673SIyappan Subramanian 	for (i = 0; i < XGENE_STATS_LEN; i++) {
142e6ad7673SIyappan Subramanian 		memcpy(p, gstrings_stats[i].name, ETH_GSTRING_LEN);
143e6ad7673SIyappan Subramanian 		p += ETH_GSTRING_LEN;
144e6ad7673SIyappan Subramanian 	}
145e6ad7673SIyappan Subramanian }
146e6ad7673SIyappan Subramanian 
147e6ad7673SIyappan Subramanian static int xgene_get_sset_count(struct net_device *ndev, int sset)
148e6ad7673SIyappan Subramanian {
149e6ad7673SIyappan Subramanian 	if (sset != ETH_SS_STATS)
150e6ad7673SIyappan Subramanian 		return -EINVAL;
151e6ad7673SIyappan Subramanian 
152e6ad7673SIyappan Subramanian 	return XGENE_STATS_LEN;
153e6ad7673SIyappan Subramanian }
154e6ad7673SIyappan Subramanian 
155e6ad7673SIyappan Subramanian static void xgene_get_ethtool_stats(struct net_device *ndev,
156e6ad7673SIyappan Subramanian 				    struct ethtool_stats *dummy,
157e6ad7673SIyappan Subramanian 				    u64 *data)
158e6ad7673SIyappan Subramanian {
159e6ad7673SIyappan Subramanian 	void *pdata = netdev_priv(ndev);
160e6ad7673SIyappan Subramanian 	int i;
161e6ad7673SIyappan Subramanian 
162e6ad7673SIyappan Subramanian 	for (i = 0; i < XGENE_STATS_LEN; i++)
163e6ad7673SIyappan Subramanian 		*data++ = *(u64 *)(pdata + gstrings_stats[i].offset);
164e6ad7673SIyappan Subramanian }
165e6ad7673SIyappan Subramanian 
166e6ad7673SIyappan Subramanian static const struct ethtool_ops xgene_ethtool_ops = {
167e6ad7673SIyappan Subramanian 	.get_drvinfo = xgene_get_drvinfo,
168e6ad7673SIyappan Subramanian 	.get_link = ethtool_op_get_link,
169e6ad7673SIyappan Subramanian 	.get_strings = xgene_get_strings,
170e6ad7673SIyappan Subramanian 	.get_sset_count = xgene_get_sset_count,
17136a19b29SPhilippe Reynes 	.get_ethtool_stats = xgene_get_ethtool_stats,
17236a19b29SPhilippe Reynes 	.get_link_ksettings = xgene_get_link_ksettings,
17336a19b29SPhilippe Reynes 	.set_link_ksettings = xgene_set_link_ksettings,
174e6ad7673SIyappan Subramanian };
175e6ad7673SIyappan Subramanian 
176e6ad7673SIyappan Subramanian void xgene_enet_set_ethtool_ops(struct net_device *ndev)
177e6ad7673SIyappan Subramanian {
178e6ad7673SIyappan Subramanian 	ndev->ethtool_ops = &xgene_ethtool_ops;
179e6ad7673SIyappan Subramanian }
180