aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRussell King <rmk+kernel@arm.linux.org.uk>2018-01-02 12:25:04 -0500
committerDavid S. Miller <davem@davemloft.net>2018-01-03 10:38:53 -0500
commit6d81f45145c1b24af32856d8a04922788537defd (patch)
tree29ca2b1c64d31ae235d34fae814b2deced1286fa
parent4932a9187df3fab8adcd7b87fd11af722973b6fc (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.c99
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
329enum {
330 ETHTOOL_STAT_EEE_WAKEUP,
331 ETHTOOL_MAX_STATS,
332};
333
323struct mvneta_statistic { 334struct 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
332static const struct mvneta_statistic mvneta_statistics[] = { 344static 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
367struct mvneta_pcpu_stats { 380struct 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
3389static 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
3372static void mvneta_mac_link_down(struct net_device *ndev, unsigned int mode) 3401static 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
3387static void mvneta_mac_link_up(struct net_device *ndev, unsigned int mode, 3419static 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
3403static const struct phylink_mac_ops mvneta_phylink_ops = { 3440static 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
4080static 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
4096static 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
4034static const struct net_device_ops mvneta_netdev_ops = { 4121static 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 */