From 9999e48639b3cecb08ffb37358bcba3b48161b29 Mon Sep 17 00:00:00 2001 From: hc <hc@nodka.com> Date: Fri, 10 May 2024 08:50:17 +0000 Subject: [PATCH] add ax88772_rst --- kernel/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c | 346 +++++++++++++++++++++++++++++++++++++++------------------ 1 files changed, 238 insertions(+), 108 deletions(-) diff --git a/kernel/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c b/kernel/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c index 5986fe9..7664ab0 100644 --- a/kernel/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c +++ b/kernel/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c @@ -1,19 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /******************************************************************************* STMMAC Ethtool support Copyright (C) 2007-2009 STMicroelectronics Ltd - This program is free software; you can redistribute it and/or modify it - under the terms and conditions of the GNU General Public License, - version 2, as published by the Free Software Foundation. - - This program is distributed in the hope it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - more details. - - The full GNU General Public License is included in this distribution in - the file called "COPYING". Author: Giuseppe Cavallaro <peppe.cavallaro@st.com> *******************************************************************************/ @@ -22,16 +12,26 @@ #include <linux/ethtool.h> #include <linux/interrupt.h> #include <linux/mii.h> -#include <linux/phy.h> +#include <linux/phylink.h> #include <linux/net_tstamp.h> #include <asm/io.h> #include "stmmac.h" #include "dwmac_dma.h" +#include "dwxgmac2.h" #define REG_SPACE_SIZE 0x1060 +#define GMAC4_REG_SPACE_SIZE 0x116C #define MAC100_ETHTOOL_NAME "st_mac100" #define GMAC_ETHTOOL_NAME "st_gmac" +#define XGMAC_ETHTOOL_NAME "st_xgmac" + +/* Same as DMA_CHAN_BASE_ADDR defined in dwmac4_dma.h + * + * It is here because dwmac_dma.h and dwmac4_dam.h can not be included at the + * same time due to the conflicting macro names. + */ +#define GMAC4_DMA_CHAN_BASE_ADDR 0x00001100 #define ETHTOOL_DMA_OFFSET 55 @@ -42,7 +42,7 @@ }; #define STMMAC_STAT(m) \ - { #m, FIELD_SIZEOF(struct stmmac_extra_stats, m), \ + { #m, sizeof_field(struct stmmac_extra_stats, m), \ offsetof(struct stmmac_priv, xstats.m)} static const struct stmmac_stats stmmac_gstrings_stats[] = { @@ -75,6 +75,7 @@ STMMAC_STAT(rx_missed_cntr), STMMAC_STAT(rx_overflow_cntr), STMMAC_STAT(rx_vlan), + STMMAC_STAT(rx_split_hdr_pkt_n), /* Tx/Rx IRQ error info */ STMMAC_STAT(tx_undeflow_irq), STMMAC_STAT(tx_process_stopped_irq), @@ -170,7 +171,7 @@ /* HW MAC Management counters (if supported) */ #define STMMAC_MMC_STAT(m) \ - { #m, FIELD_SIZEOF(struct stmmac_counters, m), \ + { #m, sizeof_field(struct stmmac_counters, m), \ offsetof(struct stmmac_priv, mmc.m)} static const struct stmmac_stats stmmac_mmc[] = { @@ -253,6 +254,12 @@ STMMAC_MMC_STAT(mmc_rx_tcp_err_octets), STMMAC_MMC_STAT(mmc_rx_icmp_gd_octets), STMMAC_MMC_STAT(mmc_rx_icmp_err_octets), + STMMAC_MMC_STAT(mmc_tx_fpe_fragment_cntr), + STMMAC_MMC_STAT(mmc_tx_hold_req_cntr), + STMMAC_MMC_STAT(mmc_rx_packet_assembly_err_cntr), + STMMAC_MMC_STAT(mmc_rx_packet_smd_err_cntr), + STMMAC_MMC_STAT(mmc_rx_packet_assembly_ok_cntr), + STMMAC_MMC_STAT(mmc_rx_fpe_fragment_cntr), }; #define STMMAC_MMC_STATS_LEN ARRAY_SIZE(stmmac_mmc) @@ -263,6 +270,8 @@ if (priv->plat->has_gmac || priv->plat->has_gmac4) strlcpy(info->driver, GMAC_ETHTOOL_NAME, sizeof(info->driver)); + else if (priv->plat->has_xgmac) + strlcpy(info->driver, XGMAC_ETHTOOL_NAME, sizeof(info->driver)); else strlcpy(info->driver, MAC100_ETHTOOL_NAME, sizeof(info->driver)); @@ -274,7 +283,6 @@ struct ethtool_link_ksettings *cmd) { struct stmmac_priv *priv = netdev_priv(dev); - struct phy_device *phy = dev->phydev; if (priv->hw->pcs & STMMAC_PCS_RGMII || priv->hw->pcs & STMMAC_PCS_SGMII) { @@ -353,18 +361,7 @@ return 0; } - if (phy == NULL) { - pr_err("%s: %s: PHY is not registered\n", - __func__, dev->name); - return -ENODEV; - } - if (!netif_running(dev)) { - pr_err("%s: interface is disabled: we cannot track " - "link speed / duplex setting\n", dev->name); - return -EBUSY; - } - phy_ethtool_ksettings_get(phy, cmd); - return 0; + return phylink_ethtool_ksettings_get(priv->phylink, cmd); } static int @@ -372,8 +369,6 @@ const struct ethtool_link_ksettings *cmd) { struct stmmac_priv *priv = netdev_priv(dev); - struct phy_device *phy = dev->phydev; - int rc; if (priv->hw->pcs & STMMAC_PCS_RGMII || priv->hw->pcs & STMMAC_PCS_SGMII) { @@ -397,9 +392,12 @@ return 0; } - rc = phy_ethtool_ksettings_set(phy, cmd); + if (priv->plat->tx_queues_to_use > 1 && cmd->base.duplex == DUPLEX_HALF) { + netdev_warn(priv->dev, "Half-Duplex can only work with single queue\n"); + return -EINVAL; + } - return rc; + return phylink_ethtool_ksettings_set(priv->phylink, cmd); } static u32 stmmac_ethtool_getmsglevel(struct net_device *dev) @@ -424,23 +422,69 @@ static int stmmac_ethtool_get_regs_len(struct net_device *dev) { + struct stmmac_priv *priv = netdev_priv(dev); + + if (priv->plat->has_xgmac) + return XGMAC_REGSIZE * 4; + else if (priv->plat->has_gmac4) + return GMAC4_REG_SPACE_SIZE; return REG_SPACE_SIZE; } static void stmmac_ethtool_gregs(struct net_device *dev, struct ethtool_regs *regs, void *space) { - u32 *reg_space = (u32 *) space; - struct stmmac_priv *priv = netdev_priv(dev); - - memset(reg_space, 0x0, REG_SPACE_SIZE); + u32 *reg_space = (u32 *) space; stmmac_dump_mac_regs(priv, priv->hw, reg_space); stmmac_dump_dma_regs(priv, priv->ioaddr, reg_space); + /* Copy DMA registers to where ethtool expects them */ - memcpy(®_space[ETHTOOL_DMA_OFFSET], ®_space[DMA_BUS_MODE / 4], - NUM_DWMAC1000_DMA_REGS * 4); + if (priv->plat->has_gmac4) { + /* GMAC4 dumps its DMA registers at its DMA_CHAN_BASE_ADDR */ + memcpy(®_space[ETHTOOL_DMA_OFFSET], + ®_space[GMAC4_DMA_CHAN_BASE_ADDR / 4], + NUM_DWMAC4_DMA_REGS * 4); + } else if (!priv->plat->has_xgmac) { + memcpy(®_space[ETHTOOL_DMA_OFFSET], + ®_space[DMA_BUS_MODE / 4], + NUM_DWMAC1000_DMA_REGS * 4); + } +} + +static int stmmac_nway_reset(struct net_device *dev) +{ + struct stmmac_priv *priv = netdev_priv(dev); + + return phylink_ethtool_nway_reset(priv->phylink); +} + +static void stmmac_get_ringparam(struct net_device *netdev, + struct ethtool_ringparam *ring) +{ + struct stmmac_priv *priv = netdev_priv(netdev); + + ring->rx_max_pending = DMA_MAX_RX_SIZE; + ring->tx_max_pending = DMA_MAX_TX_SIZE; + ring->rx_pending = priv->dma_rx_size; + ring->tx_pending = priv->dma_tx_size; +} + +static int stmmac_set_ringparam(struct net_device *netdev, + struct ethtool_ringparam *ring) +{ + if (ring->rx_mini_pending || ring->rx_jumbo_pending || + ring->rx_pending < DMA_MIN_RX_SIZE || + ring->rx_pending > DMA_MAX_RX_SIZE || + !is_power_of_2(ring->rx_pending) || + ring->tx_pending < DMA_MIN_TX_SIZE || + ring->tx_pending > DMA_MAX_TX_SIZE || + !is_power_of_2(ring->tx_pending)) + return -EINVAL; + + return stmmac_reinit_ringparam(netdev, ring->rx_pending, + ring->tx_pending); } static void @@ -450,26 +494,13 @@ struct stmmac_priv *priv = netdev_priv(netdev); struct rgmii_adv adv_lp; - pause->rx_pause = 0; - pause->tx_pause = 0; - if (priv->hw->pcs && !stmmac_pcs_get_adv_lp(priv, priv->ioaddr, &adv_lp)) { pause->autoneg = 1; if (!adv_lp.pause) return; } else { - if (!(netdev->phydev->supported & SUPPORTED_Pause) || - !(netdev->phydev->supported & SUPPORTED_Asym_Pause)) - return; + phylink_ethtool_get_pauseparam(priv->phylink, pause); } - - pause->autoneg = netdev->phydev->autoneg; - - if (priv->flow_ctrl & FLOW_RX) - pause->rx_pause = 1; - if (priv->flow_ctrl & FLOW_TX) - pause->tx_pause = 1; - } static int @@ -477,37 +508,16 @@ struct ethtool_pauseparam *pause) { struct stmmac_priv *priv = netdev_priv(netdev); - u32 tx_cnt = priv->plat->tx_queues_to_use; - struct phy_device *phy = netdev->phydev; - int new_pause = FLOW_OFF; struct rgmii_adv adv_lp; if (priv->hw->pcs && !stmmac_pcs_get_adv_lp(priv, priv->ioaddr, &adv_lp)) { pause->autoneg = 1; if (!adv_lp.pause) return -EOPNOTSUPP; + return 0; } else { - if (!(phy->supported & SUPPORTED_Pause) || - !(phy->supported & SUPPORTED_Asym_Pause)) - return -EOPNOTSUPP; + return phylink_ethtool_set_pauseparam(priv->phylink, pause); } - - if (pause->rx_pause) - new_pause |= FLOW_RX; - if (pause->tx_pause) - new_pause |= FLOW_TX; - - priv->flow_ctrl = new_pause; - phy->autoneg = pause->autoneg; - - if (phy->autoneg) { - if (netif_running(netdev)) - return phy_start_aneg(phy); - } - - stmmac_flow_ctrl(priv, priv->hw, phy->duplex, priv->flow_ctrl, - priv->pause, tx_cnt); - return 0; } static void stmmac_get_ethtool_stats(struct net_device *dev, @@ -533,7 +543,7 @@ if (ret) { /* If supported, for new GMAC chips expose the MMC counters */ if (priv->dma_cap.rmon) { - dwmac_mmc_read(priv->mmcaddr, &priv->mmc); + stmmac_mmc_read(priv, priv->mmcaddr, &priv->mmc); for (i = 0; i < STMMAC_MMC_STATS_LEN; i++) { char *p; @@ -545,7 +555,7 @@ } } if (priv->eee_enabled) { - int val = phy_get_eee_err(dev->phydev); + int val = phylink_get_eee_err(priv->phylink); if (val) priv->xstats.phy_eee_wakeup_error_n = val; } @@ -585,6 +595,8 @@ } return len; + case ETH_SS_TEST: + return stmmac_selftest_get_count(priv); default: return -EOPNOTSUPP; } @@ -621,6 +633,9 @@ p += ETH_GSTRING_LEN; } break; + case ETH_SS_TEST: + stmmac_selftest_get_strings(priv, p); + break; default: WARN_ON(1); break; @@ -632,9 +647,14 @@ { struct stmmac_priv *priv = netdev_priv(dev); + if (!priv->plat->pmt) + return phylink_ethtool_get_wol(priv->phylink, wol); + mutex_lock(&priv->lock); if (device_can_wakeup(priv->device)) { wol->supported = WAKE_MAGIC | WAKE_UCAST; + if (priv->hw_cap_support && !priv->dma_cap.pmt_magic_frame) + wol->supported &= ~WAKE_MAGIC; wol->wolopts = priv->wolopts; } mutex_unlock(&priv->lock); @@ -645,14 +665,22 @@ struct stmmac_priv *priv = netdev_priv(dev); u32 support = WAKE_MAGIC | WAKE_UCAST; + if (!device_can_wakeup(priv->device)) + return -EOPNOTSUPP; + + if (!priv->plat->pmt) { + int ret = phylink_ethtool_set_wol(priv->phylink, wol); + + if (!ret) + device_set_wakeup_enable(priv->device, !!wol->wolopts); + return ret; + } + /* By default almost all GMAC devices support the WoL via * magic frame but we can disable it if the HW capability * register shows no support for pmt_magic_frame. */ if ((priv->hw_cap_support) && (!priv->dma_cap.pmt_magic_frame)) wol->wolopts &= ~WAKE_MAGIC; - - if (!device_can_wakeup(priv->device)) - return -EINVAL; if (wol->wolopts & ~support) return -EINVAL; @@ -684,8 +712,9 @@ edata->eee_enabled = priv->eee_enabled; edata->eee_active = priv->eee_active; edata->tx_lpi_timer = priv->tx_lpi_timer; + edata->tx_lpi_enabled = priv->tx_lpi_enabled; - return phy_ethtool_get_eee(dev->phydev, edata); + return phylink_ethtool_get_eee(priv->phylink, edata); } static int stmmac_ethtool_op_set_eee(struct net_device *dev, @@ -697,14 +726,23 @@ if (!priv->dma_cap.eee) return -EOPNOTSUPP; + if (priv->tx_lpi_enabled != edata->tx_lpi_enabled) + netdev_warn(priv->dev, + "Setting EEE tx-lpi is not supported\n"); + if (!edata->eee_enabled) stmmac_disable_eee_mode(priv); - ret = phy_ethtool_set_eee(dev->phydev, edata); + ret = phylink_ethtool_set_eee(priv->phylink, edata); if (ret) return ret; - priv->tx_lpi_timer = edata->tx_lpi_timer; + if (edata->eee_enabled && + priv->tx_lpi_timer != edata->tx_lpi_timer) { + priv->tx_lpi_timer = edata->tx_lpi_timer; + stmmac_eee_init(priv); + } + return 0; } @@ -742,8 +780,10 @@ ec->tx_coalesce_usecs = priv->tx_coal_timer; ec->tx_max_coalesced_frames = priv->tx_coal_frames; - if (priv->use_riwt) + if (priv->use_riwt) { + ec->rx_max_coalesced_frames = priv->rx_coal_frames; ec->rx_coalesce_usecs = stmmac_riwt2usec(priv->rx_riwt, priv); + } return 0; } @@ -755,22 +795,15 @@ u32 rx_cnt = priv->plat->rx_queues_to_use; unsigned int rx_riwt; - /* Check not supported parameters */ - if ((ec->rx_max_coalesced_frames) || (ec->rx_coalesce_usecs_irq) || - (ec->rx_max_coalesced_frames_irq) || (ec->tx_coalesce_usecs_irq) || - (ec->use_adaptive_rx_coalesce) || (ec->use_adaptive_tx_coalesce) || - (ec->pkt_rate_low) || (ec->rx_coalesce_usecs_low) || - (ec->rx_max_coalesced_frames_low) || (ec->tx_coalesce_usecs_high) || - (ec->tx_max_coalesced_frames_low) || (ec->pkt_rate_high) || - (ec->tx_coalesce_usecs_low) || (ec->rx_coalesce_usecs_high) || - (ec->rx_max_coalesced_frames_high) || - (ec->tx_max_coalesced_frames_irq) || - (ec->stats_block_coalesce_usecs) || - (ec->tx_max_coalesced_frames_high) || (ec->rate_sample_interval)) - return -EOPNOTSUPP; + if (priv->use_riwt && (ec->rx_coalesce_usecs > 0)) { + rx_riwt = stmmac_usec2riwt(ec->rx_coalesce_usecs, priv); - if (ec->rx_coalesce_usecs == 0) - return -EINVAL; + if ((rx_riwt > MAX_DMA_RIWT) || (rx_riwt < MIN_DMA_RIWT)) + return -EINVAL; + + priv->rx_riwt = rx_riwt; + stmmac_rx_watchdog(priv, priv->ioaddr, priv->rx_riwt, rx_cnt); + } if ((ec->tx_coalesce_usecs == 0) && (ec->tx_max_coalesced_frames == 0)) @@ -780,20 +813,105 @@ (ec->tx_max_coalesced_frames > STMMAC_TX_MAX_FRAMES)) return -EINVAL; - rx_riwt = stmmac_usec2riwt(ec->rx_coalesce_usecs, priv); - - if ((rx_riwt > MAX_DMA_RIWT) || (rx_riwt < MIN_DMA_RIWT)) - return -EINVAL; - else if (!priv->use_riwt) - return -EOPNOTSUPP; - /* Only copy relevant parameters, ignore all others. */ priv->tx_coal_frames = ec->tx_max_coalesced_frames; priv->tx_coal_timer = ec->tx_coalesce_usecs; - priv->rx_riwt = rx_riwt; - stmmac_rx_watchdog(priv, priv->ioaddr, priv->rx_riwt, rx_cnt); + priv->rx_coal_frames = ec->rx_max_coalesced_frames; + return 0; +} + +static int stmmac_get_rxnfc(struct net_device *dev, + struct ethtool_rxnfc *rxnfc, u32 *rule_locs) +{ + struct stmmac_priv *priv = netdev_priv(dev); + + switch (rxnfc->cmd) { + case ETHTOOL_GRXRINGS: + rxnfc->data = priv->plat->rx_queues_to_use; + break; + default: + return -EOPNOTSUPP; + } return 0; +} + +static u32 stmmac_get_rxfh_key_size(struct net_device *dev) +{ + struct stmmac_priv *priv = netdev_priv(dev); + + return sizeof(priv->rss.key); +} + +static u32 stmmac_get_rxfh_indir_size(struct net_device *dev) +{ + struct stmmac_priv *priv = netdev_priv(dev); + + return ARRAY_SIZE(priv->rss.table); +} + +static int stmmac_get_rxfh(struct net_device *dev, u32 *indir, u8 *key, + u8 *hfunc) +{ + struct stmmac_priv *priv = netdev_priv(dev); + int i; + + if (indir) { + for (i = 0; i < ARRAY_SIZE(priv->rss.table); i++) + indir[i] = priv->rss.table[i]; + } + + if (key) + memcpy(key, priv->rss.key, sizeof(priv->rss.key)); + if (hfunc) + *hfunc = ETH_RSS_HASH_TOP; + + return 0; +} + +static int stmmac_set_rxfh(struct net_device *dev, const u32 *indir, + const u8 *key, const u8 hfunc) +{ + struct stmmac_priv *priv = netdev_priv(dev); + int i; + + if ((hfunc != ETH_RSS_HASH_NO_CHANGE) && (hfunc != ETH_RSS_HASH_TOP)) + return -EOPNOTSUPP; + + if (indir) { + for (i = 0; i < ARRAY_SIZE(priv->rss.table); i++) + priv->rss.table[i] = indir[i]; + } + + if (key) + memcpy(priv->rss.key, key, sizeof(priv->rss.key)); + + return stmmac_rss_configure(priv, priv->hw, &priv->rss, + priv->plat->rx_queues_to_use); +} + +static void stmmac_get_channels(struct net_device *dev, + struct ethtool_channels *chan) +{ + struct stmmac_priv *priv = netdev_priv(dev); + + chan->rx_count = priv->plat->rx_queues_to_use; + chan->tx_count = priv->plat->tx_queues_to_use; + chan->max_rx = priv->dma_cap.number_rx_queues; + chan->max_tx = priv->dma_cap.number_tx_queues; +} + +static int stmmac_set_channels(struct net_device *dev, + struct ethtool_channels *chan) +{ + struct stmmac_priv *priv = netdev_priv(dev); + + if (chan->rx_count > priv->dma_cap.number_rx_queues || + chan->tx_count > priv->dma_cap.number_tx_queues || + !chan->rx_count || !chan->tx_count) + return -EINVAL; + + return stmmac_reinit_queues(dev, chan->rx_count, chan->tx_count); } static int stmmac_get_ts_info(struct net_device *dev, @@ -869,6 +987,8 @@ } static const struct ethtool_ops stmmac_ethtool_ops = { + .supported_coalesce_params = ETHTOOL_COALESCE_USECS | + ETHTOOL_COALESCE_MAX_FRAMES, .begin = stmmac_check_if_running, .get_drvinfo = stmmac_ethtool_getdrvinfo, .get_msglevel = stmmac_ethtool_getmsglevel, @@ -876,9 +996,12 @@ .get_regs = stmmac_ethtool_gregs, .get_regs_len = stmmac_ethtool_get_regs_len, .get_link = ethtool_op_get_link, - .nway_reset = phy_ethtool_nway_reset, + .nway_reset = stmmac_nway_reset, + .get_ringparam = stmmac_get_ringparam, + .set_ringparam = stmmac_set_ringparam, .get_pauseparam = stmmac_get_pauseparam, .set_pauseparam = stmmac_set_pauseparam, + .self_test = stmmac_selftest_run, .get_ethtool_stats = stmmac_get_ethtool_stats, .get_strings = stmmac_get_strings, .get_wol = stmmac_get_wol, @@ -886,9 +1009,16 @@ .get_eee = stmmac_ethtool_op_get_eee, .set_eee = stmmac_ethtool_op_set_eee, .get_sset_count = stmmac_get_sset_count, + .get_rxnfc = stmmac_get_rxnfc, + .get_rxfh_key_size = stmmac_get_rxfh_key_size, + .get_rxfh_indir_size = stmmac_get_rxfh_indir_size, + .get_rxfh = stmmac_get_rxfh, + .set_rxfh = stmmac_set_rxfh, .get_ts_info = stmmac_get_ts_info, .get_coalesce = stmmac_get_coalesce, .set_coalesce = stmmac_set_coalesce, + .get_channels = stmmac_get_channels, + .set_channels = stmmac_set_channels, .get_tunable = stmmac_get_tunable, .set_tunable = stmmac_set_tunable, .get_link_ksettings = stmmac_ethtool_get_link_ksettings, -- Gitblit v1.6.2