|
25 | 25 |
|
26 | 26 | #include "mt7530.h" |
27 | 27 |
|
| 28 | +#define MT7530_STATS_POLL_INTERVAL (1 * HZ) |
| 29 | +#define MT7530_STATS_RATE_LIMIT (HZ / 10) |
| 30 | + |
28 | 31 | static struct mt753x_pcs *pcs_to_mt753x_pcs(struct phylink_pcs *pcs) |
29 | 32 | { |
30 | 33 | return container_of(pcs, struct mt753x_pcs, pcs); |
@@ -906,10 +909,9 @@ static void mt7530_get_rmon_stats(struct dsa_switch *ds, int port, |
906 | 909 | *ranges = mt7530_rmon_ranges; |
907 | 910 | } |
908 | 911 |
|
909 | | -static void mt7530_get_stats64(struct dsa_switch *ds, int port, |
910 | | - struct rtnl_link_stats64 *storage) |
| 912 | +static void mt7530_read_port_stats64(struct mt7530_priv *priv, int port, |
| 913 | + struct rtnl_link_stats64 *storage) |
911 | 914 | { |
912 | | - struct mt7530_priv *priv = ds->priv; |
913 | 915 | uint64_t data; |
914 | 916 |
|
915 | 917 | /* MIB counter doesn't provide a FramesTransmittedOK but instead |
@@ -951,6 +953,54 @@ static void mt7530_get_stats64(struct dsa_switch *ds, int port, |
951 | 953 | &storage->rx_crc_errors); |
952 | 954 | } |
953 | 955 |
|
| 956 | +static void mt7530_stats_refresh(struct mt7530_priv *priv) |
| 957 | +{ |
| 958 | + struct rtnl_link_stats64 stats = {}; |
| 959 | + struct dsa_port *dp; |
| 960 | + int port; |
| 961 | + |
| 962 | + dsa_switch_for_each_user_port(dp, priv->ds) { |
| 963 | + port = dp->index; |
| 964 | + |
| 965 | + mt7530_read_port_stats64(priv, port, &stats); |
| 966 | + |
| 967 | + spin_lock_bh(&priv->stats_lock); |
| 968 | + priv->ports[port].stats = stats; |
| 969 | + priv->stats_last = jiffies; |
| 970 | + spin_unlock_bh(&priv->stats_lock); |
| 971 | + } |
| 972 | +} |
| 973 | + |
| 974 | +static void mt7530_stats_poll(struct work_struct *work) |
| 975 | +{ |
| 976 | + struct mt7530_priv *priv = container_of(work, struct mt7530_priv, |
| 977 | + stats_work.work); |
| 978 | + |
| 979 | + mt7530_stats_refresh(priv); |
| 980 | + schedule_delayed_work(&priv->stats_work, |
| 981 | + MT7530_STATS_POLL_INTERVAL); |
| 982 | +} |
| 983 | + |
| 984 | +static void mt7530_get_stats64(struct dsa_switch *ds, int port, |
| 985 | + struct rtnl_link_stats64 *storage) |
| 986 | +{ |
| 987 | + struct mt7530_priv *priv = ds->priv; |
| 988 | + bool refresh; |
| 989 | + |
| 990 | + if (priv->bus) { |
| 991 | + spin_lock_bh(&priv->stats_lock); |
| 992 | + *storage = priv->ports[port].stats; |
| 993 | + refresh = time_after(jiffies, priv->stats_last + |
| 994 | + MT7530_STATS_RATE_LIMIT); |
| 995 | + spin_unlock_bh(&priv->stats_lock); |
| 996 | + if (refresh) |
| 997 | + mod_delayed_work(system_percpu_wq, |
| 998 | + &priv->stats_work, 0); |
| 999 | + } else { |
| 1000 | + mt7530_read_port_stats64(priv, port, storage); |
| 1001 | + } |
| 1002 | +} |
| 1003 | + |
954 | 1004 | static void mt7530_get_eth_ctrl_stats(struct dsa_switch *ds, int port, |
955 | 1005 | struct ethtool_eth_ctrl_stats *ctrl_stats) |
956 | 1006 | { |
@@ -3137,9 +3187,24 @@ mt753x_setup(struct dsa_switch *ds) |
3137 | 3187 | if (ret && priv->irq_domain) |
3138 | 3188 | mt7530_free_mdio_irq(priv); |
3139 | 3189 |
|
| 3190 | + if (!ret && priv->bus) { |
| 3191 | + mt7530_stats_refresh(priv); |
| 3192 | + schedule_delayed_work(&priv->stats_work, |
| 3193 | + MT7530_STATS_POLL_INTERVAL); |
| 3194 | + } |
| 3195 | + |
3140 | 3196 | return ret; |
3141 | 3197 | } |
3142 | 3198 |
|
| 3199 | +static void |
| 3200 | +mt753x_teardown(struct dsa_switch *ds) |
| 3201 | +{ |
| 3202 | + struct mt7530_priv *priv = ds->priv; |
| 3203 | + |
| 3204 | + if (priv->bus) |
| 3205 | + cancel_delayed_work_sync(&priv->stats_work); |
| 3206 | +} |
| 3207 | + |
3143 | 3208 | static int mt753x_set_mac_eee(struct dsa_switch *ds, int port, |
3144 | 3209 | struct ethtool_keee *e) |
3145 | 3210 | { |
@@ -3257,6 +3322,7 @@ static int mt7988_setup(struct dsa_switch *ds) |
3257 | 3322 | static const struct dsa_switch_ops mt7530_switch_ops = { |
3258 | 3323 | .get_tag_protocol = mtk_get_tag_protocol, |
3259 | 3324 | .setup = mt753x_setup, |
| 3325 | + .teardown = mt753x_teardown, |
3260 | 3326 | .preferred_default_local_cpu_port = mt753x_preferred_default_local_cpu_port, |
3261 | 3327 | .get_strings = mt7530_get_strings, |
3262 | 3328 | .get_ethtool_stats = mt7530_get_ethtool_stats, |
@@ -3395,6 +3461,9 @@ mt7530_probe_common(struct mt7530_priv *priv) |
3395 | 3461 | priv->ds->ops = &mt7530_switch_ops; |
3396 | 3462 | priv->ds->phylink_mac_ops = &mt753x_phylink_mac_ops; |
3397 | 3463 | mutex_init(&priv->reg_mutex); |
| 3464 | + spin_lock_init(&priv->stats_lock); |
| 3465 | + INIT_DELAYED_WORK(&priv->stats_work, mt7530_stats_poll); |
| 3466 | + |
3398 | 3467 | dev_set_drvdata(dev, priv); |
3399 | 3468 |
|
3400 | 3469 | return 0; |
|
0 commit comments