mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-11 21:38:32 +08:00
net: fec: add eee mode tx lpi support
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>
This commit is contained in:
parent
947240ebcc
commit
b82f8c3f14
@ -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 */
|
||||
|
||||
@ -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*/
|
||||
|
@ -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)
|
||||
{
|
||||
@ -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,
|
||||
@ -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");
|
||||
|
Loading…
Reference in New Issue
Block a user