diff --git a/target/linux/ipq40xx/files/drivers/net/phy/ar40xx.c b/target/linux/ipq40xx/files/drivers/net/phy/ar40xx.c index c35ba2799f..369124a27a 100644 --- a/target/linux/ipq40xx/files/drivers/net/phy/ar40xx.c +++ b/target/linux/ipq40xx/files/drivers/net/phy/ar40xx.c @@ -82,6 +82,8 @@ static const struct ar40xx_mib_desc ar40xx_mibs[] = { MIB_DESC(1, AR40XX_STATS_TXLATECOL, "TxLateCol"), }; +static const int ar40xx_mibs_rx_tx[] = { 15, 31 }; + static u32 ar40xx_read(struct ar40xx_priv *priv, int reg) { @@ -430,6 +432,36 @@ ar40xx_mib_fetch_port_stat(struct ar40xx_priv *priv, int port, bool flush) } } +/* similar to ar40xx_mib_fetch_port_stat, but only fetch RXGOODBYTE and TXBYTE */ +static void +ar40xx_mib_fetch_port_stat_rx_tx(struct ar40xx_priv *priv, int port) +{ + unsigned int base; + u64 *mib_stats; + int j; + u32 num_mibs = ARRAY_SIZE(ar40xx_mibs); + + WARN_ON(port >= priv->dev.ports); + + lockdep_assert_held(&priv->mib_lock); + + base = AR40XX_REG_PORT_STATS_START + + AR40XX_REG_PORT_STATS_LEN * port; + + mib_stats = &priv->mib_stats[port * num_mibs]; + for (j = 0; j < ARRAY_SIZE(ar40xx_mibs_rx_tx); j++) { + const int i = ar40xx_mibs_rx_tx[j]; + const struct ar40xx_mib_desc *mib; + u64 t; + + mib = &ar40xx_mibs[i]; + t = ar40xx_read(priv, base + mib->offset); + t |= ar40xx_read(priv, base + mib->offset + 4) << 32; + + mib_stats[i] += t; + } +} + static int ar40xx_mib_capture(struct ar40xx_priv *priv) { @@ -771,6 +803,36 @@ ar40xx_sw_get_port_link(struct switch_dev *dev, int port, return 0; } +static int +ar40xx_sw_get_port_stats(struct switch_dev *dev, int port, + struct switch_port_stats *stats) +{ + struct ar40xx_priv *priv = swdev_to_ar40xx(dev); + u32 num_mibs = ARRAY_SIZE(ar40xx_mibs); + u64 *mib_stats; + int ret = 0; + static int last_port = AR40XX_NUM_PORTS - 1; + + mutex_lock(&priv->mib_lock); + + /* Avoid unnecessary capture */ + if (last_port >= port) { + ret = ar40xx_mib_capture(priv); + if (ret) + goto unlock; + } + last_port = port; + + ar40xx_mib_fetch_port_stat_rx_tx(priv, port); + + mib_stats = &priv->mib_stats[port * num_mibs]; + stats->rx_bytes = mib_stats[ar40xx_mibs_rx_tx[0]]; + stats->tx_bytes = mib_stats[ar40xx_mibs_rx_tx[1]]; +unlock: + mutex_unlock(&priv->mib_lock); + return ret; +} + static const struct switch_attr ar40xx_sw_attr_globals[] = { { .type = SWITCH_TYPE_INT, @@ -1724,6 +1786,7 @@ static const struct switch_dev_ops ar40xx_sw_ops = { .apply_config = ar40xx_sw_hw_apply, .reset_switch = ar40xx_sw_reset_switch, .get_port_link = ar40xx_sw_get_port_link, + .get_port_stats = ar40xx_sw_get_port_stats, }; /* Platform driver probe function */