18c2ecf20Sopenharmony_ci/* Copyright 2008-2016 Freescale Semiconductor, Inc. 28c2ecf20Sopenharmony_ci * 38c2ecf20Sopenharmony_ci * Redistribution and use in source and binary forms, with or without 48c2ecf20Sopenharmony_ci * modification, are permitted provided that the following conditions are met: 58c2ecf20Sopenharmony_ci * * Redistributions of source code must retain the above copyright 68c2ecf20Sopenharmony_ci * notice, this list of conditions and the following disclaimer. 78c2ecf20Sopenharmony_ci * * Redistributions in binary form must reproduce the above copyright 88c2ecf20Sopenharmony_ci * notice, this list of conditions and the following disclaimer in the 98c2ecf20Sopenharmony_ci * documentation and/or other materials provided with the distribution. 108c2ecf20Sopenharmony_ci * * Neither the name of Freescale Semiconductor nor the 118c2ecf20Sopenharmony_ci * names of its contributors may be used to endorse or promote products 128c2ecf20Sopenharmony_ci * derived from this software without specific prior written permission. 138c2ecf20Sopenharmony_ci * 148c2ecf20Sopenharmony_ci * 158c2ecf20Sopenharmony_ci * ALTERNATIVELY, this software may be distributed under the terms of the 168c2ecf20Sopenharmony_ci * GNU General Public License ("GPL") as published by the Free Software 178c2ecf20Sopenharmony_ci * Foundation, either version 2 of that License or (at your option) any 188c2ecf20Sopenharmony_ci * later version. 198c2ecf20Sopenharmony_ci * 208c2ecf20Sopenharmony_ci * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY 218c2ecf20Sopenharmony_ci * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 228c2ecf20Sopenharmony_ci * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 238c2ecf20Sopenharmony_ci * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY 248c2ecf20Sopenharmony_ci * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 258c2ecf20Sopenharmony_ci * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 268c2ecf20Sopenharmony_ci * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 278c2ecf20Sopenharmony_ci * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 288c2ecf20Sopenharmony_ci * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 298c2ecf20Sopenharmony_ci * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 308c2ecf20Sopenharmony_ci */ 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_ci#include <linux/string.h> 358c2ecf20Sopenharmony_ci#include <linux/of_platform.h> 368c2ecf20Sopenharmony_ci#include <linux/net_tstamp.h> 378c2ecf20Sopenharmony_ci#include <linux/fsl/ptp_qoriq.h> 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_ci#include "dpaa_eth.h" 408c2ecf20Sopenharmony_ci#include "mac.h" 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_cistatic const char dpaa_stats_percpu[][ETH_GSTRING_LEN] = { 438c2ecf20Sopenharmony_ci "interrupts", 448c2ecf20Sopenharmony_ci "rx packets", 458c2ecf20Sopenharmony_ci "tx packets", 468c2ecf20Sopenharmony_ci "tx confirm", 478c2ecf20Sopenharmony_ci "tx S/G", 488c2ecf20Sopenharmony_ci "tx error", 498c2ecf20Sopenharmony_ci "rx error", 508c2ecf20Sopenharmony_ci "rx dropped", 518c2ecf20Sopenharmony_ci "tx dropped", 528c2ecf20Sopenharmony_ci}; 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_cistatic char dpaa_stats_global[][ETH_GSTRING_LEN] = { 558c2ecf20Sopenharmony_ci /* dpa rx errors */ 568c2ecf20Sopenharmony_ci "rx dma error", 578c2ecf20Sopenharmony_ci "rx frame physical error", 588c2ecf20Sopenharmony_ci "rx frame size error", 598c2ecf20Sopenharmony_ci "rx header error", 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_ci /* demultiplexing errors */ 628c2ecf20Sopenharmony_ci "qman cg_tdrop", 638c2ecf20Sopenharmony_ci "qman wred", 648c2ecf20Sopenharmony_ci "qman error cond", 658c2ecf20Sopenharmony_ci "qman early window", 668c2ecf20Sopenharmony_ci "qman late window", 678c2ecf20Sopenharmony_ci "qman fq tdrop", 688c2ecf20Sopenharmony_ci "qman fq retired", 698c2ecf20Sopenharmony_ci "qman orp disabled", 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_ci /* congestion related stats */ 728c2ecf20Sopenharmony_ci "congestion time (ms)", 738c2ecf20Sopenharmony_ci "entered congestion", 748c2ecf20Sopenharmony_ci "congested (0/1)" 758c2ecf20Sopenharmony_ci}; 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_ci#define DPAA_STATS_PERCPU_LEN ARRAY_SIZE(dpaa_stats_percpu) 788c2ecf20Sopenharmony_ci#define DPAA_STATS_GLOBAL_LEN ARRAY_SIZE(dpaa_stats_global) 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_cistatic int dpaa_get_link_ksettings(struct net_device *net_dev, 818c2ecf20Sopenharmony_ci struct ethtool_link_ksettings *cmd) 828c2ecf20Sopenharmony_ci{ 838c2ecf20Sopenharmony_ci if (!net_dev->phydev) 848c2ecf20Sopenharmony_ci return 0; 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_ci phy_ethtool_ksettings_get(net_dev->phydev, cmd); 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_ci return 0; 898c2ecf20Sopenharmony_ci} 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_cistatic int dpaa_set_link_ksettings(struct net_device *net_dev, 928c2ecf20Sopenharmony_ci const struct ethtool_link_ksettings *cmd) 938c2ecf20Sopenharmony_ci{ 948c2ecf20Sopenharmony_ci int err; 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_ci if (!net_dev->phydev) 978c2ecf20Sopenharmony_ci return -ENODEV; 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_ci err = phy_ethtool_ksettings_set(net_dev->phydev, cmd); 1008c2ecf20Sopenharmony_ci if (err < 0) 1018c2ecf20Sopenharmony_ci netdev_err(net_dev, "phy_ethtool_ksettings_set() = %d\n", err); 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_ci return err; 1048c2ecf20Sopenharmony_ci} 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_cistatic void dpaa_get_drvinfo(struct net_device *net_dev, 1078c2ecf20Sopenharmony_ci struct ethtool_drvinfo *drvinfo) 1088c2ecf20Sopenharmony_ci{ 1098c2ecf20Sopenharmony_ci strlcpy(drvinfo->driver, KBUILD_MODNAME, 1108c2ecf20Sopenharmony_ci sizeof(drvinfo->driver)); 1118c2ecf20Sopenharmony_ci strlcpy(drvinfo->bus_info, dev_name(net_dev->dev.parent->parent), 1128c2ecf20Sopenharmony_ci sizeof(drvinfo->bus_info)); 1138c2ecf20Sopenharmony_ci} 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_cistatic u32 dpaa_get_msglevel(struct net_device *net_dev) 1168c2ecf20Sopenharmony_ci{ 1178c2ecf20Sopenharmony_ci return ((struct dpaa_priv *)netdev_priv(net_dev))->msg_enable; 1188c2ecf20Sopenharmony_ci} 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_cistatic void dpaa_set_msglevel(struct net_device *net_dev, 1218c2ecf20Sopenharmony_ci u32 msg_enable) 1228c2ecf20Sopenharmony_ci{ 1238c2ecf20Sopenharmony_ci ((struct dpaa_priv *)netdev_priv(net_dev))->msg_enable = msg_enable; 1248c2ecf20Sopenharmony_ci} 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_cistatic int dpaa_nway_reset(struct net_device *net_dev) 1278c2ecf20Sopenharmony_ci{ 1288c2ecf20Sopenharmony_ci int err; 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_ci if (!net_dev->phydev) 1318c2ecf20Sopenharmony_ci return -ENODEV; 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_ci err = 0; 1348c2ecf20Sopenharmony_ci if (net_dev->phydev->autoneg) { 1358c2ecf20Sopenharmony_ci err = phy_start_aneg(net_dev->phydev); 1368c2ecf20Sopenharmony_ci if (err < 0) 1378c2ecf20Sopenharmony_ci netdev_err(net_dev, "phy_start_aneg() = %d\n", 1388c2ecf20Sopenharmony_ci err); 1398c2ecf20Sopenharmony_ci } 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_ci return err; 1428c2ecf20Sopenharmony_ci} 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_cistatic void dpaa_get_pauseparam(struct net_device *net_dev, 1458c2ecf20Sopenharmony_ci struct ethtool_pauseparam *epause) 1468c2ecf20Sopenharmony_ci{ 1478c2ecf20Sopenharmony_ci struct mac_device *mac_dev; 1488c2ecf20Sopenharmony_ci struct dpaa_priv *priv; 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_ci priv = netdev_priv(net_dev); 1518c2ecf20Sopenharmony_ci mac_dev = priv->mac_dev; 1528c2ecf20Sopenharmony_ci 1538c2ecf20Sopenharmony_ci if (!net_dev->phydev) 1548c2ecf20Sopenharmony_ci return; 1558c2ecf20Sopenharmony_ci 1568c2ecf20Sopenharmony_ci epause->autoneg = mac_dev->autoneg_pause; 1578c2ecf20Sopenharmony_ci epause->rx_pause = mac_dev->rx_pause_active; 1588c2ecf20Sopenharmony_ci epause->tx_pause = mac_dev->tx_pause_active; 1598c2ecf20Sopenharmony_ci} 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_cistatic int dpaa_set_pauseparam(struct net_device *net_dev, 1628c2ecf20Sopenharmony_ci struct ethtool_pauseparam *epause) 1638c2ecf20Sopenharmony_ci{ 1648c2ecf20Sopenharmony_ci struct mac_device *mac_dev; 1658c2ecf20Sopenharmony_ci struct phy_device *phydev; 1668c2ecf20Sopenharmony_ci bool rx_pause, tx_pause; 1678c2ecf20Sopenharmony_ci struct dpaa_priv *priv; 1688c2ecf20Sopenharmony_ci int err; 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_ci priv = netdev_priv(net_dev); 1718c2ecf20Sopenharmony_ci mac_dev = priv->mac_dev; 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_ci phydev = net_dev->phydev; 1748c2ecf20Sopenharmony_ci if (!phydev) { 1758c2ecf20Sopenharmony_ci netdev_err(net_dev, "phy device not initialized\n"); 1768c2ecf20Sopenharmony_ci return -ENODEV; 1778c2ecf20Sopenharmony_ci } 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_ci if (!phy_validate_pause(phydev, epause)) 1808c2ecf20Sopenharmony_ci return -EINVAL; 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_ci /* The MAC should know how to handle PAUSE frame autonegotiation before 1838c2ecf20Sopenharmony_ci * adjust_link is triggered by a forced renegotiation of sym/asym PAUSE 1848c2ecf20Sopenharmony_ci * settings. 1858c2ecf20Sopenharmony_ci */ 1868c2ecf20Sopenharmony_ci mac_dev->autoneg_pause = !!epause->autoneg; 1878c2ecf20Sopenharmony_ci mac_dev->rx_pause_req = !!epause->rx_pause; 1888c2ecf20Sopenharmony_ci mac_dev->tx_pause_req = !!epause->tx_pause; 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_ci /* Determine the sym/asym advertised PAUSE capabilities from the desired 1918c2ecf20Sopenharmony_ci * rx/tx pause settings. 1928c2ecf20Sopenharmony_ci */ 1938c2ecf20Sopenharmony_ci 1948c2ecf20Sopenharmony_ci phy_set_asym_pause(phydev, epause->rx_pause, epause->tx_pause); 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_ci fman_get_pause_cfg(mac_dev, &rx_pause, &tx_pause); 1978c2ecf20Sopenharmony_ci err = fman_set_mac_active_pause(mac_dev, rx_pause, tx_pause); 1988c2ecf20Sopenharmony_ci if (err < 0) 1998c2ecf20Sopenharmony_ci netdev_err(net_dev, "set_mac_active_pause() = %d\n", err); 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_ci return err; 2028c2ecf20Sopenharmony_ci} 2038c2ecf20Sopenharmony_ci 2048c2ecf20Sopenharmony_cistatic int dpaa_get_sset_count(struct net_device *net_dev, int type) 2058c2ecf20Sopenharmony_ci{ 2068c2ecf20Sopenharmony_ci unsigned int total_stats, num_stats; 2078c2ecf20Sopenharmony_ci 2088c2ecf20Sopenharmony_ci num_stats = num_online_cpus() + 1; 2098c2ecf20Sopenharmony_ci total_stats = num_stats * (DPAA_STATS_PERCPU_LEN + 1) + 2108c2ecf20Sopenharmony_ci DPAA_STATS_GLOBAL_LEN; 2118c2ecf20Sopenharmony_ci 2128c2ecf20Sopenharmony_ci switch (type) { 2138c2ecf20Sopenharmony_ci case ETH_SS_STATS: 2148c2ecf20Sopenharmony_ci return total_stats; 2158c2ecf20Sopenharmony_ci default: 2168c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 2178c2ecf20Sopenharmony_ci } 2188c2ecf20Sopenharmony_ci} 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_cistatic void copy_stats(struct dpaa_percpu_priv *percpu_priv, int num_cpus, 2218c2ecf20Sopenharmony_ci int crr_cpu, u64 bp_count, u64 *data) 2228c2ecf20Sopenharmony_ci{ 2238c2ecf20Sopenharmony_ci int num_values = num_cpus + 1; 2248c2ecf20Sopenharmony_ci int crr = 0; 2258c2ecf20Sopenharmony_ci 2268c2ecf20Sopenharmony_ci /* update current CPU's stats and also add them to the total values */ 2278c2ecf20Sopenharmony_ci data[crr * num_values + crr_cpu] = percpu_priv->in_interrupt; 2288c2ecf20Sopenharmony_ci data[crr++ * num_values + num_cpus] += percpu_priv->in_interrupt; 2298c2ecf20Sopenharmony_ci 2308c2ecf20Sopenharmony_ci data[crr * num_values + crr_cpu] = percpu_priv->stats.rx_packets; 2318c2ecf20Sopenharmony_ci data[crr++ * num_values + num_cpus] += percpu_priv->stats.rx_packets; 2328c2ecf20Sopenharmony_ci 2338c2ecf20Sopenharmony_ci data[crr * num_values + crr_cpu] = percpu_priv->stats.tx_packets; 2348c2ecf20Sopenharmony_ci data[crr++ * num_values + num_cpus] += percpu_priv->stats.tx_packets; 2358c2ecf20Sopenharmony_ci 2368c2ecf20Sopenharmony_ci data[crr * num_values + crr_cpu] = percpu_priv->tx_confirm; 2378c2ecf20Sopenharmony_ci data[crr++ * num_values + num_cpus] += percpu_priv->tx_confirm; 2388c2ecf20Sopenharmony_ci 2398c2ecf20Sopenharmony_ci data[crr * num_values + crr_cpu] = percpu_priv->tx_frag_skbuffs; 2408c2ecf20Sopenharmony_ci data[crr++ * num_values + num_cpus] += percpu_priv->tx_frag_skbuffs; 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_ci data[crr * num_values + crr_cpu] = percpu_priv->stats.tx_errors; 2438c2ecf20Sopenharmony_ci data[crr++ * num_values + num_cpus] += percpu_priv->stats.tx_errors; 2448c2ecf20Sopenharmony_ci 2458c2ecf20Sopenharmony_ci data[crr * num_values + crr_cpu] = percpu_priv->stats.rx_errors; 2468c2ecf20Sopenharmony_ci data[crr++ * num_values + num_cpus] += percpu_priv->stats.rx_errors; 2478c2ecf20Sopenharmony_ci 2488c2ecf20Sopenharmony_ci data[crr * num_values + crr_cpu] = percpu_priv->stats.rx_dropped; 2498c2ecf20Sopenharmony_ci data[crr++ * num_values + num_cpus] += percpu_priv->stats.rx_dropped; 2508c2ecf20Sopenharmony_ci 2518c2ecf20Sopenharmony_ci data[crr * num_values + crr_cpu] = percpu_priv->stats.tx_dropped; 2528c2ecf20Sopenharmony_ci data[crr++ * num_values + num_cpus] += percpu_priv->stats.tx_dropped; 2538c2ecf20Sopenharmony_ci 2548c2ecf20Sopenharmony_ci data[crr * num_values + crr_cpu] = bp_count; 2558c2ecf20Sopenharmony_ci data[crr++ * num_values + num_cpus] += bp_count; 2568c2ecf20Sopenharmony_ci} 2578c2ecf20Sopenharmony_ci 2588c2ecf20Sopenharmony_cistatic void dpaa_get_ethtool_stats(struct net_device *net_dev, 2598c2ecf20Sopenharmony_ci struct ethtool_stats *stats, u64 *data) 2608c2ecf20Sopenharmony_ci{ 2618c2ecf20Sopenharmony_ci struct dpaa_percpu_priv *percpu_priv; 2628c2ecf20Sopenharmony_ci struct dpaa_rx_errors rx_errors; 2638c2ecf20Sopenharmony_ci unsigned int num_cpus, offset; 2648c2ecf20Sopenharmony_ci u64 bp_count, cg_time, cg_num; 2658c2ecf20Sopenharmony_ci struct dpaa_ern_cnt ern_cnt; 2668c2ecf20Sopenharmony_ci struct dpaa_bp *dpaa_bp; 2678c2ecf20Sopenharmony_ci struct dpaa_priv *priv; 2688c2ecf20Sopenharmony_ci int total_stats, i; 2698c2ecf20Sopenharmony_ci bool cg_status; 2708c2ecf20Sopenharmony_ci 2718c2ecf20Sopenharmony_ci total_stats = dpaa_get_sset_count(net_dev, ETH_SS_STATS); 2728c2ecf20Sopenharmony_ci priv = netdev_priv(net_dev); 2738c2ecf20Sopenharmony_ci num_cpus = num_online_cpus(); 2748c2ecf20Sopenharmony_ci 2758c2ecf20Sopenharmony_ci memset(&bp_count, 0, sizeof(bp_count)); 2768c2ecf20Sopenharmony_ci memset(&rx_errors, 0, sizeof(struct dpaa_rx_errors)); 2778c2ecf20Sopenharmony_ci memset(&ern_cnt, 0, sizeof(struct dpaa_ern_cnt)); 2788c2ecf20Sopenharmony_ci memset(data, 0, total_stats * sizeof(u64)); 2798c2ecf20Sopenharmony_ci 2808c2ecf20Sopenharmony_ci for_each_online_cpu(i) { 2818c2ecf20Sopenharmony_ci percpu_priv = per_cpu_ptr(priv->percpu_priv, i); 2828c2ecf20Sopenharmony_ci dpaa_bp = priv->dpaa_bp; 2838c2ecf20Sopenharmony_ci if (!dpaa_bp->percpu_count) 2848c2ecf20Sopenharmony_ci continue; 2858c2ecf20Sopenharmony_ci bp_count = *(per_cpu_ptr(dpaa_bp->percpu_count, i)); 2868c2ecf20Sopenharmony_ci rx_errors.dme += percpu_priv->rx_errors.dme; 2878c2ecf20Sopenharmony_ci rx_errors.fpe += percpu_priv->rx_errors.fpe; 2888c2ecf20Sopenharmony_ci rx_errors.fse += percpu_priv->rx_errors.fse; 2898c2ecf20Sopenharmony_ci rx_errors.phe += percpu_priv->rx_errors.phe; 2908c2ecf20Sopenharmony_ci 2918c2ecf20Sopenharmony_ci ern_cnt.cg_tdrop += percpu_priv->ern_cnt.cg_tdrop; 2928c2ecf20Sopenharmony_ci ern_cnt.wred += percpu_priv->ern_cnt.wred; 2938c2ecf20Sopenharmony_ci ern_cnt.err_cond += percpu_priv->ern_cnt.err_cond; 2948c2ecf20Sopenharmony_ci ern_cnt.early_window += percpu_priv->ern_cnt.early_window; 2958c2ecf20Sopenharmony_ci ern_cnt.late_window += percpu_priv->ern_cnt.late_window; 2968c2ecf20Sopenharmony_ci ern_cnt.fq_tdrop += percpu_priv->ern_cnt.fq_tdrop; 2978c2ecf20Sopenharmony_ci ern_cnt.fq_retired += percpu_priv->ern_cnt.fq_retired; 2988c2ecf20Sopenharmony_ci ern_cnt.orp_zero += percpu_priv->ern_cnt.orp_zero; 2998c2ecf20Sopenharmony_ci 3008c2ecf20Sopenharmony_ci copy_stats(percpu_priv, num_cpus, i, bp_count, data); 3018c2ecf20Sopenharmony_ci } 3028c2ecf20Sopenharmony_ci 3038c2ecf20Sopenharmony_ci offset = (num_cpus + 1) * (DPAA_STATS_PERCPU_LEN + 1); 3048c2ecf20Sopenharmony_ci memcpy(data + offset, &rx_errors, sizeof(struct dpaa_rx_errors)); 3058c2ecf20Sopenharmony_ci 3068c2ecf20Sopenharmony_ci offset += sizeof(struct dpaa_rx_errors) / sizeof(u64); 3078c2ecf20Sopenharmony_ci memcpy(data + offset, &ern_cnt, sizeof(struct dpaa_ern_cnt)); 3088c2ecf20Sopenharmony_ci 3098c2ecf20Sopenharmony_ci /* gather congestion related counters */ 3108c2ecf20Sopenharmony_ci cg_num = 0; 3118c2ecf20Sopenharmony_ci cg_status = false; 3128c2ecf20Sopenharmony_ci cg_time = jiffies_to_msecs(priv->cgr_data.congested_jiffies); 3138c2ecf20Sopenharmony_ci if (qman_query_cgr_congested(&priv->cgr_data.cgr, &cg_status) == 0) { 3148c2ecf20Sopenharmony_ci cg_num = priv->cgr_data.cgr_congested_count; 3158c2ecf20Sopenharmony_ci 3168c2ecf20Sopenharmony_ci /* reset congestion stats (like QMan API does */ 3178c2ecf20Sopenharmony_ci priv->cgr_data.congested_jiffies = 0; 3188c2ecf20Sopenharmony_ci priv->cgr_data.cgr_congested_count = 0; 3198c2ecf20Sopenharmony_ci } 3208c2ecf20Sopenharmony_ci 3218c2ecf20Sopenharmony_ci offset += sizeof(struct dpaa_ern_cnt) / sizeof(u64); 3228c2ecf20Sopenharmony_ci data[offset++] = cg_time; 3238c2ecf20Sopenharmony_ci data[offset++] = cg_num; 3248c2ecf20Sopenharmony_ci data[offset++] = cg_status; 3258c2ecf20Sopenharmony_ci} 3268c2ecf20Sopenharmony_ci 3278c2ecf20Sopenharmony_cistatic void dpaa_get_strings(struct net_device *net_dev, u32 stringset, 3288c2ecf20Sopenharmony_ci u8 *data) 3298c2ecf20Sopenharmony_ci{ 3308c2ecf20Sopenharmony_ci unsigned int i, j, num_cpus, size; 3318c2ecf20Sopenharmony_ci char string_cpu[ETH_GSTRING_LEN]; 3328c2ecf20Sopenharmony_ci u8 *strings; 3338c2ecf20Sopenharmony_ci 3348c2ecf20Sopenharmony_ci memset(string_cpu, 0, sizeof(string_cpu)); 3358c2ecf20Sopenharmony_ci strings = data; 3368c2ecf20Sopenharmony_ci num_cpus = num_online_cpus(); 3378c2ecf20Sopenharmony_ci size = DPAA_STATS_GLOBAL_LEN * ETH_GSTRING_LEN; 3388c2ecf20Sopenharmony_ci 3398c2ecf20Sopenharmony_ci for (i = 0; i < DPAA_STATS_PERCPU_LEN; i++) { 3408c2ecf20Sopenharmony_ci for (j = 0; j < num_cpus; j++) { 3418c2ecf20Sopenharmony_ci snprintf(string_cpu, ETH_GSTRING_LEN, "%s [CPU %d]", 3428c2ecf20Sopenharmony_ci dpaa_stats_percpu[i], j); 3438c2ecf20Sopenharmony_ci memcpy(strings, string_cpu, ETH_GSTRING_LEN); 3448c2ecf20Sopenharmony_ci strings += ETH_GSTRING_LEN; 3458c2ecf20Sopenharmony_ci } 3468c2ecf20Sopenharmony_ci snprintf(string_cpu, ETH_GSTRING_LEN, "%s [TOTAL]", 3478c2ecf20Sopenharmony_ci dpaa_stats_percpu[i]); 3488c2ecf20Sopenharmony_ci memcpy(strings, string_cpu, ETH_GSTRING_LEN); 3498c2ecf20Sopenharmony_ci strings += ETH_GSTRING_LEN; 3508c2ecf20Sopenharmony_ci } 3518c2ecf20Sopenharmony_ci for (j = 0; j < num_cpus; j++) { 3528c2ecf20Sopenharmony_ci snprintf(string_cpu, ETH_GSTRING_LEN, 3538c2ecf20Sopenharmony_ci "bpool [CPU %d]", j); 3548c2ecf20Sopenharmony_ci memcpy(strings, string_cpu, ETH_GSTRING_LEN); 3558c2ecf20Sopenharmony_ci strings += ETH_GSTRING_LEN; 3568c2ecf20Sopenharmony_ci } 3578c2ecf20Sopenharmony_ci snprintf(string_cpu, ETH_GSTRING_LEN, "bpool [TOTAL]"); 3588c2ecf20Sopenharmony_ci memcpy(strings, string_cpu, ETH_GSTRING_LEN); 3598c2ecf20Sopenharmony_ci strings += ETH_GSTRING_LEN; 3608c2ecf20Sopenharmony_ci 3618c2ecf20Sopenharmony_ci memcpy(strings, dpaa_stats_global, size); 3628c2ecf20Sopenharmony_ci} 3638c2ecf20Sopenharmony_ci 3648c2ecf20Sopenharmony_cistatic int dpaa_get_hash_opts(struct net_device *dev, 3658c2ecf20Sopenharmony_ci struct ethtool_rxnfc *cmd) 3668c2ecf20Sopenharmony_ci{ 3678c2ecf20Sopenharmony_ci struct dpaa_priv *priv = netdev_priv(dev); 3688c2ecf20Sopenharmony_ci 3698c2ecf20Sopenharmony_ci cmd->data = 0; 3708c2ecf20Sopenharmony_ci 3718c2ecf20Sopenharmony_ci switch (cmd->flow_type) { 3728c2ecf20Sopenharmony_ci case TCP_V4_FLOW: 3738c2ecf20Sopenharmony_ci case TCP_V6_FLOW: 3748c2ecf20Sopenharmony_ci case UDP_V4_FLOW: 3758c2ecf20Sopenharmony_ci case UDP_V6_FLOW: 3768c2ecf20Sopenharmony_ci if (priv->keygen_in_use) 3778c2ecf20Sopenharmony_ci cmd->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3; 3788c2ecf20Sopenharmony_ci fallthrough; 3798c2ecf20Sopenharmony_ci case IPV4_FLOW: 3808c2ecf20Sopenharmony_ci case IPV6_FLOW: 3818c2ecf20Sopenharmony_ci case SCTP_V4_FLOW: 3828c2ecf20Sopenharmony_ci case SCTP_V6_FLOW: 3838c2ecf20Sopenharmony_ci case AH_ESP_V4_FLOW: 3848c2ecf20Sopenharmony_ci case AH_ESP_V6_FLOW: 3858c2ecf20Sopenharmony_ci case AH_V4_FLOW: 3868c2ecf20Sopenharmony_ci case AH_V6_FLOW: 3878c2ecf20Sopenharmony_ci case ESP_V4_FLOW: 3888c2ecf20Sopenharmony_ci case ESP_V6_FLOW: 3898c2ecf20Sopenharmony_ci if (priv->keygen_in_use) 3908c2ecf20Sopenharmony_ci cmd->data |= RXH_IP_SRC | RXH_IP_DST; 3918c2ecf20Sopenharmony_ci break; 3928c2ecf20Sopenharmony_ci default: 3938c2ecf20Sopenharmony_ci cmd->data = 0; 3948c2ecf20Sopenharmony_ci break; 3958c2ecf20Sopenharmony_ci } 3968c2ecf20Sopenharmony_ci 3978c2ecf20Sopenharmony_ci return 0; 3988c2ecf20Sopenharmony_ci} 3998c2ecf20Sopenharmony_ci 4008c2ecf20Sopenharmony_cistatic int dpaa_get_rxnfc(struct net_device *dev, struct ethtool_rxnfc *cmd, 4018c2ecf20Sopenharmony_ci u32 *unused) 4028c2ecf20Sopenharmony_ci{ 4038c2ecf20Sopenharmony_ci int ret = -EOPNOTSUPP; 4048c2ecf20Sopenharmony_ci 4058c2ecf20Sopenharmony_ci switch (cmd->cmd) { 4068c2ecf20Sopenharmony_ci case ETHTOOL_GRXFH: 4078c2ecf20Sopenharmony_ci ret = dpaa_get_hash_opts(dev, cmd); 4088c2ecf20Sopenharmony_ci break; 4098c2ecf20Sopenharmony_ci default: 4108c2ecf20Sopenharmony_ci break; 4118c2ecf20Sopenharmony_ci } 4128c2ecf20Sopenharmony_ci 4138c2ecf20Sopenharmony_ci return ret; 4148c2ecf20Sopenharmony_ci} 4158c2ecf20Sopenharmony_ci 4168c2ecf20Sopenharmony_cistatic void dpaa_set_hash(struct net_device *net_dev, bool enable) 4178c2ecf20Sopenharmony_ci{ 4188c2ecf20Sopenharmony_ci struct mac_device *mac_dev; 4198c2ecf20Sopenharmony_ci struct fman_port *rxport; 4208c2ecf20Sopenharmony_ci struct dpaa_priv *priv; 4218c2ecf20Sopenharmony_ci 4228c2ecf20Sopenharmony_ci priv = netdev_priv(net_dev); 4238c2ecf20Sopenharmony_ci mac_dev = priv->mac_dev; 4248c2ecf20Sopenharmony_ci rxport = mac_dev->port[0]; 4258c2ecf20Sopenharmony_ci 4268c2ecf20Sopenharmony_ci fman_port_use_kg_hash(rxport, enable); 4278c2ecf20Sopenharmony_ci priv->keygen_in_use = enable; 4288c2ecf20Sopenharmony_ci} 4298c2ecf20Sopenharmony_ci 4308c2ecf20Sopenharmony_cistatic int dpaa_set_hash_opts(struct net_device *dev, 4318c2ecf20Sopenharmony_ci struct ethtool_rxnfc *nfc) 4328c2ecf20Sopenharmony_ci{ 4338c2ecf20Sopenharmony_ci int ret = -EINVAL; 4348c2ecf20Sopenharmony_ci 4358c2ecf20Sopenharmony_ci /* we support hashing on IPv4/v6 src/dest IP and L4 src/dest port */ 4368c2ecf20Sopenharmony_ci if (nfc->data & 4378c2ecf20Sopenharmony_ci ~(RXH_IP_SRC | RXH_IP_DST | RXH_L4_B_0_1 | RXH_L4_B_2_3)) 4388c2ecf20Sopenharmony_ci return -EINVAL; 4398c2ecf20Sopenharmony_ci 4408c2ecf20Sopenharmony_ci switch (nfc->flow_type) { 4418c2ecf20Sopenharmony_ci case TCP_V4_FLOW: 4428c2ecf20Sopenharmony_ci case TCP_V6_FLOW: 4438c2ecf20Sopenharmony_ci case UDP_V4_FLOW: 4448c2ecf20Sopenharmony_ci case UDP_V6_FLOW: 4458c2ecf20Sopenharmony_ci case IPV4_FLOW: 4468c2ecf20Sopenharmony_ci case IPV6_FLOW: 4478c2ecf20Sopenharmony_ci case SCTP_V4_FLOW: 4488c2ecf20Sopenharmony_ci case SCTP_V6_FLOW: 4498c2ecf20Sopenharmony_ci case AH_ESP_V4_FLOW: 4508c2ecf20Sopenharmony_ci case AH_ESP_V6_FLOW: 4518c2ecf20Sopenharmony_ci case AH_V4_FLOW: 4528c2ecf20Sopenharmony_ci case AH_V6_FLOW: 4538c2ecf20Sopenharmony_ci case ESP_V4_FLOW: 4548c2ecf20Sopenharmony_ci case ESP_V6_FLOW: 4558c2ecf20Sopenharmony_ci dpaa_set_hash(dev, !!nfc->data); 4568c2ecf20Sopenharmony_ci ret = 0; 4578c2ecf20Sopenharmony_ci break; 4588c2ecf20Sopenharmony_ci default: 4598c2ecf20Sopenharmony_ci break; 4608c2ecf20Sopenharmony_ci } 4618c2ecf20Sopenharmony_ci 4628c2ecf20Sopenharmony_ci return ret; 4638c2ecf20Sopenharmony_ci} 4648c2ecf20Sopenharmony_ci 4658c2ecf20Sopenharmony_cistatic int dpaa_set_rxnfc(struct net_device *dev, struct ethtool_rxnfc *cmd) 4668c2ecf20Sopenharmony_ci{ 4678c2ecf20Sopenharmony_ci int ret = -EOPNOTSUPP; 4688c2ecf20Sopenharmony_ci 4698c2ecf20Sopenharmony_ci switch (cmd->cmd) { 4708c2ecf20Sopenharmony_ci case ETHTOOL_SRXFH: 4718c2ecf20Sopenharmony_ci ret = dpaa_set_hash_opts(dev, cmd); 4728c2ecf20Sopenharmony_ci break; 4738c2ecf20Sopenharmony_ci default: 4748c2ecf20Sopenharmony_ci break; 4758c2ecf20Sopenharmony_ci } 4768c2ecf20Sopenharmony_ci 4778c2ecf20Sopenharmony_ci return ret; 4788c2ecf20Sopenharmony_ci} 4798c2ecf20Sopenharmony_ci 4808c2ecf20Sopenharmony_cistatic int dpaa_get_ts_info(struct net_device *net_dev, 4818c2ecf20Sopenharmony_ci struct ethtool_ts_info *info) 4828c2ecf20Sopenharmony_ci{ 4838c2ecf20Sopenharmony_ci struct device *dev = net_dev->dev.parent; 4848c2ecf20Sopenharmony_ci struct device_node *mac_node = dev->of_node; 4858c2ecf20Sopenharmony_ci struct device_node *fman_node = NULL, *ptp_node = NULL; 4868c2ecf20Sopenharmony_ci struct platform_device *ptp_dev = NULL; 4878c2ecf20Sopenharmony_ci struct ptp_qoriq *ptp = NULL; 4888c2ecf20Sopenharmony_ci 4898c2ecf20Sopenharmony_ci info->phc_index = -1; 4908c2ecf20Sopenharmony_ci 4918c2ecf20Sopenharmony_ci fman_node = of_get_parent(mac_node); 4928c2ecf20Sopenharmony_ci if (fman_node) { 4938c2ecf20Sopenharmony_ci ptp_node = of_parse_phandle(fman_node, "ptimer-handle", 0); 4948c2ecf20Sopenharmony_ci of_node_put(fman_node); 4958c2ecf20Sopenharmony_ci } 4968c2ecf20Sopenharmony_ci 4978c2ecf20Sopenharmony_ci if (ptp_node) { 4988c2ecf20Sopenharmony_ci ptp_dev = of_find_device_by_node(ptp_node); 4998c2ecf20Sopenharmony_ci of_node_put(ptp_node); 5008c2ecf20Sopenharmony_ci } 5018c2ecf20Sopenharmony_ci 5028c2ecf20Sopenharmony_ci if (ptp_dev) 5038c2ecf20Sopenharmony_ci ptp = platform_get_drvdata(ptp_dev); 5048c2ecf20Sopenharmony_ci 5058c2ecf20Sopenharmony_ci if (ptp) 5068c2ecf20Sopenharmony_ci info->phc_index = ptp->phc_index; 5078c2ecf20Sopenharmony_ci 5088c2ecf20Sopenharmony_ci info->so_timestamping = SOF_TIMESTAMPING_TX_HARDWARE | 5098c2ecf20Sopenharmony_ci SOF_TIMESTAMPING_RX_HARDWARE | 5108c2ecf20Sopenharmony_ci SOF_TIMESTAMPING_RAW_HARDWARE; 5118c2ecf20Sopenharmony_ci info->tx_types = (1 << HWTSTAMP_TX_OFF) | 5128c2ecf20Sopenharmony_ci (1 << HWTSTAMP_TX_ON); 5138c2ecf20Sopenharmony_ci info->rx_filters = (1 << HWTSTAMP_FILTER_NONE) | 5148c2ecf20Sopenharmony_ci (1 << HWTSTAMP_FILTER_ALL); 5158c2ecf20Sopenharmony_ci 5168c2ecf20Sopenharmony_ci return 0; 5178c2ecf20Sopenharmony_ci} 5188c2ecf20Sopenharmony_ci 5198c2ecf20Sopenharmony_cistatic int dpaa_get_coalesce(struct net_device *dev, 5208c2ecf20Sopenharmony_ci struct ethtool_coalesce *c) 5218c2ecf20Sopenharmony_ci{ 5228c2ecf20Sopenharmony_ci struct qman_portal *portal; 5238c2ecf20Sopenharmony_ci u32 period; 5248c2ecf20Sopenharmony_ci u8 thresh; 5258c2ecf20Sopenharmony_ci 5268c2ecf20Sopenharmony_ci portal = qman_get_affine_portal(smp_processor_id()); 5278c2ecf20Sopenharmony_ci qman_portal_get_iperiod(portal, &period); 5288c2ecf20Sopenharmony_ci qman_dqrr_get_ithresh(portal, &thresh); 5298c2ecf20Sopenharmony_ci 5308c2ecf20Sopenharmony_ci c->rx_coalesce_usecs = period; 5318c2ecf20Sopenharmony_ci c->rx_max_coalesced_frames = thresh; 5328c2ecf20Sopenharmony_ci 5338c2ecf20Sopenharmony_ci return 0; 5348c2ecf20Sopenharmony_ci} 5358c2ecf20Sopenharmony_ci 5368c2ecf20Sopenharmony_cistatic int dpaa_set_coalesce(struct net_device *dev, 5378c2ecf20Sopenharmony_ci struct ethtool_coalesce *c) 5388c2ecf20Sopenharmony_ci{ 5398c2ecf20Sopenharmony_ci const cpumask_t *cpus = qman_affine_cpus(); 5408c2ecf20Sopenharmony_ci bool needs_revert[NR_CPUS] = {false}; 5418c2ecf20Sopenharmony_ci struct qman_portal *portal; 5428c2ecf20Sopenharmony_ci u32 period, prev_period; 5438c2ecf20Sopenharmony_ci u8 thresh, prev_thresh; 5448c2ecf20Sopenharmony_ci int cpu, res; 5458c2ecf20Sopenharmony_ci 5468c2ecf20Sopenharmony_ci period = c->rx_coalesce_usecs; 5478c2ecf20Sopenharmony_ci thresh = c->rx_max_coalesced_frames; 5488c2ecf20Sopenharmony_ci 5498c2ecf20Sopenharmony_ci /* save previous values */ 5508c2ecf20Sopenharmony_ci portal = qman_get_affine_portal(smp_processor_id()); 5518c2ecf20Sopenharmony_ci qman_portal_get_iperiod(portal, &prev_period); 5528c2ecf20Sopenharmony_ci qman_dqrr_get_ithresh(portal, &prev_thresh); 5538c2ecf20Sopenharmony_ci 5548c2ecf20Sopenharmony_ci /* set new values */ 5558c2ecf20Sopenharmony_ci for_each_cpu_and(cpu, cpus, cpu_online_mask) { 5568c2ecf20Sopenharmony_ci portal = qman_get_affine_portal(cpu); 5578c2ecf20Sopenharmony_ci res = qman_portal_set_iperiod(portal, period); 5588c2ecf20Sopenharmony_ci if (res) 5598c2ecf20Sopenharmony_ci goto revert_values; 5608c2ecf20Sopenharmony_ci res = qman_dqrr_set_ithresh(portal, thresh); 5618c2ecf20Sopenharmony_ci if (res) { 5628c2ecf20Sopenharmony_ci qman_portal_set_iperiod(portal, prev_period); 5638c2ecf20Sopenharmony_ci goto revert_values; 5648c2ecf20Sopenharmony_ci } 5658c2ecf20Sopenharmony_ci needs_revert[cpu] = true; 5668c2ecf20Sopenharmony_ci } 5678c2ecf20Sopenharmony_ci 5688c2ecf20Sopenharmony_ci return 0; 5698c2ecf20Sopenharmony_ci 5708c2ecf20Sopenharmony_cirevert_values: 5718c2ecf20Sopenharmony_ci /* restore previous values */ 5728c2ecf20Sopenharmony_ci for_each_cpu_and(cpu, cpus, cpu_online_mask) { 5738c2ecf20Sopenharmony_ci if (!needs_revert[cpu]) 5748c2ecf20Sopenharmony_ci continue; 5758c2ecf20Sopenharmony_ci portal = qman_get_affine_portal(cpu); 5768c2ecf20Sopenharmony_ci /* previous values will not fail, ignore return value */ 5778c2ecf20Sopenharmony_ci qman_portal_set_iperiod(portal, prev_period); 5788c2ecf20Sopenharmony_ci qman_dqrr_set_ithresh(portal, prev_thresh); 5798c2ecf20Sopenharmony_ci } 5808c2ecf20Sopenharmony_ci 5818c2ecf20Sopenharmony_ci return res; 5828c2ecf20Sopenharmony_ci} 5838c2ecf20Sopenharmony_ci 5848c2ecf20Sopenharmony_ciconst struct ethtool_ops dpaa_ethtool_ops = { 5858c2ecf20Sopenharmony_ci .supported_coalesce_params = ETHTOOL_COALESCE_RX_USECS | 5868c2ecf20Sopenharmony_ci ETHTOOL_COALESCE_RX_MAX_FRAMES, 5878c2ecf20Sopenharmony_ci .get_drvinfo = dpaa_get_drvinfo, 5888c2ecf20Sopenharmony_ci .get_msglevel = dpaa_get_msglevel, 5898c2ecf20Sopenharmony_ci .set_msglevel = dpaa_set_msglevel, 5908c2ecf20Sopenharmony_ci .nway_reset = dpaa_nway_reset, 5918c2ecf20Sopenharmony_ci .get_pauseparam = dpaa_get_pauseparam, 5928c2ecf20Sopenharmony_ci .set_pauseparam = dpaa_set_pauseparam, 5938c2ecf20Sopenharmony_ci .get_link = ethtool_op_get_link, 5948c2ecf20Sopenharmony_ci .get_sset_count = dpaa_get_sset_count, 5958c2ecf20Sopenharmony_ci .get_ethtool_stats = dpaa_get_ethtool_stats, 5968c2ecf20Sopenharmony_ci .get_strings = dpaa_get_strings, 5978c2ecf20Sopenharmony_ci .get_link_ksettings = dpaa_get_link_ksettings, 5988c2ecf20Sopenharmony_ci .set_link_ksettings = dpaa_set_link_ksettings, 5998c2ecf20Sopenharmony_ci .get_rxnfc = dpaa_get_rxnfc, 6008c2ecf20Sopenharmony_ci .set_rxnfc = dpaa_set_rxnfc, 6018c2ecf20Sopenharmony_ci .get_ts_info = dpaa_get_ts_info, 6028c2ecf20Sopenharmony_ci .get_coalesce = dpaa_get_coalesce, 6038c2ecf20Sopenharmony_ci .set_coalesce = dpaa_set_coalesce, 6048c2ecf20Sopenharmony_ci}; 605