This patch implements read clock api whose purpose is to return
raw clock ticks. Using this API real time ticks spent in
processing a packet can be known:
    <read_clock val at any time> - mbuf->timestamp

Signed-off-by: Harman Kalra <hka...@marvell.com>
---
 drivers/common/octeontx2/otx2_mbox.h |  2 +
 drivers/net/octeontx2/otx2_ethdev.c  | 86 ++++++++++++++++++++++++++++
 drivers/net/octeontx2/otx2_ethdev.h  |  4 ++
 drivers/net/octeontx2/otx2_ptp.c     | 30 ++++++++++
 4 files changed, 122 insertions(+)

diff --git a/drivers/common/octeontx2/otx2_mbox.h 
b/drivers/common/octeontx2/otx2_mbox.h
index c0bb676b2..b2c59c86e 100644
--- a/drivers/common/octeontx2/otx2_mbox.h
+++ b/drivers/common/octeontx2/otx2_mbox.h
@@ -1354,11 +1354,13 @@ struct ptp_req {
        struct mbox_msghdr hdr;
        uint8_t __otx2_io op;
        int64_t __otx2_io scaled_ppm;
+       uint8_t __otx2_io is_pmu;
 };
 
 struct ptp_rsp {
        struct mbox_msghdr hdr;
        uint64_t __otx2_io clk;
+       uint64_t __otx2_io tsc;
 };
 
 struct get_hw_cap_rsp {
diff --git a/drivers/net/octeontx2/otx2_ethdev.c 
b/drivers/net/octeontx2/otx2_ethdev.c
index 595c8003a..799e67480 100644
--- a/drivers/net/octeontx2/otx2_ethdev.c
+++ b/drivers/net/octeontx2/otx2_ethdev.c
@@ -521,6 +521,17 @@ otx2_nix_rx_queue_setup(struct rte_eth_dev *eth_dev, 
uint16_t rq,
 
        eth_dev->data->rx_queues[rq] = rxq;
        eth_dev->data->rx_queue_state[rq] = RTE_ETH_QUEUE_STATE_STOPPED;
+
+       /* Calculating delta and freq mult between PTP HI clock and rdtsc.
+        * These are needed for deriving PTP HI clock value from tsc counter.
+        */
+       if ((dev->rx_offloads & DEV_RX_OFFLOAD_TIMESTAMP) ||
+           otx2_ethdev_is_ptp_en(dev)) {
+               rc = otx2_nix_raw_clock_rdtsc_conv(dev);
+               if (rc)
+                       otx2_err("Failed to calculate delta and freq mult");
+       }
+
        return 0;
 
 free_rxq:
@@ -1186,6 +1197,79 @@ nix_set_nop_rxtx_function(struct rte_eth_dev *eth_dev)
        rte_mb();
 }
 
+static int
+nix_read_raw_clock(struct otx2_eth_dev *dev, uint64_t *clock, uint64_t *tsc,
+                  uint8_t is_pmu)
+{
+       struct otx2_mbox *mbox = dev->mbox;
+       struct ptp_req *req;
+       struct ptp_rsp *rsp;
+       int rc = 0;
+
+       req = otx2_mbox_alloc_msg_ptp_op(mbox);
+       req->op = PTP_OP_GET_CLOCK;
+       req->is_pmu = is_pmu;
+       rc = otx2_mbox_process_msg(mbox, (void *)&rsp);
+       if (rc)
+               goto done;
+
+       *clock = rsp->clk;
+       *tsc = rsp->tsc;
+
+done:
+       return rc;
+}
+
+/* This function calculates two parameters "clk_freq_mult" and
+ * "clk_delta" which is useful in deriving PTP HI clock from
+ * rdtsc value.
+ */
+int
+otx2_nix_raw_clock_rdtsc_conv(struct otx2_eth_dev *dev)
+{
+       uint64_t ticks_base = 0, ticks = 0, t_freq = 0, tsc = 0;
+       uint8_t retval = 0, val;
+
+       /* Calculating the frequency at which PTP HI clock is running */
+       retval = nix_read_raw_clock(dev, &ticks_base, &tsc, false);
+       if (retval != 0) {
+               otx2_err("Failed to read the raw clock value: %d", retval);
+               goto done;
+       }
+
+       rte_delay_ms(100);
+
+       retval = nix_read_raw_clock(dev, &ticks, &tsc, false);
+       if (retval != 0) {
+               otx2_err("Failed to read the raw clock value: %d", retval);
+               goto done;
+       }
+
+       t_freq = (ticks - ticks_base) * 10;
+
+       /* Calculating the freq multiplier viz the ratio between the
+        * frequency at which PTP HI clock works and rdtsc clock runs
+        */
+       dev->clk_freq_mult =
+               (double)pow(10, floor(log10(t_freq))) / rte_get_timer_hz();
+
+       val = false;
+#ifdef RTE_ARM_EAL_RDTSC_USE_PMU
+       val = true;
+#endif
+       retval = nix_read_raw_clock(dev, &ticks, &tsc, val);
+       if (retval != 0) {
+               otx2_err("Failed to read the raw clock value: %d", retval);
+               goto done;
+       }
+
+       /* Calculating delta between PTP HI clock and rdtsc */
+       dev->clk_delta = ((uint64_t)(ticks / dev->clk_freq_mult) - tsc);
+
+done:
+       return retval;
+}
+
 static int
 otx2_nix_configure(struct rte_eth_dev *eth_dev)
 {
@@ -1363,6 +1447,7 @@ otx2_nix_configure(struct rte_eth_dev *eth_dev)
        dev->configured = 1;
        dev->configured_nb_rx_qs = data->nb_rx_queues;
        dev->configured_nb_tx_qs = data->nb_tx_queues;
+
        return 0;
 
 cq_fini:
@@ -1649,6 +1734,7 @@ static const struct eth_dev_ops otx2_eth_dev_ops = {
        .vlan_pvid_set            = otx2_nix_vlan_pvid_set,
        .rx_queue_intr_enable     = otx2_nix_rx_queue_intr_enable,
        .rx_queue_intr_disable    = otx2_nix_rx_queue_intr_disable,
+       .read_clock               = otx2_nix_read_clock,
 };
 
 static inline int
diff --git a/drivers/net/octeontx2/otx2_ethdev.h 
b/drivers/net/octeontx2/otx2_ethdev.h
index 863d4877f..a2bd0ffcf 100644
--- a/drivers/net/octeontx2/otx2_ethdev.h
+++ b/drivers/net/octeontx2/otx2_ethdev.h
@@ -300,6 +300,8 @@ struct otx2_eth_dev {
        struct rte_timecounter  systime_tc;
        struct rte_timecounter  rx_tstamp_tc;
        struct rte_timecounter  tx_tstamp_tc;
+       double clk_freq_mult;
+       uint64_t clk_delta;
 } __rte_cache_aligned;
 
 struct otx2_eth_txq {
@@ -527,5 +529,7 @@ int otx2_nix_timesync_write_time(struct rte_eth_dev 
*eth_dev,
 int otx2_nix_timesync_read_time(struct rte_eth_dev *eth_dev,
                                struct timespec *ts);
 int otx2_eth_dev_ptp_info_update(struct otx2_dev *dev, bool ptp_en);
+int otx2_nix_read_clock(struct rte_eth_dev *eth_dev, uint64_t *time);
+int otx2_nix_raw_clock_rdtsc_conv(struct otx2_eth_dev *dev);
 
 #endif /* __OTX2_ETHDEV_H__ */
diff --git a/drivers/net/octeontx2/otx2_ptp.c b/drivers/net/octeontx2/otx2_ptp.c
index 0186c629a..3f54cfeaf 100644
--- a/drivers/net/octeontx2/otx2_ptp.c
+++ b/drivers/net/octeontx2/otx2_ptp.c
@@ -224,6 +224,13 @@ otx2_nix_timesync_adjust_time(struct rte_eth_dev *eth_dev, 
int64_t delta)
                rc = otx2_mbox_process_msg(mbox, (void *)&rsp);
                if (rc)
                        return rc;
+               /* Since the frequency of PTP comp register is tuned, delta and
+                * freq mult calculation for deriving PTP_HI from rdtsc should
+                * be done again.
+                */
+               rc = otx2_nix_raw_clock_rdtsc_conv(dev);
+               if (rc)
+                       otx2_err("Failed to calculate delta and freq mult");
        }
        dev->systime_tc.nsec += delta;
        dev->rx_tstamp_tc.nsec += delta;
@@ -271,3 +278,26 @@ otx2_nix_timesync_read_time(struct rte_eth_dev *eth_dev, 
struct timespec *ts)
 
        return 0;
 }
+
+
+int
+otx2_nix_read_clock(struct rte_eth_dev *eth_dev, uint64_t *clock)
+{
+       struct otx2_eth_dev *dev = otx2_eth_pmd_priv(eth_dev);
+
+       if (!otx2_ethdev_is_ptp_en(dev)) {
+               otx2_err("PTP should be enabled.");
+               return -EINVAL;
+       }
+
+       /* This API returns the raw PTP HI clock value. Since LFs doesn't
+        * have direct access to PTP registers and it requires mbox msg
+        * to AF for this value. In fastpath reading this value for every
+        * packet (which involes mbox call) becomes very expensive, hence
+        * we should be able to derive PTP HI clock value from rdtsc by
+        * using freq_mult and clk_delta calculated during configure stage.
+        */
+       *clock = (rte_rdtsc() + dev->clk_delta) * dev->clk_freq_mult;
+
+       return 0;
+}
-- 
2.18.0

Reply via email to