aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net
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
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')
-rw-r--r--drivers/net/dsa/microchip/ksz9477.c123
-rw-r--r--drivers/net/dsa/microchip/ksz_common.c103
-rw-r--r--drivers/net/dsa/microchip/ksz_common.h18
-rw-r--r--drivers/net/dsa/microchip/ksz_priv.h9
4 files changed, 205 insertions, 48 deletions
diff --git a/drivers/net/dsa/microchip/ksz9477.c b/drivers/net/dsa/microchip/ksz9477.c
index 4573b6ed2c4f..94cd38515ab8 100644
--- a/drivers/net/dsa/microchip/ksz9477.c
+++ b/drivers/net/dsa/microchip/ksz9477.c
@@ -10,6 +10,7 @@
10#include <linux/gpio.h> 10#include <linux/gpio.h>
11#include <linux/kernel.h> 11#include <linux/kernel.h>
12#include <linux/module.h> 12#include <linux/module.h>
13#include <linux/iopoll.h>
13#include <linux/platform_data/microchip-ksz.h> 14#include <linux/platform_data/microchip-ksz.h>
14#include <linux/phy.h> 15#include <linux/phy.h>
15#include <linux/etherdevice.h> 16#include <linux/etherdevice.h>
@@ -18,8 +19,8 @@
18#include <net/switchdev.h> 19#include <net/switchdev.h>
19 20
20#include "ksz_priv.h" 21#include "ksz_priv.h"
21#include "ksz_common.h"
22#include "ksz9477_reg.h" 22#include "ksz9477_reg.h"
23#include "ksz_common.h"
23 24
24static const struct { 25static const struct {
25 int index; 26 int index;
@@ -259,6 +260,75 @@ static int ksz9477_reset_switch(struct ksz_device *dev)
259 return 0; 260 return 0;
260} 261}
261 262
263static void ksz9477_r_mib_cnt(struct ksz_device *dev, int port, u16 addr,
264 u64 *cnt)
265{
266 struct ksz_poll_ctx ctx = {
267 .dev = dev,
268 .port = port,
269 .offset = REG_PORT_MIB_CTRL_STAT__4,
270 };
271 struct ksz_port *p = &dev->ports[port];
272 u32 data;
273 int ret;
274
275 /* retain the flush/freeze bit */
276 data = p->freeze ? MIB_COUNTER_FLUSH_FREEZE : 0;
277 data |= MIB_COUNTER_READ;
278 data |= (addr << MIB_COUNTER_INDEX_S);
279 ksz_pwrite32(dev, port, REG_PORT_MIB_CTRL_STAT__4, data);
280
281 ret = readx_poll_timeout(ksz_pread32_poll, &ctx, data,
282 !(data & MIB_COUNTER_READ), 10, 1000);
283
284 /* failed to read MIB. get out of loop */
285 if (ret < 0) {
286 dev_dbg(dev->dev, "Failed to get MIB\n");
287 return;
288 }
289
290 /* count resets upon read */
291 ksz_pread32(dev, port, REG_PORT_MIB_DATA, &data);
292 *cnt += data;
293}
294
295static void ksz9477_r_mib_pkt(struct ksz_device *dev, int port, u16 addr,
296 u64 *dropped, u64 *cnt)
297{
298 addr = ksz9477_mib_names[addr].index;
299 ksz9477_r_mib_cnt(dev, port, addr, cnt);
300}
301
302static void ksz9477_freeze_mib(struct ksz_device *dev, int port, bool freeze)
303{
304 u32 val = freeze ? MIB_COUNTER_FLUSH_FREEZE : 0;
305 struct ksz_port *p = &dev->ports[port];
306
307 /* enable/disable the port for flush/freeze function */
308 mutex_lock(&p->mib.cnt_mutex);
309 ksz_pwrite32(dev, port, REG_PORT_MIB_CTRL_STAT__4, val);
310
311 /* used by MIB counter reading code to know freeze is enabled */
312 p->freeze = freeze;
313 mutex_unlock(&p->mib.cnt_mutex);
314}
315
316static void ksz9477_port_init_cnt(struct ksz_device *dev, int port)
317{
318 struct ksz_port_mib *mib = &dev->ports[port].mib;
319
320 /* flush all enabled port MIB counters */
321 mutex_lock(&mib->cnt_mutex);
322 ksz_pwrite32(dev, port, REG_PORT_MIB_CTRL_STAT__4,
323 MIB_COUNTER_FLUSH_FREEZE);
324 ksz_write8(dev, REG_SW_MAC_CTRL_6, SW_MIB_COUNTER_FLUSH);
325 ksz_pwrite32(dev, port, REG_PORT_MIB_CTRL_STAT__4, 0);
326 mutex_unlock(&mib->cnt_mutex);
327
328 mib->cnt_ptr = 0;
329 memset(mib->counters, 0, dev->mib_cnt * sizeof(u64));
330}
331
262static enum dsa_tag_protocol ksz9477_get_tag_protocol(struct dsa_switch *ds, 332static enum dsa_tag_protocol ksz9477_get_tag_protocol(struct dsa_switch *ds,
263 int port) 333 int port)
264{ 334{
@@ -342,47 +412,6 @@ static void ksz9477_get_strings(struct dsa_switch *ds, int port,
342 } 412 }
343} 413}
344 414
345static void ksz_get_ethtool_stats(struct dsa_switch *ds, int port,
346 uint64_t *buf)
347{
348 struct ksz_device *dev = ds->priv;
349 int i;
350 u32 data;
351 int timeout;
352
353 mutex_lock(&dev->stats_mutex);
354
355 for (i = 0; i < TOTAL_SWITCH_COUNTER_NUM; i++) {
356 data = MIB_COUNTER_READ;
357 data |= ((ksz9477_mib_names[i].index & 0xFF) <<
358 MIB_COUNTER_INDEX_S);
359 ksz_pwrite32(dev, port, REG_PORT_MIB_CTRL_STAT__4, data);
360
361 timeout = 1000;
362 do {
363 ksz_pread32(dev, port, REG_PORT_MIB_CTRL_STAT__4,
364 &data);
365 usleep_range(1, 10);
366 if (!(data & MIB_COUNTER_READ))
367 break;
368 } while (timeout-- > 0);
369
370 /* failed to read MIB. get out of loop */
371 if (!timeout) {
372 dev_dbg(dev->dev, "Failed to get MIB\n");
373 break;
374 }
375
376 /* count resets upon read */
377 ksz_pread32(dev, port, REG_PORT_MIB_DATA, &data);
378
379 dev->mib_value[i] += (uint64_t)data;
380 buf[i] = dev->mib_value[i];
381 }
382
383 mutex_unlock(&dev->stats_mutex);
384}
385
386static void ksz9477_cfg_port_member(struct ksz_device *dev, int port, 415static void ksz9477_cfg_port_member(struct ksz_device *dev, int port,
387 u8 member) 416 u8 member)
388{ 417{
@@ -1151,9 +1180,14 @@ static int ksz9477_setup(struct dsa_switch *ds)
1151 /* queue based egress rate limit */ 1180 /* queue based egress rate limit */
1152 ksz_cfg(dev, REG_SW_MAC_CTRL_5, SW_OUT_RATE_LIMIT_QUEUE_BASED, true); 1181 ksz_cfg(dev, REG_SW_MAC_CTRL_5, SW_OUT_RATE_LIMIT_QUEUE_BASED, true);
1153 1182
1183 /* enable global MIB counter freeze function */
1184 ksz_cfg(dev, REG_SW_MAC_CTRL_6, SW_MIB_COUNTER_FREEZE, true);
1185
1154 /* start switch */ 1186 /* start switch */
1155 ksz_cfg(dev, REG_SW_OPERATION, SW_START, true); 1187 ksz_cfg(dev, REG_SW_OPERATION, SW_START, true);
1156 1188
1189 ksz_init_mib_timer(dev);
1190
1157 return 0; 1191 return 0;
1158} 1192}
1159 1193
@@ -1287,6 +1321,7 @@ static int ksz9477_switch_init(struct ksz_device *dev)
1287 if (!dev->ports) 1321 if (!dev->ports)
1288 return -ENOMEM; 1322 return -ENOMEM;
1289 for (i = 0; i < dev->mib_port_cnt; i++) { 1323 for (i = 0; i < dev->mib_port_cnt; i++) {
1324 mutex_init(&dev->ports[i].mib.cnt_mutex);
1290 dev->ports[i].mib.counters = 1325 dev->ports[i].mib.counters =
1291 devm_kzalloc(dev->dev, 1326 devm_kzalloc(dev->dev,
1292 sizeof(u64) * 1327 sizeof(u64) *
@@ -1311,6 +1346,10 @@ static const struct ksz_dev_ops ksz9477_dev_ops = {
1311 .flush_dyn_mac_table = ksz9477_flush_dyn_mac_table, 1346 .flush_dyn_mac_table = ksz9477_flush_dyn_mac_table,
1312 .phy_setup = ksz9477_phy_setup, 1347 .phy_setup = ksz9477_phy_setup,
1313 .port_setup = ksz9477_port_setup, 1348 .port_setup = ksz9477_port_setup,
1349 .r_mib_cnt = ksz9477_r_mib_cnt,
1350 .r_mib_pkt = ksz9477_r_mib_pkt,
1351 .freeze_mib = ksz9477_freeze_mib,
1352 .port_init_cnt = ksz9477_port_init_cnt,
1314 .shutdown = ksz9477_reset_switch, 1353 .shutdown = ksz9477_reset_switch,
1315 .detect = ksz9477_switch_detect, 1354 .detect = ksz9477_switch_detect,
1316 .init = ksz9477_switch_init, 1355 .init = ksz9477_switch_init,
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
diff --git a/drivers/net/dsa/microchip/ksz_common.h b/drivers/net/dsa/microchip/ksz_common.h
index 2dd832de0d52..f45a55369e4b 100644
--- a/drivers/net/dsa/microchip/ksz_common.h
+++ b/drivers/net/dsa/microchip/ksz_common.h
@@ -1,19 +1,21 @@
1/* SPDX-License-Identifier: GPL-2.0 1/* SPDX-License-Identifier: GPL-2.0
2 * Microchip switch driver common header 2 * Microchip switch driver common header
3 * 3 *
4 * Copyright (C) 2017-2018 Microchip Technology Inc. 4 * Copyright (C) 2017-2019 Microchip Technology Inc.
5 */ 5 */
6 6
7#ifndef __KSZ_COMMON_H 7#ifndef __KSZ_COMMON_H
8#define __KSZ_COMMON_H 8#define __KSZ_COMMON_H
9 9
10void ksz_update_port_member(struct ksz_device *dev, int port); 10void ksz_update_port_member(struct ksz_device *dev, int port);
11void ksz_init_mib_timer(struct ksz_device *dev);
11 12
12/* Common DSA access functions */ 13/* Common DSA access functions */
13 14
14int ksz_phy_read16(struct dsa_switch *ds, int addr, int reg); 15int ksz_phy_read16(struct dsa_switch *ds, int addr, int reg);
15int ksz_phy_write16(struct dsa_switch *ds, int addr, int reg, u16 val); 16int ksz_phy_write16(struct dsa_switch *ds, int addr, int reg, u16 val);
16int ksz_sset_count(struct dsa_switch *ds, int port, int sset); 17int ksz_sset_count(struct dsa_switch *ds, int port, int sset);
18void ksz_get_ethtool_stats(struct dsa_switch *ds, int port, uint64_t *buf);
17int ksz_port_bridge_join(struct dsa_switch *ds, int port, 19int ksz_port_bridge_join(struct dsa_switch *ds, int port,
18 struct net_device *br); 20 struct net_device *br);
19void ksz_port_bridge_leave(struct dsa_switch *ds, int port, 21void ksz_port_bridge_leave(struct dsa_switch *ds, int port,
@@ -211,4 +213,18 @@ static void ksz_port_cfg(struct ksz_device *dev, int port, int offset, u8 bits,
211 ksz_write8(dev, addr, data); 213 ksz_write8(dev, addr, data);
212} 214}
213 215
216struct ksz_poll_ctx {
217 struct ksz_device *dev;
218 int port;
219 int offset;
220};
221
222static inline u32 ksz_pread32_poll(struct ksz_poll_ctx *ctx)
223{
224 u32 data;
225
226 ksz_pread32(ctx->dev, ctx->port, ctx->offset, &data);
227 return data;
228}
229
214#endif 230#endif
diff --git a/drivers/net/dsa/microchip/ksz_priv.h b/drivers/net/dsa/microchip/ksz_priv.h
index 0fdc58bdd503..1d2d98f35bb0 100644
--- a/drivers/net/dsa/microchip/ksz_priv.h
+++ b/drivers/net/dsa/microchip/ksz_priv.h
@@ -14,8 +14,6 @@
14#include <linux/etherdevice.h> 14#include <linux/etherdevice.h>
15#include <net/dsa.h> 15#include <net/dsa.h>
16 16
17#include "ksz9477_reg.h"
18
19struct ksz_io_ops; 17struct ksz_io_ops;
20 18
21struct vlan_table { 19struct vlan_table {
@@ -23,6 +21,7 @@ struct vlan_table {
23}; 21};
24 22
25struct ksz_port_mib { 23struct ksz_port_mib {
24 struct mutex cnt_mutex; /* structure access */
26 u8 cnt_ptr; 25 u8 cnt_ptr;
27 u64 *counters; 26 u64 *counters;
28}; 27};
@@ -38,7 +37,8 @@ struct ksz_port {
38 u32 fiber:1; /* port is fiber */ 37 u32 fiber:1; /* port is fiber */
39 u32 sgmii:1; /* port is SGMII */ 38 u32 sgmii:1; /* port is SGMII */
40 u32 force:1; 39 u32 force:1;
41 u32 link_just_down:1; /* link just goes down */ 40 u32 read:1; /* read MIB counters in background */
41 u32 freeze:1; /* MIB counter freeze is enabled */
42 42
43 struct ksz_port_mib mib; 43 struct ksz_port_mib mib;
44}; 44};
@@ -79,8 +79,6 @@ struct ksz_device {
79 79
80 struct vlan_table *vlan_cache; 80 struct vlan_table *vlan_cache;
81 81
82 u64 mib_value[TOTAL_SWITCH_COUNTER_NUM];
83
84 u8 *txbuf; 82 u8 *txbuf;
85 83
86 struct ksz_port *ports; 84 struct ksz_port *ports;
@@ -153,6 +151,7 @@ struct ksz_dev_ops {
153 u64 *cnt); 151 u64 *cnt);
154 void (*r_mib_pkt)(struct ksz_device *dev, int port, u16 addr, 152 void (*r_mib_pkt)(struct ksz_device *dev, int port, u16 addr,
155 u64 *dropped, u64 *cnt); 153 u64 *dropped, u64 *cnt);
154 void (*freeze_mib)(struct ksz_device *dev, int port, bool freeze);
156 void (*port_init_cnt)(struct ksz_device *dev, int port); 155 void (*port_init_cnt)(struct ksz_device *dev, int port);
157 int (*shutdown)(struct ksz_device *dev); 156 int (*shutdown)(struct ksz_device *dev);
158 int (*detect)(struct ksz_device *dev); 157 int (*detect)(struct ksz_device *dev);