xref: /openbmc/linux/drivers/net/ethernet/broadcom/asp2/bcmasp_ethtool.c (revision 5804c19b80bf625c6a9925317f845e497434d6d3)
1490cb412SJustin Chen // SPDX-License-Identifier: GPL-2.0
2490cb412SJustin Chen #define pr_fmt(fmt)				"bcmasp_ethtool: " fmt
3490cb412SJustin Chen 
47c10691eSJustin Chen #include <asm-generic/unaligned.h>
5490cb412SJustin Chen #include <linux/ethtool.h>
6490cb412SJustin Chen #include <linux/netdevice.h>
7490cb412SJustin Chen #include <linux/platform_device.h>
8490cb412SJustin Chen 
9490cb412SJustin Chen #include "bcmasp.h"
10490cb412SJustin Chen #include "bcmasp_intf_defs.h"
11490cb412SJustin Chen 
127c10691eSJustin Chen enum bcmasp_stat_type {
137c10691eSJustin Chen 	BCMASP_STAT_RX_EDPKT,
147c10691eSJustin Chen 	BCMASP_STAT_RX_CTRL,
157c10691eSJustin Chen 	BCMASP_STAT_RX_CTRL_PER_INTF,
167c10691eSJustin Chen 	BCMASP_STAT_SOFT,
177c10691eSJustin Chen };
187c10691eSJustin Chen 
197c10691eSJustin Chen struct bcmasp_stats {
207c10691eSJustin Chen 	char stat_string[ETH_GSTRING_LEN];
217c10691eSJustin Chen 	enum bcmasp_stat_type type;
227c10691eSJustin Chen 	u32 reg_offset;
237c10691eSJustin Chen };
247c10691eSJustin Chen 
257c10691eSJustin Chen #define STAT_BCMASP_SOFT_MIB(str) { \
267c10691eSJustin Chen 	.stat_string = str, \
277c10691eSJustin Chen 	.type = BCMASP_STAT_SOFT, \
287c10691eSJustin Chen }
297c10691eSJustin Chen 
307c10691eSJustin Chen #define STAT_BCMASP_OFFSET(str, _type, offset) { \
317c10691eSJustin Chen 	.stat_string = str, \
327c10691eSJustin Chen 	.type = _type, \
337c10691eSJustin Chen 	.reg_offset = offset, \
347c10691eSJustin Chen }
357c10691eSJustin Chen 
367c10691eSJustin Chen #define STAT_BCMASP_RX_EDPKT(str, offset) \
377c10691eSJustin Chen 	STAT_BCMASP_OFFSET(str, BCMASP_STAT_RX_EDPKT, offset)
387c10691eSJustin Chen #define STAT_BCMASP_RX_CTRL(str, offset) \
397c10691eSJustin Chen 	STAT_BCMASP_OFFSET(str, BCMASP_STAT_RX_CTRL, offset)
407c10691eSJustin Chen #define STAT_BCMASP_RX_CTRL_PER_INTF(str, offset) \
417c10691eSJustin Chen 	STAT_BCMASP_OFFSET(str, BCMASP_STAT_RX_CTRL_PER_INTF, offset)
427c10691eSJustin Chen 
437c10691eSJustin Chen /* Must match the order of struct bcmasp_mib_counters */
447c10691eSJustin Chen static const struct bcmasp_stats bcmasp_gstrings_stats[] = {
457c10691eSJustin Chen 	/* EDPKT counters */
467c10691eSJustin Chen 	STAT_BCMASP_RX_EDPKT("RX Time Stamp", ASP_EDPKT_RX_TS_COUNTER),
477c10691eSJustin Chen 	STAT_BCMASP_RX_EDPKT("RX PKT Count", ASP_EDPKT_RX_PKT_CNT),
487c10691eSJustin Chen 	STAT_BCMASP_RX_EDPKT("RX PKT Buffered", ASP_EDPKT_HDR_EXTR_CNT),
497c10691eSJustin Chen 	STAT_BCMASP_RX_EDPKT("RX PKT Pushed to DRAM", ASP_EDPKT_HDR_OUT_CNT),
507c10691eSJustin Chen 	/* ASP RX control */
517c10691eSJustin Chen 	STAT_BCMASP_RX_CTRL_PER_INTF("Frames From Unimac",
527c10691eSJustin Chen 				     ASP_RX_CTRL_UMAC_0_FRAME_COUNT),
537c10691eSJustin Chen 	STAT_BCMASP_RX_CTRL_PER_INTF("Frames From Port",
547c10691eSJustin Chen 				     ASP_RX_CTRL_FB_0_FRAME_COUNT),
557c10691eSJustin Chen 	STAT_BCMASP_RX_CTRL_PER_INTF("RX Buffer FIFO Depth",
567c10691eSJustin Chen 				     ASP_RX_CTRL_FB_RX_FIFO_DEPTH),
577c10691eSJustin Chen 	STAT_BCMASP_RX_CTRL("Frames Out(Buffer)",
587c10691eSJustin Chen 			    ASP_RX_CTRL_FB_OUT_FRAME_COUNT),
597c10691eSJustin Chen 	STAT_BCMASP_RX_CTRL("Frames Out(Filters)",
607c10691eSJustin Chen 			    ASP_RX_CTRL_FB_FILT_OUT_FRAME_COUNT),
617c10691eSJustin Chen 	/* Software maintained statistics */
627c10691eSJustin Chen 	STAT_BCMASP_SOFT_MIB("RX SKB Alloc Failed"),
637c10691eSJustin Chen 	STAT_BCMASP_SOFT_MIB("TX DMA Failed"),
647c10691eSJustin Chen 	STAT_BCMASP_SOFT_MIB("Multicast Filters Full"),
657c10691eSJustin Chen 	STAT_BCMASP_SOFT_MIB("Unicast Filters Full"),
667c10691eSJustin Chen 	STAT_BCMASP_SOFT_MIB("MDA Filters Combined"),
677c10691eSJustin Chen 	STAT_BCMASP_SOFT_MIB("Promisc Filter Set"),
687c10691eSJustin Chen 	STAT_BCMASP_SOFT_MIB("TX Realloc For Offload Failed"),
697c10691eSJustin Chen 	STAT_BCMASP_SOFT_MIB("Tx Timeout Count"),
707c10691eSJustin Chen };
717c10691eSJustin Chen 
727c10691eSJustin Chen #define BCMASP_STATS_LEN	ARRAY_SIZE(bcmasp_gstrings_stats)
737c10691eSJustin Chen 
bcmasp_stat_fixup_offset(struct bcmasp_intf * intf,const struct bcmasp_stats * s)747c10691eSJustin Chen static u16 bcmasp_stat_fixup_offset(struct bcmasp_intf *intf,
757c10691eSJustin Chen 				    const struct bcmasp_stats *s)
767c10691eSJustin Chen {
777c10691eSJustin Chen 	struct bcmasp_priv *priv = intf->parent;
787c10691eSJustin Chen 
797c10691eSJustin Chen 	if (!strcmp("Frames Out(Buffer)", s->stat_string))
807c10691eSJustin Chen 		return priv->hw_info->rx_ctrl_fb_out_frame_count;
817c10691eSJustin Chen 
827c10691eSJustin Chen 	if (!strcmp("Frames Out(Filters)", s->stat_string))
837c10691eSJustin Chen 		return priv->hw_info->rx_ctrl_fb_filt_out_frame_count;
847c10691eSJustin Chen 
857c10691eSJustin Chen 	if (!strcmp("RX Buffer FIFO Depth", s->stat_string))
867c10691eSJustin Chen 		return priv->hw_info->rx_ctrl_fb_rx_fifo_depth;
877c10691eSJustin Chen 
887c10691eSJustin Chen 	return s->reg_offset;
897c10691eSJustin Chen }
907c10691eSJustin Chen 
bcmasp_get_sset_count(struct net_device * dev,int string_set)917c10691eSJustin Chen static int bcmasp_get_sset_count(struct net_device *dev, int string_set)
927c10691eSJustin Chen {
937c10691eSJustin Chen 	switch (string_set) {
947c10691eSJustin Chen 	case ETH_SS_STATS:
957c10691eSJustin Chen 		return BCMASP_STATS_LEN;
967c10691eSJustin Chen 	default:
977c10691eSJustin Chen 		return -EOPNOTSUPP;
987c10691eSJustin Chen 	}
997c10691eSJustin Chen }
1007c10691eSJustin Chen 
bcmasp_get_strings(struct net_device * dev,u32 stringset,u8 * data)1017c10691eSJustin Chen static void bcmasp_get_strings(struct net_device *dev, u32 stringset,
1027c10691eSJustin Chen 			       u8 *data)
1037c10691eSJustin Chen {
1047c10691eSJustin Chen 	unsigned int i;
1057c10691eSJustin Chen 
1067c10691eSJustin Chen 	switch (stringset) {
1077c10691eSJustin Chen 	case ETH_SS_STATS:
1087c10691eSJustin Chen 		for (i = 0; i < BCMASP_STATS_LEN; i++) {
1097c10691eSJustin Chen 			memcpy(data + i * ETH_GSTRING_LEN,
1107c10691eSJustin Chen 			       bcmasp_gstrings_stats[i].stat_string,
1117c10691eSJustin Chen 			       ETH_GSTRING_LEN);
1127c10691eSJustin Chen 		}
1137c10691eSJustin Chen 		break;
1147c10691eSJustin Chen 	default:
1157c10691eSJustin Chen 		return;
1167c10691eSJustin Chen 	}
1177c10691eSJustin Chen }
1187c10691eSJustin Chen 
bcmasp_update_mib_counters(struct bcmasp_intf * intf)1197c10691eSJustin Chen static void bcmasp_update_mib_counters(struct bcmasp_intf *intf)
1207c10691eSJustin Chen {
1217c10691eSJustin Chen 	unsigned int i;
1227c10691eSJustin Chen 
1237c10691eSJustin Chen 	for (i = 0; i < BCMASP_STATS_LEN; i++) {
1247c10691eSJustin Chen 		const struct bcmasp_stats *s;
1257c10691eSJustin Chen 		u32 offset, val;
1267c10691eSJustin Chen 		char *p;
1277c10691eSJustin Chen 
1287c10691eSJustin Chen 		s = &bcmasp_gstrings_stats[i];
1297c10691eSJustin Chen 		offset = bcmasp_stat_fixup_offset(intf, s);
1307c10691eSJustin Chen 		switch (s->type) {
1317c10691eSJustin Chen 		case BCMASP_STAT_SOFT:
1327c10691eSJustin Chen 			continue;
1337c10691eSJustin Chen 		case BCMASP_STAT_RX_EDPKT:
1347c10691eSJustin Chen 			val = rx_edpkt_core_rl(intf->parent, offset);
1357c10691eSJustin Chen 			break;
1367c10691eSJustin Chen 		case BCMASP_STAT_RX_CTRL:
1377c10691eSJustin Chen 			val = rx_ctrl_core_rl(intf->parent, offset);
1387c10691eSJustin Chen 			break;
1397c10691eSJustin Chen 		case BCMASP_STAT_RX_CTRL_PER_INTF:
1407c10691eSJustin Chen 			offset += sizeof(u32) * intf->port;
1417c10691eSJustin Chen 			val = rx_ctrl_core_rl(intf->parent, offset);
1427c10691eSJustin Chen 			break;
1437c10691eSJustin Chen 		default:
1447c10691eSJustin Chen 			continue;
1457c10691eSJustin Chen 		}
1467c10691eSJustin Chen 		p = (char *)(&intf->mib) + (i * sizeof(u32));
1477c10691eSJustin Chen 		put_unaligned(val, (u32 *)p);
1487c10691eSJustin Chen 	}
1497c10691eSJustin Chen }
1507c10691eSJustin Chen 
bcmasp_get_ethtool_stats(struct net_device * dev,struct ethtool_stats * stats,u64 * data)1517c10691eSJustin Chen static void bcmasp_get_ethtool_stats(struct net_device *dev,
1527c10691eSJustin Chen 				     struct ethtool_stats *stats,
1537c10691eSJustin Chen 				     u64 *data)
1547c10691eSJustin Chen {
1557c10691eSJustin Chen 	struct bcmasp_intf *intf = netdev_priv(dev);
1567c10691eSJustin Chen 	unsigned int i;
1577c10691eSJustin Chen 	char *p;
1587c10691eSJustin Chen 
1597c10691eSJustin Chen 	if (netif_running(dev))
1607c10691eSJustin Chen 		bcmasp_update_mib_counters(intf);
1617c10691eSJustin Chen 
1627c10691eSJustin Chen 	for (i = 0; i < BCMASP_STATS_LEN; i++) {
1637c10691eSJustin Chen 		p = (char *)(&intf->mib) + (i * sizeof(u32));
1647c10691eSJustin Chen 		data[i] = *(u32 *)p;
1657c10691eSJustin Chen 	}
1667c10691eSJustin Chen }
1677c10691eSJustin Chen 
bcmasp_get_drvinfo(struct net_device * dev,struct ethtool_drvinfo * info)168490cb412SJustin Chen static void bcmasp_get_drvinfo(struct net_device *dev,
169490cb412SJustin Chen 			       struct ethtool_drvinfo *info)
170490cb412SJustin Chen {
171490cb412SJustin Chen 	strscpy(info->driver, "bcmasp", sizeof(info->driver));
172490cb412SJustin Chen 	strscpy(info->bus_info, dev_name(dev->dev.parent),
173490cb412SJustin Chen 		sizeof(info->bus_info));
174490cb412SJustin Chen }
175490cb412SJustin Chen 
bcmasp_get_msglevel(struct net_device * dev)176490cb412SJustin Chen static u32 bcmasp_get_msglevel(struct net_device *dev)
177490cb412SJustin Chen {
178490cb412SJustin Chen 	struct bcmasp_intf *intf = netdev_priv(dev);
179490cb412SJustin Chen 
180490cb412SJustin Chen 	return intf->msg_enable;
181490cb412SJustin Chen }
182490cb412SJustin Chen 
bcmasp_set_msglevel(struct net_device * dev,u32 level)183490cb412SJustin Chen static void bcmasp_set_msglevel(struct net_device *dev, u32 level)
184490cb412SJustin Chen {
185490cb412SJustin Chen 	struct bcmasp_intf *intf = netdev_priv(dev);
186490cb412SJustin Chen 
187490cb412SJustin Chen 	intf->msg_enable = level;
188490cb412SJustin Chen }
189490cb412SJustin Chen 
190c5d511c4SJustin Chen #define BCMASP_SUPPORTED_WAKE   (WAKE_MAGIC | WAKE_MAGICSECURE | WAKE_FILTER)
bcmasp_get_wol(struct net_device * dev,struct ethtool_wolinfo * wol)191a2f07512SJustin Chen static void bcmasp_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
192a2f07512SJustin Chen {
193a2f07512SJustin Chen 	struct bcmasp_intf *intf = netdev_priv(dev);
194a2f07512SJustin Chen 
195a2f07512SJustin Chen 	wol->supported = BCMASP_SUPPORTED_WAKE;
196a2f07512SJustin Chen 	wol->wolopts = intf->wolopts;
197a2f07512SJustin Chen 	memset(wol->sopass, 0, sizeof(wol->sopass));
198a2f07512SJustin Chen 
199a2f07512SJustin Chen 	if (wol->wolopts & WAKE_MAGICSECURE)
200a2f07512SJustin Chen 		memcpy(wol->sopass, intf->sopass, sizeof(intf->sopass));
201a2f07512SJustin Chen }
202a2f07512SJustin Chen 
bcmasp_set_wol(struct net_device * dev,struct ethtool_wolinfo * wol)203a2f07512SJustin Chen static int bcmasp_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
204a2f07512SJustin Chen {
205a2f07512SJustin Chen 	struct bcmasp_intf *intf = netdev_priv(dev);
206a2f07512SJustin Chen 	struct bcmasp_priv *priv = intf->parent;
207a2f07512SJustin Chen 	struct device *kdev = &priv->pdev->dev;
208a2f07512SJustin Chen 
209a2f07512SJustin Chen 	if (!device_can_wakeup(kdev))
210a2f07512SJustin Chen 		return -EOPNOTSUPP;
211a2f07512SJustin Chen 
212a2f07512SJustin Chen 	/* Interface Specific */
213a2f07512SJustin Chen 	intf->wolopts = wol->wolopts;
214a2f07512SJustin Chen 	if (intf->wolopts & WAKE_MAGICSECURE)
215a2f07512SJustin Chen 		memcpy(intf->sopass, wol->sopass, sizeof(wol->sopass));
216a2f07512SJustin Chen 
217a2f07512SJustin Chen 	mutex_lock(&priv->wol_lock);
218a2f07512SJustin Chen 	priv->enable_wol(intf, !!intf->wolopts);
219a2f07512SJustin Chen 	mutex_unlock(&priv->wol_lock);
220a2f07512SJustin Chen 
221a2f07512SJustin Chen 	return 0;
222a2f07512SJustin Chen }
223a2f07512SJustin Chen 
bcmasp_flow_insert(struct net_device * dev,struct ethtool_rxnfc * cmd)224c5d511c4SJustin Chen static int bcmasp_flow_insert(struct net_device *dev, struct ethtool_rxnfc *cmd)
225c5d511c4SJustin Chen {
226c5d511c4SJustin Chen 	struct bcmasp_intf *intf = netdev_priv(dev);
227c5d511c4SJustin Chen 	struct bcmasp_net_filter *nfilter;
228c5d511c4SJustin Chen 	u32 loc = cmd->fs.location;
229c5d511c4SJustin Chen 	bool wake = false;
230c5d511c4SJustin Chen 
231c5d511c4SJustin Chen 	if (cmd->fs.ring_cookie == RX_CLS_FLOW_WAKE)
232c5d511c4SJustin Chen 		wake = true;
233c5d511c4SJustin Chen 
234c5d511c4SJustin Chen 	/* Currently only supports WAKE filters */
235c5d511c4SJustin Chen 	if (!wake)
236c5d511c4SJustin Chen 		return -EOPNOTSUPP;
237c5d511c4SJustin Chen 
238c5d511c4SJustin Chen 	switch (cmd->fs.flow_type & ~(FLOW_EXT | FLOW_MAC_EXT)) {
239c5d511c4SJustin Chen 	case ETHER_FLOW:
240c5d511c4SJustin Chen 	case IP_USER_FLOW:
241c5d511c4SJustin Chen 	case TCP_V4_FLOW:
242c5d511c4SJustin Chen 	case UDP_V4_FLOW:
243c5d511c4SJustin Chen 	case TCP_V6_FLOW:
244c5d511c4SJustin Chen 	case UDP_V6_FLOW:
245c5d511c4SJustin Chen 		break;
246c5d511c4SJustin Chen 	default:
247c5d511c4SJustin Chen 		return -EOPNOTSUPP;
248c5d511c4SJustin Chen 	}
249c5d511c4SJustin Chen 
250c5d511c4SJustin Chen 	/* Check if filter already exists */
251c5d511c4SJustin Chen 	if (bcmasp_netfilt_check_dup(intf, &cmd->fs))
252c5d511c4SJustin Chen 		return -EINVAL;
253c5d511c4SJustin Chen 
254c5d511c4SJustin Chen 	nfilter = bcmasp_netfilt_get_init(intf, loc, wake, true);
255c5d511c4SJustin Chen 	if (IS_ERR(nfilter))
256c5d511c4SJustin Chen 		return PTR_ERR(nfilter);
257c5d511c4SJustin Chen 
258c5d511c4SJustin Chen 	/* Return the location where we did insert the filter */
259c5d511c4SJustin Chen 	cmd->fs.location = nfilter->hw_index;
260c5d511c4SJustin Chen 	memcpy(&nfilter->fs, &cmd->fs, sizeof(struct ethtool_rx_flow_spec));
261c5d511c4SJustin Chen 
262c5d511c4SJustin Chen 	/* Since we only support wake filters, defer register programming till
263c5d511c4SJustin Chen 	 * suspend time.
264c5d511c4SJustin Chen 	 */
265c5d511c4SJustin Chen 	return 0;
266c5d511c4SJustin Chen }
267c5d511c4SJustin Chen 
bcmasp_flow_delete(struct net_device * dev,struct ethtool_rxnfc * cmd)268c5d511c4SJustin Chen static int bcmasp_flow_delete(struct net_device *dev, struct ethtool_rxnfc *cmd)
269c5d511c4SJustin Chen {
270c5d511c4SJustin Chen 	struct bcmasp_intf *intf = netdev_priv(dev);
271c5d511c4SJustin Chen 	struct bcmasp_net_filter *nfilter;
272c5d511c4SJustin Chen 
273c5d511c4SJustin Chen 	nfilter = bcmasp_netfilt_get_init(intf, cmd->fs.location, false, false);
274c5d511c4SJustin Chen 	if (IS_ERR(nfilter))
275c5d511c4SJustin Chen 		return PTR_ERR(nfilter);
276c5d511c4SJustin Chen 
277c5d511c4SJustin Chen 	bcmasp_netfilt_release(intf, nfilter);
278c5d511c4SJustin Chen 
279c5d511c4SJustin Chen 	return 0;
280c5d511c4SJustin Chen }
281c5d511c4SJustin Chen 
bcmasp_flow_get(struct bcmasp_intf * intf,struct ethtool_rxnfc * cmd)282c5d511c4SJustin Chen static int bcmasp_flow_get(struct bcmasp_intf *intf, struct ethtool_rxnfc *cmd)
283c5d511c4SJustin Chen {
284c5d511c4SJustin Chen 	struct bcmasp_net_filter *nfilter;
285c5d511c4SJustin Chen 
286c5d511c4SJustin Chen 	nfilter = bcmasp_netfilt_get_init(intf, cmd->fs.location, false, false);
287c5d511c4SJustin Chen 	if (IS_ERR(nfilter))
288c5d511c4SJustin Chen 		return PTR_ERR(nfilter);
289c5d511c4SJustin Chen 
290c5d511c4SJustin Chen 	memcpy(&cmd->fs, &nfilter->fs, sizeof(nfilter->fs));
291c5d511c4SJustin Chen 
292c5d511c4SJustin Chen 	cmd->data = NUM_NET_FILTERS;
293c5d511c4SJustin Chen 
294c5d511c4SJustin Chen 	return 0;
295c5d511c4SJustin Chen }
296c5d511c4SJustin Chen 
bcmasp_set_rxnfc(struct net_device * dev,struct ethtool_rxnfc * cmd)297c5d511c4SJustin Chen static int bcmasp_set_rxnfc(struct net_device *dev, struct ethtool_rxnfc *cmd)
298c5d511c4SJustin Chen {
299c5d511c4SJustin Chen 	struct bcmasp_intf *intf = netdev_priv(dev);
300c5d511c4SJustin Chen 	int ret = -EOPNOTSUPP;
301c5d511c4SJustin Chen 
302c5d511c4SJustin Chen 	mutex_lock(&intf->parent->net_lock);
303c5d511c4SJustin Chen 
304c5d511c4SJustin Chen 	switch (cmd->cmd) {
305c5d511c4SJustin Chen 	case ETHTOOL_SRXCLSRLINS:
306c5d511c4SJustin Chen 		ret = bcmasp_flow_insert(dev, cmd);
307c5d511c4SJustin Chen 		break;
308c5d511c4SJustin Chen 	case ETHTOOL_SRXCLSRLDEL:
309c5d511c4SJustin Chen 		ret = bcmasp_flow_delete(dev, cmd);
310c5d511c4SJustin Chen 		break;
311c5d511c4SJustin Chen 	default:
312c5d511c4SJustin Chen 		break;
313c5d511c4SJustin Chen 	}
314c5d511c4SJustin Chen 
315c5d511c4SJustin Chen 	mutex_unlock(&intf->parent->net_lock);
316c5d511c4SJustin Chen 
317c5d511c4SJustin Chen 	return ret;
318c5d511c4SJustin Chen }
319c5d511c4SJustin Chen 
bcmasp_get_rxnfc(struct net_device * dev,struct ethtool_rxnfc * cmd,u32 * rule_locs)320c5d511c4SJustin Chen static int bcmasp_get_rxnfc(struct net_device *dev, struct ethtool_rxnfc *cmd,
321c5d511c4SJustin Chen 			    u32 *rule_locs)
322c5d511c4SJustin Chen {
323c5d511c4SJustin Chen 	struct bcmasp_intf *intf = netdev_priv(dev);
324c5d511c4SJustin Chen 	int err = 0;
325c5d511c4SJustin Chen 
326c5d511c4SJustin Chen 	mutex_lock(&intf->parent->net_lock);
327c5d511c4SJustin Chen 
328c5d511c4SJustin Chen 	switch (cmd->cmd) {
329c5d511c4SJustin Chen 	case ETHTOOL_GRXCLSRLCNT:
330c5d511c4SJustin Chen 		cmd->rule_cnt = bcmasp_netfilt_get_active(intf);
331c5d511c4SJustin Chen 		/* We support specifying rule locations */
332c5d511c4SJustin Chen 		cmd->data |= RX_CLS_LOC_SPECIAL;
333c5d511c4SJustin Chen 		break;
334c5d511c4SJustin Chen 	case ETHTOOL_GRXCLSRULE:
335c5d511c4SJustin Chen 		err = bcmasp_flow_get(intf, cmd);
336c5d511c4SJustin Chen 		break;
337c5d511c4SJustin Chen 	case ETHTOOL_GRXCLSRLALL:
338*9b90aca9SHangyu Hua 		err = bcmasp_netfilt_get_all_active(intf, rule_locs, &cmd->rule_cnt);
339c5d511c4SJustin Chen 		cmd->data = NUM_NET_FILTERS;
340c5d511c4SJustin Chen 		break;
341c5d511c4SJustin Chen 	default:
342c5d511c4SJustin Chen 		err = -EOPNOTSUPP;
343c5d511c4SJustin Chen 		break;
344c5d511c4SJustin Chen 	}
345c5d511c4SJustin Chen 
346c5d511c4SJustin Chen 	mutex_unlock(&intf->parent->net_lock);
347c5d511c4SJustin Chen 
348c5d511c4SJustin Chen 	return err;
349c5d511c4SJustin Chen }
350c5d511c4SJustin Chen 
bcmasp_eee_enable_set(struct bcmasp_intf * intf,bool enable)351550e6f34SJustin Chen void bcmasp_eee_enable_set(struct bcmasp_intf *intf, bool enable)
352550e6f34SJustin Chen {
353550e6f34SJustin Chen 	u32 reg;
354550e6f34SJustin Chen 
355550e6f34SJustin Chen 	reg = umac_rl(intf, UMC_EEE_CTRL);
356550e6f34SJustin Chen 	if (enable)
357550e6f34SJustin Chen 		reg |= EEE_EN;
358550e6f34SJustin Chen 	else
359550e6f34SJustin Chen 		reg &= ~EEE_EN;
360550e6f34SJustin Chen 	umac_wl(intf, reg, UMC_EEE_CTRL);
361550e6f34SJustin Chen 
362550e6f34SJustin Chen 	intf->eee.eee_enabled = enable;
363550e6f34SJustin Chen 	intf->eee.eee_active = enable;
364550e6f34SJustin Chen }
365550e6f34SJustin Chen 
bcmasp_get_eee(struct net_device * dev,struct ethtool_eee * e)366550e6f34SJustin Chen static int bcmasp_get_eee(struct net_device *dev, struct ethtool_eee *e)
367550e6f34SJustin Chen {
368550e6f34SJustin Chen 	struct bcmasp_intf *intf = netdev_priv(dev);
369550e6f34SJustin Chen 	struct ethtool_eee *p = &intf->eee;
370550e6f34SJustin Chen 
371550e6f34SJustin Chen 	if (!dev->phydev)
372550e6f34SJustin Chen 		return -ENODEV;
373550e6f34SJustin Chen 
374550e6f34SJustin Chen 	e->eee_enabled = p->eee_enabled;
375550e6f34SJustin Chen 	e->eee_active = p->eee_active;
376550e6f34SJustin Chen 	e->tx_lpi_enabled = p->tx_lpi_enabled;
377550e6f34SJustin Chen 	e->tx_lpi_timer = umac_rl(intf, UMC_EEE_LPI_TIMER);
378550e6f34SJustin Chen 
379550e6f34SJustin Chen 	return phy_ethtool_get_eee(dev->phydev, e);
380550e6f34SJustin Chen }
381550e6f34SJustin Chen 
bcmasp_set_eee(struct net_device * dev,struct ethtool_eee * e)382550e6f34SJustin Chen static int bcmasp_set_eee(struct net_device *dev, struct ethtool_eee *e)
383550e6f34SJustin Chen {
384550e6f34SJustin Chen 	struct bcmasp_intf *intf = netdev_priv(dev);
385550e6f34SJustin Chen 	struct ethtool_eee *p = &intf->eee;
386550e6f34SJustin Chen 	int ret;
387550e6f34SJustin Chen 
388550e6f34SJustin Chen 	if (!dev->phydev)
389550e6f34SJustin Chen 		return -ENODEV;
390550e6f34SJustin Chen 
391550e6f34SJustin Chen 	if (!p->eee_enabled) {
392550e6f34SJustin Chen 		bcmasp_eee_enable_set(intf, false);
393550e6f34SJustin Chen 	} else {
394550e6f34SJustin Chen 		ret = phy_init_eee(dev->phydev, 0);
395550e6f34SJustin Chen 		if (ret) {
396550e6f34SJustin Chen 			netif_err(intf, hw, dev,
397550e6f34SJustin Chen 				  "EEE initialization failed: %d\n", ret);
398550e6f34SJustin Chen 			return ret;
399550e6f34SJustin Chen 		}
400550e6f34SJustin Chen 
401550e6f34SJustin Chen 		umac_wl(intf, e->tx_lpi_timer, UMC_EEE_LPI_TIMER);
402550e6f34SJustin Chen 		intf->eee.eee_active = ret >= 0;
403550e6f34SJustin Chen 		intf->eee.tx_lpi_enabled = e->tx_lpi_enabled;
404550e6f34SJustin Chen 		bcmasp_eee_enable_set(intf, true);
405550e6f34SJustin Chen 	}
406550e6f34SJustin Chen 
407550e6f34SJustin Chen 	return phy_ethtool_set_eee(dev->phydev, e);
408550e6f34SJustin Chen }
409550e6f34SJustin Chen 
bcmasp_get_eth_mac_stats(struct net_device * dev,struct ethtool_eth_mac_stats * mac_stats)41064931534SJustin Chen static void bcmasp_get_eth_mac_stats(struct net_device *dev,
41164931534SJustin Chen 				     struct ethtool_eth_mac_stats *mac_stats)
41264931534SJustin Chen {
41364931534SJustin Chen 	struct bcmasp_intf *intf = netdev_priv(dev);
41464931534SJustin Chen 
41564931534SJustin Chen 	mac_stats->FramesTransmittedOK = umac_rl(intf, UMC_GTPOK);
41664931534SJustin Chen 	mac_stats->SingleCollisionFrames = umac_rl(intf, UMC_GTSCL);
41764931534SJustin Chen 	mac_stats->MultipleCollisionFrames = umac_rl(intf, UMC_GTMCL);
41864931534SJustin Chen 	mac_stats->FramesReceivedOK = umac_rl(intf, UMC_GRPOK);
41964931534SJustin Chen 	mac_stats->FrameCheckSequenceErrors = umac_rl(intf, UMC_GRFCS);
42064931534SJustin Chen 	mac_stats->AlignmentErrors = umac_rl(intf, UMC_GRALN);
42164931534SJustin Chen 	mac_stats->OctetsTransmittedOK = umac_rl(intf, UMC_GTBYT);
42264931534SJustin Chen 	mac_stats->FramesWithDeferredXmissions = umac_rl(intf, UMC_GTDRF);
42364931534SJustin Chen 	mac_stats->LateCollisions = umac_rl(intf, UMC_GTLCL);
42464931534SJustin Chen 	mac_stats->FramesAbortedDueToXSColls = umac_rl(intf, UMC_GTXCL);
42564931534SJustin Chen 	mac_stats->OctetsReceivedOK = umac_rl(intf, UMC_GRBYT);
42664931534SJustin Chen 	mac_stats->MulticastFramesXmittedOK = umac_rl(intf, UMC_GTMCA);
42764931534SJustin Chen 	mac_stats->BroadcastFramesXmittedOK = umac_rl(intf, UMC_GTBCA);
42864931534SJustin Chen 	mac_stats->FramesWithExcessiveDeferral = umac_rl(intf, UMC_GTEDF);
42964931534SJustin Chen 	mac_stats->MulticastFramesReceivedOK = umac_rl(intf, UMC_GRMCA);
43064931534SJustin Chen 	mac_stats->BroadcastFramesReceivedOK = umac_rl(intf, UMC_GRBCA);
43164931534SJustin Chen }
43264931534SJustin Chen 
43364931534SJustin Chen static const struct ethtool_rmon_hist_range bcmasp_rmon_ranges[] = {
43464931534SJustin Chen 	{    0,   64},
43564931534SJustin Chen 	{   65,  127},
43664931534SJustin Chen 	{  128,  255},
43764931534SJustin Chen 	{  256,  511},
43864931534SJustin Chen 	{  512, 1023},
43964931534SJustin Chen 	{ 1024, 1518},
44064931534SJustin Chen 	{ 1519, 1522},
44164931534SJustin Chen 	{}
44264931534SJustin Chen };
44364931534SJustin Chen 
bcmasp_get_rmon_stats(struct net_device * dev,struct ethtool_rmon_stats * rmon_stats,const struct ethtool_rmon_hist_range ** ranges)44464931534SJustin Chen static void bcmasp_get_rmon_stats(struct net_device *dev,
44564931534SJustin Chen 				  struct ethtool_rmon_stats *rmon_stats,
44664931534SJustin Chen 				  const struct ethtool_rmon_hist_range **ranges)
44764931534SJustin Chen {
44864931534SJustin Chen 	struct bcmasp_intf *intf = netdev_priv(dev);
44964931534SJustin Chen 
45064931534SJustin Chen 	*ranges = bcmasp_rmon_ranges;
45164931534SJustin Chen 
45264931534SJustin Chen 	rmon_stats->undersize_pkts = umac_rl(intf, UMC_RRUND);
45364931534SJustin Chen 	rmon_stats->oversize_pkts = umac_rl(intf, UMC_GROVR);
45464931534SJustin Chen 	rmon_stats->fragments = umac_rl(intf, UMC_RRFRG);
45564931534SJustin Chen 	rmon_stats->jabbers = umac_rl(intf, UMC_GRJBR);
45664931534SJustin Chen 
45764931534SJustin Chen 	rmon_stats->hist[0] = umac_rl(intf, UMC_GR64);
45864931534SJustin Chen 	rmon_stats->hist[1] = umac_rl(intf, UMC_GR127);
45964931534SJustin Chen 	rmon_stats->hist[2] = umac_rl(intf, UMC_GR255);
46064931534SJustin Chen 	rmon_stats->hist[3] = umac_rl(intf, UMC_GR511);
46164931534SJustin Chen 	rmon_stats->hist[4] = umac_rl(intf, UMC_GR1023);
46264931534SJustin Chen 	rmon_stats->hist[5] = umac_rl(intf, UMC_GR1518);
46364931534SJustin Chen 	rmon_stats->hist[6] = umac_rl(intf, UMC_GRMGV);
46464931534SJustin Chen 
46564931534SJustin Chen 	rmon_stats->hist_tx[0] = umac_rl(intf, UMC_TR64);
46664931534SJustin Chen 	rmon_stats->hist_tx[1] = umac_rl(intf, UMC_TR127);
46764931534SJustin Chen 	rmon_stats->hist_tx[2] = umac_rl(intf, UMC_TR255);
46864931534SJustin Chen 	rmon_stats->hist_tx[3] = umac_rl(intf, UMC_TR511);
46964931534SJustin Chen 	rmon_stats->hist_tx[4] = umac_rl(intf, UMC_TR1023);
47064931534SJustin Chen 	rmon_stats->hist_tx[5] = umac_rl(intf, UMC_TR1518);
47164931534SJustin Chen 	rmon_stats->hist_tx[6] = umac_rl(intf, UMC_TRMGV);
47264931534SJustin Chen }
47364931534SJustin Chen 
bcmasp_get_eth_ctrl_stats(struct net_device * dev,struct ethtool_eth_ctrl_stats * ctrl_stats)47464931534SJustin Chen static void bcmasp_get_eth_ctrl_stats(struct net_device *dev,
47564931534SJustin Chen 				      struct ethtool_eth_ctrl_stats *ctrl_stats)
47664931534SJustin Chen {
47764931534SJustin Chen 	struct bcmasp_intf *intf = netdev_priv(dev);
47864931534SJustin Chen 
47964931534SJustin Chen 	ctrl_stats->MACControlFramesTransmitted = umac_rl(intf, UMC_GTXCF);
48064931534SJustin Chen 	ctrl_stats->MACControlFramesReceived = umac_rl(intf, UMC_GRXCF);
48164931534SJustin Chen 	ctrl_stats->UnsupportedOpcodesReceived = umac_rl(intf, UMC_GRXUO);
48264931534SJustin Chen }
48364931534SJustin Chen 
484490cb412SJustin Chen const struct ethtool_ops bcmasp_ethtool_ops = {
485490cb412SJustin Chen 	.get_drvinfo		= bcmasp_get_drvinfo,
486490cb412SJustin Chen 	.get_link		= ethtool_op_get_link,
487490cb412SJustin Chen 	.get_link_ksettings	= phy_ethtool_get_link_ksettings,
488490cb412SJustin Chen 	.set_link_ksettings	= phy_ethtool_set_link_ksettings,
489490cb412SJustin Chen 	.get_msglevel		= bcmasp_get_msglevel,
490490cb412SJustin Chen 	.set_msglevel		= bcmasp_set_msglevel,
491a2f07512SJustin Chen 	.get_wol		= bcmasp_get_wol,
492a2f07512SJustin Chen 	.set_wol		= bcmasp_set_wol,
493c5d511c4SJustin Chen 	.get_rxnfc		= bcmasp_get_rxnfc,
494c5d511c4SJustin Chen 	.set_rxnfc		= bcmasp_set_rxnfc,
495550e6f34SJustin Chen 	.set_eee		= bcmasp_set_eee,
496550e6f34SJustin Chen 	.get_eee		= bcmasp_get_eee,
49764931534SJustin Chen 	.get_eth_mac_stats	= bcmasp_get_eth_mac_stats,
49864931534SJustin Chen 	.get_rmon_stats		= bcmasp_get_rmon_stats,
49964931534SJustin Chen 	.get_eth_ctrl_stats	= bcmasp_get_eth_ctrl_stats,
5007c10691eSJustin Chen 	.get_strings		= bcmasp_get_strings,
5017c10691eSJustin Chen 	.get_ethtool_stats	= bcmasp_get_ethtool_stats,
5027c10691eSJustin Chen 	.get_sset_count		= bcmasp_get_sset_count,
503490cb412SJustin Chen };
504