Skip to content

Commit a8d0066

Browse files
author
Paolo Abeni
committed
Merge branch 'introduce-unified-and-structured-phy'
Oleksij Rempel says: ==================== Introduce unified and structured PHY This patch set introduces a unified and well-structured interface for reporting PHY statistics. Instead of relying on arbitrary strings in PHY drivers, this interface provides a consistent and structured way to expose PHY statistics to userspace via ethtool. The initial groundwork for this effort was laid by Jakub Kicinski, who contributed patches to plumb PHY statistics to drivers and added support for structured statistics in ethtool. Building on Jakub's work, I tested the implementation with several PHYs, addressed a few issues, and added support for statistics in two specific PHY drivers. Most of changes are tracked in separate patches. changes v6: - drop ethtool_stat_add patch changes v5: - rebase against latest net-next ==================== Link: https://patch.msgid.link/[email protected] Signed-off-by: Paolo Abeni <[email protected]>
2 parents 6a46e3e + 677d895 commit a8d0066

File tree

15 files changed

+583
-20
lines changed

15 files changed

+583
-20
lines changed

Documentation/networking/diagnostic/twisted_pair_layer1_diagnostics.rst

Lines changed: 28 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -713,17 +713,23 @@ driver supports reporting such events.
713713

714714
- **Monitor Error Counters**:
715715

716-
- While some NIC drivers and PHYs provide error counters, there is no unified
717-
set of PHY-specific counters across all hardware. Additionally, not all
718-
PHYs provide useful information related to errors like CRC errors, frame
719-
drops, or link flaps. Therefore, this step is dependent on the specific
720-
hardware and driver support.
721-
722-
- **Next Steps**: Use `ethtool -S <interface>` to check if your driver
723-
provides useful error counters. In some cases, counters may provide
724-
information about errors like link flaps or physical layer problems (e.g.,
725-
excessive CRC errors), but results can vary significantly depending on the
726-
PHY.
716+
- Use `ethtool -S <interface> --all-groups` to retrieve standardized interface
717+
statistics if the driver supports the unified interface:
718+
719+
- **Command:** `ethtool -S <interface> --all-groups`
720+
721+
- **Example Output (if supported)**:
722+
723+
.. code-block:: bash
724+
725+
phydev-RxFrames: 100391
726+
phydev-RxErrors: 0
727+
phydev-TxFrames: 9
728+
phydev-TxErrors: 0
729+
730+
- If the unified interface is not supported, use `ethtool -S <interface>` to
731+
retrieve MAC and PHY counters. Note that non-standardized PHY counter names
732+
vary by driver and must be interpreted accordingly:
727733

728734
- **Command:** `ethtool -S <interface>`
729735

@@ -740,6 +746,17 @@ driver supports reporting such events.
740746
condition) or kernel log messages (e.g., link up/down events) to further
741747
diagnose the issue.
742748

749+
- **Compare Counters**:
750+
751+
- Compare the egress and ingress frame counts reported by the PHY and MAC.
752+
753+
- A small difference may occur due to sampling rate differences between the
754+
MAC and PHY drivers, or if the PHY and MAC are not always fully
755+
synchronized in their UP or DOWN states.
756+
757+
- Significant discrepancies indicate potential issues in the data path
758+
between the MAC and PHY.
759+
743760
When All Else Fails...
744761
~~~~~~~~~~~~~~~~~~~~~~
745762

Documentation/networking/ethtool-netlink.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1616,6 +1616,7 @@ the ``ETHTOOL_A_STATS_GROUPS`` bitset. Currently defined values are:
16161616
ETHTOOL_STATS_ETH_PHY eth-phy Basic IEEE 802.3 PHY statistics (30.3.2.1.*)
16171617
ETHTOOL_STATS_ETH_CTRL eth-ctrl Basic IEEE 802.3 MAC Ctrl statistics (30.3.3.*)
16181618
ETHTOOL_STATS_RMON rmon RMON (RFC 2819) statistics
1619+
ETHTOOL_STATS_PHY phy Additional PHY statistics, not defined by IEEE
16191620
====================== ======== ===============================================
16201621

16211622
Each group should have a corresponding ``ETHTOOL_A_STATS_GRP`` in the reply.

drivers/net/phy/dp83td510.c

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,29 @@
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+
6191
struct 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+
180290
static 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

Comments
 (0)