]> git.droids-corp.org - dpdk.git/commitdiff
event/cnxk: add external clock support for timer
authorPavan Nikhilesh <pbhagavatula@marvell.com>
Mon, 13 Dec 2021 11:13:44 +0000 (16:43 +0530)
committerJerin Jacob <jerinj@marvell.com>
Thu, 20 Jan 2022 13:44:59 +0000 (14:44 +0100)
Add external clock support for cnxk timer adapter.

External clock mapping is as follows:
RTE_EVENT_TIMER_ADAPTER_EXT_CLK0 = TIM_CLK_SRC_10NS,
RTE_EVENT_TIMER_ADAPTER_EXT_CLK1 = TIM_CLK_SRC_GPIO,
RTE_EVENT_TIMER_ADAPTER_EXT_CLK2 = TIM_CLK_SRC_PTP,
RTE_EVENT_TIMER_ADAPTER_EXT_CLK3 = TIM_CLK_SRC_SYNCE,

TIM supports clock input from external GPIO, PTP, SYNCE clocks.
Input resolution is adjusted based on CNTVCT frequency for better
estimation.

Since TIM is unaware of input clock frequency, application is
expected to pass the frequency.
Example:
-a 0002:0e:00.0,tim_eclk_freq=122880000-0-0

The order of frequencies above is GPIO-PTP-SYNCE.

Signed-off-by: Shijith Thotton <sthotton@marvell.com>
Signed-off-by: Pavan Nikhilesh <pbhagavatula@marvell.com>
doc/guides/eventdevs/cnxk.rst
drivers/common/cnxk/roc_platform.h
drivers/event/cnxk/cn10k_eventdev.c
drivers/event/cnxk/cnxk_tim_evdev.c
drivers/event/cnxk/cnxk_tim_evdev.h

index 1c0ea988f239d50185c085ed07461a6813572a8b..8537f6257eaa75ec033573e8313f37ebd45957c4 100644 (file)
@@ -164,6 +164,24 @@ Runtime Config Options
 
     -a 0002:0e:00.0,tim_ring_ctl=[2-1023-1-0]
 
+- ``TIM external clock frequency``
+
+  The ``tim_eclk_freq`` devagrs can be used to pass external clock frequencies
+  when external clock source is selected.
+
+  External clock frequencies are mapped as follows::
+
+    RTE_EVENT_TIMER_ADAPTER_EXT_CLK0 = TIM_CLK_SRC_10NS,
+    RTE_EVENT_TIMER_ADAPTER_EXT_CLK1 = TIM_CLK_SRC_GPIO,
+    RTE_EVENT_TIMER_ADAPTER_EXT_CLK2 = TIM_CLK_SRC_PTP,
+    RTE_EVENT_TIMER_ADAPTER_EXT_CLK3 = TIM_CLK_SRC_SYNCE
+
+  The order of frequencies supplied to device args should be GPIO-PTP-SYNCE.
+
+  For Example::
+
+    -a 0002:0e:00.0,tim_eclk_freq=122880000-1000000000-0
+
 Debugging Options
 -----------------
 
index 85aa6dcebc0e46318ad35b0ab0588c64f01cf420..b055dd349e0507c46e7e94b28b9d9ac8248dc5a3 100644 (file)
@@ -45,6 +45,7 @@
 #define PLT_MAX                         RTE_MAX
 #define PLT_DIM                         RTE_DIM
 #define PLT_SET_USED            RTE_SET_USED
+#define PLT_SWAP                RTE_SWAP
 #define PLT_STATIC_ASSERT(s)    _Static_assert(s, #s)
 #define PLT_ALIGN               RTE_ALIGN
 #define PLT_ALIGN_MUL_CEIL      RTE_ALIGN_MUL_CEIL
index c5a8c1ae8f7c69314730f7ffd7a13bbaa7123784..7ee44ad61c67ddbe6bdbe6d5d80f6d1473c5fbce 100644 (file)
@@ -905,4 +905,5 @@ RTE_PMD_REGISTER_PARAM_STRING(event_cn10k, CNXK_SSO_XAE_CNT "=<int>"
                              CNXK_TIM_DISABLE_NPA "=1"
                              CNXK_TIM_CHNK_SLOTS "=<int>"
                              CNXK_TIM_RINGS_LMT "=<int>"
-                             CNXK_TIM_STATS_ENA "=1");
+                             CNXK_TIM_STATS_ENA "=1"
+                             CNXK_TIM_EXT_CLK "=<string>");
index becab1d1b12848a942489a7e3c05763267b95289..5d52a3975288a74d377fdd8bbe715a1c90da111c 100644 (file)
@@ -117,6 +117,80 @@ cnxk_tim_ring_info_get(const struct rte_event_timer_adapter *adptr,
                   sizeof(struct rte_event_timer_adapter_conf));
 }
 
+static inline void
+sort_multi_array(double ref_arr[], uint64_t arr1[], uint64_t arr2[],
+                uint64_t arr3[], uint8_t sz)
+{
+       int x;
+
+       for (x = 0; x < sz - 1; x++) {
+               if (ref_arr[x] > ref_arr[x + 1]) {
+                       PLT_SWAP(ref_arr[x], ref_arr[x + 1]);
+                       PLT_SWAP(arr1[x], arr1[x + 1]);
+                       PLT_SWAP(arr2[x], arr2[x + 1]);
+                       PLT_SWAP(arr3[x], arr3[x + 1]);
+                       x = -1;
+               }
+       }
+}
+
+static inline void
+populate_sample(uint64_t tck[], uint64_t ns[], double diff[], uint64_t dst[],
+               uint64_t req_tck, uint64_t clk_freq, double tck_ns, uint8_t sz,
+               bool mov_fwd)
+{
+       int i;
+
+       for (i = 0; i < sz; i++) {
+               tck[i] = i ? tck[i - 1] : req_tck;
+               do {
+                       mov_fwd ? tck[i]++ : tck[i]--;
+                       ns[i] = round((double)tck[i] * tck_ns);
+                       if (round((double)tck[i] * tck_ns) >
+                           ((double)tck[i] * tck_ns))
+                               continue;
+               } while (ns[i] % (uint64_t)cnxk_tim_ns_per_tck(clk_freq));
+               diff[i] = PLT_MAX((double)ns[i], (double)tck[i] * tck_ns) -
+                         PLT_MIN((double)ns[i], (double)tck[i] * tck_ns);
+               dst[i] = mov_fwd ? tck[i] - req_tck : req_tck - tck[i];
+       }
+}
+
+static void
+tim_adjust_resolution(uint64_t *req_ns, uint64_t *req_tck, double tck_ns,
+                     uint64_t clk_freq, uint64_t max_tmo, uint64_t m_tck)
+{
+#define MAX_SAMPLES 5
+       double rmax_diff[MAX_SAMPLES], rmin_diff[MAX_SAMPLES];
+       uint64_t min_tck[MAX_SAMPLES], max_tck[MAX_SAMPLES];
+       uint64_t min_dst[MAX_SAMPLES], max_dst[MAX_SAMPLES];
+       uint64_t min_ns[MAX_SAMPLES], max_ns[MAX_SAMPLES];
+       int i;
+
+       populate_sample(max_tck, max_ns, rmax_diff, max_dst, *req_tck, clk_freq,
+                       tck_ns, MAX_SAMPLES, true);
+       sort_multi_array(rmax_diff, max_dst, max_tck, max_ns, MAX_SAMPLES);
+
+       populate_sample(min_tck, min_ns, rmin_diff, min_dst, *req_tck, clk_freq,
+                       tck_ns, MAX_SAMPLES, false);
+       sort_multi_array(rmin_diff, min_dst, min_tck, min_ns, MAX_SAMPLES);
+
+       for (i = 0; i < MAX_SAMPLES; i++) {
+               if (min_dst[i] < max_dst[i] && min_tck[i] > m_tck &&
+                   (max_tmo / min_ns[i]) <=
+                           (TIM_MAX_BUCKET_SIZE - TIM_MIN_BUCKET_SIZE)) {
+                       *req_tck = min_tck[i];
+                       *req_ns = min_ns[i];
+                       break;
+               } else if ((max_tmo / max_ns[i]) <
+                          (TIM_MAX_BUCKET_SIZE - TIM_MIN_BUCKET_SIZE)) {
+                       *req_tck = max_tck[i];
+                       *req_ns = max_ns[i];
+                       break;
+               }
+       }
+}
+
 static int
 cnxk_tim_ring_create(struct rte_event_timer_adapter *adptr)
 {
@@ -178,10 +252,25 @@ cnxk_tim_ring_create(struct rte_event_timer_adapter *adptr)
                goto tim_hw_free;
        }
 
-       /* Round */
        tim_ring->tck_nsec =
                round(RTE_ALIGN_MUL_NEAR((long double)rcfg->timer_tick_ns,
                                         cnxk_tim_ns_per_tck(clk_freq)));
+       if (log10(clk_freq) - floor(log10(clk_freq)) != 0.0) {
+               uint64_t req_ns, req_tck;
+               double tck_ns;
+
+               req_ns = tim_ring->tck_nsec;
+               tck_ns = NSECPERSEC / clk_freq;
+               req_tck = round(rcfg->timer_tick_ns / tck_ns);
+               tim_adjust_resolution(&req_ns, &req_tck, tck_ns, clk_freq,
+                                     rcfg->max_tmo_ns, min_intvl_cyc);
+               if ((tim_ring->tck_nsec != req_ns) &&
+                   !(rcfg->flags & RTE_EVENT_TIMER_ADAPTER_F_ADJUST_RES)) {
+                       rc = -ERANGE;
+                       goto tim_hw_free;
+               }
+               tim_ring->tck_nsec = ceil(req_tck * tck_ns);
+       }
 
        tim_ring->tck_int = round((long double)tim_ring->tck_nsec /
                                  cnxk_tim_ns_per_tck(clk_freq));
@@ -457,11 +546,16 @@ cnxk_tim_parse_ring_ctl_list(const char *value, void *opaque)
        char *end = NULL;
        char *f = s;
 
+       if (s == NULL || !strlen(s))
+               return;
+
        while (*s) {
                if (*s == '[')
                        start = s;
                else if (*s == ']')
                        end = s;
+               else
+                       continue;
 
                if (start && start < end) {
                        *end = 0;
@@ -488,6 +582,43 @@ cnxk_tim_parse_kvargs_dict(const char *key, const char *value, void *opaque)
        return 0;
 }
 
+static void
+cnxk_tim_parse_clk_list(const char *value, void *opaque)
+{
+       enum roc_tim_clk_src src[] = {ROC_TIM_CLK_SRC_GPIO, ROC_TIM_CLK_SRC_PTP,
+                                     ROC_TIM_CLK_SRC_SYNCE,
+                                     ROC_TIM_CLK_SRC_INVALID};
+       struct cnxk_tim_evdev *dev = opaque;
+       char *str = strdup(value);
+       char *tok;
+       int i = 0;
+
+       if (str == NULL || !strlen(str))
+               return;
+
+       tok = strtok(str, "-");
+       while (tok != NULL && src[i] != ROC_TIM_CLK_SRC_INVALID) {
+               dev->ext_clk_freq[src[i]] = strtoull(tok, NULL, 10);
+               tok = strtok(NULL, "-");
+               i++;
+       }
+
+       free(str);
+}
+
+static int
+cnxk_tim_parse_kvargs_dsv(const char *key, const char *value, void *opaque)
+{
+       RTE_SET_USED(key);
+
+       /* DSV format GPIO-PTP-SYNCE-BTS use '-' as ','
+        * isn't allowed. 0 represents default.
+        */
+       cnxk_tim_parse_clk_list(value, opaque);
+
+       return 0;
+}
+
 static void
 cnxk_tim_parse_devargs(struct rte_devargs *devargs, struct cnxk_tim_evdev *dev)
 {
@@ -510,6 +641,8 @@ cnxk_tim_parse_devargs(struct rte_devargs *devargs, struct cnxk_tim_evdev *dev)
                           &dev->min_ring_cnt);
        rte_kvargs_process(kvlist, CNXK_TIM_RING_CTL,
                           &cnxk_tim_parse_kvargs_dict, &dev);
+       rte_kvargs_process(kvlist, CNXK_TIM_EXT_CLK, &cnxk_tim_parse_kvargs_dsv,
+                          dev);
 
        rte_kvargs_free(kvlist);
 }
@@ -558,7 +691,7 @@ cnxk_tim_fini(void)
 {
        struct cnxk_tim_evdev *dev = cnxk_tim_priv_get();
 
-       if (rte_eal_process_type() != RTE_PROC_PRIMARY)
+       if (dev == NULL || rte_eal_process_type() != RTE_PROC_PRIMARY)
                return;
 
        roc_tim_fini(&dev->tim);
index 1fb17f571d97f7732feb0fb9399e6ae73f193fc3..6b5342cc34d4ac79c9b53f0eac67169fa4cde735 100644 (file)
@@ -40,6 +40,7 @@
 #define CNXK_TIM_STATS_ENA   "tim_stats_ena"
 #define CNXK_TIM_RINGS_LMT   "tim_rings_lmt"
 #define CNXK_TIM_RING_CTL    "tim_ring_ctl"
+#define CNXK_TIM_EXT_CLK     "tim_eclk_freq"
 
 #define CNXK_TIM_SP       0x1
 #define CNXK_TIM_MP       0x2
@@ -95,6 +96,7 @@ struct cnxk_tim_evdev {
        uint32_t min_ring_cnt;
        uint8_t enable_stats;
        uint16_t ring_ctl_cnt;
+       uint64_t ext_clk_freq[ROC_TIM_CLK_SRC_INVALID];
        struct cnxk_tim_ctl *ring_ctl_data;
 };
 
@@ -236,6 +238,8 @@ cnxk_tim_get_clk_freq(struct cnxk_tim_evdev *dev, enum roc_tim_clk_src clk_src,
        case ROC_TIM_CLK_SRC_GPIO:
        case ROC_TIM_CLK_SRC_PTP:
        case ROC_TIM_CLK_SRC_SYNCE:
+               *freq = dev->ext_clk_freq[clk_src];
+               break;
        default:
                return -EINVAL;
        }