aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/dsa/microchip/ksz_common.c
diff options
context:
space:
mode:
authorTristram Ha <Tristram.Ha@microchip.com>2019-02-22 19:36:48 -0500
committerDavid S. Miller <davem@davemloft.net>2019-02-24 20:49:59 -0500
commit7c6ff470aa867f53b8522a3a5c84c36ac7a20090 (patch)
tree84c02ceed3dc03618f080a027f2418c4a14f52ae /drivers/net/dsa/microchip/ksz_common.c
parent42fc6a4c613019666f2fd11bc0b542cf2f4dae24 (diff)
net: dsa: microchip: add MIB counter reading support
Add background MIB counter reading support. Port MIB counters should only be read when there is link. Otherwise it is a waste of time as hardware never increases those counters. There are exceptions as some switches keep track of dropped counts no matter what. Signed-off-by: Tristram Ha <Tristram.Ha@microchip.com> Reviewed-by: Andrew Lunn <andrew@lunn.ch> Reviewed-by: Florian Fainelli <f.fainelli@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/dsa/microchip/ksz_common.c')
-rw-r--r--drivers/net/dsa/microchip/ksz_common.c103
1 files changed, 103 insertions, 0 deletions
diff --git a/drivers/net/dsa/microchip/ksz_common.c b/drivers/net/dsa/microchip/ksz_common.c
index 6f728429eec6..eecfbf30cdc2 100644
--- a/drivers/net/dsa/microchip/ksz_common.c
+++ b/drivers/net/dsa/microchip/ksz_common.c
@@ -40,6 +40,85 @@ void ksz_update_port_member(struct ksz_device *dev, int port)
40} 40}
41EXPORT_SYMBOL_GPL(ksz_update_port_member); 41EXPORT_SYMBOL_GPL(ksz_update_port_member);
42 42
43static void port_r_cnt(struct ksz_device *dev, int port)
44{
45 struct ksz_port_mib *mib = &dev->ports[port].mib;
46 u64 *dropped;
47
48 /* Some ports may not have MIB counters before SWITCH_COUNTER_NUM. */
49 while (mib->cnt_ptr < dev->reg_mib_cnt) {
50 dev->dev_ops->r_mib_cnt(dev, port, mib->cnt_ptr,
51 &mib->counters[mib->cnt_ptr]);
52 ++mib->cnt_ptr;
53 }
54
55 /* last one in storage */
56 dropped = &mib->counters[dev->mib_cnt];
57
58 /* Some ports may not have MIB counters after SWITCH_COUNTER_NUM. */
59 while (mib->cnt_ptr < dev->mib_cnt) {
60 dev->dev_ops->r_mib_pkt(dev, port, mib->cnt_ptr,
61 dropped, &mib->counters[mib->cnt_ptr]);
62 ++mib->cnt_ptr;
63 }
64 mib->cnt_ptr = 0;
65}
66
67static void ksz_mib_read_work(struct work_struct *work)
68{
69 struct ksz_device *dev = container_of(work, struct ksz_device,
70 mib_read);
71 struct ksz_port_mib *mib;
72 struct ksz_port *p;
73 int i;
74
75 for (i = 0; i < dev->mib_port_cnt; i++) {
76 p = &dev->ports[i];
77 mib = &p->mib;
78 mutex_lock(&mib->cnt_mutex);
79
80 /* Only read MIB counters when the port is told to do.
81 * If not, read only dropped counters when link is not up.
82 */
83 if (!p->read) {
84 const struct dsa_port *dp = dsa_to_port(dev->ds, i);
85
86 if (!netif_carrier_ok(dp->slave))
87 mib->cnt_ptr = dev->reg_mib_cnt;
88 }
89 port_r_cnt(dev, i);
90 p->read = false;
91 mutex_unlock(&mib->cnt_mutex);
92 }
93}
94
95static void mib_monitor(struct timer_list *t)
96{
97 struct ksz_device *dev = from_timer(dev, t, mib_read_timer);
98
99 mod_timer(&dev->mib_read_timer, jiffies + dev->mib_read_interval);
100 schedule_work(&dev->mib_read);
101}
102
103void ksz_init_mib_timer(struct ksz_device *dev)
104{
105 int i;
106
107 /* Read MIB counters every 30 seconds to avoid overflow. */
108 dev->mib_read_interval = msecs_to_jiffies(30000);
109
110 INIT_WORK(&dev->mib_read, ksz_mib_read_work);
111 timer_setup(&dev->mib_read_timer, mib_monitor, 0);
112
113 for (i = 0; i < dev->mib_port_cnt; i++)
114 dev->dev_ops->port_init_cnt(dev, i);
115
116 /* Start the timer 2 seconds later. */
117 dev->mib_read_timer.expires = jiffies + msecs_to_jiffies(2000);
118 add_timer(&dev->mib_read_timer);
119}
120EXPORT_SYMBOL_GPL(ksz_init_mib_timer);
121
43int ksz_phy_read16(struct dsa_switch *ds, int addr, int reg) 122int ksz_phy_read16(struct dsa_switch *ds, int addr, int reg)
44{ 123{
45 struct ksz_device *dev = ds->priv; 124 struct ksz_device *dev = ds->priv;
@@ -72,6 +151,24 @@ int ksz_sset_count(struct dsa_switch *ds, int port, int sset)
72} 151}
73EXPORT_SYMBOL_GPL(ksz_sset_count); 152EXPORT_SYMBOL_GPL(ksz_sset_count);
74 153
154void ksz_get_ethtool_stats(struct dsa_switch *ds, int port, uint64_t *buf)
155{
156 const struct dsa_port *dp = dsa_to_port(ds, port);
157 struct ksz_device *dev = ds->priv;
158 struct ksz_port_mib *mib;
159
160 mib = &dev->ports[port].mib;
161 mutex_lock(&mib->cnt_mutex);
162
163 /* Only read dropped counters if no link. */
164 if (!netif_carrier_ok(dp->slave))
165 mib->cnt_ptr = dev->reg_mib_cnt;
166 port_r_cnt(dev, port);
167 memcpy(buf, mib->counters, dev->mib_cnt * sizeof(u64));
168 mutex_unlock(&mib->cnt_mutex);
169}
170EXPORT_SYMBOL_GPL(ksz_get_ethtool_stats);
171
75int ksz_port_bridge_join(struct dsa_switch *ds, int port, 172int ksz_port_bridge_join(struct dsa_switch *ds, int port,
76 struct net_device *br) 173 struct net_device *br)
77{ 174{
@@ -339,6 +436,12 @@ EXPORT_SYMBOL(ksz_switch_register);
339 436
340void ksz_switch_remove(struct ksz_device *dev) 437void ksz_switch_remove(struct ksz_device *dev)
341{ 438{
439 /* timer started */
440 if (dev->mib_read_timer.expires) {
441 del_timer_sync(&dev->mib_read_timer);
442 flush_work(&dev->mib_read);
443 }
444
342 dev->dev_ops->exit(dev); 445 dev->dev_ops->exit(dev);
343 dsa_unregister_switch(dev->ds); 446 dsa_unregister_switch(dev->ds);
344 447