The cpfl PMD advertises RTE_ETH_RX_OFFLOAD_TIMESTAMP, so received
packets carry a 32-bit hardware timestamp that the common idpf Rx
path extends to 64-bit nanoseconds using the device PTP clock (PHC).
However, it never initialised the PHC, so the timestamp conversion
had no reference time, and the read_clock operation was missing
entirely.
Applications had no way to enable timestamping or to read the
current device clock to correlate the mbuf timestamps.

This patch adds PTP support by reusing the idpf common PTP helpers:

- timesync_enable: allocate and initialise the adapter PTP state,
  query the PTP capabilities, program the base increment value
  and set the device clock to the current system time.
  The PTP state is shared by all vports of an adapter, so it
  is initialised only once.

- timesync_read_time: return the current device clock as a timespec.

- timesync_disable: release the PTP state.

- read_clock: return the raw device clock value in nanoseconds,
  on the same clock used to stamp received packets.

Once timesync is enabled, the common Rx path resolves the cached
PHC time, so the mbuf Rx timestamp dynfield reports valid
nanosecond values and rte_eth_read_clock() returns a consistent
reference.

Signed-off-by: Anurag Mandal <[email protected]>
---
 drivers/net/intel/cpfl/cpfl_ethdev.c | 117 +++++++++++++++++++++++++++
 drivers/net/intel/cpfl/cpfl_ethdev.h |   1 +
 drivers/net/intel/idpf/idpf_ptp.c    |   5 ++
 drivers/net/intel/idpf/idpf_ptp.h    |   4 +
 4 files changed, 127 insertions(+)

diff --git a/drivers/net/intel/cpfl/cpfl_ethdev.c 
b/drivers/net/intel/cpfl/cpfl_ethdev.c
index 4315adb68c..bab7aa8230 100644
--- a/drivers/net/intel/cpfl/cpfl_ethdev.c
+++ b/drivers/net/intel/cpfl/cpfl_ethdev.c
@@ -1335,6 +1335,119 @@ cpfl_hairpin_unbind(struct rte_eth_dev *dev, uint16_t 
rx_port)
        return 0;
 }
 
+static int
+cpfl_timesync_enable(struct rte_eth_dev *dev)
+{
+       struct cpfl_vport *cpfl_vport = dev->data->dev_private;
+       struct idpf_vport *vport = &cpfl_vport->base;
+       struct idpf_adapter *adapter = vport->adapter;
+       struct timespec sys_ts;
+       uint64_t ns;
+       int ret;
+
+       if (dev->data->dev_started && !(dev->data->dev_conf.rxmode.offloads &
+           RTE_ETH_RX_OFFLOAD_TIMESTAMP)) {
+               PMD_DRV_LOG(ERR, "Rx timestamp offload not configured");
+               return -1;
+       }
+
+       /* PTP state is shared by all vports of the adapter. */
+       if (adapter->ptp != NULL)
+               return 0;
+
+       adapter->ptp = rte_zmalloc(NULL, sizeof(struct idpf_ptp), 0);
+       if (adapter->ptp == NULL) {
+               PMD_DRV_LOG(ERR, "Failed to allocate memory for PTP");
+               return -ENOMEM;
+       }
+
+       ret = idpf_ptp_get_caps(adapter);
+       if (ret) {
+               PMD_DRV_LOG(ERR, "Failed to get PTP capabilities, err=%d", ret);
+               goto fail_ptp;
+       }
+
+       /*
+        * Write the default increment time value if the clock adjustments
+        * are enabled.
+        */
+       if (adapter->ptp->adj_dev_clk_time_access != IDPF_PTP_NONE) {
+               ret = idpf_ptp_adj_dev_clk_fine(adapter, 
adapter->ptp->base_incval);
+               if (ret) {
+                       PMD_DRV_LOG(ERR, "PTP set incval failed, err=%d", ret);
+                       goto fail_ptp;
+               }
+       }
+
+       /* Do not initialize the PTP if the device clock time cannot be read. */
+       if (adapter->ptp->get_dev_clk_time_access == IDPF_PTP_NONE) {
+               PMD_DRV_LOG(ERR, "Getting device clock time is not supported");
+               ret = -EIO;
+               goto fail_ptp;
+       }
+
+       /* Set the device clock time to system time. */
+       if (adapter->ptp->set_dev_clk_time_access != IDPF_PTP_NONE) {
+               clock_gettime(CLOCK_REALTIME, &sys_ts);
+               ns = rte_timespec_to_ns(&sys_ts);
+               ret = idpf_ptp_set_dev_clk_time(adapter, ns);
+               if (ret) {
+                       PMD_DRV_LOG(ERR, "PTP set clock time failed, err=%d", 
ret);
+                       goto fail_ptp;
+               }
+       }
+
+       adapter->ptp->cmd.shtime_enable_mask = PF_GLTSYN_CMD_SYNC_SHTIME_EN_M;
+       adapter->ptp->cmd.exec_cmd_mask = PF_GLTSYN_CMD_SYNC_EXEC_CMD_M;
+
+       return 0;
+
+fail_ptp:
+       rte_free(adapter->ptp);
+       adapter->ptp = NULL;
+       return ret;
+}
+
+static int
+cpfl_timesync_read_time(struct rte_eth_dev *dev, struct timespec *ts)
+{
+       struct cpfl_vport *cpfl_vport = dev->data->dev_private;
+       struct idpf_adapter *adapter = cpfl_vport->base.adapter;
+       uint64_t time;
+       int ret;
+
+       ret = idpf_ptp_read_src_clk_reg(adapter, &time);
+       if (ret)
+               PMD_DRV_LOG(ERR, "PTP read time failed, err %d", ret);
+       else
+               *ts = rte_ns_to_timespec(time);
+
+       return ret;
+}
+
+static int
+cpfl_dev_read_clock(struct rte_eth_dev *dev, uint64_t *clock)
+{
+       struct cpfl_vport *cpfl_vport = dev->data->dev_private;
+       struct idpf_adapter *adapter = cpfl_vport->base.adapter;
+
+       return idpf_ptp_read_src_clk_reg(adapter, clock);
+}
+
+static int
+cpfl_timesync_disable(struct rte_eth_dev *dev)
+{
+       struct cpfl_vport *cpfl_vport = dev->data->dev_private;
+       struct idpf_adapter *adapter = cpfl_vport->base.adapter;
+
+       if (adapter->ptp != NULL) {
+               rte_free(adapter->ptp);
+               adapter->ptp = NULL;
+       }
+
+       return 0;
+}
+
 static const struct eth_dev_ops cpfl_eth_dev_ops = {
        .dev_configure                  = cpfl_dev_configure,
        .dev_close                      = cpfl_dev_close,
@@ -1368,6 +1481,10 @@ static const struct eth_dev_ops cpfl_eth_dev_ops = {
        .hairpin_get_peer_ports         = cpfl_hairpin_get_peer_ports,
        .hairpin_bind                   = cpfl_hairpin_bind,
        .hairpin_unbind                 = cpfl_hairpin_unbind,
+       .timesync_enable                = cpfl_timesync_enable,
+       .timesync_read_time             = cpfl_timesync_read_time,
+       .timesync_disable               = cpfl_timesync_disable,
+       .read_clock                     = cpfl_dev_read_clock,
 };
 
 static int
diff --git a/drivers/net/intel/cpfl/cpfl_ethdev.h 
b/drivers/net/intel/cpfl/cpfl_ethdev.h
index d41aa93191..a9e532a46c 100644
--- a/drivers/net/intel/cpfl/cpfl_ethdev.h
+++ b/drivers/net/intel/cpfl/cpfl_ethdev.h
@@ -16,6 +16,7 @@
 
 #include <idpf_common_device.h>
 #include <idpf_common_virtchnl.h>
+#include <idpf_ptp.h>
 #include <base/idpf_prototype.h>
 #include <base/virtchnl2.h>
 
diff --git a/drivers/net/intel/idpf/idpf_ptp.c 
b/drivers/net/intel/idpf/idpf_ptp.c
index 5c3fcb90e4..47830de239 100644
--- a/drivers/net/intel/idpf/idpf_ptp.c
+++ b/drivers/net/intel/idpf/idpf_ptp.c
@@ -2,6 +2,7 @@
  * Copyright(c) 2025 Intel Corporation
  */
 
+#include <eal_export.h>
 #include "idpf_ptp.h"
 #include "idpf_common_virtchnl.h"
 #include "base/virtchnl2.h"
@@ -38,6 +39,7 @@ idpf_ptp_get_features_access(const struct idpf_adapter 
*adapter)
                IDPF_PTP_ACCESS(adapter, VIRTCHNL2_CAP_PTP_TX_TSTAMPS);
 }
 
+RTE_EXPORT_INTERNAL_SYMBOL(idpf_ptp_get_caps)
 int
 idpf_ptp_get_caps(struct idpf_adapter *adapter)
 {
@@ -212,6 +214,7 @@ idpf_ptp_get_cross_time(struct idpf_adapter *adapter,
        return err;
 }
 
+RTE_EXPORT_INTERNAL_SYMBOL(idpf_ptp_set_dev_clk_time)
 int
 idpf_ptp_set_dev_clk_time(struct idpf_adapter *adapter, uint64_t time)
 {
@@ -256,6 +259,7 @@ idpf_ptp_adj_dev_clk_time(struct idpf_adapter *adapter, 
int64_t delta)
        return err;
 }
 
+RTE_EXPORT_INTERNAL_SYMBOL(idpf_ptp_adj_dev_clk_fine)
 int
 idpf_ptp_adj_dev_clk_fine(struct idpf_adapter *adapter, uint64_t incval)
 {
@@ -487,6 +491,7 @@ idpf_ptp_read_src_clk_reg_mailbox(struct idpf_adapter 
*adapter,
  *
  * Return: 0 on success, -errno otherwise.
  */
+RTE_EXPORT_INTERNAL_SYMBOL(idpf_ptp_read_src_clk_reg)
 int
 idpf_ptp_read_src_clk_reg(struct idpf_adapter *adapter, uint64_t *src_clk)
 {
diff --git a/drivers/net/intel/idpf/idpf_ptp.h 
b/drivers/net/intel/idpf/idpf_ptp.h
index 0c901440fb..851cdad027 100644
--- a/drivers/net/intel/idpf/idpf_ptp.h
+++ b/drivers/net/intel/idpf/idpf_ptp.h
@@ -88,13 +88,17 @@ struct idpf_ptp_dev_timers {
        uint64_t dev_clk_time_ns;
 };
 
+__rte_internal
 int idpf_ptp_get_caps(struct idpf_adapter *adapter);
+__rte_internal
 int idpf_ptp_read_src_clk_reg(struct idpf_adapter *adapter, uint64_t *src_clk);
 int idpf_ptp_get_dev_clk_time(struct idpf_adapter *adapter,
                             struct idpf_ptp_dev_timers *dev_clk_time);
 int idpf_ptp_get_cross_time(struct idpf_adapter *adapter,
                            struct idpf_ptp_dev_timers *cross_time);
+__rte_internal
 int idpf_ptp_set_dev_clk_time(struct idpf_adapter *adapter, uint64_t time);
+__rte_internal
 int idpf_ptp_adj_dev_clk_fine(struct idpf_adapter *adapter, uint64_t incval);
 int idpf_ptp_adj_dev_clk_time(struct idpf_adapter *adapter, int64_t delta);
 int idpf_ptp_get_vport_tstamps_caps(struct idpf_vport *vport);
-- 
2.34.1

Reply via email to