+static void
+__lpm_rcu_qsbr_free_resource(void *p, void *data, unsigned int n)
+{
+ struct rte_lpm_tbl_entry *tbl8 = ((struct rte_lpm *)p)->tbl8;
+ struct rte_lpm_tbl_entry zero_tbl8_entry = {0};
+ uint32_t tbl8_group_index = *(uint32_t *)data;
+
+ RTE_SET_USED(n);
+ /* Set tbl8 group invalid */
+ __atomic_store(&tbl8[tbl8_group_index], &zero_tbl8_entry,
+ __ATOMIC_RELAXED);
+}
+
+/* Associate QSBR variable with an LPM object.
+ */
+int
+rte_lpm_rcu_qsbr_add(struct rte_lpm *lpm, struct rte_lpm_rcu_config *cfg)
+{
+ struct rte_rcu_qsbr_dq_parameters params = {0};
+ char rcu_dq_name[RTE_RCU_QSBR_DQ_NAMESIZE];
+ struct __rte_lpm *internal_lpm;
+
+ if (lpm == NULL || cfg == NULL) {
+ rte_errno = EINVAL;
+ return 1;
+ }
+
+ internal_lpm = container_of(lpm, struct __rte_lpm, lpm);
+ if (internal_lpm->v != NULL) {
+ rte_errno = EEXIST;
+ return 1;
+ }
+
+ if (cfg->mode == RTE_LPM_QSBR_MODE_SYNC) {
+ /* No other things to do. */
+ } else if (cfg->mode == RTE_LPM_QSBR_MODE_DQ) {
+ /* Init QSBR defer queue. */
+ snprintf(rcu_dq_name, sizeof(rcu_dq_name),
+ "LPM_RCU_%s", lpm->name);
+ params.name = rcu_dq_name;
+ params.size = cfg->dq_size;
+ if (params.size == 0)
+ params.size = lpm->number_tbl8s;
+ params.trigger_reclaim_limit = cfg->reclaim_thd;
+ params.max_reclaim_size = cfg->reclaim_max;
+ if (params.max_reclaim_size == 0)
+ params.max_reclaim_size = RTE_LPM_RCU_DQ_RECLAIM_MAX;
+ params.esize = sizeof(uint32_t); /* tbl8 group index */
+ params.free_fn = __lpm_rcu_qsbr_free_resource;
+ params.p = lpm;
+ params.v = cfg->v;
+ internal_lpm->dq = rte_rcu_qsbr_dq_create(¶ms);
+ if (internal_lpm->dq == NULL) {
+ RTE_LOG(ERR, LPM, "LPM defer queue creation failed\n");
+ return 1;
+ }
+ } else {
+ rte_errno = EINVAL;
+ return 1;
+ }
+ internal_lpm->rcu_mode = cfg->mode;
+ internal_lpm->v = cfg->v;
+
+ return 0;
+}
+