3434#define DP83TD510E_CTRL_HW_RESET BIT(15)
3535#define DP83TD510E_CTRL_SW_RESET BIT(14)
3636
37+ /*
38+ * DP83TD510E_PKT_STAT_x registers correspond to similarly named registers
39+ * in the datasheet (PKT_STAT_1 through PKT_STAT_6). These registers store
40+ * 32-bit or 16-bit counters for TX and RX statistics and must be read in
41+ * sequence to ensure the counters are cleared correctly.
42+ *
43+ * - DP83TD510E_PKT_STAT_1: Contains TX packet count bits [15:0].
44+ * - DP83TD510E_PKT_STAT_2: Contains TX packet count bits [31:16].
45+ * - DP83TD510E_PKT_STAT_3: Contains TX error packet count.
46+ * - DP83TD510E_PKT_STAT_4: Contains RX packet count bits [15:0].
47+ * - DP83TD510E_PKT_STAT_5: Contains RX packet count bits [31:16].
48+ * - DP83TD510E_PKT_STAT_6: Contains RX error packet count.
49+ *
50+ * Keeping the register names as defined in the datasheet helps maintain
51+ * clarity and alignment with the documentation.
52+ */
53+ #define DP83TD510E_PKT_STAT_1 0x12b
54+ #define DP83TD510E_PKT_STAT_2 0x12c
55+ #define DP83TD510E_PKT_STAT_3 0x12d
56+ #define DP83TD510E_PKT_STAT_4 0x12e
57+ #define DP83TD510E_PKT_STAT_5 0x12f
58+ #define DP83TD510E_PKT_STAT_6 0x130
59+
3760#define DP83TD510E_AN_STAT_1 0x60c
3861#define DP83TD510E_MASTER_SLAVE_RESOL_FAIL BIT(15)
3962
@@ -58,8 +81,16 @@ static const u16 dp83td510_mse_sqi_map[] = {
5881 0x0000 /* 24dB =< SNR */
5982};
6083
84+ struct dp83td510_stats {
85+ u64 tx_pkt_cnt ;
86+ u64 tx_err_pkt_cnt ;
87+ u64 rx_pkt_cnt ;
88+ u64 rx_err_pkt_cnt ;
89+ };
90+
6191struct dp83td510_priv {
6292 bool alcd_test_active ;
93+ struct dp83td510_stats stats ;
6394};
6495
6596/* Time Domain Reflectometry (TDR) Functionality of DP83TD510 PHY
@@ -177,6 +208,85 @@ struct dp83td510_priv {
177208#define DP83TD510E_ALCD_COMPLETE BIT(15)
178209#define DP83TD510E_ALCD_CABLE_LENGTH GENMASK(10, 0)
179210
211+ /**
212+ * dp83td510_update_stats - Update the PHY statistics for the DP83TD510 PHY.
213+ * @phydev: Pointer to the phy_device structure.
214+ *
215+ * The function reads the PHY statistics registers and updates the statistics
216+ * structure.
217+ *
218+ * Returns: 0 on success or a negative error code on failure.
219+ */
220+ static int dp83td510_update_stats (struct phy_device * phydev )
221+ {
222+ struct dp83td510_priv * priv = phydev -> priv ;
223+ u32 count ;
224+ int ret ;
225+
226+ /* The DP83TD510E_PKT_STAT registers are divided into two groups:
227+ * - Group 1 (TX stats): DP83TD510E_PKT_STAT_1 to DP83TD510E_PKT_STAT_3
228+ * - Group 2 (RX stats): DP83TD510E_PKT_STAT_4 to DP83TD510E_PKT_STAT_6
229+ *
230+ * Registers in each group are cleared only after reading them in a
231+ * plain sequence (e.g., 1, 2, 3 for Group 1 or 4, 5, 6 for Group 2).
232+ * Any deviation from the sequence, such as reading 1, 2, 1, 2, 3, will
233+ * prevent the group from being cleared. Additionally, the counters
234+ * for a group are frozen as soon as the first register in that group
235+ * is accessed.
236+ */
237+ ret = phy_read_mmd (phydev , MDIO_MMD_VEND2 , DP83TD510E_PKT_STAT_1 );
238+ if (ret < 0 )
239+ return ret ;
240+ /* tx_pkt_cnt_15_0 */
241+ count = ret ;
242+
243+ ret = phy_read_mmd (phydev , MDIO_MMD_VEND2 , DP83TD510E_PKT_STAT_2 );
244+ if (ret < 0 )
245+ return ret ;
246+ /* tx_pkt_cnt_31_16 */
247+ count |= ret << 16 ;
248+ priv -> stats .tx_pkt_cnt += count ;
249+
250+ ret = phy_read_mmd (phydev , MDIO_MMD_VEND2 , DP83TD510E_PKT_STAT_3 );
251+ if (ret < 0 )
252+ return ret ;
253+ /* tx_err_pkt_cnt */
254+ priv -> stats .tx_err_pkt_cnt += ret ;
255+
256+ ret = phy_read_mmd (phydev , MDIO_MMD_VEND2 , DP83TD510E_PKT_STAT_4 );
257+ if (ret < 0 )
258+ return ret ;
259+ /* rx_pkt_cnt_15_0 */
260+ count = ret ;
261+
262+ ret = phy_read_mmd (phydev , MDIO_MMD_VEND2 , DP83TD510E_PKT_STAT_5 );
263+ if (ret < 0 )
264+ return ret ;
265+ /* rx_pkt_cnt_31_16 */
266+ count |= ret << 16 ;
267+ priv -> stats .rx_pkt_cnt += count ;
268+
269+ ret = phy_read_mmd (phydev , MDIO_MMD_VEND2 , DP83TD510E_PKT_STAT_6 );
270+ if (ret < 0 )
271+ return ret ;
272+ /* rx_err_pkt_cnt */
273+ priv -> stats .rx_err_pkt_cnt += ret ;
274+
275+ return 0 ;
276+ }
277+
278+ static void dp83td510_get_phy_stats (struct phy_device * phydev ,
279+ struct ethtool_eth_phy_stats * eth_stats ,
280+ struct ethtool_phy_stats * stats )
281+ {
282+ struct dp83td510_priv * priv = phydev -> priv ;
283+
284+ stats -> tx_packets = priv -> stats .tx_pkt_cnt ;
285+ stats -> tx_errors = priv -> stats .tx_err_pkt_cnt ;
286+ stats -> rx_packets = priv -> stats .rx_pkt_cnt ;
287+ stats -> rx_errors = priv -> stats .rx_err_pkt_cnt ;
288+ }
289+
180290static int dp83td510_config_intr (struct phy_device * phydev )
181291{
182292 int ret ;
@@ -599,6 +709,8 @@ static struct phy_driver dp83td510_driver[] = {
599709 .get_sqi_max = dp83td510_get_sqi_max ,
600710 .cable_test_start = dp83td510_cable_test_start ,
601711 .cable_test_get_status = dp83td510_cable_test_get_status ,
712+ .get_phy_stats = dp83td510_get_phy_stats ,
713+ .update_stats = dp83td510_update_stats ,
602714
603715 .suspend = genphy_suspend ,
604716 .resume = genphy_resume ,
0 commit comments