From 9fc506e9b2e40db8f3a6df5b59556e59351e376f Mon Sep 17 00:00:00 2001 From: Chuanhong Guo Date: Fri, 11 Jan 2019 11:51:54 +0800 Subject: [PATCH] generic: ar8216: add support for get_port_stats() Partially reverts commit eff3549c5883a9abc5dbff00c084cabbcfdf4437. AR7240 and AR9341 have buggy hardware switch LED trigger. The AR7240 one doesn't blink and the blinking of port0/port5 is reversed on AR9341 if we swap PHY0 and PHY4. (Only blinking is reversed, which means LED for PHY0 will lit when PHY0 is link up and will blink when PHY4 has active link and vice versa.) On these two chips a software swconfig LED trigger is required. This commit adds swconfig port stats back but: 1. move checking of mib_t/rxb_id into ar8xxx_chip since we can't distinguish ar7240sw and ar8216 using only chip id. 2. don't update mib counter in get_port_stat. This function is called every 0.01s and this capturing procedure will take up a lot of CPU. We already have a mib_work_func updating mib counters every 2s so return the saved counter instead of fetching new data. The blinking rate will be weird but it should solve the previously mentioned CPU time problem. Signed-off-by: Chuanhong Guo --- .../generic/files/drivers/net/phy/ar8216.c | 56 ++++++++++++++----- .../generic/files/drivers/net/phy/ar8216.h | 11 ++++ .../generic/files/drivers/net/phy/ar8327.c | 17 ++---- 3 files changed, 59 insertions(+), 25 deletions(-) diff --git a/target/linux/generic/files/drivers/net/phy/ar8216.c b/target/linux/generic/files/drivers/net/phy/ar8216.c index 3cee84f0df..c62411c9c1 100644 --- a/target/linux/generic/files/drivers/net/phy/ar8216.c +++ b/target/linux/generic/files/drivers/net/phy/ar8216.c @@ -1797,6 +1797,33 @@ ar8xxx_sw_set_flush_port_arl_table(struct switch_dev *dev, return ret; } +int +ar8xxx_sw_get_port_stats(struct switch_dev *dev, int port, + struct switch_port_stats *stats) +{ + struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev); + u64 *mib_stats; + + if (!ar8xxx_has_mib_counters(priv)) + return -EOPNOTSUPP; + + if (!(priv->chip->mib_rxb_id || priv->chip->mib_txb_id)) + return -EOPNOTSUPP; + + if (port >= dev->ports) + return -EINVAL; + + mutex_lock(&priv->mib_lock); + + mib_stats = &priv->mib_stats[port * priv->chip->num_mibs]; + + stats->tx_bytes = mib_stats[priv->chip->mib_txb_id]; + stats->rx_bytes = mib_stats[priv->chip->mib_rxb_id]; + + mutex_unlock(&priv->mib_lock); + return 0; +} + static int ar8xxx_phy_read(struct mii_bus *bus, int phy_addr, int reg_addr) { @@ -1927,16 +1954,7 @@ static const struct switch_dev_ops ar8xxx_sw_ops = { .apply_config = ar8xxx_sw_hw_apply, .reset_switch = ar8xxx_sw_reset_switch, .get_port_link = ar8xxx_sw_get_port_link, -/* The following op is disabled as it hogs the CPU and degrades performance. - An implementation has been attempted in 4d8a66d but reading MIB data is slow - on ar8xxx switches. - - The high CPU load has been traced down to the ar8xxx_reg_wait() call in - ar8xxx_mib_op(), which has to usleep_range() till the MIB busy flag set by - the request to update the MIB counter is cleared. */ -#if 0 .get_port_stats = ar8xxx_sw_get_port_stats, -#endif }; static const struct ar8xxx_chip ar7240sw_chip = { @@ -1968,7 +1986,9 @@ static const struct ar8xxx_chip ar7240sw_chip = { .num_mibs = ARRAY_SIZE(ar8236_mibs), .mib_decs = ar8236_mibs, - .mib_func = AR8216_REG_MIB_FUNC + .mib_func = AR8216_REG_MIB_FUNC, + .mib_rxb_id = AR8236_MIB_RXB_ID, + .mib_txb_id = AR8236_MIB_TXB_ID, }; static const struct ar8xxx_chip ar8216_chip = { @@ -1998,7 +2018,9 @@ static const struct ar8xxx_chip ar8216_chip = { .num_mibs = ARRAY_SIZE(ar8216_mibs), .mib_decs = ar8216_mibs, - .mib_func = AR8216_REG_MIB_FUNC + .mib_func = AR8216_REG_MIB_FUNC, + .mib_rxb_id = AR8216_MIB_RXB_ID, + .mib_txb_id = AR8216_MIB_TXB_ID, }; static const struct ar8xxx_chip ar8229_chip = { @@ -2030,7 +2052,9 @@ static const struct ar8xxx_chip ar8229_chip = { .num_mibs = ARRAY_SIZE(ar8236_mibs), .mib_decs = ar8236_mibs, - .mib_func = AR8216_REG_MIB_FUNC + .mib_func = AR8216_REG_MIB_FUNC, + .mib_rxb_id = AR8236_MIB_RXB_ID, + .mib_txb_id = AR8236_MIB_TXB_ID, }; static const struct ar8xxx_chip ar8236_chip = { @@ -2060,7 +2084,9 @@ static const struct ar8xxx_chip ar8236_chip = { .num_mibs = ARRAY_SIZE(ar8236_mibs), .mib_decs = ar8236_mibs, - .mib_func = AR8216_REG_MIB_FUNC + .mib_func = AR8216_REG_MIB_FUNC, + .mib_rxb_id = AR8236_MIB_RXB_ID, + .mib_txb_id = AR8236_MIB_TXB_ID, }; static const struct ar8xxx_chip ar8316_chip = { @@ -2090,7 +2116,9 @@ static const struct ar8xxx_chip ar8316_chip = { .num_mibs = ARRAY_SIZE(ar8236_mibs), .mib_decs = ar8236_mibs, - .mib_func = AR8216_REG_MIB_FUNC + .mib_func = AR8216_REG_MIB_FUNC, + .mib_rxb_id = AR8236_MIB_RXB_ID, + .mib_txb_id = AR8236_MIB_TXB_ID, }; static int diff --git a/target/linux/generic/files/drivers/net/phy/ar8216.h b/target/linux/generic/files/drivers/net/phy/ar8216.h index 0bdd3e9dd8..9b39064551 100644 --- a/target/linux/generic/files/drivers/net/phy/ar8216.h +++ b/target/linux/generic/files/drivers/net/phy/ar8216.h @@ -258,6 +258,9 @@ #define AR8216_STATS_TXDEFER 0x98 #define AR8216_STATS_TXLATECOL 0x9c +#define AR8216_MIB_RXB_ID 14 /* RxGoodByte */ +#define AR8216_MIB_TXB_ID 29 /* TxByte */ + #define AR8229_REG_OPER_MODE0 0x04 #define AR8229_OPER_MODE0_MAC_GMII_EN BIT(6) #define AR8229_OPER_MODE0_PHY_MII_EN BIT(10) @@ -321,6 +324,9 @@ #define AR8236_STATS_TXDEFER 0xa0 #define AR8236_STATS_TXLATECOL 0xa4 +#define AR8236_MIB_RXB_ID 15 /* RxGoodByte */ +#define AR8236_MIB_TXB_ID 31 /* TxByte */ + #define AR8316_REG_POSTRIP 0x0008 #define AR8316_POSTRIP_MAC0_GMII_EN BIT(0) #define AR8316_POSTRIP_MAC0_RGMII_EN BIT(1) @@ -451,6 +457,8 @@ struct ar8xxx_chip { const struct ar8xxx_mib_desc *mib_decs; unsigned num_mibs; unsigned mib_func; + int mib_rxb_id; + int mib_txb_id; }; struct ar8xxx_priv { @@ -607,6 +615,9 @@ ar8xxx_sw_set_flush_port_arl_table(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val); int +ar8xxx_sw_get_port_stats(struct switch_dev *dev, int port, + struct switch_port_stats *stats); +int ar8216_wait_bit(struct ar8xxx_priv *priv, int reg, u32 mask, u32 val); static inline struct ar8xxx_priv * diff --git a/target/linux/generic/files/drivers/net/phy/ar8327.c b/target/linux/generic/files/drivers/net/phy/ar8327.c index 36a4520678..b0da346314 100644 --- a/target/linux/generic/files/drivers/net/phy/ar8327.c +++ b/target/linux/generic/files/drivers/net/phy/ar8327.c @@ -1457,16 +1457,7 @@ static const struct switch_dev_ops ar8327_sw_ops = { .apply_config = ar8327_sw_hw_apply, .reset_switch = ar8xxx_sw_reset_switch, .get_port_link = ar8xxx_sw_get_port_link, -/* The following op is disabled as it hogs the CPU and degrades performance. - An implementation has been attempted in 4d8a66d but reading MIB data is slow - on ar8xxx switches. - - The high CPU load has been traced down to the ar8xxx_reg_wait() call in - ar8xxx_mib_op(), which has to usleep_range() till the MIB busy flag set by - the request to update the MIB counter is cleared. */ -#if 0 .get_port_stats = ar8xxx_sw_get_port_stats, -#endif }; const struct ar8xxx_chip ar8327_chip = { @@ -1501,7 +1492,9 @@ const struct ar8xxx_chip ar8327_chip = { .num_mibs = ARRAY_SIZE(ar8236_mibs), .mib_decs = ar8236_mibs, - .mib_func = AR8327_REG_MIB_FUNC + .mib_func = AR8327_REG_MIB_FUNC, + .mib_rxb_id = AR8236_MIB_RXB_ID, + .mib_txb_id = AR8236_MIB_TXB_ID, }; const struct ar8xxx_chip ar8337_chip = { @@ -1537,5 +1530,7 @@ const struct ar8xxx_chip ar8337_chip = { .num_mibs = ARRAY_SIZE(ar8236_mibs), .mib_decs = ar8236_mibs, - .mib_func = AR8327_REG_MIB_FUNC + .mib_func = AR8327_REG_MIB_FUNC, + .mib_rxb_id = AR8236_MIB_RXB_ID, + .mib_txb_id = AR8236_MIB_TXB_ID, }; -- 2.35.1