Skip to content

Commit

Permalink
net: fec: add eee mode tx lpi support
Browse files Browse the repository at this point in the history
The i.MX8MQ ENET version support IEEE802.3az eee mode, add
eee mode tx lpi enable to support ethtool interface.

usage:
1. set sleep and wake timer to 5ms:
ethtool --set-eee eth0 eee on tx-lpi on tx-timer 5000
2. check the eee mode:
~# ethtool --show-eee eth0
EEE Settings for eth0:
        EEE status: enabled - active
        Tx LPI: 5000 (us)
        Supported EEE link modes:  100baseT/Full
                                   1000baseT/Full
        Advertised EEE link modes:  100baseT/Full
                                    1000baseT/Full
        Link partner advertised EEE link modes:  100baseT/Full

Note: For realtime case and IEEE1588 ptp case, it should disable
EEE mode.

Signed-off-by: Fugang Duan <fugang.duan@nxp.com>
Signed-off-by: Joakim Zhang <qiangqing.zhang@nxp.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
Fugang Duan authored and David S. Miller committed Jul 28, 2021
1 parent 947240e commit b82f8c3
Show file tree
Hide file tree
Showing 2 changed files with 95 additions and 0 deletions.
6 changes: 6 additions & 0 deletions drivers/net/ethernet/freescale/fec.h
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,8 @@
#define FEC_R_DES_ACTIVE_2 0x1e8 /* Rx descriptor active for ring 2 */
#define FEC_X_DES_ACTIVE_2 0x1ec /* Tx descriptor active for ring 2 */
#define FEC_QOS_SCHEME 0x1f0 /* Set multi queues Qos scheme */
#define FEC_LPI_SLEEP 0x1f4 /* Set IEEE802.3az LPI Sleep Ts time */
#define FEC_LPI_WAKE 0x1f8 /* Set IEEE802.3az LPI Wake Tw time */
#define FEC_MIIGSK_CFGR 0x300 /* MIIGSK Configuration reg */
#define FEC_MIIGSK_ENR 0x308 /* MIIGSK Enable reg */

Expand Down Expand Up @@ -602,6 +604,10 @@ struct fec_enet_private {
unsigned int tx_time_itr;
unsigned int itr_clk_rate;

/* tx lpi eee mode */
struct ethtool_eee eee;
unsigned int clk_ref_rate;

u32 rx_copybreak;

/* ptp clock period in ns*/
Expand Down
89 changes: 89 additions & 0 deletions drivers/net/ethernet/freescale/fec_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -2722,6 +2722,92 @@ static int fec_enet_set_tunable(struct net_device *netdev,
return ret;
}

/* LPI Sleep Ts count base on tx clk (clk_ref).
* The lpi sleep cnt value = X us / (cycle_ns).
*/
static int fec_enet_us_to_tx_cycle(struct net_device *ndev, int us)
{
struct fec_enet_private *fep = netdev_priv(ndev);

return us * (fep->clk_ref_rate / 1000) / 1000;
}

static int fec_enet_eee_mode_set(struct net_device *ndev, bool enable)
{
struct fec_enet_private *fep = netdev_priv(ndev);
struct ethtool_eee *p = &fep->eee;
unsigned int sleep_cycle, wake_cycle;
int ret = 0;

if (enable) {
ret = phy_init_eee(ndev->phydev, 0);
if (ret)
return ret;

sleep_cycle = fec_enet_us_to_tx_cycle(ndev, p->tx_lpi_timer);
wake_cycle = sleep_cycle;
} else {
sleep_cycle = 0;
wake_cycle = 0;
}

p->tx_lpi_enabled = enable;
p->eee_enabled = enable;
p->eee_active = enable;

writel(sleep_cycle, fep->hwp + FEC_LPI_SLEEP);
writel(wake_cycle, fep->hwp + FEC_LPI_WAKE);

return 0;
}

static int
fec_enet_get_eee(struct net_device *ndev, struct ethtool_eee *edata)
{
struct fec_enet_private *fep = netdev_priv(ndev);
struct ethtool_eee *p = &fep->eee;

if (!(fep->quirks & FEC_QUIRK_HAS_EEE))
return -EOPNOTSUPP;

if (!netif_running(ndev))
return -ENETDOWN;

edata->eee_enabled = p->eee_enabled;
edata->eee_active = p->eee_active;
edata->tx_lpi_timer = p->tx_lpi_timer;
edata->tx_lpi_enabled = p->tx_lpi_enabled;

return phy_ethtool_get_eee(ndev->phydev, edata);
}

static int
fec_enet_set_eee(struct net_device *ndev, struct ethtool_eee *edata)
{
struct fec_enet_private *fep = netdev_priv(ndev);
struct ethtool_eee *p = &fep->eee;
int ret = 0;

if (!(fep->quirks & FEC_QUIRK_HAS_EEE))
return -EOPNOTSUPP;

if (!netif_running(ndev))
return -ENETDOWN;

p->tx_lpi_timer = edata->tx_lpi_timer;

if (!edata->eee_enabled || !edata->tx_lpi_enabled ||
!edata->tx_lpi_timer)
ret = fec_enet_eee_mode_set(ndev, false);
else
ret = fec_enet_eee_mode_set(ndev, true);

if (ret)
return ret;

return phy_ethtool_set_eee(ndev->phydev, edata);
}

static void
fec_enet_get_wol(struct net_device *ndev, struct ethtool_wolinfo *wol)
{
Expand Down Expand Up @@ -2782,6 +2868,8 @@ static const struct ethtool_ops fec_enet_ethtool_ops = {
.set_tunable = fec_enet_set_tunable,
.get_wol = fec_enet_get_wol,
.set_wol = fec_enet_set_wol,
.get_eee = fec_enet_get_eee,
.set_eee = fec_enet_set_eee,
.get_link_ksettings = phy_ethtool_get_link_ksettings,
.set_link_ksettings = phy_ethtool_set_link_ksettings,
.self_test = net_selftest,
Expand Down Expand Up @@ -3722,6 +3810,7 @@ fec_probe(struct platform_device *pdev)
fep->clk_ref = devm_clk_get(&pdev->dev, "enet_clk_ref");
if (IS_ERR(fep->clk_ref))
fep->clk_ref = NULL;
fep->clk_ref_rate = clk_get_rate(fep->clk_ref);

fep->bufdesc_ex = fep->quirks & FEC_QUIRK_HAS_BUFDESC_EX;
fep->clk_ptp = devm_clk_get(&pdev->dev, "ptp");
Expand Down

0 comments on commit b82f8c3

Please sign in to comment.