11ccea77eSThomas Gleixner// SPDX-License-Identifier: GPL-2.0-or-later
2e6ad7673SIyappan Subramanian/* Applied Micro X-Gene SoC Ethernet Driver
3e6ad7673SIyappan Subramanian *
4e6ad7673SIyappan Subramanian * Copyright (c) 2014, Applied Micro Circuits Corporation
5e6ad7673SIyappan Subramanian * Authors: Iyappan Subramanian <isubramanian@apm.com>
6e6ad7673SIyappan Subramanian */
7e6ad7673SIyappan Subramanian
8e6ad7673SIyappan Subramanian#include <linux/ethtool.h>
9e6ad7673SIyappan Subramanian#include "xgene_enet_main.h"
10e6ad7673SIyappan Subramanian
11e6ad7673SIyappan Subramanianstruct xgene_gstrings_stats {
12e6ad7673SIyappan Subramanian	char name[ETH_GSTRING_LEN];
13e6ad7673SIyappan Subramanian	int offset;
142d07d8e4SQuan Nguyen	u32 addr;
152d07d8e4SQuan Nguyen	u32 mask;
16e6ad7673SIyappan Subramanian};
17e6ad7673SIyappan Subramanian
183f5a2ef1SQuan Nguyen#define XGENE_STAT(m) { #m, offsetof(struct rtnl_link_stats64, m) }
192d07d8e4SQuan Nguyen#define XGENE_EXTD_STAT(s, a, m)		\
202d07d8e4SQuan Nguyen		{			\
212d07d8e4SQuan Nguyen		.name = #s,		\
222d07d8e4SQuan Nguyen		.addr = a ## _ADDR,	\
232d07d8e4SQuan Nguyen		.mask = m		\
242d07d8e4SQuan Nguyen		}
25e6ad7673SIyappan Subramanian
26e6ad7673SIyappan Subramanianstatic const struct xgene_gstrings_stats gstrings_stats[] = {
27e6ad7673SIyappan Subramanian	XGENE_STAT(rx_packets),
28e6ad7673SIyappan Subramanian	XGENE_STAT(tx_packets),
29e6ad7673SIyappan Subramanian	XGENE_STAT(rx_bytes),
30e6ad7673SIyappan Subramanian	XGENE_STAT(tx_bytes),
31e6ad7673SIyappan Subramanian	XGENE_STAT(rx_errors),
32e6ad7673SIyappan Subramanian	XGENE_STAT(tx_errors),
33e6ad7673SIyappan Subramanian	XGENE_STAT(rx_length_errors),
34e6ad7673SIyappan Subramanian	XGENE_STAT(rx_crc_errors),
35e6ad7673SIyappan Subramanian	XGENE_STAT(rx_frame_errors),
36e6ad7673SIyappan Subramanian	XGENE_STAT(rx_fifo_errors)
37e6ad7673SIyappan Subramanian};
38e6ad7673SIyappan Subramanian
392d07d8e4SQuan Nguyenstatic const struct xgene_gstrings_stats gstrings_extd_stats[] = {
402d07d8e4SQuan Nguyen	XGENE_EXTD_STAT(tx_rx_64b_frame_cntr, TR64, 31),
412d07d8e4SQuan Nguyen	XGENE_EXTD_STAT(tx_rx_127b_frame_cntr, TR127, 31),
422d07d8e4SQuan Nguyen	XGENE_EXTD_STAT(tx_rx_255b_frame_cntr, TR255, 31),
432d07d8e4SQuan Nguyen	XGENE_EXTD_STAT(tx_rx_511b_frame_cntr, TR511, 31),
442d07d8e4SQuan Nguyen	XGENE_EXTD_STAT(tx_rx_1023b_frame_cntr, TR1K, 31),
452d07d8e4SQuan Nguyen	XGENE_EXTD_STAT(tx_rx_1518b_frame_cntr, TRMAX, 31),
462d07d8e4SQuan Nguyen	XGENE_EXTD_STAT(tx_rx_1522b_frame_cntr, TRMGV, 31),
472d07d8e4SQuan Nguyen	XGENE_EXTD_STAT(rx_fcs_error_cntr, RFCS, 16),
482d07d8e4SQuan Nguyen	XGENE_EXTD_STAT(rx_multicast_pkt_cntr, RMCA, 31),
492d07d8e4SQuan Nguyen	XGENE_EXTD_STAT(rx_broadcast_pkt_cntr, RBCA, 31),
502d07d8e4SQuan Nguyen	XGENE_EXTD_STAT(rx_ctrl_frame_pkt_cntr, RXCF, 16),
512d07d8e4SQuan Nguyen	XGENE_EXTD_STAT(rx_pause_frame_pkt_cntr, RXPF, 16),
522d07d8e4SQuan Nguyen	XGENE_EXTD_STAT(rx_unk_opcode_cntr, RXUO, 16),
532d07d8e4SQuan Nguyen	XGENE_EXTD_STAT(rx_align_err_cntr, RALN, 16),
542d07d8e4SQuan Nguyen	XGENE_EXTD_STAT(rx_frame_len_err_cntr, RFLR, 16),
55eaef62a4SQuan Nguyen	XGENE_EXTD_STAT(rx_frame_len_err_recov_cntr, DUMP, 0),
562d07d8e4SQuan Nguyen	XGENE_EXTD_STAT(rx_code_err_cntr, RCDE, 16),
572d07d8e4SQuan Nguyen	XGENE_EXTD_STAT(rx_carrier_sense_err_cntr, RCSE, 16),
582d07d8e4SQuan Nguyen	XGENE_EXTD_STAT(rx_undersize_pkt_cntr, RUND, 16),
592d07d8e4SQuan Nguyen	XGENE_EXTD_STAT(rx_oversize_pkt_cntr, ROVR, 16),
602d07d8e4SQuan Nguyen	XGENE_EXTD_STAT(rx_fragments_cntr, RFRG, 16),
612d07d8e4SQuan Nguyen	XGENE_EXTD_STAT(rx_jabber_cntr, RJBR, 16),
6261c759cdSQuan Nguyen	XGENE_EXTD_STAT(rx_jabber_recov_cntr, DUMP, 0),
632d07d8e4SQuan Nguyen	XGENE_EXTD_STAT(rx_dropped_pkt_cntr, RDRP, 16),
64ca6d550cSIyappan Subramanian	XGENE_EXTD_STAT(rx_overrun_cntr, DUMP, 0),
652d07d8e4SQuan Nguyen	XGENE_EXTD_STAT(tx_multicast_pkt_cntr, TMCA, 31),
662d07d8e4SQuan Nguyen	XGENE_EXTD_STAT(tx_broadcast_pkt_cntr, TBCA, 31),
672d07d8e4SQuan Nguyen	XGENE_EXTD_STAT(tx_pause_ctrl_frame_cntr, TXPF, 16),
682d07d8e4SQuan Nguyen	XGENE_EXTD_STAT(tx_defer_pkt_cntr, TDFR, 31),
692d07d8e4SQuan Nguyen	XGENE_EXTD_STAT(tx_excv_defer_pkt_cntr, TEDF, 31),
702d07d8e4SQuan Nguyen	XGENE_EXTD_STAT(tx_single_col_pkt_cntr, TSCL, 31),
712d07d8e4SQuan Nguyen	XGENE_EXTD_STAT(tx_multi_col_pkt_cntr, TMCL, 31),
722d07d8e4SQuan Nguyen	XGENE_EXTD_STAT(tx_late_col_pkt_cntr, TLCL, 31),
732d07d8e4SQuan Nguyen	XGENE_EXTD_STAT(tx_excv_col_pkt_cntr, TXCL, 31),
742d07d8e4SQuan Nguyen	XGENE_EXTD_STAT(tx_total_col_cntr, TNCL, 31),
752d07d8e4SQuan Nguyen	XGENE_EXTD_STAT(tx_pause_frames_hnrd_cntr, TPFH, 16),
762d07d8e4SQuan Nguyen	XGENE_EXTD_STAT(tx_drop_frame_cntr, TDRP, 16),
772d07d8e4SQuan Nguyen	XGENE_EXTD_STAT(tx_jabber_frame_cntr, TJBR, 12),
782d07d8e4SQuan Nguyen	XGENE_EXTD_STAT(tx_fcs_error_cntr, TFCS, 12),
792d07d8e4SQuan Nguyen	XGENE_EXTD_STAT(tx_ctrl_frame_cntr, TXCF, 12),
802d07d8e4SQuan Nguyen	XGENE_EXTD_STAT(tx_oversize_frame_cntr, TOVR, 12),
812d07d8e4SQuan Nguyen	XGENE_EXTD_STAT(tx_undersize_frame_cntr, TUND, 12),
82ca6d550cSIyappan Subramanian	XGENE_EXTD_STAT(tx_fragments_cntr, TFRG, 12),
83ca6d550cSIyappan Subramanian	XGENE_EXTD_STAT(tx_underrun_cntr, DUMP, 0)
842d07d8e4SQuan Nguyen};
852d07d8e4SQuan Nguyen
86e6ad7673SIyappan Subramanian#define XGENE_STATS_LEN		ARRAY_SIZE(gstrings_stats)
872d07d8e4SQuan Nguyen#define XGENE_EXTD_STATS_LEN	ARRAY_SIZE(gstrings_extd_stats)
8861c759cdSQuan Nguyen#define RFCS_IDX		7
8961c759cdSQuan Nguyen#define RALN_IDX		13
9061c759cdSQuan Nguyen#define RFLR_IDX		14
91eaef62a4SQuan Nguyen#define FALSE_RFLR_IDX		15
9261c759cdSQuan Nguyen#define RUND_IDX		18
9361c759cdSQuan Nguyen#define FALSE_RJBR_IDX		22
9461c759cdSQuan Nguyen#define RX_OVERRUN_IDX		24
9561c759cdSQuan Nguyen#define TFCS_IDX		38
9661c759cdSQuan Nguyen#define TFRG_IDX		42
9761c759cdSQuan Nguyen#define TX_UNDERRUN_IDX		43
98e6ad7673SIyappan Subramanian
99e6ad7673SIyappan Subramanianstatic void xgene_get_drvinfo(struct net_device *ndev,
100e6ad7673SIyappan Subramanian			      struct ethtool_drvinfo *info)
101e6ad7673SIyappan Subramanian{
102e6ad7673SIyappan Subramanian	struct xgene_enet_pdata *pdata = netdev_priv(ndev);
103e6ad7673SIyappan Subramanian	struct platform_device *pdev = pdata->pdev;
104e6ad7673SIyappan Subramanian
105e6ad7673SIyappan Subramanian	strcpy(info->driver, "xgene_enet");
106e6ad7673SIyappan Subramanian	sprintf(info->bus_info, "%s", pdev->name);
107e6ad7673SIyappan Subramanian}
108e6ad7673SIyappan Subramanian
10936a19b29SPhilippe Reynesstatic int xgene_get_link_ksettings(struct net_device *ndev,
11036a19b29SPhilippe Reynes				    struct ethtool_link_ksettings *cmd)
111e6ad7673SIyappan Subramanian{
112e6ad7673SIyappan Subramanian	struct xgene_enet_pdata *pdata = netdev_priv(ndev);
113971d3a44SPhilippe Reynes	struct phy_device *phydev = ndev->phydev;
11436a19b29SPhilippe Reynes	u32 supported;
115e6ad7673SIyappan Subramanian
116326dde3eSIyappan Subramanian	if (phy_interface_mode_is_rgmii(pdata->phy_mode)) {
11741aace6eSIyappan Subramanian		if (phydev == NULL)
11841aace6eSIyappan Subramanian			return -ENODEV;
119e6ad7673SIyappan Subramanian
1205514174fSyuval.shaia@oracle.com		phy_ethtool_ksettings_get(phydev, cmd);
1215514174fSyuval.shaia@oracle.com
1225514174fSyuval.shaia@oracle.com		return 0;
1235e6a024bSIyappan Subramanian	} else if (pdata->phy_mode == PHY_INTERFACE_MODE_SGMII) {
12452d1fd99SIyappan Subramanian		if (pdata->mdio_driver) {
12552d1fd99SIyappan Subramanian			if (!phydev)
12652d1fd99SIyappan Subramanian				return -ENODEV;
12752d1fd99SIyappan Subramanian
1285514174fSyuval.shaia@oracle.com			phy_ethtool_ksettings_get(phydev, cmd);
1295514174fSyuval.shaia@oracle.com
1305514174fSyuval.shaia@oracle.com			return 0;
13152d1fd99SIyappan Subramanian		}
13252d1fd99SIyappan Subramanian
13336a19b29SPhilippe Reynes		supported = SUPPORTED_1000baseT_Full | SUPPORTED_Autoneg |
13436a19b29SPhilippe Reynes			SUPPORTED_MII;
13536a19b29SPhilippe Reynes		ethtool_convert_legacy_u32_to_link_mode(
13636a19b29SPhilippe Reynes			cmd->link_modes.supported,
13736a19b29SPhilippe Reynes			supported);
13836a19b29SPhilippe Reynes		ethtool_convert_legacy_u32_to_link_mode(
13936a19b29SPhilippe Reynes			cmd->link_modes.advertising,
14036a19b29SPhilippe Reynes			supported);
14136a19b29SPhilippe Reynes
14236a19b29SPhilippe Reynes		cmd->base.speed = SPEED_1000;
14336a19b29SPhilippe Reynes		cmd->base.duplex = DUPLEX_FULL;
14436a19b29SPhilippe Reynes		cmd->base.port = PORT_MII;
14536a19b29SPhilippe Reynes		cmd->base.autoneg = AUTONEG_ENABLE;
1465e6a024bSIyappan Subramanian	} else {
14736a19b29SPhilippe Reynes		supported = SUPPORTED_10000baseT_Full | SUPPORTED_FIBRE;
14836a19b29SPhilippe Reynes		ethtool_convert_legacy_u32_to_link_mode(
14936a19b29SPhilippe Reynes			cmd->link_modes.supported,
15036a19b29SPhilippe Reynes			supported);
15136a19b29SPhilippe Reynes		ethtool_convert_legacy_u32_to_link_mode(
15236a19b29SPhilippe Reynes			cmd->link_modes.advertising,
15336a19b29SPhilippe Reynes			supported);
15436a19b29SPhilippe Reynes
15536a19b29SPhilippe Reynes		cmd->base.speed = SPEED_10000;
15636a19b29SPhilippe Reynes		cmd->base.duplex = DUPLEX_FULL;
15736a19b29SPhilippe Reynes		cmd->base.port = PORT_FIBRE;
15836a19b29SPhilippe Reynes		cmd->base.autoneg = AUTONEG_DISABLE;
15941aace6eSIyappan Subramanian	}
16041aace6eSIyappan Subramanian
16141aace6eSIyappan Subramanian	return 0;
162e6ad7673SIyappan Subramanian}
163e6ad7673SIyappan Subramanian
16436a19b29SPhilippe Reynesstatic int xgene_set_link_ksettings(struct net_device *ndev,
16536a19b29SPhilippe Reynes				    const struct ethtool_link_ksettings *cmd)
166e6ad7673SIyappan Subramanian{
167e6ad7673SIyappan Subramanian	struct xgene_enet_pdata *pdata = netdev_priv(ndev);
168971d3a44SPhilippe Reynes	struct phy_device *phydev = ndev->phydev;
169e6ad7673SIyappan Subramanian
170326dde3eSIyappan Subramanian	if (phy_interface_mode_is_rgmii(pdata->phy_mode)) {
17152d1fd99SIyappan Subramanian		if (!phydev)
17241aace6eSIyappan Subramanian			return -ENODEV;
17341aace6eSIyappan Subramanian
17436a19b29SPhilippe Reynes		return phy_ethtool_ksettings_set(phydev, cmd);
17541aace6eSIyappan Subramanian	}
176e6ad7673SIyappan Subramanian
17752d1fd99SIyappan Subramanian	if (pdata->phy_mode == PHY_INTERFACE_MODE_SGMII) {
17852d1fd99SIyappan Subramanian		if (pdata->mdio_driver) {
17952d1fd99SIyappan Subramanian			if (!phydev)
18052d1fd99SIyappan Subramanian				return -ENODEV;
18152d1fd99SIyappan Subramanian
18236a19b29SPhilippe Reynes			return phy_ethtool_ksettings_set(phydev, cmd);
18352d1fd99SIyappan Subramanian		}
18452d1fd99SIyappan Subramanian	}
18552d1fd99SIyappan Subramanian
18641aace6eSIyappan Subramanian	return -EINVAL;
187e6ad7673SIyappan Subramanian}
188e6ad7673SIyappan Subramanian
189e6ad7673SIyappan Subramanianstatic void xgene_get_strings(struct net_device *ndev, u32 stringset, u8 *data)
190e6ad7673SIyappan Subramanian{
191e6ad7673SIyappan Subramanian	int i;
192e6ad7673SIyappan Subramanian	u8 *p = data;
193e6ad7673SIyappan Subramanian
194e6ad7673SIyappan Subramanian	if (stringset != ETH_SS_STATS)
195e6ad7673SIyappan Subramanian		return;
196e6ad7673SIyappan Subramanian
197e6ad7673SIyappan Subramanian	for (i = 0; i < XGENE_STATS_LEN; i++) {
198e6ad7673SIyappan Subramanian		memcpy(p, gstrings_stats[i].name, ETH_GSTRING_LEN);
199e6ad7673SIyappan Subramanian		p += ETH_GSTRING_LEN;
200e6ad7673SIyappan Subramanian	}
2012d07d8e4SQuan Nguyen
2022d07d8e4SQuan Nguyen	for (i = 0; i < XGENE_EXTD_STATS_LEN; i++) {
2032d07d8e4SQuan Nguyen		memcpy(p, gstrings_extd_stats[i].name, ETH_GSTRING_LEN);
2042d07d8e4SQuan Nguyen		p += ETH_GSTRING_LEN;
2052d07d8e4SQuan Nguyen	}
206e6ad7673SIyappan Subramanian}
207e6ad7673SIyappan Subramanian
208e6ad7673SIyappan Subramanianstatic int xgene_get_sset_count(struct net_device *ndev, int sset)
209e6ad7673SIyappan Subramanian{
210e6ad7673SIyappan Subramanian	if (sset != ETH_SS_STATS)
211e6ad7673SIyappan Subramanian		return -EINVAL;
212e6ad7673SIyappan Subramanian
2132d07d8e4SQuan Nguyen	return XGENE_STATS_LEN + XGENE_EXTD_STATS_LEN;
2142d07d8e4SQuan Nguyen}
2152d07d8e4SQuan Nguyen
2162d07d8e4SQuan Nguyenstatic void xgene_get_extd_stats(struct xgene_enet_pdata *pdata)
2172d07d8e4SQuan Nguyen{
218ca6d550cSIyappan Subramanian	u32 rx_drop, tx_drop;
21961c759cdSQuan Nguyen	u32 mask, tmp;
2202d07d8e4SQuan Nguyen	int i;
2212d07d8e4SQuan Nguyen
2222d07d8e4SQuan Nguyen	for (i = 0; i < XGENE_EXTD_STATS_LEN; i++) {
2232d07d8e4SQuan Nguyen		tmp = xgene_enet_rd_stat(pdata, gstrings_extd_stats[i].addr);
22461c759cdSQuan Nguyen		if (gstrings_extd_stats[i].mask) {
22561c759cdSQuan Nguyen			mask = GENMASK(gstrings_extd_stats[i].mask - 1, 0);
22661c759cdSQuan Nguyen			pdata->extd_stats[i] += (tmp & mask);
22761c759cdSQuan Nguyen		}
22861c759cdSQuan Nguyen	}
22961c759cdSQuan Nguyen
23061c759cdSQuan Nguyen	if (pdata->phy_mode == PHY_INTERFACE_MODE_XGMII) {
23161c759cdSQuan Nguyen		/* Errata 10GE_10 - SW should intepret RALN as 0 */
23261c759cdSQuan Nguyen		pdata->extd_stats[RALN_IDX] = 0;
23361c759cdSQuan Nguyen	} else {
23461c759cdSQuan Nguyen		/* Errata ENET_15 - Fixes RFCS, RFLR, TFCS counter */
23561c759cdSQuan Nguyen		pdata->extd_stats[RFCS_IDX] -= pdata->extd_stats[RALN_IDX];
23661c759cdSQuan Nguyen		pdata->extd_stats[RFLR_IDX] -= pdata->extd_stats[RUND_IDX];
23761c759cdSQuan Nguyen		pdata->extd_stats[TFCS_IDX] -= pdata->extd_stats[TFRG_IDX];
2382d07d8e4SQuan Nguyen	}
239ca6d550cSIyappan Subramanian
240ca6d550cSIyappan Subramanian	pdata->mac_ops->get_drop_cnt(pdata, &rx_drop, &tx_drop);
241ca6d550cSIyappan Subramanian	pdata->extd_stats[RX_OVERRUN_IDX] += rx_drop;
242ca6d550cSIyappan Subramanian	pdata->extd_stats[TX_UNDERRUN_IDX] += tx_drop;
243eaef62a4SQuan Nguyen
244eaef62a4SQuan Nguyen	/* Errata 10GE_8 -  Update Frame recovered from Errata 10GE_8/ENET_11 */
245eaef62a4SQuan Nguyen	pdata->extd_stats[FALSE_RFLR_IDX] = pdata->false_rflr;
24661c759cdSQuan Nguyen	/* Errata ENET_15 - Jabber Frame recov'ed from Errata 10GE_10/ENET_15 */
24761c759cdSQuan Nguyen	pdata->extd_stats[FALSE_RJBR_IDX] = pdata->vlan_rjbr;
2482d07d8e4SQuan Nguyen}
2492d07d8e4SQuan Nguyen
2502d07d8e4SQuan Nguyenint xgene_extd_stats_init(struct xgene_enet_pdata *pdata)
2512d07d8e4SQuan Nguyen{
2522d07d8e4SQuan Nguyen	pdata->extd_stats = devm_kmalloc_array(&pdata->pdev->dev,
2532d07d8e4SQuan Nguyen			XGENE_EXTD_STATS_LEN, sizeof(u64), GFP_KERNEL);
2542d07d8e4SQuan Nguyen	if (!pdata->extd_stats)
2552d07d8e4SQuan Nguyen		return -ENOMEM;
2562d07d8e4SQuan Nguyen
2572d07d8e4SQuan Nguyen	xgene_get_extd_stats(pdata);
2582d07d8e4SQuan Nguyen	memset(pdata->extd_stats, 0, XGENE_EXTD_STATS_LEN * sizeof(u64));
2592d07d8e4SQuan Nguyen
2602d07d8e4SQuan Nguyen	return 0;
261e6ad7673SIyappan Subramanian}
262e6ad7673SIyappan Subramanian
263e6ad7673SIyappan Subramanianstatic void xgene_get_ethtool_stats(struct net_device *ndev,
264e6ad7673SIyappan Subramanian				    struct ethtool_stats *dummy,
265e6ad7673SIyappan Subramanian				    u64 *data)
266e6ad7673SIyappan Subramanian{
2672d07d8e4SQuan Nguyen	struct xgene_enet_pdata *pdata = netdev_priv(ndev);
2683f5a2ef1SQuan Nguyen	struct rtnl_link_stats64 stats;
269e6ad7673SIyappan Subramanian	int i;
270e6ad7673SIyappan Subramanian
2713f5a2ef1SQuan Nguyen	dev_get_stats(ndev, &stats);
272e6ad7673SIyappan Subramanian	for (i = 0; i < XGENE_STATS_LEN; i++)
2733f5a2ef1SQuan Nguyen		data[i] = *(u64 *)((char *)&stats + gstrings_stats[i].offset);
2742d07d8e4SQuan Nguyen
2752d07d8e4SQuan Nguyen	xgene_get_extd_stats(pdata);
2762d07d8e4SQuan Nguyen	for (i = 0; i < XGENE_EXTD_STATS_LEN; i++)
2772d07d8e4SQuan Nguyen		data[i + XGENE_STATS_LEN] = pdata->extd_stats[i];
278e6ad7673SIyappan Subramanian}
279e6ad7673SIyappan Subramanian
2800296fe4dSIyappan Subramanianstatic void xgene_get_pauseparam(struct net_device *ndev,
2810296fe4dSIyappan Subramanian				 struct ethtool_pauseparam *pp)
2820296fe4dSIyappan Subramanian{
2830296fe4dSIyappan Subramanian	struct xgene_enet_pdata *pdata = netdev_priv(ndev);
2840296fe4dSIyappan Subramanian
2850296fe4dSIyappan Subramanian	pp->autoneg = pdata->pause_autoneg;
2860296fe4dSIyappan Subramanian	pp->tx_pause = pdata->tx_pause;
2870296fe4dSIyappan Subramanian	pp->rx_pause = pdata->rx_pause;
2880296fe4dSIyappan Subramanian}
2890296fe4dSIyappan Subramanian
2900296fe4dSIyappan Subramanianstatic int xgene_set_pauseparam(struct net_device *ndev,
2910296fe4dSIyappan Subramanian				struct ethtool_pauseparam *pp)
2920296fe4dSIyappan Subramanian{
2930296fe4dSIyappan Subramanian	struct xgene_enet_pdata *pdata = netdev_priv(ndev);
2940296fe4dSIyappan Subramanian	struct phy_device *phydev = ndev->phydev;
2950296fe4dSIyappan Subramanian
296326dde3eSIyappan Subramanian	if (phy_interface_mode_is_rgmii(pdata->phy_mode) ||
2970296fe4dSIyappan Subramanian	    pdata->phy_mode == PHY_INTERFACE_MODE_SGMII) {
2980296fe4dSIyappan Subramanian		if (!phydev)
2990296fe4dSIyappan Subramanian			return -EINVAL;
3000296fe4dSIyappan Subramanian
30122b7d299SAndrew Lunn		if (!phy_validate_pause(phydev, pp))
3020296fe4dSIyappan Subramanian			return -EINVAL;
3030296fe4dSIyappan Subramanian
3040296fe4dSIyappan Subramanian		pdata->pause_autoneg = pp->autoneg;
3050296fe4dSIyappan Subramanian		pdata->tx_pause = pp->tx_pause;
3060296fe4dSIyappan Subramanian		pdata->rx_pause = pp->rx_pause;
3070296fe4dSIyappan Subramanian
30870814e81SAndrew Lunn		phy_set_asym_pause(phydev, pp->rx_pause,  pp->tx_pause);
3090296fe4dSIyappan Subramanian
31070814e81SAndrew Lunn		if (!pp->autoneg) {
31170814e81SAndrew Lunn			pdata->mac_ops->flowctl_tx(pdata, pdata->tx_pause);
31270814e81SAndrew Lunn			pdata->mac_ops->flowctl_rx(pdata, pdata->rx_pause);
3130296fe4dSIyappan Subramanian		}
3140296fe4dSIyappan Subramanian	} else {
3150296fe4dSIyappan Subramanian		if (pp->autoneg)
3160296fe4dSIyappan Subramanian			return -EINVAL;
3170296fe4dSIyappan Subramanian
3180296fe4dSIyappan Subramanian		pdata->tx_pause = pp->tx_pause;
3190296fe4dSIyappan Subramanian		pdata->rx_pause = pp->rx_pause;
3200296fe4dSIyappan Subramanian
3210296fe4dSIyappan Subramanian		pdata->mac_ops->flowctl_tx(pdata, pdata->tx_pause);
3220296fe4dSIyappan Subramanian		pdata->mac_ops->flowctl_rx(pdata, pdata->rx_pause);
3230296fe4dSIyappan Subramanian	}
3240296fe4dSIyappan Subramanian
3250296fe4dSIyappan Subramanian	return 0;
3260296fe4dSIyappan Subramanian}
3270296fe4dSIyappan Subramanian
328e6ad7673SIyappan Subramanianstatic const struct ethtool_ops xgene_ethtool_ops = {
329e6ad7673SIyappan Subramanian	.get_drvinfo = xgene_get_drvinfo,
330e6ad7673SIyappan Subramanian	.get_link = ethtool_op_get_link,
331e6ad7673SIyappan Subramanian	.get_strings = xgene_get_strings,
332e6ad7673SIyappan Subramanian	.get_sset_count = xgene_get_sset_count,
33336a19b29SPhilippe Reynes	.get_ethtool_stats = xgene_get_ethtool_stats,
33436a19b29SPhilippe Reynes	.get_link_ksettings = xgene_get_link_ksettings,
33536a19b29SPhilippe Reynes	.set_link_ksettings = xgene_set_link_ksettings,
3360296fe4dSIyappan Subramanian	.get_pauseparam = xgene_get_pauseparam,
3370296fe4dSIyappan Subramanian	.set_pauseparam = xgene_set_pauseparam
338e6ad7673SIyappan Subramanian};
339e6ad7673SIyappan Subramanian
340e6ad7673SIyappan Subramanianvoid xgene_enet_set_ethtool_ops(struct net_device *ndev)
341e6ad7673SIyappan Subramanian{
342e6ad7673SIyappan Subramanian	ndev->ethtool_ops = &xgene_ethtool_ops;
343e6ad7673SIyappan Subramanian}
344