Skip to content

Commit 4a38cde

Browse files
committed
Merge branch 'ethtool-get_ts_stats-for-dsa-and-ocelot-driver'
Vladimir Oltean says: ==================== ethtool get_ts_stats() for DSA and ocelot driver After a recent patch set with fixes and general restructuring, Jakub asked for the Felix DSA driver to start reporting standardized statistics for hardware timestamping: https://lore.kernel.org/netdev/[email protected]/ Testing follows the same procedure as in the aforementioned series, with PTP packet loss induced through taprio: $ ethtool -I --show-time-stamping swp3 Time stamping parameters for swp3: Capabilities: hardware-transmit software-transmit hardware-receive software-receive software-system-clock hardware-raw-clock PTP Hardware Clock: 1 Hardware Transmit Timestamp Modes: off on onestep-sync Hardware Receive Filter Modes: none ptpv2-l4-event ptpv2-l2-event ptpv2-event Statistics: tx_pkts: 14591 tx_lost: 85 tx_err: 0 v1: https://lore.kernel.org/[email protected]/ ==================== Link: https://patch.msgid.link/[email protected] Signed-off-by: Jakub Kicinski <[email protected]>
2 parents 19e1e17 + e777a4b commit 4a38cde

File tree

12 files changed

+147
-16
lines changed

12 files changed

+147
-16
lines changed

Documentation/netlink/specs/ethtool.yaml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -842,6 +842,9 @@ attribute-sets:
842842
-
843843
name: tx-err
844844
type: uint
845+
-
846+
name: tx-onestep-pkts-unconfirmed
847+
type: uint
845848
-
846849
name: ts-hwtstamp-provider
847850
attr-cnt-name: __ethtool-a-ts-hwtstamp-provider-cnt

Documentation/networking/ethtool-netlink.rst

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1281,11 +1281,17 @@ would be empty (no bit set).
12811281

12821282
Additional hardware timestamping statistics response contents:
12831283

1284-
===================================== ====== ===================================
1285-
``ETHTOOL_A_TS_STAT_TX_PKTS`` uint Packets with Tx HW timestamps
1286-
``ETHTOOL_A_TS_STAT_TX_LOST`` uint Tx HW timestamp not arrived count
1287-
``ETHTOOL_A_TS_STAT_TX_ERR`` uint HW error request Tx timestamp count
1288-
===================================== ====== ===================================
1284+
================================================== ====== =====================
1285+
``ETHTOOL_A_TS_STAT_TX_PKTS`` uint Packets with Tx
1286+
HW timestamps
1287+
``ETHTOOL_A_TS_STAT_TX_LOST`` uint Tx HW timestamp
1288+
not arrived count
1289+
``ETHTOOL_A_TS_STAT_TX_ERR`` uint HW error request
1290+
Tx timestamp count
1291+
``ETHTOOL_A_TS_STAT_TX_ONESTEP_PKTS_UNCONFIRMED`` uint Packets with one-step
1292+
HW TX timestamps with
1293+
unconfirmed delivery
1294+
================================================== ====== =====================
12891295

12901296
CABLE_TEST
12911297
==========

drivers/net/dsa/ocelot/felix.c

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1316,6 +1316,14 @@ static void felix_get_eth_phy_stats(struct dsa_switch *ds, int port,
13161316
ocelot_port_get_eth_phy_stats(ocelot, port, phy_stats);
13171317
}
13181318

1319+
static void felix_get_ts_stats(struct dsa_switch *ds, int port,
1320+
struct ethtool_ts_stats *ts_stats)
1321+
{
1322+
struct ocelot *ocelot = ds->priv;
1323+
1324+
ocelot_port_get_ts_stats(ocelot, port, ts_stats);
1325+
}
1326+
13191327
static void felix_get_strings(struct dsa_switch *ds, int port,
13201328
u32 stringset, u8 *data)
13211329
{
@@ -2237,6 +2245,7 @@ static const struct dsa_switch_ops felix_switch_ops = {
22372245
.get_stats64 = felix_get_stats64,
22382246
.get_pause_stats = felix_get_pause_stats,
22392247
.get_rmon_stats = felix_get_rmon_stats,
2248+
.get_ts_stats = felix_get_ts_stats,
22402249
.get_eth_ctrl_stats = felix_get_eth_ctrl_stats,
22412250
.get_eth_mac_stats = felix_get_eth_mac_stats,
22422251
.get_eth_phy_stats = felix_get_eth_phy_stats,

drivers/net/ethernet/mscc/ocelot_net.c

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -993,13 +993,24 @@ static int ocelot_port_get_ts_info(struct net_device *dev,
993993
return ocelot_get_ts_info(ocelot, port, info);
994994
}
995995

996+
static void ocelot_port_ts_stats(struct net_device *dev,
997+
struct ethtool_ts_stats *ts_stats)
998+
{
999+
struct ocelot_port_private *priv = netdev_priv(dev);
1000+
struct ocelot *ocelot = priv->port.ocelot;
1001+
int port = priv->port.index;
1002+
1003+
ocelot_port_get_ts_stats(ocelot, port, ts_stats);
1004+
}
1005+
9961006
static const struct ethtool_ops ocelot_ethtool_ops = {
9971007
.get_strings = ocelot_port_get_strings,
9981008
.get_ethtool_stats = ocelot_port_get_ethtool_stats,
9991009
.get_sset_count = ocelot_port_get_sset_count,
10001010
.get_link_ksettings = phy_ethtool_get_link_ksettings,
10011011
.set_link_ksettings = phy_ethtool_set_link_ksettings,
10021012
.get_ts_info = ocelot_port_get_ts_info,
1013+
.get_ts_stats = ocelot_port_ts_stats,
10031014
};
10041015

10051016
static void ocelot_port_attr_stp_state_set(struct ocelot *ocelot, int port,

drivers/net/ethernet/mscc/ocelot_ptp.c

Lines changed: 42 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -680,9 +680,14 @@ static int ocelot_port_queue_ptp_tx_skb(struct ocelot *ocelot, int port,
680680
skb_queue_walk_safe(&ocelot_port->tx_skbs, skb, skb_tmp) {
681681
if (time_before(OCELOT_SKB_CB(skb)->ptp_tx_time +
682682
OCELOT_PTP_TX_TSTAMP_TIMEOUT, jiffies)) {
683-
dev_warn_ratelimited(ocelot->dev,
684-
"port %d invalidating stale timestamp ID %u which seems lost\n",
685-
port, OCELOT_SKB_CB(skb)->ts_id);
683+
u64_stats_update_begin(&ocelot_port->ts_stats->syncp);
684+
ocelot_port->ts_stats->lost++;
685+
u64_stats_update_end(&ocelot_port->ts_stats->syncp);
686+
687+
dev_dbg_ratelimited(ocelot->dev,
688+
"port %d invalidating stale timestamp ID %u which seems lost\n",
689+
port, OCELOT_SKB_CB(skb)->ts_id);
690+
686691
__skb_unlink(skb, &ocelot_port->tx_skbs);
687692
kfree_skb(skb);
688693
ocelot->ptp_skbs_in_flight--;
@@ -748,13 +753,20 @@ int ocelot_port_txtstamp_request(struct ocelot *ocelot, int port,
748753
return 0;
749754

750755
ptp_class = ptp_classify_raw(skb);
751-
if (ptp_class == PTP_CLASS_NONE)
752-
return -EINVAL;
756+
if (ptp_class == PTP_CLASS_NONE) {
757+
err = -EINVAL;
758+
goto error;
759+
}
753760

754761
/* Store ptp_cmd in OCELOT_SKB_CB(skb)->ptp_cmd */
755762
if (ptp_cmd == IFH_REW_OP_ORIGIN_PTP) {
756763
if (ocelot_ptp_is_onestep_sync(skb, ptp_class)) {
757764
OCELOT_SKB_CB(skb)->ptp_cmd = ptp_cmd;
765+
766+
u64_stats_update_begin(&ocelot_port->ts_stats->syncp);
767+
ocelot_port->ts_stats->onestep_pkts_unconfirmed++;
768+
u64_stats_update_end(&ocelot_port->ts_stats->syncp);
769+
758770
return 0;
759771
}
760772

@@ -764,14 +776,16 @@ int ocelot_port_txtstamp_request(struct ocelot *ocelot, int port,
764776

765777
if (ptp_cmd == IFH_REW_OP_TWO_STEP_PTP) {
766778
*clone = skb_clone_sk(skb);
767-
if (!(*clone))
768-
return -ENOMEM;
779+
if (!(*clone)) {
780+
err = -ENOMEM;
781+
goto error;
782+
}
769783

770784
/* Store timestamp ID in OCELOT_SKB_CB(clone)->ts_id */
771785
err = ocelot_port_queue_ptp_tx_skb(ocelot, port, *clone);
772786
if (err) {
773787
kfree_skb(*clone);
774-
return err;
788+
goto error;
775789
}
776790

777791
skb_shinfo(*clone)->tx_flags |= SKBTX_IN_PROGRESS;
@@ -780,6 +794,12 @@ int ocelot_port_txtstamp_request(struct ocelot *ocelot, int port,
780794
}
781795

782796
return 0;
797+
798+
error:
799+
u64_stats_update_begin(&ocelot_port->ts_stats->syncp);
800+
ocelot_port->ts_stats->err++;
801+
u64_stats_update_end(&ocelot_port->ts_stats->syncp);
802+
return err;
783803
}
784804
EXPORT_SYMBOL(ocelot_port_txtstamp_request);
785805

@@ -816,6 +836,7 @@ void ocelot_get_txtstamp(struct ocelot *ocelot)
816836

817837
while (budget--) {
818838
struct skb_shared_hwtstamps shhwtstamps;
839+
struct ocelot_port *ocelot_port;
819840
u32 val, id, seqid, txport;
820841
struct sk_buff *skb_match;
821842
struct timespec64 ts;
@@ -832,17 +853,27 @@ void ocelot_get_txtstamp(struct ocelot *ocelot)
832853
id = SYS_PTP_STATUS_PTP_MESS_ID_X(val);
833854
txport = SYS_PTP_STATUS_PTP_MESS_TXPORT_X(val);
834855
seqid = SYS_PTP_STATUS_PTP_MESS_SEQ_ID(val);
856+
ocelot_port = ocelot->ports[txport];
835857

836858
/* Retrieve its associated skb */
837859
skb_match = ocelot_port_dequeue_ptp_tx_skb(ocelot, txport, id,
838860
seqid);
839861
if (!skb_match) {
840-
dev_warn_ratelimited(ocelot->dev,
841-
"port %d received TX timestamp (seqid %d, ts id %u) for packet previously declared stale\n",
842-
txport, seqid, id);
862+
u64_stats_update_begin(&ocelot_port->ts_stats->syncp);
863+
ocelot_port->ts_stats->err++;
864+
u64_stats_update_end(&ocelot_port->ts_stats->syncp);
865+
866+
dev_dbg_ratelimited(ocelot->dev,
867+
"port %d received TX timestamp (seqid %d, ts id %u) for packet previously declared stale\n",
868+
txport, seqid, id);
869+
843870
goto next_ts;
844871
}
845872

873+
u64_stats_update_begin(&ocelot_port->ts_stats->syncp);
874+
ocelot_port->ts_stats->pkts++;
875+
u64_stats_update_end(&ocelot_port->ts_stats->syncp);
876+
846877
/* Get the h/w timestamp */
847878
ocelot_get_hwtimestamp(ocelot, &ts);
848879

drivers/net/ethernet/mscc/ocelot_stats.c

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -821,6 +821,26 @@ void ocelot_port_get_eth_phy_stats(struct ocelot *ocelot, int port,
821821
}
822822
EXPORT_SYMBOL_GPL(ocelot_port_get_eth_phy_stats);
823823

824+
void ocelot_port_get_ts_stats(struct ocelot *ocelot, int port,
825+
struct ethtool_ts_stats *ts_stats)
826+
{
827+
struct ocelot_port *ocelot_port = ocelot->ports[port];
828+
struct ocelot_ts_stats *stats = ocelot_port->ts_stats;
829+
unsigned int start;
830+
831+
if (!ocelot->ptp)
832+
return;
833+
834+
do {
835+
start = u64_stats_fetch_begin(&stats->syncp);
836+
ts_stats->pkts = stats->pkts;
837+
ts_stats->onestep_pkts_unconfirmed = stats->onestep_pkts_unconfirmed;
838+
ts_stats->lost = stats->lost;
839+
ts_stats->err = stats->err;
840+
} while (u64_stats_fetch_retry(&stats->syncp, start));
841+
}
842+
EXPORT_SYMBOL_GPL(ocelot_port_get_ts_stats);
843+
824844
void ocelot_port_get_stats64(struct ocelot *ocelot, int port,
825845
struct rtnl_link_stats64 *stats)
826846
{
@@ -960,6 +980,23 @@ int ocelot_stats_init(struct ocelot *ocelot)
960980
if (!ocelot->stats)
961981
return -ENOMEM;
962982

983+
if (ocelot->ptp) {
984+
for (int port = 0; port < ocelot->num_phys_ports; port++) {
985+
struct ocelot_port *ocelot_port = ocelot->ports[port];
986+
987+
if (!ocelot_port)
988+
continue;
989+
990+
ocelot_port->ts_stats = devm_kzalloc(ocelot->dev,
991+
sizeof(*ocelot_port->ts_stats),
992+
GFP_KERNEL);
993+
if (!ocelot_port->ts_stats)
994+
return -ENOMEM;
995+
996+
u64_stats_init(&ocelot_port->ts_stats->syncp);
997+
}
998+
}
999+
9631000
snprintf(queue_name, sizeof(queue_name), "%s-stats",
9641001
dev_name(ocelot->dev));
9651002
ocelot->stats_queue = create_singlethread_workqueue(queue_name);

include/linux/ethtool.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -559,6 +559,12 @@ struct ethtool_rmon_stats {
559559
/**
560560
* struct ethtool_ts_stats - HW timestamping statistics
561561
* @pkts: Number of packets successfully timestamped by the hardware.
562+
* @onestep_pkts_unconfirmed: Number of PTP packets with one-step TX
563+
* timestamping that were sent, but for which the
564+
* device offers no confirmation whether they made
565+
* it onto the wire and the timestamp was inserted
566+
* in the originTimestamp or correctionField, or
567+
* not.
562568
* @lost: Number of hardware timestamping requests where the timestamping
563569
* information from the hardware never arrived for submission with
564570
* the skb.
@@ -571,6 +577,7 @@ struct ethtool_rmon_stats {
571577
struct ethtool_ts_stats {
572578
struct_group(tx_stats,
573579
u64 pkts;
580+
u64 onestep_pkts_unconfirmed;
574581
u64 lost;
575582
u64 err;
576583
);

include/net/dsa.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -906,6 +906,8 @@ struct dsa_switch_ops {
906906
void (*get_rmon_stats)(struct dsa_switch *ds, int port,
907907
struct ethtool_rmon_stats *rmon_stats,
908908
const struct ethtool_rmon_hist_range **ranges);
909+
void (*get_ts_stats)(struct dsa_switch *ds, int port,
910+
struct ethtool_ts_stats *ts_stats);
909911
void (*get_stats64)(struct dsa_switch *ds, int port,
910912
struct rtnl_link_stats64 *s);
911913
void (*get_pause_stats)(struct dsa_switch *ds, int port,

include/soc/mscc/ocelot.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -759,6 +759,14 @@ struct ocelot_mm_state {
759759
u8 active_preemptible_tcs;
760760
};
761761

762+
struct ocelot_ts_stats {
763+
u64 pkts;
764+
u64 onestep_pkts_unconfirmed;
765+
u64 lost;
766+
u64 err;
767+
struct u64_stats_sync syncp;
768+
};
769+
762770
struct ocelot_port;
763771

764772
struct ocelot_port {
@@ -778,6 +786,7 @@ struct ocelot_port {
778786

779787
phy_interface_t phy_mode;
780788

789+
struct ocelot_ts_stats *ts_stats;
781790
struct sk_buff_head tx_skbs;
782791

783792
unsigned int trap_proto;
@@ -1023,6 +1032,8 @@ void ocelot_port_get_eth_mac_stats(struct ocelot *ocelot, int port,
10231032
struct ethtool_eth_mac_stats *mac_stats);
10241033
void ocelot_port_get_eth_phy_stats(struct ocelot *ocelot, int port,
10251034
struct ethtool_eth_phy_stats *phy_stats);
1035+
void ocelot_port_get_ts_stats(struct ocelot *ocelot, int port,
1036+
struct ethtool_ts_stats *ts_stats);
10261037
int ocelot_get_ts_info(struct ocelot *ocelot, int port,
10271038
struct kernel_ethtool_ts_info *info);
10281039
void ocelot_set_ageing_time(struct ocelot *ocelot, unsigned int msecs);

include/uapi/linux/ethtool_netlink_generated.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -382,6 +382,7 @@ enum {
382382
ETHTOOL_A_TS_STAT_TX_PKTS,
383383
ETHTOOL_A_TS_STAT_TX_LOST,
384384
ETHTOOL_A_TS_STAT_TX_ERR,
385+
ETHTOOL_A_TS_STAT_TX_ONESTEP_PKTS_UNCONFIRMED,
385386

386387
__ETHTOOL_A_TS_STAT_CNT,
387388
ETHTOOL_A_TS_STAT_MAX = (__ETHTOOL_A_TS_STAT_CNT - 1)

0 commit comments

Comments
 (0)