Skip to content

Commit 8fbd24f

Browse files
vladimirolteankuba-moo
authored andcommitted
net: mscc: ocelot: add TX timestamping statistics
Add an u64 hardware timestamping statistics structure for each ocelot port. Export a function from the common switch library for reporting them to ethtool. This is called by the ocelot switchdev front-end for now. Note that for the switchdev driver, we report the one-step PTP packets as unconfirmed, even though in principle, for some transmission mechanisms like FDMA, we may be able to confirm transmission and bump the "pkts" counter in ocelot_fdma_tx_cleanup() instead. I don't have access to hardware which uses the switchdev front-end, and I've kept the implementation simple. Signed-off-by: Vladimir Oltean <[email protected]> Reviewed-by: Jakub Kicinski <[email protected]> Link: https://patch.msgid.link/[email protected] Signed-off-by: Jakub Kicinski <[email protected]>
1 parent 4b0a3ff commit 8fbd24f

File tree

4 files changed

+101
-11
lines changed

4 files changed

+101
-11
lines changed

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/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);

0 commit comments

Comments
 (0)