[PATCH] event/cnxk: fix TIM HWWQE handling and chunk alignment
pbhagavatula at marvell.com
pbhagavatula at marvell.com
Fri Oct 16 11:51:31 CEST 2026
From: Pavan Nikhilesh <pbhagavatula at marvell.com>
Use a single predicate for HWWQE enable, fast-path selection and chunk
pool sizing so a TIM_HWWQE_VER_0 device is not run with HWWQE paths
without being configured. Fix the burst response mapping in
cnxk_tim_add_entry_tmo_hwwqe() to match the single timer path.
With tim_disable_npa, the generic ring ops only align objects to
RTE_MEMPOOL_ALIGN, which does not give the 256B alignment CN20K needs.
Populate the pool from a 256B aligned memzone with the trailer padded
so the object stride is a multiple of 256B, and keep the chunk slot
count within CNXK_TIM_MAX_CHUNK_SLOTS after rounding up.
Fixes: 19861e9eac8d ("event/cnxk: align CN20K TIM chunk buffers")
Signed-off-by: Pavan Nikhilesh <pbhagavatula at marvell.com>
---
drivers/event/cnxk/cnxk_tim_evdev.c | 100 ++++++++++++++++++++++-----
drivers/event/cnxk/cnxk_tim_worker.h | 41 +++++------
2 files changed, 103 insertions(+), 38 deletions(-)
diff --git a/drivers/event/cnxk/cnxk_tim_evdev.c b/drivers/event/cnxk/cnxk_tim_evdev.c
index 44acd4ef5170..41f1d20cec5a 100644
--- a/drivers/event/cnxk/cnxk_tim_evdev.c
+++ b/drivers/event/cnxk/cnxk_tim_evdev.c
@@ -12,14 +12,56 @@
static struct event_timer_adapter_ops cnxk_tim_ops;
static cnxk_sso_set_priv_mem_t sso_set_priv_mem_fn;
+static void
+cnxk_tim_chnk_pool_mem_free(struct rte_mempool_memhdr *memhdr, void *opaque)
+{
+ RTE_SET_USED(memhdr);
+ rte_free(opaque);
+}
+
+/* CN20K needs 256B aligned chunk buffers (cn20k-tim 14.2), other models use ROC_ALIGN. */
+static inline size_t
+cnxk_tim_chunk_buf_align(void)
+{
+ return roc_model_is_cn20k() ? CNXK_TIM_CN20K_CHUNK_BUF_ALIGN : ROC_ALIGN;
+}
+
+/* Populate the pool from a single aligned block, like the SSO XAQ pool. */
+static int
+cnxk_tim_chnk_pool_populate_aligned(struct rte_mempool *mp, size_t align)
+{
+ size_t stride, len;
+ void *mem;
+ int rc;
+
+ stride = (size_t)mp->header_size + mp->elt_size + mp->trailer_size;
+ len = stride * mp->size;
+
+ mem = rte_zmalloc_socket("cnxk_tim_chunks", len, align, mp->socket_id);
+ if (mem == NULL)
+ return -ENOMEM;
+
+ rc = rte_mempool_populate_iova(mp, mem, rte_malloc_virt2iova(mem), len,
+ cnxk_tim_chnk_pool_mem_free, mem);
+ if (rc <= 0) {
+ /* The pool only takes ownership of the memory when objects were added. */
+ rte_free(mem);
+ return rc < 0 ? rc : -ENOMEM;
+ }
+
+ return 0;
+}
+
static int
cnxk_tim_chnk_pool_create(struct cnxk_tim_ring *tim_ring,
struct rte_event_timer_adapter_conf *rcfg)
{
unsigned int mp_flags = 0;
+ struct rte_mempool *mp;
unsigned int cache_sz;
- const char *ops;
char pool_name[25];
+ size_t align, sz;
+ const char *ops;
int rc;
/* Create chunk pool. */
@@ -29,6 +71,10 @@ cnxk_tim_chnk_pool_create(struct cnxk_tim_ring *tim_ring,
tim_ring->prod_type_sp = true;
}
+ /* One aligned block backs the pool, so objects need not be page contiguous. */
+ if (tim_ring->disable_npa)
+ mp_flags |= RTE_MEMPOOL_F_NO_IOVA_CONTIG;
+
snprintf(pool_name, sizeof(pool_name), "cnxk_tim_chunk_pool%d",
tim_ring->ring_id);
@@ -43,10 +89,12 @@ cnxk_tim_chnk_pool_create(struct cnxk_tim_ring *tim_ring,
return -ENOMEM;
}
- /* cn20k needs 256B-aligned chunk buffers (cn20k-tim 14.2). */
- if (roc_model_is_cn20k())
- tim_ring->chunk_pool->header_size = RTE_ALIGN_CEIL(
- tim_ring->chunk_pool->header_size, CNXK_TIM_CN20K_CHUNK_BUF_ALIGN);
+ /* Align the header and pad the trailer so every chunk buffer is aligned. */
+ mp = tim_ring->chunk_pool;
+ align = cnxk_tim_chunk_buf_align();
+ mp->header_size = RTE_ALIGN_CEIL(mp->header_size, align);
+ sz = (size_t)mp->header_size + mp->elt_size + mp->trailer_size;
+ mp->trailer_size += RTE_ALIGN_CEIL(sz, align) - sz;
if (!tim_ring->disable_npa)
ops = rte_mbuf_platform_mempool_ops();
@@ -61,7 +109,11 @@ cnxk_tim_chnk_pool_create(struct cnxk_tim_ring *tim_ring,
goto free;
}
- rc = rte_mempool_populate_default(tim_ring->chunk_pool);
+ if (tim_ring->disable_npa) {
+ rc = cnxk_tim_chnk_pool_populate_aligned(tim_ring->chunk_pool, align);
+ } else {
+ rc = rte_mempool_populate_default(tim_ring->chunk_pool);
+ }
if (rc < 0) {
plt_err("Unable to populate chunkpool.");
goto free;
@@ -81,6 +133,12 @@ cnxk_tim_chnk_pool_create(struct cnxk_tim_ring *tim_ring,
return rc;
}
+static inline bool
+cnxk_tim_hwwqe_enabled(const struct cnxk_tim_evdev *dev)
+{
+ return dev->tim.feat.hwwqe && dev->tim.feat.hwwqe_ver != TIM_HWWQE_VER_0;
+}
+
static int
cnxk_tim_enable_hwwqe(struct cnxk_tim_evdev *dev, struct cnxk_tim_ring *tim_ring)
{
@@ -120,7 +178,7 @@ cnxk_tim_set_fp_ops(struct cnxk_tim_ring *tim_ring)
if (dev == NULL)
return;
- if (dev->tim.feat.hwwqe) {
+ if (cnxk_tim_hwwqe_enabled(dev)) {
cnxk_tim_ops.arm_burst = cnxk_tim_arm_burst_hwwqe;
cnxk_tim_ops.arm_tmo_tick_burst = cnxk_tim_arm_tmo_burst_hwwqe;
cnxk_tim_ops.cancel_burst = cnxk_tim_timer_cancel_burst_hwwqe;
@@ -243,24 +301,30 @@ cnxk_tim_ring_create(struct rte_event_timer_adapter *adptr)
struct cnxk_tim_ctl *ring_ctl = &dev->ring_ctl_data[i];
if (ring_ctl->ring == tim_ring->ring_id) {
- tim_ring->chunk_sz =
- ring_ctl->chunk_slots ?
- ((uint32_t)(ring_ctl->chunk_slots + 1) *
- CNXK_TIM_CHUNK_ALIGNMENT) :
- tim_ring->chunk_sz;
+ if (ring_ctl->chunk_slots >= CNXK_TIM_MIN_CHUNK_SLOTS &&
+ ring_ctl->chunk_slots <= CNXK_TIM_MAX_CHUNK_SLOTS)
+ tim_ring->chunk_sz = ((uint32_t)ring_ctl->chunk_slots + 1) *
+ CNXK_TIM_CHUNK_ALIGNMENT;
tim_ring->enable_stats = ring_ctl->enable_stats;
tim_ring->disable_npa = ring_ctl->disable_npa;
}
}
- if (roc_model_is_cn20k())
+ if (roc_model_is_cn20k()) {
tim_ring->chunk_sz =
RTE_ALIGN_CEIL(tim_ring->chunk_sz, CNXK_TIM_CN20K_CHUNK_BUF_ALIGN);
+ /* Clamp to the largest 256B aligned size within the slot limit. */
+ if (CNXK_TIM_NB_CHUNK_SLOTS(tim_ring->chunk_sz) > CNXK_TIM_MAX_CHUNK_SLOTS)
+ tim_ring->chunk_sz = RTE_ALIGN_FLOOR(
+ (CNXK_TIM_MAX_CHUNK_SLOTS + 1) * CNXK_TIM_CHUNK_ALIGNMENT,
+ CNXK_TIM_CN20K_CHUNK_BUF_ALIGN);
+ }
- if (!dev->tim.feat.hwwqe && tim_ring->disable_npa) {
- tim_ring->nb_chunks =
- tim_ring->nb_timers /
- CNXK_TIM_NB_CHUNK_SLOTS(tim_ring->chunk_sz);
+ if (!cnxk_tim_hwwqe_enabled(dev) && tim_ring->disable_npa) {
+ /* Each bucket needs at least one chunk. */
+ tim_ring->nb_chunks = RTE_MAX(RTE_ALIGN_MUL_CEIL(tim_ring->nb_timers,
+ CNXK_TIM_NB_CHUNK_SLOTS(tim_ring->chunk_sz)) /
+ CNXK_TIM_NB_CHUNK_SLOTS(tim_ring->chunk_sz), 1UL);
tim_ring->nb_chunks = tim_ring->nb_chunks * tim_ring->nb_bkts;
} else {
tim_ring->disable_npa = 0;
@@ -289,7 +353,7 @@ cnxk_tim_ring_create(struct rte_event_timer_adapter *adptr)
goto tim_chnk_free;
}
- if (dev->tim.feat.hwwqe && dev->tim.feat.hwwqe_ver != TIM_HWWQE_VER_0) {
+ if (cnxk_tim_hwwqe_enabled(dev)) {
rc = cnxk_tim_enable_hwwqe(dev, tim_ring);
if (rc < 0) {
plt_err("Failed to enable hwwqe");
diff --git a/drivers/event/cnxk/cnxk_tim_worker.h b/drivers/event/cnxk/cnxk_tim_worker.h
index 9e33ff58d683..e031e83dabec 100644
--- a/drivers/event/cnxk/cnxk_tim_worker.h
+++ b/drivers/event/cnxk/cnxk_tim_worker.h
@@ -692,31 +692,31 @@ cnxk_tim_add_entry_tmo_hwwqe(struct cnxk_tim_ring *const tim_ring,
done += CNXK_TIM_ENT_PER_LMT;
rsp &= 0xF;
- if (rsp != 0x1) {
+ if (rsp != 0x1 && rsp != 0x5) {
switch (rsp) {
case 0x3:
for (j = 0; j < CNXK_TIM_ENT_PER_LMT; j++)
tim[(i * CNXK_TIM_ENT_PER_LMT) + j]->state =
- RTE_EVENT_TIMER_ERROR_TOOEARLY;
+ RTE_EVENT_TIMER_ERROR_TOOLATE;
done -= CNXK_TIM_ENT_PER_LMT;
break;
case 0x4:
for (j = 0; j < CNXK_TIM_ENT_PER_LMT; j++)
tim[(i * CNXK_TIM_ENT_PER_LMT) + j]->state =
- RTE_EVENT_TIMER_ERROR_TOOLATE;
+ RTE_EVENT_TIMER_ERROR_TOOEARLY;
done -= CNXK_TIM_ENT_PER_LMT;
break;
case 0x2:
default:
for (j = 0; j < CNXK_TIM_ENT_PER_LMT; j++) {
- if ((rte_atomic_load_explicit(
- (uint64_t __rte_atomic
- *)&tim[(i * CNXK_TIM_ENT_PER_LMT) + j]
- ->impl_opaque[0],
- rte_memory_order_relaxed) &
- 0xF0) != 0x10) {
- tim[(i * CNXK_TIM_ENT_PER_LMT) + j]->state =
- RTE_EVENT_TIMER_ERROR;
+ struct rte_event_timer *t =
+ tim[(i * CNXK_TIM_ENT_PER_LMT) + j];
+ uint64_t res = rte_atomic_load_explicit(
+ (uint64_t __rte_atomic *)&t->impl_opaque[0],
+ rte_memory_order_relaxed) & 0xF0;
+
+ if (res != 0x10 && res != 0x50) {
+ t->state = RTE_EVENT_TIMER_ERROR;
done--;
}
}
@@ -749,27 +749,28 @@ cnxk_tim_add_entry_tmo_hwwqe(struct cnxk_tim_ring *const tim_ring,
done += (nb_timers - cnt);
rsp &= 0xF;
- if (rsp != 0x1) {
+ if (rsp != 0x1 && rsp != 0x5) {
switch (rsp) {
case 0x3:
for (j = 0; j < nb_timers - cnt; j++)
- tim[cnt + j]->state = RTE_EVENT_TIMER_ERROR_TOOEARLY;
+ tim[cnt + j]->state = RTE_EVENT_TIMER_ERROR_TOOLATE;
done -= (nb_timers - cnt);
break;
case 0x4:
for (j = 0; j < nb_timers - cnt; j++)
- tim[cnt + j]->state = RTE_EVENT_TIMER_ERROR_TOOLATE;
+ tim[cnt + j]->state = RTE_EVENT_TIMER_ERROR_TOOEARLY;
done -= (nb_timers - cnt);
break;
case 0x2:
default:
for (j = 0; j < nb_timers - cnt; j++) {
- if ((rte_atomic_load_explicit(
- (uint64_t __rte_atomic *)&tim[cnt + j]
- ->impl_opaque[0],
- rte_memory_order_relaxed) &
- 0xF0) != 0x10) {
- tim[cnt + j]->state = RTE_EVENT_TIMER_ERROR;
+ struct rte_event_timer *t = tim[cnt + j];
+ uint64_t res = rte_atomic_load_explicit(
+ (uint64_t __rte_atomic *)&t->impl_opaque[0],
+ rte_memory_order_relaxed) & 0xF0;
+
+ if (res != 0x10 && res != 0x50) {
+ t->state = RTE_EVENT_TIMER_ERROR;
done--;
}
}
--
2.50.1 (Apple Git-155)
More information about the dev
mailing list