diff options
author | Russell King <rmk+kernel@arm.linux.org.uk> | 2018-01-02 12:25:04 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2018-01-03 10:38:53 -0500 |
commit | 6d81f45145c1b24af32856d8a04922788537defd (patch) | |
tree | 29ca2b1c64d31ae235d34fae814b2deced1286fa | |
parent | 4932a9187df3fab8adcd7b87fd11af722973b6fc (diff) |
net: mvneta: add EEE support
Add support for EEE to mvneta.
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | drivers/net/ethernet/marvell/mvneta.c | 99 |
1 files changed, 94 insertions, 5 deletions
diff --git a/drivers/net/ethernet/marvell/mvneta.c b/drivers/net/ethernet/marvell/mvneta.c index 0b8701d3ba38..44d665887b50 100644 --- a/drivers/net/ethernet/marvell/mvneta.c +++ b/drivers/net/ethernet/marvell/mvneta.c | |||
@@ -244,6 +244,12 @@ | |||
244 | #define MVNETA_TXQ_TOKEN_SIZE_REG(q) (0x3e40 + ((q) << 2)) | 244 | #define MVNETA_TXQ_TOKEN_SIZE_REG(q) (0x3e40 + ((q) << 2)) |
245 | #define MVNETA_TXQ_TOKEN_SIZE_MAX 0x7fffffff | 245 | #define MVNETA_TXQ_TOKEN_SIZE_MAX 0x7fffffff |
246 | 246 | ||
247 | #define MVNETA_LPI_CTRL_0 0x2cc0 | ||
248 | #define MVNETA_LPI_CTRL_1 0x2cc4 | ||
249 | #define MVNETA_LPI_REQUEST_ENABLE BIT(0) | ||
250 | #define MVNETA_LPI_CTRL_2 0x2cc8 | ||
251 | #define MVNETA_LPI_STATUS 0x2ccc | ||
252 | |||
247 | #define MVNETA_CAUSE_TXQ_SENT_DESC_ALL_MASK 0xff | 253 | #define MVNETA_CAUSE_TXQ_SENT_DESC_ALL_MASK 0xff |
248 | 254 | ||
249 | /* Descriptor ring Macros */ | 255 | /* Descriptor ring Macros */ |
@@ -320,6 +326,11 @@ | |||
320 | #define MVNETA_RX_GET_BM_POOL_ID(rxd) \ | 326 | #define MVNETA_RX_GET_BM_POOL_ID(rxd) \ |
321 | (((rxd)->status & MVNETA_RXD_BM_POOL_MASK) >> MVNETA_RXD_BM_POOL_SHIFT) | 327 | (((rxd)->status & MVNETA_RXD_BM_POOL_MASK) >> MVNETA_RXD_BM_POOL_SHIFT) |
322 | 328 | ||
329 | enum { | ||
330 | ETHTOOL_STAT_EEE_WAKEUP, | ||
331 | ETHTOOL_MAX_STATS, | ||
332 | }; | ||
333 | |||
323 | struct mvneta_statistic { | 334 | struct mvneta_statistic { |
324 | unsigned short offset; | 335 | unsigned short offset; |
325 | unsigned short type; | 336 | unsigned short type; |
@@ -328,6 +339,7 @@ struct mvneta_statistic { | |||
328 | 339 | ||
329 | #define T_REG_32 32 | 340 | #define T_REG_32 32 |
330 | #define T_REG_64 64 | 341 | #define T_REG_64 64 |
342 | #define T_SW 1 | ||
331 | 343 | ||
332 | static const struct mvneta_statistic mvneta_statistics[] = { | 344 | static const struct mvneta_statistic mvneta_statistics[] = { |
333 | { 0x3000, T_REG_64, "good_octets_received", }, | 345 | { 0x3000, T_REG_64, "good_octets_received", }, |
@@ -362,6 +374,7 @@ static const struct mvneta_statistic mvneta_statistics[] = { | |||
362 | { 0x304c, T_REG_32, "broadcast_frames_sent", }, | 374 | { 0x304c, T_REG_32, "broadcast_frames_sent", }, |
363 | { 0x3054, T_REG_32, "fc_sent", }, | 375 | { 0x3054, T_REG_32, "fc_sent", }, |
364 | { 0x300c, T_REG_32, "internal_mac_transmit_err", }, | 376 | { 0x300c, T_REG_32, "internal_mac_transmit_err", }, |
377 | { ETHTOOL_STAT_EEE_WAKEUP, T_SW, "eee_wakeup_errors", }, | ||
365 | }; | 378 | }; |
366 | 379 | ||
367 | struct mvneta_pcpu_stats { | 380 | struct mvneta_pcpu_stats { |
@@ -424,6 +437,10 @@ struct mvneta_port { | |||
424 | struct mvneta_bm_pool *pool_short; | 437 | struct mvneta_bm_pool *pool_short; |
425 | int bm_win_id; | 438 | int bm_win_id; |
426 | 439 | ||
440 | bool eee_enabled; | ||
441 | bool eee_active; | ||
442 | bool tx_lpi_enabled; | ||
443 | |||
427 | u64 ethtool_stats[ARRAY_SIZE(mvneta_statistics)]; | 444 | u64 ethtool_stats[ARRAY_SIZE(mvneta_statistics)]; |
428 | 445 | ||
429 | u32 indir[MVNETA_RSS_LU_TABLE_SIZE]; | 446 | u32 indir[MVNETA_RSS_LU_TABLE_SIZE]; |
@@ -3369,6 +3386,18 @@ static void mvneta_mac_config(struct net_device *ndev, unsigned int mode, | |||
3369 | } | 3386 | } |
3370 | } | 3387 | } |
3371 | 3388 | ||
3389 | static void mvneta_set_eee(struct mvneta_port *pp, bool enable) | ||
3390 | { | ||
3391 | u32 lpi_ctl1; | ||
3392 | |||
3393 | lpi_ctl1 = mvreg_read(pp, MVNETA_LPI_CTRL_1); | ||
3394 | if (enable) | ||
3395 | lpi_ctl1 |= MVNETA_LPI_REQUEST_ENABLE; | ||
3396 | else | ||
3397 | lpi_ctl1 &= ~MVNETA_LPI_REQUEST_ENABLE; | ||
3398 | mvreg_write(pp, MVNETA_LPI_CTRL_1, lpi_ctl1); | ||
3399 | } | ||
3400 | |||
3372 | static void mvneta_mac_link_down(struct net_device *ndev, unsigned int mode) | 3401 | static void mvneta_mac_link_down(struct net_device *ndev, unsigned int mode) |
3373 | { | 3402 | { |
3374 | struct mvneta_port *pp = netdev_priv(ndev); | 3403 | struct mvneta_port *pp = netdev_priv(ndev); |
@@ -3382,6 +3411,9 @@ static void mvneta_mac_link_down(struct net_device *ndev, unsigned int mode) | |||
3382 | val |= MVNETA_GMAC_FORCE_LINK_DOWN; | 3411 | val |= MVNETA_GMAC_FORCE_LINK_DOWN; |
3383 | mvreg_write(pp, MVNETA_GMAC_AUTONEG_CONFIG, val); | 3412 | mvreg_write(pp, MVNETA_GMAC_AUTONEG_CONFIG, val); |
3384 | } | 3413 | } |
3414 | |||
3415 | pp->eee_active = false; | ||
3416 | mvneta_set_eee(pp, false); | ||
3385 | } | 3417 | } |
3386 | 3418 | ||
3387 | static void mvneta_mac_link_up(struct net_device *ndev, unsigned int mode, | 3419 | static void mvneta_mac_link_up(struct net_device *ndev, unsigned int mode, |
@@ -3398,6 +3430,11 @@ static void mvneta_mac_link_up(struct net_device *ndev, unsigned int mode, | |||
3398 | } | 3430 | } |
3399 | 3431 | ||
3400 | mvneta_port_up(pp); | 3432 | mvneta_port_up(pp); |
3433 | |||
3434 | if (phy && pp->eee_enabled) { | ||
3435 | pp->eee_active = phy_init_eee(phy, 0) >= 0; | ||
3436 | mvneta_set_eee(pp, pp->eee_active && pp->tx_lpi_enabled); | ||
3437 | } | ||
3401 | } | 3438 | } |
3402 | 3439 | ||
3403 | static const struct phylink_mac_ops mvneta_phylink_ops = { | 3440 | static const struct phylink_mac_ops mvneta_phylink_ops = { |
@@ -3859,26 +3896,35 @@ static void mvneta_ethtool_update_stats(struct mvneta_port *pp) | |||
3859 | { | 3896 | { |
3860 | const struct mvneta_statistic *s; | 3897 | const struct mvneta_statistic *s; |
3861 | void __iomem *base = pp->base; | 3898 | void __iomem *base = pp->base; |
3862 | u32 high, low, val; | 3899 | u32 high, low; |
3863 | u64 val64; | 3900 | u64 val; |
3864 | int i; | 3901 | int i; |
3865 | 3902 | ||
3866 | for (i = 0, s = mvneta_statistics; | 3903 | for (i = 0, s = mvneta_statistics; |
3867 | s < mvneta_statistics + ARRAY_SIZE(mvneta_statistics); | 3904 | s < mvneta_statistics + ARRAY_SIZE(mvneta_statistics); |
3868 | s++, i++) { | 3905 | s++, i++) { |
3906 | val = 0; | ||
3907 | |||
3869 | switch (s->type) { | 3908 | switch (s->type) { |
3870 | case T_REG_32: | 3909 | case T_REG_32: |
3871 | val = readl_relaxed(base + s->offset); | 3910 | val = readl_relaxed(base + s->offset); |
3872 | pp->ethtool_stats[i] += val; | ||
3873 | break; | 3911 | break; |
3874 | case T_REG_64: | 3912 | case T_REG_64: |
3875 | /* Docs say to read low 32-bit then high */ | 3913 | /* Docs say to read low 32-bit then high */ |
3876 | low = readl_relaxed(base + s->offset); | 3914 | low = readl_relaxed(base + s->offset); |
3877 | high = readl_relaxed(base + s->offset + 4); | 3915 | high = readl_relaxed(base + s->offset + 4); |
3878 | val64 = (u64)high << 32 | low; | 3916 | val = (u64)high << 32 | low; |
3879 | pp->ethtool_stats[i] += val64; | 3917 | break; |
3918 | case T_SW: | ||
3919 | switch (s->offset) { | ||
3920 | case ETHTOOL_STAT_EEE_WAKEUP: | ||
3921 | val = phylink_get_eee_err(pp->phylink); | ||
3922 | break; | ||
3923 | } | ||
3880 | break; | 3924 | break; |
3881 | } | 3925 | } |
3926 | |||
3927 | pp->ethtool_stats[i] += val; | ||
3882 | } | 3928 | } |
3883 | } | 3929 | } |
3884 | 3930 | ||
@@ -4031,6 +4077,47 @@ static int mvneta_ethtool_set_wol(struct net_device *dev, | |||
4031 | return ret; | 4077 | return ret; |
4032 | } | 4078 | } |
4033 | 4079 | ||
4080 | static int mvneta_ethtool_get_eee(struct net_device *dev, | ||
4081 | struct ethtool_eee *eee) | ||
4082 | { | ||
4083 | struct mvneta_port *pp = netdev_priv(dev); | ||
4084 | u32 lpi_ctl0; | ||
4085 | |||
4086 | lpi_ctl0 = mvreg_read(pp, MVNETA_LPI_CTRL_0); | ||
4087 | |||
4088 | eee->eee_enabled = pp->eee_enabled; | ||
4089 | eee->eee_active = pp->eee_active; | ||
4090 | eee->tx_lpi_enabled = pp->tx_lpi_enabled; | ||
4091 | eee->tx_lpi_timer = (lpi_ctl0) >> 8; // * scale; | ||
4092 | |||
4093 | return phylink_ethtool_get_eee(pp->phylink, eee); | ||
4094 | } | ||
4095 | |||
4096 | static int mvneta_ethtool_set_eee(struct net_device *dev, | ||
4097 | struct ethtool_eee *eee) | ||
4098 | { | ||
4099 | struct mvneta_port *pp = netdev_priv(dev); | ||
4100 | u32 lpi_ctl0; | ||
4101 | |||
4102 | /* The Armada 37x documents do not give limits for this other than | ||
4103 | * it being an 8-bit register. */ | ||
4104 | if (eee->tx_lpi_enabled && | ||
4105 | (eee->tx_lpi_timer < 0 || eee->tx_lpi_timer > 255)) | ||
4106 | return -EINVAL; | ||
4107 | |||
4108 | lpi_ctl0 = mvreg_read(pp, MVNETA_LPI_CTRL_0); | ||
4109 | lpi_ctl0 &= ~(0xff << 8); | ||
4110 | lpi_ctl0 |= eee->tx_lpi_timer << 8; | ||
4111 | mvreg_write(pp, MVNETA_LPI_CTRL_0, lpi_ctl0); | ||
4112 | |||
4113 | pp->eee_enabled = eee->eee_enabled; | ||
4114 | pp->tx_lpi_enabled = eee->tx_lpi_enabled; | ||
4115 | |||
4116 | mvneta_set_eee(pp, eee->tx_lpi_enabled && eee->eee_enabled); | ||
4117 | |||
4118 | return phylink_ethtool_set_eee(pp->phylink, eee); | ||
4119 | } | ||
4120 | |||
4034 | static const struct net_device_ops mvneta_netdev_ops = { | 4121 | static const struct net_device_ops mvneta_netdev_ops = { |
4035 | .ndo_open = mvneta_open, | 4122 | .ndo_open = mvneta_open, |
4036 | .ndo_stop = mvneta_stop, | 4123 | .ndo_stop = mvneta_stop, |
@@ -4064,6 +4151,8 @@ static const struct ethtool_ops mvneta_eth_tool_ops = { | |||
4064 | .set_link_ksettings = mvneta_ethtool_set_link_ksettings, | 4151 | .set_link_ksettings = mvneta_ethtool_set_link_ksettings, |
4065 | .get_wol = mvneta_ethtool_get_wol, | 4152 | .get_wol = mvneta_ethtool_get_wol, |
4066 | .set_wol = mvneta_ethtool_set_wol, | 4153 | .set_wol = mvneta_ethtool_set_wol, |
4154 | .get_eee = mvneta_ethtool_get_eee, | ||
4155 | .set_eee = mvneta_ethtool_set_eee, | ||
4067 | }; | 4156 | }; |
4068 | 4157 | ||
4069 | /* Initialize hw */ | 4158 | /* Initialize hw */ |