11edb9ca6SSiva Reddy /* 10G controller driver for Samsung SoCs 21edb9ca6SSiva Reddy * 31edb9ca6SSiva Reddy * Copyright (C) 2013 Samsung Electronics Co., Ltd. 41edb9ca6SSiva Reddy * http://www.samsung.com 51edb9ca6SSiva Reddy * 61edb9ca6SSiva Reddy * Author: Siva Reddy Kallam <siva.kallam@samsung.com> 71edb9ca6SSiva Reddy * 81edb9ca6SSiva Reddy * This program is free software; you can redistribute it and/or modify 91edb9ca6SSiva Reddy * it under the terms of the GNU General Public License version 2 as 101edb9ca6SSiva Reddy * published by the Free Software Foundation. 111edb9ca6SSiva Reddy */ 121edb9ca6SSiva Reddy 131edb9ca6SSiva Reddy #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 141edb9ca6SSiva Reddy 1525f72a74SVipul Pandya #include <linux/clk.h> 1625f72a74SVipul Pandya #include <linux/interrupt.h> 171edb9ca6SSiva Reddy #include <linux/kernel.h> 181edb9ca6SSiva Reddy #include <linux/netdevice.h> 1925f72a74SVipul Pandya #include <linux/net_tstamp.h> 201edb9ca6SSiva Reddy #include <linux/phy.h> 2125f72a74SVipul Pandya #include <linux/ptp_clock_kernel.h> 221edb9ca6SSiva Reddy 231edb9ca6SSiva Reddy #include "sxgbe_common.h" 2425f72a74SVipul Pandya #include "sxgbe_reg.h" 2525f72a74SVipul Pandya #include "sxgbe_dma.h" 261edb9ca6SSiva Reddy 271edb9ca6SSiva Reddy struct sxgbe_stats { 281edb9ca6SSiva Reddy char stat_string[ETH_GSTRING_LEN]; 291edb9ca6SSiva Reddy int sizeof_stat; 301edb9ca6SSiva Reddy int stat_offset; 311edb9ca6SSiva Reddy }; 321edb9ca6SSiva Reddy 331edb9ca6SSiva Reddy #define SXGBE_STAT(m) \ 341edb9ca6SSiva Reddy { \ 351edb9ca6SSiva Reddy #m, \ 361edb9ca6SSiva Reddy FIELD_SIZEOF(struct sxgbe_extra_stats, m), \ 371edb9ca6SSiva Reddy offsetof(struct sxgbe_priv_data, xstats.m) \ 381edb9ca6SSiva Reddy } 391edb9ca6SSiva Reddy 401edb9ca6SSiva Reddy static const struct sxgbe_stats sxgbe_gstrings_stats[] = { 4125f72a74SVipul Pandya /* TX/RX IRQ events */ 4225f72a74SVipul Pandya SXGBE_STAT(tx_process_stopped_irq), 4325f72a74SVipul Pandya SXGBE_STAT(tx_ctxt_desc_err), 4425f72a74SVipul Pandya SXGBE_STAT(tx_threshold), 4525f72a74SVipul Pandya SXGBE_STAT(rx_threshold), 4625f72a74SVipul Pandya SXGBE_STAT(tx_pkt_n), 4725f72a74SVipul Pandya SXGBE_STAT(rx_pkt_n), 4825f72a74SVipul Pandya SXGBE_STAT(normal_irq_n), 4925f72a74SVipul Pandya SXGBE_STAT(tx_normal_irq_n), 5025f72a74SVipul Pandya SXGBE_STAT(rx_normal_irq_n), 5125f72a74SVipul Pandya SXGBE_STAT(napi_poll), 5225f72a74SVipul Pandya SXGBE_STAT(tx_clean), 5325f72a74SVipul Pandya SXGBE_STAT(tx_reset_ic_bit), 5425f72a74SVipul Pandya SXGBE_STAT(rx_process_stopped_irq), 5525f72a74SVipul Pandya SXGBE_STAT(rx_underflow_irq), 5625f72a74SVipul Pandya 5725f72a74SVipul Pandya /* Bus access errors */ 5825f72a74SVipul Pandya SXGBE_STAT(fatal_bus_error_irq), 5925f72a74SVipul Pandya SXGBE_STAT(tx_read_transfer_err), 6025f72a74SVipul Pandya SXGBE_STAT(tx_write_transfer_err), 6125f72a74SVipul Pandya SXGBE_STAT(tx_desc_access_err), 6225f72a74SVipul Pandya SXGBE_STAT(tx_buffer_access_err), 6325f72a74SVipul Pandya SXGBE_STAT(tx_data_transfer_err), 6425f72a74SVipul Pandya SXGBE_STAT(rx_read_transfer_err), 6525f72a74SVipul Pandya SXGBE_STAT(rx_write_transfer_err), 6625f72a74SVipul Pandya SXGBE_STAT(rx_desc_access_err), 6725f72a74SVipul Pandya SXGBE_STAT(rx_buffer_access_err), 6825f72a74SVipul Pandya SXGBE_STAT(rx_data_transfer_err), 6925f72a74SVipul Pandya 7025f72a74SVipul Pandya /* EEE-LPI stats */ 71acc18c14SGirish K S SXGBE_STAT(tx_lpi_entry_n), 72acc18c14SGirish K S SXGBE_STAT(tx_lpi_exit_n), 73acc18c14SGirish K S SXGBE_STAT(rx_lpi_entry_n), 74acc18c14SGirish K S SXGBE_STAT(rx_lpi_exit_n), 75acc18c14SGirish K S SXGBE_STAT(eee_wakeup_error_n), 7625f72a74SVipul Pandya 7725f72a74SVipul Pandya /* RX specific */ 7825f72a74SVipul Pandya /* L2 error */ 7925f72a74SVipul Pandya SXGBE_STAT(rx_code_gmii_err), 8025f72a74SVipul Pandya SXGBE_STAT(rx_watchdog_err), 8125f72a74SVipul Pandya SXGBE_STAT(rx_crc_err), 8225f72a74SVipul Pandya SXGBE_STAT(rx_gaint_pkt_err), 8325f72a74SVipul Pandya SXGBE_STAT(ip_hdr_err), 8425f72a74SVipul Pandya SXGBE_STAT(ip_payload_err), 8525f72a74SVipul Pandya SXGBE_STAT(overflow_error), 8625f72a74SVipul Pandya 8725f72a74SVipul Pandya /* L2 Pkt type */ 8825f72a74SVipul Pandya SXGBE_STAT(len_pkt), 8925f72a74SVipul Pandya SXGBE_STAT(mac_ctl_pkt), 9025f72a74SVipul Pandya SXGBE_STAT(dcb_ctl_pkt), 9125f72a74SVipul Pandya SXGBE_STAT(arp_pkt), 9225f72a74SVipul Pandya SXGBE_STAT(oam_pkt), 9325f72a74SVipul Pandya SXGBE_STAT(untag_okt), 9425f72a74SVipul Pandya SXGBE_STAT(other_pkt), 9525f72a74SVipul Pandya SXGBE_STAT(svlan_tag_pkt), 9625f72a74SVipul Pandya SXGBE_STAT(cvlan_tag_pkt), 9725f72a74SVipul Pandya SXGBE_STAT(dvlan_ocvlan_icvlan_pkt), 9825f72a74SVipul Pandya SXGBE_STAT(dvlan_osvlan_isvlan_pkt), 9925f72a74SVipul Pandya SXGBE_STAT(dvlan_osvlan_icvlan_pkt), 10025f72a74SVipul Pandya SXGBE_STAT(dvan_ocvlan_icvlan_pkt), 10125f72a74SVipul Pandya 10225f72a74SVipul Pandya /* L3/L4 Pkt type */ 10325f72a74SVipul Pandya SXGBE_STAT(not_ip_pkt), 10425f72a74SVipul Pandya SXGBE_STAT(ip4_tcp_pkt), 10525f72a74SVipul Pandya SXGBE_STAT(ip4_udp_pkt), 10625f72a74SVipul Pandya SXGBE_STAT(ip4_icmp_pkt), 10725f72a74SVipul Pandya SXGBE_STAT(ip4_unknown_pkt), 10825f72a74SVipul Pandya SXGBE_STAT(ip6_tcp_pkt), 10925f72a74SVipul Pandya SXGBE_STAT(ip6_udp_pkt), 11025f72a74SVipul Pandya SXGBE_STAT(ip6_icmp_pkt), 11125f72a74SVipul Pandya SXGBE_STAT(ip6_unknown_pkt), 11225f72a74SVipul Pandya 11325f72a74SVipul Pandya /* Filter specific */ 11425f72a74SVipul Pandya SXGBE_STAT(vlan_filter_match), 11525f72a74SVipul Pandya SXGBE_STAT(sa_filter_fail), 11625f72a74SVipul Pandya SXGBE_STAT(da_filter_fail), 11725f72a74SVipul Pandya SXGBE_STAT(hash_filter_pass), 11825f72a74SVipul Pandya SXGBE_STAT(l3_filter_match), 11925f72a74SVipul Pandya SXGBE_STAT(l4_filter_match), 12025f72a74SVipul Pandya 12125f72a74SVipul Pandya /* RX context specific */ 12225f72a74SVipul Pandya SXGBE_STAT(timestamp_dropped), 12325f72a74SVipul Pandya SXGBE_STAT(rx_msg_type_no_ptp), 12425f72a74SVipul Pandya SXGBE_STAT(rx_ptp_type_sync), 12525f72a74SVipul Pandya SXGBE_STAT(rx_ptp_type_follow_up), 12625f72a74SVipul Pandya SXGBE_STAT(rx_ptp_type_delay_req), 12725f72a74SVipul Pandya SXGBE_STAT(rx_ptp_type_delay_resp), 12825f72a74SVipul Pandya SXGBE_STAT(rx_ptp_type_pdelay_req), 12925f72a74SVipul Pandya SXGBE_STAT(rx_ptp_type_pdelay_resp), 13025f72a74SVipul Pandya SXGBE_STAT(rx_ptp_type_pdelay_follow_up), 13125f72a74SVipul Pandya SXGBE_STAT(rx_ptp_announce), 13225f72a74SVipul Pandya SXGBE_STAT(rx_ptp_mgmt), 13325f72a74SVipul Pandya SXGBE_STAT(rx_ptp_signal), 13425f72a74SVipul Pandya SXGBE_STAT(rx_ptp_resv_msg_type), 1351edb9ca6SSiva Reddy }; 1361edb9ca6SSiva Reddy #define SXGBE_STATS_LEN ARRAY_SIZE(sxgbe_gstrings_stats) 1371edb9ca6SSiva Reddy 138acc18c14SGirish K S static int sxgbe_get_eee(struct net_device *dev, 139acc18c14SGirish K S struct ethtool_eee *edata) 140acc18c14SGirish K S { 141acc18c14SGirish K S struct sxgbe_priv_data *priv = netdev_priv(dev); 142acc18c14SGirish K S 143acc18c14SGirish K S if (!priv->hw_cap.eee) 144acc18c14SGirish K S return -EOPNOTSUPP; 145acc18c14SGirish K S 146acc18c14SGirish K S edata->eee_enabled = priv->eee_enabled; 147acc18c14SGirish K S edata->eee_active = priv->eee_active; 148acc18c14SGirish K S edata->tx_lpi_timer = priv->tx_lpi_timer; 149acc18c14SGirish K S 1502ebc440aSPhilippe Reynes return phy_ethtool_get_eee(dev->phydev, edata); 151acc18c14SGirish K S } 152acc18c14SGirish K S 153acc18c14SGirish K S static int sxgbe_set_eee(struct net_device *dev, 154acc18c14SGirish K S struct ethtool_eee *edata) 155acc18c14SGirish K S { 156acc18c14SGirish K S struct sxgbe_priv_data *priv = netdev_priv(dev); 157acc18c14SGirish K S 158acc18c14SGirish K S priv->eee_enabled = edata->eee_enabled; 159acc18c14SGirish K S 160acc18c14SGirish K S if (!priv->eee_enabled) { 161acc18c14SGirish K S sxgbe_disable_eee_mode(priv); 162acc18c14SGirish K S } else { 163acc18c14SGirish K S /* We are asking for enabling the EEE but it is safe 164acc18c14SGirish K S * to verify all by invoking the eee_init function. 165acc18c14SGirish K S * In case of failure it will return an error. 166acc18c14SGirish K S */ 167acc18c14SGirish K S priv->eee_enabled = sxgbe_eee_init(priv); 168acc18c14SGirish K S if (!priv->eee_enabled) 169acc18c14SGirish K S return -EOPNOTSUPP; 170acc18c14SGirish K S 171acc18c14SGirish K S /* Do not change tx_lpi_timer in case of failure */ 172acc18c14SGirish K S priv->tx_lpi_timer = edata->tx_lpi_timer; 173acc18c14SGirish K S } 174acc18c14SGirish K S 1752ebc440aSPhilippe Reynes return phy_ethtool_set_eee(dev->phydev, edata); 176acc18c14SGirish K S } 177acc18c14SGirish K S 17825f72a74SVipul Pandya static void sxgbe_getdrvinfo(struct net_device *dev, 17925f72a74SVipul Pandya struct ethtool_drvinfo *info) 18025f72a74SVipul Pandya { 18125f72a74SVipul Pandya strlcpy(info->driver, KBUILD_MODNAME, sizeof(info->driver)); 18225f72a74SVipul Pandya strlcpy(info->version, DRV_VERSION, sizeof(info->version)); 18325f72a74SVipul Pandya } 18425f72a74SVipul Pandya 18525f72a74SVipul Pandya static u32 sxgbe_getmsglevel(struct net_device *dev) 18625f72a74SVipul Pandya { 18725f72a74SVipul Pandya struct sxgbe_priv_data *priv = netdev_priv(dev); 18825f72a74SVipul Pandya return priv->msg_enable; 18925f72a74SVipul Pandya } 19025f72a74SVipul Pandya 19125f72a74SVipul Pandya static void sxgbe_setmsglevel(struct net_device *dev, u32 level) 19225f72a74SVipul Pandya { 19325f72a74SVipul Pandya struct sxgbe_priv_data *priv = netdev_priv(dev); 19425f72a74SVipul Pandya priv->msg_enable = level; 19525f72a74SVipul Pandya } 19625f72a74SVipul Pandya 19725f72a74SVipul Pandya static void sxgbe_get_strings(struct net_device *dev, u32 stringset, u8 *data) 19825f72a74SVipul Pandya { 19925f72a74SVipul Pandya int i; 20025f72a74SVipul Pandya u8 *p = data; 20125f72a74SVipul Pandya 20225f72a74SVipul Pandya switch (stringset) { 20325f72a74SVipul Pandya case ETH_SS_STATS: 20425f72a74SVipul Pandya for (i = 0; i < SXGBE_STATS_LEN; i++) { 20525f72a74SVipul Pandya memcpy(p, sxgbe_gstrings_stats[i].stat_string, 20625f72a74SVipul Pandya ETH_GSTRING_LEN); 20725f72a74SVipul Pandya p += ETH_GSTRING_LEN; 20825f72a74SVipul Pandya } 20925f72a74SVipul Pandya break; 21025f72a74SVipul Pandya default: 21125f72a74SVipul Pandya WARN_ON(1); 21225f72a74SVipul Pandya break; 21325f72a74SVipul Pandya } 21425f72a74SVipul Pandya } 21525f72a74SVipul Pandya 21625f72a74SVipul Pandya static int sxgbe_get_sset_count(struct net_device *netdev, int sset) 21725f72a74SVipul Pandya { 21825f72a74SVipul Pandya int len; 21925f72a74SVipul Pandya 22025f72a74SVipul Pandya switch (sset) { 22125f72a74SVipul Pandya case ETH_SS_STATS: 22225f72a74SVipul Pandya len = SXGBE_STATS_LEN; 22325f72a74SVipul Pandya return len; 22425f72a74SVipul Pandya default: 22525f72a74SVipul Pandya return -EINVAL; 22625f72a74SVipul Pandya } 22725f72a74SVipul Pandya } 22825f72a74SVipul Pandya 22925f72a74SVipul Pandya static void sxgbe_get_ethtool_stats(struct net_device *dev, 23025f72a74SVipul Pandya struct ethtool_stats *dummy, u64 *data) 23125f72a74SVipul Pandya { 23225f72a74SVipul Pandya struct sxgbe_priv_data *priv = netdev_priv(dev); 23325f72a74SVipul Pandya int i; 23425f72a74SVipul Pandya char *p; 23525f72a74SVipul Pandya 23625f72a74SVipul Pandya if (priv->eee_enabled) { 2372ebc440aSPhilippe Reynes int val = phy_get_eee_err(dev->phydev); 23825f72a74SVipul Pandya 23925f72a74SVipul Pandya if (val) 24025f72a74SVipul Pandya priv->xstats.eee_wakeup_error_n = val; 24125f72a74SVipul Pandya } 24225f72a74SVipul Pandya 24325f72a74SVipul Pandya for (i = 0; i < SXGBE_STATS_LEN; i++) { 24425f72a74SVipul Pandya p = (char *)priv + sxgbe_gstrings_stats[i].stat_offset; 24525f72a74SVipul Pandya data[i] = (sxgbe_gstrings_stats[i].sizeof_stat == sizeof(u64)) 24625f72a74SVipul Pandya ? (*(u64 *)p) : (*(u32 *)p); 24725f72a74SVipul Pandya } 24825f72a74SVipul Pandya } 24925f72a74SVipul Pandya 25025f72a74SVipul Pandya static void sxgbe_get_channels(struct net_device *dev, 25125f72a74SVipul Pandya struct ethtool_channels *channel) 25225f72a74SVipul Pandya { 25325f72a74SVipul Pandya channel->max_rx = SXGBE_MAX_RX_CHANNELS; 25425f72a74SVipul Pandya channel->max_tx = SXGBE_MAX_TX_CHANNELS; 25525f72a74SVipul Pandya channel->rx_count = SXGBE_RX_QUEUES; 25625f72a74SVipul Pandya channel->tx_count = SXGBE_TX_QUEUES; 25725f72a74SVipul Pandya } 25825f72a74SVipul Pandya 25925f72a74SVipul Pandya static u32 sxgbe_riwt2usec(u32 riwt, struct sxgbe_priv_data *priv) 26025f72a74SVipul Pandya { 26125f72a74SVipul Pandya unsigned long clk = clk_get_rate(priv->sxgbe_clk); 26225f72a74SVipul Pandya 26325f72a74SVipul Pandya if (!clk) 26425f72a74SVipul Pandya return 0; 26525f72a74SVipul Pandya 26625f72a74SVipul Pandya return (riwt * 256) / (clk / 1000000); 26725f72a74SVipul Pandya } 26825f72a74SVipul Pandya 26925f72a74SVipul Pandya static u32 sxgbe_usec2riwt(u32 usec, struct sxgbe_priv_data *priv) 27025f72a74SVipul Pandya { 27125f72a74SVipul Pandya unsigned long clk = clk_get_rate(priv->sxgbe_clk); 27225f72a74SVipul Pandya 27325f72a74SVipul Pandya if (!clk) 27425f72a74SVipul Pandya return 0; 27525f72a74SVipul Pandya 27625f72a74SVipul Pandya return (usec * (clk / 1000000)) / 256; 27725f72a74SVipul Pandya } 27825f72a74SVipul Pandya 27925f72a74SVipul Pandya static int sxgbe_get_coalesce(struct net_device *dev, 28025f72a74SVipul Pandya struct ethtool_coalesce *ec) 28125f72a74SVipul Pandya { 28225f72a74SVipul Pandya struct sxgbe_priv_data *priv = netdev_priv(dev); 28325f72a74SVipul Pandya 28425f72a74SVipul Pandya if (priv->use_riwt) 28525f72a74SVipul Pandya ec->rx_coalesce_usecs = sxgbe_riwt2usec(priv->rx_riwt, priv); 28625f72a74SVipul Pandya 28725f72a74SVipul Pandya return 0; 28825f72a74SVipul Pandya } 28925f72a74SVipul Pandya 29025f72a74SVipul Pandya static int sxgbe_set_coalesce(struct net_device *dev, 29125f72a74SVipul Pandya struct ethtool_coalesce *ec) 29225f72a74SVipul Pandya { 29325f72a74SVipul Pandya struct sxgbe_priv_data *priv = netdev_priv(dev); 29425f72a74SVipul Pandya unsigned int rx_riwt; 29525f72a74SVipul Pandya 29625f72a74SVipul Pandya if (!ec->rx_coalesce_usecs) 29725f72a74SVipul Pandya return -EINVAL; 29825f72a74SVipul Pandya 29925f72a74SVipul Pandya rx_riwt = sxgbe_usec2riwt(ec->rx_coalesce_usecs, priv); 30025f72a74SVipul Pandya 30125f72a74SVipul Pandya if ((rx_riwt > SXGBE_MAX_DMA_RIWT) || (rx_riwt < SXGBE_MIN_DMA_RIWT)) 30225f72a74SVipul Pandya return -EINVAL; 30325f72a74SVipul Pandya else if (!priv->use_riwt) 30425f72a74SVipul Pandya return -EOPNOTSUPP; 30525f72a74SVipul Pandya 30625f72a74SVipul Pandya priv->rx_riwt = rx_riwt; 30725f72a74SVipul Pandya priv->hw->dma->rx_watchdog(priv->ioaddr, priv->rx_riwt); 30825f72a74SVipul Pandya 30925f72a74SVipul Pandya return 0; 31025f72a74SVipul Pandya } 31125f72a74SVipul Pandya 31225f72a74SVipul Pandya static int sxgbe_get_rss_hash_opts(struct sxgbe_priv_data *priv, 31325f72a74SVipul Pandya struct ethtool_rxnfc *cmd) 31425f72a74SVipul Pandya { 31525f72a74SVipul Pandya cmd->data = 0; 31625f72a74SVipul Pandya 31725f72a74SVipul Pandya /* Report default options for RSS on sxgbe */ 31825f72a74SVipul Pandya switch (cmd->flow_type) { 31925f72a74SVipul Pandya case TCP_V4_FLOW: 32025f72a74SVipul Pandya case UDP_V4_FLOW: 32125f72a74SVipul Pandya cmd->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3; 32225f72a74SVipul Pandya case SCTP_V4_FLOW: 32325f72a74SVipul Pandya case AH_ESP_V4_FLOW: 32425f72a74SVipul Pandya case AH_V4_FLOW: 32525f72a74SVipul Pandya case ESP_V4_FLOW: 32625f72a74SVipul Pandya case IPV4_FLOW: 32725f72a74SVipul Pandya cmd->data |= RXH_IP_SRC | RXH_IP_DST; 32825f72a74SVipul Pandya break; 32925f72a74SVipul Pandya case TCP_V6_FLOW: 33025f72a74SVipul Pandya case UDP_V6_FLOW: 33125f72a74SVipul Pandya cmd->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3; 33225f72a74SVipul Pandya case SCTP_V6_FLOW: 33325f72a74SVipul Pandya case AH_ESP_V6_FLOW: 33425f72a74SVipul Pandya case AH_V6_FLOW: 33525f72a74SVipul Pandya case ESP_V6_FLOW: 33625f72a74SVipul Pandya case IPV6_FLOW: 33725f72a74SVipul Pandya cmd->data |= RXH_IP_SRC | RXH_IP_DST; 33825f72a74SVipul Pandya break; 33925f72a74SVipul Pandya default: 34025f72a74SVipul Pandya return -EINVAL; 34125f72a74SVipul Pandya } 34225f72a74SVipul Pandya 34325f72a74SVipul Pandya return 0; 34425f72a74SVipul Pandya } 34525f72a74SVipul Pandya 34625f72a74SVipul Pandya static int sxgbe_get_rxnfc(struct net_device *dev, struct ethtool_rxnfc *cmd, 34725f72a74SVipul Pandya u32 *rule_locs) 34825f72a74SVipul Pandya { 34925f72a74SVipul Pandya struct sxgbe_priv_data *priv = netdev_priv(dev); 35025f72a74SVipul Pandya int ret = -EOPNOTSUPP; 35125f72a74SVipul Pandya 35225f72a74SVipul Pandya switch (cmd->cmd) { 35325f72a74SVipul Pandya case ETHTOOL_GRXFH: 35425f72a74SVipul Pandya ret = sxgbe_get_rss_hash_opts(priv, cmd); 35525f72a74SVipul Pandya break; 35625f72a74SVipul Pandya default: 35725f72a74SVipul Pandya break; 35825f72a74SVipul Pandya } 35925f72a74SVipul Pandya 36025f72a74SVipul Pandya return ret; 36125f72a74SVipul Pandya } 36225f72a74SVipul Pandya 36325f72a74SVipul Pandya static int sxgbe_set_rss_hash_opt(struct sxgbe_priv_data *priv, 36425f72a74SVipul Pandya struct ethtool_rxnfc *cmd) 36525f72a74SVipul Pandya { 36625f72a74SVipul Pandya u32 reg_val = 0; 36725f72a74SVipul Pandya 36825f72a74SVipul Pandya /* RSS does not support anything other than hashing 36925f72a74SVipul Pandya * to queues on src and dst IPs and ports 37025f72a74SVipul Pandya */ 37125f72a74SVipul Pandya if (cmd->data & ~(RXH_IP_SRC | RXH_IP_DST | 37225f72a74SVipul Pandya RXH_L4_B_0_1 | RXH_L4_B_2_3)) 37325f72a74SVipul Pandya return -EINVAL; 37425f72a74SVipul Pandya 37525f72a74SVipul Pandya switch (cmd->flow_type) { 37625f72a74SVipul Pandya case TCP_V4_FLOW: 37725f72a74SVipul Pandya case TCP_V6_FLOW: 37825f72a74SVipul Pandya if (!(cmd->data & RXH_IP_SRC) || 37925f72a74SVipul Pandya !(cmd->data & RXH_IP_DST) || 38025f72a74SVipul Pandya !(cmd->data & RXH_L4_B_0_1) || 38125f72a74SVipul Pandya !(cmd->data & RXH_L4_B_2_3)) 38225f72a74SVipul Pandya return -EINVAL; 38325f72a74SVipul Pandya reg_val = SXGBE_CORE_RSS_CTL_TCP4TE; 38425f72a74SVipul Pandya break; 38525f72a74SVipul Pandya case UDP_V4_FLOW: 38625f72a74SVipul Pandya case UDP_V6_FLOW: 38725f72a74SVipul Pandya if (!(cmd->data & RXH_IP_SRC) || 38825f72a74SVipul Pandya !(cmd->data & RXH_IP_DST) || 38925f72a74SVipul Pandya !(cmd->data & RXH_L4_B_0_1) || 39025f72a74SVipul Pandya !(cmd->data & RXH_L4_B_2_3)) 39125f72a74SVipul Pandya return -EINVAL; 39225f72a74SVipul Pandya reg_val = SXGBE_CORE_RSS_CTL_UDP4TE; 39325f72a74SVipul Pandya break; 39425f72a74SVipul Pandya case SCTP_V4_FLOW: 39525f72a74SVipul Pandya case AH_ESP_V4_FLOW: 39625f72a74SVipul Pandya case AH_V4_FLOW: 39725f72a74SVipul Pandya case ESP_V4_FLOW: 39825f72a74SVipul Pandya case AH_ESP_V6_FLOW: 39925f72a74SVipul Pandya case AH_V6_FLOW: 40025f72a74SVipul Pandya case ESP_V6_FLOW: 40125f72a74SVipul Pandya case SCTP_V6_FLOW: 40225f72a74SVipul Pandya case IPV4_FLOW: 40325f72a74SVipul Pandya case IPV6_FLOW: 40425f72a74SVipul Pandya if (!(cmd->data & RXH_IP_SRC) || 40525f72a74SVipul Pandya !(cmd->data & RXH_IP_DST) || 40625f72a74SVipul Pandya (cmd->data & RXH_L4_B_0_1) || 40725f72a74SVipul Pandya (cmd->data & RXH_L4_B_2_3)) 40825f72a74SVipul Pandya return -EINVAL; 40925f72a74SVipul Pandya reg_val = SXGBE_CORE_RSS_CTL_IP2TE; 41025f72a74SVipul Pandya break; 41125f72a74SVipul Pandya default: 41225f72a74SVipul Pandya return -EINVAL; 41325f72a74SVipul Pandya } 41425f72a74SVipul Pandya 41525f72a74SVipul Pandya /* Read SXGBE RSS control register and update */ 41625f72a74SVipul Pandya reg_val |= readl(priv->ioaddr + SXGBE_CORE_RSS_CTL_REG); 41725f72a74SVipul Pandya writel(reg_val, priv->ioaddr + SXGBE_CORE_RSS_CTL_REG); 41825f72a74SVipul Pandya readl(priv->ioaddr + SXGBE_CORE_RSS_CTL_REG); 41925f72a74SVipul Pandya 42025f72a74SVipul Pandya return 0; 42125f72a74SVipul Pandya } 42225f72a74SVipul Pandya 42325f72a74SVipul Pandya static int sxgbe_set_rxnfc(struct net_device *dev, struct ethtool_rxnfc *cmd) 42425f72a74SVipul Pandya { 42525f72a74SVipul Pandya struct sxgbe_priv_data *priv = netdev_priv(dev); 42625f72a74SVipul Pandya int ret = -EOPNOTSUPP; 42725f72a74SVipul Pandya 42825f72a74SVipul Pandya switch (cmd->cmd) { 42925f72a74SVipul Pandya case ETHTOOL_SRXFH: 43025f72a74SVipul Pandya ret = sxgbe_set_rss_hash_opt(priv, cmd); 43125f72a74SVipul Pandya break; 43225f72a74SVipul Pandya default: 43325f72a74SVipul Pandya break; 43425f72a74SVipul Pandya } 43525f72a74SVipul Pandya 43625f72a74SVipul Pandya return ret; 43725f72a74SVipul Pandya } 43825f72a74SVipul Pandya 43925f72a74SVipul Pandya static void sxgbe_get_regs(struct net_device *dev, 44025f72a74SVipul Pandya struct ethtool_regs *regs, void *space) 44125f72a74SVipul Pandya { 44225f72a74SVipul Pandya struct sxgbe_priv_data *priv = netdev_priv(dev); 44325f72a74SVipul Pandya u32 *reg_space = (u32 *)space; 44425f72a74SVipul Pandya int reg_offset; 44525f72a74SVipul Pandya int reg_ix = 0; 44625f72a74SVipul Pandya void __iomem *ioaddr = priv->ioaddr; 44725f72a74SVipul Pandya 44825f72a74SVipul Pandya memset(reg_space, 0x0, REG_SPACE_SIZE); 44925f72a74SVipul Pandya 45025f72a74SVipul Pandya /* MAC registers */ 45125f72a74SVipul Pandya for (reg_offset = START_MAC_REG_OFFSET; 45225f72a74SVipul Pandya reg_offset <= MAX_MAC_REG_OFFSET; reg_offset += 4) { 45325f72a74SVipul Pandya reg_space[reg_ix] = readl(ioaddr + reg_offset); 45425f72a74SVipul Pandya reg_ix++; 45525f72a74SVipul Pandya } 45625f72a74SVipul Pandya 45725f72a74SVipul Pandya /* MTL registers */ 45825f72a74SVipul Pandya for (reg_offset = START_MTL_REG_OFFSET; 45925f72a74SVipul Pandya reg_offset <= MAX_MTL_REG_OFFSET; reg_offset += 4) { 46025f72a74SVipul Pandya reg_space[reg_ix] = readl(ioaddr + reg_offset); 46125f72a74SVipul Pandya reg_ix++; 46225f72a74SVipul Pandya } 46325f72a74SVipul Pandya 46425f72a74SVipul Pandya /* DMA registers */ 46525f72a74SVipul Pandya for (reg_offset = START_DMA_REG_OFFSET; 46625f72a74SVipul Pandya reg_offset <= MAX_DMA_REG_OFFSET; reg_offset += 4) { 46725f72a74SVipul Pandya reg_space[reg_ix] = readl(ioaddr + reg_offset); 46825f72a74SVipul Pandya reg_ix++; 46925f72a74SVipul Pandya } 47025f72a74SVipul Pandya 47125f72a74SVipul Pandya BUG_ON(reg_ix * 4 > REG_SPACE_SIZE); 47225f72a74SVipul Pandya } 47325f72a74SVipul Pandya 47425f72a74SVipul Pandya static int sxgbe_get_regs_len(struct net_device *dev) 47525f72a74SVipul Pandya { 47625f72a74SVipul Pandya return REG_SPACE_SIZE; 47725f72a74SVipul Pandya } 47825f72a74SVipul Pandya 4791edb9ca6SSiva Reddy static const struct ethtool_ops sxgbe_ethtool_ops = { 48025f72a74SVipul Pandya .get_drvinfo = sxgbe_getdrvinfo, 48125f72a74SVipul Pandya .get_msglevel = sxgbe_getmsglevel, 48225f72a74SVipul Pandya .set_msglevel = sxgbe_setmsglevel, 48325f72a74SVipul Pandya .get_link = ethtool_op_get_link, 48425f72a74SVipul Pandya .get_strings = sxgbe_get_strings, 48525f72a74SVipul Pandya .get_ethtool_stats = sxgbe_get_ethtool_stats, 48625f72a74SVipul Pandya .get_sset_count = sxgbe_get_sset_count, 48725f72a74SVipul Pandya .get_channels = sxgbe_get_channels, 48825f72a74SVipul Pandya .get_coalesce = sxgbe_get_coalesce, 48925f72a74SVipul Pandya .set_coalesce = sxgbe_set_coalesce, 49025f72a74SVipul Pandya .get_rxnfc = sxgbe_get_rxnfc, 49125f72a74SVipul Pandya .set_rxnfc = sxgbe_set_rxnfc, 49225f72a74SVipul Pandya .get_regs = sxgbe_get_regs, 49325f72a74SVipul Pandya .get_regs_len = sxgbe_get_regs_len, 494acc18c14SGirish K S .get_eee = sxgbe_get_eee, 495acc18c14SGirish K S .set_eee = sxgbe_set_eee, 496*13e4c230SPhilippe Reynes .get_link_ksettings = phy_ethtool_get_link_ksettings, 497*13e4c230SPhilippe Reynes .set_link_ksettings = phy_ethtool_set_link_ksettings, 4981edb9ca6SSiva Reddy }; 4991edb9ca6SSiva Reddy 5001edb9ca6SSiva Reddy void sxgbe_set_ethtool_ops(struct net_device *netdev) 5011edb9ca6SSiva Reddy { 5027ad24ea4SWilfried Klaebe netdev->ethtool_ops = &sxgbe_ethtool_ops; 5031edb9ca6SSiva Reddy } 504