event/octeontx2: optimize timer Arm routine
[dpdk.git] / drivers / event / octeontx2 / otx2_tim_evdev.c
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright(C) 2019 Marvell International Ltd.
3  */
4
5 #include <rte_kvargs.h>
6 #include <rte_malloc.h>
7 #include <rte_mbuf_pool_ops.h>
8
9 #include "otx2_evdev.h"
10 #include "otx2_tim_evdev.h"
11
12 static struct rte_event_timer_adapter_ops otx2_tim_ops;
13
14 static inline int
15 tim_get_msix_offsets(void)
16 {
17         struct otx2_tim_evdev *dev = tim_priv_get();
18         struct otx2_mbox *mbox = dev->mbox;
19         struct msix_offset_rsp *msix_rsp;
20         int i, rc;
21
22         /* Get TIM MSIX vector offsets */
23         otx2_mbox_alloc_msg_msix_offset(mbox);
24         rc = otx2_mbox_process_msg(mbox, (void *)&msix_rsp);
25
26         for (i = 0; i < dev->nb_rings; i++)
27                 dev->tim_msixoff[i] = msix_rsp->timlf_msixoff[i];
28
29         return rc;
30 }
31
32 static void
33 tim_set_fp_ops(struct otx2_tim_ring *tim_ring)
34 {
35         uint8_t prod_flag = !tim_ring->prod_type_sp;
36
37         /* [DFB/FB] [SP][MP]*/
38         const rte_event_timer_arm_burst_t arm_burst[2][2][2] = {
39 #define FP(_name, _f3, _f2, _f1, flags)                                        \
40         [_f3][_f2][_f1] = otx2_tim_arm_burst_##_name,
41                 TIM_ARM_FASTPATH_MODES
42 #undef FP
43         };
44
45         const rte_event_timer_arm_tmo_tick_burst_t arm_tmo_burst[2][2] = {
46 #define FP(_name, _f2, _f1, flags)                                             \
47         [_f2][_f1] = otx2_tim_arm_tmo_tick_burst_##_name,
48                 TIM_ARM_TMO_FASTPATH_MODES
49 #undef FP
50         };
51
52         otx2_tim_ops.arm_burst =
53                 arm_burst[tim_ring->enable_stats][tim_ring->ena_dfb][prod_flag];
54         otx2_tim_ops.arm_tmo_tick_burst =
55                 arm_tmo_burst[tim_ring->enable_stats][tim_ring->ena_dfb];
56         otx2_tim_ops.cancel_burst = otx2_tim_timer_cancel_burst;
57 }
58
59 static void
60 otx2_tim_ring_info_get(const struct rte_event_timer_adapter *adptr,
61                        struct rte_event_timer_adapter_info *adptr_info)
62 {
63         struct otx2_tim_ring *tim_ring = adptr->data->adapter_priv;
64
65         adptr_info->max_tmo_ns = tim_ring->max_tout;
66         adptr_info->min_resolution_ns = tim_ring->ena_periodic ?
67                 tim_ring->max_tout : tim_ring->tck_nsec;
68         rte_memcpy(&adptr_info->conf, &adptr->data->conf,
69                    sizeof(struct rte_event_timer_adapter_conf));
70 }
71
72 static int
73 tim_chnk_pool_create(struct otx2_tim_ring *tim_ring,
74                      struct rte_event_timer_adapter_conf *rcfg)
75 {
76         unsigned int cache_sz = (tim_ring->nb_chunks / 1.5);
77         unsigned int mp_flags = 0;
78         char pool_name[25];
79         int rc;
80
81         cache_sz /= rte_lcore_count();
82         /* Create chunk pool. */
83         if (rcfg->flags & RTE_EVENT_TIMER_ADAPTER_F_SP_PUT) {
84                 mp_flags = MEMPOOL_F_SP_PUT | MEMPOOL_F_SC_GET;
85                 otx2_tim_dbg("Using single producer mode");
86                 tim_ring->prod_type_sp = true;
87         }
88
89         snprintf(pool_name, sizeof(pool_name), "otx2_tim_chunk_pool%d",
90                  tim_ring->ring_id);
91
92         if (cache_sz > RTE_MEMPOOL_CACHE_MAX_SIZE)
93                 cache_sz = RTE_MEMPOOL_CACHE_MAX_SIZE;
94
95         if (!tim_ring->disable_npa) {
96                 tim_ring->chunk_pool = rte_mempool_create_empty(pool_name,
97                                 tim_ring->nb_chunks, tim_ring->chunk_sz,
98                                 cache_sz, 0, rte_socket_id(), mp_flags);
99
100                 if (tim_ring->chunk_pool == NULL) {
101                         otx2_err("Unable to create chunkpool.");
102                         return -ENOMEM;
103                 }
104
105                 rc = rte_mempool_set_ops_byname(tim_ring->chunk_pool,
106                                                 rte_mbuf_platform_mempool_ops(),
107                                                 NULL);
108                 if (rc < 0) {
109                         otx2_err("Unable to set chunkpool ops");
110                         goto free;
111                 }
112
113                 rc = rte_mempool_populate_default(tim_ring->chunk_pool);
114                 if (rc < 0) {
115                         otx2_err("Unable to set populate chunkpool.");
116                         goto free;
117                 }
118                 tim_ring->aura = npa_lf_aura_handle_to_aura(
119                                 tim_ring->chunk_pool->pool_id);
120                 tim_ring->ena_dfb = tim_ring->ena_periodic ? 1 : 0;
121         } else {
122                 tim_ring->chunk_pool = rte_mempool_create(pool_name,
123                                 tim_ring->nb_chunks, tim_ring->chunk_sz,
124                                 cache_sz, 0, NULL, NULL, NULL, NULL,
125                                 rte_socket_id(),
126                                 mp_flags);
127                 if (tim_ring->chunk_pool == NULL) {
128                         otx2_err("Unable to create chunkpool.");
129                         return -ENOMEM;
130                 }
131                 tim_ring->ena_dfb = 1;
132         }
133
134         return 0;
135
136 free:
137         rte_mempool_free(tim_ring->chunk_pool);
138         return rc;
139 }
140
141 static void
142 tim_err_desc(int rc)
143 {
144         switch (rc) {
145         case TIM_AF_NO_RINGS_LEFT:
146                 otx2_err("Unable to allocat new TIM ring.");
147                 break;
148         case TIM_AF_INVALID_NPA_PF_FUNC:
149                 otx2_err("Invalid NPA pf func.");
150                 break;
151         case TIM_AF_INVALID_SSO_PF_FUNC:
152                 otx2_err("Invalid SSO pf func.");
153                 break;
154         case TIM_AF_RING_STILL_RUNNING:
155                 otx2_tim_dbg("Ring busy.");
156                 break;
157         case TIM_AF_LF_INVALID:
158                 otx2_err("Invalid Ring id.");
159                 break;
160         case TIM_AF_CSIZE_NOT_ALIGNED:
161                 otx2_err("Chunk size specified needs to be multiple of 16.");
162                 break;
163         case TIM_AF_CSIZE_TOO_SMALL:
164                 otx2_err("Chunk size too small.");
165                 break;
166         case TIM_AF_CSIZE_TOO_BIG:
167                 otx2_err("Chunk size too big.");
168                 break;
169         case TIM_AF_INTERVAL_TOO_SMALL:
170                 otx2_err("Bucket traversal interval too small.");
171                 break;
172         case TIM_AF_INVALID_BIG_ENDIAN_VALUE:
173                 otx2_err("Invalid Big endian value.");
174                 break;
175         case TIM_AF_INVALID_CLOCK_SOURCE:
176                 otx2_err("Invalid Clock source specified.");
177                 break;
178         case TIM_AF_GPIO_CLK_SRC_NOT_ENABLED:
179                 otx2_err("GPIO clock source not enabled.");
180                 break;
181         case TIM_AF_INVALID_BSIZE:
182                 otx2_err("Invalid bucket size.");
183                 break;
184         case TIM_AF_INVALID_ENABLE_PERIODIC:
185                 otx2_err("Invalid bucket size.");
186                 break;
187         case TIM_AF_INVALID_ENABLE_DONTFREE:
188                 otx2_err("Invalid Don't free value.");
189                 break;
190         case TIM_AF_ENA_DONTFRE_NSET_PERIODIC:
191                 otx2_err("Don't free bit not set when periodic is enabled.");
192                 break;
193         case TIM_AF_RING_ALREADY_DISABLED:
194                 otx2_err("Ring already stopped");
195                 break;
196         default:
197                 otx2_err("Unknown Error.");
198         }
199 }
200
201 static int
202 otx2_tim_ring_create(struct rte_event_timer_adapter *adptr)
203 {
204         struct rte_event_timer_adapter_conf *rcfg = &adptr->data->conf;
205         struct otx2_tim_evdev *dev = tim_priv_get();
206         struct otx2_tim_ring *tim_ring;
207         struct tim_config_req *cfg_req;
208         struct tim_ring_req *free_req;
209         struct tim_lf_alloc_req *req;
210         struct tim_lf_alloc_rsp *rsp;
211         uint8_t is_periodic;
212         int i, rc;
213
214         if (dev == NULL)
215                 return -ENODEV;
216
217         if (adptr->data->id >= dev->nb_rings)
218                 return -ENODEV;
219
220         req = otx2_mbox_alloc_msg_tim_lf_alloc(dev->mbox);
221         req->npa_pf_func = otx2_npa_pf_func_get();
222         req->sso_pf_func = otx2_sso_pf_func_get();
223         req->ring = adptr->data->id;
224
225         rc = otx2_mbox_process_msg(dev->mbox, (void **)&rsp);
226         if (rc < 0) {
227                 tim_err_desc(rc);
228                 return -ENODEV;
229         }
230
231         if (NSEC2TICK(RTE_ALIGN_MUL_CEIL(rcfg->timer_tick_ns, 10),
232                       rsp->tenns_clk) < OTX2_TIM_MIN_TMO_TKS) {
233                 if (rcfg->flags & RTE_EVENT_TIMER_ADAPTER_F_ADJUST_RES)
234                         rcfg->timer_tick_ns = TICK2NSEC(OTX2_TIM_MIN_TMO_TKS,
235                                         rsp->tenns_clk);
236                 else {
237                         rc = -ERANGE;
238                         goto rng_mem_err;
239                 }
240         }
241
242         is_periodic = 0;
243         if (rcfg->flags & RTE_EVENT_TIMER_ADAPTER_F_PERIODIC) {
244                 if (rcfg->max_tmo_ns &&
245                     rcfg->max_tmo_ns != rcfg->timer_tick_ns) {
246                         rc = -ERANGE;
247                         goto rng_mem_err;
248                 }
249
250                 /* Use 2 buckets to avoid contention */
251                 rcfg->max_tmo_ns = rcfg->timer_tick_ns;
252                 rcfg->timer_tick_ns /= 2;
253                 is_periodic = 1;
254         }
255
256         tim_ring = rte_zmalloc("otx2_tim_prv", sizeof(struct otx2_tim_ring), 0);
257         if (tim_ring == NULL) {
258                 rc =  -ENOMEM;
259                 goto rng_mem_err;
260         }
261
262         adptr->data->adapter_priv = tim_ring;
263
264         tim_ring->tenns_clk_freq = rsp->tenns_clk;
265         tim_ring->clk_src = (int)rcfg->clk_src;
266         tim_ring->ring_id = adptr->data->id;
267         tim_ring->tck_nsec = RTE_ALIGN_MUL_CEIL(rcfg->timer_tick_ns, 10);
268         tim_ring->max_tout = is_periodic ?
269                 rcfg->timer_tick_ns * 2 : rcfg->max_tmo_ns;
270         tim_ring->nb_bkts = (tim_ring->max_tout / tim_ring->tck_nsec);
271         tim_ring->chunk_sz = dev->chunk_sz;
272         tim_ring->nb_timers = rcfg->nb_timers;
273         tim_ring->disable_npa = dev->disable_npa;
274         tim_ring->ena_periodic = is_periodic;
275         tim_ring->enable_stats = dev->enable_stats;
276
277         for (i = 0; i < dev->ring_ctl_cnt ; i++) {
278                 struct otx2_tim_ctl *ring_ctl = &dev->ring_ctl_data[i];
279
280                 if (ring_ctl->ring == tim_ring->ring_id) {
281                         tim_ring->chunk_sz = ring_ctl->chunk_slots ?
282                                 ((uint32_t)(ring_ctl->chunk_slots + 1) *
283                                  OTX2_TIM_CHUNK_ALIGNMENT) : tim_ring->chunk_sz;
284                         tim_ring->enable_stats = ring_ctl->enable_stats;
285                         tim_ring->disable_npa = ring_ctl->disable_npa;
286                 }
287         }
288
289         tim_ring->nb_chunks = tim_ring->nb_timers / OTX2_TIM_NB_CHUNK_SLOTS(
290                                                         tim_ring->chunk_sz);
291         tim_ring->nb_chunk_slots = OTX2_TIM_NB_CHUNK_SLOTS(tim_ring->chunk_sz);
292
293         if (tim_ring->disable_npa)
294                 tim_ring->nb_chunks = tim_ring->nb_chunks * tim_ring->nb_bkts;
295         else
296                 tim_ring->nb_chunks = tim_ring->nb_chunks + tim_ring->nb_bkts;
297
298         /* Create buckets. */
299         tim_ring->bkt = rte_zmalloc("otx2_tim_bucket", (tim_ring->nb_bkts) *
300                                     sizeof(struct otx2_tim_bkt),
301                                     RTE_CACHE_LINE_SIZE);
302         if (tim_ring->bkt == NULL)
303                 goto bkt_mem_err;
304
305         rc = tim_chnk_pool_create(tim_ring, rcfg);
306         if (rc < 0)
307                 goto chnk_mem_err;
308
309         cfg_req = otx2_mbox_alloc_msg_tim_config_ring(dev->mbox);
310
311         cfg_req->ring = tim_ring->ring_id;
312         cfg_req->bigendian = false;
313         cfg_req->clocksource = tim_ring->clk_src;
314         cfg_req->enableperiodic = tim_ring->ena_periodic;
315         cfg_req->enabledontfreebuffer = tim_ring->ena_dfb;
316         cfg_req->bucketsize = tim_ring->nb_bkts;
317         cfg_req->chunksize = tim_ring->chunk_sz;
318         cfg_req->interval = NSEC2TICK(tim_ring->tck_nsec,
319                                       tim_ring->tenns_clk_freq);
320
321         rc = otx2_mbox_process(dev->mbox);
322         if (rc < 0) {
323                 tim_err_desc(rc);
324                 goto chnk_mem_err;
325         }
326
327         tim_ring->base = dev->bar2 +
328                 (RVU_BLOCK_ADDR_TIM << 20 | tim_ring->ring_id << 12);
329
330         rc = tim_register_irq(tim_ring->ring_id);
331         if (rc < 0)
332                 goto chnk_mem_err;
333
334         otx2_write64((uint64_t)tim_ring->bkt,
335                      tim_ring->base + TIM_LF_RING_BASE);
336         otx2_write64(tim_ring->aura, tim_ring->base + TIM_LF_RING_AURA);
337
338         /* Set fastpath ops. */
339         tim_set_fp_ops(tim_ring);
340
341         /* Update SSO xae count. */
342         sso_updt_xae_cnt(sso_pmd_priv(dev->event_dev), (void *)tim_ring,
343                          RTE_EVENT_TYPE_TIMER);
344         sso_xae_reconfigure(dev->event_dev);
345
346         otx2_tim_dbg("Total memory used %"PRIu64"MB\n",
347                         (uint64_t)(((tim_ring->nb_chunks * tim_ring->chunk_sz)
348                         + (tim_ring->nb_bkts * sizeof(struct otx2_tim_bkt))) /
349                         BIT_ULL(20)));
350
351         return rc;
352
353 chnk_mem_err:
354         rte_free(tim_ring->bkt);
355 bkt_mem_err:
356         rte_free(tim_ring);
357 rng_mem_err:
358         free_req = otx2_mbox_alloc_msg_tim_lf_free(dev->mbox);
359         free_req->ring = adptr->data->id;
360         otx2_mbox_process(dev->mbox);
361         return rc;
362 }
363
364 static void
365 otx2_tim_calibrate_start_tsc(struct otx2_tim_ring *tim_ring)
366 {
367 #define OTX2_TIM_CALIB_ITER     1E6
368         uint32_t real_bkt, bucket;
369         int icount, ecount = 0;
370         uint64_t bkt_cyc;
371
372         for (icount = 0; icount < OTX2_TIM_CALIB_ITER; icount++) {
373                 real_bkt = otx2_read64(tim_ring->base + TIM_LF_RING_REL) >> 44;
374                 bkt_cyc = rte_rdtsc();
375                 bucket = (bkt_cyc - tim_ring->ring_start_cyc) /
376                                                         tim_ring->tck_int;
377                 bucket = bucket % (tim_ring->nb_bkts);
378                 tim_ring->ring_start_cyc = bkt_cyc - (real_bkt *
379                                                         tim_ring->tck_int);
380                 if (bucket != real_bkt)
381                         ecount++;
382         }
383         tim_ring->last_updt_cyc = bkt_cyc;
384         otx2_tim_dbg("Bucket mispredict %3.2f distance %d\n",
385                      100 - (((double)(icount - ecount) / (double)icount) * 100),
386                      bucket - real_bkt);
387 }
388
389 static int
390 otx2_tim_ring_start(const struct rte_event_timer_adapter *adptr)
391 {
392         struct otx2_tim_ring *tim_ring = adptr->data->adapter_priv;
393         struct otx2_tim_evdev *dev = tim_priv_get();
394         struct tim_enable_rsp *rsp;
395         struct tim_ring_req *req;
396         int rc;
397
398         if (dev == NULL)
399                 return -ENODEV;
400
401         req = otx2_mbox_alloc_msg_tim_enable_ring(dev->mbox);
402         req->ring = tim_ring->ring_id;
403
404         rc = otx2_mbox_process_msg(dev->mbox, (void **)&rsp);
405         if (rc < 0) {
406                 tim_err_desc(rc);
407                 goto fail;
408         }
409 #ifdef RTE_ARM_EAL_RDTSC_USE_PMU
410         uint64_t tenns_stmp, tenns_diff;
411         uint64_t pmu_stmp;
412
413         pmu_stmp = rte_rdtsc();
414         asm volatile("mrs %0, cntvct_el0" : "=r" (tenns_stmp));
415
416         tenns_diff = tenns_stmp - rsp->timestarted;
417         pmu_stmp = pmu_stmp - (NSEC2TICK(tenns_diff  * 10, rte_get_timer_hz()));
418         tim_ring->ring_start_cyc = pmu_stmp;
419 #else
420         tim_ring->ring_start_cyc = rsp->timestarted;
421 #endif
422         tim_ring->tck_int = NSEC2TICK(tim_ring->tck_nsec, rte_get_timer_hz());
423         tim_ring->tot_int = tim_ring->tck_int * tim_ring->nb_bkts;
424         tim_ring->fast_div = rte_reciprocal_value_u64(tim_ring->tck_int);
425         tim_ring->fast_bkt = rte_reciprocal_value_u64(tim_ring->nb_bkts);
426
427         otx2_tim_calibrate_start_tsc(tim_ring);
428
429 fail:
430         return rc;
431 }
432
433 static int
434 otx2_tim_ring_stop(const struct rte_event_timer_adapter *adptr)
435 {
436         struct otx2_tim_ring *tim_ring = adptr->data->adapter_priv;
437         struct otx2_tim_evdev *dev = tim_priv_get();
438         struct tim_ring_req *req;
439         int rc;
440
441         if (dev == NULL)
442                 return -ENODEV;
443
444         req = otx2_mbox_alloc_msg_tim_disable_ring(dev->mbox);
445         req->ring = tim_ring->ring_id;
446
447         rc = otx2_mbox_process(dev->mbox);
448         if (rc < 0) {
449                 tim_err_desc(rc);
450                 rc = -EBUSY;
451         }
452
453         return rc;
454 }
455
456 static int
457 otx2_tim_ring_free(struct rte_event_timer_adapter *adptr)
458 {
459         struct otx2_tim_ring *tim_ring = adptr->data->adapter_priv;
460         struct otx2_tim_evdev *dev = tim_priv_get();
461         struct tim_ring_req *req;
462         int rc;
463
464         if (dev == NULL)
465                 return -ENODEV;
466
467         tim_unregister_irq(tim_ring->ring_id);
468
469         req = otx2_mbox_alloc_msg_tim_lf_free(dev->mbox);
470         req->ring = tim_ring->ring_id;
471
472         rc = otx2_mbox_process(dev->mbox);
473         if (rc < 0) {
474                 tim_err_desc(rc);
475                 return -EBUSY;
476         }
477
478         rte_free(tim_ring->bkt);
479         rte_mempool_free(tim_ring->chunk_pool);
480         rte_free(adptr->data->adapter_priv);
481
482         return 0;
483 }
484
485 static int
486 otx2_tim_stats_get(const struct rte_event_timer_adapter *adapter,
487                    struct rte_event_timer_adapter_stats *stats)
488 {
489         struct otx2_tim_ring *tim_ring = adapter->data->adapter_priv;
490         uint64_t bkt_cyc = rte_rdtsc() - tim_ring->ring_start_cyc;
491
492
493         stats->evtim_exp_count = __atomic_load_n(&tim_ring->arm_cnt,
494                                                  __ATOMIC_RELAXED);
495         stats->ev_enq_count = stats->evtim_exp_count;
496         stats->adapter_tick_count = rte_reciprocal_divide_u64(bkt_cyc,
497                                 &tim_ring->fast_div);
498         return 0;
499 }
500
501 static int
502 otx2_tim_stats_reset(const struct rte_event_timer_adapter *adapter)
503 {
504         struct otx2_tim_ring *tim_ring = adapter->data->adapter_priv;
505
506         __atomic_store_n(&tim_ring->arm_cnt, 0, __ATOMIC_RELAXED);
507         return 0;
508 }
509
510 int
511 otx2_tim_caps_get(const struct rte_eventdev *evdev, uint64_t flags,
512                   uint32_t *caps,
513                   const struct rte_event_timer_adapter_ops **ops)
514 {
515         struct otx2_tim_evdev *dev = tim_priv_get();
516
517         RTE_SET_USED(flags);
518
519         if (dev == NULL)
520                 return -ENODEV;
521
522         otx2_tim_ops.init = otx2_tim_ring_create;
523         otx2_tim_ops.uninit = otx2_tim_ring_free;
524         otx2_tim_ops.start = otx2_tim_ring_start;
525         otx2_tim_ops.stop = otx2_tim_ring_stop;
526         otx2_tim_ops.get_info   = otx2_tim_ring_info_get;
527
528         if (dev->enable_stats) {
529                 otx2_tim_ops.stats_get   = otx2_tim_stats_get;
530                 otx2_tim_ops.stats_reset = otx2_tim_stats_reset;
531         }
532
533         /* Store evdev pointer for later use. */
534         dev->event_dev = (struct rte_eventdev *)(uintptr_t)evdev;
535         *caps = RTE_EVENT_TIMER_ADAPTER_CAP_INTERNAL_PORT |
536                 RTE_EVENT_TIMER_ADAPTER_CAP_PERIODIC;
537         *ops = &otx2_tim_ops;
538
539         return 0;
540 }
541
542 #define OTX2_TIM_DISABLE_NPA    "tim_disable_npa"
543 #define OTX2_TIM_CHNK_SLOTS     "tim_chnk_slots"
544 #define OTX2_TIM_STATS_ENA      "tim_stats_ena"
545 #define OTX2_TIM_RINGS_LMT      "tim_rings_lmt"
546 #define OTX2_TIM_RING_CTL       "tim_ring_ctl"
547
548 static void
549 tim_parse_ring_param(char *value, void *opaque)
550 {
551         struct otx2_tim_evdev *dev = opaque;
552         struct otx2_tim_ctl ring_ctl = {0};
553         char *tok = strtok(value, "-");
554         struct otx2_tim_ctl *old_ptr;
555         uint16_t *val;
556
557         val = (uint16_t *)&ring_ctl;
558
559         if (!strlen(value))
560                 return;
561
562         while (tok != NULL) {
563                 *val = atoi(tok);
564                 tok = strtok(NULL, "-");
565                 val++;
566         }
567
568         if (val != (&ring_ctl.enable_stats + 1)) {
569                 otx2_err(
570                 "Invalid ring param expected [ring-chunk_sz-disable_npa-enable_stats]");
571                 return;
572         }
573
574         dev->ring_ctl_cnt++;
575         old_ptr = dev->ring_ctl_data;
576         dev->ring_ctl_data = rte_realloc(dev->ring_ctl_data,
577                                          sizeof(struct otx2_tim_ctl) *
578                                          dev->ring_ctl_cnt, 0);
579         if (dev->ring_ctl_data == NULL) {
580                 dev->ring_ctl_data = old_ptr;
581                 dev->ring_ctl_cnt--;
582                 return;
583         }
584
585         dev->ring_ctl_data[dev->ring_ctl_cnt - 1] = ring_ctl;
586 }
587
588 static void
589 tim_parse_ring_ctl_list(const char *value, void *opaque)
590 {
591         char *s = strdup(value);
592         char *start = NULL;
593         char *end = NULL;
594         char *f = s;
595
596         while (*s) {
597                 if (*s == '[')
598                         start = s;
599                 else if (*s == ']')
600                         end = s;
601
602                 if (start && start < end) {
603                         *end = 0;
604                         tim_parse_ring_param(start + 1, opaque);
605                         start = end;
606                         s = end;
607                 }
608                 s++;
609         }
610
611         free(f);
612 }
613
614 static int
615 tim_parse_kvargs_dict(const char *key, const char *value, void *opaque)
616 {
617         RTE_SET_USED(key);
618
619         /* Dict format [ring-chunk_sz-disable_npa-enable_stats] use '-' as ','
620          * isn't allowed. 0 represents default.
621          */
622         tim_parse_ring_ctl_list(value, opaque);
623
624         return 0;
625 }
626
627 static void
628 tim_parse_devargs(struct rte_devargs *devargs, struct otx2_tim_evdev *dev)
629 {
630         struct rte_kvargs *kvlist;
631
632         if (devargs == NULL)
633                 return;
634
635         kvlist = rte_kvargs_parse(devargs->args, NULL);
636         if (kvlist == NULL)
637                 return;
638
639         rte_kvargs_process(kvlist, OTX2_TIM_DISABLE_NPA,
640                            &parse_kvargs_flag, &dev->disable_npa);
641         rte_kvargs_process(kvlist, OTX2_TIM_CHNK_SLOTS,
642                            &parse_kvargs_value, &dev->chunk_slots);
643         rte_kvargs_process(kvlist, OTX2_TIM_STATS_ENA, &parse_kvargs_flag,
644                            &dev->enable_stats);
645         rte_kvargs_process(kvlist, OTX2_TIM_RINGS_LMT, &parse_kvargs_value,
646                            &dev->min_ring_cnt);
647         rte_kvargs_process(kvlist, OTX2_TIM_RING_CTL,
648                            &tim_parse_kvargs_dict, &dev);
649
650         rte_kvargs_free(kvlist);
651 }
652
653 void
654 otx2_tim_init(struct rte_pci_device *pci_dev, struct otx2_dev *cmn_dev)
655 {
656         struct rsrc_attach_req *atch_req;
657         struct rsrc_detach_req *dtch_req;
658         struct free_rsrcs_rsp *rsrc_cnt;
659         const struct rte_memzone *mz;
660         struct otx2_tim_evdev *dev;
661         int rc;
662
663         if (rte_eal_process_type() != RTE_PROC_PRIMARY)
664                 return;
665
666         mz = rte_memzone_reserve(RTE_STR(OTX2_TIM_EVDEV_NAME),
667                                  sizeof(struct otx2_tim_evdev),
668                                  rte_socket_id(), 0);
669         if (mz == NULL) {
670                 otx2_tim_dbg("Unable to allocate memory for TIM Event device");
671                 return;
672         }
673
674         dev = mz->addr;
675         dev->pci_dev = pci_dev;
676         dev->mbox = cmn_dev->mbox;
677         dev->bar2 = cmn_dev->bar2;
678
679         tim_parse_devargs(pci_dev->device.devargs, dev);
680
681         otx2_mbox_alloc_msg_free_rsrc_cnt(dev->mbox);
682         rc = otx2_mbox_process_msg(dev->mbox, (void *)&rsrc_cnt);
683         if (rc < 0) {
684                 otx2_err("Unable to get free rsrc count.");
685                 goto mz_free;
686         }
687
688         dev->nb_rings = dev->min_ring_cnt ?
689                 RTE_MIN(dev->min_ring_cnt, rsrc_cnt->tim) : rsrc_cnt->tim;
690
691         if (!dev->nb_rings) {
692                 otx2_tim_dbg("No TIM Logical functions provisioned.");
693                 goto mz_free;
694         }
695
696         atch_req = otx2_mbox_alloc_msg_attach_resources(dev->mbox);
697         atch_req->modify = true;
698         atch_req->timlfs = dev->nb_rings;
699
700         rc = otx2_mbox_process(dev->mbox);
701         if (rc < 0) {
702                 otx2_err("Unable to attach TIM rings.");
703                 goto mz_free;
704         }
705
706         rc = tim_get_msix_offsets();
707         if (rc < 0) {
708                 otx2_err("Unable to get MSIX offsets for TIM.");
709                 goto detach;
710         }
711
712         if (dev->chunk_slots &&
713             dev->chunk_slots <= OTX2_TIM_MAX_CHUNK_SLOTS &&
714             dev->chunk_slots >= OTX2_TIM_MIN_CHUNK_SLOTS) {
715                 dev->chunk_sz = (dev->chunk_slots + 1) *
716                         OTX2_TIM_CHUNK_ALIGNMENT;
717         } else {
718                 dev->chunk_sz = OTX2_TIM_RING_DEF_CHUNK_SZ;
719         }
720
721         return;
722
723 detach:
724         dtch_req = otx2_mbox_alloc_msg_detach_resources(dev->mbox);
725         dtch_req->partial = true;
726         dtch_req->timlfs = true;
727
728         otx2_mbox_process(dev->mbox);
729 mz_free:
730         rte_memzone_free(mz);
731 }
732
733 void
734 otx2_tim_fini(void)
735 {
736         struct otx2_tim_evdev *dev = tim_priv_get();
737         struct rsrc_detach_req *dtch_req;
738
739         if (rte_eal_process_type() != RTE_PROC_PRIMARY)
740                 return;
741
742         dtch_req = otx2_mbox_alloc_msg_detach_resources(dev->mbox);
743         dtch_req->partial = true;
744         dtch_req->timlfs = true;
745
746         otx2_mbox_process(dev->mbox);
747         rte_memzone_free(rte_memzone_lookup(RTE_STR(OTX2_TIM_EVDEV_NAME)));
748 }