net/cxgbe: support flow API for matching QinQ VLAN
[dpdk.git] / drivers / net / octeontx2 / otx2_ptp.c
index 0186c62..ae5a2b7 100644 (file)
@@ -8,6 +8,113 @@
 
 #define PTP_FREQ_ADJUST (1 << 9)
 
+/* Function to enable ptp config for VFs */
+void
+otx2_nix_ptp_enable_vf(struct rte_eth_dev *eth_dev)
+{
+       struct otx2_eth_dev *dev = otx2_eth_pmd_priv(eth_dev);
+
+       if (otx2_nix_recalc_mtu(eth_dev))
+               otx2_err("Failed to set MTU size for ptp");
+
+       dev->scalar_ena = true;
+       dev->rx_offload_flags |= NIX_RX_OFFLOAD_TSTAMP_F;
+
+       /* Setting up the function pointers as per new offload flags */
+       otx2_eth_set_rx_function(eth_dev);
+       otx2_eth_set_tx_function(eth_dev);
+}
+
+static uint16_t
+nix_eth_ptp_vf_burst(void *queue, struct rte_mbuf **mbufs, uint16_t pkts)
+{
+       struct otx2_eth_rxq *rxq = queue;
+       struct rte_eth_dev *eth_dev;
+
+       RTE_SET_USED(mbufs);
+       RTE_SET_USED(pkts);
+
+       eth_dev = rxq->eth_dev;
+       otx2_nix_ptp_enable_vf(eth_dev);
+
+       return 0;
+}
+
+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;
+
+       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 fail;
+
+       if (clock)
+               *clock = rsp->clk;
+       if (tsc)
+               *tsc = rsp->tsc;
+
+fail:
+       return rc;
+}
+
+/* This function calculates two parameters "clk_freq_mult" and
+ * "clk_delta" which is useful in deriving PTP HI clock from
+ * timestamp counter (tsc) value.
+ */
+int
+otx2_nix_raw_clock_tsc_conv(struct otx2_eth_dev *dev)
+{
+       uint64_t ticks_base = 0, ticks = 0, tsc = 0, t_freq;
+       int rc, val;
+
+       /* Calculating the frequency at which PTP HI clock is running */
+       rc = nix_read_raw_clock(dev, &ticks_base, &tsc, false);
+       if (rc) {
+               otx2_err("Failed to read the raw clock value: %d", rc);
+               goto fail;
+       }
+
+       rte_delay_ms(100);
+
+       rc = nix_read_raw_clock(dev, &ticks, &tsc, false);
+       if (rc) {
+               otx2_err("Failed to read the raw clock value: %d", rc);
+               goto fail;
+       }
+
+       t_freq = (ticks - ticks_base) * 10;
+
+       /* Calculating the freq multiplier viz the ratio between the
+        * frequency at which PTP HI clock works and tsc 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
+       rc = nix_read_raw_clock(dev, &ticks, &tsc, val);
+       if (rc) {
+               otx2_err("Failed to read the raw clock value: %d", rc);
+               goto fail;
+       }
+
+       /* Calculating delta between PTP HI clock and tsc */
+       dev->clk_delta = ((uint64_t)(ticks / dev->clk_freq_mult) - tsc);
+
+fail:
+       return rc;
+}
+
 static void
 nix_start_timecounters(struct rte_eth_dev *eth_dev)
 {
@@ -27,9 +134,9 @@ nix_ptp_config(struct rte_eth_dev *eth_dev, int en)
 {
        struct otx2_eth_dev *dev = otx2_eth_pmd_priv(eth_dev);
        struct otx2_mbox *mbox = dev->mbox;
-       uint8_t rc = 0;
+       uint8_t rc = -EINVAL;
 
-       if (otx2_dev_is_vf(dev))
+       if (otx2_dev_is_vf_or_sdp(dev) || otx2_dev_is_lbk(dev))
                return rc;
 
        if (en) {
@@ -61,9 +168,16 @@ int
 otx2_eth_dev_ptp_info_update(struct otx2_dev *dev, bool ptp_en)
 {
        struct otx2_eth_dev *otx2_dev = (struct otx2_eth_dev *)dev;
-       struct rte_eth_dev *eth_dev = otx2_dev->eth_dev;
+       struct rte_eth_dev *eth_dev;
        int i;
 
+       if (!dev)
+               return -EINVAL;
+
+       eth_dev = otx2_dev->eth_dev;
+       if (!eth_dev)
+               return -EINVAL;
+
        otx2_dev->ptp_en = ptp_en;
        for (i = 0; i < eth_dev->data->nb_rx_queues; i++) {
                struct otx2_eth_rxq *rxq = eth_dev->data->rx_queues[i];
@@ -71,6 +185,17 @@ otx2_eth_dev_ptp_info_update(struct otx2_dev *dev, bool ptp_en)
                        otx2_nix_rxq_mbuf_setup(otx2_dev,
                                                eth_dev->data->port_id);
        }
+       if (otx2_dev_is_vf(otx2_dev) && !(otx2_dev_is_sdp(otx2_dev)) &&
+           !(otx2_dev_is_lbk(otx2_dev))) {
+               /* In case of VF, setting of MTU cant be done directly in this
+                * function as this is running as part of MBOX request(PF->VF)
+                * and MTU setting also requires MBOX message to be
+                * sent(VF->PF)
+                */
+               eth_dev->rx_pkt_burst = nix_eth_ptp_vf_burst;
+               rte_mb();
+       }
+
        return 0;
 }
 
@@ -80,27 +205,36 @@ otx2_nix_timesync_enable(struct rte_eth_dev *eth_dev)
        struct otx2_eth_dev *dev = otx2_eth_pmd_priv(eth_dev);
        int i, rc = 0;
 
-       if (otx2_ethdev_is_ptp_en(dev)) {
-               otx2_info("PTP mode is already enabled ");
+       /* If we are VF/SDP/LBK, ptp cannot not be enabled */
+       if (otx2_dev_is_vf_or_sdp(dev) || otx2_dev_is_lbk(dev)) {
+               otx2_info("PTP cannot be enabled in case of VF/SDP/LBK");
                return -EINVAL;
        }
 
-       /* If we are VF, no further action can be taken */
-       if (otx2_dev_is_vf(dev))
+       if (otx2_ethdev_is_ptp_en(dev)) {
+               otx2_info("PTP mode is already enabled");
                return -EINVAL;
+       }
 
        if (!(dev->rx_offload_flags & NIX_RX_OFFLOAD_PTYPE_F)) {
                otx2_err("Ptype offload is disabled, it should be enabled");
                return -EINVAL;
        }
 
+       if (dev->npc_flow.switch_header_type == OTX2_PRIV_FLAGS_HIGIG) {
+               otx2_err("Both PTP and switch header enabled");
+               return -EINVAL;
+       }
+
        /* Allocating a iova address for tx tstamp */
        const struct rte_memzone *ts;
        ts = rte_eth_dma_zone_reserve(eth_dev, "otx2_ts",
                                      0, OTX2_ALIGN, OTX2_ALIGN,
                                      dev->node);
-       if (ts == NULL)
+       if (ts == NULL) {
                otx2_err("Failed to allocate mem for tx tstamp addr");
+               return -ENOMEM;
+       }
 
        dev->tstamp.tx_tstamp_iova = ts->iova;
        dev->tstamp.tx_tstamp = ts->addr;
@@ -123,6 +257,11 @@ otx2_nix_timesync_enable(struct rte_eth_dev *eth_dev)
                otx2_eth_set_rx_function(eth_dev);
                otx2_eth_set_tx_function(eth_dev);
        }
+
+       rc = otx2_nix_recalc_mtu(eth_dev);
+       if (rc)
+               otx2_err("Failed to set MTU size for ptp");
+
        return rc;
 }
 
@@ -137,8 +276,7 @@ otx2_nix_timesync_disable(struct rte_eth_dev *eth_dev)
                return -EINVAL;
        }
 
-       /* If we are VF, nothing else can be done */
-       if (otx2_dev_is_vf(dev))
+       if (otx2_dev_is_vf_or_sdp(dev) || otx2_dev_is_lbk(dev))
                return -EINVAL;
 
        dev->rx_offloads &= ~DEV_RX_OFFLOAD_TIMESTAMP;
@@ -156,6 +294,11 @@ otx2_nix_timesync_disable(struct rte_eth_dev *eth_dev)
                otx2_eth_set_rx_function(eth_dev);
                otx2_eth_set_tx_function(eth_dev);
        }
+
+       rc = otx2_nix_recalc_mtu(eth_dev);
+       if (rc)
+               otx2_err("Failed to set MTU size for ptp");
+
        return rc;
 }
 
@@ -175,9 +318,9 @@ otx2_nix_timesync_read_rx_timestamp(struct rte_eth_dev *eth_dev,
        *timestamp = rte_ns_to_timespec(ns);
        tstamp->rx_ready = 0;
 
-       otx2_nix_dbg("rx timestamp: %llu sec: %lu nsec %lu",
-                    (unsigned long long)tstamp->rx_tstamp, timestamp->tv_sec,
-                    timestamp->tv_nsec);
+       otx2_nix_dbg("rx timestamp: %"PRIu64" sec: %"PRIu64" nsec %"PRIu64"",
+                    (uint64_t)tstamp->rx_tstamp, (uint64_t)timestamp->tv_sec,
+                    (uint64_t)timestamp->tv_nsec);
 
        return 0;
 }
@@ -196,9 +339,9 @@ otx2_nix_timesync_read_tx_timestamp(struct rte_eth_dev *eth_dev,
        ns = rte_timecounter_update(&dev->tx_tstamp_tc, *tstamp->tx_tstamp);
        *timestamp = rte_ns_to_timespec(ns);
 
-       otx2_nix_dbg("tx timestamp: %llu sec: %lu nsec %lu",
-                    *(unsigned long long *)tstamp->tx_tstamp,
-                    timestamp->tv_sec, timestamp->tv_nsec);
+       otx2_nix_dbg("tx timestamp: %"PRIu64" sec: %"PRIu64" nsec %"PRIu64"",
+                    *tstamp->tx_tstamp, (uint64_t)timestamp->tv_sec,
+                    (uint64_t)timestamp->tv_nsec);
 
        *tstamp->tx_tstamp = 0;
        rte_wmb();
@@ -224,6 +367,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 timestamp
+                * counter should be done again.
+                */
+               rc = otx2_nix_raw_clock_tsc_conv(dev);
+               if (rc)
+                       otx2_err("Failed to calculate delta and freq mult");
        }
        dev->systime_tc.nsec += delta;
        dev->rx_tstamp_tc.nsec += delta;
@@ -267,7 +417,26 @@ otx2_nix_timesync_read_time(struct rte_eth_dev *eth_dev, struct timespec *ts)
        ns = rte_timecounter_update(&dev->systime_tc, rsp->clk);
        *ts = rte_ns_to_timespec(ns);
 
-       otx2_nix_dbg("PTP time read: %ld.%09ld", ts->tv_sec, ts->tv_nsec);
+       otx2_nix_dbg("PTP time read: %"PRIu64" .%09"PRIu64"",
+                    (uint64_t)ts->tv_sec, (uint64_t)ts->tv_nsec);
+
+       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);
+
+       /* 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 tsc by
+        * using freq_mult and clk_delta calculated during configure stage.
+        */
+       *clock = (rte_get_tsc_cycles() + dev->clk_delta) * dev->clk_freq_mult;
 
        return 0;
 }