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>
This commit is contained in:

committed by
David S. Miller

parent
42fc6a4c61
commit
7c6ff470aa
@@ -10,6 +10,7 @@
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/iopoll.h>
|
||||
#include <linux/platform_data/microchip-ksz.h>
|
||||
#include <linux/phy.h>
|
||||
#include <linux/etherdevice.h>
|
||||
@@ -18,8 +19,8 @@
|
||||
#include <net/switchdev.h>
|
||||
|
||||
#include "ksz_priv.h"
|
||||
#include "ksz_common.h"
|
||||
#include "ksz9477_reg.h"
|
||||
#include "ksz_common.h"
|
||||
|
||||
static const struct {
|
||||
int index;
|
||||
@@ -259,6 +260,75 @@ static int ksz9477_reset_switch(struct ksz_device *dev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ksz9477_r_mib_cnt(struct ksz_device *dev, int port, u16 addr,
|
||||
u64 *cnt)
|
||||
{
|
||||
struct ksz_poll_ctx ctx = {
|
||||
.dev = dev,
|
||||
.port = port,
|
||||
.offset = REG_PORT_MIB_CTRL_STAT__4,
|
||||
};
|
||||
struct ksz_port *p = &dev->ports[port];
|
||||
u32 data;
|
||||
int ret;
|
||||
|
||||
/* retain the flush/freeze bit */
|
||||
data = p->freeze ? MIB_COUNTER_FLUSH_FREEZE : 0;
|
||||
data |= MIB_COUNTER_READ;
|
||||
data |= (addr << MIB_COUNTER_INDEX_S);
|
||||
ksz_pwrite32(dev, port, REG_PORT_MIB_CTRL_STAT__4, data);
|
||||
|
||||
ret = readx_poll_timeout(ksz_pread32_poll, &ctx, data,
|
||||
!(data & MIB_COUNTER_READ), 10, 1000);
|
||||
|
||||
/* failed to read MIB. get out of loop */
|
||||
if (ret < 0) {
|
||||
dev_dbg(dev->dev, "Failed to get MIB\n");
|
||||
return;
|
||||
}
|
||||
|
||||
/* count resets upon read */
|
||||
ksz_pread32(dev, port, REG_PORT_MIB_DATA, &data);
|
||||
*cnt += data;
|
||||
}
|
||||
|
||||
static void ksz9477_r_mib_pkt(struct ksz_device *dev, int port, u16 addr,
|
||||
u64 *dropped, u64 *cnt)
|
||||
{
|
||||
addr = ksz9477_mib_names[addr].index;
|
||||
ksz9477_r_mib_cnt(dev, port, addr, cnt);
|
||||
}
|
||||
|
||||
static void ksz9477_freeze_mib(struct ksz_device *dev, int port, bool freeze)
|
||||
{
|
||||
u32 val = freeze ? MIB_COUNTER_FLUSH_FREEZE : 0;
|
||||
struct ksz_port *p = &dev->ports[port];
|
||||
|
||||
/* enable/disable the port for flush/freeze function */
|
||||
mutex_lock(&p->mib.cnt_mutex);
|
||||
ksz_pwrite32(dev, port, REG_PORT_MIB_CTRL_STAT__4, val);
|
||||
|
||||
/* used by MIB counter reading code to know freeze is enabled */
|
||||
p->freeze = freeze;
|
||||
mutex_unlock(&p->mib.cnt_mutex);
|
||||
}
|
||||
|
||||
static void ksz9477_port_init_cnt(struct ksz_device *dev, int port)
|
||||
{
|
||||
struct ksz_port_mib *mib = &dev->ports[port].mib;
|
||||
|
||||
/* flush all enabled port MIB counters */
|
||||
mutex_lock(&mib->cnt_mutex);
|
||||
ksz_pwrite32(dev, port, REG_PORT_MIB_CTRL_STAT__4,
|
||||
MIB_COUNTER_FLUSH_FREEZE);
|
||||
ksz_write8(dev, REG_SW_MAC_CTRL_6, SW_MIB_COUNTER_FLUSH);
|
||||
ksz_pwrite32(dev, port, REG_PORT_MIB_CTRL_STAT__4, 0);
|
||||
mutex_unlock(&mib->cnt_mutex);
|
||||
|
||||
mib->cnt_ptr = 0;
|
||||
memset(mib->counters, 0, dev->mib_cnt * sizeof(u64));
|
||||
}
|
||||
|
||||
static enum dsa_tag_protocol ksz9477_get_tag_protocol(struct dsa_switch *ds,
|
||||
int port)
|
||||
{
|
||||
@@ -342,47 +412,6 @@ static void ksz9477_get_strings(struct dsa_switch *ds, int port,
|
||||
}
|
||||
}
|
||||
|
||||
static void ksz_get_ethtool_stats(struct dsa_switch *ds, int port,
|
||||
uint64_t *buf)
|
||||
{
|
||||
struct ksz_device *dev = ds->priv;
|
||||
int i;
|
||||
u32 data;
|
||||
int timeout;
|
||||
|
||||
mutex_lock(&dev->stats_mutex);
|
||||
|
||||
for (i = 0; i < TOTAL_SWITCH_COUNTER_NUM; i++) {
|
||||
data = MIB_COUNTER_READ;
|
||||
data |= ((ksz9477_mib_names[i].index & 0xFF) <<
|
||||
MIB_COUNTER_INDEX_S);
|
||||
ksz_pwrite32(dev, port, REG_PORT_MIB_CTRL_STAT__4, data);
|
||||
|
||||
timeout = 1000;
|
||||
do {
|
||||
ksz_pread32(dev, port, REG_PORT_MIB_CTRL_STAT__4,
|
||||
&data);
|
||||
usleep_range(1, 10);
|
||||
if (!(data & MIB_COUNTER_READ))
|
||||
break;
|
||||
} while (timeout-- > 0);
|
||||
|
||||
/* failed to read MIB. get out of loop */
|
||||
if (!timeout) {
|
||||
dev_dbg(dev->dev, "Failed to get MIB\n");
|
||||
break;
|
||||
}
|
||||
|
||||
/* count resets upon read */
|
||||
ksz_pread32(dev, port, REG_PORT_MIB_DATA, &data);
|
||||
|
||||
dev->mib_value[i] += (uint64_t)data;
|
||||
buf[i] = dev->mib_value[i];
|
||||
}
|
||||
|
||||
mutex_unlock(&dev->stats_mutex);
|
||||
}
|
||||
|
||||
static void ksz9477_cfg_port_member(struct ksz_device *dev, int port,
|
||||
u8 member)
|
||||
{
|
||||
@@ -1151,9 +1180,14 @@ static int ksz9477_setup(struct dsa_switch *ds)
|
||||
/* queue based egress rate limit */
|
||||
ksz_cfg(dev, REG_SW_MAC_CTRL_5, SW_OUT_RATE_LIMIT_QUEUE_BASED, true);
|
||||
|
||||
/* enable global MIB counter freeze function */
|
||||
ksz_cfg(dev, REG_SW_MAC_CTRL_6, SW_MIB_COUNTER_FREEZE, true);
|
||||
|
||||
/* start switch */
|
||||
ksz_cfg(dev, REG_SW_OPERATION, SW_START, true);
|
||||
|
||||
ksz_init_mib_timer(dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1287,6 +1321,7 @@ static int ksz9477_switch_init(struct ksz_device *dev)
|
||||
if (!dev->ports)
|
||||
return -ENOMEM;
|
||||
for (i = 0; i < dev->mib_port_cnt; i++) {
|
||||
mutex_init(&dev->ports[i].mib.cnt_mutex);
|
||||
dev->ports[i].mib.counters =
|
||||
devm_kzalloc(dev->dev,
|
||||
sizeof(u64) *
|
||||
@@ -1311,6 +1346,10 @@ static const struct ksz_dev_ops ksz9477_dev_ops = {
|
||||
.flush_dyn_mac_table = ksz9477_flush_dyn_mac_table,
|
||||
.phy_setup = ksz9477_phy_setup,
|
||||
.port_setup = ksz9477_port_setup,
|
||||
.r_mib_cnt = ksz9477_r_mib_cnt,
|
||||
.r_mib_pkt = ksz9477_r_mib_pkt,
|
||||
.freeze_mib = ksz9477_freeze_mib,
|
||||
.port_init_cnt = ksz9477_port_init_cnt,
|
||||
.shutdown = ksz9477_reset_switch,
|
||||
.detect = ksz9477_switch_detect,
|
||||
.init = ksz9477_switch_init,
|
||||
|
Reference in New Issue
Block a user