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