Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Merge branch 'add-shared-phy-counter-support-for-qca807x-and-qca808x'

Luo Jie says:

====================
Add shared PHY counter support for QCA807x and QCA808x

The implementation of the PHY counter is identical for both QCA808x and
QCA807x series devices. This includes counters for both good and bad CRC
frames in the RX and TX directions, which are active when CRC checking
is enabled.

This patch series introduces PHY counter functions into a shared library,
enabling counter support for the QCA808x and QCA807x families through this
common infrastructure. Additionally, enable CRC checking and configure
automatic clearing of counters after reading within config_init() to ensure
accurate counter recording.

v2: https://lore.kernel.org/20250714-qcom_phy_counter-v2-0-94dde9d9769f@quicinc.com
v1: https://lore.kernel.org/20250709-qcom_phy_counter-v1-0-93a54a029c46@quicinc.com
====================

Link: https://patch.msgid.link/20250715-qcom_phy_counter-v3-0-8b0e460a527b@quicinc.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>

+146
+25
drivers/net/phy/qcom/qca807x.c
··· 124 124 bool dac_full_amplitude; 125 125 bool dac_full_bias_current; 126 126 bool dac_disable_bias_current_tweak; 127 + struct qcom_phy_hw_stats hw_stats; 127 128 }; 128 129 129 130 static int qca807x_cable_test_start(struct phy_device *phydev) ··· 769 768 return ret; 770 769 } 771 770 771 + ret = qcom_phy_counter_config(phydev); 772 + if (ret) 773 + return ret; 774 + 772 775 control_dac = phy_read_mmd(phydev, MDIO_MMD_AN, 773 776 QCA807X_MMD7_1000BASE_T_POWER_SAVE_PER_CABLE_LENGTH); 774 777 control_dac &= ~QCA807X_CONTROL_DAC_MASK; ··· 785 780 return phy_write_mmd(phydev, MDIO_MMD_AN, 786 781 QCA807X_MMD7_1000BASE_T_POWER_SAVE_PER_CABLE_LENGTH, 787 782 control_dac); 783 + } 784 + 785 + static int qca807x_update_stats(struct phy_device *phydev) 786 + { 787 + struct qca807x_priv *priv = phydev->priv; 788 + 789 + return qcom_phy_update_stats(phydev, &priv->hw_stats); 790 + } 791 + 792 + static void qca807x_get_phy_stats(struct phy_device *phydev, 793 + struct ethtool_eth_phy_stats *eth_stats, 794 + struct ethtool_phy_stats *stats) 795 + { 796 + struct qca807x_priv *priv = phydev->priv; 797 + 798 + qcom_phy_get_stats(stats, priv->hw_stats); 788 799 } 789 800 790 801 static struct phy_driver qca807x_drivers[] = { ··· 821 800 .suspend = genphy_suspend, 822 801 .cable_test_start = qca807x_cable_test_start, 823 802 .cable_test_get_status = qca808x_cable_test_get_status, 803 + .update_stats = qca807x_update_stats, 804 + .get_phy_stats = qca807x_get_phy_stats, 824 805 }, 825 806 { 826 807 PHY_ID_MATCH_EXACT(PHY_ID_QCA8075), ··· 846 823 .led_hw_is_supported = qca807x_led_hw_is_supported, 847 824 .led_hw_control_set = qca807x_led_hw_control_set, 848 825 .led_hw_control_get = qca807x_led_hw_control_get, 826 + .update_stats = qca807x_update_stats, 827 + .get_phy_stats = qca807x_get_phy_stats, 849 828 }, 850 829 }; 851 830 module_phy_driver(qca807x_drivers);
+23
drivers/net/phy/qcom/qca808x.c
··· 93 93 94 94 struct qca808x_priv { 95 95 int led_polarity_mode; 96 + struct qcom_phy_hw_stats hw_stats; 96 97 }; 97 98 98 99 static int qca808x_phy_fast_retrain_config(struct phy_device *phydev) ··· 243 242 } 244 243 245 244 qca808x_fill_possible_interfaces(phydev); 245 + 246 + ret = qcom_phy_counter_config(phydev); 247 + if (ret) 248 + return ret; 246 249 247 250 /* Configure adc threshold as 100mv for the link 10M */ 248 251 return at803x_debug_reg_mask(phydev, QCA808X_PHY_DEBUG_ADC_THRESHOLD, ··· 627 622 active_low ? 0 : QCA808X_LED_ACTIVE_HIGH); 628 623 } 629 624 625 + static int qca808x_update_stats(struct phy_device *phydev) 626 + { 627 + struct qca808x_priv *priv = phydev->priv; 628 + 629 + return qcom_phy_update_stats(phydev, &priv->hw_stats); 630 + } 631 + 632 + static void qca808x_get_phy_stats(struct phy_device *phydev, 633 + struct ethtool_eth_phy_stats *eth_stats, 634 + struct ethtool_phy_stats *stats) 635 + { 636 + struct qca808x_priv *priv = phydev->priv; 637 + 638 + qcom_phy_get_stats(stats, priv->hw_stats); 639 + } 640 + 630 641 static struct phy_driver qca808x_driver[] = { 631 642 { 632 643 /* Qualcomm QCA8081 */ ··· 672 651 .led_hw_control_set = qca808x_led_hw_control_set, 673 652 .led_hw_control_get = qca808x_led_hw_control_get, 674 653 .led_polarity_set = qca808x_led_polarity_set, 654 + .update_stats = qca808x_update_stats, 655 + .get_phy_stats = qca808x_get_phy_stats, 675 656 }, }; 676 657 677 658 module_phy_driver(qca808x_driver);
+75
drivers/net/phy/qcom/qcom-phy-lib.c
··· 699 699 return 0; 700 700 } 701 701 EXPORT_SYMBOL_GPL(qca808x_led_reg_blink_set); 702 + 703 + /* Enable CRC checking for both received and transmitted frames to ensure 704 + * accurate counter recording. The hardware supports a 32-bit counter, 705 + * configure the counter to clear after it is read to facilitate the 706 + * implementation of a 64-bit software counter 707 + */ 708 + int qcom_phy_counter_config(struct phy_device *phydev) 709 + { 710 + return phy_set_bits_mmd(phydev, MDIO_MMD_AN, QCA808X_MMD7_CNT_CTRL, 711 + QCA808X_MMD7_CNT_CTRL_CRC_CHECK_EN | 712 + QCA808X_MMD7_CNT_CTRL_READ_CLEAR_EN); 713 + } 714 + EXPORT_SYMBOL_GPL(qcom_phy_counter_config); 715 + 716 + int qcom_phy_update_stats(struct phy_device *phydev, 717 + struct qcom_phy_hw_stats *hw_stats) 718 + { 719 + int ret; 720 + u32 cnt; 721 + 722 + /* PHY 32-bit counter for RX packets. */ 723 + ret = phy_read_mmd(phydev, MDIO_MMD_AN, QCA808X_MMD7_CNT_RX_PKT_15_0); 724 + if (ret < 0) 725 + return ret; 726 + 727 + cnt = ret; 728 + 729 + ret = phy_read_mmd(phydev, MDIO_MMD_AN, QCA808X_MMD7_CNT_RX_PKT_31_16); 730 + if (ret < 0) 731 + return ret; 732 + 733 + cnt |= ret << 16; 734 + hw_stats->rx_pkts += cnt; 735 + 736 + /* PHY 16-bit counter for RX CRC error packets. */ 737 + ret = phy_read_mmd(phydev, MDIO_MMD_AN, QCA808X_MMD7_CNT_RX_ERR_PKT); 738 + if (ret < 0) 739 + return ret; 740 + 741 + hw_stats->rx_err_pkts += ret; 742 + 743 + /* PHY 32-bit counter for TX packets. */ 744 + ret = phy_read_mmd(phydev, MDIO_MMD_AN, QCA808X_MMD7_CNT_TX_PKT_15_0); 745 + if (ret < 0) 746 + return ret; 747 + 748 + cnt = ret; 749 + 750 + ret = phy_read_mmd(phydev, MDIO_MMD_AN, QCA808X_MMD7_CNT_TX_PKT_31_16); 751 + if (ret < 0) 752 + return ret; 753 + 754 + cnt |= ret << 16; 755 + hw_stats->tx_pkts += cnt; 756 + 757 + /* PHY 16-bit counter for TX CRC error packets. */ 758 + ret = phy_read_mmd(phydev, MDIO_MMD_AN, QCA808X_MMD7_CNT_TX_ERR_PKT); 759 + if (ret < 0) 760 + return ret; 761 + 762 + hw_stats->tx_err_pkts += ret; 763 + 764 + return 0; 765 + } 766 + EXPORT_SYMBOL_GPL(qcom_phy_update_stats); 767 + 768 + void qcom_phy_get_stats(struct ethtool_phy_stats *stats, 769 + struct qcom_phy_hw_stats hw_stats) 770 + { 771 + stats->tx_packets = hw_stats.tx_pkts; 772 + stats->tx_errors = hw_stats.tx_err_pkts; 773 + stats->rx_packets = hw_stats.rx_pkts; 774 + stats->rx_errors = hw_stats.rx_err_pkts; 775 + } 776 + EXPORT_SYMBOL_GPL(qcom_phy_get_stats);
+23
drivers/net/phy/qcom/qcom.h
··· 195 195 #define AT803X_MIN_DOWNSHIFT 2 196 196 #define AT803X_MAX_DOWNSHIFT 9 197 197 198 + #define QCA808X_MMD7_CNT_CTRL 0x8029 199 + #define QCA808X_MMD7_CNT_CTRL_READ_CLEAR_EN BIT(1) 200 + #define QCA808X_MMD7_CNT_CTRL_CRC_CHECK_EN BIT(0) 201 + 202 + #define QCA808X_MMD7_CNT_RX_PKT_31_16 0x802a 203 + #define QCA808X_MMD7_CNT_RX_PKT_15_0 0x802b 204 + #define QCA808X_MMD7_CNT_RX_ERR_PKT 0x802c 205 + #define QCA808X_MMD7_CNT_TX_PKT_31_16 0x802d 206 + #define QCA808X_MMD7_CNT_TX_PKT_15_0 0x802e 207 + #define QCA808X_MMD7_CNT_TX_ERR_PKT 0x802f 208 + 198 209 enum stat_access_type { 199 210 PHY, 200 211 MMD ··· 221 210 struct at803x_ss_mask { 222 211 u16 speed_mask; 223 212 u8 speed_shift; 213 + }; 214 + 215 + struct qcom_phy_hw_stats { 216 + u64 rx_pkts; 217 + u64 rx_err_pkts; 218 + u64 tx_pkts; 219 + u64 tx_err_pkts; 224 220 }; 225 221 226 222 int at803x_debug_reg_read(struct phy_device *phydev, u16 reg); ··· 264 246 int qca808x_led_reg_blink_set(struct phy_device *phydev, u16 reg, 265 247 unsigned long *delay_on, 266 248 unsigned long *delay_off); 249 + int qcom_phy_counter_config(struct phy_device *phydev); 250 + int qcom_phy_update_stats(struct phy_device *phydev, 251 + struct qcom_phy_hw_stats *hw_stats); 252 + void qcom_phy_get_stats(struct ethtool_phy_stats *stats, 253 + struct qcom_phy_hw_stats hw_stats);