162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Copyright (c) 2007 Freescale Semiconductor, Inc. All rights reserved.
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Description: QE UCC Gigabit Ethernet Ethtool API Set
662306a36Sopenharmony_ci *
762306a36Sopenharmony_ci * Author: Li Yang <leoli@freescale.com>
862306a36Sopenharmony_ci *
962306a36Sopenharmony_ci * Limitation:
1062306a36Sopenharmony_ci * Can only get/set settings of the first queue.
1162306a36Sopenharmony_ci * Need to re-open the interface manually after changing some parameters.
1262306a36Sopenharmony_ci */
1362306a36Sopenharmony_ci
1462306a36Sopenharmony_ci#include <linux/kernel.h>
1562306a36Sopenharmony_ci#include <linux/errno.h>
1662306a36Sopenharmony_ci#include <linux/stddef.h>
1762306a36Sopenharmony_ci#include <linux/interrupt.h>
1862306a36Sopenharmony_ci#include <linux/netdevice.h>
1962306a36Sopenharmony_ci#include <linux/etherdevice.h>
2062306a36Sopenharmony_ci#include <linux/skbuff.h>
2162306a36Sopenharmony_ci#include <linux/spinlock.h>
2262306a36Sopenharmony_ci#include <linux/mm.h>
2362306a36Sopenharmony_ci#include <linux/delay.h>
2462306a36Sopenharmony_ci#include <linux/dma-mapping.h>
2562306a36Sopenharmony_ci#include <linux/ethtool.h>
2662306a36Sopenharmony_ci#include <linux/mii.h>
2762306a36Sopenharmony_ci#include <linux/phy.h>
2862306a36Sopenharmony_ci
2962306a36Sopenharmony_ci#include <asm/io.h>
3062306a36Sopenharmony_ci#include <asm/irq.h>
3162306a36Sopenharmony_ci#include <linux/uaccess.h>
3262306a36Sopenharmony_ci#include <asm/types.h>
3362306a36Sopenharmony_ci
3462306a36Sopenharmony_ci#include "ucc_geth.h"
3562306a36Sopenharmony_ci
3662306a36Sopenharmony_cistatic const char hw_stat_gstrings[][ETH_GSTRING_LEN] = {
3762306a36Sopenharmony_ci	"tx-64-frames",
3862306a36Sopenharmony_ci	"tx-65-127-frames",
3962306a36Sopenharmony_ci	"tx-128-255-frames",
4062306a36Sopenharmony_ci	"rx-64-frames",
4162306a36Sopenharmony_ci	"rx-65-127-frames",
4262306a36Sopenharmony_ci	"rx-128-255-frames",
4362306a36Sopenharmony_ci	"tx-bytes-ok",
4462306a36Sopenharmony_ci	"tx-pause-frames",
4562306a36Sopenharmony_ci	"tx-multicast-frames",
4662306a36Sopenharmony_ci	"tx-broadcast-frames",
4762306a36Sopenharmony_ci	"rx-frames",
4862306a36Sopenharmony_ci	"rx-bytes-ok",
4962306a36Sopenharmony_ci	"rx-bytes-all",
5062306a36Sopenharmony_ci	"rx-multicast-frames",
5162306a36Sopenharmony_ci	"rx-broadcast-frames",
5262306a36Sopenharmony_ci	"stats-counter-carry",
5362306a36Sopenharmony_ci	"stats-counter-mask",
5462306a36Sopenharmony_ci	"rx-dropped-frames",
5562306a36Sopenharmony_ci};
5662306a36Sopenharmony_ci
5762306a36Sopenharmony_cistatic const char tx_fw_stat_gstrings[][ETH_GSTRING_LEN] = {
5862306a36Sopenharmony_ci	"tx-single-collision",
5962306a36Sopenharmony_ci	"tx-multiple-collision",
6062306a36Sopenharmony_ci	"tx-late-collision",
6162306a36Sopenharmony_ci	"tx-aborted-frames",
6262306a36Sopenharmony_ci	"tx-lost-frames",
6362306a36Sopenharmony_ci	"tx-carrier-sense-errors",
6462306a36Sopenharmony_ci	"tx-frames-ok",
6562306a36Sopenharmony_ci	"tx-excessive-differ-frames",
6662306a36Sopenharmony_ci	"tx-256-511-frames",
6762306a36Sopenharmony_ci	"tx-512-1023-frames",
6862306a36Sopenharmony_ci	"tx-1024-1518-frames",
6962306a36Sopenharmony_ci	"tx-jumbo-frames",
7062306a36Sopenharmony_ci};
7162306a36Sopenharmony_ci
7262306a36Sopenharmony_cistatic const char rx_fw_stat_gstrings[][ETH_GSTRING_LEN] = {
7362306a36Sopenharmony_ci	"rx-crc-errors",
7462306a36Sopenharmony_ci	"rx-alignment-errors",
7562306a36Sopenharmony_ci	"rx-in-range-length-errors",
7662306a36Sopenharmony_ci	"rx-out-of-range-length-errors",
7762306a36Sopenharmony_ci	"rx-too-long-frames",
7862306a36Sopenharmony_ci	"rx-runt",
7962306a36Sopenharmony_ci	"rx-very-long-event",
8062306a36Sopenharmony_ci	"rx-symbol-errors",
8162306a36Sopenharmony_ci	"rx-busy-drop-frames",
8262306a36Sopenharmony_ci	"reserved",
8362306a36Sopenharmony_ci	"reserved",
8462306a36Sopenharmony_ci	"rx-mismatch-drop-frames",
8562306a36Sopenharmony_ci	"rx-small-than-64",
8662306a36Sopenharmony_ci	"rx-256-511-frames",
8762306a36Sopenharmony_ci	"rx-512-1023-frames",
8862306a36Sopenharmony_ci	"rx-1024-1518-frames",
8962306a36Sopenharmony_ci	"rx-jumbo-frames",
9062306a36Sopenharmony_ci	"rx-mac-error-loss",
9162306a36Sopenharmony_ci	"rx-pause-frames",
9262306a36Sopenharmony_ci	"reserved",
9362306a36Sopenharmony_ci	"rx-vlan-removed",
9462306a36Sopenharmony_ci	"rx-vlan-replaced",
9562306a36Sopenharmony_ci	"rx-vlan-inserted",
9662306a36Sopenharmony_ci	"rx-ip-checksum-errors",
9762306a36Sopenharmony_ci};
9862306a36Sopenharmony_ci
9962306a36Sopenharmony_ci#define UEC_HW_STATS_LEN ARRAY_SIZE(hw_stat_gstrings)
10062306a36Sopenharmony_ci#define UEC_TX_FW_STATS_LEN ARRAY_SIZE(tx_fw_stat_gstrings)
10162306a36Sopenharmony_ci#define UEC_RX_FW_STATS_LEN ARRAY_SIZE(rx_fw_stat_gstrings)
10262306a36Sopenharmony_ci
10362306a36Sopenharmony_cistatic int
10462306a36Sopenharmony_ciuec_get_ksettings(struct net_device *netdev, struct ethtool_link_ksettings *cmd)
10562306a36Sopenharmony_ci{
10662306a36Sopenharmony_ci	struct ucc_geth_private *ugeth = netdev_priv(netdev);
10762306a36Sopenharmony_ci	struct phy_device *phydev = ugeth->phydev;
10862306a36Sopenharmony_ci
10962306a36Sopenharmony_ci	if (!phydev)
11062306a36Sopenharmony_ci		return -ENODEV;
11162306a36Sopenharmony_ci
11262306a36Sopenharmony_ci	phy_ethtool_ksettings_get(phydev, cmd);
11362306a36Sopenharmony_ci
11462306a36Sopenharmony_ci	return 0;
11562306a36Sopenharmony_ci}
11662306a36Sopenharmony_ci
11762306a36Sopenharmony_cistatic int
11862306a36Sopenharmony_ciuec_set_ksettings(struct net_device *netdev,
11962306a36Sopenharmony_ci		  const struct ethtool_link_ksettings *cmd)
12062306a36Sopenharmony_ci{
12162306a36Sopenharmony_ci	struct ucc_geth_private *ugeth = netdev_priv(netdev);
12262306a36Sopenharmony_ci	struct phy_device *phydev = ugeth->phydev;
12362306a36Sopenharmony_ci
12462306a36Sopenharmony_ci	if (!phydev)
12562306a36Sopenharmony_ci		return -ENODEV;
12662306a36Sopenharmony_ci
12762306a36Sopenharmony_ci	return phy_ethtool_ksettings_set(phydev, cmd);
12862306a36Sopenharmony_ci}
12962306a36Sopenharmony_ci
13062306a36Sopenharmony_cistatic void
13162306a36Sopenharmony_ciuec_get_pauseparam(struct net_device *netdev,
13262306a36Sopenharmony_ci                     struct ethtool_pauseparam *pause)
13362306a36Sopenharmony_ci{
13462306a36Sopenharmony_ci	struct ucc_geth_private *ugeth = netdev_priv(netdev);
13562306a36Sopenharmony_ci
13662306a36Sopenharmony_ci	pause->autoneg = ugeth->phydev->autoneg;
13762306a36Sopenharmony_ci
13862306a36Sopenharmony_ci	if (ugeth->ug_info->receiveFlowControl)
13962306a36Sopenharmony_ci		pause->rx_pause = 1;
14062306a36Sopenharmony_ci	if (ugeth->ug_info->transmitFlowControl)
14162306a36Sopenharmony_ci		pause->tx_pause = 1;
14262306a36Sopenharmony_ci}
14362306a36Sopenharmony_ci
14462306a36Sopenharmony_cistatic int
14562306a36Sopenharmony_ciuec_set_pauseparam(struct net_device *netdev,
14662306a36Sopenharmony_ci                     struct ethtool_pauseparam *pause)
14762306a36Sopenharmony_ci{
14862306a36Sopenharmony_ci	struct ucc_geth_private *ugeth = netdev_priv(netdev);
14962306a36Sopenharmony_ci	int ret = 0;
15062306a36Sopenharmony_ci
15162306a36Sopenharmony_ci	ugeth->ug_info->receiveFlowControl = pause->rx_pause;
15262306a36Sopenharmony_ci	ugeth->ug_info->transmitFlowControl = pause->tx_pause;
15362306a36Sopenharmony_ci
15462306a36Sopenharmony_ci	if (ugeth->phydev->autoneg) {
15562306a36Sopenharmony_ci		if (netif_running(netdev)) {
15662306a36Sopenharmony_ci			/* FIXME: automatically restart */
15762306a36Sopenharmony_ci			netdev_info(netdev, "Please re-open the interface\n");
15862306a36Sopenharmony_ci		}
15962306a36Sopenharmony_ci	} else {
16062306a36Sopenharmony_ci		struct ucc_geth_info *ug_info = ugeth->ug_info;
16162306a36Sopenharmony_ci
16262306a36Sopenharmony_ci		ret = init_flow_control_params(ug_info->aufc,
16362306a36Sopenharmony_ci					ug_info->receiveFlowControl,
16462306a36Sopenharmony_ci					ug_info->transmitFlowControl,
16562306a36Sopenharmony_ci					ug_info->pausePeriod,
16662306a36Sopenharmony_ci					ug_info->extensionField,
16762306a36Sopenharmony_ci					&ugeth->uccf->uf_regs->upsmr,
16862306a36Sopenharmony_ci					&ugeth->ug_regs->uempr,
16962306a36Sopenharmony_ci					&ugeth->ug_regs->maccfg1);
17062306a36Sopenharmony_ci	}
17162306a36Sopenharmony_ci
17262306a36Sopenharmony_ci	return ret;
17362306a36Sopenharmony_ci}
17462306a36Sopenharmony_ci
17562306a36Sopenharmony_cistatic uint32_t
17662306a36Sopenharmony_ciuec_get_msglevel(struct net_device *netdev)
17762306a36Sopenharmony_ci{
17862306a36Sopenharmony_ci	struct ucc_geth_private *ugeth = netdev_priv(netdev);
17962306a36Sopenharmony_ci	return ugeth->msg_enable;
18062306a36Sopenharmony_ci}
18162306a36Sopenharmony_ci
18262306a36Sopenharmony_cistatic void
18362306a36Sopenharmony_ciuec_set_msglevel(struct net_device *netdev, uint32_t data)
18462306a36Sopenharmony_ci{
18562306a36Sopenharmony_ci	struct ucc_geth_private *ugeth = netdev_priv(netdev);
18662306a36Sopenharmony_ci	ugeth->msg_enable = data;
18762306a36Sopenharmony_ci}
18862306a36Sopenharmony_ci
18962306a36Sopenharmony_cistatic int
19062306a36Sopenharmony_ciuec_get_regs_len(struct net_device *netdev)
19162306a36Sopenharmony_ci{
19262306a36Sopenharmony_ci	return sizeof(struct ucc_geth);
19362306a36Sopenharmony_ci}
19462306a36Sopenharmony_ci
19562306a36Sopenharmony_cistatic void
19662306a36Sopenharmony_ciuec_get_regs(struct net_device *netdev,
19762306a36Sopenharmony_ci               struct ethtool_regs *regs, void *p)
19862306a36Sopenharmony_ci{
19962306a36Sopenharmony_ci	int i;
20062306a36Sopenharmony_ci	struct ucc_geth_private *ugeth = netdev_priv(netdev);
20162306a36Sopenharmony_ci	u32 __iomem *ug_regs = (u32 __iomem *)ugeth->ug_regs;
20262306a36Sopenharmony_ci	u32 *buff = p;
20362306a36Sopenharmony_ci
20462306a36Sopenharmony_ci	for (i = 0; i < sizeof(struct ucc_geth) / sizeof(u32); i++)
20562306a36Sopenharmony_ci		buff[i] = in_be32(&ug_regs[i]);
20662306a36Sopenharmony_ci}
20762306a36Sopenharmony_ci
20862306a36Sopenharmony_cistatic void
20962306a36Sopenharmony_ciuec_get_ringparam(struct net_device *netdev,
21062306a36Sopenharmony_ci		  struct ethtool_ringparam *ring,
21162306a36Sopenharmony_ci		  struct kernel_ethtool_ringparam *kernel_ring,
21262306a36Sopenharmony_ci		  struct netlink_ext_ack *extack)
21362306a36Sopenharmony_ci{
21462306a36Sopenharmony_ci	struct ucc_geth_private *ugeth = netdev_priv(netdev);
21562306a36Sopenharmony_ci	struct ucc_geth_info *ug_info = ugeth->ug_info;
21662306a36Sopenharmony_ci	int queue = 0;
21762306a36Sopenharmony_ci
21862306a36Sopenharmony_ci	ring->rx_max_pending = UCC_GETH_BD_RING_SIZE_MAX;
21962306a36Sopenharmony_ci	ring->rx_mini_max_pending = UCC_GETH_BD_RING_SIZE_MAX;
22062306a36Sopenharmony_ci	ring->rx_jumbo_max_pending = UCC_GETH_BD_RING_SIZE_MAX;
22162306a36Sopenharmony_ci	ring->tx_max_pending = UCC_GETH_BD_RING_SIZE_MAX;
22262306a36Sopenharmony_ci
22362306a36Sopenharmony_ci	ring->rx_pending = ug_info->bdRingLenRx[queue];
22462306a36Sopenharmony_ci	ring->rx_mini_pending = ug_info->bdRingLenRx[queue];
22562306a36Sopenharmony_ci	ring->rx_jumbo_pending = ug_info->bdRingLenRx[queue];
22662306a36Sopenharmony_ci	ring->tx_pending = ug_info->bdRingLenTx[queue];
22762306a36Sopenharmony_ci}
22862306a36Sopenharmony_ci
22962306a36Sopenharmony_cistatic int
23062306a36Sopenharmony_ciuec_set_ringparam(struct net_device *netdev,
23162306a36Sopenharmony_ci		  struct ethtool_ringparam *ring,
23262306a36Sopenharmony_ci		  struct kernel_ethtool_ringparam *kernel_ring,
23362306a36Sopenharmony_ci		  struct netlink_ext_ack *extack)
23462306a36Sopenharmony_ci{
23562306a36Sopenharmony_ci	struct ucc_geth_private *ugeth = netdev_priv(netdev);
23662306a36Sopenharmony_ci	struct ucc_geth_info *ug_info = ugeth->ug_info;
23762306a36Sopenharmony_ci	int queue = 0, ret = 0;
23862306a36Sopenharmony_ci
23962306a36Sopenharmony_ci	if (ring->rx_pending < UCC_GETH_RX_BD_RING_SIZE_MIN) {
24062306a36Sopenharmony_ci		netdev_info(netdev, "RxBD ring size must be no smaller than %d\n",
24162306a36Sopenharmony_ci			    UCC_GETH_RX_BD_RING_SIZE_MIN);
24262306a36Sopenharmony_ci		return -EINVAL;
24362306a36Sopenharmony_ci	}
24462306a36Sopenharmony_ci	if (ring->rx_pending % UCC_GETH_RX_BD_RING_SIZE_ALIGNMENT) {
24562306a36Sopenharmony_ci		netdev_info(netdev, "RxBD ring size must be multiple of %d\n",
24662306a36Sopenharmony_ci			    UCC_GETH_RX_BD_RING_SIZE_ALIGNMENT);
24762306a36Sopenharmony_ci		return -EINVAL;
24862306a36Sopenharmony_ci	}
24962306a36Sopenharmony_ci	if (ring->tx_pending < UCC_GETH_TX_BD_RING_SIZE_MIN) {
25062306a36Sopenharmony_ci		netdev_info(netdev, "TxBD ring size must be no smaller than %d\n",
25162306a36Sopenharmony_ci			    UCC_GETH_TX_BD_RING_SIZE_MIN);
25262306a36Sopenharmony_ci		return -EINVAL;
25362306a36Sopenharmony_ci	}
25462306a36Sopenharmony_ci
25562306a36Sopenharmony_ci	if (netif_running(netdev))
25662306a36Sopenharmony_ci		return -EBUSY;
25762306a36Sopenharmony_ci
25862306a36Sopenharmony_ci	ug_info->bdRingLenRx[queue] = ring->rx_pending;
25962306a36Sopenharmony_ci	ug_info->bdRingLenTx[queue] = ring->tx_pending;
26062306a36Sopenharmony_ci
26162306a36Sopenharmony_ci	return ret;
26262306a36Sopenharmony_ci}
26362306a36Sopenharmony_ci
26462306a36Sopenharmony_cistatic int uec_get_sset_count(struct net_device *netdev, int sset)
26562306a36Sopenharmony_ci{
26662306a36Sopenharmony_ci	struct ucc_geth_private *ugeth = netdev_priv(netdev);
26762306a36Sopenharmony_ci	u32 stats_mode = ugeth->ug_info->statisticsMode;
26862306a36Sopenharmony_ci	int len = 0;
26962306a36Sopenharmony_ci
27062306a36Sopenharmony_ci	switch (sset) {
27162306a36Sopenharmony_ci	case ETH_SS_STATS:
27262306a36Sopenharmony_ci		if (stats_mode & UCC_GETH_STATISTICS_GATHERING_MODE_HARDWARE)
27362306a36Sopenharmony_ci			len += UEC_HW_STATS_LEN;
27462306a36Sopenharmony_ci		if (stats_mode & UCC_GETH_STATISTICS_GATHERING_MODE_FIRMWARE_TX)
27562306a36Sopenharmony_ci			len += UEC_TX_FW_STATS_LEN;
27662306a36Sopenharmony_ci		if (stats_mode & UCC_GETH_STATISTICS_GATHERING_MODE_FIRMWARE_RX)
27762306a36Sopenharmony_ci			len += UEC_RX_FW_STATS_LEN;
27862306a36Sopenharmony_ci
27962306a36Sopenharmony_ci		return len;
28062306a36Sopenharmony_ci
28162306a36Sopenharmony_ci	default:
28262306a36Sopenharmony_ci		return -EOPNOTSUPP;
28362306a36Sopenharmony_ci	}
28462306a36Sopenharmony_ci}
28562306a36Sopenharmony_ci
28662306a36Sopenharmony_cistatic void uec_get_strings(struct net_device *netdev, u32 stringset, u8 *buf)
28762306a36Sopenharmony_ci{
28862306a36Sopenharmony_ci	struct ucc_geth_private *ugeth = netdev_priv(netdev);
28962306a36Sopenharmony_ci	u32 stats_mode = ugeth->ug_info->statisticsMode;
29062306a36Sopenharmony_ci
29162306a36Sopenharmony_ci	if (stats_mode & UCC_GETH_STATISTICS_GATHERING_MODE_HARDWARE) {
29262306a36Sopenharmony_ci		memcpy(buf, hw_stat_gstrings, UEC_HW_STATS_LEN *
29362306a36Sopenharmony_ci			       	ETH_GSTRING_LEN);
29462306a36Sopenharmony_ci		buf += UEC_HW_STATS_LEN * ETH_GSTRING_LEN;
29562306a36Sopenharmony_ci	}
29662306a36Sopenharmony_ci	if (stats_mode & UCC_GETH_STATISTICS_GATHERING_MODE_FIRMWARE_TX) {
29762306a36Sopenharmony_ci		memcpy(buf, tx_fw_stat_gstrings, UEC_TX_FW_STATS_LEN *
29862306a36Sopenharmony_ci			       	ETH_GSTRING_LEN);
29962306a36Sopenharmony_ci		buf += UEC_TX_FW_STATS_LEN * ETH_GSTRING_LEN;
30062306a36Sopenharmony_ci	}
30162306a36Sopenharmony_ci	if (stats_mode & UCC_GETH_STATISTICS_GATHERING_MODE_FIRMWARE_RX)
30262306a36Sopenharmony_ci		memcpy(buf, rx_fw_stat_gstrings, UEC_RX_FW_STATS_LEN *
30362306a36Sopenharmony_ci			       	ETH_GSTRING_LEN);
30462306a36Sopenharmony_ci}
30562306a36Sopenharmony_ci
30662306a36Sopenharmony_cistatic void uec_get_ethtool_stats(struct net_device *netdev,
30762306a36Sopenharmony_ci		struct ethtool_stats *stats, uint64_t *data)
30862306a36Sopenharmony_ci{
30962306a36Sopenharmony_ci	struct ucc_geth_private *ugeth = netdev_priv(netdev);
31062306a36Sopenharmony_ci	u32 stats_mode = ugeth->ug_info->statisticsMode;
31162306a36Sopenharmony_ci	u32 __iomem *base;
31262306a36Sopenharmony_ci	int i, j = 0;
31362306a36Sopenharmony_ci
31462306a36Sopenharmony_ci	if (stats_mode & UCC_GETH_STATISTICS_GATHERING_MODE_HARDWARE) {
31562306a36Sopenharmony_ci		if (ugeth->ug_regs)
31662306a36Sopenharmony_ci			base = (u32 __iomem *)&ugeth->ug_regs->tx64;
31762306a36Sopenharmony_ci		else
31862306a36Sopenharmony_ci			base = NULL;
31962306a36Sopenharmony_ci
32062306a36Sopenharmony_ci		for (i = 0; i < UEC_HW_STATS_LEN; i++)
32162306a36Sopenharmony_ci			data[j++] = base ? in_be32(&base[i]) : 0;
32262306a36Sopenharmony_ci	}
32362306a36Sopenharmony_ci	if (stats_mode & UCC_GETH_STATISTICS_GATHERING_MODE_FIRMWARE_TX) {
32462306a36Sopenharmony_ci		base = (u32 __iomem *)ugeth->p_tx_fw_statistics_pram;
32562306a36Sopenharmony_ci		for (i = 0; i < UEC_TX_FW_STATS_LEN; i++)
32662306a36Sopenharmony_ci			data[j++] = base ? in_be32(&base[i]) : 0;
32762306a36Sopenharmony_ci	}
32862306a36Sopenharmony_ci	if (stats_mode & UCC_GETH_STATISTICS_GATHERING_MODE_FIRMWARE_RX) {
32962306a36Sopenharmony_ci		base = (u32 __iomem *)ugeth->p_rx_fw_statistics_pram;
33062306a36Sopenharmony_ci		for (i = 0; i < UEC_RX_FW_STATS_LEN; i++)
33162306a36Sopenharmony_ci			data[j++] = base ? in_be32(&base[i]) : 0;
33262306a36Sopenharmony_ci	}
33362306a36Sopenharmony_ci}
33462306a36Sopenharmony_ci
33562306a36Sopenharmony_ci/* Report driver information */
33662306a36Sopenharmony_cistatic void
33762306a36Sopenharmony_ciuec_get_drvinfo(struct net_device *netdev,
33862306a36Sopenharmony_ci                       struct ethtool_drvinfo *drvinfo)
33962306a36Sopenharmony_ci{
34062306a36Sopenharmony_ci	strscpy(drvinfo->driver, DRV_NAME, sizeof(drvinfo->driver));
34162306a36Sopenharmony_ci	strscpy(drvinfo->bus_info, "QUICC ENGINE", sizeof(drvinfo->bus_info));
34262306a36Sopenharmony_ci}
34362306a36Sopenharmony_ci
34462306a36Sopenharmony_ci#ifdef CONFIG_PM
34562306a36Sopenharmony_ci
34662306a36Sopenharmony_cistatic void uec_get_wol(struct net_device *netdev, struct ethtool_wolinfo *wol)
34762306a36Sopenharmony_ci{
34862306a36Sopenharmony_ci	struct ucc_geth_private *ugeth = netdev_priv(netdev);
34962306a36Sopenharmony_ci	struct phy_device *phydev = ugeth->phydev;
35062306a36Sopenharmony_ci
35162306a36Sopenharmony_ci	if (phydev && phydev->irq)
35262306a36Sopenharmony_ci		wol->supported |= WAKE_PHY;
35362306a36Sopenharmony_ci	if (qe_alive_during_sleep())
35462306a36Sopenharmony_ci		wol->supported |= WAKE_MAGIC;
35562306a36Sopenharmony_ci
35662306a36Sopenharmony_ci	wol->wolopts = ugeth->wol_en;
35762306a36Sopenharmony_ci}
35862306a36Sopenharmony_ci
35962306a36Sopenharmony_cistatic int uec_set_wol(struct net_device *netdev, struct ethtool_wolinfo *wol)
36062306a36Sopenharmony_ci{
36162306a36Sopenharmony_ci	struct ucc_geth_private *ugeth = netdev_priv(netdev);
36262306a36Sopenharmony_ci	struct phy_device *phydev = ugeth->phydev;
36362306a36Sopenharmony_ci
36462306a36Sopenharmony_ci	if (wol->wolopts & ~(WAKE_PHY | WAKE_MAGIC))
36562306a36Sopenharmony_ci		return -EINVAL;
36662306a36Sopenharmony_ci	else if (wol->wolopts & WAKE_PHY && (!phydev || !phydev->irq))
36762306a36Sopenharmony_ci		return -EINVAL;
36862306a36Sopenharmony_ci	else if (wol->wolopts & WAKE_MAGIC && !qe_alive_during_sleep())
36962306a36Sopenharmony_ci		return -EINVAL;
37062306a36Sopenharmony_ci
37162306a36Sopenharmony_ci	ugeth->wol_en = wol->wolopts;
37262306a36Sopenharmony_ci	device_set_wakeup_enable(&netdev->dev, ugeth->wol_en);
37362306a36Sopenharmony_ci
37462306a36Sopenharmony_ci	return 0;
37562306a36Sopenharmony_ci}
37662306a36Sopenharmony_ci
37762306a36Sopenharmony_ci#else
37862306a36Sopenharmony_ci#define uec_get_wol NULL
37962306a36Sopenharmony_ci#define uec_set_wol NULL
38062306a36Sopenharmony_ci#endif /* CONFIG_PM */
38162306a36Sopenharmony_ci
38262306a36Sopenharmony_cistatic const struct ethtool_ops uec_ethtool_ops = {
38362306a36Sopenharmony_ci	.get_drvinfo            = uec_get_drvinfo,
38462306a36Sopenharmony_ci	.get_regs_len           = uec_get_regs_len,
38562306a36Sopenharmony_ci	.get_regs               = uec_get_regs,
38662306a36Sopenharmony_ci	.get_msglevel           = uec_get_msglevel,
38762306a36Sopenharmony_ci	.set_msglevel           = uec_set_msglevel,
38862306a36Sopenharmony_ci	.nway_reset             = phy_ethtool_nway_reset,
38962306a36Sopenharmony_ci	.get_link               = ethtool_op_get_link,
39062306a36Sopenharmony_ci	.get_ringparam          = uec_get_ringparam,
39162306a36Sopenharmony_ci	.set_ringparam          = uec_set_ringparam,
39262306a36Sopenharmony_ci	.get_pauseparam         = uec_get_pauseparam,
39362306a36Sopenharmony_ci	.set_pauseparam         = uec_set_pauseparam,
39462306a36Sopenharmony_ci	.get_sset_count		= uec_get_sset_count,
39562306a36Sopenharmony_ci	.get_strings            = uec_get_strings,
39662306a36Sopenharmony_ci	.get_ethtool_stats      = uec_get_ethtool_stats,
39762306a36Sopenharmony_ci	.get_wol		= uec_get_wol,
39862306a36Sopenharmony_ci	.set_wol		= uec_set_wol,
39962306a36Sopenharmony_ci	.get_ts_info		= ethtool_op_get_ts_info,
40062306a36Sopenharmony_ci	.get_link_ksettings	= uec_get_ksettings,
40162306a36Sopenharmony_ci	.set_link_ksettings	= uec_set_ksettings,
40262306a36Sopenharmony_ci};
40362306a36Sopenharmony_ci
40462306a36Sopenharmony_civoid uec_set_ethtool_ops(struct net_device *netdev)
40562306a36Sopenharmony_ci{
40662306a36Sopenharmony_ci	netdev->ethtool_ops = &uec_ethtool_ops;
40762306a36Sopenharmony_ci}
408