18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/* 10G controller driver for Samsung SoCs
38c2ecf20Sopenharmony_ci *
48c2ecf20Sopenharmony_ci * Copyright (C) 2013 Samsung Electronics Co., Ltd.
58c2ecf20Sopenharmony_ci *		http://www.samsung.com
68c2ecf20Sopenharmony_ci *
78c2ecf20Sopenharmony_ci * Author: Siva Reddy Kallam <siva.kallam@samsung.com>
88c2ecf20Sopenharmony_ci */
98c2ecf20Sopenharmony_ci
108c2ecf20Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
118c2ecf20Sopenharmony_ci
128c2ecf20Sopenharmony_ci#include <linux/clk.h>
138c2ecf20Sopenharmony_ci#include <linux/interrupt.h>
148c2ecf20Sopenharmony_ci#include <linux/kernel.h>
158c2ecf20Sopenharmony_ci#include <linux/netdevice.h>
168c2ecf20Sopenharmony_ci#include <linux/net_tstamp.h>
178c2ecf20Sopenharmony_ci#include <linux/phy.h>
188c2ecf20Sopenharmony_ci#include <linux/ptp_clock_kernel.h>
198c2ecf20Sopenharmony_ci
208c2ecf20Sopenharmony_ci#include "sxgbe_common.h"
218c2ecf20Sopenharmony_ci#include "sxgbe_reg.h"
228c2ecf20Sopenharmony_ci#include "sxgbe_dma.h"
238c2ecf20Sopenharmony_ci
248c2ecf20Sopenharmony_cistruct sxgbe_stats {
258c2ecf20Sopenharmony_ci	char stat_string[ETH_GSTRING_LEN];
268c2ecf20Sopenharmony_ci	int sizeof_stat;
278c2ecf20Sopenharmony_ci	int stat_offset;
288c2ecf20Sopenharmony_ci};
298c2ecf20Sopenharmony_ci
308c2ecf20Sopenharmony_ci#define SXGBE_STAT(m)						\
318c2ecf20Sopenharmony_ci{								\
328c2ecf20Sopenharmony_ci	#m,							\
338c2ecf20Sopenharmony_ci	sizeof_field(struct sxgbe_extra_stats, m),		\
348c2ecf20Sopenharmony_ci	offsetof(struct sxgbe_priv_data, xstats.m)		\
358c2ecf20Sopenharmony_ci}
368c2ecf20Sopenharmony_ci
378c2ecf20Sopenharmony_cistatic const struct sxgbe_stats sxgbe_gstrings_stats[] = {
388c2ecf20Sopenharmony_ci	/* TX/RX IRQ events */
398c2ecf20Sopenharmony_ci	SXGBE_STAT(tx_process_stopped_irq),
408c2ecf20Sopenharmony_ci	SXGBE_STAT(tx_ctxt_desc_err),
418c2ecf20Sopenharmony_ci	SXGBE_STAT(tx_threshold),
428c2ecf20Sopenharmony_ci	SXGBE_STAT(rx_threshold),
438c2ecf20Sopenharmony_ci	SXGBE_STAT(tx_pkt_n),
448c2ecf20Sopenharmony_ci	SXGBE_STAT(rx_pkt_n),
458c2ecf20Sopenharmony_ci	SXGBE_STAT(normal_irq_n),
468c2ecf20Sopenharmony_ci	SXGBE_STAT(tx_normal_irq_n),
478c2ecf20Sopenharmony_ci	SXGBE_STAT(rx_normal_irq_n),
488c2ecf20Sopenharmony_ci	SXGBE_STAT(napi_poll),
498c2ecf20Sopenharmony_ci	SXGBE_STAT(tx_clean),
508c2ecf20Sopenharmony_ci	SXGBE_STAT(tx_reset_ic_bit),
518c2ecf20Sopenharmony_ci	SXGBE_STAT(rx_process_stopped_irq),
528c2ecf20Sopenharmony_ci	SXGBE_STAT(rx_underflow_irq),
538c2ecf20Sopenharmony_ci
548c2ecf20Sopenharmony_ci	/* Bus access errors */
558c2ecf20Sopenharmony_ci	SXGBE_STAT(fatal_bus_error_irq),
568c2ecf20Sopenharmony_ci	SXGBE_STAT(tx_read_transfer_err),
578c2ecf20Sopenharmony_ci	SXGBE_STAT(tx_write_transfer_err),
588c2ecf20Sopenharmony_ci	SXGBE_STAT(tx_desc_access_err),
598c2ecf20Sopenharmony_ci	SXGBE_STAT(tx_buffer_access_err),
608c2ecf20Sopenharmony_ci	SXGBE_STAT(tx_data_transfer_err),
618c2ecf20Sopenharmony_ci	SXGBE_STAT(rx_read_transfer_err),
628c2ecf20Sopenharmony_ci	SXGBE_STAT(rx_write_transfer_err),
638c2ecf20Sopenharmony_ci	SXGBE_STAT(rx_desc_access_err),
648c2ecf20Sopenharmony_ci	SXGBE_STAT(rx_buffer_access_err),
658c2ecf20Sopenharmony_ci	SXGBE_STAT(rx_data_transfer_err),
668c2ecf20Sopenharmony_ci
678c2ecf20Sopenharmony_ci	/* EEE-LPI stats */
688c2ecf20Sopenharmony_ci	SXGBE_STAT(tx_lpi_entry_n),
698c2ecf20Sopenharmony_ci	SXGBE_STAT(tx_lpi_exit_n),
708c2ecf20Sopenharmony_ci	SXGBE_STAT(rx_lpi_entry_n),
718c2ecf20Sopenharmony_ci	SXGBE_STAT(rx_lpi_exit_n),
728c2ecf20Sopenharmony_ci	SXGBE_STAT(eee_wakeup_error_n),
738c2ecf20Sopenharmony_ci
748c2ecf20Sopenharmony_ci	/* RX specific */
758c2ecf20Sopenharmony_ci	/* L2 error */
768c2ecf20Sopenharmony_ci	SXGBE_STAT(rx_code_gmii_err),
778c2ecf20Sopenharmony_ci	SXGBE_STAT(rx_watchdog_err),
788c2ecf20Sopenharmony_ci	SXGBE_STAT(rx_crc_err),
798c2ecf20Sopenharmony_ci	SXGBE_STAT(rx_gaint_pkt_err),
808c2ecf20Sopenharmony_ci	SXGBE_STAT(ip_hdr_err),
818c2ecf20Sopenharmony_ci	SXGBE_STAT(ip_payload_err),
828c2ecf20Sopenharmony_ci	SXGBE_STAT(overflow_error),
838c2ecf20Sopenharmony_ci
848c2ecf20Sopenharmony_ci	/* L2 Pkt type */
858c2ecf20Sopenharmony_ci	SXGBE_STAT(len_pkt),
868c2ecf20Sopenharmony_ci	SXGBE_STAT(mac_ctl_pkt),
878c2ecf20Sopenharmony_ci	SXGBE_STAT(dcb_ctl_pkt),
888c2ecf20Sopenharmony_ci	SXGBE_STAT(arp_pkt),
898c2ecf20Sopenharmony_ci	SXGBE_STAT(oam_pkt),
908c2ecf20Sopenharmony_ci	SXGBE_STAT(untag_okt),
918c2ecf20Sopenharmony_ci	SXGBE_STAT(other_pkt),
928c2ecf20Sopenharmony_ci	SXGBE_STAT(svlan_tag_pkt),
938c2ecf20Sopenharmony_ci	SXGBE_STAT(cvlan_tag_pkt),
948c2ecf20Sopenharmony_ci	SXGBE_STAT(dvlan_ocvlan_icvlan_pkt),
958c2ecf20Sopenharmony_ci	SXGBE_STAT(dvlan_osvlan_isvlan_pkt),
968c2ecf20Sopenharmony_ci	SXGBE_STAT(dvlan_osvlan_icvlan_pkt),
978c2ecf20Sopenharmony_ci	SXGBE_STAT(dvan_ocvlan_icvlan_pkt),
988c2ecf20Sopenharmony_ci
998c2ecf20Sopenharmony_ci	/* L3/L4 Pkt type */
1008c2ecf20Sopenharmony_ci	SXGBE_STAT(not_ip_pkt),
1018c2ecf20Sopenharmony_ci	SXGBE_STAT(ip4_tcp_pkt),
1028c2ecf20Sopenharmony_ci	SXGBE_STAT(ip4_udp_pkt),
1038c2ecf20Sopenharmony_ci	SXGBE_STAT(ip4_icmp_pkt),
1048c2ecf20Sopenharmony_ci	SXGBE_STAT(ip4_unknown_pkt),
1058c2ecf20Sopenharmony_ci	SXGBE_STAT(ip6_tcp_pkt),
1068c2ecf20Sopenharmony_ci	SXGBE_STAT(ip6_udp_pkt),
1078c2ecf20Sopenharmony_ci	SXGBE_STAT(ip6_icmp_pkt),
1088c2ecf20Sopenharmony_ci	SXGBE_STAT(ip6_unknown_pkt),
1098c2ecf20Sopenharmony_ci
1108c2ecf20Sopenharmony_ci	/* Filter specific */
1118c2ecf20Sopenharmony_ci	SXGBE_STAT(vlan_filter_match),
1128c2ecf20Sopenharmony_ci	SXGBE_STAT(sa_filter_fail),
1138c2ecf20Sopenharmony_ci	SXGBE_STAT(da_filter_fail),
1148c2ecf20Sopenharmony_ci	SXGBE_STAT(hash_filter_pass),
1158c2ecf20Sopenharmony_ci	SXGBE_STAT(l3_filter_match),
1168c2ecf20Sopenharmony_ci	SXGBE_STAT(l4_filter_match),
1178c2ecf20Sopenharmony_ci
1188c2ecf20Sopenharmony_ci	/* RX context specific */
1198c2ecf20Sopenharmony_ci	SXGBE_STAT(timestamp_dropped),
1208c2ecf20Sopenharmony_ci	SXGBE_STAT(rx_msg_type_no_ptp),
1218c2ecf20Sopenharmony_ci	SXGBE_STAT(rx_ptp_type_sync),
1228c2ecf20Sopenharmony_ci	SXGBE_STAT(rx_ptp_type_follow_up),
1238c2ecf20Sopenharmony_ci	SXGBE_STAT(rx_ptp_type_delay_req),
1248c2ecf20Sopenharmony_ci	SXGBE_STAT(rx_ptp_type_delay_resp),
1258c2ecf20Sopenharmony_ci	SXGBE_STAT(rx_ptp_type_pdelay_req),
1268c2ecf20Sopenharmony_ci	SXGBE_STAT(rx_ptp_type_pdelay_resp),
1278c2ecf20Sopenharmony_ci	SXGBE_STAT(rx_ptp_type_pdelay_follow_up),
1288c2ecf20Sopenharmony_ci	SXGBE_STAT(rx_ptp_announce),
1298c2ecf20Sopenharmony_ci	SXGBE_STAT(rx_ptp_mgmt),
1308c2ecf20Sopenharmony_ci	SXGBE_STAT(rx_ptp_signal),
1318c2ecf20Sopenharmony_ci	SXGBE_STAT(rx_ptp_resv_msg_type),
1328c2ecf20Sopenharmony_ci};
1338c2ecf20Sopenharmony_ci#define SXGBE_STATS_LEN ARRAY_SIZE(sxgbe_gstrings_stats)
1348c2ecf20Sopenharmony_ci
1358c2ecf20Sopenharmony_cistatic int sxgbe_get_eee(struct net_device *dev,
1368c2ecf20Sopenharmony_ci			 struct ethtool_eee *edata)
1378c2ecf20Sopenharmony_ci{
1388c2ecf20Sopenharmony_ci	struct sxgbe_priv_data *priv = netdev_priv(dev);
1398c2ecf20Sopenharmony_ci
1408c2ecf20Sopenharmony_ci	if (!priv->hw_cap.eee)
1418c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
1428c2ecf20Sopenharmony_ci
1438c2ecf20Sopenharmony_ci	edata->eee_enabled = priv->eee_enabled;
1448c2ecf20Sopenharmony_ci	edata->eee_active = priv->eee_active;
1458c2ecf20Sopenharmony_ci	edata->tx_lpi_timer = priv->tx_lpi_timer;
1468c2ecf20Sopenharmony_ci
1478c2ecf20Sopenharmony_ci	return phy_ethtool_get_eee(dev->phydev, edata);
1488c2ecf20Sopenharmony_ci}
1498c2ecf20Sopenharmony_ci
1508c2ecf20Sopenharmony_cistatic int sxgbe_set_eee(struct net_device *dev,
1518c2ecf20Sopenharmony_ci			 struct ethtool_eee *edata)
1528c2ecf20Sopenharmony_ci{
1538c2ecf20Sopenharmony_ci	struct sxgbe_priv_data *priv = netdev_priv(dev);
1548c2ecf20Sopenharmony_ci
1558c2ecf20Sopenharmony_ci	priv->eee_enabled = edata->eee_enabled;
1568c2ecf20Sopenharmony_ci
1578c2ecf20Sopenharmony_ci	if (!priv->eee_enabled) {
1588c2ecf20Sopenharmony_ci		sxgbe_disable_eee_mode(priv);
1598c2ecf20Sopenharmony_ci	} else {
1608c2ecf20Sopenharmony_ci		/* We are asking for enabling the EEE but it is safe
1618c2ecf20Sopenharmony_ci		 * to verify all by invoking the eee_init function.
1628c2ecf20Sopenharmony_ci		 * In case of failure it will return an error.
1638c2ecf20Sopenharmony_ci		 */
1648c2ecf20Sopenharmony_ci		priv->eee_enabled = sxgbe_eee_init(priv);
1658c2ecf20Sopenharmony_ci		if (!priv->eee_enabled)
1668c2ecf20Sopenharmony_ci			return -EOPNOTSUPP;
1678c2ecf20Sopenharmony_ci
1688c2ecf20Sopenharmony_ci		/* Do not change tx_lpi_timer in case of failure */
1698c2ecf20Sopenharmony_ci		priv->tx_lpi_timer = edata->tx_lpi_timer;
1708c2ecf20Sopenharmony_ci	}
1718c2ecf20Sopenharmony_ci
1728c2ecf20Sopenharmony_ci	return phy_ethtool_set_eee(dev->phydev, edata);
1738c2ecf20Sopenharmony_ci}
1748c2ecf20Sopenharmony_ci
1758c2ecf20Sopenharmony_cistatic void sxgbe_getdrvinfo(struct net_device *dev,
1768c2ecf20Sopenharmony_ci			     struct ethtool_drvinfo *info)
1778c2ecf20Sopenharmony_ci{
1788c2ecf20Sopenharmony_ci	strlcpy(info->driver, KBUILD_MODNAME, sizeof(info->driver));
1798c2ecf20Sopenharmony_ci	strlcpy(info->version, DRV_VERSION, sizeof(info->version));
1808c2ecf20Sopenharmony_ci}
1818c2ecf20Sopenharmony_ci
1828c2ecf20Sopenharmony_cistatic u32 sxgbe_getmsglevel(struct net_device *dev)
1838c2ecf20Sopenharmony_ci{
1848c2ecf20Sopenharmony_ci	struct sxgbe_priv_data *priv = netdev_priv(dev);
1858c2ecf20Sopenharmony_ci	return priv->msg_enable;
1868c2ecf20Sopenharmony_ci}
1878c2ecf20Sopenharmony_ci
1888c2ecf20Sopenharmony_cistatic void sxgbe_setmsglevel(struct net_device *dev, u32 level)
1898c2ecf20Sopenharmony_ci{
1908c2ecf20Sopenharmony_ci	struct sxgbe_priv_data *priv = netdev_priv(dev);
1918c2ecf20Sopenharmony_ci	priv->msg_enable = level;
1928c2ecf20Sopenharmony_ci}
1938c2ecf20Sopenharmony_ci
1948c2ecf20Sopenharmony_cistatic void sxgbe_get_strings(struct net_device *dev, u32 stringset, u8 *data)
1958c2ecf20Sopenharmony_ci{
1968c2ecf20Sopenharmony_ci	int i;
1978c2ecf20Sopenharmony_ci	u8 *p = data;
1988c2ecf20Sopenharmony_ci
1998c2ecf20Sopenharmony_ci	switch (stringset) {
2008c2ecf20Sopenharmony_ci	case ETH_SS_STATS:
2018c2ecf20Sopenharmony_ci		for (i = 0; i < SXGBE_STATS_LEN; i++) {
2028c2ecf20Sopenharmony_ci			memcpy(p, sxgbe_gstrings_stats[i].stat_string,
2038c2ecf20Sopenharmony_ci			       ETH_GSTRING_LEN);
2048c2ecf20Sopenharmony_ci			p += ETH_GSTRING_LEN;
2058c2ecf20Sopenharmony_ci		}
2068c2ecf20Sopenharmony_ci		break;
2078c2ecf20Sopenharmony_ci	default:
2088c2ecf20Sopenharmony_ci		WARN_ON(1);
2098c2ecf20Sopenharmony_ci		break;
2108c2ecf20Sopenharmony_ci	}
2118c2ecf20Sopenharmony_ci}
2128c2ecf20Sopenharmony_ci
2138c2ecf20Sopenharmony_cistatic int sxgbe_get_sset_count(struct net_device *netdev, int sset)
2148c2ecf20Sopenharmony_ci{
2158c2ecf20Sopenharmony_ci	int len;
2168c2ecf20Sopenharmony_ci
2178c2ecf20Sopenharmony_ci	switch (sset) {
2188c2ecf20Sopenharmony_ci	case ETH_SS_STATS:
2198c2ecf20Sopenharmony_ci		len = SXGBE_STATS_LEN;
2208c2ecf20Sopenharmony_ci		return len;
2218c2ecf20Sopenharmony_ci	default:
2228c2ecf20Sopenharmony_ci		return -EINVAL;
2238c2ecf20Sopenharmony_ci	}
2248c2ecf20Sopenharmony_ci}
2258c2ecf20Sopenharmony_ci
2268c2ecf20Sopenharmony_cistatic void sxgbe_get_ethtool_stats(struct net_device *dev,
2278c2ecf20Sopenharmony_ci				    struct ethtool_stats *dummy, u64 *data)
2288c2ecf20Sopenharmony_ci{
2298c2ecf20Sopenharmony_ci	struct sxgbe_priv_data *priv = netdev_priv(dev);
2308c2ecf20Sopenharmony_ci	int i;
2318c2ecf20Sopenharmony_ci	char *p;
2328c2ecf20Sopenharmony_ci
2338c2ecf20Sopenharmony_ci	if (priv->eee_enabled) {
2348c2ecf20Sopenharmony_ci		int val = phy_get_eee_err(dev->phydev);
2358c2ecf20Sopenharmony_ci
2368c2ecf20Sopenharmony_ci		if (val)
2378c2ecf20Sopenharmony_ci			priv->xstats.eee_wakeup_error_n = val;
2388c2ecf20Sopenharmony_ci	}
2398c2ecf20Sopenharmony_ci
2408c2ecf20Sopenharmony_ci	for (i = 0; i < SXGBE_STATS_LEN; i++) {
2418c2ecf20Sopenharmony_ci		p = (char *)priv + sxgbe_gstrings_stats[i].stat_offset;
2428c2ecf20Sopenharmony_ci		data[i] = (sxgbe_gstrings_stats[i].sizeof_stat == sizeof(u64))
2438c2ecf20Sopenharmony_ci			? (*(u64 *)p) : (*(u32 *)p);
2448c2ecf20Sopenharmony_ci	}
2458c2ecf20Sopenharmony_ci}
2468c2ecf20Sopenharmony_ci
2478c2ecf20Sopenharmony_cistatic void sxgbe_get_channels(struct net_device *dev,
2488c2ecf20Sopenharmony_ci			       struct ethtool_channels *channel)
2498c2ecf20Sopenharmony_ci{
2508c2ecf20Sopenharmony_ci	channel->max_rx = SXGBE_MAX_RX_CHANNELS;
2518c2ecf20Sopenharmony_ci	channel->max_tx = SXGBE_MAX_TX_CHANNELS;
2528c2ecf20Sopenharmony_ci	channel->rx_count = SXGBE_RX_QUEUES;
2538c2ecf20Sopenharmony_ci	channel->tx_count = SXGBE_TX_QUEUES;
2548c2ecf20Sopenharmony_ci}
2558c2ecf20Sopenharmony_ci
2568c2ecf20Sopenharmony_cistatic u32 sxgbe_riwt2usec(u32 riwt, struct sxgbe_priv_data *priv)
2578c2ecf20Sopenharmony_ci{
2588c2ecf20Sopenharmony_ci	unsigned long clk = clk_get_rate(priv->sxgbe_clk);
2598c2ecf20Sopenharmony_ci
2608c2ecf20Sopenharmony_ci	if (!clk)
2618c2ecf20Sopenharmony_ci		return 0;
2628c2ecf20Sopenharmony_ci
2638c2ecf20Sopenharmony_ci	return (riwt * 256) / (clk / 1000000);
2648c2ecf20Sopenharmony_ci}
2658c2ecf20Sopenharmony_ci
2668c2ecf20Sopenharmony_cistatic u32 sxgbe_usec2riwt(u32 usec, struct sxgbe_priv_data *priv)
2678c2ecf20Sopenharmony_ci{
2688c2ecf20Sopenharmony_ci	unsigned long clk = clk_get_rate(priv->sxgbe_clk);
2698c2ecf20Sopenharmony_ci
2708c2ecf20Sopenharmony_ci	if (!clk)
2718c2ecf20Sopenharmony_ci		return 0;
2728c2ecf20Sopenharmony_ci
2738c2ecf20Sopenharmony_ci	return (usec * (clk / 1000000)) / 256;
2748c2ecf20Sopenharmony_ci}
2758c2ecf20Sopenharmony_ci
2768c2ecf20Sopenharmony_cistatic int sxgbe_get_coalesce(struct net_device *dev,
2778c2ecf20Sopenharmony_ci			      struct ethtool_coalesce *ec)
2788c2ecf20Sopenharmony_ci{
2798c2ecf20Sopenharmony_ci	struct sxgbe_priv_data *priv = netdev_priv(dev);
2808c2ecf20Sopenharmony_ci
2818c2ecf20Sopenharmony_ci	if (priv->use_riwt)
2828c2ecf20Sopenharmony_ci		ec->rx_coalesce_usecs = sxgbe_riwt2usec(priv->rx_riwt, priv);
2838c2ecf20Sopenharmony_ci
2848c2ecf20Sopenharmony_ci	return 0;
2858c2ecf20Sopenharmony_ci}
2868c2ecf20Sopenharmony_ci
2878c2ecf20Sopenharmony_cistatic int sxgbe_set_coalesce(struct net_device *dev,
2888c2ecf20Sopenharmony_ci			      struct ethtool_coalesce *ec)
2898c2ecf20Sopenharmony_ci{
2908c2ecf20Sopenharmony_ci	struct sxgbe_priv_data *priv = netdev_priv(dev);
2918c2ecf20Sopenharmony_ci	unsigned int rx_riwt;
2928c2ecf20Sopenharmony_ci
2938c2ecf20Sopenharmony_ci	if (!ec->rx_coalesce_usecs)
2948c2ecf20Sopenharmony_ci		return -EINVAL;
2958c2ecf20Sopenharmony_ci
2968c2ecf20Sopenharmony_ci	rx_riwt = sxgbe_usec2riwt(ec->rx_coalesce_usecs, priv);
2978c2ecf20Sopenharmony_ci
2988c2ecf20Sopenharmony_ci	if ((rx_riwt > SXGBE_MAX_DMA_RIWT) || (rx_riwt < SXGBE_MIN_DMA_RIWT))
2998c2ecf20Sopenharmony_ci		return -EINVAL;
3008c2ecf20Sopenharmony_ci	else if (!priv->use_riwt)
3018c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
3028c2ecf20Sopenharmony_ci
3038c2ecf20Sopenharmony_ci	priv->rx_riwt = rx_riwt;
3048c2ecf20Sopenharmony_ci	priv->hw->dma->rx_watchdog(priv->ioaddr, priv->rx_riwt);
3058c2ecf20Sopenharmony_ci
3068c2ecf20Sopenharmony_ci	return 0;
3078c2ecf20Sopenharmony_ci}
3088c2ecf20Sopenharmony_ci
3098c2ecf20Sopenharmony_cistatic int sxgbe_get_rss_hash_opts(struct sxgbe_priv_data *priv,
3108c2ecf20Sopenharmony_ci				   struct ethtool_rxnfc *cmd)
3118c2ecf20Sopenharmony_ci{
3128c2ecf20Sopenharmony_ci	cmd->data = 0;
3138c2ecf20Sopenharmony_ci
3148c2ecf20Sopenharmony_ci	/* Report default options for RSS on sxgbe */
3158c2ecf20Sopenharmony_ci	switch (cmd->flow_type) {
3168c2ecf20Sopenharmony_ci	case TCP_V4_FLOW:
3178c2ecf20Sopenharmony_ci	case UDP_V4_FLOW:
3188c2ecf20Sopenharmony_ci		cmd->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3;
3198c2ecf20Sopenharmony_ci		fallthrough;
3208c2ecf20Sopenharmony_ci	case SCTP_V4_FLOW:
3218c2ecf20Sopenharmony_ci	case AH_ESP_V4_FLOW:
3228c2ecf20Sopenharmony_ci	case AH_V4_FLOW:
3238c2ecf20Sopenharmony_ci	case ESP_V4_FLOW:
3248c2ecf20Sopenharmony_ci	case IPV4_FLOW:
3258c2ecf20Sopenharmony_ci		cmd->data |= RXH_IP_SRC | RXH_IP_DST;
3268c2ecf20Sopenharmony_ci		break;
3278c2ecf20Sopenharmony_ci	case TCP_V6_FLOW:
3288c2ecf20Sopenharmony_ci	case UDP_V6_FLOW:
3298c2ecf20Sopenharmony_ci		cmd->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3;
3308c2ecf20Sopenharmony_ci		fallthrough;
3318c2ecf20Sopenharmony_ci	case SCTP_V6_FLOW:
3328c2ecf20Sopenharmony_ci	case AH_ESP_V6_FLOW:
3338c2ecf20Sopenharmony_ci	case AH_V6_FLOW:
3348c2ecf20Sopenharmony_ci	case ESP_V6_FLOW:
3358c2ecf20Sopenharmony_ci	case IPV6_FLOW:
3368c2ecf20Sopenharmony_ci		cmd->data |= RXH_IP_SRC | RXH_IP_DST;
3378c2ecf20Sopenharmony_ci		break;
3388c2ecf20Sopenharmony_ci	default:
3398c2ecf20Sopenharmony_ci		return -EINVAL;
3408c2ecf20Sopenharmony_ci	}
3418c2ecf20Sopenharmony_ci
3428c2ecf20Sopenharmony_ci	return 0;
3438c2ecf20Sopenharmony_ci}
3448c2ecf20Sopenharmony_ci
3458c2ecf20Sopenharmony_cistatic int sxgbe_get_rxnfc(struct net_device *dev, struct ethtool_rxnfc *cmd,
3468c2ecf20Sopenharmony_ci			   u32 *rule_locs)
3478c2ecf20Sopenharmony_ci{
3488c2ecf20Sopenharmony_ci	struct sxgbe_priv_data *priv = netdev_priv(dev);
3498c2ecf20Sopenharmony_ci	int ret = -EOPNOTSUPP;
3508c2ecf20Sopenharmony_ci
3518c2ecf20Sopenharmony_ci	switch (cmd->cmd) {
3528c2ecf20Sopenharmony_ci	case ETHTOOL_GRXFH:
3538c2ecf20Sopenharmony_ci		ret = sxgbe_get_rss_hash_opts(priv, cmd);
3548c2ecf20Sopenharmony_ci		break;
3558c2ecf20Sopenharmony_ci	default:
3568c2ecf20Sopenharmony_ci		break;
3578c2ecf20Sopenharmony_ci	}
3588c2ecf20Sopenharmony_ci
3598c2ecf20Sopenharmony_ci	return ret;
3608c2ecf20Sopenharmony_ci}
3618c2ecf20Sopenharmony_ci
3628c2ecf20Sopenharmony_cistatic int sxgbe_set_rss_hash_opt(struct sxgbe_priv_data *priv,
3638c2ecf20Sopenharmony_ci				  struct ethtool_rxnfc *cmd)
3648c2ecf20Sopenharmony_ci{
3658c2ecf20Sopenharmony_ci	u32 reg_val = 0;
3668c2ecf20Sopenharmony_ci
3678c2ecf20Sopenharmony_ci	/* RSS does not support anything other than hashing
3688c2ecf20Sopenharmony_ci	 * to queues on src and dst IPs and ports
3698c2ecf20Sopenharmony_ci	 */
3708c2ecf20Sopenharmony_ci	if (cmd->data & ~(RXH_IP_SRC | RXH_IP_DST |
3718c2ecf20Sopenharmony_ci			  RXH_L4_B_0_1 | RXH_L4_B_2_3))
3728c2ecf20Sopenharmony_ci		return -EINVAL;
3738c2ecf20Sopenharmony_ci
3748c2ecf20Sopenharmony_ci	switch (cmd->flow_type) {
3758c2ecf20Sopenharmony_ci	case TCP_V4_FLOW:
3768c2ecf20Sopenharmony_ci	case TCP_V6_FLOW:
3778c2ecf20Sopenharmony_ci		if (!(cmd->data & RXH_IP_SRC) ||
3788c2ecf20Sopenharmony_ci		    !(cmd->data & RXH_IP_DST) ||
3798c2ecf20Sopenharmony_ci		    !(cmd->data & RXH_L4_B_0_1) ||
3808c2ecf20Sopenharmony_ci		    !(cmd->data & RXH_L4_B_2_3))
3818c2ecf20Sopenharmony_ci			return -EINVAL;
3828c2ecf20Sopenharmony_ci		reg_val = SXGBE_CORE_RSS_CTL_TCP4TE;
3838c2ecf20Sopenharmony_ci		break;
3848c2ecf20Sopenharmony_ci	case UDP_V4_FLOW:
3858c2ecf20Sopenharmony_ci	case UDP_V6_FLOW:
3868c2ecf20Sopenharmony_ci		if (!(cmd->data & RXH_IP_SRC) ||
3878c2ecf20Sopenharmony_ci		    !(cmd->data & RXH_IP_DST) ||
3888c2ecf20Sopenharmony_ci		    !(cmd->data & RXH_L4_B_0_1) ||
3898c2ecf20Sopenharmony_ci		    !(cmd->data & RXH_L4_B_2_3))
3908c2ecf20Sopenharmony_ci			return -EINVAL;
3918c2ecf20Sopenharmony_ci		reg_val = SXGBE_CORE_RSS_CTL_UDP4TE;
3928c2ecf20Sopenharmony_ci		break;
3938c2ecf20Sopenharmony_ci	case SCTP_V4_FLOW:
3948c2ecf20Sopenharmony_ci	case AH_ESP_V4_FLOW:
3958c2ecf20Sopenharmony_ci	case AH_V4_FLOW:
3968c2ecf20Sopenharmony_ci	case ESP_V4_FLOW:
3978c2ecf20Sopenharmony_ci	case AH_ESP_V6_FLOW:
3988c2ecf20Sopenharmony_ci	case AH_V6_FLOW:
3998c2ecf20Sopenharmony_ci	case ESP_V6_FLOW:
4008c2ecf20Sopenharmony_ci	case SCTP_V6_FLOW:
4018c2ecf20Sopenharmony_ci	case IPV4_FLOW:
4028c2ecf20Sopenharmony_ci	case IPV6_FLOW:
4038c2ecf20Sopenharmony_ci		if (!(cmd->data & RXH_IP_SRC) ||
4048c2ecf20Sopenharmony_ci		    !(cmd->data & RXH_IP_DST) ||
4058c2ecf20Sopenharmony_ci		    (cmd->data & RXH_L4_B_0_1) ||
4068c2ecf20Sopenharmony_ci		    (cmd->data & RXH_L4_B_2_3))
4078c2ecf20Sopenharmony_ci			return -EINVAL;
4088c2ecf20Sopenharmony_ci		reg_val = SXGBE_CORE_RSS_CTL_IP2TE;
4098c2ecf20Sopenharmony_ci		break;
4108c2ecf20Sopenharmony_ci	default:
4118c2ecf20Sopenharmony_ci		return -EINVAL;
4128c2ecf20Sopenharmony_ci	}
4138c2ecf20Sopenharmony_ci
4148c2ecf20Sopenharmony_ci	/* Read SXGBE RSS control register and update */
4158c2ecf20Sopenharmony_ci	reg_val |= readl(priv->ioaddr + SXGBE_CORE_RSS_CTL_REG);
4168c2ecf20Sopenharmony_ci	writel(reg_val, priv->ioaddr + SXGBE_CORE_RSS_CTL_REG);
4178c2ecf20Sopenharmony_ci	readl(priv->ioaddr + SXGBE_CORE_RSS_CTL_REG);
4188c2ecf20Sopenharmony_ci
4198c2ecf20Sopenharmony_ci	return 0;
4208c2ecf20Sopenharmony_ci}
4218c2ecf20Sopenharmony_ci
4228c2ecf20Sopenharmony_cistatic int sxgbe_set_rxnfc(struct net_device *dev, struct ethtool_rxnfc *cmd)
4238c2ecf20Sopenharmony_ci{
4248c2ecf20Sopenharmony_ci	struct sxgbe_priv_data *priv = netdev_priv(dev);
4258c2ecf20Sopenharmony_ci	int ret = -EOPNOTSUPP;
4268c2ecf20Sopenharmony_ci
4278c2ecf20Sopenharmony_ci	switch (cmd->cmd) {
4288c2ecf20Sopenharmony_ci	case ETHTOOL_SRXFH:
4298c2ecf20Sopenharmony_ci		ret = sxgbe_set_rss_hash_opt(priv, cmd);
4308c2ecf20Sopenharmony_ci		break;
4318c2ecf20Sopenharmony_ci	default:
4328c2ecf20Sopenharmony_ci		break;
4338c2ecf20Sopenharmony_ci	}
4348c2ecf20Sopenharmony_ci
4358c2ecf20Sopenharmony_ci	return ret;
4368c2ecf20Sopenharmony_ci}
4378c2ecf20Sopenharmony_ci
4388c2ecf20Sopenharmony_cistatic void sxgbe_get_regs(struct net_device *dev,
4398c2ecf20Sopenharmony_ci			   struct ethtool_regs *regs, void *space)
4408c2ecf20Sopenharmony_ci{
4418c2ecf20Sopenharmony_ci	struct sxgbe_priv_data *priv = netdev_priv(dev);
4428c2ecf20Sopenharmony_ci	u32 *reg_space = (u32 *)space;
4438c2ecf20Sopenharmony_ci	int reg_offset;
4448c2ecf20Sopenharmony_ci	int reg_ix = 0;
4458c2ecf20Sopenharmony_ci	void __iomem *ioaddr = priv->ioaddr;
4468c2ecf20Sopenharmony_ci
4478c2ecf20Sopenharmony_ci	memset(reg_space, 0x0, REG_SPACE_SIZE);
4488c2ecf20Sopenharmony_ci
4498c2ecf20Sopenharmony_ci	/* MAC registers */
4508c2ecf20Sopenharmony_ci	for (reg_offset = START_MAC_REG_OFFSET;
4518c2ecf20Sopenharmony_ci	     reg_offset <= MAX_MAC_REG_OFFSET; reg_offset += 4) {
4528c2ecf20Sopenharmony_ci		reg_space[reg_ix] = readl(ioaddr + reg_offset);
4538c2ecf20Sopenharmony_ci		reg_ix++;
4548c2ecf20Sopenharmony_ci	}
4558c2ecf20Sopenharmony_ci
4568c2ecf20Sopenharmony_ci	/* MTL registers */
4578c2ecf20Sopenharmony_ci	for (reg_offset = START_MTL_REG_OFFSET;
4588c2ecf20Sopenharmony_ci	     reg_offset <= MAX_MTL_REG_OFFSET; reg_offset += 4) {
4598c2ecf20Sopenharmony_ci		reg_space[reg_ix] = readl(ioaddr + reg_offset);
4608c2ecf20Sopenharmony_ci		reg_ix++;
4618c2ecf20Sopenharmony_ci	}
4628c2ecf20Sopenharmony_ci
4638c2ecf20Sopenharmony_ci	/* DMA registers */
4648c2ecf20Sopenharmony_ci	for (reg_offset = START_DMA_REG_OFFSET;
4658c2ecf20Sopenharmony_ci	     reg_offset <= MAX_DMA_REG_OFFSET; reg_offset += 4) {
4668c2ecf20Sopenharmony_ci		reg_space[reg_ix] = readl(ioaddr + reg_offset);
4678c2ecf20Sopenharmony_ci		reg_ix++;
4688c2ecf20Sopenharmony_ci	}
4698c2ecf20Sopenharmony_ci
4708c2ecf20Sopenharmony_ci	BUG_ON(reg_ix * 4 > REG_SPACE_SIZE);
4718c2ecf20Sopenharmony_ci}
4728c2ecf20Sopenharmony_ci
4738c2ecf20Sopenharmony_cistatic int sxgbe_get_regs_len(struct net_device *dev)
4748c2ecf20Sopenharmony_ci{
4758c2ecf20Sopenharmony_ci	return REG_SPACE_SIZE;
4768c2ecf20Sopenharmony_ci}
4778c2ecf20Sopenharmony_ci
4788c2ecf20Sopenharmony_cistatic const struct ethtool_ops sxgbe_ethtool_ops = {
4798c2ecf20Sopenharmony_ci	.supported_coalesce_params = ETHTOOL_COALESCE_RX_USECS,
4808c2ecf20Sopenharmony_ci	.get_drvinfo = sxgbe_getdrvinfo,
4818c2ecf20Sopenharmony_ci	.get_msglevel = sxgbe_getmsglevel,
4828c2ecf20Sopenharmony_ci	.set_msglevel = sxgbe_setmsglevel,
4838c2ecf20Sopenharmony_ci	.get_link = ethtool_op_get_link,
4848c2ecf20Sopenharmony_ci	.get_strings = sxgbe_get_strings,
4858c2ecf20Sopenharmony_ci	.get_ethtool_stats = sxgbe_get_ethtool_stats,
4868c2ecf20Sopenharmony_ci	.get_sset_count = sxgbe_get_sset_count,
4878c2ecf20Sopenharmony_ci	.get_channels = sxgbe_get_channels,
4888c2ecf20Sopenharmony_ci	.get_coalesce = sxgbe_get_coalesce,
4898c2ecf20Sopenharmony_ci	.set_coalesce = sxgbe_set_coalesce,
4908c2ecf20Sopenharmony_ci	.get_rxnfc = sxgbe_get_rxnfc,
4918c2ecf20Sopenharmony_ci	.set_rxnfc = sxgbe_set_rxnfc,
4928c2ecf20Sopenharmony_ci	.get_regs = sxgbe_get_regs,
4938c2ecf20Sopenharmony_ci	.get_regs_len = sxgbe_get_regs_len,
4948c2ecf20Sopenharmony_ci	.get_eee = sxgbe_get_eee,
4958c2ecf20Sopenharmony_ci	.set_eee = sxgbe_set_eee,
4968c2ecf20Sopenharmony_ci	.get_link_ksettings = phy_ethtool_get_link_ksettings,
4978c2ecf20Sopenharmony_ci	.set_link_ksettings = phy_ethtool_set_link_ksettings,
4988c2ecf20Sopenharmony_ci};
4998c2ecf20Sopenharmony_ci
5008c2ecf20Sopenharmony_civoid sxgbe_set_ethtool_ops(struct net_device *netdev)
5018c2ecf20Sopenharmony_ci{
5028c2ecf20Sopenharmony_ci	netdev->ethtool_ops = &sxgbe_ethtool_ops;
5038c2ecf20Sopenharmony_ci}
504