162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci#define pr_fmt(fmt)				"bcmasp_ethtool: " fmt
362306a36Sopenharmony_ci
462306a36Sopenharmony_ci#include <asm-generic/unaligned.h>
562306a36Sopenharmony_ci#include <linux/ethtool.h>
662306a36Sopenharmony_ci#include <linux/netdevice.h>
762306a36Sopenharmony_ci#include <linux/platform_device.h>
862306a36Sopenharmony_ci
962306a36Sopenharmony_ci#include "bcmasp.h"
1062306a36Sopenharmony_ci#include "bcmasp_intf_defs.h"
1162306a36Sopenharmony_ci
1262306a36Sopenharmony_cienum bcmasp_stat_type {
1362306a36Sopenharmony_ci	BCMASP_STAT_RX_EDPKT,
1462306a36Sopenharmony_ci	BCMASP_STAT_RX_CTRL,
1562306a36Sopenharmony_ci	BCMASP_STAT_RX_CTRL_PER_INTF,
1662306a36Sopenharmony_ci	BCMASP_STAT_SOFT,
1762306a36Sopenharmony_ci};
1862306a36Sopenharmony_ci
1962306a36Sopenharmony_cistruct bcmasp_stats {
2062306a36Sopenharmony_ci	char stat_string[ETH_GSTRING_LEN];
2162306a36Sopenharmony_ci	enum bcmasp_stat_type type;
2262306a36Sopenharmony_ci	u32 reg_offset;
2362306a36Sopenharmony_ci};
2462306a36Sopenharmony_ci
2562306a36Sopenharmony_ci#define STAT_BCMASP_SOFT_MIB(str) { \
2662306a36Sopenharmony_ci	.stat_string = str, \
2762306a36Sopenharmony_ci	.type = BCMASP_STAT_SOFT, \
2862306a36Sopenharmony_ci}
2962306a36Sopenharmony_ci
3062306a36Sopenharmony_ci#define STAT_BCMASP_OFFSET(str, _type, offset) { \
3162306a36Sopenharmony_ci	.stat_string = str, \
3262306a36Sopenharmony_ci	.type = _type, \
3362306a36Sopenharmony_ci	.reg_offset = offset, \
3462306a36Sopenharmony_ci}
3562306a36Sopenharmony_ci
3662306a36Sopenharmony_ci#define STAT_BCMASP_RX_EDPKT(str, offset) \
3762306a36Sopenharmony_ci	STAT_BCMASP_OFFSET(str, BCMASP_STAT_RX_EDPKT, offset)
3862306a36Sopenharmony_ci#define STAT_BCMASP_RX_CTRL(str, offset) \
3962306a36Sopenharmony_ci	STAT_BCMASP_OFFSET(str, BCMASP_STAT_RX_CTRL, offset)
4062306a36Sopenharmony_ci#define STAT_BCMASP_RX_CTRL_PER_INTF(str, offset) \
4162306a36Sopenharmony_ci	STAT_BCMASP_OFFSET(str, BCMASP_STAT_RX_CTRL_PER_INTF, offset)
4262306a36Sopenharmony_ci
4362306a36Sopenharmony_ci/* Must match the order of struct bcmasp_mib_counters */
4462306a36Sopenharmony_cistatic const struct bcmasp_stats bcmasp_gstrings_stats[] = {
4562306a36Sopenharmony_ci	/* EDPKT counters */
4662306a36Sopenharmony_ci	STAT_BCMASP_RX_EDPKT("RX Time Stamp", ASP_EDPKT_RX_TS_COUNTER),
4762306a36Sopenharmony_ci	STAT_BCMASP_RX_EDPKT("RX PKT Count", ASP_EDPKT_RX_PKT_CNT),
4862306a36Sopenharmony_ci	STAT_BCMASP_RX_EDPKT("RX PKT Buffered", ASP_EDPKT_HDR_EXTR_CNT),
4962306a36Sopenharmony_ci	STAT_BCMASP_RX_EDPKT("RX PKT Pushed to DRAM", ASP_EDPKT_HDR_OUT_CNT),
5062306a36Sopenharmony_ci	/* ASP RX control */
5162306a36Sopenharmony_ci	STAT_BCMASP_RX_CTRL_PER_INTF("Frames From Unimac",
5262306a36Sopenharmony_ci				     ASP_RX_CTRL_UMAC_0_FRAME_COUNT),
5362306a36Sopenharmony_ci	STAT_BCMASP_RX_CTRL_PER_INTF("Frames From Port",
5462306a36Sopenharmony_ci				     ASP_RX_CTRL_FB_0_FRAME_COUNT),
5562306a36Sopenharmony_ci	STAT_BCMASP_RX_CTRL_PER_INTF("RX Buffer FIFO Depth",
5662306a36Sopenharmony_ci				     ASP_RX_CTRL_FB_RX_FIFO_DEPTH),
5762306a36Sopenharmony_ci	STAT_BCMASP_RX_CTRL("Frames Out(Buffer)",
5862306a36Sopenharmony_ci			    ASP_RX_CTRL_FB_OUT_FRAME_COUNT),
5962306a36Sopenharmony_ci	STAT_BCMASP_RX_CTRL("Frames Out(Filters)",
6062306a36Sopenharmony_ci			    ASP_RX_CTRL_FB_FILT_OUT_FRAME_COUNT),
6162306a36Sopenharmony_ci	/* Software maintained statistics */
6262306a36Sopenharmony_ci	STAT_BCMASP_SOFT_MIB("RX SKB Alloc Failed"),
6362306a36Sopenharmony_ci	STAT_BCMASP_SOFT_MIB("TX DMA Failed"),
6462306a36Sopenharmony_ci	STAT_BCMASP_SOFT_MIB("Multicast Filters Full"),
6562306a36Sopenharmony_ci	STAT_BCMASP_SOFT_MIB("Unicast Filters Full"),
6662306a36Sopenharmony_ci	STAT_BCMASP_SOFT_MIB("MDA Filters Combined"),
6762306a36Sopenharmony_ci	STAT_BCMASP_SOFT_MIB("Promisc Filter Set"),
6862306a36Sopenharmony_ci	STAT_BCMASP_SOFT_MIB("TX Realloc For Offload Failed"),
6962306a36Sopenharmony_ci	STAT_BCMASP_SOFT_MIB("Tx Timeout Count"),
7062306a36Sopenharmony_ci};
7162306a36Sopenharmony_ci
7262306a36Sopenharmony_ci#define BCMASP_STATS_LEN	ARRAY_SIZE(bcmasp_gstrings_stats)
7362306a36Sopenharmony_ci
7462306a36Sopenharmony_cistatic u16 bcmasp_stat_fixup_offset(struct bcmasp_intf *intf,
7562306a36Sopenharmony_ci				    const struct bcmasp_stats *s)
7662306a36Sopenharmony_ci{
7762306a36Sopenharmony_ci	struct bcmasp_priv *priv = intf->parent;
7862306a36Sopenharmony_ci
7962306a36Sopenharmony_ci	if (!strcmp("Frames Out(Buffer)", s->stat_string))
8062306a36Sopenharmony_ci		return priv->hw_info->rx_ctrl_fb_out_frame_count;
8162306a36Sopenharmony_ci
8262306a36Sopenharmony_ci	if (!strcmp("Frames Out(Filters)", s->stat_string))
8362306a36Sopenharmony_ci		return priv->hw_info->rx_ctrl_fb_filt_out_frame_count;
8462306a36Sopenharmony_ci
8562306a36Sopenharmony_ci	if (!strcmp("RX Buffer FIFO Depth", s->stat_string))
8662306a36Sopenharmony_ci		return priv->hw_info->rx_ctrl_fb_rx_fifo_depth;
8762306a36Sopenharmony_ci
8862306a36Sopenharmony_ci	return s->reg_offset;
8962306a36Sopenharmony_ci}
9062306a36Sopenharmony_ci
9162306a36Sopenharmony_cistatic int bcmasp_get_sset_count(struct net_device *dev, int string_set)
9262306a36Sopenharmony_ci{
9362306a36Sopenharmony_ci	switch (string_set) {
9462306a36Sopenharmony_ci	case ETH_SS_STATS:
9562306a36Sopenharmony_ci		return BCMASP_STATS_LEN;
9662306a36Sopenharmony_ci	default:
9762306a36Sopenharmony_ci		return -EOPNOTSUPP;
9862306a36Sopenharmony_ci	}
9962306a36Sopenharmony_ci}
10062306a36Sopenharmony_ci
10162306a36Sopenharmony_cistatic void bcmasp_get_strings(struct net_device *dev, u32 stringset,
10262306a36Sopenharmony_ci			       u8 *data)
10362306a36Sopenharmony_ci{
10462306a36Sopenharmony_ci	unsigned int i;
10562306a36Sopenharmony_ci
10662306a36Sopenharmony_ci	switch (stringset) {
10762306a36Sopenharmony_ci	case ETH_SS_STATS:
10862306a36Sopenharmony_ci		for (i = 0; i < BCMASP_STATS_LEN; i++) {
10962306a36Sopenharmony_ci			memcpy(data + i * ETH_GSTRING_LEN,
11062306a36Sopenharmony_ci			       bcmasp_gstrings_stats[i].stat_string,
11162306a36Sopenharmony_ci			       ETH_GSTRING_LEN);
11262306a36Sopenharmony_ci		}
11362306a36Sopenharmony_ci		break;
11462306a36Sopenharmony_ci	default:
11562306a36Sopenharmony_ci		return;
11662306a36Sopenharmony_ci	}
11762306a36Sopenharmony_ci}
11862306a36Sopenharmony_ci
11962306a36Sopenharmony_cistatic void bcmasp_update_mib_counters(struct bcmasp_intf *intf)
12062306a36Sopenharmony_ci{
12162306a36Sopenharmony_ci	unsigned int i;
12262306a36Sopenharmony_ci
12362306a36Sopenharmony_ci	for (i = 0; i < BCMASP_STATS_LEN; i++) {
12462306a36Sopenharmony_ci		const struct bcmasp_stats *s;
12562306a36Sopenharmony_ci		u32 offset, val;
12662306a36Sopenharmony_ci		char *p;
12762306a36Sopenharmony_ci
12862306a36Sopenharmony_ci		s = &bcmasp_gstrings_stats[i];
12962306a36Sopenharmony_ci		offset = bcmasp_stat_fixup_offset(intf, s);
13062306a36Sopenharmony_ci		switch (s->type) {
13162306a36Sopenharmony_ci		case BCMASP_STAT_SOFT:
13262306a36Sopenharmony_ci			continue;
13362306a36Sopenharmony_ci		case BCMASP_STAT_RX_EDPKT:
13462306a36Sopenharmony_ci			val = rx_edpkt_core_rl(intf->parent, offset);
13562306a36Sopenharmony_ci			break;
13662306a36Sopenharmony_ci		case BCMASP_STAT_RX_CTRL:
13762306a36Sopenharmony_ci			val = rx_ctrl_core_rl(intf->parent, offset);
13862306a36Sopenharmony_ci			break;
13962306a36Sopenharmony_ci		case BCMASP_STAT_RX_CTRL_PER_INTF:
14062306a36Sopenharmony_ci			offset += sizeof(u32) * intf->port;
14162306a36Sopenharmony_ci			val = rx_ctrl_core_rl(intf->parent, offset);
14262306a36Sopenharmony_ci			break;
14362306a36Sopenharmony_ci		default:
14462306a36Sopenharmony_ci			continue;
14562306a36Sopenharmony_ci		}
14662306a36Sopenharmony_ci		p = (char *)(&intf->mib) + (i * sizeof(u32));
14762306a36Sopenharmony_ci		put_unaligned(val, (u32 *)p);
14862306a36Sopenharmony_ci	}
14962306a36Sopenharmony_ci}
15062306a36Sopenharmony_ci
15162306a36Sopenharmony_cistatic void bcmasp_get_ethtool_stats(struct net_device *dev,
15262306a36Sopenharmony_ci				     struct ethtool_stats *stats,
15362306a36Sopenharmony_ci				     u64 *data)
15462306a36Sopenharmony_ci{
15562306a36Sopenharmony_ci	struct bcmasp_intf *intf = netdev_priv(dev);
15662306a36Sopenharmony_ci	unsigned int i;
15762306a36Sopenharmony_ci	char *p;
15862306a36Sopenharmony_ci
15962306a36Sopenharmony_ci	if (netif_running(dev))
16062306a36Sopenharmony_ci		bcmasp_update_mib_counters(intf);
16162306a36Sopenharmony_ci
16262306a36Sopenharmony_ci	for (i = 0; i < BCMASP_STATS_LEN; i++) {
16362306a36Sopenharmony_ci		p = (char *)(&intf->mib) + (i * sizeof(u32));
16462306a36Sopenharmony_ci		data[i] = *(u32 *)p;
16562306a36Sopenharmony_ci	}
16662306a36Sopenharmony_ci}
16762306a36Sopenharmony_ci
16862306a36Sopenharmony_cistatic void bcmasp_get_drvinfo(struct net_device *dev,
16962306a36Sopenharmony_ci			       struct ethtool_drvinfo *info)
17062306a36Sopenharmony_ci{
17162306a36Sopenharmony_ci	strscpy(info->driver, "bcmasp", sizeof(info->driver));
17262306a36Sopenharmony_ci	strscpy(info->bus_info, dev_name(dev->dev.parent),
17362306a36Sopenharmony_ci		sizeof(info->bus_info));
17462306a36Sopenharmony_ci}
17562306a36Sopenharmony_ci
17662306a36Sopenharmony_cistatic u32 bcmasp_get_msglevel(struct net_device *dev)
17762306a36Sopenharmony_ci{
17862306a36Sopenharmony_ci	struct bcmasp_intf *intf = netdev_priv(dev);
17962306a36Sopenharmony_ci
18062306a36Sopenharmony_ci	return intf->msg_enable;
18162306a36Sopenharmony_ci}
18262306a36Sopenharmony_ci
18362306a36Sopenharmony_cistatic void bcmasp_set_msglevel(struct net_device *dev, u32 level)
18462306a36Sopenharmony_ci{
18562306a36Sopenharmony_ci	struct bcmasp_intf *intf = netdev_priv(dev);
18662306a36Sopenharmony_ci
18762306a36Sopenharmony_ci	intf->msg_enable = level;
18862306a36Sopenharmony_ci}
18962306a36Sopenharmony_ci
19062306a36Sopenharmony_ci#define BCMASP_SUPPORTED_WAKE   (WAKE_MAGIC | WAKE_MAGICSECURE | WAKE_FILTER)
19162306a36Sopenharmony_cistatic void bcmasp_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
19262306a36Sopenharmony_ci{
19362306a36Sopenharmony_ci	struct bcmasp_intf *intf = netdev_priv(dev);
19462306a36Sopenharmony_ci
19562306a36Sopenharmony_ci	wol->supported = BCMASP_SUPPORTED_WAKE;
19662306a36Sopenharmony_ci	wol->wolopts = intf->wolopts;
19762306a36Sopenharmony_ci	memset(wol->sopass, 0, sizeof(wol->sopass));
19862306a36Sopenharmony_ci
19962306a36Sopenharmony_ci	if (wol->wolopts & WAKE_MAGICSECURE)
20062306a36Sopenharmony_ci		memcpy(wol->sopass, intf->sopass, sizeof(intf->sopass));
20162306a36Sopenharmony_ci}
20262306a36Sopenharmony_ci
20362306a36Sopenharmony_cistatic int bcmasp_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
20462306a36Sopenharmony_ci{
20562306a36Sopenharmony_ci	struct bcmasp_intf *intf = netdev_priv(dev);
20662306a36Sopenharmony_ci	struct bcmasp_priv *priv = intf->parent;
20762306a36Sopenharmony_ci	struct device *kdev = &priv->pdev->dev;
20862306a36Sopenharmony_ci
20962306a36Sopenharmony_ci	if (!device_can_wakeup(kdev))
21062306a36Sopenharmony_ci		return -EOPNOTSUPP;
21162306a36Sopenharmony_ci
21262306a36Sopenharmony_ci	/* Interface Specific */
21362306a36Sopenharmony_ci	intf->wolopts = wol->wolopts;
21462306a36Sopenharmony_ci	if (intf->wolopts & WAKE_MAGICSECURE)
21562306a36Sopenharmony_ci		memcpy(intf->sopass, wol->sopass, sizeof(wol->sopass));
21662306a36Sopenharmony_ci
21762306a36Sopenharmony_ci	mutex_lock(&priv->wol_lock);
21862306a36Sopenharmony_ci	priv->enable_wol(intf, !!intf->wolopts);
21962306a36Sopenharmony_ci	mutex_unlock(&priv->wol_lock);
22062306a36Sopenharmony_ci
22162306a36Sopenharmony_ci	return 0;
22262306a36Sopenharmony_ci}
22362306a36Sopenharmony_ci
22462306a36Sopenharmony_cistatic int bcmasp_flow_insert(struct net_device *dev, struct ethtool_rxnfc *cmd)
22562306a36Sopenharmony_ci{
22662306a36Sopenharmony_ci	struct bcmasp_intf *intf = netdev_priv(dev);
22762306a36Sopenharmony_ci	struct bcmasp_net_filter *nfilter;
22862306a36Sopenharmony_ci	u32 loc = cmd->fs.location;
22962306a36Sopenharmony_ci	bool wake = false;
23062306a36Sopenharmony_ci
23162306a36Sopenharmony_ci	if (cmd->fs.ring_cookie == RX_CLS_FLOW_WAKE)
23262306a36Sopenharmony_ci		wake = true;
23362306a36Sopenharmony_ci
23462306a36Sopenharmony_ci	/* Currently only supports WAKE filters */
23562306a36Sopenharmony_ci	if (!wake)
23662306a36Sopenharmony_ci		return -EOPNOTSUPP;
23762306a36Sopenharmony_ci
23862306a36Sopenharmony_ci	switch (cmd->fs.flow_type & ~(FLOW_EXT | FLOW_MAC_EXT)) {
23962306a36Sopenharmony_ci	case ETHER_FLOW:
24062306a36Sopenharmony_ci	case IP_USER_FLOW:
24162306a36Sopenharmony_ci	case TCP_V4_FLOW:
24262306a36Sopenharmony_ci	case UDP_V4_FLOW:
24362306a36Sopenharmony_ci	case TCP_V6_FLOW:
24462306a36Sopenharmony_ci	case UDP_V6_FLOW:
24562306a36Sopenharmony_ci		break;
24662306a36Sopenharmony_ci	default:
24762306a36Sopenharmony_ci		return -EOPNOTSUPP;
24862306a36Sopenharmony_ci	}
24962306a36Sopenharmony_ci
25062306a36Sopenharmony_ci	/* Check if filter already exists */
25162306a36Sopenharmony_ci	if (bcmasp_netfilt_check_dup(intf, &cmd->fs))
25262306a36Sopenharmony_ci		return -EINVAL;
25362306a36Sopenharmony_ci
25462306a36Sopenharmony_ci	nfilter = bcmasp_netfilt_get_init(intf, loc, wake, true);
25562306a36Sopenharmony_ci	if (IS_ERR(nfilter))
25662306a36Sopenharmony_ci		return PTR_ERR(nfilter);
25762306a36Sopenharmony_ci
25862306a36Sopenharmony_ci	/* Return the location where we did insert the filter */
25962306a36Sopenharmony_ci	cmd->fs.location = nfilter->hw_index;
26062306a36Sopenharmony_ci	memcpy(&nfilter->fs, &cmd->fs, sizeof(struct ethtool_rx_flow_spec));
26162306a36Sopenharmony_ci
26262306a36Sopenharmony_ci	/* Since we only support wake filters, defer register programming till
26362306a36Sopenharmony_ci	 * suspend time.
26462306a36Sopenharmony_ci	 */
26562306a36Sopenharmony_ci	return 0;
26662306a36Sopenharmony_ci}
26762306a36Sopenharmony_ci
26862306a36Sopenharmony_cistatic int bcmasp_flow_delete(struct net_device *dev, struct ethtool_rxnfc *cmd)
26962306a36Sopenharmony_ci{
27062306a36Sopenharmony_ci	struct bcmasp_intf *intf = netdev_priv(dev);
27162306a36Sopenharmony_ci	struct bcmasp_net_filter *nfilter;
27262306a36Sopenharmony_ci
27362306a36Sopenharmony_ci	nfilter = bcmasp_netfilt_get_init(intf, cmd->fs.location, false, false);
27462306a36Sopenharmony_ci	if (IS_ERR(nfilter))
27562306a36Sopenharmony_ci		return PTR_ERR(nfilter);
27662306a36Sopenharmony_ci
27762306a36Sopenharmony_ci	bcmasp_netfilt_release(intf, nfilter);
27862306a36Sopenharmony_ci
27962306a36Sopenharmony_ci	return 0;
28062306a36Sopenharmony_ci}
28162306a36Sopenharmony_ci
28262306a36Sopenharmony_cistatic int bcmasp_flow_get(struct bcmasp_intf *intf, struct ethtool_rxnfc *cmd)
28362306a36Sopenharmony_ci{
28462306a36Sopenharmony_ci	struct bcmasp_net_filter *nfilter;
28562306a36Sopenharmony_ci
28662306a36Sopenharmony_ci	nfilter = bcmasp_netfilt_get_init(intf, cmd->fs.location, false, false);
28762306a36Sopenharmony_ci	if (IS_ERR(nfilter))
28862306a36Sopenharmony_ci		return PTR_ERR(nfilter);
28962306a36Sopenharmony_ci
29062306a36Sopenharmony_ci	memcpy(&cmd->fs, &nfilter->fs, sizeof(nfilter->fs));
29162306a36Sopenharmony_ci
29262306a36Sopenharmony_ci	cmd->data = NUM_NET_FILTERS;
29362306a36Sopenharmony_ci
29462306a36Sopenharmony_ci	return 0;
29562306a36Sopenharmony_ci}
29662306a36Sopenharmony_ci
29762306a36Sopenharmony_cistatic int bcmasp_set_rxnfc(struct net_device *dev, struct ethtool_rxnfc *cmd)
29862306a36Sopenharmony_ci{
29962306a36Sopenharmony_ci	struct bcmasp_intf *intf = netdev_priv(dev);
30062306a36Sopenharmony_ci	int ret = -EOPNOTSUPP;
30162306a36Sopenharmony_ci
30262306a36Sopenharmony_ci	mutex_lock(&intf->parent->net_lock);
30362306a36Sopenharmony_ci
30462306a36Sopenharmony_ci	switch (cmd->cmd) {
30562306a36Sopenharmony_ci	case ETHTOOL_SRXCLSRLINS:
30662306a36Sopenharmony_ci		ret = bcmasp_flow_insert(dev, cmd);
30762306a36Sopenharmony_ci		break;
30862306a36Sopenharmony_ci	case ETHTOOL_SRXCLSRLDEL:
30962306a36Sopenharmony_ci		ret = bcmasp_flow_delete(dev, cmd);
31062306a36Sopenharmony_ci		break;
31162306a36Sopenharmony_ci	default:
31262306a36Sopenharmony_ci		break;
31362306a36Sopenharmony_ci	}
31462306a36Sopenharmony_ci
31562306a36Sopenharmony_ci	mutex_unlock(&intf->parent->net_lock);
31662306a36Sopenharmony_ci
31762306a36Sopenharmony_ci	return ret;
31862306a36Sopenharmony_ci}
31962306a36Sopenharmony_ci
32062306a36Sopenharmony_cistatic int bcmasp_get_rxnfc(struct net_device *dev, struct ethtool_rxnfc *cmd,
32162306a36Sopenharmony_ci			    u32 *rule_locs)
32262306a36Sopenharmony_ci{
32362306a36Sopenharmony_ci	struct bcmasp_intf *intf = netdev_priv(dev);
32462306a36Sopenharmony_ci	int err = 0;
32562306a36Sopenharmony_ci
32662306a36Sopenharmony_ci	mutex_lock(&intf->parent->net_lock);
32762306a36Sopenharmony_ci
32862306a36Sopenharmony_ci	switch (cmd->cmd) {
32962306a36Sopenharmony_ci	case ETHTOOL_GRXCLSRLCNT:
33062306a36Sopenharmony_ci		cmd->rule_cnt = bcmasp_netfilt_get_active(intf);
33162306a36Sopenharmony_ci		/* We support specifying rule locations */
33262306a36Sopenharmony_ci		cmd->data |= RX_CLS_LOC_SPECIAL;
33362306a36Sopenharmony_ci		break;
33462306a36Sopenharmony_ci	case ETHTOOL_GRXCLSRULE:
33562306a36Sopenharmony_ci		err = bcmasp_flow_get(intf, cmd);
33662306a36Sopenharmony_ci		break;
33762306a36Sopenharmony_ci	case ETHTOOL_GRXCLSRLALL:
33862306a36Sopenharmony_ci		err = bcmasp_netfilt_get_all_active(intf, rule_locs, &cmd->rule_cnt);
33962306a36Sopenharmony_ci		cmd->data = NUM_NET_FILTERS;
34062306a36Sopenharmony_ci		break;
34162306a36Sopenharmony_ci	default:
34262306a36Sopenharmony_ci		err = -EOPNOTSUPP;
34362306a36Sopenharmony_ci		break;
34462306a36Sopenharmony_ci	}
34562306a36Sopenharmony_ci
34662306a36Sopenharmony_ci	mutex_unlock(&intf->parent->net_lock);
34762306a36Sopenharmony_ci
34862306a36Sopenharmony_ci	return err;
34962306a36Sopenharmony_ci}
35062306a36Sopenharmony_ci
35162306a36Sopenharmony_civoid bcmasp_eee_enable_set(struct bcmasp_intf *intf, bool enable)
35262306a36Sopenharmony_ci{
35362306a36Sopenharmony_ci	u32 reg;
35462306a36Sopenharmony_ci
35562306a36Sopenharmony_ci	reg = umac_rl(intf, UMC_EEE_CTRL);
35662306a36Sopenharmony_ci	if (enable)
35762306a36Sopenharmony_ci		reg |= EEE_EN;
35862306a36Sopenharmony_ci	else
35962306a36Sopenharmony_ci		reg &= ~EEE_EN;
36062306a36Sopenharmony_ci	umac_wl(intf, reg, UMC_EEE_CTRL);
36162306a36Sopenharmony_ci
36262306a36Sopenharmony_ci	intf->eee.eee_enabled = enable;
36362306a36Sopenharmony_ci	intf->eee.eee_active = enable;
36462306a36Sopenharmony_ci}
36562306a36Sopenharmony_ci
36662306a36Sopenharmony_cistatic int bcmasp_get_eee(struct net_device *dev, struct ethtool_eee *e)
36762306a36Sopenharmony_ci{
36862306a36Sopenharmony_ci	struct bcmasp_intf *intf = netdev_priv(dev);
36962306a36Sopenharmony_ci	struct ethtool_eee *p = &intf->eee;
37062306a36Sopenharmony_ci
37162306a36Sopenharmony_ci	if (!dev->phydev)
37262306a36Sopenharmony_ci		return -ENODEV;
37362306a36Sopenharmony_ci
37462306a36Sopenharmony_ci	e->eee_enabled = p->eee_enabled;
37562306a36Sopenharmony_ci	e->eee_active = p->eee_active;
37662306a36Sopenharmony_ci	e->tx_lpi_enabled = p->tx_lpi_enabled;
37762306a36Sopenharmony_ci	e->tx_lpi_timer = umac_rl(intf, UMC_EEE_LPI_TIMER);
37862306a36Sopenharmony_ci
37962306a36Sopenharmony_ci	return phy_ethtool_get_eee(dev->phydev, e);
38062306a36Sopenharmony_ci}
38162306a36Sopenharmony_ci
38262306a36Sopenharmony_cistatic int bcmasp_set_eee(struct net_device *dev, struct ethtool_eee *e)
38362306a36Sopenharmony_ci{
38462306a36Sopenharmony_ci	struct bcmasp_intf *intf = netdev_priv(dev);
38562306a36Sopenharmony_ci	struct ethtool_eee *p = &intf->eee;
38662306a36Sopenharmony_ci	int ret;
38762306a36Sopenharmony_ci
38862306a36Sopenharmony_ci	if (!dev->phydev)
38962306a36Sopenharmony_ci		return -ENODEV;
39062306a36Sopenharmony_ci
39162306a36Sopenharmony_ci	if (!p->eee_enabled) {
39262306a36Sopenharmony_ci		bcmasp_eee_enable_set(intf, false);
39362306a36Sopenharmony_ci	} else {
39462306a36Sopenharmony_ci		ret = phy_init_eee(dev->phydev, 0);
39562306a36Sopenharmony_ci		if (ret) {
39662306a36Sopenharmony_ci			netif_err(intf, hw, dev,
39762306a36Sopenharmony_ci				  "EEE initialization failed: %d\n", ret);
39862306a36Sopenharmony_ci			return ret;
39962306a36Sopenharmony_ci		}
40062306a36Sopenharmony_ci
40162306a36Sopenharmony_ci		umac_wl(intf, e->tx_lpi_timer, UMC_EEE_LPI_TIMER);
40262306a36Sopenharmony_ci		intf->eee.eee_active = ret >= 0;
40362306a36Sopenharmony_ci		intf->eee.tx_lpi_enabled = e->tx_lpi_enabled;
40462306a36Sopenharmony_ci		bcmasp_eee_enable_set(intf, true);
40562306a36Sopenharmony_ci	}
40662306a36Sopenharmony_ci
40762306a36Sopenharmony_ci	return phy_ethtool_set_eee(dev->phydev, e);
40862306a36Sopenharmony_ci}
40962306a36Sopenharmony_ci
41062306a36Sopenharmony_cistatic void bcmasp_get_eth_mac_stats(struct net_device *dev,
41162306a36Sopenharmony_ci				     struct ethtool_eth_mac_stats *mac_stats)
41262306a36Sopenharmony_ci{
41362306a36Sopenharmony_ci	struct bcmasp_intf *intf = netdev_priv(dev);
41462306a36Sopenharmony_ci
41562306a36Sopenharmony_ci	mac_stats->FramesTransmittedOK = umac_rl(intf, UMC_GTPOK);
41662306a36Sopenharmony_ci	mac_stats->SingleCollisionFrames = umac_rl(intf, UMC_GTSCL);
41762306a36Sopenharmony_ci	mac_stats->MultipleCollisionFrames = umac_rl(intf, UMC_GTMCL);
41862306a36Sopenharmony_ci	mac_stats->FramesReceivedOK = umac_rl(intf, UMC_GRPOK);
41962306a36Sopenharmony_ci	mac_stats->FrameCheckSequenceErrors = umac_rl(intf, UMC_GRFCS);
42062306a36Sopenharmony_ci	mac_stats->AlignmentErrors = umac_rl(intf, UMC_GRALN);
42162306a36Sopenharmony_ci	mac_stats->OctetsTransmittedOK = umac_rl(intf, UMC_GTBYT);
42262306a36Sopenharmony_ci	mac_stats->FramesWithDeferredXmissions = umac_rl(intf, UMC_GTDRF);
42362306a36Sopenharmony_ci	mac_stats->LateCollisions = umac_rl(intf, UMC_GTLCL);
42462306a36Sopenharmony_ci	mac_stats->FramesAbortedDueToXSColls = umac_rl(intf, UMC_GTXCL);
42562306a36Sopenharmony_ci	mac_stats->OctetsReceivedOK = umac_rl(intf, UMC_GRBYT);
42662306a36Sopenharmony_ci	mac_stats->MulticastFramesXmittedOK = umac_rl(intf, UMC_GTMCA);
42762306a36Sopenharmony_ci	mac_stats->BroadcastFramesXmittedOK = umac_rl(intf, UMC_GTBCA);
42862306a36Sopenharmony_ci	mac_stats->FramesWithExcessiveDeferral = umac_rl(intf, UMC_GTEDF);
42962306a36Sopenharmony_ci	mac_stats->MulticastFramesReceivedOK = umac_rl(intf, UMC_GRMCA);
43062306a36Sopenharmony_ci	mac_stats->BroadcastFramesReceivedOK = umac_rl(intf, UMC_GRBCA);
43162306a36Sopenharmony_ci}
43262306a36Sopenharmony_ci
43362306a36Sopenharmony_cistatic const struct ethtool_rmon_hist_range bcmasp_rmon_ranges[] = {
43462306a36Sopenharmony_ci	{    0,   64},
43562306a36Sopenharmony_ci	{   65,  127},
43662306a36Sopenharmony_ci	{  128,  255},
43762306a36Sopenharmony_ci	{  256,  511},
43862306a36Sopenharmony_ci	{  512, 1023},
43962306a36Sopenharmony_ci	{ 1024, 1518},
44062306a36Sopenharmony_ci	{ 1519, 1522},
44162306a36Sopenharmony_ci	{}
44262306a36Sopenharmony_ci};
44362306a36Sopenharmony_ci
44462306a36Sopenharmony_cistatic void bcmasp_get_rmon_stats(struct net_device *dev,
44562306a36Sopenharmony_ci				  struct ethtool_rmon_stats *rmon_stats,
44662306a36Sopenharmony_ci				  const struct ethtool_rmon_hist_range **ranges)
44762306a36Sopenharmony_ci{
44862306a36Sopenharmony_ci	struct bcmasp_intf *intf = netdev_priv(dev);
44962306a36Sopenharmony_ci
45062306a36Sopenharmony_ci	*ranges = bcmasp_rmon_ranges;
45162306a36Sopenharmony_ci
45262306a36Sopenharmony_ci	rmon_stats->undersize_pkts = umac_rl(intf, UMC_RRUND);
45362306a36Sopenharmony_ci	rmon_stats->oversize_pkts = umac_rl(intf, UMC_GROVR);
45462306a36Sopenharmony_ci	rmon_stats->fragments = umac_rl(intf, UMC_RRFRG);
45562306a36Sopenharmony_ci	rmon_stats->jabbers = umac_rl(intf, UMC_GRJBR);
45662306a36Sopenharmony_ci
45762306a36Sopenharmony_ci	rmon_stats->hist[0] = umac_rl(intf, UMC_GR64);
45862306a36Sopenharmony_ci	rmon_stats->hist[1] = umac_rl(intf, UMC_GR127);
45962306a36Sopenharmony_ci	rmon_stats->hist[2] = umac_rl(intf, UMC_GR255);
46062306a36Sopenharmony_ci	rmon_stats->hist[3] = umac_rl(intf, UMC_GR511);
46162306a36Sopenharmony_ci	rmon_stats->hist[4] = umac_rl(intf, UMC_GR1023);
46262306a36Sopenharmony_ci	rmon_stats->hist[5] = umac_rl(intf, UMC_GR1518);
46362306a36Sopenharmony_ci	rmon_stats->hist[6] = umac_rl(intf, UMC_GRMGV);
46462306a36Sopenharmony_ci
46562306a36Sopenharmony_ci	rmon_stats->hist_tx[0] = umac_rl(intf, UMC_TR64);
46662306a36Sopenharmony_ci	rmon_stats->hist_tx[1] = umac_rl(intf, UMC_TR127);
46762306a36Sopenharmony_ci	rmon_stats->hist_tx[2] = umac_rl(intf, UMC_TR255);
46862306a36Sopenharmony_ci	rmon_stats->hist_tx[3] = umac_rl(intf, UMC_TR511);
46962306a36Sopenharmony_ci	rmon_stats->hist_tx[4] = umac_rl(intf, UMC_TR1023);
47062306a36Sopenharmony_ci	rmon_stats->hist_tx[5] = umac_rl(intf, UMC_TR1518);
47162306a36Sopenharmony_ci	rmon_stats->hist_tx[6] = umac_rl(intf, UMC_TRMGV);
47262306a36Sopenharmony_ci}
47362306a36Sopenharmony_ci
47462306a36Sopenharmony_cistatic void bcmasp_get_eth_ctrl_stats(struct net_device *dev,
47562306a36Sopenharmony_ci				      struct ethtool_eth_ctrl_stats *ctrl_stats)
47662306a36Sopenharmony_ci{
47762306a36Sopenharmony_ci	struct bcmasp_intf *intf = netdev_priv(dev);
47862306a36Sopenharmony_ci
47962306a36Sopenharmony_ci	ctrl_stats->MACControlFramesTransmitted = umac_rl(intf, UMC_GTXCF);
48062306a36Sopenharmony_ci	ctrl_stats->MACControlFramesReceived = umac_rl(intf, UMC_GRXCF);
48162306a36Sopenharmony_ci	ctrl_stats->UnsupportedOpcodesReceived = umac_rl(intf, UMC_GRXUO);
48262306a36Sopenharmony_ci}
48362306a36Sopenharmony_ci
48462306a36Sopenharmony_ciconst struct ethtool_ops bcmasp_ethtool_ops = {
48562306a36Sopenharmony_ci	.get_drvinfo		= bcmasp_get_drvinfo,
48662306a36Sopenharmony_ci	.get_link		= ethtool_op_get_link,
48762306a36Sopenharmony_ci	.get_link_ksettings	= phy_ethtool_get_link_ksettings,
48862306a36Sopenharmony_ci	.set_link_ksettings	= phy_ethtool_set_link_ksettings,
48962306a36Sopenharmony_ci	.get_msglevel		= bcmasp_get_msglevel,
49062306a36Sopenharmony_ci	.set_msglevel		= bcmasp_set_msglevel,
49162306a36Sopenharmony_ci	.get_wol		= bcmasp_get_wol,
49262306a36Sopenharmony_ci	.set_wol		= bcmasp_set_wol,
49362306a36Sopenharmony_ci	.get_rxnfc		= bcmasp_get_rxnfc,
49462306a36Sopenharmony_ci	.set_rxnfc		= bcmasp_set_rxnfc,
49562306a36Sopenharmony_ci	.set_eee		= bcmasp_set_eee,
49662306a36Sopenharmony_ci	.get_eee		= bcmasp_get_eee,
49762306a36Sopenharmony_ci	.get_eth_mac_stats	= bcmasp_get_eth_mac_stats,
49862306a36Sopenharmony_ci	.get_rmon_stats		= bcmasp_get_rmon_stats,
49962306a36Sopenharmony_ci	.get_eth_ctrl_stats	= bcmasp_get_eth_ctrl_stats,
50062306a36Sopenharmony_ci	.get_strings		= bcmasp_get_strings,
50162306a36Sopenharmony_ci	.get_ethtool_stats	= bcmasp_get_ethtool_stats,
50262306a36Sopenharmony_ci	.get_sset_count		= bcmasp_get_sset_count,
50362306a36Sopenharmony_ci};
504