From: Prasanna Vengateshan <prasanna.vengateshan@xxxxxxxxxxxxx> Added support for get_eth_**_stats() (phy/mac/ctrl) and get_stats64() Reused the KSZ common APIs for get_ethtool_stats() & get_sset_count() along with relevant lan937x hooks for KSZ common layer and added support for get_strings() Signed-off-by: Prasanna Vengateshan <prasanna.vengateshan@xxxxxxxxxxxxx> Signed-off-by: Arun Ramadoss <arun.ramadoss@xxxxxxxxxxxxx> Reviewed-by: Florian Fainelli <f.fainelli@xxxxxxxxx> --- drivers/net/dsa/microchip/lan937x_dev.c | 107 +++++++++++++++++++++- drivers/net/dsa/microchip/lan937x_dev.h | 47 ++++++++++ drivers/net/dsa/microchip/lan937x_main.c | 109 +++++++++++++++++++++++ 3 files changed, 262 insertions(+), 1 deletion(-) diff --git a/drivers/net/dsa/microchip/lan937x_dev.c b/drivers/net/dsa/microchip/lan937x_dev.c index 4612642e8f5e..b154bc52f64a 100644 --- a/drivers/net/dsa/microchip/lan937x_dev.c +++ b/drivers/net/dsa/microchip/lan937x_dev.c @@ -16,6 +16,45 @@ #include "ksz_common.h" #include "lan937x_dev.h" +const struct mib_names lan937x_mib_names[] = { + { 0x00, "rx_hi" }, + { 0x01, "rx_undersize" }, + { 0x02, "rx_fragments" }, + { 0x03, "rx_oversize" }, + { 0x04, "rx_jabbers" }, + { 0x05, "rx_symbol_err" }, + { 0x06, "rx_crc_err" }, + { 0x07, "rx_align_err" }, + { 0x08, "rx_mac_ctrl" }, + { 0x09, "rx_pause" }, + { 0x0A, "rx_bcast" }, + { 0x0B, "rx_mcast" }, + { 0x0C, "rx_ucast" }, + { 0x0D, "rx_64_or_less" }, + { 0x0E, "rx_65_127" }, + { 0x0F, "rx_128_255" }, + { 0x10, "rx_256_511" }, + { 0x11, "rx_512_1023" }, + { 0x12, "rx_1024_1522" }, + { 0x13, "rx_1523_2000" }, + { 0x14, "rx_2001" }, + { 0x15, "tx_hi" }, + { 0x16, "tx_late_col" }, + { 0x17, "tx_pause" }, + { 0x18, "tx_bcast" }, + { 0x19, "tx_mcast" }, + { 0x1A, "tx_ucast" }, + { 0x1B, "tx_deferred" }, + { 0x1C, "tx_total_col" }, + { 0x1D, "tx_exc_col" }, + { 0x1E, "tx_single_col" }, + { 0x1F, "tx_mult_col" }, + { 0x80, "rx_total" }, + { 0x81, "tx_total" }, + { 0x82, "rx_discards" }, + { 0x83, "tx_discards" }, +}; + int lan937x_cfg(struct ksz_device *dev, u32 addr, u8 bits, bool set) { return regmap_update_bits(dev->regmap[0], addr, bits, set ? bits : 0); @@ -93,6 +132,53 @@ static void lan937x_flush_dyn_mac_table(struct ksz_device *dev, int port) } } +static void lan937x_r_mib_cnt(struct ksz_device *dev, int port, u16 addr, + u64 *cnt) +{ + unsigned int val; + u32 data; + int ret; + + /* Enable MIB Counter read */ + data = MIB_COUNTER_READ; + data |= (addr << MIB_COUNTER_INDEX_S); + lan937x_pwrite32(dev, port, REG_PORT_MIB_CTRL_STAT, data); + + ret = regmap_read_poll_timeout(dev->regmap[2], + PORT_CTRL_ADDR(port, + REG_PORT_MIB_CTRL_STAT), + val, !(val & MIB_COUNTER_READ), + 10, 1000); + if (ret) { + dev_err(dev->dev, "Failed to get MIB\n"); + return; + } + + /* count resets upon read */ + lan937x_pread32(dev, port, REG_PORT_MIB_DATA, &data); + *cnt += data; +} + +void lan937x_r_mib_pkt(struct ksz_device *dev, int port, u16 addr, + u64 *dropped, u64 *cnt) +{ + addr = lan937x_mib_names[addr].index; + lan937x_r_mib_cnt(dev, port, addr, cnt); +} + +static void lan937x_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); + lan937x_pwrite32(dev, port, REG_PORT_MIB_CTRL_STAT, + MIB_COUNTER_FLUSH_FREEZE); + ksz_write8(dev, REG_SW_MAC_CTRL_6, SW_MIB_COUNTER_FLUSH); + lan937x_pwrite32(dev, port, REG_PORT_MIB_CTRL_STAT, 0); + mutex_unlock(&mib->cnt_mutex); +} + int lan937x_reset_switch(struct ksz_device *dev) { u32 data32; @@ -573,7 +659,7 @@ static int lan937x_mdio_register(struct ksz_device *dev) static int lan937x_switch_init(struct ksz_device *dev) { - int ret; + int i, ret; dev->ds->ops = &lan937x_switch_ops; @@ -584,12 +670,27 @@ static int lan937x_switch_init(struct ksz_device *dev) dev->port_mask = (1 << dev->port_cnt) - 1; + dev->reg_mib_cnt = SWITCH_COUNTER_NUM; + dev->mib_cnt = ARRAY_SIZE(lan937x_mib_names); + dev->ports = devm_kzalloc(dev->dev, dev->port_cnt * sizeof(struct ksz_port), GFP_KERNEL); if (!dev->ports) return -ENOMEM; + for (i = 0; i < dev->port_cnt; i++) { + spin_lock_init(&dev->ports[i].mib.stats64_lock); + mutex_init(&dev->ports[i].mib.cnt_mutex); + dev->ports[i].mib.counters = + devm_kzalloc(dev->dev, + sizeof(u64) * (dev->mib_cnt + 1), + GFP_KERNEL); + + if (!dev->ports[i].mib.counters) + return -ENOMEM; + } + /* set the real number of ports */ dev->ds->num_ports = dev->port_cnt; return 0; @@ -626,6 +727,10 @@ const struct ksz_dev_ops lan937x_dev_ops = { .cfg_port_member = lan937x_cfg_port_member, .flush_dyn_mac_table = lan937x_flush_dyn_mac_table, .port_setup = lan937x_port_setup, + .r_mib_cnt = lan937x_r_mib_cnt, + .r_mib_pkt = lan937x_r_mib_pkt, + .port_init_cnt = lan937x_port_init_cnt, + .r_mib_stat64 = ksz_r_mib_stats64, .shutdown = lan937x_reset_switch, .detect = lan937x_switch_detect, .init = lan937x_init, diff --git a/drivers/net/dsa/microchip/lan937x_dev.h b/drivers/net/dsa/microchip/lan937x_dev.h index 0141d417c446..147800550162 100644 --- a/drivers/net/dsa/microchip/lan937x_dev.h +++ b/drivers/net/dsa/microchip/lan937x_dev.h @@ -38,8 +38,55 @@ void lan937x_config_interface(struct ksz_device *dev, int port, bool tx_pause, bool rx_pause); void lan937x_mac_config(struct ksz_device *dev, int port, phy_interface_t interface); +void lan937x_r_mib_pkt(struct ksz_device *dev, int port, u16 addr, + u64 *dropped, u64 *cnt); + +struct mib_names { + int index; + char string[ETH_GSTRING_LEN]; +}; + +enum lan937x_mib_list { + lan937x_mib_rx_hi_pri_byte = 0, + lan937x_mib_rx_undersize, + lan937x_mib_rx_fragments, + lan937x_mib_rx_oversize, + lan937x_mib_rx_jabbers, + lan937x_mib_rx_sym_err, + lan937x_mib_rx_crc_err, + lan937x_mib_rx_align_err, + lan937x_mib_rx_mac_ctrl, + lan937x_mib_rx_pause, + lan937x_mib_rx_bcast, + lan937x_mib_rx_mcast, + lan937x_mib_rx_ucast, + lan937x_mib_rx_64_or_less, + lan937x_mib_rx_65_127, + lan937x_mib_rx_128_255, + lan937x_mib_rx_256_511, + lan937x_mib_rx_512_1023, + lan937x_mib_rx_1024_1522, + lan937x_mib_rx_1523_2000, + lan937x_mib_rx_2001, + lan937x_mib_tx_hi_pri_byte, + lan937x_mib_tx_late_col, + lan937x_mib_tx_pause, + lan937x_mib_tx_bcast, + lan937x_mib_tx_mcast, + lan937x_mib_tx_ucast, + lan937x_mib_tx_deferred, + lan937x_mib_tx_total_col, + lan937x_mib_tx_exc_col, + lan937x_mib_tx_single_col, + lan937x_mib_tx_mult_col, + lan937x_mib_rx_total, + lan937x_mib_tx_total, + lan937x_mib_rx_discard, + lan937x_mib_tx_discard, +}; extern const struct dsa_switch_ops lan937x_switch_ops; extern const struct ksz_dev_ops lan937x_dev_ops; +extern const struct mib_names lan937x_mib_names[]; #endif diff --git a/drivers/net/dsa/microchip/lan937x_main.c b/drivers/net/dsa/microchip/lan937x_main.c index 38d5311bf21f..6d0b0d62b8e1 100644 --- a/drivers/net/dsa/microchip/lan937x_main.c +++ b/drivers/net/dsa/microchip/lan937x_main.c @@ -45,6 +45,20 @@ static int lan937x_phy_write16(struct dsa_switch *ds, int addr, int reg, return lan937x_internal_phy_write(dev, addr, reg, val); } +static void lan937x_get_strings(struct dsa_switch *ds, int port, u32 stringset, + u8 *buf) +{ + struct ksz_device *dev = ds->priv; + int i; + + if (stringset != ETH_SS_STATS) + return; + + for (i = 0; i < dev->mib_cnt; i++) + memcpy(buf + i * ETH_GSTRING_LEN, lan937x_mib_names[i].string, + ETH_GSTRING_LEN); +} + static void lan937x_port_stp_state_set(struct dsa_switch *ds, int port, u8 state) { @@ -215,6 +229,8 @@ static int lan937x_setup(struct dsa_switch *ds) /* start switch */ lan937x_cfg(dev, REG_SW_OPERATION, SW_START, true); + ksz_init_mib_timer(dev); + return 0; } @@ -320,12 +336,105 @@ static void lan937x_phylink_get_caps(struct dsa_switch *ds, int port, } } +static void lan937x_get_eth_phy_stats(struct dsa_switch *ds, int port, + struct ethtool_eth_phy_stats *phy_stats) +{ + struct ksz_device *dev = ds->priv; + struct ksz_port_mib *mib = &dev->ports[port].mib; + u64 *cnt; + + mutex_lock(&mib->cnt_mutex); + + cnt = &mib->counters[lan937x_mib_rx_sym_err]; + lan937x_r_mib_pkt(dev, port, lan937x_mib_rx_sym_err, NULL, cnt); + + phy_stats->SymbolErrorDuringCarrier = *cnt; + + mutex_unlock(&mib->cnt_mutex); +} + +static void lan937x_get_eth_mac_stats(struct dsa_switch *ds, int port, + struct ethtool_eth_mac_stats *mac_stats) +{ + struct ksz_device *dev = ds->priv; + struct ksz_port_mib *mib = &dev->ports[port].mib; + u64 *ctr = mib->counters; + + mutex_lock(&mib->cnt_mutex); + + while (mib->cnt_ptr < dev->mib_cnt) { + lan937x_r_mib_pkt(dev, port, mib->cnt_ptr, + NULL, &mib->counters[mib->cnt_ptr]); + ++mib->cnt_ptr; + } + + mac_stats->FramesTransmittedOK = ctr[lan937x_mib_tx_mcast] + + ctr[lan937x_mib_tx_bcast] + + ctr[lan937x_mib_tx_ucast] + + ctr[lan937x_mib_tx_pause]; + + mac_stats->SingleCollisionFrames = ctr[lan937x_mib_tx_single_col]; + mac_stats->MultipleCollisionFrames = ctr[lan937x_mib_tx_mult_col]; + + mac_stats->FramesReceivedOK = ctr[lan937x_mib_rx_mcast] + + ctr[lan937x_mib_rx_bcast] + + ctr[lan937x_mib_rx_ucast] + + ctr[lan937x_mib_rx_pause]; + + mac_stats->FrameCheckSequenceErrors = ctr[lan937x_mib_rx_crc_err]; + mac_stats->AlignmentErrors = ctr[lan937x_mib_rx_align_err]; + mac_stats->OctetsTransmittedOK = ctr[lan937x_mib_tx_total]; + mac_stats->FramesWithDeferredXmissions = ctr[lan937x_mib_tx_deferred]; + mac_stats->LateCollisions = ctr[lan937x_mib_tx_late_col]; + mac_stats->FramesAbortedDueToXSColls = ctr[lan937x_mib_tx_exc_col]; + mac_stats->FramesLostDueToIntMACXmitError = ctr[lan937x_mib_tx_discard]; + + mac_stats->OctetsReceivedOK = ctr[lan937x_mib_rx_total]; + mac_stats->FramesLostDueToIntMACRcvError = ctr[lan937x_mib_rx_discard]; + mac_stats->MulticastFramesXmittedOK = ctr[lan937x_mib_tx_mcast]; + mac_stats->BroadcastFramesXmittedOK = ctr[lan937x_mib_tx_bcast]; + + mac_stats->MulticastFramesReceivedOK = ctr[lan937x_mib_rx_mcast]; + mac_stats->BroadcastFramesReceivedOK = ctr[lan937x_mib_rx_bcast]; + mac_stats->InRangeLengthErrors = ctr[lan937x_mib_rx_fragments]; + + mib->cnt_ptr = 0; + mutex_unlock(&mib->cnt_mutex); +} + +static void lan937x_get_eth_ctrl_stats(struct dsa_switch *ds, int port, + struct ethtool_eth_ctrl_stats *ctrl_sts) +{ + struct ksz_device *dev = ds->priv; + struct ksz_port_mib *mib = &dev->ports[port].mib; + u64 *cnt; + + mutex_lock(&mib->cnt_mutex); + + cnt = &mib->counters[lan937x_mib_rx_pause]; + lan937x_r_mib_pkt(dev, port, lan937x_mib_rx_pause, NULL, cnt); + ctrl_sts->MACControlFramesReceived = *cnt; + + cnt = &mib->counters[lan937x_mib_tx_pause]; + lan937x_r_mib_pkt(dev, port, lan937x_mib_tx_pause, NULL, cnt); + ctrl_sts->MACControlFramesTransmitted = *cnt; + + mutex_unlock(&mib->cnt_mutex); +} + const struct dsa_switch_ops lan937x_switch_ops = { .get_tag_protocol = lan937x_get_tag_protocol, .setup = lan937x_setup, .phy_read = lan937x_phy_read16, .phy_write = lan937x_phy_write16, .port_enable = ksz_enable_port, + .get_strings = lan937x_get_strings, + .get_ethtool_stats = ksz_get_ethtool_stats, + .get_sset_count = ksz_sset_count, + .get_eth_ctrl_stats = lan937x_get_eth_ctrl_stats, + .get_eth_mac_stats = lan937x_get_eth_mac_stats, + .get_eth_phy_stats = lan937x_get_eth_phy_stats, + .get_stats64 = ksz_get_stats64, .port_bridge_join = ksz_port_bridge_join, .port_bridge_leave = ksz_port_bridge_leave, .port_stp_state_set = lan937x_port_stp_state_set, -- 2.33.0