18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Copyright (c) 2007 Freescale Semiconductor, Inc. All rights reserved.
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Description: QE UCC Gigabit Ethernet Ethtool API Set
68c2ecf20Sopenharmony_ci *
78c2ecf20Sopenharmony_ci * Author: Li Yang <leoli@freescale.com>
88c2ecf20Sopenharmony_ci *
98c2ecf20Sopenharmony_ci * Limitation:
108c2ecf20Sopenharmony_ci * Can only get/set settings of the first queue.
118c2ecf20Sopenharmony_ci * Need to re-open the interface manually after changing some parameters.
128c2ecf20Sopenharmony_ci */
138c2ecf20Sopenharmony_ci
148c2ecf20Sopenharmony_ci#include <linux/kernel.h>
158c2ecf20Sopenharmony_ci#include <linux/errno.h>
168c2ecf20Sopenharmony_ci#include <linux/stddef.h>
178c2ecf20Sopenharmony_ci#include <linux/interrupt.h>
188c2ecf20Sopenharmony_ci#include <linux/netdevice.h>
198c2ecf20Sopenharmony_ci#include <linux/etherdevice.h>
208c2ecf20Sopenharmony_ci#include <linux/skbuff.h>
218c2ecf20Sopenharmony_ci#include <linux/spinlock.h>
228c2ecf20Sopenharmony_ci#include <linux/mm.h>
238c2ecf20Sopenharmony_ci#include <linux/delay.h>
248c2ecf20Sopenharmony_ci#include <linux/dma-mapping.h>
258c2ecf20Sopenharmony_ci#include <linux/ethtool.h>
268c2ecf20Sopenharmony_ci#include <linux/mii.h>
278c2ecf20Sopenharmony_ci#include <linux/phy.h>
288c2ecf20Sopenharmony_ci
298c2ecf20Sopenharmony_ci#include <asm/io.h>
308c2ecf20Sopenharmony_ci#include <asm/irq.h>
318c2ecf20Sopenharmony_ci#include <linux/uaccess.h>
328c2ecf20Sopenharmony_ci#include <asm/types.h>
338c2ecf20Sopenharmony_ci
348c2ecf20Sopenharmony_ci#include "ucc_geth.h"
358c2ecf20Sopenharmony_ci
368c2ecf20Sopenharmony_cistatic const char hw_stat_gstrings[][ETH_GSTRING_LEN] = {
378c2ecf20Sopenharmony_ci	"tx-64-frames",
388c2ecf20Sopenharmony_ci	"tx-65-127-frames",
398c2ecf20Sopenharmony_ci	"tx-128-255-frames",
408c2ecf20Sopenharmony_ci	"rx-64-frames",
418c2ecf20Sopenharmony_ci	"rx-65-127-frames",
428c2ecf20Sopenharmony_ci	"rx-128-255-frames",
438c2ecf20Sopenharmony_ci	"tx-bytes-ok",
448c2ecf20Sopenharmony_ci	"tx-pause-frames",
458c2ecf20Sopenharmony_ci	"tx-multicast-frames",
468c2ecf20Sopenharmony_ci	"tx-broadcast-frames",
478c2ecf20Sopenharmony_ci	"rx-frames",
488c2ecf20Sopenharmony_ci	"rx-bytes-ok",
498c2ecf20Sopenharmony_ci	"rx-bytes-all",
508c2ecf20Sopenharmony_ci	"rx-multicast-frames",
518c2ecf20Sopenharmony_ci	"rx-broadcast-frames",
528c2ecf20Sopenharmony_ci	"stats-counter-carry",
538c2ecf20Sopenharmony_ci	"stats-counter-mask",
548c2ecf20Sopenharmony_ci	"rx-dropped-frames",
558c2ecf20Sopenharmony_ci};
568c2ecf20Sopenharmony_ci
578c2ecf20Sopenharmony_cistatic const char tx_fw_stat_gstrings[][ETH_GSTRING_LEN] = {
588c2ecf20Sopenharmony_ci	"tx-single-collision",
598c2ecf20Sopenharmony_ci	"tx-multiple-collision",
608c2ecf20Sopenharmony_ci	"tx-late-collision",
618c2ecf20Sopenharmony_ci	"tx-aborted-frames",
628c2ecf20Sopenharmony_ci	"tx-lost-frames",
638c2ecf20Sopenharmony_ci	"tx-carrier-sense-errors",
648c2ecf20Sopenharmony_ci	"tx-frames-ok",
658c2ecf20Sopenharmony_ci	"tx-excessive-differ-frames",
668c2ecf20Sopenharmony_ci	"tx-256-511-frames",
678c2ecf20Sopenharmony_ci	"tx-512-1023-frames",
688c2ecf20Sopenharmony_ci	"tx-1024-1518-frames",
698c2ecf20Sopenharmony_ci	"tx-jumbo-frames",
708c2ecf20Sopenharmony_ci};
718c2ecf20Sopenharmony_ci
728c2ecf20Sopenharmony_cistatic const char rx_fw_stat_gstrings[][ETH_GSTRING_LEN] = {
738c2ecf20Sopenharmony_ci	"rx-crc-errors",
748c2ecf20Sopenharmony_ci	"rx-alignment-errors",
758c2ecf20Sopenharmony_ci	"rx-in-range-length-errors",
768c2ecf20Sopenharmony_ci	"rx-out-of-range-length-errors",
778c2ecf20Sopenharmony_ci	"rx-too-long-frames",
788c2ecf20Sopenharmony_ci	"rx-runt",
798c2ecf20Sopenharmony_ci	"rx-very-long-event",
808c2ecf20Sopenharmony_ci	"rx-symbol-errors",
818c2ecf20Sopenharmony_ci	"rx-busy-drop-frames",
828c2ecf20Sopenharmony_ci	"reserved",
838c2ecf20Sopenharmony_ci	"reserved",
848c2ecf20Sopenharmony_ci	"rx-mismatch-drop-frames",
858c2ecf20Sopenharmony_ci	"rx-small-than-64",
868c2ecf20Sopenharmony_ci	"rx-256-511-frames",
878c2ecf20Sopenharmony_ci	"rx-512-1023-frames",
888c2ecf20Sopenharmony_ci	"rx-1024-1518-frames",
898c2ecf20Sopenharmony_ci	"rx-jumbo-frames",
908c2ecf20Sopenharmony_ci	"rx-mac-error-loss",
918c2ecf20Sopenharmony_ci	"rx-pause-frames",
928c2ecf20Sopenharmony_ci	"reserved",
938c2ecf20Sopenharmony_ci	"rx-vlan-removed",
948c2ecf20Sopenharmony_ci	"rx-vlan-replaced",
958c2ecf20Sopenharmony_ci	"rx-vlan-inserted",
968c2ecf20Sopenharmony_ci	"rx-ip-checksum-errors",
978c2ecf20Sopenharmony_ci};
988c2ecf20Sopenharmony_ci
998c2ecf20Sopenharmony_ci#define UEC_HW_STATS_LEN ARRAY_SIZE(hw_stat_gstrings)
1008c2ecf20Sopenharmony_ci#define UEC_TX_FW_STATS_LEN ARRAY_SIZE(tx_fw_stat_gstrings)
1018c2ecf20Sopenharmony_ci#define UEC_RX_FW_STATS_LEN ARRAY_SIZE(rx_fw_stat_gstrings)
1028c2ecf20Sopenharmony_ci
1038c2ecf20Sopenharmony_cistatic int
1048c2ecf20Sopenharmony_ciuec_get_ksettings(struct net_device *netdev, struct ethtool_link_ksettings *cmd)
1058c2ecf20Sopenharmony_ci{
1068c2ecf20Sopenharmony_ci	struct ucc_geth_private *ugeth = netdev_priv(netdev);
1078c2ecf20Sopenharmony_ci	struct phy_device *phydev = ugeth->phydev;
1088c2ecf20Sopenharmony_ci
1098c2ecf20Sopenharmony_ci	if (!phydev)
1108c2ecf20Sopenharmony_ci		return -ENODEV;
1118c2ecf20Sopenharmony_ci
1128c2ecf20Sopenharmony_ci	phy_ethtool_ksettings_get(phydev, cmd);
1138c2ecf20Sopenharmony_ci
1148c2ecf20Sopenharmony_ci	return 0;
1158c2ecf20Sopenharmony_ci}
1168c2ecf20Sopenharmony_ci
1178c2ecf20Sopenharmony_cistatic int
1188c2ecf20Sopenharmony_ciuec_set_ksettings(struct net_device *netdev,
1198c2ecf20Sopenharmony_ci		  const struct ethtool_link_ksettings *cmd)
1208c2ecf20Sopenharmony_ci{
1218c2ecf20Sopenharmony_ci	struct ucc_geth_private *ugeth = netdev_priv(netdev);
1228c2ecf20Sopenharmony_ci	struct phy_device *phydev = ugeth->phydev;
1238c2ecf20Sopenharmony_ci
1248c2ecf20Sopenharmony_ci	if (!phydev)
1258c2ecf20Sopenharmony_ci		return -ENODEV;
1268c2ecf20Sopenharmony_ci
1278c2ecf20Sopenharmony_ci	return phy_ethtool_ksettings_set(phydev, cmd);
1288c2ecf20Sopenharmony_ci}
1298c2ecf20Sopenharmony_ci
1308c2ecf20Sopenharmony_cistatic void
1318c2ecf20Sopenharmony_ciuec_get_pauseparam(struct net_device *netdev,
1328c2ecf20Sopenharmony_ci                     struct ethtool_pauseparam *pause)
1338c2ecf20Sopenharmony_ci{
1348c2ecf20Sopenharmony_ci	struct ucc_geth_private *ugeth = netdev_priv(netdev);
1358c2ecf20Sopenharmony_ci
1368c2ecf20Sopenharmony_ci	pause->autoneg = ugeth->phydev->autoneg;
1378c2ecf20Sopenharmony_ci
1388c2ecf20Sopenharmony_ci	if (ugeth->ug_info->receiveFlowControl)
1398c2ecf20Sopenharmony_ci		pause->rx_pause = 1;
1408c2ecf20Sopenharmony_ci	if (ugeth->ug_info->transmitFlowControl)
1418c2ecf20Sopenharmony_ci		pause->tx_pause = 1;
1428c2ecf20Sopenharmony_ci}
1438c2ecf20Sopenharmony_ci
1448c2ecf20Sopenharmony_cistatic int
1458c2ecf20Sopenharmony_ciuec_set_pauseparam(struct net_device *netdev,
1468c2ecf20Sopenharmony_ci                     struct ethtool_pauseparam *pause)
1478c2ecf20Sopenharmony_ci{
1488c2ecf20Sopenharmony_ci	struct ucc_geth_private *ugeth = netdev_priv(netdev);
1498c2ecf20Sopenharmony_ci	int ret = 0;
1508c2ecf20Sopenharmony_ci
1518c2ecf20Sopenharmony_ci	ugeth->ug_info->receiveFlowControl = pause->rx_pause;
1528c2ecf20Sopenharmony_ci	ugeth->ug_info->transmitFlowControl = pause->tx_pause;
1538c2ecf20Sopenharmony_ci
1548c2ecf20Sopenharmony_ci	if (ugeth->phydev->autoneg) {
1558c2ecf20Sopenharmony_ci		if (netif_running(netdev)) {
1568c2ecf20Sopenharmony_ci			/* FIXME: automatically restart */
1578c2ecf20Sopenharmony_ci			netdev_info(netdev, "Please re-open the interface\n");
1588c2ecf20Sopenharmony_ci		}
1598c2ecf20Sopenharmony_ci	} else {
1608c2ecf20Sopenharmony_ci		struct ucc_geth_info *ug_info = ugeth->ug_info;
1618c2ecf20Sopenharmony_ci
1628c2ecf20Sopenharmony_ci		ret = init_flow_control_params(ug_info->aufc,
1638c2ecf20Sopenharmony_ci					ug_info->receiveFlowControl,
1648c2ecf20Sopenharmony_ci					ug_info->transmitFlowControl,
1658c2ecf20Sopenharmony_ci					ug_info->pausePeriod,
1668c2ecf20Sopenharmony_ci					ug_info->extensionField,
1678c2ecf20Sopenharmony_ci					&ugeth->uccf->uf_regs->upsmr,
1688c2ecf20Sopenharmony_ci					&ugeth->ug_regs->uempr,
1698c2ecf20Sopenharmony_ci					&ugeth->ug_regs->maccfg1);
1708c2ecf20Sopenharmony_ci	}
1718c2ecf20Sopenharmony_ci
1728c2ecf20Sopenharmony_ci	return ret;
1738c2ecf20Sopenharmony_ci}
1748c2ecf20Sopenharmony_ci
1758c2ecf20Sopenharmony_cistatic uint32_t
1768c2ecf20Sopenharmony_ciuec_get_msglevel(struct net_device *netdev)
1778c2ecf20Sopenharmony_ci{
1788c2ecf20Sopenharmony_ci	struct ucc_geth_private *ugeth = netdev_priv(netdev);
1798c2ecf20Sopenharmony_ci	return ugeth->msg_enable;
1808c2ecf20Sopenharmony_ci}
1818c2ecf20Sopenharmony_ci
1828c2ecf20Sopenharmony_cistatic void
1838c2ecf20Sopenharmony_ciuec_set_msglevel(struct net_device *netdev, uint32_t data)
1848c2ecf20Sopenharmony_ci{
1858c2ecf20Sopenharmony_ci	struct ucc_geth_private *ugeth = netdev_priv(netdev);
1868c2ecf20Sopenharmony_ci	ugeth->msg_enable = data;
1878c2ecf20Sopenharmony_ci}
1888c2ecf20Sopenharmony_ci
1898c2ecf20Sopenharmony_cistatic int
1908c2ecf20Sopenharmony_ciuec_get_regs_len(struct net_device *netdev)
1918c2ecf20Sopenharmony_ci{
1928c2ecf20Sopenharmony_ci	return sizeof(struct ucc_geth);
1938c2ecf20Sopenharmony_ci}
1948c2ecf20Sopenharmony_ci
1958c2ecf20Sopenharmony_cistatic void
1968c2ecf20Sopenharmony_ciuec_get_regs(struct net_device *netdev,
1978c2ecf20Sopenharmony_ci               struct ethtool_regs *regs, void *p)
1988c2ecf20Sopenharmony_ci{
1998c2ecf20Sopenharmony_ci	int i;
2008c2ecf20Sopenharmony_ci	struct ucc_geth_private *ugeth = netdev_priv(netdev);
2018c2ecf20Sopenharmony_ci	u32 __iomem *ug_regs = (u32 __iomem *)ugeth->ug_regs;
2028c2ecf20Sopenharmony_ci	u32 *buff = p;
2038c2ecf20Sopenharmony_ci
2048c2ecf20Sopenharmony_ci	for (i = 0; i < sizeof(struct ucc_geth) / sizeof(u32); i++)
2058c2ecf20Sopenharmony_ci		buff[i] = in_be32(&ug_regs[i]);
2068c2ecf20Sopenharmony_ci}
2078c2ecf20Sopenharmony_ci
2088c2ecf20Sopenharmony_cistatic void
2098c2ecf20Sopenharmony_ciuec_get_ringparam(struct net_device *netdev,
2108c2ecf20Sopenharmony_ci                    struct ethtool_ringparam *ring)
2118c2ecf20Sopenharmony_ci{
2128c2ecf20Sopenharmony_ci	struct ucc_geth_private *ugeth = netdev_priv(netdev);
2138c2ecf20Sopenharmony_ci	struct ucc_geth_info *ug_info = ugeth->ug_info;
2148c2ecf20Sopenharmony_ci	int queue = 0;
2158c2ecf20Sopenharmony_ci
2168c2ecf20Sopenharmony_ci	ring->rx_max_pending = UCC_GETH_BD_RING_SIZE_MAX;
2178c2ecf20Sopenharmony_ci	ring->rx_mini_max_pending = UCC_GETH_BD_RING_SIZE_MAX;
2188c2ecf20Sopenharmony_ci	ring->rx_jumbo_max_pending = UCC_GETH_BD_RING_SIZE_MAX;
2198c2ecf20Sopenharmony_ci	ring->tx_max_pending = UCC_GETH_BD_RING_SIZE_MAX;
2208c2ecf20Sopenharmony_ci
2218c2ecf20Sopenharmony_ci	ring->rx_pending = ug_info->bdRingLenRx[queue];
2228c2ecf20Sopenharmony_ci	ring->rx_mini_pending = ug_info->bdRingLenRx[queue];
2238c2ecf20Sopenharmony_ci	ring->rx_jumbo_pending = ug_info->bdRingLenRx[queue];
2248c2ecf20Sopenharmony_ci	ring->tx_pending = ug_info->bdRingLenTx[queue];
2258c2ecf20Sopenharmony_ci}
2268c2ecf20Sopenharmony_ci
2278c2ecf20Sopenharmony_cistatic int
2288c2ecf20Sopenharmony_ciuec_set_ringparam(struct net_device *netdev,
2298c2ecf20Sopenharmony_ci                    struct ethtool_ringparam *ring)
2308c2ecf20Sopenharmony_ci{
2318c2ecf20Sopenharmony_ci	struct ucc_geth_private *ugeth = netdev_priv(netdev);
2328c2ecf20Sopenharmony_ci	struct ucc_geth_info *ug_info = ugeth->ug_info;
2338c2ecf20Sopenharmony_ci	int queue = 0, ret = 0;
2348c2ecf20Sopenharmony_ci
2358c2ecf20Sopenharmony_ci	if (ring->rx_pending < UCC_GETH_RX_BD_RING_SIZE_MIN) {
2368c2ecf20Sopenharmony_ci		netdev_info(netdev, "RxBD ring size must be no smaller than %d\n",
2378c2ecf20Sopenharmony_ci			    UCC_GETH_RX_BD_RING_SIZE_MIN);
2388c2ecf20Sopenharmony_ci		return -EINVAL;
2398c2ecf20Sopenharmony_ci	}
2408c2ecf20Sopenharmony_ci	if (ring->rx_pending % UCC_GETH_RX_BD_RING_SIZE_ALIGNMENT) {
2418c2ecf20Sopenharmony_ci		netdev_info(netdev, "RxBD ring size must be multiple of %d\n",
2428c2ecf20Sopenharmony_ci			    UCC_GETH_RX_BD_RING_SIZE_ALIGNMENT);
2438c2ecf20Sopenharmony_ci		return -EINVAL;
2448c2ecf20Sopenharmony_ci	}
2458c2ecf20Sopenharmony_ci	if (ring->tx_pending < UCC_GETH_TX_BD_RING_SIZE_MIN) {
2468c2ecf20Sopenharmony_ci		netdev_info(netdev, "TxBD ring size must be no smaller than %d\n",
2478c2ecf20Sopenharmony_ci			    UCC_GETH_TX_BD_RING_SIZE_MIN);
2488c2ecf20Sopenharmony_ci		return -EINVAL;
2498c2ecf20Sopenharmony_ci	}
2508c2ecf20Sopenharmony_ci
2518c2ecf20Sopenharmony_ci	if (netif_running(netdev))
2528c2ecf20Sopenharmony_ci		return -EBUSY;
2538c2ecf20Sopenharmony_ci
2548c2ecf20Sopenharmony_ci	ug_info->bdRingLenRx[queue] = ring->rx_pending;
2558c2ecf20Sopenharmony_ci	ug_info->bdRingLenTx[queue] = ring->tx_pending;
2568c2ecf20Sopenharmony_ci
2578c2ecf20Sopenharmony_ci	return ret;
2588c2ecf20Sopenharmony_ci}
2598c2ecf20Sopenharmony_ci
2608c2ecf20Sopenharmony_cistatic int uec_get_sset_count(struct net_device *netdev, int sset)
2618c2ecf20Sopenharmony_ci{
2628c2ecf20Sopenharmony_ci	struct ucc_geth_private *ugeth = netdev_priv(netdev);
2638c2ecf20Sopenharmony_ci	u32 stats_mode = ugeth->ug_info->statisticsMode;
2648c2ecf20Sopenharmony_ci	int len = 0;
2658c2ecf20Sopenharmony_ci
2668c2ecf20Sopenharmony_ci	switch (sset) {
2678c2ecf20Sopenharmony_ci	case ETH_SS_STATS:
2688c2ecf20Sopenharmony_ci		if (stats_mode & UCC_GETH_STATISTICS_GATHERING_MODE_HARDWARE)
2698c2ecf20Sopenharmony_ci			len += UEC_HW_STATS_LEN;
2708c2ecf20Sopenharmony_ci		if (stats_mode & UCC_GETH_STATISTICS_GATHERING_MODE_FIRMWARE_TX)
2718c2ecf20Sopenharmony_ci			len += UEC_TX_FW_STATS_LEN;
2728c2ecf20Sopenharmony_ci		if (stats_mode & UCC_GETH_STATISTICS_GATHERING_MODE_FIRMWARE_RX)
2738c2ecf20Sopenharmony_ci			len += UEC_RX_FW_STATS_LEN;
2748c2ecf20Sopenharmony_ci
2758c2ecf20Sopenharmony_ci		return len;
2768c2ecf20Sopenharmony_ci
2778c2ecf20Sopenharmony_ci	default:
2788c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
2798c2ecf20Sopenharmony_ci	}
2808c2ecf20Sopenharmony_ci}
2818c2ecf20Sopenharmony_ci
2828c2ecf20Sopenharmony_cistatic void uec_get_strings(struct net_device *netdev, u32 stringset, u8 *buf)
2838c2ecf20Sopenharmony_ci{
2848c2ecf20Sopenharmony_ci	struct ucc_geth_private *ugeth = netdev_priv(netdev);
2858c2ecf20Sopenharmony_ci	u32 stats_mode = ugeth->ug_info->statisticsMode;
2868c2ecf20Sopenharmony_ci
2878c2ecf20Sopenharmony_ci	if (stats_mode & UCC_GETH_STATISTICS_GATHERING_MODE_HARDWARE) {
2888c2ecf20Sopenharmony_ci		memcpy(buf, hw_stat_gstrings, UEC_HW_STATS_LEN *
2898c2ecf20Sopenharmony_ci			       	ETH_GSTRING_LEN);
2908c2ecf20Sopenharmony_ci		buf += UEC_HW_STATS_LEN * ETH_GSTRING_LEN;
2918c2ecf20Sopenharmony_ci	}
2928c2ecf20Sopenharmony_ci	if (stats_mode & UCC_GETH_STATISTICS_GATHERING_MODE_FIRMWARE_TX) {
2938c2ecf20Sopenharmony_ci		memcpy(buf, tx_fw_stat_gstrings, UEC_TX_FW_STATS_LEN *
2948c2ecf20Sopenharmony_ci			       	ETH_GSTRING_LEN);
2958c2ecf20Sopenharmony_ci		buf += UEC_TX_FW_STATS_LEN * ETH_GSTRING_LEN;
2968c2ecf20Sopenharmony_ci	}
2978c2ecf20Sopenharmony_ci	if (stats_mode & UCC_GETH_STATISTICS_GATHERING_MODE_FIRMWARE_RX)
2988c2ecf20Sopenharmony_ci		memcpy(buf, rx_fw_stat_gstrings, UEC_RX_FW_STATS_LEN *
2998c2ecf20Sopenharmony_ci			       	ETH_GSTRING_LEN);
3008c2ecf20Sopenharmony_ci}
3018c2ecf20Sopenharmony_ci
3028c2ecf20Sopenharmony_cistatic void uec_get_ethtool_stats(struct net_device *netdev,
3038c2ecf20Sopenharmony_ci		struct ethtool_stats *stats, uint64_t *data)
3048c2ecf20Sopenharmony_ci{
3058c2ecf20Sopenharmony_ci	struct ucc_geth_private *ugeth = netdev_priv(netdev);
3068c2ecf20Sopenharmony_ci	u32 stats_mode = ugeth->ug_info->statisticsMode;
3078c2ecf20Sopenharmony_ci	u32 __iomem *base;
3088c2ecf20Sopenharmony_ci	int i, j = 0;
3098c2ecf20Sopenharmony_ci
3108c2ecf20Sopenharmony_ci	if (stats_mode & UCC_GETH_STATISTICS_GATHERING_MODE_HARDWARE) {
3118c2ecf20Sopenharmony_ci		if (ugeth->ug_regs)
3128c2ecf20Sopenharmony_ci			base = (u32 __iomem *)&ugeth->ug_regs->tx64;
3138c2ecf20Sopenharmony_ci		else
3148c2ecf20Sopenharmony_ci			base = NULL;
3158c2ecf20Sopenharmony_ci
3168c2ecf20Sopenharmony_ci		for (i = 0; i < UEC_HW_STATS_LEN; i++)
3178c2ecf20Sopenharmony_ci			data[j++] = base ? in_be32(&base[i]) : 0;
3188c2ecf20Sopenharmony_ci	}
3198c2ecf20Sopenharmony_ci	if (stats_mode & UCC_GETH_STATISTICS_GATHERING_MODE_FIRMWARE_TX) {
3208c2ecf20Sopenharmony_ci		base = (u32 __iomem *)ugeth->p_tx_fw_statistics_pram;
3218c2ecf20Sopenharmony_ci		for (i = 0; i < UEC_TX_FW_STATS_LEN; i++)
3228c2ecf20Sopenharmony_ci			data[j++] = base ? in_be32(&base[i]) : 0;
3238c2ecf20Sopenharmony_ci	}
3248c2ecf20Sopenharmony_ci	if (stats_mode & UCC_GETH_STATISTICS_GATHERING_MODE_FIRMWARE_RX) {
3258c2ecf20Sopenharmony_ci		base = (u32 __iomem *)ugeth->p_rx_fw_statistics_pram;
3268c2ecf20Sopenharmony_ci		for (i = 0; i < UEC_RX_FW_STATS_LEN; i++)
3278c2ecf20Sopenharmony_ci			data[j++] = base ? in_be32(&base[i]) : 0;
3288c2ecf20Sopenharmony_ci	}
3298c2ecf20Sopenharmony_ci}
3308c2ecf20Sopenharmony_ci
3318c2ecf20Sopenharmony_ci/* Report driver information */
3328c2ecf20Sopenharmony_cistatic void
3338c2ecf20Sopenharmony_ciuec_get_drvinfo(struct net_device *netdev,
3348c2ecf20Sopenharmony_ci                       struct ethtool_drvinfo *drvinfo)
3358c2ecf20Sopenharmony_ci{
3368c2ecf20Sopenharmony_ci	strlcpy(drvinfo->driver, DRV_NAME, sizeof(drvinfo->driver));
3378c2ecf20Sopenharmony_ci	strlcpy(drvinfo->bus_info, "QUICC ENGINE", sizeof(drvinfo->bus_info));
3388c2ecf20Sopenharmony_ci}
3398c2ecf20Sopenharmony_ci
3408c2ecf20Sopenharmony_ci#ifdef CONFIG_PM
3418c2ecf20Sopenharmony_ci
3428c2ecf20Sopenharmony_cistatic void uec_get_wol(struct net_device *netdev, struct ethtool_wolinfo *wol)
3438c2ecf20Sopenharmony_ci{
3448c2ecf20Sopenharmony_ci	struct ucc_geth_private *ugeth = netdev_priv(netdev);
3458c2ecf20Sopenharmony_ci	struct phy_device *phydev = ugeth->phydev;
3468c2ecf20Sopenharmony_ci
3478c2ecf20Sopenharmony_ci	if (phydev && phydev->irq)
3488c2ecf20Sopenharmony_ci		wol->supported |= WAKE_PHY;
3498c2ecf20Sopenharmony_ci	if (qe_alive_during_sleep())
3508c2ecf20Sopenharmony_ci		wol->supported |= WAKE_MAGIC;
3518c2ecf20Sopenharmony_ci
3528c2ecf20Sopenharmony_ci	wol->wolopts = ugeth->wol_en;
3538c2ecf20Sopenharmony_ci}
3548c2ecf20Sopenharmony_ci
3558c2ecf20Sopenharmony_cistatic int uec_set_wol(struct net_device *netdev, struct ethtool_wolinfo *wol)
3568c2ecf20Sopenharmony_ci{
3578c2ecf20Sopenharmony_ci	struct ucc_geth_private *ugeth = netdev_priv(netdev);
3588c2ecf20Sopenharmony_ci	struct phy_device *phydev = ugeth->phydev;
3598c2ecf20Sopenharmony_ci
3608c2ecf20Sopenharmony_ci	if (wol->wolopts & ~(WAKE_PHY | WAKE_MAGIC))
3618c2ecf20Sopenharmony_ci		return -EINVAL;
3628c2ecf20Sopenharmony_ci	else if (wol->wolopts & WAKE_PHY && (!phydev || !phydev->irq))
3638c2ecf20Sopenharmony_ci		return -EINVAL;
3648c2ecf20Sopenharmony_ci	else if (wol->wolopts & WAKE_MAGIC && !qe_alive_during_sleep())
3658c2ecf20Sopenharmony_ci		return -EINVAL;
3668c2ecf20Sopenharmony_ci
3678c2ecf20Sopenharmony_ci	ugeth->wol_en = wol->wolopts;
3688c2ecf20Sopenharmony_ci	device_set_wakeup_enable(&netdev->dev, ugeth->wol_en);
3698c2ecf20Sopenharmony_ci
3708c2ecf20Sopenharmony_ci	return 0;
3718c2ecf20Sopenharmony_ci}
3728c2ecf20Sopenharmony_ci
3738c2ecf20Sopenharmony_ci#else
3748c2ecf20Sopenharmony_ci#define uec_get_wol NULL
3758c2ecf20Sopenharmony_ci#define uec_set_wol NULL
3768c2ecf20Sopenharmony_ci#endif /* CONFIG_PM */
3778c2ecf20Sopenharmony_ci
3788c2ecf20Sopenharmony_cistatic const struct ethtool_ops uec_ethtool_ops = {
3798c2ecf20Sopenharmony_ci	.get_drvinfo            = uec_get_drvinfo,
3808c2ecf20Sopenharmony_ci	.get_regs_len           = uec_get_regs_len,
3818c2ecf20Sopenharmony_ci	.get_regs               = uec_get_regs,
3828c2ecf20Sopenharmony_ci	.get_msglevel           = uec_get_msglevel,
3838c2ecf20Sopenharmony_ci	.set_msglevel           = uec_set_msglevel,
3848c2ecf20Sopenharmony_ci	.nway_reset             = phy_ethtool_nway_reset,
3858c2ecf20Sopenharmony_ci	.get_link               = ethtool_op_get_link,
3868c2ecf20Sopenharmony_ci	.get_ringparam          = uec_get_ringparam,
3878c2ecf20Sopenharmony_ci	.set_ringparam          = uec_set_ringparam,
3888c2ecf20Sopenharmony_ci	.get_pauseparam         = uec_get_pauseparam,
3898c2ecf20Sopenharmony_ci	.set_pauseparam         = uec_set_pauseparam,
3908c2ecf20Sopenharmony_ci	.get_sset_count		= uec_get_sset_count,
3918c2ecf20Sopenharmony_ci	.get_strings            = uec_get_strings,
3928c2ecf20Sopenharmony_ci	.get_ethtool_stats      = uec_get_ethtool_stats,
3938c2ecf20Sopenharmony_ci	.get_wol		= uec_get_wol,
3948c2ecf20Sopenharmony_ci	.set_wol		= uec_set_wol,
3958c2ecf20Sopenharmony_ci	.get_ts_info		= ethtool_op_get_ts_info,
3968c2ecf20Sopenharmony_ci	.get_link_ksettings	= uec_get_ksettings,
3978c2ecf20Sopenharmony_ci	.set_link_ksettings	= uec_set_ksettings,
3988c2ecf20Sopenharmony_ci};
3998c2ecf20Sopenharmony_ci
4008c2ecf20Sopenharmony_civoid uec_set_ethtool_ops(struct net_device *netdev)
4018c2ecf20Sopenharmony_ci{
4028c2ecf20Sopenharmony_ci	netdev->ethtool_ops = &uec_ethtool_ops;
4038c2ecf20Sopenharmony_ci}
404